sillclass.py

Checks: THERMAL: The lim inf is the class minimum theorem; observation; THERMAL: The 2-power tower raises the sill theorem; rule.

Cited on: THERMAL.

To run it: save sillclass.py, with fieldtop.py, growth.py, memory.py, spectrum.py, splitend.py, splitloss.py, splitsharp.py, typeloss.py beside it; needs mpmath, numpy, scipy.

"""sillclass.py -- the sill without its hypothesis: the lim inf of the
columns at the places of prime norm, read through the classes that K's
largest abelian subfield K_ab allows, and whether a field containing
Q(i), where the sill rises, still loses.

QUESTION. The sill L = L(2) is the lim inf over split r = 3 mod 4
given a prime s = 3 mod 4 split completely and = 1 mod no odd ramified
prime. Without that hypothesis, what is the lim inf of the headroom sums
at the places P of prime norm r, and at type (1, 0) with Q(i) inside K,
where it rises, does the F2 place still lose, at every degree?

THE DERIVATION. N~ the Galois closure, H = Gal(N~/K), A = N~ cap Q^ab,
K_ab = K cap Q^ab, f its conductor, N = lcm(4, f), m(a) = prod over
l | N of l^min(v_l(a - 1), v_l(N)), L(m) the product over the places R
of K of 1 + n^-b + ... + n^-(j b), n = N(R), j the deepest with
lambda(R^j) | m (finite: lambda(R) | m needs n <= m + 1).
  (1) CLASSES. r has a place of degree 1 iff Frob_r lies in U, the union
  of H's conjugates; conjugation is trivial on A, so U|_A = H|_A =
  Gal(A/K_ab): the classes r mod N that occur are the a trivial on K_ab
  (G_N). Split r give only the classes trivial on A.
  (2) FLOOR. At P of prime norm r > m(a) + 1, r = a mod N: m(a) | r - 1,
  so every R with lambda(R^j) | m(a) enters to depth j: Sigma >= L(m(a)).
  (3) REACH (the sill's z-step). A lift a' mod N rad N with v_l(a' - 1)
  = v_l(m(a)) exactly, r = a' there, Frob_r in U over a, r != 1 mod each
  l < z off N, z > N + 1: an entrant past L(m(a)) has n > z (a prime of
  n - 1 off N divides r - 1) or lies over r (norm r without bound, factor
  -> 1; norm r^f, f >= 2, never), and no entrant of L(m(a)) is deeper
  (its prime p is below z and deepens R only where p | r - 1, so p
  divides N, where v_p(r - 1) is exact).
  (4) TAIL (Brun-Titchmarsh): log T = O(d A(r)) + o(1), A(r)
  the sum of delta^-b over divisors z <= delta <= sqrt r of r - 1, its
  sum to X at most (4X/log X) eps(z), eps(z) -> 0.
  (5) DENSITY (Chebotarev). F = N~ cap Q(zeta_N'), N' = N rad N times
  the l < z off N, lies in A; any c mod N' with c = a' and c != 0, 1
  mod each such l is trivial on K_ab, so c|_F is in Gal(F/F cap K_ab) =
  U|_F and some sigma in U matches it: the set has density at least
  [F:Q] prod (l - 2) / (|Gal(N~/Q)| phi(N rad N) prod (l - 1)), of order
  1/log z, c mod l off N being free, and by Markov half of it has A(r) <= 9 eps(z)/c_z -> 0.
So lim inf over the places of prime norm of Sigma(P) is L* = min over
a in G_N of L(m(a)), finitely many classes, a read through 2 and the
primes ramified in K_ab. K_ab = Q (every primitive K not Galois over
Q, every S_d closure at d >= 3 among them, Q(i) or Q(sqrt -3) in it or
not; a quadratic or cyclic K has K_ab = K): a = 3 mod 4, m = 2, L* = L. K containing Q(i): every a is 1 mod 4 and every
odd norm 1 mod 4 (p = 3 mod 4 is inert in Q(i)), so L(4) floors every
odd column of norm above 5; it is sharp where some a in G_N has m(a)
= 4 (then a lift a' = 5 mod 8 in step (3)), as at K_ab = Q(i). At Q(i)
itself U^1 = mu_4 x U^3 and squaring
maps U^j onto U^(j+2) for j >= 3, so the chain over 2 is 1, 2, 4, 4, 4,
4, 4, 8: depth 7. At type (1, 0), e = d >= 4, the place over 2 is
held to depth exactly 4 at v_2 = 2 ((1 + pi)^2 has valuation 2, its
square 4 when e > 2; every 4th power of a 1-unit is in U^4), no place
has norm 3: L_i = (1 + x + x^2 + x^3 + x^4) S5 against sigma_F2 = S5 W'.
M = l - l5 - w' (norm 5 cancels); at x_c, M = h5(x_c) + w5(x_c), h5 = 2
l - l5 + log x increasing; (1 - x) M' = 1 - 5 x^4/(1 + ... + x^4) - the
n != 5 terms, each increasing on (0, 1/2] (typeloss's D(x, a) > 0 at a
>= log2 9), so M is quasi-concave on [0, x_c], x_c <= 1/2, and
log(1 + margin) >= min(0, M(x_c)). At fixed n5 both terms rise with x_c,
which falls with the other counts, so the bound takes them maximal
(n9 <= d/2: 3 is inert in Q(i)) and scans n5 = 0..d.
  REALIZATION. K = Q(i)[t]/g, g monic over Z[i] of degree m = d/2, by
  the Chinese remainder theorem near local polynomials at the primes of
  Z[i] below Y = 10^5 and, by Krasner's lemma, with exactly those local
  algebras; at three primes of Z[i] above Y of norm a rational prime the
  unramified field of degree m, degree m - 1 beside Q_p, and the
  unramified quadratic beside Q_p^(m - 2) give S_m over Q(i) (m >= 3),
  and K_ab = Q(i): S_m is primitive, so no field lies strictly between
  Q(i) and K, and K is not Galois over Q(i), so not abelian; at m = 2, split at one prime over q >= Y
  and inert at its conjugate, K is not Galois over Q, D_4, K_ab =
  Q(i). At 2,
  Q_2(i)((1 + i)^(1/m)), e = d.
  (L) THE LEMMA FROM 930, at arm B's law (below). lam = log(1/x), a_n
  = log2 n, y = 9^-b = x^a9. The point solves l + lz + log(1 - (1 -
  x)e^-s) = 0, lz the log of the odd places' zeta, s = log(Z'/W); the
  last term is at most log x + s/x, so g_up = l + lz + log x + s/x
  bounds the left side, which rises with x. x1 solves d x^a9 = lam (the
  d/2 places of norm 9 give (d/2) 9^-b = lam/2), falls as d rises, and
  x1 <= 1/7 iff d >= d0 = lam0 7^a9, lam0 = log 7. There, with d = lam
  9^b: lz <= (lam/2)/(1 - y) + lam sum_{n = 17, 257, 65537} (9/n)^b/(1
  - n^-b) + lam (9/Y)^b (1 + Y/(b - 1))/(1 - Y^-b) (the tail past Y, d
  places over each prime) + E, E over the places of norm p^m and p^d
  below Y, at most 4 5^(-m b)(1 + 5/(m b - 1)) (integral test); s/x <=
  (lam/2) x^(a9 - 1)/(1 - y^2) + lam sum_n (18/n^2)^b/(1 - n^-2b) + lam
  (18/Y)^b (1 + Y/(b - 1))/(1 - Y^-b) + E/x (a place of W adds
  -log(1 - y^2) <= y^2/(1 - y^2), the others whole). Every coefficient
  of lam rises with x, so is bounded at 1/7, and l <= log(7/6): g_up(x1)
  <= log(7/6) - (1 - c_z - c_s) lam0 + E', needing 1 - c_z - c_s > 0.
  w' >= (d/2) log(1 + y) >= (lam/2)(1 - y/2), so M(x1) <= log(7/6) -
  (lam0/2)(1 - y0/2), y0 = 7^-a9; M'(x1) <= 7/6 - a9 (lam0/2) 7/(1 +
  y0), every other term of M' being negative. Where g_up(x1) < 0 the
  point is above x1; M is quasi-concave on [0, x_c], the point at most
  x_c, so M'(x1) < 0 puts x1 past the peak and the margin at most M(x1).

PREDICTIONS (frozen before this code).
  P1 quadratic fields with an F2 place, |D| <= 400: L* = L at every D
     but -4; at -4, L* = (1 + ... + x^7)(1 + 5^-b)^2, the chain over 2
     of Z[i] reading 1, 2, 4, 4, 4, 4, 4, 8.
  P2 at Q(i) and Q(sqrt -7), over the split r < 2*10^5 in the best
     class, Sigma/L* - 1 >= -1e-12 and its least value below 1e-4; in
     a worse class (Q(sqrt -7), a = 1 mod 8) its least value stays above
     L(8)/L* - 1 > 0.01.
  P3 K in Q(i), type (1, 0), even d: the bound positive up to D_low,
     the certificate negative from D_high, both in [30, 100], and
     negative at every even d from D_high to 1000.
  P4 (the lemma, frozen before its code) d0 = ceil(log 7 * 7^a9) is
     between 900 and 960.
  P5 at x = 1/7: g_up <= -0.40, M <= -0.80, M' <= -20. KILL: g_up >= 0,
     M >= 0 or M' >= 0 printed at x = 1/7, or d0 > 1000.

CONTROLS (frozen).
  C1 at six quadratic fields the class minimum equals the direct L to
     1e-12 at b = 1.5.
  C2 at Q(i), L* >= sigma_F2 at the F2 point (the quadratic theorem).
  C3 the brute chain over 2 at Q(i), j = 1..8, is 1, 2, 4, 4, 4, 4, 4,
     8.
  C4 with the sill and law set back to typeloss's (1, 0), QiLaw's
     certificate reproduces typeloss.extremal(1, 0, d, "E").cert() to
     1e-12 at d = 4, 8.
  C5 PLANT: a Q(i) law with 5, 17, 257, 65537 of residue degree m over
     each prime of Z[i] gives a certificate >= 0 at D_high.
  C6 (added at review, the new M's own control): QiLaw.m at x = 0.3
     equals log(L_i/sigma_F2) from the products at qi_law(20) to 1e-12;
     QiLaw.dm equals M's central difference to 1e-6; and at d = 20, n5 =
     0 and 20, bound_i's h5(x_c) + n5 log(1 + x_c^a5) equals QiLaw.m at
     x_c on the law of exactly those counts, to 1e-12.
  C7 at every even d from d0 to 1000, at arm B's law: x1 <= x_low of
     the certificate, C <= M(x1) <= the lemma's M bound, and the law's
     own g_up(x1) and M'(x1) below the lemma's.
  C8 PLANT: the lemma's constants with d places of norm 9 (3 split
     completely, which Q(i) forbids) print g_up >= 0 at x = 1/7.
  C9 the lemma's lz and s/x bounds against a brute sum over arm B's
     places at d = 1000, x = x1, coefficients at 1/7 and at x1.

FINDINGS.
  CONTROLS. C1: L* = L to the last printed digit at D = -7, 8, -8, 12,
  -20, 17, each at m = 2 (a = 11 mod 28, 7 mod 8, 3 mod 8, 11 mod 12,
  3 mod 20, 15 mod 68). C2: at Q(i) the F2 point 1.496693, sigma_F2
  1.268618, L* 1.839476, +0.44998. C3: the chain over 2 of Z[i] is 1,
  2, 4, 4, 4, 4, 4, 8, 8, 16, 16, 32, 32 at j = 1..13. C4: difference 0
  at d = 4 and 8 (C -0.075606, -0.332186, typeloss's), by construction
  (QiLaw(old=True) is typeloss's TypeLaw): it reads the wiring, not the
  new M. C5 (restated, see RUN RECORD): no certificate negative where the
  bound is positive. C6: 8.9e-16, 3.7e-10, 6.1e-16.
  P1 HOLDS. 160 fundamental D, |D| <= 400, with an F2 place; L* != L at
  D = -4 alone, L*/L - 1 = 0.241461 at b = 1.5, m = 4, entrants (2, 7),
  (5, 1), (5, 1); the old hypothesis holds exactly where some class has
  m = 2 (no field differs).
  P2 FAILS as frozen, at one column: at Q(i), r = 5, Sigma/L* - 1 =
  -0.07317, the column at a place of norm 5 = m + 1, which L* counts as
  an entrant (the floor needs r > m(a) + 1). Over r > m + 1, 0 of the
  4510 columns past r = 5 at Q(i) (r = 5 mod 8) and 0 of the 4511 at
  Q(sqrt -7) (split, r = 3 mod 4, the classes of m = 2 and 14) fall
  below L*; the least Sigma/L* - 1 is 1.165e-8 at r = 199877 (r - 1 =
  4*107*467) and 1.558e-9 at r = 199679 (r - 1 = 2*99839). In the worse class (Q(sqrt -7), r = 1 mod 8) the least over
  2195 columns is 4.467e-2 at r = 198377, L(8)/L* - 1 = 0.044666.
  P3 FAILS as frozen. The bound is positive at every even d <= 10
  (+0.282440 at 4, +0.027465 at 10) and at most 0 at every even d from
  12 (-0.029970) to 200, where it is computed, its argmin n5 = 0 at
  every d printed: the worst field has no place of
  norm 5, which cancels in M and only holds the point low. So the frozen
  law (5 split completely) is not the worst: its certificate is
  positive to d = 62 (+0.001821) and negative from 64 (-0.000138) to
  1000 (-0.073291), M' < 0 and x_c < 1/2 at each. ARM B, added after
  the run, the bound's argmin, 5 of residue degree m over each prime of
  Z[i]: certificate +0.041683 at 12, negative from 14 (-0.007276) at
  every even d to 1000 (-1.537822), M' < 0, x_c < 1/2. So with Q(i) in
  K, type (1, 0): no field loses at d = 4..10, and at every even d =
  14..1000 a field that loses exists (realized by Krasner over Z[i],
  K_ab = Q(i)), d = 12 undecided at this law (tower.py, its algebras
  fixed to Y = 10^30, certifies it). "Loses" means infinitely many
  columns top the F2 place: the at most d columns at places of norm 5 sit below L_i (the
  r = 5 print at Q(i)) and are raced apart, as the cubic column of norm
  3 is.
  THE LEMMA. C7: at each of the 36 even d from 930 to 1000 it holds, the
  largest M(x1) -1.144476 at d = 930 (x1 0.142816, x_low 0.154056, C
  -1.513372, g_up(x1) -0.478610, M'(x1) -29.7347). C8: c_z 1.169962,
  g_up <= +0.514220, so the lemma can say no. C9: lz + lt 1.307854
  against c_z lam 1.315025 (at 1/7) and 1.308875 (at x1); (lz - sw +
  lt)/x 1.455e-2 against 1.523e-2 and 1.455e-2 (the norm-9 term all but
  exact at x1). P4 HOLDS: d0 = 930 (929.0096). P5 HOLDS: c_z 0.668913,
  c_s 0.007745, 1 - c_z - c_s 0.323342, E' at most 10^-910.94 (kept as
  1e-300, an upper bound, not a float zero); g_up <= -0.475044, M <=
  -0.817785, M' <= -20.3776.
  KILL MISSED: arm B loses at every even d >= 930, so with its
  certificates, a field containing Q(i), type (1, 0), loses at every
  even d >= 14.

RUN RECORD. `python sillclass.py` under the gate's 512 MB cap: 16 of 16
checks (12 before section L), 24.7 s, peak commit 68.7 MB. First run: the chain over 2 (to
norm 2^13) ran out at r - 1 with a high power of 2; extended by lambda(j)
= 2 lambda(j - e) past the brute (long_chain), read against the brute
at Q(i) through j = 13. The P1 print first compared the old hypothesis
with the first minimizing class's m, which ties miscount (D = 120,
204); it now asks whether some class has m = 2. The r > m + 1 read was
added beside the frozen one after the r = 5 column. C5 was frozen as
"the law with 5, 17, 257, 65537 of residue degree m prints C >= 0 at
D_high" (a plant meant to show the certificate can say no); it printed
-0.357978, the plant pushing the wrong way (dropping norm 5 hurts the
F2 place), and is restated as the consistency check above. At review:
C1 was frozen at five fields and runs six; C4 was frozen to reproduce
typeloss.bound too, and its bound arm was dropped (bound_i shares no code
with it), C4 reading only the subclass wiring; C6 was added as the new
M's control, read failing on a scratch copy with l5 replaced by l4.
The lemma (section L) ran first as a lab script, its first run
4 of 4 checks; it entered here unchanged but for names, the kill's
slope clause (1 - c_z - c_s > 0, which the frozen kill lacks and the
step in lam needs) printed beside the frozen ones.
"""

import math
import os
import sys
import time

HERE = os.path.dirname(os.path.abspath(__file__))
sys.path.insert(0, os.path.join(HERE, "..", "code"))
os.environ.setdefault("OPENBLAS_NUM_THREADS", "1")

import numpy as np  # noqa: E402
from scipy.optimize import brentq  # noqa: E402

import fieldtop as ft  # noqa: E402
import splitend as se  # noqa: E402
import splitsharp as ss  # noqa: E402
import typeloss as tl  # noqa: E402
from growth import factor, is_prime_mr  # noqa: E402

CHECKS = []
A5 = math.log2(5)


def check(name, ok, detail=""):
    CHECKS.append(bool(ok))
    print(f"  [{'PASS' if ok else 'FAIL'}] {name}" + (f"  ({detail})"
                                                   if detail else ""))


def guard():
    if not all(CHECKS):
        print("a control failed: no verdict")
        sys.exit(1)


def vl(n, l):
    v = 0
    while n % l == 0:
        n //= l
        v += 1
    return v


# ------------------------------------------- the classes, quadratic K

def classes(F):
    """G_N and m(a) for K = Q(sqrt D): K_ab = K, f = |D|."""
    f = abs(F.D)
    N = f * 4 // math.gcd(f, 4)
    ls = sorted(factor(N))
    out = []
    for a in range(1, N):
        if math.gcd(a, N) != 1 or ft.kronecker(F.D, a) != 1:
            continue
        m = 1
        for l in ls:
            cap = vl(N, l)
            m *= l ** (cap if (a - 1) % l ** cap == 0 else vl(a - 1, l))
        out.append((a, m))
    return N, out


def entrants(F, ch2, m):
    """(norm, depth) of every place R with lambda(R) | m."""
    out = []
    for r in range(2, m + 2):
        if not is_prime_mr(r):
            continue
        if r == 2:
            for NR, ch in ch2:
                j = 0
                while j < len(ch) and m % ch[j] == 0:
                    j += 1
                assert j < len(ch)
                if j:
                    out.append((NR, j))
            continue
        k = F.kind(r)
        NR = r * r if k == "inert" else r
        cnt = 2 if k == "split" else 1
        if m % ft.lam_formula(F, r, 1):
            continue
        j = 1
        while m % ft.lam_formula(F, r, j + 1) == 0:
            j += 1
        out += [(NR, j)] * cnt
    return out


def lval(ent, b):
    s = 1.0
    for NR, j in ent:
        x = NR ** -b
        s *= sum(x ** k for k in range(j + 1))
    return s


def direct_sill(F, b):
    x = 2.0 ** -b
    k2, k3 = F.kind(2), F.kind(3)
    L = (1 + x + x * x + x ** 3) ** 2 if k2 == "split" else 1 + x + x * x
    S3 = {"split": (1 + 3.0 ** -b) ** 2, "ram": 1 + 3.0 ** -b,
          "inert": 1.0}[k3]
    return L * S3


def lstar(F, ch2, b):
    N, cl = classes(F)
    best = None
    for a, m in cl:
        v = lval(entrants(F, ch2, m), b)
        if best is None or v < best[0] - 1e-15:
            best = (v, a, m)
    return best + (N,)


def old_hyp(F):
    """A split prime s = 3 mod 4, = 1 mod no odd prime dividing D."""
    odd = [p for p in factor(abs(F.D)) if p != 2]
    for s in range(3, 20000, 4):
        if is_prime_mr(s) and F.kind(s) == "split" and \
                all((s - 1) % p for p in odd):
            return s
    return None


def fundamental(D):
    if D in (0, 1):
        return False
    if D % 4 == 1:
        core = D
    elif D % 4 == 0 and (D // 4) % 4 in (2, 3):
        core = D // 4
    else:
        return False
    return all(e == 1 for e in factor(abs(core)).values()) if abs(core) > 1 \
        else core == -1


def section_q():
    print("\n=== Q: the class minimum at the quadratic fields")
    print("CONTROL C3: the chain over 2 at Q(i)")
    Fi = ft.Field(-4)
    ch = ft.chain2(Fi, 16)
    print(f"  chains over 2: {ch}")
    check("C3 lambda((1 + i)^j), j = 1..8, is 1, 2, 4, 4, 4, 4, 4, 8",
          ch[0][1][:8] == [1, 2, 4, 4, 4, 4, 4, 8])
    print("CONTROL C1: the class minimum against the direct sill, b = 1.5")
    for D in (-7, 8, -8, 12, -20, 17):
        F = ft.Field(D)
        v, a, m, N = lstar(F, ft.chain2(F, 16), 1.5)
        L = direct_sill(F, 1.5)
        check(f"C1 D={D}: L* = L", abs(v / L - 1) < 1e-12,
              f"L* {v:.15f} at a={a} mod {N}, m={m}; L {L:.15f}")
    guard()
    print("P1: every fundamental D, |D| <= 400, with an F2 place")
    raised, n, bad_old = [], 0, []
    for D in range(-400, 401):
        if not fundamental(D) or D % 8 == 5:
            continue
        F = ft.Field(D)
        ch2 = ft.chain2(F, 16)
        n += 1
        v, a, m, N = lstar(F, ch2, 1.5)
        L = direct_sill(F, 1.5)
        s = old_hyp(F)
        m2 = any(mm == 2 for _, mm in classes(F)[1])
        if (s is None) != (not m2):
            bad_old.append(D)
        if abs(v / L - 1) > 1e-12:
            raised.append((D, v / L - 1, a, m, N, s))
    print(f"  {n} fields read; L* != L at {[r[0] for r in raised]}")
    for D, rel, a, m, N, s in raised:
        print(f"    D={D}: L*/L - 1 = {rel:.6f} at a={a} mod {N}, m={m}; "
              f"old hypothesis s = {s}")
    print(f"  fields where 'old hypothesis holds' differs from 'some class "
          f"has m = 2': {bad_old}")
    ent = entrants(Fi, ch, 4)
    print(f"  Q(i) at m = 4: entrants {ent}")
    p1 = [r[0] for r in raised] == [-4] and \
        sorted(ent) == [(2, 7), (5, 1), (5, 1)]
    print(f"  P1 {'holds' if p1 else 'FAILS'}")
    return Fi, ch


# --------------------------------------------- R: the reach, sampled

def column_sum(F, ch2, r, b, nmax=10 ** 10):
    """Sigma at a place of norm r (r split), entrants of norm <= nmax."""
    s = 1.0 / (1 - r ** -b)  # the conjugate over r, without bound
    divs = [1]
    for p, e in factor(r - 1).items():
        divs = [dd * p ** k for dd in divs for k in range(e + 1)]
    seen = set()
    for dlt in divs:
        n = dlt + 1
        while n <= nmax:
            if n not in seen:
                seen.add(n)
                s *= norm_factor(F, ch2, n, r, b)
            n = (n - 1) * r + 1
    return s


def norm_factor(F, ch2, n, r, b):
    if n == 2:
        f = 1.0
        for NR, ch in ch2:
            if NR != 2:
                continue
            j = 0
            while j < len(ch) and ft.fits(ch[j], r, r):
                j += 1
            assert j < len(ch)
            f *= sum(2.0 ** (-b * k) for k in range(j + 1))
        return f
    if n % 2 == 0:
        k = 0
        while n % 2 == 0:
            n //= 2
            k += 1
        if n != 1:
            return 1.0
        return math.prod(sum(NR ** (-b * t) for t in range(_depth(ch, r) + 1))
                         for NR, ch in ch2 if NR == 2 ** k)
    if is_prime_mr(n):
        p, NR = n, n
    else:
        q = math.isqrt(n)
        if q * q != n or not is_prime_mr(q):
            return 1.0
        p, NR = q, n
    if p == r:
        return 1.0
    k = F.kind(p)
    if (k == "inert") != (NR == p * p):
        return 1.0
    cnt = 2 if k == "split" else 1
    j = 1
    while ft.fits(ft.lam_formula(F, p, j + 1), r, r):
        j += 1
    x = NR ** -b
    return sum(x ** t for t in range(j + 1)) ** cnt


def _depth(ch, r):
    j = 0
    while j < len(ch) and ft.fits(ch[j], r, r):
        j += 1
    assert j < len(ch)
    return j


def long_chain(F, jmax=80):
    """The brute chains over 2 (to norm 2^13), extended by lambda(j) =
    2 lambda(j - e) past them (squaring U^j onto U^(j+e) for j > e)."""
    out = []
    for NR, ch in ft.chain2(F, 16):
        e = 1 if F.kind(2) == "split" else 2
        ch = list(ch)
        while len(ch) < jmax:
            ch.append(2 * ch[len(ch) - e])
        out.append((NR, ch))
    return out


def f2_point(D):
    F = ft.Field(D)
    ch2 = long_chain(F)
    men = ft.menu(F, (2, 2), ch2)
    b = ft.point(F, men)
    return F, ch2, b, ft.sigma(men, b)


def section_r():
    print("\n=== R: the reach, the columns at split r < 2*10^5")
    Fi, ch2, bi, sfi = f2_point(-4)
    Ls, a, m, N = lstar(Fi, ch2, bi)
    print(f"  Q(i): F2 point {bi:.6f}, sigma_F2 {sfi:.6f}, L* {Ls:.6f} "
          f"(a={a} mod {N}, m={m})")
    check("C2 Q(i): L* >= sigma_F2 at the F2 point", Ls >= sfi,
          f"{Ls / sfi - 1:+.5f}")
    guard()
    out = {}
    for D, cls, tag in ((-4, (5, 8), "best"), (-7, None, "best"),
                        (-7, (1, 8), "worse")):
        F, ch2, b, sf = f2_point(D)
        Lb, a, m, N = lstar(F, ch2, b)
        ref = Lb
        if cls is None:
            ok = (lambda r: r % 4 == 3)
        else:
            ok = (lambda r, c=cls: r % c[1] == c[0])
        rel, n, neg, big = [], 0, 0, []
        for r in range(3, 2 * 10 ** 5):
            if not is_prime_mr(r) or F.kind(r) != "split" or not ok(r):
                continue
            n += 1
            v = column_sum(F, ch2, r, b) / ref - 1
            rel.append((v, r))
            neg += v < -1e-12
            if r > m + 1:
                big.append((v, r))
        rel.sort()
        lo = rel[0]
        big.sort()
        lob = big[0]
        nbig = sum(v < -1e-12 for v, _ in big)
        extra = ""
        if tag == "worse":
            L8 = lval(entrants(F, ch2, 8), b)
            extra = f"; L(8)/L* - 1 = {L8 / ref - 1:.6f}"
            out["L8"] = L8 / ref - 1
        print(f"  D={D} {tag} class {cls or '3 mod 4'}: {n} columns, "
              f"{neg} below L*, least Sigma/L* - 1 = {lo[0]:.3e} at r={lo[1]}"
              f" (r - 1 = {dict(factor(lo[1] - 1))}){extra}")
        print(f"    over r > m + 1 = {m + 1}: {nbig} of {len(big)} below "
              f"L*, least "
              f"{lob[0]:.3e} at r={lob[1]} (r - 1 = {dict(factor(lob[1] - 1))})")
        out[(D, tag)] = (n, neg, lo[0])
    p2 = (out[(-4, "best")][1] == 0 and out[(-4, "best")][2] < 1e-4
          and out[(-7, "best")][1] == 0 and out[(-7, "best")][2] < 1e-4
          and out[(-7, "worse")][2] >= out["L8"] - 1e-12 > 0.01)
    print(f"  P2 {'holds' if p2 else 'FAILS'}")


# ------------------------------- I: type (1, 0) with Q(i) inside K

def l5(x):
    return -math.log1p(-x ** 5)


def h5(x):
    return 2 * se.lf(x) - l5(x) + math.log(x)


def bound_at(d, n5):
    """(M(x_c), n5, x_c) at n5 places of norm 5, the others maximal."""
    cnt = [n5] + se.counts(d)[1:]
    xc = brentq(lambda x: se.lf(x) + se.wlog(x, cnt) + math.log(x),
                1e-14, 0.5, xtol=1e-18, rtol=1e-15, maxiter=500)
    return h5(xc) + n5 * math.log1p(xc ** A5), n5, xc


def bound_i(d):
    """min over n5 = 0..d of M(x_c) at the worst other counts."""
    return min((bound_at(d, n5) for n5 in range(d + 1)),
               key=lambda r: r[0])


def qi_law(d, plant=False, no5=False):
    """K in Q(i), d = 2m: odd places below Y. 3 gives d/2 of norm 9;
    5, 17, 257, 65537 split completely (plant: residue degree m over
    each prime of Z[i]); every other p = 1 mod 4 residue degree m over
    each prime of Z[i], p = 3 mod 4 residue degree d."""
    m = d // 2
    W = [(math.log2(9), m, 1)]
    for n in (5, 17, 257, 65537):
        W.append((m * math.log2(n), 2, 0) if plant or (no5 and n == 5)
                 else (math.log2(n), d, 1))
    for p in ss.INERT:
        if p % 4 == 1:
            W.append((m * math.log2(p), 2, 0))
        else:
            W.append((d * math.log2(p), 1, 0))
    return ss.Law(d, W)


class QiLaw(tl.TypeLaw):
    """Type (1, 0) at 2, M = l - l5 - (w - w5) (old=True: typeloss's
    M = l - l3 - w, for the instrument control)."""

    def __init__(self, base, old=False):
        super().__init__(1, 0, [], base)
        self.old = old

    def w5(self, x):
        B = self.base
        sel = (B.k == 1) & (np.abs(B.a - A5) < 1e-12)
        return float((B.c[sel] * np.log1p(x ** B.a[sel])).sum())

    def m(self, x):
        if self.old:
            return super().m(x)
        return se.lf(x) - l5(x) - (self.w(x) - self.w5(x))

    def dm(self, x):
        if self.old:
            return super().dm(x)
        B = self.base
        sel = (B.k == 1) & (np.abs(B.a - A5) > 1e-12)
        aa = B.a[sel]
        dw = float((B.c[sel] * aa * x ** (aa - 1) / (1 + x ** aa)).sum())
        return 1 / (1 - x) - 5 * x ** 4 / (1 - x ** 5) - dw


def section_i(dmax=1000):
    print("\n=== I: type (1, 0), K in Q(i), even d")
    print("CONTROL C4: QiLaw with typeloss's sill and law")
    for d in (4, 8):
        a = QiLaw(ss.law(d, "E"), old=True).cert()
        b = tl.extremal(1, 0, d, "E").cert()
        dif = max(abs(u - v) for u, v in zip(a, b))
        check(f"C4 d={d}: the certificate is typeloss's", dif < 1e-12,
              f"{dif:.1e}, C {a[0]:+.6f}")
    print("CONTROL C6: the new M against its products, its derivative "
          "and bound_i")
    law = qi_law(20)
    q = QiLaw(law)
    x = 0.3
    b = -math.log2(x)
    lnum = math.log(sum(x ** k for k in range(5))) + 20 * math.log1p(5 ** -b)
    lden = sum(c * math.log1p(2 ** (-b * a)) for a, c, k in
               zip(law.a, law.c, law.k) if k == 1)
    e1 = abs(q.m(x) - (lnum - lden))
    hh = 1e-6
    e2 = abs(q.dm(x) - (q.m(x + hh) - q.m(x - hh)) / (2 * hh))
    rest = se.counts(20)[1:]
    e3 = 0.0
    for n5 in (0, 20):
        v, _, xc = bound_at(20, n5)
        W = [(e, c, 1) for e, c in zip(se.EXPS, [n5] + rest) if c]
        e3 = max(e3, abs(v - QiLaw(ss.Law(20, W, tail=False)).m(xc)))
    check("C6 M = log(L_i/sigma_F2), M' its derivative, bound_i = M(x_c)",
          e1 < 1e-12 and e2 < 1e-6 and e3 < 1e-12,
          f"{e1:.1e}, {e2:.1e}, {e3:.1e}")
    guard()
    rows = {}
    for d in range(4, dmax + 1, 2):
        C, dm, xl, xc = QiLaw(qi_law(d)).cert()
        rows[d] = [C, dm, xl, xc, None]
    for d in range(4, min(dmax, 200) + 1, 2):
        rows[d][4] = bound_i(d)
    pos = [d for d in rows if rows[d][4] is not None and rows[d][4][0] > 0]
    d_low = max(pos) if pos else None
    neg_b = [d for d in rows if rows[d][4] is not None and rows[d][4][0] <= 0]
    mono = all(d < min(neg_b) for d in pos) if neg_b else True
    cert = [d for d in rows if rows[d][0] < 0 and rows[d][1] < 0
            and rows[d][3] < 0.5]
    d_high = min(cert) if cert else None
    for d in sorted(rows):
        C, dm, xl, xc, bd = rows[d]
        if d <= 120 or d % 100 == 0:
            bs = (f"bound {bd[0]:+.6f} (n5 {bd[1]}, x_c {bd[2]:.5f})"
                  if bd else "")
            print(f"  d={d:4d}: certificate {C:+.6f} (M' {dm:+.3f}, x_low "
                  f"{xl:.5f}, x_c {xc:.5f})  {bs}")
    print(f"  bound positive at every even d <= {d_low}, monotone: {mono}")
    print(f"  least even d with a certificate (C < 0, M' < 0, x_c < 1/2): "
          f"{d_high}")
    tail = d_high is not None and all(d in cert for d in rows if d >= d_high)
    print(f"  every even d from {d_high} to {dmax} certified: {tail}")
    if d_high:
        C = QiLaw(qi_law(d_high, plant=True)).cert()[0]
        print(f"  the frozen C5 law (5, 17, 257, 65537 of residue degree m) "
              f"at d = {d_high}: certificate {C:+.6f}")
    print("  ARM B (added after the run): 5 of residue degree m over each "
          "prime of Z[i], n5 = 0, the bound's argmin")
    certb = []
    for d in range(4, dmax + 1, 2):
        C, dm, xl, xc = QiLaw(qi_law(d, no5=True)).cert()
        ok = C < 0 and dm < 0 and xc < 0.5
        if ok:
            certb.append(d)
        if d <= 30 or d % 100 == 0:
            bd = rows[d][4]
            print(f"  d={d:4d}: certificate B {C:+.6f} (M' {dm:+.3f}, x_low "
                  f"{xl:.5f}, x_c {xc:.5f})"
                  + (f"  bound {bd[0]:+.6f}" if bd else ""))
    db = min(certb) if certb else None
    clash = [d for d in pos if d in cert or d in certb]
    check("C5 no certificate (arm A or B) is negative where the bound is "
          "positive", not clash, f"bound positive at {min(pos)}..{max(pos)}")
    tb = db is not None and all(d in certb for d in range(db, dmax + 1, 2))
    print(f"  ARM B: least certified even d {db}; every even d from it to "
          f"{dmax} certified: {tb}; bound positive to {d_low}")
    p3 = (d_low is not None and d_high is not None and 30 <= d_low <= 100
          and 30 <= d_high <= 100 and tail)
    print(f"  P3 {'holds' if p3 else 'FAILS'}")


# ------------------------------- L: the loss from 930, a lemma

A9 = math.log2(9)
LY = 10 ** 5
LX0 = 1 / 7
LAM0 = math.log(7)
FERMAT = (17, 257, 65537)


def lemma_d0():
    return math.ceil(LAM0 * 7 ** A9)


def lemma_coeffs(x, h=0.5):
    """(c_z, c_s): lz <= c_z lam + E and s/x <= c_s lam + E/x at x, the
    norm-9 count h d (h = 1/2 at arm B, 1 at the plant)."""
    b = -math.log2(x)
    y = 9.0 ** -b
    tail = (9 / LY) ** b * (1 + LY / (b - 1)) / (1 - LY ** -b)
    cz = h / (1 - y) + sum((9 / n) ** b / (1 - n ** -b) for n in FERMAT) \
        + tail
    stail = (18 / LY) ** b * (1 + LY / (b - 1)) / (1 - LY ** -b)
    cs = h * x ** (A9 - 1) / (1 - y * y) \
        + sum((18 / n ** 2) ** b / (1 - n ** (-2 * b)) for n in FERMAT) \
        + stail
    return cz, cs


def lemma_e(m, x, log10=False):
    """E + E/x, E <= 4 5^(-m b)(1 + 5/(m b - 1)), kept as an upper bound
    (1e-300 where the float would underflow; log10=True: its exponent)."""
    b = -math.log2(x)
    lg = (math.log10(4) - m * b * math.log10(5)
          + math.log10(1 + 5 / (m * b - 1)) + math.log10(1 + 1 / x))
    if log10:
        return lg
    return max(10.0 ** lg, 1e-300) if lg > -300 else 1e-300


def lemma(h=0.5, x=LX0):
    """The lemma's bounds at x: g_up, M and M' at x1, and the slope."""
    lam = -math.log(x)
    y = 9.0 ** (math.log2(x))
    cz, cs = lemma_coeffs(x, h)
    E = lemma_e(lemma_d0() // 2, x)
    lx = -math.log1p(-x)
    return dict(cz=cz, cs=cs, E=E, slope=1 - cz - cs,
                G=lx - (1 - cz - cs) * lam + E,
                M=lx - h * lam * (1 - y / 2),
                Mp=1 / (1 - x) - A9 * h * lam / (x * (1 + y)))


def lemma_x1(d):
    return brentq(lambda x: d * x ** A9 + math.log(x), 1e-12, 0.5,
                  xtol=1e-18, rtol=1e-15, maxiter=500)


def section_l():
    print("\n=== L: arm B from 930, the lemma at x = 1/7")
    D0 = lemma_d0()
    L = lemma()
    print(f"  d0 = ceil(log 7 * 7^a9) = {D0} (log 7 * 7^a9 = "
          f"{LAM0 * 7 ** A9:.4f})")
    print(f"  c_z {L['cz']:.6f}, c_s {L['cs']:.6f}, 1 - c_z - c_s "
          f"{L['slope']:.6f}, E' <= {L['E']:.1e} (10^"
          f"{lemma_e(D0 // 2, LX0, log10=True):.2f})")
    print(f"  g_up <= {L['G']:+.6f}; M <= {L['M']:+.6f}; M' <= "
          f"{L['Mp']:+.4f}")
    P = lemma(h=1.0)
    check("C8 PLANT: d places of norm 9 (3 split completely) give g_up "
          ">= 0", P["G"] >= 0, f"c_z {P['cz']:.6f}, g_up <= {P['G']:+.6f}")
    d = 1000
    x = lemma_x1(d)
    lam = -math.log(x)
    lz, sw, w, lt = qi_law(d, no5=True).parts(x)
    E = lemma_e(d // 2, x)
    for tag, xx in (("1/7", LX0), ("x1", x)):
        cz, cs = lemma_coeffs(xx)
        check(f"C9 d = 1000, coefficients at {tag}: lz + lt <= c_z lam + "
              f"E, (lz - sw + lt)/x <= c_s lam + E/x",
              lz + lt <= cz * lam + E and (lz - sw + lt) / x <= cs * lam + E,
              f"{lz + lt:.6f} <= {cz * lam:.6f}; {(lz - sw + lt) / x:.3e} "
              f"<= {cs * lam:.3e}")
    bad, worst = [], None
    degs = range(D0 + D0 % 2, 1001, 2)
    for d in degs:
        q = QiLaw(qi_law(d, no5=True))
        C, dm, xl, xc = q.cert()
        x = lemma_x1(d)
        ok = (x <= LX0 and x <= xl and C <= q.m(x) <= L["M"]
              and q.g_up(x) <= L["G"] and q.dm(x) <= L["Mp"])
        if not ok:
            bad.append(d)
        row = (q.m(x), q.g_up(x), q.dm(x), d, x, xl, C)
        worst = row if worst is None or row[0] > worst[0] else worst
    m, g, dmx, d, x, xl, C = worst
    check(f"C7 at the {len(degs)} even d from {degs[0]} to 1000: x1 <= "
          f"1/7, x1 <= x_low, C <= M(x1) <= M bound, g_up(x1) and M'(x1) "
          f"below theirs", not bad, f"largest M(x1) {m:+.6f} at d = {d}, "
          f"x1 {x:.6f}, x_low {xl:.6f}, C {C:+.6f}, g_up(x1) {g:+.6f}, "
          f"M'(x1) {dmx:+.4f}")
    guard()
    p4 = 900 <= D0 <= 960
    p5 = L["G"] <= -0.40 and L["M"] <= -0.80 and L["Mp"] <= -20
    kill = (L["G"] >= 0 or L["M"] >= 0 or L["Mp"] >= 0 or D0 > 1000
            or L["slope"] <= 0)
    print(f"  P4 {'holds' if p4 else 'FAILS'}; P5 {'holds' if p5 else 'FAILS'}")
    print(f"  KILL {'fires' if kill else 'missed'}: arm B loses at every "
          f"even d >= {D0}")


def main():
    t0 = time.time()
    section_q()
    section_r()
    section_i()
    section_l()
    print(f"\n{sum(CHECKS)} of {len(CHECKS)} checks, "
          f"{time.time() - t0:.1f} s")
    return 0 if all(CHECKS) else 1


if __name__ == "__main__":
    sys.exit(main())