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.

- Group Elements
- Comparisons of Group Elements
- Operations for Group Elements
- IsGroupElement
- Order
- More about Groups and Subgroups
- IsParent
- Parent
- Group
- AsGroup
- IsGroup
- Subgroup
- AsSubgroup
- Subgroups
- Agemo
- Centralizer
- Centre
- Closure
- CommutatorSubgroup
- ConjugateSubgroup
- Core
- DerivedSubgroup
- FittingSubgroup
- FrattiniSubgroup
- NormalClosure
- NormalIntersection
- Normalizer
- PCore
- PrefrattiniSubgroup
- Radical
- SylowSubgroup
- TrivialSubgroup
- FactorGroup
- FactorGroupElement
- CommutatorFactorGroup
- Series of Subgroups
- DerivedSeries
- CompositionSeries
- ElementaryAbelianSeries
- JenningsSeries
- LowerCentralSeries
- PCentralSeries
- SubnormalSeries
- UpperCentralSeries
- Properties and Property Tests
- AbelianInvariants
- DimensionsLoewyFactors
- EulerianFunction
- Exponent
- Factorization
- Index
- IsAbelian
- IsCentral
- IsConjugate
- IsCyclic
- IsElementaryAbelian
- IsNilpotent
- IsNormal
- IsPerfect
- IsSimple
- IsSolvable
- IsSubgroup
- IsSubnormal
- IsTrivial for Groups
- GroupId
- PermutationCharacter
- Conjugacy Classes
- ConjugacyClasses
- ConjugacyClass
- IsConjugacyClass
- Set Functions for Conjugacy Classes
- Conjugacy Class Records
- ConjugacyClassesSubgroups
- Lattice
- ConjugacyClassSubgroups
- IsConjugacyClassSubgroups
- Set Functions for Subgroup Conjugacy Classes
- Subgroup Conjugacy Class Records
- ConjugacyClassesMaximalSubgroups
- MaximalSubgroups
- NormalSubgroups
- ConjugateSubgroups
- Cosets of Subgroups
- RightCosets
- RightCoset
- IsRightCoset
- Set Functions for Right Cosets
- Right Cosets Records
- LeftCosets
- LeftCoset
- IsLeftCoset
- DoubleCosets
- DoubleCoset
- IsDoubleCoset
- Set Functions for Double Cosets
- Double Coset Records
- Group Constructions
- DirectProduct
- DirectProduct for Groups
- SemidirectProduct
- SemidirectProduct for Groups
- SubdirectProduct
- WreathProduct
- WreathProduct for Groups
- Group Homomorphisms
- IsGroupHomomorphism
- KernelGroupHomomorphism
- Mapping Functions for Group Homomorphisms
- NaturalHomomorphism
- ConjugationGroupHomomorphism
- InnerAutomorphism
- GroupHomomorphismByImages
- Set Functions for Groups
- Elements for Groups
- Intersection for Groups
- Operations for Groups
- Group Records

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.

`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.

`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( `

of group elements
`g1`, ..., `gn-1` ), `gn` )`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( `

of group elements
`g1`, RightNormedComm( `g2`, ..., `gn` ) )`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.

`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

`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

**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).

`IsParent( `

`G` )

`IsParent`

returns `true`

if `G` is a parent group, and `false`

otherwise
(see More about Groups and Subgroups).

`Parent( `

` U_1`, ...,

`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.

`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`, ...,

`Group`

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

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

to
these generators.
`G`.m

`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.

`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

`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

, so it is safe
to modify *U*.generators`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

`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) ] )

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

`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`.

`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`.

`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`.

`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

then
`U`.elements`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

then
`U`.elements`GroupOps.Closure`

computes the set of elements for the closure *C* and
binds it to

.
*C*.elements

`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`.

`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

, and `U`.isSolvable

are
copied to `U`.size*<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.

`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`.

`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*.

`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`.

`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).

`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

`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`

.

`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).

`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).

`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) ) gap> Radical( g ); 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.

`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.

`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

`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

(see Operations for Groups).
`G` / `N`

`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

. If this component is bound,
`N`.factorGroup`FactorGroup`

returns its value. Otherwise, `FactorGroup`

calls

, remembers the returned value in
`G`.operations.FactorGroup( `G`, `N` )

, and returns it. If `N`.factorGroup`G` is not the parent group of
`N`, `FactorGroup`

calls

and
returns this value.
`G`.operations.FactorGroup( `G`, `N` )

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.

`FactorGroupElement( `

`N`, `g` )

`FactorGroupElement`

returns the coset

as a group element.
It is not tested whether `N` * `g``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, () )

`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.

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.

`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`.

`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.

`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).

`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, [ ] ) ]

`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

in the group record of `G`.lowerCentralSeries`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`.

`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) ] ) ]

`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}}*.

`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

in the group
record of `G`.upperCentralSeries`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 ), [ ] ) ]

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.

`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.

`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.

`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).

`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.

`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

which contains a list of `G`.abstractGenerators*n* abstract words *h_1, ..., h_n*. Otherwise a
list of *n* abstract generators is bound to

. The
function returns an abstract word `G`.abstractGenerators*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`.

`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

if `U`.index`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( `

and `G` )`Size( `

.
`U` )

`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

. If `G`.isAbelian`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*.

`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

if `U`.isCentral`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`.

`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`.

`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`.

`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*.

`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.

`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

if `U`.isNormal`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`.

`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).

`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

`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.

`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`

.

`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

if `U`.isSubnormal`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`.

`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`

.

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

`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.

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

`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

is bound. If
the component is bound, it returns that value. Otherwise it calls
`G`.conjugacyClasses

, remembers the returned value in
`G`.operations.ConjugacyClasses( `G` )

, and returns it.
`G`.conjugacyClasses

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( `

(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`, `g` )`G`.

`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

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

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.

`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'

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(`

(see RepresentativeOperation).
`G`,`h`,`g`)

`Random( `

`C` )

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

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`.

`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

) the `G`.operations.ConjugacyClassesSubgroups( `G` )`Lattice`

command
(see Lattice), constructs the whole subgroup lattice of `G`, stores it
in the record component

, and finally returns the list
`G`.lattice

. This means, in particular, that it will fail if
`G`.lattice.classes`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

`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

in the group
record `G`.lattice`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

, and then call the `G`.perfectSubgroups`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

to be an empty list.
`G`.perfectSubgroups

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

. 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 `lat`.classes*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(,`

".
However, you can ask `group`,)**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 `n`th 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

. The argument `lattice`.printLevel`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.

`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

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

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.

`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'

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`.

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

in`C`.representative

.`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

. It is a list of length 2. The first element is another conjugacy class`C`.representative`D`(in the same group), the second is an element`g`in

. The normalizer of`C`.group

is then`C`.representative

.`D`.representative ^`g`

`conjugands`

:-

A right transversal of the normalizer of

in`C`.representative

. Thus the elements of the class`C`.group`C`can be computed by conjugating

with those elements.`C`.representative

`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.

`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.

`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.

`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) ] ) ]

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.

`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

, remembers the returned value in
`G`.operations.RightCosets(`G`,`U`)

and returns it. If `U`.rightCosets`G` is not the parent of `U`,
`RightCosets`

directly calls the function

and returns that value.
`G`.operations.RightCosets(`G`,`U`)

The default function called this way is `GroupOps.RightCosets`

, which
calls `Orbit( `

. Look up `G`, RightCoset( `U` ), OnRight )`RightCosets`

in the index, to see for which groups this function is overlaid.

`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

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

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.

`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

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

lies in the subgroup `h` / `u``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 `(`

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

`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

. Otherwise
the result is obtained by multiplying the proper set of elements of `u` * `v``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.

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.

`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

, remembers the returned value in
`G`.operations.LeftCosets(`G`,`U`)

and returns it. If `U`.leftCosets`G` is not the parent of `U`,
`LeftCosets`

calls

directly and
returns that value.
`G`.operations.LeftCosets(`G`,`U`)

The default function called this way is `GroupOps.LeftCosets`

, which
calls `RightCosets( `

and turns each right coset `G`, `U` )

into the left coset `U` * `u`

. Look up the entries for
`u`^-1 * `U``LeftCosets`

in the index, to see for which groups this function is
overlaid.

`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.

`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.

`DoubleCosets( `

`G`, `U`, `V` )

`DoubleCosets`

returns a list of the double cosets of the subgroups `U`
and `V` in the group `G`. 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

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

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.

`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

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

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.

`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

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

that contains a
list of right cosets of the left group `D`.rightCosets`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

, where
Double Coset Records).
`U` * `u`

`Elements( `

`D` )

To compute the proper set of elements the union of the right cosets

is computed.
`D`.rightCosets

`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

. In other cases the the test is delegated to
`D`.rightCosets`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

and returns the
result of applying `D`.rightCosets`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.

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.

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

`DirectProduct( `

` G_1`, ...,

`DirectProduct`

returns a group record of the direct product *D* of the
groups ` G_1`, ....,

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

`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).

`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 `(`

is mapped to `g`,`h`)`g`.

`Projection( `

`S`, `H`, 2 )

`Projection`

returns the homomorphism of `S` onto `H`, where `(`

is mapped to `g`,`h`)`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

with the arguments `G`.operations.SemidirectProduct`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.

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 `(`

is represented by a record with the
following components.
`g`,`h`)

`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.

`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 `(`

is mapped to `g1`,`g2`)`g1`.

`Projection( `

`S`, `G2`, 2 )

`Projection`

returns the projection of `S` onto `G2`, where `(`

is mapped to `g1`,`g2`)`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

with the arguments `G1`.operations.SubdirectProduct`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.

`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

`WreathProduct`

returns the wreath product of

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 ]

`GroupOps.WreathProduct( `

`G`, `H`, ` alpha` )

Let *d* be the degree of

. A group element of the
wreath product ` alpha`.range

`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).

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

`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

is bound. If the flag is bound, `map`.isGroupHomomorphism`IsGroupHomomorphism`

returns its value.
Otherwise it calls

, remembers the
returned value in `map`.source.operations.IsGroupHomomorphism( `map` )

, and returns it. Note that
of course all functions that create group homomorphisms set the flag
`map`.isGroupHomomorphism

to `map`.isGroupHomomorphism`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.

`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

is bound. If it is bound, `hom`.kernelGroupHomomorphism`KernelGroupHomomorphisms`

returns that value.
Otherwise it calls

, remembers the
returned value in `hom`.operations.KernelGroupHomomorphism( `hom` )

, and returns it.
`hom`.kernelGroupHomomorphism

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( `

. Note that
this implies that the image of `hom`.source ) / Size( Image( hom ) )`hom` and its size are computed. Look
under **Kernel** in the index to see for which group homomorphisms this
function is overlaid.

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( `

(see KernelGroupHomomorphism) is
trivial.
`hom` )

`IsSurjective( `

`hom` )

The group homomorphism `hom` is surjective if the size of the image
`Size( Image( `

(see Image and below) is equal to the size of
the range `hom` ) )`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( `

and the result is the coset of `hom`, `elm` )`Kernel( `

containing this
representative.
`hom` )

`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.

`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(`

(see FactorGroup) or `H`,`N`)

(see
Operations for Groups), and `H`/`N``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

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

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( `

, the preimages of an factor
group element `N`, `g` )`f` as `Coset( Kernel(`

, and the kernel by computing `phi`), `f`.element.representative
)`Intersection( `

. Look under
`G`, `N` )**NaturalHomomorphism** in the index to see for which groups this function
is overlaid.

`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

must be a subgroup of `G` ^ `x``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

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

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

. If the sizes of the range and the
source are equal the inverse of such a homomorphism is computed as a
conjugation homomorphism from `g` ^ `x``H` to `G` by

. To multiply two
such homomorphisms their elements are multiplied. Look under
`x`^-1**ConjugationGroupHomomorphism** in the index to see for which groups this
default function is overlaid.

`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( `

calls `G`, `g` )`ConjugationGroupHomomorphism( `

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

`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^`

such that `n``g.1^`

is the identity in `n``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

to `map`.isMapping`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

. In parallel they computes and sort a list of images,
and store this list in `hom`.elements

.
`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

with its image under `map2`.images`map1`.

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

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.

`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

. It recomputes the set of elements even it is bound to
`G`.elements

.
`G`.elements

`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`

.

`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(`

(see FactorGroup).
`G`,`N`)

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

, contains the conjugacy classes of subgroups of*G*.lattice.classes*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.

Domain Records and Dispatchers).

GAP 3.4.4

April 1997