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