///<param name="onlyNonTrivialZeros">
        ///If true, only empty expansion lists will be returned,
        ///and of those none will correspond to z values that are divisible by 3.
        ///</param>
        public static IEnumerable <KeyValuePair <BigInteger, BigInteger> > IterateExpansionCounts(BigInteger maxZ, bool onlyNonTrivialZeros = false, Action <ExpansionTerm> currentPathStartingPointPrinter = null)
        {
            var termOptions = new TermOptionsMatrix(maxZ);

            var foundExpansionCounts = new Dictionary <BigInteger, BigInteger>();

            BigInteger prevStartingPointEval = BigInteger.Zero;             //Starts lower than any evaluated starting point

            foreach (ExpansionTerm pathStartingPoint in EnumerateSortedTermOptions())
            {
                currentPathStartingPointPrinter?.Invoke(pathStartingPoint);

                BigInteger startingPointEval = pathStartingPoint.Evaluate();

                if (startingPointEval > maxZ)
                {
                    //If gone past end of requested range, return all remaining stored values
                    //up to end of requested range, then stop enumerating.
                    for (BigInteger i = prevStartingPointEval + 1; i <= maxZ; i++)
                    {
                        BigInteger countToYield;
                        if (TryGetExpansionCountToYield(foundExpansionCounts, i, onlyNonTrivialZeros, out countToYield))
                        {
                            yield return(new KeyValuePair <BigInteger, BigInteger>(i, countToYield));
                        }
                    }
                    yield break;
                }

                foreach (BigInteger summedPath in termOptions.EnumerateSummedExpansionPaths(pathStartingPoint, capToMaximum: true))
                {
                    BigInteger existingCount;
                    if (foundExpansionCounts.TryGetValue(summedPath, out existingCount))
                    {
                        if (!onlyNonTrivialZeros)
                        {
                            foundExpansionCounts[summedPath] = existingCount + 1;
                        }
                    }
                    else
                    {
                        foundExpansionCounts.Add(summedPath, 1);
                    }
                }

                for (BigInteger i = prevStartingPointEval + 1; i <= startingPointEval; i++)
                {
                    BigInteger countToYield;
                    if (TryGetExpansionCountToYield(foundExpansionCounts, i, onlyNonTrivialZeros, out countToYield))
                    {
                        yield return(new KeyValuePair <BigInteger, BigInteger>(i, countToYield));
                    }
                }

                prevStartingPointEval = startingPointEval;
            }
        }
        ///<param name="onlyNonTrivialZeros">
        ///If true, only empty expansion lists will be returned,
        ///and of those none will correspond to z values that are divisible by 3.
        ///</param>
        public static IEnumerable <KeyValuePair <int, int> > IterateExpansionCounts_array(int maxZ, bool onlyNonTrivialZeros = false, Action <ExpansionTerm> currentPathStartingPointPrinter = null)
        {
            var termOptions = new TermOptionsMatrix(maxZ);

            var expansionCounts = new int[maxZ + 1];

            int prevStartingPointEval = 0;             //Starts lower than any evaluated starting point

            foreach (ExpansionTerm pathStartingPoint in EnumerateSortedTermOptions())
            {
                currentPathStartingPointPrinter?.Invoke(pathStartingPoint);

                int startingPointEval = (int)pathStartingPoint.Evaluate();

                if (startingPointEval > maxZ)
                {
                    //If gone past end of requested range, return all remaining stored values
                    //up to end of requested range, then stop enumerating.
                    for (int i = prevStartingPointEval + 1; i <= maxZ; i++)
                    {
                        int countToYield;
                        if (TryGetExpansionCountToYield_array(expansionCounts, i, onlyNonTrivialZeros, out countToYield))
                        {
                            yield return(new KeyValuePair <int, int>(i, countToYield));
                        }
                    }
                    yield break;
                }

                foreach (BigInteger summedPath in termOptions.EnumerateSummedExpansionPaths(pathStartingPoint, capToMaximum: true))
                //foreach (var expansionPath in termOptions.EnumerateExpansionPaths(pathStartingPoint, capToMaximum: true))
                {
                    //int intSummedPath = (int)expansionPath.Sum;
                    int intSummedPath = (int)summedPath;

                    int existingCount = expansionCounts[intSummedPath];
                    if (!onlyNonTrivialZeros || existingCount == 0)
                    {
                        expansionCounts[intSummedPath] = existingCount + 1;
                    }
                }

                for (int i = prevStartingPointEval + 1; i <= startingPointEval; i++)
                {
                    int countToYield;
                    if (TryGetExpansionCountToYield_array(expansionCounts, i, onlyNonTrivialZeros, out countToYield))
                    {
                        yield return(new KeyValuePair <int, int>(i, countToYield));
                    }
                }

                prevStartingPointEval = startingPointEval;
            }
        }
        public static IEnumerable <BigInteger> IterateNonTrivialZeros_bitarray(int maxZ, Action <ExpansionTerm> currentPathStartingPointPrinter = null)
        {
            var termOptions = new TermOptionsMatrix(maxZ);

            var eliminatedPoints = new BitArray(length: maxZ + 1);

            int prevStartingPointEval = 0;             //Starts lower than any evaluated starting point

            foreach (ExpansionTerm pathStartingPoint in EnumerateSortedTermOptions())
            {
                currentPathStartingPointPrinter?.Invoke(pathStartingPoint);

                int startingPointEval = (int)pathStartingPoint.Evaluate();

                if (startingPointEval > maxZ)
                {
                    //If gone past end of requested range, return all remaining stored values
                    //up to end of requested range, then stop enumerating.
                    for (int i = prevStartingPointEval + 1; i <= maxZ; i++)
                    {
                        if (i % 3 != 0 && eliminatedPoints[i] == false)
                        {
                            yield return(i);
                        }
                    }
                    yield break;
                }

                foreach (BigInteger summedPath in termOptions.EnumerateSummedExpansionPaths(pathStartingPoint, capToMaximum: true))
                {
                    int intSummedPath = (int)summedPath;

                    eliminatedPoints[intSummedPath] = true;
                }

                for (int i = prevStartingPointEval + 1; i <= startingPointEval; i++)
                {
                    if (i % 3 != 0 && eliminatedPoints[i] == false)
                    {
                        yield return(i);
                    }
                }

                prevStartingPointEval = startingPointEval;
            }
        }
        public static IEnumerable <BigInteger> IterateNonTrivialZeros(BigInteger maxZ, Action <ExpansionTerm> currentPathStartingPointPrinter = null)
        {
            var termOptions = new TermOptionsMatrix(maxZ);

            //	var sortedEliminatedRanges = new List<BigIntRange>();
            var eliminatedRanges = new RangeSet();

            BigInteger prevStartingPointEval = BigInteger.Zero;             //Starts lower than any evaluated starting point

            foreach (ExpansionTerm pathStartingPoint in EnumerateSortedTermOptions())
            {
                currentPathStartingPointPrinter?.Invoke(pathStartingPoint);
                //	Console.WriteLine("#25 current starting point: " + pathStartingPoint);

                //	//Debugging:
                //	eliminatedRanges.DebugBounds();
                //	foreach (var range in eliminatedRanges.IncludedRanges) {
                //		Console.WriteLine("#40: " + range.Start + " to " + range.End);
                //	}
                //	Console.WriteLine("#41: " + eliminatedRanges.Count);

                BigInteger startingPointEval = pathStartingPoint.Evaluate();

                if (startingPointEval > maxZ)
                {
                    //If gone past end of requested range, return all remaining stored values
                    //up to end of requested range, then stop enumerating.
                    var gaps = eliminatedRanges.EnumerateExcludedValues(
                        searchRange: BigIntRange.CreateStartEnd(
                            start: prevStartingPointEval + 1,
                            end: maxZ
                            )
                        );
                    foreach (BigInteger gap in gaps)
                    {
                        yield return(gap);
                    }
                    //	foreach (var range in eliminatedRanges.IncludedRanges) {
                    //		Console.WriteLine("#42: " + range.Start + " to " + range.End);
                    //	}
                    //	Console.WriteLine("#43: " + eliminatedRanges.Count);
                    yield break;
                }

                foreach (BigInteger summedPath in termOptions.EnumerateSummedExpansionPaths(pathStartingPoint, capToMaximum: true))
                {
                    //	Console.WriteLine("#44: " + summedPath + ", " + expansionPath.ToString(includeSpaces: false));

                    BigInteger newRangeMax = summedPath;
                    BigInteger newRangeMin = summedPath;

                    //	Console.WriteLine("#44.1: " + newRangeMin + ", " + newRangeMax);

                    //Exclude adjacent trivial zeros (multiples of 3) as well
                    if ((newRangeMax + 1) % 3 == 0)
                    {
                        newRangeMax += 1;
                    }
                    if ((newRangeMin - 1) % 3 == 0)
                    {
                        newRangeMin -= 1;
                    }

                    //	Console.WriteLine("#44.2: " + newRangeMin + ", " + newRangeMax);

                    //	Console.WriteLine("#45: " + eliminatedRanges.Count);
                    eliminatedRanges.AddRange(BigIntRange.CreateStartEnd(newRangeMin, newRangeMax));
                    //	Console.WriteLine("#46: " + eliminatedRanges.Count);
                }

                {
                    //	Console.WriteLine("#47: " + eliminatedRanges.Count);
                    var gaps = eliminatedRanges.EnumerateExcludedValues(
                        searchRange: BigIntRange.CreateStartEnd(
                            start: prevStartingPointEval + 1,
                            end: startingPointEval
                            )
                        );
                    foreach (BigInteger gap in gaps)
                    {
                        yield return(gap);
                    }
                    //	Console.WriteLine("#48");
                }

                prevStartingPointEval = startingPointEval;
            }
        }