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