In this section we will show some easy computations with groups. The example uses permutation groups, but this is visible for the user only because the output contains permutations. The functions, like `Group`, `Size` or `SylowSubgroup` (for detailed information, see chapters Domains, Groups), are the same for all kinds of groups, although the algorithms which compute the information of course will be different in most cases.

It is not even necessary to know more about permutations than the two facts that they are elements of permutation groups and that they are written in disjoint cycle notation (see chapter Permutations). So let's construct a permutation group:

```    gap> s8:= Group( (1,2), (1,2,3,4,5,6,7,8) );
Group( (1,2), (1,2,3,4,5,6,7,8) )```

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

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

The alternating group `a8` is printed as instruction to compute that subgroup of the group `s8` that is generated by the given six permutations. This representation is much shorter than the internal structure, and it is completely self--explanatory; one could, for example, print such a group to a file and read it into GAP later. But if one object occurs several times it is useful to refer to this object; this can be settled by assigning a name to the group.

```    gap> s8.name:= "s8";
"s8"
gap> a8;
Subgroup( s8, [ (1,3,2), (2,4,3), (2,3)(4,5), (2,4,6,5,3),
(2,5,3)(4,7,6), (2,3)(5,6,8,7) ] )
gap> a8.name:= "a8";
"a8"
gap> a8;
a8```

Whenever a group has a component `name`, GAP prints this name instead of the group itself. Note that there is no link between the name and the identifier, but it is of course useful to choose name and identifier compatible.

```    gap> copya8:= Copy( a8 );
a8```

We examine the group `a8`. Like all complex GAP structures, it is represented as a record (see Group Records).

```    gap> RecFields( a8 );
[ "isDomain", "isGroup", "parent", "identity", "generators",
"operations", "isPermGroup", "1", "2", "3", "4", "5", "6",
"stabChainOptions", "stabChain", "orbit", "transversal",
"stabilizer", "name" ]```

Many functions store information about the group in this group record, this avoids duplicate computations. But we are not interested in the organisation of data but in the group, e.g., some of its properties (see chapter Groups, especially Properties and Property Tests):

```    gap> Size( a8 ); IsAbelian( a8 ); IsPerfect( a8 );
20160
false
true```

Some interesting subgroups are the Sylow p subgroups for prime divisors p of the group order; a call of `SylowSubgroup` stores the required subgroup in the group record:

```    gap> Set( Factors( Size( a8 ) ) );
[ 2, 3, 5, 7 ]
gap> for p in last do
>      SylowSubgroup( a8, p );
>    od;
gap> a8.sylowSubgroups;
[ , Subgroup( s8, [ (1,5)(7,8), (1,5)(2,6), (3,4)(7,8), (2,3)(4,6),
(1,7)(2,3)(4,6)(5,8), (1,2)(3,7)(4,8)(5,6) ] ),
Subgroup( s8, [ (3,8,7), (2,6,4)(3,7,8) ] ),,
Subgroup( s8, [ (3,7,8,6,4) ] ),,
Subgroup( s8, [ (2,8,4,5,7,3,6) ] ) ]```

The record component `sylowSubgroups` is a list which stores at the p--th position, if bound, the Sylow p subgroup; in this example this means that there are holes at positions 1, 4 and 6. Note that a call of `SylowSubgroup` for the cyclic group of order 65521 and for the prime 65521 would cause GAP to store the group at the end of a list of length 65521, so there are special situations where it is possible to bring GAP and yourselves into troubles.

We now can investigate the Sylow 2 subgroup.

```    gap> syl2:= last[2];;
gap> Size( syl2 );
64
gap> Normalizer( a8, syl2 );
Subgroup( s8, [ (3,4)(7,8), (2,3)(4,6), (1,2)(3,7)(4,8)(5,6) ] )
gap> last = syl2;
true
gap> Centre( syl2 );
Subgroup( s8, [ ( 1, 5)( 2, 6)( 3, 4)( 7, 8) ] )
gap> cent:= Centralizer( a8, last );
Subgroup( s8, [ ( 1, 5)( 2, 6)( 3, 4)( 7, 8), (3,4)(7,8), (3,7)(4,8),
(2,3)(4,6), (1,2)(5,6) ] )
gap> Size( cent );
192
gap> DerivedSeries( cent );
[ Subgroup( s8, [ ( 1, 5)( 2, 6)( 3, 4)( 7, 8), (3,4)(7,8),
(3,7)(4,8), (2,3)(4,6), (1,2)(5,6) ] ),
Subgroup( s8, [ ( 1, 6, 3)( 2, 4, 5), ( 1, 8, 3)( 4, 5, 7),
( 1, 7)( 2, 3)( 4, 6)( 5, 8), ( 1, 5)( 2, 6) ] ),
Subgroup( s8, [ ( 1, 3)( 2, 7)( 4, 5)( 6, 8),
( 1, 6)( 2, 5)( 3, 8)( 4, 7), ( 1, 5)( 3, 4), ( 1, 5)( 7, 8) ] )
, Subgroup( s8, [ ( 1, 5)( 2, 6)( 3, 4)( 7, 8) ] ),
Subgroup( s8, [  ] ) ]
gap> List( last, Size );
[ 192, 96, 32, 2, 1 ]
gap> low:= LowerCentralSeries( cent );
[ Subgroup( s8, [ ( 1, 5)( 2, 6)( 3, 4)( 7, 8), (3,4)(7,8),
(3,7)(4,8), (2,3)(4,6), (1,2)(5,6) ] ),
Subgroup( s8, [ ( 1, 6, 3)( 2, 4, 5), ( 1, 8, 3)( 4, 5, 7),
( 1, 7)( 2, 3)( 4, 6)( 5, 8), ( 1, 5)( 2, 6) ] ) ]```

Another kind of subgroups is given by the point stabilizers.

```    gap> stab:= Stabilizer( a8, 1 );
Subgroup( s8, [ (2,5,6), (2,5)(3,6), (2,5,6,4,3), (2,5,3)(4,6,8),
(2,5)(3,4,7,8) ] )
gap> Size( stab );
2520
gap> Index( a8, stab );
8```

We can fetch an arbitrary group element and look at its centralizer in `a8`, and then get other subgroups by conjugation and intersection of already known subgroups. Note that we form the subgroups inside `a8`, but GAP regards these groups as subgroups of `s8` because this is the common ``parent'' group of all these groups and of `a8` (for the idea of parent groups, see More about Groups and Subgroups).

```    gap> Random( a8 );
(1,6,3,2,7)(4,5,8)
gap> Random( a8 );
(1,3,2,4,7,5,6)
gap> cent:= Centralizer( a8, (1,2)(3,4)(5,8)(6,7) );
Subgroup( s8, [ (1,2)(3,4)(5,8)(6,7), (5,6)(7,8), (5,7)(6,8),
(3,4)(6,7), (3,5)(4,8), (1,3)(2,4) ] )
gap> Size( cent );
192
gap> conj:= ConjugateSubgroup( cent, (2,3,4) );
Subgroup( s8, [ (1,3)(2,4)(5,8)(6,7), (5,6)(7,8), (5,7)(6,8),
(2,4)(6,7), (2,8)(4,5), (1,4)(2,3) ] )
gap> inter:= Intersection( cent, conj );
Subgroup( s8, [ (5,6)(7,8), (5,7)(6,8), (1,2)(3,4), (1,3)(2,4) ] )
gap> Size( inter );
16
gap> IsElementaryAbelian( inter );
true
gap> norm:= Normalizer( a8, inter );
Subgroup( s8, [ (6,7,8), (5,6,8), (3,4)(6,8), (2,3)(6,8), (1,2)(6,8),
(1,5)(2,6,3,7,4,8) ] )
gap> Size( norm );
576```

Suppose we do not only look which funny things may appear in our group but want to construct a subgroup, e.g., a group of structure 2^3:L_3(2) in `a8`. One idea is to look for an appropriate 2^3 which is specified by the fact that all its involutions are fixed point free, and then compute its normalizer in `a8`:

```    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
gap> norm:= Normalizer( a8, AsSubgroup( s8, elab ) );
Subgroup( s8, [ (5,6)(7,8), (5,7)(6,8), (3,4)(7,8), (3,5)(4,6),
(2,3)(6,7), (1,2)(7,8) ] )
gap> Size( norm );
1344```

Note that `elab` was defined as separate group, thus we had to call `AsSubgroup` to achieve that it has the same parent group as `a8`. Let's look at some usual misuses:

` Normalizer( a8, elab );`

Intuitively, it is clear that here again we wanted to compute the normalizer of `elab` in `a8`, and in fact we would get it by this call. However, this would be a misuse in the sense that now GAP cannot use some clever method for the computation of the normalizer. So, for larger groups, the computation may be very time consuming. That is the reason why we used the the function `AsSubgroup` in the preceding example.

Let's have a closer look at that function.

```    gap> IsSubgroup( a8, AsSubgroup( a8, elab ) );
Error, <G> must be a parent group in
AsSubgroup( a8, elab ) called from
main loop
brk> quit;
gap> IsSubgroup( a8, AsSubgroup( s8, elab ) );
true```

What we tried here was not correct. Since all our computations up to now are done inside `s8` which is the parent of `a8`, it is easy to understand that `IsSubgroup` works for two subgroups with this parent.

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

```    gap> elab < a8;
false```

or

```    gap> AsSubgroup( s8, elab ) < a8;
false```

will not cause an error, but the result does not tell anything about the inclusion of one group in another; `<` looks at the element lists for the two domains which means that it computes them if they are not already stored --which is not desirable to do for large groups-- and then simply compares the lists with respect to lexicographical order (see Comparisons of Domains).

On the other hand, the equality operator `=` in fact does test the equality of groups. Thus

```    gap> elab = AsSubgroup( s8, elab );
true```

means that the two groups are equal in the sense that they have the same elements. Note that they may behave differently since they have different parent groups. In our example, it is necessary to work with subgroups of `s8`:

```    gap> elab:= AsSubgroup( s8, elab );;
gap> elab.name:= "elab";;```

If we are given the subgroup `norm` of order 1344 and its subgroup `elab`, the factor group can be considered.

```    gap> f:= norm / elab;
(Subgroup( s8, [ (5,6)(7,8), (5,7)(6,8), (3,4)(7,8), (3,5)(4,6),
(2,3)(6,7), (1,2)(7,8) ] ) / elab)
gap> Size( f );
168```

As the output shows, this is not a permutation group. The factor group and its elements can, however, be handled in the usual way.

```    gap> Random( f );
FactorGroupElement( elab, (2,8,7)(3,5,6) )
gap> Order( f, last );
3```

The natural link between the group `norm` and its factor group `f` is the natural homomorphism onto `f`, mapping each element of `norm` to its coset modulo the kernel `elab`. In GAP you can construct the homomorphism, but note that the images lie in `f` since they are elements of the factor group, but the preimage of each such element is only a coset, not a group element (for cosets, see the relevant sections in chapter Groups, for homomorphisms see chapters Operations of Groups and Mappings).

```    gap> f.name:= "f";;
gap> hom:= NaturalHomomorphism( norm, f );
NaturalHomomorphism( Subgroup( s8,
[ (5,6)(7,8), (5,7)(6,8), (3,4)(7,8), (3,5)(4,6), (2,3)(6,7),
(1,2)(7,8) ] ), (Subgroup( s8,
[ (5,6)(7,8), (5,7)(6,8), (3,4)(7,8), (3,5)(4,6), (2,3)(6,7),
(1,2)(7,8) ] ) / elab) )
gap> Kernel( hom ) = elab;
true
gap> x:= Random( norm );
(1,7,5,8,3,6,2)
gap> Image( hom, x );
FactorGroupElement( elab, (2,7,3,4,6,8,5) )
gap> coset:= PreImages( hom, last );
(elab*(2,7,3,4,6,8,5))
gap> IsCoset( coset );
true
gap> x in coset;
true
gap> coset in f;
false```

The group `f` acts on its elements (not on the cosets) via right multiplication, yielding the regular permutation representation of `f` and thus a new permutation group, namely the linear group L_3(2). A more elaborate discussion of operations of groups can be found in section About Operations of Groups and chapter Operations of Groups.

```    gap> op:= Operation( f, Elements( f ), OnRight );;
gap> IsPermGroup( op );
true
gap> Maximum( List( op.generators, LargestMovedPointPerm ) );
168
gap> IsSimple( op );
true```

`norm` acts on the seven nontrivial elements of its normal subgroup `elab` by conjugation, yielding a representation of L_3(2) on seven points. We embed this permutation group in `norm` and deduce that `norm` is a split extension of an elementary abelian group 2^3 with L_3(2).

```    gap> op:= Operation( norm, Elements( elab ), OnPoints );
Group( (5,6)(7,8), (5,7)(6,8), (3,4)(7,8), (3,5)(4,6), (2,3)(6,7),
(3,4)(5,6) )
gap> IsSubgroup(   a8, AsSubgroup( s8, op ) );
true
gap> IsSubgroup( norm, AsSubgroup( s8, op ) );
true
gap> Intersection( elab, op );
Group( () )```

Yet another kind of information about our `a8` concerns its conjugacy classes.

```    gap> ccl:= ConjugacyClasses( a8 );
[ ConjugacyClass( a8, () ), ConjugacyClass( a8, (1,3)(2,6)(4,7)(5,8) )
, ConjugacyClass( a8, (1,3)(2,8,5)(6,7) ),
ConjugacyClass( a8, (2,5,8) ), ConjugacyClass( a8, (1,3)(6,7) ),
ConjugacyClass( a8, (1,3,2,5,4,7,8) ),
ConjugacyClass( a8, (1,5,8,2,7,3,4) ),
ConjugacyClass( a8, (1,5)(2,8,7,4,3,6) ),
ConjugacyClass( a8, (2,7,3)(4,6,8) ),
ConjugacyClass( a8, (1,6)(3,8,5,4) ),
ConjugacyClass( a8, (1,3,5,2)(4,6,8,7) ),
ConjugacyClass( a8, (1,8,6,2,5) ),
ConjugacyClass( a8, (1,7,2,4,3)(5,8,6) ),
ConjugacyClass( a8, (1,2,3,7,4)(5,8,6) ) ]
gap> Length( ccl );
14
gap> reps:= List( ccl, Representative );
[ (), (1,3)(2,6)(4,7)(5,8), (1,3)(2,8,5)(6,7), (2,5,8), (1,3)(6,7),
(1,3,2,5,4,7,8), (1,5,8,2,7,3,4), (1,5)(2,8,7,4,3,6),
(2,7,3)(4,6,8), (1,6)(3,8,5,4), (1,3,5,2)(4,6,8,7), (1,8,6,2,5),
(1,7,2,4,3)(5,8,6), (1,2,3,7,4)(5,8,6) ]
gap> List( reps, r -> Order( a8, r ) );
[ 1, 2, 6, 3, 2, 7, 7, 6, 3, 4, 4, 5, 15, 15 ]
gap> List( ccl, Size );
[ 1, 105, 1680, 112, 210, 2880, 2880, 3360, 1120, 2520, 1260, 1344,
1344, 1344 ]```

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

Having the conjugacy classes, we can consider class functions, i.e., maps that are defined on the group elements, and that are constant on each conjugacy class. One nice example is the number of fixed points; here we use that permutations act on points via `^`.

```    gap> nrfixedpoints:= function( perm, support )
> return Number( [ 1 .. support ], x -> x^perm = x );
> end;
function ( perm, support ) ... end```

Note that we must specify the support since a permutation does not know about the group it is an element of; e.g. the trivial permutation `()` has as many fixed points as the support denotes.

```    gap> permchar1:= List( reps, x -> nrfixedpoints( x, 8 ) );
[ 8, 0, 1, 5, 4, 1, 1, 0, 2, 2, 0, 3, 0, 0 ]```

This is the character of the natural permutation representation of `a8` (More about characters can be found in chapters Character Tables ff.). In order to get another representation of `a8`, we consider another action, namely that on the elements of a conjugacy class by conjugation; note that this is denoted by `OnPoints`, too.

```    gap> class := First( ccl, c -> Size(c) = 112 );
ConjugacyClass( a8, (2,5,8) )
gap> op:= Operation( a8, Elements( class ), OnPoints );;```

We get a permutation representation `op` on 112 points. It is more useful to look for properties than at the permutations.

```    gap> IsPrimitive( op, [ 1 .. 112 ] );
false
gap> blocks:= Blocks( op, [ 1 .. 112 ] );
[ [ 1, 2 ], [ 6, 8 ], [ 14, 19 ], [ 17, 20 ], [ 36, 40 ], [ 32, 39 ],
[ 3, 5 ], [ 4, 7 ], [ 10, 15 ], [ 65, 70 ], [ 60, 69 ], [ 54, 63 ],
[ 55, 68 ], [ 50, 67 ], [ 13, 16 ], [ 27, 34 ], [ 22, 29 ],
[ 28, 38 ], [ 24, 37 ], [ 31, 35 ], [ 9, 12 ], [ 106, 112 ],
[ 100, 111 ], [ 11, 18 ], [ 93, 104 ], [ 23, 33 ], [ 26, 30 ],
[ 94, 110 ], [ 88, 109 ], [ 49, 62 ], [ 44, 61 ], [ 43, 56 ],
[ 53, 58 ], [ 48, 57 ], [ 45, 66 ], [ 59, 64 ], [ 87, 103 ],
[ 81, 102 ], [ 80, 96 ], [ 92, 98 ], [ 47, 52 ], [ 42, 51 ],
[ 41, 46 ], [ 82, 108 ], [ 99, 105 ], [ 21, 25 ], [ 75, 101 ],
[ 74, 95 ], [ 86, 97 ], [ 76, 107 ], [ 85, 91 ], [ 73, 89 ],
[ 72, 83 ], [ 79, 90 ], [ 78, 84 ], [ 71, 77 ] ]
gap> op2:= Operation( op, blocks, OnSets );;
gap> IsPrimitive( op2, [ 1 .. 56 ] );
true```

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 homomorphisms (which of course are monomorphisms).

```    gap> ophom := OperationHomomorphism( a8, op  );;
gap> Kernel(ophom);
Subgroup( s8, [  ] )
gap> ophom2:= OperationHomomorphism( op, op2 );;
gap> stab:= Stabilizer( op2, 1 );;
gap> Size( stab );
360
gap> composition:= ophom * ophom2;;
gap> preim:= PreImage( composition, stab );
Subgroup( s8, [ (1,3,2), (2,4,3), (1,3)(7,8), (2,3)(4,5), (6,8,7) ] )```

And this is the permutation character (with respect to the succession of conjugacy classes in `ccl`):

```    gap> permchar2:= List( reps, x->nrfixedpoints(x^composition,56) );
[ 56, 0, 3, 11, 12, 0, 0, 0, 2, 2, 0, 1, 1, 1 ]```

The normalizer of an element in the conjugacy class `class` is a group of order 360, too. In fact, it is essentially the same as the maximal

```    gap> sgp:= Normalizer( a8,
>                      Subgroup( s8, [ Representative(class) ] ) );
Subgroup( s8, [ (2,5)(3,4), (1,3,4), (2,5,8), (1,3,7)(2,5,8),
(1,4,7,3,6)(2,5,8) ] )
gap> Size( sgp );
360
gap> IsConjugate( a8, sgp, preim );
true```

The scalar product of permutation characters of two subgroups U, V, say, equals the number of (U,V)--double cosets (again, see chapters Character Tables ff. for the details). For example, the norm of the permutation character `permchar1` of degree eight is two since the action of `a8` on the cosets of a point stabilizer is at least doubly transitive:

```    gap> stab:= Stabilizer( a8, 1 );;
gap> double:= DoubleCosets( a8, stab, stab );
[ DoubleCoset( Subgroup( s8, [ (3,8,7), (3,4)(7,8), (3,5,4,8,7),
(3,6,5)(4,8,7), (2,6,4,5)(7,8) ] ), (), Subgroup( s8,
[ (3,8,7), (3,4)(7,8), (3,5,4,8,7), (3,6,5)(4,8,7),
(2,6,4,5)(7,8) ] ) ),
DoubleCoset( Subgroup( s8, [ (3,8,7), (3,4)(7,8), (3,5,4,8,7),
(3,6,5)(4,8,7), (2,6,4,5)(7,8) ] ), (1,2)(7,8), Subgroup( s8,
[ (3,8,7), (3,4)(7,8), (3,5,4,8,7), (3,6,5)(4,8,7),
(2,6,4,5)(7,8) ] ) ) ]
gap> Length( double );
2```

We compute the numbers of ('sgp','sgp') and ('sgp','stab') double cosets.

```    gap> Length( DoubleCosets( a8, sgp, sgp ) );
4
gap> Length( DoubleCosets( a8, sgp, stab ) );
2```

Thus both irreducible constituents of `permchar1` are also constituents of `permchar2`, i.e., the difference of the two permutation characters is a proper character of `a8` of norm two.

```    gap> permchar2 - permchar1;
[ 48, 0, 2, 6, 8, -1, -1, 0, 0, 0, 0, -2, 1, 1 ]```

GAP 3.4.4
April 1997