SNAP Library , Developer Reference
2013-01-07 14:03:36
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); 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