from cxr.math.snr import Seq from cxr.math.base64 import Tridozenal as Td import cxr.math.base64 import os import threading """ This module explores the Choix de Bruxelles algorithm in bases between 2 and 36. You can learn about this algorithm here: https://www.youtube.com/watch?v=AeqK96UX3rA When run, this script will compute CDB and output each result to its appropriate location. At the end of computation, the main script will display variants of http://oeis.org/A323289 for each base. Note that due to the nature of the operation (doubling/halving) any base which is a power of two will trivially yield the positive integers (http://oeis.org/A000027). Should CDB be extended to tripling/tralving, the powers of three would be trivial. Same goes for four-timesing, etc. """ output_dir = "cdb" # output files are of the form {output_dir}\\cdb{base}\\{step}.txt def choix_de_bruxelles(d, length, log=False): """ The Brussels Choice in arbitrary base Set cxr.base64.default_base to set the base this is executed in """ def do_one_number(substring): if substring[0] != "0": i_ss = Td.get_from_string(substring) if i_ss % 2 == Td.zero(): # Silly that I didn't use this functionality in the first place quotient = i_ss * two_inverse quotient.round(place=0) # Actually-correct rounding quotient = quotient.integer_part() to_add = s_d[:i] + str(quotient) + s_d[i + substring_length:] td = Td.get_from_string(to_add) if td not in output: output.add(td) # Can always double selected substring to_add = s_d[:i] + str(i_ss * two) + s_d[i + substring_length:] td = Td.get_from_string(to_add) if td not in output: output.add(td) if not isinstance(d, list): d = [d] output = set(number for number in d) len_d = len(d) two = Td(2) two_inverse = two.multiplicative_inverse() current_threads = [] for index, number in enumerate(d): # Traversal of numbers loop if log: if index and index % 33 == 0: print(f"{index}/{len_d} done") s_d = str(number) for substring_length in range(1, length): # Length-defining loop if len(s_d) < substring_length: break for i in range(len(s_d) - substring_length + 1): # Substring-defining loop substring = s_d[i:i + substring_length] t = threading.Thread(target=do_one_number(substring), args=(substring,)) if len(current_threads) <= 7: current_threads.append(t) t.start() else: current_threads = [t for t in current_threads if t.is_alive()] current_threads.append(t) t.start() for thread in current_threads: thread.join() return output def analyze_cdb(base): """ Collect lengths of each set for the given base, and compiles it into a Seq """ analysis = [] if not os.path.exists(f"{output_dir}\\cdb{base}"): os.makedirs(f"{output_dir}\\cdb{base}") files = os.listdir(f"{output_dir}\\cdb{base}") for file in range(len(files)): with open(f"{output_dir}\\cdb{base}\\{file}.txt", "r") as f: lines = f.readlines() analysis.append(len(lines)) return Seq(analysis) def compute_next_cdb_in_base(base): """ Perform the next step of Choix de Bruxelles for the given base. Saves the results in the appropriate directory """ cxr.math.base64.default_base = base os.makedirs(f"{output_dir}\\cdb{base}", exist_ok=True) def open_step(step): output = [] with open(f"{output_dir}\\cdb{base}\\{step}.txt", "r") as file: lines = file.readlines() for line in lines: output.append(Td.get_from_string(line.strip())) return output files = os.listdir(f"{output_dir}\\cdb{base}") current_step = len(files) # Set initial step if necessary if current_step == 0: with open(f"{output_dir}\\cdb{base}\\0.txt", "w+") as f: f.write("1\n") current_step += 1 # Get previous steps g = open_step(current_step - 1) s = open_step(current_step - 2) if current_step > 1 else [] # Get difference, which is the set on which CDB will be performed s = set(s) g = set(g).difference(s) g = list(sorted(g)) l_g = len(g) print(f"Difference yields set of size {l_g} for base {base}") # Perform CDBN max_length = max([len(k.integer) for k in g]) + 1 g = choix_de_bruxelles(g, max_length, log=True) # Recombine with previous step to get full output set g = set(g).union(s) g = list(sorted(g)) os.makedirs(f"{output_dir}\\cdb{base}", exist_ok=True) with open(f"{output_dir}\\cdb{base}\\{current_step}.txt", "w+") as f: for each in g: f.write(str(each) + "\n") print(f"Step {current_step} of base {base} saved.") return True def main(): """ Selects opportunities to compute CDB based on the given threshold. At the end, prints all potential OEIS sequences You can modify the_range to tackle a particular base or set of bases. For example, the_range = [7] will only compute base 7, while the_range = [3, 5, 7, 11, 13, 17, 19, 23, 29, 31] computes all viable prime bases """ the_range = range(3, 4) trivial = [2 ** n for n in range(6)] compute = True # False means show results, True means compute then show results inp = "continue" while inp.lower() == "continue": print(f"Beginning CDB analysis of {the_range}...") sequences = {} # Iterate over all bases for base in the_range: # Bases of the form 2**n are trivial, so are skipped if base not in trivial: compute_next_cdb_in_base(base) sequences[base] = analyze_cdb(base) print() # Displays the sequences associated with each base for base in the_range: if base not in trivial: print(f"{base}: Seq({sequences[base]}),") # Easy to copy & paste for scratch work print() with open(f"{output_dir}\\sequences.txt", "w+") as f: for k, v in sequences.items(): f.write(f"{k}:{str(v)}\n") print("sequences.txt updated.") inp = "continue" if __name__ == "__main__": main()