%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%
%W  group.tex                 GAP documentation             Thomas Breuer
%W                                                         & Frank Celler
%W                                                     & Martin Schoenert
%W                                                       & Heiko Theissen
%%
%H  @(#)$Id: group.tex,v 4.38.2.2 2005/08/29 08:02:16 gap Exp $
%%
%Y  Copyright 1997,  Lehrstuhl D fuer Mathematik,  RWTH Aachen,   Germany
%%
%%  This file contains a tutorial introduction to groups.
%%


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\Chapter{Groups and Homomorphisms}

In this chapter we will show  some computations with groups. The examples
deal mostly with permutation groups, because they are the easiest 
to input.  The functions mentioned here, like `Group', `Size' or
`SylowSubgroup', however, are the same for all  kinds of groups, although
the algorithms which compute the information  of course will be different
in most cases.

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\Section{Permutation groups}

Permutation  groups  are so easy to  input  because their elements, i.e.,
permutations,  are  so easy to  type: they  are  entered and displayed in
disjoint cycle notation. So let's construct a permutation group:

\beginexample
gap> s8 := Group( (1,2), (1,2,3,4,5,6,7,8) );
Group([ (1,2), (1,2,3,4,5,6,7,8) ])
\endexample

We formed the group generated by the permutations `(1,2)' and
`(1,2,3,4,5,6,7,8)', which is well known to be the symmetric group on
eight points, and assigned it to the identifier `s8'.  Now the group
$S_8$ contains the alternating group on eight points which can be
described in several ways, e.g., as the group of all even permutations
in `s8', or as its derived subgroup.

\beginexample
gap> a8 := DerivedSubgroup( s8 );
Group([ (1,2,3), (2,3,4), (2,4)(3,5), (2,6,4), (2,4)(5,7), (2,8,6,4)(3,5) ])
gap> Size( a8 ); IsAbelian( a8 ); IsPerfect( a8 );
20160
false
true
\endexample

Once information about a group like `s8' or `a8' has been computed, it
is stored in the group so that  it can simply be looked  up when it is
required  again.   This holds for  all pieces   of  information in the
previous  example.  Namely,  `a8'  stores its  order and  that   it is
nonabelian  and perfect,  and `s8'  stores its  derived subgroup `a8'.
Had we computed `a8' as  `CommutatorSubgroup( s8,  s8 )', however,  it
would not have been stored,  because it would  then have been computed
as a function of *two* arguments, and hence one could not attribute it
to just one of them. (Of course  the function `CommutatorSubgroup' can
compute the commutator  subgroup  of *two* arbitrary  subgroups.)  The
situation is  a bit  different for  Sylow  <p>-subgroups: The function
`SylowSubgroup' also  requires  two arguments,  namely a   group and a
prime <p>, but the result is  stored in the  group --- namely together
with the prime  <p> in a  list called `ComputedSylowSubgroups', but we
won't dwell on the details here.

\beginexample
gap> syl2 := SylowSubgroup( a8, 2 );; Size( syl2 );
64
gap> Normalizer( a8, syl2 ) = syl2;
true
gap> cent := Centralizer( a8, Centre( syl2 ) );; Size( cent );
192
gap> DerivedSeries( cent );; List( last, Size );
[ 192, 96, 32, 2, 1 ]
\endexample

We have typed double semicolons  after some commands  to avoid the output
of the  groups   (which would  be  printed  by their  generator   lists).
Nevertheless, the beginner  is  encouraged to   type  a single  semicolon
instead and study the full output. This  remark also applies for the rest
of this tutorial.

With the next  examples, we want  to calculate a  subgroup of `a8', then
its  normalizer and finally determine the  structure of the extension. We
begin by forming a subgroup   generated by three commuting   involutions,
i.e., a subgroup  isomorphic to the   additive group of the  vector space
$2^3$.

\beginexample
gap> elab := Group( (1,2)(3,4)(5,6)(7,8), (1,3)(2,4)(5,7)(6,8),
>                   (1,5)(2,6)(3,7)(4,8) );;
gap> Size( elab );
8
gap> IsElementaryAbelian( elab );
true
\endexample

As usual, {\GAP} prints the group by giving  all its generators. This can
be annoying, especially if there are many of them or  if they are of huge
degree. It also makes  it difficult to recognize  a particular group when
there already several  around. Note  that  although it is no  problem for
*us* to    specify a particular  group to   {\GAP}, by  using well-chosen
identifiers such as `a8'  and `elab', it is  impossible for {\GAP} to use
these identifiers when printing  a group for us,  because the group  does
not know which identifier(s) point  to it, in fact  there can be several.
In order to    give a name  to  the  group  itself (rather   than  to the
identifier), you have to use the function `SetName'.  We do this with the
name `2^3' here which reflects  the mathematical properties of the group.
From now on,  {\GAP} will use  this name when  printing the group for us,
but we still cannot use this name to specify the group to {\GAP}, because
the name does  not know to which group   it was assigned (after  all, you
could assign the   same  name to several  groups).  When  talking  to the
computer, you must always use identifiers.

\beginexample
gap> SetName( elab, "2^3" ); elab;
2^3
gap> norm := Normalizer( a8, elab );; Size( norm );
1344
\endexample

\index{homomorphism!natural}
Now that  we  have the subgroup `norm'   of order 1344   and its subgroup
`elab', we want to look  at its factor  group. But since  we also want to
find preimages of factor group elements in `norm', we really want to look
at the  *natural homomorphism* defined on  `norm' with  kernel `elab' and
whose image is the factor group.

\beginexample
gap> hom := NaturalHomomorphismByNormalSubgroup( norm, elab );
<action epimorphism>
gap> f := Image( hom );
Group([ (), (), (), (4,5)(6,7), (4,6)(5,7), (2,3)(6,7), (2,4)(3,5), 
  (1,2)(5,6) ])
gap> Size( f );
168
\endexample

The factor group  is again represented as  a  permutation group. However,
the action domain  of this factor  group has  nothing  to do with  the
action domain of `norm'. (It only happens that both are subsets of the
natural numbers.) We can now form  images and preimages under the natural
homomorphism. The set of  preimages of an element under  `hom' is a coset
modulo `elab'. We use the function  `PreImages' here because `hom' is not
a bijection, so an  element of the range can   have several preimages  or
none at all.

\beginexample
gap> ker:= Kernel( hom );
2^3
gap> x := (1,8,3,5,7,6,2);; Image( hom, x );
(1,7,5,6,2,3,4)
gap> coset := PreImages( hom, last );
RightCoset(2^3,(2,8,6,7,3,4,5))
\endexample

Note that {\GAP} is free to choose any representative for the coset
of preimages.
Of course the quotient of two representatives lies in the kernel of
the homomorphism.

\beginexample
gap> rep:= Representative( coset );
(2,8,6,7,3,4,5)
gap> x * rep^-1 in ker;
true
\endexample

The factor  group `f'  is  a simple  group,  i.e., it has  no non-trivial
normal subgroups. {\GAP} can detect this fact,  and it can then also find
the name by which this simple group is known among group theorists. (Such
names are of course not available for non-simple groups.)

\beginexample
gap> IsSimple( f ); IsomorphismTypeInfoFiniteSimpleGroup( f );
true
rec( series := "L", parameter := [ 2, 7 ], 
  name := "A(1,7) = L(2,7) ~ B(1,7) = O(3,7) ~ C(1,7) = S(2,7) ~ 2A(1,7) = U(2\
,7) ~ A(2,2) = L(3,2)" )
gap> SetName( f, "L_3(2)" );
\endexample

We give `f' the name  `L_3(2)' because the  last part of the name  string
reveals that  it is isomorphic to  the simple linear group $L_3(2)$. This
group, however, also has a  lot of other  names. Names that are connected
with a  `=' sign  are different names   for the same matrix group,  e.g.,
`A(2,2)' is the  Lie type notation for  the  classical notation `L(3,2)'.
Other pairs  of  names are  connected via `~',  these then  specify other
classical  groups  that are isomorphic  to that  linear  group (e.g., the
symplectic group `S(2,7)', whose Lie type notation would be `C(1,7)').

The group `norm' acts on the eight elements of its normal subgroup `elab'
by conjugation,  yielding  a representation   of $L_3(2)$ in   `s8' which
leaves one    point  fixed  (namely  point~`1').    The   image of   this
representation can be computed with the function  `Action'; it is even
contained  in the group `norm' and  we can show  that `norm'  is indeed a
split extension of the elementary abelian group $2^3$  with this image of
$L_3(2)$.

\beginexample
gap> op := Action( norm, elab );
Group([ (), (), (), (5,6)(7,8), (5,7)(6,8), (3,4)(7,8), (3,5)(4,6), 
  (2,3)(6,7) ])
gap> IsSubgroup( a8, op ); IsSubgroup( norm, op );
true
true
gap> IsTrivial( Intersection( elab, op ) );
true
gap> SetName( norm, "2^3:L_3(2)" );
\endexample

By the way, you should not try the operator `\<'  instead of the function
`IsSubgroup'. Something like

\beginexample
gap> elab < a8;
false
\endexample

will not cause an error, but the result does not signify anything about the
inclusion of one group in another; `\<' tests  which of the two groups is
less in some total order. On the other hand, the equality operator `=' in
fact does test the equality of its arguments.

{\bf Summary.}   In  this section   we have   used   the elementary group
functions to determine  the structure of  a normalizer. We have  assigned
names  to the involved groups which  reflect their mathematical structure
and {\GAP} uses these names when printing the groups.

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\Section{Actions of Groups}

In  order to get  another  representation  of  `a8', we consider  another
action, namely  that on  the elements   of a  certain conjugacy  class by
conjugation.

In the following example we temporarily increase the line length limit
from its default value 80 to 82 in order to make the long expression fit
into one line.

\beginexample
gap> ccl := ConjugacyClasses( a8 );; Length( ccl );
14
gap> List( ccl, c -> Order( Representative( c ) ) );
[ 1, 2, 2, 3, 6, 3, 4, 4, 5, 15, 15, 6, 7, 7 ]
gap> SizeScreen([ 82, ]);;
gap> List( ccl, Size );
[ 1, 210, 105, 112, 1680, 1120, 2520, 1260, 1344, 1344, 1344, 3360, 2880, 2880 ]
gap> SizeScreen([ 80, ]);;
\endexample

Note  the  difference between `Order'  (which   means the element order),
`Size' (which means the size of the conjugacy  class) and `Length' (which
means the length of  a list). We choose to  let `a8' operate on the class
of length~112.

\beginexample
gap> class := First( ccl, c -> Size(c) = 112 );;
gap> op := Action( a8, AsList( class ) );;
\endexample

We use `AsList' here  to convert the conjugacy class  into a list  of its
elements whereas we   wrote  `Action( norm,  elab )'   directly in the
previous section. The reason is that  the elementary abelian group `elab'
can  be quickly enumerated by   {\GAP}  whereas the standard  enumeration
method for conjugacy classes is  slower than just explicit calculation of
the elements. However, {\GAP} is reluctant  to construct explicit element
lists, because for really large groups this direct method is infeasible.

Note also  the function `First', used to  find the  first element in a
list which  passes some test. See  "ref:First" in the reference manual
for more details.

We now have a permutation representation `op' on 112 points, which we
test for primitivity. If it is not primitive, we can obtain a minimal
block system (i.e., one where the blocks have minimal length) by the
function `Blocks'.

\beginexample
gap> IsPrimitive( op, [ 1 .. 112 ] );
false
gap> blocks := Blocks( op, [ 1 .. 112 ] );;
\endexample

Note that we  must specify the domain  of the action. You  might think
that the   functions `IsPrimitive' and `Blocks'  could  use `[1..112]' as
default  domain if no  domain was  given. But  this  is not so  easy, for
example  would the default domain  of `Group(  (2,3,4)  )' be `[1..4]' or
`[2..4]'? To  avoid confusion, all action  functions  require that you
specify  the domain of action. If  we had specified  `[1..113]' in the
primitivity test above,  point~113  would have been  a fixpoint  (and the
action would not even have been transitive).

Now `blocks' is a list of blocks (i.e., a list of lists), which we do not
print  here for the  sake of saving paper (try  it for yourself). In fact
all we want to know is the size of  the blocks, or  rather how many there
are (the product of these two numbers must of course be~112). Then we can
obtain a new  permutation group  of the  corresponding  degree by letting
`op' act on these blocks setwise.

\beginexample
gap> Length( blocks[1] );  Length( blocks );
2
56
gap> op2 := Action( op, blocks, OnSets );;
gap> IsPrimitive( op2, [ 1 .. 56 ] );
true
\endexample

Note that we give a third argument (the action function `OnSets') to
indicate that the action is not the default action on points but an
action on sets of elements given as sorted lists.
(Section~"ref:Basic Actions" of the reference manual lists all
actions that are pre-defined by {\GAP}.)

The action of `op' on the given block system gave us a new representation
on 56 points which is primitive, i.e., the  point stabilizer is a maximal
subgroup. We  compute its preimage in the  representation on eight points
using the   associated   action homomorphisms (which   of   course are
monomorphisms). We construct  the  composition of two  homomorphisms with
the `*' operator, reading left-to-right.

\beginexample
gap> ophom := ActionHomomorphism( a8, op );;
gap> ophom2 := ActionHomomorphism( op, op2 );;
gap> composition := ophom * ophom2;;
gap> stab := Stabilizer( op2, 2 );;
gap> preim := PreImages( composition, stab );
Group([ (1,4,2), (3,6,7), (3,8,5,7,6), (1,4)(7,8) ])
\endexample

The normalizer of an element in the conjugacy class `class' is a group of
order 360, too. In fact, it is a conjugate of the maximal subgroup we had
found before, and a conjugating element in `a8'  is found by the function
`RepresentativeAction'.

\beginexample
gap> sgp := Normalizer( a8, Subgroup(a8,[Representative(class)]) );;
gap> Size( sgp );
360
gap> RepresentativeAction( a8, sgp, preim );
(3,4)(7,8)
\endexample
% The scalar product  of permutation characters  of two subgroups <U>, <V>,
% say, equals  the number  of $(<U>,<V>)$-double  cosets. For example,  the
% norm of  the natural permutation character of  degree  eight is two since
% the action of `a8' on the cosets of a point stabilizer is at least doubly
% transitive. We   also   compute  the   numbers  of    $(`sgp',`sgp')$ and
% $(`sgp',`stab')$ double cosets.
% \b eginexample
% gap> stab := Stabilizer( a8, 1 );;
% gap> Length( DoubleCosets( a8, stab, stab ) );
% 2
% gap> Length( DoubleCosets( a8, sgp, sgp ) );
% 4
% gap> Length( DoubleCosets( a8, sgp, stab ) );
% 2
% \e ndexample

\index{homomorphism!operation} \index{homomorphism!action}\index{external set}
So far we have seen  a few applications  of the functions `Action' and
`ActionHomomorphism'. But perhaps even  more  interesting is the  fact
that  the  natural  homomorphism `hom'   constructed  above  is  also  an
*action  homomorphism*;  this  is also  the  reason  why its image  is
represented as a permutation group:  it is the natural representation for
actions. We will now look at this action homomorphism again to find
out on what   objects it  operates.  These  objects  form the   so-called
*external set* which is  associated with every action homomorphism. We
will  mention  external sets  only   superficially in this  tutorial, for
details see "ref:External Sets" in the  reference manual. For the moment,
we need   only know that   the external set is  obtained  by the function
`UnderlyingExternalSet'.

\beginexample
gap> t := UnderlyingExternalSet( hom );
<xset:RightTransversal(2^3:L_3(2),Group(
[ (1,5)(2,6)(3,7)(4,8), (1,3)(2,4)(5,7)(6,8), (1,2)(3,4)(5,6)(7,8), 
  (5,6)(7,8), (5,7)(6,8), (3,4)(7,8), (3,5)(4,6) ]))>
\endexample

\index{right transversal}
For  the   natural homomorphism   `hom' the  external   set  is a  *right
transversal* of a subgroup  <U>   in `norm',  and   action on the   right
transversal really means action  on the cosets  of the subgroup <U>. When
executing  the function  call `NaturalHomomorphismByNormalSubgroup( norm,
elab )', {\GAP} has  chosen a subgroup  <U> for which  the kernel of this
action (i.e., the core of  <U> in `norm')  is the desired normal subgroup
`elab'. For the purpose of operating on the cosets, the right transversal
`t' contains  one representative  from each coset  of <U>.  Regarded this
way, a transversal  is simply a list of  group elements, and you can make
{\GAP} produce this list by `AsList(t)'. (Try it.)

The  image of  such   a   representative from  `AsList(t)' under    right
multiplication with an  element  from `norm'  will in general  not be  in
`AsList(t)',  because it will   not  be among the  chosen representatives
again.   Hence right multiplication is not   an action on `AsList(t)'.
However, {\GAP} uses a special trick to be discussed below to make this a
well-defined  action  on the  cosets   represented by the  elements of
`AsList(t)'. For now, it is important  to know that  the external set `t'
is   more  than just the  right  transversal  on  which  the group `norm'
operates. Altogether three things  are necessary to specify an action:
a  group~<G>, a  set~<D>, and a   function $<opr>\colon <D>\times  <G>\to
<D>$. We can access these ingredients with the following functions:

\beginexample
gap> ActingDomain(t);  # the group
2^3:L_3(2)
gap> Enumerator(t);
RightTransversal(2^3:L_3(2),Group(
[ (1,5)(2,6)(3,7)(4,8), (1,3)(2,4)(5,7)(6,8), (1,2)(3,4)(5,6)(7,8), 
  (5,6)(7,8), (5,7)(6,8), (3,4)(7,8), (3,5)(4,6) ]))
gap> FunctionAction(t);
function( pnt, elm ) ... end
gap> NameFunction( last );
"OnRight"
\endexample

The function  which   is  named  `"OnRight"'  is  also   assigned to  the
identifier `OnRight', and it means multiplication from the right; this is
the usual way to operate on a right transversal. `OnRight( <d>, <g> )' is
defined as `<d> * <g>'.

%\exercise In analogy to `OnRight'  you might expect a function  `OnLeft',
%but  actually    there   are    two    functions    `OnLeftInverse'   and
%`OnLeftAntiOperation'. How are they defined and why?
%
%\answer   `OnLeftInverse(  <d>,  <g>  )'  means   `<g>^-1 *  <d>',  i.e.,
%multiplication  with the  inverse   from   the  left, which defines    an
%operation. In contrast,  the mapping $<left>\colon (<d>,<g>) \mapsto <g>
%* <d>$ does not yield an operation, but an anti-operation, i.e., $<left>(
%<left>( <d>,  <g>_1 ), <g>_2  ) = <left>( <d>, <g>_2  * <g>_1 )$, whereas
%for an  operation, the  right hand side  is required  to have the product
%$<g>_1 * <g>_2$.  The {\GAP} function which  performs this mapping <left>
%is therefore called  `OnLeftAntiOperation', and, unlike  `OnLeftInverse',
%this cannot be used as last argument to an operation function.

\index{enumerator}
Observe  that the external set `t'  and  its `Enumerator' are printed the
same way, but  be aware that an   external set also comprises  the acting
domain  and the action function.  The  `Enumerator' itself, i.e.,  the
right transversal, in turn comprises knowledge about the group `norm' and
the  subgroup <U>,  and  this is what  allows  the special trick promised
above. As far as `Position' is  concerned, the `Enumerator' behaves as an
(immutable) list and you can ask for the position of an element in it.

\beginexample
gap> elm := (1,4)(2,7)(3,6)(5,8);;
gap> Position( Enumerator(t), elm );
fail
gap> PositionCanonical( Enumerator(t), elm );
5
\endexample

\atindex{Position vs. PositionCanonical}{@\noexpand `Position' vs.\ %
\noexpand `PositionCanonical'}
The result `fail'   means that the element was   not found at  all in the
list: it is not among the chosen  representatives. The difference between
the functions `Position' and `PositionCanonical' is that the first simply
looks whether `elm' is contained among the representatives which together
form the  right transversal `t', whereas  the second really looks for the
position of the  coset described by  the  representative `elm'. In  other
words, it first replaces `elm' by a  canonical representative of the same
coset (which must be contained in `Enumerator(t)') and then looks for its
position, hence the name. The  function `ActionHomomorphism' (and  its
relatives) always use  `PositionCanonical' when they calculate the images
of   the  generators of  the    source  group (here,  `norm')   under the
homomorphism  (here, `hom').  Therefore  they  can  give a   well-defined
action on an   <enumerator>, even   if the   action  would not   be
well-defined on `AsList( <enumerator> )'.

%\exercise   What   would     be  the  result    of   the  function   call
%`PositionCanonical( AsList(t), elm )' (where `AsList(t)' is equivalent to
%`AsList(Enumerator(t))')?
%
%\answer `fail', because `AsList(t)'  is simply a list of  representatives
%without  any knowledge about the  cosets  they represent. In other words,
%{\GAP}    does not  know  that  they   are   representatives, and so  the
%``canonical representative'' associated with `elm' is `elm' itself, which
%is not among the elements of the list.

The image of  the natural homomorphism  is the permutation group `f' that
results from the action of `norm' on the right  transversal. It can be
calculated by either of the following commands. The second of them shows
that the external set `t' contains all information  that is necessary for
`Action' to do its work.

\beginexample
gap> Action( norm, Enumerator(t), OnRight ) = f;
true
gap> Action( t ) = f;
true
\endexample

We  have specified the action function  `OnRight' in this example, but
we have seen  examples like `Action( norm,  elab )' earlier where this
third argument was not given. If an action function is omitted, {\GAP}
always assumes `OnPoints' which is defined as `OnPoints( <d>, <g> ) = <d>
^ <g>'. This ``caret''  operator denotes conjugation in  a group if  both
arguments <d> and  <g> are group elements  (contained in a common group),
but it also  denotes the natural  action  of permutations on  positive
integers (and exponentiation of integers as well, of course).

%\exercise Could   these  several meanings    of  `<d>  ^ <g>'   lead   to
%ambiguities?
%
%\answer Yes, if <d> is a cyclotomic and <g> a positive integer, then `<d>
%^ <g>' could mean exponentiation  as well as conjugation  in the group of
%non-zero cyclotomics.  To   avoid such  ambiguities, {\GAP}   refuses  to
%construct groups of cyclotomic numbers.

% \exercise What difference does  it make whether something  is stored in a
% record  component   like `hom!.externalSet'   or   as  an attribute  like
% `Enumerator(t)'?
%  
% \answer  A record component  like `hom!.externalSet' must be entered when
% the object `hom'  is constructed, which makes  sense because an operation
% homomorphism   like  `hom' is  constructed for     a given external  set.
% Attributes like `Enumerator(t)' need not  be set upon construction of the
% object, they can be computed  and stored when  they are required for  the
% first time and subsequently be looked up. This  mechanism is explained in
% section~"Attributes".

{\bf Summary.} In this section we have learned  how groups can operate on
{\GAP}   objects such as  integers  and   group  elements.  We  have used
`ActionHomomorphism',    among   others,   to   construct   a  natural
homomorphism,  in which case the  group operated on the right transversal
of a suitable subgroup. This right transversal gave us an example for the
use of `PositionCanonical', which allowed  us to specify cosets by giving
representatives.

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\Section{Subgroups!as Stabilizers}

Action functions can also be  used without constructing external sets.
We will try to   find several subgroups  in `a8'  as stabilizers of  such
actions. One subgroup is immediately  available, namely the stabilizer
of one point. The index of the stabilizer must of course  be equal to the
length of the orbit, i.e.,~8.

\beginexample
gap> u8 := Stabilizer( a8, 1 );
Group([ (2,3,4), (2,4)(3,5), (2,6,4), (2,4)(5,7), (2,8,6,4)(3,5) ])
gap> Index( a8, u8 );
8
gap> Orbit( a8, 1 ); Length( last );
[ 1, 3, 2, 4, 5, 6, 7, 8 ]
8
\endexample

This gives us a hint how to find further  subgroups. Each subgroup is the
stabilizer of a point of an appropriate  transitive action (namely the
action  on  the cosets of that  subgroup  or another action that is
equivalent to  this action).  So the question   is how  to find  other
actions. The obvious thing is to operate  on pairs of points. So using
the function `Tuples' we first generate a list of all pairs.

\beginexample
gap> pairs := Tuples( [1..8], 2 );;
\endexample

Now we would like to have `a8' operate on this  domain. But we cannot use
the  default action `OnPoints'  because    `<list> ^ <perm>' is    not
defined. So we  must tell the functions  from the actions package  how
the group elements operate on the elements of  the domain. In our example
we can do this by simply passing `OnPairs' as an optional last argument.
All functions from the actions package accept such an optional argument
that describes the action. One example is `IsTransitive'.

\beginexample
gap> IsTransitive( a8, pairs, OnPairs );
false
\endexample

The action is of course not transitive, since the pairs `[ 1, 1 ]' and
`[ 1, 2 ]' cannot lie in the same orbit.
So we want to  find out what the orbits are.
The function `Orbits' does that for us.
It returns a list of all the orbits.
We look at the orbit lengths and representatives for the orbits.

\beginexample
gap> orbs := Orbits( a8, pairs, OnPairs );; Length( orbs );
2
gap> List( orbs, Length );
[ 8, 56 ]
gap> List( orbs, o -> o[1] );
[ [ 1, 1 ], [ 1, 2 ] ]
\endexample

The action of `a8'   on the first  orbit (this  is the one  containing
`[1,1]', try `[1,1] in orbs[1]') is of  course equivalent to the original
action, so we ignore it and work with the second orbit.

\beginexample
gap> u56 := Stabilizer( a8, orbs[2][1], OnPairs );; Index( a8, u56 );
56
\endexample

So   now   we have  found   a  second subgroup.   To   make the following
computations a little bit easier and more efficient  we would now like to
work on the points `[1..56]'  instead of the list  of pairs. The function
`ActionHomomorphism' does what  we need.   It creates a   homomorphism
defined on `a8' whose image is a new group  that operates on `[1..56]' in
the same way that `a8' operates on the second orbit.

\beginexample
gap> h56 := ActionHomomorphism( a8, orbs[2], OnPairs );;
gap> a8_56 := Image( h56 );;
\endexample

We would now like to know if the subgroup `u56' of index 56 that we found
is  maximal or  not.
As we have used already in Section~"Actions of groups",
a subgroup is maximal if and only if the action on the cosets of this
subgroup is primitive.

\beginexample
gap> IsPrimitive( a8_56, [1..56] );
false
\endexample

Remember that we  can leave out the  function  if we mean  `OnPoints' but
that we have to specify the action domain for all action functions.

%\exercise What happens if  you call a function  like `Operation( <G>, <D>
%)',  where the group  <G>  moves points  that are   not contained in  the
%operation domain~<D>?
%
%\answer If the  operation domain <D> is  closed  under the action  of the
%group <G>, i.e., if  it is a union of  orbits, `Operation' will construct
%the operation only on that domain, i.e.,  it will compute the restriction
%of <G> to~<D>. If  the operation domain  is  not closed, however,  {\GAP}
%will   fail to construct  the     generating permutations and return    a
%`MagmaWithInverses( [ fail,  \dots,  fail  ] )',  which  is no  good  for
%further computations. An exception to this rule is the function `Orbits':
%if  <D> is not   closed under <G>, then    `Orbits( <G>, <D> )'  silently
%replaces  <D> by its  closure under <G>  and then computes the orbits. In
%other words, it  computes all <G>-orbits that contain  at least one point
%from the original~<D>.

We see that `a8_56'   is not primitive. This  means  of course   that the
action  of `a8'  on  `orb[2]'  is not  primitive,  because those   two
actions are equivalent. So the stabilizer `u56' is not maximal. Let us
try to find its supergroups. We use the function `Blocks' to find a block
system. The  (optional) third  argument  in the following   example tells
`Blocks' that we want a block system where 1 and 14 lie in one block.

\beginexample
gap> blocks := Blocks( a8_56, [1..56], [1,14] );
[ [ 1, 3, 4, 5, 6, 14, 31 ], [ 2, 13, 15, 16, 17, 23, 24 ], 
  [ 7, 8, 22, 34, 37, 47, 49 ], [ 9, 11, 18, 20, 35, 38, 48 ], 
  [ 10, 25, 26, 27, 32, 39, 50 ], [ 12, 28, 29, 30, 33, 36, 40 ], 
  [ 19, 21, 42, 43, 45, 46, 55 ], [ 41, 44, 51, 52, 53, 54, 56 ] ]
\endexample

The result is a list  of sets, such that  `a8_56' operates on those sets.
Now we would like  the stabilizer of this  action on the sets. Because
we  want to operate on   the sets we  have  to  pass `OnSets' as  third
argument.

\beginexample
gap> u8_56 := Stabilizer( a8_56, blocks[1], OnSets );;
gap> Index( a8_56, u8_56 );
8
gap> u8b := PreImages( h56, u8_56 );; Index( a8, u8b );
8
gap> IsConjugate( a8, u8, u8b );
true
\endexample

So we have found a supergroup of `u56' that is conjugate in `a8' to `u8'.
This is not surprising, since `u8' is a point stabilizer, and `u56' is a
two point stabilizer in the natural action of `a8' on eight points.

Here  is a *warning*:   If you specify `OnSets'  as  third argument  to a
function like  `Stabilizer', you have to  make sure that the  point (i.e.
the second argument) is  indeed a set. Otherwise you  will get a puzzling
error message or  even  wrong results! In  the above  example, the second
argument  `blocks[1]'  came from the  function  `Blocks', which returns a
list of sets, so everything was OK.

Actually there  is a third  block system of `a8_56'  that gives rise to a
third subgroup.

\beginexample
gap> blocks := Blocks( a8_56, [1..56], [1,13] );;
gap> u28_56 := Stabilizer( a8_56, [1,13], OnSets );;
gap> u28 := PreImages( h56, u28_56 );;
gap> Index( a8, u28 );
28
\endexample

We know that  the subgroup `u28' of index  28 is maximal, because we know
that  `a8' has no  subgroups  of index 2,  4,  or 7.  However we can also
quickly verify this by checking  that `a8_56' operates primitively on the
28 blocks.

\beginexample
gap> IsPrimitive( a8_56, blocks, OnSets );
true
\endexample

`Stabilizer' is not only applicable to groups like `a8' but also to their
subgroups like  `u56'. So another  method  to find  a  new subgroup is to
compute the stabilizer of another point in `u56'. Note that `u56' already
leaves 1 and 2 fixed.

\beginexample
gap> u336 := Stabilizer( u56, 3 );;
gap> Index( a8, u336 );
336
\endexample

Other  functions  are also applicable  to  subgroups. In the following we
show that  `u336' operates regularly on the  60~triples of `[4..8]' which
contain no element twice. We  constuct the list  of these 60~triples with
the function `Orbit' (using `OnTuples'  as the natural generalization  of
`OnPairs')  and   then  pass it   as  action domain  to   the function
`IsRegular'.  The positive result of  the regularity test means that this
action is equivalent  to the actions of `u336'  on  its 60 elements
from the right.

\beginexample
gap> IsRegular( u336, Orbit( u336, [4,5,6], OnTuples ), OnTuples );
true
\endexample

Just as we did in the  case of the  action on the  pairs above, we now
construct a new permutation group that operates on `[1..336]' in the same
way that `a8' operates on the cosets of `u336'. But this time we let `a8'
operate  on a right   transversal, just like  `norm'  did in  the natural
homomorphism above.

\beginexample
gap> t := RightTransversal( a8, u336 );;
gap> a8_336 := Action( a8, t, OnRight );;
\endexample

To find  subgroups above `u336' we again look for nontrivial block systems.

\beginexample
gap> blocks := Blocks( a8_336, [1..336] );; blocks[1];
[ 1, 43, 85 ]
\endexample

We see that the union of `u336' with its 43rd and its 85th coset
is a subgroup in `a8_336', its index is 112.
We can obtain it as the closure of `u336' with a representative
of the  43rd coset, which can be found as the 43rd element
of the transversal~`t'.
Note that in the representation `a8_336' on 336 points,
this subgroup corresponds to the stabilizer of the block `[ 1, 43, 85 ]'.

\beginexample
gap> u112 := ClosureGroup( u336, t[43] );;
gap> Index( a8, u112 );
112
\endexample

Above this subgroup of index 112 lies a  subgroup  of index 56, which  is
not conjugate to `u56'.  In fact, unlike `u56' it is  maximal.  We obtain
this subgroup in  the same way that we obtained `u112', this time forcing
two points, namely 7 and 43 into the first block.

\beginexample
gap> blocks := Blocks( a8_336, [1..336], [1,7,43] );;
gap> Length( blocks );
56
gap> u56b := ClosureGroup( u112, t[7] );; Index( a8, u56b );
56
gap> IsPrimitive( a8_336, blocks, OnSets );
true
\endexample

We  already mentioned  in Section~"Actions of groups"
that there is another  standard
action of permutations, namely the  conjugation.
E.g., since no  other action is specified  in the  following example,
`OrbitLength' simply operates via `OnPoints',
and because `$<perm>_1$ ^ $<perm>_2$' is defined as the conjugation
of $perm_2$ on $perm_1$, in fact we compute the length of
the conjugacy class of `(1,2)(3,4)(5,6)(7,8)'.

\beginexample
gap> OrbitLength( a8, (1,2)(3,4)(5,6)(7,8) );
105
gap> orb := Orbit( a8, (1,2)(3,4)(5,6)(7,8) );;
gap> u105 := Stabilizer( a8, (1,2)(3,4)(5,6)(7,8) );; Index( a8, u105 );
105
\endexample

Note that although the length of a conjugacy class of any element <elm>
in any finite group <G> can be computed as `OrbitLength( <G>, <elm> )',
the command `Size( ConjugacyClass( <G>, <elm> ) )' is probably more
efficient.

\beginexample
gap> Size( ConjugacyClass( a8, (1,2)(3,4)(5,6)(7,8) ) );
105
\endexample

Of course the stabilizer `u105' is in fact the centralizer of the element
`(1,2)(3,4)(5,6)(7,8)'.  `Stabilizer' notices    that and computes    the
stabilizer using the centralizer algorithm for permutation groups. In the
usual way we now look for the subgroups above `u105'.

\beginexample
gap> blocks := Blocks( a8, orb );; Length( blocks );
15
gap> blocks[1];
[ (1,2)(3,4)(5,6)(7,8), (1,3)(2,4)(5,7)(6,8), (1,4)(2,3)(5,8)(6,7), 
  (1,5)(2,6)(3,7)(4,8), (1,6)(2,5)(3,8)(4,7), (1,7)(2,8)(3,5)(4,6), 
  (1,8)(2,7)(3,6)(4,5) ]
\endexample

To find the subgroup of index 15 we  again use closure. Now  we must be a
little bit  careful to avoid    confusion. `u105' is the  stabilizer   of
`(1,2)(3,4)(5,6)(7,8)'. We  know  that there is  a correspondence between
the  points  of  the   orbit and  the   cosets  of  `u105'.   The   point
`(1,2)(3,4)(5,6)(7,8)' corresponds   to `u105'.
To get the subgroup above `u105' that has index 15 in `a8',
we must form the closure of `u105' with an element of the coset that
corresponds to any other point in the first block.
If we choose the point `(1,3)(2,4)(5,8)(6,7)',
we must use an element of `a8' that maps `(1,2)(3,4)(5,6)(7,8)' to
`(1,3)(2,4)(5,8)(6,7)'.
The function `RepresentativeAction' does what we need.
It takes a group and two points and returns an element of the group
that maps the first point to the second.
In fact it also allows you to specify the action as an optional fourth
argument as usual, but we do not need this here.
If no such element exists in the  group, i.e., if the two points do not
lie in one orbit under the group,
`RepresentativeAction' returns `fail'.

\beginexample
gap> rep := RepresentativeAction( a8, (1,2)(3,4)(5,6)(7,8),
>                                        (1,3)(2,4)(5,8)(6,7) );
(2,3)(6,8)
gap> u15 := ClosureGroup( u105, rep );; Index( a8, u15 );
15
\endexample

`u15' is of course a maximal  subgroup, because `a8'  has no subgroups of
index 3 or~5.  There is in fact  another  class of subgroups  of index 15
above `u105' that we get by adding `(2,3)(6,7)' to `u105'.

\beginexample
gap> u15b := ClosureGroup( u105, (2,3)(6,7) );; Index( a8, u15b );
15
gap> RepresentativeAction( a8, u15, u15b );
fail
\endexample

`RepresentativeAction' tells us that  there is no  element <g> in `a8'
such that `u15 ^ <g> = u15b'. Because `^' also denotes the conjugation of
subgroups this tells us  that  `u15' and  `u15b' are not  conjugate.

{\bf  Summary.} In this section we  have demonstrated some functions from
the actions package. There  is a whole class of  functions that we did
not mention, namely  those that take a  single element instead of a whole
group as first argument, e.g., `Cycle' and `Permutation'. These are fully
described  in Chapter "ref:Group Actions"  in the  reference
manual.

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\Section{Group Homomorphisms!by Images}

We   have already  seen  examples of   group homomorphisms  in  the  last
sections,  namely natural homomorphisms  and  action homomorphisms. In
this section we will show how to construct a  group homomorphism $G\to H$
by specifying a generating set for $G$ and the images of these generators
in~$H$. We use the function `GroupHomomorphismByImages( <G>, <H>, <gens>,
<imgs> )' where <gens> is a  generating set for <G> and  <imgs> is a list
whose $i$th entry is the image of `<gens>[ $i$ ]' under the homomorphism.

\beginexample
gap> s4 := Group((1,2,3,4),(1,2));; s3 := Group((1,2,3),(1,2));;
gap> hom := GroupHomomorphismByImages( s4, s3,
>           GeneratorsOfGroup(s4), [(1,2),(2,3)] );
[ (1,2,3,4), (1,2) ] -> [ (1,2), (2,3) ]
gap> Kernel( hom );
Group([ (1,4)(2,3), (1,3)(2,4) ])
gap> Image( hom, (1,2,3) );
(1,2,3)
gap> Image( hom, DerivedSubgroup(s4) );
Group([ (1,3,2), (1,3,2) ])
\endexample

%notest
\beginexample
gap> PreImage( hom, (1,2,3) );
Error, <map> must be an inj. and surj. mapping called from
<function>( <arguments> ) called from read-eval-loop
Entering break read-eval-print loop ...
you can 'quit;' to quit to outer loop, or
you can 'return;' to continue
brk> quit;
\endexample

\beginexample
gap> PreImagesRepresentative( hom, (1,2,3) );
(1,4,2)
gap> PreImage( hom, TrivialSubgroup(s3) );  # the kernel
Group([ (1,4)(2,3), (1,3)(2,4) ])
\endexample

This homomorphism  from $S_4$ onto  $S_3$  is well known  from elementary
group theory.  Images   of elements and  subgroups  under   `hom' can  be
calculated with the function `Image'. But since the mapping `hom' is  not
bijective, we  cannot use   the   function `PreImage' for  preimages   of
elements  (they can have   several preimages). Instead,   we have  to use
`PreImagesRepresentative', which  returns  one  preimage if at  least one
exists (and would  return `fail' if none  exists, which  cannot occur for
our surjective `hom'.)  On the other hand, we  can use `PreImage' for the
preimage of a set (which always exists, even if it  is empty).

Suppose we mistype the input when trying to construct a homomorphism,
as in the following example.

\beginexample
gap> GroupHomomorphismByImages( s4, s3,
>        GeneratorsOfGroup(s4), [(1,2,3),(2,3)] );
fail
\endexample

There is no such homomorphism, hence `fail' is returned.
But note that because of this, `GroupHomomorphismByImages' must do
some checks, and this was also done for the mapping `hom' above.
One can avoid these checks if one is sure that the desired
homomorphism really exists.
For that, the function `GroupHomomorphismByImagesNC' can be used;
the `NC' stands for ``no check''.

But note that horrible things can happen if `GroupHomomorphismByImagesNC'
is used when the input does not describe a homomorphism.

\beginexample
gap> hom2 := GroupHomomorphismByImagesNC( s4, s3,
>            GeneratorsOfGroup(s4), [(1,2,3),(2,3)] );
[ (1,2,3,4), (1,2) ] -> [ (1,2,3), (2,3) ]
gap> Size( Kernel(hom2) );
24
\endexample

In other words, {\GAP} claims that the kernel is the full `s4',
yet `hom2' obviously has some non-trivial images!
Clearly there is no such thing as a homomorphism
which maps an element of order~4 (namely, (1,2,3,4))
to an element of order~3 (namely, (1,2,3)).
*But if you use the command `GroupHomomorphismByImagesNC',
{\GAP} trusts you.*

\beginexample
gap> IsGroupHomomorphism( hom2 );
true
\endexample

And then it produces serious nonsense if the thing is not a homomorphism,
as seen above!

Besides the safe command `GroupHomomorphismByImages',
which returns `fail' if the requested homomorphism does not exist,
there is the function `GroupGeneralMappingByImages',
which returns a general mapping (that is, a possibly multi-valued
mapping) that can be tested with `IsGroupHomomorphism'.

\beginexample
gap> hom2 := GroupGeneralMappingByImages( s4, s3,
>            GeneratorsOfGroup(s4), [(1,2,3),(2,3)] );;
gap> IsGroupHomomorphism( hom2 );
false
\endexample

\index{group general mapping}\index{cokernel}\index{kernel}
\atindex{GroupHomomorphismByImages vs. GroupGeneralMappingByImages}%
{@\noexpand `GroupHomomorphismByImages' vs.\ %
\noexpand `GroupGeneralMappingByImages'}
But the  possibility of testing for being  a homomorphism is not the only
reason  why    {\GAP} offers  *group   general  mappings*.  Another (more
important?) reason is that  their existence allows ``reversal of arrows''
in a  homomorphism such   as  our original  `hom'. By   this we mean  the
`GroupHomomorphismByImages' with left and right sides exchanged, in which
case it is of course merely a `GroupGeneralMappingByImages'.

\beginexample
gap> rev := GroupGeneralMappingByImages( s3, s4,
>           [(1,2),(2,3)], GeneratorsOfGroup(s4) );;
\endexample

Now we have 
$a {\buildrel hom\over\longmapsto} b \iff b {\buildrel rev\over\longmapsto} a$
for $a\in `s4'$ and $b\in `s3'$. Since every
such $b$ has 4~preimages under `hom', it now has 4~images under `rev'.
Just as the 4~preimages form a coset of the kernel $V_4\le `s4'$ of
`hom', they also form a coset of the *cokernel* $V_4\le `s4'$ of
`rev'.  The cokernel itself is the set of all images of `One( s3 )'
(it is a normal subgroup in the group of all images under `rev'). The
operation 'One' returns the identity element of a group, see "ref:One"
in the reference manual.  And this is why {\GAP} wants to perform such
a reversal of arrows: it calculates the kernel of a homomorphism like
`hom' as the cokernel of the reversed group general mapping (here `rev').

\beginexample
gap> CoKernel( rev );
Group([ (1,4)(2,3), (1,3)(2,4) ])
\endexample

\index{group general mapping!single-valued}
\index{group general mapping!total}
The  reason  why  `rev'   is not  a    homomorphism is  that   it is  not
single-valued  (because `hom' was   not injective). But there  is another
critical  condition: If   we   reverse the arrows   of  a  non-surjective
homomorphism,  we  obtain a group  general mapping  which  is not defined
everywhere, i.e.,  which is not total  (although it will be single-valued
if the original homomorphism is  injective). {\GAP} requires that a group
homomorphism be  both  single-valued  and total,
so you will get `fail' if you say
`GroupHomomorphismByImages( <G>, <H>, <gens>, <imgs> )' where <gens> does
not generate <G> (even if this would give a decent homomorphism on the
subgroup generated by <gens>).  For a full description,
see Chapter "ref:Group Homomorphisms" in the reference manual.

The last  example of this   section shows that  the  notion of kernel and
cokernel naturally extends even to the case  where neither `hom2' nor its
inverse general mapping (with arrows reversed) is a homomorphism.

\beginexample
gap> CoKernel( hom2 );  Kernel( hom2 );
Group([ (2,3), (1,3) ])
Group([ (3,4), (2,3,4), (1,2,4) ])
gap> IsGroupHomomorphism( InverseGeneralMapping( hom2 ) );
false
\endexample

{\bf  Summary.}   In this section   we  have constructed homomorphisms by
specifying images for a set of generators. We have seen that by reversing
the direction of  the mapping, we get  group general mappings, which need
not be single-valued (unless the mapping was injective) nor total (unless
the mapping was surjective).

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\Section{Nice Monomorphisms}

For some types of groups, the best method to calculate in an isomorphic
group in a ``better'' representation (say, a permutation group).  We call an
injective homomorphism, that will give such an isomorphic image a ``nice
monomorphism''.

For example in the case of a matrix group we can take the action on the
underlying vector space (or a suitable subset) to obtain such a
monomorphism:

\beginexample
gap> grp:=GL(2,3);;
gap> dom:=GF(3)^2;;
gap> hom := ActionHomomorphism( grp, dom );; IsInjective( hom );
true
gap> p := Image( hom,grp );
Group([ (4,7)(5,8)(6,9), (2,7,6)(3,4,8) ])
\endexample

To  demonstrate the technique  of   nice  monomorphisms, we  compute  the
conjugacy classes of the  permutation group and  lift them back into  the
matrix group with the monomorphism `hom'. Lifting  back a conjugacy class
means finding the preimage of  the representative and of the centralizer;
the latter  is   called  `StabilizerOfExternalSet'   in {\GAP}   (because
conjugacy  classes are represented as   external sets, see
Section~"ref:Conjugacy Classes" in the reference manual).

\beginexample
gap> pcls := ConjugacyClasses( p );; gcls := [  ];;
gap> for pc  in pcls  do
>      gc:=ConjugacyClass(grp,PreImagesRepresentative(hom,Representative(pc)));
>      SetStabilizerOfExternalSet(gc,PreImage(hom,
>                                 StabilizerOfExternalSet(pc)));
>      Add( gcls, gc );
>    od;
gap> List( gcls, Size );
[ 1, 8, 12, 1, 8, 6, 6, 6 ]
\endexample

All the steps we have made above are automatically performed by {\GAP} if
you  simply ask for `ConjugacyClasses(   grp   )', provided that   {\GAP}
already knows  that `grp' is finite (e.g.,  because  you asked `IsFinite(
grp  )' before). The reason  for this is that  a  finite matrix group like
`grp' is ``handled by a nice monomorphism''. For such groups, {\GAP} uses
the command `NiceMonomorphism' to construct a monomorphism (such as the
`hom' in the previous example) and then proceeds as we have done above.

\beginexample
gap> grp:=GL(2,3);;
gap> IsHandledByNiceMonomorphism( grp );
true
gap> hom := NiceMonomorphism( grp );
<action isomorphism>
gap> p :=Image(hom,grp);
Group([ (4,7)(5,8)(6,9), (2,7,6)(3,4,8) ])
gap> cc := ConjugacyClasses( grp );; ForAll(cc, x-> x in gcls); 
true
gap> ForAll(gcls, x->x in cc); # cc and gcls might be ordered differently
true
\endexample

Note that a nice monomorphism might be defined on a larger group than `grp'
-- so we have to use `Image(hom,grp)' and not only `Image(hom)'.

%\exercise (To be done after you know  about methods and method selection,
%see Chapter~"Attributes and their Methods".)  Study the {\GAP} library to
%find out how the finiteness of `grp' was determined in the above example.
%
%\answer `IsFinite' delegates to  `Size' which delegates  to `Enumerator'.
%This  operation finally constructs    a list of  all  group   elements by
%repeated calls of   `ClosureGroupDefault', which effectively performs  an
%orbit algorithm for the group acting on itself via right multiplication.

Nice monomorphisms are not only used for matrix groups, but also for
other kinds of groups in which one cannot calculate easily enough. As
another example, let us show that the automorphism group of the
quaternion group of order~8 is isomorphic to the symmetric group of
degree~4  by examining the ``nice object'' associated with that
automorphism group.

\beginexample
gap> p:=Group((1,7,6,8)(2,5,3,4), (1,2,6,3)(4,8,5,7));;
gap> aut := AutomorphismGroup( p );; NiceMonomorphism(aut);;
gap> niceaut := NiceObject( aut );
Group([ (1,2)(3,4), (3,4)(5,6), (1,3)(2,4)(5,6), (1,6)(2,5)(3,4) ])
gap> IsomorphismGroups( niceaut, SymmetricGroup( 4 ) );
[ (1,2)(3,4), (3,4)(5,6), (1,3)(2,4)(5,6), (1,6)(2,5)(3,4) ] -> 
[ (1,4)(2,3), (1,2)(3,4), (2,3), (2,4) ]
\endexample

%\exercise The nice monomorphism associated with the automorphism group of
%`p' is an operation homomorphism. What is its underlying external set?
%
%\answer `UnderlyingExternalSet( NiceMonomorphism( aut ) )' gives the list
%\begintt|nobreak
%[ (1,2,5,7)(3,6,8,4), (1,3,5,8)(2,4,7,6), (1,4,5,6)(2,8,7,3), 
%  (1,6,5,4)(2,3,7,8), (1,7,5,2)(3,4,8,6), (1,8,5,3)(2,6,7,4) ]
%\endtt
%which contains the six elements of order~4 in `p'. The automorphism group
%must permute  these elements,  and the  action  is faithful because  they
%generate~`p'.

The range of  a nice monomorphism is  in most cases a permutation  group,
because  nice monomorphisms  are mostly action  homomorphisms. In some
cases,  like in  our last example,  the  group is solvable  and you might
prefer a pc group as nice object. You cannot change the nice monomorphism
of  the automorphism  group (because it  is   the value  of the attribute
`NiceMonomorphism'), but you can compose  it with an isomorphism from the
permutation  group to  a  pc   group  to   obtain your  personal    nicer
monomorphism. If  you reconstruct  the automorphism  group,  you can even
prescribe it this nicer monomorphism as its `NiceMonomorphism', because a
newly-constructed group will not yet have a `NiceMonomorphism' set.

\beginexample
gap> nicer := NiceMonomorphism(aut) * IsomorphismPcGroup(niceaut);;
gap> aut2 := GroupByGenerators( GeneratorsOfGroup( aut ) );;
gap> SetIsHandledByNiceMonomorphism( aut2, true );
gap> SetNiceMonomorphism( aut2, nicer );
gap> NiceObject( aut2 );  # a pc group
Group([ f4, f3, f1*f2^2*f3, f1*f2*f3*f4 ])
\endexample

The star `*' denotes composition of mappings  from the left to the right,
as we  have  seen in  Section "Actions of  groups" above.
Reconstructing the
automorphism group may of course result in the  loss of other information
{\GAP} had already gathered, besides the (not-so-)nice monomorphism.

%\exercise In  analogy to `IsomorphismPcGroup',  there is also the command
%`IsomorphismPermGroup'.  Continuing the  first  example  of this section,
%what  is the  difference    between  `IsomorphismPermGroup( grp )'    and
%`NiceMonomorphism( grp )'?
%
%\answer `IsomorphismPermGroup( grp  )'  returns a bijective   mapping, in
%particular its  `Range' is a permutation  group of size~8, whereas a nice
%monomorphism  which  is an operation homomorphism   has as `Range' a full
%symmetric group. Also a  nice monomorphism could  be defined on a  larger
%group. This is   not   the case in   the   example `grp', but   the  nice
%monomorphism of a $d$-dimensional matrix group over the finite field with
%$q$ elements is defined on the general linear group~$GL(d,q)$.

{\bf Summary.}  In this section we have  seen  how calculations in groups
can be carried  out in isomorphic  images in  nicer groups. We  have seen
that {\GAP}  pursues this technique  automatically for certain classes of
groups, e.g., for matrix groups that are known to be finite.

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\Section{Further Information about Groups and Homomorphisms}

Groups and the functions for groups are treated in Chapter~"ref:Groups".
There are several chapters dealing with groups in specific representations,
for example Chapter~"ref:Permutation Groups" on permutation groups,
"ref:Polycyclic Groups" on polycyclic (including finite solvable) groups,
"ref:Matrix Groups" on matrix groups and "ref:Finitely Presented Groups" on
finitely presented groups.
Chapter~"ref:Group Actions" deals with group actions. Group
homomorphisms are the subject of Chapter~"ref:Group Homomorphisms".

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%
%E  group.tex . . . . . . . . . . . . . . . . . . . . . . . . . ends here

