# -*- coding: utf-8 -*-
"""
PHASE 5b — COMPLETE SYMBOLIC PROOF that det J == 1 for the dim-22 degree-3 map,
via verified elementary factorization (replaces the infeasible direct 22x22
symbolic determinant).

THEOREM (chain decomposition). The final map F_final factors as
    F_final = Phi2^(m) o ... o Phi2^(1) interleaved with aux-extensions
    (F x id) o Phi1,
where every Phi1 / Phi2 is an elementary map whose Jacobian differs from the
identity only on a small support block S. For such matrices,
    M[k,l] = delta_{kl}  whenever k not in S or l not in S
implies det M = det M[S,S]  (Laplace expansion along identity rows/columns).

We therefore verify, PER FACTOR, symbolically and exactly:
  (i)  the support-block property (structural scan of the full symbolic Jacobian),
  (ii) det M[S,S] == 1 (small symbolic determinant, exact),
and PER STEP the composition identity F_new == Phi2 o F_old (symbolic expansion),
plus base case det J == 1 for the 3x3 normalized map (full symbolic det).

Chain rule then gives det J_final == 1 identically. Every link machine-checked.

The replay is DETERMINISTIC (same algorithm as phase 3); we assert the replayed
step log matches the recorded artifact exactly.
"""
import sympy as sp
import json, time

t0 = time.time()
x, y, z = sp.symbols('x y z')

f1 = (1 + x*y)**3 * z + y**2 * (1 + x*y) * (4 + 3*x*y)
f2 = y + 3*x*(1 + x*y)**2 * z + 3*x*y**2 * (4 + 3*x*y)
f3 = 2*x - 3*x**2*y - x**3*z
F = [sp.expand(f3/sp.Integer(2)), sp.expand(f2), sp.expand(f1)]
V = [x, y, z]

art = json.load(open('post-jc-program/degree3_counterexample.json', encoding='utf-8'))
rec_steps = art["elimination_steps"]

proof = {"base_case": None, "factors": [], "steps": [], "ALL_PASS": True}
def check(label, ok):
    print(f"[{'PASS' if ok else 'FAIL'}] {label}")
    if not ok:
        proof["ALL_PASS"] = False
    return ok

# ---- base case: full symbolic 3x3 det --------------------------------------
J3 = sp.Matrix(F).jacobian(V)
d3 = sp.expand(J3.det())
proof["base_case"] = {"det": str(d3)}
check("base case: det J (3x3, normalized map) == 1 FULL SYMBOLIC", d3 == 1)

# ---- factor verifiers -------------------------------------------------------
def verify_phi1_factor(w_sym, mono, Vext):
    """Phi1: (prev, w) -> (prev, w + mono(prev)). Full symbolic Jacobian scan +
    support-block det == 1."""
    n = len(Vext)
    comps = list(Vext[:-1]) + [Vext[-1] + mono]
    Jm = sp.Matrix(comps).jacobian(Vext)
    wi = n - 1
    supp = sorted({wi} | {k for k in range(n) if sp.diff(mono, Vext[k]) != 0})
    # (i) support-block property over the FULL symbolic matrix
    for r in range(n):
        for c in range(n):
            if r not in supp or c not in supp:
                if Jm[r, c] != (1 if r == c else 0):
                    return False, "support property violated"
    # (ii) small symbolic det
    B = Jm[supp, supp]
    db = sp.expand(B.det())
    return db == 1, str(db)

def verify_phi2_factor(i, coeff, slot_u, slot_v, n, Vext):
    """Phi2: Y_i -= coeff * Y_su * Y_sv. Symbolic Jacobian in target coords."""
    Y = sp.symbols(f'Y0:{n}')
    comps = [Y[k] - (coeff * Y[slot_u] * Y[slot_v] if k == i else 0) for k in range(n)]
    Jm = sp.Matrix(comps).jacobian(Y)
    supp = sorted({i, slot_u, slot_v})
    for r in range(n):
        for c in range(n):
            if r not in supp or c not in supp:
                if Jm[r, c] != (1 if r == c else 0):
                    return False, "support property violated"
    B = Jm[supp, supp]
    db = sp.expand(B.det())
    return db == 1, str(db)

# ---- deterministic replay ---------------------------------------------------
aux_registry = {}
aux_n = 0

def high_monomial():
    best = None
    for i in range(len(V)):
        h = sp.expand(F[i] - V[i])
        if h == 0:
            continue
        p = sp.Poly(h, *V)
        for mono, c in zip(p.monoms(), p.coeffs()):
            d = sum(mono)
            if d > 3 and (best is None or d > best[3]):
                best = (i, c, mono, d)
    return best

def monomial_expr(exps):
    return sp.prod([V[k]**exps[k] for k in range(len(exps))])

def split(exps, D):
    a = (D + 1) // 2
    u_e = [0]*len(exps); rem = list(exps); got = 0
    for k in range(len(exps)):
        take = min(rem[k], a - got)
        u_e[k] = take; rem[k] -= take; got += take
        if got == a:
            break
    u_e += [0]*(len(V)-len(u_e)); rem += [0]*(len(V)-len(rem))
    return monomial_expr(u_e), monomial_expr(rem)

def get_aux(m_expr):
    global aux_n
    if m_expr in aux_registry:
        return aux_registry[m_expr], False
    aux_n += 1
    w = sp.Symbol(f'a{aux_n}')
    V.append(w)
    F.append(sp.expand(w + m_expr))
    ok, det_s = verify_phi1_factor(w, m_expr, list(V))
    check(f"  factor Phi1[{w}]: aux-extension w + {m_expr}: support block det == 1 (symbolic)", ok)
    proof["factors"].append({"type": "Phi1", "aux": str(w), "monomial": str(m_expr),
                             "block_det": det_s, "pass": ok})
    aux_registry[m_expr] = w
    return w, True

step_no = 0
while True:
    tgt = high_monomial()
    if tgt is None:
        break
    step_no += 1
    i, c, exps, D = tgt
    m_expr = monomial_expr(exps)
    u, v = split(exps, D)
    wu, _ = get_aux(u)
    wv, _ = get_aux(v)
    slot_u, slot_v = V.index(wu), V.index(wv)
    n = len(V)

    # replay must match the recorded artifact exactly
    r = rec_steps[step_no - 1]
    assert (r["component"] == i and r["monomial"] == str(m_expr)
            and r["u"] == str(u) and r["v"] == str(v)), f"replay diverged at step {step_no}"

    # factor Phi2 verification (target-coordinate symbolic Jacobian)
    ok2, det_s = verify_phi2_factor(i, c, slot_u, slot_v, n, V)
    check(f"step {step_no:2d} factor Phi2: Y_{i} -= ({c})*Y_{slot_u}*Y_{slot_v}: support block det == 1 (symbolic)", ok2)

    # composition identity: F_new == Phi2 o F_old (symbolic)
    F_new_i = sp.expand(F[i] - c * F[slot_u] * F[slot_v])
    direct = sp.expand(F[i] - c*(wu*wv + wu*v + wv*u + u*v))
    okc = sp.expand(F_new_i - direct) == 0
    check(f"step {step_no:2d} composition identity F_new == Phi2 ∘ F_old (symbolic)", okc)
    F[i] = F_new_i
    proof["steps"].append({"step": step_no, "phi2_block_det": det_s,
                           "composition_identity": okc, "pass": ok2 and okc})

check(f"replay reproduced all {len(rec_steps)} recorded steps exactly", step_no == len(rec_steps))

# final map must equal the artifact byte-for-byte (symbolic equality)
F_art = [sp.sympify(s) for s in art["components"]]
ok_final = all(sp.expand(F[k] - F_art[k]) == 0 for k in range(len(V)))
check("replayed final map == published artifact (symbolic equality, all 22 components)", ok_final)

proof["conclusion"] = ("det J_final = (prod of factor dets) * det J_base = 1 * 1 = 1 "
                       "identically, by the chain rule over the verified factorization. "
                       "Every factor det and every composition identity verified symbolically "
                       "in exact arithmetic.")
proof["elapsed_sec"] = round(time.time() - t0, 2)
json.dump(proof, open('post-jc-program/chain_det_proof.json', 'w', encoding='utf-8'), indent=2)
print()
print("=" * 66)
print(f"CHAIN DETERMINANT PROOF: ALL_PASS = {proof['ALL_PASS']}  ({proof['elapsed_sec']}s)")
print("=> det J == 1 IDENTICALLY, proven symbolically via verified factorization")
print("artifact: chain_det_proof.json")
