private HashSet <BlockSet> ExploreExistingCosetsByNewGenerator(CubeAction newGenerator)
                {
                    var newStates = new HashSet <BlockSet>();

                    int walkedCount    = 0;
                    var needWalkStates = new HashSet <BlockSet>(OrbitToCoset.Keys);

                    foreach (var startState in needWalkStates)
                    {
                        walkedCount++;

                        var newState = ExploreNewCoset(startState, newGenerator);
                        if (newState != null)
                        {
                            newStates.Add(newState);

                            Console.WriteLine(
                                $"Stablized[{Stablized.Indexes.Count}] " +
                                $"ExploreNewGeneratorOnExistingCosets: foundCount/needWalk/total=" +
                                $"{newStates.Count}/{needWalkStates.Count - walkedCount}/{OrbitToCoset.Count} " +
                                $"newState=[{newState}] newCoset=[{OrbitToCoset[newState].Count()}] " +
                                $"startState=[{startState}] generator=[{newGenerator.Count()}]");
                        }
                    }

                    return(newStates);
                }
                /// <summary>
                /// Stablizer chain algorithm templated from https://www.jaapsch.net/puzzles/schreier.htm.
                ///
                /// __Basic stablizer chain algorithm__
                ///
                /// Each GStep in the stablizer chain corresponds to gradually more blocks were rotated to
                /// the ideal cube position. Since the next GStep stablizes more blocks, it's the subgroup
                /// of the previous GStep.
                ///
                /// To obtain the next GStep, we obtain its generators. Subgroup generators can be obtained
                /// by Schreier subgroup lemma. It needs the set of cosets, i.e. coset representatives, and
                /// the parent group generators.
                ///
                /// Coset representatives can be obtained by repeating permutation of parent group generators.
                /// We know coset representatives are 1-on-1 mapping to block states we are trying to stablize.
                /// So we can find whether coset representatives are equal, or whether we walked all of them.
                ///
                /// So, giving parent group generators, we can obtain subgroup generators. Recursively, we
                /// walk along the stablizer chain of GSteps, until we solved all blocks.
                ///
                /// __Incremental stablizer chain algorithm__
                ///
                /// The problem is, the count of generators grow exponentially along the stablizer chain.
                /// We want to know whether a generator is not necessary, i.e. this generator and all descendants
                /// generators discovered by it, won't help us find any new cosets.
                ///
                /// The cosets at each GStep stablizer chain are the final results we want. Because given a cube
                /// state, we use 1-on-1 mapping to know its coset representative, We use the reverse of the coset
                /// representative to rotate the cube to ideal position. We do it along the stablizer chain, we
                /// then solve the cube.
                ///
                /// That's why, if a generator discovers no new coset, the generator is not necessary. We can then
                /// rewrite the algorithm in the new way, to incrementally add generators one by one. If a generator
                /// is found not necessary, we then discard it, so that it won't further exponentially increase our
                /// computation overhead.
                /// </summary>
                public int AddGeneratorIncrementally(CubeAction newGenerator, List <ProgressInfo> progressInfoList)
                {
                    if (null == Generators)
                    {
                        Generators = new HashSet <CubeAction>();
                    }

                    if (null == RejectedGenerators)
                    {
                        RejectedGenerators = new HashSet <CubeAction>();
                    }
                    if (RejectedGenerators.Contains(newGenerator))
                    {
                        return(0);
                    }

                    if (PrintProgress)
                    {
                        foreach (var p in progressInfoList)
                        {
                            Console.Write($"{p.StablizedCount}:{p.CompletedWork}/{p.TotalWork} ");
                        }
                        Console.WriteLine();

                        Console.WriteLine(
                            $"{new string(' ', Stablized.Indexes.Count)}" +
                            $"{Stablized.Indexes.Count} - G:{newGenerator.Count()} " +
                            $"FC:{GeneratorFilter.JumpCount} GC:{Generators.Count} " +
                            $"CC:{(OrbitToCoset != null ? OrbitToCoset.Count : 0)} RJ:{RejectedGenerators.Count}");
                    }

                    var filteredGenerator = GeneratorFilter.FilterGeneratorIncrementally(newGenerator);

                    if (filteredGenerator != null)
                    {
                        newGenerator = filteredGenerator;
                    }
                    else
                    {
                        RejectedGenerators.Add(newGenerator);
                        return(0);
                    }

                    if (Generators.Contains(newGenerator))
                    {
                        Utils.DebugAssert(false);
                        return(0);
                    }

                    ProgressInfo progressInfo    = null;
                    int          foundStateCount = 0;

                    {
                        var newStates = ExploreOrbitToCosetIncrementally(newGenerator);
                        foundStateCount += newStates.Count;

                        var newSubgroupGenerators = ObtainGeneratorsOfStablizerSubgroupIncrementally(
                            newGenerator, newStates);

                        if (Next != null)
                        {
                            progressInfo = new ProgressInfo(Stablized.Indexes.Count, newSubgroupGenerators.Count);
                            progressInfoList.Add(progressInfo);
                            foreach (var subgroupGenerator in newSubgroupGenerators)
                            {
                                foundStateCount += Next.AddGeneratorIncrementally(subgroupGenerator, progressInfoList);
                                progressInfo.CompletedWork++;
                            }
                        }
                    }

                    Utils.DebugAssert(GeneratorFilter.AcceptedGeneratorCount == Generators.Count);
                    Console.WriteLine(
                        $"Stablized[{Stablized.Indexes.Count}] " +
                        $"AddGeneratorIncrementally: Accepted new generator: " +
                        $"foundStateCount={foundStateCount} Generators={Generators.Count} " +
                        $"Cosets={OrbitToCoset.Count} FilterCount={GeneratorFilter.JumpCount} " +
                        $"newGenerator=[{newGenerator.Count()}]");

                    if (progressInfo != null)
                    {
                        progressInfoList.RemoveAt(progressInfoList.Count - 1);
                    }
                    return(foundStateCount);
                }