############################################################################# ## ## This file is part of GAP, a system for computational discrete algebra. ## This file's authors include Heiko Theißen. ## ## Copyright of GAP belongs to its developers, whose names are too numerous ## to list here. Please refer to the COPYRIGHT file for details. ## ## SPDX-License-Identifier: GPL-2.0-or-later ## ## This file contains functions which deal with polycyclic generating ## systems of solvable permutation groups. ##
############################################################################# ## #R IsMemberPcSeriesPermGroup . . . . . . . . . . . . . members of pc series ##
DeclareRepresentation( "IsMemberPcSeriesPermGroup",
IsPermGroup, [ "noInSeries" ] );
############################################################################# ## #F AddNormalizingElementPcgs( <G>, <z> ) . . . . . cyclic extension for pcgs ##
InstallGlobalFunction( AddNormalizingElementPcgs, function( G, z )
local S, A, pos, relord,
pnt, orb, l, L, n, m, img, i, f, p, edg;
StretchImportantSLPElement(z);
S := G;
A := G;
pos := 1;
L := [ ]; if IsBound( G.relativeOrders ) then relord := G.relativeOrders; else relord := false; fi;
# Loop over the stabilizer chain. while z <> S.identity do
# If necessary, extend the stabilizer chain. if IsBound( G.base ) then
ChooseNextBasePoint( S, G.base, [ z ] ); elif not IsBound( S.stabilizer ) then
InsertTrivialStabilizer( S, SmallestMovedPoint( z ) );
Unbind( S.stabilizer.relativeOrders ); fi;
# Extend the orbit.
orb := S.orbit;
pnt := orb[ 1 ];
l := Length( orb ); Add( L, l );
n := l;
m := 1;
img := pnt / z; while not IsBound( S.translabels[ img ] ) do
orb[ n + 1 ] := img; for i in [ 2 .. l ] do
orb[ n + i ] := orb[ n - l + i ] / z;
od;
n := n + l;
m := m + 1;
img := img / z;
od;
# Let $m = p_1p_2...p_l$. Then instead of entering <z> into # '<G>.translabels' <d> times, enter $z^d$ once, for $d=p_1p_2...p_k$ # (where $k<=l$). if m > 1then
# If <m> = 1, the current level <A> has not been extended and <z> # has been shifted into <w> in the next level. <w> or something # further down, which will extend a future level, must be put in # as a generator here.
AddSet( S.genlabels, 1 - pos ); while A.orbit[ 1 ] <> S.orbit[ 1 ] do
AddSet( A.genlabels, 1 - pos );
A := A.stabilizer;
od;
A := A.stabilizer;
f := 1; for p in Factors(Integers, m ) do if relord <> false then
Add( relord, p, pos ); fi;
pos := pos + 1;
Add( S.labels, z, pos );
edg := ListWithIdenticalEntries( l, -pos ); for i in f * [ 1 .. m / f - 1 ] do
S.translabels{ orb{ i * l + [ 1 .. l ] } } := edg;
od;
f := f * p;
z := z ^ p;
od;
fi;
# Find a cofactor to <z> such that the product fixes <pnt>.
edg := S.translabels[ pnt ^ z ]; while edg <> 1do if edg > 1then z := z * S.labels[ edg + pos - 1 ]; else z := z * S.labels[ -edg ]; fi;
edg := S.translabels[ pnt ^ z ];
od;
# Go down one step in the stabilizer chain.
S := S.stabilizer;
od;
if pos = 1then
return false; fi;
# Correct the `genlabels' and `translabels' entries and install the # `generators'.
S := G; i := 0; pos := pos - 1; while IsBound( S.stabilizer ) do
p := PositionSorted( S.genlabels, 2 ); if not IsEmpty( S.genlabels )
and S.genlabels[ 1 ] < 1then
S.genlabels[ 1 ] := 2 - S.genlabels[ 1 ]; fi;
orb := [ p .. Length( S.genlabels ) ];
S.genlabels{ orb } := S.genlabels{ orb } + pos; if i < Length( L ) then i := i + 1; l := L[ i ]; else l := Length( S.orbit ); fi;
orb := S.orbit{ [ 2 .. l ] };
S.translabels{ orb } := S.translabels{ orb } + pos;
orb := S.orbit{ [ l + 1 .. Length( S.orbit ) ] };
S.translabels{ orb } := -S.translabels{ orb };
S.transversal := [ ];
S.transversal{ S.orbit } := S.labels{ S.translabels{ S.orbit } };
S.generators := S.labels{ S.genlabels }; for z in S.generators do
StretchImportantSLPElement(z);
od;
S := S.stabilizer;
od;
return true; end );
############################################################################# ## #F ExtendSeriesPermGroup( ... ) . . . . . . extend a series of a perm group ##
InstallGlobalFunction( ExtendSeriesPermGroup, function(
G, # the group in which factors are to be normal/central
series, # the series being constructed
cent, # flag: true if central factors are wanted
desc, # flag: true if a fastest-descending series is wanted
elab, # flag: true if elementary abelian factors are wanted
s, # the element to be added to `series[ <lev> ]'
lev, # the level of the series which is to be extended
dep, # the depth of <s> in <G>
bound ) # a bound on the depth, for solvability/nilpotency tests
local M0, M1, C, X, oldX, T, t, u, w, r, done,
ndep, ord, gcd, p;
# If we are too deep in the derived series, give up. if dep > bound then
return s; fi;
if desc then
# If necessary, add a new (trivial) subgroup to the series. if lev + 2 > Length( series ) then
series[ lev + 2 ] := StructuralCopy( series[ lev + 1 ] ); fi;
M0 := series[ lev + 1 ];
M1 := series[ lev + 2 ];
X := M0.labels{ [ 2 .. Length( M0.labels )
- Length( M1.labels ) + 1 ] };
r := lev + 2;
# If the series need not be fastest-descending, prepare to add a new # group to the list. else
M1 := series[ 1 ];
M0 := StructuralCopy( M1 );
X := [ ];
r := 1; fi;
# For elementary abelian factors, find a suitable prime. if IsInt( elab ) then
p := elab; elif elab then
# For central series, the prime must be given. if cent then
Error("cannot construct central el ab series with varying primes"); fi;
ord := Order( s ); if not IsEmpty( X ) then
gcd := GcdInt( ord, Order( X[ 1 ] ) ); if gcd <> 1then
ord := gcd; fi; fi;
p := Factors(Integers, ord )[ 1 ]; fi;
# Loop over all conjugates of <s>.
C := [ s ]; while not IsEmpty( C ) do
t := C[ 1 ];
C := C{ [ 2 .. Length( C ) ] }; if not MembershipTestKnownBase( M0, G, t ) then
# Form all necessary commutators with <t> and for elementary # abelian factors also a <p>th power. if cent then T := SSortedList( GeneratorsOfGroup( G ) ); else T := SSortedList( X ); fi; done := false; while not done and ( not IsEmpty( T ) or elab <> false ) do if not IsEmpty( T ) then
u := T[ 1 ]; RemoveSet( T, u );
w := Comm( t, u ); ndep := dep + 1; else done := true;
w := t ^ p; ndep := dep; fi;
# If the commutator or power is not in <M1>, recursively # extend <M1>. if not MembershipTestKnownBase( M1, G, w ) then
w := ExtendSeriesPermGroup( G, series, cent,
desc, elab, w, lev + 1, ndep, bound ); if w <> true then
return w; fi;
M1 := series[ r ];
# The enlarged <M1> also pushes up <M0>.
M0 := StructuralCopy( M1 );
oldX := X;
X := [ ]; for u in oldX do if AddNormalizingElementPcgs( M0, u ) then
Add( X, u ); else
RemoveSet( T, u ); fi;
od; if MembershipTestKnownBase( M0, G, t ) then done := true; fi; fi;
od;
# Add <t> to <M0> and register its conjugates. if AddNormalizingElementPcgs( M0, t ) then
Add( X, t ); fi;
UniteSet( C, List( GeneratorsOfGroup( G ), g -> t ^ g ) );
fi;
od;
# For a fastest-descending series, replace the old group. Otherwise, add # the new group to the list. if desc then
series[ lev + 1 ] := M0; if IsEmpty( X ) then
Remove( series, lev + 2 ); fi; else if not IsEmpty( X ) then
Add( series, M0, 1 ); fi; fi;
return true; end );
############################################################################# ## #F TryPcgsPermGroup(<Act>[, <G>] , <cent>, <desc>, <elab>) . . try for pcgs ##
InstallGlobalFunction(TryPcgsPermGroup,function(arg)
local grp, pcgs, U, oldlen, series, y, w, whole,
bound, deg, step, i, S, filter,A,G,cent,desc,elab;
# If the last member <U> of the series <G> already has a pcgs, start with # its stabilizer chain. if IsList( A ) then
G:=A;
A:=A[1];
U := Last(G); if HasPcgs( U ) and IsPcgsPermGroupRep( Pcgs( U ) ) then
U := CopyStabChain( Pcgs( U )!.stabChain ); fi; elif Length(arg)>4then
G:=arg[2];
U := TrivialSubgroup( G ); if ForAll(GeneratorsOfGroup(G),IsOne) then G:=[G]; else G:=[G,U];fi; else
G:=A;
U := TrivialSubgroup( G ); if IsTrivial( G ) then G := [ G ]; else G := [ G, U ]; fi; fi;
# Otherwise start with stabilizer chain of <U> with identical `labels' # components on all levels. if IsGroup( U ) then if IsTrivial( U ) and not HasStabChainMutable( U ) then
U := EmptyStabChain( [ ], One( U ) ); else
S:=U;
U := StabChainMutable( U ); if IsBound( U.base ) and Length(U.base)>0then i := U.base; else i := fail; fi;
# ensure compatible bases if HasBaseOfGroup(G[1])
and not IsSubset(BaseOfGroup(G[1]),BaseStabChain(U)) then
# ensure compatible bases
# compute a new stab chain without touching the stab chain # stored in S #T this is less than satisficial but I don't see how otherwise #T to avoid those %$#@ side effects. AH
U:= StabChainOp( GroupByGenerators(GeneratorsOfGroup(S),One(S) ),
rec(base:=BaseOfGroup(G[1]),size:=Size(S))); else
U := StabChainBaseStrongGenerators( BaseStabChain( U ),
StrongGeneratorsStabChain( U ),U.identity ); if i <> fail then
U.base := i; fi; fi; fi; fi;
# The `genlabels' at every level of $U$ must be sets.
S := U; while not IsEmpty( S.genlabels ) do
Sort( S.genlabels );
S := S.stabilizer;
od;
grp := G[ 1 ];
whole := IsTrivial( Last(G) );
oldlen := Length( U.labels );
series := [ U ];
series[ 1 ].relativeOrders := [ ];
if not IsTrivial( grp ) then
# The derived length of <G> was bounded by Dixon. The nilpotency # class of <G> is at most Max( log_p(d)-1 ).
deg := NrMovedPoints( grp ); if cent then
bound := Maximum( List( Collected( Factors(Integers, deg ) ), p ->
p[ 1 ] ^ ( LogInt( deg, p[ 1 ] ) ) ) ); else
bound := Int( LogInt( deg ^ 5, 3 ) / 2 ); fi; # avoid recursion trap through Size if bound>4900then Size(grp); fi; if HasSize( grp )
and Length( Factors(Integers, Size( grp ) ) ) < bound then
bound := Length( Factors(Integers, Size( grp ) ) ); fi;
for step in Reversed( [ 1 .. Length( G ) - 1 ] ) do for y in GeneratorsOfGroup( G[ step ] ) do if not y in GeneratorsOfGroup( G[ step + 1 ] ) then
w := ExtendSeriesPermGroup( A, series, cent,
desc, elab, y, 0, 0, bound ); if w <> true then
SetIsNilpotentGroup( grp, false ); if not cent then
SetIsSolvableGroup( grp, false ); fi;
# In case of failure, return two ``witnesses'': The # pcgs of the solvable normal subgroup of <G> # constructed so far, and an element in # $G^{(\infty)}$. #T this should be cleaned up.
return [ PcgsStabChainSeries( IsPcgsPermGroupRep,
GroupStabChain( grp, series[ 1 ], true ),
series, oldlen,false ),
w ];
fi; fi;
od;
od; fi;
# Construct the pcgs object. if whole then filter := IsPcgsPermGroupRep; else filter := IsModuloPcgsPermGroupRep; fi;
if elab=true then
filter:=filter and IsPcgsElementaryAbelianSeries; fi;
if cent then
filter:=filter and IsPcgsCentralSeries; fi;
pcgs := PcgsStabChainSeries( filter, grp, series, oldlen,
(elab=true) or cent);
if whole then
SetIsSolvableGroup( grp, true );
SetPcgs( grp, pcgs ); if not HasHomePcgs( grp ) then
SetHomePcgs( grp, pcgs ); fi;
SetGroupOfPcgs (pcgs, grp); if cent then
SetIsNilpotentGroup( grp, true ); fi; else
pcgs!.denominator := Last(G); if HasIsSolvableGroup( Last(G) )
and IsSolvableGroup( Last(G) ) then
SetIsSolvableGroup( grp, true ); fi; fi;
return pcgs; end);
## Based on `TryPcgsPermGroup', a method for PcgsByPcSequence
BindGlobal("ExtendSeriesPGParticular", function(
G, # the group in which factors are to be normal
series, # the series being constructed
adds) # the elements to be added to `series[ <lev> ]'
local M0, M1, C, X, oldX, T, t, u, w, r, done,
ord, p,ap,s;
# As series need not be fastest-descending, prepare to add a new # group to the list.
M1 := series[ 1 ];
M0 := StructuralCopy( M1 );
X := [ ];
r := 1;
# find next elt to add
ap:=1; while MembershipTestKnownBase(M0,G,adds[ap])=true do
ap:=ap+1; if ap>Length(adds) then
return fail; # nothing to add fi;
od;
s:=adds[ap];
# find prime.
ord:=Factors(Order( s ));
p:=First(Set(ord),x->MembershipTestKnownBase(M0,G,s^x)=true);
# Loop over adds
ap:=ap-1;
C := [s]; while not IsEmpty( C ) do
t := C[ 1 ]; if not MembershipTestKnownBase( M0, G, t ) then
# Form all necessary commutators with <t> and for elementary # abelian factors also a <p>th power.
T := SSortedList( X ); done := false; while not done and not IsEmpty( T ) do if not IsEmpty( T ) then
u := T[ 1 ]; RemoveSet( T, u );
w := Comm( t, u ); else done := true;
w := t ^ p; fi;
# If the commutator or power is not in <M1>, # it was not a proper pcgs if not MembershipTestKnownBase( M1, G, w ) then
return w; fi;
od;
ap:=ap+1;
t:=adds[ap];
# Add <t> to <M0> and register its conjugates. if AddNormalizingElementPcgs( M0, t ) then
Add( X, t ); fi;
Append( C, List( GeneratorsOfGroup( G ), g -> t ^ g ) );
else # this t is done with
C := C{ [ 2 .. Length( C ) ] }; fi;
od;
if not IsEmpty( X ) then
Add( series, M0, 1 ); fi;
return true; end );
InstallGlobalFunction(PermgroupSuggestPcgs,function(G,pcseq)
local grp, pcgs, U, series, w, bound, deg, S, filter;
U := TrivialSubgroup( G );
G := [ G, U ]; # Otherwise start with stabilizer chain of <U> with identical `labels' # components on all levels.
U := EmptyStabChain( [ ], One( U ) );
# The `genlabels' at every level of $U$ must be sets.
S := U; while not IsEmpty( S.genlabels ) do
Sort( S.genlabels );
S := S.stabilizer;
od;
grp := G[ 1 ];
series := [ U ];
series[ 1 ].relativeOrders := [ ];
# The derived length of <G> was bounded by Dixon. The nilpotency # class of <G> is at most Max( log_p(d)-1 ).
deg := NrMovedPoints( grp );
bound := Int( LogInt( deg ^ 5, 3 ) / 2 ); if HasSize( grp ) and Length( Factors(Integers, Size( grp ) ) ) < bound then
bound:=Length( Factors(Integers, Size( grp ) ) ); fi;
pcseq:=Reversed(pcseq); # build up
# can do repeat-until as group is not trivial
repeat
w := ExtendSeriesPGParticular( G[1], series, pcseq); if w <> true and w<>fail then # if it fails the pcgs does not fit an elementary # abelian series. In this case we need to defer to the # generic approach.
return fail; fi; #Print(List(series,SizeStabChain),":",Length(series[1].labels),":",List(series[1].labels,x->Position(pcseq,x)),"\n");
until w=fail;
# Construct the pcgs object.
filter := IsPcgsPermGroupRep and IsPcgsElementaryAbelianSeries;
# arbitrary pc sequence pcgs for perm group. Construct pcgs from it using # variant of sims' algorithm, then use translation of exponents.
InstallMethod(PcgsByPcSequenceNC,"perm group, Sims' algorithm",true,
[IsFamily,IsHomogeneousList and IsPermCollection],0,
function( efam, pcs )
local pfa, pcgs, pag, id, g, dg, i, new,
ord,codepths,pagpow,sorco,filter;
# quick check if not IsIdenticalObj( efam, ElementsFamily(FamilyObj(pcs)) ) then
Error( "elements family of <pcs> does not match <efam>" ); fi;
if ForAll(pcs,IsOne) then
TryNextMethod(); # degenerate case fi;
pfa := PermgroupSuggestPcgs(Group(pcs),pcs); if pfa=fail then
TryNextMethod(); fi;
if pfa=pcs then # is it by happenstance the one we want?
return pfa;
else # make a sorted/unsorted pcgs
# sort the elements according to the depth wrt pfa
pag := [];
new := [];
ord := [];
id := One(pcs[1]); for i in [ Length(pcs), Length(pcs)-1 .. 1 ] do
g := pcs[i];
dg := DepthOfPcElement( pfa, g ); while g <> id and IsBound(pag[dg]) do
g := ReducedPcElement( pfa, g, pag[dg] );
dg := DepthOfPcElement( pfa, g );
od; if g <> id then
pag[dg] := g;
new[dg] := i;
ord[i] := RelativeOrderOfPcElement( pfa, g ); fi;
od; if not IsHomogeneousList(ord) then
Error("not all relative orders given"); fi;
filter:=IsPcgs;
if IsSSortedList(new) and Length(new)=Length(pfa) then
filter:=filter and IsSortedPcgsRep; else
filter:=filter and IsUnsortedPcgsRep; fi;
# we have the same sequence, same depths, just changed by # multiplying elements of a lower level
pcgs := PcgsByPcSequenceCons( IsPcgsDefaultRep, filter,
efam, pcs,[] );
# Precompute the leading coeffs and the powers of pag up to the # relative order
pagpow:=[];
sorco:=[]; for i in [1..Length(pag)] do if IsBound(pag[i]) then
pagpow[i]:=
List([1..RelativeOrderOfPcElement(pfa,pag[i])-1],j->pag[i]^j);
sorco[i]:=LeadingExponentOfPcElement(pfa,pag[i]); fi;
od;
pcgs!.sortedPcSeqPowers:=pagpow;
pcgs!.sortedPcSequenceLeadCoeff:=sorco;
# codepths[i]: the minimum pcgs-depth that can be implied by pag-depth i
codepths:=[]; for dg in [1..Length(new)] do
g:=Length(new)+1; for i in [dg..Length(new)] do if IsBound(new[i]) and new[i]<g then
g:=new[i]; fi;
od;
codepths[dg]:=g;
od;
pcgs!.minimumCodepths:=codepths;
SetRelativeOrders( pcgs, ord ); if IsSortedPcgsRep(pcgs) then
pcgs!.inversePowers:=
List([1..Length(pfa)],i->(1/sorco[i]) mod ord[i]); fi; fi;
# if HasHomePcgs(G) and HomePcgs(G)<>pcgs then # G:=Group(series[1].generators,()); # fi; # SetGroupOfPcgs( pcgs, G );
return pcgs; end );
BindGlobal("NorSerPermPcgs",function(pcgs)
local ppcgs,series,stbc,G,i;
ppcgs := ParentPcgs (pcgs);
G:=GroupOfPcgs(pcgs);
series:=EmptyPlist( Length(pcgs!.generatingSeries) ); for i in [ 1 .. Length( pcgs!.generatingSeries ) ] do
stbc := ShallowCopy (pcgs!.generatingSeries[i]);
Unbind( stbc.relativeOrders );
Unbind( stbc.base );
series[ i ] := GroupStabChain( G, stbc, true ); if (not HasHomePcgs(series[i]) ) or HomePcgs(series[i]) = ppcgs then
SetHomePcgs ( series[ i ], ppcgs );
SetFilterObj( series[ i ], IsMemberPcSeriesPermGroup );
series[ i ]!.noInSeries := i; fi;
od;
return series; end);
InstallMethod(EANormalSeriesByPcgs,"perm group rep",true,
[IsPcgs and IsPcgsElementaryAbelianSeries and IsPcgsPermGroupRep],0,
NorSerPermPcgs);
InstallOtherMethod(EANormalSeriesByPcgs,"perm group modulo rep",true,
[IsModuloPcgsPermGroupRep and IsPcgsElementaryAbelianSeries],0,
NorSerPermPcgs);
############################################################################# ## #F PcgsMemberPcSeriesPermGroup( <U> ) . . . . pcgs for a group in the series ##
InstallGlobalFunction( PcgsMemberPcSeriesPermGroup, function( U )
local home, pcgs,npf;
home := HomePcgs( U );
npf:=home!.permpcgsNormalSteps;
if U!.noInSeries>Length(npf) then # special treatment for the trivial subgroup
pcgs:=InducedPcgsByGenerators(home,GeneratorsOfGroup(U)); else
pcgs := TailOfPcgsPermGroup( home,
npf[ U!.noInSeries ] ); fi;
SetGroupOfPcgs( pcgs, U );
return pcgs; end );
if mode = 'e'then
exp := ListWithIdenticalEntries( maxdepth - mindepth + 1, 0 ); fi;
base := BaseStabChain( pcgs!.stabChain );
bimg := OnTuples( base, g );
r := Length( base );
depth := mindepth;
while depth <= maxdepth do
# Determine the depth of <g>.
repeat
img := ShallowCopy( bimg );
gen := pcgs!.pcSequence[ depth ];
depth := depth + 1;
# Find the base level of the <depth>th generator, remove the part # of <g> moving the earlier basepoints.
H := pcgs!.stabChain;
bpt := H.orbit[ 1 ];
i := 1; while bpt ^ gen = bpt do while img[ i ] <> bpt do
img{ [ i .. r ] } := OnTuples( img{ [ i .. r ] },
H.transversal[ img[ i ] ] );
od;
H := H.stabilizer;
bpt := H.orbit[ 1 ];
i := i + 1;
od;
until depth > maxdepth or H.translabels[ img[ i ] ] = depth;
# If `H.translabels[ img[ i ] ] = depth', then <g> is not the # identity. if H.translabels[ img[ i ] ] = depth then if mode = 'd'then
return depth - 1; fi;
# Determine the <depth>th exponent.
e := RelativeOrders( pcgs )[ depth - 1 ];
i := img[ i ];
repeat
e := e - 1;
i := i ^ gen;
until H.translabels[ i ] <> depth;
# Remove the appropriate power of the <depth>th generator and # iterate.
exp[ depth - mindepth ] := e;
g := LeftQuotient( gen ^ e, g );
bimg := OnTuples( base, g );
############################################################################# ## #F PermpcgsPcGroupPcgs( <pcgs>, <index>, <isPcgsCentral> ) ## ## different than `PcGroupWithPcgs' since extra parameters for shortcut. ##
InstallGlobalFunction( PermpcgsPcGroupPcgs, function( pcgs, index, isPcgsCentral )
local m, sc, gens, p, i, i2, n, n2;
m := Length( pcgs );
sc := SingleCollector( FreeGroup(IsSyllableWordsFamily, m ),
RelativeOrders( pcgs ) );
gens := GeneratorsOfRws( sc );
# Find the relations of the p-th powers. Use the vector space structure # of the elementary abelian factors. for i in [ 1 .. Length( index ) - 1 ] do
p := RelativeOrders( pcgs )[ index[ i ] ]; for n in [ index[ i ] .. index[ i + 1 ] - 1 ] do
SetPowerNC( sc, n, LinearCombinationPcgs
( gens, ExponentsOfPcElement
( pcgs, pcgs[ n ] ^ p ) ) );
od;
od;
# Find the relations of the conjugates. for i in [ 1 .. Length( index ) - 1 ] do for n in [ index[ i ] .. index[ i + 1 ] - 1 ] do for i2 in [ 1 .. i - 1 ] do if isPcgsCentral then for n2 in [ index[ i2 ] .. index[ i2 + 1 ] - 1 ] do
SetConjugateNC( sc, n, n2,
GeneratorsOfRws( sc )[ n ]*
LinearCombinationPcgs( gens,
ExponentsOfPcElement( pcgs, Comm
( pcgs[ n ], pcgs[ n2 ] ) ) ) );
od; else for n2 in [ index[ i2 ] .. index[ i2 + 1 ] - 1 ] do
SetConjugateNC( sc, n, n2, LinearCombinationPcgs( gens,
ExponentsOfPcElement
( pcgs,
pcgs[ n ] ^ pcgs[ n2 ]) ) );
od; fi;
od; for n2 in [ index[ i ] .. n - 1 ] do
SetConjugateNC( sc, n, n2,
GeneratorsOfRws( sc )[ n ]*LinearCombinationPcgs( gens,
ExponentsOfPcElement( pcgs, Comm
( pcgs[ n ], pcgs[ n2 ] ) ) ) );
od;
od;
od;
UpdatePolycyclicCollector( sc );
m:=GroupByRwsNC( sc );
SetParentAttr(m,m); # some other routines are obnocious otherwise.
return m; end );
############################################################################# ## #F SolvableNormalClosurePermGroup( <G>, <H> ) . . . solvable normal closure ##
InstallGlobalFunction( SolvableNormalClosurePermGroup, function( G, H )
local U, oldlen, series, bound, z, S;
U := CopyStabChain( StabChainImmutable( TrivialSubgroup( G ) ) );
oldlen := Length( U.labels );
# The `genlabels' at every level of $U$ must be sets.
S := U; while not IsEmpty( S.genlabels ) do
Sort( S.genlabels );
S := S.stabilizer;
od;
if HasBaseOfGroup(G) and not IsSubset(G,BaseStabChain(U)) then
Error("incompatible bases"); fi;
U.relativeOrders := [ ];
series := [ U ];
# The derived length of <G> is at most (5 log_3(deg(<G>)))/2 (Dixon).
bound := Int( LogInt( Maximum(1,NrMovedPoints( G ) ^ 5), 3 ) / 2 ); if HasSize( G )
and Length( Factors(Integers, Size( G ) ) ) < bound then
bound := Length( Factors(Integers, Size( G ) ) ); fi;
if IsGroup( H ) then
H := GeneratorsOfGroup( H ); fi; for z in H do if ExtendSeriesPermGroup( G, series, false, false, false, z, 0, 0,
bound ) <> true then
return fail; fi;
od;
U := GroupStabChain( G, series[ 1 ], true );
SetIsSolvableGroup( U, true );
SetIsNormalInParent( U, true );
# remember the pcgs
SetPcgs(U,PcgsStabChainSeries(IsPcgsPermGroupRep,U,series,oldlen,false));
############################################################################# ## #M Pcgs( <G> ) . . . . . . . . . . . . . . . . . . . . pcgs for perm groups ##
InstallMethod( Pcgs, "Sims's method", true, [ IsPermGroup ], 100, # to override method ``from indep. generators of abelian group'' function( G )
local pcgs;
pcgs := TryPcgsPermGroup( G, false, false, true ); if not IsPcgs( pcgs ) then
return fail; else if not HasPcgsElementaryAbelianSeries(G) then
SetPcgsElementaryAbelianSeries(G,pcgs); fi;
return pcgs; fi; end );
if not IsPcgs( pcgs ) then
TryNextMethod(); else if not HasPcgsElementaryAbelianSeries(G) then
SetPcgsElementaryAbelianSeries(G,pcgs); fi;
return pcgs; fi; end );
G := GroupStabChain( pcgs!.stabChain );
SetPcgs( G, pcgs );
return G; end );
############################################################################# ## #M PcSeries( <pcgs> ) . . . . . . . . . . . . . . . . . . . for perm groups ##
InstallMethod( PcSeries, true, [ IsPcgs and IsPcgsPermGroupRep ], 0, function( pcgs )
local series, G, N, i;
G := GroupOfPcgs( pcgs );
N := CopyStabChain( StabChainImmutable( TrivialSubgroup( G ) ) );
series := [ GroupStabChain( G, CopyStabChain( N ), true ) ]; for i in Reversed( [ 1 .. Length( pcgs ) ] ) do
AddNormalizingElementPcgs( N, pcgs[ i ] );
Add( series, GroupStabChain( G, CopyStabChain( N ), true ) );
od;
return Reversed( series ); end );
i := 1;
pins:=pcgs!.permpcgsNormalSteps; while pins[ i ] < from do
i := i + 1;
od;
ran:=[pins[i]..Length(pcgs)];
ins:=pins{[i..Length(pins)]}-from+1;
filt:=IsPcgs #NOT PcgsPermGroupRep -- otherwise we get wrong exponents! #and IsPcgsPermGroupRep
and IsPrimeOrdersPcgs
and IsInducedPcgs and IsInducedPcgsRep and IsTailInducedPcgsRep
and HasParentPcgs;
attr:=[ParentPcgs,pcgs];
if HasIndicesEANormalSteps(pcgs) then
filt:=filt and HasIndicesEANormalSteps;
Append(attr,[IndicesEANormalSteps,ins]); fi; if HasEANormalSeriesByPcgs(pcgs) then
filt:=filt and HasEANormalSeriesByPcgs;
Append(attr,[EANormalSeriesByPcgs,
EANormalSeriesByPcgs(pcgs){[i..Length(pins)]}]); fi;
SetRelativeOrders(tail,RelativeOrders(pcgs){[from..Length(pcgs)]});
tail!.stabChain := StabChainMutable( EANormalSeriesByPcgs( pcgs )[ i ] ); if from < pins[ i ] then
tail := ExtendedPcgs( tail,
pcgs{ [ from .. pins[ i ] - 1 ] } ); fi;
tail!.tailStart := from; # information many InducedPcgs methods use
tail!.depthsInParent:=ran;
tail!.depthMapFromParent:=[];
tail!.depthMapFromParent{ran}:=[1..Length(tail)];
tail!.depthMapFromParent[Length(pcgs)+1]:=Length(tail)+1;
return tail;
end );
############################################################################# ## #M InducedPcgsByPcSequenceNC( <pcgs>, <pcs> ) . . . . . . . . as perm pcgs ##
InstallMethod( InducedPcgsByPcSequenceNC, "tail of perm pcgs", true,
[ IsPcgsPermGroupRep and IsPrimeOrdersPcgs and IsPcgs,
IsList and IsPermCollection ], 0, function( pcgs, pcs )
local l,i,ran;
l := Length( pcgs )-Length( pcs );
i := Position( pcgs!.permpcgsNormalSteps, l+1 );
ran:=[ l + 1 .. Length( pcgs ) ]; if i = fail or pcgs{ ran } <> pcs then
TryNextMethod(); fi;
return TailOfPcgsPermGroup(pcgs,ran[1]); end );
############################################################################# ## #M InducedPcgsWrtHomePcgs( <U> ) . . . . . . . . . . . . . . . via home pcgs ##
InstallMethod( InducedPcgsWrtHomePcgs, "tail of perm pcgs", true,
[ IsMemberPcSeriesPermGroup and HasHomePcgs ], 0, function( U )
local pcgs,par,ran;
pcgs := PcgsMemberPcSeriesPermGroup( U );
par:=HomePcgs(U);
SetFilterObj( pcgs, IsInducedPcgs and IsInducedPcgsRep);
SetParentPcgs( pcgs,par ) ; # information many InducedPcgs methods use
ran:=[par!.permpcgsNormalSteps[U!.noInSeries]..Length(par)];
pcgs!.depthsInParent:=ran;
pcgs!.depthMapFromParent:=[];
pcgs!.depthMapFromParent{ran}:=[1..Length(pcgs)];
pcgs!.depthMapFromParent[Length(par)+1]:=Length(pcgs)+1;
pcgs!.tailStart:=par!.permpcgsNormalSteps[U!.noInSeries];
return pcgs; end );
############################################################################# ## #M ExtendedPcgs( <N>, <gens> ) . . . . . . . . . . . . . . . in perm groups ##
InstallMethod( ExtendedPcgs, "perm pcgs", true,
[ IsPcgs and IsPcgsPermGroupRep and IsPrimeOrdersPcgs,
IsList and IsPermCollection ], 0, function( N, gens )
local S, gen, pcs, pcgs;
S := CopyStabChain( N!.stabChain );
S.relativeOrders := ShallowCopy( RelativeOrders( N ) ); for gen in Reversed( gens ) do
AddNormalizingElementPcgs( S, gen );
od;
pcs := S.labels{ [ 2 .. Length( S.labels ) -
Length( N!.stabChain.labels ) + Length( N ) + 1 ] }; if IsInducedPcgs( N ) then
pcgs := InducedPcgsByPcSequenceNC( ParentPcgs( N ), pcs ); else
pcgs := PcgsByPcSequenceCons( IsPcgsDefaultRep,
IsPcgs and IsPcgsPermGroupRep and IsPrimeOrdersPcgs,
FamilyObj( OneOfPcgs( N ) ), pcs,[] ); fi;
pcgs!.stabChain := S;
SetRelativeOrders( pcgs, S.relativeOrders );
Unbind( S.relativeOrders );
pcgs!.permpcgsNormalSteps:=Concatenation([1],N!.permpcgsNormalSteps+1);
SetEANormalSeriesByPcgs( pcgs, Concatenation( [ GroupStabChain( S ) ],
EANormalSeriesByPcgs( N ) ) );
return pcgs; end );
############################################################################# ## #M DepthOfPcElement( <pcgs>, <g> [ , <from> ] ) . . . . . . for perm groups ##
InstallMethod( DepthOfPcElement,"permpcgs", true,
[ IsPcgs and IsPcgsPermGroupRep and IsPrimeOrdersPcgs, IsPerm ], 0, function( pcgs, g )
return ExponentsOfPcElementPermGroup( pcgs, g, 1, Length( pcgs ), 'd' ); end );
InstallMethod( DepthAndLeadingExponentOfPcElement,"permpcgs", true,
[ IsPcgs and IsPcgsPermGroupRep and IsPrimeOrdersPcgs, IsPerm ], 0, function( pcgs, g )
return ExponentsOfPcElementPermGroup( pcgs, g, 1, Length( pcgs ), 's' ); end );
InstallOtherMethod( DepthOfPcElement,"permpcgs,start", true,
[ IsPcgs and IsPcgsPermGroupRep and IsPrimeOrdersPcgs, IsPerm,
IsPosInt ], 0, function( pcgs, g, depth )
return ExponentsOfPcElementPermGroup( pcgs, g, depth, Length( pcgs ), 'd' ); end );
############################################################################# ## #M LeadingExponentOfPcElement( <pcgs>, <g> ) . . . . . . . . for perm groups ##
InstallMethod( LeadingExponentOfPcElement, true,
[ IsPcgs and IsPcgsPermGroupRep and IsPrimeOrdersPcgs, IsPerm ], 0, function( pcgs, g )
return ExponentsOfPcElementPermGroup( pcgs, g, 1, Length( pcgs ), 'l' ); end );
############################################################################# ## #M ExponentsOfPcElement( <pcgs>, <g> [ , <poss> ] ) . . . . for perm groups ##
InstallMethod( ExponentsOfPcElement, "perm group", true,
[ IsPcgs and IsPcgsPermGroupRep and IsPrimeOrdersPcgs, IsPerm ], 0, function( pcgs, g )
return ExponentsOfPcElementPermGroup( pcgs, g, 1, Length( pcgs ), 'e' ); end );
InstallOtherMethod( ExponentsOfPcElement, "perm group with positions", true,
[ IsPcgs and IsPcgsPermGroupRep and IsPrimeOrdersPcgs, IsPerm,
IsList and IsCyclotomicCollection ], 0, function( pcgs, g, poss )
return ExponentsOfPcElementPermGroup( pcgs, g, 1, Maximum( poss ), 'e' )
{ poss }; # was: { poss - Minimum( poss ) + 1 }; end );
InstallOtherMethod( ExponentsOfPcElement, "perm group with 0 positions", true,
[ IsPcgs and IsPcgsPermGroupRep and IsPrimeOrdersPcgs, IsPerm,
IsList and IsEmpty ], 0, function( pcgs, g, poss )
return [ ]; end );
############################################################################# ## #M ExponentOfPcElement( <pcgs>, <g>, <pos> ) . . . . . . . . for perm groups ##
InstallMethod( ExponentOfPcElement, true,
[ IsPcgs and IsPcgsPermGroupRep and IsPrimeOrdersPcgs, IsPerm,
IsPosInt ], 0, function( pcgs, g, pos )
return ExponentsOfPcElementPermGroup( pcgs, g, 1, pos, 'e' )[ pos ]; end );
############################################################################# ## #M RepresentativeAction( <G>, <d>, <e>, OnPoints ) first compare cycles ##
InstallOtherMethod( RepresentativeActionOp, "cycle structure comparison for solvable perm groups", true,
[ IsPermGroup and CanEasilyComputePcgs, IsPerm, IsPerm, IsFunction ], 0, function( G, d, e, opr ) if opr <> OnPoints or not (d in G and e in G) then
TryNextMethod(); elif Collected( CycleLengths( d, MovedPoints( G ) ) ) <>
Collected( CycleLengths( e, MovedPoints( G ) ) ) then
return fail; else
TryNextMethod(); fi; end );
InstallGlobalFunction(CreateIsomorphicPcGroup,function(pcgs,needindices,flag)
local r,i,p,A,f,a;
r:=RelativeOrders(pcgs); if Length(r)<=1then
p:=Product(r);
return GET_FROM_SORTED_CACHE(CYCLICACHE, p,
{} -> PermpcgsPcGroupPcgs( pcgs, IndicesEANormalSteps(pcgs), flag )); fi;
# is the group in the mappings families cache?
f:=FamiliesOfGeneralMappingsAndRanges(FamilyObj(OneOfPcgs(pcgs)));
i:=1;
atomic readonly GENERAL_MAPPING_REGION do# for HPC-GAP; does nothing in plain GAP while i<=Length(f) do
a:=ElmWPObj(f,i); if a<>fail and IsBound(a!.DefiningPcgs)
and RelativeOrders(a!.DefiningPcgs)=r then # right type PCGS -- test relations
a:=a!.DefiningPcgs; if (needindices=false or (not HasIndicesEANormalSteps(a)) or
IndicesEANormalSteps(a)=IndicesEANormalSteps(pcgs)) and
ForAll([1..Length(r)-1],x->
ExponentsOfPcElement(a,a[x]^r[x])
=ExponentsOfPcElement(pcgs,pcgs[x]^r[x])) and
ForAll([1..Length(r)],x->ForAll([x+1..Length(r)],y->
ExponentsOfPcElement(a,a[y]^a[x])
=ExponentsOfPcElement(pcgs,pcgs[y]^pcgs[x]))) then
# indeed the group is OK if not HasIndicesEANormalSteps(a) then
SetIndicesEANormalSteps(a,IndicesEANormalSteps(pcgs)); fi;
A:=GroupOfPcgs(a);
return A; fi; fi;
i:=i+2;
od;
od; # end of atomic
A := PermpcgsPcGroupPcgs( pcgs, IndicesEANormalSteps(pcgs), flag );
return A; end);
############################################################################# ## #M IsomorphismPcGroup( <G> ) . . . . . . . . . . . . perm group as pc group ##
InstallMethod( IsomorphismPcGroup, true, [ IsPermGroup ], 0, function( G )
local iso, A, pcgs;
# Make a pcgs based on an elementary abelian series (good for ag # routines).
pcgs:=PcgsElementaryAbelianSeries(G); if not IsPcgs( pcgs ) then
return fail; fi;
# Construct the pcp group <A> and the bijection between <A> and <G>.
A:=CreateIsomorphicPcGroup(pcgs,false,false);
iso := GroupHomomorphismByImagesNC( G, A, pcgs, GeneratorsOfGroup( A ) );
SetIsBijective( iso, true );
# Make a pcgs based on an elementary abelian series (good for ag # routines).
pcgs := TryPcgsPermGroup( [ G, N ], false, false, true );
if not IsModuloPcgs( pcgs ) then
return fail; fi;
# set nomerator and denominator appropriately
SetNumeratorOfModuloPcgs(pcgs,GeneratorsOfGroup(G));
SetDenominatorOfModuloPcgs(pcgs,GeneratorsOfGroup(N));
return pcgs; end);
############################################################################# ## #M PcgsElementaryAbelianSeries( <G> ) ##
InstallMethod( PcgsElementaryAbelianSeries, "perm group", true,
[ IsPermGroup ], 0, function(G)
local pcgs; if HasPcgs(G) and IsPcgsElementaryAbelianSeries(Pcgs(G)) then
return Pcgs(G); fi;
pcgs:=TryPcgsPermGroup( G, false, false, true ); if IsPcgs(pcgs) and not HasPcgs(G) then
SetPcgs(G,pcgs); fi;
return pcgs; end);
############################################################################# ## #M MaximalSubgroupClassReps( <G> ) ## ## method for solvable perm groups -- it is cheaper to translate to a pc ## group
InstallMethod( CalcMaximalSubgroupClassReps,"solvable perm group",true,
[ IsPermGroup and CanEasilyComputePcgs and IsFinite ], 0, function(G)
local hom,m;
hom:=IsomorphismPcGroup(G);
m:=MaximalSubgroupClassReps(Image(hom));
List(m,Size); # force
return List(m,i->PreImage(hom,i)); end);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.