From 6e222517e182e98499239bc9a4009f540e1c5520 Mon Sep 17 00:00:00 2001 From: Chafik Boukhalfa Date: Wed, 14 Oct 2026 20:22:46 +0400 Subject: [PATCH] Realize the P104 low-rank channel with exact native Clifford recipes --- .github/workflows/p104-native-channel.yml | 42 + research/p104-native-channel/EXPECTED.json | 35 + .../NATIVE-RECIPES.json.gz | Bin 0 -> 53882 bytes research/p104-native-channel/PROOF.md | 100 + research/p104-native-channel/README.md | 91 + research/p104-native-channel/SOURCES.json | 87 + research/p104-native-channel/SUMMARY.json | 23 + research/p104-native-channel/TASK.json | 66 + research/p104-native-channel/VERIFY.json | 21 + research/p104-native-channel/check_native.py | 141 ++ research/p104-native-channel/compile.py | 118 ++ .../inputs/LOWRANK-RESULT.json | 28 + .../inputs/LOWRANK-WITNESS.json | 1 + .../inputs/P104-FIXTURE.json | 1713 +++++++++++++++++ .../notices/FRAME-SA504-NOTICE.md | 24 + .../notices/PR1862-NOTICE.md | 50 + .../notices/PR1972-NOTICE.md | 11 + .../vendor/clifford_exact.py | 149 ++ .../vendor/native_verify.py | 277 +++ research/p104-native-channel/verify.py | 34 + 20 files changed, 3011 insertions(+) create mode 100644 .github/workflows/p104-native-channel.yml create mode 100644 research/p104-native-channel/EXPECTED.json create mode 100644 research/p104-native-channel/NATIVE-RECIPES.json.gz create mode 100644 research/p104-native-channel/PROOF.md create mode 100644 research/p104-native-channel/README.md create mode 100644 research/p104-native-channel/SOURCES.json create mode 100644 research/p104-native-channel/SUMMARY.json create mode 100644 research/p104-native-channel/TASK.json create mode 100644 research/p104-native-channel/VERIFY.json create mode 100644 research/p104-native-channel/check_native.py create mode 100644 research/p104-native-channel/compile.py create mode 100644 research/p104-native-channel/inputs/LOWRANK-RESULT.json create mode 100644 research/p104-native-channel/inputs/LOWRANK-WITNESS.json create mode 100644 research/p104-native-channel/inputs/P104-FIXTURE.json create mode 100644 research/p104-native-channel/notices/FRAME-SA504-NOTICE.md create mode 100644 research/p104-native-channel/notices/PR1862-NOTICE.md create mode 100644 research/p104-native-channel/notices/PR1972-NOTICE.md create mode 100644 research/p104-native-channel/vendor/clifford_exact.py create mode 100644 research/p104-native-channel/vendor/native_verify.py create mode 100644 research/p104-native-channel/verify.py diff --git a/.github/workflows/p104-native-channel.yml b/.github/workflows/p104-native-channel.yml new file mode 100644 index 0000000000..b3c64ed80f --- /dev/null +++ b/.github/workflows/p104-native-channel.yml @@ -0,0 +1,42 @@ +name: P104 exact native low-rank channel + +on: + pull_request: + paths: + - research/p104-native-channel/** + - .github/workflows/p104-native-channel.yml + push: + branches: + - codex/p104-native-channel-20261014 + paths: + - research/p104-native-channel/** + - .github/workflows/p104-native-channel.yml + workflow_dispatch: + +permissions: + contents: read + +jobs: + verify: + runs-on: ubuntu-latest + timeout-minutes: 8 + strategy: + fail-fast: false + matrix: + python: ['3.11', '3.12', '3.14'] + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + - uses: actions/setup-python@v5 + with: + python-version: ${{ matrix.python }} + - name: Validate registered package metadata + run: python scripts/research_package.py --package research/p104-native-channel --check-only + - name: Independent native replay and complete regeneration + run: python -I -O -B research/p104-native-channel/verify.py --regenerate --out "$RUNNER_TEMP/native-channel.json" + - uses: actions/upload-artifact@v4 + with: + name: p104-native-channel-${{ matrix.python }} + path: ${{ runner.temp }}/native-channel.json + if-no-files-found: error diff --git a/research/p104-native-channel/EXPECTED.json b/research/p104-native-channel/EXPECTED.json new file mode 100644 index 0000000000..c7c818d402 --- /dev/null +++ b/research/p104-native-channel/EXPECTED.json @@ -0,0 +1,35 @@ +{ + "all_physical_pairings": 14400, + "all_private_copy_gaussian_columns": 4096, + "controls": { + "global_phase": true, + "missing_final_query_cleanup": true, + "missing_initial_query_compensation": true, + "missing_transport": true, + "physical_label": true + }, + "formal_boundary_columns": 280, + "intrinsic_endpoint_adapters": 208, + "paid_profile": { + "1": 1074, + "2": 58, + "3": 86, + "4": 104, + "5": 48, + "6": 24, + "7": 8, + "8": 8 + }, + "rank_mass": 2368, + "recipes_raw_sha256": "0aa152945ffe3797e8295cd17d4ec6646ba24a93372ec35b16c0b164d9858529", + "scalar_events": { + "add": 2624, + "copy": 8, + "erase": 8, + "zero": 8 + }, + "scope": "Concrete finite Clifford primitives plus a complete framed induction over all 280 arbitrary channel inputs, source gathering and 72 dirty helper restorations. No I-G/2 side correction, global helper assignment, precision, all-size admission or new kappa.", + "source_witness_sha256": "0f541bef7f19fdeffd67157684e9f03d785f42c89973632f508fc1a0452b580e", + "status": "PASS_CONCRETE_NATIVE_P104_LOW_RANK_CHANNEL", + "transports": 740 +} diff --git a/research/p104-native-channel/NATIVE-RECIPES.json.gz b/research/p104-native-channel/NATIVE-RECIPES.json.gz new file mode 100644 index 0000000000000000000000000000000000000000..ab129678c2df4f0d39b02b88457d02c37de0d9b6 GIT binary patch literal 53882 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 Q{J($r|B*>Mcdeuo05mbBY5)KL literal 0 HcmV?d00001 diff --git a/research/p104-native-channel/PROOF.md b/research/p104-native-channel/PROOF.md new file mode 100644 index 0000000000..a69311b74f --- /dev/null +++ b/research/p104-native-channel/PROOF.md @@ -0,0 +1,100 @@ +# Finite native realization and its boundary + +## 1. Physical labels + +Reconstruct the 120 root lines from doubled integer E8 coordinates. Write +`B[i,j] = (+1) mod 2`. Its rank is nine. Select nine independent +principal coordinates as recorded in `label_isometry`. The compressed labels +`l_i` do **not** use the ordinary dot product: their pairing matrix is `J`, +the inverse of the recorded nonsingular compressed Gram matrix. + +Find a `J`-orthonormal basis `v_0,...,v_8` and set +`q(l)_a = l^t J v_a`. The independent checker reconstructs the roots and Gram +matrix without producer imports, checks the inverse and orthonormality, and +verifies every one of the 120^2 identities +`q(l_i) dot q(l_j) = B[i,j]`. +The map is a linear isometry on the whole nine-dimensional binary space, so +it applies to every intermediate frame, including labels outside the 120 roots. +Each root label is odd because `B[i,i]=1`. + +This is a concrete finite choice of physical labels. It is not an all-size +admission proof for an extended label alphabet. + +## 2. Complete primitive identities + +Use the retained canonical chart `Gamma_W` for a binary frame `W`. A literal +transport from `A` to `B` is `Gamma_B Gamma_A^-1`. Every transport is nested. +The exact compiler emits a Gaussian monomial, one positive child of rank +`|dim B-dim A|`, and another Gaussian monomial. No rank is inferred merely +from scalar event counts. There are 740 distinct recipes and 1410 paid uses; +the checker binds every use to its literal source-witness event and rank. + +The independent interpreter imports no Clifford compiler. It compares signed +Pauli conjugations and an exact Gaussian state column. Equal signed Pauli +actions determine a Clifford up to scalar phase; equality on the nonzero state +column fixes that phase. Thus this checks the complete operator, not only its +unsigned symplectic matrix. In addition, all 512 Gaussian columns of each of +the eight rank-seven private drops are compared directly: 4096 columns total. + +Let `C_q = ((1+i)I+(1-i)X_q)/2` and `F9 = product_a C_ea`. +For each source root the intrinsic input chart is `C_q`; its recorded adapter +is `Gamma_ C_q^-1`. For each target the intrinsic output chart is +`F9 C_q^-1`; its adapter is `F9 C_q^-1 Gamma_(q-perp)^-1`. +All 208 operators independently check as rank-zero Gaussian monomials, +including their phases. The final source and dirty-helper full charts are +already `F9`. Monomial endpoints add no positive child to this finite invoice. + +## 3. Full channel induction + +For each live register maintain a rational row `a_r` over the 280 independent +logical inputs. Its physical value is `Gamma_(W_r) a_r z`. +The entry adapters establish this invariant for the 104 intrinsic source +inputs. All other inputs start in the zero frame. + +- A verified native transport changes only `W_r`, retaining `a_r`. +- A literal scalar addition is allowed only in a common physical chart; it + changes `a_r` by the stated exact rational row addition. +- Owned private initialization creates the zero row, copying requires that + zero row and the same chart, and discard requires the prescribed owned + private register and chart. These are the inherited private-copy semantics, + not a claim that a live copy was reversibly uncomputed to zero. + +Inducting through every event proves the complete physical composition. The +checker reconstructs the expected ordinary Gram matrix directly from root +coordinates. At the end each source and each of the 72 dirty helper rows is +its original logical input; each target row is +`y_t + sum_s x_s/2`. +Every endpoint frame also matches. Applying the target exit adapters gives +the stated intrinsic output charts. This covers arbitrary address functions, +not only scalar samples: the rows are identities of operators under the +verified common-chart invariant. + +The source witness is hash-pinned to PR1972. None of its gather, dirty +compensation, delivery or query-cleanup algorithms is newly claimed here. +The new step proves that its abstract chart cancellations have this particular +exact native realization. + +## 4. Accounting and controls + +The independent occurrence recount gives +`{1:1074,2:58,3:86,4:104,5:48,6:24,7:8,8:8}`. +Rank mass is `2368`; the monotone boundary coverage is +`104*8 + 104*8 + 72*9 = 2312`, leaving eight rank-seven private descents. +There are 2624 scalar additions and eight each of private initialization, +copy and discard, for 4058 total events. No additional rank-zero endpoint +child is inserted. + +Five actual faults reject: change a native recipe's global phase; remove a +transport recipe; corrupt a physical root image; set the first initial-query +compensation coefficient to zero; set the last query-cleanup coefficient to +zero. The last two preserve every transport index and are rejected by the +complete endpoint induction, not merely by an event-index mismatch. + +## 5. Unresolved supplier obligations + +This channel implements `G/2`, not `I`. A compatible `I-G/2` correction must +be integrated and priced. The 72 dirty width-nine roles are a local inventory, +not a chronological global owner map. The finite native identities do not +establish recursive precision, arbitrary-size lifting, all global residual +children or an improved recursive moment. No new kappa follows from this +certificate alone. diff --git a/research/p104-native-channel/README.md b/research/p104-native-channel/README.md new file mode 100644 index 0000000000..f187d1ac0b --- /dev/null +++ b/research/p104-native-channel/README.md @@ -0,0 +1,91 @@ +# Native P104 low-rank channel + +Concrete finite Clifford recipes for the complete low-rank channel in +[Rohan Arun's PR1972](https://github.com/CrocSwap/integer-mult-bounds/pull/1972), +head `fd82d172f46933fd253c2c6de4bd5eaff5429cfd`. Its scalar/frame construction +is retained, not claimed new. This package replaces its conditional free-chart +realization with exact Gaussian-dyadic primitive recipes and intrinsic data +endpoint adapters. + +**No complete P104 supplier or new kappa.** The `I-G/2` side correction, +chronological global hosting, precision and all-size admission remain open. +The selected frontier is unchanged. + +## Result + +For the frozen 104 root ports, source logical values `x`, target values `y` +and 72 independent arbitrary dirty helpers, the channel implements +`y <- y + (G/2)x`, with the prescribed source/target transports. All 72 helper +logical values are restored at the full frame. A separate owned private copy +has eight explicit allocate/copy/descend/discard lifetimes under the inherited +private-copy contract; it is not one of the 72 dirty inputs. + +[EXPECTED.json](EXPECTED.json) records: + +- 740 distinct native transport recipes covering all 1410 paid occurrences; +- 208 monomial data endpoint adapters: 104 source entries and 104 target exits; +- all 280 arbitrary register input columns in a complete framed induction; +- 14,400 physical root-pairing checks and 4096 exact Gaussian private-drop columns; +- five rejecting controls, including global phase and missing query compensation/cleanup. + +The exact profile remains +`1074 H1 + 58 H2 + 86 H3 + 104 H4 + 48 H5 + 24 H6 + 8 H7 + 8 H8`. +Its rank mass is **2368 = 2312 boundary coverage + COPY56**. This is the same +local boundary invoice as PR1972, not a globally hosted recursive price. + +The compressed root labels require a nontrivial Gram isometry before using +ordinary physical binary dot products. [PROOF.md](PROOF.md) gives that binding, +the native operator check and the full-word induction. + +## Reproduce + +Standard-library Python. Default replay is read-only, needs no network or Git, +and imports neither the channel producer nor the Clifford compiler: + +```sh +python3 -I -O -B research/p104-native-channel/verify.py +``` + +Also rebuild every recipe in temporary storage and compare the complete +decompressed payload: + +```sh +python3 -I -O -B research/p104-native-channel/verify.py --regenerate +``` + +The registered hook runs both checks with a 300-second limit: + +```sh +python3 scripts/research_package.py --package research/p104-native-channel --check-only +python3 scripts/research_package.py --package research/p104-native-channel +``` + +The generic metadata check needs Git provenance. The direct command also works +from a read-only source export. `--out PATH` writes a receipt exclusively to a +new caller-selected file. Source hashes and exact origins are in +[SOURCES.json](SOURCES.json); [TASK.json](TASK.json) records the changed audit scope. +Compression bytes are not used to compare regenerated mathematics. + +## Open next questions + +Integrate a fully charged `I-G/2` side word while the required source/target +frames remain available. Appending it after source completion is not justified. +Then assign actual chronological owners to the completed word, count all idle +and residual children, and compare the exact recursive moment. Those steps, +plus precision and all-size lifting, are required before a supplier or kappa +claim. Concrete first steps and blockers are in `TASK.json`. + +## Credit + +Rohan Arun / PR1972 supplies the complete scalar/frame channel; Adam Gall / +PR1940 supplies the schedule. The P104 fixture and decoder derive from Josie +Elliston / PR1071, with Ali Romman / PR1125 and the PR968/717/446/595/620 lineage. +The exact compiler is retained through icekylinx's frame-sa504 package; the +independent Gaussian interpreter comes from Ali Romman's PR1862, also retained +in PR1931. Exact predecessor notices are under `notices/`. + +Native lowering, the independent physical binding and framed induction were +prepared for Chafik Boukhalfa with substantial OpenAI Codex assistance. +Apache-2.0. No independent human review, proof assistant or literature-priority +guarantee is claimed. The fresh overlap screen covered 470 open PRs and 614 +discussions; its limits are recorded in `SOURCES.json`. diff --git a/research/p104-native-channel/SOURCES.json b/research/p104-native-channel/SOURCES.json new file mode 100644 index 0000000000..901ad0fb42 --- /dev/null +++ b/research/p104-native-channel/SOURCES.json @@ -0,0 +1,87 @@ +{ + "schema_version": 1, + "base_commit": "25c80aa5345afa3867ff4bc81108a8e182669abd", + "files": [ + { + "path": "certificates/selected-result.json", + "usage": "provenance", + "git_blob": "ae6a99f28aa468649eb66a361e764d769363bf11", + "sha256": "10b9e340fd8e354a37a0c4813c90e5de1dd42044b5f6aca4a3fc5a42b685fa32" + }, + { + "path": "docs/research/agent-task-catalog.json", + "usage": "provenance", + "git_blob": "06c96f5579bb67ed1b86d334e78fbed7da6945f1", + "sha256": "6686ad58f1fbdbc87134a78901b60fd53a20d3984355e91defbbebc9e9fa8075" + } + ], + "vendored_inputs": [ + { + "path": "inputs/LOWRANK-WITNESS.json", + "sha256": "0f541bef7f19fdeffd67157684e9f03d785f42c89973632f508fc1a0452b580e", + "head": "fd82d172f46933fd253c2c6de4bd5eaff5429cfd", + "upstream_path": "research/p104-restored-dirty-delivery/LOWRANK-WITNESS.json", + "role": "Rohan Arun / PR1972: complete frame-model low-rank channel" + }, + { + "path": "inputs/LOWRANK-RESULT.json", + "sha256": "7143ec7780f6f38a8c294df8009c3621936b281d05ae79946ce22f581b73d1b1", + "head": "fd82d172f46933fd253c2c6de4bd5eaff5429cfd", + "upstream_path": "research/p104-restored-dirty-delivery/LOWRANK-RESULT.json", + "role": "PR1972 exact invoice; independently recounted" + }, + { + "path": "inputs/P104-FIXTURE.json", + "sha256": "516c06f6ec3cb84be588c546108de897650288576dd5fbf5fe44b9c5546ad8a4", + "head": "fd82d172f46933fd253c2c6de4bd5eaff5429cfd", + "upstream_path": "research/p104-restored-dirty-delivery/source/research/biframe-decoder-ladder/RESULTS.json", + "role": "Josie Elliston / PR1071 fixture through PR1940 and PR1972" + }, + { + "path": "vendor/clifford_exact.py", + "sha256": "2982ead07721e83358dc67c6f49c2b4c16a236a6bebdfd72f58221be1f5d0962", + "head": "25c80aa5345afa3867ff4bc81108a8e182669abd", + "upstream_path": "research/frame-sa504/vendor/clifford/clifford_exact.py", + "role": "Exact compiler through icekylinx PR531; PR523/514/507/425/433 ancestry" + }, + { + "path": "vendor/native_verify.py", + "sha256": "3049471905b47b385c88378a1a3be7a18b8858aadd035b8a6da2f4a03b470f38", + "head": "bb29ea73ad9be9a0c3d53cdcb1d22b2ee9ffe42f", + "upstream_path": "research/native-source-codes/native_verify.py", + "role": "PR1862 independent exact Gaussian interpreter, also retained through PR1931" + } + ], + "predecessors": [ + { + "pr": 1972, + "head": "fd82d172f46933fd253c2c6de4bd5eaff5429cfd", + "role": "Entire scalar/frame low-rank construction and dirty-helper cancellation; not invented here" + }, + { + "pr": 1940, + "head": "a9b7dfe2809092a9a4c90784d12bb60061e995e8", + "role": "Adam Gall: 32-chain target-order schedule" + }, + { + "pr": 1931, + "head": "7c9b37812b6803fe64bf4427dee7ab82c0155513", + "role": "Retained exact Gaussian interpreter distribution; not the reflection construction" + } + ], + "disclosure": "Native lowering, independent physical binding and framed induction prepared for Chafik Boukhalfa with substantial OpenAI Codex assistance. No independent human review or formal proof assistant.", + "overlap": { + "checked_utc": "2026-10-14T16:12:30Z", + "open_prs": 470, + "discussions": 614, + "pagination_complete": true, + "terms": [ + "P104", + "Clifford", + "dirty-restored" + ], + "closest_predecessor": 1972, + "difference": "Replace free-chart conditional replay by concrete Gaussian-dyadic primitive recipes and intrinsic endpoint adapters. No scalar construction or kappa improvement claimed.", + "limits": "Open PR bodies, discussion bodies/comments and local metadata; no complete code or literature novelty search." + } +} diff --git a/research/p104-native-channel/SUMMARY.json b/research/p104-native-channel/SUMMARY.json new file mode 100644 index 0000000000..fba272d33b --- /dev/null +++ b/research/p104-native-channel/SUMMARY.json @@ -0,0 +1,23 @@ +{ + "status": "COMPILED_EXACT_P104_LOW_RANK_CHANNEL", + "source_pr": 1972, + "source_head": "fd82d172f46933fd253c2c6de4bd5eaff5429cfd", + "upstream_schedule_pr": 1940, + "upstream_schedule_head": "a9b7dfe2809092a9a4c90784d12bb60061e995e8", + "source_witness_sha256": "0f541bef7f19fdeffd67157684e9f03d785f42c89973632f508fc1a0452b580e", + "source_compiler_sha256": "2982ead07721e83358dc67c6f49c2b4c16a236a6bebdfd72f58221be1f5d0962", + "source_native_checker_sha256": "3049471905b47b385c88378a1a3be7a18b8858aadd035b8a6da2f4a03b470f38", + "paid_profile": { + "3": 86, + "1": 1074, + "4": 104, + "8": 8, + "2": 58, + "5": 48, + "6": 24, + "7": 8 + }, + "rank_mass": 2368, + "private_drop_basis_columns": 4096, + "scope": "Concrete finite Clifford transport and endpoint adapters for the complete low-rank G/2 channel, including gathering and all 72 dirty helper restorations. Not I-G/2 side correction, chronological global hosting, all-size compilation, precision or a new supplier/kappa." +} diff --git a/research/p104-native-channel/TASK.json b/research/p104-native-channel/TASK.json new file mode 100644 index 0000000000..7dfcf778e4 --- /dev/null +++ b/research/p104-native-channel/TASK.json @@ -0,0 +1,66 @@ +{ + "schema_version": 1, + "task_id": "supplier-boundary-audit", + "priority_revision": 3, + "base_commit": "25c80aa5345afa3867ff4bc81108a8e182669abd", + "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" + ], + "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", + "research/owner-boundary-audit/verify.py" + ], + "expected": "PASS_PR626_NEXT_TOUCH_BOUNDARY_AUDIT", + "inspect": "Identify why the timing-only omission passes but the full production controller still rejects it.", + "scope": "Positive control / source-bound orientation only; this is not a new construction or full cold replay." + }, + "first_experiment": "Choose one current supplier obligation and trace whether its acceptance depends on an independent check.", + "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." + ], + "overlap_terms": [ + "owner boundary", + "bridge omission", + "hosting" + ] + }, + "scope_status": "changed", + "actual_scope": "Construct and independently verify finite native Clifford recipes for PR1972 complete P104 low-rank G/2 channel.", + "scope_change_reason": "The user assigned continuing frontier research. This component targets a pending changed supplier rather than the selected supplier; PR1972 explicitly leaves concrete native realization open.", + "bottleneck_link": "P104 COPY56 is a possible changed centre interface. Concrete phase-correct native delivery and gather are required before side-word integration, global hosting and any moment gain can be tested.", + "budget_minutes": 120, + "stop_rule": "Stop this component when all native transports/endpoints and all 280 input columns replay independently, or a concrete obstruction appears; keep the full kappa=1 research objective open.", + "outcome": "completed", + "evidence": "EXPECTED.json: 740 native transports, 208 rank-zero endpoints, 280 arbitrary input columns, 4096 exact private-drop Gaussian columns, five mutation controls.", + "author": "Chafik Boukhalfa", + "ai_assistance": "Substantial OpenAI Codex assistance; standard-library exact integer and Fraction arithmetic. No independent human review or formal proof assistant.", + "open_questions": [ + { + "question": "Can an I-G/2 side-correction word be integrated with these source and target frame paths?", + "why_it_matters": "The G/2 channel alone is not the identity-transfer component required by a complete supplier.", + "first_step": "Derive the actual P104 side word and interleave its events before the affected source/target frames become unavailable; independently replay all dirty inputs.", + "blocked_by": "No complete compatible side word or fully charged profile supplied." + }, + { + "question": "Can all 72 width-nine dirty roles and private-copy lifetimes be hosted chronologically with a net moment gain?", + "why_it_matters": "Boundary coverage and COPY56 do not price the full recursive network.", + "first_step": "Assign real owners to the completed local word, include all residual/idle children and compare the exact whole-word moment.", + "blocked_by": "Requires a completed side-corrected word, global owner allocation, all-size lifting and precision accounting." + } + ] +} diff --git a/research/p104-native-channel/VERIFY.json b/research/p104-native-channel/VERIFY.json new file mode 100644 index 0000000000..963883dbe7 --- /dev/null +++ b/research/p104-native-channel/VERIFY.json @@ -0,0 +1,21 @@ +{ + "schema_version": 1, + "status": "ready", + "python": "3.12", + "requirements": [], + "inputs": [], + "commands": [ + { + "argv": [ + "{python}", + "-I", + "-O", + "-B", + "{package}/verify.py", + "--regenerate" + ], + "timeout_seconds": 300, + "checks": "All physical pairings; every native edge and endpoint including global phase; all 280 columns and dirty-helper endpoints; all 4096 private-copy Gaussian columns; five mutations; complete regenerated recipe payload." + } + ] +} diff --git a/research/p104-native-channel/check_native.py b/research/p104-native-channel/check_native.py new file mode 100644 index 0000000000..f8e54afbf1 --- /dev/null +++ b/research/p104-native-channel/check_native.py @@ -0,0 +1,141 @@ +"""Read-only native boundary proof: no compiler or producer imports. + +Each literal transport is verified as a complete Clifford operator, including +its scalar phase. A separate frame-invariant scalar replay composes the full +channel, including source query formation. The side correction is outside it. +""" +from pathlib import Path +from fractions import Fraction as Q +from itertools import combinations,product +from collections import Counter +import argparse,copy,gzip,hashlib,importlib.util,json +H=Path(__file__).resolve().parent +P=H/'inputs' +NP=H/'vendor/native_verify.py' +sp=importlib.util.spec_from_file_location('independent_gaussian',NP);N=importlib.util.module_from_spec(sp);sp.loader.exec_module(N) + +def need(ok,why): + if not ok:raise ValueError(why) + +def roots(): + lines=set() + for i,j in combinations(range(8),2): + for sign in (-1,1): + v=[0]*8;v[i]=2;v[j]=2*sign;lines.add(tuple(v)) + for signs in product((-1,1),repeat=7): + if signs.count(-1)%2==0:lines.add((1,*signs)) + need(len(lines)==120,'independent E8 roots');return sorted(lines) + +def span(vs): + out={0} + for v in vs:out|={x^v for x in tuple(out)} + return tuple(sorted(out)) + +def validate(c,w,fixture,full_gaussian=False): + rr=roots();inner=lambda a,b:sum(x*y for x,y in zip(a,b))//4 + binary=[sum(((inner(a,b)+1)&1)<>j)&1)<>j)&1),'all 14400 physical binary pairings') + labels=dict(zip(rr,q));pairs=[(tuple(a),tuple(b))for a,b in fixture['pairs_doubled_coordinates']];removed={tuple(r)for r in fixture['F0']+fixture['C']};ports=[r for r in rr if r not in removed] + need(len(pairs)==8 and len(ports)==104,'P104 fixture binding') + key=lambda f:span(convert(v)for v in f) + charts={};edges={};covered={};paid=Counter();gaussian_columns=0 + def chart(f): + k=span(f);need(len(k)==1<0,'exact native jump rank') + expected=N.adjoint(N.frame(a,9))+N.frame(b,9);N.equal(N.recipe(rec['recipe']),expected,'independent native boundary edge') + if full_gaussian and len(a)==8 and len(b)==1: + for j in range(512):need(N.state(N.recipe(rec['recipe']),j)==N.state(expected,j),'all private-copy basis columns');gaussian_columns+=1 + for i in rec['events']: + need(i not in covered and 0<=ij and piv[k]>>j&1:piv[k]^=piv[j] + return tuple(piv[j]for j in sorted(piv,reverse=True)) + +def label_isometry(): + roots=root_lines();matrix=[sum(((inner(a,b)+1)&1)<len(rows):indices.append(i);rows.append(row) + need(len(indices)==9,'symmetric pairing rank nine') + labels=[sum(((row>>j)&1)<>j)&1),'all physical binary pairings') + return roots,labels,physical,transform,dict(pivot_root_indices=indices,compressed_gram=gram,compressed_dual_gram=dual,orthonormal_basis_compressed=orthogonal,physical_root_labels=physical) + +def main(): + ap=argparse.ArgumentParser();ap.add_argument('--out-dir',type=Path,required=True);args=ap.parse_args();destination=args.out_dir;destination.mkdir(parents=True,exist_ok=True) + need(not any((destination/f).exists()for f in ['NATIVE-RECIPES.json.gz','SUMMARY.json']),'output files already exist') + started=time.monotonic();need(hashlib.sha256(CP.read_bytes()).hexdigest()=='2982ead07721e83358dc67c6f49c2b4c16a236a6bebdfd72f58221be1f5d0962','pinned native compiler') + roots,labels,physical,transform,iso=label_isometry();word=json.loads((P/'LOWRANK-WITNESS.json').read_text());fixture=json.loads((P/'P104-FIXTURE.json').read_text())['section4_explicit_P104'];removed={tuple(r)for r in fixture['F0']+fixture['C']};geom={'ports':[r for r in roots if r not in removed]};byroot=dict(zip(roots,physical)) + frame=lambda f:canon(transform(x)for x in f) + all_frames={frame(f)for f in word['initial_frames'].values()}|{frame(f)for f in word['final_frames'].values()} + edges={} + for index,e in enumerate(word['program']): + if e[0]=='transport': + old,new=frame(e[2]),frame(e[3]);edges.setdefault((old,new),dict(rank=e[4],events=[]))['events'].append(index);all_frames.update((old,new)) + @lru_cache(None) + def chart(f):return CE.canonical_frame(9,f) + recs=[];copy_keys=set();full=tuple(1<>i)&1)<>j&1);a[j],a[k]=a[k],a[j] + for i in range(n): + if i!=j and a[i]>>j&1:a[i]^=a[j] + assert [r&((1<>n for r in a) +def basis_extend(cols,n): + out=[] + for x in list(cols)+[1<len(out):out.append(x) + assert len(out)==n + return tuple(out) +def nullspace(rows,n): + a=list(rows);p=[];k=0 + for j in range(n): + t=next((i for i in range(k,len(a)) if a[i]>>j&1),None) + if t is None:continue + a[t],a[k]=a[k],a[t] + for i in range(len(a)): + if i!=k and a[i]>>j&1:a[i]^=a[k] + p.append(j);k+=1 + return tuple((1<>j)&1)<>i&1:out=pmul(out,T[i]) + for i in range(n): + if z>>i&1:out=pmul(out,T[n+i]) + return out +def compose(A,B):return tuple(apply(A,p) for p in B) +def inverse(T): + n=len(T)//2;cols=[x|(z<>n;u,v,p=apply(T,(x,z,0));assert (u,v)==identity(n)[j][:2];out.append((x,z,(-p)%4)) + return tuple(out) +def qvalue(Q,alpha,x,n): + return (sum(alpha[i] for i in range(n) if x>>i&1)+2*sum(parity((Q[i]>>(i+1))&(x>>(i+1))) for i in range(n) if x>>i&1))%4 +def mul_i(a,p): + x,y=a;p%=4 + return [(x,y),(-y,x),(-x,-y),(y,-x)][p] +@dataclass +class Op: + n:int + tab:tuple + circuit:list + def then(self,b): + assert self.n==b.n + return Op(self.n,compose(b.tab,self.tab),self.circuit+b.circuit) + def adjoint(self): + circ=[] + for e in reversed(self.circuit): + if e[0]=='P':circ.append(('P',inv(e[1],self.n))) + elif e[0]=='D':circ.append(('D',e[1],tuple((-x)%4 for x in e[2]))) + elif e[0]=='C':circ.append(('C',e[1],-e[2])) + elif e[0]=='phase':circ.append(('phase',(-e[1])%4)) + else:circ.append(e) + return Op(self.n,inverse(self.tab),circ) + def zero_state(self,basis=0): + N=1<>i)&1 for i in range(n)) + assert all(alpha[i]%2==(Q[i]>>i)&1 for i in range(n)) + return Op(n,tuple([(1<>i&1 else 0,1<>i&1 else 0) for i in range(n)]),[('C',q,sgn)]) +def xgate(n,b):return Op(n,tuple([(1<>i)&1)) for i in range(n)]),[('X',b)]) +def fourier(n,axes=None): + out=ident(n) + for i in range(n) if axes is None else axes:out=out.then(cgate(n,1<len(selected):picks.append(j);selected.append(x) + assert len(picks)==r and all(x>>r==0 for x in Bcols) + Br=transpose(selected,r);Bi=inv(Br,r);Dr=transpose([Dcols[j]&((1<> j) & 1) << i for i, row in enumerate(matrix)) for j in range(len(matrix))) + + +def inverse(matrix): + n = len(matrix) + rows = [row | (1 << (n+i)) for i, row in enumerate(matrix)] + for j in range(n): + pivot = next((i for i in range(j, n) if rows[i] >> j & 1), None) + require(pivot is not None, 'singular binary chart') + rows[j], rows[pivot] = rows[pivot], rows[j] + for i in range(n): + if i != j and rows[i] >> j & 1: + rows[i] ^= rows[j] + require([row & ((1 << n)-1) for row in rows] == [1 << i for i in range(n)], 'binary inverse') + return tuple(row >> n for row in rows) + + +def extend(vectors, n): + columns, pivots = [], {} + for value in tuple(vectors) + tuple(1 << i for i in range(n)): + reduced = value + while reduced: + j = reduced.bit_length()-1 + if j not in pivots: + pivots[j] = reduced + columns.append(value) + break + reduced ^= pivots[j] + require(len(columns) == n, 'frame basis extension') + return tuple(columns) + + +def adjoint(circuit): + out = [] + for gate in reversed(circuit): + if gate[0] == 'P': + out.append(('P', inverse(gate[1]))) + elif gate[0] == 'D': + out.append(('D', gate[1], tuple(-a % 4 for a in gate[2]))) + elif gate[0] == 'C': + out.append(('C', gate[1], -gate[2])) + elif gate[0] == 'phase': + out.append(('phase', -gate[1] % 4)) + else: + require(gate[0] == 'X', 'adjoint gate type') + out.append(gate) + return tuple(out) + + +def fourier(rank): + return tuple(('C', 1 << i, 1) for i in range(rank)) + + +def frame(vectors, n): + rank = len(vectors) + if rank == 0: + return () + if rank == n: + return fourier(n) + matrix = transpose(extend(vectors, n)) + columns = transpose(inverse(matrix)) + quadratic = tuple((1 << i) ^ sum(parity(a & b) << j for j, b in enumerate(columns)) for i, a in enumerate(columns)) + diagonal = tuple((row >> i) & 1 for i, row in enumerate(quadratic)) + chart = (('P', matrix), ('D', quadratic, diagonal)) + return adjoint(chart) + fourier(rank) + chart + + +def monomial(record): + matrix = tuple(record['matrix_rows']) + quadratic = tuple(record['quadratic_rows']) + linear = tuple(record['linear_Z4']) + require(transpose(quadratic) == quadratic, 'quadratic symmetry') + require(len(matrix) == len(quadratic) == len(linear) == 9, 'monomial dimension') + require(all(a % 2 == (quadratic[i] >> i) & 1 for i, a in enumerate(linear)), 'diagonal parity') + inverse(matrix) + return (('D', quadratic, linear), ('P', matrix), ('X', record['offset']), ('phase', record['phase'])) + + +def recipe(record): + rank = record['rank'] + require(isinstance(rank, int) and 0 <= rank <= 9, 'child rank') + if rank == 0: + require(record['right'] is None, 'rank zero right factor') + return monomial(record['left']) + return monomial(record['right']) + fourier(rank) + monomial(record['left']) + + +def tableau(circuit, n=9): + rows = [(1 << i, 0, 0) for i in range(n)] + [(0, 1 << i, 0) for i in range(n)] + for gate in circuit: + tag = gate[0] + out = [] + inverse_transpose = transpose(inverse(gate[1])) if tag == 'P' else None + for x, z, phase in rows: + if tag == 'P': + x, z = mul(gate[1], x), mul(inverse_transpose, z) + elif tag == 'X': + phase += 2 * parity(z & gate[1]) + elif tag == 'C': + if parity(z & gate[1]): + x ^= gate[1] + phase += 3 * gate[2] + elif tag == 'D': + quadratic, linear = gate[1:] + phase += sum(linear[i] for i in range(n) if x >> i & 1) + phase += 2 * sum(parity((quadratic[i] >> (i+1)) & (x >> (i+1))) for i in range(n) if x >> i & 1) + z ^= mul(quadratic, x) + else: + require(tag == 'phase', 'tableau gate type') + out.append((x, z, phase % 4)) + rows = out + return tuple(rows) + + +@lru_cache(maxsize=512) +def action(gate): + if gate[0] == 'P': + return tuple(mul(gate[1], x) for x in range(512)) + require(gate[0] == 'D', 'state action type') + quadratic, linear = gate[1:] + return tuple((sum(linear[i] for i in range(9) if x >> i & 1) + + 2 * sum(parity((quadratic[i] >> (i+1)) & (x >> (i+1))) for i in range(9) if x >> i & 1)) % 4 for x in range(512)) + + +def rotate(pair, power): + a, b = pair + return ((a, b), (-b, a), (-a, -b), (b, -a))[power % 4] + + +def state(circuit, basis=0): + value, denominator = {basis: (1, 0)}, 0 + for gate in circuit: + tag = gate[0] + result = {} + if tag == "C": + direction, sign = gate[1:] + for address, (a, b) in value.items(): + for target, pair in ((address, (a - sign*b, b + sign*a)), + (address ^ direction, (a + sign*b, b - sign*a))): + old = result.get(target, (0, 0)) + result[target] = (old[0] + pair[0], old[1] + pair[1]) + denominator += 1 + else: + for address, pair in value.items(): + if tag == "P": + target = mul(gate[1], address) + elif tag == "X": + target = address ^ gate[1] + else: + target = address + if tag == "D": + pair = rotate(pair, action(gate)[address]) + else: + require(tag == "phase", "Unknown Gaussian state gate") + pair = rotate(pair, gate[1]) + require(target not in result, "A monomial address map is not injective") + result[target] = pair + value = {address: pair for address, pair in result.items() if pair != (0, 0)} + while denominator and all((a | b) % 2 == 0 for a, b in value.values()): + denominator -= 1 + value = {address: (a//2, b//2) for address, (a, b) in value.items()} + return value, denominator + + +def equal(actual, expected, label): + require(tableau(actual) == tableau(expected), label + ": signed Pauli action") + require(state(actual) == state(expected), label + ": exact global phase") + + +def verify(data, certificate): + word = data["word"] + original, clean = data["programs"], data["clean_programs"] + source_recipes = data["recipes"] + residuals = data["residuals"]["recipes"] + native_tags = {"climb", "adapter", "residual_adapter"} + for orientation in ("forward", "backward"): + native = [event for event in clean[orientation] if event[0] in native_tags] + require(native == [event for event in original[orientation] if event[0] in native_tags], + "A retained native event changed") + require(len(native) == 5056, "The retained native event count changed") + frames = [frame(tuple(vectors), 9) for vectors in word["frames"]] + used = {(event[3], event[4]) for program in clean.values() + for event in program if event[0] == "climb"} + children = {(record["old"], record["new"]): record for record in source_recipes["children"]} + require(len(children) == len(source_recipes["children"]) and used <= set(children), + "The retained child recipe coverage is incomplete") + for old, new in sorted(used): + record = children[old, new] + require(record["rank"] == len(word["frames"][new]) - len(word["frames"][old]), + "A retained child has the wrong rank") + equal(recipe(record), adjoint(frames[old]) + frames[new], "Retained child") + endpoints = {(record["role"], record["port"]): record + for record in source_recipes["endpoint_adapters"]} + require(len(endpoints) == len(source_recipes["endpoint_adapters"]) + and set(endpoints) == {(role, p) for role in ("source", "target") for p in range(112)}, + "The endpoint adapter coverage is incomplete") + for (role, port), record in endpoints.items(): + direction = word["ports"][port] + conventional = (("C", direction, 1),) if role == "source" else ( + ("C", direction, -1),) + fourier(9) + index = word["start"][port] if role == "source" else word["final"][112 + port] + require(record["frame"] == index and record["rank"] == 0, "An endpoint frame changed") + equal(recipe(record), adjoint(conventional) + frames[index], "Endpoint adapter") + used_residuals = set() + for program in clean.values(): + for event in program: + if event[0] != "residual_adapter": + continue + _, position, register, entry, *tail = event + terminal = tail[0] if tail else 1 + key = str(entry) if terminal == 1 else str(entry) + ":" + str(terminal) + require(key in residuals and position in ("pre", "post"), "A residual binding changed") + require(entry == word["start"][register] and terminal == word["final"][register], + "A residual endpoint changed") + used_residuals.add(key) + for key in sorted(used_residuals): + record = residuals[key] + equal(recipe(record), adjoint(frames[record["frame"]]) + frames[record.get("terminal", 1)], + "Residual adapter") + records = certificate["input_recipes"] + ports = certificate["compensation_ports"] + require([record["port"] for record in records] == ports and len(records) == 8, + "The eight input recipes changed") + columns = 0 + for item in records: + port, label = item["port"], item["label"] + require(label == word["ports"][port] and item["canonical_start_frame_id"] == word["start"][port], + "An input recipe has the wrong supplier label") + record = item["recipe"] + require(record["rank"] == 1, "An input copy has the wrong child rank") + for side in ("left", "right"): + factor = record[side] + require(factor["quadratic_rows"] == [0] * 9 and factor["linear_Z4"] == [0] * 9 + and factor["offset"] == factor["phase"] == 0, + "An input factor is not an address permutation") + actual, expected = recipe(record), (("C", label, 1),) + equal(actual, expected, "Positive inherited input line") + for basis in range(512): + require(state(actual, basis) == state(expected, basis), "A complete input Gaussian column differs") + columns += 1 + negative = monomial(record["right"]) + (("C", 1, -1),) + monomial(record["left"]) + require(tableau(negative) != tableau(expected) or state(negative) != state(expected), + "An inverse input child was not detected") + phased = actual + (("phase", 1),) + require(tableau(phased) == tableau(actual) and state(phased) != state(expected), + "An input phase-only error was not detected") + return {"status": "PASS_EXACT_INPUT_NATIVE_FRAMES", "retained_native_events_per_orientation": 5056, + "retained_child_recipes": len(used), "endpoint_adapter_recipes": len(endpoints), + "residual_adapter_recipes": len(used_residuals), "new_input_recipes": len(records), + "new_exact_gaussian_columns": columns, "inverse_input_child_controls": len(records), + "phase_only_controls": len(records), "address_permutation_factors": 2 * len(records), + "method": "Independent signed Pauli and exact Gaussian interpretation; no compiler import", + "scope": "Positive inherited input frames before every retained adapter. No recursive hosting claim."} diff --git a/research/p104-native-channel/verify.py b/research/p104-native-channel/verify.py new file mode 100644 index 0000000000..ba41aa0476 --- /dev/null +++ b/research/p104-native-channel/verify.py @@ -0,0 +1,34 @@ +"""Read-only exact native channel replay; no network, Git or producer imports. + +--regenerate also runs the compiler in temporary storage and compares the +complete decompressed certificate. Ordinary replay uses only the independent +native interpreter and framed scalar induction. +""" +from pathlib import Path +import argparse,gzip,hashlib,importlib.util,json,subprocess,sys,tempfile +P=Path(__file__).resolve().parent + +def need(ok,why): + if not ok:raise ValueError(why) + +def main(): + ap=argparse.ArgumentParser();ap.add_argument('--out',type=Path);ap.add_argument('--regenerate',action='store_true');args=ap.parse_args() + sources=json.loads((P/'SOURCES.json').read_text()) + for item in sources['vendored_inputs']: + need(hashlib.sha256((P/item['path']).read_bytes()).hexdigest()==item['sha256'],'pinned source changed: '+item['path']) + spec=importlib.util.spec_from_file_location('p104_independent_channel',P/'check_native.py');checker=importlib.util.module_from_spec(spec);spec.loader.exec_module(checker) + result=json.loads(json.dumps(checker.replay(True))) + need(result==json.loads((P/'EXPECTED.json').read_text()),'independent replay differs from expected exact receipt') + if args.regenerate: + with tempfile.TemporaryDirectory(prefix='p104-native-')as directory: + subprocess.run([sys.executable,'-I','-O','-B',str(P/'compile.py'),'--out-dir',directory],check=True,timeout=300) + for filename in ['NATIVE-RECIPES.json.gz','SUMMARY.json']: + a=(P/filename).read_bytes();b=(Path(directory)/filename).read_bytes() + if filename.endswith('.gz'):a,b=gzip.decompress(a),gzip.decompress(b) + need(a==b,'regenerated complete payload differs: '+filename) + out=json.dumps(result,sort_keys=True,indent=2)+'\n' + if args.out: + with args.out.open('x')as handle:handle.write(out) + print(out,end='') + +if __name__=='__main__':main()