Quellcode-Bibliothek gpfpiso.gi
Interaktion und PortierbarkeitShell
############################################################################# ## ## This file is part of GAP, a system for computational discrete algebra. ## This file's authors include Bettina Eick, Alexander Hulpke. ## ## 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 computing presentations for ## (permutation) groups. ##
############################################################################# ## #M IsomorphismFpGroup( G ) ##
InstallOtherMethod( IsomorphismFpGroup, "supply name", true, [IsGroup], 0, function( G )
return IsomorphismFpGroup( G, "F" ); end );
InstallGlobalFunction( IsomorphismFpGroupByGenerators,function(arg)
local G,gens,nam;
G:=arg[1];
gens:=arg[2]; if Length(arg)>2then
nam:=arg[3]; else
nam:="F"; fi; if not ForAll(gens,i->i in G) or Index(G,SubgroupNC(G,gens))>1then
Error("<gens> must be a generating set for G"); fi;
return IsomorphismFpGroupByGeneratorsNC(G,gens,nam); end);
InstallOtherMethod( IsomorphismFpGroupByCompositionSeries, "supply name", true, [IsGroup], 0, function( G )
return IsomorphismFpGroupByCompositionSeries( G, "F" ); end );
InstallOtherMethod( IsomorphismFpGroupByChiefSeries, "supply name", true, [IsGroup], 0, function( G )
return IsomorphismFpGroupByChiefSeries( G, "F" ); end );
InstallOtherMethod(IsomorphismFpGroup,"for perm groups",true,
[IsPermGroup,IsString],0, function( G,nam ) # test frequent, special cases if (not HasIsSymmetricGroup(G) and IsSymmetricGroup(G)) or
(not HasIsAlternatingGroup(G) and IsAlternatingGroup(G)) then
return IsomorphismFpGroup(G,nam); fi;
return IsomorphismFpGroupByChiefSeries( G, nam ); end );
InstallOtherMethod( IsomorphismFpGroup,"for simple solvable permutation groups",
true,
[IsPermGroup and IsSimpleGroup and IsSolvableGroup,IsString],0, function(G,str)
return IsomorphismFpGroupByPcgs( Pcgs(G), str ); end);
InstallOtherMethod( IsomorphismFpGroup,"for nonabelian simple permutation groups",
true, [IsPermGroup and IsNonabelianSimpleGroup,IsString],0, function(G,str)
local l,iso,fp,stbc,gens; # use the perfect groups library (as far as hand-created)
PerfGrpLoad(Size(G)); if Size(G)<10^6 and IsRecord(PERFRec) and
ValueOption(NO_PRECOMPUTED_DATA_OPTION)<>true and
not Size(G) in PERFRec.notKnown then
Info(InfoPerformance,2,"Using Perfect Groups Library"); # loop over the groups for l in List([1..NrPerfectGroups(Size(G))],
i->PerfectGroup(IsPermGroup,Size(G),i)) do
iso:=IsomorphismGroups(G,l); if iso<>fail then
fp:=IsomorphismFpGroup(l);
iso:=GroupHomomorphismByImagesNC(G,Range(fp),
List(MappingGeneratorsImages(fp)[1],
i->PreImagesRepresentative(iso,i)),
MappingGeneratorsImages(fp)[2]);
SetIsBijective(iso,true);
return iso; fi;
od; fi;
############################################################################# ## #M IsomorphismFpGroupByCompositionSeries( G, str ) ##
InstallOtherMethod( IsomorphismFpGroupByCompositionSeries, "for permutation groups", true,
[IsPermGroup, IsString], 0, function( G, str )
local l, H, gensH, iso, F, gensF, imgsF, relatorsF, free, n, k, N, M,
hom, preiH, c, new, T, gensT, E, gensE, imgsE, relatorsE, rel,
w, t, i, j, series;
if IsSolvableGroup( G ) then
return IsomorphismFpGroupByPcgs( Pcgs(G), str ); fi;
# compute composition series
series := CompositionSeries( G );
l := Length( series );
# set up
H := series[l-1]; # if IsPrime( Size( H ) ) then # gensH := Filtered( GeneratorsOfGroup( H ), # x -> Order(x)=Size(H) ){[1]}; # else # gensH := Set( GeneratorsOfGroup( H ) ); # gensH := Filtered( gensH, x -> x <> One(H) ); # fi;
IsNonabelianSimpleGroup(H); #ensure H knows to be simple, thus the call to # `IsomorphismFpGroup' will not yield an infinite recursion.
IsNaturalAlternatingGroup(H); # We have quite often a factor A_n for # which GAP knows better presentations. Thus this test is worth doing.
iso := IsomorphismFpGroup( H,str );
F := FreeGroupOfFpGroup( Image( iso ) );
gensF := GeneratorsOfGroup( F );
imgsF := MappingGeneratorsImages(iso)[1];
relatorsF := RelatorsOfFpGroup( Image( iso ) );
free := GroupHomomorphismByImagesNC( F, series[l-1], gensF, imgsF );
n := Length( gensF );
# loop over series upwards for k in Reversed( [1..l-2] ) do
# get composition factor
N := series[k];
M := series[k+1]; # do not call `InParent'-- rather safe than sorry.
hom := NaturalHomomorphismByNormalSubgroupNC(N, M );
H := Image( hom ); # if IsPrime( Size( H ) ) then # gensH := Filtered( GeneratorsOfGroup( H ), # x -> Order(x)=Size(H) ){[1]}; # else # gensH := Set( GeneratorsOfGroup( H ) ); # gensH := Filtered( gensH, x -> x <> One(H) ); # fi;
# compute presentation of H
IsNonabelianSimpleGroup(H);
IsNaturalAlternatingGroup(H);
new:=IsomorphismFpGroup(H,"@");
gensH:=List(GeneratorsOfGroup(Image(new)),
i->PreImagesRepresentative(new,i));
preiH := List( gensH, x -> PreImagesRepresentative( hom, x ) );
c := Length( gensH );
T := Image( new );
gensT := GeneratorsOfGroup( FreeGroupOfFpGroup( T ) );
# create new free group
E := FreeGroup( n+c, str );
gensE := GeneratorsOfGroup( E );
imgsE := Concatenation( preiH, imgsF );
relatorsE := [];
# modify presentation of H for rel in RelatorsOfFpGroup( T ) do
w := MappedWord( rel, gensT, gensE{[1..c]} );
t := MappedWord( rel, gensT, imgsE{[1..c]} ); if not t = One( G ) then
t := PreImagesRepresentative( free, t );
t := MappedWord( t, gensF, gensE{[c+1..n+c]} ); else
t := One( E ); fi;
Add( relatorsE, w/t );
od;
# add operation of T on F for i in [1..c] do for j in [1..n] do
w := Comm( gensE[c+j], gensE[i] );
t := Comm( imgsE[c+j], imgsE[i] ); if not t = One( G ) then
t := PreImagesRepresentative( free, t );
t := MappedWord( t, gensF, gensE{[c+1..n+c]} ); else
t := One( E ); fi;
Add( relatorsE, w/t );
od;
od;
# append relators of F for rel in relatorsF do
w := MappedWord( rel, gensF, gensE{[c+1..c+n]} );
Add( relatorsE, w );
od;
# iterate
F := E;
gensF := gensE;
imgsF := imgsE;
relatorsF := relatorsE;
free := GroupHomomorphismByImagesNC( F, N, gensF, imgsF );
n := n + c;
od;
# set up
F := F / relatorsF;
gensF := GeneratorsOfGroup( F ); if HasSize(G) then
SetSize(F,Size(G)); fi;
iso := GroupHomomorphismByImagesNC( G, F, imgsF, gensF );
SetIsBijective( iso, true );
SetKernelOfMultiplicativeGeneralMapping( iso, TrivialSubgroup( G ) );
ProcessEpimorphismToNewFpGroup(iso);
return iso; end );
abelianlimit:=ValueOption("abelianlimit"); if abelianlimit=fail then
abelianlimit:=infinity; fi;
if Size(g)=1then # often occurs in induction base
return
GroupHomomorphismByFunction(g,TRIVIAL_FP_GROUP,x->One(TRIVIAL_FP_GROUP),x->One(g):noassert); elif g=N then # often occurs in induction base
return GroupHomomorphismByImagesNC(g,TRIVIAL_FP_GROUP,GeneratorsOfGroup(g),
List(GeneratorsOfGroup(g),x->One(TRIVIAL_FP_GROUP)):noassert); fi;
if ValueOption("rewrite")=true then # try to go through radical (image) and pick generators split in radical factor
rad:=ClosureGroup(SolvableRadical(g),N);
ser:=[];
gens:=[]; if Size(rad)<Size(g) then
hom:=NaturalHomomorphismByNormalSubgroupNC(g,rad);
f:=Image(hom);
ser:=ShallowCopy(DirectFactorsFittingFreeSocle(f));
gens:=Concatenation(List(ser,SmallGeneratingSet));
j:=SubgroupNC(f,gens); for i in GeneratorsOfGroup(f) do if not i in j then
Add(gens,i);
j:=ClosureSubgroupNC(j,i); fi;
od; # build series for i in [Length(ser)-1,Length(ser)-2..1] do
ser[i]:=ClosureGroup(ser[i+1],ser[i]);
od; if Size(ser[1])<Size(f) then
ser:=ChiefSeriesThrough(f,ser);
gens:=Union(gens,Union(List(ser,SmallGeneratingSet))); fi; if f<>g then
gens:=List(gens,x->PreImagesRepresentative(hom,x));
ser:=List(ser,x->PreImage(hom,x)); fi; # change generators to make split
ser:=List(ser,x->ClosureGroup(rad,Filtered(gens,y->y in x))); else
rad:=g; fi;
if Length(ser)=0 or Size(Last(ser))>Size(rad) then Add(ser,rad);fi;
if Size(rad)>1then if HasChiefSeries(g) and N in ChiefSeries(g) and rad in ChiefSeries(g) then
f:=Filtered(ChiefSeries(g),x->IsSubset(rad,x)); elif IsTrivial(N) then if rad=g then
f:=ChiefSeries(g); else
f:=ChiefSeriesUnderAction(g,rad); fi; else
f:=ChiefSeriesThrough(g,[rad,N]); fi;
Append(ser,Filtered(f,x->Size(x)<Size(rad))); fi; elif IsTrivial(N) then
ser:=ChiefSeries(g); else if HasChiefSeries(g) and N in ChiefSeries(g) then
ser:=ChiefSeries(g); else
ser:=ChiefSeriesThrough(g,[N]); fi; fi;
if Size(N)>1then
ser:=Filtered(ser,i->IsSubset(i,N)); fi;
if IsSolvableGroup(g) then
fampcgs:=SpecialPcgs(g); else
fampcgs:=fail; fi;
ab:=[];
homs:=[];
gens:=[];
idx:=[];
abpow:=[]; # store powers for large order abelian for i in [2..Length(ser)] do
start:=Length(gens)+1; if HasAbelianFactorGroup(ser[i-1],ser[i]) then
ab[i-1]:=true; if fampcgs<>fail then
pcgs:=CanonicalPcgs(InducedPcgs(fampcgs,ser[i-1])) mod
CanonicalPcgs(InducedPcgs(fampcgs,ser[i])); else
pcgs:=ModuloPcgs(ser[i-1],ser[i]); fi;
homs[i-1]:=pcgs;
Append(gens,pcgs);
f:=pcgs;
j:=RelativeOrders(pcgs)[1];
abpow[i-1]:=[]; if abelianlimit<>infinity then # split up evenly
k:=LogInt(j-1,abelianlimit)+1; # ensure rounded up
locallim:=RootInt(j-1,k)+1; # ensure rounded up
while j>locallim do
k:=Minimum(locallim,RootInt(j,2));
Add(abpow[i-1],k);
f:=List(f,x->x^k);
Append(gens,f);
j:=QuoInt(j,k);
od; fi;
else
ab[i-1]:=false;
hom:=NaturalHomomorphismByNormalSubgroup(ser[i-1],ser[i]:noassert);
IsOne(hom);
f:=Image(hom); # knowing simplicity makes it easy to test whether a map is faithful if IsNonabelianSimpleGroup(f) then if DataAboutSimpleGroup(f).idSimple.series="A" and
not IsNaturalAlternatingGroup(f) then # force natural alternating
hom:=hom*IsomorphismGroups(f,
AlternatingGroup(DataAboutSimpleGroup(f).idSimple.parameter)); elif IsPermGroup(f) and
NrMovedPoints(f)>SufficientlySmallDegreeSimpleGroupOrder(Size(f)) then
hom:=hom*SmallerDegreePermutationRepresentation(f:cheap); fi; elif IsPermGroup(f) then
hom:=hom*SmallerDegreePermutationRepresentation(f:cheap); fi;
# the range is elementary. Use this for the fp group isomorphism
f:=Image(hom); # calculate automorphisms of f induced by G
fgens:=GeneratorsOfGroup(f);
auts:=List(GeneratorsOfGroup(g),i->
GroupHomomorphismByImagesNC(f,f,fgens,
List(fgens,j->Image(hom,PreImagesRepresentative(hom,j)^i)):noassert)); for j in auts do
SetIsBijective(j,true);
od; # get the minimal normal subgroups, together with isomorphisms
sf:=CompositionSeries(f);
sf:=sf[Length(sf)-1];
orb:=[sf];
tra:=[IdentityMapping(f)];
j:=1; while j<=Length(orb) do for k in auts do
a:=Image(k,orb[j]); if not a in orb then
Add(orb,a);
Add(tra,tra[j]*k); fi;
od;
j:=j+1;
od;
# we know sf is simple
SetIsNonabelianSimpleGroup(sf,true);
IsNaturalAlternatingGroup(sf); if ValueOption("rewrite")=true then
a:=IsomorphismFpGroupForRewriting(sf:noassert); else
a:=IsomorphismFpGroup(sf:noassert); fi;
ad:=List(GeneratorsOfGroup(Range(a)),i->PreImagesRepresentative(a,i));
lad:=Length(ad);
n:=Length(orb); if n=1 and ValueOption("rewrite")=true then
fgens:=ad; else if ValueOption("rewrite")=true then
Info(InfoPerformance,1, "Rewriting system preservation for direct product not yet written"); fi;
fg:=FreeGroup(Length(ad)*n,"@");
free:=GeneratorsOfGroup(fg);
rels:=[];
fgens:=[]; for j in [1..n] do
Append(fgens,List(ad,x->Image(tra[j],x))); # translate relators for k in RelatorsOfFpGroup(Range(a)) do
Add(rels,MappedWord(k,FreeGeneratorsOfFpGroup(Range(a)),
free{[(j-1)*lad+1..j*lad]}));
od; # commutators with older gens for k in [j+1..n] do for l in [1..Length(ad)] do for m in [1..Length(ad)] do
Add(rels,Comm(free[(k-1)*lad+l],free[(j-1)*lad+m]));
od;
od;
od;
od;
# here we really want a composed homomorphism, to avoid extra work for # a new stabilizer chain if not IsOne(hom) then
hom:=CompositionMapping2General(a,hom); else
hom:=a; fi;
homs[i-1]:=hom; fi;
Add(idx,[start..Length(gens)]);
od;
for i in [2..Length(ser)] do
still:=i<Length(ser);
lgens:=gens{idx[i-1]};
ngens:=free{idx[i-1]}; # new generators on this level
nrels:=[];
nvals:=[]; if ab[i-1] then
pcgs:=homs[i-1];
needgens:=Length(pcgs);
p:=RelativeOrders(pcgs)[1]; # define function in function to preserve local variables
dodecomp:=function(ngens,pcgs,abpow)
local l;
l:=Length(pcgs);
return function(elm)
local e,i,j,q;
e:=ShallowCopy(ExponentsOfPcElement(pcgs,elm)); for i in [1..Length(abpow)] do for j in [1..l] do # reduce entry so far
q:=QuotientRemainder(e[l*(i-1)+j],abpow[i]);
e[l*(i-1)+j]:=q[2];
e[l*i+j]:=q[1];
od;
od;
return LinearCombinationPcgs(ngens,e); end; end;
decomp:=dodecomp(ngens,pcgs,abpow[i-1]); for j in [1..Length(pcgs)] do
Add(nrels,ngens[j]^p); if still then
Add(nvals,pcgs[j]^p); fi; for k in [1..j-1] do
Add(nrels,Comm(ngens[j],ngens[k])); if still then
Add(nvals,Comm(pcgs[j],pcgs[k])); fi;
od;
od;
# generator power relations if Length(abpow[i-1])>0then for k in [1..Length(abpow[i-1])] do for j in [1..Length(pcgs)] do
Add(nrels,ngens[Length(pcgs)*(k-1)+j]^abpow[i-1][k]
/ngens[Length(pcgs)*k+j]); if still then
Add(nvals,One(pcgs[1])); # new generator is just shorthand for # power, so no tail to consider fi;
od;
od;
fi;
else
hom:=homs[i-1];
hogens:=FreeGeneratorsOfFpGroup(Range(hom));
needgens:=Length(hogens);
dodecomp:=function(ngens,hogens,hom)
return elm->
MappedWord(UnderlyingElement(Image(hom,elm)),
hogens,ngens); end;
decomp:=dodecomp(ngens,hogens,hom); for j in RelatorsOfFpGroup(Range(hom)) do
a:=MappedWord(j,hogens,ngens);
Add(nrels,a); if still then
Add(nvals,MappedWord(j,hogens,lgens)); fi;
od; fi;
Add(dec,decomp); # change relators by cofactors for j in [1..Length(rels)] do
a:=decomp(vals[j]);
rels[j]:=rels[j]/a; if still then
vals[j]:=vals[j]/MappedWord(a,ngens,lgens); fi;
od; # action relators for j in [1..idx[i-1][1]-1] do for k in [1..needgens] do
a:=lgens[k]^gens[j];
ad:=decomp(a);
Add(rels,ngens[k]^free[j]/ad); if still then
Add(vals,a/MappedWord(ad,ngens,lgens)); fi;
od;
od; # new level relators
Append(rels,nrels);
Append(vals,nvals);
od;
Assert(1,ForAll(rels,i->MappedWord(i,GeneratorsOfGroup(f),gens) in N));
fp:=f/rels;
di:=rec(gens:=gens,fp:=fp,idx:=idx,dec:=dec,source:=g,homs:=homs,
abpow:=abpow); if IsTrivial(N) then
hom:=GroupHomomorphismByImagesNC(g,fp,gens,GeneratorsOfGroup(fp):noassert);
SetIsBijective(hom,true); else
hom:=GroupHomomorphismByImagesNC(g,fp,
Concatenation(gens,GeneratorsOfGroup(N)),
Concatenation(GeneratorsOfGroup(fp),
List(GeneratorsOfGroup(N),i->One(fp))):noassert);
SetIsSurjective(hom,true);
SetKernelOfMultiplicativeGeneralMapping(hom,N); fi;
BindGlobal("DecompElmHomChiefSer",function(di,elm)
local f, w, a, i;
f:=FreeGroupOfFpGroup(di.fp);
w:=One(f); for i in di.dec do
a:=i(elm);
w:=a*w;
elm:=elm/MappedWord(a,GeneratorsOfGroup(f),di.gens);
od;
return ElementOfFpGroup(ElementsFamily(FamilyObj(di.fp)),w); end);
InstallGlobalFunction(LiftFactorFpHom, function(hom,G,N,mnsf)
local fpq, qgens, qreps, fpqg, rels, pcgs, p, f, qimg, idx, nimg, decomp,
ngen, fp, hom2, di, source, dih, dec, i, j;
fpq:=Range(hom);
qgens:=GeneratorsOfGroup(fpq);
qreps:=List(qgens,i->PreImagesRepresentative(hom,i));
fpqg:=FreeGeneratorsOfFpGroup(fpq);
rels:=[]; if IsModuloPcgs(mnsf) then
pcgs:=mnsf;
p:=RelativeOrders(pcgs)[1];
f:=FreeGroup(Length(fpqg)+Length(pcgs));
qimg:=GeneratorsOfGroup(f){[1..Length(fpqg)]};
idx:=[Length(fpqg)+1..Length(fpqg)+Length(pcgs)];
nimg:=GeneratorsOfGroup(f){idx};
decomp:=function(elm)
return LinearCombinationPcgs(nimg,ExponentsOfPcElement(pcgs,elm)); end; # n-relators for i in [1..Length(pcgs)] do
Add(rels,nimg[i]^p); for j in [1..i-1] do
Add(rels,Comm(nimg[i],nimg[j]));
od;
od;
elif IsRecord(mnsf) then # mnsf is record with components: # pcgs: generator list for pcgs # p: prime # decomp: Exponents for element of pcgs
pcgs:=mnsf.pcgs;
p:=mnsf.prime;
f:=FreeGroup(Length(fpqg)+Length(pcgs));
qimg:=GeneratorsOfGroup(f){[1..Length(fpqg)]};
idx:=[Length(fpqg)+1..Length(fpqg)+Length(pcgs)];
nimg:=GeneratorsOfGroup(f){idx};
decomp:=function(elm)
local coeff;
coeff:=mnsf.decomp(elm); if LinearCombinationPcgs(pcgs,coeff)<>elm then
Error("decomperror"); fi;
return LinearCombinationPcgs(nimg,mnsf.decomp(elm)); end; # n-relators for i in [1..Length(pcgs)] do
Add(rels,nimg[i]^p); for j in [1..i-1] do
Add(rels,Comm(nimg[i],nimg[j]));
od;
od;
else # nonabelian
p:=Range(mnsf);
ngen:=FreeGeneratorsOfFpGroup(p); # This is not really a pcgs, but treated as layer generators the same # way, thus use the same variable name
pcgs:=List(GeneratorsOfGroup(p),i->PreImagesRepresentative(mnsf,i));
f:=FreeGroup(Length(fpqg)+Length(pcgs));
qimg:=GeneratorsOfGroup(f){[1..Length(fpqg)]};
idx:=[Length(fpqg)+1..Length(fpqg)+Length(pcgs)];
nimg:=GeneratorsOfGroup(f){idx};
for i in RelatorsOfFpGroup(p) do
Add(rels,MappedWord(i,ngen,nimg));
od;
fi;
# action on n for i in [1..Length(pcgs)] do for j in [1..Length(qgens)] do
Add(rels,nimg[i]^qimg[j]/
decomp(pcgs[i]^qreps[j]));
od;
od;
# lift old relators with cofactors for i in RelatorsOfFpGroup(fpq) do
Add(rels,MappedWord(i,fpqg,qimg)/decomp(MappedWord(i,fpqg,qreps)));
od;
fp:=f/rels; if HasGeneratorsOfGroup(N) then
di:=GeneratorsOfGroup(N); else
di:=[]; fi;
hom2:=GroupHomomorphismByImagesNC(G,fp,
Concatenation(Concatenation(qreps,pcgs),di),
Concatenation(GeneratorsOfGroup(fp),
List(di,x->One(fp))):noassert);
# build decompositioninfo
di:=rec(gens:=Concatenation(qreps,pcgs),fp:=fp,source:=G); if IsBound(hom!.decompinfo) then
dih:=hom!.decompinfo; if dih.source=G then
di.idx:=Concatenation(dih.idx,[idx]);
dec:=[]; for i in dih.dec do
Add(dec,elm->MappedWord(i(elm),fpqg,qimg));
od;
Add(dec,decomp);
di.dec:=dec; fi; fi;
if not IsBound(di.dec) then
di.idx:=[[1..Length(fpqg)],idx];
di.dec:=[elm->MappedWord(Image(hom,elm),fpqg,qimg),decomp]; fi;
SetIsSurjective(hom2,true); if N<>false then
SetKernelOfMultiplicativeGeneralMapping(hom2,N); fi;
return hom2; end);
InstallGlobalFunction(ComplementFactorFpHom, function(h,m,n,k,ggens,cgens)
local di, hom; if IsBound(h!.decompinfo) then
di:=ShallowCopy(h!.decompinfo); if di.gens=ggens or cgens=ggens then
di.gens:=cgens;
di.source:=k; # this homomorphism is just to store decomposition information and is # not declared total, so an assertion test will fail
hom:=GroupHomomorphismByImagesNC(k,di.fp,cgens,GeneratorsOfGroup(di.fp):noassert);
hom!.decompinfo:=MakeImmutable(di); if HasIsSurjective(h) and IsSurjective(h)
and HasKernelOfMultiplicativeGeneralMapping(h)
and m=KernelOfMultiplicativeGeneralMapping(h) then
SetIsSurjective(hom,true);
SetKernelOfMultiplicativeGeneralMapping(hom,n); fi;
if ggens=MappingGeneratorsImages(h)[1] then # can we simply translate a map on generators?
hom:=GroupHomomorphismByImagesNC(k,Range(h),
Concatenation(GeneratorsOfGroup(n),cgens),
Concatenation(List(GeneratorsOfGroup(n),i->One(Range(h))),
MappingGeneratorsImages(h)[2]));
return hom; fi; if IsBound(h!.decompinfo) then
Error("do not know yet how to lift to complement"); fi;
hom:=GroupHomomorphismByImagesNC(k,Range(h),
Concatenation(GeneratorsOfGroup(n),cgens),
Concatenation(List(GeneratorsOfGroup(n),i->One(Range(h))),
List(ggens,i->Image(h,i))));
return hom; end);
# check for trivial cases
ngens := Length( gens ); if ngens = 0then
S := FreeGroup( 0 ); elif ngens = 1then
F := FreeGroup( 1 );
gensF := GeneratorsOfGroup( F );
relators := [ gensF[1]^Size( G ) ];
S := F/relators; # check options else
F := FreeGroup( ngens, str );
gensF := GeneratorsOfGroup( F );
method := ValueOption( "method" ); if not IsString( method ) and IsList( method ) and
Length( method ) = 2 and method[1] = "regular"then if not IsInt( method[2] ) then
Info( InfoFpGroup + InfoWarning, 1, "Warning: function ", "IsomorphismFpGroupByGeneratorsNC encountered an" );
Info( InfoFpGroup + InfoWarning, 1, " non-integer bound ", "for method \"regular\"; the option has been ignored" ); elif Size( G ) <= method[2] then
method := "regular"; fi; fi; if method = "fast"then # use the old method
hom := GroupHomomorphismByImagesNC( G, F, gens, gensF );
relators := CoKernelGensPermHom( hom ); elif method = "regular" and not IsRegular( G ) then # construct a regular permutation representation of G and then # apply the default method to it
reg := RegularActionHomomorphism( G );
R := Image( reg );
gensR := List( gens, gen -> gen^reg );
hom := GroupHomomorphismByImagesNC( R, F, gensR, gensF );
relators := RelatorsPermGroupHom( hom, gensR ); else # apply the default method to G
hom := GroupHomomorphismByImagesNC( G, F, gens, gensF );
relators := RelatorsPermGroupHom( hom, gens ); fi;
S := F/relators; fi;
gensS := GeneratorsOfGroup( S );
iso := GroupHomomorphismByImagesNC( G, S, gens, gensS ); if HasSize(G) then
SetSize(S,Size(G)); fi;
SetIsSurjective( iso, true );
SetIsInjective( iso, true );
SetKernelOfMultiplicativeGeneralMapping( iso, TrivialSubgroup( G ));
info := ValueOption( "infolevel" ); if info <> 2then
info := 1; fi; if ngens = 0then
Info( InfoFpGroup, info, "the image fp group is trivial" ); else
Info( InfoFpGroup, info, "the image group has ", ngens, " gens and ",
Length( relators ), " rels of total length ",
Sum( List( relators, rel -> Length( rel ) ) ) ); fi;
ProcessEpimorphismToNewFpGroup(iso);
return iso; end );
############################################################################# ## #M IsomorphismFpGroupByGeneratorsNC( G, gens, str ) ##
InstallMethod( IsomorphismFpGroupByGeneratorsNC, "via cokernel", IsFamFamX,
[IsGroup, IsList, IsString], 0, function( G, gens, str )
local F, hom, rels, H, gensH, iso;
F := FreeGroup( Length(gens), str );
hom := GroupGeneralMappingByImagesNC( G, F, gens, GeneratorsOfGroup(F) );
rels := GeneratorsOfGroup( CoKernelOfMultiplicativeGeneralMapping( hom ) );
H := F /rels;
gensH := GeneratorsOfGroup( H );
iso := GroupHomomorphismByImagesNC( G, H, gens, gensH ); if HasSize(G) then
SetSize(H,Size(G)); fi;
SetIsBijective( iso, true );
SetKernelOfMultiplicativeGeneralMapping( iso, TrivialSubgroup(G) );
ProcessEpimorphismToNewFpGroup(iso);
return iso; end );
InstallMethod( IsomorphismFpGroupByGeneratorsNC, "for trivial group",
[ IsGroup, IsList and IsEmpty, IsString ], function( G, emptygens, name )
local hom;
if not IsTrivial( G ) then
Error( "<emptygens> does not generate <G>" ); fi;
hom:= GroupHomomorphismByImagesNC( G, FreeGroup( 0 ), [], [] );
SetIsBijective( hom, true );
return hom; end );
############################################################################# ## #M IsomorphismFpGroupBySubnormalSeries( G, series, str ) ##
InstallMethod( IsomorphismFpGroupBySubnormalSeries, "for groups",
true,
[IsPermGroup, IsList, IsString], 0, function( G, series, str )
local l, H, gensH, iso, F, gensF, imgsF, relatorsF, free, n, k, N, M,
hom, preiH, c, new, T, gensT, E, gensE, imgsE, relatorsE, rel,
w, t, i, j,known;
known:=ValueOption("knownfactor"); # set up with smallest subgroup of series
l := Length( series );
H := series[l-1];
gensH := Set( GeneratorsOfGroup( H ) );
gensH := Filtered( gensH, x -> x <> One(H) );
iso := IsomorphismFpGroupByGeneratorsNC( H, gensH, str );
F := FreeGroupOfFpGroup( Image( iso ) );
gensF := GeneratorsOfGroup( F );
imgsF := MappingGeneratorsImages(iso)[1];
relatorsF := RelatorsOfFpGroup( Image( iso ) );
free := GroupHomomorphismByImagesNC( F, series[l-1], gensF, imgsF );
n := Length( gensF );
# loop over series upwards for k in Reversed( [1..l-2] ) do
N := series[k];
M := series[k+1]; if known<>fail and M=KernelOfMultiplicativeGeneralMapping(known) then
hom:=known; else # get composition factor
hom := NaturalHomomorphismByNormalSubgroupNC( N, M ); fi;
H := Image( hom );
gensH := GeneratorsOfGroup( H );
gensH := Filtered( gensH, x -> x <> One(H) );
preiH := List( gensH, x -> PreImagesRepresentative( hom, x ) );
c := Length( gensH );
# compute presentation of H if IsFpGroup(H) then
new:=IdentityMapping(H); else
new := IsomorphismFpGroupByGeneratorsNC( H, gensH, "g" ); fi;
T := Image( new );
gensT := GeneratorsOfGroup( FreeGroupOfFpGroup( T ) );
# create new free group
E := FreeGroup( n+c, str );
gensE := GeneratorsOfGroup( E );
imgsE := Concatenation( preiH, imgsF );
relatorsE := [];
# modify presentation of H for rel in RelatorsOfFpGroup( T ) do
w := MappedWord( rel, gensT, gensE{[1..c]} );
t := MappedWord( rel, gensT, imgsE{[1..c]} ); if not t = One( G ) then
t := PreImagesRepresentative( free, t );
t := MappedWord( t, gensF, gensE{[c+1..n+c]} ); else
t := One( E ); fi;
Add( relatorsE, w/t );
od;
# add operation of T on F for i in [1..c] do for j in [1..n] do
w := Comm( gensE[c+j], gensE[i] );
t := Comm( imgsE[c+j], imgsE[i] ); if not t = One( G ) then
t := PreImagesRepresentative( free, t );
t := MappedWord( t, gensF, gensE{[c+1..n+c]} ); else
t := One( E ); fi;
Add( relatorsE, w/t );
od;
od;
# append relators of F for rel in relatorsF do
w := MappedWord( rel, gensF, gensE{[c+1..c+n]} );
Add( relatorsE, w );
od;
# iterate
F := E;
gensF := gensE;
imgsF := imgsE;
relatorsF := relatorsE;
free := GroupHomomorphismByImagesNC( F, N, gensF, imgsF );
n := n + c;
od;
# set up
F := F / relatorsF;
gensF := GeneratorsOfGroup( F ); if HasSize(G) then
SetSize(F,Size(G)); fi;
iso := GroupHomomorphismByImagesNC( G, F, imgsF, gensF );
SetIsBijective( iso, true );
SetKernelOfMultiplicativeGeneralMapping( iso, TrivialSubgroup( G ) );
ProcessEpimorphismToNewFpGroup(iso);
return iso; end);
InstallOtherMethod(IsomorphismFpGroupForRewriting, "generic, deal with large element orders", true,
[IsGroup],0, function(G)
local hom;
IsSimpleGroup(G);
hom:=IsomorphismFpGroup(G:abelianlimit:=10);
return hom; end);
InstallGlobalFunction(MakeFpGroupToMonoidHomType1,function(fp,m)
local fam,mfam,fpfam,mfpfam,hom;
fam:=FamilyObj(UnderlyingElement(One(fp)));
mfam:=FamilyObj(UnderlyingElement(One(m)));
fpfam:=FamilyObj(One(fp));
mfpfam:=FamilyObj(One(m));
hom:=MagmaIsomorphismByFunctionsNC(fp,m, function(w)
local l,i;
l:=[]; for i in LetterRepAssocWord(UnderlyingElement(w)) do if i>0then Add(l,2*i-1); else Add(l,-2*i);fi;
od;
return ElementOfFpMonoid(mfpfam,AssocWordByLetterRep(mfam,l)); end, function(w)
local g,i,x;
g:=[]; for i in LetterRepAssocWord(UnderlyingElement(w)) do if IsOddInt(i) then x:=(i+1)/2; else x:=-i/2;fi; # word must be freely cancelled if Length(g)>0 and x=-Last(g) then
Remove(g); else Add(g,x); fi;
od;
return ElementOfFpGroup(fpfam,AssocWordByLetterRep(fam,g)); end);
# type 0 is inverses first
hom!.type:=1; if not HasIsomorphismFpMonoid(fp) then
SetIsomorphismFpMonoid(fp,hom); fi;
return hom; end);
# return isomorphism G-fp and fp->mon, such that presentation of monoid is # confluent (wrt wreath order). Returns record with fphom,monhom,ordering
InstallMethod(ConfluentMonoidPresentationForGroup,"generic",
[IsGroup and IsFinite], function(G)
local iso,fp,dec,homs,mos,i,j,ffp,imo,m,k,gens,fm,mgens,rules,
loff,off,monreps,left,right,fmgens,r,diff,monreal,nums,reduce,hom,dept,
lode,lrules,rulet,addrule;
IsSimpleGroup(G); if IsSymmetricGroup(G) then
i:=SymmetricGroup(SymmetricDegree(G));
iso:=CheapIsomSymAlt(G,i)*IsomorphismFpGroup(i);
fp:=Range(iso);
hom:=IsomorphismFpMonoid(fp);
m:=Range(hom);
fm:=FreeMonoidOfFpMonoid(m);
k:=KnuthBendixRewritingSystem(m);
MakeConfluent(k);
rules:=Rules(k);
dept:=fail; else
iso:=IsomorphismFpGroupByChiefSeries(G:rewrite);
fmgens:=[];
mgens:=[]; for i in gens do
Add(fmgens,i);
Add(fmgens,i^-1);
Add(mgens,String(i));
Add(mgens,String(i^-1));
od;
nums:=List(fmgens,x->LetterRepAssocWord(UnderlyingElement(x))[1]);
fm:=FreeMonoid(mgens);
mgens:=GeneratorsOfMonoid(fm);
rules:=[];
lrules:=[];
rulet:=List(mgens,x->[]); # rules involving a particular letter
addrule:=function(rule)
local i,p;
Add(rules,rule);
rule:=List(rule,LetterRepAssocWord);
Add(lrules,rule);
p:=Length(lrules); for i in Set(rule[1]) do
AddSet(rulet[i],p);
od; end;
reduce:=function(w)
local red,i,p,pool,wn;
w:=LetterRepAssocWord(w);
repeat
i:=1;
pool:=Union(rulet{Set(w)});
red:=false; while i<=Length(pool) and red=false do
p:=fail; if Length(w)>=Length(lrules[pool[i]][1]) then
p:=PositionSublist(w,lrules[pool[i]][1]); fi; if p<>fail then
wn:=Concatenation(w{[1..p-1]},lrules[pool[i]][2],
w{[p+Length(lrules[pool[i]][1])..Length(w)]}); #if Length(wn)>Length(w) then Error("HOH");fi;
w:=wn; # w:=Concatenation(w{[1..p-1]},lrules[pool[i]][2], # w{[p+Length(lrules[pool[i]][1])..Length(w)]});
red:=true; else
i:=i+1; fi;
od;
until red=false;
return AssocWordByLetterRep(FamilyObj(One(fm)),w); end;
homs:=ShallowCopy(dec.homs);
mos:=[];
off:=Length(mgens);
dept:=[];
lode:=[]; # go up so we may reduce tails for i in [Length(homs),Length(homs)-1..1] do
Add(dept,off); if IsGeneralPcgs(homs[i]) then if Length(dec.abpow[i])>0then
ffp:=FreeAbelianGroup(Length(homs[i])*(Length(dec.abpow[i])+1)); # relations: order
m:=GeneratorsOfGroup(ffp);
r:=List(m,x->x^RelativeOrders(homs[i])[1]); # power dependence for j in [1..Length(dec.abpow[i])] do for k in [1..Length(homs[i])] do
Add(r,m[Length(homs[i])*(j-1)+k]^dec.abpow[i][j]
/m[Length(homs[i])*j+k]);
od;
od;
ffp:=ffp/r;
imo:=IsomorphismFpMonoid(ffp);
Add(mos,imo);
m:=Range(imo);
loff:=off-Length(GeneratorsOfMonoid(m));
monreps:=fmgens{[loff+1..off]};
monreal:=mgens{[loff+1..off]}; if IsBound(m!.rewritingSystem) then
k:=m!.rewritingSystem; else
k:=KnuthBendixRewritingSystem(m); fi; if HasLevelsOfGenerators(k!.ordering) then
Add(lode,LevelsOfGenerators(k!.ordering)); else
Add(lode,fail); fi;
MakeConfluent(k); # convert rules for r in Rules(k) do
left:=MappedWord(r[1],FreeGeneratorsOfFpMonoid(m),monreps);
right:=MappedWord(r[2],FreeGeneratorsOfFpMonoid(m),monreps);
diff:=LeftQuotient(PreImagesRepresentative(iso,right),
PreImagesRepresentative(iso,left));
diff:=ImagesRepresentative(iso,diff);
left:=MappedWord(r[1],FreeGeneratorsOfFpMonoid(m),monreal);
right:=MappedWord(r[2],FreeGeneratorsOfFpMonoid(m),monreal); if not IsOne(diff) then
right:=right*Product(List(LetterRepAssocWord(UnderlyingElement(diff)),
x->mgens[Position(nums,x)])); fi;
right:=reduce(right); # monoid word might change
addrule([left,right]);
od; for j in [loff+1..off] do # if the generator gets reduced away, won't need to use it if reduce(mgens[j])=mgens[j] then for k in [off+1..Length(mgens)] do if reduce(mgens[k])=mgens[k] then
right:=fmgens[j]^-1*fmgens[k]*fmgens[j]; #collect
right:=ImagesRepresentative(iso,PreImagesRepresentative(iso,right));
right:=Product(List(LetterRepAssocWord(UnderlyingElement(right)),
x->mgens[Position(nums,x)]));
right:=reduce(mgens[j]*right); #Print("Did rule ",mgens[k],"*",mgens[j],"->",right,"\n");
addrule([mgens[k]*mgens[j],right]); fi;
od; fi;
od; #if i<Length(homs) then Error("ZU");fi;
off:=loff;
od;
Add(dept,off); # calculate levels for ordering
dept:=dept+1;
dept:=List([1..Length(mgens)],
x->PositionProperty(dept,y->x>=y)-1);
# are there local levels to keep? First make them fractional additions
off:=10^(1+LogInt(Length(dept),10)); # cent level for local depths for i in [1..Maximum(dept)] do if lode[i]<>fail then
diff:=Filtered([1..Length(dept)],x->dept[x]=i);
dept{diff}:=dept{diff}+lode[i]/off; fi;
od; if ForAny(dept,x->not IsInt(x)) then # reintegralize
diff:=Set(dept);
dept:=List(dept,x->Position(diff,x)); fi;
# if AssertionLevel()>1 and ForAny(rules,x->x[2]<>reduce(x[2])) then # Error("irreduced right"); # fi;
# inverses are true inverses, also for extension for i in [1..Length(gens)] do
left:=mgens[2*i-1]*mgens[2*i];
left:=reduce(left); if left<>One(fm) then addrule([left,One(fm)]); fi;
left:=mgens[2*i]*mgens[2*i-1];
left:=reduce(left); if left<>One(fm) then addrule([left,One(fm)]); fi;
od; fi;
j:=rec(fphom:=iso,monhom:=hom); if dept=fail then
j.ordering:=k!.ordering; else
j.ordering:=WreathProductOrdering(fm,dept); fi;
k:=KnuthBendixRewritingSystem(FamilyObj(One(m)),j.ordering:isconfluent);
MakeConfluent(k); # will store in monoid as reducedConfluent
return j; end);
# special method for pc groups, basically just writing down the pc # presentation
InstallMethod(ConfluentMonoidPresentationForGroup,"pc",
[IsGroup and IsFinite and IsPcGroup], function(G)
local pcgs,iso,fp,i,j,gens,numi,ord,fm,fam,mword,k,r,addrule,a,e,m;
pcgs:=Pcgs(G);
iso:=IsomorphismFpGroup(G);
fp:=Range(iso); if List(GeneratorsOfGroup(fp),x->PreImagesRepresentative(iso,x))<>pcgs then
Error("pcgs"); fi;
gens:=[];
numi:=[];
ord:=[]; for i in [1..Length(pcgs)] do
Add(gens,String(fp.(i)));
Add(gens,String(fp.(i)^-1));
Add(numi,i);
Add(numi,-i);
Append(ord,[i,i]);
od;
fm:=FreeMonoid(gens);
fam:=FamilyObj(One(fm));
mword:=w->AssocWordByLetterRep(fam,
List(LetterRepAssocWord(UnderlyingElement(w)),x->Position(numi,x)));
ord:=WreathProductOrdering(fm,Reversed(ord));
k:=CreateKnuthBendixRewritingSystem(FamilyObj(One(fm/[])),ord); if AssertionLevel()<=2then # assertion level <=2 so the auto tests will never trigger it
Unbind(k!.pairs2check); fi;
addrule:=function(rul) #Print("Add:",rul,"\n");
AddRuleReduced(k,List(rul,LetterRepAssocWord)); #Print(Rules(k),"\n"); end;
for i in [Length(pcgs),Length(pcgs)-1..1] do if RelativeOrders(pcgs)[i]>2then
addrule([mword(fp.(i))*mword(fp.(i)^-1),One(fm)]);
addrule([mword(fp.(i)^-1)*mword(fp.(i)),One(fm)]); fi; for j in [Length(pcgs),Length(pcgs)-1..i+1] do for e in [[1,1],[1,-1],[-1,1],[-1,-1]] do if (RelativeOrders(pcgs)[j]>2 or e[1]=1) and
(RelativeOrders(pcgs)[i]>2 or e[2]=1) then
a:=(pcgs[j]^e[1])^(pcgs[i]^e[2]);
addrule([mword(fp.(j)^e[1]*fp.(i)^e[2]),mword(fp.(i)^e[2])*mword(a)]); fi;
od;
od;
r:=RelativeOrders(pcgs)[i]; if r=2then
a:=ImagesRepresentative(iso,pcgs[i]^2);
addrule([mword(fp.(i)^2),mword(a)]);
a:=ImagesRepresentative(iso,pcgs[i]^-2);
addrule([mword(fp.(i)^-1),mword(fp.(i))*mword(a)]); else
a:=ImagesRepresentative(iso,pcgs[i]^r);
addrule([mword(fp.(i)^((r+1)/2)),mword(fp.(i)^(-(r-1)/2))*mword(a)]);
a:=ImagesRepresentative(iso,pcgs[i]^-r);
addrule([mword(fp.(i)^(-(r+1)/2)),mword(fp.(i)^((r-1)/2))*mword(a)]); fi; if IsBound(k!.pairs2check) then
e:=StructuralCopy(Rules(k));
MakeConfluent(k);
Assert(3,Set(Rules(k))=Set(e)); fi;
od;
SetIsConfluent(k,true);
SetIsReduced(k,true);
m:=fm/Rules(k);
a:=MakeFpGroupToMonoidHomType1(fp,m);
SetReducedConfluentRewritingSystem(m,k);
j:=rec(fphom:=iso,monhom:=a,ordering:=ord);
return j; end);
# ser is a string indicating the series (A, B, C, D, E, F), n is a number. If argument `false` is added, only braid # relations
BindGlobal("WeylGroupFp",function(ser,n,docox...)
local f,rels,i,j,gens,coxrel;
coxrel:=function(a,b,n)
local m,f,g; if n=2then Add(rels,Comm(a,b)); else if docox then # coxeter: no negative exponents
Add(rels,(a*b)^n); else # braid: bababa... = ababab...
m:=QuoInt(n+1,2);
f:=Subword((b*a)^m,1,n);
g:=Subword((a*b)^m,1,n);
Add(rels,f/g); fi; fi; end;
f:=FreeGroup(List([1..n],x->Concatenation("s",String(x))));
gens:=GeneratorsOfGroup(f); if Length(docox)=0then
docox:=true; else
docox:=docox[1]=true; fi; if docox then
rels:=List(gens,x->x^2); else
rels:=[]; fi; if ser="A"then for i in [1..n] do for j in [1..i-1] do if i-j>1then
coxrel(gens[j],gens[i],2); else
coxrel(gens[j],gens[i],3); fi;
od;
od; elif ser="B" or ser="C"then for i in [1..n] do for j in [1..i-1] do if i-j>1then
coxrel(gens[j],gens[i],2); elif j=1then
coxrel(gens[j],gens[i],4); else
coxrel(gens[j],gens[i],3); fi;
od;
od; elif ser="D" and n>=4then
coxrel(gens[1],gens[2],2);
coxrel(gens[1],gens[3],3);
coxrel(gens[2],gens[3],3); for i in [4..n] do for j in [1..i-1] do if i-j>1then
coxrel(gens[j],gens[i],2); else
coxrel(gens[j],gens[i],3); fi;
od;
od; elif ser="E"then # 1-2-3-5-6-7-8 # | # 4
coxrel(gens[1],gens[2],3);
coxrel(gens[2],gens[3],3);
coxrel(gens[3],gens[4],3);
coxrel(gens[3],gens[5],3);
coxrel(gens[5],gens[6],3);
coxrel(gens[1],gens[3],2);
coxrel(gens[1],gens[4],2);
coxrel(gens[2],gens[4],2);
coxrel(gens[1],gens[5],2);
coxrel(gens[2],gens[5],2);
coxrel(gens[4],gens[5],2);
coxrel(gens[1],gens[6],2);
coxrel(gens[2],gens[6],2);
coxrel(gens[3],gens[6],2);
coxrel(gens[4],gens[6],2); if n>=7then
coxrel(gens[6],gens[7],3); for i in [1..5] do
coxrel(gens[i],gens[7],2);
od; fi; if n=8then
coxrel(gens[7],gens[8],3); for i in [1..6] do
coxrel(gens[i],gens[8],2);
od; elif n>8then
Error("E>8 does not exist"); fi; elif ser="F" and n=4then
coxrel(gens[1],gens[2],3);
coxrel(gens[2],gens[3],4);
coxrel(gens[3],gens[4],3);
coxrel(gens[1],gens[3],2);
coxrel(gens[1],gens[4],2);
coxrel(gens[2],gens[4],2); elif ser="G" and n=2then
coxrel(gens[1],gens[2],6); else
Error("series ",ser," not yet done"); fi;
return f/rels; end);
BindGlobal("IsomorphismFpGroupForWeyl", function(G)
local iso,n,fn,sz,bigcount,tryweyl;
tryweyl:=function(ser,n)
local H,isp,P,iso;
H:=WeylGroupFp(ser,n);
isp:=IsomorphismPermGroup(H);
P:=Image(isp,H);
iso:=IsomorphismGroups(G,P); if iso<>fail then
P:=List(GeneratorsOfGroup(H),
x->PreImagesRepresentative(iso,ImagesRepresentative(isp,x)));
iso:=GroupHomomorphismByImagesNC(G,H,P,GeneratorsOfGroup(H)); fi;
return iso; end;
# try to identify Weyl series
n:=0;
fn:=1;
repeat
n:=n+1;
fn:=fn*n;
bigcount:=0;
sz:=fn*(n+1); if Size(G)<sz then bigcount:=bigcount+1; elif Size(G)=sz and IsSymmetricGroup(G) then # try Sn if HasIsomorphismFpGroup(G) then # We can access the special `symmetric' presentation only as method # for `IsomorphismFp` for the symmetric group. But if such an # isomorphism is already stored, it might be a different one. # In this case recreate a new group that will then get it (because # it is symmetric).
G:=Group(GeneratorsOfGroup(G));
SetSize(G,sz);
SetIsSymmetricGroup(G,true); fi;
return IsomorphismFpGroup(G); # uses symmetric method fi;
sz:=2^n*fn; if Size(G)<sz then bigcount:=bigcount+1; elif Size(G)=sz then
iso:=tryweyl("B",n); if iso<>fail then return iso;fi; fi;
sz:=2^(n-1)*fn; if Size(G)<sz then bigcount:=bigcount+1; elif n>=4 and Size(G)=sz then
iso:=tryweyl("D",n); if iso<>fail then return iso;fi; fi;
until bigcount=3;
if Size(G)=12then
iso:=tryweyl("G",2); if iso<>fail then return iso;fi; elif Size(G)=1152then
iso:=tryweyl("F",4); if iso<>fail then return iso;fi; elif Size(G)=51840then
iso:=tryweyl("E",6); if iso<>fail then return iso;fi; elif Size(G)=72*Factorial(8) then
iso:=tryweyl("E",7); if iso<>fail then return iso;fi; elif Size(G)=192*Factorial(10) then
iso:=tryweyl("E",8); if iso<>fail then return iso;fi; fi;
return fail; end);
BindGlobal("CanoDC",function(chain,sub,orep)
local i,j,u,o,r,stb,m,g,img,p,rep,b,expand,dict,act,gens,gf,writestab;
expand:=function(n)
local e;
e:=r[n][2]; while r[n][1]<>0do
n:=r[n][1];
e:=r[n][2]*e;
od;
return e; end;
writestab:=function()
local p,k;
p:=stb; if Length(p)>3then # permute randomly
p:=p{FLOYDS_ALGORITHM(
GlobalMersenneTwister,Length(stb),false)}; fi;
stb:=SubgroupNC(sub,p{[1..Minimum(3,Length(p))]}); for k in p{[4..Length(p)]} do
stb:=ClosureSubgroupNC(stb,k);
od; end;
b:=One(sub);
rep:=orep; for i in [Length(chain)-1,Length(chain)-2..1] do
u:=chain[i];
act:=function(e,g) return CanonicalRightCosetElement(u,e*g);end;
# orbit/rep stabilizer
o:=[CanonicalRightCosetElement(u,rep)];
dict:=NewDictionary(rep,true,Last(chain));
AddDictionary(dict,o[1],1);
r:=[[0,One(sub)]];
stb:=[]; #stb:=TrivialSubgroup(sub);
j:=1;
m:=1;
gens:=GeneratorsOfGroup(sub);
gf:=true; while j<=Length(o) and Length(o)*Size(stb)<Size(sub) do if gf and Length(o)>40then
gf:=false;
gens:=SmallGeneratingSet(sub); fi; for g in gens do
img:=act(o[j],g); #p:=Position(o,img);
p:=LookupDictionary(dict,img); if p=fail then
Add(o,img);
AddDictionary(dict,img,Length(o));
Add(r,[j,g]); #Add(r,[0,r[j][2]*g]); if img<o[m] then m:=Length(o); fi; elif IsList(stb) then
AddSet(stb,expand(j)*g/expand(p)); if Length(o)>20then
writestab(); fi; else
stb:=ClosureSubgroupNC(stb,expand(j)*g/expand(p)); fi;
od;
j:=j+1;
od;
b:=b*expand(m);
j:=expand(m);
rep:=rep*j;
if i>1then if IsList(stb) then writestab();fi;
sub:=stb^j; fi;
od;
return [o[m],b]; end);
# rewriting systems for simple groups based on BN pairs, following # (Schmidt, Finite groups have short rewriting systems. Computational group # theory and the theory of groups, II, 185–200, Contemp. Math., 511.)
BindGlobal("SplitBNRewritingPresentation",function(group,borel,weyl,newstyle)
local isob,isos,iso,gens,a,rels,l,i,j,bgens,cb,cs,b,f,k,w,monoid,
lev,ord,monb,mons,gp,trawo,trawou,hom,tst,dc,dcreps,act,decomp,ranb,ranw,
nofob,nofow,reduce,pcgs,can,pri,stb,addrule,invmap,jj,wo,pciso,
borelelm,borelran,borelreduce,bpairs,brws,specialborelreduce,
rdag,mdag,wdag,dcnum,dcfix,
rt,dcnums,rti,maketzf,mytzf,csetperm,pc,bpcgs,noncomm,noncelm,
wgens,weylword,borelword,coxrels,ha,directerr,bhom,ac,relab,ostab,dcr,single;
specialborelreduce:=false; if Size(ClosureGroup(borel,weyl))<Size(group) then return fail;fi;
ha:=Intersection(borel,weyl);
dc:=DoubleCosets(group,borel,borel);
if newstyle then
# use exactly the generators of borel
bpcgs:=PcgsByPcSequence(FamilyObj(One(borel)),GeneratorsOfGroup(borel));
pc:=PcGroupWithPcgs(bpcgs);
pciso:=GroupHomomorphismByImages(borel,pc,bpcgs,FamilyPcgs(pc));
cb:=ConfluentMonoidPresentationForGroup(pc); else if Size(Intersection(borel,weyl))>1then # can we fix this? # assume weyl is not too large
cs:=Concatenation(List(ConjugacyClassesSubgroups(weyl),AsList));;
SortBy(cs,x->-Size(x));
l:=false;
i:=1; while l=false and i<=Length(cs) do if Size(Intersection(borel,cs[i]))=1 and Size(cs[i])>=Length(dc)
and Size(ClosureGroup(borel,cs[i]))=Size(group) and
Length(Set(Elements(cs[i]),
x->PositionProperty(dc,y->x in y)))=Length(dc) then
Info(InfoFpGroup,1,"replaced weyl candidate with better subgroup\n");
l:=cs[i]; fi;
i:=i+1;
od; if l<>false then
weyl:=l; fi; fi;
# force going to pc group, as this will give better ordering
isob:=GroupHomomorphismByFunction(borel,Range(cb.fphom),
x->ImagesRepresentative(cb.fphom,ImagesRepresentative(pciso,x)),
x->PreImagesRepresentative(pciso,PreImagesRepresentative(cb.fphom,x)));
b:=Range(isob);
wgens:=GeneratorsOfGroup(weyl);
bgens:=List(GeneratorsOfGroup(b),x->PreImagesRepresentative(isob,x)); if newstyle and bgens<>GeneratorsOfGroup(borel) then Error("gens");fi;
# borel-only reduction to deal with large primes
borelreduce:=function(w)
local i,j,need;
i:=1;
repeat # find borel range while i<Length(w) and not (w[i] in borelran) do
i:=i+1;
od; if i<Length(w) and w[i+1] in borelran then
j:=i;
need:=false; while j+1<=Length(w) and w[j+1] in borelran do
j:=j+1; if need=false and QuoInt(w[j-1]+1,2)=QuoInt(w[j]+1,2) # element and inverse
or w[j]<w[j-1] # wrong order then need:=true; fi;
od; if need then
need:=w{[i..j]};
need:=Product(bpairs{need});
need:=ImagesRepresentative(cb.monhom,ImagesRepresentative(isob,need));
need:=UnderlyingElement(need); if Length(need)>0then
need:=ReducedForm(brws,need); fi;
w:=Concatenation(w{[1..i-1]},LetterRepAssocWord(need),w{[j+1..Length(w)]});
i:=i+Length(need); else
i:=j+1; fi; else if i<Length(w) then i:=i+2;fi; fi;
until i>=Length(w);
return w; end;
maketzf:=function(rules)
local tzf,tzrules,p,i;
tzrules:=List(rules,x->List(x,LetterRepAssocWord));
tzf:=[]; for i in tzrules do
p:=i[1][1]; if not IsBound(tzf[p]) then
tzf[p]:=[i]; else
Add(tzf[p],i); fi;
od;
return tzf; end;
reduce:=function(wo,rules,dag,tzf)
local w,fam,red,i,j,p,ww,sp,has; #Print("Reduce ",wo,"\n");
fam:=FamilyObj(wo); # is it in big monoid?
w:=LetterRepAssocWord(wo);
sp:=specialborelreduce and fam=FamilyObj(One(f)) and ForAny(w,x->x in borelran);
# collect from the left if sp then
w:=borelreduce(w); fi;
if dag<>fail then
repeat
has:=false;
p:=1; while p<=Length(w) do
i:=RuleAtPosKBDAG(dag,w,p); if i<>fail then
has:=true; # replace
w:=Concatenation(w{[1..p-1]},LetterRepAssocWord(rules[i][2]),
w{[p+Length(rules[i][1])..Length(w)]}); if sp then
w:=borelreduce(w); fi;
p:=0; fi;
p:=p+1;
od;
until has=false;
else
p:=Length(w); while p>0do if IsBound(tzf[w[p]]) then
red:=tzf[w[p]];
i:=1; while i<=Length(red) do if p+Length(red[i][1])-1<=Length(w) then
j:=2; while j<=Length(red[i][1]) and w[p+j-1]=red[i][1][j] do
j:=j+1;
od; if j>Length(red[i][1]) then # replace
w:=Concatenation(w{[1..p-1]},red[i][2],
w{[p+Length(red[i][1])..Length(w)]}); #Print("intermed ",red[i],":",AssocWordByLetterRep(fam,w),"\n");
p:=Minimum(p+Length(red[i][2]),Length(w)); if sp then
ww:=borelreduce(w); if ww<>w then
w:=ww;
p:=Length(w); fi;
fi;
i:=Length(red); fi; fi;
i:=i+1;
od;
fi;
p:=p-1;
od; fi;
w:=AssocWordByLetterRep(fam,w); #Print("To ",w,"\n"); #if sp and w<>oreduce(wo,rules) then Error("baeh!");fi;
return w; end;
mdag:=EmptyKBDAG(Union(List(FreeGeneratorsOfFpMonoid(monoid),
LetterRepAssocWord)));
a:=RelationsOfFpMonoid(monoid); for i in [1..Length(a)] do
AddRuleKBDAG(mdag,LetterRepAssocWord(a[i][1]),i);
od;
if newstyle then
if IsBound(weyl!.epiweyl) then
cs:=GroupHomomorphismByImages(weyl,weyl!.epiweyl,
GeneratorsOfGroup(weyl),GeneratorsOfGroup(weyl!.epiweyl)); if Size(ha)>1then
w:=CompositionSeriesThrough(weyl,[ha]);
w:=Concatenation([weyl],Filtered(w,x->IsSubset(ha,x)));
cs:=IsomorphismFpGroupBySubnormalSeries(weyl,w,"w":knownfactor:=cs); fi; else
cs:=IsomorphismFpGroupByGenerators(weyl,wgens); fi;
w:=IsomorphismFpMonoid(Range(cs));
k:=KnuthBendixRewritingSystem(Range(w));
MakeConfluent(k);
k:=Rules(k);
w:=FreeMonoidOfFpMonoid(Range(w))/k;
w:=MakeFpGroupToMonoidHomType1(Range(cs),w);
cs:=rec(fphom:=cs,monhom:=w); else
cs:=IsomorphismFpGroupForWeyl(weyl); if cs<>fail then
cs:=rec(fphom:=cs,monhom:=IsomorphismFpMonoid(Range(cs))); else
cs:=ConfluentMonoidPresentationForGroup(weyl); fi;
wdag:=EmptyKBDAG(Union(List(FreeGeneratorsOfFpMonoid(Range(cs.monhom)),
LetterRepAssocWord)));
a:=RelationsOfFpMonoid(Range(cs.monhom)); for i in [1..Length(a)] do
AddRuleKBDAG(wdag,LetterRepAssocWord(a[i][1]),i);
od;
while Length(ac)>2 and
IndexNC(Last(ac),ac[Length(ac)-2])<10^7do
ac:=ac{Difference([1..Length(ac)],[Length(ac)-1])};
od;
i:=Length(ac)-1; while i>2do if IndexNC(ac[i],ac[i-2])<=100then
ac:=ac{Difference([1..Length(ac)],[i-1])}; fi;
i:=i-1;
od;
# perm action of group on top, small gen set
rt:=RightTransversal(group,ac[Length(ac)-1]);
a:=Group(SmallGeneratingSet(group)); # so nothing stores
csetperm:=List(GeneratorsOfGroup(a),x->Permutation(x,rt,OnRight));
iso:=EpimorphismFromFreeGroup(a);
csetperm:=List(bgens,x->MappedWord(PreImagesRepresentative(iso,x),
MappingGeneratorsImages(iso)[1],csetperm));
act:=Group(csetperm,());
rti:=List(dcnums,ReturnFalse); # which double are hit already for i in weyl do
a:=PositionCanonical(rt,i);
j:=PositionProperty(dcnums,x->a in x); if rti[j]=false then
rti[j]:=true; if dcnums[j][1]<>a then
dcnums[j]:=Concatenation([a],Difference(dcnums[j],[a])); fi; fi;
od;
# index the orbit nr.
rti:=[];
ostab:=[]; for i in [1..Length(dcnums)] do for j in dcnums[i] do
rti[j]:=i;
od;
a:=Stabilizer(borel,dcnums[i][1],bgens,csetperm,OnPoints);
a:=SubgroupNC(borel,SmallGeneratingSet(a));
ostab[i]:=a;
od;
ac:=ac{[1..Length(ac)-1]}; # remove top step
Info(InfoFpGroup,1,List(ac,Size));
Assert(0,single=(Length(ac)=1));
dcr:=function(elm)
local a,b,rep;
a:=PositionCanonical(rt,elm);
b:=rti[a];
rep:=RepresentativeAction(Image(bhom),a,dcnums[b][1]);
rep:=PreImagesRepresentative(bhom,rep); if single then
a:=[CanonicalRightCosetElement(ac[1],rt[dcnums[b][1]]),rep]; else
a:=CanoDC(ac,ostab[b],elm*rep);
a:=[a[1],rep*a[2]]; fi; if relab then
b:=Position(dcnum,a[1]);
a:=[dcreps[b],a[2]*dcfix[b]]; fi;
return a; end;
# the calculated reps
relab:=false;
dcfix:=List(dc,x->One(group));
dcnum:=fail;
dcnum:=List(dc,x->dcr(Representative(x))[1]);
# ensure the Weyl group is the reps
dcreps:=[]; for i in AsList(weyl) do
j:=dcr(i);
a:=Position(dcnum,j[1]); if not IsBound(dcreps[a]) then
dcreps[a]:=i;
dcfix[a]:=j[2]^-1; # mapping calculated to weyl elt fi;
od;
if not ForAll([1..Length(dc)],x->IsBound(dcreps[x])) then
Error("weyl does not cover dc"); fi;
relab:=true;
decomp:=function(elm)
local rep,a; if elm in borel then return [elm,One(borel),One(borel)];fi;
a:=dcr(elm);
rep:=a[2];
rep:=[elm*rep/a[1],a[1],rep^-1];
Assert(0,rep[1] in borel);
return rep; end;
iso:=IsomorphismFpGroupByGenerators(group,gens);
# else # alternative, old, code # # identify double cosets # rt:=RightTransversal(group,borel); # # # perm action of group, small gen set # a:=Group(SmallGeneratingSet(group)); # so nothing stores # csetperm:=List(GeneratorsOfGroup(a),x->Permutation(x,rt,OnRight)); # iso:=EpimorphismFromFreeGroup(a); # csetperm:=List(bgens,x->MappedWord(PreImagesRepresentative(iso,x),MappingGeneratorsImages(iso)[1],csetperm)); # act:=Group(csetperm,()); # # bhom:=GroupHomomorphismByImagesNC(borel,act,bgens,csetperm); # #Assert(0,bhom<>fail); # # dcnums:=OrbitsDomain(act,[1..Length(rt)]); # dcnums:=List(dcnums,x->Immutable(Set(x))); # rti:=[]; # for i in [1..Length(dc)] do # a:=PositionCanonical(rt,Representative(dc[i])); # a:=PositionProperty(dcnums,x->a in x); # for j in dcnums[a] do # rti[j]:=i; # od; # od; # dcnums:=false; # clean memory # iso:=false; # act:=false; # # # BN decomposition # dcreps:=[]; # for i in AsList(weyl) do # #a:=PositionProperty(dc,y->i in y); # a:=rti[PositionCanonical(rt,i)]; # if not IsBound(dcreps[a]) then dcreps[a]:=i;fi; # od; # # if not ForAll([1..Length(dc)],x->IsBound(dcreps[x])) then # Error("weyl does not cover dc"); # fi; # # iso:=IsomorphismFpGroupByGenerators(group,gens); # # act:=function(r,g) # return CanonicalRightCosetElement(borel,r*g); # end; # # decomp:=function(elm) # local pos,rep; # if elm in borel then return [elm,One(borel),One(borel)];fi; # #pos:=PositionProperty(dc,y->elm in y); # pos:=rti[PositionCanonical(rt,elm)]; # #rep:=RepresentativeAction(borel,PositionCanonical(rt,elm), # # PositionCanonical(rt,dcreps[pos]),bgens,csetperm,OnPoints); # rep:=PreImagesRepresentative(bhom, # RepresentativeAction(Range(bhom),PositionCanonical(rt,elm), # PositionCanonical(rt,dcreps[pos]))); # rep:=[elm*rep/dcreps[pos],dcreps[pos],rep^-1]; # Assert(0,rep[1] in borel); # return rep; # end; # fi;
# now build new presentation
a:=[]; for i in [1..Length(GeneratorsOfGroup(b))] do
Add(a,Concatenation("b",String(i)));
od;
borelran:=[1..Length(a)]; for i in [1..Length(GeneratorsOfGroup(w))] do
Add(a,Concatenation("w",String(i)));
od;
f:=FreeGroup(a);
gens:=FreeGeneratorsOfFpGroup(f);
rels:=[]; # take the relators of both groups
ranb:=gens{[1..l]}; for i in RelatorsOfFpGroup(b) do
Add(rels,MappedWord(i,FreeGeneratorsOfFpGroup(b),ranb));
od;
ranw:=gens{[l+1..Length(gens)]}; for i in RelatorsOfFpGroup(w) do
Add(rels,MappedWord(i,FreeGeneratorsOfFpGroup(w),ranw));
od;
# throw in relators for the whole group, so we guarantee a presentation
Append(rels,List(RelatorsOfFpGroup(Range(iso)),
w->MappedWord(w,FreeGeneratorsOfFpGroup(Range(iso)),gens)));
gp:=f/rels;
# now combine monoid presentations
rels:=[];
mytzf:=maketzf(rels);
mytzf:=fail;
directerr:=false; if newstyle then directerr:=true;fi;
addrule:=function(rule)
local left,right,let,p,trule,j,stack;
stack:=[];
left:=reduce(rule[1],rels,rdag,mytzf);
right:=reduce(rule[2],rels,rdag,mytzf); if left=right then return;fi; if IsLessThanUnder(ord,right,left) then
rule:=[left,right]; elif directerr then
Error("direction!");
rule:=[right,left]; else
rule:=[right,left]; fi; # try to shift
let:=LetterRepAssocWord(rule[1])[1];
left:=Subword(rule[1],2,Length(rule[1]));
right:=reduce(invmap[let]*rule[2],rels,rdag,mytzf); while IsLessThanUnder(ord,right,left) do
rule:=[left,right];
let:=LetterRepAssocWord(rule[1])[1];
left:=Subword(rule[1],2,Length(rule[1]));
right:=reduce(invmap[let]*rule[2],rels,rdag,mytzf);
od;
let:=LetterRepAssocWord(rule[1])[Length(rule[1])];
left:=Subword(rule[1],1,Length(rule[1])-1);
right:=reduce(rule[2]*invmap[let],rels,rdag,mytzf); while IsLessThanUnder(ord,right,left) do
rule:=[left,right];
let:=LetterRepAssocWord(rule[1])[Length(rule[1])];
left:=Subword(rule[1],1,Length(rule[1])-1);
right:=reduce(rule[2]*invmap[let],rels,rdag,mytzf);
od;
# delete common letters at start/end while Length(rule[2])>0 and Subword(rule[1],1,1)=Subword(rule[2],1,1) do
rule:=[Subword(rule[1],2,Length(rule[1])),
Subword(rule[2],2,Length(rule[2]))];
od; while Length(rule[2])>0 and Subword(rule[1],Length(rule[1]),Length(rule[1]))
=Subword(rule[2],Length(rule[2]),Length(rule[2])) do
rule:=[Subword(rule[1],1,Length(rule[1])-1),
Subword(rule[2],1,Length(rule[2])-1)];
od;
# are they now redundant?
left:=reduce(rule[1],rels,rdag,mytzf);
right:=reduce(rule[2],rels,rdag,mytzf); if IsLessThanUnder(ord,right,left) then
rule:=[left,right]; else
rule:=[right,left]; fi; if rule[1]=rule[2] then return;fi;
trule:=List(rule,LetterRepAssocWord); if rdag<>fail then
p:=AddRuleKBDAG(rdag,trule[1],Length(rels)+1); if p=fail then # need to reduce rules
left:=Filtered([1..Length(rels)],
x->PositionSublist(LetterRepAssocWord(rels[x][1]),trule[1])<>fail);
left:=Reversed(left); for p in left do
Add(stack,rels[p]);
DeleteRuleKBDAG(rdag,LetterRepAssocWord(rels[p][1]),p);
Remove(rels,p);
od;
p:=AddRuleKBDAG(rdag,trule[1],Length(rels)+1); elif p=false then Error("could be reduced");fi; fi;
Add(rels,rule); if mytzf<>fail then
p:=trule[1][1]; if not IsBound(mytzf[p]) then
mytzf[p]:=[trule]; else
Add(mytzf[p],trule); fi; fi; if Length(stack)>0then #Print("deleted ",Length(stack)," rules @",Length(rels),"\n"); for j in stack do
addrule(j);
od; fi; end;
lev:=ShallowCopy(LevelsOfGenerators(cb.ordering));
monb:=monoid;
mons:=Range(cs.monhom);
l:=Length(GeneratorsOfMonoid(monb));
a:=[]; for i in [1..l/2] do
Add(a,Concatenation("b",String(i)));
Add(a,Concatenation("B",String(i)));
od;
borelran:=[1..Length(a)]; for i in [1..Length(MappingGeneratorsImages(isos)[2])] do
Add(a,Concatenation("w",String(i)));
Add(a,Concatenation("W",String(i)));
od;
f:=FreeMonoid(a);
rdag:=EmptyKBDAG(Union(List(GeneratorsOfMonoid(f),LetterRepAssocWord)));
# translate from fp word to monoid word
trawo:=function(w)
local a,i;
w:=LetterRepAssocWord(w);
a:=[]; for i in w do if i>0then
Add(a,2*i-1); else
Add(a,-2*i); fi;
od;
a:=AssocWordByLetterRep(FamilyObj(One(f)),a);
return a; end;
coxrels:=[]; if Size(ha)>1then for i in Pcgs(ha) do
a:=[weylword(i),borelword(i)];
Info(InfoFpGroup,2,"intersection:",a);
a:=List(a,trawou);
addrule(a);
od;
b:=IsomorphismFpMonoid(weyl!.epiweyl);
k:=KnuthBendixRewritingSystem(Range(b));
MakeConfluent(k); for i in Rules(k) do
a:=List(i,LetterRepAssocWord); if ForAll(a,x->ForAll(x,IsOddInt)) then #Relation does not involve inverses # write with weyl numbers
a:=List(a,x->List(x,y->(y+1)/2));
Add(coxrels,a); fi;
od; else for i in RelationsOfFpMonoid(mons) do
a:=List(i,LetterRepAssocWord); if ForAll(a,x->ForAll(x,IsOddInt)) then #Relation does not involve inverses # write with weyl numbers
a:=List(a,x->List(x,y->(y+1)/2));
Add(coxrels,a); fi;
od; fi;
directerr:=false; else
j:=Intersection(borel,weyl); if Size(j)>1then for i in Pcgs(j) do
a:=[
MappedWord(Image(cs.fphom,i),GeneratorsOfGroup(Range(cs.fphom)),
GeneratorsOfGroup(gp){[Length(GeneratorsOfGroup(Range(isob)))+1
..Length(GeneratorsOfGroup(gp))]}),
MappedWord(Image(isob,i),GeneratorsOfGroup(Range(isob)),
GeneratorsOfGroup(gp){[1..Length(GeneratorsOfGroup(Range(isob)))]})
];
Info(InfoFpGroup,2,"intersection:",a);
a:=List(a,x->trawo(UnderlyingElement(x)));
addrule(a);
od; fi; fi;
for i in RelationsOfFpMonoid(monb) do
addrule(List(i,x->MappedWord(x,FreeGeneratorsOfFpMonoid(monb),
gens{[1..l]})));
od;
for i in RelationsOfFpMonoid(mons) do
addrule(List(i,x->MappedWord(x,FreeGeneratorsOfFpMonoid(mons),
gens{[l+1..Length(gens)]})));
od;
directerr:=false;
if newstyle then
noncomm:=List(wgens,x->[]); # To use standard wreath product order, move borel to the right.
# relations b*w->w*b' for i in [1..Length(wgens)] do
pri:=wgens[i]; for jj in [1..Length(bgens)] do
j:=bgens[jj];
k:=j^pri; if k in borel then
a:=weylword(pri);
b:=borelword(j);
k:=borelword(k);
a:=[b*a,a*k];
a:=List(a,trawou);
addrule(a); else
Add(noncomm[i],jj); fi;
od;
od;
# relations b*x*w -> x^(b^-1)*reduced(b*w) if xw does not transform for i in [1..Length(wgens)] do for jj in Difference(noncelm[i],[One(group)]) do# non-mappable for j in [1..Minimum(noncomm[i])-1] do# earlier generators
a:=weylword(wgens[i]);
pri:=borelword(bgens[j])*a;
pri:=reduce(trawou(pri),rels,rdag,mytzf);
a:=[trawou(borelword(bgens[j])*borelword(jj)*a),
trawou(borelword(jj^Inverse(bgens[j])))*pri];
addrule(a);
od;
od;
od; # modified coxeter relations with blocking borels in between # normalize using bn-pairs for pri in coxrels do
pri:=pri[1];
a:=List(pri,x->trawou(weylword(wgens[x]))); if Product(List(noncelm{pri{[2..Length(pri)]}},Length))>10^7then
Info(InfoWarning,1,"Likely huge RWS"); else for jj in Cartesian(noncelm{pri{[2..Length(pri)]}}) do if not ForAll(jj,IsOne) then
b:=wgens[pri[1]]*Product([1..Length(jj)],x->jj[x]*wgens[pri[x+1]]);
j:=decomp(b);
j:=[borelword(j[1]),weylword(j[2]),borelword(j[3])];
k:=List(jj,x->trawou(borelword(x)));
b:=a[1]*Product([1..Length(jj)],x->k[x]*a[x+1]);
j:=j[1]*j[2]*j[3];
b:=[b,trawou(j)];
addrule(b); fi;
od; fi;
od;
specialborelreduce:=true;
wo:=Filtered(w,x->not IsOne(x)); for i in wo do
# which elements b*i can we write as i*\tilde b. Then b^i=\tilde b, that # is b\in B\cvap B^(i^-1)
pri:=PreImagesRepresentative(isos,i);
stb:=Intersection(borel,borel^(pri^-1));
Info(InfoFpGroup,2,i," ",Size(stb));
if Size(stb)>1then
can:=CanonicalPcgs(InducedPcgs(pcgs,stb)); #can:=Filtered(Elements(stb),x->not IsOne(x)); for j in can do #for jj in borel do # Also products borel*stb for jj in List(RightTransversal(borel,stb),Inverse) do
k:=trawo(MappedWord(UnderlyingElement(i),FreeGeneratorsOfFpGroup(w),
ranw)); #Print("e.g. ",ImagesRepresentative(isob,jj*j)," => ", # nofob(ImagesRepresentative(isob,jj*j)),"\n");
a:=[ trawo(MappedWord(UnderlyingElement(
nofob(ImagesRepresentative(isob,jj*j))),
FreeGeneratorsOfFpGroup(b),ranb))*k,
trawo(MappedWord(UnderlyingElement(
nofob(ImagesRepresentative(isob,jj))),
FreeGeneratorsOfFpGroup(b),ranb))*
k*trawo(MappedWord(UnderlyingElement(
nofob(ImagesRepresentative(isob,j^pri))),
FreeGeneratorsOfFpGroup(b),ranb))]; #if not IsLessThanUnder(ord,a[2],a[1]) then Error("ord!");fi; #tst:=List(a,LetterRepAssocWord); #if not ForAny(rels,x-> # PositionSublist(tst[1],LetterRepAssocWord(x[1]))<>fail) then
addrule(a); #fi;
od;
od; fi;
od;
# avoid running through too many elements in borel if Size(borel)<100then borelelm:=AsList(borel); else
a:=Pcgs(borel);
pri:=RelativeOrders(a);
k:=[]; for i in [1..Length(a)] do
k[i]:=[]; for j in [0..LogInt(QuoInt(pri[i],2),5)] do
k[i]:=Union(k[i],5^j*[-2..2]);
od;
k[i]:=Intersection(k[i],[-QuoInt(pri[i],2)..QuoInt(pri[i],2)]);
k[i]:=List(k[i],x->a[i]^x);
od;
borelelm:=Set(Cartesian(k),Product);
fi;
for i in wo do
Info(InfoFpGroup,3,"borelrun ",Position(wo,i)," of ",Length(wo));
# rewrite i*b*j as \tilde b*k*\hat b.
pri:=PreImagesRepresentative(isos,i);
stb:=Intersection(borel^pri,borel);
for j in wo do
Info(InfoFpGroup,2,"DC:",i,", ",j," from ",Length(rels)); for k in borelelm do#RightTransversal(borel,stb) do
a:=PreImagesRepresentative(isos,i)*k*
PreImagesRepresentative(isos,j);
a:=decomp(a);
a:=[nofob(ImagesRepresentative(isob,a[1])),
nofow(ImagesRepresentative(isos,a[2])),
nofob(ImagesRepresentative(isob,a[3]))];
a:=[MappedWord(UnderlyingElement(a[1]),FreeGeneratorsOfFpGroup(b),ranb),
MappedWord(UnderlyingElement(a[2]),FreeGeneratorsOfFpGroup(w),ranw),
MappedWord(UnderlyingElement(a[3]),FreeGeneratorsOfFpGroup(b),ranb)
];
a:=List(a,trawo);
a:=[
trawo(MappedWord(UnderlyingElement(i),FreeGeneratorsOfFpGroup(w),ranw))
*trawo(MappedWord(UnderlyingElement(
nofob(ImagesRepresentative(isob,k))),
FreeGeneratorsOfFpGroup(b),ranb))*
trawo(MappedWord(UnderlyingElement(j),FreeGeneratorsOfFpGroup(w),ranw)),
Product(a)];
tst:=List(a,LetterRepAssocWord); #if ForAny(rels,x-> # PositionSublist(tst[1],LetterRepAssocWord(x[1]))<>fail) then
addrule(a); #fi;
od;
od;
od; fi;
# group relators to make sure it's the proper group
Info(InfoFpGroup,3,"grouprelators"); for i in RelatorsOfFpGroup(gp) do # split in two -- not optimal, want to get minimal offset
j:=Length(i); if IsEvenInt(j) then
j:=QuoInt(j+1,2);
a:=[Subword(i,1,j),Subword(i,j+1,Length(i))^-1]; if a[1]=a[2] then
a:=[Subword(i,1,j+1),Subword(i,j+2,Length(i))^-1]; fi; else
j:=QuoInt(j+1,2);
a:=[Subword(i,1,j),Subword(i,j+1,Length(i))^-1]; fi;
a:=List(a,trawo); if IsLessThanUnder(ord,a[1],a[2]) then
a:=Reversed(a); fi;
addrule(a);
od;
l:=[]; for i in FreeGeneratorsOfFpGroup(gp) do
Add(l,i);
Add(l,i^-1);
od;
tst:=List(rels,x->List(x,w->MappedWord(w,GeneratorsOfMonoid(f),l)));
tst:=List(tst,x->x[1]/x[2]);
Assert(2,Size(FreeGroupOfFpGroup(gp)/tst)=Size(group));
rdag:=fail;
# back-reduce
Info(InfoFpGroup,3,"backreduce");
repeat
jj:=[];
a:=true;
i:=1; while i<=Length(rels) do if IsSubset(borelran,Union(List(rels[i],LetterRepAssocWord))) then
specialborelreduce:=false; fi;
l:=rels{Difference([1..Length(rels)],[i])};
mytzf:=maketzf(l);
tst:=[reduce(rels[i][1],l,fail,mytzf),reduce(rels[i][2],l,fail,mytzf)]; if tst<>rels[i] then
Add(jj,i);
rels:=l; # note that tzf is already set if tst[1]<>tst[2] then
addrule(tst); fi;
a:=false; #i:=Length(rels); #just continue fi;
specialborelreduce:=true;
i:=i+1;
od;
Info(InfoFpGroup,2,"rulereduce ",jj);
until a;
i:=Length(rels);
Info(InfoFpGroup,2,"have ",i," rules");
a:=KnuthBendixRewritingSystem(f/rels,ord);
MakeConfluent(a);
Info(InfoFpGroup,1,"confluent RWS ",i," -> ",Length(Rules(a)),"\n");
b:=f/Rules(a); # make once more for the fp monoid.
SetReducedConfluentRewritingSystem(b,a);
l:=[]; for i in FreeGeneratorsOfFpGroup(gp) do
Add(l,i);
Add(l,i^-1);
od;
tst:=List(rels,x->List(x,w->MappedWord(w,GeneratorsOfMonoid(f),l)));
tst:=List(tst,x->x[1]/x[2]); #if Size(FreeGroupOfFpGroup(gp)/tst)<>Size(group) then Error("wrong2!");fi;
b!.rewritingSystem:=a;
hom:=MagmaIsomorphismByFunctionsNC(gp,b, function(w)
local l,i;
l:=[]; for i in LetterRepAssocWord(UnderlyingElement(w)) do if i>0then Add(l,2*i-1); else Add(l,-2*i);fi;
od;
return ElementOfFpMonoid(FamilyObj(One(b)),
AssocWordByLetterRep(FamilyObj(One(f)),l)); end, function(w)
local g,i,x;
g:=[]; for i in LetterRepAssocWord(UnderlyingElement(w)) do if IsOddInt(i) then x:=(i+1)/2; else x:=-i/2;fi; # word must be freely cancelled if Length(g)>0 and x=-Last(g) then
Remove(g); else Add(g,x); fi;
od;
return ElementOfFpGroup(FamilyObj(One(gp)),
AssocWordByLetterRep(FamilyObj(One(FreeGroupOfFpGroup(gp))),g)); end);
SetIsomorphismFpMonoid(gp,hom);
SetIsBijective(hom,true);
return iso; end);
# creator function for data in grp/simplrerew.grp -- for documentation #ConfluentRewritingData:=function(hom) #local f,miso,lm,mg,l,pre,gens,m,bas,pownum; # pownum:=function(w) # local l,s,i; # l:=LetterRepAssocWord(w); # s:=0; # for i in [1..Length(l)] do # s:=s+l[i]*bas^(i-1); # od; # return s; # end; # pre:=DataAboutSimpleGroup(Source(hom)); # pre:=ShallowCopy(pre.idSimple); # if not IsBound(pre.parameter) then pre.parameter:=pre.shortname;fi; # f:=Range(hom); # miso:=IsomorphismFpMonoid(f); # gens:=MappingGeneratorsImages(hom)[2]; # m:=Range(miso); # mg:=List(GeneratorsOfMonoid(m)); # bas:=Length(mg); # l:=[Size(f),pre.series,pre.parameter]; # if IsBound(pre.shortname) then Add(l,pre.shortname);fi; # l:=[l,MappingGeneratorsImages(hom)[1]]; # Add(l,bas); # bas:=bas+1; # need to go one larger, to avoid missing trailing 1's # Add(l,List(mg,String)); # if List(mg,x->LetterRepAssocWord(UnderlyingElement(x)))<> # List([1..Length(mg)],x->[x]) then Error("gens!"); fi; # pre:=List(mg,x->LetterRepAssocWord(UnderlyingElement( # PreImagesRepresentative(miso,x)))); # if ForAny(pre,x->Length(x)<>1) then Error("double");fi; # Add(l,Concatenation(pre)); # if IsBound(m!.rewritingSystem) then # mg:=m!.rewritingSystem; # Add(l,LevelsOfGenerators(mg!.ordering)); # else # Add(l,0); # fi; # Add(l,List(RelationsOfFpMonoid(m),x->List(x,pownum))); # return l; #end;
BindGlobal("BuildRewritingFromData",function(dat)
local bas,fm,fam,mfam,mrels,rels,i,f,g,m,hom;
bas:=dat[3]+1;
fm:=FreeMonoid(dat[4]);
mfam:=FamilyObj(One(fm));
mrels:=[];
rels:=[]; for i in dat[7] do
i:=List(i,x->CoefficientsQadic(x,bas));
Add(mrels,List(i,x->AssocWordByLetterRep(mfam,x)));
i:=List(i,x->dat[5]{x}); # avoid the inverse relations if not (Length(i[1])=2 and i[1][1]=-i[1][2]) then
i:=List(i,x->AssocWordByLetterRep(fam,x));
Add(rels,i[1]/i[2]); fi;
od;
m:=fm/mrels; if IsList(dat[6]) then
i:=KnuthBendixRewritingSystem(m,WreathProductOrdering(fm,dat[6]):isconfluent);
i!.reduced:=true;
m!.rewritingSystem:=i; fi;
InstallMethod(IsomorphismFpGroupForRewriting,"simple groups: stored",
[IsSimpleGroup and IsFinite],1, function(G)
local a,f,iso;
a:=DataAboutSimpleGroup(G); if not IsBound(a.classicalId)
or ValueOption(NO_PRECOMPUTED_DATA_OPTION)=true then
TryNextMethod(); fi;
iso:=ShallowCopy(a.idSimple); if not IsBound(iso.parameter) then
iso.parameter:=iso.shortname; fi;
# is it a pre-stored presentation?
f:=Filename(DirectoriesLibrary("grp"), "simplerew.grp"); if f<>fail then
f:=ReadAsFunction(f)();
f:=First(f,x->x[1][2]=iso.series
and x[1][3]=iso.parameter); if f<>fail then
a:=BuildRewritingFromData(f);
return IsomorphismGroups(G,Source(a))*a; fi; fi;
TryNextMethod(); end);
InstallMethod(IsomorphismFpGroupForRewriting,"simple groups: L and C",
[IsSimpleGroup and IsFinite],0, function(G)
local d,f,group,act,g,sy,b,c,borel,weyl,a,i,iso,ucs,gens,gl;
a:=DataAboutSimpleGroup(G); if not IsBound(a.classicalId) then
TryNextMethod(); fi;
if a.classicalId.series="L"then
d:=a.classicalId.parameter[1];
f:=a.classicalId.parameter[2];
a:=List(GeneratorsOfGroup(g),x->PermutationMat(x,d,GF(f))); for i in [1..Length(a)] do if not IsOne(DeterminantMat(a[i])) then
a[i][1]:=-a[i][1]; fi;
od;
a:=Group(a);
a:=Image(act,a);
a!.epiweyl:=weyl;
weyl:=a;
gens:=IndependentGeneratorsOfAbelianGroup(Centre(sy));
gens:=Concatenation(List(gens,x->Filtered(Orbit(weyl,x),x->x in sy)));
SortBy(gens,x->PositionProperty(ucs,y->x in y));
a:=gens;
c:=TrivialSubgroup(sy);
gens:=[]; for i in a do if not i in c and IsNormal(ClosureGroup(c,i),c) then
Add(gens,i);
c:=ClosureGroup(c,i); fi;
od; if c<>sy then Error("sylow (A) generators");fi;
gens:=Reversed(gens);
if Size(borel)=Size(sy) then
borel:=Group(gens);
iso:=SplitBNRewritingPresentation(group,borel,weyl,true);
return IsomorphismGroups(G,Source(iso))*iso; elif IsPrimePowerInt(Index(borel,sy)) then
gens:=Concatenation(Pcgs(SylowSubgroup(borel,
SmallestPrimeDivisor(IndexNC(borel,sy)))),gens);
a:=Group(gens); if Size(a)<Size(borel) then Error("wrong"); else borel:=a;fi;
iso:=SplitBNRewritingPresentation(group,borel,weyl,true);
return IsomorphismGroups(G,Source(iso))*iso; else
borel:=Group(SpecialPcgs(borel));
iso:=SplitBNRewritingPresentation(group,borel,weyl,true);
return IsomorphismGroups(G,Source(iso))*iso; fi;
elif a.idSimple.series="C" or #B(n,2^m) ~ C(n,2^m)
(a.idSimple.series="B" and
SmallestPrimeDivisor(a.classicalId.parameter[2])=2) then
d:=a.idSimple.parameter[1];
f:=a.idSimple.parameter[2];
group:=PSP(2*d,f);
act:=group!.actionHomomorphism;
g:=Source(act); # get sylow subgroup as intersection with GL-Sylow so it is upper # triangular
gl:=GL(2*d,f);
sy:=SylowSubgroup(gl,SmallestPrimeDivisor(f));
sy:=Intersection(g,sy); if Gcd(Size(sy),Size(g)/Size(sy))<>1then
Info(InfoWarning,1,"Sylow intersection did not work");
sy:=SylowSubgroup(g,SmallestPrimeDivisor(f)); fi;
# Weyl
weyl:=SymmetricGroup(d);
a:=[]; for i in GeneratorsOfGroup(weyl) do
c:=IdentityMat(2*d,GF(f));
b:=PermutationMat(i,d,GF(f));
c{[1..d]}{[1..d]}:=b;
c{[d+1..2*d]}{[d+1..2*d]}:=Reversed(List(b,Reversed)); if not IsOne(DeterminantMat(c)) then
c[1]:=-c[1]; fi;
Add(a,c);
od;
b:=PermutationMat((d,d+1),2*d,GF(f));
b[d+1]:=-b[d+1];
Add(a,b);
a:=Group(a);
a:=Image(act,a);
weyl:=WeylGroupFp("B",d);
Size(weyl);
c:=GQuotients(a,weyl); if Length(c)>1then
c:=Filtered(c,
x->KernelOfMultiplicativeGeneralMapping(x)=Intersection(a,borel)); fi;
c:=c[1];
a:=SubgroupNC(group,List(GeneratorsOfGroup(weyl),
x->PreImagesRepresentative(c,x)));
Size(a);
a!.epiweyl:=weyl;
weyl:=a; if group<>ClosureGroup(borel,weyl) then Error("wrong BN");fi;
# cannot yet do the refined process, as its not yet the right weyl # candidate # # sy:=SylowSubgroup(borel,SmallestPrimeDivisor(f)); # ucs:=Reversed(PCentralSeries(sy)); # # #gens:=IndependentGeneratorsOfAbelianGroup(Centre(sy)); # #gens:=Concatenation(List(gens,x->Filtered(Orbit(weyl,x),x->x in sy))); # gens:=Union(Orbit(weyl,Centre(sy))); # i:=1; # while not IsSubset(Group(gens),sy) do # i:=i+1; # gens:=Union(Orbit(weyl,ucs[i])); # od; # # gens:=Difference(gens,[One(sy)]); # SortBy(gens,x->PositionProperty(ucs,y->x in y)); # a:=gens; # c:=TrivialSubgroup(sy); # gens:=[]; # for i in a do # if not i in c and IsNormal(ClosureGroup(c,i),c) then # Add(gens,i); # c:=ClosureGroup(c,i); # fi; # od; # if c<>sy then Error("sylow (B) generators");fi; # gens:=Reversed(gens); # # if Size(borel)=Size(sy) then # borel:=Group(gens); # iso:=SplitBNRewritingPresentation(group,borel,weyl,true); # return IsomorphismGroups(G,Source(iso))*iso; # elif IsPrimePowerInt(Index(borel,sy)) then # gens:=Concatenation(Pcgs(SylowSubgroup(borel, # SmallestPrimeDivisor(IndexNC(borel,sy)))),gens); # a:=Group(gens); # if Size(a)<Size(borel) then Error("wrong"); # else borel:=a;fi; # iso:=SplitBNRewritingPresentation(group,borel,weyl,true); # return IsomorphismGroups(G,Source(iso))*iso; # else # Error("can't do yet"); # fi;
InstallMethod(IsomorphismFpGroupForRewriting,"generic simple",
[IsSimpleGroup and IsFinite],-1, function(G)
local p,dat,lev,l,sub,c,s,r,dc; # try to find subgroups similar to Borel and Weyl
dat:=DataAboutSimpleGroup(G); if IsBound(dat.idSimple.parameter) and IsList(dat.idSimple.parameter)
and Length(dat.idSimple.parameter)>1then
p:=Factors(dat.idSimple.parameter[2])[1];
s:=SylowSubgroup(G,p);
l:=Normalizer(G,s);
sub:=ComplementClassesRepresentatives(l,s); # torus if Length(sub)>0 and Size(sub[1])>1then
s:=Normalizer(G,sub[1]);
r:=ComplementClassesRepresentatives(s,sub[1]); if Length(r)>0then
s:=r[1]; fi;
r:=SplitBNRewritingPresentation(G,l,s,false); if r<>fail then return r;fi; fi; fi;
lev:=1;
repeat
lev:=lev+1;
l:=LowLayerSubgroups(G,lev);
l:=Filtered(l,IsSolvableGroup);
until Length(l)>0;
SortBy(l,Size);
l:=Last(l); # will be "borel"
dc:=DoubleCosets(G,l,l);
# small subgroup that will act transitively on the double cosets.
sub:=ShallowCopy(ConjugacyClassesSubgroups(G));;
SortBy(sub,x->Size(Representative(x)));
for c in sub do for s in c do if Size(Intersection(l,s))=1 and Size(s)>=Length(dc)
and Size(ClosureGroup(l,s))=Size(G) and
Length(Set(Elements(s),
x->PositionProperty(dc,y->x in y)))=Length(dc) then
r:=SplitBNRewritingPresentation(G,l,s,false); if r<>fail then return r;fi; fi;
od;
od;
TryNextMethod(); end);
Messung V0.5 in Prozent
¤ 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.0.80Bemerkung:
(vorverarbeitet am 2026-10-13)
¤
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.