diff --git a/.gitattributes b/.gitattributes index 6825630198..660ca3e3e0 100644 --- a/.gitattributes +++ b/.gitattributes @@ -18,3 +18,5 @@ research/coordinated-frames-and-entrance-banks/** -text -whitespace # Frozen PR210 package and round-nine evidence retain their audited bytes. research/five-stage-source527-banks/** -text -whitespace research/community-round9-audit/** -text -whitespace +# E8 complex unit with far piece relocation (e8st): MANIFEST.sha256 and the git-blob pins fix exact bytes (Sussman gx.py keeps its original whitespace). +research/e8-complex-far-retiming/** -text -whitespace diff --git a/.github/workflows/e8-complex-far-retiming.yml b/.github/workflows/e8-complex-far-retiming.yml new file mode 100644 index 0000000000..6ea1a85aa1 --- /dev/null +++ b/.github/workflows/e8-complex-far-retiming.yml @@ -0,0 +1,37 @@ +name: e8-complex-far-retiming + +on: + pull_request: + paths: + - 'research/e8-complex-far-retiming/**' + - '.github/workflows/e8-complex-far-retiming.yml' + push: + paths: + - 'research/e8-complex-far-retiming/**' + - '.github/workflows/e8-complex-far-retiming.yml' + workflow_dispatch: + +permissions: + contents: read + +jobs: + verify: + runs-on: ubuntu-latest + timeout-minutes: 30 + strategy: + fail-fast: false + matrix: + python-version: ['3.12', '3.14'] + steps: + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 + with: + persist-credentials: false + - uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7 + with: + python-version: ${{ matrix.python-version }} + - name: Quick verification (manifest, pins, Sussman's checkers, operator identity, layout, kappa) + run: bash research/e8-complex-far-retiming/verify.sh --quick "$RUNNER_TEMP/e8st-quick" + - name: Full verification (adds the regeneration of the certificate from Sussman's original) + run: bash research/e8-complex-far-retiming/verify.sh "$RUNNER_TEMP/e8st-full" + - name: Require an unchanged tree + run: git diff --exit-code diff --git a/certificates/joint-dual-kappa.json b/certificates/joint-dual-kappa.json index b7f7b89bc2..1f35b89221 100644 --- a/certificates/joint-dual-kappa.json +++ b/certificates/joint-dual-kappa.json @@ -842,7 +842,7 @@ "scripts/experiments/pin_joint_dual_sources.py": "4d31cc0e38b7902709ca5f8f714cba109760d2592346dd7f8dc0b900a2d9fe00", "scripts/experiments/verify_joint_dual.py": "7a31bba1e9c0ded32ae285df2ca9bc91ef20c330f6789fdba361876f3c7a1985" }, - "source_manifest_sha256": "4f3c15b82a2d97335d4fe95fb8bcb96bd2a921087da289d9da16c68213a17f17", + "source_manifest_sha256": "698fe862a620e5b80b85fbc6034c9456fa0fa9aea638dbbbcb3f9edd24c0415e", "sources": [ { "files": { diff --git a/certificates/joint-dual-validation.json b/certificates/joint-dual-validation.json index 194861d3c3..61a8d41622 100644 --- a/certificates/joint-dual-validation.json +++ b/certificates/joint-dual-validation.json @@ -226,7 +226,7 @@ } }, "bit_saving": "2382370177/50000000000000", - "certificate_sha256": "9801147b1502cf1e43d5fa39aa37f5291f03b48c30c4dd4f272e0877894a1c24", + "certificate_sha256": "6f684fa7f747073a132e8d0b5652cf12a8afa389f2a16ff6ade8e080d786dd22", "kappa": "4764513337/100000000000000", "margins": 7, "producer_words_regenerated_and_matched": true, diff --git a/research/e8-complex-far-retiming/LICENSE b/research/e8-complex-far-retiming/LICENSE new file mode 100644 index 0000000000..261eeb9e9f --- /dev/null +++ b/research/e8-complex-far-retiming/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/research/e8-complex-far-retiming/MANIFEST.sha256 b/research/e8-complex-far-retiming/MANIFEST.sha256 new file mode 100644 index 0000000000..c66ceed3bd --- /dev/null +++ b/research/e8-complex-far-retiming/MANIFEST.sha256 @@ -0,0 +1,27 @@ +c71d239df91726fc519c6eb72d318ec65820627232b2f796219e87dcf35d0ab4 LICENSE +b4d2d9f6ed3419a56e76cc36bcab5059993c4853532401b56e4e77a8455d0f93 NOTICE.md +7caa44d8318c0f94ffb86b8be454eb55e0e38544e84611b5622e243d925cea76 PROOF.md +a36178b70a075b3fcc07b274ae9ffc2fddfbf2588984c6e154471f2a5a912b3f README.md +97b461509656798d30b2610b4755ce825b1f84ae8772b9b4efd5c84d7404385b code/cxcheck.py +316cbf7d7c777e1fbe8a5d5fb249f0970b591330f4c2769c6827965a0e9c1adf code/cxfar.py +7b2afb0be9591c72d31d7fbcce4e2d45bbe09daf7caa21123bca050b92cd2882 code/cxfinal.py +8fc2a43e70fa8c1ce3f3025c9568b562accc5cf25b2ed53d7c0a1cbf954a0599 code/cxkernel.py +2655e1e9ec94fb39512329ec86d261959ccd7c635c7535238f254a82861c2db1 code/cxop.py +1c78b3025203c802c3aab9cc4113c48a7357d582f5bc75c47bde7953787f2e82 code/cxpiece.py +e7e06595c12fbafb707a6846719c54b85e0c2bb105927e7e7ee20f028a37438b code/cxretime.py +9f6c0718f371120b015733983b3c91285a3825d306b557f0b9013059c6c88b0e code/cxsplit.py +1cb286196c1530d06f50f0997febc5993b388f33464e295611b920ba30a24eeb code/e8core.py +aee70c242a2f1d225528fabe2002e1564d1dc884797c07d28a831c7878ee9098 code/engines/base_two_moment.py +81cbc864e106418fc7854322746f72180cb8110ff39f74450a3b8d55a82c1482 code/engines/moment.py +c1ebb52163a7219504c728a5c2b098bf1e50bf20148a2879c5a74c3cadc7c03c code/engines/outer.py +bd2c7d5bf546babf4700de802f9f49b45e8da0b3e75edcb4a5dfed914d186c6e code/kappa.py +e650d16538db8d80495fda5109cdfa0775e1d5f3b56b0aa39e5c1efc660877e7 code/layout_bk.py +c71d239df91726fc519c6eb72d318ec65820627232b2f796219e87dcf35d0ab4 complex/LICENSE-wht-power-saving-lean +557c9ad4660eebd14a00583736c4d12d2c45f3fc9bc148845f9f3efec72c9434 complex/NOTICE-wht-power-saving-lean +4b92f00fc7454b9b15e6d71a3b05062792eacca0a0ca4efee46f87827d57c8aa complex/gcert1-e8-r783.json.gz +6f3dc8bb639933227a8dae181ec4a542e85c7276be9c9e330f49518e7b630b95 complex/gx/gx.py +eb972c06fe8c322db2d9a8d9a7d05596e8f40c4ca8e5f42eb6df3c7361b5d517 complex/gx/gxcore.py +1fb726ea3818fe0837cceb0dd22a71a0814f064e5e781628104610d6468e0e55 data/bit/bitE8-r865.json.gz +f2664ee7bcdfb55893abe9f1be8ee6a394a602e8262e611de2a0328bbd508aa7 data/gcert1-e8-r783-far.json.gz +0643931a5c713c5861e462ba8397acbaf5d5fd366e0a0d1506fd06b8aa6e324c lean/LEAN-B2-E8FR.txt +42811ea3cb74d0132699e6ba6b2ada81527d69f8e654d6a94fbccf6d9c0b2cd8 verify.sh diff --git a/research/e8-complex-far-retiming/NOTICE.md b/research/e8-complex-far-retiming/NOTICE.md new file mode 100644 index 0000000000..ba19bb7de1 --- /dev/null +++ b/research/e8-complex-far-retiming/NOTICE.md @@ -0,0 +1,21 @@ +# Notice + +Apache-2.0 (`LICENSE`). Prepared by Chafik Boukhalfa (chafreaky) with substantial Anthropic Claude assistance. + +- `complex/gcert1-e8-r783.json.gz`, `complex/gx/gx.py`, `complex/gx/gxcore.py`: Jacob Sussman, + jacobalansussman/wht-power-saving-lean at `9c94857`, Apache-2.0. The bytes are identical (by git blob id) to the copies vendored in + DaysSky's #363/#375 and aliromman's #365. The upstream LICENSE and NOTICE are kept as `complex/LICENSE-wht-power-saving-lean` + and `complex/NOTICE-wht-power-saving-lean`. +- `data/gcert1-e8-r783-far.json.gz`: this package's certificate, derived from Sussman's by `code/cxfar.py` and `code/cxfinal.py`. + It keeps his format, and its `derived_from` field records the derivation. +- `data/bit/bitE8-r865.json.gz`: utcorvusvolat-dotcom's (Dylan Crow) #370 E8 bit word, byte-identical to #370's and #373's + `data/bit` (Apache-2.0). +- `code/engines/moment.py`, `base_two_moment.py`, `outer.py`: PR #315's engines (DreamingOfClouds; eumemic; the #144/#23 + lineage), as vendored in our #329/#359 packages. +- `code/layout_bk.py`: our reimplementation of DaysSky's B_K rule (#363), on Sussman's B₂ and stage geometry. #363's `bridged.py` was read as data + and not run. +- `code/e8core.py`, `cxcheck.py`, `cxop.py`, `kappa.py`, `cxretime.py`, `cxsplit.py`, `cxpiece.py`, `cxfar.py`, `cxfinal.py`, + `cxkernel.py`: our own code. The retiming and reorder mechanisms follow our #329/#359 stage lineage (#287/#291/#299/#306), and + aliromman's #365 is generalised (read as data, not run). `cxkernel.py` also holds the exterior-gauge kernel census, which is + unprofitable on this unit, together with the helpers it shares with the search (`rehist`, `price`). +- PR #375's halving-degree-two guard (DaysSky) is cited, not vendored. diff --git a/research/e8-complex-far-retiming/PROOF.md b/research/e8-complex-far-retiming/PROOF.md new file mode 100644 index 0000000000..686cace756 --- /dev/null +++ b/research/e8-complex-far-retiming/PROOF.md @@ -0,0 +1,40 @@ +# Why the new certificate prices as claimed + +**1. Same operator.** Every change is one of these: +- re-framing a gate or a set of gates; +- splitting a fan-out (s → t₁…t_k) or fan-in (t += s₁…s_k) gate into elementary additions in the same order; +- moving an elementary addition u += c·s across gates that neither read nor write u and do not write s; +- merging consecutive elementary additions that share kind, frame and the shared register (distinct partners). + +Splitting and merging leave the sequence of scalar operations unchanged. In a fan-out every piece reads the unchanged source, and in a fan-in every piece adds into one destination from distinct sources. Moving an addition across operations on disjoint data, or across operations that only read s, commutes, over every coefficient ring and for all initial values. + +`cxop.py` checks the result directly: the complete rational operator on all 1,023 registers (x, y and every dirty slot) after A, the scatter and B, and the 8 retained totals at the scatter, equal Sussman's original. The dirt gate and the undo gate that Sussman's invocation theorem derives from the product are therefore the same. + +**2. Same family data.** These are asserted equal to the original: +- h, v, R, cst and N; +- the ports, the start and final frames, the scatter table and the retained totals with their frames. + +The frame table only grows, by two frames, and is still reduced echelon with no repeats (E0). + +**3. Legal frames.** `gx.check1` (E1) re-checks the following, replayed from the gates: +- every step is nested; +- every gate is at one frame; +- the y roles are at frame 0 before the scatter, and the retained slots are at their frames. + +The block histograms (E6) and N are recomputed and must match the certificate's fields. In addition, every gate frame contains the x-content support of each non-y operand and of a slot destination after the gate (the source-span rule; zero violations on both certificates). + +**4. Price.** In B₃ the profile is 7 × the block histogram plus 2v copies of each idle climb of the layout, with W = 6v + R and deficit 6v − 7·cst = 216. Only the block histogram changes, and b is the largest 10⁻¹⁸ grid point below the exact moment root by both rational engines with the 10⁻¹⁶ fallback, the next grid point excluded. + +With the unsplit idle climbs (#375), the largest child is 38 of m = 63, so the halving degree is 2. This is #375's admitted condition, and the guard quantities it uses (m, W, R, h, cst) are unchanged. + +**5. Assembly.** PR #315's `outer.assembly` with the bit c = 968197503705007/10¹⁸ (#373) and this b: +- all 47 strict constraints hold; +- the complex side binds; +- κ = 95464544449649/10¹⁷; +- κ + 10⁻¹⁸ is rejected. + +**6. Lean (B₂ only).** In Sussman's five-stage word B₂ the unit theorem of the new certificate is kernel-checked by his +unchanged generators and checker (wht-power-saving-lean `9c94857`): `wht_main_block_B2Ge8FRx` states +`WHTTimeBoundsAt (1 - 8766835/(10:ℝ)^10)`, `tools/Compare.lean` gives `RESULT: PASS`, and the axioms are propext, +Classical.choice and Quot.sound (`lean/LEAN-B2-E8FR.txt`). The B₃ pricing of points 4 and 5, and #377's layouts, have no +Lean proof. diff --git a/research/e8-complex-far-retiming/README.md b/research/e8-complex-far-retiming/README.md new file mode 100644 index 0000000000..f11c1d2d5e --- /dev/null +++ b/research/e8-complex-far-retiming/README.md @@ -0,0 +1,119 @@ +κ = 9.5464544449649e-4 + +# Jacob Sussman's E8 complex unit, re-timed by far piece relocation, in the seven-stage bridged word B₃ + +A conditional finite construction with **κ = 95464544449649/10¹⁷ ≈ 9.5464544449649 × 10⁻⁴**: + +- +4.0188·10⁻⁷ (+0.0421 %) over DaysSky's #375 (9.5424356568133e-4), which is Sussman's original unit in the same layout; +- +2.5031·10⁻⁷ (+0.0262 %) over aliromman's #365 certificate in the same layout (9.54395132518163e-4, computed here). + +The complex side binds. The bit side is #370's E8 bit word in #373's B₃ construction. It is unchanged and does not bind. + +| side | supplier | layout | coarse saving | +| --- | --- | --- | ---: | +| complex | **this package's certificate** `gcert1-e8-r783-far` (Sussman's E8 unit, same operator, new frames and gate order) | B₃ unsplit (#375): m = 63, W = 6v + R = 1,503, deficit 216, max child 38, halving degree 2 | b = 477778832512643/(5·10¹⁷) ≈ **9.55557665025286e-4** | +| bit | #370's `bitE8-r865` in #373's B₃ (split at 27) | m = 56, W = 1,585, deficit 216 | c = 968197503705007/10¹⁸ (= #373) | + +| complex certificate | B₃ split b (#363/#373) | B₃ unsplit b (#375) | κ (unsplit, bit #373) | +| --- | ---: | ---: | ---: | +| Sussman's `gcert1-e8-r783` | 9.32783231884153e-4 | 9.55155017966616e-4 | 9.5424356568133e-4 (= #375) | +| #365 (aliromman, 4 moves) | 9.32928054566567e-4 | 9.55306874505079e-4 | 9.54395132518163e-4 | +| **this package** | 9.33167230469274e-4 | **9.55557665025286e-4** | **9.5464544449649e-4** | + +## What changed in the certificate + +The scalar program is the same. The verifier checks that the full rational operator on all 1,023 registers, with every +initial value a variable, and the 8 retained totals are identical to Sussman's original. h, v, R = 783, cst = 72, +N = 9,039, the ports, start/final frames, scatter table and retained totals are also unchanged. + +Only the frames at which additions happen, and the position of some elementary additions, change: + +1. **Split.** Every fan-out or fan-in gate is split into elementary single additions, in the original order. +2. **Retiming.** Moves stay inside each gate's feasible frame interval, the source-span rule included. There are three kinds: + - single gates; + - connected same-frame blocks; + - sub-blocks (time prefixes and suffixes of a block). These generalise #365's move 4, which re-frames two gates of a four-gate block. + + The candidate frames are: + - the participants' neighbour frames; + - the join of the lower bounds; + - the meet of the upper bounds; + - the lower join plus one vector of the meet. +3. **In-group piece relocation.** A subset of one gate's additions moves to the start or end of its group, at a frame of its own. +4. **Far piece relocation** (new here). An elementary addition moves forward or backward across gates it commutes with + as a scalar operation: they neither read nor write its written register, and do not write its read register. It + then takes its best frame between its new neighbours. This is the generalisation of #365's moves 1 and 2. +5. **Merge.** Consecutive elementary additions with the same kind, frame and shared register are merged back into fan-out + or fan-in gates. The result has 775/1,226 gates in A/B, against 773/1,220, and two new frames. + +The greedy search, which uses the χ ledger χ(r) = r((m/r)^a − 1) at m = 63, first reaches #365's certificate value +exactly (b = 9.32928054566567e-4 split). It then finds 14 further far relocations, each worth 0.253·a. Started from +#365's certificate it reaches the same final value. The block-histogram change against Sussman's original is +x {1:+1, 2:+1, 3:+1, 4:+1, 5:−2}, y {1:+2, 2:+8, 4:−22, 5:+2, 6:+10}, s {1:−1, 2:−7, 3:+5}. + +Not profitable on this unit, and not used: +- a shared-donor response kernel through exterior gauges (Sussman's E7/Q2 rule). The 783 slot responses have rank 120, but every relation at a line entrance loses, and higher entrances have no dependent members; +- lowering a retained total's copy rank. No rational combination of the 8 totals is supported in any of the 511 hyperplanes of F₂⁹. + +## Verify + + bash research/e8-complex-far-retiming/verify.sh --quick /tmp/e8st-q # ~15 s + bash research/e8-complex-far-retiming/verify.sh /tmp/e8st-full # adds the regeneration (~1 min) + +Only Python 3.11+ and the standard library are needed. The steps are: + +0. `MANIFEST.sha256`: every file listed, none unlisted. +1. Inputs pinned by git blob id: + - Sussman's certificate, `gx.py` and `gxcore.py`, the same bytes as in #363/#365/#375; + - #370's bit word, the same bytes as #373's `data/bit`. +2. On both Sussman's original and ours: + - Sussman's `gx.check1` (E0–E7, including the exact scalar replay E5) and the `gxcore` mirror histogram; + - a flipped-sign control, which must be rejected with E5; + - our source-span rule (the x-content support of every non-y operand, and of a slot destination, lies in the gate frame). + + Then the full rational operator identity, the unchanged family data, and the histogram delta. +3. Our reimplementation of the bridged layout B_K (#363's rule, Sussman's coordinate-frame stage geometry): + - nested climbs, equal-frame twin gates, stage entries, final frames, and m − 1 moves per role; + - the exchange identity X_p = −y_p, Y_p = x_p; + - B₂ gives Sussman's idle climbs, and B₃ gives #363's for h = 9 and #373's for h = 8. +4. Coarse savings and κ: + - bit c in B₃ (split, = #373) from our own replay of the bit word's local histogram; + - complex b in B₃, split and unsplit, by both rational engines with the 10⁻¹⁶ fallback and the next grid point excluded; + - PR #315's `outer.assembly`: 47 strict constraints, adjacent κ rejected, complex-bound. + + Regressions: Sussman's split b is #363's 932783231884153/10¹⁸, and the unsplit κ is #375's 95424356568133/10¹⁷. + + 4b. B₂ (Sussman's five-stage word): the unit histogram of both certificates equals the unit block list of the Lean + modules, and b₂ gives the stated Lean exponents (⌊10¹⁰ b₂⌋ − 3, his generator's margin): 8762479 for his, + 8766835 for ours (b₂ = 8.76683894547596e-4, +0.0497 %). +5. Full mode only: our search (`code/cxfar.py`, `code/cxfinal.py`) re-run from Sussman's original must regenerate the shipped certificate byte for byte (decompressed). + +## Admitted conditions and open obligations + +- **Lean: the five-stage (B₂) unit theorem of the new certificate is kernel-checked; the B₃ and #377 layouts remain + without Lean proof.** Sussman's generators (wht-power-saving-lean `9c94857`, unchanged) run on our certificate give + `wht_main_block_B2Ge8FRx : ∃ solve W, WHTProgram solve W ∧ WHTTimeBoundsAt (1 - 8766835/(10:ℝ)^10) W`, against his + `wht_main_block_B2Ge8x` at 1 − 8762479/10¹⁰ for the original. `lake build` passes, `tools/Compare.lean` prints + `RESULT: PASS`, and the axioms are propext, Classical.choice and Quot.sound (`lean/LEAN-B2-E8FR.txt`). The κ of this + package is priced in B₃, which has no Lean proof on either side. There the certificate is checked with his + `gx.check1` and `gxcore`, plus the full operator identity against the original. +- **#375's halving-degree-two guard** for the unsplit complex idle climbs (max child 38 at m = 63: 63² > 2·38²) is + admitted as #375 states it: the row coefficient is 2·1903 + 9909 + 252 = 13,967 < 20,161, with m ≤ 72. The stock + quantities in it (m, W, R, h, cst) are unchanged here. +- **#352/#363's portable complex checks are not re-run on the new certificate.** That covers labels, scalar words and lifetimes, the splice, and the parts of the finite guard that read scalar-macro counts. Its gate count changes from 773/1,220 to 775/1,226 (+0.4 %). +- **The bit side is #373's claim.** We re-certify only c from #370's word with our own engines and layout. #373's checks + of the bit word (seven-stage formal columns, geometry, banks, finite bill) are not re-run here. +- Everything #375/#373/#363/#352 admits: the complex interfaces, precision/recovery and rows, and the analytic transfer. +- This is a conditional finite construction, not a formal verification of the multiplication theorem. + +## Credits + +- **Jacob Sussman:** the E8 unit `gcert1-e8-r783`, `gx`/`gxcore`, the bridged five-stage word and the stage geometry (wht-power-saving-lean, Apache-2.0). +- **aliromman (#365):** the first coupled re-timing of this unit. Our block, sub-block and piece moves generalise its four moves, and our search reproduces its certificate value before going further. +- **DaysSky (#363, #373, #375):** B_K, the seven-stage bit construction and the halving-degree-two complex layout. +- **utcorvusvolat-dotcom (#370):** the E8 bit word. +- **rohanarun (#374):** the #365 composition in split B₃, which we compare against. +- **Our stage lineage:** retiming/descent (#287/#291/#299 via our #329/#359) and reorder (#299/#306), ported to Sussman's format. The far piece relocation is new here. +- PR #315's moment engines and outer assembly (DreamingOfClouds). + +Prepared by Chafik Boukhalfa (chafreaky) with substantial Anthropic Claude assistance. Apache-2.0 (`LICENSE`). See `NOTICE.md` and `PROOF.md`. diff --git a/research/e8-complex-far-retiming/code/cxcheck.py b/research/e8-complex-far-retiming/code/cxcheck.py new file mode 100644 index 0000000000..4973f511e5 --- /dev/null +++ b/research/e8-complex-far-retiming/code/cxcheck.py @@ -0,0 +1,23 @@ +"""Complex certificate checks: Jacob Sussman's gx.check1 (E0-E7: sizes, labels/nesting, equal frames at gates, scatter +cut, gate shapes, bracket rule, exact scalar x-content replay E5, price data E6, exterior gauges E7) and his gxcore +mirror histogram, a flipped-sign control (must fail E5), and the source-span rule (our check: the x-content support of +every non-y operand, and of a slot destination after the gate, lies in the gate frame). +usage: cxcheck.py CERT.json.gz GXDIR""" +import sys, os, gzip, json, copy +from collections import Counter +sys.path.insert(0, os.path.dirname(os.path.abspath(__file__))) +from cxretime import CX +c = json.load(gzip.open(sys.argv[1])); sys.path.insert(0, sys.argv[2]); import gx, gxcore +st = {}; gx.check1(c, scalar=True, stats=st) +Hinv = Counter() +for w in c['blocks'].values(): + for r, n in w.items(): Hinv[int(r)] += n +assert gxcore.mirror(gxcore.normal(copy.deepcopy(c)))['hist'] == dict(Hinv), 'gxcore histogram' +c2 = copy.deepcopy(c) +for g in c2['A']: + if g[0] in ('out', 'in') and g[3]: t, a, b = g[3][0]; g[3][0] = [t, -a, b]; break +try: gx.check1(c2, scalar=True); raise SystemExit('flipped sign accepted') +except AssertionError as e: assert str(e).startswith('E5'), str(e) +sv = CX(c).span_ok(); assert sv == 0, sv +print(' %s: gx.check1 PASS (E0-E7, exact scalar), gxcore mirror PASS, flipped sign rejected (E5), source-span violations 0 | h %d v %d R %d cst %d N %d, gates A/B %d/%d, frames %d' + % (os.path.basename(sys.argv[1]), c['h'], c['v'], c['R'], c['cst'], c['N'], len(c['A']), len(c['B']), len(c['frames']))) diff --git a/research/e8-complex-far-retiming/code/cxfar.py b/research/e8-complex-far-retiming/code/cxfar.py new file mode 100644 index 0000000000..a8e53204f9 --- /dev/null +++ b/research/e8-complex-far-retiming/code/cxfar.py @@ -0,0 +1,85 @@ +"""Far piece relocation on a split gcert/1 program: an elementary piece (out: u += c s with s only read; in: s += c u with +u only read) moves forward/backward across gates that commute with it as scalar operations (they touch neither u, nor +write the read register; for an in-piece, other gates may only ADD into s from sources other than u, never read s), +within its phase, and gets its own best frame between the new neighbours. Greedy best move per pass. +usage: cxfar.py CERT(.json.gz or anneal output) GXDIR OUT [passes]""" +import sys, os, gzip, json, math, copy, random +sys.path.insert(0, os.path.dirname(os.path.abspath(__file__))) +from cxpiece import * +from cxretime import sweep as bsweep + + +def rw(g): + """(reads, writes) of a gate""" + if g[0] == 'neg': return {g[2]}, {g[2]} + if g[0] == 'out': return {g[2]} | {t for t, _, _ in g[3]} | set(g[4]), {t for t, _, _ in g[3]} + return {g[2]} | {s for s, _, _ in g[3]}, {g[2]} + + +def far_pass(c, tag, a, m): + M = CX(c); d = lambda f: len(M.fr[f]); chi = lambda r: 0.0 if r <= 0 else r * (math.exp(a * math.log(m / r)) - 1) + G = M.gates; best = None + for i, (ph, g) in enumerate(G): + if g[0] == 'out' and len(g[3]) == 1 and not g[4]: u = g[3][0][0]; s = g[2]; kind = 'out' + elif g[0] == 'in' and len(g[3]) == 1: u = g[2]; s = g[3][0][0]; kind = 'in' # u written (dst), s read + else: continue + # registers: w = written register (u for out, u for in): naming: wreg written, rreg read + wreg, rreg = u, s + iw, ir = M.where[i][wreg], M.where[i][rreg] + f_i = M.gf[i] + pw, nw = M.F(wreg, iw - 1), M.F(wreg, iw + 1) + a_r, b_r = M.F(rreg, ir - 1), M.F(rreg, ir + 1) + rem_r = chi(d(f_i) - d(a_r)) + chi(d(b_r) - d(f_i)) - chi(d(b_r) - d(a_r)) + for step in (1, -1): + j = i + while True: + j += step + if j < 0 or j >= len(G) or G[j][0] != ph: break + rj, wj = rw(G[j][1]) + if wreg in rj or rreg in wj: break # does not commute (another addition into wreg also breaks: keep simple) + if rreg not in rj: continue # read register untouched: same neighbours + # new position just after j (forward) or just before j (backward): rreg neighbours change + jr = M.where[j][rreg] + if step == 1: ps, ns = M.F(rreg, jr), M.F(rreg, jr + 1) if jr + 1 != ir else b_r + else: ps, ns = (M.F(rreg, jr - 1) if jr - 1 != ir else a_r), M.F(rreg, jr) + if step == 1 and jr + 1 == ir: continue + loE = echelon(list(M.lb[i]) + list(M.fr[ps]) + list(M.fr[pw])) + hiV = span_vecs(M.fr[ns]) & span_vecs(M.fr[nw]) + if not all(x in hiV for x in loE): continue + cands = {M.fid(loE), M.fid(echelon(sorted(hiV))), ps, ns, pw, nw} + for x in sorted(hiV - span_vecs(loE))[:64]: cands.add(M.fid(echelon(loE + [x]))) + old_w = chi(d(f_i) - d(pw)) + chi(d(nw) - d(f_i)) + for F in cands: + if not (inside(M.fr[ps], M.fr[F]) and inside(M.fr[F], M.fr[ns]) and inside(M.fr[pw], M.fr[F]) and inside(M.fr[F], M.fr[nw]) and inside(loE, M.fr[F])): continue + gain = old_w - chi(d(F) - d(pw)) - chi(d(nw) - d(F)) + rem_r - (chi(d(F) - d(ps)) + chi(d(ns) - d(F)) - chi(d(ns) - d(ps))) + if gain > 1e-9 and (best is None or gain > best[0]): best = (gain, i, j, step, F) + if best is None: return c, tag, 0.0 + gain, i, j, step, F = best + gates = [copy.deepcopy(x) for x in G] + for k in range(len(gates)): gates[k][1][1] = M.gf[k] + gates[i][1][1] = F + order = [k for k in range(len(gates)) if k != i] + pos = order.index(j) + (1 if step == 1 else 0); order.insert(pos, i) + c2 = copy.deepcopy(c); c2['frames'] = [list(x) for x in M.fr]; c2['A'] = []; c2['B'] = []; tag2 = [] + for k in order: + c2[gates[k][0]].append(gates[k][1]); tag2.append(list(tag[k][:2]) + (['far', k] if k == i else list(tag[k][2:]))) + return rehist(c2), tag2, gain + + +if __name__ == '__main__': + src = json.load(gzip.open(sys.argv[1])); sys.path.insert(0, sys.argv[2]); import gx + if 'cert' in src: c, tag = src['cert'], [tuple(t) for t in src['tag']] + else: c, tag = split(src) + K = 3; h = c['h']; m = (2 * K + 1) * h; b0 = price(c, K); a = float(b0); rng = random.Random(1) + print('start b3', b0, float(b0)); passes = int(sys.argv[4]) if len(sys.argv) > 4 else 100 + for p in range(passes): + c, tag, g = far_pass(c, tag, a, m) + M = CX(c) + for s in range(10): + m1, _ = single_sweep(M, a, m, rng); m2, _ = bsweep(M, a, m, rng) + if not (m1 or m2): break + c = rehist(to_cert(M)); c, tag, g2 = piece_pass(c, tag, a, m) + b = price(c, K); print('pass', p, 'far gain/a %.3f piece %.3f' % (g / a, g2 / a), 'b3', b, '%.12e' % float(b), flush=True) + if g == 0 and g2 == 0: break + gx.check1(c, scalar=True); print('gx.check1 PASS') + json.dump(dict(cert=c, tag=[list(t) for t in tag]), gzip.open(sys.argv[3], 'wt')) diff --git a/research/e8-complex-far-retiming/code/cxfinal.py b/research/e8-complex-far-retiming/code/cxfinal.py new file mode 100644 index 0000000000..3c55ca4c63 --- /dev/null +++ b/research/e8-complex-far-retiming/code/cxfinal.py @@ -0,0 +1,29 @@ +"""Finalize an optimised split program: merge consecutive elementary gates of one phase that share kind, frame and the +read register (fan-out: same source, distinct targets) or the destination (fan-in: same destination, distinct sources), +drop unused appended frames, recompute the block histograms and N. usage: cxfinal.py IN(anneal/far output) ORIG OUT""" +import sys, os, gzip, json, copy +sys.path.insert(0, os.path.dirname(os.path.abspath(__file__))) +from cxkernel import rehist +def finalize(c, c0): + c = copy.deepcopy(c) + for ph in ('A', 'B'): + out = [] + for g in c[ph]: + p = out[-1] if out else None + if p and p[0] == g[0] == 'out' and p[1] == g[1] and p[2] == g[2] and not ({t for t, _, _ in g[3]} | set(g[4])) & ({t for t, _, _ in p[3]} | set(p[4])): + p[3] = p[3] + g[3]; p[4] = p[4] + g[4] + elif p and p[0] == g[0] == 'in' and p[1] == g[1] and p[2] == g[2] and not {s for s, _, _ in g[3]} & {s for s, _, _ in p[3]}: + p[3] = p[3] + g[3] + else: out.append(copy.deepcopy(g)) + c[ph] = out + used = set(c['start']) | set(c['final']) | {g[1] for g in c['A'] + c['B']} | {f for _, _, f in c['ret']} + keep = list(range(len(c0['frames']))) + [i for i in range(len(c0['frames']), len(c['frames'])) if i in used] + ren = {o: n for n, o in enumerate(keep)}; c['frames'] = [c['frames'][i] for i in keep] + for ph in ('A', 'B'): + for g in c[ph]: g[1] = ren[g[1]] + c['derived_from'] = c0['derived_from'] + ' | e8st far piece relocation + block retiming (chafreaky)' + return rehist(c) +if __name__ == '__main__': + x = json.load(gzip.open(sys.argv[1])); c = x['cert'] if 'cert' in x else x; c0 = json.load(gzip.open(sys.argv[2])) + w = finalize(c, c0); print('gates A/B', len(w['A']), len(w['B']), 'frames', len(w['frames'])) + with gzip.GzipFile(sys.argv[3], 'wb', mtime=0) as f: f.write(json.dumps(w, separators=(',', ':')).encode()) diff --git a/research/e8-complex-far-retiming/code/cxkernel.py b/research/e8-complex-far-retiming/code/cxkernel.py new file mode 100644 index 0000000000..32b26a1755 --- /dev/null +++ b/research/e8-complex-far-retiming/code/cxkernel.py @@ -0,0 +1,222 @@ +"""Shared-donor response kernel on a gcert/1 complex program (Sussman's format), via exterior gauges (rule E7/Q2). +Entry: pivot slot p, entrance E (a frame inside p's first frame and inside every donor's first frame), donors d with +rational coefficients c_d such that resp(p) + sum c_d resp(d) = 0, where resp(s) in Q^v = the column of slot s's +initial value in the y rows of the product (A, scatter, B). Transform: p starts at E (ext gauge [p, E]); at the start +of A each donor climbs to E and takes d += c_d p ('in' gate at E). Then Q2 holds for p. +Price (entrance-residual rule, as the bit side's #320/#329 lineage): W = 2Kv + sum_slots (h - dim ext)/h, deficit fixed. +usage: cxkernel.py CERT.json.gz GXDIR OUT.json.gz [K]""" +import sys, os, gzip, json, math, copy +from fractions import Fraction as Fr +from collections import Counter +sys.path.insert(0, os.path.dirname(os.path.abspath(__file__))) +from e8core import coarse +from layout_bk import layout + + +def reduce(u, basis): + for b in basis: + if u >> (b.bit_length() - 1) & 1: u ^= b + return u +def inside(a, b): return all(reduce(u, b) == 0 for u in a) +def echelon(vecs): + """reduced echelon (descending pivots) of the F2 span of vecs""" + B = [] + for u in vecs: + u = reduce(u, B) + if u: + B = [b ^ u if b >> (u.bit_length() - 1) & 1 else b for b in B] + [u] + B.sort(reverse=True) + return B + + +def responses(c): + v, R = c['v'], c['R']; n = 2 * v + R + reg = [dict() for _ in range(n)] + for r in range(2 * v, n): reg[r] = {r: Fr(1)} + def axpy(t, src, co): + d = reg[t] + for k, u in src.items(): + w = d.get(k, 0) + co * u + if w: d[k] = w + else: d.pop(k, None) + def run(gates): + for g in gates: + if g[0] == 'neg': reg[g[2]] = {k: -u for k, u in reg[g[2]].items()} + elif g[0] == 'out': + src = dict(reg[g[2]]) + for t, a, b in g[3]: axpy(t, src, Fr(a, b)) + else: + for s, a, b in g[3]: axpy(g[2], reg[s], Fr(a, b)) + run(c['A']) + tot = {k: dict(reg[s]) for k, s, _ in c['ret']} + for t in range(v): + for k, a, b in c['scat']['table'][t]: axpy(v + t, tot[k], Fr(a, b)) + run(c['B']) + resp = {s: {} for s in range(2 * v, n)} + for t in range(v): + for s, co in reg[v + t].items(): resp[s][t] = co + return resp + + +def first_frames(c): + v, R = c['v'], c['R']; n = 2 * v + R; first = {} + for ph in ('A', 'B'): + for g in c[ph]: + regs = [g[2]] + ([t for t, _, _ in g[3]] + list(g[4]) if g[0] == 'out' else [s for s, _, _ in g[3]] if g[0] == 'in' else []) + for r in regs: + if r >= 2 * v and r not in first and g[1] != 0: first[r] = g[1] + return first + + +class QBasis: + """incremental rational basis over Q^v with combination tracking (donor slots)""" + def __init__(self): self.rows = [] # (pivot, vec dict, combo dict) + def reduce(self, x): + x = dict(x); cm = {} + for p, vec, co in self.rows: + if p in x: + f = x[p] / vec[p] + for k, u in vec.items(): + w = x.get(k, 0) - f * u + if w: x[k] = w + else: x.pop(k, None) + for k, u in co.items(): + w = cm.get(k, 0) - f * u + if w: cm[k] = w + else: cm.pop(k, None) + return x, cm + def add(self, x, slot): + r, cm = self.reduce(x) + cm = {k: u for k, u in cm.items()}; cm[slot] = cm.get(slot, 0) + 1 + p = min(r); self.rows.append((p, r, cm)) + + +def select(c, a, K=3): + h, v, R = c['h'], c['v'], c['R']; m = (2 * K + 1) * h + fr = [tuple(f) for f in c['frames']]; dim = [len(f) for f in fr] + chi = lambda r: 0.0 if r <= 0 else r * (math.exp(a * math.log(m / r)) - 1) + resp = responses(c); first = first_frames(c) + ret = {s for _, s, _ in c['ret']} + H = [s for s in range(2 * v, 2 * v + R) if s not in ret and s in first and c['start'][s] == 0] + # candidate entrances: frames of the table inside some first frame, plus pairwise intersections not in table skipped + fset = sorted(set(first[s] for s in H)) + cand = [E for E in range(2, len(fr)) if dim[E] > 0 and dim[E] < h and any(inside(fr[E], fr[f]) for f in fset)] + ins = {} + def isin(E, f): + k = (E, f) + if k not in ins: ins[k] = inside(fr[E], fr[f]) + return ins[k] + groups = {E: [s for s in H if isin(E, first[s])] for E in cand} + avail_p = set(H); avail_d = set(H); donor_at = {} + def plan(E): + e = dim[E]; G = groups[E]; mem = [] + for s in G: + d1 = dim[first[s]] + dc = (0.0 if donor_at.get(s) == E else (chi(e) + chi(d1 - e) - chi(d1)) if s in avail_d else None) + if s in donor_at and donor_at[s] != E: dc = None + pg = chi(d1) - chi(d1 - e) if s in avail_p else None + if dc is None and pg is None: continue + mem.append((s, dc, pg)) + mem.sort(key=lambda t: (t[1] if t[1] is not None else 1e9, t[2] if t[2] is not None else -1)) + B = QBasis(); slots = {}; piv = [] + for s, dc, pg in mem: + r, cm = B.reduce(resp[s]) + if not r and pg is not None and pg > 0: piv.append((s, cm, pg)) + elif r and dc is not None: B.add(resp[s], s); slots[s] = dc + if not piv: return None + keep = list(piv) + def users(): + u = Counter() + for _, cm, _ in keep: + for k in cm: u[k] += 1 + return u + while keep: + u = users(); best = None + for i, (s, cm, pg) in enumerate(keep): + freed = sum(slots[k] for k in cm if u[k] == 1) + if freed > pg and (best is None or freed - pg > best[0]): best = (freed - pg, i) + if best is None: break + keep.pop(best[1]) + u = users(); gain = sum(pg for _, _, pg in keep) - sum(slots[k] for k in u) + if gain <= 1e-15: return None + # coefficients: resp(p) = sum cm_k resp(k) -> donor gate d += (-cm_d) p + return gain, [(s, {k: -x for k, x in cm.items()}) for s, cm, _ in keep] + plans = {E: plan(E) for E in cand} + chosen = []; total = 0.0 + while True: + live = [(p[0], E) for E, p in plans.items() if p] + if not live: break + g, E = max(live); _, ents = plans[E] + touched = set() + for p, cm in ents: + chosen.append((E, p, cm)); avail_p.discard(p); avail_d.discard(p); touched.add(p) + for d in cm: donor_at[d] = E; avail_p.discard(d); avail_d.discard(d); touched.add(d) + total += g + for E2 in cand: + if plans.get(E2) and any(s in touched for s in groups[E2]): plans[E2] = plan(E2) + plans[E] = plan(E) + return chosen, total + + +def apply(c, chosen): + c = copy.deepcopy(c); head = [] + ext = [] + for E, p, cm in chosen: + ext.append([p, E]); c['start'][p] = E + byd = {} + for E, p, cm in chosen: + for d, co in cm.items(): byd.setdefault((d, E), []).append([p, co.numerator, co.denominator]) + for (d, E), lst in sorted(byd.items()): head.append(['in', E, d, sorted(lst)]) + c['A'] = head + c['A']; c['ext'] = sorted(ext) + return c + + +def rehist(c): + """recompute block histograms and N exactly as gx.check1 counts them (climbs per class, COPY ranks)""" + v, R = c['v'], c['R']; n = 2 * v + R; dim = [len(f) for f in c['frames']] + cls = lambda r: 'x' if r < v else 'y' if r < 2 * v else 's' + cur = list(c['start']); H = {'x': Counter(), 'y': Counter(), 's': Counter(), 'c': Counter()} + def climb(r, f): + if cur[r] != f: H[cls(r)][dim[f] - dim[cur[r]]] += 1; cur[r] = f + for ph in ('A', 'B'): + if ph == 'B': + for k, s_, f in c['ret']: H['c'][dim[f]] += 1 + for g in c[ph]: + regs = [g[2]] + ([t for t, _, _ in g[3]] + list(g[4]) if g[0] == 'out' else [x for x, _, _ in g[3]] if g[0] == 'in' else []) + for r in regs: climb(r, g[1]) + for r in range(n): climb(r, c['final'][r]) + c['blocks'] = {k: {str(r): x for r, x in sorted(w.items())} for k, w in H.items()} + c['N'] = sum(r * x for w in H.values() for r, x in w.items()) + return c + + +def price(c, K): + """returns b in B_K with the entrance-residual W""" + h, v, R, cst = c['h'], c['v'], c['R'], c['cst'] + Hinv = Counter() + for w in c['blocks'].values(): + for r, n in w.items(): Hinv[int(r)] += n + s = 2 * K + 1; m = s * h; lay = layout(K, h, split=(m - 1) // 2 if K > 2 else None) + tails = sum(len(c['frames'][f]) for _, f in c['ext']) + T = 1 if tails % h == 0 else h + H = Counter({r: T * s * n for r, n in Hinv.items()}) + for r in lay['blocks']: H[r] += T * 2 * v + W = (2 * K * v + R) * T - tails * T // h; assert tails * T % h == 0 + assert m * W - sum(r * n for r, n in H.items()) == T * (2 * K * v - s * cst), 'deficit' + assert 2 * max(H) < m + return coarse(H, m, W) + + +if __name__ == '__main__': + c = json.load(gzip.open(sys.argv[1])); sys.path.insert(0, sys.argv[2]); import gx, gxcore + K = int(sys.argv[4]) if len(sys.argv) > 4 else 3 + b0 = price(c, K); print('start b(B_%d) =' % K, b0, float(b0)) + chosen, tot = select(c, float(b0), K) + fr = c['frames'] + print('entries', len(chosen), 'chi %.5f' % tot, 'ranks', Counter(len(fr[E]) for E, _, _ in chosen), + 'donors', len({d for _, _, cm in chosen for d in cm})) + w = rehist(apply(c, chosen)); w['derived_from'] = c['derived_from'] + ' + shared-donor kernel via exterior gauges' + st = {}; gx.check1(w, scalar=True, stats=st); print('gx.check1 (E0-E7 incl. exact scalar E5 and Q2) PASS', st) + for K2 in (2, 3, 4): + b = price(w, K2); print('b(B_%d) =' % K2, b, float(b)) + json.dump(w, gzip.open(sys.argv[3], 'wt')) diff --git a/research/e8-complex-far-retiming/code/cxop.py b/research/e8-complex-far-retiming/code/cxop.py new file mode 100644 index 0000000000..772d6698da --- /dev/null +++ b/research/e8-complex-far-retiming/code/cxop.py @@ -0,0 +1,32 @@ +"""Full rational operator of a gcert/1 program (A, scatter, B) on all registers, every initial value a variable; +compare two programs. usage: cxop.py CERT1 CERT2 [GXDIR]""" +import sys, gzip, json +from fractions import Fraction as Fr +def load(p): + x = json.load(gzip.open(p)); return x['cert'] if 'cert' in x else x +def op(c): + v, R = c['v'], c['R']; n = 2 * v + R + reg = [{r: Fr(1)} for r in range(n)] + def axpy(t, src, co): + d = reg[t] + for k, u in src.items(): + w = d.get(k, 0) + co * u + if w: d[k] = w + else: d.pop(k, None) + def run(G): + for g in G: + if g[0] == 'neg': reg[g[2]] = {k: -u for k, u in reg[g[2]].items()} + elif g[0] == 'out': + src = dict(reg[g[2]]) + for t, a, b in g[3]: axpy(t, src, Fr(a, b)) + else: + for s, a, b in g[3]: axpy(g[2], reg[s], Fr(a, b)) + run(c['A']); tot = {k: dict(reg[s]) for k, s, _ in c['ret']} + for t in range(v): + for k, a, b in c['scat']['table'][t]: axpy(v + t, tot[k], Fr(a, b)) + run(c['B']); return reg, tot +a, ta = op(load(sys.argv[1])); b, tb = op(load(sys.argv[2])) +assert ta == tb, 'retained totals differ' +diff = [r for r in range(len(a)) if a[r] != b[r]] +print('full rational operator on all %d registers (every initial value a variable) and the retained totals: %s' % (len(a), 'IDENTICAL' if not diff else 'DIFFER at %d registers' % len(diff))) +assert not diff diff --git a/research/e8-complex-far-retiming/code/cxpiece.py b/research/e8-complex-far-retiming/code/cxpiece.py new file mode 100644 index 0000000000..6cebe19c80 --- /dev/null +++ b/research/e8-complex-far-retiming/code/cxpiece.py @@ -0,0 +1,64 @@ +"""Piece relocation on a split gcert/1 program: a fan-out piece (s -> t) or fan-in piece (t += s) of an original gate +moves to the end (frame F >= the group frame) or the start (F <= the group frame) of its group, with its own frame +F between the outside neighbours of the shared register and of its own register (source-span rule kept). +Pieces of one original gate commute (fan-out pieces read an unchanged source; fan-in pieces add into one destination).""" +import sys, os, gzip, json, math, random, copy +sys.path.insert(0, os.path.dirname(os.path.abspath(__file__))) +from cxsplit import * + + +def piece_pass(c, tag, a, m, eps=1e-9): + M = CX(c); d = lambda f: len(M.fr[f]); chi = lambda r: 0.0 if r <= 0 else r * (math.exp(a * math.log(m / r)) - 1) + groups = {} + for gi, t in enumerate(tag): groups.setdefault(tuple(t[:2]), []).append(gi) + best = None + for t, gis in groups.items(): + if len(gis) < 2: continue + f = M.gf[gis[0]] + if any(M.gf[g] != f for g in gis): continue + g0 = M.gates[gis[0]][1]; shared = g0[2] + if any(M.gates[g][1][2] != shared for g in gis): continue + ish = [M.where[x][shared] for x in gis] + info = [] + for gi in gis: + uniq = [r for r in M.where[gi] if r != shared] + if len(uniq) != 1: info.append(None); continue + u = uniq[0]; iu = M.where[gi][u]; info.append((u, M.F(u, iu - 1), M.F(u, iu + 1))) + for side in ('end', 'start'): + if side == 'end': ps, ns = f, M.F(shared, max(ish) + 1) + else: ps, ns = M.F(shared, min(ish) - 1), f + cands = set() + for k, gi in enumerate(gis): + if info[k] is None: continue + u, pu, nu = info[k] + loE = echelon(list(M.lb[gi]) + list(M.fr[ps]) + list(M.fr[pu])) + hiV = span_vecs(M.fr[ns]) & span_vecs(M.fr[nu]) + if not all(x in hiV for x in loE): continue + cands |= {M.fid(loE), M.fid(echelon(sorted(hiV))), ps, ns, pu, nu} + for x in sorted(hiV - span_vecs(loE)): cands.add(M.fid(echelon(loE + [x]))) + for F in cands: + if not (inside(M.fr[ps], M.fr[F]) and inside(M.fr[F], M.fr[ns])): continue + chosen = []; gain = 0.0 + for k, gi in enumerate(gis): + if info[k] is None: continue + u, pu, nu = info[k] + if not (inside(M.fr[pu], M.fr[F]) and inside(M.fr[F], M.fr[nu]) and inside(M.lb[gi], M.fr[F])): continue + du = chi(d(f) - d(pu)) + chi(d(nu) - d(f)) - chi(d(F) - d(pu)) - chi(d(nu) - d(F)) + if du > eps: chosen.append(gi); gain += du + if not chosen or len(chosen) == len(gis): continue + gain -= chi(d(F) - d(ps)) + chi(d(ns) - d(F)) - chi(d(ns) - d(ps)) + if gain > eps and (best is None or gain > best[0]): best = (gain, chosen, side, F, gis) + if best is None: return c, tag, 0.0 + g_, chosen, side, F, gis = best + gates = [copy.deepcopy(M.gates[i]) for i in range(len(M.gates))] + for i in range(len(gates)): gates[i][1][1] = M.gf[i] + for gi in chosen: gates[gi][1][1] = F + rest = [i for i in range(len(gates)) if i not in set(chosen)] + anchor = max(set(gis) - set(chosen)) if side == 'end' else min(set(gis) - set(chosen)) + pos = rest.index(anchor) + (1 if side == 'end' else 0) + order = rest[:pos] + sorted(chosen) + rest[pos:] + c2 = copy.deepcopy(c); c2['frames'] = [list(x) for x in M.fr]; c2['A'] = []; c2['B'] = []; tag2 = [] + for i in order: + c2[gates[i][0]].append(gates[i][1]) + tag2.append(list(tag[i][:2]) + ([side, len(tag)] if i in chosen else [])) + return rehist(c2), tag2, g_ diff --git a/research/e8-complex-far-retiming/code/cxretime.py b/research/e8-complex-far-retiming/code/cxretime.py new file mode 100644 index 0000000000..06f79f8280 --- /dev/null +++ b/research/e8-complex-far-retiming/code/cxretime.py @@ -0,0 +1,169 @@ +"""Retiming / descent on a gcert/1 complex program: move gate frames inside +[span(LB_g + prev frames of participants), AND of next frames] with the source-span rule (the x-content support of every +non-y operand, and of a slot destination after the gate, lies in the gate frame). Pins: start, scatter (y at 0, retained +slots at their ret frame), final. Greedy best-improvement with the chi ledger at m = (2K+1)h. +usage: cxretime.py CERT.json.gz GXDIR OUT.json.gz [K] [sweeps]""" +import sys, os, gzip, json, math, random, copy +from fractions import Fraction as Fr +from collections import Counter +sys.path.insert(0, os.path.dirname(os.path.abspath(__file__))) +from cxkernel import reduce, inside, echelon, rehist, price + + +def regs_of(g): + if g[0] == 'neg': return [g[2]] + if g[0] == 'out': return [g[2]] + [t for t, _, _ in g[3]] + list(g[4]) + return [g[2]] + [s for s, _, _ in g[3]] + + +class CX: + def __init__(self, c): + self.c = c; v = c['v']; self.v = v; n = 2 * v + c['R']; self.n = n + self.fr = [tuple(f) for f in c['frames']]; self.key = {f: i for i, f in enumerate(self.fr)} + self.gates = [['A', g] for g in c['A']] + [['B', g] for g in c['B']] + self.gf = [g[1] for _, g in self.gates] + nA = len(c['A']) + occ = [[('p', c['start'][r])] for r in range(n)] + retf = {s: f for _, s, f in c['ret']} + for gi, (ph, g) in enumerate(self.gates): + if gi == nA: + for t in range(v): occ[v + t].append(('p', 0)) + for s, f in retf.items(): occ[s].append(('p', f)) + for r in regs_of(g): occ[r].append(('g', gi)) + for r in range(n): occ[r].append(('p', c['final'][r])) + self.occ = occ; self.where = [dict() for _ in self.gates] + for r in range(n): + for i, (k, x) in enumerate(occ[r]): + if k == 'g': self.where[x][r] = i + self.lb = self._lb() + + def _lb(self): + c = self.c; v = self.v; ports = c['ports'] + sup = [{r} if r < v else set() for r in range(self.n)] + lb = [] + for ph, g in self.gates: + need = set() + if g[0] == 'out': + for t, _, _ in g[3]: sup[t] |= sup[g[2]] + if g[2] < v or g[2] >= 2 * v: need |= sup[g[2]] + for t, _, _ in g[3]: + if t >= 2 * v: need |= sup[t] + elif g[0] == 'in': + for s, _, _ in g[3]: + sup[g[2]] |= sup[s] + if s < v or s >= 2 * v: need |= sup[s] + if g[2] >= 2 * v: need |= sup[g[2]] + lb.append(tuple(echelon([ports[x] for x in need]))) + return lb + + def fid(self, f): + f = tuple(f) + if f not in self.key: self.key[f] = len(self.fr); self.fr.append(f) + return self.key[f] + + def F(self, r, i): + k, x = self.occ[r][i]; return x if k == 'p' else self.gf[x] + + def span_ok(self): + return sum(1 for gi in range(len(self.gates)) if not inside(self.lb[gi], self.fr[self.gf[gi]])) + + +_sv = {} +def span_vecs(B): + B = tuple(B) + if B not in _sv: + out = {0} + for b in B: out |= {x ^ b for x in out} + _sv[B] = frozenset(out) + return _sv[B] + + +def block_of(M, gi): + f = M.gf[gi]; S = {gi}; stack = [gi] + while stack: + g = stack.pop() + for r, i in M.where[g].items(): + for j in (i - 1, i + 1): + k, x = M.occ[r][j] + if k == 'g' and x not in S and M.gf[x] == f: S.add(x); stack.append(x) + return S + + +def try_move(M, S, chi, d, temp=0.0, rng=None): + """move gate set S (all at one frame) to the best feasible frame; returns gain or None""" + old = M.gf[next(iter(S))]; regs = {} + for g in S: + for r, i in M.where[g].items(): regs.setdefault(r, []).append(i) + parts = [] + for r, ii in regs.items(): + lo_i, hi_i = min(ii), max(ii) + if len(ii) != hi_i - lo_i + 1: return None + parts.append((M.F(r, lo_i - 1), M.F(r, hi_i + 1))) + loE = echelon([u for g in S for u in M.lb[g]] + [u for p, _ in parts for u in M.fr[p]]) + hiV = None + for _, q in parts: + vs = span_vecs(M.fr[q]); hiV = vs if hiV is None else hiV & vs + if not all(u in hiV for u in loE): return None + cands = {M.fid(loE), M.fid(echelon(sorted(hiV)))} | {p for p, _ in parts} | {q for _, q in parts} + for u in sorted(hiV - span_vecs(loE)): cands.add(M.fid(echelon(loE + [u]))) + def ok(F): + return all(inside(M.fr[p], M.fr[F]) and inside(M.fr[F], M.fr[q]) for p, q in parts) and inside(loE, M.fr[F]) + def score(F): return sum(chi(d(F) - d(p)) + chi(d(q) - d(F)) for p, q in parts) + base = score(old); opts = [(score(F), F) for F in cands if F != old and ok(F)] + if not opts: return None + if temp > 0: + sc, F = rng.choice(opts) + if sc < base - 1e-12 or rng.random() < math.exp(-(sc - base) / temp): + for g in S: M.gf[g] = F + return base - sc + return None + sc, F = min(opts) + if sc < base - 1e-12: + for g in S: M.gf[g] = F + return base - sc + return None + + +def subblocks(M, S): + T = sorted(S); out = [S] + for k in range(1, len(T)): out.append(set(T[:k])); out.append(set(T[k:])) + out += [{g} for g in T] if len(T) > 1 else [] + return out + + +def sweep(M, a, m, rng, temp=0.0): + d = lambda f: len(M.fr[f]); chi = lambda r: 0.0 if r <= 0 else r * (math.exp(a * math.log(m / r)) - 1) + moved = 0; gain = 0.0; idx = list(range(len(M.gates))); rng.shuffle(idx); done = set() + for gi in idx: + if gi in done: continue + S = block_of(M, gi); done |= S + subs = subblocks(M, S) if len(S) <= 12 else [S] + if temp > 0: subs = [rng.choice(subs)] + for sub in subs: + g = try_move(M, sub, chi, d, temp, rng) + if g is not None: moved += 1; gain += g; break + return moved, gain + + +def to_cert(M): + c = copy.deepcopy(M.c); c['frames'] = [list(f) for f in M.fr] + A = []; B = [] + for gi, (ph, g) in enumerate(M.gates): + g2 = copy.deepcopy(g); g2[1] = M.gf[gi]; (A if ph == 'A' else B).append(g2) + c['A'] = A; c['B'] = B + return rehist(c) + + +if __name__ == '__main__': + c = json.load(gzip.open(sys.argv[1])); sys.path.insert(0, sys.argv[2]); import gx + K = int(sys.argv[4]) if len(sys.argv) > 4 else 3; sw = int(sys.argv[5]) if len(sys.argv) > 5 else 20 + h = c['h']; m = (2 * K + 1) * h + M = CX(c); print('span violations on input', M.span_ok()) + b0 = price(c, K); print('start b', b0, float(b0)); rng = random.Random(1) + for s in range(sw): + mv, g = sweep(M, float(b0), m, rng); print('sweep', s, 'moved', mv, 'chi/a %.4f' % (g / float(b0)), flush=True) + if not mv: break + w = to_cert(M); print('span violations', M.span_ok()) + st = {}; gx.check1(w, scalar=True, stats=st); print('gx.check1 PASS') + for K2 in (2, 3): b = price(w, K2); print('b(B_%d) =' % K2, b, float(b)) + json.dump(w, gzip.open(sys.argv[3], 'wt')) diff --git a/research/e8-complex-far-retiming/code/cxsplit.py b/research/e8-complex-far-retiming/code/cxsplit.py new file mode 100644 index 0000000000..e9cd44a1fe --- /dev/null +++ b/research/e8-complex-far-retiming/code/cxsplit.py @@ -0,0 +1,92 @@ +"""Split every multi-addition gate of a gcert/1 program into elementary single-addition gates in the same order (same +scalar operator: fan-out pieces read an unchanged source, fan-in pieces add into one destination), then run block and +single-gate retiming (cxretime) on the split program, then re-merge adjacent pieces of one original gate that kept a +common frame. usage: cxsplit.py CERT.json.gz GXDIR OUT.json.gz [K] [sweeps] [seed]""" +import sys, os, gzip, json, math, random, copy +sys.path.insert(0, os.path.dirname(os.path.abspath(__file__))) +from cxretime import * +from cxretime import sweep as block_sweep + + +def split(c): + c = copy.deepcopy(c); tag = [] + for ph in ('A', 'B'): + out = [] + for gi, g in enumerate(c[ph]): + if g[0] == 'out' and len(g[3]) + len(g[4]) > 1: + pieces = [['out', g[1], g[2], [x], []] for x in g[3]] + if g[4]: pieces[0][4] = list(g[4]) if pieces else None + for p_ in pieces: out.append(p_); tag.append((ph, gi)) + elif g[0] == 'in' and len(g[3]) > 1: + for x in g[3]: out.append(['in', g[1], g[2], [x]]); tag.append((ph, gi)) + else: out.append(g); tag.append((ph, gi)) + c[ph] = out + return c, tag + + +def merge(c, tag): + c = copy.deepcopy(c); k = 0 + for ph in ('A', 'B'): + out = []; prev = None + for g in c[ph]: + t = tag[k]; k += 1 + if prev is not None and prev[0] == t and out[-1][0] == g[0] and out[-1][1] == g[1] and out[-1][2] == g[2]: + out[-1][3] = out[-1][3] + g[3] + if g[0] == 'out': out[-1][4] = out[-1][4] + g[4] + else: out.append(copy.deepcopy(g)) + prev = (t,) + c[ph] = out + return c + + +def single_sweep(M, a, m, rng): + d = lambda f: len(M.fr[f]); chi = lambda r: 0.0 if r <= 0 else r * (math.exp(a * math.log(m / r)) - 1) + moved = 0; gain = 0.0; idx = list(range(len(M.gates))); rng.shuffle(idx) + for gi in idx: + old = M.gf[gi]; parts = [(M.F(r, i - 1), M.F(r, i + 1)) for r, i in M.where[gi].items()] + loE = echelon(list(M.lb[gi]) + [u for p, _ in parts for u in M.fr[p]]) + hiV = None + for _, q in parts: + vs = span_vecs(M.fr[q]); hiV = vs if hiV is None else hiV & vs + if not all(u in hiV for u in loE): continue + cands = {M.fid(loE), M.fid(echelon(sorted(hiV)))} | {p for p, _ in parts} | {q for _, q in parts} + loS = span_vecs(loE) + for u in sorted(hiV - loS): cands.add(M.fid(echelon(loE + [u]))) + def ok(F): return all(inside(M.fr[p], M.fr[F]) and inside(M.fr[F], M.fr[q]) for p, q in parts) and inside(loE, M.fr[F]) + def score(F): return sum(chi(d(F) - d(p)) + chi(d(q) - d(F)) for p, q in parts) + base = score(old); best, bs = old, base + for F in cands: + if F != old and ok(F): + sc = score(F) + if sc < bs - 1e-12: best, bs = F, sc + if best != old: M.gf[gi] = best; moved += 1; gain += base - bs + return moved, gain + + +def prune_frames(c): + """drop unused appended frames (keep the original table prefix), renumber""" + return c + + +if __name__ == '__main__': + c0 = json.load(gzip.open(sys.argv[1])); sys.path.insert(0, sys.argv[2]); import gx + K = int(sys.argv[4]) if len(sys.argv) > 4 else 3; sw = int(sys.argv[5]) if len(sys.argv) > 5 else 30 + rng = random.Random(int(sys.argv[6]) if len(sys.argv) > 6 else 1) + h = c0['h']; m = (2 * K + 1) * h; b0 = price(c0, K); print('start b', b0, float(b0)) + c, tag = split(c0); M = CX(c); a = float(b0) + for s in range(sw): + m1, g1 = single_sweep(M, a, m, rng); m2, g2 = block_sweep(M, a, m, rng) + print('sweep', s, 'single', m1, 'block', m2, 'chi/a %.4f' % ((g1 + g2) / a), flush=True) + if not (m1 or m2): break + w = to_cert(M); w = rehist(merge(w, tag)) + # drop unused frames beyond the original table + used = set(w['start']) | set(w['final']) | {g[1] for g in w['A'] + w['B']} | {f for _, _, f in w['ret']} + keep = list(range(len(c0['frames']))) + [i for i in range(len(c0['frames']), len(w['frames'])) if i in used] + ren = {o: n for n, o in enumerate(keep)}; w['frames'] = [w['frames'][i] for i in keep] + for ph in ('A', 'B'): + for g in w[ph]: g[1] = ren[g[1]] + w = rehist(w) + print('span violations', CX(w).span_ok(), '| gates A/B', len(w['A']), len(w['B']), 'vs', len(c0['A']), len(c0['B']), '| new frames', len(w['frames']) - len(c0['frames'])) + st = {}; gx.check1(w, scalar=True, stats=st); print('gx.check1 PASS (E0-E7, exact scalar E5)') + for K2 in (2, 3): b = price(w, K2); print('b(B_%d) =' % K2, b, float(b)) + json.dump(w, gzip.open(sys.argv[3], 'wt')) diff --git a/research/e8-complex-far-retiming/code/e8core.py b/research/e8-complex-far-retiming/code/e8core.py new file mode 100644 index 0000000000..78983b3687 --- /dev/null +++ b/research/e8-complex-far-retiming/code/e8core.py @@ -0,0 +1,203 @@ +"""Our own engine for bitE8/1 words (E8 root-line labels, h = 8): frame algebra over Q via root-line masks, +legality/F2 replay, five-stage histogram, exact bit coarse saving and PR #315 outer assembly (our engine copies). +Chafik Boukhalfa (chafreaky) with Anthropic Claude assistance; Apache-2.0.""" +import gzip, json, os, importlib.util +from fractions import Fraction as Q +from collections import Counter + +HERE = os.path.dirname(os.path.abspath(__file__)) +def _load(n): + s = importlib.util.spec_from_file_location('e8_' + n, os.path.join(HERE, "engines", n + ".py")) + m = importlib.util.module_from_spec(s); s.loader.exec_module(m); return m +moment = _load('moment'); other = _load('base_two_moment'); outer = _load('outer') + +B2 = Q(876248285600677, 10**18) # Sussman E8 five-stage (PR #352) +B3 = Q(932783231884153, 10**18) # DaysSky seven-stage B_3 (PR #363; no Lean proof) + + +def load_word(p): + with (gzip.open(p, 'rt') if p.endswith('.gz') else open(p)) as f: + return json.load(f) + + +def save_word(c, p): + with gzip.open(p, 'wt') as f: + json.dump(c, f, separators=(',', ':')) + + +def rank(vecs): + rows = [[Q(x) for x in r] for r in vecs]; rk = 0 + n = len(rows[0]) if rows else 0 + for col in range(n): + p = next((i for i in range(rk, len(rows)) if rows[i][col] != 0), None) + if p is None: continue + rows[rk], rows[p] = rows[p], rows[rk] + for i in range(len(rows)): + if i != rk and rows[i][col] != 0: + f = rows[i][col] / rows[rk][col]; rows[i] = [a - f * b for a, b in zip(rows[i], rows[rk])] + rk += 1 + return rk + + +class Lat: + """Root-spanned subspaces of Q^8 represented by the mask of root lines they contain.""" + def __init__(self, lines): + self.lines = [tuple(x) for x in lines]; self.v = len(lines) + self._dim = {0: 0}; self._close = {} + # Gram (form /2) for orthogonality + self.ip = [[sum(a * b for a, b in zip(x, y)) // 2 for y in self.lines] for x in self.lines] + + def close(self, mask): + """mask of all root lines in span(roots of mask)""" + if mask in self._close: return self._close[mask] + idx = [i for i in range(self.v) if mask >> i & 1] + basis = [] + for i in idx: + if rank([self.lines[j] for j in basis] + [self.lines[i]]) > len(basis): basis.append(i) + d = len(basis); out = 0 + if d == 8: out = (1 << self.v) - 1 + elif d: + B = [self.lines[j] for j in basis] + for i in range(self.v): + if rank(B + [self.lines[i]]) == d: out |= 1 << i + self._close[mask] = out; self._close[out] = out; self._dim[out] = d + return out + + def dim(self, mask): + if mask not in self._dim: self.close(mask) + return self._dim[mask] + + def basis(self, mask): + b = [] + for i in range(self.v): + if mask >> i & 1 and rank([self.lines[j] for j in b] + [self.lines[i]]) > len(b): b.append(i) + return b + + def perp(self, t): + return self.close(sum(1 << j for j in range(self.v) if self.ip[t][j] == 0)) + + +def to_masks(c, L): + return [L.close(sum(1 << i for i in fr)) for fr in c['frames']] + + +PHASES = ('D', 'A', 'B', 'C') + + +def replay(c, L=None, masks=None, check_f2=True, span=True, span_mode='z'): + """Exact legality + F2 replay + histogram of a bitE8/1 word. Returns dict(H_local, steps, ...). + Legality: each register's frames nested (mask inclusion = exact Q-subspace inclusion for root-spanned frames) and + strictly increasing at each move; every gate at one common frame; D compensation at frame 0; y at frame 0 at the + scatter; COPY of retained totals; final frames (x, helpers FULL; y_t at its cap t-perp). + Source-span: every non-target operand's x-support lies in the gate frame.""" + L = L or Lat(c['lines']); masks = masks or to_masks(c, L) + v, R, h = c['v'], c['R'], c['h']; n = 2 * v + R; FULL = (1 << v) - 1 + cur = [masks[f] for f in c['start']] + for r in range(v): assert cur[r] == L.close(1 << r), 'x start' + for r in range(v, 2 * v): assert cur[r] == 0, 'y start at 0' + sig = [L.dim(cur[r]) for r in range(n)] + H = Counter(); steps = 0; viol = [] + val = [1 << i for i in range(n)] + zsupp = [{i: 1} if i < v else {} for i in range(n)] # integer support of each register over the x columns (all ADDs are +1) + def climb(r, m): + nonlocal steps + if cur[r] == m: return + assert cur[r] & ~m == 0 and cur[r] != m, ('not nested', r) + H[L.dim(m) - L.dim(cur[r])] += 1; steps += 1; cur[r] = m + def run(gates, ph): + for k, (f, d, srcs) in enumerate(gates): + m = masks[f] + assert d >= v and d not in srcs and len(set(srcs)) == len(srcs), (ph, k) + for x in [d] + srcs: climb(x, m) + for s in srcs: + val[d] ^= val[s] + if span: + if s < v or s >= 2 * v: + ms = sum(1 << i for i in zsupp[s]) + if ms & ~m: viol.append((ph, k, s)) + zd = zsupp[d] + for i, a in zsupp[s].items(): + w = zd.get(i, 0) + a + if w: zd[i] = w + else: zd.pop(i, None) + if span_mode == 'f2': + zsupp[d] = {i: 1 for i in range(v) if val[d] >> i & 1} + if span and d >= 2 * v: + md = sum(1 << i for i in zsupp[d]) + if md & ~m: viol.append((ph, k, d)) + run(c['D'], 'D') + for r in range(v, n): assert cur[r] == masks[c['start'][r]], 'D compensation at frame 0 (helpers untouched otherwise)' + run(c['A'], 'A') + for t in range(v): assert cur[v + t] == 0, 'y at frame 0 at the scatter' + copies = [val[q] for q in c['ret']] + for q in c['ret']: + assert q >= 2 * v; H[L.dim(cur[q])] += 1 + for t, row in enumerate(c['scatter']): + for k in row: val[v + t] ^= copies[k] + run(c['B'], 'B'); run(c['C'], 'C') + for r in range(n): climb(r, masks[c['final'][r]]) + for r in range(v): assert cur[r] == FULL + for r in range(2 * v, n): assert cur[r] == FULL + for t in range(v): assert cur[v + t] == L.perp(t), 'y final at cap' + if check_f2: + for s in range(v): assert val[s] == 1 << s + for t in range(v): assert val[v + t] == (1 << (v + t)) | (1 << t), ('target', t) + for r in range(2 * v, n): assert val[r] == 1 << r, ('helper', r) + return dict(sig=sig, viol=viol, H=H, steps=steps, n=n, v=v, R=R, h=h, L=L, masks=masks, ncopy=len(c['ret'])) + + +def profile(H_local, v, h=8): + prof = Counter({j: 5 * c for j, c in H_local.items()}) + for j in (2 * h - 2, h - 1, 2 * h + 2, 4): prof[j] += 2 * v + return prof + + +def coarse(H, m, W): + grid = Q(1, 10**18) + root = moment.certify(dict(H), m, W, True); c = Q(int(Q(root['lower']) * 10**18), 10**18) + assert moment.moment(H, m, W, c, True)[1] < 1 < moment.moment(H, m, W, c + grid, True)[0] + fb = 32 * m * m * sum(H.values()) + _, up = other.moment(m, W, list(H.items()), c); _, bad = other.moment(m, W, [(1, fb)], c) + lo, _ = other.moment(m, W, list(H.items()), c + grid); blo, _ = other.moment(m, W, [(1, fb)], c + grid) + assert up + Q(1, 10**16) * bad < 1 < lo + Q(1, 10**16) * blo + return c + + +def kappa(c, b): + grid = Q(1, 10**18); eta = Q(1, 10**12); beta = Q(1, 10**9); cap = (1 - beta) * b + sv = min(c, Q(((cap - grid) * 10**18).__floor__(), 10**18)); binding = 'bit' if sv == c else 'complex' + chain = [Q(384599, 10**10)] + for _ in range(3): + a = (1 - sv) * sv + sv * chain[-1]; assert chain[-1] < a < sv < 1 - a; chain.append(a) + bit = chain[-1] + bridge = dict(proof='PROOF.md', representation='Exact powers with source-bound finite overcharges', + semantic=dict(G=dict(base=2, exponent=30000), E=dict(base=2, exponent=100000), B_upper=dict(base=2, exponent=100001), + C0=dict(base=2, exponent=210000), C1=1, strict_literal_gap=1, induction_gap_lower=1), + rows=dict(coefficient=20161, degree=10**6, suffix_slope=4 * 10**6, degree_gap=Q(10**6) - Q(51 * 20161, 25))) + q = bit * (1 - 2 * eta); mn = (1 - eta) * q / (1 + q); t = mn * 10**18; k = Q((t.numerator - 1) // t.denominator, 10**18) + asm = outer.assembly(bit, b, bridge, k, eta=eta, beta=beta) + assert len(asm['strict_constraints']) == 47 and min(asm['strict_constraints'].values()) > 0 + try: + outer.assembly(bit, b, bridge, k + grid, eta=eta, beta=beta); raise SystemExit('ADJACENT ADMITTED') + except AssertionError: pass + return k, binding + + +def price_word(c, **kw): + r = replay(c, **kw) + v, h, R = r['v'], r['h'], r['R']; m = 5 * h + resid = sum(h - r['sig'][x] for x in range(2 * v, 2 * v + R)) + T = 1 if resid % h == 0 else h + W = (4 * v * h + resid) * T // h; assert (4 * v * h + resid) * T % h == 0 + prof = Counter({j: T * k for j, k in profile(r['H'], v, h).items()}); mass = sum(a * b for a, b in prof.items()) + L_copy = h * r['ncopy'] + assert m * W - mass == T * (4 * v - 5 * L_copy), ('deficit', m * W - mass) + assert 2 * max(prof) < m + cc = coarse(prof, m, W) + return dict(c=cc, H=r['H'], prof=prof, W=W, T=T, resid=resid, m=m, deficit=m * W - mass, replay=r) + + +def phi_fn(m, W, a): + """linearized moment term per child of rank r (float), for search scoring""" + import math + return lambda r: r / (m * W) * math.exp(a * math.log(m / r)) diff --git a/research/e8-complex-far-retiming/code/engines/base_two_moment.py b/research/e8-complex-far-retiming/code/engines/base_two_moment.py new file mode 100644 index 0000000000..14a90fa0e7 --- /dev/null +++ b/research/e8-complex-far-retiming/code/engines/base_two_moment.py @@ -0,0 +1,63 @@ +#!/usr/bin/env python3 +"""Maintainer arithmetic cross-check of the pinned PR39 certificate. + +Uses no producer/checker imports. Counts are inputs, not proved by this script. +80-term rational logarithms and 12-term exponentials independently enclose +the two moments. The accompanying written review addresses their realization. +""" +import argparse +from fractions import Fraction as Q +from hashlib import sha256 +import json +from pathlib import Path + +ROOT = Path(__file__).resolve().parents[1] +GRID = 10**30 + + +def require(condition, message): + if not condition: + raise ValueError(message) + + +def log_unit(x): + require(1 <= x <= 2, "logarithm range") + z = (x-1)/(x+1) + lo = 2*sum((z**(2*j+1)/(2*j+1) for j in range(80)), Q(0)) + return lo, lo+2*z**161/(161*(1-z*z)) + + +def log_bounds(x): + k = 0 + while x > 2: + x /= 2 + k += 1 + lo, hi = log_unit(x) + l2, u2 = log_unit(Q(2)) + lo, hi = lo+k*l2, hi+k*u2 + # Outward rational rounding keeps later certificates compact. + return Q((lo*GRID).__floor__(), GRID), Q((hi*GRID).__ceil__(), GRID) + + +def exp_bounds(x): + require(0 <= x < 1, "exponential range") + term = total = Q(1) + for j in range(1, 13): + term *= x/j + total += term + tail = term*x/13/(1-x/14) + return total, total+tail + + +def moment(m, W, entries, saving): + lo = hi = Q(0) + for t, count in entries: + t, count = int(t), int(count) + require(0 < t < m and count > 0, "improper child") + l, u = log_bounds(Q(m, t)) + lower = exp_bounds(saving*l)[0] + upper = exp_bounds(saving*u)[1] + lo += Q(t*count, m*W)*lower + hi += Q(t*count, m*W)*upper + return Q((lo*GRID).__floor__(), GRID), Q((hi*GRID).__ceil__(), GRID) + diff --git a/research/e8-complex-far-retiming/code/engines/moment.py b/research/e8-complex-far-retiming/code/engines/moment.py new file mode 100644 index 0000000000..7d697cb452 --- /dev/null +++ b/research/e8-complex-far-retiming/code/engines/moment.py @@ -0,0 +1,113 @@ +"""Independent prospective ordinary five-stage cost, never supplier admission. + +Consumes a raw one-invocation ledger made from the actual source/internal/target +paths. No packed profile is used as an input. Missing physical/finite/compiler +obligations must remain explicit in the accompanying report. +""" +from collections import Counter +from decimal import Decimal, localcontext, ROUND_FLOOR +from fractions import Fraction as F +from functools import lru_cache +from math import factorial +import hashlib, json, sys +from pathlib import Path + +DYAD = 1 << 224 + +def floor(x): return F(x.numerator*DYAD//x.denominator, DYAD) +def ceil(x): return -floor(-x) + +@lru_cache(None) +def logarithm(x): + """Mercator bounds after binary reduction; ln(2) via two Mercator sums. + + For 1 <= y < 2, log(y) is an alternating series in z=y-1. + We instead reduce to 1 <= y < 3/2, and bound log(3/2) and + log(2) by the same alternating series at z=1/2 and z=1/3, + using log(2)=log(3/2)+log(4/3). All sums are exact rationals. + """ + assert x >= 1 + k = 0 + while x >= 2: x /= 2; k += 1 + j = int(x >= F(3, 2)) + if j: x /= F(3, 2) + def mercator(y): + z=y-1 + assert 0 <= z <= F(1,2) + # An even partial sum is below log; the next term bounds its tail. + t=z; s=F(0) + for n in range(1, 225): + s += (t if n & 1 else -t)/n + t *= z + return s, s+t/225 + a,b=mercator(x); c,d=mercator(F(3,2)); e,f=mercator(F(4,3)) + return floor(a+(k+j)*c+k*e), ceil(b+(k+j)*d+k*f) + +def exponential(l,u): + assert 0 <= l <= u < F(1,10) + def poly(x): + s=t=F(1) + for j in range(1,25): t=t*x/j; s+=t + return s,t + lo,_=poly(l);hi,last=poly(u) + return floor(lo),ceil(hi+last*u/25/(1-u/26)) + +def moment(H,m,W,a,bad=False): + lo=hi=F(0) + for r,n in H.items(): + assert 0 < r < m and n > 0 + l,u=logarithm(F(m,r)); e,f=exponential(a*l,a*u) + p=F(r*n,m*W);lo+=p*e;hi+=p*f + if bad: + # Existing envelope shape, only conditionally portable to the new cover. + l,u=logarithm(F(m));e,f=exponential(a*l,a*u) + p=F(32*m*sum(H.values()),10**16*W) + lo+=p*e;hi+=p*f + return floor(lo),ceil(hi) + +def decimal(x): + with localcontext() as c: + c.prec=70 + return str(Decimal(x.numerator)/Decimal(x.denominator)) + +def certify(H,m,W,bad=False): + with localcontext() as c: + c.prec=70 + terms=[(Decimal(r*n)/Decimal(m*W),(Decimal(m)/Decimal(r)).ln()) for r,n in H.items()] + fallback=Decimal(32*m*sum(H.values()))/Decimal(10**16*W) if bad else Decimal(0) + lm=Decimal(m).ln();lo=Decimal(0);hi=Decimal('.003') + for _ in range(210): + a=(lo+hi)/2 + if sum(p*(a*l).exp() for p,l in terms)+fallback*(a*lm).exp()<1:lo=a + else:hi=a + q=int(((lo+hi)/2*10**24).to_integral_value(rounding=ROUND_FLOOR)) + lo=F(q,10**24);hi=lo+F(1,10**24) + lv=moment(H,m,W,lo,bad);hv=moment(H,m,W,hi,bad) + assert lv[1]<10 for v in slacks.values()),{k:str(v) for k,v in slacks.items() if v<=0} + assert min(margins.values())==minimum + assert margins['balanced_prefix']-minimum==eta and 1-eps-r==eta/2 + assert 1-eps*(1+c)==eta-eps*eta/4 + return dict(parameters=dict(a_bit=a,a_complex=b,tau=tau,sigma=sigma, + eta=eta,beta=beta,q=q,c=c,epsilon=eps,lambda_=lam, + lambda_prime=lp,alpha_squared_power=r,delta=delta, + C0=bridge['semantic']['C0'],C1=1,kappa=kappa), + strict_constraints=slacks,margins=margins,minimum_margin=minimum, + absorption_gap=minimum-kappa, + recurrence=dict(internal=internal,leaf=leaf,reservations=1-c)) diff --git a/research/e8-complex-far-retiming/code/kappa.py b/research/e8-complex-far-retiming/code/kappa.py new file mode 100644 index 0000000000..3209b54672 --- /dev/null +++ b/research/e8-complex-far-retiming/code/kappa.py @@ -0,0 +1,52 @@ +"""Exact coarse savings in the seven-stage bridged word B_3 and PR #315's outer assembly. +Complex: (2K+1) x Sussman-format block histogram + 2v x B_3 idle climbs, UNSPLIT (38 | 16, 8, 22 | 32, 8, 6 at h = 9, +m = 63; max child 38: halving degree two, the admitted condition of DaysSky's PR #375), W = 6v + R, deficit 6v - 7 cst. +Bit (non-binding): #370's E8 bit word (as in #373) local histogram (our replay) x 7 + 2v x B_3 idle climbs at h = 8, +split at 27 (#373), m = 56, W = 6v + R, deficit 6v - 7 x 72. Both rational engines, 1e-16 fallback, adjacent grid +point excluded; kappa by outer.assembly (47 strict constraints, adjacent kappa rejected). +usage: kappa.py COMPLEX_CERT ORIGINAL_CERT BITWORD OUT.json""" +import sys, os, gzip, json +from collections import Counter +sys.path.insert(0, os.path.dirname(os.path.abspath(__file__))) +from e8core import coarse, kappa, price_word, load_word, Q +from layout_bk import layout + + +def complex_b(c, K=3, split=False): + h, v, R, cst = c['h'], c['v'], c['R'], c['cst']; Hinv = Counter() + for w in c['blocks'].values(): + for r, n in w.items(): Hinv[int(r)] += n + s = 2 * K + 1; m = s * h; lay = layout(K, h, split=(m - 1) // 2 if split else None) + H = Counter({r: s * n for r, n in Hinv.items()}) + for r in lay['blocks']: H[r] += 2 * v + W = 2 * K * v + R; assert m * W - sum(r * n for r, n in H.items()) == 2 * K * v - s * cst + mx = max(H); t = 1 + while m ** t <= 2 * mx ** t: t += 1 + assert m <= 72 and t == (1 if split else 2) + return coarse(H, m, W), mx, t, lay['per_pair'] + + +def bit_c(word, K=3): + p = price_word(word); h, v = 8, 120; s = 2 * K + 1; m = s * h + assert p['T'] == 1; R = word['R'] + lay = layout(K, h, split=(m - 1) // 2) + H = Counter({r: s * n for r, n in p['H'].items()}) + for r in lay['blocks']: H[r] += 2 * v + W = 2 * K * v + R; assert m * W - sum(r * n for r, n in H.items()) == 2 * K * v - s * 72 and 2 * max(H) < m + return coarse(H, m, W) + + +ours = json.load(gzip.open(sys.argv[1])); orig = json.load(gzip.open(sys.argv[2])); word = load_word(sys.argv[3]) +c = bit_c(word); assert c == Q(968197503705007, 10**18), c +print(' bit side (non-binding): #370 E8 bit word in B_3 (split at 27, as #373): c = %s = %.15e (= #373)' % (c, float(c))) +out = dict(bit_coarse=str(c)) +for name, cert in (('original', orig), ('ours', ours)): + bs, _, _, _ = complex_b(cert, split=True) + b, mx, t, idle = complex_b(cert) + k, bd = kappa(c, b); assert bd == 'complex' + print(' %-8s complex B_3 split b = %.15e | unsplit (max child %d, halving degree %d, idle %s) b = %s = %.15e | kappa = %s = %.15e (%s-bound)' + % (name, float(bs), mx, t, idle, b, float(b), k, float(k), bd)) + out[name] = dict(b_split=str(bs), b_unsplit=str(b), kappa=str(k), kappa_float=float(k), binding=bd) +assert out['original']['b_split'] == '932783231884153/1000000000000000000' # #363 +assert out['original']['kappa'] == '95424356568133/100000000000000000' # #375 reproduced +json.dump(out, open(sys.argv[4], 'w'), indent=1) diff --git a/research/e8-complex-far-retiming/code/layout_bk.py b/research/e8-complex-far-retiming/code/layout_bk.py new file mode 100644 index 0000000000..57aa98085b --- /dev/null +++ b/research/e8-complex-far-retiming/code/layout_bk.py @@ -0,0 +1,63 @@ +"""Our own check of the bridged layout B_K (Sussman's B_2, Work/Bridge/Net.lean; DaysSky's B_K generalisation, PR #363), +reimplemented from the schedule stated in PR #363's README and Sussman's coordinate-frame stage geometry: +K bank pairs, 2K+1 stages on H + 2K.H (m = (2K+1)h). Pair 1: forward, backward, forward; pair p >= 2: backward, forward, +borrowing its first forward from pair p-1 through twin gates (+-1 additions at equal frames). +Checks: frames are coordinate sets; every climb nested; twin gates at equal frames; each invocation entered at its +stage frame; final frames; m-1 moves per data role; exchange identity X_p = -y_p, Y_p = x_p (exact integer +linear algebra on symbolic coefficient vectors). Returns the idle climbs per role pair (optionally split at s). +Chafik Boukhalfa (chafreaky) with Anthropic Claude assistance; Apache-2.0.""" +def layout(K, h, split=None): + s = 2 * K + 1; m = s * h; l = 0 + blk = lambda name, skip=None: {(name, j) for j in range(h) if j != skip} + B0 = blk('b0'); F = ['F%d' % i for i in range(s - 1)] + ALL = set(B0).union(*[blk(f) for f in F]); assert len(ALL) == m + def enter(t, X): + if t == 0: return {('b0', l)} if X else set() + base = set(B0) if X else B0 - {('b0', l)} + for f in F[:t - 1]: base |= blk(f, l) + return base + def leave(t, X): + return (set(B0) if X else B0 - {('b0', l)}) if t == 0 else enter(t, X) | blk(F[t - 1], l) + sched = [(0, 'F', 1), (1, 'B', 1), (2, 'F', 1)] + for p in range(2, K + 1): sched += [(2 * p - 1, 'B', p), (2 * p, 'F', p)] + fr = {(X, p): enter(0, X) for p in range(1, K + 1) for X in (True, False)} + inv = {k: 0 for k in fr}; idle = {k: [] for k in fr} + # symbolic values: vector over symbols x1..xK, y1..yK + sym = lambda nm, p: tuple(int(q == (nm, p)) for q in [(a, b) for a in 'xy' for b in range(1, K + 1)]) + val = {(True, p): sym('x', p) for p in range(1, K + 1)} | {(False, p): sym('y', p) for p in range(1, K + 1)} + add = lambda u, w, c: tuple(a + c * b for a, b in zip(u, w)) + def go(k, new, is_idle): + assert fr[k] <= new, 'climb not nested' + if new != fr[k]: + (idle[k].append(len(new) - len(fr[k])) if is_idle else None) + if not is_idle: inv[k] += len(new) - len(fr[k]) + fr[k] = set(new) + def gate(d, s_, c): + assert fr[d] == fr[s_], 'twin gate at unequal frames' + val[d] = add(val[d], val[s_], c) + for t, kind, p in sched: + for X in (True, False): + go((X, p), enter(t, X), True); go((X, p), leave(t, X), False) + if kind == 'F': val[(False, p)] = add(val[(False, p)], val[(True, p)], 1) + else: val[(True, p)] = add(val[(True, p)], val[(False, p)], -1) + for q in range(2, K + 1): + if t in (2 * q - 3, 2 * q - 2): + for X in (True, False): go((X, q), fr[(X, q - 1)], True) + if t == 2 * q - 3: gate((True, q - 1), (True, q), 1); gate((False, q), (False, q - 1), -1) + else: gate((False, q), (False, q - 1), 1); gate((True, q - 1), (True, q), -1) + for k in fr: go(k, ALL if k[0] else ALL - {('b0', l)}, True) + for q in range(K, 1, -1): gate((False, q - 1), (False, q), -1); gate((True, q), (True, q - 1), 1) + for k in fr: assert inv[k] + sum(idle[k]) == m - 1 + for p in range(1, K + 1): + assert val[(True, p)] == tuple(-a for a in sym('y', p)) and val[(False, p)] == sym('x', p), ('exchange', p) + assert idle[(True, p)] == idle[(False, p)] + blocks = [r for p in range(1, K + 1) for r in idle[(True, p)]] + if split: + out = [] + for r in blocks: + while r > split: out.append(split); r -= split + if r: out.append(r) + blocks = out + return dict(m=m, per_pair={p: idle[(True, p)] for p in range(1, K + 1)}, blocks=blocks) +if __name__ == '__main__': + print(layout(2, 9)); print(layout(3, 9)); print(layout(3, 9, split=31)) diff --git a/research/e8-complex-far-retiming/complex/LICENSE-wht-power-saving-lean b/research/e8-complex-far-retiming/complex/LICENSE-wht-power-saving-lean new file mode 100644 index 0000000000..261eeb9e9f --- /dev/null +++ b/research/e8-complex-far-retiming/complex/LICENSE-wht-power-saving-lean @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/research/e8-complex-far-retiming/complex/NOTICE-wht-power-saving-lean b/research/e8-complex-far-retiming/complex/NOTICE-wht-power-saving-lean new file mode 100644 index 0000000000..7008ce01c1 --- /dev/null +++ b/research/e8-complex-far-retiming/complex/NOTICE-wht-power-saving-lean @@ -0,0 +1,489 @@ +Walsh-Hadamard power saving (wht-power-saving-lean) +Copyright 2026 Jacob Sussman + +Repository: https://github.com/jacobalansussman/wht-power-saving-lean + +This repository is not a project of OpenAI. OpenAI did not write, review or +endorse it. The package name "OAI" and the namespace "OAI.PowerSaving" are +those of openai/math and are kept only because the new files extend that +development. + +This repository is not a project of CrocSwap/integer-mult-bounds either. Its +authors did not write, review or endorse it. Section 6 says what is taken +from their repository. + +This repository contains files from, and files derived from, the repository +"openai/math" (https://github.com/openai/math), family 130, "Exact Fourier +transforms below n log n", at commit fd4aeeb2ee4fc729c18d98444fed42fd0529eeeb. +That repository is published under the Apache License, Version 2.0. A copy of +the licence is in the file LICENSE. The upstream repository has no NOTICE file +and its licence text names no copyright holder; the files are attributed here +to the authors of openai/math (OpenAI). + +1. Unmodified upstream files. + The 89 files under OAI/Computability/ are byte-for-byte copies of the files + with the same paths under lean/ in openai/math at the commit above. They + have not been changed. Modified copies of some of them are under + Work/Fourier/ and Work/FourierE8/ and are listed in section 7. + One more file of openai/math is here unchanged, outside the Lean build: + third-party/openai-math/lean/ComparatorChallenges/UniformFourier.lean is a + byte-for-byte copy of lean/ComparatorChallenges/UniformFourier.lean at the + commit above (the statement of OpenAI's Fourier challenge). It is included + so that the modified copy named in section 2 can be compared with it. + +2. Files that contain upstream text. + - Work/CarrierCheck/ChallengeB2Ke16x.lean, + Work/CarrierCheck/ChallengeB2Ke16xR.lean, + Work/GCert/Data/ChallengeB2Gp193x.lean, + Work/GCert/Data/ChallengeB2Ge8x.lean and the text template + tools/gen/templates/ChallengeB2L16x.lean.txt each contain, as their + lines 22-270, lines 9-257 of + lean/ComparatorChallenges/UniformFourier.lean of openai/math (the RAM cost + model), unchanged. Everything else in these files was written for this + repository. + - Work/Fourier/UniformFourierChallenge.lean is a modified copy of + lean/ComparatorChallenges/UniformFourier.lean of openai/math (the + statement of OpenAI's Fourier challenge, 336 lines). Changes: a comment + was added at the top; the exponent 1 - 1/(10^(13:ℕ)) was replaced by + 1 - 7474546/(10^(10:ℕ)); seven names received the suffix "Z" + (decimalExponent, decimalTime, TimeBounds, DFTGoal, ConvGoal, + transform_main, convolution_main). Everything else in the file is the + upstream text, unchanged. See section 7. + - Work/FourierE8/UniformFourierChallenge.lean is a second modified copy + of the same upstream file, for the fourth result, with the same three + kinds of change: a comment added at the top; the exponent replaced by + 1 - 8762478/(10^(10:ℕ)); the suffix "E8" on the same seven names. + Everything else in the file is the upstream text, unchanged. See + section 7. + - Work/Scratch/Engine.lean and Work/Block/Engine.lean contain copies of + proofs of openai/math, changed for this repository: sections 1, 2 and 5 + of Work/Scratch/Engine.lean are upstream proofs with the batch layout + renamed, and both files contain a copy of the private upstream theorem + "hills_project" (lean/OAI/Computability/FourierTransform/ + TensorProgram.lean) with its envelope generalised. The comments in the + two files mark these places. + - lakefile.lean is adapted from lean/lakefile.lean of openai/math: the same + package name, toolchain, package option and Mathlib pin; every other + dependency was removed and the libraries of this repository were added. + lean-toolchain is a byte-for-byte copy of lean/lean-toolchain. + lake-manifest.json lists Mathlib and its dependencies at the revisions of + lean/lake-manifest.json. + - RELATED-WORK.md reproduces the BibTeX entries of two manuscripts of + openai/math. + +3. New files that build on upstream proofs. + The other files under WHTCheck/ and Work/ were written for this + repository. They import the upstream files, and several of them generalise + or adapt proofs of upstream files (for example Work/Block/Recursion.lean, + which says so in its header). They are changes and additions made for this + repository and are not part of openai/math. + +4. How the new files were made. + Jacob Sussman made the new files on 2026-10-08, 2026-10-09 and 2026-10-10 + by directing a team of AI agents (Claude). The agents wrote the new Lean + files, the certificate data and the generator scripts. They made the + rebuild scripts under tools/rebuild/, in part by adapting programs of + CrocSwap/integer-mult-bounds (section 6): ten of the thirteen on + 2026-10-09, tidied for this repository on 2026-10-10, and three on + 2026-10-10. On 2026-10-10 they also wrote the search programs under + tools/e8/ and found with them the certificate of the fourth result + (section 8). See README.md, section 4. + +5. Ideas taken from other public work. + The network of the first result uses ideas published by others, among them + the helper circuit "NStar3" (Swapnil-jain/integer-mult-kappa, which credits + CrocSwap pull request #36 and Paureel for parts of it), its transfer to + family 130 (shea256/fourier-transform-below-nlogn), and "carrier links" and + "whole-residual batching" (pull requests to CrocSwap/integer-mult-bounds). + No file of Swapnil-jain/integer-mult-kappa or of + shea256/fourier-transform-below-nlogn is included here. One comment in + Work/Scratch/Engine.lean quotes three counts reported in + Swapnil-jain/integer-mult-kappa and names that source. The general frame + lemma that Work/GFrame proves is stated in + notes/general-clifford-frames.tex of CrocSwap/integer-mult-bounds; its Lean + proof was written for this repository. The credits, with links, are in + RELATED-WORK.md. + +6. Data derived from, and programs adapted from, + CrocSwap/integer-mult-bounds (second result). + The helper circuit of the second result is the paired-cube circuit of the + repository "CrocSwap/integer-mult-bounds" + (https://github.com/CrocSwap/integer-mult-bounds), in the state of its pull + request #193. It is the design of that community: icekylinx (pull requests + #144 and #184), eumemic (#168, and #117 behind its modules), ikeboy / + Avi Eisenberg (#191 and #193), with an664 (#128) credited there for the + workspace-sharing principle, and DaysSky (#162) and chafreaky (#163) + credited by #168 for its closure-compiled carrier arcs and for the + fusion of its single-target outputs. That repository is published under + the Apache + License, Version 2.0 (the same licence text as the file LICENSE). Its + NOTICE file begins "A sharper exponent for integer multiplication / + Copyright 2026 Douglas Colkitt" and says that the community release "is + not solely Douglas Colkitt's work". A complete copy of that NOTICE file, as + it is at the head of pull request #193, is in + third-party/CrocSwap-integer-mult-bounds/NOTICE. + + The data were taken from these files of that repository. They were loaded + as data by the programs under tools/rebuild/. No program of that + repository was run, and none is included here unchanged; six of the + programs under tools/rebuild/ are adapted from programs of that + repository ("Programs", below). + - at the head of pull request #168 (eumemic), + 4a3c769e5c5430e7114c4d3e099ff34664677f17: + references/paired-cube/sources/local_L1.json + references/paired-cube/sources/tmod_TE_TD_TB3_1_1_4_full_6.0617964e-4.json + references/paired-cube/sources/pmod_J0_full_6.0666810e-4.json + references/paired-cube/sources/qmod_climb3u_best.json + references/paired-cube/selected-module/matching-arcs.json + references/paired-cube/physical/frames.json + - at the head of pull request #193 (ikeboy), + 187e1010ac8b259af8e9b5166f68b64bc27b4b47: + research/source-assisted-v4/data/physical-pairs.json + + Two more files at the head of pull request #168 are read for comparison + only: the programs print whether their graph and their counts agree + with them. Nothing in the certificate is taken from them: + references/paired-cube/selected-module/SOURCE.json + certificates/paired-cube-complex-input.json + + One more file is fetched and read only on request. No certificate and + no Lean module of this repository is made from it; the documentation + gives its sha256 and the price that tools/gx/gxdry.py computes for + the certificate that the rebuild makes from it: + - at the head of pull request #233 (chafreaky), + 109a857a329d18ed5552d5573f17ddfa886ae57f: + research/source-assisted-v4-layer/witness/physical-pairs.json + + None of these ten files is included in this repository. + tools/rebuild/fetch_inputs.py fetches them and checks their sha256. + + Files of this repository that contain data derived from them: + tools/certificate/gcert1-p11-pr193.json.gz and the Lean data modules + generated from it, Work/GCert/Data/Gen/P193*.lean and the files they import + from Work/GCert/Data/Gen/P193/; its block counts are also in the generated + modules Work/GCert/Data/P193Price.lean, RateB2Gp193.lean, RateB2Gp193x.lean + and InstB2Gp193.lean. + Changes made: the circuit was rebuilt from those data as one explicit, + renumbered list of additions with a table of frames, in the certificate + format "gcert/1" of this repository; its 1,980 in-place steps were written + as pairs of additions with rescaled coefficients; the Lean data modules + were generated from that list. No file of that repository is included + unchanged, except the copy of its NOTICE file named above. + + Programs. The Python files under tools/rebuild/ were made by the agents + (section 4), who read programs of that repository as text and ran none + of them. Six of the thirteen files are adapted from those programs: + the parts named below follow the outside program statement by statement + or method by method, with the layout changed, some names changed and + the parts that this certificate does not use left out. Each of the six + says so in its first lines. + - tools/rebuild/compile.py: the function closure follows + compile_closure of scripts/paired_cube/closure.py; the function + select follows the first part of select of + scripts/paired_cube/gauges.py. + - tools/rebuild/graphgen.py: the class Gen follows the class Graph of + scripts/paired_cube/graph.py; its method fuse follows the branch + "f8:" of merge_outputs of scripts/paired_cube/modules.py, which + fuses the three single-target outputs of a port into one. That + branch came with pull request #168 (eumemic), which says of the + fusion that it "follows #163's same-singleton fusion" and credits + it so: "Same-singleton output fusion: @chafreaky (#163); the fold + orders here come from our own search." + - tools/rebuild/aligned.py: the functions op_tags, local_values and + build follow op_tags, local_values and main of + research/source-assisted-v4/source_aligned_local_v4.py, except its + search for pairs and the records it writes. + - tools/rebuild/stage.py: the order of the events, the backward pass + (responses) and many names are those of + research/terminal-sinks/sinks_gate.py and of + scripts/paired_cube_physical.py; the event records and the exact + arithmetic were written for this repository, and the frame scan + was rewritten so that it returns every block. + - tools/rebuild/build.py: the function target_hist and the field names + of profile follow the last part of select of + scripts/paired_cube/gauges.py; the calls that make the graph and its + hash follow regenerate of scripts/paired_cube_producer.py. + - tools/rebuild/f2.py: the function perp follows perp, and the second + half of the function rref follows the second half of basis, of + scripts/paired_cube/frames.py. + The outside programs are those at the two commits named above + (source_aligned_local_v4.py at the second, the others at the first). + Of the other seven files, rebuild.py, fetch_inputs.py, rbpaths.py, + rewrite.py, phys.py and emit.py were written for this repository. + modules.py was written for this repository too; for the three module + files it checks the contract that the outside + scripts/paired_cube/modules.py states for them in its functions + triple_module_from, pair_module_from and all_but_one_from, each of + which is marked there "eumemic, Claude assistance; Apache-2.0". + + Notices and attribution sentences in the first lines of those outside + programs, quoted with the line numbers of each file at its commit. + The other lines of each header say what the program does and name no + person: + + scripts/paired_cube/closure.py, lines 4-5 (pull request #168, + eumemic; from pull request #162, DaysSky): + Copyright 2026 DaysSky (PR162, + research/extended-links/cxlinks.py), Apache-2.0; moved here + unchanged apart from this header and the imports (eumemic, Claude + assistance). + + scripts/paired_cube/graph.py, modules.py, frames.py, gauges.py and + scripts/paired_cube_producer.py (pull request #144, icekylinx; + graph.py, modules.py and paired_cube_producer.py changed in #168, + eumemic), the two comment lines at the top of each: + Copyright 2026 icekylinx. Apache-2.0. + Developed with GPT-6 Astra assistance; integrated with Codex + assistance. + graph.py, lines 6-9: + The coarse positive query modules restrict the already adopted + PR117 DAG (eumemic; Apache-2.0; Claude assistance; + cbb05ce504d571546d9b7794c186a613c659c3bf). The paired-channel + decomposition and this assembly are new work for icekylinx with + OpenAI GPT-6 Astra assistance. + modules.py, lines 6-7: + The pair-disjoint module is a specialization of the already + adopted PR117 positive DAG (eumemic, Apache-2.0, pinned + cbb05ce504d571546d9b7794c186a613c659c3bf). + modules.py, line 272, above merge_outputs: + Output merging (pmerge.py variants; eumemic, Claude assistance; + Apache-2.0). + frames.py, line 7: + New work for icekylinx, OpenAI GPT-6 Astra assistance. + paired_cube_producer.py, line 8: + Copyright 2026 icekylinx, Apache-2.0; OpenAI GPT-6 Astra + assistance, inherited PR117 notices. + + scripts/paired_cube_physical.py, lines 4-7 (pull request #168, + eumemic): + Prepared by eumemic with Anthropic Claude assistance. Apache-2.0. + The signed word, frozen arcs, gauges, chronology and shared-core + accounting are icekylinx's PR144. Frame descent under PR130's + general Clifford frames and compensated birth-cut reuse follow + PR131 and jamesyc's PR124; deadline (late) compensation reads + follow PR143. + + research/terminal-sinks/sinks_gate.py, lines 4-6 (pull request + #168, eumemic): + The substitution is the terminal-sink lemma of PR #166 by jamesyc + (closed by its author), independently audited here: this gate's + own frame scans, replay and controls carry the soundness argument + and do not use #166's checker. Gate, audit and integration by + eumemic with Anthropic Claude assistance. Apache-2.0. + + research/source-assisted-v4/source_aligned_local_v4.py, lines 4-9 + (pull requests #191 and #193, ikeboy / Avi Eisenberg): + Derived from + research/source-assisted/decision/source_aligned_local.py + (icekylinx, GPT-6 Astra assistance, Apache-2.0). Only the three + frozen query modules change: this copy reads PR168 v4's selected + modules (eumemic, Claude assistance) from + references/paired-cube/sources instead of the PR168 fd25adb7 + modules. The local configuration, arc transport, frame + inheritance and physical layer code are unchanged. + + Notices of that NOTICE file that pertain to these data, quoted: + + Paired-cube and shared-core extension, 9 October 2026 + Copyright 2026 icekylinx + + Source-assisted common-frame extension (2026-10-09) + Copyright 2026 icekylinx. Apache-2.0. + Substantial dependency: eumemic PR168, + fd25adb7fbaa12ee761d02c733c54d1d2a7687ee + + The full text of both notices, and the notices of the work they build on, + are in the copy named above. The credits, with links and with the words of + pull request #193 about its own sources, are in README.md ("Whose circuit + this is") and in RELATED-WORK.md, section 1. + +7. Modified copies of upstream files (third and fourth results). + The files listed below are copies of files of openai/math at the commit + above, changed for this repository. Each begins with a comment that names + the upstream file it is derived from and states what was changed. The + upstream originals under lean/OAI/Computability/ are in this repository + as well, unchanged (section 1), and the copies import them. The upstream + challenge file lean/ComparatorChallenges/UniformFourier.lean is in this + repository in both forms: unchanged under third-party/openai-math/ + (section 1) and modified (section 2). + + - Work/Fourier/ArbitraryLength.lean: modified copy of + lean/OAI/Computability/FourierTransform/ArbitraryLength.lean (224 + lines; 159 of them unchanged in the copy). Changes: identifiers renamed + on 64 lines (18 names: 15 with the suffix Z, 3 with Z inserted); 1 + import line replaced by 1; 15 comment lines added; no other change to + the code. + - Work/Fourier/Asymptotics.lean: modified copy of + lean/OAI/Computability/FourierTransform/Asymptotics.lean (187 lines; + 112 of them unchanged in the copy). Changes: identifiers renamed on 74 + lines (32 names: 26 with the suffix Z, 6 with Z inserted); 1 import + line replaced by 1; 15 comment lines added; no other change to the + code. + - Work/Fourier/Axioms.lean: written for this repository (not a copy of an + upstream file). + - Work/Fourier/ConvolutionProgram.lean: modified copy of + lean/OAI/Computability/FourierTransform/ConvolutionProgram.lean (100 + lines; 77 of them unchanged in the copy). Changes: identifiers renamed + on 22 lines (10 names: 9 with the suffix Z, 1 with Z inserted); 1 + import line replaced by 1; 15 comment lines added; no other change to + the code. + - Work/Fourier/Goal.lean: written for this repository; contains lines of + upstream files: of its 7 code lines, 6 are lines of + lean/OAI/Computability/FourierTransform/Goal.lean (original lines 35, + 75-77, 79, 81): unchanged: its lines 25; with identifiers renamed: its + lines 21, 24, 26, 28, 30. + - Work/Fourier/Main.lean: modified copy of + lean/OAI/Computability/FourierTransform/Main.lean (151 lines; 90 of + them unchanged in the copy). Changes: identifiers renamed on 59 lines + (40 names: 35 with the suffix Z, 5 with Z inserted); 1 import line + replaced by 2; 24 comment lines added; other code lines changed: 1 of + the original, 1 of the copy (copy line 59). + - Work/Fourier/Seam.lean: written for this repository; contains lines of + upstream files: of its 122 code lines, 15 are lines of + lean/OAI/Computability/FourierTransform/TensorProgram.lean (original + lines 36-37, 95-96): unchanged: its lines 93-94, 113-114, 141-142, + 163-164, 185-187, 194-196; with identifiers renamed: its lines 184; 3 + are lines of lean/OAI/Computability/FourierTransform/TensorSaving.lean + (original lines 83-84, 114): with identifiers renamed: its lines 45-46, + 59; 1 is a line of lean/OAI/Computability/FourierTransform/Main.lean + (original line 60): with identifiers renamed: its lines 213. + - Work/Fourier/SectorAlgorithm.lean: modified copy of + lean/OAI/Computability/FourierTransform/SectorAlgorithm.lean (224 + lines; 162 of them unchanged in the copy). Changes: identifiers renamed + on 61 lines (17 names: 13 with the suffix Z, 4 with Z inserted); 1 + import line replaced by 1; 15 comment lines added; no other change to + the code. + - Work/Fourier/SynchronizedAlgorithm.lean: modified copy of + lean/OAI/Computability/FourierTransform/SynchronizedAlgorithm.lean (126 + lines; 94 of them unchanged in the copy). Changes: identifiers renamed + on 31 lines (12 names: 10 with the suffix Z, 1 with Z inserted, 1 + other), the other being "canopy" to "Grove.canopy" (5 lines); 1 import + line replaced by 1; 16 comment lines added; no other change to the + code. + - Work/Fourier/TransformProgram.lean: modified copy of + lean/OAI/Computability/FourierTransform/TransformProgram.lean (146 + lines; 94 of them unchanged in the copy). Changes: identifiers renamed + on 51 lines (21 names: 19 with the suffix Z, 2 with Z inserted); 1 + import line replaced by 1; 15 comment lines added; no other change to + the code. + - Work/Fourier/UniformBounds.lean: modified copy of + lean/OAI/Computability/FourierTransform/UniformBounds.lean (183 lines; + 115 of them unchanged in the copy). Changes: identifiers renamed on 67 + lines (29 names: 25 with the suffix Z, 4 with Z inserted); 1 import + line replaced by 1; 15 comment lines added; no other change to the + code. + - Work/Fourier/UniformFourierChallenge.lean: modified copy of + lean/ComparatorChallenges/UniformFourier.lean (336 lines; 328 of them + unchanged in the copy). Changes: identifiers renamed on 7 lines (7 + names: 7 with the suffix Z); 12 comment lines added; other code lines + changed: 1 of the original, 1 of the copy (copy line 281). + - Work/Fourier/WorkingCompiler.lean: modified copy of + lean/OAI/Computability/FourierTransform/WorkingCompiler.lean (153 + lines; 104 of them unchanged in the copy). Changes: identifiers renamed + on 48 lines (14 names: 14 with the suffix Z); 1 import line replaced by + 1; 15 comment lines added; no other change to the code. + - Work/Fourier/WorkingPreparation.lean: modified copy of + lean/OAI/Computability/FourierTransform/WorkingPreparation.lean (212 + lines; 156 of them unchanged in the copy). Changes: identifiers renamed + on 55 lines (30 names: 28 with the suffix Z, 2 with Z inserted); 1 + import line replaced by 1; 15 comment lines added; no other change to + the code. + - Work/Fourier/WorkingTransform.lean: modified copy of + lean/OAI/Computability/FourierTransform/WorkingTransform.lean (119 + lines; 91 of them unchanged in the copy). Changes: identifiers renamed + on 27 lines (9 names: 8 with the suffix Z, 1 with Z inserted); 1 import + line replaced by 1; 15 comment lines added; no other change to the + code. + + Changes made to the eleven copied proof files: every declaration received + the letter "Z" in its name (as a suffix of its own name, or of the name + of the declaration it belongs to), so that it does not collide with the + upstream declaration of the same name; the upstream exponent "alpha" + (1 - 2/10^11) and the bound "hills" defined from it were replaced by + "alphaZ" (1 - 7474547/10^10) and "hillsZ", which are defined in + Work/Fourier/Seam.lean, and the single use of the upstream theorem + "hills_program" by "hillsZ_program"; the five definitions of the upstream + statement that contain its exponent (decimalExponent, decimalTime, + TimeBounds, DFTGoal, ConvGoal) were replaced by the versions of + Work/Fourier/Goal.lean, whose exponent is 1 - 7474546/(10^(10:ℕ)); + the import lines point to the copies; a header comment was added. + Two further changes: in the copy of Main.lean the same constant stands + once as the literal 2/10^11 and was replaced there too, and the two + final theorems of that copy received a documentation comment; in the + copy of SynchronizedAlgorithm.lean the name "canopy" was written out as + "Grove.canopy" in 5 places, because the short name is shadowed in the + larger environment of the copy. The script also renamed three names + inside upstream comments; the comments are otherwise the upstream ones + and describe the upstream network. + The proofs are those of openai/math. The copies were made by the script + tools/fourier/mkchain.py of this repository. + + Work/Fourier/Goal.lean contains copies of those five definitions of + lean/OAI/Computability/FourierTransform/Goal.lean, with the exponent + replaced and the suffix "Z" on the five names. + + Work/Fourier/Seam.lean was written for this repository. It repeats the + statement of the upstream theorem "hills_program" (TensorProgram.lean) and + the definition of "hills" (TensorSaving.lean) with the two names replaced; + its header says so. + + Fourth result. The 15 files under Work/FourierE8/ repeat the 15 files + under Work/Fourier/ for the kernel program of the fourth result, file + for file and under the same file names: ArbitraryLength.lean, + Asymptotics.lean, ConvolutionProgram.lean, Goal.lean, Main.lean, + SectorAlgorithm.lean, SynchronizedAlgorithm.lean, TransformProgram.lean, + UniformBounds.lean, UniformFourierChallenge.lean, WorkingCompiler.lean, + WorkingPreparation.lean, WorkingTransform.lean, Seam.lean and + Axioms.lean. The eleven copied proof files, + Goal.lean and UniformFourierChallenge.lean are modified copies of the + same upstream files as their namesakes above, made by the script + tools/fourier/mkchain_e8.py (a copy of tools/fourier/mkchain.py with + its constants changed). The changes are those described above with + three differences: the suffix is "E8" where the copies of the third + result have "Z"; "alphaE8" is 1 - 8762479/10^10; and the exponent of + Work/FourierE8/Goal.lean is 1 - 8762478/(10^(10:ℕ)). Each of these + files begins with a comment that names the upstream file it is derived + from and states what was changed. Work/FourierE8/Seam.lean and + Work/FourierE8/Axioms.lean were written for this repository: they are + Work/Fourier/Seam.lean and Work/Fourier/Axioms.lean with names and + numbers replaced, and the seam repeats the same upstream statement and + definition as the seam of the third result. The proofs are those of + openai/math. + + The work of others that the third result follows (danadran01, shea256, + eumemic) is credited in README.md ("Whose reduction this is") and in + RELATED-WORK.md, section 1. No file of their repositories is included + here. + +8. The certificate of the fourth result and the search programs. + tools/certificate/gcert1-e8-r783.json.gz, the Lean data modules + generated from it (Work/GCert/Data/Gen/E8*.lean, Work/GCert/Data/Gen/E8/ + and the modules of Work/GCert/Data/ with E8 or B2Ge8 in their names) and + the Python programs under tools/e8/ were made by the agents for this + repository on 2026-10-10 (section 4). The circuit in that certificate + is not the circuit of section 6, and no data file of + CrocSwap/integer-mult-bounds was loaded to make it. It uses three + devices that were published by others in pull requests to that + repository: + - the in-place pair, a + b and a - b formed on the two arrays that held + a and b: icekylinx (#184), carried in #191 and #193 (ikeboy); + - the re-use of a finished helper with a compensating read: jamesyc + (#124) and eumemic (#143); + - the late pairing rule, the choice of which finished helper a new + value takes: Chafik Boukhalfa (the account chafreaky), #200 and #233, + and pull request #2 of this repository. The search programs apply the + idea with a greedy rule of their own; his program, his pairs and his + certificate were not used. + No program of that repository is included in tools/e8/, imported or + run by it. The programs of tools/e8/ have not been compared statement + by statement with the programs of that repository, as those of + tools/rebuild/ were (section 6). The integer programme of + tools/e8/ is solved with the open-source solver HiGHS, called through + SciPy (scipy.optimize.milp), with NumPy; none of the three is included + here. The credits, with links, are in README.md ("Whose ideas the new + unit uses") and in RELATED-WORK.md, section 8. + +Not included in this repository and fetched by the build: Mathlib +(https://github.com/leanprover-community/mathlib4, Apache License 2.0) and its +dependencies. The comparator (https://github.com/leanprover/comparator) is a +separate tool and is not included. diff --git a/research/e8-complex-far-retiming/complex/gcert1-e8-r783.json.gz b/research/e8-complex-far-retiming/complex/gcert1-e8-r783.json.gz new file mode 100644 index 0000000000..0bd0bacf74 Binary files /dev/null and b/research/e8-complex-far-retiming/complex/gcert1-e8-r783.json.gz differ diff --git a/research/e8-complex-far-retiming/complex/gx/gx.py b/research/e8-complex-far-retiming/complex/gx/gx.py new file mode 100644 index 0000000000..6d14c0a976 --- /dev/null +++ b/research/e8-complex-far-retiming/complex/gx/gx.py @@ -0,0 +1,296 @@ +#!/usr/bin/python3 -I +"""gx.py. OWN code (imports nothing of port-producer, nothing outside). +(1) convert(c0): gcert/0 (port-producer's event list) -> gcert/1, the LEAN-FACING NORMAL FORM: + only the main phase (no read0 / undo / uninj: the invocation theorem derives the dirt gate and the undo + gate from the product), every gate an elementary fan-out or fan-in add, the 4x4 K block written as three + such adds plus a sign carried by one register, the star scatter as a table. +(2) check1(c1): the local decidable conditions of EXTENDED-CERT-SPEC.md on a gcert/1 file: + E0 sizes, E1 labels (nested subspaces by containment, equal frame at a gate), E2 scatter cut, + E3 shape (kinds of gates; X1; S1), E4 bracket rule S2, E5 scalar (x-content replay: hid and X3), + E6 price data (block histograms, N), E7 exterior gauges only (Q2). Raises AssertionError(": ..."). +""" +from fractions import Fraction as Fr +from collections import Counter +from math import lcm + + +def need(c, msg): + if not c: + raise AssertionError(msg) + + +def reduce(u, basis): + """basis: reduced echelon, pivot = leading bit, descending. Returns u modulo the span.""" + for b in basis: + if u >> (b.bit_length() - 1) & 1: + u ^= b + return u + + +def echelon_ok(f): + piv = [b.bit_length() - 1 for b in f] + if any(b == 0 for b in f) or piv != sorted(piv, reverse=True) or len(set(piv)) != len(piv): + return False + return all(not (b >> p & 1) for i, b in enumerate(f) for j, p in enumerate(piv) if i != j) + + +def inside(a, b): + return all(reduce(u, b) == 0 for u in a) + + +def par(x): + return bin(x).count("1") & 1 + + +KJ = [[[1, 2] if i == j else [-1, 2] for j in range(4)] for i in range(4)] + + +def convert(c0): + need(c0["format"] == "gcert/0", "input is not gcert/0") + v, h, R = c0["v"], c0["h"], c0["R"] + ev = c0["events"] + cen = [n for n, e in enumerate(ev) if e[0] == "centre"] + need(cen == list(range(cen[0], cen[0] + len(cen))), "centres are not contiguous: no single scatter cut") + A, B, ret = [], [], [] + neg = set() # x registers currently holding MINUS their value (between the two K blocks) + openq = {} + for n, e in enumerate(ev): + k = e[0] + out = A if n < cen[0] else B + if k in ("read0", "undo", "uninj"): + continue + if k == "inj": + need(e[2] not in neg, "inj reads a negated x register") + out.append(["out", e[3], e[2], [[e[1], 1, 1]], []]) + elif k == "op": + if e[3] == -1: + out.append(["neg", e[5], e[1]]) + else: + need(e[3] == 1, "op ca") + out.append(["out", e[5], e[2], [[e[1], e[4], 1]], []]) + elif k == "centre": + ret.append([e[2], e[1], e[3]]) + elif k == "gread": + hit = set(t for t, _, _ in e[3]) + out.append(["out", e[2], e[1], [[v + t, a, b] for t, a, b in e[3]], [v + t for t in e[4] if t not in hit]]) + elif k == "rread": + out.append(["out", e[2], e[1], [[v + t, a, b] for t, a, b in e[3]], []]) + elif k == "ysh": + out.append(["out", e[4], e[2], [[e[1], e[3], 1]], []]) + elif k == "yw": + out.append(["out", e[4], e[2], [[e[1], e[3][0], e[3][1]]], []]) + elif k == "kd": + out.append(["out", e[3], e[2], [[e[1], -1 if e[2] in neg else 1, 1]], []]) + elif k == "ktr": + q = tuple(e[1]) + need(e[2] == KJ, "ktr matrix is not 1 - J/2") + x1, rest = q[0], list(q[1:]) + if q not in openq: # first block: x := M x, register x1 keeps the sign + out.append(["in", e[3], x1, [[r, 1, 1] for r in rest]]) + out.append(["out", e[3], x1, [[r, -1, 2] for r in rest], []]) + out.append(["in", e[3], x1, [[r, 1, 1] for r in rest]]) + openq[q] = n + neg.add(x1) + else: # second block: the three adds undone in reverse order + out.append(["in", e[3], x1, [[r, -1, 1] for r in rest]]) + out.append(["out", e[3], x1, [[r, 1, 2] for r in rest], []]) + out.append(["in", e[3], x1, [[r, -1, 1] for r in rest]]) + del openq[q] + neg.discard(x1) + else: + raise AssertionError("unknown event kind %r" % k) + need(not openq and not neg, "a K block is not closed") + ext = sorted([z[3], z[1]] for z in c0["gauge"] if z[5]) + c1 = dict(format="gcert/1", derived_from=c0["name"] + " (gcert/0)", p=c0["p"], h=h, v=v, R=R, cst=c0["cst"], + N=c0["N"], ports=c0["ports"], frames=c0["frames"], start=c0["start"], final=c0["final"], + ext=ext, ret=sorted(ret), scat=dict(inside=c0["scat"]["inside"], outside=c0["scat"]["outside"]), + A=A, B=B, blocks=c0["blocks"]) + return c1 + + +def scat_row(c, t): + """the scatter of target t: [(k, coefficient)], from the table or from the star rule""" + sc = c["scat"] + if "table" in sc: + return [(k, Fr(a, b)) for k, a, b in sc["table"][t]] + sin, sout = Fr(*sc["inside"]), Fr(*sc["outside"]) + return [(k, sin if c["ports"][t] >> k & 1 else sout) for k in range(c["h"])] + + +def gate_regs(g): + if g[0] == "neg": + return [g[2]], [], [] + if g[0] == "out": + return [g[2]] + [t for t, _, _ in g[3]] + list(g[4]), [(t, g[2], Fr(a, b)) for t, a, b in g[3]], g[4] + if g[0] == "in": + return [g[2]] + [s for s, _, _ in g[3]], [(g[2], s, Fr(a, b)) for s, a, b in g[3]], [] + raise AssertionError("E0: unknown gate kind %r" % (g[0],)) + + +def check1(c, scalar=True, stats=None): + need(c.get("format") == "gcert/1", "E0: format") + h, v, R = c["h"], c["v"], c["R"] + nreg = 2 * v + R + ports, fr = c["ports"], [tuple(f) for f in c["frames"]] + need(len(ports) == v == len(set(ports)) and all(par(q) and 0 < q < 1 << h for q in ports), "E0: ports") + need(fr[0] == () and fr[1] == tuple(1 << i for i in range(h - 1, -1, -1)), "E0: frames 0 and 1") + need(all(echelon_ok(f) for f in fr) and len(set(fr)) == len(fr), "E0: frame table not reduced echelon / repeats") + dim = [len(f) for f in fr] + start, final = c["start"], c["final"] + need(len(start) == len(final) == nreg, "E0: start / final") + ext = {r: f for r, f in c["ext"]} + for t in range(v): + need(fr[start[t]] == (ports[t],) and final[t] == 1, "E1: x start / final") + f = fr[final[v + t]] + need(start[v + t] == 0 and len(f) == h - 1 and all(par(u & ports[t]) == 0 for u in f), "E1: y start / final") + for r in range(2 * v, nreg): + need(start[r] == ext.get(r, 0) and final[r] == 1, "E1: slot start / final") + cls = lambda r: "x" if r < v else "y" if r < 2 * v else "s" + cur = list(start) + H = {"x": Counter(), "y": Counter(), "s": Counter(), "c": Counter()} + steps = set() + + def climb(r, f, where): + o = cur[r] + if o != f: + if (o, f) not in steps: + need(dim[o] < dim[f] and inside(fr[o], fr[f]), "E1: step not nested (%s, register %d)" % (where, r)) + steps.add((o, f)) + H[cls(r)][dim[f] - dim[o]] += 1 + cur[r] = f + okind = {("x", "s"), ("s", "s"), ("s", "y"), ("x", "y"), ("x", "x"), ("y", "y")} + ysum, piv, ytg = Counter(), set(), set() + inc = 0 + for ph, gates in (("A", c["A"]), ("B", c["B"])): + if ph == "B": # ---- E2: the scatter cut + need(sorted(k for k, _, _ in c["ret"]) == list(range(len(c["ret"]))), "E2: retained totals numbered 0..") + if "table" in c["scat"]: + need(len(c["scat"]["table"]) == v and all(0 <= k < len(c["ret"]) for row in c["scat"]["table"] for k, _, _ in row), + "E2: scatter table") + else: + need(len(c["ret"]) == h, "E2: one retained total per coordinate (star rule)") + for k, s, f in c["ret"]: + need(cls(s) == "s" and cur[s] == f, "E2: retained slot %d is not at its frame" % s) + H["c"][dim[f]] += 1 + need(all(cur[v + t] == 0 for t in range(v)), "E2: a y role left frame 0 before the scatter") + for i, g in enumerate(gates): + regs, pairs, _ = gate_regs(g) + need(all(0 <= r < nreg for r in regs) and len(set(regs)) == len(regs), "E3: registers of gate %s%d" % (ph, i)) + inc += len(regs) + for r in regs: + climb(r, g[1], "%s%d" % (ph, i)) + for t, s, co in pairs: + kd = (cls(s), cls(t)) + need(kd in okind, "E3: gate kind %s -> %s (gate %s%d)" % (kd + (ph, i))) + need(ph == "B" or kd in {("x", "s"), ("s", "s")}, "E3: bank gate before the scatter (gate A%d)" % i) + if kd == ("y", "y"): + ysum[s, t] += co + piv.add(s) + ytg.add(t) + need(ph == "B" or all(cls(r) != "y" for r in regs), "E2: y role named in phase A") + for r in range(nreg): + climb(r, final[r], "final") + need(not (piv & ytg), "E4: a pivot is the target of a gate reading y") + need(all(x == 0 for x in ysum.values()), "E4: y-reads of a (pivot, target) pair do not cancel") + Hs = {k: {str(r): n for r, n in sorted(w.items())} for k, w in H.items()} + need(Hs == c["blocks"], "E6: block histograms") + N = sum(r * n for w in H.values() for r, n in w.items()) + tails = sum(dim[f] for f in ext.values()) + need(N == c["N"] and N + tails == R * h + 2 * v * (h - 1) + c["cst"], "E6: N") + if stats is not None: + stats.update(steps=len(steps), incidences=inc, blocks=sum(sum(w.values()) for w in H.values()), + step_work=sum(dim[a] * dim[b] for a, b in steps), ysh_pairs=len(ysum)) + if scalar: + scal(c, stats) + q2(c) + return True + + +def scal(c, stats=None): + """E5: exact replay of the x-content of every register through A, scatter, B.""" + h, v, R = c["h"], c["v"], c["R"] + nreg = 2 * v + R + reg = [({r: Fr(1)} if r < v else {}) for r in range(nreg)] + den = {"x": 1, "y": 1, "s": 1} + mx = {"x": Fr(0), "y": Fr(0), "s": Fr(0)} + cls = lambda r: "x" if r < v else "y" if r < 2 * v else "s" + + def axpy(t, src, co): + d = reg[t] + for k, u in src.items(): + w = d.get(k, 0) + co * u + if w: + d[k] = w + kk = cls(t) + if w.denominator != 1: + den[kk] = lcm(den[kk], w.denominator) + if abs(w) > mx[kk]: + mx[kk] = abs(w) + else: + d.pop(k, None) + + def run(gates): + for g in gates: + if g[0] == "neg": + reg[g[2]] = {k: -u for k, u in reg[g[2]].items()} + elif g[0] == "out": + src = dict(reg[g[2]]) + for t, a, b in g[3]: + axpy(t, src, Fr(a, b)) + else: + for s, a, b in g[3]: + axpy(g[2], reg[s], Fr(a, b)) + run(c["A"]) + tot = {k: dict(reg[s]) for k, s, _ in c["ret"]} + for t in range(v): + for k, co in scat_row(c, t): + axpy(v + t, tot[k], co) + run(c["B"]) + need(all(reg[t] == {t: 1} for t in range(v)), "E5: an x role is not restored (X3)") + need(all(reg[v + t] == {t: 1} for t in range(v)), "E5: a target does not receive exactly its source (hid)") + if stats is not None: + stats.update(den=dict(den), maxabs={k: str(x) for k, x in mx.items()}, + gates_A=len(c["A"]), gates_B=len(c["B"])) + + +def q2(c): + """E7 (only for files with exterior gauges, rule (2)): for every slot q that starts off the zero frame, the + column of q in the y rows of the product is zero (its dirt is removed in line, the derived dirt gate at + frame 0 does not touch it). Replay with the gauged slots as variables, x = 0.""" + h, v, R = c["h"], c["v"], c["R"] + ext = [r for r, _ in c["ext"]] + if not ext: + return True + reg = [dict() for _ in range(2 * v + R)] + for r in ext: + reg[r] = {r: Fr(1)} + + def axpy(t, src, co): + d = reg[t] + for k, u in src.items(): + w = d.get(k, 0) + co * u + if w: + d[k] = w + else: + d.pop(k, None) + + def run(gates): + for g in gates: + if g[0] == "neg": + reg[g[2]] = {k: -u for k, u in reg[g[2]].items()} + elif g[0] == "out": + src = dict(reg[g[2]]) + for t, a, b in g[3]: + axpy(t, src, Fr(a, b)) + else: + for s, a, b in g[3]: + axpy(g[2], reg[s], Fr(a, b)) + run(c["A"]) + tot = {k: dict(reg[s]) for k, s, _ in c["ret"]} + for t in range(v): + for k, co in scat_row(c, t): + if tot[k]: + axpy(v + t, tot[k], co) + run(c["B"]) + need(all(not reg[v + t] for t in range(v)), "E7: the dirt of an exterior-gauged slot reaches a y role (Q2)") + return True diff --git a/research/e8-complex-far-retiming/complex/gx/gxcore.py b/research/e8-complex-far-retiming/complex/gx/gxcore.py new file mode 100644 index 0000000000..3e3f0a3076 --- /dev/null +++ b/research/e8-complex-far-retiming/complex/gx/gxcore.py @@ -0,0 +1,375 @@ +"""gxcore.py: gcert/1 JSON -> normal data D, PYTHON MIRROR of the two Lean checks +(label side: E0 frames, E1 pairs, E1/E2/E6 replay in segments; scalar side: E3 kinds, E4 bracket, E5 replay +in source batches, E7), derived data (distinct climbs, cut states, block histogram) and kernel sizes. +Own code; the reference is gx.py (check1), not imported. Python 3, standard library only.""" +import json, gzip +from collections import Counter +from math import gcd + + +class Reject(Exception): + pass + + +def need(c, msg): + if not c: + raise Reject(msg) + + +def load(path): + c = json.load(gzip.open(path, "rt") if path.endswith(".gz") else open(path)) + need(c.get("format") == "gcert/1", "E0: format is not gcert/1") + return c + + +def co(num, den): + need(den > 0, "E0: denominator") + return (num < 0, abs(num), den) + + +def normal(c): + """the Lean-facing data: gates as tuples, coefficients (neg, num, den), ret by total""" + def gate(g): + if g[0] == "out": + return ("out", g[1], g[2], [(t, co(a, b)) for t, a, b in g[3]], list(g[4])) + need(g[0] == "in", "E0: unknown gate kind %r" % (g[0],)) + return ("in", g[1], g[2], [(s, co(a, b)) for s, a, b in g[3]]) + ret = sorted(c["ret"]) + need([k for k, _, _ in ret] == list(range(len(ret))), "E2: retained totals numbered 0..") + sc = c["scat"] + scat = ("table", [[(k, co(a, b)) for k, a, b in row] for row in sc["table"]]) if "table" in sc else \ + ("star", co(*sc["inside"]), co(*sc["outside"])) + return dict(h=c["h"], v=c["v"], R=c["R"], N=c["N"], cst=c["cst"], ports=list(c["ports"]), + frames=[list(f) for f in c["frames"]], start=list(c["start"]), final=list(c["final"]), + ext=[tuple(e) for e in c.get("ext", [])], ret=[(s, f) for _, s, f in ret], scat=scat, + A=[gate(g) for g in c["A"]], B=[gate(g) for g in c["B"]], + blocks={k: {int(r): n for r, n in c["blocks"][k].items()} for k in "xysc"}) + + +def regs(g): + return [g[2]] + [t for t, _ in g[3]] + (g[4] if g[0] == "out" else []) + + +def adds(g): + """single adds (tgt, src, coef) in order""" + return [(t, g[2], k) for t, k in g[3]] if g[0] == "out" else [(g[2], s, k) for s, k in g[3]] + + +def reduce(u, basis): + for b in basis: + if u >> (b.bit_length() - 1) & 1: + u ^= b + return u + + +def echelon_ok(f): + piv = [b.bit_length() - 1 for b in f] + if any(b == 0 for b in f) or any(piv[i] <= piv[i + 1] for i in range(len(piv) - 1)): + return False + return all(not (b >> p & 1) for i, b in enumerate(f) for j, p in enumerate(piv) if i != j) + + +def par(x): + return bin(x).count("1") & 1 + + +def cls(D, r): + return "x" if r < D["v"] else "y" if r < 2 * D["v"] else "s" + + +# ---- label side ------------------------------------------------------------------------------------------ +def chk_frames(D): + """E0: ports; frame table reduced echelon, no repeats, zero first, full second""" + h, v, fr = D["h"], D["v"], D["frames"] + p = D["ports"] + need(len(p) == v == len(set(p)) and all(par(q) and 0 < q < 1 << h for q in p), "E0: ports") + need(len(fr) >= 2 and fr[0] == [] and fr[1] == [1 << i for i in range(h - 1, -1, -1)], "E0: frames 0 and 1") + need(all(echelon_ok(f) and all(b < 1 << h for b in f) for f in fr), "E0: frame table not reduced echelon") + need(len(set(map(tuple, fr))) == len(fr), "E0: frame table has repeats") + return [len(f) for f in fr] + + +def derive(D): + """distinct climbs in order of first use (NOT a check: plain replay of the frame ids)""" + cur, seen, pairs = list(D["start"]), set(), [] + + def go(r, f): + o = cur[r] + if o != f: + if (o, f) not in seen: + seen.add((o, f)) + pairs.append((o, f)) + cur[r] = f + for g in D["A"] + D["B"]: + for r in regs(g): + go(r, g[1]) + for r, f in enumerate(D["final"]): + go(r, f) + return pairs + + +def chk_pairs(D, dim, pairs): + """E1, level 2: every listed pair is a nested pair of the table; returns the mask-operation count""" + fr, n, work = D["frames"], len(D["frames"]), 0 + for a, b in pairs: + need(a < n and b < n and dim[a] < dim[b], "E1: pair (%d, %d) does not climb" % (a, b)) + need(all(reduce(u, fr[b]) == 0 for u in fr[a]), "E1: pair (%d, %d) is not nested" % (a, b)) + work += dim[a] * dim[b] + return work + + +def cut_points(D, gmax, wmax=210000): + """replay segments: each phase (A, B) is cut into k pieces of equal gate count, k = the least number with at + most `gmax` gates AND at most `wmax` work per piece on average (work = sum over gates of the dimension of the + gate's frame; measured at h = 22: about 1 ms of kernel time per unit, NOTES.md). + Cut points = gate counts in A ++ B (always 0, |A| and the end).""" + nA, nB = len(D["A"]), len(D["B"]) + cuts = [0] + for off, gs in ((0, D["A"]), (nA, D["B"])): + n = len(gs) + k = max(1, -(-n // gmax), -(-sum(len(D["frames"][g[1]]) for g in gs) // wmax)) + cuts += [off + (n * i) // k for i in range(1, k + 1)] + return sorted(set(cuts)) + + +def label_data(D, dim, cuts): + """for gx-labels (gcert-interface.md LABELS v1): ordered block ranks per replay segment, the final climbs as + gates without adds (same final frame, at most 32 registers, only registers that still climb), their ranks, + the largest number of registers named by one gate. Plain replay (the mirror has accepted the file).""" + cur, G = list(D["start"]), D["A"] + D["B"] + rs, most = [], 0 + for a, b in zip(cuts, cuts[1:]): + r = [] + for g in G[a:b]: + most = max(most, len(regs(g))) + for x in regs(g): + if cur[x] != g[1]: + r.append(dim[g[1]] - dim[cur[x]]) + cur[x] = g[1] + rs.append(r) + by = {} + for x, f in enumerate(D["final"]): + if cur[x] != f: + by.setdefault(f, []).append(x) + fins, rF = [], [] + for f in sorted(by): + for i in range(0, len(by[f]), 32): + xs = by[f][i:i + 32] + fins.append(("out", f, xs[0], [], xs[1:])) + rF += [dim[f] - dim[cur[x]] for x in xs] + return dict(rs=rs, fins=fins, rF=rF, most=max(most, 32 if fins else 0)) + + +def chk_replay(D, dim, pairs, cuts): + """E1 (labels), E2 (scatter cut), E6 (price), in the segments given by `cuts`. + Returns (states at the cuts, histogram by class, visits per segment).""" + h, v, R, fr = D["h"], D["v"], D["R"], D["frames"] + n = 2 * v + R + start, final, ext = D["start"], D["final"], dict(D["ext"]) + need(len(start) == len(final) == n, "E0: start / final") + for t in range(v): + need(fr[start[t]] == [D["ports"][t]] and final[t] == 1, "E1: x start / final") + f = fr[final[v + t]] + need(start[v + t] == 0 and len(f) == h - 1 and all(par(u & D["ports"][t]) == 0 for u in f), "E1: y start / final") + for r in range(2 * v, n): + need(start[r] == ext.get(r, 0) and final[r] == 1, "E1: slot start / final") + ok = set(pairs) + need(len(ok) == len(pairs), "E1: pair list has repeats") + cur = list(start) + H = {k: Counter() for k in "xysc"} + + def climb(r, f, where): + o = cur[r] + if o != f: + need((o, f) in ok, "E1: climb (%d, %d) is not a tested pair (%s, register %d)" % (o, f, where, r)) + H[cls(D, r)][dim[f] - dim[o]] += 1 + seg[dim[f] - dim[o]] += 1 + cur[r] = f + seg, segs = Counter(), [] + G, nA = D["A"] + D["B"], len(D["A"]) + states, visits = [], [] + need(cuts[0] == 0 and cuts[-1] == len(G) and cuts == sorted(cuts), "cut points") + for a, b in zip(cuts, cuts[1:]): + states.append(list(cur)) + vs = 0 + for i in range(a, b): + if i == nA: + scatter_cut(D, cur, dim, H, seg) + g = G[i] + rs = regs(g) + need(all(0 <= r < n for r in rs) and len(set(rs)) == len(rs), "E3: registers of gate %d" % i) + need(i >= nA or all(r < v or r >= 2 * v for r in rs), "E2: y role named in phase A (gate %d)" % i) + vs += len(rs) + for r in rs: + climb(r, g[1], "gate %d" % i) + visits.append(vs) + if b < len(G): + segs.append(seg) + seg = Counter() + if nA == len(G): + scatter_cut(D, cur, dim, H, seg) + states.append(list(cur)) + for r in range(n): + climb(r, final[r], "final") + segs.append(seg) + Hb = {k: dict(sorted(w.items())) for k, w in H.items()} + need(Hb == D["blocks"], "E6: block histogram differs from `blocks`") + N = sum(r * c for w in H.values() for r, c in w.items()) + need(N == D["N"] and N + sum(dim[f] for f in ext.values()) == R * h + 2 * v * (h - 1) + D["cst"], "E6: N") + need(sum(r * c for r, c in H["c"].items()) == D["cst"], "E6: cst") + return states, Hb, visits, [[w[r] for r in range(h + 1)] for w in segs] + + +def scatter_cut(D, cur, dim, H, seg): + v = D["v"] + if D["scat"][0] == "table": + need(len(D["scat"][1]) == v and all(k < len(D["ret"]) for row in D["scat"][1] for k, _ in row), "E2: scatter table") + else: + need(len(D["ret"]) == D["h"], "E2: one retained total per coordinate (star rule)") + for s, f in D["ret"]: + need(s >= 2 * v and cur[s] == f, "E2: retained slot %d is not at its frame" % s) + H["c"][dim[f]] += 1 + seg[dim[f]] += 1 + need(all(cur[v + t] == 0 for t in range(v)), "E2: a y role left frame 0 before the scatter") + + +# ---- scalar side ----------------------------------------------------------------------------------------- +SC = 6 # all scalar entries are kept as integers in units of 1/6 +KINDS = {("x", "s"), ("s", "s"), ("s", "y"), ("x", "y"), ("x", "x"), ("y", "y")} + + +def chk_shape(D): + """E3 kinds, E4 bracket""" + ysum, piv, ytg = Counter(), set(), set() + for ph in "AB": + for i, g in enumerate(D[ph]): + for t, s, (ng, a, b) in adds(g): + kd = (cls(D, s), cls(D, t)) + need(kd in KINDS and t != s, "E3: gate kind %s -> %s (gate %s%d)" % (kd + (ph, i))) + need(ph == "B" or kd in {("x", "s"), ("s", "s")}, "E3: bank gate before the scatter (gate A%d)" % i) + if kd == ("y", "y"): + need(SC % b == 0, "E4: denominator beyond sixths") + ysum[s, t] += (-a if ng else a) * (SC // b) + piv.add(s) + ytg.add(t) + need(not (piv & ytg), "E4: a pivot is the target of a gate reading y") + need(all(x == 0 for x in ysum.values()), "E4: y-reads of a (pivot, target) pair do not cancel") + return len(ysum) + + +def scat_row(D, t): + sc = D["scat"] + if sc[0] == "table": + return sc[1][t] + return [(k, sc[1] if D["ports"][t] >> k & 1 else sc[2]) for k in range(D["h"])] + + + +def replay(D, init, count=None): + """exact replay through A, scatter, B of sparse vectors with entries in sixths; `init` = register -> {key: 6}""" + v = D["v"] + reg = [dict(init.get(r, ())) for r in range(2 * v + D["R"])] + + def axpy(t, src, k): + ng, a, b = k + d = reg[t] + for key, u in src.items(): + w = u * a + need(w % b == 0, "E5: an entry needs a denominator beyond sixths (register %d)" % t) + w = w // b + w = d.get(key, 0) + (-w if ng else w) + if count is not None: + count[key] += 1 + if w: + d[key] = w + else: + d.pop(key, None) + + def run(gates): + for g in gates: + if g[0] == "out": + src = dict(reg[g[2]]) + for t, k in g[3]: + axpy(t, src, k) + else: + for s, k in g[3]: + axpy(g[2], reg[s], k) + run(D["A"]) + afterA = sum(len(d) for d in reg) + tot = [dict(reg[s]) for s, _ in D["ret"]] + for t in range(v): + for k, cf in scat_row(D, t): + if tot[k]: + axpy(v + t, tot[k], cf) + run(D["B"]) + return reg, afterA + + +def chk_scalar(D, batches=1): + """E5 (+ E7 when `ext` is non-empty). Returns stats: denominators and largest numerators per class in the + units of the spec (x halves, y sixths, slots integers), updates per source batch, entries after A.""" + v = D["v"] + count = Counter() + reg, afterA = replay(D, {t: {t: SC} for t in range(v)}, count) + need(all(reg[t] == {t: SC} for t in range(v)), "E5: an x role is not restored (X3)") + need(all(reg[v + t] == {t: SC} for t in range(v)), "E5: a target does not receive exactly its source (hid)") + if D["ext"]: + rg, _ = replay(D, {r: {r: SC} for r, _ in D["ext"]}) + need(all(not rg[v + t] for t in range(v)), "E7: the dirt of an exterior-gauged slot reaches a y role") + step = -(-v // batches) + per = [sum(count[k] for k in range(lo, min(lo + step, v))) for lo in range(0, v, step)] + return dict(updates=sum(count.values()), per_batch=per, afterA=afterA, + batches=[(lo, min(lo + step, v)) for lo in range(0, v, step)]) + + +def digits(D): + """largest |entry| met and denominators per class, by a second replay that watches every write (slow path + kept separate from the check): returns {class: (lcm of denominators, largest |numerator| in units 1/den)}""" + v = D["v"] + den = {"x": 1, "y": 1, "s": 1} + mx = {"x": 0, "y": 0, "s": 0} + reg = [({r: SC} if r < v else {}) for r in range(2 * v + D["R"])] + + def axpy(t, src, k): + ng, a, b = k + d, kk = reg[t], cls(D, t) + for key, u in src.items(): + w = d.get(key, 0) + (-(u * a // b) if ng else u * a // b) + if w: + d[key] = w + q = SC // gcd(w, SC) + if den[kk] % q: + den[kk] = den[kk] * q // gcd(den[kk], q) + if abs(w) > mx[kk]: + mx[kk] = abs(w) + else: + d.pop(key, None) + for g in D["A"]: + for t, s, k in adds(g): + axpy(t, reg[s], k) + tot = [dict(reg[s]) for s, _ in D["ret"]] + for t in range(v): + for k, cf in scat_row(D, t): + axpy(v + t, tot[k], cf) + for g in D["B"]: + for t, s, k in adds(g): + axpy(t, reg[s], k) + return {k: (den[k], mx[k] * den[k] // SC if (mx[k] * den[k]) % SC == 0 else "%d/6" % mx[k]) for k in "xys"} + + +def mirror(D, gmax=12000, batches=1, pairs=None, cuts=None): + """both checks; returns everything the generator and the dry run need""" + dim = chk_frames(D) + pairs = derive(D) if pairs is None else pairs + work = chk_pairs(D, dim, pairs) + cuts = cut_points(D, gmax) if cuts is None else cuts + states, H, visits, segH = chk_replay(D, dim, pairs, cuts) + ysh = chk_shape(D) + S = chk_scalar(D, batches) + hist = Counter() + for k in "xysc": + for r, n in H[k].items(): + hist[r] += n + return dict(dim=dim, pairs=pairs, pair_work=work, cuts=cuts, states=states, H=H, visits=visits, ysh=ysh, + scal=S, hist=dict(sorted(hist.items())), segH=segH, + lab=label_data(D, dim, cuts)) diff --git a/research/e8-complex-far-retiming/data/bit/bitE8-r865.json.gz b/research/e8-complex-far-retiming/data/bit/bitE8-r865.json.gz new file mode 100644 index 0000000000..8bec1751f7 Binary files /dev/null and b/research/e8-complex-far-retiming/data/bit/bitE8-r865.json.gz differ diff --git a/research/e8-complex-far-retiming/data/gcert1-e8-r783-far.json.gz b/research/e8-complex-far-retiming/data/gcert1-e8-r783-far.json.gz new file mode 100644 index 0000000000..56708f99a4 Binary files /dev/null and b/research/e8-complex-far-retiming/data/gcert1-e8-r783-far.json.gz differ diff --git a/research/e8-complex-far-retiming/lean/LEAN-B2-E8FR.txt b/research/e8-complex-far-retiming/lean/LEAN-B2-E8FR.txt new file mode 100644 index 0000000000..9edc512cac --- /dev/null +++ b/research/e8-complex-far-retiming/lean/LEAN-B2-E8FR.txt @@ -0,0 +1,159 @@ +Lean evidence: the re-timed E8 certificate (data/gcert1-e8-r783-far.json.gz) in Sussman's five-stage word B_2 +============================================================================================================== + +Scope. This is a kernel-checked theorem for ONE unit of the certificate in Sussman's bridged five-stage word B_2 +(m = 5h = 45, W = 4v + R = 1,263), the layout that his theorem wht_main_block_B2Ge8x covers for the original +gcert1-e8-r783. It is NOT a proof of the seven-stage B_3 layout this package prices (b, kappa), and not a proof +of any #377 nine-stage layout; those remain without a Lean proof. + +Theorem (OAI.PowerSaving.WHT.wht_main_block_B2Ge8FRx, module Work.GCert.Data.SolutionB2Ge8FRx): + + ∃ solve W, WHTProgram solve W ∧ WHTTimeBoundsAt (1 - 8766835/(10:ℝ)^10) W + +Sussman's original (wht_main_block_B2Ge8x, same generators): 1 - 8762479/(10:ℝ)^10 +Gain in the stated B_2 exponent: 4356/10^10 (+0.0497 %). + +Toolchain and inputs +-------------------- +- jacobalansussman/wht-power-saving-lean at 9c94857bbaee886f8649edee0bc2d3c738f9555e (2026-10-10), a fresh + clone (the older checkout at f010392, an ancestor, was left untouched); lean-toolchain leanprover/lean4:v4.34.1, + lakefile.lean and lake-manifest.json unchanged; no repository file modified, only new files added. +- Lean (version 4.34.1, aarch64-unknown-linux-gnu, commit 5045d0056413266e57c625dcd7c365b10e377c52, Release), + Linux 6.17.0 aarch64, 20 threads (builds pinned to 16 with taskset -c 0-15), 121 GB. +- Certificate: data/gcert1-e8-r783-far.json.gz of this package, copied to tools/certificate/ in the clone. + sha256 (gz) f2664ee7bcdfb55893abe9f1be8ee6a394a602e8262e611de2a0328bbd508aa7 + sha256 (decompressed) f2a404fe3f00cf843718fc8c23c6227d84e5e65c5a19cc1141dc1a6997ca86e7 +- Tags: certificate name E8FR, instance B2Ge8FR (Sussman's: E8, B2Ge8). + +Control. In the same clone, python3 tools/gx/regen_check_e8.py (Sussman's original) printed + RESULT: REPRODUCED (25 repository files reproduced byte for byte, 0 different, 3 generated files not in the repository) + +Commands (repository root of the clone) +--------------------------------------- + GX_OUT= python3 tools/gx/gxgen.py tools/certificate/gcert1-e8-r783-far.json.gz E8FR + GX_OUT= python3 tools/gx/gxrate.py B2Ge8FR E8FR + cp -r /Work/GCert/Data/. Work/GCert/Data/ ; cp /cmp/B2Ge8FRx.json comparator/ + for m in Gen.E8FR.S0 Gen.E8FR Gen.E8FRPar Gen.E8FRTab0 Gen.E8FRTab1 Gen.E8FRTab2 Gen.E8FRTab3 Gen.E8FRSeg0 \ + Gen.E8FRSeg1 Gen.E8FRSegF Gen.E8FREnd Gen.E8FRHist Gen.E8FRYChk Gen.E8FRScal0 RateB2Ge8FR RateB2Ge8FRx \ + InstB2Ge8FR E8FRPrice E8FRCert E8FRScalOK B2Ge8FR B2Ge8FRMain ChallengeB2Ge8FRx SolutionB2Ge8FRx; do + lake build Work.GCert.Data.$m || break + done + lake env lean --run tools/Compare.lean Work.GCert.Data.ChallengeB2Ge8FRx \ + Work.GCert.Data.SolutionB2Ge8FRx OAI.PowerSaving.WHT.wht_main_block_B2Ge8FRx + +Generator output (gxgen.py, gxrate.py), verbatim +------------------------------------------------ + E8FR: mirror accepts; h=9 v=120 R=783 N=9039; pairs=3120; replay segments=2; scalar batches=1 + wrote 2 data modules ([227296] bytes), 10 check modules, Work.GCert.Data.Gen.E8FRHist, Work.GCert.Data.E8FRCert + build order: Work.GCert.Data.Gen.E8FR.S0 Work.GCert.Data.Gen.E8FR Work.GCert.Data.Gen.E8FRScal0 Work.GCert.Data.Gen.E8FRYChk Work.GCert.Data.Gen.E8FRTab0 Work.GCert.Data.Gen.E8FRTab1 Work.GCert.Data.Gen.E8FRTab2 Work.GCert.Data.Gen.E8FRTab3 Work.GCert.Data.Gen.E8FRSeg0 Work.GCert.Data.Gen.E8FRSeg1 Work.GCert.Data.Gen.E8FRSegF Work.GCert.Data.Gen.E8FREnd Work.GCert.Data.Gen.E8FRHist Work.GCert.Data.E8FRPrice Work.GCert.Data.E8FRCert Work.GCert.Data.E8FRScalOK + unit B2Ge8FR: W=1263 m=45 D=120 tally=56715 blocks=[(1, 10465), (2, 3030), (3, 2620), (4, 835), (5, 1075), (6, 1705), (7, 215), (8, 360), (9, 40), (16, 240), (20, 240)] + RateB2Ge8FR: block 87667/10^8 (evaluated 87667, fails 87669), rank 55517 (evaluated 55517, fails 55524), s=13, slack 2.13e-08, rank slack 1.53e-06 + RateB2Ge8FRx: block 8766835/10^10 (evaluated 8766838, fails 8766839), rank 5552387 (evaluated 5552389, fails 5552394), s=40, slack 2.06e-10, rank slack 2.91e-09 + packed B2Ge8FRx wht_main_block_B2Ge8FRx 1 - 8766835/10^10 challenge code lines changed (0-based): [321, 322, 323] + packed B2Ge8FR wht_main_block_B2Ge8FR 1 - 87667/10^8 challenge code lines changed (0-based): [321, 322, 323] + +The Python mirror of both Lean checks accepts. The unit block list equals our own B_2 histogram (5 x the block +histogram + 2v x B_2 idle climbs {20 | 16, 8, 4}); verify.sh step 4b recomputes it. The exact B_2 coarse saving +by our engines is b_2 = 219170973636899/(2.5*10^17) = 8.76683894547596e-4, so floor(10^10 b_2) = 8766838 = +Sussman's "evaluated" figure. His generator states the exponent at 3 grid points below (s = 40 rank-sharp plan), +exactly as for his original (stated 8762479, evaluated 8762482, b_2 = 8.76248285600677e-4). + +Challenge vs Sussman's ChallengeB2Ge8x: after renaming B2Ge8FR -> B2Ge8 and E8FR -> E8, the only differing lines +are the four that carry the exponent (8766835 in place of 8762479): doc lines 6, 13, 322 and the statement, line 324. + +Build (lake build, one module per call, 24 modules) +--------------------------------------------------- +- 24 of 24 exit code 0, each "Build completed successfully"; last: (9213 jobs); no line starting with "error". +- "declaration uses `sorry`" appears exactly once, for Work/GCert/Data/ChallengeB2Ge8FRx.lean:323:8 (the + challenge states the theorem without proof, as intended); for no other module. +- The large evaluations are kernel evaluations (`by decide +kernel`): tab0..tab3, seg0, seg1, segF, end, hist, + yChk, scal0. +- Axiom lines printed by the build for the 24 new modules (each once): + Work/GCert/Data/Gen/E8FRTab0.lean:10:0: 'GXD.E8FR.tab0_ok' depends on axioms: [propext] + Work/GCert/Data/Gen/E8FRTab1.lean:10:0: 'GXD.E8FR.tab1_ok' depends on axioms: [propext] + Work/GCert/Data/Gen/E8FRTab2.lean:10:0: 'GXD.E8FR.tab2_ok' depends on axioms: [propext] + Work/GCert/Data/Gen/E8FRTab3.lean:10:0: 'GXD.E8FR.tab3_ok' depends on axioms: [propext] + Work/GCert/Data/Gen/E8FRSeg0.lean:9:0: 'GXD.E8FR.seg0_ok' depends on axioms: [propext] + Work/GCert/Data/Gen/E8FRSeg1.lean:9:0: 'GXD.E8FR.seg1_ok' depends on axioms: [propext] + Work/GCert/Data/Gen/E8FRSegF.lean:9:0: 'GXD.E8FR.segF_ok' depends on axioms: [propext] + Work/GCert/Data/Gen/E8FREnd.lean:10:0: 'GXD.E8FR.end_ok' depends on axioms: [propext] + Work/GCert/Data/Gen/E8FRYChk.lean:10:0: 'GXD.E8FR.ychk_ok' depends on axioms: [propext] + Work/GCert/Data/Gen/E8FRScal0.lean:10:0: 'GXD.E8FR.scal0_ok' depends on axioms: [propext] + Work/GCert/Data/RateB2Ge8FR.lean:204:0: 'OAI.PowerSaving.BlockAccounting.fold_B2Ge8FR' depends on axioms: [propext, Classical.choice, Quot.sound] + Work/GCert/Data/RateB2Ge8FR.lean:205:0: 'OAI.PowerSaving.BlockAccounting.fold_B2Ge8FR_sharp' depends on axioms: [propext, Classical.choice, Quot.sound] + Work/GCert/Data/RateB2Ge8FR.lean:206:0: 'OAI.PowerSaving.BlockAccounting.foldRank_B2Ge8FR' depends on axioms: [propext, Classical.choice, Quot.sound] + Work/GCert/Data/RateB2Ge8FR.lean:207:0: 'OAI.PowerSaving.BlockAccounting.foldRank_B2Ge8FR_sharp' depends on axioms: [propext, Classical.choice, Quot.sound] + Work/GCert/Data/RateB2Ge8FRx.lean:204:0: 'OAI.PowerSaving.BlockAccounting.fold_B2Ge8FRx' depends on axioms: [propext, Classical.choice, Quot.sound] + Work/GCert/Data/RateB2Ge8FRx.lean:205:0: 'OAI.PowerSaving.BlockAccounting.fold_B2Ge8FRx_sharp' depends on axioms: [propext, Classical.choice, Quot.sound] + Work/GCert/Data/RateB2Ge8FRx.lean:206:0: 'OAI.PowerSaving.BlockAccounting.foldRank_B2Ge8FRx' depends on axioms: [propext, Classical.choice, Quot.sound] + Work/GCert/Data/RateB2Ge8FRx.lean:207:0: 'OAI.PowerSaving.BlockAccounting.foldRank_B2Ge8FRx_sharp' depends on axioms: [propext, Classical.choice, Quot.sound] + Work/GCert/Data/InstB2Ge8FR.lean:54:0: 'OAI.PowerSaving.BridgeRate.B2Ge8FR.unit_cost' depends on axioms: [propext, Classical.choice, Quot.sound] + Work/GCert/Data/InstB2Ge8FR.lean:55:0: 'OAI.PowerSaving.BridgeRate.B2Ge8FR.unit_tally' depends on axioms: [propext, Classical.choice, Quot.sound] + Work/GCert/Data/E8FRPrice.lean:53:0: 'GXD.E8FR.inv_cost' depends on axioms: [propext, Classical.choice, Quot.sound] + Work/GCert/Data/E8FRPrice.lean:54:0: 'GXD.E8FR.inv_moves' depends on axioms: [propext, Classical.choice, Quot.sound] + Work/GCert/Data/E8FRCert.lean:77:0: 'GXD.E8FR.valid' depends on axioms: [propext, Classical.choice, Quot.sound] + Work/GCert/Data/E8FRCert.lean:78:0: 'GXD.E8FR.lab_price' depends on axioms: [propext, Classical.choice, Quot.sound] + Work/GCert/Data/E8FRScalOK.lean:15:0: 'GXD.E8FR.scalOK' depends on axioms: [propext, Classical.choice, Quot.sound] + Work/GCert/Data/B2Ge8FR.lean:100:0: 'OAI.PowerSaving.WHT.wht_B2Ge8FR_of_scal' depends on axioms: [propext, Classical.choice, Quot.sound] + Work/GCert/Data/B2Ge8FR.lean:101:0: 'OAI.PowerSaving.WHT.wht_B2Ge8FRx_of_scal' depends on axioms: [propext, Classical.choice, Quot.sound] + Work/GCert/Data/B2Ge8FR.lean:102:0: 'OAI.PowerSaving.WHT.wht_B2Ge8FR_of_ids' depends on axioms: [propext, Classical.choice, Quot.sound] + Work/GCert/Data/B2Ge8FR.lean:103:0: 'OAI.PowerSaving.WHT.wht_B2Ge8FRx_of_ids' depends on axioms: [propext, Classical.choice, Quot.sound] + Work/GCert/Data/B2Ge8FRMain.lean:32:0: 'OAI.PowerSaving.WHT.wht_main_B2Ge8FR' depends on axioms: [propext, Classical.choice, Quot.sound] + Work/GCert/Data/B2Ge8FRMain.lean:33:0: 'OAI.PowerSaving.WHT.wht_main_B2Ge8FRx' depends on axioms: [propext, Classical.choice, Quot.sound] + Work/GCert/Data/SolutionB2Ge8FRx.lean:38:0: 'OAI.PowerSaving.WHT.wht_main_block_B2Ge8FRx' depends on axioms: [propext, Classical.choice, Quot.sound] +- Wall time 24 modules: about 90 s; largest Lean process 7.04 GB. + +tools/Compare.lean (exit code 0), verbatim +------------------------------------------ + challenge module: Work.GCert.Data.ChallengeB2Ge8FRx (10745 modules loaded) + solution module: Work.GCert.Data.SolutionB2Ge8FRx (11034 modules loaded) + sanity: imported proofs are loaded (Nat.add_comm uses 7 constants, Real.exp_pos uses 85) + + === OAI.PowerSaving.WHT.wht_main_block_B2Ge8FRx === + challenge: theorem in Work.GCert.Data.ChallengeB2Ge8FRx; solution: theorem in Work.GCert.Data.SolutionB2Ge8FRx + OK: statement is the same kernel term in both + challenge proof uses sorryAx: true + statement depends on 2035 constants; 107 are declared in the challenge file itself + OK: every statement dependency is identical in the solution + solution proof reaches 36821 constants; axioms: #[Classical.choice, Quot.sound, propext] + OK: only permitted axioms + + RESULT: PASS + CMP_EXIT 0 + + (the 107 per-constant "identical: ..." lines, indented in the log, are omitted) + Wall 15.7 s, maximum resident set 16.1 GB. + +Not run: the official leanprover/comparator (comparator/B2Ge8FRx.json was generated; it needs landrun / +Landlock, as in Sussman's VERIFY.md section 8). + +SHA-256 of the 26 generated Lean modules and 2 comparator configurations +------------------------------------------------------------------------ + 7d756363c48bf9de60db8eb6108f9b36c14ab927f502532faae27a7ad17d9756 cmp/B2Ge8FR.json + 5ac2659d6c8e9c981d0f69f6beeae98abad33d361414ca4a608f2fdc5232a1fa cmp/B2Ge8FRx.json + 7151321cef1612922b2b9961cde0803f92a8c905ffd6f0c3556a8bac80864582 Work/GCert/Data/B2Ge8FR.lean + b273786f6f973628f882127abc26b7307d1046b7ab80888ec3403ddc05f3e07f Work/GCert/Data/B2Ge8FRMain.lean + 42d88d6b7fead91bab2e7051cb2ddd8a19d49323fe186c3fef6d75acfb8343e5 Work/GCert/Data/ChallengeB2Ge8FR.lean + ac370d35ba633a80c917fda44129655feaec874f6f96491bc748e4c52d219d7a Work/GCert/Data/ChallengeB2Ge8FRx.lean + 7c8369d5e510837911b1199e5ca3f4b862226b4f61753b4cdacc65c67eb46bbf Work/GCert/Data/E8FRCert.lean + 42a041e5f80e33376c3f6627e9663395e5af6c72785645227000dd58924139b8 Work/GCert/Data/E8FRPrice.lean + d62cedaa79d2badb7ffe6c5ab5dec73b6392a90883b66596b2024e497d650bdc Work/GCert/Data/E8FRScalOK.lean + e62f8ba7cbf5bd06989609d30bb9c812bac9a1656620bf9c0e6e7d275b7d8ee9 Work/GCert/Data/Gen/E8FREnd.lean + fed2c5788b9fbca540c1bf1772fa3f5ec4c9b5ab771d5ecfcc3cc149599d755f Work/GCert/Data/Gen/E8FRHist.lean + 9dba64181b0f7aa46d6fc45b9eba9d9e5de2da9fa07cff605a7b29dccf24b5be Work/GCert/Data/Gen/E8FR.lean + 776aab4f5d0ec5fc56e0a81a645a2698cbc1153524b3de8cff308266b5e5aaba Work/GCert/Data/Gen/E8FRPar.lean + a657d8ffece650ce41625fff21c24626f6816911ec102c9fe7b09f0eaa59a63e Work/GCert/Data/Gen/E8FR/S0.lean + 853fc82b6c5fb1ac55febbe78da5d46a06fb844d9528ceb403afff2ee8bbacaf Work/GCert/Data/Gen/E8FRScal0.lean + b3fc8760bb8a0f03d03b7952c6c871f50517de377c9bf640043d74ba5ff3d28c Work/GCert/Data/Gen/E8FRSeg0.lean + d8116703d1bcfe2ea847f471e183b03abadefc0b34aab9fd3b02d24740e353dd Work/GCert/Data/Gen/E8FRSeg1.lean + 695b3d53f9d754fecc234f29f692701ac7cacb3c867604f27899fd89a188fea4 Work/GCert/Data/Gen/E8FRSegF.lean + c9568cd8e456d116cea1d14d157524f5478e9760fc7f328a4eda0df32d0c3139 Work/GCert/Data/Gen/E8FRTab0.lean + 096fef120b0e3af85bd6512bad12b1f15655fb67cf6e6f41036063de813503ff Work/GCert/Data/Gen/E8FRTab1.lean + ba5820e0b41a56a3ff0dd7f0ff4401d36f82d60e7fb835ffc6f38622fa6ea3a0 Work/GCert/Data/Gen/E8FRTab2.lean + 868944bfacea917b2958492ecea31f564de951d0ed7f10d17b680f93c7fa958e Work/GCert/Data/Gen/E8FRTab3.lean + 82909506ed4b3288676dad6af108c7fa9b5f7ca88565165cc68db897acba939e Work/GCert/Data/Gen/E8FRYChk.lean + dbd7cbb4ef78bf48852fce9ab582d4ded574f6239cac7d602b62d0cee2cb3dd3 Work/GCert/Data/InstB2Ge8FR.lean + ceda23d73841d962024f6e7ed539f9da1e06fbfee627c4a05a21908408fac571 Work/GCert/Data/RateB2Ge8FR.lean + 3eb3d99db71857c4dbe759f0bfb2f935ff7cd80ef4a9e26c8972723886420270 Work/GCert/Data/RateB2Ge8FRx.lean + 6f1e4eae4a3369a6956696d98f297a1bcf13de2c05a79a5b7e66a1d2dcbd7cb8 Work/GCert/Data/SolutionB2Ge8FR.lean + 836ba4e14d6eb2bd9a01146f723dcbf29ed1ef9e06a6797c565096a6f88ef446 Work/GCert/Data/SolutionB2Ge8FRx.lean diff --git a/research/e8-complex-far-retiming/verify.sh b/research/e8-complex-far-retiming/verify.sh new file mode 100644 index 0000000000..9636475cc3 --- /dev/null +++ b/research/e8-complex-far-retiming/verify.sh @@ -0,0 +1,84 @@ +#!/usr/bin/env bash +# One-command verification of research/e8-complex-far-retiming. usage: bash verify.sh [--quick] /fresh/output/dir +# python3 >= 3.11, standard library only. --quick skips step 5 (regeneration of the certificate, about 1 min). +set -euo pipefail +QUICK=0; if [ "${1:-}" = "--quick" ]; then QUICK=1; shift; fi +HERE=$(cd "$(dirname "$0")" && pwd); WD=$(mkdir -p "$1" && cd "$1" && pwd) +case "$WD" in "$HERE"*) echo "output dir must be outside the package"; exit 2;; esac +PY="${PYTHON:-python3} -I -B"; C=$HERE/code; GX=$HERE/complex/gx +ORIG=$HERE/complex/gcert1-e8-r783.json.gz; OURS=$HERE/data/gcert1-e8-r783-far.json.gz; WORD=$HERE/data/bit/bitE8-r865.json.gz + +echo "== 0. manifest"; (cd "$HERE" && $PY -c " +import hashlib,sys,os +bad=0;listed=set() +for line in open('MANIFEST.sha256'): + h,p=line.rstrip('\n').split(' ',1);listed.add(p) + if hashlib.sha256(open(p,'rb').read()).hexdigest()!=h: print('MISMATCH',p);bad+=1 +files={os.path.relpath(os.path.join(r,f)) for r,_,fs in os.walk('.') for f in fs if '__pycache__' not in r}-{'MANIFEST.sha256'} +if files-listed: print('UNLISTED',sorted(files-listed));bad+=1 +sys.exit(1 if bad else 0)") || { echo "MANIFEST FAIL"; exit 1; }; echo " all files match MANIFEST.sha256" + +echo "== 1. pinned inputs (git blob ids)" +$PY -c " +import hashlib +def blob(p): + d=open(p,'rb').read();return hashlib.sha1(b'blob %d\0'%len(d)+d).hexdigest() +pins={'$ORIG':('0bd0bacf744f1c31419e05b834e34a92be77ae57','Sussman gcert1-e8-r783 (wht-power-saving-lean 9c94857; = #363/#365/#375 vendored copy)'), + '$GX/gx.py':('6d14c0a976146eb881c1e3897b2476f8633d4e9c','Sussman tools/gx/gx.py (= #375 vendored copy)'), + '$GX/gxcore.py':('3e3f0a3076f3c326e7833c74eceecb3436dd3185','Sussman tools/gx/gxcore.py (= upstream main copies)'), + '$WORD':('8bec1751f7e33c3a1e4673ef5dbc34d6f205321e','#370 E8 bit word bitE8-r865 (= #373 data/bit)')} +for p,(h,what) in pins.items(): + assert blob(p)==h,(p,blob(p));print(' ',h[:12],what)" + +echo "== 2. complex certificates: Sussman's checkers, the source-span rule, and the full operator identity" +$PY $C/cxcheck.py $ORIG $GX +$PY $C/cxcheck.py $OURS $GX +$PY $C/cxop.py $ORIG $OURS +$PY -c " +import gzip,json +a=json.load(gzip.open('$ORIG'));b=json.load(gzip.open('$OURS')) +assert (a['h'],a['v'],a['R'],a['cst'],a['N'],a['ports'],a['start'],a['final'],a['ret'],a['scat'],a['ext'])==(b['h'],b['v'],b['R'],b['cst'],b['N'],b['ports'],b['start'],b['final'],b['ret'],b['scat'],b['ext']) +assert b['frames'][:len(a['frames'])]==a['frames'] +d={k:{r:b['blocks'][k].get(r,0)-a['blocks'][k].get(r,0) for r in sorted(set(a['blocks'][k])|set(b['blocks'][k]),key=int) if b['blocks'][k].get(r,0)!=a['blocks'][k].get(r,0)} for k in a['blocks']} +print(' same family, ports, start/final frames, retained totals, scatter table, N = %d; frame table extended by %d frames'%(b['N'],len(b['frames'])-len(a['frames']))) +print(' block-histogram delta (ours - Sussman):',{k:x for k,x in d.items() if x})" + +echo "== 3. the bridged layout B_K (our reimplementation of #363's rule): B_2 = Sussman's, B_3 = #363's idle climbs" +$PY -c " +import sys;sys.path.insert(0,'$C');from layout_bk import layout +assert layout(2,9)['per_pair']=={1:[20],2:[16,8,4]} and layout(3,9)['per_pair']=={1:[38],2:[16,8,22],3:[32,8,6]} +assert layout(3,8)['per_pair']=={1:[34],2:[14,7,20],3:[28,7,6]} +print(' nested climbs, equal-frame twin gates, stage entries, final frames, m-1 moves per role, exchange identity: PASS') +print(' B_3 idle climbs h = 9 (complex):',layout(3,9)['per_pair'],'| h = 8 (bit):',layout(3,8)['per_pair'])" + +echo "== 4. exact coarse savings in B_3 and PR #315's outer assembly" +$PY $C/kappa.py $OURS $ORIG $WORD $WD/kappa.json +$PY -c " +import json;k=json.load(open('$WD/kappa.json'))['ours'] +assert k['kappa']=='95464544449649/100000000000000000' and k['binding']=='complex' and k['b_unsplit']=='477778832512643/500000000000000000',k +print('PASS conditional kappa =',k['kappa'],'=',k['kappa_float'],'(complex-bound: our E8 certificate in the unsplit B_3 at halving degree two; bit side #370/#373)')" + +echo "== 4b. B_2 (Sussman's five-stage word): the unit behind the Lean theorem of lean/LEAN-B2-E8FR.txt" +$PY -c " +import sys,gzip,json,math;sys.path.insert(0,'$C') +from collections import Counter;from e8core import coarse;from layout_bk import layout +def b2(f): + c=json.load(gzip.open(f));H=Counter() + for w in c['blocks'].values(): + for r,n in w.items():H[int(r)]+=5*n + for r in layout(2,c['h'])['blocks']:H[r]+=2*c['v'] + W=4*c['v']+c['R'];m=5*c['h'];assert m*W-sum(r*n for r,n in H.items())==4*c['v']-5*c['cst'] and 2*max(H) $WD/regen.txt + $PY $C/cxfinal.py $WD/regen-split.json.gz $ORIG $WD/regen.json.gz + $PY -c " +import gzip;assert gzip.open('$WD/regen.json.gz').read()==gzip.open('$OURS').read();print(' regenerated certificate equals the shipped one (decompressed bytes)')" +fi diff --git a/research/joint-dual/SOURCE.json b/research/joint-dual/SOURCE.json index e3a8386b17..e1fbf9c5aa 100644 --- a/research/joint-dual/SOURCE.json +++ b/research/joint-dual/SOURCE.json @@ -3,9 +3,9 @@ "base_pr57_commit": "cd350f76c9bc01489ec83568bded532cb69be938", "base_pr58_commit": "bc2f7ed4c20dc18898305ab17165c0c995cbb804", "files": { - "Makefile": "768131bd4ce18433f6abccdc9812a38c92e11220e3a1019c6d95334b42f529d1", + "Makefile": "cd0fb59dc078d1fdf54a163ea13bb3660d03c8fe69c1a7f99fc8e5f476a3d5c2", "NOTICE": "b49022cb4104d90b182e4c335f670faf45529025b15db77bf0291835083c28bd", - "README.md": "d104c31d5b7e0d3a8d011a0e3517ab615e5b499b3dc05684f7ad3cadcd28bdae", + "README.md": "b81f8035b859007add6693c6d860371c9100a6766e494045495a28a457a5fcb9", "certificates/joint-dual-compiler.json": "516c4d85158553dabd0a98216a064b2a7397957a9d5dd0df1d6e5aec53a4e805", "certificates/joint-dual-profiles-23.json": "159fa8fee175fc1d24f63e72d3c2f1dc9f4fcd78b938c5e7d2f735fd0fd37209", "certificates/joint-dual-profiles-25.json": "8d190ce42d097e828c5756918c52f2963df576cf4c6600b0fc7f2b7fdb6ad223",