# -*- coding: utf-8 -*-
"""
DEEP DIVE 2 — Export the mechanism to dimension 2 and see what it forces.

Class: reflection-equivariant maps of C^2,
   sigma = diag(-1, 1) (source),  tau = diag(1, -1) (target)
   F1(-x,y) = F1(x,y)   => F1 = H(u, y),  u = x^2
   F2(-x,y) = -F2(x,y)  => F2 = x * g(u, y)

Results proven/verified below:
  (A) det J_F = 2u*H_u*g_y - H_y*(g + 2u*g_u)   -- a polynomial in (u,y)
  (B) QUOTIENT IDENTITY: the descended map Fbar = (H, u*g^2) on C^2 = C^2/sigma
      has det J(Fbar) = g * det J_F.  For a Keller map (det = c) this reads
                  Jac(H, u g^2) = c * g
      -- the downstairs Jacobian IS the odd part.
  (C) DICHOTOMY: g constant  => F is an automorphism (explicit inverse);
      g nonconstant => F is NON-INJECTIVE (collision pair from any zero of g
      off {u=0}; zeros only on {u=0} forces g = const*u^m which contradicts
      det = const != 0). No middle ground.
  (D) REDUCTION: setting K = u g^2, the Keller condition becomes
                  u * Jac(H,K)^2 = c^2 * K.
      Any polynomial solution with Jac(H,K) nonconstant KILLS JC_2 outright.
  (E) SWEEP: first exclusion data for the new equation.
"""
import sympy as sp
import random, time, json

t0 = time.time()
x, y, u, c, alpha = sp.symbols('x y u c alpha')
G0, G1 = sp.symbols('G0 G1')

def check(label, ok):
    print(f"[{'PASS' if ok else 'FAIL'}] {label}")
    return ok

random.seed(20260721)
def rpoly(deg):
    return sum(sp.Rational(random.randint(-4, 4), random.randint(1, 3)) * u**i * y**j
               for i in range(deg + 1) for j in range(deg + 1 - i))

print("=== (A) the determinant identity ===")
okA = True
for _ in range(5):
    Hp, gp = rpoly(3), rpoly(3)
    F1i = Hp.subs(u, x**2); F2i = sp.expand(x * gp.subs(u, x**2))
    Di = sp.expand(sp.Matrix([F1i, F2i]).jacobian([x, y]).det())
    Ti = sp.expand((2*u*sp.diff(Hp, u)*sp.diff(gp, y)
                    - sp.diff(Hp, y)*(gp + 2*u*sp.diff(gp, u))).subs(u, x**2))
    if sp.expand(Di - Ti) != 0:
        okA = False
check("det J_F = 2u*H_u*g_y - H_y*(g + 2u*g_u)   [5 random exact instances]", okA)

print()
print("=== (B) the quotient identity: downstairs Jacobian = c * g ===")
okB = True
for _ in range(5):
    Hp, gp = rpoly(3), rpoly(3)
    Db = sp.expand(sp.Matrix([Hp, u*gp**2]).jacobian([u, y]).det())
    Tb = sp.expand(gp * (2*u*sp.diff(Hp, u)*sp.diff(gp, y)
                         - sp.diff(Hp, y)*(gp + 2*u*sp.diff(gp, u))))
    if sp.expand(Db - Tb) != 0:
        okB = False
check("Jac(H, u*g^2) = g * [det J_F expression]   [5 random exact instances]", okB)

print()
print("=== (C) dichotomy, constant branch: g = c2 => explicit automorphism ===")
c2 = sp.Symbol('c2')
h = sp.Function('h')
Y1, Y2 = sp.symbols('Y1 Y2')
# g constant c2: det = -c2*H_y = const  =>  H_y = const alpha  =>  H = alpha*y + h(u)
Fex = [alpha*y + h(x**2), c2*x]
Ginv = [Y2/c2, (Y1 - h(Y2**2/c2**2))/alpha]
comp1 = sp.simplify(Fex[0].subs({x: Ginv[0], y: Ginv[1]}))
comp2 = sp.simplify(Fex[1].subs({x: Ginv[0], y: Ginv[1]}))
check("explicit inverse verified: F o G = id  (so linear-odd => AUTOMORPHISM)",
      sp.simplify(comp1 - Y1) == 0 and sp.simplify(comp2 - Y2) == 0)
# degenerate escape hatch g = k*u^m dies:
okC = True
for m in (1, 2, 3):
    k = sp.Symbol('k')
    gm = k*u**m
    D = sp.expand(2*u*sp.diff(rpoly(3), u)*sp.diff(gm, y))  # first term: g_y = 0
    # det = -H_y * (g + 2u g_u) = -(2m+1) k u^m H_y : constant nonzero impossible
    expr = sp.expand(gm + 2*u*sp.diff(gm, u) - (2*m + 1)*k*u**m)
    if expr != 0:
        okC = False
check("g = k*u^m: det = -(2m+1)k u^m H_y -> constant != 0 impossible (m=1,2,3 identity)", okC)
print("        => g nonconstant forces a zero of g OFF {u=0} (C[u,y] factorial +")
print("           nonvanishing polynomial = const), giving x0 = sqrt(u0) != 0 and the")
print("           collision pair (x0,y0) vs (-x0,y0):  F1 equal (even), F2 = 0 both.")

print()
print("=== (C') collision demo on a concrete nonconstant-g instance ===")
# NOT a Keller map (that's the whole open question) — demo of the collision logic only:
gd = y - u        # zero at u=1,y=1 -> x0=1
Hd = u + y**2
F1d = Hd.subs(u, x**2); F2d = sp.expand(x*gd.subs(u, x**2))
p, q = {x: 1, y: 1}, {x: -1, y: 1}
check("demo: distinct pair (+-1, 1) with F1 equal and F2 = 0 at both  (collision)",
      sp.expand(F1d.subs(p) - F1d.subs(q)) == 0
      and F2d.subs(p) == 0 and F2d.subs(q) == 0)

print()
print("=== (D) THE REDUCTION EQUATION:  u * Jac(H,K)^2 = c^2 * K ===")
okD = True
for _ in range(5):
    Hp, gp = rpoly(3), rpoly(2)
    K = sp.expand(u*gp**2)
    Jc = sp.expand(sp.Matrix([Hp, K]).jacobian([u, y]).det())
    # if Jac(H,K) = c*g then u*Jac^2 = u*c^2*g^2 = c^2*K  -- verify the algebra:
    lhs = sp.expand(u*(gp*sp.Symbol('cc'))**2)
    rhs = sp.expand(sp.Symbol('cc')**2 * K)
    if sp.expand(lhs - rhs) != 0:
        okD = False
check("algebraic equivalence: Jac(H,K) = c*g with K = u*g^2  <=>  u*Jac(H,K)^2 = c^2*K", okD)
print("        REDUCTION THEOREM: a polynomial solution (H, K, c) of")
print("            u * Jac(H,K)^2 = c^2 * K,   c != 0,   Jac(H,K) NONCONSTANT")
print("        yields F = (H(x^2,y), x*Jac(H,K)(x^2,y)/c): a Keller map of C^2 that")
print("        is non-injective by the dichotomy  =>  JC_2 IS FALSE.")
print("        Conversely JC_2 true => only constant-Jac solutions exist.")

print()
print("=== (E) SWEEP: exclusion data for the reduction equation ===")
# per-shape linear solve: g-shape fixed with symbolic (G0,G1), H fully general deg<=4
hs = sp.symbols('h0:15')
monH = [u**i * y**j for i in range(5) for j in range(5 - i)]
shapes = {
    'g = G0 + G1*y':   G0 + G1*y,
    'g = G0 + G1*u':   G0 + G1*u,
    'g = G0 + G1*u*y': G0 + G1*u*y,
    'g = G0 + G1*y^2': G0 + G1*y**2,
    'g = G0 + G1*u^2': G0 + G1*u**2,
}
sweep = []
for name, gp in shapes.items():
    Hp = sum(a*m for a, m in zip(hs, monH))
    D = sp.expand(2*u*sp.diff(Hp, u)*sp.diff(gp, y)
                  - sp.diff(Hp, y)*(gp + 2*u*sp.diff(gp, u)))
    P = sp.Poly(D, u, y)
    eqs, constc = [], sp.Integer(0)
    for mono, co in zip(P.monoms(), P.coeffs()):
        if mono == (0, 0):
            constc = co
        else:
            eqs.append(co)
    sol = sp.linsolve(eqs, list(hs))
    verdict = 'NO-SOLUTION'
    if sol != sp.EmptySet:
        tup = list(sol)[0]
        cval = sp.simplify(constc.subs({hh: vv for hh, vv in zip(hs, tup)}))
        # free parameters may remain; check if cval can be nonzero
        verdict = ('EXCLUDED (det forced to 0 => no Keller map with this g-shape)'
                   if cval == 0 else f'LIVE: det = {cval}')
    print(f"   {name:22s} ->  {verdict}")
    sweep.append({'shape': name, 'verdict': str(verdict)})

json.dump({'sweep': sweep, 'H_degree': 4,
           'meaning': 'generic-coefficient exclusion for the reduction equation, '
                      'nonconstant g of the listed shapes, deg H <= 4'},
          open('post-jc-program/breakthrough/dim2_sweep.json', 'w'), indent=2)
print(f"\nartifact: dim2_sweep.json   elapsed: {round(time.time()-t0, 2)}s")
