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