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