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
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines
alg.h
Go to the documentation of this file.
00001 namespace TSnap {
00002 
00004 // Node Degrees
00005 
00007 template <class PGraph> int CntInDegNodes(const PGraph& Graph, const int& NodeInDeg);
00009 template <class PGraph> int CntOutDegNodes(const PGraph& Graph, const int& NodeOutDeg);
00011 template <class PGraph> int CntDegNodes(const PGraph& Graph, const int& NodeDeg);
00013 template <class PGraph> int CntNonZNodes(const PGraph& Graph);
00014 // TODO ROK document CntEdgesToSet()
00015 template <class PGraph> int CntEdgesToSet(const PGraph& Graph, const int& NId, const TIntSet& NodeSet);
00016 
00018 template <class PGraph> int GetMxDegNId(const PGraph& Graph);
00020 template <class PGraph> int GetMxInDegNId(const PGraph& Graph);
00022 template <class PGraph> int GetMxOutDegNId(const PGraph& Graph);
00023 
00024 // degree histograms
00026 template <class PGraph> void GetInDegCnt(const PGraph& Graph, TIntPrV& DegToCntV);
00028 template <class PGraph> void GetInDegCnt(const PGraph& Graph, TFltPrV& DegToCntV);
00030 template <class PGraph> void GetOutDegCnt(const PGraph& Graph, TIntPrV& DegToCntV);
00032 template <class PGraph> void GetOutDegCnt(const PGraph& Graph, TFltPrV& DegToCntV);
00034 template <class PGraph> void GetDegCnt(const PGraph& Graph, TIntPrV& DegToCntV);
00036 template <class PGraph> void GetDegCnt(const PGraph& Graph, TFltPrV& DegToCntV);
00038 template <class PGraph> void GetDegSeqV(const PGraph& Graph, TIntV& DegV);
00040 template <class PGraph> void GetDegSeqV(const PGraph& Graph, TIntV& InDegV, TIntV& OutDegV);
00041 
00043 template <class PGraph> void GetNodeInDegV(const PGraph& Graph, TIntPrV& NIdInDegV);
00045 template <class PGraph> void GetNodeOutDegV(const PGraph& Graph, TIntPrV& NIdOutDegV);
00046 
00048 template <class PGraph> int CntUniqUndirEdges(const PGraph& Graph);
00050 template <class PGraph> int CntUniqDirEdges(const PGraph& Graph);
00052 template <class PGraph> int CntUniqBiDirEdges(const PGraph& Graph);
00054 template <class PGraph> int CntSelfEdges(const PGraph& Graph);
00055 
00057 // Manipulation
00059 template <class PGraph> PGraph GetUnDir(const PGraph& Graph);
00061 template <class PGraph> void MakeUnDir(const PGraph& Graph);
00063 template <class PGraph> void AddSelfEdges(const PGraph& Graph);
00065 template <class PGraph> void DelSelfEdges(const PGraph& Graph);
00066 
00067 //TODO Implement:
00068 //template <class PGraph> void DelBiDirEdges(const PGraph& Graph);
00069 
00071 template <class PGraph> void DelNodes(PGraph& Graph, const TIntV& NIdV);
00073 template <class PGraph> void DelZeroDegNodes(PGraph& Graph);
00075 template <class PGraph> void DelDegKNodes(PGraph& Graph, const int& OutDegK, const int& InDegK);
00076 
00078 // Tree Routines
00079 template <class PGraph> bool IsTree(const PGraph& Graph, int& RootNIdX);
00080 template <class PGraph> int GetTreeRootNId(const PGraph& Graph) { int RootNId; bool Tree; Tree = IsTree(Graph, RootNId);  Assert(Tree);  return RootNId; }
00081 template <class PGraph> void GetTreeSig(const PGraph& Graph, const int& RootNId, TIntV& Sig);
00082 template <class PGraph> void GetTreeSig(const PGraph& Graph, const int& RootNId, TIntV& Sig, TIntPrV& NodeMap);
00083 
00085 // Implementation
00086 template <class PGraph>
00087 int CntInDegNodes(const PGraph& Graph, const int& NodeInDeg) {
00088   int Cnt = 0;
00089   for (typename PGraph::TObj::TNodeI NI = Graph->BegNI(); NI < Graph->EndNI(); NI++) {
00090     if (NI.GetInDeg() == NodeInDeg) Cnt++;
00091   }
00092   return Cnt;
00093 }
00094 
00095 template <class PGraph>
00096 int CntOutDegNodes(const PGraph& Graph, const int& NodeOutDeg) {
00097   int Cnt = 0;
00098   for (typename PGraph::TObj::TNodeI NI = Graph->BegNI(); NI < Graph->EndNI(); NI++) {
00099     if (NI.GetOutDeg() == NodeOutDeg) Cnt++;
00100   }
00101   return Cnt;
00102 }
00103 
00104 template <class PGraph>
00105 int CntDegNodes(const PGraph& Graph, const int& NodeDeg) {
00106   int Cnt = 0;
00107   for (typename PGraph::TObj::TNodeI NI = Graph->BegNI(); NI < Graph->EndNI(); NI++) {
00108     if (NI.GetDeg() == NodeDeg) Cnt++;
00109   }
00110   return Cnt;
00111 }
00112 
00113 template <class PGraph>
00114 int CntNonZNodes(const PGraph& Graph) {
00115   int Cnt = 0;
00116   for (typename PGraph::TObj::TNodeI NI = Graph->BegNI(); NI < Graph->EndNI(); NI++) {
00117     if (NI.GetDeg() > 0) Cnt++;
00118   }
00119   return Cnt;
00120 }
00121 
00122 template <class PGraph> 
00123 int CntEdgesToSet(const PGraph& Graph, const int& NId, const TIntSet& NodeSet) {
00124   if (! Graph->IsNode(NId)) { return 0; }
00125   const bool IsDir = Graph->HasFlag(gfDirected);
00126   const typename PGraph::TObj::TNodeI NI = Graph->GetNI(NId);
00127   if (! IsDir) {
00128     int EdgesToSet = 0;
00129     for (int e = 0; e < NI.GetOutDeg(); e++) {
00130       if (NodeSet.IsKey(NI.GetOutNId(e))) { EdgesToSet++; } }
00131     return EdgesToSet;
00132   } else {
00133     TIntSet Set(NI.GetDeg());
00134     for (int e = 0; e < NI.GetOutDeg(); e++) {
00135       if (NodeSet.IsKey(NI.GetOutNId(e))) { Set.AddKey(NI.GetOutNId(e)); } }
00136     for (int e = 0; e < NI.GetInDeg(); e++) {
00137       if (NodeSet.IsKey(NI.GetInNId(e))) { Set.AddKey(NI.GetInNId(e)); } }
00138     return Set.Len();
00139   }
00140 }
00141 
00142 template <class PGraph> 
00143 int GetMxDegNId(const PGraph& Graph) {
00144   TIntV MxDegV;
00145   int MxDeg=-1;
00146   for (typename PGraph::TObj::TNodeI NI = Graph->BegNI(); NI < Graph->EndNI(); NI++) {
00147     if (MxDeg < NI.GetDeg()) { MxDegV.Clr(); MxDeg = NI.GetDeg(); }
00148     if (MxDeg == NI.GetDeg()) { MxDegV.Add(NI.GetId()); }
00149   }
00150   EAssertR(! MxDegV.Empty(), "Input graph is empty!");
00151   return MxDegV[TInt::Rnd.GetUniDevInt(MxDegV.Len())];
00152 }
00153 
00154 template <class PGraph> 
00155 int GetMxInDegNId(const PGraph& Graph) {
00156   TIntV MxDegV;
00157   int MxDeg=-1;
00158   for (typename PGraph::TObj::TNodeI NI = Graph->BegNI(); NI < Graph->EndNI(); NI++) {
00159     if (MxDeg < NI.GetInDeg()) { MxDegV.Clr(); MxDeg = NI.GetInDeg(); }
00160     if (MxDeg == NI.GetInDeg()) { MxDegV.Add(NI.GetId()); }
00161   }
00162   EAssertR(! MxDegV.Empty(), "Input graph is empty!");
00163   return MxDegV[TInt::Rnd.GetUniDevInt(MxDegV.Len())];
00164 }
00165 
00166 template <class PGraph> 
00167 int GetMxOutDegNId(const PGraph& Graph) {
00168   TIntV MxDegV;
00169   int MxDeg=-1;
00170   for (typename PGraph::TObj::TNodeI NI = Graph->BegNI(); NI < Graph->EndNI(); NI++) {
00171     if (MxDeg < NI.GetOutDeg()) { MxDegV.Clr(); MxDeg = NI.GetOutDeg(); }
00172     if (MxDeg == NI.GetOutDeg()) { MxDegV.Add(NI.GetId()); }
00173   }
00174   EAssertR(! MxDegV.Empty(), "Input graph is empty!");
00175   return MxDegV[TInt::Rnd.GetUniDevInt(MxDegV.Len())];
00176 }
00177 
00178 template <class PGraph>
00179 void GetInDegCnt(const PGraph& Graph, TIntPrV& DegToCntV) {
00180   TIntH DegToCntH;
00181   for (typename PGraph::TObj::TNodeI NI = Graph->BegNI(); NI < Graph->EndNI(); NI++) {
00182     DegToCntH.AddDat(NI.GetInDeg())++; }
00183   DegToCntV.Gen(DegToCntH.Len(), 0);
00184   for (int i = 0; i < DegToCntH.Len(); i++) {
00185     DegToCntV.Add(TIntPr(DegToCntH.GetKey(i), DegToCntH[i])); }
00186   DegToCntV.Sort();
00187 }
00188 
00189 template <class PGraph>
00190 void GetInDegCnt(const PGraph& Graph, TFltPrV& DegToCntV) {
00191   TIntH DegToCntH;
00192   for (typename PGraph::TObj::TNodeI NI = Graph->BegNI(); NI < Graph->EndNI(); NI++) {
00193     DegToCntH.AddDat(NI.GetInDeg())++; }
00194   DegToCntV.Gen(DegToCntH.Len(), 0);
00195   for (int i = 0; i < DegToCntH.Len(); i++) {
00196     DegToCntV.Add(TFltPr(DegToCntH.GetKey(i).Val, DegToCntH[i].Val)); }
00197   DegToCntV.Sort();
00198 }
00199 
00200 template <class PGraph>
00201 void GetOutDegCnt(const PGraph& Graph, TIntPrV& DegToCntV) {
00202   TIntH DegToCntH;
00203   for (typename PGraph::TObj::TNodeI NI = Graph->BegNI(); NI < Graph->EndNI(); NI++) {
00204     DegToCntH.AddDat(NI.GetOutDeg())++; }
00205   DegToCntV.Gen(DegToCntH.Len(), 0);
00206   for (int i = 0; i < DegToCntH.Len(); i++) {
00207     DegToCntV.Add(TIntPr(DegToCntH.GetKey(i), DegToCntH[i])); }
00208   DegToCntV.Sort();
00209 }
00210 
00211 template <class PGraph>
00212 void GetOutDegCnt(const PGraph& Graph, TFltPrV& DegToCntV) {
00213   TIntH DegToCntH;
00214   for (typename PGraph::TObj::TNodeI NI = Graph->BegNI(); NI < Graph->EndNI(); NI++) {
00215     DegToCntH.AddDat(NI.GetOutDeg())++; }
00216   DegToCntV.Gen(DegToCntH.Len(), 0);
00217   for (int i = 0; i < DegToCntH.Len(); i++) {
00218     DegToCntV.Add(TFltPr(DegToCntH.GetKey(i).Val, DegToCntH[i].Val)); }
00219   DegToCntV.Sort();
00220 }
00221 
00222 template <class PGraph>
00223 void GetDegCnt(const PGraph& Graph, TIntPrV& DegToCntV) {
00224   TIntH DegToCntH;
00225   for (typename PGraph::TObj::TNodeI NI = Graph->BegNI(); NI < Graph->EndNI(); NI++) {
00226     DegToCntH.AddDat(NI.GetDeg())++; }
00227   DegToCntV.Gen(DegToCntH.Len(), 0);
00228   for (int i = 0; i < DegToCntH.Len(); i++) {
00229     DegToCntV.Add(TIntPr(DegToCntH.GetKey(i), DegToCntH[i])); }
00230   DegToCntV.Sort();
00231 }
00232 
00233 template <class PGraph>
00234 void GetDegCnt(const PGraph& Graph, TFltPrV& DegToCntV) {
00235   TIntH DegToCntH;
00236   for (typename PGraph::TObj::TNodeI NI = Graph->BegNI(); NI < Graph->EndNI(); NI++) {
00237     DegToCntH.AddDat(NI.GetDeg())++; }
00238   DegToCntV.Gen(DegToCntH.Len(), 0);
00239   for (int i = 0; i < DegToCntH.Len(); i++) {
00240     DegToCntV.Add(TFltPr(DegToCntH.GetKey(i).Val, DegToCntH[i].Val)); }
00241   DegToCntV.Sort();
00242 }
00243 
00244 template <class PGraph> 
00245 void GetDegSeqV(const PGraph& Graph, TIntV& DegV) {
00246   DegV.Gen(Graph->GetNodes(), 0);
00247   for (typename PGraph::TObj::TNodeI NI = Graph->BegNI(); NI < Graph->EndNI(); NI++) {
00248     DegV.Add(NI.GetDeg()); 
00249   }
00250 }
00251 
00252 template <class PGraph> 
00253 void GetDegSeqV(const PGraph& Graph, TIntV& InDegV, TIntV& OutDegV) {
00254   InDegV.Gen(Graph->GetNodes(), 0);
00255   OutDegV.Gen(Graph->GetNodes(), 0);
00256   for (typename PGraph::TObj::TNodeI NI = Graph->BegNI(); NI < Graph->EndNI(); NI++) {
00257     InDegV.Add(NI.GetInDeg()); 
00258     OutDegV.Add(NI.GetOutDeg());
00259   }
00260 }
00261 
00262 template <class PGraph> 
00263 void GetNodeInDegV(const PGraph& Graph, TIntPrV& NIdInDegV) {
00264   NIdInDegV.Reserve(Graph->GetNodes(), 0);
00265   for (typename PGraph::TObj::TNodeI NI = Graph->BegNI(); NI < Graph->EndNI(); NI++) {
00266     NIdInDegV.Add(TIntPr(NI.GetId(), NI.GetInDeg()));
00267   }
00268 }
00269 
00270 template <class PGraph> 
00271 void GetNodeOutDegV(const PGraph& Graph, TIntPrV& NIdOutDegV) {
00272   NIdOutDegV.Reserve(Graph->GetNodes(), 0);
00273   for (typename PGraph::TObj::TNodeI NI = Graph->BegNI(); NI < Graph->EndNI(); NI++) {
00274     NIdOutDegV.Add(TIntPr(NI.GetId(), NI.GetOutDeg()));
00275   }
00276 }
00277 
00278 template <class PGraph>
00279 int CntUniqUndirEdges(const PGraph& Graph) {
00280   TIntSet NbrSet;
00281   int Cnt = 0;
00282   for (typename PGraph::TObj::TNodeI NI = Graph->BegNI(); NI < Graph->EndNI(); NI++) {
00283     NbrSet.Clr(false);
00284     for (int e = 0; e < NI.GetDeg(); e++) { // unique neighbors of a node
00285       if (NI.GetNbrNId(e) != NI.GetId()) { // skip self-edges
00286         NbrSet.AddKey(NI.GetNbrNId(e)); }
00287     }
00288     Cnt += NbrSet.Len();
00289   }
00290   return Cnt / 2;
00291 }
00292 
00293 template <class PGraph>
00294 int CntUniqDirEdges(const PGraph& Graph) {
00295   TIntSet NbrSet;
00296   int Cnt = 0;
00297   for (typename PGraph::TObj::TNodeI NI = Graph->BegNI(); NI < Graph->EndNI(); NI++) {
00298     NbrSet.Clr(false);
00299     for (int e = 0; e < NI.GetOutDeg(); e++) { // unique out-neighbors of a node
00300       if (NI.GetOutNId(e) != NI.GetId()) { // skip self-edges
00301         NbrSet.AddKey(NI.GetOutNId(e)); }
00302     }
00303     Cnt += NbrSet.Len();
00304   }
00305   return Cnt;
00306 }
00307 
00308 template <class PGraph>
00309 int CntUniqBiDirEdges(const PGraph& Graph) {
00310   if (! Graph->HasFlag(gfDirected)) { // graph is undirected
00311     return CntUniqUndirEdges(Graph);  // then every edge is bi-directional
00312   }
00313   TIntSet NbrSet;
00314   int Cnt = 0;
00315   for (typename PGraph::TObj::TNodeI NI = Graph->BegNI(); NI < Graph->EndNI(); NI++) {
00316     const int SrcId = NI.GetId();
00317     for (int e = 0; e < NI.GetOutDeg(); e++) {
00318       const int DstId = NI.GetOutNId(e);
00319       if (DstId <= SrcId) { continue; } // count each un-dir edge only once
00320       if (Graph->IsEdge(DstId, SrcId)) { Cnt++; }
00321     }
00322   }
00323   return Cnt;
00324 }
00325 
00326 template <class PGraph> 
00327 int CntSelfEdges(const PGraph& Graph) {
00328   int Cnt = 0;
00329   for (typename PGraph::TObj::TNodeI NI = Graph->BegNI(); NI < Graph->EndNI(); NI++) {
00330     for (int e = 0; e < NI.GetOutDeg(); e++) {
00331       if (NI.GetId() == NI.GetOutNId(e)) { Cnt++; }
00332     }
00333   }
00334   return Cnt;
00335 }
00336 
00337 template <class PGraph>
00338 PGraph GetUnDir(const PGraph& Graph) {
00339   PGraph NewGraphPt = PGraph::New();
00340   *NewGraphPt = *Graph;
00341   MakeUnDir(NewGraphPt);
00342   return NewGraphPt;
00343 }
00344 
00345 template <class PGraph>
00346 void MakeUnDir(const PGraph& Graph) {
00347   CAssert(HasGraphFlag(typename PGraph::TObj, gfDirected)); // graph has to be directed
00348   TIntPrV EdgeV;
00349   for (typename PGraph::TObj::TEdgeI EI = Graph->BegEI(); EI < Graph->EndEI(); EI++) {
00350     const int SrcNId = EI.GetSrcNId();
00351     const int DstNId = EI.GetDstNId();
00352     if (! Graph->IsEdge(DstNId, SrcNId)) {
00353       EdgeV.Add(TIntPr(DstNId, SrcNId));
00354     }
00355   }
00356   for (int i = 0; i < EdgeV.Len(); i++) {
00357     Graph->AddEdge(EdgeV[i].Val1, EdgeV[i].Val2);
00358   }
00359 }
00360 
00361 template <class PGraph>
00362 void AddSelfEdges(const PGraph& Graph) {
00363   TIntV EdgeV;
00364   for (typename PGraph::TObj::TNodeI NI = Graph->BegNI(); NI < Graph->EndNI(); NI++) {
00365     const int NId = NI.GetId();
00366     if (! Graph->IsEdge(NId, NId)) {
00367       EdgeV.Add(NId);
00368     }
00369   }
00370   for (int i = 0; i < EdgeV.Len(); i++) {
00371     Graph->AddEdge(EdgeV[i], EdgeV[i]);
00372   }
00373 }
00374 
00375 namespace TSnapDetail {
00376 
00377 template <class PGraph, bool IsMultiGraph>
00378 struct TDelSelfEdges { // not a multigraph graph
00379   static void Do(const PGraph& Graph) {
00380     TIntV EdgeV;
00381     // node graph, no explicit edge ids
00382     for (typename PGraph::TObj::TEdgeI EI = Graph->BegEI(); EI < Graph->EndEI(); EI++) {
00383       if (EI.GetSrcNId() == EI.GetDstNId()) {
00384         EdgeV.Add(EI.GetSrcNId());
00385       }
00386     }
00387     for (int i = 0; i < EdgeV.Len(); i++) {
00388       Graph->DelEdge(EdgeV[i], EdgeV[i]);
00389     }
00390   }
00391 };
00392 
00393 template <class PGraph>
00394 struct TDelSelfEdges<PGraph, true> { // mutligraph specialization
00395   static void Do(const PGraph& Graph) {
00396     TIntV EdgeV;
00397     for (typename PGraph::TObj::TEdgeI EI = Graph->BegEI(); EI < Graph->EndEI(); EI++) {
00398       if (EI.GetSrcNId() == EI.GetDstNId()) {
00399         IAssert(EI.GetId() >= 0); // real edge id
00400         EdgeV.Add(EI.GetId());
00401       }
00402     }
00403     for (int i = 0; i < EdgeV.Len(); i++) { // delete all edges between a pair of nodes
00404       Graph->DelEdge(EdgeV[i]);
00405     }
00406   }
00407 };
00408 
00409 } // namespace TSnapDetail
00410 
00411 template <class PGraph>
00412 void DelSelfEdges(const PGraph& Graph) {
00413   TSnapDetail::TDelSelfEdges<PGraph, HasGraphFlag(typename PGraph::TObj, gfMultiGraph)>
00414     ::Do(Graph);
00415 }
00416 
00417 template <class PGraph>
00418 void DelNodes(PGraph& Graph, const TIntV& NIdV) {
00419   for (int n = 0; n < NIdV.Len(); n++) {
00420     Graph->DelNode(NIdV[n]);
00421   }
00422 }
00423 
00424 template <class PGraph>
00425 void DelZeroDegNodes(PGraph& Graph) {
00426   TIntV DelNIdV;
00427   for (typename PGraph::TObj::TNodeI NI = Graph->BegNI(); NI < Graph->EndNI(); NI++) {
00428     if (NI.GetDeg() == 0) {
00429       DelNIdV.Add(NI.GetId());
00430     }
00431   }
00432   for (int i = 0; i < DelNIdV.Len(); i++) {
00433     Graph->DelNode(DelNIdV[i]);
00434   }
00435 }
00436 
00437 template <class PGraph>
00438 void DelDegKNodes(PGraph& Graph, const int& OutDegK, const int& InDegK) {
00439   TIntV DelNIdV;
00440   for (typename PGraph::TObj::TNodeI NI = Graph->BegNI(); NI < Graph->EndNI(); NI++) {
00441     if (NI.GetOutDeg() == OutDegK || NI.GetInDeg() == InDegK) {
00442       DelNIdV.Add(NI.GetId());
00443     }
00444   }
00445   for (int i = 0; i < DelNIdV.Len(); i++) {
00446     Graph->DelNode(DelNIdV[i]);
00447   }
00448 }
00449 
00450 // tree has directed edges -- so root is a well-defined
00451 // children point to a parent
00452 template <class PGraph>
00453 bool IsTree(const PGraph& Graph, int& RootNId) {
00454   if (Graph->GetNodes() == 1 && Graph->GetEdges() == 0) {
00455     RootNId = Graph->BegNI().GetId();
00456     return true;
00457   }
00458   RootNId = -1;
00459   if (Graph->GetNodes() != Graph->GetEdges()+1) { return false; }
00460   int NZeroOutDeg = 0;
00461   int ZeroOutDegN = -1;
00462   for (typename PGraph::TObj::TNodeI NI = Graph->BegNI(); NI < Graph->EndNI(); NI++) {
00463     if (NI.GetOutDeg() == 0) {
00464       ZeroOutDegN = NI.GetId();  NZeroOutDeg++;
00465     }
00466     if (NI.GetDeg() == 0) { return false; } // isolated nodes
00467   }
00468   if (NZeroOutDeg==1) {
00469     if (! TSnap::IsConnected(Graph)) { return false; }
00470     RootNId = ZeroOutDegN;  return true;
00471   }
00472   return false;
00473 }
00474 
00475 // tree signature -- for each level we sort the node in-degrees and concatenate them into a vector
00476 template <class PGraph>
00477 void GetTreeSig(const PGraph& Graph, const int& RootNId, TIntV& Sig) {
00478   CAssert(HasGraphFlag(typename PGraph::TObj, gfDirected));
00479   Sig.Gen(Graph->GetNodes(), 0);
00480   TSnapQueue<int> NIdQ(Graph->GetNodes());
00481   NIdQ.Push(RootNId);
00482   int LastPos = 0, NodeCnt = 1;
00483   while (! NIdQ.Empty()) {
00484     const typename PGraph::TObj::TNodeI Node = Graph->GetNI(NIdQ.Top());  NIdQ.Pop();
00485     IAssert(Node.GetInDeg()==0 || Node.GetOutDeg()==0); // child points or is-pointed to by the parent
00486     if (Node.GetInDeg() != 0) {
00487       for (int e = 0; e < Node.GetInDeg(); e++) {
00488         NIdQ.Push(Node.GetInNId(e)); }
00489     } else if (Node.GetOutDeg() != 0) {
00490       for (int e = 0; e < Node.GetOutDeg(); e++) {
00491         NIdQ.Push(Node.GetOutNId(e)); }
00492     }
00493     Sig.Add(Node.GetInDeg());
00494     if (--NodeCnt == 0) {
00495       for (int i = LastPos; i < Sig.Len(); i++) NodeCnt += Sig[i];
00496       Sig.QSort(LastPos, Sig.Len()-1, false);
00497       LastPos = Sig.Len();
00498     }
00499   }
00500 }
00501 
00502 // tree signature -- for each level we sort the node in-degrees and concatenate them into a vector
00503 template <class PGraph>
00504 void GetTreeSig(const PGraph& Graph, const int& RootNId, TIntV& Sig, TIntPrV& NodeMap) {
00505   CAssert(HasGraphFlag(typename PGraph::TObj, gfDirected));
00506   NodeMap.Gen(Graph->GetNodes(), 0);
00507   Sig.Gen(Graph->GetNodes(), 0);
00508   TSnapQueue<int> NIdQ(Graph->GetNodes());
00509   NIdQ.Push(RootNId);
00510   int LastPos = 0, NodeCnt = 1;
00511   while (! NIdQ.Empty()) {
00512     const typename PGraph::TObj::TNodeI Node = Graph->GetNI(NIdQ.Top());  NIdQ.Pop();
00513     IAssert(Node.GetInDeg()==0 || Node.GetOutDeg()==0); // child points or is-pointed to by the parent
00514     if (Node.GetInDeg() != 0) {
00515       for (int e = 0; e < Node.GetInDeg(); e++) {
00516         NIdQ.Push(Node.GetInNId(e)); }
00517       NodeMap.Add(TIntPr(Node.GetInDeg(), Node.GetId()));
00518     } else if (Node.GetOutDeg() != 0) {
00519       for (int e = 0; e < Node.GetOutDeg(); e++) {
00520         NIdQ.Push(Node.GetOutNId(e)); }
00521       NodeMap.Add(TIntPr(Node.GetOutDeg(), Node.GetId()));
00522     }
00523     if (--NodeCnt == 0) {
00524       for (int i = LastPos; i < NodeMap.Len(); i++) {
00525         NodeCnt += NodeMap[i].Val1; }
00526       NodeMap.QSort(LastPos, NodeMap.Len()-1, false);
00527       LastPos = NodeMap.Len();
00528     }
00529   }
00530   for (int i = 0; i < NodeMap.Len(); i++) {
00531     Sig.Add(NodeMap[i].Val1); // degree dignature
00532     NodeMap[i].Val1 = NodeMap[i].Val2;
00533     NodeMap[i].Val2 = i;
00534   }
00535 }
00536 
00537 }; // namespace TSnap