import java.util.ArrayList; import java.util.HashSet; class Simulation { // We don't need to steenkin command line arguments, we got constants static final int REDS = 1000, BLACKS = 1000, NODES = REDS + BLACKS; static final int DEGREE = 10, JOINS = 5, COLUMNS = 20; static final int ROUNDS = 100, SWAPS_PER_ROUND = 1000 * 1000; static final int SWAP_RESET = 2000; static final boolean SHOW_BLACKS = true; static final int DRIFT_NODES=100; static final double DRIFT_PRESSURE=0.1; ArrayList reds, blacks, nodes; int[] loc = new int[COLUMNS]; Node r0; Node b0; Simulation() { // Create two separate networks each covering the whole keyspace reds = new ArrayList (REDS); for (int i = 0; i < REDS; i++) reds.add (new Node()); makeKleinbergNetwork (reds); blacks = new ArrayList (BLACKS); for (int i = 0; i < BLACKS; i++) blacks.add (new Node()); makeKleinbergNetwork (blacks); // Join the networks at a few randomly chosen points for (int i = 0; i < JOINS; i++) { Node r = reds.get ((int) (Math.random() * REDS)); Node b = blacks.get ((int) (Math.random() * BLACKS)); r.neighbours.add (b); b.neighbours.add (r); } // Allow the networks to swap with each other nodes = new ArrayList (NODES); nodes.addAll (reds); nodes.addAll (blacks); r0=reds.get(0); b0=blacks.get(0); // See whether the locations become segregated for (int i = 0; i < ROUNDS; i++) { printLocations(); swapLocations(); //incurDrift(); } System.err.println("END"); } void printLocations() { // Print the location distribution of the reds for (Node r : reds) loc[(int) (r.location * COLUMNS)]++; for (int i = 0; i < COLUMNS; i++) { int val=loc[i]; String padding=" "; if (val>=1000) padding=""; else if (val>=100) padding=" "; else if (val>=10) padding=" "; System.out.print (padding+loc[i] + " "); loc[i] = 0; } System.out.println(" reds [0]="+r0.location); if (SHOW_BLACKS) { // Print the location distribution of the blacks System.out.print(" "); for (Node b : blacks) loc[(int) (b.location * COLUMNS)]++; for (int i = 0; i < COLUMNS; i++) { int val=loc[i]; String padding=" "; if (val>=1000) padding=""; else if (val>=100) padding=" "; else if (val>=10) padding=" "; System.out.print (padding+loc[i] + " "); loc[i] = 0; } System.out.println(" blacks[0]="+b0.location); } } void swapLocations() { for (int i = 0; i < SWAPS_PER_ROUND; i++) { Node a = nodes.get ((int) (Math.random() * NODES)); Node b = nodes.get ((int) (Math.random() * NODES)); if (shouldSwap (a, b)) { double temp = a.location; a.location = b.location; b.location = temp; /* if (Math.random()*SWAP_RESET<1.0) a.location=Math.random(); // */ } } } static double distance (Node a, Node b) { double x = a.location, y = b.location; if (x > y) return Math.min (x - y, y - x + 1.0); else return Math.min (y - x, x - y + 1.0); } boolean shouldSwap (Node a, Node b) { boolean inSameSubnet= (reds.contains(a) == reds.contains(b)); /*much less likely to swap (e.g. routing too far away) if (!inSameSubnet && (Math.random()>(JOINS/REDS))) { return false; } // */ double before = 1.0; for (Node c : a.neighbours) before *= distance (a, c); for (Node d : b.neighbours) before *= distance (b, d); double after = 1.0; for (Node c : a.neighbours) after *= distance (b, c); for (Node d : b.neighbours) after *= distance (a, d); if (after <= before) return true; else return Math.random() < before / after; } static void makeKleinbergNetwork (ArrayList nodes) { for (Node a : nodes) { // Normalise the probabilities double norm = 0.0; for (Node b : nodes) { if (a.location == b.location) continue; norm += 1.0 / distance (a, b); } // Create DEGREE/2 outgoing connections for (Node b : nodes) { if (a.location == b.location) continue; double p = 1.0 / distance (a, b) / norm; for (int i = 0; i < DEGREE / 2; i++) { if (Math.random() < p) { a.neighbours.add (b); b.neighbours.add (a); break; } } } } } public void incurDrift() { for (int i = 0; i < DRIFT_NODES/2; i++) { //Reds drift right Node r = reds.get ((int) (Math.random() * REDS)); r.location+=DRIFT_PRESSURE; if (r.location>1.0) r.location-=1.0; //Blacks drift left Node b = blacks.get ((int) (Math.random() * BLACKS)); b.location-=DRIFT_PRESSURE; if (b.location<0.0) b.location+=1.0; } } public static void main (String[] args) { new Simulation(); } static class Node { HashSet neighbours = new HashSet(); double location = Math.random(); String id; } }