////////////////////////////////////////////////// // Implementation of parabolic group extensions // Author: Gonzalo TornarĂ­a ////////////////////////////////////////////////// declare type GrpExt; declare attributes GrpExt : group, abelian, self, ambient, pi, gmodule, gmap, _gmodules; intrinsic ParabolicExtension(G :: GrpMat, A :: ModMatFld) -> GrpExt { Construct the parabolic extension of G by A } one := Matrix(One(G)); zero := Matrix(Zero(A)); require IsCompatible(one, zero) : "G and A must have equal degree and base ring"; require &and [ g*a*g^-1 in A : g in Generators(G), a in Generators(A)] : "G must act on A by conjugation"; n := Degree(G); R := BaseRing(G); GL2n := GL(2*n, R); // c : A --> ext c := func< a | BlockMatrix([[one, a], [zero, one]]) >; Cs := [c(r*a) : a in OrderedGenerators(A), r in Basis(R)]; // r : G --> ext r := func< g | BlockMatrix([[g, zero], [zero, g]]) >; Rs := [r(g) : g in OrderedGenerators(G)]; // p : ext --> G p := func< x | ExtractBlock(x, 1, 1, n, n) >; // e := New(GrpExt); e`group := G; e`abelian := sub< GL2n | Cs >; e`self := sub< GL2n | Cs cat Rs >; e`ambient := e; Ps := [p(x) : x in OrderedGenerators(e`self) ]; e`pi := hom< e`self -> e`group | Ps >; cinv := func< x | ExtractBlock(x, 1, 1+n, n, n) >; MA := MatrixAlgebra(R, Dimension(A)); gmap := func< x | Coordinates(A, A!cinv(x)) >; gmat := func< g | MA ! [gmap(g^(-1)*c(a)*g) : a in Basis(A)] >; action := [MA | gmat(r(g)) : g in Generators(G)]; // gmodule corresponding to the ambient e`gmodule := GModule(G, action); // e`gmap : e`abelian -> e`gmodule e`gmap := hom< e`abelian -> e`gmodule | x :-> gmap(x) >; // cache gmodules in the ambient for consistency e`ambient`_gmodules := AssociativeArray(); e`ambient`_gmodules[G] := e`ambient`gmodule; // it is required that G acts on A by conjugation assert Kernel(e`pi) eq e`abelian; assert Image(e`pi) eq e`group; assert #e`abelian eq #A; assert #e`self eq #e`group * #e`abelian; return e; end intrinsic function sub(e, s) assert s subset e`self; f := New(GrpExt); f`group := e`pi(s); f`abelian := e`abelian meet s; f`self := s; f`ambient := e`ambient; Ps := [e`pi(x) : x in OrderedGenerators(f`self)]; // compute gmodule f`pi := hom< f`self -> f`group | Ps>; b, gm := IsDefined(f`ambient`_gmodules, f`group); if not b then gm := Restriction(f`ambient`gmodule, f`group); f`ambient`_gmodules[f`group] := gm; end if; f`gmodule := sub< gm | [f`ambient`gmap(a) : a in Generators(f`abelian)] >; f`gmap := hom< f`abelian -> f`gmodule | x :-> f`ambient`gmap(x) >; assert Kernel(f`pi) eq f`abelian; assert Image(f`pi) eq f`group; assert #f`self eq #f`group * #f`abelian; return f; end function; ////////////////////////////////////////////////// // Some Lie algebras (gl_n, sl_n, sp_n, gsp_n) function gl(n, R) return RMatrixSpace(R, n, n); end function; function sl(n, R) A := gl(n, R); B := RSpace(R, 1); m := homB | [ [Trace(m)] : m in OrderedGenerators(A)]>; return Kernel(m); end function; // the standard symplectic form used by Sp(n, q) in magma function symplectic_form(n, R) assert IsEven(n); J := Matrix(R, n, [i+j eq n+1 select (i lt j select 1 else -1) else 0 : i,j in [1..n] ]); assert J+Transpose(J) eq 0; assert J*Transpose(J) eq 1; return J; end function; function sp(n, R) assert IsEven(n); J := symplectic_form(n, R); A := gl(n, R); m := homA | [ mJ-Transpose(mJ) where mJ is m*J : m in OrderedGenerators(A)]>; return Kernel(m); end function; function gsp(n, R) assert IsEven(n); J := symplectic_form(n, R); assert J[1,n] eq 1; A := gl(n, R); m := homA | [ m1 - mu*J where mu := m1[1,n] // m[1,1] + m[n,n] where m1 := mJ-Transpose(mJ) where mJ is m*J : m in OrderedGenerators(A)]>; return Kernel(m); end function; intrinsic SmallParabolic(G :: GrpMat) -> GrpExt { Small parabolic as a group extension } n := Degree(G); R := BaseRing(G); require IsEven(n) : "Degree of G must be even"; spn := sp(n, R); gspn := gsp(n, R); e := ParabolicExtension(G, spn); // use the normalizer as ambient space a := ParabolicExtension(G, gspn); return sub(a, e`self); end intrinsic; intrinsic Normalizer(e :: GrpExt) -> GrpExt { Normalizer of a group extension inside its ambient space } return sub(e`ambient, Normalizer(e`ambient`self, e`self)); end intrinsic; intrinsic Centralizer(e :: GrpExt) -> GrpExt { Centralizer of Normalizer(e) } return sub(e`ambient, Centralizer(Normalizer(e)`self, e`self)); end intrinsic; intrinsic GModule(e :: GrpExt) -> ModGrp { GModule corresponding to e } return e`gmodule; end intrinsic; ////////////////////////////////////////////////// intrinsic Group(e :: GrpExt) -> GrpMat { .. } return e`group; end intrinsic; intrinsic Abelian(e :: GrpExt) -> GrpMat { .. } return e`abelian; end intrinsic; intrinsic Self(e :: GrpExt) -> GrpMat { .. } return e`self; end intrinsic; intrinsic Ambient(e :: GrpExt) -> GrpMat { .. } return e`ambient; end intrinsic; intrinsic BaseRing(e :: GrpExt) -> Rng { .. } return BaseRing(Group(e)); end intrinsic; intrinsic Dimension(e :: GrpExt) -> RngIntElt { .. } return Integers() ! Log(#BaseRing(e), #Abelian(e)); end intrinsic; intrinsic '#'(e :: GrpExt) -> RngIntElt { .. } return #Self(e); end intrinsic; intrinsic GroupNameExt(G :: GrpMat : TeX := false) -> Str { ... } GN := GroupName(G : TeX:=TeX); G_3 := [g : g in G | Order(g) eq 3]; G_6 := [g : g in G | Order(g) eq 6]; if (#G_3 gt 0 and &and [Trace(g) eq 0 : g in G_3]) or (#G_6 gt 0 and &and [Trace(g) eq 0 : g in G_6]) then return GN cat "(A)"; end if; if (#G_3 gt 0 and &and [Trace(g) eq 1 : g in G_3]) or (#G_6 gt 0 and &and [Trace(g) eq 1 : g in G_6]) then return GN cat "(B)"; end if; return GN; end intrinsic; intrinsic Print(e :: GrpExt) { .. } printf "GrpExt of %o by GF(%o)^%o", GroupNameExt(Group(e)), #BaseRing(e), Dimension(e); end intrinsic; intrinsic Restriction(e :: GrpExt, H :: GrpMat) -> GrpExt { .. } require H subset e`group : "H must be a subgroup of G"; return sub(e, H @@ e`pi meet e`self); end intrinsic; intrinsic Conjugates(e :: GrpExt, f :: GrpExt) -> [] { .. } return Conjugates(e`self, f`self); end intrinsic; intrinsic Conjugates(e :: GrpExt) -> [] { .. } return Conjugates(e`ambient`self, e`self); end intrinsic; intrinsic IsConjugate(e :: GrpExt, f :: GrpExt) -> BoolElt { .. } require e`ambient eq f`ambient: "ambient spaces must be equal"; return IsConjugate(e`ambient`self, e`self, f`self); end intrinsic; intrinsic FilterConjugates(es :: [GrpExt]) -> [] { .. } fs := []; ii := []; for i := 1 to #es do for j := 1 to #fs do if IsConjugate(es[i], fs[j]) then Append(~ii[j], i); continue i; end if; end for; // not found Append(~fs, es[i]); Append(~ii, [i]); end for; return fs, ii; end intrinsic; intrinsic Subextensions(e :: GrpExt : Codim := -1) -> [] { .. } if Codim eq -1 then candidates := [ s`subgroup : s in Subgroups(e`self : OrderMultipleOf:=#e`group , OrderDividing:=#e`self) ]; elif Codim gt Dimension(e) then return []; else q := #BaseRing(e); o := IntegerRing() ! (#e/q^Codim); candidates := [ s`subgroup : s in Subgroups(e`self : OrderEqual := o) ]; end if; return [ sub(e, s) : s in candidates | e`pi(s) eq e`group ]; end intrinsic; intrinsic 'meet' (e :: GrpExt, f :: GrpExt) -> GrpExt { .. } return sub(e, e`self meet f`self); end intrinsic; intrinsic 'subset' (e :: GrpExt, f :: GrpExt) -> BoolElt { .. } return Self(e) subset Self(f); end intrinsic; intrinsic 'eq' (e :: GrpExt, f :: GrpExt) -> BoolElt { .. } assert e`ambient`self eq f`ambient`self; return Self(e) eq Self(f); end intrinsic; // m can be of type HomGrp or GrpAutoElt intrinsic IsIsomorphism(m, e :: GrpExt, f :: GrpExt) -> BoolElt { .. } return IsTrivial(Kernel(m)) and Image(m) eq f`self and // m should commute with the projections pi &and[ x @ e`pi eq x @ m @ f`pi : x in Generators(e`self) ]; end intrinsic; intrinsic IsIsomorphic (e :: GrpExt, f :: GrpExt) -> BoolElt, Map { test isomorphism as group extensions } if e`group ne f`group or #e`abelian ne #f`abelian then return false; end if; b, m := IsIsomorphic(e`self, f`self); if not b then return false; end if; // may or may not be isomorphic as group extensions error if m(e`abelian) ne f`abelian, "Not implemented -- FIXME"; b, g := IsInnerAutomorphism(e`group, Inverse(e`pi) * m * f`pi); // may or may not be isomorphic as group extensions error if not b, "Not implemented for non-inner -- FIXME"; gg := g @@ f`pi; mm := hom< e`self->f`self | [gg*m(x)*gg^-1 : x in OrderedGenerators(e`self)] >; // mm should be an isomorphism assert IsIsomorphism(mm, e, f); return true, mm; end intrinsic; intrinsic AutomorphismGroup(e :: GrpExt) -> GrpAuto { automorphisms as group extensions } aut := AutomorphismGroup(e`self); autg := AutomorphismGroup(e`group); // m1 : autfp -> aut // m2 : autfp -> autp autfp, m1 := FPGroup(aut); autp, m2 := PermutationGroup(autfp); k := Kernel(homautg | [ home`group | [x @@ e`pi @ (a@@m2@m1) @ e`pi : x in OrderedGenerators(e`group)]> : a in OrderedGenerators(autp)] >); return k; end intrinsic; intrinsic OuterAutomorphismRepresentatives(e :: GrpExt) -> [] { outer aut as gp ext (modulo inner aut by normalizer !!!)} aut := AutomorphismGroup(e`self); autg := AutomorphismGroup(e`group); // m1 : autfp -> aut // m2 : autfp -> outfp // m3 : outfp -> outp autfp, m1 := FPGroup(aut); outfp, m2 := OuterFPGroup(aut); outp, m3 := PermutationGroup(outfp); // m0 : outp -> aut m0 := Inverse(m3) * Inverse(m2) * m1; out := [ m0(x) : x in outp ]; /* error if not &and[ IsIsomorphism(x, e, e) : x in out ], */ /* "an outer automorphism is not identity on G -- FIXME"; */ return out; /* v := e`abelian; vg := e`self; out3 := [m0(x) : x in outp | v @ m0(x) eq v and vg @ m0(x) eq vg]; // must fix x as in 'IsIsomorphic' so it is an isomorphism // however, it seems to be ok due to the way magma computes aut gp out2 := [ m0(x) : x in outp | b where b,g := IsInnerAutomorphism(e`group, home`group | [g @@ e`pi @ m0(x) @ e`pi : g in OrderedGenerators(e`group)]> )]; print #Kernel(m2), #Set(out3), #out3, #outp, #out2; error if not &and[ IsIsomorphism((x), e, e) : x in out2 ], "an outer automorphism is not identity on G -- FIXME"; return out2; //return "-", #out2, #out3, #outp, "-"; */ end intrinsic; intrinsic GaloisExtension(R2 :: FldAb, VGs :: []) -> GrpExt { HACK, compute VGs := IsomorphismClasses(Subextensions(SmallParabolic(Image(rho)))); } gal, r, s := AbsoluteGaloisGroup(R2); for VG in VGs do b, m := IsIsomorphic(gal, VG`self); if b then print Dimension(VG); end if; end for; return 0; end intrinsic; intrinsic GaloisExtension(R2 :: FldAb, R1 :: FldNum, rho :: HomGrp) -> GrpExt { Construct an extension corresponding to rho. WARNING: This is a hack that works by finding a parabolic extension so it will be ok as long as G has no outer automorphisms, otherwise we should fix it by checking traces of frobenius or something like that. IOW the aim at first is to construct an extension corresponding to some conjugate of rho } gal, r, s := AbsoluteGaloisGroup(R2); G := Image(rho); SG := SmallParabolic(G); for VG in IsomorphismClasses(Subextensions(SG)) do b, m := IsIsomorphic(gal, VG`self); if b then print Dimension(VG); end if; end for; return 0; /* one := Matrix(One(G)); zero := Matrix(Zero(A)); */ /* require Parent(one) eq Parent(zero) */ /* : "G and A must have equal degree and base ring"; */ /* n := Degree(G); */ /* R := BaseRing(G); */ /* GL2n := GL(2*n, R); */ /* // c : A --> ext */ /* c := func< a | BlockMatrix([[one, a], [zero, one]]) >; */ /* Cs := [c(a) : a in OrderedGenerators(A)]; */ /* // r : G --> ext */ /* r := func< g | BlockMatrix([[g, zero], [zero, g]]) >; */ /* Rs := [r(g) : g in OrderedGenerators(G)]; */ /* // p : ext --> G */ /* p := func< x | ExtractBlock(x, 1, 1, n, n) >; */ /* // */ e := New(GrpExt); e`group := Image(rho); /* e`abelian := sub< GL2n | Cs >; */ /* e`self := sub< GL2n | Cs cat Rs >; */ /* e`ambient := e`self; */ /* Ps := [p(x) : x in OrderedGenerators(e`self) ]; */ /* e`pi := hom< e`self -> e`group | Ps >; */ /* // it is required that G acts on A by conjugation */ /* assert Kernel(e`pi) eq e`abelian; */ /* assert Image(e`pi) eq e`group; */ /* assert #e`self eq #e`group * #e`abelian; */ /* return e; */ end intrinsic