"""single.py -- the least multiple of the dam's bar under which one run escapes from the void. QUESTION. A c-run is a run from the void whose every move from a state of tide m0 is at most floor(c F(max(m0, 4))), F the dam's bar; a run's envelope stays within cF at every t exactly when it is a c-run. c0 is the infimum of the c at which some c-run escapes. Where is c0? DESIGN. F from fwide.py's widened tau table, fixed on 4..10^4. (1) Lemma D, the crossing. For a prime r and e >= 1 write d = r^e and its point T(d) = min(r^(e+1), p(d)) at odd r, min(2^(e+2), p(d)) at 2. At a state with v_r(lambda) <= e - 1, m0 <= T(d): r's price is at most the point, and p(d), unheld, prices itself. An escaping run's tide is unbounded, so it passes every crossing, by a move from a tide <= T(d), at most X(d) = floor(cF(T(d))), that brings a prime = 1 mod d, every earlier prime being at most X(d) too. Raising r's own exponent instead leaves the tide at most r (odd r past depth e with no anchor), at most 2 (2 at b >= e + 2 with u_2 <= b - 2) or at most 4 (the move 4 at e = 1), until a prime = 1 mod d enters by a move at most X(d). (2) Lemma H, a held crossing. A held odd q with v_q(lambda) <= f - 1 has m0 <= q^f, its price q^max(1, v - a + 2) <= q^(f + 1 - a). (3) Viability. Y*(a), the least Y such that a, entering with every earlier prime at most Y, has each crossing a^f (a^f <= 10^4) passable: by a prime b = 1 mod a^f held before a (b <= Y) or after (b <= Z = floor(cF(a^f)), by (2)), b's earlier primes at most max(Y, Z). So need_f(a) = 0 if some such b <= Z has Y*(b) <= Z, else the least max(b, Y*(b)); Y*(a) = max_f need_f(a), and 0 past 10^4. An over-approximation of viability, so sound for a dam. (4) THE CROSSING TEST at c: every crossing d with T(d) <= 10^4 has a prime a = 1 mod d with a <= X(d) and Y*(a) <= X(d). A failing crossing dams every c-run: a proof at that c, given F's table. It is monotone in c; c_low, the least c at which it passes, is found by bisection over exact fractions and named as the critical ratio n/F(x) above the last failing c. (5) THE CROSSING-LED RUN, one prime per move at exponent 1 from the void: at each state the tide's class (anchor.py's modulus and cls), the candidates its unheld primes P <= floor(cF(m0)) with Y*(P) <= floor(cF(m0)); it seats the least, and a state with none stops it. c_up is the least c on the grid 2.30, 2.35, ..., 6.75 at which its tide passes 10^4. PREDICTIONS (frozen before the code). P1 (proved by hand) the crossing test fails at every c < 53/23: c_low >= 53/23, and at c = 2.30 the 4-crossing fails with Y*(5), Y*(13), Y*(17) > 25. P2 (guess, 50%) c_low < 3. P3 (guess, 40%) c_up < 6.7315: some crossing-led run beats the chain-led. P4 (guess, 30%) c_up <= 1.5 c_low. CONTROLS, read first. C1 the crossing test fails at c = 1 (F is dammed from the void at 23). C2 it passes at c = 10831/1609 (the chain-led run's moves stay within that multiple of F to tide 10^4). C3 Lemma D over cgreedy's brute box (the primes <= 13) and 2000 random states on the primes < 300: m0 <= T(d) at every state and every d = r^e <= 10^4, r < 60, e <= 4, with v_r(lambda) <= e - 1. C4 Y* against a brute recursion (viable(a, Y) by its definition, bisected on Y) on the primes <= 200 at c = 3. THE PRINT. "c0 >= , PROVED BY THE CROSSING TEST; A c-RUN AT REACHES TIDE 10^4" (frozen as "c0 IN [, ]", which read the run as an upper bound past 10^4); c_up / c_low above 2 prints "KILL: THE CROSSING TEST DOES NOT LOCATE c0", and no crossing-led run below 6.75 prints "KILL: NO CROSSING-LED RUN BELOW THE CHAIN-LED". (Frozen with "door" where every line now says "crossing".) FINDINGS (from the printed run; the controls passed first: 309 crossings with T(d) <= 10^4; C1's first failing crossing at c = 1 is d = 2, T 3, X 5; C3 over 5780 states and 221,864 (state, crossing) pairs; C4 equal on the 45 primes <= 200). At c = 2.30 the failing crossings are 2 (X 11), 4 (X 25), 16, 3, 5 and 41, with Y*(5) = 11251, Y*(13) = 131, Y*(17) = 127739: P1 holds. c_low = 739/233 = 3.171674, the test failing at 3.1716738 at one crossing only, d = 41: T(41) = min(1681, 83) = 83, X = 738, and its one candidate 83 has Y* = 997. While 41 does not divide lambda, 83 prices itself, so the tide is at most 83 and a prime = 1 mod 41 enters by a move at most 233c; below 739/233 that is 83 alone. 83's crossing, by a move at most 738, reaches 167 (Y* 2339, past 167's own reach 2039) and 499 (Y* 10979: its one anchor in reach, 1997, has Y* 87869 = p(1997), so the anchor 10979 must be held first); else 997 is held first. P2 FAILS: c_low is 3.1717, not below 3. The crossing-led run is STUCK at the void below 2.95 and at tide 83, the 41-crossing, from 2.95 to 3.15; at 3.20 it ESCAPES, tide 10,007 after 503 seats: c_up = 3.20, P3 holds (below 6.7315) and P4 holds (ratio 1.0089). READINGS: at c_low = 739/233 itself the crossing-led run ESCAPES, tide 10,007 after 503 seats; re-tided by cgreedy.m0 on the full factor map it AGREES at all 504 states, the void included, and its largest seat / F(m0) is 739/233 exactly, the seat 739 = 18*41 + 1 taken from the tide 83. THE PRINT: c0 >= 739/233, PROVED BY THE CROSSING TEST; A c-RUN AT 3.20 REACHES TIDE 10^4. No kill fires. With the reading, c_low is met: no run from the void escapes within cF for c < 739/233 (a proof, given F's table and the lemmas), and the crossing-led run at c = 739/233 stays within cF until its tide passes 10^4. RUN RECORD. First run: C3 read p(d) past the sieve at d = r^e > 10^4 and was cut to the crossings the test uses, d <= 10^4; then 6/6, 34.5 s, 60.4 MB. With the c_low run and the Y* readings: 6/6, 34.3 s, 60.7 MB. With the re-tiding: 6/6, 34.7 s, 60.9 MB. With the void re-tided too (it had been set to 3 by hand) and THE PRINT reworded: 6/6, 35.1 s, 61.3 MB. From code/, THE PRINT giving c_low as a fraction and the largest seat placed: 6/6, 34.9 s, 60.9 MB. With "door" renamed "crossing": 6/6, 34.7 s, 60.8 MB. With each Y* reading's reach and its primes = 1 mod a within it printed (2039 and 1997 had been worked by hand): 6/6, 34.7 s, 60.9 MB. python single.py """ import os import random import time from fractions import Fraction as Fr os.environ.setdefault("OPENBLAS_NUM_THREADS", "1") import cgreedy # noqa: E402 import envelope as ev # noqa: E402 import choosy # noqa: E402 import dambar # noqa: E402 import fwide # noqa: E402 import anchor # noqa: E402 T = ev.T CHECKS = [] 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(n): s = bytearray([1]) * (n + 1) s[0] = s[1] = 0 for i in range(2, int(n ** 0.5) + 1): if s[i]: s[i * i::i] = bytearray(len(range(i * i, n + 1, i))) return s class World: def __init__(self, F): self.F = F self.W = 7 * F[T] + 7 self.S = sieve(self.W) self.small = [q for q in range(3, T + 1) if self.S[q]] def Fx(self, t): return self.F[max(t, 4)] def cap(self, c, t): return (c.numerator * self.Fx(t)) // c.denominator def p(self, s): n = s + 1 while not self.S[n]: n += s return n def ystar(self, c): """{a: Y*(a)} for the odd primes a <= T; W + 1 stands for no Y within the sieve.""" Y = {} INF = self.W + 1 for a in reversed(self.small): worst = 0 s = a while s <= T: Z = self.cap(c, s) need, b = INF, s + 1 while b <= self.W: if self.S[b]: yb = Y.get(b, 0) if b <= Z and yb <= Z: need = 0 break need = min(need, max(b, yb)) if b >= need: break b += s worst = max(worst, need) if worst >= INF: break s *= a Y[a] = worst return Y def crossings(self): out = [] for r in [2] + self.small: e = 1 while True: d = r ** e if d > T: break pt = 2 ** (e + 2) if r == 2 else r ** (e + 1) Td = min(pt, self.p(d)) if Td <= T: out.append((d, r, e, Td)) e += 1 return out def test(self, c, Y=None, why=False): Y = self.ystar(c) if Y is None else Y bad = [] for d, r, e, Td in self.CROSSINGS: X = self.cap(c, Td) ok = False a = d + 1 while a <= X: if self.S[a] and Y.get(a, 0) <= X: ok = True break a += d if not ok: bad.append((d, Td, X)) if not why: return False, bad return not bad, bad def crossing_run(w, c, Y, log=None): """The crossing-led run: (escaped, final tide, seats); log gathers (m0, seat) per move.""" held, vN, seats = set(), {}, 0 while True: m0, r, kind = choosy.tide(held, vN) if m0 > T: return True, m0, seats s = anchor.modulus(m0, r, kind, vN) X = w.cap(c, m0) P = None n = s + 1 while n <= X: if w.S[n] and n not in held and Y.get(n, 0) <= X: P = n break n += s if P is None: return False, m0, seats held.add(P) seats += 1 if log is not None: log.append((m0, P)) for q, e in choosy.factor(P - 1).items(): if e > vN.get(q, 0): vN[q] = e def brute_y(w, c, top): """Y* by its definition on the primes <= top, recursing upward.""" memo = {} def viable(a, Yb): if a > T: return True key = (a, Yb) if key in memo: return memo[key] memo[key] = False s, ok = a, True while s <= T and ok: Z = w.cap(c, s) M = max(Yb, Z) ok = any(w.S[b] and viable(b, M) for b in range(s + 1, M + 1, s)) s *= a memo[key] = ok return ok out = {} for a in [q for q in w.small if q <= top]: lo, hi = 0, w.W + 1 if viable(a, 0): out[a] = 0 continue if not viable(a, w.W): out[a] = w.W + 1 continue lo, hi = 0, w.W while hi - lo > 1: mid = (lo + hi) // 2 if viable(a, mid): hi = mid else: lo = mid out[a] = hi return out def main(): t0 = time.time() fwide.widen(fwide.PMAX) F = dambar.f_table(fwide.tau_wide(fwide.PMAX, T)) assert all(F[t] is not None for t in range(4, T + 1)) w = World(F) w.CROSSINGS = w.crossings() print(f"F fixed on 4..{T}; {len(w.CROSSINGS)} crossings with T(d) <= {T}; " f"sieve to {w.W} ({time.time() - t0:.1f} s)") print("CONTROLS") ok1, bad1 = w.test(Fr(1), why=True) check("C1 the crossing test fails at c = 1", not ok1, f"first failing crossing {bad1[0] if bad1 else None}") cch = Fr(10831, 1609) ok2, bad2 = w.test(cch, why=True) check("C2 the crossing test passes at c = 10831/1609", ok2, f"failing {bad2[:3]}") rng = random.Random(1) states = cgreedy.brute_box(13) pr = [p for p in cgreedy.PR if p < 300] for _ in range(2000): mf = {2: rng.randint(0, 8)} if rng.random() < 0.7 else {} for q in rng.sample(pr[1:], rng.randint(1, 12)): mf[q] = rng.randint(1, 3) states.append({q: a for q, a in mf.items() if a}) viol, tested = [], 0 rs = [r for r in cgreedy.PR if r < 60] for mf in states: lf = cgreedy.lam(mf) m0 = cgreedy.m0(mf) for r in rs: for e in range(1, 5): d = r ** e if d <= T and lf.get(r, 0) <= e - 1: pt = 2 ** (e + 2) if r == 2 else r ** (e + 1) tested += 1 if m0 > min(pt, w.p(d)): viol.append((mf, d)) check("C3 Lemma D: m0 <= T(d) wherever v_r(lambda) <= e - 1", not viol, f"{len(states)} states, {tested} (state, crossing) pairs, " f"first violation {viol[:1]}") Y3 = w.ystar(Fr(3)) B3 = brute_y(w, Fr(3), 200) diff = [a for a in B3 if min(B3[a], w.W + 1) != min(Y3[a], w.W + 1)] check("C4 Y* against the brute recursion, primes <= 200 at c = 3", not diff, f"{len(B3)} primes, differing {diff[:5]}") if not all(ok for _, ok in CHECKS): print("CONTROL FAILED: nothing below is read.") raise SystemExit(1) print("THE CROSSING TEST") c23 = Fr(23, 10) Y = w.ystar(c23) ok, bad = w.test(c23, Y, why=True) four = [b for b in bad if b[0] == 4] ys = {a: Y.get(a) for a in (5, 13, 17)} p1a = (not ok and bool(four) and four[0][2] == 25 and all(v > 25 for v in ys.values())) print(f" c = 2.30: failing crossings {bad[:6]}; Y*(5, 13, 17) = {ys}") lo, hi = Fr(1), cch while hi - lo > Fr(1, 10 ** 7): mid = (lo + hi) / 2 mid = Fr(round(mid * 10 ** 8), 10 ** 8) if w.test(mid)[0]: hi = mid else: lo = mid fv = sorted(set(F[t] for t in range(4, T + 1))) crit = min(Fr(int(lo * f) + 1, f) for f in fv) okc = crit <= hi and w.test(crit)[0] and not w.test(lo)[0] check("the critical ratio above the last failing c passes", okc, f"c_low = {crit} = {float(crit):.6f}, last failing {float(lo):.7f}") Yl = w.ystar(lo) _, badl = w.test(lo, Yl, why=True) check("P1 c_low >= 53/23, the 4-crossing failing at 2.30 with " "Y*(5), Y*(13), Y*(17) > 25", p1a and crit >= Fr(53, 23)) print(f" crossings failing just below c_low: {badl[:8]}") for d, Td, X in badl[:4]: cands = [(a, Yl.get(a, 0)) for a in range(d + 1, X + 1, d) if w.S[a]] print(f" crossing {d}: T {Td}, X {X}, candidates (a, Y*) " f"{cands[:10]}") print(f" P2 (guess) c_low < 3: " f"{'HOLDS' if crit < 3 else 'FAILS'}, c_low {float(crit):.4f}") print("THE CROSSING-LED RUN") grid = [Fr(230 + 5 * i, 100) for i in range(int((675 - 230) / 5) + 1)] c_up, rows = None, [] for c in grid: Yc = w.ystar(c) esc, tide, seats = crossing_run(w, c, Yc) rows.append((c, esc, tide, seats)) if esc: c_up = c break for c, esc, tide, seats in rows[::max(1, len(rows) // 12)] + rows[-1:]: print(f" c = {float(c):.2f}: {'ESCAPES' if esc else 'STUCK'} at " f"tide {tide} after {seats} seats") if c_up is not None: print(f" P3 (guess) c_up < 6.7315: " f"{'HOLDS' if c_up < cch else 'FAILS'}, c_up {float(c_up):.2f}") print(f" P4 (guess) c_up <= 1.5 c_low: " f"{'HOLDS' if c_up <= Fr(3, 2) * crit else 'FAILS'}, " f"ratio {float(c_up / crit):.4f}") print("READINGS") log = [] esc, tide, seats = crossing_run(w, crit, w.ystar(crit), log) print(f" the crossing-led run at c_low = {crit} itself: " f"{'ESCAPES' if esc else 'STUCK'} at tide {tide} after {seats} " f"seats") held, worst, at, agree = set(), Fr(0), None, True for m0, P in log: m_full = cgreedy.m0({p: 1 for p in held}) agree = agree and m_full == m0 if Fr(P, w.Fx(m_full)) > worst: worst, at = Fr(P, w.Fx(m_full)), (m_full, P) held.add(P) agree = agree and cgreedy.m0({p: 1 for p in held}) == tide print(f" re-tided by cgreedy.m0 on the full factor map: " f"{'AGREES' if agree else 'DIFFERS'} at all {len(log) + 1} states; " f"largest seat / F(m0) {worst} = {float(worst):.6f}, within " f"c_low: {worst <= crit}, at (tide, seat) {at}") for a in (83, 167, 499, 1997): reach = w.cap(lo, a) anchors = [b for b in range(2 * a + 1, reach + 1, 2 * a) if w.S[b]] print(f" Y*({a}) just below c_low: {Yl.get(a)}; its reach " f"{reach}, the primes = 1 mod {a} within it {anchors}") print("THE PRINT") if c_up is None: print(" KILL: NO CROSSING-LED RUN BELOW THE CHAIN-LED") else: print(f" c0 >= {crit}, PROVED BY THE CROSSING TEST; A " f"c-RUN AT {float(c_up):.2f} REACHES TIDE 10^4") if c_up / crit > 2: print(" KILL: THE CROSSING TEST DOES NOT LOCATE c0") 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()