home *** CD-ROM | disk | FTP | other *** search
Text File | 1993-05-05 | 59.5 KB | 1,823 lines |
- #############################################################################
- ##
- #A permgrp.g GAP library Udo Polis
- #A & Martin Schoenert
- ##
- #A @(#)$Id: permgrp.g,v 3.43 1993/02/10 10:11:14 martin Rel $
- ##
- #Y Copyright 1990-1992, Lehrstuhl D fuer Mathematik, RWTH Aachen, Germany
- ##
- ## This file contains the basic functions that work with permutation groups.
- ## There are functions to compute a stabilizer chain for a permutation
- ## group, to change to a stabilizer chain for a different base, and simple
- ## functions that use stabilizer chain, e.g., 'Size' and 'in'.
- ##
- #H $Log: permgrp.g,v $
- #H Revision 3.43 1993/02/10 10:11:14 martin
- #H added "permcser"
- #H
- #H Revision 3.42 1993/01/18 18:55:16 martin
- #H added character table computation
- #H
- #H Revision 3.41 1993/01/18 17:40:29 martin
- #H moved coset functions to 'permcose.g'
- #H
- #H Revision 3.40 1993/01/15 14:43:03 martin
- #H added 'MakeStabChainRandom'
- #H
- #H Revision 3.39 1993/01/08 13:46:51 fceller
- #H changed '.size' into 'Size' call in 'ConjugacyClassOps.\='
- #H
- #H Revision 3.38 1993/01/04 11:16:53 fceller
- #H added 'Exponent'
- #H
- #H Revision 3.37 1992/12/16 19:47:27 martin
- #H replaced quoted record names with escaped ones
- #H
- #H Revision 3.36 1992/12/02 08:09:50 fceller
- #H added "permag.g"
- #H
- #H Revision 3.35 1992/07/14 13:13:34 martin
- #H added package "permprod"
- #H
- #H Revision 3.34 1992/06/03 09:18:00 martin
- #H added 'PermGroupOps.IsSimple'
- #H
- #H Revision 3.33 1992/05/14 10:43:50 martin
- #H fixed 'SylowSubgroups', groups with known size need not have a stabchain
- #H
- #H Revision 3.32 1992/03/13 13:47:16 martin
- #H fixed 'PermGroupOps.Subgroup' from overwriting the or of parent groups
- #H
- #H Revision 3.31 1992/02/19 13:07:04 martin
- #H added the new Sylow subgroup algorithm
- #H
- #H Revision 3.30 1992/02/12 15:44:23 martin
- #H added the lattice package
- #H
- #H Revision 3.29 1992/02/11 12:44:04 martin
- #H added 'SmallestGenerators'
- #H
- #H Revision 3.28 1992/01/29 09:09:38 martin
- #H changed 'Order' to take two arguments, group and element
- #H
- #H Revision 3.27 1992/01/27 11:22:41 martin
- #H fixed another bug in 'Closure' (hopefully the last)
- #H
- #H Revision 3.26 1992/01/20 15:58:36 martin
- #H added permgroup homomorphisms
- #H
- #H Revision 3.25 1992/01/20 15:40:31 martin
- #H changed 'Closure' to avoid calling 'GroupOps.Closure'
- #H
- #H Revision 3.24 1992/01/16 12:30:33 martin
- #H added 'MakeStabChainStrongGenerators'
- #H
- #H Revision 3.23 1992/01/14 16:42:29 martin
- #H fixed yet another bug in 'Closure'
- #H
- #H Revision 3.22 1992/01/07 14:44:34 martin
- #H added 'PermGroupOps.Normalizer' (in 'permnorm.g')
- #H
- #H Revision 3.21 1992/01/07 13:59:28 martin
- #H changed 'Closure' to ignore element lists
- #H
- #H Revision 3.20 1991/12/05 11:23:33 martin
- #H removed incorrect redefinition of 'GroupOps.^'
- #H
- #H Revision 3.19 1991/11/28 16:04:07 martin
- #H added permgroups conjugacy classes
- #H
- #H Revision 3.18 1991/11/28 15:52:32 martin
- #H added permgroup cosets
- #H
- #H Revision 3.17 1991/11/28 14:36:55 martin
- #H changed the order of the functions in the file
- #H
- #H Revision 3.16 1991/11/28 14:28:55 martin
- #H fixed 'ConjugateSubgroup', 'GroupOps.CS' may return identical subgroup
- #H
- #H Revision 3.15 1991/11/28 14:07:49 martin
- #H moved 'PermutationsOps.Group' from 'permutat.g' to 'permgrp.g'
- #H
- #H Revision 3.14 1991/11/28 14:06:34 martin
- #H changed 'Subgroup', now delegates to 'GroupOps.Subgroup'
- #H
- #H Revision 3.13 1991/11/28 11:31:18 martin
- #H removed 'Print', inherit from 'GroupOps'
- #H
- #H Revision 3.12 1991/11/28 11:18:11 martin
- #H changed 'ChangeStabChain' to leave the generators on the top level
- #H
- #H Revision 3.11 1991/11/21 15:27:58 martin
- #H added code to update base entry in permgroups
- #H
- #H Revision 3.10 1991/10/15 11:13:32 martin
- #H fixed 'Closure' from incorrect 'MakeStabStrong' call
- #H
- #H Revision 3.9 1991/10/14 11:35:29 martin
- #H changed 'Print' to honor '<G>.name'
- #H
- #H Revision 3.8 1991/10/11 10:52:06 martin
- #H moved 'MakeStabChain', etc into the 'PermGroupOps' record
- #H
- #H Revision 3.7 1991/10/08 16:07:23 martin
- #H fixed 'Elements' from the idea that stabilizers are subgroups
- #H
- #H Revision 3.6 1991/10/07 15:34:51 martin
- #H fixed another nasty bug in 'Closure'
- #H
- #H Revision 3.5 1991/10/04 15:37:16 martin
- #H fixed a minor problem in 'ListStabChain'
- #H
- #H Revision 3.4 1991/10/02 14:18:29 martin
- #H fixed a nasty bug in 'Closure'
- #H
- #H Revision 3.3 1991/10/01 14:59:23 martin
- #H changed stabchain, stabilizer are no subgroups
- #H
- #H Revision 3.2 1991/09/30 13:02:08 martin
- #H fixed 'MakeStabChain' for the trivial group
- #H
- #H Revision 3.1 1991/09/30 12:49:09 martin
- #H 'Subgroup' binds the generators to '<S>.<i>'
- #H
- #H Revision 3.0 1991/09/30 11:39:21 martin
- #H initial revision under RCS
- #H
- ##
-
-
- #############################################################################
- ##
- #F InfoPermGroup1( ... ) . . information function for the permgroup package
- #F InfoPermGroup2( ... ) . . information function for the permgroup package
- ##
- if not IsBound( InfoPermGroup1 ) then InfoPermGroup1 := Ignore; fi;
- if not IsBound( InfoPermGroup2 ) then InfoPermGroup2 := Ignore; fi;
-
-
- #############################################################################
- ##
- #F IsPermGroup(<D>) . . . . . . . . . . . . is a domain a permutation group
- ##
- IsPermGroup := function ( D )
- return IsRec( D )
- and IsBound( D.isPermGroup ) and D.isPermGroup;
- end;
-
-
- #############################################################################
- ##
- #F PermutationsOps.Group(<D>,<gens>,<id>) . . . create a permutation group
- ##
- PermutationsOps.Group := function ( Permutations, gens, id )
- local G; # permutation group <G>, result
-
- # let the default function do the main work
- G := GroupElementsOps.Group( Permutations, gens, id );
-
- # add the permutation group tag
- G.isPermGroup := true;
-
- # add known information
- G.isFinite := true;
-
- # add the operations record
- G.operations := PermGroupOps;
-
- # return the permuation group
- return G;
- end;
-
-
- #############################################################################
- ##
- #V PermGroupOps . . . . . . operation record for permutation group category
- ##
- ## 'PermGroupOps' is the operation record for permutation groups. It
- ## contains the function for domain operation, e.g., 'Size' and
- ## 'Intersection' as well as the functions for group operations, e.g.,
- ## 'Centralizer' and 'Orbit'.
- ##
- ## 'PermGroupOps' is initially a copy of 'GroupOps', thus permutation groups
- ## inherit the default group functions, e.g., 'DerivedSubgroup' and 'Index'.
- ## However 'PermGroupOps' overlays some of those functions with more
- ## efficient ones, e.g., 'Elements' and 'Size'.
- ##
- PermGroupOps := Copy( GroupOps );
-
-
- #############################################################################
- ##
- #F PermGroupOps.Subgroup(<G>,<gens>) . . . . . . make a permutation subgroup
- ##
- PermGroupOps.Subgroup := function ( G, gens )
- local S; # subgroup, result
-
- # let the default function do the main work
- S := GroupOps.Subgroup( G, gens );
-
- # add permgroup tag and permgroup operations record
- if IsBound( S.parent ) then
- S.isPermGroup := true;
- S.operations := PermGroupOps;
- fi;
-
- # return the subgroup
- return S;
- end;
-
-
- #############################################################################
- ##
- #F PermGroupOps.Closure(<G>,<obj>) . . . . . . . . . . closure < <G>, <g> >
- ##
- PermGroupOps.Closure := function ( G, obj )
- local C, # closure of < <G>, <obj> >, result
- gens; # generators of <obj> that are not in <G>
-
- # get the elements that must be added to <G>
- if IsGroup( obj ) then
- gens := obj.generators;
- else
- gens := [ obj ];
- fi;
-
- # handle a closure in the parent
- if IsParent( G ) then
- C := G;
-
- # handle the closure with a group that has a stabilizer chain
- elif IsBound( G.orbit ) then
-
- # if all generators are in <G>, <G> is the closure
- gens := Filtered( gens, gen -> not G.operations.\in( gen, G ) );
- if gens = [] then
- C := G;
-
- # otherwise make the closure and copy the stabilizer chain
- else
- C := Subgroup( Parent( G ), G.generators );
- C.orbit := ShallowCopy( G.orbit );
- C.transversal := ShallowCopy( G.transversal );
- C.stabilizer := Copy( G.stabilizer );
- C.operations.MakeStabStrong( C, gens, C.operations.Base( C ) );
-
- fi;
-
- # handle the closure with a group that has no stabilizer chain
- else
-
- # if all generators are in <G>, <G> is the closure
- gens := Filtered( gens, gen -> not gen in G.generators
- and not gen^-1 in G.generators
- and not (IsBound( G.elements )
- and gen in G.elements) );
- if gens = [] then
- C := G;
-
- # otherwise make the closure group
- else
- C := G.operations.Subgroup( Parent( G ),
- Concatenation( G.generators, gens ) );
-
- fi;
-
- fi;
-
- # return the closure
- return C;
- end;
-
-
- #############################################################################
- ##
- ## A stabilizer chain of a permutation group is a chain of subgroups, each
- ## of which is a stabilizer of a point in the previous subgroup.
- ##
- ## Each stabilizer <S> is represented by a record with the following fields
- ##
- ## '<S>.identity': identity of <S>.
- ##
- ## '<S>.generators': system of generators for the <S>.
- ##
- ## '<S>.orbit': orbit of the point '<S>.orbit[1]' under <S>.
- ## '<S>.orbit[1]' is called the basepoint of <S>.
- ##
- ## '<S>.transversal': transversal corresponding to '<S>.orbit'.
- ## For each point <p> in the orbit '<S>.orbit'
- ## '<S>.transversal[<p>]' is a permutation that
- ## takes <p> to a point earlier in '<S>.orbit'.
- ## This is usually called a Schreier vector of <S>,
- ## however 'factoredInverseTransversal' would be a
- ## more appropriate name.
- ##
- ## '<S>.stabilizer': stabilizer of the point 'orbit[1]' in <S>.
- ##
- ## The chain begins with the group <G> itself and is terminated by a trivial
- ## stabilizer, i.e., 'rec( identity := (), generators := [] )'.
- ##
- SC_level := 0; # only for information
-
-
- #############################################################################
- ##
- #F PermGroupOps.AddGensExtOrb(<S>,<new>) . . . . . add generators and extend
- #F orbit and transversal
- ##
- PermGroupOps.AddGensExtOrb := function ( S, new )
- local gens, # generators of <S> or <new>
- gen, # one generator in <gens>
- orb, # orbit of <S>
- len, # length of the orbit
- i; # loop variable
-
- # add the new generators to the generator list
- for gen in new do
- if not gen in S.generators then
- Add( S.generators, gen );
- fi;
- od;
-
- # extend the orbit and the transversal with the new generators
- orb := S.orbit;
- len := Length(orb);
- i := 1;
- while i <= Length(orb) do
- if i <= len then gens := new; else gens := S.generators; fi;
- for gen in gens do
- if not IsBound(S.transversal[orb[i]/gen]) then
- S.transversal[orb[i]/gen] := gen;
- Add( orb, orb[i]/gen );
- fi;
- od;
- i := i + 1;
- od;
-
- end;
-
-
- #############################################################################
- ##
- #F PermGroupOps.MakeStabStrong(<S>,<new>,<base>) . make a stabilizer strong
- ##
- PermGroupOps.MakeStabStrong := function ( S, new, base )
- local gens, # generators of <S>
- gen, # one generator of <S>
- orb, # orbit of <S>, same as '<S>.orbit'
- len, # initial length of <orb>
- rep, # representative of point in <orb>
- sch, # schreier generator of '<S>.stabilizer'
- stb, # stabilizer beneath <S>
- bpt, # basepoint of <stb>, same as '<stb>.orbit[1]'
- i, j; # loop variables
-
- # find the index of the first point moved by <new> in '<base>+[1..]'
- i := 1;
- while i <= Length(base)
- and ForAll( new, gen -> base[i]^gen = base[i] ) do
- i := i + 1;
- od;
- if Length(base) < i then
- while ForAll( new, gen -> (i-Length(base))^gen = i-Length(base) ) do
- i := i + 1;
- od;
- fi;
-
- # if necessary add a new stabilizer to the stabchain
- if not IsBound(S.stabilizer) then
- if i <= Length(base) then
- S.orbit := [ base[i] ];
- else
- S.orbit := [ i-Length(base) ];
- fi;
- S.transversal := [];
- S.transversal[S.orbit[1]] := S.identity;
- S.stabilizer := rec();
- S.stabilizer.identity := S.identity;
- S.stabilizer.generators := [];
- fi;
-
- # find the index of the basepoint in '<base>+[1..]'
- j := Position( base, S.orbit[1] );
- if j = false then
- j := S.orbit[1] + Length(base);
- fi;
-
- # if the new generators move an earlier point insert a new stabilizer
- if i < j then
- S.stabilizer := ShallowCopy( S );
- S.stabilizer.generators := ShallowCopy( S.generators );
- if i <= Length(base) then
- S.orbit := [ base[i] ];
- else
- S.orbit := [ i-Length(base) ];
- fi;
- S.transversal := [];
- S.transversal[S.orbit[1]] := S.identity;
- fi;
-
- # add the new generators to <S> and extend the orbit and transversal
- orb := S.orbit;
- len := Length(orb);
- PermGroupOps.AddGensExtOrb( S, new );
-
- # force all the new generators that fix the basepoint into the stabilizer
- for gen in new do
- if orb[1]^gen = orb[1] then
- PermGroupOps.MakeStabStrong( S.stabilizer, [ gen ], base );
- fi;
- od;
-
- # compute the Schreier generators (seems to work better backwards)
- for i in Reversed([1..Length(orb)]) do
-
- # compute an inverse representant '<orb>[1]^(<rep>^-1) = <orb>[i]'
- rep := S.transversal[orb[i]];
- while orb[i] ^ rep <> orb[1] do
- rep := rep * S.transversal[ orb[i]^rep ];
- od;
-
- # take only the new generators for old, all generators for new points
- if i <= len then gens := new; else gens := S.generators; fi;
- for gen in gens do
-
- # avoid to compute schreier generators that will turn out trivial
- if gen <> S.transversal[ orb[i] / gen ] then
-
- # divide (gen * rep)^-1 by the representantives
- sch := (gen * rep)^-1;
- stb := S;
- while stb.generators <> []
- and IsBound(stb.transversal[stb.orbit[1]^sch]) do
- bpt := stb.orbit[1];
- while bpt ^ sch <> bpt do
- sch := sch * stb.transversal[bpt^sch];
- od;
- stb := stb.stabilizer;
- od;
-
- # force nontrivial reduced Schreier generator into the stab.
- if sch <> S.identity then
- PermGroupOps.MakeStabStrong( S.stabilizer, [sch], base );
- fi;
-
- fi;
- od;
-
- od;
-
- end;
-
-
- #############################################################################
- ##
- #F PermGroupOps.MakeStabStrongRandom(<S>,<new>,<base>) . make a stab. strong
- ##
- ## Does almost the same, except that only a few Schreier generators are
- ## tried on each level.
- ##
- PermGroupOps.MakeStabStrongRandom := function ( S, new, base )
- local gens, # generators of <S>
- gen, # one generator of <S>
- orb, # orbit of <S>, same as '<S>.orbit'
- len, # initial length of <orb>
- rep, # representative of point in <orb>
- sch, # schreier generator of '<S>.stabilizer'
- stb, # stabilizer beneath <S>
- bpt, # basepoint of <stb>, same as '<stb>.orbit[1]'
- rind, # random indices no tried so far
- rlen, # length of <rind>
- rlog, # 'Length(<orb>) / 2^ <nr of indices tried so far>'
- i, j; # loop variables
-
- # find the index of the first point moved by <new> in '<base>+[1..]'
- i := 1;
- while i <= Length(base)
- and ForAll( new, gen -> base[i]^gen = base[i] ) do
- i := i + 1;
- od;
- if Length(base) < i then
- while ForAll( new, gen -> (i-Length(base))^gen = i-Length(base) ) do
- i := i + 1;
- od;
- fi;
-
- # if necessary add a new stabilizer to the stabchain
- if not IsBound(S.stabilizer) then
- if i <= Length(base) then
- S.orbit := [ base[i] ];
- else
- S.orbit := [ i-Length(base) ];
- fi;
- S.transversal := [];
- S.transversal[S.orbit[1]] := S.identity;
- S.stabilizer := rec();
- S.stabilizer.identity := S.identity;
- S.stabilizer.generators := [];
- fi;
-
- # find the index of the basepoint in '<base>+[1..]'
- j := Position( base, S.orbit[1] );
- if j = false then
- j := S.orbit[1] + Length(base);
- fi;
-
- # if the new generators move an earlier point insert a new stabilizer
- if i < j then
- S.stabilizer := ShallowCopy( S );
- S.stabilizer.generators := ShallowCopy( S.generators );
- if i <= Length(base) then
- S.orbit := [ base[i] ];
- else
- S.orbit := [ i-Length(base) ];
- fi;
- S.transversal := [];
- S.transversal[S.orbit[1]] := S.identity;
- fi;
-
- # add the new generators to <S> and extend the orbit and transversal
- orb := S.orbit;
- len := Length(orb);
- PermGroupOps.AddGensExtOrb( S, new );
-
- # force all the new generators that fix the basepoint into the stabilizer
- for gen in new do
- if orb[1]^gen = orb[1] then
- PermGroupOps.MakeStabStrongRandom( S.stabilizer, [ gen ], base );
- fi;
- od;
-
- # compute the Schreier generators (seems to work better backwards)
- rind := [1..Length(orb)];
- rlen := Length( orb );
- rlog := Length( orb );
- while 0 < rlen and 0 < rlog do
- j := Random( [1..rlen] );
- i := rind[j];
- rind[j] := rind[rlen];
- rlen := rlen - 1;
- rlog := QuoInt( rlog, 2 );
-
- # compute an inverse representant '<orb>[1]^(<rep>^-1) = <orb>[i]'
- rep := S.transversal[orb[i]];
- while orb[i] ^ rep <> orb[1] do
- rep := rep * S.transversal[ orb[i]^rep ];
- od;
-
- # take only the new generators for old, all generators for new points
- if i <= len then gens := new; else gens := S.generators; fi;
- for gen in gens do
-
- # avoid to compute schreier generators that will turn out trivial
- if gen <> S.transversal[ orb[i] / gen ] then
-
- # divide (gen * rep)^-1 by the representantives
- sch := (gen * rep)^-1;
- stb := S;
- while stb.generators <> []
- and IsBound(stb.transversal[stb.orbit[1]^sch]) do
- bpt := stb.orbit[1];
- while bpt ^ sch <> bpt do
- sch := sch * stb.transversal[bpt^sch];
- od;
- stb := stb.stabilizer;
- od;
-
- # force nontrivial reduced Schreier generator into the stab.
- if sch <> S.identity then
- rlog := Length( orb );
- PermGroupOps.MakeStabStrongRandom( S.stabilizer,
- [sch],
- base );
- fi;
-
- fi;
- od;
-
- od;
-
- end;
-
-
- #############################################################################
- ##
- #F PermGroupOps.SwapStabChain(<S>) . . . . . . . . . exchange two basepoints
- ##
- PermGroupOps.SwapStabChain := function ( S )
- local a, b, # basepoints that are to be switched
- T, # copy of $S$ with $T.stabilizer$ becomes $S_b$
- pnt, # one point from $a^S$ not yet in $a^{T_b}$
- ind, # index of <pnt> in $S.orbit$
- img, # image $b^{Rep(S,pnt)^-}$
- gen, # new generator of $T_b$
- i; # loop variable
-
- # get the two basepoints $a$ and $b$ that we have to switch
- a := S.orbit[1];
- b := S.stabilizer.orbit[1];
- InfoPermGroup2("#I swap ",b," with ",a," on level ",SC_level,"\n");
-
- # set $T = S$ and compute $T.orbit = b^T$ and a transversal $T/T_b$
- T := rec();
- T.identity := S.identity;
- T.generators := [];
- T.orbit := [ b ];
- T.transversal := [];
- T.transversal[b] := S.identity;
- PermGroupOps.AddGensExtOrb( T, S.generators );
-
- # initialize $T.stabilizer$, which will become $T_b$
- T.stabilizer := rec();
- T.stabilizer.identity := T.identity;
- T.stabilizer.generators:=ShallowCopy(S.stabilizer.stabilizer.generators);
- T.stabilizer.orbit := [ a ];
- T.stabilizer.transversal := [];
- T.stabilizer.transversal[a] := T.identity;
-
- # in the end $|b^T||a^{T_b}| = [T:T_{ab}] = [S:S_{ab}] = |a^S||b^{S_a}|$
- ind := 1;
- while Length(T.orbit) * Length(T.stabilizer.orbit)
- < Length(S.orbit) * Length(S.stabilizer.orbit) do
-
- # choose a point $pnt \in a^S \ a^{T_b}$ with representative $s$
- repeat ind := ind + 1; until not S.orbit[ind] in T.stabilizer.orbit;
- pnt := S.orbit[ind];
-
- # find out what $s^-$ does with $b$ (without computing $s$!)
- img := b;
- i := pnt;
- while i <> a do
- img := img ^ S.transversal[i];
- i := i ^ S.transversal[i];
- od;
-
- # if $b^{s^-}} \in b^{S_a}$ with representative $r \in S_a$
- if IsBound(S.stabilizer.transversal[img]) then
-
- # with $gen = s^- r^-$ we have
- # $b^gen = {b^{s^-}}^{r^-} = img^{r-} = b$, so $gen \in S_b$
- # and $pnt^gen = {pnt^{s^-}}^{r^-} = a^{r-} = a$, so $gen$ is new
- gen := S.transversal[pnt];
- while pnt ^ gen <> a do
- gen := gen * S.transversal[pnt^gen];
- od;
- while b ^ gen <> b do
- gen := gen * S.stabilizer.transversal[b^gen];
- od;
-
- # add the new generator to $T_b$ and extend orbit and transversal
- PermGroupOps.AddGensExtOrb( T.stabilizer, [ gen ] );
-
- fi;
-
- od;
-
- # copy everything back into the stabchain
- S.generators := T.generators;
- S.orbit := T.orbit;
- S.transversal := T.transversal;
- if Length(T.stabilizer.orbit) = 1 then
- S.stabilizer := S.stabilizer.stabilizer;
- else
- S.stabilizer.generators := T.stabilizer.generators;
- S.stabilizer.orbit := T.stabilizer.orbit;
- S.stabilizer.transversal := T.stabilizer.transversal;
- fi;
-
- end;
-
-
- #############################################################################
- ##
- #F PermGroupOps.ForcePointStabChain(<S>,<pnt>) . force a point in the orbit
- ##
- PermGroupOps.ForcePointStabChain := function ( S, pnt )
-
- # do nothing if <pnt> is already in the orbit of <S>
- if not IsBound(S.orbit) or not pnt in S.orbit then
-
- # if all generators of <S> fix <pnt> insert a trivial stabilizer
- if ForAll( S.generators, gen -> pnt ^ gen = pnt ) then
-
- InfoPermGroup2("#I inserting trivial stabilizer for ",
- pnt," on level ",SC_level,"\n");
-
- S.stabilizer := ShallowCopy( S );
- S.stabilizer.generators := ShallowCopy( S.generators );
- S.orbit := [ pnt ];
- S.transversal := [];
- S.transversal[pnt] := S.identity;
-
- # otherwise
- else
-
- # get <pnt> in the orbit of the stabilizer
- SC_level := SC_level + 1;
- PermGroupOps.ForcePointStabChain( S.stabilizer, pnt );
- SC_level := SC_level - 1;
-
- # and swap the two stabilizers
- PermGroupOps.SwapStabChain( S );
-
- fi;
-
- else
- InfoPermGroup2("#I found ",pnt," on level ",SC_level,"\n");
- fi;
-
- end;
-
-
- #############################################################################
- ##
- #F PermGroupOps.ConjugateStabChain(<G>,<g>) . . . . . conjugate a stabchain
- ##
- PermGroupOps.ConjugateStabChain := function ( G, g )
- local S, # stabilizer in stabchain
- str, # strong generating system
- cnj, # conjugated strong generating system
- old, # old generators of a stabilizer
- orb, # old orbit of a stabilizer
- trn, # old transversal of a stabilizer
- i; # loop variable
-
- # initialize the strong generators and their conjugates
- str := [ G.identity ];
- cnj := [ G.identity ];
-
- # go down the stabchain to conjugate every stabilizer
- S := G;
- while S.generators <> [] do
-
- # conjugate the generators of this stabilizer
- old := S.generators;
- S.generators := [];
- for i in [1..Length(old)] do
- if not old[i] in str then
- Add( str, old[i] );
- Add( cnj, old[i] ^ g );
- fi;
- S.generators[i] := cnj[ Position(str,old[i]) ];
- od;
-
- # conjugate the orbit and the transversal of this stabilizer
- orb := S.orbit;
- trn := S.transversal;
- S.orbit := [];
- S.transversal := [];
- for i in [1..Length(orb)] do
- S.orbit[i] := orb[i] ^ g;
- S.transversal[S.orbit[i]] := cnj[ Position(str,trn[orb[i]]) ];
- od;
-
- # on to the next stabilizer
- S := S.stabilizer;
-
- od;
-
- end;
-
-
- #############################################################################
- ##
- #F PermGroupOps.ChangeStabChain(<G>,<base>) . . . . . . change a stabchain
- #F for a different base
- ##
- PermGroupOps.ChangeStabChain := function ( G, base )
- local S, # stabilizer in the stabchain
- cnj, # conjugating permutation
- i; # loop variable
-
- # give some information
- SC_level := 1;
- InfoPermGroup1("#I ChangeStabChain called\n");
-
- # intialize the conjugating permutation
- cnj := G.identity;
-
- # go down the stabchain
- S := G;
- i := 1;
- while i <= Length(base) and IsBound(S.stabilizer) do
-
- # do not insert trivial stabilizers
- if ForAny( S.generators, gen->(base[i]^cnj)^gen<>base[i]^cnj ) then
-
- # get the <i>th point of the base into the orbit of $H$
- InfoPermGroup2("#I force ",base[i]^cnj," (=",base[i],"^cnj) ",
- "to level ",SC_level,"\n");
- PermGroupOps.ForcePointStabChain( S, base[i]^cnj );
-
- # extend the conjugating permutation
- while base[i]^cnj <> S.orbit[1] do
- cnj := cnj * S.transversal[base[i]^cnj];
- od;
-
- # on to the next stabilizer
- S := S.stabilizer;
- SC_level := SC_level + 1;
-
- else
- InfoPermGroup2("#I skip ",base[i]^cnj," (=",base[i],"^cnj) ",
- "on level ",SC_level,"\n");
- fi;
-
- # on to the next basepoint
- i := i + 1;
-
- od;
-
- # conjugate <G> to move all the points to the beginning of their orbits
- if cnj <> G.identity then
- InfoPermGroup2("#I conjugating\n");
-
- # do not conjugate on the top level where we want to keep the gens
- G.orbit := [ G.orbit[1] ^ (cnj^-1) ];
- G.transversal := [];
- G.transversal[G.orbit[1]] := G.identity;
- G.operations.AddGensExtOrb( G, G.generators );
-
- # conjugate on the other levels
- PermGroupOps.ConjugateStabChain( G.stabilizer, cnj^-1 );
- fi;
-
- # unbind the, now probably incorrect, base component
- Unbind( G.base );
- InfoPermGroup1("#I ChangeStabChain done\n");
- end;
-
-
- #############################################################################
- ##
- #F ReduceStabChain(<G>) . . . . remove trivial stabilizers from a stabchain
- ##
- ## We say that a stabilizer chain is reduced if it contains no stabilizers
- ## <S> that are equal to '<S>.stabilizer', i.e., for which '<S>.orbit' has
- ## length 1. Usually it is better to work with reduced stabilizer chains,
- ## however sometimes one wants to have a stabilizer chain corresponding to a
- ## specific choice of basepoints (see "IntersectionPermGroup").
- ##
- ReduceStabChain := function ( G )
- G.operations.ReduceStabChain( G );
- end;
-
- PermGroupOps.ReduceStabChain := function ( G )
- local S; # stabilizer in the stabchain
-
- # go down the stabchain and remove trivial stabilizers
- S := G;
- while S.generators <> [] do
-
- # if this stabilizer is trivial copy the entries from the next level
- if Length(S.orbit) = 1 then
- S.identity := S.stabilizer.identity;
- S.generators := S.stabilizer.generators;
- S.orbit := S.stabilizer.orbit;
- S.transversal := S.stabilizer.transversal;
- S.stabilizer := S.stabilizer.stabilizer;
-
- # otherwise go on with the next level
- else
- S := S.stabilizer;
-
- fi;
-
- od;
-
- # remove trivial stabilizers at the end of the stabchain
- Unbind( S.orbit );
- Unbind( S.transversal );
- Unbind( S.stabilizer );
-
- # unbind the, now probably incorrect, base component
- Unbind( G.base );
- end;
-
-
- #############################################################################
- ##
- #F ExtendStabChain(<G>,<base>) . . insert trivial stabilizers in a stabchain
- ##
- ExtendStabChain := function ( G, base )
- G.operations.ExtendStabChain( G, base );
- end;
-
- PermGroupOps.ExtendStabChain := function ( G, base )
- local S, # stabilizer of <G>
- i; # loop variable
-
- # go down the stabchain and insert trivial stabilizers
- S := G;
- i := 1;
- while i <= Length(base) do
-
- # if necessary append a trivial stabilizer
- if S.generators = [] then
-
- S.orbit := [ base[i] ];
- S.transversal := [];
- S.transversal[base[i]] := S.identity;
- S.stabilizer := rec();
- S.stabilizer.identity := S.identity;
- S.stabilizer.generators := [];
-
- # if necessary insert a trivial stabilizer
- elif base[i] <> S.orbit[1] then
-
- # test that the new base is really an extension of the current
- if ForAny( S.generators, gen -> base[i]^gen <> base[i] ) then
- Error("<base> must reduce to base of <G>");
- fi;
-
- S.stabilizer := ShallowCopy(S);
- S.stabilizer.generators := ShallowCopy( S.generators );
- S.orbit := [ base[i] ];
- S.transversal := [];
- S.transversal[base[i]] := S.identity;
-
- fi;
-
- # on to the next basepoint and the next stabilizer
- S := S.stabilizer;
- i := i + 1;
-
- od;
-
- # unbind the, now probably incorrect, base component
- Unbind( G.base );
- end;
-
-
- #############################################################################
- ##
- #F MakeStabChain(<G>[,<base>]) . . . . . . . . . compute a stabilizer chain
- #F for a permutation group
- ##
- MakeStabChain := function ( arg )
- if Length(arg) = 1 then
- arg[1].operations.MakeStabChain( arg[1], [] );
- elif Length(arg) = 2 then
- arg[1].operations.MakeStabChain( arg[1], arg[2] );
- else
- Error("usage: MakeStabChain( <G> [, <base>] )");
- fi;
- end;
-
- PermGroupOps.MakeStabChain := function ( G, base )
- if G.generators <> [] and not IsBound(G.stabilizer) then
- PermGroupOps.MakeStabStrong( G, G.generators, base );
- else
- ReduceStabChain( G );
- PermGroupOps.ChangeStabChain( G, base );
- fi;
- end;
-
-
- #############################################################################
- ##
- #F MakeStabChainStrongGenerators(<G>,<base>,<stronggens>) . . . construct a
- #F reduced stabilizer chain for a given strong generating system
- ##
- MakeStabChainStrongGenerators := function ( G, base, stronggens )
-
- # check the arguments
- if not IsPermGroup( G ) then
- Error("<G> must be a permutation group");
- elif not IsList( stronggens ) then
- Error("<stronggens> must be a list of permutations");
- elif not IsList( base ) then
- Error("<base> must be a list of points");
- fi;
-
- # dispatch (very likely to 'PermGroupOps.MakeStabChainStrongGenerators')
- G.operations.MakeStabChainStrongGenerators( G, base, stronggens );
- end;
-
- PermGroupOps.MakeStabChainStrongGenerators := function ( G, base, sgs )
- local S, # stabilizer of <G>
- ssgs, # subset of strong generators
- bpt; # base point
-
- # forget old stabilizer chain (if any)
- Unbind( G.orbit );
- Unbind( G.transversal );
- Unbind( G.stabilizer );
-
- # build up the stabilizer chain
- S := G;
- ssgs := sgs;
- for bpt in base do
-
- # if this step is not trivial
- if not ForAll( ssgs, gen -> bpt ^ gen = bpt ) then
-
- # enter the new generators, but not on the top level
- if ssgs <> sgs then
- S.generators := ssgs;
- fi;
-
- # calculate orbit and transversal on this level
- S.orbit := [ bpt ];
- S.transversal := [];
- S.transversal[ bpt ] := S.identity;
- G.operations.AddGensExtOrb( S, S.generators );
-
- # initialize next stabilizer and compute its generators
- S.stabilizer := rec( generators := [],
- identity := G.identity );
- ssgs := Filtered( ssgs, gen -> bpt ^ gen = bpt );
-
- # and go down to the next level
- S := S.stabilizer;
-
- fi;
-
- od;
-
- end;
-
-
- #############################################################################
- ##
- #F MakeStabChainRandom(<G>[,<base>]) . . . . . . compute a stabilizer chain
- #F for a permutation group
- ##
- MakeStabChainRandom := function ( arg )
- if Length(arg) = 1 then
- arg[1].operations.MakeStabChainRandom( arg[1], [] );
- elif Length(arg) = 2 then
- arg[1].operations.MakeStabChainRandom( arg[1], arg[2] );
- else
- Error("usage: MakeStabChainRandom( <G> [, <base>] )");
- fi;
- end;
-
- PermGroupOps.MakeStabChainRandom := function ( G, base )
- if G.generators <> [] and not IsBound(G.stabilizer) then
- PermGroupOps.MakeStabStrongRandom( G, G.generators, base );
- else
- ReduceStabChain( G );
- PermGroupOps.ChangeStabChain( G, base );
- fi;
- end;
-
-
- #############################################################################
- ##
- #F ListStabChain(<G>) . . stabilizer chain of a permutation group as a list
- ##
- ListStabChain := function ( G )
- local S, # stabilizer of <G>
- lst; # stabchain, result
-
- # make sure that <G> has a stabchain
- if not IsBound(G.stabilizer) then MakeStabChain( G ); fi;
-
- # go down the stabchain and collect the stabilizers
- lst := [];
- S := G;
- while IsBound(S.stabilizer) do
- Add( lst, S );
- S := S.stabilizer;
- od;
- Add( lst, S );
-
- # return the stabchain
- return lst;
- end;
-
-
- #############################################################################
- ##
- #F PermGroupOps.Elements(<G>) . . . . . . . elements of a permutation group
- ##
- PermGroupOps.Elements := function ( G )
- local elms; # element set, result
-
- # make sure that <G> has a stabchain
- if not IsBound(G.stabilizer) then MakeStabChain(G); fi;
-
- # compute the elements of <G>
- elms := PermGroupOps.ElementsStab( G );
-
- # return the elements
- return elms;
- end;
-
- PermGroupOps.ElementsStab := function ( G )
- local elms, # element list, result
- stb, # elements of the stabilizer
- pnt, # point in the orbit of <G>
- rep; # inverse representative for that point
-
- # if <G> is trivial then it is easy
- if G.generators = [] then
- elms := [ G.identity ];
-
- # otherwise
- else
-
- # start with the empty list
- elms := [];
-
- # compute the elements of the stabilizer
- stb := PermGroupOps.ElementsStab( G.stabilizer );
-
- # loop over all points in the orbit
- for pnt in G.orbit do
-
- # add the corresponding coset to the set of elements
- rep := G.identity;
- while G.orbit[1] ^ rep <> pnt do
- rep := LeftQuotient( G.transversal[pnt/rep], rep );
- od;
- UniteSet( elms, stb * rep );
-
- od;
-
- fi;
-
- # return the result
- return elms;
- end;
-
-
- #############################################################################
- ##
- #F PermGroupOps.IsFinite(<P>) . . . . test if a permutation group is finite
- ##
- PermGroupOps.IsFinite := function ( G )
- return true;
- end;
-
-
- #############################################################################
- ##
- #F PermGroupOps.Size(<G>) . . . . . . . . . . . size of a permutation group
- ##
- PermGroupOps.Size := function ( G )
- local S, # stabilizer of <G>
- size; # size of <G>, result
-
- # make sure that <G> has a stabchain
- if not IsBound(G.stabilizer) then MakeStabChain( G ); fi;
-
- # go down the stabchain and multiply the orbitlengths
- size := 1;
- S := G;
- while S.generators <> [] do
- size := size * Length( S.orbit );
- S := S.stabilizer;
- od;
-
- # return the size
- return size;
- end;
-
-
- #############################################################################
- ##
- #F PermGroupOps.\in(<g>,<G>) . . . . membership test for permutation group
- ##
- PermGroupOps.\in := function ( g, G )
- local S, # stabilizer of <G>
- bpt; # basepoint of <S>
-
- # make sure that we can proceed with the rest
- if ( IsPerm( g ) = false
- or IsPerm( G.identity ) = false)
- and ( IsRec( g ) = false
- or IsBound( g.operations ) = false
- or IsRec( G.identity ) = false
- or IsBound( G.identity.operations ) = false
- or g.operations <> G.identity.operations)
- then
- return GroupOps.\in( g, G );
- fi;
-
- # handle special case
- if g in G.generators then
- return true;
- fi;
-
- # make sure that <G> has a stabchain
- if not IsBound(G.stabilizer) then MakeStabChain( G ); fi;
-
- # go down the stabchain and reduce the permutation
- S := G;
- while S.generators <> [] do
- bpt := S.orbit[1];
-
- # if '<bpt>^<g>' is not in the orbit then <g> is not in <G>
- if not IsBound(S.transversal[bpt^g]) then
- return false;
- fi;
-
- # reduce <g> into the stabilizer
- while bpt ^ g <> bpt do
- g := g * S.transversal[bpt^g];
- od;
-
- # and test if the reduced <g> lies in the stabilizer
- S := S.stabilizer;
- od;
-
- # <g> is in the trivial iff <g> is the identity
- return g = G.identity;
- end;
-
-
- #############################################################################
- ##
- #F PermGroupOps.Random(<G>) . . . . . random element of a permutation group
- ##
- PermGroupOps.Random := function ( G )
- local S, # stabilizer of <G>
- rnd, # random element of <G>, result
- pnt; # random point in <S>.orbit
-
- # make sure that <G> has a stabchain
- if not IsBound(G.stabilizer) then MakeStabChain( G ); fi;
-
- # go down the stabchain and multiply random representatives
- rnd := G.identity;
- S := G;
- while S.generators <> [] do
- pnt := RandomList(S.orbit) ^ rnd;
- while S.orbit[1]^rnd <> pnt do
- rnd := LeftQuotient( S.transversal[pnt/rnd], rnd );
- od;
- S := S.stabilizer;
- od;
-
- # return the random element
- return rnd;
- end;
-
-
- #############################################################################
- ##
- #F PermGroupOps.Order(<G>,<g>) . . . . . . . . . . . order of a permutation
- ##
- PermGroupOps.Order := function ( G, g )
- return OrderPerm( g );
- end;
-
-
- #############################################################################
- ##
- #F PermGroupOps.ConjugacyClass(<G>,<g>) . . . conjugacy class of an element
- #F in a permutation group
- #V ConjugacyClassPermGroupOps . . . operation record for conjugacy classes
- #V in a permutation group
- ##
- ## Conjugacy classes in permutation groups are almost like conjugacy
- ## classes in generic groups, except that 'Representative' accepts the
- ## centralizer of the second element as optional parameter.
- ##
- PermGroupOps.ConjugacyClass := function ( G, g )
- local C;
-
- # make the domain
- C := GroupOps.ConjugacyClass( G, g );
-
- # enter the operations record
- C.operations := ConjugacyClassPermGroupOps;
-
- # return the conjugacy class
- return C;
- end;
-
- ConjugacyClassPermGroupOps := Copy( ConjugacyClassGroupOps );
-
- ConjugacyClassPermGroupOps.\= := function ( C, D )
- local isEql;
- if IsRec( C ) and IsBound( C.isConjugacyClass )
- and IsRec( D ) and IsBound( D.isConjugacyClass )
- and C.group = D.group
- then
- if not IsBound( C.centralizer ) then
- C.centralizer := Centralizer( C.group, C.representative );
- fi;
- isEql := Size(C) = Size(D)
- and Order( C.group, C.representative )
- = Order( D.group, D.representative )
- and C.group.operations.RepresentativeConjugationElements(
- C.group,
- D.representative,
- C.representative,
- C.centralizer ) <> false;
- else
- isEql := DomainOps.\=( C, D );
- fi;
- return isEql;
- end;
-
- ConjugacyClassPermGroupOps.\in := function ( g, C )
- if not IsBound( C.centralizer ) then
- C.centralizer := Centralizer( C.group, C.representative );
- fi;
- return g in C.group
- and Order( C.group, g ) = Order( C.group, C.representative )
- and C.group.operations.RepresentativeConjugationElements(
- C.group,
- g,
- C.representative,
- C.centralizer ) <> false;
- end;
-
-
- #############################################################################
- ##
- #F PermGroupOps.ConjugateSubgroup(<G>,<g>) conjugate of a permutation group
- ##
- PermGroupOps.ConjugateSubgroup := function ( G, g )
- local H, # conjugated subgroup, result
- S, # stabilizer of <G>
- T, # stabilizer of <H>
- str, # strong generators of <G>
- cnj, # conjugated generators
- i; # loop variable
-
- # first conjugate the generators (and the element list if present)
- H := GroupOps.ConjugateSubgroup( G, g );
-
- # now conjugate the stabchain if present
- if IsBound( G.stabilizer ) and not IsBound( H.stabilizer ) then
-
- str := Concatenation( [ G.identity ], G.generators );
- cnj := Concatenation( [ H.identity ], H.generators );
-
- # go down the stabchain and conjugate every stabilizer
- S := G;
- T := H;
- while S.generators <> [] do
-
- # conjugate the generators of this stabilizer
- T.generators := [];
- for i in [1..Length(S.generators)] do
- if not S.generators[i] in str then
- Add( str, S.generators[i] );
- Add( cnj, S.generators[i] ^ g );
- fi;
- T.generators[i]:=cnj[Position(str,S.generators[i])];
- od;
-
- # conjugate the orbit and the transversal of this stabilizer
- T.orbit := [];
- T.transversal := [];
- for i in [1..Length(S.orbit)] do
- T.orbit[i] := S.orbit[i] ^ g;
- T.transversal[T.orbit[i]] :=
- cnj[ Position(str,S.transversal[S.orbit[i]]) ];
- od;
-
- # make a new stabilizer
- T.stabilizer := Group( [], T.identity );
-
- # on to the next stabilizer
- S := S.stabilizer;
- T := T.stabilizer;
- od;
-
- fi;
-
- # return the conjugated subgroup
- return H;
- end;
-
-
- #############################################################################
- ##
- #F PermGroupOps.IsSimple(<G>) . . . . test if a permutation group is simple
- ##
- ## This is a most interesting function. It tests whether a permutation
- ## group is simple by testing whether the group is perfect and then only
- ## looking at the size of the group and the degree of a primitive operation.
- ## Basically it uses the O'Nan--Scott theorem, which gives a pretty clear
- ## description of perfect primitive groups. This algorithm is described in
- ## William M. Kantor,
- ## Finding Composition Factors of Permutation Groups of Degree $n\leq 10^6$,
- ## J. Symbolic Computation, 12:517--526, 1991.
- ##
- PermGroupOps.IsSimple := function ( G )
- local D, # operation domain of <G>
- hom, # transitive constituent or blocks homomorphism
- d, # degree of <G>
- n, m, # $d = n^m$
- simple, # list of orders of simple groups
- transperf, # list of orders of transitive perfect groups
- s, t; # loop variables
-
- # if <G> is the trivial group, it is simple
- if Size( G ) = 1 then
- return true;
- fi;
-
- # first find a transitive representation for <G>
- D := Orbit( G, PermGroupOps.SmallestMovedPoint( G ) );
- if not IsEqualSet( PermGroupOps.MovedPoints( G ), D ) then
- hom := OperationHomomorphism( G, Operation( G, D ) );
- if Size( G ) <> Size( Image( hom ) ) then
- return false;
- fi;
- G := Image( hom );
- fi;
-
- # next find a primitive representation for <G>
- D := Blocks( G, PermGroupOps.MovedPoints( G ) );
- while Length( D ) <> 1 do
- hom := OperationHomomorphism( G, Operation( G, D, OnSets ) );
- if Size( G ) <> Size( Image( hom ) ) then
- return false;
- fi;
- G := Image( hom );
- D := Blocks( G, PermGroupOps.MovedPoints( G ) );
- od;
-
- # compute the degree $d$ and express it as $d = n^m$
- D := PermGroupOps.MovedPoints( G );
- d := Length( D );
- n := SmallestRootInt( Length( D ) );
- m := LogInt( Length( D ), n );
- if 10^6 < d then
- Error("cannot decide whether <G> is simple or not");
- fi;
-
- # if $G = C_p$, it is simple
- if IsPrime( Size( G ) ) then
- return true;
-
- # if $G = A_d$, it is simple (unless $d < 5$)
- elif Size( G ) = Factorial( d ) / 2 then
- return 5 <= d;
-
- # if $G = S_d$, it is not simple (except $S_2$)
- elif Size( G ) = Factorial( d ) then
- return 2 = d;
-
- # if $G$ is not perfect, it is not simple (unless $G = C_p$, see above)
- elif Size( DerivedSubgroup( G ) ) < Size( G ) then
- return false;
-
- # if $\|G\| = d^2$, it is not simple (Kantor's Lemma 4)
- elif Size( G ) = d ^ 2 then
- return false;
-
- # if $d$ is a prime, <G> is simple
- elif IsPrime( d ) then
- return true;
-
- # if $G = U(4,2)$, it is simple (operation on 27 points)
- elif d = 27 and Size( G ) = 25920 then
- return true;
-
- # if $G = PSL(n,q)$, it is simple (operations on prime power points)
- elif ( (d = 8 and Size(G) = (7^3-7)/2 ) # PSL(2,7)
- or (d = 9 and Size(G) = (8^3-8) ) # PSL(2,8)
- or (d = 32 and Size(G) = (31^3-31)/2 ) # PSL(2,31)
- or (d = 121 and Size(G) = 237783237120) # PSL(5,3)
- or (d = 128 and Size(G) = (127^3-127)/2 ) # PSL(2,127)
- or (d = 8192 and Size(G) = (8191^3-8191)/2 ) # PSL(2,8191)
- or (d = 131072 and Size(G) = (131071^3-131071)/2) # PSL(2,131071)
- or (d = 524288 and Size(G) = (524287^3-524287)/2)) # PSL(2,524287)
- and IsTransitive( Stabilizer( G, D[1] ), Difference( D, [ D[1] ] ) )
- then
- return true;
-
- # if $d$ is a prime power, <G> is not simple (except the cases above)
- elif IsPrimePowerInt( d ) then
- return false;
-
- # if we don't have at least an $A_5$ acting on the top, <G> is simple
- elif m < 5 then
- return true;
-
- # otherwise we must check for some special cases
- else
-
- # orders of simple subgroups of $S_n$ with primitive normalizer
- simple := [ ,,,,,
- [60,360],,,, # 5: A(5), A(6)
- [60,360,1814400],, # 10: A(5), A(6), A(10)
- [660,7920,95040,239500800],, # 12: PSL(2,11), M(11), M(12), A(12)
- [1092,43589145600], # 14: PSL(2,13), A(14)
- [360,2520,20160,653837184000] # 15: A(6), A(7), A(8), A(15)
- ];
-
- # orders of transitive perfect subgroups of $S_m$
- transperf := [ ,,,,
- [60], # 5: A(5)
- [60,360], # 6: A(5), A(6)
- [168,2520], # 7: PSL(3,2), A(7)
- [168,8168,20160] # 8: PSL(3,2), AGL(3,2), A(8)
- ];
-
- # test the special cases (Kantor's Lemma 3)
- for s in simple[n] do
- for t in transperf[m] do
- if Size( G ) mod (t * s^m) = 0
- and (((t * (2*s)^m) mod Size( G ) = 0 and s <> 360)
- or ((t * (4*s)^m) mod Size( G ) = 0 and s = 360))
- then
- return false;
- fi;
- od;
- od;
-
- # otherwise <G> is simple
- return true;
-
- fi;
-
- end;
-
-
- #############################################################################
- ##
- #F PermGroupOps.Base(<G>) . . . . . . . . . . base for a permutation group
- ##
- PermGroupOps.Base := function ( G )
- local S, # stabilizer of <G>
- base; # base <base>, result
-
- # make sure there is a stabchain
- if not IsBound(G.stabilizer) then MakeStabChain(G); fi;
-
- # go down the stabchain and collect the basepoints
- base := [];
- S := G;
- while IsBound(S.stabilizer) do
- Add( base, S.orbit[1] );
- S := S.stabilizer;
- od;
-
- # return the base
- return base;
- end;
-
-
- #############################################################################
- ##
- #F PermGroupOps.StrongGenerators(<G>) . . . . . . strong generating system
- #F of a permutation group
- ##
- PermGroupOps.StrongGenerators := function ( G )
- local S, # stabilizer of <G>
- gens; # strong generators, result
-
- # make sure that <G> has a stabchain
- if not IsBound(G.stabilizer) then MakeStabChain( G ); fi;
-
- # go down the stabchain and collect the strong generators
- gens := [];
- S := G;
- while S.generators <> [] do
- UniteSet( gens, S.generators );
- S := S.stabilizer;
- od;
-
- # return the strong generators
- return gens;
- end;
-
-
- #############################################################################
- ##
- #F PermGroupOps.Indices(<G>) . . . . . . . . . . indices of stabilizer chain
- #F of a permutation group
- ##
- PermGroupOps.Indices := function ( G )
- local S, # stabilizer of <G>
- inds; # indices, result
-
- # make sure that <G> has a stabchain
- if not IsBound(G.stabilizer) then MakeStabChain( G ); fi;
-
- # go down the stabchain and collect the indices
- inds := [];
- S := G;
- while IsBound(S.stabilizer) do
- Add( inds, Length( S.orbit ) );
- S := S.stabilizer;
- od;
-
- # return the indices
- return inds;
- end;
-
-
- #############################################################################
- ##
- #F PermGroupOps.SmallestGenerators(<G>) . . . . smallest generating system
- #F of a permutation group
- ##
- PermGroupOps.SmallestGenerators := function ( G )
-
- # first we need a stabilizer chain with respect to the smallest base
- MakeStabChain( G, G.operations.MovedPoints( G ) );
-
- # call the recursive function to do the work
- return G.operations.SmallestGeneratorsStab( G );
- end;
-
- PermGroupOps.SmallestGeneratorsStab := function ( S )
- local gens, # smallest generating system of <S>, result
- gen, # one generator in <gens>
- orb, # basic orbit of <S>
- pnt, # one point in <orb>
- T; # stabilizer in <S>
-
- # handle the anchor case
- if S.generators = [] then
- return [];
- fi;
-
- # now get the smallest generating system of the stabilizer
- gens := PermGroupOps.SmallestGeneratorsStab( S.stabilizer );
-
- # get the sorted orbit (the basepoint will be the first point)
- orb := Set( S.orbit );
- SubtractSet( orb, [S.orbit[1]] );
-
- # handle the other points in the orbit
- while orb <> [] do
-
- # take the smallest point (coset) and one representative
- pnt := orb[1];
- gen := S.identity;
- while S.orbit[1] ^ gen <> pnt do
- gen := LeftQuotient( S.transversal[ pnt / gen ], gen );
- od;
-
- # the next generator is the smallest element in this coset
- T := S.stabilizer;
- while T.generators <> [] do
- pnt := Minimum( OnTuples( T.orbit, gen ) );
- while T.orbit[1] ^ gen <> pnt do
- gen := LeftQuotient( T.transversal[ pnt / gen ], gen );
- od;
- T := T.stabilizer;
- od;
-
- # add this generator to the generators list and reduce orbit
- Add( gens, gen );
- SubtractSet( orb, Orbit( Group( gens, () ), S.orbit[1] ) );
-
- od;
-
- # return the smallest generating system
- return gens;
- end;
-
-
- #############################################################################
- ##
- #F PermGroupOps.SylowSubgroup(<G>,<p>) . . . . . . . . . . . Sylow subgroup
- #F of a permutation group
- ##
- PermGroupOps.SylowSubgroup := function ( G, p )
- local S, # <p>-Sylow subgroup of <G>, result
- q, # largest power of <p> dividing the size of <G>
- D, # domain of operation of <G>
- O, # one orbit of <G> in this domain
- B, # blocks of the operation of <G> on <D>
- f, # operation homomorphism of <G> on <O> or <B>
- T, # <p>-Sylow subgroup in the image of <f>
- g, g2, # one <p> element of <G>
- C, C2; # centralizer of <g> in <G>
-
- # get the size of the <p>-Sylow subgroup
- q := 1; while Size( G ) mod (q * p) = 0 do q := q * p; od;
- InfoGroup1("#I ",p,"-SylowSubgroup in ",GroupString(G,"G"),"\n");
-
- # handle trivial subgroup
- if q = 1 then
- InfoGroup1("#I ",p,"-SylowSubgroup returns trivial subgroup\n");
- return TrivialSubgroup( G );
- fi;
-
- # go down in stabilizers as long as possible
- if not IsBound( G.orbit ) then MakeStabChain( G ); fi;
- while Length( G.orbit ) mod p <> 0 do
- InfoGroup2("#I go down to stabilizer\n");
- G := Stabilizer( G, G.orbit[1] );
- od;
-
- # handle full group
- if q = Size( G ) then
- InfoGroup2("#I ",p,"-SylowSubgroup returns full group\n");
- return G;
- fi;
-
- # handle <p>-Sylow subgroups of size <p>
- if q = p then
- InfoGroup2("#I ",p,"-SylowSubgroup returns cyclic group\n");
- repeat g := Random( G ); until Order( G, g ) mod p = 0;
- g := g ^ (Order( G, g ) / p);
- return Subgroup( Parent(G), [ g ] );
- fi;
-
- # if the group is not transitive work with the transive constituents
- D := PermGroupOps.MovedPoints( G );
- if not IsTransitive( G, D ) then
- S := G;
- while q < Size( S ) do
- InfoGroup2("#I approximation is ",GroupString(S,"S"),"\n");
- O := Orbit( S, D[1] );
- f := OperationHomomorphism( S, Operation( S, O ) );
- T := PermGroupOps.SylowSubgroup( Image( f ), p );
- S := PreImage( f, T );
- SubtractSet( D, O );
- od;
- InfoGroup1("#I ",p,"-SylowSubgroup returns ",
- GroupString(S,"S"),"\n");
- return S;
- fi;
-
- # if the group is not primitive work in the image first
- B := Blocks( G, D );
- if Length( B ) <> 1 then
- f := OperationHomomorphism( G, Operation( G, B, OnSets ) );
- T := PermGroupOps.SylowSubgroup( Image( f ), p );
- if Size( T ) < Size( Image( f ) ) then
- S := PermGroupOps.SylowSubgroup( PreImage( f, T ), p );
- InfoGroup1("#I ",p,"-Sylow subgroup returns ",
- GroupString(S,"S"),"\n");
- return S;
- fi;
- fi;
-
- # find a <p> element whose centralizer contains a full <p>-Sylow subgroup
- repeat g := Random( G ); until Order( G, g ) mod p = 0;
- g := g ^ (Order( G, g ) / p);
- C := Centralizer( G, g );
- Size( C );
- InfoGroup2("#I "," ",p,"-element centralizer is ",
- GroupString(C,"C"),"\n");
- while GcdInt( q, Size( C ) ) < q do
- repeat g2 := Random( C ); until Order( G, g2 ) mod p = 0;
- g2 := g2 ^ (Order( G, g2 ) / p);
- C2 := Centralizer( G, g2 );
- if GcdInt( q, Size( C ) ) < GcdInt( q, Size( C2 ) ) then
- C := C2; g := g2;
- InfoGroup2("#I "," ",p,"-element centralizer is ",
- GroupString(C,"C"),"\n");
- fi;
- od;
-
- # the centralizer operates on the cycles of the <p> element
- B := List( Cycles( g, D ), Set );
- f := OperationHomomorphism( C, Operation( C, B, OnSets ) );
- T := PermGroupOps.SylowSubgroup( Image( f ), p );
- S := PreImage( f, T );
- InfoGroup1("#I ",p,"-SylowSubgroup returns ",GroupString(S,"S"),"\n");
- return S;
-
- end;
-
-
- #############################################################################
- ##
- #F PermGroupOps.Exponent( <G> ) . . . . . . . . . . . . . . exponent of <G>
- ##
- PermGroupOps.Exponent := function( G )
- return Lcm( Set( List( ConjugacyClasses(G),
- x -> Order( G, Representative(x) ) ) ) );
- end;
-
-
- #############################################################################
- ##
- #R Read . . . . . . . . . . . . . read other function from the other files
- ##
- ReadLib( "permoper" );
- ReadLib( "permbckt" );
- ReadLib( "permnorm" );
- ReadLib( "permcose" );
- ReadLib( "permhomo" );
- ReadLib( "permprod" );
- ReadLib( "permcser" );
- ReadLib( "permag" );
- ReadLib( "permctbl" );
- ReadLib( "lattperm" );
-
-
- #############################################################################
- ##
- #E Emacs . . . . . . . . . . . . . . . . . . . . . . . local emacs variables
- ##
- ## Local Variables:
- ## mode: outline
- ## outline-regexp: "#F\\|#V\\|#E\\|#R"
- ## fill-column: 73
- ## fill-prefix: "## "
- ## eval: (hide-body)
- ## End:
- ##
-
-
-
-