public static IEnumerable <long> EnumerateBinaryDecisionSequenceResults(int max, int multiplier, int summand) { if (max > int.MaxValue) { throw new ArgumentOutOfRangeException( nameof(max), max, nameof(max) + " is greater than int.MaxValue, so not all summed paths would be possible to return." ); } if (max < 1) { throw new ArgumentOutOfRangeException(nameof(max), max, "Cannot be less than 1."); } if (multiplier < 0) { throw new ArgumentOutOfRangeException(nameof(multiplier), multiplier, "Cannot be negative."); } if (summand < 0) { throw new ArgumentOutOfRangeException(nameof(summand), summand, "Cannot be negative."); } var decisionTracker = new BinaryDecisionTracker(max: max, multiplier: multiplier, summand: summand); //Console.WriteLine("#A : " + decisionTracker.Current + " " + decisionTracker.ToString()); decisionTracker.TakeFirstPathRepeatedlyUpToMax(); while (decisionTracker.TryAddNextPowerOfSummand()) { //Console.WriteLine("#A2: " + decisionTracker.Current + " " + decisionTracker.ToString()); } //Console.WriteLine("#B : " + decisionTracker.Current + " " + decisionTracker.ToString()); yield return(decisionTracker.Current); //Reached maximum length of this branch; yield the branch's result while (!decisionTracker.IsAtRoot) //Starts at root but we did an initial repeated doubling; when we get back to the root we're done { //Console.WriteLine("#C : " + decisionTracker.Current + " " + decisionTracker.ToString()); if (decisionTracker.BacktrackAndCheckIfWasMultiplyOp()) { //Console.WriteLine("#D : " + decisionTracker.Current + " " + decisionTracker.ToString()); if (decisionTracker.TryAddNextPowerOfSummand()) { //Console.WriteLine("#E : " + decisionTracker.Current + " " + decisionTracker.ToString()); decisionTracker.TakeFirstPathRepeatedlyUpToMax(); while (decisionTracker.TryAddNextPowerOfSummand()) { //Console.WriteLine("#E2: " + decisionTracker.Current + " " + decisionTracker.ToString()); } //Console.WriteLine("#F : " + decisionTracker.Current + " " + decisionTracker.ToString()); yield return(decisionTracker.Current); //Reached maximum length of this branch; yield the branch's result } else { //Console.WriteLine("#G : " + decisionTracker.Current + " " + decisionTracker.ToString()); //Adding the next power of 3 makes it too big; loop around to backtrack again //But first, yield the current branch as we've now explored all sub-branches (see below) yield return(decisionTracker.Current); continue; } } else { //Console.WriteLine("#H : " + decisionTracker.Current + " " + decisionTracker.ToString()); //Explored all sub-branches of the current branch; yield the current branch //When we first go into the branch, we're doubling repeatedly so can't yield at every step, //but here we can't do anything repeatedly, so for efficiency do the yielding here. yield return(decisionTracker.Current); } } }
public static IEnumerable <int> GetZeros(int max, int multiplier, int summand) { if (max > int.MaxValue) { throw new ArgumentOutOfRangeException( nameof(max), max, nameof(max) + " is greater than int.MaxValue, so not all summed paths would be possible to return." ); } if (max < 1) { throw new ArgumentOutOfRangeException(nameof(max), max, "Cannot be less than 1."); } var decisionTracker = new BinaryDecisionTracker(max: max, multiplier: multiplier, summand: summand); var expansionRegister = new LongChunkedArray <int>(max + 1, 16777216); // ^ For each position corresponding to a result found, contains exponent that was used on the //last power of 3 added to get to that result. This is encoded as a binary flag, so that if a //given result is reached multiple times using different powers of 3, all of the powers can be //recorded without needing additional storage. // //If that result has been reached multiple times, // //contains the one that was reached most recently. // // //contains the one that's closest to 3/4 * log3(10,000). This is a rough estimate for the // // //exponent that is likely to be repeated the most, saving the most steps. //Console.WriteLine("#A : " + decisionTracker.Current + " " + decisionTracker.ToString()); decisionTracker.TakeFirstPathRepeatedlyUpToMax(); while (decisionTracker.TryAddNextPowerOfSummand()) { //Console.WriteLine("#A2: " + decisionTracker.Current + " " + decisionTracker.ToString()); } //Console.WriteLine("#B : " + decisionTracker.Current + " " + decisionTracker.ToString()); //Console.WriteLine(decisionTracker.LastAddedThreeExponent + " " + decisionTracker.Current); //yield return decisionTracker.Current; //Reached maximum length of this branch; yield the branch's result expansionRegister[decisionTracker.Current] |= 1 << decisionTracker.LastAddedExponent; while (!decisionTracker.IsAtRoot) //Starts at root but we did an initial repeated doubling; when we get back to the root we're done { //Console.WriteLine("#C : " + decisionTracker.Current + " " + decisionTracker.ToString()); if (decisionTracker.BacktrackAndCheckIfWasMultiplyOp()) { if ((expansionRegister[decisionTracker.Current] & (1 << decisionTracker.LastAddedExponent)) > 0) { continue; //Already done this branch } //Console.WriteLine("#D : " + decisionTracker.Current + " " + decisionTracker.ToString()); if (decisionTracker.TryAddNextPowerOfSummand()) { if ((expansionRegister[decisionTracker.Current] & (1 << decisionTracker.LastAddedExponent)) > 0) { continue; //Already done this branch } //Console.WriteLine("#E : " + decisionTracker.Current + " " + decisionTracker.ToString()); decisionTracker.TakeFirstPathRepeatedlyUpToMax(); if ((expansionRegister[decisionTracker.Current] & (1 << decisionTracker.LastAddedExponent)) > 0) { continue; //Already done this branch } while (decisionTracker.TryAddNextPowerOfSummand()) { if ((expansionRegister[decisionTracker.Current] & (1 << decisionTracker.LastAddedExponent)) > 0) { continue; //Already done this branch } //Console.WriteLine("#E2: " + decisionTracker.Current + " " + decisionTracker.ToString()); } //Console.WriteLine("#F : " + decisionTracker.Current + " " + decisionTracker.ToString()); //Console.WriteLine(decisionTracker.LastAddedThreeExponent + " " + decisionTracker.Current); //yield return decisionTracker.Current; //Reached maximum length of this branch; yield the branch's result expansionRegister[decisionTracker.Current] |= 1 << decisionTracker.LastAddedExponent; } else { //Console.WriteLine("#G : " + decisionTracker.Current + " " + decisionTracker.ToString()); //Console.WriteLine(decisionTracker.LastAddedThreeExponent + " " + decisionTracker.Current); //yield return decisionTracker.Current; //Adding the next power of 3 makes it too big; loop around to backtrack again //But first, yield the current branch as we've now explored all sub-branches (see below) expansionRegister[decisionTracker.Current] |= 1 << decisionTracker.LastAddedExponent; continue; } } else { //Console.WriteLine("#H : " + decisionTracker.Current + " " + decisionTracker.ToString()); //Console.WriteLine(decisionTracker.LastAddedThreeExponent + " " + decisionTracker.Current); //yield return decisionTracker.Current; //Explored all sub-branches of the current branch; yield the current branch //When we first go into the branch, we're doubling repeatedly so can't yield at every step, //but here we can't do anything repeatedly, so for efficiency do the yielding here. expansionRegister[decisionTracker.Current] |= 1 << decisionTracker.LastAddedExponent; } } for (int i = 0; i < expansionRegister.Length; i++) { if (expansionRegister[i] == 0) { yield return(i); } } }