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
|
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