slack.py
Checks: IMAGE: Polynomial slack reaches breadth from the void theorem; rule.
Cited on: IMAGE.
To run it: save slack.py, with bridges.py, cgreedy.py, growth.py beside it; standard library only.
"""slack.py -- a slack polynomial in the tide escapes the dam, and its
square reaches breadth; the tide ceiling tau(P) is at least beta(P).
QUESTION. Every c-greedy walk over Z is dammed: its support stays
finite. Does a slack growing faster than linear in the tide escape, and
does the tide ceiling tau(P) grow as a power of P with no hypothesis?
DESIGN. Lam_P = lcm(p - 1 : p prime, p <= P), beta(P) the least prime
power dividing no such p - 1 (the least element order unborn at P, in
the birthday formula's sense), p(m) the least prime = 1 mod m. The
f-greedy walk, f nondecreasing with f(t) >= t, takes at a state M any
lambda-raising m <= f(m0(M)); c-greedy is f(t) = ct. A price, the least
multiplier raising lambda at one prime q (the door lemma), is a power
q^e with e > v_q(lambda), and the tide m0 is the least price.
(1) THE RECORD RUN. From the void, read the odd primes in increasing
order and seat each one whose p - 1 does not divide lambda, once. After
every prime <= P is read the state M_P is odd and squarefree with
lambda(M_P) = Lam_P, a skipped q having q - 1 | lambda when read.
(2) THE FLOOR. m0(M_P) >= beta(P) for P >= 3: 2 unseated prices
2^(v + 3), a seated odd q prices q^(v + 1), a skipped q prices q^(v + 2),
v = v_q(Lam_P), and a prime past P at least itself, a power of a prime
dividing no p - 1 with p <= P. Each is a prime power not dividing
Lam_P, so at least beta(P).
Hence tau(P) >= beta(P).
(3) THE ESCAPE. If f(t) >= p(t) at every prime power t, the record run
is an f-greedy run seating infinitely many primes, each once (not
breadth: 2 and the skipped primes stay out). The next seat R(P) is at
most p(beta(P)), a prime past P (beta divides no p - 1, p <= P) whose
p - 1 does not divide Lam_P, and p(beta) <= f(beta) <= f(m0(M_P)). By
Linnik's theorem, p(m) <= C m^L at every m >= 2 for constants C and L,
so f(t) = C t^L qualifies and beta(P) > (P/C)^(1/L); under GRH,
p(m) << (m log m)^2. The script reads (2) and (3) at every prime
P <= 10,000; the constants are the sources', no run reaches them.
(4) BREADTH. If f(t) >= p(t)^2 at every prime power t, the f-greedy
walk reaches breadth (the support every place) from the void. The
RIDING RUN: m = 4 first (lambda 1 -> 2, 4 <= f(3)); then the records
recomputed from lambda = 2, so 3 is skipped and the records run 5, 7,
11, ...; each record R is seated with the oldest skipped prime q not
yet seated, m = R q, first in first out, or alone when none waits.
q < R; a rider leaves lambda unchanged (q - 1 | lambda when skipped),
so lambda stays Lam_P and m raises it through R. 2 at exponent 2
prices 2^(v + 1), a seated rider q^(v + 1), a waiting prime as in (2):
every price is still a prime power not dividing lambda, the tide at
least beta, and m < R^2 <= p(beta)^2 <= f(m0). Records never end, so
every skipped prime rides at a finite step: support every place, every
exponent finite. By Linnik f(t) = C^2 t^(2L).
(5) SEEDS. Neither (3) nor (4) holds from every seed: at 3^N with
3^N >= f(3), 3's own part tops lambda's, so 3 prices 3^(v - a + 2) = 3,
the tide is at most 3 and every move at most f(3); a prime r lifts
v_3(lambda) past 3's own part only if 3^N | r - 1, so r > f(3), and no
move brings one: every f-greedy walk is dammed there, whatever f.
BY HAND. P = 13: Lam = 60, beta = 7; the record run seats 3, 5, 7, 11
and skips 13; at M_13 = 1155 the prices are 2^5, 9, 25, 7, 11, 13^2 and
17, m0 = 7 = beta; R(13) = 17 <= p(7) = 29. P = 7: M = 105, lambda 12,
m0 = 5, R = 11. The riding run: from the void (lambda 1, beta 2,
m0 3) the move 4; at 4 (lambda 2, beta 3, m0 4) the move 15 = 5*3; at
60 (lambda 4, beta 3, m0 3) the move 7; at 420 (lambda 12, beta 5,
m0 5) the move 11; at 4620 (lambda 60, beta 7, m0 7, 13 waiting) the
move 221 = 17*13 <= p(7)^2 = 841.
PREDICTIONS (frozen before the code).
P1 m0(M_P) >= beta(P) and tau(P) >= beta(P) at every prime
3 <= P <= 10,000 (forced).
P2 R(P) <= p(beta(P)) at every such P (forced).
P3 The riding run, at the move 4 and at every move whose record R is
<= 10,000: the move raises lambda, m0 >= beta on the state before
it, R <= p(beta), m <= p(beta)^2, a rider q < R with q - 1 | lambda
(forced).
P4 Its records from 5 on are the record run's (forced: lambda agrees
from 2 on).
KILL. "C1 FAIL" printed at a P where P1 or P2 breaks ends (2) or (3) as
stated; "C3 FAIL" at a move where P3 breaks ends (4).
CONTROLS, read first. C0: the hand values at 13 and 7, and the riding
run's first five moves with their tides and betas. C4: P3's test must
flag two planted breaks, the fifth move's rider moved alone (it does
not raise lambda) and a rider past its record (the least prime past
it with q - 1 | lambda, so only q < R fails). C2, read after the gate,
the edge: m0 = beta at P = 13, so P1's inequality is met with
equality and is not slack by construction; the count of P at equality is printed.
FINDINGS (from the printed run; the controls passed first). KILL
silent: P1 and P2 hold at all 1228 primes 3 <= P <= 10,000, every R(P)
found below X + 200; m0 = beta at 1149 of the 1228, the last at 9973.
At P = 101, 1009, 2003, 5003, 9973: beta 17, 109, 167, 227, 361; tau
47, 227, 383, 839, 1823; R 103, 1019, 2027, 5087, 10007; p(beta) 103,
1091, 2339, 5449, 10831. tau/beta = 5.0499 at 9973; ln beta / ln P over
[1000, 10^4] is least 0.6307, at P = 5443. The record run's slack R/m0
reaches 27.720 at 9973, nearly P/beta by construction, and 1.1595 times
ln^2 m0 at P = 181, so no polylog rate is claimed. P3 holds at all 302
riding moves, the move 4 and the 301 records 5 to 9887, the records the
record run's (P4); the riders leave in the order queued, and once every
prime <= 10,000 is read, 927 are queued, 296 ridden and 631 waiting, the
least 2897, so every skipped prime below 2897 has ridden. C4 flags both
planted breaks.
RUN RECORD. 10/10 checks, 0.6 s, peak commit 55.3 MB.
"""
import os
import sys
import time
from math import log
os.environ.setdefault("OPENBLAS_NUM_THREADS", "1")
import growth # noqa: E402
import cgreedy # noqa: E402
CHECKS = []
X = cgreedy.X
PR = cgreedy.PR # the primes to X + 200
PM1 = cgreedy.PM1
SIEVE = 4_000_000
def check(name, ok, detail=""):
CHECKS.append((name, bool(ok)))
print(f" [{'PASS' if ok else 'FAIL'}] {name}"
+ (f" -- {detail}" if detail else ""))
def sieve():
s = bytearray([1]) * SIEVE
s[0] = s[1] = 0
for i in range(2, int(SIEVE ** 0.5) + 1):
if s[i]:
s[i * i::i] = bytearray(len(s[i * i::i]))
return s
def least_prime_1(m, isp):
"""p(m), the least prime = 1 mod m, off the sieve."""
n = m + 1
while not isp[n]:
n += m
if n >= SIEVE:
raise SystemExit(f"sieve too short for p({m})")
return n
def beta_of(vN, pps):
"""The least prime power q = r^a with a > v_r(Lam); pps holds (q, r, a)."""
for q, r, a in pps:
if vN.get(r, 0) < a:
return q
raise SystemExit("no unborn prime power in range")
def prime_powers(n):
"""Every prime power q <= n as (q, r, a), q = r^a, in order."""
out = []
for r in PR:
if r > n:
break
q, a = r, 1
while q <= n:
out.append((q, r, a))
q, a = q * r, a + 1
return sorted(out)
def record_run():
"""At every prime P <= X: (seated set, the exponents of Lam_P), and
the run's seats in order."""
vN, seated, seats, out = {}, [], [], {}
for p in PR:
if p > 2 and not growth.divides(PM1[p], vN):
seated.append(p)
seats.append(p)
for r, e in PM1[p].items():
if e > vN.get(r, 0):
vN[r] = e
if p <= X:
out[p] = (list(seated), dict(vN))
return out, seats
def riding_run():
"""The run of (4): 4 from the void, then each record R with the
oldest queued prime q. The moves as (state before, m, R, q), the
primes in the order queued, and the queue when R passes X."""
mf, moves, queue, queued = {2: 2}, [({}, 4, None, None)], [], []
lf = cgreedy.lam(mf)
for p in PR:
if p == 2:
continue
if growth.divides(PM1[p], lf):
queue.append(p)
queued.append(p)
continue
if p > X:
break
q = queue.pop(0) if queue else None
moves.append((dict(mf), p * (q or 1), p, q))
mf = growth.merge_add(mf, {p: 1, **({q: 1} if q else {})})
lf = cgreedy.lam(mf)
return moves, queued, queue
def riding_rows(moves, pps, isp):
"""Per move: (m, m0, beta) and the moves breaking P3."""
rows, bad = [], []
for M, m, R, q in moves:
lf = cgreedy.lam(M)
b = beta_of(lf, pps)
t = cgreedy.m0(M)
pb = least_prime_1(b, isp)
ok = (cgreedy.raises(M, lf, m) and t >= b and m <= pb * pb
and (R is None or R <= pb)
and (q is None or (q < R and growth.divides(PM1[q], lf))))
rows.append((m, t, b))
if not ok:
bad.append((m, R, q, t, b, pb))
return rows, bad
def section_controls(row, run, rows, moves, pps, isp):
print("CONTROLS")
b, m0, t, R, pb = row[13]
check("C0 at 13: beta 7, m0 7, R 17, p(7) 29 (by hand)",
(b, m0, R, pb) == (7, 7, 17, 29), f"{b}, {m0}, {R}, {pb}")
b, m0, t, R, pb = row[7]
check("C0 at 7: m0 5, R 11 (by hand)", (m0, R) == (5, 11), f"{m0}, {R}")
check("C0 M_13 is 3*5*7*11", run[13][0] == [3, 5, 7, 11],
f"{run[13][0]}")
check("C0 the riding run's first moves 4, 15, 7, 11, 221, tides "
"3, 4, 3, 5, 7, beta 2, 3, 3, 5, 7 (by hand)",
rows[:5] == [(4, 3, 2), (15, 4, 3), (7, 3, 3), (11, 5, 5),
(221, 7, 7)], f"{rows[:5]}")
M, m, R, q = moves[4]
lf = cgreedy.lam(M)
nxt = next(p for p in PR if p > R and growth.divides(PM1[p], lf))
plants = [(M, q, R, q), (M, R * nxt, R, nxt)]
caught = len(riding_rows(plants, pps, isp)[1])
check(f"C4 P3 flags a rider moved alone and the rider {nxt} past its "
f"record {R}", caught == 2, f"{caught} of 2 flagged")
def section_record(row):
"""The floor (2) and the escape (3) at every prime 3 <= P <= X."""
print("THE FLOOR AND THE ESCAPE")
f1 = [P for P in row if not (row[P][1] >= row[P][0]
and row[P][2] >= row[P][0])]
f2 = [P for P in row if row[P][3] is not None
and row[P][3] > row[P][4]]
for P in (f1 + f2)[:5]:
print(f" C1 FAIL {P}: {row[P]}")
check(f"P1 m0(M_P) >= beta and tau >= beta at every prime "
f"3 <= P <= {X}", not f1, f"{len(row)} primes")
known = [P for P in row if row[P][3] is not None]
check("P2 R(P) <= p(beta(P)) wherever R(P) <= X + 200", not f2,
f"{len(known)} primes")
eq = [P for P in row if row[P][1] == row[P][0]]
check("C2 m0 = beta at 13 (the edge; C0 already fixed it)", 13 in eq,
f"{len(eq)} primes at equality, the last {eq[-1]}")
print(" P beta m0 tau R p(beta) slack")
for P in [7, 13, 101, 1009, 2003, 5003, 9973]:
b, m0, t, R, pb = row[P]
sl = f"{R / m0:6.3f}" if R else " - "
print(f" {P:5d} {b:6d} {m0:6d} {t:6d} {R or 0:6d} {pb:8d} {sl}")
print("READINGS")
sl = max((row[P][3] / row[P][1], P) for P in known)
print(f" the largest slack R/m0: {sl[0]:.4f} at P = {sl[1]}")
hi = max((row[P][3] / row[P][1] / log(row[P][1]) ** 2, P)
for P in known if P >= 100)
print(f" R/m0 over ln^2 m0 on [100, 10^4]: most {hi[0]:.4f} at "
f"P = {hi[1]}")
print(f" tau/beta at 9973: {row[9973][2] / row[9973][0]:.4f}")
lb = min((log(row[P][0]) / log(P), P) for P in row if P >= 1000)
print(f" ln beta / ln P over [1000, 10^4]: least {lb[0]:.4f} at "
f"P = {lb[1]}")
return bool(f1 or f2)
def section_riding(moves, queued, queue, bad, seats):
"""Breadth (4): the riding run's moves with record <= X."""
print("BREADTH: THE RIDING RUN")
for r in bad[:5]:
print(f" C3 FAIL move {r[0]} (R {r[1]}, q {r[2]}): m0 {r[3]}, "
f"beta {r[4]}, p(beta) {r[5]}")
check(f"P3 every riding move with R <= {X} raises lambda, m0 >= beta, "
f"R <= p(beta), m <= p(beta)^2, riders q < R, q - 1 | lambda",
not bad, f"{len(moves)} moves")
recs = [R for _, _, R, _ in moves if R]
check("P4 its records are the record run's from 5 on",
recs == [p for p in seats if 5 <= p <= X],
f"{len(recs)} records, {recs[0]} to {recs[-1]}")
riders = [q for _, _, _, q in moves if q]
print(f" riders leave in the order queued: "
f"{riders == queued[:len(riders)]}; with every prime <= {X} "
f"read, {len(queued)} queued, "
f"{len(riders)} ridden, {len(queue)} waiting, the least {queue[0]}")
return bool(bad)
def main():
t0 = time.time()
isp = sieve()
pps = prime_powers(X)
run, seats = record_run()
tab = cgreedy.tau_table()
row = {}
for P in PR:
if P < 3 or P > X:
continue
seated, vN = run[P]
m0 = cgreedy.m0({q: 1 for q in seated})
nxt = [q for q in seats if q > P]
b = beta_of(vN, pps)
row[P] = (b, m0, tab[P][0], nxt[0] if nxt else None,
least_prime_1(b, isp))
moves, queued, queue = riding_run()
rows, bad = riding_rows(moves, pps, isp)
section_controls(row, run, rows, moves, pps, isp)
if not all(ok for _, ok in CHECKS):
print("CONTROL FAILED: nothing below is read.")
raise SystemExit(1)
fired = section_record(row)
fired = section_riding(moves, queued, queue, bad, seats) or fired
print("KILL")
print(f" {'FIRED' if fired else 'silent'}")
print(f"{sum(ok for _, ok in CHECKS)}/{len(CHECKS)} checks passed, "
f"{time.time() - t0:.1f} s")
raise SystemExit(0 if all(ok for _, ok in CHECKS) else 1)
if __name__ == "__main__":
main()