SNAP Library, Developer Reference  2012-10-15 15:06:59
SNAP, a general purpose network analysis and graph mining library
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines
ggen.cpp
Go to the documentation of this file.
00001 
00002 // Graph Generators
00003 namespace TSnap {
00004 
00005 PBPGraph GenRndBipart(const int& LeftNodes, const int& RightNodes, const int& Edges, TRnd& Rnd) {
00006   PBPGraph G = TBPGraph::New();
00007   for (int i = 0; i < LeftNodes; i++) { G->AddNode(i, true); }
00008   for (int i = 0; i < RightNodes; i++) { G->AddNode(LeftNodes+i, false); }
00009   IAssertR(Edges < LeftNodes*RightNodes, "Too many edges in the bipartite graph!");
00010   for (int edges = 0; edges < Edges; ) {
00011     const int LNId = Rnd.GetUniDevInt(LeftNodes);
00012     const int RNId = LeftNodes + Rnd.GetUniDevInt(RightNodes);
00013     if (G->AddEdge(LNId, RNId) != -2) { edges++; } // is new edge
00014   }
00015   return G;
00016 }
00017 
00018 PUNGraph GenRndDegK(const int& Nodes, const int& NodeDeg, const int& NSwitch, TRnd& Rnd) {
00019   // create degree sequence
00020   TIntV DegV(Nodes, 0);
00021   int DegSum=0;
00022   for (int i = 0; i < Nodes; i++) {
00023     DegV.Add(NodeDeg);
00024     DegSum += NodeDeg;
00025   }
00026   IAssert(DegSum % 2 == 0);
00027   PUNGraph G = GenDegSeq(DegV, Rnd); // get some graph that obeys the degree sequnce
00028   return GenRewire(G, NSwitch, Rnd);  // make it random
00029 }
00030 
00034 PUNGraph GenRndPowerLaw(const int& Nodes, const double& PowerExp, const bool& ConfModel, TRnd& Rnd) {
00035   TIntV DegSeqV;
00036   uint DegSum=0;
00037   for (int n = 0; n < Nodes; n++) {
00038     const int Val = (int) TMath::Round(Rnd.GetPowerDev(PowerExp));
00039     if (! (Val >= 1 && Val < Nodes/2)) { n--; continue; } // skip nodes with too large degree
00040     DegSeqV.Add(Val);
00041     DegSum += Val;
00042   }
00043   printf("%d nodes, %u edges\n", Nodes, DegSum);
00044   if (DegSum % 2 == 1) { DegSeqV[0] += 1; }
00045   if (ConfModel) {
00046     // use configuration model -- fast but does not exactly obey the degree sequence
00047     return GenConfModel(DegSeqV, Rnd);
00048   } else {
00049     PUNGraph G = TSnap::GenDegSeq(DegSeqV, Rnd);
00050     return TSnap::GenRewire(G, 10, Rnd);
00051   }
00052 }
00053 
00058 PUNGraph GenDegSeq(const TIntV& DegSeqV, TRnd& Rnd) {
00059   const int Nodes = DegSeqV.Len();
00060   PUNGraph GraphPt = TUNGraph::New();
00061   TUNGraph& Graph = *GraphPt;
00062   Graph.Reserve(Nodes, -1);
00063   TIntH DegH(DegSeqV.Len(), true);
00064   int DegSum=0, edge=0;
00065   for (int node = 0; node < Nodes; node++) {
00066     IAssert(Graph.AddNode(node) == node);
00067     DegH.AddDat(node, DegSeqV[node]);
00068     DegSum += DegSeqV[node];
00069   }
00070   IAssert(DegSum % 2 == 0);
00071   while (! DegH.Empty()) {
00072     // pick random nodes and connect
00073     const int NId1 = DegH.GetKey(DegH.GetRndKeyId(TInt::Rnd, 0.5));
00074     const int NId2 = DegH.GetKey(DegH.GetRndKeyId(TInt::Rnd, 0.5));
00075     IAssert(DegH.IsKey(NId1) && DegH.IsKey(NId2));
00076     if (NId1 == NId2) {
00077       if (DegH.GetDat(NId1) == 1) { continue; }
00078       // find rnd edge, break it, and connect the endpoints to the nodes
00079       const TIntPr Edge = TSnapDetail::GetRndEdgeNonAdjNode(GraphPt, NId1, -1);
00080       if (Edge.Val1==-1) { continue; }
00081       Graph.DelEdge(Edge.Val1, Edge.Val2);
00082       Graph.AddEdge(Edge.Val1, NId1);
00083       Graph.AddEdge(NId1, Edge.Val2);
00084       if (DegH.GetDat(NId1) == 2) { DegH.DelKey(NId1); }
00085       else { DegH.GetDat(NId1) -= 2; }
00086     } else {
00087       if (! Graph.IsEdge(NId1, NId2)) {
00088         Graph.AddEdge(NId1, NId2); }  // good edge
00089       else {
00090         // find rnd edge, break and cross-connect
00091         const TIntPr Edge = TSnapDetail::GetRndEdgeNonAdjNode(GraphPt, NId1, NId2);
00092         if (Edge.Val1==-1) {continue; }
00093         Graph.DelEdge(Edge.Val1, Edge.Val2);
00094         Graph.AddEdge(NId1, Edge.Val1);
00095         Graph.AddEdge(NId2, Edge.Val2);
00096       }
00097       if (DegH.GetDat(NId1)==1) { DegH.DelKey(NId1); }
00098       else { DegH.GetDat(NId1) -= 1; }
00099       if (DegH.GetDat(NId2)==1) { DegH.DelKey(NId2); }
00100       else { DegH.GetDat(NId2) -= 1; }
00101     }
00102     if (++edge % 1000 == 0) {
00103       printf("\r %dk / %dk", edge/1000, DegSum/2000); }
00104   }
00105   return GraphPt;
00106 }
00107 
00108 
00117 PUNGraph GenConfModel(const TIntV& DegSeqV, TRnd& Rnd) {
00118   const int Nodes = DegSeqV.Len();
00119   PUNGraph GraphPt = TUNGraph::New();
00120   TUNGraph& Graph = *GraphPt;
00121   Graph.Reserve(Nodes, -1);
00122   TIntV NIdDegV(DegSeqV.Len(), 0);
00123   int DegSum=0, edges=0;
00124   for (int node = 0; node < Nodes; node++) {
00125     Graph.AddNode(node);
00126     for (int d = 0; d < DegSeqV[node]; d++) { NIdDegV.Add(node); }
00127     DegSum += DegSeqV[node];
00128   }
00129   NIdDegV.Shuffle(Rnd);
00130   TIntPrSet EdgeH(DegSum/2); // set of all edges, is faster than graph edge lookup
00131   if (DegSum % 2 != 0) {
00132     printf("Seg seq is odd [%d]: ", DegSeqV.Len());
00133     for (int d = 0; d < TMath::Mn(100, DegSeqV.Len()); d++) { printf("  %d", (int)DegSeqV[d]); }
00134     printf("\n");
00135   }
00136   int u=0, v=0;
00137   for (int c = 0; NIdDegV.Len() > 1; c++) {
00138     u = Rnd.GetUniDevInt(NIdDegV.Len());
00139     while ((v = Rnd.GetUniDevInt(NIdDegV.Len())) == u) { }
00140     if (u > v) { Swap(u, v); }
00141     const int E1 = NIdDegV[u];
00142     const int E2 = NIdDegV[v];
00143     if (v == NIdDegV.Len()-1) { NIdDegV.DelLast(); } 
00144     else { NIdDegV[v] = NIdDegV.Last();  NIdDegV.DelLast(); }
00145     if (u == NIdDegV.Len()-1) { NIdDegV.DelLast(); } 
00146     else { NIdDegV[u] = NIdDegV.Last();  NIdDegV.DelLast(); }
00147     if (E1 == E2 || EdgeH.IsKey(TIntPr(E1, E2))) { continue; }
00148     EdgeH.AddKey(TIntPr(E1, E2));
00149     Graph.AddEdge(E1, E2);
00150     edges++;
00151     if (c % (DegSum/100+1) == 0) { printf("\r configuration model: iter %d: edges: %d, left: %d", c, edges, NIdDegV.Len()/2); }
00152   }
00153   printf("\n");
00154   return GraphPt;
00155 }
00156 
00163 PUNGraph GenRewire(const PUNGraph& OrigGraph, const int& NSwitch, TRnd& Rnd) {
00164   const int Nodes = OrigGraph->GetNodes();
00165   const int Edges = OrigGraph->GetEdges();
00166   PUNGraph GraphPt = TUNGraph::New();
00167   TUNGraph& Graph = *GraphPt;
00168   Graph.Reserve(Nodes, -1);
00169   TExeTm ExeTm;
00170   // generate a graph that satisfies the constraints
00171   printf("Randomizing edges (%d, %d)...\n", Nodes, Edges);
00172   TIntPrSet EdgeSet(Edges);
00173   for (TUNGraph::TNodeI NI = OrigGraph->BegNI(); NI < OrigGraph->EndNI(); NI++) {
00174     const int NId = NI.GetId();
00175     for (int e = 0; e < NI.GetOutDeg(); e++) {
00176       if (NId <= NI.GetOutNId(e)) { continue; }
00177       EdgeSet.AddKey(TIntPr(NId, NI.GetOutNId(e)));
00178     }
00179     Graph.AddNode(NI.GetId());
00180   }
00181   // edge switching
00182   uint skip=0;
00183   for (uint swps = 0; swps < 2*uint(Edges)*uint(NSwitch); swps++) {
00184     const int keyId1 = EdgeSet.GetRndKeyId(Rnd);
00185     const int keyId2 = EdgeSet.GetRndKeyId(Rnd);
00186     if (keyId1 == keyId2) { skip++; continue; }
00187     const TIntPr& E1 = EdgeSet[keyId1];
00188     const TIntPr& E2 = EdgeSet[keyId2];
00189     TIntPr NewE1(E1.Val1, E2.Val1), NewE2(E1.Val2, E2.Val2);
00190     if (NewE1.Val1 > NewE1.Val2) { Swap(NewE1.Val1, NewE1.Val2); }
00191     if (NewE2.Val1 > NewE2.Val2) { Swap(NewE2.Val1, NewE2.Val2); }
00192     if (NewE1!=NewE2 && NewE1.Val1!=NewE1.Val2 && NewE2.Val1!=NewE2.Val2 && ! EdgeSet.IsKey(NewE1) && ! EdgeSet.IsKey(NewE2)) {
00193       EdgeSet.DelKeyId(keyId1);  EdgeSet.DelKeyId(keyId2);
00194       EdgeSet.AddKey(TIntPr(NewE1));
00195       EdgeSet.AddKey(TIntPr(NewE2));
00196     } else { skip++; }
00197     if (swps % Edges == 0) {
00198       printf("\r  %uk/%uk: %uk skip [%s]", swps/1000u, 2*uint(Edges)*uint(NSwitch)/1000u, skip/1000u, ExeTm.GetStr());
00199       if (ExeTm.GetSecs() > 2*3600) { printf(" *** Time limit!\n"); break; } // time limit 2 hours
00200     }
00201   }
00202   printf("\r  total %uk switchings attempted, %uk skiped  [%s]\n", 2*uint(Edges)*uint(NSwitch)/1000u, skip/1000u, ExeTm.GetStr());
00203   for (int e = 0; e < EdgeSet.Len(); e++) {
00204     Graph.AddEdge(EdgeSet[e].Val1, EdgeSet[e].Val2); }
00205   return GraphPt;
00206 }
00207 
00214 PNGraph GenRewire(const PNGraph& OrigGraph, const int& NSwitch, TRnd& Rnd) {
00215   const int Nodes = OrigGraph->GetNodes();
00216   const int Edges = OrigGraph->GetEdges();
00217   PNGraph GraphPt = TNGraph::New();
00218   TNGraph& Graph = *GraphPt;
00219   Graph.Reserve(Nodes, -1);
00220   TExeTm ExeTm;
00221   // generate a graph that satisfies the constraints
00222   printf("Randomizing edges (%d, %d)...\n", Nodes, Edges);
00223   TIntPrSet EdgeSet(Edges);
00224   for (TNGraph::TNodeI NI = OrigGraph->BegNI(); NI < OrigGraph->EndNI(); NI++) {
00225     const int NId = NI.GetId();
00226     for (int e = 0; e < NI.GetOutDeg(); e++) {
00227       EdgeSet.AddKey(TIntPr(NId, NI.GetOutNId(e))); }
00228     Graph.AddNode(NI);
00229   }
00230   // edge switching
00231   uint skip=0;
00232   for (uint swps = 0; swps < 2*uint(Edges)*uint(NSwitch); swps++) {
00233     const int keyId1 = EdgeSet.GetRndKeyId(Rnd);
00234     const int keyId2 = EdgeSet.GetRndKeyId(Rnd);
00235     if (keyId1 == keyId2) { skip++; continue; }
00236     const TIntPr& E1 = EdgeSet[keyId1];
00237     const TIntPr& E2 = EdgeSet[keyId2];
00238     TIntPr NewE1(E1.Val1, E2.Val1), NewE2(E1.Val2, E2.Val2);
00239     if (NewE1.Val1!=NewE2.Val1 && NewE1.Val2!=NewE2.Val1 && NewE1.Val2!=NewE2.Val1 && NewE1.Val2!=NewE2.Val2 && ! EdgeSet.IsKey(NewE1) && ! EdgeSet.IsKey(NewE2)) {
00240       EdgeSet.DelKeyId(keyId1);  EdgeSet.DelKeyId(keyId2);
00241       EdgeSet.AddKey(TIntPr(NewE1));
00242       EdgeSet.AddKey(TIntPr(NewE2));
00243     } else { skip++; }
00244     if (swps % Edges == 0) {
00245       printf("\r  %uk/%uk: %uk skip [%s]", swps/1000u, 2*uint(Edges)*uint(NSwitch)/1000u, skip/1000u, ExeTm.GetStr());
00246       if (ExeTm.GetSecs() > 2*3600) { printf(" *** Time limit!\n"); break; } // time limit 2 hours
00247     }
00248   }
00249   printf("\r  total %uk switchings attempted, %uk skiped  [%s]\n", 2*uint(Edges)*uint(NSwitch)/1000u, skip/1000u, ExeTm.GetStr());
00250   for (int e = 0; e < EdgeSet.Len(); e++) {
00251     Graph.AddEdge(EdgeSet[e].Val1, EdgeSet[e].Val2); }
00252   return GraphPt;
00253 }
00254 
00261 PBPGraph GenRewire(const PBPGraph& OrigGraph, const int& NSwitch, TRnd& Rnd) {
00262   const int Nodes = OrigGraph->GetNodes();
00263   const int Edges = OrigGraph->GetEdges();
00264   PBPGraph GraphPt = TBPGraph::New();
00265   TBPGraph& Graph = *GraphPt;
00266   Graph.Reserve(Nodes, -1);
00267   TExeTm ExeTm;
00268   // generate a graph that satisfies the constraints
00269   printf("Randomizing edges (%d, %d)...\n", Nodes, Edges);
00270   TIntPrSet EdgeSet(Edges);
00271   for (TBPGraph::TNodeI NI = OrigGraph->BegLNI(); NI < OrigGraph->EndLNI(); NI++) {
00272     const int NId = NI.GetId();
00273     for (int e = 0; e < NI.GetOutDeg(); e++) {
00274       EdgeSet.AddKey(TIntPr(NId, NI.GetOutNId(e))); } // edges left-->right
00275     Graph.AddNode(NI.GetId(), true); } // left nodes
00276   for (TBPGraph::TNodeI NI = OrigGraph->BegRNI(); NI < OrigGraph->EndRNI(); NI++) {
00277     Graph.AddNode(NI.GetId(), false); } // right nodes
00278   IAssert(EdgeSet.Len() == Edges);
00279   // edge switching
00280   uint skip=0;
00281   for (uint swps = 0; swps < 2*uint(Edges)*uint(NSwitch); swps++) {
00282     const int keyId1 = EdgeSet.GetRndKeyId(Rnd);
00283     const int keyId2 = EdgeSet.GetRndKeyId(Rnd);
00284     if (keyId1 == keyId2) { skip++; continue; }
00285     const TIntPr& E1 = EdgeSet[keyId1];
00286     const TIntPr& E2 = EdgeSet[keyId2];
00287     TIntPr NewE1(E1.Val1, E2.Val2), NewE2(E2.Val1, E1.Val2);
00288     if (NewE1!=NewE2 && NewE1.Val1!=NewE1.Val2 && NewE2.Val1!=NewE2.Val2 && ! EdgeSet.IsKey(NewE1) && ! EdgeSet.IsKey(NewE2)) {
00289       EdgeSet.DelKeyId(keyId1);  EdgeSet.DelKeyId(keyId2);
00290       EdgeSet.AddKey(TIntPr(NewE1));
00291       EdgeSet.AddKey(TIntPr(NewE2));
00292     } else { skip++; }
00293     if (swps % Edges == 0) {
00294       printf("\r  %uk/%uk: %uk skip [%s]", swps/1000u, 2*uint(Edges)*uint(NSwitch)/1000u, skip/1000u, ExeTm.GetStr());
00295       if (ExeTm.GetSecs() > 2*3600) { printf(" *** Time limit!\n"); break; } // time limit 2 hours
00296     }
00297   }
00298   printf("\r  total %uk switchings attempted, %uk skiped  [%s]\n", 2*uint(Edges)*uint(NSwitch)/1000u, skip/1000u, ExeTm.GetStr());
00299   for (int e = 0; e < EdgeSet.Len(); e++) {
00300     Graph.AddEdge(EdgeSet[e].Val1, EdgeSet[e].Val2); }
00301   return GraphPt;
00302 }
00303 
00308 PUNGraph GenPrefAttach(const int& Nodes, const int& NodeOutDeg, TRnd& Rnd) {
00309   PUNGraph GraphPt = PUNGraph::New();
00310   TUNGraph& Graph = *GraphPt;
00311   Graph.Reserve(Nodes, NodeOutDeg*Nodes);
00312   TIntV NIdV(NodeOutDeg*Nodes, 0);
00313   // first edge
00314   Graph.AddNode(0);  Graph.AddNode(1);
00315   NIdV.Add(0);  NIdV.Add(1);
00316   Graph.AddEdge(0, 1);
00317   TIntSet NodeSet;
00318   for (int node = 2; node < Nodes; node++) {
00319     NodeSet.Clr(false);
00320     while (NodeSet.Len() < NodeOutDeg && NodeSet.Len() < node) {
00321       NodeSet.AddKey(NIdV[TInt::Rnd.GetUniDevInt(NIdV.Len())]);
00322     }
00323     const int N = Graph.AddNode();
00324     for (int i = 0; i < NodeSet.Len(); i++) {
00325       Graph.AddEdge(N, NodeSet[i]);
00326       NIdV.Add(N);
00327       NIdV.Add(NodeSet[i]);
00328     }
00329   }
00330   return GraphPt;
00331 }
00332 
00333 namespace TSnapDetail {
00335 void GetSphereDev(const int& Dim, TRnd& Rnd, TFltV& ValV) {
00336   if (ValV.Len() != Dim) { ValV.Gen(Dim); }
00337   double Length = 0.0;
00338   for (int i = 0; i < Dim; i++) {
00339     ValV[i] = Rnd.GetNrmDev();
00340     Length += TMath::Sqr(ValV[i]); }
00341   Length = 1.0 / sqrt(Length);
00342   for (int i = 0; i < Dim; i++) {
00343     ValV[i] *= Length;
00344   }
00345 }
00346 } // namespace TSnapDetail
00347 
00353 PUNGraph GenGeoPrefAttach(const int& Nodes, const int& OutDeg, const double& Beta, TRnd& Rnd) {
00354   PUNGraph G = TUNGraph::New(Nodes, Nodes*OutDeg);
00355   TFltTrV PointV(Nodes, 0);
00356   TFltV ValV;
00357   // points on a sphere of radius 1/(2*pi)
00358   const double Rad = 0.5 * TMath::Pi;
00359   for (int i = 0; i < Nodes; i++) {
00360     TSnapDetail::GetSphereDev(3, Rnd, ValV);
00361     PointV.Add(TFltTr(Rad*ValV[0], Rad*ValV[1], Rad*ValV[2]));
00362   }
00363   const double R2 = TMath::Sqr(log((double) Nodes) / (pow((double) Nodes, 0.5-Beta)));
00364   TIntV DegV, NIdV;
00365   int SumDeg;
00366   for (int t = 0; t < Nodes; t++) {
00367     const int pid = t;
00368     const TFltTr& P1 = PointV[pid];
00369     // add node
00370     if (! G->IsNode(pid)) { G->AddNode(pid); }
00371     // find neighborhood
00372     DegV.Clr(false);  NIdV.Clr(false);  SumDeg=0;
00373     for (int p = 0; p < t; p++) {
00374       const TFltTr& P2 = PointV[p];
00375       if (TMath::Sqr(P1.Val1-P2.Val1)+TMath::Sqr(P1.Val2-P2.Val2)+TMath::Sqr(P1.Val3-P2.Val3) < R2) {
00376         NIdV.Add(p);
00377         DegV.Add(G->GetNI(p).GetDeg()+1);
00378         SumDeg += DegV.Last();
00379       }
00380     }
00381     // add edges
00382     for (int m = 0; m < OutDeg; m++) {
00383       const int rnd = Rnd.GetUniDevInt(SumDeg);
00384       int sum = 0, dst = -1;
00385       for (int s = 0; s < DegV.Len(); s++) {
00386         sum += DegV[s];
00387         if (rnd < sum) { dst=s;  break; }
00388       }
00389       if (dst != -1) {
00390         G->AddEdge(pid, NIdV[dst]);
00391         SumDeg -= DegV[dst];
00392         NIdV.Del(dst);  DegV.Del(dst);
00393       }
00394     }
00395   }
00396   return G;
00397 }
00398 
00404 PUNGraph GenSmallWorld(const int& Nodes, const int& NodeOutDeg, const double& RewireProb, TRnd& Rnd) {
00405   THashSet<TIntPr> EdgeSet(Nodes*NodeOutDeg);
00406   for (int node = 0; node < Nodes; node++) {
00407     const int src = node;
00408     for (int edge = 1; edge <= NodeOutDeg; edge++) {
00409       int dst = (node+edge) % Nodes;      // edge to next neighbor
00410       if (Rnd.GetUniDev() < RewireProb) { // random edge
00411         dst = Rnd.GetUniDevInt(Nodes);
00412         while (dst == src || EdgeSet.IsKey(TIntPr(src, dst))) {
00413           dst = Rnd.GetUniDevInt(Nodes); }
00414       }
00415       EdgeSet.AddKey(TIntPr(src, dst));
00416     }
00417   }
00418   PUNGraph GraphPt = TUNGraph::New();
00419   TUNGraph& Graph = *GraphPt;
00420   Graph.Reserve(Nodes, EdgeSet.Len());
00421   int node;
00422   for (node = 0; node < Nodes; node++) {
00423     IAssert(Graph.AddNode(node) == node);
00424   }
00425   for (int edge = 0; edge < EdgeSet.Len(); edge++) {
00426     Graph.AddEdge(EdgeSet[edge].Val1, EdgeSet[edge].Val2);
00427   }
00428   Graph.Defrag();
00429   return GraphPt;
00430 }
00431 
00432 PNGraph GenForestFire(const int& Nodes, const double& FwdProb, const double& BckProb) {
00433   return TForestFire::GenGraph(Nodes, FwdProb, BckProb);
00434 }
00435 
00443 PNGraph GenCopyModel(const int& Nodes, const double& Beta, TRnd& Rnd) {
00444   PNGraph GraphPt = TNGraph::New();
00445   TNGraph& Graph = *GraphPt;
00446   Graph.Reserve(Nodes, Nodes);
00447   const int startNId = Graph.AddNode();
00448   Graph.AddEdge(startNId, startNId);
00449   for (int n = 1; n < Nodes; n++) {
00450     const int rnd = Graph.GetRndNId();
00451     const int NId = Graph.AddNode();
00452     if (Rnd.GetUniDev() < Beta) {
00453       Graph.AddEdge(NId, rnd); }
00454     else {
00455       const TNGraph::TNodeI NI = Graph.GetNI(rnd);
00456       const int rnd2 = Rnd.GetUniDevInt(NI.GetOutDeg());
00457       Graph.AddEdge(NId, NI.GetOutNId(rnd2));
00458     }
00459   }
00460   return GraphPt;
00461 }
00462 
00468 PNGraph GenRMat(const int& Nodes, const int& Edges, const double& A, const double& B, const double& C, TRnd& Rnd) {
00469   PNGraph GraphPt = TNGraph::New();
00470   TNGraph& Graph = *GraphPt;
00471   Graph.Reserve(Nodes, Edges);
00472   IAssert(A+B+C < 1.0);
00473   int rngX, rngY, offX, offY;
00474   int Depth=0, Collisions=0, Cnt=0, PctDone=0;
00475   const int EdgeGap = Edges / 100 + 1;
00476   // sum of parameters (probabilities)
00477   TVec<double> sumA(128, 0), sumAB(128, 0), sumAC(128, 0), sumABC(128, 0);  // up to 2^128 vertices ~ 3.4e38
00478   for (int i = 0; i < 128; i++) {
00479     const double a = A * (Rnd.GetUniDev() + 0.5);
00480     const double b = B * (Rnd.GetUniDev() + 0.5);
00481     const double c = C * (Rnd.GetUniDev() + 0.5);
00482     const double d = (1.0 - (A+B+C)) * (Rnd.GetUniDev() + 0.5);
00483     const double abcd = a+b+c+d;
00484     sumA.Add(a / abcd);
00485     sumAB.Add((a+b) / abcd);
00486     sumAC.Add((a+c) / abcd);
00487     sumABC.Add((a+b+c) / abcd);
00488   }
00489   // nodes
00490   for (int node = 0; node < Nodes; node++) {
00491     IAssert(Graph.AddNode(-1) == node);
00492   }
00493   // edges
00494   for (int edge = 0; edge < Edges; ) {
00495     rngX = Nodes;  rngY = Nodes;  offX = 0;  offY = 0;
00496     Depth = 0;
00497     // recurse the matrix
00498     while (rngX > 1 || rngY > 1) {
00499       const double RndProb = Rnd.GetUniDev();
00500       if (rngX>1 && rngY>1) {
00501         if (RndProb < sumA[Depth]) { rngX/=2; rngY/=2; }
00502         else if (RndProb < sumAB[Depth]) { offX+=rngX/2;  rngX-=rngX/2;  rngY/=2; }
00503         else if (RndProb < sumABC[Depth]) { offY+=rngY/2;  rngX/=2;  rngY-=rngY/2; }
00504         else { offX+=rngX/2;  offY+=rngY/2;  rngX-=rngX/2;  rngY-=rngY/2; }
00505       } else
00506       if (rngX>1) { // row vector
00507         if (RndProb < sumAC[Depth]) { rngX/=2; rngY/=2; }
00508         else { offX+=rngX/2;  rngX-=rngX/2;  rngY/=2; }
00509       } else
00510       if (rngY>1) { // column vector
00511         if (RndProb < sumAB[Depth]) { rngX/=2; rngY/=2; }
00512         else { offY+=rngY/2;  rngX/=2;  rngY-=rngY/2; }
00513       } else { Fail; }
00514       Depth++;
00515     }
00516     // add edge
00517     const int NId1 = offX;
00518     const int NId2 = offY;
00519     if (NId1 != NId2 && ! Graph.IsEdge(NId1, NId2)) {
00520       Graph.AddEdge(NId1, NId2);
00521       if (++Cnt > EdgeGap) {
00522         Cnt=0;  printf("\r  %d%% edges", ++PctDone); }
00523       edge++;
00524     } else {
00525       Collisions++; }
00526   }
00527   printf("\r  RMat: nodes:%d, edges:%d, Iterations:%d, Collisions:%d (%.1f%%).\n", Nodes, Edges,
00528     Edges+Collisions, Collisions, 100*Collisions/double(Edges+Collisions));
00529   Graph.Defrag();
00530   return GraphPt;
00531 }
00532 
00537 PNGraph GenRMatEpinions() {
00538   return GenRMat(75888, 508837, 0.550, 0.228, 0.212);
00539 }
00540 
00541 } // namespace TSnap