# Copyright Léon Fernando Vlegels -- CC BY 4.0
"""
verify_P324.py
Verifier for Addendum 324: OI-287-1 (corrected) probe P3 --
the Z_3 character decomposition of rho on the lens space L(3,1).
Recomputes every claim from scratch (numpy only). Corpus convention.

Structural / rho-side only: NO wavefunctions, NO eigenstate overlaps. The
objects are rho's Z_3 character projections P_k = (1/3) sum_j omega^{-kj} g^j
with g: x -> omega x. The withdrawn overlap-diagonal (A321) is not revived.
"""
import math, cmath
import numpy as np

PI = math.pi
OMEGA = cmath.exp(2j * PI / 3)
PASS = 0
FAIL = 0

def check(n, desc, cond):
    global PASS, FAIL
    tag = "[PASS]" if cond else "[FAIL]"
    if cond: PASS += 1
    else:    FAIL += 1
    print(f"  {tag} ({n}) {desc}")

# ---------- recompute from scratch ----------
# rho(x) = 16 pi^3 x^3 + 3 pi^2 x^2 + 2 pi x ; rho^(d)(0) and c_d = rho^(d)(0)/(pi^d d!)
deriv0 = {1: 2*PI, 2: 6*PI**2, 3: 96*PI**3}
c = {d: deriv0[d] / (PI**d * math.factorial(d)) for d in (1, 2, 3)}   # (2,3,16)

# Z_3 projector on a monomial:  P_k x^d = (1/3) sum_j omega^{-kj} omega^{jd} x^d
def proj_scalar(k, d):
    return (1.0/3.0) * sum((OMEGA**(-k*j)) * (OMEGA**(j*d)) for j in (0, 1, 2))

# projector identity P_k x^d = [d ≡ k mod 3] x^d, over k=0,1,2 and d=0..5
proj_ok = True
for k in (0, 1, 2):
    for d in range(6):
        expect = 1.0 if (d % 3) == k else 0.0
        if abs(proj_scalar(k, d) - expect) > 1e-12:
            proj_ok = False

# character component of rho: degree d -> character d mod 3
#   deg 1 -> char 1 (c=2) ; deg 2 -> char 2 (c=3) ; deg 3 -> char 0 (c=16)
comp = {}                      # comp[k] = (degree, c_d)
for k in (0, 1, 2):
    ds = [d for d in (1, 2, 3) if (d % 3) == k]
    comp[k] = (ds[0], c[ds[0]])
coeffs_by_char = [comp[k][1] for k in (0, 1, 2)]      # (16,2,3)
degrees_by_char = [comp[k][0] for k in (0, 1, 2)]     # (3,1,2)

# family maps
m_id = [comp[n-1][1] for n in (1, 2, 3)]              # fam n -> char n-1 -> (16,2,3)
m_deg = [comp[n % 3][1] for n in (1, 2, 3)]           # fam n -> char n mod 3 -> (2,3,16)

# ---------- checks ----------
print("="*64)
print("Section 1: omega and the Z_3 projector identity")
print("="*64)
check(1, f"omega = e^(2 pi i/3) = -1/2 + i sqrt(3)/2  "
         f"[got {OMEGA.real:+.4f}{OMEGA.imag:+.4f}i]",
      abs(OMEGA.real + 0.5) < 1e-12 and abs(OMEGA.imag - math.sqrt(3)/2) < 1e-12
      and abs(OMEGA**3 - 1) < 1e-12)
check(2, "projector identity P_k x^d = [d == k mod 3] x^d holds for k=0,1,2, d=0..5",
      proj_ok)

print("="*64)
print("Section 2: c_n = rho^(n)(0)/(pi^n n!) = (2,3,16)")
print("="*64)
check(3, f"c_n = (2,3,16) exact  [got ({c[1]:.6f},{c[2]:.6f},{c[3]:.6f})]",
      abs(c[1]-2)<1e-9 and abs(c[2]-3)<1e-9 and abs(c[3]-16)<1e-9)

print("="*64)
print("Section 3: the three Z_3 character components of rho")
print("="*64)
check(4, f"P_0 rho = 16 pi^3 x^3 (char 0, degree 3, c=16)  "
         f"[degree {degrees_by_char[0]}, c={coeffs_by_char[0]:.0f}]",
      degrees_by_char[0] == 3 and abs(coeffs_by_char[0]-16) < 1e-9)
check(5, f"P_1 rho = 2 pi x (char 1, degree 1, c=2) and "
         f"P_2 rho = 3 pi^2 x^2 (char 2, degree 2, c=3)  "
         f"[deg {degrees_by_char[1]},{degrees_by_char[2]} ; "
         f"c {coeffs_by_char[1]:.0f},{coeffs_by_char[2]:.0f}]",
      degrees_by_char[1] == 1 and abs(coeffs_by_char[1]-2) < 1e-9
      and degrees_by_char[2] == 2 and abs(coeffs_by_char[2]-3) < 1e-9)
check(6, f"coefficients by character order (k=0,1,2) = (16,2,3); "
         f"SET {{2,3,16}} recovered exactly as the character components  "
         f"[{[int(round(v)) for v in coeffs_by_char]}]",
      [int(round(v)) for v in coeffs_by_char] == [16, 2, 3]
      and sorted(int(round(v)) for v in coeffs_by_char) == [2, 3, 16])

print("="*64)
print("Section 4: family <-> character map vs the corpus n <-> c_n assignment")
print("="*64)
check(7, f"identity map (fam n -> char n-1) assigns (16,2,3), does NOT reproduce "
         f"n<->c_n  [got {[int(round(v)) for v in m_id]}]",
      [int(round(v)) for v in m_id] == [16, 2, 3]
      and [int(round(v)) for v in m_id] != [2, 3, 16])
check(8, f"mod-3 reindexed map (fam n -> char n mod 3, the character of degree n) "
         f"assigns (2,3,16) = c_n: reproduces the corpus assignment under the "
         f"stated reindexing char 0 <-> degree 3  [got {[int(round(v)) for v in m_deg]}]",
      [int(round(v)) for v in m_deg] == [2, 3, 16])

print("="*64)
print("Section 5: verdict (PARTIAL -- structurally clean, mod-3 reindexing)")
print("="*64)
verdict_partial = (proj_ok
                   and sorted(int(round(v)) for v in coeffs_by_char) == [2, 3, 16]
                   and [int(round(v)) for v in m_id] != [2, 3, 16]
                   and [int(round(v)) for v in m_deg] == [2, 3, 16])
check(9, "VERDICT PARTIAL: rho's Z_3 character decomposition yields (2,3,16) as "
         "its components (structurally clean); reproducing the corpus n<->c_n "
         "needs the mod-3 reindexing char(n)=n mod 3 (char 0 <-> degree 3). "
         "Not HIT (identity labelling fails); not NULL (decomposition is clean).",
      verdict_partial)

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