//public IEnumerable<List<int>> EnumerateMIS(Graph graph) //{ // var primaryGraph = new GraphFast(graph); // var complementaryGraph = new GraphFast(graph); // var ignoredVertex = new bool[graph.VerticesKVPs.Length]; // var verticesAlreadyInMIS = new List<int>(); // foreach (var mis in FindMIS(primaryGraph, complementaryGraph, verticesAlreadyInMIS, ignoredVertex, 0)) // { // yield return mis.vertices; // } //} private Solution Recurse(int n, GraphFast primaryGraph, GraphFast complementaryGraph, Solution currentSolution, Solution bestSolution, int latestMisSize = int.MaxValue, int lastMisId = int.MaxValue) { if (complementaryGraph.vertexCount == 0) { if (currentSolution.colourCount < bestSolution.colourCount) { bestSolution = currentSolution.DeepClone(); NewBestSolutionFound?.Invoke(null, new PerformanceReport() { minimalNumberOfColoursUsed = bestSolution.colourCount, elapsedProcessorTime = stopwatch.Elapsed }); } } else if (currentSolution.colourCount + 1 < bestSolution.colourCount) // could improve this bound by finding a clique { // get MIS get and complimentary graph // compute subsolution var verticesAlreadyInMIS = new List <int>(); currentSolution.colourCount += 1; var ignoredVertex = new bool[n]; FindMIS(primaryGraph, complementaryGraph, verticesAlreadyInMIS, ignoredVertex, 0, mis => { // optionally check for cliques to delete if (mis.vertices.Count < latestMisSize || (mis.vertices.Count == latestMisSize && mis.vertices[0] > lastMisId))// pre-optimization { currentSolution.colourLayer.Push(mis.vertices); bestSolution = Recurse(n, complementaryGraph, complementaryGraph.DeepIrreversibleClone(), currentSolution, bestSolution, mis.vertices.Count, mis.vertices[0]); currentSolution.colourLayer.Pop(); } // need to fix the enumerator to ensure breakability return(currentSolution.colourCount < bestSolution.colourCount); }); currentSolution.colourCount -= 1; } return(bestSolution); }
private Solution Recurse(Graph graphToColour, Solution currentSolution, Solution bestSolution, ref int upperBoundOnNumberOfSteps, double alphaRatio, int maxDepth) { if (upperBoundOnNumberOfSteps != -1 && bestSolution.colourCount < int.MaxValue) { if (upperBoundOnNumberOfSteps == 0) { return(bestSolution); } else { upperBoundOnNumberOfSteps -= 1; } } if (currentSolution.solvedCount < graphToColour.VerticesKVPs.Length) { // choose a vertex to colour var vertexToColour = ChooseSuitableVertex(graphToColour, currentSolution, bestSolution, out var colouringPossibilities, maxDepth); // for in possible colours foreach (var colour in colouringPossibilities) { var increasedColourCount = false; if (colour >= currentSolution.colourCount) { if (colour > currentSolution.colourCount) { throw new Exception("New colour is too large"); } currentSolution.colourCount += 1; increasedColourCount = true; } if (currentSolution.colourCount * alphaRatio < bestSolution.colourCount) { currentSolution.vertexToColour[vertexToColour] = colour; currentSolution.solvedCount += 1; // recurse and update best statistics bestSolution = Recurse(graphToColour, currentSolution, bestSolution, ref upperBoundOnNumberOfSteps, alphaRatio, maxDepth); currentSolution.solvedCount -= 1; currentSolution.vertexToColour[vertexToColour] = -1; } if (increasedColourCount) { currentSolution.colourCount -= 1; } } } else { // no more vertices to colour // if the solution is indeed better... if (currentSolution.colourCount >= bestSolution.colourCount) { throw new Exception("Proposed solution is not better"); } // warning! there may be vertices with negative colourings! bestSolution = currentSolution.DeepClone(); NewBestSolutionFound?.Invoke(null, new PerformanceReport() { minimalNumberOfColoursUsed = bestSolution.colourCount, elapsedProcessorTime = stopwatch.Elapsed }); } return(bestSolution); }