%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%
%A  group.tex                   GAP documentation                Frank Celler
%%
%A  @(#)$Id: group.tex,v 3.45.1.2 1994/08/31 12:11:54 mschoene Rel $
%%
%Y  Copyright 1990-1992,  Lehrstuhl D fuer Mathematik,  RWTH Aachen,  Germany
%%
%%  This file contains the description of the group  record  and  polymorphic
%%  functions for groups.
%%
%H  $Log: group.tex,v $
%H  Revision 3.45.1.2  1994/08/31  12:11:54  mschoene
%H  added description of 'MaximalSubgroups' etc.
%H
%H  Revision 3.45.1.1  1994/08/22  15:08:07  fceller
%H  added pqr groups in 'GroupId'
%H
%H  Revision 3.45  1994/06/30  15:32:36  vfelsch
%H  included final changes for version 3.4
%H
%H  Revision 3.44  1994/06/12  14:46:40  mschoene
%H  fixed example
%H
%H  Revision 3.43  1994/06/10  03:13:19  vfelsch
%H  updated examples
%H
%H  Revision 3.42  1994/06/06  08:33:55  fceller
%H  fixed a few typos
%H
%H  Revision 3.41  1994/06/03  11:50:04  fceller
%H  updated 'GroupId' for 2- and 3-groups
%H
%H  Revision 3.40  1994/06/03  08:57:20  mschoene
%H  changed a few things to avoid LaTeX warnings
%H
%H  Revision 3.39  1994/05/30  14:52:02  vfelsch
%H  index entries rearranged
%H
%H  Revision 3.38  1994/05/19  13:49:03  sam
%H  bug fixes
%H
%H  Revision 3.37  1994/05/12  10:31:36  sam
%H  added Frank's documentation of 'GroupId'
%H
%H  Revision 3.36  1994/05/12  09:24:36  fceller
%H  added 'LeftNormedComm' and 'RightNormedComm'
%H
%H  Revision 3.35  1993/07/27  11:11:58  martin
%H  changed example of 'DimensionsLoewyFactors'
%H
%H  Revision 3.34  1993/07/22  14:33:09  felsch
%H  bugs in description of Lattice corrected
%H
%H  Revision 3.33  1993/05/04  11:38:23  fceller
%H  fixed a spelling error
%H
%H  Revision 3.32  1993/04/01  13:38:52  fceller
%H  added 'Agemo', 'JenningsSeries' and 'DimensionsLoewyFactors'
%H
%H  Revision 3.31  1993/03/30  13:33:38  fceller
%H  changed reference in 'ElementaryAbelianSeries'
%H
%H  Revision 3.30  1993/03/11  17:59:49  fceller
%H  added warning for fp groups,  added 'NormalSubgroups'
%H
%H  Revision 3.29  1993/03/10  13:35:09  fceller
%H  added description of 'PermutationCharacter'
%H
%H  Revision 3.28  1993/02/19  10:48:42  gap
%H  adjustments in line length and spelling
%H
%H  Revision 3.27  1993/02/15  14:22:26  felsch
%H  DefineName eliminated
%H
%H  Revision 3.26  1993/02/12  17:13:51  felsch
%H  examples adjusted to line length 72
%H
%H  Revision 3.25  1993/02/11  17:46:09  martin
%H  changed '@' to '&'
%H
%H  Revision 3.24  1993/02/11  15:44:48  martin
%H  added 'PCore' and 'Radical'
%H
%H  Revision 3.23  1993/02/02  12:51:37  felsch
%H  long lines in examples fixed
%H
%H  Revision 3.22  1993/02/01  13:31:03  felsch
%H  examples fixed
%H
%H  Revision 3.21  1993/01/27  10:09:53  fceller
%H  various fixes of examples
%H
%H  Revision 3.20  1993/01/22  19:33:24  felsch
%H  added 'Lattice', moved 'TableOfMarks' to "tom"
%H
%H  Revision 3.19  1993/01/04  10:59:55  fceller
%H  added 'Exponent'
%H
%H  Revision 3.18  1992/12/02  10:05:22  fceller
%H  moved 'PCentralSeries' to "group.g"
%H
%H  Revision 3.17  1992/11/30  18:46:25  fceller
%H  moved 'ElementaryAbelianSeries' and 'CompositionSeries' into "group.g"
%H
%H  Revision 3.16  1992/04/30  12:34:13  martin
%H  fixed '* ... *' to '\* ... \*'
%H
%H  Revision 3.15  1992/04/06  15:59:01  martin
%H  fixed some more typos
%H
%H  Revision 3.14  1992/04/02  21:06:23  martin
%H  changed *domain functions* to *set theoretic functions*
%H
%H  Revision 3.13  1992/04/02  16:53:52  martin
%H  added 'ConjugationGroupHomomorphism' and 'InnerAutomorphism'
%H
%H  Revision 3.12  1992/03/26  17:30:10  martin
%H  changed the order of the sections slightly
%H
%H  Revision 3.11  1992/03/26  13:28:49  martin
%H  added sections for the conjugacy classes
%H
%H  Revision 3.10  1992/03/25  15:37:32  martin
%H  added new sections for group homomorphisms
%H
%H  Revision 3.9  1992/03/11  13:58:55  martin
%H  fixed the citations
%H
%H  Revision 3.8  1992/02/07  18:26:02  fceller
%H  Initial GAP 3.1 release.
%H
%H  Revision 3.6  1992/01/24  11:49:32  martin
%H  added the description of cosets
%H
%H  Revision 3.1  1991/05/21  12:03:25  fceller
%H  Initial revision
%%
\Chapter{Groups}

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

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

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

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

The first part describes the operations and functions  that are available
for group elements, e.g., 'Order' (see "Group Elements").   The next part
tells your more about the distinction of parent groups and subgroups (see
"More  about  Groups  and  Subgroups").   The  next  parts  describe  the
functions  that compute subgroups, e.g.,  'SylowSubgroup'  ("Subgroups"),
and   series   of  subgroups,  e.g.,  'DerivedSeries'   (see  "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,   e.g.,   'NaturalHomomorphism'    (see    "Group
Homomorphisms").  The last part tells you more  about  the implementation
of   groups,  e.g., it describes  the format  of group  records (see "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.

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\Section{Group Elements}

The following  sections  describe the operations and  functions available
for group  elements (see "Comparisons of Group Elements", "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.

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\Section{Comparisons of Group Elements}%
\index{equality!of group elements}%
\index{ordering!of group elements}

'<g> = <h>' \\
'<g> \<> <h>'

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

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

\vspace{5mm}
'<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.

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\Section{Operations for Group Elements}

'<g> \*\ <h>'%
\index{product!of group elements}\\
'<g> / <h>'%
\index{quotient!of group elements}

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.

\vspace{5mm}
'<g> \^\ <h>'%
\index{conjugate!of a group element}

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.

\vspace{5mm}
'<g> \^\ <i>'%
\index{power!of group elements}

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.

\vspace{5mm}
'<list> \*\ <g>'%
\index{product!of list and group element}\\
'<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>.

\vspace{5mm}
'<list> / <g>'%
\index{quotient!of list and group element}

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

\vspace{5mm}
'Comm( <g>, <h> )'%
\index{Comm!for group elements}

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

\vspace{5mm}
'LeftNormedComm( <g1>, ..., <gn> )'%
\index{LeftNormedComm!for group elements}

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

\vspace{5mm}
'RightNormedComm( <g1>, <g2>, ..., <gn> )'%
\index{RightNormedComm!for group elements}

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

\vspace{5mm}
'LeftQuotient( <g>, <h> )'%
\index{LeftQuotient!for group elements}

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

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\Section{IsGroupElement}%
\index{test!for group element}

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

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\Section{Order}%
\index{order!of a group element}

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

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\Section{More about Groups and Subgroups}

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

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

Those group functions that take more than one  argument require that  the
arguments  have a  common parent.   Take for  instance  'Normalizer'.  It
takes two  arguments,  a  group <G>  and  a  group  <H>, and  returns the
normalizer  of <H> in <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> Normalizer( s4, c3 );
    Subgroup( Group( (1,2), (1,2,3,4) ), [ (1,2,3), (1,2), (2,3) ] )
    # 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> Normalizer( a4, c3 );
    Subgroup( Group( (1,2), (1,2,3,4) ), [ (1,2,3) ] )
    # also ok, 'c3' and 'a4' are subgroups of the parent group 's4'
    gap> x3 := Group( (1,2,3) );
    Group( (1,2,3) )
    gap> Normalizer( 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 'Normalizer' above,
return  this subgroup  as  a  subgroup  of  the  common  parent  of their
arguments.  Note  especially  that the  normalizer  of 'c3'  in  '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 normalizer 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> Normalizer( 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> Normalizer( s4, c3 );
    Subgroup( Group( (1,2), (1,2,3,4) ), [ (1,2,3), (1,2), (2,3) ] ) |

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

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\Section{IsParent}

'IsParent( <G> )'

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

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\Section{Parent}

'Parent( <$U_1$>, ..., <$U_n$> )'

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

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

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\Section{Group}

'Group( <U> )'

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

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

'Group( <list>, <id> )'

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

'Group( <$g_1$>, ..., <$g_n$> )'

'Group'  returns  a   new parent group   $G$ generated  by group elements
<$g_1$>, ..., <$g_n$>.

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

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

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

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\Section{AsGroup}

'AsGroup( <D> )'

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

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

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

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

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

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\Section{IsGroup}

'IsGroup( <obj> )'

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

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

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\Section{Subgroup}

'Subgroup( <G>, <L> )'

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

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

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

Let $g_{i_1}, ..., g_{i_m}$ be  the nontrivial  generators.   'Subgroups'
binds these generators to '<U>.1', ..., '<U>.m'.

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

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\Section{AsSubgroup}

'AsSubgroup( <G>, <U> )'

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

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

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\Section{Subgroups}

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

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

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

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

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\Section{Agemo}

'Agemo( <G>, <p> )'

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

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

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

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\Section{Centralizer}

'Centralizer( <G>, <x> )'

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

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

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

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

'Centralizer( <G>, <U> )'

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

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

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

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

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

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\Section{Centre}

'Centre( <G> )'

'Centre' returns the centre of <G>.

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

Note that 'Centre' sets and tests the record component '<G>.centre'.

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

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

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\Section{Closure}

'Closure( <U>, <g> )'

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

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

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

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

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

'Closure( <U>, <S> )'

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

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

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

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

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\Section{CommutatorSubgroup}

'CommutatorSubgroup( <G>, <H> )'

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

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

See also 'DerivedSubgroup' ("DerivedSubgroup").

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

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

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\Section{ConjugateSubgroup}

'ConjugateSubgroup( <U>, <g> )'

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

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

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

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

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

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\Section{Core}

'Core( <S>, <U> )'

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

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

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

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

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\Section{DerivedSubgroup}

'DerivedSubgroup( <G> )'

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

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

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

|    gap> s4 := Group( (1,2,3,4), (1,2) );
    Group( (1,2,3,4), (1,2) )
    gap> DerivedSubgroup( s4 );
    Subgroup( Group( (1,2,3,4), (1,2) ), [ (1,3,2), (1,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$.

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\Section{FittingSubgroup}

'FittingSubgroup( <G> )'

'FittingSubgroup' returns the Fitting subgroup of <G>.

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

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

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

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\Section{FrattiniSubgroup}

'FrattiniSubgroup( <G> )' 

'FrattiniSubgroup' returns the Frattini subgroup of group <G>.

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

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

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

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\Section{NormalClosure}

'NormalClosure( <S>, <U> )'

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

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

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

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\Section{NormalIntersection}

'NormalIntersection( <N>, <U> )'

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

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

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\Section{Normalizer}

'Normalizer( <S>, <U> )'

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

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

If <S>  is  the parent group of   <U>  then 'Normalizer'  sets and  tests
'<U>.normalizer'.

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

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

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\Section{PCore}

'PCore( <G>, <p> )'

'PCore' returns the <p>-core of the finite group <G> for a prime <p>.

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

Note that 'PCore' sets and tests '<G>.pCores[ <p> ]'.

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

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

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\Section{PrefrattiniSubgroup}

'PrefrattiniSubgroup( <G> )' 

'PrefrattiniSubgroup' returns a Prefrattini subgroup of the group <G>.

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

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

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

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\Section{Radical}

'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,4,3) ] ) |

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

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\Section{SylowSubgroup}

'SylowSubgroup( <G>, <p> )'

'SylowSubgroup' returns a Sylow-<p>-subgroup of the finite group  <G> for
a prime <p>.

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

Note that 'SylowSubgroup' sets and tests '<G>.sylowSubgroups[ <p> ]'.

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

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

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\Section{TrivialSubgroup}

'TrivialSubgroup( <U> )'

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

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

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\Section{FactorGroup}

'FactorGroup( <G>, <N> )'

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

'NaturalHomomorphism' returns the  natural  homomorphism  from  <G> (or a
subgroup thereof) onto the factor group (see "NaturalHomomorphism").

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

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

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

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

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\Section{FactorGroupElement}

'FactorGroupElement( <N>, <g> )'

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

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

'isGroupElement': \\
        contains 'true'.

'isFactorGroupElement': \\
        contains 'true'.

'element': \\
        contains a right coset of <N> (see "RightCoset").

'domain': \\
        contains 'FactorGroupElements' (see "Domain").

'operations': \\
        contains the operations record 'FactorGroupElementOps'.

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

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

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\Section{CommutatorFactorGroup}

'CommutatorFactorGroup( <G> )'

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

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

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

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\Section{Series of Subgroups}

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

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

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\Section{DerivedSeries}

'DerivedSeries( <G> )'

'DerivedSeries' returns the derived series of <G>.

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

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

|    gap> s4 := Group( (1,2,3,4), (1,2) );
    Group( (1,2,3,4), (1,2) )
    gap> DerivedSeries( s4 );
    [ Group( (1,2,3,4), (1,2) ), Subgroup( Group( (1,2,3,4), (1,2) ), 
        [ (1,3,2), (2,4,3) ] ), Subgroup( Group( (1,2,3,4), (1,2) ), 
        [ (1,4)(2,3), (1,2)(3,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>.

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\Section{CompositionSeries}

'CompositionSeries( <G> )'

'CompositionSeries'  returns  a composition  series  of <G>  as  list  of
subgroups.

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

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

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\Section{ElementaryAbelianSeries}

'ElementaryAbelianSeries( <G> )'

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

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

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

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\Section{JenningsSeries}

'JenningsSeries( <G>, <p> )'

'JenningsSeries' returns the Jennings series of a $p$-group <G>.

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

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

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

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\Section{LowerCentralSeries}

'LowerCentralSeries( <G> )'

'LowerCentralSeries' returns the lower central series of <G> as a list of
group records.

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

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

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

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

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\Section{PCentralSeries}

'PCentralSeries( <G>, <p> )'

'PCentralSeries' returns the  <p>-central  series  of  a  group <G> for a
prime <p>.

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

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

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\Section{SubnormalSeries}

'SubnormalSeries( <G>, <U> )'

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

$G_n$ is equal to <U> if and only if <U> is *subnormal* in <G>.

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

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

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

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\Section{UpperCentralSeries}

'UpperCentralSeries( <G> )'

'UpperCentralSeries' returns the upper central series of <G> as a list of
subgroups.

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

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

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

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\Section{Properties and Property Tests}

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

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

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

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\Section{AbelianInvariants}

'AbelianInvariants( <G> )'

Let  <G>  be  an  abelian group.  Then  'AbelianInvariants'  returns  the
abelian invariants of <G> as a list of integers.

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' needs a finite abelian
group <G>.

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.

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\Section{DimensionsLoewyFactors}

'DimensionsLoewyFactors( <G> )'

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

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

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

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

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

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\Section{EulerianFunction}

'EulerianFunction( <G>, <n> )' 

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

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

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

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\Section{Exponent}

'Exponent( <G> )'

Let <G> be a finite group.  Then 'Exponent' returns the exponent of <G>.

Note that 'Exponent' tests and sets '<G>.exponent'.

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

The default function 'GroupOps.Exponent' computes all elements of <G> and
their orders.

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\Section{Factorization}

'Factorization( <G>, <g> )'

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

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

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

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

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\Section{Index}

'Index( <G>, <U> )'

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

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

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

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

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\Section{IsAbelian}

'IsAbelian( <G> )'

'IsAbelian'  returns 'true' if  the  group   <G> is   abelian and 'false'
otherwise.

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

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

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

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

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\Section{IsCentral}

'IsCentral( <G>, <U> )'

'IsCentral' returns 'true' if the group <G> centralizes the group <U> and
'false' otherwise.

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

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

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

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

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\Section{IsConjugate}

'IsConjugate( <G>, <x>, <y> )'

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

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

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

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\Section{IsCyclic}

'IsCyclic( <G> )'

'IsCyclic' returns 'true' if <G> is cyclic and 'false' otherwise.

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

Note that 'IsCyclic' sets and tests the record  component '<G>.isCyclic'.

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

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

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\Section{IsElementaryAbelian}

'IsElementaryAbelian( <G> )'

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

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

Note       that    the     'IsElementaryAbelian'     sets   and     tests
'<G>.isElementaryAbelian'.

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

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

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\Section{IsNilpotent}

'IsNilpotent( <G> )'

'IsNilpotent' returns  'true' if the  group <G> is  nilpotent and 'false'
otherwise.

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

Note   that 'IsNilpotent'   sets   and   tests   the   record   component
'<G>.isNilpotent'.

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

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

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

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\Section{IsNormal}

'IsNormal( <G>, <U> )'

'IsNormal' returns 'true' if  the group  <G> normalizes the group <U> and
'false' otherwise.

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

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

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

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

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

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\Section{IsPerfect}

'IsPerfect( <G> )'

'IsPerfect' returns  'true'  if  <G>    is  a perfect group  and  'false'
otherwise.

A  group <G> is *perfect* if  <G> is equal to  its derived subgroup.  See
"DerivedSubgroup".

Note that 'IsPerfect' sets and tests '<G>.isPerfect'.

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

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

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\Section{IsSimple}

'IsSimple( <G> )'

'IsSimple' returns 'true' if <G> is simple and 'false' otherwise.

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

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

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\Section{IsSolvable}

'IsSolvable( <G> )'

'IsSolvable' returns 'true' if  the group  <G>   is solvable  and 'false'
otherwise.

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

Note that 'IsSolvable' sets and tests '<G>.isSolvable'.

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

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

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

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\Section{IsSubgroup}

'IsSubgroup( <G>, <U> )'

'IsSubgroup'  returns 'true' if   <U> is a  subgroup of  <G> and  'false'
otherwise.

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

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

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

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\Section{IsSubnormal}

'IsSubnormal( <G>, <U> )'

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

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

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

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

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

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\Section{IsTrivial for Groups}%
\index{IsTrivial!for groups}

'GroupOps.IsTrivial( <G> )'

'GroupOps.IsTrivial'  returns 'true'  if  <G> is the   trivial  group and
'false' otherwise.

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

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\Section{GroupId}

'GroupId( <G> )'

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

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

'catalogue': \\
    a pair $[o,n]$ where $o$ is the size of <G> and  $n$ is the catalogue
    number of <G> following  the catalogue of groups of order at most 100.
    See   "The  Solvable  Groups Library"  for   further  details.   This
    catalogue  uses the Neubueser  list  for groups of  order at most 100,
    excluding groups of orders 64 and 96 (see~\cite{Neu67}).  It uses the
    lists developed by~\cite{HS64} and~\cite{Lau82} for  orders 64 and 96
    respectively.\medskip\\
%
    Note that there are minor discrepancies between $n$ and the number in
    \cite{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~\cite{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 $\langle A, B, C ; A^p = B^p = C^p = [A,B] = [A,C] = 1,
    [B,C] = A \rangle$, \smallskip\\
    'B(p\^3)' is $\langle A, B, C ; B^p = C^p = A, A^p = [A,B] = [A,C] =
    1, [B,C] = A \rangle$, \smallskip\\
    'D(p,q)' is $\langle A, B ; A^q = B^p = 1, A^B = A^x \rangle$ such
    that $p\|q-1$, $x \neq 1$ mod $q$, and $x^p = 1$ mod $q$,
    \smallskip\\
    'G(p\^2,q)' is $\langle A, B, C ; A^p = B^q = 1, C^p = A, [A,B] =
    [A,C] = 1, B^C = B^x \rangle$ such that $p\|q-1$, $x \neq 1$ mod
    $q$, and $x^p = 1$ mod $q$, \smallskip\\
    'G(p,q,r,s)' is $\langle A, B, C ; A^r = B^q = C^p = [A,B] = 1, A^C =
    A^x, B^C = B^{(y^s)} \rangle$ 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 $\langle A, B ; A^q = B^{(p^2)} = 1, A^B = A^x
    \rangle$ 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 $\langle A, B ; A^r = B^{pq} = 1, A^B = A^x \rangle$
    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 $\langle A, B, C ; A^q = B^q = C^p = [A,B] = 1, A^C =
    A^x, B^C = B^x \rangle$ such that $p\|q-1$, $x \neq 1$ mod $q$, and
    $x^p = 1$ mod $q$, \smallskip\\
    'L(p,q\^2,s)' is $\langle A, B, C ; A^q = B^q = C^p = [A,B] = 1, A^C
    = A^x, B^C = B^{(x^s)} \rangle$ 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 $\langle A, B ; A^{(q^2)} = B^p = 1, A^B = A^x
    \rangle$ such that $p\|q-1$, $x \neq 1$ mod $q^2$, and $x^p = 1$ mod
    $q^2$, \smallskip\\
    'N(p,q\^2)' is $\langle 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} \rangle$ 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" ],
      size := 8, 
      pGroupId := 4 )
    gap> GroupId(d8);
    rec(
      catalogue := [ 8, 4 ],
      names := [ "D8" ],
      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 ) |

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\Section{PermutationCharacter}%
\index{character!permutation}

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

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\Section{Conjugacy Classes}

The following sections describe how  one can compute conjugacy classes of
elements   and   subgroups  in a    group    (see "ConjugacyClasses"  and
"ConjugacyClassesSubgroups").  Further sections   describe how  conjugacy
classes    of    elements are     created   (see  "ConjugacyClass"    and
"IsConjugacyClass"), and how they are implemented (see "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").

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\Section{ConjugacyClasses}

'ConjugacyClasses( <G> )'

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

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

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

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

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\Section{ConjugacyClass}

'ConjugacyClass( <G>, <g> )'

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

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

'ConjugacyClass'  calls '<G>.operations.ConjugacyClass(  <G>, <g> )'  and
returns that value.

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

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\Section{IsConjugacyClass}

'IsConjugacyClass( <obj> )'

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

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

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\Section{Set Functions for Conjugacy Classes}

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

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

\vspace{5mm}
'Elements( <C> )'%
\index{Elements!for Conjugacy Classes}

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

\vspace{5mm}
'Size( <C> )'%
\index{Size!for Conjugacy Classes}

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

\vspace{5mm}
'<h> in <C>'%
\index{in!for Conjugacy Classes}

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

\vspace{5mm}
'Random( <C> )'%
\index{Random!for Conjugacy Classes}

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

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\Section{Conjugacy Class Records}

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

'isDomain': \\
        always 'true'.

'isConjugacyClass': \\
        always 'true'.

'group': \\
        holds the group <G>.

'representative': \\
        holds the representative <g>.

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

'centralizer': \\
        holds the centralizer of <g> in <G>.

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\Section{ConjugacyClassesSubgroups}

'ConjugacyClassesSubgroups( <G> )'

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

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

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

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

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

% In the record representing the domain there is an additional component
% '<class7>.conjugands' which contains a list of conjugating elements.
% 
% |    gap> & Conjugacy classes of subgroups of S4 (continued)
%     gap> & Print a list of the subgroups in class7.
%     gap> List( class7.conjugands, c -> rep7^c );
%     [ Subgroup( s4, [ (1,2)(3,4), (1,3,2,4) ] ), 
%       Subgroup( s4, [ (1,4)(2,3), (1,2,4,3) ] ), 
%       Subgroup( s4, [ (1,3)(2,4), (1,4,3,2) ] ) ] |

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\Section{Lattice}

'Lattice( <G> )'

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

|    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; |
\index{InfoLattice1}

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.

\vspace{5mm}
'PrintClassSubgroupLattice( <lattice>, <n> )'%
\index{PrintClassSubgroupLattice}

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

\vspace{5mm}
'SetPrintLevel( <lattice>, <level> )'%
\index{SetPrintLevel}

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

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

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\Section{ConjugacyClassSubgroups}

'ConjugacyClassSubgroups( <G>, <U> )'

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

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

Another example of such domains is given in section
"ConjugacyClassesSubgroups".

'ConjugacyClassSubgroups' calls \\
'<G>.operations.ConjugacyClassSubgroups( <G>, <U> )'
and returns this value.

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

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\Section{IsConjugacyClassSubgroups}

'IsConjugacyClassSubgroups( <obj> )'

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

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

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\Section{Set Functions for Subgroup Conjugacy Classes}

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

\vspace{5mm}
'Elements( <C> )'%
\index{Elements!for conjugacy classes of subgroups}

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.

\vspace{5mm}
'<V> in <C>'%
\index{in!for conjugacy classes of subgroups}

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

\vspace{5mm}
'Size( <C> )'%
\index{Size!for conjugacy classes of subgroups}

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

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\Section{Subgroup Conjugacy Class Records}

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

'isDomain': \\
        always  'true',  because  conjugacy   classes  of  subgroups  are
        domains.

'isConjugacyClassSubgroups': \\
        as well, this entry is always set to 'true'.

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

'representative': \\
        The representative of the conjugacy class of subgroups as domain.

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

'normalizer': \\
        The normalizer of '<C>.representative' in '<C>.group'.

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

'conjugands': \\
        A right transversal of the normalizer  of '<C>.representative' in
        '<C>.group'.  Thus the elements of the class <C> can be  computed
        by conjugating '<C>.representative' with those elements.

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\Section{ConjugacyClassesMaximalSubgroups}

'ConjugacyClassesMaximalSubgroups( <G> )' 

'ConjugacyClassesMaximalSubgroups' returns a list of conjugacy classes of
maximal subgroups of the group <G>.

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

|    gap> s4 := SymmetricGroup( AgWords, 4 );;
    gap> ss4 := SpecialAgGroup( s4 );;
    gap> ConjugacyClassesMaximalSubgroups( ss4 );
    [ ConjugacyClass( Group( g1, g2, g3, g4 ), 
                  Subgroup( Group( g1, g2, g3, g4 ), [ g2, g3, g4 ] ) ), 
      ConjugacyClass( Group( g1, g2, g3, g4 ), 
                  Subgroup( Group( g1, g2, g3, g4 ), [ g1, g3, g4 ] ) ), 
      ConjugacyClass( 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.

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\Section{MaximalSubgroups}

'MaximalSubgroups( <G> )' 

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

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

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

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\Section{NormalSubgroups}

'NormalSubgroups( <G> )'

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

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

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

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\Section{ConjugateSubgroups}

'ConjugateSubgroups( <G>, <U> )'

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

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

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\Section{Cosets of Subgroups}%

The following sections  describe how one can compute the right, left, and
double   cosets   of   subgroups   (see    "RightCosets",   "LeftCosets",
"DoubleCosets").  Further sections  describe how cosets are created  (see
"RightCoset", "IsRightCoset", "LeftCoset", "IsLeftCoset",  "DoubleCoset",
and "IsDoubleCoset"),  and their implementation   (see "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.

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\Section{RightCosets}%
\index{cosets!right}

'Cosets( <G>, <U> )' \\
'RightCosets( <G>, <U> )'

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

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

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

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

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\Section{RightCoset}%
\index{Coset}%
\index{coset!right}

'<U> \*\ <u>' \\
'Coset( <U>, <u> )' \\
'RightCoset( <U>, <u> )' \\
'Coset( <U> )' \\
'RightCoset( <U> )'

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

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

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

'RightCoset' calls '<U>.operations.RightCoset(  <U>, <u>  )' and  returns
that value.

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

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\Section{IsRightCoset}%
\index{IsCoset}%
\index{coset!right}

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

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\Section{Set Functions for Right Cosets}%
\index{RightCosetGroupOps}

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

\vspace{5mm}
'Elements( <C> )'%
\index{Elements!for right cosets}

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.

\vspace{5mm}
'IsFinite( <C> )'%
\index{IsFinite!for right cosets}

This returns the result of applying 'IsFinite' to the subgroup <U>.

\vspace{5mm}
'Size( <C> )'%
\index{Size!for right cosets}

This returns the result of applying 'Size' to the subgroup <U>.

\vspace{5mm}
'<C> = <D>'%
\index{comparison!of right cosets}

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.='.

\vspace{5mm}
'<h> in <U>'%

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

\vspace{5mm}
'Intersection( <C>, <D> )'%
\index{Intersection!for right cosets}

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

\vspace{5mm}
'Random( <C> )'%
\index{Random!for right cosets}

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

\vspace{5mm}
'Print( <C> )'%
\index{Print!for right cosets}

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

\vspace{5mm}
'<C> \*\ <v>'%
\index{product!for right cosets}

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

\vspace{5mm}
'<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.

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\Section{Right Cosets Records}%
\index{domain record!for right cosets}

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.

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\Section{LeftCosets}%
\index{cosets!left}

'LeftCosets( <G>, <U> )'

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

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

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

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

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\Section{LeftCoset}%
\index{coset!left}

'<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*
(see  "RightCoset",  "Set  Functions  for  Right  Cosets", "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.

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\Section{IsLeftCoset}%
\index{coset!left}

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

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\Section{DoubleCosets}%
\index{cosets!double}

'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   '<G>.operations.DoubleCoset( <G>, <U>,  <V> )' and
returns that value.

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

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\Section{DoubleCoset}%
\index{coset!double}

'DoubleCoset( <U>, <u>, <V> )'

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

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

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

'DoubleCoset' calls '<U>.operations.DoubleCoset(<U>,<u>,<V>)' and returns
that value.

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

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\Section{IsDoubleCoset}%
\index{coset!double}

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

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\Section{Set Functions for Double Cosets}%
\index{DoubleCosetGroupOps}

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

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

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

\vspace{5mm}
'Elements( <D> )'%
\index{Elements!for double cosets}

To compute the  proper set of  elements the  union   of the right  cosets
'<D>.rightCosets' is computed.

\vspace{5mm}
'IsFinite( <D> )'%
\index{IsFinite!for double cosets}

This returns the result of 'IsFinite( <U> ) and IsFinite( <V> )'.

\vspace{5mm}
'Size( <D> )'%
\index{Size!for double cosets}

This returns the size of the left group <U> times the number of cosets in
'<D>.rightCosets'.

\vspace{5mm}
'<C> = <D>'%
\index{comparison!of double cosets}

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.='.

\vspace{5mm}
'<g> in <D>'

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

\vspace{5mm}
'Intersection( <C>, <D> )'%
\index{Intersection!for double cosets}

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

\vspace{5mm}
'Random( <D> )'%
\index{Random!for double cosets}

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

\vspace{5mm}
'Print( <D> )'%
\index{Print!for double cosets}

This prints the double coset in the form 'DoubleCoset( <U>, <u>, <V> )'.

\vspace{5mm}
'<D> \*\ <g>'%
\index{product!for double cosets}\\
'<g> \*\ <D>'

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

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\Section{Double Coset Records}%

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

'isDomain': \\
        always 'true'.

'isDoubleCoset': \\
        always 'true'.

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

'leftGroup': \\
        the left subgroup <U>.

'rightGroup': \\
        the right subgroup <V>.

'representative': \\
        an element of the double coset.  It is unspecified which element.

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

'rightCosets': \\
        a  list  of disjoint  right  cosets of the   left  subgroup  <U>,
        whose union is the double coset.

'elements': \\
        if present the proper set of elements of the double coset.

'isFinite': \\
        if present this  is 'true' if  the  double coset   is finite  and
        'false' if the  double coset is  infinite.  If not present it  is
        not known whether the double coset is finite or infinite.

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

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\Section{Group Constructions}

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

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\Section{DirectProduct}%
\index{Embedding!into direct products}

'DirectProduct( <$G_1$>, ..., <$G_n$> )'

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

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

\vspace{5mm}
'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>.

\vspace{5mm}
'Projection( <D>, <U>, <i> )'%
\index{Projection!onto component of direct products}

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

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\Section{DirectProduct for Groups}%
\index{DirectProduct!for groups}

'GroupOps.DirectProduct( <L> )'

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

'element': \\
        a list $g_1\in G_1, ..., g_n\in G_n$ describing $g$.

'domain': \\
        contains 'GroupElements'.

'isGroupElement': \\
        contains 'true'.

'isDirectProductElement': \\
        contains 'true'.

'operations': \\
        contains  the    operations   record    'DirectProductElementOps'
        (see "Domain").

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\Section{SemidirectProduct}

'SemidirectProduct( <G>, <a>, <H> )'

'SemidirectProduct' returns the semidirect  product of <G> with <H>.  <a>
must be  a homomorphism  that from  <G> onto a group <A> that operates on
<H> via the caret ('\^')  operator.  <A> may either  be a subgroup of the
parent  group  of   <H>  that  normalizes  <H>,  or  a  subgroup  of  the
automorphism  group  of <H>, i.e., a group  of automorphisms  (see "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.

\vspace{5mm}
'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 )'%
\index{Embedding!into semidirect products}

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

\vspace{5mm}
'Projection( <S>, <G>, 1 )'%
\index{Projection!onto component of semidirect products}

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

'Projection( <S>, <H>, 2 )'

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

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

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

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

'SemidirectProduct' calls the function '<G>.operations.SemidirectProduct'
with the arguments <G>, <a>, and <H>, and returns the result.

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

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\Section{SemidirectProduct for Groups}%
\index{SemidirectProduct!for groups}

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

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

'element': \\
        the list '[ <g>, <h> ]'.

'automorphism': \\
        contains the image of <g> under <a>.

'isGroupElement': \\
        always 'true'.

'isSemidirectProductElement': \\
        always 'true'.

'domain': \\
        contains 'GroupElements'.

'operations': \\
        contains the operations record 'SemidirectProductOps'.

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

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\Section{SubdirectProduct}

'SubdirectProduct( <G1>, <G2>, <h1>, <h2> )'

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

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

\vspace{5mm}
'Projection( <S>, <G1>, 1 )'%
\index{Projection!for subdirect products}

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

'Projection( <S>, <G2>, 2 )'

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

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

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

'SubdirectProduct' calls the  function '<G1>.operations.SubdirectProduct'
with the arguments <G1>, <G2>, <h1>, and <h2>.

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

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\Section{WreathProduct}

'WreathProduct( <G>, <H> )' \\
'WreathProduct( <G>, <H>, <$\alpha$> )'

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

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

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\Section{WreathProduct for Groups}

'GroupOps.WreathProduct( <G>, <H>, <$\alpha$> )'

Let  $d$ be the  degree of '<$\alpha$>.range'.    A group element  of the
wreath  product $W$ is represented  as  a record containing the following
components.

'element': \\
        a list of $d$ elements of <G> followed by an element $h$ of <H>.

'permutation': \\
        the image of $h$ under <$\alpha$>.

'domain': \\
        contains 'GroupElements'.

'isGroupElement': \\
        contains 'true'.

'isWreathProductElement': \\
        contains 'true'.

'operations': \\
        contains         the              operations             record
        'WreathProductElementOps' (see "Domain").

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\Section{Group Homomorphisms}%
\index{homomorphisms!of groups}

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 are implemented for group homomorphisms (see  "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").

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\Section{IsGroupHomomorphism}%
\index{IsHomomorphism!for groups}

'IsGroupHomomorphism( <map> )'

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

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

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

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

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

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\Section{KernelGroupHomomorphism}%
\index{Kernel!for groups}

'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,3,4), (1,2)(3,4) ] ) |

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

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

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\Section{Mapping Functions for Group Homomorphisms}

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

\vspace{5mm}
'IsInjective( <hom> )'%
\index{IsInjective!for group homomorphisms}

The  group   homomorphism <hom>  is injective  if  the  kernel  of  <hom>
'KernelGroupHomomorphism( <hom>   )' (see  "KernelGroupHomomorphism")  is
trivial.

\vspace{5mm}
'IsSurjective( <hom> )'%
\index{IsSurjective!for group homomorphisms}

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

\vspace{5mm}
'<hom1> = <hom2>'%
\index{equality!of group homomorphisms}

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.

\vspace{5mm}
'<hom1> \<\ <hom2>'%
\index{ordering!of group homomorphisms}

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.

\vspace{5mm}
'Image( <hom> )'%
\index{Image!for group homomorphisms}\\
'Image( <hom>, <H> )' \\
'Images( <hom>, <H> )'%
\index{Images!for group homomorphisms}

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.

\vspace{5mm}
'PreImages( <hom>, <elm> )'%
\index{PreImages!for group homomorphisms}

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

\vspace{5mm}
'PreImage( <hom> )'%
\index{PreImage!for group homomorphisms}\\
'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.

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\Section{NaturalHomomorphism}%
\index{group homomorphisms!natural}%
\index{homomorphisms!natural, group}

'NaturalHomomorphism( <G>, <F> )'

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

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

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

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

'NaturalHomomorphism' calls \\
'<F>.operations.NaturalHomomorphism( <G>, <F> )'
and returns that value.

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

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\Section{ConjugationGroupHomomorphism}%
\index{group homomorphisms!conjugation}%
\index{homomorphisms!conjugation, group}

'ConjugationGroupHomomorphism( <G>, <H>, <x> )'

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

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

'ConjugationGroupHomomorphism' calls \\
'<G>.operations.ConjugationGroupHomomorphism( <G>, <H>, <x> )'
and returns that value.

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

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\Section{InnerAutomorphism}%
\index{group homomorphisms!inner}%
\index{homomorphisms!inner, group}

'InnerAutomorphism( <G>, <g> )'

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

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

'InnerAutomorphism( <G>, <g> )' calls 'ConjugationGroupHomomorphism( <G>,
<G>, <g> )' (see "ConjugationGroupHomomorphism").

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\Section{GroupHomomorphismByImages}%
\index{group homomorphisms!by images}%
\index{homomorphisms!by images, group}

'GroupHomomorphismByImages( <G>, <H>, <gens>, <imgs> )'

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

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

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

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

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

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

'GroupHomomorphismByImages' calls \\
'<G>.operations.GroupHomomorphismByImages( <G>, <H>, <gens>, <imgs> )' \\
and returns this value.

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

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

\vspace{5mm}
'IsMapping( <map> )'%
\index{IsMapping!for GroupHomomorphismByImages}

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>]'.

\vspace{5mm}
'Image( <map>, <elm> )'%
\index{Image!for GroupHomomorphismByImages}

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

\vspace{5mm}
'ImagesRepresentative( <map>, <elm> )'%
\index{ImagesRepresentative!for GroupHomomorphismByImages}

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

\vspace{5mm}
'InverseMapping( <map> )'%
\index{InverseMapping!for GroupHomomorphismByImages}

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

\vspace{5mm}
'CompositionMapping( <map1>, <map2> )'%
\index{CompositionMapping!for GroupHomomorphismByImages}

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

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

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\Section{Set Functions for Groups}

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

\vspace{5mm}
'Elements( <G> )'%
\index{Elements!for groups}

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

\vspace{5mm}
'IsSubset( <G>, <H> )'%
\index{IsSubset!for groups}

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

\vspace{5mm}
'Intersection( <G>, <H> )'%
\index{Intersection!for groups}

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

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\Section{Elements for Groups}

'GroupOps.Elements( <G> )'

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

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

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\newpage
\Section{Intersection for Groups}

'GroupOps.Intersection( <G>, <H> )'

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

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

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

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

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\Section{Operations for Groups}%
\index{operations!for groups}

'<G> \^\ <s>'%
\index{conjugate!of a group}

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

\vspace{5mm}
'<s> in <G>'%
\index{membershiptest!for groups}

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 |

\vspace{5mm}
'<G> \*\ <s>'%
\index{product!of a group and a group element}

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.

\vspace{5mm}
'<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) ] )) |

\vspace{5mm}
'<G> / <N>'%
\index{quotient!of groups}

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

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\Section{Group Records}

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

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

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

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

'isDomain': \\
        is always 'true' as a group is a domain.

'isGroup': \\
        is of course 'true' as $G$ is a group.

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

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

'identity': \\
        is the group identity of $G$.

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

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

'abelianInvariants': \\
        a  list  of  integers  containing  the  abelian  invariants of an
        abelian group $G$.

'centralizer': \\
        contains the centralizer of $G$ in its parent group.

'centre': \\
        contains the centre of $G$. See "Centre".

'commutatorFactorGroup': \\
        contains     the commutator   factor   group   of     $G$.    See
        "CommutatorFactorGroup" for details.

'conjugacyClasses': \\
        contains   a  list  of   the conjugacy   classes   of  $G$.   See
        "ConjugacyClasses" for details.

'core': \\
        contains the core of $G$ under the action of  its  parent  group.
        See "Core" for details.

'derivedSubgroup':  \\   
        contains the derived subgroup of $G$. See "DerivedSubgroup".

'elements': \\
        is the set of all elements of $G$. See "Elements".

'fittingSubgroup': \\
        contains the Fitting subgroup of $G$. See "FittingSubgroup".

'frattiniSubgroup': \\
        contains the Frattini subgroup of $G$.  See "FrattiniSubgroup".

'index': \\
        contains the index of $G$ in its parent group. See "Index".

'lowerCentralSeries': \\
        contains the lower  central series of  $G$  as list of subgroups.
        See "LowerCentralSeries".

'normalizer': \\
        contains  the   normalizer  of  $G$  in  its  parent  group.  See
        "Normalizer" for details.

'normalClosure': \\
        contains the normal closure of  $G$  in  its  parent  group.  See
        "NormalClosure" for details.

'upperCentralSeries': \\
        contains the  upper central series  of $G$ as  list of subgroups.
        See "UpperCentralSeries".

'subnormalSeries': \\
        contains  a  subnormal series  from  the   parent of  $G$ down to
        $G$.  See "SubnormalSeries" for details.

'sylowSubgroups': \\
        contains a list of  Sylow subgroups  of $G$.  See "SylowSubgroup"
        for details.

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

'perfectSubgroups': \\
        contains  the a  list of  subgroups  which includes at  least one
        representative   of  each  class   of  conjugate  proper  perfect
        subgroups of $G$. See "Lattice".

'lattice': \\
        contains the subgroup lattice of $G$. See "Lattice".

'conjugacyClassesSubgroups': \\
        identical  to   the  list  '$G$.lattice.classes',   contains  the
        conjugacy    classes     of     subgroups     of     $G$.     See
        "ConjugacyClassesSubgroups".

'tableOfMarks': \\
        contains the table of narks of $G$. See "TableOfMarks".

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

'isAbelian': \\
        is 'true' if the group $G$ is abelian. See "IsAbelian".

'isCentral': \\
        is  'true'  if  the  group   $G$    is  central in   its   parent
        group.  See "IsCentral".

'isCyclic': \\
        is 'true' if the group $G$ is cyclic. See "IsCyclic".

'isElementaryAbelian': \\
        is  'true'  if   the  group  $G$    is   elementary  abelian. See
        "IsElementaryAbelian".

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

'isNilpotent': \\
        is 'true' if the group $G$ is nilpotent. See "IsNilpotent".

'isNormal': \\
        is  'true' if the group  $G$ is normal in its parent group.   See
        "IsNormal".

'isPerfect': \\
        is 'true' if the group $G$ is perfect. See "IsPerfect".

'isSimple': \\
        is 'true' if the group $G$ is simple. See "IsSimple".

'isSolvable': \\
        is 'true' if the group $G$ is solvable. See "IsSolvable".

'isSubnormal': \\
        is 'true' if the group $G$ is subnormal in its  parent group. See
        "IsSubnormal".

The component 'operations' contains  the *operations record* (see "Domain
Records" and "Dispatchers").



