# Copyright Léon Fernando Vlegels -- CC BY 4.0
"""
verify_P323.py
Independent verifier for A323 (OI-287-1 corrected, probe P2: Z_3 character
selection). Recomputes everything from scratch in the corpus convention; does
NOT import the probe. No eigenstate overlap is formed (the withdrawn
overlap-diagonal is not revived). Asserts the Z_3 structure, the Schur selection
identity, the character assigned to each rho-degree, the degree-k<->character-k
mod 3 grading, the forced family-degree pairing and its relation to the corpus
assignment, and the PARTIAL verdict's defining condition honestly.
"""
import math, cmath, sys
import numpy as np

PI = math.pi
PASS = 0
FAIL = 0

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

# ===========================================================================
print("="*60)
print("A323 / P2  --  Z_3 character SELECTION for OI-287-1 (corrected)")
print("="*60)

# ---------------------------------------------------------------------------
print("\n-- Z_3 structure of the layer-cycle (P18 S3.5; A304 forced) --")
omega = cmath.exp(2j*PI/3)
T_cycle = np.diag([omega**0, omega**1, omega**2])
T3 = T_cycle @ T_cycle @ T_cycle
check(1, "T_cycle^3 = I (order-3 layer cycle)",
      np.allclose(T3, np.eye(3), atol=1e-12))

eigs = np.linalg.eigvals(T_cycle)
def setmatch(a, b, tol=1e-12):
    a = sorted(a, key=lambda z: (round(z.real, 9), round(z.imag, 9)))
    b = sorted(b, key=lambda z: (round(z.real, 9), round(z.imag, 9)))
    return all(abs(x - y) < tol for x, y in zip(a, b))
check(2, "eigenvalues of T_cycle are {1, omega, omega^2} (the three Z_3 families)",
      setmatch(list(eigs), [1.0+0j, omega, omega**2]))

# ---------------------------------------------------------------------------
print("\n-- Schur orthogonality / selection sum --")
def schur(a, b):
    return sum(omega**(((a - b) % 3) * j) for j in range(3)) / 3.0
# (1/3) sum_j omega^{(a-b)j} = delta_{a==b mod 3}
schur_ok = all(abs(schur(a, b) - (1.0 if (a - b) % 3 == 0 else 0.0)) < 1e-12
               for a in range(3) for b in range(3))
check(3, "(1/3) sum_j omega^{(a-b)j} = delta_{a == b (mod 3)} (Schur selection)",
      schur_ok)

# each character a couples (nonzero pairing) to exactly one character b
forces_one = all(sum(1 for b in range(3) if abs(schur(a, b)) > 1e-9) == 1
                 for a in range(3))
check(4, "Schur selection forces each family character to exactly ONE matching character",
      forces_one)

# ---------------------------------------------------------------------------
print("\n-- Character grading of rho's degrees (corpus action x^k -> omega^k x^k) --")
# Corpus layer-cycle (P18 S3.5): varphi -> varphi + 2pi/3 on the Hopf fiber, which
# rotates the C^2 base coordinate z -> omega z, so x^k -> omega^k x^k. Degree-k
# carries character k mod 3.
rho_terms = {1: 2, 2: 3, 3: 16}                     # degree -> c_n (A296/A322)
deg_char = {k: k % 3 for k in rho_terms}            # {1:1, 2:2, 3:0}
check(5, "degree-k term of rho carries Z_3 character k mod 3 (degrees 1,2,3 -> chars 1,2,0)",
      deg_char == {1: 1, 2: 2, 3: 0})

# sanity: the c_n are the corpus integers (2,3,16)
check(6, "rho degree coefficients are the corpus integers (2,3,16)",
      [rho_terms[1], rho_terms[2], rho_terms[3]] == [2, 3, 16])

# ---------------------------------------------------------------------------
print("\n-- Forced family-degree pairing vs corpus assignment --")
# Family characters (P06 S3 / P20 Family Origin): e->0, mu->1, tau->2.
# Mass-law levels (A287): e->1, mu->2, tau->3 (family n draws degree n).
families = ["e", "mu", "tau"]
fam_char = {"e": 0, "mu": 1, "tau": 2}
fam_level = {"e": 1, "mu": 2, "tau": 3}

# corpus (literal n<->n): family n -> degree n -> coeff
corpus_coeffs = [rho_terms[fam_level[f]] for f in families]    # [2,3,16]

# Z_3-forced: family of character a couples only to the degree whose character
# matches (Schur). Among degrees {1,2,3} with chars {1,2,0}:
def forced_degree(a):
    m = [d for d in rho_terms if deg_char[d] == a % 3]
    return m[0]
forced_coeffs = [rho_terms[forced_degree(fam_char[f])] for f in families]  # [16,2,3]

check(7, "Z_3-forced pairing (e,mu,tau) -> coeffs (16,2,3); corpus n<->n -> (2,3,16); they DIFFER",
      forced_coeffs == [16, 2, 3] and corpus_coeffs == [2, 3, 16]
      and forced_coeffs != corpus_coeffs)

def is_cyclic_shift(a, b):
    return any(a == b[s:] + b[:s] for s in range(len(a)))
check(8, "forced pairing is a CYCLIC SHIFT of the corpus pairing (mod-3 reindex), not the identity",
      is_cyclic_shift(forced_coeffs, corpus_coeffs) and forced_coeffs != corpus_coeffs)

# ---------------------------------------------------------------------------
print("\n-- PARTIAL verdict defining condition (honest) --")
# Selection holds structurally: degree-k carries char k mod 3, Schur is delta,
# each family forced to one degree. AND the forced pairing does NOT match the
# literal corpus n<->n (it is a cyclic shift; degree 3 -> char 0, not level 3;
# level n = char k + 1). That is exactly PARTIAL.
selection_structural = (deg_char == {1: 1, 2: 2, 3: 0}) and schur_ok and forces_one
matches_literal = (forced_coeffs == corpus_coeffs)
verdict = "HIT" if (selection_structural and matches_literal) else \
          ("PARTIAL" if selection_structural else "NULL")
check(9, "verdict is PARTIAL: selection structurally exact but forced pairing is the "
         "cyclic/mod-3 reindex of the corpus n<->n (level = char + 1, degree 3 -> char 0)",
      verdict == "PARTIAL")

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