/machines/1RB0LC_1LA0RE_0RD1LF_1LC1LB_0LD0RB_0LA---/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 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 | #!/usr/bin/env python3 """check_proof.py -- simulation evidence for proof.md of 1RB0LC_1LA0RE_0RD1LF_1LC1LB_0LD0RB_0LA--- Run from this directory: python3 -B check_proof.py [--quick] Sections (match proof.md section 7): A token window lemmas W1..W6 (exact finite runs; the head never leaves the window) B right-sweep rules R1..R5 on random parameters (exact runs, step formulas) C left turnaround L (inc_L) exhaustively over the word domain, length <= 9 (8 with --quick) D departure rules GEN / ABS1 / ABS0 / ABSO1 on random instances (direct simulation to the next departure) E right-part lemmas H1..H4 on random right parts (pure arithmetic on the model) F trajectory: C dumper to 1e8 steps, lockstep model check + every invariant clause, open lemmas O1/O2 probed G initial segment: blank tape -> first departure at step >= 2000 (exact config and step) Nothing here is a proof. Every check prints PASS/FAIL; the last line is SUMMARY. Review 2026-10-10 added: L with right context O and the empty word; spacing-3 and edge-case departures; P_k (replaces O1) exhaustively; Safe(w, tau) and H4-with-strips on the trajectory. """ import sys, os, random, itertools, subprocess HERE = os.path.dirname(os.path.abspath(__file__)) sys.path.insert(0, os.path.join(HERE, 'scripts', 'deepen')) from linc import inc_L # noqa: E402 from model3 import step as model_step, inc, abs0 # noqa: E402 from nextdep import next_departure # noqa: E402 from tok import parses, compact # noqa: E402 QUICK = '--quick' in sys.argv TM = '1RB0LC_1LA0RE_0RD1LF_1LC1LB_0LD0RB_0LA---' S = 'ABCDEF' TR = {} for qi, part in enumerate(TM.split('_')): for s in (0, 1): t = part[3*s:3*s+3] TR[(S[qi], s)] = None if t == '---' else (int(t[0]), 1 if t[1] == 'R' else -1, t[2]) TOK = {'0': '00', '1': '10', 'O': '100', 'I': '110'} def w2s(w): return ''.join(TOK[c] for c in w) B = '10110' RESULTS = [] def report(name, ok, detail=''): RESULTS.append((name, ok)) print(('PASS ' if ok else 'FAIL ') + name + (' ' + detail if detail else '')) def runwin(cells, pos, q, maxn=10**6): c = list(cells); n = 0 while 0 <= pos < len(c) and n < maxn: tr = TR[(q, c[pos])] if tr is None: return c, pos, q, n, True c[pos] = tr[0]; pos += tr[1]; q = tr[2]; n += 1 return c, pos, q, n, False def bits(s): return [int(x) for x in s] # ---------------------------------------------------------------- A: token window lemmas print('== A: token window lemmas') # (name, before-cells, head index, state, after-cells, exit side 'L'/'R', exit state, steps) WL = [ ('W1 E> 1 -> 1 E>', '10', 0, 'E', '10', 'R', 'E', 4), ('W2 1 E> I -> I 1 E>', '10110', 2, 'E', '11010', 'R', 'E', 13), ('W3 E> O -> <F I', '100', 0, 'E', '110', 'L', 'F', 7), ('W4 1 E> T -> <F O T', '10'+'11'+'0'*7, 2, 'E', '100'+'11'+'0'*6, 'L', 'F', 19), ('W5 I 1 <F -> <F 1 I', '11010', 4, 'F', '10110', 'L', 'F', 9), ('W6 I <F -> <F O', '110', 2, 'F', '100', 'L', 'F', 3), ] for name, bef, p, q, aft, side, q2, n in WL: c, pos, qq, k, h = runwin(bits(bef), p, q) ok = (not h and ''.join(map(str, c)) == aft and qq == q2 and k == n and ((side == 'L' and pos == -1) or (side == 'R' and pos == len(bef)))) report(name, ok, f'{k} steps') # ---------------------------------------------------------------- B: right-sweep rules print('== B: right-sweep rules (exact runs, sentinel left part "10" so F stops on entering it)') def run_right(R, maxn=10**7): """tape = '10' + R + 0^pad, E at the first cell of R; stop when F first reads a cell left of R. returns (new R string trimmed to len, steps) or None""" L = '10'; pad = 40 c = bits(L + R + '0'*pad); pos = len(L); q = 'E'; n = 0 while n < maxn: tr = TR[(q, c[pos])] if tr is None: return ('HALT', n) c[pos] = tr[0]; pos += tr[1]; q = tr[2]; n += 1 if pos < len(L): return (q, pos - len(L), ''.join(map(str, c[len(L):])).rstrip('0'), n) return ('MAX', n) def Rstr(g, D, G): return B*g + ''.join(('110' if d else '100') + B*G[i] for i, d in enumerate(D)) + '11' rng = random.Random(7) okR1 = all(runwin(bits(B*n), 0, 'E')[1:4] == (5*n, 'E', 17*n) and ''.join(map(str, runwin(bits(B*n), 0, 'E')[0])) == '11010'*n for n in range(0, 31)) report('R1 E> B^n -> C^n E>, 17n, n=0..30', okR1) okR2 = all(runwin(bits('11010'*n), 5*n-1, 'F')[1:4] == (-1, 'F', 9*n) and ''.join(map(str, runwin(bits('11010'*n), 5*n-1, 'F')[0])) == B*n for n in range(1, 31)) report('R2 C^n <F -> <F B^n, 9n, n=1..30', okR2) cnt = {'R3': 0, 'R4': 0, 'R5': 0}; bad = [] for trial in range(600 if QUICK else 2000): a = rng.randint(1, 25); j = rng.randint(0, 6); bs = [rng.randint(0, 12) for _ in range(j)] kind = rng.choice(['zero', 'end']) if j == 0 and kind == 'zero': R = B*a + '100' + B*rng.randint(0, 3) + '11'; tail = R[5*a+3:] exp = B*a + '110' + tail; n_exp = 26*a + 7; key = 'R3' elif kind == 'zero': rest = B*rng.randint(0, 3) + '11' R = B*a + ''.join('110' + B*b for b in bs) + '100' + rest exp = B*(a-1) + ''.join('100' + B*b for b in bs[:-1]) + '100' + B*(bs[-1]+1) + '110' + rest n_exp = 26*(a+sum(bs)) + 16*j + 7; key = 'R4' else: R = B*a + ''.join('110' + B*b for b in bs) + '11' exp = B*(a-1) + ''.join('100' + B*b for b in bs) + '100100' + '11' n_exp = 26*(a+sum(bs)) + 16*j + 13; key = 'R5' r = run_right(R) ok = r[0] == 'F' and r[1] == -1 and r[2] == exp.rstrip('0') and r[3] == n_exp cnt[key] += 1 if not ok and len(bad) < 5: bad.append((key, a, bs, r[:2], r[3] if len(r) > 3 else None, n_exp)) report(f'R3/R4/R5 exact output and step formula on random parameters {cnt}', not bad, str(bad[:3])) # ---------------------------------------------------------------- C: left turnaround print('== C: left turnaround L: 0^inf w <F B -> 0^inf inc_L(w) E> B') def in_domain(w): """WS-domain for the left turnaround (proof.md 3.2): first token not 0; last token 0/1; w not ending I1; markers (O/I) pairwise >= 3 tokens apart.""" if not w or w[0] == '0' or w[-1] in 'OI' or w.endswith('I1'): return False m = [i for i, ch in enumerate(w) if ch in 'OI'] return all(b - a >= 3 for a, b in zip(m, m[1:])) def turnaround(w, pad=30): L = '0'*pad + w2s(w); R = B*2 + '0'*8 c = bits(L + R); pos = len(L) - 1; q = 'F'; n = 0; lo = pos; hi = pos while n < 10**6: tr = TR[(q, c[pos])] if tr is None: return ('HALT', n) c[pos] = tr[0]; pos += tr[1]; q = tr[2]; n += 1 lo = min(lo, pos); hi = max(hi, pos) if pos < 2: return ('OOB', n) if q == 'E' and tr[1] > 0 and pos >= len(L) - 4 and c[pos:pos+5] == [1, 0, 1, 1, 0] and pos == len(L): left = ''.join(map(str, c[:pos])).lstrip('0') return ('OK', n, left, hi - len(L) + 1, len(L) - lo) if pos > len(L) + 1: return ('RIGHT', n) return ('MAX', n) maxlen = 8 if QUICK else 9 tot = good = 0; badC = []; steps_tab = {}; reach_right = 0; out_dom_bad = 0; out_dom = 0 for n_ in range(1, maxlen+1): for tup in itertools.product('01OI', repeat=n_): w = ''.join(tup) if w[0] == '0': continue dom = in_domain(w) r = turnaround(w) if not dom: if w[-1] in '01' and not w.endswith('I1'): out_dom += 1 ok_o = r[0] == 'OK' and r[2] == w2s(inc_L(w)) if not ok_o: out_dom_bad += 1 continue tot += 1 ok = r[0] == 'OK' and r[2] == w2s(inc_L(w)) if ok: good += 1 cross0 = w[-1] == '0' and w[:-1].rstrip('1').endswith('I') # I-crossing with t = 0 if r[3] > 2 or (r[3] == 2 and not cross0): reach_right += 1 if all(ch in '01' for ch in w): u = w[:-1]; k = len(u) - len(u.rstrip('1')) key = (w[-1], 'edge' if k == len(u) else 'stop0') steps_tab.setdefault(key, {}).setdefault(k, set()).add(r[1]) elif len(badC) < 5: badC.append((w, r)) report(f'L on all {tot} domain words of length <= {maxlen}: machine == inc_L; reads right of w only on an I-crossing with t=0 (tail I 1^k 0), and then only the first token 10 of B', good == tot and reach_right == 0, str(badC)) # step formula for marker-free words: steps = 6k + 13 + 8*[t=1]... fitted and checked here fit_ok = True; fitted = {} for key, d in steps_tab.items(): for k, ss in d.items(): if len(ss) != 1: fit_ok = False fitted[(key, k)] = min(ss) # report the affine law per class law = {} for (key, k), s in sorted(fitted.items()): law.setdefault(key, []).append((k, s)) law_ok = True; law_txt = [] for key, pts in law.items(): (k0, s0), (k1, s1) = pts[0], pts[1] slope = (s1 - s0) // (k1 - k0); icpt = s0 - slope*k0 law_ok &= all(s == slope*k + icpt for k, s in pts) law_txt.append(f'{key}: {slope}k+{icpt}') report('L step count is affine in the carry length k for marker-free words (' + '; '.join(sorted(law_txt)) + ')', fit_ok and law_ok) print(f' (outside the domain, last token 0/1: {out_dom} words, {out_dom_bad} where the machine differs from inc_L)') # --- review 2026-10-10: L for any right context whose first two cells are 1,0 (a 1 token or an O token) def turnaround2(w, R0, pad=30): """0^inf w <F R0 ... ; stop when E first moves right onto the first cell after w with R0 intact. returns ('OK', steps, left cells, max cells read right of w) or a failure tag""" L = '0'*pad + w2s(w); R = R0 + '0'*8 c = bits(L + R); pos = len(L) - 1; q = 'F'; n = 0; hi = pos while n < 10**6: tr = TR[(q, c[pos])] if tr is None: return ('HALT', n) c[pos] = tr[0]; pos += tr[1]; q = tr[2]; n += 1 hi = max(hi, pos) if pos < 2: return ('OOB', n) if q == 'E' and tr[1] > 0 and pos == len(L) and ''.join(map(str, c[pos:pos+len(R0)])) == R0: return ('OK', n, ''.join(map(str, c[:pos])).lstrip('0'), hi - len(L) + 1) if pos > len(L) + 1: return ('RIGHT', n) return ('MAX', n) ctxs = {'1 I (B)': B + B, 'O B': '100' + B, '1 O': '10' + '100' + B} dom_words = [''] + [''.join(t) for n_ in range(1, (8 if QUICK else 9) + 1) for t in itertools.product('01OI', repeat=n_)] dom_words = [w for w in dom_words if w == '' or in_domain(w)] for cname, R0 in ctxs.items(): okc = 0; badc = []; rr = 0 for w in dom_words: r = turnaround2(w, R0) if r[0] == 'OK' and r[2] == w2s(inc_L(w)): okc += 1 if r[3] > 2: rr += 1 elif len(badc) < 3: badc.append((w, r[:3])) report(f'L with right context [{cname}] on {len(dom_words)} words (incl. the empty word): machine == inc_L, reads <= 2 cells right of w: {okc}/{len(dom_words)}', okc == len(dom_words) and rr == 0, str(badc)) # precondition is needed: with an I token (cells 110) right of w, the t=0 I-crossing words go wrong neg = [w for w in dom_words if w and w[-1] == '0' and w[:-1].rstrip('1').endswith('I')] negbad = sum(1 for w in neg if not (lambda r: r[0] == 'OK' and r[2] == w2s(inc_L(w)))(turnaround2(w, '110' + B))) report(f'L precondition is sharp: with I (110) right of w, {negbad}/{len(neg)} t=0 I-crossing words differ from inc_L (all other words unaffected)', negbad == len(neg) and len(neg) > 0) # ---------------------------------------------------------------- D: departure rules print('== D: departure rules on random instances (direct simulation to the next departure)') rng = random.Random(11) def rword(n): w = '1' + ''.join(rng.choice('01') for _ in range(n-1)) for _ in range(rng.choice([0, 0, 1, 1, 2]) if len(w) >= 5 else 0): i = rng.randint(0, len(w) - 4) w = w[:i] + rng.choice('OI') + w[i+1:] if w[-1] in 'OI': w = w[:-1] + rng.choice('01') return w def ws_ok(w): m = [i for i, ch in enumerate(w) if ch in 'OI'] return w[0] != '0' and w[-1] in '01' and all(b - a >= 4 for a, b in zip(m, m[1:])) def rright(k): """random right part satisfying INV-R: H_i = G_i - d_(i+1) >= 0, non-increasing, H_k = G_k = 0""" D = [rng.randint(0, 1) for _ in range(k)] H = [0]*k for i in range(k-2, -1, -1): H[i] = H[i+1] + rng.choice([0, 0, 1, 1, 2, 3, rng.randint(0, 20)]) G = [H[i] + (D[i+1] if i+1 < k else 0) for i in range(k)] return D, G from collections import Counter CD = Counter(); badD = [] N = 800 if QUICK else 3000 for t_ in range(N): w = rword(rng.randint(4, 24)) if not ws_ok(w): continue k = rng.randint(2, 12); D, G = rright(k) mode = t_ % 4 if mode == 0: g = rng.randint(2, 60) elif mode == 1: g = 1; D[0] = 0 else: g = 1; D[0] = 1 rule, pred = model_step((w, g, D, G)) if pred is None: CD[(rule, 'no-rule')] += 1; continue r = next_departure(w, g, D, G) ok = r[0] == 'OK' and r[2] == pred CD[(rule, ok)] += 1 if not ok and len(badD) < 5: badD.append((rule, w, g, D, G, r[:3], pred)) okD = not badD and all(k[1] in (True, 'no-rule') for k in CD) report('GEN/ABS1/ABS0/ABSO1 predicted == simulated ' + str(dict(CD)), not badD, str(badD[:2])) # ABSO1 explicitly (side case, never on the trajectory) CO = Counter(); badO = [] for t_ in range(200 if QUICK else 600): x = rword(rng.randint(3, 16)) if x[-1] not in '01': continue w = x + 'O1' if not ws_ok(w): continue k = rng.randint(2, 10); D, G = rright(k); D[0] = 1 rule, pred = model_step((w, 1, D, G)) if rule != 'ABSO1': continue r = next_departure(w, 1, D, G) ok = r[0] == 'OK' and r[2] == pred CO[ok] += 1 if not ok and len(badO) < 3: badO.append((w, D, G, r[:3], pred)) report(f'ABSO1 on {sum(CO.values())} targeted instances', not badO and sum(CO.values()) > 0, str(badO)) # --- review 2026-10-10: spacing 3 (markers exactly 3 tokens apart), and the edge cases |w| = 1 and w = '' def rword3(n): """random word with >= 2 markers, consecutive markers exactly 3 apart where possible""" w = list('1' + ''.join(rng.choice('01') for _ in range(n-1))) i = rng.randint(0, 2) while i <= len(w) - 3: w[i] = rng.choice('OI'); i += 3 if rng.random() < 0.7 else 4 w = ''.join(w) if w[-1] in 'OI': w = w[:-1] + rng.choice('01') return w def ws3(w): m = [i for i, ch in enumerate(w) if ch in 'OI'] return w[0] != '0' and w[-1] in '01' and all(b - a >= 3 for a, b in zip(m, m[1:])) and any(b - a == 3 for a, b in zip(m, m[1:])) C3 = Counter(); bad3 = [] for t_ in range(800 if QUICK else 3000): w = rword3(rng.randint(6, 24)) if not ws3(w): continue k = rng.randint(2, 12); D, G = rright(k) mode = t_ % 4 if mode == 0: g = rng.randint(2, 60) elif mode == 1: g = 1; D[0] = 0 else: g = 1; D[0] = 1 rule, pred = model_step((w, g, D, G)) if pred is None: C3[(rule, 'no-rule')] += 1; continue r = next_departure(w, g, D, G) ok = r[0] == 'OK' and r[2] == pred C3[(rule, ok)] += 1 if not ok and len(bad3) < 5: bad3.append((rule, w, g, D, G, r[:3], pred)) report('spacing 3: GEN/ABS1/ABS0/ABSO1 predicted == simulated on words with markers exactly 3 apart ' + str(dict(C3)), not bad3 and C3[('GEN', True)] > 0 and C3[('ABS1', True)] > 0, str(bad3[:2])) CE = Counter(); badE = [] for t_ in range(100 if QUICK else 300): k = rng.randint(2, 10); D, G = rright(k) for w, g in (('1', 1), ('', rng.randint(2, 30))): if w == '1': D[0] = 1 rule, pred = model_step((w, g, D, G)) r = next_departure(w, g, D, G) ok = pred is not None and r[0] == 'OK' and r[2] == pred CE[(rule, w or "''", ok)] += 1 if not ok and len(badE) < 3: badE.append((w, g, D, G, rule, r[:3], pred)) report('edge cases: ABS1 on w = 1 (u empty, gives 10) and GEN on the empty word (inc_L(\'\') = 10) ' + str(dict(CE)), not badE, str(badE)) # ---------------------------------------------------------------- E: right-part lemmas (arithmetic) print('== E: right-part lemmas H1..H4 (pure model arithmetic, random right parts)') def Hvec(g, D, G): k = len(D) return [g - D[0]] + [G[i] - (D[i+1] if i+1 < k else 0) for i in range(k)] rng = random.Random(5) okH1 = okH2 = okH3 = True; nH = 0 for t_ in range(4000 if QUICK else 20000): k = rng.randint(1, 10); D, G = rright(k); g = rng.randint(1, 40) if g == 1 and D[0] == 1: continue H = Hvec(g, D, G) g2, D2, G2 = inc(g, D, G); H2 = Hvec(g2, D2, G2); nH += 1 # H1: H_i (i>=1) never decreases; H_0 drops by 1 exactly when d_1 is set okH1 &= all(H2[i] >= H[i] for i in range(1, len(H))) and H2[0] == H[0] - (1 - D[0]) # H2: H_i - H_{i+1} never decreases (i>=1, over the old index range); new entries are 0 okH2 &= all(H2[i] - H2[i+1] >= H[i] - H[i+1] for i in range(1, len(H)-1)) and all(x == 0 for x in H2[len(H):]) # H3: last gap stays 0, g stays >= 1 okH3 &= G2[-1] == 0 and g2 >= 1 report(f'H1 inc never lowers H_i (i>=1); H_0 drops exactly on a set of d_1 ({nH} incs)', okH1) report('H2 inc never lowers H_i - H_(i+1); overflow appends H = 0, 0', okH2) report('H3 inc keeps G_k = 0 and g >= 1 (from g >= 2 or d_1 = 0)', okH3) # H4: absorption interval Delta = 2(h_1 + c) - 1 + d_2 (c=2 ABS1, c=1 ABS0) and next h_1 formula, on the model okH4 = True; nH4 = 0 for t_ in range(3000 if QUICK else 10000): k = rng.randint(2, 10); D, G = rright(k); D[0] = 1 if G[0] - D[1] < 0: continue c = rng.choice([1, 2]) g, D2, G2 = inc(G[0] + c, D[1:], G[1:]); n = 1 while not (g == 1 and D2[0] == 1): g, D2, G2 = inc(g, D2, G2); n += 1 if n > 10**5: break h1 = G[0] - D[1] okH4 &= n == 2*(h1 + c) - 1 + D[1]; nH4 += 1 report(f'H4 (no strips in between) sweeps from an absorption to the next = 2(h_1+c) - 1 + d_2 ({nH4} cases; with strips see F)', okH4) # P_k replaces O1 (review 2026-10-10): exhaustive one-step check, INV-R + INV-W + P_k -> INV-R + P_k for sp in (4, 3): pr = subprocess.run([sys.executable, '-B', os.path.join(HERE, 'scripts', 'review', 'pk_check.py'), '6' if QUICK else '7', '4', '4', str(sp)], capture_output=True, text=True) report('P_k ' + pr.stdout.strip().splitlines()[0], pr.returncode == 0) # ---------------------------------------------------------------- F: trajectory print('== F: trajectory (C departure dumper), lockstep model + invariant clauses') SCR = os.environ.get('CP_SCRATCH', '/tmp/claude-1000/cp_bb6_m1') os.makedirs(SCR, exist_ok=True) exe = os.path.join(SCR, 'dep'); dump = os.path.join(SCR, 'dep.txt') horizon = '3e7' if QUICK else '1e8' subprocess.run(['gcc', '-O2', '-o', exe, os.path.join(HERE, 'scripts', 'deepen', 'dep.c')], check=True) with open(dump, 'w') as f: subprocess.run([exe, horizon], stdout=f, stderr=subprocess.DEVNULL, check=True) rows = [] for line in open(dump): p = line.split() if p[0] in ('HALT', 'BADLEFT') or 'RAW' in p: rows.append(None); continue st = int(p[0]); w = compact(parses(p[4])[0]); g = int(p[5]) D = [] if p[6] == '-' else [int(ch) for ch in p[6]] G = [] if p[7] == '-' else [int(x) for x in p[7].split(',')] rows.append((st, w, g, D, G)) START = 2000 i0 = next(i for i, r in enumerate(rows) if r and r[0] >= START) C = Counter(); badF = [] def strip(w, g): while w.endswith('I1'): w = w[:-2]; g += 1 return w, g prev_rule = [] for i in range(i0, len(rows) - 1): r = rows[i]; r2 = rows[i+1] if r is None or r2 is None: C['unparsed'] += 1; continue st, w, g, D, G = r rule, pred = model_step((w, g, D, G)) C['lock', rule, pred == r2[1:]] += 1 if pred != r2[1:] and len(badF) < 5: badF.append(('lock', st, rule)) ws, gs = strip(w, g) k = len(D); H = Hvec(gs, D, G) # INV-R (proven part) C['R: g>=1, G_k=0, H_i>=0, H non-increasing (i>=1)', gs >= 1 and G[-1] == 0 and min(H[1:]) >= 0 and all(H[j] >= H[j+1] for j in range(1, k))] += 1 C['R: H_i>=1 for 1<=i<=k-3 (lemma H5)', all(H[j] >= 1 for j in range(1, k-2))] += 1 # INV-W (word shape) m = [j for j, ch in enumerate(ws) if ch in 'OI'] C['W: first token not 0, last token 0/1, markers >=4 apart', ws[0] != '0' and ws[-1] in '01' and all(b - a >= 4 for a, b in zip(m, m[1:]))] += 1 C['P_k: k>=2, or k=1, D=[1] and (g>=2 or last token 1)', k >= 2 or (k == 1 and D == [1] and (gs >= 2 or ws[-1:] == '1'))] += 1 if rule != 'GEN': C[('info', 'O1 h_1>=1 at absorptions'), k >= 2 and H[1] >= 1] += 1 if rule == 'ABS0': C['abs0: token before the trailing 1-run is not a marker (O2)', pred is not None] += 1 # transient lemma T: the two sweeps after an ABS1 are GEN if rule == 'ABS1': nxt = [model_step(rows[i+j][1:])[0] if rows[i+j] else None for j in (1, 2)] C['T: two sweeps after ABS1 are GEN', nxt == ['GEN', 'GEN']] += 1 C['rule', rule] += 1 # --- review 2026-10-10: Safe(w, tau) (O2 as a predicate on one configuration), H4 with strips, margins def spaced(w, sp): m = [j for j, ch in enumerate(w) if ch in 'OI'] return all(b - a >= sp for a, b in zip(m, m[1:])) def safe(w, tau, sp): """word-only run to the next absorption: tau = 2g-1-d_1 sweeps, each strip adds 2; at tau = 0 an ABS0 must be defined and leave markers >= sp apart. Returns (ok, word at the absorption).""" while True: while w.endswith('I1'): w = w[:-2]; tau += 2 if tau == 0: if w[-1] == '0': o = abs0(w); return (o is not None and spaced(o, sp)), w return True, w w = inc_L(w); tau -= 1 abs_idx = [i for i in range(i0, len(rows) - 1) if rows[i] and model_step(rows[i][1:])[0] != 'GEN'] starts = [i0] + [i + 1 for i in abs_idx if i + 1 < len(rows) - 1] for i in starts: st, w, g, D, G = rows[i]; ws, gs = strip(w, g); tau = 2*gs - 1 - D[0] for sp in (4, 3): ok, wa = safe(ws, tau, sp) C['Safe(w, 2g-1-d_1), spacing >= %d, at the first departure of every interval' % sp, ok] += 1 # H4 with strips: Delta = 2(h_1 + c) - 1 + d_2 + 2s, s = number of strips in the interval for a, b in zip(abs_idx, abs_idx[1:]): st, w, g, D, G = rows[a]; rule = model_step(rows[a][1:])[0] c = 2 if rule == 'ABS1' else 1 if rule == 'ABSO1': continue h1 = G[0] - (D[1] if len(D) > 1 else 0) s_ = sum((len(rows[j][1]) - len(strip(rows[j][1], 0)[0])) // 2 for j in range(a + 1, b + 1)) C['H4 with strips: Delta = 2(h_1+c) - 1 + d_2 + 2s on the trajectory', b - a == 2*(h1 + c) - 1 + D[1] + 2*s_] += 1 marg = [] for i in abs_idx: st, w, g, D, G = rows[i]; ws, gs = strip(w, g) if model_step(rows[i][1:])[0] == 'ABS0' and any(ch in 'OI' for ch in ws): marg.append((st, ws)) print(' ABS0 with a marker present (step, word):', marg) lockbad = sum(v for k_, v in C.items() if k_[0] == 'lock' and k_[2] is False) nsweeps = sum(v for k_, v in C.items() if k_[0] == 'lock') report(f'lockstep model == machine over {nsweeps} sweeps (start step {rows[i0][0]}, horizon {horizon})', lockbad == 0 and C['unparsed'] == 0, str({k_[1]: v for k_, v in C.items() if k_[0] == 'rule'})) for key in ['R: g>=1, G_k=0, H_i>=0, H non-increasing (i>=1)', 'R: H_i>=1 for 1<=i<=k-3 (lemma H5)', 'W: first token not 0, last token 0/1, markers >=4 apart', 'P_k: k>=2, or k=1, D=[1] and (g>=2 or last token 1)', 'Safe(w, 2g-1-d_1), spacing >= 4, at the first departure of every interval', 'Safe(w, 2g-1-d_1), spacing >= 3, at the first departure of every interval', 'H4 with strips: Delta = 2(h_1+c) - 1 + d_2 + 2s on the trajectory', 'abs0: token before the trailing 1-run is not a marker (O2)', 'T: two sweeps after ABS1 are GEN']: t_ = C[(key, True)]; f_ = C[(key, False)] report(f'{key}: {t_}/{t_+f_}', f_ == 0 and t_ > 0) # ---------------------------------------------------------------- G: initial segment print('== G: initial segment from the blank tape') first = rows[i0] # replay with an independent python simulator and compare the exact tape at that step size = 4000; tape = bytearray(size); pos = size//2; q = 'A'; n = 0 while n < first[0]: tr = TR[(q, tape[pos])] tape[pos] = tr[0]; pos += tr[1]; q = tr[2]; n += 1 lo = 0 while not tape[lo]: lo += 1 hi = size - 1 while not tape[hi]: hi -= 1 left = ''.join(map(str, tape[lo:pos])); right = ''.join(map(str, tape[pos:hi+1])) exp_left = w2s(first[1]); exp_right = Rstr(first[2], first[3], first[4]) report(f'init: c0 -->({first[0]}) 0^inf {first[1]} E> R(g={first[2]}, D={first[3]}, G={first[4]}) [left={left} right={right}]', q == 'E' and left == exp_left and right == exp_right) print() nf = sum(1 for _, ok in RESULTS if not ok) print(f'SUMMARY {"PASS" if nf == 0 else "FAIL"} ({len(RESULTS) - nf}/{len(RESULTS)} checks pass)') |