SNAP Library 2.1, Developer Reference
2013-09-25 10:47:25
SNAP, a general purpose, high performance system for analysis and manipulation of large networks
|
00001 namespace TSnap { 00002 00004 // Triads and clustering coefficient 00005 00007 00009 template <class PGraph> double GetClustCf(const PGraph& Graph, int SampleNodes=-1); 00011 00015 template <class PGraph> double GetClustCf(const PGraph& Graph, TFltPrV& DegToCCfV, int SampleNodes=-1); 00017 00021 template <class PGraph> double GetClustCf(const PGraph& Graph, TFltPrV& DegToCCfV, int64& ClosedTriads, int64& OpenTriads, int SampleNodes=-1); 00023 00025 template <class PGraph> double GetNodeClustCf(const PGraph& Graph, const int& NId); 00027 00031 template <class PGraph> void GetNodeClustCf(const PGraph& Graph, TIntFltH& NIdCCfH); 00032 00034 00038 template <class PGraph> int64 GetTriads(const PGraph& Graph, int SampleNodes=-1); 00040 00043 template <class PGraph> int64 GetTriads(const PGraph& Graph, int64& ClosedTriads, int64& OpenTriads, int SampleNodes); 00045 00049 template <class PGraph> void GetTriads(const PGraph& Graph, TIntTrV& NIdCOTriadV, int SampleNodes=-1); 00051 00054 template <class PGraph> int GetTriadEdges(const PGraph& Graph, int SampleEdges=-1); 00055 00057 00059 template <class PGraph> int GetNodeTriads(const PGraph& Graph, const int& NId); 00061 00063 template <class PGraph> int GetNodeTriads(const PGraph& Graph, const int& NId, int& ClosedTriads, int& OpenTriads); 00065 00069 template <class PGraph> int GetNodeTriads(const PUNGraph& Graph, const int& NId, const TIntSet& GroupSet, int& InGroupEdges, int& InOutGroupEdges, int& OutGroup); 00071 00073 template <class PGraph> void GetTriadParticip(const PGraph& Graph, TIntPrV& TriadCntV); 00074 00076 template<class PGraph> int GetCmnNbrs(const PGraph& Graph, const int& NId1, const int& NId2); 00078 template<class PGraph> int GetCmnNbrs(const PGraph& Graph, const int& NId1, const int& NId2, TIntV& NbrV); 00080 template<class PGraph> int GetLen2Paths(const PGraph& Graph, const int& NId1, const int& NId2); 00082 00084 template<class PGraph> int GetLen2Paths(const PGraph& Graph, const int& NId1, const int& NId2, TIntV& NbrV); 00085 00087 // Implementation 00088 00089 template <class PGraph> double GetClustCf(const PGraph& Graph, int SampleNodes) { 00090 TIntTrV NIdCOTriadV; 00091 GetTriads(Graph, NIdCOTriadV, SampleNodes); 00092 if (NIdCOTriadV.Empty()) { return 0.0; } 00093 double SumCcf = 0.0; 00094 for (int i = 0; i < NIdCOTriadV.Len(); i++) { 00095 const double OpenCnt = NIdCOTriadV[i].Val2()+NIdCOTriadV[i].Val3(); 00096 if (OpenCnt > 0) { 00097 SumCcf += NIdCOTriadV[i].Val2() / OpenCnt; } 00098 } 00099 IAssert(SumCcf>=0); 00100 return SumCcf / double(NIdCOTriadV.Len()); 00101 } 00102 00103 template <class PGraph> double GetClustCf(const PGraph& Graph, TFltPrV& DegToCCfV, int SampleNodes) { 00104 TIntTrV NIdCOTriadV; 00105 GetTriads(Graph, NIdCOTriadV, SampleNodes); 00106 THash<TInt, TFltPr> DegSumCnt; 00107 double SumCcf = 0.0; 00108 for (int i = 0; i < NIdCOTriadV.Len(); i++) { 00109 const int D = NIdCOTriadV[i].Val2()+NIdCOTriadV[i].Val3(); 00110 const double Ccf = D!=0 ? NIdCOTriadV[i].Val2() / double(D) : 0.0; 00111 TFltPr& SumCnt = DegSumCnt.AddDat(Graph->GetNI(NIdCOTriadV[i].Val1).GetDeg()); 00112 SumCnt.Val1 += Ccf; 00113 SumCnt.Val2 += 1; 00114 SumCcf += Ccf; 00115 } 00116 // get average clustering coefficient for each degree 00117 DegToCCfV.Gen(DegSumCnt.Len(), 0); 00118 for (int d = 0; d < DegSumCnt.Len(); d++) { 00119 DegToCCfV.Add(TFltPr(DegSumCnt.GetKey(d).Val, double(DegSumCnt[d].Val1()/DegSumCnt[d].Val2()))); 00120 } 00121 DegToCCfV.Sort(); 00122 return SumCcf / double(NIdCOTriadV.Len()); 00123 } 00124 00125 template <class PGraph> 00126 double GetClustCf(const PGraph& Graph, TFltPrV& DegToCCfV, int64& ClosedTriads, int64& OpenTriads, int SampleNodes) { 00127 TIntTrV NIdCOTriadV; 00128 GetTriads(Graph, NIdCOTriadV, SampleNodes); 00129 THash<TInt, TFltPr> DegSumCnt; 00130 double SumCcf = 0.0; 00131 int64 closedTriads = 0; 00132 int64 openTriads = 0; 00133 for (int i = 0; i < NIdCOTriadV.Len(); i++) { 00134 const int D = NIdCOTriadV[i].Val2()+NIdCOTriadV[i].Val3(); 00135 const double Ccf = D!=0 ? NIdCOTriadV[i].Val2() / double(D) : 0.0; 00136 closedTriads += NIdCOTriadV[i].Val2; 00137 openTriads += NIdCOTriadV[i].Val3; 00138 TFltPr& SumCnt = DegSumCnt.AddDat(Graph->GetNI(NIdCOTriadV[i].Val1).GetDeg()); 00139 SumCnt.Val1 += Ccf; 00140 SumCnt.Val2 += 1; 00141 SumCcf += Ccf; 00142 } 00143 // get average clustering coefficient for each degree 00144 DegToCCfV.Gen(DegSumCnt.Len(), 0); 00145 for (int d = 0; d < DegSumCnt.Len(); d++) { 00146 DegToCCfV.Add(TFltPr(DegSumCnt.GetKey(d).Val, DegSumCnt[d].Val1()/DegSumCnt[d].Val2())); 00147 } 00148 //if(closedTriads/3 > (uint64) TInt::Mx) { WarnNotify(TStr::Fmt("[%s line %d] %g closed triads.\n", __FILE__, __LINE__, float(closedTriads/3)).CStr()); } 00149 //if(openTriads > (uint64) TInt::Mx) { WarnNotify(TStr::Fmt("[%s line %d] %g open triads.\n", __FILE__, __LINE__, float(openTriads/3)).CStr()); } 00150 ClosedTriads = closedTriads/int64(3); // each triad is counted 3 times 00151 OpenTriads = openTriads; 00152 DegToCCfV.Sort(); 00153 return SumCcf / double(NIdCOTriadV.Len()); 00154 } 00155 00156 template <class PGraph> 00157 double GetNodeClustCf(const PGraph& Graph, const int& NId) { 00158 int Open, Closed; 00159 GetNodeTriads(Graph, NId, Open, Closed); 00160 //const double Deg = Graph->GetNI(NId).GetDeg(); 00161 return (Open+Closed)==0 ? 0 : double(Open)/double(Open+Closed); 00162 } 00163 00164 template <class PGraph> 00165 void GetNodeClustCf(const PGraph& Graph, TIntFltH& NIdCCfH) { 00166 TIntTrV NIdCOTriadV; 00167 GetTriads(Graph, NIdCOTriadV); 00168 NIdCCfH.Clr(false); 00169 for (int i = 0; i < NIdCOTriadV.Len(); i++) { 00170 const int D = NIdCOTriadV[i].Val2()+NIdCOTriadV[i].Val3(); 00171 const double CCf = D!=0 ? NIdCOTriadV[i].Val2() / double(D) : 0.0; 00172 NIdCCfH.AddDat(NIdCOTriadV[i].Val1, CCf); 00173 } 00174 } 00175 00176 template <class PGraph> 00177 int64 GetTriads(const PGraph& Graph, int SampleNodes) { 00178 int64 OpenTriads, ClosedTriads; 00179 return GetTriads(Graph, ClosedTriads, OpenTriads, SampleNodes); 00180 } 00181 00182 template <class PGraph> 00183 int64 GetTriads(const PGraph& Graph, int64& ClosedTriads, int64& OpenTriads, int SampleNodes) { 00184 TIntTrV NIdCOTriadV; 00185 GetTriads(Graph, NIdCOTriadV, SampleNodes); 00186 uint64 closedTriads = 0; 00187 uint64 openTriads = 0; 00188 for (int i = 0; i < NIdCOTriadV.Len(); i++) { 00189 closedTriads += NIdCOTriadV[i].Val2; 00190 openTriads += NIdCOTriadV[i].Val3; 00191 } 00192 //IAssert(closedTriads/3 < (uint64) TInt::Mx); 00193 //IAssert(openTriads < (uint64) TInt::Mx); 00194 ClosedTriads = int64(closedTriads/3); // each triad is counted 3 times 00195 OpenTriads = int64(openTriads); 00196 return ClosedTriads; 00197 } 00198 00199 // Function pretends that the graph is undirected (count unique connected triples of nodes) 00200 template <class PGraph> 00201 void GetTriads(const PGraph& Graph, TIntTrV& NIdCOTriadV, int SampleNodes) { 00202 const bool IsDir = Graph->HasFlag(gfDirected); 00203 TIntSet NbrH; 00204 TIntV NIdV; 00205 TRnd Rnd(0); 00206 00207 Graph->GetNIdV(NIdV); 00208 NIdV.Shuffle(Rnd); 00209 if (SampleNodes == -1) { 00210 SampleNodes = Graph->GetNodes(); } 00211 NIdCOTriadV.Clr(false); 00212 NIdCOTriadV.Reserve(SampleNodes); 00213 for (int node = 0; node < SampleNodes; node++) { 00214 typename PGraph::TObj::TNodeI NI = Graph->GetNI(NIdV[node]); 00215 if (NI.GetDeg() < 2) { 00216 NIdCOTriadV.Add(TIntTr(NI.GetId(), 0, 0)); // zero triangles 00217 continue; 00218 } 00219 // find neighborhood 00220 NbrH.Clr(false); 00221 for (int e = 0; e < NI.GetOutDeg(); e++) { 00222 if (NI.GetOutNId(e) != NI.GetId()) { 00223 NbrH.AddKey(NI.GetOutNId(e)); } 00224 } 00225 if (IsDir) { 00226 for (int e = 0; e < NI.GetInDeg(); e++) { 00227 if (NI.GetInNId(e) != NI.GetId()) { 00228 NbrH.AddKey(NI.GetInNId(e)); } 00229 } 00230 } 00231 // count connected neighbors 00232 int OpenCnt=0, CloseCnt=0; 00233 for (int srcNbr = 0; srcNbr < NbrH.Len(); srcNbr++) { 00234 const typename PGraph::TObj::TNodeI SrcNode = Graph->GetNI(NbrH.GetKey(srcNbr)); 00235 for (int dstNbr = srcNbr+1; dstNbr < NbrH.Len(); dstNbr++) { 00236 const int dstNId = NbrH.GetKey(dstNbr); 00237 if (SrcNode.IsNbrNId(dstNId)) { CloseCnt++; } // is edge 00238 else { OpenCnt++; } 00239 } 00240 } 00241 IAssert(2*(OpenCnt+CloseCnt) == NbrH.Len()*(NbrH.Len()-1)); 00242 NIdCOTriadV.Add(TIntTr(NI.GetId(), CloseCnt, OpenCnt)); 00243 } 00244 } 00245 00246 // Count the number of edges that participate in at least one triad 00247 template <class PGraph> 00248 int GetTriadEdges(const PGraph& Graph, int SampleEdges) { 00249 const bool IsDir = Graph->HasFlag(gfDirected); 00250 TIntSet NbrH; 00251 int TriadEdges = 0; 00252 for(typename PGraph::TObj::TNodeI NI = Graph->BegNI(); NI < Graph->EndNI(); NI++) { 00253 NbrH.Clr(false); 00254 for (int e = 0; e < NI.GetOutDeg(); e++) { 00255 if (NI.GetOutNId(e) != NI.GetId()) { 00256 NbrH.AddKey(NI.GetOutNId(e)); } 00257 } 00258 if (IsDir) { 00259 for (int e = 0; e < NI.GetInDeg(); e++) { 00260 if (NI.GetInNId(e) != NI.GetId()) { 00261 NbrH.AddKey(NI.GetInNId(e)); } 00262 } 00263 } 00264 for (int e = 0; e < NI.GetOutDeg(); e++) { 00265 if (!IsDir && NI.GetId()<NI.GetOutNId(e)) { continue; } // for undirected graphs count each edge only once 00266 const typename PGraph::TObj::TNodeI SrcNode = Graph->GetNI(NI.GetOutNId(e)); 00267 bool Triad=false; 00268 for (int e1 = 0; e1 < SrcNode.GetOutDeg(); e1++) { 00269 if (NbrH.IsKey(SrcNode.GetOutNId(e1))) { Triad=true; break; } 00270 } 00271 if (IsDir && ! Triad) { 00272 for (int e1 = 0; e1 < SrcNode.GetInDeg(); e1++) { 00273 if (NbrH.IsKey(SrcNode.GetInNId(e1))) { Triad=true; break; } 00274 } 00275 } 00276 if (Triad) { TriadEdges++; } 00277 } 00278 } 00279 return TriadEdges; 00280 } 00281 00282 // Returns number of undirected triads a node participates in 00283 template <class PGraph> 00284 int GetNodeTriads(const PGraph& Graph, const int& NId) { 00285 int ClosedTriads=0, OpenTriads=0; 00286 return GetNodeTriads(Graph, NId, ClosedTriads, OpenTriads); 00287 } 00288 00289 // Return number of undirected triads a node participates in 00290 template <class PGraph> 00291 int GetNodeTriads(const PGraph& Graph, const int& NId, int& ClosedTriads, int& OpenTriads) { 00292 const typename PGraph::TObj::TNodeI NI = Graph->GetNI(NId); 00293 ClosedTriads=0; OpenTriads=0; 00294 if (NI.GetDeg() < 2) { return 0; } 00295 // find neighborhood 00296 TIntSet NbrSet(NI.GetDeg()); 00297 for (int e = 0; e < NI.GetOutDeg(); e++) { 00298 if (NI.GetOutNId(e) != NI.GetId()) { // exclude self edges 00299 NbrSet.AddKey(NI.GetOutNId(e)); } 00300 } 00301 if (Graph->HasFlag(gfDirected)) { 00302 for (int e = 0; e < NI.GetInDeg(); e++) { 00303 if (NI.GetInNId(e) != NI.GetId()) { // exclude self edges 00304 NbrSet.AddKey(NI.GetInNId(e)); } 00305 } 00306 } 00307 // count connected neighbors 00308 for (int srcNbr = 0; srcNbr < NbrSet.Len(); srcNbr++) { 00309 const typename PGraph::TObj::TNodeI SrcNode = Graph->GetNI(NbrSet.GetKey(srcNbr)); 00310 for (int dstNbr = srcNbr+1; dstNbr < NbrSet.Len(); dstNbr++) { 00311 const int dstNId = NbrSet.GetKey(dstNbr); 00312 if (SrcNode.IsNbrNId(dstNId)) { ClosedTriads++; } 00313 else { OpenTriads++; } 00314 } 00315 } 00316 return ClosedTriads; 00317 } 00318 00319 // Node NId and a subset of its neighbors GroupSet 00320 // InGroupEdges ... triads (NId, g1, g2), where g1 and g2 are in GroupSet 00321 // InOutGroupEdges ... triads (NId, g1, o1), where g1 in GroupSet and o1 not in GroupSet 00322 // OutGroupEdges ... triads (NId, o1, o2), where o1 and o2 are not in GroupSet 00323 template <class PGraph> 00324 int GetNodeTriads(const PGraph& Graph, const int& NId, const TIntSet& GroupSet, int& InGroupEdges, int& InOutGroupEdges, int& OutGroupEdges) { 00325 const typename PGraph::TObj::TNodeI NI = Graph->GetNI(NId); 00326 const bool IsDir = Graph->HasFlag(gfDirected); 00327 InGroupEdges=0; InOutGroupEdges=0; OutGroupEdges=0; 00328 if (NI.GetDeg() < 2) { return 0; } 00329 // find neighborhood 00330 TIntSet NbrSet(NI.GetDeg()); 00331 for (int e = 0; e < NI.GetOutDeg(); e++) { 00332 if (NI.GetOutNId(e) != NI.GetId()) { // exclude self edges 00333 NbrSet.AddKey(NI.GetOutNId(e)); } 00334 } 00335 if (IsDir) { 00336 for (int e = 0; e < NI.GetInDeg(); e++) { 00337 if (NI.GetInNId(e) != NI.GetId()) { 00338 NbrSet.AddKey(NI.GetInNId(e)); } 00339 } 00340 } 00341 // count connected neighbors 00342 for (int srcNbr = 0; srcNbr < NbrSet.Len(); srcNbr++) { 00343 const int NbrId = NbrSet.GetKey(srcNbr); 00344 const bool NbrIn = GroupSet.IsKey(NbrId); 00345 const typename PGraph::TObj::TNodeI SrcNode = Graph->GetNI(NbrId); 00346 for (int dstNbr = srcNbr+1; dstNbr < NbrSet.Len(); dstNbr++) { 00347 const int DstNId = NbrSet.GetKey(dstNbr); 00348 if (SrcNode.IsNbrNId(DstNId)) { // triad (NId, NbrId, DstNid) 00349 bool DstIn = GroupSet.IsKey(DstNId); 00350 if (NbrIn && DstIn) { InGroupEdges++; } 00351 else if (NbrIn || DstIn) { InOutGroupEdges++; } 00352 else { OutGroupEdges++; } 00353 } 00354 } 00355 } 00356 return InGroupEdges; 00357 } 00358 00359 // For each node count how many triangles it participates in 00360 template <class PGraph> 00361 void GetTriadParticip(const PGraph& Graph, TIntPrV& TriadCntV) { 00362 TIntH TriadCntH; 00363 for (typename PGraph::TObj::TNodeI NI = Graph->BegNI(); NI < Graph->EndNI(); NI++) { 00364 const int Triads = GetNodeTriads(Graph, NI.GetId()); 00365 TriadCntH.AddDat(Triads) += 1; 00366 } 00367 TriadCntH.GetKeyDatPrV(TriadCntV); 00368 TriadCntV.Sort(); 00369 } 00370 00371 template<class PGraph> 00372 int GetCmnNbrs(const PGraph& Graph, const int& NId1, const int& NId2) { 00373 TIntV NbrV; 00374 return GetCmnNbrs(Graph, NId1, NId2, NbrV); 00375 } 00376 00377 // Get common neighbors between a pair of nodes (undirected) 00378 template<class PGraph> 00379 int GetCmnNbrs(const PGraph& Graph, const int& NId1, const int& NId2, TIntV& NbrV) { 00380 if (! Graph->IsNode(NId1) || ! Graph->IsNode(NId2)) { NbrV.Clr(false); return 0; } 00381 typename PGraph::TObj::TNodeI NI1 = Graph->GetNI(NId1); 00382 typename PGraph::TObj::TNodeI NI2 = Graph->GetNI(NId2); 00383 NbrV.Clr(false); 00384 NbrV.Reserve(TMath::Mn(NI1.GetDeg(), NI2.GetDeg())); 00385 TIntSet NSet1(NI1.GetDeg()), NSet2(NI2.GetDeg()); 00386 for (int i = 0; i < NI1.GetDeg(); i++) { 00387 const int nid = NI1.GetNbrNId(i); 00388 if (nid!=NId1 && nid!=NId2) { 00389 NSet1.AddKey(nid); } 00390 } 00391 for (int i = 0; i < NI2.GetDeg(); i++) { 00392 const int nid = NI2.GetNbrNId(i); 00393 if (NSet1.IsKey(nid)) { 00394 NSet2.AddKey(nid); 00395 } 00396 } 00397 NSet2.GetKeyV(NbrV); 00398 return NbrV.Len(); 00399 } 00400 00401 template<> 00402 inline int GetCmnNbrs<PUNGraph>(const PUNGraph& Graph, const int& NId1, const int& NId2, TIntV& NbrV) { 00403 if (! Graph->IsNode(NId1) || ! Graph->IsNode(NId2)) { NbrV.Clr(false); return 0; } 00404 const TUNGraph::TNodeI NI1 = Graph->GetNI(NId1); 00405 const TUNGraph::TNodeI NI2 = Graph->GetNI(NId2); 00406 int i=0, j=0; 00407 NbrV.Clr(false); 00408 NbrV.Reserve(TMath::Mn(NI1.GetDeg(), NI2.GetDeg())); 00409 while (i < NI1.GetDeg() && j < NI2.GetDeg()) { 00410 const int nid = NI1.GetNbrNId(i); 00411 while (j < NI2.GetDeg() && NI2.GetNbrNId(j) < nid) { j++; } 00412 if (j < NI2.GetDeg() && nid==NI2.GetNbrNId(j) && nid!=NId1 && nid!=NId2) { 00413 IAssert(NbrV.Empty() || NbrV.Last() < nid); 00414 NbrV.Add(nid); 00415 j++; 00416 } 00417 i++; 00418 } 00419 return NbrV.Len(); 00420 } 00421 00422 // get number of length 2 directed paths between a pair of nodes 00423 // for a pair of nodes (i,j): |{u: (i,u) and (u,j) }| 00424 template<class PGraph> 00425 int GetLen2Paths(const PGraph& Graph, const int& NId1, const int& NId2) { 00426 TIntV NbrV; 00427 return GetLen2Paths(Graph, NId1, NId2, NbrV); 00428 } 00429 00430 // get number of length 2 directed paths between a pair of nodes 00431 // for a pair of nodes (i,j): {u: (i,u) and (u,j) } 00432 template<class PGraph> 00433 int GetLen2Paths(const PGraph& Graph, const int& NId1, const int& NId2, TIntV& NbrV) { 00434 const typename PGraph::TObj::TNodeI NI = Graph->GetNI(NId1); 00435 NbrV.Clr(false); 00436 NbrV.Reserve(NI.GetOutDeg()); 00437 for (int e = 0; e < NI.GetOutDeg(); e++) { 00438 const typename PGraph::TObj::TNodeI MidNI = Graph->GetNI(NI.GetOutNId(e)); 00439 if (MidNI.IsOutNId(NId2)) { 00440 NbrV.Add(MidNI.GetId()); 00441 } 00442 } 00443 return NbrV.Len(); 00444 } 00445 00446 }; // mamespace TSnap 00447 00449 // Node and Edge Network Constraint (by Ron Burt) 00450 // works for directed and undirected graphs (but not for multigraphs) 00451 template <class PGraph> 00452 class TNetConstraint { 00453 public: 00454 PGraph Graph; 00455 THash<TIntPr, TFlt> NodePrCH; // pairs of nodes that have non-zero network constraint 00456 public: 00457 TNetConstraint(const PGraph& GraphPt, const bool& CalcaAll=true); 00458 int Len() const { return NodePrCH.Len(); } 00459 double GetC(const int& ConstraintN) const { return NodePrCH[ConstraintN]; } 00460 TIntPr GetNodePr(const int& ConstraintN) const { return NodePrCH.GetKey(ConstraintN); } 00461 double GetEdgeC(const int& NId1, const int& NId2) const; 00462 double GetNodeC(const int& NId) const; 00463 void AddConstraint(const int& NId1, const int& NId2); 00464 void CalcConstraints(); 00465 void CalcConstraints(const int& NId); 00466 void Dump() const; 00467 static void Test(); 00468 }; 00469 00470 template <class PGraph> 00471 TNetConstraint<PGraph>::TNetConstraint(const PGraph& GraphPt, const bool& CalcaAll) : Graph(GraphPt) { 00472 CAssert(! HasGraphFlag(typename PGraph::TObj, gfMultiGraph)); // must not be multigraph 00473 if (CalcaAll) { 00474 CalcConstraints(); 00475 } 00476 } 00477 00478 template <class PGraph> 00479 double TNetConstraint<PGraph>::GetEdgeC(const int& NId1, const int& NId2) const { 00480 if (NodePrCH.IsKey(TIntPr(NId1, NId2))) { 00481 return NodePrCH.GetDat(TIntPr(NId1, NId2)); } 00482 else { 00483 return 0.0; } 00484 } 00485 00486 template <class PGraph> 00487 double TNetConstraint<PGraph>::GetNodeC(const int& NId) const { 00488 typename PGraph::TObj::TNodeI NI1 = Graph->GetNI(NId); 00489 if (NI1.GetOutDeg() == 0) { return 0.0; } 00490 int KeyId = -1; 00491 for (int k = 0; k<NI1.GetOutDeg(); k++) { 00492 KeyId = NodePrCH.GetKeyId(TIntPr(NI1.GetId(), NI1.GetOutNId(k))); 00493 if (KeyId > -1) { break; } 00494 } 00495 if (KeyId < 0) { return 0.0; } 00496 double Constraint = NodePrCH[KeyId]; 00497 for (int i = KeyId-1; i >-1 && NodePrCH.GetKey(i).Val1()==NId; i--) { 00498 Constraint += NodePrCH[i]; 00499 } 00500 for (int i = KeyId+1; i < NodePrCH.Len() && NodePrCH.GetKey(i).Val1()==NId; i++) { 00501 Constraint += NodePrCH[i]; 00502 } 00503 return Constraint; 00504 } 00505 00506 template <class PGraph> 00507 void TNetConstraint<PGraph>::AddConstraint(const int& NId1, const int& NId2) { 00508 if (NId1==NId2 || NodePrCH.IsKey(TIntPr(NId1, NId2))) { 00509 return; 00510 } 00511 typename PGraph::TObj::TNodeI NI1 = Graph->GetNI(NId1); 00512 double Constraint = 0.0; 00513 if (NI1.IsOutNId(NId2)) { // is direct edge 00514 Constraint += 1.0/(double) NI1.GetOutDeg(); 00515 } 00516 const double SrcC = 1.0/(double) NI1.GetOutDeg(); 00517 for (int e = 0; e < NI1.GetOutDeg(); e++) { 00518 const int MidNId = NI1.GetOutNId(e); 00519 if (MidNId == NId1 || MidNId == NId2) { continue; } 00520 const typename PGraph::TObj::TNodeI MidNI = Graph->GetNI(MidNId); 00521 if (MidNI.IsOutNId(NId2)) { 00522 Constraint += SrcC * (1.0/(double)MidNI.GetOutDeg()); 00523 } 00524 } 00525 if (Constraint==0) { return; } 00526 Constraint = TMath::Sqr(Constraint); 00527 NodePrCH.AddDat(TIntPr(NId1, NId2), Constraint); 00528 } 00529 00530 template <class PGraph> 00531 void TNetConstraint<PGraph>::CalcConstraints() { 00532 // add edges 00533 for (typename PGraph::TObj::TEdgeI EI = Graph->BegEI(); EI < Graph->EndEI(); EI++) { 00534 AddConstraint(EI.GetSrcNId(), EI.GetDstNId()); 00535 AddConstraint(EI.GetDstNId(), EI.GetSrcNId()); 00536 } 00537 // add open triads 00538 for (typename PGraph::TObj::TNodeI NI = Graph->BegNI(); NI < Graph->EndNI(); NI++) { 00539 for (int i = 0; i < NI.GetDeg(); i++) { 00540 const int NId1 = NI.GetNbrNId(i); 00541 for (int j = 0; j < NI.GetDeg(); j++) { 00542 const int NId2 = NI.GetNbrNId(j); 00543 AddConstraint(NId1, NId2); 00544 } 00545 } 00546 } 00547 NodePrCH.SortByKey(); 00548 } 00549 00550 // calculate constraints around a node id 00551 template <class PGraph> 00552 void TNetConstraint<PGraph>::CalcConstraints(const int& NId) { 00553 typename PGraph::TObj::TNodeI StartNI = Graph->GetNI(NId); 00554 TIntSet SeenSet; 00555 for (int e = 0; e < StartNI.GetOutDeg(); e++) { 00556 typename PGraph::TObj::TNodeI MidNI = Graph->GetNI(StartNI.GetOutNId(e)); 00557 AddConstraint(NId, MidNI.GetId()); 00558 for (int i = 0; i < MidNI.GetOutDeg(); i++) { 00559 const int EndNId = MidNI.GetOutNId(i); 00560 if (! SeenSet.IsKey(EndNId)) { 00561 AddConstraint(NId, EndNId); 00562 SeenSet.AddKey(EndNId); 00563 } 00564 } 00565 } 00566 } 00567 00568 template <class PGraph> 00569 void TNetConstraint<PGraph>::Dump() const { 00570 printf("Edge network constraint: (%d, %d)\n", Graph->GetNodes(), Graph->GetEdges()); 00571 for (int e = 0; e < NodePrCH.Len(); e++) { 00572 printf(" %4d %4d : %f\n", NodePrCH.GetKey(e).Val1(), NodePrCH.GetKey(e).Val2(), NodePrCH[e].Val); 00573 } 00574 printf("\n"); 00575 } 00576 00577 // example from page 56 of Structural Holes by Ronald S. Burt 00578 // (http://www.amazon.com/Structural-Holes-Social-Structure-Competition/dp/0674843711) 00579 template <class PGraph> 00580 void TNetConstraint<PGraph>::Test() { 00581 PUNGraph G = TUNGraph::New(); 00582 G->AddNode(0); G->AddNode(1); G->AddNode(2); G->AddNode(3); 00583 G->AddNode(4); G->AddNode(5); G->AddNode(6); 00584 G->AddEdge(0,1); G->AddEdge(0,2); G->AddEdge(0,3); G->AddEdge(0,4); G->AddEdge(0,5); G->AddEdge(0,6); 00585 G->AddEdge(1,2); G->AddEdge(1,5); G->AddEdge(1,6); 00586 G->AddEdge(2,4); 00587 TNetConstraint<PUNGraph> NetConstraint(G, true); 00588 // NetConstraint.CalcConstraints(0); 00589 NetConstraint.Dump(); 00590 printf("middle node network constraint: %f\n", NetConstraint.GetNodeC(0)); 00591 } 00592