|
#############################################################################
##
## 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 normalizers of polycyclic groups.
##
#############################################################################
##
#F PCGS_STABILIZER( <pcgs>, <pnt>, <op> ) . . . . . . . . . . . . . . local
##
BindGlobal( "PCGS_STABILIZER", function( arg )
local pcgs, pnt, op, data, one, orb, prod, n, s, i,
mi, np, j, o, len, l1, k, l2, r, e, stab, ros,dict;
pcgs := arg[1];
pnt := arg[2];
op := arg[3];
one := OneOfPcgs(pcgs);
ros := RelativeOrders(pcgs);
pcgs := ShallowCopy(pcgs);
dict:=NewDictionary(pnt,true,true);
# without data blob
if Length(arg) = 3 then
# operate on canonical versions
pnt := op( pnt, one );
# store representatives in <r>
orb := [ pnt ];
AddDictionary(dict,pnt,1);
prod := [ 1 ];
n := [];
s := [];
stab := [];
# go *up* the composition series
for i in Reversed([1..Length(pcgs)]) do
mi := pcgs[i];
np := op( pnt, mi );
# is <np> really a new point or is it in <orb>
j := LookupDictionary(dict, np );
# add it if it is new
if j = fail then
o := ros[i];
Add( prod, Last(prod) * o );
Add( n, i );
len := Length(orb);
l1 := 0;
for k in [ 1 .. o-1 ] do
l2 := l1 + len;
for j in [ 1 .. len ] do
orb[j+l2] := op( orb[j+l1], mi );
AddDictionary(dict,orb[j+l2],j+l2);
od;
l1 := l2;
od;
# if it is the start point the element stabilizes
elif j = 1 then
Add( s, mi );
# compute a stabilizing element
else
if not IsBound(stab[j]) then
r := one;
l1 := j-1;
len := Length(prod);
for k in [ 1 .. len-1 ] do
e := QuoInt( l1, prod[len-k] );
r := pcgs[n[len-k]]^e * r;
l1 := l1 mod prod[len-k];
if l1 = 0 then
break;
fi;
od;
stab[j] := r;
fi;
Add( s, pcgs[i] / stab[j] );
fi;
od;
# with data blob
else
data := arg[4];
# operate on canonical versions
pnt := op( data, pnt, one );
# store representatives in <r>
orb := [ pnt ];
AddDictionary(dict,pnt,1);
prod := [ 1 ];
n := [];
s := [];
stab := [];
# go *up* the composition series
for i in Reversed([1..Length(pcgs)]) do
mi := pcgs[i];
np := op( data, pnt, mi );
# is <np> really a new point or is it in <orb>
j := LookupDictionary(dict, np );
# add it if it is new
if j = fail then
o := ros[i];
Add( prod, Last(prod) * o );
Add( n, i );
len := Length(orb);
l1 := 0;
for k in [ 1 .. o-1 ] do
l2 := l1 + len;
for j in [ 1 .. len ] do
orb[j+l2] := op( data, orb[j+l1], mi );
AddDictionary(dict,orb[j+l2],j+l2);
od;
l1 := l2;
od;
# if it is the start point the element stabilizes
elif j = 1 then
Add( s, mi );
# compute a stabilizing element
else
if not IsBound(stab[j]) then
r := one;
l1 := j-1;
len := Length(prod);
for k in [ 1 .. len-1 ] do
e := QuoInt( l1, prod[len-k] );
r := pcgs[n[len-k]]^e * r;
l1 := l1 mod prod[len-k];
if l1 = 0 then
break;
fi;
od;
stab[j] := r;
fi;
Add( s, pcgs[i] / stab[j] );
fi;
od;
fi;
Info( InfoPcNormalizer, 3, "orbit length: ", Length(orb) );
return Reversed(s);
end );
#############################################################################
##
#F PCGS_STABILIZER_HOMOMORPHIC( <pcgs>, <homs>, <pnt>, <op> ) . . . . local
##
BindGlobal( "PCGS_STABILIZER_HOMOMORPHIC", function( arg )
local pcgs, homs, pnt, op, ros, one, hone, orb, prod,
n, s, stab, i, mi, np, j, o, len, l1, k, l2,
r, e, dict;
pcgs := arg[1];
homs := arg[2];
pnt := arg[3];
op := arg[4];
dict:=NewDictionary(pnt,true,true);
if 0 = Length(pcgs) then
return pcgs;
fi;
if Length(pcgs) <> Length(homs) then
Error( "expecting ", Length(pcgs), " homomorphic images in <homs>" );
fi;
ros := RelativeOrders(pcgs);
one := OneOfPcgs(pcgs);
hone := One(homs[1]);
pcgs := ShallowCopy(pcgs);
# without data blob
if Length(arg) = 4 then
# operate on canonical versions
pnt := op( pnt, hone );
# store representatives in <r>
orb := [ pnt ];
AddDictionary(dict,pnt,1);
prod := [ 1 ];
n := [];
s := [];
stab := [];
# go *up* the composition series
for i in Reversed([1..Length(pcgs)]) do
mi := homs[i];
np := op( pnt, mi );
# is <np> really a new point or is it in <orb>
j := LookupDictionary(dict, np );
# add it if it is new
if j = fail then
o := ros[i];
Add( prod, Last(prod) * o );
Add( n, i );
len := Length(orb);
l1 := 0;
for k in [ 1 .. o-1 ] do
l2 := l1 + len;
for j in [ 1 .. len ] do
orb[j+l2] := op( orb[j+l1], mi );
AddDictionary(dict,orb[j+l2],j+l2);
od;
l1 := l2;
od;
# if it is the start point the element stabilizes
elif j = 1 then
Add( s, pcgs[i] );
# compute a stabilizing element
else
if not IsBound(stab[j]) then
r := one;
l1 := j-1;
len := Length(prod);
for k in [ 1 .. len-1 ] do
e := QuoInt( l1, prod[len-k] );
r := pcgs[n[len-k]]^e * r;
l1 := l1 mod prod[len-k];
if l1 = 0 then
break;
fi;
od;
stab[j] := r;
fi;
Add( s, pcgs[i] / stab[j] );
fi;
od;
# with data blob, this case is not used at all
else
Error("you should never be here");
fi;
Info( InfoPcNormalizer, 3, "orbit length: ", Length(orb) );
return Reversed(s);
end );
#############################################################################
##
#F PCGS_NORMALIZER( <home>, <norm>, <point>, <pcgs>, <modulo> )
##
BindGlobal( "PCGS_NORMALIZER_OPB", function( home, elm, obj )
local ord;
elm := elm^obj;
ord := RelativeOrderOfPcElement( home, elm );
return elm ^ ( 1 / LeadingExponentOfPcElement( home, elm ) mod ord );
end );
BindGlobal( "PCGS_NORMALIZER_OPC1", function( data, elm, obj )
local ord;
elm := elm^obj;
ord := RelativeOrderOfPcElement( data[1], elm );
elm := elm ^ ( 1 / LeadingExponentOfPcElement( data[1], elm ) mod ord );
return HeadPcElementByNumber( data[1], elm, data[2] );
end );
BindGlobal( "PCGS_NORMALIZER_OPC2", function( data, elm, obj )
# was: return CanonicalPcElement( data[2], elm^obj );
local ord;
elm := elm^obj;
ord:=RelativeOrderOfPcElement(data[1],elm);
elm := elm ^ ( 1 / LeadingExponentOfPcElement( data[1], elm ) mod ord );
return CanonicalPcElement( data[2], elm );
end );
BindGlobal( "PCGS_NORMALIZER_OPD", function( data, lst, obj )
lst:=CorrespondingGeneratorsByModuloPcgs(data,List(lst,i->i^obj));
return lst;
end );
BindGlobal( "PCGS_NORMALIZER_OPE", function( data, lst, obj )
local home, pag, pos, max, i, g, dg, exp, j, ros;
home := data[1];
pag := data[2]; # make sure to reset <pag> before returning
pos := [];
max := data[3];
ros := data[4];
for i in [ Length(lst), Length(lst)-1 .. 1 ] do
g := lst[i]^obj;
dg := DepthOfPcElement( home, g );
while dg < max do
if IsBound(pag[dg]) then
g := ReducedPcElement( home, g, pag[dg] );
dg := DepthOfPcElement( home, g );
else
pag[dg] := g;
AddSet( pos, dg );
break;
fi;
od;
od;
for i in Reversed(pos) do
exp := LeadingExponentOfPcElement( home, pag[i] );
if exp <> 1 then
pag[i] := pag[i] ^ (1/exp mod ros[i]);
fi;
for j in [ i+1 .. max-1 ] do
if IsBound(pag[j]) then
exp := ExponentOfPcElement( home, pag[i], j );
if exp <> 0 then
pag[i] := pag[i] * pag[j]^(ros[j]-exp);
fi;
fi;
od;
pag[i] := HeadPcElementByNumber( home, pag[i], max );
od;
lst := pag{pos};
for i in pos do Unbind(pag[i]); od;
return lst;
end );
BindGlobal( "PCGS_NORMALIZER_DATAE", function( home, modulo )
local ros, sub, i, dg, exp, max;
ros := RelativeOrders(home);
sub := [];
for i in modulo do
dg := DepthOfPcElement( home, i );
exp := LeadingExponentOfPcElement( home, i );
if exp <> 1 then
i := i ^ (1/exp mod ros[dg]);
fi;
sub[dg] := i;
od;
max := Length(home)+1;
while 2 <= max and IsBound(sub[max-1]) do
max := max-1;
od;
return [ home, sub, max, ros ];
end );
BindGlobal( "PCGS_NORMALIZER", function( home, pcgs, pnt, modulo )
local op, s, data;
Info( InfoPcNormalizer, 5, "home: ", ShallowCopy(home) );
Info( InfoPcNormalizer, 4, "normalizer: ", ShallowCopy(pcgs) );
Info( InfoPcNormalizer, 4, "point: ", ShallowCopy(pnt) );
Info( InfoPcNormalizer, 5, "modulo: ", ShallowCopy(modulo) );
# if <pnt> and <modulo> have the same length nothing is to be done
if Length(pnt) = Length(modulo) then
Info( InfoPcNormalizer, 3, "PCGS_NORMALIZER case A" );
return pcgs;
# if <pnt> mod <modulo> has only one element operate on elements
elif Length(pnt)-1 = Length(modulo) then
if 0 = Length(modulo) then
Info( InfoPcNormalizer, 3, "PCGS_NORMALIZER case B" );
pnt := pnt[1];
op := PCGS_NORMALIZER_OPB;
data := home;
s := PCGS_STABILIZER( pcgs, pnt, op, home );
else
pnt := pnt mod modulo;
pnt := pnt[1];
if ParentPcgs(modulo)=home and IsTailInducedPcgsRep(modulo) then
Info( InfoPcNormalizer, 3, "PCGS_NORMALIZER case C1" );
op := PCGS_NORMALIZER_OPC1;
data := [ home, modulo!.tailStart ];
else
Info( InfoPcNormalizer, 3, "PCGS_NORMALIZER case C2" );
op := PCGS_NORMALIZER_OPC2;
data := [home,modulo];
fi;
s := PCGS_STABILIZER( pcgs, pnt, op, data );
fi;
# if the <modulo> is trivial it is relatively easy
elif 0 = Length(modulo) then
Info( InfoPcNormalizer, 3, "PCGS_NORMALIZER case D" );
op := PCGS_NORMALIZER_OPD;
pnt := ShallowCopy(pnt);
s := PCGS_STABILIZER( pcgs, pnt, op, home );
# it is get more complicated
else
Info( InfoPcNormalizer, 3, "PCGS_NORMALIZER case E" );
data := PCGS_NORMALIZER_DATAE( home, modulo );
op := PCGS_NORMALIZER_OPE;
pnt := ShallowCopy( pnt mod modulo );
s := PCGS_STABILIZER( pcgs, pnt, op, data );
fi;
# convert it into a modulo pcgs
pcgs := SumPcgs( home, DenominatorOfModuloPcgs(pcgs), s )
mod DenominatorOfModuloPcgs(pcgs);
Info( InfoPcNormalizer, 4, "new norm: ", ShallowCopy(pcgs) );
return pcgs;
end );
#############################################################################
##
#F PCGS_NORMALIZER_LINEAR( <home>, <norm>, <point>, <modulo-pcgs> )
##
BindGlobal( "PCGS_NORMALIZER_LINEAR", function( home, pcgs, pnt, modulo )
local f, o, m, sub, s,p,op;
Info( InfoPcNormalizer, 5, "home: ", ShallowCopy(home) );
Info( InfoPcNormalizer, 4, "normalizer: ", ShallowCopy(pcgs) );
Info( InfoPcNormalizer, 4, "point: ", ShallowCopy(pnt) );
Info( InfoPcNormalizer, 5, "modulo: ", ShallowCopy(modulo) );
# construct the linear operation
p:=RelativeOrderOfPcElement( home, modulo[1] );
f := GF(p);
o := One(f);
m := List( pcgs, x -> List( modulo, y ->
ExponentsConjugateLayer( modulo, y,x ) * o ) );
for s in [1..Length(m)] do
m[s]:=ImmutableMatrix(f,m[s]);
od;
# convert <pnt> into a subspace
sub := pnt mod DenominatorOfModuloPcgs(modulo);
sub := List( sub, x -> ExponentsOfPcElement( modulo, x ) * o );
sub:=ImmutableMatrix(f,sub);
# select operation function and prepare matrices if necessary
if p=2 then
op:=OnSubspacesByCanonicalBasisGF2;
else
op:=OnSubspacesByCanonicalBasis;
fi;
# compute the stabilizer
Info( InfoPcNormalizer, 3, "PCGS_NORMALIZER_LINEAR case A" );
s := PCGS_STABILIZER_HOMOMORPHIC( pcgs, m, sub, op );
# convert it into a modulo pcgs
pcgs := SumPcgs( home, DenominatorOfModuloPcgs(pcgs), s )
mod DenominatorOfModuloPcgs(pcgs);
Info( InfoPcNormalizer, 4, "new norm: ", ShallowCopy(pcgs) );
return pcgs;
end );
#############################################################################
##
#F PCGS_CONJUGATING_WORD_GS( <home>, <n>, <u>, <v>, <k> )
##
## Let <u> / <k> and <v> / <k> be two p-groups such that <u>*<n> = <v>*<n>
## and let <n> be an elementary abelian q-group with q <> p. Then a word x
## of <n> with <u> ^ x = <v> is returned. <k> must be normal in <u>*<n>.
##
## It is important, that the weights of <K> are less than those of <N>.
##
BindGlobal( "PCGS_CONJUGATING_WORD_GS", function( home, n, u, v, k )
local id, x, q, i, p, t, m, vv, mm, xx, j;
# if <n> or <u> / <k> is trivial, just return identity
id := OneOfPcgs(home);
if 0 = Length(n) or 0 = Length(u) or u = v then
return id;
fi;
# Find the word <n> using the algorithm of Kantor. See S.P.Glasby and
# Michael C. Slattery, "Computing intersections and normalizers in
# soluble groups", 1989.
x := id;
q := RelativeOrderOfPcElement( home, n[1] );
for i in Reversed( [ 1 .. Length(u) ] ) do
# the orders must be coprime
p := RelativeOrderOfPcElement( home, u[i] );
if q = p then
Error( "relative orders <u> and <n> are not coprime" );
fi;
# Compute an integer <t> such that <t> * <p> = -1 mod <q>.
t := -Gcdex( p, q ).coeff1;
while t > q do t := t - q; od;
while t < 0 do t := t + q; od;
m := LeftQuotient( u[i]^x, v[i] );
m := SiftedPcElement( k, m );
vv := id;
mm := id;
xx := id;
# construct the product m^v * (m^2)^(v^2) * ... * (m^p-1)^(v^p-1)
for j in [ 1 .. p-1 ] do
vv := vv * v[i];
mm := mm * m;
xx := xx * ( mm^vv );
od;
x := x * ( xx ^ t );
od;
return x;
end );
#############################################################################
##
#F PCGS_NORMALIZER_GLASBY( <home>, <norm>, <nis>, <pcgs>, <modulo> )
##
BindGlobal( "PCGS_NORMALIZER_GLASBY", function( home, pcgs, nis, u1, u2 )
local id, stb, data, pnt, i, cnj, ns, one, mats, sys,
sol, v, j;
# The situation is as follows:
#
# S
# \
# \
# Us
# / \
# / \
# U1 Ns N
# \ / \ /
# \ / \ /
# U2 NiS
# \ /
# \ /
# Un
#
# and <S> stabilizes <U2>
# first correct (S mod NiS)
Info( InfoPcNormalizer, 4, "correcting glasby block stabilizer" );
id := OneOfPcgs(pcgs);
stb := NumeratorOfModuloPcgs(pcgs) mod NumeratorOfModuloPcgs(nis);
stb := ShallowCopy(stb);
data := PCGS_NORMALIZER_DATAE( home, u2 );
pnt := PCGS_NORMALIZER_OPE( data, u1 mod u2, id );
for i in [ 1 .. Length(stb) ] do
cnj := PCGS_NORMALIZER_OPE( data, pnt, stb[i] );
cnj := PCGS_CONJUGATING_WORD_GS( home, nis, cnj, pnt, u2 );
stb[i] := stb[i] * cnj;
od;
# now compute the stabilizer in <nis>
Info( InfoPcNormalizer, 4, "computing the centralizer in <nis>" );
# first the operation of <pnt> on (NiS mod U2)
ns := SumPcgs( home, u2, NumeratorOfModuloPcgs(nis) ) mod u2;
one := One( GF(RelativeOrderOfPcElement(home,ns[1])) );
mats := List( pnt, x -> List( ns, y ->
ExponentsConjugateLayer( ns, y,x ) * one ) );
# set up the system of equations
one := One(mats[1]);
sys := [];
for i in [ 1 .. Length(mats[1]) ] do
sys[i] := [];
for j in [ 1 .. Length(mats) ] do
Append( sys[i], one[i] - mats[j][i] );
od;
od;
sol := TriangulizedNullspaceMat(sys);
for v in sol do
v := List( v, IntFFE );
Add( stb, PcElementByExponentsNC(ns,v) );
od;
# Now we have the normalizer in <S> / <U2>. Get the complete preimage.
return SumPcgs( home, u2, stb )
mod DenominatorOfModuloPcgs(pcgs);
end );
#############################################################################
##
#F PCGS_NORMALIZER_COBOUNDS( <home>, <norm>, <nis>, <pcgs>, <modulo> )
##
BindGlobal( "PCGS_NORMALIZER_COBOUNDS", function( home, pcgs, nis, u1, u2 )
local ns, us, gf, one, data, u, ui, mats, t, l, i, b,
nb, c, heads, k, ln1, ln2, op, stab, s, j, v;
# The situation is as follows:
#
# S
# \
# \
# Us
# / \
# / \
# U1 Ns N
# \ / \ /
# \ / \ /
# U2 NiS
# \ /
# \ /
# Un
#
# and <S> stabilizes <U2>
# compute the operation of <u1> mod <u2> on <ns> mod <u2>
ns := SumPcgs( home, u2, NumeratorOfModuloPcgs(nis) ) mod u2;
us := SumPcgs( home, u1, NumeratorOfModuloPcgs(nis) );
gf := GF(RelativeOrderOfPcElement(home,ns[1]));
one := One(gf);
data := PCGS_NORMALIZER_DATAE( home, u2 );
u := PCGS_NORMALIZER_OPE( data, u1 mod u2, OneOfPcgs(home) );
ui := List( u, Inverse );
mats := List( u, x -> List(ns, y -> ExponentsConjugateLayer(ns,y,x)*one) );
# compute the coboundaries
Info( InfoPcNormalizer, 4, "using coboundaries and centralizer" );
t := One(mats[1]);
l := [];
for i in [ 1 .. Length(mats[1]) ] do
l[i] := [];
for j in [ 1 .. Length(mats) ] do
Append( l[i], t[i]-mats[j][i] );
od;
od;
b := TriangulizedGeneratorsByMatrix( ns, l, gf );
nb := b[1];
b := b[2];
b := ImmutableMatrix(gf, b);
# trivial coboundaries, use ordinary orbit
if IsEmpty(b) then
Info( InfoPcNormalizer, 4, "coboundaries are trivial" );
return PCGS_NORMALIZER( home, pcgs, u1, u2 );
fi;
Info( InfoPcNormalizer, 4, "|coboundaries| = ",
RelativeOrderOfPcElement(home,ns[1]), "^", Length(b) );
# compute the stabilizer
c := List( TriangulizedNullspaceMat(l), x -> PcElementByExponentsNC(ns,x) );
# compute the heads of the coboundaries
heads := [];
k := 1;
i := 1;
while i <= Length(b) and k <= Length(b[1]) do
if IntFFE(b[i][k]) <> 0 then
heads[i] := k;
i := i+1;
fi;
k := k+1;
od;
# now the function which acts on the coboundaries
ln1 := Length(ns);
ln2 := Length(u);
op := function( v, x )
local w, i;
# add the coboundary <v> to <u>
w := ShallowCopy(u);
for i in [ 1 .. ln2 ] do
w[i] := w[i] * PcElementByExponentsNC(ns, v{[(i-1)*ln1+1..i*ln1]});
od;
# operate with <x> on <w> and normalize modulo <u2>
w := PCGS_NORMALIZER_OPE( data, w, x );
# convert back into a vector
v := [];
for i in [ 1 .. ln2 ] do
Append( v, ExponentsOfPcElement( ns, ui[i]*w[i] ) );
od;
v := v * One(gf);
v := ImmutableVector(gf, v);
for i in [ 1 .. Length(heads) ] do
v := v - v[heads[i]] * b[i];
od;
return Immutable(v);
end;
# compute the blockstabilizer
Info( InfoPcNormalizer, 4, "computing blockstabilizer" );
stab := PCGS_STABILIZER( NumeratorOfModuloPcgs(pcgs) mod us,
b[1] * Zero(gf),
op );
# compute and correct the blockstabilizer
Info( InfoPcNormalizer, 4, "correcting blockstabilizer" );
nb := List( nb, x -> x ^ -1 );
for i in [ 1 .. Length(stab) ] do
s := PCGS_NORMALIZER_OPE( data, u, stab[i] );
v := [];
for j in [ 1 .. ln2 ] do
Append( v, ExponentsOfPcElement( ns, ui[j]*s[j] ) );
od;
for j in [ 1 .. Length(heads) ] do
if v[heads[j] ] <> 0 then
stab[i] := stab[i] * ( nb[j]^v[heads[j]] );
fi;
od;
od;
# return sum of <L>, <C> and <U1>
return InducedPcgsByGeneratorsNC( home, Concatenation( stab, c, u1 ) )
mod DenominatorOfModuloPcgs(pcgs);
end );
#############################################################################
##
#F PcGroup_NormalizerWrtHomePcgs( <u>, <f1>, <f2>, <f3>, <f4> )
##
## compute the normalizer of <u> in its home pcgs, the flags <f1> to <f4>
## can be used to fine tune the normalizer computation:
##
## <f1> if 'true', intersections with the same prime than the module are
## computed using one cobounds. Otherwise an ordinary orbit
## stabilizer algorithm is used.
##
## <f2> if 'true', intersections with different prime than the module are
## computed using one cobounds. Otherwise the method of computation
## depends on the flag <f3>.
##
## <f3> if 'true' and <f2> is 'false', then intersections with different
## prime than the module are computed using Glasby's algorithm.
## Otherwise a ordinary orbit stabilizer algorithm is used.
##
## <f4> if 'true', the first intersection is computed using linear
## operations. Otherwise a ordinary orbit stabilizer algorithm is
## used.
##
DeclareGlobalName("PcGroup_NormalizerWrtHomePcgs");
BindGlobal( "PcGroup_NormalizerWrtHomePcgs", function( u, f1, f2, f3, f4 )
local g, # home pcgs of <pcgs>
e, r, # elementary abelian series of <G> and its length
ue, # factor pcgs <pcgs><e>[i] mod <e>[i]
uk, uj, ui_1, # intersections of <pcgs> with <e>[x]
s, si_1, # stabilizer and its intersection with <e>[i-1]
ei_1, # <e>[i-1] mod <e>[i]
pj, pi_1, # primes of <e>[j] and <e>[i-1]
st, # used for checking the algorithm
i, j, k, # loops
pcgs, # pcgs of <u>
id, # identity element
tmp; # temporary
# get the parent pcgs and the elementary abelian series
g := HomePcgs(u);
id := OneOfPcgs(g);
e := ElementaryAbelianSubseries(g);
if e = fail then
Info( InfoPcNormalizer, 1, "Computing el.ab. PCGS" );
s := SpecialPcgs(g);
k := NaturalIsomorphismByPcgs( GroupOfPcgs(g), s );
if ElementaryAbelianSubseries(Pcgs(Image(k))) = fail then
Error( "corrupted special pcgs" );
fi;
tmp := InducedPcgsByGeneratorsNC( g, List(
PcGroup_NormalizerWrtHomePcgs( Image(k,u), f1, f2, f3, f4 ),
x -> PreImage( k, x ) ) );
SetHomePcgs( tmp, g );
return tmp;
fi;
r := Length(e);
# get a canonical pcgs for <u>
pcgs := CanonicalPcgsWrtHomePcgs(u);
# If <r> = 2, <g> is abelian, so we can return <g>
if r = 2 then
return g;
fi;
# compute the closure of <pcgs> and <e>[i]
ue := [];
for i in [ 1 .. r ] do
ue[i] := SumPcgs( g, e[i], pcgs );
od;
# begin with <g>/<e>[2], in this factorgroup nothing is to be done
s := e[1] mod e[2];
Info( InfoPcNormalizer, 1, "skipping level 1 of ", r );
Info( InfoPcNormalizer, 1, "skipping level 2 of ", r );
# start with <g>/<e>[3] because <g>/<e>[2] is abelian
for i in [ 3 .. r ] do
# <s> = Normalizer( <G>/<E>[i-1], <pcgs> )
#
# The first step looks like ( U = <pcgs> )
#
# S
# \
# \
# U Ei-1
# \ /
# \ /
# Ui-1
# \
# \
# Ei
#
# Now get the complete preimage of <s> in <g>/<e>[i] and start the
# whole computation for that factorgroup.
s := NumeratorOfModuloPcgs(s) mod e[i];
Info( InfoPcNormalizer, 1, "reached level ", i, " of ", r );
Info( InfoPcNormalizer, 4, "normalizer: ", AsList(s) );
Info( InfoPcNormalizer, 4, "subgroup: ", AsList(ue[i]) );
Info( InfoPcNormalizer, 5, "modulo: ", AsList(e[i]) );
# keep the old stabilizer for an assert later
st := s;
# if <ue>[i] is trivial we can skip this step
ei_1 := e[i-1] mod e[i];
if Length(ue[i]) = Length(e[i]) then
Info( InfoPcNormalizer, 2, "<ue>[", i, "] is trivial" );
Assert( 1, IsNormal(GroupOfPcgs(st),GroupOfPcgs(ue[i])) );
# if <e>[i-1] is a subgroup of <ue>[i] we can skip this step
elif ForAll( ei_1, x -> SiftedPcElement(ue[i],x) = id ) then
Info( InfoPcNormalizer, 2, "<e>[",i,"] > <ue>[",i-1,"]" );
Assert( 1, IsNormal(GroupOfPcgs(st),GroupOfPcgs(ue[i])) );
# now do some real work
else
# remember the prime of the current section for later
pi_1 := RelativeOrderOfPcElement( g, ei_1[1] );
# get the first section
ui_1 := NormalIntersectionPcgs( g, e[i-1], ue[i] );
# if the factor is trivial do nothing
if Length(ui_1) = Length(e[i]) then
Info( InfoPcNormalizer, 2,
"<ue>[",i,"] /\\ <e>[",i-1,"] is trivial" );
# if <f4> is true, use linear operations
elif f4 then
Info( InfoPcNormalizer, 2, "<ue>[", i, "] /\\ <e>[", i-1,
"] using linear operation" );
s := PCGS_NORMALIZER_LINEAR( g, s, ui_1, ei_1 );
# otherwise use a normal stabilizer
else
Info( InfoPcNormalizer, 2, "<ue>[", i, "] /\\ <e>[", i-1,
"] using orbit" );
s := PCGS_NORMALIZER( g, s, ui_1, e[i] );
fi;
# check the stabilizer
Assert( 3, Stabilizer( GroupOfPcgs(st), GroupOfPcgs(ui_1),
function(U,g) return U^g;end)
= GroupOfPcgs(s) );
# now <ui_1> must be stabilized by <s>
st := s;
Assert( 1, IsNormal(GroupOfPcgs(st),GroupOfPcgs(ui_1)) );
# find <ue>[i]/\<E>[j] which is larger then <ue>[i]/\<E>[i-1]
j := i-2;
uj := NormalIntersectionPcgs( g, e[j], ue[i] );
k := i-1;
uk := ui_1;
while 0 < j and Length(uj) = Length(ui_1) do
Info( InfoPcNormalizer, 2, "<ue>[",i,"] /\\ <e>[", j,
"] = <ue>[", i, "] /\\ e[", k, "]" );
k := j;
uk := uj;
j := j - 1;
if 0 < j then
uj := NormalIntersectionPcgs( g, e[j], ue[i] );
fi;
od;
# The next step for <s> = Normalizer( <uk> ) is
#
# S
# \ Ej
# \ / \
# U ** \
# \ / \ Ek
# \ / \ / \
# Uj ** \
# \ / \ Ei-1
# \ / \ /
# Uk Si-1
# \ /
# \ /
# Ui-1
# \
# \
# Ei
#
# If <j> = 0 or <s> and <u> have the same <E>[i-1] intersection
# we are finished with this step.
si_1 := NormalIntersectionPcgs(
g,
e[i-1],
NumeratorOfModuloPcgs(s) )
mod e[i];
while 0<j and not ForAll(si_1,x ->SiftedPcElement(ui_1,x)=id) do
# this only works for subseries <e>
tmp := First( e[j], x -> not x in e[j+1] );
pj := RelativeOrderOfPcElement( g, tmp );
# cobounds
if ( pj = pi_1 and f1 ) or ( pj <> pi_1 and f2 ) then
Info( InfoPcNormalizer, 2, "<ue>[", i, "] /\\ <e>[", j,
"] using cobounds" );
s := PCGS_NORMALIZER_COBOUNDS( g, s, si_1, uj, uk );
# glasby
elif pj <> pi_1 and f3 then
Info( InfoPcNormalizer, 2, "<ue>[", i, "] /\\ <e>[", j,
"] using Glasby" );
s := PCGS_NORMALIZER_GLASBY( g, s, si_1, uj, uk );
# orbit
else
Info( InfoPcNormalizer, 2, "<ue>[", i, "] /\\ <e>[", j,
"] using orbit" );
s := PCGS_NORMALIZER( g, s, uj, uk );
fi;
# check the stabilizer
Assert( 3, Stabilizer( GroupOfPcgs(st), GroupOfPcgs(uj),
function(U,g) return U^g;end)
= GroupOfPcgs(s) );
# now <uj> must be stabilized by <s>
st := s;
Assert( 1, IsNormal(GroupOfPcgs(st),GroupOfPcgs(uj)) );
# find the next non-trivial intersection
k := j;
uk := uj;
while 0 < j and Length(uj) = Length(uk) do
if k <> j then
Info( InfoPcNormalizer, 2, "<ue>[", i, "] /\\ <e>[",
j, "] = <ue>[", i, "] /\\ e[", k, "]" );
fi;
k := j;
uk := uj;
j := j - 1;
if 0 < j then
uj := NormalIntersectionPcgs( g, e[j], ue[i] );
fi;
od;
# Now we know our new <S>, if <j>-1 is still nonzero, compute
# the intersection in order to see, if we are finished.
if 0 < j then
si_1 := NormalIntersectionPcgs(
g,
e[i-1],
NumeratorOfModuloPcgs(s) )
mod e[i];
fi;
od;
fi;
od;
Assert( 1, IsNormal( GroupOfPcgs(s), u ) );
if Length(s) = Length(pcgs) then
return pcgs;
else
tmp := InducedPcgsByPcSequence( g, List( s, x -> x ) );
SetHomePcgs( tmp, g );
return tmp;
fi;
end );
#############################################################################
##
#M NormalizerInHomePcgs( <pc-group> )
##
InstallMethod( NormalizerInHomePcgs,
"for group with home pcgs",
true,
[ IsGroup and HasHomePcgs ],
0,
function( u )
if not IsPrimeOrdersPcgs(HomePcgs(u)) then
TryNextMethod();
fi;
return PcGroup_NormalizerWrtHomePcgs( u, true, false, true, true );
end );
#############################################################################
##
#M Normalizer( <pc-group>, <pc-group> )
##
InstallMethod( NormalizerOp, "for groups with home pcgs", IsIdenticalObj,
[ IsGroup and HasHomePcgs and CanComputeFittingFree, IsGroup and HasHomePcgs ],
1, #better than the next method
function( g, u )
local home, norm, pcgs;
# for small groups use direct calculation
if Size(g) < 1000 or (Size(g)<100000 and Size(g)/Size(u)<500) then
TryNextMethod();
fi;
home := HomePcgs(g);
if home <> HomePcgs(u) then
TryNextMethod();
fi;
# first compute the normalizer with respect to the home
pcgs := NormalizerInHomePcgs(u);
norm := SubgroupByPcgs( g, pcgs );
# then the intersection
norm := Intersection( g, norm );
# and return
return norm;
end );
InstallMethod( NormalizerOp, "slightly better orbit algorithm for pc groups",
IsIdenticalObj, [ IsGroup and HasHomePcgs, IsGroup and HasHomePcgs ], 0,
function( G, U )
local N,h,opfun;
h:=HomePcgs(G);
opfun:=function(p,g)
return CanonicalPcgs(InducedPcgsByGeneratorsNC(h,List(p,i->i^g)));
end;
N:=Stabilizer(G,CanonicalPcgs(InducedPcgs(h,U)),opfun);
return N;
end);
[ Verzeichnis aufwärts0.46unsichere Verbindung
Übersetzung europäischer Sprachen durch Browser
]
|