diff --git a/research/dihedral-packed-replay/BENCHMARK.json b/research/dihedral-packed-replay/BENCHMARK.json new file mode 100644 index 0000000000..79efbd90d1 --- /dev/null +++ b/research/dihedral-packed-replay/BENCHMARK.json @@ -0,0 +1,169 @@ +{ + "schema_version": 1, + "python": "3.12.15 (main, Oct 14 2026, 00:55:37) [Clang 23.1.3 ]", + "platform": "macOS-27.0.1-arm64-arm-64bit", + "scope": "complete fresh-process replay including startup, pin reads and certificate comparison", + "flags": [ + "-I", + "-O", + "-W", + "error", + "-B" + ], + "pairs": 15, + "rows": [ + { + "pair": 0, + "order": [ + "research/bit-dihedral-commutator/verify.py", + "research/dihedral-packed-replay/run.py" + ], + "baseline_ns": 30877041, + "packed_ns": 22495083 + }, + { + "pair": 1, + "order": [ + "research/dihedral-packed-replay/run.py", + "research/bit-dihedral-commutator/verify.py" + ], + "baseline_ns": 32130500, + "packed_ns": 22420375 + }, + { + "pair": 2, + "order": [ + "research/bit-dihedral-commutator/verify.py", + "research/dihedral-packed-replay/run.py" + ], + "baseline_ns": 31752041, + "packed_ns": 22438875 + }, + { + "pair": 3, + "order": [ + "research/dihedral-packed-replay/run.py", + "research/bit-dihedral-commutator/verify.py" + ], + "baseline_ns": 30607792, + "packed_ns": 22176541 + }, + { + "pair": 4, + "order": [ + "research/bit-dihedral-commutator/verify.py", + "research/dihedral-packed-replay/run.py" + ], + "baseline_ns": 31458041, + "packed_ns": 23190834 + }, + { + "pair": 5, + "order": [ + "research/dihedral-packed-replay/run.py", + "research/bit-dihedral-commutator/verify.py" + ], + "baseline_ns": 30364292, + "packed_ns": 22664833 + }, + { + "pair": 6, + "order": [ + "research/bit-dihedral-commutator/verify.py", + "research/dihedral-packed-replay/run.py" + ], + "baseline_ns": 30705500, + "packed_ns": 22319334 + }, + { + "pair": 7, + "order": [ + "research/dihedral-packed-replay/run.py", + "research/bit-dihedral-commutator/verify.py" + ], + "baseline_ns": 31259834, + "packed_ns": 21783667 + }, + { + "pair": 8, + "order": [ + "research/bit-dihedral-commutator/verify.py", + "research/dihedral-packed-replay/run.py" + ], + "baseline_ns": 30652417, + "packed_ns": 22212917 + }, + { + "pair": 9, + "order": [ + "research/dihedral-packed-replay/run.py", + "research/bit-dihedral-commutator/verify.py" + ], + "baseline_ns": 31565542, + "packed_ns": 22640083 + }, + { + "pair": 10, + "order": [ + "research/bit-dihedral-commutator/verify.py", + "research/dihedral-packed-replay/run.py" + ], + "baseline_ns": 30526834, + "packed_ns": 22711792 + }, + { + "pair": 11, + "order": [ + "research/dihedral-packed-replay/run.py", + "research/bit-dihedral-commutator/verify.py" + ], + "baseline_ns": 31036000, + "packed_ns": 22607542 + }, + { + "pair": 12, + "order": [ + "research/bit-dihedral-commutator/verify.py", + "research/dihedral-packed-replay/run.py" + ], + "baseline_ns": 30776917, + "packed_ns": 21606125 + }, + { + "pair": 13, + "order": [ + "research/dihedral-packed-replay/run.py", + "research/bit-dihedral-commutator/verify.py" + ], + "baseline_ns": 30390291, + "packed_ns": 21779875 + }, + { + "pair": 14, + "order": [ + "research/bit-dihedral-commutator/verify.py", + "research/dihedral-packed-replay/run.py" + ], + "baseline_ns": 29794875, + "packed_ns": 22564375 + } + ], + "baseline_median_ns": 30776917, + "packed_median_ns": 22438875, + "baseline_range_ns": [ + 29794875, + 32130500 + ], + "packed_range_ns": [ + 21606125, + 23190834 + ], + "median_reduction_percent": 27.091868883423253, + "faster_pairs": 15, + "failed_processes": 0, + "stdout_sha256": "e3fcec609ad50af53cd8aad6e20d8b2742fedd403c27f8d0e4600d9a46daf18f", + "source_sha256": { + "research/bit-dihedral-commutator/verify.py": "dff2985bc4ec27d0e527d017471f6e6d43bb7855e555385fc80027aad499735d", + "research/dihedral-packed-replay/run.py": "2fe0708b31277175bed28a5db89c71b298e171d94610d3d8c68768fdc27d4d6e" + } +} diff --git a/research/dihedral-packed-replay/PROFILE.json b/research/dihedral-packed-replay/PROFILE.json new file mode 100644 index 0000000000..2e87dec00f --- /dev/null +++ b/research/dihedral-packed-replay/PROFILE.json @@ -0,0 +1,105 @@ +{ + "scope": "Separate profiled complete commands, excluded from benchmark timings. CPython cProfile instrumentation affects durations.", + "flags": [ + "-I", + "-O", + "-W", + "error", + "-B" + ], + "profiles": { + "original": { + "total_seconds": 0.025667391999999987, + "total_calls": 135568, + "rows": [ + { + "file": "verify.py", + "line": 52, + "function": "run", + "primitive_calls": 1, + "calls": 1, + "own_seconds": 0.00026834600000000004, + "cumulative_seconds": 0.021448292 + }, + { + "file": "verify.py", + "line": 23, + "function": "ball", + "primitive_calls": 2, + "calls": 2, + "own_seconds": 0.002153237, + "cumulative_seconds": 0.018650083 + }, + { + "file": "verify.py", + "line": 13, + "function": "step", + "primitive_calls": 13568, + "calls": 13568, + "own_seconds": 0.010420338000000001, + "cumulative_seconds": 0.0162612 + } + ] + }, + "packed": { + "total_seconds": 0.012817212000000001, + "total_calls": 52152, + "rows": [ + { + "file": "run.py", + "line": 72, + "function": "replay", + "primitive_calls": 1, + "calls": 1, + "own_seconds": 7.5707e-05, + "cumulative_seconds": 0.008882833 + }, + { + "file": "verify.py", + "line": 52, + "function": "run", + "primitive_calls": 1, + "calls": 1, + "own_seconds": 0.000280101, + "cumulative_seconds": 0.007277083 + }, + { + "file": "verify.py", + "line": 23, + "function": "ball", + "primitive_calls": 2, + "calls": 2, + "own_seconds": 0.0024215680000000002, + "cumulative_seconds": 0.0043858330000000004 + }, + { + "file": "run.py", + "line": 56, + "function": "step", + "primitive_calls": 13568, + "calls": 13568, + "own_seconds": 0.00174741, + "cumulative_seconds": 0.00174741 + }, + { + "file": "run.py", + "line": 35, + "function": "load_original", + "primitive_calls": 1, + "calls": 1, + "own_seconds": 2.5400000000000002e-06, + "cumulative_seconds": 0.001376375 + }, + { + "file": "run.py", + "line": 25, + "function": "source_bytes", + "primitive_calls": 1, + "calls": 1, + "own_seconds": 7.627000000000001e-06, + "cumulative_seconds": 0.000158875 + } + ] + } + } +} diff --git a/research/dihedral-packed-replay/README.md b/research/dihedral-packed-replay/README.md new file mode 100644 index 0000000000..560293551a --- /dev/null +++ b/research/dihedral-packed-replay/README.md @@ -0,0 +1,164 @@ +# Packed transitions for the complete D8 replay + +The complete pinned PR1443 replay takes 27.09% less median wall time locally, +30.78 ms versus 22.44 ms, over fifteen alternating fresh-process pairs. Every +pair improves, every process succeeds, and scientific stdout is byte-identical. +This is a small absolute saving, about 8.34 ms per invocation on this host. + +Claim type: scoped implementation-equivalence proof, exact finite conformance, +and local performance evidence. The eight-call mathematical minimum remains +woklerx's PR1443 result. This contribution was produced by Nick Petalas. +No new mathematical minimum, supplier admission or kappa is claimed. + +## The one change + +[run.py](run.py) authenticates the four live inputs in [SOURCES.json](SOURCES.json), +loads the fixed original program with its main block disabled, and replaces +only its `step` function. The original `ball`, `run`, source checks, finite group +law, both complete radius-four searches, state hashes, witness selection, +independent matrix-set products, direct word, eight omission controls and +certificate comparison all remain active. The adapter accepts no arguments +and cannot enter the original `--write` branch. + +The original transition allocates four coefficient cells and loops over the two +columns and rows. The replacement gathers two coefficient bytes into a 16-bit +row, applies two 256-entry delta tables, and scatters the result with one +integer multiplication. It retains 512 delta entries and four scatter constants. +It caches no search states or scientific result across invocations. + +## Equivalence for every packed state + +Write the coefficient matrix as `[[a,c],[b,d]]`, with byte entries. A legal +source generator is `(g,x,y)`, where `x,y` are nonzero two-bit vectors. +Let `L_g` be the original permutation of the eight group coefficients. +On the first column, the original code computes + +```text +v = y_0 a XOR y_1 b +h = v XOR L_g(v) +a' = a XOR x_0 h +b' = b XOR x_1 h +``` + +The second column follows the identical rule on `c,d`. The packed code gathers +`R = (y_0 (a | c<<8)) XOR (y_1 (b | d<<8))`. Its low and high bytes are exactly +the two original `v` values. The precomputed table is `D_g(v)=v XOR L_g(v)`. +Consequently `H=D_g(R_low) | D_g(R_high)<<8` contains precisely both deltas. +Multiplying `H` by `x_0 + 2^16 x_1` puts those deltas in exactly the selected +rows. Since `0<=H<2^16`, its two copies have disjoint bits and introduce no +arithmetic carry. XOR with the original state gives the same four output bytes. + +Thus the replacement agrees for all `2^32` packed states and all twelve legal +generators. This written argument supplies the universal state quantifier; +the program does not enumerate four billion states. Deterministic transitions +with unchanged search order give identical first-witness maps by induction on +search depth. Neither argument changes or re-establishes the predecessor's +mathematical minimum. + +## Exact checks + +[verify.py](verify.py) checks all 65,536 byte pairs in each column for every +legal generator, totaling 1,572,864 comparisons. It compares every state and +first witness in both complete balls. Their union has 5,650 states, and all +67,800 outgoing transitions agree. It also runs both complete scientific +calculations and requires equality of the full certificate payload. + +Eleven controls cover missing/short/out-of-range tables, an incorrect coefficient +permutation, scatter, label and dropped row, and independent corruption of each +of the four live source inputs. Source mutations occur through read interception; +no source file is edited. The same checks run with assertions disabled. The +verifier prints a generated receipt containing counts and every package file's +SHA256. It neither writes nor regenerates a stored scientific receipt. + +## Timing evidence and limits + +[BENCHMARK.json](BENCHMARK.json) contains all thirty full-process measurements, +flags, environment, source hashes, stdout hash and statistics. CPython 3.12.15 +on macOS arm64 was used. The original command's range was 29.79 to 32.13 ms; +the adapter's range was 21.61 to 23.19 ms. The ranges do not overlap. Each pair +alternates its first side. Both sides use `-I -O -W error -B` and the exact same +complete fixture. Startup, table construction, pin reads, original scientific +checks and certificate comparison are inside the timed region. There were zero +failed processes and every stdout matched the exact expected success output. + +[PROFILE.json](PROFILE.json) records separate instrumented executions, excluded +from the timing sample. The original transition has 13,568 calls and dominates +the search cost. The adapter removes the repeated cell allocation and Python +row/column loops. Process startup, imports, unchanged search bookkeeping and +independent witness checks limit the complete-command gain. The median wall +saving is smaller than the original transition's profiled cumulative time. + +The host was shared, with eighteen logical CPUs and load averages 3.82, 3.33, +2.83 at intake. Alternation limits drift; it does not isolate every scheduling +or filesystem-cache effect. Fresh processes do not imply a cold filesystem. +The claim is local to this short command and host. Hosted CI checks exact +conformance and execution, not the timing percentage or acceptance of the proof. +No selected scientific cold replay, native implementation, physical caller, +compiler closure, tape/precision proof, Lean or Docker job is provided or run. +The five selected framework assumptions remain. + +## Reproduce + +From the repository root, the exact local interpreter is +`/Users/nick/git/integer-mult-bounds/.venv/bin/python3.12`. +Another CPython 3.12 installation can run the same standard-library commands. + +```sh +/Users/nick/git/integer-mult-bounds/.venv/bin/python3.12 -I -O -W error -B research/dihedral-packed-replay/run.py +/Users/nick/git/integer-mult-bounds/.venv/bin/python3.12 -I -W error -B research/dihedral-packed-replay/verify.py +/Users/nick/git/integer-mult-bounds/.venv/bin/python3.12 -I -O -W error -B research/dihedral-packed-replay/verify.py +/Users/nick/git/integer-mult-bounds/.venv/bin/python3.12 -B scripts/research_package.py --package research/dihedral-packed-replay +/Users/nick/git/integer-mult-bounds/.venv/bin/python3.12 -B scripts/check_research_commit.py --package research/dihedral-packed-replay --check-source-history +``` + +The adapter prints the unchanged `PASS_DIHEDRAL_COMMUTATOR` line. Conformance +prints `PASS_DIHEDRAL_PACKED_REPLAY`. The registered hook and publication checks +print `PASS_REGISTERED_RESEARCH_PACKAGE` and `PASS_RESEARCH_COMMIT_BYTES`. + +For new local timings, use `benchmark.py --pairs 15 --out /path/to/new/benchmark.json` +with the same interpreter. The output path must not exist. The driver uses +bounded thirty-second children, counts errors by failing on any unsuccessful +or differing output, and times fresh complete invocations. Timings are optional +and are excluded from CI acceptance. To inspect the limiter, profile each +complete command separately with Python's `-m cProfile -o /path/to/new/profile`. + +## Implementation bounds + +The adapter runs the unchanged depth-four search and builds only two 256-entry +delta tables. The conformance domain and all controls have explicit finite +bounds. The optional benchmark accepts five through fifty pairs and runs its +children sequentially. All new functions fit within sixty physical lines. + +Python's managed allocation is a declared deviation from allocation-free steady +operation. Live search memory is bounded by the fixed two-register depth-four +fixture. Integer widths stay within the source's 32-bit state and intermediate +scatter bounds. Dynamic source execution is limited to the fixed, authenticated +predecessor script with its main block disabled; dynamic importing is limited +to the local adapter. Read interception has four explicit mutation targets. +These mechanisms preserve source checks and do not execute supplied text. + +## Open next questions + +Can a table of complete column transitions repay initialization and memory costs +on a genuinely larger complete replay? First pin that larger fixture and compare +full-process time, including construction and exact conformance. The present +512-entry method and short fixture do not establish such a gain. No larger +implementation or follow-on optimization is reserved here. + +## Credit and overlap + +Credit woklerx / [PR1443](https://github.com/CrocSwap/integer-mult-bounds/pull/1443) +for the source replay, complete balls, exact certificate, independent matrix-set +checks and mathematical result. Retain its scalar-idempotent normalization +lineage through Ali Romman, eumemic / PR288 and Gareth Davidson / PR1333. +Original source notices remain unchanged. The new adapter, equivalence argument, +conformance checks and timing driver were produced by Nick Petalas. Apache-2.0. + +The [advance claim](https://github.com/CrocSwap/integer-mult-bounds/discussions/1166#discussioncomment-19363476) +pins canonical main `7c49fe32c55de02c2c873655c804b16e4c3fef0a`, priority revision 8 +and selected PR6030. The card is refined to this source-bound runtime step. +Open/account PRs, recent handoffs, local reservations, distinctive main-tree +terms and merged D8/UT3 runtime searches found no matching transition adapter +in their coverage. Sparse notes, unpublished work and arbitrary historical diffs +remain outside that coverage. The source's larger-register question has known +successors; this package does not target or re-audit that question. diff --git a/research/dihedral-packed-replay/SOURCES.json b/research/dihedral-packed-replay/SOURCES.json new file mode 100644 index 0000000000..1ee4afdbf4 --- /dev/null +++ b/research/dihedral-packed-replay/SOURCES.json @@ -0,0 +1,42 @@ +{ + "schema_version": 1, + "base_commit": "7c49fe32c55de02c2c873655c804b16e4c3fef0a", + "files": [ + { + "path": "certificates/selected-result.json", + "usage": "provenance", + "git_blob": "d59b5035e7b4cbaa9d688a1d32dd0d6eb79c466a", + "sha256": "9b8d0eea95b3bf0dfcb7938a732a6439b87a2685dec2a5ab9e525b3b34debbfa" + }, + { + "path": "docs/research/agent-task-catalog.json", + "usage": "provenance", + "git_blob": "3404fbdd5e7529a0674eef26114b5071e4586cec", + "sha256": "ead6cdc9d0af6d58e8a49744d8ec8c7c15e13d2ba93c276c434bcf9b51b93a81" + }, + { + "path": "research/bit-dihedral-commutator/CERTIFICATE.json", + "usage": "input", + "git_blob": "a52cee87ee16903ccd95a6872788e66a7a029202", + "sha256": "8ec4519a34ab5c6eca6dea92b90aa317c851c566040caf89d822d1d96c70a8c5" + }, + { + "path": "research/bit-dihedral-commutator/SOURCES.json", + "usage": "input", + "git_blob": "853900add7c066a31a47d5e50a854b2843798baa", + "sha256": "8b54ff152eaa87502cb88da77da0e73a2606e60f83c69ca5b9b60ff42f526ccd" + }, + { + "path": "research/bit-dihedral-commutator/verify.py", + "usage": "input", + "git_blob": "30c04afbc7f457f381143f57fc87a479dc9a36fa", + "sha256": "dff2985bc4ec27d0e527d017471f6e6d43bb7855e555385fc80027aad499735d" + }, + { + "path": "research/bit-three-register-lower-bound/README.md", + "usage": "input", + "git_blob": "25e41c370c101a33a6deb978de08b03ed7539b79", + "sha256": "c12b33ef388deece0cbf891505a2ce2c0779a0c3a6cf1f0f7f7039bab59cbebd" + } + ] +} diff --git a/research/dihedral-packed-replay/TASK.json b/research/dihedral-packed-replay/TASK.json new file mode 100644 index 0000000000..94aef6a1f4 --- /dev/null +++ b/research/dihedral-packed-replay/TASK.json @@ -0,0 +1,61 @@ +{ + "schema_version": 1, + "task_id": "replay-runtime", + "priority_revision": 8, + "base_commit": "7c49fe32c55de02c2c873655c804b16e4c3fef0a", + "original_card": { + "id": "replay-runtime", + "question": "Can one measured replay bottleneck be sped up without dropping coverage?", + "starting_points": [ + "scripts/run_isolated_tests.py", + "scripts/verify_replay_coverage.py", + "certificates/selected-result.json" + ], + "methods": [ + "Profile one isolated replay and optimize the measured bottleneck.", + "Design source-bound reuse with explicit dependency invalidation and negative controls." + ], + "acceptance_gate": "Report before/after wall time on the same fixture, retained checks and invalidation behavior.", + "first_step": { + "command": [ + "python3", + "-B", + "scripts/research_selected_baseline.py" + ], + "expected": "PASS_RESEARCH_BASELINE_BINDINGS_ONLY", + "inspect": "Resolve the current selected review, separate complex/ordinary BIT/admitted BIT/outer budgets, and compare the card against live handoffs before starting. Historical ceilings require exact source/model equivalence.", + "scope": "Source-binding orientation only; not a scientific replay or all-size proof. Materialize selected inputs if this checkout is sparse." + }, + "first_experiment": "Measure one unchanged fixture, preserve check coverage, and test one optimization with invalidation controls.", + "bottleneck_link": "Faster trustworthy replays increase review throughput and let mechanism candidates be checked sooner.", + "allowed_variations": [ + "Profile one stage or design one source-bound cache boundary." + ], + "scope_change_triggers": [ + "Skipping coverage or comparing different fixtures to claim speedup." + ], + "overlap_terms": [ + "replay runtime", + "cache invalidation", + "isolated tests" + ] + }, + "scope_status": "refined", + "actual_scope": "Speed up the complete pinned two-register D8 commutator replay through a packed two-column transition, retaining every original search, certificate and rejection control.", + "scope_change_reason": "Refine the runtime card to one source-bound exact transition replacement. The predecessor mathematical theorem is cited, not an audit deliverable.", + "bottleneck_link": "A small verifier-engineering result reduces repeated execution cost for this exact historical replay. It does not move the binding supplier or kappa.", + "budget_minutes": 60, + "stop_rule": "Stop optimization at the first exact implementation with a reproducible complete-process speedup; retain follow-on ideas as questions.", + "outcome": "completed", + "evidence": "README.md gives the transition-equivalence proof. verify.py checks 1,572,864 column cases, 67,800 reached-state transitions, complete ball witness maps, complete scientific results and eleven controls. BENCHMARK.json retains fifteen alternating fresh-process pairs with no failures.", + "author": "Nick Petalas", + "ai_assistance": "Independent human and formal proof-kernel review are unclaimed.", + "open_questions": [ + { + "question": "Can a direct table of complete column transitions repay its initialization and memory costs on a genuinely larger declared replay?", + "why_it_matters": "The current packed-byte method avoids a large table; a larger workload might amortize one.", + "first_step": "Choose and pin one larger complete replay, then count table initialization, storage and full-process time alongside exact conformance.", + "blocked_by": "No larger fixture or table implementation is supplied; the present result makes no such performance claim." + } + ] +} diff --git a/research/dihedral-packed-replay/VERIFY.json b/research/dihedral-packed-replay/VERIFY.json new file mode 100644 index 0000000000..7dca2f8bc2 --- /dev/null +++ b/research/dihedral-packed-replay/VERIFY.json @@ -0,0 +1,52 @@ +{ + "schema_version": 1, + "status": "ready", + "python": "3.12", + "requirements": [], + "inputs": [ + "research/bit-dihedral-commutator/CERTIFICATE.json", + "research/bit-dihedral-commutator/SOURCES.json", + "research/bit-dihedral-commutator/verify.py", + "research/bit-three-register-lower-bound/README.md" + ], + "commands": [ + { + "argv": [ + "{python}", + "-I", + "-O", + "-W", + "error", + "-B", + "{package}/run.py" + ], + "timeout_seconds": 60, + "checks": "Complete pinned scientific replay using packed transitions, original source checks, both radius-four balls, state hashes, independent matrix-set witness, eight omissions and full certificate equality." + }, + { + "argv": [ + "{python}", + "-I", + "-W", + "error", + "-B", + "{package}/verify.py" + ], + "timeout_seconds": 120, + "checks": "Exhaustive column conformance, every reached transition and both complete first-witness maps, full-result equality, malformed tables, wrong transitions and four live-source mutation controls." + }, + { + "argv": [ + "{python}", + "-I", + "-O", + "-W", + "error", + "-B", + "{package}/verify.py" + ], + "timeout_seconds": 120, + "checks": "Exhaustive column conformance, every reached transition and both complete first-witness maps, full-result equality, malformed tables, wrong transitions and four live-source mutation controls." + } + ] +} diff --git a/research/dihedral-packed-replay/benchmark.py b/research/dihedral-packed-replay/benchmark.py new file mode 100644 index 0000000000..f026daaf01 --- /dev/null +++ b/research/dihedral-packed-replay/benchmark.py @@ -0,0 +1,65 @@ +"""Measure fresh complete predecessor and packed-adapter processes. Apache-2.0.""" +import argparse +import hashlib +import json +import platform +import statistics +import subprocess +import sys +import time +from pathlib import Path + +ROOT = Path(__file__).resolve().parents[2] +BASELINE = "research/bit-dihedral-commutator/verify.py" +PACKED = "research/dihedral-packed-replay/run.py" +EXPECTED = (b"PASS_DIHEDRAL_COMMUTATOR minimum=8 layers=[1, 12, 80, 472, 2459] " + b"meetings={'8': 398}\n") + + +def measure(path): + command = [sys.executable, "-I", "-O", "-W", "error", "-B", path] + started = time.perf_counter_ns() + result = subprocess.run(command, cwd=ROOT, capture_output=True, timeout=30, check=True) + elapsed = time.perf_counter_ns() - started + if result.stdout != EXPECTED or result.stderr: + raise ValueError("unexpected complete scientific output: " + path) + return elapsed + + +def main(): + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument("--pairs", type=int, default=15) + parser.add_argument("--out", type=Path, required=True) + args = parser.parse_args() + if not 5 <= args.pairs <= 50: + parser.error("pairs must be in [5, 50]") + if args.out.exists(): + parser.error("output must not exist") + rows = [] + for pair in range(args.pairs): + order = (BASELINE, PACKED) if pair % 2 == 0 else (PACKED, BASELINE) + values = {path: measure(path) for path in order} + rows.append({"pair": pair, "order": list(order), "baseline_ns": values[BASELINE], + "packed_ns": values[PACKED]}) + before = [row["baseline_ns"] for row in rows] + after = [row["packed_ns"] for row in rows] + mb, ma = statistics.median(before), statistics.median(after) + result = {"schema_version": 1, "python": sys.version, "platform": platform.platform(), + "scope": "complete fresh-process replay including startup, pin reads and certificate comparison", + "flags": ["-I", "-O", "-W", "error", "-B"], "pairs": args.pairs, "rows": rows, + "baseline_median_ns": mb, "packed_median_ns": ma, + "baseline_range_ns": [min(before), max(before)], + "packed_range_ns": [min(after), max(after)], "median_reduction_percent": 100 * (1 - ma / mb), + "faster_pairs": sum(a < b for a, b in zip(after, before)), "failed_processes": 0, + "stdout_sha256": hashlib.sha256(EXPECTED).hexdigest(), + "source_sha256": {path: hashlib.sha256((ROOT / path).read_bytes()).hexdigest() + for path in (BASELINE, PACKED)}} + with args.out.open("x") as stream: + json.dump(result, stream, indent=2) + stream.write("\n") + print(json.dumps({key: result[key] for key in ("pairs", "baseline_median_ns", "packed_median_ns", + "median_reduction_percent", "faster_pairs", "failed_processes")}, sort_keys=True)) + + +if __name__ == "__main__": + main() diff --git a/research/dihedral-packed-replay/run.py b/research/dihedral-packed-replay/run.py new file mode 100644 index 0000000000..040a3fe817 --- /dev/null +++ b/research/dihedral-packed-replay/run.py @@ -0,0 +1,90 @@ +"""Packed transition adapter for the pinned PR1443 replay. Apache-2.0.""" +import hashlib +import json +import sys +from pathlib import Path + +ROOT = Path(__file__).resolve().parents[2] +PINS = ( + ('research/bit-dihedral-commutator/CERTIFICATE.json', + '8ec4519a34ab5c6eca6dea92b90aa317c851c566040caf89d822d1d96c70a8c5'), + ('research/bit-dihedral-commutator/SOURCES.json', + '8b54ff152eaa87502cb88da77da0e73a2606e60f83c69ca5b9b60ff42f526ccd'), + ('research/bit-dihedral-commutator/verify.py', + 'dff2985bc4ec27d0e527d017471f6e6d43bb7855e555385fc80027aad499735d'), + ('research/bit-three-register-lower-bound/README.md', + 'c12b33ef388deece0cbf891505a2ce2c0779a0c3a6cf1f0f7f7039bab59cbebd'), +) + + +def require(ok, message): + if not ok: + raise ValueError(message) + + +def source_bytes(root=ROOT): + """Authenticate every executable/data input before executing fixed source.""" + contents = {} + for name, digest in PINS: + raw = (root / name).read_bytes() + require(hashlib.sha256(raw).hexdigest() == digest, "source pin: " + name) + contents[name] = raw + return contents + + +def load_original(root=ROOT): + contents = source_bytes(root) + name = "research/bit-dihedral-commutator/verify.py" + path = root / name + namespace = {"__file__": str(path), "__name__": "pinned_dihedral_original"} + # This is only the hash-authenticated, fixed predecessor program. Its main + # block, including the explicit --write option, is never entered. + exec(compile(contents[name], str(path), "exec"), namespace) + return namespace + + +def packed_step(permutations): + require(set(permutations) == {1, 2}, "two paid label tables") + tables = {} + for label in (1, 2): + values = permutations[label] + require(len(values) == 256 and all(0 <= v < 256 for v in values), + "byte permutation range") + tables[label] = tuple(v ^ values[v] for v in range(256)) + scatter = (0, 1, 1 << 16, (1 << 16) + 1) + + def step(state, generator): + label, x, y = generator + # Each 16-bit row holds the two independent coefficient bytes. + if y == 1: + row = state + elif y == 2: + row = state >> 16 + else: + row = state ^ (state >> 16) + table = tables[label] + delta = table[row & 255] | (table[(row >> 8) & 255] << 8) + return state ^ (delta * scatter[x]) + + return step + + +def replay(): + original = load_original() + original["step"] = packed_step(original["PERM"]) + result = json.loads(json.dumps(original["run"]())) + certificate = json.loads((original["H"] / "CERTIFICATE.json").read_text()) + require(result == certificate, "complete original certificate") + return result + + +def main(): + require(len(sys.argv) == 1, "this replay accepts no arguments") + result = replay() + print(result["status"], "minimum=" + str(result["minimum"]), + "layers=" + str(result["identity_layers"]), + "meetings=" + str(result["meeting_lengths"])) + + +if __name__ == "__main__": + main() diff --git a/research/dihedral-packed-replay/verify.py b/research/dihedral-packed-replay/verify.py new file mode 100644 index 0000000000..f8ce7e9210 --- /dev/null +++ b/research/dihedral-packed-replay/verify.py @@ -0,0 +1,119 @@ +"""Exact conformance of the packed PR1443 transition. Apache-2.0.""" +import hashlib +import importlib.util +import json +from pathlib import Path +from unittest.mock import patch + +HERE = Path(__file__).resolve().parent + + +def require(ok, message): + if not ok: + raise ValueError(message) + + +def load_adapter(): + spec = importlib.util.spec_from_file_location("dihedral_adapter", HERE / "run.py") + require(spec is not None and spec.loader is not None, "adapter loader") + module = importlib.util.module_from_spec(spec) + spec.loader.exec_module(module) + return module + + +def columns(original, fast): + count = 0 + for generator in original["GEN"]: + for pair in range(1 << 16): + first = (pair & 255) | ((pair >> 8) << 16) + for state in (first, first << 8): + require(fast(state, generator) == original["step"](state, generator), + "single-column transition") + count += 1 + return count + + +def balls(original, fast): + reference = original["step"] + states = set() + for start in (original["IDENTITY"], original["TARGET"]): + expected, layers = original["ball"](start, 4) + original["step"] = fast + actual, actual_layers = original["ball"](start, 4) + original["step"] = reference + require(actual == expected and actual_layers == layers, + "every ball state and its first witness") + states.update(expected) + count = 0 + for state in sorted(states): + for generator in original["GEN"]: + require(fast(state, generator) == reference(state, generator), + "all reached-state transitions") + count += 1 + return len(states), count + + +def expect_failure(call, label): + try: + call() + except ValueError: + return + raise ValueError("control accepted: " + label) + + +def controls(adapter, original, fast): + permutations = original["PERM"] + expect_failure(lambda: adapter.packed_step({1: permutations[1]}), "missing label") + expect_failure(lambda: adapter.packed_step({1: [], 2: permutations[2]}), "short table") + invalid = {key: list(value) for key, value in permutations.items()} + invalid[1][0] = 256 + expect_failure(lambda: adapter.packed_step(invalid), "non-byte value") + changed = {key: list(value) for key, value in permutations.items()} + changed[1][1], changed[1][2] = changed[1][2], changed[1][1] + mutant = adapter.packed_step(changed) + probes = [(state, generator) for state in (1, 2, 256, 65536, 0x12345678) + for generator in original["GEN"]] + require(any(mutant(s, g) != fast(s, g) for s, g in probes), "wrong permutation rejected") + require(any(fast(s, (g, 3 if x == 1 else 1, y)) != fast(s, (g, x, y)) + for s, (g, x, y) in probes), "wrong scatter rejected") + require(any(fast(s, (3 - g, x, y)) != fast(s, (g, x, y)) + for s, (g, x, y) in probes), "wrong label rejected") + require(any((fast(s, g) & 0xFFFF) != fast(s, g) for s, g in probes), + "discarded second row rejected") + return 7 + + +def source_controls(adapter): + read = Path.read_bytes + for name, _ in adapter.PINS: + target = adapter.ROOT / name + + def changed(path): + raw = read(path) + return raw + b"corrupt" if path == target else raw + + with patch.object(Path, "read_bytes", changed): + expect_failure(adapter.source_bytes, "changed source: " + name) + return len(adapter.PINS) + + +def main(): + adapter = load_adapter() + original = adapter.load_original() + fast = adapter.packed_step(original["PERM"]) + column_checks = columns(original, fast) + states, reached_checks = balls(original, fast) + rejected = controls(adapter, original, fast) + source_controls(adapter) + expected = json.loads(json.dumps(original["run"]())) + actual = adapter.replay() + require(actual == expected, "complete original scientific result") + hashes = {path.name: hashlib.sha256(path.read_bytes()).hexdigest() + for path in sorted(HERE.iterdir()) if path.is_file()} + print(json.dumps({"status": "PASS_DIHEDRAL_PACKED_REPLAY", "column_checks": column_checks, + "reached_states": states, "reached_transition_checks": reached_checks, + "controls": rejected, "minimum": actual["minimum"], + "complete_certificate_equal": True, "package_sha256": hashes}, sort_keys=True)) + + +if __name__ == "__main__": + main()