diff --git a/grp/simple.gd b/grp/simple.gd index 7863ef7c79..882cee7ed1 100644 --- a/grp/simple.gd +++ b/grp/simple.gd @@ -121,6 +121,7 @@ BindGlobal("SIMPLE_GROUPS_ITERATOR_RANGE",10^27); ## <#/GAPDoc> DeclareGlobalFunction("ClassicalIsomorphismTypeFiniteSimpleGroup"); +DeclareGlobalFunction("MinimalFaithfulPermutationDegreeOfSimpleGroupWithIsomorphismType"); DeclareAttribute("DataAboutSimpleGroup",IsGroup,"mutable"); ############################################################################# diff --git a/grp/simple.gi b/grp/simple.gi index 30abd8f5a7..29f90d38ee 100644 --- a/grp/simple.gi +++ b/grp/simple.gi @@ -954,6 +954,134 @@ local p,e,f,rels,gp; return gp; end); +BindGlobal("SporadicGroupMinimalFaithfulPermutationDegrees", rec( + M11 := 11, + M12 := 12, + M22 := 22, + M23 := 23, + M24 := 24, + Co1 := 98280, + Co2 := 2300, + Co3 := 276, + McL := 275, + HS := 100, + Suz := 1782, + Fi22 := 3510, + Fi23 := 31671, + Fi24 := 306936, + M := 97239461142009186000, + B := 13571955000, + Th := 143127000, + HN := 1140000, + He := 2058, + J1 := 266, + J2 := 100, + J3 := 6156, + J4 := 173067389, + ON := 122760, + Ly := 8835156, + Ru := 4060, +)); + +InstallGlobalFunction(MinimalFaithfulPermutationDegreeOfSimpleGroupWithIsomorphismType,function (info) + # This function is derived from table 4 of this paper : + # https://www.ams.org/journals/tran/2015-367-11/S0002-9947-2015-06293-X/S0002-9947-2015-06293-X.pdf + + # `info` is the a record containing information about the type of the simple group, + # like one obtained from `IsomorphismTypeInfoFiniteSimpleGroup`. You need to give the series, + # parameter, and shortname values in the record. + local + series, # series of simple groups + d, # mostly the dimension of vector space for classical groups + q, # elements in the field over which group is defined + m, # first parameter + b; # q = p^b for some prime p + + series := info.series; + if series = "Spor" then + return SporadicGroupMinimalFaithfulPermutationDegrees.(info.shortname); + else + if IsList(info.parameter) then + q := info.parameter[2]; + m := info.parameter[1]; + else + q := info.parameter; + fi; + fi; + if series = "Z" then #Cyclic group of prime order + return q; + elif series = "A" then # Alternating group + return q; + elif series = "L" then # PSL(m,q) + d := m; + if (d = 4 and q = 2) then return 8; fi; + if d = 2 then + if q = 9 then return 6; fi; + if q in [5,7,11] then return q; fi; + fi; + return (q^d-1)/(q-1); + elif series = "2A" then # PSU(m+1,q) + d := m + 1; + if d = 3 and q = 5 then return 50; fi; + if d = 3 then return q^3 + 1; fi; + if d = 4 then return (q+1)*(q^3 + 1); fi; + if d mod 2 = 0 and q = 2 then return (2^(d-1)*(2^d - 1))/3; fi; + return ((q^d - (-1)^d)*(q^(d-1) + (-1)^d))/(q^2-1); + elif series = "B" then # P\Omega(2*m+1,q) or O + if q = 3 and m > 2 then return (3^m)*(3^m - 1)/2; + elif q > 4 and m > 2 then return (q^(2*m)-1)/(q-1); + elif q = 3 and m = 2 then return 27; #Special case : B(2,3) ~ 2A(3,2) = PSU(4,2) + elif q = 2 and m = 2 then # B(2,2) is not a simple group. + Error("B(2,2) is not a simple group. This shouldn't be happening.\n"); + elif m = 2 then return (q^(2*m) -1)/(q-1); #Special case : B(2,q) ~ C(2,q) = PSp(4,q) + elif q = 2 then return (2^(m-1))*(2^m -1); #Special case : B(m,2) ~ C(m,2) = PSp(2*m,2) + else Error("series B and m,q not of proper form\n"); fi; + elif series = "2B" then # Sz or _2 B^2 + b := Log2Int(q); + if 2^b = q and b mod 2 = 1 then return q^2 + 1; + else Error("2B series without q of proper form\n"); fi; + elif series = "C" then # PSp(2*m,q) + d := 2*m; + if d=4 and q=2 then return 6;fi; + if d=4 and q=3 then return 27;fi; + if m>2 and q=2 then return (2^(m-1))*(2^m -1);fi; + if m>1 and q>2 then return (q^d -1)/(q-1);fi; + Error("series C and m,q are not of proper form\n"); + elif series = "D" then # POmega(+1,2*m,q) or O+ + if m > 3 then + if q < 4 then return q^(m-1)*(q^m -1)/(q-1); + else return (q^(m-1) + 1)*(q^m-1)/(q-1); fi; + else Error("series D and m < 4\n"); fi; + elif series = "2D" then # POmega(-1,2*m,q) or O- + if m > 3 then return (q^m+1)*(q^(m-1)-1)/(q-1); + else Error("series 2D and m < 4\n"); fi; + elif series = "3D" then # ^3 D_4 + return (q^8 + q^4 + 1)*(q+1); + elif series = "E" then #E_n(q) + if m = 6 then return (q^9 - 1)*(q^8 + q^4 + 1)/(q-1); + elif m = 7 then return (q^14 - 1)*(q^9 + 1)*(q^5 -1)/(q-1); + elif m = 8 then return (q^30 - 1)*(q^12 + 1)*(q^10 + 1)*(q^6 + 1)/(q-1); + else Error("series E and m is not 6,7 or 8\n"); + fi; + elif series = "2E" then #2E(6,q) + return (q^12 -1)*(q^6 - q^3 + 1)^(q^4 +1)/(q-1); + elif series = "F" then #F(4,q) + return (q^12 -1)*(q^4 + 1)/(q-1); + elif series = "2F" then #2F(4,q) + if q = 2 then return 1600; #special case : 2F4(2) ~ Tits + else return (q^6 + 1)*(q^3 + 1)*(q+1); fi; + elif series = "G" then #G(2,q) + if q = 3 then return 351; + elif q = 4 then return 416; + else return (q^6 -1)/(q-1); fi; + elif series = "2G" then #2G(2,q) + b := PValuation(q,3); + if q = 3^b and b mod 2 = 1 then return q^3 + 1; + else Error("series 2G and q not of proper form\n"); fi; + fi; + Error("series `",series,"` is not valid\n"); +end); + InstallOtherMethod(DataAboutSimpleGroup,true,[IsRecord],0, function(id) local nam,e,efactors,par,expo,prime,result,aut,i,classical,classaut,shortname, @@ -1219,6 +1347,7 @@ local nam,e,efactors,par,expo,prime,result,aut,i,classical,classaut,shortname, tomName:=nam, allExtensions:=e, fullAutGroup:=aut, + minPerDeg:=MinimalFaithfulPermutationDegreeOfSimpleGroupWithIsomorphismType(id), classicalId:=ClassicalIsomorphismTypeFiniteSimpleGroup(id)); if classaut<>fail then result.outerAutomorphismGroup:=classaut; diff --git a/lib/grplatt.gd b/lib/grplatt.gd index 857a23c853..eb1d916a02 100644 --- a/lib/grplatt.gd +++ b/lib/grplatt.gd @@ -535,6 +535,9 @@ DeclareSynonym("EmbeddingConjugates",ContainingConjugates); ## positive integer n=\mu(G) such that G is isomorphic to a ## subgroup of the symmetric group of degree n. ## This can require calculating the whole subgroup lattice. +## In case you know that G is simple or semi-simple, you can use +## MinimalFaithfulPermutationDegreeOfSimpleGroup and +## MinimalFaithfulPermutationDegreeOfSemiSimpleGroup instead. ## The operation ## ## returns a @@ -556,6 +559,7 @@ DeclareSynonym("EmbeddingConjugates",ContainingConjugates); DeclareOperation("MinimalFaithfulPermutationDegree",[IsGroup and IsFinite]); DeclareOperation("MinimalFaithfulPermutationRepresentation", [IsGroup and IsFinite]); +DeclareGlobalFunction("MinimalFaithfulPermutationDegreeOfFittingFreeGroup"); ############################################################################# ## diff --git a/lib/grplatt.gi b/lib/grplatt.gi index 4f7a0d5569..ca346e66d7 100644 --- a/lib/grplatt.gi +++ b/lib/grplatt.gi @@ -3654,6 +3654,481 @@ function(G) return DoMinimalFaithfulPermutationDegree(G,true); end); +######################################################################### +## +#F CanLiftPermutationDegreeToNormaliserOfSimpleMatrixGroup(,,,,) +## +## Checks whether mu(A) = mu(S) when S is isomorphic to the +## simple matrix group specified by "d","q" and "type", +## where A is an automorphism subgroup of S, +## made of all conjugators ^n for all n in normaliser of S in G, +## and mu(X) is the Minimal Faithful Permutation Degree of X. +## This is implemented, as described in this research paper: +## https://dl.acm.org/doi/10.1145/3618260.3649641 +BindGlobal("CanLiftPermutationDegreeToNormaliserOfSimpleMatrixGroup",function(S,G,d,q,type) + # S is a simple subgroup of G, which is isomorphic to PSL(d,q) , or PSp(d,q) , or POmega(1,2d,q) + # type is the type of simple group we are dealing with ("PSL","PSp","POmega+") + # For the sake of sanity, the varaibles are chosen to represent the process for type="PSL" only, + # but work functionally, for every type of simple matrix group specified. + local + Sldq, # SL(d,q) with generators Slgen + Slgen, # Very specific generating set of SL(d,q), or correspoding group based on "type" + p, # q = p^e + s,g, # Any element in S + m2, # A homomorphism between SL(d,q) and PSL(d,q) + i,j,x,r, # Dummy variables + pS, # PSL(d,q) + AutpSgens, # Generators of AutpS + lambda, # Any automorphism from Sldq to Sldq + C, # Centraliser of S in G, + # and later, the Center of Sldq, + m2lambm2inv, # A function that returns the composition m2inv * lambda * m2 , + # given lambda, where m2inv maps to the elements in coset with order p + AutSlgens, # Generators of AutSl + alpha, # The automorphism corresponding to m2lambm2inv + alphaSlgen, # Images of Slgen under alpha + StopS, # An isomorphism from S to pS + pStoS, # An isomorphism from pS to S + A, # Group of conjugation automorphisms of S with elements from G + U, # Any matrix in Slgen + N, # Normaliser of S in G + NbyC, # Natural Homomorphism from N, by normal subgroup C + Ngens, # Generators of N + AutS, # The group made of conjugator automorphisms ^n for all n in N, + # also called A. + NgensNeeded, # A minimal subset of Ngens that still creates AutS + good, # A boolean + n, # any element of N + AutSgens, # Generators of group AutS (also called A) + pSgens, # Generators of pS + StoS, # Any automorphism of S, can also be called lambda + alphapSgens, # Images of Hgens under alpha + h, # any element of pS + pStopS, # Any automorphism of pS, can also be called alpha + lambda_g, # Image of g under lambda (StoS) + alpha_h, # Image of h under alpha (pStoHpS) + AutpS, # The Automorphism subgroup of pS isomorphic to A + g_list, # preimages of pSgens under the isomorphism StopS + lambda_g_list, # Images of g_list under any isomorphism of S, StoS + L, # Any list + conj, # true if everything in A is a conjugator, + # upto a field automorphism + M, # Any matrix + f, # Any field automorphism of GF(q) + alphafinv, # alpha * f^-1 + scalars, # all required elements from GF(q) + flisinit, # initial list of field automorphisms + finvlisinit, # f^-1 for f in flisinit + findlis, # list of indices of flisinit + finvlis,finv, + FirstOfimagesOfscalarMatrices, + scalarMatrices,imagesOfscalars, + MakeFieldAutomorphismOfSldq,finvmatrixlist,O,phi,PO,POgens; + + # Computing Normaliser and Centraliser + N := Normaliser(G,S); + C := Centraliser(G,S); + Ngens := SmallGeneratingSet(N); + + # Computing NgensNeeded + NbyC := NaturalHomomorphismByNormalSubgroupNC(N,C); + NgensNeeded := ImagesSet(NbyC,Ngens); + NgensNeeded := List(NgensNeeded,x->PreImagesRepresentative(NbyC,x)); + + # Finding generators of AutS (A) + AutSgens := List(NgensNeeded,n -> ConjugatorAutomorphismNC(S,n)); + + # Calculating Sldq + p := PrimeDivisors(q)[1]; + Slgen := []; + if type = "PSL" then + for i in [1..d] do + for j in [1..d] do + if i=j then continue; fi; + for r in [0,1..p-1] do + U := IdentityMatrix(GF(q),d); + U[i][j] := Z(q)^r; + Add(Slgen,U); + od; + od; + od; + elif type="POmega+" then + for j in [2..d] do + for i in [1..j-1] do + for r in [0,1..q-2] do + # I + z(e_{i,j} - e_{-j,-i}) + U := IdentityMatrix(GF(q),2*d); + U[i][j] := Z(q)^r; + U[d+j][d+i] := -Z(q)^r; + Add(Slgen,U); + # I + z(e_{j,i} - e_{-i,-j}) + U := IdentityMatrix(GF(q),2*d); + U[j][i] := Z(q)^r; + U[d+i][d+j] := -Z(q)^r; + Add(Slgen,U); + # I + z(e_{i,-i} - e_{j,-i}) + U := IdentityMatrix(GF(q),2*d); + U[i][d+j] := Z(q)^r; + U[j][d+i] := -Z(q)^r; + Add(Slgen,U); + # I + z(e_{-i,j} - e_{-j,i}) + U := IdentityMatrix(GF(q),2*d); + U[d+i][j] := Z(q)^r; + U[d+j][i] := -Z(q)^r; + Add(Slgen,U); + od; + od; + od; + d := 2*d; + elif type="PSp" then + for j in [2..d] do + for i in [1..j-1] do + for r in [0,1..q-2] do + # I + z(e_{i,j} - e_{-j,-i}) + U := IdentityMatrix(GF(q),2*d); + U[i][j] := Z(q)^r; + U[d+j][d+i] := -Z(q)^r; + Add(Slgen,U); + # I - z(e_{-i,-j} - e_{j,i}) + U := IdentityMatrix(GF(q),2*d); + U[j][i] := Z(q)^r; + U[d+i][d+j] := -Z(q)^r; + Add(Slgen,U); + # I + z(e_{i,-i} + e_{j,-i}) + U := IdentityMatrix(GF(q),2*d); + U[i][d+j] := Z(q)^r; + U[j][d+i] := Z(q)^r; + Add(Slgen,U); + # I - z( - e_{-i,j} - e_{-j,i}) + U := IdentityMatrix(GF(q),2*d); + U[d+i][j] := Z(q)^r; + U[d+j][i] := Z(q)^r; + Add(Slgen,U); + od; + od; + od; + for i in [1..d] do + # I + z e_{i,-i} + U := IdentityMatrix(GF(q),2*d); + U[i][d+i] := Z(q)^r; + Add(Slgen,U); + # I + z e_{-i,i} + U := IdentityMatrix(GF(q),2*d); + U[d+i][i] := Z(q)^r; + Add(Slgen,U); + od; + d := 2*d; + fi; + Sldq := GroupWithGenerators(Slgen); + + # Calculating m2 and pS + if type="PSL" or type="PSp" then + C := Center(Sldq); + elif type="POmega+" then + C := Center(GO(1,d,q)); + C := Filtered(C,x->x in Sldq); #There are only O(q) elements in C + C := AsGroup(C); + fi; + m2 := NaturalHomomorphismByNormalSubgroupNC(Sldq,C); + pS := Image(m2); #PSL(d,q),PSp(d,q),or POmega+(2d,q) + + # Calculating StopS + StopS := IsomorphismSimpleGroups(S,pS); # Isomorphism between S and pS + if StopS = fail then StopS := IsomorphismGroups(S,pS);fi; + + # Calculating AutpSgens + AutpSgens := List(AutSgens,x -> InducedAutomorphism(StopS,x)); + + # Function to get alpha for any lambda + m2lambm2inv := function(U,lambda,m2,C,p) + local UZ,VZ,VZrep,V; + UZ := Image(m2,U); + VZ := Image(lambda,UZ); + VZrep := PreImagesRepresentative(m2,VZ); + if Size(C)=1 then return VZrep;fi; + VZ := RightCoset(C,VZrep); + for V in VZ do + if Order(V) = p then return V; fi; + od; + Error("No element found"); + end; + + # Calculating AutSl + AutSlgens := []; + for lambda in AutpSgens do + alphaSlgen := List(Slgen,U -> m2lambm2inv(U,lambda,m2,C,p)); + alpha := GroupHomomorphismByImagesNC(Sldq,Sldq,Slgen,alphaSlgen); + Add(AutSlgens,alpha); + od; + + # Checking if AutSlgens contains an automorphism that is not a + # conjugator automorphism times a field automorphism. + scalars := Filtered(GF(q), x -> x^d = One(GF(q))); + scalars := SmallGeneratingSet(AsGroup(scalars)); + scalarMatrices := List(scalars,x -> x * IdentityMatrix(GF(q),d)); + f := FrobeniusAutomorphism(GF(q)); + flisinit := List([1..Order(f)],x->f^x); + finvlisinit := List(flisinit,f -> f^-1); + imagesOfscalars := List(flisinit,f -> List(scalars,f)); + MakeFieldAutomorphismOfSldq := function(f) + local row,M,applyfonrow,applyf,fgens,x; + applyfonrow := row -> List(row,x -> Image(f,x)); + applyf := M -> List(M,applyfonrow); + fgens := List(Slgen,applyf); + return GroupHomomorphismByImagesNC(Sldq,Sldq,Slgen,fgens); + end; + finvmatrixlist := List(finvlisinit,MakeFieldAutomorphismOfSldq); + if type="PSL" or type="PSp" then + for alpha in AutSlgens do + conj := false; + FirstOfimagesOfscalarMatrices := List(scalarMatrices,M -> alpha(M)[1][1]); + findlis := Filtered([1..Length(flisinit)], i -> FirstOfimagesOfscalarMatrices = imagesOfscalars[i]); + finvlis := List(findlis,i -> finvmatrixlist[i]); + for finv in finvlis do + alphafinv := alpha * finv; + if IsConjugatorAutomorphism(alphafinv) then + conj := true; + break; + fi; + od; + if not conj then return false; fi; + od; + elif type="POmega+" then + O := GO(1,d,q); + C := Center(GO(1,d,q)); + phi := NaturalHomomorphismByNormalSubgroupNC(O,C); + PO := Image(phi); + POgens := GeneratorsOfGroup(PO); + POgens := List(POgens,x -> PreImagesRepresentative(phi,x)); + POgens := List(POgens,x-> ConjugatorAutomorphismNC(Sldq,x)); + PO := GroupWithGenerators(POgens); + if d > 8 then + for alpha in AutSlgens do + if not alpha in PO then return false; fi; + od; + elif d = 8 then + + fi; + fi; + return true; +end); + +################################################################################## +## +#F MinimalFaithfulPermutationDegreeOfAlmostSimpleGroupWithSimpleSubgroup(,,) +## +## Returns mu(A) where S =~ Inn(S) < A < Aut(S) and S is a simple group if G is 0. +## If group G is given, A is congruent to the +## group of conjugator automorphisms of simple group S < G +## , using elements of normalieser of S in G as conjugators. +## This function really only need the size of A if G is given +## , so that can be given directly instead of the group A too. +## For more details, take a look at this paper : +## https://www.sciencedirect.com/science/article/pii/S0747717118300993 +BindGlobal("MinimalFaithfulPermutationDegreeOfAlmostSimpleGroupWithSimpleSubgroup",function(A,S,G) + local info,d,q,m,series,name,parameter,mu,Aut,b,sizeS,sizeA; + + # Just for convenience + Aut := AutomorphismGroup; + mu := MinimalFaithfulPermutationDegreeOfSimpleGroupWithIsomorphismType; + + if IsInt(A) then sizeA := A; + else sizeA := Size(A); fi; + sizeS := Size(S); + info := IsomorphismTypeInfoFiniteSimpleGroup(S); + series := info.series; + name := info.shortname; + + if series = "Spor" then + if name = "M12" and + sizeA = Size(Aut(S)) #A = Aut(S) + then return 2 * mu(info); + elif name = "ON" and + sizeA = Size(Aut(S)) #A = Aut(S) + then return 2 * mu(info); + fi; + else # Set q and m + parameter := info.parameter; + if IsList(parameter) then + q := parameter[2]; + m := parameter[1]; + else q := parameter; fi; + fi; + + if series = "A" and q = 6 then + #if not A <~ SymmetricGroup(6) then return 10; fi; + if 720 mod sizeA <> 0 then return 10; + else + if G = 0 then + Assert(not IsInt(A),"If group G is not given, then group A must be given"); + elif IsInt(A) then + A := Normaliser(G,S) / Centraliser(G,S); + fi; + return MinimalFaithfulPermutationDegree(A); + fi; + + elif series = "L" then + d := m; + if d = 2 and q = 7 then + # if A ~ PGL(2,7) then return 8; fi; + # PGL(2,7) is isomorphic to Aut(PSL(2,7)) which is Aut(S) which has a subgroup isomorphic to A + # Thus A <~ PGL(2,7); So, the only requirement for isomorphism is that Size(A) = Size(PGL(2,7)) = 336 + if sizeA = 336 then return 8; fi; + elif d > 2 and not (q = 2 and (d = 3 or d = 4)) then + #if not A <~ GammaL(d,q) then return 2 * mu(info); + if Size(GammaL(d,q)) mod sizeA <> 0 then + return 2 * mu(info); + elif G=0 then + Assert(not IsInt(A),"If group G is not given, then group A must be given"); + return MinimalFaithfulPermutationDegree(A); + elif CanLiftPermutationDegreeToNormaliserOfSimpleMatrixGroup(S,G,d,q,"PSL") then + return MinimalFaithfulPermutationDegreeOfSimpleGroupWithIsomorphismType(info); + else + return 2*MinimalFaithfulPermutationDegreeOfSimpleGroupWithIsomorphismType(info); + fi; + fi; + + elif series = "2A" # PSU(3,5) + and m+1 = 3 + and q = 5 then + #if not A <~ PSigmaU(3,5) then return 126; fi; + if G = 0 then + Assert(not IsInt(A),"If group G is not given, then group A must be given"); + elif IsInt(A) then + A := Normaliser(G,S) / Centraliser(G,S); + fi; + return MinimalFaithfulPermutationDegree(A); + + elif series = "D" then #P\Omega^+ + d := 2*m; + if d = 8 and q = 2 + and sizeA/sizeS mod 3 = 0 + then return 3 * mu(info); + elif d = 8 and q = 3 + and sizeA/sizeS mod 3 = 0 + and sizeA/sizeS mod 12 <> 0 + then return 3 * mu(info); + elif d = 8 and q = 3 + and sizeA/sizeS mod 12 = 0 + then return 3360; + elif d = 8 + and sizeA/sizeS mod 3 = 0 + then return 3 * mu(info); + elif q = 3 and d > 7 and + sizeA/sizeS mod 3 <> 0 then + if Size(PGO(1,d,3)) mod sizeA <>0 # (*) + then return (3^(m-1) + 1) * (3^m -1) / 2 ; + elif G=0 then + Assert(not IsInt(A),"If group G is not given, then group A must be given"); + return MinimalFaithfulPermutationDegree(A); + elif CanLiftPermutationDegreeToNormaliserOfSimpleMatrixGroup(S,G,m,q,"POmega+") then + return MinimalFaithfulPermutationDegreeOfSimpleGroupWithIsomorphismType(info); + else + return (3^(m-1) + 1) * (3^m -1) / 2 ; + fi; + fi; + + elif series = "G" then + #if q = 3 and Iso(A,Aut(S)) then return 2 * mu(info);fi; + if q = 3 and sizeA = Size(Aut(S)) then return 2 * mu(info); fi; + #This is because A is isomorphic to a subgroup in Aut(S) that contains Inn(S) \cong S at any point. + b := LogInt(q,3); + if 3^b = q and b >1 then + #if not A <~ GammaG(q) then return 2 * mu(info); fi; + if Size(GF(q))*Size(GaloisGroup(AsField(GF(q),GF(3)))) mod sizeA <> 0 then return 2 * mu(info); + else + if G = 0 then + Assert(not IsInt(A),"If group G is not given, then group A must be given"); + elif IsInt(A) then + A := Normaliser(G,S) / Centraliser(G,S); + fi; + return MinimalFaithfulPermutationDegree(A); + fi; + fi; + elif series = "C" #PSp + and m = 2 + and 2^Log2Int(q) = q + and q > 3 then + #if not A <~ PGammaSp(d,q) then return 2*mu(info); fi; + if G=0 then + Assert(not IsInt(A),"If group G is not given, then group A must be given"); + return MinimalFaithfulPermutationDegree(A); + elif CanLiftPermutationDegreeToNormaliserOfSimpleMatrixGroup(S,G,m,q,"PSp") then + return MinimalFaithfulPermutationDegreeOfSimpleGroupWithIsomorphismType(info); + else + return 2*MinimalFaithfulPermutationDegreeOfSimpleGroupWithIsomorphismType(info); + fi; + elif series = "F" and 2^Log2Int(q) = q then + #if not A <~ GammaF(d,q) then return 2*mu(info); fi; + if sizeS * Size(GaloisGroup(GF(q))) mod sizeA <> 0 then return 2 * mu(info); + else + if G = 0 then + Assert(not IsInt(A),"If group G is not given, then group A must be given"); + elif IsInt(A) then + A := Normaliser(G,S) / Centraliser(G,S); + fi; + return MinimalFaithfulPermutationDegree(A); + fi; + elif series = "E" and m = 6 then + #if not A <~ GammaE(d,q) then return 2*mu(info); fi; + if sizeS * Size(GaloisGroup(GF(q))) mod sizeA <> 0 then return 2 * mu(info); + else + if G = 0 then + Assert(not IsInt(A),"If group G is not given, then group A must be given"); + elif IsInt(A) then + A := Normaliser(G,S) / Centraliser(G,S); + fi; + return MinimalFaithfulPermutationDegree(A); + fi; + fi; + return mu(info); +end); + +################################################################################## +## +#F MinimalFaithfulPermutationDegreeOfFittingFreeGroup() +## +## Returns the minimal faithful permutation degree for a semi-simple group G, +## which is a group that doesn't contain any abelian normal subgroups. +## The function is based on this research paper : +## https://dl.acm.org/doi/10.1145/3618260.3649641 +InstallGlobalFunction(MinimalFaithfulPermutationDegreeOfFittingFreeGroup,function(G) + local + mu, # Objective value to compute + Slis, # Decomposition of N as direct product of simple groups + N, # Any minimal normal subgroup of G + NGS, # Normaliser of S in G + CGS, # Centraliser of S in G + phi, # Homomorphism from NGS to NGS/CGS + A, # NGS/CGS =~ {^n for n in N_G(S)} + muA, # Minimal Permutation Degree of A + S, # Slis[1] =~ Slis[i] + info, # Information about isomorphism type of S + MNS,m,q; + mu := 0; + MNS := MinimalNormalSubgroups(G); + if Length(MNS) = 1 and MNS[1] = G then + info := IsomorphismTypeInfoFiniteSimpleGroup(G); + return MinimalFaithfulPermutationDegreeOfSimpleGroupWithIsomorphismType(info); + fi; + for N in MNS do + Slis := DirectFactorsOfGroup(N); + S := Slis[1]; + NGS := Normalizer(G,S); + CGS := Centralizer(G,S); + A := NGS/CGS; + muA := MinimalFaithfulPermutationDegreeOfAlmostSimpleGroupWithSimpleSubgroup(A,S,G); + mu := mu + (Length(Slis) * muA); + od; + return mu; +end); + +InstallMethod(MinimalFaithfulPermutationDegree,"for simple groups",true, + [IsSimpleGroup and IsFinite],0,function(S) + local info; + info := IsomorphismTypeInfoFiniteSimpleGroup(S); + return MinimalFaithfulPermutationDegreeOfSimpleGroupWithIsomorphismType(info); +end); # utility function: Find a subgroup $S$ of $G\le P$, with $G'\le S\le G$ such # that $[G:S]<=limit$ and that $S\lhd N_P(G)$. diff --git a/tst/testextra/MinimalFaithfulPermutationDegreeOfFittingFreeGroup.tst b/tst/testextra/MinimalFaithfulPermutationDegreeOfFittingFreeGroup.tst new file mode 100644 index 0000000000..59e8f76abd --- /dev/null +++ b/tst/testextra/MinimalFaithfulPermutationDegreeOfFittingFreeGroup.tst @@ -0,0 +1,54 @@ +gap> START_TEST("MinimalFaithfulPermutationDegreeOfFittingFreeGroup.tst"); +gap> CheckInList := function(L,Mus) +> local i,stop,mu,mu2,G,g; +> for i in [1..Length(L)] do +> G := L[i]; +> if IsList(Mus) then mu := Mus[i]; +> else +> mu := DoMinimalFaithfulPermutationDegree(G,false); +> fi; +> mu2 := MinimalFaithfulPermutationDegreeOfFittingFreeGroup(G); +> if mu2 = mu then +> else +> return Concatenation("F.A.I.L on",String(G)); +> fi; +> od; +> return "pass"; +> end;; +gap> +gap> TestCases := Filtered(List(SimpleGroupsIterator(2,50000)), +> G->IsPSL(G) or (Size(G) < 1000 and not IsAbelian(G)));; +gap> Degs := List(TestCases,MinimalFaithfulPermutationDegree);; +gap> l := Length(TestCases);; +gap> for i in [1..l] do +> for j in [1..i] do +> G := DirectProduct(TestCases[i],TestCases[j]); +> Add(TestCases,G); +> Add(Degs,Degs[i] + Degs[j]); +> od; +> od; +gap> +gap> SemiSimpleGroupsTillSize1000 := [ +> SmallGroup(60,5), +> SmallGroup(120,34), +> SmallGroup(168,42), +> SmallGroup(336,208), +> SmallGroup(360,118), +> SmallGroup(504,156), +> SmallGroup(660,13), +> SmallGroup(720,763), +> SmallGroup(720,764), +> SmallGroup(720,765), +> #sizes 512 and 768 skipped +> ];; +gap> +gap> +gap> # Semi Simple Groups below size 1000 +gap> CheckInList(SemiSimpleGroupsTillSize1000,-1); +"pass" +gap> +gap> # Products of Simple Groups +gap> ind := List([1..30],x->Random([1..Length(TestCases)]));; +gap> CheckInList(List(ind,n->TestCases[n]),List(ind,n->Degs[n])); +"pass" +gap> STOP_TEST( "MinimalFaithfulPermutationDegreeOfFittingFreeGroup.tst", 1); \ No newline at end of file diff --git a/tst/testextra/MinimalFaithfulPermutationDegreeOfSimpleGroup.tst b/tst/testextra/MinimalFaithfulPermutationDegreeOfSimpleGroup.tst new file mode 100644 index 0000000000..76f006fe33 --- /dev/null +++ b/tst/testextra/MinimalFaithfulPermutationDegreeOfSimpleGroup.tst @@ -0,0 +1,113 @@ +gap> START_TEST("MinimalFaithfulPermutationDegreeOfSimpleGroupWithIsomorphismType.tst"); +gap> Clean := function(INFO) +> local SporNames,SeriesNames,info,name,q,size; +> info := ShallowCopy(INFO); +> SporNames := [ +> ["M11","M(11)"], +> ["M12","M(12)"], +> ["M22","M(22)"], +> ["M23","M(23)"], +> ["M24","M(24)"], +> ["J1","J(1)"], +> ["J2","J(2)"], +> ["J3","J(3)"], +> ["Co2","Co(2)"], +> ["Co3","Co(3)"], +> ["Fi22","Fi(22)"], +> ]; +> SeriesNames := [ +> ["U","2A"], +> ["S","C"], +> ["Sz","2B"], +> ["O+","D"], +> ["O-","2D"], +> ["O","B"], +> ]; +> if IsString(info[3]) then +> for name in SporNames do +> if name[2] = info[3] then +> info[3] := name[1]; +> fi; +> od; +> if info[3] = "T" then +> info[2] := "2F"; +> info[3] := 2; +> info[4] := 0; +> fi; +> else +> for name in SeriesNames do +> if name[1] = info[2] then +> info[2] := name[2]; +> fi; +> if INFO[2] = "U" then info[3] := INFO[3] -1;fi; +> if INFO[2] in ["S","O+","O-"] then info[3] := INFO[3]/2; fi; +> if INFO[2] = "O" then info[3] := (INFO[3] -1)/2; fi; +> if not IsInt(info[3]) then Error("wierd .. ",INFO,"\n"); fi; +> if info[2] = "R" then +> q := info[3]; +> size := info[1]; +> if size = q^3 * (q^3 + 1) * (q-1) and PrimeDivisors(q) = [3] then +> info[2] := "2G"; +> elif size = q^12 * (q^6 + 1) * (q^4 -1) * (q^3+1) * (q-1) +> and PrimeDivisors(q) = [2] then +> info[2] := "2F"; +> else +> Error("Couldn't identify"); +> fi; +> fi; +> od; +> fi; +> return info; +> end; +function( INFO ) ... end +gap> MakeRecord := function(INFO) +> local info,parameter,series,shortname; +> if IsString(INFO[3]) then +> return rec( +> series := "Spor", +> parameter := INFO[4], +> shortname := INFO[3], +> ); +> fi; +> if INFO[4] = 0 then +> parameter := INFO[3]; +> else +> parameter := [INFO[3],INFO[4]]; +> fi; +> return rec( +> series := INFO[2], +> parameter := parameter, +> ); +> end; +function( INFO ) ... end +gap> LightChecknonabelianSimple := function(perfectTill) +> local size,series,INFO,G,mu,mu2,mu3,info; +> for INFO in SIMPLEGPSNONL2 do +> if LENGTH(INFO) <> 5 then continue; fi; +> size := INFO[1]; +> series := INFO[2]; +> mu := Last(INFO); +> info := MakeRecord(Clean(INFO)); +> mu2 := MinimalFaithfulPermutationDegreeOfSimpleGroupWithIsomorphismType(info); +> if mu < mu2 then +> return Concatenation("failed on",String(INFO),". From table :",String(mu),", Computed :",String(mu2),"\n"); +> elif size <= perfectTill and mu>mu2 then +> if IsString(INFO[3]) then +> G := SimpleGroup(INFO[3]); +> elif INFO[4] = 0 then +> G := SimpleGroup(INFO[2],INFO[3]); +> else +> G := SimpleGroup(INFO[2],INFO[3],INFO[4]); +> fi; +> mu3 := DoMinimalFaithfulPermutationDegree(G,false); +> if mu2 <> mu3 then +> return Concatenation("failed on",String(INFO),". From MinimalFaithfulPermutationDegree :",String(mu3),", Computed :",String(mu2),"\n"); +> fi; +> fi; +> od; +> return "PASS"; +> end; +function( perfectTill ) ... end +gap> LightChecknonabelianSimple(10^6); +"PASS" +gap> STOP_TEST( "MinimalFaithfulPermutationDegreeOfSimpleGroup.tst", 1); \ No newline at end of file