SNAP Library, Developer Reference  2012-10-02 12:56:23
SNAP, a general purpose network analysis and graph mining library
 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