#!/usr/bin/env python3
"""
ch25-verify.py — Principia Orthogona, Book 4, Chapter 25
"The Selection Principle, or What the Sheet Pays to Close"

Regenerates every number in the chapter. Repo rule: a published number must be
regenerable by a tool.  Run: python3 ch25-verify.py   Requires: sympy.
"""
from math import log
import sympy as sp

FAIL = []
def ok(label, cond):
    if not cond: FAIL.append(label)
    print(f"  [{'PASS' if cond else 'FAIL'}] {label}")

def shells(T):
    """Geometrically distinct Goldberg shells GP(m,n), 0<=n<=m, m>0, with m^2+mn+n^2=T.
       chiral = the mirror image is a different shell (n != 0 and n != m)."""
    out = []
    m = 0
    while m*m <= T:
        m += 1
        for n in range(0, m+1):
            if m*m + m*n + n*n == T:
                out.append((m, n, n != 0 and n != m))
    return out

def W(T):
    """Microstate count: enantiomers are distinct states, so a chiral class counts twice."""
    return sum(2 if c else 1 for _, _, c in shells(T))

def dchi(T):
    """d_1(T) - d_2(T): divisors congruent to 1 minus those congruent to 2, mod 3."""
    ds = sp.divisors(T)
    return sum(1 for d in ds if d % 3 == 1) - sum(1 for d in ds if d % 3 == 2)

# ----------------------------------------------------------------------
print("="*72)
print("[1] The closable T are the Loeschian numbers; 10T+2 sites, 12 pentagons")
print("="*72)
T_ok = [T for T in range(1, 250) if shells(T)]
print(f"      first closable T: {T_ok[:16]}")
ok("T=1 is GP(1,0), the dodecahedron, 12 sites",
   shells(1) == [(1, 0, False)] and 10*1+2 == 12)
ok("every closable shell has 12 pentagons and 10T-10 hexagons",
   all(12 + (10*T-10) == 10*T + 2 for T in T_ok))
ok("T=2 and T=5 are NOT closable (inert primes 2 and 5, both 2 mod 3)",
   not shells(2) and not shells(5))

# ----------------------------------------------------------------------
print()
print("="*72)
print("[2] THE ENTROPY.  W(T) = d_1(T) - d_2(T), exactly.")
print("="*72)
mism = [T for T in range(1, 1000) if shells(T) and W(T) != dchi(T)]
print(f"      checked T = 1..999 ; mismatches: {mism if mism else 'none'}")
ok("W(T) = d_1(T) - d_2(T) for every closable T below 1000", not mism)
ok("W(T) = 0 exactly when T is not closable",
   all((dchi(T) == 0) == (not shells(T)) for T in range(1, 400)))
print()
print("       T   sites   W   S/k = ln W    shells")
print("      " + "-"*62)
for T in T_ok[:14]:
    s = shells(T)
    lbl = ", ".join(f"GP({m},{n}){'*' if c else ''}" for m, n, c in s)
    print(f"      {T:3d} {10*T+2:6d} {W(T):3d}   {log(W(T)):8.4f}    {lbl}")
print("      (* = chiral: the mirror image is a different shell)")
first2 = next(T for T in T_ok if len(shells(T)) > 1)
print(f"\n      first T carrying two distinct shells: T = {first2}  -> {shells(first2)}")
ok("T=49 is the first T with two distinct shells, W=3", first2 == 49 and W(49) == 3)
ok("49 = 7^2 and 7 is a split prime (7 = 1 mod 3)", 49 == 7**2 and 7 % 3 == 1)

# ----------------------------------------------------------------------
print()
print("="*72)
print("[3] Chirality is the split primes, and it is worth k ln 2")
print("="*72)
for T in [3, 4, 7, 13, 21]:
    s = shells(T)
    chi = any(c for _, _, c in s)
    fac = sp.factorint(T)
    split = [p for p in fac if p % 3 == 1]
    print(f"      T={T:3d}  {str(fac):18s} split primes {str(split):10s} chiral={chi}  W={W(T)}")
ok("T=3 (ramified) is achiral, W=1", W(3) == 1 and not any(c for _,_,c in shells(3)))
ok("T=7 (split) is chiral, W=2", W(7) == 2 and all(c for _,_,c in shells(7)))
ok("T=21=3*7 inherits chirality from the split factor 7", W(21) == 2)
print(f"\n      entropy of one enantiomeric pair: ln 2 = {log(2):.6f} k per shell")

# ----------------------------------------------------------------------
print()
print("="*72)
print("[4] A standard 216-sphere set: what it can build, and what it prefers")
print("="*72)
budget = 216
fit = [T for T in T_ok if 10*T + 2 <= budget]
print(f"      T fitting in {budget} spheres: {fit}")
ok("the 216-set family is T in {1,3,4,7,9,12,13,16,19,21} (Ch 21, Ex. 21.3)",
   fit == [1, 3, 4, 7, 9, 12, 13, 16, 19, 21])
big = max(fit)
print(f"      largest: T={big}, GP{shells(big)[0][:2]}, {10*big+2} sites, "
      f"{budget - (10*big+2)} spheres left over, chiral={any(c for _,_,c in shells(big))}")
ok("largest shell in a 216-set is GP(4,1) at 212 sites, and it is chiral",
   big == 21 and 10*big+2 == 212 and any(c for _, _, c in shells(21)))
chiral_T = [T for T in fit if any(c for _, _, c in shells(T))]
achiral_T = [T for T in fit if not any(c for _, _, c in shells(T))]
print(f"      chiral  (W=2, S/k=ln2): T = {chiral_T}")
print(f"      achiral (W=1, S/k=0)  : T = {achiral_T}")
ok("chiral and achiral partition the 216-family with no overlap",
   sorted(chiral_T + achiral_T) == fit and not set(chiral_T) & set(achiral_T))

# ----------------------------------------------------------------------
print()
print("="*72)
print("[5] The partition function, CONDITIONAL on a log-cost assumption")
print("="*72)
print("      If the cost of a shell is E(T) = e0 * log(10T+2) + const, then")
print("      Z(s) = sum_T W(T) T^-s = zeta(s) * L(s, chi_-3).")
# The coefficient identity in [2] IS the theorem: the Dirichlet series with
# coefficients d_1(T)-d_2(T) is zeta(s)L(s,chi_-3) by Euler factorisation.
# Below is a convergence illustration, with the truncation shown rather than hidden.
def sieve_dchi(N):
    a = [0]*(N+1)
    for d in range(1, N+1):
        c = 1 if d % 3 == 1 else (-1 if d % 3 == 2 else 0)
        if c:
            for m in range(d, N+1, d): a[m] += c
    return a
s0 = 2.0
for N in (10**4, 10**5, 10**6):
    a = sieve_dchi(N)
    lhs = sum(a[T]/T**s0 for T in range(1, N+1))
    print(f"      N = {N:>8d}:  sum_(T<=N) W(T)/T^2 = {lhs:.10f}")
zeta = float(sp.N(sp.zeta(s0)))
L = sum((1 if n % 3 == 1 else (-1 if n % 3 == 2 else 0))/n**s0 for n in range(1, 2000000))
print(f"      limit  zeta(2)*L(2,chi_-3)          = {zeta*L:.10f}")
ok("partial sums increase toward zeta(2)L(2,chi_-3), residual falling with N",
   abs(lhs - zeta*L)/(zeta*L) < 3e-6)
ok("W(T) equals the coefficient of zeta(s)L(s,chi_-3) exactly (the real check, from [2])",
   all(W(T) == dchi(T) for T in range(1, 300) if shells(T)))
ok("this is an identity about W, NOT a derivation of the cost function", True)

# ----------------------------------------------------------------------
print()
print("="*72)
print("[6] What entropy buys, and what it does not")
print("="*72)
kln2 = log(2)
print(f"      S_chiral - S_achiral = ln 2 = {kln2:.4f} k")
print(f"      free-energy bias at T_room:  -T dS = -k T ln 2 = -{kln2:.4f} kT")
print("      Elastic energy of a closed shell scales with its site count; the")
print("      entropy difference does not scale at all. So the bias is a")
print("      TIE-BREAKER between near-degenerate shells, not a determinant.")
ok("ln 2 is O(1) while the site count is O(10T) — entropy cannot outrun elasticity",
   kln2 < 1 and 10*21+2 > 200)


# ----------------------------------------------------------------------
print()
print("="*72)
print("[7] Maximum-entropy shells, 1729, and the borrowed strategy")
print("="*72)
rec, records = 0, []
for T in range(1, 4000):
    w = W(T)
    if w > rec:
        rec = w; records.append((T, w, dict(sp.factorint(T))))
print("      record-setters for W below 4000:")
for T, w, f in records:
    print(f"        T={T:5d}  W={w:2d}  {f}  sites {10*T+2}")
ok("the record-setters below 4000 are 1, 7, 49, 91, 637, 1729",
   [r[0] for r in records] == [1, 7, 49, 91, 637, 1729])
ok("1729 = 7*13*19 with all three primes split (1 mod 3), so W = 2^3 = 8",
   sp.factorint(1729) == {7: 1, 13: 1, 19: 1}
   and all(p % 3 == 1 for p in (7, 13, 19)) and W(1729) == 8)

def is_carmichael(n):
    f = sp.factorint(n)
    if len(f) < 3 or any(e > 1 for e in f.values()): return False
    return all((n-1) % (p-1) == 0 for p in f)
ok("1729 satisfies Korselt: squarefree and p-1 | n-1 for every p", is_carmichael(1729))
ok("1729 is also the taxicab number 1^3+12^3 = 9^3+10^3",
   1 + 12**3 == 1729 == 9**3 + 10**3)

carms = [n for n in range(3, 20000, 2) if is_carmichael(n)][:8]
print(f"\n      first eight Carmichael numbers: {carms}")
closable = [n for n in carms if W(n) > 0]
print(f"      of those, closable shell sizes: {closable}")
print(f"      not closable:                   {[n for n in carms if W(n) == 0]}")
ok("exactly the Carmichael numbers with all prime factors split are closable",
   all((W(n) > 0) == all(p % 3 == 1 for p in sp.factorint(n)) for n in carms))
ok("each closable Carmichael number in this range has W = 8 (three split primes)",
   all(W(n) == 8 for n in closable))

# The Larsen-shaped question: is there a max-entropy shell in every (x,2x)?
import bisect
print("\n      T = p*q*r in (x,2x) with three distinct split primes:")
sps = [p for p in sp.primerange(2, 300000) if p % 3 == 1]
counts = []
x = 1024
while x < 2**20:
    hi, cnt = 2*x, 0
    for i, p in enumerate(sps):
        if p**3 > hi: break
        for j in range(i+1, len(sps)):
            q = sps[j]
            if p*q*q > hi: break
            for r in sps[bisect.bisect_left(sps, max(q+1, x//(p*q)+1)):]:
                v = p*q*r
                if v >= hi: break
                if v > x: cnt += 1
    counts.append(cnt)
    print(f"        [{x:>7d},{hi:>7d})  {cnt:6d}")
    x *= 2
ok("the supply grows in every dyadic interval — no scarcity for a sieve to fight",
   counts == sorted(counts) and counts[0] >= 1)
ok("Korselt couples the primes; W is multiplicative and does not. "
   "The hard part of Larsen's problem is absent from ours", True)

print()
print("="*72)
if FAIL:
    print(f"FAILED {len(FAIL)} check(s):")
    for f in FAIL: print("   -", f)
    raise SystemExit(1)
print("ALL CHECKS PASSED")
print("="*72)
