private static void simulate(Graph g, RandomGenerator rand, int nRequests, final FoldingPolicy foldingPolicy, final RoutingPolicy routingPolicy, final boolean bootstrap) {

		int successes = 0, disconnectedFolding = 0, disconnectedBootstrap = 0, totalPathLength = 0;
		for (int i = 0; i < nRequests; i++) {
			final SimpleNode origin = g.getNode(rand.nextInt(g.size()));
			/*
			 * It causes distortion to select among node locations for destinations as they may be less
			 * evenly distributed, but it allows determining if a request was routed exactly based on
			 * whether the target location is equal.
			 */
			final SimpleNode destination = g.getNode(rand.nextInt(g.size()));
			final RouteResult result = origin.route(destination, 50, routingPolicy, foldingPolicy);

			// Count successes.
			if (result.success) successes++;

			/*
			 * Bootstrap all nodes which became disconnected during path folding.
			 * Bootstrapping will not connect to disconnected nodes.
			 * Bootstrapping will drop connections when making new ones so that the total connection count
			 * remains the same; additional nodes may become disconnected in the process.
			 */
			Queue<SimpleNode> disconnected = new LinkedList<SimpleNode>(result.disconnected);
			disconnectedFolding += result.disconnected.size();
			while (bootstrap && !disconnected.isEmpty()) {
				for (SimpleNode additional : g.bootstrap(disconnected.remove(), rand)) {
					disconnected.offer(additional);
					disconnectedBootstrap++;
				}
			}

			totalPathLength += result.pathLength;
		}
		System.out.println(disconnectedFolding + " nodes became disconnected due to folding.");
		System.out.println(disconnectedBootstrap + " nodes became disconnected due to bootstrapping.");
		System.out.println("Routing success rate: " + (double)successes / nRequests * 100);
		System.out.println("Mean path length " + (double)totalPathLength / nRequests);
	}