///////////////////////////////////////////////////////////////////////// // // roots.mgm, written by Jim Stark // Copyright (C) 2015, Jim Stark // // This file contains magma code that computes maximal sets of commuting // roots, lie subalgebras corresponding to those sets, and checks if // such subalgebras can be conjugated to a Chevalley subalgebra. // See ArXiv: 1503.01043 for more information. // ///////////////////////////////////////////////////////////////////////// // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program. If not, see . // ///////////////////////////////////////////////////////////////////////// forward MaximalCommutingRoots; // (R) forward IsIdealOfRoots; // (R, C) forward RootCmp; // (R, a, b) forward Xelt; // (R, L, r) forward Helt; // (R, L, r) forward GenGensOfLieC; // (R, C) forward CommIdeal; // (gens) forward MakeComm; // (~gens) forward MakeSub; // (~gens, v, r) forward AllTerms; // (R, x) forward ReduceGens; // (R, ~gens) forward RootExp; // (R, L, r, lambda) forward SimpleRefl; // (R, L, r) forward ConjToDiag; // (R, ~gens) forward IsDiag; // (gens) forward CheckConj; // (rootStr) // Given a root datum or root system R this returns the maximal // sets of commuting positive roots as a list of lists of root // numbers. function MaximalCommutingRoots(R) n := NumberOfPositiveRoots(R); G := EmptyGraph(n); for i := 1 to n - 1 do for j := i + 1 to n do if Sum(R, i, j) eq 0 then AddEdge(~G, i, j); end if; end for; end for; cliques := AllCliques(G); max := 0; for c in cliques do if #c gt max then max := #c; result := [[Index(v) : v in c]]; elif #c eq max then Append(~result, [Index(v) : v in c]); end if; end for; return result; end function; // Given a root datum/system R and a list C of root numbers (of // positive roots) this returns true if the given set is an ideal // and false if the given set is not an ideal. function IsIdealOfRoots(R, C) for r in C do for i := 1 to NumberOfPositiveRoots(R) do if r eq i then continue i; end if; s := Sum(R, r, i); if s ne 0 and s notin C then return false; end if; end for; end for; return true; end function; // Gives the comparison function for roots as defined in the // paper. For types for which no comparison function was // defined this refines reverse height by the order given // when magma lists the roots. function RootCmp(R, a, b) if Type(a) ne RngIntElt then a := RootPosition(R, a); end if; if Type(b) ne RngIntElt then b := RootPosition(R, b); end if; if a eq b then return 0; end if; case [IsPositive(R, a), IsPositive(R, b)]: when [true, false]: return 1; when [false, true]: return -1; when [false, false]: return $$(R, Negative(R, b), Negative(R, a)); end case; type := CartanName(R)[1]; ar := Root(R, a); br := Root(R, b); n := Rank(R); case type: when "B": ind := [n..1 by -1]; rev := true; when "D": ind := [n, n - 1] cat [1..n - 2]; rev := true; else: if RootHeight(R, a) gt RootHeight(R, b) then return -1; elif RootHeight(R, a) lt RootHeight(R, b) then return 1; else ind := [1..n]; rev := false; end if; end case; for i in ind do if ar[i] eq br[i] then continue i; end if; return ((ar[i] gt br[i]) select 1 else -1)*(rev select -1 else 1); end for; end function; // Given a root datum R and lie algebra L (assumed to be LieAlgebra(R, F) // for some field F) this returns the chevalley basis element x_\alpha // where \alpha is the r-th root. function Xelt(R, L, r) if IsPositive(R, r) then return L.(NumberOfPositiveRoots(R) + Rank(R) + r); else return L.(2*NumberOfPositiveRoots(R) - r + 1); end if; end function; // Given a root datum R and lie algebra L (assumed to be LieAlgebra(R, F) // for some field F) this returns the element h_\alpha where \alpha is the // r-th root. function Helt(R, L, r) return Xelt(R, L, r)*Xelt(R, L, Negative(R, r)); end function; // Given a root datum R and a list of positive root numbers C this returns // a list of elements in LieAlgebra(R, F). The list of elements are the // generators of a generic subalgebra with leading terms from C and F is // a function field with the minimal number of variables needed, save when // no variables are needed F is still a function field of at least one // variable. function GenGensOfLieC(R, C) Sort(~C, func); P := Sort([1..NumberOfPositiveRoots(R)], func); terms := [[c] cat [P[i] : i in [Index(P, c) + 1..#P] | P[i] notin C] : c in C]; vars := &+[#x - 1 : x in terms]; F := FunctionField(Rationals(), Max(1, vars)); L := LieAlgebra(R, F); i := 1; result := []; for inds in terms do Append(~result, Xelt(R, L, inds[1])); for j in [2..#inds] do result[#result] +:= F.i*Xelt(R, L, inds[j]); i +:= 1; end for; end for; return result; end function; // Given a list of generators of a lie subalgebra this returns the ideal // generated by the coordinates in all possible brackets of these // elements. In other words, the ideal which must vanish for the // subalgebra to be commutative. A groebner basis is computed for this // ideal if and only if gb is true. function CommIdeal(gens : gb := true) I := []; for i := 1 to #gens - 1 do for j := i + 1 to #gens do I cat:= [Numerator(x) : x in Eltseq(gens[i]*gens[j])]; end for; end for; I := ideal; if gb then Groebner(I); end if; return I; end function; // Given a list of generators of a lie subalgebra whose field of definition // is a function field this procedure attempts to make the minimal number of // substitutions necessary to get a commutative subalgebra. The resulting // elements are not guarenteed to generate a commutative subalgebra; one // should check if the output of CommIdeal is zero. procedure MakeComm(~gens) L := Parent(gens[1]); F := BaseRing(L); gb := false; repeat I := CommIdeal(gens : gb := gb); v := 0; r := 0; success := false; for b in Basis(I) do coefs, mons := CoefficientsAndMonomials(b); for i := 1 to #mons do if TotalDegree(mons[i]) ne 1 then continue i; end if; v := [j : j in [1..Rank(F)] | Exponents(mons[i])[j] ne 0][1]; for j := 1 to #mons do if j ne i and Exponents(mons[j])[v] ne 0 then continue i; end if; end for; r := mons[i] - coefs[i]^(-1)*b; success := true; break b; end for; end for; if success then MakeSub(~gens, v, r); elif not gb then gb := true; success := true; end if; until gb and not success; end procedure; // Given a list gens of elements of a lie subalgebra whose field of definition // is a function field, a variable number v, and a value r, this procedure // substitutes r into the v-th variable in all the coordinates of the // elements in gens. procedure MakeSub(~gens, v, r) L := Parent(gens[1]); F := BaseRing(L); n := Dimension(L); for i := 1 to #gens do for j := 1 to n do for t in Terms(Numerator(gens[i][j])) cat Terms(Denominator(gens[i][j])) do if v in Support(t) then gens[i][j] := (F!Evaluate(Numerator(gens[i][j]), v, r))/(F!Evaluate(Denominator(gens[i][j]), v, r)); continue j; end if; end for; end for; end for; end procedure; // Given a root datum/system R and an element x of a lie algebra of type R // this function returns a list of root numbers corresponding to the roots // alpha such that x is supported at the chevalley basis element x_alpha. function AllTerms(R, x) n := NumberOfPositiveRoots(R) + Rank(R); result := [i - n : i in [n + 1..2*n - Rank(R)] | x[i] ne 0]; Sort(~result, func); return result; end function; // Given a root system/datum R and a list gens of elements of a lie algebra // of type R this function reduces the generators using the ordering of // roots supplied by RootCmp. procedure ReduceGens(R, ~gens) n := NumberOfPositiveRoots(R) + Rank(R); terms := [AllTerms(R, g) : g in gens]; for i := 1 to #gens do for j := 1 to #gens do if i eq j or gens[j][n + terms[i][1]] eq 0 then continue j; end if; gens[j] -:= (gens[j][n + terms[i][1]]/gens[i][n + terms[i][1]])*gens[i]; terms[j] := AllTerms(R, gens[j]); end for; end for; leadingterms := [x[1] : x in terms]; p := 0; Sort(~leadingterms, func, ~p); gens := [(1/gens[i^p][n + leadingterms[i]])*gens[i^p] : i in [1..#gens]]; end procedure; // Given a root datum R, a lie algebra L of type R, a root number r, and an // element lambda of the base ring of L this function returns the lie algebra // homomorphism exp(lambda*x_alpha): L -> L where alpha is the r-th root. function RootExp(R, L, r, lambda) negr := Negative(R, r); Q := [, ]; for s := 1 to NumberOfPositiveRoots(R) do if s eq r or s eq Negative(R, r) then continue s; end if; Append(~Q, ); string := RightString(R, r, s); for i := 1 to #string do Q[#Q][2] +:= LieConstant_M(R, r, s, i)*lambda^i*Xelt(R, L, string[i]); end for; negs := Negative(R, s); Append(~Q, ); string := RightString(R, r, negs); for i := 1 to #string do Q[#Q][2] +:= LieConstant_M(R, r, negs, i)*lambda^i*Xelt(R, L, string[i]); end for; end for; for s := 1 to Rank(R) do if s eq r or s eq Negative(R, r) then Append(~Q, ); else Append(~Q, ); end if; end for; return hom L | Q>; end function; // Given a root system/datum R, a lie algebra L of type R, and a root number r, // this function returns the lie algebra homomorphism L -> L given by the adjoint // action of a representative of the reflection s_alpha where alpha is the r-th // root. function SimpleRefl(R, L, r) w := ReflectionPermutation(R, r); Q := [ : i in [1..2*NumberOfPositiveRoots(R)]]; Q cat:= [ : i in [1..Rank(R)]]; return hom L | Q>; end function; // Given a root datum R and a list gens of generators of a lie subalgebra this // procedure tries to conjugate the lie subalgebra to Lie(LT()). If status // is true then the elements we conjugate by are printed to the screen. The // resulting gens are not guarenteed to generate Lie(LT()) and should be // checked using IsDiag. procedure ConjToDiag(R, ~gens : status := false) n := NumberOfPositiveRoots(R) + Rank(R); L := Parent(gens[1]); repeat currentMax := Negative(R, 1); for i := 1 to #gens do terms := AllTerms(R, gens[i]); for j := 2 to #terms do max := Sum(R, terms[j], Negative(R, terms[1])); if max eq 0 then continue j; end if; if RootCmp(R, max, currentMax) eq 1 then currentMax := max; indi := i; indst := terms[j]; indlt := terms[1]; end if; continue i; end for; end for; if IsNegative(R, currentMax) then break; end if; f := RootExp(R, L, currentMax, -gens[indi][n+indst]/LieConstant_M(R, currentMax, indlt, 1)); if status then print "Conjugating by ( " cat Sprint(currentMax) cat " , " cat Sprint(-gens[indi][n+indst]/LieConstant_M(R, currentMax, indlt, 1)) cat " )"; end if; gens := [f(x) : x in gens]; ReduceGens(R, ~gens); until false; end procedure; // Given a list of lie algebra elements this function returns true if each // element is supported in a single basis element. When gens come from a // lie algebra of type R for some root datum R this corresponds to the lie // subalgebra they generate being in the form Lie(C) for some set of roots // C. function IsDiag(gens) for g in gens do if #Support(g) ne 1 then return false; end if; end for; return true; end function; // Given a string that defines a root system (or given a root syste/datum) // this function tries to conjugate every maximal abelian lie subalgebra into // the form Lie(C) for some set of roots C. If Csupplied is a string it is // taken to be a file name from which the maximal sets of commuting roots are // read (needed in type E8 and if it is neither a string nor a boolean it is // assume to be exactly the list of maximal sets of commuting roots. If // status is true then the elements we conjugate by are printed to the screen. // The return value is the list of maximal sets of commuting roots which the // function failed to conjugate to the form Lie(C). function CheckConj(rootStr : Csupplied := false, status := false) if Type(rootStr) eq RootDtm then R := rootStr; else R := RootDatum(rootStr); end if; fails := []; if Type(Csupplied) eq BoolElt then print "Computing maximal commuting roots..."; Cs := MaximalCommutingRoots(R); elif Type(Csupplied) eq MonStgElt then print "Loading maximal commuting roots from file..."; Cs := eval Read(Csupplied); else print "Using the supplied list of maximal commuting roots."; Cs := Csupplied; end if; i := 1; for C in Cs do print "Creating " cat Sprint(i) cat " of " cat Sprint(#Cs) cat "..."; i +:= 1; gens := GenGensOfLieC(R, C); MakeComm(~gens); if not IsZero(CommIdeal(gens)) then print "Commutativity substitutions FAILED for " cat Sprint(C) cat "!!"; Append(~fails, C); continue C; end if; print "Checking conjugacy..."; ConjToDiag(R, ~gens : status := status); if IsDiag(gens) then print "Good."; else print "Conjugation to diagonal FAILED for " cat Sprint(C) cat "!!"; Append(~fails, C); end if; end for; return fails; end function;