# Copyright Léon Fernando Vlegels -- CC BY 4.0
"""
probe_oi287_z3decomp.py
OI-287-1 (corrected), probe P3 (A324).

The corrected OI-287-1 asks why the lepton mass correction law assigns
charged-lepton family n the degree-n Taylor coefficient c_n of the density rho,
with the integers (2,3,16) read directly. A322 gated IN exactly one corpus-
faithful object: O-Z3-grading, the three families as the omega^k eigenspaces of
the layer-cycle operator T_cycle (P18 S3.5, P20). This probe works ONLY within
that gated object, at the STRUCTURAL level: it decomposes rho itself into its
Z_3 character components. It does NOT form any wavefunction overlap; the
withdrawn overlap-diagonal of A299-A320 (A321) is not revived.

The corpus action (P18 S3.5, lines 274-285): T_cycle rotates the Hopf fiber
coordinate by 2 pi / 3, phi -> phi + 2 pi/3, with eigenspaces carrying omega^k,
omega = e^{2 pi i / 3}; the quotient is the lens space L(3,1) = S^3 / Z_3
(P06 S, P20). A function on S^3 decomposes into the three Z_3 character sectors
k = 0,1,2 under this phase action. The natural graded extension of the phase
rotation to the degree of a base monomial is g: x -> omega x, so that x^d carries
character d mod 3. This probe tests whether the three Z_3 character components of
rho ARE the coefficient set, and how the character <-> degree <-> family map
relates to the corpus family-n <-> coefficient-c_n assignment.

Pre-registration (HIT / PARTIAL / NULL):
  HIT  iff the Z_3 character decomposition of rho yields exactly the three
       coefficients (2,3,16) as the character components AND the corpus
       family<->character map sends family n to the character whose component is
       c_n -- deriving the assignment from rho's own Z_3 grading.
  PARTIAL iff the Z_3 decomposition yields the three coefficients as character
       components (structurally clean) but the family<->character<->degree
       correspondence requires a stated reindexing (the mod-3 subtlety:
       char 0 <-> deg 3) to match the corpus n<->n assignment.
  NULL iff rho's Z_3 character decomposition does NOT cleanly yield the
       coefficients as components (e.g. the corpus action does not act as
       x -> omega x, or the grading mixes degrees).

Writes Outputs/oi287_z3decomp.json (four levels up from verify/).
Prints VERDICT (HIT / PARTIAL / NULL).
"""
import json, os, math, cmath
import numpy as np

PI = math.pi
OMEGA = cmath.exp(2j * PI / 3)            # omega = e^{2 pi i / 3}, Z_3 generator eigenvalue

# ---------------------------------------------------------------------------
# rho(x) = 16 pi^3 x^3 + 3 pi^2 x^2 + 2 pi x   (P03/P18)
#   coefficient of x^d, in plain units:  a_1 = 2 pi, a_2 = 3 pi^2, a_3 = 16 pi^3
#   Taylor coefficient in pi^d units:    c_d = rho^(d)(0) / (pi^d d!)
#       c_1 = 2 pi / pi      = 2
#       c_2 = 6 pi^2 / (2 pi^2) = 3
#       c_3 = 96 pi^3 / (6 pi^3) = 16
# ---------------------------------------------------------------------------
a = {1: 2*PI, 2: 3*PI**2, 3: 16*PI**3}            # plain coefficients a_d of x^d
deriv0 = {1: 2*PI, 2: 6*PI**2, 3: 96*PI**3}       # rho^(d)(0)
c = {d: deriv0[d] / (PI**d * math.factorial(d)) for d in (1, 2, 3)}   # (2,3,16)

# ---------------------------------------------------------------------------
# Z_3 character projectors  P_k = (1/3) sum_{j=0,1,2} omega^{-k j} g^j
# acting on a monomial x^d via g: x -> omega x  =>  g^j x^d = omega^{j d} x^d.
# Hence P_k x^d = (1/3) sum_j omega^{j(d-k)} x^d = [d == k mod 3] x^d.
# Verify the projector identity numerically (not just symbolically).
# ---------------------------------------------------------------------------
def projector_on_monomial(k, d):
    """Return the scalar s such that P_k x^d = s x^d, computed from the group sum."""
    s = (1.0/3.0) * sum((OMEGA**(-k*j)) * (OMEGA**(j*d)) for j in (0, 1, 2))
    return s

# the projector identity P_k x^d = [d ≡ k mod 3] x^d
proj_matrix = {}      # proj_matrix[(k,d)] = projector scalar (should be 1 or 0)
proj_ok = True
for k in (0, 1, 2):
    for d in (0, 1, 2, 3, 4, 5):
        s = projector_on_monomial(k, d)
        expect = 1.0 if (d % 3) == k else 0.0
        proj_matrix[(k, d)] = complex(s)
        if abs(s - expect) > 1e-12:
            proj_ok = False

# ---------------------------------------------------------------------------
# Apply the projectors to rho. rho has degrees 1,2,3 with plain coeffs a_d and
# pi^d-unit coeffs c_d. Each degree d goes to character d mod 3:
#   deg 1 -> char 1 ; deg 2 -> char 2 ; deg 3 -> char 0.
# So the three Z_3 character components of rho are:
#   P_0 rho = a_3 x^3 = 16 pi^3 x^3   (char 0, coeff c_3 = 16)
#   P_1 rho = a_1 x^1 = 2  pi   x     (char 1, coeff c_1 = 2)
#   P_2 rho = a_2 x^2 = 3  pi^2 x^2   (char 2, coeff c_2 = 3)
# ---------------------------------------------------------------------------
rho_degrees = {1: 1, 2: 2, 3: 3}     # the three nonzero degrees of rho
# character component of rho: for each k, sum the c_d of degrees with d mod 3 == k
char_component_coeff = {}            # char_component_coeff[k] = (degree, c_d)
for k in (0, 1, 2):
    comp = [(d, c[d]) for d in (1, 2, 3) if (d % 3) == k]
    # rho has exactly one degree in each residue class (1,2,3 cover {1,2,0})
    assert len(comp) == 1, f"residue class {k} should hold exactly one degree"
    char_component_coeff[k] = comp[0]

# coefficients by character order (k = 0,1,2):
coeffs_by_char = [char_component_coeff[k][1] for k in (0, 1, 2)]   # (16, 2, 3)
degrees_by_char = [char_component_coeff[k][0] for k in (0, 1, 2)]  # (3, 1, 2)

# the coefficient SET {2,3,16} recovered as character components?
coeff_set_recovered = sorted(coeffs_by_char) == [2, 3, 16]

# ---------------------------------------------------------------------------
# Corpus family <-> character map and reconciliation with family-n <-> c_n.
#
# The mass law (A287) assigns family n the degree-n coefficient:
#     family 1 -> deg 1 -> c_1 = 2
#     family 2 -> deg 2 -> c_2 = 3
#     family 3 -> deg 3 -> c_3 = 16
#
# The Z_3 grading assigns character k the degree-(k or k mod 3) term:
#     char 0 -> deg 3 -> c_3 = 16
#     char 1 -> deg 1 -> c_1 = 2
#     char 2 -> deg 2 -> c_2 = 3
#
# P20 labels the families e, mu, tau by T_cycle eigenvalue 1, omega, omega^2,
# i.e. characters k = 0, 1, 2 in order. The QUESTION is which degree of rho the
# eigenspace-k component carries, and whether composing the corpus family<->char
# label with the Z_3 grading reproduces family-n <-> c_n.
#
# Two candidate family<->character maps:
#   (M-id)   family n -> character (n-1):  fam1->char0, fam2->char1, fam3->char2
#            then via the grading: fam1->deg3->16, fam2->deg1->2, fam3->deg2->3
#            -> assigns (16,2,3), which is NOT (2,3,16). FAILS the n<->n law.
#   (M-deg)  family n -> the character whose graded degree IS n:
#            deg 1 = char 1, deg 2 = char 2, deg 3 = char 0, so
#            fam1->char1, fam2->char2, fam3->char0
#            -> assigns (2,3,16) = c_n exactly. REPRODUCES the n<->n law,
#               at the cost of a mod-3 reindexing on the character label
#               (the family index n is the DEGREE n, not the character k;
#               char 0 carries degree 3, not degree 0).
# ---------------------------------------------------------------------------
# M-id: identity family->character labelling (fam n -> char n-1)
m_id_assign = [char_component_coeff[n-1][1] for n in (1, 2, 3)]   # (16,2,3)
m_id_reproduces = (m_id_assign == [2, 3, 16])

# M-deg: family n -> character k with graded-degree k... == n (i.e. k = n mod 3)
# degree-n term sits in character (n mod 3); family n reads degree n -> c_n.
m_deg_assign = []
for n in (1, 2, 3):
    k = n % 3                      # degree n -> character n mod 3
    deg, coeff = char_component_coeff[k]
    assert deg == n                # the character holds exactly degree n
    m_deg_assign.append(coeff)
m_deg_reproduces = (m_deg_assign == [2, 3, 16])

# The corpus-faithful reconciliation: the family index is the DEGREE n (the mass
# law's own statement); the Z_3 character of degree n is k = n mod 3. So the
# family<->character map is n -> n mod 3, a reindexing in which char 0 carries
# the TOP degree (3), not degree 0. Under this map the character components ARE
# the c_n in family order: (2,3,16). This is a PARTIAL: the coefficient SET is
# exactly the Z_3 character components, but reproducing the n<->n assignment
# needs the mod-3 reindexing char(n) = n mod 3 (so char 0 <-> deg 3) stated.
reindexing_needed = m_deg_reproduces and (not m_id_reproduces)

# ---------------------------------------------------------------------------
# Verdict
# ---------------------------------------------------------------------------
if not (proj_ok and coeff_set_recovered):
    verdict = "NULL"
    verdict_reason = ("the Z_3 character decomposition does not cleanly yield "
                      "the coefficients as components")
elif m_id_reproduces:
    # would mean the identity family->character label already gives (2,3,16)
    verdict = "HIT"
    verdict_reason = ("the Z_3 character decomposition yields (2,3,16) as its "
                      "components AND the identity family<->character map "
                      "reproduces the n<->c_n assignment")
elif reindexing_needed:
    verdict = "PARTIAL"
    verdict_reason = ("the Z_3 character decomposition yields the three "
                      "coefficients (2,3,16) as its character components "
                      "(structurally clean), but reproducing the corpus n<->c_n "
                      "assignment requires the stated mod-3 reindexing "
                      "char(n) = n mod 3, i.e. char 0 <-> degree 3")
else:
    verdict = "NULL"
    verdict_reason = "the family<->character map does not reproduce the assignment"

# ---------------------------------------------------------------------------
# Honesty note on the corpus action
# ---------------------------------------------------------------------------
action_note = (
    "The corpus mandates the Z_3 action as a phase rotation of the Hopf fiber "
    "coordinate, phi -> phi + 2 pi/3 (P18 S3.5 lines 274-285), with eigenspaces "
    "carrying omega^k and quotient L(3,1)=S^3/Z_3 (P06, P20). The grading g: "
    "x -> omega x used here is the natural extension of that phase action to the "
    "degree of a base monomial, under which x^d carries character d mod 3. The "
    "corpus does NOT literally state g acts as x -> omega x on the radial base "
    "coordinate; it states the phase rotation on the fiber. The character "
    "decomposition by degree is therefore the graded reading of rho consistent "
    "with the corpus phase action, not a separately mandated radial action. The "
    "structural result (each rho-degree carries one Z_3 character) holds for any "
    "Z_3 action that grades by monomial degree, which the fiber phase rotation "
    "induces on the homogeneous components."
)

# ---------------------------------------------------------------------------
# Assemble + write
# ---------------------------------------------------------------------------
out = {
    "probe": "P3 / A324 -- Z_3 character decomposition of rho on L(3,1)",
    "object": "O-Z3-grading (gated IN by A322); structural, rho-side only; NO wavefunctions",
    "omega": [OMEGA.real, OMEGA.imag],
    "rho": "16 pi^3 x^3 + 3 pi^2 x^2 + 2 pi x",
    "taylor_coeffs_c": {str(d): c[d] for d in (1, 2, 3)},      # (2,3,16)
    "plain_coeffs_a": {str(d): a[d] for d in (1, 2, 3)},
    "projector_identity_P_k_x_d": {
        f"k={k},d={d}": [proj_matrix[(k, d)].real, proj_matrix[(k, d)].imag]
        for k in (0, 1, 2) for d in (0, 1, 2, 3)
    },
    "projector_identity_holds": bool(proj_ok),
    "character_components_of_rho": {
        "char_0": {"degree": degrees_by_char[0], "coeff_c": coeffs_by_char[0],
                   "term": "16 pi^3 x^3"},
        "char_1": {"degree": degrees_by_char[1], "coeff_c": coeffs_by_char[1],
                   "term": "2 pi x"},
        "char_2": {"degree": degrees_by_char[2], "coeff_c": coeffs_by_char[2],
                   "term": "3 pi^2 x^2"},
    },
    "coeffs_by_character_order_k012": coeffs_by_char,          # (16,2,3)
    "degrees_by_character_order_k012": degrees_by_char,        # (3,1,2)
    "coefficient_set_recovered_as_components": bool(coeff_set_recovered),
    "family_to_character_maps": {
        "M_id (fam n -> char n-1)": {"assigns": m_id_assign,
                                     "reproduces_n<->c_n": bool(m_id_reproduces)},
        "M_deg (fam n -> char n mod 3, char of degree n)": {
            "assigns": m_deg_assign,
            "reproduces_n<->c_n": bool(m_deg_reproduces)},
    },
    "reindexing_needed_char_0_is_deg_3": bool(reindexing_needed),
    "corpus_action_note": action_note,
    "verdict": verdict,
    "verdict_reason": verdict_reason,
    "scope": ("A derivation STEP at most: the coefficient SET is exactly the Z_3 "
              "character components of rho (structurally clean), and the family "
              "assignment n<->c_n is reproduced under the mod-3 reindexing "
              "char(n)=n mod 3. The overlap-diagonal stays withdrawn. P4 (does "
              "this grading pairing reproduce the A287 beta_n mass law) is the "
              "next gated step."),
}

# Outputs/ is four levels up from verify/:
# verify/ -> addenda/ -> corpus/ -> Lumen/ -> LumenOS/  then Outputs/
here = os.path.dirname(os.path.abspath(__file__))
root = os.path.abspath(os.path.join(here, "..", "..", "..", ".."))
outdir = os.path.join(root, "Outputs")
os.makedirs(outdir, exist_ok=True)
outpath = os.path.join(outdir, "oi287_z3decomp.json")
with open(outpath, "w") as f:
    json.dump(out, f, indent=2)

# ---------------------------------------------------------------------------
# Report
# ---------------------------------------------------------------------------
print("="*64)
print("P3 / A324 -- Z_3 character decomposition of rho on L(3,1)")
print("="*64)
print(f"omega = e^(2 pi i/3) = {OMEGA.real:+.6f}{OMEGA.imag:+.6f}i")
print(f"rho = 16 pi^3 x^3 + 3 pi^2 x^2 + 2 pi x ; c = (c1,c2,c3) = "
      f"({c[1]:.0f},{c[2]:.0f},{c[3]:.0f})")
print()
print("Projector identity P_k x^d = [d == k mod 3] x^d :",
      "HOLDS" if proj_ok else "FAILS")
print()
print("Z_3 character components of rho (k = 0,1,2):")
print(f"  P_0 rho = 16 pi^3 x^3   (degree {degrees_by_char[0]}, c = {coeffs_by_char[0]:.0f})")
print(f"  P_1 rho = 2  pi   x     (degree {degrees_by_char[1]}, c = {coeffs_by_char[1]:.0f})")
print(f"  P_2 rho = 3  pi^2 x^2   (degree {degrees_by_char[2]}, c = {coeffs_by_char[2]:.0f})")
print(f"  coefficients by character order (k=0,1,2): {coeffs_by_char}")
print(f"  coefficient SET {{2,3,16}} recovered as components: {coeff_set_recovered}")
print()
print("Family <-> character reconciliation:")
print(f"  M_id  (fam n -> char n-1): assigns {m_id_assign}  "
      f"reproduces n<->c_n: {m_id_reproduces}")
print(f"  M_deg (fam n -> char of degree n = char n mod 3): assigns {m_deg_assign}  "
      f"reproduces n<->c_n: {m_deg_reproduces}")
print(f"  mod-3 reindexing needed (char 0 <-> degree 3): {reindexing_needed}")
print()
print(f"wrote {outpath}")
print()
print(f"VERDICT: {verdict}")
print(f"  {verdict_reason}")
