# qm-spline: compressing Taylor's (gtmcknight) qm tables with cubic B-splines Source: github.com/gtmcknight/amm-sim at 4812a6382311624e1506aca131ca35c378f930d9, `research/solved`. All the work is by Taylor (gtmcknight). This item only compresses `qm_k1e-5.json`. Everything here ran on the pure-Python replica. No engine seeds were used and no Solidity was written. **Result:** 10,167 bytes in total (one 3-D cubic B-spline per table). On the holdout the paired loss against the full qm tables is **0.0632, se 0.0072, n = 2048**. Both targets are met (≤ 12 KB, loss < 0.2). ## Gate P (before any change) `python3 -I gates.py`, unmodified checkout, plain Python 3.12.3: ``` seed perfect-info gaussian+plain gaussian+qm lattice+qm 10000 448.261189 443.455598 443.522608 443.663520 10001 576.779199 571.463409 571.623551 571.977293 10002 531.886497 525.168028 525.865859 526.411631 ``` The gaussian+qm column matches the README exactly (443.522608 / 571.623551 / 525.865859). My per-seed harness gives a full-table holdout mean of 533.326 on 10000..12047. The README gives 533.33. ## Inventory of `qm_k1e-5.json` (7,892,018 bytes) - Scalars: `W0`=160, `NW`=321, `N2`=49, `C2`=24, `FB`=6, `H_bps`=5.0, `lam` 0.8, `sigma` 9.45, `size` 20, `g`, `kappa` 1e-5. `W2L` has 49 rival-displacement nodes in bps: -160,-130,-100,-80,-60,-50,-40,-30,-25,-20,-17,-14,-12,-11,…,-1,0,1,…,12,14,17,20,25,30,40,50,60,80,100,130,160. All are integers. - `S` = [0, 4, 8, 12, 16, 20, 26, 34]: the 8 belief-sd levels in bps. - Tables. Each is level × row × column, with offsets in bps from the price: | table | shape | values | range (bps) | visits (ask+bid lookups, 256 seeds) | |---|---|---|---|---| | A0c, B0c (phase 0) | 8×321×13 | 33,384 each | -32.67 .. 800 | 1,972,302 | | A1s, B1s (phase 1, synced) | 8×321×49 | 125,832 each | -60 .. 800 | 2,056,484 | | A1c, B1c (phase 1, clipped) | 8×321×49 | 125,832 each | -53.12 .. 800 | 444,824 | | A2s, B2s (phase 2, synced) | 8×321×49 | 125,832 each | -60 .. 800 | 1,070,896 | | A2c, B2c (phase 2, clipped) | 8×321×49 | 125,832 each | -55.56 .. 800 | 30,322 | That is 1,073,424 values in total, or 536,712 on the ask side. - Axes. The row is own displacement, w = (row - 160) × 5 bps (-800..+800). For phase 0 the column is the rival displacement clipped to ±30 bps on a 5-bps grid (13 columns). For phases 1 and 2 the column is the rival displacement at `W2L` (non-uniform, located by `_pos2`). - How real.py reads them (`RealPolicy.lookup`): - It finds the sd level k with S[k] ≤ sd < S[k+1] and sets tt = (sd - S[k]) / (S[k+1] - S[k]), clamped to 0..1, so sd > 34 uses level 7. - The tag is `0c` in phase 0, otherwise phase + (`s` if synced else `c`). - It interpolates bilinearly in (row, column) at levels k and k+1, then linearly in tt. - ask fee = 1 - exp(-(a - w)·1e-4) if a > w, else 0. bid fee = 1 - exp(-(b + w)·1e-4) if b > -w, else 0. - The row/column axes come from `pol_mid.json` (the `T` argument). Only `S` and the A/B tables are read from the qm file. ## Symmetry finding I tested the point mirror B[k][i][j] == A[k][320-i][last-j] for every sd level and table. **It holds exactly in 1,073,423 of 1,073,424 cells.** The only exception is one cell of `1c` at sd level 6 (26 bps), which differs by 0.71 bps. Every other level of every table has a maximum difference of 0.0. Only the ask side is stored. The decoder sets B = mirror(A), so the one 0.71-bps cell is reproduced from the mirror. That error is included in the measured loss. ## Fee surface The quantity fitted is F = A - w (the ask fee in bps), never A. - min F = 0.0 exactly, so the fee is never negative. - F = 0 in 47–48% of cells (0c 47.7%, 1s 46.9%, 1c 47.4%, 2s 46.9%, 2c 47.4%). These fractions are nearly constant across sd levels. - max F is 772–782 bps, at the far rows (w near -800). - A = 800 only at row 320, where w = 800, so F = 0 there. ## Method (spline) - **Representation:** one 3-D cubic tensor-product B-spline per table, over (row, column, sd-level index 0..7). It is clamped (four end knots repeated) on every axis. There are 5 tables (0c, 1s, 1c, 2s, 2c), ask side only. - I chose 3-D because the 2-D form (one spline per phase and sd level) was larger at equal loss. At ~10 KB, 2-D lost 0.094 and 3-D lost 0.055. At 5.0 KB, 3-D lost 0.092, while 2-D needed 6.8 KB to reach 0.128. - With nk = 4 the sd axis has no interior knots, so it is a single cubic in the level index. Its basis at the 8 integer levels is a fixed 8×4 table. - **Coefficients:** int16, unit 1/8 bps (coefficient range in the chosen blob: -1107.4 .. +1150.6 bps). - **Knots** sit at visit quantiles. - Visits are every qm lookup (ask and bid) made by gaussian+qm with the full tables on choose seeds 60000..60255. Each bid lookup is mapped into ask coordinates by the mirror (row → 320-row, column → last-column). - Interior knots are quantiles of a mixture: 0.8 × the visit distribution plus 0.2 × uniform. They are rounded to 1/64 grid unit, with a minimum spacing of 0.25 grid unit. - **Weights:** visit density is splatted tri-linearly onto the (level, row, column) grid nodes, the same way real.py interpolates. A floor of 1e-3 × the mean weight is added so unvisited regions stay determined. - **Censored least squares (one-sided fit):** weighted least squares on the grid nodes. In cells where F = 0, the target is replaced by min(prediction, 0) at each iteration (12 iterations). A negative prediction there costs nothing, because the fee clamps to 0. Positive cells are fitted two-sided. - **Decode:** evaluate the spline at all grid nodes, then F̂ = max(F̂, 0) per node, A = w + F̂, B = mirror(A). The result is written as a JSON that real.py's `qm:` variant loads (`qm=`). The reference policy is therefore exactly real.py with these tables. - **Scoring:** a per-seed harness equivalent to `real.ev`. It runs `real.RealPolicy(T, {'soft': 1, 'qm': file})` through `replica2.run` per seed, with `T = pol_mid.json`. - loss = full-table edge - decoded edge, per seed, paired. - The setting was chosen on 60000..61023 (n = 1024), then frozen and scored once on 10000..12047. - real.py's own CLI also loads the decoded file (checked on 24 seeds). ## Exact byte layout (QMS1, little-endian) | offset | field | type | value in chosen blob | |---|---|---|---| | 0 | magic | 4 bytes | `QMS1` | | 4 | form | u8 | 3 (3-D spline; 2 = per-level 2-D, where nk = 8 and there are no sd knots) | | 5 | ntab | u8 | 5 (order 0c, 1s, 1c, 2s, 2c) | | 6 | NW | u16 | 321 | | 8 | W0 | u16 | 160 | | 10 | H (bps) | u8 | 5 | | 11 | nS | u8 | 8 | | 12 | S | 8 × u8 | 0,4,8,12,16,20,26,34 | | 20 | N2 | u8 | 49 | | 21 | W2L | 49 × i16 | rival nodes in bps | | 119 | FB | u8 | 6 | | 120 | per table: nr, nc, nk | 3 × u8 | | | | row interior knots | (nr-4) × u16, unit 1/64 row | | | | column interior knots | (nc-4) × u16, unit 1/64 column index | | | | sd interior knots (form 3) | (nk-4) × u16, unit 1/64 level | none (nk = 4) | | 375 | coefficients, table by table | nk·nr·nc × i16, order [sd][row][col], unit 1/8 bps | | | 10167 | end | | | Notes on the layout: - Knot vectors are clamped: [0]×4 + interior + [last]×4. The last value is 320 for rows, 12 or 48 for columns and 7 for sd. - Chosen sizes (nr, nc, nk) are: 0c (24,10,4); 1s (24,14,4); 1c (18,12,4); 2s (24,14,4); 2c (12,8,4). - Byte breakdown: header 120 bytes, table descriptors and knots 255 bytes, coefficients 4,896 × 2 = 9,792 bytes. The total is **10,167 bytes**, with axes and header included. ## Tradeoff table (choose seeds 60000..61023, n = 1024; loss = full - decoded edge) | setting (form; nr,nc,nk per 0c/1s/1c/2s/2c; weight power) | bytes | choose loss | se | visit-weighted fee rms (bps) | |---|---|---|---|---| | 2-D; 12,6/12,10/10,6/12,10/6,6 | 6,763 | 0.1280 | 0.0148 | 0.833 | | 2-D; 14,8/16,12/12,8/16,12/8,6 | 10,519 | 0.0935 | 0.0116 | 0.715 | | 3-D; 16,8,4/16,10,4/12,8,4/16,10,4/8,6,4 | 5,011 | 0.0924 | 0.0114 | 0.739 | | 3-D; 20,8,4/20,12,4/16,10,4/20,12,4/12,8,4; w^1 | 7,499 | 0.0682 | 0.0109 | 0.659 | | 3-D; same; w^0.5 | 7,499 | 0.0662 | 0.0106 | 0.672 | | 3-D; 20,8,5/20,12,5/16,10,5/20,12,5/12,8,4 | 9,107 | 0.0665 | 0.0107 | 0.651 | | **3-D; 24,10,4/24,14,4/18,12,4/24,14,4/12,8,4; w^1** | **10,167** | **0.0549** | **0.0103** | 0.601 | | 3-D; 28,12,4/28,16,4/20,12,4/26,14,4/12,8,4 | 12,279 | not scored | | 0.568 | The 12,279-byte setting was dropped without scoring. It is 9 bytes under 12,288 but over 12,000, so it was left out to stay clearly inside "12 KB". Fitting at nk = 3 was not possible (a cubic needs at least 4 coefficients). ## Chosen setting, frozen, scored once on the holdout The chosen setting is 3-D, (24,10,4)/(24,14,4)/(18,12,4)/(24,14,4)/(12,8,4), weight power 1, floor 1e-3, alpha 0.8. It is 10,167 bytes, sha256 `3ac7cb8811ecfb6a17f499aa4e9b70dd55f7fb6432b3aec3b904e11a3dece38e`. | | value | |---|---| | seeds | 10000..12047, n = 2048 | | full-table mean edge | 533.3260 | | decoded mean edge | 533.2628 | | **paired loss (full - decoded)** | **0.0632, se 0.0072** | | worst5 (seed, loss) | (10522, 1.458), (10711, 1.360), (12015, 1.342), (10268, 1.172), (10203, 1.092) | | implied vs HA (HA mean 529.557 on these seeds, README) | about +3.71 (full: +3.77) | | per-seed check values, decoded tables, 10000/10001/10002 | 443.101741 / 571.454483 / 525.908441 | ## Lookup cost for one ask/bid pair (operation counts, not measured gas) To match the reference exactly, the contract must reproduce real.py on the decoded grid: 1. Compute F̂ at the 4 surrounding nodes × 2 sd levels. 2. Clamp each node at 0. 3. Interpolate bilinearly, then linearly in sd. The bid side does the same at the mirrored point (320 - pw, last - p2). Counts per side: - **Reads:** 4×4×4 = 64 int16 coefficients when rows i, i+1 and columns j, j+1 share a knot span. The worst case is 5×5×4 = 100. Add the knots of the spans found: a binary search over at most 20 row knots and 10 column knots, about 5 + 4 knot reads. 16 int16 fit in a 32-byte word, so this is at most about 4 to 7 SLOAD/code reads of 32 bytes per row-stripe if packed column-major. - **Multiplies:** - Basis evaluation (Cox–de Boor, cubic) at 2 row nodes and 2 column nodes: 12 each, so 48. - Contracting the block: 128 (columns) + 64 (rows) + 32 (sd), so 224. - Interpolation: about 12. - Per side ≈ 284, so **about 570 per pair**. - **Divisions:** 6 per Cox–de Boor evaluation × 4 nodes = 24 per side, so **48 per pair**. - The sd basis is a constant 8×4 table (no interior sd knots), so it needs no divisions. - Storing reciprocal knot differences instead of knots would remove all divisions, at the cost of more bytes. - The fee conversion (exp) is the same as in the full-table policy and is not counted. ## Standalone decoder (stdlib + numpy) Save as `qms_decode.py`. Usage: `python3 -I qms_decode.py blob.b64 qm_spline.json`, then `python3 -I real.py pol_mid.json qm:soft=1,qm=/qm_spline.json`. Decoding the base64 below reproduces, byte for byte, the JSON that was scored. ```python """Decode a QMS1 blob (cubic B-spline fee surfaces of gtmcknight's qm tables) to a JSON that real.py's qm variant loads. usage: python3 -I qms_decode.py stdlib + numpy only.""" import sys, json, struct, base64 import numpy as np TAGS = ['0c', '1s', '1c', '2s', '2c'] def basis(knots, x): """cubic B-spline basis values, shape (len(x), len(knots) - 4); right end included.""" t = np.asarray(knots, float); x = np.asarray(x, float); n = len(t) - 4 B = np.zeros((len(x), len(t) - 1)) for m in range(len(t) - 1): if t[m] < t[m + 1]: B[:, m] = (x >= t[m]) & (x < t[m + 1]) last = np.max(np.nonzero(t[:-1] < t[1:])[0]) B[x >= t[-1], :] = 0.0; B[x >= t[-1], last] = 1.0 for d in range(1, 4): Bn = np.zeros((len(x), len(t) - 1 - d)) for m in range(len(t) - 1 - d): a = t[m + d] - t[m]; b = t[m + d + 1] - t[m + 1] if a > 0: Bn[:, m] += (x - t[m]) / a * B[:, m] if b > 0: Bn[:, m] += (t[m + d + 1] - x) / b * B[:, m + 1] B = Bn return B[:, :n] def clamped(lo, hi, interior): return [lo] * 4 + list(interior) + [hi] * 4 def parse(blob): o = 0 def rd(fmt): nonlocal o v = struct.unpack_from('<' + fmt, blob, o); o += struct.calcsize('<' + fmt); return v assert blob[:4] == b'QMS1'; o = 4 form, ntab, nw, w0, h, ns = rd('BBHHBB') S = list(rd('%dB' % ns)) n2 = rd('B')[0]; W2L = list(rd('%dh' % n2)) fb = rd('B')[0] tabs = [] for _ in range(ntab): nr, nc, nk = rd('BBB') kr = [v / 64.0 for v in rd('%dH' % (nr - 4))] kc = [v / 64.0 for v in rd('%dH' % (nc - 4))] ks = [v / 64.0 for v in rd('%dH' % (nk - 4))] if form == 3 else None tabs.append((nr, nc, nk, kr, kc, ks)) for idx, (nr, nc, nk, kr, kc, ks) in enumerate(tabs): cnt = nr * nc * nk C = np.array(rd('%dh' % cnt), float).reshape(nk, nr, nc) / 8.0 tabs[idx] = tabs[idx] + (C,) assert o == len(blob), (o, len(blob)) return dict(form=form, NW=nw, W0=w0, H=float(h), S=S, W2L=W2L, FB=fb, tabs=tabs) def surfaces(P): """fee surface F[t] (level x row x col) at the grid nodes, clamped at 0.""" out = [] for t, (nr, nc, nk, kr, kc, ks, C) in enumerate(P['tabs']): ncol = 2 * P['FB'] + 1 if t == 0 else len(P['W2L']) Br = basis(clamped(0.0, P['NW'] - 1.0, kr), np.arange(P['NW'])) Bc = basis(clamped(0.0, ncol - 1.0, kc), np.arange(ncol)) if P['form'] == 3: Bs = basis(clamped(0.0, len(P['S']) - 1.0, ks), np.arange(len(P['S']))) F = np.einsum('ks,src,ir,jc->kij', Bs, C, Br, Bc) else: F = np.einsum('krc,ir,jc->kij', C, Br, Bc) out.append(np.maximum(F, 0.0)) return out def to_qm(blob): P = parse(blob) w = (np.arange(P['NW']) - P['W0']) * P['H'] Q = {'S': [float(s) for s in P['S']], 'W0': P['W0'], 'NW': P['NW'], 'N2': len(P['W2L']), 'FB': P['FB'], 'H_bps': P['H'], 'W2L': [float(v) for v in P['W2L']]} for tag, F in zip(TAGS, surfaces(P)): A = F + w[None, :, None] # ask offset = w + fee B = A[:, ::-1, ::-1] # point mirror: B[k][i][j] = A[k][NW-1-i][last-j] Q['A' + tag] = np.round(A, 6).tolist(); Q['B' + tag] = np.round(B, 6).tolist() return Q if __name__ == '__main__': raw = open(sys.argv[1], 'rb').read() if not raw.startswith(b'QMS1'): raw = base64.b64decode(raw) json.dump(to_qm(raw), open(sys.argv[2], 'w')) ``` ## Data: base64 of the 10,167-byte blob (sha256 3ac7cb88…38e) ``` UU1TMQMFQQGgAAUIAAQIDBAUGiIxYP9+/5z/sP/E/87/2P/i/+f/7P/v//L/9P/1//b/9//4//n/+v/7//z//f/+////AAABAAIA AwAEAAUABgAHAAgACQAKAAsADAAOABEAFAAZAB4AKAAyADwAUABkAIIAoAAGGAoE0REHHiEitCOKJAclUSWZJRAm/iYCKfApZyqv KvkqditMLN8t+TEvPgsAGwC4AEgC4ALwAhgOBMUS2CD0I98kdyX5JXcm7yZgJ8wnNCigKBEpiSkHKokqISsMLCgvOz3wAlcECgVz BdAFMAaNBvYGqQcQCRIMBCMYZSIMJdMlciYJJ6snVSj3KI4pLSr0Kpst3Td/BMAERAW7BUUGvAZAB4EHGA4EtxJMIJUjtCRnJfcl dybtJl4nyic2KKIoEymJKQkqmSpMK2sstC9JPbsCHQTgBGMFzQUzBp0GIAfjB0UJDAgEsh44JP4lPCfEKAIqyCtOMY8EewWFBnEH PhgAADkYRxhGGGMYgBhSGAAAYhiJFAAAqhR4FMsUZRQcFPMUAACkFFAOAAAfDngOFQ7JDlcPDg4AAJcORgcAAGoHMgePBy8Hmwax BwAAPQe6AwAAoAPXA70DDQQGBkYFAADNBYECAABvAqUCbwItBesC7gMAADkDAQIAAFQC1QEmA1gCWAPHBgAAmwXMAQAAtQHzARQC pQNVA6wAAADZAbIBAADqAZUBlALMAfgCqgMAAF0DlwEAAHgBxAG1AQgDbwIxAwAAEwNiAQAAdgEzAQACwgGiAnMBAAC8AfoAAAAF AiUBlADtAYIBlwIAAO0BawEAABf+fgGr/+IA5wDEAAAA+ABB/QAAJQEtAB4Az/9zAIoAAACEAOoBAAAD/9b/r//f//n/IAAAAB8A sv0AAA4ACgD0/xQA7v8MAAAAAABNAAAAw/8IAPv//f8DAP7/AAD9/8L/AAD7/wEA/v8CAP7/AgAAAAEAAQAAAAAAAAAAAP//AAAA AAAA//8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAD//wAAAAAAAAAAAAAAAAAAAAAAAAAANhgAAMYXchiqF0QZrBjbFwAAWhiBFAAAiRWwE0sWWBFuEyYVAABKFEUOAADf DC0PMwwLEiEQCQ4AAAQPRAcAAOMH1AZcCJoFTgYKBwAAtAa6AwAAeQPsA2kDygQtBjoFAAC6BYcCAACmAngCDAMlBCADEQQAAK4D DwIAANsBOAJQAnwDkAOOBAAAPwPaAQAA/wHIAWwC9AKzAiMDAAA6A8MBAABwAegBxgE9A6sCnwMAAEADtgEAABsCcQEMAmkCHwNV AgAAAwJmAQAAZgDeASsBpAJrAaUDAABzA/YAAABpA63/JQJpAKoCjQAAAKgBIgAAANf6HAKW/iQCOQA3AgAAFAHf/wAA9w0O/MgC pv4aAVb/AAB0ADgCAADL7OgEEv7DAGb/JQEAAAoAyv4AAHIGa/0MAWr/cQAN/wAA0P9aAAAAxf18AKb/RwDO/1wAAAAUAOv/AABf ANr/HwDo/xIAz/8AAPT/AgAAAOn/CQD2/woA+f8PAAAABAD//wAACwD6/wcA+f8FAPL/AAD+/wEAAADy/wgA9f8MAPf/KQAAAAcA //8AABYA8/8SAOr/FgBP/wAA5v8BAAAA8f8JAPP/EQDs/24AAAATAAAAAAAFAP3/BAD6/wUAxP8AAPr/UhgAAM8YGxgdGckXRRj5 GAAAfRitFAAAiROBFf8SgRciFrYUAACVFWAOAADwD4gNwhDmC/gM1g4AALwNXgcAAIkG/gcwBigJLwmCCAAA7gj6AwAATQToA9kE 2QTLA8wEAABxBO0CAACnAjEDCQPDAogEjgMAAO4DSwIAAJwCXQJvAh4D6QItAgAAHwMSAgAAogFIAugBoAL3ApIDAAABA8sBAAC3 AogBWQIlAsYCMgIAAIYCyAEAAKAALgJKAYcCdgJmAgAA7QJoAQAATwOYAHACaQFeAmcCAADsAQIBAADK/TYC9v7eAvoAVQIAANYB yP8AAOUEdv7mATT/nAFEAAAA/wC4AAAAc/aoAn78hwGv/yEBAABcANn7AAC0FMf22QWb/EABpf4AAEoAfgEAAC35VANc/YMBKf/L AAAAyv9k/wAAUQN7/jABI/9iAMb/AAAeABYAAABe/08AsP84AOX/yv8AAMX//v8AADcA4f8eAOb/BgAoAAAAFgABAAAA6f8OAPD/ DgD9/6r/AADS////AAAkAOr/GwDl//7/PQAAACwAAQAAANX/GgDa/yUA8/8JAAAAlv///wAAHQDu/xkA5f8MAOf/AAA8AAAAAAD4 /wUA+P8IAPv/FAAAANP/ABgAAO8XExgMGFQYUBgyGAAASRhMFAAAgBQ6FMUUPhRZFKIUAAByFB4OAADWDVAO3g2yDr0OVg4AAJ0O TwcAAIMHOwfSB30HZwekBwAAfAcSBAAA/gMqBCgETQTbBHYEAACSBMgCAADyAsACIAOvAy0DpQMAAIgDagIAADICZgKyAsUCEgM9 AwAABQMuAgAAcgL+AYQCjgLiAoACAADSAi0CAACKATgC6AG2AlcCBwMAAKsC7AEAAKwCngFKAgMCrAJtAgAAeQLVAQAA/wAzAhQB oALZAW0CAABGAkIBAAAzAvUArgHjAPEBWgEAAKEBuQAAAJT/IQHw/zQBjwBAAQAA9QAMAAAA6gDR/7IAlv+OABIAAABjABAAAABV /l0AM/9VALT/iQAAAA0Asv8AAKIAm/9DAOL/CwDp/wAA4P8IAAAAiv8uANf/EAD+/93/AAABAPr/AAAQAPT/BgAAAPv/HQAAAAUA //8AAP3/AgD///7/BADh/wAA+/8AAAAA/P8CAPz/BAD6/xgAAAAFAAAAAAADAP//AQD+/wQA2v8AAPj/AAAAAAEA//8BAAAA/f8X AAAACAAAAAAA//8BAP//AQABAPT/AAD3/wAAAAABAP//AQAAAP//AQAAAAEABhgGGAoYIhgsGCwYDxhiGE4YdRiTGN4XCRgrGBsU NRQbFGEULBRyFMkUtBNFE0MSlhNlFb8VsBRbDTINbQ08DZENRA3dDDAOFA/nDxUPAgy7CgIN8AX/Bd8FJAb/BTYGgwa3BQ8FngS+ BLQGigmYB2ICRQKBAmACnwKHAkkC2gKYAzwEygSuBCoEdwQ1AYMBkwG7AcUB5gEZAyoDMQMUAwwDPQPsA5ID8QBDAR0BpQGYATgC DgIrAnkCxwIrAy0DPQNCA5QB4P+GAQMBhAGqARICQgJWAnYClQKyAj8DFAMSASAA2AD5AD0BrgGWAdIB9AEyAm4CkwK2ArQCRAD2 /4cA4QD2AC8BkAGRAccB4QEwAgICGQOUAtIAsv7TAEgADgEKAScBWAFkAbgBvQFHAkcCsQE5/tj/yv+hADoBgwAGAfwAQQFhAaMB HgI1AjkKS/sqA7v9JAG0AIUA4gDGACAB5AC9AcoAhgY6B2UCFP2sANgAtADAABUAgQDmAJIAqQGAAI0GRgT9/pX/fQBjAE8AMQBY AH0AbwBwAI4B5f/pBh0F1/4LAEIAPQA+AEsAx//w/1IAaADjAEsA8wUHAyoA3//Y/ywA5v/q/x8A7v/G/xAA9wBC/w4HvgPy//3/ GADX/wwA/P/z//f/FQDK/zMA8P//BNEAAwD3////BQD///n/BwD2/wIA9v8QAFf/jAX0AgIA+f8IAPf/BgD2/woA5f8ZAMj/XgDN /twCEgH8/wgA9v8JAPj/DADw/yEA1/8+AJr/d/1GACb8AwD3/wwA8v8JAO7/EwDM/zIAof9wALsD4QEOAf7/BQD5/wgA+/8JAPb/ GQDn/ykA5/9b+9j8CAAAAP7/AwD8/wIA/f8DAPb/BwDt/xEAZgCaAOf/+xfZF9YXvBdWGGUX5he+GTEaPxm2F6UXLRjBFy4UoROd FOcUyBMSFocUDA8TELIS7RRbFbsTrRUDDc0NWgxADN0NPAtgDGcVIhMvEUMM6AvzDZAKxgXoBekF9QapBSQH7waZAeYCPgMDBk4H 0gb0CJMCGAKEAisCqAIsAvgBoARLBNQEYgR+BJsEmQS8/1QB0wG3AdUBXQL0Am4CygLkAngDKwO9A3kD5wLe/+IBiwG/AbEBSwKY As4C6wL4AgYDkAOHA///UgAoAUcBewHNAeUBFgJLAnMCvwK2AhEDdgKF/w0A/wAvAS0BPQHLAegBBgI3AmcCfgLiAuUDvgM9//0A rwAtAUQBMgGzAbkB+QH9AWsCqQLfAHjuMwJL/y0BbgDjADgBRQGuAXUBRwKsAeICwgWpC0z7+gGy/3kA3gDSACABTgGpAXQBjQKt AagFwfdeAlj/KQAkAFQAugDUAPsARgG5AYMBRgSgA0X/eARz/sn/UwD1/7sAbQAGASoBNgEoAW8FjgoaAev6DQLj//4A5/8tAI8A QQDIAPkAwAFjAV4ICv8SBIX9WAGQ/woB4//4/7QAdADHACUB/wIxCIAAy/1+AUn/dgCF/3j/KQCn/xIA5gDO/1cENwmw/zYBKv9l AMD/EgBsAIn/egC6/yAAKAG4AQENEgCd/zwA5/8SAPr/1/87AKn/ZQC2/7P/eQIOFPz/6P8NAOz/CgC4/2IAyf7OAM7+RgF3/hYD 3wQEAPv/CQAFAAoAGgDE/3gAb/8HAZT/ugCj+pwB8v8kAL//JQCF/20AX/46AoX7RQTd7eUXcv6lAAkA4/8wANz/VgBu/3IBpfyp BMP3eBFl3cgBzv/8/wwA6v8PANP/KABg/8QALf5pAUr5Xgbh/wYAGRhrGAEYlhg3GPkYwhhgFxcXmhfFGLkYdRi8GA4UDxU5FJMT dRS+EpwTzhc6F/0V/BMPFIcVVxTPDZEM/Q1hDs8Niw+BD2UIQwrWCuQOfw66DNIO4QVhBpgFlwX/BTgF0wROCWQIXAgzBgEGHAib Bg8CUgLeAmkCQAPEA6YEigJeA1IDUwRQBOUEmwSOAaUAIALYAS0COgLEAbYCuwIXAxQDpAPBA7UDz//rAawBmwHBAfsB3QEiAkMC iwL9AkkDWwN7AyEAqQBlAYEBegGTAbwB4QEDAlgCkQLuAkYDTgM4/xoBJQEOAS4BhAFhAcUB9QEfAnkCuQIOA9ECNP7KAIYAIgHH AAQBaQFQAb0B3QF+AkwCOwNcA3kE3/8UAYQA0QDvAOsAQwFbAeMB8wHvAloCTQOq98gCRf/lAHoAXgDmANoAMQFCARUCmgH3BBEG egWv/MMAXgBSAIsAawDFAO4ATwFfATMCnQEiB+4A2fqYAVf/GQAPACwAkwCDAOwARwHuAX0AMwPy/LsI8fvZ//L+QAD9/yEAjQC7 ADIB2AAqBXUHXQIi+CYEzv2cAJn92P8CAPr/cgDGAE0BZwEeBm3+cQRX/RQBSv9xAQIA9v/M/2sAOgCaARkBnwiRAKX9ZwFq/1oA Pf+5/6kAgv+h/50A//9FAckC2P+JAK7/GwDw/yIATwAh/7EA2/+w/5gA8gJ1AwwAy/8nAPL/DQDc/+P/aADb/3r+CgL0+s0FA/35 /xQA+v/t/xoArv8hATv9vQJy+2wIgv3//d8BCgDi/xUACgD+/0wA9P7bAtD9MAbh87MB6AQu/Pv/EAD1//n/AwDM/6oAOv45Aab8 ZAWfAgr7mQECAPn/BgAAAAEADgC2/4QAnf9UASf9nwCeAKL/OxftFjkX2BfNF9AXwxdBGC8YLBgUGBsYXRhSGEkTGhNXEwUUBBSN FKkUZRPfE/UTTxRdFFoUgRSBDHEMYgw+DQANrgxJDK4OwA3sDWYNbg39DbANjwX0BVgFEAZEBuMGRgeiBUYGRgamBtAGrQboBpAC YQJGA48CEAOmAoACpQNjA5QDdQOOAy0EFwRpAUsBVgIRAvwBVwLJAngCsQLEAhADHgPHA7wDZQF9AbEB7gHSAfgBKwJAAlwCfgKv AscCrgOKA8UA+gDXAbEBswHYAekB+wEqAkICkQK9AqMDhQOzABMBFgGfAXYBfgHFAcUB2wENAkwCnAKMA5MDZgBqAFABPQFXAVwB VAGjAaEB1QERAoICrwOiAwgALgC6AB4BGAH8AEMBPwF1AXoB2QEVAv4D1AMgAAcAzQDiAOcA/ADiABgBPAFVAbwBowElBOUDWP9A /w8BUQDeAIMAzwDOAPYAGwFkAbgBGARoBGT/mQDc/9UAigCLAH8AkADOAOQAMQGvAfIDfgR8AOL92AAkAIgATQBGAGsAZgCuAO0A QwERAw4EYP9bAVH/QwDR/5EA9f8fAFoAYgCqAFIB+wLlA0MAzf60AMX/LgBY/xEAiv++/yAAmwAyAEQEDgPQ/2sAmf8TAPL/LQAd ANn/VQC8/y0AwgB+AgEDBwDe/xYA+v8GAOb/4P8uAKb/0/8AAHn/wAOeAvr/DQDu/wYA9/8QAPv/DAAGAOv/qADT/ocB1QECAPz/ AgADAPX/DQB7/7cAlP4/Aaf7KwIs/jb+/v8EAP3//P8IAPH/eAAy/zABVf7/A+v8EAL9AAEA/v8BAAMA+v8MAKT/igAi/yIBL/1c AmP+hv///wEA/////wEA/P8PANn/IQCr/3QAff8tAA8AJhg2GB4YKBgsGCkYQxhdGE4YqhjhF1wYKBMoExoTJxM5E0QT4BKWEssS nBKlE/IS9AsbDO4L/AvyC+ILeAzcDJwMMw16C5MMcwSBBFsEegSHBKIEOwTxAxgEkAPyBBQEqAFkAqkB4gHuAcIBggKZAwYE/gUz AnwESAEEAtUAmQFsATgE+gQrAfcBxwDoA+0BbAFRAOYB8ADVAYr/JwGfAnoCewOmAbwC+/+IA+H9aAExAFADkAEEAcYB6AHGAdkB WwHb/0YCnAA1Acb/pwGWATkBcwEJAocB5QANAG4BrwAtANcACQFmAG8BCwE6ATQBPQAtAVb/JQEeAZP/VgAGAZMA+gECACwBQABz AKD/bgG3ALz/LwDE/7oAygCZAKoAr//OAAT/kP/I/yoA7v8ZAOP/3gAJ/3kAAADx/wYA//8GAPP/CADx/woArf9MAMf/AAAEAP// AAD9/wYA+v8JAPn/NQDK/xgA///7/wEA//8FAPX/CgDv/w0Al/9cANz/AAACAAAAAQD8/wcA+P8MAPb/SAC8/xYAAAAAAP//AAAB AP3/AgD8/wIA7f8PAPj/DhjPFz8YExgHGCcZFhhbG9MYNhayGckX9BI1E9USHRMQFMEOWg9tDpERaBccD70TAQwZC5sM4guYCyIP RxCtDxcO8wWmERwLUQTABPcDhASMBHQDaQL5AlsD9wZSAYoEBwJFARsCzwHoAaUCPwQbBFoEHgLFBusDiwALBFwBoAH0AbgAXwDy ApECOwRZAL8C4AACAuYASQEcAe8ChQL4AVsCgAGkA2ECBwEUAfYAzwBQAXMAVQFlAsYBHAPXAAcC7gA4/eYBYADiAEgBOgEaAesB BgKqAAcCdv+PAy//KQBOALEAhQCyAfcAOwJgATsB5P8vAdL93v++/4MA0AAiAAkBHwBIAesAFgGF/acE7v4QAE4AxP8cAWMArgGL /+cAmP8hASL+agDt/7D/EAA8/x0Abv/AAkD/FQCt/2IABQDs/zUAvf80ADkAn/8r/msA5f9WAJL/9v8IAMH/UADh/6H/NgHF//X/ FwCs/1cAIgDt/5EA+f7JAIoAef5oAP7/9P8jAO7/uv87AAn/jAEV/hMAsgC///7/AgD6//3/FwAAAB4Am/9ZAEz/6v8yAPX/Uhi4 GAgYDBheGHMXJxiXFDoWghuDFukYeBMbE1kT8BOKEmQXwRatGYcYVgxsGH4S7At7DfMKkAtfDGkJxAckBwAIwRPuBnwNvgScA50F kQSBBMAFFgf6BkEG5QIcB9gExwFKA5UAmALxAtEC6AF6ArECzQQYAUwD+AGYABYCdwF6AVoCyAIVAmAC9gFTA20CwAG8/0ABKgF3 AcwAggECAhMCcAMpAXUCvgG//soB6gDhAGIBkAFuAQECQwEqA/MBdv8uBJH/xAAtANsA2wCgATwBfAInAeMBmgDl/n//ewAwADoA 0QCgAGABrQAKAkQB0P9e/0IBCADv//j/FgDiALEACgLAAP4AQf8b/+v9zf9h/y7/QgDS/3wAfAAVAkgAQgBf/1QB3P87ADcAxP/M /3QAZgDOADgA7f9FAKb/+P/U/wYA9f/fAK/9MQMs/WcAGgC2/2cACQBKAOn/LQCP/cIDt/f9BY3+7/8xAMv/2f8X/zMAHABEBMb1 AQ5P9qABBQD//+3/TACQAFkAzf73/D0HiPZQBt7+AADz/xwA1P+F/zYAvP93ATT8EQQ+/UoAYxcgF5wX2hewFwcYVRimGKcYShdb GOYXdRJFEowS+RKlE3oSrBGdET4RzhQCEjYTPAvkCpULlguvCkIMrQ2EDdEN/AkFDbYLZQSLBPEDEAW0BbQEGwRiBLIEVgXZBA0F XQL6AhcCEALGAVYCDQPqAukCQwJbA7oC2gHRAfMB3wELAsQB5gE9AkgCyAIdAn8CrQGdAacBqQFvAQcC3AHmAQ0C1wGBAhYCLgG8 AVEBVAE6AVYBZwG4AZEB8gLTABUCKQH3ANgAEQFBAeIAUAEbAXcBHwEVAmsB7QAGALMBogDIAL0AvgAQAeUAUwJHAIABUQBdAZH/ jQCHAGUAlQB7AMEAkwBlAdYATgCS/+cAAwBaADkA8f9/AGIAMAEsANcA0v9pAFb/EwDN/wIA9v/0/8//9gDl/40ADgC6/0cA9/8q ANH/RwBQ/4YA0P6mAKf/6f9IAKH/DgC3/1QAZv8MARD/ggHc/jgAEwCs/2kA3f+LAEX/+gCy/ZsBg/2hAZz/8/8xAMH/EACL/3EA U/99AXb+2QHV/jkAAQD0/w0A+v8XANj/LwBb/04AcP9WAOT/BxgDGA8YDRghGB8YKxj3FygYPhg+GGcZlRdwGCYUNhQaFFcUMBQ3 FCkUFRUjFKUTxxPeERoV7hNuDWYNeQ1fDYsNnQ2TDYwMog1BDtIOABDUDREOKgYsBhcGRAY2Bi8GQAbnBlgGywVjBUMECAa1BYsC igKmApcCtQLMAsICLwKPAiEDkAMVBR8FQwV2AYIBuAG8AdIBtgGxAQoDswPZA84DXwNCAwIDfgHcAG8BhQGfAZ4B4AJ2AlMCigLR AhMDgQOCAyYBSwBCAQ0BRgHpAasBIwJ6ArUCzQKtAtQCnAKzAAcA8wDlAP8AbQHTAd8B9QEjAlYCZQL/ApMCwABX/+cAmwD4AEIB WQGRAc8BBwIqAjoCEQJdAmb/8/8pAJoAjAD5AD0BVwF+AaYB2QHJAQ8DDgLcAIH9JQHU/yABqQDnABIBPAGGAZMBfALnAL4BDP5D Aob+hwDQAHQAzwDHABEBGAHGARcBswQiCTMBsf2bAN8ArAC4ACkApQDUAPgAbgG9AG8GGQKj/pcAcwA8AFQANABDAHIATgCiAHwB BQD1BnYDpADu/+r/fgAeAGYA1f/6/3EAdQAIAUYABAbKBc//9/6NALb/GADQ/xsA6/+//zAAIAFi//UGLwLx/0cA0v8QAPn/CwD3 /wMAEADI/zEA9f94BTcBAwDg/xMA9f8GAPL/CgDq/wwA6v8cABX/Mgb+Af//BgD8/wAAAQD8/wUA6v8YAMn/XADd/nkCUQABAPn/ BQD//wAAAQD+/woA7/8cAOr/2v4//9f+/f8KAPf/BAD8/wUA7v8MAN//IADk/tUDKAEDAAIA+P8IAPz/BQD2/xQA3v8rALn/LAHc +nr+JQD//wIA/f8BAP7/AQD6/wYA8f8OAKf/rQBOAPP/9RfJFwYYtBcoGBsYbxcKF9sY9Bg/GYYWMBnsFyAU4BP5EwEVtBP3E8wV TxYjEh8SIhEjFywSRBQjDZ8NMw1LDAIOvw0GC/gJdhADESYSmgqAD9wNKwbqBTYGngYBBg4GnQeCCIMEWgTkATgIzAO2BaECdQKc AngCugLFAr4BNgFhA6cDmgWlA3MGSgX9ACsB2QG3AdQBpAGZAk8E9QKfAyoDsgPfAlMDkgGRAMABoQGpAQYCXgLUAf0C2wItA8EC NQRFA6QBU/9FATkBeQFwARMCawJbAnYCqwK7Ap8CtwI4/74A6wArATcBVwGfAdYBBQJsAkoCoQJvAvQC4gFS/8wAwgDlACQBTAHJ AckB0wEmAgcCtwIWAjT7/gBZAJ8A4AC+ACwBVAGPAdYB6gErAlMCkgLgAEUAef/OAK7/+QDHAB4BhwFSATICwQGJAc0BlwLT+sAC 7P5/ABcAyADeAPsAgAF1AToBNwUZCKH5qgr/+jQADAAJAKMAegASAQMBVwE7AWIFlwcSBNH37AICAP8A7P81AIAAXwAKAbkAdgKy /cMGmv0uBGn+BAGd/9EA0f8mAIgAgwDTAMIAQAR6BCkBSv5hAMT/KADN/2n/8f+h/2kAqAA3ACAEUgit/94Ak/8/AM3/MgAfADQA IACe/0wApwALAs4EGABh/1IAyv8mALv/FgCE/wcALwD5/xn/KgXlDvb/GQDv/woA9//0/ywAjv+EAOL+uAAP/+sB3wIHAO//DwD3 /wwAAgC5/1oAP//IAV3+JACz/bz/9/8ZAN//GADD/z8Af//bAM/9Lv/6+hIMyf4tAQUA8P8XAOr/LACu/5YAZf5lAu39tgaF7HUB xf/+/wUA+f8GAO//EQDS/0cAPP8cALT9FwPj/wEAKBh4GAUYfRhGGEQYvhhqGRgYPhjxF28Z6hehGBQUyBReFJMTbBSJFE4T+BES FZYUnBVFEpEVTBQaDsgMXQ4rDvoNVA2hD40RLQ2wDTkM0hD5DEAOxQXaBn0FKQbyBZQGaQXAA5YG9QUnCPcDEQiBBj0CmAL4ArQC WwMqA1UEaAXJAwsFwAHTBhQC2ARnADQBDQLkARcC7gLRAkABQQOjAlcEngLcBHwDWQHiAaEBnwHBAcEBTgHQAvwB0gKJAr4DYgJv AwP/fgFMAXUBZwG/AZ4BnwEfAmsC2AKwAmQD+AJ0ANgBwAAjAfsAWgFgAdoB5gETAnkClQIHA5gC2v4tAa8A9wDnAPkAUwEyAeIB FAJ3AmEC1gK3AlYAWQEDAN0AewDdAPAAOQGDAcQBcgIlAh4DSgLx/kL/LwHv/xMBKADgANwAHwHIAVwB1wIxA9sCsP2rA579fQHa /5IAUgDEAP8ANAHbAbEB1wGNBNAEcvaDAyX/3//9/yEAgQCTACgBMgG4Anb8HQWl/JsG4/3T/t3+0f/x/ykAkwCsAIoBEABZB9kF ewJE+UYCTf7QAA7+7v/Y/zEAiQDKAPIBsP0sAwD+1AOz/sAAPf8mAeH/GQDW/1oAfgBBAekAHwlvAHf+nwCf/1MAV//d/1IAYv/w /04AzQCM/yv/3f9/AMj/KQDf/0YAJQBU/6AAzP/V/3IAHwH9CA0AyP8rANn/IgC2//3/MQD1/3P+FQE5/fgCCv/3/xkA7/8NAPn/ //+nAIH+qAEb/5v/+QM3+2AEBwDt/wQA/v/y/zkAkf7OAij8fwTr/U39bwXw+v3/BAAFAPn/EwC2/xMBo/0MA3j7pQLz/279mgEB AP///P8EAPP/GwBx/8oAcf6HAe7+rAB/AML/LxcEFygXuxelF9wXuRekF9cX4Bf3F80XIhgGGFgTMhMPE/IT8RPxEzsUmhQcFCEU 8BN2FAoUQhSgDL0MegxRDeEMfA3dDGkMMw1CDa4N8AzYDYgNrwXpBZwFBAaNBksG0AZiB8cG4QZlBj4HiAbhBsIC1wInA8sCGANL AwYD7gJvAwwDBgSiAmUEoAODAZgBYQIoAg8CHQIOAisDYQL7AnwCUwMeA10DrAFCAbAB9AHSAQUCjgL2AYcCZwKxAmACZQP6AvUA cQG9AbcBswG8AeoBDgIZAj8CXgKXAgADAwMcAY0AVQF9AZQBewHIAbMB5gEKAlECZgIOA/cChgAQARwBSAFFAVMBXAGqAZwB3gEA An8C+gLqAvAAjf9YAdwAPwECATcBRgFuAXYBxAE0AgMDNAPw/0gBMQApAbAADgHjABwBRAE7AQMCHwEmBIkCEgEd/vcBzf8EAYEA 0ADQAPsANAEwATUCwQE6A3L+oQFf/8sAzwCQAIcAmADVAM4AXwEbAVYFDQKIACX/LgCcAFkAfgBEAGwAcwDLAMcAuAGiADMDfP+z AMT/UwDQ/3QA+f8lAEsAZwDAACIB3gOTAicAlP/N//j/EACz/8v/wv/2/zIAkQBmAJICOQLu////GgD8//v/IQACADcAuf/V/zIA vAD7Ao8CAwDz//3/9/8KANH/GACa/10A1//d/47/SAPdAf3/BgD5/wcA8v8kANn/UwCB/6r/ywAZ/1cAoQEBAPz/BAD6/wcA4/8D ALT/cwBD//D+/wC8/xX+//8CAP//AgD+/wgAGQDs/+j/0P99AX39VgHWAAAAAAAAAAAA//8BAOP/JQDb/18Azf7qAaP+uf8AAAAA AQD//wEA/f8KAOb/GwC//1YALf9qAPX/KBgIGCAYGxhCGAoYOhgLGMkRshGeEc8RYREfEo8ROBIdCmAKOwohCqsK+AlECr8JkgKV AmcCsgJdAr0CHwPWAlcDd/z3AfUAiQIqCYL8iQWg/qYGo/siBBEBRP96BCUAtwEH/rgCf/54ABkDz//yAYn/OwAoABMA/v+z/+4A lf/6/w8A6v/6//z/GgBv/xsA///2/xkACAAGAMf/BAGq/wIACQDr//b/+/8vABb/OwD///b/AAACAP//9v8gAOz/CxhUGJsVoh28 FioO4x/rFdkQtxL4EwEMCw/NIiIHaRQ+C5kHPAnKDAUNEvy3D7MIpAFuBKgC9QE4AeUITgHRAkgCk/9NAeoBYwTn/UwGmwNL/bgH mgFp/88A7gQD+zwD6gBn/r3+IAGlAXMAjgI+Adz+QAOa/xEAy/7uAfr7fwFoAIf9mwC+/3wAPwBlAT//0P43BMv9LAHx/Z8AVf6+ APkAX/ubAxv9ggNL+28EJP9r/4ABI/4JAlb8YwRs/HQAuBeIGmkWVxcKEiMbFhhaGNgTMAxsF9kP9SP4EBwNyBNjCTMMJAsSCRIB nA9zCk0KRAPoAWsB6QPYBYL/RwWTAtAAuAIeAagBqADTBuj6HwU0//8FUP+WARQCQgCVCxD+0gJZ9o0BI/8fAKUCwfmkBCn/kv/7 /4P/FQD+AHEDnv5HAOH9PAAiAKwA8PcGBtT96P+oAMMA0v7w/AoWj+iVBKj/sAEq/HoFxwEc7tQQj/tYAOT94gPJ+fgAegFw/F4A ZxeRFiEYCxjZGWgXtRfhF9gQFhLqDysRywsaElwSRRFECbgIuglkC2YObAibCuAJFAOgAvYCnQJ+AnQEKAK1AyQBlgOuAdMBoQIL AakEbAESAr7+EALHADQBdQLs/2ECwQDAACsAzgDZAAEB4wG+AHv/TADS/9n/n/+vAAQAaADg/zYA1P9MAOv/kv5NAJn/GAAN/1YB 1/1fANv+kgGe//f/YQBC/5QBKf/PAOb+PQDx//L/OgAk//z/iP9sANP/ ``` ## Problems and caveats - **The fitting code is not included.** It is reproducible from the description above: scipy sparse normal equations, visits from 60000..60255, 12 censoring iterations. Regenerating it would need my scratch scripts, which are not delivered; the blob above is the deliverable. - **Mirror exception.** One cell (`B1c`, level 6) differs from the mirror by 0.71 bps. The decoder reproduces the mirror, not the stored value. - **Grid rule versus point evaluation.** The reference clamps F̂ at the grid nodes and interpolates bilinearly, as real.py does. A contract that evaluates the spline directly at the continuous point would differ from this reference. Gate F needs the grid rule. - **Untested at these sizes.** Visit weights come from the full-table policy, so the visit distribution under the decoded policy may shift slightly. The weight power (1 vs 0.5) made no clear difference at 7.5 KB (0.068 vs 0.066, both se 0.011). - **Scope.** Everything is replica-only. Replica levels do not convert to board scores (README).