diff --git a/.github/workflows/cleanup-sandwich-272.yml b/.github/workflows/cleanup-sandwich-272.yml new file mode 100644 index 0000000000..036788d294 --- /dev/null +++ b/.github/workflows/cleanup-sandwich-272.yml @@ -0,0 +1,41 @@ +name: Verify cancelled cleanup sandwiches on the PR272 bit word + +on: + push: + pull_request: + workflow_dispatch: + +permissions: + contents: read + +jobs: + certificate: + runs-on: ubuntu-24.04 + timeout-minutes: 45 + strategy: + fail-fast: false + matrix: + python-version: ['3.11', '3.14'] + steps: + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 + with: + persist-credentials: false + - uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7 + with: + python-version: ${{ matrix.python-version }} + - name: Install SymPy and Boost headers + run: | + python3 -m pip install -r research/cleanup-sandwich-272/requirements.txt + sudo apt-get update && sudo apt-get install -y libboost-dev + - name: Fetch the pinned PR272 package + run: | + git fetch --no-tags https://github.com/CrocSwap/integer-mult-bounds 4d23d0ee5682c99b792614bae4bc5330da19ff13 + mkdir -p "$RUNNER_TEMP/base272" + git archive 4d23d0ee5682c99b792614bae4bc5330da19ff13 research/filtered-kernel-target120 | tar -x -C "$RUNNER_TEMP/base272" + - name: Replay PR272, rewrite the 99 sandwiches, check endpoints and banks, reprice and run the finite invoice + run: > + python3 -B research/cleanup-sandwich-272/verify.py + --base "$RUNNER_TEMP/base272/research/filtered-kernel-target120" + --boost-include /usr/include --output "$RUNNER_TEMP/cleanup-sandwich-272" + - name: Require committed files to remain unchanged + run: git diff --exit-code diff --git a/research/cleanup-sandwich-272/NOTICE b/research/cleanup-sandwich-272/NOTICE new file mode 100644 index 0000000000..3ee961c591 --- /dev/null +++ b/research/cleanup-sandwich-272/NOTICE @@ -0,0 +1,18 @@ +Cancelling cleanup sandwiches on #272's word, 10 October 2026 +Copyright 2026 evmckinney9. Apache-2.0. + +The construction was found and first checked with OpenAI Codex (GPT-6 Astra) assistance; the package and its +independent replay were prepared with Anthropic Claude assistance. The contribution is the +three-gate cancellation that ends 99 cleanup helpers at dimension 4, their shortened completed endpoints and bank +re-tiling, and their verification. No priority over concurrent work is claimed. + +Credits for what this package uses: + +- Dugongue: #272, frame-filtered collective kernels and target-prefix sharing; its word and package are the pinned + base. Also #259, multi-cut kernel condensation, and #254, response-kernel entrance gauges. +- rohanarun (Rohan Arun): #263, concave-descent retiming, which #272 composes. +- eumemic: #249, transported entrances, and the source527 five-stage construction it extends. +- Douglas Colkitt: the completed-core bank scheduling supplement (research/community-round8-audit/BANK-SCHEDULE.md). +- The contributors credited in #272's NOTICE.md, whose work the base package carries. + +All inherited licenses, notices and assistance disclosures remain in force and unchanged. diff --git a/research/cleanup-sandwich-272/PROOF.md b/research/cleanup-sandwich-272/PROOF.md new file mode 100644 index 0000000000..8f196bee5b --- /dev/null +++ b/research/cleanup-sandwich-272/PROOF.md @@ -0,0 +1,49 @@ +# Cancelling cleanup sandwiches: argument and scope + +**Setting.** This is the five-stage bit word of Dugongue's #272: frame-filtered collective kernels and target-prefix +sharing on Dugongue's #259 multi-cut kernel condensation of eumemic's #249 transported entrances. Payload arithmetic is over F2. Address geometry is over +Q with the form G = 9I − J on the 24 local coordinates; a frame is a nondegenerate subspace with projector +P = B^T (B G B^T)^{-1} B G. Every register's chain is charged per stage by its frame increments, and completed +endpoints are banked by the inherited completed-core identity (research/community-round8-audit/BANK-SCHEDULE.md). + +**The sandwich.** Let c be the first kernel cut of #272's word. A helper a is selected when every gate on a after c +is one of exactly three, in this order, + + t += a, a += b, t += a, + +and no gate strictly between the first and the third uses t as a control. No selected helper is the source or +target of another selected helper. + +**Scalar identity.** Write a_0 and b_1 for the values of a and b just before the middle gate. The three gates add +a_0 + (a_0 + b_1) = b_1 to t and leave a = a_0 + b_1. Since t is not a control in between, delaying or advancing what +t receives does not change any other register. The rewrite performs a += b at c and t += b at the middle position. +It agrees with the original whenever b at c equals b_1 and a is not read between c and the middle gate. These side +conditions are not assumed: `sandwich272.py` replays all 20,107 formal columns (sources, targets and arbitrary +dirty helpers) over F2 and requires every register to end as itself and every target as itself plus its source. +Omitting either new gate makes the replay fail on 99 rows. + +**Frames.** At c, a and b sit at frames S_a and S_b. The early gate runs at F = S_a + S_b, which has dimension 4 for +every selected helper and a nonsingular Gram matrix for 9I − J (checked modulo 1000003, which implies rank 4 over +Q). Every new adjacent pair of frames is checked for exact rational inclusion. The middle gate keeps its inherited +frame. After c the helper has no gate, so its chain ends at F: the inherited cleanup climb from dimension 4 to 24 is +not needed. #272's independent legality checker accepts the new word with these final frames. + +**Endpoints.** Each selected helper enters at a rank-one gauge S and now ends at F with P_S P_F = P_F P_S = P_S. Its +completed relative endpoint is therefore the partial swap D_(P_F − P_S), of rank 3, on arbitrary contents, by the +same identity that #186 and BANK-SCHEDULE.md use for completed cores. Its bank residual changes from width 23 to +width 3. Over #272's 120 replicas this frees 11,880 width-23 slots: 2,970 banks [23^4, 4^7] are dissolved, their +20,790 width-4 blocks fill 693 banks [4^30], and the 11,880 width-3 residuals fill 297 banks [3^40]. Each stage has +1,980 fewer banks. #272's own bank review charges every role 24 − dim(entrance), as if each chain ended at full; +this re-tiling is the only step that accounts for the shorter chains, and `endpoints272.py` checks it exactly. +`endpoints272.py` gives every new endpoint and connector an exact chart within #259's bound of 548 elementary +factors (below #272's normalizer ceiling), with all entries below 2^80, so the inherited prime admission applies. + +**Accounting.** Per helper the histogram loses two rank-21 steps and gains two rank-1 steps and one rank-20 step: +the rank mass falls by 20. With the stock falling by the same amount through the banks, the deficit is unchanged. +The new word is priced by #272's unchanged exact engine and 47-constraint assembly, which first reproduces its own +baseline. #272's finite invoice and fixed-prime refinement run on the new word and bank inventory. + +**Scope.** Proved by hand: the three-gate identity above. Computer, exact: the formal F2 replay, frame +nondegeneracy and inclusions, endpoint ranks and charts, bank tiling, price and finite invoice. Every all-size +interface that #272 retains stays an assumption, and #272's inherited audits are relied on, not repeated. No claim +is made that 99 is the largest such set. diff --git a/research/cleanup-sandwich-272/README.md b/research/cleanup-sandwich-272/README.md new file mode 100644 index 0000000000..2c93bac8b2 --- /dev/null +++ b/research/cleanup-sandwich-272/README.md @@ -0,0 +1,73 @@ +# Cancelling cleanup sandwiches on #272's word + +Under the interfaces retained by #272, this package certifies + + T(n) = O(n (log n)^(1 - κ)), κ = 713662156389609974540991/10^27 = 7.13662156389610e-4 + +That is +0.223% over #272 (712074434532274423885827/10^27 = 7.12074434532274e-4). The package adds this directory +and one workflow; no existing file changes. + +## What changes + +**Idea.** Some helpers climb to the full frame only to take part in cleanup. When that part is redundant, here the F2 +identity `t += a; a += b; t += a = a += b; t += b`, the climb can be removed: 99 helpers in #272's word stop at +dimension 4 instead of 24, saving two rank-21 climbs each and shrinking their banked endpoints from rank 23 to rank 3. + +After #272's first kernel cut, 99 helpers appear in exactly three gates, all in the full-frame cleanup: + + t += a, a += b, t += a (F2) + +with t never a control between the first and the last. Over F2 these three gates equal `a += b; t += b`. This package +moves `a += b` to the first cut, where a and b already sit at frames whose sum is a nondegenerate four-dimensional +frame, and keeps `t += b` at the position of the middle gate. Nothing else in the word moves. [PROOF.md](PROOF.md) +gives the argument and its scope. + +| | normalized stock | coarse bit saving | κ | +|---|---|---|---| +| #272 | 519,887 | 712581842140497/10^18 | 712074434532274423885827/10^27 | +| this package | 517,907 | 714171830081841/10^18 | **713662156389609974540991/10^27** | + +Per helper the child histogram loses two rank-21 climbs and gains two rank-1 steps and one rank-20 step, so the +rank mass falls by 20 per helper. Over #272's 120 replicas the banks re-tile with 1,980 fewer banks per stage. The +deficit is unchanged and the bit supplier still binds. + +## Verify + + python3 -m pip install sympy==1.14.0 + git fetch https://github.com/CrocSwap/integer-mult-bounds 4d23d0ee5682c99b792614bae4bc5330da19ff13 + git archive 4d23d0ee5682c99b792614bae4bc5330da19ff13 research/filtered-kernel-target120 | tar -x -C /tmp/base272 + python3 -B research/cleanup-sandwich-272/verify.py --base /tmp/base272/research/filtered-kernel-target120 \ + --boost-include /usr/include --output /tmp/cleanup-sandwich-272 + +About 8 minutes; 7 of them are #272's own replay. `verify.py` runs these checks: + +1. The base package matches `SOURCE.json`: its manifest hash and every file the manifest lists. +2. #272's own `verify.py` regenerates the base word from its pinned sources and passes; word hash and κ are pinned. +3. Every frozen helper has exactly the sandwich after the cut. Each new frame is nondegenerate for 9I − J, each new + connector is an exact rational inclusion, and the F2 replay of all 20,107 formal source, target and dirty + columns is the identity. Omitting either new gate is rejected. +4. #272's native checkers, compiled from its pinned sources and unchanged, check the new word: frame legality, + multi-cut prefix kernels, bank charts and role census, and five-stage columns. +5. Each shortened endpoint is the rank-3 projector difference P_F − P_S, with an exact chart, and the bank review + is re-tiled exactly for the shortened residuals. +6. Every new frame, connector and endpoint has an exact chart within the chart-factor bound, entries below 2^80. +7. #272's price engine reproduces its baseline and prices the new word (47 strict constraints, adjacent grid point + rejected); #272's finite invoice and fixed-prime refinement pass. +8. All results equal `expected.json`. + +## Files + +- `sandwich272.py`: the rewrite, the new frames and the F2 formal replay. +- `endpoints272.py`: shortened endpoints, bank re-tiling and normalizer charts (exact, SymPy). +- `selection.json`: the 99 helpers. `SOURCE.json`: the pinned base. `expected.json`: the certified values. + +## Limits + +- This is a finite conditional construction. Every interface #272 retains (all-size compiler, common weighted + chart, restored rows, routing, prime supply, precision and recovery, analytic reduction) stays an assumption. +- #272's bank review charges every role as if its chain ended at full; the re-tiling for the 99 shorter chains is + done and checked here, not by that tool. +- The 99 helpers were found by a frame-dimension screen of the cleanup suffix. Verification does not use the + screen; it checks the frozen list. No claim is made that 99 is the largest such set. + +Credits are in [NOTICE](NOTICE). diff --git a/research/cleanup-sandwich-272/SOURCE.json b/research/cleanup-sandwich-272/SOURCE.json new file mode 100644 index 0000000000..0b93a93d6e --- /dev/null +++ b/research/cleanup-sandwich-272/SOURCE.json @@ -0,0 +1,11 @@ +{ + "base_pr": 272, + "repository": "https://github.com/CrocSwap/integer-mult-bounds", + "commit": "4d23d0ee5682c99b792614bae4bc5330da19ff13", + "package": "research/filtered-kernel-target120", + "manifest_sha256": "c235b9c0bd17a369fa6fd6c936ea8bf17bbb8085bca65e2bf2b3530c44fcb199", + "word_sha256": "3b097edfe0d0178749efcee6f51edc9284b17881317ed0eb84a32c29f66858e9", + "status": "PASS_NINE_NATIVE_CHECKERS_EXACT_RETIMING_AND_PINNED_RECEIPTS", + "kappa": "712074434532274423885827/1000000000000000000000000000", + "lineage": "#272 (Dugongue) builds on #259 (Dugongue), which extends #249 (eumemic)." +} diff --git a/research/cleanup-sandwich-272/endpoints272.py b/research/cleanup-sandwich-272/endpoints272.py new file mode 100644 index 0000000000..e4e90d7fb3 --- /dev/null +++ b/research/cleanup-sandwich-272/endpoints272.py @@ -0,0 +1,153 @@ +"""Exact rational checks of the shortened endpoints, the bank tiling and the new normalizers (SymPy). + +Address geometry is over Q with G = 9I - J; a frame with row basis B has projector P = B^T (B G B^T)^-1 B G. + +`banks`: each retired helper keeps its rank-one entrance S and now ends at its four-dimensional frame F. Since +P_S P_F = P_F P_S = P_S, its completed relative endpoint is the partial swap D_(P_F - P_S) of rank 3, by the +inherited completed-core identity (research/community-round8-audit/BANK-SCHEDULE.md). Its bank residual therefore +changes from width 23 to width 3. The width-120 bank patterns are re-tiled and must fill every slot exactly. + +`normalizers`: every new frame Gram matrix, every connector that touches a new frame and every new endpoint has an +exact chart reducing it to a coordinate projector by elementary factors, all with numerator and denominator below +2^80. Their nonzero factors are units modulo every admissible prime, as for the inherited charts. +""" +from collections import Counter +from fractions import Fraction as Q +import json +import struct + +import sympy as sp + +H = 24 +BOUND = 2 ** 80 +MAX_FACTORS = 548 # #259's chart-factor bound, below #272's normalizer ceiling +G = 9 * sp.eye(H) - sp.ones(H) + + +def frames_of(export, lead, new_frames): + def load(p): return json.loads(p.read_text()) + frames = load(export / 'frames.json')['frames'] + frames.update(load(lead / 'COHORT249-FRAMES.json')) + frames.update(new_frames) + return frames + + +def projector(frames, f): + d = frames[str(f)]['dim'] + if d == H: + return sp.eye(H), None + if d == 0: + return sp.zeros(H), None + B = sp.Matrix(frames[str(f)]['B']) + gram = B * G * B.T + return B.T * gram.inv() * B * G, gram + + +def chart(E, rank, guard): + """Exact chart C with C^-1 E C = diag(1^rank, 0); returns (C, C^-1, elementary factor count).""" + C = sp.Matrix.hstack(*E.columnspace(), *E.nullspace()) + inverse = C.inv() + assert inverse * E * C == sp.diag(*([1] * rank + [0] * (H - rank))), 'chart does not normalize the projector' + guard(list(E) + list(C) + list(inverse) + [C.det()]) + A = [[Q(x) for x in C.row(i)] for i in range(H)] + factors = 0 + for j in range(H): + k = next(k for k in range(j, H) if A[k][j]) + if k != j: + A[j], A[k] = A[k], A[j] + factors += 1 + pivot = A[j][j] + guard([pivot, 1 / pivot]) + if pivot != 1: + A[j] = [x / pivot for x in A[j]] + factors += 1 + for i in range(H): + if i != j and A[i][j]: + c = A[i][j] + guard([c]) + A[i] = [x - c * y for x, y in zip(A[i], A[j])] + factors += 1 + assert A == [[Q(i == j) for j in range(H)] for i in range(H)] + assert factors <= MAX_FACTORS, 'chart exceeds the inherited factor bound' + return C, inverse, factors + + +def make_guard(): + state = {'max': 1} + + def guard(values): + for value in values: + x = Q(value) + state['max'] = max(state['max'], abs(x.numerator), x.denominator) + assert state['max'] < BOUND, 'normalizer entry exceeds 2^80' + return guard, state + + +def banks(export, lead, new_frames, receipt, bank): + """Shortened endpoints are rank-3 partial swaps; re-tile the base bank review and return the new inventory. + + The base bank review charges each role the residual 24 - dim(entrance), as if every chain ended at full. A + retired helper ends at its four-dimensional frame instead, so its residual is 3, not 23. With R replicas, R*k + width-23 slots become width-3 slots: R*k/4 banks [23]*4 + [4]*7 are dissolved, their width-4 blocks refill + 7*R*k/120 banks [4]*30, and the width-3 residuals fill R*k/40 banks [3]*40. + """ + frames = frames_of(export, lead, new_frames) + guard, state = make_guard() + for e in receipt['edits']: + assert frames[str(e['entrance_frame'])]['dim'] == 1 + S, _ = projector(frames, e['entrance_frame']) + F, _ = projector(frames, e['frame']) + assert S * F == F * S == S, 'entrance is not inside the new exit frame' + E = F - S + assert E * E == E and E.rank() == 3 + chart(E, 3, guard) + k = len(receipt['edits']) + family = Counter({int(r): c for r, c in bank['residual_families'].items()}) + patterns = [dict(p) for p in bank['bank_patterns']] + slots = Counter() + for p in patterns: + for r in p['widths']: + slots[r] += p['count'] + R = slots[23] // family[23] + assert all(slots[r] == R * c for r, c in family.items() if c), 'replica count is not uniform' + assert R * k % 120 == 0, 'width-4 blocks do not refill whole banks' + dissolve, refill, added = R * k // 4, 7 * R * k // 120, R * k // 40 + next(p for p in patterns if p['widths'] == [23] * 4 + [4] * 7)['count'] -= dissolve + next(p for p in patterns if p['widths'] == [4] * 30)['count'] += refill + patterns.append({'widths': [3] * 40, 'count': added}) + family[23] -= k + family[3] += k + slots, count = Counter(), 0 + for p in patterns: + assert p['count'] >= 0 and sum(p['widths']) == 120, 'bank pattern does not fill width 120' + count += p['count'] + for r in p['widths']: + slots[r] += p['count'] + assert slots == Counter({r: R * c for r, c in family.items() if c}), 'residuals do not tile the banks exactly' + saved = dissolve - refill - added + stock = bank['literal_stock'] - 5 * saved + new = dict(bank, bank_patterns=patterns, residual_families={str(r): c for r, c in sorted(family.items()) if c}, + banks_per_stage=bank['banks_per_stage'] - saved, literal_stock=stock, normalized_stock=stock // 5, + saved_literal_banks=bank['saved_literal_banks'] + 5 * saved, + selector_charge=2 * 5 * R * ((stock - 1) + 16587 * R * bank['normalizer_factor_ceiling'])) + return new, {'replicas': R, 'banks_saved_per_stage': saved, 'endpoint_max_entry': state['max']} + + +def normalizers(export, lead, new_frames, records, receipt): + """Charts for every new frame, every connector touching a new frame and every new endpoint.""" + frames = frames_of(export, lead, new_frames) + guard, state = make_guard() + for f in new_frames: + _, gram = projector(frames, f) + guard(list(gram) + list(gram.inv()) + [gram.det()]) + pairs = {(b, c, r) for op, a, b, c, r, z in struct.iter_unpack('<6i', records) + if op == 0 and (str(b) in new_frames or str(c) in new_frames)} + moves = len(pairs) + pairs |= {(e['entrance_frame'], e['frame'], 3) for e in receipt['edits']} + most = 0 + for before, after, rank in sorted(pairs): + E = projector(frames, after)[0] - projector(frames, before)[0] + assert E * E == E and E.rank() == rank, ('connector is not a projector of its rank', before, after) + most = max(most, chart(E, rank, guard)[2]) + return {'new_frames': len(new_frames), 'move_pairs': moves, 'charts': len(pairs), + 'max_factors': most, 'max_numerator_denominator': state['max']} diff --git a/research/cleanup-sandwich-272/expected.json b/research/cleanup-sandwich-272/expected.json new file mode 100644 index 0000000000..6fa9ad19c7 --- /dev/null +++ b/research/cleanup-sandwich-272/expected.json @@ -0,0 +1,14 @@ +{ + "base_kappa": "712074434532274423885827/1000000000000000000000000000", + "deficit": 105600, + "exact_price_kappa": "356831076214141/500000000000000000", + "helpers_retired": 99, + "histogram_delta": { + "1": 198, + "20": 99, + "21": -198 + }, + "kappa": "713662156389609974540991/1000000000000000000000000000", + "stock": 517907, + "word_sha256": "0c4d8262996622a8e36b3c0db1e712d868e7c35d13d7848508176efaa3754473" +} diff --git a/research/cleanup-sandwich-272/requirements.txt b/research/cleanup-sandwich-272/requirements.txt new file mode 100644 index 0000000000..1ca5fd0616 --- /dev/null +++ b/research/cleanup-sandwich-272/requirements.txt @@ -0,0 +1 @@ +sympy==1.14.0 diff --git a/research/cleanup-sandwich-272/sandwich272.py b/research/cleanup-sandwich-272/sandwich272.py new file mode 100644 index 0000000000..9d9b98f4ae --- /dev/null +++ b/research/cleanup-sandwich-272/sandwich272.py @@ -0,0 +1,194 @@ +"""Remove the cleanup sandwich of 99 helpers in #272's word and check the result on every formal column. + +For a selected helper a, the suffix of the word after the first cut contains exactly three gates on a: + + t += a, a += b, t += a (F2, in this order) + +and t is not a control strictly between the first and the last. Over F2 the three gates equal + + a += b, t += b. + +`rewrite` moves a += b to the first cut, at the common frame of a and b there, and replaces the middle gate by +t += b at its original position and frame. The helper then has no gate after the cut. It stops at the new +four-dimensional frame instead of climbing to the full frame for cleanup. The emitted word is checked over F2 on +every source, target and dirty column, so the side conditions (b unchanged on the interval, no other use of a) are +verified, not assumed. +""" +from collections import Counter +from fractions import Fraction as Q +from hashlib import sha256 +import json +from math import lcm +import struct + +H = 24 # local address dimension +PRIME = 1000003 # Gram ranks are computed modulo this prime: full rank mod p implies full rank over Q +SANDWICH, EARLY = 32, 33 # tags on the two new gates, used by the omission controls + + +def rational_basis(rows): + """Reduced integer basis of the rational row space.""" + basis = {} + for values in rows: + row = list(map(Q, values)) + for p, b in sorted(basis.items()): + if row[p]: + row = [x - row[p] * y for x, y in zip(row, b)] + p = next((i for i, x in enumerate(row) if x), None) + if p is not None: + basis[p] = [x / row[p] for x in row] + out = [] + for _, row in sorted(basis.items()): + d = lcm(*(x.denominator for x in row)) + out.append([int(x * d) for x in row]) + return out + + +def rank_mod_prime(rows): + basis = {} + for row in rows: + row = [x % PRIME for x in row] + for p, b in sorted(basis.items()): + if row[p]: + c = row[p] + row = [(x - c * y) % PRIME for x, y in zip(row, b)] + p = next((i for i, x in enumerate(row) if x), None) + if p is not None: + inv = pow(row[p], -1, PRIME) + basis[p] = [x * inv % PRIME for x in row] + return len(basis) + + +def annihilator(B): + """Rational basis of {x : B x = 0} for a reduced basis B.""" + pivots = [next(i for i, x in enumerate(row) if x) for row in B] + out = [] + for free in sorted(set(range(H)) - set(pivots)): + v = [Q(i == free) for i in range(H)] + for p, row in reversed(list(zip(pivots, B))): + v[p] = -sum(Q(row[j]) * v[j] for j in range(p + 1, H)) / row[p] + out.append([str(x) for x in v]) + return out + + +def histogram(records): + h = Counter() + for op, a, b, c, f, z in records: + if op == 0 and f: + h[f] += 1 + elif op == 2: + h[z] += 1 + return h + + +def rewrite(export, lead, helpers): + """Return (records, new frames, receipt) for the frozen helpers; export and lead are base replay directories.""" + def load(p): return json.loads(p.read_text()) + frames = load(export / 'frames.json')['frames'] + frames.update(load(lead / 'COHORT249-FRAMES.json')) + states = load(export / '249-states.json') + initial = {int(a): f for a, f in load(lead / 'COHORT249-INITIAL.json').items()} + blob = (lead / 'COHORT249-RECORDS.bin').read_bytes() + old = list(struct.iter_unpack('<6i', blob)) + n, v = states['n'], states['v'] + + # Frames of every register at the first cut (the first kernel cut record). + cut = next(i for i, r in enumerate(old) if r[0] == 1 and r[5] == 3) + at_cut = dict(initial) + for op, a, b, c, f, z in old[:cut]: + if op == 1: + at_cut[a] = at_cut[b] = f + elif op == 2: + at_cut[a], at_cut[b] = c, f + elif op == 3: + del at_cut[b] + + edits, skip, replace, new_frames = [], set(), {}, {} + for a in helpers: + gates = [(i, r) for i, r in enumerate(old) if i >= cut and r[0] == 1 and a in r[1:3]] + assert len(gates) == 3, ('helper must have exactly three gates after the cut', a) + (first, x), (middle, y), (last, w) = gates + t, b = x[1], y[2] + assert x[2] == a and y[1] == a and w[1:3] == (t, a), ('not a sandwich t+=a, a+=b, t+=a', a) + assert all(r[0] != 1 or r[2] != t for r in old[first + 1:last]), ('t is a control inside the sandwich', a) + assert b not in helpers and t not in helpers, ('overlapping sandwiches', a) + B = rational_basis(frames[str(at_cut[a])]['B'] + frames[str(at_cut[b])]['B']) + assert len(B) == 4, ('the joint frame of a and b at the cut is not four-dimensional', a) + sums = [sum(u) for u in B] + gram = [[9 * sum(p * q for p, q in zip(u, w)) - su * sw for w, sw in zip(B, sums)] for u, su in zip(B, sums)] + assert rank_mod_prime(gram) == 4, ('new frame is degenerate for 9I - J', a) + frame = 600000 + len(new_frames) + assert str(frame) not in frames + frames[str(frame)] = new_frames[str(frame)] = {'dim': 4, 'B': B, 'A': annihilator(B)} + skip.update((first, last)) + replace[middle] = (1, t, b, y[3], y[4], SANDWICH) + edits.append({'helper': a, 'source': b, 'target': t, 'frame': frame, + 'old_indices': [first, middle, last], 'entrance_frame': initial[a]}) + + # Re-emit the word with explicit frame moves; every new connector is checked for exact rational inclusion. + state, new, checked = dict(initial), [], set() + inherited = {(b, c) for op, a, b, c, f, z in old if op == 0} + + def move(a, f): + before = state[a] + if before == f: + return + if (before, f) not in inherited and (before, f) not in checked: + B, A = frames[str(before)]['B'], frames[str(f)]['A'] + assert all(sum(Q(p) * Q(q) for p, q in zip(u, w)) == 0 for u in B for w in A), ('not nested', before, f) + checked.add((before, f)) + rank = frames[str(f)]['dim'] - frames[str(before)]['dim'] + assert rank >= 0, ('frame retreats', a, before, f) + new.append((0, a, before, f, rank, 0)) + state[a] = f + + def emit(r): + op, a, b, c, f, z = r + if op == 1: + move(a, f) + move(b, f) + elif op == 2: + move(a, c) + state[b] = f + elif op == 3: + assert state[a] == c and state[b] == f + del state[b] + new.append(r) + + for i, r in enumerate(old): + if i == cut: + for e in edits: + emit((1, e['helper'], e['source'], 1, e['frame'], EARLY)) + if r[0] != 0 and i not in skip: + emit(replace.get(i, r)) + final = {int(a): f for a, f in states['final'].items()} + final.update({e['helper']: e['frame'] for e in edits}) + for a in range(n): + move(a, final[a]) + + def wrong_rows(records, omit=None): + """F2 formal replay: every register must end as itself, every target as itself plus its source.""" + rows = [1 << a for a in range(n)] + [0] + for op, a, b, c, f, z in records: + if op == 1 and c % 2 and z != omit: + rows[a] ^= rows[b] + elif op == 2: + rows[b] = rows[a] + elif op == 3: + assert rows[a] == rows[b] + rows[b] = 0 + return sum(rows[a] != ((1 << a) ^ ((1 << (a - v)) if v <= a < 2 * v else 0)) for a in range(n)) + + assert wrong_rows(new) == 0, 'rewritten word fails the formal replay' + controls = {'omit early a += b': wrong_rows(new, EARLY), 'omit sandwich t += b': wrong_rows(new, SANDWICH)} + assert all(controls.values()), 'an omission control was accepted' + delta = histogram(new) + delta.subtract(histogram(old)) + assert sum(r * c for r, c in delta.items()) == -20 * len(edits), 'endpoint rank mass must drop by 20 per helper' + data = b''.join(struct.pack('<6i', *r) for r in new) + receipt = {'helpers_retired': len(edits), 'input_sha256': sha256(blob).hexdigest(), + 'output_sha256': sha256(data).hexdigest(), 'formal_columns': n, + 'omission_controls_wrong_rows': controls, 'new_connectors_checked': len(checked), + 'new_frames': len(new_frames), 'histogram_delta': {str(r): c for r, c in sorted(delta.items()) if c}, + 'endpoint_rank_mass_drop': 20 * len(edits), 'edits': edits} + return data, new_frames, receipt diff --git a/research/cleanup-sandwich-272/selection.json b/research/cleanup-sandwich-272/selection.json new file mode 100644 index 0000000000..fb42022071 --- /dev/null +++ b/research/cleanup-sandwich-272/selection.json @@ -0,0 +1,103 @@ +{ + "helpers": [ + 10131, + 10135, + 10159, + 10163, + 10175, + 10179, + 10183, + 10191, + 10199, + 10215, + 10231, + 10243, + 10255, + 10259, + 10263, + 10271, + 10283, + 10291, + 10299, + 10303, + 10307, + 10311, + 10319, + 10323, + 10339, + 10351, + 10355, + 10359, + 10371, + 10383, + 10387, + 10415, + 10427, + 10443, + 10447, + 10459, + 10463, + 10467, + 10471, + 10479, + 10491, + 10495, + 10511, + 10519, + 10527, + 10531, + 10555, + 10559, + 10575, + 10583, + 10595, + 10603, + 10611, + 10647, + 10663, + 10667, + 10675, + 10679, + 10687, + 10695, + 10703, + 10707, + 10715, + 10727, + 10735, + 10747, + 10759, + 10763, + 10767, + 10771, + 10779, + 10783, + 10791, + 10795, + 10803, + 10807, + 10815, + 10823, + 10831, + 10843, + 10851, + 10855, + 10863, + 10871, + 10875, + 10883, + 10887, + 10891, + 10911, + 10915, + 10919, + 10927, + 10943, + 10959, + 10967, + 10971, + 10987, + 10991, + 10995 + ] +} diff --git a/research/cleanup-sandwich-272/verify.py b/research/cleanup-sandwich-272/verify.py new file mode 100644 index 0000000000..0b435031a4 --- /dev/null +++ b/research/cleanup-sandwich-272/verify.py @@ -0,0 +1,185 @@ +#!/usr/bin/env python3 +"""Verify the cleanup-sandwich rewrite of 99 helpers on #272's word (SymPy 1.14.0, g++ with C++17, Boost headers). + + 1. Pins. The base package (#272, research/filtered-kernel-target120) matches SOURCE.json: its MANIFEST.json hash + and every file it lists. + 2. Base replay. #272's own verify.py regenerates the word from its pinned sources, compiles its nine native + checkers and passes (about 7 minutes). Its final word hash and kappa equal SOURCE.json. With --replay, an + existing completed base replay is accepted after the same checks. + 3. Rewrite (sandwich272.py). Each of the 99 frozen helpers has exactly the gates t += a, a += b, t += a after the + first cut, with t not a control between them. The rewritten word moves a += b to the cut at a new + four-dimensional frame and keeps t += b. Every new frame is nondegenerate for 9I - J and every new connector + is an exact rational inclusion. The F2 replay of all formal source, target and dirty columns is the + identity, and omitting either new gate is rejected. + 4. #272's native checkers, unchanged, on the new word: independent frame legality, multi-cut prefix kernels, + the generic bank charts and role census, and the five-stage columns. + 5. Endpoints and banks (endpoints272.banks). Each shortened endpoint is the rank-3 partial swap D_(P_F - P_S), + with an exact chart, and the bank review is re-tiled exactly for the shortened residuals. + 6. Normalizers (endpoints272.normalizers). Exact charts for every new frame, connector and endpoint, below the + chart-factor bound and with entries below 2^80. + 7. #272's price engine reproduces its baseline, then prices the new histogram at the re-tiled stock: 47 strict + constraints positive and the adjacent grid point rejected. #272's finite invoice and fixed-prime refinement + pass on the new word and bank inventory. + 8. The results equal expected.json. + +Usage: python3 -B research/cleanup-sandwich-272/verify.py --base PKG --boost-include DIR --output NEW_DIR [--replay DIR] + PKG is research/filtered-kernel-target120 from a checkout of commit 4d23d0ee (#272). +""" +import sys + +if sys.flags.optimize: + raise SystemExit('Assertions must remain enabled: run without -O') + +import argparse +from fractions import Fraction as Q +from hashlib import sha256 +import json +from math import lcm +from pathlib import Path +import shutil +import subprocess +import time + +HERE = Path(__file__).resolve().parent +sys.path.insert(0, str(HERE)) +import endpoints272 +import sandwich272 + +T0 = time.time() +SOURCE = json.loads((HERE / 'SOURCE.json').read_text()) +EXPECT = json.loads((HERE / 'expected.json').read_text()) + + +def log(*a): + print('[%5.0fs]' % (time.time() - T0), *a, flush=True) + + +def digest(p): + return sha256(p.read_bytes()).hexdigest() + + +def load(p): + return json.loads(p.read_text()) + + +def save(p, value): + p.write_text(json.dumps(value, indent=2, sort_keys=True) + '\n') + + +def run(cmd, logfile): + with logfile.open('w') as out: + subprocess.run(list(map(str, cmd)), stdout=out, stderr=subprocess.STDOUT, check=True) + + +def main(): + ap = argparse.ArgumentParser(description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter) + ap.add_argument('--base', type=Path, required=True) + ap.add_argument('--boost-include', type=Path, required=True) + ap.add_argument('--output', type=Path, required=True) + ap.add_argument('--replay', type=Path) + ap.add_argument('--cxx', default='g++') + args = ap.parse_args() + base, out = args.base.resolve(), args.output.resolve() + assert not out.exists() and not out.is_relative_to(HERE), 'output must be a new directory outside the package' + + # 1. Pins. + assert digest(base / 'MANIFEST.json') == SOURCE['manifest_sha256'], 'base MANIFEST.json differs from SOURCE.json' + for name, h in load(base / 'MANIFEST.json')['files'].items(): + assert digest(base / name) == h, ('base file differs from its manifest', name) + log('PASS pins: base package', SOURCE['commit'][:8], 'matches SOURCE.json') + out.mkdir(parents=True) + + # 2. Base replay. + if args.replay: + replay = args.replay.resolve() + else: + replay = out / 'base' + run([sys.executable, '-B', base / 'verify.py', '--output', replay, '--boost-include', args.boost_include.resolve(), + '--cxx', args.cxx], out / 'base.log') + certificate = load(replay / 'CERTIFICATE.json') + assert certificate['status'] == SOURCE['status'] and certificate['kappa'] == SOURCE['kappa'], 'base replay differs' + export, lead, binary = replay / 'temporal/CURRENT249-EXPORT', replay / 'targeted', replay / 'bin' + assert digest(lead / 'COHORT249-RECORDS.bin') == SOURCE['word_sha256'], 'base word differs from SOURCE.json' + log('PASS base replay: kappa', certificate['kappa']) + + # 3. Rewrite. + records, new_frames, receipt = sandwich272.rewrite(export, lead, load(HERE / 'selection.json')['helpers']) + log('PASS rewrite: %d helpers, %d formal columns, controls %s, histogram delta %s' % ( + receipt['helpers_retired'], receipt['formal_columns'], receipt['omission_controls_wrong_rows'], + receipt['histogram_delta'])) + + # The new word in the base layout: final frames, frame table, records and the price input. + X, L, C, T, V = out / 'export', out / 'lead', out / 'compiler', out / 'temporal', out / 'review' + shutil.copytree(export, X) + for d in (L, C, T, V): + d.mkdir() + for name in ('COHORT249-INITIAL.json', 'COHORT249-SELECTION.json'): + shutil.copyfile(lead / name, L / name) + states = load(X / '249-states.json') + states['final'].update({str(e['helper']): e['frame'] for e in receipt['edits']}) + save(X / '249-states.json', states) + frames = load(lead / 'COHORT249-FRAMES.json') + for f, spec in new_frames.items(): + rows = [] + for row in spec['A']: + q = [Q(x) for x in row] + d = lcm(*(x.denominator for x in q)) + rows.append([int(x * d) for x in q]) + frames[f] = dict(spec, A=rows) + save(L / 'COHORT249-FRAMES.json', frames) + (L / 'COHORT249-RECORDS.bin').write_bytes(records) + + # 4. Native checkers of the base, unchanged. + run([binary / 'cohort-legality-independent', X, L, V / 'INDEPENDENT-LEGALITY.json'], out / 'legality.log') + run([binary / 'cohort-prefix-independent', X, L, V / 'INDEPENDENT-PREFIX.json'], out / 'prefix.log') + run([binary / 'cohort-bank-review', X, L / 'COHORT249-INITIAL.json', L / 'COHORT249-FRAMES.json', C, + 'actual_multicut120'], out / 'bank-review.log') + run([binary / 'cohort-five-stage-columns', L / 'COHORT249-RECORDS.bin', T / 'COHORT-FIVE-STAGE-COLUMNS.json'], + out / 'columns.log') + log('PASS native legality, prefix kernels, bank charts and five-stage columns') + + # 5-6. Endpoints, banks and normalizers. + bank, bank_receipt = endpoints272.banks(export, lead, new_frames, receipt, load(C / 'BANK-REVIEW.json')) + save(C / 'COHORT-BANK-REVIEW.json', bank) + log('PASS endpoints and banks: %d replicas, %d banks saved per stage, literal stock %d' % ( + bank_receipt['replicas'], bank_receipt['banks_saved_per_stage'], bank['literal_stock'])) + norm = endpoints272.normalizers(export, lead, new_frames, records, receipt) + log('PASS normalizers: %d charts, at most %d factors, max entry %d' % ( + norm['charts'], norm['max_factors'], norm['max_numerator_denominator'])) + + # 7. Price, finite invoice and fixed prime. #272's price main charges stock 521649 - new_entrance_rank; the + # re-tiled banks lower the normalized stock by 20 per helper, which is passed through that field. + replay_summary = load(lead / 'COHORT249-REPLAY.json') + histogram, delta = dict(replay_summary['histogram']), dict(replay_summary['delta']) + for r, c in receipt['histogram_delta'].items(): + histogram[r] = histogram.get(r, 0) + c + delta[r] = delta.get(r, 0) + c + saved = (load(C / 'BANK-REVIEW.json')['literal_stock'] - bank['literal_stock']) // 5 + assert saved == 20 * receipt['helpers_retired'] + save(L / 'COHORT249-REPLAY.json', dict(replay_summary, histogram=histogram, delta=delta, + new_entrance_rank=replay_summary['new_entrance_rank'] + saved)) + run([binary / 'cohort-price', L / 'COHORT249-REPLAY.json', L / 'COHORT-EXACT-PRICE.json'], out / 'price.log') + price = load(L / 'COHORT-EXACT-PRICE.json')['cohort_candidate'] + assert price['stock'] * 5 == bank['literal_stock'], 'priced stock differs from the bank inventory' + assert price['positive_constraints'] == 47 and price['next_kappa_rejected'] > 0 + run([binary / 'cohort-finite-invoice', L / 'COHORT249-RECORDS.bin', L / 'COHORT-EXACT-PRICE.json', + C / 'COHORT-BANK-REVIEW.json', T / 'COHORT-FIVE-STAGE-COLUMNS.json', T / 'COHORT-FINITE-INVOICE.json'], + out / 'finite.log') + run([binary / 'fixed-price', L / 'COHORT-EXACT-PRICE.json', T / 'COHORT-FINITE-INVOICE.json', + L / 'FIXED-PRICE.json'], out / 'fixed.log') + fixed = load(L / 'FIXED-PRICE.json') + log('PASS price, finite invoice and fixed prime: kappa', fixed['kappa']) + + # 8. Expected values. + result = {'kappa': fixed['kappa'], 'base_kappa': certificate['kappa'], 'exact_price_kappa': price['kappa'], + 'stock': price['stock'], 'deficit': price['deficit'], 'helpers_retired': receipt['helpers_retired'], + 'histogram_delta': receipt['histogram_delta'], 'word_sha256': receipt['output_sha256']} + assert result == EXPECT, ('results differ from expected.json', result) + save(out / 'CERTIFICATE.json', dict(result, status='PASS conditional finite witness', scope=( + 'Finite rewrite of #272; all-size compiler, analytic and assembly interfaces are those retained by #272.'), + receipts={'rewrite': receipt, 'banks': bank_receipt, 'normalizers': norm})) + log('PASS kappa = %s = %.18e, equal to expected.json' % (fixed['kappa'], float(Q(fixed['kappa'])))) + + +if __name__ == '__main__': + main()