Esempio n. 1
0
	void customMCMC(mcmcArgs& args)
	{
		//Check that we have at least five vertices. Can still run the MCMC with 4, but there's nothing really to estimate, because using the MCMC assumes that the first six count values are known. Which is all of them in the case of four vertices. 
		int nVertices = args.nVertices;
		if(nVertices <= 4)
		{
			throw std::runtime_error("Input nVertices must be at least 5");
		}
		//The case where the edgeLimit is 5 or smaller is not interesting. 
		int edgeLimit = args.approximateCounts.size()-1;
		if(edgeLimit > ((nVertices + 1) * nVertices) /2 || edgeLimit <= 5)
		{
			throw std::runtime_error("Input edgeLimit out of the valid range or smaller than 6");
		}
		//Set up clique tree and graph
		cliqueTreeType currentTree(nVertices);
		graphType graph(nVertices);
		for(int i = 0; i < nVertices; i++) currentTree.addVertex();

		working temp(nVertices);

		std::size_t burnIn = args.burnIn;
		//burn-in
		for(std::size_t i = 0; i < burnIn; i++)
		{
			stepCustom(currentTree, graph, args.approximateCounts, nVertices, args.randomSource, temp, edgeLimit);
		}
		std::vector<std::size_t> counters(args.approximateCounts.size(), 0);
		for(std::size_t i = 0; i < args.runSize; i++)
		{
			stepCustom(currentTree, graph, args.approximateCounts, nVertices, args.randomSource, temp, edgeLimit);
			counters[boost::num_edges(graph)]++;
		}
		mpfr_class sumFirstSix = 0;
		for(int i = 0; i < 6; i++) sumFirstSix += mpfr_class(counters[i]) / args.runSize;

		args.estimates.resize(args.approximateCounts.size());
		for(std::size_t i = 0; i < args.approximateCounts.size(); i++)
		{
			args.estimates[i] = 6 * args.approximateCounts[i] * (mpfr_class(counters[i]) / args.runSize) / sumFirstSix;
		}
	}
inline mpfr_class epsilon<mpfr_class>(BOOST_MATH_EXPLICIT_TEMPLATE_TYPE_SPEC(mpfr_class))
{
   return ldexp(mpfr_class(1), 1-boost::math::policies::digits<mpfr_class, boost::math::policies::policy<> >());
}
	ContextDirected::ContextDirected(boost::shared_ptr<const inputGraph> inputDirectedGraph, int source, int sink, const std::vector<capacityDistribution>& inputDistributions, const mpfr_class& threshold)
		: source(source), sink(sink)
	{
		std::size_t nVertices = boost::num_vertices(*inputDirectedGraph);
		int minVertexIndex = std::min(source, sink);
		int maxVertexIndex = std::max(source, sink);
		if(minVertexIndex < 0 || maxVertexIndex >= (int)nVertices)
		{
			throw std::runtime_error("Input interestVertices was out of range");
		}
		{
			std::size_t nEdges = boost::num_edges(*inputDirectedGraph);
			if(inputDistributions.size() != nEdges)
			{
				throw std::runtime_error("Input distributions must have an entry for every edge");
			}
			
			capacityVector.resize(nEdges);
			if(boost::connected_components(*inputDirectedGraph, &(capacityVector[0])) > 1)
			{
				throw std::runtime_error("Input graph must contain a single connected component");
			}
			//Check that the edge indices of the input graph are unique, and are in [0, nEdges)
			std::vector<int> counters(nEdges, 0);
			inputGraph::edge_iterator current, end;
			boost::tie(current, end) = boost::edges(*inputDirectedGraph);
			for(; current != end; current++)
			{
				int edgeIndex = boost::get(boost::edge_index, *inputDirectedGraph, *current);
				if(edgeIndex < 0 || edgeIndex >= (int)nEdges)
				{
					throw std::runtime_error("Edge index was out of range");
				}
				if(counters[edgeIndex] > 0)
				{
					throw std::runtime_error("Edge indices were not unique");
				}
				counters[edgeIndex]++;
			}
		}

		//Construct a new graph, where the edge indices are assigned consecutively
		boost::shared_ptr<internalGraph> internalDirectedGraph(new internalGraph(nVertices));
		inputGraph::edge_iterator start, end;
		boost::tie(start, end) = boost::edges(*inputDirectedGraph);
		int index = 0;

		std::vector<std::pair<mpfr_class, mpfr_class>> alwaysZeroCapacity;
		alwaysZeroCapacity.push_back(std::make_pair(mpfr_class(0), mpfr_class(1)));
		capacityDistribution zeroDistribution(alwaysZeroCapacity);

		for(; start != end; start++)
		{
			//This has all the reverse edges too. 
			int source = boost::source(*start, *inputDirectedGraph), target = boost::target(*start, *inputDirectedGraph);
			std::pair<internalGraph::edge_descriptor, bool> tmp = boost::edge(source, target, *internalDirectedGraph);
			//Doing it this way because I'm not sure if add_edge overwrites the edge_index in the case that the edge already exists. 
			internalGraph::edge_descriptor firstEdge;
			int inputEdgeIndex = boost::get(boost::edge_index, *inputDirectedGraph, *start);
			if(!tmp.second)
			{
				firstEdge = boost::add_edge(source, target, index, *internalDirectedGraph).first;
				//Put in the distribution for the original directed edge
				distributions.push_back(inputDistributions[inputEdgeIndex].makeCopy());
				index++;
			}
			else 
			{
				firstEdge = tmp.first;
				distributions[boost::get(boost::edge_index, *internalDirectedGraph, firstEdge)] = inputDistributions[inputEdgeIndex].makeCopy();
			}

			internalGraph::edge_descriptor secondEdge;
			tmp = boost::edge(target, source, *internalDirectedGraph);
			if(!tmp.second)
			{
				secondEdge = boost::add_edge(target, source, index, *internalDirectedGraph).first;
				distributions.push_back(alwaysZeroCapacity);
				index++;
			}
			else secondEdge = tmp.first;
			//Put in reverse edges
			boost::put(boost::edge_reverse, *internalDirectedGraph, firstEdge, secondEdge);
			boost::put(boost::edge_reverse, *internalDirectedGraph, secondEdge, firstEdge);
		}
		std::size_t nEdgesWithReverse = boost::num_edges(*internalDirectedGraph);
		capacityVector.resize(nEdgesWithReverse);
		edgeResidualCapacityVector.resize(nEdgesWithReverse);
		vertexPredecessorVector.resize(nEdgesWithReverse);
		vertexPredecessorVector.resize(nEdgesWithReverse);
		colorVector.resize(nEdgesWithReverse);
		distanceVector.resize(nEdgesWithReverse);

		this->graph = internalDirectedGraph;
		if(distributions.size() != boost::num_edges(*internalDirectedGraph.get()))
		{
				throw std::runtime_error("Internal error");
		}
	}
	void averageComponentSize()
	{
		const context& contextObj = args.contextObj;
		const context::inputGraph& graph = contextObj.getGraph();
		std::size_t nVertices = boost::num_vertices(graph);
		std::vector<mpfr_class>& probabilities = contextObj.getProbabilities();

		std::vector<unsigned long long> integerSum(nVertices, 0);
		for(int i = 0; i < n; i++)
		{
			observation obs(args.contextObj, args.randomSource);
			isSingleComponentAllOn(args.contextObj, obs.getState(), scratchMemory, stack);
		}

		result.clear();
		std::transform(integerSum.begin(), integerSum.end(), std::make_back_inserter(result), [n](unsigned long long x){return mpfr_class(x)/mpfr_class(n);});
	}
Esempio n. 5
0
SEXP customMCMC(SEXP nVertices_sexp, SEXP approximateCounts_sexp, SEXP seed_sexp, SEXP burnIn_sexp, SEXP runSize_sexp)
{
BEGIN_RCPP
	int nVertices;
	try
	{
		nVertices = Rcpp::as<int>(nVertices_sexp);
	}
	catch(...)
	{
		throw std::runtime_error("Input nVertices must be an integer");
	}

	std::vector<std::string> approximateCounts_string;
	try
	{
		approximateCounts_string = Rcpp::as<std::vector<std::string> >(approximateCounts_sexp);
	}
	catch(...)
	{
		throw std::runtime_error("Input approximateCounts must be a character vector");
	}
	std::vector<mpfr_class> approximateCounts;
	std::transform(approximateCounts_string.begin(), approximateCounts_string.end(), std::back_inserter(approximateCounts), [](std::string x){return mpfr_class(x);});

	int seed;
	try
	{
		seed = Rcpp::as<int>(seed_sexp);
	}
	catch(...)
	{
		throw std::runtime_error("Input seed must be an integer");
	}

	int burnIn;
	try
	{
		burnIn = Rcpp::as<int>(burnIn_sexp);
	}
	catch(...)
	{
		throw std::runtime_error("Input burnIn must be an integer");
	}

	int runSize;
	try
	{
		runSize = Rcpp::as<int>(runSize_sexp);
	}
	catch(...)
	{
		throw std::runtime_error("Input runSize must be an integer");
	}
	boost::mt19937 randomSource;
	randomSource.seed(seed);

	chordalGraph::mcmcArgs args(randomSource);
	args.nVertices = nVertices;
	args.approximateCounts.swap(approximateCounts);
	args.burnIn = burnIn;
	args.runSize = runSize;
	chordalGraph::customMCMC(args);

	std::vector<std::string> returnValues;
	std::transform(args.estimates.begin(), args.estimates.end(), std::back_inserter(returnValues), [](mpfr_class x){return x.str(10, std::ios_base::dec); });

	return Rcpp::wrap(returnValues);
END_RCPP
}
Esempio n. 6
0
	void stepCustom(cliqueTreeType& currentTree, graphType& graph, std::vector<mpfr_class>& exactValues, int nVertices, boost::mt19937& randomSource, working& temp, int edgeLimit)
	{
		boost::random::uniform_int_distribution<> randomVertexDist(0, nVertices-1);
		boost::random::bernoulli_distribution<> standardBernoulli;
		boost::random::uniform_real_distribution<> standardUniform;
		int randomVertex1, randomVertex2;
		do
		{
			randomVertex1 = randomVertexDist(randomSource);
			randomVertex2 = randomVertexDist(randomSource);
		} while(randomVertex1 == randomVertex2);
		std::size_t original_edges = boost::num_edges(graph);
		std::pair<graphType::edge_descriptor, bool> existingEdge = boost::edge(randomVertex1, randomVertex2, graph);

		cliqueTreeAdjacencyMatrix& copied = temp.copied;
		//Here we remove edges
		if(existingEdge.second)
		{
			int cliqueVertex = -1;
			//Can we remove this edge?
			if(currentTree.canRemoveEdge(randomVertex1, randomVertex2, temp.counts1, cliqueVertex))
			{
				//Form tree of removable edge subsets and work out the counts. 
				currentTree.formRemovalTree(temp.stateCounts, copied, randomVertex1, randomVertex2, temp.uniqueSubsets, temp.removalTemporaries);
				//The maximum number of other removable edges, in addition to edge (u, v).  
				int maximumOtherRemovableEdges = 0;
				for(int i = 0; i < nVertices; i++) 
				{
					if(temp.stateCounts[i] == 0) break;
					maximumOtherRemovableEdges = i;
				}
				//The number of edges to actually remove for the proposal. 
				int extraToRemove = 0;
				//Compute probabilities and normalizing constant. 
				temp.probabilities.clear();
				double sum1 = 0;
				for(int i = 0; i < maximumOtherRemovableEdges + 1; i++)
				{
					temp.probabilities.push_back(mpfr_class(exactValues[original_edges] / exactValues[original_edges - i - 1]).convert_to<double>());
					sum1 += temp.probabilities.back();
				}
				if(maximumOtherRemovableEdges > 0)
				{
					boost::random::discrete_distribution<> extraNumberToRemoveDist(temp.probabilities.begin(), temp.probabilities.end());
					extraToRemove = extraNumberToRemoveDist(randomSource);
				}
				//The acceptance probability for the Metropolis-Hasting proposal. 
				mpfr_class acceptanceProbability = 0;
				//If we actually only remove a single edge then things are more complicated - There are two ways this can happen, the second way corresponds to swapping randomVertex1 and randomVertex2
				if(extraToRemove == 0)
				{
					//Form tree of removable edge subsets and work out the counts. 
					currentTree.formRemovalTree(temp.stateCounts, copied, randomVertex2, randomVertex1, temp.uniqueSubsets, temp.removalTemporaries);
					
					int maximumOtherRemovableEdges2 = 0;
					for(int i = 0; i < nVertices; i++)
					{
						if(temp.stateCounts[i] == 0) break;
						maximumOtherRemovableEdges2 = i;
					}
					double sum2 = 0;
					for(int i = 0; i < maximumOtherRemovableEdges2 + 1; i++)
					{
						sum2 += mpfr_class(exactValues[original_edges] / exactValues[original_edges - i - 1]).convert_to<double>();
					}
					acceptanceProbability = 1/(0.5 * (1/sum1 + 1/sum2));
				}
				else acceptanceProbability = sum1 * temp.stateCounts[extraToRemove];
				if(acceptanceProbability >= 1 || standardUniform(randomSource) <= acceptanceProbability.convert_to<double>())
				{
					currentTree.removeEdgeKnownCliqueVertex(randomVertex1, randomVertex2, temp.colourVector, temp.counts2, cliqueVertex);
					boost::remove_edge(randomVertex1, randomVertex2, graph);
					if(extraToRemove != 0)
					{
						boost::random::uniform_int_distribution<> randomSubset(0, temp.stateCounts[extraToRemove] - 1);
						int index = randomSubset(randomSource);
						bitsetType chosenSubset;
						for(std::unordered_set<bitsetType>::iterator i = temp.uniqueSubsets.begin(); i != temp.uniqueSubsets.end(); i++)
						{
							if((int)i->count() == extraToRemove+1)
							{
								if(index == 0)
								{
									chosenSubset = *i;
									break;
								}
								index--;
							}
						}
						//This is 1 rather than 0, because the edge randomVertex1, randomVertex2 is already deleted. 
						while(chosenSubset.count() > 1)
						{
							currentTree.canRemoveEdge(randomVertex1, randomVertex2, temp.counts1, cliqueVertex);
							for(int i = 0; i < nVertices; i++)
							{
								if(chosenSubset[i] && temp.counts1[i] == 1)
								{
									chosenSubset[i] = false;
									currentTree.tryRemoveEdge(randomVertex1, i, temp.colourVector, temp.counts2);
									boost::remove_edge(randomVertex1, i, graph);
								}
							}
						}
					}
				}
			}
		}
		//Here we add edges
		else
		{
			cliqueTreeAdjacencyMatrix& copied2 = temp.copied2;
			bitsetType newEdgesVertex1;
			currentTree.unionMinimalSeparators(randomVertex1, randomVertex2, newEdgesVertex1, temp.vertexSequence, temp.edgeSequence, temp.addEdges, temp.removeEdges, temp.unionMinimalSepTemp);
			int increaseInEdges = 1;
			for(int i = 0; i < nVertices; i++)
			{
				if(newEdgesVertex1[i] && !boost::edge(i, randomVertex1, graph).second) increaseInEdges++;
			}
			if((int)original_edges + increaseInEdges <= edgeLimit)
			{
				mpfr_class acceptanceProbability;
				if(increaseInEdges != 1)
				{
					copied.makeCopy(currentTree);
					//Actually add the edges to the copy
					copied.addEdge(randomVertex1, randomVertex2, newEdgesVertex1, temp.vertexSequence, temp.edgeSequence, temp.addEdges, temp.removeEdges, temp.unionMinimalSepTemp, true);
					copied.formRemovalTree(temp.stateCounts, copied2, randomVertex1, randomVertex2, temp.uniqueSubsets, temp.removalTemporaries);
					//Work out how many more edges can be removed from the original
					int otherBackwardsCanRemove = 0;
					for(int i = 0; i < nVertices; i++) 
					{
						if(temp.stateCounts[i] == 0) break;
						otherBackwardsCanRemove = i;
					}

					double sum = 0;
					for(int i = 0; i < otherBackwardsCanRemove + 1; i++)
					{
						sum += mpfr_class(exactValues[original_edges + increaseInEdges] / exactValues[original_edges + increaseInEdges - i - 1]).convert_to<double>();
					}
					acceptanceProbability = 1/(sum * temp.stateCounts[increaseInEdges - 1]);
				}
				else
				{
					copied.makeCopy(currentTree);
					//Actually add the edges to the copy
					copied.addEdge(randomVertex1, randomVertex2, newEdgesVertex1, temp.vertexSequence, temp.edgeSequence, temp.addEdges, temp.removeEdges, temp.unionMinimalSepTemp, true);
					//Form removal tree with the vertices the same way round
					copied.formRemovalTree(temp.stateCounts, copied2, randomVertex1, randomVertex2, temp.uniqueSubsets, temp.removalTemporaries);
					//Work out how many more edges can be removed from the original
					int otherBackwardsCanRemove = 0;
					for(int i = 0; i < nVertices; i++) 
					{
						if(temp.stateCounts[i] == 0) break;
						otherBackwardsCanRemove = i;
					}

					double sum1 = 0;
					for(int i = 0; i < otherBackwardsCanRemove + 1; i++)
					{
						sum1 += mpfr_class(exactValues[original_edges + increaseInEdges] / exactValues[original_edges + increaseInEdges - i - 1]).convert_to<double>();
					}
					//Form removal tree with the vertices reversed
					copied.formRemovalTree(temp.stateCounts, copied2, randomVertex2, randomVertex1, temp.uniqueSubsets, temp.removalTemporaries);
					//Work out how many more edges can be removed from the original
					int otherBackwardsCanRemove2 = 0;
					for(int i = 0; i < nVertices; i++) 
					{
						if(temp.stateCounts[i] == 0) break;
						otherBackwardsCanRemove2 = i;
					}

					double sum2 = 0;
					for(int i = 0; i < otherBackwardsCanRemove2 + 1; i++)
					{
						sum2 += mpfr_class(exactValues[original_edges + increaseInEdges] / exactValues[original_edges + increaseInEdges - i - 1]).convert_to<double>();
					}
					acceptanceProbability = 0.5 * (1/sum1 + 1/sum2);
				}
				if (acceptanceProbability >= 1 || standardUniform(randomSource) <= acceptanceProbability.convert_to<double>())
				{
					currentTree.swap(copied);
					newEdgesVertex1[randomVertex2] = true;
					for(int i = 0; i < nVertices; i++)
					{
						if(newEdgesVertex1[i])
						{
							boost::add_edge(randomVertex1, i, graph);
						}
					}
				}
			}
		}
#ifndef NDEBUG
		currentTree.check();
#endif
	}
	bool stochasticEnumeration2(stochasticEnumerationArgs& args)
	{
		const context::inputGraph& graph = args.graph;
		const std::size_t nVertices = boost::num_vertices(graph);
		boost::random_number_generator<boost::mt19937> generator(args.randomSource);

		int vertexCount = args.vertexCount;
		if (vertexCount > (int)nVertices)
		{
			args.message = "Input vertexCount cannot be larger than the number of vertices";
			return false;
		}
		if(vertexCount == 0)
		{
			args.estimate = 1; return true;
		}
		else if(vertexCount == 1)
		{
			args.estimate = nVertices; 
			return true;
		}

		int n = args.n;
		if(n < 2)
		{
			args.message = "Input n must be greater than 2";
			return false;
		}

		int nPermutations = args.nPermutations;
		if (nPermutations < 1)
		{
			args.message = "Input nPermutations must be at least 1";
			return false;
		}

		std::vector<int> nActiveVertices(n, 0);
		std::vector<int> anActiveVertex(n, 0);
		std::vector<int> rank(n*nVertices, 0);
		std::vector<int> parent(n*nVertices, 0);
		std::vector<bool> alreadyPresent(n*nVertices, false);

		std::vector<int> copiedNActiveVertices(n, 0);
		std::vector<int> copiedAnActiveVertex(n, 0);
		std::vector<int> copiedRank(n*nVertices, 0);
		std::vector<int> copiedParent(n*nVertices, 0);
		std::vector<bool> copiedAlreadyPresent(n*nVertices, false);

		//Scratch memory
		std::vector<std::pair<int, int> > scratchPairs;
		scratchPairs.reserve(n * 2);

		//Scratch memory for depth first search
		typedef boost::color_traits<boost::default_color_type> Color;
		std::vector<boost::default_color_type> colors(nVertices, Color::black());
		std::vector<int> connectedComponentVector(nVertices);
		boost::detail::depth_first_visit_restricted_impl_helper<context::inputGraph>::stackType stack;
		std::vector<context::inputGraph::vertex_descriptor> initialVertex(0);
		initialVertex.reserve(nVertices);

		//The permutation is initially the identity. This means that if we set nPermutations = 1 we will get the same permutation for every seed. 
		std::vector<int> permutation(boost::counting_iterator<int>(0), boost::counting_iterator<int>((int)nVertices));
		mpfr_class totalOverPermutations = 0;
		for(int permutationCounter = 0; permutationCounter < args.nPermutations; permutationCounter++)
		{
			//It seems the easiest thing is to actually reorder the vertices within the graph (because we rely on being able to easily determine which vertices are AFTER the current vertex)
			context::inputGraph reorderedGraph(nVertices);
			{
				context::inputGraph::edge_iterator current, end;
				boost::tie(current, end) = boost::edges(graph);
				for(; current != end; current++)
				{
					boost::add_edge(permutation[current->m_source], permutation[current->m_target], reorderedGraph);
				}
			}

			//Initialize the algorithm by having the first vertex both up and down. 
			int nParticles = 2;
			{
				boost::disjoint_sets<int*, int*> ds(&rank[0], &parent[0]);
				ds.make_set(0);
			}
			nActiveVertices[0] = 1;
			nActiveVertices[1] = 0;
			alreadyPresent[0] = true;
			alreadyPresent[nVertices] = false;
			anActiveVertex[0] = 0;
			std::fill(rank.begin(), rank.end(), 0);
			std::fill(parent.begin(), parent.end(), 0);

			mpfr_class total = 0;
			mpfr_class multiple = 1;

			for(int vertexCounter = 1; vertexCounter < (int)nVertices; vertexCounter++)
			{
				scratchPairs.clear();
				if(nParticles == 0) break;
				int nConnected = 0;
				for(int particleCounter = 0; particleCounter < nParticles; particleCounter++)
				{
					//No more vertices will be added to this particle
					if(nActiveVertices[particleCounter] == vertexCount)
					{
						boost::disjoint_sets<int*, int*> ds(&rank[particleCounter*nVertices], &parent[particleCounter*nVertices]);
						int connectedComponents = 0;
						for(int i = 0; i < (int)vertexCounter; i++)
						{
							if(alreadyPresent[particleCounter*nVertices+i]) connectedComponents += parent[particleCounter*nVertices+i] == i;
						}
						nConnected += connectedComponents == 1;
					}
					//All remaining vertices will be added to this particle
					else if(nActiveVertices[particleCounter] + (int)nVertices - vertexCounter == vertexCount)
					{
						boost::disjoint_sets<int*, int*> ds(&rank[particleCounter*nVertices], &parent[particleCounter*nVertices]);
						//Add in remaining vertices
						for(int k = vertexCounter; k < (int)nVertices; k++)
						{
							ds.make_set(k);
							context::inputGraph::out_edge_iterator current, last;
							boost::tie(current, last) = boost::out_edges(k, reorderedGraph);
							for(; current != last; current++)
							{
								int other = (int)current->m_target;
								if((alreadyPresent[particleCounter*nVertices+other] && other < vertexCounter) || (other <= k && other >= vertexCounter))
								{
									ds.union_set(other, k);
								}
							}
						}
						int connectedComponents = 0;
						for(int i = 0; i < (int)nVertices; i++)
						{
							if(alreadyPresent[particleCounter*nVertices+i] || i >= vertexCounter) connectedComponents += parent[particleCounter*nVertices+i] == i;
						}
						nConnected += (connectedComponents == 1);
					}
					//In this case we have a choice of whether or not to take this vertex as active. So we check that
					//1. This vertex is contained in the connected component attached to anActiveVertex[particleCounter]
					//2. The connected component attached to anActiveVertex has at least vertexCount vertices
					else
					{
						bool possiblyOn = true, possiblyOff = true;
						if(nActiveVertices[particleCounter] > 0) 
						{
							//Colours are initially all white
							std::fill(colors.begin(), colors.end(), Color::white());
							//Those that are fixed at OFF are marked as black
							for(int i = 0; i < vertexCounter; i++) 
							{
								if(!alreadyPresent[particleCounter*nVertices+i]) colors[i] = Color::black();
							}
							initialVertex.clear();
							initialVertex.push_back(anActiveVertex[particleCounter]);
							//First the maximum size with this vertex on
							std::fill(connectedComponentVector.begin(), connectedComponentVector.end(), -1);
							boost::connected_components_restricted(reorderedGraph, &(connectedComponentVector[0]), &(colors[0]), stack, initialVertex);
							int importantComponent = connectedComponentVector[initialVertex[0]];
							int maximumSizeOn = 0;
							for(int i = 0; i < (int)nVertices; i++)
							{
								if(connectedComponentVector[i] == importantComponent) maximumSizeOn++;
							}
							//If (no matter how many more vertices we add) we cannot reach the desired component size, then this corresponds to a leaf with zero children, and 0 cost. So skip this one completely
							if(maximumSizeOn < vertexCount) continue;
							//If the vertex under consideration is in a different connected component then it can't be on
							if (connectedComponentVector[vertexCounter] != importantComponent)
							{
								possiblyOn = false;
							}
							int maximumSizeOff = 0;
							std::fill(connectedComponentVector.begin(), connectedComponentVector.end(), -1);
							std::fill(colors.begin(), colors.end(), Color::white());
							initialVertex.clear();
							//Those that are fixed at OFF are marked as black
							for (int i = 0; i < vertexCounter; i++)
							{
								if (!alreadyPresent[particleCounter*nVertices + i]) colors[i] = Color::black();
								else initialVertex.push_back(i);
							}
							colors[vertexCounter] = Color::black();
							boost::connected_components_restricted(reorderedGraph, &(connectedComponentVector[0]), &(colors[0]), stack, initialVertex);
							bool multipleComponents = false;
							for (int i = 0; i < (int)nVertices; i++)
							{
								if (connectedComponentVector[i] == importantComponent) maximumSizeOff++;
								else if (i < vertexCounter && alreadyPresent[particleCounter*nVertices + i]) multipleComponents = true;
							}
							if (maximumSizeOff < vertexCount || multipleComponents) possiblyOff = false;
						}
						if(possiblyOn)
						{
							scratchPairs.push_back(std::make_pair(particleCounter, 1));
						}
						if (possiblyOff)
						{
							scratchPairs.push_back(std::make_pair(particleCounter, 0));
						}
					}
				}
				int newParticlesCount = std::min(n, (int)scratchPairs.size());
				boost::random_shuffle(scratchPairs, generator);
				total += multiple * nConnected;
				multiple *= mpfr_class(scratchPairs.size()) / mpfr_class(newParticlesCount);

				for(int particleCounter = 0; particleCounter < newParticlesCount; particleCounter++)
				{
					std::pair<int, int> newParticleData = *scratchPairs.rbegin();
					scratchPairs.pop_back();

					//Same number of active vertices, or maybe one more. 
					copiedNActiveVertices[particleCounter] = nActiveVertices[newParticleData.first] + newParticleData.second;
					//Copy rank data
					std::copy(rank.begin() + (newParticleData.first*nVertices), rank.begin() + (newParticleData.first+1)*nVertices, copiedRank.begin() + particleCounter*nVertices);
					//copy parent data
					std::copy(parent.begin() + (newParticleData.first*nVertices), parent.begin() + (newParticleData.first+1)*nVertices, copiedParent.begin() + (particleCounter*nVertices));
					//copy already present data
					std::copy(alreadyPresent.begin() + newParticleData.first*nVertices, alreadyPresent.begin() + (newParticleData.first+1)*nVertices, copiedAlreadyPresent.begin() + particleCounter*nVertices);
					//Copy data about a (random) active vertex (for use in depth-first search)
					copiedAnActiveVertex[particleCounter] = anActiveVertex[newParticleData.first];
					//Add extra vertex, if required
					if(newParticleData.second)
					{
						copiedAlreadyPresent[particleCounter * nVertices + vertexCounter] = true;
						copiedAnActiveVertex[particleCounter] = vertexCounter;

						boost::disjoint_sets<int*, int*> ds(&copiedRank[particleCounter*nVertices], &copiedParent[particleCounter*nVertices]);
						ds.make_set(vertexCounter);

						context::inputGraph::out_edge_iterator current, last;
						boost::tie(current, last) = boost::out_edges(vertexCounter, reorderedGraph);
						for(; current != last; current++)
						{
							if((int)current->m_target < vertexCounter && copiedAlreadyPresent[particleCounter*nVertices + current->m_target])
							{
								ds.union_set(vertexCounter, (int)current->m_target);
							}
						}
					}
					else
					{
						copiedAlreadyPresent[particleCounter * nVertices + vertexCounter] = false;
					}
				}

				nActiveVertices.swap(copiedNActiveVertices);
				rank.swap(copiedRank);
				parent.swap(copiedParent);
				alreadyPresent.swap(copiedAlreadyPresent);
				anActiveVertex.swap(copiedAnActiveVertex);
				nParticles = newParticlesCount;
			}
			boost::random_shuffle(permutation, generator);
			std::string totalStr = total.str();
			totalOverPermutations += total;
		}

		args.estimate = totalOverPermutations/nPermutations;
		return true;
	}