norms.py

48.0 kB · python · 1102 lines

1import itertools2import math3import sys4import time5from fractions import Fraction67import numpy as np8from mpmath import iv, mp, mpf, mpc, quad, expjpi, cos as mpcos, log as mplog910# DESIGNS1112def cube_minus(q, D, drop):13    return (q, D, [v for v in itertools.product(range(q), repeat=D) if v != drop])1415def base_missing(b, a0):16    return (b, 1, [(a,) for a in range(b) if a != a0])1718GASKET = cube_minus(2, 2, (1, 1))19CARPET = cube_minus(3, 2, (1, 1))20GASKET4 = base_missing(4, 3)21CARPET9 = base_missing(9, 4)2223ROSTER = [24    ("gasket 2D", GASKET),25    ("carpet 2D", CARPET),26    ("gasket base 4", GASKET4),27    ("carpet base 9", CARPET9),28    ("base 10 missing 0", base_missing(10, 0)),29    ("base 10 missing 1", base_missing(10, 1)),30    ("base 10 missing 5", base_missing(10, 5)),31]3233# CHECKS3435FAILS = []3637def chk(value, want, tol):38    if abs(value - want) <= tol:39        return "ok"40    FAILS.append((value, want))41    return "MISMATCH"4243def chk_le(value, cap, name):44    if value <= cap:45        return "ok"46    FAILS.append((name, value, cap))47    return "MISMATCH"4849def close(t0):50    print(f"runtime {time.time() - t0:.1f}s")51    if FAILS:52        raise SystemExit(f"{len(FAILS)} rows off target: {FAILS}")53    print("every asserted row matches")5455# FLOAT TRANSFORM5657def mask(F, D):58    k = len(F)59    def f(t):60        acc = np.zeros(np.broadcast(*t).shape, dtype=complex)61        for v in F:62            acc = acc + np.exp(2j * np.pi * sum(v[i] * t[i] for i in range(D)))63        return np.abs(acc) / k64    return f, k6566def lip_of(F):67    return (2 * math.pi / len(F)) * sum(sum(abs(c) for c in v) for v in F)6869# ONE DIGIT, EXACT7071def digit_sums():72    for name, (q, D, F) in ROSTER:73        k = len(F)74        assert k == q ** D - 175        exact = Fraction(1) + Fraction(q ** D - 1, k)76        f, _ = mask(F, D)77        axes = np.meshgrid(*([np.arange(q)] * D), indexing="ij")78        num = float(f([a / q for a in axes]).sum())79        e = math.log(float(exact)) / math.log(q)80        print(f"{name}: q={q} D={D} k={k} one-digit l1 sum {exact} exact, scan {num:.12f} {chk(num, float(exact), 1e-12)}, log_q sum {e:.6f}, dim {math.log(k) / math.log(q):.6f}")8182def sqrt_split(n):83    a, b = 1, n84    d = 285    while d * d <= b:86        while b % (d * d) == 0:87            b //= d * d88            a *= d89        d += 190    return a, b9192def gasket_anchor():93    q, D, F = GASKET94    c4 = [1, 0, -1, 0]95    terms = {}96    for i in itertools.product(range(4), repeat=2):97        s = []98        for j in (0, 1):99            u = ((2 ** j) * i[0] % 4, (2 ** j) * i[1] % 4)100            s.append(3 + 2 * c4[u[0]] + 2 * c4[u[1]] + 2 * c4[(u[0] - u[1]) % 4])101        a, b = sqrt_split(s[0] * s[1])102        terms[b] = terms.get(b, 0) + a103    body = " + ".join(f"{a} sqrt {b}" if b > 1 else f"{a}" for b, a in sorted(terms.items()))104    val = sum(a * math.sqrt(b) for b, a in terms.items()) / 9105    g = Fraction(sum(terms.values()) if len(terms) == 1 else 0)106    f, k = mask(F, D)107    n = 4108    axes = [a.ravel() for a in np.meshgrid(*([np.arange(n)] * D), indexing="ij")]109    prod = np.ones(axes[0].shape)110    for j in range(2):111        prod *= f([((2 ** j) * a % n) / n for a in axes])112    scan = float(prod.sum())113    print(f"gasket 2D Sigma_2(0) = ({body})/9 = (8 + 2 sqrt 5)/3 exact = {val:.12f}, scan {scan:.12f} {chk(scan, val, 1e-12)}, threshold q^(ND/2) = 4, margin {val - 4:.6f}, exponent {math.log(val) / (2 * math.log(2)):.6f}")114115def entropy_bound():116    mp.dps = 30117    m1 = 2 * quad(lambda u: mplog(2 * mpcos(mp.pi * u)), [0, mpf(1) / 3])118    q, D, F = GASKET119    a = float(m1) - math.log(3)120    print(f"gasket 2D entropy bound: int_(T^2) log|1 + e(t1) + e(t2)| = {float(m1):.12f}, int log|hat F| = {a:.12f}, Jensen gives alpha_1 >= D + that/log q = {2 + a / math.log(2):.6f}, threshold D/2 = 1.0")121122# GRID SUMS123124def grid_sum(q, D, F, L):125    f, k = mask(F, D)126    n = q ** L127    axes = np.meshgrid(*([np.arange(n)] * D), indexing="ij")128    prod = np.ones(axes[0].shape)129    for j in range(L):130        prod *= f([((q ** j) * a % n) / n for a in axes])131    return float(prod.sum())132133GRID = [134    ("gasket 2D", GASKET, [1.0000, 1.0278, 1.0388, 1.0446, 1.0482, 1.0505, 1.0522, 1.0535, 1.0545, 1.0553]),135    ("carpet 2D", CARPET, [0.6309, 0.6931, 0.7174, 0.7301, 0.7378, 0.7429]),136    ("gasket base 4", GASKET4, [0.5000, 0.4903, 0.4876, 0.4862, 0.4853, 0.4848, 0.4844, 0.4841, 0.4838, 0.4836]),137    ("carpet base 9", CARPET9, [0.3155, 0.3298, 0.3344, 0.3367, 0.3380, 0.3389]),138    ("base 10 missing 0", base_missing(10, 0), [None, None, None, None, None, 0.3086]),139    ("base 10 missing 1", base_missing(10, 1), [None, None, None, None, None, 0.3328]),140    ("base 10 missing 5", base_missing(10, 5), [None, None, None, None, None, 0.3420]),141]142143def grids(rows):144    for name, (q, D, F), want in rows:145        for L, w in enumerate(want, start=1):146            S = grid_sum(q, D, F, L)147            e = math.log(S) / (L * math.log(q))148            tag = "" if w is None else " " + chk(e, w, 1e-4)149            print(f"{name} L={L:2d}: sum {S:16.4f} exponent {e:.6f}{tag}")150151# SANDWICH, FLOAT152153def sandwich(name, q, D, F, N, m, want_lo, want_hi, chunk=2048):154    t0 = time.time()155    f, k = mask(F, D)156    lip = lip_of(F)157    n = q ** N158    axes = [a.ravel() for a in np.meshgrid(*([np.arange(n)] * D), indexing="ij")]159    h = 1.0 / (n * m)160    slack = lip * (q ** N - 1) / (q - 1) * (q ** (D * N)) * h / 2161    shifts = [a.ravel() * h for a in np.meshgrid(*([np.arange(m)] * D), indexing="ij")]162    vals = np.empty(len(shifts[0]))163    for s0 in range(0, len(shifts[0]), chunk):164        sh = [s[s0:s0 + chunk] for s in shifts]165        prod = np.ones((len(sh[0]), len(axes[0])))166        for j in range(N):167            prod *= f([((q ** j) * (a[None, :] / n + b[:, None])) % 1.0 for a, b in zip(axes, sh)])168        vals[s0:s0 + chunk] = prod.sum(axis=1)169    lo, hi = float(vals.min()) - slack, float(vals.max()) + slack170    el, eh = math.log(lo) / (N * math.log(q)), math.log(hi) / (N * math.log(q))171    thr = q ** (N * D / 2)172    tl = "" if want_lo is None else " " + chk(el, want_lo, 1e-4)173    th = "" if want_hi is None else " " + chk(eh, want_hi, 1e-4)174    print(f"{name} N={N} m={m}: scan [{vals.min():.6f}, {vals.max():.6f}] slack {slack:.6f} threshold {thr:.4f} -> alpha_1 > {el:.6f}{tl} and < {eh:.6f}{th}  ({time.time() - t0:.1f}s)")175176# INTERVAL KERNEL177178def dn(x):179    return np.nextafter(x, -np.inf)180181def up(x):182    return np.nextafter(x, np.inf)183184PI_UP = up(math.pi)185TABLES = {}186187def costable(Q):188    if Q not in TABLES:189        iv.prec = 96190        lo = np.empty(Q)191        hi = np.empty(Q)192        two = 2 * iv.pi193        for j in range(Q // 2 + 1):194            c = iv.cos(two * j / Q)195            lo[j] = dn(float(c.a))196            hi[j] = up(float(c.b))197        for j in range(Q // 2 + 1, Q):198            lo[j], hi[j] = lo[Q - j], hi[Q - j]199        TABLES[Q] = (lo, hi)200    return TABLES[Q]201202def folded(F):203    mult = {}204    for v in F:205        for w in F:206            d = tuple(a - b for a, b in zip(v, w))207            mult[d] = mult.get(d, 0) + 1208    zero = tuple(0 for _ in F[0])209    out, seen = [], set()210    for d, c in mult.items():211        if d == zero or d in seen:212            continue213        neg = tuple(-a for a in d)214        seen.add(d)215        seen.add(neg)216        out.append((c + mult.get(neg, 0), d))217    return out218219def lip_up(F):220    s = sum(sum(abs(c) for c in v) for v in F)221    return up(up(2 * PI_UP * s) / len(F))222223def hat_iv(kc, Q, dif, k, side):224    lo, hi = costable(Q)225    tab = hi if side else lo226    s = np.full(kc[0].shape, float(k))227    for c, d in dif:228        idx = kc[0] * d[0]229        for j in range(1, len(d)):230            idx = idx + kc[j] * d[j]231        t = tab[idx % Q]232        s = up(s + up(c * t)) if side else dn(s + dn(c * t))233    r = np.sqrt(np.maximum(s, 0.0))234    if side:235        return np.minimum(up(up(r) / k), 1.0)236    return dn(dn(r) / k)237238def kernel_check(pts=400, Q=1944):239    mp.dps = 40240    rng = np.random.default_rng(20250906)241    bad, wide = 0, 0.0242    for name, (q, D, F) in [("gasket 2D", GASKET), ("carpet 2D", CARPET), ("carpet base 9", CARPET9)]:243        dif, k = folded(F), len(F)244        kc = [rng.integers(0, Q, pts) for _ in range(D)]245        lo = hat_iv(kc, Q, dif, k, False)246        hi = hat_iv(kc, Q, dif, k, True)247        for i in range(pts):248            acc = mpc(0)249            for v in F:250                acc += expjpi(2 * mpf(int(sum(int(v[c]) * int(kc[c][i]) for c in range(D)))) / Q)251            t = abs(acc) / k252            if not (mpf(float(lo[i])) <= t <= mpf(float(hi[i]))):253                bad += 1254            wide = max(wide, float(hi[i] - lo[i]))255    print(f"interval kernel against {mp.dps}-digit truth on {3 * pts} arguments mod {Q}: outside enclosure {bad} {chk(bad, 0, 0)}, widest enclosure {wide:.3e}")256257# SANDWICH, CERTIFIED258259def sandwich_iv(name, q, D, F, N, m, chunk=2048):260    t0 = time.time()261    Q = q ** N * m262    costable(Q)263    dif, k = folded(F), len(F)264    n = q ** N265    grid = [a.ravel() * m for a in np.meshgrid(*([np.arange(n)] * D), indexing="ij")]266    shifts = [a.ravel() for a in np.meshgrid(*([np.arange(m)] * D), indexing="ij")]267    slack = up(up(up(lip_up(F) * ((q ** N - 1) // (q - 1))) * q ** (D * N)) / (2 * q ** N * m))268    best_lo, best_hi = np.inf, 0.0269    for s0 in range(0, len(shifts[0]), chunk):270        sh = [s[s0:s0 + chunk] for s in shifts]271        pl = np.ones((len(sh[0]), len(grid[0])))272        ph = np.ones((len(sh[0]), len(grid[0])))273        for j in range(N):274            kc = [((q ** j) * (g[None, :] + b[:, None])) % Q for g, b in zip(grid, sh)]275            pl = dn(pl * hat_iv(kc, Q, dif, k, False))276            ph = up(ph * hat_iv(kc, Q, dif, k, True))277        al = np.zeros(len(sh[0]))278        ah = np.zeros(len(sh[0]))279        for c in range(pl.shape[1]):280            al = dn(al + pl[:, c])281            ah = up(ah + ph[:, c])282        best_lo = min(best_lo, float(al.min()))283        best_hi = max(best_hi, float(ah.max()))284    cl, ch = dn(best_lo - slack), up(best_hi + slack)285    thr = q ** (N * D / 2)286    el = math.floor(math.log(cl) / (N * math.log(q)) * 1e4) / 1e4287    eh = math.ceil(math.log(ch) / (N * math.log(q)) * 1e4) / 1e4288    assert cl > q ** (N * el) and ch < q ** (N * eh)289    print(f"{name} N={N} m={m} certified: min > {cl:.6f}, max < {ch:.6f}, slack {slack:.6f}, threshold q^(ND/2) = {thr:.4f} -> alpha_1 > {el:.4f} and < {eh:.4f}  [{'KILL' if cl > thr else 'no kill'}]  ({time.time() - t0:.1f}s)")290    return el, eh291292# WINDOW STATES293294def window_state(q, D, nd):295    S = q ** D296    dig = np.array(list(itertools.product(range(q), repeat=D)))297    W = S ** nd298    idx = np.arange(W)299    bi = []300    for c in range(D):301        acc = np.zeros(W, dtype=np.int64)302        for i in range(nd):303            acc = acc + dig[:, c][(idx // S ** i) % S] * (q ** (nd - 1 - i))304        bi.append(acc)305    return S, W, idx, bi306307def window_G(q, D, F, nd, m):308    f, k = mask(F, D)309    S, W, idx, bi = window_state(q, D, nd)310    box = 2.0 / q ** nd311    h = box / m312    sub = [a.ravel() for a in np.meshgrid(*([np.arange(m) * h + h / 2] * D), indexing="ij")]313    G = np.empty(W)314    B = max(1, 2_000_000 // len(sub[0]))315    for s0 in range(0, W, B):316        t = [(b[s0:s0 + B, None] / q ** nd + s[None, :]) % 1.0 for b, s in zip(bi, sub)]317        G[s0:s0 + B] = f(t).max(axis=1)318    return np.minimum(G + lip_of(F) * h / 2, 1.0), S, W319320def window_G_iv(q, D, F, nd, m):321    Q = q ** nd * m322    costable(Q)323    dif, k = folded(F), len(F)324    S, W, idx, bi = window_state(q, D, nd)325    sub = [a.ravel() for a in np.meshgrid(*([2 * np.arange(m) + 1] * D), indexing="ij")]326    G = np.empty(W)327    B = max(1, 2_000_000 // len(sub[0]))328    for s0 in range(0, W, B):329        kc = [(b[s0:s0 + B, None] * m + s[None, :]) % Q for b, s in zip(bi, sub)]330        G[s0:s0 + B] = hat_iv(kc, Q, dif, k, True).max(axis=1)331    return np.minimum(up(G + up(lip_up(F) / (q ** nd * m))), 1.0), S, W332333def perron(G, S, nd, t=1.0, iters=500):334    idx = np.arange(len(G))335    succ = [(idx % S ** (nd - 1)) * S + s for s in range(S)]336    Gt = G if t == 1.0 else G ** t337    w = np.ones(len(G))338    lam = 0.0339    for it in range(iters):340        nw = sum(Gt[u] * w[u] for u in succ)341        nl = float(nw.max())342        w = nw / nl343        if abs(nl - lam) < 1e-13:344            lam = nl345            break346        lam = nl347    return lam, np.maximum(w, 1e-12), succ, Gt348349def cw_bound(Gt, w, succ):350    acc = np.zeros(len(w))351    for u in succ:352        acc = up(acc + up(Gt[u] * w[u]))353    plain = np.zeros(len(w))354    for u in succ:355        plain = up(plain + Gt[u])356    return float(up(acc / w).max()), float(plain.max())357358MAY1 = ("published lambda_(1,4) < 2.24190 at 5 digits and box 10^(-5)", 2.24190, 27 / 77)359MAYT = ("published lambda_(235/154,4) < 1.36854", 1.36854, 59 / 433)360KAR1 = ("published 0.3219 at 4 digits", None, 0.3219)361KART = ("published 0.14355 at 4 digits", None, 0.14355)362363WINDOWS = [364    ("base 10 missing 5", base_missing(10, 5), [(4, 64, 2.245878, MAY1), (5, 64, 2.242123, MAY1)]),365    ("base 10 missing 0", base_missing(10, 0), [(4, 64, 2.045493, None), (5, 64, 2.041488, None)]),366    ("carpet 2D", CARPET, [(3, 24, 3.355167, None), (4, 24, 2.670258, None), (5, 24, 2.441254, None)]),367    ("gasket 2D", GASKET, [(4, 24, 2.627210, None), (6, 24, 2.219782, None), (7, 24, 2.153314, None)]),368    ("gasket base 4", GASKET4, [(4, 256, 1.988435, None), (6, 256, 1.952957, None), (8, 256, 1.950717, None)]),369    ("carpet base 9", CARPET9, [(4, 256, 2.134067, None)]),370    ("base 9 missing 0", base_missing(9, 0), [(4, 64, 2.033782, KAR1)]),371]372373def windows(rows):374    for name, (q, D, F), rs in rows:375        for nd, m, want, ref in rs:376            t0 = time.time()377            G, S, W = window_G(q, D, F, nd, m)378            lam, w, succ, Gt = perron(G, S, nd)379            e = math.log(lam) / math.log(q)380            cal = "" if ref is None else f" calibration {ref[0]}, exponent {ref[2]:.6f}, gap {e - ref[2]:+.6f}"381            print(f"{name} windows {nd} digits {W} states sub-scan {m}^{D}: lambda {lam:.6f} {chk(lam, want, 5e-6)} exponent {e:.6f} threshold D/2 = {D / 2}{cal}  ({time.time() - t0:.1f}s)")382383def certify_windows(rows):384    for name, (q, D, F), nd, m in rows:385        t0 = time.time()386        G, S, W = window_G_iv(q, D, F, nd, m)387        lam, w, succ, Gt = perron(G, S, nd)388        mu, plain = cw_bound(Gt, w, succ)389        e = math.ceil(math.log(mu) / math.log(q) * 1e4) / 1e4390        ep = math.ceil(math.log(plain) / math.log(q) * 1e4) / 1e4391        assert mu < q ** e and plain < q ** ep392        print(f"{name} windows {nd} digits {W} states sub-scan {m}^{D} certified: row sum {plain:.6f} -> alpha_1* < {ep:.4f}, weighted {mu:.6f} -> alpha_1* < {e:.4f}, threshold D/2 = {D / 2}  [{'PASS' if mu < q ** (D / 2) else 'no pass'}]  ({time.time() - t0:.1f}s)")393394# MOMENTS395396def crit(b):397    return (1 + math.log(b - 1) / math.log(b) / 2) / 5398399MOMENTS = [400    ("base 10 missing 5", base_missing(10, 5), 4, 64, [(1.0, 0.3514, MAY1), (1.5, 0.1447, None), (235 / 154, 0.1370, MAYT), (1.6, 0.1170, None), (1.7, 0.0937, None)]),401    ("base 9 missing 0", base_missing(9, 0), 4, 64, [(1.5, 0.1446, KART), (235 / 154, 0.1380, None), (1.6, 0.1204, None), (1.7, 0.0995, None)]),402    ("carpet base 9", CARPET9, 4, 64, [(1.0, 0.3451, None), (1.5, 0.1544, None), (235 / 154, 0.1470, None), (1.6, 0.1275, None), (1.7, 0.1042, None)]),403    ("carpet base 9", CARPET9, 5, 64, [(1.0, 0.3437, None), (1.5, 0.1531, None), (235 / 154, 0.1457, None), (1.6, 0.1262, None), (1.7, 0.1031, None), (1.8, 0.0835, None)]),404    ("carpet base 9", CARPET9, 6, 64, [(1.0, 0.3435, None), (1.5, 0.1529, None)]),405    ("gasket base 4", GASKET4, 8, 256, [(1.0, 0.4820, None), (235 / 154, 0.3170, None)]),406]407408def moments(rows):409    for name, (q, D, F), nd, m, ss in rows:410        t0 = time.time()411        G, S, W = window_G(q, D, F, nd, m)412        for s, want, ref in ss:413            lam, w, succ, Gt = perron(G, S, nd, s)414            g = math.log(lam) / math.log(q)415            rhs = crit(q) * (2 - s)416            cal = "" if ref is None else f" calibration {ref[0]}, exponent {ref[2]:.6f}, gap {g - ref[2]:+.6f}"417            print(f"{name} {nd} digits s={s:.6f}: lambda {lam:.6f} g(s) {g:.6f} {chk(g, want, 1e-4)} criterion {rhs:.6f} margin {rhs - g:+.6f} {'PASS' if g < rhs else 'FAIL'}{cal}")418        print(f"  ({time.time() - t0:.1f}s)")419420# LEMMA A PRIME421422def m_of(q, d):423    m, p = 1, q424    while 2 * p <= d:425        p *= q426        m += 1427    return m428429def order(q, d):430    r, x = 1, q % d431    while x != 1:432        x = x * q % d433        r += 1434    return r435436def lemma_a(name, q, D, F, dmax, want):437    f, k = mask(F, D)438    c = 1 - (2 / k) * (1 - math.cos(math.pi / (2 * q)))439    worst = []440    for d in range(3, dmax + 1):441        if math.gcd(d, q) != 1:442            continue443        r, md = order(q, d), m_of(q, d)444        axes = np.meshgrid(*([np.arange(d)] * D), indexing="ij")445        prod = np.ones(axes[0].shape)446        for j in range(r):447            prod *= f([((q ** j % d) * a % d) / d for a in axes])448        prod[(0,) * D] = 0.0449        rate = float(prod.max()) ** (1 / r)450        assert rate <= c ** (1 / md) + 1e-12451        worst.append((rate, d, r, md))452    worst.sort(reverse=True)453    print(f"{name}: c(q,k) = {c:.6f}, moduli 3..{dmax} coprime to q, every per-digit rate at most c^(1/m_d), zero violations")454    for rate, d, r, md in worst[:4]:455        w = want.get(d)456        tag = "" if w is None else " " + chk(rate, w, 5e-7)457        print(f"  d={d:4d} ord={r:3d} m_d={md:2d} rate {rate:.6f}{tag} Lemma A' rate c^(1/m_d) {c ** (1 / md):.6f} Lemma A rate c^(1/ord) {c ** (1 / r):.6f}")458459# COROLLARIES460461def counts_mod(q, D, F, d, n):462    c = np.zeros((d,) * D, dtype=np.int64)463    c[(0,) * D] = 1464    ax = tuple(range(D))465    for j in range(n):466        w = pow(q, j, d)467        nx = np.zeros((d,) * D, dtype=np.int64)468        for v in F:469            nx += np.roll(c, [(w * a) % d for a in v], axis=ax)470        c = nx471    return c472473def corollary(name, q, D, F, dmax, nmax, cells):474    k = len(F)475    assert k ** nmax < 2 ** 62476    c = 1 - (2 / k) * (1 - math.cos(math.pi / (2 * q)))477    worst, rows = (0.0, None), []478    for d in range(3, dmax + 1):479        if math.gcd(d, q) != 1:480            continue481        r, md = order(q, d), m_of(q, d)482        for n in range(2, nmax + 1):483            C = counts_mod(q, D, F, d, n)484            dev = max(abs(Fraction(int(x), k ** n) - Fraction(1, d ** D)) for x in C.ravel())485            bp, ba = c ** (n // md), c ** (n // r)486            assert float(dev) <= bp487            ratio = float(dev) / bp488            if ratio > worst[0]:489                worst = (ratio, (d, n, r, md, float(dev), bp, ba))490            if (d, n) in cells:491                rows.append((d, n, r, md, float(dev), bp, ba, cells[(d, n)]))492    d, n, r, md, dev, bp, ba = worst[1]493    print(f"{name} equidistribution band: moduli 3..{dmax} coprime to q, levels 2..{nmax}, every exact deviation at most c^floor(n/m_d), zero violations")494    print(f"  worst ratio to the window bound {worst[0]:.6f} at d={d} n={n} (ord {r}, m_d {md}): deviation {math.ceil(dev * 1e7) / 1e7:.7f} against A' {math.ceil(bp * 1e6) / 1e6:.6f} and A {math.ceil(ba * 1e6) / 1e6:.6f}")495    for d, n, r, md, dev, bp, ba, want in rows:496        tag = "" if want is None else " " + chk(math.ceil(dev * 1e7) / 1e7, want, 5e-9)497        print(f"  d={d:3d} n={n:3d} ord={r:3d} m_d={md:2d} deviation {math.ceil(dev * 1e7) / 1e7:.7f}{tag} A' bound {math.ceil(bp * 1e6) / 1e6:.6f} A bound {math.ceil(ba * 1e6) / 1e6:.6f}")498499def base_peel(name, q, D, F, ms, nmax):500    k = len(F)501    c = 1 - (2 / k) * (1 - math.cos(math.pi / (2 * q)))502    e = 1503    for p in range(2, q + 1):504        if q % p == 0 and all(p % r for r in range(2, p)):505            e *= p506    ke = sum(1 for v in F if all(a % e == 0 for a in v))507    worst = (0.0, None)508    for m in ms:509        assert math.gcd(m, q) == 1510        mm = m_of(q, m)511        for n in range(2, nmax + 1):512            T = int(counts_mod(q, D, F, e * m, n)[(0,) * D])513            assert T == int(counts_mod(q, D, F, m, n - 1)[(0,) * D])514            err = abs(Fraction(T, k ** n) - Fraction(ke, k) * Fraction(1, m ** D))515            bp = c ** ((n - 1) // mm)516            assert float(err) <= bp517            ratio = float(err) / bp518            if ratio > worst[0]:519                worst = (ratio, (m, n, mm, float(err), bp, c ** ((n - 1) // order(q, m))))520    m, n, mm, err, bp, ba = worst[1]521    print(f"{name} base peel band: rad(q) = {e}, k_e = {ke}, coprime parts {list(ms)}, levels 2..{nmax}, T_(e m)(n) = T_m(n-1) exact and every error at most c^floor((n-1)/m_m), zero violations")522    print(f"  worst ratio {worst[0]:.6f} at m={m} n={n} (m_m {mm}): error {math.ceil(err * 1e7) / 1e7:.7f} against A' {math.ceil(bp * 1e6) / 1e6:.6f} and A {math.ceil(ba * 1e6) / 1e6:.6f}")523524# THE ORDER BAND525526def hat_missing(b, a0, th):527    th = th - np.floor(th)528    s = np.sin(np.pi * th)529    safe = np.where(s == 0.0, 1.0, s)530    K = np.where(s == 0.0, float(b), np.sin(b * np.pi * th) / safe)531    ph = np.cos(2 * np.pi * th * (a0 - (b - 1) / 2))532    return np.sqrt(np.maximum(K * K - 2 * K * ph + 1.0, 0.0)) / (b - 1)533534def hat_missing_check(b, a0, pts=2000):535    f, k = mask(base_missing(b, a0)[2], 1)536    rng = np.random.default_rng(20250906)537    th = rng.random(pts)538    w = float(np.abs(hat_missing(b, a0, th) - f([th])).max())539    print(f"base {b} missing {a0} closed form |sin(b pi th)/sin(pi th) - e((a0 - (b-1)/2) th)|/(b-1) against the character sum on {pts} arguments: worst gap {w:.3e} {chk(w, 0.0, 1e-11)}")540541def order_band(b, a0, N, m, ss, chunk=500):542    lip = (2 * math.pi / (b - 1)) * sum(a for a in range(b) if a != a0)543    n = b ** N544    i = np.arange(n)545    h = 1.0 / (n * m)546    best = {s: np.inf for s in ss}547    for s0 in range(0, m, chunk):548        xg = (np.arange(s0, min(s0 + chunk, m)) + 0.5) * h549        P = np.ones((len(xg), n))550        for j in range(N):551            P *= np.maximum(hat_missing(b, a0, (b ** j) * (xg[:, None] + i[None, :] / n)) - (b ** j) * lip * h / 2, 0.0)552        lg = np.log(np.maximum(P, 1e-300))553        for s in ss:554            best[s] = min(best[s], float(np.exp(s * lg).sum(axis=1).min()))555    return best556557def criterion_band(name, b, a0, N, m, want):558    t0 = time.time()559    ss = sorted(set([round(1.0 + 0.01 * i, 4) for i in range(30)] + [round(1.3 + 0.002 * i, 4) for i in range(151)] + [round(1.6 + 0.01 * i, 4) for i in range(21)] + [1.85, 1.9, 2.0]))560    best = order_band(b, a0, N, m, ss)561    par = (b / (b - 1)) ** N562    print(f"{name} shift sandwich at N={N}, m={m}: Parseval gives Sigma_N^(2)(x) = (b/(b-1))^N = {par:.6f} for every x, scan {best[2.0]:.6f}, slack {par - best[2.0]:.6f}, scan <= anchor {chk_le(best[2.0], par, 'parseval anchor')} ({time.time() - t0:.1f}s)")563    best[2.0] = par564    lo = {s: math.floor(math.log(best[s]) / (N * math.log(b)) * 1e6) / 1e6 for s in ss}565    rhs = {s: math.ceil(crit(b) * (2 - s) * 1e6) / 1e6 for s in ss}566    for s in ss:567        if s in want:568            print(f"  s={s:.4f} min Sigma {best[s]:.6f} -> m_s > {lo[s]:.6f} {chk(lo[s], want[s], 5e-7)} criterion {rhs[s]:.6f} margin {lo[s] - rhs[s]:+.6f}")569    for left in (1.5, 1.0):570        cur, cover = left, []571        while cur < 2.0:572            nxt = max((s for s in ss if s > cur and lo[s] > rhs[cur]), default=None)573            if nxt is None:574                break575            cover.append((cur, nxt))576            cur = nxt577        ok = bool(cover) and cover[-1][1] >= 2.0578        a, z = min(cover, key=lambda p: lo[p[1]] - rhs[p[0]])579        print(f"  monotone cover of [{left}, 2) in {len(cover)} intervals, Sigma_N^(s) falling in s and the criterion falling in s: {'COMPLETE' if ok else 'INCOMPLETE'} {chk(1.0 if ok else 0.0, 1.0, 0.0)}")580        print(f"    tightest cell s={a:.4f} to {z:.4f}: m_s > {lo[z]:.6f} against the criterion {rhs[a]:.6f} at the left end, margin {lo[z] - rhs[a]:+.6f}")581    print(f"  the criterion asks m_s < {crit(b):.6f} (2 - s) for some s in [3/2, 2) and no order in [1, 2) delivers it")582583def order_rows(name, b, a0, N, m, ss, want, chunk):584    t0 = time.time()585    best = order_band(b, a0, N, m, ss, chunk)586    for s in ss:587        lo = math.floor(math.log(best[s]) / (N * math.log(b)) * 1e6) / 1e6588        rhs = math.ceil(crit(b) * (2 - s) * 1e6) / 1e6589        tag = "" if s not in want else " " + chk(lo, want[s], 5e-7)590        print(f"{name} shift sandwich at N={N}, m={m}, s={s:.6f}: min Sigma {best[s]:.6f} -> m_s > {lo:.6f}{tag} criterion {rhs:.6f} margin {lo - rhs:+.6f}  ({time.time() - t0:.1f}s)")591592def two_dim_moments(rows, ss):593    for name, (q, D, F), nd, m, want in rows:594        G, S, W = window_G(q, D, F, nd, m)595        for s in ss:596            lam, w, succ, Gt = perron(G, S, nd, s)597            e = math.log(lam) / (D * math.log(q))598            tag = "" if s not in want else " " + chk(math.ceil(e * 1e6) / 1e6, want[s], 5e-8)599            print(f"{name} {nd} digit-vectors s={s:.6f}: lambda {lam:.6f} exponent in X = q^(D M) units {math.ceil(e * 1e6) / 1e6:.6f}{tag} criterion {math.ceil(crit(q ** D) * (2 - s) * 1e6) / 1e6:.6f}")600601# THE LEAST BASE602603TWIDDLE = {}604605def imul(al, ah, bl, bh):606    p1, p2, p3, p4 = al * bl, al * bh, ah * bl, ah * bh607    return dn(np.minimum(np.minimum(p1, p2), np.minimum(p3, p4))), up(np.maximum(np.maximum(p1, p2), np.maximum(p3, p4)))608609def isq(lo, hi):610    a, c = lo * lo, hi * hi611    return dn(np.where(lo >= 0.0, a, np.where(hi <= 0.0, c, 0.0))), up(np.maximum(a, c))612613def twiddle(Q):614    if Q in TWIDDLE:615        return TWIDDLE[Q]616    B = math.isqrt(Q) + 1617    iv.prec = 96618    def tab(n, step):619        cl, ch, sl, sh = (np.empty(n) for _ in range(4))620        two = 2 * iv.pi621        for j in range(n):622            a = two * ((j * step) % Q) / Q623            c, s = iv.cos(a), iv.sin(a)624            cl[j], ch[j] = dn(float(c.a)), up(float(c.b))625            sl[j], sh[j] = dn(float(s.a)), up(float(s.b))626        return cl, ch, sl, sh627    TWIDDLE[Q] = (B, tab(B, 1), tab(Q // B + 2, B))628    return TWIDDLE[Q]629630def cos_iv(TW, idx):631    B, small, big = TW632    i1 = idx // B633    i0 = idx - i1 * B634    pl, ph = imul(big[0][i1], big[1][i1], small[0][i0], small[1][i0])635    ql, qh = imul(big[2][i1], big[3][i1], small[2][i0], small[3][i0])636    return dn(pl - qh), up(ph - ql)637638def hat_missing_iv(b, a0, j, P, Q, TW):639    jm = j % P640    s1l, s1h = cos_iv(TW, (2 * jm - P) % Q)641    sbl, sbh = cos_iv(TW, (2 * b * jm - P) % Q)642    phl, phh = cos_iv(TW, ((4 * a0 - 2 * b + 2) * jm) % Q)643    if s1l.min() <= 0.0:644        raise SystemExit("denominator enclosure touches zero")645    kl, kh = imul(sbl, sbh, dn(1.0 / s1h), up(1.0 / s1l))646    k2l, k2h = isq(kl, kh)647    ml, mh = imul(kl, kh, phl, phh)648    el = dn(dn(k2l - up(2.0 * mh)) + 1.0)649    eh = up(up(k2h - dn(2.0 * ml)) + 1.0)650    return dn(dn(np.sqrt(np.maximum(el, 0.0))) / (b - 1)), up(up(np.sqrt(np.maximum(eh, 0.0))) / (b - 1))651652def base_windows(b, a0, nd, m, wide=1):653    W = b ** nd654    P = 2 * m * W655    Q = 4 * P656    TW = twiddle(Q)657    lip = up(up(2 * PI_UP * sum(a for a in range(b) if a != a0)) / (b - 1))658    slack = up(up(lip * wide) / (2 * W * m))659    off = (wide * (2 * np.arange(m) + 1)).astype(np.int64)660    Ghi, Glo = np.empty(W), np.empty(W)661    CH = max(1, 400_000 // m)662    for s0 in range(0, W, CH):663        w = np.arange(s0, min(s0 + CH, W), dtype=np.int64)664        j = 2 * m * w[:, None] + off[None, :]665        vl, vh = hat_missing_iv(b, a0, j, P, Q, TW)666        Ghi[s0:s0 + CH] = np.minimum(up(vh.max(axis=1) + slack), 1.0)667        Glo[s0:s0 + CH] = np.maximum(dn(vl.min(axis=1) - slack), 0.0)668    return Ghi, Glo, slack669670def perron_red(G, b, nd, iters=6000, floor_it=300, streak_need=50, tol=1e-13):671    S = b ** (nd - 1)672    U = b ** (nd - 2)673    G3 = G.reshape(b, U, b)674    y = np.ones(S)675    z = np.empty((b, U))676    lam = 0.0677    streak = 0678    for it in range(iters):679        Y = y.reshape(U, b)680        for c in range(b):681            z[c] = (G3[c] * Y).sum(axis=1)682        nl = float(z.max())683        if nl <= 0.0:684            return 0.0, np.ones(S)685        y = (z / nl).reshape(S)686        streak = streak + 1 if abs(nl - lam) <= tol * nl else 0687        lam = nl688        if streak >= streak_need and it >= floor_it:689            break690    return lam, np.maximum(y, 1e-30)691692def cw_red(G, y, b, nd, side):693    U = b ** (nd - 2)694    G3 = G.reshape(b, U, b)695    Y = y.reshape(U, b)696    acc = np.empty((b, U))697    for c1 in range(b):698        r = up(G3[c1] * Y) if side else np.maximum(dn(G3[c1] * Y), 0.0)699        a = np.zeros(U)700        for c0 in range(b):701            a = up(a + r[:, c0]) if side else np.maximum(dn(a + r[:, c0]), 0.0)702        acc[c1] = a703    ratio = acc.reshape(b * U) / y704    return float(up(ratio).max()) if side else float(dn(ratio).min())705706def alpha_band(b, a0, nd, m, wide=1):707    Ghi, Glo, slack = base_windows(b, a0, nd, m, wide)708    lh, yh = perron_red(Ghi, b, nd)709    ll, yl = perron_red(Glo, b, nd)710    mu_hi = cw_red(Ghi, yh, b, nd, True)711    mu_lo = cw_red(Glo, yl, b, nd, False)712    eh = math.ceil(math.log(mu_hi) / math.log(b) * 1e7) / 1e7713    el = None if mu_lo <= 0.0 else math.floor(math.log(mu_lo) / math.log(b) * 1e7) / 1e7714    if not (mu_hi < b ** eh and (el is None or mu_lo > b ** el)):715        raise SystemExit(f"rounding unsafe at base {b} missing {a0}")716    return el, eh, mu_lo, mu_hi, slack717718def shift_check(b, a0, N, m):719    t0 = time.time()720    lip = (2 * math.pi / (b - 1)) * sum(a for a in range(b) if a != a0)721    n = b ** N722    i = np.arange(n)723    h = 1.0 / (n * m)724    lo, hi = np.inf, 0.0725    for s0 in range(0, m, 200):726        xg = (np.arange(s0, min(s0 + 200, m)) + 0.5) * h727        Pl = np.ones((len(xg), n))728        Ph = np.ones((len(xg), n))729        for j in range(N):730            v = hat_missing(b, a0, (b ** j) * (xg[:, None] + i[None, :] / n))731            Pl *= np.maximum(v - (b ** j) * lip * h / 2, 0.0)732            Ph *= np.minimum(v + (b ** j) * lip * h / 2, 1.0)733        lo = min(lo, float(Pl.sum(axis=1).min()))734        hi = max(hi, float(Ph.sum(axis=1).max()))735    el = math.floor(math.log(lo) / (N * math.log(b)) * 1e6) / 1e6736    eh = math.ceil(math.log(hi) / (N * math.log(b)) * 1e6) / 1e6737    print(f"base {b} missing {a0} shift sandwich N={N} m={m}, the grid machine not the window machine: min Sigma {lo:.6f} max Sigma {hi:.6f} -> alpha_1 in [{el:.6f}, {eh:.6f}]  ({time.time() - t0:.1f}s)")738    return el, eh739740def base_cert(b, a0, nd, m, wide=1, tag=""):741    t0 = time.time()742    el, eh, mu_lo, mu_hi, slack = alpha_band(b, a0, nd, m, wide)743    lo = "no positive certificate at this window length" if el is None else f"{el:.7f}"744    verdict = "CLEARS 1/4" if eh < 0.25 else ("FAILS 1/4" if el is not None and el >= 0.25 else "undecided at 1/4")745    print(f"base {b} missing {a0}{tag} windows {nd} digits sub-scan {m} box {wide}/{b}^{nd} certified: lambda in [{mu_lo:.6f}, {mu_hi:.6f}] slack {slack:.3e} -> alpha_1 > {lo} and < {eh:.7f}  [{verdict}]  ({time.time() - t0:.1f}s)")746    return el, eh747748def base_family(b, nd, m, side, want=None):749    t0 = time.time()750    rows = []751    for a0 in range((b + 1) // 2):752        el, eh, mu_lo, mu_hi, slack = alpha_band(b, a0, nd, m)753        rows.append((a0, el, eh))754    worst = max(rows, key=lambda r: r[2])755    best = min(rows, key=lambda r: r[2])756    band = " ".join(f"{a0}:[{-1.0 if el is None else el:.7f},{eh:.7f}]" for a0, el, eh in rows)757    if side:758        ok = all(eh < 0.25 for _, _, eh in rows)759        head = f"every one-missing-digit set in base {b} clears alpha_1 < 1/4" if ok else f"base {b} does not clear at every digit"760    else:761        ok = all(el is not None and el >= 0.25 for _, el, _ in rows)762        head = f"no one-missing-digit set in base {b} clears alpha_1 < 1/4" if ok else f"base {b} clears at some digit"763    print(f"{head}: {nd} digits sub-scan {m}, {len(rows)} digits up to the symmetry a0 <-> {b - 1} - a0, worst a0 = {worst[0]} at [{-1.0 if worst[1] is None else worst[1]:.7f}, {worst[2]:.7f}], best a0 = {best[0]} at [{-1.0 if best[1] is None else best[1]:.7f}, {best[2]:.7f}] {chk(1.0 if ok else 0.0, 1.0, 0.0)}  ({time.time() - t0:.1f}s)")764    print(f"  base {b} certified alpha_1 band by missing digit: {band}")765    return rows766767def family_window(b, a0, nd, m):768    Ghi, Glo, slack = base_windows(b, a0, nd, m)769    lh, yh = perron_red(Ghi, b, nd)770    mu_hi = cw_red(Ghi, yh, b, nd, True)771    eh = math.ceil(math.log(mu_hi) / math.log(b) * 1e7) / 1e7772    if not mu_hi < b ** eh:773        raise SystemExit(f"rounding unsafe at base {b} missing {a0}")774    return eh, mu_hi775776def family_close(lo, hi, m, nds):777    t0 = time.time()778    rows, bad = [], []779    for b in range(lo, hi + 1):780        for nd in nds:781            worst, arg = -1.0, -1782            for a0 in range((b + 1) // 2):783                eh, mu = family_window(b, a0, nd, m)784                if eh > worst:785                    worst, arg = eh, a0786            if worst < 0.25:787                break788        rows.append((b, nd, arg, worst))789        if worst >= 0.25:790            bad.append((b, arg, worst))791    ok = not bad792    head = f"every one-missing-digit set of every base {lo} <= q <= {hi} clears alpha_1 < 1/4" if ok else f"{len(bad)} base(s) in {lo} <= q <= {hi} do not clear at every digit"793    ceiling = max(rows, key=lambda r: r[3])794    print(f"{head}: {hi - lo + 1} bases, {sum((b + 1) // 2 for b in range(lo, hi + 1))} distinct sets, sub-scan {m}, shortest window in {nds} that clears; the band ceiling is q = {ceiling[0]} missing {ceiling[2]} at alpha_1 < {ceiling[3]:.7f} on {ceiling[1]} window digits {chk(1.0 if ok else 0.0, 1.0, 0.0)}  ({time.time() - t0:.1f}s)")795    for b, nd, arg, worst in rows:796        flag = "" if worst < 0.25 else "  FAILS 1/4"797        print(f"  q={b:3d} {(b + 1) // 2:2d} distinct sets {nd} window digits: worst a0 = {arg:2d} at alpha_1 < {worst:.7f}{flag}")798    return rows, bad799800def base_ladder(bases, nd, m, a0s):801    t0 = time.time()802    out = []803    for b in bases:804        a0 = a0s(b)805        el, eh, mu_lo, mu_hi, slack = alpha_band(b, a0, nd, m)806        out.append((b, a0, el, eh))807    print(f"certified alpha_1 ladder at {nd} digits sub-scan {m}, one missing digit per base: " + " ".join(f"q={b} a0={a0} [{-1.0 if el is None else el:.7f},{eh:.7f}]" for b, a0, el, eh in out) + f"  ({time.time() - t0:.1f}s)")808    return out809810# THE PAIR FAMILY811812def pair_missing(b, a, c):813    return (b, 1, [(d,) for d in range(b) if d != a and d != c])814815def hat_pair(b, a, c, th):816    th = th - np.floor(th)817    s = np.sin(np.pi * th)818    safe = np.where(s == 0.0, 1.0, s)819    K = np.where(s == 0.0, float(b), np.sin(b * np.pi * th) / safe)820    p = a - (b - 1) / 2821    r = c - (b - 1) / 2822    v = K * K + 2.0 + 2.0 * np.cos(2 * np.pi * (a - c) * th) - 2.0 * K * (np.cos(2 * np.pi * p * th) + np.cos(2 * np.pi * r * th))823    return np.sqrt(np.maximum(v, 0.0)) / (b - 2)824825def hat_pair_check(b, a, c, pts=2000):826    f, k = mask(pair_missing(b, a, c)[2], 1)827    rng = np.random.default_rng(20250907)828    th = rng.random(pts)829    w = float(np.abs(hat_pair(b, a, c, th) - f([th])).max())830    print(f"base {b} missing {{{a},{c}}} closed form |K - e((a - (b-1)/2) th) - e((c - (b-1)/2) th)|/(b-2) against the character sum on {pts} arguments: worst gap {w:.3e} {chk(w, 0.0, 1e-11)}")831832def pair_count(b):833    return ((b - 2) * (b - 3) // 2 + (b - 2) // 2) // 2 + b // 2834835def pair_sets(b):836    out = [(0, c) for c in range(1, b // 2 + 1)]837    seen = set()838    for a in range(1, b - 1):839        for c in range(a + 1, b - 1):840            if (b - 1 - c, b - 1 - a) in seen:841                continue842            seen.add((a, c))843            out.append((a, c))844    return out845846def hat_pair_iv(b, a, c, j, P, Q, TW):847    jm = j % P848    s1l, s1h = cos_iv(TW, (2 * jm - P) % Q)849    sbl, sbh = cos_iv(TW, (2 * b * jm - P) % Q)850    pal, pah = cos_iv(TW, ((4 * a - 2 * b + 2) * jm) % Q)851    pcl, pch = cos_iv(TW, ((4 * c - 2 * b + 2) * jm) % Q)852    dfl, dfh = cos_iv(TW, (4 * (a - c) * jm) % Q)853    if s1l.min() <= 0.0:854        raise SystemExit("denominator enclosure touches zero")855    kl, kh = imul(sbl, sbh, dn(1.0 / s1h), up(1.0 / s1l))856    k2l, k2h = isq(kl, kh)857    ml, mh = imul(kl, kh, dn(pal + pcl), up(pah + pch))858    el = dn(dn(dn(k2l + 2.0) + dn(2.0 * dfl)) - up(2.0 * mh))859    eh = up(up(up(k2h + 2.0) + up(2.0 * dfh)) - dn(2.0 * ml))860    return dn(dn(np.sqrt(np.maximum(el, 0.0))) / (b - 2)), up(up(np.sqrt(np.maximum(eh, 0.0))) / (b - 2))861862def pair_windows(b, a, c, nd, m, wide=1):863    W = b ** nd864    P = 2 * m * W865    Q = 4 * P866    TW = twiddle(Q)867    lip = up(up(2 * PI_UP * (b * (b - 1) // 2 - a - c)) / (b - 2))868    slack = up(up(lip * wide) / (2 * W * m))869    off = (wide * (2 * np.arange(m) + 1)).astype(np.int64)870    Ghi, Glo = np.empty(W), np.empty(W)871    CH = max(1, 400_000 // m)872    for s0 in range(0, W, CH):873        w = np.arange(s0, min(s0 + CH, W), dtype=np.int64)874        j = 2 * m * w[:, None] + off[None, :]875        vl, vh = hat_pair_iv(b, a, c, j, P, Q, TW)876        Ghi[s0:s0 + CH] = np.minimum(up(vh.max(axis=1) + slack), 1.0)877        Glo[s0:s0 + CH] = np.maximum(dn(vl.min(axis=1) - slack), 0.0)878    return Ghi, Glo, slack879880def pair_band(b, a, c, nd, m, wide=1, side=None):881    Ghi, Glo, slack = pair_windows(b, a, c, nd, m, wide)882    eh = el = None883    mu_hi = mu_lo = 0.0884    if side is None or side:885        lh, yh = perron_red(Ghi, b, nd)886        mu_hi = cw_red(Ghi, yh, b, nd, True)887        eh = math.ceil(math.log(mu_hi) / math.log(b) * 1e7) / 1e7888        if not mu_hi < b ** eh:889            raise SystemExit(f"rounding unsafe at base {b} missing {a},{c}")890    if side is None or not side:891        ll, yl = perron_red(Glo, b, nd)892        mu_lo = cw_red(Glo, yl, b, nd, False)893        el = None if mu_lo <= 0.0 else math.floor(math.log(mu_lo) / math.log(b) * 1e7) / 1e7894        if el is not None and not mu_lo > b ** el:895            raise SystemExit(f"rounding unsafe at base {b} missing {a},{c}")896    return el, eh, mu_lo, mu_hi, slack897898def pair_cert(b, a, c, nd, m, wide=1, tag="", thr=0.25, name="1/4"):899    t0 = time.time()900    el, eh, mu_lo, mu_hi, slack = pair_band(b, a, c, nd, m, wide)901    lo = "no positive certificate at this window length" if el is None else f"{el:.7f}"902    verdict = f"CLEARS {name}" if eh < thr else (f"FAILS {name}" if el is not None and el >= thr else f"undecided at {name}")903    print(f"base {b} missing {{{a},{c}}}{tag} windows {nd} digits sub-scan {m} box {wide}/{b}^{nd} certified: lambda in [{mu_lo:.6f}, {mu_hi:.6f}] slack {slack:.3e} -> alpha_1 > {lo} and < {eh:.7f}  [{verdict}]  ({time.time() - t0:.1f}s)")904    return el, eh905906def pair_census(bs):907    th = (np.arange(1001) + 0.5) / 1001908    for b in bs:909        fp = {}910        for a in range(b):911            for c in range(a + 1, b):912                fp.setdefault(tuple(np.round(hat_pair(b, a, c, th), 11)), []).append((a, c))913        sets = pair_sets(b)914        reps = {tuple(np.round(hat_pair(b, a, c, th), 11)) for (a, c) in sets}915        print(f"base {b}: {b * (b - 1) // 2} excluded pairs fall into {len(fp)} distinct transforms against (C(q-2,2) + floor((q-2)/2))/2 + floor(q/2) = {pair_count(b)} {chk(float(len(fp)), float(pair_count(b)), 0.0)}, the scan list holds {len(sets)} {chk(float(len(sets)), float(pair_count(b)), 0.0)} and meets every class {chk(float(len(reps)), float(len(fp)), 0.0)}; the edge class {{0,c}} is the one-missing-digit set of the {b - 1}-digit interval and collapses {{0,c}} with {{0,{b}-c}}")916917def pair_shortest(b, nds, m, side, thr=0.25, name="1/4"):918    t0 = time.time()919    todo = pair_sets(b)920    n0 = len(todo)921    done, wnd = [], {}922    for nd in nds:923        nxt = []924        for (a, c) in todo:925            el, eh, mu_lo, mu_hi, slack = pair_band(b, a, c, nd, m, side=side)926            v = eh if side else (-1.0 if el is None else el)927            if (v < thr) if side else (v >= thr):928                done.append((a, c, v))929                wnd[nd] = wnd.get(nd, 0) + 1930            else:931                nxt.append((a, c))932        todo = nxt933        if not todo:934            break935    ok = not todo936    key = (max(done, key=lambda r: r[2]) if side else min(done, key=lambda r: r[2])) if done else (-1, -1, -1.0)937    spread = " ".join(f"{nd}:{wnd[nd]}" for nd in sorted(wnd))938    verb = f"clears alpha_1 < {name} at every pair" if side else f"fails {name} at every pair"939    tail = ""940    if not ok:941        ups = []942        for (a, c) in todo:943            el, eh, mu_lo, mu_hi, slack = pair_band(b, a, c, nds[-1], m, side=not side)944            ups.append(f"{{{a},{c}}} S={a + c - b + 1} D={c - a} alpha_1 {'>' if side else '<'} {(-1.0 if el is None else el) if side else eh:.7f}")945        note = "not shown to clear" if side else "no positive lower certificate"946        tail = f"; {len(todo)} UNCLEAR at {nds[-1]} digits, {note}: " + ", ".join(ups)947    print(f"  q={b:3d} {n0:5d} distinct sets {verb}: window digits used {spread}, {'worst' if side else 'closest'} {{{key[0]},{key[1]}}} at alpha_1 {'<' if side else '>'} {key[2]:.7f}{tail} {chk(1.0 if ok else 0.0, 1.0, 0.0)}  ({time.time() - t0:.1f}s)", flush=True)948    return b, ok, key, wnd949950def pair_first(b, nds, m, thr=0.25, name="1/4", want=None):951    t0 = time.time()952    best, arg, wnd = None, None, None953    for (a, c) in pair_sets(b):954        for nd in nds:955            el, eh, mu_lo, mu_hi, slack = pair_band(b, a, c, nd, m, side=True)956            if eh < thr:957                break958        if best is None or eh < best:959            best, arg, wnd = eh, (a, c), nd960    ok = best < thr961    fl = pair_band(b, arg[0], arg[1], wnd, m, side=False)[0]962    floor = "no positive lower certificate" if fl is None else f"{fl:.7f}"963    pin = "" if want is None else " " + chk(1.0 if ok == want[0] else 0.0, 1.0, 0.0) + chk(best, want[1], 5e-7)964    print(f"  q={b:3d} {len(pair_sets(b)):5d} distinct sets, best pair {{{arg[0]},{arg[1]}}} at {wnd} window digits: alpha_1 < {best:.7f} [{'CLEARS' if ok else 'does not clear'} {name}], the infimum matrix of that set brackets it from below at alpha_1 > {floor} {chk(1.0 if fl is None or fl <= best else 0.0, 1.0, 0.0)}{pin}  ({time.time() - t0:.1f}s)", flush=True)965    return b, ok, arg, best966967def pair_some(b, nds, m, thr=0.25, name="1/4"):968    t0 = time.time()969    best, arg, wnd = -1.0, None, None970    for nd in nds:971        for (a, c) in pair_sets(b):972            el, eh, mu_lo, mu_hi, slack = pair_band(b, a, c, nd, m, side=False)973            v = -1.0 if el is None else el974            if v > best:975                best, arg, wnd = v, (a, c), nd976            if v >= thr:977                break978        if best >= thr:979            break980    print(f"  q={b:3d} {len(pair_sets(b)):5d} distinct sets, witness pair {{{arg[0]},{arg[1]}}} at {wnd} window digits: alpha_1 > {best:.7f} [{'FAILS' if best >= thr else 'no witness at these windows'} {name}] {chk(1.0 if best >= thr else 0.0, 1.0, 0.0)}  ({time.time() - t0:.1f}s)", flush=True)981    return b, best >= thr, arg, best982983def pair_ladder(bases, a, c, nd, m):984    t0 = time.time()985    out = []986    for b in bases:987        el, eh, mu_lo, mu_hi, slack = pair_band(b, a, c, nd, m)988        out.append((b, el, eh))989    print(f"certified alpha_1 ladder at {nd} digits sub-scan {m}, the interval class {{{a},{c}}} in each base: " + " ".join(f"q={b} [{-1.0 if el is None else el:.7f},{eh:.7f}]" for b, el, eh in out) + f"  ({time.time() - t0:.1f}s)")990    return out991992# VERBS993994def main():995    verb = sys.argv[1] if len(sys.argv) > 1 else "check"996    t0 = time.time()997    if verb == "check":998        digit_sums()999        gasket_anchor()1000        entropy_bound()1001        grids(GRID[:2])1002        lemma_a("gasket 2D", *GASKET, 129, {127: 0.808166, 129: 0.809637})1003        windows(WINDOWS[:1])1004        kernel_check()1005        sandwich_iv("gasket 2D", *GASKET, 2, 256)1006        certify_windows([("carpet 2D", CARPET, 4, 24)])1007        corollary("gasket 2D", *GASKET, 9, 10, {(5, 10): 0.0014741})1008    elif verb == "grid":1009        grids(GRID)1010    elif verb == "sandwich":1011        sandwich("gasket 2D", *GASKET, 2, 256, 1.0105, 1.1029)1012        sandwich("gasket 2D", *GASKET, 3, 256, 1.0126, 1.1022)1013        sandwich("gasket 2D", *GASKET, 4, 300, 1.0096, 1.1046)1014        sandwich("carpet 2D", *CARPET, 2, 256, 0.5828, 0.9507)1015        sandwich("carpet 2D", *CARPET, 3, 400, None, 0.9421)1016        sandwich("gasket base 4", *GASKET4, 4, 20000, None, 0.4864)1017        sandwich("carpet base 9", *CARPET9, 3, 20000, None, 0.3704)1018    elif verb == "certify":1019        gasket_anchor()1020        entropy_bound()1021        kernel_check()1022        sandwich_iv("gasket 2D", *GASKET, 2, 256)1023        sandwich_iv("gasket 2D", *GASKET, 3, 256)1024        certify_windows([("carpet 2D", CARPET, 4, 24), ("carpet 2D", CARPET, 5, 24)])1025    elif verb == "windows":1026        windows(WINDOWS)1027    elif verb == "moments":1028        moments(MOMENTS)1029    elif verb == "lemma":1030        lemma_a("gasket 2D", *GASKET, 301, {257: 0.830915, 255: 0.830253, 129: 0.809637, 127: 0.808166})1031    elif verb == "corollary":1032        corollary("gasket 2D", *GASKET, 15, 12, {(3, 2): 0.2222223, (5, 10): 0.0014741})1033        corollary("carpet 2D", *CARPET, 11, 8, {(4, 2): 0.0625, (5, 8): 0.0002842})1034        base_peel("gasket 2D", *GASKET, [3, 5, 7], 11)1035        base_peel("carpet 2D", *CARPET, [2, 5, 7], 7)1036    elif verb == "criterion":1037        hat_missing_check(9, 4)1038        hat_missing_check(10, 5)1039        criterion_band("carpet base 9", 9, 4, 4, 4000, {1.0: 0.334604, 1.46: 0.159988, 1.5: 0.148588, 1.6: 0.122780, 1.8: 0.081955, 2.0: 0.053605})1040        order_rows("carpet base 9", 9, 4, 5, 3000, [1.5, 235 / 154], {1.5: 0.149397, 235 / 154: 0.142274}, 60)1041        two_dim_moments([("carpet 2D", CARPET, 5, 24, {1.0: 0.406200, 1.5: 0.195631}), ("carpet base 9", CARPET9, 5, 64, {1.0: 0.343674, 1.5: 0.153069})], [1.0, 1.5, 235 / 154, 1.6, 1.7, 1.8])1042    elif verb == "least":1043        hat_missing_check(21, 0)1044        hat_missing_check(34, 16)1045        base_cert(10, 5, 4, 16, 2, " calibration against the study float row lambda 2.245878 and Maynard lambda_(1,4) < 2.24190")1046        base_cert(10, 5, 5, 16, 2, " calibration against the study float row lambda 2.242123 and 27/77 = 0.3506494")1047        base_cert(10, 5, 6, 16, 2, " calibration: 27/77 = 0.3506494 is a finite-window upper bound, not the exponent")1048        base_cert(9, 0, 4, 16, 2, " calibration against the study float row lambda 2.033782 and Karwatowski 0.3219")1049        base_cert(21, 0, 5, 8, 1, " THE LEAST BASE CARRYING ONE SUCH SET")1050        base_family(20, 4, 8, False)1051        base_family(34, 4, 8, True)1052        base_cert(33, 15, 4, 8, 1, " THE WITNESS THAT 34 IS LEAST FOR THE WHOLE FAMILY")1053        base_ladder([10, 14, 18, 20, 21, 22, 26, 30, 33, 34], 4, 8, lambda b: 0)1054        base_ladder([10, 14, 18, 20, 21, 22, 26, 30, 33, 34], 4, 8, lambda b: b // 2)1055        shift_check(21, 0, 4, 400)1056        shift_check(34, 16, 3, 600)1057        grids([("base 21 missing 0", base_missing(21, 0), [None] * 4)])1058    elif verb == "six":1059        base_cert(21, 0, 6, 8, 1, " THE LEAST BASE CARRYING ONE SUCH SET, THE HEADLINE WINDOW")1060        base_cert(10, 5, 7, 16, 2, " calibration: the exponent is strictly under 27/77 = 0.3506494")1061    elif verb == "pairs":1062        hat_pair_check(21, 0, 1)1063        hat_pair_check(32, 7, 19)1064        pair_census([6, 9, 10, 12])1065        pair_cert(32, 0, 1, 4, 8, 1, " THE LEAST BASE CARRYING ONE CERTIFIED SUCH SET")1066        pair_cert(31, 0, 1, 4, 8, 1, " THE WITNESS THAT 32 IS LEAST FOR THE INTERVAL CLASS")1067        pair_cert(20, 3, 11, 5, 8, 1, " THE WITNESS THAT 21 IS LEAST FOR THE WHOLE FAMILY AGAINST 1/3", 1 / 3, "1/3")1068        pair_first(13, [3], 8, 1 / 3, "1/3", (True, 0.3318819))1069        pair_first(12, [5], 8, 1 / 3, "1/3", (False, 0.3371162))1070        pair_ladder([20, 24, 28, 30, 31, 32, 33, 36, 40], 0, 1, 4, 8)1071    elif verb == "pairone":1072        v = sys.argv[2:]1073        thr, name = (1 / 3, "1/3") if v and v[-1] == "third" else (0.25, "1/4")1074        n = [int(x) for x in v if x != "third"]1075        pair_cert(n[0], n[1], n[2], n[3], n[4], n[5] if len(n) > 5 else 1, "", thr, name)1076    elif verb == "pairfail":1077        v = sys.argv[2:]1078        thr, name = (1 / 3, "1/3") if len(v) > 2 and v[2] == "third" else (0.25, "1/4")1079        for b in range(int(v[0]), int(v[1]) + 1):1080            pair_shortest(b, [2, 3, 4, 5], 8, False, thr, name)1081    elif verb == "pairclear":1082        v = sys.argv[2:]1083        thr, name = (1 / 3, "1/3") if len(v) > 2 and v[2] == "third" else (0.25, "1/4")1084        for b in range(int(v[0]), int(v[1]) + 1):1085            pair_shortest(b, [2, 3, 4], 8, True, thr, name)1086    elif verb == "pairsome":1087        v = sys.argv[2:]1088        thr, name = (1 / 3, "1/3") if len(v) > 2 and v[2] == "third" else (0.25, "1/4")1089        for b in range(int(v[0]), int(v[1]) + 1):1090            pair_some(b, [3, 4, 5], 8, thr, name)1091    elif verb == "pairfirst":1092        v = sys.argv[2:]1093        thr, name = (1 / 3, "1/3") if len(v) > 2 and v[2] == "third" else (0.25, "1/4")1094        for b in range(int(v[0]), int(v[1]) + 1):1095            pair_first(b, [2, 3, 4, 5], 8, thr, name)1096    elif verb == "family":1097        family_close(35, 125, 8, [2, 3, 4])1098    else:1099        raise SystemExit("verbs: check grid sandwich certify windows moments lemma corollary criterion least six family pairs pairfail pairclear")1100    close(t0)11011102main()