#!/usr/bin/env python3
"""
verify_P110.py -- Addendum 110: NNNNLO Weinberg-angle c8 coefficient.

This verifier checks the c8 face-density arithmetic and the accumulated
600-cell-only Weinberg-angle table. The c8 numerics mostly reproduce, but the
paper's combinatorial/binomial pattern has internal errors, and the proposed
next c10 sign would worsen rather than cancel the remaining negative residual.
"""

from __future__ import annotations

import math
import sys
from pathlib import Path

sys.path.insert(0, str(Path(__file__).resolve().parent))

PASS = FAIL = 0
_N = 0


def check(n, desc, cond):
    global PASS, FAIL
    ok = bool(cond)
    PASS += ok
    FAIL += not ok
    print(f"  [{'PASS' if ok else 'FAIL'}] {n:>2}. {desc}")
    return ok


class Verifier:
    """Output adapter: identical check semantics, modern [PASS]/[FAIL] format."""

    def __init__(self, name):
        print(name)

    def check(self, label, computed, claimed, *, rel=1e-3, abs_tol=None, detail=""):
        if abs_tol is not None:
            ok = abs(computed - claimed) <= abs_tol
            err_detail = f"abs err={abs(computed - claimed):.6g}, tol={abs_tol:.6g}"
        else:
            if claimed == 0:
                ok = abs(computed) <= (rel or 1e-12)
                err_detail = f"abs value={abs(computed):.6g}, tol={rel:.6g}"
            else:
                err = (computed - claimed) / abs(claimed)
                ok = abs(err) <= (rel or 0)
                err_detail = f"rel err={100 * err:+.6g}%, tol={100 * (rel or 0):.6g}%"
        return self.record(label, ok, computed, claimed, detail, err_detail)

    def record(self, label, ok, computed="", claimed="", detail="", err_detail=""):
        global _N
        _N += 1
        desc = label + (f" -- {detail}" if detail else "")
        check(_N, desc, ok)
        if computed != "" or claimed != "":
            print(f"        computed: {computed}")
            print(f"        claimed : {claimed}")
        if err_detail:
            print(f"        {err_detail}")
        return ok

    def summary(self):
        print(f"\n{'='*60}\nRESULT: {PASS} PASS / {FAIL} FAIL")
        return 1 if FAIL else 0


v = Verifier("P110 -- Weinberg NNNNLO c8")

ROOT = Path(__file__).resolve().parents[1]
TEX = (ROOT / "110_Addendum_WeinbergNNNNLO.tex").read_text()

PI = math.pi
PHI = (1.0 + math.sqrt(5.0)) / 2.0
LAM = math.sin(PI / 14.0)
BASE = 1.0 / (1.0 + PI)
TARGET = 3.0 / (8.0 * PHI)
C4 = -74.0 / 25.0
C6 = -24.0 / 5.0
C8 = 8.0
C10_PROPOSED = -4.0 / 5.0


def gap_pct(value: float) -> float:
    return 100.0 * (value - TARGET) / TARGET


nlo = BASE * (1.0 - 4.0 * LAM**2 / 5.0)
nlo_plus_c6 = BASE * (1.0 - 4.0 * LAM**2 / 5.0 + C6 * LAM**6)
nlo_plus_c6_c8 = BASE * (1.0 - 4.0 * LAM**2 / 5.0 + C6 * LAM**6 + C8 * LAM**8)
full_through_c8 = BASE * (1.0 - 4.0 * LAM**2 / 5.0 + C4 * LAM**4 + C6 * LAM**6 + C8 * LAM**8)
delta_c8 = C8 * LAM**8 / (1.0 + PI)
c8_exact = -(nlo_plus_c6 - TARGET) * (1.0 + PI) / LAM**8
c10_shift = C10_PROPOSED * LAM**10 / (1.0 + PI)

v.check("lambda", LAM, 0.22252, rel=5e-5)
v.check("lambda^2", LAM**2, 0.04952, rel=9e-5)
v.check("lambda^6", LAM**6, 1.214e-4, rel=2e-4)
v.check("lambda^8", LAM**8, 6.011e-6, rel=7e-5)
v.check("golden target 3/(8phi)", TARGET, 0.23176, rel=2e-5)

v.check("600-cell face/vertex density", 1200.0 / 120.0, 10.0, rel=1e-12)
v.check("c8 = hvee*(F/V)/N_Fano", 4.0 * (1200.0 / 120.0) / 5.0, C8, rel=1e-12)
v.check("c8 NNNNLO shift", delta_c8, 1.161e-5, rel=2e-4)
v.check("NLO plus c6 value", nlo_plus_c6, 0.231748, rel=2e-6)
v.check("NLO plus c6 residual", nlo_plus_c6 - TARGET, -1.499e-5, rel=3e-4)
v.check("NLO plus c6 gap percent", gap_pct(nlo_plus_c6), -0.0065, rel=6e-3)
v.check("NLO plus c6 plus c8 value", nlo_plus_c6_c8, 0.231759, rel=2e-6)
v.check("NLO plus c6 plus c8 residual", nlo_plus_c6_c8 - TARGET, -3.4e-6, rel=8e-3)
v.check("NLO plus c6 plus c8 gap percent", gap_pct(nlo_plus_c6_c8), -0.0015, rel=3e-2)
v.check("c8 improvement factor", abs((nlo_plus_c6 - TARGET) / (nlo_plus_c6_c8 - TARGET)), 4.5, rel=2e-2)
v.check("exact c8 required from c6 residual", c8_exact, 10.3, rel=3e-3)
v.check("c8 face-density discrepancy percent", 100.0 * (C8 - c8_exact) / abs(c8_exact), -22.0, rel=3e-2)

v.record(
    "c4 exclusion is disclosed in the numerical proposition",
    "skipping the Freudenthal $c_4$ term" in TEX,
    computed="the near-target running sum is explicitly the 600-cell-only c2+c6+c8 subseries",
    claimed="c4 contributes separately",
)
v.check(
    "full displayed expansion through c8 value",
    full_through_c8,
    0.23176,
    rel=2e-5,
    detail="Expected caveat/fail: including the displayed c4 term gives about 0.230007, not the table's 600-cell-only near-hit.",
)
v.check(
    "full displayed expansion through c8 gap percent",
    gap_pct(full_through_c8),
    -0.0015,
    rel=3e-2,
    detail="Expected caveat/fail: including c4 gives about -0.758%, not -0.0015%.",
)

v.record(
    "1,6,10,5 are binomial coefficients C(4,k) for k=0..3",
    False,
    computed="C(4,k) for k=0..3 is 1,4,6,4; the 600-cell ratios are 1,6,10,5",
    claimed="1, 6, 10, 5 are binomial coefficients binom(4,k)",
    detail="Expected combinatorics fail.",
)
v.record(
    "F600/V600 = 10 equals binom(4,2)",
    math.comb(4, 2) == 10,
    computed=f"binom(4,2)={math.comb(4, 2)}",
    claimed="F600/V600=10=binom(4,2)",
    detail="Expected combinatorics fail.",
)
v.record(
    "C600/V600 = 5 equals binom(4,4)",
    math.comb(4, 4) == 5,
    computed=f"binom(4,4)={math.comb(4, 4)}",
    claimed="C600/V600=5=binom(4,4)",
    detail="Expected combinatorics fail.",
)
v.check(
    "single formula generates c2 from C/V=5",
    4.0 * (600.0 / 120.0) / 5.0,
    4.0 / 5.0,
    rel=1e-12,
    detail="Expected fail: applying the stated hvee*(sigma/V)/N_Fano formula to C/V=5 gives 4, not 4/5.",
)
v.check(
    "required c6 from exact NLO gap",
    -(nlo - TARGET) * (1.0 + PI) / LAM**6,
    -4.43,
    rel=5e-3,
    detail="Expected fail: exact formulas give about -4.29; -4.43 is the rounded P109 route.",
)
v.record(
    "proposed c10=-4/5 would partially cancel the remaining residual",
    (nlo_plus_c6_c8 - TARGET) * c10_shift < 0.0,
    computed=f"residual={nlo_plus_c6_c8 - TARGET:+.6g}, proposed c10 shift={c10_shift:+.6g}",
    claimed="negative residual will be partially cancelled by c10=-4/5",
    detail="Expected sign fail: both residual and proposed shift are negative.",
)
v.record(
    "c8 derivation includes an explicit Jordan-loop enumeration",
    False,
    computed="the derivation imports the same hvee, density-ratio, and N_Fano weighting rule; no loop enumeration or operator trace is supplied",
    claimed="c8 derived from 600-cell face density",
    detail="Expected proof-status fail.",
)

sys.exit(v.summary())
