From 7fac5292693bf738ff5eed6ec754f8ec22ebcf8e Mon Sep 17 00:00:00 2001 From: DreamingOfClouds Date: Sun, 11 Oct 2026 09:52:16 -0500 Subject: [PATCH] =?UTF-8?q?[Draft]=20Complex=20supplier=20b=20=E2=89=88=20?= =?UTF-8?q?1.334e-3=20(+5.2%):=20shared-donor=20kernel=20and=20entrance=20?= =?UTF-8?q?gauges?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit WIP snapshot on PR #442's complex word. Conditional on two new lemmas (entrance adapter, gauge compensation); local exact checks pass via check.sh. Prepared by DreamingOfClouds with Claude Opus 5.5 (Anthropic), via Claude Code. Co-Authored-By: Claude Opus 5.5 --- research/e8-complex-gauge-kernel/NOTICE.md | 4 + research/e8-complex-gauge-kernel/PROOF.md | 59 +++ research/e8-complex-gauge-kernel/README.md | 58 +++ research/e8-complex-gauge-kernel/check.sh | 23 ++ .../e8-complex-gauge-kernel/code/audit_cxg.py | 165 +++++++++ .../code/build_final.py | 17 + .../e8-complex-gauge-kernel/code/build_v4.py | 8 + .../e8-complex-gauge-kernel/code/cxcheck.py | 79 ++++ .../e8-complex-gauge-kernel/code/cxlab.py | 38 ++ .../e8-complex-gauge-kernel/code/emit_cxg.py | 146 ++++++++ .../code/final_eval.py | 17 + .../code/final_sel2.py | 31 ++ .../e8-complex-gauge-kernel/code/gauge.py | 51 +++ .../e8-complex-gauge-kernel/code/gauge2.py | 72 ++++ .../e8-complex-gauge-kernel/code/gauge3.py | 53 +++ .../e8-complex-gauge-kernel/code/gauge4.py | 53 +++ .../e8-complex-gauge-kernel/code/hostmodel.py | 88 +++++ research/e8-complex-gauge-kernel/code/iso1.py | 53 +++ research/e8-complex-gauge-kernel/code/kcap.py | 13 + research/e8-complex-gauge-kernel/code/kern.py | 53 +++ .../e8-complex-gauge-kernel/code/kern2.py | 43 +++ .../e8-complex-gauge-kernel/code/kern3.py | 73 ++++ .../e8-complex-gauge-kernel/code/kern4.py | 46 +++ .../e8-complex-gauge-kernel/code/kern5.py | 50 +++ .../e8-complex-gauge-kernel/code/kern6.py | 29 ++ .../e8-complex-gauge-kernel/code/mkword.py | 26 ++ .../code/mkword_gauge.py | 30 ++ research/e8-complex-gauge-kernel/code/nec3.py | 15 + research/e8-complex-gauge-kernel/code/nec4.py | 40 +++ .../code/phases_cxg.py | 39 ++ .../e8-complex-gauge-kernel/code/retime.py | 203 +++++++++++ .../e8-complex-gauge-kernel/code/reuse.py | 120 +++++++ .../e8-complex-gauge-kernel/code/reuse2.py | 79 ++++ .../e8-complex-gauge-kernel/code/sa_long.py | 15 + .../data/final_eval_reference.json | 189 ++++++++++ .../data/selection/gauge80.json | 271 ++++++++++++++ .../data/selection/kernel79.json | 339 ++++++++++++++++++ .../words/gauge80-kernel42/FULL-WORD.json.gz | Bin 0 -> 38701 bytes .../data/words/gauge80/FULL-WORD.json.gz | Bin 0 -> 37547 bytes .../data/words/kernel79/FULL-WORD.json.gz | Bin 0 -> 37942 bytes 40 files changed, 2688 insertions(+) create mode 100644 research/e8-complex-gauge-kernel/NOTICE.md create mode 100644 research/e8-complex-gauge-kernel/PROOF.md create mode 100644 research/e8-complex-gauge-kernel/README.md create mode 100755 research/e8-complex-gauge-kernel/check.sh create mode 100644 research/e8-complex-gauge-kernel/code/audit_cxg.py create mode 100644 research/e8-complex-gauge-kernel/code/build_final.py create mode 100644 research/e8-complex-gauge-kernel/code/build_v4.py create mode 100644 research/e8-complex-gauge-kernel/code/cxcheck.py create mode 100644 research/e8-complex-gauge-kernel/code/cxlab.py create mode 100644 research/e8-complex-gauge-kernel/code/emit_cxg.py create mode 100644 research/e8-complex-gauge-kernel/code/final_eval.py create mode 100644 research/e8-complex-gauge-kernel/code/final_sel2.py create mode 100644 research/e8-complex-gauge-kernel/code/gauge.py create mode 100644 research/e8-complex-gauge-kernel/code/gauge2.py create mode 100644 research/e8-complex-gauge-kernel/code/gauge3.py create mode 100644 research/e8-complex-gauge-kernel/code/gauge4.py create mode 100644 research/e8-complex-gauge-kernel/code/hostmodel.py create mode 100644 research/e8-complex-gauge-kernel/code/iso1.py create mode 100644 research/e8-complex-gauge-kernel/code/kcap.py create mode 100644 research/e8-complex-gauge-kernel/code/kern.py create mode 100644 research/e8-complex-gauge-kernel/code/kern2.py create mode 100644 research/e8-complex-gauge-kernel/code/kern3.py create mode 100644 research/e8-complex-gauge-kernel/code/kern4.py create mode 100644 research/e8-complex-gauge-kernel/code/kern5.py create mode 100644 research/e8-complex-gauge-kernel/code/kern6.py create mode 100644 research/e8-complex-gauge-kernel/code/mkword.py create mode 100644 research/e8-complex-gauge-kernel/code/mkword_gauge.py create mode 100644 research/e8-complex-gauge-kernel/code/nec3.py create mode 100644 research/e8-complex-gauge-kernel/code/nec4.py create mode 100644 research/e8-complex-gauge-kernel/code/phases_cxg.py create mode 100644 research/e8-complex-gauge-kernel/code/retime.py create mode 100644 research/e8-complex-gauge-kernel/code/reuse.py create mode 100644 research/e8-complex-gauge-kernel/code/reuse2.py create mode 100644 research/e8-complex-gauge-kernel/code/sa_long.py create mode 100644 research/e8-complex-gauge-kernel/data/final_eval_reference.json create mode 100644 research/e8-complex-gauge-kernel/data/selection/gauge80.json create mode 100644 research/e8-complex-gauge-kernel/data/selection/kernel79.json create mode 100644 research/e8-complex-gauge-kernel/data/words/gauge80-kernel42/FULL-WORD.json.gz create mode 100644 research/e8-complex-gauge-kernel/data/words/gauge80/FULL-WORD.json.gz create mode 100644 research/e8-complex-gauge-kernel/data/words/kernel79/FULL-WORD.json.gz diff --git a/research/e8-complex-gauge-kernel/NOTICE.md b/research/e8-complex-gauge-kernel/NOTICE.md new file mode 100644 index 0000000000..a5682058c5 --- /dev/null +++ b/research/e8-complex-gauge-kernel/NOTICE.md @@ -0,0 +1,4 @@ +Apache-2.0. `code/audit_cxg.py`, `emit_cxg.py`, `phases_cxg.py` are modified copies of PR #433's `complex_audit.py`, +`complex_emit.py`, `complex_phases_full.py` (icekylinx with Codex; adapted from PR #425 by jacklightChen / Zhihao Chen). +`code/hostmodel.py` replicates the profile arithmetic of PR #442's `complex_hosted.py` (DaysSky) for mixed widths. +Prepared by DreamingOfClouds with Claude Opus 5.5 (Anthropic), via Claude Code. diff --git a/research/e8-complex-gauge-kernel/PROOF.md b/research/e8-complex-gauge-kernel/PROOF.md new file mode 100644 index 0000000000..78315a32e6 --- /dev/null +++ b/research/e8-complex-gauge-kernel/PROOF.md @@ -0,0 +1,59 @@ +# Lemmas used by the draft (both are NEW and are the review points) + +Setting: #442's complex word (#433's split-centre R560 word, m = 73, nine stages) with the idle-axis hosting of #442. +Notation: frames are subspaces of F2^9; T_U = canonical_frame(9, U) (clifford_exact.py); T_FULL is the full Fourier +transform; a helper normally climbs ∅ → … → FULL and its residual has width 9. + +## 0. What is not claimed +The entrance lines used here are all of EVEN weight, i.e. totally isotropic for the F2 dot product (14 distinct rank-1 +lines in the kernel word; 16 frames of rank 1, 2 and 4 in the combined word). The bit-style criterion of #440 +(`validate_isometries`: an orthonormal basis whose first e rows span E, i.e. coordinate entrances) is therefore NOT met: +no orthogonal matrix of O(9,2) sends an isotropic E to coordinate axes. `code/iso1.py` shows that, restricted to +entrances that do meet it, the kernel potential and the number of gauge-eligible helpers are both 0. #442's shipped +complex audit asserts `w == 9` for hosted residuals (`idle-axis-hosting/audit.py:92`), and #433's emit asserts +`c['start'][r]==0` for compensated registers (`complex_emit.py:55`). No shipped complex word has a nonzero helper +entrance. Everything below is therefore CONDITIONAL on Lemma A and Lemma G. + +## Lemma A (entrance adapter) — review point 1 +Let E ⊆ F2^9, e = dim E, w = 9 − e, and Φ_E = T_E^† T_FULL (the chain ∅ → E removed from the helper's climb). +(i) Φ_E = R_E (C_[w] ⊗ I) L_E with R_E, L_E explicit Gaussian monomials (address permutation, quadratic phase, X +translation), exactly, including the global phase. This is `lower_child` applied to Φ_E: it asserts rank w, +`compiled.tab == Φ_E.tab` and `compiled.zero_state() == Φ_E.zero_state()`. +(ii) Claim (assumed, not proved): a helper that starts at frame E and ends at FULL, with its compensation moved off +the zero frame (kernel: absorbed by donors; gauge: Lemma G), acts on its residual stream as the exact coordinate +factor P_g C_[w] P_g^-1 that hosting lemma (a) of #442 uses, where the monomials R_E, L_E are rank-zero local gates like +the endpoint adapters of #425. Its residual block has width w; the e remaining local coordinates carry arbitrary +dirt and are transformed by Φ_E like any other dirt coordinate, which the arbitrary-dirt restoration identity +(replayed exactly on all 800 columns) tolerates. +Evidence: `code/nec4.py` — all 16 entrance frames of `gauge80-kernel42` pass (i); `code/nec3.py` shows the tableaux: +for coordinate frames Φ_E fixes every X_i, for the isotropic and odd-weight non-coordinate frames it does not, i.e. +the monomials are genuinely non-orthogonal GL(9,2) address maps. Part (ii) is where a reviewer must look: it is the +statement that the bank block of width w plus a non-orthogonal monomial adapter is an admissible residual route. + +## Lemma K (shared-donor kernel, port of #417/#435/#434) +A pivot p with exact response relation col(p) = Σ q_d col(d) over donors d, entrance E ⊆ first frame of p and of every +donor, starts at frame E; each donor receives `d += -q_d p` at frame E before the main word (inverse after the +cleanup at the full frame); the compensation columns of pivots are dropped. Exactness is the arbitrary-dirt replay +(donor update is part of the replayed word); frames are checked by the chain assertion. Same statement as in #440, +with rational coefficients (all denominators are powers of two, as required by `primitive_bound`). + +## Lemma G (entrance gauge, nonzero-frame compensation and centre scatter) — review point 2 +For a helper j with entrance E_j (a member of a nested family) its compensation `y_t += c_tj x_j` is executed at +frame E_j instead of frame 0, as the first gates of the main word; the helper starts at E_j and every target t in its +response support climbs ∅ → L_t, L_t = the largest E_j with t in the support of j. +Constraints (all checked): (a) E_j ⊆ first frame of j and ⊆ the first main frame of every target in its support; +(b) the entrances touching one target are pairwise nested; (c) for every centre k, the levels L_t of the targets it +scatters into form a chain whose top lies inside the centre frame c_k. The centre scatter then runs as: copy at c_k; +lower stepwise c_k → (served levels, descending) → lowest served level; scatter into the targets of level L at frame L; +clear at the lowest level (reversed in the transposed orientation). The total lowering rank equals the baseline 8 +whenever some served target has level ∅, so the rank deficit stays 2496. +Claim (assumed): a scalar add at frame E between a helper at E and a target raised to E, and the centre scatter at +frame L between a copy lowered only to L and a target at L, are the same operators as the zero-frame versions up to the +common exterior window (the common-frame lemma of #425, extended from frame 0 to frame L). +Evidence: audit (exact arbitrary-dirt and inverse-transpose replay of the full program including the gauge gates), +emit (literal scalar replay of both orientations on 800 columns, centre lifetimes, `paid` equals the audit profile), +exact Gaussian recipes for every used transition (2,940 edges for the gauge word). + +## Mutation controls (to be added in the full package) +Not yet run: omit the donor update, flip a gauge coefficient sign, move an entrance out of the first frame, break a +centre chain. `audit_cxg.py` already rejects frame-chain violations by assertion. diff --git a/research/e8-complex-gauge-kernel/README.md b/research/e8-complex-gauge-kernel/README.md new file mode 100644 index 0000000000..d5c1be2e0a --- /dev/null +++ b/research/e8-complex-gauge-kernel/README.md @@ -0,0 +1,58 @@ +# Complex supplier b: shared-donor kernel and entrance gauges on the E8 complex word (DRAFT, status: work in progress) + +Not a claim yet. The claim is CONDITIONAL on two new lemmas (see `PROOF.md`) and the global package is not built. + +## Construction +On #442's complex word (#433's split-centre R560 word, m = 73, nine stages, idle-axis hosting), two tools of the +bit side are ported: +- **Shared-donor kernel** (#417/#435/#434/#439/#440 style): 79 pivots, rank-1 entrances, 14 entrance frames. +- **Entrance gauges** (#401/#408–#416 style): compensation moved to the entrance frame; 80 helpers, entrance + rank 106 (62 rank-1, 14 rank-2, 4 rank-4), nested per target and per centre. +- Not portable on this word: elimination reuse and early resets (#436/#437): 0 helpers survive the frame-monotonicity + check; block retiming (#441/#440): 0 improvement (frame cost unchanged after single-gate and closure moves). + +## Measured (hosted b, exact moment engine; the hosting step is my replica of #442's, which reproduces #442's complex b +1.267453159029119e-3, live stock 8400 and rank deficit 2496 to the last digit) +| word | helpers entering | total entrance rank | b | gain | κ cap if complex-bound | +| --- | ---: | ---: | ---: | ---: | ---: | +| #442 complex | 0 | 0 | 1.267453e-3 | | 1.265849e-3 | +| kernel only | 79 | 79 | 1.310216e-3 | +3.37% | 1.308502e-3 | +| gauge only | 80 | 106 | 1.310916e-3 | +3.43% | 1.309200e-3 | +| gauge + kernel | 122 | 148 | **1.333854e-3** | **+5.24%** | 1.332077e-3 | +The combined word hosts all 40,320 residuals (live stock 7,680, no bank). The rank deficit is 2496 in every row. + +## Checks that PASS (local word only; `sh check.sh DIR`) +- Exact arbitrary-dirt and inverse-transpose replay of the full word (800 columns), frame chain, paid profile. +- Emitted local program, literal scalar replay in both orientations on 800 columns with centre lifetimes. +- Exact Gaussian phase recipes for every used frame transition (`PHASES=1`): 2,932 / 2,940 / 2,952 edges. +- Entrance-adapter evidence: for all 16 entrance frames E→FULL = monomial · C_[9−e] · monomial exactly + (`lower_child`: tableau and state-vector equality, global phase included). + +## Plain statements about what is NOT met +- **The entrances are isotropic** (even-weight lines of F2^9). The bit-style coordinate-entrance criterion (#440's + `validate_isometries`) is NOT met, and no orthogonal map of O(9,2) can meet it for these lines. Restricted to + entrances that meet it, the gain is 0 (`code/iso1.py`). +- **#442's shipped complex audit and emit assume `w == 9` and `start == 0`.** No shipped complex word has a nonzero + helper entrance. The audit, emit and phase scripts used here are PATCHED copies (`code/audit_cxg.py`, `emit_cxg.py`, + `phases_cxg.py`: pre-ops, entrance starts, target levels, centre descent); their defaults are not yet shown to + reproduce #442's files byte for byte. +- The claim is therefore **conditional on Lemma A (entrance adapter) and Lemma G (nonzero-frame compensation and centre + scatter)**, which are the headline review points. + +## Pending +Global template, owner tables and hosting generator for mixed residual widths (the hosted b above is a model); +residual-to-bank routes for each entrance frame; written proofs of Lemma A(ii) and Lemma G; mutation controls; +finite invoices and the outer assembly (47/47) with a bit word; byte-for-byte regression of the generalised scripts at +the #442 defaults; two fresh-copy replays. + +## Files +`PROOF.md` lemmas and scope; `check.sh`; `data/words/*/FULL-WORD.json.gz` the three words; `data/selection/*.json` +frozen selections; `code/` checks (`audit_cxg.py`, `emit_cxg.py`, `phases_cxg.py`, `cxcheck.py`, `hostmodel.py`, +`final_eval.py`, `nec3.py`, `nec4.py`, `iso1.py`) and the search scripts that produced the selections +(`kern*.py`, `gauge*.py`, `retime.py`, `reuse*.py`). + +## Credits +Builds on #442 (DaysSky, idle-axis hosting), #433 (icekylinx, split centres), #425 and #386 (jacklightChen / Zhihao +Chen, mutable packets, compressed windows), the shared-donor kernel of #417/#435 (chafreaky) and #434/#440 (rohanarun, +chafreaky), the entrance gauges of #401/#408–#416, #370 (Dylan Crow) and Jacob Sussman's E8 unit. +Prepared by DreamingOfClouds with Claude Opus 5.5 (Anthropic), via Claude Code. Apache-2.0. diff --git a/research/e8-complex-gauge-kernel/check.sh b/research/e8-complex-gauge-kernel/check.sh new file mode 100755 index 0000000000..94c4cc61f5 --- /dev/null +++ b/research/e8-complex-gauge-kernel/check.sh @@ -0,0 +1,23 @@ +#!/bin/sh +# Draft local checks for the complex gauge/kernel words. +# CXG_BASE : output directory of `python -B research/idle-axis-hosting/verify.py $CXG_BASE` (PR #442 replay; contains parent/changed/) +# CXG_REPO : checkout of PR #442's tree (research/split-centres-global, research/idle-axis-hosting) +# PY : python with numpy + scipy (hosted-b model); stdlib python is enough for the other steps +# PHASES=1 : also replay the exact Gaussian phase recipes of every used frame transition (about 160 s per word) +# usage: sh check.sh /absolute/new/output/dir +set -e +: "${CXG_BASE:?}"; : "${CXG_REPO:?}"; PY=${PY:-python3}; OUT=${1:?new output dir} +PKG=$(cd "$(dirname "$0")" && pwd); export CXG_PKG=$PKG CXG_BASE CXG_REPO PYTHONDONTWRITEBYTECODE=1 +mkdir -p "$OUT" +for w in kernel79 gauge80 gauge80-kernel42; do + d="$OUT/$w"; mkdir -p "$d" + cp -RL "$CXG_BASE/parent/changed/split-centres" "$d/split-centres" + cp -RL "$CXG_BASE/parent/changed/work" "$d/work" + cp "$PKG/data/words/$w/FULL-WORD.json.gz" "$d/split-centres/FULL-WORD.json.gz" + echo "== $w: arbitrary-dirt + inverse-transpose replay, frame chain, paid profile"; (cd "$d" && python3 -B "$PKG/code/audit_cxg.py" | tail -3) + echo "== $w: emitted program, literal scalar replay (forward and backward, 800 columns, centre lifetimes)"; (cd "$d" && python3 -B "$PKG/code/emit_cxg.py" | tail -2) + if [ -n "$PHASES" ]; then echo "== $w: exact Gaussian phase recipes (all used edges)"; (cd "$d" && python3 -B "$PKG/code/phases_cxg.py" | tail -1); fi +done +echo "== entrance-adapter evidence (nec3: tableau shapes, nec4: lower_child equality for every entrance frame)" +(cd "$PKG/code" && python3 -B nec3.py && $PY -B nec4.py) +echo "== hosted b (exact moment engine) per tool"; (cd "$PKG/code" && CXG_OUT="$OUT" $PY -B final_eval.py | cut -c1-200) diff --git a/research/e8-complex-gauge-kernel/code/audit_cxg.py b/research/e8-complex-gauge-kernel/code/audit_cxg.py new file mode 100644 index 0000000000..b19202899d --- /dev/null +++ b/research/e8-complex-gauge-kernel/code/audit_cxg.py @@ -0,0 +1,165 @@ +# Modified from PR425 by icekylinx with Codex assistance. +"""Read-back audit, independent of the Hamming producer and its row state.""" +import copy,gzip,hashlib,importlib.util,json,math,time +from collections import Counter +from fractions import Fraction as Q +from pathlib import Path + +import os +OUT=Path(os.environ.get('CXOUT','split-centres'));p=OUT/'FULL-WORD.json.gz' +word=json.load(gzip.open(p));v=120;n=240+word['report']['R'];start=time.monotonic() +def apply(e,rows): + if e[0]=='scale': + _,t,a,b,*_=e;q=Q(a,b);assert q + rows[t]={j:q*x for j,x in rows[t].items()} + else: + _,t,s,a,b,*_=e;q=Q(a,b);assert t!=s + for j,x in list(rows[s].items()): + z=rows[t].get(j,Q(0))+q*x + if z:rows[t][j]=z + else:rows[t].pop(j,None) +def ident():return [{r:Q(1)} for r in range(n)] +def inv(e): + e=copy.deepcopy(e) + if e[0]=='add':e[3]*=-1 + else:e[2],e[3]=e[3],e[2] + return e +def dual(e): + e=inv(e) + if e[0]=='add':e[1],e[2]=e[2],e[1] + return e + +main=word['A']+word['cut']+word['B'] +assert all(not 120<=e[2]<240 for e in word['A']+word['B'] if e[0]=='add' and not 120<=e[1]<240) +matrix=ident() +for e in main:apply(e,matrix) +print('full main columns',n,'replayed',flush=True) +# Compute -A_Y^-1 B_S using only rows of the explicit main operator. +dirty=[{} for r in range(n)] +for r in range(v,2*v):dirty[r]={j:x for j,x in matrix[r].items() if j>=2*v} +for e in word['precondition']:apply(e,dirty) +comp=[] +for r in range(v,2*v): + for j,q in sorted(dirty[r].items()):comp.append(['add',r,j,-q.numerator,q.denominator,[]]) + +cleanup=[inv(e) for e in reversed(word['A']+word['B']) if not v<=e[1]<2*v] +assert [e[:-1] for e in cleanup]==[e[:-1] for e in word['cleanup']] +program=word['precondition']+comp+main+cleanup +actual=ident() +for e in program:apply(e,actual) +expected=ident() +for t in range(v):expected[v+t][t]=Q(1) +assert actual==expected +print('PASS exact arbitrary dirt and restored sources/helpers',flush=True) +back=ident() +for e in program:apply(dual(e),back) +expected_back=ident() +for t in range(v):expected_back[t][v+t]=Q(-1) +assert back==expected_back +print('PASS exact inverse-transpose on every column',flush=True) +# Independent sparse vector controls avoid repeating a dense full replay. +def vector(es,x): + x=list(map(Q,x)) + for e in es: + if e[0]=='scale':x[e[1]]*=Q(e[2],e[3]) + else:x[e[1]]+=Q(e[3],e[4])*x[e[2]] + return x +sample=[((i*137+13)%101)-50 for i in range(n)] +want=vector(program,sample) +controls={ + 'missing_dirty_compensation':word['precondition']+main+cleanup, + 'missing_Y_inverse_basis':comp+main+cleanup, + 'missing_source_cleanup':word['precondition']+comp+main, + 'wrong_dual_event_order':[dual(e) for e in reversed(program)], +} +for name,es in controls.items(): + expected_sample=vector([dual(e) for e in program],sample) if name=='wrong_dual_event_order' else want + assert vector(es,sample)!=expected_sample,name + +# Orthogonal transvection and a port permutation bring the new geometry onto +# the already fixed 120-port routing family. Every incidence is transformed. +old=json.load(gzip.open('work/higher-stage-e8/verified/gcert1-e8-retimed.json.gz')) +def tau(x):return x^(43 if (x&43).bit_count()%2 else 0) +assert 43 .bit_count()%2==0 +assert set(map(tau,word['ports']))==set(old['ports']) +mapping={i:old['ports'].index(tau(q)) for i,q in enumerate(word['ports'])} +mapping.update({v+i:v+mapping[i] for i in range(v)}) +mapping.update({r:r for r in range(2*v,n)}) +def basis(vs): + b={} + for x in vs: + for k in sorted(b,reverse=True): + if x>>k&1:x^=b[k] + if x: + k=x.bit_length()-1 + for j in b: + if b[j]>>k&1:b[j]^=x + b[k]=x + return tuple(b[k] for k in sorted(b,reverse=True)) +def perp(x):return basis([z for z in range(1,512) if not (x&z).bit_count()%2]) +full=tuple(1<0 + edges.add((old,f));paid[delta]+=1;cur[r]=f +for part in ('A','B'): + if part=='B': + assert all(cur[r]==f for r,f in zip(can['centers'],can['center_frames'])) + assert all(cur[r]==can['target_levels'].get(r-v,0) for r in range(v,2*v)) + for r_c,f in zip(can['centers'],can['center_frames']): + # mass-neutral descent: cf -> served levels (descending) -> lowest served level + served={can['target_levels'].get(e[1]-v,0) for e in can['cut'] if e[2]==r_c} + o=f + for L in sorted(served,key=lambda L:-len(frames[L])): + assert basis(frames[L]+frames[o])==tuple(frames[o]),('centre frame must contain served level',r_c) + if L!=o:paid[len(frames[o])-len(frames[L])]+=1;edges.add((o,L));edges.add((L,o));o=L + if o==f:paid[0]+=0 + for e in can[part]: + rs=[e[1]]+([e[2]] if e[0]=='add' else []) + for r in rs:climb(r,e[-1]);incidences+=1 +for r,f in enumerate(can['final']):climb(r,f) +assert dict(paid)=={int(r):x for r,x in word['report']['local_profile'].items()} +assert sum(r*x for r,x in paid.items())==sum(int(r)*x for r,x in word['report']['local_profile'].items()) +can['local_profile']=dict(sorted(paid.items()));can['edges']=sorted(edges) +cp=OUT/'CANONICAL-WORD.json.gz';cp.write_bytes(gzip.compress(json.dumps(can,sort_keys=True,separators=(',',':')).encode(),mtime=0)) + +b=Q(0);grid=Q(1,10**18) +coeff=Counter(str(Q(e[3],e[4]) if e[0]=='add' else Q(e[2],e[3])) for e in program) +report={'status':'PASS_EXACT_SCALAR_AND_FRAME_RESEARCH_CANDIDATE_NOT_YET_ADMITTED', + 'full_word_sha256':hashlib.sha256(p.read_bytes()).hexdigest(), + 'canonical_word_sha256':hashlib.sha256(cp.read_bytes()).hexdigest(), + 'live_columns_each_orientation':n,'arbitrary_helper_columns':can['R'], + 'all_live_source_and_helper_rows_restored':True,'all_target_rows_correct':True, + 'negative_controls_rejected':list(controls),'old_response_additions':len(comp), + 'complete_forward_scalar_operations':len(program),'coefficient_histogram':dict(coeff), + 'frames':len(frames),'nested_directed_edges':len(edges),'common_frame_incidences':incidences, + 'orthogonal_transport_vector':43,'transported_ports_exactly_match_fixed_routes':True, + 'local_profile':dict(sorted(paid.items())), + 'two_rational_moment_engines':True,'next_b_grid_rejected':True, + 'remaining':['new general scalar-interface proof integration','exact phase and emitted local/global program','finite invoice and outer assembly'], + 'scope':'Substantial new scalar-network candidate. All parameter values remain prospective until the expanded scalar interface and complete phase-aware supplier are admitted.', + 'seconds':time.monotonic()-start} +(OUT/'SCALAR-FRAME-AUDIT.json').write_text(json.dumps(report,indent=2)+'\n') +print('PASS audit',report['seconds'],flush=True) diff --git a/research/e8-complex-gauge-kernel/code/build_final.py b/research/e8-complex-gauge-kernel/code/build_final.py new file mode 100644 index 0000000000..945d233719 --- /dev/null +++ b/research/e8-complex-gauge-kernel/code/build_final.py @@ -0,0 +1,17 @@ +import pickle,sys,json +from mkword_gauge import * +from kern6 import asg_to_groups,groups_to_pre +from kern import setup +import numpy as np +w=load();w['R']=w['report']['R'];col,first=setup(w);R=len(col) +C=np.zeros((v,R)) +for h in range(R): + for t,x in col[h].items():C[t,h]=float(x) +which=sys.argv[1];out=sys.argv[2] +if which=='v1': + best,asg=pickle.load(open('sa_long_12.pkl','rb')) + groups=asg_to_groups(C,asg);pre,start,eps=groups_to_pre(col,groups);gauge={} +elif which=='v3': + pre,start,gauge,flag=pickle.load(open('v3_sel.pkl','rb')) +mkword_gauge(w,pre,start,gauge,out) +print(which,'pre',len(pre),'pivots',len(start),'gauge',len(gauge)) diff --git a/research/e8-complex-gauge-kernel/code/build_v4.py b/research/e8-complex-gauge-kernel/code/build_v4.py new file mode 100644 index 0000000000..e280d0ccab --- /dev/null +++ b/research/e8-complex-gauge-kernel/code/build_v4.py @@ -0,0 +1,8 @@ +import pickle,sys +from mkword_gauge import * +w=load();w['R']=w['report']['R'] +which=sys.argv[1];out=sys.argv[2] +pre,start,gauge,_=pickle.load(open('v4_sel.pkl','rb')) +if which=='g80':pre,start=[],{} +mkword_gauge(w,pre,start,gauge,out) +print(which,'pre',len(pre),'pivots',len(start),'gauge',len(gauge)) diff --git a/research/e8-complex-gauge-kernel/code/cxcheck.py b/research/e8-complex-gauge-kernel/code/cxcheck.py new file mode 100644 index 0000000000..c0eee7f6d0 --- /dev/null +++ b/research/e8-complex-gauge-kernel/code/cxcheck.py @@ -0,0 +1,79 @@ +"""Generalised exact checker for variants of the #433 complex word (arbitrary dirt, inverse-transpose, frame chain, paid profile). +A variant = dict(A,B,cut,precondition,pre,start,ports,...). pre = list of ['add',donor,pivot,num,den,E] ops placed first in main. +start = {register: frame(list of masks)} for pivots (default () for helpers, (P[s],) for sources, () for targets). +cleanup is rebuilt: inverse of all non-target ops of pre+A+B at FULL, reversed.""" +from cxlab import * +import time +FULL=tuple(1<=2*v} + for e in prec:apply(e,dirty) + comp=[] + for r in range(v,2*v): + for j,x in sorted(dirty[r].items()):comp.append(['add',r,j,-x.numerator,x.denominator,[]]) + ncomp_cols=len({e[2] for e in comp}) + cleanup=[] + for e in reversed(list(pre)+A+B): + if not v<=e[1]<2*v: + c=inv(e);c[-1]=list(FULL);cleanup.append(c) + program=list(prec)+comp+main+cleanup + rep=dict(R=R,comp_adds=len(comp),comp_cols=ncomp_cols) + if full: + actual=ident(n) + for e in program:apply(e,actual) + expected=ident(n) + for t in range(v):expected[v+t][t]=Q(1) + assert actual==expected,'arbitrary-dirt exactness FAILED' + back=ident(n) + for e in program:apply(dual(e),back) + eb=ident(n) + for t in range(v):eb[t][v+t]=Q(-1) + assert back==eb,'inverse-transpose FAILED' + rep['exact_arbitrary_dirt']=True;rep['exact_inverse_transpose']=True + # frame chain + paid profile (mirrors complex_audit canonical climb check) + cur={} + for r in range(n): + if r=2*v) else perp(P[r-v])) + rep['local_profile']=dict(sorted(paid.items()));rep['edges']=len(edges) + rep['mass']=sum(r*z for r,z in paid.items()) + rep['widths']=[9-startrank[r] for r in range(2*v,n)] + rep['seconds']=time.time()-t0 + rep['_program']=program + return rep,edges +if __name__=='__main__': + w=load();rep,_=check(w) + print({k:v for k,v in rep.items() if k not in('_program','widths')},sum(rep['widths'])) diff --git a/research/e8-complex-gauge-kernel/code/cxlab.py b/research/e8-complex-gauge-kernel/code/cxlab.py new file mode 100644 index 0000000000..caed7a48d6 --- /dev/null +++ b/research/e8-complex-gauge-kernel/code/cxlab.py @@ -0,0 +1,38 @@ +"""cx lab helpers. Paths come from the environment: CXG_BASE = output directory of +`python -B research/idle-axis-hosting/verify.py $CXG_BASE` (PR #442 replay, which contains parent/changed/split-centres).""" +import gzip,json,copy,os,sys +from fractions import Fraction as Q +from collections import Counter,defaultdict +CX=os.environ.get('CXG_BASE','') +CH=CX+'/parent/changed/split-centres/' +v=120 +def load(path=None): + return json.load(gzip.open(path or (CH+'FULL-WORD.json.gz'))) +def apply(e,rows): + if e[0]=='scale': + _,t,a,b,*_=e;q=Q(a,b) + rows[t]={j:q*x for j,x in rows[t].items()} + else: + _,t,s,a,b,*_=e;q=Q(a,b) + for j,x in list(rows[s].items()): + z=rows[t].get(j,Q(0))+q*x + if z:rows[t][j]=z + else:rows[t].pop(j,None) +def inv(e): + e=copy.deepcopy(e) + if e[0]=='add':e[3]*=-1 + else:e[2],e[3]=e[3],e[2] + return e +def basis(vs): + b={} + for x in vs: + for k in sorted(b,reverse=True): + if x>>k&1:x^=b[k] + if x: + k=x.bit_length()-1 + for j in b: + if b[j]>>k&1:b[j]^=x + b[k]=x + return tuple(b[k] for k in sorted(b,reverse=True)) +def inside(a,b):return basis(list(a)+list(b))==tuple(b) if basis(b)==tuple(b) else basis(list(a)+list(b))==basis(b) +def ident(n):return [{r:Q(1)} for r in range(n)] diff --git a/research/e8-complex-gauge-kernel/code/emit_cxg.py b/research/e8-complex-gauge-kernel/code/emit_cxg.py new file mode 100644 index 0000000000..8075000813 --- /dev/null +++ b/research/e8-complex-gauge-kernel/code/emit_cxg.py @@ -0,0 +1,146 @@ +# Adapted from PR425 by icekylinx with Codex assistance. +"""Emit both local programs, integrate the fixed nine-stage geometry, and bill. + +The expanded scalar interface is justified in PROOF.txt. This script does not +claim a Lean proof or discharge the inherited all-size/analytic interfaces. +""" +import copy,gzip,hashlib,importlib.util,json,math +from collections import Counter +from fractions import Fraction as Q +from pathlib import Path + +OUT=Path('split-centres');cp=OUT/'CANONICAL-WORD.json.gz' +c=json.load(gzip.open(cp)) +frames=c['frames'];v,R,h=c['v'],c['R'],c['h'];n=2*v+R +def digest(x):return hashlib.sha256(json.dumps(x,sort_keys=True,separators=(',',':')).encode()).hexdigest() +def basis(vs): + b={} + for x in vs: + for p in sorted(b,reverse=True): + if x>>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 dual(e): + e=list(e) + if e[0]=='add':e[1],e[2]=e[2],e[1];e[3]*=-1 + else:e[2],e[3]=e[3],e[2] + return e +def scalar(e,back): + e=dual(e) if back else list(e) + if e[0]=='add':return ['add',['L',e[1]],['L',e[2]],e[3],e[4]] + return ['scale',['L',e[1]],e[2],e[3]] +def primitive_bound(e): + if e[0] in ('clear','copy'):return 1 + q=Q(e[3],e[4]) if e[0]=='add' else Q(e[2],e[3]) + a,b=abs(q.numerator),q.denominator + assert b&(b-1)==0 + if e[0]=='scale': + assert a&(a-1)==0 + return abs(a.bit_length()-b.bit_length())+int(q<0) + # Exact binary Horner multiplication on a cleared private stream, repeated + # halving, signed accumulation into the target, then clear the private stream. + return 3+(a.bit_length()-1)+a.bit_count()+(b.bit_length()-1) + +def emit(back): + out=[];cur=c['start'].copy() + def event(e):out.append(e) + def scal(e,f):event(['scalar',e,f]) + event(['phase','zero_frame_precondition']) + for e in c['precondition']+c['compensation']: + regs=[e[1]]+([e[2]] if e[0]=='add' else []) + assert all(c['start'][r]==0 for r in regs) + scal(scalar(e,back),0) + event(['phase','entry_adapters']) + for r,f in enumerate(c['start']):event(['adapter','old_to_new',r,f]) + def climb(r,f,part): + old=cur[r] + if old==f:return + assert basis(frames[old]+frames[f])==tuple(frames[f]) + rank=len(frames[f])-len(frames[old]);assert rank>0 + event(['climb',part,r,old,f,rank]);cur[r]=f + for part in ('A','centers','B','final'): + event(['phase',part]) + if part in ('A','B'): + for e in c[part]: + regs=[e[1]]+([e[2]] if e[0]=='add' else []) + for r in regs:climb(r,e[-1],part) + scal(scalar(e,back),e[-1]) + elif part=='centers': + tl=c.get('target_levels',{}) + lv=lambda r:tl.get(str(r-v),tl.get(r-v,0)) + assert all(cur[r]==lv(r) for r in range(v,2*v)) + for k,r in enumerate(c['centers']): + cf=c['center_frames'][k];assert cur[r]==cf + terms=[e for e in c['cut'] if e[2]==r] + served=sorted({lv(e[1]) for e in terms},key=lambda L:-len(frames[L])) + path=[cf]+[L for L in served if L!=cf] # descending chain of frames + C=['C',k] + if not back: + scal(['clear',C],cf);scal(['copy',C,['L',r]],cf) + for a in range(len(path)): + if a>0:event(['center',k,path[a-1],path[a],len(frames[path[a-1]])-len(frames[path[a]])]) + for e in terms: + if lv(e[1])==path[a] or (a==0 and lv(e[1])==cf):scal(['add',['L',e[1]],C,e[3],e[4]],path[a]) + scal(['clear',C],path[-1]) + else: + scal(['clear',C],path[-1]) + for a in range(len(path)-1,-1,-1): + for e in terms: + if lv(e[1])==path[a] or (a==0 and lv(e[1])==cf):scal(['add',C,['L',e[1]],e[3],e[4]],path[a]) + if a>0:event(['center',k,path[a],path[a-1],len(frames[path[a-1]])-len(frames[path[a]])]) + scal(['add',['L',r],C,-1,1],cf);scal(['clear',C],cf) + else: + for r,f in enumerate(c['final']):climb(r,f,part) + event(['phase','exit_adapters']) + for r,f in enumerate(c['final']):event(['adapter','new_to_old',r,f]) + event(['phase','full_frame_cleanup']) + for e in c['cleanup']: + regs=[e[1]]+([e[2]] if e[0]=='add' else []) + assert all(c['final'][r]==1 for r in regs) + scal(scalar(e,back),1) + event(['phase','done']) + return out + +def check_local(events,back): + # Literal scalar replay of the emitted stream, including center lifetimes. + state={('L',r):{r:Q(1)} for r in range(n)};live=[];paid=Counter();prims=0;macros=0 + for e in events: + if e[0]=='climb':assert not live;paid[e[5]]+=1 + elif e[0]=='center':assert live==[e[1]];paid[e[4]]+=1 + elif e[0]=='scalar': + op=e[1];tag=op[0];t=tuple(op[1]);macros+=1;prims+=2*primitive_bound(op) + if tag=='clear': + state[t]={} + if t[0]=='C' and t[1] in live:live.remove(t[1]) + elif tag=='copy':state[t]=dict(state.get(tuple(op[2]),{}));live.append(t[1]) + elif tag=='scale':state[t]={j:Q(op[2],op[3])*x for j,x in state[t].items()} + else: + s=tuple(op[2]);q=Q(op[3],op[4]);row=state.setdefault(t,{}) + if t[0]=='C' and t[1] not in live:live.append(t[1]) + for j,x in list(state.get(s,{}).items()): + z=row.get(j,Q(0))+q*x + if z:row[j]=z + else:row.pop(j,None) + assert not live and all(not row for r,row in state.items() if r[0]=='C') + for r in range(n): + expected={r:Q(1)} + if back and r=2 and len(G)-np.linalg.matrix_rank(C[:,G])>0] +print('kernel classes available on rest',len(Es)) +best=None +if Es: + for seed in range(2): + b_,asg=sa(col,first,C,cand,Es,iters=40000,seed=seed) + if best is None or b_>best[0]:best=(b_,asg) + groups=asg_to_groups(C,best[1]);pre,start,eps=groups_to_pre(col,groups) +else:pre,start,eps=[],{},0 +prof,widths=gauge_profile(w,pre,start,gauge,None) +r=HM.evaluate(prof,widths,exact=True) +print('gauge+kernel: kernel eps',eps,'total eps',sum(len(E) for E in gauge.values())+eps,'b',r['b'],'%+.3f%%'%(100*(r['b']/r0['b']-1)),r['W'],r['banks'],r['hosted']) +pickle.dump((pre,start,gauge,None),open('v4_sel.pkl','wb')) diff --git a/research/e8-complex-gauge-kernel/code/gauge.py b/research/e8-complex-gauge-kernel/code/gauge.py new file mode 100644 index 0000000000..45ddbacdd6 --- /dev/null +++ b/research/e8-complex-gauge-kernel/code/gauge.py @@ -0,0 +1,51 @@ +from kern import * +import random +def span(F): + s={0} + for b in F:s|={x^b for x in s} + return frozenset(s) +def perp(x):return basis([z for z in range(1,512) if not (x&z).bit_count()%2]) +def prep(w): + col,first=setup(w);R=len(col);P=w['ports'] + A,B=w['A'],w['B'];FB={} + for seq in (A,B): + for e in seq: + for r in ([e[1]]+([e[2]] if e[0]=='add' else [])): + if v<=r<2*v and e[-1] is not None:FB.setdefault(r-v,basis(e[-1])) + cap={t:span(FB[t]) if t in FB else span(perp(P[t])) for t in range(v)} + cands={} + for h in range(R): + S=list(col[h]);inter=set(span(first[h])) + for t in S:inter&=cap[t] + # candidate subspaces of first[h] inside inter + cs=[] + for E in subspaces(first[h]): + if span(E)<=inter:cs.append(E) + cands[h]=sorted(cs,key=lambda E:-len(E)) + return col,first,cap,cands,P +def nested(sa,sb):return sa<=sb or sb<=sa +def greedy(col,cands,seed=0,order=None): + R=len(col);rnd=random.Random(seed) + chain={t:[] for t in range(v)} # list of span-sets + E_of={} + hs=list(range(R)) + if order is None: + hs.sort(key=lambda h:(len(col[h]),rnd.random())) + else:hs=order + eps=0 + for h in hs: + for E in cands[h]: + sE=span(E) + if all(all(nested(sE,c) for c in chain[t]) for t in col[h]): + E_of[h]=E;eps+=len(E) + for t in col[h]:chain[t].append(sE) + break + return E_of,eps +if __name__=='__main__': + w=load();col,first,cap,cands,P=prep(w) + print('cands sizes',Counter(len(c) for c in cands.values()).most_common(6)) + print('upper (sum of max cand rank)',sum(len(c[0]) if c else 0 for c in cands.values())) + best=0 + for seed in range(30): + E_of,eps=greedy(col,cands,seed) + if eps>best:best=eps;print(seed,eps,len(E_of),Counter(len(E) for E in E_of.values())) diff --git a/research/e8-complex-gauge-kernel/code/gauge2.py b/research/e8-complex-gauge-kernel/code/gauge2.py new file mode 100644 index 0000000000..84c9c839e6 --- /dev/null +++ b/research/e8-complex-gauge-kernel/code/gauge2.py @@ -0,0 +1,72 @@ +"""Gauge variant (entrance comps at nonzero frames on a global flag; centre copies climb the flag). Profile model on top of the exact word.""" +from cxcheck import * +from gauge import prep,span,perp +import pickle +import hostmodel as HM +def gauge_profile(w,pre,start_kernel,gauge,flag): + """gauge: {helper h: E basis tuple (member of flag)}; start_kernel: {reg: E} kernel pivots (registers absolute ids); returns profile dict + widths""" + rep,edges=check(w,pre=pre,start=start_kernel,full=False) # kernel/baseline chain profile (comps ignored) + paid=Counter(rep['local_profile']) + # remove climbs saved for gauge helpers: recompute their chains with start E + A,B=w['A'],w['B'];P=w['ports'];R=w['report']['R'];n=240+R + # recompute full chain simulation with gauge starts and target levels + col,first=__import__('kern').setup(w) + supp={h:set(col[h]) for h in range(R)} + lev={t:() for t in range(v)} + for h,E in gauge.items(): + for t in supp[h]: + if len(E)>len(lev[t]): + assert span(lev[t])<=span(E) + lev[t]=E + st={} + for h,E in start_kernel.items():st[h]=E + cur={} + for r in range(n): + if r top served level -> ... -> lowest served level (mass-neutral descent) + for r,f in zip(ce,cf): + f=basis(list(f)) + tl={lev[e[1]-v] for e in w['cut'] if e[2]==r} + path=sorted(tl,key=lambda L:-len(L)) + o=f + for L in path: + assert basis(list(L)+list(o))==o,('centre frame does not contain served level',r,L,o) + if L!=o:paid[len(o)-len(L)]+=1;o=L + for e in seq: + for r in ([e[1]]+([e[2]] if e[0]=='add' else [])):climb(r,e[-1]) + for r in range(n):climb(r,FULL if (r=2*v) else perp(P[r-v])) + widths=[9-len(gauge.get(h,st.get(2*v+h,()))) for h in range(R)] + return dict(sorted(paid.items())),widths +if __name__=='__main__': + w=load();w['R']=w['report']['R'] + sc,flag,per=pickle.load(open('flag_best.pkl','rb')) + col,first,cap,cands,P=prep(w);R=len(col) + gauge={} + for h,k in per.items(): + if k>0: + E=[F for F in flag if len(F)==k][0];gauge[h]=E + prof,widths=gauge_profile(w,(),{},gauge,flag) + print('gauge helpers',len(gauge),'eps',sum(len(E) for E in gauge.values()),'profile',prof) + r0=HM.evaluate({1:1912,2:784,3:168,4:224,5:392,8:24},[9]*560) + r=HM.evaluate(prof,widths) + print('b',r['b'],'%+.3f%%'%(100*(r['b']/r0['b']-1)),r['W'],r['banks']) diff --git a/research/e8-complex-gauge-kernel/code/gauge3.py b/research/e8-complex-gauge-kernel/code/gauge3.py new file mode 100644 index 0000000000..5b17140c0c --- /dev/null +++ b/research/e8-complex-gauge-kernel/code/gauge3.py @@ -0,0 +1,53 @@ +"""per-target nested + per-centre chain gauge assignment (greedy / SA-lite)""" +from gauge import * +import random,pickle +def setup_g(w): + col,first,cap,cands,P=prep(w);R=len(col) + served={} + for i,r in enumerate(w['centers']): + served[i]=sorted({e[1]-v for e in w['cut'] if e[2]==r}) + cf=[span(f) for f in w['center_frames']] + tcent=defaultdict(list) + for i,ts in served.items(): + for t in ts:tcent[t].append(i) + return col,first,cap,cands,P,served,cf,tcent +def greedy_g(col,cands,served,cf,tcent,order,minrank=1): + R=len(col) + L={t:frozenset({0}) for t in range(v)} # span sets of current level + Lall={t:[] for t in range(v)} + Lb={t:() for t in range(v)} + E_of={};eps=0 + for h in order: + for E in cands[h]: + sE=span(E) + ok=True;newL={} + for t in col[h]: + cur=L[t] + if not all(sE<=c or c<=sE for c in Lall[t]):ok=False;break + newL[t]=sE if len(sE)>len(cur) else cur + if not ok:continue + # centre chains + containment in cf + cs={i for t in newL for i in tcent[t]} + for i in cs: + levels=[newL.get(u,L[u]) for u in served[i]] + top=max(levels,key=len) + if not all(a<=b or b<=a for a in set(levels) for b in set(levels)):ok=False;break + if not top<=cf[i]:ok=False;break + if not ok:continue + E_of[h]=E;eps+=len(E) + for t,s in newL.items(): + L[t]=s;Lb[t]=E if len(s)>len(span(Lb[t])) else Lb[t] + for t in col[h]:Lall[t].append(sE) + break + return E_of,eps +if __name__=='__main__': + w=load();w['R']=w['report']['R'] + col,first,cap,cands,P,served,cf,tcent=setup_g(w);R=len(col) + print('centres served sizes',[len(served[i]) for i in served]) + best=(0,None) + for seed in range(300): + rnd=random.Random(seed);order=list(range(R));rnd.shuffle(order) + if seed%3==0:order.sort(key=lambda h:len(col[h])) + E_of,eps=greedy_g(col,cands,served,cf,tcent,order) + if eps>best[0]:best=(eps,E_of);print(seed,eps,len(E_of),Counter(len(E) for E in E_of.values()),flush=True) + pickle.dump(best,open('gauge3_best.pkl','wb')) diff --git a/research/e8-complex-gauge-kernel/code/gauge4.py b/research/e8-complex-gauge-kernel/code/gauge4.py new file mode 100644 index 0000000000..f1be84aba6 --- /dev/null +++ b/research/e8-complex-gauge-kernel/code/gauge4.py @@ -0,0 +1,53 @@ +from gauge3 import * +import time +def state_from(E_of,col,tcent,served,cf): + pass +def refill(col,cands,served,cf,tcent,E_of,drop,rnd): + keep={h:E for h,E in E_of.items() if h not in drop} + R=len(col) + # rebuild L from keep + L={t:frozenset({0}) for t in range(v)} + Lall={t:[] for t in range(v)} + for h,E in keep.items(): + sE=span(E) + for t in col[h]: + Lall[t].append(sE) + if len(sE)>len(L[t]):L[t]=sE + cur=dict(keep);eps=sum(len(E) for E in keep.values()) + order=[h for h in range(R) if h not in keep];rnd.shuffle(order) + for h in order: + for E in cands[h]: + sE=span(E);ok=True;newL={} + for t in col[h]: + c=L[t] + if not all(sE<=x or x<=sE for x in Lall[t]):ok=False;break + newL[t]=sE if len(sE)>len(c) else c + if not ok:continue + cs={i for t in newL for i in tcent[t]} + for i in cs: + levels=[newL.get(u,L[u]) for u in served[i]] + top=max(levels,key=len) + if not all(a<=b or b<=a for a in set(levels) for b in set(levels)) or not top<=cf[i]:ok=False;break + if not ok:continue + cur[h]=E;eps+=len(E) + for t,s in newL.items():L[t]=s + for t in col[h]:Lall[t].append(sE) + break + return cur,eps +if __name__=='__main__': + import sys + seed=int(sys.argv[1]);iters=int(sys.argv[2]) + w=load();w['R']=w['report']['R'] + col,first,cap,cands,P,served,cf,tcent=setup_g(w);R=len(col) + eps0,E_of=pickle.load(open('gauge3_best.pkl','rb')) + rnd=random.Random(seed);best=(eps0,E_of);t0=time.time() + cands_h=[h for h in range(R) if cands[h]] + for it in range(iters): + cur=best[1] + drop=set(rnd.sample(list(cur),max(1,int(len(cur)*rnd.choice([0.05,0.1,0.2,0.4]))))) + n,e=refill(col,cands,served,cf,tcent,cur,drop,rnd) + if e>=best[0]: + if e>best[0]:print(it,e,len(n),Counter(len(E) for E in n.values()),round(time.time()-t0),flush=True) + best=(e,n) + pickle.dump(best,open('gauge4_best_%d.pkl'%seed,'wb')) + print('final',best[0]) diff --git a/research/e8-complex-gauge-kernel/code/hostmodel.py b/research/e8-complex-gauge-kernel/code/hostmodel.py new file mode 100644 index 0000000000..6d7723269d --- /dev/null +++ b/research/e8-complex-gauge-kernel/code/hostmodel.py @@ -0,0 +1,88 @@ +"""Hosted complex model: replicates idle-axis-hosting/complex_hosted.py profile arithmetic for arbitrary local paid profile +and per-helper residual widths (same for every stage/replica). Needs scipy (venv python).""" +import gzip,json,sys,math,importlib.util,time +from collections import Counter +from pathlib import Path +from fractions import Fraction as Q +import os +CX=os.environ['CXG_BASE'];REPO=os.environ.get('CXG_REPO','.') +sys.path.insert(0,REPO+'/research/idle-axis-hosting') +import hosting_core as HC +V,K,T,L,M=120,4,8,9,73 +DATA=2*K*V*T +PAR=Path(CX+'/parent/changed') +_t=json.loads(gzip.decompress((PAR/'split-centres/GLOBAL-TEMPLATE.json.gz').read_bytes())) +def _eng(name): + sp=importlib.util.spec_from_file_location('h_'+name,PAR/'work/pr361/code/engines'/(name+'.py'));mod=importlib.util.module_from_spec(sp);sp.loader.exec_module(mod);return mod +ENG=_eng('moment') +rank={};pair_of_stage={e['stage']:e['pair'] for e in _t['recipe'] if e['kind']=='local'} +sched=[];side_of={};pair_of={} +for it in _t['idle_children']:rank.setdefault(it['child'],it['rank']) +for e in _t['execution_schedule']: + if e['kind']=='local_cover_sweep':sched.append(dict(kind='local',stage=e['stage'],pair=pair_of_stage[e['stage']])) + elif e['kind']=='bridge':sched.append(dict(kind='bridge',dst=e['dst'],src=e['src'])) + elif e['kind']=='idle_cover_sweep': + for sd,ch in enumerate(e['child_indices']): + if ch in rank:sched.append(dict(kind='idle',pair=e['pair'],rank=rank[ch],idx=ch));side_of[ch]=sd;pair_of[ch]=e['pair'] +WINALL=HC.windows(sched) +IDLE=_t['idle_children'] +def evaluate(local_profile,widths,discover=True,sel=None,verbose=False,pad_val=None,exact=False): + """local_profile: {rank:count per call}; widths: list of residual widths (len R) -> dict(b,W,profile)""" + R=len(widths);wmin=min(widths) + win={k:x for k,x in WINALL.items() if x[1]>=wmin and x[2]} + cnt=Counter(widths) + avail={(s,w):c for s in range(L) for w,c in cnt.items()} + # identify helper ids per width + hl={}; + ids=sorted(range(R),key=lambda h:(-widths[h],h)) + helpers={s:[(h,widths[h]) for h in ids] for s in range(L)} + if discover: + ys,zs,val=HC.solve(win,V,avail,M,pad_value=(HC.cost(1,M)/8 if pad_val is None else pad_val)) + else:ys,zs,val=sel + slots,rem=HC.expand(win,ys,zs,helpers,V) + hosted={(s,h) for i,port,off,w,s,h in slots} # per replica? slots are per (idx,copy) -> one replica set + hosted_cnt=Counter((s,h) for i,c,o,w,s,h in slots) + # each slot hosts replicas T times (same for all replicas) + base=DATA;partial=Counter();banks=[] + paid=Counter() + W=DATA + for s in range(L): + left=[(rep,h) for rep in range(T) for h in range(R) if (s,h) not in {(s2,h2) for (_,_,_,_,s2,h2) in []}] + # build hosted set + hset={(s,h) for (_,_,_,_,s,h) in slots} + for s in range(L): + items=sorted([widths[h] for rep in range(T) for h in range(R) if (s,h) not in hset],reverse=True) + bins=[] + for w in items: + for i,b in enumerate(bins): + if b+w<=M:bins[i]+=w;break + else:bins.append(w) + W+=len(bins);banks.append(len(bins)) + for b in bins: + if M-b:paid[M-b]+=1 + for r_,z in local_profile.items():paid[int(r_)]+=int(z)*L*T + nid=0 + for it in IDLE: + ch,port=it['child'],it['port'];rr=rem.get((ch,port),it['rank']) if ch in win else it['rank'] + if rr:paid[rr]+=T + mass=sum(r*z for r,z in paid.items());D=M*W-mass + out=dict(W=W,D=D,profile=dict(sorted(paid.items())),hosted=len(slots)*T,banks=banks,val=val,sel=(ys,zs,val)) + if exact: + rc=ENG.certify({int(r):n for r,n in paid.items()},M,W,True);out['b']=float(Q(int(Q(rc['lower'])*10**18),10**18)) + else:out['b']=float(bfloat(paid,W)) + return out +def bfloat(paid,W,m=M): + lo,hi=0.,.01 + for _ in range(80): + q=(lo+hi)/2 + mom=sum(r*z/(m*W)*(m/r)**q for r,z in paid.items())+32*m*sum(paid.values())/(10**16*W)*m**q + if mom<1:lo=q + else:hi=q + return (lo+hi)/2 +if __name__=='__main__': + t0=time.time() + loc={1:1912,2:784,3:168,4:224,5:392,8:24} + r=evaluate(loc,[9]*560,discover=False,sel=HC.load_selection(REPO+'/research/idle-axis-hosting/SELECTION.json','complex'),exact=True) + print('frozen sel:',r['W'],r['D'],r['b'],r['banks'],r['hosted'],time.time()-t0) + r=evaluate(loc,[9]*560,discover=True,exact=True) + print('discover:',r['W'],r['D'],r['b'],r['banks'],r['hosted'],time.time()-t0) diff --git a/research/e8-complex-gauge-kernel/code/iso1.py b/research/e8-complex-gauge-kernel/code/iso1.py new file mode 100644 index 0000000000..715255d443 --- /dev/null +++ b/research/e8-complex-gauge-kernel/code/iso1.py @@ -0,0 +1,53 @@ +from kern import * +import numpy as np +def gram(E): + return [[bin(a&b).count('1')&1 for b in E] for a in E] +def det2(G): + n=len(G);M=[r[:] for r in G] + for c in range(n): + p=next((i for i in range(c,n) if M[i][c]),None) + if p is None:return 0 + M[c],M[p]=M[p],M[c] + for i in range(n): + if i!=c and M[i][c]:M[i]=[x^y for x,y in zip(M[i],M[c])] + return 1 +def spanvecs(E): + s={0} + for b in E:s|={x^b for x in s} + return s +ONE=511 +def isometric(E): + """E has orthonormal basis and E^perp (in F2^9) too""" + if not E:return True + if not det2(gram(E)):return False + S=spanvecs(E) + if ONE in S:return False # complement alternating + if all(bin(x).count('1')%2==0 for x in S):return False # E alternating + # E^perp contains ONE? ONE in E^perp iff all vectors of E even-weight -> excluded above + return True +if __name__=='__main__': + w=load();col,first=setup(w);R=len(col) + # which first-frame subspaces are isometric + cand={} + for h,F in first.items(): + for E in subspaces(F):cand.setdefault(E,[]).append(h) + iso={E:G for E,G in cand.items() if isometric(E)} + print('first-frame subspaces',len(cand),'isometric',len(iso),Counter(len(E) for E in iso)) + C=np.zeros((v,R)) + for h in range(R): + for t,x in col[h].items():C[t,h]=float(x) + pot=[] + for E,G in iso.items(): + if len(G)>=2: + rk=np.linalg.matrix_rank(C[:,G]); + if len(G)-rk>0:pot.append((len(E)*(len(G)-rk),E,len(G),rk)) + print('kernel potentials with isometric E',sorted(pot,reverse=True)[:10]) + # gauge: eligible helpers per isometric E + from gauge import prep,span + col2,first2,cap,cands,P=prep(w) + best=[] + for E in iso: + sE=span(E) + el=[h for h in range(R) if sE<=span(first2[h]) and all(sE<=cap[t] for t in col2[h])] + best.append((len(E)*len(el),len(el),E)) + best.sort(reverse=True);print('gauge best isometric E (eps,n,E)',best[:8]) diff --git a/research/e8-complex-gauge-kernel/code/kcap.py b/research/e8-complex-gauge-kernel/code/kcap.py new file mode 100644 index 0000000000..37e9724fcc --- /dev/null +++ b/research/e8-complex-gauge-kernel/code/kcap.py @@ -0,0 +1,13 @@ +from fractions import Fraction as Q +def kappa_of(s_in,eta=Q(1,10**18),beta=Q(1,10**18)): + s=Q(s_in)-Q(1,10**24) + a=Q(384599,10**10) + for _ in range(6):a=(1-s)*s+s*a + q=a*(1-2*eta);margin=(1-eta)*q/(1+q);grid=Q(1,10**18);ticks=margin/grid + return grid*((ticks.numerator-1)//ticks.denominator) +def cap_from_b(b):return float(kappa_of((1-Q(1,10**18))*Q(b))) +if __name__=='__main__': + c=Q('1239085165241180038597')/Q(10**24) + print('check kappa(c bit)',float(kappa_of(c)),'expected 0.001237551733247294') + for name,b in (('baseline cx hosted',1.267453159029119e-3),('kernel77',1.309121737234019e-3),('gauge70+kernel44 (model)',1.329163e-3)): + print(name,'b',b,'kappa cap',cap_from_b(Q(b).limit_denominator(10**18))) diff --git a/research/e8-complex-gauge-kernel/code/kern.py b/research/e8-complex-gauge-kernel/code/kern.py new file mode 100644 index 0000000000..3ca9dfeb0d --- /dev/null +++ b/research/e8-complex-gauge-kernel/code/kern.py @@ -0,0 +1,53 @@ +from cxlab import * +import numpy as np, itertools, sys +def subspaces(F): + """all nonzero subspaces of span(F) as canonical bases, any rank""" + F=list(F);k=len(F);out=set() + vecs=[] + for mask in range(1,1<>i&1:x^=F[i] + vecs.append(x) + # enumerate subspaces by generating from subsets of vectors up to rank k + seen=set() + def rec(cur,start): + for i in range(start,len(vecs)): + b=basis(list(cur)+[vecs[i]]) + if len(b)==len(cur)+1 and b not in seen: + seen.add(b);rec(b,i+1) + rec((),0) + return seen +def setup(w): + A,B=w['A'],w['B'];n=240+w['report']['R'];R=w['report']['R'] + M=ident(n) + for e in A+w['cut']+B:apply(e,M) + dirty=[{} for r in range(n)] + for r in range(v,2*v):dirty[r]={j:x for j,x in M[r].items() if j>=2*v} + for e in w['precondition']:apply(e,dirty) + col=[dict() for _ in range(R)] + for r in range(v,2*v): + for j,x in dirty[r].items():col[j-2*v][r-v]=x + first={} + for seq in (A,B): + for e in seq: + F=basis(e[-1]) + for r in ([e[1]]+([e[2]] if e[0]=='add' else [])): + if r>=2*v:first.setdefault(r-2*v,F) + return col,first +if __name__=='__main__': + w=load();col,first=setup(w);R=len(col) + cand={} + for h,F in first.items(): + for E in subspaces(F):cand.setdefault(E,[]).append(h) + print('first-frame subspaces',len(cand),Counter(len(E) for E in cand)) + C=np.zeros((v,R)) + for h in range(R): + for t,x in col[h].items():C[t,h]=float(x) + pot=[] + for E,G in cand.items(): + if len(G)<2:continue + rk=np.linalg.matrix_rank(C[:,G]);pot.append((len(E)*(len(G)-rk),E,len(G),rk)) + pot.sort(reverse=True) + print('E with positive potential',sum(1 for p in pot if p[0]>0),Counter((len(p[1]),p[2]-p[3]) for p in pot if p[0]>0)) + print(pot[:5]) diff --git a/research/e8-complex-gauge-kernel/code/kern2.py b/research/e8-complex-gauge-kernel/code/kern2.py new file mode 100644 index 0000000000..23ac0ea211 --- /dev/null +++ b/research/e8-complex-gauge-kernel/code/kern2.py @@ -0,0 +1,43 @@ +from kern import * +from cxcheck import check +import hostmodel as HM +def span(F): + s={0} + for b in F:s|={x^b for x in s} + return s +def dup_pairs(col): + key=defaultdict(list) + for h,c in enumerate(col): + if not c:continue + ts=sorted(c);f=c[ts[0]] + key[tuple((t,c[t]/f) for t in ts)].append(h) + out=[] + for g in key.values(): + if len(g)==2:out.append(tuple(g)) + return out +def build_pre(col,plan,first): + """plan: list of (pivot, donor, E_basis_tuple) with proportional columns. returns pre ops (register ids absolute) and start dict""" + pre=[];start={} + for p,d,E in sorted(plan,key=lambda x:len(x[2])): + cp,cd=col[p],col[d] + t0=sorted(cd)[0];c=cp[t0]/cd[t0] + assert all(cp.get(t,0)==c*cd.get(t,0) for t in set(cp)|set(cd)) + q=-c + pre.append(['add',2*v+d,2*v+p,q.numerator,q.denominator,list(E)]) + start[2*v+p]=list(E) + return pre,start +if __name__=='__main__': + w=load();w['R']=w['report']['R'];col,first=setup(w) + base,_=check(w);print('base profile',base['local_profile']) + pairs=dup_pairs(col);print(len(pairs)) + plan=[] + for a,b in pairs: + I=span(first[a])&span(first[b]);x=[y for y in I if y] + assert len(x)==1 + plan.append((a,b,(x[0],))) + pre,start=build_pre(col,plan,first) + rep,edges=check(w,pre=pre,start=start) + print('exact ok',rep.get('exact_arbitrary_dirt'),rep['exact_inverse_transpose'],'comp cols',rep['comp_cols'],'profile',rep['local_profile'],'sumwidth',sum(rep['widths'])) + r0=HM.evaluate({1:1912,2:784,3:168,4:224,5:392,8:24},[9]*560) + r=HM.evaluate(rep['local_profile'],rep['widths']) + print('b base',r0['b'],'b kernel56',r['b'],'%+.3f%%'%(100*(r['b']/r0['b']-1)),'W',r['W'],r['banks']) diff --git a/research/e8-complex-gauge-kernel/code/kern3.py b/research/e8-complex-gauge-kernel/code/kern3.py new file mode 100644 index 0000000000..eaf0ff7d28 --- /dev/null +++ b/research/e8-complex-gauge-kernel/code/kern3.py @@ -0,0 +1,73 @@ +"""General exact kernel (shared-donor) for the complex word: partition helpers by rank-1 entrance E; donors independent, pivots dependent.""" +from kern2 import * +import itertools,random +def solve_rel(col,donors,p): + """exact rational coefficients c_d with col[p]=sum c_d col[d] (or None)""" + cols=sorted({t for d in donors for t in col[d]}|set(col[p])) + if not cols:return {} + idx={t:i for i,t in enumerate(cols)} + M=[[Q(0)]*(len(donors)+1) for _ in cols] + for ci,d in enumerate(donors): + for t,x in col[d].items():M[idx[t]][ci]=x + for t,x in col[p].items():M[idx[t]][-1]=x + piv=[];r=0 + for c in range(len(donors)): + pr=next((i for i in range(r,len(M)) if M[i][c]),None) + if pr is None:continue + M[r],M[pr]=M[pr],M[r];q=M[r][c];M[r]=[x/q for x in M[r]] + for i in range(len(M)): + if i!=r and M[i][c]: + f=M[i][c];M[i]=[a-f*b for a,b in zip(M[i],M[r])] + piv.append(c);r+=1 + for i in range(r,len(M)): + if M[i][-1]:return None + return {donors[c]:M[i][-1] for i,c in enumerate(piv) if M[i][-1]} +def plan_greedy(col,first,seed=0,minE=1): + R=len(col) + cand={} + for h,F in first.items(): + for E in subspaces(F):cand.setdefault(E,[]).append(h) + C=np.zeros((v,R)) + for h in range(R): + for t,x in col[h].items():C[t,h]=float(x) + Es=[E for E,G in cand.items() if len(G)>=2 and len(G)-np.linalg.matrix_rank(C[:,G])>0] + free=set(range(R));groups=[] + while True: + best=None + for E in Es: + G=[h for h in cand[E] if h in free] + if len(G)<2:continue + rk=np.linalg.matrix_rank(C[:,G]);pv=len(G)-rk + val=pv*len(E) + if best is None or val>best[0]:best=(val,E,G) + if not best or best[0]<=0:break + val,E,G=best + # donors: greedy independent in order of G; pivots rest + donors=[];rows=np.zeros((v,0)) + for h in sorted(G): + c=C[:,h:h+1] + if np.linalg.matrix_rank(np.hstack([rows,c]))>rows.shape[1]:rows=np.hstack([rows,c]);donors.append(h) + pivots=[h for h in G if h not in donors] + groups.append((E,donors,pivots));free-=set(G) + return groups +def groups_to_pre(col,groups): + pre=[];start={};eps=0 + for E,donors,pivots in sorted(groups,key=lambda g:len(g[0])): + for p in pivots: + rel=solve_rel(col,donors,p) + assert rel is not None,(E,p) + start[2*v+p]=list(E);eps+=len(E) + for d,c in rel.items(): + q=-c;pre.append(['add',2*v+d,2*v+p,q.numerator,q.denominator,list(E)]) + return pre,start,eps +if __name__=='__main__': + w=load();w['R']=w['report']['R'];col,first=setup(w) + groups=plan_greedy(col,first) + print([(E,len(d),len(p)) for E,d,p in groups]) + pre,start,eps=groups_to_pre(col,groups) + print('pre ops',len(pre),'eps',eps) + rep,edges=check(w,pre=pre,start=start) + print('exact',rep['exact_arbitrary_dirt'],rep['exact_inverse_transpose'],rep['local_profile'],'sumwidth',sum(rep['widths']),'newedges',len(edges)) + r=HM.evaluate(rep['local_profile'],rep['widths']) + r0=HM.evaluate({1:1912,2:784,3:168,4:224,5:392,8:24},[9]*560) + print('b',r['b'],'%+.3f%%'%(100*(r['b']/r0['b']-1)),'W',r['W'],r['banks']) diff --git a/research/e8-complex-gauge-kernel/code/kern4.py b/research/e8-complex-gauge-kernel/code/kern4.py new file mode 100644 index 0000000000..04d7cec6e3 --- /dev/null +++ b/research/e8-complex-gauge-kernel/code/kern4.py @@ -0,0 +1,46 @@ +from kern3 import * +def rand_plan(col,first,C,cand,Es,rnd): + R=len(col);free=set(range(R));groups=[] + Eorder=Es[:] + while True: + opts=[] + for E in Eorder: + G=[h for h in cand[E] if h in free] + if len(G)<2:continue + rk=np.linalg.matrix_rank(C[:,G]);pv=len(G)-rk + if pv>0:opts.append((pv,E,G)) + if not opts:break + # pick randomly weighted by pivots + tot=sum(o[0] for o in opts);x=rnd.random()*tot;acc=0 + for o in opts: + acc+=o[0] + if acc>=x:pick=o;break + pv,E,G=pick + donors=[];rows=np.zeros((v,0));Gs=G[:];rnd.shuffle(Gs) + for h in Gs: + c=C[:,h:h+1] + if np.linalg.matrix_rank(np.hstack([rows,c]))>rows.shape[1]:rows=np.hstack([rows,c]);donors.append(h) + pivots=[h for h in G if h not in donors] + groups.append((E,donors,pivots));free-=set(G) + # completion: free helpers that can pivot onto existing classes + for h in sorted(free): + for gi,(E,donors,pivots) in enumerate(groups): + if not span(E)<=span(first[h]):continue + M=np.hstack([C[:,donors],C[:,h:h+1]]) + if np.linalg.matrix_rank(M)==len(donors):pivots.append(h);free.discard(h);break + return groups +if __name__=='__main__': + w=load();w['R']=w['report']['R'];col,first=setup(w);R=len(col) + cand={} + for h,F in first.items(): + for E in subspaces(F):cand.setdefault(E,[]).append(h) + C=np.zeros((v,R)) + for h in range(R): + for t,x in col[h].items():C[t,h]=float(x) + Es=[E for E,G in cand.items() if len(G)>=2 and len(G)-np.linalg.matrix_rank(C[:,G])>0] + best=0;bg=None + for seed in range(300): + rnd=random.Random(seed);g=rand_plan(col,first,C,cand,Es,rnd) + tot=sum(len(p)*len(E) for E,d,p in g) + if tot>best:best=tot;bg=g;print(seed,tot,[(E[0],len(d),len(p)) for E,d,p in g],flush=True) + import pickle;pickle.dump(bg,open('kern4_best.pkl','wb')) diff --git a/research/e8-complex-gauge-kernel/code/kern5.py b/research/e8-complex-gauge-kernel/code/kern5.py new file mode 100644 index 0000000000..5064b882cc --- /dev/null +++ b/research/e8-complex-gauge-kernel/code/kern5.py @@ -0,0 +1,50 @@ +from kern4 import * +import math,pickle,time +def nullity(C,S): + return len(S)-(np.linalg.matrix_rank(C[:,sorted(S)],tol=1e-8) if S else 0) +def sa(col,first,C,cand,Es,iters=30000,seed=0,init=None,T0=0.6): + rnd=random.Random(seed);big=sorted({h for E in Es for h in cand[E]}) + allowed={h:[E for E in Es if h in set(cand[E])] for h in big} + cls={E:set() for E in Es};asg={} + if init: + for E,d,p in init: + for h in d+p: + if E in cls:cls[E].add(h);asg[h]=E + val={E:nullity(C,cls[E]) for E in Es} + cur=sum(val.values());best=cur;bestasg=dict(asg);t0=time.time() + for it in range(iters): + T=T0*(1-it/iters)+0.02 + h=rnd.choice(big);old=asg.get(h) + choices=allowed[h]+[None] + new=rnd.choice(choices) + if new==old:continue + dv=0;newvals={} + if old is not None: + S=cls[old]-{h};nv=nullity(C,S);newvals[old]=nv;dv+=nv-val[old] + if new is not None: + S=cls[new]|{h};nv=nullity(C,S);newvals[new]=nv;dv+=nv-val[new] + if dv>=0 or rnd.random()best:best=cur;bestasg=dict(asg) + return best,bestasg +if __name__=='__main__': + w=load();w['R']=w['report']['R'];col,first=setup(w);R=len(col) + cand={} + for h,F in first.items(): + for E in subspaces(F):cand.setdefault(E,[]).append(h) + C=np.zeros((v,R)) + for h in range(R): + for t,x in col[h].items():C[t,h]=float(x) + Es=[E for E,G in cand.items() if len(G)>=2 and len(G)-np.linalg.matrix_rank(C[:,G])>0] + init=pickle.load(open('kern4_best.pkl','rb')) + print('init',sum(len(p) for E,d,p in init)) + b0=None + for seed in range(4): + best,asg=sa(col,first,C,cand,Es,iters=40000,seed=seed,init=init) + print('seed',seed,'best nullity sum',best,flush=True) + if b0 is None or best>b0[0]:b0=(best,asg) + pickle.dump(b0,open('kern5_best.pkl','wb')) diff --git a/research/e8-complex-gauge-kernel/code/kern6.py b/research/e8-complex-gauge-kernel/code/kern6.py new file mode 100644 index 0000000000..e2699ebaff --- /dev/null +++ b/research/e8-complex-gauge-kernel/code/kern6.py @@ -0,0 +1,29 @@ +from kern5 import * +def asg_to_groups(C,asg): + cls={} + for h,E in asg.items():cls.setdefault(E,[]).append(h) + groups=[] + for E,G in cls.items(): + G=sorted(G);donors=[];rows=np.zeros((v,0)) + for h in G: + c=C[:,h:h+1] + if np.linalg.matrix_rank(np.hstack([rows,c]),tol=1e-8)>rows.shape[1]:rows=np.hstack([rows,c]);donors.append(h) + pivots=[h for h in G if h not in donors] + if pivots:groups.append((E,donors,pivots)) + return groups +if __name__=='__main__': + w=load();w['R']=w['report']['R'];col,first=setup(w);R=len(col) + C=np.zeros((v,R)) + for h in range(R): + for t,x in col[h].items():C[t,h]=float(x) + best,asg=pickle.load(open('kern5_best.pkl','rb')) + groups=asg_to_groups(C,asg) + print([(E[0],len(d),len(p)) for E,d,p in groups]) + pre,start,eps=groups_to_pre(col,groups) + print('pre ops',len(pre),'eps',eps) + rep,edges=check(w,pre=pre,start=start) + print('exact',rep['exact_arbitrary_dirt'],rep['exact_inverse_transpose'],rep['local_profile'],'sumwidth',sum(rep['widths']),'newedges',len(edges)) + r=HM.evaluate(rep['local_profile'],rep['widths'],exact=True) + r0=HM.evaluate({1:1912,2:784,3:168,4:224,5:392,8:24},[9]*560,exact=True) + print('b',r['b'],'%+.3f%%'%(100*(r['b']/r0['b']-1)),'W',r['W'],r['banks'],'hosted',r['hosted']) + pickle.dump((pre,start),open('kern6_word.pkl','wb')) diff --git a/research/e8-complex-gauge-kernel/code/mkword.py b/research/e8-complex-gauge-kernel/code/mkword.py new file mode 100644 index 0000000000..1d6c1b51c8 --- /dev/null +++ b/research/e8-complex-gauge-kernel/code/mkword.py @@ -0,0 +1,26 @@ +"""Write a modified FULL-WORD.json.gz (kernel variant): A = pre + A, cleanup rebuilt, start_extra for pivots, report updated.""" +import gzip,json,sys,pickle,os +from cxlab import * +from cxcheck import check,FULL +def mkword(w,pre,start,outdir): + w2=copy.deepcopy(w) + w2['R']=w['report']['R'] + rep,edges=check(w,pre=pre,start=start,full=True) + w2['A']=[list(e) for e in pre]+w2['A'] + # cleanup: inverse of non-target ops of A+B reversed at FULL + cl=[] + for e in reversed(w2['A']+w2['B']): + if not v<=e[1]<2*v: + c=inv(e);c[-1]=list(FULL);cl.append(c) + w2['cleanup']=cl + w2['start_extra']={str(r):list(E) for r,E in start.items()} + w2['report']['local_profile']={str(k):x for k,x in rep['local_profile'].items()} + w2['report']['pivots']=len(start);w2['report']['entrance_rank']=sum(len(E) for E in start.values()) + os.makedirs(outdir,exist_ok=True) + (open(outdir+'/FULL-WORD.json.gz','wb')).write(gzip.compress(json.dumps(w2,sort_keys=True,separators=(',',':')).encode(),mtime=0)) + return rep +if __name__=='__main__': + w=load() + pre,start=pickle.load(open('kern6_word.pkl','rb')) + rep=mkword(w,pre,start,sys.argv[1]) + print('written',rep['local_profile'],len(pre),len(start)) diff --git a/research/e8-complex-gauge-kernel/code/mkword_gauge.py b/research/e8-complex-gauge-kernel/code/mkword_gauge.py new file mode 100644 index 0000000000..a92d986dab --- /dev/null +++ b/research/e8-complex-gauge-kernel/code/mkword_gauge.py @@ -0,0 +1,30 @@ +import gzip,json,sys,pickle,os +from cxlab import * +from cxcheck import check,FULL +from kern import setup +def mkword_gauge(w,pre,start_k,gauge,outdir): + w2=copy.deepcopy(w);R=w['report']['R'];w2['R']=R + col,first=setup(w) + gc=[] + for h,E in sorted(gauge.items(),key=lambda kv:(len(kv[1]),kv[0])): + for t,x in sorted(col[h].items()): + c=-x;gc.append(['add',v+t,2*v+h,c.numerator,c.denominator,list(E)]) + lev={t:() for t in range(v)} + for h,E in gauge.items(): + for t in col[h]: + if len(E)>len(lev[t]):lev[t]=E + w2['A']=gc+[list(e) for e in pre]+w2['A'] + cl=[] + for e in reversed(w2['A']+w2['B']): + if not v<=e[1]<2*v: + c=inv(e);c[-1]=list(FULL);cl.append(c) + w2['cleanup']=cl + st=dict(start_k);st.update({2*v+h:E for h,E in gauge.items()}) + w2['start_extra']={str(r):list(E) for r,E in st.items()} + w2['target_levels']={str(t):list(E) for t,E in lev.items() if E} + from gauge2 import gauge_profile + prof,widths=gauge_profile(w,pre,start_k,gauge,None) + w2['report']['local_profile']={str(k):x for k,x in prof.items()} + os.makedirs(outdir,exist_ok=True) + open(outdir+'/FULL-WORD.json.gz','wb').write(gzip.compress(json.dumps(w2,sort_keys=True,separators=(',',':')).encode(),mtime=0)) + return w2 diff --git a/research/e8-complex-gauge-kernel/code/nec3.py b/research/e8-complex-gauge-kernel/code/nec3.py new file mode 100644 index 0000000000..4673e03fb0 --- /dev/null +++ b/research/e8-complex-gauge-kernel/code/nec3.py @@ -0,0 +1,15 @@ +import sys +import os +sys.path.insert(0,os.environ['CXG_REPO']+'/research/split-centres-global/vendor') +from clifford_exact import * +n=9 +FULL=tuple(1<=2: + kp+=max(0,len(G)-np.linalg.matrix_rank(C[:,G]))*len(E) +print('relaxed-isometric kernel potential',kp) +col2,first2,cap,cands,P=prep(w) +ge=0 +for E in cand: + if relaxed(E): + sE=span(E);el=[h for h in range(R) if sE<=span(first2[h]) and all(sE<=cap[t] for t in col2[h])] + ge=max(ge,len(el)*len(E)) +print('relaxed-isometric gauge best eps',ge) +# (2) adapter factorisation for every entrance used in v4 +d=json.load(gzip.open(os.path.join(os.environ['CXG_PKG'],'data/words/gauge80-kernel42/FULL-WORD.json.gz'))) +Es={tuple(E) for E in d['start_extra'].values()} +print('distinct entrance frames in v4',len(Es)) +ok=0 +for E in sorted(Es,key=lambda e:(len(e),e)): + op=canonical_frame(n,tuple(E)).adjoint().then(canonical_frame(n,FULL)) + rec,compiled=lower_child(op) + assert rec['rank']==n-len(E) and compiled.tab==op.tab and compiled.zero_state()==op.zero_state() + ok+=1 +print('E->FULL composite = monomial . C_[9-e] . monomial exactly for',ok,'frames (adapters entrance/exit give C_[w] on w coordinates)') diff --git a/research/e8-complex-gauge-kernel/code/phases_cxg.py b/research/e8-complex-gauge-kernel/code/phases_cxg.py new file mode 100644 index 0000000000..b5a5bd64b4 --- /dev/null +++ b/research/e8-complex-gauge-kernel/code/phases_cxg.py @@ -0,0 +1,39 @@ +# Adapted from PR425 for heterogeneous centres by icekylinx with Codex assistance. +"""Exact phase-aware lowering of every used edge of the new structural word.""" +import gzip,hashlib,json,sys,time +from collections import Counter +from pathlib import Path +sys.path.insert(0,str(Path('work/odd-stages').resolve())) +from clifford_exact import * + +OUT=Path('split-centres');P=OUT/'CANONICAL-WORD.json.gz' +c=json.load(gzip.open(P));n=c['h'];frames=c['frames'];start=time.monotonic();ops=[] +for U in frames: + op=canonical_frame(n,U) + L=[u|(u<=2*v) else perp(self.P[r-v]) + self.pos=defaultdict(list) + for i,rs in enumerate(self.regs): + for r in rs:self.pos[r].append(i) + self.mk={} + self.m=m + self.centers_pin={} + # pinned: centre registers final frame within A (last A gate) + for r,f in zip(w['centers'],w['center_frames']): + for i in reversed(self.pos[r]): + if i0 else 0.0 + def chain_cost(self,r,F=None): + """cost of register r's chain with current frames (F: optional override list)""" + F=F or self.F + cur=self.start[r];c=0.0;cnt=Counter() + for i in self.pos[r]: + f=F[i] + if f!=cur: + d=len(f)-len(cur);c+=self.phi(d);cnt[d]+=1;cur=f + f=self.final[r] + if f!=cur: + d=len(f)-len(cur);c+=self.phi(d);cnt[d]+=1 + return c,cnt + def total(self): + c=0.;cnt=Counter() + for r in range(self.n): + a,b=self.chain_cost(r);c+=a;cnt+=b + return c,cnt + def legal(self): + for r in range(self.n): + cur=self.sm(self.start[r]) + for i in self.pos[r]: + f=self.sm(self.F[i]) + if cur&~f:return False,(r,i) + cur=f + if cur&~self.sm(self.final[r]):return False,(r,'final') + return True,None + +def family(W): + fam={} + for F in W.F:fam[W.sm(F)]=tuple(F) + for r in range(W.n): + for F in (W.start[r],W.final[r]):fam[W.sm(F)]=tuple(F) + return fam +def bounds(W,i): + rs=W.regs[i];L=0;U=None + for r in rs: + ps=W.pos[r];k=ps.index(i) + prev=W.F[ps[k-1]] if k>0 else W.start[r] + L|=0 + nxt=W.F[ps[k+1]] if k+10 else W.start[r]) + Lb=basis(Lb) + return Lb,U +def local_cost(W,i,F,rs=None): + rs=rs or W.regs[i];old=W.F[i];W.F[i]=F + c=sum(W.chain_cost(r)[0] for r in rs);W.F[i]=old;return c +def descent(W,fam,seed=0,passes=10,verbose=True): + rnd=random.Random(seed);gates=[i for i in range(len(W.ops)) if i not in W.centers_pin] + famitems=list(fam.items()) + for p in range(passes): + rnd.shuffle(gates);moved=0 + for i in gates: + Lb,U=bounds(W,i);Lm=W.sm(Lb) + cur=W.F[i];best=cur;bc=local_cost(W,i,cur) + for m_,F in famitems: + if m_==W.sm(cur):continue + if Lm&~m_ or m_&~U:continue + c=local_cost(W,i,F) + if c>x&1] + return basis(vs) +def descent2(W,seed=0,passes=10,verbose=True,allow_new=True): + rnd=random.Random(seed);gates=[i for i in range(len(W.ops)) if i not in W.centers_pin] + for p in range(passes): + rnd.shuffle(gates);moved=0 + for i in gates: + Lb,U=bounds(W,i) + cur=W.F[i];best=cur;bc=local_cost(W,i,cur) + cands=[Lb,basis_of_mask(U)] + for F in cands: + if W.sm(F)==W.sm(cur):continue + c=local_cost(W,i,F) + if cframe or None if illegal.""" + ch={i:Fnew};queue=[i] + while queue: + g=queue.pop();Fg=ch[g] + for r in W.regs[g]: + ps=W.pos[r];k=ps.index(g) + if k+1maxn:return None + else: + if W.sm(Fg)&~W.sm(W.final[r]):return None + return ch +def lower_closure(W,i,Fnew,maxn=60): + """set F[i]=Fnew (subframe of F[i]) and cascade lowering on predecessors whose frame must sit inside Fnew.""" + ch={i:Fnew};queue=[i] + while queue: + g=queue.pop();Fg=ch[g] + if g in W.centers_pin and g!=i:return None + for r in W.regs[g]: + ps=W.pos[r];k=ps.index(g) + if k>0: + h=ps[k-1];Fh=ch.get(h,W.F[h]) + if W.sm(Fh)&~W.sm(Fg): + if h in W.centers_pin:return None + nf=basis_of_mask(W.sm(Fh)&W.sm(Fg));ch[h]=nf;queue.append(h) + if len(ch)>maxn:return None + else: + if W.sm(W.start[r])&~W.sm(Fg):return None + return ch +def apply_ch(W,ch): + old={g:W.F[g] for g in ch} + for g,f in ch.items():W.F[g]=f + return old +def delta(W,ch): + regs=set() + for g in ch:regs|=set(W.regs[g]) + before=sum(W.chain_cost(r)[0] for r in regs) + old=apply_ch(W,ch);after=sum(W.chain_cost(r)[0] for r in regs) + for g,f in old.items():W.F[g]=f + return after-before +def closure_descent(W,seed=0,passes=6,verbose=True,maxn=60): + rnd=random.Random(seed);gates=[i for i in range(len(W.ops)) if i not in W.centers_pin] + for p in range(passes): + rnd.shuffle(gates);moved=0 + for i in gates: + best=None;bd=-1e-9 + cands=[] + for r in W.regs[i]: + ps=W.pos[r];k=ps.index(i) + if k+10:cands.append(('l',W.F[ps[k-1]])) + cands.append(('rf',W.final[r])) if k+1==len(ps) else None + for kind,F in cands: + if W.sm(F)==W.sm(W.F[i]):continue + if kind in('r','rf') and not (W.sm(W.F[i])&~W.sm(F)): + ch=raise_closure(W,i,F,maxn) + elif kind=='l' and not (W.sm(F)&~W.sm(W.F[i])): + ch=lower_closure(W,i,F,maxn) + else:continue + if ch is None:continue + d=delta(W,ch) + if d list of (idx, frame) + for i,e in enumerate(ops): + F=basis(e[-1]) if e[-1] is not None else None + for r in ([e[1]]+([e[2]] if e[0]=='add' else [])): + uses[r].append((i,F)) + for r in range(2*v,n): + if uses[r]:first[r]=uses[r][0][0];last[r]=uses[r][-1][0];ffr[r]=uses[r][0][1] if uses[r][0][1] is not None else () + # centres of A->cut etc: cut ops for center frames use None frame -> treated as () + rows=[{r:Q(1)} if r=2*v and (k not in first or first[k]>i+0 and False):pass + if not span(cur[k])<=span(F2):continue + # k's future frames must contain the frame we will force + cands.append(k) + sol=solve(rows[h1],cands,rows) + if sol is None:continue + # frame of reset ops + ok=True + for k in sol: + Fr=basis(list(F1)+list(cur[k])) + if not span(Fr)<=span(F2):ok=False;break + nf=next((fr for (ii,fr) in uses[k] if ii>i and fr is not None),None) + if nf is not None and not span(Fr)<=span(nf):ok=False;break + if ok:out.append((h1,h2,i,sol,F1)) + return out,tl +def rewrite(word,h1,h2,i,sol,tl): + """alias h2 onto h1; insert reset adds after timeline index i""" + w=copy.deepcopy(word);P=w['ports'] + # recompute frames of reset ops: need cur frames at time i -> replay frames only + n=240+(w['R'] if 'R' in w else w['report']['R']) + cur=[()]*n + for r in range(v):cur[r]=(P[r],) + for j,(ph,e) in enumerate(tl): + if j>i:break + if e[-1] is not None: + F=basis(e[-1]) + for r in ([e[1]]+([e[2]] if e[0]=='add' else [])):cur[r]=F + resets=[] + for k,c in sol.items(): + Fr=list(basis(list(cur[h1])+list(cur[k]))) + c=-c + resets.append(['add',h1,k,c.numerator,c.denominator,Fr]) + # split timeline back to lists + lst={'A':[], 'C':[], 'B':[]} + for j,(ph,e) in enumerate(tl): + e=copy.deepcopy(e) + if j>i: + if e[1]==h2:e[1]=h1 + if e[0]=='add' and e[2]==h2:e[2]=h1 + lst[ph].append(e) + if j==i:lst[ph]+=resets + # for ops before i (h2 unused) fine. compact ids: remove h2 + mp={} + R=(w['R'] if 'R' in w else w['report']['R']) + for r in range(n): + if r==h2:continue + mp[r]=r-(1 if r>h2 else 0) + for ph in lst: + for e in lst[ph]: + e[1]=mp[e[1]] + if e[0]=='add':e[2]=mp[e[2]] + w['A'],w['cut'],w['B']=lst['A'],lst['C'],lst['B'] + w['centers']=[mp[r] for r in w['centers']] if all(r!=h2 for r in w['centers']) else None + assert w['centers'] is not None + w['R']=R-1 + return w diff --git a/research/e8-complex-gauge-kernel/code/reuse2.py b/research/e8-complex-gauge-kernel/code/reuse2.py new file mode 100644 index 0000000000..b7ae091dd3 --- /dev/null +++ b/research/e8-complex-gauge-kernel/code/reuse2.py @@ -0,0 +1,79 @@ +from reuse import * +from retime import Word,raise_closure,apply_ch,join as rjoin +from cxcheck import check +import hostmodel as HM +import copy +def repair(w,maxn=400): + """make frame chains legal by raising gate frames (cascade). returns new word or None""" + w=copy.deepcopy(w) + W=Word(w) + for it in range(2000): + bad=None + for r in range(W.n): + cur=W.start[r] + for i in W.pos[r]: + if W.sm(cur)&~W.sm(W.F[i]):bad=(r,i,cur);break + cur=W.F[i] + if bad:break + if not bad: + for i,e in enumerate(W.ops): + (w['A'][i] if i=2 and len(G)-np.linalg.matrix_rank(C[:,G])>0] +init=pickle.load(open('kern4_best.pkl','rb')) +best,asg=sa(col,first,C,cand,Es,iters=iters,seed=seed,init=init,T0=0.5) +print('seed',seed,'best',best,flush=True) +pickle.dump((best,asg),open('sa_long_%d.pkl'%seed,'wb')) diff --git a/research/e8-complex-gauge-kernel/data/final_eval_reference.json b/research/e8-complex-gauge-kernel/data/final_eval_reference.json new file mode 100644 index 0000000000..eaeb796fa7 --- /dev/null +++ b/research/e8-complex-gauge-kernel/data/final_eval_reference.json @@ -0,0 +1,189 @@ +{ + "baseline": { + "b": 0.001267453159029119, + "W": 8400, + "eps": 0 + }, + "k77": { + "b": 0.001309121737234019, + "W": 7977, + "D": 2496, + "eps": 77, + "banks": [ + 143, + 152, + 0, + 1, + 0, + 1, + 0, + 0, + 0 + ], + "hosted": 37944, + "gain": 3.2875832852725217, + "kappa_cap": 0.001307410178150321, + "profile": { + "1": 1979, + "2": 928, + "3": 24, + "4": 224, + "5": 392, + "8": 24 + }, + "maxchild": 9 + }, + "v1": { + "b": 0.001310216366506891, + "W": 7966, + "D": 2496, + "eps": 79, + "banks": [ + 139, + 147, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ], + "hosted": 38032, + "gain": 3.3739477607621415, + "kappa_cap": 0.001308501945841842, + "profile": { + "1": 1981, + "2": 932, + "3": 20, + "4": 224, + "5": 392, + "8": 24 + }, + "maxchild": 8 + }, + "g70": { + "b": 0.001305167273080109, + "W": 7966, + "D": 2496, + "eps": 96, + "banks": [ + 278, + 0, + 0, + 0, + 0, + 0, + 0, + 8, + 0 + ], + "hosted": 38032, + "gain": 2.975582472797589, + "kappa_cap": 0.001303466031873735, + "profile": { + "1": 2003, + "2": 824, + "3": 152, + "4": 276, + "5": 314, + "6": 2, + "7": 1, + "8": 17 + }, + "maxchild": 8 + }, + "v3": { + "b": 0.001328773171067089, + "W": 7724, + "D": 2496, + "eps": 140, + "banks": [ + 44, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ], + "hosted": 39968, + "gain": 4.838049564288571, + "kappa_cap": 0.00132700987594619, + "profile": { + "1": 2055, + "2": 920, + "3": 56, + "4": 276, + "5": 314, + "6": 2, + "7": 1, + "8": 17 + }, + "maxchild": 8 + }, + "g80": { + "b": 0.001310916123494978, + "W": 7912, + "D": 2496, + "eps": 106, + "banks": [ + 232, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ], + "hosted": 38464, + "gain": 3.4291574529785374, + "kappa_cap": 0.001309199872273537, + "profile": { + "1": 2009, + "2": 838, + "3": 140, + "4": 274, + "5": 314, + "6": 2, + "7": 1, + "8": 17 + }, + "maxchild": 8 + }, + "v4": { + "b": 0.001333854156208409, + "W": 7680, + "D": 2496, + "eps": 148, + "banks": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ], + "hosted": 40320, + "gain": 5.2389310568410785, + "kappa_cap": 0.001332077359286333, + "profile": { + "1": 2057, + "2": 928, + "3": 50, + "4": 274, + "5": 314, + "6": 2, + "7": 1, + "8": 17 + }, + "maxchild": 8 + } +} \ No newline at end of file diff --git a/research/e8-complex-gauge-kernel/data/selection/gauge80.json b/research/e8-complex-gauge-kernel/data/selection/gauge80.json new file mode 100644 index 0000000000..93ec6b64d4 --- /dev/null +++ b/research/e8-complex-gauge-kernel/data/selection/gauge80.json @@ -0,0 +1,271 @@ +{ + "kind": "gauge80", + "gauge": { + "553": [ + 510 + ], + "305": [ + 510 + ], + "409": [ + 408 + ], + "278": [ + 510 + ], + "249": [ + 510 + ], + "275": [ + 408, + 102 + ], + "534": [ + 510 + ], + "415": [ + 408 + ], + "277": [ + 510 + ], + "164": [ + 510 + ], + "552": [ + 510 + ], + "193": [ + 510 + ], + "551": [ + 408, + 102 + ], + "250": [ + 510 + ], + "495": [ + 408 + ], + "549": [ + 408, + 102 + ], + "191": [ + 408, + 102 + ], + "194": [ + 510 + ], + "221": [ + 510 + ], + "547": [ + 510 + ], + "546": [ + 510 + ], + "139": [ + 510 + ], + "327": [ + 408 + ], + "550": [ + 408, + 102 + ], + "471": [ + 408 + ], + "279": [ + 510 + ], + "548": [ + 408, + 102 + ], + "248": [ + 510 + ], + "247": [ + 408, + 102 + ], + "276": [ + 510 + ], + "138": [ + 510 + ], + "220": [ + 510 + ], + "306": [ + 510 + ], + "167": [ + 510 + ], + "559": [ + 510 + ], + "494": [ + 408 + ], + "541": [ + 291, + 163, + 102, + 24 + ], + "246": [ + 408, + 102 + ], + "533": [ + 510 + ], + "492": [ + 408 + ], + "195": [ + 510 + ], + "165": [ + 510 + ], + "535": [ + 510 + ], + "408": [ + 408 + ], + "542": [ + 291, + 163, + 102, + 24 + ], + "166": [ + 510 + ], + "538": [ + 408, + 102 + ], + "493": [ + 408 + ], + "223": [ + 510 + ], + "307": [ + 510 + ], + "137": [ + 510 + ], + "326": [ + 408 + ], + "536": [ + 408, + 102 + ], + "470": [ + 408 + ], + "136": [ + 510 + ], + "330": [ + 408 + ], + "251": [ + 510 + ], + "544": [ + 510 + ], + "539": [ + 408, + 102 + ], + "540": [ + 291, + 163, + 102, + 24 + ], + "558": [ + 510 + ], + "556": [ + 510 + ], + "555": [ + 510 + ], + "554": [ + 510 + ], + "465": [ + 408 + ], + "532": [ + 510 + ], + "222": [ + 510 + ], + "414": [ + 408 + ], + "190": [ + 408, + 102 + ], + "464": [ + 408 + ], + "304": [ + 510 + ], + "557": [ + 510 + ], + "192": [ + 510 + ], + "331": [ + 408 + ], + "537": [ + 408, + 102 + ], + "274": [ + 408, + 102 + ], + "545": [ + 510 + ], + "543": [ + 291, + 163, + 102, + 24 + ], + "134": [ + 510 + ], + "135": [ + 510 + ] + } +} \ No newline at end of file diff --git a/research/e8-complex-gauge-kernel/data/selection/kernel79.json b/research/e8-complex-gauge-kernel/data/selection/kernel79.json new file mode 100644 index 0000000000..98ce1c66a4 --- /dev/null +++ b/research/e8-complex-gauge-kernel/data/selection/kernel79.json @@ -0,0 +1,339 @@ +{ + "kind": "kernel79", + "classes": [ + { + "E": [ + 480 + ], + "donors": [ + 134, + 135, + 270, + 271, + 272, + 273, + 298, + 300, + 384, + 390, + 410, + 519, + 536, + 558 + ], + "pivots": [ + 299, + 301, + 385, + 411, + 440, + 441, + 466, + 467 + ] + }, + { + "E": [ + 510 + ], + "donors": [ + 166, + 167, + 194, + 195, + 532, + 539, + 541, + 543 + ], + "pivots": [ + 222, + 223, + 250, + 251, + 278, + 279, + 306, + 307 + ] + }, + { + "E": [ + 408 + ], + "donors": [ + 184, + 190, + 191, + 240, + 246, + 247, + 274, + 275, + 324, + 326, + 408, + 507, + 540 + ], + "pivots": [ + 327, + 330, + 331, + 414, + 415, + 464, + 465, + 470, + 471, + 492, + 493, + 494 + ] + }, + { + "E": [ + 384 + ], + "donors": [ + 162, + 163, + 248, + 249, + 297, + 304, + 305, + 356, + 409, + 412, + 413, + 439, + 514, + 525, + 534, + 542 + ], + "pivots": [ + 357, + 360, + 361, + 416, + 417, + 436, + 437, + 442, + 443, + 495, + 502 + ] + }, + { + "E": [ + 126 + ], + "donors": [ + 160, + 161, + 533, + 535, + 552 + ], + "pivots": [ + 242, + 243 + ] + }, + { + "E": [ + 414 + ], + "donors": [ + 185, + 192, + 193, + 218, + 219, + 302, + 303, + 352, + 353, + 380, + 382, + 468, + 505, + 510, + 511, + 521, + 547, + 548 + ], + "pivots": [ + 358, + 359, + 381, + 383, + 386, + 387, + 469, + 472, + 473, + 496, + 497 + ] + }, + { + "E": [ + 390 + ], + "donors": [ + 164, + 165, + 220, + 221, + 276, + 277, + 325, + 328, + 506, + 512, + 515, + 529 + ], + "pivots": [ + 329, + 332, + 333, + 388, + 389, + 500, + 501, + 503 + ] + }, + { + "E": [ + 102 + ], + "donors": [ + 188, + 189, + 537, + 538 + ], + "pivots": [ + 244, + 245 + ] + }, + { + "E": [ + 486 + ], + "donors": [ + 136, + 137, + 334, + 335, + 354, + 362, + 363, + 509, + 526, + 531 + ], + "pivots": [ + 355, + 444, + 445, + 446, + 447, + 474, + 475 + ] + }, + { + "E": [ + 96 + ], + "donors": [ + 186, + 187, + 438, + 517, + 549 + ], + "pivots": [ + 216, + 217 + ] + }, + { + "E": [ + 30 + ], + "donors": [ + 132, + 133, + 296, + 498, + 499, + 528 + ], + "pivots": [ + 268, + 269 + ] + }, + { + "E": [ + 120 + ], + "donors": [ + 158, + 159, + 527, + 546, + 553 + ], + "pivots": [ + 214, + 215 + ] + }, + { + "E": [ + 6 + ], + "donors": [ + 128, + 129, + 138, + 139, + 508, + 513, + 554, + 555 + ], + "pivots": [ + 156, + 157 + ] + }, + { + "E": [ + 24 + ], + "donors": [ + 130, + 131, + 241, + 419, + 557 + ], + "pivots": [ + 212, + 213 + ] + } + ] +} \ No newline at end of file diff --git a/research/e8-complex-gauge-kernel/data/words/gauge80-kernel42/FULL-WORD.json.gz b/research/e8-complex-gauge-kernel/data/words/gauge80-kernel42/FULL-WORD.json.gz new file mode 100644 index 0000000000000000000000000000000000000000..85da3f86a2602122d95c3080834397ac1abdfce7 GIT binary patch literal 38701 zcmYhhWmFwa7cPjq9NgVqgCE?Tgb)bs4hMI4hu{vu9fG^N1_%dtcXzqG-<_E?{iC{T zt?H`o{m9-eWKjqZ|7}no4V{x{G@W+j_pEL{g!FF;>ojrfE6BzM?sghe zG|9fQ5wA9EZGU}a)v)E%7$Yb@y1U=V{9a1BKi=#=u0`I5H+*SRauwbmhF?!FE_!u7 zUZ=Z}j?0UgQvU119xUrUKa7>DD= z9J&xiSN}WygMl_y=XxS!jTftv+QXbCy`%xKY~}`EN4w3e=#p1xR|irsNzDQecH@d*}fsVb+jZ*@f^zQ=V-b|NcSp5DlG`ZOGy^J`Cuc ziHS#Cw<7z$V?aW9v5iq#TFEA^Ts?s(frqAPw!7}}2VwyyNHX6a)o^^(L&$L2+aUnF z<$ZCHcGxY_7My#(#bCvvd71FeWKmW|u7QwPq2_(HLs}>+$y*&-`MP~o8wQjm3=n@K zJ&6d!zv)m--v=vF=R^#o3;4HGV;W(q>sA;}vhD&3ltP)rNZ*dR* zPuyKi&m4PfKEQHrT;-d`^9%J&3=$ZjGR_iaf0+9Z^T3r*Pa38O?fuPXw9^*RnQ%?` zJo)JFt)n5APR0d7{-p7CgU4V8`V)1v?7$^nS>lptqNghtN;QatQEKS*6@&_cG zuevpKs@3H6{z!r0(hIe>m3#k%-i-45{}+1h!xWF(^g0BzZHzw6fjNsa`m2~~B6VM4 zw~)Q++SR}D17dcj1Dlqn*f45eJFTcB4g;-Co^t#ndblw78ll5aB12o`rvOco)mspjsRglmDac%yudc$()><0PmK#Jf!+CWiz*?UWE|0DU3?qo1G{ z$_*@bLw8zyRZ##q*>HbfA+`Zt2%3uKoj5CjvV>@jC;d2Kxf~^w_5lz6SQBZhgD zWDOx5G_jnNWiF)V*gz2^#U8VbOySa-08I)tE|Evn+KgdYqf;<&YjVo6Aep<~5(TeC ziVctytz{Z^+k31oO`I;FYr}ArB9$>x$+;N43A*d6|H;+9WkIw8GaE~IVm3-*ahYJE6Mc3v>`(8bd()dYVhDR)^O|GEtLr+OVz%(j<`(Vp z?WXaf`A>(5T{GY=?IsLM4p|mYEq3zyr#g5I!tE3yvWWp(O|UCKK5}=k%d%Vcy{^;! z+ili;!Bn^Iw8w_iI=a9`JL`*D>PGd+pNqCrMZUcbt}POL;Zrw*uuWaC>4wXao33wr z&O-q!cu1?r(bj7{U=24~H}kAC>glYF=cT$iGd_vQ9M>}fP1Scng^mb{nXOMg+(i_s zDLR~m%4qx*MkiYiQv056b1bsu52c|NhPE;_%L7*Jo}^87t@w5KBG2>|p=bcKRLi$b zQ8Y1Z;NjS%ExUd8o}C*x@zU;K_J#lC*S-Q`kp z1w0NK_SW@a--UHSrVEjU=jT)}4MvBiZ6*GI$kj8m7U>6&)1#JW12qgha*1Ki;Rsdu zzF@0%dkQhLKl3Q>9D;PF&XdC~(h}Az6L+VV?G+xEj(_~EP@sjj+hae-dSZEKFRtqj(bn^ayK);_DG31`VNn4Zv!=in*y67fHCH`bC)X0Ml zdH6XRFfixfIig|?F%)=23<^JbRU@&*Z$@77HY(iI9DpQ%Z%{mx)wH3s;{zS~8p1qY zJrxBS1$L_qKcF^M=k>2V6hc4g8p2SL&UO+Sd904n1ciq}8Z|v4xgWwz6%B5Zrsqte zv6rK_iV4+exXtcX4;NV0+1RTaB`jM>g$f}@W0$a(!#msET{{69_Hz-tmSZj!FdN}f z≷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 bop?>NQuEr%rw{$fYztnb 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