|
#############################################################################
##
## This file is part of GAP, a system for computational discrete algebra.
## This file's authors include Frank Celler, Bettina Eick.
##
## 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 the methods for attributes of polycyclic groups.
##
#############################################################################
##
#M AsSSortedList( <pcgrp> )
##
InstallMethod( AsSSortedListNonstored,"pcgs computable groups",true,
[ IsGroup and CanEasilyComputePcgs and IsFinite ],0,
function( grp )
local elms, pcgs, g, u, e, i;
elms := [ One(grp) ];
pcgs := Pcgs(grp);
for g in pcgs do
u := One(grp);
e := ShallowCopy(elms);
for i in [ 1 .. RelativeOrderOfPcElement(pcgs,g)-1 ] do
u := u * g;
UniteSet( elms, e * u );
od;
od;
return elms;
end );
InstallMethod( AsSSortedList,"pcgs computable groups",true,
[ IsGroup and CanEasilyComputePcgs and IsFinite ],0,
AsSSortedListNonstored);
#############################################################################
##
#M AsList(<G>)
##
InstallMethod(AsList,"pc group",true,[IsPcGroup],0,AsSSortedListNonstored);
#############################################################################
##
#M CompositionSeries( <G> )
##
InstallMethod( CompositionSeries, "pcgs computable groups", true,
[ IsGroup and CanEasilyComputePcgs and IsFinite ], 0,
function( G )
local pcgsG, m, S, parent, i, igs, U;
# get a pcgs of <G>
pcgsG := Pcgs(G);
m := Length(pcgsG);
S := [];
# if <pcgsG> is induced use the parent
parent := ParentPcgs(pcgsG);
#if IsInducedPcgs(pcgsG) then
# parent := ParentPcgs(pcgsG);
#else
# parent := pcgsG;
#fi;
# compute the pcgs of the composition subgroups
for i in [ 1 .. m+1 ] do
igs := InducedPcgsByPcSequenceNC( parent, pcgsG{[i..m]} );
U := SubgroupByPcgs( G, igs );
Add( S, U );
od;
# and return
return S;
end );
#############################################################################
##
#M DerivedSubgroup( <G> )
##
InstallMethod( DerivedSubgroup,
"pcgs computable groups",
true,
[ IsGroup and CanEasilyComputePcgs and IsFinite ],
0,
function( U )
local pcgsU, parent, C, i, j, tmp;
# compute the commutators of the elements of a pcgs
pcgsU := Pcgs(U);
parent := ParentPcgs( pcgsU );
C := [];
for i in [ 1 .. Length(pcgsU) ] do
for j in [ i+1 .. Length(pcgsU) ] do
AddSet( C, Comm( pcgsU[j], pcgsU[i] ) );
od;
od;
# if <pcgsU> is induced use the parent
tmp := InducedPcgsByGeneratorsNC( parent, C );
C := SubgroupByPcgs( U, tmp );
return C;
end);
#############################################################################
##
#M ElementaryAbelianSeries( <G> )
##
InstallMethod( ElementaryAbelianSeries,
"pcgs computable groups using `PcgsElementaryAbelianSeries'", true,
[ IsGroup and CanEasilyComputePcgs and IsFinite ], 0,
G->EANormalSeriesByPcgs(PcgsElementaryAbelianSeries(G)));
#############################################################################
##
#M FrattiniSubgroup( <G> )
##
InstallMethod( FrattiniSubgroup,
"pcgs computable groups using prefrattini and core",
true,
[ IsGroup and CanEasilyComputePcgs and IsFinite ],
0,
function( G )
G := Core( G, PrefrattiniSubgroup( G ) );
Assert( 2, IsNilpotentGroup( G) );
SetIsNilpotentGroup( G, true );
return G;
end);
#############################################################################
##
#M HallSubgroupOp( <G>, <pi> )
##
## compute and use special pcgs of <G>.
##
InstallMethod( HallSubgroupOp,
"pcgs computable groups using special pcgs",
true,
[ IsGroup and CanEasilyComputePcgs and IsFinite, IsList ],
0,
function( G, pi )
local spec, weights, gens, i, S;
spec := SpecialPcgs( G );
weights := LGWeights( spec );
gens := [];
for i in [1..Length(spec)] do
if weights[i][3] in pi then Add( gens, spec[i] ); fi;
od;
gens := InducedPcgsByPcSequenceNC( spec, gens );
S := SubgroupByPcgs( G, gens );
return S;
end );
RedispatchOnCondition(HallSubgroupOp,true,[IsGroup,IsList],
[IsGroup and IsSolvableGroup and CanEasilyComputePcgs and IsFinite,
IsList ],0);
#############################################################################
##
#M PrefrattiniSubgroup( <G> )
##
InstallMethod( PrefrattiniSubgroup,
"pcgs computable groups using special pcgs",
true,
[ IsGroup and CanEasilyComputePcgs and IsFinite ],
0,
function( G )
local spec, first, weights, m, pref, i, start,
next, p, pcgsS, pcgsN, pcgsL, mats, modu, rad,
elms, P;
spec := SpecialPcgs( G );
first := LGFirst( spec );
weights := LGWeights( spec );
m := Length( spec );
pref := [];
for i in [1..Length(first)-1] do
start := first[i];
next := first[i+1];
p := weights[start][3];
if weights[start][1] > 1 and weights[start][2] = 1 and
next-start > 1 then
pcgsS := InducedPcgsByPcSequenceNC( spec, spec{[start..m]} );
pcgsN := InducedPcgsByPcSequenceNC( spec, spec{[next..m]} );
pcgsL := pcgsS mod pcgsN;
mats := LinearOperationLayer( spec, pcgsL );
modu := GModuleByMats( mats, GF(p) );
rad := MTX.BasisRadical( modu );
elms := List( rad, x -> PcElementByExponentsNC( pcgsL, x ) );
Append( pref, elms );
elif weights[start][2] > 1 then
Append(pref, spec{[start..next-1]} );
fi;
od;
pref := InducedPcgsByPcSequenceNC( spec, pref );
P := SubgroupByPcgs( G, pref );
return P;
end);
#############################################################################
##
#M IsFinite( <pcgrp> )
##
InstallMethod( IsFinite,
"pcgs computable groups",
true,
[ IsGroup and CanEasilyComputePcgs ],
0,
grp -> not 0 in RelativeOrders( Pcgs( grp ) ) );
#T is this method necessary at all?
#############################################################################
##
#M Size( <pcgrp> )
##
InstallMethod( Size, "pcgs computable groups", true,
[ IsGroup and CanEasilyComputePcgs ], 0,
function( grp )
local ords;
ords := RelativeOrders(Pcgs(grp));
if 0 in ords then
return infinity;
else
return Product(ords);
fi;
end );
#############################################################################
##
#M SylowComplementOp( <G>, <p> )
##
## compute and use special pcgs of <G>.
##
InstallMethod( SylowComplementOp,
"pcgs computable groups using special pcgs",
true,
[ IsGroup and CanEasilyComputePcgs and IsFinite,
IsPosInt ],
80,
function( G, p )
local spec, weights, gens, i, S, pi;
spec := SpecialPcgs( G );
weights := LGWeights( spec );
gens := [];
pi := [];
for i in [1..Length(spec)] do
if weights[i][3] <> p then
Add( gens, spec[i] );
AddSet( pi, weights[i][3] );
fi;
od;
gens := InducedPcgsByPcSequenceNC( spec, gens );
S := SubgroupByPcgs( G, gens );
SetHallSubgroup( G, pi, S );
if Length( pi ) = 1 then
SetSylowSubgroup( G, pi[1], S );
fi;
return S;
end );
RedispatchOnCondition(SylowComplementOp,true,[IsGroup,IsPosInt],
[IsGroup and IsSolvableGroup and CanEasilyComputePcgs and IsFinite,
IsPosInt ],0);
#############################################################################
##
#M SylowSubgroupOp( <G>, <p> )
##
## compute and use special pcgs of <G>.
##
InstallMethod( SylowSubgroupOp,
"pcgs computable groups using special pcgs",
true,
[ IsGroup and CanEasilyComputePcgs and IsFinite,
IsPosInt ],
100,
function( G, p )
local spec, weights, gens, i, S;
spec := SpecialPcgs( G );
weights := LGWeights( spec );
gens := [];
for i in [1..Length(spec)] do
if weights[i][3] = p then Add( gens, spec[i] ); fi;
od;
gens := InducedPcgsByPcSequenceNC( spec, gens );
S := SubgroupByPcgs( G, gens );
if Size(S) > 1 then
SetIsPGroup( S, true );
SetPrimePGroup( S, p );
SetHallSubgroup(G, [p], S);
fi;
return S;
end );
#############################################################################
##
#F MaximalSubgroupClassesRepsLayer( <pcgs>, <layer> )
##
BindGlobal( "MaximalSubgroupClassesRepsLayer", function( pcgs, l )
local first, weights, m, start, next, pcgsS, pcgsN, pcgsL, p, mats,
modu, maxi, i, elms, sub, M, G;
first := LGFirst( pcgs );
weights := LGWeights( pcgs );
m := Length( pcgs );
start := first[l];
next := first[l+1];
G := GroupOfPcgs( pcgs );
# catch the trivial case
if weights[start][2] <> 1 then
return [];
fi;
pcgsS := InducedPcgsByPcSequenceNC( pcgs, pcgs{[start..m]} );
pcgsN := InducedPcgsByPcSequenceNC( pcgs, pcgs{[next..m]} );
pcgsL := pcgsS mod pcgsN;
p := weights[start][3];
mats := LinearOperationLayer( pcgs, pcgsL );
modu := GModuleByMats( mats, GF(p) );
maxi := MTX.BasesMaximalSubmodules( modu );
for i in [1..Length( maxi )] do
maxi[i] := ShallowCopy( maxi[i] );
TriangulizeMat( maxi[i] );
elms := List( maxi[i], x -> PcElementByExponentsNC( pcgsL, x ) );
sub := Concatenation( pcgs{[1..start-1]}, elms, pcgsN );
sub := InducedPcgsByPcSequenceNC( pcgs, sub );
M := SubgroupByPcgs( G, sub );
maxi[i] := M;
od;
return maxi;
end );
BindGlobal( "MAXSUBS_BY_PCGS", function( G )
local spec, first, max, i, new;
spec := SpecialPcgs(G);
first := LGFirst( spec );
max := [];
for i in [1..Length(first)-1] do
new := MaximalSubgroupClassesRepsLayer( spec, i );
Append( max, new );
od;
return max;
end );
#############################################################################
##
#M MaximalSubgroupClassReps( <G> )
##
InstallMethod( CalcMaximalSubgroupClassReps,
"pcgs computable groups using special pcgs",
true,
[ IsGroup and CanEasilyComputePcgs and IsFinite ],
0,
MAXSUBS_BY_PCGS);
#fallback
InstallMethod( CalcMaximalSubgroupClassReps,
"pcgs computable groups using special pcgs",
true,
[ IsGroup and IsSolvableGroup and IsFinite ],
0,
MAXSUBS_BY_PCGS);
#############################################################################
##
#M MaximalSubgroups( <G> )
##
InstallMethod( MaximalSubgroups,
"pcgs computable groups using special pcgs",
true,
[ IsGroup and HasFamilyPcgs and IsFinite ],
0,
function( G )
local spec, first, m, max, i, U, new, M;
spec := SpecialPcgs(G);
first := LGFirst( spec );
m := Length( spec );
max := [];
for i in [1..Length(first)-1] do
U := Subgroup( G, spec{[first[i]..m]} );
new := MaximalSubgroupClassesRepsLayer( spec, i );
for M in new do
if IsNormal( G, M ) then
Add( max, M );
else
Append( max, ConjugateSubgroups( U, M ) );
fi;
od;
od;
return max;
end );
#############################################################################
##
#M ConjugacyClassesMaximalSubgroups( <G> )
##
#T InstallMethod( ConjugacyClassesMaximalSubgroups,
#T "generic method for groups with pcgs",
#T true,
#T [ IsGroup and CanEasilyComputePcgs ],
#T 0,
#T
#T function( G )
#T return List( MaximalSubgroupClassReps(G),
#T x -> ConjugacyClassSubgroup( G, x ) );
#T end);
#############################################################################
##
#M NormalMaximalSubgroups( <G> )
##
InstallMethod( NormalMaximalSubgroups,
"pcgs computable groups using special pcgs",
true,
[ IsGroup and CanEasilyComputePcgs and IsFinite ],
0,
function( G )
local spec, first, weights, max, i, new;
spec := SpecialPcgs( G );
first := LGFirst( spec );
weights := LGWeights( spec );
max := [];
for i in [1..Length(first)-1] do
if weights[first[i]][1] = 1 then
new := MaximalSubgroupClassesRepsLayer( spec, i );
Append( max, new );
fi;
od;
return max;
end );
#############################################################################
##
#M MaximalNormalSubgroups( <G> )
##
InstallMethod( MaximalNormalSubgroups, "for abelian groups",
[ IsGroup and IsAbelian ],
# IsGroup and IsFinite ranks higher than IsGroup and IsAbelian,
# so we have to increase the rank, otherwise the method for
# normal subgroup computation is selected.
{} -> RankFilter( IsGroup and IsFinite and IsAbelian )
- RankFilter( IsGroup and IsAbelian ),
function( G )
local Gf, # FactorGroup of G
hom, # homomorphism from G to Gf
MaxGf, # MaximalNormalSubgroups of Gf
AbInv; # abelian invariants of G
if not IsPcGroup(G) then
AbInv := AbelianInvariants(G);
if 0 in AbInv then
# (p) is a maximal normal subgroup in Z for every prime p
Error("number of maximal normal subgroups is infinity");
else
# convert it to an abelian PcGroup with same invariants
hom := IsomorphismPcGroup(G);
Gf := Image(hom);
# for abelian groups all maximal normal subgroup are also
# normal maximal subgroups and vice-versa
MaxGf := NormalMaximalSubgroups(Gf);
return List(MaxGf, N -> PreImage(hom, N));
fi;
else
# for abelian groups all maximal normal subgroup are also
# normal maximal subgroups and vice-versa
# for abelian pc groups return all maximal subgroups
# NormalMaximalSubgroups seems to omit some unnecessary checks,
# hence faster than MaximalSubgroups
return NormalMaximalSubgroups(G);
fi;
end);
InstallMethod( MaximalNormalSubgroups, "for solvable groups",
[ IsGroup and IsSolvableGroup ],
# IsGroup and IsFinite ranks higher than
# IsGroup and IsSolvableGroup, so we have to increase the
# rank, otherwise the method for normal subgroup computation
# is selected.
{} -> RankFilter( IsGroup and IsFinite and IsSolvableGroup )
- RankFilter( IsGroup and IsSolvableGroup ),
function( G )
local Gf, # FactorGroup of G
hom, # homomorphism from G to Gf
MaxGf; # MaximalNormalSubgroups of Gf
# every maximal normal subgroup is above the derived subgroup
hom := MaximalAbelianQuotient(G);
Gf := Image(hom);
# One would hope this is true
SetIsAbelian(Gf, true);
MaxGf := MaximalNormalSubgroups(Gf);
return List(MaxGf, N -> PreImage(hom, N));
end);
RedispatchOnCondition( MaximalNormalSubgroups, true,
[ IsGroup ],
[ IsSolvableGroup ], 0);
#############################################################################
##
#F ModifyMinGens( <pcgsG>, <pcgsS>, <pcgsL>, <min> )
##
BindGlobal( "ModifyMinGens", function( pcgs, pcgsS, pcgsL, min )
local pcgsF, g, i, new, pcgsT;
# set up
pcgsF := pcgsS mod pcgsL;
# try to modify mingens
for g in pcgsF do
for i in [1..Length( min )] do
new := ShallowCopy( min );
new[i] := min[i] * g;
pcgsT := InducedPcgsByPcSequenceAndGenerators(pcgs, pcgsL, new);
pcgsT := Pcgs( ZassenhausIntersection( pcgs, pcgsS, pcgsT ) );
if Length( pcgsT ) > Length( pcgsL ) then
min[i] := new[i];
return;
fi;
od;
od;
# mingens cannot be modified - add new generator
Add( min, pcgsF[1] );
end );
#############################################################################
##
#F MinimalGensLayer( <pcgsG>, <pcgsS>, <pcgsN>, <min> )
##
BindGlobal( "MinimalGensLayer", function( pcgs, pcgsS, pcgsN, min )
local series, pcgsL, pcgsU, pcgsV, pcgsM;
series := [pcgsN];
# set up
pcgsL := pcgsN;
pcgsU := InducedPcgsByPcSequenceAndGenerators( pcgs, pcgsN, min );
pcgsV := pcgsU;
# loop
while Length( pcgsU ) < Length( pcgs ) do
# get intersection of V with layer
pcgsM := Pcgs( ZassenhausIntersection( pcgs, pcgsS, pcgsV ) );
if Length( pcgsM ) <> Length( pcgsL ) then
Add( series, pcgsM );
fi;
pcgsL := Last(series);
# modify minimal gens
ModifyMinGens( pcgs, pcgsS, pcgsL, min );
pcgsV := InducedPcgsByPcSequenceAndGenerators( pcgs, pcgsL, min );
pcgsU := InducedPcgsByPcSequenceAndGenerators( pcgs, pcgsN, min );
if Length( pcgs ) = Length( pcgsV ) then
pcgsS := pcgsL;
Remove(series);
fi;
od;
return min;
end );
#############################################################################
##
#M MinimalGeneratingSet( <G> )
##
InstallMethod( MinimalGeneratingSet,
"pcgs computable groups using special pcgs",
true, [ IsSolvableGroup and IsFinite and CanEasilyComputePcgs], 0,
function( G )
local spec, weights, first, m, mingens, i, start, next, j,
pcgsN, pcgsS;
if IsTrivial(G) then
return [];
fi;
spec := SpecialPcgs( G );
weights := LGWeights( spec );
first := LGFirst( spec );
m := Length( spec );
# the first head
mingens := spec{[1..first[2]-1]};
i := 2;
while i <= Length( first ) -1 and
weights[first[i]][1] = 1 and weights[first[i]][2] = 1 do
start := first[i];
next := first[i+1];
for j in [1..next-start] do
if j <= Length(mingens) then
mingens[j] := mingens[j] * spec[ start+j-1 ];
else
Add(mingens, spec[ start+j-1 ] );
fi;
od;
i := i + 1;
od;
# the other heads
while i <= Length( first ) -1 do
if weights[first[i]][2] = 1 then
start := first[i];
next := first[i+1];
pcgsS := InducedPcgsByPcSequenceNC( spec, spec{[start..m]} );
pcgsN := InducedPcgsByPcSequenceNC( spec, spec{[next..m]} );
mingens := MinimalGensLayer( spec, pcgsS, pcgsN, mingens );
fi;
i := i + 1;
od;
return Set(mingens);
end );
#############################################################################
##
#M SmallGeneratingSet(<G>)
##
InstallMethod(SmallGeneratingSet,"using minimal generating set",true,
[IsSolvableGroup and IsFinite and CanEasilyComputePcgs],0,
MinimalGeneratingSet);
#############################################################################
##
#M GeneratorsSmallest(<pcgrp>)
##
InstallMethod(GeneratorsSmallest,"group of pc words which is full family",
true, [IsGroup and HasFamilyPcgs],0,
function(G)
local pcgs,gens,U,e,i,j,pa,ros,smallpcgs,exp;
# the smallest generating system is obtained from the
# family pcgs by throwing out redundant generators.
pcgs:=InducedPcgsWrtFamilyPcgs(G);
# normalize leading exponent to one
pa := ParentPcgs(pcgs);
ros := RelativeOrders(pcgs);
smallpcgs := [];
for i in [ 1 .. Length(pcgs) ] do
exp := LeadingExponentOfPcElement( pa, pcgs[i] );
smallpcgs[i] := pcgs[i] ^ (1/exp mod ros[i]);
od;
# make entry 1 above the diagonal
for i in [ 1 .. Length(smallpcgs)-1 ] do
for j in [ i+1 .. Length(smallpcgs) ] do
exp := ExponentOfPcElement( pa, smallpcgs[i], DepthOfPcElement(
pa, smallpcgs[j] ) );
if exp <> 1 then
smallpcgs[i]:=smallpcgs[i]*smallpcgs[j]^(ros[j]-exp+1);
fi;
od;
od;
gens:=[];
U:=TrivialSubgroup(G);
for i in [1..Length(smallpcgs)] do
e:=Product(smallpcgs{[1..i]});
if not e in U then
Add(gens,e);
U:=ClosureGroup(U,e);
fi;
od;
return gens;
end);
#############################################################################
##
#F NextStepCentralizer( <gens>, <cent>, <pcgsF>, <field> )
##
BindGlobal( "NextStepCentralizer", function( gens, cent, pcgsF, field )
local g, matlist, null;
for g in gens do
if Length( cent ) = 0 then return []; fi;
matlist := List( cent, x -> ExponentsOfPcElement(pcgsF, Comm(x,g)));
null := TriangulizedNullspaceMat(matlist*One(field));
cent := List( null, x -> PcElementByExponentsNC(pcgsF, cent, x));
od;
return cent;
end );
#############################################################################
##
#F GeneratorsCentrePGroup( <U> )
##
InstallGlobalFunction( GeneratorsCentrePGroup, function( U )
local pcgs, spec, n, firs, p, field, ser, gens, cent, i, pcgsF;
# catch the trivial case
pcgs := Pcgs(U);
if Length( pcgs ) = 0 then return []; fi;
# set up series
spec := SpecialPcgs( U );
n := Length( spec );
firs := LGFirst( spec );
p := PrimePGroup( U );
field := GF(p);
ser := List( firs, x ->
InducedPcgsByPcSequenceNC( spec, spec{[x..n]} ) );
gens := spec{[1..firs[2]-1]};
cent := gens;
for i in [2..Length(ser)-1] do
pcgsF := ser[i] mod ser[i+1];
cent := NextStepCentralizer( gens, cent, pcgsF, field );
Append( cent, AsList( pcgsF ) );
od;
return cent;
end );
#############################################################################
##
#F CentrePcGroup( <G> )
##
InstallGlobalFunction (CentrePcGroup, function( G )
local spec, first, weights, m, primes, cent, i, gens,
start, next, p, j, field, pcgsS, pcgsN, pcgsF, q,
U, newgens, matlist, g, conj, expo, order, eigen,
null, n, elm, r, ksi, large, pcgsH, H, oper;
# get special pcgs
spec := SpecialPcgs( G );
first := LGFirst( spec );
weights := LGWeights( spec );
m := Length( spec );
# get primes and set up
primes := Set( weights, x -> x[3] );
cent := List( primes, x -> [] );
# the first nilpotent factor
i := 1;
gens := [];
while i <= Length( first ) - 1 and weights[first[i]][1] = 1 do
start := first[i];
next := first[i+1];
p := weights[start][3];
j := Position( primes, p );
if weights[start][2] = 1 then
gens[j] := spec{[start..next-1]};
cent[j] := spec{[start..next-1]};
elif weights[start][3] = p then
field := GF(p);
pcgsS := InducedPcgsByPcSequenceNC( spec, spec{[start..m]} );
pcgsN := InducedPcgsByPcSequenceNC( spec, spec{[next..m]} );
pcgsF := pcgsS mod pcgsN;
cent[j] := NextStepCentralizer( gens[j], cent[j], pcgsF, field );
Append( cent[j], AsList( pcgsF ) );
fi;
i := i + 1;
od;
# the remaining layers
while i <= Length( first ) - 1 do
start := first[i];
next := first[i+1];
q := weights[start][3];
field := GF(q);
pcgsS := InducedPcgsByPcSequenceNC( spec, spec{[start..m]} );
pcgsN := InducedPcgsByPcSequenceNC( spec, spec{[next..m]} );
pcgsF := pcgsS mod pcgsN;
for j in [1..Length(primes)] do
p := primes[j];
if p = q and (weights[start][2] > 1 or Length( cent[j] ) > 0) then
pcgsH := spec mod pcgsN;
H := GroupByPcgs( pcgsH );
gens := List(cent[j], x->MappedPcElement(x, pcgsH, Pcgs(H)));
Append( gens, Pcgs(H){[start..next-1]} );
# calculate centre of centF
U := Subgroup( H, gens );
gens := GeneratorsCentrePGroup( U );
gens := List( gens, x -> MappedPcElement(x,Pcgs(H),pcgsH));
# get centralizer
oper := spec{Filtered([1..start-1], x -> weights[x][2] = 1)};
cent[j] := NextStepCentralizer( oper, gens, pcgsF, field );
# case p <> q
elif Length( cent[j] ) > 0 then
# get operation of centF on M
newgens := [];
matlist := [];
for g in cent[j] do
conj := List( pcgsF,
x -> ExponentsOfPcElement( pcgsF, x^g ) )
* One( field );
if IsOne( conj ) then
AddSet( newgens, g );
else
Add( matlist, conj );
fi;
od;
cent[j] := Filtered( cent[j], g -> not g in newgens );
if Length( matlist ) > 0 then
# get exponent of <cent[j]> mod N
expo := 1;
for g in cent[j] do
order := 1;
while SiftedPcElement( pcgsN, g ) <> Identity(G) do
g := g ^ p;
order := order * p;
od;
expo := Maximum( expo, order );
od;
# get splitting field
r := 1;
while EuclideanRemainder( q^r - 1, expo ) <> 0 do
r := r+1;
od;
if q^r >= 2^16 then
TryNextMethod();
fi;
large := GF(q^r);
ksi := GeneratorsOfField(large)[1]^((q^r - 1) / expo);
# calculate simultaneous eigenvalues
eigen := SimultaneousEigenvalues( matlist, expo, ksi );
# solve system
null := BasisNullspaceModN( eigen, expo );
# calculate elements corresponding to null
for n in null do
elm := PcElementByExponentsNC( pcgsF, cent[j], n );
if elm <> Identity( G ) then
AddSet( newgens, elm );
fi;
od;
fi;
cent[j] := newgens;
fi;
od;
i := i + 1;
od;
# return centre as direct product of p-parts
G:= SubgroupNC( G, Concatenation( cent ) );
Assert( 1, IsAbelian( G ) );
SetIsAbelian( G, true );
return G;
end);
#############################################################################
##
#M Centre( <G> )
##
InstallMethod( Centre,
"pcgs computable groups using special pcgs",
[ IsGroup and CanEasilyComputePcgs and IsFinite ],
CentrePcGroup);
#############################################################################
##
#M OmegaSeries( G )
##
InstallMethod( OmegaSeries,
"for p-groups",
true,
[IsGroup and CanEasilyComputePcgs and IsFinite],
0,
function( G )
local pcgs, cl, U, series, exp, sub, p, M;
pcgs := Pcgs( G );
if Length( pcgs ) = 0 then return [G]; fi;
if Length( pcgs ) = 1 then return [G,TrivialSubgroup(G)]; fi;
U := TrivialSubgroup( G );
series := [U];
p := PrimePGroup( G );
cl := ConjugacyClasses( G );
exp := 1;
while Size( U ) < Size( G ) do
sub := Filtered( cl, x -> Order( Representative( x ) ) = p ^ exp );
sub := Concatenation( List( sub, AsList ) );
sub := InducedPcgsByPcSequenceAndGenerators( pcgs, Pcgs(U), sub );
M := SubgroupByPcgs( G, sub );
if Size( M ) > Size( U ) then
Add( series, M );
fi;
U := M;
exp := exp + 1;
od;
return Reversed( series );
end);
#############################################################################
##
#M PCentralSeriesOp( <G>, <p> ) . . . . . . . . . . . . <p>-central series
##
InstallMethod( PCentralSeriesOp,
"method for pc groups and prime",
true,
[ IsPcGroup and IsFinite, IsPosInt ],
0,
function( G, p )
local spec, weig, firs, ser, int, i, t, s, w, sub, N;
spec := SpecialPcgs(G);
weig := LGWeights( spec );
firs := LGFirst( spec );
ser := [G];
int := [];
for i in [1..Length(firs)-1] do
t := firs[i];
s := firs[i+1];
w := weig[t];
if w[1] = 1 and w[3] = p then
sub := Concatenation( int, spec{[s..Length(spec)]} );
sub := InducedPcgsByPcSequenceNC( spec, sub );
N := SubgroupByPcgs( G, sub );
Add( ser, N );
else
Append( int, spec{[t..s-1]} );
fi;
od;
return ser;
end );
[ 0.62Quellennavigators
Projekt
]
|