# Commit Independent repeat, item ref-2. Taylor / gtmcknight's `amm-sim` was cloned into `test/scratch/amm-sim` and checked out at **4812a6382311624e1506aca131ca35c378f930d9**, before running any reference checks. No upstream file was edited; no dependencies were installed. All replica executions used plain `python3 -I`. This item reproduces the reference only; it does not implement or score a Solidity strategy. Sources below are pinned to that commit: [README][readme], [gates.py][gates], [real.py][real], [evalpol.py][eval], [pol_mid.json][pol], [replica2.py][replica]. Line numbers below refer to these exact files. Numerical reproduction and exhaustive table checks are observations from this repeat, with their commands recorded below; the upstream files define the inputs. The table file's SHA-256 measured locally is `efbb5ee102db4d312f64565d9bf7232b6becbe02b624164f744a402bbbf2983b`. # Gates Ran `python3 -I gates.py` from `research/solved`, before any changes. Exact stdout (all printed values): ```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 ``` Exit status 0. All 12 values match the README Gates block exactly at its six printed decimals. `gates.py:10–18` loads the full plain and qm tables and evaluates the four policies; Gaussian plain uses `{'soft': 1.0}`. This is the unmodified reference gate, not a gate on compressed tables. # Score Command, from the pinned checkout's `research/solved` directory: ```sh python3 -I real.py pol_mid.json plain:soft=1 ``` Exact stdout: ```text plain:soft=1 edge 532.386 retail 564.827 arb -32.441 rv 77686 av 24942 vs HA +2.828 se 0.041 misclass 16.57% p rms 14.7 bps (68s) ``` Exit status 0. **n=2,048**, seeds **10000..12047 inclusive**, mean absolute edge **532.386**, mean paired edge difference vs stored HA **+2.828**, paired standard error **0.041** (all score figures at the harness's printed precision). This reproduces the README's +2.828. The README table rounds the absolute mean to 532.39 and SE to 0.04, also consistent. The seed range and default n are defined in `real.py:202–207`; each seed runs 10,000 simulation steps (`replica2.py:20`). Pairing uses the stored `HA` rows of `calib_out_2048.json`, not a fresh HA run (`real.py:190–198,206–207`). The standard error uses sample variance with divisor n−1, divided by sqrt(n) (`evalpol.py:82–85`). This is a replica edge comparison, not a Rust engine or t03 comparison. # Timing The unmodified harness printed **68 seconds** for the full score (`real.py:190–198` measures elapsed wall time around the pool evaluation and reporting). Therefore aggregate wall time per seed is approximately **68/2048 = 0.033203125 s/seed**, or **0.0332 s/seed**. Its time display rounds to whole seconds, so this derived timing is approximate; it is not a measured serial per-seed latency or CPU time. The stock harness uses 14 worker processes and batches of eight seeds (`real.py:192,208`). No timing setup or dependency installation was needed. # Tables The following are exhaustive local measurements of [pol_mid.json][pol], not estimates. `evalpol.py:22–25` selects exactly these six policy arrays, and `real.py:69–70` delegates to them when no `qm` option is supplied. | Table | Meaning / phase | Shape (w × R) | Values | Minimum (bps) | Maximum (bps) | |---|---|---:|---:|---:|---:| | A0 | ask, inferred arb / phase 0 | 321 × 13 | 4,173 | -24.262 | 800 | | B0 | bid, inferred arb / phase 0 | 321 × 13 | 4,173 | -24.262 | 800 | | A1 | ask, first own inferred retail / phase 1 | 321 × 49 | 15,729 | -31.323 | 800 | | B1 | bid, first own inferred retail / phase 1 | 321 × 49 | 15,729 | -31.323 | 800 | | A2 | ask, subsequent own inferred retail / phase 2 | 321 × 49 | 15,729 | -31.333 | 800 | | B2 | bid, subsequent own inferred retail / phase 2 | 321 × 49 | 15,729 | -31.333 | 800 | Total **71,262 policy values**, range **[-31.333, 800] bps**. A and B are log quote offsets from estimated fair price: `a=10^4 ln(ask/p_est)`, `b=10^4 ln(p_est/bid)`. They are not directly fee bps; negative offsets are valid. Fee conversion is below. These meanings agree with the README model and tables sections and `evalpol.py:57–58`. Axes and metadata from the file: - `H_bps=5`, `W0=160`, `NW=321`: row i has `w=(i-160)*5`, from -800 to +800 bps in uniform 5 bps steps. - Phase 0: `FB=6`; column j has `R=(j-6)*5`, from -30 to +30 bps in 5 bps steps. - Phases 1 and 2: `N2=49`, `C2=24`; column j has `R=W2L[j]*5`. The full R axis in bps is: ```text [-800,-650,-500,-400,-300,-250,-200,-150,-125,-100,-85,-70, -60,-55,-50,-45,-40,-35,-30,-25,-20,-15,-10,-5,0, 5,10,15,20,25,30,35,40,45,50,55,60,70,85,100,125,150, 200,250,300,400,500,650,800] ``` Adjacent R steps are nonuniform: 5, 10, 15, 25, 50, 100 or 150 bps. `W2L` is in lattice units, not bps. Plain tables have **no sd axis and no synced/clipped subtable axis**. Phase is discrete; no interpolation between phases. Solver metadata: `lam=0.8`, `sigma=9.45`, `size=20.0`, `g=0.05368206098114493`. These are file metadata, not per-run filter adaptations. The JSON additionally has `VD0` (321 × 13) and `VD1` (321 × 49), 19,902 saved solver value entries. They are not quote offsets and are not read by the plain lookup. Thus 71,262 refers to the six policy tables, not every number in the JSON. With those two arrays included there are 91,164 two-dimensional array entries, before axis and scalar metadata. # Symmetry For every index of every phase, measured `abs(Aph[i][j] - Bph[320-i][ncol-1-j])`. Both axes are exactly sign-symmetric, including the nonuniform `W2L`. Also checked the reverse B-to-A direction for every entry. | Phase | Ask→reflected bid comparisons | Max absolute difference (bps) | Within 0.5 bps | |---|---:|---:|---:| | 0 | 4,173 | 0 | 4,173 / 4,173 = 100% | | 1 | 15,729 | 0 | 15,729 / 15,729 = 100% | | 2 | 15,729 | 0 | 15,729 / 15,729 = 100% | Reverse comparisons have the same counts and results. Across all six arrays: **71,262 / 71,262 = 100%**, maximum **0 bps**, using the stored JSON numbers parsed as Python floats (no rounding or resampling). Therefore `A(w,R,phase)=B(-w,-R,phase)` exactly at every stored grid point. Reproducible table/range/symmetry check, run from `research/solved` as a `python3 -I` stdin script: ```python import json T = json.load(open('pol_mid.json')) assert T['W2L'] == [-x for x in T['W2L'][::-1]] count = 0 for ph in range(3): for side, other in [('A','B'), ('B','A')]: a, b = T[side+str(ph)], T[other+str(ph)] vals = [x for row in a for x in row] ds = [abs(x-b[len(a)-1-i][len(row)-1-j]) for i,row in enumerate(a) for j,x in enumerate(row)] print(side+str(ph), len(a), len(a[0]), len(vals), min(vals), max(vals), max(ds), sum(d <= 0.5 for d in ds)/len(ds)) count += len(vals) print(count) ``` # Lookup This specifies **plain:soft=1**, not qm. Relevant code: `real.py:49–99,100–177` and `evalpol.py:20–59`. The filter and phase/rival updates in the next section precede this lookup. ```text s = reserveY / reserveX w = (ln(s) - m) * 10000 R = (ln(s2h) - m) * 10000 sd = sqrt(v) * 10000 lookup(w,R,phase,sd): # Q is None: real.py:69–70 immediately returns _fees. # sd and synced have no effect on this plain lookup. A,B = (A0,B0) if phase==0 else (A1,B1) if phase==1 else (A2,B2) pw = clamp(w/5 + 160, 0, 320) l2 = R/5 if phase == 0: p2 = clamp(l2, -6, 6) + 6 n2 = 13 else: n2 = 49 if l2 <= W2L[0]: p2 = 0 elif l2 >= W2L[48]: p2 = 48 else: # Binary search, W2L[lo] <= l2 < W2L[hi], hi=lo+1 p2 = lo + (l2-W2L[lo])/(W2L[hi]-W2L[lo]) i = min(int(pw),319) j = min(int(p2),n2-2) f = pw-i g = p2-j BL(T) = (T[i][j]*(1-f)+T[i+1][j]*f)*(1-g) + (T[i][j+1]*(1-f)+T[i+1][j+1]*f)*g a = BL(A) b = BL(B) fa = 1-exp(-(a-w)*0.0001) if a>w else 0 fb = 1-exp(-(b+w)*0.0001) if b>-w else 0 return (fb,fa) ``` Bilinear interpolation is used, not nearest-neighbor. At the last row/column the lower index is backed off by one, leaving fraction 1; this prevents an out-of-bounds neighbor. Clamp **lookup coordinates**, but retain the original, unclamped `w` for the fee conversion. Do not clamp offsets themselves or substitute `(a-w)/10000` for the exponential fee formula. `soft=1` is filter-mixture processing, not smoothing or interpolating the policy tables. There is no extra plain-table post-processing. `real.py:173–177` stores `tlast=t`, `sp=s`, then computes the lookup and stores `fb,fa=clampf(raw_fb),clampf(raw_fa)`. `replica2.py:12–17` clamps to [0,0.1]. The callback returns the raw pair; the replica also clamps the returned pair before using it (`replica2.py`, callback sites). A Solidity port must preserve the effective clamped fees and the clamped fees in its persistent filter state. `RealPolicy.init` (`real.py:63–66`) calls the plain `_fees(0,0,0)`, stores the clamped pair, and returns the raw pair. It does not initially call the qm lookup, even in qm variants. For contrast only: when a qm file is supplied, `real.py:71–98` selects sd levels, linearly blends between their bilinear lookups, uses `0c` at phase 0 and `1s/1c/2s/2c` according to phase and synced. None of that path runs for this scored plain policy. # Filter All logarithms are natural. Internally m and sd use log-price units; multiply by 10,000 only at the table interface. Source: [real.py][real], with exact line spans below. **Persistent state and constants** (`real.py:19–29,51–66`): m = ln(100), v = 0, tlast = 0, cnt = 0, s2h = 100, sp = 100, synced = false, fb = fa = 0.003 before init overwrites the fees. Price estimate is exp(m). `SIG2=(0.000945)^2`, `RHO=0.26`, `LD_M=ln(11.12e-4)`, `LD_S=1.176`, `G2=1-NF=0.997`. Own amounts ax, ay are accepted but unused. The inherited table metadata is also retained. Diagnostic counters do not affect policy decisions. Define `phi(z)=exp(-z*z/2)/2.5066282746310002` and `Phi(z)=0.5*(1+erf(z/1.4142135623730951))` (`real.py:28–29`). The truncated normal helper `trunc(m,v,lo,hi)` returns mass Z, conditional mean mt and conditional variance vt, exactly as follows (`real.py:32–46`): ```text if v <= 0: return (1 if lo<=m<=hi else 0), m, 0 sd = sqrt(v) a = (lo-m)/sd; b = (hi-m)/sd Z = Phi(b)-Phi(a) if Z < 1e-12: return Z, (lo if m=1`, reset cnt=0. Compute the fixed no-arb interval of the **previous quotes**: `lo=ln(sp*(1-fb))`, `hi=ln(sp/(1-fa))`. Copy local m,v from persistent state. For `min(dt-1,12)` silent steps, first `v+=SIG2`, then replace m,v with the conditional mean and variance from `trunc(m,v,lo,hi)`, discarding the mass. Bounds stay the same throughout the loop. Then add `SIG2` once more for the current step, with no truncation yet (`real.py:104–111`). Thus long gaps use at most 12 silent updates plus this one current-step variance increment; no extra growth is added for skipped silent steps. 3. Arb reading: `lp=ln(s*(1-fb))` for `is_buy`, otherwise `lp=ln(s/(1-fa))`. Here `is_buy` is the replica callback's side; do not reverse it based on the trader-facing English meaning. Set `sd=sqrt(v)`, `Larb=phi((lp-m)/sd)/sd`. Compute `Z,mt,vt=trunc(m,v,lo,hi)`. Let `d=max(abs(ln(s/sp)),1e-9)`. For this variant `Lret=Z*0.26*phi((ln(d)-ln(11.12e-4))/1.176)/(d*1.176)`. Set `pi=Larb/(Larb+Lret)` if the denominator is positive, else 0 (`real.py:113–140`, default branch at 138–139). No tail mixture, fill-law alternative, or oracle flag override is enabled. 4. Set local `is_arb=(pi>0.5)`; equality is classified retail. With `soft=1`, if `0.0050000000000000044 < pi < 0.995` (the literal lower expression is `1.0-0.995` in Python floating arithmetic), set `mnew=pi*lp+(1-pi)*mt`, `vnew=pi*(lp-mnew)^2+(1-pi)*(vt+(mt-mnew)^2)`. Otherwise use `(lp,0)` if is_arb, or `(mt,vt)` if not. Store new m,v. The strict inequalities matter at the thresholds. The soft mixture does **not** change the hard `pi>0.5` phase decision (`real.py:140–152`). 5. Still inside the new-step branch, clip s2h to `[exp(m)*0.997, exp(m)/0.997]` using the **updated** m, then set synced=false (`real.py:153–157`). This band uses exact multiplicative 30 bps fees, rather than a ±30 log-bps approximation. 6. For every callback classified retail (including every same-step callback), update rival from post-trade s using the **old fees in force**: on is_buy, `cand=s*(1-fb)/0.997`, replacing s2h only if cands2h. Set synced=true on replacement. It stays as it was when no replacement occurs. Increment cnt. Phase is 1 if cnt<=1, else 2. On inferred arb, phase=0 and no retail increment occurs (`real.py:159–169`). No additional band reclip follows this candidate update. 7. Store tlast, sp; derive w, R, sd from the updated state, perform the lookup above, and store the clamped new fees (`real.py:173–177`). The true arb flag and true price appear in `on_trade` arguments solely for optional diagnostics in this variant. `arb` feeds misclassification counters; p feeds squared-error counters (`real.py:143–144,170–172`). Neither diagnostic modifies m, v, fees, phase or rival estimate. The true rival s2 and true retail index j are unused. No drift term or run-specific sigma/rate adaptation is applied by this Gaussian filter, even though the replica generates a drifted price process and random per-seed parameters (`replica2.py:20–28`). # Deviations No numerical reproduction failures: all gate values match, and the 2,048-seed plain score matches the README at its reported precision. No command names differed from the README. The README shows a combined plain-and-qm score command; this item's score invocation intentionally selected only `plain:soft=1`, as requested. `gates.py` still checked all four reference policies. Both executions were bounded with `timeout 470` (under eight minutes) and stdout/stderr redirected to scratch logs; both exited 0 without timeout. The commands actually launched were `timeout 470 python3 -I gates.py` and `timeout 470 python3 -I real.py pol_mid.json plain:soft=1`, from `research/solved`. No upstream script or table was changed. The Linux engine/Solidity setup was not run because this item is exclusively REPLICA reproduction; no engine seeds were consumed. Working files and the clone are under `test/scratch/`; only the two requested deliverables are outputs. Two details in README prose must not override the implementation: plain lookup has no sd/synced table selection, and the filter's no-arb interval is mathematically open in the docstring but inclusive in the zero-variance helper branch. Both are specified from source above. No compressed table or contract claims are made by this repeat. [readme]: https://github.com/gtmcknight/amm-sim/blob/4812a6382311624e1506aca131ca35c378f930d9/research/solved/README.md [gates]: https://github.com/gtmcknight/amm-sim/blob/4812a6382311624e1506aca131ca35c378f930d9/research/solved/gates.py [real]: https://github.com/gtmcknight/amm-sim/blob/4812a6382311624e1506aca131ca35c378f930d9/research/solved/real.py [eval]: https://github.com/gtmcknight/amm-sim/blob/4812a6382311624e1506aca131ca35c378f930d9/research/solved/evalpol.py [pol]: https://github.com/gtmcknight/amm-sim/blob/4812a6382311624e1506aca131ca35c378f930d9/research/solved/pol_mid.json [replica]: https://github.com/gtmcknight/amm-sim/blob/4812a6382311624e1506aca131ca35c378f930d9/research/solved/replica2.py