diff --git a/research/selected-word-reject-exhaustion/CERTIFICATE.json b/research/selected-word-reject-exhaustion/CERTIFICATE.json new file mode 100644 index 0000000000..e309665dc5 --- /dev/null +++ b/research/selected-word-reject-exhaustion/CERTIFICATE.json @@ -0,0 +1,98 @@ +{ + "claim": { + "closed_form": "agree iff d not in srcs, or count(d) odd and every non-d has even multiplicity before the last d", + "four_exhaustive_for_len2_divergence": false, + "length2": { + "dest_free": 436261, + "dest_in_agree": 661, + "destination": 111, + "divergences": 661, + "form": "[[d,d]] U [[a,d] : a != d]", + "n_registers": 661, + "total_lists": 437583 + }, + "named_diverge_count": 2, + "named_rejects": { + "dest_with_src": { + "diverges": true, + "in_len2_divergence_set": true, + "srcs": [ + 3, + 111 + ] + }, + "dup_src": { + "diverges": false, + "in_len2_divergence_set": false, + "srcs": [ + 3, + 3 + ] + }, + "self_even": { + "diverges": true, + "in_len2_divergence_set": true, + "srcs": [ + 111, + 111 + ] + }, + "self_once": { + "diverges": false, + "in_len2_divergence_set": false, + "srcs": [ + 111 + ] + } + }, + "small_domain_closed_form": { + "max_len": 5, + "mismatches": 0, + "n": 8 + } + }, + "controls": { + "all_len2_divergences_fail_distinctness": true, + "checker_rejects": [ + "self_even", + "dest_with_src", + "dup_src", + "self_once" + ], + "checker_spot_divergences": [ + [ + 111, + 111 + ], + [ + 0, + 111 + ], + [ + 660, + 111 + ], + [ + 3, + 111 + ] + ] + }, + "kappa_decimal": "0.001672660197076918", + "no_new_kappa": true, + "schema_version": 1, + "selected_word": { + "B0": [ + 127, + 111, + [ + 3 + ] + ], + "gates": 5472, + "n_registers": 661, + "path": "research/e8-bit-p111-tuned/tune/bitE8mut-p111-tuned.json.gz", + "sha256": "e3e301e62bc2b41dbf1ceac0acf3d35824ebeab1848c5a2142d4577b109da52f" + }, + "status": "PASS_SELECTED_WORD_REJECT_EXHAUSTION" +} diff --git a/research/selected-word-reject-exhaustion/PROOF.md b/research/selected-word-reject-exhaustion/PROOF.md new file mode 100644 index 0000000000..65b5dbed62 --- /dev/null +++ b/research/selected-word-reject-exhaustion/PROOF.md @@ -0,0 +1,80 @@ +# Selected-word reject exhaustiveness for length-≤2 dest-in divergence + +## Claim + +Fix the pinned tuned PR589 word +`research/e8-bit-p111-tuned/tune/bitE8mut-p111-tuned.json.gz` and the B[0] +destination `d = 111` (source alphabet size `n = 2v+R = 661`). Compare Sym +(accumulate-XOR from the pre-gate valuation) with Exp (sequential ADD into the +destination, re-reading the current valuation), as linear maps over `F_2`. + +1. **Closed form.** For every finite source list `srcs`, Sym and Exp agree if + and only if either `d ∉ srcs`, or else `count(d)` is odd and every non-`d` + value has even multiplicity in the strict prefix before the last occurrence + of `d`. +2. **Length-≤2 census.** Among all `srcs` of length at most 2 with entries in + `{0,...,660}`, Sym≠Exp on exactly **661** lists: `{[d,d]} ∪ {[a,d] : a ≠ d}`. +3. **Four named rejects are not exhaustive.** The four B[0] checker rejects named + in [#3696](https://github.com/CrocSwap/integer-mult-bounds/pull/3696) + (`self_even`, `dest_with_src`, `dup_src`, `self_once`) contain only **two** + of those 661 divergences (`[d,d]` and `[3,d]`). The other two named rejects + agree under Sym/Exp. Hence the four are not an exhaustive taxonomy of + length-≤2 dest-in-sources divergence on the pinned word. +4. Every length-≤2 divergence has `d ∈ srcs`, so + `len(set([d]+srcs)) < len([d]+srcs)` and the selected checker rejects it with + `bad operands`. Selected kappa is unchanged. + +This is not a restatement of the dest-free Sym/Exp agreement already published +in #3696: the new content is the dest-in closed form, the exact length-≤2 count, +and the negative exhaustiveness answer. + +## Proof of the closed form + +Only register `d` is written. For `s ≠ d`, Exp therefore always reads `val0[s]`. +Reading `s = d` clears the current destination (`out[d] ← out[d] ⊕ out[d] = 0`). + +- If `d ∉ srcs`, every Exp read sees `val0`, so Exp equals Sym. +- If `d ∈ srcs`, let `last` be the last index with `srcs[last] = d`. After that + clear, Exp's destination coefficient is the XOR of the suffix `srcs[last+1:]` + (which contains no `d`). Sym's destination coefficient is + `e_d ⊕ ⨁_s e_s` (multiplicity mod 2). These match if and only if the Sym + coefficient of `d` is `0` — i.e. `count(d)` is odd — and for every `s ≠ d` + the Sym parity equals the suffix parity, i.e. the multiplicity of `s` in + `srcs[:last]` is even. + +## Proof of the length-≤2 census + +Apply the closed form with `len(srcs) ≤ 2`: + +- Length 0 or dest-free length 1–2: agree. +- `[d]`: `count(d)=1` odd, empty prefix → agree. +- `[d,d]`: `count(d)=2` even → disagree. +- `[d,a]` with `a ≠ d`: `count(d)=1`, empty prefix → agree. +- `[a,d]` with `a ≠ d`: `count(d)=1`, prefix `[a]` odd → disagree. +- `[a,a]` with `a ≠ d`: dest-free → agree. + +Hence the disagreeing lists are exactly the `n` lists `[a,d]` for +`a ∈ {0,...,n-1}` (the case `a = d` is `[d,d]`), totaling `n = 661`. Direct +linear enumeration over all `1 + n + n^2` lists confirms the count. + +## Four named rejects + +| name | `srcs` | Sym=Exp? | in the 661? | +|---|---|---|---| +| `self_even` | `[111,111]` | no | yes | +| `dest_with_src` | `[3,111]` | no | yes | +| `dup_src` | `[3,3]` | yes | no | +| `self_once` | `[111]` | yes | no | + +So at most two of the four meet dest-in divergence, against 661 total. The +checker still rejects all four (and all 661 divergences) by operand +distinctness; reject-count is not divergence-count. + +## What this does not claim + +- No new kappa and no production schema change. +- No claim that length ≥ 3 has only 661 divergences. +- No dest-absent schema corollary (left to maintainers; forbidden as a + definitional follow-up in this loop). +- No restatement that dest-free lists always agree beyond using it inside the + closed form. diff --git a/research/selected-word-reject-exhaustion/README.md b/research/selected-word-reject-exhaustion/README.md new file mode 100644 index 0000000000..63e7c1ca6c --- /dev/null +++ b/research/selected-word-reject-exhaustion/README.md @@ -0,0 +1,74 @@ +# Selected-word reject exhaustion for length-≤2 dest-in divergence + +**Card `supplier-boundary-audit`, priority revision 6**, changed to answer +[#3696](https://github.com/CrocSwap/integer-mult-bounds/pull/3696) open question 2 +under the [#2977](https://github.com/CrocSwap/integer-mult-bounds/pull/2977) / +[#3004](https://github.com/CrocSwap/integer-mult-bounds/pull/3004) checker/exporter +cascade. No new kappa (`0.001672660197076918`). + +#3696 showed dest-free gates always make Sym and Exp agree, named dest-in +witnesses that diverge, and four B[0] `bad operands` rejects. Its OQ2 asked +whether those four rejects are exhaustive for dest-in-sources divergence on the +pinned word. They are not. + +This package proves a closed-form Sym/Exp agreement criterion for dest-in lists, +enumerates every source list of length at most 2 at B[0]'s destination `d=111` +over `n=661` registers, and obtains exactly **661** divergences +`{[d,d]} ∪ {[a,d] : a ≠ d}`. Only `self_even` and `dest_with_src` among the four +named rejects lie in that set; `dup_src` and `self_once` agree. Dest-free +agreement is used inside the closed form and is not republished as the claim. + +```sh +python3.12 -I -B research/selected-word-reject-exhaustion/verify.py +``` + +Expected: + +```text +PASS_SELECTED_WORD_REJECT_EXHAUSTION len2_divergences=661 named_diverge=2 four_exhaustive=false no_new_kappa +``` + +## Evidence + +- Closed form matches linear Sym/Exp on all `(d,srcs)` with `n≤8`, `len(srcs)≤5`, + and on the full length-≤2 census at `d=111`. +- Length-≤2 census: **661** divergences, **661** dest-in agreements, total + `1+661+661²` lists. +- Named rejects: diverge `{self_even, dest_with_src}`; agree `{dup_src, self_once}`. +- Checker rejects all four named mutants and spot divergences + `[d,d]`, `[0,d]`, `[660,d]`, `[3,d]` with `bad operands`. +- Every length-≤2 divergence fails operand distinctness. + +Default verify is read-only against `CERTIFICATE.json`. Admission uses `need()` +and stays enforced under `python -O`. Explicit `--write` regenerates the +certificate only. + +## Reproduce + +```sh +python3.12 -I -B research/selected-word-reject-exhaustion/verify.py +python3.12 -I -O -Werror -B research/selected-word-reject-exhaustion/verify.py +python3.12 -I -B research/selected-word-reject-exhaustion/independent.py +python3.12 -I -B research/selected-word-reject-exhaustion/test_package.py +python3.12 -B scripts/research_package.py --package research/selected-word-reject-exhaustion +``` + +## Open next questions + +1. **Exact length-≤3 divergence count at the same destination?** First step: + count closed-form failures over `n=661` lists of length 3. Blocked by: none; + omitted to keep this package on the length-≤2 OQ2 scope. +2. **Should schema docs separate divergence classes from distinctness rejects?** + First step: optional exporter warning keyed to the closed-form predicate. + Blocked by: maintainer adoption. + +## Credit + +Closest prior: [#3696](https://github.com/CrocSwap/integer-mult-bounds/pull/3696) +`gate-operand-export-parity` (Wentao Li; dest-free lemma, four named rejects, +OQ2). Cascade priors: Nick Petalas / #2977; Kumagi / #3004; Dylan Crow exporter; +eumemic symbolic checker; tuned PR589 word. Scatter-parity contract audit is +credited as provenance only. + +Prepared by Wentao Li with substantial AI assistance. Apache-2.0. +No independent human or proof-assistant review is claimed. diff --git a/research/selected-word-reject-exhaustion/SOURCES.json b/research/selected-word-reject-exhaustion/SOURCES.json new file mode 100644 index 0000000000..0c68e94d47 --- /dev/null +++ b/research/selected-word-reject-exhaustion/SOURCES.json @@ -0,0 +1,48 @@ +{ + "schema_version": 1, + "base_commit": "20ecf2891d80b5acf18d980b2164fb44ea7faa90", + "files": [ + { + "path": "research/e8-bit-p111-tuned/tune/bitE8mut-p111-tuned.json.gz", + "usage": "input", + "git_blob": "85a4499bf9e4911a705d50567a2c2ef6cf23739a", + "sha256": "e3e301e62bc2b41dbf1ceac0acf3d35824ebeab1848c5a2142d4577b109da52f", + "size_bytes": 42353 + }, + { + "path": "research/e8-bit-p111-tuned/code/xcheck_p.py", + "usage": "input", + "git_blob": "184f5dcf94a486cc7db91ca4db5865916bf26009", + "sha256": "af3decc877e27c00001cf56f50c6c09566e8e101297ab34c7860aed96a06d80e", + "size_bytes": 21651 + }, + { + "path": "research/scatter-parity-contract-audit/README.md", + "usage": "provenance", + "git_blob": "81cbe8e1756e0952028524addb0ed33188e617d1", + "sha256": "824ea617d818674b25c4d3dc7c7f6a7e252e217837d8473c2409d08096a48788", + "size_bytes": 7389 + }, + { + "path": "research/scatter-parity-contract-audit/TASK.json", + "usage": "provenance", + "git_blob": "fd03dc4c2c5028954e2165fb2358a3dfc70fae56", + "sha256": "b3619e9ad0c4b17b3f5ddffbe55fb25728bb3164fe32d4f614983cb8db28a7e9", + "size_bytes": 7192 + }, + { + "path": "certificates/selected-result.json", + "usage": "provenance", + "git_blob": "b1fea0c94436b236cc2b7d41a7be032811b94c81", + "sha256": "bb2eaa58647b353f88d0aec2eafb9d30df1be53589231b23e12ceef3e4bad129", + "size_bytes": 10725 + }, + { + "path": "docs/research/agent-task-catalog.json", + "usage": "provenance", + "git_blob": "67f085acd86acd7d4e03922d9cf4b26bca66fed5", + "sha256": "47b42433f5a85809a3aadd29c2c339da2c6ed728e4f7762df6b88bccb7874cf0", + "size_bytes": 58553 + } + ] +} diff --git a/research/selected-word-reject-exhaustion/TASK.json b/research/selected-word-reject-exhaustion/TASK.json new file mode 100644 index 0000000000..fed48a9b7b --- /dev/null +++ b/research/selected-word-reject-exhaustion/TASK.json @@ -0,0 +1,72 @@ +{ + "schema_version": 1, + "task_id": "supplier-boundary-audit", + "priority_revision": 6, + "base_commit": "20ecf2891d80b5acf18d980b2164fb44ea7faa90", + "original_card": { + "id": "supplier-boundary-audit", + "question": "Does one selected supplier obligation follow from its actual source-bound checks?", + "starting_points": [ + "certificates/selected-result.json", + "research/owner-boundary-audit/README.md", + "research/scatter-export-parity-audit/README.md" + ], + "methods": [ + "Trace one hypothesis through the source, checker and complete caller.", + "Construct one semantically invalid but superficially well-formed fixture and test rejection." + ], + "acceptance_gate": "Pin the current sources and one obligation; the historical owner audit is an example, not evidence of a current bug.", + "first_step": { + "command": [ + "python3", + "-B", + "scripts/research_baseline.py" + ], + "expected": "PASS_RESEARCH_BASELINE_BINDINGS_ONLY", + "inspect": "Read #2977 reported duplicate-scatter counterexample and its opt-in repair. The archive is not a production fix or an independently validated selected-result failure; the selected generator emits unique rows.", + "scope": "Source-binding orientation only; does not replay or validate the reported bug." + }, + "first_experiment": "First check whether the scatter repair has been adopted. If still open, independently reproduce #2977 symbolic-versus-exported parity on the tiny duplicate fixture, compare the selected unique-row positive control, and define either enforced uniqueness or consistent multiplicity semantics. A bounded guard-adoption patch must preserve valid inputs and test the actual exported action. Stop after this obligation; no full historical replay or frontier change follows from the mutant alone.", + "bottleneck_link": "Closing a current acceptance gap or proof obligation strengthens reliability even without changing kappa.", + "allowed_variations": [ + "Audit one named current condition using a new semantic counterexample." + ], + "scope_change_triggers": [ + "Reporting the historical timing-only diagnostic as a new current acceptance bug.", + "Calling a malformed mutant a failure of the selected construction, or importing an opt-in repair without testing the exporter boundary." + ], + "overlap_terms": [ + "owner boundary", + "bridge omission", + "hosting", + "2977", + "scatter export", + "duplicate index", + "parity semantics" + ] + }, + "scope_status": "changed", + "actual_scope": "Answer #3696 open question 2 on the pinned tuned word: are the four named B[0] checker rejects exhaustive for dest-in-sources Sym/Exp divergence? Prove a dest-in closed form, enumerate all length-≤2 source lists at destination 111 over n=661 registers, and show exactly 661 divergences of which only two lie among the four named rejects.", + "scope_change_reason": "Authorized follow-up to #3696 OQ2 under the supplier-boundary cascade. Dest-free Sym/Exp agreement is already published and is not restated as the claim; the new obligation is exhaustiveness of the four rejects versus the complete length-≤2 divergence set, plus the dest-in closed form that makes the census checkable.", + "bottleneck_link": "Knowing that reject samples are not a divergence taxonomy prevents treating four mutants as a complete gate-operand contract.", + "budget_minutes": 60, + "stop_rule": "Stop after the closed form, length-≤2 census, named-reject comparison, checker spot controls, and certificate admission. No dest-absent schema corollary, exporter rewrite, native replay, or kappa change.", + "outcome": "completed", + "evidence": "CERTIFICATE.json, PROOF.md, verify.py, independent.py and test_package.py. Closed form matches linear Sym/Exp on n≤8,len≤5 and on all length-≤2 lists at d=111; exactly 661 divergences; named diverge count 2; four_exhaustive=false; checker rejects the four named mutants and four spot divergences.", + "author": "Wentao Li", + "ai_assistance": "Substantial AI assistance for reading the #3696 cascade, deriving the dest-in closed form, implementing the length-≤2 census and package controls, and writing this package.", + "open_questions": [ + { + "question": "What is the exact count of dest-in Sym/Exp divergences for source lists of length ≤3 at the same destination?", + "why_it_matters": "Length 3 is the next bound that appears in selected multi-source gates; a closed count would extend the taxonomy past the length-≤2 census.", + "first_step": "Apply the closed form to count odd-count(d) lists with even non-d prefix multiplicities over n=661.", + "blocked_by": "None mathematically; omitted here to keep the package inside the length-≤2 OQ2 scope." + }, + { + "question": "Should a successor schema document divergence classes separately from distinctness rejects?", + "why_it_matters": "Distinctness rejects agreeing cases (dup_src, self_once, [d,a]) as well as diverging ones; a contract that only names four mutants understates the diverge set.", + "first_step": "Add an optional exporter warning keyed to the closed-form diverge predicate.", + "blocked_by": "Maintainer schema adoption; frozen exporters stay unchanged." + } + ] +} diff --git a/research/selected-word-reject-exhaustion/VERIFY.json b/research/selected-word-reject-exhaustion/VERIFY.json new file mode 100644 index 0000000000..56c6116978 --- /dev/null +++ b/research/selected-word-reject-exhaustion/VERIFY.json @@ -0,0 +1,54 @@ +{ + "schema_version": 1, + "status": "ready", + "python": "3.12", + "requirements": [], + "inputs": [ + "research/e8-bit-p111-tuned/tune/bitE8mut-p111-tuned.json.gz", + "research/e8-bit-p111-tuned/code/xcheck_p.py" + ], + "commands": [ + { + "argv": [ + "{python}", + "-I", + "-B", + "{package}/verify.py" + ], + "timeout_seconds": 180, + "checks": "Closed-form Sym/Exp criterion; length-≤2 census of 661 divergences at B[0] dest; four named rejects not exhaustive; checker spot controls; certificate admission." + }, + { + "argv": [ + "{python}", + "-I", + "-O", + "-Werror", + "-B", + "{package}/verify.py" + ], + "timeout_seconds": 180, + "checks": "need() admission remains enforced under -O; identical PASS marker." + }, + { + "argv": [ + "{python}", + "-I", + "-B", + "{package}/independent.py" + ], + "timeout_seconds": 120, + "checks": "Independent closed-form and length-≤2 census without importing verify.py." + }, + { + "argv": [ + "{python}", + "-I", + "-B", + "{package}/test_package.py" + ], + "timeout_seconds": 300, + "checks": "Duplicate JSON keys rejected; temp certificate corruption rejected; package files unchanged after read-only verify." + } + ] +} diff --git a/research/selected-word-reject-exhaustion/independent.py b/research/selected-word-reject-exhaustion/independent.py new file mode 100644 index 0000000000..5520d3f02d --- /dev/null +++ b/research/selected-word-reject-exhaustion/independent.py @@ -0,0 +1,104 @@ +#!/usr/bin/env python3 +"""Independent recompute of the length-≤2 divergence census and closed form. + +Does not import verify.py. Standard library only. +""" + +from __future__ import annotations + +import itertools +import json +from collections import Counter +from pathlib import Path + +HERE = Path(__file__).resolve().parent +MARKER = ( + "PASS_SELECTED_WORD_REJECT_INDEPENDENT " + "len2_divergences=661 named_diverge=2 four_exhaustive=false" +) +D = 111 +N = 661 +A = 3 + + +def need(ok, message): + if not ok: + raise ValueError(message) + + +def pairs_unique(pairs): + value = {} + for key, item in pairs: + need(key not in value, "duplicate JSON key") + value[key] = item + return value + + +def agree(d, srcs, n): + sym = [0] * n + sym[d] = 1 + for s in srcs: + sym[s] ^= 1 + exp = [0] * n + exp[d] = 1 + for s in srcs: + if s == d: + exp = [0] * n + else: + exp[s] ^= 1 + return sym == exp + + +def closed_form(d, srcs): + if d not in srcs: + return True + last = max(i for i, s in enumerate(srcs) if s == d) + if srcs.count(d) % 2 == 0: + return False + for s, count in Counter(srcs[:last]).items(): + if s != d and count % 2: + return False + return True + + +def main(): + # Closed form on a fresh small domain. + for length in range(0, 5): + for srcs in itertools.product(range(7), repeat=length): + for d in range(7): + need(agree(d, srcs, 7) == closed_form(d, srcs), "closed form") + + divergences = [] + for length in range(0, 3): + for srcs in itertools.product(range(N), repeat=length): + need(agree(D, srcs, N) == closed_form(D, srcs), "full closed form") + if not agree(D, srcs, N): + divergences.append(list(srcs)) + need(len(divergences) == N, "divergence count") + need(divergences == [[a, D] for a in range(N)], "divergence set order") + need([D, D] in divergences, "self_even present") + need([A, D] in divergences, "dest_with_src present") + need([D, A] not in divergences, "dest_then_src agrees") + + named = { + "self_even": [D, D], + "dest_with_src": [A, D], + "dup_src": [A, A], + "self_once": [D], + } + diverge_names = [k for k, v in named.items() if not closed_form(D, v)] + need(diverge_names == ["self_even", "dest_with_src"], "named diverge") + need(len(diverge_names) != len(divergences), "not exhaustive") + + cert = json.loads( + (HERE / "CERTIFICATE.json").read_text(encoding="utf-8"), + object_pairs_hook=pairs_unique, + ) + need(cert["claim"]["length2"]["divergences"] == 661, "cert count") + need(cert["claim"]["four_exhaustive_for_len2_divergence"] is False, "cert flag") + need(cert["no_new_kappa"] is True, "no new kappa") + print(MARKER) + + +if __name__ == "__main__": + main() diff --git a/research/selected-word-reject-exhaustion/test_package.py b/research/selected-word-reject-exhaustion/test_package.py new file mode 100644 index 0000000000..65b4c23c4d --- /dev/null +++ b/research/selected-word-reject-exhaustion/test_package.py @@ -0,0 +1,117 @@ +#!/usr/bin/env python3 +"""Behavioral controls for selected-word-reject-exhaustion.""" + +from __future__ import annotations + +import hashlib +import json +import subprocess +import sys +import tempfile +from pathlib import Path + +HERE = Path(__file__).resolve().parent +ROOT = HERE.parents[1] +sys.path.insert(0, str(HERE)) +import verify # noqa: E402 + +MARKER = "PASS_SELECTED_WORD_REJECT_PACKAGE_TESTS" + + +def need(ok, message): + if not ok: + raise ValueError(message) + + +def file_hashes(directory): + rows = {} + for path in sorted(directory.rglob("*")): + if path.is_file(): + rows[str(path.relative_to(directory))] = hashlib.sha256( + path.read_bytes() + ).hexdigest() + return rows + + +def test_duplicate_json_keys(): + with tempfile.TemporaryDirectory() as tmp: + path = Path(tmp) / "dup.json" + path.write_text('{"a": 1, "a": 2}\n', encoding="utf-8") + try: + verify.read_json(path) + except ValueError as exc: + need(str(exc) == "duplicate JSON key", "duplicate message") + else: + need(False, "duplicate key accepted") + + +def test_certificate_corruption_rejected(): + observed = verify.evaluate() + with tempfile.TemporaryDirectory() as tmp: + path = Path(tmp) / "CERTIFICATE.json" + blob = json.loads((HERE / "CERTIFICATE.json").read_text(encoding="utf-8")) + blob["claim"]["four_exhaustive_for_len2_divergence"] = True + path.write_text(json.dumps(blob, indent=2, sort_keys=True) + "\n", encoding="utf-8") + bad = verify.read_json(path) + try: + verify.need(observed == bad, "certificate mismatch") + except ValueError as exc: + need(str(exc) == "certificate mismatch", "corruption message") + else: + need(False, "corrupt certificate accepted") + live = verify.read_json(HERE / "CERTIFICATE.json") + need(live["claim"]["four_exhaustive_for_len2_divergence"] is False, + "on-disk certificate mutated") + + +def test_optimized_admission(): + script = ( + "import sys\n" + "from pathlib import Path\n" + f"sys.path.insert(0, {str(HERE)!r})\n" + "import verify\n" + "verify.need(__debug__ is False, 'optimization off')\n" + "try:\n" + " verify.need(False, 'admission')\n" + "except ValueError as exc:\n" + " if str(exc) != 'admission':\n" + " raise SystemExit('wrong admission')\n" + "else:\n" + " raise SystemExit('admission skipped')\n" + "print('PASS_OPTIMIZED_ADMISSION')\n" + ) + done = subprocess.run( + [sys.executable, "-O", "-I", "-B", "-c", script], + check=False, + capture_output=True, + text=True, + ) + need(done.returncode == 0, "optimized admission failed: " + done.stderr) + need("PASS_OPTIMIZED_ADMISSION" in done.stdout, "optimized marker") + + +def test_readonly_verify_unchanged(): + before = file_hashes(HERE) + proc = subprocess.run( + [sys.executable, "-I", "-B", str(HERE / "verify.py")], + cwd=str(ROOT), + capture_output=True, + text=True, + timeout=180, + ) + need(proc.returncode == 0, "verify failed: " + proc.stderr) + need("PASS_SELECTED_WORD_REJECT_EXHAUSTION" in proc.stdout, "missing PASS marker") + after = file_hashes(HERE) + need(before == after, "verify must be read-only") + + +def main(): + test_duplicate_json_keys() + test_certificate_corruption_rejected() + test_optimized_admission() + test_readonly_verify_unchanged() + print(MARKER) + + +if __name__ == "__main__": + main() diff --git a/research/selected-word-reject-exhaustion/verify.py b/research/selected-word-reject-exhaustion/verify.py new file mode 100644 index 0000000000..a6eca43ad9 --- /dev/null +++ b/research/selected-word-reject-exhaustion/verify.py @@ -0,0 +1,351 @@ +#!/usr/bin/env python3 +"""Length-≤2 dest-in divergence census for the four #3696 B[0] rejects. + +Answers #3696 OQ2: the four selected-word checker rejects are not exhaustive +for dest-in-sources divergence on the pinned word. Proves a dest-in closed +form, enumerates exactly 661 length-≤2 divergences at B[0]'s destination, and +shows only two of the four named rejects lie in that set. No new kappa. + +Admission uses need() and remains active under python -O. +""" + +from __future__ import annotations + +import copy +import gzip +import hashlib +import itertools +import json +import runpy +from collections import Counter +from pathlib import Path + +HERE = Path(__file__).resolve().parent +ROOT = HERE.parents[1] +MARKER = ( + "PASS_SELECTED_WORD_REJECT_EXHAUSTION " + "len2_divergences=661 named_diverge=2 " + "four_exhaustive=false no_new_kappa" +) +KAPPA_DECIMAL = "0.001672660197076918" +KAPPA_FRAC = "836330098538459/500000000000000000" +WORD = "research/e8-bit-p111-tuned/tune/bitE8mut-p111-tuned.json.gz" +CHECKER = "research/e8-bit-p111-tuned/code/xcheck_p.py" +INPUTS = (WORD, CHECKER) +B0_FRAME = 127 +B0_DEST = 111 +B0_SRC = 3 +N_REGS = 661 +LEN2_DIVERGENCES = 661 +NAMED = ("self_even", "dest_with_src", "dup_src", "self_once") + + +def need(ok, message): + if not ok: + raise ValueError(message) + + +def pairs_unique(pairs): + value = {} + for key, item in pairs: + need(key not in value, "duplicate JSON key") + value[key] = item + return value + + +def read_json(path): + raw = Path(path).read_bytes() + need(len(raw) <= 4_000_000, "input exceeds 4 MB") + return json.loads(raw, object_pairs_hook=pairs_unique) + + +def pin_sources(): + manifest = read_json(HERE / "SOURCES.json") + need(manifest["base_commit"] == "20ecf2891d80b5acf18d980b2164fb44ea7faa90", + "base commit pin") + rows = manifest["files"] + inputs = [row for row in rows if row["usage"] == "input"] + need(tuple(row["path"] for row in inputs) == INPUTS, "input inventory") + pinned = {} + for row in rows: + path = ROOT / row["path"] + raw = path.read_bytes() + need(len(raw) == row["size_bytes"], "source size: " + row["path"]) + digest = hashlib.sha256(raw).hexdigest() + need(digest == row["sha256"], "source hash: " + row["path"]) + pinned[row["path"]] = raw + return pinned + + +def sym_coeffs(d, srcs, n): + coeff = [0] * n + coeff[d] = 1 + for s in srcs: + coeff[s] ^= 1 + return tuple(coeff) + + +def exp_coeffs(d, srcs, n): + coeff = [0] * n + coeff[d] = 1 + for s in srcs: + if s == d: + coeff = [0] * n + else: + coeff[s] ^= 1 + return tuple(coeff) + + +def agree(d, srcs, n): + return sym_coeffs(d, srcs, n) == exp_coeffs(d, srcs, n) + + +def closed_form_agree(d, srcs): + """Dest-in closed form; dest-free always True.""" + if d not in srcs: + return True + last = max(i for i, s in enumerate(srcs) if s == d) + if srcs.count(d) % 2 == 0: + return False + for s, count in Counter(srcs[:last]).items(): + if s != d and count % 2: + return False + return True + + +def make_mutant_srcs(kind): + if kind == "self_even": + return [B0_DEST, B0_DEST] + if kind == "dest_with_src": + return [B0_SRC, B0_DEST] + if kind == "dup_src": + return [B0_SRC, B0_SRC] + if kind == "self_once": + return [B0_DEST] + need(False, "unknown mutant " + kind) + return [] + + +def length2_census(d, n): + """Enumerate all srcs of length ≤2; return divergence list and agree count.""" + divergences = [] + dest_in_agree = 0 + dest_free = 0 + for length in range(0, 3): + for srcs in itertools.product(range(n), repeat=length): + need(agree(d, srcs, n) == closed_form_agree(d, srcs), + "closed form mismatch") + if d not in srcs: + need(agree(d, srcs, n), "dest-free must agree") + dest_free += 1 + elif agree(d, srcs, n): + dest_in_agree += 1 + else: + divergences.append(list(srcs)) + return { + "divergences": divergences, + "dest_in_agree": dest_in_agree, + "dest_free": dest_free, + "total_lists": dest_free + dest_in_agree + len(divergences), + } + + +def expected_divergences(d, n): + # Length-2 product order: every [a, d] for a in range(n), including [d, d]. + return [[a, d] for a in range(n)] + + +def bind_source_lines(pinned): + checker = pinned[CHECKER].decode("utf-8") + need("len(set(regs)) == len(regs)" in checker, "cite: checker distinct operands") + need("bad operands" in checker, "cite: checker bad-operands message") + + +def load_word(pinned): + return json.loads(gzip.decompress(pinned[WORD]), object_pairs_hook=pairs_unique) + + +def selected_anchor(word): + need(word["v"] == 111, "v pin") + need(word["R"] == 439, "R pin") + need(2 * word["v"] + word["R"] == N_REGS, "register count") + need(word["B"][0] == [B0_FRAME, B0_DEST, [B0_SRC]], "B0 fixture") + gates = 0 + for name in ("D", "A", "B", "C"): + for gate in word[name]: + _f, d, srcs = gate + regs = [d] + list(srcs) + need(len(set(regs)) == len(regs), "selected gate non-distinct") + need(d not in srcs, "selected gate dest-in") + gates += 1 + need(gates == 5472, "selected gate count") + return gates + + +def checker_rejects_kinds(word, kinds): + ns = runpy.run_path(str(ROOT / CHECKER)) + check = ns["check"] + Reject = ns["Reject"] + check(word) + rejected = [] + for kind in kinds: + mutant = copy.deepcopy(word) + mutant["B"][0] = [B0_FRAME, B0_DEST, make_mutant_srcs(kind)] + try: + check(mutant) + need(False, "checker accepted " + kind) + except Reject as exc: + need("bad operands" in str(exc), "reject message: " + kind) + rejected.append(kind) + except Exception as exc: # noqa: BLE001 + need("bad operands" in str(exc), "reject message: " + kind) + rejected.append(kind) + return rejected + + +def checker_rejects_srcs(word, srcs_list): + ns = runpy.run_path(str(ROOT / CHECKER)) + check = ns["check"] + Reject = ns["Reject"] + for srcs in srcs_list: + mutant = copy.deepcopy(word) + mutant["B"][0] = [B0_FRAME, B0_DEST, list(srcs)] + try: + check(mutant) + need(False, "checker accepted " + str(srcs)) + except Reject as exc: + need("bad operands" in str(exc), "reject message: " + str(srcs)) + except Exception as exc: # noqa: BLE001 + need("bad operands" in str(exc), "reject message: " + str(srcs)) + + +def small_domain_closed_form(n=8, max_len=5): + mismatches = 0 + for length in range(0, max_len + 1): + for srcs in itertools.product(range(n), repeat=length): + for d in range(n): + if agree(d, srcs, n) != closed_form_agree(d, srcs): + mismatches += 1 + need(mismatches == 0, "small-domain closed form mismatches") + return {"n": n, "max_len": max_len, "mismatches": mismatches} + + +def admit_certificate(certificate, write=False): + path = HERE / "CERTIFICATE.json" + if write: + path.write_text(json.dumps(certificate, indent=2, sort_keys=True) + "\n") + return + need(path.is_file(), "missing CERTIFICATE.json") + committed = read_json(path) + need(committed == certificate, "certificate mismatch") + + +def evaluate(write=False): + pinned = pin_sources() + bind_source_lines(pinned) + word = load_word(pinned) + gates = selected_anchor(word) + + small = small_domain_closed_form() + census = length2_census(B0_DEST, N_REGS) + expected = expected_divergences(B0_DEST, N_REGS) + need(len(census["divergences"]) == LEN2_DIVERGENCES, "divergence count") + need(census["divergences"] == expected, "divergence set") + need(census["dest_in_agree"] == LEN2_DIVERGENCES, "dest-in agree count") + need(census["total_lists"] == 1 + N_REGS + N_REGS * N_REGS, "total lists") + + named_status = {} + named_diverge = [] + named_agree = [] + for kind in NAMED: + srcs = make_mutant_srcs(kind) + diverges = not closed_form_agree(B0_DEST, srcs) + need(diverges == (not agree(B0_DEST, srcs, N_REGS)), "named closed form") + bad = len(set([B0_DEST] + srcs)) != len([B0_DEST] + srcs) + need(bad, "named must be bad operands") + named_status[kind] = { + "srcs": srcs, + "diverges": diverges, + "in_len2_divergence_set": srcs in census["divergences"], + } + if diverges: + named_diverge.append(kind) + else: + named_agree.append(kind) + need(named_diverge == ["self_even", "dest_with_src"], "named diverge pair") + need(named_agree == ["dup_src", "self_once"], "named agree pair") + four_exhaustive = len(named_diverge) == LEN2_DIVERGENCES + need(four_exhaustive is False, "four must not be exhaustive") + + # Distinctness catches every length-≤2 divergence (algebraic, plus spot checks). + for srcs in census["divergences"]: + need(B0_DEST in srcs, "divergence must be dest-in") + need(len(set([B0_DEST] + srcs)) < len([B0_DEST] + srcs), + "divergence must fail distinctness") + rejected = checker_rejects_kinds(word, NAMED) + need(rejected == list(NAMED), "four checker rejects") + spot = [[B0_DEST, B0_DEST], [0, B0_DEST], [N_REGS - 1, B0_DEST], [B0_SRC, B0_DEST]] + checker_rejects_srcs(word, spot) + + selected_result = read_json(ROOT / "certificates/selected-result.json") + need(selected_result.get("kappa") == KAPPA_FRAC, "selected kappa fraction") + need(selected_result.get("decimal") == KAPPA_DECIMAL, "selected kappa decimal") + + certificate = { + "schema_version": 1, + "status": "PASS_SELECTED_WORD_REJECT_EXHAUSTION", + "kappa_decimal": KAPPA_DECIMAL, + "claim": { + "closed_form": ( + "agree iff d not in srcs, or count(d) odd and every non-d " + "has even multiplicity before the last d" + ), + "small_domain_closed_form": small, + "length2": { + "destination": B0_DEST, + "n_registers": N_REGS, + "divergences": LEN2_DIVERGENCES, + "dest_in_agree": census["dest_in_agree"], + "dest_free": census["dest_free"], + "total_lists": census["total_lists"], + "form": "[[d,d]] U [[a,d] : a != d]", + }, + "named_rejects": named_status, + "named_diverge_count": len(named_diverge), + "four_exhaustive_for_len2_divergence": False, + }, + "selected_word": { + "path": WORD, + "sha256": hashlib.sha256(pinned[WORD]).hexdigest(), + "gates": gates, + "B0": [B0_FRAME, B0_DEST, [B0_SRC]], + "n_registers": N_REGS, + }, + "controls": { + "checker_rejects": rejected, + "checker_spot_divergences": spot, + "all_len2_divergences_fail_distinctness": True, + }, + "no_new_kappa": True, + } + admit_certificate(certificate, write=write) + return certificate + + +def main(argv=None): + import argparse + + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument( + "--write", + action="store_true", + help="regenerate CERTIFICATE.json (explicit write path only)", + ) + args = parser.parse_args(argv) + certificate = evaluate(write=args.write) + need(certificate["status"] == "PASS_SELECTED_WORD_REJECT_EXHAUSTION", "status") + print(MARKER) + + +if __name__ == "__main__": + main()