compbound.py
Checks: FLATTEN: The takeover depth grows at least as r^(3/2) theorem; rule; pattern.
Cited on: FLATTEN.
To run it: save compbound.py, with band.py, bandend.py, bandfamily.py, circlemean.py, flatten.py, prunerr.py, takeph.py beside it; needs mpmath, numpy, sympy.
"""compbound.py -- at the takeover theorem's depth J*, does a closed-form
lower bound put every non-champion pure product above F_e's circle mean?
QUESTION. At J* = (4e - 1) l - 1, l = r - 2, height(F_e) < H_ch (the takeover
theorem) and the cell (J* + r, J*) fails once every other
admissible pure product is above F_e. takeph.py read that by enumeration
to r = 25. A bound that sees a shape only through a few numbers would
carry it to every rank; at which orders s does this one, at e = 3, 4?
BY HAND (re-derived before the code). A shape: k >= 0, parts g_i >= 2,
k + sum(g_i - 1) <= r - 1; s = #even parts, o = #odd parts, Pi = prod
over even parts of g/2. After x -> -x, [g](-x) = (1 + x^g)/(1 + x) at odd
g and (1 - x)[g/2](x^2) at even g, so up to sign
P = (1 + x)^(J + k - o) (1 - x)^s prod_even [g/2](x^2) prod_odd (1 + x^g).
On x = e^(2iu), P = e^(iuN) (-i)^s 2^(J+k+s) Pi cos^(J+k-o) u sin^s u Phi,
Phi = prod_even D_(g/2)(2u) prod_odd cos(gu), D_j(y) = sin(jy)/(j sin y).
The test w = x^m (1 + x)^p (1 - x)^q, 2m + p + q = N, q = s mod 2,
p = J + k mod 2 (the centring itself: 2m + p + q = N) gives
|<P, w>| = (2^(J+k+s+p+q)/pi) Pi B(al, be) |E_nu Phi|,
al = (s + q + 1)/2, be = (J + k - o + p + 1)/2,
nu ~ cos^(2be - 1) sin^(2al - 1) on [0, pi/2]. Each factor of Phi has
|f| <= 1, so 1 - Phi <= sum (1 - f); 1 - D_j(y) <= (j^2 - 1) y^2/6, 1 -
cos(gu) <= g^2 u^2/2, u <= tan u, E_nu tan^2 u = al/(be - 1). With T =
sum_even (g^2 - 4)/6 + sum_odd g^2/2,
height(P) >= LB = (2^(J+k+s+p+q)/pi) Pi B(al, be) (1 - T al/(be - 1))_+
/ |w|_1,
|w|_1 = 2^p (q = 0), 2 C(p, floor(p/2)) (q = 1). The bound must die at one
odd part g with g^2/2 >~ 4e - 1: a part 5 at e = 3, a part 7 at e = 4.
PREDICTIONS (frozen before the code). P1 at e = 3 (odd r = 21..33) every
order s >= r - 4 clears, least LB/mean(F_e) >= 1.79 (order r - 2). P2 at
e = 3 some order s <= r - 5 fails, the first failure (largest s) a shape
with a part 5. P3 at e = 4 (odd r = 35..51) the largest failing order is
r - 7 or r - 6, its shape with a part 7 or two parts 5. P4 the direct
scan (exact ph, r = 27 timed, then odd r to 35 if r = 27 runs under 30 s)
reads height(F_e) < ph at each rank run.
KILL. K1 at e = 3 a least LB/mean <= 1 at an order s >= r - 4. K2 the
orders failing, printed per rank of the e = 4 arm: non-empty kills the
bound as the whole proof. K3 a rank of P4's arm with height(F_e) >= ph.
CONTROLS, read first. C1 at r = 11, 13, 21, 25, every shape: LB <= exact
height; at T = 0 the closed form equals |<P, w>|/|w|_1 in integers at
p = p0, p0 + 2, p0 + 10 (relative 1e-9). PLANTS: Pi doubled must give LB
> height somewhere; m moved off centre by one must break the equality at
every T = 0 shape. (Frozen was p of the wrong parity; replaced before the
run: 2m + p + q = N makes p = J + k mod 2 the centring itself.) The T = 0
shapes have Pi = 1, o = 0, Phi = 1: Pi, o and the remainder are tested
only through LB <= height. C2 mean(F_e)/H_ch against takeph's READ
0.7370, 0.7016, 0.6709 (r = 21, 23, 25); mean >= exact height(F_e). C3 at
r = 21, 25 the frontier sweep (a key off the frontier is evaluated only
when the frontier key dominating it fails) against every key evaluated:
the same failing keys and per-order least.
Floats: lgamma in log space; a ratio within 1e-6 above 1 counts as
failing.
FINDINGS (copied from the printed output).
(1) C1 holds at r = 11, 13, 21, 25: LB <= height at every shape, the
T = 0 closed form equal to the integer pairing at all 195, 270, 690,
972 (shape, p) pairs; the m plant caught at every T = 0 shape, the
Pi plant at 391, 775, 8817, 21939 shapes. C2 reproduces 0.7370,
0.7016, 0.6709, mean >= height(F_e) (0.5292, 0.5134, 0.4966).
(2) K1 misses: at e = 3 (odd r = 21..33) orders r - 2, r - 3, r - 4 clear,
least LB/mean 1.7226 (r = 21) .. 2.2225 (r = 33), always at order r - 2
(k=0 2^(r-2), p = 10). P1's 1.79 misses at r = 21 (1.7226;
1.8154 at r = 23): the centred test with q = s mod 2 sits below takeph's best,
which also shifts off centre and tries the other q.
(3) K2 fires, as P2 and P3 said: at e = 3 the first failure is order
r - 5 at the part 5 (k=0 2^(r-5) 5, LB/mean 0.465 .. 0.166 over r = 21..
33); order r - 6 clears to r = 29 (1.013) and fails from r = 31; at
e = 4 (odd r = 35..51) orders r - 2 .. r - 6 clear (least 1.9656 ..
2.4075, at r - 2) and the first failure is r - 7 at the part 7 (LB/mean
0.014 .. 0.000). At each failing order printed (r - 5 .. r - 10) the
least shape is the order-s champion (1 + x)^J (1 - x)^s with one odd
part g = 5, 7 or 9 traded in.
(4) K3 misses (P4 holds): the direct scan at odd r = 27..35 reads ph =
H_ch, the champion, and ph/height(F_e) = 2.0854, 2.1613, 2.2402,
2.3216, 1.7969, so J_hi(r) >= J* there, computed.
READS. The failing part sits where the hand's remainder put it (g^2/2 >~
4e - 1) and near the half wave of the champion's oscillation: u
concentrates at u0 = arcsin(1/(2 sqrt(e))): g u0 = 1.46 at g = 5, e = 3 and
1.77 at g = 7, e = 4, near pi/2 (cos 0.106, -0.197), so E cos(gu) itself
is small there, not only its bound (a TRANSPLANT from the Gaussian
concentration, unread; sin^2 u0 = 1/(4e) is U's mean at p = 0 only
nearly (0.0756 against 0.0833 at 2^16 5, r = 21), and a failing shape's
best p moves it).
(5) The failing keys (a key failing when LB at its least Pi does)
number 14, 26, 45, 87, 154, 260, 430 at odd r = 21..33 and 141, 221,
371, 584, 895, 1376, 2035, 2994, 4332 at odd r = 35..51; C3 holds at
r = 21, 25 (14, 45). The least-Pi shape carries an odd part >= 5 at
all but 0, 0, 0, 1, 2, 3, 6 of them (r = 21..33) and 0, 0, 0, 0, 1,
4, 7, 15, 32 (r = 35..51): parts 3 only (k=0 2^18 3 3 3 3 at r = 27)
or a large even part (k=0 2^21 12 and 2^19 14 at r = 33, 2^27 16 at
r = 43, 2^31 14 3 at r = 47).
RUN RECORD. 74.2 s (the scan 36.5 s of it), peak commit 71.0 MB (one k
of the key table at a time).
"""
import math
import os
import sys
import time
os.environ.setdefault("OPENBLAS_NUM_THREADS", "1")
import mpmath as mp # noqa: E402
import flatten # noqa: E402
import circlemean # noqa: E402
import takeph # noqa: E402
LN2 = math.log(2)
LNPI = math.log(math.pi)
def stats(k, parts):
"""(s, o, Pi, 6T) of a shape; 6T is an integer."""
s = o = 0
pi = 1
t6 = 0
for g in parts:
if g % 2:
o += 1
t6 += 3 * g * g
else:
s += 1
pi *= g // 2
t6 += g * g - 4
return s, o, pi, t6
def keys(r, k):
"""Every non-champion shape with k extra (x - 1)'s grouped by (s, o,
6T), keeping the least Pi and one shape attaining it: the bound is Pi
times a function of the key (s, k, o, 6T). One k at a time, so the
table never holds every k at once."""
top = r - 1
out = {}
stack = [((), top - k, top - k, 0, 0, 1, 0)]
while stack:
parts, left, cap, s, o, pi, t6 = stack.pop()
if not (k == 0 and s == top):
key = (s, o, t6)
if key not in out or pi < out[key][0]:
out[key] = (pi, parts)
for x in range(min(left, cap), 0, -1):
g = x + 1
if g % 2:
stack.append((parts + (g,), left - x, x, s, o + 1, pi,
t6 + 3 * g * g))
else:
stack.append((parts + (g,), left - x, x, s + 1, o,
pi * (g // 2), t6 + g * g - 4))
return out
def log_w1(p, q):
if q == 0:
return p * LN2
return LN2 + math.lgamma(p + 1) - math.lgamma(p // 2 + 1) \
- math.lgamma(p - p // 2 + 1)
def log_lb(J, s, k, o, pi, t6, p, plant=False):
"""log LB at test exponent p (-inf where 1 - T tau <= 0)."""
q = s % 2
al = (s + q + 1) / 2
be = (J + k - o + p + 1) / 2
f = 1 - t6 / 6 * al / (be - 1)
if f <= 0:
return -math.inf
lpi = math.log(2 * pi if plant else pi)
return ((J + k + s + p + q) * LN2 - LNPI + lpi + math.lgamma(al)
+ math.lgamma(be) - math.lgamma(al + be) + math.log(f)
- log_w1(p, q))
def best_lb(J, s, k, o, pi, t6, plant=False, patience=40):
"""(log LB, p) maximised over p = J + k mod 2, scanned upward until the
bound has fallen for `patience` steps past its best."""
q = s % 2
al = (s + q + 1) / 2
# 1 - T tau > 0 needs be > 1 + T al: start at the least such p
pmin = math.floor(2 * (t6 / 6 * al + 1) - (J + k - o + 1)) + 1
p = max((J + k) % 2, pmin)
p += (p - J - k) % 2
best = (-math.inf, p)
since = 0
while since < patience:
v = log_lb(J, s, k, o, pi, t6, p, plant)
if v > best[0]:
best, since = (v, p), 0
else:
since += 1
p += 2
return best
def int_pairing(c, J, k, parts, p, shift=0):
"""(|<P, w>|, |w|_1) in integers, P the flipped coefficients of c, w =
x^m (1 + x)^p (1 - x)^q centred (shift: the PLANT, m moved)."""
s = takeph.order(parts)
q = s % 2
cf = [v if i % 2 == 0 else -v for i, v in enumerate(c)]
n = len(cf) - 1
v = [math.comb(p, i) for i in range(p + 1)]
if q:
v = [a - b for a, b in zip(v + [0], [0] + v)]
m = (n - p - q) // 2 + shift
tot = sum(cf[m + i] * a for i, a in enumerate(v) if 0 <= m + i <= n)
return abs(tot), sum(abs(a) for a in v)
def c1(r):
"""LB <= height at every shape; T = 0 closed form against integers;
the two plants."""
J = takeph.theorem_J(r)
worst = -math.inf
planted = 0
eq = 0
eqbad = 0
off = 0
offcaught = 0
for c, k, parts in takeph.walk_all(J, r):
if (k, parts) == takeph.champion(r):
continue
s, o, pi, t6 = stats(k, parts)
lh = math.log(flatten.height(c))
lb = best_lb(J, s, k, o, pi, t6)[0]
worst = max(worst, lb - lh)
if best_lb(J, s, k, o, pi, t6, plant=True)[0] > lh + 1e-9:
planted += 1
if t6 == 0:
p0 = (J + k) % 2
for p in (p0, p0 + 2, p0 + 10):
num, w1 = int_pairing(c, J, k, parts, p)
want = math.exp(log_lb(J, s, k, o, pi, t6, p) - lh)
got = num / w1 / flatten.height(c)
eq += 1
if abs(got - want) > 1e-9 * want:
eqbad += 1
num, w1 = int_pairing(c, J, k, parts, p0, shift=1)
want = math.exp(log_lb(J, s, k, o, pi, t6, p0) - lh)
off += 1
if abs(num / w1 / flatten.height(c) - want) > 1e-9 * want:
offcaught += 1
return worst, planted, eq, eqbad, off, offcaught
def bound_rank(r, lbar=None):
"""Per order s the least LB/mean(F_e) over non-champion shapes; a key
fails at or below the log bar lbar (default the mean)."""
J, e = takeph.theorem_J(r), takeph.theorem_e(r)
lmean = float(circlemean.log_mean(r, J, e))
lhch = math.log(circlemean.exact_Hch(r, J))
bar = (lmean if lbar is None else lbar) + math.log(1 + 1e-6)
# at fixed (s, k, o) LB rises with Pi and falls with T: the frontier,
# each key with a Pi below every key of larger T, holds each order's
# least; a key off it is above the frontier key that dominates it, so
# it is evaluated only when that key fails
nkeys = nfront = 0
by_s = {}
failing = []
for k in range(r):
groups = {}
for (s, o, t6), (pi, parts) in keys(r, k).items():
groups.setdefault((s, o), []).append((t6, pi, parts))
nkeys += 1
for (s, o), lst in groups.items():
low, low_v = math.inf, None
for t6, pi, parts in sorted(lst, reverse=True):
if pi < low:
v, p = best_lb(J, s, k, o, pi, t6)
low, low_v = pi, v
nfront += 1
if s not in by_s or v < by_s[s][0]:
by_s[s] = (v, p, k, parts)
elif low_v > bar:
continue
else:
v, p = best_lb(J, s, k, o, pi, t6)
if v <= bar:
failing.append((s, k, o, t6, pi, parts))
rows = {}
for s in sorted(by_s, reverse=True):
v, p, k, parts = by_s[s]
rows[s] = (math.exp(v - lmean) if v > -math.inf else 0.0, p,
takeph.name(k, parts))
return J, e, math.exp(lmean - lhch), (nkeys, nfront), rows, failing
def main():
t0 = time.time()
ok = True
for r in (11, 13, 21, 25):
worst, planted, eq, eqbad, off, offc = c1(r)
print("C1 r = %d: max log(LB/height) %.4f; T = 0 equality %d of %d"
" off; PLANT m moved by one caught %d of %d; PLANT Pi doubled"
" LB > height at %d shapes [%.1f s]"
% (r, worst, eqbad, eq, offc, off, planted,
time.time() - t0), flush=True)
ok &= worst <= 1e-9 and eqbad == 0 and offc == off and planted > 0
print("C1 %s" % ("holds" if ok else "FAILS"), flush=True)
for r, want in ((21, 0.7370), (23, 0.7016), (25, 0.6709)):
J, e = takeph.theorem_J(r), takeph.theorem_e(r)
m = float(mp.exp(circlemean.log_mean(r, J, e))) \
/ circlemean.exact_Hch(r, J)
hf = circlemean.exact_height_F(r, J, e) / circlemean.exact_Hch(r, J)
print("C2 r = %d: mean(F_e)/H_ch %.4f (takeph %.4f), height(F_e)/H_ch"
" %.4f, mean >= height %s" % (r, m, want, hf, m >= hf),
flush=True)
ok &= abs(m - want) < 6e-5 and m >= hf
for r in (21, 25):
J, e, mr, nk, rows, failing = bound_rank(r)
lmean = float(circlemean.log_mean(r, J, e))
bar = lmean + math.log(1 + 1e-6)
every, least = 0, {}
for k in range(r):
for (s, o, t6), (pi, parts) in keys(r, k).items():
v = best_lb(J, s, k, o, pi, t6)[0]
every += v <= bar
least[s] = min(least.get(s, math.inf), v)
same = every == len(failing) and all(
abs(math.exp(least[s] - lmean) - rows[s][0]) < 1e-12 for s in rows)
print("C3 r = %d: every key evaluated, %d failing (frontier sweep %d),"
" per-order least the same %s" % (r, every, len(failing), same),
flush=True)
ok &= same
k1 = []
for r in list(range(21, 34, 2)) + list(range(35, 52, 2)):
J, e, mr, nk, rows, failing = bound_rank(r)
fail = [s for s, (q, p, nm) in rows.items() if q <= 1 + 1e-6]
top = [s for s in rows if s >= r - 4]
lt = min(top, key=lambda s: rows[s][0])
print("r = %2d e = %d J* = %3d: %s keys, frontier; mean/H_ch %.4f;"
" least over"
" s >= r-4 %.4f at s = r-%d (%s, p = %d); orders failing: %s"
" [%.1f s]"
% (r, e, J, nk, mr, rows[lt][0], r - lt, rows[lt][2],
rows[lt][1], ["r-%d" % (r - s) for s in fail],
time.time() - t0), flush=True)
print(" by order: %s" % ", ".join(
"r-%d %.3f (%s)" % (r - s, q, nm)
for s, (q, p, nm) in sorted(rows.items(), reverse=True)[:9]),
flush=True)
if fail:
s = max(fail)
print(" first failure r-%d: %s" % (r - s, rows[s][2]),
flush=True)
rest = [f for f in failing if not any(g % 2 and g >= 5 for g in f[5])]
print(" failing keys %d, %d of them without an odd part >= 5"
" in the least-Pi shape%s" % (
len(failing), len(rest), (": " + ", ".join(
takeph.name(f[1], f[5]) for f in rest))
if 0 < len(rest) <= 8 else ""), flush=True)
if e == 3 and rows[lt][0] <= 1 + 1e-6:
k1.append(r)
print("K1 %s" % ("fires at %s" % k1 if k1 else "misses"), flush=True)
k3 = []
for r in range(27, 36, 2):
t1 = time.time()
J, e = takeph.theorem_J(r), takeph.theorem_e(r)
best, hch, by_s = takeph.read_cell(J, r)
hf = circlemean.exact_height_F(r, J, e)
print("SCAN r = %d e = %d J* = %d: ph/H_ch %.4f at %s; ph/height(F_e)"
" %.4f [%.1f s]"
% (r, e, J, best[0] / hch, takeph.name(best[1], best[2]),
best[0] / hf, time.time() - t1), flush=True)
if hf >= best[0]:
k3.append(r)
if r == 27 and time.time() - t1 > 30:
print("SCAN stops: r = 27 ran over 30 s")
break
print("K3 %s" % ("fires at %s" % k3 if k3 else "misses"))
print("%.1f s" % (time.time() - t0))
return not ok or bool(k1) or bool(k3)
if __name__ == "__main__":
sys.exit(1 if main() else 0)