abfloor.py
Checks: THERMAL: The 2-power tower raises the sill theorem; rule.
Cited on: THERMAL.
To run it: save abfloor.py, with fieldtop.py, growth.py, memory.py, sillclass.py, spectrum.py, splitend.py, splitloss.py, splitsharp.py, tower.py, towerpast.py, typeloss.py beside it; needs mpmath, numpy, scipy.
"""abfloor.py -- the 2-power tower past Q(zeta_(2^k)): fields whose
largest abelian subfield F strictly contains C = Q(zeta_(2^k)).
QUESTION. Let K have 2 totally ramified (type (1, 0)), k >= 2 the
largest with C = Q(zeta_(2^k)) in K, F = K_ab strictly containing C,
f = 2^s f' its conductor (f' odd), N = lcm(4, f), H = G_N in G =
(Z/N)^*, m(a) as in the class-minimum theorem. (A) Does some a in H
have m(a) = 2^k, so L* = L(2^k) as at K_ab = C? (B) Does the Fermat
equivalence carry over to F, the Fermat primes past n_c = 2^k + 1
replaced by W_F, the norms n > n_c with n - 1 a power of 2 of places
of F? (C) Where W_F is empty or every m(a) exceeds 2^k, what then?
THE DERIVATION (by hand, before this code).
(A) Write G = (Z/2^s)^* x (Z/f')^*, U_j = {u = 1 mod 2^j}. 2 totally
ramified in K, so in F, puts the inertia group at 2, the image of
(Z/2^s)^* x 1, onto G/H: H maps onto (Z/f')^*. C in F gives H in
U_k x (Z/f')^*. K2 = {u : (u, 1) in H} is a subgroup of the cyclic
U_k/U_s, so K2 = U_t/U_s, k <= t <= s; t = k would give H = U_k x
(Z/f')^*, F = C; so t >= k + 1 (and s > k: at s = k, [F : Q] <=
2^(k-1) = [C : Q]). The fibre of H over v is a coset u_v K2, and v ->
u_v U_t is a homomorphism into the cyclic U_k/U_t; were its image in
U_(k+1)/U_t, Q(zeta_(2^(k+1))) would lie in F, against k largest. So
its preimage V0 of U_(k+1)/U_t has index 2, the kernel of a quadratic
character chi = prod chi_l of (Z/f')^*, chi_l trivial or the Legendre
symbol at each l | f', and every (u, v) in H with chi(v) = -1 has
v2(u - 1) = k exactly. Choose v by the Chinese remainder theorem: at
each l, v ≢ 1 mod l, a nonresidue where chi_l is Legendre; the sign is
(-1)^|S|, S = {l : chi_l nontrivial} nonempty; if |S| is even, S has
some l >= 5 (3 at most once), and a residue ≢ 1 mod l there (4) flips
it. So m((u, v)) = 2^k: YES at every such K, L* = L(2^k) (theorem).
Type (1, 0) is what carries it: without the onto map the odd parts can
cover H. At N = 120, H = {1, 89, 101, 109}: 109 = 1 mod 3, 101 = 1
mod 5, 89 = 1 mod 8, so m = 12, 20, 8, 120 and L* > L(4), F of degree
8 with Q(i) and neither Q(zeta_8), Q(zeta_3) nor Q(zeta_5) in it, 2
not totally ramified (H does not map onto (Z/15)^*).
(B) K strictly contains F, so d >= 2 [F : Q] > 2^(k-1) = D, e = d, and
the place over 2 is held to depth 2^k: L* = P_k S_c as at K_ab = C.
An odd place of K with n - 1 a power of 2 has n a prime or 9 = 3^2;
its place in F has norm n (F-norm 3 is not = 1 mod 4). So sigma_F2 =
S_c W(K) with W(K) over places of K above the places of W_F: where
W_F is empty, log(1 + margin) = log P_k > 0 at every degree, NO loss
(theorem). A Fermat prime p = F_m past n_c (2^m >= k + 1) is in W_F
when it splits completely in F (p ∤ N: p mod N in H) or ramifies with
residue degree 1. The twist by 3: F_k^(3), N = 3 2^(k+1), H = {(u, v)
: u in U_k, u in U_(k+1) iff v = 1 mod 3}, of degree 2^k, maps onto
(Z/3)^*, holds C and not Q(zeta_(2^(k+1))); every F_m, m >= 1, is 2
mod 3 (2^(2^m) = 1 mod 3), and 1 mod 2^(k+1) where 2^m >= k + 1, so (1, 2) is
its class, not in H: no Fermat prime past n_c has a place of norm p in
F_k^(3), 3 is ramified and not Fermat past n_c, and 9 is n_c at k = 3
and no norm from k = 4 (9 ≢ 1 mod 16). So at every k >= 3, every K of
type (1, 0) with K_ab = F_k^(3) has the F2 place topping all but
finitely many columns, at every degree, with no hypothesis on the
Fermat primes. At k = 2 the same twist, Q(i, sqrt 6), has 3 ramified
with residue degree 2 (inert in Q(i)): one place of norm 9, W_F =
{9} at weight 1/4; every F_m, m >= 2, has (6/F_m) = (3/F_m) = -1, so
that is all of W_F, unconditionally.
Where W_F is not empty, B its least norm, w_B the share of [F : Q]
places of F of norm B, the realization over F is K_ab = C's verbatim
with F for C (TRANSPLANT, re-derived): K = F[t]/g by the Chinese
remainder theorem and Krasner's lemma, the places of W_F split
completely in K, the others of residue degree m', at 2 an Eisenstein
extension of degree m', and three primes above Y giving a closure
over F of group S_(m'), m' >= 6, primitive and not abelian; for F'
abelian in K, F'F lies between F and K and is abelian over F, so F'F
= F and K_ab = F. The lemma (towerpast.lemma) carries w_B on B's
terms only (TRANSPLANT, re-derived from its coeffs): B's terms scale
as c w_B, the later norms' and the tail past Y as c, and every later
norm read at weight 1 bounds it from above (weights are at most 1).
So with no later norm and c w_B held, a lower w_B costs only d0 (and
Y). E' (places off W_F below Y) is at most (1 + 1/X) [F : Q] n_c^-s
(1 + n_c/(s - 1))/(1 - n_c^-s), s = m' b, m' = d0/[F : Q]. Two rows:
(i) k = 2, F = Q(i, sqrt 6), (B, w_B) = (9, 1/4), no later norm, at
(X, c, Y) = (1/7, 2, 10^5), so c w_B = 1/2 as in the K_ab = C row at
k = 2, whose later norms 17, 257, 65537 this row lacks: M and M' are
that row's -0.817, -20.37 (each reads B only through c w_B), g below
its -0.474 by about lam0 c (9/17)^b ~ 0.3 less the doubled tail past
Y (~10^-7); d0 = ceil(2 log 7 7^(log2 9)) about 1860, s ~ 1300, E'
negligible. (ii) k = 4..7, F = F_k^(257), the twist by the Legendre
symbol mod 257: 257 = 1 mod 2^(k+1), ramified in F with e = 2 and f =
1, so w_B = 1/2; 65537 = 2 mod 257, a residue, so 65537 splits
completely (weight 1), and the Fermat numbers past it read at weight
1: at (X, c, Y) = (0.381, 1, 257^10), c w_B = 1/2 as in the k >= 4
row, the later norms' terms doubled: c_z - c w_B ~ 0.00067, c_s ~
0.00058, so g ~ -0.0016, M ~ -0.0027, M' ~ -8.5 (all below 0); d0 ~
2186.
So (B) carries over with W_F for the Fermat primes past n_c: no loss
where W_F is empty (theorem); a loss at some degree wherever a lemma
row closes at (B, w_B), its later norms at weight 1. Rows with w_B
small and later norms at weight 1 can fail (c = c'/w_B multiplies
them), so the loss side is a theorem only at the rows read
(superseded: fweights.py closes it at every weight, X falling with
w_B; these rows stand as instances).
PREDICTIONS (frozen before the engine).
P1 Over every subgroup H of {a = 1 mod 4} in (Z/N)^*, N = 2^s f', s =
2..6, f' odd, phi(N) <= 128, whose fixed field has lcm(4, f) = N
and k >= 2: every H with 2 totally ramified (|I_2 H| = |G|, I_2 the
classes = 1 mod f') and F != C has min m(a) = 2^k; at least one H
without it has min m(a) > 2^k, N = 120's {1, 89, 101, 109} among
them; no H with 2 totally ramified has k = s.
P2 F_k^(3) at k = 2..15: conductor 3 2^(k+1), 2 totally ramified, k
largest, degree 2^k; F_m mod N not in H at every m = 1..12 with 2^m
>= k + 1; at k = 2 the place over 3 has residue degree 2 and e = 2;
at k >= 3 no place of F_k^(3) has norm in {17, 257, 65537} past n_c.
P3 Row (i): g, M, M' < 0 and E' < 10^-100; row (ii) at k = 4..7: g,
M, M' < 0 and E' < 10^-20; 257 ramified in F_k^(257) with e = 2, f
= 1, and 65537 mod N in H.
KILL (frozen): a subgroup H of P1 with 2 totally ramified, F != C and
min m(a) > 2^k (kills (A)); a Fermat prime among 17, 257, 65537 past
n_c, or any F_m of P2's range, in the class group H of some F_k^(3), k
>= 3 (kills the unconditional no-loss); row (i) or (ii) not closing
at its frozen constants (leaves the loss side over that F open, the
answer to (B) there "not shown").
CONTROLS (frozen).
C1 POSITIVE for P1: the N = 120 subgroup is found with min m = 8 > 4.
C2 m(a) and the enumerator at known fields: Q (N = 4, H = {1, 3}):
min m = 2; Q(i) (N = 4, H = {1}): 4; Q(zeta_8) (N = 8, H = {1}): 8,
2 totally ramified in both; Q(sqrt -7) (N = 28): 2 not totally
ramified (it splits).
C3 the lemma instrument: towerpast.lemma at the K_ab = C row k = 2,
(9, 1/2, (17, 257, 65537), 1/7, 1, 10^5), reproduces g, M, M' =
-0.474, -0.817, -20.37 to three places; and fails (g >= 0 or M >=
0) at X = 0.45, where 2 l(X) + log X > 0, at row (i)'s other
constants.
C4 the splitting reader: in Q(i) (N = 4, H = {1}), 5 splits (two
places of norm 5) and 3 has residue degree 2; in Q(zeta_8), 17
splits completely.
FINDINGS (entered after the run, from its printed output).
CONTROLS. C1: N = 120's H read, (min m, k, 2 totally ramified,
degree) = (8, 2, False, 8). C2: 2, 4, 8; True, True, False (Q(sqrt -7)
of conductor 7). C3: towerpast.lemma at the K_ab = C row k = 2 prints
g -0.475044, M -0.817785, M' -20.3776, sillclass.py's own print; the
row at X = 0.45 fails (g 74.25, M 0.214). C4: (1, 1, 2), (1, 2, 1),
(1, 1, 4).
P1 HOLDS: 85 moduli (every N = 0 mod 4 with phi(N) <= 128, s = 2..8),
643 fields holding Q(i), 52 with 2 totally ramified, 45 of them past
Q(zeta_(2^k)) (24 at k = 2, 12 at 3, 6 at 4, 2 at 5, 1 at 6); every
one of the 45 has some m(a) = 2^k; 223 fields without total
ramification and F != C have none (the first Q(zeta_12), N = 12, min
m 12); none of the 45 has k = s.
P2 HOLDS: F_k^(3) at k = 2..15 has degree 2^k, k read k, 2 totally
ramified, conductor 3 2^(k+1) (read to k = 9); no F_m, m = 1..12 with
2^m >= k + 1, in H; no norm 17, 257 or 65537 past n_c; 3 has e = 2
throughout and f = 2, 2, then 2^(k-2) from k = 4 (g = 1 at k = 2, 2
after), so at k = 2 one place of norm 9.
P3 HOLDS: row (i), Q(i, sqrt 6), w_9 = 1/4: d0 1859, c_z 0.501050,
c_s 0.007335, g -0.802489, M -0.817785, M' -20.3776, log10 E' <=
-910.45. Row (ii), F_k^(257) at k = 4..7, 257 with e = 2, f = 1, w_B
1/2, 65537 in H: d0 2186, c_z 0.500669, c_s 0.000585, g -0.001618, M
-0.002721, M' -8.5179 at each k, E' 5.87e-233, 6.08e-143, 3.47e-84,
2.05e-47.
KILL MISSED: over every K of type (1, 0), k largest, L* = L(2^k)
whatever K_ab is (theorem by (A); read at the 45 fields past
Q(zeta_(2^k)) with phi(N) <= 128); no loss at any degree where W_F is
empty, F_k^(3) such a field at every k >= 3 with no hypothesis on the
Fermat primes; a loss at some degree at Q(i, sqrt 6), W_F = {9} at
1/4, unconditionally, and at F_k^(257), k = 4..7, where 257 ramifies.
The Fermat equivalence carries over with W_F for the Fermat primes
past n_c wherever a lemma row closes at (B, w_B).
RUN RECORD. `python abfloor.py` under a 2048 MB cap: 9 of 9 checks, 0.1
s, peak commit 60.2 MB. The engine was appended in one write after the
frozen docstring and rehearsed at phi(N) <= 32 and 64. Changed from the
frozen text, named: C3's comparison is against sillclass.py's printed
-0.475044, -0.817785, -20.3776 (to six places), not the frozen -0.474,
a weaker upper bound; row
(i)'s E' is read in logs (the float underflows to 0, so its frozen
"E' < 10^-100" is read on log10 E' <= -910.45, the hand formula's
value). The subgroup enumerator was read against an independent one
(every <a, b, c>, the 2-ranks here at most 3) at N = 96, 120, 240,
252: 11, 27, 54, 30 subgroups, the same sets. Row (ii)'s later norms
stop at F_9 (a float past 2^1024 overflows); each dropped term is below
c (257/2^1024)^b < 10^-420 at b = log2(1/0.381), under every margin.
At review: the moduli had stopped at s = 6, missing N = 128, 256, 384
(P1 frozen at s = 2..6 and phi(N) <= 128 at once); they now run s =
2..8, checked against every N = 0 mod 4 with phi(N) <= 128 (phi(N) >=
sqrt(N/2) bounds the search), and N = 384 adds the 45th field. A
scratch copy at s = 2..6 prints "[FAIL] the moduli are every N = 0 mod
4 with phi(N) <= PHI_MAX (82 against 85)". The derivation's "(Pepin's)"
is restated as the arithmetic it is, 2^(2^m) = 1 mod 3.
"""
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 towerpast as tp # noqa: E402
CHECKS = []
PHI_MAX = 128
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)
# ------------------------------------------------------------ arithmetic
def factor(n):
out, p = {}, 2
while p * p <= n:
while n % p == 0:
out[p] = out.get(p, 0) + 1
n //= p
p += 1
if n > 1:
out[n] = out.get(n, 0) + 1
return out
def phi(n):
r = n
for p in factor(n):
r = r // p * (p - 1)
return r
def vp(n, p):
v = 0
while n % p == 0:
n //= p
v += 1
return v
def m_of(a, N):
"""m(a) = prod l^min(v_l(a - 1), v_l(N)) over l | N."""
r = 1
for l, e in factor(N).items():
t = (a - 1) % (l ** e)
r *= l ** (e if t == 0 else min(vp(t, l), e))
return r
def units(N):
return [a for a in range(1, N) if math.gcd(a, N) == 1]
def conductor(H, N):
"""The least M | N with every unit = 1 mod M in H."""
for M in sorted(d for d in range(1, N + 1) if N % d == 0):
if all(a in H for a in range(1, N, M) if math.gcd(a, N) == 1):
return M
return N
def two_split(N):
s = vp(N, 2)
return s, N >> s
def k_of(H, N):
s, _ = two_split(N)
mod = 1 << s
best = s
for h in H:
t = (h - 1) % mod
best = min(best, s if t == 0 else vp(t, 2))
return best
def totally_ramified_2(H, N, G):
"""|I_2 H| = |G|, I_2 the classes = 1 mod the odd part of N."""
_, fo = two_split(N)
I2 = [a for a in G if a % fo == 1 % fo]
inter = sum(1 for a in I2 if a in H)
return len(I2) * len(H) // inter == len(G)
def crt(r1, m1, r2, m2):
return (r1 + m1 * ((r2 - r1) * pow(m1, -1, m2) % m2)) % (m1 * m2)
def splitting(p, H, N, deg):
"""(e, f, g) of p in the fixed field of H in Q(zeta_N)."""
if N % p:
a, e, HI = p % N, 1, H
else:
ep = vp(N, p)
q = p ** ep
Np = N // q
I = {crt(1, Np, t, q) for t in range(q) if t % p}
e = len(I) // len(I & H)
HI = {h * i % N for h in H for i in I}
a = crt(p % Np, Np, 1, q)
f, x = 1, a
while x not in HI:
x, f = x * a % N, f + 1
return e, f, deg // (e * f)
# ------------------------------------------------------- the enumeration
def subgroups(Gp, N):
"""Every subgroup of the abelian group Gp (a list of units mod N):
the cyclic ones, closed under the join S<g> = union of S g^i."""
one = frozenset([1])
gens = []
seen = set()
for g in Gp:
S, x = {1}, g
while x not in S:
S.add(x)
x = x * g % N
S = frozenset(S)
if S not in seen:
seen.add(S)
gens.append(g)
subs = {one} | seen
frontier = list(subs)
while frontier:
new = []
for S in frontier:
for g in gens:
if g in S:
continue
J, x = set(S), g
while x not in S:
J |= {s * x % N for s in S}
x = x * g % N
J = frozenset(J)
if J not in subs:
subs.add(J)
new.append(J)
frontier = new
return subs
def moduli():
out = []
for s in range(2, 9):
for fo in range(1, 400, 2):
N = (1 << s) * fo
if phi(N) <= PHI_MAX:
out.append(N)
return out
def part_a():
print(f"\n=== (A) every K_ab holding Q(i), N = 2^s f', s = 2..8, "
f"phi(N) <= {PHI_MAX}")
t0 = time.time()
read = tr = trF = 0
bad_tr, bad_other, ks_eq_s, by_k = [], [], [], {}
found120 = None
Ns = moduli()
# every N = 0 mod 4 with phi(N) <= PHI_MAX, phi(N) >= sqrt(N/2)
every = [N for N in range(4, 2 * PHI_MAX ** 2 + 1, 4)
if phi(N) <= PHI_MAX]
check("the moduli are every N = 0 mod 4 with phi(N) <= PHI_MAX",
sorted(Ns) == every, f"{len(Ns)} against {len(every)}")
for N in Ns:
G = units(N)
Gp = [a for a in G if a % 4 == 1]
s, _ = two_split(N)
for H in subgroups(Gp, N):
f = conductor(H, N)
if math.lcm(4, f) != N:
continue
k = k_of(H, N)
read += 1
deg = len(G) // len(H)
mmin = min(m_of(h, N) for h in H)
ram = totally_ramified_2(H, N, G)
isC = deg == 1 << (k - 1)
if N == 120 and H == {1, 89, 101, 109}:
found120 = (mmin, k, ram, deg)
if ram:
tr += 1
if k == s and not isC:
ks_eq_s.append((N, sorted(H)))
if not isC:
trF += 1
by_k[k] = by_k.get(k, 0) + 1
if mmin != 1 << k:
bad_tr.append((N, sorted(H)[:6], mmin, k))
elif not isC and mmin != 1 << k:
bad_other.append((N, mmin, k, deg))
print(f" {len(Ns)} moduli, {read} fields holding Q(i) read, {tr} with "
f"2 totally ramified, {trF} of them past Q(zeta_(2^k)) (by k: "
f"{dict(sorted(by_k.items()))}), {time.time() - t0:.1f} s")
print(f" 2 totally ramified, F != C, min m(a) != 2^k: {len(bad_tr)} "
f"{bad_tr[:4]}")
print(f" 2 not totally ramified, F != C, min m(a) > 2^k: "
f"{len(bad_other)}, first {bad_other[:4]}")
print(f" N = 120, H = {{1, 89, 101, 109}}: (min m, k, 2 tot. ram., "
f"degree) = {found120}")
check("C1 POSITIVE: N = 120's H is read, min m = 8 > 4, 2 not totally "
"ramified", found120 == (8, 2, False, 8))
check("P1 every F past Q(zeta_(2^k)) with 2 totally ramified has some "
"m(a) = 2^k; some F without it has none; none has k = s",
not bad_tr and bad_other and not ks_eq_s and trF > 0)
# ------------------------------------------------------------ the twists
def twist(k, q):
"""F_k^(q): H = {(u, v): u in U_k, u in U_(k+1) iff (v/q) = 1}."""
N = q << (k + 1)
m2 = 1 << (k + 1)
res = {pow(t, 2, q) for t in range(1, q)}
H = set()
for v in range(1, q):
u = 1 if v in res else 1 + (1 << k)
H.add(crt(u, m2, v, q))
return N, H
def fermat(m):
return (1 << (1 << m)) + 1
def part_b():
print("\n=== (B) the twist by 3, k = 2..15")
ok = True
for k in range(2, 16):
N, H = twist(k, 3)
G_order = phi(N)
deg = G_order // len(H)
kk = k_of(H, N)
I2 = [crt(u, 1 << (k + 1), 1, 3) for u in range(1, 1 << (k + 1), 2)]
inter = sum(1 for a in I2 if a in H)
ram = len(I2) * len(H) // inter == G_order
f = conductor(H, N) if k <= 9 else None
hits = [m for m in range(1, 13) if (1 << m) >= k + 1
and fermat(m) % N in H]
nc = (1 << k) + 1
norm_hits = []
for p in (17, 257, 65537):
if p > nc and splitting(p, H, N, deg)[1] == 1:
norm_hits.append(p)
e3, f3, g3 = splitting(3, H, N, deg)
print(f" k = {k}: N {N}, degree {deg}, k read {kk}, 2 tot. ram. "
f"{ram}, conductor {f if f else '(read to k = 9)'}; F_m in H "
f"at {hits}; norms 17, 257, 65537 past n_c held {norm_hits}; "
f"3: e {e3}, f {f3}, g {g3}")
good = (deg == 1 << k and kk == k and ram and not hits
and (f is None or f == N))
if k >= 3:
good &= not norm_hits
else:
good &= (e3, f3) == (2, 2)
ok &= good
check("P2 F_k^(3): degree 2^k, k largest, 2 totally ramified, no F_m "
"(m <= 12) in H, no norm 17, 257, 65537 past n_c from k = 3; at "
"k = 2, 3 has e = f = 2", ok)
# --------------------------------------------------------- the lemma rows
def e_off(DF, nc, d0, X):
"""E' + E'/x: at most DF places per p off W_F, norms distinct prime
powers >= nc^m', m' >= d0/DF; 1/x <= 1/X is safe since each term's
(2/q)^b falls in b, as towerpast.e3."""
s = (d0 / DF) * -math.log2(X)
return (1 + 1 / X) * DF * nc ** -s * (1 + nc / (s - 1)) / (1 - nc ** -s)
def show(tag, L):
print(f" {tag}: d0 {L['d0']}, c_z {L['cz']:.6f}, c_s {L['cs']:.6f}, "
f"g {L['G']:.6f}, M {L['M']:.6f}, M' {L['Mp']:.4f}, E' "
f"{L['E']:.3g}")
def closes(L):
return L["G"] < 0 and L["M"] < 0 and L["Mp"] < 0
def controls():
print("=== CONTROLS")
a9 = math.log2(9)
L = tp.lemma(1 / 7, 1.0, 0.5, a9, 9, (17, 257, 65537), 1e5, 0.0)
show("C3 the K_ab = C row at k = 2", L)
check("C3 towerpast.lemma reproduces sillclass's -0.475044, -0.817785, "
"-20.3776", f"{L['G']:.6f} {L['M']:.6f} {L['Mp']:.4f}"
== "-0.475044 -0.817785 -20.3776")
Lf = tp.lemma(0.45, 2.0, 0.25, a9, 9, (), 1e5, 0.0)
show("C3 row (i) at X = 0.45", Lf)
check("C3 POSITIVE: row (i) fails at X = 0.45", not closes(Lf))
m_q = min(m_of(a, 4) for a in (1, 3))
m_i, m_8 = m_of(1, 4), m_of(1, 8)
tr_i = totally_ramified_2({1}, 4, units(4))
tr_8 = totally_ramified_2({1}, 8, units(8))
H7 = {a for a in units(28) if pow(a, 3, 7) == 1}
tr_7 = totally_ramified_2(H7, 28, units(28))
check("C2 min m at Q, Q(i), Q(zeta_8) = 2, 4, 8; 2 totally ramified in "
"Q(i), Q(zeta_8), not in Q(sqrt -7)",
(m_q, m_i, m_8, tr_i, tr_8, tr_7) == (2, 4, 8, True, True, False),
f"{m_q}, {m_i}, {m_8}; {tr_i}, {tr_8}, {tr_7}; Q(sqrt -7)'s "
f"conductor {conductor(H7, 28)}")
s5, s3 = splitting(5, {1}, 4, 2), splitting(3, {1}, 4, 2)
s17 = splitting(17, {1}, 8, 4)
check("C4 Q(i): 5 splits, 3 has f = 2; Q(zeta_8): 17 splits completely",
s5 == (1, 1, 2) and s3 == (1, 2, 1) and s17 == (1, 1, 4),
f"{s5}, {s3}, {s17}")
guard()
def part_c():
print("\n=== (C) the loss rows over F")
a9 = math.log2(9)
N, H = twist(2, 3)
e3, f3, g3 = splitting(3, H, N, 4)
w9 = g3 / 4
L = tp.lemma(1 / 7, 2.0, w9, a9, 9, (), 1e5, 0.0)
L = tp.lemma(1 / 7, 2.0, w9, a9, 9, (), 1e5, e_off(4, 5, L["d0"], 1 / 7))
show(f"(i) Q(i, sqrt 6), (9, {w9})", L)
s = (L["d0"] / 4) * math.log2(7)
lgE = math.log10(8 * 4 * (1 + 5 / (s - 1))) - s * math.log10(5)
print(f" (i) E' in logs (the float reads 0, an underflow): log10 E' <= "
f"{lgE:.2f}")
ok_i = closes(L) and lgE < -100 and w9 == 0.25
ok_ii = True
a257 = math.log2(257)
later = (65537,) + tuple(fermat(m) for m in range(5, 10))
for k in range(4, 8):
N, H = twist(k, 257)
deg = phi(N) // len(H)
e, f, g = splitting(257, H, N, deg)
sp = 65537 % N in H
wB = g / deg
X = 0.381
L = tp.lemma(X, 1.0, wB, a257, 257, later, 257.0 ** 10, 0.0)
L = tp.lemma(X, 1.0, wB, a257, 257, later, 257.0 ** 10,
e_off(deg, (1 << k) + 1, L["d0"], X))
show(f"(ii) k = {k}, F_k^(257), degree {deg}, 257: e {e}, f {f}, "
f"w_B {wB}; 65537 in H {sp}", L)
ok_ii &= closes(L) and L["E"] < 1e-20 and (e, f) == (2, 1) and sp
check("P3 row (i) closes, E' < 1e-100; row (ii) closes at k = 4..7, "
"E' < 1e-20, 257 with e = 2, f = 1, 65537 in H", ok_i and ok_ii)
return ok_i and ok_ii
def main():
t0 = time.time()
controls()
part_a()
part_b()
rows = part_c()
if all(CHECKS):
print(" KILL MISSED: (A) holds at every field read, F_k^(3) holds "
"no norm of W past n_c, and both loss rows close")
elif not rows:
print(" a loss row did not close: the loss side over that F is "
"not shown")
print(f"\n{sum(CHECKS)} of {len(CHECKS)} checks, {time.time() - t0:.1f} s")
return 0 if all(CHECKS) else 1
if __name__ == "__main__":
sys.exit(main())