############################################################################# ## ## This file is part of GAP, a system for computational discrete algebra. ## This file's authors include Frank Celler. ## ## 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 polycyclic generating systems. ##
############################################################################# ## #M Pcgs( <A> ) . . . . . . . . from independent generators of abelian group ##
InstallGlobalFunction( PcgsByIndependentGeneratorsOfAbelianGroup, function( A )
local pcgs, pcs, rel, gen, f;
pcs := [ ];
rel := [ ]; for gen in IndependentGeneratorsOfAbelianGroup( A ) do for f in Factors(Integers, Order( gen ) ) do
Add( pcs, gen );
Add( rel, f );
gen := gen ^ f;
od;
od;
pcgs := PcgsByPcSequenceNC( FamilyObj( One( A ) ), pcs );
SetOneOfPcgs( pcgs, One( A ) );
SetRelativeOrders( pcgs, rel );
SetIsPrimeOrdersPcgs( pcgs, true );
return pcgs; end );
InstallMethod( Pcgs, "from independent generators of abelian group", true,
[ IsGroup and IsAbelian and HasIndependentGeneratorsOfAbelianGroup ], 0, function(A) if HasHomePcgs(A) then
TryNextMethod(); else
return PcgsByIndependentGeneratorsOfAbelianGroup(A); fi; end);
InstallMethod( Pcgs, "from independent generators of abelian group", true,
[ IsGroup and IsAbelian and CanEasilyComputeWithIndependentGensAbelianGroup ], 0, function(A) if HasHomePcgs(A) then
TryNextMethod(); else
return PcgsByIndependentGeneratorsOfAbelianGroup(A); fi; end);
############################################################################# ## #M SetPcgs( <G>, fail ) . . . . . . . . . . . . . . . . . never set `fail' ## ## `HasPcgs' implies `CanEasilyComputePcgs', which implies `IsSolvable', ## so a pcgs cannot be set for insoluble permutation groups. ## As Pcgs may return 'fail' for non-solvable permutation groups, this method ## is necessary. ##
InstallMethod( SetPcgs, true, [ IsGroup, IsBool ], 0, function( G, failval )
SetIsSolvableGroup( G, false ); end );
imp:=filter and imp; # if the <efam> has a family pcgs check if the are equal if HasDefiningPcgs(efam) and DefiningPcgs(efam) = pcs then
imp := imp and IsFamilyPcgs; fi;
imp:=imp and HasLength;
# get the pcgs family
fam := CollectionsFamily(efam);
# set a one if HasOne(efam) then
one:=One(efam); elif0 < Length(pcs) then
one:=One(pcs[1]); else
one:=fail; fi; if one<>fail then
attl:=Concatenation([pcgs, NewType( fam, imp and HasOneOfPcgs),
Length,Length(pcs),OneOfPcgs,one],attl); else
attl:=Concatenation([pcgs, NewType( fam, imp ),
Length,Length(pcs)],attl); fi;
# convert record into component object
CallFuncList( ObjectifyWithAttributes,attl );
# a place to cache powers
pcgs!.pcSeqPowers:=List(pcs,i->[]);
pcgs!.pcSeqPowersInv:=List(pcs,i->[]);
############################################################################# ## #M IsomorphismRefinedPcGroup( <G> ) ##
InstallMethod( IsomorphismRefinedPcGroup, "group with refined pcgs", true, [IsPcGroup], 0, function( G )
local word, expo, pcgs, rels, new, ord, i, facs, g, f, n, F, gens,
rela, w, t, H, map, j;
word := function( exp, gens, id )
local h, i;
h := id; for i in [1..Length(exp)] do
h := h * gens[i]^exp[i];
od;
return h; end;
expo := function( pcgs, g, map )
local exp, new, i, c;
exp := ExponentsOfPcElement( pcgs, g );
new := []; for i in [1..Length(exp)] do
c := CoefficientsMultiadic( Reversed(map[i]), exp[i] );
Append( new, Reversed( c ) );
od;
return new; end;
# get the pcgs of G
pcgs := Pcgs(G);
rels := RelativeOrders( pcgs ); if ForAll( rels, IsPrime ) then return IdentityMapping(G); fi;
# get the refined pcgs
new := [];
ord := [];
map := []; for i in [1..Length(pcgs)] do
facs := Factors(Integers, rels[i] );
g := pcgs[i]; for f in facs do
Add( new, g );
Add( ord, f );
g := g^f;
od;
Add( map, facs );
od;
# compute a group with respect to <new>
n := Length( new );
F := FreeGroup(IsSyllableWordsFamily, n );
gens := GeneratorsOfGroup( F );
rela := [];
for i in [1..n] do
# the power
w := gens[i]^ord[i];
t := expo( pcgs, new[i]^ord[i], map );
t := word( t, gens, One(F) );
Add( rela, w/t );
for j in [i+1..n] do
# the commutator
w := Comm( gens[i], gens[j] );
t := expo( pcgs, Comm( new[i], new[j] ), map );
t := word( t, gens, One(F) );
Add( rela, w/t );
od;
od;
H := F/rela;
H:=PcGroupFpGroup( H );
return GroupHomomorphismByImagesNC(G,H,new,FamilyPcgs(H)); end );
exp := ShallowCopy(ExponentsOfPcElement( pcgs, elm )); if pos < 1then pos := 1; fi; for i in [ pos .. Length(exp) ] do
exp[i] := 0;
od;
return PcElementByExponentsNC( pcgs, exp ); end );
exp := ExponentsOfPcElement( pcgs, elm );
dep := PositionNonZero( exp ); if Length(exp) < dep then
return fail; else
return exp[dep]; fi; end );
############################################################################# ## #M PcElementByExponents( <pcgs>, <empty-list> ) ##
InstallGlobalFunction(PcElementByExponents,function(arg)
local i,ro; if Length(arg)=2then if Length(arg[1])<>Length(arg[2]) then
Error( "<list> and <pcgs> have different lengths" ); fi;
ro:=RelativeOrders(arg[1]); for i in [1..Length(ro)] do if ro[i]<>0 and IsRat(arg[2][i])
and (arg[2][i]<0 or arg[2][i]>=ro[i]) then
Error("Exponent out of range!"); fi;
od;
return PcElementByExponentsNC(arg[1],arg[2]); else if Length(arg[3])<>Length(arg[2]) then
Error( "<list> and <basis> have different lengths" ); fi;
return PcElementByExponentsNC(arg[1],arg[2],arg[3]); fi; end);
InstallMethod( PcElementByExponentsNC, "generic method for empty lists",
true,
[ IsPcgs,
IsList and IsEmpty ], 0,
function( pcgs, list )
return OneOfPcgs(pcgs); end );
############################################################################# ## #F PowerPcgsElement( <pcgs>, <i>,<exp> ) ##
InstallGlobalFunction(PowerPcgsElement,function( pcgs, i,exp )
local l,e; if exp=0then
return OneOfPcgs(pcgs); elif exp>0then
l:=pcgs!.pcSeqPowers[i];
e:=exp; else
l:=pcgs!.pcSeqPowersInv[i];
e:=-exp; fi; if not IsBound(l[e]) then
l[e]:=pcgs[i]^exp; fi;
return l[e]; end );
############################################################################# ## #F LeftQuotientPowerPcgsElement( <pcgs>, <i>,<exp> ) ##
InstallGlobalFunction(LeftQuotientPowerPcgsElement,function( pcgs, i,exp,elm )
return LeftQuotient(PowerPcgsElement(pcgs,i,exp),elm); # the following code seemed more clever, but somehow `LeftQuotient' # performs better. 5-5-99, AH #local e; # e:=pcgs[i]; # if NumberSyllables(UnderlyingElement(e))=1 then # # single pc element (or its power): LeftQuotient is clever # return LeftQuotient(e^exp,elm); # else # # more complicated element: rather go via the inverse power # return PowerPcgsElement(pcgs,i,-exp)*elm; # fi; end );
BindGlobal( "DoPcElementByExponentsGeneric", function(pcgs,basis,list)
local elm,i,a;
elm := fail;
for i in [ 1 .. Length(list) ] do
a:=list[i]; if IsFFE(a) then a:=Int(a);fi; if a=1then if elm=fail then elm := basis[i]; else elm := elm * basis[i];fi; elif a<> 0then if elm=fail then elm := basis[i] ^ a; else elm := elm * basis[i] ^ a;fi; fi;
od;
if elm=fail then if IsPcgs(pcgs) then
return OneOfPcgs(pcgs); else
return One(pcgs[1]); fi; else
return elm; fi;
function( pcgs, left, right )
local d, ll, lr, ord;
d := DepthOfPcElement( pcgs, left ); if d <> DepthOfPcElement( pcgs, right ) then
Error( "pc elms <left> and <right> have different depth" ); fi;
ll := LeadingExponentOfPcElement( pcgs, left );
lr := LeadingExponentOfPcElement( pcgs, right );
ord := RelativeOrderOfPcElement( pcgs, left );
return LeftQuotient( right^(ll/lr mod ord), left ); end );
# the following is the system setter for `RelativeOrders'.
SET_RELATIVE_ORDERS := SETTER_FUNCTION( "RelativeOrders", HasRelativeOrders );
InstallMethod( SetRelativeOrders, "setting orders for prime orders pcgs",
true,
[ IsPcgs and IsComponentObjectRep and IsAttributeStoringRep and
HasIsPrimeOrdersPcgs and HasIsFiniteOrdersPcgs,
IsList ], 1, #better than the following method # only call the system setter function
SET_RELATIVE_ORDERS );
############################################################################# ## #M SetRelativeOrders( <pcgs>, <orders> ) ##
InstallMethod( SetRelativeOrders, "setting orders and checking for prime orders",
true,
[ IsPcgs and IsComponentObjectRep and IsAttributeStoringRep,
IsList ], 0,
function( pcgs, orders ) if not HasIsFiniteOrdersPcgs(pcgs) then
SetIsFiniteOrdersPcgs( pcgs,
ForAll( orders, x -> x <> 0 and x <> infinity ) ); fi; if IsFiniteOrdersPcgs(pcgs) and not HasIsPrimeOrdersPcgs(pcgs) then
SetIsPrimeOrdersPcgs( pcgs, ForAll( orders, IsPrimeInt ) ); fi; # and call the system setter function
SET_RELATIVE_ORDERS( pcgs, orders ); end );
############################################################################# ## #M ExtendedIntersectionSumPcgs( <parent-pcgs>, <n>, <u>, <modpcgs> ) ##
InstallMethod( ExtendedIntersectionSumPcgs, "generic method for modulo pcgs",
true, #function(a,b,c) return IsIdenticalObj(a,b) and IsIdenticalObj(a,c); end,
[ IsPcgs and IsPrimeOrdersPcgs, IsList, IsList, IsObject ], 0, function( pcgs, n, u, pcgsM )
local id, ls, rs, is, g, z, I, ros, al, ar, tmp,
sum, int;
# set up
id := OneOfPcgs( pcgs );
# What follows is a Zassenhausalgorithm: <ls> and <rs> are the left and # rights sides. They are initialized with [ n, n ] and [ u, 1 ]. <is> is # the intersection. <I> contains the words [ u, 1 ] which must be # Sifted through [ <ls>, <rs> ].
ls := List( pcgs, x -> id );
rs := List( pcgs, x -> id );
is := List( pcgs, x -> id );
for g in u do
z := DepthOfPcElement( pcgs, g );
ls[z] := g;
rs[z] := g;
od;
I := []; for g in n do
z := DepthOfPcElement( pcgs, g ); if ls[z] = id then
ls[z] := g; else
Add( I, g ); fi;
od;
# enter the pairs [ u, 1 ] of <I> into [ <ls>, <rs> ]
ros := RelativeOrders(pcgs); for al in I do
ar := id; if IsInt(pcgsM) then if DepthOfPcElement(pcgs,al)>=pcgsM then
al:=id; fi; elif not IsBool( pcgsM ) then
al := SiftedPcElement( pcgsM, al ); fi;
z := DepthOfPcElement( pcgs, al );
# shift through and reduced from the left while al <> id and ls[z] <> id do
tmp := LeadingExponentOfPcElement( pcgs, al )
/ LeadingExponentOfPcElement( pcgs, ls[z] )
mod ros[z];
al := LeftQuotient( ls[z]^tmp, al ); if IsInt(pcgsM) then if DepthOfPcElement(pcgs,al)>=pcgsM then
al:=id; fi; elif not IsBool( pcgsM ) then
al := SiftedPcElement( pcgsM, al ); fi;
ar := LeftQuotient( rs[z]^tmp, ar );
z := DepthOfPcElement( pcgs, al );
od;
# have we a new sum or intersection generator if al <> id then
ls[z] := al;
rs[z] := ar; else
z := DepthOfPcElement( pcgs, ar ); while ar <> id and is[z] <> id do
ar := ReducedPcElement( pcgs, ar, is[z] ); if IsInt(pcgsM) then if DepthOfPcElement(pcgs,ar)>=pcgsM then
ar:=id; fi; elif not IsBool( pcgsM ) then
ar := SiftedPcElement( pcgsM, ar ); fi;
z := DepthOfPcElement( pcgs, ar );
od; if ar <> id then
is[z] := ar; fi; fi;
od;
# Construct the sum and intersection aggroups. Return left and right # sides, so one can decompose words of <N> * <U>.
#sum := InducedPcgsByPcSequence( pcgs, Filtered( ls, x -> x <> id ) ); #int := InducedPcgsByPcSequence( pcgs, # Filtered( is, x -> x <> id ) );
sum := Filtered( ls, x -> x <> id );
int := Filtered( is, x -> x <> id );
return rec(
leftSide := ls,
rightSide := rs,
sum := sum,
intersection := int ); end );
############################################################################# ## #M IntersectionSumPcgs( <parent-pcgs>, <n>, <u> ) ##
InstallMethod( IntersectionSumPcgs, "using 'ExtendedIntersectionSumPcgs'", function(a,b,c) return IsIdenticalObj(a,b) and IsIdenticalObj(a,c); end,
[ IsPcgs and IsPrimeOrdersPcgs, IsList, IsList ], 0, function( pcgs, n, u )
local e;
e:=ExtendedIntersectionSumPcgs(pcgs, n, u, true);
e.sum:=InducedPcgsByPcSequenceNC(pcgs,e.sum);
e.intersection:=InducedPcgsByPcSequenceNC(pcgs,e.intersection);
return e; end );
function( pcgs, n, u )
local id, ls, g, z, I, ros, al, tmp;
if false and IsPcgs(u) and IsPcgs(n) and ParentPcgs(n)=pcgs
and ParentPcgs(u)=pcgs then if ForAll(n,i->i in u) then
return u; elif ForAll(u,i->i in n) then
return n; fi; fi;
# set up
id := OneOfPcgs( pcgs );
# what follows is a Zassenhausalgorithm
ls := List( pcgs, x -> id );
for g in u do
z := DepthOfPcElement( pcgs, g );
ls[z] := g;
od;
I := []; for g in n do
z := DepthOfPcElement( pcgs, g ); if ls[z] = id then
ls[z] := g; else
Add( I, g ); fi;
od;
# enter the elements of <I> into <ls>
ros := RelativeOrders(pcgs); for al in I do
z := DepthOfPcElement( pcgs, al );
# shift through and reduced from the left while al <> id and ls[z] <> id do
tmp := LeadingExponentOfPcElement( pcgs, al )
/ LeadingExponentOfPcElement( pcgs, ls[z] )
mod ros[z];
al := LeftQuotient( ls[z]^tmp, al );
z := DepthOfPcElement( pcgs, al );
od;
# have we a new sum or intersection generator if al <> id then
ls[z] := al; fi;
od;
return InducedPcgsByPcSequence( pcgs, Filtered( ls, x -> x <> id ) );
end );
############################################################################# ## #M SumFactorizationFunctionPcgs( <parent-pcgs>, <u>, <n>, <modpcgs> ) ##
InstallMethod( SumFactorizationFunctionPcgs, "generic method", #function(a,b,c) return IsIdenticalObj(a,b) and IsIdenticalObj(a,c); end,
true,
[ IsPcgs and IsPrimeOrdersPcgs, IsList, IsList, IsObject ], 0, function( pcgs, u, n, pcgsM )
local id, S, f;
# do we want to prune the tails? if IsInt(pcgsM) and pcgsM<0then
pcgsM:=-pcgsM; # this will not affect the result -- as we have a tail we only want # the result modulo a normal subgroup
u:=List(u,i->CleanedTailPcElement(pcgs,i,pcgsM));
n:=List(n,i->CleanedTailPcElement(pcgs,i,pcgsM)); fi;
id := OneOfPcgs( pcgs );
S := ExtendedIntersectionSumPcgs( pcgs, n, u, pcgsM );
# decomposition function
f := function( un )
local a, u, w, z;
# Catch trivial case. if un = id then
return rec( u := id, n := id ); fi;
# Shift through 'leftSide' and do the inverse operations with # 'rightSide'. This will give the <N> part.
u := id;
a := un;
w := DepthOfPcElement( pcgs, a ); while a <> id and S.leftSide[ w ] <> id do
z := LeadingExponentOfPcElement( pcgs, a )
/ LeadingExponentOfPcElement( pcgs, S.leftSide[ w ] )
mod RelativeOrderOfPcElement( pcgs, a );
a := LeftQuotient( S.leftSide[ w ] ^ z, a );
u := u * S.rightSide[ w ] ^ z;
w := DepthOfPcElement( pcgs, a );
od;
return rec( u := u, n := u^-1 * un ); end;
# Return the sum, intersection and the function.
return rec( sum := S.sum,
intersection := S.intersection,
factorization := f );
end );
############################################################################# ## #M PcGroupWithPcgs( <pcgs> ) ##
BindGlobal( "GROUP_BY_PCGS_FINITE_ORDERS", function( pcgs )
local f, e, m, i, type, s, id, tmp, j;
# construct a new free group
f := FreeGroup(IsSyllableWordsFamily, Length(pcgs) );
e := ElementsFamily( FamilyObj(f) );
# and a default type if0 = Length(pcgs) then
m := 1; else
m := Maximum(RelativeOrders(pcgs)); fi;
i := 1; while i < 4 and e!.expBitsInfo[i] <= m do
i := i + 1;
od;
type := e!.types[i];
# and use a single collector
s := SingleCollector( f, RelativeOrders(pcgs) );
# compute the power relations
id := pcgs!.zeroVector; for i in [ 1 .. Length(pcgs) ] do #tmp := pcgs[i]^RelativeOrderOfPcElement(pcgs,pcgs[i]);
tmp := ExponentsOfRelativePower(pcgs,i); if tmp <> id then #tmp := ExponentsOfPcElement( pcgs, tmp );
tmp := ObjByVector( type, tmp );
SetPowerNC( s, i, tmp ); fi;
od;
# compute the conjugates for i in [ 1 .. Length(pcgs) ] do for j in [ i+1 .. Length(pcgs) ] do #tmp := pcgs[j] ^ pcgs[i];
tmp := ExponentsOfConjugate(pcgs,j,i); if tmp <> id then #tmp := ExponentsOfPcElement( pcgs, tmp );
tmp := ObjByVector( type, tmp );
SetConjugateNC( s, j, i, tmp ); fi;
od;
od;
# and return the new group
return GroupByRwsNC(s);
pcgs := enum!.pcgs;
elm := OneOfPcgs( pcgs );
pos := pos - 1; for i in Reversed( enum!.sublist ) do
p := enum!.relativeOrders[i];
elm := pcgs[ i ] ^ ( pos mod p ) * elm;
pos := QuoInt( pos, p );
od;
return elm; end );
function( enum, elm, zero )
local pcgs, exp, pos, i;
pcgs := enum!.pcgs; if not elm in GroupOfPcgs (pcgs) then
return fail; fi;
exp := ExponentsOfPcElement( pcgs, elm );
pos := 0; if ForAny( enum!.complementList, x -> 0 <> exp[x] ) then
return fail; fi; for i in enum!.sublist do
pos := pos * enum!.relativeOrders[i] + exp[i];
od;
Assert (1, elm = enum[pos+1], "enum-by-pcgs: wrong element found");
return pos + 1; end );
pcgs := enum!.pcgs; if not elm in GroupOfPcgs (pcgs) then
return fail; fi;
exp := ExponentsOfPcElement( pcgs, elm );
pos := 0; for i in enum!.sublist do
pos := pos * enum!.relativeOrders[i] + exp[i];
od;
return pos + 1; end );
BindGlobal( "InstallPcgsSeriesFromIndices", function(series,indices)
InstallMethod(series,"from indices",true,[Tester(indices) and IsPcgs],0, function(pcgs)
local p,l,g,h,i,ipcgs,home;
home:=ParentPcgs(pcgs);
l:=indices(pcgs);
p := GroupOfPcgs(pcgs);
SetInducedPcgs(home,p,pcgs);
g:=[p]; for i in [2..Length(l)-1] do
ipcgs:=InducedPcgsByPcSequenceNC(home,pcgs{[l[i]..Length(pcgs)]});
h:=SubgroupByPcgs(p,ipcgs);
SetInducedPcgs(home,h,ipcgs);
Add(g,h);
od;
Add(g,TrivialSubgroup(p));
return g; end);
# for perm grps, the tail method is problematic
InstallMethod(series,"from indices",true,
[Tester(indices) and IsPcgs and IsPcgsPermGroupRep],0, function(pcgs)
local p,l,g,h,i,ipcgs,home;
home:=ParentPcgs(pcgs);
l:=indices(pcgs);
p := GroupOfPcgs(pcgs);
SetInducedPcgs(home,p,pcgs);
g:=[p]; for i in [2..Length(l)-1] do
ipcgs:=pcgs{[l[i]..Length(pcgs)]};
h:=SubgroupNC(p,ipcgs);
SetGroupOfPcgs (ipcgs, h);
Add(g,h);
od;
Add(g,TrivialSubgroup(p));
return g; end);
InstallMethod(series,"from PcSeries",true,
[IsPcgs and HasPcSeries and Tester(indices)],0, function(pcgs)
return PcSeries(pcgs){indices(pcgs)}; end);
# workaround for old code
InstallMethod(series,"compatibility only",true,
[IsPcgs and HasIndicesNormalSteps],
{} -> -RankFilter(HasIndicesNormalSteps), function(pcgs)
local p,l,g,h,i,ipcgs,home;
home:=ParentPcgs(pcgs);
l:=IndicesNormalSteps(pcgs);
Info(InfoWarning,1, "using (obsolete) `IndicesNormalSteps'. Might lead to problems");
p := GroupOfPcgs(pcgs);
SetInducedPcgs(home,p,pcgs);
g:=[p]; for i in [2..Length(l)-1] do
ipcgs:=InducedPcgsByPcSequenceNC(home,pcgs{[l[i]..Length(pcgs)]});
h:=SubgroupByPcgs(p,ipcgs);
SetInducedPcgs(home,p,ipcgs);
Add(g,h);
od;
Add(g,TrivialSubgroup(p));
return g; end);
InstallMethod(indices,"compatibility only",true,
[IsPcgs and HasIndicesNormalSteps],
{} -> -RankFilter(HasIndicesNormalSteps), function(pcgs)
local l;
l:=IndicesNormalSteps(pcgs);
Info(InfoWarning,1, "using (obsolete) `IndicesNormalSteps'. Might lead to problems");
return l; end);
############################################################################# ## #M IndicesEANormalStepsBounded( <pcgs>,<bound> ) ##
InstallGlobalFunction(IndicesEANormalStepsBounded,function(pcgs,bound)
local rel,ind,gp,i,j,try;
rel:=RelativeOrders(pcgs);
ind:=IndicesEANormalSteps(pcgs);
gp:=GroupOfPcgs(pcgs);
i:=2; while i<=Length(ind) do if rel[ind[i-1]]^(ind[i]-ind[i-1])>bound then # too large, try to make smaller while keeping pcgs
j:=ind[i-1]+1;
try:=true; while try and j<ind[i] do if IsNormal(gp,SubgroupByPcgs(gp,
InducedPcgsByPcSequenceNC(pcgs,pcgs{[j..Length(pcgs)]}))) then # found normal in between
ind:=Concatenation(ind{[1..i-1]},[j],ind{[i..Length(ind)]});
try:=false; else
j:=j+1; fi;
od; if try then i:=i+1;fi; else
i:=i+1; fi;
od;
return ind; end);
############################################################################# ## #M BoundedRefinementEANormalSeries( <home>,<bound> ) ## ## try to make series factors smaller, even if at cost of changing pcgs
InstallGlobalFunction(BoundedRefinementEANormalSeries,function(home,ind,bound)
local pcgs,rel,gp,i,indp,inds,module,sub;
pcgs:=home;
rel:=RelativeOrders(pcgs);
gp:=GroupOfPcgs(pcgs);
i:=2; while i<=Length(ind) do if rel[ind[i-1]]^(ind[i]-ind[i-1])>bound then # too large, try to find submodule
indp:=InducedPcgsByPcSequenceNC(pcgs,pcgs{[ind[i-1]..Length(pcgs)]});
inds:=indp
mod InducedPcgsByPcSequenceNC(pcgs,pcgs{[ind[i]..Length(pcgs)]});
module:=GModuleByMats(LinearActionLayer(gp,inds),GF(rel[ind[i-1]])); if not MTX.IsIrreducible(module) then # the subbasis will be part of the pcgs
sub:=MTX.Subbasis(module);
sub:=List(sub,x->PcElementByExponentsNC(inds,x));
Append(sub,pcgs{[ind[i]..Length(pcgs)]});
sub:=InducedPcgsByPcSequenceNC(pcgs,sub);
sub:=CanonicalPcgs(sub);
inds:=indp mod sub; if Length(inds)=0then Error("EE");fi; # make new pcgs indices, relative orders stay the same
pcgs:=Concatenation(pcgs{[1..ind[i-1]-1]},inds!.pcSequence,sub);
pcgs:=PcgsByPcSequence(ElementsFamily(FamilyObj(home)),pcgs);
ind:=Concatenation(ind{[1..i-1]},[ind[i-1]+Length(inds)],
ind{[i..Length(ind)]});
SetIndicesChiefNormalSteps(pcgs,ind); else
i:=i+1; # cannot do
SetIndicesChiefNormalSteps(pcgs,ind); fi; else
i:=i+1; fi;
od;
return [pcgs,ind]; end);
############################################################################# ## #M IsPcgsElementaryAbelianSeries( <pcgs> ) ##
InstallMethod(IsPcgsElementaryAbelianSeries,"test if elm. abelian",true,
[IsPcgs],0, function(p)
local n, o, j, i, d, ro, n2, ea, ran; if HasIndicesEANormalSteps(p) then
n:=IndicesEANormalSteps(p); # get the indices stored already else
n:=[Length(p)+1];
o:=Length(p); # next attempted normal level
j:=o; # generator currently conjugated while j>0do
repeat
i:=1; # conjugating generator while i<o do
d:=DepthOfPcElement(p,p[j]^p[i]); if d<o then # NT is larger than expected
o:=d; fi;
i:=i+1;
od;
j:=j-1;
until j<o; # we've found another normal step
Add(n,o);
o:=j;
od;
n:=Reversed(n); fi;
ro:=RelativeOrders(p);
n2:=[1];
i:=1; while i<=Length(n)-1do # test el ab and whether we can make it coarser
j:=i;
ea:=true;
repeat
j:=j+1;
ran:=[n[i]..n[j]-1]; #pcgs range
o:=Set(ro{ran}); if Length(o)>1then
ea:=false; # could this ever happen anyhow? fi;
o:=o[1]; if ForAny(p{ran},x->DepthOfPcElement(p,x^o)<n[j]) then
ea:=false; # not exponent p fi; if ForAny(p{ran},
k->ForAny(p{ran},x->DepthOfPcElement(p,Comm(x,k))<n[j])) then
ea:=false; # not abelian fi;
until ea=false or j=Length(n); if ea=false then
j:=j-1; # last ea step if j=i then
return false; # not EA series, even first step failed. fi;
Add(n2,n[j]);
i:=j; else
Add(n2,n[j]);
i:=j+1; fi;
od;
SetIndicesEANormalSteps(p,n);
return true; end);
InstallGlobalFunction(LiftedPcElement,function(new,old,elm)
local e;
e:=ShallowCopy(new!.zeroVector);
e{[1..Length(old)]}:=ExponentsOfPcElement(old,elm);
return PcElementByExponentsNC(new,e); end);
InstallGlobalFunction(ProjectedInducedPcgs,function(old,new,pcgs)
local p,i,e;
p:=[]; for i in pcgs!.pcSequence do
e:=ProjectedPcElement(old,new,i); if not IsOne(e) then
Add(p,e); fi;
od;
return InducedPcgsByPcSequenceNC(new,p); end);
InstallGlobalFunction(LiftedInducedPcgs,function(new,old,pcgs,ker)
local p,i;
p:=[]; for i in pcgs do
Add(p,LiftedPcElement(new,old,i));
od;
return InducedPcgsByPcSequenceNC(new,Concatenation(p,ker)); end);
############################################################################# ## #M IsPcgsElementaryAbelianSeries( <pcgs> ) ##
BindGlobal("DoPcgsElementaryAbelianSeries",function(param)
local G,e,ind,s,m,i,p; if IsList(param) then
G:=param[1]; if HasPcgsElementaryAbelianSeries(G) then # can we use the known pcgs?
p:=PcgsElementaryAbelianSeries(G);
e:=EANormalSeriesByPcgs(p); if ForAll(param,i->i in e) then
return p; fi; fi; else
G:=param; fi; if not IsSolvableGroup(G) then
Error("<G> must be solvable"); fi;
IsFinite(G); # trigger finiteness test
e:=ElementaryAbelianSeriesLargeSteps(param);
ind:=[];
s:=[]; for i in [1..Length(e)-1] do
m:=ModuloPcgs(e[i],e[i+1]);
Add(ind,Length(s)+1);
Append(s,m);
od;
Add(ind,Length(s)+1);
p:=PcgsByPcSequence(FamilyObj(One(G)),s);
SetIsPcgsElementaryAbelianSeries(p,true);
SetIsPrimeOrdersPcgs(p,true);
SetIndicesEANormalSteps(p,ind);
SetEANormalSeriesByPcgs(p,e);
return p; end);
############################################################################# ## #M PcgsElementaryAbelianSeries( <G> ) ##
InstallMethod( PcgsElementaryAbelianSeries, "generic group", true, [ IsGroup ], 1, # rank higher than package method to make behavior more predictable
DoPcgsElementaryAbelianSeries);
############################################################################# ## #R IsPcgsByPcgsRep ## ## representation for a pcgs that calculates exponents wrt. one pcgs and ## then determines the desired exponents in a shadowing pc group ##
DeclareRepresentation( "IsPcgsByPcgsRep",
IsPcgsDefaultRep and IsFiniteOrdersPcgs, [ "usePcgs", "shadowFamilyPcgs", "shadowImagePcgs" ] );
InstallGlobalFunction(PcgsByPcgs,function(gens,use,family,images)
local pcgs;
pcgs:=PcgsByPcSequenceCons(IsPcgsDefaultRep,
IsPcgsByPcgsRep and IsPcgs and IsPrimeOrdersPcgs,
FamilyObj(gens[1]),gens,[]);
pcgs!.usePcgs:=use;
pcgs!.shadowFamilyPcgs:=family;
pcgs!.shadowImagePcgs:=images;
SetRelativeOrders(pcgs,RelativeOrders(images));
return pcgs; end);
InstallMethod(ExponentsOfPcElement,"pcgs by pcgs",IsCollsElms,
[IsPcgsByPcgsRep and IsPcgs,IsObject], function(pcgs,elm)
local e;
e:=ExponentsOfPcElement(pcgs!.usePcgs,elm);
e:=PcElementByExponentsNC(pcgs!.shadowFamilyPcgs,e);
e:=ExponentsOfPcElement(pcgs!.shadowImagePcgs,e);
return e; end);
InstallMethod(DepthOfPcElement,"pcgs by pcgs",IsCollsElms,
[IsPcgsByPcgsRep and IsPcgs,IsObject], function(pcgs,elm)
local e;
e:=ExponentsOfPcElement(pcgs!.usePcgs,elm);
e:=PcElementByExponentsNC(pcgs!.shadowFamilyPcgs,e);
e:=DepthOfPcElement(pcgs!.shadowImagePcgs,e);
return e; 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.