tower.py
Checks: THERMAL: The 2-power tower raises the sill theorem; rule.
Cited on: THERMAL.
To run it: save tower.py, with fieldtop.py, growth.py, memory.py, sillclass.py, spectrum.py, splitend.py, splitloss.py, splitsharp.py, typeloss.py beside it; needs mpmath, numpy, scipy.
"""tower.py -- the sill's 2-power tower: with Q(zeta_(2^k)) in K, K_ab =
Q(zeta_(2^k)), 2 totally ramified (type (1, 0)), does the F2 place
lose, and from which degree; and, beside it, Q(i) in K at d = 12 with
the law's algebras fixed to Y = 10^8.
QUESTION. At k = 3 (Q(zeta_8) in K, d = 0 mod 4), where is the bound
positive (no field loses), and from which d does a field that loses
exist? Is there one formula in k? At k = 2, d = 12: does a field lose?
THE DERIVATION (by hand, before this code). Let C_k = Q(zeta_(2^k)), of
degree D = 2^(k-1), k >= 2, inside K, of degree d = D m', K_ab = C_k.
(1) The class. f(K_ab) = 2^k, N = lcm(4, 2^k) = 2^k, G_N = {1}, m(1)
= 2^k: L* = L(2^k) (sillclass's class minimum).
(2) The odd places. Every odd residue field holds zeta_(2^k), so every
odd norm is 1 mod 2^k. An odd R counts in L(2^k) iff N(R) - 1 | 2^k,
so N(R) = 2^k + 1 =: n_c, which must be a prime power: a Fermat prime
(k = 2, 4, 8, 16; none known past) or 9 (k = 3, Mihailescu); not at k = 5
(33). Depth 1: lambda(R^2) = (n_c - 1) p, p odd, does not divide 2^k.
The F2 column holds the odd places with N - 1 a power of 2 once (the
losses section's proof): here the Fermat norms n_c and above.
(3) The place over 2, e = d, residue F2. For v(z) = j >= 1, (1 +
z)^2 - 1 = 2z + z^2 has valuation 2j while 2j < e + j, i.e. j < e:
the valuations of (1 + pi)^(2^s) - 1 run 1, 2, 4, ..., 2^s while
2^(s-1) < e. Every 1-unit u has v(u^(2^s) - 1) >= min(2^s, ...) >=
2^s by the same step. So lambda(P^j) = 2^ceil(log2 j) for j <= 2^k
when 2^(k-1) < e, and lambda(P^(2^k + 1)) = 2^(k+1): the place over 2
is held to depth exactly 2^k. e = d > 2^(k-1) = D excludes K = C_k
only (d = D m', m' >= 2).
(4) So L(2^k) = P_k S_c, P_k = 1 + x + ... + x^(2^k) = (1 -
x^(2^k+1))/(1 - x), S_c over the places of norm n_c; sigma_F2 = S_c
W_k, W_k over the Fermat norms above n_c; log(1 + margin) = M = l -
l_c - w_k, l_c = log(1/(1 - x^(2^k + 1))). (At k = 2: l5, W_2 the
norms 9, 17, 257, 65537: sillclass's QiLaw.) The places of norm n_c
cancel in M.
(5) The bound. (1 - x)M' = 1 - (2^k + 1)x^(2^k)/P_k - the W_k terms;
x^(2^k)/P_k increases on (0, 1) (the k = 2 algebra: x^(q-1) P_k' <
(q - 1) x^(q-2) P_k termwise), the W_k terms increase on (0, 1/2]
(D(x, a) > 0 at a >= log2 9), so M rises, then falls once, on [0,
x_c], x_c <= 1/2 the root of l + w + log x = 0, w = w_c + w_k. At
x_c, M = h_c(x_c) + n_c-count log(1 + n_c^-b), h_c = 2 l - l_c + log
x, increasing ((2^k + 1) x^(2^k) <= P_k). At a fixed count of n_c both
terms rise with x_c, which falls with the other counts, so the bound
takes those maximal (d each: a Fermat prime above n_c is 1 mod 2^k,
split completely in C_k) and scans the count of n_c from 0 to its cap:
d, but d/2 at k = 3 (3 has two primes of norm 9 in Z[zeta_8], each
with at most m' places of degree 1 over it).
(6) The certificate's law (arm Z, the TRANSPLANT from Q(i), where the
bound's argmin had no place of the cancelling norm): over the primes
of Z[zeta_(2^k)] below Y = 10^5, the Fermat norms above n_c split
completely; every other prime of Z[zeta_(2^k)] of residue degree m'
over each prime above it (a rational p of order f mod 2^k gives D/f
places of norm p^(f m')), n_c among them; at 2, Q_2(zeta_(2^k))(pi^
(1/m')), e = d; three primes of C_k above Y for S_(m') at m' >= 3,
and at m' = 2 one prime split and a conjugate inert, so K is not
Galois over Q; either way K_ab = C_k (an abelian subfield F gives F
C_k between C_k and K, abelian over Q, so C_k). Its certificate is
splitsharp's: M at x_low, the root of the increasing bound g_up on the
point's equation, with M' < 0 there and x_c < 1/2.
(7) Hand sizes. h_c(x) = 0 near x = (3 - sqrt 5)/2 = 0.382 (2 l + log
x = 0 at (1 - x)^2 = x, l_c ~ x^9 a shift of 3e-5). At the count 0,
x_c >= 0.382 iff w_k(0.382) <= l(0.382) = 0.48121: per unit of d,
w_3(0.382) = 0.019832 (17: 0.01938; 257: 4.5e-4), so d <= 24.26 at k
= 3; w_4(0.382) = 4.513e-4 (257, 65537), d <= 1066 at k = 4.
PREDICTIONS (frozen before the engine).
P1 at k = 3 the bound's argmin over the count of 9 is 0 at every d
scanned (d = 8..200, d = 0 mod 4).
P2 at k = 3 the bound is positive at every d = 0 mod 4 from 8 to 24
and at most 0 at every one from 28 to 200.
P3 at k = 3 the arm-Z certificate (C < 0, M' < 0, x_c < 1/2) holds
at every d = 0 mod 4 from a least D3 in {28, 32, 36} to 1000, and
at no d where the bound is positive.
P4 at k = 4 (d = 0 mod 8, from 16) the bound at count 0 is positive
at every d to 1064 and at most 0 from 1072 to 1200; the arm-Z
certificate holds from a least D4 in [1072, 1200] to 1600.
P5 at k = 2, d = 12, arm B with its algebras fixed to Y = 10^8 (the
places between 10^5 and Y of norm p^6 or p^12, bounded): the
certificate is in [-0.009, -0.006], M' < 0, x_c < 1/2, so a field
containing Q(i) loses at d = 12. (A rough probe that dropped those
places printed -0.0073 at 10^8, +0.0020 at 10^7.)
KILL of the tower reading: P2's band missed by more than one step of
4 at either end, or P3 failing (a d past D3 to 1000 uncertified).
CONTROLS (frozen).
C1 POSITIVE: the engine at k = 2 reproduces sillclass.bound_i(d) at d
= 4, 12, 20, 100 and QiLaw(qi_law(d, no5=True)).cert() at d = 12,
14, 100, 1000, each to 1e-12.
C2 the chain over 2 by brute force (U^1/U^j generated by 1 + t^i, i
< j, its exponent the largest of their orders) in Z_2[t]/(t^e - 2):
at e = 8 and 12, lambda(P^j) | 8 exactly for j <= 8 (1, 2, 4, 4, 8,
8, 8, 8, then 16); at e = 16, | 16 exactly for j <= 16. At K = C_3
itself (e = 4, pi = 1 - zeta_8) the chain is printed, an
observation.
C3 the new M against its products at k = 3, d = 24, x = 0.3 (to
1e-12), its derivative against a central difference (1e-6), and
the bound at counts 0 and d/2 against M(x_c) on the law of exactly
those counts (1e-12).
C4 (P5's own control; its first half by construction, BigLaw.mid
being 0 at Y = 10^5, so it reads the wiring) the Y = 10^8 law at
Y = 10^5 reproduces arm B's
certificate +0.041683 at d = 12 (1e-12), and its bound on the
places between 10^5 and 10^6 is at least their brute sum at x_low.
C5 (added after the run with BigLaw's D, ARM Y's own control; its
first half by construction, as C4's) the Y law at k = 3, D =
4: at Y = 10^5 it is arm Z to 1e-12, and at d = 28 its bound on the
places between 10^5 and 10^6 is at least their brute sum at x_low.
FINDINGS (entered after the run, from its printed output).
CONTROLS. C1: difference 0.0 on the bound and the certificate. C2: e =
8 and 12 read 1, 2, 4, 4, 8, 8, 8, 8, 16; e = 16 reads 2^ceil(log2 j)
through 32 at j = 17; Z_2 reads 1, 2, 2, 4, 8, 16. At K = Q(zeta_8)
itself (e = 4, outside the derivation's e > 4) the chain reads 1, 2,
4, 4, 8 at j = 5..14, then 16: 8 held to depth 14, an observation. C3:
0.0, 1.7e-11, 6.7e-16. C4: 0.0; 3.053e-39 >= 1.289e-40. C5: 0.0;
5.686e-46 >= 1.174e-47.
P1 HOLDS: the bound's argmin over the count of 9 is 0 at every d = 8..
200 at k = 3. P2 HOLDS: positive at 8..24 (+0.299509 at 8, +0.003126
at 24), at most 0 from 28 (-0.043153) to 1000 (-1.164273, count 0
past 200). P3 HOLDS: the arm-Z certificate at Y = 10^5 is negative
with M' < 0, x_c < 1/2 at every d = 0 mod 4 from D3 = 36 (-0.013356)
to 1000 (-1.156163), positive at 28 (+0.061523) and 32 (+0.022713),
and nowhere the bound is positive.
P4 FAILS as frozen. Its bound half holds: at count 0 the bound is
positive at every d = 0 mod 8 to 1064 (+0.000656) and at most 0 from
1072 (-0.000818) to 1200; with the full scan (run to 1080, past the
first run's 200), positive at 16..1064, its argmin n = d at every
printed d to 200 and 0 at every printed d from 400 to 1080. The
certificate half fails: at Y = 10^5 no certificate is negative to 1600
(+0.286780 at 1072, +0.259753 at 1600, x_low near 0.30 against x_c
near 0.38): the tail allowance past Y prints 0.3024 at d = 1600 (x_low
0.29368, b 1.768), the hand sizes having priced w_k and not the
tail.
P5 HOLDS: at Y = 10^8 the d = 12 certificate is -0.007295 (M' -2.970,
x_c 0.37817); +0.041683, +0.017877, +0.002006 at 10^5, 10^6, 10^7,
-0.012014 at 10^9. So a field containing Q(i), type (1, 0), loses at
d = 12.
KILL MISSED.
ARM Y (added after the run, the P4 failure's design variable): the
arm-Z algebras fixed to Y = 10^30, the places between 10^5 and Y
bounded (C5), the certificate negative with M' < 0 and x_c < 1/2 at
every degree read from the bound's first degree at most 0 (at k = 2
sillclass's bound_i, -0.029970 at 12, +0.027465 at 10; x_c < 1/2
holds by the bracket, brentq raising otherwise): k = 2,
every even d from 12 (-0.015555) to 1000 (-1.537829); k = 3, every d
= 0 mod 4 from 28 (-0.033743) to 1000 (-1.156851), +0.011781 at 24;
k = 4, every d = 0 mod 8 from 1072 (-0.000483) to 2000 (-0.123796),
+0.000991 at 1064. So at each k read the losing degrees are exactly
those where the bound is at most 0: with Q(zeta_(2^k)) in K, K_ab =
Q(zeta_(2^k)), type (1, 0), excluding K = Q(zeta_(2^k)) itself (e =
2^(k - 1), outside the depth step), no field loses at d < D(k) and
one loses
at each d from D(k) to the read's end, D(2) = 12 (to 1000, and every
even d past 928 by sillclass's lemma), D(3) = 28 (to 1000), D(4) =
1072 (to 2000). D(k) is the first d = 0 mod D past d* =
l(x0)/u_k(x0), x0 = (3 - sqrt 5)/2, u_k the W_k terms of w per unit
of d (9 at weight 1/2 at k = 2): d* = 11.20, 24.27, 1067.55 (arm_y's
print, added after the run; (7) gave 24.26 and 1066 from rounded
terms), read at three k, a pattern. The bound at count 0 turns where
x_c crosses h_c's root, x0 shifted by l_c, and x_c = x0 where d u_k(x0)
= l(x0): the pattern's content is that neither the shift nor the scan
over the count of n_c moves the turn across an admissible degree, and
that the certificate turns there too.
RUN RECORD. `python tower.py` under a 2048 MB cap: 6 of 6 checks, 6.7
s, peak commit 62.4 MB. The first run (5 of 5 checks, 2.1 s, 61.9 MB)
had k = 4's full scan to 200 and no ARM Y; P1-P5 and the kill read the
same in both. At review: the tail print added, ARM Y's k = 2 start
computed from bound_i (it was 12 by hand), dead names cut; every other
line printed as before, 6 of 6 checks, 6.9 s, 62.9 MB. The engine's
first draft set t = 0 in the e = 1 brute (fixed before any control
read, the Z_2 row added as its check). Moved in from the lab with two
references rewritten and the d* print added (dstar, read in arm_y); every
other line printed as before, 6 of 6 checks, 6.9 s.
"""
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 sillclass as sc # noqa: E402
import splitend as se # noqa: E402
import splitloss as sl # noqa: E402
import splitsharp as ss # noqa: E402
import typeloss as tl # noqa: E402
CHECKS = []
Y = ss.Y
YBIG = 10 ** 30
PR_Y = [int(p) for p in ss.PR_Y.tolist() if p > 2]
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)
# ------------------------------------------------------------- the tower
def nc(k):
return 2 ** k + 1
def wk(k):
"""The F2 column's norms above n_c, 1 mod 2^k (Fermat numbers counted
as prime, a bound, as splitend's NORMS)."""
return [n for n in se.NORMS if n > nc(k) and (n - 1) % 2 ** k == 0]
def caps(k, d):
"""The worst counts: the norms of W_k and the cap on n_c's."""
w = [(n, d // 2 if n == 9 else d) for n in wk(k)]
return w, (d // 2 if k == 3 else d)
def lc(k, x):
return -math.log1p(-x ** nc(k))
def hc(k, x):
return 2 * se.lf(x) - lc(k, x) + math.log(x)
def bound_at(k, d, n):
"""(M(x_c), n, x_c) at n places of norm n_c, the others maximal."""
w, _ = caps(k, d)
pairs = [(math.log2(m), c) for m, c in w] + [(math.log2(nc(k)), n)]
def g(x):
lx = math.log(x)
return (se.lf(x) + lx + sum(c * math.log1p(math.exp(a * lx))
for a, c in pairs if c))
xc = brentq(g, 1e-14, 0.5, xtol=1e-18, rtol=1e-15, maxiter=500)
return hc(k, xc) + n * math.log1p(xc ** math.log2(nc(k))), n, xc
def bound(k, d, full=True):
if not full:
return bound_at(k, d, 0)
return min((bound_at(k, d, n) for n in range(caps(k, d)[1] + 1)),
key=lambda r: r[0])
def order_mod(p, q):
f, r = 1, p % q
while r != 1:
r = r * p % q
f += 1
return f
def law(k, d):
"""Arm Z: over the primes of Z[zeta_(2^k)] below Y, those of norm in
W_k split completely, every other of residue degree m' = d/D."""
D = 2 ** (k - 1)
mp = d // D
W = set(wk(k))
out = []
for p in PR_Y:
f = order_mod(p, 2 ** k)
q = p ** f
if q in W:
out.append((math.log2(q), d // f, 1))
else:
out.append((f * mp * math.log2(p), D // f, 0))
return ss.Law(d, out)
class TowerLaw(tl.TypeLaw):
"""Type (1, 0), M = l - l_c - (w - w_c)."""
def __init__(self, k, base):
super().__init__(1, 0, [], base)
self.k = k
self.ac = math.log2(nc(k))
def wc(self, x):
B = self.base
sel = (B.k == 1) & (np.abs(B.a - self.ac) < 1e-12)
return float((B.c[sel] * np.log1p(x ** B.a[sel])).sum())
def m(self, x):
return se.lf(x) - lc(self.k, x) - (self.w(x) - self.wc(x))
def dm(self, x):
B = self.base
sel = (B.k == 1) & (np.abs(B.a - self.ac) > 1e-12)
aa = B.a[sel]
dw = float((B.c[sel] * aa * x ** (aa - 1) / (1 + x ** aa)).sum())
q = nc(self.k)
return 1 / (1 - x) - q * x ** (q - 1) / (1 - x ** q) - dw
def certify(k, d):
C, dm, xl, xc = TowerLaw(k, law(k, d)).cert()
return C, dm, xl, xc, (C < 0 and dm < 0 and xc < 0.5)
# ------------------------------------------------------- the chain over 2
def chain(E, jmax):
"""lambda(P^j), j = 1..jmax, in Z_2[t]/(E), E Eisenstein given by its
lower coefficients (t^e = -sum E_i t^i): the exponent of U^1/U^j,
generated by 1 + t^i, i < j."""
e = len(E)
def mul(a, b, mod):
r = [0] * (2 * e)
for i, ai in enumerate(a):
if ai:
for j, bj in enumerate(b):
r[i + j] += ai * bj
for i in range(2 * e - 1, e - 1, -1):
c = r[i]
if c:
r[i] = 0
for j, Ej in enumerate(E):
r[i - e + j] -= c * Ej
return [c % mod for c in r[:e]]
def val(a, mod):
v = math.inf
for i, c in enumerate(a):
if c % mod:
v = min(v, e * ((c & -c).bit_length() - 1) + i)
return v
out = []
for j in range(1, jmax + 1):
mod = 2 ** (-(-j // e) + 2)
lam = 1
for i in range(1, j):
u = [0] * e
u[0] = 1
ti = [0] * e
ti[0] = 1
for _ in range(i):
ti = mul(ti, [0, 1] + [0] * (e - 2) if e > 1
else [-E[0] % mod], mod)
u = [(a + b) % mod for a, b in zip(u, ti)]
o = 1
while True:
z = list(u)
z[0] -= 1
if val(z, mod) >= j:
break
u = mul(u, u, mod)
o *= 2
lam = max(lam, o)
out.append(lam)
return out
# ----------------------------------------------------- Q(i) at d = 12, Y
class BigLaw(ss.Law):
"""A law's places below 10^5 (base); those between 10^5 and Yc
bounded: residue degree m' = d/D over each prime of C_k there gives at
most D places per prime, each of norm at least p^(m'); d places per
prime past Yc (the tail). At k = 2 (D = 2): arm B's algebras fixed to
Yc."""
def __init__(self, base, Yc, D=2):
self.d, self.Yc, self.tail, self.D = base.d, Yc, True, D
self.a, self.c, self.k = base.a, base.c, base.k
def mid(self, x):
if self.Yc <= Y:
return 0.0
s = -math.log2(x) * (self.d // self.D)
N = Y
return self.D * (N ** -s + N ** (1 - s) / (s - 1)) / (1 - N ** -s)
def parts(self, x):
lz, sw, w, lt = super().parts(x)
return lz, sw, w, lt + self.mid(x)
# ------------------------------------------------------------------ main
def controls():
print("=== CONTROLS")
e1 = max(abs(bound(2, d)[0] - sc.bound_i(d)[0]) for d in (4, 12, 20, 100))
e2 = 0.0
for d in (12, 14, 100, 1000):
a = TowerLaw(2, law(2, d)).cert()
b = sc.QiLaw(sc.qi_law(d, no5=True)).cert()
e2 = max(e2, max(abs(u - v) for u, v in zip(a, b)))
check("C1 POSITIVE: k = 2 is sillclass's bound_i and arm B", e1 < 1e-12
and e2 < 1e-12, f"{e1:.1e}, {e2:.1e}")
want8 = [1, 2, 4, 4, 8, 8, 8, 8, 16]
c8, c12 = chain([-2] + [0] * 7, 9), chain([-2] + [0] * 11, 9)
c16 = chain([-2] + [0] * 15, 17)
z2 = chain([-2], 6)
ok16 = all(c16[j - 1] == 2 ** math.ceil(math.log2(j)) for j in
range(1, 18))
check("C2 the brute chain: e = 8, 12 read 1, 2, 4, 4, 8, 8, 8, 8, 16; "
"e = 16 reads 2^ceil(log2 j) to j = 17", c8 == want8 and
c12 == want8 and ok16, f"e = 8 {c8}; e = 16 {c16}")
check("C2 the brute at Z_2 reads (Z/2^j)^*'s exponent", z2 ==
[1, 2, 2, 4, 8, 16], f"{z2}")
print(f" K = Q(zeta_8) itself (e = 4, pi = 1 - zeta_8): "
f"{chain([2, -4, 6, -4], 17)}")
d, x = 24, 0.3
base = law(3, d)
base = ss.Law(d, list(zip(base.a, base.c, base.k)) +
[(math.log2(9), 5, 1)])
q = TowerLaw(3, base)
b = -math.log2(x)
lnum = (math.log(sum(x ** i for i in range(9)))
+ 5 * math.log1p(9 ** -b))
lden = sum(c * math.log1p(2 ** (-b * a)) for a, c, kk in
zip(base.a, base.c, base.k) if kk == 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))
e3 = 0.0
for n in (0, d // 2):
v, _, xc = bound_at(3, d, n)
w, _ = caps(3, d)
W = [(math.log2(m), c, 1) for m, c in w] + [(math.log2(9), n, 1)]
e3 = max(e3, abs(v - TowerLaw(3, ss.Law(d, W, tail=False)).m(xc)))
check("C3 k = 3: M = log(L(8)/sigma_F2), M' its derivative, the bound "
"= M(x_c)", e1 < 1e-12 and e2 < 1e-6 and e3 < 1e-12,
f"{e1:.1e}, {e2:.1e}, {e3:.1e}")
base = sc.qi_law(12, no5=True)
a = sc.QiLaw(BigLaw(base, Y)).cert()
b = sc.QiLaw(base).cert()
e4 = max(abs(u - v) for u, v in zip(a, b))
xl = sc.QiLaw(BigLaw(base, 10 ** 8)).cert()[2]
pr = sl.primes_to(10 ** 6)
pr = pr[pr > Y].tolist()
bb = -math.log2(xl)
brute = sum(2 * -math.log1p(-float(p) ** (-6 * bb)) if p % 4 == 1 else
-math.log1p(-float(p) ** (-12 * bb)) for p in pr)
mid = BigLaw(base, 10 ** 8).mid(xl)
check("C4 the Y law at Y = 10^5 is arm B; its mid bound >= the places "
"10^5..10^6 at x_low", e4 < 1e-12 and mid >= brute,
f"{e4:.1e}; {mid:.3e} >= {brute:.3e}")
d = 28
q = TowerLaw(3, BigLaw(law(3, d), YBIG, 4))
xl = q.cert()[2]
bb = -math.log2(xl)
brute = 0.0
for p in pr:
f = order_mod(p, 8)
brute += (4 // f) * -math.log1p(-float(p) ** (-f * (d // 4) * bb))
mid = q.base.mid(xl)
e5 = max(abs(u - v) for u, v in zip(
TowerLaw(3, BigLaw(law(3, d), Y, 4)).cert(),
TowerLaw(3, law(3, d)).cert()))
check("C5 (added after the run) the Y law at k = 3: at Y = 10^5 it is "
"arm Z; its mid bound >= the places 10^5..10^6 at x_low, d = 28",
e5 < 1e-12 and mid >= brute, f"{e5:.1e}; {mid:.3e} >= {brute:.3e}")
guard()
def section_tower(k, dmax, dfull, step):
print(f"\n=== k = {k}: Q(zeta_{2 ** k}) in K, d = 0 mod {step}")
d0 = 2 * step
rows = {}
for d in range(d0, dmax + 1, step):
full = d <= dfull
bd = bound(k, d, full)
rows[d] = [bd, full, None]
pos = [d for d in rows if rows[d][0][0] > 0]
neg = [d for d in rows if rows[d][0][0] <= 0]
print(f" bound (full scan to {dfull}, count 0 past it): positive at "
f"{min(pos) if pos else None}..{max(pos) if pos else None}, "
f"at most 0 from {min(neg) if neg else None}; "
f"monotone: {not neg or not pos or max(pos) < min(neg)}")
nz = [(d, rows[d][0][1]) for d in rows if rows[d][1]
and rows[d][0][1] != 0]
print(f" argmin count of n_c = {nc(k)}: 0 at every fully scanned d: "
f"{not nz}" + ("" if not nz else f"; else at {nz[:8]}"))
return rows, pos, neg
def certs(k, rows, dmax, step):
out = []
for d in range(2 * step, dmax + 1, step):
C, dm, xl, xc, ok = certify(k, d)
if d in rows:
rows[d][2] = (C, dm, xl, xc, ok)
out.append((d, C, dm, xl, xc, ok))
return out
def main():
t0 = time.time()
controls()
out = {}
for k, dmax, dfull, cmax, step in ((3, 1000, 200, 1000, 4),
(4, 1200, 1080, 1600, 8)):
rows, pos, neg = section_tower(k, dmax, dfull, step)
cs = certs(k, rows, cmax, step)
good = [d for d, C, dm, xl, xc, ok in cs if ok]
dh = min(good) if good else None
tail = dh is not None and all(ok for d, C, dm, xl, xc, ok in cs
if d >= dh)
clash = [d for d in pos if d in good]
for d, C, dm, xl, xc, ok in cs:
if (d <= 64 or d % 200 == 0 or (dh and abs(d - dh) <= 2 * step)
or (pos and abs(d - max(pos)) <= 2 * step)):
bd = rows.get(d, [None])[0]
bs = (f" bound {bd[0]:+.6f} (n {bd[1]}, x_c {bd[2]:.5f})"
if bd else "")
print(f" d={d:5d}: certificate {C:+.6f} (M' {dm:+.3f}, "
f"x_low {xl:.5f}, x_c {xc:.5f}){bs}")
print(f" least certified d {dh}; every d from it to {cmax} "
f"certified: {tail}; a certificate where the bound is "
f"positive: {clash}")
out[k] = (pos, neg, dh, tail, clash, rows)
d, C, dm, xl, xc, ok = cs[-1]
b = -math.log2(xl)
lt = d * (Y ** -b + Y ** (1 - b) / (b - 1)) / (1 - Y ** -b)
print(f" the tail past Y = 10^5 at d = {d}, x_low {xl:.5f} (b "
f"{b:.3f}): d (Y^-b + Y^(1-b)/(b - 1))/(1 - Y^-b) = {lt:.4f}")
print("\n=== Q(i), d = 12, arm B's algebras fixed to Y")
base = sc.qi_law(12, no5=True)
c12 = {}
for e in (5, 6, 7, 8, 9):
C, dm, xl, xc = sc.QiLaw(BigLaw(base, 10 ** e)).cert()
c12[e] = (C, dm, xl, xc)
print(f" Y = 10^{e}: certificate {C:+.6f} (M' {dm:+.3f}, x_low "
f"{xl:.5f}, x_c {xc:.5f})")
pos3, neg3, dh3, tail3, clash3, rows3 = out[3]
p1 = all(rows3[d][0][1] == 0 for d in rows3 if rows3[d][1])
p2 = (pos3 == [d for d in range(8, 25, 4)]
and all(d in neg3 for d in range(28, 201, 4)))
p3 = dh3 in (28, 32, 36) and tail3 and not clash3
pos4, neg4, dh4, tail4, clash4, rows4 = out[4]
b0 = {d: bound_at(4, d, 0)[0] for d in range(16, 1201, 8)}
p4 = (all(b0[d] > 0 for d in b0 if d <= 1064)
and all(b0[d] <= 0 for d in b0 if d >= 1072)
and dh4 is not None and 1072 <= dh4 <= 1200 and tail4)
lo = max([d for d in b0 if b0[d] > 0], default=None)
print(f"\n k = 4, count 0 alone: positive to {lo}")
C, dm, xl, xc = c12[8]
p5 = -0.009 <= C <= -0.006 and dm < 0 and xc < 0.5
for name, ok in (("P1", p1), ("P2", p2), ("P3", p3), ("P4", p4),
("P5", p5)):
print(f" {name} {'holds' if ok else 'FAILS'}")
kill = not p2_band(pos3, neg3) or not (dh3 and tail3)
print(f" KILL {'fires' if kill else 'missed'}")
arm_y(out)
print(f"\n{sum(CHECKS)} of {len(CHECKS)} checks, "
f"{time.time() - t0:.1f} s")
return 0 if all(CHECKS) else 1
def arm_y(out):
"""ARM Y (added after the run): the arm-Z algebras fixed to Y = 10^30,
the certificate read from the bound's first degree at most 0."""
print(f"\n=== ARM Y: the algebras fixed to Y = 10^30")
for k, step, dmax in ((2, 2, 1000), (3, 4, 1000), (4, 8, 2000)):
if k == 2:
first = min(d for d in range(4, 201, 2) if sc.bound_i(d)[0] <= 0)
else:
first = min(out[k][1])
D = 2 ** (k - 1)
good, bad = [], []
for d in range(first, dmax + 1, step):
base = sc.qi_law(d, no5=True) if k == 2 else law(k, d)
C, dm, xl, xc = TowerLaw(k, BigLaw(base, YBIG, D)).cert()
ok = C < 0 and dm < 0 and xc < 0.5
(good if ok else bad).append(d)
if d - first <= 2 * step or d % 200 == 0:
print(f" k = {k}, d={d:5d}: certificate {C:+.6f} (M' "
f"{dm:+.3f}, x_low {xl:.5f}, x_c {xc:.5f})")
print(f" k = {k}: certified at every d = 0 mod {step} from {first} "
f"to {dmax}: {not bad}" + ("" if not bad else f" (not at "
f"{bad[:6]})"))
if k > 2:
pre = TowerLaw(k, BigLaw(law(k, first - step), YBIG, D)).cert()
print(f" k = {k}, d = {first - step} (bound positive): "
f"certificate {pre[0]:+.6f}")
ds = dstar(k)
fa = step * math.ceil(ds / step)
print(f" k = {k}: d* = l(x0)/u_k(x0) = {ds:.2f}; the first d = 0 "
f"mod {step} past it {fa}, the bound's first at most 0 "
f"{first}: equal {fa == first}")
def dstar(k):
"""d* = l(x0)/u_k(x0), x0 = (3 - sqrt 5)/2 (2 l + log x = 0), u_k the
W_k terms of w per unit of d (9 at weight 1/2)."""
x0 = (3 - math.sqrt(5)) / 2
u = sum((0.5 if n == 9 else 1.0) * math.log1p(x0 ** math.log2(n))
for n in wk(k))
return se.lf(x0) / u
def p2_band(pos, neg):
"""P2's band within one step of 4 at either end."""
return (pos and min(pos) == 8 and 20 <= max(pos) <= 28
and neg and 24 <= min(neg) <= 32)
if __name__ == "__main__":
sys.exit(main())