"""machine.py -- the growth apparatus read as a machine: a state M, moves that multiply it, and the reads a program may make before it moves. What a program can decide about its own halting depends only on which read it holds. QUESTION. A growth walk only multiplies: M -> Mm. Read as a counter machine, the depths v_p(M) are counters that only rise, so the bare machine has no decrement. Is that the end of it, or does the same multiply-only world hold counters that fall? If it does, which reads of the state does a program need to be universal, and which reads leave it decidable? THE OBJECT. lambda is the Carmichael function, W(L) the wall (the largest M with lambda(M) | L, which is Adams' number; growth.py) and xi(M) = W(lambda(M))/M the headroom (headroom.py). A move m is TRANSPARENT at M when lambda(Mm) = lambda(M), which holds iff m | xi(M). An odd prime l is SEATED in M when l | M, and at a seated l, v_l(xi) = v_l(lambda) + 1 - v_l(M). A PROGRAM is a finite list of instructions over counters; Minsky's two instructions are INC(c) and DJZ(c): if counter c is zero go one way, else decrement it and go the other. Two counters with both are universal (Minsky 1967), cited. THE ARGUMENT (written before the engine). (D) THE DEPTH MACHINE DECIDES. Take counters c_i = v_(p_i)(M), INC(i) the push of p_i and the zero-test the presence read p_i | M. A program over INC and the zero-test moves from (instruction, zero-pattern) to the next such pair by a map that reads nothing else, and a counter once nonzero stays nonzero. So the run's projection to the finite set Q x {0, +}^eta is itself a deterministic run there: it halts iff the projected run reaches HALT, and otherwise it revisits a pair within |Q| 2^eta steps and loops. Restore DJZ and the projection is unsound: the program "at q0: zero -> HALT, else decrement to q1; at q1: zero -> LOOP, else decrement to q0" halts from 2 and loops from 3, and both runs start at the pair (q0, +). (M) THE HEADROOM COUNTS BOTH WAYS. Fix odd primes l_1, ..., l_eta seated in M and read the counter h_i = v_(l_i)(xi(M)). DEC: push l = l_i. With a = v_l(M) before the push, lambda(l^(a+1)) = l^a (l - 1) and (l - 1) already divides lambda, so lambda moves only at l, to max(v_l(lambda), a); with v_l(M) up by one, h_i goes to max(0, h_i - 1), and no other v(lambda) or v(M) moves, so no sibling moves. (This is HEADROOM's ledger at a prime move.) ZERO-TEST: h_i = 0 iff l does not divide xi iff the push l is not transparent, i.e. iff lambda(Ml) != lambda(M). INC: push a prime q not dividing M with v_l(q - 1) = v_l(lambda) + 1 and q not 1 mod any sibling l_j. lambda goes to lcm(lambda, q - 1): v_l(lambda) rises by one, every sibling's is unchanged, and v_l(M) and the siblings' v(M) are unchanged, so h_i rises by one and nothing else counted moves. The conditions are congruences to the coprime moduli l^(v_l(lambda)+2) and l_j, so Dirichlet supplies such q at every state and every number of counters. So pushes alone run any Minsky program on the headroom, reading the zero-test off the transparency of one push: universal. The increment is a SELECTOR, not a fixed move: its import is chosen from v_l(lambda), and so is the padded decrement's below. (S) WHICH READ PAYS. The three demands independence (gcd(m, M) = 1), new idempotents (m has a prime M lacks) and semisimplicity (Mm squarefree) answer, for a fixed m, as functions of the support of M on the primes of m and of whether M is squarefree. Give a program the same moves as (M): fixed pushes and the selectors above, each selector's prime chosen off the fixed moves' primes (Dirichlet's theorem still supplies one), else the import could flip a support bit by the hidden v_l(lambda). A selector's import is a prime M lacks, so on it independence and new idempotents answer yes and semisimplicity answers the squarefree bit; on the padded decrement they answer no, yes, no. So what these reads can see is (instruction, support on the fixed moves' primes, the squarefree bit), each coordinate write-once: finite, and (D)'s argument decides it. The comparison with the sighted reads changes the read and nothing else. The lambda-reading demands (dynamics: lambda rises; new orders, the same predicate; transparency, its complement) answer (M)'s zero-test exactly, so a program holding one is universal. AUTONOMY. If every move a program makes must itself be admissible under the demand it reads, dynamics forbids the bare DEC (a transparent push) but admits the PADDED DEC l q', q' a fresh prime with q' not 1 mod any counter prime and (q' - 1) not dividing lambda: lambda rises through q', q' carries no counter prime into lambda, and the push of l does (M)'s decrement. INC raises lambda by construction. So a dynamics-autonomous program is universal. Transparency-autonomy is mortal: its reachable states divide W(lambda(seed)) (growth.py, the three fates). THE PREDICTIONS (fixed before the engine ran). P1 section_control: at every M <= 3000 and every odd l seated in M, v_l(W(lambda(M))/M), computed from the wall itself, equals v_l(lambda) + 1 - v_l(M). P2 section_decide: on every program over two counters with at most three instructions from a fixed family, HALT apart, from the starts (0, 0), (0, 1), (1, 0) and (2, 3), the quotient decider's verdict matches a direct run of 4 |Q| 2^eta + 1 steps, past the bound, so a later halt would show; the DJZ program above halts from 0, 2, 4 and loops from 1, 3, 5, and as a control the quotient gives its starts 2 and 3 one verdict. P3 section_counters: DEC and the zero-test at every odd M <= 3000 and every seated odd l, INC at every odd M <= 1200, every seated odd l and every odd prime q < 3000 not dividing M that is an import for l (v_l(q - 1) = v_l(lambda) + 1, q not 1 mod a sibling), with no exception; siblings unmoved in every case. P4 section_minsky: halts-iff-even, transfer and roundtrip, run on pushes from the seed 15 (counters at 3 and 5, both 0) for x0 = 0 to 6, match a reference interpreter step for step, the counter read off lambda and M equal to the reference counter at every step; at 2, 3, 4 and 5 counters (3, 5, 7, 11, 13) every INC and DEC moves its own counter by one and no sibling. P5 section_square: 855 and 2565 (support {3, 5, 19}, neither squarefree) read 1 and 0 at the counter prime 3; independence, new idempotents and semisimplicity answer identically on both at every 2 <= m <= 400, while dynamics answers the push 3 differently. The three programs rerun dynamics-autonomously, with padded DEC, match the reference, and every move made raises lambda. P6 section_square (added at audit): on the moves the programs offer (the bare push of a seated l, the INC import, the padded DEC) each blind answer is fixed by the move's kind and the squarefree bit, by construction: the import is fresh and l is seated. The zero-test is not: over the runs it takes both values at some (counter, squarefree bit) key. THE DESIGN. Pure Python. States are held as factorization dicts, so lambda and the counters are exact at any size; imports are found by search along q = 1 + l^(v_l(lambda)+1) t (the padded decrement's fresh prime along q = 1 + 2t) and certified by deterministic Miller-Rabin, exact below 3.3e24 (asserted). section_control and section_counters work from trial division and the wall's closed form, which is independent of the formula the Minsky engine reads. FINDINGS (entered after the run, from its printed output). 1. P1 hit: the formula holds at 5346 (M, seated odd l) cells, M <= 3000, 0 exceptions. The planted defect fires: from 15 the import 31, which is 1 mod both 3 and 5, moves both counters to 1, so the State-based sibling checks of section_minsky can see a moved sibling. 2. P2 hit: the quotient decider agrees with a direct run on 258,352 (program, start) cases, every INC/JZ program of up to three instructions over two counters. Halts-iff-even with DJZ halts from 0, 2, 4 and loops from 1, 3, 5, and the quotient answers LOOP from both 2 and 3. 3. P3 hit: DEC, the zero-test and INC hold with 0 exceptions over 2816 DEC cells and 25,546 INC cells, and no sibling moves. 4. P4 hit: the three programs on pushes match the reference at x0 = 0 to 6 (halts-iff-even H L H L H L H), the counter read at every step; at 2 to 5 counters 56 more moves; all 266 shift their own counter by exactly one and no sibling. 5. P5 hit: 855 and 2565 read 1 and 0 at 3; the three blind demands answer alike on both at every 2 <= m <= 400; dynamics answers the push 3 False and True. The autonomous runs match the reference, and all 210 moves raise lambda. 6. P6 (added at audit, after the first green run, when the blind half's proof was found to assume a finite move set the universal machine does not use): over the autonomous runs the zero-test takes both values at 3 of the 4 (counter, bit) keys. Tiers: (D) and (M) are theorems, proved above, with universality given Minsky's theorem and the imports' existence given Dirichlet's; the engine checks the instruction set, never a claim over programs. RUN RECORD. 20 checks, 2.5 s, peak 17 MB; with P2's direct run four times past the bound, 4.0 s, 11.5 MB. Two defects caught before the first run, on reading: a stray test in the import search, and a program enumerator whose later instructions could never jump back to the first. The planted-defect control was added after the first green run. """ import sys from itertools import product from math import gcd CHECKS = [] def check(name, ok, detail=""): CHECKS.append(bool(ok)) print(f" {'PASS' if ok else 'FAIL'} {name}" + (f" ({detail})" if detail else "")) def section(title): print() print(title) # ---------------------------------------------------------------------- # arithmetic MR_BASES = (2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41) MR_LIMIT = 3317044064679887385961981 def is_prime(n): if n < 2: return False for p in MR_BASES: if n % p == 0: return n == p assert n < MR_LIMIT, "Miller-Rabin bases not certified this high" d, s = n - 1, 0 while d % 2 == 0: d //= 2 s += 1 for a in MR_BASES: x = pow(a, d, n) if x in (1, n - 1): continue for _ in range(s - 1): x = x * x % n if x == n - 1: break else: return False return True def factor(n): f, p = {}, 2 while p * p <= n: while n % p == 0: f[p] = f.get(p, 0) + 1 n //= p p += 1 if n > 1: f[n] = f.get(n, 0) + 1 return f def val(n, p): v = 0 while n % p == 0: n //= p v += 1 return v def lcm_f(a, b): out = dict(a) for p, e in b.items(): if e > out.get(p, 0): out[p] = e return out def lam_pp_f(p, a, known=None): """lambda(p^a) as a factor dict; known = factor dict of p - 1.""" if p == 2: return {} if a == 1 else ({2: 1} if a == 2 else {2: a - 2}) f = dict(known if known is not None else factor(p - 1)) if a > 1: f[p] = f.get(p, 0) + a - 1 return f def value(f): out = 1 for p, e in f.items(): out *= p ** e return out # ---------------------------------------------------------------------- # the wall, from its closed form, for the small-scale sections def divisors(n): ds = [1] for p, e in factor(n).items(): ds = [d * p ** i for d in ds for i in range(e + 1)] return ds def wall(L): if L % 2: return 2 w = 2 ** (val(L, 2) + 2) for d in divisors(L): p = d + 1 if p > 2 and is_prime(p): w *= p ** (val(L, p) + 1) return w def lam_int(M): L = 1 for p, e in factor(M).items(): x = value(lam_pp_f(p, e)) L = L * x // gcd(L, x) return L # ---------------------------------------------------------------------- # section_control def section_control(): section("CONTROL -- the counter formula against the wall itself") bad = cells = 0 for M in range(1, 3001): L = lam_int(M) xi = wall(L) // M assert wall(L) % M == 0 for l in factor(M): if l == 2: continue cells += 1 if val(xi, l) != val(L, l) + 1 - val(M, l): bad += 1 print(f" {cells} (M, seated odd l) cells, M <= 3000") check("P1 v_l(xi) = v_l(lambda) + 1 - v_l(M) at every seated odd l", bad == 0, f"{bad} exceptions") st = State(15) st.push_prime(31) moved = (st.counter(3), st.counter(5)) print(f" planted defect: from 15 the import 31 (30 = 2 3 5) moves " f"the counters at 3 and 5 to {moved}") check("P1 an import 1 mod a sibling moves that sibling", moved == (1, 1)) # ---------------------------------------------------------------------- # section_decide: the depth machine and its quotient def run_direct(prog, counters, steps): """INC/JZ/DJZ program; returns ('HALT'|'LOOP'|'OPEN', trace).""" q, c, trace = 0, list(counters), [] for _ in range(steps): ins = prog[q] trace.append((q, tuple(x > 0 for x in c))) if ins[0] == "HALT": return "HALT", trace if ins[0] == "LOOP": return "LOOP", trace if ins[0] == "INC": c[ins[1]] += 1 q = ins[2] elif ins[0] == "JZ": q = ins[2] if c[ins[1]] == 0 else ins[3] else: if c[ins[1]] == 0: q = ins[2] else: c[ins[1]] -= 1 q = ins[3] return "OPEN", trace def decide(prog, counters): """The quotient decider for INC/JZ programs.""" q, z, seen = 0, tuple(x > 0 for x in counters), set() while (q, z) not in seen: seen.add((q, z)) ins = prog[q] if ins[0] == "HALT": return "HALT" if ins[0] == "LOOP": return "LOOP" if ins[0] == "INC": z = tuple(True if i == ins[1] else b for i, b in enumerate(z)) q = ins[2] else: q = ins[2] if not z[ins[1]] else ins[3] return "LOOP" def programs(n): """Every INC/JZ program of n instructions over two counters, with HALT at index n; targets range over 0..n.""" opts = [] for c in (0, 1): for t in range(n + 1): opts.append(("INC", c, t)) for x in range(n + 1): for y in range(n + 1): opts.append(("JZ", c, x, y)) for body in product(opts, repeat=n): yield list(body) + [("HALT",)] HALTS_IFF_EVEN = [("DJZ", 0, 2, 1), ("DJZ", 0, 3, 0), ("HALT",), ("LOOP",)] def same_fate(verdict, run): """The comparison P2 reads: halting in one iff halting in the other.""" return (verdict == "HALT") == (run == "HALT") def section_decide(): section("DECIDE -- the depth machine and its finite quotient") out = {x: run_direct(HALTS_IFF_EVEN, (x,), 50) for x in range(6)} print(" halts-iff-even with DJZ: " + " ".join( f"{x}:{out[x][0]}" for x in range(6))) check("P2 halts-iff-even halts from 0, 2, 4 and loops from 1, 3, 5", all(out[x][0] == ("HALT" if x % 2 == 0 else "LOOP") for x in range(6))) v2, v3 = decide(HALTS_IFF_EVEN, (2,)), decide(HALTS_IFF_EVEN, (3,)) agrees = [same_fate(v, out[x][0]) for x, v in ((2, v2), (3, v3))] check("P2 CONTROL the quotient gives the starts 2 and 3 one verdict, " "and the comparison below fails on one", v2 == v3 and agrees.count(False) == 1, f"{v2} from both") total = agree = 0 for n in (1, 2, 3): for prog in programs(n): k, Q = 2, len(prog) for c0 in ((0, 0), (0, 1), (1, 0), (2, 3)): total += 1 v = decide(prog, c0) r, _ = run_direct(prog, c0, 4 * Q * 2 ** k + 1) agree += same_fate(v, r) print(f" {total} (program, start) cases, up to three instructions") check("P2 the quotient decider matches a direct run everywhere", agree == total, f"{total - agree} disagreements") # ---------------------------------------------------------------------- # the headroom machine: states as factor dicts class State: """M and lambda(M) as factor dicts; pm1 holds each prime's p - 1.""" def __init__(self, seed): self.m, self.lam, self.pm1 = {}, {}, {} for p, e in factor(seed).items(): for _ in range(e): self.push_prime(p) def lam_after(self, p, pm1=None): a = self.m.get(p, 0) + 1 known = pm1 if pm1 is not None else self.pm1.get(p) return lcm_f(self.lam, lam_pp_f(p, a, known)) def push_prime(self, p, pm1=None): if pm1 is not None: self.pm1[p] = pm1 elif p not in self.pm1: self.pm1[p] = factor(p - 1) self.lam = self.lam_after(p, self.pm1[p]) self.m[p] = self.m.get(p, 0) + 1 def counter(self, l): return self.lam.get(l, 0) + 1 - self.m.get(l, 0) def transparent(self, l): return self.lam_after(l) == self.lam def find_import(st, l, sibs, pad=False): """A prime q, absent from M, with v_l(q - 1) = v_l(lambda) + 1 and q not 1 mod any sibling (INC); with pad, q not 1 mod l or any sibling and (q - 1) not dividing lambda (the padded DEC's fresh prime).""" v = st.lam.get(l, 0) step = l ** (v + 1) if not pad else 2 t = 1 while True: q = 1 + step * t t += 1 if q in st.m or q in sibs or q == l: continue if not pad and (q - 1) % (l ** (v + 2)) == 0: continue if any((q - 1) % s == 0 for s in sibs): continue if pad and (q - 1) % l == 0: continue if not is_prime(q): continue f = factor_known(q - 1, l) if pad and all(st.lam.get(p, 0) >= e for p, e in f.items()): continue return q, f def factor_known(n, l): """Factor n = q - 1, stripping powers of l first (n = l^a t, t small), then trial division.""" f = {} while n % l == 0: n //= l f[l] = f.get(l, 0) + 1 for p, e in factor(n).items(): f[p] = f.get(p, 0) + e return f # ---------------------------------------------------------------------- # section_counters: the three laws at small scale, from the wall def section_counters(): section("COUNTERS -- DEC, the zero-test and INC, from the wall") small_primes = [q for q in range(3, 3000) if is_prime(q)] dec_bad = jz_bad = inc_bad = sib_bad = dec_n = inc_n = 0 xi_of = {} def xi(M): if M not in xi_of: xi_of[M] = wall(lam_int(M)) // M return xi_of[M] for M in range(3, 3001, 2): seated = [l for l in factor(M) if l != 2] x = xi(M) for l in seated: c = val(x, l) y = xi(M * l) dec_n += 1 if val(y, l) != max(0, c - 1): dec_bad += 1 if any(val(y, s) != val(x, s) for s in seated if s != l): sib_bad += 1 if (c == 0) != (lam_int(M * l) != lam_int(M)): jz_bad += 1 if M > 1200: continue L = lam_int(M) for l in seated: v = val(L, l) for q in small_primes: if M % q == 0 or val(q - 1, l) != v + 1: continue if any((q - 1) % s == 0 for s in seated if s != l): continue inc_n += 1 y = xi(M * q) if val(y, l) != val(x, l) + 1: inc_bad += 1 if any(val(y, s) != val(x, s) for s in seated if s != l): sib_bad += 1 print(f" {dec_n} DEC cells (odd M <= 3000), {inc_n} INC cells " f"(odd M <= 1200, primes q < 3000)") check("P3 DEC: the push l sends the counter to max(0, c - 1)", dec_bad == 0, f"{dec_bad} exceptions") check("P3 zero-test: counter 0 iff the push l moves lambda", jz_bad == 0, f"{jz_bad} exceptions") check("P3 INC: the import raises its counter by exactly one", inc_bad == 0, f"{inc_bad} exceptions") check("P3 no sibling counter moves under DEC or INC", sib_bad == 0, f"{sib_bad} exceptions") # ---------------------------------------------------------------------- # section_minsky: programs on pushes TRANSFER = [("DJZ", 0, 2, 1), ("INC", 1, 0), ("HALT",)] ROUNDTRIP = [("DJZ", 0, 2, 1), ("INC", 1, 0), ("DJZ", 1, 4, 3), ("INC", 0, 2), ("HALT",)] PROGRAMS = (("halts-iff-even", HALTS_IFF_EVEN), ("transfer", TRANSFER), ("roundtrip", ROUNDTRIP)) def run_pushes(prog, x0, primes, autonomous=False, cap=200): """Load x0 into counter 0 by INC, then run prog on pushes. Returns (verdict, reference verdict, ok, stats).""" st = State(value({p: 1 for p in primes})) stats = {"moves": 0, "sib": 0, "own": 0, "lam_flat": 0, "sighted": set()} def sighted_reads(): """The zero-test of every counter, keyed by the counter and the squarefree bit.""" sqf = all(e == 1 for e in st.m.values()) for i, l in enumerate(primes): stats["sighted"].add((i, sqf, st.transparent(l))) def inc(i): l = primes[i] sibs = [p for p in primes if p != l] before = [st.counter(p) for p in primes] lam0 = dict(st.lam) q, f = find_import(st, l, sibs) st.push_prime(q, f) note(before, i, +1, lam0) def dec(i): l = primes[i] before = [st.counter(p) for p in primes] lam0 = dict(st.lam) if autonomous: q, f = find_import(st, l, [p for p in primes if p != l], pad=True) st.push_prime(q, f) st.push_prime(l) note(before, i, -1, lam0) def note(before, i, d, lam0): stats["moves"] += 1 after = [st.counter(p) for p in primes] stats["own"] += after[i] != before[i] + d stats["sib"] += any(after[j] != before[j] for j in range(len(primes)) if j != i) stats["lam_flat"] += st.lam == lam0 assert all(st.counter(p) == 0 for p in primes) for _ in range(x0): inc(0) ref = [x0] + [0] * (len(primes) - 1) q, ok = 0, True for _ in range(cap): ins = prog[q] if ins[0] in ("HALT", "LOOP"): break c = ins[1] if ins[0] == "INC": inc(c) ref[c] += 1 q = ins[2] else: sighted_reads() zero = not st.transparent(primes[c]) if zero != (ref[c] == 0): ok = False if zero: q = ins[2] else: dec(c) ref[c] -= 1 q = ins[3] if [st.counter(p) for p in primes] != ref: ok = False verdict = prog[q][0] if prog[q][0] in ("HALT", "LOOP") else "OPEN" rv, _ = run_direct(prog, (x0,) + (0,) * (len(primes) - 1), cap) return verdict, rv, ok, stats def section_minsky(): section("MINSKY -- three programs on pushes, from the seed 15") all_ok, sib, own, moves = True, 0, 0, 0 for name, prog in PROGRAMS: row = [] for x0 in range(7): v, rv, ok, s = run_pushes(prog, x0, (3, 5)) all_ok &= ok and v == rv sib += s["sib"] own += s["own"] moves += s["moves"] row.append(v[0]) print(f" {name:15s} x0 = 0..6: {' '.join(row)}") check("P4 every run matches the reference, counter read at every " "step", all_ok) many = 0 for k in (2, 3, 4, 5): primes = (3, 5, 7, 11, 13)[:k] st = State(value({p: 1 for p in primes})) for rnd in range(3): for i, l in enumerate(primes): sibs = [p for p in primes if p != l] before = [st.counter(p) for p in primes] q, f = find_import(st, l, sibs) st.push_prime(q, f) after = [st.counter(p) for p in primes] moves += 1 many += 1 sib += any(after[j] != before[j] for j in range(k) if j != i) own += after[i] != before[i] + 1 for i, l in enumerate(primes): before = [st.counter(p) for p in primes] st.push_prime(l) after = [st.counter(p) for p in primes] moves += 1 many += 1 sib += any(after[j] != before[j] for j in range(k) if j != i) own += after[i] != before[i] - 1 print(f" 2 to 5 counters (3, 5, 7, 11, 13): {many} moves") check("P4 every move shifts its own counter by exactly one", own == 0, f"{moves} moves in all, {own} off") check("P4 no move shifts a sibling counter", sib == 0, f"{moves} moves in all, {sib} off") # ---------------------------------------------------------------------- # section_square: which read pays def independence(M, m): return gcd(M, m) == 1 def new_idempotents(M, m): return any(M % p for p in factor(m)) def semisimple(M, m): return all(e == 1 for e in factor(M * m).values()) def dynamics(M, m): return lam_int(M * m) != lam_int(M) def section_square(): section("SQUARE -- the blind reads, the sighted read, autonomy") a, b = 855, 2565 ca = val(wall(lam_int(a)) // a, 3) cb = val(wall(lam_int(b)) // b, 3) print(f" {a} = {factor(a)}, {b} = {factor(b)}: counters at 3 read " f"{ca} and {cb}") check("P5 855 and 2565 read 1 and 0 at the counter prime 3", (ca, cb) == (1, 0)) blind = {"independence": independence, "new idempotents": new_idempotents, "semisimplicity": semisimple} for name, f in blind.items(): diff = sum(f(a, m) != f(b, m) for m in range(2, 401)) check(f"P5 {name} answers alike on both at every 2 <= m <= 400", diff == 0, f"{diff} differences") check("P5 dynamics answers the push 3 differently", dynamics(a, 3) != dynamics(b, 3), f"{dynamics(a, 3)} and {dynamics(b, 3)}") all_ok, flat, moves = True, 0, 0 sighted = set() for name, prog in PROGRAMS: row = [] for x0 in range(7): v, rv, ok, s = run_pushes(prog, x0, (3, 5), autonomous=True) all_ok &= ok and v == rv flat += s["lam_flat"] sighted |= s["sighted"] moves += s["moves"] row.append(v[0]) print(f" {name:15s} autonomous, x0 = 0..6: {' '.join(row)}") check("P5 the autonomous runs match the reference", all_ok) check("P5 every move made raises lambda", flat == 0, f"{moves} moves, {flat} leave lambda fixed") both = {(i, b) for i, b, t in sighted if (i, b, not t) in sighted} keys = {(i, b) for i, b, _ in sighted} print(f" the zero-test takes both values at {len(both)} of {len(keys)} " f"(counter, squarefree bit) keys") check("P6 the sighted zero-test varies at a (counter, bit) key", len(both) > 0) def main(): section_control() section_decide() section_counters() section_minsky() section_square() print() print(f"{sum(CHECKS)}/{len(CHECKS)} checks passed") sys.exit(0 if all(CHECKS) else 1) if __name__ == "__main__": main()