# 7 Groups

Finitely generated groups and their subgroups are important domains in GAP. They are represented as permutation groups, matrix groups, ag groups or even more complicated constructs as for instance automorphism groups, direct products or semi-direct products where the group elements are represented by records.

Groups are created using `Group` (see Group), they are represented by records that contain important information about the groups. Subgroups are created as subgroups of a given group using `Subgroup`, and are also represented by records. See More about Groups and Subgroups for details about the distinction between groups and subgroups.

Because this chapter is very large it is split into several parts. Each part consists of several sections.

Note that some functions will only work if the elements of a group are represented in an unique way. This is not true in finitely presented groups, see Group Functions for Finitely Presented Groups for a list of functions applicable to finitely presented groups.

The first part describes the operations and functions that are available for group elements, e.g., `Order` (see Group Elements). The next part tells your more about the distinction of parent groups and subgroups (see More about Groups and Subgroups). The next parts describe the functions that compute subgroups, e.g., `SylowSubgroup` (Subgroups), Series of Subgroups). The next part describes the functions that compute and test properties of groups, e.g., `AbelianInvariants` and `IsSimple` (see Properties and Property Tests), and that identify the isomorphism type. The next parts describe conjugacy classes of elements and subgroups (see Conjugacy Classes) and cosets (see Cosets of Subgroups). The next part describes the functions that create new groups, e.g., `DirectProduct` (see Group Constructions). The next part describes Group Homomorphisms). The last part tells you more about the implementation Set Functions for Groups).

The functions described in this chapter are implemented in the following library files. `LIBNAME/"grpelms.g"` contains the functions for group elements, `LIBNAME/"group.g"` contains the dispatcher and default group functions, `LIBNAME/"grpcoset.g"` contains the functions for cosets and factor groups, `LIBNAME/"grphomom.g"` implements the group homomorphisms, and `LIBNAME/"grpprods.g"` implements the group constructions.

## 7.1 Group Elements

The following sections describe the operations and functions available Operations for Group Elements, IsGroupElement, and Order).

Note that group elements usually exist independently of a group, e.g., you can write down two permutations and compute their product without ever defining a group that contains them.

## 7.2 Comparisons of Group Elements

`g = h`
`g < h`

The equality operator `=` evaluates to `true` if the group elements g and h are equal and to `false` otherwise. The inequality operator `<` evaluates to `true` if the group elements g and h are not equal and to `false` otherwise.

You can compare group elements with objects of other types. Of course they are never equal. Standard group elements are permutations, ag words and matrices. For examples of generic group elements see for instance DirectProduct.

`g < h`
`g <= h`
`g = h`
`g h`

The operators `<`, `<=`, `=` and evaluate to `true` if the group element g is strictly less than, less than or equal to, greater than or equal to and strictly greater than the group element h. There is no general ordering on group elements.

Standard group elements may be compared with objects of other types while generic group elements may disallow such a comparison.

## 7.3 Operations for Group Elements

`g * h` `g / h`

The operators `*` and `/` evaluate to the product and quotient of the two group elements g and h. The operands must of course lie in a common parent group, otherwise an error is signaled.

`g ^ h`

The operator `^` evaluates to the conjugate <h>^{-1}* <g>* <h> of g under h for two group elements elements g and h. The operands must of course lie in a common parent group, otherwise an error is signaled.

`g ^ i`

The powering operator `^` returns the i-th power of a group element g and an integer i. If i is zero the identity of a parent group of g is returned.

`list * g` `g * list`

In this form the operator `*` returns a new list where each entry is the product of g and the corresponding entry of list. Of course multiplication must be defined between g and each entry of list.

`list / g`

In this form the operator `/` returns a new list where each entry is the quotient of g and the corresponding entry of list. Of course division must be defined between g and each entry of list.

`Comm( g, h )`

`Comm` returns the commutator <g>^{-1}* <h>^{-1}* <g>* <h> of two group elements g and h. The operands must of course lie in a common parent group, otherwise an error is signaled.

`LeftNormedComm( g1, ..., gn )`

`LeftNormedComm` returns the left normed commutator `Comm( LeftNormedComm( g1, ..., gn-1 ), gn )` of group elements g1, ..., gn. The operands must of course lie in a common parent group, otherwise an error is signaled.

`RightNormedComm( g1, g2, ..., gn )`

`RightNormedComm` returns the right normed commutator `Comm( g1, RightNormedComm( g2, ..., gn ) )` of group elements g1, ..., gn. The operands must of course lie in a common parent group, otherwise an error is signaled.

`LeftQuotient( g, h )`

`LeftQuotient` returns the left quotient <g>^{-1}* <h> of two group elements g and h. The operands must of course lie in a common parent group, otherwise an error is signaled.

## 7.4 IsGroupElement

`IsGroupElement( obj )`

`IsGroupElement` returns `true` if obj, which may be an object of arbitrary type, is a group element, and `false` otherwise. The function will signal an error if obj is an unbound variable.

```    gap> IsGroupElement( 10 );
false
gap> IsGroupElement( (11,10) );
true
gap> IsGroupElement( IdWord );
true ```

## 7.5 Order

`Order( G, g )`

`Order` returns the order of a group element g in the group G.

The order is the smallest positive integer i such that <g>^i is the identity. The order of the identity is one.

```    gap> Order( Group( (1,2), (1,2,3,4) ), (1,2,3) );
3
gap> Order( Group( (1,2), (1,2,3,4) ), () );
1 ```

## 7.6 More about Groups and Subgroups

GAP distinguishs between parent groups and subgroups of parent groups. Each subgroup belongs to a unique parent group. We say that this parent group is the parent of the subgroup. We also say that a parent group is its own parent.

Parent groups are constructed by `Group` and subgroups are constructed by `Subgroup`. The first argument of `Subgroup` must be a parent group, i.e., it must not be a subgroup of a parent group, and this parent group will be the parent of the constructed subgroup.

Those group functions that take more than one argument require that the arguments have a common parent. Take for instance `CommutatorSubgroup`. It takes two arguments, a group G and a group H, and returns the commutator subgroup of H with G. So either G is a parent group, and H is a subgroup of this parent group, or G and H are subgroups of a common parent group P.

```    gap> s4 := Group( (1,2), (1,2,3,4) );
Group( (1,2), (1,2,3,4) )
gap> c3 := Subgroup( s4, [ (1,2,3) ] );
Subgroup( Group( (1,2), (1,2,3,4) ), [ (1,2,3) ] )
gap> CommutatorSubgroup( s4, c3 );
Subgroup( Group( (1,2), (1,2,3,4) ), [ (1,3,2), (1,2,4) ] )
# ok, 'c3' is a subgroup of the parent group 's4'
gap> a4 := Subgroup( s4, [ (1,2,3), (2,3,4) ] );
Subgroup( Group( (1,2), (1,2,3,4) ), [ (1,2,3), (2,3,4) ] )
gap> CommutatorSubgroup( a4, c3 );
Subgroup( Group( (1,2), (1,2,3,4) ), [ (1,4)(2,3), (1,3)(2,4) ] )
# also ok, 'c3' and 'a4' are subgroups of the parent group 's4'
gap> x3 := Group( (1,2,3) );
Group( (1,2,3) )
gap> CommutatorSubgroup( s4, x3 );
Error, <G> and <H> must have the same parent group
# not ok, 's4' is its own parent and 'x3' is its own parent ```

Those functions that return new subgroups, as with `CommutatorSubgroup` above, return this subgroup as a subgroup of the common parent of their arguments. Note especially that the commutator subgroup of `c3` with `a4` is returned as a subgroup of their common parent group `s4`, not as a subgroup of `a4`. It can not be a subgroup of `a4`, because subgroups must be subgroups of parent groups, and `a4` is not a parent group. Of course, mathematically the commutator subgroup is a subgroup of `a4`.

Note that a subgroup of a parent group need not be a proper subgroup, as can be seen in the following example.

```    gap> s4 := Group( (1,2), (1,2,3,4) );
Group( (1,2), (1,2,3,4) )
gap> x4 := Subgroup( s4, [ (1,2,3,4), (3,4) ] );
Subgroup( Group( (1,2), (1,2,3,4) ), [ (1,2,3,4), (3,4) ] )
gap> Index( s4, x4 );
1 ```

One exception to the rule are functions that construct new groups such as `DirectProduct`. They accept groups with different parents. If you want rename the function `DirectProduct` to `OuterDirectProduct`.

Another exception is `Intersection` (see Intersection), which allows groups with different parent groups, it computes the intersection in such cases as if the groups were sets of elements. This is because `Intersection` is not a group function, but a domain function, i.e., it accepts two (or more) arbitrary domains as arguments.

Whenever you have two subgroups which have different parent groups but have a common supergroup G you can use `AsSubgroup` (see AsSubgroup) in order to construct new subgroups which have a common parent group G.

```    gap> s4 := Group( (1,2), (1,2,3,4) );
Group( (1,2), (1,2,3,4) )
gap> x3 := Group( (1,2,3) );
Group( (1,2,3) )
gap> CommutatorSubgroup( s4, x3 );
Error, <G> and <H> must have the same parent group
# not ok, 's4' is its own parent and 'x3' is its own parent
gap> c3 := AsSubgroup( s4, x3 );
Subgroup( Group( (1,2), (1,2,3,4) ), [ (1,2,3) ] )
gap> CommutatorSubgroup( s4, c3 );
Subgroup( Group( (1,2), (1,2,3,4) ), [ (1,3,2), (1,2,4) ] )```

The following sections describe the functions related to this concept (see IsParent, Parent, Group, AsGroup, IsGroup, Subgroup, AsSubgroup).

## 7.7 IsParent

`IsParent( G )`

`IsParent` returns `true` if G is a parent group, and `false` otherwise (see More about Groups and Subgroups).

## 7.8 Parent

`Parent( U_1, ..., U_n )`

`Parent` returns the common parent group of its subgroups and parent group arguments.

In case more than one argument is given, all groups must have the same parent group. Otherwise an error is signaled. This can be used to ensure that a collection of given subgroups have a common parent group.

## 7.9 Group

`Group( U )`

Let U be a parent group or a subgroup. `Group` returns a new parent group G which is isomorphic to U. The generators of G need not be the same elements as the generators of U. The default group function uses the same generators, while the ag group function may create new generators along with a new collector.

```    gap> s4 := Group( (1,2,3,4), (1,2) );
Group( (1,2,3,4), (1,2) )
gap> s3 := Subgroup( s4, [ (1,2,3), (1,2) ] );
Subgroup( Group( (1,2,3,4), (1,2) ), [ (1,2,3), (1,2) ] )
gap> Group( s3 ); # same elements
Group( (1,2,3), (1,2) )
gap> s4.1 * s3.1;
(1,3,4,2)
gap> s4 := AgGroup( s4 );
Group( g1, g2, g3, g4 )
gap> a4 := DerivedSubgroup( s4 );
Subgroup( Group( g1, g2, g3, g4 ), [ g2, g3, g4 ] )
gap> a4 := Group( a4 ); # different elements
Group( g1, g2, g3 )
gap> s4.1 * a4.1;
Error, AgWord op: agwords have different groups ```

`Group( list, id )`

`Group` returns a new parent group G generated by group elements g_1, ..., g_n of list. id must be the identity of this group.

`Group( g_1, ..., g_n )`

`Group` returns a new parent group G generated by group elements g_1, ..., g_n.

The generators of this new parent group need not be the same elements as g_1, ..., g_n. The default group function however returns a group record with generators g_1, ..., g_n and identity id, while the ag group function may create new generators along with a new collector.

```    gap> s4 := Group( (1,2,3,4), (1,2) );
Group( (1,2,3,4), (1,2) )
gap> z4 := Group( s4.1 ); # same element
Group( (1,2,3,4) )
gap> s4.1 * z4.1;
(1,3)(2,4)
gap> s4 := AgGroup( s4 );
Group( g1, g2, g3, g4 )
gap> z4 := Group( s4.1 * s4.3 ); # different elements
Group( g1, g2 )
gap> s4.1 * z4.1;
Error, AgWord op: agwords have different groups ```

Let g_{i_1}, ..., g_{i_m} be the set of nontrivial generators in all four cases. `Groups` sets record components `G.1`, ..., `G.m` to these generators.

## 7.10 AsGroup

`AsGroup( D )`

Let D be a domain. `AsGroup` returns a group G such that the set of elements of D is the same as the set of elements of G if this is possible.

If D is a list of group elements these elements must form a group. Otherwise an error is signaled.

Note that this function returns a parent group or a subgroup of a parent group depending on D. In order to convert a subgroup into a parent group you must use `Group` (see Group).

```    gap> s4 := AgGroup( Group( (1,2,3,4), (2,3) ) );
Group( g1, g2, g3, g4 )
gap> Elements( last );
[ IdAgWord, g4, g3, g3*g4, g2, g2*g4, g2*g3, g2*g3*g4, g2^2, g2^2*g4,
g2^2*g3, g2^2*g3*g4, g1, g1*g4, g1*g3, g1*g3*g4, g1*g2, g1*g2*g4,
g1*g2*g3, g1*g2*g3*g4, g1*g2^2, g1*g2^2*g4, g1*g2^2*g3,
g1*g2^2*g3*g4 ]
gap> AsGroup( last );
Group( g1, g2, g3, g4 ) ```

The default function `GroupOps.AsGroup` for a group D returns a copy of D. If D is a subgroup then a subgroup is returned. The default function `GroupElementsOps.AsGroup` expects a list D of group elements forming a group and uses successively `Closure` in order to compute a reduced generating set.

## 7.11 IsGroup

`IsGroup( obj )`

`IsGroup` returns `true` if obj, which can be an object of arbitrary type, is a parent group or a subgroup and `false` otherwise. The function will signal an error if obj is an unbound variable.

```    gap> IsGroup( Group( (1,2,3) ) );
true
gap> IsGroup( 1/2 );
false ```

## 7.12 Subgroup

`Subgroup( G, L )`

Let G be a parent group and L be a list of elements g_1, ..., g_n of G. `Subgroup` returns the subgroup U generated by g_1, ..., g_n with parent group G.

Note that this function is the only group function in which the name `Subgroup` does not refer to the mathematical terms subgroup and supergroup but to the implementation of groups as subgroups and parent groups. `IsSubgroup` (see IsSubgroup) is not the negation of `IsParent` (see IsParent) but decides subgroup and supergroup relations.

`Subgroup` always binds a copy of L to `U.generators`, so it is safe to modify L after calling `Subgroup` because this will not change the entries in U.

Let g_{i_1}, ..., g_{i_m} be the nontrivial generators. `Subgroups` binds these generators to `U.1`, ..., `U.m`.

```    gap> s4 := Group( (1,2,3,4), (1,2) );
Group( (1,2,3,4), (1,2) )
gap> v4 := Subgroup( s4, [ (1,2), (1,2)(3,4) ] );
Subgroup( Group( (1,2,3,4), (1,2) ), [ (1,2), (1,2)(3,4) ] )
gap> IsParent( v4 );
false ```

## 7.13 AsSubgroup

`AsSubgroup( G, U )`

Let G be a parent group and U be a parent group or a subgroup with a possibly different parent group, such that the generators g_1, ..., g_n of U are elements of G. `AsSubgroup` returns a new subgroup S such that S has parent group G and is generated by g_1, ..., g_n.

```    gap> d8 := Group( (1,2,3,4), (1,2)(3,4) );
Group( (1,2,3,4), (1,2)(3,4) )
gap> z := Centre( d8 );
Subgroup( Group( (1,2,3,4), (1,2)(3,4) ), [ (1,3)(2,4) ] )
gap> s4 := Group( (1,2,3,4), (1,2) );
Group( (1,2,3,4), (1,2) )
gap> Normalizer( s4, AsSubgroup( s4, z ) );
Subgroup( Group( (1,2,3,4), (1,2) ), [ (2,4), (1,2,3,4), (1,3)(2,4)
] ) ```

## 7.14 Subgroups

The following sections describe functions that compute certain subgroups of a given group, e.g., `SylowSubgroup` computes a Sylow subgroup of a group (see Centralizer, Centre, Closure, CommutatorSubgroup, ConjugateSubgroup, Core, DerivedSubgroup, FittingSubgroup, FrattiniSubgroup, NormalClosure, NormalIntersection, Normalizer, PCore, PrefrattiniSubgroup, Radical, SylowSubgroup, TrivialSubgroup).

They return group records as described in Group Records for the computed subgroups. Some functions may not terminate if the given group has an infinite set of elements, while other functions may signal an error in such cases.

Here the term ``subgroup'' is used in a mathematical sense. But in GAP, every group is either a parent group or a subgroup of a unique parent group. If you compute a Sylow subgroup S of a group U with parent group G then S is a subgroup of U but its parent group is G (see More about Groups and Subgroups).

Further sections describe functions that return factor groups of a given group (see FactorGroup and CommutatorFactorGroup).

## 7.15 Agemo

`Agemo( G, p )`

G must be a p-group. `Agemo` returns the subgroup of G generated by the p.th powers of the elements of G.

```    gap> d8 := Group( (1,3)(2,4), (1,2) );
Group( (1,3)(2,4), (1,2) )
gap> Agemo( d8, 2 );
Subgroup( Group( (1,3)(2,4), (1,2) ), [ (1,2)(3,4) ] ) ```

The default function `GroupOps.Agemo` computes the subgroup of G generated by the p.th powers of the generators of G if G is abelian. Otherwise the function computes the normal closure of the p.th powers of the representatives of the conjugacy classes of G.

## 7.16 Centralizer

`Centralizer( G, x )`

`Centralizer` returns the centralizer of an element x in G where x must be an element of the parent group of G.

The centralizer of an element x in G is defined as the set C of elements c of G such that c and x commute.

```    gap> s4 := Group( (1,2,3,4), (1,2) );
Group( (1,2,3,4), (1,2) )
gap> v4 := Centralizer( s4, (1,2) );
Subgroup( Group( (1,2,3,4), (1,2) ), [ (3,4), (1,2) ] )```

The default function `GroupOps.Centralizer` uses `Stabilizer` (see Stabilizer) in order to compute the centralizer of x in G acting by conjugation.

`Centralizer( G, U )`

`Centralizer` returns the centralizer of a group U in G as group record. Note that G and U must have a common parent group.

The centralizer of a group U in G is defined as the set C of elements c of C such c commutes with every element of U.

If G is the parent group of U then `Centralizer` will set and test the record component `U.centralizer`.

```    gap> s4 := Group( (1,2,3,4), (1,2) );
Group( (1,2,3,4), (1,2) )
gap> v4 := Centralizer( s4, (1,2) );
Subgroup( Group( (1,2,3,4), (1,2) ), [ (3,4), (1,2) ] )
gap> c2 := Subgroup( s4, [ (1,3) ] );
Subgroup( Group( (1,2,3,4), (1,2) ), [ (1,3) ] )
gap> Centralizer( v4, c2 );
Subgroup( Group( (1,2,3,4), (1,2) ), [  ] ) ```

The default function `GroupOps.Centralizer` uses `Stabilizer` in order to compute successively the stabilizer of the generators of U.

## 7.17 Centre

`Centre( G )`

`Centre` returns the centre of G.

The centre of a group G is defined as the centralizer of G in G.

Note that `Centre` sets and tests the record component `G.centre`.

```    gap> d8 := Group( (1,2,3,4), (1,2)(3,4) );
Group( (1,2,3,4), (1,2)(3,4) )
gap> Centre( d8 );
Subgroup( Group( (1,2,3,4), (1,2)(3,4) ), [ (1,3)(2,4) ] ) ```

The default group function `GroupOps.Centre` uses `Centralizer` (see Centralizer) in order to compute the centralizer of G in G.

## 7.18 Closure

`Closure( U, g )`

Let U be a group with parent group G and let g be an element of G. Then `Closure` returns the closure C of U and g as subgroup of G. The closure C of U and g is the subgroup generated by U and g.

```    gap> s4 := Group( (1,2,3,4), (1,2 ) );
Group( (1,2,3,4), (1,2) )
gap> s2 := Subgroup( s4, [ (1,2) ] );
Subgroup( Group( (1,2,3,4), (1,2) ), [ (1,2) ] )
gap> Closure( s2, (3,4) );
Subgroup( Group( (1,2,3,4), (1,2) ), [ (1,2), (3,4) ] ) ```

The default function `GroupOps.Closure` returns U if U is a parent group, or if g or its inverse is a generator of U, or if the set of elements is known and g is in this set, or if g is trivial. Otherwise the function constructs a new subgroup C which is generated by the generators of U and the element g.

Note that if the set of elements of U is bound to `U.elements` then `GroupOps.Closure` computes the set of elements for C and binds it to `C.elements`.

If U is known to be non-abelian or infinite so is C. If U is known to be abelian the function checks whether g commutes with every generator of U.

`Closure( U, S )`

Let U and S be two group with a common parent group G. Then `Closure` returns the subgroup of G generated by U and S.

```    gap> s4 := Group( (1,2,3,4), (1,2 ) );
Group( (1,2,3,4), (1,2) )
gap> s2 := Subgroup( s4, [ (1,2) ] );
Subgroup( Group( (1,2,3,4), (1,2) ), [ (1,2) ] )
gap> z3 := Subgroup( s4, [ (1,2,3) ] );
Subgroup( Group( (1,2,3,4), (1,2) ), [ (1,2,3) ] )
gap> Closure( z3, s2 );
Subgroup( Group( (1,2,3,4), (1,2) ), [ (1,2,3), (1,2) ] ) ```

The default function `GroupOps.Closure` returns the parent of U and S if U or S is a parent group. Otherwise the function computes the closure of U under all generators of S.

Note that if the set of elements of U is bound to `U.elements` then `GroupOps.Closure` computes the set of elements for the closure C and binds it to `C.elements`.

## 7.19 CommutatorSubgroup

`CommutatorSubgroup( G, H )`

Let G and H be groups with a common parent group. `CommutatorSubgroup` returns the commutator subgroup [ G, H ].

The commutator subgroup of G and H is the group generated by all commutators [ g, h ] with g in <G> and h in <H>.

See also `DerivedSubgroup` (DerivedSubgroup).

```    gap> s4 := Group( (1,2,3,4), (1,2) );
Group( (1,2,3,4), (1,2) )
gap> d8 := Group( (1,2,3,4), (1,2)(3,4) );
Group( (1,2,3,4), (1,2)(3,4) )
gap> CommutatorSubgroup( s4, AsSubgroup( s4, d8 ) );
Subgroup( Group( (1,2,3,4), (1,2) ), [ (1,3)(2,4), (1,3,2) ] ) ```

Let G be generated by g_1, ..., g_n and H be generated by h_1, ..., h_m. The normal closure of the subgroup S generated by Comm( g_i, h_j ) for 1 leq i leq n and 1 leq j leq m under G and H is the commutator subgroup of G and H (see Hup67). The default function `GroupOps.CommutatorSubgroup` returns the normal closure of S under the closure of G and H.

## 7.20 ConjugateSubgroup

`ConjugateSubgroup( U, g )`

`ConjugateSubgroup` returns the subgroup <U>^<g> conjugate to U under g, which must be an element of the parent group of G.

If present, the flags `U.isAbelian`, `U.isCyclic`, `U.isElementaryAbelian`, `U.isFinite`, `U.isNilpotent`, `U.isPerfect`, `U.isSimple`, `U.isSolvable`, and `U.size` are copied to <U>^<g>.

```    gap> s4 := Group( (1,2,3,4), (1,2) );
Group( (1,2,3,4), (1,2) )
gap> c2 := Subgroup( s4, [ (1,2)(3,4) ] );
Subgroup( Group( (1,2,3,4), (1,2) ), [ (1,2)(3,4) ] )
gap> ConjugateSubgroup( c2, (1,3) );
Subgroup( Group( (1,2,3,4), (1,2) ), [ (1,4)(2,3) ] ) ```

The default function `GroupOps.ConjugateSubgroup` returns U if the set of elements of U is known and g is an element of this set or if g is a generator of U. Otherwise it conjugates the generators of U with g.

If the set of elements of U is known the default function also conjugates and binds it to the conjugate subgroup.

## 7.21 Core

`Core( S, U )`

Let S and U be groups with a common parent group G. Then `Core` returns the core of U under conjugation of S.

The core of a group U under a group S Core_{<S>}( <U> ) is the intersection bigcap_{s in <S>} <U>^s of all groups conjugate to U under conjugation by elements of S.

```    gap> s4 := Group( (1,2,3,4), (1,2) );
Group( (1,2,3,4), (1,2) )
gap> s4.name := "s4";;
gap> d8 := Subgroup( s4, [ (1,2,3,4), (1,2)(3,4) ] );
Subgroup( s4, [ (1,2,3,4), (1,2)(3,4) ] )
gap> Core( s4, d8 );
Subgroup( s4, [ (1,2)(3,4), (1,3)(2,4) ] )
gap> Core( d8, s4 );
s4 ```

The default function `GroupOps.Core` starts with U and replaces U with the intersection of U and a conjugate subgroup of U under a generator of G until the subgroup is normalized by G.

## 7.22 DerivedSubgroup

`DerivedSubgroup( G )`

`DerivedSubgroup` returns the derived subgroup <G>^prime = [ <G>, <G> ] of G.

The derived subgroup of G is the group generated by all commutators [ g, h ] with g, h in <G>.

Note that `DerivedSubgroup` sets and tests `G.derivedSubgroup`. `CommutatorSubgroup` (see CommutatorSubgroup) allows you to compute the commutator group of two subgroups.

```    gap> s4 := Group( (1,2,3,4), (1,2) );
Group( (1,2,3,4), (1,2) )
gap> DerivedSubgroup( s4 );
Subgroup( Group( (1,2,3,4), (1,2) ), [ (1,3,2), (2,4,3) ] ) ```

Let G be generated by g_1, ..., g_n. Then the default function `GroupOps.DerivedSubgroup` returns the normal closure of S under G where S is the subgroup of G generated by Comm( g_i, g_j ) for 1 leq j < i leq n.

## 7.23 FittingSubgroup

`FittingSubgroup( G )`

`FittingSubgroup` returns the Fitting subgroup of G.

The Fitting subgroup of a group G is the biggest nilpotent normal subgroup of G.

```    gap> s4;
Group( (1,2,3,4), (1,2) )
gap> FittingSubgroup( s4 );
Subgroup( Group( (1,2,3,4), (1,2) ), [ (1,3)(2,4), (1,4)(2,3) ] )
gap> IsNilpotent( last );
true ```

Let G be a finite group. Then the default group function `GroupOps.FittingSubgroup` computes the subgroup of G generated by the cores of the Sylow subgroups in G.

## 7.24 FrattiniSubgroup

`FrattiniSubgroup( G )`

`FrattiniSubgroup` returns the Frattini subgroup of group G.

The Frattini subgroup of a group G is the intersection of all maximal subgroups of G.

```    gap> s4 := SymmetricGroup( AgWords, 4 );;
gap> ss4 := SpecialAgGroup( s4 );;
gap> FrattiniSubgroup( ss4 );
Subgroup( Group( g1, g2, g3, g4 ), [  ] ) ```

The generic method computes the Frattini subgroup as intersection of the cores (see Core) of the representatives of the conjugacy classes of maximal subgroups (see ConjugacyClassesMaximalSubgroups).

## 7.25 NormalClosure

`NormalClosure( S, U )`

Let S and U be groups with a common parent group G. Then `NormalClosure` returns the normal closure of U under S as a subgroup of G.

The normal closure N of a group U under the action of a group S is the smallest subgroup in G that contains U and is invariant under conjugation by elements of S. Note that N is independent of G.

```    gap> s4 := Group( (1,2,3,4), (1,2) );
Group( (1,2,3,4), (1,2) )
gap> s4.name := "s4";;
gap> d8 := Subgroup( s4, [ (1,2,3,4), (1,2)(3,4) ] );
Subgroup( s4, [ (1,2,3,4), (1,2)(3,4) ] )
gap> NormalClosure( s4, d8 );
Subgroup( s4, [ (1,2,3,4), (1,2)(3,4), (1,3,4,2) ] )
gap> last = s4;
true ```

## 7.26 NormalIntersection

`NormalIntersection( N, U )`

Let N and U be two subgroups with a common parent group. `NormalIntersection` returns the intersection in case U normalizes N.

Depending on the domain this may be faster than the general intersection algorithm (see Intersection). The default function `GroupOps.NormalIntersection` however uses `Intersection`.

## 7.27 Normalizer

`Normalizer( S, U )`

Let S and U be groups with a common parent group G. Then `Normalizer` returns the normalizer of U in S.

The normalizer N_{<S>}( <U> ) of U in S is the biggest subgroup of S which leaves U invariant under conjugation.

If S is the parent group of U then `Normalizer` sets and tests `U.normalizer`.

```    gap> s4 := Group( (1,2,3,4), (1,2) );
Group( (1,2,3,4), (1,2) )
gap> c2 := Subgroup( s4, [ (1,2) ] );
Subgroup( Group( (1,2,3,4), (1,2) ), [ (1,2) ] )
gap> Normalizer( s4, c2 );
Subgroup( Group( (1,2,3,4), (1,2) ), [ (3,4), (1,2) ] )```

The default function `GroupOps.Normalizer` uses `Stabilizer` (see Stabilizer) in order to compute the stabilizer of U in S acting by conjugation (see ConjugateSubgroup).

## 7.28 PCore

`PCore( G, p )`

`PCore` returns the p-core of the finite group G for a prime p.

The p-core is the largest normal subgroup whose size is a power of p. This is the core of the Sylow-p-subgroups (see Core and SylowSubgroup).

Note that `PCore` sets and tests `G.pCores[ p ]`.

```    gap> s4 := Group( (1,2,3,4), (1,2) );
Group( (1,2,3,4), (1,2) )
gap> PCore( s4, 2 );
Subgroup( Group( (1,2,3,4), (1,2) ), [ (1,4)(2,3), (1,3)(2,4) ] )
gap> PCore( s4, 3 );
Subgroup( Group( (1,2,3,4), (1,2) ), [  ] ) ```

The default function `GroupOps.PCore` computes the p-core as the core of a Sylow-p-subgroup (see Core and SylowSubgroup).

## 7.29 PrefrattiniSubgroup

`PrefrattiniSubgroup( G )`

`PrefrattiniSubgroup` returns a Prefrattini subgroup of the group G.

A factor M/N of G is called a Frattini factor if M/N leq phi(G/N) holds. The group P is a Prefrattini subgroup of G if P covers each Frattini chief factor of G, and if for each maximal subgroup of G there exists a conjugate maximal subgroup, which contains P.

```    gap> s4 := SymmetricGroup( AgWords, 4 );;
gap> ss4 := SpecialAgGroup( s4 );;
gap> PrefrattiniSubgroup( ss4 );
Subgroup( Group( g1, g2, g3, g4 ), [  ] ) ```

Currently `PrefrattiniSubgroup` can only be applied to special Ag groups (see Special Ag Groups).

`Radical( G )`

`Radical` returns the radical of the finite group G.

The radical is the largest normal solvable subgroup of G.

```    gap> g := Group( (1,5), (1,5,6,7,8)(2,3,4) );
Group( (1,5), (1,5,6,7,8)(2,3,4) )
Subgroup( Group( (1,5), (1,5,6,7,8)(2,3,4) ), [ ( 2, 3, 4) ] )```

The default function `GroupOps.Radical` tests if G is solvable and signals an error if not.

## 7.31 SylowSubgroup

`SylowSubgroup( G, p )`

`SylowSubgroup` returns a Sylow-p-subgroup of the finite group G for a prime p.

Let p be a prime and G be a finite group of order <p>^n m where m is relative prime to p. Then by Sylow's theorem there exists at least one subgroup S of G of order <p>^n.

Note that `SylowSubgroup` sets and tests `G.sylowSubgroups[ p ]`.

```    gap> s4 := Group( (1,2,3,4), (1,2) );
Group( (1,2,3,4), (1,2) )
gap> SylowSubgroup( s4, 2 );
Subgroup( Group( (1,2,3,4), (1,2) ), [ (3,4), (1,2), (1,3)(2,4) ] )
gap> SylowSubgroup( s4, 3 );
Subgroup( Group( (1,2,3,4), (1,2) ), [ (2,3,4) ] ) ```

The default function `GroupOps.SylowSubgroup` computes the set of elements of p power order of G, starts with such an element of maximal order and computes the closure (see Closure) with normalizing elements of p power order until a Sylow group is found.

## 7.32 TrivialSubgroup

`TrivialSubgroup( U )`

Let U be a group with parent group G. Then `TrivialSubgroup` returns the trivial subgroup T of U. Note that the parent group of T is G not U (see Subgroups).

The default function `GroupOps.TrivialSubgroup` binds the set of elements of U, namely [ <U>.identity ], to `T.elements`,

## 7.33 FactorGroup

`FactorGroup( G, N )`

`FactorGroup` returns the factor group <G> / <N> where N must be a normal subgroup of G (see IsNormal). This is the same as `G / N` (see Operations for Groups).

`NaturalHomomorphism` returns the natural homomorphism from G (or a subgroup thereof) onto the factor group (see NaturalHomomorphism).

It is not specified how the factor group N is represented.

```    gap> a4 := Group( (1,2,3), (2,3,4) );;  a4.name := "a4";
"a4"
gap> v4 := Subgroup(a4,[(1,2)(3,4),(1,3)(2,4)]);;  v4.name := "v4";
"v4"
gap> f := FactorGroup( a4, v4 );
(a4 / v4)
gap> Size( f );
3
gap> Elements( f );
[ FactorGroupElement( v4, () ), FactorGroupElement( v4, (2,3,4) ),
FactorGroupElement( v4, (2,4,3) ) ] ```

If G is the parent group of N, `FactorGroup` first checks for the knowledge component `N.factorGroup`. If this component is bound, `FactorGroup` returns its value. Otherwise, `FactorGroup` calls `G.operations.FactorGroup( G, N )`, remembers the returned value in `N.factorGroup`, and returns it. If G is not the parent group of N, `FactorGroup` calls `G.operations.FactorGroup( G, N )` and returns this value.

The default function called this way is `GroupOps.FactorGroup`. It returns the factor group as a group of factor group elements (see FactorGroupElement). Look under FactorGroup in the index to see for which groups this function is overlaid.

## 7.34 FactorGroupElement

`FactorGroupElement( N, g )`

`FactorGroupElement` returns the coset `N * g` as a group element. It is not tested whether g normalizes N, but g must be an element of the parent group of N.

Factor group elements returned by `FactorGroupElement` are represented by records. Those records contain the following components.

`isGroupElement`:

contains `true`.

`isFactorGroupElement`:

contains `true`.

`element`:

contains a right coset of N (see RightCoset).

`domain`:

contains `FactorGroupElements` (see Domain).

`operations`:

contains the operations record `FactorGroupElementOps`.

All operations for group elements (see Operations for Group Elements) are available for factor group elements, e.g., two factor group elements can be multiplied (provided that they have the same subgroup N).

```    gap> a4 := Group( (1,2,3), (2,3,4) );;  a4.name := "a4";;
gap> v4 := Subgroup(a4,[(1,2)(3,4),(1,3)(2,4)]);;  v4.name := "v4";;
gap> x := FactorGroupElement( v4, (1,2,3) );
FactorGroupElement( v4, (2,4,3) )
gap> y := FactorGroupElement( v4, (2,3,4) );
FactorGroupElement( v4, (2,3,4) )
gap> x * y;
FactorGroupElement( v4, () ) ```

## 7.35 CommutatorFactorGroup

`CommutatorFactorGroup( G )`

`CommutatorFactorGroup` returns a group isomorphic to G/<G>^prime where <G>^prime is the derived subgroup of G (see DerivedSubgroup).

```    gap> s4 := AgGroup( Group( (1,2,3,4), (1,2) ) );
Group( g1, g2, g3, g4 )
gap> CommutatorFactorGroup( s4 );
Group( g1 ) ```

The default group function `GroupOps.CommutatorFactorGroup` uses `DerivedSubgroup` (see DerivedSubgroup) and `FactorGroup` (see FactorGroup) in order to compute the commutator factor group.

## 7.36 Series of Subgroups

The following sections describe functions that compute and return series of subgroups of a given group (see DerivedSeries, LowerCentralSeries, SubnormalSeries, and UpperCentralSeries). The series are returned as lists of subgroups of the group (see More about Groups and Subgroups).

These functions print warnings if the argument is an infinite group, because they may run forever.

## 7.37 DerivedSeries

`DerivedSeries( G )`

`DerivedSeries` returns the derived series of G.

The derived series is the series of iterated derived subgroups. The group G is solvable if and only if this series reaches {1} after finitely many steps.

Note that this function does not terminate if G is an infinite group with derived series of infinite length.

```    gap> s4 := Group( (1,2,3,4), (1,2) );
Group( (1,2,3,4), (1,2) )
gap> DerivedSeries( s4 );
[ Group( (1,2,3,4), (1,2) ), Subgroup( Group( (1,2,3,4), (1,2) ),
[ (1,3,2), (1,4,3) ] ), Subgroup( Group( (1,2,3,4), (1,2) ),
[ (1,4)(2,3), (1,3)(2,4) ] ),
Subgroup( Group( (1,2,3,4), (1,2) ), [  ] ) ] ```

The default function `GroupOps.DerivedSeries` uses `DerivedSubgroup` (see DerivedSubgroup) in order to compute the derived series of G.

## 7.38 CompositionSeries

`CompositionSeries( G )`

`CompositionSeries` returns a composition series of G as list of subgroups.

```    gap> s4 := SymmetricGroup( 4 );
Group( (1,4), (2,4), (3,4) )
gap> s4.name := "s4";;
gap> CompositionSeries( s4 );
[ Subgroup( s4, [ (1,2), (1,3,2), (1,3)(2,4), (1,2)(3,4) ] ),
Subgroup( s4, [ (1,3,2), (1,3)(2,4), (1,2)(3,4) ] ),
Subgroup( s4, [ (1,3)(2,4), (1,2)(3,4) ] ),
Subgroup( s4, [ (1,2)(3,4) ] ), Subgroup( s4, [  ] ) ]
gap> d8 := SylowSubgroup( s4, 2 );
Subgroup( s4, [ (1,2), (3,4), (1,3)(2,4) ] )
gap> CompositionSeries( d8 );
[ Subgroup( s4, [ (1,3)(2,4), (1,2), (3,4) ] ),
Subgroup( s4, [ (1,2), (3,4) ] ), Subgroup( s4, [ (3,4) ] ),
Subgroup( s4, [  ] ) ] ```

Note that there is no default function. `GroupOps.CompositionSeries` signals an error if called.

## 7.39 ElementaryAbelianSeries

`ElementaryAbelianSeries( G )`

Let G be a solvable group (see IsSolvable). Then the functions returns a normal series G = E_0, E_1, ..., E_n = {1} of G such that the factor groups E_i / E_{i+1} are elementary abelian groups.

```    gap> s5 := SymmetricGroup( 5 );; s5.name := "s5";;
gap> s4 := Subgroup( s5, [ (2,3,4,5), (2,3) ] );
Subgroup( s5, [ (2,3,4,5), (2,3) ] )
gap> ElementaryAbelianSeries( s4 );
[ Subgroup( s5, [ (2,3), (2,4,3), (2,5)(3,4), (2,3)(4,5) ] ),
Subgroup( s5, [ (2,4,3), (2,5)(3,4), (2,3)(4,5) ] ),
Subgroup( s5, [ (2,5)(3,4), (2,3)(4,5) ] ), Subgroup( s5, [  ] ) ] ```

The default function `GroupOps.ElementaryAbelianSeries` uses `AgGroup` (see AgGroup) in order to convert G into an isomorphic ag group and computes the elementary abelian series in this group. (see Group Functions for Ag Groups).

## 7.40 JenningsSeries

`JenningsSeries( G, p )`

`JenningsSeries` returns the Jennings series of a p-group G.

The Jennings series of a p-group G is defined as follows. S_1 = G and S_n = [ S_{n-1}, G ] {S_i}^p where i is the smallest integer equal or greater than n / p. The length l of S is the smallest integer such that S_l = { 1 }.

Note that S_n = S_{n+1} is possible.

```    gap> G := CyclicGroup( AgWords, 27 );
Group( c27_1, c27_2, c27_3 )
gap> G.name := "G";;
gap> JenningsSeries( G );
[ G, Subgroup( G, [ c27_2, c27_3 ] ), Subgroup( G, [ c27_2, c27_3 ] ),
Subgroup( G, [ c27_3 ] ), Subgroup( G, [ c27_3 ] ),
Subgroup( G, [ c27_3 ] ), Subgroup( G, [ c27_3 ] ),
Subgroup( G, [ c27_3 ] ), Subgroup( G, [ c27_3 ] ),
Subgroup( G, [  ] ) ] ```

## 7.41 LowerCentralSeries

`LowerCentralSeries( G )`

`LowerCentralSeries` returns the lower central series of G as a list of group records.

The lower central series is the series defined by S_1 = <G> and S_i = [ <G>, S_{i-1} ]. The group G is nilpotent if this series reaches {1} after finitely many steps.

Note that this function may not terminate if G is an infinite group. `LowerCentralSeries` sets and tests the record component `G.lowerCentralSeries` in the group record of G.

```    gap> s4 := Group( (1,2,3,4), (1,2) );
Group( (1,2,3,4), (1,2) )
gap> LowerCentralSeries( s4 );
[ Group( (1,2,3,4), (1,2) ), Subgroup( Group( (1,2,3,4), (1,2) ),
[ (1,3,2), (2,4,3) ] ) ] ```

The default group function `GroupOps.LowerCentralSeries` uses `CommutatorSubgroup` (see CommutatorSubgroup) in order to compute the lower central series of G.

## 7.42 PCentralSeries

`PCentralSeries( G, p )`

`PCentralSeries` returns the p-central series of a group G for a prime p.

The p-central series of a group G is defined as follows. S_1 = G and S_{i+1} is set to [G,S_i] * S_i^p. The length of this series is n, where n = max{ i ; S_i > S_{i+1} }.

```    gap> s4 := Group( (1,2,3,4), (1,2) );; s4.name := "s4";;
gap> PCentralSeries( s4, 3 );
[ s4 ]
gap> PCentralSeries( s4, 2 );
[ s4, Subgroup( s4, [ (1,2,3), (1,3,4) ] ) ] ```

## 7.43 SubnormalSeries

`SubnormalSeries( G, U )`

Let U be a subgroup of G, then `SubnormalSeries` returns a subnormal series <G> = G_1 > ... > G_n of groups such that U is contained in G_n and there exists no proper subgroup V between G_n and U which is normal in G_n.

G_n is equal to U if and only if U is subnormal in G.

Note that this function may not terminate if G is an infinite group.

```    gap> s4 := Group( (1,2,3,4), (1,2) );
Group( (1,2,3,4), (1,2) )
gap> c2 := Subgroup( s4, [ (1,2) ] );
Subgroup( Group( (1,2,3,4), (1,2) ), [ (1,2) ] )
gap> SubnormalSeries( s4, c2 );
[ Group( (1,2,3,4), (1,2) ) ]
gap> IsSubnormal( s4, c2 );
false
gap> c2 := Subgroup( s4, [ (1,2)(3,4) ] );
Subgroup( Group( (1,2,3,4), (1,2) ), [ (1,2)(3,4) ] )
gap> SubnormalSeries( s4, c2 );
[ Group( (1,2,3,4), (1,2) ), Subgroup( Group( (1,2,3,4), (1,2) ),
[ (1,2)(3,4), (1,3)(2,4) ] ),
Subgroup( Group( (1,2,3,4), (1,2) ), [ (1,2)(3,4) ] ) ]
gap> IsSubnormal( s4, c2 );
true ```

The default function `GroupOps.SubnormalSeries` constructs the subnormal series as follows. G_1 = G and G_{i+1} is set to the normal closure (see NormalClosure) of U under G_i. The length of the series is n, where n = max{i; G_i > G_{i+1}}.

## 7.44 UpperCentralSeries

`UpperCentralSeries( G )`

`UpperCentralSeries` returns the upper central series of G as a list of subgroups.

The upper central series is the series S_n, ..., S_0 defined by S_0 = {1} < <G> and S_i/S_{i-1} = Z( <G>/S_{i-1} ) where n = min{ i ; S_i = S_{i+1} }

Note that this function may not terminate if G is an infinite group. `UpperCentralSeries` sets and tests `G.upperCentralSeries` in the group record of G.

```    gap> d8 := AgGroup( Group( (1,2,3,4), (1,2)(3,4) ) );
Group( g1, g2, g3 )
gap> UpperCentralSeries( d8 );
[ Group( g1, g2, g3 ), Subgroup( Group( g1, g2, g3 ), [ g3 ] ),
Subgroup( Group( g1, g2, g3 ), [  ] ) ] ```

## 7.45 Properties and Property Tests

The following sections describe the functions that computes or test properties of groups (see AbelianInvariants, DimensionsLoewyFactors, EulerianFunction, Exponent, Factorization, Index, IsAbelian, IsCentral, IsConjugate, IsCyclic, IsElementaryAbelian, IsNilpotent, IsNormal, IsPerfect, IsSimple, IsSolvable, IsSubgroup, IsSubnormal, IsTrivial for Groups, GroupId, PermutationCharacter).

All tests expect a parent group or subgroup and return `true` if the group has the property and `false` otherwise. Some functions may not terminate if the given group has an infinite set of elements. A warning may be printed in such cases.

In addition the set theoretic functions `Elements`, `Size` and `IsFinite`, which are described in chapter Domains, can be used for groups. `Size` (see Size) returns the order of a group, this is either a positive integer or the string ``infinity''. `IsFinite` (see IsFinite) returns `true` if a group is finite and `false` otherwise.

## 7.46 AbelianInvariants

`AbelianInvariants( G )`

Let G be an abelian group. Then `AbelianInvariants` returns the abelian invariants of G as a list of integers. If G is not abelian then the abelian invariants of the commutator factor group of G are returned.

Let G be a finitely generated abelian group. Then there exist n nontrivial subgroups A_i of prime power order p_i^{e_i} and m infinite cyclic subgroups Z_j such that <G> = A_1 times ... times A_n times Z_1 ... times Z_m. The invariants of G are the integers p_1^{e_1}, ..., p_n^{e_n} together with m zeros.

Note that `AbelianInvariants` tests and sets `G.abelianInvariants`.

```    gap> AbelianInvariants( AbelianGroup( AgWords, [2,3,4,5,6,9] ) );
[ 2, 2, 3, 3, 4, 5, 9 ] ```

The default function `GroupOps.AbelianInvariants` requires that G is finite.

Let G be a finite abelian group of order p_1^{e_1}...p_n^{e_n} where p_i are distinct primes. The default function constructs for every prime p_i the series <G>, <G>^{p_i}, <G>^{p_i^2}, ... and computes the abelian invariants using the indices of these groups.

## 7.47 DimensionsLoewyFactors

`DimensionsLoewyFactors( G )`

Let G be p-group. Then `DimensionsLoewyFactors` returns the dimensions c_i of the Loewy factors of F_p<G>.

The Loewy series of F_p<G> is defined as follows. Let R be the Jacobson radical of the group ring F_p<G>. The series R^0 = F_p<G> > R^1 > ... > R^{l+1} = {1} is the Loewy series. The dimensions c_i are the dimensions of R^i / R^{i+1}.

```    gap> f6 := FreeGroup( 6, "f6" );;
gap> g := f6 / [ f6.1^3, f6.2^3, f6.3^3, f6.4^3, f6.5^3, f6.6^3,
>          Comm(f6.3,f6.2)/f6.6^2,  Comm(f6.3,f6.1)/(f6.6*f6.5),
>          Comm(f6.2,f6.1)/(f6.5*f6.4^2) ];;
gap> a := AgGroupFpGroup(g);
Group( f6.1, f6.2, f6.3, f6.4, f6.5, f6.6 )
gap> DimensionsLoewyFactors(a);
[ 1, 3, 9, 16, 30, 42, 62, 72, 87, 85, 87, 72, 62, 42, 30, 16, 9, 3,
1 ] ```

The default function `GroupOps.DimensionsLoewyFactors` computes the Jennings series of G and uses Jennings thereom in order to calculate the dimensions of the Loewy factors.

Let G = X_1 geq X_2 geq ... geq X_l > X_{l+1}={1} be the Jennings series of G (see JenningsSeries) and let d_i be the dimensions of X_i / X_{i+1}. Then the Jennings polynomial is sum_i=0^l c_i x^i = prod_k=1^l (1+x^k+x^2k+...+x^(p-1)k)^d_k.

## 7.48 EulerianFunction

`EulerianFunction( G, n )`

`EulerianFunction` returns the number of n-tuples (g_1, g_2, ldots g_n) of elements of the group G that generate the whole group G. The elements of a tuple need not be different.

```    gap> s4 := SymmetricGroup( AgWords, 4 );;
gap> ss4 := SpecialAgGroup( s4 );;
gap> EulerianFunction( ss4, 1 );
0
gap> EulerianFunction( ss4, 2 );
216
gap> EulerianFunction( ss4, 3 );
10080 ```

Currently `EulerianFunction` can only be applied to special Ag groups (see Special Ag Groups).

## 7.49 Exponent

`Exponent( G )`

Let G be a finite group. Then `Exponent` returns the exponent of G.

Note that `Exponent` tests and sets `G.exponent`.

```    gap> Exponent( Group( (1,2,3,4), (1,2) ) );
12 ```

The default function `GroupOps.Exponent` computes all elements of G and their orders.

## 7.50 Factorization

`Factorization( G, g )`

Let G be a group with generators g_1, ..., g_n and let g be an element of G. `Factorization` returns a representation of g as word in the generators of G.

The group record of G must have a component `G.abstractGenerators` which contains a list of n abstract words h_1, ..., h_n. Otherwise a list of n abstract generators is bound to `G.abstractGenerators`. The function returns an abstract word h = h_{i_1}^{e_1} * ... * h_{i_m}^{e_m} such that g_{i_1}^{e_1} * ... * g_{i_m}^{e_m} = <g>.

```    gap> s4 := Group( (1,2,3,4), (1,2) );
Group( (1,2,3,4), (1,2) )
gap> Factorization( s4, (1,2,3) );
x1^3*x2*x1*x2
gap> (1,2,3,4)^3 * (1,2) * (1,2,3,4) * (1,2);
(1,2,3) ```

The default group function `GroupOps.Factorization` needs a finite group G. It computes the set of elements of G using a Dimino algorithm, together with a representation of these elements as words in the generators of G.

## 7.51 Index

`Index( G, U )`

Let U be a subgroup of G. Then `Index` returns the index of U in G as an integer.

Note that `Index` sets and checks `U.index` if G is the parent group of U.

```    gap> s4 := Group( (1,2,3,4), (1,2) );
Group( (1,2,3,4), (1,2) )
gap> Index( s4, DerivedSubgroup( s4 ) );
2 ```

The default function `GroupOps.Index` needs a finite group G. It returns the quotient of `Size( G )` and `Size( U )`.

## 7.52 IsAbelian

`IsAbelian( G )`

`IsAbelian` returns `true` if the group G is abelian and `false` otherwise.

A group G is abelian if and only if for every g, h in <G> the equation g* h = h* g holds.

Note that `IsAbelian` sets and tests the record component `G.isAbelian`. If G is abelian it also sets `G.centre`.

```    gap> s4 := Group( (1,2,3,4), (1,2) );;
gap> IsAbelian( s4 );
false
gap> IsAbelian( Subgroup( s4, [ (1,2) ] ) );
true ```

The default group function `GroupOps.IsAbelian` returns `true` for a group G generated by g_1, ..., g_n if g_i commutes with g_j for i > j.

## 7.53 IsCentral

`IsCentral( G, U )`

`IsCentral` returns `true` if the group G centralizes the group U and `false` otherwise.

A group G centralizes a group U if and only if for all g in <G> and for all u in <U> the equation g* u = u* g holds. Note that U need not to be a subgroup of G but they must have a common parent group.

Note that `IsCentral` sets and tests `U.isCentral` if G is the parent group of U.

```    gap> s4 := Group( (1,2,3,4), (1,2) );;
gap> d8 := Subgroup( s4, [ (1,2,3,4), (1,2)(3,4) ] );;
gap> c2 := Subgroup( s4, [ (1,3)(2,4) ] );;
gap> IsCentral( s4, c2 );
false
gap> IsCentral( d8, c2 );
true ```

The default function `GroupOps.IsCentral` tests whether G centralizes U by testing whether the generators of G commutes with the generators of U.

## 7.54 IsConjugate

`IsConjugate( G, x, y )`

Let x and y be elements of the parent group of G. Then `IsConjugate` returns `true` if x is conjugate to y under an element g of G and `false` otherwise.

```    gap> s5 := Group( (1,2,3,4,5), (1,2) );
Group( (1,2,3,4,5), (1,2) )
gap> a5 := Subgroup( s5, [ (1,2,3), (2,3,4), (3,4,5) ] );
Subgroup( Group( (1,2,3,4,5), (1,2) ), [ (1,2,3), (2,3,4), (3,4,5) ] )
gap> IsConjugate( a5, (1,2,3,4,5), (1,2,3,4,5)^2 );
false
gap> IsConjugate( s5, (1,2,3,4,5), (1,2,3,4,5)^2 );
true ```

The default function `GroupOps.IsConjugate` uses `Representative` (see Representative) in order to check whether x is conjugate to y under G.

## 7.55 IsCyclic

`IsCyclic( G )`

`IsCyclic` returns `true` if G is cyclic and `false` otherwise.

A group G is cyclic if and only if there exists an element g in <G> such that G is generated by g.

Note that `IsCyclic` sets and tests the record component `G.isCyclic`.

```    gap> z6 := Group( (1,2,3), (4,5) );;
gap> IsCyclic( z6 );
true
gap> z36 := AbelianGroup( AgWords, [ 9, 4 ] );;
gap> IsCyclic( z36 );
true ```

The default function `GroupOps.IsCyclic` returns `false` if G is not an abelian group. Otherwise it computes the abelian invariants (see AbelianInvariants) if G is infinite. If G is finite of order p_1^{e_1} ... p_n^{e_n}, where p_i are distinct primes, then G is cyclic if and only if each <G>^{p_i} has index p_i in G.

## 7.56 IsElementaryAbelian

`IsElementaryAbelian( G )`

`IsElementaryAbelian` returns `true` if the group G is an elementary abelian p-group for a prime p and `false` otherwise.

A p-group G is elementary abelian if and only if for every g, h in <G> the equations g* h = h* g and g^p = 1 hold.

Note that the `IsElementaryAbelian` sets and tests `G.isElementaryAbelian`.

```    gap> z4 := Group( (1,2,3,4) );;
gap> IsElementaryAbelian( z4 );
false
gap> v4 := Group( (1,2)(3,4), (1,3)(2,4) );;
gap> IsElementaryAbelian( v4 );
true ```

The default function `GroupOps.IsElementaryAbelian` returns `true` if G is abelian and for some prime p each generator is of order p.

## 7.57 IsNilpotent

`IsNilpotent( G )`

`IsNilpotent` returns `true` if the group G is nilpotent and `false` otherwise.

A group G is nilpotent if and only if the lower central series of G is of finite length and reaches {1}.

Note that `IsNilpotent` sets and tests the record component `G.isNilpotent`.

```    gap> s4 := Group( (1,2,3,4), (1,2) );;
gap> IsNilpotent( s4 );
false
gap> v4 := Group( (1,2)(3,4), (1,3)(2,4) );;
gap> IsNilpotent( v4 );
true ```

The default group function `GroupOps.IsNilpotent` computes the lower central series using `LowerCentralSeries` (see LowerCentralSeries) in order to check whether G is nilpotent.

If G has an infinite set of elements a warning is given, as this function does not stop if G has a lower central series of infinite length.

## 7.58 IsNormal

`IsNormal( G, U )`

`IsNormal` returns `true` if the group G normalizes the group U and `false` otherwise.

A group G normalizes a group U if and only if for every g in <G> and u in <U> the element u^g is a member of U. Note that U need not be a subgroup of G but they must have a common parent group.

Note that `IsNormal` tests and sets `U.isNormal` if G is the parent group of U.

```    gap> s4 := Group( (1,2,3,4), (1,2) );;
gap> d8 := Subgroup( s4, [ (1,2,3,4), (1,2)(3,4) ] );;
gap> c2 := Subgroup( s4, [ (1,3)(2,4) ] );;
gap> IsNormal( s4, c2 );
false
gap> IsNormal( d8, c2 );
true ```

Let G be a finite group. Then the default function `GroupOps.IsNormal` checks whether the conjugate of each generator of U under each generator of G is an element of U.

If G is an infinite group, then the default function `GroupOps.IsNormal` checks whether the conjugate of each generator of U under each generator of G and its inverse is an element of U.

## 7.59 IsPerfect

`IsPerfect( G )`

`IsPerfect` returns `true` if G is a perfect group and `false` otherwise.

A group G is perfect if G is equal to its derived subgroup. See DerivedSubgroup.

Note that `IsPerfect` sets and tests `G.isPerfect`.

```    gap> a4 := Group( (1,2,3), (2,3,4) );
Group( (1,2,3), (2,3,4) )
gap> IsPerfect( a4 );
false
gap> a5 := Group( (1,2,3), (2,3,4), (3,4,5) );
Group( (1,2,3), (2,3,4), (3,4,5) )
gap> IsPerfect( a5 );
true ```

The default group function `GroupOps.IsPerfect` checks for a finite group G the index of <G>^prime (see DerivedSubgroup) in G. For an infinite group it computes the abelian invariants of the commutator factor group (see AbelianInvariants and CommutatorFactorGroup).

## 7.60 IsSimple

`IsSimple( G )`

`IsSimple` returns `true` if G is simple and `false` otherwise.

A group G is simple if and only if G and the trivial subgroup are the only normal subgroups of G.

```    gap> s4 := Group( (1,2,3,4), (1,2) );
Group( (1,2,3,4), (1,2) )
gap> IsSimple( DerivedSubgroup( s4 ) );
false
gap> s5 := Group( (1,2,3,4,5), (1,2) );
Group( (1,2,3,4,5), (1,2) )
gap> IsSimple( DerivedSubgroup( s5 ) );
true ```

## 7.61 IsSolvable

`IsSolvable( G )`

`IsSolvable` returns `true` if the group G is solvable and `false` otherwise.

A group G is solvable if and only if the derived series of G is of finite length and reaches {1}.

Note that `IsSolvable` sets and tests `G.isSolvable`.

```    gap> s4 := Group( (1,2,3,4), (1,2) );;
gap> IsSolvable( s4 );
true ```

The default function `GroupOps.IsSolvable` computes the derived series using the function `DerivedSeries` (see DerivedSeries) in order to see whether G is solvable.

If G has an infinite set of elements a warning is given, as this function does not stop if G has a derived series of infinite length.

## 7.62 IsSubgroup

`IsSubgroup( G, U )`

`IsSubgroup` returns `true` if U is a subgroup of G and `false` otherwise.

Note that G and U must have a common parent group. This function returns `true` if and only if the set of elements of U is a subset of the set of elements of G, it is not the inverse of `IsParent` (see IsParent).

```    gap> s6  := Group( (1,2,3,4,5,6), (1,2) );;
gap> s4 := Subgroup( s6, [ (1,2,3,4), (1,2) ] );;
gap> z2 := Subgroup( s6, [ (5,6) ] );;
gap> IsSubgroup( s4, z2 );
false
gap> v4 := Subgroup( s6, [ (1,2)(3,4), (1,3)(2,4) ] );;
gap> IsSubgroup( s4, v4 );
true ```

If the elements of G are known, then the default function `GroupOps.IsSubgroup` checks whether the set of generators of U is a subset of the set of elements of G. Otherwise the function checks whether each generator of U is an element of G using `in`.

## 7.63 IsSubnormal

`IsSubnormal( G, U )`

`IsSubnormal` returns `true` if the subgroup U of G is subnormal in G and `false` otherwise.

A subgroup U of G is subnormal if and only if there exists a series of subgroups <G> = G_0 > G_1 > ... > G_n = <U> such that G_i is normal in G_{i-1} for all i in {1, ..., n}.

Note that U must be a subgroup of G. The function sets and checks `U.isSubnormal` if G is the parent group of G.

```    gap> s4 := Group( (1,2,3,4), (1,2) );
Group( (1,2,3,4), (1,2) )
gap> c2 := Subgroup( s4, [ (1,2) ] );
Subgroup( Group( (1,2,3,4), (1,2) ), [ (1,2) ] )
gap> IsSubnormal( s4, c2 );
false
gap> c2 := Subgroup( s4, [ (1,2)(3,4) ] );
Subgroup( Group( (1,2,3,4), (1,2) ), [ (1,2)(3,4) ] )
gap> IsSubnormal( s4, c2 );
true ```

The default function `GroupOps.IsSubnormal` uses `SubnormalSeries` (see SubnormalSeries) in order to check if U is subnormal in G.

## 7.64 IsTrivial for Groups

`GroupOps.IsTrivial( G )`

`GroupOps.IsTrivial` returns `true` if G is the trivial group and `false` otherwise.

Note that G is trivial if and only if the component `generators` of the group record of G is the empty list. It is faster to check this than to call `IsTrivial`.

## 7.65 GroupId

`GroupId( G )`

For certain small groups the function returns a record which will identify the isomorphism type of G with respect to certain classifications. This record contains the components described below.

The function will work for all groups of order at most 100 or whose order is a product of at most three primes. Moreover if the ANU pq is installed and loaded (see RequirePackage and ANU pq Package) you can also use `GroupId` to identify groups of order 128, 256, 243 and 729. In this case a standard presentation for G is computed (see StandardPresentation) and the returned record will only contain the components `size`, `pGroupId`, and possibly `abelianInvariants`. For 2- or 3-groups of order at most 100 `GroupId` will return the `pGroupId` identifier even if the ANU pq is not installed.

`catalogue`:

a pair [o,n] where o is the size of G and n is the catalogue number of G following the catalogue of groups of order at most 100. See The Solvable Groups Library for further details. This catalogue uses the Neubueser list for groups of order at most 100, excluding groups of orders 64 and 96 (see~Neu67). It uses the lists developed by~HS64 and~Lau82 for orders 64 and 96 respectively.medskip
Note that there are minor discrepancies between n and the number in Neu67 for abelian groups and groups of type `D(p,q)xr`. However, a solvable group G is isomorphic to `SolvableGroup(o, n)`, i.e., `GroupId(SolvableGroup(o,n)).catalogue` will be `[o,n]`.medskip
If G is a 2- or 3-group of order at most 100, its number in the appropriate p-group library is also returned. Note that, for such groups, the number n usually differs from the p-group identifier returned in `pGroupId` (see below).

`3primes`:

if G is non-abelian and its size is a product of at most three primes then `3primes` holds an identifier for G. The following isomorphisms are returned in `3primes`:
`["A",p]` = `A(p^3)`, `["B",p]` = `B(p^3)`, `["D",p,q,r]` = `D(p,q)xr`,
`["D",p,q]` = `D(p,q)`, `["G",p,q]` = `G(p^2,q)`, `["G",p,q,r,s]` = `G(p,q,r,s)`,
`["H",p,q]` = `H(p^2,q)`, `["H",p,q,r]` = `H(p,q,r)`, `["K",p,q]` = `K(p,q^2)`,
`["L",p,q,s]` = `L(p,q^2,s)`, `["M",p,q]` = `M(p,q^2)`, `["N",p,q]` = `N(p,q^2)`
(see `names` below for a definition of `A` ... `N`).

`pGroupId`:

if G is a 2- or 3-group, this will be the number of G in the list of 2-groups of order at most 256, prepared by Newman and O'Brien, or 3-groups of order at most 729, prepared by O'Brien and Rhodes. In particular, for an integer n and for o a power of 2 at most 256, `GroupId(TwoGroup(o,n)).pGroupId` is always n (and similarly for 3-groups). See The 2-Groups Library and The 3-Groups Library for details about the libraries of 2- and 3-groups. Note that if G is a 2- or 3-group of order at most 100 its `pGroupId` usually differs from its GAP solvable library number returned in `catalogue`.

`abelianInvariants`:

if G is abelian, this is a list of abelian invariants.

`names`:

a list of names of G. For non-abelian groups of order 96 this name is that used in the Laue catalogue (see~Lau82). For the other groups the following symbols are used. Note that this list of names is neither complete, i.e., most of the groups of order 64 do not have a name even if they are of one of the types described below, nor does it uniquely determine the group up to isomorphism in some cases. medskip
`m` is the cyclic group of order m,
`Dm` is the dihedral group of order m,
`Qm` is the quaternion group of order m,
`QDm` is the quasi-dihedral group of order m,
`Sm` is the symmetric group on m points,
`Am` is the alternating group on m points,
`SL(d,q)` is the special linear group,
`GL(d,q)` is the general linear group,
`PSL(d,q)` is the projective special linear group,
`K^n` is the direct power of m copies of K,
`K\$H` is a wreath product of K and H,
`K:H` is a split extension of K by H,
`K.H` is a non-split extension of K and H,
`K+H` is a subdirect product with identified factor groups of K and H,
`KYH` is a central amalgamated product of the groups K and H,
`KxH` is the direct product of K and H, smallskip
`A(p^3)` is < A, B, C ; A^p = B^p = C^p = [A,B] = [A,C] = 1, [B,C] = A > , smallskip
`B(p^3)` is < A, B, C ; B^p = C^p = A, A^p = [A,B] = [A,C] = 1, [B,C] = A > , smallskip
`D(p,q)` is < A, B ; A^q = B^p = 1, A^B = A^x > such that p|q-1, x neq 1 mod q, and x^p = 1 mod q, smallskip
`G(p^2,q)` is < A, B, C ; A^p = B^q = 1, C^p = A, [A,B] = [A,C] = 1, B^C = B^x > such that p|q-1, x neq 1 mod q, and x^p = 1 mod q, smallskip
`G(p,q,r,s)` is < A, B, C ; A^r = B^q = C^p = [A,B] = 1, A^C = A^x, B^C = B^{(y^s)} > such that p|q-1, p|r-1, x minimal with x neq 1 mod r and x^p = 1 mod r, y minimal with y neq 1 mod q and y^p = 1 mod q, and 0 < s < p,smallskip
`H(p^2,q)` is < A, B ; A^q = B^{(p^2)} = 1, A^B = A^x > such that p^2|q-1, x^p neq 1 mod q, and x^{(p^2)} = 1 mod q, smallskip
`H(p,q,r)` is < A, B ; A^r = B^{pq} = 1, A^B = A^x > such that pq|r-1, x^p neq 1 mod r, x^q neq 1 mod r, and x^{pq} = 1 mod r, smallskip
`K(p,q^2)` is < A, B, C ; A^q = B^q = C^p = [A,B] = 1, A^C = A^x, B^C = B^x > such that p|q-1, x neq 1 mod q, and x^p = 1 mod q, smallskip
`L(p,q^2,s)` is < A, B, C ; A^q = B^q = C^p = [A,B] = 1, A^C = A^x, B^C = B^{(x^s)} > such that p|q-1, x neq 1 mod q, x^p = 1 mod q, and 1 < s < p, note that `L(q,p^2,s)` cong `L(q,p^2,t)` iff s t = 1 mod p, smallskip
`M(p,q^2)` is < A, B ; A^{(q^2)} = B^p = 1, A^B = A^x > such that p|q-1, x neq 1 mod q^2, and x^p = 1 mod q^2, smallskip
`N(p,q^2)` is < A, B, C ; A^q = B^q = C^p = [A,B] = 1, A^C = A^{-1}B, B^C = A^{-1}B^{x^q+x-1} > such that 2 < p, p|q+1, x is an element of order p mod q^2, smallskip
`^` has the strongest, `x` the weakest binding.

```    gap> q8 := SolvableGroup( 8, 5 );;
gap> s4 := SymmetricGroup(4);;
gap> d8 := SylowSubgroup( s4, 2 );;
gap> GroupId(q8);
rec(
catalogue := [ 8, 5 ],
names := [ "Q8" ],
3primes := [ "B", 2 ],
size := 8,
pGroupId := 4 )
gap> GroupId(d8);
rec(
catalogue := [ 8, 4 ],
names := [ "D8" ],
3primes := [ "A", 2 ],
size := 8,
pGroupId := 3 )
gap> GroupId(s4);
rec(
catalogue := [ 24, 15 ],
names := [ "S4" ],
size := 24 )
gap> GroupId(DirectProduct(d8,d8));
rec(
catalogue := [ 64, 154 ],
names := [ "D8xD8" ],
size := 64,
pGroupId := 226 )
gap> GroupId(DirectProduct(q8,d8));
rec(
catalogue := [ 64, 155 ],
names := [ "D8xQ8" ],
size := 64,
pGroupId := 230 )
gap> GroupId( WreathProduct( CyclicGroup(2), CyclicGroup(4) ) );
rec(
catalogue := [ 64, 250 ],
names := [  ],
size := 64,
pGroupId := 32 )
gap> f := FreeGroup("c","b","a");; a:=f.3;;b:=f.2;;c:=f.1;;
gap> r := [ c^5, b^31, a^31, Comm(b,c)/b^7, Comm(a,c)/a, Comm(a,b) ];;
gap> g := AgGroupFpGroup( f / r );
Group( c, b, a )
gap> GroupId(g);
rec(
3primes := [ "L", 5, 31, 2 ],
names := [ "L(5,31^2,2)" ],
size := 4805 )
gap> RequirePackage("anupq");
gap> g := TwoGroup(256,4);
Group( a1, a2, a3, a4, a5, a6, a7, a8 )
gap> GroupId(g);
rec(
size := 256,
pGroupId := 4 )
gap> g := TwoGroup(256,232);
Group( a1, a2, a3, a4, a5, a6, a7, a8 )
gap> GroupId(g);
rec(
size := 256,
pGroupId := 232 ) ```

## 7.66 PermutationCharacter

`PermutationCharacter( G, U )`

computes the permutation character of the operation of G on the cosets of U. The permutation character is returned as list of integers such that the i.th position contains the value of the permutation character on the i.th conjugacy class of G (see ConjugacyClasses).

The value of the permutation character of U in G on a class c of G is the number of right cosets invariant under the action of an element of c.

```    gap> G := SymmetricPermGroup(5);;
gap> PermutationCharacter( G, SylowSubgroup(G,2) );
[ 15, 3, 3, 0, 0, 1, 0 ] ```

For small groups the default function `GroupOps.PermutationCharacter` calculates the permutation character by inducing the trivial character of U. For large groups it counts the fixed points by examining double cosets of U and the subgroup generated by a class element.

## 7.67 Conjugacy Classes

The following sections describe how one can compute conjugacy classes of elements and subgroups in a group (see ConjugacyClasses and ConjugacyClassesSubgroups). Further sections describe how conjugacy classes of elements are created (see ConjugacyClass and Set Functions for Conjugacy Classes and Conjugacy Class Records). Further sections describe how classes of subgroups are created (see ConjugacyClassSubgroups and IsConjugacyClassSubgroups), and how they are implemented (see Set Functions for Subgroup Conjugacy Classes and Subgroup Conjugacy Class Records). Another section describes the function that returns a conjugacy class of subgroups as a list of subgroups (see ConjugateSubgroups).

## 7.68 ConjugacyClasses

`ConjugacyClasses( G )`

`ConjugacyClasses` returns a list of the conjugacy classes of elements of the group G. The elements in the list returned are conjugacy class domains as created by `ConjugacyClass` (see ConjugacyClass). Because conjugacy classes are domains, all set theoretic functions can be applied to them (see Domains).

```    gap> a5 := Group( (1,2,3), (3,4,5) );;  a5.name := "a5";;
gap> ConjugacyClasses( a5 );
[ ConjugacyClass( a5, () ), ConjugacyClass( a5, (3,4,5) ),
ConjugacyClass( a5, (2,3)(4,5) ), ConjugacyClass( a5, (1,2,3,4,5) ),
ConjugacyClass( a5, (1,2,3,5,4) ) ] ```

`ConjugacyClasses` first checks if `G.conjugacyClasses` is bound. If the component is bound, it returns that value. Otherwise it calls `G.operations.ConjugacyClasses( G )`, remembers the returned value in `G.conjugacyClasses`, and returns it.

The default function called this way is `GroupOps.ConjugacyClasses`. This function takes random elements in G and tests whether such a random element g lies in one of the already known classes. If it does not it adds the new class `ConjugacyClass( G, g )` (see ConjugacyClass). Also after adding a new class it tests whether any power of the representative gives rise to a new class. It returns the list of classes when the sum of the sizes is equal to the size of G.

## 7.69 ConjugacyClass

`ConjugacyClass( G, g )`

`ConjugacyClass` returns the conjugacy class of the element g in the group G. Signals an error if g is not an element in G. The conjugacy class is returned as a domain, so that all set theoretic functions are applicable (see Domains).

```    gap> a5 := Group( (1,2,3), (3,4,5) );;  a5.name := "a5";;
gap> c := ConjugacyClass( a5, (1,2,3,4,5) );
ConjugacyClass( a5, (1,2,3,4,5) )
gap> Size( c );
12
gap> Representative( c );
(1,2,3,4,5)
gap> Elements( c );
[ (1,2,3,4,5), (1,2,4,5,3), (1,2,5,3,4), (1,3,5,4,2), (1,3,2,5,4),
(1,3,4,2,5), (1,4,3,5,2), (1,4,5,2,3), (1,4,2,3,5), (1,5,4,3,2),
(1,5,2,4,3), (1,5,3,2,4) ] ```

`ConjugacyClass` calls `G.operations.ConjugacyClass( G, g )` and returns that value.

The default function called this way is `GroupOps.ConjugacyClass`, which creates a conjugacy class record (see Conjugacy Class Records) with the Set Functions for Conjugacy Classes). Look in the index under ConjugacyClass to see for which groups this function is overlaid.

## 7.70 IsConjugacyClass

`IsConjugacyClass( obj )`

`IsConjugacyClass` returns `true` if obj is a conjugacy class as created by `ConjugacyClass` (see ConjugacyClass) and `false` otherwise.

```    gap> a5 := Group( (1,2,3), (3,4,5) );;  a5.name := "a5";;
gap> c := ConjugacyClass( a5, (1,2,3,4,5) );
ConjugacyClass( a5, (1,2,3,4,5) )
gap> IsConjugacyClass( c );
true
gap> IsConjugacyClass(
>       [ (1,2,3,4,5), (1,2,4,5,3), (1,2,5,3,4), (1,3,5,4,2),
>         (1,3,2,5,4), (1,3,4,2,5), (1,4,3,5,2), (1,4,5,2,3),
>         (1,4,2,3,5), (1,5,4,3,2), (1,5,2,4,3), (1,5,3,2,4) ] );
false    # even though this is as a set equal to 'c' ```

## 7.71 Set Functions for Conjugacy Classes

As mentioned above, conjugacy classes are domains, so all domain functions are applicable to conjugacy classes (see Domains). This section describes the functions that are implemented especially for conjugacy classes. Functions not mentioned here inherit the default functions mentioned in the respective sections.

In the following let C be the conjugacy class of the element g in the group G.

`Elements( C )`

The elements of the conjugacy class C are computed as the orbit of g under G, where G operates by conjugation.

`Size( C )`

The size of the conjugacy class C is computed as the index of the centralizer of g in G.

`h in C`

To test whether an element h lies in C, `in` tests whether there is an element of G that takes h to g. This is done by calling `RepresentativeOperation(G,h,g)` (see RepresentativeOperation).

`Random( C )`

A random element of the conjugacy class C is computed by conjugating g with a random element of G.

## 7.72 Conjugacy Class Records

A conjugacy class C of an element g in a group G is represented by a record with the following components.

`isDomain`:

always `true`.

`isConjugacyClass`:

always `true`.

`group`:

holds the group G.

`representative`:

holds the representative g.

The following component is optional. It is computed and assigned when the size of a conjugacy class is computed.

`centralizer`:

holds the centralizer of g in G.

## 7.73 ConjugacyClassesSubgroups

`ConjugacyClassesSubgroups( G )`

`ConjugacyClassesSubgroups` returns a list of all conjugacy classes of subgroups of the group G. The elements in the list returned are conjugacy class domains as created by `ConjugacyClassSubgroups` (see ConjugacyClassSubgroups). Because conjugacy classes are domains, all set theoretic functions can be applied to them (see Domains).

In fact, `ConjugacyClassesSubgroups` computes much more than it returns, for it calls (indirectly via the function `G.operations.ConjugacyClassesSubgroups( G )`) the `Lattice` command (see Lattice), constructs the whole subgroup lattice of G, stores it in the record component `G.lattice`, and finally returns the list `G.lattice.classes`. This means, in particular, that it will fail if G is non-solvable and its maximal perfect subgroup is not in the built-in catalogue of perfect groups (see the description of the `Lattice` command Lattice for details).

```    gap> # Conjugacy classes of subgroups of S4
gap> s4 := Group( (1,2,3,4), (1,2) );;
gap> s4.name := "s4";;
gap> cl := ConjugacyClassesSubgroups( s4 );
[ ConjugacyClassSubgroups( s4, Subgroup( s4, [  ] ) ),
ConjugacyClassSubgroups( s4, Subgroup( s4, [ (1,2)(3,4) ] ) ),
ConjugacyClassSubgroups( s4, Subgroup( s4, [ (3,4) ] ) ),
ConjugacyClassSubgroups( s4, Subgroup( s4, [ (2,3,4) ] ) ),
ConjugacyClassSubgroups( s4, Subgroup( s4, [ (1,2)(3,4), (1,3)(2,4)
] ) ), ConjugacyClassSubgroups( s4, Subgroup( s4,
[ (3,4), (1,2) ] ) ), ConjugacyClassSubgroups( s4, Subgroup( s4,
[ (1,2)(3,4), (1,4,2,3) ] ) ),
ConjugacyClassSubgroups( s4, Subgroup( s4, [ (2,3,4), (3,4) ] ) ),
ConjugacyClassSubgroups( s4, Subgroup( s4,
[ (3,4), (1,2), (1,3)(2,4) ] ) ),
ConjugacyClassSubgroups( s4, Subgroup( s4,
[ (1,2)(3,4), (1,3)(2,4), (2,3,4) ] ) ),
ConjugacyClassSubgroups( s4, s4 ) ] ```

Each entry of the resulting list is a domain. As an example, let us take the seventh class in the above list of conjugacy classes of S_4.

```    gap> # Conjugacy classes of subgroups of S4 (continued)
gap> class7 := cl[7];;
gap> # Print the class representative subgroup.
gap> rep7 := Representative( class7 );
Subgroup( s4, [ (1,2)(3,4), (1,4,2,3) ] )
gap> # Print the order of the class representative subgroup.
gap> Size( rep7 );
4
gap> # Print the number of conjugates.
gap> Size( class7 );
3 ```

## 7.74 Lattice

`Lattice( G )`

`Lattice` returns the lattice of subgroups of the group G in the form of a record L, say, which contains certain lists with some appropriate information on the subgroups of G and their conjugacy classes. In particular, in its component `L.classes`, L provides the same list of all conjugacy classes of all subgroups of G as is returned by the `ConjugacyClassesSubgroups` command (see ConjugacyClassesSubgroups).

The construction of the subgroup lattice record L of a group G may be very time consuming. Therefore, as soon as L has been computed for the first time, it will be saved as a component `G.lattice` in the group record G to avoid any duplication of that effort.

The underlying routines are a reimplementation of the subgroup lattice routines which have been developed since 1958 by several people in Kiel and Aachen under the supervision of Joachim Neubaccent127 user. Their final version, written by Volkmar Felsch in 1984, has been available since then in Cayley (see BC92) and has also been used in SOGOS (see Sog89). The current implementation in GAP by Jaccent127 urgen Mnich is described in Mni92, a summary of the method and references to all predecessors can be found in FS84.

The `Lattice` command invokes the following procedure. In a first step, the solvable re-si-du-um P, say, of G is computed and looked up in a built-in catalogue of perfect groups which is given in the file `LIBNAME/"lattperf.g"`. A list of subgroups is read off from that catalogue which contains just one representative of each conjugacy class of perfect subgroups of P and hence at least one representative of each conjugacy class of perfect subgroups of G. Then, starting from the identity subgroup and the conjugacy classes of perfect subgroups, the so called cyclic extension method is used to compute the non-perfect subgroups of G by forming for each class representative all its not yet involved cyclic extensions of prime number index and adding their conjugacy classes to the list.

It is clear that this procedure cannot work if the catalogue of perfect groups does not contain a group isomorphic to P. At present, it contains only all perfect groups of order less than 5000 and, in addition, the groups PSL(3,3), M_{11}, and A_8. If the `Lattice` command is called for a group G with a solvable residuum P not in the catalogue, it will provide an error message. As an example we handle the group SL(2,19) of order 6840.

```    gap> s := [ [4,0], [0,5] ] * Z( 19 )^0;;
gap> t := [ [4,4], [-9,-4] ] * Z(19)^0;;
gap> G := Group( s, t );;
gap> Size( G );
6840
gap> Lattice( G );
Error, sorry, can' t identify the group's solvable residuum ```

However, if you know the perfect subgroups of G, you can use the `Lattice` command to compute the whole subgroup lattice of G even if the solvable residuum of G is not in the catalogue. All you have to do in such a case is to create a list of subgroups of G which contains at least one representative of each conjugacy class of proper perfect subgroups of G, attach this list to the group record as a new component `G.perfectSubgroups`, and then call the `Lattice` command. The existence of that record component will prevent GAP from looking up the solvable residuum of G in the catalogue. Instead, it will insert the given subgroups into the lattice, leaving it to you to guarantee that in fact all conjugacy classes of proper perfect subgroups are involved.

If you miss classes, the resulting lattice will be incomplete, but you will not get any warning. As long as you are aware of this fact, you may use this possibility to compute a sublattice of the subgroup lattice of G without getting the above mentioned error message even if the solvable residuum of G is not in the catalogue. In particular, you will get at least the classes of all proper solvable subgroups of G if you define `G.perfectSubgroups` to be an empty list.

As an example for the computation of the complete lattice of subgroups of a group which is not covered by the catalogue, we handle the Mathieu group M_{12}.

```    gap> # Define the Mathieu group M12.
gap> a := (2,3,5,7,11,9,8,12,10,6,4);;
gap> b := (3,6)(5,8)(9,11)(10,12);;
gap> c := (1,2)(3,4)(5,9)(6,8)(7,12)(10,11);;
gap> M12 := Group( a, b, c );;
gap> Print( "#I  M12 has order ", Size( M12 ), "\n" );
#I  M12 has order 95040
gap> # Define a list of proper perfect subgroups of M_12 and attach
gap> # it to the group record M12 as component M12.perfectSubgroups.
gap> L2_11a := Subgroup( M12, [ a, b ] );;
gap> M11a   := Subgroup( M12, [ a, b, c*a^-1*b*a*c ] );;
gap> M11b   := Subgroup( M12, [ a, b, c*a*b*a^-1*c ] );;
gap> x      := a*b*a^2;;
gap> y      := a*c*a^-1*b*a*c*a^6;;
gap> A6a    := Subgroup( M12, [ x, y ] );;
gap> A5c    := Subgroup( M12, [ x*y, x^3*y^2*x^2*y ] );;
gap> x      := a^2*b*a;;
gap> y      := a^6*c*a*b*a^-1*c*a;;
gap> A6b    := Subgroup( M12, [ x, y ] );;
gap> A5d    := Subgroup( M12, [ x*y, x^3*y^2*x^2*y ] );;
gap> x      := a;;
gap> y      := b*c*b;;
gap> z      := c;;
gap> L2_11b := Subgroup( M12, [ x, y, z ] );;
gap> A5b    := Subgroup( M12, [ y, x*z ] );;
gap> x      := c;;
gap> y      := b*a^-1*c*a*b;;
gap> z      := a^2*b*a^-1*c*a*b*a^-2;;
gap> A5a    := Subgroup( M12, [ (x*z)^2, (y*z)^2 ] );;
gap> M12.perfectSubgroups := [
>   L2_11a, L2_11b, M11a, M11b, A6a, A6b, A5a, A5b, A5c, A5d ];;
gap> # Now compute the subgroup lattice of M12.
gap> lat := Lattice( M12 );
LatticeSubgroups( Group( ( 2, 3, 5, 7,11, 9, 8,12,10, 6, 4), ( 3, 6)
( 5, 8)( 9,11)(10,12), ( 1, 2)( 3, 4)( 5, 9)( 6, 8)( 7,12)(10,11) ) )```

The `Lattice` command returns a record which represents a very complicated structure.

```    gap> # Subgroup lattice of M12 (continued)
gap> RecFields( lat );
[ "isLattice", "classes", "group", "printLevel", "operations" ] ```

Probably the most important component of the lattice record is the list `lat.classes`. Its elements are domains. They are described in section ConjugacyClassesSubgroups. We can use this list, for instance, to print the number of conjugacy classes of subgroups and the number of subgroups of M_{12}.

```    gap> # Subgroup lattice of M12 (continued)
gap> n1 := Length( lat.classes );;
gap> n2 := Sum( [ 1 .. n1 ], i -> Size( lat.classes[i] ) );;
gap> Print( "#I  M12 has ", n1, " classes of altogether ", n2,
>   " subgroups\n" );
#I  M12 has 147 classes of altogether 214871 subgroups ```

It would not make sense to get all components of a subgroup lattice record printed in full detail whenever we ask GAP to print the lattice. Therefore, as you can see in the above example, the default printout is just an expression of the form "`Lattice(,group,)`". However, you can ask GAP to display some additional information in any subsequent printout of the lattice by increasing its individual print level. This print level is stored (in the form of a list of several print flags) in the lattice record and can be changed by an appropriate call of the `SetPrintLevel` indexSetPrintLevel command described below.

The following example demonstrates the effect of the subgroup lattice print level.

```    gap> # Subgroup lattice of S4
gap> s4 := Group( (1,2,3,4), (1,2) );;
gap> lat := Lattice( s4 );
LatticeSubgroups( Group( (1,2,3,4), (1,2) ) ) ```

The default subgroup lattice print level is 0. In this case, the print command provides just the expression mentioned above.

```    gap> # Subgroup lattice of S4 (continued)
gap> SetPrintLevel( lat, 1 );
gap> lat;
#I  class 1, size 1, length 1
#I  class 2, size 2, length 3
#I  class 3, size 2, length 6
#I  class 4, size 3, length 4
#I  class 5, size 4, length 1
#I  class 6, size 4, length 3
#I  class 7, size 4, length 3
#I  class 8, size 6, length 4
#I  class 9, size 8, length 3
#I  class 10, size 12, length 1
#I  class 11, size 24, length 1
LatticeSubgroups( Group( (1,2,3,4), (1,2) ) ) ```

If the print level is set to a value greater than 0, you get, in addition, for each class a kind of heading line. This line contains the position number and the length of the respective class as well as the order of the subgroups in the class.

```    gap> # Subgroup lattice of S4 (continued)
gap> SetPrintLevel( lat, 2 );
gap> lat;
#I  class 1, size 1, length 1
#I    representative [  ]
#I      maximals
#I  class 2, size 2, length 3
#I    representative [ (1,2)(3,4) ]
#I      maximals [ 1, 1 ]
#I  class 3, size 2, length 6
#I    representative [ (3,4) ]
#I      maximals [ 1, 1 ]
#I  class 4, size 3, length 4
#I    representative [ (2,3,4) ]
#I      maximals [ 1, 1 ]
#I  class 5, size 4, length 1
#I    representative [ (1,2)(3,4), (1,3)(2,4) ]
#I      maximals [ 2, 1 ] [ 2, 2 ] [ 2, 3 ]
#I  class 6, size 4, length 3
#I    representative [ (3,4), (1,2) ]
#I      maximals [ 3, 1 ] [ 3, 4 ] [ 2, 1 ]
#I  class 7, size 4, length 3
#I    representative [ (1,2)(3,4), (1,4,2,3) ]
#I      maximals [ 2, 1 ]
#I  class 8, size 6, length 4
#I    representative [ (2,3,4), (3,4) ]
#I      maximals [ 4, 1 ] [ 3, 1 ] [ 3, 2 ] [ 3, 3 ]
#I  class 9, size 8, length 3
#I    representative [ (3,4), (1,2), (1,3)(2,4) ]
#I      maximals [ 7, 1 ] [ 6, 1 ] [ 5, 1 ]
#I  class 10, size 12, length 1
#I    representative [ (1,2)(3,4), (1,3)(2,4), (2,3,4) ]
#I      maximals [ 5, 1 ] [ 4, 1 ] [ 4, 2 ] [ 4, 3 ] [ 4, 4 ]
#I  class 11, size 24, length 1
#I    representative [ (1,2,3,4), (1,2) ]
#I      maximals [ 10, 1 ] [ 9, 1 ] [ 9, 2 ] [ 9, 3 ] [ 8, 1 ]
[ 8, 2 ] [ 8, 3 ] [ 8, 4 ]
LatticeSubgroups( Group( (1,2,3,4), (1,2) ) )
gap> PrintClassSubgroupLattice( lat, 8 );
#I  class 8, size 6, length 4
#I    representative [ (2,3,4), (3,4) ]
#I      maximals [ 4, 1 ] [ 3, 1 ] [ 3, 2 ] [ 3, 3 ] ```

If the subgroup lattice print level is at least 2, GAP prints, in addition, for each class representative subgroup a set of generators and a list of its maximal subgroups, where each maximal subgroup is represented by a pair of integers consisting of its class number and its position number in that class. As this information blows up the output, it may be convenient to restrict it to a particular class. We can do this by calling the `PrintClassSubgroupLattice`

```    gap> # Subgroup lattice of S4 (continued)
gap> SetPrintLevel( lat, 3 );
gap> PrintClassSubgroupLattice( lat, 8 );
#I  class 8, size 6, length 4
#I    representative [ (2,3,4), (3,4) ]
#I      maximals [ 4, 1 ] [ 3, 1 ] [ 3, 2 ] [ 3, 3 ]
#I    conjugate 2 by (1,4,3,2) is [ (1,2,3), (2,3) ]
#I    conjugate 3 by (1,2) is [ (1,3,4), (3,4) ]
#I    conjugate 4 by (1,3)(2,4) is [ (1,2,4), (1,2) ] ```

If the subgroup lattice print level has been set to at least 3, GAP displays, in addition, for each non-representative subgroup of a class its number in the class, an element which transforms the class representative subgroup into that subgroup, and a set of generators.

```    gap> # Subgroup lattice of S4 (continued)
gap> SetPrintLevel( lat, 4 );
gap> PrintClassSubgroupLattice( lat, 8 );
#I  class 8, size 6, length 4
#I    representative [ (2,3,4), (3,4) ]
#I      maximals [ 4, 1 ] [ 3, 1 ] [ 3, 2 ] [ 3, 3 ]
#I    conjugate 2 by (1,4,3,2) is [ (1,2,3), (2,3) ]
#I      maximals [ 4, 2 ] [ 3, 2 ] [ 3, 4 ] [ 3, 5 ]
#I    conjugate 3 by (1,2) is [ (1,3,4), (3,4) ]
#I      maximals [ 4, 3 ] [ 3, 1 ] [ 3, 5 ] [ 3, 6 ]
#I    conjugate 4 by (1,3)(2,4) is [ (1,2,4), (1,2) ]
#I      maximals [ 4, 4 ] [ 3, 4 ] [ 3, 6 ] [ 3, 3 ] ```

A subgroup lattice print level value of at least 4 causes GAP to list the maximal subgroups not only for the class representatives, but also for the other subgroups.

```    gap> # Subgroup lattice of S4 (continued)
gap> SetPrintLevel( lat, 5 );
gap> PrintClassSubgroupLattice( lat, 8 );
#I  class 8, size 6, length 4
#I    representative [ (2,3,4), (3,4) ]
#I      maximals [ 4, 1 ] [ 3, 1 ] [ 3, 2 ] [ 3, 3 ]
#I      minimals [ 11, 1 ]
#I    conjugate 2 by (1,4,3,2) is [ (1,2,3), (2,3) ]
#I      maximals [ 4, 2 ] [ 3, 2 ] [ 3, 4 ] [ 3, 5 ]
#I      minimals [ 11, 1 ]
#I    conjugate 3 by (1,2) is [ (1,3,4), (3,4) ]
#I      maximals [ 4, 3 ] [ 3, 1 ] [ 3, 5 ] [ 3, 6 ]
#I      minimals [ 11, 1 ]
#I    conjugate 4 by (1,3)(2,4) is [ (1,2,4), (1,2) ]
#I      maximals [ 4, 4 ] [ 3, 4 ] [ 3, 6 ] [ 3, 3 ]
#I      minimals [ 11, 1 ] ```

The maximal valid value of the subgroup lattice print level is 5. If it is set, GAP displays not only the maximal subgroups, but also the minimal supergroups of each subgroup. This is the most extensive output of a subgroup lattice record which you can get with the `Print` command, but of course you can use the `RecFields` command (see RecFields) to list all record components and then print them out individually in full detail.

If the computation of some subgroup lattice is very time consuming (as in the above example of the Mathieu group M_{12}), you might wish to see some intermediate printout which informs you about the progress of the computation. In fact, you can get such messages by activating a print mechanism which has been inserted into the subgroup lattice routines for diagnostic purposes. All you have to do is to replace the call

` lat := Lattice( M12 ); `

by the three calls

```    InfoLattice1 := Print;
lat := Lattice( M12 );
InfoLattice1 := Ignore; ```

Note, however, that the final numbering of the conjugacy classes of subgroups will differ from the order in which they occur in the intermediate listing because they will be reordered by increasing subgroup orders at the end of the construction.

`PrintClassSubgroupLattice( lattice, n )`

`PrintClassSubgroupLattice` prints information on the nth conjugacy class of subgroups in the subgroup lattice lattice. The amount of this information depends on the current value of the subgroup lattice print level of lattice. Note that the default of that print level is zero which means that you will not get any output from the `PrintClassSubgroupLattice` command without increasing it (see `SetPrintLevel` below). Examples are given in the above description of the `Lattice` command.

`SetPrintLevel( lattice, level )`

`SetPrintLevel` changes the subgroup lattice print level of the subgroup lattice lattice to the specified value level by an appropriate alteration of the list of print flags which is stored in `lattice.printLevel`. The argument level is expected to be an integer between 0 and 5.

Examples of the effect of the subgroup lattice print level are given in the above description of the `Lattice` command.

## 7.75 ConjugacyClassSubgroups

`ConjugacyClassSubgroups( G, U )`

`ConjugacyClassSubgroups` returns the conjugacy class of the subgroup U in the group G. Signals an error if U is not a subgroup of G. The conjugacy class is returned as a domain, so all set theoretic functions are applicable (see Domains).

```    gap> s5 := Group( (1,2), (1,2,3,4,5) );;  s5.name := "s5";;
gap> a5 := DerivedSubgroup( s5 );
Subgroup( s5, [ (1,2,3), (2,3,4), (3,4,5) ] )
gap> C := ConjugacyClassSubgroups( s5, a5 );
ConjugacyClassSubgroups( s5, Subgroup( s5,
[ (1,2,3), (2,3,4), (3,4,5) ] ) )
gap> Size( C );
1 ```

Another example of such domains is given in section ConjugacyClassesSubgroups.

`ConjugacyClassSubgroups` calls
`G.operations.ConjugacyClassSubgroups( G, U )` and returns this value.

The default function called is `GroupOps.ConjugacyClassSubgroups`, which creates a conjugacy class record (see Subgroup Conjugacy Class Records) Set Functions for Subgroup Conjugacy Classes). Look in the index under ConjugacyClassSubgroups to see for which groups this function is overlaid.

## 7.76 IsConjugacyClassSubgroups

`IsConjugacyClassSubgroups( obj )`

`IsConjugacyClassSubgroups` returns `true` if obj is a conjugacy class of subgroups as created by `ConjugacyClassSubgroups` (see ConjugacyClassSubgroups) and `false` otherwise.

```    gap> s5 := Group( (1,2), (1,2,3,4,5) );;  s5.name := "s5";;
gap> a5 := DerivedSubgroup( s5 );
Subgroup( s5, [ (1,2,3), (2,3,4), (2,4)(3,5) ] )
gap> c := ConjugacyClassSubgroups( s5, a5 );
ConjugacyClassSubgroups( s5, Subgroup( s5,
[ (1,2,3), (2,3,4), (2,4)(3,5) ] ) )
gap> IsConjugacyClassSubgroups( c );
true
gap> IsConjugacyClassSubgroups( [ a5 ] );
false    # even though this is as a set equal to 'c' ```

## 7.77 Set Functions for Subgroup Conjugacy Classes

As mentioned above, conjugacy classes of subgroups are domains, so all set theoretic functions are also are applicable to conjugacy classes (see Domains). This section describes the functions that are implemented especially for conjugacy classes. Functions not mentioned here inherit the default functions mentioned in the respective sections.

`Elements( C )`

The elements of the conjugacy class C with representative U in the group G are computed by first finding a right transversal of the normalizer of U in G and by computing the conjugates of U with the elements in the right transversal.

`V in C`

Membership of a group V is tested by comparing the set of contained cyclic subgroups of prime power order of V with those of the groups in C.

`Size( C )`

The size of the conjugacy class C with representative U in the group G is computed as the index of the normalizer of U in G.

## 7.78 Subgroup Conjugacy Class Records

Each conjugacy class of subgroups C is represented as a record with at least the following components.

`isDomain`:

always `true`, because conjugacy classes of subgroups are domains.

`isConjugacyClassSubgroups`:

as well, this entry is always set to `true`.

`group`:

The group in which the members of this conjugacy class lie. This is not necessarily a parent group; it may also be a subgroup.

`representative`:

The representative of the conjugacy class of subgroups as domain.

The following components are optional and may be bound by some functions which compute or make use of their value.

`normalizer`:

The normalizer of `C.representative` in `C.group`.

`normalizerLattice`:

A special entry that is used when the conjugacy classes of subgroups are computed by `ConjugacyClassesSubgroups`. It determines the normalizer of the subgroup `C.representative`. It is a list of length 2. The first element is another conjugacy class D (in the same group), the second is an element g in `C.group`. The normalizer of `C.representative` is then `D.representative ^ g`.

`conjugands`:

A right transversal of the normalizer of `C.representative` in `C.group`. Thus the elements of the class C can be computed by conjugating `C.representative` with those elements.

## 7.79 ConjugacyClassesMaximalSubgroups

`ConjugacyClassesMaximalSubgroups( G )`

`ConjugacyClassesMaximalSubgroups` returns a list of conjugacy classes of maximal subgroups of the group G.

A subgroup H of G is maximal if H is a proper subgroup and for all subgroups I of G with H < I leq G the equality I = G holds.

```    gap> s4 := SymmetricGroup( AgWords, 4 );;
gap> ss4 := SpecialAgGroup( s4 );;
gap> ConjugacyClassesMaximalSubgroups( ss4 );
[ ConjugacyClassSubgroups( Group( g1, g2, g3, g4 ), Subgroup( Group(
g1, g2, g3, g4 ), [ g2, g3, g4 ] ) ),
ConjugacyClassSubgroups( Group( g1, g2, g3, g4 ), Subgroup( Group(
g1, g2, g3, g4 ), [ g1, g3, g4 ] ) ),
ConjugacyClassSubgroups( Group( g1, g2, g3, g4 ), Subgroup( Group(
g1, g2, g3, g4 ), [ g1, g2 ] ) ) ]```

The generic method computes the entire lattice of conjugacy classes of subgroups (see Lattice) and returns the maximal ones.

`MaximalSubgroups` (see MaximalSubgroups) computes the list of all maximal subgroups.

## 7.80 MaximalSubgroups

`MaximalSubgroups( G )`

MaximalSubgroups calculates all maximal subroups of the special ag group G.

```    gap> s4 := SymmetricGroup( AgWords, 4 );;
gap> ss4 := SpecialAgGroup( s4 );;
gap> MaximalSubgroups( ss4 );
[ Subgroup( Group( g1, g2, g3, g4 ), [ g2, g3, g4 ] ),
Subgroup( Group( g1, g2, g3, g4 ), [ g1, g3, g4 ] ),
Subgroup( Group( g1, g2, g3, g4 ), [ g1*g2^2, g3, g4 ] ),
Subgroup( Group( g1, g2, g3, g4 ), [ g1*g2, g3, g4 ] ),
Subgroup( Group( g1, g2, g3, g4 ), [ g1, g2 ] ),
Subgroup( Group( g1, g2, g3, g4 ), [ g1, g2*g3*g4 ] ),
Subgroup( Group( g1, g2, g3, g4 ), [ g1*g4, g2*g4 ] ),
Subgroup( Group( g1, g2, g3, g4 ), [ g1*g4, g2*g3 ] ) ]  ```

`ConjugacyClassesMaximalSubgroups` (see ConjugacyClassesMaximalSubgroups) computes the list of conjugacy classes of maximal subgroups.

## 7.81 NormalSubgroups

`NormalSubgroups( G )`

`NormalSubgroups` returns a list of all normal subgroups of G. The subgroups are sorted according to their sizes.

```    gap> s4 := Group( (1,2,3,4), (1,2) );; s4.name := "s4";;
gap> NormalSubgroups( s4 );
[ Subgroup( s4, [  ] ), Subgroup( s4, [ (1,2)(3,4), (1,4)(2,3) ] ),
Subgroup( s4, [ (2,3,4), (1,3,4) ] ),
Subgroup( s4, [ (3,4), (1,4), (1,2,4) ] ) ] ```

The default function `GroupOps.NormalSubgroups` uses the conjugacy classes of G and normal closures in order to compute the normal subgroups.

## 7.82 ConjugateSubgroups

`ConjugateSubgroups( G, U )`

`ConjugateSubgroups` returns the orbit of U under G acting by conjugation (see ConjugateSubgroup) as list of subgroups. U and G must have a common parent group.

```    gap> s4 := Group( (1,2,3,4), (1,2) );
Group( (1,2,3,4), (1,2) )
gap> s3 := Subgroup( s4, [ (1,2,3), (1,2) ] );
Subgroup( Group( (1,2,3,4), (1,2) ), [ (1,2,3), (1,2) ] )
gap> ConjugateSubgroups( s4, s3 );
[ Subgroup( Group( (1,2,3,4), (1,2) ), [ (1,2,3), (1,2) ] ),
Subgroup( Group( (1,2,3,4), (1,2) ), [ (2,3,4), (2,3) ] ),
Subgroup( Group( (1,2,3,4), (1,2) ), [ (1,3,4), (3,4) ] ),
Subgroup( Group( (1,2,3,4), (1,2) ), [ (1,2,4), (1,4) ] ) ] ```

## 7.83 Cosets of Subgroups

The following sections describe how one can compute the right, left, and double cosets of subgroups (see RightCosets, LeftCosets, DoubleCosets). Further sections describe how cosets are created (see RightCoset, IsRightCoset, LeftCoset, IsLeftCoset, DoubleCoset, Set Functions for Right Cosets, Right Cosets Records, Set Functions for Double Cosets, and Double Coset Records).

A coset is a GAP domain, which is different from a group. Altough the set of elements of a group and its trivial coset are equal, the group functions do not take trivial cosets as arguments. A trivial coset must be convert into a group using `AsGroup` (see AsGroup) in order to be used as group.

## 7.84 RightCosets

`Cosets( G, U )`
`RightCosets( G, U )`

`Cosets` and `RightCosets` return a list of the right cosets of the subgroup U in the group G. The list is not sorted, i.e., the right cosets may appear in any order. The right cosets are domains as constructed by `RightCoset` (see RightCoset).

```    gap> G := Group( (1,2), (1,2,3,4) );;
gap> G.name := "G";;
gap> U := Subgroup( G, [ (1,2), (3,4) ] );;
gap> RightCosets( G, U );
[ (Subgroup( G, [ (1,2), (3,4) ] )*()),
(Subgroup( G, [ (1,2), (3,4) ] )*(2,4,3)),
(Subgroup( G, [ (1,2), (3,4) ] )*(2,3)),
(Subgroup( G, [ (1,2), (3,4) ] )*(1,2,4,3)),
(Subgroup( G, [ (1,2), (3,4) ] )*(1,2,3)),
(Subgroup( G, [ (1,2), (3,4) ] )*(1,3)(2,4)) ] ```

If G is the parent of U, the dispatcher `RightCosets` first checks whether U has a component `rightCosets`. If U has this component, it returns that value. Otherwise it calls `G.operations.RightCosets(G,U)`, remembers the returned value in `U.rightCosets` and returns it. If G is not the parent of U, `RightCosets` directly calls the function `G.operations.RightCosets(G,U)` and returns that value.

The default function called this way is `GroupOps.RightCosets`, which calls `Orbit( G, RightCoset( U ), OnRight )`. Look up `RightCosets` in the index, to see for which groups this function is overlaid.

## 7.85 RightCoset

`U * u`
`Coset( U, u )`
`RightCoset( U, u )`
`Coset( U )`
`RightCoset( U )`

The first three forms return the right coset of the subgroup U with the representative u. u must lie in the parent group of U, otherwise an error is signalled. In the last two forms the right coset of U with the identity element of the parent of U as representative is returned. In each case the right coset is returned as a domain, so all domain functions are applicable to right cosets (see chapter Domains and Set Functions for Right Cosets).

```    gap> G := Group( (1,2), (1,2,3,4) );;
gap> U := Subgroup( G, [ (1,2), (3,4) ] );;
gap> U * (1,2,3);
(Subgroup( Group( (1,2), (1,2,3,4) ), [ (1,2), (3,4) ] )*(1,2,3)) ```

`RightCosets` (see RightCosets) computes the set of all right cosets of a subgroup in a group. `LeftCoset` (see LeftCoset) constructs left cosets.

`RightCoset` calls `U.operations.RightCoset( U, u )` and returns that value.

The default function called this way is `GroupOps.RightCoset`, which creates a right coset record (see Right Cosets Records) with the Set Functions for Right Cosets). Look up the entries for `RightCoset` in the index to see for which groups this function is overlaid.

## 7.86 IsRightCoset

`IsRightCoset( obj )`
`IsCoset( obj )`

`IsRightCoset` and `IsCoset` return `true` if the object obj is a right coset, i.e., a record with the component `isRightCoset` with value `true`, and `false` otherwise. Will signal an error if obj is an unbound variable.

```    gap> C := Subgroup( Group( (1,2), (1,2,3) ), [ (1,2,3) ] ) * (1,2);;
gap> IsRightCoset( C );
true
gap> D := (1,2) * Subgroup( Group( (1,2), (1,2,3) ), [ (1,2,3) ] );;
gap> IsCoset( D );
false    # note that <D> is a *left coset* record,
gap> C = D;
true     # though as a set, it is of course also a right coset
gap> IsCoset( 17 );
false ```

## 7.87 Set Functions for Right Cosets

Right cosets are domains, thus all set theoretic functions are applicable to cosets (see chapter Domains). The following describes the functions that are implemented especially for right cosets. Functions not mentioned here inherit the default function mentioned in the respective sections.

More technically speaking, all right cosets of generic groups have the operations record `RightCosetGroupOps`, which inherits its functions from `DomainOps` and overlays the components mentioned below with more efficient functions.

In the following let C be the coset `U * u`.

`Elements( C )`

To compute the proper set of elements of a right coset C the proper set of elements of the subgroup U is computed, each element is multiplied by u, and the result is sorted.

`IsFinite( C )`

This returns the result of applying `IsFinite` to the subgroup U.

`Size( C )`

This returns the result of applying `Size` to the subgroup U.

`C = D`

If C and D are both right cosets of the same subgroup, `=` returns `true` if the quotient of the representatives lies in the subgroup U, otherwise the test is delegated to `DomainOps.=`.

`h in U`

If h is an element of the parent group of U, this returns `true` if the quotient `h / u` lies in the subgroup U, otherwise the test is delegated to `DomainOps.in`.

`Intersection( C, D )`

If C and D are both right cosets of subgroups U and V with the same parent group the result is a right coset of the intersection of U and V. The representative is found by a random search for a common element. In other cases the computation of the intersection is delegated to `DomainOps.Intersection`.

`Random( C )`

This takes a random element of the subgroup U and returns the product of this element by the representative u.

`Print( C )`

A right coset C is printed as `(U * u)` (the parenthesis are used to avoid confusion about the precedence, which could occur if the coset is part of a larger object).

`C * v`

If v is an element of the parent group of the subgroup U, the result is a new right coset of U with representative `u * v`. Otherwise the result is obtained by multiplying the proper set of elements of C with the element v, which may signal an error.

`v * C`

The result is obtained by multiplying the proper set of elements of the coset C with the element v, which may signal an error.

## 7.88 Right Cosets Records

A right coset is represented by a domain record with the following tag components.

`isDomain`:

always `true`.

`isRightCoset`:

always `true`.

The right coset is determined by the following identity components, which every right coset record has.

`group`:

the subgroup U of which this right coset is a right coset.

`representative`:

an element of the right coset. It is unspecified which element.

In addition, a right coset record may have the following optional information components.

`elements`:

if present the proper set of elements of the coset.

`isFinite`:

if present this is `true` if the coset is finite, and `false` if the coset is infinite. If not present it is not known whether the coset is finite or infinite.

`size`:

if present the size of the coset. Is "infinity" if the coset is infinite. If not present the size of the coset is not known.

## 7.89 LeftCosets

`LeftCosets( G, U )`

`LeftCosets` returns a list of the left cosets of the subgroup U in the group G. The list is not sorted, i.e., the left cosets may appear in any order. The left cosets are domains as constructed by `LeftCosets` (see LeftCosets).

```    gap> G := Group( (1,2), (1,2,3,4) );;
gap> G.name := "G";;
gap> U := Subgroup( G, [ (1,2), (3,4) ] );;
gap> LeftCosets( G, U );
[ (()*Subgroup( G, [ (1,2), (3,4) ] )),
((2,3,4)*Subgroup( G, [ (1,2), (3,4) ] )),
((2,3)*Subgroup( G, [ (1,2), (3,4) ] )),
((1,3,4,2)*Subgroup( G, [ (1,2), (3,4) ] )),
((1,3,2)*Subgroup( G, [ (1,2), (3,4) ] )),
((1,3)(2,4)*Subgroup( G, [ (1,2), (3,4) ] )) ] ```

If G is the parent of U, the dispatcher `LeftCosets` first checks whether U has a component `leftCosets`. If U has this component, it returns that value. Otherwise `LeftCosets` calls `G.operations.LeftCosets(G,U)`, remembers the returned value in `U.leftCosets` and returns it. If G is not the parent of U, `LeftCosets` calls `G.operations.LeftCosets(G,U)` directly and returns that value.

The default function called this way is `GroupOps.LeftCosets`, which calls `RightCosets( G, U )` and turns each right coset `U * u` into the left coset `u^-1 * U`. Look up the entries for `LeftCosets` in the index, to see for which groups this function is overlaid.

## 7.90 LeftCoset

`u * U`
`LeftCoset( U, u )`
`LeftCoset( U )`

`LeftCoset` is exactly like `RightCoset`, except that it constructs left cosets instead of right cosets. So everything that applies to `RightCoset` applies also to `LeftCoset`, with right replaced by left Right Cosets Records).

```    gap> G := Group( (1,2), (1,2,3,4) );;
gap> U := Subgroup( G, [ (1,2), (3,4) ] );;
gap> (1,2,3) * U;
((1,2,3)*Subgroup( Group( (1,2), (1,2,3,4) ), [ (1,2), (3,4) ] )) ```

`LeftCosets` (see LeftCosets) computes the set of all left cosets of a subgroup in a group.

## 7.91 IsLeftCoset

`IsLeftCoset( obj )`

`IsLeftCoset` returns `true` if the object obj is a left coset, i.e., a record with the component `isLeftCoset` with value `true`, and `false` otherwise. Will signal an error if obj is an unbound variable.

```    gap> C := (1,2) * Subgroup( Group( (1,2), (1,2,3) ), [ (1,2,3) ] );;
gap> IsLeftCoset( C );
true
gap> D := Subgroup( Group( (1,2), (1,2,3) ), [ (1,2,3) ] ) * (1,2);;
gap> IsLeftCoset( D );
false    # note that <D> is a *right coset* record,
gap> C = D;
true     # though as a set, it is of course also a left coset
gap> IsLeftCoset( 17 );
false ```

`IsRightCoset` (see IsRightCoset) tests if an object is a right coset.

## 7.92 DoubleCosets

`DoubleCosets( G, U, V )`

`DoubleCosets` returns a list of the double cosets of the subgroups U and V in the group G. The three groups G, U and V must have a common parent. The list is not sorted, i.e., the double cosets may appear in any order. The double cosets are domains as constructed by `DoubleCoset` (see DoubleCoset).

```    gap> G := Group( (1,2), (1,2,3,4) );;
gap> U := Subgroup( G, [ (1,2), (3,4) ] );;  U.name := "U";;
gap> DoubleCosets( G, U, U );
[ DoubleCoset( U, (), U ), DoubleCoset( U, (2,3), U ),
DoubleCoset( U, (1,3)(2,4), U ) ] ```

`DoubleCosets` calls `G.operations.DoubleCoset( G, U, V )` and returns that value.

The default function called this way is `GroupOps.DoubleCosets`, which takes random elements from G, tests if this element lies in one of the already found double cosets, adds the double coset if this is not the case, and continues this until the sum of the sizes of the found double cosets equals the size of G. Look up `DoubleCosets` in the index, to see for which groups this function is overlaid.

## 7.93 DoubleCoset

`DoubleCoset( U, u, V )`

`DoubleCoset` returns the double coset with representative u and left group U and right group V. U and V must have a common parent and u must lie in this parent, otherwise an error is signaled. Double cosets are domains, so all domain function are applicable to double cosets (see chapter Domains and Set Functions for Double Cosets).

```    gap> G := Group( (1,2), (1,2,3,4) );;
gap> U := Subgroup( G, [ (1,2), (3,4) ] );;
gap> D := DoubleCoset( U, (1,2,3), U );
DoubleCoset( Subgroup( Group( (1,2), (1,2,3,4) ), [ (1,2), (3,4) ] ),
(1,2,3), Subgroup( Group( (1,2), (1,2,3,4) ), [ (1,2), (3,4) ] ) )
gap> Size( D );
16 ```

`DoubleCosets` (see DoubleCosets) computes the set of all double cosets of two subgroups in a group.

`DoubleCoset` calls `U.operations.DoubleCoset(U,u,V)` and returns that value.

The default function called this way is `GroupOps.DoubleCoset`, which creates a double coset record (see Double Coset Records) with the Set Functions for Double Cosets). Look up `DoubleCosets` in the index to see for which groups this function is overlaid.

## 7.94 IsDoubleCoset

`IsDoubleCoset( obj )`

`IsDoubleCoset` returns `true` if the object obj is a double coset, i.e., a record with the component `isDoubleCoset` with value `true`, and `false` otherwise. Will signal an error if obj is an unbound variable.

```    gap> G := Group( (1,2), (1,2,3,4) );;
gap> U := Subgroup( G, [ (1,2), (3,4) ] );;
gap> D := DoubleCoset( U, (1,2,3), U );;
gap> IsDoubleCoset( D );
true ```

## 7.95 Set Functions for Double Cosets

Double cosets are domains, thus all set theoretic functions are applicable to double cosets (see chapter Domains). The following describes the functions that are implemented especially for double cosets. Functions not mentioned here inherit the default functions mentioned in the respective sections.

More technically speaking, double cosets of generic groups have the operations record `DoubleCosetGroupOps`, which inherits its functions from `DomainOps` and overlays the components mentioned below with more efficient functions.

Most functions below use the component `D.rightCosets` that contains a list of right cosets of the left group U whose union is this double coset. If this component is unbound they will compute it by computing the orbit of the right group V on the right coset `U * u`, where Double Coset Records).

`Elements( D )`

To compute the proper set of elements the union of the right cosets `D.rightCosets` is computed.

`IsFinite( D )`

This returns the result of `IsFinite( U ) and IsFinite( V )`.

`Size( D )`

This returns the size of the left group U times the number of cosets in `D.rightCosets`.

`C = D`

If C and D are both double cosets with the same left and right groups this returns the result of testing whether the representative of C lies in D. In other cases the test is delegated to `DomainOps.=`.

`g in D`

If g is an element of the parent group of the left and right group of D, this returns `true` if g lies in one of the right cosets in `D.rightCosets`. In other cases the the test is delegated to `DomainOps.in`.

`Intersection( C, D )`

If C and D are both double cosets that are equal, this returns C. If C and D are both double cosets with the same left and right groups that are not equal, this returns `[]`. In all other cases the computation is delegated to `DomainsOps.Intersection`.

`Random( D )`

This takes a random right coset from `D.rightCosets` and returns the result of applying `Random` to this right coset.

`Print( D )`

This prints the double coset in the form `DoubleCoset( U, u, V )`.

`D * g` `g * D`

Those returns the result of multiplying the proper set of element of D with the element g, which may signal an error.

## 7.96 Double Coset Records

A double coset is represented by a domain record with the following tag components.

`isDomain`:

always `true`.

`isDoubleCoset`:

always `true`.

The double coset is determined by the following identity components, which every double coset must have.

`leftGroup`:

the left subgroup U.

`rightGroup`:

the right subgroup V.

`representative`:

an element of the double coset. It is unspecified which element.

In addition, a double coset record may have the following optional information components.

`rightCosets`:

a list of disjoint right cosets of the left subgroup U, whose union is the double coset.

`elements`:

if present the proper set of elements of the double coset.

`isFinite`:

if present this is `true` if the double coset is finite and `false` if the double coset is infinite. If not present it is not known whether the double coset is finite or infinite.

`size`:

if present the size of the double coset. Is "infinity" if the coset is infinite. If not present the size of the double coset is not known.

## 7.97 Group Constructions

The following functions construct new parent groups from given groups (see DirectProduct, SemidirectProduct, SubdirectProduct and WreathProduct).

## 7.98 DirectProduct

`DirectProduct( G_1, ..., G_n )`

`DirectProduct` returns a group record of the direct product D of the groups G_1, ...., G_n which need not to have a common parent group, it is even possible to construct the direct product of an ag group with a permutation group.

Note that the elements of the direct product may be just represented as records. But more complicate constructions, as for instance installing a new collector, may be used. The choice of method strongly depends on the type of group arguments.

`Embedding( U, D, i )`

Let U be a subgroup of G_<i>. `Embedding` returns a homomorphism of U into D which describes the embedding of U in D.

`Projection( D, U, i )`

Let U be a supergroup of G_<i>. `Projection` returns a homomorphism of D into U which describes the projection of D onto G_<i>.

```    gap> s4 := Group( (1,2,3,4), (1,2) );
Group( (1,2,3,4), (1,2) )
gap> S4 := AgGroup( s4 );
Group( g1, g2, g3, g4 )
gap> D := DirectProduct( s4, S4 );
Group( DirectProductElement(
(1,2,3,4), IdAgWord ), DirectProductElement(
(1,2), IdAgWord ), DirectProductElement( (),
g1 ), DirectProductElement( (), g2 ), DirectProductElement( (),
g3 ), DirectProductElement( (), g4 ) )
gap> pr := Projection( D, s4, 1 );;
gap> Image( pr );
Group( (1,2,3,4), (1,2) ) ```

## 7.99 DirectProduct for Groups

`GroupOps.DirectProduct( L )`

Let L be a list of groups G_1, ..., G_n. Then a group element g of the direct product D is represented as record containing the following components.

`element`:

a list g_1 in G_1, ..., g_n in G_n describing g.

`domain`:

contains `GroupElements`.

`isGroupElement`:

contains `true`.

`isDirectProductElement`:

contains `true`.

`operations`:

contains the operations record `DirectProductElementOps` (see Domain).

## 7.100 SemidirectProduct

`SemidirectProduct( G, a, H )`

`SemidirectProduct` returns the semidirect product of G with H. a must be a homomorphism that from G onto a group A that operates on H via the caret (`^`) operator. A may either be a subgroup of the parent group of H that normalizes H, or a subgroup of the Group Homomorphisms).

The semidirect product of G and H is a the group of pairs (g,h) with g in G and h in H, where the product of (g_1,h_1) (g_2,h_2) is defined as (g_1 g_2, h_1^{g_2^a} h_2). Note that the elements (1_G,h) form a normal subgroup in the semidirect product.

`Embedding( U, S, 1 )`

Let U be a subgroup of G. `Embedding` returns the homomorphism of U into the semidirect product S where u is mapped to `(u,1)`.

`Embedding( U, S, 2 )`

Let U be a subgroup of H. `Embedding` returns the homomorphism of U into the semidirect product S where u is mapped to `(1,u)`.

`Projection( S, G, 1 )`

`Projection` returns the homomorphism of S onto G, where `(g,h)` is mapped to g.

`Projection( S, H, 2 )`

`Projection` returns the homomorphism of S onto H, where `(g,h)` is mapped to h.

It is not specified how the elements of the semidirect product are represented. Thus `Embedding` and `Projection` are the only general possibility to relate G and H with the semidirect product.

```    gap> s4 := Group( (1,2), (1,2,3,4) );;  s4.name := "s4";;
gap> s3 := Subgroup( s4, [ (1,2), (1,2,3) ] );; s3.name := "s3";;
gap> a4 := Subgroup( s4, [ (1,2,3), (2,3,4) ] );;  a4.name := "a4";;
gap> a := IdentityMapping( s3 );;
gap> s := SemidirectProduct( s3, a, a4 );
Group( SemidirectProductElement( (1,2),
(1,2), () ), SemidirectProductElement( (1,2,3),
(1,2,3), () ), SemidirectProductElement( (), (),
(1,2,3) ), SemidirectProductElement( (), (), (2,3,4) ) )
gap> Size( s );
72 ```

Note that the three arguments of `SemidirectProductElement` are the element g, its image under a, and the element h.

`SemidirectProduct` calls the function `G.operations.SemidirectProduct` with the arguments G, a, and H, and returns the result.

The default function called this way is `GroupOps.SemidirectProduct`. This function constructs the semidirect product as a group of semidirect product elements (see SemidirectProduct for Groups). Look in the index under SemidirectProduct to see for which groups this function is overlaid.

## 7.101 SemidirectProduct for Groups

The function `GroupOps.SemidirectProduct` constructs the semidirect product as a group of semidirect product elements. In the following let G, a, and H be the arguments of `SemidirectProduct`.

Each such element `(g,h)` is represented by a record with the following components.

`element`:

the list `[ g, h ]`.

`automorphism`:

contains the image of g under a.

`isGroupElement`:

always `true`.

`isSemidirectProductElement`:

always `true`.

`domain`:

contains `GroupElements`.

`operations`:

contains the operations record `SemidirectProductOps`.

The operations of semidirect product elements in done in the obvious way.

## 7.102 SubdirectProduct

`SubdirectProduct( G1, G2, h1, h2 )`

`SubdirectProduct` returns the subdirect product of the groups G1 and G2. h1 and h2 must be homomorphisms from G1 and G2 into a common group H.

The subdirect product of G_1 and G_2 is the subgroup of the direct product of G_1 and G_2 of those elements (g_1,g_2) with g_1^{h_1} = g_2^{h_2}. This subgroup is generated by the elements (g_1,x_{g_1}), where g_1 loops over the generators of G_1 and x_{g_1} in G_2 is an arbitrary element such that g_1^{h_1} = x_{g_1}^{h_2} together with the element (1_G,k_2) where k_2 loops over the generators of the kernel of h_2.

`Projection( S, G1, 1 )`

`Projection` returns the projection of S onto G1, where `(g1,g2)` is mapped to g1.

`Projection( S, G2, 2 )`

`Projection` returns the projection of S onto G2, where `(g1,g2)` is mapped to g2.

It is not specified how the elements of the subdirect product are represented. Therefor `Projection` is the only general possibility to relate G1 and G2 with the subdirect product.

```    gap> s3 := Group( (1,2,3), (1,2) );;
gap> c3 := Subgroup( s3, [ (1,2,3) ] );;
gap> x1 := Operation( s3, Cosets( s3, c3 ), OnRight );;
gap> h1 := OperationHomomorphism( s3, x1 );;
gap> d8 := Group( (1,2,3,4), (2,4) );;
gap> c4 := Subgroup( d8, [ (1,2,3,4) ] );;
gap> x2 := Operation( d8, Cosets( d8, c4 ), OnRight );;
gap> h2 := OperationHomomorphism( d8, x2 );;
gap> s := SubdirectProduct( s3, d8, h1, h2 );
Group( (1,2,3), (1,2)(5,7), (4,5,6,7) )
gap> Size( s );
24 ```

`SubdirectProduct` calls the function `G1.operations.SubdirectProduct` with the arguments G1, G2, h1, and h2.

The default function called this way is `GroupOps.SubdirectProduct`. This function constructs the subdirect product as a subgroup of the direct product. The generators for this subgroup are computed as described above.

## 7.103 WreathProduct

`WreathProduct( G, H )`
`WreathProduct( G, H, alpha )`

In the first form of `WreathProduct` the right regular permutation representation of H on its elements is used as the homomorphism alpha. In the second form alpha must be a homomorphism of H into a permutation group. Let d be the degree of the range of alpha. Then `WreathProduct` returns the wreath product of G by H with respect to alpha, that is the semi-direct product of the direct product of d copies of G which are permuted by H through application of alpha to H.

```    gap> s3 := Group( (1,2,3), (1,2) );
Group( (1,2,3), (1,2) )
gap> z2 := CyclicGroup( AgWords, 2 );
Group( c2 )
gap> f := IdentityMapping( s3 );
IdentityMapping( Group( (1,2,3), (1,2) ) )
gap> w := WreathProduct( z2, s3, f );
Group( WreathProductElement(
c2, IdAgWord, IdAgWord, (), () ), WreathProductElement( IdAgWord,
c2, IdAgWord, (), () ), WreathProductElement( IdAgWord, IdAgWord,
c2, (), () ), WreathProductElement( IdAgWord, IdAgWord, IdAgWord,
(1,2,3),
(1,2,3) ), WreathProductElement( IdAgWord, IdAgWord, IdAgWord, (1,2),
(1,2) ) )
gap> Factors( Size( w ) );
[ 2, 2, 2, 2, 3 ] ```

## 7.104 WreathProduct for Groups

`GroupOps.WreathProduct( G, H, alpha )`

Let d be the degree of `alpha.range`. A group element of the wreath product W is represented as a record containing the following components.

`element`:

a list of d elements of G followed by an element h of H.

`permutation`:

the image of h under alpha.

`domain`:

contains `GroupElements`.

`isGroupElement`:

contains `true`.

`isWreathProductElement`:

contains `true`.

`operations`:

contains the operations record `WreathProductElementOps` (see Domain).

## 7.105 Group Homomorphisms

Since groups is probably the most important category of domains in GAP group homomorphisms are probably the most important homomorphisms (see chapter Homomorphisms)

A group homomorphism phi is a mapping that maps each element of a group G, called the source of phi, to an element of another group H, called the range of phi, such that for each pair x, y in G we have (xy)^phi = x^phi y^phi.

Examples of group homomorphisms are the natural homomorphism of a group into a factor group (see NaturalHomomorphism) and the homomorphism of a group into a symmetric group defined by an operation (see OperationHomomorphism). Look under group homomorphisms in the index for a list of all available group homomorphisms.

Since group homomorphisms are just a special case of homomorphisms, all functions described in chapter Homomorphisms are applicable to all group homomorphisms, e.g., the function to test if a homomorphism is an automorphism (see IsAutomorphism). More general, since group homomorphisms are just a special case of mappings all functions described in chapter Mappings are also applicable, e.g., the function to compute the image of an element under a group homomorphism (see Image).

The following sections describe the functions that test whether a mapping is a group homomorphism (see IsGroupHomomorphism), compute the kernel of a group homomorphism (see KernelGroupHomomorphism), how the general Mapping Functions for Group Homomorphisms), the natural homomorphism of a group onto a factor group (see NaturalHomomorphism), homomorphisms by conjugation (see ConjugationGroupHomomorphism, InnerAutomorphism), and the most general group homomorphism, which is defined by simply specifying the images of a set of generators (see GroupHomomorphismByImages).

## 7.106 IsGroupHomomorphism

`IsGroupHomomorphism( map )`

`IsGroupHomomorphism` returns `true` if the function map is a group homomorphism and `false` otherwise. Signals an error if map is a multi value mapping.

A mapping map is a group homomorphism if its source G and range H are both groups and if for every pair of elements x, y in G it holds that (x y)^{map} = x^{map} y^{map}.

```    gap> s4 := Group( (1,2), (1,2,3,4) );;
gap> v4 := Subgroup( s4, [ (1,2)(3,4), (1,3)(2,4) ] );;
gap> phi := NaturalHomomorphism( s4, s4/v4 );;
gap> IsGroupHomomorphism( phi );
true
gap> IsHomomorphism( phi );
true    # since the source is a group this is equivalent to the above
gap> IsGroupHomomorphism( FrobeniusAutomorphism( GF(16) ) );
false   # it is a field automorphism ```

`IsGroupHomomorphism` first tests if the flag `map.isGroupHomomorphism` is bound. If the flag is bound, `IsGroupHomomorphism` returns its value. Otherwise it calls
`map.source.operations.IsGroupHomomorphism( map )`, remembers the returned value in `map.isGroupHomomorphism`, and returns it. Note that of course all functions that create group homomorphisms set the flag `map.isGroupHomomorphism` to `true`, so that no function is called for those group homomorphisms.

The default function called this way is `MappingOps.IsGroupHomomorphism`. It computes all the elements of the source of map and for each such element x and each generator y tests whether (xy)^{map} = x^{map} y^{map}. Look under IsHomomorphism in the index to see for which mappings this function is overlaid.

## 7.107 KernelGroupHomomorphism

`KernelGroupHomomorphism( hom )`

`KernelGroupHomomorphism` returns the kernel of the group homomorphism hom as a subgroup of the group `hom.source`.

The kernel of a group homomorphism hom is the subset of elements x of the source G that are mapped to the identity of the range H, i.e., x^{hom} = H.identity.

```    gap> s4 := Group( (1,2), (1,2,3,4) );;
gap> v4 := Subgroup( s4, [ (1,2)(3,4), (1,3)(2,4) ] );;
gap> phi := NaturalHomomorphism( s4, s4/v4 );;
gap> KernelGroupHomomorphism( phi );
Subgroup( Group( (1,2), (1,2,3,4) ), [ (1,2)(3,4), (1,3)(2,4) ] )
gap> Kernel( phi );
Subgroup( Group( (1,2), (1,2,3,4) ), [ (1,2)(3,4), (1,3)(2,4) ] )
# since the source is a group this is equivalent to the above
gap> rho := GroupHomomorphismByImages( s4, Group( (1,2) ),
>                          [ (1,2), (1,2,3,4) ], [ (1,2), (1,2) ] );;
gap> Kernel( rho );
Subgroup( Group( (1,2), (1,2,3,4) ), [ (2,4,3), (1,4,3) ] ) ```

`KernelGroupHomomorphism` first tests if `hom.kernelGroupHomomorphism` is bound. If it is bound, `KernelGroupHomomorphisms` returns that value. Otherwise it calls
`hom.operations.KernelGroupHomomorphism( hom )`, remembers the returned value in `hom.kernelGroupHomomorphism`, and returns it.

The default function for this is `MappingOps.KernelGroupHomomorphism`, which simply tries random elements of the source of hom, until the subgroup generated by those that map to the identity has the correct size, i.e., `Size( hom.source ) / Size( Image( hom ) )`. Note that this implies that the image of hom and its size are computed. Look under Kernel in the index to see for which group homomorphisms this function is overlaid.

## 7.108 Mapping Functions for Group Homomorphisms

This section describes how the mapping functions defined in chapter Mappings are implemented for group homomorphisms. Those functions not mentioned here are implemented by the default functions described in the respective sections.

`IsInjective( hom )`

The group homomorphism hom is injective if the kernel of hom `KernelGroupHomomorphism( hom )` (see KernelGroupHomomorphism) is trivial.

`IsSurjective( hom )`

The group homomorphism hom is surjective if the size of the image `Size( Image( hom ) )` (see Image and below) is equal to the size of the range `Size( hom.range )`.

`hom1 = hom2`

The two group homomorphisms hom1 and hom2 are equal if the have the same source and range and if the images of the generators of the source under hom1 and hom2 are equal.

`hom1 < hom2`

By definition hom1 is smaller than hom2 if either the source of hom1 is smaller than the source of hom2, or, if the sources are equal, if the range of hom1 is smaller than the range of hom2, or, if sources and ranges are equal, the image of the smallest element x of the source for that the images are not equal under hom1 is smaller than the image under hom2. Therefor `GroupHomomorphismOps.<` first compares the sources and the ranges. For group homomorphisms with equal sources and ranges only the images of the smallest irredundant generating system are compared. A generating system g_1, g_2, ..., g_n is called irredundant if no g_i lies in the subgroup generated by g_1, ..., g_{i-1}. The smallest irredundant generating system is simply the smallest such generating system with respect to the lexicographical ordering.

`Image( hom )` `Image( hom, H )`
`Images( hom, H )`

The image of a subgroup under a group homomorphism is computed by computing the images of a set of generators of the subgroup, and the result is the subgroup generated by those images.

`PreImages( hom, elm )`

The preimages of an element under a group homomorphism are computed by computing a representative with `PreImagesRepresentative( hom, elm )` and the result is the coset of `Kernel( hom )` containing this representative.

`PreImage( hom )` `PreImage( hom, H )`
`PreImages( hom, H )`

The preimages of a subgroup under a group homomorphism are computed by computing representatives of the preimages of all the generators of the subgroup, adding the generators of the kernel of hom, and the result is the subgroup generated by those elements.

Look under IsInjective, IsSurjective, equality, ordering, Image, Images, PreImage, and PreImages in the index to see for which group homomorphisms these functions are overlaid.

## 7.109 NaturalHomomorphism

`NaturalHomomorphism( G, F )`

`NaturalHomomorphism` returns the natural homomorphism of the group G into the factor group F. F must be a factor group, i.e., the result of `FactorGroup(H,N)` (see FactorGroup) or `H/N` (see Operations for Groups), and G must be a subgroup of H.

Mathematically the factor group H/N consists of the cosets of N, and the natural homomorphism phi maps each element h of H to the coset N h. Note that in GAP the representation of factor group elements is unspecified, but they are never cosets (see IsRightCoset), because cosets are domains and not group elements in GAP. Thus the natural homomorphism is the only connection between a group and one of its factorgroups.

G is the source of the natural homomorphism phi, F is its range. Note that because G may be a proper subgroup of the group H of which F is a factor group phi need not be surjective, i.e., the image of phi may be a proper subgroup of F. The kernel of phi is of course the intersection of N and G.

```    gap> s4 := Group( (1,2), (1,2,3,4) );;
gap> v4 := Subgroup( s4, [ (1,2)(3,4), (1,3)(2,4) ] );;
gap> v4.name := "v4";;
gap> phi := NaturalHomomorphism( s4, s4/v4 );;
gap> (1,2,3) ^ phi;
FactorGroupElement( v4, (2,4,3) )
gap> PreImages( phi, last );
(v4*(2,4,3))
gap> (1,2,3) in last;
true
gap> rho :=
>  NaturalHomomorphism( Subgroup( s4, [ (1,2), (1,2,3) ] ), s4/v4 );;
gap> Kernel( rho );
Subgroup( Group( (1,2), (1,2,3,4) ), [  ] )
gap> IsIsomorphism( rho );
true ```

`NaturalHomomorphism` calls
`F.operations.NaturalHomomorphism( G, F )` and returns that value.

The default function called this way is `GroupOps.NaturalHomomorphism`. The homomorphism constructed this way has the operations record `NaturalHomomorphismOps`. It computes the image of an element g of G by calling `FactorGroupElement( N, g )`, the preimages of an factor group element f as ```Coset( Kernel(phi), f.element.representative )```, and the kernel by computing `Intersection( G, N )`. Look under NaturalHomomorphism in the index to see for which groups this function is overlaid.

## 7.110 ConjugationGroupHomomorphism

`ConjugationGroupHomomorphism( G, H, x )`

`ConjugationGroupHomomorphism` returns the homomorphism from G into H that takes each element g in G to the element `g ^ x`. G and H must have a common parent group P and x must lie in this parent group. Of course `G ^ x` must be a subgroup of H.

```    gap> d12 := Group( (1,2,3,4,5,6), (2,6)(3,5) );; d12.name := "d12";;
gap> c2 := Subgroup( d12, [ (2,6)(3,5) ] );
Subgroup( d12, [ (2,6)(3,5) ] )
gap> v4 := Subgroup( d12, [ (1,2)(3,6)(4,5), (1,4)(2,5)(3,6) ] );
Subgroup( d12, [ (1,2)(3,6)(4,5), (1,4)(2,5)(3,6) ] )
gap> x := ConjugationGroupHomomorphism( c2, v4, (1,3,5)(2,4,6) );
ConjugationGroupHomomorphism( Subgroup( d12,
[ (2,6)(3,5) ] ), Subgroup( d12, [ (1,2)(3,6)(4,5), (1,4)(2,5)(3,6)
] ), (1,3,5)(2,4,6) )
gap> IsSurjective( x );
false
gap> Image( x );
Subgroup( d12, [ (1,5)(2,4) ] ) ```

`ConjugationGroupHomomorphism` calls
`G.operations.ConjugationGroupHomomorphism( G, H, x )` and returns that value.

The default function called is `GroupOps.ConjugationGroupHomomorphism`. It just creates a homomorphism record with range G, source H, and the component `element` with the value x. It computes the image of an element g of G as `g ^ x`. If the sizes of the range and the source are equal the inverse of such a homomorphism is computed as a conjugation homomorphism from H to G by `x^-1`. To multiply two such homomorphisms their elements are multiplied. Look under ConjugationGroupHomomorphism in the index to see for which groups this default function is overlaid.

## 7.111 InnerAutomorphism

`InnerAutomorphism( G, g )`

`InnerAutomorphism` returns the automorphism on the group G that takes each element h to `h ^ g`. g must be an element in the parent group of G (but need not actually be in G) that normalizes G.

```    gap> s5 := Group( (1,2), (1,2,3,4,5) );;  s5.name := "s5";;
gap> i := InnerAutomorphism( s5, (1,2) );
InnerAutomorphism( s5, (1,2) )
gap> (1,2,3,4,5) ^ i;
(1,3,4,5,2) ```

`InnerAutomorphism( G, g )` calls ```ConjugationGroupHomomorphism( G, G, g )``` (see ConjugationGroupHomomorphism).

## 7.112 GroupHomomorphismByImages

`GroupHomomorphismByImages( G, H, gens, imgs )`

`GroupHomomorphismByImages` returns the group homomorphism with source G and range H that is defined by mapping the list gens of generators of G to the list imgs of images in H.

```    gap> g := Group( (1,2,3,4), (1,2) );;
gap> h := Group( (2,3), (1,2) );;
gap> m := GroupHomomorphismByImages(g,h,g.generators,h.generators);
GroupHomomorphismByImages( Group( (1,2,3,4), (1,2) ), Group( (2,3),
(1,2) ), [ (1,2,3,4), (1,2) ], [ (2,3), (1,2) ] )
gap> Image( m, (1,3,4) );
(1,3,2)
gap> Kernel( m );
Subgroup( Group( (1,2,3,4), (1,2) ), [ (1,4)(2,3), (1,2)(3,4) ] ) ```

Note that the result need not always be a single value mapping, even though the name seems to imply this. Namely if the elements in imgs do not satisfy all relations that hold for the generators gens, no element of G has a unique image under the mapping. This is demonstrated in the following example.

```    gap> g := Group( (1,2,3,4,5,6,7,8,9,10) );;
gap> h := Group( (1,2,3,4,5,6) );;
gap> m := GroupHomomorphismByImages(g,h,g.generators,h.generators);
GroupHomomorphismByImages( Group( ( 1, 2, 3, 4, 5, 6, 7, 8, 9,10
) ), Group( (1,2,3,4,5,6) ), [ ( 1, 2, 3, 4, 5, 6, 7, 8, 9,10) ],
[ (1,2,3,4,5,6) ] )
gap> IsMapping( m );
false
gap> Images( m, () );
(Subgroup( Group( (1,2,3,4,5,6) ), [ ( 1, 3, 5)( 2, 4, 6) ] )*())
gap> g.1^10;
()    # the generator of <g> satisfies this relation
gap> h.1^10;
(1,5,3)(2,6,4)    # but its image does not ```

The set of images of the identity returned by `Images` is the set of elements `h.1^n` such that `g.1^n` is the identity in `g`.

The test whether a mapping constructed by `GroupHomomorphismByImages` is a single valued mapping, is usually quite expensive. Note that this test is automatically performed the first time that you apply a function that expects a single valued mapping, e.g., `Image` or `Images`. There are two possibilities to avoid this test. When you know that the mapping constructed is really a single valued mapping, you can set the flag `map.isMapping` to `true`. Then the functions assume that map is indeed a mapping and do not test it again. On the other hand if you are not certain whether the mapping is single valued, you can use `ImagesRepresentative` instead of `Image` (see ImagesRepresentative). `ImagesRepresentative` returns just one possible image, without testing whether there might actually be more than one possible image.

`GroupHomomorphismByImages` calls
`G.operations.GroupHomomorphismByImages( G, H, gens, imgs )`
and returns this value.

The default function called this way is `GroupOps.GroupHomomorphismByImages`. Below we describe how the mapping functions are implemented for such a mapping. The functions not mentioned below are implemented by the default functions described in Mapping Functions for Group Homomorphisms.

All the function below first compute the list of elements of G with an orbit algorithm, sorts this list, and stores this list in `hom.elements`. In parallel they computes and sort a list of images, and store this list in `hom.images`.

`IsMapping( map )`

The mapping constructed by `GroupHomomorphismByImages` is a single valued mapping if for each i and for each k the following equation holds
```map.images[Position(map.elements,map.elements[i]*gens[k])] = map.images[i] * imgs[k]```.

`Image( map, elm )`

If the mapping map is a single valued mapping, the image of an element elm is computed as `map.images[ Position(map.elements,elm) ]`.

`ImagesRepresentative( map, elm )`

The representative of the images of an element elm under the mapping map is computed as `map.images[ Position(map.elements,elm) ]`.

`InverseMapping( map )`

The inverse of the mapping map is constructed as `GroupHomomorphismByImages( H, G, imgs, gens )`.

`CompositionMapping( map1, map2 )`

If map2 is a mapping constructed by `GroupHomomorphismByImages` the composition is constructed by making a copy of map2 and replacing every element in `map2.images` with its image under map1.

Look under GroupHomomorphismByImages in the index to see for which groups this function is overlaid.

## 7.113 Set Functions for Groups

As already mentioned in the introduction of the chapter, groups are domains. Thus all set theoretic functions, for example `Intersection` and `Size` can be applied to groups. This and the following sections give further comments on the definition and implementations of those functions for groups. All set theoretic functions not mentioned here not treated specially for groups. The last section describes the format of the records that describe groups (see Group Records).

`Elements( G )`

The elements of a group G are constructed using a Dimino algorithm. See Elements for Groups.

`IsSubset( G, H )`

If G and H are groups then `IsSubset` tests whether the generators of H are elements of G. Otherwise `DomainOps.IsSubset` is used.

`Intersection( G, H )`

The intersection of groups G and H is computed using an orbit algorithm. See Intersection for Groups.

## 7.114 Elements for Groups

`GroupOps.Elements( G )`

`GroupOps.Elements` returns the sets of elements of G (see Elements). The function starts with the trivial subgroup of G, for which the set of elements is known and constructs the successive closures with the generators of G using `GroupOps.Closure` (see Closure).

Note that this function neither checks nor sets the record component `G.elements`. It recomputes the set of elements even it is bound to `G.elements`.

## 7.115 Intersection for Groups

`GroupOps.Intersection( G, H )`

`GroupOps.Intersection` returns the intersection of G and H either as set of elements or as a group record (see Intersection).

If one argument, say G, is a set and the other a group, say H, then `GroupOps.Intersection` returns the subset of elements of G which lie in H.

If G and H have different parent groups then `GroupOps.Intersection` uses the function `DomainOps.Intersection` in order to compute the intersection.

Otherwise `GroupOps.Intersection` computes the stabilizer of the trivial coset of the bigger group in the smaller group using `Stabilizer` and `Coset`.

## 7.116 Operations for Groups

`G ^ s`

The operator `^` evaluates to the subgroup conjugate to G under a group element s of the parent group of G. See ConjugateSubgroup.

```    gap> s4 := Group( (1,2,3,4), (1,2) );
Group( (1,2,3,4), (1,2) )
gap> s4.name := "s4";;
gap> v4 := Subgroup( s4, [ (1,2), (1,2)(3,4) ] );
Subgroup( s4, [ (1,2), (1,2)(3,4) ] )
gap> v4 ^ (2,3);
Subgroup( s4, [ (1,3), (1,3)(2,4) ] )
gap> v4 ^ (2,5);
Error, <g> must be an element of the parent group of <G> ```

`s in G`

The operator `in` evaluates to `true` if s is an element of G and `false` otherwise. s must be an element of the parent group of G.

```    gap> (1,2,3,4) in v4;
false
gap> (2,4) in v4^(2,3);
true ```

`G * s`

The operator `*` evaluates to the right coset of G with representative s. s must be an element of the parent group of G. See RightCoset for details about right cosets.

`s * G`

The operator `*` evaluates to the left coset of G with representative s. s must be an element of the parent group of G. See LeftCoset for details about left cosets.

```    gap> v4 * (1,2,3,4);
(Subgroup( s4, [ (1,2), (1,2)(3,4) ] )*(1,2,3))
gap> (1,2,3,4) * v4;
((1,2,3,4)*Subgroup( s4, [ (1,2), (1,2)(3,4) ] )) ```

`G / N`

The operator `/` evaluates to the factor group <G> / <N> where N must be a normal subgroup of G. This is the same as `FactorGroup(G,N)` (see FactorGroup).

## 7.117 Group Records

As for all domains (see Domains and Domain Records) groups and their subgroups are represented by records that contain important information about groups. Most of the following functions return such records. Of course it is possible to create a group record by hand but generally `Group` (see Group) and `Subgroup` (see Subgroup) should be used for such tasks.

Once a group record is created you may add record components to it but you must not alter informations already present, especially not `generators` and `identity`.

Group records must always contain the components `generators`, `identity`, `isDomain` and `isGroup`. Subgroups contain an additional component `parent`. The contents of all components of a group G are described below.

The following two components are the so-called category components used to identify the category this domain belongs to.

`isDomain`:

is always `true` as a group is a domain.

`isGroup`:

is of course `true` as G is a group.

The following three components determine a group domain. These are the so-called identification components.

`generators`:

is a list group generators. Duplicate generators are allowed but none of the generators may be the group identity. The group G is the trivial group if and only if `generators` is the empty list. Note that once created this entry must never be changed, as most of the other entries depend on `generators`.

`identity`:

is the group identity of G.

`parent`:

if present this contains the group record of the parent group of a subgroup G, otherwise G itself is a parent group.

The following components are optional and contain knowledge about the group G.

`abelianInvariants`:

a list of integers containing the abelian invariants of an abelian group G.

`centralizer`:

contains the centralizer of G in its parent group.

`centre`:

contains the centre of G. See Centre.

`commutatorFactorGroup`:

contains the commutator factor group of G. See CommutatorFactorGroup for details.

`conjugacyClasses`:

contains a list of the conjugacy classes of G. See ConjugacyClasses for details.

`core`:

contains the core of G under the action of its parent group. See Core for details.

`derivedSubgroup`:

contains the derived subgroup of G. See DerivedSubgroup.

`elements`:

is the set of all elements of G. See Elements.

`fittingSubgroup`:

contains the Fitting subgroup of G. See FittingSubgroup.

`frattiniSubgroup`:

contains the Frattini subgroup of G. See FrattiniSubgroup.

`index`:

contains the index of G in its parent group. See Index.

`lowerCentralSeries`:

contains the lower central series of G as list of subgroups. See LowerCentralSeries.

`normalizer`:

contains the normalizer of G in its parent group. See Normalizer for details.

`normalClosure`:

contains the normal closure of G in its parent group. See NormalClosure for details.

`upperCentralSeries`:

contains the upper central series of G as list of subgroups. See UpperCentralSeries.

`subnormalSeries`:

contains a subnormal series from the parent of G down to G. See SubnormalSeries for details.

`sylowSubgroups`:

contains a list of Sylow subgroups of G. See SylowSubgroup for details.

`size`:

is either an integer containing the size of a finite group or the string ``infinity'' if the group is infinite. See Size.

`perfectSubgroups`:

contains the a list of subgroups which includes at least one representative of each class of conjugate proper perfect subgroups of G. See Lattice.

`lattice`:

contains the subgroup lattice of G. See Lattice.

`conjugacyClassesSubgroups`:

identical to the list `G.lattice.classes`, contains the conjugacy classes of subgroups of G. See ConjugacyClassesSubgroups.

`tableOfMarks`:

contains the table of narks of G. See TableOfMarks.

The following components are `true` if the group G has the property, `false` if not, and are not present if it is unknown whether the group has the property or not.

`isAbelian`:

is `true` if the group G is abelian. See IsAbelian.

`isCentral`:

is `true` if the group G is central in its parent group. See IsCentral.

`isCyclic`:

is `true` if the group G is cyclic. See IsCyclic.

`isElementaryAbelian`:

is `true` if the group G is elementary abelian. See IsElementaryAbelian.

`isFinite`:

is `true` if the group G is finite. If you know that a group for which you want to use the generic low level group functions is infinite, you should set this component to `false`. This will avoid attempts to compute the set of elements.

`isNilpotent`:

is `true` if the group G is nilpotent. See IsNilpotent.

`isNormal`:

is `true` if the group G is normal in its parent group. See IsNormal.

`isPerfect`:

is `true` if the group G is perfect. See IsPerfect.

`isSimple`:

is `true` if the group G is simple. See IsSimple.

`isSolvable`:

is `true` if the group G is solvable. See IsSolvable.

`isSubnormal`:

is `true` if the group G is subnormal in its parent group. See IsSubnormal.

GAP 3.4.4
April 1997