SNAP Library, Developer Reference
2012-10-15 15:06:59
SNAP, a general purpose network analysis and graph mining library
|
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