From 0b0143343f98d6c40ba21028ee6c46f73df686a1 Mon Sep 17 00:00:00 2001 From: Alexander Hulpke Date: Wed, 26 Oct 2022 16:14:02 +1100 Subject: [PATCH] ENHANCE: Speedup MinimalFaithfulPermutationDegreee --- lib/grplatt.gi | 204 ++++++++++++++++++++++++++++++++--- tst/teststandard/permgrp.tst | 6 +- 2 files changed, 197 insertions(+), 13 deletions(-) diff --git a/lib/grplatt.gi b/lib/grplatt.gi index a1cf55e534..2700efc517 100644 --- a/lib/grplatt.gi +++ b/lib/grplatt.gi @@ -3355,9 +3355,87 @@ local l,N,t,gens,i,c,o,rep,r,sub,gen; fi; end); +# return function that finds index in list +BindGlobal("SubgroupPositionIdentifier",function(G,l) +local quicks,dom,trySplit,tree,idder; + + quicks:=[]; + Add(quicks,Size); + idder:=fail; + if IsPermGroup(G) then + dom:=MovedPoints(G); + Add(quicks,x->Set(List(Orbits(G,dom),Set))); + elif IsPcGroup(G) then + dom:=FamilyPcgs(G); + Add(quicks, + y->Minimum(List(GeneratorsOfGroup(y),x->DepthOfPcElement(dom,x)))); + idder:=CanonicalPcgsWrtFamilyPcgs; + fi; + Add(quicks,AbelianInvariants); + + trySplit:=function(propnum,pool,poolids) + local prop,nv,nlp,nlpi,v,p,j; + if propnum>Length(quicks) or Length(pool)<=1 then + if idder=fail or Length(pool)=1 then + return [fail,fail,pool,poolids]; + else + nlp:=List(pool,idder); + nlpi:=ShallowCopy(poolids); + SortParallel(nlp,nlpi); + return [fail,idder,nlp,nlpi]; + fi; + fi; + prop:=quicks[propnum]; + nv:=[]; + nlp:=[]; + nlpi:=[]; + for j in [1..Length(pool)] do + v:=Immutable(prop(pool[j])); + p:=Position(nv,v); + if p=fail then + # new value -- add to lists + p:=PositionSorted(nv,v); + nv:=Concatenation(nv{[1..p-1]},[v],nv{[p..Length(nv)]}); + nlp:=Concatenation(nlp{[1..p-1]},[[]],nlp{[p..Length(nlp)]}); + nlpi:=Concatenation(nlpi{[1..p-1]},[[]],nlpi{[p..Length(nlpi)]}); + fi; + Add(nlp[p],pool[j]); + Add(nlpi[p],poolids[j]); + od; + if Length(nv)=1 then +# Print("no improve ",propnum,":",Length(pool),"\n"); + return trySplit(propnum+1,pool,poolids); + else +# Print("improve ",propnum,":",Length(pool),"->",List(nlp,Length),"\n"); + return [prop,nv, + List([1..Length(nlp)],x->trySplit(propnum+1,nlp[x],nlpi[x]))]; + fi; + end; + + tree:=trySplit(1,l,[1..Length(l)]); + return function(gp) + local node,v,p; + node:=tree; + while node[1]<>fail do + v:=Immutable(node[1](gp)); + p:=Position(node[2],v); + node:=node[3][p]; + od; + if node[2]<>fail then + v:=node[2](gp); + p:=PositionSorted(node[3],v); + else + p:=Position(node[3],gp); + fi; + return node[4][p]; + end; +end); + BindGlobal("DoMinimalFaithfulPermutationDegree", function(G,dorep) -local c,n,deg,ind,core,i,j,sum; +local c,n,deg,ind,core,i,j,sum,ma,h,ig,dec,bm,m,sel,ds,ise,cnt, + start,cind,nind,sl,idfun,spos,select,bla; + if Size(G)=1 then # option allows to calculate actual representation -- maybe access under # different name @@ -3366,36 +3444,130 @@ local c,n,deg,ind,core,i,j,sum; else return GroupHomomorphismByImages(G,Group(()),[One(G)],[()]); fi; + elif IsAbelian(G) then + c:=IndependentGeneratorsOfAbelianGroup(G); + if dorep=false then + return Sum(c,Order); + else + deg:=AbelianGroup(IsPermGroup,List(c,Order)); + return GroupHomomorphismByImagesNC(G,deg,c,GeneratorsOfGroup(deg)); + fi; fi; + c:=ConjugacyClassesSubgroups(G); # sort by reversed order to get core by inclusion test c:=ShallowCopy(c); # allow sorting SortBy(c,x->-Size(Representative(x))); - n:=Filtered(c,x->Size(x)=1); # normals - n:=List(n,Representative); + cind:=[]; + nind:=[]; + n:=[]; + for i in [1..Length(c)] do + if Size(c[i])=1 then + Add(n,Representative(c[i])); + nind[i]:=Length(n); + cind[Length(n)]:=i; + fi; + od; c:=List(c,Representative); # reps of classes + Info(InfoGroup,1, Length( n ), " normals ", Number( n, function ( x ) + return IsSubset( x, DerivedSubgroup( G ) ); end ), " abelfact" ); - deg:=List(n,x->[IndexNC(G,x),[Position(c,x)]]); # best known degrees for + deg:=List([1..Length(n)],x->[IndexNC(G,n[x]),[cind[x]]]); # best known degrees for # factors of each of n and how. + sel:=[]; + ds:=DerivedSubgroup(G); + if not IsPerfectGroup(G) then + # handle abelian quotients separately + ma:=MaximalAbelianQuotient(G); + h:=Image(ma); + ig:=IndependentGeneratorsOfAbelianGroup(h); + h:=Group(ig); + dec:=EpimorphismFromFreeGroup(h); + bm:=DiagonalMat(List(ig,Order)); + + for i in [2..Length(c)-1] do + if IsSubset(c[i],ds) then + Add(sel,i); + m:=List(bm,ShallowCopy); + for j in GeneratorsOfGroup(c[i]) do + Add(m,ExponentSums(UnderlyingElement(Factorization(h, + ImagesRepresentative(ma,j))))); + od; + m:=Filtered(DiagonalOfMat(SmithNormalFormIntegerMat(m)),x->x>1); + #j:=Position(n,c[i]); + j:=nind[i]; + deg[j]:=[Sum(m),[-j]]; + fi; + od; + fi; + + #indexing + idfun:=SubgroupPositionIdentifier(G,n); + sl:=Set(List(n,Size)); + start:=List(sl,x->0); + for i in [1..Length(n)] do + ind:=Position(sl,Size(n[i])); + if start[ind]=0 then start[ind]:=i;fi; + od; + + cnt:=Int(Length(c)/10); # determine minimal degrees by descending through lattice for i in [2..Length(c)-1] do # exclude trivial subgroup and whole group + if i=cnt then + #Print(Int(i/Length(c)*100),"% done\n"); + cnt:=cnt+Int(Length(c)/10); + fi; + ind:=IndexNC(G,c[i]); + spos:=PositionSorted(sl,Size(c[i]))-1; + + + if i in sel then + # do nothing --already processed + elif IsNormal(G,c[i]) then # subgroup normal, must be in other case + #core:=Position(n,c[i]); + core:=nind[i]; + + select:=fail; + if Size(c[i])>1 and 10*(Length(n)-start[spos])IsSubset(c[i],n[x])); + AddSet(select,core); +#Print("|select|=",Length(select),"\n"); + fi; - if IsNormal(G,c[i]) then # subgroup normal, must be in other case - core:=Position(n,c[i]); for j in [2..core-1] do # Intersect with all prior normals sum:=deg[core][1]+deg[j][1]; if sum50 then + bla:=Reversed(Filtered(select,x->deg[x][1]<=sum)); + if ForAny(bla,x->IsSubset(n[j],n[x])) then + ind:=fail; # intersection will not help with better degree + else + # otherwise try the rest + ind:=First(Difference(select,bla),x->IsSubset(n[j],n[x])); + fi; + else + ind:=First(select,x->IsSubset(n[j],n[x])); + fi; + if ind<>fail and sumIsSubset(c[i],n[x])); # position of core + # find size *strictly smaller* (since not normal) + if Length(n)-start[spos]<10000 then + core:=First([start[spos]..Length(n)],x->IsSubset(c[i],n[x])); # position of core + else + core:=Core(G,c[i]); + core:=idfun(core); + fi; if indFactorCosetAction(G,c[x])); + sum:=deg[Length(n)][2]; # the subgroups needed + #deg:=List(deg,x->FactorCosetAction(G,c[x])); + deg:=[]; + for i in sum do + if i>0 then Add(deg,FactorCosetAction(G,c[i])); + else + j:=NaturalHomomorphismByNormalSubgroupNC(G,n[-i]); + Add(deg,j*MinimalFaithfulPermutationRepresentation(Image(j,G))); + fi; + od; sum:=List(GeneratorsOfGroup(G),x->Image(deg[1],x)); for i in [2..Length(deg)] do diff --git a/tst/teststandard/permgrp.tst b/tst/teststandard/permgrp.tst index 2db111f47a..822efaae2a 100644 --- a/tst/teststandard/permgrp.tst +++ b/tst/teststandard/permgrp.tst @@ -140,10 +140,14 @@ true gap> Length(ConjugacyClasses(PSL(2,64))); 65 -# MinimalGeneratingSet +# MinimalGeneratingSet -- factor 400 speedup gap> AllTransitiveGroups(NrMovedPoints,12, > x->Length(MinimalGeneratingSet(x)),4); [ [3^4:2^3]E(4) ] +# MinimalFaithfulPermutationDegree +gap> MinimalFaithfulPermutationDegree(SmallGroup(5^6,33)); +55 + # gap> STOP_TEST( "permgrp.tst", 1);