SNAP Library 2.0, Developer Reference
2013-05-13 16:33:57
SNAP, a general purpose, high performance system for analysis and manipulation of large networks
|
00001 namespace TSnap { 00002 00004 // BFS and DFS 00006 00009 template <class PGraph> PNGraph GetBfsTree(const PGraph& Graph, const int& StartNId, const bool& FollowOut, const bool& FollowIn); 00011 template <class PGraph> int GetSubTreeSz(const PGraph& Graph, const int& StartNId, const bool& FollowOut, const bool& FollowIn, int& TreeSz, int& TreeDepth); 00013 00015 template <class PGraph> int GetNodesAtHop(const PGraph& Graph, const int& StartNId, const int& Hop, TIntV& NIdV, const bool& IsDir=false); 00017 00019 template <class PGraph> int GetNodesAtHops(const PGraph& Graph, const int& StartNId, TIntPrV& HopCntV, const bool& IsDir=false); 00020 00022 // Shortest paths 00024 00026 template <class PGraph> int GetShortPath(const PGraph& Graph, const int& SrcNId, const int& DstNId, const bool& IsDir=false); 00028 00032 template <class PGraph> int GetShortPath(const PGraph& Graph, const int& SrcNId, TIntH& NIdToDistH, const bool& IsDir=false, const int& MaxDist=TInt::Mx); 00033 00035 // Diameter 00036 00038 00040 template <class PGraph> int GetBfsFullDiam(const PGraph& Graph, const int& NTestNodes, const bool& IsDir=false); 00042 00044 template <class PGraph> double GetBfsEffDiam(const PGraph& Graph, const int& NTestNodes, const bool& IsDir=false); 00046 00048 template <class PGraph> double GetBfsEffDiam(const PGraph& Graph, const int& NTestNodes, const bool& IsDir, double& EffDiam, int& FullDiam); 00050 template <class PGraph> double GetBfsEffDiam(const PGraph& Graph, const int& NTestNodes, const bool& IsDir, double& EffDiam, int& FullDiam, double& AvgSPL); 00052 template <class PGraph> double GetBfsEffDiam(const PGraph& Graph, const int& NTestNodes, const TIntV& SubGraphNIdV, const bool& IsDir, double& EffDiam, int& FullDiam); 00053 00054 // TODO: Implement in the future 00055 //template <class PGraph> int GetRangeDist(const PGraph& Graph, const int& SrcNId, const int& DstNId, const bool& IsDir=false); 00056 //template <class PGraph> int GetShortPath(const PGraph& Graph, const int& SrcNId, TIntH& NIdToDistH, const bool& IsDir=false, const int& MaxDist=1000); 00057 //template <class PGraph> int GetShortPath(const PGraph& Graph, const int& SrcNId, const TIntSet& TargetSet, const bool& IsDir, TIntV& PathNIdV); 00058 //template <class PGraph> int GetShortPath(TIntH& NIdPrnH, TCcQueue<int>& NIdQ, const PGraph& Graph, const int& SrcNId, const TIntSet& TargetSet, const bool& IsDir, TIntV& PathNIdV); 00059 //template <class PGraph> int GetMxShortDist(const PGraph& Graph, const int& SrcNId, const bool& IsDir=false); 00060 //template <class PGraph> int GetMxShortDist(const PGraph& Graph, const int& SrcNId, const bool& IsDir, int& MxDistNId); 00061 //template <class PGraph> int GetMxShortDist(const PGraph& Graph, const int& SrcNId, const bool& IsDir, int& MxDistNId, TCcQueue<int>& NIdQ, TCcQueue<int>& DistQ, TIntSet& VisitedH); 00062 //template <class PGraph> int GetMxGreedyDist(const PGraph& Graph, const int& SrcNId, const bool& IsDir=false); 00063 //template <class PGraph> int GetMxGreedyDist(const PGraph& Graph, const int& SrcNId, const bool& IsDir, TCcQueue<int>& NIdQ, TCcQueue<int>& DistQ, TIntSet& VisitedH); 00064 //template <class PGraph> PNGraph GetShortPathsSubGraph(const PGraph& Graph, const TIntV& SubGraphNIdV); 00065 //template <class PGraph> PGraph GetWccPathsSubGraph(const PGraph& Graph, const TIntV& NIdV); 00066 //template <class PGraph> void GetSubTreeSz(const PGraph& Graph, const int& StartNId, const bool& FollowOutEdges, int& TreeSz, int& TreeDepth); 00067 00068 } // namespace TSnap 00069 00070 //#////////////////////////////////////////////// 00073 template<class PGraph> 00074 class TBreathFS { 00075 public: 00076 PGraph Graph; 00077 TSnapQueue<int> Queue; 00078 TInt StartNId; 00079 TIntH NIdDistH; 00080 public: 00081 TBreathFS(const PGraph& GraphPt, const bool& InitBigQ=true) : 00082 Graph(GraphPt), Queue(InitBigQ?Graph->GetNodes():1024), NIdDistH(InitBigQ?Graph->GetNodes():1024) { } 00084 void SetGraph(const PGraph& GraphPt); 00086 int DoBfs(const int& StartNode, const bool& FollowOut, const bool& FollowIn, const int& TargetNId=-1, const int& MxDist=TInt::Mx); 00088 int GetNVisited() const { return NIdDistH.Len(); } 00090 void GetVisitedNIdV(TIntV& NIdV) const { NIdDistH.GetKeyV(NIdV); } 00093 int GetHops(const int& SrcNId, const int& DstNId) const; 00096 int GetRndPath(const int& SrcNId, const int& DstNId, TIntV& PathNIdV) const; 00097 }; 00098 00099 template<class PGraph> 00100 void TBreathFS<PGraph>::SetGraph(const PGraph& GraphPt) { 00101 Graph=GraphPt; 00102 const int N=GraphPt->GetNodes(); 00103 if (Queue.Reserved() < N) { Queue.Gen(N); } 00104 if (NIdDistH.GetReservedKeyIds() < N) { NIdDistH.Gen(N); } 00105 } 00106 00107 template<class PGraph> 00108 int TBreathFS<PGraph>::DoBfs(const int& StartNode, const bool& FollowOut, const bool& FollowIn, const int& TargetNId, const int& MxDist) { 00109 StartNId = StartNode; 00110 IAssert(Graph->IsNode(StartNId)); 00111 // const typename PGraph::TObj::TNodeI StartNodeI = Graph->GetNI(StartNode); 00112 // IAssertR(StartNodeI.GetOutDeg() > 0, TStr::Fmt("No neighbors from start node %d.", StartNode)); 00113 NIdDistH.Clr(false); NIdDistH.AddDat(StartNId, 0); 00114 Queue.Clr(false); Queue.Push(StartNId); 00115 int v, MaxDist = 0; 00116 while (! Queue.Empty()) { 00117 const int NId = Queue.Top(); Queue.Pop(); 00118 const int Dist = NIdDistH.GetDat(NId); 00119 if (Dist == MxDist) { break; } // max distance limit reached 00120 const typename PGraph::TObj::TNodeI NodeI = Graph->GetNI(NId); 00121 if (FollowOut) { // out-links 00122 for (v = 0; v < NodeI.GetOutDeg(); v++) { // out-links 00123 const int DstNId = NodeI.GetOutNId(v); 00124 if (! NIdDistH.IsKey(DstNId)) { 00125 NIdDistH.AddDat(DstNId, Dist+1); 00126 MaxDist = TMath::Mx(MaxDist, Dist+1); 00127 if (DstNId == TargetNId) { return MaxDist; } 00128 Queue.Push(DstNId); 00129 } 00130 } 00131 } 00132 if (FollowIn) { // in-links 00133 for (v = 0; v < NodeI.GetInDeg(); v++) { 00134 const int DstNId = NodeI.GetInNId(v); 00135 if (! NIdDistH.IsKey(DstNId)) { 00136 NIdDistH.AddDat(DstNId, Dist+1); 00137 MaxDist = TMath::Mx(MaxDist, Dist+1); 00138 if (DstNId == TargetNId) { return MaxDist; } 00139 Queue.Push(DstNId); 00140 } 00141 } 00142 } 00143 } 00144 return MaxDist; 00145 } 00146 00147 template<class PGraph> 00148 int TBreathFS<PGraph>::GetHops(const int& SrcNId, const int& DstNId) const { 00149 TInt Dist; 00150 if (SrcNId!=StartNId) { return -1; } 00151 if (! NIdDistH.IsKeyGetDat(DstNId, Dist)) { return -1; } 00152 return Dist.Val; 00153 } 00154 00155 template<class PGraph> 00156 int TBreathFS<PGraph>::GetRndPath(const int& SrcNId, const int& DstNId, TIntV& PathNIdV) const { 00157 PathNIdV.Clr(false); 00158 if (SrcNId!=StartNId || ! NIdDistH.IsKey(DstNId)) { return -1; } 00159 PathNIdV.Add(DstNId); 00160 TIntV CloserNIdV; 00161 int CurNId = DstNId; 00162 TInt CurDist, NextDist; 00163 while (CurNId != SrcNId) { 00164 typename PGraph::TObj::TNodeI NI = Graph->GetNI(CurNId); 00165 IAssert(NIdDistH.IsKeyGetDat(CurNId, CurDist)); 00166 CloserNIdV.Clr(false); 00167 for (int e = 0; e < NI.GetDeg(); e++) { 00168 const int Next = NI.GetNbrNId(e); 00169 IAssert(NIdDistH.IsKeyGetDat(Next, NextDist)); 00170 if (NextDist == CurDist-1) { CloserNIdV.Add(Next); } 00171 } 00172 IAssert(! CloserNIdV.Empty()); 00173 CurNId = CloserNIdV[TInt::Rnd.GetUniDevInt(CloserNIdV.Len())]; 00174 PathNIdV.Add(CurNId); 00175 } 00176 PathNIdV.Reverse(); 00177 return PathNIdV.Len()-1; 00178 } 00179 00181 // Implementation 00182 namespace TSnap { 00183 00184 template <class PGraph> 00185 PNGraph GetBfsTree(const PGraph& Graph, const int& StartNId, const bool& FollowOut, const bool& FollowIn) { 00186 TBreathFS<PGraph> BFS(Graph, false); 00187 BFS.DoBfs(StartNId, FollowOut, FollowIn, -1, TInt::Mx); 00188 PNGraph Tree = TNGraph::New(); 00189 BFS.NIdDistH.SortByDat(); 00190 for (int i = 0; i < BFS.NIdDistH.Len(); i++) { 00191 const int NId = BFS.NIdDistH.GetKey(i); 00192 const int Dist = BFS.NIdDistH[i]; 00193 typename PGraph::TObj::TNodeI NI = Graph->GetNI(NId); 00194 if (!Tree->IsNode(NId)) { 00195 Tree->AddNode(NId); 00196 } 00197 if (FollowOut) { 00198 for (int e = 0; e < NI.GetInDeg(); e++) { 00199 const int Prev = NI.GetInNId(e); 00200 if (Tree->IsNode(Prev) && BFS.NIdDistH.GetDat(Prev)==Dist-1) { 00201 Tree->AddEdge(Prev, NId); } 00202 } 00203 } 00204 if (FollowIn) { 00205 for (int e = 0; e < NI.GetOutDeg(); e++) { 00206 const int Prev = NI.GetOutNId(e); 00207 if (Tree->IsNode(Prev) && BFS.NIdDistH.GetDat(Prev)==Dist-1) { 00208 Tree->AddEdge(Prev, NId); } 00209 } 00210 } 00211 } 00212 return Tree; 00213 } 00214 00215 template <class PGraph> 00216 int GetSubTreeSz(const PGraph& Graph, const int& StartNId, const bool& FollowOut, const bool& FollowIn, int& TreeSz, int& TreeDepth) { 00217 TBreathFS<PGraph> BFS(Graph); 00218 BFS.DoBfs(StartNId, FollowOut, FollowIn, -1, TInt::Mx); 00219 TreeSz = BFS.NIdDistH.Len(); 00220 TreeDepth = 0; 00221 for (int i = 0; i < BFS.NIdDistH.Len(); i++) { 00222 TreeDepth = TMath::Mx(TreeDepth, BFS.NIdDistH[i].Val); 00223 } 00224 return TreeSz; 00225 } 00226 00227 template <class PGraph> 00228 int GetNodesAtHop(const PGraph& Graph, const int& StartNId, const int& Hop, TIntV& NIdV, const bool& IsDir) { 00229 TBreathFS<PGraph> BFS(Graph); 00230 BFS.DoBfs(StartNId, true, !IsDir, -1, Hop); 00231 NIdV.Clr(false); 00232 for (int i = 0; i < BFS.NIdDistH.Len(); i++) { 00233 if (BFS.NIdDistH[i] == Hop) { 00234 NIdV.Add(BFS.NIdDistH.GetKey(i)); } 00235 } 00236 return NIdV.Len(); 00237 } 00238 00239 template <class PGraph> 00240 int GetNodesAtHops(const PGraph& Graph, const int& StartNId, TIntPrV& HopCntV, const bool& IsDir) { 00241 TBreathFS<PGraph> BFS(Graph); 00242 BFS.DoBfs(StartNId, true, !IsDir, -1, TInt::Mx); 00243 TIntH HopCntH; 00244 for (int i = 0; i < BFS.NIdDistH.Len(); i++) { 00245 HopCntH.AddDat(BFS.NIdDistH[i]) += 1; 00246 } 00247 HopCntH.GetKeyDatPrV(HopCntV); 00248 HopCntV.Sort(); 00249 return HopCntV.Len(); 00250 } 00251 00252 template <class PGraph> 00253 int GetShortPath(const PGraph& Graph, const int& SrcNId, TIntH& NIdToDistH, const bool& IsDir, const int& MaxDist) { 00254 TBreathFS<PGraph> BFS(Graph); 00255 BFS.DoBfs(SrcNId, true, ! IsDir, -1, MaxDist); 00256 NIdToDistH.Clr(); 00257 NIdToDistH.Swap(BFS.NIdDistH); 00258 return NIdToDistH[NIdToDistH.Len()-1]; 00259 } 00260 00261 template <class PGraph> 00262 int GetShortPath(const PGraph& Graph, const int& SrcNId, const int& DstNId, const bool& IsDir) { 00263 TBreathFS<PGraph> BFS(Graph); 00264 BFS.DoBfs(SrcNId, true, ! IsDir, DstNId, TInt::Mx); 00265 return BFS.GetHops(SrcNId, DstNId); 00266 } 00267 00268 template <class PGraph> 00269 int GetBfsFullDiam(const PGraph& Graph, const int& NTestNodes, const bool& IsDir) { 00270 int FullDiam; 00271 double EffDiam; 00272 GetBfsEffDiam(Graph, NTestNodes, IsDir, EffDiam, FullDiam); 00273 return FullDiam; 00274 } 00275 00276 template <class PGraph> 00277 double GetBfsEffDiam(const PGraph& Graph, const int& NTestNodes, const bool& IsDir) { 00278 int FullDiam; 00279 double EffDiam; 00280 GetBfsEffDiam(Graph, NTestNodes, IsDir, EffDiam, FullDiam); 00281 return EffDiam; 00282 } 00283 00284 template <class PGraph> 00285 double GetBfsEffDiam(const PGraph& Graph, const int& NTestNodes, const bool& IsDir, double& EffDiam, int& FullDiam) { 00286 double AvgDiam; 00287 EffDiam = -1; FullDiam = -1; 00288 return GetBfsEffDiam(Graph, NTestNodes, IsDir, EffDiam, FullDiam, AvgDiam); 00289 } 00290 00291 template <class PGraph> 00292 double GetBfsEffDiam(const PGraph& Graph, const int& NTestNodes, const bool& IsDir, double& EffDiam, int& FullDiam, double& AvgSPL) { 00293 EffDiam = -1; FullDiam = -1; AvgSPL = -1; 00294 TIntFltH DistToCntH; 00295 TBreathFS<PGraph> BFS(Graph); 00296 // shotest paths 00297 TIntV NodeIdV; 00298 Graph->GetNIdV(NodeIdV); NodeIdV.Shuffle(TInt::Rnd); 00299 for (int tries = 0; tries < TMath::Mn(NTestNodes, Graph->GetNodes()); tries++) { 00300 const int NId = NodeIdV[tries]; 00301 BFS.DoBfs(NId, true, ! IsDir, -1, TInt::Mx); 00302 for (int i = 0; i < BFS.NIdDistH.Len(); i++) { 00303 DistToCntH.AddDat(BFS.NIdDistH[i]) += 1; } 00304 } 00305 TIntFltKdV DistNbrsPdfV; 00306 double SumPathL=0, PathCnt=0; 00307 for (int i = 0; i < DistToCntH.Len(); i++) { 00308 DistNbrsPdfV.Add(TIntFltKd(DistToCntH.GetKey(i), DistToCntH[i])); 00309 SumPathL += DistToCntH.GetKey(i) * DistToCntH[i]; 00310 PathCnt += DistToCntH[i]; 00311 } 00312 DistNbrsPdfV.Sort(); 00313 EffDiam = TSnap::TSnapDetail::CalcEffDiamPdf(DistNbrsPdfV, 0.9); // effective diameter (90-th percentile) 00314 FullDiam = DistNbrsPdfV.Last().Key; // approximate full diameter (max shortest path length over the sampled nodes) 00315 AvgSPL = SumPathL/PathCnt; // average shortest path length 00316 return EffDiam; 00317 } 00318 00319 template <class PGraph> 00320 double GetBfsEffDiam(const PGraph& Graph, const int& NTestNodes, const TIntV& SubGraphNIdV, const bool& IsDir, double& EffDiam, int& FullDiam) { 00321 EffDiam = -1; 00322 FullDiam = -1; 00323 00324 TIntFltH DistToCntH; 00325 TBreathFS<PGraph> BFS(Graph); 00326 // shotest paths 00327 TIntV NodeIdV(SubGraphNIdV); NodeIdV.Shuffle(TInt::Rnd); 00328 TInt Dist; 00329 for (int tries = 0; tries < TMath::Mn(NTestNodes, SubGraphNIdV.Len()); tries++) { 00330 const int NId = NodeIdV[tries]; 00331 BFS.DoBfs(NId, true, ! IsDir, -1, TInt::Mx); 00332 for (int i = 0; i < SubGraphNIdV.Len(); i++) { 00333 if (BFS.NIdDistH.IsKeyGetDat(SubGraphNIdV[i], Dist)) { 00334 DistToCntH.AddDat(Dist) += 1; 00335 } 00336 } 00337 } 00338 TIntFltKdV DistNbrsPdfV; 00339 for (int i = 0; i < DistToCntH.Len(); i++) { 00340 DistNbrsPdfV.Add(TIntFltKd(DistToCntH.GetKey(i), DistToCntH[i])); 00341 } 00342 DistNbrsPdfV.Sort(); 00343 EffDiam = TSnap::TSnapDetail::CalcEffDiamPdf(DistNbrsPdfV, 0.9); // effective diameter (90-th percentile) 00344 FullDiam = DistNbrsPdfV.Last().Key; // approximate full diameter (max shortest path length over the sampled nodes) 00345 return EffDiam; // average shortest path length 00346 } 00347 00348 } // namespace TSnap