# Independent exact checks for the E6/F4 claims audited by A5 (standard library only).
from fractions import Fraction as Fr
from itertools import combinations
N = 6
adj = {(1,3),(3,4),(4,5),(5,6),(2,4)}
A = [[0]*N for _ in range(N)]
for i in range(N):
    for j in range(N):
        if i == j: A[i][j] = 2
        elif (i+1,j+1) in adj or (j+1,i+1) in adj: A[i][j] = -1
def pair(beta, cov):  # <beta, cov>, beta root coords, cov coroot coords (simply laced: Gram = A)
    return sum(beta[i]*A[i][j]*cov[j] for i in range(N) for j in range(N))
def refl(i, v):  # s_i on root (or coroot) coordinates
    c = sum(v[j]*A[j][i] for j in range(N))
    w = list(v); w[i] -= c; return tuple(w)
# positive roots
simple = [tuple(1 if k == i else 0 for k in range(N)) for i in range(N)]
roots = set(simple); frontier = list(simple)
while frontier:
    new = []
    for r in frontier:
        for i in range(N):
            s = refl(i, r)
            if s not in roots: roots.add(s); new.append(s)
    frontier = new
pos = sorted([r for r in roots if all(x >= 0 for x in r)])
print("roots", len(roots), "positive", len(pos))
D4 = [1,2,3,4]  # zero-based nodes 2,3,4,5
def word_apply(word, v):
    for i in reversed(word): v = refl(i, v)
    return v
# w_L: find element of <s_2..s_5> negating all D4 simple roots, via BFS on images of simple roots
from collections import deque
def apply_mat(M, v): return tuple(sum(M[i][j]*v[j] for j in range(N)) for i in range(N))
I = tuple(tuple(1 if i == j else 0 for j in range(N)) for i in range(N))
def mat_of_refl(k):
    cols = [refl(k, simple[j]) for j in range(N)]
    return tuple(tuple(cols[j][i] for j in range(N)) for i in range(N))
def mul(M1, M2): return tuple(tuple(sum(M1[i][k]*M2[k][j] for k in range(N)) for j in range(N)) for i in range(N))
gens = {k: mat_of_refl(k) for k in range(N)}
WL = {I: ()}; dq = deque([I])
while dq:
    M = dq.popleft()
    for k in D4:
        M2 = mul(gens[k], M)
        if M2 not in WL: WL[M2] = (k,) + WL[M]; dq.append(M2)
print("|W(D4)|", len(WL))
wL = [M for M in WL if all(apply_mat(M, simple[k]) == tuple(-x for x in simple[k]) for k in D4)]
assert len(wL) == 1; wL = wL[0]; print("length of w_L", len(WL[wL]))
theta = tuple(tuple(-x for x in row) for row in wL)  # theta = -w_L on root/coroot coords
th = lambda v: apply_mat(theta, v)
PhiL = [r for r in roots if r[0] == 0 and r[5] == 0]
print("|Phi_L|", len(PhiL))
fixed = [r for r in roots if th(r) == r]; neg = [r for r in roots if th(r) == tuple(-x for x in r)]
print("theta-fixed roots = Phi_L:", sorted(fixed) == sorted(PhiL), " roots with theta b=-b:", len(neg))
rootset = set(roots)
bad = [r for r in roots if r not in PhiL and tuple(a+b for a,b in zip(r, th(r))) in rootset]
print("roots b notin Phi_L with b+theta(b) a root:", len(bad))
print("theta maps Phi+ minus Phi_L into Phi-:", all(all(x <= 0 for x in th(r)) for r in pos if r not in PhiL))
# coroot computations (simply laced: coroot coords = root coords)
e1 = tuple(a-b for a,b in zip(simple[0], th(simple[0]))); e6 = tuple(a-b for a,b in zip(simple[5], th(simple[5])))
print("e1 =", e1, " e6 =", e6)
print("<alpha_j, e1>:", [pair(simple[j], e1) for j in range(N)], " <alpha_j, e6>:", [pair(simple[j], e6) for j in range(N)])
print("(1-theta) alpha_j^v for j=2..5:", [tuple(a-b for a,b in zip(simple[k], th(simple[k]))) for k in D4])
# 3 omega_1^v = 2 e1 + e6 ? omega_1^v has <alpha_j, .> = delta_{1j}
def solve_cow(i):  # coweight with <alpha_j, x> = delta_ij, coordinates in coroot basis (rational)
    # A x = e_i  (A symmetric)
    M = [[Fr(A[r][c]) for c in range(N)] + [Fr(1 if r == i else 0)] for r in range(N)]
    for c in range(N):
        p = next(r for r in range(c, N) if M[r][c] != 0); M[c], M[p] = M[p], M[c]
        for r in range(N):
            if r != c and M[r][c] != 0:
                f = M[r][c]/M[c][c]; M[r] = [a - f*b for a,b in zip(M[r], M[c])]
    return tuple(M[r][N]/M[r][r] for r in range(N))
w1 = solve_cow(0); w6 = solve_cow(5)
print("omega_1^v coords:", [str(x) for x in w1])
print("3 omega_1^v == 2e1+e6:", tuple(3*x for x in w1) == tuple(2*a+b for a,b in zip(e1, e6)))
# theta-fixed cocharacters rank: kernel of (theta - 1) on Z^6
def rank(rows):
    M = [[Fr(x) for x in r] for r in rows]; rk = 0; cols = len(M[0])
    for c in range(cols):
        p = next((r for r in range(rk, len(M)) if M[r][c] != 0), None)
        if p is None: continue
        M[rk], M[p] = M[p], M[rk]
        for r in range(len(M)):
            if r != rk and M[r][c] != 0:
                f = M[r][c]/M[rk][c]; M[r] = [a - f*b for a,b in zip(M[r], M[rk])]
        rk += 1
    return rk
thm1 = [[theta[i][j] - (1 if i == j else 0) for j in range(N)] for i in range(N)]
print("rank(theta-1) =", rank(thm1), " => rank X_*(T)^theta =", N - rank(thm1))
# Smith normal form of (1 - theta^*) on X^*(T) = P (weight lattice), omega basis.
# theta^* = -w_L on weights. Matrix of w_L on omega-basis: w_L(omega_i) = omega_i - sum ...; compute via action on roots: roots in omega coords = A^T coords
def to_omega(v):  # root-coordinate vector -> omega coordinates
    return tuple(sum(A[i][j]*v[j] for j in range(N)) for i in range(N))
# action of reflection s_k on omega basis: s_k(omega_i) = omega_i - delta_ik alpha_k
def refl_w(k, w):  # w in omega coords
    ak = to_omega(simple[k]); c = w[k]
    return tuple(w[i] - c*ak[i] for i in range(N))
wordL = WL[wL]
def wL_omega(w):
    for k in reversed(wordL): w = refl_w(k, w)
    return w
om = [tuple(1 if i == j else 0 for i in range(N)) for j in range(N)]
thstar = lambda w: tuple(-x for x in wL_omega(w))
cols = [tuple(a - b for a,b in zip(om[j], thstar(om[j]))) for j in range(N)]
print("(1-theta^*) omega_j:", cols)
def smith_diag(M):
    import math
    M = [list(r) for r in M]; m = len(M); n = len(M[0]); d = []
    r0 = 0
    for c0 in range(min(m, n)):
        # find nonzero pivot with minimal abs in submatrix
        while True:
            entries = [(abs(M[i][j]), i, j) for i in range(r0, m) for j in range(c0, n) if M[i][j] != 0]
            if not entries: return d
            _, pi, pj = min(entries)
            M[r0], M[pi] = M[pi], M[r0]
            for row in M: row[c0], row[pj] = row[pj], row[c0]
            p = M[r0][c0]; done = True
            for i in range(r0+1, m):
                q = M[i][c0] // p; M[i] = [a - q*b for a,b in zip(M[i], M[r0])]
                if M[i][c0] != 0: done = False
            for j in range(c0+1, n):
                q = M[r0][j] // p
                for i in range(m): M[i][j] -= q*M[i][c0]
                if M[r0][j] != 0: done = False
            if done:
                if all(M[i][j] % p == 0 for i in range(r0+1, m) for j in range(c0+1, n)):
                    d.append(abs(p)); r0 += 1; break
                else:
                    for j in range(c0+1, n):
                        if any(M[i][j] % p for i in range(r0+1, m)):
                            i2 = next(i for i in range(r0+1, m) if M[i][j] % p)
                            M[r0] = [a + b for a,b in zip(M[r0], M[i2])]; break
    return d
Mrows = [[cols[j][i] for j in range(N)] for i in range(N)]
print("elementary divisors of 1-theta^* on P:", smith_diag(Mrows))
print("---- part 2 ----")
# W-orbit of the subsystem Phi_L
start = frozenset(PhiL); orb = {start}; fr = [start]
while fr:
    nw = []
    for S in fr:
        for k in range(N):
            S2 = frozenset(refl(k, r) for r in S)
            if S2 not in orb: orb.add(S2); nw.append(S2)
    fr = nw
print("W-orbit of Phi_L:", len(orb), " => |N_W(Phi_L)| =", 51840 // len(orb))
# w_gamma1 = s1 s3 s4 s2 s5 s4 s3 s1 (zero-based 0 2 3 1 4 3 2 0)
wg1 = (0,2,3,1,4,3,2,0); wg6 = (5,4,3,1,2,3,4,5)
PhiLpos = [r for r in PhiL if all(x >= 0 for x in r)]
for name, w in (("w_g1", wg1), ("w_g6", wg6)):
    pres = all(all(x >= 0 for x in word_apply(w, r)) for r in PhiLpos) and all(word_apply(w, r) in set(PhiL) for r in PhiL)
    inv = all(word_apply(w, word_apply(w, s)) == s for s in simple)
    # length = number of positive roots sent to negative
    ln = sum(1 for r in pos if not all(x >= 0 for x in word_apply(w, r)))
    # action on omega_1, omega_6 (omega coords)
    def act_w(word, wv):
        for k in reversed(word): wv = refl_w(k, wv)
        return wv
    print(name, "preserves Phi_L^+:", pres, " involution:", inv, " length:", ln,
          " omega1->", act_w(w, om[0]), " omega6->", act_w(w, om[5]))
# group generated by w_g1, w_g6 acting on simple roots (as matrices)
def word_mat(word):
    M = I
    for k in word: M = mul(M, gens[k])
    return M
g1 = word_mat(wg1); g6 = word_mat(wg6)
grp = {I}; fr = [I]
while fr:
    nw = []
    for M in fr:
        for g in (g1, g6):
            M2 = mul(M, g)
            if M2 not in grp: grp.add(M2); nw.append(M2)
    fr = nw
print("|<w_g1,w_g6>| =", len(grp))
# gamma_1 = alpha_1 + beta_1, beta_1 = w_L alpha_1
b1 = apply_mat(wL, simple[0]); g1r = tuple(a+b for a,b in zip(simple[0], b1))
print("beta_1 =", b1, " gamma_1 =", g1r, " gamma_1 in omega coords:", to_omega(g1r),
      " alpha1-beta1 root?", tuple(a-b for a,b in zip(simple[0], b1)) in rootset, " alpha1+beta1 root?", g1r in rootset,
      " (alpha1,beta1)=", pair(simple[0], b1))
# Levi subsystem sizes for subsets of <=4 nodes
sizes = set(); d4count = 0
for k in range(0, 5):
    for Sub in combinations(range(N), k):
        cnt = sum(1 for r in roots if all(r[i] == 0 for i in range(N) if i not in Sub))
        sizes.add(cnt)
        if cnt == 24: d4count += 1; d4sub = Sub
print("Levi sizes (<=4 nodes):", sorted(sizes), " subsets with 24 roots:", d4count, [x+1 for x in d4sub])
# A3-9: mu_1 = 2a1v + a3v + a4v + a5v + a6v
mu1 = (2,0,1,1,1,1)
phimu1 = tuple(a - b for a,b in zip(mu1, th(mu1)))
print("phi(mu_1) =", phimu1, " 3 omega_1^v =", tuple(3*x for x in w1))
UQ = [r for r in pos if r[0] > 0]; PM = [r for r in pos if r[0] == 0 and r[5] > 0]  # U_{P cap M}: roots of M (alpha1-coeff 0) not in Phi_L, positive
print("|Phi(U_Q)| =", len(UQ), " min <b,mu1> on U_Q:", min(pair(r, mu1) for r in UQ),
      " |Phi(U_{P cap M})| =", len(PM), " min <b,mu1> there:", min(pair(r, mu1) for r in PM))
zeta = tuple(3*x for x in w1)
print("<b,3w1v> on Phi_M:", set(pair(r, zeta) for r in roots if r[0] == 0), " on U_Q:", set(pair(r, zeta) for r in UQ))
# weights of V(omega_1) (27-dim, minuscule => W-orbit of omega_1) lying in Z omega_1 + Z omega_6
orbw = {om[0]}; fr = [om[0]]
while fr:
    nw = []
    for wv in fr:
        for k in range(N):
            w2 = refl_w(k, wv)
            if w2 not in orbw: orbw.add(w2); nw.append(w2)
    fr = nw
print("|W omega_1| =", len(orbw), " weights in Z w1 + Z w6:", [wv for wv in orbw if all(wv[i] == 0 for i in (1,2,3,4))])
print("---- part 3: Brion path of A3-10 ----")
setL = set(PhiL); posset = set(pos)
def vinv_apply(word, r):  # v^{-1} r where v = s_{word[0]} ... s_{word[-1]} ; v^{-1} = reversed product
    for k in word: r = refl(k, r)
    return r
def dimY(word):
    Rv = set(vinv_apply(word, r) for r in pos)        # v^{-1} Phi^+
    Rv = set(r for r in Rv if th(r) in Rv)            # intersect with theta(v^{-1}Phi^+)
    inL = len([r for r in Rv if r in setL]); out = len(Rv) - inL
    assert out % 2 == 0
    return 42 - (4 + inL + out // 2)
path = [(), (0,), (2,0), (3,2,0), (1,3,2,0), (4,3,2,0)]   # v = s1, s3 s1, s4 s3 s1, s2 s4 s3 s1, s5 s4 s3 s1
labels = [None, 0, 2, 3, 1, 4]
for word in path:
    print("v =", ["s%d" % (k+1) for k in word], " dim Y_v =", dimY(word))
# type of each edge: edge from Y_v (parent word) with label alpha lowers to Y_{s_alpha v}; type U iff v^{-1}alpha notin Phi_L
edges = [((), 0), ((0,), 2), ((2,0), 3), ((3,2,0), 1), ((3,2,0), 4)]
for word, a in edges:
    b = vinv_apply(word, simple[a])
    print("edge from v=", ["s%d" % (k+1) for k in word], "label alpha_%d" % (a+1), " v^-1 alpha in Phi_L?", b in setL, " theta(b) == b?", th(b) == b)
print("---- part 4: rank-two vertices of the Brion path ----")
neg = lambda r: tuple(-x for x in r)
def levi_info(word, d, e):
    dp = vinv_apply(word, simple[d]); ep = vinv_apply(word, simple[e])
    s = tuple(a+b for a,b in zip(dp, ep))
    levi = [dp, neg(dp), ep, neg(ep)] + ([s, neg(s)] if s in rootset else [])
    fixed = [r for r in levi if th(r) == r]
    return dp, ep, (s in rootset), fixed, th(dp), th(ep)
for word, d, e in [((0,), 0, 2), ((2,0), 2, 3), ((3,2,0), 3, 1), ((3,2,0), 3, 4), ((3,2,0), 1, 4)]:
    dp, ep, isA2, fixed, tdp, tep = levi_info(word, d, e)
    print("v=", ["s%d" % (k+1) for k in word], "labels a%d,a%d" % (d+1, e+1), " A2?", isA2,
          " theta-fixed Levi roots:", fixed, " in Phi_L:", all(r in setL for r in fixed),
          " theta(d')==-e'?", tdp == neg(ep), " theta(e')==-d'?", tep == neg(dp))
