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
cncom.h
Go to the documentation of this file.
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