diff --git a/lib/autsr.gi b/lib/autsr.gi index 29f1181e83..de67d2d35c 100644 --- a/lib/autsr.gi +++ b/lib/autsr.gi @@ -620,8 +620,7 @@ local ff,r,d,ser,u,v,i,j,k,p,bd,e,gens,lhom,M,N,hom,Q,Mim,q,ocr,split,MPcgs, # do we use induced radical automorphisms to help next step? if Size(KernelOfMultiplicativeGeneralMapping(hom))>1 and - Size(A)>10^8 and (IsAbelian(r) or - Length(AbelianInvariants(r))<10) + Size(A)>10^8 and (IsAbelian(r) or AbelianRank(r)<10) #( ## potentially large GL #Size(GL(Length(MPcgs),RelativeOrders(MPcgs)[1]))>10^10 and diff --git a/lib/ctbl.gd b/lib/ctbl.gd index 8f6f7cfa5a..cffa5d0c91 100644 --- a/lib/ctbl.gd +++ b/lib/ctbl.gd @@ -4436,11 +4436,11 @@ DeclareGlobalFunction( "NormalSubgroupClasses" ); ## Character( CharacterTable( S4 ), [ 3, 1, -1, 0, -1 ] ), ## Character( CharacterTable( S4 ), [ 1, 1, 1, 1, 1 ] ) ] ## gap> kernel:= KernelOfCharacter( irr[3] ); -## Group([ (1,2)(3,4), (1,3)(2,4) ]) +## Group([ (1,2)(3,4), (1,4)(2,3) ]) ## gap> HasNormalSubgroupClassesInfo( tbl ); ## true ## gap> NormalSubgroupClassesInfo( tbl ); -## rec( nsg := [ Group([ (1,2)(3,4), (1,3)(2,4) ]) ], +## rec( nsg := [ Group([ (1,2)(3,4), (1,4)(2,3) ]) ], ## nsgclasses := [ [ 1, 3 ] ], nsgfactors := [ ] ) ## gap> ClassPositionsOfNormalSubgroup( tbl, kernel ); ## [ 1, 3 ] diff --git a/lib/ghomperm.gi b/lib/ghomperm.gi index 8704e466f4..d8d72c9075 100644 --- a/lib/ghomperm.gi +++ b/lib/ghomperm.gi @@ -1964,6 +1964,13 @@ function( hom ) if IsEndoGeneralMapping( hom ) then + # cheap test for cycle structures + if Length(Set(List(MappingGeneratorsImages(hom), + x->List(x,CycleStructurePerm))))>1 + then + return false; + fi; + # test in transitive case whether we can realize in S_n # we do not yet compute the permutation here because we will still have to # test first whether it is in fact an inner automorphism: @@ -2106,9 +2113,11 @@ function( hom ) if rep<>fail then pi:=List([1..Length(orb)],x->MappingPermListList(Permuted(orb[x],rep[x]),orb[x])); rep:=Product(pi); - Assert(1,ForAll(genss,i->ImagesRepresentative(hom,i)=i^rep)); - SetConjugatorOfConjugatorIsomorphism( hom, rep ); - return true; + # must do final test, in case element maps to restricted perm + if ForAll(genss,i->ImagesRepresentative(hom,i)=i^rep) then + SetConjugatorOfConjugatorIsomorphism( hom, rep ); + return true; + fi; fi; if ValueOption("cheap")=true then diff --git a/lib/gpprmsya.gi b/lib/gpprmsya.gi index a5334b4d76..97b3a0b064 100644 --- a/lib/gpprmsya.gi +++ b/lib/gpprmsya.gi @@ -2320,6 +2320,8 @@ local G,max,dom,n,A,S,issn,p,i,j,m,k,powdec,pd,gps,v,invol,sel,mf,l,prim; fi; od; + Info(InfoPerformance,2,"Using Primitive Groups Library"); + # type (f): Almost simple if not PrimitiveGroupsAvailable(n) then Error("tables missing"); diff --git a/lib/grp.gd b/lib/grp.gd index c40b5ab3b9..264d4e866d 100644 --- a/lib/grp.gd +++ b/lib/grp.gd @@ -710,6 +710,9 @@ InstallTrueMethod( IsSimpleGroup, IsSporadicSimpleGroup ); DeclareProperty( "IsAlmostSimpleGroup", IsGroup ); InstallTrueMethod( IsGroup, IsAlmostSimpleGroup ); +# a simple group is almost simple +InstallTrueMethod( IsAlmostSimpleGroup, IsSimpleGroup ); + ############################################################################# ## @@ -858,6 +861,10 @@ InstallTrueMethod( IsPolycyclicGroup, ## DeclareAttribute( "AbelianInvariants", IsGroup ); +# minimal number of generators for abelianization. Used internally to check +# whether it is worth to attempt to reduce generator number +DeclareAttribute( "AbelianRank", IsGroup ); + ############################################################################# ## #A IsInfiniteAbelianizationGroup( ) @@ -1221,7 +1228,9 @@ DeclareAttribute("TryMaximalSubgroupClassReps",IsGroup,"mutable"); # utility function in maximal subgroups code DeclareGlobalFunction("TryMaxSubgroupTainter"); DeclareGlobalFunction("DoMaxesTF"); -DeclareGlobalFunction("MaxesAlmostSimple"); + +# make this an operation to allow for overloading and TryNextMethod(); +DeclareOperation("MaxesAlmostSimple",[IsGroup]); ############################################################################# ## @@ -1868,8 +1877,8 @@ DeclareAttribute( "MinimalNormalSubgroups", IsGroup ); ## returns a list of all normal subgroups of G. ## g:=SymmetricGroup(4);;NormalSubgroups(g); -## [ Sym( [ 1 .. 4 ] ), Alt( [ 1 .. 4 ] ), Group([ (1,4)(2,3), (1,2) -## (3,4) ]), Group(()) ] +## [ Sym( [ 1 .. 4 ] ), Alt( [ 1 .. 4 ] ), Group([ (1,4)(2,3), (1,3) +## (2,4) ]), Group(()) ] ## ]]> ##

## The algorithm for the computation of normal subgroups is described in diff --git a/lib/grp.gi b/lib/grp.gi index d4aa4ae6ce..6b2ca3bae8 100644 --- a/lib/grp.gi +++ b/lib/grp.gi @@ -701,6 +701,18 @@ InstallMethod( AbelianInvariants, return inv; end ); +InstallMethod( AbelianRank ,"generic method for groups", [ IsGroup ],0, +function(G) +local a,r; + a:=AbelianInvariants(G); + r:=Number(a,IsZero); + a:=Filtered(a,x->not IsZero(x)); + if Length(a)=0 then return r; fi; + a:=List(Set(a,SmallestRootInt),p->Number(a,x->x mod p=0)); + return r+Maximum(a); +end); + + ############################################################################# ## #M IsInfiniteAbelianizationGroup( ) diff --git a/lib/grpffmat.gi b/lib/grpffmat.gi index fed1aa76d2..5bc3f0928a 100644 --- a/lib/grpffmat.gi +++ b/lib/grpffmat.gi @@ -125,14 +125,26 @@ end ); ## #M NiceMonomorphism( ) ## +MakeThreadLocal("FULLGLNICOCACHE"); # avoid recreating same homom. repeatedly +FULLGLNICOCACHE:=[]; InstallGlobalFunction( NicomorphismFFMatGroupOnFullSpace, function( grp ) local field, dim, V, xset, nice; field := FieldOfMatrixGroup( grp ); dim := DimensionOfMatrixGroup( grp ); + + #check cache + V:=Size(field); + nice:=First(FULLGLNICOCACHE,x->x[1]=V and x[2]=dim); + if nice<>fail then return nice[3];fi; + + if not (HasIsNaturalGL(grp) and IsNaturalGL(grp)) then + grp:=GL(dim,field); # enforce map on full GL + fi; V := field ^ dim; xset := ExternalSet( grp, V ); + # STILL: reverse the base to get point sorting compatible with lexicographic # vector arrangement SetBaseOfGroup( xset, One( grp )); @@ -144,6 +156,16 @@ InstallGlobalFunction( NicomorphismFFMatGroupOnFullSpace, function( grp ) SetFilterObj(nice,IsNiceMonomorphism); # because we act on the full space we are canonical. SetIsCanonicalNiceMonomorphism(nice,true); + if Size(V)>10^5 then + # store only one big one and have it get thrown out quickly + FULLGLNICOCACHE[1]:=[Size(field),dim,nice]; + else + if Length(FULLGLNICOCACHE)>4 then + FULLGLNICOCACHE:=FULLGLNICOCACHE{[2..5]}; + fi; + Add(FULLGLNICOCACHE,[Size(field),dim,nice]); + fi; + return nice; end ); diff --git a/lib/grpfp.gi b/lib/grpfp.gi index 8a8bbf5fb1..743ceab477 100644 --- a/lib/grpfp.gi +++ b/lib/grpfp.gi @@ -93,6 +93,13 @@ InstallOtherMethod( Length, [ IsElementOfFpGroup and IsPackedElementDefaultRep ],0, x->Length(UnderlyingElement(x))); +InstallOtherMethod(Subword,"for an element of an f.p. group (default repres.)",true, + [ IsElementOfFpGroup and IsPackedElementDefaultRep, IsInt, IsInt ],0, +function(word,a,b) + return ElementOfFpGroup(FamilyObj(word),Subword(UnderlyingElement(word),a,b)); +end); + + ############################################################################# ## #M InverseOp( ) . . . . . . . . . . . . . . for element of f.p. group diff --git a/lib/grplatt.gd b/lib/grplatt.gd index 1d8910ece2..b902580149 100644 --- a/lib/grplatt.gd +++ b/lib/grplatt.gd @@ -439,6 +439,8 @@ DeclareGlobalFunction("TomDataSubgroupsAlmostSimple"); ## returned. If also a function dosub is given, maximal subgroups ## are only attempted if this function returns true (this is separated for ## performance reasons). +## In the example below, the result would be the same with leaving out the +## fourth function, but calculation this way is slightly faster. ## ## ## <#/GAPDoc> diff --git a/lib/grplatt.gi b/lib/grplatt.gi index 6e14cb213d..ee337435e7 100644 --- a/lib/grplatt.gi +++ b/lib/grplatt.gi @@ -2122,14 +2122,25 @@ local G, # group Info(InfoLattice,2,"Search involution"); # find involution in M/T + cnt:=0; repeat - repeat - inv:=Random(M); - until (Order(inv) mod 2 =0) and not inv in T; - o:=First([2..Order(inv)],i->inv^i in T); - until (o mod 2 =0); - Info(InfoLattice,2,"Element of order ",o); - inv:=inv^(o/2); # this is an involution in the factor + repeat + repeat + inv:=Random(M); + until (Order(inv) mod 2 =0) and not inv in T; + o:=First([2..Order(inv)],i->inv^i in T); + until (o mod 2 =0); + Info(InfoLattice,2,"Element of order ",o); + inv:=inv^(o/2); # this is an involution in the factor + + cnt:=cnt+1; + # in permgroups try to pick an involution that does not move all + # points. This can make the core of C to be computed quicker. + until not (IsPermGroup(M) and cnt<10 + and Length(MovedPoints(inv))=Length(MovedPoints(M))); + + + Assert(1,inv^2 in T and not inv in T); S:=Normalizer(G,T); # stabilize first component diff --git a/lib/grpnice.gi b/lib/grpnice.gi index fa8f6db39d..08976dea85 100644 --- a/lib/grpnice.gi +++ b/lib/grpnice.gi @@ -850,6 +850,13 @@ end); AttributeMethodByNiceMonomorphism( Size, [ IsGroup ] ); +############################################################################# +## +#M StructureDescription( ) +## +AttributeMethodByNiceMonomorphism( StructureDescription, + [ IsGroup ] ); + ############################################################################# ## diff --git a/lib/grppcext.gi b/lib/grppcext.gi index 886d5f1af5..73d6fce41c 100644 --- a/lib/grppcext.gi +++ b/lib/grppcext.gi @@ -495,7 +495,7 @@ end); InstallGlobalFunction( CompatiblePairs, function( arg ) local G, M, Mgrp, oper, A, B, D, translate, gens, genimgs, triso, K, K1, K2, f, tmp, Ggens, pcgs, l, idx, u, tup,Dos,elmlist,preimlist,pows, - baspt,newimgs,i,j,basicact; + baspt,newimgs,i,j,basicact,neu; # catch arguments G := arg[1]; @@ -694,24 +694,34 @@ local G, M, Mgrp, oper, A, B, D, translate, gens, genimgs, triso, K, K1, tmp:=List(genimgs,x->x[1]); preimlist:=List(tmp,x->[x,List(Ggens,y->PreImagesRepresentative(x,y))]); - # ensure wa also account for action + # ensure we also account for action u:=Group(tup); elmlist:=AsSSortedList(u); - tmp:=GeneratorsOfGroup(u); + tmp:=SmallGeneratingSet(u); i:=1; while elmlist<>fail and i<=Length(tmp) do - for j in genimgs do - if elmlist<>fail and not tmp[i]^j[2] in elmlist then - u:=ClosureGroup(u,tmp[i]^j[2]); + j:=1; + while j<=Length(genimgs) do + neu:=tmp[i]^genimgs[j][2]; + if elmlist<>fail and not neu in elmlist then + u:=ClosureGroup(u,neu); if Size(u)>50000 then # catch cases of too many elements. elmlist:=fail; f:=basicact; + j:=Length(genimgs)+1; else elmlist:=AsSSortedList(u); - tmp:=GeneratorsOfGroup(u); + if Length(SmallGeneratingSet(u))G-conjugacy. ##

## The optional argument opt is a record, which may -## be used to put restrictions on the subgroups computed. The following record -## components of opt are recognized and have the following effects: +## be used to suggest restrictions on the subgroups computed. +## The following record +## components of opt are recognized and have the following effects. +## Note that all of the following +## restrictions to subgroups with particular properties are +## only used to speed up the calculation, but the result might still contain +## subgroups (that had to be computed in any case) that do not satisfy the +## properties. If this is not desired, the calculation must be followed by an +## explicit test for the desired properties (which is not done by default, as +## it would be a general slowdown). +## The function guarantees that representatives of all subgroups that +## satisfy the properties are found, i.e. there can be only false positives. ## ## actions ## diff --git a/lib/grppclat.gi b/lib/grppclat.gi index 159a362714..5b9380e46a 100644 --- a/lib/grppclat.gi +++ b/lib/grppclat.gi @@ -1201,7 +1201,7 @@ InstallMethod(CharacteristicSubgroups,"solvable, automorphisms",true, [IsGroup and IsSolvableGroup],0, function(G) local A,s; - if Length(AbelianInvariants(G))<5 then + if AbelianRank(G)<5 then TryNextMethod(); fi; A:=AutomorphismGroup(G); diff --git a/lib/grpperm.gi b/lib/grpperm.gi index 0b58877e72..e842966bd7 100644 --- a/lib/grpperm.gi +++ b/lib/grpperm.gi @@ -1519,7 +1519,7 @@ end ); ## #M Socle( ) . . . . . . . . . . . socle of primitive permutation group ## -InstallMethod( Socle,"for permgrp", true, [ IsPermGroup ], 0, +InstallMethod( Socle,"test primitive", true, [ IsPermGroup ], 0, function( G ) local Omega, deg, shortcut, coll, d, m, c, ds, L, z, ord, p, i; @@ -1539,25 +1539,27 @@ InstallMethod( Socle,"for permgrp", true, [ IsPermGroup ], 0, deg := Length( Omega ); if deg >= 6103515625 then TryNextMethod(); - elif deg < 12960000 then - shortcut := true; - if deg >= 3125 then - coll := Collected( Factors(Integers, deg ) ); - d := Gcd( List( coll, c -> c[ 2 ] ) ); - if d mod 5 = 0 then - m := 1; - for c in coll do - m := m * c[ 1 ] ^ ( c[ 2 ] / d ); - od; - if m >= 5 then - shortcut := false; - fi; - fi; - fi; - if shortcut then - ds := DerivedSeriesOfGroup( G ); - return ds[ Length( ds ) ]; - fi; + # the normal closure actually seems to be faster than derived series, so + # this is not really a shortcut + #elif deg < 12960000 then + # shortcut := true; + # if deg >= 3125 then + # coll := Collected( Factors( deg ) ); + # d := Gcd( List( coll, c -> c[ 2 ] ) ); + # if d mod 5 = 0 then + # m := 1; + # for c in coll do + # m := m * c[ 1 ] ^ ( c[ 2 ] / d ); + # od; + # if m >= 5 then + # shortcut := false; + # fi; + # fi; + # fi; + # if shortcut then + # ds := DerivedSeriesOfGroup( G ); + # return ds[ Length( ds ) ]; + # fi; fi; coll := Collected( Factors(Integers, Size( G ) ) ); @@ -1577,7 +1579,10 @@ InstallMethod( Socle,"for permgrp", true, [ IsPermGroup ], 0, until ord mod p = 0; z := z ^ ( ord / p ); until Index( G, Centralizer( G, z ) ) mod p <> 0; - L := NormalClosure( G, SubgroupNC( G, [ z ] ) ); + + # immediately add conjugate as this will be needed anyhow and seems to + # speed up the closure process + L := NormalClosure( G, SubgroupNC( G, [ z,z^Random(G) ] ) ); if deg >= 78125 then ds := DerivedSeriesOfGroup( L ); L := ds[ Length( ds ) ]; diff --git a/lib/integer.gi b/lib/integer.gi index 1daee58305..155ecf1351 100644 --- a/lib/integer.gi +++ b/lib/integer.gi @@ -744,7 +744,7 @@ end); ## #F PrimeDivisors( ) . . . . . . . . . . . . . . list of prime divisors ## -## delegating to FactorsInt +## delegating to Factors ## InstallMethod( PrimeDivisors, "for integer", [ IsInt ], function(n) if n = 0 then @@ -756,7 +756,7 @@ InstallMethod( PrimeDivisors, "for integer", [ IsInt ], function(n) if n = 1 then return []; fi; - return Set(FactorsInt(n)); + return Set(Factors(Integers,n)); end); @@ -1090,7 +1090,7 @@ InstallGlobalFunction(PrimePowersInt,function( n ) elif n < 0 then n := -1 * n; fi; - return Flat(Collected(FactorsInt(n))); + return Flat(Collected(Factors(Integers,n))); end); diff --git a/lib/maxsub.gi b/lib/maxsub.gi index 358666bdda..0debf3f803 100644 --- a/lib/maxsub.gi +++ b/lib/maxsub.gi @@ -536,42 +536,16 @@ local hom,embs,s,k,agens,ad,i,j,perm,dia,ggens,e,tgens,d,m,reco,emba,outs,id; return m; end); -InstallGlobalFunction(MaxesAlmostSimple,function(G) -local id,m,epi,cnt,h; - - # is a permutation degree too big? - if IsPermGroup(G) then - if NrMovedPoints(G)> - SufficientlySmallDegreeSimpleGroupOrder(Size(PerfectResiduum(G))) then - h:=G; - for cnt in [1..5] do - epi:=SmallerDegreePermutationRepresentation(h); - if NrMovedPoints(Range(epi))PreImage(epi,x)); - return m; - fi; - # new group to avoid storing the map - h:=Group(GeneratorsOfGroup(G)); - SetSize(h,Size(G)); - od; - fi; - - - # Are just finding out that a group is symmetric or alternating? - # if so, try to use method that uses data library - if - #not (HasIsNaturalSymmetricGroup(G) or HasIsNaturalAlternatingGroup(G)) and - (IsNaturalSymmetricGroup(G) or IsNaturalAlternatingGroup(G)) then - Info(InfoLattice,1,"MaxesAlmostSimple: Use S_n/A_n"); - m:=MaximalSubgroupsSymmAlt(G,false); - if m<>fail then - return m; - fi; - fi; - fi; +InstallMethod(MaxesAlmostSimple,"fallback to lattice",true,[IsGroup],0, +function(G) + if ValueOption("cheap")=true then return [];fi; + Info(InfoLattice,1,"MaxesAlmostSimple: Fallback to lattice"); + return MaxesByLattice(G); +end); - # is the degree bad? +InstallMethod(MaxesAlmostSimple,"table of marks and linear",true,[IsGroup],0, +function(G) +local m,id,epi; # does the table of marks have it? m:=TomDataMaxesAlmostSimple(G); @@ -595,10 +569,41 @@ local id,m,epi,cnt,h; fi; fi; + TryNextMethod(); +end); - if ValueOption("cheap")=true then return [];fi; - Info(InfoLattice,1,"MaxesAlmostSimple: Fallback to lattice"); - return MaxesByLattice(G); +InstallMethod(MaxesAlmostSimple,"permutation group",true,[IsPermGroup],0, +function(G) +local m,epi,cnt,h; + + # Are we just finding out that a group is symmetric or alternating? + # if so, try to use method that uses data library + if (IsNaturalSymmetricGroup(G) or IsNaturalAlternatingGroup(G)) then + Info(InfoLattice,1,"MaxesAlmostSimple: Use S_n/A_n"); + m:=MaximalSubgroupsSymmAlt(G,false); + if m<>fail then + return m; + fi; + fi; + + # is a permutation degree too big? + if NrMovedPoints(G)> + SufficientlySmallDegreeSimpleGroupOrder(Size(PerfectResiduum(G))) then + h:=G; + for cnt in [1..5] do + epi:=SmallerDegreePermutationRepresentation(h); + if NrMovedPoints(Range(epi))PreImage(epi,x)); + return m; + fi; + # re-create group to avoid storing the map + h:=Group(GeneratorsOfGroup(G)); + SetSize(h,Size(G)); + od; + fi; + + TryNextMethod(); end); BindGlobal("MaxesType4a",function(w,G,a,t,n) diff --git a/lib/morpheus.gi b/lib/morpheus.gi index 8c53229076..da48a8dad7 100644 --- a/lib/morpheus.gi +++ b/lib/morpheus.gi @@ -1267,8 +1267,7 @@ local G,cl,lcl,len,comb,combc,com,a,cnt,s,alltwo; #create just a list of ordinary classes. lcl:=List(cl,i->Concatenation(List(i,j->j.classes))); len:=1; - len:=Maximum(1,Length(MinimalGeneratingSet( - Image(IsomorphismPcGroup((G/DerivedSubgroup(G))))))-1); + len:=Maximum(1,AbelianRank(G)-1); while true do len:=len+1; Info(InfoMorph,2,"Trying length ",len); @@ -2188,8 +2187,8 @@ local m; return fail; fi; - if (Length(AbelianInvariants(G))>2 or Length(SmallGeneratingSet(G))>2) and Size(RadicalGroup(G))>1 then - # In place until a proper implementation of Cannon/Holt automorphism is + if (AbelianRank(G)>2 or Length(SmallGeneratingSet(G))>2) and Size(RadicalGroup(G))>1 then + # In place until a proper implementation of Cannon/Holt isomorphism is # made available. return PatheticIsomorphism(G,H); fi; diff --git a/lib/permutat.g b/lib/permutat.g index 144738e4f8..65bc89834f 100644 --- a/lib/permutat.g +++ b/lib/permutat.g @@ -780,6 +780,7 @@ InstallMethod( Order, [ IsPerm ], ORDER_PERM ); + ############################################################################# ## #O DistancePerms( , ) . returns NrMovedPoints( / ) diff --git a/tst/testbugfix/2018-08-22-IsConjugatorAutomorphism.tst b/tst/testbugfix/2018-08-22-IsConjugatorAutomorphism.tst new file mode 100644 index 0000000000..a71bd9dabd --- /dev/null +++ b/tst/testbugfix/2018-08-22-IsConjugatorAutomorphism.tst @@ -0,0 +1,4 @@ +gap> a:=Group((9,11)(10,12)(13,15)(14,16), (1,5,3,7)(2,6,4,8));; +gap> hom:=GroupHomomorphismByImages(a,a,[a.1,a.2*a.1],[a.1,a.2]);; +gap> IsConjugatorAutomorphism(hom); +false diff --git a/tst/testbugfix/2018-09-05-CacheGL.tst b/tst/testbugfix/2018-09-05-CacheGL.tst new file mode 100644 index 0000000000..0af0ce6150 --- /dev/null +++ b/tst/testbugfix/2018-09-05-CacheGL.tst @@ -0,0 +1,5 @@ +gap> g:=SL(4,3);; +gap> NiceMonomorphism(g);; +gap> g:=GL(4,3);; +gap> hom:=NiceMonomorphism(g);; +gap> List(GeneratorsOfGroup(g),x->Image(hom,x));;