#!/usr/bin/env python3
# =============================================================================
# PILOT (floating point): reproduction of the DKMM 1912.10047 vacuum
# |W0| = 2.037e-8 on (the mirror of) the degree-18 hypersurface in CP[1,1,1,6,9],
# plus factor-forensics against Broeckel et al. 2108.04266 (|W0| = 2.048e-8)
# and Carta-Mininno-Shukla 2112.13863 (|W0| = 2.0482e-8).
#
# STATUS: UNCERTIFIED. mpmath arbitrary-precision floats, NOT Arb balls.
# Exact rational arithmetic (fractions.Fraction) for every PFFV-layer step;
# mpmath at dps >= 50 for the Li3/instanton layer. The certified computation is in ../cert_w0 and
# ../cert_w0_vac.
#
# Resource note: pure-Python single-threaded; run as
#   python3 repro_w0.py
# Runtime: seconds-class.
#
# Provenance of every constant (see README.md for the table):
#  [L]   arXiv:1912.10047 v2 LaTeX source (archive 1912.10047.tar.gz of ../manifests,
#        SHA-256 4c530d47...d8c81b), eqs. as numbered in the PRL letter.
#  [B]   arXiv:2108.04266 W0draftFinal.tex (archive 2108.04266.gz of ../manifests,
#        SHA-256 7d08a878...9ed5c691), their Sec. 4.1 + Table 1.
#  [C]   arXiv:2112.13863 paper.tex (archive 2112.13863.tar.gz of ../manifests,
#        SHA-256 eabaa17d...7cd35612), eq. (nis-11169), Table "CY 39" GV data,
#        Table row M_{2,39} (c2 = {102,36}), and their eq. (2.x) block.
#  [J]   arXiv:2107.09064 AdS4_v3.tex (archive 2107.09064.tar.gz of ../manifests,
#        SHA-256 03c7d9d7...8862e92b), the F_poly convention line:
#        F_poly = -(1/3!)kt~ zzz + (1/2)a~ zz + (1/24)c~ z + zeta(3)chi(X~)/(2(2pi i)^3)
#        -- chi of the MIRROR of the compactification manifold.
# =============================================================================

from fractions import Fraction as Fr
import mpmath as mp

banner = lambda s: print("\n" + "=" * 78 + "\n" + s + "\n" + "=" * 78)

# =============================================================================
# LAYER 0 -- EXACT RATIONAL ARITHMETIC (the PFFV layer; zero floats)
# =============================================================================
banner("LAYER 0: exact PFFV arithmetic (fractions only)")

# Effective 2-moduli prepotential data for the G = Z6 x Z18 invariant locus.
# [L] eq. (12): kappa_111 = 9, kappa_112 = 3, kappa_122 = 1 (kappa_222 = 0),
#               a = (1/2)[[9,3],[3,0]],  b = (1/4)(17,6).
# Cross-check [C]: model M_{2,39} has c2.D = {102, 36}; b = c2.D/24 = (17/4, 3/2). OK.
kappa = {(0, 0, 0): Fr(9), (0, 0, 1): Fr(3), (0, 1, 1): Fr(1), (1, 1, 1): Fr(0)}


def kap(i, j, k):
    return kappa[tuple(sorted((i, j, k)))]


a_mat = [[Fr(9, 2), Fr(3, 2)], [Fr(3, 2), Fr(0)]]
b_vec = [Fr(17, 4), Fr(6, 4)]
assert b_vec == [Fr(102, 24), Fr(36, 24)], "b != c2.D/24 with c2.D=(102,36)"

# [L] eq. (16): flux integers.
M = [Fr(-16), Fr(50)]
K = [Fr(3), Fr(-4)]

# N_ab = kappa_abc M^c  [L] Lemma
N = [[sum(kap(i, j, c) * M[c] for c in range(2)) for j in range(2)] for i in range(2)]
detN = N[0][0] * N[1][1] - N[0][1] * N[1][0]
assert N == [[Fr(6), Fr(2)], [Fr(2), Fr(-16)]] and detN == Fr(-100)
Ninv = [[N[1][1] / detN, -N[0][1] / detN], [-N[1][0] / detN, N[0][0] / detN]]
p = [Ninv[0][0] * K[0] + Ninv[0][1] * K[1], Ninv[1][0] * K[0] + Ninv[1][1] * K[1]]
assert p == [Fr(2, 5), Fr(3, 10)], "flat direction p"
assert K[0] * p[0] + K[1] * p[1] == 0, "K^T N^-1 K = 0"
assert p[0] > 0 and p[1] > 0, "p in Kahler cone (both entries positive)"

aM = [a_mat[0][0] * M[0] + a_mat[0][1] * M[1], a_mat[1][0] * M[0] + a_mat[1][1] * M[1]]
bM = b_vec[0] * M[0] + b_vec[1] * M[1]
assert aM == [Fr(3), Fr(-24)] and aM[0].denominator == 1 and aM[1].denominator == 1
assert bM == Fr(7) and bM.denominator == 1
Nflux = Fr(-1, 2) * (M[0] * K[0] + M[1] * K[1])
assert Nflux == 124 and Nflux <= 138, "tadpole -M.K/2 = 124 <= Q_D3 = 138"

# Flux vectors in the symplectic frame [L] eq. (9):
#   F = (M.b, (a.M)^T, 0, M^T),  H = (0, K^T, 0, 0)
# Ordering: Pi = (F_0, F_1, F_2, X^0, X^1, X^2), Sigma = [[0,I],[-I,0]].
Fflux = [bM, aM[0], aM[1], Fr(0), M[0], M[1]]
Hflux = [Fr(0), K[0], K[1], Fr(0), Fr(0), Fr(0)]

# Racetrack constants [L] eqs. (14),(18): the two dominant instantons are
# q1 = (1,0) (GV 540, M.q = -16) and q2 = (0,1) (GV 3, M.q = 50).
# A = (A_(0,1) * M.(0,1)) / (A_(1,0) * M.(1,0)) with A_q = -n_q at 1-instanton.
A_rt = (Fr(-3) * M[1]) / (Fr(-540) * M[0])
assert A_rt == Fr(-5, 288), "racetrack A = -5/288"
# c_derived = sqrt(2/pi) * (A_(1,0) M.(1,0)) / (2 pi i)^2 = sqrt(2/pi)*8640/(2pi i)^2
c_numerator = Fr(-540) * M[0]
assert c_numerator == 8640
print("N          =", N)
print("p          =", p, " (K.p = 0 exact; p > 0)")
print("a.M        =", aM, "  b.M =", bM, "  (integrality OK)")
print("N_flux     =", Nflux, "<= Q_D3 = 138")
print("A          =", A_rt, "   c = sqrt(2/pi)*8640/(2 pi i)^2  [derived]")
print("[L] PRINTED c = -sqrt(2/pi)*8640/(2 pi i)^3 differs from derived c by")
print("    -1/(2 pi i): |c_printed|/|c_derived| = 1/(2 pi).  Forensics in Layer 3.")

# GV invariants, genus 0, classes (d1,d2) with d1,d2 <= 4.
# Source [C] Table 'CY 39' (independent of DKMM); deg <= 2 entries cross-checked
# against [L] eqs. (12)-(13) below, exactly.
GV = {
    (1, 0): 540, (0, 1): 3,
    (2, 0): 540, (1, 1): -1080, (0, 2): -6,
    (3, 0): 540, (2, 1): 143370, (1, 2): 2700, (0, 3): 27,
    (4, 0): 540, (3, 1): 204071184, (2, 2): -574560, (1, 3): -17280, (0, 4): -192,
    (4, 1): 21772947555, (3, 2): 74810520, (2, 3): 5051970, (1, 4): 154440,
    (4, 2): -49933059660, (3, 3): -913383000, (2, 4): -57879900,
    (4, 3): 224108858700, (3, 4): 13593850920,
    (4, 4): -2953943334360,
}

# Exact multicover check: (2 pi i)^3 F_inst = -sum_q n_q Li3(e^{2pi i q.U}) must
# reproduce [L] F_1 = -540 q1 - 3 q2 and
#           F_2 = -(1215/2) q1^2 + 1080 q1 q2 + (45/8) q2^2.
coeff = {}
for (d1, d2), n in GV.items():
    for k in (1, 2):
        cls = (k * d1, k * d2)
        if cls[0] <= 2 and cls[1] <= 2 and cls[0] + cls[1] <= 2:
            coeff[cls] = coeff.get(cls, Fr(0)) - Fr(n, k ** 3)
assert coeff[(1, 0)] == Fr(-540) and coeff[(0, 1)] == Fr(-3)
assert coeff[(2, 0)] == Fr(-1215, 2), coeff[(2, 0)]
assert coeff[(1, 1)] == Fr(1080)
assert coeff[(0, 2)] == Fr(45, 8)
print("GV multicover check vs [L] F_1, F_2: exact match",
      "{(1,0):-540, (0,1):-3, (2,0):-1215/2, (1,1):+1080, (0,2):+45/8}")

# xi convention [J]: F_poly constant = + zeta(3) chi(Xtilde) / (2 (2 pi i)^3),
# chi of the MIRROR of the manifold whose complex structures are stabilized.
# Effective 2-moduli model: the A-side (mirror-role) manifold is X = P[1,1,1,6,9][18]
# itself, chi(X) = 2(2 - 272) = -540; the CS-side (compactification-role) manifold
# is Xtilde with chi = +540.  [L] eq. (6) writes xi = -zeta(3) chi/(2(2pi i)^3),
# equivalent iff its 'chi' = chi of the CS-side manifold = +540.
# We parametrize xi by chi_A = chi of the A-side manifold:
#   xi(chi_A) = + zeta(3) * chi_A / (2 (2 pi i)^3)
# Variants: chi_A = -540 (correct, = DKMM frame), xi = 0 (Broeckel/CMS drop),
#           chi_A = +540 (wrong-sign trap).
chi_X = -540
print("chi(X) =", chi_X, " (X = P[1,1,1,6,9][18]; fiber GV 540 = -chi cross-check OK)")

# =============================================================================
# LAYER 1 -- the model at arbitrary precision (mpmath)
# =============================================================================
# Prepotential (gauge X^0 = 1), U = (U1, U2) complex:
#   F(U) = -(1/6) k_abc U^3 + (1/2) a_ab U^a U^b + b_a U^a + xi + F_inst(U)
#   F_inst = -(1/(2 pi i)^3) sum_q n_q Li3(e^{2 pi i q.U})   [J]/[L] convention
#   Pi = (F_0, F_a, 1, U^a),  F_0 = 2F - U^a F_a
#   W = sqrt(2/pi) (F - tau H)^T . Sigma . Pi,  Sigma = [[0,I],[-I,0]]
#   K = -log(-i Pi^dag Sigma Pi) - log(-i (tau - taubar))
#   |W0| = e^{K/2} |W|  (i.e. the quoted W0 includes the CS+dilaton e^{K/2}) [L] eq.(1)

KMAX_MULTICOVER = 60  # e^{-2 pi k * 2.05}: k=60 gives < 1e-336, enough for dps<=120


def make_model(chi_A, gv_deg, dps):
    """Return dict of callables for variant: xi from chi_A (None = xi omitted),
    GV classes restricted to max(d1,d2) <= gv_deg."""
    mp.mp.dps = dps
    twopii = 2j * mp.pi
    if chi_A is None:
        xi = mp.mpc(0)
    else:
        xi = mp.zeta(3) * chi_A / (2 * twopii ** 3)
    gv = {q: n for q, n in GV.items() if max(q) <= gv_deg and min(q) >= 0
          and (q[0] + q[1] <= 2 * gv_deg)}
    if gv_deg <= 2:  # rectangular-with-total-degree cut used by the papers
        gv = {q: n for q, n in GV.items() if q[0] + q[1] <= gv_deg}
    kapf = {k: mp.mpf(int(v)) for k, v in kappa.items()}

    def kapm(i, j, k):
        return kapf[tuple(sorted((i, j, k)))]

    am = [[mp.mpf(x.numerator) / x.denominator for x in row] for row in a_mat]
    bm = [mp.mpf(x.numerator) / x.denominator for x in b_vec]
    Ff = [mp.mpf(int(x)) for x in Fflux]
    Hf = [mp.mpf(int(x)) for x in Hflux]

    def Li(s, z):
        # exact multicover sum; |z| << 1 here always
        return mp.fsum(z ** k / mp.mpf(k) ** s for k in range(1, KMAX_MULTICOVER + 1))

    def F_parts(U):
        """returns F, F_a (2-vec), F_ab (2x2) including instantons."""
        U1, U2 = U
        Fc = -(kapm(0, 0, 0) * U1 ** 3 + 3 * kapm(0, 0, 1) * U1 ** 2 * U2
               + 3 * kapm(0, 1, 1) * U1 * U2 ** 2 + kapm(1, 1, 1) * U2 ** 3) / 6
        Fa = [-(kapm(i, 0, 0) * U1 * U1 + 2 * kapm(i, 0, 1) * U1 * U2
                + kapm(i, 1, 1) * U2 * U2) / 2 for i in range(2)]
        Fab = [[-(kapm(i, j, 0) * U1 + kapm(i, j, 1) * U2) for j in range(2)]
               for i in range(2)]
        for i in range(2):
            Fa[i] += am[i][0] * U1 + am[i][1] * U2 + bm[i]
            for j in range(2):
                Fab[i][j] += am[i][j]
        Fc += (am[0][0] * U1 * U1 + 2 * am[0][1] * U1 * U2 + am[1][1] * U2 * U2) / 2 \
            + bm[0] * U1 + bm[1] * U2 + xi
        # instantons
        c3 = (2j * mp.pi) ** 3
        for (d1, d2), n in gv.items():
            z = mp.exp(2j * mp.pi * (d1 * U1 + d2 * U2))
            l3, l2, l1 = Li(3, z), Li(2, z), Li(1, z)
            Fc += -n * l3 / c3
            pref = -n * (2j * mp.pi) * l2 / c3
            Fa[0] += pref * d1
            Fa[1] += pref * d2
            pref2 = -n * (2j * mp.pi) ** 2 * l1 / c3
            for i in range(2):
                for j in range(2):
                    Fab[i][j] += pref2 * (d1, d2)[i] * (d1, d2)[j]
        return Fc, Fa, Fab

    def periods(U):
        Fc, Fa, Fab = F_parts(U)
        F0 = 2 * Fc - U[0] * Fa[0] - U[1] * Fa[1]
        Pi = [F0, Fa[0], Fa[1], mp.mpc(1), U[0], U[1]]
        dPi = []
        for a in range(2):
            dF0 = Fa[a] - U[0] * Fab[0][a] - U[1] * Fab[1][a]
            dv = [dF0, Fab[0][a], Fab[1][a], mp.mpc(0),
                  mp.mpc(1) if a == 0 else mp.mpc(0),
                  mp.mpc(1) if a == 1 else mp.mpc(0)]
            dPi.append(dv)
        return Pi, dPi

    def sympl(v, w):
        # v^T Sigma w with Sigma = [[0,I],[-I,0]], 3+3 blocks
        return (v[0] * w[3] + v[1] * w[4] + v[2] * w[5]
                - v[3] * w[0] - v[4] * w[1] - v[5] * w[2])

    sq2pi = mp.sqrt(2 / mp.pi)

    def eval_all(tau, U):
        Pi, dPi = periods(U)
        FmtH = [Ff[i] - tau * Hf[i] for i in range(6)]
        W = sq2pi * sympl(FmtH, Pi)
        dWtau = -sq2pi * sympl(Hf, Pi)
        dWU = [sq2pi * sympl(FmtH, dPi[a]) for a in range(2)]
        emK_cs = (-1j * sympl([mp.conj(x) for x in Pi], Pi)).real
        emK = emK_cs * (-1j * (tau - mp.conj(tau))).real
        Kcs_a = []
        for a in range(2):
            num = -1j * sympl([mp.conj(x) for x in Pi], dPi[a])
            Kcs_a.append(-num / emK_cs)
        Ktau = -1 / (tau - mp.conj(tau))
        DWtau = dWtau + Ktau * W
        DWU = [dWU[a] + Kcs_a[a] * W for a in range(2)]
        return dict(W=W, DWtau=DWtau, DWU=DWU, emK=emK, emK_cs=emK_cs, Pi=Pi)

    return dict(eval_all=eval_all, xi=xi, gv=gv, dps=dps)


def solve_vacuum(model, guess, dps):
    """Newton on 6 real unknowns (Re tau, Im tau, Re U1, Im U1, Re U2, Im U2)."""
    mp.mp.dps = dps
    ev = model["eval_all"]

    def eqs(x):
        tau = mp.mpc(x[0], x[1])
        U = [mp.mpc(x[2], x[3]), mp.mpc(x[4], x[5])]
        r = ev(tau, U)
        return [r["DWtau"].real, r["DWtau"].imag,
                r["DWU"][0].real, r["DWU"][0].imag,
                r["DWU"][1].real, r["DWU"][1].imag]

    x = [mp.mpf(g) for g in guess]
    for it in range(120):
        f = eqs(x)
        resid = max(abs(v) for v in f)
        if resid < mp.mpf(10) ** (-(dps - 8)):
            break
        # numeric Jacobian
        Jm = mp.zeros(6, 6)
        h0 = mp.mpf(10) ** (-(dps // 2))
        for j in range(6):
            h = h0 * max(1, abs(x[j]))
            xp = list(x); xp[j] += h
            xmn = list(x); xmn[j] -= h
            fp, fmn = eqs(xp), eqs(xmn)
            for i in range(6):
                Jm[i, j] = (fp[i] - fmn[i]) / (2 * h)
        d = mp.lu_solve(Jm, mp.matrix(f))
        x = [x[i] - d[i] for i in range(6)]
    tau = mp.mpc(x[0], x[1])
    U = [mp.mpc(x[2], x[3]), mp.mpc(x[4], x[5])]
    r = ev(tau, U)
    r["tau"], r["U"], r["resid"], r["iters"] = tau, U, resid, it
    r["W0abs"] = abs(r["W"]) / mp.sqrt(r["emK"])
    return r


def report(tag, r, digits=12):
    mp.mp.dps = max(digits + 8, 30)
    print(f"--- {tag}")
    print(f"    tau  = {mp.nstr(r['tau'], digits)}")
    print(f"    U1   = {mp.nstr(r['U'][0], digits)}")
    print(f"    U2   = {mp.nstr(r['U'][1], digits)}")
    print(f"    e^-K = {mp.nstr(r['emK'], digits)}  (CS block {mp.nstr(r['emK_cs'], digits)})")
    print(f"    |W|  = {mp.nstr(abs(r['W']), digits)}")
    print(f"    |W0| = {mp.nstr(r['W0abs'], digits)}   [max residual {mp.nstr(r['resid'], 3)}]")


# =============================================================================
# LAYER 2 -- the four variants (forensics grid), dps = 50
# =============================================================================
banner("LAYER 2: variant grid at dps = 50 (the adjudication)")
DPS = 50
guess = [0, 6.8556, 0, 2.7422, 0, 2.0567]

# V1: DKMM frame -- xi with chi_A = chi(X) = -540, full GV table (deg <= 4)
m_v1 = make_model(chi_X, 4, DPS)
r_v1 = solve_vacuum(m_v1, guess, DPS)
report("V1  xi(chi_A=-540) [DKMM frame], GV deg<=4  -> expect 2.037e-8, tau=6.856i", r_v1)

# V1deg2: same frame, GV truncated at total degree 2 (exactly the letter's data)
m_v1d2 = make_model(chi_X, 2, DPS)
r_v1d2 = solve_vacuum(m_v1d2, guess, DPS)
report("V1deg2  same, GV total degree <= 2 (letter's own truncation)", r_v1d2)

# V2: Broeckel/CMS -- xi dropped, GV total degree <= 2
m_v2 = make_model(None, 2, DPS)
r_v2 = solve_vacuum(m_v2, guess, DPS)
report("V2  xi = 0 [Broeckel/CMS], GV deg<=2  -> expect 2.048e-8, tau=6.85505i", r_v2)

# V2full: xi dropped, full GV
m_v2f = make_model(None, 4, DPS)
r_v2f = solve_vacuum(m_v2f, guess, DPS)
report("V2full  xi = 0, GV deg<=4", r_v2f)

# V3: wrong-sign trap -- xi with chi_A = +540
m_v3 = make_model(-chi_X, 4, DPS)
r_v3 = solve_vacuum(m_v3, guess, DPS)
report("V3  xi(chi_A=+540) [wrong-sign trap], GV deg<=4  -> matches neither", r_v3)

# Flux sign flip (Broeckel Table 1 quotes M=(16,-50), K=(-3,4)): |W0| must be equal
banner("Flux sign-flip test: (M,K) -> (-M,-K) [Broeckel Table 1 vectors]")
Fflux_s, Hflux_s = [-x for x in Fflux], [-x for x in Hflux]
Fflux_orig, Hflux_orig = Fflux, Hflux
Fflux, Hflux = Fflux_s, Hflux_s
m_flip = make_model(None, 2, DPS)
r_flip = solve_vacuum(m_flip, guess, DPS)
report("V2 with sign-flipped fluxes", r_flip)
Fflux, Hflux = Fflux_orig, Hflux_orig
mp.mp.dps = 30
print("| |W0|_flip - |W0|_V2 | =", mp.nstr(abs(r_flip["W0abs"] - r_v2["W0abs"]), 5),
      " -> flux sign flip is NOT the source of the discrepancy")

# =============================================================================
# LAYER 3 -- printed-constant forensics (the letter's c typo)
# =============================================================================
banner("LAYER 3: racetrack-constant forensics")
mp.mp.dps = 50
t1 = r_v1["tau"].imag
x_, y_ = mp.exp(-2 * mp.pi * t1 * mp.mpf(2) / 5), mp.exp(-2 * mp.pi * t1 * mp.mpf(3) / 10)
sq2pi = mp.sqrt(2 / mp.pi)
c_derived = sq2pi * 8640 / (2j * mp.pi) ** 2      # = [B],[C] printed constant
c_printed_L = -sq2pi * 8640 / (2j * mp.pi) ** 3   # [L] eq. (19) as printed
A_ = mp.mpf(-5) / 288
eKhalf = 1 / mp.sqrt(r_v1["emK"])
W0_derived = abs(c_derived * (x_ + A_ * y_)) * eKhalf
W0_printedc = abs(c_printed_L * (x_ + A_ * y_)) * eKhalf
print("2-term racetrack at the V1 vacuum point (e^{K/2}-dressed):")
print("  with c = sqrt(2/pi) 8640/(2pi i)^2  [derived; = Broeckel/CMS printed]:")
print("     |W0| =", mp.nstr(W0_derived, 8), "  (matches the letter's 2.037e-8 scale)")
print("  with c = -sqrt(2/pi) 8640/(2pi i)^3 [as printed in 1912.10047 eq.(19)]:")
print("     |W0| =", mp.nstr(W0_printedc, 8), "  = derived/(2 pi) -> the printed c is a typo")
print("  ratio printed/derived =", mp.nstr(W0_printedc / W0_derived, 10), "= 1/(2 pi) =",
      mp.nstr(1 / (2 * mp.pi), 10))

# =============================================================================
# LAYER 4 -- headline number at dps 50 and dps 90 (two-precision control)
# =============================================================================
banner("LAYER 4: headline |W0|, two-precision control (dps 50 vs 90)")
m_hi = make_model(chi_X, 4, 90)
guess_hi = [0, r_v1["tau"].imag, 0, r_v1["U"][0].imag, 0, r_v1["U"][1].imag]
r_hi = solve_vacuum(m_hi, guess_hi, 90)
mp.mp.dps = 95
W0_50 = r_v1["W0abs"]
W0_90 = r_hi["W0abs"]
print("dps=50: |W0| =", mp.nstr(W0_50, 40))
print("dps=90: |W0| =", mp.nstr(W0_90, 40))
print("agreement: |diff|/|W0| =", mp.nstr(abs(W0_50 - W0_90) / W0_90, 5))
print()
print("HEADLINE (model value, GV deg<=4, DKMM frame, 35 digits):")
print("  |W0| =", mp.nstr(W0_90, 35))
print("  Im tau =", mp.nstr(r_hi["tau"].imag, 35))
print("  Im U1  =", mp.nstr(r_hi["U"][0].imag, 35))
print("  Im U2  =", mp.nstr(r_hi["U"][1].imag, 35))
print("  g_s = 1/Im tau =", mp.nstr(1 / r_hi["tau"].imag, 12))
print("  Re parts:", mp.nstr(r_hi["tau"].real, 3), mp.nstr(r_hi["U"][0].real, 3),
      mp.nstr(r_hi["U"][1].real, 3))
print("  flat-dir displacement: U - tau*p =",
      mp.nstr(r_hi["U"][0] - r_hi["tau"] * mp.mpf(2) / 5, 8),
      mp.nstr(r_hi["U"][1] - r_hi["tau"] * mp.mpf(3) / 10, 8))

# =============================================================================
# LAYER 5 -- truncation audit: shell-by-shell + tail bound
# =============================================================================
banner("LAYER 5: instanton-shell audit and truncation tail bound")
mp.mp.dps = 50
t, u1, u2 = r_hi["tau"].imag, r_hi["U"][0].imag, r_hi["U"][1].imag
# W_eff units: S = sum_q (multicover-corrected) n-terms (M.q) e^{-2 pi q.u};
# shell d = total degree d1+d2 contribution incl. its multicovers at that level.
shell = {}
for (d1, d2), n in GV.items():
    for k in range(1, KMAX_MULTICOVER + 1):
        deg = k * (d1 + d2)
        if deg > 60:
            break
        Mq = k * (int(M[0]) * d1 + int(M[1]) * d2)
        term = mp.mpf(-n) / k ** 3 * Mq * mp.exp(-2 * mp.pi * k * (d1 * u1 + d2 * u2))
        shell[deg] = shell.get(deg, mp.mpf(0)) + term
S_all = mp.fsum(shell.values())
print("shell d = sum over classes+multicovers at total instanton degree d of")
print("          A_q,k (M.q) e^{-2 pi k q.u}   (units: W_eff = sqrt(2/pi)/(2pi i)^2 * S)")
for d in sorted(shell):
    if abs(shell[d]) > 0:
        print(f"  d={d:2d}: {mp.nstr(shell[d], 8):>16}   |shell|/|S| = "
              f"{mp.nstr(abs(shell[d]) / abs(S_all), 4)}")
print("S =", mp.nstr(S_all, 12))
r21 = abs(shell[2]) / abs(shell[1])
r32 = abs(shell.get(3, mp.mpf(0))) / abs(shell[2])
r43 = abs(shell.get(4, mp.mpf(0))) / abs(shell.get(3, mp.mpf(1)))
print("shell ratios: 2/1 =", mp.nstr(r21, 4), " 3/2 =", mp.nstr(r32, 4),
      " 4/3 =", mp.nstr(r43, 4), " (letter's claim: both O(1e-5))")

# Tail bound for classes outside the 5x5 GV window (d1>=5 or d2>=5), under the
# STATED growth assumption |n_(d1,d2)| <= Nstar * g1^d1 * g2^d2 with
# Nstar=540, g1=10^4, g2=10^2 (margins: max observed per-degree ratios in the
# window are 1423 in d1 and 14.9 in d2; local-P2 asymptote in d2 is 27).
Nstar, g1b, g2b = mp.mpf(540), mp.mpf(10) ** 4, mp.mpf(10) ** 2
q1s, q2s = mp.exp(-2 * mp.pi * u1), mp.exp(-2 * mp.pi * u2)
f1, f2 = g1b * q1s, g2b * q2s   # per-degree net factors, both << 1
assert f1 < 1 and f2 < 1


def geom_sum(f, dlo, dhi=200):
    return mp.fsum(f(d) for d in range(dlo, dhi))


# sum over d1>=5, d2>=0  and  d1<=4, d2>=5 of Nstar f1^d1 f2^d2 * |M.q|max(d1,d2)
def Mq_bound(d1, d2):
    return 16 * d1 + 50 * d2


tail = mp.mpf(0)
for d1 in range(5, 200):
    inner = mp.fsum(f2 ** d2 * Mq_bound(d1, d2) for d2 in range(0, 200))
    tail += Nstar * f1 ** d1 * inner
for d2 in range(5, 200):
    inner = mp.fsum(f1 ** d1 * Mq_bound(d1, d2) for d1 in range(0, 5))
    tail += Nstar * f2 ** d2 * inner
tail *= mp.mpf(1.01)  # multicover allowance (multicovers of omitted classes)
print("\nTail bound (classes with d1>=5 or d2>=5), assumption",
      "|n| <= 540 * (1e4)^d1 * (1e2)^d2:")
print("  |S_tail| <=", mp.nstr(tail, 4), "   relative to |S|:",
      mp.nstr(tail / abs(S_all), 4))
print("  => true-CY |W0| = model |W0| * (1 + delta), |delta| <=",
      mp.nstr(tail / abs(S_all), 4))
print("  (K-side instanton tail is O(1e-5) x this in e^{-K}, subleading)")

# =============================================================================
# LAYER 6 -- checks
# =============================================================================
banner("LAYER 6: check evaluation")


def sig4(x):
    return mp.nstr(x, 4)


mp.mp.dps = 30
print("g2 (DKMM): |W0|_V1 =", sig4(r_v1["W0abs"]), " vs printed 2.037e-8 ;",
      " Im tau =", mp.nstr(r_v1["tau"].imag, 7), " vs printed 6.856")
print("g3 (Broeckel/CMS): |W0|_V2 =", mp.nstr(r_v2["W0abs"], 5), " vs printed 2.048e-8 /",
      "2.0482e-8 ;  Im tau =", mp.nstr(r_v2["tau"].imag, 7), " vs CMS 6.85505")
print("g4 (vevs, DKMM frame): Im U1 =", mp.nstr(r_v1["U"][0].imag, 7),
      " vs 2.742 ;  Im U2 =", mp.nstr(r_v1["U"][1].imag, 7), " vs 2.057",
      " ;  CMS U = (2.74202, 2.05652) vs V2:",
      mp.nstr(r_v2["U"][0].imag, 7), mp.nstr(r_v2["U"][1].imag, 7))
print("g1: headline above (Layer 4), two-precision agreement + stated tail bound")
print("\nRatio structure: |W0|_V2/|W0|_V1 =", mp.nstr(r_v2["W0abs"] / r_v1["W0abs"], 8),
      " ;  printed 2.048/2.037 =", mp.nstr(mp.mpf("2.048") / mp.mpf("2.037"), 8),
      " ;  2.0482/2.037 =", mp.nstr(mp.mpf("2.0482") / mp.mpf("2.037"), 8))
print("Done.")
