diff --git a/lib/grp.gd b/lib/grp.gd index 6c2b9ff670..20e16aec6c 100644 --- a/lib/grp.gd +++ b/lib/grp.gd @@ -1759,10 +1759,22 @@ DeclareAttribute( "NilpotencyClassOfGroup", IsGroup ); ## ## ## is a list containing those proper normal subgroups of the group G -## that are maximal among the proper normal subgroups. +## that are maximal among the proper normal subgroups. Gives error if +## G/G' is infinite, yielding infinitely many maximal normal +## subgroups. +## +## Note, that the maximal normal subgroups of a group G can be +## computed more efficiently if the character table of G is known or +## if G is known to be abelian or solvable (even if infinite). So if +## the character table is needed, anyhow, or G is suspected to be +## abelian or solvable, then these should be computed before computing the +## maximal normal subgroups. ## MaximalNormalSubgroups( g ); ## [ Group([ (1,2,3), (2,3,4) ]) ] +## gap> f := FreeGroup("x", "y");; x := f.1;; y := f.2;; +## gap> List(MaximalNormalSubgroups(f/[x^2, y^2]), GeneratorsOfGroup); +## [ [ x, y*x*y^-1 ], [ y, x*y*x^-1 ], [ y*x^-1 ] ] ## ]]> ## ## diff --git a/lib/grp.gi b/lib/grp.gi index 7a32022406..1b42683d07 100644 --- a/lib/grp.gi +++ b/lib/grp.gi @@ -4582,9 +4582,14 @@ end); ## anyhow,you should compute it before computing the maximal normal ## subgroups. ## +## *Note* that for abelian and solvable groups the maximal normal subgroups +## can be computed very quickly. Thus if you suspect your group to be +## abelian or solvable, then check it before computing the maximal normal +## subgroups. +## InstallMethod( MaximalNormalSubgroups, "generic search", - [ IsGroup ], + [ IsGroup and IsFinite ], function(G) local maximal, # list of maximal normal subgroups,result @@ -4611,6 +4616,10 @@ InstallMethod( MaximalNormalSubgroups, end); +RedispatchOnCondition( MaximalNormalSubgroups, true, + [ IsGroup ], + [ IsFinite ], 0); + ############################################################################# ## #M MaximalNormalSubgroups( ) @@ -4620,6 +4629,23 @@ InstallMethod( MaximalNormalSubgroups, "for simple groups", function(G) return [ TrivialSubgroup(G) ]; end); +############################################################################# +## +#M MaximalNormalSubgroups( ) +## +InstallMethod( MaximalNormalSubgroups, "general method selection", + [ IsGroup ], + function(G) + + if 0 in AbelianInvariants(G) then + # (p) is a maximal normal subgroup in Z for every prime p + Error("number of maximal normal subgroups is infinity"); + else + TryNextMethod(); + fi; +end); + + ############################################################################## ## #F MinimalNormalSubgroups() @@ -4723,8 +4749,8 @@ InstallMethod( MinimalNormalSubgroups, "for nilpotent groups", # IsGroup and IsFinite ranks higher than IsGroup and IsNilpotentGroup # so we have to increase the rank, otherwise the method for computation # by conjugacy classes above is selected. - RankFilter(IsGroup and IsFinite) - - RankFilter(IsGroup and IsNilpotentGroup), + RankFilter( IsGroup and IsFinite and IsNilpotentGroup ) + - RankFilter( IsGroup and IsNilpotentGroup ), function(G) local soc, i, p, primes, gen, min, MinimalSubgroupsOfPGroupByGenerators; diff --git a/lib/grppcatr.gi b/lib/grppcatr.gi index 6f9b1dd848..067c4611e8 100644 --- a/lib/grppcatr.gi +++ b/lib/grppcatr.gi @@ -480,19 +480,35 @@ end ); ## #M MaximalNormalSubgroups( ) ## -InstallMethod( MaximalNormalSubgroups, "for solvable groups", +InstallMethod( MaximalNormalSubgroups, "for abelian groups", [ IsGroup and IsAbelian ], + # IsGroup and IsFinite ranks higher than IsGroup and IsAbelian, + # so we have to increase the rank, otherwise the method for + # normal subgroup computation is selected. + RankFilter( IsGroup and IsFinite and IsAbelian ) + - RankFilter( IsGroup and IsAbelian ), function( G ) local Gf, # FactorGroup of G hom, # homomorphism from G to Gf - MaxGf; # MaximalNormalSubgroups of Gf + MaxGf, # MaximalNormalSubgroups of Gf + AbInv; # abelian invariants of G if not IsPcGroup(G) then - # convert it to an Abelian PcGroup with same invariants - Gf := AbelianGroup(IsPcGroup, AbelianInvariants(G)); - hom := IsomorphismGroups(G, Gf); - MaxGf := NormalMaximalSubgroups(Gf); - return List(MaxGf, N -> PreImage(hom, N)); + AbInv := AbelianInvariants(G); + if 0 in AbInv then + # (p) is a maximal normal subgroup in Z for every prime p + Error("number of maximal normal subgroups is infinity"); + else + # convert it to an abelian PcGroup with same invariants + hom := IsomorphismPcGroup(G); + Gf := Image(hom); + # for abelian groups all maximal normal subgroup are also + # normal maximal subgroups and vice-versa + MaxGf := NormalMaximalSubgroups(Gf); + return List(MaxGf, N -> PreImage(hom, N)); + fi; else + # for abelian groups all maximal normal subgroup are also + # normal maximal subgroups and vice-versa # for abelian pc groups return all maximal subgroups # NormalMaximalSubgroups seems to omit some unnecessary checks, # hence faster than MaximalSubgroups @@ -502,6 +518,12 @@ end); InstallMethod( MaximalNormalSubgroups, "for solvable groups", [ IsGroup and IsSolvableGroup ], + # IsGroup and IsFinite ranks higher than + # IsGroup and IsSolvableGroup, so we have to increase the + # rank, otherwise the method for normal subgroup computation + # is selected. + RankFilter( IsGroup and IsFinite and IsSolvableGroup ) + - RankFilter( IsGroup and IsSolvableGroup ), function( G ) local Gf, # FactorGroup of G hom, # homomorphism from G to Gf @@ -515,6 +537,10 @@ function( G ) return List(MaxGf, N -> PreImage(hom, N)); end); +RedispatchOnCondition( MaximalNormalSubgroups, true, + [ IsGroup ], + [ IsSolvableGroup ], 0); + ############################################################################# ## diff --git a/tst/testinstall/opers/MaximalNormalSubgroups.tst b/tst/testinstall/opers/MaximalNormalSubgroups.tst index edf36b9864..11f0ce6436 100644 --- a/tst/testinstall/opers/MaximalNormalSubgroups.tst +++ b/tst/testinstall/opers/MaximalNormalSubgroups.tst @@ -6,46 +6,53 @@ true gap> G := AlternatingGroup(5);; Size(MaximalNormalSubgroups(G))=1 and IsTrivial(MaximalNormalSubgroups(G)[1]); true gap> l := [2,4,8,3,9,5,25,7];; G := DirectProduct(List(l, CyclicGroup));; -gap> List(MaximalNormalSubgroups(G),N ->List(MinimalGeneratingSet(N),Order)); -[ [ 2, 60, 6300 ], [ 2, 30, 12600 ], [ 2, 30, 12600 ], [ 60, 12600 ], - [ 60, 12600 ], [ 60, 12600 ], [ 60, 12600 ], [ 2, 60, 4200 ], - [ 2, 20, 12600 ], [ 2, 20, 12600 ], [ 2, 20, 12600 ], [ 2, 60, 2520 ], - [ 2, 12, 12600 ], [ 2, 12, 12600 ], [ 2, 12, 12600 ], [ 2, 12, 12600 ], - [ 2, 12, 12600 ], [ 2, 60, 1800 ] ] +gap> SortedList(List(MaximalNormalSubgroups(G),N ->List(MinimalGeneratingSet(N),Order))); +[ [ 2, 12, 12600 ], [ 2, 12, 12600 ], [ 2, 12, 12600 ], [ 2, 12, 12600 ], + [ 2, 12, 12600 ], [ 2, 20, 12600 ], [ 2, 20, 12600 ], [ 2, 20, 12600 ], + [ 2, 30, 12600 ], [ 2, 30, 12600 ], [ 2, 60, 1800 ], [ 2, 60, 2520 ], + [ 2, 60, 4200 ], [ 2, 60, 6300 ], [ 60, 12600 ], [ 60, 12600 ], + [ 60, 12600 ], [ 60, 12600 ] ] gap> A := AbelianGroup(IsFpGroup, [2,4,8,3,9,5,25,7]);; -gap> List(MaximalNormalSubgroups(A),N -> AbelianInvariants(N)); -[ [ 2, 3, 4, 4, 5, 7, 9, 25 ], [ 2, 2, 3, 5, 7, 8, 9, 25 ], - [ 2, 2, 3, 5, 7, 8, 9, 25 ], [ 3, 4, 5, 7, 8, 9, 25 ], - [ 3, 4, 5, 7, 8, 9, 25 ], [ 3, 4, 5, 7, 8, 9, 25 ], - [ 3, 4, 5, 7, 8, 9, 25 ], [ 2, 3, 3, 4, 5, 7, 8, 25 ], - [ 2, 4, 5, 7, 8, 9, 25 ], [ 2, 4, 5, 7, 8, 9, 25 ], - [ 2, 4, 5, 7, 8, 9, 25 ], [ 2, 3, 4, 5, 5, 7, 8, 9 ], +gap> SortedList(List(MaximalNormalSubgroups(A),N -> AbelianInvariants(N))); +[ [ 2, 2, 3, 5, 7, 8, 9, 25 ], [ 2, 2, 3, 5, 7, 8, 9, 25 ], + [ 2, 3, 3, 4, 5, 7, 8, 25 ], [ 2, 3, 4, 4, 5, 7, 9, 25 ], + [ 2, 3, 4, 5, 5, 7, 8, 9 ], [ 2, 3, 4, 5, 8, 9, 25 ], [ 2, 3, 4, 7, 8, 9, 25 ], [ 2, 3, 4, 7, 8, 9, 25 ], [ 2, 3, 4, 7, 8, 9, 25 ], [ 2, 3, 4, 7, 8, 9, 25 ], - [ 2, 3, 4, 7, 8, 9, 25 ], [ 2, 3, 4, 5, 8, 9, 25 ] ] + [ 2, 3, 4, 7, 8, 9, 25 ], [ 2, 4, 5, 7, 8, 9, 25 ], + [ 2, 4, 5, 7, 8, 9, 25 ], [ 2, 4, 5, 7, 8, 9, 25 ], + [ 3, 4, 5, 7, 8, 9, 25 ], [ 3, 4, 5, 7, 8, 9, 25 ], + [ 3, 4, 5, 7, 8, 9, 25 ], [ 3, 4, 5, 7, 8, 9, 25 ] ] gap> ForAll(MaximalNormalSubgroups(A), N -> IsSubgroup(A, N) and IsNormal(A, N)); true gap> D1 := DihedralGroup(Factorial(10));; gap> SortedList(List(MaximalNormalSubgroups(D1), StructureDescription)); [ "C1814400", "D1814400", "D1814400" ] -gap> D2 := DihedralGroup(IsFpGroup, 360);; +gap> D2 := DihedralGroup(IsFpGroup, 36);; gap> SortedList(List(MaximalNormalSubgroups(D2), StructureDescription)); -[ "C180", "D180", "D180" ] +[ "C18", "D18", "D18" ] gap> ForAll(MaximalNormalSubgroups(D2), N -> IsSubgroup(D2, N) and IsNormal(D2, N)); true # some infinite fp-groups gap> F := FreeGroup("r", "s");; r := F.1;; s := F.2;; gap> G := F/[r^(-1)*s^(-1)*r*s, r^18, s^24];; -gap> IsNilpotentGroup(G);; gap> Length(MaximalNormalSubgroups(G)); 7 gap> G := F/[s^2, s*r*s*r];; - -# currently IsSolvable(G) would not run, will be remedied later -gap> IsAbelian(DerivedSubgroup(G)); -true -gap> SetIsSolvableGroup(G, true); gap> Length(MaximalNormalSubgroups(G)); 3 +gap> G := F/[s^2];; +gap> MaximalNormalSubgroups(G); +Error, number of maximal normal subgroups is infinity +gap> G := F/[s^2, r*s*r^(-1)*s^(-1)];; +gap> MaximalNormalSubgroups(G); +Error, number of maximal normal subgroups is infinity +gap> MaximalNormalSubgroups( AbelianGroup( [ 0 ] ) ); +Error, number of maximal normal subgroups is infinity + +# a finite fp-group +gap> G := F/[r^12, s^2, r*s*r^(-1)*s^(-1)];; +gap> SortedList(List(MaximalNormalSubgroups(G), AbelianInvariants)); +[ [ 2, 2, 3 ], [ 2, 4 ], [ 3, 4 ], [ 3, 4 ] ] gap> STOP_TEST("MaximalNormalSubgroups.tst", 10000);