# lattice-2: gas probe for Taylor's (gtmcknight) lattice filter in Solidity **Verdict: the lattice as Taylor wrote it (121 cells of 2.5 bps, 33-tap kernel, silent-step cap 30) does not fit.** I ported it exactly: it matches the Python lattice to about 1e-8 bps. Over 20,000 replayed callbacks its afterSwap gas averages 453k and peaks at 10.5M, and 64.5% of callbacks are over 245,000. Neither reduction alone fixes this. Cutting the step cap to 1 still leaves the 2.5 bps lattice at a 401k mean. The closest variant I measured is **10 bps cells, 31 cells, cap 1**: peak 258,576 and 15 of 20,000 callbacks over 245k, mean 105k. Driven by its own Python reference it peaks at 268,830 with 10 over 245k. So it is **near the budget but still over it**. On replica seeds 60000..60047 this variant costs −0.18 edge (se 0.09) against the full lattice with the same quotes, while port-3's Gaussian filter costs −0.61 (se 0.10). My verdict: **does not fit as ported, and no measured reduction fits on its own.** The next step should be a cheaper diffusion inner loop or a narrower kernel on top of 10 bps / cap 1. That is not measured here. All numbers are local runs: pyrevm `message_call` gas_used and the pure-Python replica. No engine seed was used: I did not run the engine `gas_stats()` on 9525000..9525063 because I ran out of time. ## Gate P (before any change) These were run on unmodified files from `gtmcknight/amm-sim@4812a6382311624e1506aca131ca35c378f930d9`, `research/solved`, with `python3 -I gates.py`: ```text 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 lattice+qm column matches the brief's figures (443.663520 / 571.977293 / 526.411631) and the README's gate block. Setup ran once from the amm-challenge checkout at 6b6921f8: exit 0, the wheel sha256 matched, and `Strategy 'StarterStrategy' validated successfully!`. ## (1) Per-callback work of the lattice update (`latt.py`) The source is `research/solved/latt.py`, class `LatticePolicy`. The README describes it as "probability mass on 121 cells of 2.5 bps". | item | value (source) | |---|---| | price cells | NC = 121, HC = 2.5e-4 log (2.5 bps), so ±150 bps around a moving centre `c` | | kernel | Gaussian, sigma = 9.45 bps per step = 3.78 cells, truncated at ceil(4·3.78) = 16 cells: **33 taps** | | silent step (each of `min(dt-1, 30)`) | `diffuse`: for each support cell with P > 1e-15, **33 multiply-adds**, and the support grows by 16 cells per side (clipped to 0..120). `cut`: one interval clip per support cell (two compares, one multiply when partial). `norm`: one divide plus one 1e-12 threshold per support cell, which also re-tightens the support | | step cap | **30** silent steps (`for _ in range(min(dt - 1, 30))`). The Gaussian `real.py` uses 12 | | first trade of a step | one more `diffuse` (33 MAC/cell); `dens` (2 cells); `cut`; the lognormal retail likelihood (2 ln, 1 exp); then either a pin, a renormalise, or a mixture (scale every cell, optionally `recentre` at 2 MAC/cell, `deposit` into 2 cells) | | every new step | `moments` (2 passes over the support), plus a second `recentre` + `moments` when \|m − c\| > 40 cells | | later trades in the same step | no lattice work: only the rival estimate and the table lookup | | persistent state (Python) | P[121] floats, c, lo_i, hi_i, m, v, fb, fa, sp, tlast, cnt, s2h, synced (synced only matters to the qm tables) | | persistent state (this port) | 31 of the 32 `slots`: 0..7 m, v, fb, fa, sp, r, t, cnt (port-3's layout); 8 c; 9 lo, hi; 10..30 hold the 121 cells packed 6 per word as 42-bit fixed point (scale 2^41, bit 255 set so a word is never zero and a write never pays the zero-to-nonzero price). Only the words that overlap the support are read and written | Worst case per silent step is 121 × 33 = 3,993 multiply-adds. Typical cases are smaller. After a cut, the support is the no-arb interval (about 20–30 cells) plus the kernel tails. A mixture posterior (point mass plus the cut prior) can span most of the window. Why the gas comes out this way: one MAC on a Solidity memory array costs roughly 60–80 gas, because of bounds checks plus mload/mstore. One diffusion of a 60–120-cell support therefore already costs about 250–300k. That is why cap 1 hardly helps at 2.5 bps (mean 401k). ## (2) The port - `contract Strategy is AMMStrategyBase`: port-3's shell (artifact 0dbcc10a…) with its Strategy.sol (sha256 `62930b8e…2ac1`, matching port-3's stated hash) kept verbatim for the header, TABLE, `mul/divi/ab/clip/ln/exp/pdf`, `knot/lookup/blend/fees` and `getName`. Port-3's Gaussian `root/cdf/trunc/update/afterSwap/afterInitialize/save` were replaced by the lattice. There is no assembly; arithmetic is WAD and unchecked, as in port-3. - The quotes are port-3's coarse **plain** tables, not qm: the qm tables (8 sd levels) are not in the shell. So the contract is a **gas and filter-fidelity probe**, not the +4.26 policy. - `amm-match validate`: `Strategy 'TaylorLatticeProbe' validated successfully!` - Deployed runtime: **20,992 bytes** (2.5 bps/121); 20,598 (5 bps/61); 20,404 (10 bps/31). Limit 24,576. - Taylor (gtmcknight) is credited in the header. - The variants come from one generator. Only the constants `HC`, `NC`, `N0`, `KM`, `CAP` and the kernel literal in `kern()` change between them. - The verbatim full contract and the sha256 of every variant are at the end. ## (3) Replay in pyrevm: seeds 70100..70109, 2,000 callbacks each (20,000 total) How the replay works: 1. A driver policy runs the replica (Taylor's `replica2.run`). 2. Its first 2,000 own-pool callbacks are recorded, together with its fees and its (m, v) after each callback. 3. A fresh deployment of the contract gets `afterInitialize(100e18, 10000e18)` and then the same callbacks, converted with `int(float*1e18)`. There is no state injection. 4. After each call, `slots[0]` (m) and `slots[1]` (v) are read from storage and compared with the driver's per-callback m and sqrt(v). 5. The gas limit per call was 60M, so peaks are measured rather than cut off. **OOG@245k counts callbacks whose gas_used is above 245,000.** There are two drivers: - **taylor**: `latt.LatticePolicy(T, {'qm': qm_k1e-5.json})`, Taylor's +4.26 policy, unmodified. - **exact**: Taylor's `latt.LatticePolicy` code unmodified, with only `init`/`lookup` replaced by port-3's coarse plain fee function (`standalone.Coarse._fees` over the same TABLE). This is the Python twin of the contract, so the fees in force (and therefore the cut intervals) are identical. ### Gas table (afterSwap, pyrevm gas_used) | contract (cells × width, cap) | driver | callbacks | peak gas | mean gas | OOG@245k | runtime bytes | |---|---|---:|---:|---:|---:|---:| | 121 × 2.5 bps, cap 30 (Taylor's) | exact | 20,000 | 10,513,884 | 453,463 | 12,900 | 20,992 | | 121 × 2.5 bps, cap 30 (Taylor's) | taylor (qm) | 20,000 | 13,998,870 | 445,920 | 12,848 | 20,992 | | 121 × 2.5 bps, cap 2 | exact (full) | 20,000 | 2,442,141 | 427,486 | 12,900 | 20,992 | | 121 × 2.5 bps, cap 1 | exact (full) | 20,000 | 1,688,758 | 401,460 | 12,899 | 20,993 | | 61 × 5 bps, cap 30 | exact (full) | 20,000 | 3,075,267 | 190,284 | 4,695 | 20,598 | | 61 × 5 bps, cap 2 | exact (full) | 20,000 | 815,784 | 182,332 | 4,698 | 20,598 | | 61 × 5 bps, cap 1 | exact (full) | 20,000 | 575,880 | 174,297 | 4,705 | 20,598 | | 31 × 10 bps, cap 30 | exact (full) | 20,000 | 1,098,264 | 110,623 | 499 | 20,403 | | 31 × 10 bps, cap 2 | exact (full) | 20,000 | 335,145 | 107,761 | 116 | 20,403 | | 31 × 10 bps, cap 1 | exact (full) | 20,000 | 258,576 | 104,959 | 15 | 20,404 | | 31 × 10 bps, cap 1 | its own Python twin | 20,000 | 268,830 | 105,008 | 10 | 20,404 | Per seed, for the full port under the exact driver (peak / mean / OOG@245k): - 70100: 8,696,300 / 410,339 / 1,217 - 70101: 3,930,815 / 431,510 / 1,286 - 70102: 5,721,893 / 419,317 / 1,258 - 70103: 10,513,884 / 482,516 / 1,309 - 70104: 4,673,332 / 452,341 / 1,293 - 70105: 5,472,113 / 439,127 / 1,272 - 70106: 6,451,314 / 471,482 / 1,334 - 70107: 8,390,326 / 537,315 / 1,414 - 70108: 6,985,824 / 392,134 / 1,154 - 70109: 5,631,425 / 498,549 / 1,363 For scale, port-3 reports a pyrevm replay peak of 156,888 (mean 61,334) for its Gaussian port on other callbacks. Engine numbers include more than pyrevm gas_used: port-3 measured 206,161 on the engine. A pyrevm peak near 245k is therefore not safe on the engine. ### Match table (per callback, |contract − reference|) | contract | driver / reference | max \|m − ref\| bps | mean \|m − ref\| bps | max \|sd − ref\| bps | mean \|sd − ref\| bps | max fee diff bps | |---|---|---:|---:|---:|---:|---:| | 121 × 2.5, cap 30 | exact (Python twin) | 1.15e-8 | 7.2e-11 | 1.28e-8 | 6.4e-11 | 9.4e-9 | | 31 × 10, cap 1 | its own Python twin | 8.3e-9 | 4.9e-11 | 7.0e-9 | 4.4e-11 | 7.8e-9 | | 121 × 2.5, cap 30 | taylor (qm quotes) | 57.7 | 3.66 | 24.8 | 1.12 | 35.6 | | 121 × 2.5, cap 2 | exact full | 33.2 | 1.00 | 16.2 | 0.27 | 34.4 | | 121 × 2.5, cap 1 | exact full | 41.5 | 2.40 | 33.0 | 0.72 | 30.2 | | 61 × 5, cap 30 | exact full | 18.9 | 0.40 | 12.1 | 0.15 | 15.5 | | 61 × 5, cap 2 | exact full | 32.8 | 1.22 | 16.8 | 0.37 | 35.0 | | 61 × 5, cap 1 | exact full | 41.5 | 2.56 | 33.1 | 0.77 | 30.0 | | 31 × 10, cap 30 | exact full | 31.2 | 1.54 | 32.9 | 0.65 | 19.0 | | 31 × 10, cap 2 | exact full | 41.5 | 2.19 | 32.6 | 0.78 | 32.5 | | 31 × 10, cap 1 | exact full | 55.6 | 3.33 | 33.1 | 1.07 | 31.0 | Reading the table: - **Port fidelity.** The first two rows test the port itself. They are at about 1e-8 bps, so Gate-F-style agreement (0.01 bps) holds by six orders of magnitude for both the full and the 10 bps/cap 1 port. - **The taylor (qm) driver row.** This compares the contract with Taylor's own lattice+qm run. The contract quotes from plain tables, so its fees in force, and therefore its cut intervals, differ from the qm run. The gap there measures that quote mismatch, not a port error. - **Reduction rows.** These are closed-loop. Each reduced contract sets its own fees, so its trajectory drifts from the full reference it is compared with. Max values are single-callback spikes after ambiguous arb/retail calls; the means are the better summary. ### Replica edge of the reductions (Python twins, port-3 quotes, paired) Seeds 60000..60047 (n = 48, from the brief's choice range; the 10000..12047 report range was not run). Each policy is on its own trajectory and is compared with the full lattice (121 × 2.5, cap 30) using the same coarse plain quotes, whose mean edge is 541.3482. | policy | minus full lattice | se | |---|---:|---:| | 61 × 5 bps, cap 30 | −0.043 | 0.036 | | 31 × 10 bps, cap 2 | −0.086 | 0.076 | | 61 × 5 bps, cap 1 | −0.173 | 0.072 | | 31 × 10 bps, cap 1 | −0.182 | 0.087 | | port-3 Gaussian filter (same coarse plain quotes) | −0.615 | 0.097 | | Taylor lattice + full qm tables (reference only) | +1.754 | 0.108 | On this small sample the 10 bps / cap 1 lattice keeps about 0.43 of the 0.61 the lattice gains over the Gaussian with plain coarse quotes. Most of the +4.26 headline comes from the qm tables (+1.75 here), which this shell does not have. ## (4) Reductions: what brings the peak under 245,000 - **Fewer cells (wider cells).** This is the strongest lever. Wider cells shrink both the cell count and the tap count (2.5 bps: 33 taps; 5 bps: 17; 10 bps: 9). Mean gas falls 453k → 190k → 111k at cap 30. - Only 10 bps cells get the bulk of callbacks under 245k: 499 → 15 OOG as the cap drops. - At 5 bps, about 23.5% of callbacks are still over 245k at any cap: one diffusion of a wide mixture support already exceeds the budget. - **Collapsing silent steps (step cap).** Cutting the cap from 30 to 2 or 1 removes the multi-million peaks (long silent gaps). It does not move the mean much, because most new steps have dt = 1. The match cost grows as the cap shrinks (mean |Δm| at 10 bps: 1.54 → 2.19 → 3.33 bps). I did not test the alternative of one σ·sqrt(n) diffusion followed by one cut. - **Cheaper exp/ln.** Not the bottleneck. The lattice update calls ln 5–6 times and exp twice per new step, the same as port-3's Gaussian path; port-3's whole Gaussian callback averages about 61k in pyrevm. The diffusion MAC loop dominates (thousands of MACs per step), so cheaper exp/ln would save at most a few thousand gas and was not measured separately. - **Best measured combination: 31 × 10 bps, cap 1.** Peak 258,576 (exact-full driver) and 268,830 (self driver); 10–15 per 20,000 callbacks over 245k; mean 105k; replica −0.18 ± 0.09 against the full lattice. It still exceeds the limit. On the real engine, which has extra overhead, it would very likely have more OutOfGas. **Not fitting.** - **Not measured (candidates):** - truncating the kernel at 3σ (10 bps: 7 taps instead of 9); - skipping cells below 1e-9 instead of 1e-15 in `diffuse`; - a 1-step cap combined with a narrower window, e.g. 21 cells × 10 bps; - an unrolled or bounds-check-free inner loop without assembly (fixed-size `int256[31] memory` arrays). ## Problems and limits - **No engine run.** `gas_stats()` on 9525000..9525063 was not run because of time, so no engine seed was used. All gas figures are pyrevm `message_call` gas_used. Engine figures are higher; port-3's own contract read 206,161 on the engine. - **Quotes are port-3's coarse plain tables, not qm.** So this measures filter gas and fidelity, not the +4.26 policy's score. - **The full port needs very large gas.** For the full lattice, the first replay attempt with a 10M per-call gas limit ran out of gas on a seed-70103 callback. The rerun used 60M; the measured peak is 13,998,870 under the taylor driver. - **Not tested at the edges:** the `recentre` edge clamps when a shift is over 60 cells, and a fully dead lattice (norm returns false), are rare paths that were not exercised separately. - **Scratch only.** Variant contracts, generator and harness were scratch files under `test/scratch/` and are not delivered except as described here. Replica seeds used: 70100..70109 (replay) and 60000..60047 (edge). No other seeds were consumed. ## Contract (full port: 121 × 2.5 bps, cap 30), verbatim sha256 of the file below: `cf9a9ba84ff70b054bbc5ae78fd16626a86f64b0bcbf92fab45ef4738e9e0eaf` (34,645 bytes). It was validated with `amm-match validate`; the deployed runtime is 20,992 bytes. The variants come from the same generator and differ only in the constants and the `kern()` literal: | variant | sha256 | |---|---| | 10 bps / 31 / cap 1 | `77e2a33a9d8acc531b83a1669e366c99ba75e7fb1adca4cd8630c71027b33b63` | | 10 / 31 / 2 | `af9976bfafcdf0ce4135d85d76e22d49810807a4d6614b34d34cbccfcf8eb9a7` | | 10 / 31 / 30 | `2d07498826e41e2cd55368e7f0edb2387f94c3cef80e524db8612dc73213d2f6` | | 5 / 61 / 1 | `3766e72243482d831b92ffd251130fc13d4867f5fb5f5961ef789e14dc60bdce` | | 5 / 61 / 2 | `22ee4fd2fe92a19a97c36793da04020f10df8d60c78989cee6024c5ba658f155` | | 5 / 61 / 30 | `3b1fb4df38b21a99e10f4672f068668fd0542bc17979b46e5f096082cc10bfe8` | | 2.5 / 121 / 1 | `e586161feb81d5c3664875e5336871369575f82d8fb3b079a7313eea16ecdfeb` | | 2.5 / 121 / 2 | `932b872c32510a2fadf500ddae5f309dc2e5ad9542010d594223bd5f74fd9b80` | The TABLE literal is port-3's, byte for byte. ```solidity // SPDX-License-Identifier: MIT pragma solidity ^0.8.24; import {AMMStrategyBase} from "./AMMStrategyBase.sol"; import {TradeInfo} from "./IAMMStrategy.sol"; // Lattice filter (latt.py) of the solved policy by Taylor (gtmcknight), amm-sim 4812a638, // ported into port-3's shell (its quote code, coarse plain tables, WAD math). Gas probe. // Port: signed WAD arithmetic; coarse plain tables, signed int16 eighth-bps. // TABLE uses 32 payload bytes per 33-byte block, prefixed with PUSH32 (0x7f). // Taylor source: https://github.com/gtmcknight/amm-sim/tree/4812a6382311624e1506aca131ca35c378f930d9/research/solved contract Strategy is AMMStrategyBase { int256 constant U=1e18; int256 constant LN2=693147180559945309; bytes constant TABLE=hex"7fff3eff46ff4dff53ff58ff5dff61ff3eff47ff4eff53ff59ff5dff62ff3fff477fff4eff54ff59ff5eff62ff3fff48ff4eff55ff5aff5fff63ff40ff48ff4fff557fff5bff5fff64ff40ff48ff4fff56ff5bff60ff65ff41ff49ff50ff56ff5cff617fff66ff41ff4aff51ff57ff5dff62ff66ff42ff4bff51ff58ff5eff63ff67ff437fff4bff52ff59ff5fff64ff68ff44ff4cff53ff59ff5fff65ff6aff44ff4dff547fff5aff60ff66ff6bff45ff4dff54ff5bff62ff67ff6cff46ff4eff55ff5dff637fff69ff6eff47ff4fff57ff5eff64ff6aff6fff48ff50ff58ff5fff66ff6cff717fff49ff51ff59ff61ff68ff6eff72ff4aff53ff5aff62ff69ff6fff74ff4cff547fff5cff64ff6bff71ff77ff4dff56ff5eff66ff6dff74ff79ff4fff57ff60ff687fff70ff76ff7cff50ff59ff62ff6aff72ff79ff7fff52ff5bff64ff6dff75ff7d7fff83ff54ff5eff67ff70ff78ff81ff88ff57ff61ff6bff74ff7dff85ff8dff5a7fff64ff6eff78ff82ff8bff93ff5eff68ff73ff7dff88ff92ff99ff61ff6cff787fff83ff8fff99ffa2ff65ff71ff7eff8aff97ff9effa4ff6aff77ff85ff93ffa07fffa500adff70ff7eff8dff9cffab008e00c0ff77ff86ff97ffaaffb700a700d47fff80ff91ffa6ffbb007c00bd00e7ff8aff9dffb8ffe7009c00d200fbff94ffad7fffd4006e00b600e8010effa5ffc40019008d00cc00fd0122ffbbffea005700a67f00e0010e0134ffee0022007700b900f0011f0145005f0061009300c90100012f7f0157009a009000a800d7010c0139016100ec00dd00bd00e201170144016d01147f010500f100f601220154017f01400140014001400140016b019701e001e001e07f01e001e001e001e00280028002800280028002800280032003200320032003207f0320032003c003c003c003c003c003c003c004600460046004600460046004607f050005000500050005000500050005a005a005a005a005a005a005a0064006407f0640064006400640064006e006e006e006e006e006e006e007800780078007807f078007800780082008200820082008200820082008c008c008c008c008c008c07f08c009600960096009600960096009600a000a000a000a000a000a000a000aa07f0aa00aa00aa00aa00aa00aa00b400b400b400b400b400b400b400be00be00be07f0be00be00be00be00c800c800c800c800c800c800c800d200d200d200d200d207f0d200d200dc00dc00dc00dc00dc00dc00dc00e600e600e600e600e600e600e607f0f000f000f000f000f000f000f000fa00fa00fa00fa00fa00fa00fa0104010407f1040104010401040104010e010e010e010e010e010e010e011801180118011807f118011801180122012201220122012201220122012c012c012c012c012c012c07f12c01360136013601360136013601360140014001400140014001400140014a07f14a014a014a014a014a014a0154015401540154015401540154015e015e015e07f15e015e015e015e01680168016801680168016801680172017201720172017207f1720172017c017c017c017c017c017c017c018601860186018601860186018607f19001900190019001900190019001900190019001900190019001900186018607f1860186018601860186017c017c017c017c017c017c017c017201720172017207f172017201720168016801680168016801680168015e015e015e015e015e015e07f15e0154015401540154015401540154014a014a014a014a014a014a014a014007f140014001400140014001400136013601360136013601360136012c012c012c07f12c012c012c012c01220122012201220122012201220118011801180118011807f1180118010e010e010e010e010e010e010e010401040104010401040104010407f0fa00fa00fa00fa00fa00fa00fa00f000f000f000f000f000f000f000e600e607f0e600e600e600e600e600dc00dc00dc00dc00dc00dc00dc00d200d200d200d207f0d200d200d200c800c800c800c800c800c800c800be00be00be00be00be00be07f0be00b400b400b400b400b400b400b400aa00aa00aa00aa00aa00aa00aa00a007f0a000a000a000a000a000a00096009600960096009600960096008c008c008c07f08c008c008c008c00820082008200820082008200820078007800780078007807f0780078006e006e006e006e006e006e006e006400640064006400640064006407f05a005a005a005a005a005a005a00500050005000500050005000500046004607f0460046004600460046003c003c003c003c003c003c003c003200320032003207f032003200320028002800280028002800280028001e001e001e001e001e001e07f01e00197016b01400140014001400140017f0154012200f600f101050114016d7f0144011700e200bd00dd00ec01610139010c00d700a80090009a0157012f01007f00c900930061005f0145011f00f000b900770022ffee0134010e00e000a600577fffeaffbb012200fd00cc008d0019ffc4ffa5010e00e800b6006effd4ffadff947f00fb00d2009cffe7ffb8ff9dff8a00e700bd007cffbbffa6ff91ff8000d400a77fffb7ffaaff97ff86ff7700c0008effabff9cff8dff7eff7000adffa5ffa0ff937fff85ff77ff6affa4ff9eff97ff8aff7eff71ff65ffa2ff99ff8fff83ff78ff6c7fff61ff99ff92ff88ff7dff73ff68ff5eff93ff8bff82ff78ff6eff64ff5aff8d7fff85ff7dff74ff6bff61ff57ff88ff81ff78ff70ff67ff5eff54ff83ff7dff757fff6dff64ff5bff52ff7fff79ff72ff6aff62ff59ff50ff7cff76ff70ff68ff607fff57ff4fff79ff74ff6dff66ff5eff56ff4dff77ff71ff6bff64ff5cff54ff4c7fff74ff6fff69ff62ff5aff53ff4aff72ff6eff68ff61ff59ff51ff49ff71ff6c7fff66ff5fff58ff50ff48ff6fff6aff64ff5eff57ff4fff47ff6eff69ff63ff5d7fff55ff4eff46ff6cff67ff62ff5bff54ff4dff45ff6bff66ff60ff5aff54ff4d7fff44ff6aff65ff5fff59ff53ff4cff44ff68ff64ff5fff59ff52ff4bff43ff677fff63ff5eff58ff51ff4bff42ff66ff62ff5dff57ff51ff4aff41ff66ff61ff5c7fff56ff50ff49ff41ff65ff60ff5bff56ff4fff48ff40ff64ff5fff5bff55ff4f7fff48ff40ff63ff5fff5aff55ff4eff48ff3fff62ff5eff59ff54ff4eff47ff3f7fff62ff5dff59ff53ff4eff47ff3eff61ff5dff58ff53ff4dff46ff3eff05ff077fff0bff17ff22ff2bff31ff36ff3aff3dff43ff4aff4dff06ff07ff0cff17ff227fff2bff32ff36ff3bff3dff44ff4bff4eff06ff08ff0cff18ff23ff2cff32ff377fff3bff3eff44ff4bff4fff07ff08ff0dff18ff23ff2cff33ff38ff3cff3fff457fff4cff4fff07ff08ff0dff18ff23ff2cff33ff38ff3dff40ff46ff4dff50ff087fff09ff0eff19ff24ff2dff34ff39ff3eff40ff47ff4eff51ff09ff0aff0eff1a7fff25ff2eff35ff3aff3eff41ff48ff4fff52ff09ff0bff0fff1aff25ff2eff367fff3bff3fff42ff49ff50ff53ff0aff0bff0fff1bff26ff2fff36ff3cff40ff437fff4aff51ff54ff0bff0cff10ff1cff27ff30ff37ff3dff41ff44ff4bff52ff557fff0cff0dff11ff1dff27ff30ff38ff3eff42ff45ff4cff53ff57ff0cff0eff127fff1dff28ff31ff39ff3fff43ff46ff4dff54ff58ff0dff0eff13ff1eff28ff327fff3aff40ff45ff48ff4fff56ff59ff0eff10ff14ff1fff2aff33ff3bff42ff467fff4aff50ff57ff5bff10ff11ff15ff20ff2bff34ff3dff43ff48ff4bff52ff597fff5dff10ff12ff16ff21ff2bff36ff3eff44ff49ff4cff53ff5aff5eff12ff137fff18ff23ff2dff37ff40ff46ff4aff4eff55ff5cff60ff13ff14ff19ff24ff2e7fff38ff41ff48ff4cff50ff57ff5eff62ff15ff16ff1aff25ff2fff3aff43ff497fff4eff52ff59ff60ff64ff17ff18ff1cff27ff31ff3cff45ff4cff50ff54ff5c7fff63ff67ff19ff1aff1eff29ff33ff3eff47ff4eff53ff57ff5eff66ff6aff1b7fff1cff20ff2aff34ff3fff49ff50ff55ff59ff61ff69ff6dff1dff1eff23ff2c7fff37ff42ff4cff53ff58ff5cff65ff6cff70ff20ff21ff25ff2fff39ff45ff4f7fff56ff5cff60ff68ff70ff74ff23ff24ff28ff31ff3cff48ff52ff5aff5fff647fff6cff74ff79ff26ff27ff2bff34ff3eff4bff56ff5eff63ff68ff71ff7900e17fff29ff2aff2eff37ff42ff4fff5aff63ff67ff6bff7400e300ebff2dff2eff327fff3bff46ff53ff60ff67ff69ff6eff7900ef00f7ff31ff33ff37ff3fff4aff577fff65ff69ff68ff6b00e700fc0104ff36ff37ff3bff44ff4eff5dff6cff6bff6a7fff6e00f5010a0110ff3aff3cff40ff48ff53ff63ff72ff6eff70ff74010501187f011fff41ff42ff47ff4fff59ff6bff78ff72ff7500f601150128012fff48ff497fff4dff56ff60ff74ff7fff7900f2010901270139013fff4eff50ff56ff5eff697fff7fff87ff830106011c0139014b0152ff54ff55ff5eff67ff71ff8bff9100e27f01190130014d015e0165ff5cff5dff66ff75ff7fff9aff9f00f7012e014301617f0173017aff68ff69ff72ff8bff92ffb3009f010a01410157017501890190ff807fff81ff8fffc2ffd2fff700b5011c0153016a018a01a001a8ff8aff8bff9affe57f0010005400c7012d0166017e01a201bd01c7ff90ff91ffa3000d0035007c00d57f013a0172018c01c101f00202000000000000004c00c000d100e00146018401bc7f02a204b004b000a000a000b70105011500fc00f4015801b101f1039a04b004b07f0140014001400140014001400140016a01ca021903c404b004b001e001e001e07f01e001e001e001e001e001e0023f03ca04b004b00280028002800280028002807f028002800280028003da04b004b00320032003200320032003200320032003207f032003e104b004b003c003c003c003c003c003c003c003c003c003c003ec04b07f04b00460046004600460046004600460046004600460046004b004b0050005007f0500050005000500050005000500050005000500050005a005a005a005a005a07f05a005a005a005a005a005a005a005a0064006400640064006400640064006407f0640064006400640064006e006e006e006e006e006e006e006e006e006e006e07f06e006e0078007800780078007800780078007800780078007800780078008207f08200820082008200820082008200820082008200820082008c008c008c008c07f08c008c008c008c008c008c008c008c008c009600960096009600960096009607f0960096009600960096009600a000a000a000a000a000a000a000a000a000a007f0a000a000a000aa00aa00aa00aa00aa00aa00aa00aa00aa00aa00aa00aa00aa07f0b400b400b400b400b400b400b400b400b400b400b400b400b400be00be00be07f0be00be00be00be00be00be00be00be00be00be00c800c800c800c800c800c807f0c800c800c800c800c800c800c800d200d200d200d200d200d200d200d200d207f0d200d200d200d200dc00dc00dc00dc00dc00dc00dc00dc00dc00dc00dc00dc07f0dc00e600e600e600e600e600e600e600e600e600e600e600e600e600f000f007f0f000f000f000f000f000f000f000f000f000f000f000fa00fa00fa00fa00fa07f0fa00fa00fa00fa00fa00fa00fa00fa0104010401040104010401040104010407f1040104010401040104010e010e010e010e010e010e010e010e010e010e010e07f10e010e0118011801180118011801180118011801180118011801180118012207f12201220122012201220122012201220122012201220122012c012c012c012c07f12c012c012c012c012c012c012c012c012c013601360136013601360136013607f13601360136013601360136014001400140014001400140014001400140014007f14001400140014a014a014a014a014a014a014a014a014a014a014a014a014a07f154015401540154015401540154015401540154015401540154015e015e015e07f15e015e015e015e015e015e015e015e015e015e01680168016801680168016807f16801680168016801680168016801720172017201720172017201720172017207f172017201720172017c017c017c017c017c017c017c017c017c017c017c017c07f17c01860186018601860186018601860186018601860186018601860190019007f19001900190019001900190019001900190019001900190019001900190019007f19001900190019001900190019001900186018601860186018601860186018607f1860186018601860186017c017c017c017c017c017c017c017c017c017c017c07f17c017c0172017201720172017201720172017201720172017201720172016807f16801680168016801680168016801680168016801680168015e015e015e015e07f15e015e015e015e015e015e015e015e015e015401540154015401540154015407f15401540154015401540154014a014a014a014a014a014a014a014a014a014a07f14a014a014a014001400140014001400140014001400140014001400140014007f136013601360136013601360136013601360136013601360136012c012c012c07f12c012c012c012c012c012c012c012c012c012c01220122012201220122012207f12201220122012201220122012201180118011801180118011801180118011807f118011801180118010e010e010e010e010e010e010e010e010e010e010e010e07f10e010401040104010401040104010401040104010401040104010400fa00fa07f0fa00fa00fa00fa00fa00fa00fa00fa00fa00fa00fa00f000f000f000f000f007f0f000f000f000f000f000f000f000f000e600e600e600e600e600e600e600e607f0e600e600e600e600e600dc00dc00dc00dc00dc00dc00dc00dc00dc00dc00dc07f0dc00dc00d200d200d200d200d200d200d200d200d200d200d200d200d200c807f0c800c800c800c800c800c800c800c800c800c800c800c800be00be00be00be07f0be00be00be00be00be00be00be00be00be00b400b400b400b400b400b400b407f0b400b400b400b400b400b400aa00aa00aa00aa00aa00aa00aa00aa00aa00aa07f0aa00aa00aa00a000a000a000a000a000a000a000a000a000a000a000a000a007f096009600960096009600960096009600960096009600960096008c008c008c07f08c008c008c008c008c008c008c008c008c008c00820082008200820082008207f08200820082008200820082008200780078007800780078007800780078007807f078007800780078006e006e006e006e006e006e006e006e006e006e006e006e07f06e0064006400640064006400640064006400640064006400640064005a005a07f05a005a005a005a005a005a005a005a005a005a005a0050005000500050005007f0500050005000500050005000500050004b004b00460046004600460046004607f0460046004600460046004b004b003ec03c003c003c003c003c003c003c003c07f03c003c004b004b003e1032003200320032003200320032003200320032004b07f04b003da028002800280028002800280028002800280028004b004b003ca023f7f01e001e001e001e001e001e001e001e001e004b004b003c4021901ca016a01407f01400140014001400140014004b004b0039a01f101b1015800f400fc011501057f00b700a000a004b004b002a201bc0184014600e000d100c0004c0000000000007f020201f001c1018c0172013a00d5007c0035000dffa3ff91ff9001c701bd01a27f017e0166012d00c700540010ffe5ff9aff8bff8a01a801a0018a016a0153011c7f00b5fff7ffd2ffc2ff8fff81ff8001900189017501570141010a009fffb3ff927fff8bff72ff69ff68017a017301610143012e00f7ff9fff9aff7fff75ff66ff5d7fff5c0165015e014d0130011900e2ff91ff8bff71ff67ff5eff55ff540152014b7f0139011c0106ff83ff87ff7fff69ff5eff56ff50ff4e013f01390127010900f27fff79ff7fff74ff60ff56ff4dff49ff48012f0128011500f6ff75ff72ff78ff6b7fff59ff4fff47ff42ff41011f01180105ff74ff70ff6eff72ff63ff53ff48ff407fff3cff3a0110010a00f5ff6eff6aff6bff6cff5dff4eff44ff3bff37ff3601047f00fc00e7ff6bff68ff69ff65ff57ff4aff3fff37ff33ff3100f700efff79ff6e7fff69ff67ff60ff53ff46ff3bff32ff2eff2d00eb00e3ff74ff6bff67ff63ff5a7fff4fff42ff37ff2eff2aff2900e1ff79ff71ff68ff63ff5eff56ff4bff3eff347fff2bff27ff26ff79ff74ff6cff64ff5fff5aff52ff48ff3cff31ff28ff24ff237fff74ff70ff68ff60ff5cff56ff4fff45ff39ff2fff25ff21ff20ff70ff6cff657fff5cff58ff53ff4cff42ff37ff2cff23ff1eff1dff6dff69ff61ff59ff55ff507fff49ff3fff34ff2aff20ff1cff1bff6aff66ff5eff57ff53ff4eff47ff3eff337fff29ff1eff1aff19ff67ff63ff5cff54ff50ff4cff45ff3cff31ff27ff1cff187fff17ff64ff60ff59ff52ff4eff49ff43ff3aff2fff25ff1aff16ff15ff62ff5e7fff57ff50ff4cff48ff41ff38ff2eff24ff19ff14ff13ff60ff5cff55ff4eff4a7fff46ff40ff37ff2dff23ff18ff13ff12ff5eff5aff53ff4cff49ff44ff3eff367fff2bff21ff16ff12ff10ff5dff59ff52ff4bff48ff43ff3dff34ff2bff20ff157fff11ff10ff5bff57ff50ff4aff46ff42ff3bff33ff2aff1fff14ff10ff0eff597fff56ff4fff48ff45ff40ff3aff32ff28ff1eff13ff0eff0dff58ff54ff4dff467fff43ff3fff39ff31ff28ff1dff12ff0eff0cff57ff53ff4cff45ff42ff3eff387fff30ff27ff1dff11ff0dff0cff55ff52ff4bff44ff41ff3dff37ff30ff27ff1c7fff10ff0cff0bff54ff51ff4aff43ff40ff3cff36ff2fff26ff1bff0fff0bff0a7fff53ff50ff49ff42ff3fff3bff36ff2eff25ff1aff0fff0bff09ff52ff4fff487fff41ff3eff3aff35ff2eff25ff1aff0eff0aff09ff51ff4eff47ff40ff3eff397fff34ff2dff24ff19ff0eff09ff08ff50ff4dff46ff40ff3dff38ff33ff2cff237fff18ff0dff08ff07ff4fff4cff45ff3fff3cff38ff33ff2cff23ff18ff0dff087fff07ff4fff4bff44ff3eff3bff37ff32ff2cff23ff18ff0cff08ff06ff4eff4b7fff44ff3dff3bff36ff32ff2bff22ff17ff0cff07ff06ff4dff4aff43ff3dff3a7fff36ff31ff2bff22ff17ff0bff07ff05ff05ff06ff09ff11ff18ff1eff22ff257fff28ff29ff2dff31ff33ff06ff07ff0aff11ff18ff1eff23ff26ff28ff2aff2e7fff32ff34ff06ff07ff0aff12ff19ff1fff23ff26ff29ff2aff2eff32ff35ff077fff08ff0bff12ff19ff1fff24ff27ff29ff2bff2fff33ff35ff07ff08ff0bff127fff1aff20ff24ff28ff2aff2cff30ff34ff36ff08ff09ff0cff13ff1aff21ff257fff28ff2bff2dff31ff35ff37ff09ff0aff0dff14ff1bff21ff26ff29ff2cff2e7fff32ff36ff38ff09ff0aff0dff15ff1cff22ff27ff2aff2dff2eff32ff37ff397fff0aff0aff0dff15ff1cff23ff27ff2bff2eff2fff33ff38ff3aff0bff0bff0e7fff16ff1dff23ff28ff2cff2fff30ff35ff39ff3bff0cff0cff0fff17ff1eff247fff29ff2dff30ff32ff36ff3aff3cff0cff0dff10ff18ff1fff25ff2aff2eff317fff32ff37ff3bff3dff0dff0eff11ff18ff1fff26ff2bff2fff32ff34ff38ff3c7fff3fff0eff0fff12ff19ff21ff27ff2cff30ff34ff35ff3aff3eff40ff0fff107fff13ff1bff22ff28ff2dff32ff35ff37ff3bff40ff42ff10ff11ff14ff1bff237fff29ff2fff33ff36ff38ff3cff41ff43ff12ff13ff16ff1dff24ff2aff30ff357fff38ff3aff3eff42ff44ff13ff14ff17ff1eff25ff2cff32ff36ff39ff3bff407fff44ff46ff14ff15ff18ff1fff26ff2eff34ff38ff3bff3dff42ff46ff48ff177fff18ff1bff22ff28ff2fff36ff3aff3eff40ff44ff48ff4bff19ff19ff1cff247fff2aff31ff38ff3dff40ff42ff47ff4bff4dff1bff1bff1eff25ff2cff33ff3a7fff3fff42ff44ff49ff4dff50ff1dff1eff21ff27ff2eff36ff3dff42ff45ff487fff4cff51ff53ff20ff20ff23ff2aff30ff38ff40ff45ff49ff4bff50ff54ff567fff23ff24ff26ff2cff33ff3bff43ff49ff4cff4eff53ff57ff5aff25ff26ff297fff2fff36ff3fff47ff4cff4fff52ff57ff5cff5eff29ff29ff2cff32ff3aff437fff4bff50ff52ff55ff5aff5eff61ff2dff2eff31ff36ff3eff47ff50ff53ff507fff52ff58ff5dff61ff31ff32ff35ff3aff42ff4bff56ff56ff53ff55ff59ff5e7fff60ff36ff36ff39ff3fff46ff50ff5bff58ff54ff56ff5bff5fff62ff3aff3b7fff3eff43ff4bff57ff61ff5cff5dff5fff63ff67ff69ff41ff42ff45ff4bff527fff5fff67ff61ff62ff64ff680108010dff48ff48ff4bff51ff58ff67ff6cff687fff6bff6d010d0119011eff4eff4fff53ff59ff61ff71ff72ff71ff75ff7701207f012d0131ff54ff55ff5cff62ff69ff7cff7eff7e011101200134013f0144ff5c7fff5cff64ff6fff77ff8aff8d00f501260135014801540158ff68ff69ff70ff867fff8bff9c009b010801390148015c0168016cff80ff81ff8dffbdffcbffda00b27f011a014c015b0170017d0182ff8aff8bff99ffe00003004a00c60129015f016c7f01850194019aff90ff90ffa600070028007000d50139016b0180019801b901c07f000000000000003700ab00cc00e00145018301be021504b004b000a000a000eb7f00f2010c00f900f4015801ad01e2036e04b004b00140014001400157014001557f0140016b01c8020b03b604b004b001e001e001e001e001e001e001e001e001e07f023703be04b004b0028002800280028002800280028002800280028003d704b07f04b0032003200320032003200320032003200320032003de04b004b003c003c07f03c003c003c003c003c003c003c003c003ea04b004b0046004600460046004607f04600460046004600460046004b004b0050005000500050005000500050005007f0500050005000500050005a005a005a005a005a005a005a005a005a005a005a07f05a005a0064006400640064006400640064006400640064006400640064006e07f06e006e006e006e006e006e006e006e006e006e006e006e007800780078007807f07800780078007800780078007800780078008200820082008200820082008207f08200820082008200820082008c008c008c008c008c008c008c008c008c008c07f08c008c008c009600960096009600960096009600960096009600960096009607f0a000a000a000a000a000a000a000a000a000a000a000a000a000aa00aa00aa07f0aa00aa00aa00aa00aa00aa00aa00aa00aa00aa00b400b400b400b400b400b407f0b400b400b400b400b400b400b400be00be00be00be00be00be00be00be00be07f0be00be00be00be00c800c800c800c800c800c800c800c800c800c800c800c807f0c800d200d200d200d200d200d200d200d200d200d200d200d200d200dc00dc07f0dc00dc00dc00dc00dc00dc00dc00dc00dc00dc00dc00e600e600e600e600e607f0e600e600e600e600e600e600e600e600f000f000f000f000f000f000f000f007f0f000f000f000f000f000fa00fa00fa00fa00fa00fa00fa00fa00fa00fa00fa07f0fa00fa0104010401040104010401040104010401040104010401040104010e07f10e010e010e010e010e010e010e010e010e010e010e010e011801180118011807f11801180118011801180118011801180118012201220122012201220122012207f12201220122012201220122012c012c012c012c012c012c012c012c012c012c07f12c012c012c013601360136013601360136013601360136013601360136013607f140014001400140014001400140014001400140014001400140014a014a014a07f14a014a014a014a014a014a014a014a014a014a01540154015401540154015407f154015401540154015401540154015e015e015e015e015e015e015e015e015e07f15e015e015e015e01680168016801680168016801680168016801680168016807f1680172017201720172017201720172017201720172017201720172017c017c07f17c017c017c017c017c017c017c017c017c017c017c0186018601860186018607f18601860186018601860186018601860190019001900190019001900190019007f19001900190019001900190019001900190019001900190019001900190019007f19001900186018601860186018601860186018601860186018601860186017c07f17c017c017c017c017c017c017c017c017c017c017c017c017201720172017207f17201720172017201720172017201720172016801680168016801680168016807f16801680168016801680168015e015e015e015e015e015e015e015e015e015e07f15e015e015e015401540154015401540154015401540154015401540154015407f14a014a014a014a014a014a014a014a014a014a014a014a014a01400140014007f14001400140014001400140014001400140014001360136013601360136013607f136013601360136013601360136012c012c012c012c012c012c012c012c012c07f12c012c012c012c01220122012201220122012201220122012201220122012207f1220118011801180118011801180118011801180118011801180118010e010e07f10e010e010e010e010e010e010e010e010e010e010e0104010401040104010407f104010401040104010401040104010400fa00fa00fa00fa00fa00fa00fa00fa07f0fa00fa00fa00fa00fa00f000f000f000f000f000f000f000f000f000f000f007f0f000f000e600e600e600e600e600e600e600e600e600e600e600e600e600dc07f0dc00dc00dc00dc00dc00dc00dc00dc00dc00dc00dc00dc00d200d200d200d207f0d200d200d200d200d200d200d200d200d200c800c800c800c800c800c800c807f0c800c800c800c800c800c800be00be00be00be00be00be00be00be00be00be07f0be00be00be00b400b400b400b400b400b400b400b400b400b400b400b400b407f0aa00aa00aa00aa00aa00aa00aa00aa00aa00aa00aa00aa00aa00a000a000a007f0a000a000a000a000a000a000a000a000a000a000960096009600960096009607f096009600960096009600960096008c008c008c008c008c008c008c008c008c07f08c008c008c008c00820082008200820082008200820082008200820082008207f0820078007800780078007800780078007800780078007800780078006e006e07f06e006e006e006e006e006e006e006e006e006e006e0064006400640064006407f0640064006400640064006400640064005a005a005a005a005a005a005a005a07f05a005a005a005a005a0050005000500050005000500050005000500050005007f0500050004b004b00460046004600460046004600460046004600460046004b07f04b003ea03c003c003c003c003c003c003c003c003c003c004b004b003de03207f03200320032003200320032003200320032004b004b003d702800280028002807f02800280028002800280028004b004b003be023701e001e001e001e001e001e07f01e001e001e004b004b003b6020b01c8016b01400155014001570140014001407f04b004b0036e01e201ad015800f400f9010c00f200eb00a000a004b004b002157f01be0183014500e000cc00ab003700000000000001c001b901980180016b01397f00d5007000280007ffa6ff90ff90019a01940185016c015f012900c6004a00037fffe0ff99ff8bff8a0182017d0170015b014c011a00b2ffdaffcbffbdff8dff817fff80016c0168015c014801390108009bff9cff8bff86ff70ff69ff68015801547f01480135012600f5ff8dff8aff77ff6fff64ff5cff5c0144013f0134012001117fff7eff7eff7cff69ff62ff5cff55ff540131012d0120ff77ff75ff71ff72ff717fff61ff59ff53ff4fff4e011e0119010dff6dff6bff68ff6cff67ff58ff51ff4b7fff48ff48010d0108ff68ff64ff62ff61ff67ff5fff52ff4bff45ff42ff41ff697fff67ff63ff5fff5dff5cff61ff57ff4bff43ff3eff3bff3aff62ff5fff5bff567fff54ff58ff5bff50ff46ff3fff39ff36ff36ff60ff5eff59ff55ff53ff56ff567fff4bff42ff3aff35ff32ff31ff61ff5dff58ff52ff50ff53ff50ff47ff3eff367fff31ff2eff2dff61ff5eff5aff55ff52ff50ff4bff43ff3aff32ff2cff29ff297fff5eff5cff57ff52ff4fff4cff47ff3fff36ff2fff29ff26ff25ff5aff57ff537fff4eff4cff49ff43ff3bff33ff2cff26ff24ff23ff56ff54ff50ff4bff49ff457fff40ff38ff30ff2aff23ff20ff20ff53ff51ff4cff48ff45ff42ff3dff36ff2e7fff27ff21ff1eff1dff50ff4dff49ff44ff42ff3fff3aff33ff2cff25ff1eff1b7fff1bff4dff4bff47ff42ff40ff3dff38ff31ff2aff24ff1cff19ff19ff4bff487fff44ff40ff3eff3aff36ff2fff28ff22ff1bff18ff17ff48ff46ff42ff3dff3b7fff38ff34ff2eff26ff1fff18ff15ff14ff46ff44ff40ff3bff39ff36ff32ff2c7fff25ff1eff17ff14ff13ff44ff42ff3eff3aff38ff35ff30ff2aff24ff1dff167fff13ff12ff43ff41ff3cff38ff36ff33ff2fff29ff23ff1bff14ff11ff10ff427fff40ff3bff37ff35ff32ff2dff28ff22ff1bff13ff10ff0fff40ff3eff3aff357fff34ff30ff2cff27ff21ff19ff12ff0fff0eff3fff3cff38ff34ff32ff2fff2b7fff26ff1fff18ff11ff0eff0dff3dff3bff37ff32ff31ff2eff2aff25ff1fff187fff10ff0dff0cff3cff3aff36ff32ff30ff2dff29ff24ff1eff17ff0fff0cff0c7fff3bff39ff35ff30ff2fff2cff28ff23ff1dff16ff0eff0bff0bff3aff38ff337fff2fff2eff2bff27ff23ff1cff15ff0dff0aff0aff39ff37ff32ff2eff2dff2a7fff27ff22ff1cff15ff0dff0aff09ff38ff36ff32ff2eff2cff29ff26ff21ff1b7fff14ff0dff0aff09ff37ff35ff31ff2dff2bff28ff25ff21ff1aff13ff0cff097fff08ff36ff34ff30ff2cff2aff28ff24ff20ff1aff12ff0bff08ff07ff35ff337fff2fff2bff29ff27ff24ff1fff19ff12ff0bff08ff07ff35ff32ff2eff2aff297fff26ff23ff1fff19ff12ff0aff07ff06ff34ff32ff2eff2aff28ff26ff23ff1e7fff18ff11ff0aff07ff06ff33ff31ff2dff29ff28ff25ff22ff1eff18ff11ff097fff06ff0500000000000000000000000000000000000000000000000000000000"; function getName() external pure override returns(string memory) { unchecked {return "TaylorLatticeProbe";} } 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)<10*U)return 0;return divi(exp(-mul(x,x)/2),2506628274631000200);} } function knot(uint256 j) internal pure returns(int256){ unchecked { bool neg=j<6;if(neg)j=12-j; int256 k=j==6?int256(0):j==7?int256(20):j==8?int256(40):j==9?int256(60):j==10?int256(125):j==11?int256(300):int256(800); return (neg?-k:k)*U; } } struct Position {bytes data;uint256 n;uint256 i;uint256 j;int256 f;int256 g;uint256 base;} function lookup(bytes memory data,uint256 index) internal pure returns(int256){ unchecked { uint256 p=index*2+1+index/16; uint256 x=(uint256(uint8(data[p]))<<8)|uint8(data[p+1]); return int256(int16(uint16(x)))*U/8; } } function blend(Position memory q,uint256 base) internal pure returns(int256){ unchecked { int256 l=mul(lookup(q.data,base+q.i*q.n+q.j),U-q.f)+mul(lookup(q.data,base+(q.i+1)*q.n+q.j),q.f); int256 h=mul(lookup(q.data,base+q.i*q.n+q.j+1),U-q.f)+mul(lookup(q.data,base+(q.i+1)*q.n+q.j+1),q.f); return mul(l,U-q.g)+mul(h,q.g); } } function fees(int256 w,int256 r,uint256 ph) internal pure returns(int256 fb,int256 fa){ unchecked { Position memory q;q.data=TABLE; int256 p=clip((w+800*U)/20,0,80*U);q.i=uint256(p/U);if(q.i>79)q.i=79; q.f=p-int256(q.i)*U; if(ph==0){r=clip(r,-30*U,30*U);p=(r+30*U)/10;q.j=uint256(p/U);if(q.j>5)q.j=5;q.g=p-int256(q.j)*U;q.n=7;} else{r=clip(r,-800*U,800*U);while(q.j<11&&r>=knot(q.j+1))q.j++;q.g=divi(r-knot(q.j),knot(q.j+1)-knot(q.j));q.n=13;q.base=1134+(ph-1)*2106;} int256 a=blend(q,q.base);int256 b=blend(q,q.base+81*q.n); fb=b> -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); } } // ---- lattice (latt.py): 121 cells of 2.5 bps, kernel +-16 cells, silent-step cap 30 int256 constant HC=250000000000000; uint256 constant NC=121; int256 constant N0=60; uint256 constant KM=16; uint256 constant CAP=30; uint256 constant CW=6; uint256 constant B0=10; uint256 constant MK=(1<<42)-1; struct Belief { int256 m; int256 v; int256 fb; int256 fa; int256 sp; int256 r; uint256 t; uint256 cnt; } struct Lat { int256[] P; int256[] Q; int256 c; uint256 lo; uint256 hi; } function kern() internal pure returns(int256[] memory k){ unchecked { k=new int256[](2*KM+1); k[0]=13579267349454;k[1]=40178829530513;k[2]=110846841719911;k[3]=285137584831271;k[4]=683897018469628;k[5]=1529438627520569;k[6]=3189176088379630;k[7]=6200547579537577;k[8]=11240527438039824;k[9]=18999774050356352;k[10]=29944377071762656;k[11]=44003500901339808;k[12]=60292636860258312;k[13]=77027610575445280;k[14]=91755831423616320;k[15]=101912164136388608;k[16]=105541551410908560;k[17]=101912164136388608;k[18]=91755831423616320;k[19]=77027610575445280;k[20]=60292636860258312;k[21]=44003500901339808;k[22]=29944377071762656;k[23]=18999774050356352;k[24]=11240527438039824;k[25]=6200547579537577;k[26]=3189176088379630;k[27]=1529438627520569;k[28]=683897018469628;k[29]=285137584831271;k[30]=110846841719911;k[31]=40178829530513;k[32]=13579267349454; } } function fl(int256 x) internal pure returns(int256){ unchecked { return x>=0?x/U:-((-x+U-1)/U); } } function loadL() internal view returns(Lat memory L){ unchecked { L.P=new int256[](NC); L.Q=new int256[](NC); L.c=int256(slots[8]); uint256 w=slots[9]; L.lo=w&255; L.hi=(w>>8)&255; uint256 cur=type(uint256).max; uint256 word; for(uint256 i=L.lo;i<=L.hi;i++){ uint256 s=i/CW; if(s!=cur){cur=s;word=slots[B0+s];} L.P[i]=int256((((word>>(42*(i%CW)))&MK)*1e18+(1<<40))>>41); } } } function saveL(Lat memory L) internal { unchecked { slots[8]=uint256(L.c); slots[9]=L.lo|(L.hi<<8); for(uint256 s=L.lo/CW;s<=L.hi/CW;s++){ uint256 word=1<<255; for(uint256 k=0;k=L.lo&&i<=L.hi){ int256 p=L.P[i]; if(p>0)word|=((uint256(p)<<41)+5e17)/1e18<<(42*k); } } slots[B0+s]=word; } } } function swapClear(Lat memory L,int256[] memory O) internal pure { unchecked { for(uint256 i=L.lo;i<=L.hi;i++)L.P[i]=0; L.Q=L.P; L.P=O; } } function diffuse(Lat memory L,int256[] memory K) internal pure { unchecked { uint256 lo=L.lo>KM?L.lo-KM:0; uint256 hi=L.hi+KM; if(hi>NC-1)hi=NC-1; int256[] memory O=L.Q; for(uint256 i=L.lo;i<=L.hi;i++){ int256 p=L.P[i]; if(p<=1000)continue; uint256 k0=iNC-1?NC-1+KM-i:2*KM; for(uint256 k=k0;k<=k1;k++)O[i+k-KM]+=p*K[k]; } for(uint256 j=lo;j<=hi;j++)O[j]/=U; swapClear(L,O); L.lo=lo; L.hi=hi; } } function cut(Lat memory L,int256 lo,int256 hi) internal pure returns(int256 tot){ unchecked { for(uint256 i=L.lo;i<=L.hi;i++){ int256 p=L.P[i]; if(p==0)continue; int256 x0=L.c+(int256(i)-N0)*HC-HC/2; int256 x1=x0+HC; int256 a=lo>x0?lo:x0; int256 b=hi0){ p=p*U/tot; if(p<1e6)L.P[i]=0; else {L.P[i]=p; if(lo==type(uint256).max)lo=i; hi=i;} } } if(lo==type(uint256).max)return false; L.lo=lo; L.hi=hi; return true; } } function dens(Lat memory L,int256 x) internal pure returns(int256){ unchecked { int256 pos=divi(x-L.c,HC)+N0*U; int256 i=fl(pos); int256 f=pos-i*U; if(i<0||i>=int256(NC)-1)return 0; return divi(mul(L.P[uint256(i)],U-f)+mul(L.P[uint256(i)+1],f),HC); } } function moments(Lat memory L) internal pure returns(int256,int256){ unchecked { int256 tot; int256 s; for(uint256 i=L.lo;i<=L.hi;i++){ int256 p=L.P[i]; s+=p*(int256(i)-N0); tot+=p; } if(tot<=0)return (L.c,0); int256 mc=s*U/tot; int256 vv; for(uint256 i=L.lo;i<=L.hi;i++){ int256 d=(int256(i)-N0)*U-mc; vv+=L.P[i]*d/U*d; } vv=vv/tot; return (L.c+mc*HC/U, vv*HC/U*HC/U); } } function recentre(Lat memory L,int256 cnew) internal pure { unchecked { int256 sh=divi(cnew-L.c,HC); int256[] memory O=L.Q; int256 n=int256(NC); for(uint256 i=L.lo;i<=L.hi;i++){ int256 p=L.P[i]; if(p==0)continue; int256 pos=int256(i)*U-sh; int256 j=fl(pos); int256 f=pos-j*U; if(j>=0&&j=0&&j+1n-1)lo=n-1; if(hi>n-1)hi=n-1; if(hi<0)hi=0; swapClear(L,O); L.c=cnew; L.lo=uint256(lo); L.hi=uint256(hi); } } function pin(Lat memory L,int256 x) internal pure { unchecked { for(uint256 i=L.lo;i<=L.hi;i++)L.P[i]=0; L.c=x; L.P[uint256(N0)]=U; L.lo=uint256(N0); L.hi=uint256(N0); } } function deposit(Lat memory L,int256 x,int256 w) internal pure { unchecked { int256 pos=divi(x-L.c,HC)+N0*U; int256 i=fl(pos); int256 f=pos-i*U; int256 n=int256(NC); if(i>=0&&iL.hi)L.hi=uint256(i); } if(i+1>=0&&i+1L.hi)L.hi=uint256(i+1); } } } function save(Belief memory b) internal { unchecked { slots[0]=uint256(b.m);slots[1]=uint256(b.v);slots[2]=uint256(b.fb);slots[3]=uint256(b.fa); slots[4]=uint256(b.sp);slots[5]=uint256(b.r);slots[6]=b.t;slots[7]=b.cnt; } } function afterInitialize(uint256 x,uint256 y) external override returns(uint256,uint256){ unchecked { Belief memory b; b.sp=int256(y*1e18/x);b.r=b.sp;b.m=ln(b.sp); b.fb=2821013442392051;b.fa=2821013442392051;save(b); slots[8]=uint256(b.m); slots[9]=uint256(N0)|(uint256(N0)<<8); slots[B0+uint256(N0)/CW]=(1<<255)|(uint256(1<<41)<<(42*(uint256(N0)%CW))); return(uint256(b.fb),uint256(b.fa)); } } struct Work {int256 lo;int256 hi;int256 lp;int256 la;int256 Z;int256 d;int256 pi;bool ok;} function update(Belief memory b,int256 s,bool buy,uint256 dt) internal returns(bool arb){ unchecked { Work memory q; Lat memory L=loadL(); int256[] memory K=kern(); q.lo=ln(mul(b.sp,U-b.fb));q.hi=ln(divi(b.sp,U-b.fa)); q.ok=true; uint256 n=dt-1;if(n>CAP)n=CAP; for(uint256 i=0;i0?divi(q.la,q.la+lr):U; if(q.pi>=999e15||q.Z<=0)pin(L,q.lp); else if(q.pi<=1e15)norm(L,q.Z); else { norm(L,q.Z); for(uint256 i=L.lo;i<=L.hi;i++)L.P[i]=mul(L.P[i],U-q.pi); if(q.pi>U/2)recentre(L,q.lp); deposit(L,q.lp,q.pi); } } arb=q.pi>U/2; (b.m,b.v)=moments(L); if(ab(b.m-L.c)>40*HC){ recentre(L,b.m); (b.m,b.v)=moments(L); } saveL(L); int256 pe=exp(b.m);b.r=clip(b.r,mul(pe,997e15),divi(pe,997e15));b.cnt=0; } } function afterSwap(TradeInfo calldata t) external override returns(uint256,uint256){ unchecked { Belief memory b=Belief(int256(slots[0]),int256(slots[1]),int256(slots[2]),int256(slots[3]),int256(slots[4]),int256(slots[5]),slots[6],slots[7]); int256 s=int256(t.reserveY*1e18/t.reserveX);bool arb; if(t.timestamp>b.t)arb=update(b,s,t.isBuy,t.timestamp-b.t); uint256 ph; if(!arb){ int256 c=t.isBuy?divi(mul(s,U-b.fb),997e15):divi(mul(s,997e15),U-b.fa); if(t.isBuy?cb.r)b.r=c; b.cnt++;ph=b.cnt==1?1:2; } int256 w=(ln(s)-b.m)*10000;int256 r=(ln(b.r)-b.m)*10000; (b.fb,b.fa)=fees(w,r,ph);b.sp=s;b.t=t.timestamp;save(b); return(uint256(b.fb),uint256(b.fa)); } } } ```