Skip to content

Commit

Permalink
Improve construction of permutation actions and by this e.g. make `Fa…
Browse files Browse the repository at this point in the history
…ctorCosetAction` faster by several magnitudes in certain examples (gap-system#5698)

* PERFORMANCE: Permutation Group transversal

Rewrite a condition, mapping with inverse permutations, to test for a
small set of numbers rather than a large one. Doing so can give a
substantial speedup for constructing certain right transversals.

Also adjust of storage limits to reflect hardware progress over
20 years.

* ENHANCE: Orbit calculation may keep permutations

using an option, if they are obtained for free during the calculation

* ENHANCE: FactorCosetAction and RightTransversal

Speed up these operations by finding a better subgroup series, defined by
actions, and use these actions if possible.

Added example and clarify that ordering of points in `FactorCosetAction`
is not guaranteed.
  • Loading branch information
hulpke authored May 6, 2024
1 parent 603dcdb commit 6935405
Show file tree
Hide file tree
Showing 6 changed files with 307 additions and 30 deletions.
3 changes: 3 additions & 0 deletions lib/csetgrp.gd
Original file line number Diff line number Diff line change
Expand Up @@ -441,3 +441,6 @@ DeclareGlobalFunction("IntermediateGroup");
# forward declaration for recursive call.
DeclareGlobalFunction("DoConjugateInto");

# action-based ascending series for perm group
DeclareGlobalFunction("ActionRefinedSeries");

8 changes: 6 additions & 2 deletions lib/csetgrp.gi
Original file line number Diff line number Diff line change
Expand Up @@ -332,6 +332,10 @@ local o,b,img,G1,c,m,hardlimit,gens,t,k,intersize;
fi;
fi;

if ValueOption("cheap")=true then
return fail; # do not do hard work
fi;

if Index(G,U)>hardlimit then
Info(InfoWarning,1,
"will have to use permutation action of degree bigger than ", hardlimit);
Expand Down Expand Up @@ -988,9 +992,9 @@ local c, flip, maxidx, cano, tryfct, p, r, t,
actlimit, uplimit, badlimit,avoidlimit,start,includestab,quot;

actlimit:=300000; # maximal degree on which we try blocks
uplimit:=10000; # maximal index for up step
uplimit:=500000; # maximal index for up step
avoidlimit:=200000; # beyond this index we want to get smaller
badlimit:=1000000; # beyond this index things might break down
badlimit:=5000000; # beyond this index things might break down

mayflip:=true; # are we allowed to flip?

Expand Down
247 changes: 231 additions & 16 deletions lib/csetperm.gi
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,54 @@ end );
##
MAX_SIZE_TRANSVERSAL := 100000;

# so far only orbits and perm groups -- TODO: Other deduced actions
InstallGlobalFunction(ActionRefinedSeries,function(G,U)
local o,A,ser,act,i;
o:=List(Orbits(U,MovedPoints(G)),Set);
SortBy(o,Length);
A:=G;
ser:=[A];
act:=[0]; # dummy entry
i:=1;
while i<=Length(o) and Size(A)>Size(U) do
A:=Stabilizer(A,o[i],OnSets);
if Size(A)<Size(ser[Length(ser)]) then
Add(ser,A);
Add(act,[o[i],OnSets]);
fi;
i:=i+1;
od;
if Size(A)>Size(U) then
Add(ser,U);
Add(act,fail);
fi;
# refine large step?
for i in [1..Length(ser)-1] do
if IndexNC(ser[i],ser[i+1])>MAX_SIZE_TRANSVERSAL then
A:=IntermediateGroup(ser[i],ser[i+1]:cheap);
if A<>fail then
# refine with action
o:=ActionRefinedSeries(ser[i],A);
ser:=Concatenation(ser{[1..i]},o[1]{[1..Length(o[1])-1]},
ser{[i+1..Length(ser)]});
act:=Concatenation(act{[1..i]},o[2]{[1..Length(o[2])-1]},
act{[i+1..Length(act)]});
else
# no refinement, next step
i:=i+1;
fi;
else
# no refinement needed, next step
i:=i+1;
fi;
od;
# make ascending like AscendingSeries
return [Reversed(ser),Reversed(act)];
end);

BindGlobal( "RightTransversalPermGroupConstructor", function( filter, G, U )
local GC, UC, noyet, orbs, domain, GCC, UCC, ac, nc, bpt, enum, i;
local GC, UC, noyet, orbs, domain, GCC, UCC, ac, nc, bpt, enum, i,
actions,nct;

GC := CopyStabChain( StabChainImmutable( G ) );
UC := CopyStabChain( StabChainImmutable( U ) );
Expand All @@ -62,20 +108,27 @@ BindGlobal( "RightTransversalPermGroupConstructor", function( filter, G, U )
#Print(SizeStabChain(GCC),"/",SizeStabChain(UCC),":",
# SizeStabChain(GCC)/SizeStabChain(UCC),"\n");
if noyet and (
(SizeStabChain(GCC)/SizeStabChain(UCC)*10 >MAX_SIZE_TRANSVERSAL) or
(SizeStabChain(GCC)/SizeStabChain(UCC) >MAX_SIZE_TRANSVERSAL) or
(Length(UCC.genlabels)=0 and
SizeStabChain(GCC)>MAX_SIZE_TRANSVERSAL)
) then
# we potentially go through many steps, making it expensive
ac:=AscendingChain(G,U:cheap);

# first get a factorization through actions
ac:=ActionRefinedSeries(G,U);
actions:=ac[2];
ac:=ac[1];

# go in biggish steps through the chain
nc:=[ac[1]];
nct:=[actions[1]];
for i in [3..Length(ac)] do
if Size(ac[i])/Size(nc[Length(nc)])>MAX_SIZE_TRANSVERSAL then
Add(nc,ac[i-1]);
Add(nct,actions[i-1]);
fi;
od;
Add(nc,ac[Length(ac)]);
Add(nct,actions[Length(actions)]);
if Length(nc)>2 then
ac:=[];
for i in [Length(nc),Length(nc)-1..2] do
Expand Down Expand Up @@ -158,7 +211,8 @@ end );
InstallGlobalFunction( AddCosetInfoStabChain, function( G, U, maxmoved )
local orb, pimg, img, vert, s, t, index,
block, B, blist, pos, sliced, lenflock, i, j,
ss, tt,t1,t1lim,found,tl,vimg;
ss, tt,t1,t1lim,found,tl,vimg,
sel,shortsel,gorpo,pisel,prepi,transinv;

# iterated image
vimg:=function(point,list)
Expand Down Expand Up @@ -251,13 +305,85 @@ InstallGlobalFunction( AddCosetInfoStabChain, function( G, U, maxmoved )
t1lim:=50;
fi;

sel:=Filtered([1..Maximum(G.orbit)],x->IsBound(U.translabels[x]));
shortsel:=Length(sel)<t1lim;

if shortsel then
# inverse transversal elements
t1:=ShallowCopy(G.generators);
Add(t1,G.identity);
vert:=List(t1,x->x^-1);
# inverses of transversal, stored compact
# TODO: Instead of `Position`, use translabels entry
#transinv:=List(G.transversal,x->vert[Position(t1,x)]);
transinv:=[];
for i in [1..Length(G.transversal)] do
if IsBound(G.transversal[i]) then
t:=Position(t1,G.transversal[i]);
if t=fail then
Add(t1,G.transversal[i]);
Add(vert,G.transversal[i]^-1);
t:=Length(t1);
fi;
transinv[i]:=vert[t];
fi;
od;
# Position in orbit
gorpo:=[];
for i in [1..Length(G.orbit)] do
gorpo[G.orbit[i]]:=i;
od;
fi;

orb := G.orbit{ [ 1 .. U.lenblock ] };
pimg := [ ];
while index < U.index do

pimg{ orb } := CosetNumber( G.stabilizer, U.stabilizer, s,
orb );
t := 2;
while t <= U.lenblock and index < U.index do

if shortsel then

# test for the few wrong values, mapping backwards

pisel:=Filtered([1..Length(pimg)],
x->IsBound(pimg[x]) and pimg[x] in sel);

while t <= U.lenblock and index < U.index do

# For this point in the block, find the images of the
# earlier points under the representative.
vert := G.orbit{ [ 1 .. t-1 ] };
img := G.orbit[ t ];
tl:=[];
while img <> G.orbit[ 1 ] do
Add(tl,transinv[img]);
img := img ^ G.transversal[ img ];
od;
prepi:=pisel;
for t1 in [Length(tl),Length(tl)-1..1] do
prepi:=OnTuples(prepi,tl[t1]);
od;

# If $Ust = Us't'$ then $1t'/t/s in 1U$. Also if $1t'/t/s
# in 1U$ then $st/t' = u.g_1$ with $u in U, g_1 in G_1$
# and $g_1 = u_1.s'$ with $u_1 in U_1, s' in S_1$, so
# $Ust = Us't'$.
#if ForAll( [ 1 .. t-1 ], i -> not
# vert[ i ] in prepi ) then
if not ForAny(gorpo{prepi},x->x>=1 and x<=t-1) then
U.repsStab[ t ][ s ] := true;
index := index + lenflock;

fi;

t := t + 1;
od;

else

while t <= U.lenblock and index < U.index do

# do not test all points first if not necessary
# (test only at most t1lim points, if the test succeeds,
Expand All @@ -269,25 +395,25 @@ InstallGlobalFunction( AddCosetInfoStabChain, function( G, U, maxmoved )
vert := G.orbit{ [ 1 .. t1 ] };
img := G.orbit[ t ];
while img <> G.orbit[ 1 ] do
vert := OnTuples( vert, G.transversal[ img ] );
img := img ^ G.transversal[ img ];
vert := OnTuples( vert, G.transversal[ img ] );
img := img ^ G.transversal[ img ];
od;

# If $Ust = Us't'$ then $1t'/t/s in 1U$. Also if $1t'/t/s
# in 1U$ then $st/t' = u.g_1$ with $u in U, g_1 in G_1$
# and $g_1 = u_1.s'$ with $u_1 in U_1, s' in S_1$, so
# $Ust = Us't'$.
if ForAll( [ 1 .. t1 ], i -> not IsBound
( U.translabels[ pimg[ vert[ i ] ] ] ) ) then
( U.translabels[ pimg[ vert[ i ] ] ] ) ) then

# do all points
if t1<t-1 then
img := G.orbit[ t ];
if t<=10*t1lim then
vert := G.orbit{ [ 1 .. t - 1 ] };
while img <> G.orbit[ 1 ] do
vert := OnTuples( vert, G.transversal[ img ] );
img := img ^ G.transversal[ img ];
vert := OnTuples( vert, G.transversal[ img ] );
img := img ^ G.transversal[ img ];
od;
found:=ForAll( [ t1+1 .. t - 1 ], i -> not IsBound
( U.translabels[ pimg[ vert[ i ] ] ] ) );
Expand All @@ -298,16 +424,16 @@ InstallGlobalFunction( AddCosetInfoStabChain, function( G, U, maxmoved )
# long a list, failure will happen quickly.
tl:=[];
while img <> G.orbit[ 1 ] do
Add(tl,G.transversal[img]);
img := img ^ G.transversal[ img ];
Add(tl,G.transversal[img]);
img := img ^ G.transversal[ img ];
od;
found:=ForAll( [ t1+1 .. t - 1 ], i -> not IsBound
( U.translabels[ pimg[ vimg(G.orbit[ i ],tl) ] ] ) );
fi;

if found then
U.repsStab[ t ][ s ] := true;
index := index + lenflock;
U.repsStab[ t ][ s ] := true;
index := index + lenflock;
fi;

else
Expand All @@ -317,7 +443,9 @@ InstallGlobalFunction( AddCosetInfoStabChain, function( G, U, maxmoved )
fi;

t := t + 1;
od;
od;
fi;

s := s + 1;
od;

Expand Down Expand Up @@ -735,3 +863,90 @@ function(cos1,cos2)
od;
return [];
end);


#############################################################################
##
#F FactorCosetAction( <G>, <U>, [<N>] ) operation on the right cosets Ug
## with possibility to indicate kernel
##
BindGlobal("DoFactorCosetActionPerm",function(arg)
local G,u,op,h,N,rt,ac,actions,hom,i,q;
G:=arg[1];
u:=arg[2];
if Length(arg)>2 then
N:=arg[3];
else
N:=false;
fi;
if IsList(u) and Length(u)=0 then
u:=G;
Error("only trivial operation ? I Set u:=G;");
fi;
if N=false then
N:=Core(G,u);
fi;

ac:=ActionRefinedSeries(G,u);
actions:=ac[2];
ac:=ac[1];
hom:=false;
for i in [2..Length(ac)] do
if actions[i-1]<>fail
# allow 2GB memory use for writing down orbit
and SIZE_OBJ(actions[i-1][1])*IndexNC(ac[i],ac[i-1])<2*10^9 then

op:=rec();
h:=Orbit(ac[i],actions[i-1][1],actions[i-1][2]:permutations:=op);
if IsBound(op.permutations) then
rt:=List(op.permutations,PermList);
q:=Group(rt);
SetSize(q,IndexNC(G,N));
h:=GroupHomomorphismByImagesNC(ac[i],Group(rt),
op.generators,rt);
else
h:=ActionHomomorphism(ac[i],h,actions[i-1][2],"surjective");
fi;
else
rt:=RightTransversal(ac[i],ac[i-1]);
if not IsRightTransversalRep(rt) then
# the right transversal has no special `PositionCanonical' method.
rt:=List(rt,i->RightCoset(ac[i-1],i));
fi;
h:=ActionHomomorphism(ac[i],rt,OnRight,"surjective");

fi;
Unbind(op);
Unbind(rt);
if i=2 then
hom:=h;
else
hom:=KuKGenerators(ac[i],h,hom);;
q:=Group(hom);
StabChainOptions(q).limit:=Size(ac[i]);
hom:=GroupHomomorphismByImagesNC(ac[i],q,GeneratorsOfGroup(ac[i]),hom);;
fi;
od;

op:=Image(hom,G);
SetSize(op,IndexNC(G,N));

# and note our knowledge
SetKernelOfMultiplicativeGeneralMapping(hom,N);
AddNaturalHomomorphismsPool(G,N,hom);
return hom;
end);

InstallMethod(FactorCosetAction,"by right transversal operation",
IsIdenticalObj,[IsPermGroup,IsPermGroup],0,
function(G,U)
return DoFactorCosetActionPerm(G,U);
end);

InstallOtherMethod(FactorCosetAction,
"by right transversal operation, given kernel",IsFamFamFam,
[IsPermGroup,IsPermGroup,IsPermGroup],0,
function(G,U,N)
return DoFactorCosetActionPerm(G,U,N);
end);

6 changes: 5 additions & 1 deletion lib/factgrp.gd
Original file line number Diff line number Diff line change
Expand Up @@ -150,13 +150,17 @@ DeclareAttribute("NaturalHomomorphismsPool",IsGroup,
## gap> g:=Group((1,2,3,4,5),(1,2));;u:=SylowSubgroup(g,2);;Index(g,u);
## 15
## gap> FactorCosetAction(g,u);
## <action epimorphism>
## [ (1,2,3,4,5), (1,2) ] -> [ (1,4,7,10,13)(2,5,8,11,14)(3,6,9,12,15),\
## (1,4)(2,6)(3,5)(7,8)(10,12)(13,14) ]
## gap> StructureDescription(Range(last));
## "S5"
## gap> FactorCosetAction(g,[u,SylowSubgroup(g,3)]);;
## gap> Size(Image(last));
## 120
## ]]></Example>
## The correspondence of points with cosets will, for performance reasons,
## depend on the method used. It is not guaranteed that it will be the same
## as used by <C>RightTransversal</C> or <C>RightCosets</C>.
## </Description>
## </ManSection>
## <#/GAPDoc>
Expand Down
Loading

0 comments on commit 6935405

Please sign in to comment.