SNAP Library , Developer Reference  2013-01-07 14:03:36
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
cncom.h
Go to the documentation of this file.
00001 
00002 // Connected Components
00003 class TCnCom;
00004 typedef TVec<TCnCom> TCnComV;
00005 
00006 namespace TSnap {
00007 
00009 template <class PGraph> void GetNodeWcc(const PGraph& Graph, const int& NId, TIntV& CnCom);
00011 template <class PGraph> bool IsConnected(const PGraph& Graph);
00013 template <class PGraph> bool IsWeaklyConn(const PGraph& Graph);
00016 template <class PGraph> void GetWccSzCnt(const PGraph& Graph, TIntPrV& WccSzCnt);
00019 template <class PGraph> void GetWccs(const PGraph& Graph, TCnComV& CnComV);
00022 template <class PGraph> void GetSccSzCnt(const PGraph& Graph, TIntPrV& SccSzCnt);
00025 template <class PGraph> void GetSccs(const PGraph& Graph, TCnComV& CnComV);
00027 template <class PGraph> double GetMxWccSz(const PGraph& Graph);
00028 
00032 template <class PGraph> PGraph GetMxWcc(const PGraph& Graph);
00036 template <class PGraph> PGraph GetMxScc(const PGraph& Graph);
00040 template <class PGraph> PGraph GetMxBiCon(const PGraph& Graph);
00041 
00044 void GetBiConSzCnt(const PUNGraph& Graph, TIntPrV& SzCntV);
00047 void GetBiCon(const PUNGraph& Graph, TCnComV& BiCnComV);
00050 void GetArtPoints(const PUNGraph& Graph, TIntV& ArtNIdV);
00054 void GetEdgeBridges(const PUNGraph& Graph, TIntPrV& EdgeV);
00058 void Get1CnComSzCnt(const PUNGraph& Graph, TIntPrV& SzCntV);
00062 void Get1CnCom(const PUNGraph& Graph, TCnComV& Cn1ComV);
00067 PUNGraph GetMxBiCon(const PUNGraph& Graph, const bool& RenumberNodes=false);
00068 
00069 }; // namespace TSnap
00070 
00074 class TCnCom {
00075 public:
00076   TIntV NIdV;
00077 public:
00078   TCnCom() : NIdV() { }
00079   TCnCom(const TIntV& NodeIdV) : NIdV(NodeIdV) { }
00080   TCnCom(const TCnCom& CC) : NIdV(CC.NIdV) { }
00081   TCnCom(TSIn& SIn) : NIdV(SIn) { }
00082   void Save(TSOut& SOut) const { NIdV.Save(SOut); }
00083   TCnCom& operator = (const TCnCom& CC) { if (this != &CC) NIdV = CC.NIdV;  return *this; }
00084   bool operator == (const TCnCom& CC) const { return NIdV == CC.NIdV; }
00085   bool operator < (const TCnCom& CC) const { return NIdV < CC.NIdV; }
00086 
00087   int Len() const { return NIdV.Len(); }
00088   bool Empty() const { return NIdV.Empty(); }
00089   void Clr() { NIdV.Clr(); }
00090   void Add(const int& NodeId) { NIdV.Add(NodeId); }
00091   const TInt& operator [] (const int& NIdN) const { return NIdV[NIdN]; }
00092   const TIntV& operator () () const { return NIdV; }
00093   TIntV& operator () () { return NIdV; }
00094   void Sort(const bool& Asc = true) { NIdV.Sort(Asc); }
00095   bool IsNIdIn(const int& NId) const { return NIdV.SearchBin(NId) != -1; }
00096   const TInt& GetRndNId() const { return NIdV[TInt::Rnd.GetUniDevInt(Len())]; }
00097   static void Dump(const TCnComV& CnComV, const TStr& Desc=TStr());
00098   static void SaveTxt(const TCnComV& CnComV, const TStr& FNm, const TStr& Desc=TStr());
00102   template <class PGraph, class TVisitor>
00103   static void GetDfsVisitor(const PGraph& Graph, TVisitor& Visitor);
00104 };
00105 
00106 template <class PGraph, class TVisitor>
00107 void TCnCom::GetDfsVisitor(const PGraph& Graph, TVisitor& Visitor) {
00108   const int Nodes = Graph->GetNodes();
00109   TSStack<TIntTr> Stack(Nodes);
00110   int edge=0, Deg=0, U=0;
00111   TIntH ColorH(Nodes);
00112   typename PGraph::TObj::TNodeI NI, UI;
00113   for (NI = Graph->BegNI(); NI < Graph->EndNI(); NI++) {
00114     U = NI.GetId();
00115     if (! ColorH.IsKey(U)) {         // is unvisited node
00116       ColorH.AddDat(U, 1); 
00117       Visitor.DiscoverNode(U);       // discover
00118       Stack.Push(TIntTr(U, 0, Graph->GetNI(U).GetOutDeg()));
00119       while (! Stack.Empty()) {
00120         const TIntTr& Top = Stack.Top();
00121         U=Top.Val1; edge=Top.Val2; Deg=Top.Val3;
00122         typename PGraph::TObj::TNodeI UI = Graph->GetNI(U);
00123         Stack.Pop();
00124         while (edge != Deg) {
00125           const int V = UI.GetOutNId(edge);
00126           Visitor.ExamineEdge(U, V); // examine edge
00127           if (! ColorH.IsKey(V)) {
00128             Visitor.TreeEdge(U, V);  // tree edge
00129             Stack.Push(TIntTr(U, ++edge, Deg));
00130             U = V;
00131             ColorH.AddDat(U, 1); 
00132             Visitor.DiscoverNode(U); // discover
00133             UI = Graph->GetNI(U);
00134             edge = 0;  Deg = UI.GetOutDeg();
00135           }
00136           else if (ColorH.GetDat(V) == 1) {
00137             Visitor.BackEdge(U, V);  // edge upward
00138             ++edge; }
00139           else {
00140             Visitor.FwdEdge(U, V);   // edge downward
00141             ++edge; }
00142         }
00143         ColorH.AddDat(U, 2); 
00144         Visitor.FinishNode(U);       // finish
00145       }
00146     }
00147   }
00148 }
00149 
00152 class TArtPointVisitor {
00153 public:
00154   THash<TInt, TIntPr> VnLowH;
00155   THash<TInt, TInt> ParentH;
00156   TIntSet ArtSet;
00157   TInt Time;
00158 public:
00159   TArtPointVisitor() { }
00160   TArtPointVisitor(const int& Nodes) : VnLowH(Nodes), ParentH(Nodes)  { }
00161   void DiscoverNode(int NId) { Time++; VnLowH.AddDat(NId, TIntPr(Time, Time)); }
00162   void FinishNode(const int& NId) {
00163     if (! ParentH.IsKey(NId)) { return; }  const int Prn = ParentH.GetDat(NId);
00164     VnLowH.GetDat(Prn).Val2 = TMath::Mn(VnLowH.GetDat(Prn).Val2, VnLowH.GetDat(NId).Val2);
00165     if (VnLowH.GetDat(Prn).Val1==1 && VnLowH.GetDat(NId).Val1!=2) { ArtSet.AddKey(Prn); }
00166     if (VnLowH.GetDat(Prn).Val1!=1 && VnLowH.GetDat(NId).Val2>=VnLowH.GetDat(Prn).Val1) { ArtSet.AddKey(Prn); } }
00167   void ExamineEdge(const int& NId1, const int& NId2) { }
00168   void TreeEdge(const int& NId1, const int& NId2) { ParentH.AddDat(NId2, NId1); }
00169   void BackEdge(const int& NId1, const int& NId2) {
00170     if (ParentH.IsKey(NId1) && ParentH.GetDat(NId1)!=NId2) {
00171       VnLowH.GetDat(NId1).Val2 = TMath::Mn(VnLowH.GetDat(NId1).Val2, VnLowH.GetDat(NId2).Val1); } }
00172   void FwdEdge(const int& NId1, const int& NId2) {
00173     VnLowH.GetDat(NId1).Val2 = TMath::Mn(VnLowH.GetDat(NId1).Val2, VnLowH.GetDat(NId2).Val1); }
00174 };
00175 
00178 class TBiConVisitor {
00179 public:
00180   THash<TInt, TIntPr> VnLowH;
00181   THash<TInt, TInt> ParentH;
00182   TSStack<TIntPr> Stack;
00183   TCnComV CnComV;
00184   TIntSet NSet;
00185   TInt Time;
00186 public:
00187   TBiConVisitor() { }
00188   TBiConVisitor(const int& Nodes) : VnLowH(Nodes), ParentH(Nodes), Stack(Nodes) { }
00189   void DiscoverNode(int NId) { Time++; VnLowH.AddDat(NId, TIntPr(Time, Time)); }
00190   void FinishNode(const int& NId) {
00191     if (! ParentH.IsKey(NId)) { return; }  const int Prn = ParentH.GetDat(NId);
00192     VnLowH.GetDat(Prn).Val2 = TMath::Mn(VnLowH.GetDat(Prn).Val2, VnLowH.GetDat(NId).Val2);
00193     if (VnLowH.GetDat(NId).Val2 >= VnLowH.GetDat(Prn).Val1) {
00194       NSet.Clr(false);
00195       while (! Stack.Empty() && Stack.Top() != TIntPr(Prn, NId)) {
00196         const TIntPr& Top = Stack.Top();
00197         NSet.AddKey(Top.Val1);  NSet.AddKey(Top.Val2); Stack.Pop();  }
00198       if (! Stack.Empty()) {
00199         const TIntPr& Top = Stack.Top();
00200         NSet.AddKey(Top.Val1);  NSet.AddKey(Top.Val2); Stack.Pop(); }
00201       TIntV NIdV; NSet.GetKeyV(NIdV);  NIdV.Sort();
00202       CnComV.Add(NIdV); } }
00203   void ExamineEdge(const int& NId1, const int& NId2) { }
00204   void TreeEdge(const int& NId1, const int& NId2) {
00205     ParentH.AddDat(NId2, NId1);
00206     Stack.Push(TIntPr(NId1, NId2)); }
00207   void BackEdge(const int& NId1, const int& NId2) {
00208     if (ParentH.IsKey(NId1) && ParentH.GetDat(NId1)!=NId2) {
00209       Stack.Push(TIntPr(NId1, NId2));
00210       VnLowH.GetDat(NId1).Val2 = TMath::Mn(VnLowH.GetDat(NId1).Val2, VnLowH.GetDat(NId2).Val1); } }
00211   void FwdEdge(const int& NId1, const int& NId2) { }
00212 };
00213 
00216 template <class PGraph, bool OnlyCount = false>
00217 class TSccVisitor {
00218 public:
00219   PGraph Graph;
00220   THash<TInt, TIntPr> TmRtH;
00221   TSStack<TInt> Stack;
00222   TInt Time;
00223   TIntH SccCntH;
00224   TCnComV CnComV;
00225 public:
00226   TSccVisitor(const PGraph& _Graph) :
00227       Graph(_Graph), TmRtH(Graph->GetNodes()), Stack(Graph->GetNodes()) { }
00228   void DiscoverNode(int NId) {
00229     Time++; TmRtH.AddDat(NId, TIntPr(-Time, NId)); // negative time -- node not yet in any SCC
00230     Stack.Push(NId); }
00231   void FinishNode(const int& NId) {
00232     typename PGraph::TObj::TNodeI NI = Graph->GetNI(NId);
00233     TIntPr& TmRtN = TmRtH.GetDat(NId);
00234     int W = -1, Cnt = 0;
00235     for (int i = 0; i < NI.GetOutDeg(); i++) {
00236       W = NI.GetOutNId(i);
00237       const TIntPr& TmRtW = TmRtH.GetDat(W);
00238       if (TmRtW.Val1 < 0) { // node not yet in any SCC
00239         TmRtN.Val2 = GetMinDiscTm(TmRtN.Val2, TmRtW.Val2); } }
00240     if (TmRtN.Val2 == NId) {
00241       if (! OnlyCount) { CnComV.Add(); }
00242       do { W = Stack.Top();  Stack.Pop();
00243       if (OnlyCount) { Cnt++; } else { CnComV.Last().Add(W); }
00244       TmRtH.GetDat(W).Val1 = abs(TmRtH.GetDat(W).Val1); // node is in SCC
00245       } while (W != NId);
00246       if (OnlyCount) { SccCntH.AddDat(Cnt) += 1; } } }
00247   void ExamineEdge(const int& NId1, const int& NId2) { }
00248   void TreeEdge(const int& NId1, const int& NId2) { }
00249   void BackEdge(const int& NId1, const int& NId2) { }
00250   void FwdEdge(const int& NId1, const int& NId2) { }
00251   int GetMinDiscTm(const int& NId1, const int& NId2) const {
00252     return abs(TmRtH.GetDat(NId1).Val1) < abs(TmRtH.GetDat(NId2).Val1) ? NId1 : NId2; }
00253 };
00254 
00256 // Implementation
00257 namespace TSnap {
00258 
00259 template <class PGraph> 
00260 void GetNodeWcc(const PGraph& Graph, const int& NId, TIntV& CnCom) {
00261   typename PGraph::TObj::TNodeI NI;
00262   THashSet<TInt> VisitedNId(Graph->GetNodes()+1);
00263   TSnapQueue<int> NIdQ(Graph->GetNodes()+1);
00264   VisitedNId.AddKey(NId);
00265   NIdQ.Push(NId);
00266   while (! NIdQ.Empty()) {
00267     const typename PGraph::TObj::TNodeI Node = Graph->GetNI(NIdQ.Top());  NIdQ.Pop();
00268     if (HasGraphFlag(typename PGraph::TObj, gfDirected)) {
00269       for (int e = 0; e < Node.GetInDeg(); e++) {
00270         const int InNId = Node.GetInNId(e);
00271         if (! VisitedNId.IsKey(InNId)) {
00272           NIdQ.Push(InNId);  VisitedNId.AddKey(InNId); }
00273       }
00274     }
00275     for (int e = 0; e < Node.GetOutDeg(); e++) {
00276       const int OutNId = Node.GetOutNId(e);
00277       if (! VisitedNId.IsKey(OutNId)) {
00278         NIdQ.Push(OutNId);  VisitedNId.AddKey(OutNId); }
00279     }
00280   }
00281   CnCom.Gen(VisitedNId.Len(), 0);
00282   for (int i = 0; i < VisitedNId.Len(); i++) {
00283     CnCom.Add(VisitedNId.GetKey(i));
00284   }
00285 }
00286 
00287 template <class PGraph> 
00288 bool IsConnected(const PGraph& Graph) {
00289   return IsWeaklyConn(Graph);
00290 }
00291 
00292 template <class PGraph>
00293 bool IsWeaklyConn(const PGraph& Graph) {
00294   THashSet<TInt> VisitedNId(Graph->GetNodes());
00295   TSnapQueue<int> NIdQ(Graph->GetNodes()+1);
00296   typename PGraph::TObj::TNodeI NI;
00297   // the rest of the nodes
00298   NIdQ.Push(Graph->BegNI().GetId());
00299   while (! NIdQ.Empty()) {
00300     const typename PGraph::TObj::TNodeI Node = Graph->GetNI(NIdQ.Top());  NIdQ.Pop();
00301     if (HasGraphFlag(typename PGraph::TObj, gfDirected)) {
00302       for (int e = 0; e < Node.GetInDeg(); e++) {
00303         const int InNId = Node.GetInNId(e);
00304         if (! VisitedNId.IsKey(InNId)) { NIdQ.Push(InNId);  VisitedNId.AddKey(InNId); }
00305       }
00306     }
00307     for (int e = 0; e < Node.GetOutDeg(); e++) {
00308       const int OutNId = Node.GetOutNId(e);
00309       if (! VisitedNId.IsKey(OutNId)) { NIdQ.Push(OutNId);  VisitedNId.AddKey(OutNId); }
00310     }
00311   }
00312   if (VisitedNId.Len() < Graph->GetNodes()) { return false; }
00313   return true;
00314 }
00315 
00316 template <class PGraph>
00317 void GetWccSzCnt(const PGraph& Graph, TIntPrV& WccSzCnt) {
00318   THashSet<TInt> VisitedNId(Graph->GetNodes());
00319   TIntH SzToCntH;
00320   TSnapQueue<int> NIdQ(Graph->GetNodes()+1);
00321   typename PGraph::TObj::TNodeI NI;
00322   int Cnt = 0;
00323   // zero degree nodes
00324   for (NI = Graph->BegNI(); NI < Graph->EndNI(); NI++) {
00325     if (NI.GetDeg() == 0) { Cnt++;  VisitedNId.AddKey(NI.GetId()); }
00326   }
00327   if (Cnt > 0) SzToCntH.AddDat(1, Cnt);
00328   // the rest of the nodes
00329   for (NI = Graph->BegNI(); NI < Graph->EndNI(); NI++) {
00330     if (! VisitedNId.IsKey(NI.GetId())) {
00331       VisitedNId.AddKey(NI.GetId());
00332       NIdQ.Clr(false);  NIdQ.Push(NI.GetId());
00333       Cnt = 0;
00334       while (! NIdQ.Empty()) {
00335         const typename PGraph::TObj::TNodeI Node = Graph->GetNI(NIdQ.Top());  NIdQ.Pop();
00336         if (HasGraphFlag(typename PGraph::TObj, gfDirected)) {
00337           for (int e = 0; e < Node.GetInDeg(); e++) {
00338             const int InNId = Node.GetInNId(e);
00339             if (! VisitedNId.IsKey(InNId)) { NIdQ.Push(InNId);  VisitedNId.AddKey(InNId); }
00340           }
00341         }
00342         for (int e = 0; e < Node.GetOutDeg(); e++) {
00343           const int OutNId = Node.GetOutNId(e);
00344           if (! VisitedNId.IsKey(OutNId)) { NIdQ.Push(OutNId);  VisitedNId.AddKey(OutNId); }
00345         }
00346         Cnt++;
00347       }
00348       SzToCntH.AddDat(Cnt) += 1;
00349     }
00350   }
00351   SzToCntH.GetKeyDatPrV(WccSzCnt);
00352   WccSzCnt.Sort(true);
00353 }
00354 
00355 template <class PGraph>
00356 void GetWccs(const PGraph& Graph, TCnComV& CnComV) {
00357   typename PGraph::TObj::TNodeI NI;
00358   THashSet<TInt> VisitedNId(Graph->GetNodes()+1);
00359   TSnapQueue<int> NIdQ(Graph->GetNodes()+1);
00360   TIntV CcNIdV;
00361   CnComV.Clr();  CcNIdV.Gen(1);
00362   // zero degree nodes
00363   for (NI = Graph->BegNI(); NI < Graph->EndNI(); NI++) {
00364     if (NI.GetDeg() == 0) {
00365       const int NId = NI.GetId();
00366       VisitedNId.AddKey(NId);
00367       CcNIdV[0] = NId;  CnComV.Add(CcNIdV);
00368     }
00369   }
00370   // the rest of the nodes
00371   for (NI = Graph->BegNI(); NI < Graph->EndNI(); NI++) {
00372     const int NId = NI.GetId();
00373     if (! VisitedNId.IsKey(NId)) {
00374       VisitedNId.AddKey(NId);
00375       NIdQ.Clr(false);  NIdQ.Push(NId);
00376       CcNIdV.Clr();  CcNIdV.Add(NId);
00377       while (! NIdQ.Empty()) {
00378         const typename PGraph::TObj::TNodeI Node = Graph->GetNI(NIdQ.Top());  NIdQ.Pop();
00379         if (HasGraphFlag(typename PGraph::TObj, gfDirected)) {
00380           for (int e = 0; e < Node.GetInDeg(); e++) {
00381             const int InNId = Node.GetInNId(e);
00382             if (! VisitedNId.IsKey(InNId)) {
00383               NIdQ.Push(InNId);  VisitedNId.AddKey(InNId);  CcNIdV.Add(InNId); }
00384           }
00385         }
00386         for (int e = 0; e < Node.GetOutDeg(); e++) {
00387           const int OutNId = Node.GetOutNId(e);
00388           if (! VisitedNId.IsKey(OutNId)) {
00389             NIdQ.Push(OutNId);  VisitedNId.AddKey(OutNId);  CcNIdV.Add(OutNId); }
00390         }
00391       }
00392       CcNIdV.Sort(true);
00393       CnComV.Add(TCnCom(CcNIdV)); // add wcc comoponent
00394     }
00395   }
00396   CnComV.Sort(false);
00397 }
00398 
00399 template <class PGraph>
00400 void GetSccSzCnt(const PGraph& Graph, TIntPrV& SccSzCnt) {
00401   TSccVisitor<PGraph, true> Visitor(Graph);
00402   TCnCom::GetDfsVisitor(Graph, Visitor);
00403   Visitor.SccCntH.GetKeyDatPrV(SccSzCnt);
00404   SccSzCnt.Sort(true);
00405 }
00406 
00407 template <class PGraph>
00408 void GetSccs(const PGraph& Graph, TCnComV& CnComV) {
00409   TSccVisitor<PGraph, false> Visitor(Graph);
00410   TCnCom::GetDfsVisitor(Graph, Visitor);
00411   CnComV = Visitor.CnComV;
00412 }
00413 
00414 template <class PGraph> 
00415 double GetMxWccSz(const PGraph& Graph) {
00416   TCnComV CnComV;
00417   GetWccs(Graph, CnComV);
00418   if (Graph->GetNodes() == 0) { return 0; }
00419   else { return CnComV[0].Len() / double(Graph->GetNodes()); }
00420 }
00421 
00422 template <class PGraph>
00423 PGraph GetMxWcc(const PGraph& Graph) {
00424   TCnComV CnComV;
00425   GetWccs(Graph, CnComV);
00426   if (CnComV.Empty()) { return PGraph::TObj::New(); }
00427   int CcId = 0, MxSz = 0;
00428   for (int i = 0; i < CnComV.Len(); i++) {
00429     if (MxSz < CnComV[i].Len()) {
00430       MxSz=CnComV[i].Len();  CcId=i; }
00431   }
00432   if (CnComV[CcId].Len()==Graph->GetNodes()) { 
00433     return Graph; }
00434   else { 
00435     return TSnap::GetSubGraph(Graph, CnComV[CcId]()); 
00436   }
00437 }
00438 
00439 template <class PGraph>
00440 PGraph GetMxScc(const PGraph& Graph) {
00441   TCnComV CnComV;
00442   GetSccs(Graph, CnComV);
00443   if (CnComV.Empty()) { return PGraph::TObj::New(); }
00444   int CcId = 0, MxSz = 0;
00445   for (int i = 0; i < CnComV.Len(); i++) {
00446     if (MxSz < CnComV[i].Len()) {
00447       MxSz=CnComV[i].Len();  CcId=i; }
00448   }
00449   if (CnComV[CcId].Len()==Graph->GetNodes()) { 
00450     return Graph; }
00451   else { 
00452     return TSnap::GetSubGraph(Graph, CnComV[CcId]()); 
00453   }
00454 }
00455 
00456 template <class PGraph>
00457 PGraph GetMxBiCon(const PGraph& Graph) {
00458   TCnComV CnComV;
00459   GetBiCon(TSnap::ConvertGraph<PUNGraph, PGraph>(Graph), CnComV);
00460   if (CnComV.Empty()) { return PGraph::TObj::New(); }
00461   int CcId = 0, MxSz = 0;
00462   for (int i = 0; i < CnComV.Len(); i++) {
00463     if (MxSz < CnComV[i].Len()) {
00464       MxSz=CnComV[i].Len();  CcId=i; }
00465   }
00466   if (CnComV[CcId].Len()==Graph->GetNodes()) { 
00467     return Graph; }
00468   else { 
00469     return TSnap::GetSubGraph(Graph, CnComV[CcId]()); 
00470   }
00471 }
00472 
00473 } // namespace TSnap