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);