SNAP Library 2.2, Developer Reference  2014-03-11 19:15:55
SNAP, a general purpose, high performance system for analysis and manipulation of large networks
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines
triad.h
Go to the documentation of this file.
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