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