diff --git a/research/leaver-partial-cells/KEYS-ALL16.json b/research/leaver-partial-cells/KEYS-ALL16.json new file mode 100644 index 0000000000..8e096bec87 --- /dev/null +++ b/research/leaver-partial-cells/KEYS-ALL16.json @@ -0,0 +1 @@ +{"keys": [[[0, 2], -1], [[0, 2], 1], [[0, 3], -1], [[0, 3], 1], [[1, 2], -1], [[1, 2], 1], [[1, 3], -1], [[1, 3], 1], [[4, 6], -1], [[4, 6], 1], [[4, 7], -1], [[4, 7], 1], [[5, 6], -1], [[5, 6], 1], [[5, 7], -1], [[5, 7], 1]]} \ No newline at end of file diff --git a/research/leaver-partial-cells/KEYS-CLASS4567.json b/research/leaver-partial-cells/KEYS-CLASS4567.json new file mode 100644 index 0000000000..20f8bc09b8 --- /dev/null +++ b/research/leaver-partial-cells/KEYS-CLASS4567.json @@ -0,0 +1 @@ +{"keys": [[[4, 6], -1], [[4, 6], 1], [[4, 7], -1], [[4, 7], 1], [[5, 6], -1], [[5, 6], 1], [[5, 7], -1], [[5, 7], 1]]} \ No newline at end of file diff --git a/research/leaver-partial-cells/KEYS-ONE.json b/research/leaver-partial-cells/KEYS-ONE.json new file mode 100644 index 0000000000..6cd7cf2f4a --- /dev/null +++ b/research/leaver-partial-cells/KEYS-ONE.json @@ -0,0 +1 @@ +{"keys": [[[0, 2], 1]]} \ No newline at end of file diff --git a/research/leaver-partial-cells/LICENSE b/research/leaver-partial-cells/LICENSE new file mode 100644 index 0000000000..261eeb9e9f --- /dev/null +++ b/research/leaver-partial-cells/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/leaver-partial-cells/NOTICE.md b/research/leaver-partial-cells/NOTICE.md new file mode 100644 index 0000000000..864ae78dd9 --- /dev/null +++ b/research/leaver-partial-cells/NOTICE.md @@ -0,0 +1,11 @@ +# Notice + +Prepared by higherbeing with substantial Claude (Anthropic) assistance, under Apache-2.0 (see LICENSE). + +Built on, and patching copies of, files from: +- **jeremykothe2**, #1005 (research/gauge44-leaver8): the mutable-leaver all-K cells, `cgx_leaver.py`, `reproduce_leaver.py` and the k8 chain this note measures against. +- **icekylinx**, #645 (gauge44) and the PartialK no-triangle constructors (`notri/cgx.py`, `notri/port_stage_x.py`, `notri/cold44x.py`). +- The PR635 supplier lineage: `code/prefix_trace.py` is `hpe_audit_local.py` from research/complex-571-cold14-st2 with the 192-bit assertion replaced by a print of the bound and the gates that attain it. It is a measuring copy, not a verifier. +- The #645 / #1005 independent price engine (`independent/price_profile.py`), called unchanged by `code/price_delta.py`. + +No inherited file in the repository is changed; the patches are applied to copies under the output directory. diff --git a/research/leaver-partial-cells/README.md b/research/leaver-partial-cells/README.md new file mode 100644 index 0000000000..0f32aa6091 --- /dev/null +++ b/research/leaver-partial-cells/README.md @@ -0,0 +1,60 @@ +# Partial leaver cells on #1005's word: a negative result (no κ claim) + +**No κ claim.** This note tests the obvious next step after #1005: extending mutable-leaver cells beyond the eight all-K cells. It does not raise κ. The note records why, because two of the obstructions will bind any further leaver-style rewrite on this line. + +## Setup + +#1005 replaced the eight all-K delivery cells with helper-free circuits that use *leaver* sources (registers with no later reads) as scratch. Outside those cells, 144 face events remain. Only 32 of them have leaver operands. They form **16 keys** (p, ε) with leaver operands in exactly two of their three blocks: the two blocks whose targets request the face. The third block (0123 for eight keys, 4567 for the other eight) feeds an M combination instead. Each of these keys uses three face copies and one slot copy. No other key has leaver operands in all three blocks, which is why #1005 stopped at eight cells. + +For each key, four targets each need four of five inputs (their own row, the other leaver pair, and the third block's face), and one register must end holding the sum of the four leaver inputs (M). + +## Method + +- **Exact legality as taint bits.** A register frame F fits target t's hyperplane iff every generator of F is orthogonal to the port P_t. That property is a union under frame joins. So frame legality for these circuits is exactly a few bits per register: one per circuit target, plus one per class of downstream targets whose final-frame allowance can bind. +- **Layered CP-SAT** (`code/satcell.py`) over set and taint states, with optional helper registers, target-to-target gates on/off, reader constraints for kept helpers, and allowances on final frames. +- **Construction hook** (`patches/cgx_leaver.patch`): applies a circuit template per key inside #1005's constructor, drops the freed copies through the helper map exactly as #1005 drops its copies, and recomputes frames. The constructor's own exact identity check runs unchanged. +- **Port stages.** Moving own-row reads breaks the port stage's gate alignment (the all-K cells lose their anchor and land before the entrance reads). `patches/port_stage_x.patch` adds two construction-side options: successor anchoring for unmatched gates (`PORT_SUCC`) and a monotone frame repair that reports any hyperplane violation (`PORT_REPAIR`). On #1005's own word both are byte-identical no-ops. On every variant below, all four port stages needed **zero** repairs. +- **Verification** is the inherited chain: regroup, HPE, cold44, then the native audit (exact forward and inverse replay with arbitrary dirt), ledgers and the local replay. + +## Results + +Profiles are measured on the cold-end word (before #1005's later layers), as a per-call delta against #1005's cell word. κ is #1005's global profile plus 72 × delta, with the saved rank mass placed as rank-48 idle (ideal packing, an upper bound on what an owner map can achieve). Bits are the local replay's coefficient bound (L1 prefix), which must stay below **192**. + +| variant | helpers removed | cold-end pairing in the 8 touched blocks | native audit | bits (fwd) | κ, ideal packing | +|---|---|---|---|---|---| +| #1005 baseline | 0 | 4 each | pass | 188 | 0.001671387264390146 | +| one helper + 2 target-to-target gates (reuses an entering copy) | 32 | 0 | **fail**: zero-frame compensation reads an entering helper | — | (0.00168268 if it were legal) | +| two kept entering copies, all 16 keys | 16 | 0–1 | pass, all stages | 107 | 0.0016650 (loss) | +| one fresh non-entering helper, all 16 keys | 32 | 0 | pass | **210** (over the cap) | 0.0016702 (loss) | +| one fresh helper, 4567 class only | 16 | 2 each | pass | **203** (over the cap) | 0.0016723 (+0.05 %) | +| one fresh helper, one key | 2 | 3 in two blocks | pass | 187 | 0.0016712 (loss) | + +`reproduce.sh` rebuilds every row and writes `RESULTS.json` with the exact deltas, pairing ranks, stage outcomes, bits and prices. + +## Obstructions + +1. **The packet copies are entering helpers.** After the port stages, the copies start holding arbitrary dirt, and each original reader pre-reads the copy so its dirt cancels. A kept copy must therefore be read exactly once by each of its original readers, and no circuit may copy a dirty target into another target. The 32-helper circuit violates both and the native audit rejects it. With own rows first and one helper, CP-SAT proves the key infeasible (L ≤ 20); with one *fresh* helper the audit passes, but fresh helpers start at the zero frame and add rank-1 climbs. +2. **Cold-end pairing collapses.** Every target in the eight touched blocks belongs to one of the 16 keys. Using their own-row registers as leavers moves all of them out of the block frame, so the rank-4 cold-end pairing in those blocks falls from 4 to 0–2. The copies were what kept the own rows inside their blocks. At roughly the same price per item, a lost cold end costs about as much as a removed helper earns. +3. **The 192-bit coefficient allowance is nearly exhausted.** #1005's word already needs 188 of the 192 bits allowed by the local payload rule, attained in the full-frame cleanup of block 4567's scratch registers. Leaver rewrites add accumulation chains: eight circuits push it to 203 bits and sixteen to 210. Only one or two circuits fit. Anyone extending #1005's line with more leaver mutations will hit this bound before the others. + +## Reproduce + +```sh +bash research/leaver-partial-cells/reproduce.sh . /tmp/gauge44-pr635 /tmp/leaver-partial-cells +``` + +The second argument is the pinned #635 supplier prepared as in #645. The script runs #645's no-triangle base, #1005's cell driver with its pins checked, the census, the raw-level template checks and the five variants, then prices them. It takes about 45 minutes on a laptop. + +The circuit search is optional and needs ortools. For example, after a run: + +```sh +PC_CENSUS=/tmp/leaver-partial-cells/census/raw/CENSUS.pkl PC_PROTO=/tmp/leaver-partial-cells/notri-base/hamming/PROTOTYPE.json \ +PC_PORTED=/tmp/leaver-partial-cells/base/port3/FULL-WORD.json.gz PCELL_MOVEOWN=1 PCELL_H2=0 \ +python research/leaver-partial-cells/code/postport.py "((0,2),1)" 1500 2 +``` + +`TEMPLATES.json` holds the four circuits used above. + +## Scope + +Finite, local measurements on #1005's cell word. Prices assume ideal owner packing and omit #1005's later layers (NP and p6n ends, promotions, hybrids, frame re-optimisation), which act mostly on other registers. The negative conclusions do not depend on either: the legal variants lose or break the 192-bit rule before any layer is applied. diff --git a/research/leaver-partial-cells/RESULTS.json b/research/leaver-partial-cells/RESULTS.json new file mode 100644 index 0000000000..785e8dfa00 --- /dev/null +++ b/research/leaver-partial-cells/RESULTS.json @@ -0,0 +1,277 @@ +{ + "baseline": { + "R": 480, + "pairing": [ + 0, + 0, + 0, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 0, + 0, + 0 + ], + "profile": { + "1": 2394, + "2": 398, + "3": 508, + "4": 142, + "5": 56, + "8": 8 + }, + "bits": { + "forward": 188, + "backward": 126 + }, + "kappa": "0.001671387264390146" + }, + "v1-yy-entering": { + "R": 448, + "helpers_removed": 32, + "pairing": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ], + "delta_per_call": { + "1": 78, + "2": 28, + "3": -8, + "4": -56 + }, + "bits": null, + "stage": [ + [ + "cells", + "gauge-forward", + "port0", + "port1", + "port2", + "port3", + "cold44", + "leaver" + ], + [ + "native", + [ + "AssertionError: zero-frame compensation reads an entering helper" + ] + ] + ], + "kappa_ideal_packing": "0.001682679188273388" + }, + "v2-two-kept": { + "R": 464, + "helpers_removed": 16, + "pairing": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 0, + 0, + 0 + ], + "delta_per_call": { + "1": -42, + "2": 24, + "3": 60, + "4": -56, + "6": 12 + }, + "bits": { + "forward": 107, + "backward": 98 + }, + "stage": [ + [ + "cells", + "gauge-forward", + "port0", + "port1", + "port2", + "port3", + "cold44", + "leaver", + "native", + "ledgers", + "local-replay", + "wrappers" + ], + null + ], + "kappa_ideal_packing": "0.001664963941291308" + }, + "v3-fresh-all16": { + "R": 448, + "helpers_removed": 32, + "pairing": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ], + "delta_per_call": { + "1": 106, + "2": 20, + "3": 4, + "4": -56 + }, + "bits": { + "forward": 210, + "backward": 135 + }, + "stage": [ + [ + "cells", + "gauge-forward", + "port0", + "port1", + "port2", + "port3", + "cold44", + "leaver", + "native", + "ledgers" + ], + [ + "local-replay", + [ + "AssertionError" + ] + ] + ], + "kappa_ideal_packing": "0.001670235002450254" + }, + "v3-fresh-4567": { + "R": 464, + "helpers_removed": 16, + "pairing": [ + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0 + ], + "delta_per_call": { + "1": 62, + "3": 8, + "4": -32 + }, + "bits": { + "forward": 203, + "backward": 139 + }, + "stage": [ + [ + "cells", + "gauge-forward", + "port0", + "port1", + "port2", + "port3", + "cold44", + "leaver", + "native", + "ledgers" + ], + [ + "local-replay", + [ + "AssertionError" + ] + ] + ], + "kappa_ideal_packing": "0.001672268739935671" + }, + "v3-fresh-one": { + "R": 478, + "helpers_removed": 2, + "pairing": [ + 0, + 0, + 0, + 3, + 3, + 4, + 4, + 4, + 4, + 4, + 4, + 0, + 0, + 0 + ], + "delta_per_call": { + "1": 5, + "2": 2, + "4": -3 + }, + "bits": { + "forward": 187, + "backward": 127 + }, + "stage": [ + [ + "cells", + "gauge-forward", + "port0", + "port1", + "port2", + "port3", + "cold44", + "leaver", + "native", + "ledgers", + "local-replay", + "wrappers" + ], + null + ], + "kappa_ideal_packing": "0.001671190140624238" + } +} \ No newline at end of file diff --git a/research/leaver-partial-cells/TEMPLATES.json b/research/leaver-partial-cells/TEMPLATES.json new file mode 100644 index 0000000000..f53a94b0ae --- /dev/null +++ b/research/leaver-partial-cells/TEMPLATES.json @@ -0,0 +1 @@ +{"TPL_one_helper_with_target_gates": [["y1", "a0"], ["y0", "a1"], ["h", "a4"], ["y2", "a3"], ["y3", "a2"], ["a1", "a0"], ["y2", "y0"], ["y1", "y3"], ["y2", "a4"], ["y3", "a1"], ["a2", "a3"], ["y0", "a2"], ["y2", "a0"], ["y1", "h"], ["y0", "a4"], ["a1", "a2"], ["y3", "h"], ["y1", "a3"]], "TPL2_one_helper_no_target_gates": [["y1", "a3"], ["y0", "a2"], ["y3", "a0"], ["h", "a1"], ["y2", "a4"], ["y0", "a4"], ["a1", "a3"], ["y2", "h"], ["y2", "a3"], ["y3", "a2"], ["y0", "h"], ["y1", "a0"], ["a1", "a0"], ["y1", "a2"], ["a2", "a1"], ["y3", "a4"], ["y2", "a0"], ["y1", "a4"], ["y3", "h"], ["y0", "a3"]], "TPLA_two_helpers_class0123": [["y1", "a3"], ["y2", "a4"], ["h1", "a0"], ["h0", "a2"], ["a2", "a0"], ["y3", "a1"], ["a1", "a3"], ["h0", "a4"], ["y0", "a1"], ["y3", "h0"], ["h1", "a1"], ["y2", "h1"], ["y1", "a2"], ["a2", "a1"], ["y1", "a4"], ["y0", "h0"], ["y3", "a0"]], "TPLB_two_helpers_class4567": [["h0", "a0"], ["h1", "a1"], ["y3", "a2"], ["y2", "a3"], ["a2", "a3"], ["y0", "a4"], ["y1", "a2"], ["h1", "a2"], ["a0", "a1"], ["y0", "h1"], ["h0", "a4"], ["y3", "a0"], ["a2", "a0"], ["y3", "a4"], ["y2", "h0"], ["y1", "h0"], ["y2", "a1"]]} \ No newline at end of file diff --git a/research/leaver-partial-cells/code/collect.py b/research/leaver-partial-cells/code/collect.py new file mode 100644 index 0000000000..e75a4fbc4f --- /dev/null +++ b/research/leaver-partial-cells/code/collect.py @@ -0,0 +1,29 @@ +"""Collect each variant: cold44 profile delta vs baseline, cold-end pairing, native/local-replay outcome, +coefficient (L1 prefix) bits, and the κ of #1005's global profile plus 72 x delta (ideal rank-48 packing).""" +import json,gzip,os,sys +from collections import Counter +sys.path.insert(0,os.path.dirname(os.path.abspath(__file__))) +from price_delta import price +OUT=sys.argv[1];rd=lambda p:json.loads(gzip.decompress(open(p,'rb').read())) +def prof(d): + w=rd(f'{OUT}/{d}/cold44/FULL-WORD.json.gz');c=json.load(open(f'{OUT}/{d}/cold44/CONSTRUCTION.json')) + return Counter({int(k):v for k,v in w['report']['local_profile'].items()}),[b['pairing_rank'] for b in c['blocks']],w['report']['R'] +def bits(d): + p=f'{OUT}/{d}.prefix' + if not os.path.exists(p):return None + return {('backward' if 'True' in l else 'forward'):int(l.split()[2]) for l in open(p) if l.startswith('PREFIX')} +def stage(d): + log=open(f'{OUT}/{d}.log').read() if os.path.exists(f'{OUT}/{d}.log') else '' + passed=[l.split()[1] for l in log.splitlines() if l.startswith('PASS ')] + fail=None + for name in ('native','ledgers','local-replay','wrappers'): + lp=f'{OUT}/{d}/{name}.log' + if os.path.exists(lp) and name not in passed: + fail=(name,[l for l in open(lp).read().splitlines() if 'Error' in l][-1:]);break + return passed,fail +H0,P0,R0=prof('base');res={'baseline':dict(R=R0,pairing=P0,profile=dict(H0),bits=bits('base'),kappa=price({},tag='base'))} +for d in ('v1-yy-entering','v2-two-kept','v3-fresh-all16','v3-fresh-4567','v3-fresh-one'): + if not os.path.exists(f'{OUT}/{d}/cold44/FULL-WORD.json.gz'):res[d]=dict(status='no cold44 word',stage=stage(d));continue + H,Pr,R=prof(d);dd=Counter(H);dd.subtract(H0);dd={k:v for k,v in sorted(dd.items()) if v} + res[d]=dict(R=R,helpers_removed=R0-R,pairing=Pr,delta_per_call=dd,bits=bits(d),stage=stage(d),kappa_ideal_packing=price(dd,tag=d)) +json.dump(res,open(f'{OUT}/RESULTS.json','w'),indent=1);print(json.dumps(res,indent=1)) diff --git a/research/leaver-partial-cells/code/copyelim.py b/research/leaver-partial-cells/code/copyelim.py new file mode 100644 index 0000000000..50d3026f96 --- /dev/null +++ b/research/leaver-partial-cells/code/copyelim.py @@ -0,0 +1,99 @@ +import pickle,json,sys,math +from collections import Counter,defaultdict +from fractions import Fraction as Q +sys.path.insert(0,sys.path[0]) +from rawframes import basis,inside,hyper,FULL +v=120 +def replay(W,P,nreg,check=True): + used=set() + for e in W: + used.add(e[1]) + if e[0]=='add':used.add(e[2]) + cur=[(p,) for p in P]+[()]*(nreg-len(P));H=Counter();bad=[] + for k,e in enumerate(W): + regs=(e[1],e[2]) if e[0]=='add' else (e[1],) + G=basis(list(e[-1])+[x for r in regs for x in cur[r]]) + for r in regs: + if v<=r<2*v and not inside(G,hyper(P[r-v])):bad.append((k,r)); + dr=len(G)-len(cur[r]) + if dr:H[dr]+=1 + cur[r]=G + for r in range(nreg): + if r>=2*v and r not in used:continue + T=hyper(P[r-v]) if v<=r<2*v else FULL + if not inside(cur[r],T):bad.append(('final',r));continue + dr=len(T)-len(cur[r]) + if dr:H[dr]+=1 + return H,bad +def rows_of(W,nreg): + rows=[{r:Q(1)} if r=2*v and first[e[1]]==k and Q(e[3],e[4])==1:out.append((e[1],e[2],k)) + return out +def try_elim(W,h,a,kc): + """remove copy event kc (h+=a); redirect reads of h to a, moving each read to just after kc if a is written + between kc and the read. Readers must be Y targets (commutative adds) and h must have no other writes.""" + ev=[(k,e) for k,e in enumerate(W) if k!=kc and (e[1]==h or (e[0]=='add' and e[2]==h))] + if any(e[1]==h for k,e in ev):return None,'h written' + if any(not (v<=e[1]<2*v) for k,e in ev):return None,'non-Y reader' + wa=[k for k,e in enumerate(W) if e[1]==a and k>kc] + moves={} + for k,e in ev: + nxt=min([x for x in wa],default=10**9) + if nxt=2*v and r not in atoms] + Mreg=d['Ms'][(c3,)+key][0] + return dict(lv=lv,c3=c3,atoms=atoms,targets=targets,copies=copies,M=Mreg,face=face) +def first_write_after(W,r,k0): + return next((k for k in range(k0+1,len(W)) if W[k][1]==r),None) +def segment(d,W,K): + """events to delete: face events in lv blocks, copy events, target reads of atoms/copies (own rows incl.), M event.""" + A=set(K['atoms']);C=set(K['copies']);T=set(v+t for t in K['targets']) + dele=[] + for k,e in enumerate(W): + if e[0]!='add':continue + t,s=e[1],e[2] + if t in C and s in A:dele.append(k) # copy + elif t in T and (s in A or s in C):dele.append(k) # target reads (own rows, faces, copies) + elif t in A and s in A and t!=K['atoms'][4] :dele.append(k) # face events in leaver blocks, M event + elif t==K['M'] and t in C and s in C:dele.append(k) # M formed inside a copy (4567 class) + return dele +def symbolic(W,K,dele,nreg): + """values of atoms at the first deleted event; contributions to targets; M value; check deleted set is closed.""" + k0=dele[0] + # atom registers must not be written between k0 and their last deleted use, except by deleted events + sym={} + for i,r in enumerate(K['atoms']):sym[r]={i:Q(1)} + for r in K['copies']:sym[r]={} + for t in K['targets']:sym[v+t]={} + for k in dele: + e=W[k];t,s,q=e[1],e[2],Q(e[3],e[4]) + for j,x in sym.get(s,{}).items(): + sym[t][j]=sym[t].get(j,Q(0))+q*x + if not sym[t][j]:del sym[t][j] + # writes to atoms by non-deleted events between k0 and their last deleted use? + last=max(dele);bad=[] + for k in range(k0,last+1): + if k in set(dele):continue + e=W[k] + if e[1] in K['atoms'] or (e[1] in K['copies'] and e[1]!=K['M']) or (e[1]==K['M'] and k>max(dele)) or (v+0<=e[1]<2*v and e[1]-v in K['targets'] and e[0]=='add' and e[2] in sym):bad.append(k) + if e[0]=='add' and (e[2] in K['copies']) and e[2]!=K['M']:bad.append(('copyread',k)) + return sym,bad +def frames_at(W,P,nreg,k0): + cur=[(p,) for p in P]+[()]*(nreg-len(P)) + for e in W[:k0]: + regs=(e[1],e[2]) if e[0]=='add' else (e[1],) + G=basis(list(e[-1])+[x for r in regs for x in cur[r]]) + for r in regs:cur[r]=G + return cur +def search(K,sym,cur0,P,maxdepth=18,maxstates=3_000_000,Mreg=None): + atoms=K['atoms'];na=len(atoms) + Ys=[v+t for t in K['targets']] + goal={y:frozenset(sym[y]) for y in Ys} + coefY={y:set(sym[y].values()) for y in Ys} + Mgoal=frozenset(sym[K['M']]);Mreg=K['M'] if Mreg is None else Mreg + regs=atoms+Ys;idx={r:i for i,r in enumerate(regs)} + hy={y:hyper(P[y-v]) for y in Ys} + S0=tuple(frozenset([i]) for i in range(na))+tuple(frozenset() for _ in Ys) + F0=tuple(cur0[r] for r in regs) + from collections import deque + start=(S0,F0);seen={start:None};q=deque([(start,0)]);sol=[] + while q: + (S,F),dep=q.popleft() + if all(S[idx[y]]==goal[y] for y in Ys) and S[idx[Mreg]]==Mgoal: + sol.append((S,F)); + if len(sol)>=200:break + continue + if dep>=maxdepth or len(seen)>maxstates:continue + for ti,t in enumerate(regs): + for si,s in enumerate(regs[:na]): + if ti==si:continue + a,b=S[ti],S[si] + if not b or a&b:continue + if t in Ys: + if not (b<=goal[t]-a):continue + G=basis(list(F[ti])+list(F[si])) + if not inside(G,hy[t]):continue + else: + G=basis(list(F[ti])+list(F[si])) + NS=list(S);NS[ti]=a|b;NF=list(F);NF[ti]=G;NF[si]=G + st=(tuple(NS),tuple(NF)) + if st in seen:continue + seen[st]=((S,F),(t,s)) + q.append((st,dep+1)) + def path(st): + out=[] + while seen[st] is not None: + prev,g=seen[st];out.append(g);st=prev + return out[::-1] + return [path(s) for s in sol],len(seen) +def taint_of(F,Ys,P): + m=0 + for i,y in enumerate(Ys): + if not inside(F,hyper(P[y-v])):m|=1<best+extra:break + S,T=st + if all(S[na+i]==goal[na+i] for i in range(ny)) and any(S[h]==Mgoal for h in Mhosts): + if best is None:best=dep + goals.append(st);continue + if dep>=maxdepth:continue + for ti in range(nr): + for si in range(nr): + if ti==si:continue + a,b=S[ti],S[si] + if not b or a&b:continue + isy_t=ti>=na;isy_s=si>=na + if isy_s and not (isy_t and yy):continue + if isy_t and not (b<=goal[ti]-a):continue + J=T[ti]|T[si] + if J&(forb[ti]|forb[si]):continue + NS=list(S);NS[ti]=a|b;NT=list(T);NT[ti]=J;NT[si]=J + ns=(tuple(NS),tuple(NT)) + if ns not in dist: + dist[ns]=dep+1;q.append(ns) + if dist[ns]==dep+1:par[ns].append((st,(regs[ti],regs[si]))) + return best,goals,par,dist,len(dist) +def paths(goal,par,limit=2000): + out=[] + def rec(st,acc): + if len(out)>=limit:return + if not par.get(st):out.append(acc[::-1]);return + for prev,g in par[st]:rec(prev,acc+[g]) + rec(goal,[]);return out +YYLOG=[] +def coeffs(K,sym): + """rank-one factorisation C[y][j]=r_y*c_j over atoms; M = mu * c.""" + Ys=[v+t for t in K['targets']];na=len(K['atoms']) + c=[None]*na + # pick c from first target that has each atom + y0=Ys[0];r={y0:Q(1)} + for j,x in sym[y0].items():c[j]=x + changed=True + while changed: + changed=False + for y in Ys: + if y not in r: + j=next((j for j in sym[y] if c[j] is not None),None) + if j is not None:r[y]=sym[y][j]/c[j];changed=True + if y in r: + for j,x in sym[y].items(): + if c[j] is None:c[j]=x/r[y];changed=True + for y in Ys: + for j,x in sym[y].items():assert x==r[y]*c[j],('not rank one',y,j) + Mv=sym[K['M']];j0=next(iter(Mv));mu=Mv[j0]/c[j0] + assert all(Mv[j]==mu*c[j] for j in Mv),'M not proportional' + return r,c,mu +def build(W,K,sym,dele,sol,host,newh=(),halpha=None): + """sol: list of (treg,sreg) register ids. returns new W.""" + atoms=K['atoms'];Ys=[v+t for t in K['targets']] + r,c,mu=coeffs(K,sym) + # atom register value = alpha_reg * sum_{j in set} c_j x_j ; initially alpha = 1/c_own + alpha={a:1/c[i] for i,a in enumerate(atoms)} + for h in newh:alpha[h]=None + if halpha:alpha.update(halpha) + gates=[] + for t,s in sol: + if t in Ys and s in Ys:q=r[t]/r[s];YYLOG.append((t,s,str(q))) + elif t in Ys:q=r[t]/alpha[s] + else: + if alpha[t] is None:alpha[t]=alpha[s] + q=alpha[t]/alpha[s] + gates.append(['add',t,s,q.numerator,q.denominator,[]]) + # host ends with alpha_host*sum c_j x_j ; M register must hold mu*sum c_j x_j + fix=mu/alpha[host] + if fix!=1:gates.append(['scale',host,fix.numerator,fix.denominator,[]]) + last=dele[-1];M=K['M'] + ownregs={v+t:K['own'][t] for t in K['targets']} if 'own' in K else {} + isown=lambda e:e[0]=='add' and e[1] in ownregs and e[2]==ownregs[e[1]] + import os as _os + if ownregs and _os.environ.get('PCELL_MOVEOWN'): + k0=next(k for k in dele if not isown(W[k])) + elif ownregs: + dele=[k for k in dele if not isown(W[k])] + gates=[g for g in gates if not isown(g)] + k0=dele[0] + else:k0=dele[0] + ds=set(dele) + NW=[] + for k,e in enumerate(W): + if k==k0:NW.extend(gates) + if k in ds:continue + if k>k0 and host!=M: + e=list(e) + if e[1]==M:e[1]=host + if e[0]=='add' and e[2]==M:e[2]=host + NW.append(e) + return NW +def check(W,NW,K,host,n,P,H0): + R0=rows_of(W,n);R=rows_of(NW,n);n0=len(R0) + M=K['M'];bad=[] + R0=R0+[{}]*(len(R)-len(R0)) + for x in range(len(R)): + if x in K['atoms'] or x in K['copies'] or x>=n0:continue + if R[x]!=R0[x]:bad.append(x) + if R[host]!=R0[M]:bad.append(('host',host)) + H,fb=replay(NW,P,n) + dH=Counter(H);dH.subtract(H0);dH={a:b for a,b in dH.items() if b} + return bad,fb,dH diff --git a/research/leaver-partial-cells/code/pipeline.py b/research/leaver-partial-cells/code/pipeline.py new file mode 100644 index 0000000000..0675a0397e --- /dev/null +++ b/research/leaver-partial-cells/code/pipeline.py @@ -0,0 +1,61 @@ +import sys,time,pickle,json;sys.path.insert(0,__import__('os').path.dirname(__import__('os').path.abspath(__file__))) +from pcell import * +from satcell import solve +def frames_after(W,P,n,k1): + return frames_at(W,P,n,k1+1) +def run_key(d,P,W,n,H0,key,L=20,tl=600,log=print,nh=0): + K=key_parts(d,W,key);dele=segment(d,W,K);sym,bad=symbolic(W,K,dele,n) + if bad:return dict(key=key,status='window writes %s'%bad[:3]) + atoms=K['atoms'];Ys=[v+t for t in K['targets']];regs=atoms+Ys;na=len(atoms);ny=len(Ys) + try:r,c,mu=coeffs(K,sym) + except AssertionError as e:return dict(key=key,status='coeff %s'%e) + cur0=frames_at(W,P,n,dele[0]);curE=frames_at(W,P,n,dele[-1]+1) + # extra bits: equivalence classes of all target hyperplanes on the 9 initial frames + allY=[y for y in range(v,2*v)] + pat={} + for y in allY: + hp=hyper(P[y-v]);key2=tuple(0 if inside(cur0[x],hp) else 1 for x in regs) + if any(key2):pat.setdefault(key2,[]).append(y) + classes=[ys for k2,ys in pat.items()] + # own bits first (one per circuit target), then other classes + own=[[y] for y in Ys];others=[ys for ys in classes if not any(y in Ys for y in ys)] + # keep only classes whose allowance can bind (some final allowance excludes them) + def okF(F,ys):return all(inside(F,hyper(P[y-v])) for y in ys) + keep=[ys for ys in others if okF(curE[K['M']],ys) or any(okF(curE[Y],ys) for Y in Ys)] + bits=own+keep;nb=len(bits) + def tmask(F): + m=0 + for b,ys in enumerate(bits): + if any(not inside(F,hyper(P[y-v])) for y in ys):m|=1< host candidates + last=dele[-1];later={x for e in W[last+1:] for x in ((e[1],e[2]) if e[0]=='add' else (e[1],))} + hosts=[i for i,a in enumerate(atoms) if a==K['M'] or a not in later] + hostallow=tmask(curE[K['M']]) + Yallow=[tmask(curE[y]) for y in Ys] + gm=lambda s:sum(1<=224 else ())) for r in range(nreg)} + lev={int(t):basis(E) for t,E in PW.get('target_levels',{}).items()} + for e in PW['A']: + for r in ([e[1]]+([e[2]] if e[0]=='add' else [])):cur[r]=basis(e[-1]) + for t in range(112):cur[112+t]=lev.get(t,()) + for e in PW['B'][:upto]: + if e[0]=='add' and (e[1],e[2]) in skip:continue + for r in ([e[1]]+([e[2]] if e[0]=='add' else [])):cur[r]=basis(e[-1]) + return cur +def setup(d,W,n,PW,key): + K=key_parts(d,W,key);dele=segment(d,W,K);sym,bad=symbolic(W,K,dele,n);assert not bad + own={t:d['own_rows'][t][0] for t in K['targets']} + atoms=K['atoms'];Ys=[v+t for t in K['targets']] + zc=zcopy(W,K);z=atoms[4] + ownset={(v+t,own[t]) for t in K['targets']} + k0=next(k for k in dele if not (W[k][0]=='add' and (W[k][1],W[k][2]) in ownset)) + g0=W[k0];kz=next(i for i,e in enumerate(PW['B']) if e[0]=='add' and e[1]==restr(g0[1]) and e[2]==restr(g0[2]) and e[3]==g0[3] and e[4]==g0[4]) + # end of segment in ported word: last gate touching any atom/target/copy among deleted ones -> approximate by last read of copies/targets + imgs={(restr(W[k][1]),restr(W[k][2]),W[k][3],W[k][4]) for k in dele if W[k][0]=='add'} + kend=max(i for i,e in enumerate(PW['B']) if e[0]=='add' and (e[1],e[2],e[3],e[4]) in imgs) + import os + skip={(restr(v+t),restr(own[t])) for t in K['targets']} if os.environ.get('PCELL_MOVEOWN') else set() + c0=ported_state(PW,kz,skip);cE=ported_state(PW,kend+1) + Pp=PW['ports'] + hyp=lambda t:perpP(Pp[t]) + return K,dele,sym,own,c0,cE,kz,kend +_pc={} +def perpP(p): + if p not in _pc:_pc[p]=basis([x for x in range(1,512) if (x&p).bit_count()%2==0]) + return _pc[p] +def solve_key(d,W,n,PW,key,nh=1,L=20,tl=600,maxh=1): + K,dele,sym,own,c0,cE,kz,kend=setup(d,W,n,PW,key) + atoms=K['atoms'];Ys=[v+t for t in K['targets']];na=5;ny=4 + Pp=PW['ports'] + regsR=[restr(x) for x in atoms]+[restr(y) for y in Ys] + allT=list(range(112)) + pat={} + for t in allT: + hp=perpP(Pp[t]);k2=tuple(0 if inside(c0[x],hp) else 1 for x in regsR) + pat.setdefault(k2,[]).append(t) + ownT=[y-v-8 for y in Ys] + okF=lambda F,ts:all(inside(F,perpP(Pp[t])) for t in ts) + others=[ts for k2,ts in pat.items() if any(k2) and not any(t in ownT for t in ts)] + keep=[ts for ts in others if okF(cE[restr(K['M'])],ts) or any(okF(cE[restr(y)],ts) for y in Ys)] + bits=[[t] for t in ownT]+keep + tm=lambda F:sum(1<1 else []) + zreaders=[K['targets'].index(t) for t in K['targets'] if any(e[0]=='add' and e[1]==v+t and e[2]==zc for e in W)] + # role order y0..y3 = targets ordered by own atom a1,a0,a3,a2 + want=[atoms[1],atoms[0],atoms[3],atoms[2]];order=[next(t for t in K['targets'] if own[t]==w) for w in want] + Ys=[v+t for t in order];regsR=[restr(x) for x in atoms]+[restr(y) for y in Ys];ownT=[t-8 for t in order] + hroles={} + for hi,hr in enumerate(hregs): + hroles[hi]=[order.index(t) for t in K['targets'] if any(e[0]=='add' and e[1]==v+t and e[2]==hr for e in W)] + zroles=hroles[0] + bits=[[t] for t in ownT]+keep + T0=[tm(c0[x]) for x in regsR[:na]]+[tm(c0[restr(h)]) for h in hregs]+[tm(c0[x]) for x in regsR[na:]] + gm=lambda s:sum(1<3 else 1;st,sol,info=solve_key(d,W,n,PW,key,tl=float(sys.argv[2]),nh=nh,maxh=nh) + print(key,st,info);print('SOL',sol) diff --git a/research/leaver-partial-cells/code/prefix_trace.py b/research/leaver-partial-cells/code/prefix_trace.py new file mode 100644 index 0000000000..d3b8ca8743 --- /dev/null +++ b/research/leaver-partial-cells/code/prefix_trace.py @@ -0,0 +1,173 @@ +# Local-only extraction of the attributed PR514 / PR433 independent replay. +# Prepared for icekylinx with OpenAI Codex assistance. Apache-2.0. +# The complete local checker and its negative controls are retained verbatim. +# Global hosting is verified separately for the changed 112-port geometry. +TRACE=[] +import copy,gzip,hashlib,json,sys +from collections import Counter +from fractions import Fraction as Q +from pathlib import Path +OUT=Path(sys.argv[1]) +c=json.load(gzip.open(OUT/'CANONICAL-WORD.json.gz')) +ir={'local_programs':json.load(gzip.open(OUT/'LOCAL-PROGRAMS.json.gz'))} +v,R,h=c['v'],c['R'],c['h'];n=2*v+R;frames=c['frames'] +levels={int(t):f for t,f in c.get('target_levels',{}).items()} +entering=[r for r,f in enumerate(c['start']) if r>=2*v and f!=0] +plain={r for r in range(n) if r not in set(entering)} + +def contains(a,b): + for x in a: + for y in b: + if x>>(y.bit_length()-1)&1:x^=y + if x:return False + return True +hpe={r for r in range(2*v,n) if c['final'][r]!=1} # HPE: helpers whose terminal frame is a proper subspace U of FULL +assert all(len(frames[c['final'][r]])0 + hist[rank]+=1;cur[r]=b + elif tag=='center': + _,k,a,b,rank=event + assert phases[-1]=='centers' and private=={('C',k):a} + cf=c['center_frames'][k];cr=len(frames[cf]) + # GK: stepwise descent cf -> served levels -> lowest (forward), reversed ascent (backward); each step is a nested child + assert contains(frames[a],frames[b]) if back else contains(frames[b],frames[a]) + assert rank==abs(len(frames[a])-len(frames[b]))>0 + chain.setdefault(k,[]).append((a,b)) + private['C',k]=b;hist[rank]+=1;centers.append(k) + elif tag=='scalar': + _,e,f=event;op=e[0];target=tuple(e[1]);source=tuple(e[2]) if op in ('copy','add') else None + if target[0]=='C' and op=='clear': + assert private.get(target,f)==f + private.pop(target,None) + else: + for r in (target,source): + if r is None:continue + if r[0]=='L':assert cur[r[1]]==f and (r[1] not in wset or (r[1] in pre_seen and r[1] not in post_seen)),('common frame / wrapper order',r,cur[r[1]],f) + else: + if r==target and r not in private:private[r]=f + assert private[r]==f + if op=='clear':rows[target]={};norm[target]=Q(0) + elif op=='copy':rows[target]=dict(rows[source]);norm[target]=norm[source] + elif op=='scale': + q=Q(e[2],e[3]);a,b=abs(q.numerator),q.denominator + assert a&(a-1)==0 and b&(b-1)==0 + rows[target]={j:q*x for j,x in rows[target].items()};norm[target]*=abs(q) + else: + q=Q(e[3],e[4]);a,b=abs(q.numerator),q.denominator + assert source!=target and b&(b-1)==0 + # Independent symbolic replay of the cleared coefficient work. + w=0 + for bit in bin(a)[2:]:w=2*w+int(bit) + assert Q(w,b)*(1 if q>0 else -1)==q + prefix=max(prefix,Q(a)*norm[source]) + norm[target]=norm.get(target,Q(0))+abs(q)*norm[source] + row=rows.setdefault(target,{}) + for j,x in list(rows[source].items()): + z=row.get(j,Q(0))+q*x + if z:row[j]=z + else:row.pop(j,None) + if norm[target]>prefix:TRACE.append((len(TRACE),phases[-1] if phases else None,target,source,op,norm[target].numerator.bit_length()-norm[target].denominator.bit_length())) + prefix=max(prefix,norm[target]) + else:raise AssertionError(tag) + assert phases==allowed and set(centers)==set(range(len(c['centers']))) and not private + assert sorted(r for k,r,_ in wrappers if k=='pre')==wrapped and sorted(r for k,r,_ in wrappers if k=='post')==wrapped # GK + for k,st in chain.items(): # GK: the steps of each centre chain link up and end at the centre frame + cf=c['center_frames'][k] + if back:assert st[-1][1]==cf and all(st[i][1]==st[i+1][0] for i in range(len(st)-1)) + else:assert st[0][0]==cf and all(st[i][1]==st[i+1][0] for i in range(len(st)-1)) + assert all(not row for reg,row in rows.items() if reg[0]=='C') + for r in range(n): + expected={r:Q(1)} + if back and r>p&1:x^=b[p] + if x: + p=x.bit_length()-1 + for q in b: + if b[q]>>p&1:b[q]^=x + b[p]=x + return tuple(b[p] for p in sorted(b,reverse=True)) +def inside(a,b):return basis(list(a)+list(b))==b +_hc={} +def hyper(p): + if p not in _hc:_hc[p]=basis([x for x in range(1,512) if (x&p).bit_count()%2==0]) + return _hc[p] +FULL=basis([1<>j)&1) if (S0Y is not None and r>=na_regs) else 0))) + for i in range(ny):m.Add(T[0][r][i]==((T0[r]>>i)&1)) + act=[m.NewBoolVar('') for k in range(L)] + selt=[[m.NewBoolVar('') for r in range(nr)] for k in range(L)] + sels=[[m.NewBoolVar('') for r in range(nr)] for k in range(L)] + nyy=[] + for k in range(L): + m.Add(sum(selt[k])==act[k]);m.Add(sum(sels[k])==act[k]) + if k:m.AddImplication(act[k],act[k-1]) + for r in range(nr):m.AddBoolOr([selt[k][r].Not(),sels[k][r].Not()]) + ysrc=m.NewBoolVar('');m.Add(sum(sels[k][na_regs:])==ysrc) + m.Add(sum(selt[k][na_regs:])>=ysrc);nyy.append(ysrc) + if not yy:m.Add(ysrc==0) + A=[m.NewBoolVar('') for j in range(na)];Bt=[m.NewBoolVar('') for j in range(na)] + Ts=[m.NewBoolVar('') for i in range(ny)];Tt=[m.NewBoolVar('') for i in range(ny)] + for r in range(nr): + for j in range(na): + m.Add(A[j]==S[k][r][j]).OnlyEnforceIf(sels[k][r]) + m.Add(Bt[j]==S[k][r][j]).OnlyEnforceIf(selt[k][r]) + for i in range(ny): + m.Add(Ts[i]==T[k][r][i]).OnlyEnforceIf(sels[k][r]) + m.Add(Tt[i]==T[k][r][i]).OnlyEnforceIf(selt[k][r]) + for j in range(na): + m.Add(A[j]==0).OnlyEnforceIf(act[k].Not());m.Add(Bt[j]==0).OnlyEnforceIf(act[k].Not());m.Add(A[j]+Bt[j]<=1) + for i in range(ny): + m.Add(Ts[i]==0).OnlyEnforceIf(act[k].Not());m.Add(Tt[i]==0).OnlyEnforceIf(act[k].Not()) + m.Add(sum(A)>=1).OnlyEnforceIf(act[k]) + J=[m.NewBoolVar('') for i in range(ny)] + for i in range(ny): + m.AddMaxEquality(J[i],[Ts[i],Tt[i]]) + if i=S[k][r][j]) + m.Add(S[k+1][r][j]<=S[k][r][j]+A[j]) + m.Add(S[k+1][r][j]<=S[k][r][j]).OnlyEnforceIf(selt[k][r].Not()) + m.Add(S[k+1][r][j]>=A[j]).OnlyEnforceIf(selt[k][r]) + inv=m.NewBoolVar('');m.AddMaxEquality(inv,[selt[k][r],sels[k][r]]) + for i in range(ny): + m.Add(T[k+1][r][i]==J[i]).OnlyEnforceIf(inv) + m.Add(T[k+1][r][i]==T[k][r][i]).OnlyEnforceIf(inv.Not()) + for i in range(NY): + for j in range(na):m.Add(S[L][na_regs+i][j]==((goalY[i]>>j)&1)) + if Yallow is not None: + for b in range(ny): + if not (Yallow[i]>>b)&1:m.Add(T[L][na_regs+i][b]==0) + hv=[m.NewBoolVar('') for h in Mhosts] + for b,h in zip(hv,Mhosts): + for j in range(na):m.Add(S[L][h][j]==((Mgoal>>j)&1)).OnlyEnforceIf(b) + if hostallow is not None: + for i in range(ny): + if not (hostallow>>i)&1:m.Add(T[L][h][i]==0).OnlyEnforceIf(b) + m.AddBoolOr(hv) + if maxyy is not None:m.Add(sum(nyy)<=maxyy) + for sol in forbid_solutions: + lits=[] + for k,(t,s) in enumerate(sol):lits+=[selt[k][t].Not(),sels[k][s].Not()] + m.AddBoolOr(lits) + for k,(t,s) in enumerate(fixed_prefix):m.Add(selt[k][t]==1);m.Add(sels[k][s]==1) + hu=[] + for h in range(na,na_regs): + u=m.NewBoolVar('');m.AddMaxEquality(u,[selt[k][h] for k in range(L)]+[sels[k][h] for k in range(L)]);hu.append(u) + if maxh is not None:m.Add(sum(hu)<=maxh) + if hreads is not None: + # hreads: {helper_index_offset: [allowed target indices]} -> helper read exactly once by each allowed target, nothing else + for ho,allowed in hreads.items(): + h=na+ho + for i in allowed: + bs=[] + for k in range(L): + b=m.NewBoolVar('');m.AddBoolAnd([sels[k][h],selt[k][na_regs+i]]).OnlyEnforceIf(b) + m.AddBoolOr([sels[k][h].Not(),selt[k][na_regs+i].Not()]).OnlyEnforceIf(b.Not());bs.append(b) + m.Add(sum(bs)==1) + for k in range(L): + for r in range(nr): + if r>=na_regs and (r-na_regs) in allowed:continue + m.AddBoolOr([sels[k][h].Not(),selt[k][r].Not()]) + if hint: + for k in range(L): + on=k1: + keys=[((0,2),-1),((0,2),1),((0,3),-1),((0,3),1),((1,2),-1),((1,2),1),((1,3),-1),((1,3),1)] + if sys.argv[1]=='all':keys+=[((4,6),-1),((4,6),1),((4,7),-1),((4,7),1),((5,6),-1),((5,6),1),((5,7),-1),((5,7),1)] + W2,br,fb,dH,rm=joint(W,d,P,n,keys,TPL) + print('JOINT rows',br[:5],'frames',fb[:5],'dH',sorted(dH.items()),'removed',len(rm)) + pickle.dump(dict(W=W2,rm=sorted(rm)),open(__import__('os').environ.get('PC_OUT','.')+'/joint.pkl','wb')) + +def apply_key2(W,d,n,key): + """two-helper templates: class by third block; kept helpers = z copy (h0) and the copy read by role R (h1).""" + global OWN;OWN=d['own_rows'] + K=key_parts(d,W,key);dele=segment(d,W,K);sym,bad=symbolic(W,K,dele,n) + if bad:return None,'window %s'%bad[:2],K,None + K['own']={t:OWN[t][0] for t in K['targets']} + a=K['atoms'];own=K['own'] + want=[a[1],a[0],a[3],a[2]];order=[next(t for t in K['targets'] if own[t]==w) for w in want] + y=[v+t for t in order] + zc=zcopy(W,K) + zr={i for i in range(4) if any(e[0]=='add' and e[1]==y[i] and e[2]==zc for e in W)} + SIG={'a0':'a1','a1':'a0','a2':'a3','a3':'a2','y0':'y1','y1':'y0','y2':'y3','y3':'y2','a4':'a4','h0':'h0','h1':'h1'} + base={(0,3):(TPLA,2),(1,2):(TPLB,0)} + if K['c3']==(0,1,2,3):tpl,role,zb=TPLA,2,{0,3} + else:tpl,role,zb=TPLB,0,{1,2} + if zr!=zb: + assert zr=={ {0:1,1:0,2:3,3:2}[i] for i in zb},(key,zr) + tpl=[(SIG[t],SIG[s_]) for t,s_ in tpl];role={0:1,1:0,2:3,3:2}[role] + h1=next(c for c in K['copies'] if c!=zc and any(e[0]=='add' and e[1]==y[role] and e[2]==c for e in W)) + nm={'a%d'%i:a[i] for i in range(5)};nm.update({'y%d'%i:y[i] for i in range(4)});nm['h0']=zc;nm['h1']=h1 + sol=[(nm[t],nm[s]) for t,s in tpl] + # host = atom whose final set is M + sets={r:{i} for i,r in enumerate(a)};sets.update({zc:set(),h1:set()});sets.update({r:set() for r in y}) + for t,s_ in sol:sets[t]=sets[t]|sets[s_] + host=next(r for r in a if sets[r]==set(sym[K['M']])) + r_,c_,mu=coeffs(K,sym);alpha={x:1/c_[i] for i,x in enumerate(a)} + src=lambda h:next(e[2] for e in W if e[0]=='add' and e[1]==h and e[2] in a) + halpha={zc:alpha[src(zc)],h1:alpha[src(h1)]} + NW=build(W,K,sym,dele,sol,host,newh=[zc,h1],halpha=halpha) + return NW,'ok',K,dict(host=host,kept=[zc,h1],removed=sorted(set(K['copies'])-{zc,h1})) + +def apply_key3(W,d,n,key,newreg): + """TPL2 (one helper, no Y+=Y, own rows inside) with a FRESH helper register newreg (no entrance).""" + global OWN;OWN=d['own_rows'] + K=key_parts(d,W,key);dele=segment(d,W,K);sym,bad=symbolic(W,K,dele,n) + if bad:return None,'window %s'%bad[:2],K,None + K['own']={t:OWN[t][0] for t in K['targets']} + a=K['atoms'];own=K['own'] + want=[a[1],a[0],a[3],a[2]];order=[next(t for t in K['targets'] if own[t]==w) for w in want] + y=[v+t for t in order] + nm={'a%d'%i:a[i] for i in range(5)};nm.update({'y%d'%i:y[i] for i in range(4)});nm['h']=newreg + sol=[(nm[t],nm[s_]) for t,s_ in TPL2] + sets={r:{i} for i,r in enumerate(a)};sets[newreg]=set();sets.update({r:set() for r in y}) + for t,s_ in sol:sets[t]=sets[t]|sets[s_] + host=next(r for r in a if sets[r]==set(sym[K['M']])) + NW=build(W,K,sym,dele,sol,host,newh=[newreg]) + return NW,'ok',K,dict(host=host,removed=sorted(K['copies'])) diff --git a/research/leaver-partial-cells/patches/cgx_census.patch b/research/leaver-partial-cells/patches/cgx_census.patch new file mode 100644 index 0000000000..a1fd418e7d --- /dev/null +++ b/research/leaver-partial-cells/patches/cgx_census.patch @@ -0,0 +1,19 @@ +--- leaver/cgx_leaver.py 2026-10-13 18:36:24 ++++ leaver/cgx_leaver.py 2026-10-13 18:37:42 +@@ -436,7 +436,16 @@ + for r in range(len(cur)):climb(r,hyper(P[r-v]) if v<=r<2*v else FULL) + H[8]+=8;H[1]+=8 + assert sum(r*z for r,z in H.items())==9*NH+240*8+72,sum(r*z for r,z in H.items()) ++ + ++import pickle as _pk ++_face={} ++for _c,_z in sorted(blocks.items()): ++ for _p in it.combinations(_c,2): ++ for _e in (-1,1): ++ _j,_al=face_info(_c,_p,_e);_ev=_z['events'][_j] ++ _face[(_c,_p,_e)]=dict(j=_j,t=maps[_c][_ev[0]],s=maps[_c][_ev[1]],a=_ev[2],b=_ev[3],F=_z['event_frames'][_j],early=(_j-40) in early[_c]) ++_pk.dump(dict(maps=maps,face=_face,packets=packets,Ms=Ms,slots={str(k):v for k,v in slots.items()},requests=dict(requests),FULLT=FULLT,A=A,B=B,pairs=pairs,own_rows=own_rows,block_totals=block_totals,centers=centers,NH=NH),open(str(OUT)+'/CENSUS.pkl','wb')) + def apply(e,matrix): + if e[0]=='add': + _,t,s,a,b,*_=e;q=Q(a,b) diff --git a/research/leaver-partial-cells/patches/cgx_leaver.patch b/research/leaver-partial-cells/patches/cgx_leaver.patch new file mode 100644 index 0000000000..5686a75b4a --- /dev/null +++ b/research/leaver-partial-cells/patches/cgx_leaver.patch @@ -0,0 +1,59 @@ +--- leaver/cgx_leaver.py 2026-10-13 18:36:24 ++++ leaver/cgx_leaver.py 2026-10-13 22:02:33 +@@ -422,6 +422,56 @@ + expected={s:-Q(G[t][s],2) for s in range(v) if s!=t and G[t][s] and s not in frame.values()} if t not in frame.values() else {} + assert rows[v+t]==expected,('side identity',t) + ++# --- partial leaver cells (higherbeing, experimental): helper-free-but-one circuits on 16 two-leaver keys --- ++if os.environ.get('PCELLS'): ++ sys.path.insert(0,os.environ['PCELL_TOOLS']) ++ import pcell as _pc, template as _tp ++ _keys=[tuple((tuple(k[0]),k[1])) for k in json.load(open(os.environ['PCELLS']))['keys']] ++ _face={} ++ for _c,_z in sorted(blocks.items()): ++ for _p in it.combinations(_c,2): ++ for _e in (-1,1): ++ _j,_al=face_info(_c,_p,_e);_ev=_z['events'][_j] ++ _face[(_c,_p,_e)]=dict(j=_j,t=maps[_c][_ev[0]],s=maps[_c][_ev[1]],a=_ev[2],b=_ev[3],F=_z['event_frames'][_j]) ++ _d=dict(face=_face,packets=packets,Ms=Ms,requests=dict(requests),own_rows=own_rows,FULLT=FULLT) ++ _W=[list(e) for e in A+B];_nA=len(A);_rm=set();_pc.YYLOG.clear() ++ for _key in _keys: ++ if os.environ.get('PCELL_V3'): ++ _nr=len(cur);cur.append(());rows.append({});shadow.append(None) ++ _NW,_st,_K,_info=_tp.apply_key3(_W,_d,len(cur),_key,_nr);assert _NW is not None,(_key,_st);_W=_NW;_rm|=set(_info['removed']) ++ continue ++ if os.environ.get('PCELL_V2'): ++ _NW,_st,_K,_info=_tp.apply_key2(_W,_d,len(cur),_key);assert _NW is not None,(_key,_st);_W=_NW;_rm|=set(_info['removed']) ++ continue ++ _K=_pc.key_parts(_d,_W,_key) ++ _rm|=set(_K['copies'])-{_tp.zcopy(_W,_K)} ++ _NW,_st,_K=_tp.apply_key(_W,_d,None,len(cur),_key,_tp.TPL);assert _NW is not None,(_key,_st);_W=_NW ++ assert _W[:_nA]==[list(e) for e in A],'pcells touch phase A' ++ coded_target_edges[:0]=[(t_,s_,Q(q_)) for t_,s_,q_ in _pc.YYLOG] ++ _used={x for e in _W for x in ((e[1],e[2]) if e[0]=='add' else (e[1],))} ++ assert not (_rm&_used),'removed helper still used' ++ _old=list(range(len(cur)));_keep=[r for r in _old if r not in _rm];_nm={r:i for i,r in enumerate(_keep)} ++ for e in _W: ++ e[1]=_nm[e[1]] ++ if e[0]=='add':e[2]=_nm[e[2]] ++ centers=[_nm[r] for r in centers] ++ coded_target_edges=[(_nm[t_],_nm[s_],q_) for t_,s_,q_ in coded_target_edges] ++ for r in sorted(_rm,reverse=True): ++ i=r-240;skipped.append(shadow[i]);del shadow[i];del cur[r];del rows[r] ++ NH=len(cur)-240 ++ # recompute monotone frames and the paid climbs over A+B ++ cur[:]=[(p,) for p in P]+[()]*(len(cur)-len(P));H=Counter() ++ for e in _W: ++ regs_=(e[1],e[2]) if e[0]=='add' else (e[1],) ++ G_=basis(list(e[-1])+[x for r in regs_ for x in cur[r]]) ++ for r in regs_: ++ if v<=r<2*v:assert inside(G_,hyper(P[r-v])),('pcell frame',r) ++ dr=len(G_)-len(cur[r]) ++ if dr:H[dr]+=1 ++ cur[r]=G_ ++ e[-1]=list(G_) ++ A[:]=_W[:_nA];B[:]=_W[_nA:] ++ print('PCELLS applied',len(_keys),'keys, removed helpers',len(_rm),flush=True) + scatter=[[Q(r[i],4) if t not in frame.values() else Q(0) for i in range(8)]+[Q(t==frame[i]) for i in range(8)] for t,r in enumerate(R)] + precondition=[] + for t,u,z in output_basis: diff --git a/research/leaver-partial-cells/patches/port_stage_x.patch b/research/leaver-partial-cells/patches/port_stage_x.patch new file mode 100644 index 0000000000..db26878627 --- /dev/null +++ b/research/leaver-partial-cells/patches/port_stage_x.patch @@ -0,0 +1,73 @@ +--- notri/port_stage_x.py 2026-10-13 18:36:24 ++++ notri/port_stage_x_rep.py 2026-10-13 21:07:01 +@@ -47,6 +47,8 @@ + + + def transfer_section(I4, O4, I8, stats): ++ import os ++ if os.environ.get('PORT_SUCC'): return transfer_section_succ(I4, O4, I8, stats) + a, b = align(I4, O4), align(I4, I8) + o2i = {j: i for i, j in a.items()}; i8from4 = {j: i for i, j in b.items()} + anchor = {j8: a[i4] for j8, i4 in i8from4.items() if i4 in a} +@@ -69,6 +71,33 @@ + return out + + ++def transfer_section_succ(I4, O4, I8, stats): ++ """as transfer_section, but each I8-only gate is placed just before the O4 image of its next matched I8 gate""" ++ a, b = align(I4, O4), align(I4, I8) ++ o2i = {j: i for i, j in a.items()}; i8from4 = {j: i for i, j in b.items()} ++ anchor = {j8: a[i4] for j8, i4 in i8from4.items() if i4 in a} ++ before, tail, buf = {}, [], [] ++ for j8, g in enumerate(I8): ++ if j8 in anchor: ++ if buf: before.setdefault(anchor[j8], []).extend(buf); buf = [] ++ elif j8 not in i8from4: buf.append(copy.deepcopy(g)); stats['kept_own'] += 1 ++ else: stats['dropped_by_stage'] += 1 ++ tail = buf ++ out = [] ++ for k, g in enumerate(O4): ++ out.extend(before.get(k, [])) ++ if k in o2i: ++ i4 = o2i[k] ++ if i4 in b: ++ g8 = copy.deepcopy(I8[b[i4]]) ++ if I4[i4][-1] != g[-1]: g8[-1] = copy.deepcopy(g[-1]); stats['frames_changed'] += 1 ++ out.append(g8) ++ else: ++ out.append(copy.deepcopy(g)); stats['introduced'] += 1 ++ out.extend(tail) ++ return out ++ ++ + def main(): + ap = argparse.ArgumentParser() + for k in ('--shadow-input', '--shadow-output', '--input', '--map', '--gk-dir', '--out'): ap.add_argument(k, type=Path, required=True) +@@ -109,6 +138,27 @@ + for k in O4: + if k not in ('A', 'B', 'cleanup', 'report', 'start_extra', 'target_levels', 'cut', 'precondition'): + assert O4r[k] == I4r[k], 'stage changed an unported field: ' + k ++ import os ++ if os.environ.get('PORT_REPAIR'): ++ Rr = O8['report']['R']; nreg = 2 * 112 + Rr; Pp = O8['ports'] ++ cur = {r: ((Pp[r],) if r < 112 else ((tuple(G.basis(O8['start_extra'][str(r)])) if str(r) in O8.get('start_extra', {}) else ()) if r >= 224 else ())) for r in range(nreg)} ++ lev = {int(t): tuple(G.basis(E)) for t, E in O8.get('target_levels', {}).items()} ++ nrep = 0; hv = [] ++ for sec in ('A', 'B'): ++ if sec == 'B': ++ for t in range(112): ++ if cur[112 + t] != lev.get(t, ()): hv.append(('level', t, cur[112 + t], lev.get(t, ()))) ++ cur[112 + t] = lev.get(t, ()) ++ for e in O8[sec]: ++ rr = [e[1]] + ([e[2]] if e[0] == 'add' else []) ++ F = tuple(G.basis(list(e[-1]) + [x for r in rr for x in cur[r]])) ++ if list(F) != list(e[-1]): ++ if os.environ.get('PORT_REPAIR_DBG') and nrep < 40: print('REP', sec, O8[sec].index(e), e[:5], 'stage', e[-1], '->', F, [(r, cur[r]) for r in rr], flush=True) ++ e[-1] = list(F); nrep += 1 ++ for r in rr: ++ cur[r] = F ++ if 112 <= r < 224 and G.basis(list(F) + list(G.perp(Pp[r - 112]))) != G.perp(Pp[r - 112]): hv.append(('hyper', sec, r, F)) ++ print('PORT_REPAIR frames repaired', nrep, 'violations', len(hv), hv[:5], flush=True) + O8['cleanup'] = [inverse(e) for e in reversed(O8['A'] + O8['B']) if not 112 <= e[1] < 224] + H = G.profile(O8) + ws = [9 - len(G.basis(O8['start_extra'].get(str(224 + h), []))) for h in range(R)] diff --git a/research/leaver-partial-cells/patches/reproduce_leaver.patch b/research/leaver-partial-cells/patches/reproduce_leaver.patch new file mode 100644 index 0000000000..5a3b8555e9 --- /dev/null +++ b/research/leaver-partial-cells/patches/reproduce_leaver.patch @@ -0,0 +1,11 @@ +--- leaver/reproduce_leaver.py 2026-10-13 18:36:24 ++++ leaver/reproduce_leaver.py 2026-10-13 20:08:59 +@@ -118,7 +118,7 @@ + wd / 'shadow-prefix/FULL-WORD.json.gz'] + for i, (b, c) in enumerate(zip(chain, chain[1:])): + t = out / ('port%d' % i) +- run('port%d' % i, NOTRI / 'port_stage_x.py', '--shadow-input', b, '--shadow-output', c, '--input', word, ++ run('port%d' % i, NOTRI / ('port_stage_x_rep.py' if os.environ.get('PORT_REPAIR') else 'port_stage_x.py'), '--shadow-input', b, '--shadow-output', c, '--input', word, + '--map', raw / 'HELPER-MAP.json', '--gk-dir', gk, '--out', t) + word = t / 'FULL-WORD.json.gz' + # 3. regroup diff --git a/research/leaver-partial-cells/reproduce.sh b/research/leaver-partial-cells/reproduce.sh new file mode 100644 index 0000000000..43c93defef --- /dev/null +++ b/research/leaver-partial-cells/reproduce.sh @@ -0,0 +1,44 @@ +#!/usr/bin/env bash +# Partial leaver cells on #1005's k8 word: rebuild the baseline and every variant, measure, price. +# usage: bash research/leaver-partial-cells/reproduce.sh +# Needs Python 3.11+ (assertions on). The optional circuit search (postport.py) also needs ortools. +set -euo pipefail +MAIN=$(cd "$1" && pwd); PR635=$(cd "$2" && pwd); mkdir -p "$3"; OUT=$(cd "$3" && pwd) +HERE=$(cd "$(dirname "$0")" && pwd); PY=${PYTHON:-python3}; L8=$MAIN/research/gauge44-leaver8 +MC=$MAIN/research/complex-k492-owner-repair/vendor/multicold +# 0. no-triangle base word (#645/#1005 chain, unchanged) +$PY -B $L8/construction/reproduce.py --main $MAIN --pr635 $PR635 --out $OUT/notri-base --until word +# 1. baseline: #1005's own cell driver, pins checked +$PY -B $L8/construction/leaver/reproduce_leaver.py --main $MAIN --pr635 $PR635 --word-dir $OUT/notri-base --id k8 --out $OUT/base --skip-phases +# 2. patched copy of the construction tree (partial-cell hook, successor anchoring, census dump) +cp -R $L8/construction $OUT/construction +( cd $OUT/construction + cp leaver/cgx_leaver.py leaver/cgx_census.py; patch -s leaver/cgx_census.py < $HERE/patches/cgx_census.patch + patch -s leaver/cgx_leaver.py < $HERE/patches/cgx_leaver.patch + patch -s leaver/reproduce_leaver.py < $HERE/patches/reproduce_leaver.patch + cp notri/port_stage_x.py notri/port_stage_x_rep.py; patch -s notri/port_stage_x_rep.py < $HERE/patches/port_stage_x.patch ) +# 3. delivery census of the cell word (byte-identical word, plus CENSUS.pkl) +mkdir -p $OUT/census; cp $OUT/base/TRI.json $OUT/base/CODED-CELLS.json $OUT/census/ +( cd $OUT/census && XPARAM=$L8/construction/notri/PRIO6.json MULTICOLD_SOURCE=$MC PYTHONINTMAXSTRDIGITS=0 \ + $PY -B $OUT/construction/leaver/cgx_census.py $OUT/notri-base/hamming $OUT/census/raw $OUT/census/TRI.json > census.log ) +cmp <(gzip -dc $OUT/census/raw/FULL-WORD.json.gz) <(gzip -dc $OUT/base/raw/FULL-WORD.json.gz) +export PC_CENSUS=$OUT/census/raw/CENSUS.pkl PC_PROTO=$OUT/notri-base/hamming/PROTOTYPE.json PC_PORTED=$OUT/base/port3/FULL-WORD.json.gz PC_MAIN=$MAIN PC_OUT=$OUT +# 4. raw-level checks (exact rows, frames) of the templates +( cd $OUT && $PY -B $HERE/code/template.py all > raw-template-yy.txt ) +# 5. variants through the native chain +run() { name=$1; keys=$2; shift 2 + rm -rf $OUT/$name + env "$@" PORT_REPAIR=1 PCELL_LATE=1 PCELLS=$HERE/$keys PCELL_TOOLS=$HERE/code \ + $PY -B $OUT/construction/leaver/reproduce_leaver.py --main $MAIN --pr635 $PR635 --word-dir $OUT/notri-base --id k8 \ + --out $OUT/$name --record-pins --skip-phases > $OUT/$name.log 2>&1 || true + if [ -d $OUT/$name/local ] && [ -f $OUT/$name/local/LOCAL-PROGRAMS.json.gz ]; then + ( cd $PR635/research/complex-571-cold14-st2/code && MULTICOLD_SOURCE=$MC $PY -B $HERE/code/prefix_trace.py $OUT/$name/local 2>&1 | grep PREFIX | cut -c1-60 > $OUT/$name.prefix ) || true + fi; } +( cd $PR635/research/complex-571-cold14-st2/code && MULTICOLD_SOURCE=$MC $PY -B $HERE/code/prefix_trace.py $OUT/base/local | grep PREFIX | cut -c1-60 > $OUT/base.prefix ) +run v1-yy-entering KEYS-ALL16.json PCELL_X=1 +run v2-two-kept KEYS-ALL16.json PCELL_V2=1 PORT_SUCC=1 PCELL_MOVEOWN=1 +run v3-fresh-all16 KEYS-ALL16.json PCELL_V3=1 PORT_SUCC=1 PCELL_MOVEOWN=1 +run v3-fresh-4567 KEYS-CLASS4567.json PCELL_V3=1 PORT_SUCC=1 PCELL_MOVEOWN=1 +run v3-fresh-one KEYS-ONE.json PCELL_V3=1 PORT_SUCC=1 PCELL_MOVEOWN=1 +# 6. collect profiles, pairing, audit outcome, coefficient bits, price +$PY -B $HERE/code/collect.py $OUT