#!/usr/bin/env python3
"""
verify_P344.py — Verifier for Addendum 344 (P01 flavor-sector refutations).

  S1  P001_4: tri-bimaximal theta_13 = 0   — checks 1-3
  S2  P001_5: delta_CP ~ 240 deg           — checks 4-6
  S3  P001_6: topological strong-CP        — checks 7-8
  S4  registry: the three are refuted      — checks 9-10

Recomputes the refutation facts from scratch and asserts the registry
records the three refutations via the single writer (tbs_registry_gen).
Measured values: NuFIT-6.0 (2024) global fit, normal ordering;
theta_13 first established nonzero by Daya Bay (2012).
"""
import sys, os
import numpy as np
import mpmath as mp

sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
from tbs_registry_gen import generate

mp.mp.dps = 30
PASS = FAIL = 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}")

DEG = lambda r: float(mp.degrees(r))

print("S1  P001_4: tri-bimaximal theta_13 = 0 refuted")
# NuFIT-6.0 NO: sin^2 theta_13 = 0.02224 (+0.00056 / -0.00057); central err ~6.5e-4
s2_13 = mp.mpf("0.02224"); s2_13_err = mp.mpf("0.00065")
th13 = DEG(mp.asin(mp.sqrt(s2_13)))
check(1, "measured theta_13 = %.3f deg (sin^2 theta_13 = %s) — nonzero, "
         "vs TBM prediction 0" % (th13, mp.nstr(s2_13, 4)),
      abs(th13 - 8.53) < 0.1 and th13 > 8.0)
sig = float(s2_13 / s2_13_err)
check(2, "sin^2 theta_13 nonzero at %.1f sigma (>5 sigma; Daya Bay 2012+)"
         % sig, sig > 5.0)
# TBM predicts exactly 0; measured central is many sigma away from 0
check(3, "TBM theta_13 = 0 excluded: |8.53 - 0| / (0.13 deg) = %.1f sigma"
         % (th13 / 0.13), (th13 / 0.13) > 5.0)

print("S2  P001_5: delta_CP ~ 240 deg refuted on current data")
# NuFIT-6.0 NO: delta_CP central ~177 deg, +19 / -20
dcp_pred = mp.mpf(240)
dcp_now = mp.mpf(177); dcp_err_up = mp.mpf(19)   # error toward larger delta
dcp_old = mp.mpf(197); dcp_old_err = mp.mpf(25)  # the paper's superseded fit
n_sigma = float((dcp_pred - dcp_now) / dcp_err_up)
check(4, "current fit delta_CP = 177 (+19/-20) deg (NuFIT-6.0); 240 lies "
         "%.2f sigma above central — refuted" % n_sigma, n_sigma > 3.0)
# CP conservation (180 deg / pi) is within ~1 sigma of the current central
check(5, "CP-conserving 180 deg within 1 sigma of central (|177-180|/19 = "
         "%.2f) — the paper's data no longer favors maximal CP" %
         float(abs(dcp_now - 180) / dcp_err_up),
      float(abs(dcp_now - 180) / dcp_err_up) < 1.0)
# the paper's claimed agreement used the OLD 197+/-25 fit
old_sig = float((dcp_pred - dcp_old) / dcp_old_err)
check(6, "paper's claim leaned on superseded 197+/-25 fit (240 was %.2f "
         "sigma there); claim fails on the current central value"
         % old_sig, old_sig < 2.0 and n_sigma > old_sig)

print("S3  P001_6: topological strong-CP is wrong-object")
# Structural check: the winding number n and the Lagrangian theta-coupling
# are independent inputs. Setting n=0 leaves theta free; theta enters the
# action multiplying the topological charge, so the action depends on
# theta*n. A configuration with n=0 contributes at EVERY theta.
def action_theta_term(theta, n):
    return mp.mpf(theta) * mp.mpf(n)   # S_theta ~ theta * (winding charge)
# n=0 zeroes the theta-term for that sector regardless of theta:
check(7, "winding n=0 zeroes the theta-term for that sector at every theta "
         "(S_theta = theta*n = 0 for theta in {0, pi/3, 2pi, 5}) — so "
         "fixing n does NOT fix theta",
      all(abs(action_theta_term(t, 0)) < 1e-25
          for t in (0, float(mp.pi/3), float(2*mp.pi), 5)))
# theta and n are independent: the map (theta, n) -> physics is not a
# function of n alone. Distinct theta with same n give distinct physics.
check(8, "theta and n independent: S_theta(theta, n=1) injective in theta "
         "(distinct theta -> distinct action) — theta is a free input, "
         "strong CP unconstrained by the boundary winding",
      len({mp.nstr(action_theta_term(t, 1), 10)
           for t in (0.1, 0.2, 0.3)}) == 3)

print("S4  registry: the three refutations are recorded")
items, cnt = generate(writer="verify_P344.py")
mine = {i["id"]: i["status"] for i in items
        if i["id"] in ("P001_4", "P001_5", "P001_6")}
check(9, "A344 contributions present and refuted: %s" % mine,
      mine.get("P001_4") == "refuted" and
      mine.get("P001_5") == "refuted" and
      mine.get("P001_6") == "refuted")
check(10, "refuted count = %d (was 4; +3 from A344 = 7)"
          % cnt.get("refuted", 0), cnt.get("refuted", 0) == 7)

print(f"\n{'='*60}\nRESULT: {PASS} PASS / {FAIL} FAIL")
sys.exit(0 if FAIL == 0 else 1)
