public Dictionary <int, int> ColourGraph(Graph graph) { stopwatch.Restart(); var dummySolution = new Solution() { colourCount = int.MaxValue, }; var initialSolution = new Solution() { colourCount = 0, colourLayer = new Stack <List <int> >() }; graph = graph.CloneNeighboursSorted(v => graph.VerticesKVPs[v].Length); // var solution = Recurse(graph, initialSolution, dummySolution, ref leftSteps, alphaRatio).vertexToColour; var dictionary = new Dictionary <int, int>(); //var misCount = 0; //var largestMIS = 0; //foreach (var mis in EnumerateMIS(graph)) //{ // misCount += 1; // if (mis.vertices.Count > largestMIS) // largestMIS = mis.vertices.Count; //} //System.Console.WriteLine($"MIS count: {misCount}, largest: {largestMIS}"); var ignoredVertices = new bool[graph.VerticesKVPs.Length]; var primaryGraph = new GraphFast(graph); var complementaryGraph = new GraphFast(graph); var bestSolution = Recurse(graph.VerticesKVPs.Length, primaryGraph, complementaryGraph, initialSolution, dummySolution); var layerColour = 0; foreach (var layer in bestSolution.colourLayer) { foreach (var vertex in layer) { dictionary.Add(vertex, layerColour); } layerColour += 1; } stopwatch.Stop(); return(dictionary); }
//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); }
// ignoredVertexCount might turn out to be useless private bool FindMIS( GraphFast graph, GraphFast complementaryGraph, List <int> verticesAlreadyInMIS, bool[] ignoredVertex, int ignoredVertexCount, Func <MisResult, bool> consumeAndDecideToContinue) { var continueExecution = true; // add detailed parameters if (graph.vertexCount == 0) { // ignored vertices can only be removed by nonignored so the following if is unnecessary // if (ignoredVertexCount == 0) continueExecution = consumeAndDecideToContinue(new MisResult() { graphWithoutMIS = complementaryGraph, vertices = verticesAlreadyInMIS }); } else { // choose a vertex v var chosenVertex = -1; var vertexScore = int.MinValue; for (int i = 0; i < graph.vertexCount; i++) { var tmpVertex = graph.vertices[i]; if (!ignoredVertex[tmpVertex]) { var tmpVertexScore = graph.neighbourCount[tmpVertex]; if (tmpVertexScore > vertexScore) { chosenVertex = tmpVertex; vertexScore = tmpVertexScore; } } } if (chosenVertex != -1) { // ADD VERTEX V TO MIS // remove the vertex and all its neighbours var neighbours = graph.neighbours[chosenVertex]; var neighbourCount = graph.neighbourCount[chosenVertex]; graph.RemoveVertex(chosenVertex); var newIgnoredVertexCount = ignoredVertexCount; for (int i = 0; i < neighbourCount; i++) { var neighbour = neighbours[i]; if (ignoredVertex[neighbour]) { newIgnoredVertexCount -= 1; } graph.RemoveVertex(neighbour); } // construct complementary graph complementaryGraph.RemoveVertex(chosenVertex); verticesAlreadyInMIS.Add(chosenVertex); continueExecution = FindMIS(graph, complementaryGraph, verticesAlreadyInMIS, ignoredVertex, newIgnoredVertexCount, consumeAndDecideToContinue); verticesAlreadyInMIS.RemoveAt(verticesAlreadyInMIS.Count - 1); complementaryGraph.RestoreDeletedVertex(); // restore for (int i = 0; i < neighbourCount; i++) { graph.RestoreDeletedVertex(); } graph.RestoreDeletedVertex(); // DO NOT ADD VERTEX V TO MIS // TODO: add warnings to his neighbours, add notion that the chosen vertex needs to be "covered" by someone! // each vertex has a satifiability list // there is a variable representing vertices left to satisfy // each vertex has a counter that (when >0) triggers satisfiability stuff // TODO make extra checks here and there is it possible to satisfy an ignored vertex, if not STOP if (continueExecution && graph.neighbourCount[chosenVertex] > 0) { ignoredVertex[chosenVertex] = true; continueExecution = FindMIS(graph, complementaryGraph, verticesAlreadyInMIS, ignoredVertex, ignoredVertexCount + 1, consumeAndDecideToContinue); ignoredVertex[chosenVertex] = false; } } } return(continueExecution); }