# A5 checks for A1-7: W_X' actions on (gamma1, gamma6); (7.4) constant, triangularity, leading coefficients (A2, exact).
from fractions import Fraction as Fr
from itertools import combinations
N = 6
adj = {(1,3),(3,4),(4,5),(5,6),(2,4)}
A = [[2 if i == j else (-1 if ((i+1,j+1) in adj or (j+1,i+1) in adj) else 0) for j in range(N)] for i in range(N)]
def refl(i, v):
    c = sum(v[j]*A[j][i] for j in range(N)); w = list(v); w[i] -= c; return tuple(w)
def word_apply(word, v):
    for i in reversed(word): v = refl(i, v)
    return v
g1 = (2,1,2,2,1,0); g6 = (0,1,1,2,2,2)
wg1 = (0,2,3,1,4,3,2,0); wg6 = (5,4,3,1,2,3,4,5)
# enumerate group generated by the two words (as words), record action on gamma1, gamma6
elems = {(): None}; frontier = [()]
def act(word, v): return word_apply(word, v)
seen = {}
def key(word): return (act(word, g1), act(word, g6))
seen[key(())] = ()
fr = [()]
while fr:
    nw = []
    for w in fr:
        for g in (wg1, wg6):
            w2 = g + w
            k = key(w2)
            if k not in seen: seen[k] = w2; nw.append(w2)
    fr = nw
def in_basis(v):  # express v = a*g1 + b*g6
    # g1 has 0 in coord 6 and 2 in coord 1; g6 has 0 in coord 1
    a = Fr(v[0], 2); b = Fr(v[5], 2)
    assert tuple(a*x + b*y for x, y in zip(g1, g6)) == v, v
    return (a, b)
print("number of distinct actions:", len(seen))
for k in seen:
    print("gamma1 ->", in_basis(k[0]), " gamma6 ->", in_basis(k[1]))
# ---- A2 algebra in coroot coordinates (a,b) = a e1 + b e6 ----
def s1(v): a, b = v; return (-a + b, b)
def s6(v): a, b = v; return (a, a - b)
W = {(0,0): None}
group = [((1,0),(0,1))]  # represent elements by images of basis
def compose(f, g): return lambda v: f(g(v))
els = [lambda v: v]; imgs = {((1,0),(0,1)): (lambda v: v, 1)}
fr = [(lambda v: v, 1)]
while fr:
    nw = []
    for f, sg in fr:
        for s in (s1, s6):
            h = (lambda f=f, s=s: (lambda v: s(f(v))))()
            k = (h((1,0)), h((0,1)))
            if k not in imgs: imgs[k] = (h, -sg); nw.append((h, -sg))
    fr = nw
Wel = list(imgs.values()); print("|W(A2)| =", len(Wel))
rho = (1,1)
def add(u, v): return (u[0]+v[0], u[1]+v[1])
def sub(u, v): return (u[0]-v[0], u[1]-v[1])
D = {(0,0):1, (1,0):-1, (0,1):-1, (2,1):1, (1,2):1, (2,2):-1}
def schur_lowest(nu):
    num = {}
    for f, sg in Wel:
        wt = add(sub(rho, f(rho)), f(nu)); num[wt] = num.get(wt, 0) + sg
    num = {k: c for k, c in num.items() if c != 0}
    Q = {}; R = dict(num); steps = 0
    while R:
        steps += 1; assert steps < 10000
        k = min(R, key=lambda t: (t[0]+t[1], t[0])); c = R[k]
        Q[k] = Q.get(k, 0) + c
        for dk, dc in D.items():
            kk = add(k, dk); R[kk] = R.get(kk, 0) - c*dc
            if R[kk] == 0: del R[kk]
    return Q
PhiXpos = [(1,0),(0,1),(1,1)]
def P(lam, t):
    tot = {}
    for r in range(4):
        for I in combinations(PhiXpos, r):
            sI = (sum(x[0] for x in I), sum(x[1] for x in I))
            s = schur_lowest(add(lam, sI))
            for k, c in s.items(): tot[k] = tot.get(k, 0) + c*(-t)**r
    return {k: c for k, c in tot.items() if c != 0}
t = Fr(1, 81)
c0 = P((0,0), t); print("P at lambda=0:", c0, " expected (1+t)(1+t+t^2) =", (1+t)*(1+t+t*t))
def antidominant(v): a, b = v; return (2*a - b <= 0) and (-a + 2*b <= 0)
lams = [(a, b) for a in range(-4, 1) for b in range(-4, 1) if antidominant((a, b))]
ok_tri = True; minlead = None
for lam in lams:
    p = P(lam, t)
    for k in p:
        if not (k[0]-lam[0] >= 0 and k[1]-lam[1] >= 0): ok_tri = False
    lead = p.get(lam, 0)
    minlead = lead if minlead is None else min(minlead, abs(lead))
    # W-invariance check
    for f, sg in Wel:
        for k, cc in p.items():
            assert p.get(f(k), 0) == cc
print("antidominant lambdas tested:", len(lams), " weights in lambda+R:", ok_tri, " min |leading coeff| =", float(minlead))
