diff --git a/certificates/stronger-rank-screens.json b/certificates/stronger-rank-screens.json index b8c1114ece..1cf78a6585 100644 --- a/certificates/stronger-rank-screens.json +++ b/certificates/stronger-rank-screens.json @@ -581,7 +581,7 @@ "source_sha256": { "docs/research/stronger-rank-screens.md": "58e9946054e31df444932833514d6a0f197fdee35334e7511c63af5e52f45ab1", "scripts/audit_stronger_screens.py": "9678b66043b384f1454181bc2069c6d72685eda6576e284ce799d4b9aeb79860", - "scripts/experiments/balanced_fano.py": "1586fb1db4f40e79e97bae59f47192675663403bbcacbf5f4e0b702edfd22b0a", + "scripts/experiments/balanced_fano.py": "b8ae21d9d4e5c687cda3935e8750c84c80f5bb6d42bcaa2f44c9d907b461fca1", "scripts/experiments/fano_completion.py": "6cade2a36b910bf7e68a872dc4fd3560837935cffe80f9526cd012a28b247738", "scripts/finite_bit_contract.py": "3cff26a332cb6056f656b824e3a523fb8937d15206ddcc4118b911ac8df1b2a7", "scripts/rank_obstructions.py": "af0bb5d7c21409bf0318ec4ec7d5f391163b7ad9564ed9e35de92ada14bca975" diff --git a/research/balanced-fano-performance/CLAIM.json b/research/balanced-fano-performance/CLAIM.json new file mode 100644 index 0000000000..06c5787ed0 --- /dev/null +++ b/research/balanced-fano-performance/CLAIM.json @@ -0,0 +1,50 @@ +{ + "track": "verification engineering", + "assignment_seed": 91, + "seed_source": "Python secrets.randbelow(100), using operating-system randomness", + "base_commit": "66849e1475c930fd7732b1a0067ffee7e1e95f60", + "started_utc": "2026-10-13T04:50:54Z", + "claimed_utc": "2026-10-13T04:54:00Z", + "expected_finish_utc": "2026-10-13T05:25:00Z", + "time_budget": "About 35 minutes; reserve the final quarter for verification and handoff.", + "coordination": { + "pinned_issue": null, + "checked_via": "GitHub GraphQL repository.pinnedIssues and open issue inventory", + "open_pull_requests_inspected": 543, + "latest_pr_at_initial_snapshot": 723, + "claim_location": "Local: no pinned sprint coordination issue exists." + }, + "candidates": [ + { + "object": "Selected source-inventory hashing", + "decision": "Not chosen: adjacent to PR721's streamed archive validation." + }, + { + "object": "Exact logarithm/exponential moment arithmetic", + "decision": "Not chosen: overlapping work in PR667 and PR672." + }, + { + "object": "Historical balanced-Fano meet-in-the-middle replay", + "decision": "Chosen: distinct from pending frame algebra, Gram-prefix, Clifford, R420 geometry, and streaming work." + } + ], + "object": "scripts/experiments/balanced_fano.py: existence() on the fixed 10-role, 14-gate model", + "hypothesis": "Propagating packed binary columns avoids the quadratic row-to-column transpose at every leaf while preserving the ordered exhaustive streams and recovered witnesses.", + "method": "Exact Python integer bit operations; same GL(2,F2) choices, enumeration order, matching keys, hashes, budgets and witness checks. Seed 91 also fixes the differential corpus and benchmark order.", + "coverage": "The existing 279936 prefixes and 279936 inverse suffixes, plus independent dense small-model controls. No extension or reopening of the closed search.", + "deliverable": "Focused checker optimization, source-pinned sequential before/after benchmark, exact equality and failure controls, one regenerated historical certificate if its source hash changes.", + "status": "completed", + "completed_utc": "2026-10-13T05:07:13.379148+00:00", + "final_overlap_check": { + "open_pr_count": 567, + "latest_pr_number": 748, + "finding": "No balanced-Fano or packed-column replay contribution found. New tooling PR727 (owner footprints) and PR736 (cyclic-inverse row updates) have distinct objects; no pending code used." + }, + "result": { + "classification": "tooling improvement; no new kappa", + "wall_speedup": 2.9108981566293375, + "peak_rss_reduction_fraction": 0.30299667036625966, + "validation": "555 tests in 85 isolated modules plus exact full-stream comparison and pinned A/B evidence", + "url": "https://github.com/VictorLiwentao/integer-mult-bounds/tree/tooling%2Fseed91-balanced-fano-columns/research/balanced-fano-performance" + } +} diff --git a/research/balanced-fano-performance/NOTICE.md b/research/balanced-fano-performance/NOTICE.md new file mode 100644 index 0000000000..51b6db6921 --- /dev/null +++ b/research/balanced-fano-performance/NOTICE.md @@ -0,0 +1,30 @@ +# Attribution and scope + +Prepared by **Wentao Li** ([GitHub: VictorLiwentao](https://github.com/VictorLiwentao), +[X: @Is__Victor](https://x.com/Is__Victor)) with substantial **OpenAI Codex** +assistance in task selection, implementation, proof explanation, tests, +benchmarks and writing. No independent human review is claimed. + +Douglas R. Colkitt authored the retained historical balanced-Fano investigation, +its exact meet-in-the-middle checker, negative certificate and independent +dense controls. The preserved research documentation discloses AI assistance. +`baseline.py` is an unchanged copy of his `scripts/experiments/balanced_fano.py` +from base `66849e1475c930fd7732b1a0067ffee7e1e95f60`, originating at +`d55bcd62ceb8f322bcf311a5a66e94c3ac7724f0`. The graph, local operations, matching +criterion, search domain, stream hashes and negative finding are predecessor +work; this contribution claims the packed-column implementation and its +performance/equivalence evidence only. + +See [the original stronger-screen note](../../docs/research/stronger-rank-screens.md) +and [Fano completion audit](../../docs/research/fano-completion-audit.md) for the +mathematical context and underlying literature. No new literature theorem is +claimed or independently verified here. + +The selected conditional certificate remains the separately reviewed #626 +construction with eumemic's #543 bit supplier, credited to Chafik Boukhalfa, +Jeremy Kothe and the full predecessor chain in the maintainer review. Pending +verification-engineering PRs were consulted for overlap; none is a code or +mathematical dependency of this change. + +All added and modified code and evidence use the repository's Apache-2.0 +license. The original root license and contributor notices remain in place. diff --git a/research/balanced-fano-performance/README.md b/research/balanced-fano-performance/README.md new file mode 100644 index 0000000000..99380ddaef --- /dev/null +++ b/research/balanced-fano-performance/README.md @@ -0,0 +1,141 @@ +# Faster exact balanced-Fano replay + +This tooling change accelerates the existing exhaustive check of the historical +10-role, 14-gate balanced-Fano model. It preserves the negative result and its +complete ordered enumeration. It does not extend the search domain or claim a +new κ. The selected conditional result remains #626 with #543, exactly +`51110230636731/31250000000000000`, at the base commit below. + +The production change is confined to +[`balanced_fano.py`](../../scripts/experiments/balanced_fano.py). Each local +binary operation now acts on a packed column representation, avoiding a fresh +10-by-10 transpose at every leaf. The matching table retains each first prefix +word; its matrix is reconstructed only when recovering a witness. + +## Reproduce + +From the repository root, using Python 3.11 or later and no third-party packages: + +```sh +python3 -B research/balanced-fano-performance/benchmark.py --rounds 5 +``` + +Expected: `PASS_IDENTICAL_COMPLETE_RESULTS`, with **279,936 prefixes**, +**258,156 distinct prefix keys**, **279,936 inverse suffixes**, no witness, +and these unchanged stream hashes: + +```text +prefix b34379c5feeb67216fb7531294f13da5f67ce4a22f92b94ff8ea2b26f3aa21ec +suffix a19c1f14c463451e7bdd0900a2aeae701d98bcee790e9145d70e05c316555c38 +``` + +Each sample runs in a fresh process. The two implementations run sequentially +in alternating order, fixed by assignment seed 91, on identical inputs. Every +sample must match **every result field** in the original certificate, including +counts, both hashes, witness and scope. The benchmark fails on a changed source +pin, unequal result, or subprocess failure. It has no noisy timing threshold. +The benchmark's RSS measurement supports macOS and Linux; the checker itself +uses portable Python integers. Use `--output /path/to/new-result.json` to retain +a new measurement without overwriting the shipped receipt. + +[`RESULT.json`](RESULT.json) records all local samples, medians, environment and +exact implementation hashes. The measurement is for this fixed search, not the +complete research suite, selected supplier replay, or multiplication runtime. +OS caches were not flushed and no CPU affinity was imposed. + +The contributor name was corrected after measurement. `RESULT.json` records +both the measured and updated hashes for the benchmark's attribution-only +module-docstring edit. Its executable AST was checked unchanged after removing +that docstring; all timing samples and mathematical results are retained. + +On CPython 3.13.2 / macOS arm64, five sequential pairs give median search time +**5.969 → 2.051 seconds (2.91×)** and median peak process RSS +**162,381,824 → 113,180,672 bytes (30.3% lower)**. These are measured local +results, not guaranteed performance on other environments. + +Additional checks: + +```sh +python3 -B -m unittest discover -s tests -p 'test_balanced_fano_performance.py' -v +python3 -B -m unittest discover -s tests -p 'test_stronger_screens.py' -v +python3 -B -S scripts/audit_stronger_screens.py +make selected-record-check +``` + +The audit regenerates only `certificates/stronger-rank-screens.json`. Its sole +change is the SHA256 binding for the optimized source. A test restores that one +old binding and requires the entire serialized certificate to match its +original SHA256, so other certificate differences cannot pass unnoticed. + +Local validation also passed `PYTHONDONTWRITEBYTECODE=1 make verify-tests`: +555 tests in 85 isolated modules and the existing patch-application checks. +The six added tests also pass under `python3 -B -O`. See +[`VALIDATION.json`](VALIDATION.json) for the precise coverage. Full `make verify` +and the selected supplier cold replay were not rerun for this historical-checker +change; unrelated artifacts were not regenerated. Remote CI is separate from +this local evidence. + +## Why the enumeration is identical + +For a binary matrix `M` with `W` rows, encode its columns as + +```text +S = sum(M[i,j] * 2**(W*j+i) for i,j in range(W)). +U = sum(2**(W*j) for j in range(W)). +``` + +The masks `(S >> a) & U` and `(S >> b) & U` extract rows `a` and `b` +into the same column-start positions. XOR therefore adds those two rows over +F2 simultaneously in every column. Clearing only `U << a` and `U << b` and +placing the two selected linear combinations in those positions gives exactly +the old local row operation. The positions are disjoint because `a != b` and +both are in `[0,W)`. Python integers have arbitrary precision; this uses no +fixed-width truncation or approximate arithmetic. + +The identity uses bits `i*(W+1)`. Induction on the unchanged depth-first GL2 +choice order shows that each leaf has the same word and matrix as before. +Reading each W-bit block yields the old `columns(rows)` tuple. Thus prescribed +columns, sorted free columns, packed keys, first-prefix selection, stream +order and both hashes remain identical. There is no pruning, orbit reduction, +sampling, memoized result reuse, or changed stopping rule. + +When keys match, replaying the retained first prefix word reconstructs its +original columns exactly. The suffix inversion and full recovered-permutation +checks are unchanged. Half-enumeration budgets and invalid-terminal/port +rejections run before enumeration as before. + +The existing meet-in-the-middle argument still covers all `6**14 = 78,364,164,096` +complete local assignments via the two `6**7` streams. The absence of a match +excludes only this fixed balanced topology, with its three prescribed +terminals and free permutation of the other seven roles. It does not exclude +other Fano completions, larger gates, or different terminal obligations. + +## Evidence and provenance + +- Exact base: `66849e1475c930fd7732b1a0067ffee7e1e95f60`. +- The reference is the byte-for-byte original `balanced_fano.py`, last changed + by `d55bcd62ceb8f322bcf311a5a66e94c3ac7724f0`; its SHA256 and shared dependencies + are pinned in [`SOURCE.json`](SOURCE.json). No pending PR code is required. +- Tests compare every `(columns, word)` pair in both full historical streams, + not only their final hashes. Independent dense matrix controls cover widths + 2, 3, 5, 9, 16, 33 and 65, including integer limb and byte boundaries. +- Seeded small-model comparisons cover complete result dictionaries, positive + witnesses, first matching suffixes, empty words, repeated/reversed ports, + fixed/free terminals and negative cases. Existing tests independently exhaust + 9,294 complete dense assignments. +- A missing-leaf mutation still reports no completion, but changes both counts + and hashes and is rejected by the receipt comparison. Invalid inputs and an + exhausted half budget retain the original exceptions; budget exhaustion is + never reported as a negative mathematical result. + +[`CLAIM.json`](CLAIM.json) records assignment seed 91, candidate selection and +overlap review. No pinned sprint coordination issue existed. Nearby PRs #367, +#452, #662, #667, #672, #707, #709 and #721 address other algebra, producer, +geometry, arithmetic or archive checks. This contribution replays the already +closed Fano model more efficiently; it is not a renewed search. + +No selected construction, `upstream/`, theorem claim or inherited compiler, +hosting, precision, tape, or analytic assumption changes. These are exact +finite checks and an implementation equivalence argument, not a formal proof +of the full multiplication theorem. Attribution and AI disclosure are in +[`NOTICE.md`](NOTICE.md). diff --git a/research/balanced-fano-performance/RESULT.json b/research/balanced-fano-performance/RESULT.json new file mode 100644 index 0000000000..ee1592c3b2 --- /dev/null +++ b/research/balanced-fano-performance/RESULT.json @@ -0,0 +1,169 @@ +{ + "assignment_seed": 91, + "attribution_revision": { + "change": "Contributor name corrected in the module docstring only. Executable AST after removing that docstring is identical. Existing measurements are retained; they were not rerun.", + "executable_ast_unchanged_without_module_docstring": true, + "measured_source_sha256": "dec749e1d9832586acbfda1a76f8fa7c3ef3dd8f955a4eae26e7de7295c7446d", + "source_path": "research/balanced-fano-performance/benchmark.py", + "timing_samples_unchanged": true, + "updated_source_sha256": "6d46bbd5d8b7550b452dd3561522fa80586e8bbdbff246db4529161b31598760" + }, + "base_commit": "66849e1475c930fd7732b1a0067ffee7e1e95f60", + "environment": { + "cpu_count": 8, + "executable": "/opt/homebrew/opt/python@3.13/bin/python3.13", + "machine": "arm64", + "platform": "macOS-27.0.1-arm64-arm-64bit-Mach-O", + "python": "3.13.2 (main, Feb 4 2025, 14:51:09) [Clang 16.0.0 (clang-1600.0.26.6)]", + "python_hash_seed": "91" + }, + "expected_result": { + "W": 10, + "exhaustive_negative": true, + "exists": false, + "full_assignment_count": 78364164096, + "gates": 14, + "prefix_assignments": 279936, + "prefix_keys": 258156, + "prefix_sha256": "b34379c5feeb67216fb7531294f13da5f67ce4a22f92b94ff8ea2b26f3aa21ec", + "prescribed": { + "0": 7, + "1": 0, + "2": 3 + }, + "scope": "Existence with a free permutation of unprescribed roles; not an enumeration of every matching circuit.", + "split": 7, + "suffix_assignments": 279936, + "suffix_sha256": "a19c1f14c463451e7bdd0900a2aeae701d98bcee790e9145d70e05c316555c38", + "witness": null + }, + "medians": { + "baseline": { + "cpu_seconds": 5.931452, + "peak_rss_bytes": 162381824, + "process_wall_seconds": 6.058809750000364, + "wall_seconds": 5.969119416000467 + }, + "packed": { + "cpu_seconds": 2.040183, + "peak_rss_bytes": 113180672, + "process_wall_seconds": 2.1339019579991145, + "wall_seconds": 2.05061087499962 + } + }, + "method": "Fresh process for each sample, sequential alternating order; caches not flushed, no CPU affinity", + "peak_rss_reduction_fraction": 0.30299667036625966, + "rounds": 5, + "samples": [ + { + "cpu_seconds": 5.936161, + "input_sha256": "9248d1858b891a071d087dd2f4bf6e8d242249d3ec26b3f8e99e5a7ed5dcfea8", + "mode": "baseline", + "peak_rss_bytes": 156139520, + "process_wall_seconds": 6.351126208001006, + "result_sha256": "06487fed742a8fbfe4f00702ecb71657fef48cc8b3b1eda99055dbb1e78af8ac", + "round": 1, + "wall_seconds": 6.021428957999888 + }, + { + "cpu_seconds": 2.050778, + "input_sha256": "9248d1858b891a071d087dd2f4bf6e8d242249d3ec26b3f8e99e5a7ed5dcfea8", + "mode": "packed", + "peak_rss_bytes": 113082368, + "process_wall_seconds": 2.170751333998851, + "result_sha256": "06487fed742a8fbfe4f00702ecb71657fef48cc8b3b1eda99055dbb1e78af8ac", + "round": 1, + "wall_seconds": 2.0861264579998533 + }, + { + "cpu_seconds": 2.050669, + "input_sha256": "9248d1858b891a071d087dd2f4bf6e8d242249d3ec26b3f8e99e5a7ed5dcfea8", + "mode": "packed", + "peak_rss_bytes": 113328128, + "process_wall_seconds": 2.163195499999347, + "result_sha256": "06487fed742a8fbfe4f00702ecb71657fef48cc8b3b1eda99055dbb1e78af8ac", + "round": 2, + "wall_seconds": 2.0848514579993207 + }, + { + "cpu_seconds": 5.933592, + "input_sha256": "9248d1858b891a071d087dd2f4bf6e8d242249d3ec26b3f8e99e5a7ed5dcfea8", + "mode": "baseline", + "peak_rss_bytes": 162349056, + "process_wall_seconds": 6.159905291999166, + "result_sha256": "06487fed742a8fbfe4f00702ecb71657fef48cc8b3b1eda99055dbb1e78af8ac", + "round": 2, + "wall_seconds": 6.080203667001115 + }, + { + "cpu_seconds": 5.931452, + "input_sha256": "9248d1858b891a071d087dd2f4bf6e8d242249d3ec26b3f8e99e5a7ed5dcfea8", + "mode": "baseline", + "peak_rss_bytes": 162381824, + "process_wall_seconds": 6.058809750000364, + "result_sha256": "06487fed742a8fbfe4f00702ecb71657fef48cc8b3b1eda99055dbb1e78af8ac", + "round": 3, + "wall_seconds": 5.969119416000467 + }, + { + "cpu_seconds": 2.040183, + "input_sha256": "9248d1858b891a071d087dd2f4bf6e8d242249d3ec26b3f8e99e5a7ed5dcfea8", + "mode": "packed", + "peak_rss_bytes": 113344512, + "process_wall_seconds": 2.1339019579991145, + "result_sha256": "06487fed742a8fbfe4f00702ecb71657fef48cc8b3b1eda99055dbb1e78af8ac", + "round": 3, + "wall_seconds": 2.05061087499962 + }, + { + "cpu_seconds": 2.037389, + "input_sha256": "9248d1858b891a071d087dd2f4bf6e8d242249d3ec26b3f8e99e5a7ed5dcfea8", + "mode": "packed", + "peak_rss_bytes": 113180672, + "process_wall_seconds": 2.1284873749991675, + "result_sha256": "06487fed742a8fbfe4f00702ecb71657fef48cc8b3b1eda99055dbb1e78af8ac", + "round": 4, + "wall_seconds": 2.047367832999953 + }, + { + "cpu_seconds": 5.915992, + "input_sha256": "9248d1858b891a071d087dd2f4bf6e8d242249d3ec26b3f8e99e5a7ed5dcfea8", + "mode": "baseline", + "peak_rss_bytes": 162938880, + "process_wall_seconds": 6.02306554200004, + "result_sha256": "06487fed742a8fbfe4f00702ecb71657fef48cc8b3b1eda99055dbb1e78af8ac", + "round": 4, + "wall_seconds": 5.943898292000085 + }, + { + "cpu_seconds": 5.921253, + "input_sha256": "9248d1858b891a071d087dd2f4bf6e8d242249d3ec26b3f8e99e5a7ed5dcfea8", + "mode": "baseline", + "peak_rss_bytes": 163364864, + "process_wall_seconds": 6.028649834001044, + "result_sha256": "06487fed742a8fbfe4f00702ecb71657fef48cc8b3b1eda99055dbb1e78af8ac", + "round": 5, + "wall_seconds": 5.949636125000325 + }, + { + "cpu_seconds": 2.029332, + "input_sha256": "9248d1858b891a071d087dd2f4bf6e8d242249d3ec26b3f8e99e5a7ed5dcfea8", + "mode": "packed", + "peak_rss_bytes": 112558080, + "process_wall_seconds": 2.120065875000364, + "result_sha256": "06487fed742a8fbfe4f00702ecb71657fef48cc8b3b1eda99055dbb1e78af8ac", + "round": 5, + "wall_seconds": 2.0395690410005045 + } + ], + "scope": "Fixed W=10, 14-gate existence search; not the complete repository suite or selected-frontier replay", + "source_sha256": { + "research/balanced-fano-performance/SOURCE.json": "88f64211656d17d16fdd13506f55eee9327bf3c691d9c11464a02ba5724c63b6", + "research/balanced-fano-performance/baseline.py": "1586fb1db4f40e79e97bae59f47192675663403bbcacbf5f4e0b702edfd22b0a", + "research/balanced-fano-performance/benchmark.py": "6d46bbd5d8b7550b452dd3561522fa80586e8bbdbff246db4529161b31598760", + "research/balanced-fano-performance/common.py": "cb25c6be4a45122b72cf9591e3bfc53e9e49eebf4c648be5204504637bd16853", + "scripts/experiments/balanced_fano.py": "b8ae21d9d4e5c687cda3935e8750c84c80f5bb6d42bcaa2f44c9d907b461fca1" + }, + "status": "PASS_IDENTICAL_COMPLETE_RESULTS", + "wall_speedup": 2.9108981566293375 +} diff --git a/research/balanced-fano-performance/SOURCE.json b/research/balanced-fano-performance/SOURCE.json new file mode 100644 index 0000000000..77fbb2bf63 --- /dev/null +++ b/research/balanced-fano-performance/SOURCE.json @@ -0,0 +1,32 @@ +{ + "base_commit": "66849e1475c930fd7732b1a0067ffee7e1e95f60", + "baseline_path": "scripts/experiments/balanced_fano.py", + "baseline_certificate_sha256": "6000ff822aaf386baff5e9dfcc6818d0b4c3f176be99202f966201bda54ca9f3", + "baseline_sha256": "1586fb1db4f40e79e97bae59f47192675663403bbcacbf5f4e0b702edfd22b0a", + "expected_result": { + "W": 10, + "exhaustive_negative": true, + "exists": false, + "full_assignment_count": 78364164096, + "gates": 14, + "prefix_assignments": 279936, + "prefix_keys": 258156, + "prefix_sha256": "b34379c5feeb67216fb7531294f13da5f67ce4a22f92b94ff8ea2b26f3aa21ec", + "prescribed": { + "0": 7, + "1": 0, + "2": 3 + }, + "scope": "Existence with a free permutation of unprescribed roles; not an enumeration of every matching circuit.", + "split": 7, + "suffix_assignments": 279936, + "suffix_sha256": "a19c1f14c463451e7bdd0900a2aeae701d98bcee790e9145d70e05c316555c38", + "witness": null + }, + "shared_source_sha256": { + "scripts/audit_stronger_screens.py": "9678b66043b384f1454181bc2069c6d72685eda6576e284ce799d4b9aeb79860", + "scripts/certify.py": "2348d95008276c5d5764f7e028c3918e484582cd589bd4d9b82919161745e53e", + "scripts/experiments/fano_completion.py": "6cade2a36b910bf7e68a872dc4fd3560837935cffe80f9526cd012a28b247738" + }, + "source_commit": "d55bcd62ceb8f322bcf311a5a66e94c3ac7724f0" +} diff --git a/research/balanced-fano-performance/VALIDATION.json b/research/balanced-fano-performance/VALIDATION.json new file mode 100644 index 0000000000..d28ed5b93d --- /dev/null +++ b/research/balanced-fano-performance/VALIDATION.json @@ -0,0 +1,71 @@ +{ + "attribution": "Wentao Li with substantial OpenAI Codex assistance; predecessor credits and public profiles in NOTICE.md; no independent human review claimed.", + "attribution_revision": { + "checks": [ + "Benchmark source differs only in its module attribution docstring.", + "Executable AST excluding that docstring is unchanged.", + "Benchmark samples and mathematical result fields are unchanged.", + "All current benchmark source pins and the validation receipt binding match." + ], + "name": "Wentao Li", + "scope": "Attribution-only correction; the recorded historical validation was not rerun.", + "updated_utc": "2026-10-13T05:32:34.303823+00:00", + "x_profile": "https://x.com/Is__Victor" + }, + "base_commit": "66849e1475c930fd7732b1a0067ffee7e1e95f60", + "benchmark_receipt_sha256": "f23b66957506e08f5ddbe3d0ea49edcb563f53073eb0d3eb43bdf1c187237a9e", + "checks": [ + { + "command": "PYTHONDONTWRITEBYTECODE=1 make verify-tests", + "exit_code": 0, + "isolated_modules": 85, + "patch_application_checks": 20, + "tests": 555 + }, + { + "command": "python3 -B -O -m unittest discover -s tests -p 'test_balanced_fano_performance.py' -v", + "exit_code": 0, + "tests": 6 + }, + { + "certificate_diff": "Only scripts/experiments/balanced_fano.py source SHA256 changes; reconstructed original complete certificate hash checked in tests.", + "command": "python3 -B -S scripts/audit_stronger_screens.py", + "exit_code": 0 + }, + { + "command": "make selected-record-check", + "exit_code": 0, + "scope": "Exact selected kappa and frozen source inventory, not a supplier replay." + }, + { + "command": "python3 -B research/balanced-fano-performance/benchmark.py --rounds 5", + "exit_code": 0, + "receipt": "RESULT.json", + "samples": 10 + }, + { + "command": "git diff --check", + "exit_code": 0 + } + ], + "completed_utc": "2026-10-13T05:07:13.379148+00:00", + "differential_coverage": { + "existing_independent_dense_complete_assignments": 9294, + "full_half_assignments_compared_pointwise": 559872, + "independent_dense_column_controls": 1512, + "small_model_complete_result_comparisons": 132 + }, + "local_test_log_sha256": "465f797405e31e5f7b97e307d9a839c2b78c721f94e822d73a5ca8f03bbc588a", + "negative_controls": [ + "Omitted last leaf still gives a negative Boolean but fails both count and hash comparisons.", + "Invalid widths, ports and terminal prescriptions retain original ValueError messages.", + "An exhausted half budget raises instead of certifying nonexistence; the exact budget boundary succeeds." + ], + "not_run": [ + "Full make verify (would regenerate unrelated artifacts)", + "Selected supplier cold replay", + "Remote CI (reported by GitHub separately)" + ], + "status": "PASS_LOCAL_VALIDATION", + "test_source_sha256": "6e8b8a2d006ff1563a88cf4f4979c8e13f3f7c25be6f76930d9cddaa84d0ed8b" +} diff --git a/research/balanced-fano-performance/baseline.py b/research/balanced-fano-performance/baseline.py new file mode 100644 index 0000000000..136446fa01 --- /dev/null +++ b/research/balanced-fano-performance/baseline.py @@ -0,0 +1,123 @@ +"""Balance the Fano DAG, then exhaust the local reversible binary model. + +The meet-in-the-middle algorithm tests existence with a free permutation of +unprescribed roles. Keeping one prefix per key is sufficient for existence, +but not for enumerating all possible complete words or output permutations. +""" +from hashlib import sha256 + +from certify import require +from experiments.fano_completion import FANO_EDGES + + +GL2 = ((1, 2), (2, 1), (1, 3), (3, 2), (2, 3), (3, 1)) + + +def balanced_fano(): + order = ('a', 'b', 'c', 'u1', 'u2', 'u3', 'u4', 'u5', 'u6', 'u7', 'u8', 'u9', 'u10', 'ta', 'tb', 'tc') + source = {'a': 0, 'b': 1, 'c': 2} + edge_roles = {}; next_role = 3; pairs = []; gates_at = [] + auxiliary_inputs = []; auxiliary_outputs = []; targets = {} + for vertex in order: + incoming = [i for i, (u, v) in enumerate(FANO_EDGES) if v == vertex] + outgoing = [i for i, (u, v) in enumerate(FANO_EDGES) if u == vertex] + roles = [edge_roles[i] for i in incoming] + if vertex in source: roles.append(source[vertex]) + output_count = len(outgoing)+int(vertex in ('ta', 'tb', 'tc')) + width = max(len(roles), output_count) + require(width in (1, 2), 'Unexpected local width') + while len(roles) < width: + auxiliary_inputs.append((vertex, next_role)) + roles.append(next_role); next_role += 1 + if width == 2: + pairs.append(tuple(roles)); gates_at.append(vertex) + for edge, role in zip(outgoing, roles): edge_roles[edge] = role + occupied = len(outgoing) + if vertex in ('ta', 'tb', 'tc'): + targets[vertex] = roles[occupied]; occupied += 1 + auxiliary_outputs.extend((vertex, r) for r in roles[occupied:]) + require(next_role == 10 and len(pairs) == 14, 'Wrong balanced model size') + outputs = list(targets.values())+[r for v, r in auxiliary_outputs] + require(sorted(outputs) == list(range(next_role)), 'Output roles are not a partition') + return dict(W=next_role, pairs=pairs, gate_vertices=gates_at, + prescribed={0: targets['ta'], 1: targets['tb'], 2: targets['tc']}, + auxiliary_inputs=auxiliary_inputs, auxiliary_outputs=auxiliary_outputs, + edge_roles=[edge_roles[i] for i in range(len(FANO_EDGES))]) + + +def execute(W, pairs, choices): + require(len(pairs) == len(choices), 'One choice per gate required') + rows = [1 << i for i in range(W)] + for (a, b), k in zip(pairs, choices): + values = (0, rows[a], rows[b], rows[a]^rows[b]) + x, y = GL2[k] + rows[a], rows[b] = values[x], values[y] + return tuple(rows) + + +def columns(rows): + W = len(rows) + return tuple(sum(((row >> j) & 1) << i for i, row in enumerate(rows)) for j in range(W)) + + +def assignments(W, pairs): + pairs = tuple(pairs) + def descend(depth, rows, word): + if depth == len(pairs): + yield rows, word + return + a, b = pairs[depth]; x, y = rows[a], rows[b] + values = (0, x, y, x^y) + for k, (s, t) in enumerate(GL2): + new = list(rows); new[a] = values[s]; new[b] = values[t] + yield from descend(depth+1, tuple(new), word+(k,)) + yield from descend(0, tuple(1 << i for i in range(W)), ()) + + +def inverse_choice(k): + for j in range(6): + if execute(2, [(0, 1), (0, 1)], [k, j]) == (1, 2): return j + raise ValueError('GL2 inverse missing') + + +def existence(W, pairs, prescribed=None, half_budget=300000): + """Exact complete search, not a heuristic or solver-unsat certificate.""" + prescribed = dict(prescribed or {}) + require(W >= 2 and all(0 <= i < W and 0 <= j < W for i, j in prescribed.items()), 'Invalid fixed terminals') + require(len(set(prescribed.values())) == len(prescribed), 'Fixed terminal outputs repeat') + require(all(len(p) == 2 and p[0] != p[1] and all(0 <= i < W for i in p) for p in pairs), 'Invalid ports') + split = len(pairs)//2 + require(max(6**split, 6**(len(pairs)-split)) <= half_budget, 'Half-enumeration budget exceeded') + source_fixed = tuple(sorted(prescribed)) + output_fixed = tuple(prescribed[i] for i in source_fixed) + def key(cols, fixed): + return tuple(cols[i] for i in fixed)+tuple(sorted(cols[i] for i in range(W) if i not in fixed)) + width = (W+7)//8 + def packed(key): return b''.join(v.to_bytes(width, 'big') for v in key) + seen = {}; prefix_hash = sha256(); suffix_hash = sha256(); prefix_count = suffix_count = 0 + for rows, word in assignments(W, pairs[:split]): + k = key(columns(rows), source_fixed) + seen.setdefault(k, (rows, word)) + prefix_hash.update(packed(k)); prefix_count += 1 + found = None + for rows, word in assignments(W, list(reversed(pairs[split:]))): + # These are inverse-suffix words. Inversion is a bijection on GL2, + # so this enumeration covers every possible suffix exactly once. + cols = columns(rows); k = key(cols, output_fixed) + suffix_hash.update(packed(k)); suffix_count += 1 + if k not in seen: continue + A, prefix_word = seen[k] + rho = tuple(cols.index(c) for c in columns(A)) + suffix_word = tuple(inverse_choice(j) for j in reversed(word)) + full_word = prefix_word+suffix_word + transfer = execute(W, pairs, full_word) + require(all(transfer[rho[i]] == 1 << i for i in range(W)), 'Recovered scalar permutation is wrong') + require(all(rho[i] == j for i, j in prescribed.items()), 'Recovered terminals are wrong') + found = dict(choices=full_word, rho=rho) + break + return dict(W=W, gates=len(pairs), split=split, prescribed=prescribed, + prefix_assignments=prefix_count, prefix_keys=len(seen), suffix_assignments=suffix_count, + prefix_sha256=prefix_hash.hexdigest(), suffix_sha256=suffix_hash.hexdigest(), + full_assignment_count=6**len(pairs), exists=found is not None, + exhaustive_negative=found is None, witness=found, + scope='Existence with a free permutation of unprescribed roles; not an enumeration of every matching circuit.') diff --git a/research/balanced-fano-performance/benchmark.py b/research/balanced-fano-performance/benchmark.py new file mode 100644 index 0000000000..6408e87686 --- /dev/null +++ b/research/balanced-fano-performance/benchmark.py @@ -0,0 +1,129 @@ +#!/usr/bin/env python3 +"""Sequential fresh-process A/B of the complete fixed balanced-Fano search. + +Uses only the standard library. Run on macOS or Linux; no timing threshold is +an acceptance criterion. Every sample must reproduce the pinned exact result. +Wentao Li, with substantial OpenAI Codex assistance. Apache-2.0. +""" +import argparse +import hashlib +import json +import os +import platform +from pathlib import Path +import random +import resource +import statistics +import subprocess +import sys +import time + +from common import HERE, ROOT, canonical, load_baseline, source_pins + + +def worker(mode): + pins = source_pins() + if mode == 'baseline': + module = load_baseline() + else: + from experiments import balanced_fano as module + model = module.balanced_fano() + wall = time.perf_counter() + cpu = time.process_time() + result = module.existence(model['W'], model['pairs'], model['prescribed']) + cpu = time.process_time() - cpu + wall = time.perf_counter() - wall + if canonical(result) != canonical(pins['expected_result']): + raise ValueError(f'{mode} did not reproduce the complete pinned result') + return { + 'mode': mode, + 'wall_seconds': wall, + 'cpu_seconds': cpu, + 'peak_rss_bytes': resource.getrusage(resource.RUSAGE_SELF).ru_maxrss + * (1 if sys.platform == 'darwin' else 1024), + 'result_sha256': hashlib.sha256(canonical(result)).hexdigest(), + 'input_sha256': hashlib.sha256(canonical(model)).hexdigest(), + } + + +def benchmark(rounds): + pins = source_pins() + env = dict(os.environ, PYTHONHASHSEED='91', PYTHONDONTWRITEBYTECODE='1') + env.pop('PYTHONOPTIMIZE', None) + first = random.Random(91).randrange(2) + modes = ('baseline', 'packed') + samples = [] + for trial in range(rounds): + order = modes if (first + trial) % 2 == 0 else tuple(reversed(modes)) + for mode in order: + start = time.perf_counter() + process = subprocess.run( + [sys.executable, '-B', str(HERE / 'benchmark.py'), '--worker', mode], + cwd=ROOT, env=env, text=True, capture_output=True, check=True) + sample = json.loads(process.stdout) + sample['process_wall_seconds'] = time.perf_counter() - start + sample['round'] = trial + 1 + samples.append(sample) + print(f'round {trial + 1}: {mode} {sample["wall_seconds"]:.3f}s', + file=sys.stderr, flush=True) + if len({r['result_sha256'] for r in samples}) != 1 or len({r['input_sha256'] for r in samples}) != 1: + raise ValueError('Benchmark inputs or exact outputs differ') + medians = { + mode: {field: statistics.median(r[field] for r in samples if r['mode'] == mode) + for field in ('wall_seconds', 'cpu_seconds', 'process_wall_seconds', 'peak_rss_bytes')} + for mode in modes + } + return { + 'status': 'PASS_IDENTICAL_COMPLETE_RESULTS', + 'scope': 'Fixed W=10, 14-gate existence search; not the complete repository suite or selected-frontier replay', + 'base_commit': pins['base_commit'], + 'assignment_seed': 91, + 'rounds': rounds, + 'environment': { + 'python': sys.version, + 'executable': sys.executable, + 'platform': platform.platform(), + 'machine': platform.machine(), + 'cpu_count': os.cpu_count(), + 'python_hash_seed': env['PYTHONHASHSEED'], + }, + 'method': 'Fresh process for each sample, sequential alternating order; caches not flushed, no CPU affinity', + 'source_sha256': { + name: hashlib.sha256((ROOT / name).read_bytes()).hexdigest() + for name in ('scripts/experiments/balanced_fano.py', + 'research/balanced-fano-performance/baseline.py', + 'research/balanced-fano-performance/common.py', + 'research/balanced-fano-performance/benchmark.py', + 'research/balanced-fano-performance/SOURCE.json') + }, + 'expected_result': pins['expected_result'], + 'samples': samples, + 'medians': medians, + 'wall_speedup': medians['baseline']['wall_seconds'] / medians['packed']['wall_seconds'], + 'peak_rss_reduction_fraction': 1 - medians['packed']['peak_rss_bytes'] / medians['baseline']['peak_rss_bytes'], + } + + +def main(): + if sys.flags.optimize: + raise SystemExit('Run the benchmark with assertions enabled') + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument('--rounds', type=int, default=5) + parser.add_argument('--output', type=Path) + parser.add_argument('--worker', choices=('baseline', 'packed'), help=argparse.SUPPRESS) + args = parser.parse_args() + if args.rounds < 1: + parser.error('--rounds must be positive') + if args.output and args.output.exists(): + parser.error('--output must be a fresh path') + result = worker(args.worker) if args.worker else benchmark(args.rounds) + rendered = json.dumps(result, indent=2, sort_keys=True) + '\n' + if args.output: + with args.output.open('x') as stream: + stream.write(rendered) + else: + print(rendered, end='') + + +if __name__ == '__main__': + main() diff --git a/research/balanced-fano-performance/common.py b/research/balanced-fano-performance/common.py new file mode 100644 index 0000000000..7d117bd6c2 --- /dev/null +++ b/research/balanced-fano-performance/common.py @@ -0,0 +1,32 @@ +"""Pinned reference loading for the balanced-Fano performance evidence.""" +import hashlib +import importlib.util +import json +from pathlib import Path +import sys + +HERE = Path(__file__).resolve().parent +ROOT = HERE.parents[1] +sys.path.insert(0, str(ROOT / 'scripts')) + + +def canonical(value): + return json.dumps(value, sort_keys=True, separators=(',', ':')).encode() + + +def source_pins(): + pins = json.loads((HERE / 'SOURCE.json').read_text()) + files = {HERE / 'baseline.py': pins['baseline_sha256']} + files.update({ROOT / name: digest for name, digest in pins['shared_source_sha256'].items()}) + for path, digest in files.items(): + if hashlib.sha256(path.read_bytes()).hexdigest() != digest: + raise ValueError(f'Changed pinned source: {path.relative_to(ROOT)}') + return pins + + +def load_baseline(): + source_pins() + spec = importlib.util.spec_from_file_location('balanced_fano_baseline', HERE / 'baseline.py') + module = importlib.util.module_from_spec(spec) + spec.loader.exec_module(module) + return module diff --git a/scripts/experiments/balanced_fano.py b/scripts/experiments/balanced_fano.py index 136446fa01..2ee1f307da 100644 --- a/scripts/experiments/balanced_fano.py +++ b/scripts/experiments/balanced_fano.py @@ -74,6 +74,33 @@ def descend(depth, rows, word): yield from descend(0, tuple(1 << i for i in range(W)), ()) +def _column_assignments(W, pairs): + """The same ordered assignments, with columns packed into one integer. + + Column j occupies bits W*j through W*j+W-1. A row operation can then + update its two bits in *every* column using masks and shifts, before + unpacking the columns once at each leaf. No assignment is skipped. + """ + pairs = tuple(pairs) + column_mask = (1 << W)-1 + starts = ((1 << (W*W))-1)//column_mask + identity = sum(1 << (i*(W+1)) for i in range(W)) + + def descend(depth, state, word): + if depth == len(pairs): + yield tuple((state >> (W*j)) & column_mask for j in range(W)), word + return + a, b = pairs[depth] + x, y = (state >> a) & starts, (state >> b) & starts + values = (0, x, y, x^y) + other_rows = state & ~((starts << a) | (starts << b)) + for k, (s, t) in enumerate(GL2): + new = other_rows | (values[s] << a) | (values[t] << b) + yield from descend(depth+1, new, word+(k,)) + + yield from descend(0, identity, ()) + + def inverse_choice(k): for j in range(6): if execute(2, [(0, 1), (0, 1)], [k, j]) == (1, 2): return j @@ -95,19 +122,22 @@ def key(cols, fixed): width = (W+7)//8 def packed(key): return b''.join(v.to_bytes(width, 'big') for v in key) seen = {}; prefix_hash = sha256(); suffix_hash = sha256(); prefix_count = suffix_count = 0 - for rows, word in assignments(W, pairs[:split]): - k = key(columns(rows), source_fixed) - seen.setdefault(k, (rows, word)) + for cols, word in _column_assignments(W, pairs[:split]): + k = key(cols, source_fixed) + # The first word reconstructs its columns exactly if a match is found; + # retaining every prefix matrix is unnecessary for existence. + seen.setdefault(k, word) prefix_hash.update(packed(k)); prefix_count += 1 found = None - for rows, word in assignments(W, list(reversed(pairs[split:]))): + for cols, word in _column_assignments(W, list(reversed(pairs[split:]))): # These are inverse-suffix words. Inversion is a bijection on GL2, # so this enumeration covers every possible suffix exactly once. - cols = columns(rows); k = key(cols, output_fixed) + k = key(cols, output_fixed) suffix_hash.update(packed(k)); suffix_count += 1 if k not in seen: continue - A, prefix_word = seen[k] - rho = tuple(cols.index(c) for c in columns(A)) + prefix_word = seen[k] + prefix_cols = columns(execute(W, pairs[:split], prefix_word)) + rho = tuple(cols.index(c) for c in prefix_cols) suffix_word = tuple(inverse_choice(j) for j in reversed(word)) full_word = prefix_word+suffix_word transfer = execute(W, pairs, full_word) diff --git a/tests/test_balanced_fano_performance.py b/tests/test_balanced_fano_performance.py new file mode 100644 index 0000000000..966b4d1d29 --- /dev/null +++ b/tests/test_balanced_fano_performance.py @@ -0,0 +1,138 @@ +"""Exact differential and independent dense controls for packed Fano replay.""" +from hashlib import sha256 +from itertools import product, zip_longest +import json +from pathlib import Path +import random +import sys +import unittest +from unittest.mock import patch + +ROOT = Path(__file__).resolve().parents[1] +sys.path.insert(0, str(ROOT / 'research/balanced-fano-performance')) +from common import canonical, load_baseline, source_pins +from experiments import balanced_fano as packed + + +def dense_columns(W, pairs, word): + """Literal binary matrices: no packed-state or transpose helper calls.""" + rows = [[int(i == j) for j in range(W)] for i in range(W)] + for (a, b), choice in zip(pairs, word): + old_a, old_b = rows[a], rows[b] + for target, coefficients in zip((a, b), packed.GL2[choice]): + rows[target] = [((coefficients % 2)*x + (coefficients // 2)*y) % 2 + for x, y in zip(old_a, old_b)] + return tuple(sum(rows[i][j]*2**i for i in range(W)) for j in range(W)) + + +class PackedFanoReplay(unittest.TestCase): + @classmethod + def setUpClass(cls): + cls.baseline = load_baseline() + + def test_full_fano_streams_match_each_assignment_in_order(self): + model = packed.balanced_fano() + self.assertEqual(model, self.baseline.balanced_fano()) + halves = (model['pairs'][:7], list(reversed(model['pairs'][7:]))) + for pairs in halves: + count = 0 + for old, new in zip_longest(self.baseline.assignments(10, pairs), + packed._column_assignments(10, pairs)): + self.assertIsNotNone(old, 'Extra optimized assignment') + self.assertIsNotNone(new, 'Missing optimized assignment') + rows, word = old + self.assertEqual(new, (self.baseline.columns(rows), word)) + count += 1 + self.assertEqual(count, 279936) + + def test_packed_stream_against_independent_dense_actions(self): + rng = random.Random(91) + for W in (2, 3, 5, 9, 16, 33, 65): + pairs = [tuple(rng.sample(range(W), 2)) for _ in range(3)] + expected_words = product(range(6), repeat=len(pairs)) + count = 0 + for actual, expected_word in zip_longest(packed._column_assignments(W, pairs), expected_words): + self.assertIsNotNone(actual) + self.assertIsNotNone(expected_word) + cols, word = actual + self.assertEqual(word, expected_word) + self.assertEqual(cols, dense_columns(W, pairs, word)) + count += 1 + self.assertEqual(count, 216) + self.assertEqual(list(packed._column_assignments(9, [])), + [(tuple(1 << i for i in range(9)), ())]) + + def test_complete_results_witnesses_and_early_stops_match(self): + rng = random.Random(91) + cases = [(2, [(0, 1)]*4), (3, [(1, 0), (2, 1), (0, 1)]), + (4, [(0, 3), (2, 1), (3, 1), (2, 0), (0, 1)]), (9, [])] + for W in (2, 3, 4, 8, 9, 16, 33, 65): + for gates in range(1, 6): + cases.append((W, [tuple(rng.sample(range(W), 2)) for _ in range(gates)])) + outcomes = set() + for W, pairs in cases: + targets = rng.sample(range(W), W) + prescriptions = ({}, {i: i for i in range(W)}, + {i: targets[i] for i in range(min(W, 3))}) + for prescribed in prescriptions: + old = self.baseline.existence(W, pairs, prescribed) + new = packed.existence(W, pairs, prescribed) + self.assertEqual(new, old) + outcomes.add(new['exists']) + if new['exists']: + witness = new['witness'] + cols = dense_columns(W, pairs, witness['choices']) + self.assertEqual(cols, tuple(1 << i for i in witness['rho'])) + self.assertEqual(outcomes, {True, False}) + + def test_same_input_failures_and_exact_budget_boundary(self): + invalid = [((1, []), {}), ((2, [(0, 0)]), {}), ((2, [(0, 2)]), {}), + ((2, [(-1, 1)]), {}), ((2, [(0, 1, 1)]), {}), + ((2, [(0, 1)], {0: 1, 1: 1}), {}), + ((2, [(0, 1)], {2: 1}), {}), + ((2, [(0, 1)]*4), {'half_budget': 35}), + ((2, []), {'half_budget': 0})] + for args, kwargs in invalid: + messages = [] + for module in (self.baseline, packed): + with self.assertRaises(ValueError) as failure: + module.existence(*args, **kwargs) + messages.append(str(failure.exception)) + self.assertEqual(*messages) + self.assertEqual(packed.existence(2, [(0, 1)]*4, half_budget=36), + self.baseline.existence(2, [(0, 1)]*4, half_budget=36)) + + def test_missing_assignment_changes_the_committed_receipt(self): + # A skipped leaf must be detected even if this closed model still says + # "no completion"; comparing only the Boolean result is insufficient. + original = packed._column_assignments + def omit_last(W, pairs): + iterator = iter(original(W, pairs)) + pending = next(iterator) + for item in iterator: + yield pending + pending = item + model = packed.balanced_fano() + with patch.object(packed, '_column_assignments', omit_last): + result = packed.existence(model['W'], model['pairs'], model['prescribed']) + expected = source_pins()['expected_result'] + self.assertFalse(result['exists']) + self.assertEqual(result['prefix_assignments'], expected['prefix_assignments'] - 1) + self.assertEqual(result['suffix_assignments'], expected['suffix_assignments'] - 1) + self.assertNotEqual(result['prefix_sha256'], expected['prefix_sha256']) + self.assertNotEqual(result['suffix_sha256'], expected['suffix_sha256']) + self.assertNotEqual(canonical(result), canonical(expected)) + + def test_only_historical_source_binding_changes(self): + pins = source_pins() + receipt = json.loads((ROOT / 'certificates/stronger-rank-screens.json').read_text()) + self.assertEqual(canonical(receipt['exact_scalar_search']), canonical(pins['expected_result'])) + source = 'scripts/experiments/balanced_fano.py' + self.assertEqual(receipt['source_sha256'][source], sha256((ROOT / source).read_bytes()).hexdigest()) + receipt['source_sha256'][source] = pins['baseline_sha256'] + original_bytes = (json.dumps(receipt, indent=2, sort_keys=True) + '\n').encode() + self.assertEqual(sha256(original_bytes).hexdigest(), pins['baseline_certificate_sha256']) + + +if __name__ == '__main__': + unittest.main()