package com.twitter.pers.graph_generator; import java.util.ArrayList; import java.util.Random; /** * Graph generator based on the R-MAT algorithm * R-MAT: A Recursive Model for Graph Mining * Chakrabarti, Zhan, Faloutsos: http://www.cs.cmu.edu/~christos/PUBLICATIONS/siam04.pdf */ public class RMATGraphGenerator { private GraphOutput outputter; /* Parameters for top-left, top-right, bottom-left, bottom-right probabilities */ private double pA, pB, pC, pD; private long numEdges; private int numVertices; /** * From http://pywebgraph.sourceforge.net ## Probability of choosing quadrant A self.probA = 0.45 ## Probability of choosing quadrant B self.probB = 0.15 ## Probability of choosing quadrant C self.probC = 0.15 ## Probability of choosing quadrant D self.probD = 0.25 */ public RMATGraphGenerator(GraphOutput outputter, double pA, double pB, double pC, double pD, int nVertices,long nEdges) { this.outputter = outputter; this.pA = pA; this.pB = pB; this.pC = pC; this.pD = pD; if (Math.abs(pA + pB + pC + pD - 1.0) > 0.01) throw new IllegalArgumentException("Probabilities do not add up to one!"); numVertices = nVertices; numEdges = nEdges; } public void execute() { int nThreads = Runtime.getRuntime().availableProcessors(); ArrayList<Thread> threads = new ArrayList<Thread>(); for(int i=0; i < nThreads; i++) { Thread t = new Thread(new RMATGenerator(numEdges / nThreads)); t.start(); threads.add(t); } /* Wait */ try { for(Thread t : threads) t.join(); } catch (InterruptedException ie) { throw new RuntimeException(ie); } } private class RMATGenerator implements Runnable { private long edgesToGenerate; private RMATGenerator(long genEdges) { this.edgesToGenerate = genEdges; } public void run() { int nEdgesATime = 1000000; long createdEdges = 0; Random r = new Random(System.currentTimeMillis() + this.hashCode()); double cumA = pA; double cumB = cumA + pB; double cumC = cumB + pC; double cumD = 1.0; assert(cumD > cumC); while(edgesToGenerate > createdEdges) { int ne = (int) Math.min(edgesToGenerate - createdEdges, nEdgesATime); int[] fromIds = new int[ne]; int[] toIds = new int[ne]; for(int j=0; j < ne; j++) { int col_st = 0, col_en = numVertices - 1, row_st = 0, row_en = numVertices - 1; while (col_st != col_en || row_st != row_en) { double x = r.nextDouble(); if (x < cumA) { // Top-left col_en = col_st + (col_en - col_st) / 2; row_en = row_st + (row_en - row_st) / 2; } else if (x < cumB) { // Top-right col_st = col_en - (col_en - col_st) / 2; row_en = row_st + (row_en - row_st) / 2; } else if (x < cumC) { // Bottom-left col_en = col_st + (col_en - col_st) / 2; row_st = row_en - (row_en - row_st) / 2; } else { // Bottom-right col_st = col_en - (col_en - col_st) / 2; row_st = row_en - (row_en - row_st) / 2; } } fromIds[j] = col_st; toIds[j] = row_st; } outputter.addEdges(fromIds, toIds); createdEdges += ne; System.out.println(Thread.currentThread().getId() + " created " + createdEdges + " edges."); } outputter.finishUp(); } } public static void main(String[] args) { int k = 0; String outputFile = args[k++]; int numVertices = Integer.parseInt(args[k++]); long numEdges = Long.parseLong(args[k++]); double pA = Double.parseDouble(args[k++]); double pB = Double.parseDouble(args[k++]); double pC = Double.parseDouble(args[k++]); double pD = Double.parseDouble(args[k++]); System.out.println("Going to create graph with approx. " + numVertices + " vertices and " + numEdges + " edges"); long t = System.currentTimeMillis(); RMATGraphGenerator generator = new RMATGraphGenerator(new EdgeListOutput(outputFile), pA, pB, pC, pD, numVertices, numEdges); generator.execute(); System.out.println("Generating took " + (System.currentTimeMillis() - t) * 0.001 + " secs"); } }