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