//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);
        }