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