# qt2: Taylor's (gtmcknight) qm tables in trim-2's contract via the qm-spline compression (copy 2 of 2) **Outcome in one paragraph.** The port is built, compiles with the challenge compiler to **20,593 / 24,576 deployed bytes** (`contract Strategy is AMMStrategyBase`, no assembly, Taylor credited in the header), reproduces the reference fees to about 1e-6 bps on 48 of the 50 Gate F runs, and on the real engine (seeds 9536000..9536127, n=128) scores **+2.398 (SE 0.165) over t03** and **+1.005 (SE 0.063) over trim-2**. It **fails the gas limit**: pyrevm afterSwap peak **238,465** (target ≤ 200,000) and on the engine **93 OutOfGas in 1,418,815 afterSwap calls** (peak ok gas 249,487 against the engine's 250,000 transaction limit). Gate F is therefore **not passed as a whole**: 1 of 100,000 replica callbacks ran out of gas at 245,000 (seed 70032), and a second run (seed 70026) has a single-call divergence of 200.08 bps at callback 1702 whose cause I did not isolate in the time available. All figures are my local measurements. Nothing below is estimated or invented; what was not done is marked as such. Credit: the solved policy, the qm tables, the filter and the replica are Taylor's (gtmcknight), amm-sim @ 4812a638 `research/solved`; the WAD filter is port-3's, as trimmed by trim-2; the QMS1 blob and lookup rule are qm-spline's. ## Setup and gates P / check values | Step | Result | |---|---| | Platform | Linux x86_64 (required) | | amm-challenge @ 6b6921f8 cloned under the workspace's `test/scratch/`; port-3's setup script saved as `scratch/setup.sh` and run once from the checkout root | exit 0; wheel sha256 `aedb6828…` OK; `Strategy 'StarterStrategy' validated successfully!` | | Taylor amm-sim @ 4812a638, `research/solved` | cloned; README read first | | **Gate P**: unmodified `python3 -I gates.py` | gaussian+qm column **443.522608 / 571.623551 / 525.865859**: pass (whole table identical to the README) | | QMS1 blob decoded from qm-spline's base64 | 10,167 bytes, sha256 `3ac7cb8811ecfb6a17f499aa4e9b70dd55f7fb6432b3aec3b904e11a3dece38e` (matches) | | trim-2 `Strategy.sol` extracted from its artifact | 26,867 bytes, sha256 `6157028022f7f2151781ea3a772e4a99956ab9c38c8fbabf4995887d05564b27` (matches); compiles to 11,680 bytes | | t03 = zlib(base64(`code_zb64`)) | 27,712 bytes, sha256 `cb6d945511e1e10af78baa64c2a6cb25806f0998403ce6440654bfc3c70092d9` (matches); compiles to 14,654 bytes | | **Check values**, `real.RealPolicy(T, {'soft':1,'qm':decoded.json})` through `replica2.run`, seeds 10000..10002 | **443.101741 / 571.454483 / 525.908441**: reproduced exactly | | Same three seeds with the Python reference below (`QmRef`) | **443.101741 / 571.454483 / 525.908441**: identical | | Gate Q | not re-run: the shipped tables are exactly qm-spline's decoded tables, so its holdout figure (loss 0.0632, se 0.0072, n = 2048) stands | ## What was built - **Filter, state, fee conversion: trim-2's, unchanged.** `ln/exp/root/pdf/cdf/trunc/update/fee` and the three storage slots are trim-2's text. The only state change is one flag bit: slot 2 = `fb | fa<<64 | t<<128 | cnt<<192 (63 bits) | synced<<255`, because the qm rule needs real.py's `synced` (cleared at a new step, set when the rival candidate replaces the estimate). The initial fee is real.py's `init()` (plain table at (0,0,phase 0): A0[160][6] = B0[160][6] = 28.276 bps → 2823606104386592 WAD), not trim-2's net constant. - **Inputs to the lookup**, exactly as real.py's qm variant: w = (ln s − m)·1e4, R = (ln s2 − m)·1e4, phase (0 arb, 1 first retail, 2 later), synced, and **sd = the filter's posterior sd in bps**, `root(v)*10000` after the update. - **Table choice**: 0c in phase 0, else phase + (s if synced else c). pw = w/5 + 160 clamped to [0, 320]; phase 0 column = clip(R/5, ±6) + 6 over 13 columns; phases 1–2 column = real.py's `_pos2` over the 49 `W2L` nodes (binary search). sd level k with S[k] ≤ sd < S[k+1] (S = 0,4,8,12,16,20,26,34; k ≤ 6), tt clamped to [0, 1]. - **Lookup rule = qm-spline's decoder + real.py**: F at the 4 surrounding grid nodes × the 2 sd levels is the 3-D spline evaluated at integer nodes, clamped at 0 per node; A = w_node + F; bilinear in (row, col), then linear in sd. The **bid is the ask lookup at the mirror point** (320 − pw, last − p2), which is exactly bilinear interpolation of B = mirror(A). Fees then go through trim-2's `fee()` (1 − exp(−(a−w)·1e−4) if a > w, else 0; clamp 0..10%). - **Bases at runtime.** Row and column knot vectors are clamped ([0]×4 + interior + [L]×4) with interior knots stored as u16 lanes in 1/64 grid units; the span is found by a linear scan (warm-started for the i+1 / j+1 node) and the four cubic bases come from the Cox–de Boor triangle (`cdb`, 6 divisions, WAD). The sd axis has no interior knots, so its bases are the Bernstein cubic in level/7 (`bern`). No basis tables are stored. - **Coefficients as PUSH32 immediates.** The 4,896 int16 coefficients (unit 1/8 bps) are packed 16 per 32-byte word (lane l at bits 16·l), 306 words plus 2 zero pad words, grouped 4 per leaf of a binary if-tree (`cw4`, 77 leaves, depth 7). `seg8` returns up to 8 consecutive coefficients across a word boundary; `gather` walks, for each of the 4 sd slices, the union of rows that support the two row nodes (4 to 8 rows), reads one stripe per row, and contracts over columns (`dot4`) and rows into 16 partial sums G[s][ii][jj]; `side` finishes the sd contraction, the clamp, the bilinear and the sd-linear steps. - Generator: `gen.py` (not reproduced here for size; it splices trim-2's functions by text, parses the blob with the same layout as `qms_decode.parse`, asserts knots strictly increasing and inside (0, L) and at most 4 knots per unit interval, which bounds the column union to 8 lanes). Deployed runtime: **20,593 bytes** (solc 0.8.24, challenge settings). Source 39,323 bytes, sha256 `12a2c64008c7a8fbe0719296d0d21118cd7fe9f41596fecf8d0623df45a35c8b`. `amm-match validate` on the shipped file: `Strategy 'TaylorGaussianQmSpline' validated successfully!` ## Gate F (replica seeds 70000..70049, first 2,000 own-pool callbacks each, pyrevm at 245,000 gas per call) Each run drives Taylor's `replica2.run` with the Python reference `QmRef` (below), records the first 2,000 own-pool callbacks and stops; the callbacks are replayed in order on a fresh pyrevm deployment (init at 100/10,000; amounts and reserves as int(float·1e18)), as port-3's `check.py` does, with OutOfGas caught and counted instead of aborting. | | value | |---|---| | runs / callbacks / fee comparisons | 50 / 100,000 / 199,998 (one call returned nothing) | | calls ok at 245,000 gas | 99,999; **1 OutOfGas** (seed 70032, callback 198) | | **48 clean runs** (96,000 callbacks): max / mean abs fee diff | **5.826e-06 bps / 1.688e-07 bps** (≤ 0.01 bps) | | init fee diff (both fees) | 3.04e-14 bps | | seed 70032 | the one OutOfGas call leaves the contract's state one step behind; later fees differ up to 9.74 bps (consequence of the OutOfGas, not a second fault) | | seed 70026 | no OutOfGas, but callback 1702 differs by **200.08 bps** and later callbacks by up to a few bps (run mean 0.050 bps). Cause not isolated. The only discontinuities in the policy are the arb/retail decision (pi > 0.5), the synced flag and the phase count, so a near-tie that the WAD filter and float64 resolve differently is the likely cause; this is a hypothesis, not a finding | | **pyrevm afterSwap gas** | **peak 238,465** (seed 70046), mean 175,892.5 over the 99,999 ok calls; per-run peaks 210,422..238,465 | | init gas | 90,925 | | SHA-256 of the concatenated per-run trace hashes | `6b945af3e8c6bccbb3bf7d784e66f9684b097b3263f8627eabb41e1e82ea2f9c` | **Gate F verdict: not passed** (one OutOfGas and one unexplained divergent call; the fee agreement on the other 48 runs is far inside 0.01 bps). ## Engine (seeds 9536000..9536127, each strategy alone vs the 30 bps VanillaStrategy) `amm_sim_rs.run_batch(X, VanillaStrategy, configs, 8)`, configs per `MatchRunner._build_configs` (port-3's `engine.py` transcription), 4 chunks of 32 seeds, `gas_stats_reset()` / `gas_stats()` around each chunk, each seed run once per strategy, no reruns. The engine was run although Gate F did not pass, because the chunks took 10–25 s each and the brief asks for the numbers on a gas failure; the OutOfGas calls are part of what was measured. Mean submission edge: candidate 544.448167213, t03 542.050114695, trim-2 543.443483287. | Pair | n | mean_diff | se | worst5 (seed, diff) | ahead | |---|---:|---:|---:|---|---:| | candidate − t03 | 128 | **+2.398052519** | 0.165313914 | (9536090, −0.534798), (9536027, +0.084458), (9536056, +0.090745), (9536124, +0.106339), (9536080, +0.125765) | 127/128 | | candidate − trim-2 | 128 | **+1.004683926** | 0.063000969 | (9536062, −1.478659), (9536104, −0.443143), (9536076, −0.289520), (9536099, −0.266826), (9536049, −0.188722) | 118/128 | | trim-2 − t03 (same seeds, for reference) | 128 | +1.393368592 | 0.169543832 | (9536090, −1.807433), (9536125, −1.220042), (9536124, −1.064155), (9536080, −0.953721), (9536082, −0.799253) | 104/128 | SE = sample SD of the paired differences / √n. The +1.00 over trim-2 is in line with the replica gap between gaussian+qm and gaussian+plain (+3.77 − 2.83 = 0.94) minus the spline loss (0.06); the candidate's 93 OutOfGas callbacks (fees left at the previous quote) are included in its edge. ### gas_stats (Submission role; sums over the 4 chunks, peak = max over chunks, mean = sum_ok_gas / ok) | Strategy | Callback | Calls | OOG | Peak ok gas | Mean | |---|---|---:|---:|---:|---:| | candidate | afterInitialize | 128 | 0 | 90,925 | 90,925.00 | | candidate | afterSwap | 1,418,815 | **93** | **249,487** | 188,908.38 | | candidate | getName | 128 | 0 | 21,673 | 21,673.00 | | t03 | afterInitialize | 128 | 0 | 243,234 | 243,234.00 | | t03 | afterSwap | 1,405,984 | 0 | 235,290 | 135,364.58 | | t03 | getName | 128 | 0 | 21,742 | 21,742.00 | | trim-2 | afterInitialize | 128 | 0 | 90,800 | 90,800.00 | | trim-2 | afterSwap | 1,406,131 | 0 | 130,669 | 71,112.03 | | trim-2 | getName | 128 | 0 | 21,515 | 21,515.00 | revert, other_halt, tx_error and bad_return were 0 in every row. Candidate afterSwap peaks per chunk: 249,465, 249,487, 249,364, 248,917 (these are the largest *successful* calls; the 93 failures used the full limit). Engine peak − pyrevm peak ≈ 11,000 here, consistent with trim-2's note of about 15,000. ## Gas failure: the numbers and what it would take - Where the gas goes (pyrevm, measured by two ablation builds on the same callbacks): a call costs about 175k on average; computing only one side instead of two saves about 75k, so **each `side` lookup costs about 75k**; skipping `gather` (coefficient stripes) in both sides saves about 75k, so **`gather` is about 37k per side** and the bases, span search, node assembly and interpolation about 38k per side. trim-2's filter alone is about 60k mean / 105k peak (its 2-pass net was about 25k of its 115k pyrevm peak). - The first build (memory arrays for bases, per-row memory writes, a `lane()` call per coefficient) was 190k mean; the shipped build (bases packed as 64-bit lanes, unrolled `dot4`, per-slice accumulation, warm-started span search) is 176k mean. That is the whole gain available from local tidying; the OutOfGas peak needs about 50k more (engine peak ≤ ~235k with margin), i.e. roughly 35% of the lookup. - What would take it there, in order of expected effect: 1. **Pre-contract the sd axis offline**: the reference only ever evaluates the spline at the 8 integer sd levels, so storing the 2-D coefficients per level (Σ_s Bs[k][s]·C[s][r][c], int16) removes the 4-slice loop (gather and the sd contraction drop by ~4×, saving ~50k per pair) but doubles the data to 19.6 KB; with ~8 KB of code that is over 24,576 bytes unless the row/column knot counts are reduced (a smaller qm-spline fit, which changes Gate Q) or the two least-visited tables (2c: 30k visits, 1c: 445k) are kept at 4 slices. 2. **Store knot spans with 16-bit lanes pre-shifted per row** or evaluate ask and bid from one gathered block when their row unions overlap (they do not in general: the mirror point is far from the ask point), so only (1) is a sure win. 3. Cheaper selector: 8 words per leaf (depth 6) and `seg8` inlined into `gather` save an estimated 150 gas per stripe (≈ 5k per side); not enough on its own. 4. Dropping the per-node clamp (evaluating the spline at the continuous point) would cut the 8-node work to one evaluation but changes the reference; qm-spline's note says Gate F needs the grid rule, so it was not considered. - Size has headroom: 20,593 of 24,576 bytes (target 24,000 met). ## Files - `Strategy.sol` (verbatim, sha256 `12a2c64008c7a8fbe0719296d0d21118cd7fe9f41596fecf8d0623df45a35c8b`) and the Python reference `qmref.py` (sha256 `31f38bd7500354658b4a0f5914f1de0e8dabb7ffca006616584c8a8b92dff753`) follow. The reference is driven exactly as port-3's `check.py` drives `standalone.Coarse` (`QmRef(qm_json, pol_mid_json)`, `init()`, `on_trade(...)`), with `qm_json` = `qms_decode.py` output of the QMS1 blob and `pol_mid_json` = Taylor's `pol_mid.json` (only its axes and the init table are read). - Seeds consumed: engine 9536000..9536127 once per strategy (candidate, t03, trim-2); replica 70000..70049 (Gate F), 10000..10002 (check values). No other engine seed was touched. - Not done: Gate F does not pass (see above); isolating the seed-70026 divergence; the gas reduction needed for 0 OutOfGas. ## Strategy.sol (verbatim) ```solidity // SPDX-License-Identifier: MIT pragma solidity ^0.8.24; import {AMMStrategyBase} from "./AMMStrategyBase.sol"; import {TradeInfo} from "./IAMMStrategy.sol"; // Gaussian solved policy with uncertainty-aware (qm) tables by Taylor (gtmcknight), amm-sim 4812a638 research/solved // (real.py qm variant, qm_k1e-5.json, +3.77 vs HA on Taylor's replica). Filter, 3-slot state and fee conversion are trim-2's // (port-3's WAD port of real.py's Gaussian filter). The ~1,073,424 table values are replaced by qm-spline's QMS1 blob // (sha256 3ac7cb88..., 10,167 bytes): one 3-D cubic B-spline per table (0c,1s,1c,2s,2c), ask side only, bid at the mirror point. // Lookup rule = qms_decode + real.py: F at the 4 surrounding grid nodes x 2 sd levels, clamped at 0, A = w_node + F, // bilinear in (row, col), then linear in sd. B-spline bases by Cox-de Boor at runtime (knots as u16 lanes, 1/64 grid units); // sd axis has no interior knots (Bernstein cubic in level/7). Coefficients: int16 (1/8 bps), 16 lanes per PUSH32 word, // 4 words per leaf of a binary if-tree (cw4). No assembly, no memory tables of bases. // Taylor source: https://github.com/gtmcknight/amm-sim/tree/4812a6382311624e1506aca131ca35c378f930d9/research/solved contract Strategy is AMMStrategyBase { int256 constant U=1e18; int256 constant LN2=693147180559945309; uint256 constant M64=0xffffffffffffffff; // slots[0] = m (int128) | v (int128)<<128 ; slots[1] = sp (int128) | r (int128)<<128 ; slots[2] = fb | fa<<64 | t<<128 | cnt<<192 function getName() external pure override returns(string memory) { unchecked {return "TaylorGaussianQmSpline";} } function mul(int256 a,int256 b) internal pure returns(int256){ unchecked {return a*b/U;} } function divi(int256 a,int256 b) internal pure returns(int256){ unchecked {return a*U/b;} } function ab(int256 x) internal pure returns(int256){ unchecked {return x<0?-x:x;} } function clip(int256 x,int256 a,int256 b) internal pure returns(int256){ unchecked {return xb?b:x);} } function ln(int256 x) internal pure returns(int256 z){ unchecked { require(x>0); int256 k; while(x< U){x*=2;k--;} while(x>=2*U){x/=2;k++;} int256 y=divi(x-U,x+U); int256 y2=mul(y,y); int256 q=y; z=y; for(int256 n=3;n<=29;n+=2){q=mul(q,y2);z+=q/n;} return 2*z+k*LN2; } } function exp(int256 x) internal pure returns(int256){ unchecked { if(x< -42*U)return 0; require(x<60*U); int256 k=(x>=0?x+LN2/2:x-LN2/2)/LN2; int256 r=x-k*LN2; int256 r2=mul(r,r); int256 even=665280*U+mul(r2,75600*U+mul(r2,840*U+r2)); int256 odd=mul(r,332640*U+mul(r2,10080*U+mul(r2,42*U))); int256 s=divi(even+odd,even-odd); return k>=0?s*int256(uint256(1)<>128>0){z>>=128;r<<=64;} if(z>>64>0){z>>=64;r<<=32;} if(z>>32>0){z>>=32;r<<=16;} if(z>>16>0){z>>=16;r<<=8;} if(z>>8>0){z>>=8;r<<=4;} if(z>>4>0){z>>=4;r<<=2;} if(z>>2>0){r<<=1;} for(uint256 i=0;i<7;i++)r=(r+n/r)/2; return int256(r10*U)return 0;return divi(exp(-mul(x,x)/2),2506628274631000200);} } // Hart rational normal tail approximation; erf(x)=2*Phi(x*sqrt(2))-1. function cdf(int256 x,int256 density) internal pure returns(int256){ unchecked { int256 y=ab(x);if(y>8*U)return x>0?U:int256(0); int256 n=35262496599891000; n=mul(n,y)+700383064443688000;n=mul(n,y)+6373962203531650000; n=mul(n,y)+33912866078383000000;n=mul(n,y)+112079291497871000000; n=mul(n,y)+221213596169931000000;n=mul(n,y)+220206867912376000000; int256 d=88388347648318400; d=mul(d,y)+1755667163182640000;d=mul(d,y)+16064177579207000000; d=mul(d,y)+86780732202946100000;d=mul(d,y)+296564248779674000000; d=mul(d,y)+637333633378831000000;d=mul(d,y)+793826512519948000000; d=mul(d,y)+440413735824752000000; int256 tail=mul(mul(density,2506628274631000200),divi(n,d));return x>0?U-tail:tail; } } function trunc(int256 m,int256 v,int256 lo,int256 hi) internal pure returns(int256 Z,int256 mt,int256 vt){ unchecked { if(v<=0)return (lo<=m&&m<=hi?U:int256(0),m,0); int256 sd=root(v);int256 a=divi(lo-m,sd);int256 b=divi(hi-m,sd); int256 pa=pdf(a);int256 pb=pdf(b); Z=cdf(b,pb)-cdf(a,pa); if(Z<1e6)return(Z,m -w?U-exp(-(b+w)/10000):int256(0);fa=a>w?U-exp(-(a-w)/10000):int256(0); fb=clip(fb,0,U/10);fa=clip(fa,0,U/10); } } // ---- qm-spline lookup ---- // table meta: nr, nc (spline coefficients per axis), base (flat coefficient index), row knots (2 words), column knots (1 word) function meta(uint256 t) internal pure returns(uint256,uint256,uint256,uint256,uint256,uint256){ unchecked { if(t==0)return(24,10,0,0x2b762af92aaf2a6729f0290226fe2610259925512507248a23b422211e0711d1,0x0000000000000000000000000000000000000000000000003e2f31f92ddf2c4c,0x000000000000000000000000000000000000000002f002e0024800b8001b000b);if(t==1)return(24,14,960,0x2a892a072989291128a0283427cc276026ef267725f9257724df23f420d812c5,0x0000000000000000000000000000000000000000000000003d3b2f282c0c2b21,0x000000000000000000000000091007a906f6068d063005d00573050a045702f0);if(t==2)return(18,12,2304,0x0000000037dd2d9b2af42a2d298e28f7285527ab2709267225d3250c22651823,0x0000000000000000000000000000000000000000000000000000000000000000,0x000000000000000000000000000000000781074006bc064505bb054404c0047f);if(t==3)return(24,14,3168,0x2a992a092989291328a2283627ca275e26ed267725f7256724b42395204c12b7,0x0000000000000000000000000000000000000000000000003d492fb42c6b2b4c,0x000000000000000000000000094507e30720069d063305cd056304e0041d02bb);return(12,8,4512,0x00000000000000000000000000000000314e2bc82a0228c4273c25fe24381eb2,0x0000000000000000000000000000000000000000000000000000000000000000,0x00000000000000000000000000000000000000000000000007710685057b048f); } } // 4 consecutive coefficient words (16 int16 lanes each) of group g function cw4(uint256 g) internal pure returns(uint256,uint256,uint256,uint256){ unchecked { if(g<38){if(g<19){if(g<9){if(g<4){if(g<2){if(g<1){return(0x146514cb147814aa00001489186200001852188018631846184718390000183e,0x000007460e9700000e0e0f570ec90e150e780e1f00000e5014a4000014f3141c,0x05460606040d03bd03d703a0000003ba073d000007b1069b072f078f0732076a,0x01d50254000002010339000003ee02eb052d026f02a5026f0000028105cd0000);}return(0x01d9000000ac035503a5021401f301b5000001cc059b000006c7035802580326,0x030801b501c4017800000197035d000003aa02f801cc0294019501ea000001b2,0x000000fa01bc0000017302a201c202000133017600000162031300000331026f,0x00c400e700e2ffab017efe170000016b01ed00000297018201ed009401250205);}if(g<3){return(0xffd6ff03000001ea00840000008a0073ffcf001e002d01250000fd4100f80000,0x00000000000cffee0014fff4000a000e0000fdb2001f00000020fff9ffdfffaf,0x0002fffe0001fffb0000ffc2fffd0000fffe0003fffdfffb0008ffc30000004d,0x00000000ffff000000000000ffff00000000000000000001000100000002fffe);}return(0x0000000000000000000000000000000000000000000000000000000000000000,0x0000000000000000000000000000000000000000000000000000000000000000,0x0000000000000000000000000000000000000000ffff00000000000000000000,0x1158164b13b0158900001481185a000017db18ac194417aa187217c600001836);}if(g<6){if(g<5){return(0x000007440f0400000e091021120b0c330f2d0cdf00000e45144a00001526136e,0x053a062d04ca036903ec0379000003ba06b40000070a064e059a085c06d407e3,0x023801db0000020f03ae0000041103200425030c027802a60000028705ba0000,0x033a0000032302b302f4026c01c801ff000001da033f0000048e0390037c0250);}return(0x0269020c0171021b000001b603400000039f02ab033d01c601e80170000001c3,0x000000f60373000003a5016b02a4012b01de006600000166020300000255031f,0x023700390224fe96021cfad70000002201a80000008d02aa00690225ffad0369,0x04e8eccb0000023800740000ff56011afea602c8fc0e0df70000ffdf01140000);}if(g<7){return(0xffd00000ff0d0071ff6a010cfd6b06720000feca000a00000125ff6600c3fe12,0xffe8001fffda005f0000ffeb00140000005cffce0047ffa6007cfdc50000005a,0x0000ffff00040000000ffff9000afff60009ffe900000002fff40000ffcf0012,0x0029fff7000cfff50008fff200000001fffe0000fff20005fff90007fffa000b);}if(g<8){return(0x0009fff100000001ffe60000ff4f0016ffea0012fff300160000ffff00070000,0xfffa0000ffc40005fffa0004fffd00050000000000130000006effec0011fff3,0x178112ff15811389000014ad187d000018f9184517c9191d181b18cf00001852,0x0000075e0dbc00000ed60cf80be610c20d880ff000000e601595000014b61622);}return(0x04cc03cb04d904d903e8044d000003fa08ee00000882092f0928063007fe0689,0x025d029c0000024b03ee0000038e048802c30309033102a7000002ed04710000,0x03010000039202f702a001e8024801a200000212031f0000022d02e9031e026f,0x0287014a022e00a0000001c802860000023202c602250259018802b7000001cb);}if(g<14){if(g<11){if(g<10){return(0x0000010201ec00000267025e016902700098034f0000016802ed000002660276,0x0044019cff3401e6fe7604e50000ffc801d60000025500fa02defef60236fdca,0xf6c714b40000fbd9005c00000121ffaf0187fc7e02a8f673000000b800ff0000,0xffca000000cbff290183fd5c0354f92d0000017e004a0000fea50140fc9b05d9);}return(0x0038ffb0004fff5e00000016001e0000ffc60062ff230130fe7b03510000ff64,0x000000010016000000280006ffe6001effe100370000fffeffc50000ffcaffe5,0x003dfffeffe5001bffea00240000ffffffd20000ffaafffd000efff0000effe9,0xffee001d0000ffffff9600000009fff30025ffda001affd500000001002c0000);}if(g<12){return(0xffd300000014fffb0008fff80005fff800000000003c0000ffe7000cffe50019,0x143e14c5143a14800000144c18490000183218501854180c181317ef00001800,0x0000074f0e9d00000e560ebd0eb20dde0e500dd600000e1e1472000014a21459,0x047604db044d0428042a03fe00000412077c000007a40767077d07d2073b0783);}if(g<13){return(0x026602320000026a0388000003a5032d03af032002c002f2000002c804920000,0x02d20000028002e2028e028401fe02720000022e03050000033d031202c502b2,0x0203024a019e02ac000001ec02ab00000307025702b601e80238018a0000022d,0x0000014202460000026d01d902a00114023300ff000001d502790000026d02ac);}return(0x0140008f0134fff00121ff94000000b901a10000015a01f100e301ae00f50233,0x005dfe5500000010006300000012008eff9600b2ffd100ea0000000c00f50000,0xffe00000ffe9000bffe20043ff9b00a20000ffb2000d00000089ffb40055ff33,0x00000006fff400100000fffa00010000ffddfffe0010ffd7002eff8a00000008);}if(g<16){if(g<15){return(0x00000000fffb0000ffe10004fffeffff0002fffd0000ffff00050000001dfffb,0xffda0004fffe0001ffff000300000000000500000018fffa0004fffc0002fffc,0x0001ffff00000000000800000017fffd00000001ffff000100000000fff80000,0x000100000001ffff00000001ffff000100000000fff70000fff400010001ffff);}return(0x1435141b182b180917de18931875184e1862180f182c182c1822180a18061806,0x0d3c0d6d0d320d5b14b015bf156513961243134513b414c91472142c1461141b,0x063605ff062405df05ff05f00d020abb0c020f150fe70f140e300cdd0d440d91,0x02da02490287029f02600281024502620798098a06b404be049e050f05b70683);}if(g<17){return(0x03140331032a031901e601c501bb0193018301350477042a04ae04ca043c0398,0x032d032b02c70279022b020e0238019801a5011d014300f1039203ec033d030c,0x0314033f02b20295027602560242021201aa018401030186ffe001940342033d,0xfff6004402b402b60293026e023201f401d2019601ae013d00f900d800200112);}if(g<18){return(0x004800d3feb200d2029403190202023001e101c701910190012f00f600e10087,0x0083013a00a1ffcaffd8fe3901b10247024701bd01b8016401580127010a010e,0x00c600e2008500b40124fdbb032afb4b0a390235021e01a30161014100fc0106,0x009200e60081001500c000b400d800acfd140265073a068600ca01bd00e40120);}return(0xffe5018e0070006f007d00580031004f0063007dff95fefd0446068d008001a9,0x030705f3004b00e300680052fff0ffc7004b003e003d0042000bfed7051d06e9,0xfffdfff203be070eff4200f70010ffc6ffee001fffeaffe6002cffd8ffdf002a,0x0005fffffff7000300d104fffff00033ffca0015fff7fff3fffc000cffd70018);}if(g<28){if(g<23){if(g<21){if(g<20){return(0xfff60006fff70008fff9000202f4058cff570010fff60002fff60007fff9ffff,0x0021fff0000cfff80009fff60008fffc011202dcfecd005effc80019ffe5000a,0xffa10032ffcc0013ffee0009fff2000cfff70003fc260046fd77ff9a003effd7,0xfb5bffe70029ffe70019fff60009fffb0008fff90005fffe010e01e103bb0070);}return(0xffe7009a00660011ffed0007fff60003fffd0002fffc0003fffe00000008fcd8,0x13a1142e17c1182d17a517b6193f1a3119be17e61765185617bc17d617d917fb,0x0c400c5a0dcd0d0315ad13bb155b14ed12b210130f0c1487161213c814e7149d,0x072405a906f505e905e805c60a900df30be80c43112f132215670c600b3c0ddd);}if(g<22){return(0x04a001f8022c02a8022b02840218029308f406d2074e0603033e02e6019906ef,0x02e402ca026e02f4025d01d501b701d30154ffbc0499049b047e046204d4044b,0x030602f802eb02ce0298024b01b101bf018b01e2ffde02e7037903bd032b0378,0x0276031102b602bf0273024b021601e501cd017b014701280052ffff03870390);}return(0xff3d03be03e502e2027e02670237020601e801cb013d012d012f00ff000dff85,0x012dff4b0233ee7800df02a9026b01fd01f901b901b301320144012d00af00fd,0x00de0079ffb201fafb4c0ba905c202e201ac0247017501ae0145013800e3006e,0x00d400ba005400240029ff58025ef7c105a801ad028d017401a9014e012000d2);}if(g<25){if(g<24){return(0x012a0106006d00bbfff50053ffc9fe730478ff4503a00446018301b9014600fb,0x01c000f900c80041008f002dffe700feffe3020dfaeb011a0a8e056f01280136,0x083102ff012500c7007400b4fff8ffe3010aff900158fd850412ff0a085e0163,0x0136ffb009370457ffce00e60012ffa70029ff78ff850076ff49017efdcb0080);}return(0xffe7003cff9d00120d0101b801280020ffba007aff89006c0012ffc00065ff2a,0xffb8000affec000dffe8fffc140e0279ffb3ffb60065ffa9003bffd7fffa0012,0x0078ffc4001a000a00050009fffb000404df0316fe770146fece00cefec90062,0x0445fb85023afe5f006dff850025ffbf0024fff2019cfaa300baff940107ff6f);}if(g<26){return(0xdd651178f7c304a9fca50172ff6e0056ffdc0030ffe3000900a5fe7217e5eddd,0x0006ffe1065ef94a0169fe2d00c4ff600028ffd3000fffea000cfffcffce01c8,0x150f140e18bc187518b918c5179a1717176018c218f9183718961801186b1819,0x0e610dfd0c910dcf14571587140f13fc15fd173a17ce139c12be147513931439);}if(g<27){return(0x053805ff05970598066105e10ed20cba0e7f0ee40ad60a4308650f810f8b0dcf,0x028a04a603c40340026902de0252020f069b081c06010633085c0864094e04d3,0x031702bb02b601c4023a022d01d8022000a5018e049b04e5045004530352035e,0x034902fd028b0243022201dd01fb01c1019b01ac01ebffcf03b503c103a40314);}return(0x034e034602ee02910258020301e101bc0193017a0181016500a90021037b035b,0x00cafe3402d1030e02b90279021f01f501c501610184012e010e0125011aff38,0x00840114ffdf0479035c033b024c027e01dd01bd01500169010400c701220086,0x005e007a00e5ff4502c8f7aa034d025a02ef01f301e3015b014300eb00ef00d1);}if(g<33){if(g<30){if(g<29){return(0x00c5006b008b0052005e00c3fcaf057a061104f7019a02150142013100da00e6,0x00ec00830093002c000f0019ff570198fad900ee0722019d0233015f014f00ee,0x00d8013200bb008d0021fffd0040fef2ffd9fbf108bbfcf20333007d01ee0147,0x061e0167014d00c60072fffa0002ffd8fd99009cfdce0426f822025d0775052a);}return(0xfda50091089f0119019a003a006bffccfff600020171ff4a0114fd570471fe6d,0x001bffae0089ffd802c90145ffff009dffa1ff8200a9ffb9ff3d005aff6a0167,0xffdc000dfff20027ffcb000c037502f20098ffb0ffdb00b1ff21004f0022fff0,0xfd3b0121ffae001affedfffa0014fff9fd0305cdfaf4020afe7affdb0068ffe3);}if(g<31){return(0x0630fdd002dbfef4004cfffe000a0015ffe2000a01dffdfffd82086cfb7202bd,0x029f0564fca60139fe3a00aaffcc0003fff9fff50010fffbfc2e04e801b3f3e1,0xffa2009e009ffd270154ff9d0084ffb6000e000100000006fff900020199fb0a,0x131a13491852185d181b1814182c182f184117c317d017cd17d8173916ed173b);}if(g<32){return(0x0d3e0c620c710c811481145a145d144f13f513df136514a9148d140414051357,0x06e306440610055805f4058f0db00dfd0d6e0d660dec0dc00eae0c490cae0d00,0x03a5028002a60310028f03460261029006e806ad06d006a60646064605a20746,0x02c402b1027802c9025701fc02110256014b01690417042d038e037503940363);}return(0x02c702af027e025c0240022b01f801d201ee01b1017d016503bc03c7031e0310,0x038503a302bd02910242022a01fb01e901d801b301b101d700fa00c5038a03ae,0x006a00660393038c029c024c020d01db01c501c5017e0176019f0116011300b3,0x011e00ba002e000803a203af0282021101d501a101a30154015c0157013d0150);}if(g<35){if(g<34){return(0x00fc00e700e200cd0007002003d403fe021501d9017a0175013f014300fc0118,0x00ce00cf008300de0051010fff40ff5803e5042501a301bc0155013c011800e2,0x00e400ce0090007f008b008a00d5ffdc0099ff640468041801b80164011b00f6,0x014300ed00ae0066006b0046004d0088002400d8fde2007c047e03f201af0131);}return(0x03e502fb015200aa0062005a001ffff50091ffd10043ff51015bff60040e0311,0x006bffd0030e04440032009b0020ffbeff8a0011ff58002effc500b4fecd0043,0xfffa0016ffde00070301027e00c2002dffbc0055ffd9001d002dfff20013ff99,0x0010fff70006ffee000dfffa029e03c0ff790000ffd3ffa6002effe0ffe60006);}if(g<36){return(0x00b7ff7b000dfff500030002fffc000201d50187fed300a8ffeb0006000cfffb,0xfe550130ff320078fff10008fffcfffd0004fffefe36fe2c022bfba7013ffe94,0x025cfd2f0122ff22008affa4000cfffa00030001fffe000100fd0210fceb03ff,0x000f002dff7d0074ffab0021ffd9000ffffc0001ffffffff0001ffffff86fe63);}if(g<37){return(0x1327131a13281328185c17e118aa184e185d18431829182c1828181e18361826,0x0cdc0c780be20bf20bfc0bee0c1b0bf412f213a5129c12cb129612e013441339,0x041404f20390041803f1043b04a20487047a045b048104730c930b7a0d330c9c,0x019900d502040148047c023305fe04060399028201c201ee01e201a9026401a8);}return(0x029f0127ff8a01d500f001e60051016c01ed03e800c701f7012b04fa0438016c,0x01d901c601e801c601040190035000310168fde10388fffb02bc01a6037b027a,0x00af016e000d00e50187020901730139019601a7ffc60135009c0246ffdb015b,0x01060056ff93011e0125ff56012d003d0134013a010b016f0066010900d7002d);}if(g<57){if(g<47){if(g<42){if(g<40){if(g<39){return(0x00aa009900ca00baffc4002fffbc00b7016effa000730040012c000201fa0093,0xffff0006fff100000079ff0900deffe30019ffee002affc8ff90ff0400ceffaf,0x0009fffa0006fffd0000ffff00040000ffc7004cffad000afff10008fff30006,0xffdc005cff97000dffef000afff50005ffff0001fffbffff0018ffca0035fff9);}return(0x0000ffff000000000016ffbc0048fff6000cfff80007fffc0001000000020000,0x1b5b1816192718071813183f17cf180efff8000fffed0002fffc0002fffd0001,0x13bd0f1c176811910e6d0f5a0ec11410131d12d5133512f417c919b2163618d3,0x048403f704c004510b1c11a605f30e170fad10470f220b980be20c9b0b190c01);}if(g<41){return(0x041b043f02a501e801cf021b01450207048a015206f7035b02f902690374048c,0x02bf0059043b029102f2005f00b801f401a0015c040b008b03eb06c5021e045a,0x00cf00f601140107026103a40180025b01f8028502ef011c014900e6020200e0,0x011a013a014800e2006001e6fd3800ee020700d7031c01c60265015500730150);}return(0x013b0160023b00f701b2008500b1004e0029ff2f038fff76020700aa020601eb,0xfeee04a7fd85011600eb0148001f0109002200d00083ffbeffdefdd2012fffe4,0xff3c0010ffb0ffed006afe220121ff9800e7ff8b01ae0063011cffc4004e0010,0x006bfe2bff9f00390034ffbd0035ffec00050062ffad0015ff4002c0ff6e001d);}if(g<44){if(g<43){return(0x00220057ffac0017fff5ffc50136ffa1ffe10050ffc10008fff6ff920056ffe5,0xfe15018cff09003bffbaffee0023fff4fffe0068fe79008a00c9fef90091ffed,0xfff50032ffeaff4c0059ff9b001e00000017fffdfffa0002fffeffbf00b20013,0x13f01359131b137818e916831b82163a149718271773185e180c180818b81852);}return(0x072407c409690c5f0b900af30d7b0bec127e186c0c56188719ad16c11764128a,0x04d8071c02e5064106fa071605c004810491059d039c04be0d7c06ee13c10800,0x01770216009801f8034c011804cd02b1027a01e802d102f102980095034a01c7,0x0202018200cc0177012a0140ffbc01c0026d035301f60260021502c8025a017a);}if(g<45){return(0x01f3032a01430201016e0190016200e100ea01cafebf01be0275012903700213,0x007bff7ffee5009a01e30127027c013c01a000db00db002d00c4ff91042eff76,0x00e20016fff8ffef00080142ff5effd00144020a00ad016000a000d1003a0030,0x00480215007c007cffd20042ff2eff61ffcdfdebff1bff4100fe00c0020a00b1);}if(g<46){return(0xfff8ffa60045ffed003800ce00660074ffccffc40037003bffdc0154ff5f0042,0xfd8f002dffe9004a00090067ffb6001a0067fd2c0331fdaf00dffff50006ffd4,0x01a0f64f0e01f5c60444001c0033ff17ffd9ffcb0031ffeffe8d05fdf7b703c2,0xffd4001cfff30000fede0650f688073dfcf7fecd00590090004cffedffff0005);}return(0x18a61855180717b017da179c17201763004afd3e0411fc340177ffbc0036ff85,0x1336120214ce113e119d11ac127a13a512f9128c1245127517e6185b174a18a7,0x051003f1048b04650bb60d0509fc0dd10d840dad0c420aaf0b960b950ae40b3c,0x02ea030d025601c60210021702fa025d050d04d9055604b20462041b04b405b4);}if(g<52){if(g<49){if(g<48){return(0x027f021d02c80248023d01e601c4020b01df01f301d101da02ba035b024302e9,0x0154015101bc012e0216028101d7020d01e601dc0207016f01a901a7019d01ad,0x011b015000e20141011100d800f70129021500d302f2019101b801670156013a,0x01800047025300e5011000be00bd00c800a201b3000600ed016b0215011f0177);}return(0x000300e7ff92004e00d60165009300c1007b009500650087008dff91015d0051,0xfff4fff60002ffcd0013ff560069ffd200d7002c01300062007ffff10039005a,0xffa700a6fed00086ff500047ffd1002afff70047ffba000e008dffe500f6ffcf,0xffdd0069ffac00130038fedc0182ff10010cff660054ffb7000effa10048ffe9);}if(g<50){return(0x017dff530071ff8b0010ffc10031fff3ff9c01a1fd83019bfdb200faff45008b,0xffe40056ff70004eff5b002fffd80017fffa000dfff400010039fed501d9fe76,0x14361426187017951967183e183e182817f7182b181f1821180d180f18031807,0x0d5f0d790d660d6e13ee151a11de13c713a5142315151429143714301457141a);}if(g<51){return(0x062f063606440617062c062a0e110dd410000ed20e410da20c8c0d930d9d0d8b,0x022f02c202cc02b5029702a6028a028b05b506080443056305cb065806e70640,0x03d903b3030a01b101b601d201bc01b8018201760543051f051503900321028f,0x031302d1028a0253027602e0019e019f0185016f00dc017e03020342035f03ce);}return(0x029c02d402ad02cd02b5027a022301ab01e90146010d0142004b012603820381,0xff5700c0029302ff02650256022301f501df01d3016d00ff00e500f3000700b3,0x009a0029fff3ff66025d0211023a022a020701cf01910159014200f8009b00e7,0x00a90120ffd40125fd8100dc020e030f01c901d901a6017e0157013d00f9008c);}if(g<54){if(g<53){return(0x00c700cf007400d00087fe860243fe0c01be00e7027c01930186013c011200e7,0x00f800d400a5002900b800ac00df009bfdb10133092204b3011701c601180111,0x0005017c00a2004e0072004300340054003c00730097fea30219066f00bd016e,0x05ca06040046010800750071fffaffd50066001e007effeaffee00a4037606f5);}return(0x0047fff1022f06f5ff6201200030ffbfffeb001bffd00018ffb6008dfef7ffcf,0xfff50013ffe0000301370578fff50031ffc800100003fff7000bfff90010ffd2,0xfffc00010000fffc0006ffff01fe0632ff15001cffea000cffea000afff20006,0x000afffe00010000ffff0005fff9000100510279fedd005cffc90018ffea0005);}if(g<55){return(0x0020ffdf000cffee0005fffc0004fff7000afffdfed7ff3ffedaffea001cffef,0xfadc012cffb9002bffde0014fff60005fffc0008fff800020003012803d5fee4,0xfff3004e00adffa7000efff10006fffa0001fffe0001fffd0002ffff0025fe7a,0x13e0142017ec19301686193f18f418db170a176f181b182817b4180617c917f5);}if(g<56){return(0x0c4b0d330d9f0d231444122c17231122121f1223164f15cc13f713b4150113f9,0x060e0601069e063605ea062b0ddc0f800a9a12261103107609f80b060dbf0e02,0x013601be02c502ba0278029c027502a105b603cc083801e4045a04830882079d,0x039f02f5044f029901a401d401b701d9012b00fd054a067303a5059a03a70361);}return(0x02c1032d02db02fd01d4025e020601a901a101c000910192035302df03b2032a,0x02b7029f02bb02ab0276025b026b02130170017901390145ff5301a403450435,0xff5201e202f4026f02a1024a026c020501d6019f01570137012b00eb00beff38,0x009f005900fefb34021602b70207022601d301c901c9014c012400e500c200cc);}if(g<67){if(g<62){if(g<59){if(g<58){return(0x00f9ffae00ceff79004500e002920253022b01ea01d6018f0154012c00be00e0,0x00de00c80017007ffeec02c0fad3029701cd018901c1023201520187011e00c7,0x01030112007a00a30009000c0034faff0aaaf9a108190537013a0175018000fb,0x027600b9010a005f00800035ffec00ff000202ecf7d1041207970562013b0157);}return(0x047a044000c200d3008300880026ffd100d1ff9d0104fe69042efd9a06c3fdb2,0x00deffad08520420003700a80069ffa1fff1ff69ffcd0028ffc40061fe4a0129,0xffca0052ff61001804ce020b00a7004cff9e00200034001f0032ffcd003fff93,0xfff4fff7000affef0019fff60ee5052aff19fff9002f0007ff840016ffbb0026);}if(g<60){return(0x005affb90002000cfff7000fffef000702df01ebff0f00b8fee20084ff8e002c,0xff2efdcf00dbff7f003fffc30018ffdf0019fff7ffbcfdb30024fe5d01c8ff3f,0xec8506b6fded0265fe650096ffae002cffea0017fff00005012dfec90c12fafa,0x0001ffe30317fdb4001cff3c0047ffd20011ffef0006fff90005fffeffc50175);}if(g<61){return(0x14c8141418a117ea196f17f1183e1818196a18be18441846187d180518781828,0x0e2b0e5d0cc80e1a144c15911245159c1496151211f8134e1489146c1393145e,0x069405f20629057d06da05c50e400cf910d20c390db00d2d118d0fa10d540dfa,0x05680455032a035b02b402f80298023d0681081103f7082705f5069603c00569);}return(0x02a30341014002d102ee021701e4020d0134006704d8021406d301c0050b03c9,0x03be028902d201fc02d0014e01c101c1019f01a101e20159037c04dc029e0457,0x02f8036402b002d8026b021f019f019e01bf01670175014c017eff03036f0262,0x012dfeda0298030702950279021301e601da0160015a00fb012300c001d80074);}if(g<64){if(g<63){return(0x00dd00030159005602b702d602610277021401e20132015300f900e700f700af,0x00280113ffef012fff42fef1024a031e0225027201c40183013900f000dd007b,0x00c400520092ffda017dfd9e03abfdb002db033102d7015c01c8011f00dc00e0,0x0128009300810021fffdffdfff250383f67204d0048d01d701b101db013400ff);}return(0x0010018a00ac00930029fff1ffd1feddfed3fde3069bfca5051dfc7602b80132,0x032cfdb001f200ca00890031ffd8ffeefe0e00d0fe4d0246f944027b05d90759,0xfe77006f091f00e90141007e005affd60019ffe10126ff3d00c0feb303d4fe00,0x0029ffc8007fffddff2bff8c00cd004efff0ff620052ffddff570053ff9f009f);}if(g<65){return(0xffb60022ffd9002bffc8000d08fd011f0072ffd5ffcc00a0ff5400250046ffdf,0xfe8100a7fffffff9000dffef0019fff7ff0a02f8fd390115fe73fff50031fffd,0x047ffc2802cefe910039fff2fffe0004ffed00070460fb3703f9ff9bff1b01a8,0xfff302a5fb78030cfda30113ffb60013fff900050004fffdfaf0056ffd4dfdeb);}if(g<66){return(0xffc2007f00acfeee0187fe7100caff71001bfff30004fffcffff0001019afd6e,0x133213581806182217cd17f717e017d717a417b917dc17a517bb17281704172f,0x0d510c7a0cbd0ca01442140a147613f01421141c149a143b13f113f113f2130f,0x064b068d0604059c05e905af0d880dd80cf00dae0d420d330c690cdd0d7c0ce1);}return(0x02ee0306034b031802cb032702d702c206e10688073e066506e106c7076206d0,0x02fb0261032b020e021d020f022802610198018303a0046502a20406030c036f,0x026002b10267028701f6028e020501d201f401b0014201ac035d031e0353027c,0x030303000297025e023f0219020e01ea01bc01b301b701bd017100f502fa0365);}if(g<72){if(g<69){if(g<68){return(0x0110008602f7030e02660251020a01e601b301c8017b0194017d0155008d011c,0x00dc0158ff8d00f002ea02fa027f020001de019c01aa015c015301450148011c,0x010e00b0012900310148fff003340303023401c40176016e014601370102013f,0x00d000d000810104ffcd01f7fe1d011202890426011f0203013b0144011c00e3);}return(0x00ce00d500980087009000cf00cbff5f01a1fe72033a01c102350130013400fb,0x01b800c700cb0073006c0044007e0059009c002eff250088020d0556011b015f,0x029303de012200c00067004b0025fff90074ffd00053ffc400b3ff7c033300a2,0xffffffee02390292006600910032fff6ffc2ffcbffb30010fff8ffcdff940027);}if(g<70){return(0xfff7fffdfff30003028f02fb00bc0032ffd5ffb9003700020021fffbfffc001a,0x0024fff20007fff90006fffd01dd0348ff8effddffd7005dff9a0018ffd1000a,0xffb40003ffe30007fffa0004fffc000101a10057ff1900cbffaaff810053ffd9,0xffd0ffe8ffec00190008fffe0002ffff0002fffffe15ffbc00fffef0ff430073);}if(g<71){return(0x01eafecd005fffdb0025ffe30001ffff000000000000000000d60156fd7d017d,0xfff5006aff2d0056ffbf001bffe6000afffd0001ffff000100000000ffb9fea3,0x1238118f121f116111cf119e11b211c9180b183a180a1842181b182018081828,0x02d6031f02bd025d02b202670295029209bf0a4409f80aab0a210a3b0a600a1d);}return(0x0025047aff4401110422fba306a6fea00589fc82092a028900f501f7fc770357,0xff9500eeffb3fffe00130028003bff8901f2ffcf03190078fe7f02b8fe0701b7,0xffaa0104ffc7000600080019fff6ffff001bff6f001afffcfffaffea000ffffa,0xffec0020fff6ffff00020000fff6ffff003bff16002ffffbfff6ffeb00090002);}if(g<74){if(g<73){return(0x1469072222cd0f0b0c0113f812b710d915eb1fe30e2a16bc1da2159b1854180b,0x02d1014e08e5013801f502a8046e01a408b30fb7fc120d050cca093c07990b3e,0x033cfb0304ee00cfff69019a07b8fd4b039b064cfde7046301ea014dff930248,0x017ffbfa01eefecb0011ff9a0340fedc013e028e007301a50120febdfe6700ea);}return(0x00befe55009ffdf1012cfdcb0437fed0ff3f0165003f007cffbe009bfd870068,0x0074fc6c0463fc560209fe230180ff6bff24046ffb4b0382fd1b039bfb5f00f9,0x13c80d1c10f823f50fd9176c0c3013d8185a18161b23120a175716691a8817b8,0x02930547ff8205d803e9016b01e803440a4d0a730f9c011209120b240c330963);}if(g<75){return(0xfe100b95004202140196ff5005ffff34051ffae806d300a801a8011e02b800d0,0xfe9e037100fe0015ff83fffbff92ff2904a4f9c102a5001fff23018df65902d2,0x0495e88f160afcf0fed200c300a8ffe8fdd40606f7f000ac0022003cfde10047,0x005efc70017a00f8f9c903e2fde40058fb8f10d4ee1c01c7057afc2a01b0ffa8);}if(g<76){return(0x1145125c121a0bcb112b0fea121610d817e117b5176819d9180b182116911767,0x03b502280474027e029d02f602a0031409e00a9b086c0e660b6409ba08b80944,0x0261ffec0275013400c70210febe0212016c04a9010b02a101d301ae03960124,0x0068000400afff9fffd9ffd2004cff7b00be01e3010100d900ce002b00c000c1);}return(0xff9e0192fedb005ffdd70156ff0d0018ff99004dfe92ffeb004cffd40036ffe0,0xffd3006cff88fffcff24003afff2fff1003dfee600cfff290194ff420061fff7,0x0000000000000000000000000000000000000000000000000000000000000000,0x0000000000000000000000000000000000000000000000000000000000000000); } } // cnt (<=8) consecutive coefficients starting at flat index q, packed as 16-bit lanes from bit 0 function seg8(uint256 q,uint256 cnt) internal pure returns(uint256 p){ unchecked { uint256 l=q&15;uint256 wi=q>>4;(uint256 a,uint256 b,uint256 c,uint256 d)=cw4(wi>>2);uint256 s=wi&3; p=(s==0?a:(s==1?b:(s==2?c:d)))>>(16*l); if(l+cnt>16){uint256 w2;if(s<3)w2=s==0?b:(s==1?c:d);else(w2,,,)=cw4((wi>>2)+1);p|=w2<<(16*(16-l));} } } // knot t[idx] of the clamped vector [0]*4 + interior + [L]*4, in 1/64 grid units; n = number of coefficients function kt(uint256 k0,uint256 k1,uint256 n,uint256 L,uint256 idx) internal pure returns(int256){ unchecked { if(idx<4)return 0;if(idx>=n)return int256(L);idx-=4;return int256(((idx<16?k0:k1)>>(16*(idx&15)))&0xffff); } } // cubic B-spline bases at grid node x: span m (t[m]<=x>(16*(idx&15)))&0xffff)>x*64)break;m++;} uint256 KN;for(uint256 q=0;q<6;q++)KN|=uint256(kt(k0,k1,n,L,m-2+q))<<(16*q); P=cdb(KN,int256(x*64)); } } // Cox-de Boor, cubic, at xx with knots t[m-2..m+3] packed as 16-bit lanes of KN function cdb(uint256 KN,int256 xx) internal pure returns(uint256){ unchecked { int256 n0;int256 n1;int256 n2;int256 n3;int256 d;int256 sv;int256 ta;int256 tb; ta=int256(KN>>32&0xffff);tb=int256(KN>>48&0xffff); // t2,t3 d=tb-ta;n1=(xx-ta)*U/d;n0=(tb-xx)*U/d; ta=int256(KN>>16&0xffff); // t1 d=tb-ta;sv=(xx-ta)*n0/d;n0=(tb-xx)*n0/d; ta=int256(KN>>32&0xffff);tb=int256(KN>>64&0xffff); // t2,t4 d=tb-ta;n2=(xx-ta)*n1/d;n1=sv+(tb-xx)*n1/d; ta=int256(KN&0xffff);tb=int256(KN>>48&0xffff); // t0,t3 d=tb-ta;sv=(xx-ta)*n0/d;n0=(tb-xx)*n0/d; ta=int256(KN>>16&0xffff);tb=int256(KN>>64&0xffff); // t1,t4 d=tb-ta;{int256 sv2=(xx-ta)*n1/d;n1=sv+(tb-xx)*n1/d;sv=sv2;} ta=int256(KN>>32&0xffff);tb=int256(KN>>80&0xffff); // t2,t5 d=tb-ta;n3=(xx-ta)*n2/d;n2=sv+(tb-xx)*n2/d; return uint256(n0)|uint256(n1)<<64|uint256(n2)<<128|uint256(n3)<<192; } } // sum_c C[c]*coef(p lane c) for the 4 lanes of p (C packed 64-bit WAD lanes); result WAD x 1/8 bps function dot4(uint256 C,uint256 p) internal pure returns(int256){ unchecked { return int256(C&M64)*int256(int16(uint16(p)))+int256(C>>64&M64)*int256(int16(uint16(p>>16))) +int256(C>>128&M64)*int256(int16(uint16(p>>32)))+int256(C>>192)*int256(int16(uint16(p>>48))); } } // G[s*4+ii*2+jj] = sum_r sum_c R[ii][r] C[jj][c] coef[s][row][col] over the two row nodes (spans mi0, mi1) and column nodes (mj0, mj1) // dims = base | nr<<16 | nc<<24 ; sp = mi0 | mi1<<8 | mj0<<16 | mj1<<24 function gather(uint256 dims,uint256 sp,uint256 R0,uint256 R1,uint256 C0,uint256 C1,int256[16] memory G) internal pure { unchecked { uint256 base=dims&0xffff;uint256 nr=dims>>16&0xff;uint256 nc=dims>>24&0xff; uint256 mi0=sp&0xff;uint256 mi1=sp>>8&0xff;uint256 mj0=sp>>16&0xff;uint256 mj1=sp>>24&0xff;uint256 dj=mj1-mj0; for(uint256 s=0;s<4;s++){ int256 g00;int256 g01;int256 g10;int256 g11; for(uint256 row=mi0-3;row<=mi1;row++){ uint256 p=seg8(base+(s*nr+row)*nc+mj0-3,dj+4); int256 d0=dot4(C0,p);int256 d1=dot4(C1,p>>(16*dj)); if(row<=mi0){int256 wr=int256(R0>>(64*(row+3-mi0))&M64);g00+=wr*d0;g01+=wr*d1;} if(row+3>=mi1){int256 wr=int256(R1>>(64*(row+3-mi1))&M64);g10+=wr*d0;g11+=wr*d1;} } G[s*4]=g00/U;G[s*4+1]=g01/U;G[s*4+2]=g10/U;G[s*4+3]=g11/U; } } } // Bernstein cubic in u=level/7 (sd axis, knots 0^4 7^4) function bern(uint256 lvl) internal pure returns(int256 b0,int256 b1,int256 b2,int256 b3){ unchecked { int256 u=int256(lvl)*U/7;int256 v=U-u;int256 uu=mul(u,u);int256 vv=mul(v,v); b0=mul(vv,v);b1=3*mul(vv,u);b2=3*mul(uu,v);b3=mul(uu,u); } } // ask offset A (WAD bps) of table t at (pw,p2) (grid units, WAD, already clamped), sd level k and weight tt; ncol = grid columns function side(uint256 t,int256 pw,int256 p2,uint256 k,int256 tt,uint256 ncol) internal pure returns(int256){ unchecked { uint256 i=uint256(pw/U);if(i>319)i=319;int256 f=pw-int256(i)*U; uint256 j=uint256(p2/U);if(j>ncol-2)j=ncol-2;int256 g=p2-int256(j)*U; int256[16] memory G; { (uint256 nr,uint256 nc,uint256 base,uint256 kr0,uint256 kr1,uint256 kc)=meta(t); (uint256 mi0,uint256 R0)=basis(kr0,kr1,nr,20480,i,3); (uint256 mi1,uint256 R1)=basis(kr0,kr1,nr,20480,i+1,mi0); (uint256 mj0,uint256 C0)=basis(kc,0,nc,(ncol-1)*64,j,3); (uint256 mj1,uint256 C1)=basis(kc,0,nc,(ncol-1)*64,j+1,mj0); gather(base|nr<<16|nc<<24,mi0|mi1<<8|mj0<<16|mj1<<24,R0,R1,C0,C1,G); } int256 a0;int256 a1; for(uint256 kk=0;kk<2;kk++){ (int256 b0,int256 b1,int256 b2,int256 b3)=bern(k+kk); int256[4] memory A; for(uint256 n=0;n<4;n++){ int256 F=(b0*G[n]+b1*G[4+n]+b2*G[8+n]+b3*G[12+n])/U/8;if(F<0)F=0; A[n]=(int256(i+(n>>1))-160)*5*U+F; } int256 a=mul(mul(A[0],U-f)+mul(A[2],f),U-g)+mul(mul(A[1],U-f)+mul(A[3],f),g); if(kk==0)a0=a;else a1=a; } return mul(a0,U-tt)+mul(a1,tt); } } function w2l(uint256 idx) internal pure returns(int256){ unchecked { uint256 q=idx>>4;uint256 w=q==0?0xfff7fff6fff5fff4fff2ffefffecffe7ffe2ffd8ffceffc4ffb0ff9cff7eff60:(q==1?0x00070006000500040003000200010000fffffffefffdfffcfffbfffafff9fff8:(q==2?0x008200640050003c00320028001e001900140011000e000c000b000a00090008:0x00000000000000000000000000000000000000000000000000000000000000a0)); return int256(int16(uint16(w>>(16*(idx&15))))); } } // real.py _pos2: position of l2 (grid units, WAD) on the non-uniform rival axis W2L function pos2(int256 l2) internal pure returns(int256){ unchecked { if(l2<=w2l(0)*U)return 0;if(l2>=w2l(48)*U)return 48*U; uint256 lo=0;uint256 hi=48; while(hi-lo>1){uint256 mid=(lo+hi)>>1;if(w2l(mid)*U<=l2)lo=mid;else hi=mid;} int256 wl=w2l(lo)*U;return int256(lo)*U+(l2-wl)/(w2l(hi)-w2l(lo)); } } function sdlev(int256 sd) internal pure returns(uint256 k,int256 tt){ unchecked { int256[8] memory S=[int256(0),4*U,8*U,12*U,16*U,20*U,26*U,34*U]; while(k<6&&sd>=S[k+1])k++; tt=(sd-S[k])*U/(S[k+1]-S[k]);if(tt<0)tt=0;if(tt>U)tt=U; } } // w, r: own and rival displacement (WAD bps); ph: phase; sy: rival synced this step; sd: posterior sd (WAD bps) function fees(int256 w,int256 r,uint256 ph,bool sy,int256 sd) internal pure returns(int256,int256){ unchecked { int256 pw=clip(w/5+160*U,0,320*U);int256 l2=r/5;int256 p2;uint256 t;uint256 ncol; if(ph==0){p2=clip(l2,-6*U,6*U)+6*U;ncol=13;} else{p2=pos2(l2);ncol=49;t=ph==1?(sy?1:2):(sy?3:4);} (uint256 k,int256 tt)=sdlev(sd); int256 a=side(t,pw,p2,k,tt,ncol); int256 b=side(t,320*U-pw,int256(ncol-1)*U-p2,k,tt,ncol); return fee(a,w,b); } } // init fees: real.py init() = plain-table fees at (0,0,phase 0): A0[160][6] = B0[160][6] = 28.276 bps function afterInitialize(uint256 x,uint256 y) external override returns(uint256,uint256){ unchecked { int256 sp=int256(y*1e18/x); slots[0]=uint256(uint128(int128(ln(sp)))); slots[1]=uint256(uint128(int128(sp)))*(1+(uint256(1)<<128)); slots[2]=2823606104386592|uint256(2823606104386592)<<64; return(2823606104386592,2823606104386592); } } // filter update over a gap of dt steps; returns new m, v, rival spot r and the arb flag function update(int256 m,int256 v,int256 fb,int256 fa,int256 sp,int256 r,int256 s,bool buy,uint256 dt) internal pure returns(int256,int256,int256,bool arb){ unchecked { int256 lo=ln(mul(sp,U-fb));int256 hi=ln(divi(sp,U-fa)); uint256 n=dt-1;if(n>12)n=12; for(uint256 i=0;i0?divi(la,la+lr):int256(0);arb=pi>U/2; if(pi>5e15&&pi<995e15){ m=mul(pi,lp)+mul(U-pi,mt); v=mul(pi,mul(lp-m,lp-m))+mul(U-pi,vt+mul(mt-m,mt-m)); }else if(arb){m=lp;v=0;}else{m=mt;v=vt;} int256 pe=exp(m);r=clip(r,mul(pe,997e15),divi(pe,997e15)); return(m,v,r,arb); } } // slots[2] = fb | fa<<64 | t<<128 | cnt<<192 (63 bits) | synced<<255 function afterSwap(TradeInfo calldata t) external override returns(uint256,uint256){ unchecked { uint256 s0=slots[0];uint256 s1=slots[1];uint256 s2=slots[2]; int256 m=int256(int128(uint128(s0)));int256 v=int256(int128(uint128(s0>>128))); int256 sp=int256(int128(uint128(s1)));int256 r=int256(int128(uint128(s1>>128))); int256 fb=int256(s2&M64);int256 fa=int256(s2>>64&M64);uint256 cnt=s2>>192&0x7fffffffffffffff;bool sy=s2>>255==1; int256 s=int256(t.reserveY*1e18/t.reserveX);bool arb; if(t.timestamp>(s2>>128&M64)){(m,v,r,arb)=update(m,v,fb,fa,sp,r,s,t.isBuy,t.timestamp-(s2>>128&M64));cnt=0;sy=false;} uint256 ph; if(!arb){ int256 c=t.isBuy?divi(mul(s,U-fb),997e15):divi(mul(s,997e15),U-fa); if(t.isBuy?cr){r=c;sy=true;} cnt++;ph=cnt==1?1:2; } int256 w=(ln(s)-m)*10000;int256 rr=(ln(r)-m)*10000; (fb,fa)=fees(w,rr,ph,sy,root(v)*10000); slots[0]=uint256(uint128(int128(m)))|uint256(uint128(int128(v)))<<128; slots[1]=uint256(uint128(int128(s)))|uint256(uint128(int128(r)))<<128; slots[2]=uint256(fb)|uint256(fa)<<64|t.timestamp<<128|cnt<<192|(sy?uint256(1)<<255:0); return(uint256(fb),uint256(fa)); } } } ``` ## Python reference qmref.py (verbatim) ```python """qt2 Python reference: trim-2's filter (port-3's standalone.Coarse, a transcription of real.py's Gaussian filter) + real.py's qm fee rule (RealPolicy.lookup) over the DECODED qm-spline tables (qms_decode.py output of the QMS1 blob). Standard library only. usage: QmRef(qm_json_path, pol_mid_path)""" import math, json SIG2 = .000945 ** 2 LD_M, LD_S = math.log(11.12e-4), 1.176 def phi(x): return math.exp(-.5 * x * x) / math.sqrt(2 * math.pi) def Phi(x): return .5 * (1 + math.erf(x / math.sqrt(2))) def trunc(m, v, lo, hi): if v <= 0: return float(lo <= m <= hi), m, 0. sd = math.sqrt(v); a = (lo - m) / sd; b = (hi - m) / sd; z = Phi(b) - Phi(a) if z < 1e-12: return z, lo if m < lo else hi, v * .25 pa, pb = phi(a), phi(b); r = (pa - pb) / z return z, m + sd * r, max(0, v * (1 + (a * pa - b * pb) / z - r * r)) def clampf(f): return 0.0 if f < 0.0 else (0.1 if f > 0.1 else f) class QmRef: wants_j = True def __init__(self, qm_path, pol_path): self.Q = json.load(open(qm_path)); T = json.load(open(pol_path)) self.W0 = T['W0']; self.NW = T['NW']; self.N2 = T['N2']; self.FB = T['FB']; self.h = T['H_bps']; self.W2L = T['W2L'] self.A0, self.B0 = T['A0'], T['B0'] self.synced = False self.m = math.log(100); self.v = 0.; self.tlast = 0; self.cnt = 0; self.s2h = 100.; self.fb = self.fa = .003; self.sp = 100. # --- real.py (DPPolicy._pos2 / _fees for init, RealPolicy.lookup for the qm rule) --- def _pos2(self, v): W = self.W2L; n = self.N2 if v <= W[0]: return 0.0 if v >= W[n - 1]: return float(n - 1) lo, hi = 0, n - 1 while hi - lo > 1: mid = (lo + hi) // 2 if W[mid] <= v: lo = mid else: hi = mid return lo + (v - W[lo]) / (W[hi] - W[lo]) def _grid(self, w, w2, phs): pw = w / self.h + self.W0 if pw < 0: pw = 0.0 if pw > self.NW - 1: pw = float(self.NW - 1) l2 = w2 / self.h if phs == 0: if l2 < -self.FB: l2 = -self.FB if l2 > self.FB: l2 = self.FB p2 = l2 + self.FB; n2 = 2 * self.FB + 1 else: p2 = self._pos2(l2); n2 = self.N2 i = int(pw); j = int(p2) if i > self.NW - 2: i = self.NW - 2 if j > n2 - 2: j = n2 - 2 return i, j, pw - i, p2 - j def init_fees(self): # real.py init(): plain tables at (0,0,phase 0) i, j, f, g = self._grid(0.0, 0.0, 0) A, B = self.A0, self.B0 a = (A[i][j] * (1 - f) + A[i + 1][j] * f) * (1 - g) + (A[i][j + 1] * (1 - f) + A[i + 1][j + 1] * f) * g b = (B[i][j] * (1 - f) + B[i + 1][j] * f) * (1 - g) + (B[i][j + 1] * (1 - f) + B[i + 1][j + 1] * f) * g fa = 1.0 - math.exp(-a * 1e-4) if a > 0 else 0.0 fb = 1.0 - math.exp(-b * 1e-4) if b > 0 else 0.0 return fb, fa def lookup(self, w, w2, phs, sd): Q = self.Q; S = Q['S']; k = 0 while k < len(S) - 2 and sd >= S[k + 1]: k += 1 tt = (sd - S[k]) / (S[k + 1] - S[k]) if tt < 0.0: tt = 0.0 if tt > 1.0: tt = 1.0 tag = '0c' if phs == 0 else (str(phs) + ('s' if self.synced else 'c')) A, B = Q['A' + tag], Q['B' + tag] i, j, f, g = self._grid(w, w2, phs) def bl(Tb): return (Tb[i][j] * (1 - f) + Tb[i + 1][j] * f) * (1 - g) + (Tb[i][j + 1] * (1 - f) + Tb[i + 1][j + 1] * f) * g a = bl(A[k]) * (1 - tt) + bl(A[k + 1]) * tt b = bl(B[k]) * (1 - tt) + bl(B[k + 1]) * tt fa = 1.0 - math.exp(-(a - w) * 1e-4) if a > w else 0.0 fb = 1.0 - math.exp(-(b + w) * 1e-4) if b > -w else 0.0 return fb, fa # --- filter: standalone.Coarse (trim-2's filter) plus real.py's synced flag --- def init(self, *args): fb, fa = self.init_fees(); self.fb, self.fa = clampf(fb), clampf(fa); return fb, fa def on_trade(self, is_buy, ax, ay, t, x, y, arb=False, p=100., s2=100., j=0): s = y / x; dt = t - self.tlast; is_arb = False if dt >= 1: self.cnt = 0; lo = math.log(self.sp * (1 - self.fb)); hi = math.log(self.sp / (1 - self.fa)); m, v = self.m, self.v for _ in range(min(dt - 1, 12)): v += SIG2; _, m, v = trunc(m, v, lo, hi) v += SIG2 lp = math.log(s * (1 - self.fb)) if is_buy else math.log(s / (1 - self.fa)); sd = math.sqrt(v) la = phi((lp - m) / sd) / sd; Z, mt, vt = trunc(m, v, lo, hi); d = max(abs(math.log(s / self.sp)), 1e-9) lr = Z * .26 * phi((math.log(d) - LD_M) / LD_S) / (d * LD_S) pi = la / (la + lr) if la + lr > 0 else 0.; is_arb = pi > .5 if .005 < pi < .995: m2 = pi * lp + (1 - pi) * mt; self.m, self.v = m2, pi * (lp - m2) ** 2 + (1 - pi) * (vt + (mt - m2) ** 2) elif is_arb: self.m, self.v = lp, 0. else: self.m, self.v = mt, vt pe = math.exp(self.m); self.s2h = max(pe * .997, min(pe / .997, self.s2h)) self.synced = False if not is_arb: if is_buy: cand = s * (1 - self.fb) / .997 if cand < self.s2h: self.s2h = cand; self.synced = True else: cand = s * .997 / (1 - self.fa) if cand > self.s2h: self.s2h = cand; self.synced = True self.cnt += 1; ph = 1 if self.cnt == 1 else 2 else: ph = 0 self.tlast = t; self.sp = s fb, fa = self.lookup((math.log(s) - self.m) * 1e4, (math.log(self.s2h) - self.m) * 1e4, ph, math.sqrt(self.v) * 1e4) self.fb, self.fa = clampf(fb), clampf(fa) return fb, fa ```