towerpast.py
Checks: THERMAL: The 2-power tower raises the sill theorem; rule.
Cited on: THERMAL.
To run it: save towerpast.py, with fieldtop.py, growth.py, memory.py, sillclass.py, spectrum.py, splitend.py, splitloss.py, splitsharp.py, tower.py, typeloss.py beside it; needs mpmath, numpy, scipy.
"""towerpast.py -- the 2-power tower past its reads: a lemma that every d
= 0 mod 4 from some d0 <= 1000 loses at k = 3, and the turn of the bound
at k = 8, where D(k) as the first degree past d* is untested.
QUESTION. (A) With Q(zeta_8) in K, K_ab = Q(zeta_8), type (1, 0), does
the law fixed below Y = 10^5 (tower.py's arm Z) lose at every d = 0 mod
4 from a d0 <= 1000, by a lemma as sillclass's at k = 2? (B) At k = 8
(Q(zeta_256), d = 0 mod 128), does the bound at count 0 turn at the
first such d past d* = l(x0)/u_8(x0), and does a certificate there read
the loss?
THE DERIVATION (by hand, before this code).
(A) At k = 3 the places of norm 17 number d, weight 1 (at k = 2 those
of norm 9 numbered d/2): x1 solving d 17^-b = lam = log(1/x) would
give c_z >= 1/(1 - y) > 1, the slope 1 - c_z - c_s negative, so the
lemma would say nothing (a TRANSPLANT from k = 2 that fails here). So
x1 solves d x^a17 = h lam, h in (0, 1) a free parameter, a17 = log2
17, y = 17^-b = x^a17. With d = h lam 17^b at x1:
lz <= h lam [1/(1 - y) + sum_{n = 257, 65537} (17/n)^b/(1 - n^-b)
+ (17/Y)^b (1 + Y/(b - 1))/(1 - Y^-b)] + E,
the last the tail (d places per prime past Y, each of norm >= p), E
over the places of norm (p^f)^m' below Y off W_3: at most 4 per p,
their norms distinct prime powers >= 9^m' (3 has order 2 mod 8, its
two primes of Z[zeta_8] of norm 9, n_c's), so E <= 4 9^-s (1 + 9/(s -
1))/(1 - 9^-s), s = m' b, m' = d/4 (integral test).
s_/x <= h lam [x^(a17 - 1)/(1 - y^2) + sum_n (34/n^2)^b/(1 - n^-2b)
+ (34/Y)^b (1 + Y/(b - 1))/(1 - Y^-b)] + E/x,
s_ = lz - sw + lt (a W place adds -log(1 - y^2) <= y^2/(1 - y^2), the
others whole; 1/x = 2^b folded in). g_up = l + lz + lt + log(1 - (1 -
x)e^-s_) <= l + lz + lt + log x + s_/x. Every coefficient rises with x
(17/n < 1, 34/n^2 < 1, the tail's factors), so on x1 <= X they are
bounded at X, l(x1) <= l(X), lam >= lam0 = log(1/X): g_up(x1) <= l(X)
- (1 - c_z - c_s) lam0 + E' (c_z, c_s at X, h included), needing 1 -
c_z - c_s > 0. w >= d log(1 + y) >= h lam (1 - y/2): M(x1) <= l(X) - h
lam0 (1 - y0/2), y0 = X^a17; M'(x1) <= 1/(1 - X) - a17 h lam0/(X(1 +
y0)), the l_c and other W terms of M' negative. x1 <= X iff d >= d0 =
h lam0 X^-a17. Where g_up(x1) < 0 the point is above x1, at most x_c;
M rises then falls once on [0, x_c], so M'(x1) < 0 puts x1 past the
peak and the margin is at most M(x1) < 0. Hand sizes at X = 1/4, h =
1/3: d0 = 134, c_z ~ 0.336, c_s ~ 0.009, g_up <= -0.66, M <= -0.17,
M' <= -6.
(B) At k = 8, n_c = 257 cancels, W_8 = {65537} and tower.wk's composite
F_5..F_9; x0^16 ~ 2.0e-7, d* ~ 2.35e6. At count 0, M(x_c) = h_c(x_c)
turns where x_c crosses h_c's root, x0 shifted by l_c = -log(1 -
x^257) (below 1e-100): the turn is d* up to that shift, so the kill
can fire only through an engine fault or a rounding at the step. The
certificate at m' ~ 18,000: every place off W has norm at least
9^m', so the law is the bound's but for the tail past Y; at Y = 10^30
that tail is about d Y^(1 - b)/(b - 1), b = log2(1/x0) ~ 1.389, about
2e-5, against a bound at the first d past d* of order (d - d*)
times M's slope in d, at most 128 u_8 ~ 3e-5: the certificate may
fail at D(8) for the tail alone, read at Y = 10^60 beside it.
PREDICTIONS (frozen before the engine).
P1 (A) at X = 1/4, h = 1/3: d0 = ceil(h lam0 X^-a17) in [120, 150],
slope 1 - c_z - c_s >= 0.6, g_up <= -0.5, M <= -0.1, M' <= -4.
P2 (A) at every d = 0 mod 4 from d0 to 1000, at the arm-Z law: x1 <=
X, x1 <= x_low, C <= M(x1) <= the M bound, g_up(x1) and M'(x1)
below theirs.
P3 (B) bound_at(8, d, 0) over d = 0 mod 128, 40 steps either side of
d*, is positive below the first d past d* and at most 0 from it.
P4 (B) the ARM Y certificate (tower.BigLaw at Y = 10^30) at k = 8 is
negative with M' < 0 and x_c < 1/2 at the first d past d* + 128 and
at every printed d past it (a guess, 50%, at the first d itself).
KILL of (A): g_up >= 0, M >= 0, M' >= 0 or slope <= 0 printed at X, or
d0 > 1000, or P2 failing. KILL of the first-degree pattern at k = 8: a
turn of P3's count-0 bound more than one step from the first d past
d*.
CONTROLS (frozen).
C1 POSITIVE: the same lemma code at k = 2's constants (a9, h = 1/2,
X = 1/7, the Fermat norms 17, 257, 65537, base 5, factor 2)
reproduces sillclass.lemma()'s c_z, c_s, g_up, M and M' to 1e-12.
C2 PLANT: at h = 1 (the transplant) the slope at X = 1/4 is <= 0, so
the lemma can say no.
C3 the k = 3 coefficients against a brute sum over the arm-Z law's
places at d = 1000, x = x1: lz + lt <= c_z lam + E and (lz - sw +
lt)/x <= c_s lam + E/x, coefficients at X and at x1.
C4 at k = 8, bound_at(8, d, 0) equals TowerLaw(8, law of exactly
those counts, no tail).m(x_c) at d = d*'s step, to 1e-12.
FINDINGS (entered after the run, from its printed output).
CONTROLS. C1: 0.0, d0 930. C2: slope -0.036139 (c_z 1.010738), so the
lemma can say no. C3: at d = 1000, lz + lt 0.605076 against c_z lam
0.610882 (at X) and 0.605259 (at x1); (lz - sw + lt)/x 2.2708e-03
against 1.5352e-02 and 2.2708e-03 (the norm-17 term all but exact at
x1). C4: 4.4e-16 at d = 2344064. C1 passes sillclass's own E (base 5,
factor 4: the frozen "factor 2" misnamed it), so e3 is read by no
control; e3(d0, X) bounds E(d, x1)(1 + 1/x1) since (2/9^m')^b falls in
b and in m'; it prints 2.644e-63.
(A) P1 HOLDS: d0 = 134, c_z 0.336913, c_s 0.008467, slope 0.654620,
E' 2.644e-63; g_up <= -0.619814, M <= -0.173617, M' <= -6.1958. P2
HOLDS at the 217 d = 0 mod 4 from 136 to 1000, the largest M(x1)
-0.178151 at d = 136 (x1 0.249055, x_low 0.287237, C -0.495215).
KILL (A) MISSED: the arm-Z law loses at every d = 0 mod 4 >= 136, so
with tower.py's certificates from 28, a field containing Q(zeta_8),
K_ab = Q(zeta_8), type (1, 0), loses at every d = 0 mod 4 >= 28.
(B) d* = 2343958.59; the first d = 0 mod 128 past it is 2344064 (0.8235
of a step past d*). P3 HOLDS: the count-0 bound is positive at every
read d from 2338944 to 2343936 (+1.113e-06 there) and at most 0 from
2344064 (-5.193e-06) through the read's last d, 40 steps past. KILL
(B) MISSED. P4 FAILS as frozen:
at Y = 10^30 the certificate is positive at each printed d from
2344064 (+2.161e-05) to 2344320 (+8.986e-06), the tail past Y as the
derivation priced it, and negative at 2345344 (-4.150e-05), the d
between unread (the P4 print's bracket names the first d, not where P4
fails, which is 2344192); at Y = 10^60 it is negative with M' <
0 and x_c < 1/2 at every printed d from 2344064 (-4.973e-06) and
positive at 2343936 (+1.333e-06). So at k = 8 the loss is read at the
printed degrees 2344064, +128, +256 and +1280 at Y = 10^60, and the
no-loss below the turn at count 0 alone (the full scan over the count
of 257 unread).
RUN RECORD. `python towerpast.py` under a 2048 MB cap: 4 of 4 checks,
1.1 s, peak commit 58.9 MB. The engine was appended to the frozen
docstring in one write and run once. Moved in from the lab unchanged;
every line printed as before.
"""
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")
from scipy.optimize import brentq # noqa: E402
import sillclass as sc # noqa: E402
import splitsharp as ss # noqa: E402
import tower as tw # noqa: E402
CHECKS = []
A17 = math.log2(17)
X3, H3 = 0.25, 1 / 3
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 lemma
def coeffs(x, c, wB, a, B, norms, Y):
"""(c_z, c_s) at x: d = c lam B^b, wB d places of norm B, d of each
norm in norms, d per prime past Y."""
b = -math.log2(x)
y = B ** -b
fac = (1 + Y / (b - 1)) / (1 - Y ** -b)
cz = c * (wB / (1 - y) + sum((B / n) ** b / (1 - n ** -b) for n in norms)
+ (B / Y) ** b * fac)
cs = c * (wB * x ** (a - 1) / (1 - y * y)
+ sum((2 * B / n ** 2) ** b / (1 - n ** (-2 * b))
for n in norms)
+ (2 * B / Y) ** b * fac)
return cz, cs
def lemma(X, c, wB, a, B, norms, Y, E):
lam0 = -math.log(X)
y0 = X ** a
cz, cs = coeffs(X, c, wB, a, B, norms, Y)
lx = -math.log1p(-X)
return dict(cz=cz, cs=cs, slope=1 - cz - cs, E=E,
d0=math.ceil(c * lam0 * X ** -a),
G=lx - (1 - cz - cs) * lam0 + E,
M=lx - wB * c * lam0 * (1 - y0 / 2),
Mp=1 / (1 - X) - a * wB * c * lam0 / (X * (1 + y0)))
def e3(d0, X):
"""E + E/x at k = 3: at most 4 places per p off W_3, their norms
distinct prime powers >= 9^m', m' >= d0/4."""
s = (d0 / 4) * -math.log2(X)
return 4 * 9.0 ** -s * (1 + 9 / (s - 1)) / (1 - 9.0 ** -s) * (1 + 1 / X)
def lemma3(h=H3, X=X3):
L = lemma(X, h, 1.0, A17, 17, (257, 65537), ss.Y, 0.0)
return lemma(X, h, 1.0, A17, 17, (257, 65537), ss.Y, e3(L["d0"], X))
def x1(d, c, a):
return brentq(lambda x: d * x ** a + c * math.log(x), 1e-12, 0.5,
xtol=1e-18, rtol=1e-15, maxiter=500)
# ----------------------------------------------------------------- main
def controls():
print("=== CONTROLS")
want = sc.lemma()
E = sc.lemma_e(sc.lemma_d0() // 2, sc.LX0)
got = lemma(sc.LX0, 1.0, 0.5, sc.A9, 9, sc.FERMAT, sc.LY, E)
err = max(abs(got[k] - want[k]) for k in ("cz", "cs", "G", "M", "Mp"))
check("C1 POSITIVE: k = 2's constants reproduce sillclass.lemma()",
err < 1e-12 and got["d0"] == sc.lemma_d0(),
f"{err:.1e}, d0 {got['d0']}")
P = lemma3(h=1.0)
check("C2 PLANT: h = 1 at X = 1/4 gives slope <= 0", P["slope"] <= 0,
f"slope {P['slope']:+.6f}, c_z {P['cz']:.6f}")
d = 1000
q = tw.TowerLaw(3, tw.law(3, d))
x = x1(d, H3, A17)
lam = -math.log(x)
lz, sw, w, lt = q.base.parts(x)
E = e3(d, x)
ok = True
for tag, xx in (("X", X3), ("x1", x)):
cz, cs = coeffs(xx, H3, 1.0, A17, 17, (257, 65537), ss.Y)
good = (lz + lt <= cz * lam + E
and (lz - sw + lt) / x <= cs * lam + E)
ok = ok and good
print(f" d = 1000, coefficients at {tag}: lz + lt {lz + lt:.6f} "
f"<= {cz * lam:.6f}; (lz - sw + lt)/x "
f"{(lz - sw + lt) / x:.4e} <= {cs * lam:.4e}")
check("C3 the k = 3 coefficients bound the arm-Z law's sums at d = "
"1000, x1", ok)
ds = tw.dstar(8)
d = 128 * math.ceil(ds / 128)
v, _, xc = tw.bound_at(8, d, 0)
w, _ = tw.caps(8, d)
W = [(math.log2(m), c, 1) for m, c in w] + [(math.log2(257), 0, 1)]
e4 = abs(v - tw.TowerLaw(8, ss.Law(d, W, tail=False)).m(xc))
check("C4 k = 8: bound_at(8, d, 0) = M(x_c) on its law", e4 < 1e-12,
f"{e4:.1e} at d = {d}")
guard()
def part_a():
print("\n=== (A) k = 3: the lemma at X = 1/4, h = 1/3")
L = lemma3()
print(f" d0 = ceil(h lam0 X^-a17) = {L['d0']}; c_z {L['cz']:.6f}, "
f"c_s {L['cs']:.6f}, slope {L['slope']:.6f}, E' {L['E']:.3e}")
print(f" g_up <= {L['G']:+.6f}; M <= {L['M']:+.6f}; M' <= "
f"{L['Mp']:+.4f}")
p1 = (120 <= L["d0"] <= 150 and L["slope"] >= 0.6 and L["G"] <= -0.5
and L["M"] <= -0.1 and L["Mp"] <= -4)
d0 = L["d0"] + (-L["d0"]) % 4
bad, worst, n = [], None, 0
for d in range(d0, 1001, 4):
q = tw.TowerLaw(3, tw.law(3, d))
C, dm, xl, xc = q.cert()
x = x1(d, H3, A17)
ok = (x <= X3 and x <= xl and C <= q.m(x) <= L["M"]
and q.g_up(x) <= L["G"] and q.dm(x) <= L["Mp"])
n += 1
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
print(f" at the {n} d = 0 mod 4 from {d0} to 1000: failing at "
f"{bad[:6]}; largest M(x1) {m:+.6f} at d = {d} (x1 {x:.6f}, "
f"x_low {xl:.6f}, C {C:+.6f}, g_up(x1) {g:+.6f}, M'(x1) "
f"{dmx:+.4f})")
p2 = not bad
kill = (L["G"] >= 0 or L["M"] >= 0 or L["Mp"] >= 0 or L["slope"] <= 0
or L["d0"] > 1000 or not p2)
print(f" P1 {'holds' if p1 else 'FAILS'}; P2 "
f"{'holds' if p2 else 'FAILS'}; KILL (A) "
f"{'fires' if kill else 'missed'}")
def part_b():
print("\n=== (B) k = 8: the turn at count 0 and the certificate")
ds = tw.dstar(8)
first = 128 * math.ceil(ds / 128)
print(f" d* = {ds:.2f}; the first d = 0 mod 128 past it {first} "
f"({(first - ds) / 128:.4f} steps past d*)")
vals = {d: tw.bound_at(8, d, 0)[0] for d in
range(first - 40 * 128, first + 40 * 128 + 1, 128)}
pos = [d for d in vals if vals[d] > 0]
neg = [d for d in vals if vals[d] <= 0]
turn = min(neg) if neg else None
for d in (first - 256, first - 128, first, first + 128):
print(f" d = {d}: bound at count 0 {vals[d]:+.3e}")
p3 = bool(pos) and max(pos) < first and turn == first
print(f" positive at {min(pos) if pos else None}.."
f"{max(pos) if pos else None}, at most 0 from {turn}; P3 "
f"{'holds' if p3 else 'FAILS'}")
kill = turn is None or abs(turn - first) > 128
print(f" KILL (B) {'fires' if kill else 'missed'}")
certs = {}
for Yc, tag in ((10 ** 30, "10^30"), (10 ** 60, "10^60")):
for d in (first - 128, first, first + 128, first + 256,
first + 1280):
C, dm, xl, xc = tw.TowerLaw(8, tw.BigLaw(tw.law(8, d), Yc,
128)).cert()
certs[(tag, d)] = (C, dm, xl, xc)
print(f" Y = {tag}, d = {d}: certificate {C:+.3e} (M' "
f"{dm:+.3f}, x_low {xl:.7f}, x_c {xc:.7f})")
p4 = all(certs[("10^30", d)][0] < 0 and certs[("10^30", d)][1] < 0
and certs[("10^30", d)][3] < 0.5
for d in (first + 128, first + 256, first + 1280))
c0 = certs[("10^30", first)][0]
print(f" P4 {'holds' if p4 else 'FAILS'} (at the first d itself: "
f"{c0:+.3e})")
def main():
t0 = time.time()
controls()
part_a()
part_b()
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())