Ejemplo n.º 1
0
 public bool TryGetNextInColumn(ExpansionTerm option, out ExpansionTerm next)
 {
     if (ColumnHasItemsAfter(option))
     {
         next = option.StepBy(threeExpStep: 1, twoExpStep: 0);
         return(true);
     }
     else
     {
         next = default(ExpansionTerm);
         return(false);
     }
 }
Ejemplo n.º 2
0
        private static ReadOnlyCollection <ReadOnlyCollection <ExpansionTerm> > GetExpansionTermOptions(BigInteger z)
        {
            List <List <ExpansionTerm> > terms = new List <List <ExpansionTerm> >();

            var option = new ExpansionTerm(0, 0);

            while (option.Evaluate() <= z)
            {
                var optionsForTerm = new List <ExpansionTerm>();

                while (option.Evaluate() <= z)
                {
                    optionsForTerm.Add(option);
                    option = option.StepBy(0, 1);
                }

                terms.Add(optionsForTerm);
                option = new ExpansionTerm(option.ThreeExponent + 1, 0);
            }

            return(terms.Select(row => row.AsReadOnly()).ToList().AsReadOnly());
        }
Ejemplo n.º 3
0
        public IEnumerable <int> EnumerateIntSummedExpansionPaths(ExpansionTerm pathStartingPoint)        //capToMaximum = true
        {
            if (this.Maximum > int.MaxValue)
            {
                throw new InvalidOperationException(
                          "Maximum is greater than int.MaxValue, so not all summed paths would be possible to return."
                          );
            }

            if (!this.Contains(pathStartingPoint))
            {
                throw new ArgumentException(
                          "The " + nameof(TermOptionsMatrix) + " '" + this + "' "
                          + "does not contain provided " + nameof(pathStartingPoint) + " '" + pathStartingPoint + "'."
                          );
            }

            var stack = new LongExpansionTermStack();

            stack.Push(pathStartingPoint);

            //To start with, keep moving up, adding each element to the stack, until the top row is reached
            while (stack.Peek().ThreeExponent > 0)
            {
                var termAbove = stack.Peek().StepBy(threeExpStep: -1, twoExpStep: 0);
                stack.Push(termAbove);
            }

            //Then check if that resulted in a path that isn't too big
            if (stack.Sum <= this.Maximum)
            {
                yield return((int)stack.Sum);                //stack.Sum <= this.Maximum <= int.MaxValue
            }
            else
            {
                yield break;                 //The stack currently holds the lowest possible path; if that doesn't fit in Maximum, no paths will
            }

            ExpansionTerm currentTerm = stack.Pop();

            while (true)
            {
                //If there's no items left on the stack, then the current item (which isn't on the stack)
                //is all that's left, and we're back at the starting point (or the starting point is in
                //the top row, and we never moved anywhere). Either way, we are therefore done.
                if (stack.Count <= 0)
                {
                    yield break;
                }

                ExpansionTerm termToRight = currentTerm.StepBy(threeExpStep: 0, twoExpStep: 1);
                // ^ But this might not actually be in the matrix (ie. less than or equal to this.Maximum) so need to check that next.
                //   But then, we don't actually need to check that, as we're already need to check if it, plus the stack's sum,
                //   is less than or equal to this.Maximum - so just need to do that check.
                //   But in fact, we also then need to check whether all of that, plus the lowest path from the new term,
                //   is less than or equal to this.Maximum...so just do *that* check to start with.

                if (stack.Sum + MinimumPathSum(termToRight) <= this.Maximum)
                {
                    //The first route from termToRight, which goes straight to the top, is the path with the
                    //minimum sum, which we've already checked is be less than this.Maximum, so take that route
                    //(first pushing termToRight). However, don't push the final item (hence "> 0"), just add
                    //that onto the sum manually - as it'd just be guaranteed to be popped straight after
                    //anyway, so there's no point.
                    for (int i = termToRight.ThreeExponent; i > 0; i--)
                    {
                        stack.Push(new ExpansionTerm(threeExponent: i, twoExponent: termToRight.TwoExponent));
                    }

                    //Set up currentTerm for next iteration (and for yield statement)
                    currentTerm = new ExpansionTerm(threeExponent: 0, twoExponent: termToRight.TwoExponent);

                    yield return((int)(stack.Sum) + currentTerm.EvaluateInt());

                    // ^ Only need the TwoExponent as the ThreeExponent is zero so it's just "1 * 2^whatever"
                    //   Also, ok to cast as (stack.Sum + currentTerm.TwoExponent <= this.Maximum <= int.MaxValue) (based on prior checks)

                    //Now loop around again to try moving to the right again
                    continue;
                }
                else
                {
                    //If false, then either the term to the right is itself bigger than this.Maximum (so it isn't inside the matrix);
                    //or it, plus the current stack's sum, is bigger than this.Maximum (so adding anything to it will always be outside
                    //the range of desired results); or finally it, plus the current stack's sum, plus the sum of the smallest path
                    //continuing from it, is bigger than this.Maximum. This last case means that all paths from it, and from all positions
                    //further to the right, will be too big (but this position may be valid, when reached from a different stack, that
                    //goes to the left more). In all three cases, we need move back down from the current term - which we've already done
                    //by popping earlier - and then loop back around to continue trying from there. What we do need to do, though, is set
                    //up currentTerm ready for the next loop, by popping the top value into it.
                    currentTerm = stack.Pop();
                    continue;
                }
            }

            //	while (true)
            //	{
            //		//If there's only one item left on the stack, we're back at the starting point
            //		//(or the starting point is in the top row, and we never moved anywhere).
            //		//Either way, we are therefore done.
            //		if (stack.Count <= 1) yield break;
            //
            //		ExpansionTerm currentTerm = stack.Pop();
            //		ExpansionTerm termToRight = currentTerm.StepBy(threeExpStep: 0, twoExpStep: 1);
            //		// ^ But this might not actually be in the matrix, ie. no greater than this.Maximum, so need to check that next.
            //		//   But then, we don't actually need to check that, as we're already need to check if it, plus the stack's sum,
            //		//   is no greater than this.Maximum - so just need to do that check.
            //		//   But in fact, we also then need to check whether all of that, plus the lowest path from the new term,
            //		//   is no greater than this.Maximum...so just do *that* check to start with.
            //
            //		//long termToRightEval = termToRight.EvaluateLong();
            //		//if (this.TryGetNextInRow(currentTerm, out termToRight) && stack.SumWithAlternateHead(termToRight) <= this.Maximum)
            //		//if (termToRightEval <= this.Maximum && termToRightEval + stack.Sum <= this.Maximum)
            //		//if (termToRightEval + stack.Sum <= this.Maximum)
            //		if (stack.Sum + MinimumPathSum(termToRight) <= this.Maximum)
            //		{
            //			//The first route from termToRight, which goes straight to the top, is the path with
            //			//the minimum sum, which we've already checked is be less than this.Maximum, so take
            //			//that route (first pushing termToRight)
            //			for (int i = termToRight.ThreeExponent; i >= 0; i--) {
            //				stack.Push(new ExpansionTerm(threeExponent: i, twoExponent: termToRight.TwoExponent));
            //			}
            //
            //			//	Console.WriteLine("#12: " + stack.Peek() + ", " + stack.SumWithoutHead + ", " + MinimumPathSum(stack.Peek()));
            //			yield return (int)stack.Sum; //Safe to cast based on prior checks (remember this.Maximum < int.MaxValue)
            //
            //			//Now loop around again to try moving to the right
            //			continue;
            //		}
            //		else
            //		{
            //			//If false, then either the term to the right is itself bigger than this.Maximum (so it isn't inside the matrix);
            //			//or it, plus the current stack's sum, is bigger than this.Maximum (so adding anything to it will always be outside
            //			//the range of desired results); or finally it, plus the current stack's sum, plus the sum of the smallest path
            //			//continuing from it, is bigger than this.Maximum. This last case means that all paths from it, and from all positions
            //			//further to the right, will be too big (but this position may be valid, when reached from a different stack, that
            //			//goes to the left more). In all three cases, we need move back down from the current term - which we've already done
            //			//by popping earlier - and then loop back around to continue trying from there.
            //			continue;
            //		}
            //	}
        }