//Binary decision between doubling and adding the next sequential power of 3 //Starts from 1, first power of 3 added is 3^1 = 3 public static IEnumerable <long> EnumerateTwoThreeDecisionSequenceResults(int max) //capToMaximum = true { 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 TwoThreeDecisionTracker(max: max); //Console.WriteLine("#A : " + decisionTracker.Current + " " + decisionTracker.ToString()); decisionTracker.DoubleRepeatedlyUpToMax(); while (decisionTracker.TryAddNextPowerOf3()) { //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.BacktrackAndCheckIfWasDoublingOp()) { //Console.WriteLine("#D : " + decisionTracker.Current + " " + decisionTracker.ToString()); if (decisionTracker.TryAddNextPowerOf3()) { //Console.WriteLine("#E : " + decisionTracker.Current + " " + decisionTracker.ToString()); decisionTracker.DoubleRepeatedlyUpToMax(); while (decisionTracker.TryAddNextPowerOf3()) { //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); } } }
//Returns an array that, for each position corresponding to a result found, contains the exponents //used on the highest power of 3 involved each time that result was reached, all encoded as binary flags. public static LongChunkedArray <int> GetExpansionRegister(int max) { 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 TwoThreeDecisionTracker(max: max); 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.DoubleRepeatedlyUpToMax(); while (decisionTracker.TryAddNextPowerOf3()) { //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.LastAddedThreeExponent; 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.BacktrackAndCheckIfWasDoublingOp()) { if ((expansionRegister[decisionTracker.Current] & (1 << decisionTracker.LastAddedThreeExponent)) > 0) { continue; //Already done this branch } //Console.WriteLine("#D : " + decisionTracker.Current + " " + decisionTracker.ToString()); if (decisionTracker.TryAddNextPowerOf3()) { if ((expansionRegister[decisionTracker.Current] & (1 << decisionTracker.LastAddedThreeExponent)) > 0) { continue; //Already done this branch } //Console.WriteLine("#E : " + decisionTracker.Current + " " + decisionTracker.ToString()); decisionTracker.DoubleRepeatedlyUpToMax(); if ((expansionRegister[decisionTracker.Current] & (1 << decisionTracker.LastAddedThreeExponent)) > 0) { continue; //Already done this branch } while (decisionTracker.TryAddNextPowerOf3()) { if ((expansionRegister[decisionTracker.Current] & (1 << decisionTracker.LastAddedThreeExponent)) > 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.LastAddedThreeExponent; } 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.LastAddedThreeExponent; 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.LastAddedThreeExponent; } } return(expansionRegister); }