/machines/1RB0RE_1LC0RA_1LD0LB_1LA1LF_1LE1RA_0LC---/check_proof.py · raw
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 | #!/usr/bin/env python3 """check_proof.py: simulation evidence for the DELTA proof.md of twin #24 (1RB0RE_1LC0RA_1LD0LB_1LA1LF_1LE1RA_0LC---) against the parent kill #3 (1RB0LD_1RC0RA_1RD1RF_1LA0LE_1RE1LD_0RB---). The twin is the parent mirrored (L <-> R) and renamed (twin A,B,C,D,E,F = parent D,A,B,C,E,F), but started in parent state D. So every rule, outside case and invariant of the parent's proof.md carries over unchanged; only the initial segment and the base E-start differ. This script checks exactly that delta. It has its own direct simulator of the TWIN string (section A, C, D never run the parent's table) and reuses the parent's abstract map, INV+(e) checker, cycle-pair checker (machines/<parent>/check_proof.py) and Rocq invariant J (rocq/jcheck.py). Sections (each prints PASS/FAIL lines; SUMMARY is PASS only if M, S, A, C, D, B, G and J all pass): M the map: transition-table identity under mirror + renaming (12/12 entries), uniqueness over all 2 x 720 candidates, image of the start state (D, not A), and the halting transition of the twin S step-by-step conjugacy: twin from the blank tape vs parent started in D on the blank tape, in lockstep A every macro rule of the parent's proof.md section 2, transported to the twin (mirrored words, state B), from random concrete instances, by direct simulation of the TWIN machine C the initial segment of the twin: blank tape -> K0' = K(2; (11,12,0); -) at step 1021 D direct simulation of the twin from the blank tape: every canonical transition is predicted by the parent's abstract map; the base E-start after overflow 6 is reached at step 78,911 B the base E-start K(2; (95,68,0),(34,33,1),(10,15,1),(1,25,1); -): INV+(e) clause by clause, and the parent's Rocq invariant J (ghost phase E1) G the parent's cycle_pair_checked (all identities of proof.md 3.8) on the twin's orbit from the base to L* > lmax J the parent's Rocq invariant J at every macro step of the twin's orbit from the base, for N re-pairings L INFORMATIONAL: lockstep with the parent's abstract orbit (same rule sequence; the states differ by exactly +1 on the far/tail block). Not used by the proof. N (--selftest) negative controls: every check above is fed a deliberately wrong input and must FAIL Usage: python3 -B check_proof.py [--quick] [--selftest] [--seed N] [--steps N] [--lmax N] [--sstep N] [--jcyc N] [--llmax N] """ import sys, os, re, random, argparse, hashlib, itertools, importlib.util HERE = os.path.dirname(os.path.abspath(__file__)) TW = '1RB0RE_1LC0RA_1LD0LB_1LA1LF_1LE1RA_0LC---' PA = '1RB0LD_1RC0RA_1RD1RF_1LA0LE_1RE1LD_0RB---' PDIR = os.path.join(os.path.dirname(HERE), PA) # parent files this delta rests on (sha256 at the time of writing; a change prints WARN, not FAIL) PINS = { 'check_proof.py': '7d1c92b9cf8fdd9f59a03d33dbc06309675461deca038d72cb4ef7e83aeff7fc', 'rocq/jcheck.py': '0e3909cc37b53c188d48f9cf9033c3b62dac34f5fa37a1e812738ce220fa483a', 'proof.md': 'e884353649ff3354f0abde5fbbf6965d31396cd35101e12cdb1f02013937d931', PA + '.v': '91861259c71ce3338425a86a465c4af5b854f63f071737b8cd7feaa36713fcbf', } def load_parent(): argv = sys.argv; sys.argv = ['check_proof.py'] try: spec = importlib.util.spec_from_file_location('parent_cp', os.path.join(PDIR, 'check_proof.py')) cp = importlib.util.module_from_spec(spec); spec.loader.exec_module(cp) sys.path.insert(0, os.path.join(PDIR, 'rocq')) import jcheck finally: sys.argv = argv return cp, jcheck cp, jc = load_parent() # ---------------------------------------------------------------- tables and the map def parse_tm(s): """(state index, read) -> None | (write, +1/-1, next state index).""" tab = {} for i, blk in enumerate(s.split('_')): for r in (0, 1): t = blk[3*r:3*r+3] tab[(i, r)] = None if t == '---' else (int(t[0]), 1 if t[1] == 'R' else -1, ord(t[2]) - 65) return tab TT = parse_tm(TW) # twin TP = parse_tm(PA) # parent S = 'ABCDEF' MAP = {'A': 'D', 'B': 'A', 'C': 'B', 'D': 'C', 'E': 'E', 'F': 'F'} # twin state -> parent state MI = {S.index(a): S.index(b) for a, b in MAP.items()} INV_MI = {v: k for k, v in MI.items()} TB_ = S.index('B') # twin state playing the parent's A (the canonical state) def conj_ok(perm, mirror): for (q, b), v in TT.items(): w = TP[(perm[q], b)] if v is None or w is None: if (v is None) != (w is None): return False continue if (v[0], -v[1] if mirror else v[1], perm[v[2]]) != w: return False return True def section_M(): print('== M. the map: twin = mirror + renaming of the parent') ok = conj_ok(MI, True) print(' table identity under mirror and %s: %s' % (', '.join('%s->%s' % kv for kv in MAP.items()), 'PASS (12/12 entries, halting entry F1 -> F1)' if ok else 'FAIL')) hits = [] for mirror in (False, True): for perm in itertools.permutations(range(6)): if conj_ok(dict(enumerate(perm)), mirror): hits.append((mirror, perm)) uniq = len(hits) == 1 and hits[0][0] and dict(enumerate(hits[0][1])) == MI print(' candidates searched: 2 orientations x 720 renamings; matches: %d (%s) -> %s' % ( len(hits), ['mirror ' + ''.join(S[p] for p in h[1]) if h[0] else 'plain ' + ''.join(S[p] for p in h[1]) for h in hits], 'PASS (unique)' if uniq else 'FAIL')) st = MI[0] okst = st == S.index('D') print(' start state: twin A -> parent %s, so the twin runs the parent from %s;; tape0, not from c0 -> %s' % ( S[st], S[st], 'PASS' if okst else 'FAIL')) # halting transition of the twin: which (state, read) is undefined, who enters it, who enters that und = [k for k, v in TT.items() if v is None] intoF = [(S[q], b) for (q, b), v in TT.items() if v is not None and v[2] == 5] intoD = [(S[q], b) for (q, b), v in TT.items() if v is not None and v[2] == 3] okh = und == [(5, 1)] and intoF == [('D', 1)] and intoD == [('C', 0)] and TT[(3, 1)][1] == -1 and TT[(2, 0)][1] == -1 print(' twin halts only on F1; only D1 (1LF) enters F; only C0 (1LD) enters D: halts exactly from `1 1 0 <C` ' '(mirror of the parent\'s `B> 0 1 1`) -> %s' % ('PASS' if okh else 'FAIL')) return ok and uniq and okst and okh # ---------------------------------------------------------------- S: lockstep conjugacy def section_S(nsteps): print('== S. lockstep: twin from the blank tape vs parent from D on the blank tape, %d steps' % nsteps) size = 1 << 16 t1 = bytearray(size); t2 = bytearray(size); p1 = size // 2; p2 = size // 2; q1 = 0; q2 = MI[0] bad = None for n in range(nsteps): if q2 != MI[q1]: bad = (n, 'state'); break s1 = t1[p1]; s2 = t2[p2] if s1 != s2: bad = (n, 'read'); break a = TT[(q1, s1)]; b = TP[(q2, s2)] if a is None or b is None: bad = (n, 'halt' if (a is None) == (b is None) else 'halt mismatch'); break if b != (a[0], -a[1], MI[a[2]]): bad = (n, 'transition'); break t1[p1] = a[0]; p1 += a[1]; q1 = a[2] t2[p2] = b[0]; p2 += b[1]; q2 = b[2] if not (0 < p1 < len(t1) - 1 and 0 < p2 < len(t2) - 1): # re-centre both tapes (keep the mirror relation: p2 - c2 = -(p1 - c1)) e = bytearray(len(t1)); t1 = e + t1 + bytearray(len(t1)); p1 += len(e) e = bytearray(len(t2)); t2 = e + t2 + bytearray(len(t2)); p2 += len(e) # final tapes, mirrored around the heads c1 = [i - p1 for i, v in enumerate(t1) if v]; c2 = sorted(p2 - i for i, v in enumerate(t2) if v) same = bad is None and c1 == c2 print(' %s; at step %d: twin state %s, parent state %s, %d nonzeros each, tapes mirror images around the head: %s' % ( 'every step: mapped state, same symbol read, mirrored transition' if bad is None else 'BROKEN at step %d (%s)' % bad, nsteps, S[q1], S[q2], len(c1), 'PASS' if same else 'FAIL')) return same # ---------------------------------------------------------------- the twin's own canonical configurations # Twin canonical moment: state B (= parent A) on a blank cell with only blanks to its right, and the cells to its # left, read from the head outward, parse as the parent's K word. K'(h;P;T) := mirror of K(h;P;T). BITS = bytes.maketrans(bytes([0, 1]), b'01') def run_macro_twin(h, P, T, cap=None): """Direct simulation of the TWIN from the mirrored K(h;P;T) (state B on the blank cell right of the word) to the next canonical twin configuration. Returns ((h',P',T'), steps) | ('HALT', steps) | ('CAP', steps).""" w = cp.build(h, P, T)[::-1]; n = len(w) if cap is None: cap = 400*n*n + 100000 pad = 4*n + 64 tape = bytearray(pad) + bytearray(int(c) for c in w) + bytearray(pad) pos = pad + n; st = TB_; hi = pos; steps = 0 while steps < cap: tr = TT[(st, tape[pos])] if tr is None: return ('HALT', steps) tape[pos] = tr[0]; pos += tr[1]; st = tr[2]; steps += 1 if pos < 0 or pos >= len(tape): ext = bytearray(len(tape)) if pos < 0: tape = ext + tape; pos += len(ext); hi += len(ext) else: tape = tape + ext if pos > hi: hi = pos if st == TB_ and pos >= hi - 1 and tape[pos] == 0 and not any(tape[pos:hi+1]): r = cp.parse(bytes(reversed(tape[:pos])).translate(BITS).decode()) if r is not None and r[0] != '?': return (r, steps) return ('CAP', steps) def stream_twin(max_steps): """Direct simulation of the twin from the blank tape; yields (step, K) at every canonical record config.""" size = 1 << 16 tape = bytearray(size); pos = size // 2; st = 0; lo = pos; hi = pos; steps = 0 while steps < max_steps: tr = TT[(st, tape[pos])] if tr is None: yield (steps, 'HALT'); return tape[pos] = tr[0]; pos += tr[1]; st = tr[2]; steps += 1 if pos < 0 or pos >= len(tape): ext = bytearray(len(tape)) if pos < 0: tape = ext + tape; pos += len(ext); lo += len(ext); hi += len(ext) else: tape = tape + ext if pos < lo: lo = pos if pos > hi: hi = pos if st == TB_: r = cp.parse(bytes(reversed(tape[lo:pos])).translate(BITS).decode()) if r is not None and r[0] != '?': yield (steps, r) # ---------------------------------------------------------------- A: rules on the twin directly def section_A(n, rng): print('== A. the parent\'s macro rules, transported (mirrored words), on the TWIN machine: random instances') allok = True; tot = 0 for rule in cp.RULES: ok = 0; fails = [] for i in range(n): h, P, T = cp.gen(rule, rng, i) exp = cp.astep(h, P, T) assert exp[3] == rule, (rule, exp[3], h, P, T) got = run_macro_twin(h, P, T) good = got[0] not in ('HALT', 'CAP') and got[0] == (exp[0], exp[1], exp[2]) and got[1] >= 1 ok += good if not good: fails.append((h, P, T, str(got)[:120])) tot += n; allok &= (ok == n) print(' %-14s %3d/%d %s' % (rule, ok, n, 'PASS' if ok == n else 'FAIL ' + str(fails[:2]))) print(' A total: %s (%d instances)' % ('PASS' if allok else 'FAIL', tot)) return allok # ---------------------------------------------------------------- C, D: initial segment, cross-check, base INIT_STEP = 1021 INIT_K = (2, [(11, 12, 0)], None) BASE_STEP = 78911 BASE_K = (2, [(95, 68, 0), (34, 33, 1), (10, 15, 1), (1, 25, 1)], None) ALT_BASE = (19589, (2, [(47, 32, 0), (16, 15, 1), (4, 21, 1)], None)) # E-start after overflow 4 (option) def section_CD(max_steps): print('== C. twin initial segment') seq = list(stream_twin(max_steps)) if any(k == 'HALT' for _, k in seq): print(' HALT in direct simulation -> FAIL'); return False, None pre = [(s, k) for s, k in seq if s < INIT_STEP] first = [k for s, k in seq if s == INIT_STEP] okC = first == [INIT_K] print(' canonical configs before step %d: %s' % (INIT_STEP, pre)) print(' step %d: %s -> %s' % (INIT_STEP, first[0] if first else None, 'PASS' if okC else 'FAIL')) print('== D. direct simulation of the twin from blank (%d steps) vs the parent\'s abstract map' % max_steps) from collections import Counter cnt = Counter(); bad = 0; rep = 0; base = None; reps = [] post = [x for x in seq if x[0] >= INIT_STEP] for (s0, k0), (s1, k1) in zip(post, post[1:]): try: h, P, T, name = cp.astep(*k0) if (h, P, T) == tuple(k1): cnt[name] += 1 else: bad += 1; print(' MISMATCH at step', s0, k0, '->', k1, 'predicted', (h, P, T)) except cp.Outside as e: bad += 1; name = None; print(' OUTSIDE at step', s0, e) if name in ('Ov', 'X1'): rep += 1; reps.append(s1) if rep == 6: base = (s1, k1) okD = bad == 0 and len(post) > 1 print(' %d consecutive canonical transitions, %s; re-pairings at steps %s; last canonical step %d -> %s' % ( sum(cnt.values()), dict(cnt), reps[:8] + (['...'] if len(reps) > 8 else []), post[-1][0], 'PASS' if okD else 'FAIL')) return okC and okD, (base, seq) def section_B(base, seq): print('== B. the base E-start (after overflow 6)') okpos = base is not None and base[0] == BASE_STEP and tuple(base[1]) == BASE_K print(' direct simulation: step %s, %s; expected step %d, %s -> %s' % ( base[0] if base else None, base[1] if base else None, BASE_STEP, BASE_K, 'PASS' if okpos else 'FAIL')) h, P, T = BASE_K v = cp.inv_violations(h, P, T) Ls = cp.Lstar(P, T) print(' L* = %d; (a) h = %d, p_1 = %d >= 7, digits %s, far pair %s (p_L >= 1, q_L >= 6)' % (Ls, h, P[0][0], [d for _, _, d in P], P[-1])) print(' (b) q_1+1 = %d >= 5*2^3 = 40, q_2 = %d >= 20, q_3 = %d >= 10; (c) p_j + d_j = %s odd; (d) L* = %d >= 3; ' '(e) p_1+1 = %d >= 2^6 = 64, p_2 = %d >= 2^4 = 16' % ( P[0][1] + 1, P[1][1], P[2][1], [P[j][0] + P[j][2] for j in range(3)], Ls, P[0][0] + 1, P[1][0])) print(' INV+(e) (parent\'s inv_violations): %s' % (v or 'all clauses hold')) jb = jc.J(h, [list(x) for x in P], ('N',), ('E1', False)) print(' Rocq invariant J (parent rocq/jcheck.py, ghost (E1, false)): %s' % (jb or 'holds')) diff = [(j + 1, a, b) for j, (a, b) in enumerate(zip(P, cp.BASE_K[1])) if a != b] print(' difference to the parent\'s base %s: %s (only the far pair\'s q)' % (cp.BASE_K, diff)) a_s, a_k = ALT_BASE okalt = any(s == a_s and k == a_k for s, k in seq) and not cp.inv_violations(*a_k) and \ jc.J(a_k[0], [list(x) for x in a_k[1]], ('N',), ('E1', False)) is None print(' option: the E-start after overflow 4, step %d, %s: on the orbit, INV+(e) and J hold -> %s' % ( a_s, a_k, 'yes' if okalt else 'NO')) ok = okpos and not v and jb is None and diff == [(4, (1, 25, 1), (1, 24, 1))] print(' B:', 'PASS' if ok else 'FAIL') return ok # ---------------------------------------------------------------- G: the parent's cycle-pair checker on the twin orbit def section_G(lmax): print('== G. parent\'s cycle_pair_checked (proof.md 3.8 identities) on the twin orbit, base -> L* > %d' % lmax) st = cp.new_stats(); fails = []; K = BASE_K try: while cp.Lstar(K[1], K[2]) <= lmax and len(fails) < 20: K = cp.cycle_pair_checked(K, fails, st) except cp.Outside as e: fails.append('OUTSIDE %s' % e) for f in fails[:10]: print(' FAIL', f) print(' ' + cp.fmt_stats(st)) ok = not fails print(' G:', 'PASS' if ok else 'FAIL') return ok # ---------------------------------------------------------------- J: the Rocq invariant on the twin orbit def section_J(ncyc): print('== J. parent\'s Rocq invariant J at every macro step of the twin orbit from the base, %d re-pairings' % ncyc) h, P, T = BASE_K res = jc.run(h, [list(x) for x in P], ('N',), ('E1', False), ncyc) ok = res[0] == 'OK' print(' %s %s; rules %s -> %s' % (res[0], res[1] or '', res[3], 'PASS' if ok else 'FAIL')) if not ok: print(' at', res[2]) return ok # ---------------------------------------------------------------- L: lockstep with the parent's abstract orbit (informational) def section_L(lmax): print('== L. INFORMATIONAL: twin abstract orbit vs parent abstract orbit, in lockstep, to L > %d' % lmax) from collections import Counter A = cp.INIT_K; B = INIT_K; nmac = 0; where = Counter(); bad = None def app(K, m): h, P, T = K; V = cp.value(P); W = V - m return (h + 4*m, [(p + cp.touches(V, m, j), q - cp.touches(V, m, j), (W >> j) & 1) for j, (p, q, d) in enumerate(P)], T) def plus_one(a, b): """None if b = a except +1 on exactly one of p_L, q_L, the tail value; else the location name.""" if a[0] != b[0] or len(a[1]) != len(b[1]) or (a[2] is None) != (b[2] is None): return 'shape' if a[2] is not None and a[2][0] != b[2][0]: return 'shape' d = [(j, c, y - x) for j, (u, v) in enumerate(zip(a[1], b[1])) for c, (x, y) in enumerate(zip(u, v)) if x != y] if a[2] is not None and a[2][1] != b[2][1]: d.append(('T', a[2][0], b[2][1] - a[2][1])) if len(d) != 1 or d[0][2] != 1: return 'diff %s' % d j, c, _ = d[0] if j == 'T': return c if j != len(a[1]) - 1 or c == 2: return 'diff %s' % d return 'pL' if c == 0 else 'qL' while len(A[1]) <= lmax: ba = cp.bulk(*A); bb = cp.bulk(*B) if ba and bb: m = min(ba[3], bb[3]); A = app(A, m); B = app(B, m); nmac += m else: ha, Pa, Ta, na = cp.astep(*A); hb, Pb, Tb, nb = cp.astep(*B); nmac += 1 if na != nb: bad = 'rule sequences diverge: %s vs %s at %s / %s' % (na, nb, A, B); break A = (ha, Pa, Ta); B = (hb, Pb, Tb) loc = plus_one(A, B) if loc not in ('pL', 'qL', 'T1', 'T2'): bad = 'not a +1 on the far/tail block: %s at %s / %s' % (loc, A, B); break where[loc] += 1 ok = bad is None print(' %s; macro steps ~2^%d; +1 location counts (per lockstep move): %s -> %s' % ( 'same rule at every macro step, states differ by exactly +1 on the far pair or the tail' if ok else bad, nmac.bit_length(), dict(where), 'PASS (informational)' if ok else 'FAIL (informational)')) # different orbits: no canonical twin configuration occurs among the parent's (direct simulation, both machines) N = 3*10**5 par = {repr(k) for s, k in cp.stream_canonical(N)} tw = [(s, k) for s, k in stream_twin(N)] common = [(s, k) for s, k in tw if repr(k) in par] ok2 = not common print(' first %d steps: %d twin and %d parent canonical configurations, %d in common -> %s' % ( N, len(tw), len(par), len(common), 'PASS (informational: different orbits)' if ok2 else 'FAIL %s' % common[:3])) return ok and ok2 def selftest(): """Negative controls: each check is run on a deliberately wrong input and must FAIL.""" import io, contextlib print('== N. negative controls (--selftest): every check must FAIL on a wrong input') g = globals() def run(patch, f, *a): old = {k: g[k] for k in patch} g.update(patch) try: with contextlib.redirect_stdout(io.StringIO()): r = f(*a) finally: g.update(old) return r[0] if isinstance(r, tuple) else r bad_map = dict(MI); bad_map[4], bad_map[5] = MI[5], MI[4] from_A = dict(MI); from_A[0] = 0 skeptic = (2, [(7, 19, 0), (2, 10, 1), (1, 6, 1)], None) _, (b, seq) = section_CD_quiet(100000) cases = [ ('M: map with E and F swapped', {'MI': bad_map}, section_M, ()), ('S: parent started in A instead of D', {'MI': from_A}, section_S, (5000,)), ('A: rules run on the parent\'s (unmirrored) table', {'TT': TP}, section_A, (1, random.Random(1))), ('C: expecting the parent\'s K0 = K(2;(11,11,0);-)', {'INIT_K': cp.INIT_K}, section_CD, (5000,)), ('B: expecting the parent\'s base at step 78,710', {'BASE_K': cp.BASE_K, 'BASE_STEP': 78710}, section_B, (b, seq)), ('G: from the skeptic start (violates (e))', {'BASE_K': skeptic}, section_G, (10,)), ('J: from the skeptic start', {'BASE_K': skeptic}, section_J, (4,)), ] ok = True for name, patch, f, a in cases: r = run(patch, f, *a) ok &= not r print(' %-55s -> %s' % (name, 'FAILS as it should' if not r else 'PASSES: the check is too weak')) print(' N:', 'PASS' if ok else 'FAIL') return ok def section_CD_quiet(n): import io, contextlib with contextlib.redirect_stdout(io.StringIO()): return section_CD(n) def pins(): print('== pins: parent files used by this delta') okall = True for rel, want in PINS.items(): try: got = hashlib.sha256(open(os.path.join(PDIR, rel), 'rb').read()).hexdigest() except OSError: got = None ok = got == want; okall &= ok print(' %-50s %s' % (rel, 'unchanged' if ok else 'WARN changed since the delta was written (%s)' % (got and got[:16]))) return okall if __name__ == '__main__': ap = argparse.ArgumentParser() ap.add_argument('--quick', action='store_true') ap.add_argument('--seed', type=int, default=20261010) ap.add_argument('--steps', type=int, default=None, help='section D direct-simulation steps (default 3e7; quick 2e5)') ap.add_argument('--sstep', type=int, default=None, help='section S lockstep steps (default 5e6; quick 2e5)') ap.add_argument('--lmax', type=int, default=None, help='section G: L* bound (default 300; quick 60)') ap.add_argument('--jcyc', type=int, default=None, help='section J: re-pairings (default 30; quick 16)') ap.add_argument('--llmax', type=int, default=None, help='section L: L bound (default 120; quick 40)') ap.add_argument('--selftest', action='store_true', help='also run the negative controls (section N)') a = ap.parse_args() rng = random.Random(a.seed) q = a.quick n = 12 if q else 45 steps = a.steps or (2*10**5 if q else 3*10**7) sstep = a.sstep or (2*10**5 if q else 5*10**6) lmax = a.lmax or (60 if q else 300) jcyc = a.jcyc or (16 if q else 30) llmax = a.llmax or (40 if q else 120) pins() res = {} res['M'] = section_M() res['S'] = section_S(sstep) res['A'] = section_A(n, rng) okCD, (base, seq) = section_CD(steps) res['C+D'] = okCD res['B'] = section_B(base, seq) res['G'] = section_G(lmax) res['J'] = section_J(jcyc) infoL = section_L(llmax) if a.selftest: res['N'] = selftest() allok = all(res.values()) print('SUMMARY: %s (%s; L informational: %s)' % ('PASS' if allok else 'FAIL', ', '.join('%s %s' % (k, 'PASS' if v else 'FAIL') for k, v in res.items()), 'PASS' if infoL else 'FAIL')) sys.exit(0 if allok else 1) |