From 5e589c4cacf429c1e3e221936a913272476c0738 Mon Sep 17 00:00:00 2001 From: Chris Wensley Date: Wed, 28 Sep 2022 17:21:20 +0100 Subject: [PATCH 001/234] methods for PreImRep renamed PreImRepNC --- lib/alghom.gi | 26 +++++++--- lib/fldabnum.gi | 12 ++--- lib/ghom.gi | 32 ++++++------ lib/ghomfp.gi | 14 +++--- lib/ghompcgs.gi | 8 +-- lib/ghomperm.gi | 38 +++++++------- lib/gprdmat.gi | 12 ++--- lib/gprdperm.gi | 26 +++++----- lib/grpmat.gi | 10 ++-- lib/grpnice.gd | 2 +- lib/grpnice.gi | 26 +++++----- lib/mapping.gd | 131 +++++++++++++++++++++++++++++++++++++++--------- lib/mapping.gi | 87 +++++++++++++++++++++----------- lib/mapprep.gi | 106 +++++++++++++++++++-------------------- lib/mgmring.gi | 8 +-- lib/oprt.gi | 10 ++-- lib/relation.gi | 26 +++++----- lib/ringhom.gi | 4 +- lib/vspchom.gi | 8 +-- 19 files changed, 353 insertions(+), 233 deletions(-) diff --git a/lib/alghom.gi b/lib/alghom.gi index eb13ca914e..0ea9c60808 100644 --- a/lib/alghom.gi +++ b/lib/alghom.gi @@ -578,16 +578,26 @@ InstallMethod( ImagesRepresentative, ############################################################################# ## -#M PreImagesRepresentative( , ) . . . . . . for algebra g.m.b.i. +#M PreImagesRepresentativeNC( , ) . . . . . for algebra g.m.b.i. ## -InstallMethod( PreImagesRepresentative, +InstallMethod( PreImagesRepresentativeNC, "for algebra g.m.b.i., and element", FamRangeEqFamElm, [ IsGeneralMapping and IsAlgebraGeneralMappingByImagesDefaultRep, IsObject ], function( map, elm ) - return PreImagesRepresentative( AsLeftModuleGeneralMappingByImages(map), - elm ); + return PreImagesRepresentativeNC( + AsLeftModuleGeneralMappingByImages(map), elm ); + end ); + +InstallMethod( PreImagesRepresentativeNC, + "for algebra g.m.b.i. knowing inverse, and element", + FamRangeEqFamElm, + [ IsGeneralMapping and IsAlgebraGeneralMappingByImagesDefaultRep + and HasInverseGeneralMapping, + IsObject ], + function( map, elm ) + return ImagesRepresentative( InverseGeneralMapping(map), elm ); end ); @@ -905,7 +915,7 @@ InstallMethod( ImagesRepresentative, ############################################################################# ## -#M PreImagesRepresentative( , ) +#M PreImagesRepresentativeNC( , ) ## BindGlobal( "PreImagesRepresentativeOperationAlgebraHomomorphism", function( ophom, mat ) if not IsBound( ophom!.basisImage ) then @@ -918,7 +928,7 @@ BindGlobal( "PreImagesRepresentativeOperationAlgebraHomomorphism", function( oph return mat; end ); -InstallMethod( PreImagesRepresentative, +InstallMethod( PreImagesRepresentativeNC, "for an operation algebra homomorphism, and an element", FamRangeEqFamElm, [ IsOperationAlgebraHomomorphismDefaultRep, IsMatrix ], @@ -1080,9 +1090,9 @@ InstallMethod( ImagesRepresentative, ############################################################################# ## -#M PreImagesRepresentative( , ) +#M PreImagesRepresentativeNC( , ) ## -InstallMethod( PreImagesRepresentative, +InstallMethod( PreImagesRepresentativeNC, "for an alg. hom. from f. p. algebra, and an element", FamRangeEqFamElm, [ IsAlgebraHomomorphismFromFpRep, IsMatrix ], diff --git a/lib/fldabnum.gi b/lib/fldabnum.gi index 5902772c5e..41d6adb98e 100644 --- a/lib/fldabnum.gi +++ b/lib/fldabnum.gi @@ -1918,9 +1918,9 @@ InstallMethod( PreImageElm, ############################################################################# ## -#M PreImagesElm( , ) . . . . . . for autom. of ab. number fields +#M PreImagesElmNC( , ) . . . . . for autom. of ab. number fields ## -InstallMethod( PreImagesElm, +InstallMethod( PreImagesElmNC, "for ANF automorphism and scalar", FamRangeEqFamElm, [ IsFieldHomomorphism and IsANFAutomorphismRep, IsScalar ], @@ -1932,9 +1932,9 @@ InstallMethod( PreImagesElm, ############################################################################# ## -#M PreImagesSet( , ) . . . . . for autom. of ab. number fields +#M PreImagesSetNC( , ) . . . . for autom. of ab. number fields ## -InstallMethod( PreImagesSet, +InstallMethod( PreImagesSetNC, "for ANF automorphism and scalar", CollFamRangeEqFamElms, [ IsFieldHomomorphism and IsANFAutomorphismRep, IsField ], @@ -1945,9 +1945,9 @@ InstallMethod( PreImagesSet, ############################################################################# ## -#M PreImagesRepresentative( , ) . for autom. of ab. number fields +#M PreImagesRepresentativeNC( , ) for autom. of ab. number fields ## -InstallMethod( PreImagesRepresentative, +InstallMethod( PreImagesRepresentativeNC, "for ANF automorphism and scalar", FamRangeEqFamElm, [ IsFieldHomomorphism and IsANFAutomorphismRep, IsScalar ], diff --git a/lib/ghom.gi b/lib/ghom.gi index 35462fcc8e..fa6f9cdb51 100644 --- a/lib/ghom.gi +++ b/lib/ghom.gi @@ -261,9 +261,9 @@ end ); ############################################################################# ## -#M PreImagesRepresentative( , ) . . . . . . . . . . . via images +#M PreImagesRepresentativeNC( , ) . . . . . . . . . . via images ## -InstallMethod( PreImagesRepresentative, "for PBG-Hom", FamRangeEqFamElm, +InstallMethod( PreImagesRepresentativeNC, "for PBG-Hom", FamRangeEqFamElm, [ IsPreimagesByAsGroupGeneralMappingByImages, IsMultiplicativeElementWithInverse ], 0, function( hom, elm ) @@ -272,7 +272,7 @@ function( hom, elm ) # group return ImagesRepresentative( RestrictedInverseGeneralMapping( hom ), elm ); else - return PreImagesRepresentative( AsGroupGeneralMappingByImages( hom ), elm ); + return PreImagesRepresentativeNC( AsGroupGeneralMappingByImages( hom ), elm ); fi; end ); @@ -883,19 +883,17 @@ InstallMethod( ImagesRepresentative, ############################################################################# ## -#M PreImagesRepresentative( , ) . . . . . . . . . . . . for GHBI +#M PreImagesRepresentativeNC( , ) . . . . . . . . . . . for GHBI ## -InstallMethod( PreImagesRepresentative, - "for GHBI and mult.-elm.-with-inverse", - FamRangeEqFamElm, - [ IsGroupGeneralMappingByImages, - IsMultiplicativeElementWithInverse ], 0, - function( hom, elm ) - if IsBound( hom!.images ) and elm in hom!.images then - return hom!.elements[ Position( hom!.images, elm ) ]; - else - return ImagesRepresentative( RestrictedInverseGeneralMapping( hom ), elm ); - fi; +InstallMethod( PreImagesRepresentativeNC, + "for GHBI and mult.-elm.-with-inverse", FamRangeEqFamElm, + [ IsGroupGeneralMappingByImages, IsMultiplicativeElementWithInverse ], 0, +function( hom, elm ) + if IsBound( hom!.images ) and elm in hom!.images then + return hom!.elements[ Position( hom!.images, elm ) ]; + else + return ImagesRepresentative( RestrictedInverseGeneralMapping( hom ), elm ); + fi; end ); @@ -1227,9 +1225,9 @@ InstallMethod( ImagesSet, ############################################################################# ## -#M PreImagesRepresentative( , ) . . . . for conjugator isomorphism +#M PreImagesRepresentativeNC( , ) . . . for conjugator isomorphism ## -InstallMethod( PreImagesRepresentative, +InstallMethod( PreImagesRepresentativeNC, "for conjugator isomorphism", FamRangeEqFamElm, [ IsConjugatorIsomorphism, IsMultiplicativeElementWithInverse ], 0, diff --git a/lib/ghomfp.gi b/lib/ghomfp.gi index 9a82cb7967..59be7fcbd5 100644 --- a/lib/ghomfp.gi +++ b/lib/ghomfp.gi @@ -527,9 +527,9 @@ end); ############################################################################# ## -#M PreImagesSet( , ) +#M PreImagesSetNC( , ) ## -InstallMethod( PreImagesSet, "map from (sub)group of fp group", +InstallMethod( PreImagesSetNC, "map from (sub)group of fp group", CollFamRangeEqFamElms, [ IsFromFpGroupHomomorphism,IsGroup ],0, function(hom,u) @@ -718,9 +718,9 @@ end); ############################################################################# ## -#M PreImagesRepresentative +#M PreImagesRepresentativeNC ## -InstallMethod( PreImagesRepresentative, +InstallMethod( PreImagesRepresentativeNC, "hom. to standard generators of fp group, using 'MappedWord'", FamRangeEqFamElm, [IsToFpGroupHomomorphismByImages,IsMultiplicativeElementWithInverse], @@ -1282,7 +1282,7 @@ local v,aiu,aiv,G,primes,irrel,ma,mau,a,k,gens,imgs,q,dec,deco,piv,co; fi; gens:=SmallGeneratingSet(a); - imgs:=List(gens,x->Image(mau,Image(hom,PreImagesRepresentative(ma,x)))); + imgs:=List(gens,x->Image(mau,Image(hom,PreImagesRepresentativeNC(ma,x)))); q:=GroupHomomorphismByImages(a,Image(mau),gens,imgs); k:=KernelOfMultiplicativeGeneralMapping(q); @@ -1293,7 +1293,7 @@ local v,aiu,aiv,G,primes,irrel,ma,mau,a,k,gens,imgs,q,dec,deco,piv,co; dec:=EpimorphismFromFreeGroup(Group(gens)); deco:=function(x) local i; - x:=ExponentSums(PreImagesRepresentative(dec,x)); + x:=ExponentSums(PreImagesRepresentativeNC(dec,x)); for i in [1..Length(aiv)] do x[i]:=x[i] mod aiv[i]; od; @@ -1330,7 +1330,7 @@ local hom,pcgs,impcgs; impcgs:=FamilyPcgs(Image(hom,M)); pcgs:=PcgsByPcSequenceCons(IsPcgsDefaultRep,IsModuloPcgsFpGroupRep, ElementsFamily(FamilyObj(M)), - List(impcgs,i->PreImagesRepresentative(hom,i)), + List(impcgs,i->PreImagesRepresentativeNC(hom,i)), [] ); pcgs!.hom:=hom; diff --git a/lib/ghompcgs.gi b/lib/ghompcgs.gi index f17db8b36c..f3fb30ddda 100644 --- a/lib/ghompcgs.gi +++ b/lib/ghompcgs.gi @@ -503,9 +503,9 @@ end); ############################################################################# ## -#M PreImagesRepresentative( , ) . . . . . . . . . . . via images +#M PreImagesRepresentativeNC( , ) . . . . . . . . . . via images ## -InstallMethod( PreImagesRepresentative, "method for pcgs hom", +InstallMethod( PreImagesRepresentativeNC, "method for pcgs hom", FamRangeEqFamElm, [ IsToPcGroupHomomorphismByImages,IsMultiplicativeElementWithInverse ], 0, function( hom, elm ) @@ -627,9 +627,9 @@ end ); ############################################################################# ## -#M PreImagesRepresentative( , ) . . . . . . . . . . via depth map +#M PreImagesRepresentativeNC( , ) . . . . . . . . . via depth map ## -InstallMethod( PreImagesRepresentative, FamRangeEqFamElm, +InstallMethod( PreImagesRepresentativeNC, FamRangeEqFamElm, [ IsPcgsToPcgsHomomorphism,IsMultiplicativeElementWithInverse ], 0, function( hom, elm ) local exp; diff --git a/lib/ghomperm.gi b/lib/ghomperm.gi index 2f103a6a37..b29b194847 100644 --- a/lib/ghomperm.gi +++ b/lib/ghomperm.gi @@ -11,9 +11,9 @@ ############################################################################# ## -#M PreImagesSet( , ) . for s.p. gen. mapping resp. mult. & inv. +#M PreImagesSetNC( , ) for s.p. gen. mapping resp. mult. & inv. ## -InstallMethod( PreImagesSet, +InstallMethod( PreImagesSetNC, "method for permgroup homs", CollFamRangeEqFamElms, [ IsPermGroupHomomorphism, IsGroup ], @@ -22,7 +22,7 @@ local genpreimages, pre,kg,sz,ol,orb,pos,dom,one; genpreimages:=GeneratorsOfMagmaWithInverses( elms ); genpreimages:= List(genpreimages, - gen -> PreImagesRepresentative( map, gen ) ); + gen -> PreImagesRepresentativeNC( map, gen ) ); if fail in genpreimages then TryNextMethod(); fi; @@ -1152,7 +1152,7 @@ local r, fgens, gens, kg; fi; fgens:=ShallowCopy(GeneratorsOfGroup(r)); gens:=List(fgens, - i->PreImagesRepresentative(hom2,PreImagesRepresentative(hom1,i))); + i->PreImagesRepresentativeNC(hom2,PreImagesRepresentativeNC(hom1,i))); kg:=GeneratorsOfGroup(KernelOfMultiplicativeGeneralMapping(hom2)); Append(gens,kg); Append(fgens,List(kg,i->One(r))); @@ -1162,13 +1162,13 @@ end); ############################################################################# ## -#M PreImagesRepresentative( , ) . . . . . . for perm group range +#M PreImagesRepresentativeNC( , ) . . . . . for perm group range ## -InstallMethod( PreImagesRepresentative, FamRangeEqFamElm, +InstallMethod( PreImagesRepresentativeNC, FamRangeEqFamElm, [ IsToPermGroupGeneralMappingByImages, IsMultiplicativeElementWithInverse ], 0, - function( hom, elm ) - return ImagesRepresentative( RestrictedInverseGeneralMapping( hom ), elm ); +function( hom, elm ) + return ImagesRepresentative( RestrictedInverseGeneralMapping( hom ), elm ); end ); ############################################################################# @@ -1562,10 +1562,10 @@ InstallMethod( ImagesSource,"constituent homomorphism",true, ############################################################################# ## -#M PreImagesRepresentative( , ) +#M PreImagesRepresentativeNC( , ) ## -InstallMethod( PreImagesRepresentative,"constituent homomorphism", - FamRangeEqFamElm,[IsConstituentHomomorphism,IsPerm], 0, +InstallMethod( PreImagesRepresentativeNC, "constituent homomorphism", + FamRangeEqFamElm, [IsConstituentHomomorphism,IsPerm], 0, function( hom, elm ) local D,DP; if not HasStabChainMutable(Source(hom)) then @@ -1579,9 +1579,9 @@ end); ############################################################################# ## -#M PreImagesSet( , ) . . . . . . . . . . . . . . . . for const hom +#M PreImagesSetNC( , ) . . . . . . . . . . . . . . . . for const hom ## -InstallMethod( PreImagesSet, "constituent homomorphism",CollFamRangeEqFamElms, +InstallMethod( PreImagesSetNC, "constituent homomorphism",CollFamRangeEqFamElms, [ IsConstituentHomomorphism, IsPermGroup ], 0, function( hom, I ) local H, # preimage of , result @@ -1594,7 +1594,7 @@ InstallMethod( PreImagesSet, "constituent homomorphism",CollFamRangeEqFamElms, # create the preimage group H := EmptyStabChain( [ ], One( Source( hom ) ) ); S := ConjugateStabChain( StabChainMutable( I ), H, x -> - PreImagesRepresentative( hom, x ), hom!.conperm ^ -1 ); + PreImagesRepresentativeNC( hom, x ), hom!.conperm ^ -1 ); T := H; while IsBound( T.stabilizer ) do AddGeneratorsExtendSchreierTree( T, GeneratorsOfGroup( K ) ); @@ -1817,9 +1817,9 @@ end ); ############################################################################# ## -#M PreImagesRepresentative( , ) . . . . . . . . . for blocks hom +#M PreImagesRepresentativeNC( , ) . . . . . . . . for blocks hom ## -InstallMethod( PreImagesRepresentative, "blocks homomorphism", +InstallMethod( PreImagesRepresentativeNC, "blocks homomorphism", FamRangeEqFamElm, [ IsBlocksHomomorphism, IsMultiplicativeElementWithInverse ], 0, function( hom, elm ) @@ -1869,9 +1869,9 @@ end) ; ############################################################################# ## -#M PreImagesSet( , ) . . . . . . . . . . . . . . . for blocks hom +#M PreImagesSetNC( , ) . . . . . . . . . . . . . . for blocks hom ## -InstallMethod( PreImagesSet, CollFamRangeEqFamElms, +InstallMethod( PreImagesSetNC, CollFamRangeEqFamElms, [ IsBlocksHomomorphism, IsPermGroup ], 0, function( hom, I ) local H; # preimage of under , result @@ -1905,7 +1905,7 @@ InstallGlobalFunction( PreImageSetStabBlocksHomomorphism, function( hom, I ) H := PreImageSetStabBlocksHomomorphism( hom, I.stabilizer ); ChangeStabChain( H, [ pnt ], false ); for gen in I.generators do - pre := PreImagesRepresentative( hom, gen ); + pre := PreImagesRepresentativeNC( hom, gen ); if not IsBound( H.translabels[ pnt ^ pre ] ) then AddGeneratorsExtendSchreierTree( H, [ pre ] ); fi; diff --git a/lib/gprdmat.gi b/lib/gprdmat.gi index 2480d861d1..7c64886cf1 100644 --- a/lib/gprdmat.gi +++ b/lib/gprdmat.gi @@ -143,9 +143,9 @@ end); ############################################################################# ## -#M PreImagesRepresentative(,) . . . . . . . . . . . of embedding +#M PreImagesRepresentativeNC(,) . . . . . . . . . . . of embedding ## -InstallMethod(PreImagesRepresentative,"matrix direct product embedding", +InstallMethod(PreImagesRepresentativeNC,"matrix direct product embedding", FamRangeEqFamElm, [ IsEmbeddingDirectProductMatrixGroup, IsMultiplicativeElementWithInverse ], @@ -206,9 +206,9 @@ end); ############################################################################# ## -#M PreImagesRepresentative(,) . . . . . . . . . . . of projection +#M PreImagesRepresentativeNC(,) . . . . . . . . . . . of projection ## -InstallMethod(PreImagesRepresentative,"matrix direct product projection", +InstallMethod(PreImagesRepresentativeNC,"matrix direct product projection", FamRangeEqFamElm, [ IsProjectionDirectProductMatrixGroup, IsMultiplicativeElementWithInverse ],0, @@ -382,9 +382,9 @@ end); ############################################################################# ## -#M PreImagesRepresentative( , ) . . . . . . . . . . . of embedding +#M PreImagesRepresentativeNC( , ) . . . . . . . . . . of embedding ## -InstallMethod( PreImagesRepresentative, +InstallMethod( PreImagesRepresentativeNC, "imprim matrix wreath product embedding", FamRangeEqFamElm, [ IsEmbeddingImprimitiveWreathProductMatrixGroup, IsMultiplicativeElementWithInverse ], 0, diff --git a/lib/gprdperm.gi b/lib/gprdperm.gi index 327f812adc..bb21e9b388 100644 --- a/lib/gprdperm.gi +++ b/lib/gprdperm.gi @@ -169,9 +169,9 @@ end ); ############################################################################# ## -#M PreImagesRepresentative( , ) . . . . . . . . . . . of embedding +#M PreImagesRepresentativeNC( , ) . . . . . . . . . . of embedding ## -InstallMethod( PreImagesRepresentative, "perm direct product embedding", +InstallMethod( PreImagesRepresentativeNC, "perm direct product embedding", FamRangeEqFamElm, [ IsEmbeddingDirectProductPermGroup, IsMultiplicativeElementWithInverse ], @@ -292,9 +292,9 @@ end ); ############################################################################# ## -#M PreImagesRepresentative( , ) . . . . . . . . . . . of projection +#M PreImagesRepresentativeNC( , ) . . . . . . . . . . of projection ## -InstallMethod( PreImagesRepresentative,"perm direct product projection", +InstallMethod( PreImagesRepresentativeNC,"perm direct product projection", FamRangeEqFamElm, [ IsProjectionDirectProductPermGroup, IsMultiplicativeElementWithInverse ], 0, @@ -388,7 +388,7 @@ InstallMethod( SubdirectProductOp,"permgroup", true, # over the generators of the kernel of $phi_2$. gens := []; for gen in GeneratorsOfGroup( G1 ) do - Add( gens, gen^emb1 * PreImagesRepresentative(phi2,gen^phi1)^emb2 ); + Add( gens, gen^emb1*PreImagesRepresentativeNC(phi2,gen^phi1)^emb2 ); od; for gen in GeneratorsOfGroup( KernelOfMultiplicativeGeneralMapping( phi2 ) ) do @@ -466,9 +466,9 @@ end ); ############################################################################# ## -#M PreImagesRepresentative( , ) . . . . . . . . . . . of projection +#M PreImagesRepresentativeNC( , ) . . . . . . . . . . of projection ## -InstallMethod( PreImagesRepresentative,"perm subdirect product projection", +InstallMethod( PreImagesRepresentativeNC,"perm subdirect product projection", FamRangeEqFamElm, [ IsProjectionSubdirectProductPermGroup, IsMultiplicativeElementWithInverse ], 0, @@ -487,11 +487,11 @@ InstallMethod( PreImagesRepresentative,"perm subdirect product projection", # compute the preimage if 1 = prj!.component then - elm := img ^ info.perms[1] - * PreImagesRepresentative(phi2,img^phi1) ^ info.perms[2]; + elm := img ^ info.perms[1] + * PreImagesRepresentativeNC(phi2,img^phi1) ^ info.perms[2]; else - elm := img ^ info.perms[2] - * PreImagesRepresentative(phi1,img^phi2) ^ info.perms[1]; + elm := img ^ info.perms[2] + * PreImagesRepresentativeNC(phi1,img^phi2) ^ info.perms[1]; fi; # return the preimage @@ -799,9 +799,9 @@ end ); ############################################################################# ## -#M PreImagesRepresentative( , ) . . . . . . . . . . . of embedding +#M PreImagesRepresentativeNC( , ) . . . . . . . . . . of embedding ## -InstallMethod( PreImagesRepresentative, +InstallMethod( PreImagesRepresentativeNC, "imprim perm wreath product embedding", FamRangeEqFamElm, [ IsEmbeddingImprimitiveWreathProductPermGroup, IsMultiplicativeElementWithInverse ], 0, diff --git a/lib/grpmat.gi b/lib/grpmat.gi index 1338ce2dcd..5260a63065 100644 --- a/lib/grpmat.gi +++ b/lib/grpmat.gi @@ -632,7 +632,7 @@ local gens,s,dom,mon,no; # call the recursive function to do the work gens:= SCMinSmaGens( no, s, [], One( no ), true ).gens; SetMinimalStabChain(G,s); - return List(gens,i->PreImagesRepresentative(mon,i)); + return List(gens,i->PreImagesRepresentativeNC(mon,i)); end); ############################################################################# @@ -669,7 +669,7 @@ local s,dom,mon, img; i->Position(HomeEnumerator(dom),i)))); # call the recursive function to do the work s:= LargestElementStabChain( s, One( img ) ); - return PreImagesRepresentative(mon,s); + return PreImagesRepresentativeNC(mon,s); end); ############################################################################# @@ -708,7 +708,7 @@ local mon,dom,S,o,oimgs,p,i,g; od; # change by corresponding matrix element - e:=PreImagesRepresentative(mon,g)*e; + e:=PreImagesRepresentativeNC(mon,g)*e; S:=S.stabilizer; od; @@ -1148,9 +1148,9 @@ InstallMethod( ImagesRepresentative, ############################################################################# ## -#M PreImagesRepresentative( , ) . . . for a blow up isomorphism +#M PreImagesRepresentativeNC( , ) . . for a blow up isomorphism ## -InstallMethod( PreImagesRepresentative, +InstallMethod( PreImagesRepresentativeNC, "for a blow up isomorphism, and a matrix in the range", FamRangeEqFamElm, [ IsBlowUpIsomorphism, IsMatrix ], diff --git a/lib/grpnice.gd b/lib/grpnice.gd index c0e815cb77..73ae88e9f4 100644 --- a/lib/grpnice.gd +++ b/lib/grpnice.gd @@ -363,7 +363,7 @@ BindGlobal( "AttributeMethodByNiceMonomorphismList", function( oper, par ) local nice; nice:= NiceMonomorphism( obj ); return List( oper( NiceObject( obj ) ), - x -> PreImagesRepresentative( nice, x ) ); + x -> PreImagesRepresentativeNC( nice, x ) ); end ); end ); diff --git a/lib/grpnice.gi b/lib/grpnice.gi index 0c89f4f063..1e19617b72 100644 --- a/lib/grpnice.gi +++ b/lib/grpnice.gi @@ -209,7 +209,7 @@ function( elm, G ) nice := NiceMonomorphism( G ); img := ImagesRepresentative( nice, elm:actioncanfail:=true ); return img<>fail and img in NiceObject( G ) - and PreImagesRepresentative( nice, img ) = elm; + and PreImagesRepresentativeNC( nice, img ) = elm; end ); @@ -281,7 +281,7 @@ function( obj1, obj2 ) img := ImagesRepresentative( nice, obj2:actioncanfail:=true ); if img = fail or not (img in ImagesSource(nice) and - PreImagesRepresentative(nice,img)=obj2) then + PreImagesRepresentativeNC(nice,img)=obj2) then TryNextMethod(); fi; no:=NiceObject(obj1); @@ -341,10 +341,10 @@ local mon,cl,clg,c,i; cl:=ConjugacyClasses(NiceObject(g)); clg:=[]; for i in cl do - c:=ConjugacyClass(g,PreImagesRepresentative(mon,Representative(i))); + c:=ConjugacyClass(g,PreImagesRepresentativeNC(mon,Representative(i))); c!.niceClass:=i; if HasStabilizerOfExternalSet(i) then - SetStabilizerOfExternalSet(c,PreImages(mon,StabilizerOfExternalSet(i))); + SetStabilizerOfExternalSet(c,PreImagesNC(mon,StabilizerOfExternalSet(i))); fi; Add(clg,c); od; @@ -783,7 +783,7 @@ SubgroupMethodByNiceMonomorphism( SolvableRadical, InstallMethodWithRandomSource( Random, "for a random source and a group handled by nice monomorphism", [ IsRandomSource, IsGroup and IsHandledByNiceMonomorphism ], 0, - {rs, G} -> PreImagesRepresentative( NiceMonomorphism( G ), + {rs, G} -> PreImagesRepresentativeNC( NiceMonomorphism( G ), Random( rs, NiceObject( G ) ) ) ); @@ -799,9 +799,9 @@ local mon,cl,clg,c,i; cl:=RationalClasses(NiceObject(g)); clg:=[]; for i in cl do - c:=RationalClass(g,PreImagesRepresentative(mon,Representative(i))); + c:=RationalClass(g,PreImagesRepresentativeNC(mon,Representative(i))); if HasStabilizerOfExternalSet(i) then - SetStabilizerOfExternalSet(c,PreImages(mon,StabilizerOfExternalSet(i))); + SetStabilizerOfExternalSet(c,PreImagesNC(mon,StabilizerOfExternalSet(i))); fi; if HasGaloisGroup(i) then SetGaloisGroup(c,GaloisGroup(i)); @@ -822,7 +822,7 @@ function(g,u) local mon,rt; mon:=NiceMonomorphism(g); rt:=RightTransversal(ImagesSet(mon,g),ImagesSet(mon,u)); - rt:=List(rt,i->RightCoset(u,PreImagesRepresentative(mon,i))); + rt:=List(rt,i->RightCoset(u,PreImagesRepresentativeNC(mon,i))); return rt; end); @@ -894,7 +894,7 @@ local hom,rep; rep:= RepresentativeAction( NiceObject( G ), ImageElm( hom, a ), ImageElm( hom, b ), OnPoints ); if rep<>fail then - rep:=PreImagesRepresentative(hom,rep); + rep:=PreImagesRepresentativeNC(hom,rep); fi; return rep; end); @@ -971,9 +971,9 @@ end); ############################################################################# ## -#M PreImagesRepresentative( , ) . . . . . . . . . . . via images +#M PreImagesRepresentativeNC( , ) . . . . . . . . . . via images ## -InstallMethod( PreImagesRepresentative, "for PBG-Niceo", +InstallMethod( PreImagesRepresentativeNC, "for PBG-Niceo", FamRangeEqFamElm, [ IsPreimagesByAsGroupGeneralMappingByImages and IsNiceMonomorphism, IsMultiplicativeElementWithInverse ], 0, @@ -982,7 +982,7 @@ local p, tmp; # avoid the double dispatch for `AsGroupGeneralMappingByImages' tmp := RUN_IN_GGMBI; RUN_IN_GGMBI:=true; - p:=PreImagesRepresentative( AsGroupGeneralMappingByImages( hom ), elm ); + p:=PreImagesRepresentativeNC( AsGroupGeneralMappingByImages( hom ), elm ); RUN_IN_GGMBI:=tmp; return p; end ); @@ -1077,7 +1077,7 @@ InstallMethod( \[\],"enum-by-niceo", true, function( enum, pos ) local img; img:=enum!.niceEnumerator[pos]; - return PreImagesRepresentative(enum!.morphism,img); + return PreImagesRepresentativeNC(enum!.morphism,img); end); diff --git a/lib/mapping.gd b/lib/mapping.gd index a570fe8922..b83753453e 100644 --- a/lib/mapping.gd +++ b/lib/mapping.gd @@ -970,24 +970,42 @@ DeclareGlobalFunction( "Images" ); ############################################################################# ## -#O PreImagesElm( , ) . all preimages of elm under a gen. mapping +#O PreImagesElm( , ) . . . . . . . . . . . . all preimages of elm +#O PreImagesElmNC( , ) . . . . . . . . . . . under a gen. mapping ## ## <#GAPDoc Label="PreImagesElm"> ## ## +## ## ## ## If elm is an element of the range of the general mapping -## map then returns the set of all +## map then returns the set of all ## preimages of elm under map. ##

## Anything may happen if elm is not an element of the range of -## map. +## map. +##

+## In order to improve this state of affairs, +## PreImagesElm has been renamed PreImagesElmNC +## throughout the library, and +## PreImagesElm has been declared a synonym for PreImagesElmNC. +##

+## In future versions of &GAP; PreImagesElm +## will perform additional checks and reject invalid inputs. +## These additional checks will slow the computation so, +## when the inputs are known to be valid by construction, +## users are recommended to use PreImagesElmNC. +##

+## Package authors are asked to convert their methods for +## PreImagesElm to methods for PreImagesElmNC. +## Only when this has happened will the additional checks be implemented. ## ## ## <#/GAPDoc> ## -DeclareOperation( "PreImagesElm", [ IsGeneralMapping, IsObject ] ); +DeclareOperation( "PreImagesElmNC", [ IsGeneralMapping, IsObject ] ); +DeclareSynonym( "PreImagesElm", PreImagesElmNC ); ############################################################################# @@ -1016,50 +1034,89 @@ DeclareOperation( "PreImageElm", ############################################################################# ## -#O PreImagesRepresentative( , ) . . . one preimage of an element -## under a gen. mapping +#O PreImagesRepresentative( , ) . . . one preimage of an element +#O PreImagesRepresentativeNC( , ) . . . under a general mapping ## ## <#GAPDoc Label="PreImagesRepresentative"> ## ## +## ## ## ## If elm is an element of the range of the general mapping -## map then returns either a -## representative of the set of preimages of elm under map or -## fail, the latter if and only if elm -## has no preimages under map. +## map then these operations return either a representative +## of the set of preimages of elm under map or fail, +## the latter if and only if elm has no preimages under map. ##

## Anything may happen if elm is not an element of the range of ## map. +##

+## In order to improve this state of affairs, +## PreImagesRepresentative has been renamed +## PreImagesRepresentativeNC throughout the library, +## and PreImagesRepresentative has been declared a synonym for +## PreImagesRepresentativeNC. +##

+## In future versions of &GAP; PreImagesRepresentative +## will perform additional checks and reject invalid inputs. +## These additional checks will slow the computation so, +## when the inputs are known to be valid by construction, +## users are recommended to use PreImagesRepresentativeNC. +##

+## Package authors are asked to convert their methods for +## PreImagesRepresentative to methods for +## PreImagesRepresentativeNC. +## Only when this has happened will the additional checks be implemented. ## ## ## <#/GAPDoc> ## -DeclareOperation( "PreImagesRepresentative", + +## DeclareOperation( "PreImagesRepresentative", +## [ IsGeneralMapping, IsObject ] ); +DeclareOperation( "PreImagesRepresentativeNC", [ IsGeneralMapping, IsObject ] ); +DeclareSynonym( "PreImagesRepresentative", PreImagesRepresentativeNC ); ############################################################################# ## #O PreImagesSet( , ) +#O PreImagesSetNC( , ) ## ## <#GAPDoc Label="PreImagesSet"> ## ## +## ## ## ## If elms is a subset of the range of the general mapping map -## then returns the set of all preimages of +## then returns the set of all preimages of ## elms under map. ##

## Anything may happen if elms is not a subset of the range of ## map. +##

+## In order to improve this state of affairs, +## PreImagesSet has been renamed PreImagesSetNC +## throughout the library, and +## PreImagesSet has been declared a synonym for PreImagesSetNC. +##

+## In future versions of &GAP; PreImagesSet +## will perform additional checks and reject invalid inputs. +## These additional checks will slow the computation so, +## when the inputs are known to be valid by construction, +## users are recommended to use PreImagesSetNC. +##

+## Package authors are asked to convert their methods for +## PreImagesSet to methods for PreImagesSetNC. +## Only when this has happened will the additional checks be implemented. ## ## ## <#/GAPDoc> ## -DeclareOperation( "PreImagesSet", [ IsGeneralMapping, IsListOrCollection ] ); +DeclareOperation( "PreImagesSetNC", [ IsGeneralMapping, IsListOrCollection ] ); +DeclareSynonym( "PreImagesSet", PreImagesSetNC ); ############################################################################# @@ -1120,31 +1177,40 @@ DeclareGlobalFunction( "PreImage" ); ############################################################################# ## -#F PreImages( ) . . . set of preimages of the range of a gen. mapping -#F PreImages(,) . set of preimages of an elm under a gen. mapping -#F PreImages(,) set of preimages of a coll. under a gen. mapping +#F PreImages() +#F PreImagesNC() . . . set of preimages of the range of a gen. mapping +#F PreImages(,) +#F PreImagesNC(,) set of preimages of an elm under a gen. mapping +#F PreImages(,) +#F PreImagesNC(,) set of preimages of a coll. under a gen. mapping ## ## <#GAPDoc Label="PreImages"> ## ## PreImages ## +## ## +## ## +## ## ## -## PreImages( map ) is the preimage of the general mapping +## PreImages[NC]( map ) is the preimage of the general mapping ## map, i.e., the subset of elements of the source of map -## that have actually values under map. +## that actually have values under map. ##

-## PreImages( map, elm ) is the set of preimages of the -## element elm of the range of the general mapping map under +## PreImages[NC]( map, elm ) is the set of preimages of +## the element elm of the range of the general mapping map under ## map, i.e., the set of elements of the source which map maps ## to elm. ##

-## PreImages( map, coll ) is the set of images of the +## PreImages[NC]( map, coll ) is the set of images of the ## subset coll of the range of the general mapping map under ## map, i.e., the subset of the source which map maps to ## elements of coll. @@ -1153,19 +1219,36 @@ DeclareGlobalFunction( "PreImage" ); ## (If coll and the result are lists then the positions of ## entries do in general not correspond.) ##

-## +## ## delegates to when ## called with one argument, ## and to resp. when ## called with two arguments. +## The corresponding PreImagesNC delegates to PreImagesRange +## and PreImagesSetNC. ##

## If the second argument is not an element or a subset of the range of -## the first argument, an error is signalled. +## the first argument, incorrect results may be returned. +## In order to improve this state of affairs, +## PreImages has been renamed PreImagesNC throughout the library, +## and PreImages has been declared a synonym for PreImagesNC. +##

+## In future versions of &GAP; PreImages +## will perform additional checks and reject invalid inputs. +## These additional checks will slow the computation so, +## when the inputs are known to be valid by construction, +## users are recommended to use PreImagesNC. +##

+## Package authors are asked to convert their methods for +## PreImages to methods for PreImagesNC. +## Only when this has happened will the additional checks be implemented. ## ## ## <#/GAPDoc> ## -DeclareGlobalFunction( "PreImages" ); +DeclareGlobalFunction( "PreImagesNC" ); +DeclareSynonym( "PreImages", PreImagesNC ); ############################################################################# diff --git a/lib/mapping.gi b/lib/mapping.gi index 7ae902e971..619a652c7e 100644 --- a/lib/mapping.gi +++ b/lib/mapping.gi @@ -273,9 +273,9 @@ InstallGlobalFunction( PreImage, function ( arg ) fi; if IsDomain( img ) or IsSSortedList( img ) then - return PreImagesSet( map, img ); + return PreImagesSetNC( map, img ); elif IsHomogeneousList( img ) then - return PreImagesSet( map, Set( img ) ); + return PreImagesSetNC( map, Set( img ) ); fi; # preimage of the empty list @@ -297,11 +297,14 @@ end ); ############################################################################# ## -#F PreImages( ) . . . set of preimages of the range of a gen. mapping -#F PreImages(,) . set of preimages of an elm under a gen. mapping -#F PreImages(,) set of preimages of a coll. under a gen. mapping +#F PreImages() +#F PreImagesNC() . . . set of preimages of the range of a gen. mapping +#F PreImages(,) +#F PreImagesNC(,) set of preimages of an elm under a gen. mapping +#F PreImages(,) +#F PreImagesNC(,) set of preimages of a coll. under a gen. mapping ## -InstallGlobalFunction( PreImages, function ( arg ) +InstallGlobalFunction( PreImagesNC, function ( arg ) local map, # mapping , first argument img; # element , second argument @@ -325,7 +328,7 @@ InstallGlobalFunction( PreImages, function ( arg ) if not img in Range( map ) then ErrorNoReturn( " must be an element of Range()" ); fi; - return PreImagesElm( map, img ); + return PreImagesElmNC( map, img ); # preimage of a collection of elements under elif CollFamRangeEqFamElms( FamilyObj( map ), FamilyObj( img ) ) then @@ -335,9 +338,9 @@ InstallGlobalFunction( PreImages, function ( arg ) fi; if IsDomain( img ) or IsSSortedList( img ) then - return PreImagesSet( map, img ); + return PreImagesSetNC( map, img ); elif IsHomogeneousList( img ) then - return PreImagesSet( map, Set( img ) ); + return PreImagesSetNC( map, Set( img ) ); fi; # preimage of the empty list @@ -352,8 +355,8 @@ InstallGlobalFunction( PreImages, function ( arg ) "is not a homogeneous list or collection" ); fi; fi; - ErrorNoReturn( "usage: PreImages(), PreImages(,), ", - "PreImages(,)" ); + ErrorNoReturn( "usage: PreImagesNC(), PreImagesNC(,), ", + "PreImagesNC(,)" ); end ); @@ -1067,16 +1070,16 @@ InstallMethod( PreImageElm, "for inj. & surj. general mapping, and element", FamRangeEqFamElm, [ IsGeneralMapping and IsInjective and IsSurjective, IsObject ], 0, - PreImagesRepresentative ); + PreImagesRepresentativeNC ); ############################################################################# ## -#M PreImagesElm( , ) . . . . . . for general mapping and element +#M PreImagesElmNC( , ) . . . . . for general mapping and element ## ## more or less delegate to `ImagesElm' ## -InstallMethod( PreImagesElm, +InstallMethod( PreImagesElmNC, "for general mapping with finite source, and element", FamRangeEqFamElm, [ IsGeneralMapping, IsObject ], 0, @@ -1096,9 +1099,9 @@ InstallMethod( PreImagesElm, ############################################################################# ## -#M PreImagesElm( , ) for const. time access gen. map., and elm. +#M PreImagesElmNC( , ) for const. time access gen. map., and elm. ## -InstallMethod( PreImagesElm, +InstallMethod( PreImagesElmNC, "for constant time access general mapping, and element", FamRangeEqFamElm, [ IsGeneralMapping and IsConstantTimeAccessGeneralMapping, IsObject ], 0, @@ -1116,9 +1119,9 @@ InstallMethod( PreImagesElm, ############################################################################# ## -#M PreImagesSet( , ) . for general mapping and finite collection +#M PreImagesSetNC( , ) for general mapping and finite collection ## -InstallMethod( PreImagesSet, +InstallMethod( PreImagesSetNC, "for general mapping, and finite collection", CollFamRangeEqFamElms, [ IsGeneralMapping, IsCollection ], 0, @@ -1129,12 +1132,12 @@ InstallMethod( PreImagesSet, fi; primgs:= []; for elm in Enumerator( elms ) do - UniteSet( primgs, AsList( PreImagesElm( map, elm ) ) ); + UniteSet( primgs, AsList( PreImagesElmNC( map, elm ) ) ); od; return primgs; end ); -InstallMethod( PreImagesSet, +InstallMethod( PreImagesSetNC, "for general mapping, and empty list", true, [ IsGeneralMapping, IsList and IsEmpty ], 0, @@ -1151,7 +1154,7 @@ InstallMethod( PreImagesRange, "for general mapping", true, [ IsGeneralMapping ], 0, - map -> PreImagesSet( map, Range( map ) ) ); + map -> PreImagesSetNC( map, Range( map ) ) ); ############################################################################# @@ -1168,9 +1171,22 @@ InstallMethod( PreImagesRange, ############################################################################# ## -#M PreImagesRepresentative( , ) . . for s.p. gen. mapping & elm -## -InstallMethod( PreImagesRepresentative, +#M PreImagesRepresentative( , ) . . . for s.p. gen. mapping & elm +#M PreImagesRepresentativeNC( , ) . . for s.p. gen. mapping & elm +## +## InstallMethod( PreImagesRepresentative, +## "for s.p. general mapping, and element", +## FamRangeEqFamElm, +## [ IsSPGeneralMapping, IsObject ], 0, +## function( map, elm ) +## test will be included at a later stage of the change of name +## if not elm in Image( map ) then +## return fail; +## fi; +## return PreImagesRepresentativeNC( map, elm ); +## end ); + +InstallMethod( PreImagesRepresentativeNC, "for s.p. general mapping, and element", FamRangeEqFamElm, [ IsSPGeneralMapping, IsObject ], 0, @@ -1182,16 +1198,29 @@ InstallMethod( PreImagesRepresentative, ############################################################################# ## #M PreImagesRepresentative( , ) -## -InstallMethod( PreImagesRepresentative, +#M PreImagesRepresentativeNC( , ) +## +## InstallMethod( PreImagesRepresentative, +## "for total non-s.p. general mapping, and element", +## FamRangeEqFamElm, +## [ IsNonSPGeneralMapping, IsObject ], 0, +## function( map, elm ) +## test will be included at a later stage of the change of name +## if not elm in Image( map ) then +## return fail; +## fi; +## return PreImagesRepresentativeNC( map, elm ); +## end ); + +InstallMethod( PreImagesRepresentativeNC, "for total non-s.p. general mapping, and element", FamRangeEqFamElm, [ IsNonSPGeneralMapping, IsObject ], 0, - function ( map, elm ) + function( map, elm ) local pres; # all preimages of under # get all preimages of under - pres := PreImagesElm( map, elm ); + pres := PreImagesElmNC( map, elm ); # check that has at least one preimage under if IsEmpty( pres ) then @@ -1459,7 +1488,7 @@ InstallMethod( Enumerator, return enum; elif IsFinite( R ) then for elm in Enumerator( R ) do - imgs:= PreImagesElm( map, elm ); + imgs:= PreImagesElmNC( map, elm ); if IsFinite( imgs ) then UniteSet( enum, List( imgs, im -> DirectProductElement( [ im, elm ] ) ) ); else diff --git a/lib/mapprep.gi b/lib/mapprep.gi index 96bf008e8b..b118d11ff7 100644 --- a/lib/mapprep.gi +++ b/lib/mapprep.gi @@ -302,17 +302,17 @@ InstallMethod( ImagesRepresentative, ############################################################################# ## -#M PreImagesElm( , ) . . . . . . . . . . for composition mapping +#M PreImagesElmNC( , ) . . . . . . . . . for composition mapping ## -InstallMethod( PreImagesElm, +InstallMethod( PreImagesElmNC, "for a composition mapping, and an element", FamRangeEqFamElm, [ IsCompositionMappingRep, IsObject ], 0, function( com, elm ) local im; - im:= PreImagesElm( com!.map2, elm ); + im:= PreImagesElmNC( com!.map2, elm ); if not IsEmpty( im ) then - return PreImagesSet( com!.map1, im ); + return PreImagesSetNC( com!.map1, im ); else return []; fi; @@ -321,17 +321,17 @@ InstallMethod( PreImagesElm, ############################################################################# ## -#M PreImagesSet( , ) . . . . . . . . . . for composition mapping +#M PreImagesSetNC( , ) . . . . . . . . . for composition mapping ## -InstallMethod( PreImagesSet, +InstallMethod( PreImagesSetNC, "for a composition mapping, and a collection", CollFamRangeEqFamElms, [ IsCompositionMappingRep, IsCollection ], 0, function( com, elms ) local im; - im:= PreImagesSet( com!.map2, elms ); + im:= PreImagesSetNC( com!.map2, elms ); if not IsEmpty( im ) then - return PreImagesSet( com!.map1, im ); + return PreImagesSetNC( com!.map1, im ); else return []; fi; @@ -340,27 +340,27 @@ InstallMethod( PreImagesSet, ############################################################################# ## -#M PreImagesRepresentative( , ) . . . . . for composition mapping +#M PreImagesRepresentativeNC( , ) . . . . for composition mapping ## -InstallMethod( PreImagesRepresentative, +InstallMethod( PreImagesRepresentativeNC, "for a composition mapping, and an element", FamRangeEqFamElm, [ IsCompositionMappingRep, IsObject ], 0, function( com, elm ) local im, rep; - im:= PreImagesRepresentative( com!.map2, elm ); + im:= PreImagesRepresentativeNC( com!.map2, elm ); if im = fail then # 'elm' has no preimages under 'com!.map2', so it has none under 'com'. return fail; else - im:= PreImagesRepresentative( com!.map1, im ); + im:= PreImagesRepresentativeNC( com!.map1, im ); if im <> fail then return im; fi; # It may happen that only the chosen representative has no preimages. - for im in Enumerator( PreImagesElm( com!.map2, elm ) ) do - rep:= PreImagesRepresentative( com!.map1, im ); + for im in Enumerator( PreImagesElmNC( com!.map2, elm ) ) do + rep:= PreImagesRepresentativeNC( com!.map1, im ); if rep <> fail then return rep; fi; @@ -383,7 +383,7 @@ InstallMethod( KernelOfAdditiveGeneralMapping, if IsInjective( com!.map2 ) then return KernelOfAdditiveGeneralMapping( com!.map1 ); else - return PreImagesSet( com!.map1, + return PreImagesSetNC( com!.map1, KernelOfAdditiveGeneralMapping( com!.map2 ) ); fi; end ); @@ -421,7 +421,7 @@ InstallMethod( KernelOfMultiplicativeGeneralMapping, if IsInjective( com!.map2 ) then return KernelOfMultiplicativeGeneralMapping( com!.map1 ); else - return PreImagesSet( com!.map1, + return PreImagesSetNC( com!.map1, KernelOfMultiplicativeGeneralMapping( com!.map2 ) ); fi; end ); @@ -629,9 +629,9 @@ end ); ############################################################################# ## -#M PreImagesRepresentative( , ) . . . . . for mapping by function +#M PreImagesRepresentativeNC( , ) . . . . for mapping by function ## -InstallMethod( PreImagesRepresentative, +InstallMethod( PreImagesRepresentativeNC, "for mapping by function", FamRangeEqFamElm, [ IsMappingByFunctionRep, IsObject ], 0, @@ -659,9 +659,9 @@ InstallMethod( PreImageElm, ############################################################################# ## -#M PreImagesElm( , ) . . . . . . . . . . for mapping by function +#M PreImagesElmNC( , ) . . . . . . . . . for mapping by function ## -InstallMethod( PreImagesElm, +InstallMethod( PreImagesElmNC, "for mapping by function", FamRangeEqFamElm, [ IsMappingByFunctionWithInverseRep, IsObject ], 0, @@ -671,9 +671,9 @@ InstallMethod( PreImagesElm, ############################################################################# ## -#M PreImagesRepresentative( , ) . . . . . for mapping by function +#M PreImagesRepresentativeNC( , ) . . . . for mapping by function ## -InstallMethod( PreImagesRepresentative, +InstallMethod( PreImagesRepresentativeNC, "for mapping by function with inverse", FamRangeEqFamElm, [ IsMappingByFunctionWithInverseRep, IsObject ], 0, @@ -1008,7 +1008,7 @@ InstallMethod( ImagesElm, FamSourceEqFamElm, [ IsGeneralMapping and IsInverseGeneralMappingRep, IsObject ], 0, function ( inv, elm ) - return PreImagesElm( InverseGeneralMapping( inv ), elm ); + return PreImagesElmNC( InverseGeneralMapping( inv ), elm ); end ); @@ -1021,7 +1021,7 @@ InstallMethod( ImagesSet, CollFamSourceEqFamElms, [ IsGeneralMapping and IsInverseGeneralMappingRep, IsCollection ], 0, function ( inv, elms ) - return PreImagesSet( InverseGeneralMapping( inv ), elms ); + return PreImagesSetNC( InverseGeneralMapping( inv ), elms ); end ); @@ -1034,7 +1034,7 @@ InstallMethod( ImagesRepresentative, FamSourceEqFamElm, [ IsGeneralMapping and IsInverseGeneralMappingRep, IsObject ], 0, function ( inv, elm ) - return PreImagesRepresentative( InverseGeneralMapping( inv ), elm ); + return PreImagesRepresentativeNC( InverseGeneralMapping( inv ), elm ); end ); @@ -1054,9 +1054,9 @@ InstallMethod( PreImageElm, ############################################################################# ## -#M PreImagesElm( , ) . . . . . for inverse mapping and element +#M PreImagesElmNC( , ) . . . . for inverse mapping and element ## -InstallMethod( PreImagesElm, +InstallMethod( PreImagesElmNC, "for an inverse mapping and an element", FamRangeEqFamElm, [ IsGeneralMapping and IsInverseGeneralMappingRep, IsObject ], 0, @@ -1067,9 +1067,9 @@ InstallMethod( PreImagesElm, ############################################################################# ## -#M PreImagesSet( , ) . . for inverse mapping and collection +#M PreImagesSetNC( , ) . . for inverse mapping and collection ## -InstallMethod( PreImagesSet, +InstallMethod( PreImagesSetNC, "for an inverse mapping and a collection", CollFamRangeEqFamElms, [ IsGeneralMapping and IsInverseGeneralMappingRep, IsCollection ], 0, @@ -1080,9 +1080,9 @@ InstallMethod( PreImagesSet, ############################################################################# ## -#M PreImagesRepresentative( , ) . . for inv. mapping and elm. +#M PreImagesRepresentativeNC( , ) . for inv. mapping and elm. ## -InstallMethod( PreImagesRepresentative, +InstallMethod( PreImagesRepresentativeNC, "for an inverse mapping and an element", FamRangeEqFamElm, [ IsInverseGeneralMappingRep, IsObject ], 0, @@ -1293,9 +1293,9 @@ InstallMethod( PreImageElm, ############################################################################# ## -#M PreImagesElm( , ) . . . . for identity mapping and element +#M PreImagesElmNC( , ) . . . . for identity mapping and element ## -InstallMethod( PreImagesElm, +InstallMethod( PreImagesElmNC, "for identity mapping and object", FamRangeEqFamElm, [ IsGeneralMapping and IsOne, IsObject ], @@ -1307,9 +1307,9 @@ InstallMethod( PreImagesElm, ############################################################################# ## -#M PreImagesSet( , ) . . . for identity mapping and collection +#M PreImagesSetNC( , ) . . for identity mapping and collection ## -InstallMethod( PreImagesSet, +InstallMethod( PreImagesSetNC, "for identity mapping and collection", CollFamRangeEqFamElms, [ IsGeneralMapping and IsOne, IsCollection ], @@ -1321,9 +1321,9 @@ InstallMethod( PreImagesSet, ############################################################################# ## -#M PreImagesRepresentative( , ) +#M PreImagesRepresentativeNC( , ) ## -InstallMethod( PreImagesRepresentative, +InstallMethod( PreImagesRepresentativeNC, "for identity mapping and object", FamRangeEqFamElm, [ IsGeneralMapping and IsOne, IsObject ], @@ -1581,9 +1581,9 @@ InstallMethod( ImagesRepresentative, ############################################################################# ## -#M PreImagesElm( , ) . . . . . for zero mapping and element +#M PreImagesElmNC( , ) . . . . . for zero mapping and element ## -InstallMethod( PreImagesElm, +InstallMethod( PreImagesElmNC, "for zero mapping and object", FamRangeEqFamElm, [ IsGeneralMapping and IsZero, IsObject ], SUM_FLAGS, @@ -1598,9 +1598,9 @@ InstallMethod( PreImagesElm, ############################################################################# ## -#M PreImagesSet( , ) . . . . for zero mapping and collection +#M PreImagesSetNC( , ) . . . for zero mapping and collection ## -InstallMethod( PreImagesSet, +InstallMethod( PreImagesSetNC, "for zero mapping and collection", CollFamRangeEqFamElms, [ IsGeneralMapping and IsZero, IsCollection ], SUM_FLAGS, @@ -1615,9 +1615,9 @@ InstallMethod( PreImagesSet, ############################################################################# ## -#M PreImagesRepresentative( , ) +#M PreImagesRepresentativeNC( , ) ## -InstallMethod( PreImagesRepresentative, +InstallMethod( PreImagesRepresentativeNC, "for zero mapping and object", FamRangeEqFamElm, [ IsGeneralMapping and IsZero, IsObject ], SUM_FLAGS, @@ -1817,15 +1817,15 @@ end ); ############################################################################# ## -#M PreImagesElm( , ) . . . . . . . . . . for restricted mapping +#M PreImagesElmNC( , ) . . . . . . . . . for restricted mapping ## -InstallMethod( PreImagesElm, +InstallMethod( PreImagesElmNC, "for a restricted mapping, and an element", FamRangeEqFamElm, [ IsGeneralRestrictedMappingRep, IsObject ], 0, function( res, elm ) local preim; - preim:= PreImagesElm( res!.map, elm ); + preim:= PreImagesElmNC( res!.map, elm ); if not ( (HasIsInjective(res) and IsInjective(res)) or (HasIsInjective(res!.map) and IsInjective(res!.map)) ) then preim:=Intersection(Source(res),preim); @@ -1836,15 +1836,15 @@ end ); ############################################################################# ## -#M PreImagesSet( , ) . . . . . . . . . . for restricted mapping +#M PreImagesSetNC( , ) . . . . . . . . . for restricted mapping ## -InstallMethod( PreImagesSet, +InstallMethod( PreImagesSetNC, "for a restricted mapping, and a collection", CollFamRangeEqFamElms, [ IsGeneralRestrictedMappingRep, IsCollection ], 0, function( res, elms ) local preim; - preim:= PreImagesSet( res!.map, elms ); + preim:= PreImagesSetNC( res!.map, elms ); if not ( (HasIsInjective(res) and IsInjective(res)) or (HasIsInjective(res!.map) and IsInjective(res!.map)) ) then preim:=Intersection(Source(res),preim); @@ -1855,15 +1855,15 @@ InstallMethod( PreImagesSet, ############################################################################# ## -#M PreImagesRepresentative( , ) . . . . . for restricted mapping +#M PreImagesRepresentativeNC( , ) . . . . for restricted mapping ## -InstallMethod( PreImagesRepresentative, +InstallMethod( PreImagesRepresentativeNC, "for a restricted mapping, and an element", FamRangeEqFamElm, [ IsGeneralRestrictedMappingRep, IsObject ], 0, function( res, elm ) local preim; - preim:= PreImagesRepresentative( res!.map, elm ); + preim:= PreImagesRepresentativeNC( res!.map, elm ); if preim = fail then # 'elm' has no preimages under 'res!.map', so it has none under 'res'. return fail; @@ -1872,7 +1872,7 @@ InstallMethod( PreImagesRepresentative, elif HasIsInjective(res!.map) and IsInjective(res!.map) then return fail; # no other choice else - preim:= PreImages( res!.map, elm ); + preim:= PreImagesNC( res!.map, elm ); return First(preim,x->x in Source(res)); fi; end ); diff --git a/lib/mgmring.gi b/lib/mgmring.gi index 077f27c153..f7a4688a36 100644 --- a/lib/mgmring.gi +++ b/lib/mgmring.gi @@ -1220,7 +1220,7 @@ InstallMethod( ImagesRepresentative, end ); -InstallMethod( PreImagesElm, +InstallMethod( PreImagesElmNC, "for embedding of ring into magma ring, and free magma ring element", FamRangeEqFamElm, [ IsEmbeddingRingMagmaRing, IsElementOfFreeMagmaRing ], @@ -1236,7 +1236,7 @@ InstallMethod( PreImagesElm, fi; end ); -InstallMethod( PreImagesRepresentative, +InstallMethod( PreImagesRepresentativeNC, "for embedding of ring into magma ring, and free magma ring element", FamRangeEqFamElm, [ IsEmbeddingRingMagmaRing, IsElementOfFreeMagmaRing ], @@ -1324,7 +1324,7 @@ InstallMethod( ImagesRepresentative, end ); -InstallMethod( PreImagesElm, +InstallMethod( PreImagesElmNC, "for embedding of magma into magma ring, and free magma ring element", FamRangeEqFamElm, [ IsEmbeddingMagmaMagmaRing, IsElementOfFreeMagmaRing ], @@ -1340,7 +1340,7 @@ InstallMethod( PreImagesElm, fi; end ); -InstallMethod( PreImagesRepresentative, +InstallMethod( PreImagesRepresentativeNC, "for embedding of magma into magma ring, and free magma ring element", FamRangeEqFamElm, [ IsEmbeddingMagmaMagmaRing, IsElementOfFreeMagmaRing ], diff --git a/lib/oprt.gi b/lib/oprt.gi index fd65972459..7440dbcbd2 100644 --- a/lib/oprt.gi +++ b/lib/oprt.gi @@ -2921,7 +2921,7 @@ local G, D, d, e, gens, acts, act, xset, hom, p, rep; rep := RepresentativeActionOp( ImagesSource( hom ), d, e, OnPoints ); if rep <> fail then - rep := PreImagesRepresentative( hom, rep ); + rep := PreImagesRepresentativeNC( hom, rep ); fi; return rep; elif IsBound( D ) then @@ -3375,9 +3375,9 @@ end ); ############################################################################# ## -#M PreImagesRepresentative( , ) . . . . . . . . . . build matrix +#M PreImagesRepresentativeNC( , ) . . . . . . . . . build matrix ## -InstallMethod( PreImagesRepresentative,"IsLinearActionHomomorphism", +InstallMethod( PreImagesRepresentativeNC,"IsLinearActionHomomorphism", FamRangeEqFamElm, [ IsLinearActionHomomorphism, IsPerm ], 0, function( hom, elm ) local V, xset,lab,f; @@ -3413,9 +3413,9 @@ end ); ############################################################################# ## -#M PreImagesRepresentative( , ) . . . . . . . . . . build matrix +#M PreImagesRepresentativeNC( , ) . . . . . . . . . build matrix ## -InstallMethod( PreImagesRepresentative,"IsProjectiveActionHomomorphism", +InstallMethod( PreImagesRepresentativeNC,"IsProjectiveActionHomomorphism", FamRangeEqFamElm, [ IsProjectiveActionHomomorphism, IsPerm ], 0, function( hom, elm ) local V, mat, xset,lab,f,dim,sol,i; diff --git a/lib/relation.gi b/lib/relation.gi index e5208df4b7..cc63d50d03 100644 --- a/lib/relation.gi +++ b/lib/relation.gi @@ -71,7 +71,7 @@ ## ## I. Operations and methods for binary relations on points ## 1. ImagesElm (compatibility with GeneralMapping) -## 2. PreImagesElm (compatibility with GeneralMapping) +## 2. PreImagesElmNC (compatibility with GeneralMapping) ## 3. \=, \in, \< ## 4. \* for relations, transformations, and permutation ## 5. Set operations \+, \- (union, difference) @@ -92,7 +92,7 @@ ## 4. MeetEquivalenceRelations ## 5. \= ## 6. ImagesElm (compatibility with GeneralMapping) -## 7. PreImagesElm (compatibility with GeneralMapping) +## 7. PreImagesElmNC (compatibility with GeneralMapping) ## 8. PrintObj ## ## L. Constructors of equivalence classes @@ -104,7 +104,7 @@ ## 2. PrintObj, Enumerator ## 3. \< ## 4. ImagesRepresentative -## 6. PreImagesRepresentative +## 6. PreImagesRepresentativeNC ## ############################################################################ ############################################################################ @@ -250,7 +250,7 @@ InstallMethod(IsSymmetricBinaryRelation, List(Enumerator(UnderlyingRelation(m)),x->[x[1],x[2]]))); for e in el do - if not PreImages(m,e)=Images(m,e) then + if not PreImagesNC(m,e)=Images(m,e) then return false; fi; od; @@ -312,7 +312,7 @@ InstallMethod(IsAntisymmetricBinaryRelation, List(Enumerator(UnderlyingRelation(rel)),x->[x[1],x[2]]))); for e in el do - i := IntersectionSet(PreImages(rel,e),Images(rel,e)); + i := IntersectionSet(PreImagesNC(rel,e),Images(rel,e)); if not IsEmpty(i) and not i=[e] then return false; fi; @@ -376,7 +376,7 @@ function(rel) for a in Source(rel) do for b in Source(rel) do # intersecting downsets - intersection := Intersection(PreImages(rel,b),PreImages(rel,a)); + intersection := Intersection(PreImagesNC(rel,b),PreImagesNC(rel,a)); # new relation on the intersection induced by the original relation nrel := PartialOrderByOrderingFunction( Domain(intersection), @@ -611,7 +611,7 @@ InstallMethod(HasseDiagramBinaryRelation, ## return Filtered(list, x->IsEmpty(Filtered(list, y-> (y <> x) and - (y in PreImagesElm(rel,x))))); + (y in PreImagesElmNC(rel,x))))); end; ## return the elements which cover x in rel @@ -983,11 +983,11 @@ InstallMethod(ImagesElm, ############################################################################# ## -#M PreImagesElm( , ) +#M PreImagesElmNC( , ) ## ## For binary relations over [1..n] represented as a list of images ## -InstallMethod(PreImagesElm, +InstallMethod(PreImagesElmNC, "for binary rels over [1..n] with images list", true, [IsBinaryRelation and IsBinaryRelationOnPointsRep, IsPosInt], 0, function( rel, n ) @@ -1781,9 +1781,9 @@ InstallMethod( ImagesRepresentative, "equivalence relations", ############################################################################# ## -#M PreImagesRepresentative( , ) . . . for equivalence relations +#M PreImagesRepresentativeNC( , ) . . for equivalence relations ## -InstallMethod( PreImagesRepresentative, "equivalence relations", +InstallMethod( PreImagesRepresentativeNC, "equivalence relations", FamRangeEqFamElm, [IsEquivalenceRelation, IsObject], 0, function( map, elm ) return elm; @@ -1813,9 +1813,9 @@ InstallMethod( ImagesElm, ############################################################################# ## -#M PreImagesElm( , ) for equivalence relations with partition +#M PreImagesElmNC( , ) for equivalence relations with partition ## -InstallMethod( PreImagesElm, +InstallMethod( PreImagesElmNC, "equivalence relations with partition and element", FamRangeEqFamElm, [IsEquivalenceRelation and HasEquivalenceRelationPartition, diff --git a/lib/ringhom.gi b/lib/ringhom.gi index 21791f48a8..2dc8ab4bb7 100644 --- a/lib/ringhom.gi +++ b/lib/ringhom.gi @@ -444,9 +444,9 @@ end ); ############################################################################# ## -#M PreImagesRepresentative( , ) . . . . . . for ring g.m.b.i. +#M PreImagesRepresentativeNC( , ) . . . . . . for ring g.m.b.i. ## -InstallMethod( PreImagesRepresentative, +InstallMethod( PreImagesRepresentativeNC, "for ring g.m.b.i., and element", FamRangeEqFamElm, [ IsRingGeneralMapping and IsRingGeneralMappingByImagesDefaultRep, diff --git a/lib/vspchom.gi b/lib/vspchom.gi index 1ce93b2e5f..b2148a5fe6 100644 --- a/lib/vspchom.gi +++ b/lib/vspchom.gi @@ -485,9 +485,9 @@ InstallMethod( ImagesRepresentative, ############################################################################# ## -#M PreImagesRepresentative( , ) . . . . for left module g.m.b.i. +#M PreImagesRepresentativeNC( , ) . . . for left module g.m.b.i. ## -InstallMethod( PreImagesRepresentative, +InstallMethod( PreImagesRepresentativeNC, "for left module g.m.b.i., and element", FamRangeEqFamElm, [ IsGeneralMapping and IsLinearGeneralMappingByImagesDefaultRep, @@ -1221,9 +1221,9 @@ InstallMethod( ImagesRepresentative, ############################################################################# ## -#M PreImagesRepresentative( , ) . . . . . for left module m.b.m. +#M PreImagesRepresentativeNC( , ) . . . . for left module m.b.m. ## -InstallMethod( PreImagesRepresentative, +InstallMethod( PreImagesRepresentativeNC, "for left module m.b.m., and element", FamRangeEqFamElm, [ IsGeneralMapping and IsLinearMappingByMatrixDefaultRep, From d3e48459d19975f3680fa456ed51237ae655bed9 Mon Sep 17 00:00:00 2001 From: Chris Wensley Date: Wed, 28 Sep 2022 18:24:11 +0100 Subject: [PATCH 002/234] replaced PreImRep by PreImRepNC in files from a... to g... --- lib/algebra.gi | 2 +- lib/algfp.gi | 2 +- lib/alghom.gi | 2 +- lib/alglie.gi | 36 +- lib/algrep.gi | 8 +- lib/autsr.gi | 256 ++++++----- lib/clas.gi | 2 +- lib/clashom.gi | 1177 ++++++++++++++++++++++++----------------------- lib/csetgrp.gi | 2 +- lib/ctblgrp.gi | 2 +- lib/ctblsolv.gi | 11 +- lib/field.gi | 4 +- lib/fitfree.gi | 22 +- lib/ghomperm.gi | 2 +- lib/gpfpiso.gi | 94 ++-- lib/gpprmsya.gi | 2 +- lib/gprd.gi | 28 +- lib/gprdpc.gi | 2 +- lib/grp.gi | 8 +- lib/grpcompl.gi | 8 +- lib/grpfp.gi | 30 +- lib/grplatt.gi | 61 +-- lib/grpnames.gi | 2 +- lib/grpnice.gi | 4 +- lib/grppc.gi | 4 +- lib/grppcaut.gi | 22 +- lib/grppccom.gi | 2 +- lib/grppcext.gi | 50 +- lib/grppclat.gi | 8 +- lib/grpprmcs.gi | 8 +- 30 files changed, 938 insertions(+), 923 deletions(-) diff --git a/lib/algebra.gi b/lib/algebra.gi index cf086ff597..b0a4a29767 100644 --- a/lib/algebra.gi +++ b/lib/algebra.gi @@ -3649,7 +3649,7 @@ InstallMethod( CentralIdempotentsOfAlgebra, until k>Length(ideals); - id:= List( ids, e -> PreImagesRepresentative( hom, e ) ); + id:= List( ids, e -> PreImagesRepresentativeNC( hom, e ) ); # Now we lift the idempotents to the big algebra `A'. The # first idempotent is lifted as follows: diff --git a/lib/algfp.gi b/lib/algfp.gi index c65a8ec796..51adff0b6d 100644 --- a/lib/algfp.gi +++ b/lib/algfp.gi @@ -705,7 +705,7 @@ InstallHandlingByNiceBasis( "IsFpAlgebraElementsSpace", rec( if hom = fail then TryNextMethod(); fi; - return PreImagesRepresentative( hom, r ); + return PreImagesRepresentativeNC( hom, r ); end ) ); diff --git a/lib/alghom.gi b/lib/alghom.gi index 0ea9c60808..2206697003 100644 --- a/lib/alghom.gi +++ b/lib/alghom.gi @@ -915,7 +915,7 @@ InstallMethod( ImagesRepresentative, ############################################################################# ## -#M PreImagesRepresentativeNC( , ) +#M PreImagesRepresentativeOperationAlgebraHomomorphism( , ) ## BindGlobal( "PreImagesRepresentativeOperationAlgebraHomomorphism", function( ophom, mat ) if not IsBound( ophom!.basisImage ) then diff --git a/lib/alglie.gi b/lib/alglie.gi index ea1ba5b846..f648d0e342 100644 --- a/lib/alglie.gi +++ b/lib/alglie.gi @@ -1707,7 +1707,7 @@ InstallMethod( LieSolvableRadical, quo:= ImagesSource( hom ); r1:= LieSolvableRadical( quo ); B:= BasisVectors( Basis( r1 ) ); - B:= List( B, x -> PreImagesRepresentative( hom, x ) ); + B:= List( B, x -> PreImagesRepresentativeNC( hom, x ) ); Append( B, BasisVectors( Basis( n ) ) ); fi; @@ -2099,9 +2099,9 @@ InstallMethod( DirectSumDecomposition, SetCentre( Q, Q ); SetRadicalOfAlgebra( Q, Subalgebra( Q, [ Zero( Q ) ] ) ); - id:= List( CentralIdempotentsOfAlgebra( Q ), - x->PreImagesRepresentative(hom,x)); - + id:= List( CentralIdempotentsOfAlgebra( Q ), + x->PreImagesRepresentativeNC(hom,x)); + # Now we lift the idempotents to the big algebra `A'. The # first idempotent is lifted as follows: # We have that `id[1]^2-id[1]' is an element of `Rad'. @@ -4028,9 +4028,9 @@ InstallMethod( ImagesRepresentative, ########################################################################### ## -#M PreImagesRepresentative( f, x ) +#M PreImagesRepresentativeNC( f, x ) ## -InstallMethod( PreImagesRepresentative, +InstallMethod( PreImagesRepresentativeNC, "for Fp to SCA mapping, and element", FamRangeEqFamElm, [ IsFptoSCAMorphism, IsSCAlgebraObj ], 0, @@ -5604,8 +5604,8 @@ InstallMethod( JenningsLieAlgebra, T:= EmptySCTable( dim , Zero(F) , "antisymmetric" ); pimgs := []; for i in [1..dim] do - a:= PreImagesRepresentative( Homs[pos[i]] , - PreImagesRepresentative( hom_pcg[pos[i]], gens[i] ) ); + a:= PreImagesRepresentativeNC( Homs[pos[i]] , + PreImagesRepresentativeNC( hom_pcg[pos[i]], gens[i] ) ); # calculate the p-th power image of `a': @@ -5622,10 +5622,10 @@ InstallMethod( JenningsLieAlgebra, # Calculate the commutator [a,b], and map the result into # the correct homogeneous component. - b:= PreImagesRepresentative( Homs[pos[j]], - PreImagesRepresentative( hom_pcg[pos[j]], gens[j] )); - c:= Image( hom_pcg[pos[i] + pos[j]], - Image(Homs[pos[i] + pos[j]], a^-1*b^-1*a*b) ); + b:= PreImagesRepresentativeNC( Homs[pos[j]], + PreImagesRepresentativeNC( hom_pcg[pos[j]], gens[j] )); + c:= Image( hom_pcg[pos[i] + pos[j]], + Image(Homs[pos[i] + pos[j]], a^-1*b^-1*a*b) ); e:= ExtRepOfObj(c); co:=[]; for k in [1,3..Length(e)-1] do @@ -5800,8 +5800,8 @@ InstallMethod( PCentralLieAlgebra, T:= EmptySCTable( dim , Zero(F) , "antisymmetric" ); pimgs := []; for i in [1..dim] do - a:= PreImagesRepresentative( Homs[pos[i]] , - PreImagesRepresentative( hom_pcg[pos[i]], gens[i] ) ); + a:= PreImagesRepresentativeNC( Homs[pos[i]] , + PreImagesRepresentativeNC( hom_pcg[pos[i]], gens[i] ) ); # calculate the p-th power image of `a': @@ -5819,10 +5819,10 @@ InstallMethod( PCentralLieAlgebra, # Calculate the commutator [a,b], and map the result into # the correct homogeneous component. - b:= PreImagesRepresentative( Homs[pos[j]], - PreImagesRepresentative( hom_pcg[pos[j]], gens[j] )); - c:= Image( hom_pcg[pos[i] + pos[j]], - Image(Homs[pos[i] + pos[j]], a^-1*b^-1*a*b) ); + b:= PreImagesRepresentativeNC( Homs[pos[j]], + PreImagesRepresentativeNC( hom_pcg[pos[j]], gens[j] )); + c:= Image( hom_pcg[pos[i] + pos[j]], + Image(Homs[pos[i] + pos[j]], a^-1*b^-1*a*b) ); e:= ExtRepOfObj(c); co:=[]; for k in [1,3..Length(e)-1] do diff --git a/lib/algrep.gi b/lib/algrep.gi index 8d331feee2..7607190b94 100644 --- a/lib/algrep.gi +++ b/lib/algrep.gi @@ -1212,24 +1212,24 @@ InstallMethod( NaturalHomomorphismBySubAlgebraModule, if IsLeftAlgebraModuleElementCollection( V ) then if IsRightAlgebraModuleElementCollection( V ) then left_op:= function( x, v ) - return ImagesRepresentative( f, x^PreImagesRepresentative( f, v ) ); + return ImagesRepresentative( f, x^PreImagesRepresentativeNC( f, v ) ); end; right_op:= function( v, x ) - return ImagesRepresentative( f, PreImagesRepresentative( f, v )^x ); + return ImagesRepresentative( f, PreImagesRepresentativeNC( f, v )^x ); end; qmod:= BiAlgebraModule( LeftActingAlgebra( V ), RightActingAlgebra( V ), left_op, right_op, quot ); else left_op:= function( x, v ) - return ImagesRepresentative( f, x^PreImagesRepresentative( f, v ) ); + return ImagesRepresentative( f, x^PreImagesRepresentativeNC( f, v ) ); end; qmod:= LeftAlgebraModule( LeftActingAlgebra( V ), left_op, quot); fi; else right_op:= function( v, x ) - return ImagesRepresentative( f, PreImagesRepresentative( f, v )^x ); + return ImagesRepresentative( f, PreImagesRepresentativeNC( f, v )^x ); end; qmod:= RightAlgebraModule( RightActingAlgebra( V ), right_op, quot ); diff --git a/lib/autsr.gi b/lib/autsr.gi index 241cc84115..705e1daca8 100644 --- a/lib/autsr.gi +++ b/lib/autsr.gi @@ -118,7 +118,7 @@ local C,M,p,all,gens,sub,q,hom,fp,rels,new,pre,i,free,cnt; rels:=Filtered(RelatorsOfFpGroup(fp),x->ForAll(ExponentSums(x),x->x mod p=0)); rels:=List(rels,x->ElementOfFpGroup(FamilyObj(One(fp)),x)); new:=RestrictedMapping(nat,C)*hom; - pre:=List(rels,x->PreImagesRepresentative(new,x)); + pre:=List(rels,x->PreImagesRepresentativeNC(new,x)); for i in [1..Length(rels)] do if not pre[i] in sub then Add(all,MappedWord(rels[i], @@ -141,7 +141,7 @@ local ocr,fphom,fpg,free,len,dim,tmp,L0,R,rels,mat,r,RS,i,g,v,cnt; fpg:=FreeGeneratorsOfFpGroup(Range(fphom)); ocr.factorpres:=[fpg,RelatorsOfFpGroup(Range(fphom))]; ocr.generators:=List(GeneratorsOfGroup(Range(fphom)), - i->PreImagesRepresentative(fphom,i)); + i->PreImagesRepresentativeNC(fphom,i)); OCAddMatrices(ocr,ocr.generators); OCAddRelations(ocr,ocr.generators); OCAddSumMatrices(ocr,ocr.generators); @@ -274,8 +274,8 @@ BindGlobal("AGSRAutomLift",function(ocr,nat,fhom,miso) # allow to deduce corresponding module aut. t:=ocr.trickrels; phom:=IdentityMapping(ocr.moduleauts); - s:=List(t.gens,x->PreImagesRepresentative(nat,x)); - l:=List(t.gens,x->PreImagesRepresentative(nat,ImagesRepresentative(fhom,x))); + s:=List(t.gens,x->PreImagesRepresentativeNC(nat,x)); + l:=List(t.gens,x->PreImagesRepresentativeNC(nat,ImagesRepresentative(fhom,x))); s:=List(t.rels,x->MappedWord(x,GeneratorsOfGroup(t.free),s)); l:=List(t.rels,x->MappedWord(x,GeneratorsOfGroup(t.free),l)); @@ -294,7 +294,7 @@ BindGlobal("AGSRAutomLift",function(ocr,nat,fhom,miso) Size(Image(phom))); fi; for ep in enum do - e:=PreImagesRepresentative(phom,ep); + e:=PreImagesRepresentativeNC(phom,ep); psim:=e*miso; psim:=psim^-1; w:=-List(v,i->i*psim); @@ -486,8 +486,8 @@ local S,c,hom,q,a,b,i,t,have,ups,new,u,good,abort,clim,worked,pp, cnt:=0; for b in t do - new:=PreImagesRepresentative(hom,b); - if (pp=false or new^pp in S) and locond(new) then + new:=PreImagesRepresentativeNC(hom,b); + if (pp=false or new^pp in S) and locond(new) then S:=ClosureGroup(S,new); have:=true; cnt:=cnt+1; @@ -1024,31 +1024,39 @@ local ff,r,d,ser,u,v,i,j,k,p,bd,e,gens,lhom,M,N,hom,Q,Mim,q,ocr,split,MPcgs, ocr:=OneCocycles(Q,Mim); split:=ocr.isSplitExtension; if not split then - # test: Semisimple and Frattini - b:=MTX.BasisRadical(mo); - fratsim:=Length(b)=0; - if not fratsim then - b:=List(b,x->PreImagesRepresentative(hom,PcElementByExponents(MPcgs,x))); - for j in b do - N:=ClosureSubgroup(N,b); - od; - # insert in series - for j in [Length(ser),Length(ser)-1..i+1] do - ser[j+1]:=ser[j]; - od; - ser[i+1]:=N; - Info(InfoMorph,2,"insert1"); - else - # Frattini? - fratsim:=IsSubset(FrattiniSubgroup(Q),Mim); - if not fratsim then - N:=Intersection(FrattiniSubgroup(Q),Mim); - # insert - for j in [Length(ser),Length(ser)-1..i+1] do - ser[j+1]:=ser[j]; - od; - ser[i+1]:=PreImage(hom,N); - Info(InfoMorph,2,"insert2"); + # test: Semisimple and Frattini + b:=MTX.BasisRadical(mo); + fratsim:=Length(b)=0; + if not fratsim then + b:=List(b,x->PreImagesRepresentativeNC(hom,PcElementByExponents(MPcgs,x))); + for j in b do + N:=ClosureSubgroup(N,b); + od; + # insert + for j in [Length(ser),Length(ser)-1..i+1] do + ser[j+1]:=ser[j]; + od; + ser[i+1]:=N; + Info(InfoMorph,2,"insert1"); + else + # Frattini? + fratsim:=IsSubset(FrattiniSubgroup(Q),Mim); + if not fratsim then + N:=Intersection(FrattiniSubgroup(Q),Mim); + # insert + for j in [Length(ser),Length(ser)-1..i+1] do + ser[j+1]:=ser[j]; + od; + ser[i+1]:=PreImage(hom,N); + Info(InfoMorph,2,"insert2"); + fi; + N:=ser[i+1]; # the added normal + if rada<>fail + and ForAny(GeneratorsOfGroup(rada),x->N<>Image(x,N)) then + Info(InfoMorph,3,"radical automorphism stabilizer"); + SetIsGroupOfAutomorphismsFiniteGroup(rada,true); + NiceMonomorphism(rada:autactbase:=fail,someCharacteristics:=fail); + rada:=Stabilizer(rada,N,asAutom); fi; N:=ser[i+1]; # the added normal fi; @@ -1127,11 +1135,11 @@ local ff,r,d,ser,u,v,i,j,k,p,bd,e,gens,lhom,M,N,hom,Q,Mim,q,ocr,split,MPcgs, cond:=function(perm) local aut,newgens,mo2,iso,a; if perm in Aperm then - return true; - fi; - aut:=PreImagesRepresentative(AQiso,perm); - newgens:=List(gens,x->PreImagesRepresentative(comiso, - ImagesRepresentative(aut,ImagesRepresentative(comiso,x)))); + return true; + fi; + aut:=PreImagesRepresentativeNC(AQiso,perm); + newgens:=List(gens,x->PreImagesRepresentativeNC(comiso, + ImagesRepresentative(aut,ImagesRepresentative(comiso,x)))); mo2:=GModuleByMats(LinearActionLayer(newgens,MPcgs),mo.field); iso:=MTX.IsomorphismModules(mo,mo2); @@ -1161,11 +1169,11 @@ local ff,r,d,ser,u,v,i,j,k,p,bd,e,gens,lhom,M,N,hom,Q,Mim,q,ocr,split,MPcgs, precond:=function(perm) local aut,newgens,mo2; if perm in Aperm then - return true; - fi; - aut:=PreImagesRepresentative(AQiso,perm); - newgens:=List(GeneratorsOfGroup(Q), - x->PreImagesRepresentative(q,Image(aut,ImagesRepresentative(q,x)))); + return true; + fi; + aut:=PreImagesRepresentativeNC(AQiso,perm); + newgens:=List(GeneratorsOfGroup(Q), + x->PreImagesRepresentativeNC(q,Image(aut,ImagesRepresentative(q,x)))); mo2:=GModuleByMats(LinearActionLayer(newgens,MPcgs),mo.field); return MTX.IsomorphismModules(mo,mo2)<>fail; end; @@ -1173,11 +1181,11 @@ local ff,r,d,ser,u,v,i,j,k,p,bd,e,gens,lhom,M,N,hom,Q,Mim,q,ocr,split,MPcgs, cond:=function(perm) local aut,newgens,mo2,iso,a; if perm in Aperm then - return true; - fi; - aut:=PreImagesRepresentative(AQiso,perm); - newgens:=List(GeneratorsOfGroup(Q), - x->PreImagesRepresentative(q,Image(aut,ImagesRepresentative(q,x)))); + return true; + fi; + aut:=PreImagesRepresentativeNC(AQiso,perm); + newgens:=List(GeneratorsOfGroup(Q), + x->PreImagesRepresentativeNC(q,Image(aut,ImagesRepresentative(q,x)))); mo2:=GModuleByMats(LinearActionLayer(newgens,MPcgs),mo.field); iso:=MTX.IsomorphismModules(mo,mo2); if iso=fail then @@ -1234,12 +1242,12 @@ local ff,r,d,ser,u,v,i,j,k,p,bd,e,gens,lhom,M,N,hom,Q,Mim,q,ocr,split,MPcgs, # stabilize class k:=SmallGeneratingSet(sub); ac:=OrbitStabilizerAlgorithm(sub,false,false, - k,List(k,x->PreImagesRepresentative(AQiso,x)), + k,List(k,x->PreImagesRepresentativeNC(AQiso,x)), rec(pnt:=j, act:= function(set,phi) #local phi; - #phi:=PreImagesRepresentative(AQiso,perm); + #phi:=PreImagesRepresentativeNC(AQiso,perm); return Set(List(set,x->Image(phi,x))); end, onlystab:=true)); @@ -1365,10 +1373,10 @@ local ff,r,d,ser,u,v,i,j,k,p,bd,e,gens,lhom,M,N,hom,Q,Mim,q,ocr,split,MPcgs, for j in GeneratorsOfGroup(rada) do k:=GroupHomomorphismByImagesNC(rf,rf, GeneratorsOfGroup(rf), - List(GeneratorsOfGroup(rf), - y->ImagesRepresentative(hom,ImagesRepresentative(j, - PreImagesRepresentative(hom,y))))); - Assert(2,IsBijective(k)); + List(GeneratorsOfGroup(rf), + y->ImagesRepresentative(hom,ImagesRepresentative(j, + PreImagesRepresentativeNC(hom,y))))); + Assert(2,IsBijective(k)); Add(ind,k); od; @@ -1387,81 +1395,81 @@ local ff,r,d,ser,u,v,i,j,k,p,bd,e,gens,lhom,M,N,hom,Q,Mim,q,ocr,split,MPcgs, # reduce to subgroup that induces valid automorphisms Info(InfoMorph,1,"Radical autos reduce by factor ",Size(res)/Size(ind)); resperm:=IsomorphismPermGroup(C); - proj:=GroupHomomorphismByImagesNC(AQP,Image(resperm), - B[2],List(GeneratorsOfGroup(res),x->ImagesRepresentative(resperm,x))); - C:=PreImage(proj,Image(resperm,ind)); - C:=List(SmallGeneratingSet(C),x->PreImagesRepresentative(AQiso,x)); - AQ:=Group(C); - SetIsFinite(AQ,true); - SetIsGroupOfAutomorphismsFiniteGroup(AQ,true); + proj:=GroupHomomorphismByImagesNC(AQP,Image(resperm), + B[2],List(GeneratorsOfGroup(res),x->ImagesRepresentative(resperm,x))); + C:=PreImage(proj,Image(resperm,ind)); + C:=List(SmallGeneratingSet(C),x->PreImagesRepresentativeNC(AQiso,x)); + AQ:=Group(C); + SetIsFinite(AQ,true); + SetIsGroupOfAutomorphismsFiniteGroup(AQ,true); makeaqiso(); fi; # # hook for using existing characteristics to reduce for next step if somechar<>fail then u:=Filtered(Unique(List(somechar,x->Image(hom,x))),x->Size(x)>1); - u:=Filtered(u,s->ForAny(GeneratorsOfGroup(AQ),h->Image(h,s)<>s)); - SortBy(u,Size); - Info(InfoMorph,1,"Forced characteristics ",List(u,Size)); - - if scharorb<>fail then - # these are subgroups for which certain orbits must be stabilized. - C:=List(Reversed(scharorb),x->List(x,y->Image(hom,y))); - C:=Filtered(C,x->Size(x[1])>1 and Size(x[1])Size(x[1]))); - Append(u,C); - fi; - - if Length(u)>0 then - C:=MappingGeneratorsImages(AQiso); - if C[2]<>GeneratorsOfGroup(AQP) then - C:=[List(GeneratorsOfGroup(AQP), - x->PreImagesRepresentative(AQiso,x)), - GeneratorsOfGroup(AQP)]; - fi; - for j in u do - if IsList(j) then - # stabilizer set of subgroups - jorb:=ShallowCopy(Orbit(AQP,j[1],C[2],C[1],asAutom)); - jorpo:=[Position(jorb,j[1]),Position(jorb,j[2])]; - if jorpo[2]=fail then - Append(jorb,Orbit(AQP,j[1],C[2],C[1],asAutom)); - jorpo[2]:=Position(jorb,j[2]); - fi; - if Length(jorb)>Length(j) then - B:=ActionHomomorphism(AQP,jorb,C[2],C[1],asAutom); - substb:=Group(List(C[2],x->ImagesRepresentative(B,x)),()); - substb:=Stabilizer(substb,Set(jorpo),OnSets); - substb:=PreImage(B,substb); - Info(InfoMorph,2,"Stabilize characteristic orbit ",Size(j[1]), - " :",Size(AQP)/Size(substb) ); - else - substb:=AQP; - fi; - - - else - substb:=Stabilizer(AQP,j,C[2],C[1],asAutom); - Info(InfoMorph,2,"Stabilize characteristic subgroup ",Size(j), - " :",Size(AQP)/Size(substb) ); - fi; - if Size(substb)PreImagesRepresentative(AQiso,x)),substb]; - fi; - - od; - AQ:=Group(C[1]); - SetIsFinite(AQ,true); - SetIsGroupOfAutomorphismsFiniteGroup(AQ,true); - SetSize(AQ,Size(AQP)); - #AQP:=Group(C[2]); # ensure small gen set - #SetSize(AQP,Size(AQ)); - makeaqiso(); - fi; + u:=Filtered(u,s->ForAny(GeneratorsOfGroup(AQ),h->Image(h,s)<>s)); + SortBy(u,Size); + Info(InfoMorph,1,"Forced characteristics ",List(u,Size)); + + if scharorb<>fail then + # these are subgroups for which certain orbits must be stabilized. + C:=List(Reversed(scharorb),x->List(x,y->Image(hom,y))); + C:=Filtered(C,x->Size(x[1])>1 and Size(x[1])Size(x[1]))); + Append(u,C); + fi; + + if Length(u)>0 then + C:=MappingGeneratorsImages(AQiso); + if C[2]<>GeneratorsOfGroup(AQP) then + C:=[List(GeneratorsOfGroup(AQP), + x->PreImagesRepresentativeNC(AQiso,x)), + GeneratorsOfGroup(AQP)]; + fi; + for j in u do + if IsList(j) then + # stabilizer set of subgroups + jorb:=ShallowCopy(Orbit(AQP,j[1],C[2],C[1],asAutom)); + jorpo:=[Position(jorb,j[1]),Position(jorb,j[2])]; + if jorpo[2]=fail then + Append(jorb,Orbit(AQP,j[1],C[2],C[1],asAutom)); + jorpo[2]:=Position(jorb,j[2]); + fi; + if Length(jorb)>Length(j) then + B:=ActionHomomorphism(AQP,jorb,C[2],C[1],asAutom); + substb:=Group(List(C[2],x->ImagesRepresentative(B,x)),()); + substb:=Stabilizer(substb,Set(jorpo),OnSets); + substb:=PreImage(B,substb); + Info(InfoMorph,2,"Stabilize characteristic orbit ",Size(j[1]), + " :",Size(AQP)/Size(substb) ); + else + substb:=AQP; + fi; + + + else + substb:=Stabilizer(AQP,j,C[2],C[1],asAutom); + Info(InfoMorph,2,"Stabilize characteristic subgroup ",Size(j), + " :",Size(AQP)/Size(substb) ); + fi; + if Size(substb)PreImagesRepresentativeNC(AQiso,x)),substb]; + fi; + + od; + AQ:=Group(C[1]); + SetIsFinite(AQ,true); + SetIsGroupOfAutomorphismsFiniteGroup(AQ,true); + SetSize(AQ,Size(AQP)); + #AQP:=Group(C[2]); # ensure small gen set + #SetSize(AQP,Size(AQ)); + makeaqiso(); + fi; fi; lastperm:=AQiso; @@ -1883,7 +1891,7 @@ local d,a,map,cG,nG,nH,i,j,u,v,asAutomorphism,K,L,conj,e1,e2, else gens:=SmallGeneratingSet(api); fi; - pre:=List(gens,x->PreImagesRepresentative(iso,x)); + pre:=List(gens,x->PreImagesRepresentativeNC(iso,x)); map:=RepresentativeAction(SubgroupNC(a,pre),u,v,asAutomorphism); if map=fail then return fail; @@ -1904,6 +1912,6 @@ local d,a,map,cG,nG,nH,i,j,u,v,asAutomorphism,K,L,conj,e1,e2, fi; return GroupHomomorphismByImagesNC(G,H,GeneratorsOfGroup(G), - List(GeneratorsOfGroup(G),x->PreImagesRepresentative(e2, + List(GeneratorsOfGroup(G),x->PreImagesRepresentativeNC(e2, Image(conj,Image(e1,x))))); end); diff --git a/lib/clas.gi b/lib/clas.gi index 864fdea22c..b2fd2037d0 100644 --- a/lib/clas.gi +++ b/lib/clas.gi @@ -395,7 +395,7 @@ local H,cl,a,c; H:=Image(hom,G); cl:=[]; for c in ConjugacyClasses(H) do - a:=ConjugacyClass(G,PreImagesRepresentative(hom,Representative(c))); + a:=ConjugacyClass(G,PreImagesRepresentativeNC(hom,Representative(c))); if HasStabilizerOfExternalSet(c) then SetStabilizerOfExternalSet(a,PreImage(hom,StabilizerOfExternalSet(c))); fi; diff --git a/lib/clashom.gi b/lib/clashom.gi index 201b2cd9b7..ad19193c75 100644 --- a/lib/clashom.gi +++ b/lib/clashom.gi @@ -499,7 +499,7 @@ local clT, # classes T for k in clop do Info(InfoHomClass,1,"lifting class ",Representative(k)); - r:=PreImagesRepresentative(ophom,Representative(k)); + r:=PreImagesRepresentativeNC(ophom,Representative(k)); # try to make r of small order rp:=r^Order(Representative(k)); rp:=RepresentativeAction(M,Concatenation(components), @@ -544,134 +544,134 @@ local clT, # classes T end; for j in [1..Length(reps)] do - scj:=Size(centralizers[j]); - dsz:=0; - centrhom:=ActionHomomorphism(centralizers_r[j],components[i], - "surjective"); - localcent_r:=Image(centrhom); - Info(InfoHomClass,4,i,":",j); - Info(InfoHomClass,3,"acting: ",Size(centralizers[j])," minimum ", - Int(Size(Image(projections[i]))/Size(centralizers[j])), - " orbits."); - # compute C(r)-classes - clTR:=[]; - for l in clT do - Info(InfoHomClass,4,"DC",Index(T,l[2])," ",Index(T,localcent_r)); - dc:=DoubleCosetRepsAndSizes(T,l[2],localcent_r); - clTR:=Concatenation(clTR,List(dc,i->l[1]^i[1])); - od; - - orb:=[]; - for p in [1..Length(clTR)] do - - repres:=PreImagesRepresentative(projections[i],clTR[p]); - if i=1 or isdirprod - or reps[j]*RestrictedPermNC(repres,components[i]) - in Mproj[i] then - stab:=Centralizer(localcent_r,clTR[p]); - if Index(localcent_r,stab)clTR[p] then - genpos:=Position(img,clTR[p]); - img:=Permuted(img,(1,genpos)); - fi; - else - img:=ConjugacyClass(localcent_r,clTR[p],stab); - fi; - Add(orb,[repres,PreImage(centrhom,stab),img,localcent_r]); - fi; - od; - clTR:=orb; - - #was: - #clTR:=List(clTR,i->ConjugacyClass(localcent_r,i)); - #clTR:=List(clTR,j->[PreImagesRepresentative(projections[i], - # Representative(j)), - # PreImage(centrhom,Centralizer(j)), - # j]); - - # put small classes to the top (to be sure to hit them and make - # large local stabilizers) - SortBy(clTR,x->Size(x[3])); - - Info(InfoHomClass,3,Length(clTR)," local classes"); - - cystr:=[]; - for p in [1..Length(clTR)] do - repres:=Immutable(CycleStructurePerm(Representative(clTR[p][3]))); - select:=First(cystr,x->x[1]=repres); - if select=fail then - Add(cystr,[repres,[p]]); - else - AddSet(select[2],p); - fi; - od; - - cengen:=GeneratorsOfGroup(centralizers[j]); - if Length(cengen)>10 then - cengen:=SmallGeneratingSet(centralizers[j]); - fi; - #cengen:=Filtered(cengen,i->not i in localcent_r); - - while Length(clTR)>0 do - - # orbit algorithm on classes - stab:=clTR[1][2]; - orb:=[clTR[1]]; - #repres:=RestrictedPermNC(clTR[1][1],components[i]); - repres:=clTR[1][1]; - trans:=[One(M)]; - select:=[2..Length(clTR)]; - - orpo:=1; - minlen:=Size(orb[1][3]); - possible:=false; - stabtrue:=false; - pf:=infinity; - maxdiff:=Size(T); - again:=0; - trymap:=false; - ug:=[]; - # test whether we have full orbit and full stabilizer - while Size(centralizers[j])>(Sum(orb,i->Size(i[3]))*Size(stab)) do - genpos:=1; - while genpos<=Length(cengen) and - Size(centralizers[j])>(Sum(orb,i->Size(i[3]))*Size(stab)) do - gen:=cengen[genpos]; - skip:=false; - if trymap<>false then - orpo:=trymap[1]; - gen:=trymap[2]; - trymap:=false; - elif again>0 then - if not IsBound(ug[genpos]) then - ug[genpos]:=Intersection(centralizers_r[j], - ConjugateSubgroup(centralizers_r[j],gen^-1)); - fi; - if again<500 and ForAll(GeneratorsOfGroup(centralizers_r[j]), - i->i in ug[genpos]) - then - # the random elements will give us nothing new - skip:=true; - else - # get an element not in ug[genpos] - repeat - img:=Random(centralizers_r[j]); - until not img in ug[genpos] or again>=500; - gen:=img*gen; - fi; - fi; - - if not skip then - - img:=Image(projections[i],opfun(orb[orpo][1],gen)); - - smacla:=select; - - if not stabtrue then - p:=PositionProperty(orb,i->img in i[3]); - ppos:=fail; + scj:=Size(centralizers[j]); + dsz:=0; + centrhom:=ActionHomomorphism(centralizers_r[j],components[i], + "surjective"); + localcent_r:=Image(centrhom); + Info(InfoHomClass,4,i,":",j); + Info(InfoHomClass,3,"acting: ",Size(centralizers[j])," minimum ", + Int(Size(Image(projections[i]))/Size(centralizers[j])), + " orbits."); + # compute C(r)-classes + clTR:=[]; + for l in clT do + Info(InfoHomClass,4,"DC",Index(T,l[2])," ",Index(T,localcent_r)); + dc:=DoubleCosetRepsAndSizes(T,l[2],localcent_r); + clTR:=Concatenation(clTR,List(dc,i->l[1]^i[1])); + od; + + orb:=[]; + for p in [1..Length(clTR)] do + + repres:=PreImagesRepresentativeNC(projections[i],clTR[p]); + if i=1 or isdirprod + or reps[j]*RestrictedPermNC(repres,components[i]) + in Mproj[i] then + stab:=Centralizer(localcent_r,clTR[p]); + if Index(localcent_r,stab)clTR[p] then + genpos:=Position(img,clTR[p]); + img:=Permuted(img,(1,genpos)); + fi; + else + img:=ConjugacyClass(localcent_r,clTR[p],stab); + fi; + Add(orb,[repres,PreImage(centrhom,stab),img,localcent_r]); + fi; + od; + clTR:=orb; + + #was: + #clTR:=List(clTR,i->ConjugacyClass(localcent_r,i)); + #clTR:=List(clTR,j->[PreImagesRepresentative(projections[i], + # Representative(j)), + # PreImage(centrhom,Centralizer(j)), + # j]); + + # put small classes to the top (to be sure to hit them and make + # large local stabilizers) + SortBy(clTR,x->Size(x[3])); + + Info(InfoHomClass,3,Length(clTR)," local classes"); + + cystr:=[]; + for p in [1..Length(clTR)] do + repres:=Immutable(CycleStructurePerm(Representative(clTR[p][3]))); + select:=First(cystr,x->x[1]=repres); + if select=fail then + Add(cystr,[repres,[p]]); + else + AddSet(select[2],p); + fi; + od; + + cengen:=GeneratorsOfGroup(centralizers[j]); + if Length(cengen)>10 then + cengen:=SmallGeneratingSet(centralizers[j]); + fi; + #cengen:=Filtered(cengen,i->not i in localcent_r); + + while Length(clTR)>0 do + + # orbit algorithm on classes + stab:=clTR[1][2]; + orb:=[clTR[1]]; + #repres:=RestrictedPermNC(clTR[1][1],components[i]); + repres:=clTR[1][1]; + trans:=[One(M)]; + select:=[2..Length(clTR)]; + + orpo:=1; + minlen:=Size(orb[1][3]); + possible:=false; + stabtrue:=false; + pf:=infinity; + maxdiff:=Size(T); + again:=0; + trymap:=false; + ug:=[]; + # test whether we have full orbit and full stabilizer + while Size(centralizers[j])>(Sum(orb,i->Size(i[3]))*Size(stab)) do + genpos:=1; + while genpos<=Length(cengen) and + Size(centralizers[j])>(Sum(orb,i->Size(i[3]))*Size(stab)) do + gen:=cengen[genpos]; + skip:=false; + if trymap<>false then + orpo:=trymap[1]; + gen:=trymap[2]; + trymap:=false; + elif again>0 then + if not IsBound(ug[genpos]) then + ug[genpos]:=Intersection(centralizers_r[j], + ConjugateSubgroup(centralizers_r[j],gen^-1)); + fi; + if again<500 and ForAll(GeneratorsOfGroup(centralizers_r[j]), + i->i in ug[genpos]) + then + # the random elements will give us nothing new + skip:=true; + else + # get an element not in ug[genpos] + repeat + img:=Random(centralizers_r[j]); + until not img in ug[genpos] or again>=500; + gen:=img*gen; + fi; + fi; + + if not skip then + + img:=Image(projections[i],opfun(orb[orpo][1],gen)); + + smacla:=select; + + if not stabtrue then + p:=PositionProperty(orb,i->img in i[3]); + ppos:=fail; else # we have the stabilizer and thus are only interested in # getting new elements. @@ -694,50 +694,50 @@ local clT, # classes T return fail; fi; else - p:=ppos; - fi; - - RemoveSet(select,p); - Add(orb,clTR[p]); - - if trans[orpo]=false then - Add(trans,false); - else - #change the transversal element to map to the representative - con:=trans[orpo]*gen; - limg:=opfun(repres,con); - con:=con*PreImagesRepresentative(centrhom, - RepresentativeAction(localcent_r, - Image(projections[i],limg), - Representative(clTR[p][3]))); - Assert(2,Image(projections[i],opfun(repres,con)) - =Representative(clTR[p][3])); - - Add(trans,con); - - for stgen in GeneratorsOfGroup(clTR[p][2]) do - Assert( 2, IsOne( Image( projections[i], - opfun(repres,con*stgen/con)/repres ) ) ); - stab:=ClosureGroup(stab,con*stgen/con); - od; - fi; - - # compute new minimum length - - if Length(select)>0 then - remainlen:=List(clTR{select},i->Size(i[3])); - gcd:=Gcd(remainlen); - diff:=minlen-Sum(orb,i->Size(i[3])); - - if diff<0 then - # only go through this if the orbit actually grew - # larger - minlen:=Sum(orb,i->Size(i[3])); - repeat - if dsz=0 then - dsz:=DivisorsInt(scj); - fi; - while not minlen in dsz do + p:=ppos; + fi; + + RemoveSet(select,p); + Add(orb,clTR[p]); + + if trans[orpo]=false then + Add(trans,false); + else + #change the transversal element to map to the representative + con:=trans[orpo]*gen; + limg:=opfun(repres,con); + con:=con*PreImagesRepresentativeNC(centrhom, + RepresentativeAction(localcent_r, + Image(projections[i],limg), + Representative(clTR[p][3]))); + Assert(2,Image(projections[i],opfun(repres,con)) + =Representative(clTR[p][3])); + + Add(trans,con); + + for stgen in GeneratorsOfGroup(clTR[p][2]) do + Assert( 2, IsOne( Image( projections[i], + opfun(repres,con*stgen/con)/repres ) ) ); + stab:=ClosureGroup(stab,con*stgen/con); + od; + fi; + + # compute new minimum length + + if Length(select)>0 then + remainlen:=List(clTR{select},i->Size(i[3])); + gcd:=Gcd(remainlen); + diff:=minlen-Sum(orb,i->Size(i[3])); + + if diff<0 then + # only go through this if the orbit actually grew + # larger + minlen:=Sum(orb,i->Size(i[3])); + repeat + if dsz=0 then + dsz:=DivisorsInt(scj); + fi; + while not minlen in dsz do # workaround rare problem -- try again if First(dsz,i->i>=minlen)=fail then return ConjugacyClassesSubwreath( @@ -789,150 +789,150 @@ local clT, # classes T maxdiff:=diff; stabtrue:=true; fi; - - elif not stabtrue then - # we have an element that stabilizes the conjugacy class. - # correct this to an element that fixes the representative. - # (As we have taken already the centralizer in - # centralizers_r, it is sufficient to correct by - # centralizers_r-conjugation.) - con:=trans[orpo]*gen; - limg:=opfun(repres,con); - con:=con*PreImagesRepresentative(centrhom, - RepresentativeAction(localcent_r, - Image(projections[i],limg), - Representative(orb[p][3]))); - stab:=ClosureGroup(stab,con/trans[p]); - if Size(stab)*2*minlen>Size(centralizers[j]) then - Info(InfoHomClass,3, - "true stabilizer found (cannot grow)"); - minlen:=Size(centralizers[j])/Size(stab); - maxdiff:=minlen-Sum(orb,i->Size(i[3])); - stabtrue:=true; - fi; - fi; - - if stabtrue then - - smacla:=Filtered(select,i->Size(clTR[i][3])<=maxdiff); - - if Length(smacla)Size(i[3])); - - CompletionBar(InfoHomClass,3,"trueorb ",1-maxdiff/minlen); - #Info(InfoHomClass,3, - # "This is the true orbit length (missing ", - # maxdiff,")"); - - if Size(stab)*Sum(orb,i->Size(i[3])) - =Size(centralizers[j]) then +????? + elif not stabtrue then + # we have an element that stabilizes the conjugacy class. + # correct this to an element that fixes the representative. + # (As we have taken already the centralizer in + # centralizers_r, it is sufficient to correct by + # centralizers_r-conjugation.) + con:=trans[orpo]*gen; + limg:=opfun(repres,con); + con:=con*PreImagesRepresentativeNC(centrhom, + RepresentativeAction(localcent_r, + Image(projections[i],limg), + Representative(orb[p][3]))); + stab:=ClosureGroup(stab,con/trans[p]); + if Size(stab)*2*minlen>Size(centralizers[j]) then + Info(InfoHomClass,3, + "true stabilizer found (cannot grow)"); + minlen:=Size(centralizers[j])/Size(stab); + maxdiff:=minlen-Sum(orb,i->Size(i[3])); + stabtrue:=true; + fi; + fi; + + if stabtrue then + + smacla:=Filtered(select,i->Size(clTR[i][3])<=maxdiff); + + if Length(smacla)Size(i[3])); + + CompletionBar(InfoHomClass,3,"trueorb ",1-maxdiff/minlen); + #Info(InfoHomClass,3, + # "This is the true orbit length (missing ", + # maxdiff,")"); + + if Size(stab)*Sum(orb,i->Size(i[3])) + =Size(centralizers[j]) then maxdiff:=0; - elif Sum(remainlen)=maxdiff then - Info(InfoHomClass,2, - "Full possible remainder must fuse"); - orb:=Concatenation(orb,clTR{smacla}); - select:=Difference(select,smacla); - - else - # test whether there is only one possibility to get - # this length - if Length(smacla)<20 and - Sum(List([1..Minimum(Length(smacla), - Int(maxdiff/gcd+1))], - x-> NrCombinations(smacla,x)))<10000 then - # get all reasonable combinations - smare:=[1..Length(smacla)]; #range for smacla - combl:=Concatenation(List([1..Int(maxdiff/gcd+1)], - i->Combinations(smare,i))); - # pick those that have the correct length - combl:=Filtered(combl,i->Sum(remainlen{i})=maxdiff); - if Length(combl)>1 then - Info(InfoHomClass,3,"Addendum not unique (", - Length(combl)," possibilities)"); - if (maxdiff<10 or again>0) - and ForAll(combl,i->Length(i)<=5) then - # we have tried often enough, now try to pick the - # right ones - possible:=false; - combl:=Union(combl); - combl:=smacla{combl}; - genpos2:=1; - smacla:=[]; - while possible=false and Length(combl)>0 do - img:=Image(projections[i], - opfun(clTR[combl[1]][1],cengen[genpos2])); - p:=PositionProperty(orb,i->img in i[3]); - if p<>fail then - # it is! - Info(InfoHomClass,4,"got one!"); - - # remember the element to try - trymap:=[p,(cengen[genpos2]* - PreImagesRepresentative( - RestrictedMapping(projections[i], - centralizers[j]), - RepresentativeAction( - orb[p][4], - img,Representative(orb[p][3])) ))^-1]; - - Add(smacla,combl[1]); - combl:=combl{[2..Length(combl)]}; - if Sum(clTR{smacla},i->Size(i[3]))=maxdiff then - # bingo! - possible:=true; - fi; - fi; - genpos2:=genpos2+1; - if genpos2>Length(cengen) then - genpos2:=1; - combl:=combl{[2..Length(combl)]}; - fi; - od; - if possible=false then - Info(InfoHomClass,4,"Even test failed!"); - else - orb:=Concatenation(orb,clTR{smacla}); - select:=Difference(select,smacla); - Info(InfoHomClass,3,"Completed orbit (hard)"); - fi; - fi; - elif Length(combl)>0 then - combl:=combl[1]; - orb:=Concatenation(orb,clTR{smacla{combl}}); - select:=Difference(select,smacla{combl}); - Info(InfoHomClass,3,"Completed orbit"); - fi; - fi; - fi; - fi; - - fi; - else - Info(InfoHomClass,5,"skip"); - fi; # if not skip - - genpos:=genpos+1; - od; - orpo:=orpo+1; - if orpo>Length(orb) then - Info(InfoHomClass,3,"Size factor:",EvalF( - (Sum(orb,i->Size(i[3]))*Size(stab))/Size(centralizers[j])), - " orbit consists of ",Length(orb)," suborbits, iterating"); - - if stabtrue then - pper:=false; - # we know stabilizer, just need to find orbit. As these are - # likely small additions, search in reverse. - for p in select do - for genpos in [1..Length(cengen)] do - gen:=Random(centralizers_r[j])*cengen[genpos]; - img:=Image(projections[i],opfun(clTR[p][1],gen)); - orpo:=CycleStructurePerm(img); - ppos:=First(First(cystr,x->x[1]=orpo)[2], - i->not i in select and - img in clTR[i][3]); + elif Sum(remainlen)=maxdiff then + Info(InfoHomClass,2, + "Full possible remainder must fuse"); + orb:=Concatenation(orb,clTR{smacla}); + select:=Difference(select,smacla); + + else + # test whether there is only one possibility to get + # this length + if Length(smacla)<20 and + Sum(List([1..Minimum(Length(smacla), + Int(maxdiff/gcd+1))], + x-> NrCombinations(smacla,x)))<10000 then + # get all reasonable combinations + smare:=[1..Length(smacla)]; #range for smacla + combl:=Concatenation(List([1..Int(maxdiff/gcd+1)], + i->Combinations(smare,i))); + # pick those that have the correct length + combl:=Filtered(combl,i->Sum(remainlen{i})=maxdiff); + if Length(combl)>1 then + Info(InfoHomClass,3,"Addendum not unique (", + Length(combl)," possibilities)"); + if (maxdiff<10 or again>0) + and ForAll(combl,i->Length(i)<=5) then + # we have tried often enough, now try to pick the + # right ones + possible:=false; + combl:=Union(combl); + combl:=smacla{combl}; + genpos2:=1; + smacla:=[]; + while possible=false and Length(combl)>0 do + img:=Image(projections[i], + opfun(clTR[combl[1]][1],cengen[genpos2])); + p:=PositionProperty(orb,i->img in i[3]); + if p<>fail then + # it is! + Info(InfoHomClass,4,"got one!"); + + # remember the element to try + trymap:=[p,(cengen[genpos2]* + PreImagesRepresentativeNC( + RestrictedMapping(projections[i], + centralizers[j]), + RepresentativeAction( + orb[p][4], + img,Representative(orb[p][3])) ))^-1]; + + Add(smacla,combl[1]); + combl:=combl{[2..Length(combl)]}; + if Sum(clTR{smacla},i->Size(i[3]))=maxdiff then + # bingo! + possible:=true; + fi; + fi; + genpos2:=genpos2+1; + if genpos2>Length(cengen) then + genpos2:=1; + combl:=combl{[2..Length(combl)]}; + fi; + od; + if possible=false then + Info(InfoHomClass,4,"Even test failed!"); + else + orb:=Concatenation(orb,clTR{smacla}); + select:=Difference(select,smacla); + Info(InfoHomClass,3,"Completed orbit (hard)"); + fi; + fi; + elif Length(combl)>0 then + combl:=combl[1]; + orb:=Concatenation(orb,clTR{smacla{combl}}); + select:=Difference(select,smacla{combl}); + Info(InfoHomClass,3,"Completed orbit"); + fi; + fi; + fi; + fi; + + fi; + else + Info(InfoHomClass,5,"skip"); + fi; # if not skip + + genpos:=genpos+1; + od; + orpo:=orpo+1; + if orpo>Length(orb) then + Info(InfoHomClass,3,"Size factor:",EvalF( + (Sum(orb,i->Size(i[3]))*Size(stab))/Size(centralizers[j])), + " orbit consists of ",Length(orb)," suborbits, iterating"); + + if stabtrue then + pper:=false; + # we know stabilizer, just need to find orbit. As these are + # likely small additions, search in reverse. + for p in select do + for genpos in [1..Length(cengen)] do + gen:=Random(centralizers_r[j])*cengen[genpos]; + img:=Image(projections[i],opfun(clTR[p][1],gen)); + orpo:=CycleStructurePerm(img); + ppos:=First(First(cystr,x->x[1]=orpo)[2], + i->not i in select and + img in clTR[i][3]); if ppos<>fail and p in select then # so the image is in clTR[ppos] which must be in orb ppos:=Position(orb,clTR[ppos]); @@ -1140,9 +1140,8 @@ local cs, # chief series of G # compute the classes of the simple nonabelian factor by random search hom:=NaturalHomomorphismByNormalSubgroupNC(G,lastM); cl:=ConjugacyClasses(Image(hom)); - cl:=List(cl,i->[PreImagesRepresentative(hom,Representative(i)), - PreImage(hom,StabilizerOfExternalSet(i))]); - cs:=Concatenation([G],Filtered(cs,x->IsSubset(lastM,x))); + cl:=List(cl,i->[PreImagesRepresentativeNC(hom,Representative(i)), + PreImage(hom,StabilizerOfExternalSet(i))]); fi; for i in [2..Length(cs)] do @@ -1183,144 +1182,146 @@ local cs, # chief series of G if IsNormal(G,subN) then - # only one -> Call standard process - - Fhom:=fail; - # is this an almost top factor? - if Index(G,M)<10 then - Thom:=NaturalHomomorphismByNormalSubgroupNC(G,subN); - T1:=Image(Thom,M); - S1:=Image(Thom); - if Size(Centralizer(S1,T1))=1 then - deg1:=NrMovedPoints(S1); - Info(InfoHomClass,2, - "top factor gives conjugating representation, deg ",deg1); - - Fhom:=Thom; - fi; - else - Thom:=NaturalHomomorphismByNormalSubgroupNC(M,subN); - T1:=Image(Thom,M); - fi; - - if Fhom=fail then - autos:=List(GeneratorsOfGroup(G), - i->GroupHomomorphismByImagesNC(T1,T1,GeneratorsOfGroup(T1), - List(GeneratorsOfGroup(T1), - j->Image(Thom,PreImagesRepresentative(Thom,j)^i)))); - - # find (probably another) permutation rep for T1 for which all - # automorphisms can be represented by permutations - arhom:=AutomorphismRepresentingGroup(T1,autos); - S1:=arhom[1]; - deg1:=NrMovedPoints(S1); - Fhom:=GroupHomomorphismByImagesNC(G,S1,GeneratorsOfGroup(G),arhom[3]); - fi; - - - F:=Image(Fhom,G); - - clF:=ClassesFromClassical(F); - if clF=fail then - clF:=ConjugacyClassesByRandomSearch(F); - fi; - - clF:=List(clF,j->[Representative(j),StabilizerOfExternalSet(j)]); + # only one -> Call standard process + + Fhom:=fail; + # is this an almost top factor? + if Index(G,M)<10 then + Thom:=NaturalHomomorphismByNormalSubgroupNC(G,subN); + T1:=Image(Thom,M); + S1:=Image(Thom); + if Size(Centralizer(S1,T1))=1 then + deg1:=NrMovedPoints(S1); + Info(InfoHomClass,2, + "top factor gives conjugating representation, deg ",deg1); + + Fhom:=Thom; + fi; + else + Thom:=NaturalHomomorphismByNormalSubgroupNC(M,subN); + T1:=Image(Thom,M); + fi; + + if Fhom=fail then + autos:=List(GeneratorsOfGroup(G), + i->GroupHomomorphismByImagesNC(T1,T1,GeneratorsOfGroup(T1), + List(GeneratorsOfGroup(T1), + j->Image(Thom,PreImagesRepresentativeNC(Thom,j)^i)))); + + # find (probably another) permutation rep for T1 for which all + # automorphisms can be represented by permutations + arhom:=AutomorphismRepresentingGroup(T1,autos); + S1:=arhom[1]; + deg1:=NrMovedPoints(S1); + Fhom:=GroupHomomorphismByImagesNC(G,S1,GeneratorsOfGroup(G),arhom[3]); + fi; + + + C:=KernelOfMultiplicativeGeneralMapping(Fhom); + F:=Image(Fhom,G); + + clF:=ClassesFromClassical(F); + if clF=fail then + clF:=ConjugacyClassesByRandomSearch(F); + fi; + + clF:=List(clF,j->[Representative(j),StabilizerOfExternalSet(j)]); else - csM:=Orbit(G,subN); # all conjugates - n:=Length(csM); - - if n=1 then - Error("this cannot happen"); - T:=M; - fi; - - T:=Intersection(csM{[2..Length(csM)]}); # one T_i - if Length(GeneratorsOfGroup(T))>5 then - T:=Group(SmallGeneratingSet(T)); - fi; - - T:=Orbit(G,T); # get all the t's - # now T[1] is a complement to csM[1] in G/N. - - # now compute the operation of G on M/N - Qhom:=ActionHomomorphism(G,T,"surjective"); - Q:=Image(Qhom,G); - S:=PreImage(Qhom,Stabilizer(Q,1)); - - # find a permutation rep. for S-action on T[1] - Thom:=NaturalHomomorphismByNormalSubgroupNC(T[1],N); - T1:=Image(Thom); - if not IsSubset([1..NrMovedPoints(T1)], - MovedPoints(T1)) then - Thom:=Thom*ActionHomomorphism(T1,MovedPoints(T1),"surjective"); - fi; - T1:=Image(Thom,T[1]); - if IsPermGroup(T1) and - NrMovedPoints(T1)>SufficientlySmallDegreeSimpleGroupOrder(Size(T1)) then - Thom:=Thom*SmallerDegreePermutationRepresentation(T1:cheap); - Info(InfoHomClass,1,"reduced simple degree ",NrMovedPoints(T1), - " ",NrMovedPoints(Image(Thom))); - T1:=Image(Thom,T[1]); - fi; - - autos:=List(GeneratorsOfGroup(S), - i->GroupHomomorphismByImagesNC(T1,T1,GeneratorsOfGroup(T1), - List(GeneratorsOfGroup(T1), - j->Image(Thom,PreImagesRepresentative(Thom,j)^i)))); - - # find (probably another) permutation rep for T1 for which all - # automorphisms can be represented by permutations - arhom:=AutomorphismRepresentingGroup(T1,autos); - S1:=arhom[1]; - deg1:=NrMovedPoints(S1); - Thom:=GroupHomomorphismByImagesNC(S,S1,GeneratorsOfGroup(S),arhom[3]); - - T1:=Image(Thom,T[1]); - - # now embed into wreath - w:=WreathProduct(S1,Q); - wbas:=DirectProduct(List([1..n],i->S1)); - emb:=List([1..n+1],i->Embedding(w,i)); - proj:=List([1..n],i->Projection(wbas,i)); - components:=WreathProductInfo(w).components; - - # define isomorphisms between the components - reps:=List([1..n],i-> - PreImagesRepresentative(Qhom,RepresentativeAction(Q,1,i))); - - genimages:=[]; - for j in GeneratorsOfGroup(G) do - img:=Image(Qhom,j); - gimg:=Image(emb[n+1],img); - for k in [1..n] do - # look at part of j's action on the k-th factor. - # we get this by looking at the action of - # reps[k] * j * reps[k^img]^-1 - # 1 -> k -> k^img -> 1 - # on the first component. - act:=reps[k]*j*(reps[k^img]^-1); - # this must be multiplied *before* permuting - gimg:=ImageElm(emb[k],ImageElm(Thom,act))*gimg; - gimg:=RestrictedPermNC(gimg,MovedPoints(w)); - od; - Add(genimages,gimg); - od; - - F:=Subgroup(w,genimages); - if AssertionLevel()>=2 then - Fhom:=GroupHomomorphismByImages(G,F,GeneratorsOfGroup(G),genimages); - Assert(1,fail<>Fhom); - else - Fhom:=GroupHomomorphismByImagesNC(G,F,GeneratorsOfGroup(G),genimages); - fi; - - Info(InfoHomClass,1,"constructed Fhom"); - - # 2) compute the classes for F - - if n>1 then + csM:=Orbit(G,subN); # all conjugates + n:=Length(csM); + + if n=1 then + Error("this cannot happen"); + T:=M; + fi; + + T:=Intersection(csM{[2..Length(csM)]}); # one T_i + if Length(GeneratorsOfGroup(T))>5 then + T:=Group(SmallGeneratingSet(T)); + fi; + + T:=Orbit(G,T); # get all the t's + # now T[1] is a complement to csM[1] in G/N. + + # now compute the operation of G on M/N + Qhom:=ActionHomomorphism(G,T,"surjective"); + Q:=Image(Qhom,G); + S:=PreImage(Qhom,Stabilizer(Q,1)); + + # find a permutation rep. for S-action on T[1] + Thom:=NaturalHomomorphismByNormalSubgroupNC(T[1],N); + T1:=Image(Thom); + if not IsSubset([1..NrMovedPoints(T1)], + MovedPoints(T1)) then + Thom:=Thom*ActionHomomorphism(T1,MovedPoints(T1),"surjective"); + fi; + T1:=Image(Thom,T[1]); + if IsPermGroup(T1) and + NrMovedPoints(T1)>SufficientlySmallDegreeSimpleGroupOrder(Size(T1)) then + Thom:=Thom*SmallerDegreePermutationRepresentation(T1:cheap); + Info(InfoHomClass,1,"reduced simple degree ",NrMovedPoints(T1), + " ",NrMovedPoints(Image(Thom))); + T1:=Image(Thom,T[1]); + fi; + + autos:=List(GeneratorsOfGroup(S), + i->GroupHomomorphismByImagesNC(T1,T1,GeneratorsOfGroup(T1), + List(GeneratorsOfGroup(T1), + j->Image(Thom,PreImagesRepresentativeNC(Thom,j)^i)))); + + # find (probably another) permutation rep for T1 for which all + # automorphisms can be represented by permutations + arhom:=AutomorphismRepresentingGroup(T1,autos); + S1:=arhom[1]; + deg1:=NrMovedPoints(S1); + Thom:=GroupHomomorphismByImagesNC(S,S1,GeneratorsOfGroup(S),arhom[3]); + + T1:=Image(Thom,T[1]); + + # now embed into wreath + w:=WreathProduct(S1,Q); + wbas:=DirectProduct(List([1..n],i->S1)); + emb:=List([1..n+1],i->Embedding(w,i)); + proj:=List([1..n],i->Projection(wbas,i)); + components:=WreathProductInfo(w).components; + + # define isomorphisms between the components + reps:=List([1..n],i-> + PreImagesRepresentativeNC(Qhom,RepresentativeAction(Q,1,i))); + + genimages:=[]; + for j in GeneratorsOfGroup(G) do + img:=Image(Qhom,j); + gimg:=Image(emb[n+1],img); + for k in [1..n] do + # look at part of j's action on the k-th factor. + # we get this by looking at the action of + # reps[k] * j * reps[k^img]^-1 + # 1 -> k -> k^img -> 1 + # on the first component. + act:=reps[k]*j*(reps[k^img]^-1); + # this must be multiplied *before* permuting + gimg:=ImageElm(emb[k],ImageElm(Thom,act))*gimg; + gimg:=RestrictedPermNC(gimg,MovedPoints(w)); + od; + Add(genimages,gimg); + od; + + F:=Subgroup(w,genimages); + if AssertionLevel()>=2 then + Fhom:=GroupHomomorphismByImages(G,F,GeneratorsOfGroup(G),genimages); + Assert(1,fail<>Fhom); + else + Fhom:=GroupHomomorphismByImagesNC(G,F,GeneratorsOfGroup(G),genimages); + fi; + C:=KernelOfMultiplicativeGeneralMapping(Fhom); + + Info(InfoHomClass,1,"constructed Fhom"); + + # 2) compute the classes for F + + if n>1 then #if IsPermGroup(F) and NrMovedPoints(F)<18 then # # the old Butler/Theissen approach is still OK # clF:=[]; @@ -1337,30 +1338,30 @@ local cs, # chief series of G clF:=ConjugacyClassesSubwreath(F,FM,n,S1, Action(FM,components[1]),T1,components,emb,proj); if clF=fail then - #Error("failure"); - # weird error happened -- redo - j:=Random(SymmetricGroup(MovedPoints(G))); - FM:=List(GeneratorsOfGroup(G),x->x^j); - F:=Group(FM); - SetSize(F,Size(G)); - FM:=GroupHomomorphismByImagesNC(G,F,GeneratorsOfGroup(G),FM); - clF:=ConjugacyClassesFittingFreeGroup(F); - clF:=List(clF,x->[PreImagesRepresentative(FM,x[1]),PreImage(FM,x[2])]); - return clF; - fi; - #fi; - else - FM:=Image(Fhom,M); - Info(InfoHomClass,1, - "classes by random search in almost simple group"); - - clF:=ClassesFromClassical(F); - if clF=fail then - clF:=ConjugacyClassesByRandomSearch(F); - fi; - - clF:=List(clF,j->[Representative(j),StabilizerOfExternalSet(j)]); - fi; + #Error("failer"); + # weird error happened -- redo + j:=Random(SymmetricGroup(MovedPoints(G))); + FM:=List(GeneratorsOfGroup(G),x->x^j); + F:=Group(FM); + SetSize(F,Size(G)); + FM:=GroupHomomorphismByImagesNC(G,F,GeneratorsOfGroup(G),FM); + clF:=ConjugacyClassesFittingFreeGroup(F); + clF:=List(clF,x->[PreImagesRepresentativeNC(FM,x[1]),PreImage(FM,x[2])]); + return clF; + fi; + #fi; + else + FM:=Image(Fhom,M); + Info(InfoHomClass,1, + "classes by random search in almost simple group"); + + clF:=ClassesFromClassical(F); + if clF=fail then + clF:=ConjugacyClassesByRandomSearch(F); + fi; + + clF:=List(clF,j->[Representative(j),StabilizerOfExternalSet(j)]); + fi; fi; # true orbit of T. Assert(2,Sum(clF,i->Index(F,i[2]))=Size(F)); @@ -1371,106 +1372,106 @@ local cs, # chief series of G # the length(cl)=1 gets rid of solvable stuff on the top we got ``too # early''. if IsSubgroup(N,KernelOfMultiplicativeGeneralMapping(Fhom)) then - Info(InfoHomClass,1, - "homomorphism is faithful for relevant factor, take preimages"); - if Size(N)=1 and onlysizes=true then - cl:=List(clF,i->[PreImagesRepresentative(Fhom,i[1]),Size(i[2])]); - else - cl:=List(clF,i->[PreImagesRepresentative(Fhom,i[1]), - PreImage(Fhom,i[2])]); + Info(InfoHomClass,1, + "homomorphism is faithful for relevant factor, take preimages"); + if Size(N)=1 and onlysizes=true then + cl:=List(clF,i->[PreImagesRepresentativeNC(Fhom,i[1]),Size(i[2])]); + else + cl:=List(clF,i->[PreImagesRepresentativeNC(Fhom,i[1]), + PreImage(Fhom,i[2])]); fi; else - Info(InfoHomClass,1,"forming subdirect products"); - - FM:=Image(Fhom,lastM); - FMhom:=RestrictedMapping(Fhom,lastM); - if Index(F,FM)=1 then - Info(InfoHomClass,1,"degenerated to direct product"); - ncl:=[]; - for j in cl do - for k in clF do - # modify the representative with a kernel elm. to project - # correctly on the second component - elm:=j[1]*PreImagesRepresentative(FMhom, - LeftQuotient(Image(Fhom,j[1]),k[1])); - zentr:=Intersection(j[2],PreImage(Fhom,k[2])); - Assert(3,ForAll(GeneratorsOfGroup(zentr), - i->Comm(i,elm) in N)); - Add(ncl,[elm,zentr]); - od; - od; - - cl:=ncl; - - else - - # first we add the centralizer closures and sort by them - # (this allows to reduce the number of double coset calculations) - ncl:=[]; - for j in cl do - Cim:=Image(Fhom,j[2]); - CimCl:=Cim; - #CimCl:=ClosureGroup(FM,Cim); # should be unnecessary, as we took - # the full preimage - p:=PositionProperty(ncl,i->i[1]=CimCl); - if p=fail then - Add(ncl,[CimCl,[j]]); - else - Add(ncl[p][2],j); - fi; - od; - - Qhom:=NaturalHomomorphismByNormalSubgroupNC(F,FM); - Q:=Image(Qhom); - FQhom:=Fhom*Qhom; - - # now construct the sdp's - cl:=[]; - for j in ncl do - lj:=List(j[2],i->Image(FQhom,i[1])); - for k in clF do - # test whether the classes are potential mates - elm:=Image(Qhom,k[1]); - if not ForAll(lj,i->RepresentativeAction(Q,i,elm)=fail) then - - #l:=Image(Fhom,j[1]); - - if Index(F,j[1])=1 then - dc:=[()]; - else - dc:=List(DoubleCosetRepsAndSizes(F,k[2],j[1]),i->i[1]); - fi; - good:=0; - bad:=0; - for l in j[2] do - jim:=Image(FQhom,l[1]); - for l1 in dc do - elm:=k[1]^l1; - if Image(Qhom,elm)=jim then - # modify the representative with a kernel elm. to project - # correctly on the second component - elm:=l[1]*PreImagesRepresentative(FMhom, - LeftQuotient(Image(Fhom,l[1]),elm)); - zentr:=PreImage(Fhom,k[2]^l1); - zentr:=Intersection(zentr,l[2]); - - Assert(3,ForAll(GeneratorsOfGroup(zentr), - i->Comm(i,elm) in N)); - - Info(InfoHomClass,4,"new class, order ",Order(elm), - ", size=",Index(G,zentr)); - Add(cl,[elm,zentr]); - good:=good+1; - else - Info(InfoHomClass,5,"not in"); - bad:=bad+1; - fi; - od; - od; - Info(InfoHomClass,4,good," good, ",bad," bad of ",Length(dc)); - fi; - od; - od; + Info(InfoHomClass,1,"forming subdirect products"); + + FM:=Image(Fhom,lastM); + FMhom:=RestrictedMapping(Fhom,lastM); + if Index(F,FM)=1 then + Info(InfoHomClass,1,"degenerated to direct product"); + ncl:=[]; + for j in cl do + for k in clF do + # modify the representative with a kernel elm. to project + # correctly on the second component + elm:=j[1]*PreImagesRepresentativeNC(FMhom, + LeftQuotient(Image(Fhom,j[1]),k[1])); + zentr:=Intersection(j[2],PreImage(Fhom,k[2])); + Assert(3,ForAll(GeneratorsOfGroup(zentr), + i->Comm(i,elm) in N)); + Add(ncl,[elm,zentr]); + od; + od; + + cl:=ncl; + + else + + # first we add the centralizer closures and sort by them + # (this allows to reduce the number of double coset calculations) + ncl:=[]; + for j in cl do + Cim:=Image(Fhom,j[2]); + CimCl:=Cim; + #CimCl:=ClosureGroup(FM,Cim); # should be unnecessary, as we took + # the full preimage + p:=PositionProperty(ncl,i->i[1]=CimCl); + if p=fail then + Add(ncl,[CimCl,[j]]); + else + Add(ncl[p][2],j); + fi; + od; + + Qhom:=NaturalHomomorphismByNormalSubgroupNC(F,FM); + Q:=Image(Qhom); + FQhom:=Fhom*Qhom; + + # now construct the sdp's + cl:=[]; + for j in ncl do + lj:=List(j[2],i->Image(FQhom,i[1])); + for k in clF do + # test whether the classes are potential mates + elm:=Image(Qhom,k[1]); + if not ForAll(lj,i->RepresentativeAction(Q,i,elm)=fail) then + + #l:=Image(Fhom,j[1]); + + if Index(F,j[1])=1 then + dc:=[()]; + else + dc:=List(DoubleCosetRepsAndSizes(F,k[2],j[1]),i->i[1]); + fi; + good:=0; + bad:=0; + for l in j[2] do + jim:=Image(FQhom,l[1]); + for l1 in dc do + elm:=k[1]^l1; + if Image(Qhom,elm)=jim then + # modify the representative with a kernel elm. to project + # correctly on the second component + elm:=l[1]*PreImagesRepresentativeNC(FMhom, + LeftQuotient(Image(Fhom,l[1]),elm)); + zentr:=PreImage(Fhom,k[2]^l1); + zentr:=Intersection(zentr,l[2]); + + Assert(3,ForAll(GeneratorsOfGroup(zentr), + i->Comm(i,elm) in N)); + + Info(InfoHomClass,4,"new class, order ",Order(elm), + ", size=",Index(G,zentr)); + Add(cl,[elm,zentr]); + good:=good+1; + else + Info(InfoHomClass,5,"not in"); + bad:=bad+1; + fi; + od; + od; + Info(InfoHomClass,4,good," good, ",bad," bad of ",Length(dc)); + fi; + od; + od; fi; # real subdirect product fi; # else Fhom not faithful on factor @@ -2022,7 +2023,7 @@ BindGlobal("LiftClassesEATrivRep", nsfgens:=NormalIntersection(fants[usent],Group(cl[4])); fasize:=Size(nsfgens); nsfgens:=SmallGeneratingSet(nsfgens); - nsgens:=List(nsfgens,x->PreImagesRepresentative(hom,x)); + nsgens:=List(nsfgens,x->PreImagesRepresentativeNC(hom,x)); nsimgs:=List(Concatenation(pcgs,nsgens),npcgsact); mo:=GModuleByMats(nsimgs,field); if not MTX.IsIrreducible(mo) then @@ -2338,7 +2339,7 @@ local r, #radical if IsPermGroup(Range(hom)) and not IsPermGroup(Source(hom)) then f:=Image(hom,G); cl:=ConjugacyClassesFittingFreeGroup(f:onlysizes:=false); - cl:=List(cl,x->[PreImagesRepresentative(hom,x[1]), + cl:=List(cl,x->[PreImagesRepresentativeNC(hom,x[1]), PreImage(hom,x[2])]); else cl:=ConjugacyClassesFittingFreeGroup(G:onlysizes:=false); @@ -2398,12 +2399,12 @@ local r, #radical if ntrihom then ncl:=[]; for i in cl do - new:=[PreImagesRepresentative(hom,i[1])]; - if not IsInt(i[2]) then - Add(new,[]); # no generators in radical yet - gens:=SmallGeneratingSet(i[2]); - Add(new, - List(gens,x->PreImagesRepresentative(hom,x))); + new:=[PreImagesRepresentativeNC(hom,i[1])]; + if not IsInt(i[2]) then + Add(new,[]); # no generators in radical yet + gens:=SmallGeneratingSet(i[2]); + Add(new, + List(gens,x->PreImagesRepresentativeNC(hom,x))); Add(new,gens); #TODO: PreImage groups? #Add(new,PreImage(hom,i[2])); @@ -2886,10 +2887,10 @@ local r, #radical fi; prereps:=f!.classpreimgs; if not IsBound(prereps[j]) then - prereps[j]:=PreImagesRepresentative(hom,Representative(cl[j])); + prereps[j]:=PreImagesRepresentativeNC(hom,Representative(cl[j])); fi; - r:=PreImagesRepresentative(hom,conj); + r:=PreImagesRepresentativeNC(hom,conj); d:=GeneratorsOfGroup(Centralizer(cl[j])); # Format for cl is: @@ -2897,8 +2898,8 @@ local r, #radical # in factor, 4:conjugator, 5:cenpcgs, # 6:cenfac, 7:cenfacimgs, 8:censize, 9:cenfacsize Add(nreps,[i,i^r,prereps[j],r,[], - List(d,x->PreImagesRepresentative(hom,x)),d, - radsize*Size(Centralizer(cl[j])), Size(Centralizer(cl[j]))]); + List(d,x->PreImagesRepresentativeNC(hom,x)),d, + radsize*Size(Centralizer(cl[j])), Size(Centralizer(cl[j]))]); od; reps:=nreps; diff --git a/lib/csetgrp.gi b/lib/csetgrp.gi index cacd48249b..c3da828528 100644 --- a/lib/csetgrp.gi +++ b/lib/csetgrp.gi @@ -199,7 +199,7 @@ local cla,clb,i,j,k,bd,r,rep,b2,dc, r:=SmallerDegreePermutationRepresentation(b:cheap); k:=Image(r,b); gens:=MorFindGeneratingSystem(k,MorMaxFusClasses(MorRatClasses(k))); - gens:=List(gens,x->PreImagesRepresentative(r,x)); + gens:=List(gens,x->PreImagesRepresentativeNC(r,x)); else gens:=MorFindGeneratingSystem(b,MorMaxFusClasses(MorRatClasses(b))); fi; diff --git a/lib/ctblgrp.gi b/lib/ctblgrp.gi index b8c384ba3b..bc9db6ad24 100644 --- a/lib/ctblgrp.gi +++ b/lib/ctblgrp.gi @@ -1583,7 +1583,7 @@ local tm,tme,piso,gpcgs,gals,ord,l,l2,f,fgens,rws,pow,pos,i,j,k,gen, # not easily transfer to mod p. k:=Image(piso,TrivialSubgroup(D.galMorphisms)); gpcgs:=Pcgs(k); - gals:=List(gpcgs,i->PreImagesRepresentative(piso,i)); + gals:=List(gpcgs,i->PreImagesRepresentativeNC(piso,i)); ord:=List(gpcgs,i->RelativeOrderOfPcElement(gpcgs,i)); l:=Length(gpcgs); diff --git a/lib/ctblsolv.gi b/lib/ctblsolv.gi index 0379f7a3d3..ec25e87a5c 100644 --- a/lib/ctblsolv.gi +++ b/lib/ctblsolv.gi @@ -584,7 +584,7 @@ InstallGlobalFunction( CoveringTriplesCharacters, function( G, z ) ImageElm( h, z ) ), x -> [ PreImagesSet( h, x[1] ), PreImagesSet( h, x[2] ), - PreImagesRepresentative( h, x[3] ) ] ); + PreImagesRepresentativeNC( h, x[3] ) ] ); if p = i then @@ -624,7 +624,7 @@ InstallGlobalFunction( CoveringTriplesCharacters, function( G, z ) Append( r, List( CoveringTriplesCharacters( c, zn ), x -> [ PreImagesSet( h, x[1] ), PreImagesSet( h, x[2] ), - PreImagesRepresentative( h, x[3] ) ] ) ); + PreImagesRepresentativeNC( h, x[3] ) ] ) ); od; return r; @@ -664,7 +664,7 @@ InstallGlobalFunction( CoveringTriplesCharacters, function( G, z ) List( CoveringTriplesCharacters( img, ImageElm( h, z ) ), x -> [ PreImagesSet( h, x[1] ), PreImagesSet( h, x[2] ), - PreImagesRepresentative( h, x[3] ) ] ) ); + PreImagesRepresentativeNC( h, x[3] ) ] ) ); fi; od; return r; @@ -1056,7 +1056,7 @@ InstallMethod( BaumClausenInfo, for i in [ 2 .. Length( ssr.ds ) ] do j:= NaturalHomomorphismByNormalSubgroupNC( ssr.ds[ i-1 ], ssr.ds[i] ); Append( pcgs, List( SpecialPcgs( ImagesSource( j ) ), - x -> PreImagesRepresentative( j, x ) ) ); + x -> PreImagesRepresentativeNC( j, x ) ) ); od; Append( pcgs, SpecialPcgs( Last(ssr.ds) ) ); G:= ImagesSource( hom ); @@ -1900,8 +1900,7 @@ InstallMethod( BaumClausenInfo, k:= Pcgs( kernel ); pcgs:= PcgsByPcSequence( ElementsFamily( FamilyObj( kernel ) ), Concatenation( List( pcgs, - x -> PreImagesRepresentative( hom, x ) ), - k ) ); + x -> PreImagesRepresentativeNC( hom, x ) ), k ) ); k:= ListWithIdenticalEntries( Length( k ), 0 ); linear:= List( linear, rep -> Concatenation( rep, k ) ); diff --git a/lib/field.gi b/lib/field.gi index e8158367a7..964581fae0 100644 --- a/lib/field.gi +++ b/lib/field.gi @@ -1324,7 +1324,7 @@ InstallMethod( PreImagesElm, [ IsFieldHomomorphism, IsObject ], function ( hom, elm ) if IsInjective( hom ) = 1 then - return [ PreImagesRepresentative( hom, elm ) ]; + return [ PreImagesRepresentativeNC( hom, elm ) ]; elif IsZero( elm ) then return Source( hom ); else @@ -1343,7 +1343,7 @@ InstallMethod( PreImagesSet, [ IsFieldHomomorphism, IsField ], function ( hom, elms ) elms:= FieldByGenerators( List( GeneratorsOfField( elms ), - gen -> PreImagesRepresentative( hom, gen ) ) ); + gen -> PreImagesRepresentativeNC( hom, gen ) ) ); UseSubsetRelation( Source( hom ), elms ); return elms; end ); diff --git a/lib/fitfree.gi b/lib/fitfree.gi index d68681ea93..877494deef 100644 --- a/lib/fitfree.gi +++ b/lib/fitfree.gi @@ -135,7 +135,7 @@ local ffs,pcisom,rest,kpc,k,x,ker,r,pool,i,xx,pregens,iso; # od; SetSize(U,Size(Image(rest))*Size(kpc)); k:=InducedPcgs(FamilyPcgs(Image(pcisom)),kpc); - k:=List(k,x->PreImagesRepresentative(pcisom,x)); + k:=List(k,x->PreImagesRepresentativeNC(pcisom,x)); k:=InducedPcgsByPcSequenceNC(ffs.pcgs,k); ker:=SubgroupNC(G,k); SetSize(ker,Size(kpc)); @@ -916,8 +916,9 @@ local ser,hom,s,fphom,sf,sg,sp,fp,d,head,mran,nran,mpcgs,ocr,len,pcgs,gens; s:=SylowSubgroup(Image(hom),prime); fphom:=IsomorphismFpGroup(s); fp:=Image(fphom); - sf:=List(GeneratorsOfGroup(Image(fphom)),x->PreImagesRepresentative(fphom,x)); - sg:=List(sf,x->PreImagesRepresentative(hom,x)); + sf:=List(GeneratorsOfGroup(Image(fphom)), + x->PreImagesRepresentativeNC(fphom,x)); + sg:=List(sf,x->PreImagesRepresentativeNC(hom,x)); sp:=[]; RUN_IN_GGMBI:=true; # hack to skip Nice treatment fphom:=GroupGeneralMappingByImagesNC(Group(sg,One(G)),fp,sg, @@ -1194,9 +1195,9 @@ local s,d,c,act,o,i,j,h,p,hf,img,n,k,ns,all,hl,hcomp, norm:=n); for j in [2..Length(i)] do c[i[j]]:=rec(orbit:=i,orbitpos:=j, - rep:=PreImagesRepresentative(act, - RepresentativeAction(Image(act),i[1],i[j])), - component:=d[i[j]],hall:=h, norm:=n); + rep:=PreImagesRepresentativeNC(act, + RepresentativeAction(Image(act),i[1],i[j])), + component:=d[i[j]],hall:=h, norm:=n); od; od; @@ -1232,7 +1233,7 @@ local s,d,c,act,o,i,j,h,p,hf,img,n,k,ns,all,hl,hcomp, fp:=Range(fphom); gens:=MappingGeneratorsImages(fphom); imgs:=gens[2];gens:=gens[1]; - gens:=List(gens,x->PreImagesRepresentative(act,x)); + gens:=List(gens,x->PreImagesRepresentativeNC(act,x)); # adapt to normalize B gens:=List(gens,x->x/RepresentativeAction(t,b^x,b)); @@ -1280,7 +1281,7 @@ local s,d,c,act,o,i,j,h,p,hf,img,n,k,ns,all,hl,hcomp, fp:=Image(fphom); gens:=MappingGeneratorsImages(fphom); imgs:=gens[2];gens:=gens[1]; - gens:=List(gens,x->PreImagesRepresentative(hom,x)); + gens:=List(gens,x->PreImagesRepresentativeNC(hom,x)); fi; # now run through the candidates for Hall in S @@ -1408,8 +1409,9 @@ local ser,hom,s,fphom,sf,sg,sp,fp,d,head,mran,nran,mpcgs,ocr,len,pcgs, for s in HallsFittingFree(Image(hom),pi) do fphom:=IsomorphismFpGroup(s); fp:=Image(fphom); - sf:=List(GeneratorsOfGroup(Image(fphom)),x->PreImagesRepresentative(fphom,x)); - sg:=List(sf,x->PreImagesRepresentative(hom,x)); + sf:=List(GeneratorsOfGroup(Image(fphom)), + x->PreImagesRepresentativeNC(fphom,x)); + sg:=List(sf,x->PreImagesRepresentativeNC(hom,x)); sp:=[]; RUN_IN_GGMBI:=true; # hack to skip Nice treatment fphom:=GroupGeneralMappingByImagesNC(Group(sg,One(G)),fp,sg, diff --git a/lib/ghomperm.gi b/lib/ghomperm.gi index b29b194847..38e811426d 100644 --- a/lib/ghomperm.gi +++ b/lib/ghomperm.gi @@ -1152,7 +1152,7 @@ local r, fgens, gens, kg; fi; fgens:=ShallowCopy(GeneratorsOfGroup(r)); gens:=List(fgens, - i->PreImagesRepresentativeNC(hom2,PreImagesRepresentativeNC(hom1,i))); + i->PreImagesRepresentativeNC(hom2,PreImagesRepresentativeNC(hom1,i))); kg:=GeneratorsOfGroup(KernelOfMultiplicativeGeneralMapping(hom2)); Append(gens,kg); Append(fgens,List(kg,i->One(r))); diff --git a/lib/gpfpiso.gi b/lib/gpfpiso.gi index 202d9419a7..714b77d704 100644 --- a/lib/gpfpiso.gi +++ b/lib/gpfpiso.gi @@ -90,10 +90,10 @@ local l,iso,fp,stbc,gens; 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); + List(MappingGeneratorsImages(fp)[1], + i->PreImagesRepresentativeNC(iso,i)), + MappingGeneratorsImages(fp)[2]); + SetIsBijective(iso,true); return iso; fi; od; @@ -166,13 +166,13 @@ function( G, str ) # 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 ) ); + # compute presentation of H + IsNonabelianSimpleGroup(H); + IsNaturalAlternatingGroup(H); + new:=IsomorphismFpGroup(H,"@"); + gensH:=List(GeneratorsOfGroup(Image(new)), + i->PreImagesRepresentativeNC(new,i)); + preiH := List( gensH, x -> PreImagesRepresentativeNC( hom, x ) ); c := Length( gensH ); @@ -190,7 +190,7 @@ function( G, str ) 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 := PreImagesRepresentativeNC( free, t ); t := MappedWord( t, gensF, gensE{[c+1..n+c]} ); else t := One( E ); @@ -204,7 +204,7 @@ function( G, str ) 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 := PreImagesRepresentativeNC( free, t ); t := MappedWord( t, gensF, gensE{[c+1..n+c]} ); else t := One( E ); @@ -293,7 +293,7 @@ function(g,str,N) gens:=Union(gens,Union(List(ser,SmallGeneratingSet))); fi; if f<>g then - gens:=List(gens,x->PreImagesRepresentative(hom,x)); + gens:=List(gens,x->PreImagesRepresentativeNC(hom,x)); ser:=List(ser,x->PreImage(hom,x)); fi; # change generators to make split @@ -396,8 +396,8 @@ function(g,str,N) # 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)); + GroupHomomorphismByImagesNC(f,f,fgens, + List(fgens,j->Image(hom,PreImagesRepresentativeNC(hom,j)^i)):noassert)); for j in auts do SetIsBijective(j,true); od; @@ -426,7 +426,7 @@ function(g,str,N) else a:=IsomorphismFpGroup(sf:noassert); fi; - ad:=List(GeneratorsOfGroup(Range(a)),i->PreImagesRepresentative(a,i)); + ad:=List(GeneratorsOfGroup(Range(a)),i->PreImagesRepresentativeNC(a,i)); lad:=Length(ad); n:=Length(orb); @@ -461,7 +461,7 @@ function(g,str,N) fp:=fg/rels; a:=GroupHomomorphismByImagesNC(f,fp,fgens,GeneratorsOfGroup(fp):noassert); fi; - Append(gens,List(fgens,i->PreImagesRepresentative(hom,i))); + Append(gens,List(fgens,i->PreImagesRepresentativeNC(hom,i))); # here we really want a composed homomorphism, to avoid extra work for # a new stabilizer chain @@ -640,7 +640,7 @@ 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)); + qreps:=List(qgens,i->PreImagesRepresentativeNC(hom,i)); fpqg:=FreeGeneratorsOfFpGroup(fpq); rels:=[]; if IsModuloPcgs(mnsf) then @@ -694,7 +694,7 @@ local fpq, qgens, qreps, fpqg, rels, pcgs, p, f, qimg, idx, nimg, decomp, 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)); + pcgs:=List(GeneratorsOfGroup(p),i->PreImagesRepresentativeNC(mnsf,i)); f:=FreeGroup(Length(fpqg)+Length(pcgs)); qimg:=GeneratorsOfGroup(f){[1..Length(fpqg)]}; idx:=[Length(fpqg)+1..Length(fpqg)+Length(pcgs)]; @@ -966,7 +966,7 @@ function( G, series, str ) gensH := GeneratorsOfGroup( H ); gensH := Filtered( gensH, x -> x <> One(H) ); - preiH := List( gensH, x -> PreImagesRepresentative( hom, x ) ); + preiH := List( gensH, x -> PreImagesRepresentativeNC( hom, x ) ); c := Length( gensH ); # compute presentation of H @@ -989,7 +989,7 @@ function( G, series, str ) 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 := PreImagesRepresentativeNC( free, t ); t := MappedWord( t, gensF, gensE{[c+1..n+c]} ); else t := One( E ); @@ -1003,7 +1003,7 @@ function( G, series, str ) 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 := PreImagesRepresentativeNC( free, t ); t := MappedWord( t, gensF, gensE{[c+1..n+c]} ); else t := One( E ); @@ -1228,8 +1228,8 @@ local iso,fp,dec,homs,mos,i,j,ffp,imo,m,k,gens,fm,mgens,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:=LeftQuotient(PreImagesRepresentativeNC(iso,right), + PreImagesRepresentativeNC(iso,left)); diff:=ImagesRepresentative(iso,diff); left:=MappedWord(r[1],FreeGeneratorsOfFpMonoid(m),monreal); @@ -1248,7 +1248,7 @@ local iso,fp,dec,homs,mos,i,j,ffp,imo,m,k,gens,fm,mgens,rules, if reduce(mgens[k])=mgens[k] then right:=fmgens[j]^-1*fmgens[k]*fmgens[j]; #collect - right:=ImagesRepresentative(iso,PreImagesRepresentative(iso,right)); + right:=ImagesRepresentative(iso,PreImagesRepresentativeNC(iso,right)); right:=Product(List(LetterRepAssocWord(UnderlyingElement(right)), x->mgens[Position(nums,x)])); right:=reduce(mgens[j]*right); @@ -1320,7 +1320,7 @@ 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 + if List(GeneratorsOfGroup(fp),x->PreImagesRepresentativeNC(iso,x))<>pcgs then Error("pcgs"); fi; gens:=[]; @@ -1520,7 +1520,7 @@ local iso,n,fn,sz,bigcount,tryweyl; iso:=IsomorphismGroups(G,P); if iso<>fail then P:=List(GeneratorsOfGroup(H), - x->PreImagesRepresentative(iso,ImagesRepresentative(isp,x))); + x->PreImagesRepresentativeNC(iso,ImagesRepresentative(isp,x))); iso:=GroupHomomorphismByImagesNC(G,H,P,GeneratorsOfGroup(H)); fi; return iso; @@ -1728,13 +1728,13 @@ local isob,isos,iso,gens,a,rels,l,i,j,bgens,cb,cs,b,f,k,w,monoid, # 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))); + x->PreImagesRepresentativeNC(pciso,PreImagesRepresentativeNC(cb.fphom,x))); b:=Range(isob); wgens:=GeneratorsOfGroup(weyl); - bgens:=List(GeneratorsOfGroup(b),x->PreImagesRepresentative(isob,x)); + bgens:=List(GeneratorsOfGroup(b),x->PreImagesRepresentativeNC(isob,x)); if newstyle and bgens<>GeneratorsOfGroup(borel) then Error("gens");fi; bpairs:=Concatenation(List(bgens,x->[x,x^-1])); @@ -1879,7 +1879,7 @@ local isob,isos,iso,gens,a,rels,l,i,j,bgens,cb,cs,b,f,k,w,monoid, x:=UnderlyingElement(ImagesRepresentative(cb.monhom,x)); x:=reduce(x,RelationsOfFpMonoid(monoid),mdag,fail); x:=ElementOfFpMonoid(FamilyObj(One(monoid)),x); - return PreImagesRepresentative(cb.monhom,x); + return PreImagesRepresentativeNC(cb.monhom,x); end; mdag:=EmptyKBDAG(Union(List(FreeGeneratorsOfFpMonoid(monoid), @@ -1924,7 +1924,7 @@ local isob,isos,iso,gens,a,rels,l,i,j,bgens,cb,cs,b,f,k,w,monoid, x:=UnderlyingElement(ImagesRepresentative(cs.monhom,x)); x:=reduce(x,RelationsOfFpMonoid(Range(cs.monhom)),wdag,fail); x:=ElementOfFpMonoid(FamilyObj(One(Range(cs.monhom))),x); - return PreImagesRepresentative(cs.monhom,x); + return PreImagesRepresentativeNC(cs.monhom,x); end; wdag:=EmptyKBDAG(Union(List(FreeGeneratorsOfFpMonoid(Range(cs.monhom)), @@ -1966,9 +1966,8 @@ local isob,isos,iso,gens,a,rels,l,i,j,bgens,cb,cs,b,f,k,w,monoid, 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,()); + borela:=List(bgens,x->MappedWord(PreImagesRepresentativeNC(iso,x),MappingGeneratorsImages(iso)[1],borela)); + act:=Group(borela,()); bhom:=GroupHomomorphismByImagesNC(borel,act,bgens,csetperm); #Assert(0,bhom<>fail); @@ -2055,11 +2054,14 @@ local isob,isos,iso,gens,a,rels,l,i,j,bgens,cb,cs,b,f,k,w,monoid, 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]; + #pos:=PositionProperty(dc,y->elm in y); + pos:=rti[PositionCanonical(rt,elm)]; + #rep:=RepresentativeAction(borel,PositionCanonical(rt,elm), + # PositionCanonical(rt,dcreps[pos]),bgens,borela,OnPoints); + rep:=PreImagesRepresentativeNC(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; @@ -2441,7 +2443,7 @@ if rule[1]=rule[2] then return;fi; else # BN-style reductions - pcgs:=List(GeneratorsOfGroup(b),x->PreImagesRepresentative(isob,x)); + pcgs:=List(GeneratorsOfGroup(b),x->PreImagesRepresentativeNC(isob,x)); # remove powers pcgs:=pcgs{ Filtered([1..Length(pcgs)],i->not ForAny([1..i-1], @@ -2455,7 +2457,7 @@ if rule[1]=rule[2] then return;fi; # 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); + pri:=PreImagesRepresentativeNC(isos,i); stb:=Intersection(borel,borel^(pri^-1)); Info(InfoFpGroup,2,i," ",Size(stb)); @@ -2511,14 +2513,14 @@ if rule[1]=rule[2] then return;fi; Info(InfoFpGroup,3,"borelrun ",Position(wo,i)," of ",Length(wo)); # rewrite i*b*j as \tilde b*k*\hat b. - pri:=PreImagesRepresentative(isos,i); + pri:=PreImagesRepresentativeNC(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:=PreImagesRepresentativeNC(isos,i)*k* + PreImagesRepresentativeNC(isos,j); a:=decomp(a); a:=[nofob(ImagesRepresentative(isob,a[1])), nofow(ImagesRepresentative(isos,a[2])), @@ -2684,7 +2686,7 @@ end); # 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)))); +# PreImagesRepresentativeNC(miso,x)))); # if ForAny(pre,x->Length(x)<>1) then Error("double");fi; # Add(l,Concatenation(pre)); # if IsBound(m!.rewritingSystem) then diff --git a/lib/gpprmsya.gi b/lib/gpprmsya.gi index a88508a2bb..d0af65692e 100644 --- a/lib/gpprmsya.gi +++ b/lib/gpprmsya.gi @@ -1265,7 +1265,7 @@ syll, act, typ, sel, bas, wdom, comp, lperm, other, away, i, j,b0,opg,bp; w:=AutomorphismGroup(b); opg:=NaturalHomomorphismByNormalSubgroupNC(w, InnerAutomorphismsAutomorphismGroup(w)); - ll:=List(AsSSortedList(Image(opg)),x->PreImagesRepresentative(opg,x)); + ll:=List(AsSSortedList(Image(opg)),x->PreImagesRepresentativeNC(opg,x)); ll:=Filtered(ll,IsConjugatorAutomorphism); ll:=List(ll,ConjugatorInnerAutomorphism); pg:=b; diff --git a/lib/gprd.gi b/lib/gprd.gi index e32bf13af7..c5df0b6f66 100644 --- a/lib/gprd.gi +++ b/lib/gprd.gi @@ -715,7 +715,7 @@ InstallGlobalFunction(InnerSubdirectProducts2,function( D, U, V ) # and obtain double coset reps reps := List( DoubleCosets( P, autU, autV ), Representative ); - reps := List( reps, x -> PreImagesRepresentative( gamma, x ) ); + reps := List( reps, x -> PreImagesRepresentativeNC( gamma, x ) ); # loop over automorphisms for rep in reps do @@ -724,9 +724,9 @@ InstallGlobalFunction(InnerSubdirectProducts2,function( D, U, V ) gens := Concatenation( GeneratorsOfGroup( N ), GeneratorsOfGroup( M ) ); for r in GeneratorsOfGroup( UN ) do - g := PreImagesRepresentative( pair[1], r ); + g := PreImagesRepresentativeNC( pair[1], r ); h := Image( iso, Image( rep, r ) ); - h := PreImagesRepresentative( pair[2], h ); + h := PreImagesRepresentativeNC( pair[2], h ); Add( gens, g * h ); od; S := SubgroupNC( D, gens ); @@ -1091,13 +1091,13 @@ local info,map,U,mapfun,P; U:=SubgroupNC(G,info.hgens); fi; map:=GroupHomomorphismByFunction(P,U,mapfun, - function(elm) - elm:=elm![n]; - if n>info.degI then - elm:=PreImagesRepresentative(info.alpha,elm); - fi; - return elm; - end); + function(elm) + elm:=elm![n]; + if n>info.degI then + elm:=PreImagesRepresentativeNC(info.alpha,elm); + fi; + return elm; + end); info.embeddings[n]:=map; fi; return info.embeddings[n]; @@ -1118,7 +1118,7 @@ local info,map,np; map:=GroupHomomorphismByFunction(G,info.groups[2], function(elm) - return PreImagesRepresentative(info.alpha,elm![np]); + return PreImagesRepresentativeNC(info.alpha,elm![np]); end, false, # not bijective function(elm) @@ -1179,7 +1179,7 @@ local giso,niso,P,gens,a,Go,No,i; N:=Image(niso,N); gens:=[]; for i in GeneratorsOfGroup(G) do - i:=Image(aut,PreImagesRepresentative(giso,i)); + i:=Image(aut,PreImagesRepresentativeNC(giso,i)); i:=InducedAutomorphism(niso,i); Add(gens,i); od; @@ -1220,9 +1220,9 @@ local Go,No,giso,niso,FG,GP,FN,NP,F,GI,NI,rels,i,j,P; N:=Image(niso,N); FG:=FreeGeneratorsOfFpGroup(G); - GP:=List(GeneratorsOfGroup(G),x->PreImagesRepresentative(giso,x)); + GP:=List(GeneratorsOfGroup(G),x->PreImagesRepresentativeNC(giso,x)); FN:=FreeGeneratorsOfFpGroup(N); - NP:=List(GeneratorsOfGroup(N),x->PreImagesRepresentative(niso,x)); + NP:=List(GeneratorsOfGroup(N),x->PreImagesRepresentativeNC(niso,x)); F:=FreeGroup(List(Concatenation(FG,FN),String)); GI:=GeneratorsOfGroup(F){[1..Length(FG)]}; diff --git a/lib/gprdpc.gi b/lib/gprdpc.gi index 6994897c39..a17e46436a 100644 --- a/lib/gprdpc.gi +++ b/lib/gprdpc.gi @@ -421,7 +421,7 @@ local pg,ph,kg,kh,ig,ih,mg,mh,S,info; ig:=InducedPcgs(pg,kg); ih:=InducedPcgs(ph,kh); mg:=pg mod ig; - mh:=List(mg,i->PreImagesRepresentative(hh,Image(gh,i))); + mh:=List(mg,i->PreImagesRepresentativeNC(hh,Image(gh,i))); pg:=Concatenation(mg,ig,List(ih,i->One(G))); ph:=Concatenation(mh,List(ig,i->One(H)),ih); S:=SubdirProdPcGroups(G,pg,H,ph); diff --git a/lib/grp.gi b/lib/grp.gi index dda0a8a033..b826ace85c 100644 --- a/lib/grp.gi +++ b/lib/grp.gi @@ -1793,7 +1793,7 @@ local hom,gens; fi; hom:=IsomorphismPermGroup(G); gens:=IndependentGeneratorsOfAbelianGroup(Image(hom,G)); - return List(gens,i->PreImagesRepresentative(hom,i)); + return List(gens,i->PreImagesRepresentativeNC(hom,i)); end); @@ -2090,8 +2090,8 @@ InstallGlobalFunction( SupersolvableResiduumDefault, function( G ) # dual space of the module, w.r.t. `pcgs'. mg:= List( gs, x -> TransposedMat( List( pcgs, y -> one * ExponentsOfPcElement( pcgs, Image( ph, - Image( dh, PreImagesRepresentative( - dh, PreImagesRepresentative(ph,y) )^x ) ) )))^-1); + Image( dh, PreImagesRepresentativeNC( + dh, PreImagesRepresentativeNC(ph,y) )^x ) ) )))^-1); #T inverting is not necessary, or? mg:= Filtered( mg, x -> x <> idm ); @@ -2141,7 +2141,7 @@ InstallGlobalFunction( SupersolvableResiduumDefault, function( G ) # Construct a group element corresponding to # the basis element of the submodule. - Add( tmp2, PreImagesRepresentative( ph, + Add( tmp2, PreImagesRepresentativeNC( ph, PcElementByExponentsNC( pcgs, v ) ) ); od; diff --git a/lib/grpcompl.gi b/lib/grpcompl.gi index 9adf68a175..187222cb0d 100644 --- a/lib/grpcompl.gi +++ b/lib/grpcompl.gi @@ -99,12 +99,12 @@ local G,N,K,s, h, q, fpi, factorpres, com, comgens, cen, ocrels, fpcgs, ncom, Length(MappingGeneratorsImages(fpi)[2])," generators"); factorpres:=[FreeGeneratorsOfFpGroup(Range(fpi)), RelatorsOfFpGroup(Range(fpi)), - List(GeneratorsOfGroup(Range(fpi)), - i->PreImagesRepresentative(fpi,i))]; - Assert(1,ForAll(factorpres[3],i->Image(h,PreImagesRepresentative(h,i))=i)); + List(GeneratorsOfGroup(Range(fpi)), + i->PreImagesRepresentativeNC(fpi,i))]; + Assert(1,ForAll(factorpres[3],i->Image(h,PreImagesRepresentativeNC(h,i))=i)); # initialize com:=[G]; - comgens:=[List(factorpres[3],i->PreImagesRepresentative(h,i))]; + comgens:=[List(factorpres[3],i->PreImagesRepresentativeNC(h,i))]; cen:=[s[1]]; ocrels:=false; diff --git a/lib/grpfp.gi b/lib/grpfp.gi index 363129a7cc..091a60ee2d 100644 --- a/lib/grpfp.gi +++ b/lib/grpfp.gi @@ -319,7 +319,7 @@ local fam,hom; if hom=fail then TryNextMethod(); fi; - return PreImagesRepresentative(hom,Random(rs, Image(hom,gp))); + return PreImagesRepresentativeNC(hom,Random(rs, Image(hom,gp))); end ); ############################################################################# @@ -5490,10 +5490,10 @@ local G,T,gens,g,reps,ng,index,i,j,ndef,n,iso; IsRightTransversalFpGroupRep and IsList and IsDuplicateFreeList and IsAttributeStoringRep ), rec( group := OG, - subgroup := U, - iso:=iso, - table:=T, - reps:=List(reps,i->PreImagesRepresentative(iso,i)))); + subgroup := U, + iso:=iso, + table:=T, + reps:=List(reps,i->PreImagesRepresentativeNC(iso,i)))); fi; ndef := 1; @@ -5505,16 +5505,16 @@ local G,T,gens,g,reps,ng,index,i,j,ndef,n,iso; #This assumes that reps[j] is already defined - but #this is true because T is 'standardized' ndef := ndef+1; - if ndef=index then - return Objectify( NewType( FamilyObj( OG ), - IsRightTransversalFpGroupRep and IsList and - IsDuplicateFreeList and IsAttributeStoringRep ), - rec( group := OG, - subgroup := U, - iso:=iso, - table:=T, - reps:=List(reps,i->PreImagesRepresentative(iso,i)))); - fi; + if ndef=index then + return Objectify( NewType( FamilyObj( OG ), + IsRightTransversalFpGroupRep and IsList and + IsDuplicateFreeList and IsAttributeStoringRep ), + rec( group := OG, + subgroup := U, + iso:=iso, + table:=T, + reps:=List(reps,i->PreImagesRepresentativeNC(iso,i)))); + fi; fi; od; od; diff --git a/lib/grplatt.gi b/lib/grplatt.gi index 628a925418..58600584d6 100644 --- a/lib/grplatt.gi +++ b/lib/grplatt.gi @@ -955,7 +955,8 @@ InstallGlobalFunction(LatticeViaRadical,function(arg) #k:=PreImage(hom,a); # make generators of homomorphism fit nicely to presentation gf:=IsomorphismFpGroup(a); - e:=List(MappingGeneratorsImages(gf)[1],x->PreImagesRepresentative(hom,x)); + e:=List(MappingGeneratorsImages(gf)[1], + x->PreImagesRepresentativeNC(hom,x)); # we cannot guarantee that the parent contains e, so no # ClosureSubgroup. k:=ClosureGroup(KernelOfMultiplicativeGeneralMapping(hom),e); @@ -2773,7 +2774,7 @@ local fgi,inducedfactorautos,projs,psubs,info,n,l,nl,emb,u,pos, auts:=[]; for i in GeneratorsOfGroup(n) do aut:=GroupHomomorphismByImages(f,f,gens,List(gens,x-> - Image(hom,PreImagesRepresentative(hom,x)^i))); + Image(hom,PreImagesRepresentativeNC(hom,x)^i))); SetIsBijective(aut,true); Add(auts,aut); od; @@ -2825,35 +2826,35 @@ local fgi,inducedfactorautos,projs,psubs,info,n,l,nl,emb,u,pos, no:=NormalSubgroups(j[1]); no:=SubgroupsOrbitsAndNormalizers(j[2],no,false); #Print("Try",j," ",Length(no),"\n"); - for k in no do - hom:=NaturalHomomorphismByNormalSubgroup(j[1],k.representative); - f:=Image(hom); - if Size(f)<1000 and Size(f)<>512 and uselib then - myid:=ShallowCopy(IdGroup(f)); - else - myid:=[Size(f),fail]; - fi; - for s in subs do - for t in s[3] do # look over normals of subgroup + for k in no do + hom:=NaturalHomomorphismByNormalSubgroup(j[1],k.representative); + f:=Image(hom); + if Size(f)<1000 and Size(f)<>512 and uselib then + myid:=ShallowCopy(IdGroup(f)); + else + myid:=[Size(f),fail]; + fi; + for s in subs do + for t in s[3] do # look over normals of subgroup #Print(t,"\n"); - if t{[3,4]}=myid then - if false and myid=[1,1] then - #Print("direct\n"); - g:=Subgroup(D,Concatenation(GeneratorsOfGroup(j[1]),List(GeneratorsOfGroup(s[1]),x->Image(emb,x)))); - Add(nl,[g,Normalizer(D,g)]); - else - iso:=IsomorphismGroups(f,t[6]); - if iso<>fail then - #Found isomorphic factor groups - iso:=hom*iso; - ind:=Subgroup(t[7],inducedfactorautos(k.normalizer,t[6],iso)); - for dc in DoubleCosetRepsAndSizes(t[7],ind,t[8]) do - # form the subdirect product - g:=List(GeneratorsOfGroup(j[1]), - x->x*Image(emb,PreImagesRepresentative(t[5], - Image(dc[1],Image(iso,x))) )); - Append(g,List(GeneratorsOfGroup(t[1]),x->Image(emb,x))); - g:=Subgroup(D,g); + if t{[3,4]}=myid then + if false and myid=[1,1] then + #Print("direct\n"); + g:=Subgroup(D,Concatenation(GeneratorsOfGroup(j[1]),List(GeneratorsOfGroup(s[1]),x->Image(emb,x)))); + Add(nl,[g,Normalizer(D,g)]); + else + iso:=IsomorphismGroups(f,t[6]); + if iso<>fail then + #Found isomorphic factor groups + iso:=hom*iso; + ind:=Subgroup(t[7],inducedfactorautos(k.normalizer,t[6],iso)); + for dc in DoubleCosetRepsAndSizes(t[7],ind,t[8]) do + # form the subdirect product + g:=List(GeneratorsOfGroup(j[1]), + x->x*Image(emb,PreImagesRepresentativeNC(t[5], + Image(dc[1],Image(iso,x))) )); + Append(g,List(GeneratorsOfGroup(t[1]),x->Image(emb,x))); + g:=Subgroup(D,g); if Size(g)<>Size(j[1])*Size(s[1])/Size(f) then Error("sudi\n");fi; Add(nl,[g,Normalizer(D,g)]); od; diff --git a/lib/grpnames.gi b/lib/grpnames.gi index 33d793ac5c..dc207839c0 100644 --- a/lib/grpnames.gi +++ b/lib/grpnames.gi @@ -173,7 +173,7 @@ InstallMethod( NormalComplementNC, i:=0; for gF in IndependentGeneratorsOfAbelianGroup(F) do i := i+1; - g := PreImagesRepresentative(nat, gF); + g := PreImagesRepresentativeNC(nat, gF); R := RightCoset(N, g); # DirectFactorsOfGroup already computed Center and RationalClasses # when calling NormalComplement diff --git a/lib/grpnice.gi b/lib/grpnice.gi index 1e19617b72..b08cd0a3e1 100644 --- a/lib/grpnice.gi +++ b/lib/grpnice.gi @@ -281,8 +281,8 @@ function( obj1, obj2 ) img := ImagesRepresentative( nice, obj2:actioncanfail:=true ); if img = fail or not (img in ImagesSource(nice) and - PreImagesRepresentativeNC(nice,img)=obj2) then - TryNextMethod(); + PreImagesRepresentativeNC(nice,img)=obj2) then + TryNextMethod(); fi; no:=NiceObject(obj1); img1 := ClosureGroup( NiceObject(obj1), img ); diff --git a/lib/grppc.gi b/lib/grppc.gi index f01a7af92d..d81dd970d0 100644 --- a/lib/grppc.gi +++ b/lib/grppc.gi @@ -2147,7 +2147,7 @@ local e, # EAS if iso<>false then V:=PreImage(iso,V); no:=PreImage(iso,no); - ce:=PreImagesRepresentative(iso,ce); + ce:=PreImagesRepresentativeNC(iso,ce); fi; return [V,no,ce]; end ); @@ -2568,7 +2568,7 @@ local q, pcgs, sub, hom, f, ex, C; ex:=ExponentOfPGroupAndElm(f,q); while ex[1]>q do # take the element of highest order in f and take power of its preimage - ex:=PreImagesRepresentative(hom,ex[2]^q); + ex:=PreImagesRepresentativeNC(hom,ex[2]^q); sub:=NormalClosure(G,ClosureSubgroupNC(sub,ex)); hom:=NaturalHomomorphismByNormalSubgroup(G,sub); f:=Range(hom); diff --git a/lib/grppcaut.gi b/lib/grppcaut.gi index 2840694725..6a4e5514ed 100644 --- a/lib/grppcaut.gi +++ b/lib/grppcaut.gi @@ -437,7 +437,7 @@ local spec,s,n,M, if d = 1 then hom := IsomorphismPermGroup( B ); pcgs := Pcgs( Image( hom ) ); - pcs := List( pcgs, x -> PreImagesRepresentative( hom, x ) ); + pcs := List( pcgs, x -> PreImagesRepresentativeNC( hom, x ) ); TransferPcgsInfo( B, pcs, RelativeOrders( pcgs ) ); return B; fi; @@ -509,12 +509,12 @@ local spec,s,n,M, Info( InfoOverGr, 1, "computed normalizer of size ", Size(L)); # go back to mat group - B := List( GeneratorsOfGroup(L), x -> PreImagesRepresentative(hom,x) ); + B := List( GeneratorsOfGroup(L), x -> PreImagesRepresentativeNC(hom,x) ); w := PrimitiveRoot(field)* Immutable( IdentityMat( d, field ) ); B := SubgroupNC( S, Concatenation( B, [w] ) ); if IsSolvableGroup( L ) then - pcgs := List( Pcgs(L), x -> PreImagesRepresentative( hom, x ) ); + pcgs := List( Pcgs(L), x -> PreImagesRepresentativeNC( hom, x ) ); Add( pcgs, w ); rels := ShallowCopy( RelativeOrders( Pcgs(L) ) ); Add( rels, p-1 ); @@ -536,7 +536,7 @@ BindGlobal( "CocycleSQ", function( epi, field ) H := Source( epi ); F := Image( epi ); N := KernelOfMultiplicativeGeneralMapping( epi ); - pcsH := List( Pcgs( F ), x -> PreImagesRepresentative( epi, x ) ); + pcsH := List( Pcgs( F ), x -> PreImagesRepresentativeNC( epi, x ) ); pcsN := Pcgs( N ); pcgsH := PcgsByPcSequence( ElementsFamily( FamilyObj( H ) ), Concatenation( pcsH, pcsN ) ); @@ -646,7 +646,7 @@ BindGlobal( "LiftInduciblePair", function( epi, ind, M, weight ) pcgsF := Pcgs( F ); - pcsH := List( pcgsF, x -> PreImagesRepresentative( epi, x ) ); + pcsH := List( pcgsF, x -> PreImagesRepresentativeNC( epi, x ) ); pcsN := Pcgs( N ); pcgsH := PcgsByPcSequence( ElementsFamily( FamilyObj( H ) ), Concatenation( pcsH, pcsN ) ); @@ -656,7 +656,7 @@ BindGlobal( "LiftInduciblePair", function( epi, ind, M, weight ) # use automorphism of F imgsF := List( pcgsF, x -> Image( ind[1], x ) ); opmats := List( imgsF, x -> MappedPcElement( x, pcgsF, M.generators ) ); - imgsF := List( imgsF, x -> PreImagesRepresentative( epi, x ) ); + imgsF := List( imgsF, x -> PreImagesRepresentativeNC( epi, x ) ); # use automorphism of N imgsN := List( pcsN, x -> ExponentsOfPcElement( pcsN, x ) ); @@ -1418,11 +1418,13 @@ InstallGlobalFunction(AutomorphismGroupSolvableGroup,function( G ) hom := ActionHomomorphism( xset, "surjective"); P := Image( hom ); if IsSolvableGroup( P ) then - pcsA := List( Pcgs(P), x -> PreImagesRepresentative( hom, x )); + pcsA := List( Pcgs(P), + x -> PreImagesRepresentativeNC( hom, x )); TransferPcgsInfo( A, pcsA, RelativeOrders( Pcgs(P) ) ); else imgs := SmallGeneratingSet( P ); - gens := List( imgs, x -> PreImagesRepresentative( hom, x ) ); + gens := List( imgs, + x -> PreImagesRepresentativeNC( hom, x ) ); tmp := Size( A ); A := GroupByGenerators( gens, One( A ) ); SetSize( A, tmp ); @@ -1543,10 +1545,10 @@ InstallGlobalFunction(AutomorphismGroupFrattFreeGroup,function( G ) imgs := []; for i in [1..Length(gensK)] do m := gensU[i]^n; - a := PreImagesRepresentative( hom, m ); + a := PreImagesRepresentativeNC( hom, m ); Add( imgs, a ); od; - l := PreImagesRepresentative( iso, n ); + l := PreImagesRepresentativeNC( iso, n ); Append( imgs, List( gensF, x -> Image( l, x ) ) ); new := GroupHomomorphismByImagesNC( G, G, gensG, imgs ); SetIsBijective( new, true ); diff --git a/lib/grppccom.gi b/lib/grppccom.gi index 2dc5682575..96a746a6cb 100644 --- a/lib/grppccom.gi +++ b/lib/grppccom.gi @@ -19,7 +19,7 @@ local r,img,i,gens,img2; gens:=GeneratorsOfGroup(img); img2:=Image(h[i],G); r[i]:=GroupHomomorphismByImagesNC(img,img2,gens,List(gens,j-> - Image(h[i],PreImagesRepresentative(h[i+1],j)))); + Image(h[i],PreImagesRepresentativeNC(h[i+1],j)))); SetKernelOfMultiplicativeGeneralMapping(r[i], Image(h[i+1],KernelOfMultiplicativeGeneralMapping(h[i]))); img:=img2; diff --git a/lib/grppcext.gi b/lib/grppcext.gi index f88bffcfcf..b5a7d47b78 100644 --- a/lib/grppcext.gi +++ b/lib/grppcext.gi @@ -378,11 +378,11 @@ local ag, p1iso, agp, p2iso, DP, p1, p2, gens, genimgs, triso,s,i,u,opt, genimgs:=List(gens, i->ImagesRepresentative(Embedding(D,1), - PreImagesRepresentative(p1iso, - PreImagesRepresentative(pc1,ImagesRepresentative(p1,i)))) + PreImagesRepresentativeNC(p1iso, + PreImagesRepresentativeNC(pc1,ImagesRepresentative(p1,i)))) *ImagesRepresentative(Embedding(D,2), - PreImagesRepresentative(p2iso, - PreImagesRepresentative(pc2,ImagesRepresentative(p2,i)))) ); + PreImagesRepresentativeNC(p2iso, + PreImagesRepresentativeNC(pc2,ImagesRepresentative(p2,i)))) ); else opt:=rec(limit:=s,random:=1); @@ -426,9 +426,9 @@ local ag, p1iso, agp, p2iso, DP, p1, p2, gens, genimgs, triso,s,i,u,opt, genimgs:=List(gens, i->ImagesRepresentative(Embedding(D,1), - PreImagesRepresentative(p1iso,ImagesRepresentative(p1,i))) + PreImagesRepresentativeNC(p1iso,ImagesRepresentative(p1,i))) *ImagesRepresentative(Embedding(D,2), - PreImagesRepresentative(p2iso,ImagesRepresentative(p2,i))) ); + PreImagesRepresentativeNC(p2iso,ImagesRepresentative(p2,i))) ); fi; triso:=GroupHomomorphismByImagesNC(DP,D,gens,genimgs); @@ -531,7 +531,7 @@ local G, M, Mgrp, oper, A, B, D, translate, gens, genimgs, triso, K, K1, gens,M.generators); test:=function(perm) local aut,imgs,mat; - aut:=PreImagesRepresentative(triso,perm); + aut:=PreImagesRepresentativeNC(triso,perm); imgs:=List(gens,x->ImagesRepresentative(aut,x)); imgs:=List(imgs,x->ImagesRepresentative(modulehom,x)); mat:=MTX.IsomorphismModules(M,GModuleByMats(imgs,M.field)); @@ -697,9 +697,9 @@ local G, M, Mgrp, oper, A, B, D, translate, gens, genimgs, triso, K, K1, basicact:=function( tup, elm ) local gens; - #gens := List( tup[1], x -> PreImagesRepresentative( elm[1], x ) ); + #gens := List( tup[1], x -> PreImagesRepresentativeNC( elm[1], x ) ); #gens := List( gens, x -> MappedPcElement( x, tup[1], tup[2] ) ); - gens := List( Ggens, x -> PreImagesRepresentative( elm[1], x ) ); + gens := List( Ggens, x -> PreImagesRepresentativeNC( elm[1], x ) ); gens := List( gens, x -> MappedPcElement( x, Ggens, tup ) ); gens := List( gens, x -> x ^ elm[2] ); return gens; @@ -712,10 +712,10 @@ local G, M, Mgrp, oper, A, B, D, translate, gens, genimgs, triso, K, K1, Assert(1,MappingGeneratorsImages(epi)[2]=Ggens); f:=function( tup, elm ) local gens; - #gens := List( tup[1], x -> PreImagesRepresentative( elm[1], x ) ); + #gens := List( tup[1], x -> PreImagesRepresentativeNC( elm[1], x ) ); #gens := List( gens, x -> MappedPcElement( x, tup[1], tup[2] ) ); - gens := List( Ggens, x -> PreImagesRepresentative( elm[1], x ) ); - gens := List( gens, x -> MappedWord( PreImagesRepresentative(epi,x), + gens := List( Ggens, x -> PreImagesRepresentativeNC( elm[1], x ) ); + gens := List( gens, x -> MappedWord( PreImagesRepresentativeNC(epi,x), GeneratorsOfGroup(Source(epi)), tup ) ); gens := List( gens, x -> x ^ elm[2] ); return gens; @@ -731,13 +731,13 @@ local G, M, Mgrp, oper, A, B, D, translate, gens, genimgs, triso, K, K1, elmlist:=[]; tmp:=List(genimgs,x->x[1]); - preimlist:=List(tmp,x->[x,List(Ggens,y->PreImagesRepresentative(x,y))]); + preimlist:=List(tmp,x->[x,List(Ggens,y->PreImagesRepresentativeNC(x,y))]); f:=function( tup, elm ) local gens,p; p:=PositionProperty(preimlist,x->IsIdenticalObj(x[1],elm[1])); if p=fail then - gens := List( Ggens, x -> PreImagesRepresentative( elm[1], x ) ); + gens := List( Ggens, x -> PreImagesRepresentativeNC( elm[1], x ) ); else gens:=preimlist[p][2]; fi; @@ -782,7 +782,7 @@ local G, M, Mgrp, oper, A, B, D, translate, gens, genimgs, triso, K, K1, if elmlist<>fail then tmp:=List(genimgs,x->x[1]); - preimlist:=List(tmp,x->[x,List(Ggens,y->PreImagesRepresentative(x,y))]); + preimlist:=List(tmp,x->[x,List(Ggens,y->PreImagesRepresentativeNC(x,y))]); # ensure we also account for action u:=Group(tup); @@ -912,7 +912,7 @@ BindGlobal( "MatrixOperationOfCPGroup", function( cc, gens ) mats := List( gens, x -> [] ); base := Basis( Image( cc.cohom ) ); - prei := List( base, x -> PreImagesRepresentative( cc.cohom, x ) ); + prei := List( base, x -> PreImagesRepresentativeNC( cc.cohom, x ) ); pcgs := Pcgs( cc.group ); ords := RelativeOrders( pcgs ); @@ -1009,7 +1009,7 @@ function( G, M, C ) return [ExtensionSQ( cc.collector, G, M, 0 )]; elif Dimension( Image(cc.cohom)) = 1 then c := Basis(Image(cc.cohom))[1]; - c := PreImagesRepresentative(cc.cohom, c); + c := PreImagesRepresentativeNC(cc.cohom, c); return [ExtensionSQ( cc.collector, G, M, 0 ), ExtensionSQ( cc.collector, G, M, c )]; fi; @@ -1019,7 +1019,7 @@ function( G, M, C ) # compute orbit of mats on H^2( G, M ) Mgrp := GroupByGenerators( mats ); orbs := OrbitsDomain( Mgrp, Image(cc.cohom), OnRight ); - orbs := List( orbs, x -> PreImagesRepresentative( cc.cohom, x[1] ) ); + orbs := List( orbs, x -> PreImagesRepresentativeNC( cc.cohom, x[1] ) ); ext := List( orbs, x -> ExtensionSQ( cc.collector, G, M, x ) ); return ext; end); @@ -1114,15 +1114,15 @@ BindGlobal( "NonSplitExtensions", function( arg ) red := true; elif Dimension( Image(cc.cohom ) ) = 1 then - c := PreImagesRepresentative(cc.cohom, Basis(Image(cc.cohom))[1]); + c := PreImagesRepresentativeNC(cc.cohom, Basis(Image(cc.cohom))[1]); all := [ExtensionSQ( C, G, M, c)]; red := true; # if reduction is suppressed elif IsBound( arg[3] ) and not arg[3] then all := NormedRowVectors( Image(cc.cohom) ); - all := List( all, x -> ExtensionSQ(cohom.collector, G, M, - PreImagesRepresentative(cc.cohom,x ))); + all := List( all, x -> ExtensionSQ(cohom.collector, G, M, + PreImagesRepresentativeNC(cc.cohom,x ))); red := false; # sometimes we do not want to reduce @@ -1132,8 +1132,8 @@ BindGlobal( "NonSplitExtensions", function( arg ) and not HasAutomorphismGroup( G ) then all := NormedRowVectors( Image(cc.cohom) ); - all := List( all, x -> ExtensionSQ(cc.collector, G, M, - PreImagesRepresentative(cc.cohom, x ))); + all := List( all, x -> ExtensionSQ(cc.collector, G, M, + PreImagesRepresentativeNC(cc.cohom, x ))); red := false; # then we want to reduce @@ -1151,8 +1151,8 @@ BindGlobal( "NonSplitExtensions", function( arg ) Info( InfoExtReps, 2, " Ext: found ",Length(all)," orbits "); # create extensions and add info - all := List( all, x -> ExtensionSQ(cc.collector, G, M, - PreImagesRepresentative(cc.cohom, x ))); + all := List( all, x -> ExtensionSQ(cc.collector, G, M, + PreImagesRepresentativeNC(cc.cohom, x ))); fi; if red then diff --git a/lib/grppclat.gi b/lib/grppclat.gi index 4b8113783e..336b5fcef5 100644 --- a/lib/grppclat.gi +++ b/lib/grppclat.gi @@ -85,8 +85,8 @@ local f; Image( epi, ConjugatorOfConjugatorIsomorphism( aut ) ) ); else aut:= GroupHomomorphismByImagesNC(f,f,GeneratorsOfGroup(f), - List(GeneratorsOfGroup(f), - i->Image(epi,Image(aut,PreImagesRepresentative(epi,i))))); + List(GeneratorsOfGroup(f), + i->Image(epi,Image(aut,PreImagesRepresentativeNC(epi,i))))); SetIsInjective(aut,true); SetIsSurjective(aut,true); fi; @@ -672,7 +672,7 @@ local g, # group # hom:=[]; # for i in func do # hom2:=GroupHomomorphismByImagesNC(g,g,g.generators,List(g.generators, -# j->Image(isom,Image(i,PreImagesRepresentative(isom,j))))); +# j->Image(isom,Image(i,PreImagesRepresentative(isom,j))))); # hom2.isMapping:=true; # Add(hom,hom2); # od; @@ -788,7 +788,7 @@ local g, # group hom:= GroupHomomorphismByImagesNC(f,fa,GeneratorsOfGroup(f), List(GeneratorsOfGroup(f),i-> - Image(hom,PreImagesRepresentative(epi,i)))); + Image(hom,PreImagesRepresentativeNC(epi,i)))); Assert(2,KernelOfMultiplicativeGeneralMapping(hom)=n); # lift the known groups diff --git a/lib/grpprmcs.gi b/lib/grpprmcs.gi index c8a8a1166a..4b4d6d91a6 100644 --- a/lib/grpprmcs.gi +++ b/lib/grpprmcs.gi @@ -1173,7 +1173,7 @@ InstallGlobalFunction( PullbackKernelCSPG, fi; for g in gens do for j in [1..i-1] do - g := PreImagesRepresentative(homlist[i-j],g); + g := PreImagesRepresentativeNC(homlist[i-j],g); od; Add(normals[index],g); Add(factors[index],()); @@ -1193,7 +1193,7 @@ InstallGlobalFunction( PullbackCSPG, function(p,homlist) # compute a preimage of the permutation p in the input group lenhomlist := Length(homlist); for i in [1..lenhomlist] do - p := PreImagesRepresentative(homlist[lenhomlist+1-i],p); + p := PreImagesRepresentativeNC(homlist[lenhomlist+1-i],p); od; return p; end ); @@ -1522,7 +1522,7 @@ InstallMethod( PCoreOp, for g in GeneratorsOfGroup( KernelOfMultiplicativeGeneralMapping( homlist[i] ) ) do for j in [1..i-1] do - g := PreImagesRepresentative(homlist[i-j],g); + g := PreImagesRepresentativeNC(homlist[i-j],g); od; Add(pgenlist,g); od; @@ -1747,7 +1747,7 @@ InstallMethod( SolvableRadical, for g in GeneratorsOfGroup( KernelOfMultiplicativeGeneralMapping( homlist[i] ) ) do for j in [1..i-1] do - g := PreImagesRepresentative(homlist[i-j],g); + g := PreImagesRepresentativeNC(homlist[i-j],g); od; Add(solvable,g); od; From 85c9030e3b60504f4225b3b6f7d7be753cd57b8b Mon Sep 17 00:00:00 2001 From: Chris Wensley Date: Thu, 29 Sep 2022 15:24:13 +0100 Subject: [PATCH 003/234] renamed PreImRep as PreImRepNC in files m... to t... --- lib/mapphomo.gi | 16 ++++----- lib/maxsub.gi | 20 +++++------ lib/morpheus.gi | 52 ++++++++++++++-------------- lib/norad.gi | 92 ++++++++++++++++++++++++------------------------- lib/onecohom.gi | 11 +++--- lib/oprt.gi | 2 +- lib/oprtperm.gi | 2 +- lib/pcgsnice.gi | 2 +- lib/permdeco.gi | 10 +++--- lib/schur.gi | 52 ++++++++++++++-------------- lib/semirel.gi | 2 +- lib/stbcbckt.gi | 2 +- lib/twocohom.gi | 18 +++++----- 13 files changed, 141 insertions(+), 140 deletions(-) diff --git a/lib/mapphomo.gi b/lib/mapphomo.gi index 3e396945ff..423d0769aa 100644 --- a/lib/mapphomo.gi +++ b/lib/mapphomo.gi @@ -340,7 +340,7 @@ InstallMethod( PreImagesElm, function( map, elm ) local pre; - pre:= PreImagesRepresentative( map, elm ); + pre:= PreImagesRepresentativeNC( map, elm ); if pre = fail then return []; else @@ -367,7 +367,7 @@ InstallMethod( PreImagesSet, fi; genpreimages:= List(genpreimages, - gen -> PreImagesRepresentative( map, gen ) ); + gen -> PreImagesRepresentativeNC( map, gen ) ); if fail in genpreimages then TryNextMethod(); fi; @@ -395,7 +395,7 @@ InstallMethod( PreImagesSet, pre := SubgroupNC( Source( map ), List( GeneratorsOfMagmaWithInverses( elms ), - gen -> PreImagesRepresentative( map, gen ) ) ); + gen -> PreImagesRepresentativeNC( map, gen ) ) ); UseIsomorphismRelation( elms, pre ); return pre; end ); @@ -694,7 +694,7 @@ InstallMethod( PreImagesElm, function( map, elm ) local pre; - pre:= PreImagesRepresentative( map, elm ); + pre:= PreImagesRepresentativeNC( map, elm ); if pre = fail then return []; else @@ -715,7 +715,7 @@ InstallMethod( PreImagesSet, function( map, elms ) local genpreimages; genpreimages:= List( GeneratorsOfAdditiveGroup( elms ), - gen -> PreImagesRepresentative( map, gen ) ); + gen -> PreImagesRepresentativeNC( map, gen ) ); if fail in genpreimages then TryNextMethod(); fi; @@ -901,7 +901,7 @@ InstallMethod( PreImagesSet, function( map, elms ) local genpreimages; genpreimages:= List( GeneratorsOfLeftModule( elms ), - gen -> PreImagesRepresentative( map, gen ) ); + gen -> PreImagesRepresentativeNC( map, gen ) ); if fail in genpreimages then TryNextMethod(); fi; @@ -995,7 +995,7 @@ InstallMethod( PreImagesSet, function( map, elms ) local genpreimages; genpreimages:= List( GeneratorsOfLeftOperatorRing( elms ), - gen -> PreImagesRepresentative( map, gen ) ); + gen -> PreImagesRepresentativeNC( map, gen ) ); if fail in genpreimages then TryNextMethod(); fi; @@ -1022,7 +1022,7 @@ InstallMethod( PreImagesSet, function( map, elms ) local genpreimages; genpreimages:= List( GeneratorsOfLeftOperatorRingWithOne( elms ), - gen -> PreImagesRepresentative( map, gen ) ); + gen -> PreImagesRepresentativeNC( map, gen ) ); if fail in genpreimages then TryNextMethod(); fi; diff --git a/lib/maxsub.gi b/lib/maxsub.gi index e04c94eaa5..d8e7616425 100644 --- a/lib/maxsub.gi +++ b/lib/maxsub.gi @@ -195,8 +195,8 @@ BindGlobal("MaximalSubgroupClassesSol",function(G) fam:=FamilyObj(One(Range(fphom))); # just in case the stored group generators differ... wordfpgens:=List(wordgens,x->ElementOfFpGroup(fam,x)); - wordpre:=List(wordfpgens,x->PreImagesRepresentative(ff.factorhom, - PreImagesRepresentative(fphom,x))); + wordpre:=List(wordfpgens,x->PreImagesRepresentativeNC(ff.factorhom, + PreImagesRepresentativeNC(fphom,x))); fphom:=ff.factorhom*fphom; # no assertion as this is not a proper homomorphism, but an inverse # multiplicative map @@ -513,7 +513,7 @@ local hom,embs,s,k,agens,ad,i,j,perm,dia,ggens,e,tgens,d,m,reco,emba,outs,id; m:=[]; d:=SubgroupNC(w,d); for i in e do - j:=PreImagesRepresentative(hom,i^-1); + j:=PreImagesRepresentativeNC(hom,i^-1); Info(InfoLattice,2,"Orders:",Order(i),",",Order(j)); j:=d^j; if donorm then @@ -633,9 +633,9 @@ local dom, o, t1, a1, t1d, proj, reps, ts, ta, tb, s1, i, fix, wnew, max, s, p1, # get the ts corresponding to points proj:=Projection(w); projG:=RestrictedMapping(proj,G); - reps:=List([1..n],i->PreImagesRepresentative(projG,RepresentativeAction(Image(projG),1,i))); + reps:=List([1..n],i->PreImagesRepresentativeNC(projG,RepresentativeAction(Image(projG),1,i))); reps[n+1]:= - PreImagesRepresentative(proj,RepresentativeAction(Image(proj),[1..n],[n+1..2*n],OnSets)); + PreImagesRepresentativeNC(proj,RepresentativeAction(Image(proj),[1..n],[n+1..2*n],OnSets)); for i in [2..n] do j:=reps[i]*reps[n+1]; reps[1^Image(proj,j)]:=j; @@ -665,8 +665,8 @@ local dom, o, t1, a1, t1d, proj, reps, ts, ta, tb, s1, i, fix, wnew, max, s, p1, en1:=Embedding(wnew,1); en2:=Embedding(wnew,2); emb:=List(GeneratorsOfGroup(s),i-> - Image(en1,PreImagesRepresentative(p1,RestrictedPerm(i,ts[1]))) - *Image(en2,PreImagesRepresentative(p2,RestrictedPerm(i,ts[f]))) ); + Image(en1,PreImagesRepresentativeNC(p1,RestrictedPerm(i,ts[1]))) + *Image(en2,PreImagesRepresentativeNC(p2,RestrictedPerm(i,ts[f]))) ); emb:=GroupHomomorphismByImages(s,wnew,GeneratorsOfGroup(s),emb); ma:=MaxesType3(wnew,Image(emb,s),a1,t1,2,false); for i in ma do @@ -699,7 +699,7 @@ local m, fact, fg, reps, ma, idx, nm, embs, proj, kproj, k, ag, agl, ug, # type 4c reps:=List([1..n], - i->PreImagesRepresentative(fact,RepresentativeAction(fg,1,i))); + i->PreImagesRepresentativeNC(fact,RepresentativeAction(fg,1,i))); # get the maximal subgroups of A, intersect with t to get the socle part @@ -758,8 +758,8 @@ local m, fact, fg, reps, ma, idx, nm, embs, proj, kproj, k, ag, agl, ug, #phi:=ActionHomomorphism(fg,u.orbit,OnSets); #ue:=Image(phi,fg); #reps:=List([1..nlb],i->RepresentativeAction(ue,1,i)); - #reps:=List(reps,i->PreImagesRepresentative(phi,i)); - #reps:=List(reps,i->PreImagesRepresentative(fact,i)); + #reps:=List(reps,i->PreImagesRepresentativeNC(phi,i)); + #reps:=List(reps,i->PreImagesRepresentativeNC(fact,i)); #u:=u.stabilizer; uphi:=ActionHomomorphism(Image(fact,u),b); diff --git a/lib/morpheus.gi b/lib/morpheus.gi index 75d7156d9c..1d80e1a3c4 100644 --- a/lib/morpheus.gi +++ b/lib/morpheus.gi @@ -745,10 +745,10 @@ local hom, gens, c, ran, r, cen, img, u, orbs, function(perm) if perm in store[1] then return ConjugatorAutomorphismNC(g, - PreImagesRepresentative(img[2],perm)); + PreImagesRepresentativeNC(img[2],perm)); fi; return GroupHomomorphismByImagesNC(g,g,GeneratorsOfGroup(g), - List(store[2],i->PreImagesRepresentative(img[2],i^perm))); + List(store[2],i->PreImagesRepresentativeNC(img[2],i^perm))); end); if bestdegPreImagesRepresentative(store[3],i^perm))); + List(store[4],i->PreImagesRepresentativeNC(store[3],i^perm))); end); if bestdegPreImagesRepresentative(gens,i)); + i->PreImagesRepresentativeNC(gens,i)); Ggc:=List(gens,i->First(Gcl,j->ForAny(j,j->ForAny(j.classes,k->i in k)))); combi:=List(Ggc,i->Concatenation(List(i,i->i.classes))); bcl:=ShallowCopy(combi); @@ -2102,8 +2102,8 @@ local d,id,H,iso,aut,auts,i,all,hom,field,dim,P,diag,mats,gens,gal; iso:=IsomorphismGroups(G,H); fi; aut:=GroupGeneralMappingByImages(G,G,gens, - List(gens, - x->PreImagesRepresentative(iso,Image(iso,x)^(1,2)))); + List(gens, + x->PreImagesRepresentativeNC(iso,Image(iso,x)^(1,2)))); auts:=[aut]; all:=true; fi; @@ -2163,9 +2163,9 @@ local d,id,H,iso,aut,auts,i,all,hom,field,dim,P,diag,mats,gens,gal; od; fi; auts:=Concatenation(auts, - List(mats,s->GroupGeneralMappingByImages(G,G,gens,List(gens,x-> - Image(hom,PreImagesRepresentative(hom,x)^s))))); - + List(mats,s->GroupGeneralMappingByImages(G,G,gens,List(gens,x-> + Image(hom,PreImagesRepresentativeNC(hom,x)^s))))); + else gal:=Group(()); # to force trivial fi; @@ -2173,16 +2173,16 @@ local d,id,H,iso,aut,auts,i,all,hom,field,dim,P,diag,mats,gens,gal; if Size(gal)>1 then # Galois auts:=Concatenation(auts, - List(MinimalGeneratingSet(gal), - s->GroupGeneralMappingByImages(G,G,gens,List(gens,x-> - Image(hom, - List(PreImagesRepresentative(hom,x),r->List(r,y->Image(s,y)))))))); + List(MinimalGeneratingSet(gal), + s->GroupGeneralMappingByImages(G,G,gens,List(gens,x-> + Image(hom, + List(PreImagesRepresentativeNC(hom,x),r->List(r,y->Image(s,y)))))))); fi; # graph if id.series="L" and id.parameter[1]>2 then Add(auts, GroupGeneralMappingByImages(G,G,gens,List(gens,x-> - Image(hom,Inverse(TransposedMat(PreImagesRepresentative(hom,x))))))); +Image(hom,Inverse(TransposedMat(PreImagesRepresentativeNC(hom,x))))))); all:=true; elif id.series="L" and id.parameter[1]=2 then # note no graph @@ -2344,12 +2344,12 @@ InstallGlobalFunction(AutomorphismGroupFittingFree,function(g) a:=acts[i[j][1]][3]; genimgs:=[]; for gen in GeneratorsOfGroup(a) do - thom:=i[j][2]; - thom:=GroupHomomorphismByImagesNC(t,t,GeneratorsOfGroup(t), - List(GeneratorsOfGroup(t), - j->Image(thom,PreImagesRepresentative(thom,j)^gen))); - thom:=Image(auph,thom); - Add(genimgs,thom); + thom:=i[j][2]; + thom:=GroupHomomorphismByImagesNC(t,t,GeneratorsOfGroup(t), + List(GeneratorsOfGroup(t), + j->Image(thom,PreImagesRepresentativeNC(thom,j)^gen))); + thom:=Image(auph,thom); + Add(genimgs,thom); od; ahom:=GroupHomomorphismByImagesNC(a,aup,GeneratorsOfGroup(a),genimgs); @@ -2404,8 +2404,8 @@ InstallGlobalFunction(AutomorphismGroupFittingFree,function(g) gens:=SmallGeneratingSet(aup); for i in gens do au:=GroupHomomorphismByImages(g,g,GeneratorsOfGroup(g), - List(GeneratorsOfGroup(g), - j->PreImagesRepresentative(emb,Image(emb,j)^i))); + List(GeneratorsOfGroup(g), + j->PreImagesRepresentativeNC(emb,Image(emb,j)^i))); Add(a,au); od; au:=Group(a); @@ -2446,7 +2446,7 @@ InstallGlobalFunction(AutomorphismGroupFittingFree,function(g) bi:=[]; for i in newbas do s:=List(stbs[i], - x->Image(emb,Image(autom,PreImagesRepresentative(emb,x)))); + x->Image(emb,Image(autom,PreImagesRepresentativeNC(emb,x)))); s:=First(orb[orpo[i]],x->ForAll(s,j->x^j=x)); Add(bi,s); od; diff --git a/lib/norad.gi b/lib/norad.gi index 7457f035e8..7f44100ea1 100644 --- a/lib/norad.gi +++ b/lib/norad.gi @@ -143,46 +143,46 @@ local d,orb,len,S,depths,rel,stb,img,pos,i,j,k,ii,po,rep,sg,sf,sfs,fr,first, for k in [i+1..i+po-1] do img:=act(orb[k],acts[j]); #F if LookupDictionary(d,img)<>fail then Error("err3");fi; - Add(orb,img); - AddDictionary(d,img,Length(orb)); - od; - - # should we give in? - if Length(orb)>brutelimit then - - orb:=[];d:=1; #clean memory - - # projective action is fine, as we want to fix space - Info(InfoFitFree,1,"act on whole space, fix in perm action"); - permact:=Action(GroupWithGenerators(Concatenation(acts,pcgsacts)), - induce.allobj,induce.allact); - i:=Concatenation( - List([1..Length(gens)], x->DirectProductElement([gens[x],imgs[x]])), - List(pcgs, x->DirectProductElement([x,One(imgs[1])]))); - pacthom:=GroupHomomorphismByImagesNC(GroupWithGenerators(i),permact,i, - GeneratorsOfGroup(permact)); - - lpos:=List(induce.lvecs,x->Position(induce.allobj,x)); - - # we don't care about the actual subgroup, just the inducing elements - good:=[]; - SubgroupProperty(induce.subact, - function(x) - local r; - r:=RepresentativeAction(permact,lpos,Permuted(lpos,x),OnTuples); - if r<>fail then Add(good,r);fi; - return r<>fail; - end); - good:=List(good,x->PreImagesRepresentative(pacthom,x)); - - good:=Filtered(good,x->not IsOne(x[2])); - - return rec(byinduced:=true, - gens:=List(good,x->x[1]),imgs:=List(good,x->x[2]), - pcgs:=Reversed(S)); - - fi; - + Add(orb,img); + AddDictionary(d,img,Length(orb)); + od; + + # should we give in? + if Length(orb)>brutelimit then + + orb:=[];d:=1; #clean memory + + # projective action is fine, as we want to fix space + Info(InfoFitFree,1,"act on whole space, fix in perm action"); + permact:=Action(GroupWithGenerators(Concatenation(acts,pcgsacts)), + induce.allobj,induce.allact); + i:=Concatenation( + List([1..Length(gens)], x->DirectProductElement([gens[x],imgs[x]])), + List(pcgs, x->DirectProductElement([x,One(imgs[1])]))); + pacthom:=GroupHomomorphismByImagesNC(GroupWithGenerators(i),permact,i, + GeneratorsOfGroup(permact)); + + lpos:=List(induce.lvecs,x->Position(induce.allobj,x)); + + # we don't care about the actual subgroup, just the inducing elements + good:=[]; + goodi:=SubgroupProperty(induce.subact, + function(x) + local r; + r:=RepresentativeAction(permact,lpos,Permuted(lpos,x),OnTuples); + if r<>fail then Add(good,r);fi; + return r<>fail; + end); + good:=List(good,x->PreImagesRepresentativeNC(pacthom,x)); + + good:=Filtered(good,x->not IsOne(x[2])); + + return rec(byinduced:=true, + gens:=List(good,x->x[1]),imgs:=List(good,x->x[2]), + pcgs:=Reversed(S)); + + fi; + else # get stabilizing element blp:=QuoInt((pos-1),po)+1; # which block position are we? @@ -416,10 +416,10 @@ local sus,ser,len,factorhom,uf,n,d,up,mran,nran,mpcgs,pcgs,pcisom,nf,ng,np,sub, glhom:=IsomorphismPermGroup(localgl); glperm:=Image(glhom); glact:=ActionHomomorphism(glperm,lvecs, - GeneratorsOfGroup(glperm), - List(GeneratorsOfGroup(glperm), - x->PreImagesRepresentative(glhom,x)), - OnLines,"surjective"); + GeneratorsOfGroup(glperm), + List(GeneratorsOfGroup(glperm), + x->PreImagesRepresentativeNC(glhom,x)), + OnLines,"surjective"); stb:=Image(glact); for clu in localclust do stb:=Stabilizer(stb,clu,OnSets); @@ -478,7 +478,7 @@ local sus,ser,len,factorhom,uf,n,d,up,mran,nran,mpcgs,pcgs,pcisom,nf,ng,np,sub, Info(InfoFitFree,1,"Radsize= ",Size(ufr)," index ",Index(uf,ufr)); uff:=SmallGeneratingSet(uf); - ufg:=List(uff,x->PreImagesRepresentative(sus.rest,x)); + ufg:=List(uff,x->PreImagesRepresentativeNC(sus.rest,x)); n:=Normalizer(Image(factorhom),uf); @@ -503,7 +503,7 @@ local sus,ser,len,factorhom,uf,n,d,up,mran,nran,mpcgs,pcgs,pcisom,nf,ng,np,sub, nf:=SmallGeneratingSet(n); fi; - ng:=List(nf,x->PreImagesRepresentative(factorhom,x)); + ng:=List(nf,x->PreImagesRepresentativeNC(factorhom,x)); np:=pcgs; up:=sus.pcgs; diff --git a/lib/onecohom.gi b/lib/onecohom.gi index c2b6d29723..a581680fec 100644 --- a/lib/onecohom.gi +++ b/lib/onecohom.gi @@ -128,7 +128,7 @@ local hom,fg,fpi,fpg,nt,fam; fpg:=FreeGeneratorsOfFpGroup(Range(hom)); ocr.factorpres:=[fpg,RelatorsOfFpGroup(Range(hom))]; ocr.generators:=List(GeneratorsOfGroup(Range(hom)), - i->PreImagesRepresentative(hom,i)); + i->PreImagesRepresentativeNC(hom,i)); else if (Index(ocr.group,nt)>Size(nt)^3 @@ -158,10 +158,11 @@ local hom,fg,fpi,fpg,nt,fam; fi; fpg:=FreeGeneratorsOfFpGroup(Range(fpi)); ocr.factorpres:=[fpg,RelatorsOfFpGroup(Range(fpi)), - List(GeneratorsOfGroup(Range(fpi)), - i->PreImagesRepresentative(fpi,i))]; + List(GeneratorsOfGroup(Range(fpi)), + i->PreImagesRepresentativeNC(fpi,i))]; if not IsBound(ocr.generators) then - ocr.generators:=List(ocr.factorpres[3],i->PreImagesRepresentative(hom,i)); + ocr.generators:=List(ocr.factorpres[3], + i->PreImagesRepresentativeNC(hom,i)); fi; @@ -191,7 +192,7 @@ local hom,fg,fpi,fpg,nt,fam; fpi:=IsomorphismFpGroupByChiefSeriesFactor(ocr.group,"f",nt); fam:=FamilyObj(One(Range(fpi))); fpg:=FreeGeneratorsOfFpGroup(Range(fpi)); - ocr.generators:=List(fpg,i->PreImagesRepresentative(fpi, + ocr.generators:=List(fpg,i->PreImagesRepresentativeNC(fpi, ElementOfFpGroup(fam,i))); ocr.factorpres:=[fpg,RelatorsOfFpGroup(Range(fpi)),ocr.generators]; fi; diff --git a/lib/oprt.gi b/lib/oprt.gi index 7440dbcbd2..f79b2c3152 100644 --- a/lib/oprt.gi +++ b/lib/oprt.gi @@ -2921,7 +2921,7 @@ local G, D, d, e, gens, acts, act, xset, hom, p, rep; rep := RepresentativeActionOp( ImagesSource( hom ), d, e, OnPoints ); if rep <> fail then - rep := PreImagesRepresentativeNC( hom, rep ); + rep := PreImagesRepresentativeNC( hom, rep ); fi; return rep; elif IsBound( D ) then diff --git a/lib/oprtperm.gi b/lib/oprtperm.gi index dd21ee7aaf..71a970deba 100644 --- a/lib/oprtperm.gi +++ b/lib/oprtperm.gi @@ -964,7 +964,7 @@ InstallMethod( Earns, "G, ints, gens, perms, act", true, fi; gens := [ ]; for gen in GeneratorsOfGroup( Centre( P ) ) do - pre := PreImagesRepresentative( f, gen ); + pre := PreImagesRepresentativeNC( f, gen ); ord := Order( pre ); pa := 1; while ord mod p = 0 do ord := ord / p; diff --git a/lib/pcgsnice.gi b/lib/pcgsnice.gi index 0496a0c212..caa90d90ec 100644 --- a/lib/pcgsnice.gi +++ b/lib/pcgsnice.gi @@ -23,7 +23,7 @@ AttributeMethodByNiceMonomorphism( Pcgs, if npcgs = fail then return fail; fi; - pcgs := List( npcgs, gen -> PreImagesRepresentative( nice, gen ) ); + pcgs := List( npcgs, gen -> PreImagesRepresentativeNC( nice, gen ) ); pcgs := PcgsByPcSequenceNC( ElementsFamily( FamilyObj( G ) ), pcgs ); if HasIsPrimeOrdersPcgs( npcgs ) and IsPrimeOrdersPcgs( npcgs ) then SetIsPrimeOrdersPcgs( pcgs, true ); diff --git a/lib/permdeco.gi b/lib/permdeco.gi index f57059f634..e605798c0f 100644 --- a/lib/permdeco.gi +++ b/lib/permdeco.gi @@ -314,7 +314,7 @@ local tryrep,sel,selin,a,s,dom,iso,stabs,outs,map,i,j,p,found,seln, for i in GeneratorsOfGroup(G) do a:=One(d); for j in [1..Length(stabs)] do - a:=a*Image(Embedding(d,j),PreImagesRepresentative(outs[j],i)); + a:=a*Image(Embedding(d,j),PreImagesRepresentativeNC(outs[j],i)); od; Add(p,a); od; @@ -360,7 +360,7 @@ local G,H,tg,th,hom, tga, Gemb, C, outs, auts, ar, Hemb; i->GroupHomomorphismByImagesNC(tg,tg, GeneratorsOfGroup(tg), List(GeneratorsOfGroup(tg), - j->Image(hom,PreImagesRepresentative(hom,j)^i)))); + j->Image(hom,PreImagesRepresentativeNC(hom,j)^i)))); Gemb:=fail; if ForAll(tga,IsConjugatorAutomorphism) then @@ -442,7 +442,7 @@ local cs,i,k,u,o,norm,T,Thom,autos,ng,a,Qhom,Q,Ehom,genimages, autos:=List(ng,i->GroupHomomorphismByImagesNC(T,T, GeneratorsOfGroup(T), List(GeneratorsOfGroup(T), - j->Image(Thom,PreImagesRepresentative(Thom,j)^i)))); + j->Image(Thom,PreImagesRepresentativeNC(Thom,j)^i)))); a:=AutomorphismRepresentingGroup(T,autos); Thom:=GroupHomomorphismByImagesNC(norm,a[1],ng,a[3]); a:=a[1]; @@ -455,7 +455,7 @@ local cs,i,k,u,o,norm,T,Thom,autos,ng,a,Qhom,Q,Ehom,genimages, # define isomorphisms between the components reps:=List([1..n],i-> - PreImagesRepresentative(Qhom,RepresentativeAction(Q,1,i))); + PreImagesRepresentativeNC(Qhom,RepresentativeAction(Q,1,i))); genimages:=[]; for i in GeneratorsOfGroup(G) do @@ -539,7 +539,7 @@ local limit, r, pcgs, ser, ind, m, p, l, l2, good, i, j,nser,hom; ser:=InvariantElementaryAbelianSeries(p, List( GeneratorsOfGroup( G ), i -> GroupHomomorphismByImagesNC(p,p,GeneratorsOfGroup(p), List(GeneratorsOfGroup(p), - j->Image(m,PreImagesRepresentative(m,j)^i)))), + j->Image(m,PreImagesRepresentativeNC(m,j)^i)))), TrivialSubgroup(p),true); ser:=List(ser,i->PreImage(m,i)); else diff --git a/lib/schur.gi b/lib/schur.gi index f53b66dbdd..78fa794be6 100644 --- a/lib/schur.gi +++ b/lib/schur.gi @@ -130,7 +130,7 @@ InstallMethod(EpimorphismSchurCover,"generic, via fp group",true,[IsGroup],1, j->One(F))))); hom:=GroupHomomorphismByImagesNC(D,G,GeneratorsOfGroup(D), - List(Dgens,i->PreImagesRepresentative(iso,i))); + List(Dgens,i->PreImagesRepresentativeNC(iso,i))); Dgens:=TzImagesOldGens(p); Dgens:=List(Dgens{[Length(Fgens)+1..Length(Dgens)]}, i->MappedWord(i,p!.generators,GeneratorsOfGroup(D))); @@ -201,7 +201,7 @@ local s,pcgs,n,l,cov,pco,ng,gens,imgs,ran,zer,i,j,e,a, fi; # get a decent pcgs for the cover - pco:=List(pcgs,i->Image(epi,PreImagesRepresentative(de,i))); + pco:=List(pcgs,i->Image(epi,PreImagesRepresentativeNC(de,i))); Append(pco,Pcgs(mul)); pco:=PcgsByPcSequenceNC(FamilyObj(One(cov)),pco); @@ -257,13 +257,13 @@ local s,pcgs,n,l,cov,pco,ng,gens,imgs,ran,zer,i,j,e,a, if Order(dc[i])>1 then # the trivial element will not do anything q:=Intersection(s,ConjugateSubgroup(s,dc[i]^-1)); if Size(q)>1 then - qs:=PreImage(epi,q); - # factor generators - gens:=GeneratorsOfGroup(qs); - # their conjugates - imgs:=List(gens,j->PreImagesRepresentative(epi,Image(epi,j)^dc[i])); - rels:=ClosureGroup(rels,CommutGenImgs(pco,gens,imgs, - Intersection(mul,DerivedSubgroup(qs)))); + qs:=PreImage(epi,q); + # factor generators + gens:=GeneratorsOfGroup(qs); + # their conjugates + imgs:=List(gens,j->PreImagesRepresentativeNC(epi,Image(epi,j)^dc[i])); + rels:=ClosureGroup(rels,CommutGenImgs(pco,gens,imgs, + Intersection(mul,DerivedSubgroup(qs)))); fi; fi; i:=i+1; @@ -306,7 +306,7 @@ BindGlobal("PositiveExponentsPresentationFpHom",function(hom) local G,F,geni,ro,fam,r,i,j,rel,n,e; G:=Image(hom); F:=FreeGeneratorsOfFpGroup(G); - geni:=List(GeneratorsOfGroup(G),i->PreImagesRepresentative(hom,i)); + geni:=List(GeneratorsOfGroup(G),i->PreImagesRepresentativeNC(hom,i)); ro:=List(geni,Order); fam:=FamilyObj(F[1]); r:=[]; @@ -351,7 +351,7 @@ local G,H,D,T,i,j,k,l,a,h,nk,evals,rels,gens,r,np,g,invlist,el,elp,TL,rp,pos; # this will guarantee we always take the same preimages el:=AsSSortedListNonstored(H); - elp:=List(el,i->PreImagesRepresentative(s,i)); + elp:=List(el,i->PreImagesRepresentativeNC(s,i)); #ensure the preimage of identity is one if IsOne(el[1]) then pos:=1; @@ -394,20 +394,20 @@ local G,H,D,T,i,j,k,l,a,h,nk,evals,rels,gens,r,np,g,invlist,el,elp,TL,rp,pos; k:=T[j]; h:=One(D); for l in i do - if l<0 then - g:=Inverse(gens[-l]); - else - g:=gens[l]; - fi; - np:=k*g; - nk:=TL[PositionCanonical(T,np)]; - #h:=h*PreImagesRepresentative(s,np/nk); - h:=h*elp[Position(el,np/nk)]; - k:=nk; + if l<0 then + g:=Inverse(gens[-l]); + else + g:=gens[l]; + fi; + np:=k*g; + nk:=TL[PositionCanonical(T,np)]; + #h:=h*PreImagesRepresentativeNC(s,np/nk); + h:=h*elp[Position(el,np/nk)]; + k:=nk; od; - #Print(PreImagesRepresentative(s,Image(s,h))*h,"\n"); - #a:=a/PreImagesRepresentative(s,Image(s,h))*h; + #Print(PreImagesRepresentativeNC(s,Image(s,h))*h,"\n"); + #a:=a/PreImagesRepresentativeNC(s,Image(s,h))*h; a:=a/h*elp[Position(el,Image(s,h))]; od; @@ -485,7 +485,7 @@ local G,B,P,s,D,i,j,v,ri,rank,bas,basr,row,rel,sol,snf,mat; j:=NaturalHomomorphismByNormalSubgroupNC(D,v); i:=GeneratorsOfGroup(Image(j)); i:=GroupHomomorphismByImagesNC(Image(j),P,i, - List(i,k->ImageElm(s,PreImagesRepresentative(j,k)))); + List(i,k->ImageElm(s,PreImagesRepresentativeNC(j,k)))); SetKernelOfMultiplicativeGeneralMapping(i, Image(j,KernelOfMultiplicativeGeneralMapping(s))); return i; @@ -558,7 +558,7 @@ local hom, #isomorphism fp s:=sl[pp]; mg:=IsomorphismPermGroup(KernelOfMultiplicativeGeneralMapping(s)); mg:=List(IndependentGeneratorsOfAbelianGroup(Image(mg)), - i->PreImagesRepresentative(mg,i)); + i->PreImagesRepresentativeNC(mg,i)); sdc:=ListWithIdenticalEntries(Last(ngl),One(Source(s))); sdc{[ngl[pp]+1..ngl[pp+1]]}:=mg; @@ -579,7 +579,7 @@ local hom, #isomorphism fp q:=[]; for i in ce do - Add(q,PreImagesRepresentative(sdc,i[2])); + Add(q,PreImagesRepresentativeNC(sdc,i[2])); od; rel2[pp]:=q; od; diff --git a/lib/semirel.gi b/lib/semirel.gi index dd0fad38fa..ddf52fda8f 100644 --- a/lib/semirel.gi +++ b/lib/semirel.gi @@ -1299,7 +1299,7 @@ end); ######## ######## -InstallMethod(PreImagesRepresentative, "for semigroup homomorphism by images", +InstallMethod(PreImagesRepresentativeNC,"for semigroup homomorphism by images", FamRangeEqFamElm, [IsSemigroupHomomorphism and IsSemigroupHomomorphismByImagesRep, IsMultiplicativeElement], function(hom, x) diff --git a/lib/stbcbckt.gi b/lib/stbcbckt.gi index f0b4eb0046..1d9ccd727f 100644 --- a/lib/stbcbckt.gi +++ b/lib/stbcbckt.gi @@ -2602,7 +2602,7 @@ dom, et, ft, Pr, rbase, BF, Q, data,lc; found:=PartitionBacktrack( G, Pr, true, rbase, data, L, R ); if IsPerm(found) and map<>false then - found:=PreImagesRepresentative(map,found); + found:=PreImagesRepresentativeNC(map,found); fi; return found; end ); diff --git a/lib/twocohom.gi b/lib/twocohom.gi index 8a955f00b6..824ce3bdba 100644 --- a/lib/twocohom.gi +++ b/lib/twocohom.gi @@ -813,7 +813,7 @@ local field,fp,fpg,gens,hom,mats,fm,mon,tzrules,dim,rules,eqs,i,j,k,l,o,l1, od; gens:=List(GeneratorsOfGroup(FamilyObj(fpg)!.wholeGroup), - x->PreImagesRepresentative(fp,x)); + x->PreImagesRepresentativeNC(fp,x)); hom:=GroupHomomorphismByImagesNC(G,Group(mo.generators), GeneratorsOfGroup(G),mo.generators); @@ -845,7 +845,7 @@ local field,fp,fpg,gens,hom,mats,fm,mon,tzrules,dim,rules,eqs,i,j,k,l,o,l1, else # Length of r[1] is 1. That is, this generator is not used! m:=First(RelationsOfFpMonoid(mon),x->List(x,LetterRepAssocWord)=r); - m:=List(m,x->PreImagesRepresentative(fm,ElementOfFpMonoid(FamilyObj(One(mon)),x))); + m:=List(m,x->PreImagesRepresentativeNC(fm,ElementOfFpMonoid(FamilyObj(One(mon)),x))); m:=List(m,UnderlyingElement); # free group elements/words if not IsOne(m[1]*Subword(m[2],1,1)) then @@ -866,7 +866,7 @@ local field,fp,fpg,gens,hom,mats,fm,mon,tzrules,dim,rules,eqs,i,j,k,l,o,l1, model:=ValueOption("model"); if model<>fail then q:=GQuotients(model,G)[1]; - pre:=List(gens,x->PreImagesRepresentative(q,x)); + pre:=List(gens,x->PreImagesRepresentativeNC(q,x)); ker:=KernelOfMultiplicativeGeneralMapping(q); pcgs:=Pcgs(ker); l1:=GModuleByMats(LinearActionLayer(Group(pre),pcgs),mo.field); @@ -880,7 +880,7 @@ local field,fp,fpg,gens,hom,mats,fm,mon,tzrules,dim,rules,eqs,i,j,k,l,o,l1, m:=GroupGeneralMappingByImagesNC(fpg,model,GeneratorsOfGroup(fpg),pre); mats:=List(GeneratorsOfMonoid(mon), x->ImagesRepresentative(m, - PreImagesRepresentative(fm,x))); #Elements for monoid generators + PreImagesRepresentativeNC(fm,x))); #Elements for monoid generators nonone:=[1..Length(mats)]; pre:=mats; onemat:=One(G); @@ -896,8 +896,8 @@ local field,fp,fpg,gens,hom,mats,fm,mon,tzrules,dim,rules,eqs,i,j,k,l,o,l1, zerovec:=Zero(onemat[1]); mats:=List(GeneratorsOfMonoid(mon), - x->ImagesRepresentative(hom,PreImagesRepresentative(fp, - PreImagesRepresentative(fm,x)))); # matrices for monoid generators + x->ImagesRepresentative(hom,PreImagesRepresentativeNC(fp, + PreImagesRepresentativeNC(fm,x)))); # matrices for monoid generators one:=One(mats[1]); nonone:=Filtered([1..Length(mats)],x->not IsOne(mats[x])); zero:=zerovec; @@ -1046,7 +1046,7 @@ local field,fp,fpg,gens,hom,mats,fm,mon,tzrules,dim,rules,eqs,i,j,k,l,o,l1, one:=One(FreeGroupOfFpGroup(fpg)); k:=List(GeneratorsOfMonoid(mon), - x->UnderlyingElement(PreImagesRepresentative(fm,x))); + x->UnderlyingElement(PreImagesRepresentativeNC(fm,x))); # matrix corresponding to monoid word mapped2:=function(list) local a,i; @@ -1124,8 +1124,8 @@ local field,fp,fpg,gens,hom,mats,fm,mon,tzrules,dim,rules,eqs,i,j,k,l,o,l1, local a; if not IsBound(imagemonwords[nr]) then # apply automorphism - a:=PreImagesRepresentative(fm,GeneratorsOfMonoid(mon)[nr]); - a:=PreImagesRepresentative(fp,a); + a:=PreImagesRepresentativeNC(fm,GeneratorsOfMonoid(mon)[nr]); + a:=PreImagesRepresentativeNC(fp,a); a:=ImagesRepresentative(autom,a); a:=ImagesRepresentative(fp,a); a:=ImagesRepresentative(fm,a); From 8128aa23ed9b1aa2d5aff8f1da8e5e0249efe35a Mon Sep 17 00:00:00 2001 From: Chris Wensley Date: Thu, 29 Sep 2022 15:58:43 +0100 Subject: [PATCH 004/234] PreImRep -> PreImRepNC in xml files --- doc/ref/grpfp.xml | 4 ++-- doc/ref/rws.xml | 2 +- doc/tut/algvspc.xml | 8 ++++---- doc/tut/group.xml | 4 ++-- lib/algrep.gd | 12 +++++++----- lib/fitfree.gd | 2 +- lib/ghomfp.gd | 4 ++-- 7 files changed, 19 insertions(+), 17 deletions(-) diff --git a/doc/ref/grpfp.xml b/doc/ref/grpfp.xml index 6a4507d2a0..bf4eb25727 100644 --- a/doc/ref/grpfp.xml +++ b/doc/ref/grpfp.xml @@ -486,7 +486,7 @@ gap> hom:=IsomorphismFpGroup(u); [ <[ [ 1, 1 ] ]|f2^-1*f1^-1> ] -> [ F1 ] gap> new:=Range(hom); -gap> List(GeneratorsOfGroup(new),i->PreImagesRepresentative(hom,i)); +gap> List(GeneratorsOfGroup(new),i->PreImagesRepresentativeNC(hom,i)); [ <[ [ 1, 1 ] ]|f2^-1*f1^-1> ] ]]>

@@ -504,7 +504,7 @@ behave like ordinary words and no extra treatment should be necessary. r:=Range(hom).1^10; F1^10 -gap> p:=PreImagesRepresentative(hom,r); +gap> p:=PreImagesRepresentativeNC(hom,r); <[ [ 1, 10 ] ]|(f2^-1*f1^-1)^10> ]]> diff --git a/doc/ref/rws.xml b/doc/ref/rws.xml index 86b8a5676e..e644b345a4 100644 --- a/doc/ref/rws.xml +++ b/doc/ref/rws.xml @@ -174,7 +174,7 @@ gap> red:=ReducedForm(k,UnderlyingElement(melm)); f1^-1^3*f2^-1*f1^2 gap> melm:=ElementOfFpMonoid(FamilyObj(One(mon)),red); f1^-1^3*f2^-1*f1^2 -gap> gpelm:=PreImagesRepresentative(mhom,melm); +gap> gpelm:=PreImagesRepresentativeNC(mhom,melm); f1^-3*f2^-1*f1^2 gap> r=gpelm; true diff --git a/doc/tut/algvspc.xml b/doc/tut/algvspc.xml index bbc1da8b3f..264db61955 100644 --- a/doc/tut/algvspc.xml +++ b/doc/tut/algvspc.xml @@ -207,7 +207,7 @@ gap> h:= NaturalHomomorphismBySubspace( V, W ); ( Rationals^2 )> gap> Image( h, [ 1, 2, 3, 4 ] ); [ 0, 0 ] -gap> PreImagesRepresentative( h, [ 1, 0 ] ); +gap> PreImagesRepresentativeNC( h, [ 1, 0 ] ); [ 1, 0, 0, 0 ] ]]> @@ -470,11 +470,11 @@ gap> AmodR:= ImagesSource( h ); gap> id:= CentralIdempotentsOfAlgebra( AmodR ); [ v.3, v.2+(-3)*v.3, v.1+(-2)*v.2+(3)*v.3 ] -gap> PreImagesRepresentative( h, id[1] ); +gap> PreImagesRepresentativeNC( h, id[1] ); [ [ 0, 0, 0 ], [ 0, 0, 0 ], [ 0, 0, 1 ] ] -gap> PreImagesRepresentative( h, id[2] ); +gap> PreImagesRepresentativeNC( h, id[2] ); [ [ 0, 0, 0 ], [ 0, 1, 0 ], [ 0, 0, 0 ] ] -gap> PreImagesRepresentative( h, id[3] ); +gap> PreImagesRepresentativeNC( h, id[3] ); [ [ 1, 0, 0 ], [ 0, 0, 0 ], [ 0, 0, 0 ] ] ]]>

diff --git a/doc/tut/group.xml b/doc/tut/group.xml index 228c8f71fa..ce31d31262 100644 --- a/doc/tut/group.xml +++ b/doc/tut/group.xml @@ -936,7 +936,7 @@ brk> quit; ]]>

PreImagesRepresentative( hom, (1,2,3) ); +gap> PreImagesRepresentativeNC( hom, (1,2,3) ); (1,4,2) gap> PreImage( hom, TrivialSubgroup(s3) ); # the kernel Group([ (1,4)(2,3), (1,3)(2,4) ]) @@ -1127,7 +1127,7 @@ Section ). gap> pcls := ConjugacyClasses( p );; gcls := [ ];; gap> for pc in pcls do > gc:=ConjugacyClass(grp, -> PreImagesRepresentative(hom,Representative(pc))); +> PreImagesRepresentativeNC(hom,Representative(pc))); > SetStabilizerOfExternalSet(gc,PreImage(hom, > StabilizerOfExternalSet(pc))); > Add( gcls, gc ); diff --git a/lib/algrep.gd b/lib/algrep.gd index 7e1244e589..6f65ddbe5f 100644 --- a/lib/algrep.gd +++ b/lib/algrep.gd @@ -697,10 +697,12 @@ DeclareOperation( "ModuleByRestriction", [ IsAlgebraModule, IsAlgebra ] ); ## ## ## -## Here V must be a sub-algebra module of V. This function returns -## the projection from V onto V/W. It is a linear map, that is -## also a module homomorphism. As usual images can be formed with -## Image( f, v ) and pre-images with PreImagesRepresentative( f, u ). +## Here V must be a sub-algebra module of V. +## This function returns +## the projection from V onto V/W. +## It is a linear map, that is also a module homomorphism. +## As usual images can be formed with Image( f, v ) +## and pre-images with PreImagesRepresentativeNC( f, u ). ##

## The quotient module can also be formed ## by entering V/W. @@ -726,7 +728,7 @@ DeclareOperation( "ModuleByRestriction", [ IsAlgebraModule, IsAlgebra ] ); ## 18 over Rationals>> ## gap> v:= Basis( quo )[1]; ## [ 1, 0, 0, 0, 0, 0, 0, 0, 0 ] -## gap> PreImagesRepresentative( f, v ); +## gap> PreImagesRepresentativeNC( f, v ); ## v.4 ## gap> Basis( C )[4]^v; ## [ 1, 0, 0, 0, 0, 0, 0, 0, 0 ] diff --git a/lib/fitfree.gd b/lib/fitfree.gd index c284d7259c..e4a556ac83 100644 --- a/lib/fitfree.gd +++ b/lib/fitfree.gd @@ -92,7 +92,7 @@ DeclareGlobalFunction("AttemptPermRadicalMethod"); ## the image group being ## represented in a way that decomposition into generators will work ## efficiently. In particular, it is possible to use -## to take the pre-image of elements +## to take the pre-image of elements ## in the image. For a subgroup U\le G, it is possible to apply ## to the homomorphism to obtain a ## corresponding homomorphism for U. diff --git a/lib/ghomfp.gd b/lib/ghomfp.gd index 457f5f2640..f2e534c3d7 100644 --- a/lib/ghomfp.gd +++ b/lib/ghomfp.gd @@ -264,7 +264,7 @@ DeclareAttribute("IsomorphismSimplifiedFpGroup",IsSubgroupFpGroup); ## Group([ (1,2,3,4), (1,2) ]) ## gap> hom:=EpimorphismFromFreeGroup(g:names:=["x","y"]); ## [ x, y ] -> [ (1,2,3,4), (1,2) ] -## gap> PreImagesRepresentative(hom,(1,4)); +## gap> PreImagesRepresentativeNC(hom,(1,4)); ## y^-1*x^-1*(x^-1*y^-1)^2*x ## ]]> ##

@@ -279,7 +279,7 @@ DeclareAttribute("IsomorphismSimplifiedFpGroup",IsSubgroupFpGroup); ## gap> puzzle := Group( perms );;Size( puzzle ); ## 20922789888000 ## gap> hom:=EpimorphismFromFreeGroup(puzzle:names:=["a", "b", "c", "d"]);; -## gap> word := PreImagesRepresentative( hom, (1,2) ); +## gap> word := PreImagesRepresentativeNC( hom, (1,2) ); ## a^-1*c*b*c^-1*a*b^-1*a^-2*c^-1*a*b^-1*c*b ## gap> Length( word ); ## 13 From d687596455b695ded075081c533cd91692b79263 Mon Sep 17 00:00:00 2001 From: Chris Wensley Date: Thu, 29 Sep 2022 16:09:12 +0100 Subject: [PATCH 005/234] some PreImRep -> PreImRepNC in tests --- tst/testextra/makeperfect.g | 4 ++-- tst/testinstall/gprdmat.tst | 4 ++-- tst/testinstall/grppc.tst | 2 +- tst/testinstall/mapphomo.tst | 2 +- tst/testinstall/vspchom.tst | 28 ++++++++++++++-------------- 5 files changed, 20 insertions(+), 20 deletions(-) diff --git a/tst/testextra/makeperfect.g b/tst/testextra/makeperfect.g index fd68a1560c..b7ed22e898 100644 --- a/tst/testextra/makeperfect.g +++ b/tst/testextra/makeperfect.g @@ -244,8 +244,8 @@ local respp,cf,m,mpos,coh,fgens,comp,reps,v,new,isok,pema,pf,gens,nt,quot, List(GeneratorsOfGroup(new),x->ImagesRepresentative(pema,x)), Concatenation( List(GeneratorsOfGroup(Range(coh.fphom)), - x->PreImagesRepresentative(coh.fphom,x)), - ListWithIdenticalEntries(coh.module.dimension, + x->PreImagesRepresentativeNC(coh.fphom,x)), + ListWithIdenticalEntries(coh.module.dimension, One(coh.group)) )); qk:=KernelOfMultiplicativeGeneralMapping(quot); diff --git a/tst/testinstall/gprdmat.tst b/tst/testinstall/gprdmat.tst index 8af5073eb5..7e2e3100b2 100644 --- a/tst/testinstall/gprdmat.tst +++ b/tst/testinstall/gprdmat.tst @@ -47,9 +47,9 @@ gap> Size(Image(iota2 * pi1)); 1 # -gap> ForAll(G1, g -> PreImagesRepresentative(iota1, ImagesRepresentative(iota1, g)) = g); +gap> ForAll(G1, g -> PreImagesRepresentativeNC(iota1, ImagesRepresentative(iota1, g)) = g); true -gap> ForAll(G2, g -> PreImagesRepresentative(iota2, ImagesRepresentative(iota2, g)) = g); +gap> ForAll(G2, g -> PreImagesRepresentativeNC(iota2, ImagesRepresentative(iota2, g)) = g); true gap> Size(Images(pi1,KernelOfMultiplicativeGeneralMapping(pi1))); 1 diff --git a/tst/testinstall/grppc.tst b/tst/testinstall/grppc.tst index f526eba327..b55eac934e 100644 --- a/tst/testinstall/grppc.tst +++ b/tst/testinstall/grppc.tst @@ -28,7 +28,7 @@ g3^g2 = g4 g4^g2 = g3*g4 all other pairs of generators commute gap> pcgs:=Pcgs(hh);; -gap> ForAll(pcgs,i->PreImagesRepresentative(m,i) in h); +gap> ForAll(pcgs,i->PreImagesRepresentativeNC(m,i) in h); true gap> g:=WreathProduct(Group((1,2,3),(1,2)),Group((1,2,3,4,5,6,7)));; gap> i:=IsomorphismPcGroup(g);; diff --git a/tst/testinstall/mapphomo.tst b/tst/testinstall/mapphomo.tst index fc07734442..fce1e27862 100644 --- a/tst/testinstall/mapphomo.tst +++ b/tst/testinstall/mapphomo.tst @@ -74,7 +74,7 @@ fail # Check that group homomorphisms created by a function can compute preimages. gap> for G in [ SymmetricGroup(5), SmallGroup( 24, 12 ), GL(2,3) ] do > hom:= GroupHomomorphismByFunction( G, G, x -> x ); -> PreImagesRepresentative( hom, G.1 ); +> PreImagesRepresentativeNC( hom, G.1 ); > od; # diff --git a/tst/testinstall/vspchom.tst b/tst/testinstall/vspchom.tst index 69920d91ab..2cedaa8079 100644 --- a/tst/testinstall/vspchom.tst +++ b/tst/testinstall/vspchom.tst @@ -31,9 +31,9 @@ gap> ImagesRepresentative( map1, 0*Z(3)^0 ); 0*Z(3) gap> ImagesRepresentative( map1, Z(3)^0 ); Z(3^3) -gap> PreImagesRepresentative( map1, 0*Z(3) ); +gap> PreImagesRepresentativeNC( map1, 0*Z(3) ); 0*Z(3) -gap> PreImagesRepresentative( map1, Z(27) ); +gap> PreImagesRepresentativeNC( map1, Z(27) ); Z(3)^0 gap> 2 * map1 = - map1; true @@ -60,9 +60,9 @@ gap> ImagesRepresentative( map2, Z(27) ); [ Z(3)^0, Z(3)^0 ] gap> ImagesRepresentative( map2, Z(9) ); fail -gap> PreImagesRepresentative( map2, [ Z(3)^0, Z(3)^0 ] ); +gap> PreImagesRepresentativeNC( map2, [ Z(3)^0, Z(3)^0 ] ); Z(3^3) -gap> PreImagesRepresentative( map2, [ 0*Z(3)^0, 0*Z(3)^0 ] ); +gap> PreImagesRepresentativeNC( map2, [ 0*Z(3)^0, 0*Z(3)^0 ] ); 0*Z(3) gap> 2 * map2 = - map2; true @@ -89,9 +89,9 @@ gap> ImagesRepresentative( map3, [ Z(3)^0, 0*Z(3)^0 ] ); Z(3)^0 gap> ImagesRepresentative( map3, [ 0*Z(3)^0, Z(3)^0 ] ); Z(3^3)^3 -gap> PreImagesRepresentative( map3, Z(27) ); +gap> PreImagesRepresentativeNC( map3, Z(27) ); [ Z(3)^0, Z(3)^0 ] -gap> PreImagesRepresentative( map3, Z(3)^0 ); +gap> PreImagesRepresentativeNC( map3, Z(3)^0 ); [ Z(3)^0, 0*Z(3) ] gap> 2 * map3 = - map3; true @@ -204,9 +204,9 @@ gap> ImagesRepresentative( map5, 0*Z(3)^0 ); 0*Z(3) gap> ImagesRepresentative( map5, Z(3)^0 ); Z(3^3)^19 -gap> PreImagesRepresentative( map5, 0*Z(3) ); +gap> PreImagesRepresentativeNC( map5, 0*Z(3) ); 0*Z(3) -gap> PreImagesRepresentative( map5, Z(27) ); +gap> PreImagesRepresentativeNC( map5, Z(27) ); fail gap> 2 * map5 = - map5; true @@ -232,9 +232,9 @@ gap> ImagesRepresentative( map6, Z(27) ); [ 0*Z(3), 0*Z(3) ] gap> ImagesRepresentative( map6, Z(9) ); fail -gap> PreImagesRepresentative( map6, [ Z(3)^0, Z(3)^0 ] ); +gap> PreImagesRepresentativeNC( map6, [ Z(3)^0, Z(3)^0 ] ); Z(3) -gap> PreImagesRepresentative( map6, [ 0*Z(3)^0, 0*Z(3)^0 ] ); +gap> PreImagesRepresentativeNC( map6, [ 0*Z(3)^0, 0*Z(3)^0 ] ); 0*Z(3) gap> 2 * map6 = - map6; true @@ -260,9 +260,9 @@ gap> ImagesRepresentative( map7, [ Z(3)^0, 0*Z(3)^0 ] ); Z(3^3)^21 gap> ImagesRepresentative( map7, [ 0*Z(3)^0, Z(3)^0 ] ); Z(3^3)^21 -gap> PreImagesRepresentative( map7, Z(27) ); +gap> PreImagesRepresentativeNC( map7, Z(27) ); fail -gap> PreImagesRepresentative( map7, Z(3)^0 ); +gap> PreImagesRepresentativeNC( map7, Z(3)^0 ); fail gap> 2 * map7 = - map7; true @@ -365,9 +365,9 @@ gap> ImagesRepresentative( nathom, [ Z(3), Z(3)^0 ] ); [ Z(3)^0 ] gap> ImagesRepresentative( nathom, [ Z(3)^0, Z(3)^0 ] ); [ 0*Z(3) ] -gap> PreImagesRepresentative( nathom, [ Z(3)^0 ] ); +gap> PreImagesRepresentativeNC( nathom, [ Z(3)^0 ] ); [ Z(3)^0, 0*Z(3) ] -gap> PreImagesRepresentative( nathom, [ 0*Z(3) ] ); +gap> PreImagesRepresentativeNC( nathom, [ 0*Z(3) ] ); [ 0*Z(3), 0*Z(3) ] gap> 2 * nathom = - nathom; true From 6eeafb9e135d38a4bd20d5e5c93b8e5cf94d8c03 Mon Sep 17 00:00:00 2001 From: Chris Wensley Date: Fri, 30 Sep 2022 16:50:00 +0100 Subject: [PATCH 006/234] cases where fail being returned is immediately checked --- lib/alghom.gi | 4 ++-- lib/ghomperm.gi | 2 +- lib/mapphomo.gi | 14 +++++++------- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/lib/alghom.gi b/lib/alghom.gi index 2206697003..9224131a56 100644 --- a/lib/alghom.gi +++ b/lib/alghom.gi @@ -928,7 +928,7 @@ BindGlobal( "PreImagesRepresentativeOperationAlgebraHomomorphism", function( oph return mat; end ); -InstallMethod( PreImagesRepresentativeNC, +InstallMethod( PreImagesRepresentative, "for an operation algebra homomorphism, and an element", FamRangeEqFamElm, [ IsOperationAlgebraHomomorphismDefaultRep, IsMatrix ], @@ -1090,7 +1090,7 @@ InstallMethod( ImagesRepresentative, ############################################################################# ## -#M PreImagesRepresentativeNC( , ) +#M PreImagesRepresentative( , ) ## InstallMethod( PreImagesRepresentativeNC, "for an alg. hom. from f. p. algebra, and an element", diff --git a/lib/ghomperm.gi b/lib/ghomperm.gi index 38e811426d..a72e00a98b 100644 --- a/lib/ghomperm.gi +++ b/lib/ghomperm.gi @@ -22,7 +22,7 @@ local genpreimages, pre,kg,sz,ol,orb,pos,dom,one; genpreimages:=GeneratorsOfMagmaWithInverses( elms ); genpreimages:= List(genpreimages, - gen -> PreImagesRepresentativeNC( map, gen ) ); + gen -> PreImagesRepresentative( map, gen ) ); if fail in genpreimages then TryNextMethod(); fi; diff --git a/lib/mapphomo.gi b/lib/mapphomo.gi index 423d0769aa..ca24379767 100644 --- a/lib/mapphomo.gi +++ b/lib/mapphomo.gi @@ -340,7 +340,7 @@ InstallMethod( PreImagesElm, function( map, elm ) local pre; - pre:= PreImagesRepresentativeNC( map, elm ); + pre:= PreImagesRepresentative( map, elm ); if pre = fail then return []; else @@ -367,7 +367,7 @@ InstallMethod( PreImagesSet, fi; genpreimages:= List(genpreimages, - gen -> PreImagesRepresentativeNC( map, gen ) ); + gen -> PreImagesRepresentative( map, gen ) ); if fail in genpreimages then TryNextMethod(); fi; @@ -694,7 +694,7 @@ InstallMethod( PreImagesElm, function( map, elm ) local pre; - pre:= PreImagesRepresentativeNC( map, elm ); + pre:= PreImagesRepresentative( map, elm ); if pre = fail then return []; else @@ -715,7 +715,7 @@ InstallMethod( PreImagesSet, function( map, elms ) local genpreimages; genpreimages:= List( GeneratorsOfAdditiveGroup( elms ), - gen -> PreImagesRepresentativeNC( map, gen ) ); + gen -> PreImagesRepresentative( map, gen ) ); if fail in genpreimages then TryNextMethod(); fi; @@ -901,7 +901,7 @@ InstallMethod( PreImagesSet, function( map, elms ) local genpreimages; genpreimages:= List( GeneratorsOfLeftModule( elms ), - gen -> PreImagesRepresentativeNC( map, gen ) ); + gen -> PreImagesRepresentative( map, gen ) ); if fail in genpreimages then TryNextMethod(); fi; @@ -995,7 +995,7 @@ InstallMethod( PreImagesSet, function( map, elms ) local genpreimages; genpreimages:= List( GeneratorsOfLeftOperatorRing( elms ), - gen -> PreImagesRepresentativeNC( map, gen ) ); + gen -> PreImagesRepresentative( map, gen ) ); if fail in genpreimages then TryNextMethod(); fi; @@ -1022,7 +1022,7 @@ InstallMethod( PreImagesSet, function( map, elms ) local genpreimages; genpreimages:= List( GeneratorsOfLeftOperatorRingWithOne( elms ), - gen -> PreImagesRepresentativeNC( map, gen ) ); + gen -> PreImagesRepresentative( map, gen ) ); if fail in genpreimages then TryNextMethod(); fi; From 36e527908236e11b1d13f4c146f9534c51bb8b31 Mon Sep 17 00:00:00 2001 From: Chris Wensley Date: Tue, 4 Oct 2022 16:03:45 +0100 Subject: [PATCH 007/234] PreImRep now a synonym for PreImRepNC --- doc/ref/mapping.xml | 2 +- lib/mapping.gd | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/doc/ref/mapping.xml b/doc/ref/mapping.xml index 64356ac1ab..ae5865e617 100644 --- a/doc/ref/mapping.xml +++ b/doc/ref/mapping.xml @@ -106,7 +106,7 @@ section . <#Include Label="PreImagesRange"> <#Include Label="PreImagesElm"> <#Include Label="PreImageElm"> -<#Include Label="PreImagesRepresentative"> +<#Include Label="PreImagesRepresentativeNC"> <#Include Label="PreImagesSet"> <#Include Label="PreImage"> <#Include Label="PreImages"> diff --git a/lib/mapping.gd b/lib/mapping.gd index b83753453e..cdf9059cae 100644 --- a/lib/mapping.gd +++ b/lib/mapping.gd @@ -1078,7 +1078,6 @@ DeclareOperation( "PreImagesRepresentativeNC", [ IsGeneralMapping, IsObject ] ); DeclareSynonym( "PreImagesRepresentative", PreImagesRepresentativeNC ); - ############################################################################# ## #O PreImagesSet( , ) From c307c58729df1d264fa875176aca4983d8be60d1 Mon Sep 17 00:00:00 2001 From: Chris Wensley Date: Wed, 5 Oct 2022 16:22:52 +0100 Subject: [PATCH 008/234] PreImages renamed PreImagesNC --- doc/ref/mapping.xml | 4 ++-- doc/tut/group.xml | 48 +++++++++++++++++++------------------ lib/alglie.gi | 2 +- lib/grp.gi | 2 +- lib/grpprmcs.gi | 8 +++---- lib/mapping.gd | 1 + lib/mapping.gi | 1 - tst/testextra/ctbl.tst | 2 +- tst/testinstall/mapping.tst | 12 +++++----- 9 files changed, 41 insertions(+), 39 deletions(-) diff --git a/doc/ref/mapping.xml b/doc/ref/mapping.xml index ae5865e617..16f8aa4cce 100644 --- a/doc/ref/mapping.xml +++ b/doc/ref/mapping.xml @@ -1,6 +1,6 @@ - + @@ -106,7 +106,7 @@ section . <#Include Label="PreImagesRange"> <#Include Label="PreImagesElm"> <#Include Label="PreImageElm"> -<#Include Label="PreImagesRepresentativeNC"> +<#Include Label="PreImagesRepresentative"> <#Include Label="PreImagesSet"> <#Include Label="PreImage"> <#Include Label="PreImages"> diff --git a/doc/tut/group.xml b/doc/tut/group.xml index ce31d31262..9bd202d4cb 100644 --- a/doc/tut/group.xml +++ b/doc/tut/group.xml @@ -1,12 +1,12 @@ - + - - - - + + + + - + @@ -168,9 +168,9 @@ action domain of norm. (It only happens that both are subsets of the natural numbers.) We can now form images and preimages under the natural homomorphism. The set of preimages of an element under hom is a coset modulo elab. -We use the function here because -hom is not -a bijection, so an element of the range can have several preimages or +We use one of the functions +or here because hom is not +a bijection, so an element of the range can have several preimages or none at all.

x := (1,8,3,5,7,6,2);; Image( hom, x ); (1,7,5,6,2,3,4) -gap> coset := PreImages( hom, last ); +gap> coset := PreImagesNC( hom, last ); RightCoset(Group([ (1,2)(3,4)(5,6)(7,8), (1,3)(2,4)(5,7)(6,8), (1,5) (2,6)(3,7)(4,8) ]),(2,8,6,7,3,4,5)) ]]> @@ -380,7 +380,7 @@ gap> ophom := ActionHomomorphism( a8, op );; gap> ophom2 := ActionHomomorphism( op, op2 );; gap> composition := ophom * ophom2;; gap> stab := Stabilizer( op2, 2 );; -gap> preim := PreImages( composition, stab ); +gap> preim := PreImagesNC( composition, stab ); Group([ (1,2,4), (6,7,8), (3,6,8), (5,8,6), (1,2)(3,8) ]) ]]>

@@ -676,7 +676,7 @@ Because we want to operate on the sets we have to pass gap> u8_56 := Stabilizer( a8_56, blocks[1], OnSets );; gap> Index( a8_56, u8_56 ); 8 -gap> u8b := PreImages( h56, u8_56 );; Index( a8, u8b ); +gap> u8b := PreImagesNC( h56, u8_56 );; Index( a8, u8b ); 8 gap> IsConjugate( a8, u8, u8b ); true @@ -703,7 +703,7 @@ third subgroup. gap> seed:=First(AllBlocks(a8_56),x->Length(x)=2);; gap> blocks := Blocks( a8_56, [1..56], seed);; gap> u28_56 := Stabilizer( a8_56, seed, OnSets );; -gap> u28 := PreImages( h56, u28_56 );; +gap> u28 := PreImagesNC( h56, u28_56 );; gap> Index( a8, u28 ); 28 ]]> @@ -942,18 +942,20 @@ gap> PreImage( hom, TrivialSubgroup(s3) ); # the kernel Group([ (1,4)(2,3), (1,3)(2,4) ]) ]]>

-This homomorphism from S_4 onto S_3 is well known from elementary -group theory. Images of elements and subgroups under hom can be +This homomorphism from S_4 onto S_3 is well known from +elementary group theory. +Images of elements and subgroups under hom can be calculated with the function . -But since the mapping hom is not bijective, we cannot use the -function for preimages of -elements (they can have several preimages). Instead, we have to use -, -which returns one preimage if at least one -exists (and would return fail if none exists, which cannot occur for +But since the mapping hom is not bijective, we cannot use the +function for preimages of elements +(they can have several preimages). Instead, we have to use one of + +or +which returns one preimage if at least one exists +(and would return fail if none exists, which cannot occur for our surjective hom). -On the other hand, we can use for the -preimage of a set (which always exists, even if it is empty). +On the other hand, we can use for the +preimage of a set (which always exists, even if it is empty).

Suppose we mistype the input when trying to construct a homomorphism as below.

diff --git a/lib/alglie.gi b/lib/alglie.gi index f648d0e342..ac6d794f0f 100644 --- a/lib/alglie.gi +++ b/lib/alglie.gi @@ -34,7 +34,7 @@ InstallMethod( LieUpperCentralSeries, # under the natural homomorphism. Add( S, C ); hom:= NaturalHomomorphismByIdeal( L, C ); - C:= PreImages( hom, LieCentre( Range( hom ) ) ); + C:= PreImagesNC( hom, LieCentre( Range( hom ) ) ); #T we would like to get ideals! #T is it possible to teach the hom. that the preimage of an ideal is an ideal? diff --git a/lib/grp.gi b/lib/grp.gi index b826ace85c..32008835b4 100644 --- a/lib/grp.gi +++ b/lib/grp.gi @@ -2392,7 +2392,7 @@ InstallMethod( UpperCentralSeriesOfGroup, Add( S, C ); Info( InfoGroup, 2, "UpperCentralSeriesOfGroup: step ", Length(S) ); hom := NaturalHomomorphismByNormalSubgroupNC( G, C ); - C := PreImages( hom, Centre( Image( hom ) ) ); + C := PreImagesNC( hom, Centre( Image( hom ) ) ); od; if Last(S) = G then diff --git a/lib/grpprmcs.gi b/lib/grpprmcs.gi index 4b4d6d91a6..8ba3001d28 100644 --- a/lib/grpprmcs.gi +++ b/lib/grpprmcs.gi @@ -1873,7 +1873,7 @@ InstallMethod( Centre, else order := Size( centr ); cent := IntersectionNormalClosurePermGroup(GG,centr,order*Size(GG)); - cent:= PreImages(tchom,cent); + cent:= PreImagesNC(tchom,cent); Assert( 1, IsAbelian( cent ) ); SetIsAbelian( cent, true ); return cent; @@ -1917,7 +1917,7 @@ InstallMethod( Centre, cent := IntersectionNormalClosurePermGroup ( GG, GroupByGenerators(hgens,()), order*Size(GG) ); if n <> len then - cent:= PreImages( tchom, cent ); + cent:= PreImagesNC( tchom, cent ); fi; Assert( 1, IsAbelian( cent ) ); SetIsAbelian( cent, true ); @@ -2012,7 +2012,7 @@ InstallGlobalFunction( CentralizerNormalCSPG, function(G,N) # handle case of transitive GG directly if Length(significant) = 1 then centrnorm := CentralizerNormalTransCSPG(GG,NN); - return PreImages(tchom,centrnorm); + return PreImagesNC(tchom,centrnorm); fi; # case of intransitive GG @@ -2054,7 +2054,7 @@ InstallGlobalFunction( CentralizerNormalCSPG, function(G,N) if n = len then return central; else - return PreImages(tchom,central); + return PreImagesNC(tchom,central); fi; end ); diff --git a/lib/mapping.gd b/lib/mapping.gd index cdf9059cae..c2480a3e64 100644 --- a/lib/mapping.gd +++ b/lib/mapping.gd @@ -1250,6 +1250,7 @@ DeclareGlobalFunction( "PreImagesNC" ); DeclareSynonym( "PreImages", PreImagesNC ); + ############################################################################# ## #O CompositionMapping2(,) . . . composition of general mappings diff --git a/lib/mapping.gi b/lib/mapping.gi index 619a652c7e..26b3d63855 100644 --- a/lib/mapping.gi +++ b/lib/mapping.gi @@ -359,7 +359,6 @@ InstallGlobalFunction( PreImagesNC, function ( arg ) "PreImagesNC(,)" ); end ); - ############################################################################# ## #F CompositionMapping(,, ... ) . . . . . composition of mappings diff --git a/tst/testextra/ctbl.tst b/tst/testextra/ctbl.tst index 1fa17024fb..a935018ca0 100644 --- a/tst/testextra/ctbl.tst +++ b/tst/testextra/ctbl.tst @@ -16,7 +16,7 @@ gap> tmpSolvableResiduum:= function( G ) > return TrivialSubgroup( G ); > fi; > iso:= IsomorphismFpGroup( G ); -> return PreImages( iso, Kernel( +> return PreImagesNC( iso, Kernel( > EpimorphismSolvableQuotient( ImagesSource( iso ), Size( G ) ) ) ); > end;; gap> for n in [ 1 .. 150 ] do diff --git a/tst/testinstall/mapping.tst b/tst/testinstall/mapping.tst index 108b153f1c..c3e6a2cf84 100644 --- a/tst/testinstall/mapping.tst +++ b/tst/testinstall/mapping.tst @@ -255,7 +255,7 @@ gap> PreImagesSet( map, [ 0*Z(3), Z(3) ] ); [ 0*Z(3), Z(3)^0 ] gap> PreImagesSet( map, GF(3) ); [ 0*Z(3), Z(3)^0 ] -gap> PreImagesRepresentative( map, Z(3) ); +gap> PreImagesRepresentativeNC( map, Z(3) ); Z(3)^0 # ImageElm, ImagesSet for IsMapping @@ -310,7 +310,7 @@ gap> PreImagesSet( map, [ 0*Z(3), Z(3) ] ); [ 0*Z(3), Z(3)^0 ] gap> PreImagesSet( map, GF(3) ); [ 0*Z(3), Z(3)^0, Z(3) ] -gap> PreImagesRepresentative( map, Z(3) ); +gap> PreImagesRepresentativeNC( map, Z(3) ); 0*Z(3) gap> ImagesSource( map ); [ 0*Z(3), Z(3)^0, Z(3) ] @@ -389,13 +389,13 @@ match, maybe is not contained in Range() or is not a homogeneous li\ st or collection # PreImages -gap> PreImages(x -> x, 1); +gap> PreImagesNC(x -> x, 1); Error, must be a general mapping -gap> PreImages(mapBijective, Z(9)); +gap> PreImagesNC(mapBijective, Z(9)); Error, must be an element of Range() -gap> PreImages(mapBijective, [Z(3), Z(9)]); +gap> PreImagesNC(mapBijective, [Z(3), Z(9)]); Error, the collection must be contained in Range() -gap> PreImages(mapBijective, Z(5)); +gap> PreImagesNC(mapBijective, Z(5)); Error, the families of the element or collection and Range() don't \ match, maybe is not contained in Range() or is not a homogeneous li\ st or collection From 029ce4d0cd2f69dbbe21fa15193b69e23487cedf Mon Sep 17 00:00:00 2001 From: Chris Wensley Date: Thu, 6 Oct 2022 13:58:39 +0100 Subject: [PATCH 009/234] PreImagesSet renamed PreImagesSetNC --- lib/ctblfuns.gi | 4 ++-- lib/ctblsolv.gi | 18 +++++++++--------- lib/field.gi | 4 ++-- lib/ghom.gi | 4 ++-- lib/ghomperm.gi | 6 +++--- lib/grp.gi | 12 ++++++------ lib/grpfp.gi | 12 ++++++------ lib/grpnice.gd | 2 +- lib/grppc.gi | 8 ++++---- lib/grpperm.gi | 6 +++--- lib/mapphomo.gi | 22 +++++++++++----------- lib/mapping.gd | 10 +++++----- lib/mapping.gi | 2 +- lib/mapprep.gi | 2 +- tst/testinstall/fldabnum.tst | 2 +- tst/testinstall/mapping.tst | 8 ++++---- 16 files changed, 61 insertions(+), 61 deletions(-) diff --git a/lib/ctblfuns.gi b/lib/ctblfuns.gi index 862c51fb99..4957052a66 100644 --- a/lib/ctblfuns.gi +++ b/lib/ctblfuns.gi @@ -2049,8 +2049,8 @@ InstallMethod( InertiaSubgroup, if stab = permgrp then return G; else - return PreImagesSet( GroupHomomorphismByImages( G, permgrp, - GeneratorsOfGroup( G ), perms ), + return PreImagesSetNC( GroupHomomorphismByImages( G, permgrp, + GeneratorsOfGroup( G ), perms ), stab ); fi; end ); diff --git a/lib/ctblsolv.gi b/lib/ctblsolv.gi index ec25e87a5c..14152613f6 100644 --- a/lib/ctblsolv.gi +++ b/lib/ctblsolv.gi @@ -176,7 +176,7 @@ InstallGlobalFunction( ProjectiveCharDeg, function( G, z, q ) # `N' is a normal subgroup such that `N/' is a chief factor of `G' # of order `i' which is a power of `p'. - N:= PreImagesSet( h, N ); + N:= PreImagesSetNC( h, N ); i:= Size( N ) / oz; p:= Factors( i )[1]; @@ -184,7 +184,7 @@ InstallGlobalFunction( ProjectiveCharDeg, function( G, z, q ) # `c' is a list of complement classes of `N' modulo `z' c:= List( ComplementClassesRepresentatives( ImagesSource( h ), ImagesSet( h, N ) ), - x -> PreImagesSet( h, x ) ); + x -> PreImagesSetNC( h, x ) ); r:= Centralizer( G, N ); for L in c do if IsSubset( L, r ) then @@ -563,7 +563,7 @@ InstallGlobalFunction( CoveringTriplesCharacters, function( G, z ) N:= ChiefSeriesUnderAction( img, N ); N:= N[ Length( N ) - 1 ]; fi; - N:= PreImagesSet( h, N ); + N:= PreImagesSetNC( h, N ); if not IsAbelian( N ) then Info( InfoCharacterTable, 2, @@ -582,8 +582,8 @@ InstallGlobalFunction( CoveringTriplesCharacters, function( G, z ) h:= NaturalHomomorphismByNormalSubgroupNC( G, P ); r:= List( CoveringTriplesCharacters( ImagesSource( h ), ImageElm( h, z ) ), - x -> [ PreImagesSet( h, x[1] ), - PreImagesSet( h, x[2] ), + x -> [ PreImagesSetNC( h, x[1] ), + PreImagesSetNC( h, x[2] ), PreImagesRepresentativeNC( h, x[3] ) ] ); if p = i then @@ -622,8 +622,8 @@ InstallGlobalFunction( CoveringTriplesCharacters, function( G, z ) c:= Stabilizer( img, zn ); fi; Append( r, List( CoveringTriplesCharacters( c, zn ), - x -> [ PreImagesSet( h, x[1] ), - PreImagesSet( h, x[2] ), + x -> [ PreImagesSetNC( h, x[1] ), + PreImagesSetNC( h, x[2] ), PreImagesRepresentativeNC( h, x[3] ) ] ) ); od; return r; @@ -662,8 +662,8 @@ InstallGlobalFunction( CoveringTriplesCharacters, function( G, z ) img:= ImagesSource( h ); Append( r, List( CoveringTriplesCharacters( img, ImageElm( h, z ) ), - x -> [ PreImagesSet( h, x[1] ), - PreImagesSet( h, x[2] ), + x -> [ PreImagesSetNC( h, x[1] ), + PreImagesSetNC( h, x[2] ), PreImagesRepresentativeNC( h, x[3] ) ] ) ); fi; od; diff --git a/lib/field.gi b/lib/field.gi index 964581fae0..391acb836d 100644 --- a/lib/field.gi +++ b/lib/field.gi @@ -1335,9 +1335,9 @@ InstallMethod( PreImagesElm, ############################################################################# ## -#M PreImagesSet( , ) . . . . . . . . . . . . . preimage of a set +#M PreImagesSetNC( , ) . . . . . . . . . . . . preimage of a set ## -InstallMethod( PreImagesSet, +InstallMethod( PreImagesSetNC, "for field homomorphism and field", CollFamRangeEqFamElms, [ IsFieldHomomorphism, IsField ], diff --git a/lib/ghom.gi b/lib/ghom.gi index fa6f9cdb51..4937da9003 100644 --- a/lib/ghom.gi +++ b/lib/ghom.gi @@ -1238,9 +1238,9 @@ InstallMethod( PreImagesRepresentativeNC, ############################################################################# ## -#M PreImagesSet( , ) . . . . . . . . . for conjugator isomorphism +#M PreImagesSetNC( , ) . . . . . . . . for conjugator isomorphism ## -InstallMethod( PreImagesSet, +InstallMethod( PreImagesSetNC, "for conjugator isomorphism, and group", CollFamRangeEqFamElms, [ IsConjugatorIsomorphism, IsGroup ], 0, diff --git a/lib/ghomperm.gi b/lib/ghomperm.gi index a72e00a98b..7bd32db043 100644 --- a/lib/ghomperm.gi +++ b/lib/ghomperm.gi @@ -1579,10 +1579,10 @@ end); ############################################################################# ## -#M PreImagesSetNC( , ) . . . . . . . . . . . . . . . . for const hom +#M PreImagesSetNC( , ) . . . . . . . . . . . . . . . for const hom ## -InstallMethod( PreImagesSetNC, "constituent homomorphism",CollFamRangeEqFamElms, - [ IsConstituentHomomorphism, IsPermGroup ], 0, +InstallMethod( PreImagesSetNC, "constituent homomorphism", + CollFamRangeEqFamElms, [ IsConstituentHomomorphism, IsPermGroup ], 0, function( hom, I ) local H, # preimage of , result K, # kernel of diff --git a/lib/grp.gi b/lib/grp.gi index 32008835b4..b95e03839c 100644 --- a/lib/grp.gi +++ b/lib/grp.gi @@ -2145,7 +2145,7 @@ InstallGlobalFunction( SupersolvableResiduumDefault, function( G ) PcElementByExponentsNC( pcgs, v ) ) ); od; - Add( ds, PreImagesSet( dh, + Add( ds, PreImagesSetNC( dh, SubgroupNC( df, Concatenation( tmp2, gen ) ) ) ); od; Append( gen, tmp2 ); @@ -2154,14 +2154,14 @@ InstallGlobalFunction( SupersolvableResiduumDefault, function( G ) else # cyclic case - Add( ds, PreImagesSet( dh, + Add( ds, PreImagesSetNC( dh, SubgroupNC( df, AsSSortedList( gen ) ) ) ); fi; od; # Generate the new candidate. - ssr:= PreImagesSet( dh, SubgroupNC( df, AsSSortedList( gen ) ) ); + ssr:= PreImagesSetNC( dh, SubgroupNC( df, AsSSortedList( gen ) ) ); fi; @@ -3593,7 +3593,7 @@ InstallMethod( HallSubgroupOp, iso := IsomorphismPermGroup( G ); H := HallSubgroup( ImagesSource( iso ), pi ); - return PreImagesSet(iso, H); + return PreImagesSetNC(iso, H); end ); @@ -5331,8 +5331,8 @@ InstallMethod (MinimalNormalSubgroups, function( grp ) local hom; hom := NiceMonomorphism (grp); - return List (MinimalNormalSubgroups (NiceObject (grp)), - N -> PreImagesSet (hom, N)); + return List (MinimalNormalSubgroups (NiceObject (grp)), + N -> PreImagesSetNC(hom, N)); end); diff --git a/lib/grpfp.gi b/lib/grpfp.gi index 091a60ee2d..3f5b88c272 100644 --- a/lib/grpfp.gi +++ b/lib/grpfp.gi @@ -2031,11 +2031,11 @@ local d,A,B,e1,e2,Ag,Bg,s,sg,u,v,map,sz; # instead of intersecting both preimages with s we only intersect the # intersection - u:=PreImagesSet(Projection(d,1),G!.sub); + u:=PreImagesSetNC(Projection(d,1),G!.sub); if HasSize(B) then SetSize(u,Size(G!.sub)*Size(B)); fi; - v:=PreImagesSet(Projection(d,2),H!.sub); + v:=PreImagesSetNC(Projection(d,2),H!.sub); if HasSize(A) then SetSize(v,Size(H!.sub)*Size(A)); fi; @@ -3167,7 +3167,7 @@ InstallMethod( LowIndexSubgroupsFpGroupIterator, local u, v; u:= NextIterator( iter!.fullIterator ); - v:= PreImagesSet( fpi, u ); + v:= PreImagesSetNC( fpi, u ); SetIndexInWholeGroup( v, IndexInWholeGroup( G ) * IndexInWholeGroup( u ) ); return v; @@ -3236,7 +3236,7 @@ local fpi,u,l,i,a; l:=[]; for i in u do - a:=PreImagesSet(fpi,i); + a:=PreImagesSetNC(fpi,i); SetIndexInWholeGroup(a,IndexInWholeGroup(G)*IndexInWholeGroup(i)); Add(l,a); od; @@ -3379,8 +3379,8 @@ local d,A,B,e1,e2,Ag,Bg,s,sg,u,v; # get both subgroups in the direct product via the projections # instead of intersecting both preimages with s we only intersect the # intersection - u:=PreImagesSet(Projection(d,1),G!.sub); - v:=PreImagesSet(Projection(d,2),H!.sub); + u:=PreImagesSetNC(Projection(d,1),G!.sub); + v:=PreImagesSetNC(Projection(d,2),H!.sub); u:=Intersection(u,s); v:=Intersection(v,s); diff --git a/lib/grpnice.gd b/lib/grpnice.gd index 73ae88e9f4..18ec4439eb 100644 --- a/lib/grpnice.gd +++ b/lib/grpnice.gd @@ -613,7 +613,7 @@ BindGlobal( "SubgroupMethodByNiceMonomorphismCollColl", function( oper, par ) img:=ImagesSet( nice, obj2 ); if img = fail or not ( IsSubset( ImagesSource( nice ), img ) and - PreImagesSet( nice, img ) = obj2 ) then + PreImagesSetNC( nice, img ) = obj2 ) then TryNextMethod(); fi; img := oper( NiceObject( obj1 ), img ); diff --git a/lib/grppc.gi b/lib/grppc.gi index d81dd970d0..9233d045e2 100644 --- a/lib/grppc.gi +++ b/lib/grppc.gi @@ -2646,7 +2646,7 @@ function(G,p,e) local f; f:=MaximalAbelianQuotient(G); IsAbelian(Image(f)); - return SubgroupByPcgs(G,Pcgs(PreImagesSet(f,Omega(Image(f),p,e)))); + return SubgroupByPcgs(G,Pcgs(PreImagesSetNC(f,Omega(Image(f),p,e)))); end); # Efficiency notes: @@ -2679,7 +2679,7 @@ local z,f; f:=NaturalHomomorphismByNormalSubgroup(G,Subgroup(G,[z])); IsAbelian(Image(f)); # Probably is not, but quick to check - return SubgroupByPcgs(G,Pcgs(PreImagesSet(f,Omega(Image(f),p,e)))); + return SubgroupByPcgs(G,Pcgs(PreImagesSetNC(f,Omega(Image(f),p,e)))); end); # Efficiency Points: @@ -2820,7 +2820,7 @@ InstallMethod (HallSubgroupOp, "via IsomoprhismPcGroup", true, function (grp, pi) local iso; iso := IsomorphismPcGroup (grp); - return PreImagesSet (iso, HallSubgroup (ImagesSource (iso), pi)); + return PreImagesSetNC(iso, HallSubgroup (ImagesSource (iso), pi)); end); @@ -2841,7 +2841,7 @@ InstallMethod (SylowComplementOp, "via IsomoprhismPcGroup", true, function (grp, p) local iso; iso := IsomorphismPcGroup (grp); - return PreImagesSet (iso, SylowComplement (ImagesSource (iso), p)); + return PreImagesSetNC(iso, SylowComplement (ImagesSource (iso), p)); end); diff --git a/lib/grpperm.gi b/lib/grpperm.gi index c36a63f763..e1b9d27308 100644 --- a/lib/grpperm.gi +++ b/lib/grpperm.gi @@ -1591,7 +1591,7 @@ InstallGlobalFunction( SylowSubgroupPermGroup, function( G, p ) O := Orbit( S, D[1] ); f := ActionHomomorphism( S, O,"surjective" ); T := SylowSubgroupPermGroup( Range( f ), p ); - S := PreImagesSet( f, T ); + S := PreImagesSetNC( f, T ); SubtractSet( D, O ); od; return S; @@ -1604,7 +1604,7 @@ InstallGlobalFunction( SylowSubgroupPermGroup, function( G, p ) f := ActionHomomorphism( G, B, OnSets,"surjective" ); T := SylowSubgroupPermGroup( Range( f ), p ); if Size( T ) < Size( Range( f ) ) then - T := PreImagesSet( f, T ); + T := PreImagesSetNC( f, T ); S := SylowSubgroupPermGroup( T , p) ; return S; fi; @@ -1629,7 +1629,7 @@ InstallGlobalFunction( SylowSubgroupPermGroup, function( G, p ) Info(InfoGroup,1,"PermSylow: cycleaction"); f := ActionHomomorphism( C, B, OnSets,"surjective" ); T := SylowSubgroupPermGroup( Range( f ), p ); - S := PreImagesSet( f, T ); + S := PreImagesSetNC( f, T ); return S; end ); diff --git a/lib/mapphomo.gi b/lib/mapphomo.gi index ca24379767..42498afe7a 100644 --- a/lib/mapphomo.gi +++ b/lib/mapphomo.gi @@ -351,9 +351,9 @@ InstallMethod( PreImagesElm, ############################################################################# ## -#M PreImagesSet( , ) . for s.p. gen. mapping resp. mult. & inv. +#M PreImagesSetNC( , ) for s.p. gen. mapping resp. mult. & inv. ## -InstallMethod( PreImagesSet, +InstallMethod( PreImagesSetNC, "method for s.p. general mapping respecting mult. & inv., and group", CollFamRangeEqFamElms, [ IsSPGeneralMapping and RespectsMultiplication and RespectsInverses, @@ -384,7 +384,7 @@ InstallMethod( PreImagesSet, return pre; end ); -InstallMethod( PreImagesSet, +InstallMethod( PreImagesSetNC, "method for injective s.p. mapping respecting mult. & inv., and group", CollFamRangeEqFamElms, [ IsSPGeneralMapping and IsMapping and IsInjective and @@ -705,9 +705,9 @@ InstallMethod( PreImagesElm, ############################################################################# ## -#M PreImagesSet( , ) for s.p. gen. mapping resp. add. & add.inv. +#M PreImagesSetNC( , ) for s.p. gen. mapping resp. add. & add.inv. ## -InstallMethod( PreImagesSet, +InstallMethod( PreImagesSetNC, "method for s.p. gen. mapping resp. add. & add.inv., and add. group", CollFamRangeEqFamElms, [ IsSPGeneralMapping and RespectsAddition and RespectsAdditiveInverses, @@ -890,9 +890,9 @@ InstallMethod( ImagesSet, ############################################################################# ## -#M PreImagesSet( , ) . . . . for linear mapping and left module +#M PreImagesSetNC( , ) . . . for linear mapping and left module ## -InstallMethod( PreImagesSet, +InstallMethod( PreImagesSetNC, "method for linear mapping and left module", CollFamRangeEqFamElms, [ IsSPGeneralMapping and RespectsAddition and RespectsAdditiveInverses @@ -984,9 +984,9 @@ InstallMethod( ImagesSet, ############################################################################# ## -#M PreImagesSet( , ) . . . . . . . . for algebra hom. and FLMLOR +#M PreImagesSetNC( , ) . . . . . . . for algebra hom. and FLMLOR ## -InstallMethod( PreImagesSet, +InstallMethod( PreImagesSetNC, "method for algebra hom. and FLMLOR", CollFamRangeEqFamElms, [ IsSPGeneralMapping and RespectsAddition and RespectsAdditiveInverses @@ -1010,9 +1010,9 @@ InstallMethod( PreImagesSet, ############################################################################# ## -#M PreImagesSet( , ) for alg.-with-one hom. and FLMLOR-with-one +#M PreImagesSetNC( , ) for alg.-with-one hom. and FLMLOR-with-one ## -InstallMethod( PreImagesSet, +InstallMethod( PreImagesSetNC, "method for algebra-with-one hom. and FLMLOR-with-one", CollFamRangeEqFamElms, [ IsSPGeneralMapping and RespectsAddition and RespectsAdditiveInverses diff --git a/lib/mapping.gd b/lib/mapping.gd index c2480a3e64..47633ba10f 100644 --- a/lib/mapping.gd +++ b/lib/mapping.gd @@ -753,7 +753,7 @@ DeclareAttribute( "ImagesSource", IsGeneralMapping ); ## ## is the set of preimages of the range of the general mapping map. ##

-## delegates to , +## delegates to , ## it is introduced only to store the preimage of map as attribute ## value. ## @@ -1159,10 +1159,10 @@ DeclareSynonym( "PreImagesSet", PreImagesSetNC ); ## (If coll and the result are lists then the positions of ## entries do in general not correspond.) ##

-## -## delegates to when -## called with one argument, -## and to resp. when +## +## delegates to when called with one argument, +## and to resp. when ## called with two arguments. ##

## If the second argument is not an element or a subset of the range of diff --git a/lib/mapping.gi b/lib/mapping.gi index 26b3d63855..6e41400c03 100644 --- a/lib/mapping.gi +++ b/lib/mapping.gi @@ -268,7 +268,7 @@ InstallGlobalFunction( PreImage, function ( arg ) # preimage of a collection of elements under elif CollFamRangeEqFamElms( FamilyObj( map ), FamilyObj( img ) ) then if not IsSubset( Range( map ), img ) then - ErrorNoReturn( "the collection must be contained in ", + ErrorNoReturn( "the collection must be contained in ", "Range()" ); fi; diff --git a/lib/mapprep.gi b/lib/mapprep.gi index b118d11ff7..4c6ba52779 100644 --- a/lib/mapprep.gi +++ b/lib/mapprep.gi @@ -1836,7 +1836,7 @@ end ); ############################################################################# ## -#M PreImagesSetNC( , ) . . . . . . . . . for restricted mapping +#M PreImagesSetNC( , ) . . . . . . . . . . for restricted mapping ## InstallMethod( PreImagesSetNC, "for a restricted mapping, and a collection", diff --git a/tst/testinstall/fldabnum.tst b/tst/testinstall/fldabnum.tst index 0643fbf338..b2d276c965 100644 --- a/tst/testinstall/fldabnum.tst +++ b/tst/testinstall/fldabnum.tst @@ -288,7 +288,7 @@ gap> ImagesRepresentative( aut, E(45) ); E(45)^2 gap> PreImageElm( aut, E(45) ); -E(45)^8-E(45)^38 -gap> Print(PreImagesSet( aut, Conjugates( f, E(45) ) ),"\n"); +gap> Print(PreImagesSetNC( aut, Conjugates( f, E(45) ) ),"\n"); [ -E(45)-E(45)^16, -E(45)^2-E(45)^17, -E(45)^7-E(45)^37, -E(45)^8-E(45)^38, -E(45)^11-E(45)^26, -E(45)^19-E(45)^34, -E(45)^28-E(45)^43, -E(45)^29-E(45)^44, E(45)^44, E(45)^43, E(45)^38, E(45)^37, E(45)^34, diff --git a/tst/testinstall/mapping.tst b/tst/testinstall/mapping.tst index c3e6a2cf84..514f932f47 100644 --- a/tst/testinstall/mapping.tst +++ b/tst/testinstall/mapping.tst @@ -251,9 +251,9 @@ gap> PreImageElm( map, Z(3) ); Z(3)^0 gap> PreImagesElm( map, Z(3) ); [ Z(3)^0 ] -gap> PreImagesSet( map, [ 0*Z(3), Z(3) ] ); +gap> PreImagesSetNC( map, [ 0*Z(3), Z(3) ] ); [ 0*Z(3), Z(3)^0 ] -gap> PreImagesSet( map, GF(3) ); +gap> PreImagesSetNC( map, GF(3) ); [ 0*Z(3), Z(3)^0 ] gap> PreImagesRepresentativeNC( map, Z(3) ); Z(3)^0 @@ -306,9 +306,9 @@ gap> PreImageElm( map, Z(3) ); 0*Z(3) gap> PreImagesElm( map, Z(3) ); [ 0*Z(3) ] -gap> PreImagesSet( map, [ 0*Z(3), Z(3) ] ); +gap> PreImagesSetNC( map, [ 0*Z(3), Z(3) ] ); [ 0*Z(3), Z(3)^0 ] -gap> PreImagesSet( map, GF(3) ); +gap> PreImagesSetNC( map, GF(3) ); [ 0*Z(3), Z(3)^0, Z(3) ] gap> PreImagesRepresentativeNC( map, Z(3) ); 0*Z(3) From de60e9b4ebee1a867500829eddeff7e40546ca1a Mon Sep 17 00:00:00 2001 From: Chris Wensley Date: Thu, 6 Oct 2022 16:51:10 +0100 Subject: [PATCH 010/234] PreImagesElm renamed PreImagesElmNC --- lib/alghom.gi | 4 ++-- lib/field.gi | 4 ++-- lib/ghomperm.gi | 2 +- lib/grpnice.gd | 10 +++++----- lib/liefam.gi | 2 +- lib/mapphomo.gi | 22 +++++++++++----------- lib/mapping.gi | 2 +- lib/mapprep.gi | 2 +- lib/oprt.gi | 4 ++-- lib/relation.gi | 8 ++++---- tst/testinstall/mapping.tst | 4 ++-- 11 files changed, 32 insertions(+), 32 deletions(-) diff --git a/lib/alghom.gi b/lib/alghom.gi index 9224131a56..2206697003 100644 --- a/lib/alghom.gi +++ b/lib/alghom.gi @@ -928,7 +928,7 @@ BindGlobal( "PreImagesRepresentativeOperationAlgebraHomomorphism", function( oph return mat; end ); -InstallMethod( PreImagesRepresentative, +InstallMethod( PreImagesRepresentativeNC, "for an operation algebra homomorphism, and an element", FamRangeEqFamElm, [ IsOperationAlgebraHomomorphismDefaultRep, IsMatrix ], @@ -1090,7 +1090,7 @@ InstallMethod( ImagesRepresentative, ############################################################################# ## -#M PreImagesRepresentative( , ) +#M PreImagesRepresentativeNC( , ) ## InstallMethod( PreImagesRepresentativeNC, "for an alg. hom. from f. p. algebra, and an element", diff --git a/lib/field.gi b/lib/field.gi index 391acb836d..daa0ffb42f 100644 --- a/lib/field.gi +++ b/lib/field.gi @@ -1316,9 +1316,9 @@ InstallMethod( ImagesSet, ############################################################################# ## -#M PreImagesElm( , ) . . . . . . . . . . . . preimage of an elm +#M PreImagesElmNC( , ) . . . . . . . . . . . preimage of an elm ## -InstallMethod( PreImagesElm, +InstallMethod( PreImagesElmNC, "for field homomorphism and element", FamRangeEqFamElm, [ IsFieldHomomorphism, IsObject ], diff --git a/lib/ghomperm.gi b/lib/ghomperm.gi index 7bd32db043..b8ea762715 100644 --- a/lib/ghomperm.gi +++ b/lib/ghomperm.gi @@ -22,7 +22,7 @@ local genpreimages, pre,kg,sz,ol,orb,pos,dom,one; genpreimages:=GeneratorsOfMagmaWithInverses( elms ); genpreimages:= List(genpreimages, - gen -> PreImagesRepresentative( map, gen ) ); + gen -> PreImagesRepresentativeNC( map, gen ) ); if fail in genpreimages then TryNextMethod(); fi; diff --git a/lib/grpnice.gd b/lib/grpnice.gd index 18ec4439eb..50986e5a79 100644 --- a/lib/grpnice.gd +++ b/lib/grpnice.gd @@ -398,7 +398,7 @@ BindGlobal( "AttributeMethodByNiceMonomorphismCollElm", function( oper, par ) img := ImagesRepresentative( nice, obj2 : actioncanfail:= true ); if img = fail or not ( img in ImagesSource( nice ) and - PreImagesRepresentative( nice, img ) = obj2 ) then + PreImagesRepresentativeNC( nice, img ) = obj2 ) then TryNextMethod(); fi; return oper( NiceObject( obj1 ), img ); @@ -441,7 +441,7 @@ BindGlobal( "AttributeMethodByNiceMonomorphismElmColl", img := ImagesRepresentative( nice, obj1 : actioncanfail:= true ); if img = fail or not (img in ImagesSource( nice ) and - PreImagesRepresentative( nice, img ) = obj1) then + PreImagesRepresentativeNC( nice, img ) = obj1) then TryNextMethod(); fi; return oper( img, NiceObject( obj2 ) ); @@ -525,7 +525,7 @@ BindGlobal( "GroupMethodByNiceMonomorphismCollElm", img := ImagesRepresentative( nice, obj2 : actioncanfail:= true ); if img = fail or not (img in ImagesSource( nice ) and - PreImagesRepresentative( nice, img ) = obj2) then + PreImagesRepresentativeNC( nice, img ) = obj2) then TryNextMethod(); fi; img1 := oper( NiceObject( obj1 ), img ); @@ -637,7 +637,7 @@ BindGlobal( "SubgroupMethodByNiceMonomorphismCollElm", function( oper, par ) img := ImagesRepresentative( nice, obj2 : actioncanfail:= true ); if img = fail or not ( img in ImagesSource( nice ) and - PreImagesRepresentative (nice , img ) = obj2 ) then + PreImagesRepresentativeNC(nice , img ) = obj2 ) then TryNextMethod(); fi; img1 := oper( NiceObject( obj1 ), img ); @@ -764,7 +764,7 @@ BindGlobal( "GroupSeriesMethodByNiceMonomorphismCollElm", img := ImagesRepresentative( nice, obj2 : actioncanfail:= true ); if img = fail or not ( img in ImagesSource( nice ) and - PreImagesRepresentative( nice, img ) = obj2 ) then + PreImagesRepresentativeNC( nice, img ) = obj2 ) then TryNextMethod(); fi; list := ShallowCopy( oper( NiceObject( obj1 ), img ) ); diff --git a/lib/liefam.gi b/lib/liefam.gi index 95b0d34948..54dc6bccb2 100644 --- a/lib/liefam.gi +++ b/lib/liefam.gi @@ -442,7 +442,7 @@ InstallMethod( ImagesElm, return [ LieObject( elm ) ]; end ); -InstallMethod( PreImagesElm, +InstallMethod( PreImagesElmNC, "for Lie embedding and Lie object in default representation", FamRangeEqFamElm, [ IsGeneralMapping and IsLieEmbeddingRep, diff --git a/lib/mapphomo.gi b/lib/mapphomo.gi index 42498afe7a..49e8666f05 100644 --- a/lib/mapphomo.gi +++ b/lib/mapphomo.gi @@ -330,9 +330,9 @@ InstallMethod( ImagesSet, ############################################################################# ## -#M PreImagesElm( , ) . for s.p. gen. mapping resp. mult. & inv. +#M PreImagesElmNC( , ) . for s.p. gen. mapping resp. mult. & inv. ## -InstallMethod( PreImagesElm, +InstallMethod( PreImagesElmNC, "method for s.p. general mapping respecting mult. & inv., and element", FamRangeEqFamElm, [ IsSPGeneralMapping and RespectsMultiplication and RespectsInverses, @@ -340,7 +340,7 @@ InstallMethod( PreImagesElm, function( map, elm ) local pre; - pre:= PreImagesRepresentative( map, elm ); + pre:= PreImagesRepresentativeNC( map, elm ); if pre = fail then return []; else @@ -367,7 +367,7 @@ InstallMethod( PreImagesSetNC, fi; genpreimages:= List(genpreimages, - gen -> PreImagesRepresentative( map, gen ) ); + gen -> PreImagesRepresentativeNC( map, gen ) ); if fail in genpreimages then TryNextMethod(); fi; @@ -684,9 +684,9 @@ InstallMethod( ImagesSet, ############################################################################# ## -#M PreImagesElm( , ) for s.p. gen. mapping resp. add. & add.inv. +#M PreImagesElmNC( , ) for s.p. gen. mapping resp. add. & add.inv. ## -InstallMethod( PreImagesElm, +InstallMethod( PreImagesElmNC, "method for s.p. gen. mapping respecting add. & add.inv., and element", FamRangeEqFamElm, [ IsSPGeneralMapping and RespectsAddition and RespectsAdditiveInverses, @@ -694,7 +694,7 @@ InstallMethod( PreImagesElm, function( map, elm ) local pre; - pre:= PreImagesRepresentative( map, elm ); + pre:= PreImagesRepresentativeNC( map, elm ); if pre = fail then return []; else @@ -715,7 +715,7 @@ InstallMethod( PreImagesSetNC, function( map, elms ) local genpreimages; genpreimages:= List( GeneratorsOfAdditiveGroup( elms ), - gen -> PreImagesRepresentative( map, gen ) ); + gen -> PreImagesRepresentativeNC( map, gen ) ); if fail in genpreimages then TryNextMethod(); fi; @@ -901,7 +901,7 @@ InstallMethod( PreImagesSetNC, function( map, elms ) local genpreimages; genpreimages:= List( GeneratorsOfLeftModule( elms ), - gen -> PreImagesRepresentative( map, gen ) ); + gen -> PreImagesRepresentativeNC( map, gen ) ); if fail in genpreimages then TryNextMethod(); fi; @@ -995,7 +995,7 @@ InstallMethod( PreImagesSetNC, function( map, elms ) local genpreimages; genpreimages:= List( GeneratorsOfLeftOperatorRing( elms ), - gen -> PreImagesRepresentative( map, gen ) ); + gen -> PreImagesRepresentativeNC( map, gen ) ); if fail in genpreimages then TryNextMethod(); fi; @@ -1022,7 +1022,7 @@ InstallMethod( PreImagesSetNC, function( map, elms ) local genpreimages; genpreimages:= List( GeneratorsOfLeftOperatorRingWithOne( elms ), - gen -> PreImagesRepresentative( map, gen ) ); + gen -> PreImagesRepresentativeNC( map, gen ) ); if fail in genpreimages then TryNextMethod(); fi; diff --git a/lib/mapping.gi b/lib/mapping.gi index 6e41400c03..26b3d63855 100644 --- a/lib/mapping.gi +++ b/lib/mapping.gi @@ -268,7 +268,7 @@ InstallGlobalFunction( PreImage, function ( arg ) # preimage of a collection of elements under elif CollFamRangeEqFamElms( FamilyObj( map ), FamilyObj( img ) ) then if not IsSubset( Range( map ), img ) then - ErrorNoReturn( "the collection must be contained in ", + ErrorNoReturn( "the collection must be contained in ", "Range()" ); fi; diff --git a/lib/mapprep.gi b/lib/mapprep.gi index 4c6ba52779..6b0cdd3444 100644 --- a/lib/mapprep.gi +++ b/lib/mapprep.gi @@ -1817,7 +1817,7 @@ end ); ############################################################################# ## -#M PreImagesElmNC( , ) . . . . . . . . . for restricted mapping +#M PreImagesElmNC( , ) . . . . . . . . . . for restricted mapping ## InstallMethod( PreImagesElmNC, "for a restricted mapping, and an element", diff --git a/lib/oprt.gi b/lib/oprt.gi index f79b2c3152..ab12a94889 100644 --- a/lib/oprt.gi +++ b/lib/oprt.gi @@ -3389,7 +3389,7 @@ function( hom, elm ) TryNextMethod(); fi; - # PreImagesRepresentative does not test membership + # PreImagesRepresentativeNC does not test membership #if not elm in Image( hom ) then return fail; fi; xset:=UnderlyingExternalSet(hom); V := HomeEnumerator(xset); @@ -3431,7 +3431,7 @@ function( hom, elm ) TryNextMethod(); fi; - # PreImagesRepresentative does not test membership + # PreImagesRepresentativeNC does not test membership #if not elm in Image( hom ) then return fail; fi; xset:=UnderlyingExternalSet(hom); V := HomeEnumerator(xset); diff --git a/lib/relation.gi b/lib/relation.gi index cc63d50d03..b1aacf486a 100644 --- a/lib/relation.gi +++ b/lib/relation.gi @@ -605,12 +605,12 @@ InstallMethod(HasseDiagramBinaryRelation, ## return the minimal elements of a list under rel HDBRMinElts := function(list, rel) - - ## x minimal if - ## {y in list | y<>x and y in PreImagesElm( rel,x)} is empty + + ## x minimal if + ## {y in list | y<>x and y in PreImagesElmNC(rel,x)} is empty ## return Filtered(list, - x->IsEmpty(Filtered(list, y-> (y <> x) and + x->IsEmpty(Filtered(list, y-> (y <> x) and (y in PreImagesElmNC(rel,x))))); end; diff --git a/tst/testinstall/mapping.tst b/tst/testinstall/mapping.tst index 514f932f47..66b0d3ef40 100644 --- a/tst/testinstall/mapping.tst +++ b/tst/testinstall/mapping.tst @@ -249,7 +249,7 @@ gap> IsTotal( map ); false gap> PreImageElm( map, Z(3) ); Z(3)^0 -gap> PreImagesElm( map, Z(3) ); +gap> PreImagesElmNC( map, Z(3) ); [ Z(3)^0 ] gap> PreImagesSetNC( map, [ 0*Z(3), Z(3) ] ); [ 0*Z(3), Z(3)^0 ] @@ -304,7 +304,7 @@ gap> IsTotal( map ); true gap> PreImageElm( map, Z(3) ); 0*Z(3) -gap> PreImagesElm( map, Z(3) ); +gap> PreImagesElmNC( map, Z(3) ); [ 0*Z(3) ] gap> PreImagesSetNC( map, [ 0*Z(3), Z(3) ] ); [ 0*Z(3), Z(3)^0 ] From 76df9a4a4272ecb33c95d17d89500f41edafa73b Mon Sep 17 00:00:00 2001 From: Chris Wensley Date: Thu, 27 Oct 2022 17:20:57 +0100 Subject: [PATCH 011/234] no mention of NC version in the tutorial manual --- doc/tut/algvspc.xml | 8 ++++---- doc/tut/group.xml | 23 +++++++++++------------ 2 files changed, 15 insertions(+), 16 deletions(-) diff --git a/doc/tut/algvspc.xml b/doc/tut/algvspc.xml index 264db61955..bbc1da8b3f 100644 --- a/doc/tut/algvspc.xml +++ b/doc/tut/algvspc.xml @@ -207,7 +207,7 @@ gap> h:= NaturalHomomorphismBySubspace( V, W ); ( Rationals^2 )> gap> Image( h, [ 1, 2, 3, 4 ] ); [ 0, 0 ] -gap> PreImagesRepresentativeNC( h, [ 1, 0 ] ); +gap> PreImagesRepresentative( h, [ 1, 0 ] ); [ 1, 0, 0, 0 ] ]]> @@ -470,11 +470,11 @@ gap> AmodR:= ImagesSource( h ); gap> id:= CentralIdempotentsOfAlgebra( AmodR ); [ v.3, v.2+(-3)*v.3, v.1+(-2)*v.2+(3)*v.3 ] -gap> PreImagesRepresentativeNC( h, id[1] ); +gap> PreImagesRepresentative( h, id[1] ); [ [ 0, 0, 0 ], [ 0, 0, 0 ], [ 0, 0, 1 ] ] -gap> PreImagesRepresentativeNC( h, id[2] ); +gap> PreImagesRepresentative( h, id[2] ); [ [ 0, 0, 0 ], [ 0, 1, 0 ], [ 0, 0, 0 ] ] -gap> PreImagesRepresentativeNC( h, id[3] ); +gap> PreImagesRepresentative( h, id[3] ); [ [ 1, 0, 0 ], [ 0, 0, 0 ], [ 0, 0, 0 ] ] ]]>

diff --git a/doc/tut/group.xml b/doc/tut/group.xml index 9bd202d4cb..0eda9362fe 100644 --- a/doc/tut/group.xml +++ b/doc/tut/group.xml @@ -168,10 +168,9 @@ action domain of norm. (It only happens that both are subsets of the natural numbers.) We can now form images and preimages under the natural homomorphism. The set of preimages of an element under hom is a coset modulo elab. -We use one of the functions -or here because hom is not -a bijection, so an element of the range can have several preimages or -none at all. +We use the function here +because hom is not a bijection, +so an element of the range can have several preimages or none at all.

ker:= Kernel( hom ); @@ -179,7 +178,7 @@ Group([ (1,2)(3,4)(5,6)(7,8), (1,3)(2,4)(5,7)(6,8), (1,5)(2,6)(3,7) (4,8) ]) gap> x := (1,8,3,5,7,6,2);; Image( hom, x ); (1,7,5,6,2,3,4) -gap> coset := PreImagesNC( hom, last ); +gap> coset := PreImages( hom, last ); RightCoset(Group([ (1,2)(3,4)(5,6)(7,8), (1,3)(2,4)(5,7)(6,8), (1,5) (2,6)(3,7)(4,8) ]),(2,8,6,7,3,4,5)) ]]> @@ -380,7 +379,7 @@ gap> ophom := ActionHomomorphism( a8, op );; gap> ophom2 := ActionHomomorphism( op, op2 );; gap> composition := ophom * ophom2;; gap> stab := Stabilizer( op2, 2 );; -gap> preim := PreImagesNC( composition, stab ); +gap> preim := PreImages( composition, stab ); Group([ (1,2,4), (6,7,8), (3,6,8), (5,8,6), (1,2)(3,8) ]) ]]>

@@ -676,7 +675,7 @@ Because we want to operate on the sets we have to pass gap> u8_56 := Stabilizer( a8_56, blocks[1], OnSets );; gap> Index( a8_56, u8_56 ); 8 -gap> u8b := PreImagesNC( h56, u8_56 );; Index( a8, u8b ); +gap> u8b := PreImages( h56, u8_56 );; Index( a8, u8b ); 8 gap> IsConjugate( a8, u8, u8b ); true @@ -703,7 +702,7 @@ third subgroup. gap> seed:=First(AllBlocks(a8_56),x->Length(x)=2);; gap> blocks := Blocks( a8_56, [1..56], seed);; gap> u28_56 := Stabilizer( a8_56, seed, OnSets );; -gap> u28 := PreImagesNC( h56, u28_56 );; +gap> u28 := PreImages( h56, u28_56 );; gap> Index( a8, u28 ); 28 ]]> @@ -936,7 +935,7 @@ brk> quit; ]]>

PreImagesRepresentativeNC( hom, (1,2,3) ); +gap> PreImagesRepresentative( hom, (1,2,3) ); (1,4,2) gap> PreImage( hom, TrivialSubgroup(s3) ); # the kernel Group([ (1,4)(2,3), (1,3)(2,4) ]) @@ -948,9 +947,9 @@ Images of elements and subgroups under hom can be calculated with the function . But since the mapping hom is not bijective, we cannot use the function for preimages of elements -(they can have several preimages). Instead, we have to use one of +(they can have several preimages). +Instead, we have to use -or which returns one preimage if at least one exists (and would return fail if none exists, which cannot occur for our surjective hom). @@ -1129,7 +1128,7 @@ Section ). gap> pcls := ConjugacyClasses( p );; gcls := [ ];; gap> for pc in pcls do > gc:=ConjugacyClass(grp, -> PreImagesRepresentativeNC(hom,Representative(pc))); +> PreImagesRepresentative(hom,Representative(pc))); > SetStabilizerOfExternalSet(gc,PreImage(hom, > StabilizerOfExternalSet(pc))); > Add( gcls, gc ); From 1ef1bb061d47015e20370ef73a2a3572fa3fc075 Mon Sep 17 00:00:00 2001 From: cdwensley Date: Sun, 24 Sep 2023 09:15:24 +0100 Subject: [PATCH 012/234] attempting to elininate conflict in grp.gi --- lib/grp.gi | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/grp.gi b/lib/grp.gi index b95e03839c..8dd381e83c 100644 --- a/lib/grp.gi +++ b/lib/grp.gi @@ -10,7 +10,7 @@ ## ## This file contains generic methods for groups. ## - +## (24/09/23) attempting to resolve conflicts (CDW) ############################################################################# ## @@ -515,12 +515,12 @@ local p, hom, reps, as, a, b, ap, bp, ab, ap_bp, ab_p, g, h, H, N; reps := ConjugacyClasses(Image(hom)); reps := List(reps, Representative); reps := Filtered(reps, g -> not IsOne(g)); - reps := List(reps, g -> PreImagesRepresentative(hom, g)); + reps := List(reps, g -> PreImagesRepresentativeNC(hom, g)); as := List(reps, a -> [a,a^p]); for b in Image(hom) do - b := PreImagesRepresentative(hom, b); + b := PreImagesRepresentativeNC(hom, b); bp := b^p; for a in as do ap := a[2]; a := a[1]; @@ -5331,7 +5331,7 @@ InstallMethod (MinimalNormalSubgroups, function( grp ) local hom; hom := NiceMonomorphism (grp); - return List (MinimalNormalSubgroups (NiceObject (grp)), + return List (MinimalNormalSubgroups (NiceObject (grp)), N -> PreImagesSetNC(hom, N)); end); From c3b0bcd39ccac9de73bb1062eec09a17a8c98f06 Mon Sep 17 00:00:00 2001 From: cdwensley Date: Mon, 20 Nov 2023 10:18:38 +0000 Subject: [PATCH 013/234] hopefully fixed tst/testextra/makeperfect.g --- tst/testextra/makeperfect.g | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tst/testextra/makeperfect.g b/tst/testextra/makeperfect.g index b7ed22e898..fd68a1560c 100644 --- a/tst/testextra/makeperfect.g +++ b/tst/testextra/makeperfect.g @@ -244,8 +244,8 @@ local respp,cf,m,mpos,coh,fgens,comp,reps,v,new,isok,pema,pf,gens,nt,quot, List(GeneratorsOfGroup(new),x->ImagesRepresentative(pema,x)), Concatenation( List(GeneratorsOfGroup(Range(coh.fphom)), - x->PreImagesRepresentativeNC(coh.fphom,x)), - ListWithIdenticalEntries(coh.module.dimension, + x->PreImagesRepresentative(coh.fphom,x)), + ListWithIdenticalEntries(coh.module.dimension, One(coh.group)) )); qk:=KernelOfMultiplicativeGeneralMapping(quot); From 97eb4652b997512d74e9ae121d4e21d07abe8258 Mon Sep 17 00:00:00 2001 From: cdwensley Date: Thu, 23 Nov 2023 20:29:40 +0000 Subject: [PATCH 014/234] attempting to resolve conflicts in /lib files --- lib/alglie.gi | 22 +- lib/autsr.gi | 232 +++++----- lib/clashom.gi | 1097 ++++++++++++++++++++++++----------------------- lib/fitfree.gi | 12 +- lib/ghompcgs.gi | 2 +- lib/gpfpiso.gi | 57 +-- lib/gprd.gi | 16 +- lib/grp.gi | 5 +- lib/grpcompl.gi | 7 +- lib/grpfp.gi | 28 +- lib/grplatt.gi | 2 +- lib/grpnice.gi | 4 +- lib/grppcext.gi | 28 +- lib/grppclat.gi | 8 +- lib/mapprep.gi | 6 +- lib/maxsub.gi | 10 +- lib/morpheus.gi | 36 +- lib/norad.gi | 88 ++-- lib/onecohom.gi | 9 +- lib/oprt.gi | 2 +- lib/relation.gi | 10 +- lib/schur.gi | 41 +- 22 files changed, 861 insertions(+), 861 deletions(-) diff --git a/lib/alglie.gi b/lib/alglie.gi index ac6d794f0f..2f0ba0ed43 100644 --- a/lib/alglie.gi +++ b/lib/alglie.gi @@ -2099,9 +2099,9 @@ InstallMethod( DirectSumDecomposition, SetCentre( Q, Q ); SetRadicalOfAlgebra( Q, Subalgebra( Q, [ Zero( Q ) ] ) ); - id:= List( CentralIdempotentsOfAlgebra( Q ), + id:= List( CentralIdempotentsOfAlgebra( Q ), x->PreImagesRepresentativeNC(hom,x)); - + # Now we lift the idempotents to the big algebra `A'. The # first idempotent is lifted as follows: # We have that `id[1]^2-id[1]' is an element of `Rad'. @@ -5604,7 +5604,7 @@ InstallMethod( JenningsLieAlgebra, T:= EmptySCTable( dim , Zero(F) , "antisymmetric" ); pimgs := []; for i in [1..dim] do - a:= PreImagesRepresentativeNC( Homs[pos[i]] , + a:= PreImagesRepresentativeNC( Homs[pos[i]] , PreImagesRepresentativeNC( hom_pcg[pos[i]], gens[i] ) ); # calculate the p-th power image of `a': @@ -5622,10 +5622,10 @@ InstallMethod( JenningsLieAlgebra, # Calculate the commutator [a,b], and map the result into # the correct homogeneous component. - b:= PreImagesRepresentativeNC( Homs[pos[j]], + b:= PreImagesRepresentativeNC( Homs[pos[j]], PreImagesRepresentativeNC( hom_pcg[pos[j]], gens[j] )); - c:= Image( hom_pcg[pos[i] + pos[j]], - Image(Homs[pos[i] + pos[j]], a^-1*b^-1*a*b) ); + c:= Image( hom_pcg[pos[i] + pos[j]], + Image(Homs[pos[i] + pos[j]], a^-1*b^-1*a*b) ); e:= ExtRepOfObj(c); co:=[]; for k in [1,3..Length(e)-1] do @@ -5800,7 +5800,7 @@ InstallMethod( PCentralLieAlgebra, T:= EmptySCTable( dim , Zero(F) , "antisymmetric" ); pimgs := []; for i in [1..dim] do - a:= PreImagesRepresentativeNC( Homs[pos[i]] , + a:= PreImagesRepresentativeNC( Homs[pos[i]] , PreImagesRepresentativeNC( hom_pcg[pos[i]], gens[i] ) ); @@ -5819,10 +5819,10 @@ InstallMethod( PCentralLieAlgebra, # Calculate the commutator [a,b], and map the result into # the correct homogeneous component. - b:= PreImagesRepresentativeNC( Homs[pos[j]], - PreImagesRepresentativeNC( hom_pcg[pos[j]], gens[j] )); - c:= Image( hom_pcg[pos[i] + pos[j]], - Image(Homs[pos[i] + pos[j]], a^-1*b^-1*a*b) ); + b:= PreImagesRepresentativeNC( Homs[pos[j]], + PreImagesRepresentativeNC( hom_pcg[pos[j]], gens[j] )); + c:= Image( hom_pcg[pos[i] + pos[j]], + Image(Homs[pos[i] + pos[j]], a^-1*b^-1*a*b) ); e:= ExtRepOfObj(c); co:=[]; for k in [1,3..Length(e)-1] do diff --git a/lib/autsr.gi b/lib/autsr.gi index 705e1daca8..704f9093dc 100644 --- a/lib/autsr.gi +++ b/lib/autsr.gi @@ -141,7 +141,7 @@ local ocr,fphom,fpg,free,len,dim,tmp,L0,R,rels,mat,r,RS,i,g,v,cnt; fpg:=FreeGeneratorsOfFpGroup(Range(fphom)); ocr.factorpres:=[fpg,RelatorsOfFpGroup(Range(fphom))]; ocr.generators:=List(GeneratorsOfGroup(Range(fphom)), - i->PreImagesRepresentativeNC(fphom,i)); + i->PreImagesRepresentativeNC(fphom,i)); OCAddMatrices(ocr,ocr.generators); OCAddRelations(ocr,ocr.generators); OCAddSumMatrices(ocr,ocr.generators); @@ -487,7 +487,7 @@ local S,c,hom,q,a,b,i,t,have,ups,new,u,good,abort,clim,worked,pp, cnt:=0; for b in t do new:=PreImagesRepresentativeNC(hom,b); - if (pp=false or new^pp in S) and locond(new) then + if (pp=false or new^pp in S) and locond(new) then S:=ClosureGroup(S,new); have:=true; cnt:=cnt+1; @@ -1024,39 +1024,31 @@ local ff,r,d,ser,u,v,i,j,k,p,bd,e,gens,lhom,M,N,hom,Q,Mim,q,ocr,split,MPcgs, ocr:=OneCocycles(Q,Mim); split:=ocr.isSplitExtension; if not split then - # test: Semisimple and Frattini - b:=MTX.BasisRadical(mo); - fratsim:=Length(b)=0; - if not fratsim then - b:=List(b,x->PreImagesRepresentativeNC(hom,PcElementByExponents(MPcgs,x))); - for j in b do - N:=ClosureSubgroup(N,b); - od; - # insert - for j in [Length(ser),Length(ser)-1..i+1] do - ser[j+1]:=ser[j]; - od; - ser[i+1]:=N; - Info(InfoMorph,2,"insert1"); - else - # Frattini? - fratsim:=IsSubset(FrattiniSubgroup(Q),Mim); - if not fratsim then - N:=Intersection(FrattiniSubgroup(Q),Mim); - # insert - for j in [Length(ser),Length(ser)-1..i+1] do - ser[j+1]:=ser[j]; - od; - ser[i+1]:=PreImage(hom,N); - Info(InfoMorph,2,"insert2"); - fi; - N:=ser[i+1]; # the added normal - if rada<>fail - and ForAny(GeneratorsOfGroup(rada),x->N<>Image(x,N)) then - Info(InfoMorph,3,"radical automorphism stabilizer"); - SetIsGroupOfAutomorphismsFiniteGroup(rada,true); - NiceMonomorphism(rada:autactbase:=fail,someCharacteristics:=fail); - rada:=Stabilizer(rada,N,asAutom); + # test: Semisimple and Frattini + b:=MTX.BasisRadical(mo); + fratsim:=Length(b)=0; + if not fratsim then + b:=List(b,x->PreImagesRepresentativeNC(hom,PcElementByExponents(MPcgs,x))); + for j in b do + N:=ClosureSubgroup(N,b); + od; + # insert in series + for j in [Length(ser),Length(ser)-1..i+1] do + ser[j+1]:=ser[j]; + od; + ser[i+1]:=N; + Info(InfoMorph,2,"insert1"); + else + # Frattini? + fratsim:=IsSubset(FrattiniSubgroup(Q),Mim); + if not fratsim then + N:=Intersection(FrattiniSubgroup(Q),Mim); + # insert + for j in [Length(ser),Length(ser)-1..i+1] do + ser[j+1]:=ser[j]; + od; + ser[i+1]:=PreImage(hom,N); + Info(InfoMorph,2,"insert2"); fi; N:=ser[i+1]; # the added normal fi; @@ -1135,11 +1127,11 @@ local ff,r,d,ser,u,v,i,j,k,p,bd,e,gens,lhom,M,N,hom,Q,Mim,q,ocr,split,MPcgs, cond:=function(perm) local aut,newgens,mo2,iso,a; if perm in Aperm then - return true; - fi; + return true; + fi; aut:=PreImagesRepresentativeNC(AQiso,perm); - newgens:=List(gens,x->PreImagesRepresentativeNC(comiso, - ImagesRepresentative(aut,ImagesRepresentative(comiso,x)))); + newgens:=List(gens,x->PreImagesRepresentativeNC(comiso, + ImagesRepresentative(aut,ImagesRepresentative(comiso,x)))); mo2:=GModuleByMats(LinearActionLayer(newgens,MPcgs),mo.field); iso:=MTX.IsomorphismModules(mo,mo2); @@ -1169,11 +1161,11 @@ local ff,r,d,ser,u,v,i,j,k,p,bd,e,gens,lhom,M,N,hom,Q,Mim,q,ocr,split,MPcgs, precond:=function(perm) local aut,newgens,mo2; if perm in Aperm then - return true; - fi; + return true; + fi; aut:=PreImagesRepresentativeNC(AQiso,perm); - newgens:=List(GeneratorsOfGroup(Q), - x->PreImagesRepresentativeNC(q,Image(aut,ImagesRepresentative(q,x)))); + newgens:=List(GeneratorsOfGroup(Q), + x->PreImagesRepresentativeNC(q,Image(aut,ImagesRepresentative(q,x)))); mo2:=GModuleByMats(LinearActionLayer(newgens,MPcgs),mo.field); return MTX.IsomorphismModules(mo,mo2)<>fail; end; @@ -1181,11 +1173,11 @@ local ff,r,d,ser,u,v,i,j,k,p,bd,e,gens,lhom,M,N,hom,Q,Mim,q,ocr,split,MPcgs, cond:=function(perm) local aut,newgens,mo2,iso,a; if perm in Aperm then - return true; - fi; + return true; + fi; aut:=PreImagesRepresentativeNC(AQiso,perm); - newgens:=List(GeneratorsOfGroup(Q), - x->PreImagesRepresentativeNC(q,Image(aut,ImagesRepresentative(q,x)))); + newgens:=List(GeneratorsOfGroup(Q), + x->PreImagesRepresentativeNC(q,Image(aut,ImagesRepresentative(q,x)))); mo2:=GModuleByMats(LinearActionLayer(newgens,MPcgs),mo.field); iso:=MTX.IsomorphismModules(mo,mo2); if iso=fail then @@ -1373,10 +1365,10 @@ local ff,r,d,ser,u,v,i,j,k,p,bd,e,gens,lhom,M,N,hom,Q,Mim,q,ocr,split,MPcgs, for j in GeneratorsOfGroup(rada) do k:=GroupHomomorphismByImagesNC(rf,rf, GeneratorsOfGroup(rf), - List(GeneratorsOfGroup(rf), - y->ImagesRepresentative(hom,ImagesRepresentative(j, - PreImagesRepresentativeNC(hom,y))))); - Assert(2,IsBijective(k)); + List(GeneratorsOfGroup(rf), + y->ImagesRepresentative(hom,ImagesRepresentative(j, + PreImagesRepresentativeNC(hom,y))))); + Assert(2,IsBijective(k)); Add(ind,k); od; @@ -1395,81 +1387,81 @@ local ff,r,d,ser,u,v,i,j,k,p,bd,e,gens,lhom,M,N,hom,Q,Mim,q,ocr,split,MPcgs, # reduce to subgroup that induces valid automorphisms Info(InfoMorph,1,"Radical autos reduce by factor ",Size(res)/Size(ind)); resperm:=IsomorphismPermGroup(C); - proj:=GroupHomomorphismByImagesNC(AQP,Image(resperm), - B[2],List(GeneratorsOfGroup(res),x->ImagesRepresentative(resperm,x))); - C:=PreImage(proj,Image(resperm,ind)); - C:=List(SmallGeneratingSet(C),x->PreImagesRepresentativeNC(AQiso,x)); - AQ:=Group(C); - SetIsFinite(AQ,true); - SetIsGroupOfAutomorphismsFiniteGroup(AQ,true); + proj:=GroupHomomorphismByImagesNC(AQP,Image(resperm), + B[2],List(GeneratorsOfGroup(res),x->ImagesRepresentative(resperm,x))); + C:=PreImage(proj,Image(resperm,ind)); + C:=List(SmallGeneratingSet(C),x->PreImagesRepresentativeNC(AQiso,x)); + AQ:=Group(C); + SetIsFinite(AQ,true); + SetIsGroupOfAutomorphismsFiniteGroup(AQ,true); makeaqiso(); fi; # # hook for using existing characteristics to reduce for next step if somechar<>fail then u:=Filtered(Unique(List(somechar,x->Image(hom,x))),x->Size(x)>1); - u:=Filtered(u,s->ForAny(GeneratorsOfGroup(AQ),h->Image(h,s)<>s)); - SortBy(u,Size); - Info(InfoMorph,1,"Forced characteristics ",List(u,Size)); - - if scharorb<>fail then - # these are subgroups for which certain orbits must be stabilized. - C:=List(Reversed(scharorb),x->List(x,y->Image(hom,y))); - C:=Filtered(C,x->Size(x[1])>1 and Size(x[1])Size(x[1]))); - Append(u,C); - fi; - - if Length(u)>0 then - C:=MappingGeneratorsImages(AQiso); - if C[2]<>GeneratorsOfGroup(AQP) then - C:=[List(GeneratorsOfGroup(AQP), - x->PreImagesRepresentativeNC(AQiso,x)), - GeneratorsOfGroup(AQP)]; - fi; - for j in u do - if IsList(j) then - # stabilizer set of subgroups - jorb:=ShallowCopy(Orbit(AQP,j[1],C[2],C[1],asAutom)); - jorpo:=[Position(jorb,j[1]),Position(jorb,j[2])]; - if jorpo[2]=fail then - Append(jorb,Orbit(AQP,j[1],C[2],C[1],asAutom)); - jorpo[2]:=Position(jorb,j[2]); - fi; - if Length(jorb)>Length(j) then - B:=ActionHomomorphism(AQP,jorb,C[2],C[1],asAutom); - substb:=Group(List(C[2],x->ImagesRepresentative(B,x)),()); - substb:=Stabilizer(substb,Set(jorpo),OnSets); - substb:=PreImage(B,substb); - Info(InfoMorph,2,"Stabilize characteristic orbit ",Size(j[1]), - " :",Size(AQP)/Size(substb) ); - else - substb:=AQP; - fi; - - - else - substb:=Stabilizer(AQP,j,C[2],C[1],asAutom); - Info(InfoMorph,2,"Stabilize characteristic subgroup ",Size(j), - " :",Size(AQP)/Size(substb) ); - fi; - if Size(substb)PreImagesRepresentativeNC(AQiso,x)),substb]; - fi; - - od; - AQ:=Group(C[1]); - SetIsFinite(AQ,true); - SetIsGroupOfAutomorphismsFiniteGroup(AQ,true); - SetSize(AQ,Size(AQP)); - #AQP:=Group(C[2]); # ensure small gen set - #SetSize(AQP,Size(AQ)); - makeaqiso(); - fi; + u:=Filtered(u,s->ForAny(GeneratorsOfGroup(AQ),h->Image(h,s)<>s)); + SortBy(u,Size); + Info(InfoMorph,1,"Forced characteristics ",List(u,Size)); + + if scharorb<>fail then + # these are subgroups for which certain orbits must be stabilized. + C:=List(Reversed(scharorb),x->List(x,y->Image(hom,y))); + C:=Filtered(C,x->Size(x[1])>1 and Size(x[1])Size(x[1]))); + Append(u,C); + fi; + + if Length(u)>0 then + C:=MappingGeneratorsImages(AQiso); + if C[2]<>GeneratorsOfGroup(AQP) then + C:=[List(GeneratorsOfGroup(AQP), + x->PreImagesRepresentativeNC(AQiso,x)), + GeneratorsOfGroup(AQP)]; + fi; + for j in u do + if IsList(j) then + # stabilizer set of subgroups + jorb:=ShallowCopy(Orbit(AQP,j[1],C[2],C[1],asAutom)); + jorpo:=[Position(jorb,j[1]),Position(jorb,j[2])]; + if jorpo[2]=fail then + Append(jorb,Orbit(AQP,j[1],C[2],C[1],asAutom)); + jorpo[2]:=Position(jorb,j[2]); + fi; + if Length(jorb)>Length(j) then + B:=ActionHomomorphism(AQP,jorb,C[2],C[1],asAutom); + substb:=Group(List(C[2],x->ImagesRepresentative(B,x)),()); + substb:=Stabilizer(substb,Set(jorpo),OnSets); + substb:=PreImage(B,substb); + Info(InfoMorph,2,"Stabilize characteristic orbit ",Size(j[1]), + " :",Size(AQP)/Size(substb) ); + else + substb:=AQP; + fi; + + + else + substb:=Stabilizer(AQP,j,C[2],C[1],asAutom); + Info(InfoMorph,2,"Stabilize characteristic subgroup ",Size(j), + " :",Size(AQP)/Size(substb) ); + fi; + if Size(substb)PreImagesRepresentativeNC(AQiso,x)),substb]; + fi; + + od; + AQ:=Group(C[1]); + SetIsFinite(AQ,true); + SetIsGroupOfAutomorphismsFiniteGroup(AQ,true); + SetSize(AQ,Size(AQP)); + #AQP:=Group(C[2]); # ensure small gen set + #SetSize(AQP,Size(AQ)); + makeaqiso(); + fi; fi; lastperm:=AQiso; diff --git a/lib/clashom.gi b/lib/clashom.gi index ad19193c75..1c4844545a 100644 --- a/lib/clashom.gi +++ b/lib/clashom.gi @@ -544,134 +544,134 @@ local clT, # classes T end; for j in [1..Length(reps)] do - scj:=Size(centralizers[j]); - dsz:=0; - centrhom:=ActionHomomorphism(centralizers_r[j],components[i], - "surjective"); - localcent_r:=Image(centrhom); - Info(InfoHomClass,4,i,":",j); - Info(InfoHomClass,3,"acting: ",Size(centralizers[j])," minimum ", - Int(Size(Image(projections[i]))/Size(centralizers[j])), - " orbits."); - # compute C(r)-classes - clTR:=[]; - for l in clT do - Info(InfoHomClass,4,"DC",Index(T,l[2])," ",Index(T,localcent_r)); - dc:=DoubleCosetRepsAndSizes(T,l[2],localcent_r); - clTR:=Concatenation(clTR,List(dc,i->l[1]^i[1])); - od; - - orb:=[]; - for p in [1..Length(clTR)] do - - repres:=PreImagesRepresentativeNC(projections[i],clTR[p]); - if i=1 or isdirprod - or reps[j]*RestrictedPermNC(repres,components[i]) - in Mproj[i] then - stab:=Centralizer(localcent_r,clTR[p]); - if Index(localcent_r,stab)clTR[p] then - genpos:=Position(img,clTR[p]); - img:=Permuted(img,(1,genpos)); - fi; - else - img:=ConjugacyClass(localcent_r,clTR[p],stab); - fi; - Add(orb,[repres,PreImage(centrhom,stab),img,localcent_r]); - fi; - od; - clTR:=orb; - - #was: - #clTR:=List(clTR,i->ConjugacyClass(localcent_r,i)); - #clTR:=List(clTR,j->[PreImagesRepresentative(projections[i], - # Representative(j)), - # PreImage(centrhom,Centralizer(j)), - # j]); - - # put small classes to the top (to be sure to hit them and make - # large local stabilizers) - SortBy(clTR,x->Size(x[3])); - - Info(InfoHomClass,3,Length(clTR)," local classes"); - - cystr:=[]; - for p in [1..Length(clTR)] do - repres:=Immutable(CycleStructurePerm(Representative(clTR[p][3]))); - select:=First(cystr,x->x[1]=repres); - if select=fail then - Add(cystr,[repres,[p]]); - else - AddSet(select[2],p); - fi; - od; - - cengen:=GeneratorsOfGroup(centralizers[j]); - if Length(cengen)>10 then - cengen:=SmallGeneratingSet(centralizers[j]); - fi; - #cengen:=Filtered(cengen,i->not i in localcent_r); - - while Length(clTR)>0 do - - # orbit algorithm on classes - stab:=clTR[1][2]; - orb:=[clTR[1]]; - #repres:=RestrictedPermNC(clTR[1][1],components[i]); - repres:=clTR[1][1]; - trans:=[One(M)]; - select:=[2..Length(clTR)]; - - orpo:=1; - minlen:=Size(orb[1][3]); - possible:=false; - stabtrue:=false; - pf:=infinity; - maxdiff:=Size(T); - again:=0; - trymap:=false; - ug:=[]; - # test whether we have full orbit and full stabilizer - while Size(centralizers[j])>(Sum(orb,i->Size(i[3]))*Size(stab)) do - genpos:=1; - while genpos<=Length(cengen) and - Size(centralizers[j])>(Sum(orb,i->Size(i[3]))*Size(stab)) do - gen:=cengen[genpos]; - skip:=false; - if trymap<>false then - orpo:=trymap[1]; - gen:=trymap[2]; - trymap:=false; - elif again>0 then - if not IsBound(ug[genpos]) then - ug[genpos]:=Intersection(centralizers_r[j], - ConjugateSubgroup(centralizers_r[j],gen^-1)); - fi; - if again<500 and ForAll(GeneratorsOfGroup(centralizers_r[j]), - i->i in ug[genpos]) - then - # the random elements will give us nothing new - skip:=true; - else - # get an element not in ug[genpos] - repeat - img:=Random(centralizers_r[j]); - until not img in ug[genpos] or again>=500; - gen:=img*gen; - fi; - fi; - - if not skip then - - img:=Image(projections[i],opfun(orb[orpo][1],gen)); - - smacla:=select; - - if not stabtrue then - p:=PositionProperty(orb,i->img in i[3]); - ppos:=fail; + scj:=Size(centralizers[j]); + dsz:=0; + centrhom:=ActionHomomorphism(centralizers_r[j],components[i], + "surjective"); + localcent_r:=Image(centrhom); + Info(InfoHomClass,4,i,":",j); + Info(InfoHomClass,3,"acting: ",Size(centralizers[j])," minimum ", + Int(Size(Image(projections[i]))/Size(centralizers[j])), + " orbits."); + # compute C(r)-classes + clTR:=[]; + for l in clT do + Info(InfoHomClass,4,"DC",Index(T,l[2])," ",Index(T,localcent_r)); + dc:=DoubleCosetRepsAndSizes(T,l[2],localcent_r); + clTR:=Concatenation(clTR,List(dc,i->l[1]^i[1])); + od; + + orb:=[]; + for p in [1..Length(clTR)] do + + repres:=PreImagesRepresentativeNC(projections[i],clTR[p]); + if i=1 or isdirprod + or reps[j]*RestrictedPermNC(repres,components[i]) + in Mproj[i] then + stab:=Centralizer(localcent_r,clTR[p]); + if Index(localcent_r,stab)clTR[p] then + genpos:=Position(img,clTR[p]); + img:=Permuted(img,(1,genpos)); + fi; + else + img:=ConjugacyClass(localcent_r,clTR[p],stab); + fi; + Add(orb,[repres,PreImage(centrhom,stab),img,localcent_r]); + fi; + od; + clTR:=orb; + + #was: + #clTR:=List(clTR,i->ConjugacyClass(localcent_r,i)); + #clTR:=List(clTR,j->[PreImagesRepresentative(projections[i], + # Representative(j)), + # PreImage(centrhom,Centralizer(j)), + # j]); + + # put small classes to the top (to be sure to hit them and make + # large local stabilizers) + SortBy(clTR,x->Size(x[3])); + + Info(InfoHomClass,3,Length(clTR)," local classes"); + + cystr:=[]; + for p in [1..Length(clTR)] do + repres:=Immutable(CycleStructurePerm(Representative(clTR[p][3]))); + select:=First(cystr,x->x[1]=repres); + if select=fail then + Add(cystr,[repres,[p]]); + else + AddSet(select[2],p); + fi; + od; + + cengen:=GeneratorsOfGroup(centralizers[j]); + if Length(cengen)>10 then + cengen:=SmallGeneratingSet(centralizers[j]); + fi; + #cengen:=Filtered(cengen,i->not i in localcent_r); + + while Length(clTR)>0 do + + # orbit algorithm on classes + stab:=clTR[1][2]; + orb:=[clTR[1]]; + #repres:=RestrictedPermNC(clTR[1][1],components[i]); + repres:=clTR[1][1]; + trans:=[One(M)]; + select:=[2..Length(clTR)]; + + orpo:=1; + minlen:=Size(orb[1][3]); + possible:=false; + stabtrue:=false; + pf:=infinity; + maxdiff:=Size(T); + again:=0; + trymap:=false; + ug:=[]; + # test whether we have full orbit and full stabilizer + while Size(centralizers[j])>(Sum(orb,i->Size(i[3]))*Size(stab)) do + genpos:=1; + while genpos<=Length(cengen) and + Size(centralizers[j])>(Sum(orb,i->Size(i[3]))*Size(stab)) do + gen:=cengen[genpos]; + skip:=false; + if trymap<>false then + orpo:=trymap[1]; + gen:=trymap[2]; + trymap:=false; + elif again>0 then + if not IsBound(ug[genpos]) then + ug[genpos]:=Intersection(centralizers_r[j], + ConjugateSubgroup(centralizers_r[j],gen^-1)); + fi; + if again<500 and ForAll(GeneratorsOfGroup(centralizers_r[j]), + i->i in ug[genpos]) + then + # the random elements will give us nothing new + skip:=true; + else + # get an element not in ug[genpos] + repeat + img:=Random(centralizers_r[j]); + until not img in ug[genpos] or again>=500; + gen:=img*gen; + fi; + fi; + + if not skip then + + img:=Image(projections[i],opfun(orb[orpo][1],gen)); + + smacla:=select; + + if not stabtrue then + p:=PositionProperty(orb,i->img in i[3]); + ppos:=fail; else # we have the stabilizer and thus are only interested in # getting new elements. @@ -694,50 +694,50 @@ local clT, # classes T return fail; fi; else - p:=ppos; - fi; + p:=ppos; + fi; - RemoveSet(select,p); - Add(orb,clTR[p]); - - if trans[orpo]=false then - Add(trans,false); - else - #change the transversal element to map to the representative - con:=trans[orpo]*gen; - limg:=opfun(repres,con); - con:=con*PreImagesRepresentativeNC(centrhom, - RepresentativeAction(localcent_r, - Image(projections[i],limg), - Representative(clTR[p][3]))); - Assert(2,Image(projections[i],opfun(repres,con)) - =Representative(clTR[p][3])); - - Add(trans,con); - - for stgen in GeneratorsOfGroup(clTR[p][2]) do - Assert( 2, IsOne( Image( projections[i], - opfun(repres,con*stgen/con)/repres ) ) ); - stab:=ClosureGroup(stab,con*stgen/con); - od; - fi; + RemoveSet(select,p); + Add(orb,clTR[p]); - # compute new minimum length - - if Length(select)>0 then - remainlen:=List(clTR{select},i->Size(i[3])); - gcd:=Gcd(remainlen); - diff:=minlen-Sum(orb,i->Size(i[3])); - - if diff<0 then - # only go through this if the orbit actually grew - # larger - minlen:=Sum(orb,i->Size(i[3])); - repeat - if dsz=0 then - dsz:=DivisorsInt(scj); - fi; - while not minlen in dsz do + if trans[orpo]=false then + Add(trans,false); + else + #change the transversal element to map to the representative + con:=trans[orpo]*gen; + limg:=opfun(repres,con); + con:=con*PreImagesRepresentativeNC(centrhom, + RepresentativeAction(localcent_r, + Image(projections[i],limg), + Representative(clTR[p][3]))); + Assert(2,Image(projections[i],opfun(repres,con)) + =Representative(clTR[p][3])); + + Add(trans,con); + + for stgen in GeneratorsOfGroup(clTR[p][2]) do + Assert( 2, IsOne( Image( projections[i], + opfun(repres,con*stgen/con)/repres ) ) ); + stab:=ClosureGroup(stab,con*stgen/con); + od; + fi; + + # compute new minimum length + + if Length(select)>0 then + remainlen:=List(clTR{select},i->Size(i[3])); + gcd:=Gcd(remainlen); + diff:=minlen-Sum(orb,i->Size(i[3])); + + if diff<0 then + # only go through this if the orbit actually grew + # larger + minlen:=Sum(orb,i->Size(i[3])); + repeat + if dsz=0 then + dsz:=DivisorsInt(scj); + fi; + while not minlen in dsz do # workaround rare problem -- try again if First(dsz,i->i>=minlen)=fail then return ConjugacyClassesSubwreath( @@ -781,7 +781,12 @@ local clT, # classes T Info(InfoHomClass,5,"Minimum length of this orbit ", minlen," (",diff," missing)"); + fi; + if minlen*Size(stab)=Size(centralizers[j]) then + #Assert(1,Length(smacla)>0); + maxdiff:=diff; + stabtrue:=true; fi; if minlen*Size(stab)=Size(centralizers[j]) then @@ -789,7 +794,6 @@ local clT, # classes T maxdiff:=diff; stabtrue:=true; fi; -????? elif not stabtrue then # we have an element that stabilizes the conjugacy class. # correct this to an element that fixes the representative. @@ -829,110 +833,110 @@ local clT, # classes T =Size(centralizers[j]) then maxdiff:=0; - elif Sum(remainlen)=maxdiff then - Info(InfoHomClass,2, - "Full possible remainder must fuse"); - orb:=Concatenation(orb,clTR{smacla}); - select:=Difference(select,smacla); - - else - # test whether there is only one possibility to get - # this length - if Length(smacla)<20 and - Sum(List([1..Minimum(Length(smacla), - Int(maxdiff/gcd+1))], - x-> NrCombinations(smacla,x)))<10000 then - # get all reasonable combinations - smare:=[1..Length(smacla)]; #range for smacla - combl:=Concatenation(List([1..Int(maxdiff/gcd+1)], - i->Combinations(smare,i))); - # pick those that have the correct length - combl:=Filtered(combl,i->Sum(remainlen{i})=maxdiff); - if Length(combl)>1 then - Info(InfoHomClass,3,"Addendum not unique (", - Length(combl)," possibilities)"); - if (maxdiff<10 or again>0) - and ForAll(combl,i->Length(i)<=5) then - # we have tried often enough, now try to pick the - # right ones - possible:=false; - combl:=Union(combl); - combl:=smacla{combl}; - genpos2:=1; - smacla:=[]; - while possible=false and Length(combl)>0 do - img:=Image(projections[i], - opfun(clTR[combl[1]][1],cengen[genpos2])); - p:=PositionProperty(orb,i->img in i[3]); - if p<>fail then - # it is! - Info(InfoHomClass,4,"got one!"); - - # remember the element to try - trymap:=[p,(cengen[genpos2]* - PreImagesRepresentativeNC( - RestrictedMapping(projections[i], - centralizers[j]), - RepresentativeAction( - orb[p][4], - img,Representative(orb[p][3])) ))^-1]; - - Add(smacla,combl[1]); - combl:=combl{[2..Length(combl)]}; - if Sum(clTR{smacla},i->Size(i[3]))=maxdiff then - # bingo! - possible:=true; - fi; - fi; - genpos2:=genpos2+1; - if genpos2>Length(cengen) then - genpos2:=1; - combl:=combl{[2..Length(combl)]}; - fi; - od; - if possible=false then - Info(InfoHomClass,4,"Even test failed!"); - else - orb:=Concatenation(orb,clTR{smacla}); - select:=Difference(select,smacla); - Info(InfoHomClass,3,"Completed orbit (hard)"); - fi; - fi; - elif Length(combl)>0 then - combl:=combl[1]; - orb:=Concatenation(orb,clTR{smacla{combl}}); - select:=Difference(select,smacla{combl}); - Info(InfoHomClass,3,"Completed orbit"); - fi; - fi; - fi; - fi; + elif Sum(remainlen)=maxdiff then + Info(InfoHomClass,2, + "Full possible remainder must fuse"); + orb:=Concatenation(orb,clTR{smacla}); + select:=Difference(select,smacla); + + else + # test whether there is only one possibility to get + # this length + if Length(smacla)<20 and + Sum(List([1..Minimum(Length(smacla), + Int(maxdiff/gcd+1))], + x-> NrCombinations(smacla,x)))<10000 then + # get all reasonable combinations + smare:=[1..Length(smacla)]; #range for smacla + combl:=Concatenation(List([1..Int(maxdiff/gcd+1)], + i->Combinations(smare,i))); + # pick those that have the correct length + combl:=Filtered(combl,i->Sum(remainlen{i})=maxdiff); + if Length(combl)>1 then + Info(InfoHomClass,3,"Addendum not unique (", + Length(combl)," possibilities)"); + if (maxdiff<10 or again>0) + and ForAll(combl,i->Length(i)<=5) then + # we have tried often enough, now try to pick the + # right ones + possible:=false; + combl:=Union(combl); + combl:=smacla{combl}; + genpos2:=1; + smacla:=[]; + while possible=false and Length(combl)>0 do + img:=Image(projections[i], + opfun(clTR[combl[1]][1],cengen[genpos2])); + p:=PositionProperty(orb,i->img in i[3]); + if p<>fail then + # it is! + Info(InfoHomClass,4,"got one!"); + + # remember the element to try + trymap:=[p,(cengen[genpos2]* + PreImagesRepresentativeNC( + RestrictedMapping(projections[i], + centralizers[j]), + RepresentativeAction( + orb[p][4], + img,Representative(orb[p][3])) ))^-1]; + + Add(smacla,combl[1]); + combl:=combl{[2..Length(combl)]}; + if Sum(clTR{smacla},i->Size(i[3]))=maxdiff then + # bingo! + possible:=true; + fi; + fi; + genpos2:=genpos2+1; + if genpos2>Length(cengen) then + genpos2:=1; + combl:=combl{[2..Length(combl)]}; + fi; + od; + if possible=false then + Info(InfoHomClass,4,"Even test failed!"); + else + orb:=Concatenation(orb,clTR{smacla}); + select:=Difference(select,smacla); + Info(InfoHomClass,3,"Completed orbit (hard)"); + fi; + fi; + elif Length(combl)>0 then + combl:=combl[1]; + orb:=Concatenation(orb,clTR{smacla{combl}}); + select:=Difference(select,smacla{combl}); + Info(InfoHomClass,3,"Completed orbit"); + fi; + fi; + fi; + fi; + + fi; + else + Info(InfoHomClass,5,"skip"); + fi; # if not skip - fi; - else - Info(InfoHomClass,5,"skip"); - fi; # if not skip - - genpos:=genpos+1; - od; - orpo:=orpo+1; - if orpo>Length(orb) then - Info(InfoHomClass,3,"Size factor:",EvalF( - (Sum(orb,i->Size(i[3]))*Size(stab))/Size(centralizers[j])), - " orbit consists of ",Length(orb)," suborbits, iterating"); - - if stabtrue then - pper:=false; - # we know stabilizer, just need to find orbit. As these are - # likely small additions, search in reverse. - for p in select do - for genpos in [1..Length(cengen)] do - gen:=Random(centralizers_r[j])*cengen[genpos]; - img:=Image(projections[i],opfun(clTR[p][1],gen)); - orpo:=CycleStructurePerm(img); - ppos:=First(First(cystr,x->x[1]=orpo)[2], - i->not i in select and - img in clTR[i][3]); + genpos:=genpos+1; + od; + orpo:=orpo+1; + if orpo>Length(orb) then + Info(InfoHomClass,3,"Size factor:",EvalF( + (Sum(orb,i->Size(i[3]))*Size(stab))/Size(centralizers[j])), + " orbit consists of ",Length(orb)," suborbits, iterating"); + + if stabtrue then + pper:=false; + # we know stabilizer, just need to find orbit. As these are + # likely small additions, search in reverse. + for p in select do + for genpos in [1..Length(cengen)] do + gen:=Random(centralizers_r[j])*cengen[genpos]; + img:=Image(projections[i],opfun(clTR[p][1],gen)); + orpo:=CycleStructurePerm(img); + ppos:=First(First(cystr,x->x[1]=orpo)[2], + i->not i in select and + img in clTR[i][3]); if ppos<>fail and p in select then # so the image is in clTR[ppos] which must be in orb ppos:=Position(orb,clTR[ppos]); @@ -1141,7 +1145,8 @@ local cs, # chief series of G hom:=NaturalHomomorphismByNormalSubgroupNC(G,lastM); cl:=ConjugacyClasses(Image(hom)); cl:=List(cl,i->[PreImagesRepresentativeNC(hom,Representative(i)), - PreImage(hom,StabilizerOfExternalSet(i))]); + PreImage(hom,StabilizerOfExternalSet(i))]); + cs:=Concatenation([G],Filtered(cs,x->IsSubset(lastM,x))); fi; for i in [2..Length(cs)] do @@ -1182,146 +1187,144 @@ local cs, # chief series of G if IsNormal(G,subN) then - # only one -> Call standard process - - Fhom:=fail; - # is this an almost top factor? - if Index(G,M)<10 then - Thom:=NaturalHomomorphismByNormalSubgroupNC(G,subN); - T1:=Image(Thom,M); - S1:=Image(Thom); - if Size(Centralizer(S1,T1))=1 then - deg1:=NrMovedPoints(S1); - Info(InfoHomClass,2, - "top factor gives conjugating representation, deg ",deg1); - - Fhom:=Thom; - fi; - else - Thom:=NaturalHomomorphismByNormalSubgroupNC(M,subN); - T1:=Image(Thom,M); - fi; - - if Fhom=fail then - autos:=List(GeneratorsOfGroup(G), - i->GroupHomomorphismByImagesNC(T1,T1,GeneratorsOfGroup(T1), - List(GeneratorsOfGroup(T1), - j->Image(Thom,PreImagesRepresentativeNC(Thom,j)^i)))); - - # find (probably another) permutation rep for T1 for which all - # automorphisms can be represented by permutations - arhom:=AutomorphismRepresentingGroup(T1,autos); - S1:=arhom[1]; - deg1:=NrMovedPoints(S1); - Fhom:=GroupHomomorphismByImagesNC(G,S1,GeneratorsOfGroup(G),arhom[3]); - fi; - - - C:=KernelOfMultiplicativeGeneralMapping(Fhom); - F:=Image(Fhom,G); - - clF:=ClassesFromClassical(F); - if clF=fail then - clF:=ConjugacyClassesByRandomSearch(F); - fi; - - clF:=List(clF,j->[Representative(j),StabilizerOfExternalSet(j)]); + # only one -> Call standard process + + Fhom:=fail; + # is this an almost top factor? + if Index(G,M)<10 then + Thom:=NaturalHomomorphismByNormalSubgroupNC(G,subN); + T1:=Image(Thom,M); + S1:=Image(Thom); + if Size(Centralizer(S1,T1))=1 then + deg1:=NrMovedPoints(S1); + Info(InfoHomClass,2, + "top factor gives conjugating representation, deg ",deg1); + + Fhom:=Thom; + fi; + else + Thom:=NaturalHomomorphismByNormalSubgroupNC(M,subN); + T1:=Image(Thom,M); + fi; + + if Fhom=fail then + autos:=List(GeneratorsOfGroup(G), + i->GroupHomomorphismByImagesNC(T1,T1,GeneratorsOfGroup(T1), + List(GeneratorsOfGroup(T1), + j->Image(Thom,PreImagesRepresentativeNC(Thom,j)^i)))); + + # find (probably another) permutation rep for T1 for which all + # automorphisms can be represented by permutations + arhom:=AutomorphismRepresentingGroup(T1,autos); + S1:=arhom[1]; + deg1:=NrMovedPoints(S1); + Fhom:=GroupHomomorphismByImagesNC(G,S1,GeneratorsOfGroup(G),arhom[3]); + fi; + + + F:=Image(Fhom,G); + + clF:=ClassesFromClassical(F); + if clF=fail then + clF:=ConjugacyClassesByRandomSearch(F); + fi; + + clF:=List(clF,j->[Representative(j),StabilizerOfExternalSet(j)]); else - csM:=Orbit(G,subN); # all conjugates - n:=Length(csM); - - if n=1 then - Error("this cannot happen"); - T:=M; - fi; - - T:=Intersection(csM{[2..Length(csM)]}); # one T_i - if Length(GeneratorsOfGroup(T))>5 then - T:=Group(SmallGeneratingSet(T)); - fi; - - T:=Orbit(G,T); # get all the t's - # now T[1] is a complement to csM[1] in G/N. - - # now compute the operation of G on M/N - Qhom:=ActionHomomorphism(G,T,"surjective"); - Q:=Image(Qhom,G); - S:=PreImage(Qhom,Stabilizer(Q,1)); - - # find a permutation rep. for S-action on T[1] - Thom:=NaturalHomomorphismByNormalSubgroupNC(T[1],N); - T1:=Image(Thom); - if not IsSubset([1..NrMovedPoints(T1)], - MovedPoints(T1)) then - Thom:=Thom*ActionHomomorphism(T1,MovedPoints(T1),"surjective"); - fi; - T1:=Image(Thom,T[1]); - if IsPermGroup(T1) and - NrMovedPoints(T1)>SufficientlySmallDegreeSimpleGroupOrder(Size(T1)) then - Thom:=Thom*SmallerDegreePermutationRepresentation(T1:cheap); - Info(InfoHomClass,1,"reduced simple degree ",NrMovedPoints(T1), - " ",NrMovedPoints(Image(Thom))); - T1:=Image(Thom,T[1]); - fi; - - autos:=List(GeneratorsOfGroup(S), - i->GroupHomomorphismByImagesNC(T1,T1,GeneratorsOfGroup(T1), - List(GeneratorsOfGroup(T1), - j->Image(Thom,PreImagesRepresentativeNC(Thom,j)^i)))); - - # find (probably another) permutation rep for T1 for which all - # automorphisms can be represented by permutations - arhom:=AutomorphismRepresentingGroup(T1,autos); - S1:=arhom[1]; - deg1:=NrMovedPoints(S1); - Thom:=GroupHomomorphismByImagesNC(S,S1,GeneratorsOfGroup(S),arhom[3]); - - T1:=Image(Thom,T[1]); - - # now embed into wreath - w:=WreathProduct(S1,Q); - wbas:=DirectProduct(List([1..n],i->S1)); - emb:=List([1..n+1],i->Embedding(w,i)); - proj:=List([1..n],i->Projection(wbas,i)); - components:=WreathProductInfo(w).components; - - # define isomorphisms between the components - reps:=List([1..n],i-> - PreImagesRepresentativeNC(Qhom,RepresentativeAction(Q,1,i))); - - genimages:=[]; - for j in GeneratorsOfGroup(G) do - img:=Image(Qhom,j); - gimg:=Image(emb[n+1],img); - for k in [1..n] do - # look at part of j's action on the k-th factor. - # we get this by looking at the action of - # reps[k] * j * reps[k^img]^-1 - # 1 -> k -> k^img -> 1 - # on the first component. - act:=reps[k]*j*(reps[k^img]^-1); - # this must be multiplied *before* permuting - gimg:=ImageElm(emb[k],ImageElm(Thom,act))*gimg; - gimg:=RestrictedPermNC(gimg,MovedPoints(w)); - od; - Add(genimages,gimg); - od; - - F:=Subgroup(w,genimages); - if AssertionLevel()>=2 then - Fhom:=GroupHomomorphismByImages(G,F,GeneratorsOfGroup(G),genimages); - Assert(1,fail<>Fhom); - else - Fhom:=GroupHomomorphismByImagesNC(G,F,GeneratorsOfGroup(G),genimages); - fi; - C:=KernelOfMultiplicativeGeneralMapping(Fhom); - - Info(InfoHomClass,1,"constructed Fhom"); - - # 2) compute the classes for F - - if n>1 then + csM:=Orbit(G,subN); # all conjugates + n:=Length(csM); + + if n=1 then + Error("this cannot happen"); + T:=M; + fi; + + T:=Intersection(csM{[2..Length(csM)]}); # one T_i + if Length(GeneratorsOfGroup(T))>5 then + T:=Group(SmallGeneratingSet(T)); + fi; + + T:=Orbit(G,T); # get all the t's + # now T[1] is a complement to csM[1] in G/N. + + # now compute the operation of G on M/N + Qhom:=ActionHomomorphism(G,T,"surjective"); + Q:=Image(Qhom,G); + S:=PreImage(Qhom,Stabilizer(Q,1)); + + # find a permutation rep. for S-action on T[1] + Thom:=NaturalHomomorphismByNormalSubgroupNC(T[1],N); + T1:=Image(Thom); + if not IsSubset([1..NrMovedPoints(T1)], + MovedPoints(T1)) then + Thom:=Thom*ActionHomomorphism(T1,MovedPoints(T1),"surjective"); + fi; + T1:=Image(Thom,T[1]); + if IsPermGroup(T1) and + NrMovedPoints(T1)>SufficientlySmallDegreeSimpleGroupOrder(Size(T1)) then + Thom:=Thom*SmallerDegreePermutationRepresentation(T1:cheap); + Info(InfoHomClass,1,"reduced simple degree ",NrMovedPoints(T1), + " ",NrMovedPoints(Image(Thom))); + T1:=Image(Thom,T[1]); + fi; + + autos:=List(GeneratorsOfGroup(S), + i->GroupHomomorphismByImagesNC(T1,T1,GeneratorsOfGroup(T1), + List(GeneratorsOfGroup(T1), + j->Image(Thom,PreImagesRepresentativeNC(Thom,j)^i)))); + + # find (probably another) permutation rep for T1 for which all + # automorphisms can be represented by permutations + arhom:=AutomorphismRepresentingGroup(T1,autos); + S1:=arhom[1]; + deg1:=NrMovedPoints(S1); + Thom:=GroupHomomorphismByImagesNC(S,S1,GeneratorsOfGroup(S),arhom[3]); + + T1:=Image(Thom,T[1]); + + # now embed into wreath + w:=WreathProduct(S1,Q); + wbas:=DirectProduct(List([1..n],i->S1)); + emb:=List([1..n+1],i->Embedding(w,i)); + proj:=List([1..n],i->Projection(wbas,i)); + components:=WreathProductInfo(w).components; + + # define isomorphisms between the components + reps:=List([1..n],i-> + PreImagesRepresentativeNC(Qhom,RepresentativeActionNC(Q,1,i))); + + genimages:=[]; + for j in GeneratorsOfGroup(G) do + img:=Image(Qhom,j); + gimg:=Image(emb[n+1],img); + for k in [1..n] do + # look at part of j's action on the k-th factor. + # we get this by looking at the action of + # reps[k] * j * reps[k^img]^-1 + # 1 -> k -> k^img -> 1 + # on the first component. + act:=reps[k]*j*(reps[k^img]^-1); + # this must be multiplied *before* permuting + gimg:=ImageElm(emb[k],ImageElm(Thom,act))*gimg; + gimg:=RestrictedPermNC(gimg,MovedPoints(w)); + od; + Add(genimages,gimg); + od; + + F:=Subgroup(w,genimages); + if AssertionLevel()>=2 then + Fhom:=GroupHomomorphismByImages(G,F,GeneratorsOfGroup(G),genimages); + Assert(1,fail<>Fhom); + else + Fhom:=GroupHomomorphismByImagesNC(G,F,GeneratorsOfGroup(G),genimages); + fi; + + Info(InfoHomClass,1,"constructed Fhom"); + + # 2) compute the classes for F + + if n>1 then #if IsPermGroup(F) and NrMovedPoints(F)<18 then # # the old Butler/Theissen approach is still OK # clF:=[]; @@ -1338,30 +1341,30 @@ local cs, # chief series of G clF:=ConjugacyClassesSubwreath(F,FM,n,S1, Action(FM,components[1]),T1,components,emb,proj); if clF=fail then - #Error("failer"); - # weird error happened -- redo - j:=Random(SymmetricGroup(MovedPoints(G))); - FM:=List(GeneratorsOfGroup(G),x->x^j); - F:=Group(FM); - SetSize(F,Size(G)); - FM:=GroupHomomorphismByImagesNC(G,F,GeneratorsOfGroup(G),FM); - clF:=ConjugacyClassesFittingFreeGroup(F); - clF:=List(clF,x->[PreImagesRepresentativeNC(FM,x[1]),PreImage(FM,x[2])]); - return clF; - fi; - #fi; - else - FM:=Image(Fhom,M); - Info(InfoHomClass,1, - "classes by random search in almost simple group"); - - clF:=ClassesFromClassical(F); - if clF=fail then - clF:=ConjugacyClassesByRandomSearch(F); - fi; - - clF:=List(clF,j->[Representative(j),StabilizerOfExternalSet(j)]); - fi; + #Error("failure"); + # weird error happened -- redo + j:=Random(SymmetricGroup(MovedPoints(G))); + FM:=List(GeneratorsOfGroup(G),x->x^j); + F:=Group(FM); + SetSize(F,Size(G)); + FM:=GroupHomomorphismByImagesNC(G,F,GeneratorsOfGroup(G),FM); + clF:=ConjugacyClassesFittingFreeGroup(F); + clF:=List(clF,x->[PreImagesRepresentativeNC(FM,x[1]),PreImage(FM,x[2])]); + return clF; + fi; + #fi; + else + FM:=Image(Fhom,M); + Info(InfoHomClass,1, + "classes by random search in almost simple group"); + + clF:=ClassesFromClassical(F); + if clF=fail then + clF:=ConjugacyClassesByRandomSearch(F); + fi; + + clF:=List(clF,j->[Representative(j),StabilizerOfExternalSet(j)]); + fi; fi; # true orbit of T. Assert(2,Sum(clF,i->Index(F,i[2]))=Size(F)); @@ -1372,106 +1375,106 @@ local cs, # chief series of G # the length(cl)=1 gets rid of solvable stuff on the top we got ``too # early''. if IsSubgroup(N,KernelOfMultiplicativeGeneralMapping(Fhom)) then - Info(InfoHomClass,1, - "homomorphism is faithful for relevant factor, take preimages"); - if Size(N)=1 and onlysizes=true then - cl:=List(clF,i->[PreImagesRepresentativeNC(Fhom,i[1]),Size(i[2])]); - else - cl:=List(clF,i->[PreImagesRepresentativeNC(Fhom,i[1]), - PreImage(Fhom,i[2])]); + Info(InfoHomClass,1, + "homomorphism is faithful for relevant factor, take preimages"); + if Size(N)=1 and onlysizes=true then + cl:=List(clF,i->[PreImagesRepresentativeNC(Fhom,i[1]),Size(i[2])]); + else + cl:=List(clF,i->[PreImagesRepresentativeNC(Fhom,i[1]), + PreImage(Fhom,i[2])]); fi; else - Info(InfoHomClass,1,"forming subdirect products"); - - FM:=Image(Fhom,lastM); - FMhom:=RestrictedMapping(Fhom,lastM); - if Index(F,FM)=1 then - Info(InfoHomClass,1,"degenerated to direct product"); - ncl:=[]; - for j in cl do - for k in clF do - # modify the representative with a kernel elm. to project - # correctly on the second component - elm:=j[1]*PreImagesRepresentativeNC(FMhom, - LeftQuotient(Image(Fhom,j[1]),k[1])); - zentr:=Intersection(j[2],PreImage(Fhom,k[2])); - Assert(3,ForAll(GeneratorsOfGroup(zentr), - i->Comm(i,elm) in N)); - Add(ncl,[elm,zentr]); - od; - od; - - cl:=ncl; - - else - - # first we add the centralizer closures and sort by them - # (this allows to reduce the number of double coset calculations) - ncl:=[]; - for j in cl do - Cim:=Image(Fhom,j[2]); - CimCl:=Cim; - #CimCl:=ClosureGroup(FM,Cim); # should be unnecessary, as we took - # the full preimage - p:=PositionProperty(ncl,i->i[1]=CimCl); - if p=fail then - Add(ncl,[CimCl,[j]]); - else - Add(ncl[p][2],j); - fi; - od; - - Qhom:=NaturalHomomorphismByNormalSubgroupNC(F,FM); - Q:=Image(Qhom); - FQhom:=Fhom*Qhom; - - # now construct the sdp's - cl:=[]; - for j in ncl do - lj:=List(j[2],i->Image(FQhom,i[1])); - for k in clF do - # test whether the classes are potential mates - elm:=Image(Qhom,k[1]); - if not ForAll(lj,i->RepresentativeAction(Q,i,elm)=fail) then - - #l:=Image(Fhom,j[1]); - - if Index(F,j[1])=1 then - dc:=[()]; - else - dc:=List(DoubleCosetRepsAndSizes(F,k[2],j[1]),i->i[1]); - fi; - good:=0; - bad:=0; - for l in j[2] do - jim:=Image(FQhom,l[1]); - for l1 in dc do - elm:=k[1]^l1; - if Image(Qhom,elm)=jim then - # modify the representative with a kernel elm. to project - # correctly on the second component - elm:=l[1]*PreImagesRepresentativeNC(FMhom, - LeftQuotient(Image(Fhom,l[1]),elm)); - zentr:=PreImage(Fhom,k[2]^l1); - zentr:=Intersection(zentr,l[2]); - - Assert(3,ForAll(GeneratorsOfGroup(zentr), - i->Comm(i,elm) in N)); - - Info(InfoHomClass,4,"new class, order ",Order(elm), - ", size=",Index(G,zentr)); - Add(cl,[elm,zentr]); - good:=good+1; - else - Info(InfoHomClass,5,"not in"); - bad:=bad+1; - fi; - od; - od; - Info(InfoHomClass,4,good," good, ",bad," bad of ",Length(dc)); - fi; - od; - od; + Info(InfoHomClass,1,"forming subdirect products"); + + FM:=Image(Fhom,lastM); + FMhom:=RestrictedMapping(Fhom,lastM); + if Index(F,FM)=1 then + Info(InfoHomClass,1,"degenerated to direct product"); + ncl:=[]; + for j in cl do + for k in clF do + # modify the representative with a kernel elm. to project + # correctly on the second component + elm:=j[1]*PreImagesRepresentativeNC(FMhom, + LeftQuotient(Image(Fhom,j[1]),k[1])); + zentr:=Intersection(j[2],PreImage(Fhom,k[2])); + Assert(3,ForAll(GeneratorsOfGroup(zentr), + i->Comm(i,elm) in N)); + Add(ncl,[elm,zentr]); + od; + od; + + cl:=ncl; + + else + + # first we add the centralizer closures and sort by them + # (this allows to reduce the number of double coset calculations) + ncl:=[]; + for j in cl do + Cim:=Image(Fhom,j[2]); + CimCl:=Cim; + #CimCl:=ClosureGroup(FM,Cim); # should be unnecessary, as we took + # the full preimage + p:=PositionProperty(ncl,i->i[1]=CimCl); + if p=fail then + Add(ncl,[CimCl,[j]]); + else + Add(ncl[p][2],j); + fi; + od; + + Qhom:=NaturalHomomorphismByNormalSubgroupNC(F,FM); + Q:=Image(Qhom); + FQhom:=Fhom*Qhom; + + # now construct the sdp's + cl:=[]; + for j in ncl do + lj:=List(j[2],i->Image(FQhom,i[1])); + for k in clF do + # test whether the classes are potential mates + elm:=Image(Qhom,k[1]); + if not ForAll(lj,i->RepresentativeAction(Q,i,elm)=fail) then + + #l:=Image(Fhom,j[1]); + + if Index(F,j[1])=1 then + dc:=[()]; + else + dc:=List(DoubleCosetRepsAndSizes(F,k[2],j[1]),i->i[1]); + fi; + good:=0; + bad:=0; + for l in j[2] do + jim:=Image(FQhom,l[1]); + for l1 in dc do + elm:=k[1]^l1; + if Image(Qhom,elm)=jim then + # modify the representative with a kernel elm. to project + # correctly on the second component + elm:=l[1]*PreImagesRepresentativeNC(FMhom, + LeftQuotient(Image(Fhom,l[1]),elm)); + zentr:=PreImage(Fhom,k[2]^l1); + zentr:=Intersection(zentr,l[2]); + + Assert(3,ForAll(GeneratorsOfGroup(zentr), + i->Comm(i,elm) in N)); + + Info(InfoHomClass,4,"new class, order ",Order(elm), + ", size=",Index(G,zentr)); + Add(cl,[elm,zentr]); + good:=good+1; + else + Info(InfoHomClass,5,"not in"); + bad:=bad+1; + fi; + od; + od; + Info(InfoHomClass,4,good," good, ",bad," bad of ",Length(dc)); + fi; + od; + od; fi; # real subdirect product fi; # else Fhom not faithful on factor @@ -1642,14 +1645,14 @@ BindGlobal("LiftClassesEANonsolvGeneral", h, # preimage `cl.representative' under cg, cNh, # centralizer of in - gens, # preimage `Centralizer( cl )' under + gens, # preimage `Centralizer( cl )' under r, # dimension of ran, # constant range `[ 1 .. r ]' aff, # as affine space imgs, M, # generating matrices for affine operation orb, # orbit of affine operation - rep,# set of classes with canonical representatives - c, i, # loop variables + rep, # set of classes with canonical representatives + c, i, # loop variables PPcgs,denomdepths, correctionfactor, stabfacgens, @@ -1958,7 +1961,7 @@ local classes, # classes to be constructed, the result c := [h * PcElementByExponentsNC( Npcgs,w*com.factorspace), stabrad,stabfacgens,stabfacimg,subsz,stabrsubsz]; #if reduce<>fail then - # Add(classes,[PreImagesRepresentative(reduce,c[1]), + # Add(classes,[PreImagesRepresentativeNC(reduce,c[1]), # PreImage(reduce,c[2])]); # else @@ -2399,12 +2402,12 @@ local r, #radical if ntrihom then ncl:=[]; for i in cl do - new:=[PreImagesRepresentativeNC(hom,i[1])]; - if not IsInt(i[2]) then - Add(new,[]); # no generators in radical yet - gens:=SmallGeneratingSet(i[2]); - Add(new, - List(gens,x->PreImagesRepresentativeNC(hom,x))); + new:=[PreImagesRepresentativeNC(hom,i[1])]; + if not IsInt(i[2]) then + Add(new,[]); # no generators in radical yet + gens:=SmallGeneratingSet(i[2]); + Add(new, + List(gens,x->PreImagesRepresentativeNC(hom,x))); Add(new,gens); #TODO: PreImage groups? #Add(new,PreImage(hom,i[2])); @@ -2887,7 +2890,7 @@ local r, #radical fi; prereps:=f!.classpreimgs; if not IsBound(prereps[j]) then - prereps[j]:=PreImagesRepresentativeNC(hom,Representative(cl[j])); + prereps[j]:=PreImagesRepresentativeNC(hom,Representative(cl[j])); fi; r:=PreImagesRepresentativeNC(hom,conj); @@ -2899,7 +2902,7 @@ local r, #radical # 6:cenfac, 7:cenfacimgs, 8:censize, 9:cenfacsize Add(nreps,[i,i^r,prereps[j],r,[], List(d,x->PreImagesRepresentativeNC(hom,x)),d, - radsize*Size(Centralizer(cl[j])), Size(Centralizer(cl[j]))]); + radsize*Size(Centralizer(cl[j])), Size(Centralizer(cl[j]))]); od; reps:=nreps; diff --git a/lib/fitfree.gi b/lib/fitfree.gi index 877494deef..4aa31f6be6 100644 --- a/lib/fitfree.gi +++ b/lib/fitfree.gi @@ -81,7 +81,7 @@ local ffs,pcisom,rest,kpc,k,x,ker,r,pool,i,xx,pregens,iso; else iso:=IsomorphismFpGroup(Image(rest,U)); pregens:=List(GeneratorsOfGroup(Range(iso)),x-> - PreImagesRepresentative(rest,PreImagesRepresentative(iso,x))); + PreImagesRepresentativeNC(rest,PreImagesRepresentativeNC(iso,x))); # evaluate relators pool:=List(RelatorsOfFpGroup(Range(iso)), x->MappedWord(x,FreeGeneratorsOfFpGroup(Range(iso)),pregens)); @@ -91,7 +91,7 @@ local ffs,pcisom,rest,kpc,k,x,ker,r,pool,i,xx,pregens,iso; iso:=IsomorphismFpGroup(Image(rest,U)); pregens:=List(GeneratorsOfGroup(Range(iso)),x-> - PreImagesRepresentative(rest,PreImagesRepresentative(iso,x))); + PreImagesRepresentativeNC(rest,PreImagesRepresentativeNC(iso,x))); # evaluate relators pool:=List(RelatorsOfFpGroup(Range(iso)), x->MappedWord(x,FreeGeneratorsOfFpGroup(Range(iso)),pregens)); @@ -257,7 +257,7 @@ local ffs,hom,U,rest,ker,r,p,l,i,depths,pcisom,subsz,pcimgs; pcimgs:=List(ipcgs,x->ImagesRepresentative(ffs.pcisom,x)); ker:=SubgroupNC(G,List(MinimalGeneratingSet(Group(pcimgs,One(Range(ffs.pcisom)))), - x->PreImagesRepresentative(ffs.pcisom,x))); + x->PreImagesRepresentativeNC(ffs.pcisom,x))); SetPcgs(ker,ipcgs); if Length(ipcgs)=0 then SetSize(ker,1); @@ -1195,9 +1195,9 @@ local s,d,c,act,o,i,j,h,p,hf,img,n,k,ns,all,hl,hcomp, norm:=n); for j in [2..Length(i)] do c[i[j]]:=rec(orbit:=i,orbitpos:=j, - rep:=PreImagesRepresentativeNC(act, - RepresentativeAction(Image(act),i[1],i[j])), - component:=d[i[j]],hall:=h, norm:=n); + rep:=PreImagesRepresentativeNC(act, + RepresentativeAction(Image(act),i[1],i[j])), + component:=d[i[j]],hall:=h, norm:=n); od; od; diff --git a/lib/ghompcgs.gi b/lib/ghompcgs.gi index f3fb30ddda..78ba75b339 100644 --- a/lib/ghompcgs.gi +++ b/lib/ghompcgs.gi @@ -505,7 +505,7 @@ end); ## #M PreImagesRepresentativeNC( , ) . . . . . . . . . . via images ## -InstallMethod( PreImagesRepresentativeNC, "method for pcgs hom", +InstallMethod( PreImagesRepresentativeNC, "method for pcgs hom", FamRangeEqFamElm, [ IsToPcGroupHomomorphismByImages,IsMultiplicativeElementWithInverse ], 0, function( hom, elm ) diff --git a/lib/gpfpiso.gi b/lib/gpfpiso.gi index 714b77d704..f50ea53b1d 100644 --- a/lib/gpfpiso.gi +++ b/lib/gpfpiso.gi @@ -90,10 +90,10 @@ local l,iso,fp,stbc,gens; if iso<>fail then fp:=IsomorphismFpGroup(l); iso:=GroupHomomorphismByImagesNC(G,Range(fp), - List(MappingGeneratorsImages(fp)[1], - i->PreImagesRepresentativeNC(iso,i)), - MappingGeneratorsImages(fp)[2]); - SetIsBijective(iso,true); + List(MappingGeneratorsImages(fp)[1], + i->PreImagesRepresentativeNC(iso,i)), + MappingGeneratorsImages(fp)[2]); + SetIsBijective(iso,true); return iso; fi; od; @@ -166,12 +166,12 @@ function( G, str ) # 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->PreImagesRepresentativeNC(new,i)); + # compute presentation of H + IsNonabelianSimpleGroup(H); + IsNaturalAlternatingGroup(H); + new:=IsomorphismFpGroup(H,"@"); + gensH:=List(GeneratorsOfGroup(Image(new)), + i->PreImagesRepresentativeNC(new,i)); preiH := List( gensH, x -> PreImagesRepresentativeNC( hom, x ) ); c := Length( gensH ); @@ -396,8 +396,8 @@ function(g,str,N) # calculate automorphisms of f induced by G fgens:=GeneratorsOfGroup(f); auts:=List(GeneratorsOfGroup(g),i-> - GroupHomomorphismByImagesNC(f,f,fgens, - List(fgens,j->Image(hom,PreImagesRepresentativeNC(hom,j)^i)):noassert)); + GroupHomomorphismByImagesNC(f,f,fgens, + List(fgens,j->Image(hom,PreImagesRepresentativeNC(hom,j)^i)):noassert)); for j in auts do SetIsBijective(j,true); od; @@ -426,7 +426,8 @@ function(g,str,N) else a:=IsomorphismFpGroup(sf:noassert); fi; - ad:=List(GeneratorsOfGroup(Range(a)),i->PreImagesRepresentativeNC(a,i)); + ad:=List(GeneratorsOfGroup(Range(a)), + i->PreImagesRepresentativeNC(a,i)); lad:=Length(ad); n:=Length(orb); @@ -1320,7 +1321,8 @@ 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->PreImagesRepresentativeNC(iso,x))<>pcgs then + if List(GeneratorsOfGroup(fp), + x->PreImagesRepresentativeNC(iso,x))<>pcgs then Error("pcgs"); fi; gens:=[]; @@ -1728,7 +1730,8 @@ local isob,isos,iso,gens,a,rels,l,i,j,bgens,cb,cs,b,f,k,w,monoid, # 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->PreImagesRepresentativeNC(pciso,PreImagesRepresentativeNC(cb.fphom,x))); + x->PreImagesRepresentativeNC(pciso, + PreImagesRepresentativeNC(cb.fphom,x))); b:=Range(isob); @@ -1966,8 +1969,9 @@ local isob,isos,iso,gens,a,rels,l,i,j,bgens,cb,cs,b,f,k,w,monoid, a:=Group(SmallGeneratingSet(group)); # so nothing stores csetperm:=List(GeneratorsOfGroup(a),x->Permutation(x,rt,OnRight)); iso:=EpimorphismFromFreeGroup(a); - borela:=List(bgens,x->MappedWord(PreImagesRepresentativeNC(iso,x),MappingGeneratorsImages(iso)[1],borela)); - act:=Group(borela,()); + csetperm:=List(bgens,x->MappedWord(PreImagesRepresentativeNC(iso,x), + MappingGeneratorsImages(iso)[1],csetperm)); + act:=Group(csetperm,()); bhom:=GroupHomomorphismByImagesNC(borel,act,bgens,csetperm); #Assert(0,bhom<>fail); @@ -2013,7 +2017,7 @@ local isob,isos,iso,gens,a,rels,l,i,j,bgens,cb,cs,b,f,k,w,monoid, a:=PositionCanonical(rt,elm); b:=rti[a]; rep:=RepresentativeAction(Image(bhom),a,dcnums[b][1]); - rep:=PreImagesRepresentative(bhom,rep); + rep:=PreImagesRepresentativeNC(bhom,rep); if single then a:=[CanonicalRightCosetElement(ac[1],rt[dcnums[b][1]]),rep]; else @@ -2054,14 +2058,11 @@ local isob,isos,iso,gens,a,rels,l,i,j,bgens,cb,cs,b,f,k,w,monoid, decomp:=function(elm) local rep,a; 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,borela,OnPoints); - rep:=PreImagesRepresentativeNC(bhom, - RepresentativeAction(Range(bhom),PositionCanonical(rt,elm), - PositionCanonical(rt,dcreps[pos]))); - rep:=[elm*rep/dcreps[pos],dcreps[pos],rep^-1]; + + a:=dcr(elm); + rep:=a[2]; + + rep:=[elm*rep/a[1],a[1],rep^-1]; Assert(0,rep[1] in borel); return rep; end; @@ -2686,7 +2687,7 @@ end); # if List(mg,x->LetterRepAssocWord(UnderlyingElement(x)))<> # List([1..Length(mg)],x->[x]) then Error("gens!"); fi; # pre:=List(mg,x->LetterRepAssocWord(UnderlyingElement( -# PreImagesRepresentativeNC(miso,x)))); +# PreImagesRepresentative(miso,x)))); # if ForAny(pre,x->Length(x)<>1) then Error("double");fi; # Add(l,Concatenation(pre)); # if IsBound(m!.rewritingSystem) then @@ -2898,7 +2899,7 @@ local d,f,group,act,g,sy,b,c,borel,weyl,a,i,iso,ucs,gens,gl; fi; c:=c[1]; a:=SubgroupNC(group,List(GeneratorsOfGroup(weyl), - x->PreImagesRepresentative(c,x))); + x->PreImagesRepresentativeNC(c,x))); Size(a); a!.epiweyl:=weyl; weyl:=a; diff --git a/lib/gprd.gi b/lib/gprd.gi index c5df0b6f66..49b091d983 100644 --- a/lib/gprd.gi +++ b/lib/gprd.gi @@ -1091,13 +1091,13 @@ local info,map,U,mapfun,P; U:=SubgroupNC(G,info.hgens); fi; map:=GroupHomomorphismByFunction(P,U,mapfun, - function(elm) - elm:=elm![n]; - if n>info.degI then - elm:=PreImagesRepresentativeNC(info.alpha,elm); - fi; - return elm; - end); + function(elm) + elm:=elm![n]; + if n>info.degI then + elm:=PreImagesRepresentativeNC(info.alpha,elm); + fi; + return elm; + end); info.embeddings[n]:=map; fi; return info.embeddings[n]; @@ -1118,7 +1118,7 @@ local info,map,np; map:=GroupHomomorphismByFunction(G,info.groups[2], function(elm) - return PreImagesRepresentativeNC(info.alpha,elm![np]); + return PreImagesRepresentativeNC(info.alpha,elm![np]); end, false, # not bijective function(elm) diff --git a/lib/grp.gi b/lib/grp.gi index 8dd381e83c..5453ba0420 100644 --- a/lib/grp.gi +++ b/lib/grp.gi @@ -10,7 +10,7 @@ ## ## This file contains generic methods for groups. ## -## (24/09/23) attempting to resolve conflicts (CDW) + ############################################################################# ## @@ -2091,7 +2091,8 @@ InstallGlobalFunction( SupersolvableResiduumDefault, function( G ) mg:= List( gs, x -> TransposedMat( List( pcgs, y -> one * ExponentsOfPcElement( pcgs, Image( ph, Image( dh, PreImagesRepresentativeNC( - dh, PreImagesRepresentativeNC(ph,y) )^x ) ) )))^-1); + dh, PreImagesRepresentativeNC( + ph,y) )^x ) ) )))^-1); #T inverting is not necessary, or? mg:= Filtered( mg, x -> x <> idm ); diff --git a/lib/grpcompl.gi b/lib/grpcompl.gi index 187222cb0d..82acfff647 100644 --- a/lib/grpcompl.gi +++ b/lib/grpcompl.gi @@ -99,9 +99,10 @@ local G,N,K,s, h, q, fpi, factorpres, com, comgens, cen, ocrels, fpcgs, ncom, Length(MappingGeneratorsImages(fpi)[2])," generators"); factorpres:=[FreeGeneratorsOfFpGroup(Range(fpi)), RelatorsOfFpGroup(Range(fpi)), - List(GeneratorsOfGroup(Range(fpi)), - i->PreImagesRepresentativeNC(fpi,i))]; - Assert(1,ForAll(factorpres[3],i->Image(h,PreImagesRepresentativeNC(h,i))=i)); + List(GeneratorsOfGroup(Range(fpi)), + i->PreImagesRepresentativeNC(fpi,i))]; + Assert(1,ForAll(factorpres[3], + i->Image(h,PreImagesRepresentativeNC(h,i))=i)); # initialize com:=[G]; comgens:=[List(factorpres[3],i->PreImagesRepresentativeNC(h,i))]; diff --git a/lib/grpfp.gi b/lib/grpfp.gi index 3f5b88c272..6685fed099 100644 --- a/lib/grpfp.gi +++ b/lib/grpfp.gi @@ -5490,10 +5490,10 @@ local G,T,gens,g,reps,ng,index,i,j,ndef,n,iso; IsRightTransversalFpGroupRep and IsList and IsDuplicateFreeList and IsAttributeStoringRep ), rec( group := OG, - subgroup := U, - iso:=iso, - table:=T, - reps:=List(reps,i->PreImagesRepresentativeNC(iso,i)))); + subgroup := U, + iso:=iso, + table:=T, + reps:=List(reps,i->PreImagesRepresentativeNC(iso,i)))); fi; ndef := 1; @@ -5505,16 +5505,16 @@ local G,T,gens,g,reps,ng,index,i,j,ndef,n,iso; #This assumes that reps[j] is already defined - but #this is true because T is 'standardized' ndef := ndef+1; - if ndef=index then - return Objectify( NewType( FamilyObj( OG ), - IsRightTransversalFpGroupRep and IsList and - IsDuplicateFreeList and IsAttributeStoringRep ), - rec( group := OG, - subgroup := U, - iso:=iso, - table:=T, - reps:=List(reps,i->PreImagesRepresentativeNC(iso,i)))); - fi; + if ndef=index then + return Objectify( NewType( FamilyObj( OG ), + IsRightTransversalFpGroupRep and IsList and + IsDuplicateFreeList and IsAttributeStoringRep ), + rec( group := OG, + subgroup := U, + iso:=iso, + table:=T, + reps:=List(reps,i->PreImagesRepresentativeNC(iso,i)))); + fi; fi; od; od; diff --git a/lib/grplatt.gi b/lib/grplatt.gi index 58600584d6..e24dc57f97 100644 --- a/lib/grplatt.gi +++ b/lib/grplatt.gi @@ -2774,7 +2774,7 @@ local fgi,inducedfactorautos,projs,psubs,info,n,l,nl,emb,u,pos, auts:=[]; for i in GeneratorsOfGroup(n) do aut:=GroupHomomorphismByImages(f,f,gens,List(gens,x-> - Image(hom,PreImagesRepresentativeNC(hom,x)^i))); + Image(hom,PreImagesRepresentativeNC(hom,x)^i))); SetIsBijective(aut,true); Add(auts,aut); od; diff --git a/lib/grpnice.gi b/lib/grpnice.gi index b08cd0a3e1..1e19617b72 100644 --- a/lib/grpnice.gi +++ b/lib/grpnice.gi @@ -281,8 +281,8 @@ function( obj1, obj2 ) img := ImagesRepresentative( nice, obj2:actioncanfail:=true ); if img = fail or not (img in ImagesSource(nice) and - PreImagesRepresentativeNC(nice,img)=obj2) then - TryNextMethod(); + PreImagesRepresentativeNC(nice,img)=obj2) then + TryNextMethod(); fi; no:=NiceObject(obj1); img1 := ClosureGroup( NiceObject(obj1), img ); diff --git a/lib/grppcext.gi b/lib/grppcext.gi index b5a7d47b78..8e30dfc20d 100644 --- a/lib/grppcext.gi +++ b/lib/grppcext.gi @@ -379,10 +379,10 @@ local ag, p1iso, agp, p2iso, DP, p1, p2, gens, genimgs, triso,s,i,u,opt, genimgs:=List(gens, i->ImagesRepresentative(Embedding(D,1), PreImagesRepresentativeNC(p1iso, - PreImagesRepresentativeNC(pc1,ImagesRepresentative(p1,i)))) - *ImagesRepresentative(Embedding(D,2), - PreImagesRepresentativeNC(p2iso, - PreImagesRepresentativeNC(pc2,ImagesRepresentative(p2,i)))) ); + PreImagesRepresentativeNC(pc1,ImagesRepresentative(p1,i)))) + *ImagesRepresentative(Embedding(D,2), + PreImagesRepresentativeNC(p2iso, + PreImagesRepresentativeNC(pc2,ImagesRepresentative(p2,i)))) ); else opt:=rec(limit:=s,random:=1); @@ -426,9 +426,9 @@ local ag, p1iso, agp, p2iso, DP, p1, p2, gens, genimgs, triso,s,i,u,opt, genimgs:=List(gens, i->ImagesRepresentative(Embedding(D,1), - PreImagesRepresentativeNC(p1iso,ImagesRepresentative(p1,i))) + PreImagesRepresentativeNC(p1iso,ImagesRepresentative(p1,i))) *ImagesRepresentative(Embedding(D,2), - PreImagesRepresentativeNC(p2iso,ImagesRepresentative(p2,i))) ); + PreImagesRepresentativeNC(p2iso,ImagesRepresentative(p2,i))) ); fi; triso:=GroupHomomorphismByImagesNC(DP,D,gens,genimgs); @@ -712,9 +712,9 @@ local G, M, Mgrp, oper, A, B, D, translate, gens, genimgs, triso, K, K1, Assert(1,MappingGeneratorsImages(epi)[2]=Ggens); f:=function( tup, elm ) local gens; - #gens := List( tup[1], x -> PreImagesRepresentativeNC( elm[1], x ) ); + #gens := List( tup[1], x -> PreImagesRepresentative( elm[1], x ) ); #gens := List( gens, x -> MappedPcElement( x, tup[1], tup[2] ) ); - gens := List( Ggens, x -> PreImagesRepresentativeNC( elm[1], x ) ); + gens := List( Ggens, x->PreImagesRepresentativeNC( elm[1], x ) ); gens := List( gens, x -> MappedWord( PreImagesRepresentativeNC(epi,x), GeneratorsOfGroup(Source(epi)), tup ) ); gens := List( gens, x -> x ^ elm[2] ); @@ -731,7 +731,8 @@ local G, M, Mgrp, oper, A, B, D, translate, gens, genimgs, triso, K, K1, elmlist:=[]; tmp:=List(genimgs,x->x[1]); - preimlist:=List(tmp,x->[x,List(Ggens,y->PreImagesRepresentativeNC(x,y))]); + preimlist:=List(tmp,x->[x,List(Ggens, + y->PreImagesRepresentativeNC(x,y))]); f:=function( tup, elm ) local gens,p; @@ -782,7 +783,8 @@ local G, M, Mgrp, oper, A, B, D, translate, gens, genimgs, triso, K, K1, if elmlist<>fail then tmp:=List(genimgs,x->x[1]); - preimlist:=List(tmp,x->[x,List(Ggens,y->PreImagesRepresentativeNC(x,y))]); + preimlist:=List(tmp,x->[x,List(Ggens, + y->PreImagesRepresentativeNC(x,y))]); # ensure we also account for action u:=Group(tup); @@ -1121,7 +1123,7 @@ BindGlobal( "NonSplitExtensions", function( arg ) # if reduction is suppressed elif IsBound( arg[3] ) and not arg[3] then all := NormedRowVectors( Image(cc.cohom) ); - all := List( all, x -> ExtensionSQ(cohom.collector, G, M, + all := List( all, x -> ExtensionSQ(cohom.collector, G, M, PreImagesRepresentativeNC(cc.cohom,x ))); red := false; @@ -1132,7 +1134,7 @@ BindGlobal( "NonSplitExtensions", function( arg ) and not HasAutomorphismGroup( G ) then all := NormedRowVectors( Image(cc.cohom) ); - all := List( all, x -> ExtensionSQ(cc.collector, G, M, + all := List( all, x -> ExtensionSQ(cc.collector, G, M, PreImagesRepresentativeNC(cc.cohom, x ))); red := false; @@ -1151,7 +1153,7 @@ BindGlobal( "NonSplitExtensions", function( arg ) Info( InfoExtReps, 2, " Ext: found ",Length(all)," orbits "); # create extensions and add info - all := List( all, x -> ExtensionSQ(cc.collector, G, M, + all := List( all, x -> ExtensionSQ(cc.collector, G, M, PreImagesRepresentativeNC(cc.cohom, x ))); fi; diff --git a/lib/grppclat.gi b/lib/grppclat.gi index 336b5fcef5..1476e2bd75 100644 --- a/lib/grppclat.gi +++ b/lib/grppclat.gi @@ -85,8 +85,8 @@ local f; Image( epi, ConjugatorOfConjugatorIsomorphism( aut ) ) ); else aut:= GroupHomomorphismByImagesNC(f,f,GeneratorsOfGroup(f), - List(GeneratorsOfGroup(f), - i->Image(epi,Image(aut,PreImagesRepresentativeNC(epi,i))))); + List(GeneratorsOfGroup(f), + i->Image(epi,Image(aut,PreImagesRepresentativeNC(epi,i))))); SetIsInjective(aut,true); SetIsSurjective(aut,true); fi; @@ -672,7 +672,7 @@ local g, # group # hom:=[]; # for i in func do # hom2:=GroupHomomorphismByImagesNC(g,g,g.generators,List(g.generators, -# j->Image(isom,Image(i,PreImagesRepresentative(isom,j))))); +# j->Image(isom,Image(i,PreImagesRepresentativeNC(isom,j))))); # hom2.isMapping:=true; # Add(hom,hom2); # od; @@ -788,7 +788,7 @@ local g, # group hom:= GroupHomomorphismByImagesNC(f,fa,GeneratorsOfGroup(f), List(GeneratorsOfGroup(f),i-> - Image(hom,PreImagesRepresentativeNC(epi,i)))); + Image(hom,PreImagesRepresentativeNC(epi,i)))); Assert(2,KernelOfMultiplicativeGeneralMapping(hom)=n); # lift the known groups diff --git a/lib/mapprep.gi b/lib/mapprep.gi index 6b0cdd3444..0c106745f3 100644 --- a/lib/mapprep.gi +++ b/lib/mapprep.gi @@ -1067,7 +1067,7 @@ InstallMethod( PreImagesElmNC, ############################################################################# ## -#M PreImagesSetNC( , ) . . for inverse mapping and collection +#M PreImagesSetNC( , ) . for inverse mapping and collection ## InstallMethod( PreImagesSetNC, "for an inverse mapping and a collection", @@ -1293,7 +1293,7 @@ InstallMethod( PreImageElm, ############################################################################# ## -#M PreImagesElmNC( , ) . . . . for identity mapping and element +#M PreImagesElmNC( , ) . . . for identity mapping and element ## InstallMethod( PreImagesElmNC, "for identity mapping and object", @@ -1581,7 +1581,7 @@ InstallMethod( ImagesRepresentative, ############################################################################# ## -#M PreImagesElmNC( , ) . . . . . for zero mapping and element +#M PreImagesElmNC( , ) . . . . for zero mapping and element ## InstallMethod( PreImagesElmNC, "for zero mapping and object", diff --git a/lib/maxsub.gi b/lib/maxsub.gi index d8e7616425..c4b01c0cda 100644 --- a/lib/maxsub.gi +++ b/lib/maxsub.gi @@ -182,7 +182,7 @@ BindGlobal("MaximalSubgroupClassesSol",function(G) sel:=Filtered([1..Length(mgi[2])],x->not IsOne(mgi[2][x])); if 4^Length(sel)>Size(Range(ff.factorhom)) then f:=SmallGeneratingSet(Image(ff.factorhom)); - mgi:=[List(f,x->PreImagesRepresentative(ff.factorhom,x)),f]; + mgi:=[List(f,x->PreImagesRepresentativeNC(ff.factorhom,x)),f]; sel:=[1..Length(mgi[1])]; fi; gensG:=mgi[1]{sel}; @@ -196,7 +196,7 @@ BindGlobal("MaximalSubgroupClassesSol",function(G) # just in case the stored group generators differ... wordfpgens:=List(wordgens,x->ElementOfFpGroup(fam,x)); wordpre:=List(wordfpgens,x->PreImagesRepresentativeNC(ff.factorhom, - PreImagesRepresentativeNC(fphom,x))); + PreImagesRepresentativeNC(fphom,x))); fphom:=ff.factorhom*fphom; # no assertion as this is not a proper homomorphism, but an inverse # multiplicative map @@ -699,7 +699,7 @@ local m, fact, fg, reps, ma, idx, nm, embs, proj, kproj, k, ag, agl, ug, # type 4c reps:=List([1..n], - i->PreImagesRepresentativeNC(fact,RepresentativeAction(fg,1,i))); + i->PreImagesRepresentativeNC(fact,RepresentativeAction(fg,1,i))); # get the maximal subgroups of A, intersect with t to get the socle part @@ -758,8 +758,8 @@ local m, fact, fg, reps, ma, idx, nm, embs, proj, kproj, k, ag, agl, ug, #phi:=ActionHomomorphism(fg,u.orbit,OnSets); #ue:=Image(phi,fg); #reps:=List([1..nlb],i->RepresentativeAction(ue,1,i)); - #reps:=List(reps,i->PreImagesRepresentativeNC(phi,i)); - #reps:=List(reps,i->PreImagesRepresentativeNC(fact,i)); + #reps:=List(reps,i->PreImagesRepresentative(phi,i)); + #reps:=List(reps,i->PreImagesRepresentative(fact,i)); #u:=u.stabilizer; uphi:=ActionHomomorphism(Image(fact,u),b); diff --git a/lib/morpheus.gi b/lib/morpheus.gi index 1d80e1a3c4..ee25f26a35 100644 --- a/lib/morpheus.gi +++ b/lib/morpheus.gi @@ -2102,8 +2102,8 @@ local d,id,H,iso,aut,auts,i,all,hom,field,dim,P,diag,mats,gens,gal; iso:=IsomorphismGroups(G,H); fi; aut:=GroupGeneralMappingByImages(G,G,gens, - List(gens, - x->PreImagesRepresentativeNC(iso,Image(iso,x)^(1,2)))); + List(gens, + x->PreImagesRepresentativeNC(iso,Image(iso,x)^(1,2)))); auts:=[aut]; all:=true; fi; @@ -2163,9 +2163,9 @@ local d,id,H,iso,aut,auts,i,all,hom,field,dim,P,diag,mats,gens,gal; od; fi; auts:=Concatenation(auts, - List(mats,s->GroupGeneralMappingByImages(G,G,gens,List(gens,x-> - Image(hom,PreImagesRepresentativeNC(hom,x)^s))))); - + List(mats,s->GroupGeneralMappingByImages(G,G,gens,List(gens,x-> + Image(hom,PreImagesRepresentativeNC(hom,x)^s))))); + else gal:=Group(()); # to force trivial fi; @@ -2173,10 +2173,10 @@ local d,id,H,iso,aut,auts,i,all,hom,field,dim,P,diag,mats,gens,gal; if Size(gal)>1 then # Galois auts:=Concatenation(auts, - List(MinimalGeneratingSet(gal), - s->GroupGeneralMappingByImages(G,G,gens,List(gens,x-> - Image(hom, - List(PreImagesRepresentativeNC(hom,x),r->List(r,y->Image(s,y)))))))); + List(MinimalGeneratingSet(gal), + s->GroupGeneralMappingByImages(G,G,gens,List(gens,x-> + Image(hom, + List(PreImagesRepresentativeNC(hom,x),r->List(r,y->Image(s,y)))))))); fi; # graph @@ -2344,12 +2344,12 @@ InstallGlobalFunction(AutomorphismGroupFittingFree,function(g) a:=acts[i[j][1]][3]; genimgs:=[]; for gen in GeneratorsOfGroup(a) do - thom:=i[j][2]; - thom:=GroupHomomorphismByImagesNC(t,t,GeneratorsOfGroup(t), - List(GeneratorsOfGroup(t), - j->Image(thom,PreImagesRepresentativeNC(thom,j)^gen))); - thom:=Image(auph,thom); - Add(genimgs,thom); + thom:=i[j][2]; + thom:=GroupHomomorphismByImagesNC(t,t,GeneratorsOfGroup(t), + List(GeneratorsOfGroup(t), + j->Image(thom,PreImagesRepresentativeNC(thom,j)^gen))); + thom:=Image(auph,thom); + Add(genimgs,thom); od; ahom:=GroupHomomorphismByImagesNC(a,aup,GeneratorsOfGroup(a),genimgs); @@ -2404,8 +2404,8 @@ InstallGlobalFunction(AutomorphismGroupFittingFree,function(g) gens:=SmallGeneratingSet(aup); for i in gens do au:=GroupHomomorphismByImages(g,g,GeneratorsOfGroup(g), - List(GeneratorsOfGroup(g), - j->PreImagesRepresentativeNC(emb,Image(emb,j)^i))); + List(GeneratorsOfGroup(g), + j->PreImagesRepresentativeNC(emb,Image(emb,j)^i))); Add(a,au); od; au:=Group(a); @@ -2446,7 +2446,7 @@ InstallGlobalFunction(AutomorphismGroupFittingFree,function(g) bi:=[]; for i in newbas do s:=List(stbs[i], - x->Image(emb,Image(autom,PreImagesRepresentativeNC(emb,x)))); + x->Image(emb,Image(autom,PreImagesRepresentativeNC(emb,x)))); s:=First(orb[orpo[i]],x->ForAll(s,j->x^j=x)); Add(bi,s); od; diff --git a/lib/norad.gi b/lib/norad.gi index 7f44100ea1..6323d1070d 100644 --- a/lib/norad.gi +++ b/lib/norad.gi @@ -143,46 +143,46 @@ local d,orb,len,S,depths,rel,stb,img,pos,i,j,k,ii,po,rep,sg,sf,sfs,fr,first, for k in [i+1..i+po-1] do img:=act(orb[k],acts[j]); #F if LookupDictionary(d,img)<>fail then Error("err3");fi; - Add(orb,img); - AddDictionary(d,img,Length(orb)); - od; - - # should we give in? - if Length(orb)>brutelimit then - - orb:=[];d:=1; #clean memory - - # projective action is fine, as we want to fix space - Info(InfoFitFree,1,"act on whole space, fix in perm action"); - permact:=Action(GroupWithGenerators(Concatenation(acts,pcgsacts)), - induce.allobj,induce.allact); - i:=Concatenation( - List([1..Length(gens)], x->DirectProductElement([gens[x],imgs[x]])), - List(pcgs, x->DirectProductElement([x,One(imgs[1])]))); - pacthom:=GroupHomomorphismByImagesNC(GroupWithGenerators(i),permact,i, - GeneratorsOfGroup(permact)); - - lpos:=List(induce.lvecs,x->Position(induce.allobj,x)); - - # we don't care about the actual subgroup, just the inducing elements - good:=[]; - goodi:=SubgroupProperty(induce.subact, - function(x) - local r; - r:=RepresentativeAction(permact,lpos,Permuted(lpos,x),OnTuples); - if r<>fail then Add(good,r);fi; - return r<>fail; - end); - good:=List(good,x->PreImagesRepresentativeNC(pacthom,x)); - - good:=Filtered(good,x->not IsOne(x[2])); - - return rec(byinduced:=true, - gens:=List(good,x->x[1]),imgs:=List(good,x->x[2]), - pcgs:=Reversed(S)); - - fi; - + Add(orb,img); + AddDictionary(d,img,Length(orb)); + od; + + # should we give in? + if Length(orb)>brutelimit then + + orb:=[];d:=1; #clean memory + + # projective action is fine, as we want to fix space + Info(InfoFitFree,1,"act on whole space, fix in perm action"); + permact:=Action(GroupWithGenerators(Concatenation(acts,pcgsacts)), + induce.allobj,induce.allact); + i:=Concatenation( + List([1..Length(gens)], x->DirectProductElement([gens[x],imgs[x]])), + List(pcgs, x->DirectProductElement([x,One(imgs[1])]))); + pacthom:=GroupHomomorphismByImagesNC(GroupWithGenerators(i),permact,i, + GeneratorsOfGroup(permact)); + + lpos:=List(induce.lvecs,x->Position(induce.allobj,x)); + + # we don't care about the actual subgroup, just the inducing elements + good:=[]; + SubgroupProperty(induce.subact, + function(x) + local r; + r:=RepresentativeAction(permact,lpos,Permuted(lpos,x),OnTuples); + if r<>fail then Add(good,r);fi; + return r<>fail; + end); + good:=List(good,x->PreImagesRepresentativeNC(pacthom,x)); + + good:=Filtered(good,x->not IsOne(x[2])); + + return rec(byinduced:=true, + gens:=List(good,x->x[1]),imgs:=List(good,x->x[2]), + pcgs:=Reversed(S)); + + fi; + else # get stabilizing element blp:=QuoInt((pos-1),po)+1; # which block position are we? @@ -416,10 +416,10 @@ local sus,ser,len,factorhom,uf,n,d,up,mran,nran,mpcgs,pcgs,pcisom,nf,ng,np,sub, glhom:=IsomorphismPermGroup(localgl); glperm:=Image(glhom); glact:=ActionHomomorphism(glperm,lvecs, - GeneratorsOfGroup(glperm), - List(GeneratorsOfGroup(glperm), - x->PreImagesRepresentativeNC(glhom,x)), - OnLines,"surjective"); + GeneratorsOfGroup(glperm), + List(GeneratorsOfGroup(glperm), + x->PreImagesRepresentativeNC(glhom,x)), + OnLines,"surjective"); stb:=Image(glact); for clu in localclust do stb:=Stabilizer(stb,clu,OnSets); diff --git a/lib/onecohom.gi b/lib/onecohom.gi index a581680fec..9f9b131f60 100644 --- a/lib/onecohom.gi +++ b/lib/onecohom.gi @@ -128,7 +128,7 @@ local hom,fg,fpi,fpg,nt,fam; fpg:=FreeGeneratorsOfFpGroup(Range(hom)); ocr.factorpres:=[fpg,RelatorsOfFpGroup(Range(hom))]; ocr.generators:=List(GeneratorsOfGroup(Range(hom)), - i->PreImagesRepresentativeNC(hom,i)); + i->PreImagesRepresentativeNC(hom,i)); else if (Index(ocr.group,nt)>Size(nt)^3 @@ -158,11 +158,10 @@ local hom,fg,fpi,fpg,nt,fam; fi; fpg:=FreeGeneratorsOfFpGroup(Range(fpi)); ocr.factorpres:=[fpg,RelatorsOfFpGroup(Range(fpi)), - List(GeneratorsOfGroup(Range(fpi)), - i->PreImagesRepresentativeNC(fpi,i))]; + List(GeneratorsOfGroup(Range(fpi)), + i->PreImagesRepresentativeNC(fpi,i))]; if not IsBound(ocr.generators) then - ocr.generators:=List(ocr.factorpres[3], - i->PreImagesRepresentativeNC(hom,i)); + ocr.generators:=List(ocr.factorpres[3],i->PreImagesRepresentativeNC(hom,i)); fi; diff --git a/lib/oprt.gi b/lib/oprt.gi index ab12a94889..882014725f 100644 --- a/lib/oprt.gi +++ b/lib/oprt.gi @@ -2921,7 +2921,7 @@ local G, D, d, e, gens, acts, act, xset, hom, p, rep; rep := RepresentativeActionOp( ImagesSource( hom ), d, e, OnPoints ); if rep <> fail then - rep := PreImagesRepresentativeNC( hom, rep ); + rep := PreImagesRepresentativeNC( hom, rep ); fi; return rep; elif IsBound( D ) then diff --git a/lib/relation.gi b/lib/relation.gi index b1aacf486a..b1b0981dec 100644 --- a/lib/relation.gi +++ b/lib/relation.gi @@ -605,12 +605,12 @@ InstallMethod(HasseDiagramBinaryRelation, ## return the minimal elements of a list under rel HDBRMinElts := function(list, rel) - - ## x minimal if - ## {y in list | y<>x and y in PreImagesElmNC(rel,x)} is empty + + ## x minimal if + ## {y in list | y<>x and y in PreImagesElmNC( rel,x)} is empty ## return Filtered(list, - x->IsEmpty(Filtered(list, y-> (y <> x) and + x->IsEmpty(Filtered(list, y-> (y <> x) and (y in PreImagesElmNC(rel,x))))); end; @@ -1781,7 +1781,7 @@ InstallMethod( ImagesRepresentative, "equivalence relations", ############################################################################# ## -#M PreImagesRepresentativeNC( , ) . . for equivalence relations +#M PreImagesRepresentativeNC( , ) . . . for equivalence relations ## InstallMethod( PreImagesRepresentativeNC, "equivalence relations", FamRangeEqFamElm, [IsEquivalenceRelation, IsObject], 0, diff --git a/lib/schur.gi b/lib/schur.gi index 78fa794be6..f06590728d 100644 --- a/lib/schur.gi +++ b/lib/schur.gi @@ -257,13 +257,14 @@ local s,pcgs,n,l,cov,pco,ng,gens,imgs,ran,zer,i,j,e,a, if Order(dc[i])>1 then # the trivial element will not do anything q:=Intersection(s,ConjugateSubgroup(s,dc[i]^-1)); if Size(q)>1 then - qs:=PreImage(epi,q); - # factor generators - gens:=GeneratorsOfGroup(qs); - # their conjugates - imgs:=List(gens,j->PreImagesRepresentativeNC(epi,Image(epi,j)^dc[i])); - rels:=ClosureGroup(rels,CommutGenImgs(pco,gens,imgs, - Intersection(mul,DerivedSubgroup(qs)))); + qs:=PreImage(epi,q); + # factor generators + gens:=GeneratorsOfGroup(qs); + # their conjugates + imgs:=List(gens, + j->PreImagesRepresentativeNC(epi,Image(epi,j)^dc[i])); + rels:=ClosureGroup(rels,CommutGenImgs(pco,gens,imgs, + Intersection(mul,DerivedSubgroup(qs)))); fi; fi; i:=i+1; @@ -394,20 +395,20 @@ local G,H,D,T,i,j,k,l,a,h,nk,evals,rels,gens,r,np,g,invlist,el,elp,TL,rp,pos; k:=T[j]; h:=One(D); for l in i do - if l<0 then - g:=Inverse(gens[-l]); - else - g:=gens[l]; - fi; - np:=k*g; - nk:=TL[PositionCanonical(T,np)]; - #h:=h*PreImagesRepresentativeNC(s,np/nk); - h:=h*elp[Position(el,np/nk)]; - k:=nk; + if l<0 then + g:=Inverse(gens[-l]); + else + g:=gens[l]; + fi; + np:=k*g; + nk:=TL[PositionCanonical(T,np)]; + #h:=h*PreImagesRepresentative(s,np/nk); + h:=h*elp[Position(el,np/nk)]; + k:=nk; od; - #Print(PreImagesRepresentativeNC(s,Image(s,h))*h,"\n"); - #a:=a/PreImagesRepresentativeNC(s,Image(s,h))*h; + #Print(PreImagesRepresentative(s,Image(s,h))*h,"\n"); + #a:=a/PreImagesRepresentative(s,Image(s,h))*h; a:=a/h*elp[Position(el,Image(s,h))]; od; @@ -558,7 +559,7 @@ local hom, #isomorphism fp s:=sl[pp]; mg:=IsomorphismPermGroup(KernelOfMultiplicativeGeneralMapping(s)); mg:=List(IndependentGeneratorsOfAbelianGroup(Image(mg)), - i->PreImagesRepresentativeNC(mg,i)); + i->PreImagesRepresentativeNC(mg,i)); sdc:=ListWithIdenticalEntries(Last(ngl),One(Source(s))); sdc{[ngl[pp]+1..ngl[pp+1]]}:=mg; From 0df089c92d1a65d766dec794ba30345fea1b291f Mon Sep 17 00:00:00 2001 From: cdwensley Date: Mon, 27 Nov 2023 17:52:15 +0000 Subject: [PATCH 015/234] ~use latest fitfree.gd --- lib/fitfree.gd | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/fitfree.gd b/lib/fitfree.gd index e4a556ac83..c284d7259c 100644 --- a/lib/fitfree.gd +++ b/lib/fitfree.gd @@ -92,7 +92,7 @@ DeclareGlobalFunction("AttemptPermRadicalMethod"); ## the image group being ## represented in a way that decomposition into generators will work ## efficiently. In particular, it is possible to use -## to take the pre-image of elements +## to take the pre-image of elements ## in the image. For a subgroup U\le G, it is possible to apply ## to the homomorphism to obtain a ## corresponding homomorphism for U. From 82b0d5354ce43413968b73b702ad53704e78e04d Mon Sep 17 00:00:00 2001 From: cdwensley Date: Tue, 28 Nov 2023 16:28:01 +0000 Subject: [PATCH 016/234] using latesxt version of 5 files --- lib/clashom.gi | 10 +++++----- lib/ghomfp.gd | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/lib/clashom.gi b/lib/clashom.gi index 1c4844545a..7d269b4337 100644 --- a/lib/clashom.gi +++ b/lib/clashom.gi @@ -1292,7 +1292,7 @@ local cs, # chief series of G # define isomorphisms between the components reps:=List([1..n],i-> - PreImagesRepresentativeNC(Qhom,RepresentativeActionNC(Q,1,i))); + PreImagesRepresentativeNC(Qhom,RepresentativeAction(Q,1,i))); genimages:=[]; for j in GeneratorsOfGroup(G) do @@ -1645,14 +1645,14 @@ BindGlobal("LiftClassesEANonsolvGeneral", h, # preimage `cl.representative' under cg, cNh, # centralizer of in - gens, # preimage `Centralizer( cl )' under + gens, # preimage `Centralizer( cl )' under r, # dimension of ran, # constant range `[ 1 .. r ]' aff, # as affine space imgs, M, # generating matrices for affine operation orb, # orbit of affine operation - rep, # set of classes with canonical representatives - c, i, # loop variables + rep,# set of classes with canonical representatives + c, i, # loop variables PPcgs,denomdepths, correctionfactor, stabfacgens, @@ -1961,7 +1961,7 @@ local classes, # classes to be constructed, the result c := [h * PcElementByExponentsNC( Npcgs,w*com.factorspace), stabrad,stabfacgens,stabfacimg,subsz,stabrsubsz]; #if reduce<>fail then - # Add(classes,[PreImagesRepresentativeNC(reduce,c[1]), + # Add(classes,[PreImagesRepresentative(reduce,c[1]), # PreImage(reduce,c[2])]); # else diff --git a/lib/ghomfp.gd b/lib/ghomfp.gd index f2e534c3d7..457f5f2640 100644 --- a/lib/ghomfp.gd +++ b/lib/ghomfp.gd @@ -264,7 +264,7 @@ DeclareAttribute("IsomorphismSimplifiedFpGroup",IsSubgroupFpGroup); ## Group([ (1,2,3,4), (1,2) ]) ## gap> hom:=EpimorphismFromFreeGroup(g:names:=["x","y"]); ## [ x, y ] -> [ (1,2,3,4), (1,2) ] -## gap> PreImagesRepresentativeNC(hom,(1,4)); +## gap> PreImagesRepresentative(hom,(1,4)); ## y^-1*x^-1*(x^-1*y^-1)^2*x ## ]]> ##

@@ -279,7 +279,7 @@ DeclareAttribute("IsomorphismSimplifiedFpGroup",IsSubgroupFpGroup); ## gap> puzzle := Group( perms );;Size( puzzle ); ## 20922789888000 ## gap> hom:=EpimorphismFromFreeGroup(puzzle:names:=["a", "b", "c", "d"]);; -## gap> word := PreImagesRepresentativeNC( hom, (1,2) ); +## gap> word := PreImagesRepresentative( hom, (1,2) ); ## a^-1*c*b*c^-1*a*b^-1*a^-2*c^-1*a*b^-1*c*b ## gap> Length( word ); ## 13 From c779c1137834e03ece1322b2afd9f03b74f5c0bb Mon Sep 17 00:00:00 2001 From: cdwensley Date: Wed, 29 Nov 2023 20:52:30 +0000 Subject: [PATCH 017/234] updating ghomfp.gi --- lib/ghomfp.gi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/ghomfp.gi b/lib/ghomfp.gi index 59be7fcbd5..d9e46e4a03 100644 --- a/lib/ghomfp.gi +++ b/lib/ghomfp.gi @@ -441,7 +441,7 @@ local q,r,tg,dtg,pemb,ugens,g,gi,d,o,gens,genims,i,gr,img,l,mapi; #better: orbit algo #r:=ShallowCopy(RightTransversal(q,qu)); #Sort(r,function(a,b) return 1^a<1^b;end); - #r:=List(r,i->PreImagesRepresentative(beta,i)); + #r:=List(r,i-> Representative(beta,i)); # compute transversal with short words from orbit algorithm on points o:=[1]; From 2102235593c66e7eafcfa381b21e717a56c59eab Mon Sep 17 00:00:00 2001 From: cdwensley Date: Wed, 29 Nov 2023 20:59:19 +0000 Subject: [PATCH 018/234] updating ctblgrp.gi --- lib/ctblgrp.gi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/ctblgrp.gi b/lib/ctblgrp.gi index bc9db6ad24..20ca45dd0c 100644 --- a/lib/ctblgrp.gi +++ b/lib/ctblgrp.gi @@ -1804,7 +1804,7 @@ local often,trans,e,neu,i,inv,cent,l,s,s1,x,dom; if dom=fail then x:=D.classreps[inv]; - l:=List(s,i->[x^PreImagesRepresentative(e, + l:=List(s,i->[x^PreImagesRepresentativeNC(e, RepresentativeAction(Image(e),1,i[1])),Size(cent)*Length(i)]); else l:=List(s,i->[dom[i[1]],Size(cent)*Length(i)]); From c2b8428728a2e0603771897498151d2fb6cbfd35 Mon Sep 17 00:00:00 2001 From: cdwensley Date: Sat, 2 Dec 2023 18:10:59 +0000 Subject: [PATCH 019/234] remove some trailing spaces --- lib/clashom.gi | 6 +----- lib/mapping.gd | 34 +++++++++++++++++----------------- lib/mapping.gi | 28 ++++++++++++++-------------- 3 files changed, 32 insertions(+), 36 deletions(-) diff --git a/lib/clashom.gi b/lib/clashom.gi index 7d269b4337..d262a87eba 100644 --- a/lib/clashom.gi +++ b/lib/clashom.gi @@ -781,12 +781,7 @@ local clT, # classes T Info(InfoHomClass,5,"Minimum length of this orbit ", minlen," (",diff," missing)"); - fi; - if minlen*Size(stab)=Size(centralizers[j]) then - #Assert(1,Length(smacla)>0); - maxdiff:=diff; - stabtrue:=true; fi; if minlen*Size(stab)=Size(centralizers[j]) then @@ -794,6 +789,7 @@ local clT, # classes T maxdiff:=diff; stabtrue:=true; fi; + elif not stabtrue then # we have an element that stabilizes the conjugacy class. # correct this to an element that fixes the representative. diff --git a/lib/mapping.gd b/lib/mapping.gd index 47633ba10f..1041a336a5 100644 --- a/lib/mapping.gd +++ b/lib/mapping.gd @@ -1218,36 +1218,36 @@ DeclareGlobalFunction( "PreImage" ); ## (If coll and the result are lists then the positions of ## entries do in general not correspond.) ##

-## ## delegates to when ## called with one argument, ## and to resp. when ## called with two arguments. -## The corresponding PreImagesNC delegates to PreImagesRange +## The corresponding PreImagesNC delegates to PreImagesRange ## and PreImagesSetNC. ##

## If the second argument is not an element or a subset of the range of -## the first argument, incorrect results may be returned. -## In order to improve this state of affairs, -## PreImages has been renamed PreImagesNC throughout the library, -## and PreImages has been declared a synonym for PreImagesNC. -##

-## In future versions of &GAP; PreImages -## will perform additional checks and reject invalid inputs. -## These additional checks will slow the computation so, -## when the inputs are known to be valid by construction, -## users are recommended to use PreImagesNC. -##

-## Package authors are asked to convert their methods for -## PreImages to methods for PreImagesNC. -## Only when this has happened will the additional checks be implemented. +## the first argument, incorrect results may be returned. +## In order to improve this state of affairs, +## PreImages has been renamed PreImagesNC throughout the library, +## and PreImages has been declared a synonym for PreImagesNC. +##

+## In future versions of &GAP; PreImages +## will perform additional checks and reject invalid inputs. +## These additional checks will slow the computation so, +## when the inputs are known to be valid by construction, +## users are recommended to use PreImagesNC. +##

+## Package authors are asked to convert their methods for +## PreImages to methods for PreImagesNC. +## Only when this has happened will the additional checks be implemented. ## ## ## <#/GAPDoc> ## DeclareGlobalFunction( "PreImagesNC" ); -DeclareSynonym( "PreImages", PreImagesNC ); +DeclareSynonym( "PreImages", PreImagesNC ); diff --git a/lib/mapping.gi b/lib/mapping.gi index 26b3d63855..99beb95a48 100644 --- a/lib/mapping.gi +++ b/lib/mapping.gi @@ -297,11 +297,11 @@ end ); ############################################################################# ## -#F PreImages() +#F PreImages() #F PreImagesNC() . . . set of preimages of the range of a gen. mapping -#F PreImages(,) +#F PreImages(,) #F PreImagesNC(,) set of preimages of an elm under a gen. mapping -#F PreImages(,) +#F PreImages(,) #F PreImagesNC(,) set of preimages of a coll. under a gen. mapping ## InstallGlobalFunction( PreImagesNC, function ( arg ) @@ -1178,11 +1178,11 @@ InstallMethod( PreImagesRange, ## FamRangeEqFamElm, ## [ IsSPGeneralMapping, IsObject ], 0, ## function( map, elm ) -## test will be included at a later stage of the change of name -## if not elm in Image( map ) then -## return fail; -## fi; -## return PreImagesRepresentativeNC( map, elm ); +## test will be included at a later stage of the change of name +## if not elm in Image( map ) then +## return fail; +## fi; +## return PreImagesRepresentativeNC( map, elm ); ## end ); InstallMethod( PreImagesRepresentativeNC, @@ -1203,12 +1203,12 @@ InstallMethod( PreImagesRepresentativeNC, ## "for total non-s.p. general mapping, and element", ## FamRangeEqFamElm, ## [ IsNonSPGeneralMapping, IsObject ], 0, -## function( map, elm ) -## test will be included at a later stage of the change of name -## if not elm in Image( map ) then -## return fail; -## fi; -## return PreImagesRepresentativeNC( map, elm ); +## function( map, elm ) +## test will be included at a later stage of the change of name +## if not elm in Image( map ) then +## return fail; +## fi; +## return PreImagesRepresentativeNC( map, elm ); ## end ); InstallMethod( PreImagesRepresentativeNC, From 5aa02443c707f408cc22b30b9a1d5d3dc1e1c5d7 Mon Sep 17 00:00:00 2001 From: cdwensley Date: Sat, 2 Dec 2023 18:25:39 +0000 Subject: [PATCH 020/234] removed some trailing spaces --- lib/mapping.gd | 64 +++++++++++++++++++++++++------------------------- 1 file changed, 32 insertions(+), 32 deletions(-) diff --git a/lib/mapping.gd b/lib/mapping.gd index 1041a336a5..15ce08a83a 100644 --- a/lib/mapping.gd +++ b/lib/mapping.gd @@ -1051,22 +1051,22 @@ DeclareOperation( "PreImageElm", ## Anything may happen if elm is not an element of the range of ## map. ##

-## In order to improve this state of affairs, -## PreImagesRepresentative has been renamed -## PreImagesRepresentativeNC throughout the library, -## and PreImagesRepresentative has been declared a synonym for -## PreImagesRepresentativeNC. +## In order to improve this state of affairs, +## PreImagesRepresentative has been renamed +## PreImagesRepresentativeNC throughout the library, +## and PreImagesRepresentative has been declared a synonym for +## PreImagesRepresentativeNC. ##

-## In future versions of &GAP; PreImagesRepresentative -## will perform additional checks and reject invalid inputs. -## These additional checks will slow the computation so, -## when the inputs are known to be valid by construction, -## users are recommended to use PreImagesRepresentativeNC. +## In future versions of &GAP; PreImagesRepresentative +## will perform additional checks and reject invalid inputs. +## These additional checks will slow the computation so, +## when the inputs are known to be valid by construction, +## users are recommended to use PreImagesRepresentativeNC. ##

-## Package authors are asked to convert their methods for -## PreImagesRepresentative to methods for -## PreImagesRepresentativeNC. -## Only when this has happened will the additional checks be implemented. +## Package authors are asked to convert their methods for +## PreImagesRepresentative to methods for +## PreImagesRepresentativeNC. +## Only when this has happened will the additional checks be implemented. ## ## ## <#/GAPDoc> @@ -1096,26 +1096,26 @@ DeclareSynonym( "PreImagesRepresentative", PreImagesRepresentativeNC ); ## Anything may happen if elms is not a subset of the range of ## map. ##

-## In order to improve this state of affairs, -## PreImagesSet has been renamed PreImagesSetNC -## throughout the library, and -## PreImagesSet has been declared a synonym for PreImagesSetNC. +## In order to improve this state of affairs, +## PreImagesSet has been renamed PreImagesSetNC +## throughout the library, and +## PreImagesSet has been declared a synonym for PreImagesSetNC. ##

-## In future versions of &GAP; PreImagesSet -## will perform additional checks and reject invalid inputs. -## These additional checks will slow the computation so, -## when the inputs are known to be valid by construction, -## users are recommended to use PreImagesSetNC. +## In future versions of &GAP; PreImagesSet +## will perform additional checks and reject invalid inputs. +## These additional checks will slow the computation so, +## when the inputs are known to be valid by construction, +## users are recommended to use PreImagesSetNC. ##

-## Package authors are asked to convert their methods for -## PreImagesSet to methods for PreImagesSetNC. -## Only when this has happened will the additional checks be implemented. +## Package authors are asked to convert their methods for +## PreImagesSet to methods for PreImagesSetNC. +## Only when this has happened will the additional checks be implemented. ## ## ## <#/GAPDoc> ## DeclareOperation( "PreImagesSetNC", [ IsGeneralMapping, IsListOrCollection ] ); -DeclareSynonym( "PreImagesSet", PreImagesSetNC ); +DeclareSynonym( "PreImagesSet", PreImagesSetNC ); ############################################################################# @@ -1159,9 +1159,9 @@ DeclareSynonym( "PreImagesSet", PreImagesSetNC ); ## (If coll and the result are lists then the positions of ## entries do in general not correspond.) ##

-## -## delegates to when called with one argument, +## delegates to when called with one argument, ## and to resp. when ## called with two arguments. ##

@@ -1176,11 +1176,11 @@ DeclareGlobalFunction( "PreImage" ); ############################################################################# ## -#F PreImages() +#F PreImages() #F PreImagesNC() . . . set of preimages of the range of a gen. mapping -#F PreImages(,) +#F PreImages(,) #F PreImagesNC(,) set of preimages of an elm under a gen. mapping -#F PreImages(,) +#F PreImages(,) #F PreImagesNC(,) set of preimages of a coll. under a gen. mapping ## ## <#GAPDoc Label="PreImages"> From 08ccfdd2a1f17d83d04d0746a81dbb634db5e49e Mon Sep 17 00:00:00 2001 From: cdwensley Date: Sat, 2 Dec 2023 20:18:08 +0000 Subject: [PATCH 021/234] fixing problems reported by LINT --- lib/alghom.gi | 2 +- lib/algrep.gd | 8 +++--- lib/clashom.gi | 74 ++++++++++++++++++++++++------------------------- lib/ghomperm.gi | 2 +- lib/grplatt.gi | 56 ++++++++++++++++++------------------- lib/grppcaut.gi | 4 +-- lib/mapping.gd | 36 ++++++++++++------------ 7 files changed, 91 insertions(+), 91 deletions(-) diff --git a/lib/alghom.gi b/lib/alghom.gi index 2206697003..e502f628d2 100644 --- a/lib/alghom.gi +++ b/lib/alghom.gi @@ -586,7 +586,7 @@ InstallMethod( PreImagesRepresentativeNC, [ IsGeneralMapping and IsAlgebraGeneralMappingByImagesDefaultRep, IsObject ], function( map, elm ) - return PreImagesRepresentativeNC( + return PreImagesRepresentativeNC( AsLeftModuleGeneralMappingByImages(map), elm ); end ); diff --git a/lib/algrep.gd b/lib/algrep.gd index 6f65ddbe5f..22cd2f400b 100644 --- a/lib/algrep.gd +++ b/lib/algrep.gd @@ -697,11 +697,11 @@ DeclareOperation( "ModuleByRestriction", [ IsAlgebraModule, IsAlgebra ] ); ## ## ## -## Here V must be a sub-algebra module of V. +## Here V must be a sub-algebra module of V. ## This function returns -## the projection from V onto V/W. -## It is a linear map, that is also a module homomorphism. -## As usual images can be formed with Image( f, v ) +## the projection from V onto V/W. +## It is a linear map, that is also a module homomorphism. +## As usual images can be formed with Image( f, v ) ## and pre-images with PreImagesRepresentativeNC( f, u ). ##

## The quotient module can also be formed diff --git a/lib/clashom.gi b/lib/clashom.gi index d262a87eba..b3e09fa718 100644 --- a/lib/clashom.gi +++ b/lib/clashom.gi @@ -790,43 +790,43 @@ local clT, # classes T stabtrue:=true; fi; - elif not stabtrue then - # we have an element that stabilizes the conjugacy class. - # correct this to an element that fixes the representative. - # (As we have taken already the centralizer in - # centralizers_r, it is sufficient to correct by - # centralizers_r-conjugation.) - con:=trans[orpo]*gen; - limg:=opfun(repres,con); - con:=con*PreImagesRepresentativeNC(centrhom, - RepresentativeAction(localcent_r, - Image(projections[i],limg), - Representative(orb[p][3]))); - stab:=ClosureGroup(stab,con/trans[p]); - if Size(stab)*2*minlen>Size(centralizers[j]) then - Info(InfoHomClass,3, - "true stabilizer found (cannot grow)"); - minlen:=Size(centralizers[j])/Size(stab); - maxdiff:=minlen-Sum(orb,i->Size(i[3])); - stabtrue:=true; - fi; - fi; - - if stabtrue then - - smacla:=Filtered(select,i->Size(clTR[i][3])<=maxdiff); - - if Length(smacla)Size(i[3])); - - CompletionBar(InfoHomClass,3,"trueorb ",1-maxdiff/minlen); - #Info(InfoHomClass,3, - # "This is the true orbit length (missing ", - # maxdiff,")"); - - if Size(stab)*Sum(orb,i->Size(i[3])) - =Size(centralizers[j]) then + elif not stabtrue then + # we have an element that stabilizes the conjugacy class. + # correct this to an element that fixes the representative. + # (As we have taken already the centralizer in + # centralizers_r, it is sufficient to correct by + # centralizers_r-conjugation.) + con:=trans[orpo]*gen; + limg:=opfun(repres,con); + con:=con*PreImagesRepresentativeNC(centrhom, + RepresentativeAction(localcent_r, + Image(projections[i],limg), + Representative(orb[p][3]))); + stab:=ClosureGroup(stab,con/trans[p]); + if Size(stab)*2*minlen>Size(centralizers[j]) then + Info(InfoHomClass,3, + "true stabilizer found (cannot grow)"); + minlen:=Size(centralizers[j])/Size(stab); + maxdiff:=minlen-Sum(orb,i->Size(i[3])); + stabtrue:=true; + fi; + fi; + + if stabtrue then + + smacla:=Filtered(select,i->Size(clTR[i][3])<=maxdiff); + + if Length(smacla)Size(i[3])); + + CompletionBar(InfoHomClass,3,"trueorb ",1-maxdiff/minlen); + #Info(InfoHomClass,3, + # "This is the true orbit length (missing ", + # maxdiff,")"); + + if Size(stab)*Sum(orb,i->Size(i[3])) + =Size(centralizers[j]) then maxdiff:=0; elif Sum(remainlen)=maxdiff then diff --git a/lib/ghomperm.gi b/lib/ghomperm.gi index b8ea762715..7f2c626333 100644 --- a/lib/ghomperm.gi +++ b/lib/ghomperm.gi @@ -1581,7 +1581,7 @@ end); ## #M PreImagesSetNC( , ) . . . . . . . . . . . . . . . for const hom ## -InstallMethod( PreImagesSetNC, "constituent homomorphism", +InstallMethod( PreImagesSetNC, "constituent homomorphism", CollFamRangeEqFamElms, [ IsConstituentHomomorphism, IsPermGroup ], 0, function( hom, I ) local H, # preimage of , result diff --git a/lib/grplatt.gi b/lib/grplatt.gi index e24dc57f97..9e879fea18 100644 --- a/lib/grplatt.gi +++ b/lib/grplatt.gi @@ -2826,35 +2826,35 @@ local fgi,inducedfactorautos,projs,psubs,info,n,l,nl,emb,u,pos, no:=NormalSubgroups(j[1]); no:=SubgroupsOrbitsAndNormalizers(j[2],no,false); #Print("Try",j," ",Length(no),"\n"); - for k in no do - hom:=NaturalHomomorphismByNormalSubgroup(j[1],k.representative); - f:=Image(hom); - if Size(f)<1000 and Size(f)<>512 and uselib then - myid:=ShallowCopy(IdGroup(f)); - else - myid:=[Size(f),fail]; - fi; - for s in subs do - for t in s[3] do # look over normals of subgroup + for k in no do + hom:=NaturalHomomorphismByNormalSubgroup(j[1],k.representative); + f:=Image(hom); + if Size(f)<1000 and Size(f)<>512 and uselib then + myid:=ShallowCopy(IdGroup(f)); + else + myid:=[Size(f),fail]; + fi; + for s in subs do + for t in s[3] do # look over normals of subgroup #Print(t,"\n"); - if t{[3,4]}=myid then - if false and myid=[1,1] then - #Print("direct\n"); - g:=Subgroup(D,Concatenation(GeneratorsOfGroup(j[1]),List(GeneratorsOfGroup(s[1]),x->Image(emb,x)))); - Add(nl,[g,Normalizer(D,g)]); - else - iso:=IsomorphismGroups(f,t[6]); - if iso<>fail then - #Found isomorphic factor groups - iso:=hom*iso; - ind:=Subgroup(t[7],inducedfactorautos(k.normalizer,t[6],iso)); - for dc in DoubleCosetRepsAndSizes(t[7],ind,t[8]) do - # form the subdirect product - g:=List(GeneratorsOfGroup(j[1]), - x->x*Image(emb,PreImagesRepresentativeNC(t[5], - Image(dc[1],Image(iso,x))) )); - Append(g,List(GeneratorsOfGroup(t[1]),x->Image(emb,x))); - g:=Subgroup(D,g); + if t{[3,4]}=myid then + if false and myid=[1,1] then + #Print("direct\n"); + g:=Subgroup(D,Concatenation(GeneratorsOfGroup(j[1]),List(GeneratorsOfGroup(s[1]),x->Image(emb,x)))); + Add(nl,[g,Normalizer(D,g)]); + else + iso:=IsomorphismGroups(f,t[6]); + if iso<>fail then + #Found isomorphic factor groups + iso:=hom*iso; + ind:=Subgroup(t[7],inducedfactorautos(k.normalizer,t[6],iso)); + for dc in DoubleCosetRepsAndSizes(t[7],ind,t[8]) do + # form the subdirect product + g:=List(GeneratorsOfGroup(j[1]), + x->x*Image(emb,PreImagesRepresentativeNC(t[5], + Image(dc[1],Image(iso,x))) )); + Append(g,List(GeneratorsOfGroup(t[1]),x->Image(emb,x))); + g:=Subgroup(D,g); if Size(g)<>Size(j[1])*Size(s[1])/Size(f) then Error("sudi\n");fi; Add(nl,[g,Normalizer(D,g)]); od; diff --git a/lib/grppcaut.gi b/lib/grppcaut.gi index 6a4e5514ed..0f3ca0cadc 100644 --- a/lib/grppcaut.gi +++ b/lib/grppcaut.gi @@ -1418,12 +1418,12 @@ InstallGlobalFunction(AutomorphismGroupSolvableGroup,function( G ) hom := ActionHomomorphism( xset, "surjective"); P := Image( hom ); if IsSolvableGroup( P ) then - pcsA := List( Pcgs(P), + pcsA := List( Pcgs(P), x -> PreImagesRepresentativeNC( hom, x )); TransferPcgsInfo( A, pcsA, RelativeOrders( Pcgs(P) ) ); else imgs := SmallGeneratingSet( P ); - gens := List( imgs, + gens := List( imgs, x -> PreImagesRepresentativeNC( hom, x ) ); tmp := Size( A ); A := GroupByGenerators( gens, One( A ) ); diff --git a/lib/mapping.gd b/lib/mapping.gd index 15ce08a83a..08c3134061 100644 --- a/lib/mapping.gd +++ b/lib/mapping.gd @@ -984,22 +984,22 @@ DeclareGlobalFunction( "Images" ); ## preimages of elm under map. ##

## Anything may happen if elm is not an element of the range of -## map. -##

-## In order to improve this state of affairs, -## PreImagesElm has been renamed PreImagesElmNC -## throughout the library, and -## PreImagesElm has been declared a synonym for PreImagesElmNC. -##

-## In future versions of &GAP; PreImagesElm -## will perform additional checks and reject invalid inputs. -## These additional checks will slow the computation so, -## when the inputs are known to be valid by construction, -## users are recommended to use PreImagesElmNC. -##

-## Package authors are asked to convert their methods for -## PreImagesElm to methods for PreImagesElmNC. -## Only when this has happened will the additional checks be implemented. +## map. +##

+## In order to improve this state of affairs, +## PreImagesElm has been renamed PreImagesElmNC +## throughout the library, and +## PreImagesElm has been declared a synonym for PreImagesElmNC. +##

+## In future versions of &GAP; PreImagesElm +## will perform additional checks and reject invalid inputs. +## These additional checks will slow the computation so, +## when the inputs are known to be valid by construction, +## users are recommended to use PreImagesElmNC. +##

+## Package authors are asked to convert their methods for +## PreImagesElm to methods for PreImagesElmNC. +## Only when this has happened will the additional checks be implemented. ## ## ## <#/GAPDoc> @@ -1044,8 +1044,8 @@ DeclareOperation( "PreImageElm", ## ## ## If elm is an element of the range of the general mapping -## map then these operations return either a representative -## of the set of preimages of elm under map or fail, +## map then these operations return either a representative +## of the set of preimages of elm under map or fail, ## the latter if and only if elm has no preimages under map. ##

## Anything may happen if elm is not an element of the range of From f7e6eae5decacbb33298387540b8c184d059346a Mon Sep 17 00:00:00 2001 From: Wilf Wilson Date: Wed, 17 Sep 2025 14:28:41 +0100 Subject: [PATCH 022/234] Add comments in the release.yml workflow clarifying fetch-depth: 0 and force-fetching tags (#6098) --- .github/workflows/release.yml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index aa35e805e9..3ddbd4bf8a 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -68,10 +68,18 @@ jobs: gap-build-version: ${{ steps.get-build.outputs.name }} steps: + # We need to force fetch tags on the repository in the next step, which + # requires fetching the entire history. Therefore, we might as well do + # that here when checking out the repo, which is what setting fetch-depth + # to 0 accomplishes here. - uses: actions/checkout@v5 with: fetch-depth: 0 + # We need to know the git tags of the repository, because the GAP build + # system uses the tags to generate the version string for the GAP build, + # which we then extract in the "Record the GAP build version" step below. + # # When an annotated tag is pushed, then for some reason we don't see it # in this action; instead an unannotated tag with the same name is # present, we resolve this by force-fetching tags. From 71140a2117e7ace35cca1b75d8a9c666c7c6a644 Mon Sep 17 00:00:00 2001 From: Max Horn Date: Mon, 22 Sep 2025 21:52:34 +0200 Subject: [PATCH 023/234] meataxe: rename some things internally (#6120) ... to have different copies of the code look more alike --- lib/meataxe.gi | 165 ++++++++++++++++++++++++------------------------- 1 file changed, 82 insertions(+), 83 deletions(-) diff --git a/lib/meataxe.gi b/lib/meataxe.gi index cad13b6a3a..07dfb0e573 100644 --- a/lib/meataxe.gi +++ b/lib/meataxe.gi @@ -168,18 +168,18 @@ end); ############################################################################### ## -#F TensorProductGModule( m1, m2 ) . . tensor product of two G-modules +#F TensorProductGModule( module1, module2 ) . . tensor product of two G-modules ## ## TensorProductGModule calculates the tensor product of smash -## modules m1 and m2. +## modules module1 and module2. ## They are assumed to be modules over the same algebra so, in particular, ## they should have the same number of generators. ## -InstallGlobalFunction(TensorProductGModule,function( m1, m2) +InstallGlobalFunction(TensorProductGModule,function( module1, module2) local mat1, mat2, F1, F2, gens, i, l; - mat1:=SMTX.Generators(m1); mat2:=SMTX.Generators(m2); - F1:=SMTX.Field(m1); F2:=SMTX.Field(m2); + mat1:=SMTX.Generators(module1); mat2:=SMTX.Generators(module2); + F1:=SMTX.Field(module1); F2:=SMTX.Field(module2); if F1 <> F2 then Error("GModules are defined over different fields.\n"); fi; @@ -2225,7 +2225,7 @@ end; ## Otherwise who knows what will happen? ## SMTX.IsomorphismComp:=function(module1, module2, action) - local matrices, matrices1, matrices2, F, dim, swapmodule, genpair, + local matrices, mats1, mats2, F, dim, swapmodule, genpair, swapped, i, j, el, p, fac, M, mat, v1, v2, v, N, basis, basis1, basis2; @@ -2263,9 +2263,9 @@ SMTX.IsomorphismComp:=function(module1, module2, action) Info(InfoMeatAxe,2, "Checking nullspace 1-dimensional over centralising field."); SMTX.GoodElementGModule(module1); - matrices1:=module1.generators; - matrices2:=ShallowCopy(module2.generators); - if Length(matrices1) <> Length(matrices2) then + mats1:=module1.generators; + mats2:=ShallowCopy(module2.generators); + if Length(mats1) <> Length(mats2) then Error("GModules have different numbers of defining matrices."); fi; @@ -2278,12 +2278,12 @@ SMTX.IsomorphismComp:=function(module1, module2, action) Info(InfoMeatAxe,2,"Extending generating set for second module."); el:=SMTX.AlgEl(module1); for genpair in el[1] do - Add(matrices2, matrices2[genpair[1]] * matrices2[genpair[2]]); + Add(mats2, mats2[genpair[1]] * mats2[genpair[2]]); od; - M:=ImmutableMatrix(F,Sum([1..Length(matrices2)], i -> el[2][i] * matrices2[i])); + M:=ImmutableMatrix(F,Sum([1..Length(mats2)], i -> el[2][i] * mats2[i])); # Having done that, we no longer want the extra generators of module2, # so we throw them away again. - matrices2:=ShallowCopy(module2.generators); + mats2:=ShallowCopy(module2.generators); Info(InfoMeatAxe,2, "Calculating characteristic polynomial for second module."); @@ -2304,7 +2304,7 @@ SMTX.IsomorphismComp:=function(module1, module2, action) # That concludes the easy tests for nonisomorphism. Now we must proceed # to spin up. We first form the direct sum of the generating matrices. Info(InfoMeatAxe,2,"Spinning up in direct sum."); - matrices:=SMTX.MatrixSum(matrices1, matrices2); + matrices:=SMTX.MatrixSum(mats1, mats2); v1:=SMTX.AlgElNullspaceVec(module1); v2:=N[1]; if IsVectorObj(v1) then v1:=Unpack(v1);fi; @@ -2345,14 +2345,14 @@ end; ############################################################################# ## -#F SMTX.MatrixSum(matrices1, matrices2) direct sum of two lists of matrices +#F SMTX.MatrixSum(mats1, mats2) direct sum of two lists of matrices ## -SMTX.MatrixSum:=function(matrices1, matrices2) +SMTX.MatrixSum:=function(mats1, mats2) local matrices, nmats, i; matrices:=[]; - nmats:=Length(matrices1); + nmats:=Length(mats1); for i in [1..nmats] do - matrices[i]:=DirectSumMat(matrices1[i],matrices2[i]); + matrices[i]:=DirectSumMat(mats1[i],mats2[i]); od; return matrices; @@ -2361,75 +2361,75 @@ end; ############################################################################# ## -#F SMTX.Homomorphisms( m1, m2) . . . . homomorphisms from an irreducible +#F SMTX.Homomorphisms( module1, module2) . . . . homomorphisms from an irreducible ## . . . GModule to an arbitrary GModule ## -## It is assumed that m1 is a module that has been proved irreducible -## (using IsIrreducible), and m2 is an arbitrary module for the same group. -## A basis of the space of G-homomorphisms from m1 to m2 is returned. +## It is assumed that module1 is a module that has been proved irreducible +## (using IsIrreducible), and module2 is an arbitrary module for the same group. +## A basis of the space of G-homomorphisms from module1 to module2 is returned. ## Each homomorphism is given as a list of base images. ## -SMTX.Homomorphisms:= function(m1, m2) +SMTX.Homomorphisms:= function(module1, module2) local F, mats1, mats2, dim1, dim2, m1bas, imbases, el, genpair, fac, mat, N, imlen, subdim, leadpos, vec, imvecs, numrels, rels, leadposrels, newrels, bno, genno, colno, rowno, zero, looking, ans, i, j, k; - if not SMTX.IsMTXModule(m1) then + if not SMTX.IsMTXModule(module1) then return Error("First argument is not a module."); - elif not SMTX.IsIrreducible(m1) then + elif not SMTX.IsIrreducible(module1) then return Error("First module is not known to be irreducible."); fi; - if not SMTX.IsMTXModule(m2) then + if not SMTX.IsMTXModule(module2) then return Error("Second argument is not a module."); fi; - mats1:=m1.generators; - mats2:=ShallowCopy(m2.generators); + mats1:=module1.generators; + mats2:=ShallowCopy(module2.generators); if Length(mats1) <> Length(mats2) then return Error("GModules have different numbers of generators."); fi; - F:=SMTX.Field(m1); - if F <> SMTX.Field(m2) then + F:=SMTX.Field(module1); + if F <> SMTX.Field(module2) then return Error("GModules are defined over different fields."); fi; zero:=Zero(F); - dim1:=SMTX.Dimension(m1); dim2:=SMTX.Dimension(m2); + dim1:=SMTX.Dimension(module1); dim2:=SMTX.Dimension(module2); if dim1=1 then - # m1 is 1-dimensional -- eigenspace intersection - el:=List([1..Length(m1.generators)],x->NullspaceMat(m2.generators[x]-m1.generators[x][1][1]*m2.generators[x]^0)); + # module1 is 1-dimensional -- eigenspace intersection + el:=List([1..Length(module1.generators)],x->NullspaceMat(module2.generators[x]-module1.generators[x][1][1]*module2.generators[x]^0)); imvecs:=el[1]; for j in [2..Length(el)] do imvecs:=SumIntersectionMat(imvecs,el[j])[2]; od; - return List(imvecs,x->ImmutableMatrix(m1.field,[x])); + return List(imvecs,x->ImmutableMatrix(module1.field,[x])); fi; m1bas:=[]; - m1bas[1]:= ShallowCopy(SMTX.AlgElNullspaceVec(m1)); + m1bas[1]:= ShallowCopy(SMTX.AlgElNullspaceVec(module1)); - # In any homomorphism from m1 to m2, the vector in the nullspace of the + # In any homomorphism from module1 to module2, the vector in the nullspace of the # algebraic element that was used to prove irreducibility (which is now # m1bas[1]) must map onto a vector in the nullspace of the same algebraic - # element evaluated in m2. We therefore calculate this nullspaces, and + # element evaluated in module2. We therefore calculate this nullspaces, and # store a basis in imbases. Info(InfoMeatAxe,2,"Extending generating set for second module."); - el:=SMTX.AlgEl(m1); + el:=SMTX.AlgEl(module1); for genpair in el[1] do Add(mats2, mats2[genpair[1]] * mats2[genpair[2]]); od; mat:=ImmutableMatrix(F,Sum([1..Length(mats2)], i -> el[2][i] * mats2[i])); - # Having done that, we no longer want the extra generators of m2, + # Having done that, we no longer want the extra generators of module2, # so we throw them away again. - mats2:=ShallowCopy(m2.generators); + mats2:=ShallowCopy(module2.generators); - fac:=SMTX.AlgElCharPolFac(m1); + fac:=SMTX.AlgElCharPolFac(module1); mat:=SMTX_Value(fac, mat,mat^0); Info(InfoMeatAxe,2,"Calculating nullspace for second module."); N:=NullspaceMat(mat); @@ -2449,7 +2449,7 @@ SMTX.Homomorphisms:= function(m1, m2) # under a homomorphism must be zero. This leads to a linear relation # amongst some vectors in imbas. We store up such relations, echelonizing as # we go. At the end, if we have numrels subch independent relations, then - # there will be imlen - numrels independent homomorphisms from m1 to m2, + # there will be imlen - numrels independent homomorphisms from module1 to module2, # which we can then calculate. subdim:=1; # the dimension of module spanned by m1bas @@ -2588,40 +2588,40 @@ end; ############################################################################# ## -#F SMTX.SortHomGModule( m1, m2, homs) . . sort output of HomGModule +#F SMTX.SortHomGModule( module1, module2, homs) . . sort output of HomGModule ## according to their images ## -## It is assumed that m1 is a module that has been proved irreducible -## (using IsIrreducible), and m2 is an arbitrary module for the same group, -## and that homs is the output of a call HomGModule(m1, m2). -## Let e be the degree of the centralising field of m1. +## It is assumed that module1 is a module that has been proved irreducible +## (using IsIrreducible), and module2 is an arbitrary module for the same group, +## and that homs is the output of a call HomGModule(module1, module2). +## Let e be the degree of the centralising field of module1. ## If e = 1 then SMTX.SortHomGModule does nothing. If e > 1, then it replaces ## the basis contained in homs by a new basis arranged in the form ## b11, b12, ..., b1e, b21, b22, ...b2e, ..., br1, br2, ...bre, where each ## block of e adjacent basis vectors are all equivalent under the -## centralising field of m1, and so they all have the same image in m2. +## centralising field of module1, and so they all have the same image in module2. ## A complete list of the distinct images can then be obtained with a call -## to DistinctIms(m1, m2, homs). +## to DistinctIms(module1, module2, homs). ## -SMTX.SortHomGModule:=function(m1, m2, homs) +SMTX.SortHomGModule:=function(module1, module2, homs) local e, F, dim1, dim2, centmat, fullimbas, oldhoms, homno, dimhoms, newdim, subdim, leadpos, vec, nexthom, i, j, k, zero; - if SMTX.IsAbsolutelyIrreducible(m1) then return; fi; + if SMTX.IsAbsolutelyIrreducible(module1) then return; fi; - e:=SMTX.DegreeFieldExt(m1); - F:=SMTX.Field(m1); + e:=SMTX.DegreeFieldExt(module1); + F:=SMTX.Field(module1); zero:=Zero(F); - dim1:=SMTX.Dimension(m1); dim2:=SMTX.Dimension(m2); - centmat:=SMTX.CentMat(m1); + dim1:=SMTX.Dimension(module1); dim2:=SMTX.Dimension(module2); + centmat:=SMTX.CentMat(module1); fullimbas:=[]; subdim:=0; leadpos:=[]; - # fullimbas will contain an echelonised basis for the submodule of m2 + # fullimbas will contain an echelonised basis for the submodule of module2 # generated by all images of the basis vectors of hom that we have found # so far; subdim is its length. @@ -2631,7 +2631,7 @@ local e, F, dim1, dim2, centmat, fullimbas, oldhoms, # If so, we reject hom. If not, then hom is adjoined to the new # basis of homs, as are the other e-1 linearly independent homomorphisms # that are equivalent to hom by a multiplication by centmat. The - # resulting block of e homomorphisms all have the same image in m2. + # resulting block of e homomorphisms all have the same image in module2. # first make a copy of homs. @@ -2738,38 +2738,37 @@ end; ############################################################################# ## -#F SMTX.MinimalSubGModules(m1, m2, [max]) . . -## minimal submodules of m2 isomorphic to m1 +#F SMTX.MinimalSubGModules(module1, module2, [max]) . . +## minimal submodules of module2 isomorphic to module1 ## -## It is assumed that m1 is a module that has been proved irreducible -## (using IsIrreducible), and m2 is an arbitrary module for the same group. +## It is assumed that module1 is a module that has been proved irreducible +## (using IsIrreducible), and module2 is an arbitrary module for the same group. ## MinimalSubGModules computes and outputs a list of normed bases for all of the -## distinct minimal submodules of m2 that are isomorphic to m1. +## distinct minimal submodules of module2 that are isomorphic to module1. ## max is an optional maximal number - if the total number of submodules ## exceeds max, then the procedure aborts. ## First HomGModule is called and then SMTX.SortHomGModule to get a basis for -## the homomorphisms from m1 to m2 in the correct order. +## the homomorphisms from module1 to module2 in the correct order. ## It is then easy to write down the list of distinct images. ## -SMTX.MinimalSubGModules:=function(arg) +SMTX.MinimalSubGModules:=function(module1, module2, arg...) - local m1, m2, max, e, homs, coeff, dimhom, edimhom, F, elF, q, + local max, e, homs, coeff, dimhom, edimhom, F, elF, q, submodules, sub, adno, more, count, sr, er, i, j, k; - if Length(arg) < 2 or Length(arg) > 3 then + if Length(arg) > 1 then Error("Number of arguments to MinimalSubGModules must be 2 or 3."); fi; - m1:=arg[1]; m2:=arg[2]; - if Length(arg) = 2 then max:=0; else max:=arg[3]; fi; + if Length(arg) = 0 then max:=0; else max:=arg[3]; fi; - Info(InfoMeatAxe,2,"Calculating homomorphisms from m1 to m2."); - homs:=SMTX.Homomorphisms(m1, m2); + Info(InfoMeatAxe,2,"Calculating homomorphisms from module1 to module2."); + homs:=SMTX.Homomorphisms(module1, module2); Info(InfoMeatAxe,2,"Sorting them."); - SMTX.SortHomGModule(m1, m2, homs); + SMTX.SortHomGModule(module1, module2, homs); - F:=SMTX.Field(m1); - e:=SMTX.DegreeFieldExt(m1); + F:=SMTX.Field(module1); + e:=SMTX.DegreeFieldExt(module1); dimhom:=Length(homs); edimhom:=dimhom / e; submodules:=[]; @@ -3052,26 +3051,26 @@ end; ############################################################################# ## -#F SMTX.SpanOfMinimalSubGModules(m1, m2) . . -## span of the minimal submodules of m2 isomorphic to m1 +#F SMTX.SpanOfMinimalSubGModules(module1, module2) . . +## span of the minimal submodules of module2 isomorphic to module1 ## -## It is assumed that m1 is a module that has been proved irreducible -## (using IsIrreducible), and m2 is an arbitrary module for the same group. +## It is assumed that module1 is a module that has been proved irreducible +## (using IsIrreducible), and module2 is an arbitrary module for the same group. ## SpanOfMinimalSubGModules computes a normed bases for the span of -## the minimal submodules of m2 that are isomorphic to m1, +## the minimal submodules of module2 that are isomorphic to module1, ## First HomGModule is called. ## -SMTX.SpanOfMinimalSubGModules:=function(m1, m2) +SMTX.SpanOfMinimalSubGModules:=function(module1, module2) local homs, e, mat, i; - Info(InfoMeatAxe,2,"Calculating homomorphisms from m1 to m2."); - homs:=SMTX.Homomorphisms(m1, m2); + Info(InfoMeatAxe,2,"Calculating homomorphisms from module1 to module2."); + homs:=SMTX.Homomorphisms(module1, module2); if homs=[] then return []; fi; Info(InfoMeatAxe,2,"Sorting them."); - SMTX.SortHomGModule(m1, m2, homs); + SMTX.SortHomGModule(module1, module2, homs); - e:=SMTX.DegreeFieldExt(m1); + e:=SMTX.DegreeFieldExt(module1); # homs are now grouped so that each block of e have the same image. # We only want one from each block. if e > 1 then @@ -3083,7 +3082,7 @@ SMTX.SpanOfMinimalSubGModules:=function(m1, m2) # The span of the images of homs is what we want! mat:=Concatenation(homs); TriangulizeMat(mat); - mat:=ImmutableMatrix(m1.field,mat); + mat:=ImmutableMatrix(module1.field,mat); return mat; end; From 4ddfa18277016e21833a350168f671567f24fef3 Mon Sep 17 00:00:00 2001 From: Christopher Jefferson Date: Tue, 23 Sep 2025 04:43:34 +0800 Subject: [PATCH 024/234] Use `posix_spawn_file_actions_addchdir_np` when available, to fix macOS crashes (#6122) --- src/iostream.c | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/src/iostream.c b/src/iostream.c index 68bdf6a4da..fa445f6cbb 100644 --- a/src/iostream.c +++ b/src/iostream.c @@ -309,11 +309,25 @@ static Obj FuncDEFAULT_SIGCHLD_HANDLER(Obj self) // posix_spawn_file_actions_addchdir_np. To keep things simple, we detect this // case and use some preprocessor tricks to make things work in either case. // -#if !defined(HAVE_POSIX_SPAWN_FILE_ACTIONS_ADDCHDIR) && \ +// macOS 26 has posix_spawn_file_actions_addchdir, but Xcode generates +// code which uses it even in older versions of macOS. Therefore if both +// functions are defined, we will always use the older _np version. +// See issue for details. +#if defined(HAVE_POSIX_SPAWN_FILE_ACTIONS_ADDCHDIR) || \ defined(HAVE_POSIX_SPAWN_FILE_ACTIONS_ADDCHDIR_NP) + +#if !defined(HAVE_POSIX_SPAWN_FILE_ACTIONS_ADDCHDIR) #define HAVE_POSIX_SPAWN_FILE_ACTIONS_ADDCHDIR -#define posix_spawn_file_actions_addchdir(f, d) \ +#endif + +#if HAVE_POSIX_SPAWN_FILE_ACTIONS_ADDCHDIR_NP +#define posix_spawn_file_actions_addchdir_func(f, d) \ posix_spawn_file_actions_addchdir_np(f, d) +#else +#define posix_spawn_file_actions_addchdir_func(f, d) \ + posix_spawn_file_actions_addchdir(f, d) +#endif + #endif @@ -368,9 +382,12 @@ static int posix_spawn_with_dir(pid_t * pid, // the next POSIX revision in mid-2020. When this will appear in public // is anyones guess. On the upside, also OpenBSD, FreeBSD, and Solaris // implement the _np versions of the API. + // + // UPDATE: For now we still prefer the _np version if available, to + // avoid issues in macOS 26 (see . #ifdef HAVE_POSIX_SPAWN_FILE_ACTIONS_ADDCHDIR - if (posix_spawn_file_actions_addchdir(file_actions, dir)) { + if (posix_spawn_file_actions_addchdir_func(file_actions, dir)) { PErr("posix_spawn_with_dir: addchdir failed"); return 1; } From 4533adc2429844b76ae63d27df8c197f9695d28a Mon Sep 17 00:00:00 2001 From: Max Horn Date: Tue, 23 Sep 2025 15:15:23 +0200 Subject: [PATCH 025/234] Tune MultMatrixRowLeft etc. for IsRowListMatrix (#6121) --- lib/matrobjrowlist.gi | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/lib/matrobjrowlist.gi b/lib/matrobjrowlist.gi index b9a2483bc5..fdf315cf5a 100644 --- a/lib/matrobjrowlist.gi +++ b/lib/matrobjrowlist.gi @@ -22,7 +22,7 @@ InstallMethod( MultMatrixRowLeft, "for a mutable IsRowListMatrix, a row number, [ IsRowListMatrix and IsMutable, IsInt, IsObject ], function( mat, row, scalar ) - mat[row] := scalar * mat[row]; + MultVectorLeft(mat[row], scalar); end ); @@ -35,7 +35,7 @@ InstallMethod( MultMatrixRowRight, "for a mutable IsRowListMatrix, a row number, [ IsRowListMatrix and IsMutable, IsInt, IsObject ], function( mat, row, scalar ) - mat[row] := mat[row] * scalar; + MultVectorRight(mat[row], scalar); end ); @@ -48,7 +48,8 @@ InstallMethod( AddMatrixRowsLeft, "for a mutable IsRowListMatrix, two row number [ IsRowListMatrix and IsMutable, IsInt, IsInt, IsObject ] , function( mat, row1, row2, scalar ) - mat[row1] := mat[row1] + scalar * mat[row2]; + AddVector(mat[row1], mat[row2], scalar); + # TODO: AddVector does not specify left/right... we need both variants I guess end ); @@ -61,7 +62,8 @@ InstallMethod( AddMatrixRowsRight, "for a mutable IsRowListMatrix, two row numbe [ IsRowListMatrix and IsMutable, IsInt, IsInt, IsObject ] , function( mat, row1, row2, scalar ) - mat[row1] := mat[row1] + mat[row2] * scalar; + AddVector(mat[row1], mat[row2], scalar); + # TODO: AddVector does not specify left/right... we need both variants I guess end ); @@ -77,7 +79,5 @@ InstallMethod( SwapMatrixRows, "for a mutable IsRowListMatrix, and two row numbe temp := mat[row1]; mat[row1] := mat[row2]; mat[row2] := temp; - #mat{[row1,row2]} := mat{[row2,row1]}; end ); - From 1855f04474c20159e7881eb11035a449c1334950 Mon Sep 17 00:00:00 2001 From: Max Horn Date: Tue, 23 Sep 2025 23:32:30 +0200 Subject: [PATCH 026/234] kernel: include julia_gc.h in gap_all.h (#6124) ... at least when using the Julia garbage collector. This will make it easier for the GAP.jl resp. JuliaInterface packages to interface to the GAP kernel in light of recent changes to our header include path. --- src/gap_all.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/gap_all.h b/src/gap_all.h index 1c69e2810a..6d6a1e6d61 100644 --- a/src/gap_all.h +++ b/src/gap_all.h @@ -88,6 +88,10 @@ extern "C" { #include "hpc/traverse.h" #endif +#ifdef USE_JULIA_GC +#include "julia_gc.h" +#endif + #ifdef __cplusplus } // extern "C" #endif From 0ad9cb4a9c34d897147583c9e0fdc622ebc9d71f Mon Sep 17 00:00:00 2001 From: Max Horn Date: Tue, 23 Sep 2025 23:32:46 +0200 Subject: [PATCH 027/234] kernel: avoid using PATH_MAX (#6123) ... to help compatibility with systems that don't define it, such as GNU/HURD. --- src/streams.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/streams.c b/src/streams.c index 1a45a105ef..970dc7f984 100644 --- a/src/streams.c +++ b/src/streams.c @@ -1135,7 +1135,7 @@ static Obj FuncGAP_chdir(Obj self, Obj path) static Obj FuncGAP_realpath(Obj self, Obj path) { RequireStringRep(SELF_NAME, path); - char resolved_path[PATH_MAX]; + char resolved_path[GAP_PATH_MAX]; if (NULL == realpath(CONST_CSTR_STRING(path), resolved_path)) { SySetErrorNo(); From 194ceb0a5b942b0211b6a6f6cd1c24f789f8e4d7 Mon Sep 17 00:00:00 2001 From: Thomas Breuer Date: Wed, 24 Sep 2025 02:12:22 +0200 Subject: [PATCH 028/234] Add an `IsConjugate` method based on nice monomorphisms (#6116) * add `IsConjugate` method based on nice monomorphisms and call `IsConjugate` not `RepresentativeAction` in the `LowIndexSubgroups` method for finite groups * avoid some conjugacy tests, call `IndexNC` The groups returned by `MaximalSubgroupClassReps( G )` are known to be pairwise not conjugate in `G`. --- lib/grplatt.gi | 12 +++++++----- lib/grpnice.gi | 22 +++++++++++++++++++++- tst/testinstall/grpmat.tst | 4 ++++ 3 files changed, 32 insertions(+), 6 deletions(-) diff --git a/lib/grplatt.gi b/lib/grplatt.gi index 9e879fea18..075d4e0b23 100644 --- a/lib/grplatt.gi +++ b/lib/grplatt.gi @@ -3189,15 +3189,17 @@ InstallMethod(LowIndexSubgroups,"finite groups, using iterated maximals", true,[IsGroup and IsFinite,IsPosInt],0, function(G,n) local m,all,m2; - m:=[G]; - all:=[G]; + m:= Filtered( MaximalSubgroupClassReps( G ), x -> IndexNC( G, x ) <= n ); + all:= [ G ]; + Append( all, m ); + m:= Filtered( m, x -> IndexNC( G, x ) <= n/2 ); while Length(m)>0 do m2:=Concatenation(List(m,MaximalSubgroupClassReps)); - m2:=Unique(Filtered(m2,x->Index(G,x)<=n)); + m2:=Unique(Filtered(m2,x->IndexNC(G,x)<=n)); m2:=List(SubgroupsOrbitsAndNormalizers(G,m2,false),x->x.representative); - m2:=Filtered(m2,x->ForAll(all,y->RepresentativeAction(G,x,y)=fail)); + m2:= Filtered( m2, x -> ForAll( all, y-> not IsConjugate( G, x, y ) ) ); Append(all,m2); - m:=Filtered(m2,x->Index(G,x)<=n/2); # otherwise subgroups will have too large index + m:=Filtered(m2,x->IndexNC(G,x)<=n/2); # otherwise subgroups will have too large index od; return all; end); diff --git a/lib/grpnice.gi b/lib/grpnice.gi index 1e19617b72..710c2a5ef1 100644 --- a/lib/grpnice.gi +++ b/lib/grpnice.gi @@ -876,7 +876,7 @@ GroupSeriesMethodByNiceMonomorphism( UpperCentralSeriesOfGroup, ############################################################################# ## -#M RepresentativeAction( ) +#M RepresentativeAction( , , , OnPoints ) ## InstallOtherMethod(RepresentativeActionOp,"nice group on elements", IsCollsElmsElmsX,[IsHandledByNiceMonomorphism and IsGroup, @@ -899,6 +899,26 @@ local hom,rep; return rep; end); + +############################################################################# +## +#M IsConjugate( , , ) +## +InstallOtherMethod( IsConjugate, + "nice group on subgroups", + IsFamFamFam, + [ IsGroup and IsHandledByNiceMonomorphism, IsGroup, IsGroup ], + function( G, U, V ) + local hom; + + hom:= NiceMonomorphism( G ); + if not ( IsSubset( Source( hom ), U ) and IsSubset( Source( hom ), V ) ) then + TryNextMethod(); + fi; + return IsConjugate( NiceObject( G ), ImagesSet( hom, U ), ImagesSet( hom, V ) ); +end); + + ############################################################################# ## #M NaturalHomomorphismByNormalSubgroup( , ) . . . . via nicomorphism diff --git a/tst/testinstall/grpmat.tst b/tst/testinstall/grpmat.tst index f6cff8a582..bd7f9e8428 100644 --- a/tst/testinstall/grpmat.tst +++ b/tst/testinstall/grpmat.tst @@ -71,5 +71,9 @@ gap> IsomorphismFpGroup( G );; gap> TrivialSubgroup( GL(2, 2) ); +# The following should take less than a second. +gap> Length( LowIndexSubgroups( GL(2,5), 50 ) ) = 31; +true + # gap> STOP_TEST( "grpmat.tst" ); From af60981bee7c04c7348a00fcffbd96036ef4f04d Mon Sep 17 00:00:00 2001 From: Max Horn Date: Wed, 24 Sep 2025 03:13:13 +0200 Subject: [PATCH 029/234] Update release notes for 4.15.0-beta3 --- CHANGES.md | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index a62586cc01..4141cad170 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -43,6 +43,7 @@ affect some users directly. ### Build system +- [#6122](https://github.com/gap-system/gap/pull/6122) Fix possible segfault on macOS caused by an apparent bug in Apple's developer tooling - [#6010](https://github.com/gap-system/gap/pull/6010) Fix build issues when compiling GAP with GCC 15 - [#5992](https://github.com/gap-system/gap/pull/5992) Fix a potential linker issue during `make install` on macOS - [#5859](https://github.com/gap-system/gap/pull/5859) Increase GAP kernel version to 10.0 to indicate there were breaking kernel changes @@ -91,6 +92,8 @@ affect some users directly. - [**ALCO**](https://bnasmith.github.io/alco/) 1.1.2: Tools for algebraic combinatorics, by Benjamin Nasmith - [**IBNP**](https://gap-packages.github.io/ibnp/) 0.17: Involutive Bases for Noncommutative Polynomials, by Gareth A. Evans, Christopher D. Wensley - [**InduceReduce**](https://gap-packages.github.io/InduceReduce/) 1.1: Unger's algorithm to compute character tables of finite groups, by Jonathan Gruber +- [**SmallClassNr**](https://stertooy.github.io/SmallClassNr) 1.4.1: Library of finite groups with small class number, by Sam Tertooy +- [**TwistedConjugacy**](https://stertooy.github.io/TwistedConjugacy) 3.1.0: Computation with twisted conjugacy classes, by Sam Tertooy #### Packages no longer redistributed with GAP @@ -98,7 +101,7 @@ affect some users directly. #### Updated packages redistributed with GAP -The GAP 4.15.0 distribution contains 164 packages, of which 63 have been +The GAP 4.15.0 distribution contains 166 packages, of which 69 have been updated since GAP 4.14.0. The full list of updated packages is given below: - [**ACE**](https://gap-packages.github.io/ace): 5.6.2 -> 5.7.0 @@ -107,18 +110,18 @@ updated since GAP 4.14.0. The full list of updated packages is given below: - [**AutoDoc**](https://gap-packages.github.io/AutoDoc): 2023.06.19 -> 2025.05.09 - [**AutomGrp**](https://gap-packages.github.io/automgrp): 1.3.2 -> 1.3.3 - [**AutPGrp**](https://gap-packages.github.io/autpgrp/): 1.11 -> 1.11.1 -- [**CAP**](https://homalg-project.github.io/pkg/CAP): 2024.11-02 -> 2025.08-03 +- [**CAP**](https://homalg-project.github.io/pkg/CAP): 2024.11-02 -> 2025.09-04 - [**CddInterface**](https://homalg-project.github.io/CddInterface): 2024.09.02 -> 2025.06.24 - [**CRISP**](https://github.com/bh11/crisp/): 1.4.6 -> 1.4.8 - [**crypting**](https://gap-packages.github.io/crypting/): 0.10.5 -> 0.10.6 -- [**Cryst**](https://www.math.uni-bielefeld.de/~gaehler/gap/packages.php): 4.1.27 -> 4.1.29 +- [**Cryst**](https://www.math.uni-bielefeld.de/~gaehler/gap/packages.php): 4.1.27 -> 4.1.30 - [**CTblLib**](https://www.math.rwth-aachen.de/~Thomas.Breuer/ctbllib): 1.3.9 -> 1.3.11 - [**Cubefree**](https://gap-packages.github.io/cubefree/): 1.20 -> 1.21 - [**curlInterface**](https://gap-packages.github.io/curlInterface/): 2.4.0 -> 2.4.2 - [**cvec**](https://gap-packages.github.io/cvec): 2.8.2 -> 2.8.4 - [**datastructures**](https://gap-packages.github.io/datastructures): 0.3.1 -> 0.3.3 - [**DeepThought**](https://gap-packages.github.io/DeepThought/): 1.0.7 -> 1.0.9 -- [**Digraphs**](https://digraphs.github.io/Digraphs): 1.9.0 -> 1.12.1 +- [**Digraphs**](https://digraphs.github.io/Digraphs): 1.9.0 -> 1.12.2 - [**Example**](https://gap-packages.github.io/example): 4.4.0 -> 4.4.1 - [**ferret**](https://gap-packages.github.io/ferret/): 1.0.14 -> 1.0.15 - [**float**](https://gap-packages.github.io/float/): 1.0.5 -> 1.0.9 @@ -133,10 +136,11 @@ updated since GAP 4.14.0. The full list of updated packages is given below: - [**HomalgToCAS**](https://homalg-project.github.io/pkg/HomalgToCAS): 2023.11-01 -> 2025.08-01 - [**IO**](https://gap-packages.github.io/io): 4.9.1 -> 4.9.3 - [**json**](https://gap-packages.github.io/json/): 2.2.2 -> 2.2.3 -- [**LinearAlgebraForCAP**](https://homalg-project.github.io/pkg/LinearAlgebraForCAP): 2024.10-01 -> 2025.08-02 +- [**LieAlgDB**](https://gap-packages.github.io/liealgdb/): 2.2.1 -> 2.3.0 +- [**LinearAlgebraForCAP**](https://homalg-project.github.io/pkg/LinearAlgebraForCAP): 2024.10-01 -> 2025.09-01 - [**matgrp**](https://www.math.colostate.edu/~hulpke/matgrp): 0.71 -> 0.72 - [**MatricesForHomalg**](https://homalg-project.github.io/pkg/MatricesForHomalg): 2024.11-02 -> 2025.09-01 -- [**ModulePresentationsForCAP**](https://homalg-project.github.io/pkg/ModulePresentationsForCAP): 2024.09-02 -> 2025.08-02 +- [**ModulePresentationsForCAP**](https://homalg-project.github.io/pkg/ModulePresentationsForCAP): 2024.09-02 -> 2025.09-01 - [**Modules**](https://homalg-project.github.io/pkg/Modules): 2024.01-01 -> 2024.12-01 - [**MonoidalCategories**](https://homalg-project.github.io/pkg/MonoidalCategories): 2024.09-05 -> 2025.08-02 - [**NConvex**](https://homalg-project.github.io/pkg/NConvex): 2022.09-01 -> 2024.12-01 @@ -145,21 +149,26 @@ updated since GAP 4.14.0. The full list of updated packages is given below: - [**PackageManager**](https://gap-packages.github.io/PackageManager/): 1.6 -> 1.6.3 - [**Polenta**](https://gap-packages.github.io/polenta/): 1.3.10 -> 1.3.11 - [**Polycyclic**](https://gap-packages.github.io/polycyclic/): 2.16 -> 2.17 -- [**PrimGrp**](https://gap-packages.github.io/primgrp/): 3.4.4 -> 4.0.0 +- [**PrimGrp**](https://gap-packages.github.io/primgrp/): 3.4.4 -> 4.0.1 - [**profiling**](https://gap-packages.github.io/profiling/): 2.6.0 -> 2.6.2 - [**QDistRnd**](https://QEC-pages.github.io/QDistRnd): 0.9.4 -> 0.9.5 +- [**RCWA**](https://gap-packages.github.io/rcwa/): 4.7.1 -> 4.8.0 +- [**RDS**](https://gap-packages.github.io/rds/): 1.8 -> 1.9 - [**recog**](https://gap-packages.github.io/recog): 1.4.3 -> 1.4.4 - [**RepnDecomp**](https://gap-packages.github.io/RepnDecomp): 1.3.0 -> 1.3.1 +- [**ResClasses**](https://gap-packages.github.io/resclasses/): 4.7.3 -> 4.7.4 - [**SCSCP**](https://gap-packages.github.io/scscp): 2.4.3 -> 2.4.4 - [**Semigroups**](https://semigroups.github.io/Semigroups): 5.4.0 -> 5.5.4 - [**singular**](https://gap-packages.github.io/singular/): 2024.06.03 -> 2025.08.26 - [**smallantimagmas**](https://gap-packages.github.io/smallantimagmas): 0.2.12 -> 0.4.1 - [**Smallsemi**](https://gap-packages.github.io/smallsemi/): 0.7.1 -> 0.7.2 +- [**SONATA**](https://gap-packages.github.io/sonata/): 2.9.6 -> 2.9.7 - [**ToolsForHomalg**](https://homalg-project.github.io/pkg/ToolsForHomalg): 2024.09-01 -> 2025.05-01 - [**typeset**](https://gap-packages.github.io/typeset/): 1.2.2 -> 1.2.3 - [**UnitLib**](https://gap-packages.github.io/unitlib): 4.2.0 -> 5.0.0 - [**utils**](https://gap-packages.github.io/utils): 0.85 -> 0.92 - [**Wedderga**](https://gap-packages.github.io/wedderga): 4.10.5 -> 4.11.1 +- [**XGAP**](https://gap-packages.github.io/xgap): 4.32 -> 4.33 - [**XMod**](https://gap-packages.github.io/xmod/): 2.92 -> 2.95 - [**XModAlg**](https://gap-packages.github.io/xmodalg/): 1.23 -> 1.32 - [**YangBaxter**](https://gap-packages.github.io/YangBaxter): 0.10.6 -> 0.10.7 From a6e8c966daa5baa6d45d055c118001b51049a72e Mon Sep 17 00:00:00 2001 From: Thomas Breuer Date: Fri, 26 Sep 2025 11:12:33 +0200 Subject: [PATCH 030/234] Fix a wrong `false` result of `IsSolvable` for certain trivial permutation groups (#6130) See the new test for an example where this was not the case before. --- lib/grpperm.gi | 3 ++- tst/testinstall/grpperm.tst | 8 ++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/lib/grpperm.gi b/lib/grpperm.gi index e1b9d27308..08f7805298 100644 --- a/lib/grpperm.gi +++ b/lib/grpperm.gi @@ -1288,11 +1288,12 @@ end ); # if this goes on too long the group may not be solvable. This can be much faster # for large degree groups than to use the full pcgs machinery (which uses the same # idea but builds a pcgs on the way). +# The function returns `true` if the group has been proved to be *non*solvable. BindGlobal("QuickUnsolvabilityTestPerm",function(G) local som,elvth,fct,gens,new,l,i,j,a,b,bound; # a few moved points som:=MovedPoints(G); - if Length(som) = 0 then SetIsTrivial(G,true); return true; fi; + if Length(som) = 0 then SetIsTrivial(G,true); return fail; fi; bound:=Int(LogInt(Length(som)^5,3)/2); #Dixon Bound if Length(som)>100 then som:=som{List([1..100],x->Random(1, Length(som)))}; diff --git a/tst/testinstall/grpperm.tst b/tst/testinstall/grpperm.tst index 5299b11293..7ad74c56f2 100644 --- a/tst/testinstall/grpperm.tst +++ b/tst/testinstall/grpperm.tst @@ -145,4 +145,12 @@ gap> List(Iterator(SymmetricGroup(3))); [ (), (2,3), (1,3), (1,3,2), (1,2,3), (1,2) ] gap> AsList(SymmetricGroup(6)) = List(Iterator(SymmetricGroup(6))); true + +# +gap> g:= SymmetricGroup( 4 );; +gap> h:= Subgroup( g, [ () ] );; +gap> IsSolvable( h ); +true + +# gap> STOP_TEST("grpperm.tst"); From 61a35d62d387a9ad534dcd4dc1af4c09ce8498f2 Mon Sep 17 00:00:00 2001 From: Max Horn Date: Sun, 28 Sep 2025 15:07:46 +0200 Subject: [PATCH 031/234] Update CHANGES.md for 4.15.0 ; recommend signing tags --- CHANGES.md | 5 +++-- dev/releases/README.md | 8 ++++---- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 4141cad170..8ca392443e 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -50,6 +50,7 @@ affect some users directly. ### Fixed bugs that could lead to incorrect results +- [#6130](https://github.com/gap-system/gap/pull/6130) Fix a wrong `false` result of `IsSolvable` for certain trivial permutation groups - [#6110](https://github.com/gap-system/gap/pull/6110) Fix `LowerCentralSeriesOfGroup` and `NilpotencyClassOfGroup` for trivial groups to return a list of length 1 resp. the value 0 (and not a list of length 2 resp. the value 1) - [#6002](https://github.com/gap-system/gap/pull/6002) Fix bug in `SpecialPcgs` that could corrupt group objects and cause nonsense outputs - [#5982](https://github.com/gap-system/gap/pull/5982) Fix a bug that could lead to `ConjugacyClassesSubgroups` to return wrong results when applied to permutation groups @@ -121,7 +122,7 @@ updated since GAP 4.14.0. The full list of updated packages is given below: - [**cvec**](https://gap-packages.github.io/cvec): 2.8.2 -> 2.8.4 - [**datastructures**](https://gap-packages.github.io/datastructures): 0.3.1 -> 0.3.3 - [**DeepThought**](https://gap-packages.github.io/DeepThought/): 1.0.7 -> 1.0.9 -- [**Digraphs**](https://digraphs.github.io/Digraphs): 1.9.0 -> 1.12.2 +- [**Digraphs**](https://digraphs.github.io/Digraphs): 1.9.0 -> 1.13.1 - [**Example**](https://gap-packages.github.io/example): 4.4.0 -> 4.4.1 - [**ferret**](https://gap-packages.github.io/ferret/): 1.0.14 -> 1.0.15 - [**float**](https://gap-packages.github.io/float/): 1.0.5 -> 1.0.9 @@ -160,7 +161,7 @@ updated since GAP 4.14.0. The full list of updated packages is given below: - [**SCSCP**](https://gap-packages.github.io/scscp): 2.4.3 -> 2.4.4 - [**Semigroups**](https://semigroups.github.io/Semigroups): 5.4.0 -> 5.5.4 - [**singular**](https://gap-packages.github.io/singular/): 2024.06.03 -> 2025.08.26 -- [**smallantimagmas**](https://gap-packages.github.io/smallantimagmas): 0.2.12 -> 0.4.1 +- [**smallantimagmas**](https://gap-packages.github.io/smallantimagmas): 0.2.12 -> 0.5.1 - [**Smallsemi**](https://gap-packages.github.io/smallsemi/): 0.7.1 -> 0.7.2 - [**SONATA**](https://gap-packages.github.io/sonata/): 2.9.6 -> 2.9.7 - [**ToolsForHomalg**](https://homalg-project.github.io/pkg/ToolsForHomalg): 2024.09-01 -> 2025.05-01 diff --git a/dev/releases/README.md b/dev/releases/README.md index 5a4e0ad462..ce40b0e7e7 100644 --- a/dev/releases/README.md +++ b/dev/releases/README.md @@ -13,21 +13,21 @@ you first have to create that using the `dev/releases/create_stable_branch.py` s This is the way the process should happen in practice, with the help of GitHub Actions. Instructions for achieving the same without GitHub Actions are given later (in case GitHub Actions breaks or disappears). -1. In the `gap-system/PackageDistro` GitHub repository, create an annotated tag `vX.Y.Z` based on its latest `main` branch (this determines which packages get into the release) and push the tag. For example: +1. In the `gap-system/PackageDistro` GitHub repository, create an annotated and signed tag `vX.Y.Z` based on its latest `main` branch (this determines which packages get into the release) and push the tag. For example: ``` VER=X.Y.Z # to avoid typing git checkout main git pull -git tag -m "Version ${VER}" v${VER} main +git tag -s -m "Version ${VER}" v${VER} main git push origin v${VER} ``` 2. Wait. Pushing the tag triggers the “[Assemble the package distribution](https://github.com/gap-system/PackageDistro/actions/workflows/assemble-distro.yml)” GitHub Actions workflow; on `gap-system/PackageDistro`. This takes a few minutes. -2. In the `gap-system/gap` GitHub repository, create an annotated tag `vX.Y.Z` at the appropriate commit in the `stable-X.Y` branch, and push the tag. For example: +2. In the `gap-system/gap` GitHub repository, create an annotated and signed tag `vX.Y.Z` at the appropriate commit in the `stable-X.Y` branch, and push the tag. For example: ``` VER=${VER} # to avoid typing git checkout stable-${VER%.*} git pull -git tag -m "Version ${VER}" v${VER} stable-${VER%.*} +git tag -s -m "Version ${VER}" v${VER} stable-${VER%.*} git push origin v${VER} ``` 4. Wait. Pushing the tag triggers the “[Wrap releases](https://github.com/gap-system/gap/actions/workflows/release.yml)” GitHub Actions workflow on `gap-system/gap`, which wraps the release archives and Windows installers, and creates a release on GitHub with the archives and installers attached. This takes around 90 minutes. From 281390a378dd69eff76282406ec5f1ae566ae30a Mon Sep 17 00:00:00 2001 From: Max Horn Date: Mon, 29 Sep 2025 21:57:56 +0200 Subject: [PATCH 032/234] Complete move of update_website.py to GapWWW (#6131) The script was added there in . Now we remove the unused copy here... --- dev/releases/README.md | 3 +- dev/releases/update_website.py | 183 --------------------------------- 2 files changed, 1 insertion(+), 185 deletions(-) delete mode 100755 dev/releases/update_website.py diff --git a/dev/releases/README.md b/dev/releases/README.md index ce40b0e7e7..e1ec53fa69 100644 --- a/dev/releases/README.md +++ b/dev/releases/README.md @@ -36,7 +36,6 @@ git push origin v${VER} change the release from "pre-release" to "latest release" (i.e., on disable "Set as a pre-release" and enable "Set as the latest release"). 7. Next either manually dispatch the “[Sync](https://github.com/gap-system/GapWWW/actions/workflows/sync.yml)” GitHub Actions workflow on `gap-system/GapWWW`, or wait overnight for it to happen on schedule. - This workflow creates a pull request to `gap-system/GapWWW`, which updates the GAP website according to the release data hosted on `gap-system/gap`. Check that the result is sensible. - - This workflow uses the `update_website.py` script which can also be run manually, see below for more information. 8. When it is time to publicise the new GAP release, merge the pull request to GapWWW. 9. There are currently additional steps required for the new manual to appear on , and to add a copy of the new release files to . These could and should be automated in the future but are currently not. Details are described in steps 10 and following below. @@ -89,7 +88,7 @@ Before starting the release process, the scripts have the following dependencies 5. Access your local clone of the `GapWWW` repository. 6. Make sure that your clone is up to date with `gap-system/GapWWW`. 7. Check out the master branch. -8. Start website update: either as described above via a workflow in the `GapWWW` repository; or by running `update_website.py` in root directory of `GapWWW` (see `update_website.py --help`). This: +8. Start website update: either as described above via a workflow in the `GapWWW` repository; or switch to the root directory of `GapWWW` and run `etc/update_website.py` there (see also `etc/update_website.py --help`). This: - Fetches the GitHub releases data from `gap-system/gap`. - Deletes, modifies, and adds various JSON and HTML files according to this data. 9. Inspect the changes, and commit and push them to the master branch to `gap-system/GapWWW`. diff --git a/dev/releases/update_website.py b/dev/releases/update_website.py deleted file mode 100755 index 0e526fa0c3..0000000000 --- a/dev/releases/update_website.py +++ /dev/null @@ -1,183 +0,0 @@ -#!/usr/bin/env python3 -############################################################################# -## -## This file is part of GAP, a system for computational discrete algebra. -## -## 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 script updates the website when there is a new GAP release. -## It is to be run from inside a clone of the gap-system/GapWWW repository. - -import argparse -import datetime -import gzip -import json -import os -import re -import shutil -import sys -import tarfile -import tempfile - -import github -import requests -import utils -from utils import error, notice - -if sys.version_info < (3, 6): - error("Python 3.6 or newer is required") - -parser = argparse.ArgumentParser( - formatter_class=argparse.RawDescriptionHelpFormatter, - description="""Update the GAP website from the GAP releases data on GitHub. - -Run this script in the root of a clone of the GapWWW repository, \ -checked out at the version from which you want to update \ -(most likely the master branch of github.com/gap-system/GapWWW). \ -The script modifies the working directory according to the information \ -on GitHub.""", -) -group = parser.add_argument_group("Repository details and access") -group.add_argument( - "--gap-fork", - type=str, - default="gap-system", - help="GitHub GAP fork to search for releases (for testing; default: gap-system)", -) -args = parser.parse_args() - -utils.verify_command_available("git") -utils.verify_git_repo() -utils.verify_git_clean() - -pwd = os.getcwd() -tmpdir = tempfile.gettempdir() - - -# Downloads the asset with name from the current GitHub release -# (global variable , with assets ) to . -def download_asset_by_name(asset_name: str, writedir: str) -> None: - global assets - try: - url = [x for x in assets if x.name == asset_name][0].browser_download_url - except: - error( - f"Cannot find {asset_name} in the GitHub release with tag {release.tag_name}" - ) - - with utils.working_directory(writedir): - notice(f"Downloading {url} to {writedir} . . .") - utils.download_with_sha256(url, asset_name) - - -def extract_tarball(tball: str) -> None: - notice(f"Extracting {tball} . . .") - with tarfile.open(tball) as tar: - try: - tar.extractall() - except: - error(f"Failed to extract {tball}!") - - -def get_date_from_configure_ac(gaproot: str) -> str: - with open(f"{gaproot}/configure.ac", "r", encoding="utf-8") as configure_ac: - filedata = configure_ac.read() - try: # Expect date in YYYY-MM-DD format - release_date = re.search( - r"\[gap_releaseday\], \[(\d{4}-\d{2}-\d{2})\]", filedata - ).group(1) - release_date = datetime.datetime.strptime(release_date, "%Y-%m-%d") - return release_date.strftime("%d %B %Y") - except: - error("Cannot find the release date in configure.ac!") - - -# This function deals with package-infos.json.gz and help-links.json.gz. -# The function downloads the release asset called to the tmpdir. -# The asset is assumed to be gzipped. It is extracted to the filepath . -def download_and_extract_json_gz_asset(asset_name: str, dest: str) -> None: - download_asset_by_name(asset_name, tmpdir) - with utils.working_directory(tmpdir): - with gzip.open(asset_name, "rt", encoding="utf-8") as file_in: - with open(dest, "w", encoding="utf-8") as file_out: - shutil.copyfileobj(file_in, file_out) - - -################################################################################ -# Get latest GAP release -notice(f"Will use temporary directory: {tmpdir}") - -g = github.Github() # no token required as we just read a little data -repo = g.get_repo(f"{args.gap_fork}/gap") -release = repo.get_latest_release() - -notice(f"Latest GAP release is {release.title} at tag {release.tag_name}") -if release.tag_name[0] != "v": - error("Tag name has unexpected format") -version = release.tag_name[1:] - - -# Determine which version is currently in GapWWW -with open("_data/release.json", "r", encoding="utf-8") as f: - release_json = json.load(f) -www_release = release_json["version"] - -notice(f"GAP release in GapWWW is {www_release}") - -# TODO: abort if identical or even older - - -# For all releases, record the assets (in case they were deleted/updated/added) -notice(f"Collecting GitHub release asset data in _data/assets.json") -assets = release.get_assets() -asset_data = [] -for asset in assets: - if asset.name.endswith(".sha256") or asset.name.endswith(".json.gz"): - continue - request = requests.get(f"{asset.browser_download_url}.sha256") - try: - request.raise_for_status() - sha256 = request.text.strip() - except: - error(f"Failed to download {asset.browser_download_url}.sha256") - filtered_asset = { - "bytes": asset.size, - "name": asset.name, - "sha256": sha256, - "url": asset.browser_download_url, - } - asset_data.append(filtered_asset) -asset_data.sort(key=lambda s: list(map(str, s["name"]))) -with open(f"{pwd}/_data/assets.json", "wb") as outfile: - outfile.write(json.dumps(asset_data, indent=2).encode("utf-8")) - -# Extract the release date from the configure.ac file contained in -# gap-{version}-core.tar.gz. -# This date is set by the make_archives.py script. -# First download gap-X.Y.Z-core.tar.gz, extract, and fetch the date. -tarball = f"gap-{version}-core.tar.gz" -download_asset_by_name(tarball, tmpdir) -with utils.working_directory(tmpdir): - extract_tarball(tarball) -date = get_date_from_configure_ac(f"{tmpdir}/gap-{version}") -notice(f"Using release date {date} for GAP {version}") - -notice(f"Writing the file assets/package-infos.json") -download_and_extract_json_gz_asset( - "package-infos.json.gz", f"{pwd}/assets/package-infos.json" -) - -notice("Rewriting the _data/release.json file") -release_data = { - "version": version, - "date": date, -} -with open(f"{pwd}/_data/release.json", "wb") as outfile: - outfile.write(json.dumps(release_data, indent=2).encode("utf-8")) - -notice("Overwriting _data/help.json with the contents of help-links.json.gz") -download_and_extract_json_gz_asset("help-links.json.gz", f"{pwd}/_data/help.json") From 8caec361c513192dace321f07c610187268277de Mon Sep 17 00:00:00 2001 From: Max Horn Date: Thu, 2 Oct 2025 23:14:22 +0200 Subject: [PATCH 033/234] Fix `in` and other functionality for finite rational matrix groups (#6137) --- lib/grpramat.gi | 2 +- tst/testbugfix/2025-10-02-char0-matrixgroups.tst | 15 +++++++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) create mode 100644 tst/testbugfix/2025-10-02-char0-matrixgroups.tst diff --git a/lib/grpramat.gi b/lib/grpramat.gi index 91a3e37344..4b47d9c2fd 100644 --- a/lib/grpramat.gi +++ b/lib/grpramat.gi @@ -323,7 +323,7 @@ function( G ) nice := GroupHomomorphismByFunction(G, H, function(x) if ValueOption("actioncanfail")=true then - if not ForAll( x, r -> ForAll( r, IsInt ) ) then + if not ForAll( x, r -> ForAll( r, IsRat ) ) then return fail; fi; fi; diff --git a/tst/testbugfix/2025-10-02-char0-matrixgroups.tst b/tst/testbugfix/2025-10-02-char0-matrixgroups.tst new file mode 100644 index 0000000000..5c8f995c15 --- /dev/null +++ b/tst/testbugfix/2025-10-02-char0-matrixgroups.tst @@ -0,0 +1,15 @@ +# \in incorrectly returned 'false' for finite rational matrix groups +# if the matrix being tested was not integral. +# See +# +gap> G:=Group([ 1/2 * [[-1+1*E(4), -1+1*E(4)], [1+1*E(4), -1-1*E(4)]], E(4) * [[0,1],[-1,0]] ]);; +gap> g:=List(G)[9];; +gap> g in G; +true + +# +gap> H:=Group( 1/2*[[-1,1,-1,1],[-1,-1,-1,-1],[1,1,-1,-1],[-1,1,1,-1]], +> [[0,0,0,1],[0,0,-1,0],[0,-1,0,0],[1,0,0,0]] );; +gap> h := 1/2*[[-1,-1,1,-1],[1,-1,1,1],[-1,-1,-1,1],[1,-1,-1,-1]];; +gap> h in H; +true From d38422b9b6b21d3a354fc590fb22ceb7e709bbf1 Mon Sep 17 00:00:00 2001 From: Max Horn Date: Sat, 4 Oct 2025 03:08:07 +0200 Subject: [PATCH 034/234] Fix a typo (#6136) --- doc/ref/stbchain.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/ref/stbchain.xml b/doc/ref/stbchain.xml index 1cb2bb8dfc..755b5c7091 100644 --- a/doc/ref/stbchain.xml +++ b/doc/ref/stbchain.xml @@ -187,7 +187,7 @@ This subsection explains some &GAP; functions which are local to the library file lib/stbcbckt.gi which contains the code for backtracking in permutation groups. They are mentioned here because you might find them helpful when -you want to implement you own backtracking function based on the +you want to implement your own backtracking function based on the partition concept. An important argument to most of the functions is the R-base R, which you should regard as a black box. We will tell you how to set it up, how to maintain it and where to pass it as argument, but it From c1071b13ee57c870d158eccd8e01d7a769f8400f Mon Sep 17 00:00:00 2001 From: Wilf Wilson Date: Sat, 4 Oct 2025 02:49:22 +0100 Subject: [PATCH 035/234] Stop using `transgrp` in the GAP test suites (#6117) * Remove testbugfix test that has been moved to TransGrp package * tst/consistency.g: load SmallGrp and TransGrp * Stop using transgrp in the GAP test suites --- tst/consistency.g | 2 + tst/testbugfix/2005-05-17-t00074.tst | 7 +- tst/testbugfix/2006-07-25-t00145.tst | 3 +- tst/testbugfix/2011-12-18-t00238.tst | 4 +- tst/testbugfix/2013-05-16-t00291.tst | 4 - tst/testbugfix/2016-03-01-t00331.tst | 4 +- tst/testbugfix/2018-06-28-grplatt.tst | 3 +- tst/testbugfix/2024-05-24-Cluster.tst | 5 +- tst/testextra/grplatt.tst | 4 +- tst/testextra/grpperm.tst | 4 +- tst/testinstall/morpheus.tst | 3 +- tst/testinstall/opers/IsSolvableGroup.tst | 60 +- tst/testinstall/opers/NormalHallSubgroups.tst | 14 +- .../opers/StructureDescription.tst | 14 +- tst/testinstall/pgroups.tst | 23 +- tst/testinstall/stabchain.tst | 26 +- tst/teststandard/minimalgeneratingset.tst | 533 ++++++++++++++++++ tst/teststandard/permgrp.tst | 10 +- 18 files changed, 693 insertions(+), 30 deletions(-) delete mode 100644 tst/testbugfix/2013-05-16-t00291.tst create mode 100644 tst/teststandard/minimalgeneratingset.tst diff --git a/tst/consistency.g b/tst/consistency.g index b95f1ebf48..ca366f7907 100644 --- a/tst/consistency.g +++ b/tst/consistency.g @@ -11,6 +11,8 @@ ## groups. SetAssertionLevel(2); +LoadPackage("SmallGrp", false);; +LoadPackage("TransGrp", false);; TestsForGroup:=function(G) local u,cs,ncs,n,rep,i,au,hom,cl,co; diff --git a/tst/testbugfix/2005-05-17-t00074.tst b/tst/testbugfix/2005-05-17-t00074.tst index c17482fbe0..333c678dc1 100644 --- a/tst/testbugfix/2005-05-17-t00074.tst +++ b/tst/testbugfix/2005-05-17-t00074.tst @@ -1,5 +1,10 @@ # 2005/05/17 (AH) -gap> IsConjugate(TransitiveGroup(9,19),Group([ (2,8,9,3)(4,6,7,5), +gap> g := Group([ (1,2,9)(3,4,5)(6,7,8), +> (1,4,7)(2,5,8)(3,6,9), +> (1,6,4,5,2,3,8,7), +> (1,2)(3,5)(6,7) ]);; +gap> # g = TransitiveGroup(9,19) +gap> IsConjugate(g,Group([ (2,8,9,3)(4,6,7,5), > (2,9)(3,8)(4,7)(5 ,6), (1,2,9)(3,4,5)(6,7,8), (1,4,7)(2,5,8)(3,6,9) ]), > Group([ (3,7)(4,8)(5,6), (2,9)(3,8)(4,7)(5,6),(1,7,4)(2,8,5)(3,9,6), > (1,6,5)(2,7,3)(4,9,8) ]));; diff --git a/tst/testbugfix/2006-07-25-t00145.tst b/tst/testbugfix/2006-07-25-t00145.tst index 4e48a23faa..765cff1496 100644 --- a/tst/testbugfix/2006-07-25-t00145.tst +++ b/tst/testbugfix/2006-07-25-t00145.tst @@ -1,4 +1,5 @@ # 2006/07/25 (AH) -gap> g:=TransitiveGroup(10,8);; +# g = TransitiveGroup(10,8) +gap> g := Group([ (2,7)(5,10), (1,3,5,7,9)(2,4,6,8,10) ]);; gap> ConjugatorOfConjugatorIsomorphism(ConjugatorAutomorphism(g,(4,9))); (1,6)(2,7)(3,8)(5,10) diff --git a/tst/testbugfix/2011-12-18-t00238.tst b/tst/testbugfix/2011-12-18-t00238.tst index ab3b4aaf84..2db8ab43ba 100644 --- a/tst/testbugfix/2011-12-18-t00238.tst +++ b/tst/testbugfix/2011-12-18-t00238.tst @@ -2,5 +2,7 @@ # Computing normalizers inside the trivial group could error out. gap> Normalizer(Group(()),Group((1,2,3))); Group(()) -gap> Normalizer(Group(()),TransitiveGroup(3,1)); +gap> h := Group([ (1,2,3) ]);; +gap> # h = TransitiveGroup(3,1) +gap> Normalizer(Group(()),h); Group(()) diff --git a/tst/testbugfix/2013-05-16-t00291.tst b/tst/testbugfix/2013-05-16-t00291.tst deleted file mode 100644 index 9ac1f0718c..0000000000 --- a/tst/testbugfix/2013-05-16-t00291.tst +++ /dev/null @@ -1,4 +0,0 @@ -# 2013/05/16 (AH) -gap> TransitiveIdentification(TransitiveGroup(30,4064)^(1,4,5,2) -> (6,20,15,21,7,16,12,24)(8,18,14,22,10,17,13,23,9,19,11,25)(26,30,29,28)); -4064 diff --git a/tst/testbugfix/2016-03-01-t00331.tst b/tst/testbugfix/2016-03-01-t00331.tst index a070871150..cd03528db1 100644 --- a/tst/testbugfix/2016-03-01-t00331.tst +++ b/tst/testbugfix/2016-03-01-t00331.tst @@ -2,5 +2,7 @@ gap> g:=PSL(6,4);; gap> Sum(ConjugacyClasses(g),Size)=Size(g); true -gap> Size(AutomorphismGroup(TransitiveGroup(12,269))); +gap> h:=Group([(2,4,6,8,12), (2,8)(10,12), (1,12)(2,3)(4,5)(6,7)(8,9)(10,11)]);; +gap> # h = TransitiveGroup(12,269) +gap> Size(AutomorphismGroup(h)); 14400 diff --git a/tst/testbugfix/2018-06-28-grplatt.tst b/tst/testbugfix/2018-06-28-grplatt.tst index 4e6800a8a7..f509aeaa68 100644 --- a/tst/testbugfix/2018-06-28-grplatt.tst +++ b/tst/testbugfix/2018-06-28-grplatt.tst @@ -1,6 +1,7 @@ # verify fix for bug #2586 on GitHub -gap> g:=TransitiveGroup(6,14);; +gap> g := Group([ (1,2,3,4,6), (1,2)(3,4)(5,6) ]);; +gap> # g = TransitiveGroup(6,14) = PGL(2,5) gap> cl:=ConjugacyClassesSubgroups(g);; gap> ForAll(cl,x->IsSubset(g,Representative(x))); true diff --git a/tst/testbugfix/2024-05-24-Cluster.tst b/tst/testbugfix/2024-05-24-Cluster.tst index 26d28ba409..3db44039f9 100644 --- a/tst/testbugfix/2024-05-24-Cluster.tst +++ b/tst/testbugfix/2024-05-24-Cluster.tst @@ -1,3 +1,6 @@ # Fix #5717 -gap> g := TransitiveGroup(12,288);; +gap> g := Group([ (2,4,6,8,12), +> (2,4)(6,8)(10,12), +> (1,12)(2,3)(4,5)(6,7)(8,9)(10,11) ]);; +gap> # g = TransitiveGroup(12,288);; gap> ConjugacyClassesSubgroups(g);; diff --git a/tst/testextra/grplatt.tst b/tst/testextra/grplatt.tst index 9c7b9db5ce..c718866b92 100644 --- a/tst/testextra/grplatt.tst +++ b/tst/testextra/grplatt.tst @@ -42,7 +42,9 @@ gap> Print(List(li,i->i),"\n"); [ 720, 66 ], [ 720, 66 ], [ 720, 66 ], [ 720, 66 ], [ 720, 66 ], [ 1440, 66 ], [ 1440, 66 ], [ 7920, 12 ], [ 7920, 12 ], [ 95040, 1 ] ] gap> LatticeSubgroups(Group((1,2,3,4,5,6)));; -gap> g:=WreathProduct(g,TransitiveGroup(6,13));; +gap> h := Group([ (2,4,6), (2,4), (1,4)(2,5)(3,6) ]);; +gap> # h = TransitiveGroup(6,13) +gap> g:=WreathProduct(g,h);; gap> l:=MaximalSubgroupClassReps(g);; gap> Collected(List(l,x->Index(g,x))); [ [ 2, 3 ], [ 9, 1 ], [ 2985984, 2 ], [ 82653950016, 2 ], diff --git a/tst/testextra/grpperm.tst b/tst/testextra/grpperm.tst index 2bd6acd7a9..7d2a8a06c0 100644 --- a/tst/testextra/grpperm.tst +++ b/tst/testextra/grpperm.tst @@ -160,7 +160,9 @@ gap> orbs := Orbits( a8, pairs, OnPairs );; Length( orbs ); 2 gap> u56 := Stabilizer( a8, orbs[2][1], OnPairs );; Index( a8, u56 ); 56 -gap> g:=TransitiveGroup(12,250);; +gap> g := Group([(3,6,9,12), (3,9), (1,5,9)(2,6,10)(3,7,11)(4,8,12), +> (1,5)(2,10)(4,8)(7,11)]);; +gap> # g = TransitiveGroup(12,250) gap> hom:=IsomorphismPcGroup(g);; gap> Length(ConjugacyClassesByHomomorphicImage(g,hom)); 65 diff --git a/tst/testinstall/morpheus.tst b/tst/testinstall/morpheus.tst index b42a944e98..56741335b5 100644 --- a/tst/testinstall/morpheus.tst +++ b/tst/testinstall/morpheus.tst @@ -25,7 +25,8 @@ false gap> iso4:=iso3*InnerAutomorphism(g,r^-1);; gap> iso4=IdentityMapping(g); true -gap> g:=TransitiveGroup(6,7);; +gap> g := Group([ (1,4)(2,5), (1,3,5)(2,4,6), (1,5)(2,4) ]);; +gap> # g = TransitiveGroup(6,7) gap> IsSolvableGroup(g); true gap> Size(AutomorphismGroup(g)); diff --git a/tst/testinstall/opers/IsSolvableGroup.tst b/tst/testinstall/opers/IsSolvableGroup.tst index 41835a2954..d06f79379f 100644 --- a/tst/testinstall/opers/IsSolvableGroup.tst +++ b/tst/testinstall/opers/IsSolvableGroup.tst @@ -4,7 +4,65 @@ gap> List(AllSmallGroups(120), IsSolvableGroup); true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, false, false, true, true, true, true, true, true, true, true, true, true, true, true ] -gap> List(AllTransitiveGroups(DegreeAction, 8), IsSolvable); +gap> grps := [ +> [ (1,2,3,4,5,6,7,8) ], [ (1,2,3,8)(4,5,6,7), (1,5)(2,6)(3,7)(4,8) ], +> [ (1,8)(2,3)(4,5)(6,7), (1,3)(2,8)(4,6)(5,7), (1,5)(2,6)(3,7)(4,8) ], +> [ (1,2,3,8)(4,5,6,7), (1,6)(2,5)(3,4)(7,8) ], +> [ (1,2,3,8)(4,5,6,7), (1,7,3,5)(2,6,8,4) ], +> [ (1,2,3,4,5,6,7,8), (1,6)(2,5)(3,4)(7,8) ], +> [ (1,2,3,4,5,6,7,8), (1,5)(3,7) ], [ (1,2,3,4,5,6,7,8), (1,3)(2,6)(5,7) ], +> [ (1,8)(2,3)(4,5)(6,7), (1,3)(2,8)(4,6)(5,7), (1,5)(2,6)(3,7)(4,8), +> (4,5)(6,7) ], [ (1,5)(3,7), (1,2,3,8)(4,5,6,7) ], +> [ (1,5)(3,7), (1,3,5,7)(2,4,6,8), (1,4,5,8)(2,3,6,7) ], +> [ (1,3,5,7)(2,4,6,8), (1,3,8)(4,5,7) ], +> [ (1,8)(2,3)(4,5)(6,7), (1,3)(2,8)(4,6)(5,7), (1,5)(2,6)(3,7)(4,8), +> (1,2,3)(4,6,5) ], +> [ (1,3)(2,8)(4,6)(5,7), (1,2,3)(5,6,7), (1,4)(2,6)(3,7)(5,8) ], +> [ (1,2,3,4,5,6,7,8), (1,5)(3,7), (1,6)(2,5)(3,4)(7,8) ], +> [ (2,6)(3,7), (1,2,3,4,5,6,7,8) ], [ (1,2,3,8), (1,5)(2,6)(3,7)(4,8) ], +> [ (1,8)(2,3)(4,5)(6,7), (1,3)(2,8)(4,6)(5,7), (1,5)(2,6)(3,7)(4,8), +> (4,5)(6,7), (4,6)(5,7) ], +> [ (1,8)(2,3)(4,5)(6,7), (1,3)(2,8)(4,6)(5,7), (1,5)(2,6)(3,7)(4,8), +> (1,3)(4,5,6,7) ], [ (2,6)(3,7), (1,2,3,8)(4,5,6,7) ], +> [ (1,5)(3,7), (1,4,5,8)(2,3)(6,7), (1,3)(2,8)(4,6)(5,7) ], +> [ (1,8)(2,3)(4,5)(6,7), (1,3)(2,8)(4,6)(5,7), (1,5)(2,6)(3,7)(4,8), +> (2,3)(4,5), (2,3)(6,7) ], [ (1,2,3,4,5,6,7,8), (1,3,8)(4,5,7) ], +> [ (1,8)(2,3)(4,5)(6,7), (1,3)(2,8)(4,6)(5,7), (1,5)(2,6)(3,7)(4,8), +> (1,2,3)(4,6,5), (2,3)(4,5) ], +> [ (1,8)(2,3)(4,5)(6,7), (1,3)(2,8)(4,6)(5,7), (1,5)(2,6)(3,7)(4,8), +> (1,2,6,3,4,5,7) ], [ (1,2,3,4,5,6,7,8), (1,5)(4,8), (1,7)(3,5)(4,8) ], +> [ (4,8), (1,2,3,8)(4,5,6,7) ], [ (2,6)(3,7), (1,3)(5,7), (1,2,3,4,5,6,7,8) ] +> , [ (1,8)(2,3)(4,5)(6,7), (1,3)(2,8)(4,6)(5,7), (1,5)(2,6)(3,7)(4,8), +> (1,3)(4,5,6,7), (1,3)(5,7) ], +> [ (2,6)(3,7), (1,3)(4,8)(5,7), (1,2,3,8)(4,5,6,7) ], +> [ (4,8), (1,8)(2,3)(4,5)(6,7), (1,3)(2,8)(4,6)(5,7) ], +> [ (1,8)(2,3)(4,5)(6,7), (1,3)(2,8)(4,6)(5,7), (1,5)(2,6)(3,7)(4,8), +> (1,2,3)(4,6,5), (2,5)(3,4) ], +> [ (1,8)(2,3)(4,5)(6,7), (1,3)(2,8)(4,6)(5,7), (1,5)(2,6)(3,7)(4,8), +> (1,2,3)(4,6,5), (4,6)(5,7) ], +> [ (1,8)(2,3), (1,2,3)(5,6,7), (1,5)(2,7)(3,6)(4,8) ], +> [ (4,8), (1,3)(5,7), (1,2,3,8)(4,5,6,7) ], +> [ (1,8)(2,3)(4,5)(6,7), (1,3)(2,8)(4,6)(5,7), (1,5)(2,6)(3,7)(4,8), +> (1,2,6,3,4,5,7), (1,2,3)(4,6,5) ], +> [ (1,2,3,4,5,6,8), (1,2,4)(3,6,5), (1,6)(2,3)(4,5)(7,8) ], +> [ (4,8), (1,8)(2,3)(4,5)(6,7), (1,2,3)(5,6,7) ], +> [ (1,8)(2,3)(4,5)(6,7), (1,3)(2,8)(4,6)(5,7), (1,5)(2,6)(3,7)(4,8), +> (1,2,3)(4,6,5), (1,6)(2,3,5,4) ], +> [ (1,5)(4,8), (1,8)(2,3)(4,5)(6,7), (1,2,3)(5,6,7), (2,3)(4,8)(6,7) ], +> [ (1,8)(2,3)(4,5)(6,7), (1,3)(2,8)(4,6)(5,7), (1,5)(2,6)(3,7)(4,8), +> (1,2,3)(4,6,5), (1,3)(4,5,6,7) ], +> [ (1,3)(2,8), (1,2,3), (1,5)(2,6)(3,7)(4,8) ], +> [ (1,2,3,4,5,6,8), (1,3,2,6,4,5), (1,6)(2,3)(4,5)(7,8) ], +> [ (4,8), (1,8)(4,5), (1,2,3,8)(4,5,6,7) ], +> [ (1,3)(2,8), (1,2,3), (1,8)(4,5), (1,5)(2,6)(3,7)(4,8) ], +> [ (1,3)(2,8), (1,2,3), (1,8)(4,5), (1,5)(2,7,3,6)(4,8) ], +> [ (1,2,3,8), (2,3), (1,5)(2,6)(3,7)(4,8) ], +> [ (1,8)(2,3)(4,5)(6,7), (1,3)(2,8)(4,6)(5,7), (1,5)(2,6)(3,7)(4,8), +> (1,2,6,3,4,5,7), (1,2,3)(4,6,5), (1,2)(5,6) ], +> [ (1,2,3,4,5,6,7), (6,7,8) ], [ (1,2,3,4,5,6,7,8), (1,2) ] ];; +gap> Apply(grps, Group); +gap> # grps = AllTransitiveGroups(DegreeAction, 8) +gap> List(grps, IsSolvable); [ true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, diff --git a/tst/testinstall/opers/NormalHallSubgroups.tst b/tst/testinstall/opers/NormalHallSubgroups.tst index 92baf83177..2278d619dc 100644 --- a/tst/testinstall/opers/NormalHallSubgroups.tst +++ b/tst/testinstall/opers/NormalHallSubgroups.tst @@ -45,7 +45,19 @@ gap> List(AllPrimitiveGroups(DegreeAction, 8), G -> List(NormalHallSubgroups(G), [ 1, 20160 ], [ 1, 40320 ] ] gap> List(NormalHallSubgroups(PrimitiveGroup(8,2)), Size); [ 1, 168, 56, 8 ] -gap> Positions(List(AllTransitiveGroups(DegreeAction, 6), G -> NormalHallSubgroupsFromSylows(G, "any")), fail); +gap> grps := [ [ (1,2,3,4,5,6) ], [ (1,3,5)(2,4,6), (1,4)(2,3)(5,6) ], +> [ (1,2,3,4,5,6), (1,4)(2,3)(5,6) ], [ (1,4)(2,5), (1,3,5)(2,4,6) ], +> [ (2,4,6), (1,4)(2,5)(3,6) ], [ (3,6), (1,3,5)(2,4,6) ], +> [ (1,4)(2,5), (1,3,5)(2,4,6), (1,5)(2,4) ], +> [ (1,4)(2,5), (1,3,5)(2,4,6), (1,5)(2,4)(3,6) ], +> [ (2,4,6), (1,5)(2,4), (1,4)(2,5)(3,6) ], +> [ (2,4,6), (1,5)(2,4), (1,4,5,2)(3,6) ], +> [ (3,6), (1,3,5)(2,4,6), (1,5)(2,4) ], [ (1,2,3,4,6), (1,4)(5,6) ], +> [ (2,4,6), (2,4), (1,4)(2,5)(3,6) ], [ (1,2,3,4,6), (1,2)(3,4)(5,6) ], +> [ (1,2,3,4,5), (4,5,6) ], [ (1,2,3,4,5,6), (1,2) ] ];; +gap> Apply(grps, Group); +gap> # grps = AllTransitiveGroups(DegreeAction, 6) +gap> Positions(List(grps, G -> NormalHallSubgroupsFromSylows(G, "any")), fail); [ 7, 8, 11, 12, 14, 15, 16 ] gap> N := PSL(2,32);; aut := SylowSubgroup(AutomorphismGroup(N),5);; gap> G := SemidirectProduct(aut, N);; diff --git a/tst/testinstall/opers/StructureDescription.tst b/tst/testinstall/opers/StructureDescription.tst index 76af80359e..204f6a4b91 100644 --- a/tst/testinstall/opers/StructureDescription.tst +++ b/tst/testinstall/opers/StructureDescription.tst @@ -7,7 +7,19 @@ gap> List(l, StructureDescription);; l; gap> List(AllSmallGroups(40),G->StructureDescription(G:short)); [ "5:8", "40", "5:8", "5:Q8", "4xD10", "D40", "2x(5:4)", "(10x2):2", "20x2", "5xD8", "5xQ8", "2x(5:4)", "2^2xD10", "10x2^2" ] -gap> List(AllTransitiveGroups(DegreeAction, 6), G -> StructureDescription(G:short)); +gap> grps := [ [ (1,2,3,4,5,6) ], [ (1,3,5)(2,4,6), (1,4)(2,3)(5,6) ], +> [ (1,2,3,4,5,6), (1,4)(2,3)(5,6) ], [ (1,4)(2,5), (1,3,5)(2,4,6) ], +> [ (2,4,6), (1,4)(2,5)(3,6) ], [ (3,6), (1,3,5)(2,4,6) ], +> [ (1,4)(2,5), (1,3,5)(2,4,6), (1,5)(2,4) ], +> [ (1,4)(2,5), (1,3,5)(2,4,6), (1,5)(2,4)(3,6) ], +> [ (2,4,6), (1,5)(2,4), (1,4)(2,5)(3,6) ], +> [ (2,4,6), (1,5)(2,4), (1,4,5,2)(3,6) ], +> [ (3,6), (1,3,5)(2,4,6), (1,5)(2,4) ], [ (1,2,3,4,6), (1,4)(5,6) ], +> [ (2,4,6), (2,4), (1,4)(2,5)(3,6) ], [ (1,2,3,4,6), (1,2)(3,4)(5,6) ], +> [ (1,2,3,4,5), (4,5,6) ], [ (1,2,3,4,5,6), (1,2) ] ];; +gap> Apply(grps, Group); +gap> # grps = AllTransitiveGroups(DegreeAction, 6) +gap> List(grps, G -> StructureDescription(G:short)); [ "6", "S3", "D12", "A4", "3xS3", "2xA4", "S4", "S4", "S3xS3", "(3^2):4", "2xS4", "A5", "(S3xS3):2", "S5", "A6", "S6" ] gap> StructureDescription(SmallGroup(504,7)); diff --git a/tst/testinstall/pgroups.tst b/tst/testinstall/pgroups.tst index 831157ef9c..f9b082a100 100644 --- a/tst/testinstall/pgroups.tst +++ b/tst/testinstall/pgroups.tst @@ -125,11 +125,26 @@ gap> G := F/[ r^3, s^2, r*s*r*s ]; gap> IsNilpotentGroup(G); false -gap> ForAll(List([1..11], i -> TransitiveGroup(8,i)), IsPGroup); -true -gap> IsPGroup(TransitiveGroup(8, 12)); +gap> myList := [ +> [ (1,2,3,4,5,6,7,8) ], [ (1,2,3,8)(4,5,6,7), (1,5)(2,6)(3,7)(4,8) ], +> [ (1,8)(2,3)(4,5)(6,7), (1,3)(2,8)(4,6)(5,7), (1,5)(2,6)(3,7)(4,8) ], +> [ (1,2,3,8)(4,5,6,7), (1,6)(2,5)(3,4)(7,8) ], +> [ (1,2,3,8)(4,5,6,7), (1,7,3,5)(2,6,8,4) ], +> [ (1,2,3,4,5,6,7,8), (1,6)(2,5)(3,4)(7,8) ], +> [ (1,2,3,4,5,6,7,8), (1,5)(3,7) ], [ (1,2,3,4,5,6,7,8), (1,3)(2,6)(5,7) ], +> [ (1,8)(2,3)(4,5)(6,7), (1,3)(2,8)(4,6)(5,7), (1,5)(2,6)(3,7)(4,8), +> (4,5)(6,7) ], [ (1,5)(3,7), (1,2,3,8)(4,5,6,7) ], +> [ (1,5)(3,7), (1,3,5,7)(2,4,6,8), (1,4,5,8)(2,3,6,7) ] ];; +gap> Apply(myList, Group); +gap> # myList = List([1..11], i -> TransitiveGroup(8,i)) +gap> ForAll(myList, IsPGroup); +true +gap> G := Group([ (1,3,5,7)(2,4,6,8), (1,3,8)(4,5,7) ]);; +gap> # G = TransitiveGroup(8, 12) +gap> IsPGroup(G); false -gap> IsNilpotentGroup(TransitiveGroup(8, 12)); +gap> # G = TransitiveGroup(8, 12) +gap> IsNilpotentGroup(G); false gap> IsPGroup(AlternatingGroup(3)); true diff --git a/tst/testinstall/stabchain.tst b/tst/testinstall/stabchain.tst index 3ff8d042ff..d38c4e59d5 100644 --- a/tst/testinstall/stabchain.tst +++ b/tst/testinstall/stabchain.tst @@ -1,4 +1,4 @@ -#@local TestGens,m +#@local TestGens,m,gensets gap> START_TEST("stabchain.tst"); gap> TestGens := function(g) > local m, sc; @@ -23,9 +23,27 @@ gap> TestGens := function(g) > return true; > end;; gap> TestGens(Group(()));; -gap> List([2..7], -> x -> List([1..NrTransitiveGroups(x)], -> y -> TestGens(TransitiveGroup(x,y))));; +gap> # MinimalGeneratingSets of the transitive groups of degrees 2..7, i.e +gap> # a:=Concatenation(List([2..7], x->AllTransitiveGroups(NrMovedPoints, x))); +gap> # gensets:=List(a, MinimalGeneratingSet); +gap> gensets := [ [ (1,2) ], [ (1,2,3) ], [ (2,3), (1,2,3) ], [ (1,2,3,4) ], +> [ (1,2)(3,4), (1,4)(2,3) ], [ (2,4), (1,2,3,4) ], [ (2,4,3), (1,3)(2,4) ], +> [ (2,4,3), (1,4,2,3) ], [ (1,2,3,4,5) ], [ (2,5)(3,4), (1,2,3,4,5) ], +> [ (2,3,5,4), (1,2,3,4,5) ], [ (1,2,3,4,5), (3,4,5) ], +> [ (1,2,3,4,5), (1,2) ], [ (1,6,5,4,3,2) ], +> [ (1,3,5)(2,4,6), (1,4)(2,3)(5,6) ], [ (2,6)(3,5), (1,6,5,4,3,2) ], +> [ (2,5)(3,6), (1,3,5)(2,4,6) ], [ (1,2,3,4,5,6), (1,5,3)(2,4,6) ], +> [ (1,4)(3,6), (1,6,5,4,3,2) ], [ (2,3)(5,6), (1,3,5)(2,4,6) ], +> [ (1,3,5)(2,4,6), (1,4)(2,6)(3,5) ], [ (3,5)(4,6), (1,2,3,4,5,6) ], +> [ (1,2)(3,4,5,6), (1,5,3) ], [ (1,2)(4,5), (1,6,5,4,3,2) ], +> [ (1,2,3,4,6), (1,4)(5,6) ], [ (1,4)(2,5)(3,6), (1,5,3)(4,6) ], +> [ (1,2,3,4,6), (1,2)(3,4)(5,6) ], [ (1,2,3,4,5), (4,5,6) ], +> [ (1,2,3,4,5,6), (1,2) ], [ (1,2,3,4,5,6,7) ], +> [ (2,7)(3,6)(4,5), (1,2,3,4,5,6,7) ], [ (2,3,5)(4,7,6), (1,2,3,4,5,6,7) ], +> [ (2,6,5,7,3,4), (1,6,4,2,7,5,3) ], [ (1,2,3,4,5,6,7), (1,2)(3,6) ], +> [ (1,2,3,4,5,6,7), (5,6,7) ], [ (1,2,3,4,5,6,7), (1,2) ] ];; +gap> ForAll(gensets, x -> TestGens(Group(x))); +true gap> TestGens(Group((1,2,3),(4,5,6)));; gap> TestGens(Group((1,2,3)(4,5,6)));; gap> TestGens(Group((2,4,6),(1,3,5),(1,3)));; diff --git a/tst/teststandard/minimalgeneratingset.tst b/tst/teststandard/minimalgeneratingset.tst new file mode 100644 index 0000000000..a721a9d31b --- /dev/null +++ b/tst/teststandard/minimalgeneratingset.tst @@ -0,0 +1,533 @@ +############################################################################# +## +## Some tests for computing MinimalGeneratingSet of permutation groups +## (takes on the order of a seconds to run) +## +#@local groups +gap> START_TEST("minimalgeneratingset.tst"); + +# groups = AllTransitiveGroups(NrMovedPoints,12) +# This test came from tst/teststandard/permgrp.tst, where it used +# AllTransitiveGroups and came with the comment: "factor 400 speedup" +gap> groups := [ +> [ (1,4,7,10)(2,5,8,11)(3,6,9,12), (1,5,9)(2,6,10)(3,7,11)(4,8,12) ], +> [ (1,10)(2,5)(3,12)(4,7)(6,9)(8,11), (1,7)(2,8)(3,9)(4,10)(5,11)(6,12), +> (1,5,9)(2,6,10)(3,7,11)(4,8,12) ], +> [ (1,5,9)(2,6,10)(3,7,11)(4,8,12), (1,11)(2,8)(3,9)(4,6)(5,7)(10,12), +> (1,12)(2,3)(4,5)(6,7)(8,9)(10,11) ], +> [ (1,9,5)(2,4,3)(6,8,7)(10,12,11), (1,11,6)(2,9,7)(3,10,5)(4,8,12) ], +> [ (1,5,9)(2,6,10)(3,7,11)(4,8,12), (1,7)(2,8)(3,9)(4,10)(5,11)(6,12), +> (1,8,7,2)(3,6,9,12)(4,11,10,5) ], +> [ (1,9,5)(2,4,3)(6,8,7)(10,12,11), (1,11,6)(2,9,7)(3,10,5)(4,8,12), +> (1,7)(2,11)(3,12)(4,10)(5,8)(6,9) ], +> [ (2,8)(3,9)(4,10)(5,11), (1,5,9)(2,6,10)(3,7,11)(4,8,12), +> (1,12)(2,3)(4,5)(6,7)(8,9)(10,11) ], +> [ (1,2)(3,5)(4,6)(7,9)(8,10), (1,3,6,12)(2,4,7,10)(5,8,11,9) ], +> [ (1,7)(3,9)(4,10)(6,12), (1,5,9)(2,6,10)(3,7,11)(4,8,12), +> (1,2)(3,12)(4,11)(5,10)(6,9)(7,8) ], +> [ (1,5,9)(2,6,10)(3,7,11)(4,8,12), (1,5)(2,10)(4,8)(7,11), +> (1,10)(2,5)(3,12)(4,7)(6,9)(8,11), (1,7)(2,8)(3,9)(4,10)(5,11)(6,12) ], +> [ (1,5,9)(2,6,10)(3,7,11)(4,8,12), (1,5)(2,10)(4,8)(7,11), +> (1,4,7,10)(2,5,8,11)(3,6,9,12) ], +> [ (1,5,9)(2,6,10)(3,7,11)(4,8,12), (1,4,7,10)(2,5,8,11)(3,6,9,12), +> (1,11)(2,10)(3,9)(4,8)(5,7) ], +> [ (1,5,9)(2,6,10)(3,7,11)(4,8,12), (1,10)(2,5)(3,12)(4,7)(6,9)(8,11), +> (1,7)(2,8)(3,9)(4,10)(5,11)(6,12), (1,11)(2,10)(3,9)(4,8)(5,7) ], +> [ (1,4,7,10)(2,5,8,11)(3,6,9,12), (1,7)(3,9)(5,11), +> (1,5,9)(2,6,10)(3,7,11)(4,8,12) ], +> [ (1,5,9)(2,6,10)(3,7,11)(4,8,12), (2,8)(4,10)(6,12), (1,7)(3,9)(5,11), +> (1,2)(3,12)(4,11)(5,10)(6,9)(7,8) ], +> [ (2,10,6)(4,8,12), (1,10)(2,5)(3,12)(4,7)(6,9)(8,11), +> (1,7)(2,8)(3,9)(4,10)(5,11)(6,12) ], +> [ (2,10,6)(4,8,12), (1,4,7,10)(2,5,8,11)(3,6,9,12) ], +> [ (2,6,10)(4,8,12), (1,10)(2,5)(3,12)(4,7)(6,9)(8,11), +> (1,7)(2,8)(3,9)(4,10)(5,11)(6,12) ], +> [ (2,6,10)(4,8,12), (1,4,7,10)(2,5,8,11)(3,6,9,12) ], +> [ (2,8,11)(3,6,12)(4,7,10), (1,7,10)(2,5,11)(3,6,9), +> (1,5,9)(2,6,10)(3,7,11)(4,8,12) ], +> [ (3,9)(6,12), (1,5,9)(2,6,10)(3,7,11)(4,8,12), +> (1,2)(3,12)(4,11)(5,10)(6,9)(7,8) ], +> [ (1,2)(3,5)(4,6)(7,9)(8,10), (1,3,6,12)(2,4,7,10)(5,8,11,9), +> (1,9)(2,7)(3,5)(4,10)(6,8)(11,12) ], +> [ (2,8)(3,9)(4,10)(5,11), (1,5,9)(2,6,10)(3,7,11)(4,8,12), +> (2,10)(3,11)(4,8)(5,9), (1,12)(2,3)(4,5)(6,7)(8,9)(10,11) ], +> [ (2,8)(3,9)(4,10)(5,11), (1,5,9)(2,6,10)(3,7,11)(4,8,12), +> (1,7)(2,10)(3,11)(4,8)(5,9)(6,12), (1,12)(2,3)(4,5)(6,7)(8,9)(10,11) ], +> [ (1,7)(6,12), (1,5,9)(2,6,10)(3,7,11)(4,8,12), +> (1,12)(2,3)(4,5)(6,7)(8,9)(10,11) ], +> [ (1,9,5)(2,4,3)(6,8,7)(10,12,11), (1,11,6)(2,9,7)(3,10,5)(4,8,12), +> (1,7)(2,11)(3,12)(4,10)(5,8)(6,9), (1,4)(2,5)(3,9)(6,12)(7,10)(8,11) ], +> [ (1,7)(2,11)(3,12)(4,10)(5,8)(6,9), (1,9,5)(2,4,3)(6,8,7)(10,12,11), +> (1,11,6)(2,9,7)(3,10,5)(4,8,12), (1,4,7,10)(2,3,11,12)(5,6,8,9) ], +> [ (1,4,7,10)(2,5,8,11)(3,6,9,12), (1,7)(3,9)(5,11), +> (1,5,9)(2,6,10)(3,7,11)(4,8,12), (1,5)(2,10)(4,8)(7,11) ], +> [ (1,7)(3,9)(4,10)(6,12), (1,4,7,10)(2,5,8,11)(3,6,9,12), +> (1,5,9)(2,6,10)(3,7,11)(4,8,12) ], +> [ (3,9)(6,12), (1,5,9)(2,6,10)(3,7,11)(4,8,12), +> (1,8,7,2)(3,6,9,12)(4,11,10,5) ], +> [ (1,10,7,4)(3,6,9,12), (1,5,9)(2,6,10)(3,7,11)(4,8,12) ], +> [ (1,10)(3,12)(4,7)(6,9), (1,7)(3,9)(4,10)(6,12), +> (1,5,9)(2,6,10)(3,7,11)(4,8,12) ], +> [ (1,3,5,7,9)(2,4,6,8,12), (1,11,5)(2,7,9)(3,6,8)(4,12,10) ], +> [ (1,3,5,7,9,11)(2,4,6,8,10,12), (1,8)(2,3)(4,5)(6,7)(9,12)(10,11) ], +> [ (2,6,10)(4,8,12), (2,8)(4,6)(10,12), (1,12)(2,3)(4,5)(6,7)(8,9)(10,11) ], +> [ (1,3,5,7,9,11)(2,4,6,8,10,12), (1,9)(2,3)(6,7)(8,12)(10,11) ], +> [ (2,6,10)(4,8,12), (1,5)(2,10)(4,8)(7,11), +> (1,10)(2,5)(3,12)(4,7)(6,9)(8,11), (1,7)(2,8)(3,9)(4,10)(5,11)(6,12) ], +> [ (2,6,10)(4,8,12), (1,4,7,10)(2,5,8,11)(3,6,9,12), +> (1,11)(2,10)(3,9)(4,8)(5,7) ], +> [ (2,6,10)(4,8,12), (1,5)(2,10)(4,8)(7,11), (1,4,7,10)(2,5,8,11)(3,6,9,12) ], +> [ (1,5,9)(4,8,12), (2,10)(3,11)(4,8)(5,9), (1,7)(2,8,10,4)(3,9,11,5)(6,12), +> (1,12)(2,3)(4,5)(6,7)(8,9)(10,11) ], +> [ (1,12)(2,3)(4,5)(6,7)(8,9)(10,11), (1,5,9)(4,8,12), +> (2,10)(3,11)(4,8)(5,9), (1,6,12,7)(2,8,11,5)(3,9,10,4) ], +> [ (2,6,10)(4,8,12), (1,4,7,10)(2,5,8,11)(3,6,9,12), (1,7)(3,9)(5,11) ], +> [ (2,8,11)(3,6,12)(4,7,10), (1,7,10)(2,5,11)(3,6,9), +> (1,5,9)(2,6,10)(3,7,11)(4,8,12), (1,5)(2,10)(4,8)(7,11) ], +> [ (1,5,9)(2,6,10)(3,7,11)(4,8,12), (2,8,11)(3,6,12)(4,7,10), +> (1,7,10)(2,5,11)(3,6,9), (1,11)(2,10)(3,9)(4,8)(5,7) ], +> [ (1,4,7,10)(2,5,8,11)(3,6,9,12), (1,10)(2,5)(6,9), +> (1,5,9)(2,6,10)(3,7,11)(4,8,12) ], +> [ (2,6,10)(3,7,11)(4,8,12), (1,5)(2,10)(4,8)(7,11), +> (1,4,2,11,5,8,10,7)(3,9,12,6) ], +> [ (2,6,10)(3,7,11)(4,8,12), (1,5)(2,10)(4,8)(7,11), +> (1,2,5,10)(3,12)(4,11,8,7)(6,9), (1,4,5,8)(2,7,10,11)(3,6)(9,12) ], +> [ (1,7)(6,12), (1,5,9)(2,6,10)(3,7,11)(4,8,12), (2,10)(3,11)(4,8)(5,9), +> (1,12)(2,3)(4,5)(6,7)(8,9)(10,11) ], +> [ (1,9)(2,7)(3,5)(4,10)(6,8)(11,12), (1,2)(3,5)(4,6)(7,9)(8,10), +> (1,3,6,12)(2,4,7,10)(5,8,11,9), (1,2,9,7)(3,11,5,12)(4,8,10,6) ], +> [ (3,9)(6,12), (1,7)(3,9)(5,11), (1,5,9)(2,6,10)(3,7,11)(4,8,12), +> (1,2)(3,12)(4,11)(5,10)(6,9)(7,8) ], +> [ (3,9)(6,12), (1,10)(2,5)(3,12)(4,7)(6,9)(8,11), (1,7)(3,9)(5,11), +> (1,5,9)(2,6,10)(3,7,11)(4,8,12) ], +> [ (3,9)(6,12), (1,10)(2,5)(3,12)(4,7)(6,9)(8,11), +> (1,5,9)(2,6,10)(3,7,11)(4,8,12), (1,11)(2,10)(3,9)(4,8)(5,7) ], +> [ (1,7)(3,9)(4,10)(6,12), (1,4,7,10)(2,5,8,11)(3,6,9,12), +> (1,5,9)(2,6,10)(3,7,11)(4,8,12), (1,5)(2,10)(4,8)(7,11) ], +> [ (1,12)(2,3), (1,5,9)(2,6,10)(3,7,11)(4,8,12), (2,3)(4,9)(5,8)(6,10)(7,11), +> (1,2)(3,12)(4,11)(5,10)(6,9)(7,8) ], +> [ (3,9)(6,12), (1,10,7,4)(3,6,9,12), (1,5,9)(2,6,10)(3,7,11)(4,8,12) ], +> [ (3,9)(6,12), (1,10)(3,12)(4,7)(6,9), (1,5,9)(2,6,10)(3,7,11)(4,8,12) ], +> [ (1,12)(2,3), (1,5,9)(2,6,10)(3,7,11)(4,8,12), (1,2,12,3)(4,7)(5,6)(8,9) ], +> [ (1,12)(4,5), (1,12)(8,9), (1,3,5,7,9,11)(2,4,6,8,10,12) ], +> [ (1,12)(2,3)(6,7)(8,9), (1,12)(2,3)(4,5), (2,8)(3,9)(4,10)(5,11), +> (1,5,9)(2,6,10)(3,7,11)(4,8,12) ], +> [ (1,12)(2,3)(6,7)(8,9), (1,3,5,7,9,11)(2,4,6,8,10,12), +> (4,10)(5,11)(6,7)(8,9) ], +> [ (1,12)(2,3)(6,7)(8,9), (1,12)(2,3)(4,5), (1,5,9)(2,6,10)(3,7,11)(4,8,12), +> (2,8)(3,9)(4,11)(5,10)(6,7) ], +> [ (1,10,7,4)(3,6,9,12), (1,5,9)(2,6,10)(3,7,11)(4,8,12), +> (1,5)(2,10)(4,8)(7,11) ], +> [ (1,12)(2,3)(6,7)(8,9), (1,5,9)(2,6,10)(3,7,11)(4,8,12), +> (1,2)(3,12)(4,5)(6,8)(7,9)(10,11) ], +> [ (1,12)(2,3)(6,7)(8,9), (1,5,9)(2,6,10)(3,7,11)(4,8,12), +> (1,2)(3,12)(4,5)(6,9)(7,8) ], +> [ (1,12)(2,3)(6,7)(8,9), (1,5,9)(2,6,10)(3,7,11)(4,8,12), +> (1,3)(2,12)(4,10)(5,11)(6,8)(7,9), (1,5)(2,9)(3,8)(4,12)(6,11)(7,10) ], +> [ (1,12)(2,3)(6,7)(8,9), (1,5,9)(2,6,10)(3,7,11)(4,8,12), +> (1,3,5)(2,4,12)(6,8,10)(7,9,11), (2,4)(3,5)(6,7)(8,11)(9,10) ], +> [ (1,10)(3,12)(4,7)(6,9), (1,7)(3,9)(4,10)(6,12), +> (1,5,9)(2,6,10)(3,7,11)(4,8,12), (1,5)(2,10)(4,8)(7,11) ], +> [ (1,12)(2,3)(6,7)(8,9), (2,8)(3,9)(4,10)(5,11), +> (1,5,9)(2,6,10)(3,7,11)(4,8,12), (1,7)(2,10)(3,11)(4,8)(5,9)(6,12) ], +> [ (1,12)(4,5), (1,12)(8,9), (1,5,9)(2,6,10)(3,7,11)(4,8,12), +> (1,11)(2,8)(3,9)(4,6)(5,7)(10,12) ], +> [ (2,6,10)(3,7,11)(4,8,12), (1,2)(3,12)(4,11)(5,10)(6,9)(7,8), +> (1,7)(2,8)(3,9)(4,10)(5,11)(6,12) ], +> [ (2,6,10)(3,7,11)(4,8,12), (1,10)(2,5)(3,12)(4,7)(6,9)(8,11), +> (1,7)(2,8)(3,9)(4,10)(5,11)(6,12) ], +> [ (2,6,10)(3,7,11)(4,8,12), (1,4,7,10)(2,5,8,11)(3,6,9,12) ], +> [ (2,6,10)(3,7,11)(4,8,12), (1,7)(2,8)(3,9)(4,10)(5,11)(6,12), +> (1,8,7,2)(3,6,9,12)(4,11,10,5) ], +> [ (2,4,6,8,10)(3,5,7,9,11), (1,10)(2,7)(3,12)(4,5)(6,11)(8,9) ], +> [ (1,3,5,7,9)(2,4,6,8,12), (1,11)(2,8)(3,9)(10,12), +> (1,12)(2,3)(4,5)(6,7)(8,9)(10,11) ], +> [ (1,12)(2,3)(4,5)(6,7)(8,9)(10,11), (2,4,6,8,10)(3,5,7,9,11), +> (4,10)(5,11)(6,8)(7,9), (1,2)(3,12)(4,11)(5,10) ], +> [ (2,6,10)(4,8,12), (2,10)(4,8), (1,10)(2,5)(3,12)(4,7)(6,9)(8,11), +> (1,7)(2,8)(3,9)(4,10)(5,11)(6,12) ], +> [ (1,12)(2,3)(4,5)(6,7)(8,9)(10,11), (1,3,5,7,9,11)(2,4,6,8,10,12), +> (1,3,5,11,9,7)(2,4,10,8,6,12), (2,3)(6,11)(7,10) ], +> [ (2,6,10)(4,8,12), (2,10)(4,8), (1,4,7,10)(2,5,8,11)(3,6,9,12) ], +> [ (1,12)(2,3)(4,5)(6,7)(8,9)(10,11), (2,6,10)(3,7,11), +> (1,3)(2,12)(4,6,8,10)(5,7,9,11), (2,3)(6,11)(7,10) ], +> [ (2,6,10)(4,8,12), (1,5)(2,10)(4,8)(7,11), (1,4,7,10)(2,5,8,11)(3,6,9,12), +> (1,7)(3,9)(5,11) ], +> [ (1,12)(4,5)(8,9), (1,5,9)(4,8,12), (2,10)(3,11)(4,8)(5,9), +> (1,7)(2,8,10,4)(3,9,11,5)(6,12) ], +> [ (1,4,7,10)(2,5,8,11)(3,6,9,12), (1,10)(2,5)(6,9), +> (1,5,9)(2,6,10)(3,7,11)(4,8,12), (1,5)(2,10)(4,8)(7,11) ], +> [ (2,6,10)(3,7,11)(4,8,12), (1,5)(2,10)(4,8)(7,11), +> (1,4,2,11,5,8,10,7)(3,9,12,6), (3,4)(6,10)(7,12)(8,11) ], +> [ (1,10)(3,12)(4,7)(6,9), (1,7,10)(2,5,11)(3,6,9), +> (1,5,9)(2,6,10)(3,7,11)(4,8,12) ], +> [ (3,9)(6,12), (1,10)(2,5)(3,12)(4,7)(6,9)(8,11), (1,7)(3,9)(5,11), +> (1,5,9)(2,6,10)(3,7,11)(4,8,12), (1,5)(2,10)(4,8)(7,11) ], +> [ (1,12)(2,3), (1,3,5,7,9,11)(2,4,6,8,10,12) ], +> [ (1,12)(6,7), (1,12)(2,3)(4,5), (1,5,9)(2,6,10)(3,7,11)(4,8,12), +> (1,3,11)(2,10,12)(4,6,8)(5,7,9) ], +> [ (1,12)(2,3), (1,7,9,3,5,11)(2,4,10,12,6,8), (1,12)(4,6)(5,7)(10,11) ], +> [ (3,12)(6,9), (3,9)(6,12), (1,5,9)(2,6,10)(3,7,11)(4,8,12) ], +> [ (1,12)(2,3), (1,7,9,3,5,11)(2,4,10,12,6,8), (6,7)(8,10,9,11) ], +> [ (1,12)(6,7), (1,12)(2,3)(4,5), (1,5,9)(2,6,10)(3,7,11)(4,8,12), +> (2,8)(3,9)(4,10)(5,11)(6,7) ], +> [ (1,12)(6,7), (1,12)(2,3)(4,5), (1,5,9)(2,6,10)(3,7,11)(4,8,12), +> (2,8,3,9)(4,10)(5,11) ], [ (3,6,9,12), (1,5,9)(2,6,10)(3,7,11)(4,8,12) ] +> , [ (3,9)(6,12), (1,10,7,4)(3,6,9,12), (1,5,9)(2,6,10)(3,7,11)(4,8,12), +> (1,5)(2,10)(4,8)(7,11) ], +> [ (1,12)(2,3), (1,5,9)(2,6,10)(3,7,11)(4,8,12), (2,3)(4,10)(5,11)(6,8)(7,9)], +> [ (1,12)(2,3), (1,5,9)(2,6,10)(3,7,11)(4,8,12), +> (1,3)(2,12)(4,8)(5,9)(6,11)(7,10) ], +> [ (3,9)(6,12), (1,10,7,4)(3,6,9,12), (1,5,9)(2,6,10)(3,7,11)(4,8,12), +> (1,8,7,2)(3,6,9,12)(4,11,10,5) ], +> [ (1,12)(2,3), (1,5,9)(2,6,10)(3,7,11)(4,8,12), (4,6)(5,7)(8,10)(9,11), +> (2,3)(4,5)(8,10,9,11) ], +> [ (1,12)(2,3), (1,5,9)(2,6,10)(3,7,11)(4,8,12), +> (1,7,11)(2,4,8)(3,5,9)(6,10,12), (2,3)(4,8)(5,9)(6,11)(7,10) ], +> [ (3,9)(6,12), (1,10)(3,12)(4,7)(6,9), (1,5,9)(2,6,10)(3,7,11)(4,8,12), +> (1,5)(2,10)(4,8)(7,11) ], +> [ (1,12)(2,3), (1,5,9)(2,6,10)(3,7,11)(4,8,12), +> (1,7,11)(2,4,8)(3,5,9)(6,10,12), (1,2,12,3)(4,8,5,9)(6,11,7,10) ], +> [ (3,12)(6,9), (1,7)(3,9)(4,10)(6,12), (1,5,9)(2,6,10)(3,7,11)(4,8,12), +> (1,11)(2,4)(3,9)(5,7)(6,12)(8,10) ], +> [ (1,12)(2,3), (1,5,9)(2,6,10)(3,7,11)(4,8,12), (6,7)(8,10)(9,11) ], +> [ (1,12)(2,3), (1,2,4,6,8,10,12,3,5,7,9,11) ], +> [ (1,12)(2,3), (1,12)(4,5), (1,12)(6,7), (1,5,9)(2,6,10)(3,7,11)(4,8,12), +> (1,11)(2,8)(3,9)(4,6)(5,7)(10,12) ], +> [ (1,12)(2,3), (1,12)(4,5), (1,12)(6,7), (1,5,9)(2,6,10)(3,7,11)(4,8,12), +> (1,10,12,11)(2,8)(3,9)(4,6)(5,7) ], +> [ (1,12)(4,5), (1,12)(8,9), (1,3,5,7,9,11)(2,4,6,8,10,12), +> (1,10,12,11)(2,9,3,8)(4,6)(5,7) ], +> [ (1,12)(4,5), (1,12)(8,9), (1,3,5,7,9,11)(2,4,6,8,10,12), +> (1,11)(2,8)(3,9)(4,6)(5,7)(10,12) ], +> [ (1,12)(2,3)(6,7)(8,9), (1,12)(2,3)(4,5), (2,8)(3,9)(4,10)(5,11), +> (1,5,9)(2,6,10)(3,7,11)(4,8,12), (2,10)(3,11)(4,8)(5,9) ], +> [ (1,12)(2,3)(6,7)(8,9), (1,12)(2,3)(4,5), (1,5,9)(2,6,10)(3,7,11)(4,8,12), +> (1,3,11)(2,10,12)(4,6,8)(5,7,9), (2,4)(3,5)(6,7)(8,11)(9,10) ], +> [ (1,12)(2,3)(6,7)(8,9), (1,5,9)(2,6,10)(3,7,11)(4,8,12), +> (1,3)(2,12)(4,10)(5,11)(6,8)(7,9), (2,3)(4,10)(5,11)(6,7) ], +> [ (1,12)(2,3)(6,7)(8,9), (1,3,5,7,9,11)(2,4,6,8,10,12), +> (1,3)(2,12)(4,10)(5,11)(6,8)(7,9), (4,10)(5,11)(6,7)(8,9) ], +> [ (1,12)(2,3)(6,7)(8,9), (1,12)(2,3)(4,5), (1,5,9)(2,6,10)(3,7,11)(4,8,12), +> (2,10)(3,11)(4,8)(5,9), (2,4)(3,5)(8,11)(9,10) ], +> [ (1,12)(2,3)(6,7)(8,9), (1,12)(2,3)(4,5), (1,5,9)(2,6,10)(3,7,11)(4,8,12), +> (2,4)(3,5)(6,7)(8,10)(9,11) ], +> [ (2,6,10)(3,7,11)(4,8,12), (1,4,7,10)(2,5,8,11)(3,6,9,12), +> (1,7)(3,9)(5,11) ], +> [ (2,6,10)(3,7,11)(4,8,12), (1,5)(2,10)(4,8)(7,11), +> (1,10)(2,5)(3,12)(4,7)(6,9)(8,11), (1,7)(2,8)(3,9)(4,10)(5,11)(6,12) ], +> [ (2,6,10)(3,7,11)(4,8,12), (1,10)(2,5)(3,12)(4,7)(6,9)(8,11), +> (1,7)(2,8)(3,9)(4,10)(5,11)(6,12), (1,11)(2,10)(3,9)(4,8)(5,7) ], +> [ (2,6,10)(3,7,11)(4,8,12), (1,5)(2,10)(4,8)(7,11), +> (1,4,7,10)(2,5,8,11)(3,6,9,12) ], +> [ (2,6,10)(3,7,11)(4,8,12), (1,4,7,10)(2,5,8,11)(3,6,9,12), +> (1,11)(2,10)(3,9)(4,8)(5,7) ], +> [ (2,6,10)(3,7,11)(4,8,12), (2,8)(4,10)(6,12), (1,7)(3,9)(5,11), +> (1,2)(3,12)(4,11)(5,10)(6,9)(7,8) ], +> [ (2,6,10)(3,7,11)(4,8,12), (1,5)(2,10)(4,8)(7,11), +> (2,3,4)(6,7,8)(10,11,12), (1,7,2)(3,6,9)(5,11,10) ], +> [ (1,3,5,7,9)(2,4,6,8,12), (1,11)(2,4)(3,5)(6,8)(7,9)(10,12), +> (1,12)(2,3)(4,5)(6,7)(8,9)(10,11) ], +> [ (1,12)(2,3)(4,5)(6,7)(8,9)(10,11), (2,4,6,8,10)(3,5,7,9,11), +> (1,3,12,2)(4,6,5,7)(8,11,9,10) ], +> [ (2,6,10)(4,8,12), (2,10)(4,8), (1,4,7,10)(2,5,8,11)(3,6,9,12), +> (1,7)(3,9)(5,11) ], +> [ (2,8)(4,10), (2,6,10)(4,8,12), (1,12)(2,3)(4,5)(6,7)(8,9)(10,11) ], +> [ (1,10)(3,12)(4,7)(6,9), (1,7,10)(2,5,11)(3,6,9), +> (1,5,9)(2,6,10)(3,7,11)(4,8,12), (1,2)(4,8)(5,10)(6,9)(7,11) ], +> [ (1,10)(3,12)(4,7)(6,9), (1,7,10)(2,5,11)(3,6,9), +> (1,5,9)(2,6,10)(3,7,11)(4,8,12), (1,5)(2,10)(4,8)(7,11) ], +> [ (1,10)(3,12)(4,7)(6,9), (1,7,10)(2,5,11)(3,6,9), (4,7)(6,9)(8,11), +> (1,5,9)(2,6,10)(3,7,11)(4,8,12) ], +> [ (4,8,12), (1,10)(2,5)(3,12)(4,7)(6,9)(8,11), +> (1,7)(2,8)(3,9)(4,10)(5,11)(6,12) ], +> [ (4,8,12), (1,4,7,10)(2,5,8,11)(3,6,9,12) ], +> [ (2,6,10)(3,7,11)(4,8,12), (1,10)(2,5)(3,12)(4,7)(6,9)(8,11), +> (1,7)(2,8)(3,9)(4,10)(5,11)(6,12), (1,7,10)(2,5,11)(3,6,9)(4,8,12) ], +> [ (2,6,10)(3,7,11)(4,8,12), (2,8,11)(3,6,12)(4,7,10), +> (1,7,10)(2,5,11)(3,6,9) ], [ (1,12), (1,3,5,7,9,11)(2,4,6,8,10,12) ], +> [ (1,12), (1,5,9)(2,6,10)(3,7,11)(4,8,12), +> (1,11)(2,8)(3,9)(4,6)(5,7)(10,12) ], +> [ (1,12)(2,3), (1,3,5,7,9,11)(2,4,6,8,10,12), +> (1,11)(2,8)(3,9)(4,6)(5,7)(10,12) ], +> [ (1,12)(6,7), (1,12)(2,3)(4,5), (2,8)(3,9)(4,10)(5,11), +> (1,5,9)(2,6,10)(3,7,11)(4,8,12), (2,10)(3,11)(4,8)(5,9) ], +> [ (1,12)(2,3), (1,11,5,3,9,7)(2,8,6,12,10,4), (4,8)(5,9)(6,10)(7,11), +> (4,10)(5,11)(6,9)(7,8) ], +> [ (3,12)(6,9), (3,9)(6,12), (1,5,9)(2,6,10)(3,7,11)(4,8,12), +> (1,5)(2,10)(4,8)(7,11) ], +> [ (1,12)(6,7), (1,12)(2,3)(4,5), (1,5,9)(2,6,10)(3,7,11)(4,8,12), +> (2,10)(3,11)(4,8)(5,9), (2,4)(3,5)(8,11)(9,10) ], +> [ (3,6,9,12), (1,7)(3,9)(5,11), (1,5,9)(2,6,10)(3,7,11)(4,8,12) ], +> [ (3,12)(6,9), (3,9)(6,12), (1,7)(3,9)(5,11), +> (1,5,9)(2,6,10)(3,7,11)(4,8,12) ], +> [ (1,12)(6,7), (1,12)(2,3)(4,5), (1,3,5,7,9,11)(2,4,6,8,10,12), +> (4,10)(5,11)(6,7) ], +> [ (1,12)(2,3), (2,8)(3,9)(4,10)(5,11), (1,5,9)(2,6,10)(3,7,11)(4,8,12) ], +> [ (1,12)(2,3), (1,3,5,7,9,11)(2,4,6,8,10,12), +> (1,10,12,11)(2,8)(3,9)(4,6)(5,7) ], +> [ (1,12)(6,7), (1,12)(2,3)(4,5), (2,8)(3,9)(4,10)(5,11), +> (1,5,9)(2,6,10)(3,7,11)(4,8,12), (1,7)(2,10)(3,11)(4,8)(5,9)(6,12) ], +> [ (1,12)(2,3), (1,11,5,3,9,7)(2,8,6,12,10,4), (2,3)(4,10)(5,11)(6,8)(7,9) ], +> [ (3,12)(6,9), (1,5,9)(2,6,10)(3,7,11)(4,8,12), (1,11)(2,10)(3,9)(4,8)(5,7) +> ], [ (1,12)(6,7), (1,12)(2,3)(4,5), (1,5,9)(2,6,10)(3,7,11)(4,8,12), +> (1,3)(2,12)(4,10)(5,11)(6,8)(7,9), (2,8)(3,9)(4,10)(5,11)(6,7) ], +> [ (3,6,9,12), (1,5,9)(2,6,10)(3,7,11)(4,8,12), (1,5)(2,10)(4,8)(7,11) ], +> [ (3,6,9,12), (1,5,9)(2,6,10)(3,7,11)(4,8,12), (1,11)(2,10)(3,9)(4,8)(5,7) ] +> , [ (1,12)(2,3), (1,5,9)(2,6,10)(3,7,11)(4,8,12), (4,8,6,10)(5,9,7,11), +> (2,3)(4,8)(5,9)(6,11)(7,10) ], +> [ (1,12)(2,3), (1,5,9)(2,6,10)(3,7,11)(4,8,12), +> (1,3)(2,12)(4,8,6,10)(5,9,7,11), (1,2,12,3)(4,6,5,7)(8,10,9,11) ], +> [ (1,12)(2,3), (1,5,9)(2,6,10)(3,7,11)(4,8,12), +> (1,3)(2,12)(4,10)(5,11)(6,8)(7,9), (2,3)(4,8)(5,9)(6,10)(7,11) ], +> [ (1,12)(2,3), (1,5,9)(2,6,10)(3,7,11)(4,8,12), (4,8)(5,9)(6,10)(7,11), +> (1,2,12,3)(4,10,5,11)(6,8,7,9) ], +> [ (2,6,10)(3,7,11)(4,8,12), (1,5)(2,10)(4,8)(7,11), +> (1,4,7,10)(2,5,8,11)(3,6,9,12), (1,7)(3,9)(5,11) ], +> [ (2,6,10)(3,7,11)(4,8,12), (1,5)(2,10)(4,8)(7,11), +> (1,4,2,11,5,8,10,7)(3,9,12,6), (2,3,4)(6,7,8)(10,11,12) ], +> [ (1,12)(2,3), (1,5,9)(4,8,12), (1,7)(2,8)(3,9)(4,10)(5,11)(6,12) ], +> [ (1,12)(2,3), (1,5,9)(4,8,12), (2,6,10)(3,7,11), +> (1,2,12,3)(4,10,5,11)(6,8,7,9) ], +> [ (2,8)(4,10), (2,6,10)(4,8,12), (1,7)(2,10)(3,11)(4,8)(5,9)(6,12), +> (1,12,7,6)(2,11,10,3)(4,9,8,5) ], +> [ (2,8)(4,10), (2,6,10)(4,8,12), (1,7)(2,10)(3,11)(4,8)(5,9)(6,12), +> (1,12)(2,3)(4,5)(6,7)(8,9)(10,11) ], +> [ (1,12)(4,5), (1,12)(8,9), (1,5,9)(4,8,12), (2,10)(3,11)(4,8)(5,9), +> (1,7)(2,8,10,4)(3,9,11,5)(6,12) ], +> [ (1,12)(4,5), (1,12)(8,9), (1,5,9)(4,8,12), (2,10)(3,11)(4,8)(5,9), +> (1,7)(2,8)(3,9)(4,10)(5,11)(6,12) ], +> [ (3,12)(6,9), (3,9)(6,12), (2,8,11)(3,6,12)(4,7,10), +> (1,5,9)(2,6,10)(3,7,11)(4,8,12) ], +> [ (1,10)(3,12)(4,7)(6,9), (1,7,10)(2,5,11)(3,6,9), (4,7)(6,9)(8,11), +> (1,5,9)(2,6,10)(3,7,11)(4,8,12), (1,5)(2,10)(4,8)(7,11) ], +> [ (3,12)(6,9), (3,9)(6,12), (2,8,11)(3,6,12)(4,7,10), +> (1,3,11,7,6,2,10,9,5)(4,12,8) ], +> [ (4,8,12), (1,4,7,10)(2,5,8,11)(3,6,9,12), (1,7)(3,9)(5,11) ], +> [ (4,8,12), (1,5)(2,10)(4,8)(7,11), (1,10)(2,5)(3,12)(4,7)(6,9)(8,11), +> (1,7)(2,8)(3,9)(4,10)(5,11)(6,12) ], +> [ (4,8,12), (1,4,7,10)(2,5,8,11)(3,6,9,12), (1,11)(2,10)(3,9)(4,8)(5,7) ], +> [ (4,8,12), (1,5)(2,10)(4,8)(7,11), (1,4,7,10)(2,5,8,11)(3,6,9,12) ], +> [ (4,8,12), (1,5)(2,10)(4,8)(7,11), (1,10)(2,5)(3,12)(4,7)(6,9)(8,11), +> (1,7,5,11)(2,8,10,4)(3,9)(6,12) ], +> [ (4,8,12), (1,5)(2,10)(4,8)(7,11), (1,10)(2,5)(3,12)(4,7)(6,9)(8,11), +> (1,7)(2,4)(3,9)(5,11)(6,12)(8,10) ], +> [ (4,8,12), (1,5)(2,10)(4,8)(7,11), (1,4,7,10,5,8,11,2)(3,6,9,12) ], +> [ (4,8,12), (1,5)(2,10)(4,8)(7,11), (1,10,5,2)(3,12)(4,7,8,11)(6,9), +> (1,7,5,11)(2,8,10,4)(3,9)(6,12) ], +> [ (2,6,10)(3,7,11)(4,8,12), (1,4,7,10)(2,5,8,11)(3,6,9,12), +> (1,10)(2,5)(6,9) ], +> [ (2,6,10)(3,7,11)(4,8,12), (1,5)(2,10)(4,8)(7,11), +> (2,8,11)(3,6,12)(4,7,10), (1,7,10)(2,5,11)(3,6,9) ], +> [ (2,6,10)(3,7,11)(4,8,12), (1,10)(2,5)(3,12)(4,7)(6,9)(8,11), +> (3,8)(4,7)(5,9)(6,10)(11,12), (2,7)(3,6)(4,8)(5,9)(10,11) ], +> [ (2,6,10)(3,7,11)(4,8,12), (2,8,11)(3,6,12)(4,7,10), +> (1,7,10)(2,5,11)(3,6,9), (1,11)(2,10)(3,9)(4,8)(5,7) ], +> [ (1,2,3,4,5,6,7,8,9,10,12), (1,10)(2,5)(3,7)(4,8)(6,9)(11,12) ], +> [ (1,3,5)(2,4,12), (2,4,6,8,10)(3,5,7,9,11), +> (1,12)(2,3)(4,5)(6,7)(8,9)(10,11) ], +> [ (1,3,5)(2,4,12)(7,9,11), (1,7,3,9,5)(2,4,6,8,10), +> (1,12)(2,3,4,5)(6,11,8,9)(7,10) ], +> [ (1,3,5)(2,4,12)(7,9,11), (1,7,3,9,5)(2,4,6,8,10), +> (1,12)(2,3)(4,11)(5,10)(6,9)(7,8) ], +> [ (1,3,5)(2,4,12), (2,4,6,8,10)(3,5,7,9,11), +> (1,12)(2,3)(4,5)(6,7)(8,11)(9,10) ], +> [ (1,12)(2,3), (2,8)(3,9)(4,10)(5,11), (1,5,9)(2,6,10)(3,7,11)(4,8,12), +> (2,10)(3,11)(4,8)(5,9) ], +> [ (3,6,9,12), (1,7)(3,9)(5,11), (1,5,9)(2,6,10)(3,7,11)(4,8,12), +> (1,5)(2,10)(4,8)(7,11) ], +> [ (3,12)(6,9), (3,9)(6,12), (1,7)(3,9)(5,11), +> (1,5,9)(2,6,10)(3,7,11)(4,8,12), (1,5)(2,10)(4,8)(7,11) ], +> [ (1,12)(2,3), (1,7)(6,12), (1,5,9)(2,6,10)(3,7,11)(4,8,12) ], +> [ (1,12), (2,8)(3,9)(4,10)(5,11), (1,5,9)(2,6,10)(3,7,11)(4,8,12) ], +> [ (3,6,9,12), (1,7)(3,9), (1,5,9)(2,6,10)(3,7,11)(4,8,12) ], +> [ (1,12)(2,3), (2,8)(3,9)(4,10)(5,11), (1,5,9)(2,6,10)(3,7,11)(4,8,12), +> (1,12)(2,10)(3,11)(4,8)(5,9) ], +> [ (1,12)(2,3), (2,8)(3,9)(4,10)(5,11), (1,5,9)(2,6,10)(3,7,11)(4,8,12), +> (1,7)(2,10)(3,11)(4,8)(5,9)(6,12) ], +> [ (1,12)(2,3), (2,8)(3,9)(4,10)(5,11), (1,5,9)(2,6,10)(3,7,11)(4,8,12), +> (1,6,12,7)(2,10)(3,11)(4,8)(5,9) ], +> [ (1,12), (1,3,5,7,9,11)(2,4,6,8,10,12), (1,11)(2,8)(3,9)(4,6)(5,7)(10,12) ] +> , [ (4,8,12), (2,8,11)(3,6,12)(4,7,10), (1,7,10)(2,5,11)(3,6,9) ], +> [ (1,12)(2,3), (1,5,9)(4,8,12), (2,10)(3,11)(4,8)(5,9), +> (1,7)(2,8)(3,9)(4,10)(5,11)(6,12) ], +> [ (1,12)(2,3), (1,5,9)(4,8,12), (1,3,5,7,9,11)(2,4,6,8,10,12), +> (2,3)(4,8)(5,9)(6,10)(7,11) ], +> [ (1,12)(2,3), (1,5,9)(4,8,12), (2,10)(3,11)(4,8)(5,9), +> (1,6,12,7)(2,8)(3,9)(4,10)(5,11) ], +> [ (1,12)(2,3), (1,5,9)(4,8,12), (2,10)(3,11)(4,8)(5,9), +> (1,6,12,7)(2,8,10,4)(3,9,11,5) ], +> [ (1,12)(2,3), (1,5,9)(4,8,12), (2,10)(3,11)(4,8)(5,9), +> (1,7)(2,8,10,4)(3,9,11,5)(6,12) ], +> [ (2,8)(4,10), (2,6,10)(4,8,12), (2,10)(4,8)(6,12), +> (1,12)(2,3)(4,5)(6,7)(8,9)(10,11) ], +> [ (1,12)(4,5), (1,12)(8,9), (1,3,5,11,9,7)(2,4,10,8,6,12), (2,6,10)(3,7,11), +> (6,10)(7,11)(8,9) ], +> [ (1,12)(4,5), (1,12)(8,9), (1,3,5,11,9,7)(2,4,10,8,6,12), (2,6,10)(3,7,11), +> (2,6)(3,7)(4,8)(5,9), (2,3)(6,10)(7,11)(8,9) ], +> [ (2,8)(4,10), (2,6,10)(4,8,12), (2,10)(4,8), +> (1,12)(2,3)(4,5)(6,7)(8,9)(10,11) ], +> [ (3,12)(6,9), (3,9)(6,12), (2,8,11)(3,6,12)(4,7,10), +> (1,5,9)(2,6,10)(3,7,11)(4,8,12), (1,2)(4,8)(5,10)(6,9)(7,11) ], +> [ (3,12)(6,9), (3,9)(6,12), (2,8,11)(3,6,12)(4,7,10), (1,10)(2,5)(6,9), +> (1,5,9)(2,6,10)(3,7,11)(4,8,12) ], +> [ (3,12)(6,9), (3,9)(6,12), (2,8,11)(3,6,12)(4,7,10), +> (1,5,9)(2,6,10)(3,7,11)(4,8,12), (1,5)(2,10)(4,8)(7,11) ], +> [ (3,12)(6,9), (3,9)(6,12), (2,8,11)(3,6,12)(4,7,10), +> (1,2)(4,11)(5,7)(6,9)(8,10), (1,3)(4,12)(6,10)(7,9)(8,11) ], +> [ (6,12), (2,6,10)(4,8,12), (1,12)(2,3)(4,5)(6,7)(8,9)(10,11) ], +> [ (4,8,12), (1,5)(2,10)(4,8)(7,11), (1,4,7,10)(2,5,8,11)(3,6,9,12), +> (1,7)(2,10)(3,9)(4,8)(5,11) ], +> [ (4,8,12), (2,10)(4,8), (1,10)(2,5)(3,12)(4,7)(6,9)(8,11), +> (1,7)(2,8)(3,9)(4,10)(5,11)(6,12) ], +> [ (4,8,12), (2,10)(4,8), (1,4,7,10)(2,5,8,11)(3,6,9,12) ], +> [ (4,8,12), (1,5)(2,10)(4,8)(7,11), (1,2,5,10)(3,12)(4,7,8,11)(6,9), +> (2,3)(5,9)(6,11)(7,10) ], +> [ (2,6,10)(3,7,11)(4,8,12), (1,5)(2,10)(4,8)(7,11), +> (1,4,7,10)(2,5,8,11)(3,6,9,12), (1,10)(2,5)(6,9) ], +> [ (4,8,12), (2,10)(4,8), (1,7)(2,8,10,4)(3,9,11,5)(6,12), +> (1,12)(2,3)(4,5)(6,7)(8,9)(10,11) ], +> [ (4,8,12), (2,10)(4,8), (1,7)(2,8,10,4)(3,9,11,5)(6,12), +> (1,12,7,6)(2,9,8,11,10,5,4,3) ], +> [ (4,8,12), (1,5)(2,10)(4,8)(7,11), (1,7)(2,8)(3,9)(4,10)(5,11)(6,12), +> (2,3)(5,9)(6,11)(7,10) ], +> [ (4,8,12), (1,5)(2,10)(4,8)(7,11), (1,4,7,10)(2,5,8,11)(3,6,9,12), +> (1,7)(3,9)(5,11) ], +> [ (1,2,3,4,5,6,7,8,9,10,12), (1,10)(2,5)(3,7)(4,8)(6,9)(11,12), +> (1,2,4,8,5,10,9,7,3,6) ], +> [ (1,3)(2,12), (1,3,5,7,9,11)(2,4,6,8,10,12), +> (1,12)(2,3)(4,5)(6,7)(8,9)(10,11) ], +> [ (1,3,5)(2,4,12)(7,9,11), (1,7,3,9,5)(2,4,6,8,10), (1,9)(2,12)(3,7)(5,11), +> (1,12)(2,3)(4,11)(5,10)(6,9)(7,8) ], +> [ (3,6,9,12), (1,7)(3,9), (1,5,9)(2,6,10)(3,7,11)(4,8,12), +> (1,5)(2,10)(4,8)(7,11) ], +> [ (3,6,9,12), (3,9), (1,5,9)(2,6,10)(3,7,11)(4,8,12) ], +> [ (3,12)(6,9), (3,9)(6,12), (1,7)(3,9), (1,5,9)(2,6,10)(3,7,11)(4,8,12), +> (1,11)(2,10)(3,9)(4,8)(5,7) ], +> [ (1,12), (2,8)(3,9)(4,10)(5,11), (1,5,9)(2,6,10)(3,7,11)(4,8,12), +> (1,7)(2,10)(3,11)(4,8)(5,9)(6,12) ], +> [ (3,6,9,12), (1,7)(3,9), (1,5,9)(2,6,10)(3,7,11)(4,8,12), +> (1,11)(2,10)(3,9)(4,8)(5,7) ], +> [ (1,12)(2,3), (1,7)(6,12), (1,5,9)(2,6,10)(3,7,11)(4,8,12), +> (2,10)(3,11)(4,8)(5,9) ], +> [ (1,12), (2,8)(3,9)(4,10)(5,11), (1,5,9)(2,6,10)(3,7,11)(4,8,12), +> (2,10)(3,11)(4,8)(5,9) ], +> [ (3,12)(6,9), (3,9)(6,12), (3,6,12)(4,10,7), (1,5,9)(2,6,4,8,12,7,11,3,10)], +> [ (3,12)(6,9), (3,9)(6,12), (3,6,12)(4,10,7), +> (1,5,9)(2,6,10)(3,7,11)(4,8,12) ], +> [ (1,12)(2,3), (1,3,5,7,9)(2,4,6,8,12), (1,11)(2,8)(3,9)(10,12) ], +> [ (4,8,12), (1,4,7,10)(2,5,8,11)(3,6,9,12), (1,10)(2,5)(6,9) ], +> [ (4,8,12), (1,5)(2,10)(4,8)(7,11), (1,7,10)(2,5,11)(3,6,9), +> (2,8,7)(3,6,12)(4,11,10) ], +> [ (4,8,12), (2,8,11)(3,6,12)(4,7,10), (1,7,10)(2,5,11)(3,6,9), +> (1,11)(2,10)(3,9)(4,8)(5,7) ], +> [ (4,8,12), (1,5)(2,10)(4,8)(7,11), (2,8,11)(3,6,12)(4,7,10), +> (1,7,10)(2,5,11)(3,6,9) ], +> [ (1,12)(2,3), (2,6,10)(3,7,11), (1,3,5,7,9,11)(2,4,6,8,10,12), +> (2,6)(3,7)(4,8)(5,9), (6,10)(7,11)(8,9) ], +> [ (1,12)(2,3), (1,5,9)(4,8,12), (4,8)(5,9), +> (1,7)(2,8)(3,9)(4,10)(5,11)(6,12) ], +> [ (1,12)(2,3), (2,6,10)(3,7,11), (4,8)(5,9), (1,3,5,7)(2,4,6,12)(8,10,9,11) +> ], [ (1,12)(2,3), (2,6,10)(3,7,11), (1,3)(2,12)(4,6,8,10)(5,7,9,11), +> (6,10)(7,11)(8,9) ], +> [ (3,12)(6,9), (3,9)(6,12), (2,8,11)(3,6,12)(4,7,10), (1,10)(2,5)(6,9), +> (1,5,9)(2,6,10)(3,7,11)(4,8,12), (1,5)(2,10)(4,8)(7,11) ], +> [ (1,12), (1,5,9)(4,8,12), (2,10)(3,11)(4,8)(5,9), +> (1,7)(2,8)(3,9)(4,10)(5,11)(6,12) ], +> [ (1,12), (1,5,9)(4,8,12), (2,10)(3,11)(4,8)(5,9), +> (1,7)(2,8,10,4)(3,9,11,5)(6,12) ], +> [ (4,8,12), (4,8)(7,11), (2,10)(4,8), (1,10)(2,5)(3,12)(4,7)(6,9)(8,11), +> (1,7)(2,8)(3,9)(4,10)(5,11)(6,12) ], +> [ (4,8,12), (2,10)(4,8), (1,10)(2,5)(3,12)(4,7)(6,9)(8,11), +> (1,7)(3,9)(5,11)(6,10) ], +> [ (4,8,12), (2,10)(4,8), (1,7)(2,8)(3,9)(4,10)(5,11)(6,12), +> (1,4,11,10,5,8,7,2)(3,6,9,12) ], +> [ (4,8,12), (4,8)(7,11), (1,4,7,10)(2,5,8,11)(3,6,9,12) ], +> [ (4,8,12), (2,10)(4,8), (1,10)(2,5)(3,12)(4,7)(6,9)(8,11), +> (1,7)(2,8,10,4)(3,9)(5,11)(6,12) ], +> [ (4,8,12), (2,10)(4,8), (1,4,7,10)(2,5,8,11)(3,6,9,12), +> (1,2)(3,12)(4,7)(5,10)(6,9)(8,11) ], +> [ (4,8,12), (2,10)(4,8), (1,4,7,10)(2,5,8,11)(3,6,9,12), (1,7)(3,9)(5,11) ], +> [ (4,8,12), (2,10)(4,8), (2,8,10,4)(6,12), +> (1,12)(2,3)(4,5)(6,7)(8,9)(10,11) ], +> [ (3,6,9,12), (3,9), (1,5,9)(2,6,10)(3,7,11)(4,8,12), +> (1,5)(2,10)(4,8)(7,11) ], +> [ (3,12)(6,9), (3,9)(6,12), (3,6,12)(4,10,7), +> (1,5,9)(2,6,10)(3,7,11)(4,8,12), (1,5)(2,7)(4,8)(6,9)(10,11) ], +> [ (3,12)(6,9), (3,9)(6,12), (3,6,12)(4,10,7), +> (1,5,9)(2,6,10)(3,7,11)(4,8,12), (1,5)(2,10)(4,8)(7,11) ], +> [ (3,12)(6,9), (3,9)(6,12), (1,10,7)(3,6,9), (2,11)(3,6)(7,10), +> (1,5,9)(2,6,10)(3,7,11)(4,8,12) ], +> [ (3,12)(6,9), (3,9)(6,12), (3,6,12)(4,10,7), (1,6)(3,7)(4,12)(8,11)(9,10), +> (1,5)(2,7)(4,8)(6,9)(10,11) ], +> [ (1,12), (1,3,5,7,9)(2,4,6,8,12), (1,11)(2,8)(3,9)(10,12) ], +> [ (1,12)(2,3), (1,3,5,7,9)(2,4,6,8,12), (1,10,12,11)(2,4)(3,5)(6,8)(7,9) ], +> [ (1,12)(2,3), (1,3,5,7,9)(2,4,6,8,12), (1,11)(2,4)(3,5)(6,8)(7,9)(10,12) ], +> [ (4,8,12), (1,5)(2,10)(4,8)(7,11), (1,4,7,10)(2,5,8,11)(3,6,9,12), +> (1,10)(2,5)(6,9) ], +> [ (4,8,12), (1,5)(2,10)(4,8)(7,11), (1,7,10)(2,5,11)(3,6,9), +> (3,12)(4,7)(6,10)(8,11) ], +> [ (6,12), (2,6,10)(4,8,12), (2,10)(4,8), (1,12)(2,3)(4,5)(6,7)(8,9)(10,11) ], +> [ (4,8,12), (4,8), (1,10)(2,5)(3,12)(4,7)(6,9)(8,11), +> (1,7)(2,8)(3,9)(4,10)(5,11)(6,12) ], +> [ (4,8,12), (2,10)(4,8), (2,8)(4,10)(6,12), (1,7)(3,9)(5,11), +> (1,4,11,10,5,8,7,2)(3,6,9,12) ], +> [ (4,8,12), (2,10)(4,8), (1,4,7,10)(2,5,8,11)(3,6,9,12), +> (1,7,5,11)(2,10)(3,9)(4,8) ], +> [ (4,8,12), (4,8), (1,4,7,10)(2,5,8,11)(3,6,9,12) ], +> [ (3,6,12), (3,6,9), (1,5,9)(2,6,10)(3,7,11)(4,8,12) ], +> [ (4,8,12), (2,10)(4,8), (1,10)(2,5)(3,12)(4,7)(6,9)(8,11), +> (1,7)(2,8)(3,9)(4,10)(5,11)(6,12), (1,7,5,11)(2,10)(3,9)(4,8) ], +> [ (4,8,12), (4,8)(7,11), (1,4,7,10)(2,5,8,11)(3,6,9,12), (1,7)(3,9)(5,11) ], +> [ (3,12)(6,9), (3,9)(6,12), (1,10,7)(3,6,9), (2,11)(3,6)(7,10), +> (1,5,9)(2,6,10)(3,7,11)(4,8,12), (1,5)(2,10)(4,8)(7,11) ], +> [ (2,4,6,8,12), (2,8)(10,12), (1,12)(2,3)(4,5)(6,7)(8,9)(10,11) ], +> [ (1,12), (1,3,5,7,9)(2,4,6,8,12), (1,11)(2,4)(3,5)(6,8)(7,9)(10,12) ], +> [ (4,8,12), (4,8)(7,11), (2,8,11)(3,6,12)(4,7,10), (1,7,10)(2,5,11)(3,6,9) ] +> , [ (1,7,3,10,5,9,6,12)(2,11,8,4), (1,6,3,9)(2,7,12,10,4,5,11,8) ], +> [ (3,6,12), (3,6,9), (3,12)(4,7)(8,11), (1,5,9)(2,6,10)(3,7,11)(4,8,12) ], +> [ (4,8,12), (4,8), (1,4,7,10)(2,5,8,11)(3,6,9,12), (1,7)(3,9)(5,11) ], +> [ (3,6,12), (3,6,9), (1,5,9)(2,6,10)(3,7,11)(4,8,12), +> (1,5)(2,10)(4,8)(7,11) ], +> [ (3,6,12), (3,6,9), (1,5,9)(2,6,10)(3,7,11)(4,8,12), +> (1,5)(2,10)(3,12)(4,11)(7,8) ], +> [ (1,12)(2,3), (1,3,5)(2,4,12), (2,4,6,8,10)(3,5,7,9,11) ], +> [ (2,4,6,8,12), (1,11)(2,4)(3,5)(6,8)(7,9)(10,12), +> (1,12,11,10)(2,5,4,3)(6,9,8,7) ], +> [ (2,4,6,8,12), (1,11)(2,4)(3,5)(6,8)(7,9)(10,12), +> (1,12)(2,3)(4,5)(6,7)(8,9)(10,11) ], +> [ (4,8,12), (4,8), (2,8,11)(3,6,12)(4,7,10), (1,7,10)(2,5,11)(3,6,9) ], +> [ (4,8,12), (4,8)(7,11), (1,4,7,10)(2,5,8,11)(3,6,9,12), (2,11)(3,6)(7,10) ], +> [ (4,8,12), (2,10)(4,8), (2,8,11)(3,6,12)(4,7,10), (1,7,10)(2,5,11)(3,6,9), +> (1,7,5,11)(2,10)(3,9)(4,8) ], +> [ (3,6,12), (3,6,9), (3,12)(4,7)(8,11), (1,5,9)(2,6,10)(3,7,11)(4,8,12), +> (1,5)(2,10)(4,8)(7,11) ], +> [ (3,6,12), (3,6,9), (3,12)(4,7), (1,5,9)(2,6,10)(3,7,11)(4,8,12) ], +> [ (1,12)(2,3), (1,3)(2,12), (1,3,5,7,9,11)(2,4,6,8,10,12) ], +> [ (1,12), (1,3,5)(2,4,12), (2,4,6,8,10)(3,5,7,9,11) ], +> [ (1,12)(2,3), (1,3,5)(2,4,12), (2,4,6,8,10)(3,5,7,9,11), (1,2,12,3) ], +> [ (2,4,6,8,12), (2,4)(6,8)(10,12), (1,12)(2,3)(4,5)(6,7)(8,9)(10,11) ], +> [ (4,8,12), (4,8), (1,4,7,10)(2,5,8,11)(3,6,9,12), (1,10)(2,5)(6,9) ], +> [ (3,6,12), (3,6,9), (3,12)(4,7), (1,5,9)(2,6,10)(3,7,11)(4,8,12), +> (1,5)(2,10)(4,8)(7,11) ], +> [ (3,6,12), (3,6,9), (1,10)(6,9), (1,5,9)(2,6,10)(3,7,11)(4,8,12), +> (1,2)(4,8)(5,10)(6,9)(7,11) ], +> [ (3,6,9,12), (6,9), (1,5,9)(2,6,10)(3,7,11)(4,8,12) ], +> [ (1,12), (1,3)(2,12), (1,3,5,7,9,11)(2,4,6,8,10,12) ], +> [ (3,6,9,12), (6,9), (1,5,9)(2,6,10)(3,7,11)(4,8,12), +> (1,5)(2,10)(4,8)(7,11) ], +> [ (1,11,2,3,4)(5,8,12,6,7), (1,9,5,12,11,8,2,4)(6,10) ], +> [ (2,4,12), (2,4,6,8,10), (1,12)(2,3)(4,5)(6,7)(8,9)(10,11) ], +> [ (2,4,6,8,10), (2,4,12), (1,3)(2,12), (1,12)(2,3)(4,5)(6,7)(8,9)(10,11) ], +> [ (2,4,12), (2,4,6,8,10), (1,3)(2,12), (1,12,3,2)(4,5)(6,7)(8,9)(10,11) ], +> [ (2,12), (2,4,6,8,10,12), (1,12)(2,3)(4,5)(6,7)(8,9)(10,11) ], +> [ (1,2,3,4,5,6,7,8,9,10,11), (10,11,12) ], +> [ (1,2,3,4,5,6,7,8,9,10,11,12), (1,2) ] ];; +gap> Apply(groups, Group);; +gap> Filtered(groups, x -> Length(MinimalGeneratingSet(x)) = 4) = +> [ Group( [ (7,11)(8,12), (6,10)(8,12), (1,6)(2,9)(3,12)(4,7)(5,10)(8,11), +> (1,7)(2,4)(3,9)(5,11)(6,8)(10,12) ] ) ]; +true + +# +gap> STOP_TEST("minimalgeneratingset.tst"); diff --git a/tst/teststandard/permgrp.tst b/tst/teststandard/permgrp.tst index c940f52f28..989993c2b1 100644 --- a/tst/teststandard/permgrp.tst +++ b/tst/teststandard/permgrp.tst @@ -106,7 +106,10 @@ gap> IsNonabelianSimpleGroup(g); true # small double coset -gap> g:=TransitiveGroup(12,291);; +gap> g := Group([ (3,6,12), (3,6,9), (1,10)(6,9), +> (1,5,9)(2,6,10)(3,7,11)(4,8,12), +> (1,2)(4,8)(5,10)(6,9)(7,11) ]);; +gap> # g = TransitiveGroup(12,291) gap> s:=SylowSubgroup(g,3);; gap> Length(DoubleCosets(g,s,s)); 24 @@ -140,11 +143,6 @@ true gap> Length(ConjugacyClasses(PSL(2,64))); 65 -# 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 From f7c73d8a4112c85d7e9e48eb07ef4438574a1f3f Mon Sep 17 00:00:00 2001 From: Max Horn Date: Mon, 6 Oct 2025 13:38:37 +0200 Subject: [PATCH 036/234] Another fix for rational matrix groups (#6140) --- lib/grpramat.gi | 2 +- .../2025-10-02-char0-matrixgroups.tst | 22 ++++++++++++++++--- 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/lib/grpramat.gi b/lib/grpramat.gi index 4b47d9c2fd..38608fe991 100644 --- a/lib/grpramat.gi +++ b/lib/grpramat.gi @@ -323,7 +323,7 @@ function( G ) nice := GroupHomomorphismByFunction(G, H, function(x) if ValueOption("actioncanfail")=true then - if not ForAll( x, r -> ForAll( r, IsRat ) ) then + if not ForAll( x, r -> ForAll( r, v -> IsRat(v) and DenominatorRat( v ) mod p <> 0 ) ) then return fail; fi; fi; diff --git a/tst/testbugfix/2025-10-02-char0-matrixgroups.tst b/tst/testbugfix/2025-10-02-char0-matrixgroups.tst index 5c8f995c15..8ad9dc8f8b 100644 --- a/tst/testbugfix/2025-10-02-char0-matrixgroups.tst +++ b/tst/testbugfix/2025-10-02-char0-matrixgroups.tst @@ -1,6 +1,6 @@ -# \in incorrectly returned 'false' for finite rational matrix groups -# if the matrix being tested was not integral. -# See +# \in incorrectly returned 'false' for finite rational matrix groups if the +# matrix being tested was not integral. +# See . # gap> G:=Group([ 1/2 * [[-1+1*E(4), -1+1*E(4)], [1+1*E(4), -1-1*E(4)]], E(4) * [[0,1],[-1,0]] ]);; gap> g:=List(G)[9];; @@ -13,3 +13,19 @@ gap> H:=Group( 1/2*[[-1,1,-1,1],[-1,-1,-1,-1],[1,1,-1,-1],[-1,1,1,-1]], gap> h := 1/2*[[-1,-1,1,-1],[1,-1,1,1],[-1,-1,-1,1],[1,-1,-1,-1]];; gap> h in H; true + +# +# Moreover, if given a matrix outside the original group, it may happen that +# the chosen prime p used for reduction to a prime field divides the +# denominator of one of the matrix entries, in which case mapping the matrix +# to GF(p) does not work; we need to catch that. +# See . +# +gap> G := Group([[[0, 1, 0, 0], [1, 0, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]], +> [[1, 0, 0, 0], [0, 0, 1, 0], [0, -1, 0, 0], [0, 0, 0, 1]], +> [[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 0, 1], [0, 0, 1, 0]]]); + +gap> Centralizer(G,[[0, 0, 0, 0], [0, 1/3, 1/3, 1/3], [0, 1/3, 1/3, 1/3], [0, 1/3, 1/3, 1/3]]); + +gap> Size(last); +24 From 9e098b088d872a8d8a4cc0c57276fab1b7e85726 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lars=20G=C3=B6ttgens?= Date: Mon, 6 Oct 2025 22:10:59 +0200 Subject: [PATCH 037/234] Update group library docs to be more independent of package changes (#6125) --- doc/ref/grplib.xml | 29 ++++++++++++++++------------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/doc/ref/grplib.xml b/doc/ref/grplib.xml index cc8061fe59..d2d3a1bd5f 100644 --- a/doc/ref/grplib.xml +++ b/doc/ref/grplib.xml @@ -21,30 +21,32 @@ initially knows the following groups: groups (see ), - Classical matrix groups (see ), + classical matrix groups (see ), - the transitive permutation groups of degree at most 30, + a library of transitive permutation groups, provided by the TransGrp package (see ), - a library of groups of small order (see ), + a library of groups of small order, + provided by the SmallGrp package + (see ), - the finite perfect groups of size at most 2\cdot 10^6 - (see ). + a libary of finite perfect groups, + (see ), - the primitive permutation groups of degree - < 4096, provided by the PrimGrp package + a library of primitive permutations groups, + provided by the PrimGrp package (see ), - the irreducible solvable subgroups of GL(n,p) for - n>1 and p^n < 256, provided by the - PrimGrp package - (see ), + the irreducible solvable subgroups of GL(n,q) for + n>1, q a prime power and q^n < 2^{24}, + provided by the IRREDSOL package + (see ), the irreducible maximal finite integral matrix groups @@ -52,8 +54,9 @@ initially knows the following groups: (see ), - the crystallographic groups of dimension at most 4 - + the crystallographic groups of dimension at most 4, provided by the + CrystCat package + (see ).

From 7be3ddef0cf18c0e36da585cf468cabd61a81ee0 Mon Sep 17 00:00:00 2001 From: Thomas Breuer Date: Fri, 10 Oct 2025 14:59:56 +0200 Subject: [PATCH 038/234] combine `IrrDixonSchneider` with `IrrBaumClausen` (#6134) In the `Irr` method that calls `IrrDixonSchneider`: - If the group is solvable then first call `IrrBaumClausen`. - If that yields all irreducibles then store and return them. - Otherwise pass the partial list of irreducibles to the `IrrDixonSchneider` call. In `DixonInit`, support the component `knownirreducibles` of the optional record, and call `DxIncludeIrreducibles` for them if the ordering of conjugacy classes fits. --- lib/ctblfuns.gd | 28 +++++++------- lib/ctblgrp.gi | 38 +++++++++++++++---- lib/ctblmono.gd | 27 +++++++------ .../testLuxPahlings/example_4.10.8.tst | 11 +++--- .../testLuxPahlings/example_4.12.10.tst | 9 ++--- 5 files changed, 65 insertions(+), 48 deletions(-) diff --git a/lib/ctblfuns.gd b/lib/ctblfuns.gd index bb50f75b7a..2a23a96d7f 100644 --- a/lib/ctblfuns.gd +++ b/lib/ctblfuns.gd @@ -371,25 +371,23 @@ DeclareAttribute( "ValuesOfClassFunction", IsClassFunction ); ## CharacterTable( ) ## gap> t2:= CharacterTable( grps[2] ); SetName( t2, "t2" ); ## CharacterTable( ) -## gap> irr1:= Irr( grps[1] ); -## [ Character( t1, [ 1, 1, 1, 1, 1 ] ), -## Character( t1, [ 1, -1, -1, 1, 1 ] ), -## Character( t1, [ 1, -1, 1, 1, -1 ] ), -## Character( t1, [ 1, 1, -1, 1, -1 ] ), -## Character( t1, [ 2, 0, 0, -2, 0 ] ) ] -## gap> irr2:= Irr( grps[2] ); -## [ Character( t2, [ 1, 1, 1, 1, 1 ] ), -## Character( t2, [ 1, -1, -1, 1, 1 ] ), -## Character( t2, [ 1, -1, 1, 1, -1 ] ), -## Character( t2, [ 1, 1, -1, 1, -1 ] ), -## Character( t2, [ 2, 0, 0, -2, 0 ] ) ] +## gap> CharacterDegrees( t1 ); +## [ [ 1, 4 ], [ 2, 1 ] ] +## gap> irr1:= Irr( grps[1] );; +## gap> irr2:= Irr( grps[2] );; ## gap> irr1 = irr2; ## true +## gap> irr1[1]; +## Character( t1, [ 1, 1, 1, 1, 1 ] ) +## gap> irr1[5]; +## Character( t1, [ 2, 0, 0, -2, 0 ] ) +## gap> irr2[1]; +## Character( t2, [ 1, 1, 1, 1, 1 ] ) ## gap> IsSSortedList( irr1 ); ## false -## gap> irr1[1] < irr1[2]; +## gap> irr1[1] < irr1[2]; # the triv. character has no '-1' ## false -## gap> irr1[2] < irr1[3]; +## gap> irr1[2] < irr1[5]; ## true ## ]]> ## <#/GAPDoc> @@ -1861,7 +1859,7 @@ DeclareOperation( "TensorProductOp", [ IsDenseList, IsClassFunction ] ); ## Then returns the class function of ## H obtained by restricting chi to H. ##

-## If chi is a class function of a factor group Gof +## If chi is a class function of a factor group G of ## H, where target is either the group H ## or a homomorphism from H to G ## or the character table of H diff --git a/lib/ctblgrp.gi b/lib/ctblgrp.gi index 20ca45dd0c..5d5c73dfa8 100644 --- a/lib/ctblgrp.gi +++ b/lib/ctblgrp.gi @@ -2030,12 +2030,9 @@ end ); #F DixonInit() . . . . . . . . . . initialize Dixon-Schneider algorithm ## ## -InstallGlobalFunction( DixonInit, function(arg) -local G, # group - D, # Dixon record,result - k,z,exp,prime,M,m,f,r,ga,i,fk; - - G:=arg[1]; +InstallGlobalFunction( DixonInit, function(G, opt...) +local D, # Dixon record,result + k,z,exp,prime,M,m,f,r,ga,i,fk, knownirr; # Force computation of the size of the group. Size(G); @@ -2107,6 +2104,17 @@ local G, # group D.projectionMat:=M; DxIncludeIrreducibles(D,DxLinearCharacters(D)); + if Length( opt ) = 1 and IsRecord( opt[1] ) and IsBound( opt[1].knownirreducibles ) then + # The ordering of classes for these characters refers to + # the 'ConjugacyClasses' value of their character table. + # We check whether these classes coincide with 'D.classes'. + knownirr:= opt[1].knownirreducibles; + if 0 < Length( knownirr ) and + IsIdenticalObj( D.classes, + ConjugacyClasses( UnderlyingCharacterTable( knownirr[1] ) ) ) then + DxIncludeIrreducibles( D, knownirr ); + fi; + fi; if Length(D.raeume)>0 then # indicate Stabilizer of the whole orbit,simultaneously compute @@ -2273,8 +2281,22 @@ InstallMethod( Irr, "Dixon/Schneider", [ IsGroup, IsZeroCyc ], function( G, zero ) - local irr, C; - irr:= IrrDixonSchneider( G ); + local opt, irr, C; + + # Perhaps a cheaper method for 'G' exists but is not applicable. + opt:= rec(); + if IsSolvableGroup( G ) then + irr:= IrrBaumClausen( G ); + if Length( irr ) = NrConjugacyClasses( G ) then + # The list is complete. + C:= OrdinaryCharacterTable( G ); + SetIrr( C, irr ); + return irr; + fi; + # We feed the partial list into the Dixon-Schneider-algorithm. + opt.knownirreducibles:= irr; + fi; + irr:= IrrDixonSchneider( G, opt ); C:= OrdinaryCharacterTable( G ); SetIrr( C, irr ); SetInfoText( C, "origin: Dixon's Algorithm" ); diff --git a/lib/ctblmono.gd b/lib/ctblmono.gd index d941850010..27ab893170 100644 --- a/lib/ctblmono.gd +++ b/lib/ctblmono.gd @@ -266,13 +266,13 @@ DeclareProperty( "IsBergerCondition", IsClassFunction ); ## gap> n:= DerivedSubgroup( Sl23 );; ## gap> chi:= Irr( Sl23 )[7]; ## Character( CharacterTable( SL(2,3) ), [ 3, 0, 0, 3, 0, 0, -1 ] ) -## gap> TestHomogeneous( chi, n ); -## rec( character := Character( CharacterTable( Group( -## [ [ [ 0*Z(3), Z(3) ], [ Z(3)^0, 0*Z(3) ] ], -## [ [ Z(3), 0*Z(3) ], [ 0*Z(3), Z(3) ] ], -## [ [ Z(3)^0, Z(3) ], [ Z(3), Z(3) ] ] ]) ), -## [ 1, -1, 1, -1, 1 ] ), comment := "restriction checked", -## isHomogeneous := false, multiplicity := 1 ) +## gap> test:= TestHomogeneous( chi, n );; +## gap> test.isHomogeneous; test.comment; test.multiplicity; +## false +## "restriction checked" +## 1 +## gap> Degree( test.character ); +## 1 ## gap> chi:= Irr( Sl23 )[4]; ## Character( CharacterTable( SL(2,3) ), [ 2, 1, 1, -2, -1, -1, 0 ] ) ## gap> cln:= ClassPositionsOfNormalSubgroup( CharacterTable( Sl23 ), n ); @@ -350,13 +350,12 @@ DeclareProperty( "IsPrimitiveCharacter", IsClassFunction ); ## rec( comment := "all restrictions checked", isQuasiPrimitive := true ) ## gap> chi:= Irr( Sl23 )[7]; ## Character( CharacterTable( SL(2,3) ), [ 3, 0, 0, 3, 0, 0, -1 ] ) -## gap> TestQuasiPrimitive( chi ); -## rec( character := Character( CharacterTable( Group( -## [ [ [ 0*Z(3), Z(3) ], [ Z(3)^0, 0*Z(3) ] ], -## [ [ Z(3), 0*Z(3) ], [ 0*Z(3), Z(3) ] ], -## [ [ Z(3)^0, Z(3) ], [ Z(3), Z(3) ] ] ]) ), -## [ 1, -1, 1, -1, 1 ] ), comment := "restriction checked", -## isQuasiPrimitive := false ) +## gap> test:= TestQuasiPrimitive( chi );; +## gap> test.isQuasiPrimitive; test.comment; +## false +## "restriction checked" +## gap> Degree( test.character ); +## 1 ## ]]> ## ## diff --git a/tst/teststandard/testLuxPahlings/example_4.10.8.tst b/tst/teststandard/testLuxPahlings/example_4.10.8.tst index 9dc009178b..5de6795e25 100644 --- a/tst/teststandard/testLuxPahlings/example_4.10.8.tst +++ b/tst/teststandard/testLuxPahlings/example_4.10.8.tst @@ -12,13 +12,14 @@ gap> ctn2 := CharacterTable( RepresentativeTom(t,26) ) ;; ###################################################################### gap> ctf:=CharacterTable(RepresentativeTom(t,26)/RepresentativeTom(t,3));; -gap> ctfprojectives := Irr(ctf)* DecompositionMatrix( ctf mod 3 ); +gap> ctfprojectives := Irr(ctf)* DecompositionMatrix( ctf mod 3 );; +gap> SortedList( ctfprojectives ); [ VirtualCharacter( CharacterTable( Group([ f1, f2, f3 ]) ), - [ 3, 1, 1, 0, 3, 0 ] ), VirtualCharacter( CharacterTable( Group( - [ f1, f2, f3 ]) ), [ 3, -1, -1, 0, 3, 0 ] ), + [ 3, -1, -1, 0, 3, 0 ] ), VirtualCharacter( CharacterTable( Group( + [ f1, f2, f3 ]) ), [ 3, -1, 1, 0, -3, 0 ] ), VirtualCharacter( CharacterTable( Group([ f1, f2, f3 ]) ), - [ 3, -1, 1, 0, -3, 0 ] ), VirtualCharacter( CharacterTable( Group( - [ f1, f2, f3 ]) ), [ 3, 1, -1, 0, -3, 0 ] ) ] + [ 3, 1, -1, 0, -3, 0 ] ), VirtualCharacter( CharacterTable( Group( + [ f1, f2, f3 ]) ), [ 3, 1, 1, 0, 3, 0 ] ) ] ###################################################################### gap> STOP_TEST( "example_4.10.8.tst" ); diff --git a/tst/teststandard/testLuxPahlings/example_4.12.10.tst b/tst/teststandard/testLuxPahlings/example_4.12.10.tst index 94515b824f..dd505cc965 100644 --- a/tst/teststandard/testLuxPahlings/example_4.12.10.tst +++ b/tst/teststandard/testLuxPahlings/example_4.12.10.tst @@ -106,12 +106,9 @@ gap> ind1 := InducedClassFunctionsByFusionMap(t11, ct, Irr(t11), pf[1]);; gap> ind2 := InducedClassFunctionsByFusionMap(t11, ct, Irr(t11), pf[2]);; gap> Set(ind1) = Set(ind2); true -gap> ind1:= Filtered(ind1, x -> x[1] = Size(ct)/Size(t11));; -gap> MatScalarProducts(Irr(ct){b19},ind1{[1..8]}); -[ [ 1, 1, 1, 2, 0, 0, 1, 1, 1 ], [ 0, 1, 1, 1, 1, 1, 1, 1, 1 ], - [ 0, 0, 1, 0, 1, 1, 1, 1, 1 ], [ 0, 1, 0, 0, 1, 1, 1, 1, 1 ], - [ 0, 1, 0, 0, 1, 1, 1, 1, 1 ], [ 0, 0, 1, 0, 1, 1, 1, 1, 1 ], - [ 0, 0, 1, 1, 1, 0, 1, 1, 1 ], [ 0, 1, 0, 1, 0, 1, 1, 1, 1 ] ] +gap> mat:= MatScalarProducts(Irr(ct){b19},ind1);; +gap> First( mat, row -> row[3] = 0 and row[4] = 1 ); +[ 0, 1, 0, 1, 0, 1, 1, 1, 1 ] ###################################################################### gap> STOP_TEST( "example_4.12.10.tst" ); From 7d2697c29ed7f955e36cc60bf95010719ab71306 Mon Sep 17 00:00:00 2001 From: Max Horn Date: Fri, 10 Oct 2025 17:13:55 +0200 Subject: [PATCH 039/234] Make various operations for rational matrix groups faster (fixes a performance regression from GAP 4.15.0) (#6138) This fixes a performance regression from GAP 4.15.0 and in some cases makes things actually faster than they were then. --- lib/ctblfuns.gd | 11 ++++------- lib/grpramat.gi | 16 +++++++++++----- 2 files changed, 15 insertions(+), 12 deletions(-) diff --git a/lib/ctblfuns.gd b/lib/ctblfuns.gd index 2a23a96d7f..b9e7b2584f 100644 --- a/lib/ctblfuns.gd +++ b/lib/ctblfuns.gd @@ -1343,10 +1343,8 @@ DeclareOperation( "Norm", [ IsOrdinaryTable, IsHomogeneousList ] ); ## by listing the positions of conjugacy classes in the centre.) ##

## List( Irr( S4 ), CentreOfCharacter ); -## [ Group([ (), (1,2), (1,2)(3,4), (1,2,3), (1,2,3,4) ]), Group(()), -## Group([ (1,2)(3,4), (1,3)(2,4) ]), Group(()), -## Group([ (), (1,2), (1,2)(3,4), (1,2,3), (1,2,3,4) ]) ] +## gap> List( Irr( S4 ), chi -> StructureDescription(CentreOfCharacter(chi)) ); +## [ "S4", "1", "C2 x C2", "1", "S4" ] ## ]]> ## ## @@ -1504,9 +1502,8 @@ DeclareOperation( "InertiaSubgroup", ## affords chi. ##

## List( Irr( S4 ), KernelOfCharacter ); -## [ Alt( [ 1 .. 4 ] ), Group(()), Group([ (1,2)(3,4), (1,3)(2,4) ]), -## Group(()), Group([ (), (1,2), (1,2)(3,4), (1,2,3), (1,2,3,4) ]) ] +## gap> List( Irr( S4 ), chi -> StructureDescription(KernelOfCharacter(chi)) ); +## [ "A4", "1", "C2 x C2", "1", "S4" ] ## ]]> ## ## diff --git a/lib/grpramat.gi b/lib/grpramat.gi index 38608fe991..06cea0feff 100644 --- a/lib/grpramat.gi +++ b/lib/grpramat.gi @@ -266,7 +266,7 @@ InstallMethod( IsFinite, [ IsCyclotomicMatrixGroup ], function( G ) # The code below is based on the algorithm described in [DFO13] - local badPrimes, n, g, FindPrimesInMatDenominators, p, e, H, phi, gens, rels, nice; + local badPrimes, n, g, FindPrimesInMatDenominators, p, e, H, phi, gens, rels, nice, inv, Hnice; # if not rational, use the nice monomorphism into a rational matrix group if not IsRationalMatrixGroup( G ) then @@ -309,8 +309,11 @@ function( G ) return false; fi; + Hnice := NiceMonomorphism(H); + H := NiceObject(H); + # evaluate relators - phi := IsomorphismFpGroupByGenerators(H, GeneratorsOfGroup( H )); + phi := IsomorphismFpGroupByGeneratorsNC(H, GeneratorsOfGroup( H ) : method := "fast"); gens := GeneratorsOfGroup(FreeGroupOfFpGroup(Range(phi))); rels := RelatorsOfFpGroup(Range(phi)); @@ -318,8 +321,11 @@ function( G ) return false; fi; + # bypass the finite field matrix group in the middle so that we can + # compute preimages more easily + inv := GroupHomomorphismByImagesNC(H, G : noassert); + # set as a nice monomorphism - gens := GeneratorsOfGroup(Range(phi)); nice := GroupHomomorphismByFunction(G, H, function(x) if ValueOption("actioncanfail")=true then @@ -327,10 +333,10 @@ function( G ) return fail; fi; fi; - return x * e; + return Hnice(x * e); end, function(y) - return MappedWord(phi(y), gens, GeneratorsOfGroup(G)); + return inv(y); end ); SetNiceMonomorphism(G, nice); From 15d87e1945570c0cfaf7283e8471061025a812ed Mon Sep 17 00:00:00 2001 From: Thomas Breuer Date: Mon, 13 Oct 2025 01:30:47 +0200 Subject: [PATCH 040/234] Compute power maps when irreducibles were computed without them (#6141) - add a helper function `ComputeAllPowerMaps`, - compute all power maps in `InducedCyclic` if they are not yet available, - compute all power maps in the `Irr` methods based on `IrrBaumClausen` Since #6134, more character tables use `IrrBaumClausen`, and the power maps are not automatically computed fr such tables. Thus we call `ComputeAllPowerMaps` in this situation, because computing individual power map values later on is more expensive. (The way *how* `ComputeAllPowerMaps` proceeds is just a temporary hack.) --- lib/ctblfuns.gi | 5 +++++ lib/ctblgrp.gd | 2 ++ lib/ctblgrp.gi | 28 +++++++++++++++++++++++++--- lib/ctblsolv.gi | 12 ++++++++---- tst/testinstall/ctbl.tst | 1 + 5 files changed, 41 insertions(+), 7 deletions(-) diff --git a/lib/ctblfuns.gi b/lib/ctblfuns.gi index 4957052a66..eec04e92e4 100644 --- a/lib/ctblfuns.gi +++ b/lib/ctblfuns.gi @@ -3133,6 +3133,11 @@ InstallMethod( InducedCyclic, j, single; + if HasUnderlyingGroup( tbl ) then + # Precompute the power maps if possible. + ComputeAllPowerMaps( tbl ); + fi; + centralizers:= SizesCentralizers( tbl ); orders:= OrdersClassRepresentatives( tbl ); independent:= List( orders, ReturnTrue ); diff --git a/lib/ctblgrp.gd b/lib/ctblgrp.gd index c57c226fb4..e8a33e4670 100644 --- a/lib/ctblgrp.gd +++ b/lib/ctblgrp.gd @@ -470,3 +470,5 @@ DeclareGlobalFunction("RepresentationsPermutationIrreducibleCharacters"); ## <#/GAPDoc> ## DeclareGlobalFunction("NthRootsInGroup"); + +DeclareGlobalName( "ComputeAllPowerMaps" ); diff --git a/lib/ctblgrp.gi b/lib/ctblgrp.gi index 5d5c73dfa8..cb6c5edda0 100644 --- a/lib/ctblgrp.gi +++ b/lib/ctblgrp.gi @@ -139,9 +139,10 @@ local p,primes,i,cl,spr,j,allpowermaps,pm,ex; od; for p in primes do - allpowermaps[p]:=List(D.classrange,i->ShallowCopy(D.classrange)); - allpowermaps[p][1]:=1; - #allpowermaps[p]:=InitPowerMap(D.characterTable,p); + if not IsBound( allpowermaps[p] ) then + allpowermaps[p]:=List(D.classrange,i->ShallowCopy(D.classrange)); + allpowermaps[p][1]:=1; + fi; od; for p in primes do @@ -200,6 +201,27 @@ fi; od; end ); + +############################################################################# +## +#F ComputeAllPowerMaps( ) +## +## Computing all power maps is cheaper than successively computing some +## values of individual power maps. +## The current code is a hack. +## (Apparently 'DxCalcAllPowerMaps' is much faster than other available +## functions.) +## It should be improved as soon as we have a general tool for the +## identification of conjugacy classes. +## +BindGlobal( "ComputeAllPowerMaps", function( tbl ) + tbl:= UnderlyingGroup( tbl ); + if not HasDixonRecord( tbl ) then + DxCalcAllPowerMaps( DixonRecord( tbl ) ); + fi; +end ); + + ############################################################################# ## #F DxCalcPrimeClasses() diff --git a/lib/ctblsolv.gi b/lib/ctblsolv.gi index 14152613f6..d5f909829f 100644 --- a/lib/ctblsolv.gi +++ b/lib/ctblsolv.gi @@ -848,9 +848,11 @@ InstallMethod( Irr, "for a supersolvable group (Baum-Clausen algorithm)", [ IsGroup and IsSupersolvableGroup, IsZeroCyc ], function( G, zero ) - local irr; + local irr, tbl; irr:= IrrBaumClausen( G ); - SetIrr( OrdinaryCharacterTable( G ), irr ); + tbl:= OrdinaryCharacterTable( G ); + SetIrr( tbl, irr ); + ComputeAllPowerMaps( tbl ); return irr; end ); @@ -858,9 +860,11 @@ InstallMethod( Irr, "for a supersolvable group with known `IrrBaumClausen'", [ IsGroup and IsSupersolvableGroup and HasIrrBaumClausen, IsZeroCyc ], function( G, zero ) - local irr; + local irr, tbl; irr:= IrrBaumClausen( G ); - SetIrr( OrdinaryCharacterTable( G ), irr ); + tbl:= OrdinaryCharacterTable( G ); + SetIrr( tbl, irr ); + ComputeAllPowerMaps( tbl ); return irr; end ); diff --git a/tst/testinstall/ctbl.tst b/tst/testinstall/ctbl.tst index 96d4786e25..072ab96268 100644 --- a/tst/testinstall/ctbl.tst +++ b/tst/testinstall/ctbl.tst @@ -313,6 +313,7 @@ C2 2 1 1 1a 2a + 2P 1a 1a 2 X.1 ? 1 1 X.2 ? 1 -1 From 1156bb6d563f7d7840ac9f9c31991e825786feb7 Mon Sep 17 00:00:00 2001 From: Thomas Breuer Date: Thu, 16 Oct 2025 01:58:58 +0200 Subject: [PATCH 041/234] add a missing `ComputeAllPowerMaps` call (#6145) --- lib/ctblgrp.gi | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/ctblgrp.gi b/lib/ctblgrp.gi index cb6c5edda0..36fb803c3b 100644 --- a/lib/ctblgrp.gi +++ b/lib/ctblgrp.gi @@ -2313,6 +2313,7 @@ InstallMethod( Irr, # The list is complete. C:= OrdinaryCharacterTable( G ); SetIrr( C, irr ); + ComputeAllPowerMaps( C ); return irr; fi; # We feed the partial list into the Dixon-Schneider-algorithm. From 410368d355f6ec6ab386abd368f2718c4f70ac28 Mon Sep 17 00:00:00 2001 From: Max Horn Date: Thu, 16 Oct 2025 16:09:05 +0200 Subject: [PATCH 042/234] Fix yet another issue in the char 0 matrix code (#6144) --- lib/grpramat.gi | 2 +- tst/testbugfix/2025-10-02-char0-matrixgroups.tst | 12 ++++++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/lib/grpramat.gi b/lib/grpramat.gi index 06cea0feff..98ad46a51a 100644 --- a/lib/grpramat.gi +++ b/lib/grpramat.gi @@ -333,7 +333,7 @@ function( G ) return fail; fi; fi; - return Hnice(x * e); + return ImageElm(Hnice, x * e); end, function(y) return inv(y); diff --git a/tst/testbugfix/2025-10-02-char0-matrixgroups.tst b/tst/testbugfix/2025-10-02-char0-matrixgroups.tst index 8ad9dc8f8b..849853c43a 100644 --- a/tst/testbugfix/2025-10-02-char0-matrixgroups.tst +++ b/tst/testbugfix/2025-10-02-char0-matrixgroups.tst @@ -29,3 +29,15 @@ gap> Centralizer(G,[[0, 0, 0, 0], [0, 1/3, 1/3, 1/3], [0, 1/3, 1/3, 1/3], [0, 1/ gap> Size(last); 24 + +# +# Another problem related to this: Using `Image` to apply an intermediate nice +# monomorphism for a FFE matrix group would raise an error if testing inputs +# outside its domain; changing this to use ImageElm instead produces `fail`, +# which is what we need for e.g. membership tests. +# See +# +gap> G:=Group([ [ [ 1, 0, 0, 0 ], [ 0, 0, 1, 0 ], [ 0, 0, 0, 1 ], [ 0, 1, 0, 0 ] ], [ [ 0, 1/2*E(5)+1/2*E(5)^4, 1/2, 1/2*E(5)^2+1/2*E(5)^3 ], [ 1/2*E(5)+1/2*E(5)^4, -1/2*E(5)^2-1/2*E(5)^3, -1/2, 0 ], [ 1/2, -1/2, -1/2, -1/2 ], [ 1/2*E(5)^2+1/2*E(5)^3, 0, -1/2, -1/2*E(5)-1/2*E(5)^4 ] ] ]);; +gap> g:=[ [ 1, 0, 0, 0 ], [ 0, -1/2, 1/2*E(5)^2+1/2*E(5)^3, -1/2*E(5)-1/2*E(5)^4 ], [ 0, 1/2*E(5)^2+1/2*E(5)^3, 1/2*E(5)+1/2*E(5)^4, 1/2 ], [ 0, -1/2*E(5)-1/2*E(5)^4, 1/2, 1/2*E(5)^2+1/2*E(5)^3 ] ];; +gap> g in G; +false From dac8111771e5774b0f11c4cfab568dce916f01b1 Mon Sep 17 00:00:00 2001 From: Max Horn Date: Fri, 17 Oct 2025 13:16:56 +0200 Subject: [PATCH 043/234] Fix `CompatiblePairs` to not ignore the optional automorphism group argument (#6146) --- lib/grppcext.gi | 29 +++++++++---------- tst/testbugfix/2025-10-15-CompatiblePairs.tst | 11 +++++++ 2 files changed, 25 insertions(+), 15 deletions(-) create mode 100644 tst/testbugfix/2025-10-15-CompatiblePairs.tst diff --git a/lib/grppcext.gi b/lib/grppcext.gi index 8e30dfc20d..c1e9fd20f7 100644 --- a/lib/grppcext.gi +++ b/lib/grppcext.gi @@ -497,32 +497,29 @@ 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,neu,K1nontriv,epi,hf,pool,modulehom,test, - larg; + baspt,newimgs,i,j,basicact,neu,K1nontriv,epi,hf,pool,modulehom,test; # catch arguments - A:=fail; - larg:=ShallowCopy(arg); - if Length(larg)>2 and IsGroupOfAutomorphismsFiniteGroup(arg[1]) and + if Length(arg)>2 and IsGroupOfAutomorphismsFiniteGroup(arg[1]) and Source(One(arg[1]))=arg[2] then #automorphism group given - A:=larg[1]; - larg:=larg{[2..Length(larg)]}; + A:=Remove(arg, 1); else A:=fail; fi; - G := larg[1]; - M := larg[2]; + G := arg[1]; + M := arg[2]; Mgrp := GroupByGenerators( M.generators ); Ggens:=Pcgs(G); oper:=fail; if IsPcgs(Ggens) and Length(Ggens)=Length(M.generators) then oper := GroupHomomorphismByImagesNC( G, Mgrp, Ggens, M.generators ); - elif Length(larg)=2 then + elif Length(arg)=2 then # search through automorphism group for projection image and reps, # then add module automorphisms gens:=GeneratorsOfGroup(G); if A=fail then + Info( InfoCompPairs, 1, " CompP: compute aut group"); A:=AutomorphismGroup(G); fi; triso:=IsomorphismPermGroup(A); @@ -576,13 +573,15 @@ local G, M, Mgrp, oper, A, B, D, translate, gens, genimgs, triso, K, K1, fi; # automorphism groups of G and M - if Length( larg ) = 2 then - Info( InfoCompPairs, 1, " CompP: compute aut group"); - A := AutomorphismGroup( G ); + if Length( arg ) = 2 then + if A=fail then + Info( InfoCompPairs, 1, " CompP: compute aut group"); + A:=AutomorphismGroup(G); + fi; B := GL( M.dimension, Characteristic( M.field ) ); D := DirectProduct( A, B ); else - D := larg[3]; + D := arg[3]; A := DirectProductInfo(D).groups[1]; fi; @@ -608,7 +607,7 @@ local G, M, Mgrp, oper, A, B, D, translate, gens, genimgs, triso, K, K1, Dos:=Size(D); # compute stabilizer of K in A - if Length( larg ) <= 3 or not larg[4] then + if Length( arg ) <= 3 or not arg[4] then # get kernel of oper K := KernelOfMultiplicativeGeneralMapping( oper ); diff --git a/tst/testbugfix/2025-10-15-CompatiblePairs.tst b/tst/testbugfix/2025-10-15-CompatiblePairs.tst new file mode 100644 index 0000000000..4457b884fb --- /dev/null +++ b/tst/testbugfix/2025-10-15-CompatiblePairs.tst @@ -0,0 +1,11 @@ +# CompatiblePairs used to ignore the first optional argument in certain cases. +# In the example below, the last command used to produce the output +# [ 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96 ] +# +# Reported by Heiko Dietrich, together with a helpful analysis of the problem +# that made a fix quite easy. +gap> G:=AbelianGroup([3,3]);; +gap> M:=GModuleByMats([One(GL(1,3)),One(GL(1,3))],GF(3));; +gap> aut:=List(ConjugacyClassesSubgroups(AutomorphismGroup(G)),Representative);; +gap> SortedList(List(aut,A->Size(CompatiblePairs(A,G,M)))); +[ 2, 4, 4, 6, 8, 8, 12, 12, 12, 16, 16, 16, 24, 32, 48, 96 ] From 625a444af45970399856db364a218bba8e2098ea Mon Sep 17 00:00:00 2001 From: Max Horn Date: Sat, 18 Oct 2025 11:54:05 +0200 Subject: [PATCH 044/234] CHANGES.md: sync with stable-4.15 --- CHANGES.md | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/CHANGES.md b/CHANGES.md index 8ca392443e..6f4c6c84a9 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,5 +1,45 @@ # GAP - history of changes +## GAP 4.15.1 (October 2025) + +The following gives an overview of the changes compared to the previous +release. This list is not complete, many more internal or minor changes +were made, but we tried to only list those changes which we think might +affect some users directly. + +### Performance improvements + +- [#6138](https://github.com/gap-system/gap/pull/6138) Make various operations for finite matrix groups in characteristic 0 faster (fixes a performance regression from GAP 4.15.0) + +### Improved and extended functionality + +- [#6134](https://github.com/gap-system/gap/pull/6134) Make `Irr` for solvable groups faster by using the result of `IrrBaumClausen` in `IrrDixonSchneider`. (This may cause a changed ordering of the `Irr` result).) + +### Fixed bugs that could lead to incorrect results + +- [#6146](https://github.com/gap-system/gap/pull/6146) Fix `CompatiblePairs` to not ignore the optional automorphism group argument +- [#6137](https://github.com/gap-system/gap/pull/6137) Fix `in` and other functionality for finite matrix groups in characteristic 0 (they had regressed in GAP 4.15.0) + +### Fixed bugs that could lead to unexpected errors + +- [#6140](https://github.com/gap-system/gap/pull/6140) Fix an unexpected error that could occur when working with matrix groups in characteristic zero + +### Package distribution + +#### Updated packages redistributed with GAP + +The GAP 4.15.1 distribution contains 166 packages, of which 7 have been +updated since GAP 4.15.0. The full list of updated packages is given below: + +- [**AutoDoc**](https://gap-packages.github.io/AutoDoc): 2025.05.09 -> 2025.10.16 +- [**cohomolo**](https://gap-packages.github.io/cohomolo): 1.6.11 -> 1.6.12 +- [**datastructures**](https://gap-packages.github.io/datastructures): 0.3.3 -> 0.4.0 +- [**idrel**](https://gap-packages.github.io/idrel/): 2.48 -> 2.49 +- [**InduceReduce**](https://gap-packages.github.io/InduceReduce/): 1.1 -> 1.3 +- [**SmallClassNr**](https://stertooy.github.io/SmallClassNr): 1.4.1 -> 1.4.2 +- [**TwistedConjugacy**](https://stertooy.github.io/TwistedConjugacy): 3.1.0 -> 3.1.1 + + ## GAP 4.15.0 (September 2025) The following gives an overview of the changes compared to the previous From 1ad7c81fb89e44f02ea7a768d44aa363e54c77de Mon Sep 17 00:00:00 2001 From: Max Horn Date: Mon, 20 Oct 2025 14:57:04 +0200 Subject: [PATCH 045/234] Tweak release tooling and guidelines (#6147) --- dev/releases/README.md | 19 ++++--------------- dev/releases/download_manuals.sh | 23 +++++++++++++++++++++++ dev/releases/download_release.sh | 2 +- 3 files changed, 28 insertions(+), 16 deletions(-) create mode 100755 dev/releases/download_manuals.sh diff --git a/dev/releases/README.md b/dev/releases/README.md index e1ec53fa69..8645953c3a 100644 --- a/dev/releases/README.md +++ b/dev/releases/README.md @@ -96,27 +96,16 @@ Before starting the release process, the scripts have the following dependencies ``` ssh gap-docs # assumes gap-docs is set up in ~/.ssh/config -VER=X.Y.Z # to avoid typing -cd ~/data # follow symlink to target directory -rm -rf package-infos.json* gap-* # delete leftovers from previous release -wget https://github.com/gap-system/gap/releases/download/v${VER}/package-infos.json.gz -gunzip package-infos.json.gz -wget https://github.com/gap-system/gap/releases/download/v${VER}/gap-${VER}.tar.gz -tar xf gap-${VER}.tar.gz -cd GapWWW -git pull -cd .. -GapWWW/etc/extract_manuals.py gap-${VER} package-infos.json -mv Manuals http/v${VER} -rm http/latest -ln -s v${VER} http/latest +# then on the docs host +./download_manuals.sh X.Y.Z # e.g. 4.14.0 ``` 11. Check that is functioning as expected. 12. Log into `files.gap-system.org` via SSH, then download the files in appropriate places: ``` # assumes gap-files is set up in ~/.ssh/config -scp dev/releases/download_release.sh gap-files: ssh gap-files + +# then on the files host ./download_release.sh X.Y.Z # e.g. 4.14.0 ``` diff --git a/dev/releases/download_manuals.sh b/dev/releases/download_manuals.sh new file mode 100755 index 0000000000..39e2e4e857 --- /dev/null +++ b/dev/releases/download_manuals.sh @@ -0,0 +1,23 @@ +#!/bin/sh +set -ex + +# invoke this like so: +# ./download_manuals.sh 4.14.0 + +VER=$1 +[ x"$VER" != x ] || exit 1 +echo "Downloading manuals for release $VER" + +cd ~/data # follow symlink to target directory +rm -rf package-infos.json* gap-* # delete leftovers from previous release +wget https://github.com/gap-system/gap/releases/download/v${VER}/package-infos.json.gz +gunzip package-infos.json.gz +wget https://github.com/gap-system/gap/releases/download/v${VER}/gap-${VER}.tar.gz +tar xf gap-${VER}.tar.gz +cd GapWWW +git pull +cd .. +GapWWW/etc/extract_manuals.py gap-${VER} package-infos.json +mv Manuals http/v${VER} +rm http/latest +ln -s v${VER} http/latest diff --git a/dev/releases/download_release.sh b/dev/releases/download_release.sh index 599e38b922..7831bfb708 100755 --- a/dev/releases/download_release.sh +++ b/dev/releases/download_release.sh @@ -2,7 +2,7 @@ set -ex # invoke this like so: -# ./download_release.sh 4.14.0 +# ./download_release.sh 4.14.0 VER=$1 [ x"$VER" != x ] || exit 1 From 86791955e2b5e88e8b3b10fcb43de84cdc95bf4b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 27 Oct 2025 15:51:44 +0100 Subject: [PATCH 046/234] build(deps): bump actions/download-artifact from 5 to 6 (#6154) Bumps [actions/download-artifact](https://github.com/actions/download-artifact) from 5 to 6. - [Release notes](https://github.com/actions/download-artifact/releases) - [Commits](https://github.com/actions/download-artifact/compare/v5...v6) --- updated-dependencies: - dependency-name: actions/download-artifact dependency-version: '6' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 3ddbd4bf8a..38d0059ecd 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -196,7 +196,7 @@ jobs: # Download the artifact -- for an actual release, this contains the # exact same tarball as was uploaded to the release as an asset - name: "Download GAP archive from previous job" - uses: actions/download-artifact@v5 + uses: actions/download-artifact@v6 with: name: gap From 11950bf3c1998907e4fba79aab080227e8bc2094 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 27 Oct 2025 15:52:00 +0100 Subject: [PATCH 047/234] build(deps): bump actions/upload-artifact from 4 to 5 (#6155) Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 4 to 5. - [Release notes](https://github.com/actions/upload-artifact/releases) - [Commits](https://github.com/actions/upload-artifact/compare/v4...v5) --- updated-dependencies: - dependency-name: actions/upload-artifact dependency-version: '5' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/CI.yml | 4 ++-- .github/workflows/release.yml | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index 65666dbb1f..445a8fffa2 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -254,7 +254,7 @@ jobs: run: ${{ matrix.extra }} dev/ci.sh ${{ matrix.test-suites }} - name: "Upload pdf manuals" if: ${{ contains(matrix.test-suites, 'makemanuals') }} - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v5 with: if-no-files-found: error name: manuals-pdf @@ -265,7 +265,7 @@ jobs: doc/tut/manual.pdf - name: "Upload html manuals" if: ${{ contains(matrix.test-suites, 'makemanuals') }} - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v5 with: if-no-files-found: error name: manuals-html diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 38d0059ecd..5c0a61a90b 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -152,7 +152,7 @@ jobs: # # Warning: the result is a single .zip file (so things are compressed twice). - name: "Upload GAP tarball" - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v5 with: if-no-files-found: error name: gap @@ -161,7 +161,7 @@ jobs: # Always upload metadata, and keep longer, since it is much smaller. - name: "Upload JSON metadata" - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v5 with: if-no-files-found: error name: "JSON metadata" @@ -239,7 +239,7 @@ jobs: # Artifacts live for 1 day, i.e. until the next cron job runs. - name: "Upload the installer as an artifact" if: ${{ github.event_name == 'schedule' }} - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v5 with: if-no-files-found: error name: gap-${{ env.GAP_VERSION }}-x86_64.exe From abec89ce7b0cfd5f5e424f2387755f9d5e9d579f Mon Sep 17 00:00:00 2001 From: Max Horn Date: Mon, 27 Oct 2025 15:56:50 +0100 Subject: [PATCH 048/234] Update many broken links, update outdated docs etc. (#6153) Also, - update list of contributors in COPYRIGHT file - update GPL 2.0 text to current version (with a URL instead of a postal address) - clarify copyright statement in the manual - remove invalid or misleading licensing conditions beyond GPL - add the names of Fedora packages needed by several of our packages (complementing the Debian and Homebrew names already listed) - replace outdated information about the GAP website in the dev manual - remove empty chapter about git in the dev manual --- .mailmap | 1 + CONTRIBUTING.md | 2 +- COPYRIGHT | 17 +- INSTALL.md | 25 ++- LICENSE | 9 +- README.md | 30 ++-- doc/dev/git.xml | 12 -- doc/dev/main.xml | 1 - doc/dev/testing.xml | 3 +- doc/dev/website.xml | 377 +----------------------------------------- doc/ref/copyright.xml | 57 ++----- doc/ref/gappkg.xml | 2 +- doc/ref/moreinfo.xml | 74 --------- doc/ref/overview.xml | 8 +- doc/ref/preface.xml | 28 +--- doc/tut/preface.xml | 11 -- lib/package.gi | 2 +- src/streams.c | 2 +- 18 files changed, 80 insertions(+), 581 deletions(-) delete mode 100644 doc/dev/git.xml delete mode 100644 doc/ref/moreinfo.xml diff --git a/.mailmap b/.mailmap index 404fe9a991..260174deb5 100644 --- a/.mailmap +++ b/.mailmap @@ -37,6 +37,7 @@ Max Neunhöffer Michael Young Paula Hähndel Russ Woodroofe <37375486+RussWoodroofe@users.noreply.github.com> +Sam Tertooy <5571903+stertooy@users.noreply.github.com> Sebastian Gutsche Sergio Siccha Sergio Siccha diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index f608a606fc..8254028c80 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -8,7 +8,7 @@ possible. ## Packages versus contributions to the "core" system One way of contributing to GAP is to write a -[GAP package](https://www.gap-system.org/Packages/packages.html) and send it +[GAP package](https://www.gap-system.org/packages/authors/) and send it to us to consider for redistribution with GAP. This is appropriate if your contribution adds a body of functionality for some area of mathematics (or some coherent batch of system functionality). A package is also appropriate diff --git a/COPYRIGHT b/COPYRIGHT index 93f449a8c3..6a58d3bd37 100644 --- a/COPYRIGHT +++ b/COPYRIGHT @@ -11,20 +11,21 @@ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License -along with GAP; if not, write to the Free Software Foundation, Inc., -51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +along with GAP; if not, see . -Copyright (C) 1988-2024 by its authors, which include: +Copyright (C) 1988-2025 by its authors, which include: * Ákos Seress * Alex Wegner * Alexander Hulpke * Alice Niemeyer +* Anakin Dey * Andreas Distler * Andrew Solomon * Anna Sucker * Ansgar Kaup +* Arhan Chaudhary * Arne Storjohann * Bernhard Reinke * Bettina Eick @@ -47,7 +48,7 @@ Copyright (C) 1988-2024 by its authors, which include: * Dmitrii Pasechnik * Dominik Bernhardt * Emma Ahrens -* Erik M. Bray +* E. Madison Bray * Erzsébet Horváth * Etaoin Shrdlu * Fabian Zickgraf @@ -69,9 +70,11 @@ Copyright (C) 1988-2024 by its authors, which include: * Isabel M. Araújo * Isuru Fernando * Jack Schmidt +* Jake Faulkner * James Mitchell * James Williams * Jan de Muijnck-Hughes +* Jan Engelhardt * Jendrik Brachter * Jens Brandt * Jens Hollmann @@ -80,11 +83,13 @@ Copyright (C) 1988-2024 by its authors, which include: * Jerry James * Jesse Lansdown * Joachim Neubüser +* Joe Edwards * Johannes Meier * John McDermott * Jürgen Mnich * Jürgen Müller * Juergen Wisliceny +* Lars Göttgens * Laurent Bartholdi * Lucas Jones * Lucas Wollenhaupt @@ -109,13 +114,16 @@ Copyright (C) 1988-2024 by its authors, which include: * Paula Hähndel * Ramón Esteban Romero * Reimer Behrends +* Reinis Cirpons * Rob Wainwright * Robert Arthur * Robert F. Morse * Russ Woodroofe * Ruth Hoffmann +* Sam Tertooy * Sandeep Murthy * Sarah Rees +* Scott Brenner * Scott Murray * Sebastian Gutsche * Sergio Siccha @@ -126,6 +134,7 @@ Copyright (C) 1988-2024 by its authors, which include: * Thomas Bischops * Thomas Breuer * Thomas Merkwitz +* Torben Wiedemann * Udo Polis * Ute Schiffer * VInay Wagh diff --git a/INSTALL.md b/INSTALL.md index 41791b4d82..8fdc9f5c12 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -22,13 +22,14 @@ for Windows. Alternative installation methods which aim to simplify the installation mostly by offering precompiled binaries are: +* Several Linux distributions such as Debian/Ubuntu or Fedora have + packaged GAP itself; see e.g. * GAP installer for Homebrew (package manager for macOS) * Docker image for GAP and most of the packages * the rsync-based binary distribution for Linux Note, however, that these are updated independently and may not yet provide -the latest GAP release. Further details are available on the GAP website -here: . +the latest GAP release. 1 Installation Overview @@ -49,9 +50,9 @@ section "Installing required dependencies" in the file `README.md`. To get maximum benefit from GAP and from various packages, we recommend to install a number of other free software libraries (and their associated development tools) although they are not required for basic operation. -See for more details. +See Section "Compilation" below for more details. -The installation consists of five easy steps: +The installation consists of five steps: 1. Get the archive suitable for your system 2. Unpack the archive in the directory where you wish to install GAP @@ -76,7 +77,7 @@ common problems with the installation. ===================== You can get archives for the GAP distribution from the GAP website at -. If you use Unix (including macOS), +. If you use Unix (including macOS), you need to download the GAP source distribution, that is, a file named gap-4.X.Y.tar.bz2 @@ -147,7 +148,7 @@ On Ubuntu or Debian, you can install these with the following command: On Fedora: - sudo dnf install gcc gcc-c++ make autoconf gmp gmp-devel readline readline-devel zlib zlib-devel + sudo dnf install gcc gcc-c++ make autoconf gmp-devel readline-devel zlib-devel On Alpine: @@ -164,27 +165,35 @@ prerequisites. Here is an incomplete list of GAP packages and their requirements - 4ti2Interface - Debian/Ubuntu: 4ti2 + - Fedora: 4ti2-devel - Homebrew: (not currently available) - alnuth - Debian/Ubuntu: pari-gp + - Fedora: pari-gp - Homebrew: pari - browse - Debian/Ubuntu: libncurses-dev + - Fedora: ncurses-devel - Homebrew: ncurses - CddInterface - Debian/Ubuntu: libcdd-dev + - Fedora: cddlib-devel - Homebrew: cddlib - curlInterface - Debian/Ubuntu: libcurl4-openssl-dev + - Fedora: curl-devel - Homebrew: curl - float - Debian/Ubuntu: libfplll-dev libmpc-dev libmpfi-dev libmpfr-dev + - Fedora: fplll libmpc-devel mpfi-devel mpfr-devel - Homebrew: fplll libmpc mpfi mpfr - singular - Debian/Ubuntu: singular + - Fedora: Singular - Homebrew: singular - ZeroMQInterface - Debian/Ubuntu: libzmq3-dev + - Fedora: zeromq-devel - Homebrew: zmq @@ -411,7 +420,7 @@ found at . Congratulations, your installation is finished. Once the installation is complete, you may wish to subscribe to the -[GAP forum mailing list](https://www.gap-system.org/Contacts/Forum/forum.html), +[GAP forum mailing list](https://www.gap-system.org/forum/), which provides help with user questions of a general nature. You can also chat with us on [Slack](https://gap-system.org/slack). Bug reports and other problems you have while installing and/or using GAP should be reported via @@ -465,7 +474,7 @@ the help system which provides useful search features. This section lists a few common problems when installing or running GAP and their remedies. Also see the FAQ list on the GAP web pages at -. +. ### GAP starts with a warning `hmm, I cannot find lib/init.g` diff --git a/LICENSE b/LICENSE index d159169d10..9efa6fbc96 100644 --- a/LICENSE +++ b/LICENSE @@ -2,7 +2,7 @@ Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. @@ -304,8 +304,7 @@ the "copyright" line and a pointer to where the full notice is found. GNU General Public License for more details. You should have received a copy of the GNU General Public License along - with this program; if not, write to the Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + with this program; if not, see . Also add information on how to contact you by electronic and paper mail. @@ -329,8 +328,8 @@ necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. - , 1 April 1989 - Ty Coon, President of Vice + , 1 April 1989 + Moe Ghoul, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may diff --git a/README.md b/README.md index 2b9582a831..853c9195f9 100644 --- a/README.md +++ b/README.md @@ -10,11 +10,11 @@ GAP is a system for computational discrete algebra, with particular emphasis on computational group theory. GAP provides a programming language, a library of thousands of functions implementing algebraic algorithms written in the GAP -language as well as large data libraries of algebraic objects. For a more -detailed overview, see - . +language as well as large data libraries of algebraic objects. For some more +information, see + . For a description of the mathematical capabilities, see - . + . GAP is used in research and teaching for studying groups and their representations, rings, vector spaces, algebras, combinatorial structures, and @@ -26,9 +26,8 @@ easily modify or extend it for your special use. ## Download a stable release version -The latest stable release of the GAP system, including all currently -redistributed GAP packages, can be obtained from - . +The latest stable release of the GAP system can be obtained from + . Afterwards, follow the instructions in the file `INSTALL.md` in the GAP root directory. @@ -69,7 +68,7 @@ On Ubuntu or Debian, you can install these with the following command: On Fedora: - sudo dnf install gcc gcc-c++ make autoconf gmp gmp-devel readline readline-devel zlib zlib-devel + sudo dnf install gcc gcc-c++ make autoconf gmp-devel readline-devel zlib-devel On Alpine: @@ -134,18 +133,13 @@ please read the [contributor guidelines](CONTRIBUTING.md). Additional informatio To keep up to date on GAP news (discussion of problems, release announcements, bug fixes), you can subscribe to the -[GAP forum](https://www.gap-system.org/Contacts/Forum/forum.html) and +[GAP forum](https://www.gap-system.org/forum/) and [GAP development](https://lists.uni-kl.de/gap/info/gap) mailing lists, -notifications on GitHub, and chat with us on [Slack](https://gap-system.org/slack). +notifications on GitHub, or chat with us on [Slack](https://gap-system.org/slack). -If you have any questions about working with GAP, you can ask them on -[GAP forum](https://www.gap-system.org/Contacts/Forum/forum.html) (requires subscription) -or [GAP support](https://www.gap-system.org/Contacts/People/supportgroup.html) mailing lists. - -Please tell us about your use of GAP in research or teaching. We maintain a -[bibliography of publications citing GAP](https://www.gap-system.org/Doc/Bib/bib.html). -Please [help us](https://www.gap-system.org/Contacts/publicationfeedback.html) -keeping it up to date. +If you have any questions about working with GAP, you can ask them on the +[GAP forum](https://www.gap-system.org/forum/) mailing list (requires subscription) +or [use one of our various support channels](https://www.gap-system.org/issues). # License diff --git a/doc/dev/git.xml b/doc/dev/git.xml deleted file mode 100644 index cdae395ede..0000000000 --- a/doc/dev/git.xml +++ /dev/null @@ -1,12 +0,0 @@ - -Version control using Git -

-Introduction - - -Using Git -... - - -
- \ No newline at end of file diff --git a/doc/dev/main.xml b/doc/dev/main.xml index 832b1b5a9b..469a38639e 100644 --- a/doc/dev/main.xml +++ b/doc/dev/main.xml @@ -47,7 +47,6 @@ there is a concept of modules where parts of the <#Include SYSTEM "lib.xml"> <#Include SYSTEM "documentation.xml"> <#Include SYSTEM "testing.xml"> -<#Include SYSTEM "git.xml"> <#Include SYSTEM "pkgdist.xml"> <#Include SYSTEM "website.xml"> <#Include SYSTEM "newcode.xml"> diff --git a/doc/dev/testing.xml b/doc/dev/testing.xml index 71d2a955ed..7ead6d21a7 100644 --- a/doc/dev/testing.xml +++ b/doc/dev/testing.xml @@ -42,8 +42,7 @@ Moreover, it is recommended to group tests that require packages to be performed after all other tests are completed. The directory tst/testinstall contains a subset of tests which are -recommended after installing &GAP;, -see https://www.gap-system.org/Download/INSTALL. +recommended after installing &GAP;. The idea is that the examples in these .tst files are typical &GAP; computations, and that running these tests requires only a few minutes. diff --git a/doc/dev/website.xml b/doc/dev/website.xml index f167d41594..bd05ff922c 100644 --- a/doc/dev/website.xml +++ b/doc/dev/website.xml @@ -12,19 +12,12 @@ Maintaining www.gap-system.org Maintaining the &GAP; website This chapter describes how the information accessible on -https://www.gap-system.org/ is stored +https://www.gap-system.org/ is stored and collected, and how it is transformed into web pages.
Overview -The &GAP; website (in the following just called website) has -a tree structure for easier navigation and overview. Each node and each -leaf of the tree is a web page. Every single page -resides somewhere in this tree. This position is shown in the -navigation bar on the left hand side, and the user can navigate through -the tree using this navigation bar. However, pages can still link to other -pages that reside in some other branch of the tree.

All the sources for the web pages are kept in the git repository @@ -34,372 +27,20 @@ All the sources for the web pages are kept in the git repository git clone https://github.com/gap-system/GapWWW -The web server in St Andrews also uses its clone, updates it to the latest -revision of the &master; branch, runs the Jekyll tool and then -serves the pages. Another named branch is called &testing; and it is served -on the password protected version of the &GAP; website at -https://test.gap-system.org where work in progress may -be published to be reviewed internally. +The website is hosted on a web server at RPTU Kaiserslautern-Landau. +It use a clone of the above git repository. Whenever a commit is pushed +to its &master; branch, the server automatically fetches the changes, +runs the Jekyll tool and then serves the pages.

-The &GAP; website has some pages that are treated specially such as the &GAP; -manuals, the pages for the &GAP; packages, the pages for the &GAP; -bibliography, and the (old) &GAP; forum archive. The setup for these special -pages is described in Sections to - in this chapter. -

- - -
-Getting started - -There are several possible workflows dependently on how much efforts -you would like to commit to the website maintenance. -

- -A minimalistic scenario for small improvements (e.g. correcting details -and fixing typos) only requires to install -https://git-scm.com/ and then: - - -Clone the Website repository: git clone https://github.com/gap-system/GapWWW - - -Make changes in a feature branch - - -Submit your changes as GitHub pull request so that website administrator(s) -can review and merge this update. - - - -If you are one of website administrator(s), then you will also need to -be able to access the web server in St Andrews via ssh to run -certain update scripts and copy necessary data. -

- - - -
-Git usage - -We assume here that you are familiar with the standard git commands -git clone, git pull, git push, git update, -git commit etc. -

- -The source files for the web site are kept in the git repository -https://github.com/gap-system/GapWWW. You may clone it by doing - - -git clone https://github.com/gap-system/GapWWW - - -This command creates in your current directory a directory GapWWW -with the complete source tree of the web site. -

- -Source files are treated like any other source file in the git repository, -that is you can update, modify, commit, add, remove them as usual. -

- -The only thing one has to understand with respect to git is which -implications the branch in which the change has appeared will have on the -process of its publication: - - -Changes in the &master; branch will not be automatically published on -the web server. They will be reviewed by the website administrator who -will then have to run the update script on the server in St Andrews as -described in Section to make them available online. - - -Changes in feature branches (which you may create to keep some -work in progress) will not be visible anywhere. - - -

+The README.md and etc/README.server.md in that repository +explain the technical details about the website setup. -A little comment on the rationale behind this setup might be in order. -It allows that more than one person works independently on the -website and those people exchange versions via git, without -publishing them immediately. The actual guidelines who does what -in this process should be agreed on separately.

+Furthermore the file dev/releases/README.md in the main GAP git repository +contains instructions on how to update the website when a new GAP release is made. -

- -
- The web server in St Andrews - -Currently, the actually published version of the web site is contained in -the directory /gap/GapWWW on the following machine in St Andrews: - - gap-web.host.cs.st-andrews.ac.uk - -

- -

-To get access to this data the easiest and most secure way is probably -to create an RSA key pair, append the public key to -/gap/.ssh/authorized_keys and to keep the private key in the -.ssh subdirectory of the user's home directory. - -

-Before performing an update on gap-web, -it is wise to check first whether jekyll runs without -an error message in your own checked out version of the website. - -

-The next step then is to test it on the online test version of the website. -To do so, ssh into gap-web and the enter these commands: - - cd ~/test.gap-system.org - git pull - jekyll build - -Assuming this worked without error message, you can review the results -at https://test.gap-system.org. - -

-Finally, to update the actual website, use the following: - - cd ~/www.gap-system.org - git pull - jekyll build - - -

- -
-Installation on the web server - -This section describes the procedure to install the &GAP; web site on -a machine from scratch. Thus, this section is usually not needed -because all this is already done on the machine -gap-web.host.cs.st-andrews.ac.uk. However, if one wants to have an exact -copy of the web site or have to install it somewhere anew, this -section is needed. - - -Needed ingredients - - - - standard tools: git, tar, gzip, make, sh - - - jekyll - - - a web server if pages shall be published - - - a copy of the full doc directory from a &GAP; installation for - references into the manual (this can reside on some web site) - - - setup for automatic creation of the pages for packages - - - - - - -Installation procedure - - - -Clone the git repository GapWWW: - - -git clone https://github.com/gap-system/GapWWW - - -This creates a subdirectory GapWWW in the current directory. - - - -Unpack some (frozen) subtrees, which are in archives: - - - cd GapWWW - gzip -dc ForumArchive.tar.gz | tar xvf - - cd Gap3 - gzip -dc Manual3.tar.gz | tar xvf - - cd .. - - - - - -TODO/FIXME/WARNING: everything after this is outdated!!! -

- -Edit GapWWW/lib/config, see that file for instructions: - - - vi lib/config - - - In this file a few variables have to be defined to adapt the web pages - to the local conditions. - - - -Copy a whole doc directory of a &GAP; distribution to the place -mentioned in GapWWW/lib/config (see step 4.) in the variable -GAPManualLink (this is GapWWW/Manuals in the current setup). - - - -The files for the &GAP; bibliography have been included into this directory -tree in the repository. - -

-Create the html and PDF versions by: - - - cd Doc/Bib - gap4 convbib.g - cd ../.. - - -Some more information about this is in GapWWW/Doc/Bib/INFO -which is unchanges since 2010 and may be somewhat outdated. - - - -Install package manuals: - -

- Copy the result of Frank's scripts to the place mentioned in - GapWWW/lib/config (in the variable pkgmixerpath). - (currently, this is GapWWW/Manuals, copy the whole pkg - directory) - -

- To update the package pages, copy all .mixer files and - pkgconf.py to GapWWW/Packages and rerun the - Mixer. - - - -Make sure that the file - GapWWW/lib/AllLinksOfAllHelpSections.data is always up-to-date - (this has to be adjusted whenever the released manuals change). - -

- In the development version of &GAP; there is a file - dev/LinksOfAllHelpSections.g. - Read this with a current &GAP; version with all currently released - packages installed and call WriteAllLinksOfAllHelpSections(), - this writes the file AllLinksOfAllHelpSections.data. It has - then to be checked in to its place under the GapWWW tree. - Do not forget to publish the latest revision. - - - -Run Jekyll: - - - jekyll build - - - - - - - - Installing updated versions - -If things are changed in the repository, all that has to be done to update the -pages locally is: - - -git pull - - -in the GapWWW directory, followed by a - - - jekyll build - - - - -

- -
-The &GAP; manuals on the web pages - -All &GAP; manuals are available in HTML format via the web pages. This -works by simply copying the doc directory of a complete &GAP; -installation to the place specified by the variable GAPManualLink -in GapWWW/lib/config (which is GapWWW/Manuals in the current -setup). Note that those files are not -under version control there, they are only copied to checked out -working copies, like for example on the web server in St Andrews. - -

-The single remaining point to explain is how one can specify links -to manual sections on the web pages. This is done with a special -Mixer tag like the following: - - - <mixer manual="Reference: Lists">Chapter about lists</mixer> - - -This element creates a link to the manual section which would appear -in the &GAP; help system when called with ?Reference: Lists, which -happens to be the chapter in the reference manual about lists. The -text of the link would be Chapter about lists. - -

-This works, because the Mixer has access to a file -containing the links to all manual sections. This file resides in -GapWWW/lib/AllLinksOfAllHelpSections.data, which is created -using dev/LinksOfAllHelpSections.g in the development version -of &GAP; as described in Section . - -

-The value of the attribute manual in the mixer tag -must be the complete text of the section heading the link should -point to. -

- -
-The &GAP; packages on the web pages - -The archives and web pages for the &GAP; packages are generated -by yet another set of tools described in Chapter . -These generate for every package a .mixer-file and for all packages -together a file pkgconf.py. All these files have to be put -under version control in the directory GapWWW/Packages. These nodes then only -have to be put into the tree by mentioning them in the tree file -there. - -
- -
-The &GAP; forum archive - -Until December 2003 the &GAP; forum archive was handled by a tool written -especially for this task. At that point it was switched to mailman, -a generic tool for mailing list, which also does the archiving. -Therefore the old forum archives are frozen in form of a huge amount -of HTML pages. These are not kept under version control as single files but as one big -binary archive under GapWWW/ForumArchive.tar.gz. - -

-To install those pages in a checked out working copy one just has to -extract this archive by doing - - - gzip -dc ForumArchive.tar.gz | tar xf - - -in the GapWWW directory as explained in Section .

diff --git a/doc/ref/copyright.xml b/doc/ref/copyright.xml index f7445b2e61..0766a981bd 100644 --- a/doc/ref/copyright.xml +++ b/doc/ref/copyright.xml @@ -8,18 +8,8 @@ -Copyright ©right; (1987-&RELEASEYEAR;) by the &GAP; Group, -

-incorporating the Copyright ©right; 1999, 2000 by - School of Mathematical and Computational Sciences, - University of St Andrews, - North Haugh, St Andrews, Fife KY16 9SS, Scotland -

-being the Copyright ©right; 1992 by - Lehrstuhl D für Mathematik, RWTH, - 52056 Aachen, Germany, -transferred to St Andrews on July 21st, 1997. -

+Copyright ©right; 1987-&RELEASEYEAR; by its authors, which are +listed at https://github.com/gap-system/gap/blob/master/COPYRIGHT, except for files in the distribution, which have an explicit different copyright statement. In particular, the copyright of packages distributed with &GAP; is usually with the package authors or their institutions. @@ -27,19 +17,20 @@ with &GAP; is usually with the package authors or their institutions. &GAP; is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or -(at your option) any later version. For details, see +(at your option) any later version. +

+&GAP; is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public +License for more details. +

+You should have received a copy of the GNU General Public License along with &GAP;, see the file LICENSE in the root directory of the &GAP; distribution or see https://www.gnu.org/licenses/gpl.html.

-If you obtain &GAP; please send us a short notice to that effect, e.g., -an e-mail message to the address support@gap-system.org. -This helps us to keep track of the number of &GAP; users. -

If you publish a mathematical result that was partly obtained using &GAP;, please cite &GAP;, just as you would cite another paper that you -used (see below for a sample citation). Also we would appreciate if you -could inform us about such a paper, which we will add to the &GAP; -https://www.gap-system.org/Doc/Bib/bib.html. +used (see below for a sample citation).

Specifically, please refer to

@@ -48,24 +39,6 @@ Specifically, please refer to Version &VERSIONNUMBER;; &RELEASEYEAR; (https://www.gap-system.org)

-You are permitted to modify and redistribute &GAP;, but you are not -allowed to restrict further redistribution. That is to say proprietary -modifications will not be allowed. We want all versions of &GAP; to -remain free. -

-If you modify any part of &GAP; and redistribute it, you must supply a -README document. This should specify what modifications you made in -which files. We do not want to take credit or be blamed for your -modifications. -

-Of course we are interested in all of your modifications. In particular -we would like to see bug-fixes, improvements and new functions. So again -we would appreciate it if you would inform us about all modifications you -make. -

-In addition to the general copyright for &GAP; set forth above, -the following terms apply to the versions of &GAP; for Windows. -

&GAP; for Windows is packaged with several packages from Cygwin (https://cygwin.com). Files from Cygwin are provided under their respective @@ -75,11 +48,3 @@ under the terms of the GNU General Public License (GNU GPL); either version 2 of the License, or (at your option) any later version.

Please contact support@gap-system.org if you need further information. - - - - - - - - diff --git a/doc/ref/gappkg.xml b/doc/ref/gappkg.xml index bc76de7058..0eaa2f5bfd 100644 --- a/doc/ref/gappkg.xml +++ b/doc/ref/gappkg.xml @@ -756,7 +756,7 @@ There should be at least a text version of your documentation provided for use in the terminal running &GAP; and some nicely printable version in .pdf format. Many &GAP; users like to browse the documentation in HTML format -via their Web browser. As a package author, you are not obliged +via their web browser. As a package author, you are not obliged to provide an HTML version of your package manual, but if you use the &GAPDoc; package you should have no trouble in producing one. diff --git a/doc/ref/moreinfo.xml b/doc/ref/moreinfo.xml deleted file mode 100644 index 6d06671baf..0000000000 --- a/doc/ref/moreinfo.xml +++ /dev/null @@ -1,74 +0,0 @@ - - - - - - - - - - - -Information about &GAP; is best obtained from the &GAP; website -https://www.gap-system.org. -There you will find, amongst other things: - - -directions to the sites from which you can download the -current &GAP; distribution, all accepted and deposited &GAP; packages, -and a selection of other contributions. - - -the &GAP; manual and an archive of the gap-forum mailing -list, formatted for reading with a Web browser, and indexed for -searching. - - -information about &GAP; developers, and about the email -addresses available for comment, discussion and support. - - -

-

-We would particularly ask you to note the following things: - - -The &GAP; Forum – an email discussion forum for comments, -discussions or questions about &GAP;. You must subscribe to the list -before you can post to it, see the website for details. -In particular we will announce new releases in this mailing list. - - -The email address support@gap-system.org to which you -are asked to send any questions or bug reports which do not seem likely -to be of interest to the whole &GAP; Forum. Please give a -(short, if possible) self-contained excerpt of a &GAP; -session containing both input and output that illustrates your problem -(including comments of why you think it is a bug) and state the type of -the machine, operating system, (compiler used, if UNIX/Linux) and the -version of &GAP; you are using (the first line after the &GAP; 4 -banner starting GAP, Version 4...). - - -We also ask you to send a brief message to -support@gap-system.org when you install &GAP;. - - -The correct form of citation of &GAP;, which we ask you use -whenever you publish scientific results obtained using &GAP;. - - -

-It finally remains for us to wish you all pleasure and success in using -&GAP;, and to invite your constructive comment and criticism. -

-

-

-The GAP Group, -

-&RELEASEDAY; - - - - - diff --git a/doc/ref/overview.xml b/doc/ref/overview.xml index e483fde1c2..0c300b8f9e 100644 --- a/doc/ref/overview.xml +++ b/doc/ref/overview.xml @@ -41,7 +41,7 @@ Colorado State University, Fort Collins. More information on the motivation and development of &GAP; to date, can be found on our website in a section entitled Some History of &GAP;: -https://www.gap-system.org/Doc/History/history.html. +https://www.gap-system.org/about/history/.

For those readers who have used an earlier version of &GAP;, an overview of the changes from &GAP; 4.4 and a brief @@ -81,7 +81,7 @@ a number of packages. The core system consists of four main parts. algorithms. - a read-eval-view style user interface. + a read-eval-print loop (REPL) user interface. @@ -106,7 +106,7 @@ A library of group theoretical data which contains The documentation. This is available as on-line help, as printable files in PDF format and as HTML for viewing - with a Web browser. + with a web browser.

@@ -146,7 +146,7 @@ Representations; therefore, installation and usage of packages is recommended.

Further details about &GAP; packages can be found in chapter , and on the -&GAP; website here: https://www.gap-system.org/Packages/packages.html. +&GAP; website at https://www.gap-system.org/packages/authors/. diff --git a/doc/ref/preface.xml b/doc/ref/preface.xml index e6fd7c467b..12cfdbc37c 100644 --- a/doc/ref/preface.xml +++ b/doc/ref/preface.xml @@ -75,12 +75,9 @@ provide copyright and licensing information.

Authors and Maintainers -&GAP; is the work of very many people, many of whom still maintain -parts of the system. A complete list of authors, and an approximation -to the current list of maintainers can be found on the &GAP; -website at - https://www.gap-system.org/Contacts/People/authors.html and - https://www.gap-system.org/Contacts/People/modules.html. +&GAP; is the work of very many people, some of whom still maintain +parts of the system. A complete list of authors can be found at + https://github.com/gap-system/gap/blob/master/COPYRIGHT. All &GAP; packages have their own authors and maintainers. It should however be noted that some @@ -105,8 +102,7 @@ We also include with this distribution a number of packages which have not (yet) gone through our refereeing process. Some may be accepted in the future, in other cases the authors have chosen not to submit them. More information can be found -on our website -(see Section ). +on our website https://www.gap-system.org.

@@ -136,20 +132,4 @@ technical architect of &GAP; 3 and &GAP; 4. <#Include SYSTEM "../ref/copyright.xml"> - - -
-Further Information about &GAP; -web sites -email addresses -support -<#Include SYSTEM "../ref/moreinfo.xml"> -
- - - - - - - diff --git a/doc/tut/preface.xml b/doc/tut/preface.xml index 2197d3a8fc..6460bca1b4 100644 --- a/doc/tut/preface.xml +++ b/doc/tut/preface.xml @@ -50,15 +50,4 @@ system and list sources of further information about &GAP;. <#Include SYSTEM "../ref/overview.xml"> - -
-Further Information about &GAP; -<#Include SYSTEM "../ref/moreinfo.xml"> -
- - - - - - diff --git a/lib/package.gi b/lib/package.gi index 1d86f92280..38ac50258f 100644 --- a/lib/package.gi +++ b/lib/package.gi @@ -2554,7 +2554,7 @@ GAPInfo.PackagesRestrictions := AtomicRecord(rec( " with the current version of GAP.\n", " It is strongly recommended to update to the ", "most recent version, see URL\n", - " https://www.gap-system.org/Packages/autpgrp.html\n" ); + " https://gap-packages.github.io/autpgrp/\n" ); fi; end )) )); diff --git a/src/streams.c b/src/streams.c index 970dc7f984..d36d67eb46 100644 --- a/src/streams.c +++ b/src/streams.c @@ -846,7 +846,7 @@ static Obj FuncREAD(Obj self, Obj inputObj) ** *F FuncREAD_STREAM_LOOP( , , ) . . read a stream ** -** Read data from in a read-eval-view loop and write all output +** Read data from in a read-eval-print loop and write all output ** to . This is used by the GAP function `RunTests` and hence ** indirectly for implementing `Test` and `TestDirectory`, */ From b3a658eea36baa3a4c4599466808847e93d1b71d Mon Sep 17 00:00:00 2001 From: Thomas Breuer Date: Fri, 31 Oct 2025 09:05:57 +0100 Subject: [PATCH 049/234] forbid `Order` for non-endo group homomorphisms (#6156) --- lib/morpheus.gi | 3 +++ tst/testinstall/mapphomo.tst | 14 ++++++++++++++ 2 files changed, 17 insertions(+) diff --git a/lib/morpheus.gi b/lib/morpheus.gi index ee25f26a35..3d22979de6 100644 --- a/lib/morpheus.gi +++ b/lib/morpheus.gi @@ -26,6 +26,9 @@ MORPHEUSELMS := 50000; InstallMethod(Order,"for automorphisms",true,[IsGroupHomomorphism],0, function(hom) local map,phi,o,lo,i,j,start,img,d,nat,ser,jord,first; + if not IsEndoGeneralMapping( hom ) then + Error( "Source and Range of must be equal" ); + fi; d:=Source(hom); if not (HasIsFinite(d) and IsFinite(d)) then TryNextMethod(); diff --git a/tst/testinstall/mapphomo.tst b/tst/testinstall/mapphomo.tst index fce1e27862..377a1209ad 100644 --- a/tst/testinstall/mapphomo.tst +++ b/tst/testinstall/mapphomo.tst @@ -71,6 +71,20 @@ fail gap> GroupHomomorphismByImages(G, H, [], []); fail +# Order for homomorphisms +gap> G:= SymmetricGroup( 3 );; +gap> hom:= IdentityMapping( G );; +gap> Order( hom ); +1 +gap> One( hom ) = hom; +true +gap> H:= Group( (1,2) );; +gap> hom:= RestrictedMapping( hom, H );; +gap> Order( hom ); +Error, Source and Range of must be equal +gap> One( hom ); +fail + # Check that group homomorphisms created by a function can compute preimages. gap> for G in [ SymmetricGroup(5), SmallGroup( 24, 12 ), GL(2,3) ] do > hom:= GroupHomomorphismByFunction( G, G, x -> x ); From a60112a632b901eae99727ccdc6640174be07eb7 Mon Sep 17 00:00:00 2001 From: Alexander Hulpke Date: Tue, 11 Nov 2025 07:05:25 -0700 Subject: [PATCH 050/234] Enhance support for very long transversals in a permutation group by forcing down huge index steps through an intermediate subgroup (#6114) When computing a transversal in a permutation group force down huge index steps, as they might lead to creation of infeasibly long bit lists. Incidentally, this allows for Filtering classes in A_15. --- lib/csetgrp.gi | 5 +++- lib/csetperm.gi | 20 +++++++++++--- tst/testinstall/listgen.tst | 53 ++++++++++++++++++++++++++++++++++++- 3 files changed, 73 insertions(+), 5 deletions(-) diff --git a/lib/csetgrp.gi b/lib/csetgrp.gi index c3da828528..ea7c552195 100644 --- a/lib/csetgrp.gi +++ b/lib/csetgrp.gi @@ -1819,7 +1819,10 @@ DeclareRepresentation( "IsFactoredTransversalRep", # group, subgroup, list of transversals (descending) BindGlobal("FactoredTransversal",function(G,S,t) local trans,m,i; - Assert(1,ForAll([1..Length(t)-1],i->t[i]!.subgroup=t[i+1]!.group)); + Assert(1,ForAll([1..Length(t)-1], + i -> (not IsBound(t[i]!.subgroup)) + or (not IsBound(t[i+1]!.group)) + or t[i]!.subgroup = t[i+1]!.group)); m:=[1]; for i in [Length(t),Length(t)-1..2] do diff --git a/lib/csetperm.gi b/lib/csetperm.gi index 5572d21b45..4899417c5b 100644 --- a/lib/csetperm.gi +++ b/lib/csetperm.gi @@ -42,7 +42,9 @@ end ); ## #F RightTransversalPermGroupConstructor( , , ) . constructor ## -MAX_SIZE_TRANSVERSAL := 100000; +MAX_SIZE_TRANSVERSAL := 100000; # try to keep transversals shorter than this +BITLIST_LIMIT_TRANSVERSAL:=10^8; # absolutely must keep transversals + # shorter, as otheriwse too long bit lists might be produced # so far only orbits and perm groups -- TODO: Other deduced actions InstallGlobalFunction(ActionRefinedSeries,function(G,U) @@ -121,11 +123,23 @@ BindGlobal( "RightTransversalPermGroupConstructor", function( filter, G, U ) # 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(Last(nc))>MAX_SIZE_TRANSVERSAL then + i:=3; + while i<=Length(ac) do + if Size(ac[i-1])/Size(nc[Length(nc)]) + >BITLIST_LIMIT_TRANSVERSAL then + # the next step would be horrible -- insert + bpt:=AscendingChain(ac[i-1],nc[Length(nc)]:cheap); + bpt:=bpt{[2..Length(bpt)-1]}; + ac:=Concatenation(ac{[1..i-2]},bpt,ac{[i-1..Length(ac)]}); + actions:=Concatenation(actions{[1..i-2]},List(bpt,x->fail), + actions{[i-1..Length(actions)]}); + fi; + + if Size(ac[i])/Size(nc[Length(nc)])>MAX_SIZE_TRANSVERSAL then Add(nc,ac[i-1]); Add(nct,actions[i-1]); fi; + i:=i+1; od; Add(nc,Last(ac)); Add(nct,Last(actions)); diff --git a/tst/testinstall/listgen.tst b/tst/testinstall/listgen.tst index 08c42caa28..e93acc2a5f 100644 --- a/tst/testinstall/listgen.tst +++ b/tst/testinstall/listgen.tst @@ -1,4 +1,4 @@ -#@local g,h,l,l2,p2,perm,t,filt,lcpy,permsp +#@local g,h,l,l2,p2,perm,t,filt,lcpy,permsp,old_paras,G,U,tr gap> START_TEST("listgen.tst"); gap> List( [ 1 .. 10 ], x -> x^2 ); [ 1, 4, 9, 16, 25, 36, 49, 64, 81, 100 ] @@ -156,6 +156,8 @@ gap> String( l ); "[ 10, 9, 8, 7, 6, 5, 4, 3, 2, 1 ]" gap> String( [ 1 .. 10 ] ); "[ 1 .. 10 ]" + +# right transversals gap> g:=Group((1,5)(2,6)(3,7)(4,8),(1,3)(2,4)(5,7)(6,8),(1,2)(3,4)(5,6)(7,8), > (5,6)(7,8), (5,7)(6,8), (3,4)(7,8), (3,5)(4,6), (2,3)(6,7));; gap> h:=Subgroup(g,[(5,6)(7,8),(5,7)(6,8),(2,4)(6,8),(2,5)(4,7),(1,2)(3,4)]);; @@ -167,5 +169,54 @@ true gap> p2:=Position(t,(5,7)(6,8)); fail +# right transversals, see pull request #6114 +gap> old_paras:= [ BITLIST_LIMIT_TRANSVERSAL, MAX_SIZE_TRANSVERSAL ];; +gap> BITLIST_LIMIT_TRANSVERSAL:= 59;; +gap> MAX_SIZE_TRANSVERSAL:= 59;; +gap> G:= Group( [ # the group is equal to AtlasGroup( "J1" ) +> ( 1,262)( 2,107)( 3, 21)( 4,213)( 5,191)( 6, 22)( 7,133) +> ( 8,234)( 9,232)( 10,151)( 11,139)( 12,176)( 13,202)( 14,253)( 15,222) +> ( 17,195)( 18,206)( 19, 68)( 20, 55)( 23,179)( 24,217)( 25,216)( 26,256) +> ( 27, 87)( 28, 70)( 29,131)( 30, 44)( 31,105)( 32,170)( 33, 77)( 34,104) +> ( 35,198)( 36,137)( 37,243)( 38, 56)( 39,124)( 40,223)( 41,134)( 43,174) +> ( 46, 51)( 47,128)( 48, 94)( 49,250)( 50,264)( 52,183)( 53,231)( 54,115) +> ( 57, 85)( 58,233)( 59,261)( 60, 95)( 61,235)( 62,177)( 63,249)( 64, 91) +> ( 65,247)( 66,155)( 69,219)( 71,237)( 72,211)( 73, 84)( 74,192)( 75,130) +> ( 76,251)( 79,260)( 80,112)( 81,193)( 82,156)( 83,242)( 86,238)( 88,143) +> ( 89,168)( 90,148)( 92,119)( 93,212)( 96,150)( 97,199)( 98,140)( 99,189) +> (100,180)(101,147)(102,111)(103,159)(106,162)(108,194)(109,166)(110,200) +> (113,120)(114,141)(116,182)(117,181)(118,225)(121,254)(122,125)(123,146) +> (126,208)(127,221)(129,210)(132,255)(136,175)(138,207)(142,240)(144,172) +> (145,185)(149,224)(152,169)(153,241)(154,190)(157,214)(158,161)(160,236) +> (163,239)(164,229)(165,230)(167,188)(171,258)(173,186)(178,245)(184,205) +> (187,228)(197,203)(201,252)(209,248)(215,259)(218,246)(220,227)(257,263) +> (265,266), ( 1,146, 21)( 2,132, 82)( 4,156,166)( 5,242,253) +> ( 6,107, 28)( 7,125, 76)( 8,245,130)( 9,174, 42)( 10,241,244) +> ( 11,264, 63)( 12,248,234)( 13, 36, 44)( 14,116,128)( 15, 47, 25) +> ( 16,178,112)( 17,170,110)( 18,197, 74)( 19,233,180)( 20,121, 96) +> ( 22,228,155)( 23, 48,173)( 24,201,187)( 26,136,190)( 27,212, 94) +> ( 29,175, 52)( 30, 77, 32)( 31,237, 34)( 33,226, 90)( 35,129, 54) +> ( 37,161,114)( 38,232, 87)( 39,219,192)( 40, 78,159)( 41,139, 71) +> ( 43,211,251)( 45,222,240)( 46, 97,135)( 49, 70,131)( 50,153,200) +> ( 51,186,209)( 53,203,216)( 55,169, 64)( 56,140,230)( 57,260,118) +> ( 58, 91,243)( 59,199,227)( 60,108,164)( 61,208,101)( 62,206,106) +> ( 65,103, 66)( 67, 95,205)( 68, 73,225)( 69,151,113)( 72,221,152) +> ( 75,143,202)( 79,217,254)( 80, 93,122)( 81,181,252)( 83,258,126) +> ( 84,163,177)( 85,154,213)( 86,182,196)( 88,133,215)( 89,117,247) +> ( 92,191,160)( 99,229,263)(100,138,188)(102,194,157)(105,149,184) +> (109,123,193)(111,137,183)(115,238,235)(119,167,147)(120,134,189) +> (124,185,265)(127,218,261)(141,231,210)(142,239,236)(144,224,249) +> (145,158,220)(148,214,172)(150,250,259)(162,257,256)(165,179,246) +> (176,195,266)(198,204,207)(223,262,255) ] );; +gap> U:= TrivialSubgroup( G );; +gap> tr:= RightTransversalPermGroupConstructor( +> IsRightTransversalPermGroupRep, G, U );; +gap> Length( tr ) = Size( G ); +true +gap> PositionCanonical( tr, GeneratorsOfGroup( G )[1] ) <= Length( tr ); +true +gap> BITLIST_LIMIT_TRANSVERSAL:= old_paras[1];; +gap> MAX_SIZE_TRANSVERSAL:= old_paras[2];; + # that's all, folks gap> STOP_TEST("listgen.tst"); From 83b2223a3ab037325f5d79381999dc71e33c37df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lars=20G=C3=B6ttgens?= Date: Thu, 13 Nov 2025 00:35:45 +0100 Subject: [PATCH 051/234] Only show authors in `Cite`, not maintainers (#6162) --- lib/package.gi | 4 ++-- tst/testinstall/package.tst | 32 +++++++++++++++----------------- 2 files changed, 17 insertions(+), 19 deletions(-) diff --git a/lib/package.gi b/lib/package.gi index 38ac50258f..cfa5a5c68e 100644 --- a/lib/package.gi +++ b/lib/package.gi @@ -2784,7 +2784,7 @@ InstallGlobalFunction( BibEntry, function( arg ) # author # # computed from the Persons component of the package, - # not distinguishing authors and maintainers, + # just taking authors, # keeping the ordering of entries, # # title @@ -2846,7 +2846,7 @@ InstallGlobalFunction( BibEntry, function( arg ) else entry:= Concatenation( "\n" ); author:= List( Filtered( pkginfo.Persons, - person -> person.IsAuthor or person.IsMaintainer ), + person -> person.IsAuthor ), person -> Concatenation( " ", CallFuncList( function(x) if IsBound( x.FirstNames ) then diff --git a/tst/testinstall/package.tst b/tst/testinstall/package.tst index a2f7052e4b..2b1a5d6e84 100644 --- a/tst/testinstall/package.tst +++ b/tst/testinstall/package.tst @@ -489,15 +489,15 @@ to cite mockpkg version from this installation Text: -[AAM18] Author, A., Author, R. and Maintainer, O., mockpkg, A mock package -for use by the GAP test suite, Version 0.1 (2018), GAP package, +[AA18] Author, A. and Author, R., mockpkg, A mock package for use by the GAP +test suite, Version 0.1 (2018), GAP package, https://mockpkg.gap-system.org/. HTML:

-[AAM18] Author, A., Author,\ - R. and Maintainer, O., +[AA18] Author, A. and Autho\ +r, R., mockpkg, A mock package for use by the GAP test suite, Version 0.1 (2018)
@@ -512,7 +512,6 @@ BibXML: ActiveAuthor RetiredAuthor - OnlyMaintainer <C>mockpkg</C>, <C>A mock package for use by the GAP test suite</C>, <C>V</C>ersion 0.1 @@ -525,7 +524,7 @@ BibXML: BibTeX: @misc{ mockpkg, - author = {Author, A. and Author, R. and Maintainer, O.}, + author = {Author, A. and Author, R.}, title = {{mockpkg}, {A mock package for use by the GAP test suite}, {V}ersion 0.1}, month = {Mar}, @@ -534,7 +533,7 @@ BibTeX: howpublished = {\href {https://mockpkg.gap-system.org/} {\texttt{https://mockpkg.gap\texttt{\symbol{45}}system.o\ rg/}}}, - printedkey = {AAM18} + printedkey = {AA18} } @@ -545,15 +544,15 @@ to cite mockpkg version from this installation Text: -[AAM18] Author, A., Author, R. and Maintainer, O., mockpkg, A mock package -for use by the GAP test suite, Version 0.1 (2018), GAP package, +[AA18] Author, A. and Author, R., mockpkg, A mock package for use by the GAP +test suite, Version 0.1 (2018), GAP package, https://mockpkg.gap-system.org/. HTML:

-[AAM18] Author, A., Author,\ - R. and Maintainer, O., +[AA18] Author, A. and Autho\ +r, R., mockpkg, A mock package for use by the GAP test suite, Version 0.1 (2018)
@@ -568,9 +567,8 @@ BibXML: ActiveAuthor RetiredAuthor - OnlyMaintainer - <C>mockpkg</C>, A mock package for use by the GAP test suite, + <title><C>mockpkg</C>, <C>A mock package for use by the GAP test suite</C>, <C>V</C>ersion 0.1 https://mockpkg.gap-system.org/ Mar @@ -581,15 +579,15 @@ BibXML: BibTeX: @misc{ mockpkg, - author = {Author, A. and Author, R. and Maintainer, O.}, - title = {{mockpkg}, A mock package for use by the GAP test - suite, {V}ersion 0.1}, + author = {Author, A. and Author, R.}, + title = {{mockpkg}, {A mock package for use by the GAP test + suite}, {V}ersion 0.1}, month = {Mar}, year = {2018}, note = {GAP package}, howpublished = {\href {https://mockpkg.gap-system.org/} {\texttt{https://mockpkg.gap-system.org/}}}, - printedkey = {AAM18} + printedkey = {AA18} } From caf94adee8f9ad6fa24162e9d55bb130051a9b3d Mon Sep 17 00:00:00 2001 From: Alexander Hulpke Date: Wed, 12 Nov 2025 17:39:27 -0700 Subject: [PATCH 052/234] FIX: RepresentativesPerfectSubgroups (#6160) Do not just pick normal subgroups that are normal in minimal ones on top, but their full G-orbits, with actions. This seems to avoid representative selection issues. --- lib/grplatt.gi | 9 ++++++++- tst/testbugfix/2025-11-06-perfectsubs.tst | 5 +++++ 2 files changed, 13 insertions(+), 1 deletion(-) create mode 100644 tst/testbugfix/2025-11-06-perfectsubs.tst diff --git a/lib/grplatt.gi b/lib/grplatt.gi index 075d4e0b23..6b170d1f82 100644 --- a/lib/grplatt.gi +++ b/lib/grplatt.gi @@ -993,6 +993,7 @@ InstallGlobalFunction(LatticeViaRadical,function(arg) if Length(mpcgs)>0 then gf:=GF(RelativeOrders(mpcgs)[1]); if select=IsPerfectGroup then + # the only normal subgroups are those that are normal under any # subgroup so far. @@ -1009,7 +1010,13 @@ InstallGlobalFunction(LatticeViaRadical,function(arg) od; SortBy(nts,Size); # increasing order # by setting up `act' as fail, we force a different selection later - act:=[nts,fail]; + #act:=[nts,fail]; + + # there is an issue in selecting representatives. Form G-orbits to + # remain in usual case. + nts:=Union(Orbits(G,nts)); + act:=ActionHomomorphism(G,nts,"surjective"); + act:=[nts,act]; elif select=IsNonabelianSimpleGroup then # simple -> no extensions, only the trivial subgroup is valid. diff --git a/tst/testbugfix/2025-11-06-perfectsubs.tst b/tst/testbugfix/2025-11-06-perfectsubs.tst new file mode 100644 index 0000000000..741a626b04 --- /dev/null +++ b/tst/testbugfix/2025-11-06-perfectsubs.tst @@ -0,0 +1,5 @@ +# missing subgroups when finding perfect subgroups +# See . +gap> G:=WreathProduct(Group((1,2)), SymmetricGroup(6));; +gap> Size(ConjugacyClassesPerfectSubgroups(G)); +8 From d18700b6ba3776b3ce17f7e18fd1fef11cc1187f Mon Sep 17 00:00:00 2001 From: Max Horn Date: Thu, 13 Nov 2025 15:56:23 +0100 Subject: [PATCH 053/234] Add missing local variable declaration (#6163) --- hpcgap/lib/hpc/tasks.g | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hpcgap/lib/hpc/tasks.g b/hpcgap/lib/hpc/tasks.g index 2ed1953052..c846be8e8d 100644 --- a/hpcgap/lib/hpc/tasks.g +++ b/hpcgap/lib/hpc/tasks.g @@ -366,7 +366,7 @@ end; WaitTasks := WaitTask; WaitAnyTask := function(arg) - local len, task; + local i, len, task; atomic arg[1] do if Length(arg) = 1 and IsList(arg[1]) then From c62dc3cf5adf18f8826ed9d4a39a7306fa8b619a Mon Sep 17 00:00:00 2001 From: Alexander Hulpke Date: Thu, 20 Nov 2025 11:19:38 -0700 Subject: [PATCH 054/234] Fixed a potential error message about data types when computing extensions (#6159) Disabled complicated construction for perm rep of extension. --- lib/twocohom.gi | 55 ++++++++++--------- .../2025-11-06-PermrepExtension.tst | 9 +++ 2 files changed, 39 insertions(+), 25 deletions(-) create mode 100644 tst/testbugfix/2025-11-06-PermrepExtension.tst diff --git a/lib/twocohom.gi b/lib/twocohom.gi index 824ce3bdba..7af0728b1e 100644 --- a/lib/twocohom.gi +++ b/lib/twocohom.gi @@ -1439,7 +1439,8 @@ end); InstallGlobalFunction(FpGroupCocycle,function(arg) local r,z,ogens,n,gens,str,dim,i,j,f,rels,new,quot,g,p,collect,m,e,fp,sim, it,hom,trysy,prime,mindeg,fps,ei,mgens,mwrd,nn,newfree,mfpi,mmats,sub, - tab,tab0,evalprod,gensmrep,invsmrep,zerob,step,simi,simiq,wasbold, + tab,tab0,evalprod,gensmrep,invsmrep,zerob,simi,simiq,wasbold, + #step, mon,ord,mn,melmvec,killgens,frew,fffam,ofgens,rws,formalinverse; # function to evaluate product (as integer list) in gens (and their @@ -1834,8 +1835,8 @@ local r,z,ogens,n,gens,str,dim,i,j,f,rels,new,quot,g,p,collect,m,e,fp,sim, # module is irreducible). e:=LargerQuotientBySubgroupAbelianization(mfpi,m:cheap); if e<>fail then - step:=0; - while step<=1 do +# step:=0; +# while step<=1 do # Now write down the combined representation in wreath e:=DefiningQuotientHomomorphism(e); @@ -1859,26 +1860,30 @@ local r,z,ogens,n,gens,str,dim,i,j,f,rels,new,quot,g,p,collect,m,e,fp,sim, x->IsOne(MappedWord(x,FreeGeneratorsOfFpGroup(fps), GeneratorsOfGroup(e!.quot))))); - if step=0 then - i:=GroupHomomorphismByImagesNC(e!.quot,p, - GeneratorsOfGroup(e!.quot), - GeneratorsOfGroup(p)); - j:=PreImage(i,m); - if AbelianInvariants(j)=AbelianInvariants(newfree) then - step:=2; - Info(InfoExtReps,2,"Small bit did good"); - else - Info(InfoExtReps,2,"Need expensive version"); - e:=LargerQuotientBySubgroupAbelianization(mfpi,m: - cheap:=false); - e:=Intersection(e, - KernelOfMultiplicativeGeneralMapping(quot)); - fi; - fi; - - - step:=step+1; - od; +# if step=0 then +# tab:=GroupHomomorphismByImagesNC(e!.quot,p, +# GeneratorsOfGroup(e!.quot), +# GeneratorsOfGroup(p)); +# j:=PreImage(tab,m); +# if AbelianInvariants(j)=AbelianInvariants(newfree) then +# step:=2; +# Info(InfoExtReps,2,"Small bit did good"); +# else +# Info(InfoExtReps,2,"Use expensive version"); +# +# tab:=LargerQuotientBySubgroupAbelianization(mfpi,m: +# cheap:=false); +# if tab<>fail then +# e:=Intersection(e, +# KernelOfMultiplicativeGeneralMapping(quot)); +# step:=2; +# fi; +# fi; +# fi; +# +# +# step:=step+1; +# od; fi; @@ -1894,12 +1899,12 @@ local r,z,ogens,n,gens,str,dim,i,j,f,rels,new,quot,g,p,collect,m,e,fp,sim, j:=List(Orbits(j,MovedPoints(j)),x->Stabilizer(j,x[1])); j:=List(j,x->PreImage(i,x)); e:=Intersection(j); - e:=Intersection(e,KernelOfMultiplicativeGeneralMapping(quot)); fi; fi; - if e<>fail then + e:=Intersection(e,KernelOfMultiplicativeGeneralMapping(quot)); + Info(InfoExtReps,2,"Resulting deg=",NrMovedPoints(e!.quot)); # can we do better degree -- greedy block reduction? nn:=e!.quot; if IsTransitive(nn,MovedPoints(nn)) then diff --git a/tst/testbugfix/2025-11-06-PermrepExtension.tst b/tst/testbugfix/2025-11-06-PermrepExtension.tst new file mode 100644 index 0000000000..dbafe4b761 --- /dev/null +++ b/tst/testbugfix/2025-11-06-PermrepExtension.tst @@ -0,0 +1,9 @@ +# permrep of extension, computed automatically +# See . +gap> G:=Group([(1,2,3),(1,2)(3,4),(1,2)(4,5),(1,2)(5,6), (7,8), (9,10,11) ]);; +gap> F:=GF(5);; +gap> M:=IrreducibleModules(G,F,5)[2][6];; +gap> M2:=rec(field:=F,generators:=List(M.generators,m->DirectSumMat(m,m)));; +gap> ext:=Extensions(G,M2);; +gap> List(ext,Size); +[ 21093750000 ] From 50b50cf3cfd79c6c313c5c96799890301e421d6f Mon Sep 17 00:00:00 2001 From: frankluebeck Date: Tue, 25 Nov 2025 13:31:07 +0100 Subject: [PATCH 055/234] Fix permission problem in streams.txt (#6168) The current test yields an error if called by a user that has no write permissions in the GAP installation directory. With this change the files in the test are created in a temporary directory instead. --- tst/testinstall/streams.tst | 1 + 1 file changed, 1 insertion(+) diff --git a/tst/testinstall/streams.tst b/tst/testinstall/streams.tst index 6983fc72e2..821b691506 100644 --- a/tst/testinstall/streams.tst +++ b/tst/testinstall/streams.tst @@ -212,6 +212,7 @@ Error, Print formatting status must be true or false # too many open files gap> streams := [ ];; +gap> fname := Filename(tmpdir, "testdata");; gap> for i in [ 1 .. 300 ] do > stream := OutputTextFile( fname, false ); > Assert(0, stream <> fail); From eded971757f18d942ec0d0eef65332ed32c91e0c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 3 Dec 2025 09:22:36 +0000 Subject: [PATCH 056/234] build(deps): bump actions/checkout from 5 to 6 (#6167) Bumps [actions/checkout](https://github.com/actions/checkout) from 5 to 6. - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/v5...v6) --- updated-dependencies: - dependency-name: actions/checkout dependency-version: '6' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/CI.yml | 6 +++--- .github/workflows/gapjl.yml | 2 +- .github/workflows/lint.yml | 2 +- .github/workflows/release.yml | 6 +++--- .github/workflows/update-gh-pages.yml | 2 +- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index 445a8fffa2..c25a23b30e 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -141,7 +141,7 @@ jobs: TEST_SUITES: ${{ matrix.test-suites }} steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 - name: "Set up Python" uses: actions/setup-python@v6 @@ -299,7 +299,7 @@ jobs: - name: Install cross compile dependencies run: sudo apt-get install -q -y git libgmp-dev:s390x libreadline-dev:s390x zlib1g-dev:s390x - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 - run: ./autogen.sh @@ -365,7 +365,7 @@ jobs: env: AUTOCONF_VERSION: 2.71 steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 - name: Download required GAP packages run: | diff --git a/.github/workflows/gapjl.yml b/.github/workflows/gapjl.yml index 6f2aa3c504..f7ff5e2675 100644 --- a/.github/workflows/gapjl.yml +++ b/.github/workflows/gapjl.yml @@ -44,7 +44,7 @@ jobs: steps: - name: Checkout GAP - uses: actions/checkout@v5 + uses: actions/checkout@v6 with: path: 'GAPROOT' - name: "Set up Julia" diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 410663bba4..04502aa792 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -15,7 +15,7 @@ jobs: runs-on: ubuntu-latest steps: - name: "Check out the repository" - uses: actions/checkout@v5 + uses: actions/checkout@v6 - name: "Set up Python" uses: actions/setup-python@v6 with: diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 5c0a61a90b..d154d96403 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -35,7 +35,7 @@ jobs: name: "Validate release scripts" runs-on: ubuntu-latest steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 - name: "Set up Python" uses: actions/setup-python@v6 @@ -72,7 +72,7 @@ jobs: # requires fetching the entire history. Therefore, we might as well do # that here when checking out the repo, which is what setting fetch-depth # to 0 accomplishes here. - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 with: fetch-depth: 0 @@ -207,7 +207,7 @@ jobs: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - name: "Clone the Windows installer maker scripts" - uses: actions/checkout@v5 + uses: actions/checkout@v6 with: repository: gap-system/gap-windows ref: main diff --git a/.github/workflows/update-gh-pages.yml b/.github/workflows/update-gh-pages.yml index ec8388cb7d..3f1b21e41c 100644 --- a/.github/workflows/update-gh-pages.yml +++ b/.github/workflows/update-gh-pages.yml @@ -41,7 +41,7 @@ jobs: sudo apt-get update sudo apt-get install --no-install-recommends "${packages[@]}" - name: Checkout - uses: actions/checkout@v5 + uses: actions/checkout@v6 - name: Configure GAP run: | ./autogen.sh && ./configure From 73fefd0163a6ecc80a0984513e9fa8e78ade9d26 Mon Sep 17 00:00:00 2001 From: Thomas Breuer Date: Wed, 3 Dec 2025 10:23:11 +0100 Subject: [PATCH 057/234] Fix the definition of `PClassPGroup` (#6169) --- lib/grp.gd | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/grp.gd b/lib/grp.gd index c205082bf1..f9127d72c0 100644 --- a/lib/grp.gd +++ b/lib/grp.gd @@ -556,7 +556,7 @@ DeclareAttribute( "PrimePGroup", IsPGroup ); ## ## The p-class of a p-group G ## (see ) -## is the length of the lower p-central series +## is the number of steps in the lower p-central series ## (see ) of G. ## If G is not a p-group then an error is issued. ## @@ -580,7 +580,9 @@ DeclareAttribute( "PClassPGroup", IsPGroup ); ## which is defined as the minimal size of a generating system of G. ## If G is not a p-group then an error is issued. ## h:=Group((1,2,3,4),(1,3));; +## gap> h:= Group((1,2,3,4), (1,3));; +## gap> Length(PCentralSeries(h)); +## 3 ## gap> PClassPGroup(h); ## 2 ## gap> RankPGroup(h); From c34dcaa6321d03946e6601b58720796298052e04 Mon Sep 17 00:00:00 2001 From: Thomas Breuer Date: Thu, 4 Dec 2025 00:31:35 +0100 Subject: [PATCH 058/234] fix `IsomorphismPermGroup` for trivial f. p. (sub)group (#6170) --- lib/grpfp.gi | 12 ++++++++---- tst/testinstall/grpfp.tst | 11 ++++++++++- 2 files changed, 18 insertions(+), 5 deletions(-) diff --git a/lib/grpfp.gi b/lib/grpfp.gi index 6685fed099..0546a1f18a 100644 --- a/lib/grpfp.gi +++ b/lib/grpfp.gi @@ -4017,7 +4017,7 @@ local mappow, G, max, p, gens, rels, comb, i, l, m, H, HH, t, sz, max:=CosetTableDefaultMaxLimit; fi; - # handle free and trivial group + # handle trivial free group if 0 = Length( FreeGeneratorsOfFpGroup( G )) then p:=GroupHomomorphismByImagesNC(G,GroupByGenerators([],()),[],[]); SetIsomorphismPermGroup(G,p); @@ -4056,12 +4056,16 @@ local mappow, G, max, p, gens, rels, comb, i, l, m, H, HH, t, sz, fi; SetSize(G,sz); fi; - if Size(G)=infinity then + sz:= Size(G); + if sz = infinity then return fail; + elif sz = 1 then + # handle trivial group + p:= GroupHomomorphismByImagesNC( G, GroupByGenerators( [], () ), [], [] ); + SetIsomorphismPermGroup( G, p ); + return p; fi; - sz:=Size(G); - if sz*10>max then max:=sz*10; fi; diff --git a/tst/testinstall/grpfp.tst b/tst/testinstall/grpfp.tst index efa64f1bbe..247402f216 100644 --- a/tst/testinstall/grpfp.tst +++ b/tst/testinstall/grpfp.tst @@ -1,4 +1,4 @@ -#@local a,b,c2,e,f,g,iter,l,s,F,rels,sub,iso,G,hom,m +#@local a,b,c2,e,f,g,iter,l,s,F,rels,sub,iso,G,hom,m,H gap> START_TEST("grpfp.tst"); gap> f:= FreeGroup( "a", "b" );; a := f.1;; b := f.2;; gap> c2:= f / [ a*b*a^-2*b*a/b, (b^-1*a^3*b^-1*a^-3)^2*a ];; @@ -177,5 +177,14 @@ gap> ReducedForm(F,UnderlyingElement( > Product(GeneratorsOfMonoid(m){[1,3..19]}))); b2*b4*w1*b1*b6*b8*b9 +# +gap> F:= FreeGroup( 1 );; +gap> G:= F / [ F.1 ];; +gap> H:= Subgroup( G, [ G.1 ] );; +gap> IsomorphismPermGroup( G ) <> fail; +true +gap> IsomorphismPermGroup( H ) <> fail; +true + # gap> STOP_TEST( "grpfp.tst" ); From 195fcca87383753994eb05f398ddffb1d871622f Mon Sep 17 00:00:00 2001 From: Max Horn Date: Fri, 12 Dec 2025 16:29:16 +0100 Subject: [PATCH 059/234] Don't reject paths containing a colon or backslash (#6175) --- lib/files.gi | 7 ------- 1 file changed, 7 deletions(-) diff --git a/lib/files.gi b/lib/files.gi index abcfde1f7f..f9c3dfd1f8 100644 --- a/lib/files.gi +++ b/lib/files.gi @@ -45,13 +45,6 @@ InstallMethod( Directory, [ IsString ], function( str ) str := UserHomeExpand(str); - # - # ':' or '\\' probably are untranslated MS-DOS or MacOS path - # separators, but ':' in position 2 may be OK - # - if '\\' in str or (':' in str and str[2] <> ':') then - Error( " must not contain '\\' or ':'" ); - fi; if Length( str ) > 0 and Last(str) = '/' then str := Immutable(str); else From e12781ec96f90f4725e9587054d501a7b7e27ee8 Mon Sep 17 00:00:00 2001 From: Thomas Breuer Date: Fri, 12 Dec 2025 16:31:30 +0100 Subject: [PATCH 060/234] allow running tests without GAPDoc loaded (#6172) --- lib/test.gi | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/test.gi b/lib/test.gi index 2e79a715a2..3bd9427a3a 100644 --- a/lib/test.gi +++ b/lib/test.gi @@ -600,7 +600,8 @@ end); DeclareGlobalName("TextAttr"); # from GAPDoc DeclareGlobalName("DefaultReportDiffColors"); # initialized in Test() or by the user BindGlobal("DefaultReportDiff", function(inp, expout, found, fnam, line, time) - if UserPreference("UseColorsInTerminal") = true then + if UserPreference("UseColorsInTerminal") = true + and IsBound( GAPInfo.PackagesLoaded.gapdoc ) then Print(DefaultReportDiffColors.message); Print("########> Diff in "); if IsStream(fnam) then @@ -646,7 +647,8 @@ InstallGlobalFunction("Test", function(arg) else nopts := rec(); fi; - if not IsBound(DefaultReportDiffColors) then + if not IsBound(DefaultReportDiffColors) + and IsBound( GAPInfo.PackagesLoaded.gapdoc ) then BindGlobal("DefaultReportDiffColors", rec( message := TextAttr.4, # blue text input := "", From d7717464a2e40d9b1220b304e53c2267f5ccc4d2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 15 Dec 2025 14:24:23 +0100 Subject: [PATCH 061/234] build(deps): bump actions/upload-artifact from 5 to 6 (#6177) Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 5 to 6. - [Release notes](https://github.com/actions/upload-artifact/releases) - [Commits](https://github.com/actions/upload-artifact/compare/v5...v6) --- updated-dependencies: - dependency-name: actions/upload-artifact dependency-version: '6' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/CI.yml | 4 ++-- .github/workflows/release.yml | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index c25a23b30e..170c80a564 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -254,7 +254,7 @@ jobs: run: ${{ matrix.extra }} dev/ci.sh ${{ matrix.test-suites }} - name: "Upload pdf manuals" if: ${{ contains(matrix.test-suites, 'makemanuals') }} - uses: actions/upload-artifact@v5 + uses: actions/upload-artifact@v6 with: if-no-files-found: error name: manuals-pdf @@ -265,7 +265,7 @@ jobs: doc/tut/manual.pdf - name: "Upload html manuals" if: ${{ contains(matrix.test-suites, 'makemanuals') }} - uses: actions/upload-artifact@v5 + uses: actions/upload-artifact@v6 with: if-no-files-found: error name: manuals-html diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index d154d96403..956812feb1 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -152,7 +152,7 @@ jobs: # # Warning: the result is a single .zip file (so things are compressed twice). - name: "Upload GAP tarball" - uses: actions/upload-artifact@v5 + uses: actions/upload-artifact@v6 with: if-no-files-found: error name: gap @@ -161,7 +161,7 @@ jobs: # Always upload metadata, and keep longer, since it is much smaller. - name: "Upload JSON metadata" - uses: actions/upload-artifact@v5 + uses: actions/upload-artifact@v6 with: if-no-files-found: error name: "JSON metadata" @@ -239,7 +239,7 @@ jobs: # Artifacts live for 1 day, i.e. until the next cron job runs. - name: "Upload the installer as an artifact" if: ${{ github.event_name == 'schedule' }} - uses: actions/upload-artifact@v5 + uses: actions/upload-artifact@v6 with: if-no-files-found: error name: gap-${{ env.GAP_VERSION }}-x86_64.exe From 821ee786c6bcbc7f7abe279a3a52440c6be9824e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 15 Dec 2025 14:24:29 +0100 Subject: [PATCH 062/234] build(deps): bump actions/download-artifact from 6 to 7 (#6176) Bumps [actions/download-artifact](https://github.com/actions/download-artifact) from 6 to 7. - [Release notes](https://github.com/actions/download-artifact/releases) - [Commits](https://github.com/actions/download-artifact/compare/v6...v7) --- updated-dependencies: - dependency-name: actions/download-artifact dependency-version: '7' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 956812feb1..33cfea1350 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -196,7 +196,7 @@ jobs: # Download the artifact -- for an actual release, this contains the # exact same tarball as was uploaded to the release as an asset - name: "Download GAP archive from previous job" - uses: actions/download-artifact@v6 + uses: actions/download-artifact@v7 with: name: gap From a872b58b709fca34c662f7e8be5d0672c6534c90 Mon Sep 17 00:00:00 2001 From: Torben Wiedemann <7226617+TWiedemann@users.noreply.github.com> Date: Mon, 15 Dec 2025 14:28:54 +0100 Subject: [PATCH 063/234] Improve documentation of `InverseGeneralMapping` (#6171) --- doc/ref/mapping.xml | 2 +- lib/mapping.gd | 10 ++++------ 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/doc/ref/mapping.xml b/doc/ref/mapping.xml index 16f8aa4cce..cd94676317 100644 --- a/doc/ref/mapping.xml +++ b/doc/ref/mapping.xml @@ -30,7 +30,7 @@ called differently, see Section .

Some technical details of general mappings are described in -section . +section . diff --git a/lib/mapping.gd b/lib/mapping.gd index 08c3134061..bf3a5a2af6 100644 --- a/lib/mapping.gd +++ b/lib/mapping.gd @@ -682,15 +682,13 @@ DeclareAttribute( "IdentityMapping", IsCollection ); ## if and only if the underlying relation of map contains the pair ## (s,r). ##

-## See the introduction to Chapter  -## for the subtleties concerning the difference between -## and . -##

## Note that the inverse general mapping of a mapping map is ## in general only a general mapping. -## If map knows to be bijective its inverse general mapping will know +## If map knows to be bijective, then its inverse general mapping will know ## to be a mapping. -## In this case also Inverse( map ) works. +## However, works for a bijective general mapping map +## only if the source and range of map coincide. +## This behaviour agrees with the definition of Inverse. ## ## ## <#/GAPDoc> From cbf1890dc8174127be12c3ad41377c6468e43809 Mon Sep 17 00:00:00 2001 From: Thomas Breuer Date: Thu, 18 Dec 2025 11:46:55 +0100 Subject: [PATCH 064/234] provide `DefaultRingByGenerators` for alg. extensions (#6179) In fact I want to get a meaningful `BaseDomain` for vectors and matrices over alg. extensions. And I want this first of all for vectors and matrices over the fields provided by the StandardFF package, because this is useful for matrix groups over these fields. --- lib/algfld.gi | 8 ++++++++ tst/testinstall/vecmat.tst | 4 ++++ 2 files changed, 12 insertions(+) diff --git a/lib/algfld.gi b/lib/algfld.gi index 5fec15f954..7fdfff49ea 100644 --- a/lib/algfld.gi +++ b/lib/algfld.gi @@ -1038,6 +1038,14 @@ local fam; TryNextMethod(); end); +############################################################################# +## +#M DefaultRingByGenerators( ) +## +InstallMethod( DefaultRingByGenerators, + [ "IsList and IsAlgebraicElementCollection" ], + DefaultFieldByGenerators ); + ############################################################################# ## #M DefaultFieldOfMatrixGroup( ) diff --git a/tst/testinstall/vecmat.tst b/tst/testinstall/vecmat.tst index 6b14d3f35c..29dab26f80 100644 --- a/tst/testinstall/vecmat.tst +++ b/tst/testinstall/vecmat.tst @@ -73,6 +73,8 @@ false # zero vector over GF(9) but not in internal format gap> F := F9;; v := ListWithIdenticalEntries( 3, Zero(F) ); [ !0*Z(3), !0*Z(3), !0*Z(3) ] +gap> IsIdenticalObj( BaseDomain( v ), F ); +true gap> w := ImmutableVector( 9, v ); [ !0*Z(3), !0*Z(3), !0*Z(3) ] gap> v = w; @@ -199,6 +201,8 @@ false gap> F := F9;; m := IdentityMat( 3, F ); [ [ !Z(3)^0, !0*Z(3), !0*Z(3) ], [ !0*Z(3), !Z(3)^0, !0*Z(3) ], [ !0*Z(3), !0*Z(3), !Z(3)^0 ] ] +gap> IsIdenticalObj( BaseDomain( m ), F ); +true gap> w := ImmutableMatrix( 9, m ); [ [ !Z(3)^0, !0*Z(3), !0*Z(3) ], [ !0*Z(3), !Z(3)^0, !0*Z(3) ], [ !0*Z(3), !0*Z(3), !Z(3)^0 ] ] From f87da47307f7c273f9ab7eac15de4885ebc8f17f Mon Sep 17 00:00:00 2001 From: Max Horn Date: Mon, 29 Dec 2025 19:14:43 +0100 Subject: [PATCH 065/234] Miscellaneous tweaks (#6185) --- grp/classic.gi | 4 ++-- lib/polyfinf.gi | 8 ++++---- lib/test.gi | 3 ++- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/grp/classic.gi b/grp/classic.gi index 5e772cd32e..1298a58a50 100644 --- a/grp/classic.gi +++ b/grp/classic.gi @@ -150,7 +150,7 @@ InstallMethod( GeneralUnitaryGroupCons, # We use the isomorphism of 'SU(2,q)' and 'SL(2,q)': # 'e' is mapped to '-e' under the Frobenius mapping. - e:= Z(q^2) - Z(q^2)^q; + e:= z - z^q; if q = 2 then mat1[1,1]:= z; mat1[2,2]:= z; @@ -255,7 +255,7 @@ InstallMethod( SpecialUnitaryGroupCons, # We use the isomorphism of 'SU(2,q)' and 'SL(2,q)': # 'e' is mapped to '-e' under the Frobenius mapping. - e:= Z(q^2) - Z(q^2)^q; + e:= z - z^q; if q <= 3 then mat1[1,2]:= e; mat2[1,2]:= e; diff --git a/lib/polyfinf.gi b/lib/polyfinf.gi index dfb8dc0716..99370cfd63 100644 --- a/lib/polyfinf.gi +++ b/lib/polyfinf.gi @@ -755,7 +755,7 @@ local v, R, U, x, O, n, g, q, o, bas; if Length(g[3])=0 and Length(g[4])>0 then # in this case `FFPOrderKnownDividend' might run in an infinite # recursion. - Error("cannot compute order due to limits in the integer factorization!"); + Error("cannot compute order due to limits in the integer factorization!"); fi; #o := FFPOrderKnownDividend(R,EuclideanRemainder(R,x,g[1]),g[1],g[3]); bas:=QuotRemLaurpols(x,g[1],2); @@ -763,9 +763,9 @@ local v, R, U, x, O, n, g, q, o, bas; if Length(g[4])>0 then q:=DegreeOfLaurentPolynomial(PowerMod(bas,o[1],g[1])); if not(q=0 or q=DEGREE_ZERO_LAURPOL) then - # in fact x^o[1] is not congruent to a constant -- we really need the - # primes. - Error("cannot compute order due to limits in the integer factorization!"); + # in fact x^o[1] is not congruent to a constant -- we really need the + # primes. + Error("cannot compute order due to limits in the integer factorization!"); fi; fi; q := Characteristic(CoefficientsRing(R))^g[2]; diff --git a/lib/test.gi b/lib/test.gi index 3bd9427a3a..dca2387589 100644 --- a/lib/test.gi +++ b/lib/test.gi @@ -633,7 +633,8 @@ BindGlobal("DefaultReportDiff", function(inp, expout, found, fnam, line, time) Print("# Input is:\n", inp); Print("# Expected output:\n", expout); Print("# But found:\n", found); - Print("########\n"); fi; + Print("########\n"); + fi; end); InstallGlobalFunction("Test", function(arg) From 249bf2b65df1a0dfb01e96153c20cabd56be5811 Mon Sep 17 00:00:00 2001 From: Thomas Breuer Date: Fri, 9 Jan 2026 18:22:37 +0100 Subject: [PATCH 066/234] transfer changes `lib/vecmat.gi` -> `hpcgap/lib/vecmat.gi` (#6187) --- hpcgap/lib/vecmat.gi | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/hpcgap/lib/vecmat.gi b/hpcgap/lib/vecmat.gi index e732be8ed7..1a07cda9ff 100644 --- a/hpcgap/lib/vecmat.gi +++ b/hpcgap/lib/vecmat.gi @@ -655,6 +655,24 @@ InstallOtherMethod( UNB_LIST, end); +############################################################################# +## +#M SwapMatrixRows( , , ) . . . swap rows of GF2 matrix +## +InstallMethod( SwapMatrixRows, "for a mutable GF2 matrix, and two row numbers", + [ IsList and IsGF2MatrixRep and IsMutable, IsPosInt, IsPosInt ], + SWAP_ROWS_GF2MAT ); + + +############################################################################# +## +#M SwapMatrixColumns( , , ) . . swap cols of GF2 matrix +## +InstallMethod( SwapMatrixColumns, "for a mutable GF2 matrix, and two column numbers", + [ IsList and IsGF2MatrixRep and IsMutable, IsPosInt, IsPosInt ], + SWAP_COLS_GF2MAT ); + + ############################################################################# ## #M PrintObj( ) . . . . . . . . . . . . . . . . print a GF2 matrix @@ -2144,7 +2162,8 @@ InstallMethod(DomainForAction,"matrix/matrix",IsElmsCollsX, function(pnt,acts,act) local l,f; if (not ForAll(acts,IsMatrix)) or - (act<>OnPoints and act<>OnSubspacesByCanonicalBasis and act<>OnRight) then + (act<>OnPoints and act<>OnSubspacesByCanonicalBasis and act<>OnRight and act<>OnSets and + act<>OnTuples) then TryNextMethod(); # strange operation, might extend the domain fi; l:=NaturalActedSpace(acts,pnt); From 22ba2c8bc030cc52a22ce8968b8389c3ea0fbc23 Mon Sep 17 00:00:00 2001 From: Max Horn Date: Fri, 9 Jan 2026 23:41:27 +0100 Subject: [PATCH 067/234] Sync more changes with HPC-GAP (#6189) --- hpcgap/lib/ffeconway.gi | 3 ++- hpcgap/lib/polyconw.gi | 2 +- hpcgap/lib/rwspcgrp.gi | 4 ++-- hpcgap/lib/variable.g | 12 +++++++++--- 4 files changed, 14 insertions(+), 7 deletions(-) diff --git a/hpcgap/lib/ffeconway.gi b/hpcgap/lib/ffeconway.gi index 20334a5085..ff9d82145e 100644 --- a/hpcgap/lib/ffeconway.gi +++ b/hpcgap/lib/ffeconway.gi @@ -1196,7 +1196,7 @@ end); ############################################################################# ## -#M LogFFE( , ) +#M LogFFE ## InstallMethod( LogFFE, @@ -1214,6 +1214,7 @@ InstallMethod( LogFFE, [ IsFFE and IsCoeffsModConwayPolRep, IsFFE and IsInternalRep], DoDLog ); + ############################################################################# ## #M LargeGaloisField(p,d) -- construct GFs in this size range diff --git a/hpcgap/lib/polyconw.gi b/hpcgap/lib/polyconw.gi index ee30119b3b..dad0a4a2f3 100644 --- a/hpcgap/lib/polyconw.gi +++ b/hpcgap/lib/polyconw.gi @@ -133,7 +133,7 @@ end); ## str := ""; ## get := OutputTextString(str, false); ## comm := "wget -q ftp://ftp.comlab.ox.ac.uk/pub/Documents/techpapers/Richard.Brent/factors/factors.gz -O - | gzip -dc "; -## Process(DirectoryCurrent(), Filename(DirectoriesSystemPrograms(),"sh"), +## Process(DirectoryCurrent(), PathSystemProgram("sh"), ## InputTextUser(), get, ["-c", comm]); ## res := [[],[]]; ## n := 0; diff --git a/hpcgap/lib/rwspcgrp.gi b/hpcgap/lib/rwspcgrp.gi index 55577528fe..e05aeebafc 100644 --- a/hpcgap/lib/rwspcgrp.gi +++ b/hpcgap/lib/rwspcgrp.gi @@ -878,7 +878,7 @@ InstallMethod( \<, ## #F SingleCollector_GroupRelators( ... ) ## -SingleCollector_GroupRelators := function( +BindGlobal( "SingleCollector_GroupRelators", function( efam, gens, rods, powersp, powersn, commpp, commpn, commnp, commnn, conjpp, conjpn, conjnp, conjnn, conflicts ) @@ -940,7 +940,7 @@ SingleCollector_GroupRelators := function( # return the rewriting system return col; -end; +end ); ############################################################################# ## diff --git a/hpcgap/lib/variable.g b/hpcgap/lib/variable.g index 53e9f8fa79..02fc5ee836 100644 --- a/hpcgap/lib/variable.g +++ b/hpcgap/lib/variable.g @@ -126,6 +126,8 @@ end ); ## does not work if value is an ## immediate object, i.e., an internally represented small integer or ## finite field element. It also fails for booleans. +## In addition, the use of any other type of value except for a list +## or record is deprecated. ## Furthermore, works only if ## value is a list or a record. ## (Note that makes sense only for @@ -157,14 +159,18 @@ BIND_GLOBAL( "InstallValue", function ( gvar, value ) IsToBeDefinedObj( gvar ) then Error("InstallValue: a value has been installed already"); fi; + if TNUM_OBJ(value) in UNCLONEABLE_TNUMS then + Error("InstallValue: cannot be immediate, boolean or character, ", + "and it should rather be a record or a list"); + fi; + if not IS_REC(value) and not IS_PLIST_REP(value) and not IS_STRING_REP(value) then + Print("WARNING, InstallValue: should be a record or list while reading ", INPUT_FILENAME(), ":", INPUT_LINENUMBER(), "\n"); + fi; if IsFamily( value ) then INFO_DEBUG( 1, "please use `BindGlobal' for the family object ", value!.NAME, ", not `InstallValue'" ); fi; - if TNUM_OBJ(value) in UNCLONEABLE_TNUMS then - Error("InstallValue: cannot be immediate, boolean or character"); - fi; if IsPublic(value) then # TODO: We need to handle those cases more cleanly. if IS_ATOMIC_RECORD(value) then From 7344294f5b8701547a6f3a819a92ba5b33942d9f Mon Sep 17 00:00:00 2001 From: Thomas Breuer Date: Mon, 12 Jan 2026 17:32:22 +0100 Subject: [PATCH 068/234] add `DefaultFieldOfMatrix` for `IsAlgebraicElementCollColl` (#6182) --- lib/matrix.gi | 17 +++++++++++++++++ tst/testinstall/vecmat.tst | 4 ++++ 2 files changed, 21 insertions(+) diff --git a/lib/matrix.gi b/lib/matrix.gi index ecfc9b6164..eefddce0b8 100644 --- a/lib/matrix.gi +++ b/lib/matrix.gi @@ -1253,6 +1253,23 @@ function( mat ) end ); +############################################################################# +## +#M DefaultFieldOfMatrix( ) +## +InstallMethod( DefaultFieldOfMatrix, + [ "IsMatrix and IsAlgebraicElementCollColl" ], +function( mat ) + local fam; + + fam:= ElementsFamily( ElementsFamily( FamilyObj( mat) ) ); + if not IsBound( fam!.wholeExtension ) then + TryNextMethod(); + fi; + return fam!.wholeExtension; +end ); + + ############################################################################# ## #M BaseDomain( ) diff --git a/tst/testinstall/vecmat.tst b/tst/testinstall/vecmat.tst index 29dab26f80..cb75254d14 100644 --- a/tst/testinstall/vecmat.tst +++ b/tst/testinstall/vecmat.tst @@ -224,6 +224,10 @@ gap> m = w; true gap> IsMutable(w); false +gap> DefaultFieldOfMatrix( m ) = F; +true +gap> CharacteristicPolynomial( m ); +x_1^3-!Z(3)^0 # identity matrix over a ring with zero divisors gap> F := Integers mod 6;; m := IdentityMat( 3, F ); From c54c7392a388729269b06a70deec7532177f13cb Mon Sep 17 00:00:00 2001 From: Thomas Breuer Date: Mon, 12 Jan 2026 17:33:13 +0100 Subject: [PATCH 069/234] fix `ImmutableMatrix` for `IsMatrixObj` (#6186) According to the documentation, `ImmutableMatrix` does the same as `ChangedBaseDomain` if the 2nd argument is in `IsMatrixObj`. This was not the case up to now. (And we are allowed to call `MakeImmutable` instead of `Immutable` if the 3rd argument is `true`.) --- hpcgap/lib/vecmat.gi | 8 ++++++-- lib/vecmat.gi | 8 ++++++-- tst/testinstall/vecmat.tst | 16 ++++++++++++++++ 3 files changed, 28 insertions(+), 4 deletions(-) diff --git a/hpcgap/lib/vecmat.gi b/hpcgap/lib/vecmat.gi index 1a07cda9ff..d73d04c554 100644 --- a/hpcgap/lib/vecmat.gi +++ b/hpcgap/lib/vecmat.gi @@ -1584,9 +1584,13 @@ local sf, rep, ind, ind2, row, i,big,l,nr; if IsMatrixObj(matrix) then # result is a matrix object iff 'matrix' is if field=BaseDomain(matrix) then - return Immutable(matrix); + if change then + return MakeImmutable(matrix); + else + return Immutable(matrix); + fi; else - return ImmutableMatrix(field,Unpack(matrix)); + return MakeImmutable(ChangedBaseDomain(matrix, field)); fi; elif not (IsPlistRep(matrix) or IsGF2MatrixRep(matrix) or Is8BitMatrixRep(matrix)) then diff --git a/lib/vecmat.gi b/lib/vecmat.gi index bf6142ede5..03658bd0d1 100644 --- a/lib/vecmat.gi +++ b/lib/vecmat.gi @@ -1581,9 +1581,13 @@ local sf, rep, ind, ind2, row, i,big,l,nr; if IsMatrixObj(matrix) then # result is a matrix object iff 'matrix' is if field=BaseDomain(matrix) then - return Immutable(matrix); + if change then + return MakeImmutable(matrix); + else + return Immutable(matrix); + fi; else - return ImmutableMatrix(field,Unpack(matrix)); + return MakeImmutable(ChangedBaseDomain(matrix, field)); fi; elif not (IsPlistRep(matrix) or IsGF2MatrixRep(matrix) or Is8BitMatrixRep(matrix)) then diff --git a/tst/testinstall/vecmat.tst b/tst/testinstall/vecmat.tst index cb75254d14..5d3d194d41 100644 --- a/tst/testinstall/vecmat.tst +++ b/tst/testinstall/vecmat.tst @@ -249,6 +249,22 @@ gap> w := ImmutableMatrix( F, m, true );; gap> IsMutable(w); false +# matrix object +gap> m:= Matrix( IsPlistMatrixRep, GF(2), [ [ Z(2) ] ] ); +<1x1-matrix over GF(2)> +gap> w:= ImmutableMatrix( GF(4), m ); + +gap> IsMutable( w ); +false +gap> IsMatrixObj( w ); +true +gap> w:= ImmutableMatrix( GF(2), m, true ); + +gap> IsMutable( w ); +false +gap> IsIdenticalObj( m, w ); +true + # empty matrix gap> m := ImmutableMatrix( Rationals, [] ); [ ] From d4522075c279892da920132c0722fb3335a9369c Mon Sep 17 00:00:00 2001 From: Thomas Breuer Date: Tue, 13 Jan 2026 20:23:10 +0100 Subject: [PATCH 070/234] GAP banner: split `ShowPackageInformation` into two functions (#6193) The function `ShowPackageInformation` prints part of the GAP banner. Up to now, it prints an overview of the loaded packages and then a line about GAP's interactive help system. The proposed change separates the two parts, the last line is printed by the new function `ShowHelpInformation`. --- lib/init.g | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/init.g b/lib/init.g index cb4932cc05..810305951f 100644 --- a/lib/init.g +++ b/lib/init.g @@ -815,11 +815,13 @@ BindGlobal( "ShowPackageInformation", function() GAPInfo.PackagesLoaded.( name )[2] ) ), "\n" ); fi; +end ); +BindGlobal( "ShowHelpInformation", function() Print( " Try '??help' for help. See also '?copyright', '?cite' and '?authors'", "\n" ); end ); -#T show also root paths? + CallAndInstallPostRestore( function() if not ( GAPInfo.CommandLineOptions.q or @@ -828,12 +830,14 @@ CallAndInstallPostRestore( function() ShowKernelInformation(); fi; ShowPackageInformation(); + ShowHelpInformation(); fi; end ); BindGlobal ("ShowSystemInformation", function () ShowKernelInformation(); ShowPackageInformation(); + ShowHelpInformation(); end ); From b79224e452f843a86dc24c3f9f1fce0d50d09555 Mon Sep 17 00:00:00 2001 From: Yanshu Wang Date: Sat, 10 Jan 2026 18:00:06 +0800 Subject: [PATCH 071/234] modify etc/emscripten/build.sh and web-template to split gap.data so that it can be hosted on github pages --- etc/emscripten/README.md | 3 - etc/emscripten/build.sh | 13 ++++ etc/emscripten/run-web-demo.sh | 2 +- etc/emscripten/web-template/example.worker.js | 7 -- etc/emscripten/web-template/gap-worker.js | 73 +++++++++++++++++++ etc/emscripten/web-template/index.html | 4 +- 6 files changed, 89 insertions(+), 13 deletions(-) delete mode 100755 etc/emscripten/web-template/example.worker.js create mode 100755 etc/emscripten/web-template/gap-worker.js diff --git a/etc/emscripten/README.md b/etc/emscripten/README.md index 1d76bec949..29517d16f7 100644 --- a/etc/emscripten/README.md +++ b/etc/emscripten/README.md @@ -4,9 +4,6 @@ Files: - `build.sh`: Run as `etc/emscripten/build.sh` from a fresh copy of GAP. -Note that this built copy has one major weakness -- the 'gap.data' (which includes all packages files) is huge. - - - `web-template`: Uses 'xterm-pty' to create a "nice" interface to the Wasm GAP. See 'run-web-demo.sh' as an example on how to set up a working website. diff --git a/etc/emscripten/build.sh b/etc/emscripten/build.sh index b2c9b1f330..31bd41f420 100755 --- a/etc/emscripten/build.sh +++ b/etc/emscripten/build.sh @@ -91,3 +91,16 @@ cp native-build/build/c_*.c native-build/build/ffdata.* src/ # The EXEEXT is usually for windows, but here it lets us set GAP's extension, # which lets us produce a html page to run GAP in emmake make -j8 LDFLAGS="--preload-file pkg --preload-file lib --preload-file grp --preload-file tst -s ASYNCIFY=1 -sTOTAL_STACK=32mb -sASYNCIFY_STACK_SIZE=32000000 -sINITIAL_MEMORY=2048mb -O2" EXEEXT=".html" + +# SPLIT THE DATA FILE +echo "Splitting gap.data..." +split -b 75m gap.data "gap.data.part" + +# Rename to .part1, .part2... +i=1 +for f in gap.data.part*; do + mv "$f" "gap.data.part$i" + echo "Created gap.data.part$i" + ((i++)) +done +rm gap.data diff --git a/etc/emscripten/run-web-demo.sh b/etc/emscripten/run-web-demo.sh index 210d639750..c5e52107ff 100755 --- a/etc/emscripten/run-web-demo.sh +++ b/etc/emscripten/run-web-demo.sh @@ -6,6 +6,6 @@ echo This script assumes you have already run 'build.sh' mkdir -p web-example cp etc/emscripten/web-template/* web-example -cp gap.js gap.wasm gap.data web-example +cp gap.js gap.wasm gap.data.part* web-example cd web-example ../etc/emscripten/server.rb diff --git a/etc/emscripten/web-template/example.worker.js b/etc/emscripten/web-template/example.worker.js deleted file mode 100755 index 11608c64ec..0000000000 --- a/etc/emscripten/web-template/example.worker.js +++ /dev/null @@ -1,7 +0,0 @@ -importScripts("https://cdn.jsdelivr.net/npm/xterm-pty@0.9.4/workerTools.js"); - -onmessage = (msg) => { - importScripts(location.origin + "/gap.js"); - - emscriptenHack(new TtyClient(msg.data)); -}; diff --git a/etc/emscripten/web-template/gap-worker.js b/etc/emscripten/web-template/gap-worker.js new file mode 100755 index 0000000000..45b33a8f5a --- /dev/null +++ b/etc/emscripten/web-template/gap-worker.js @@ -0,0 +1,73 @@ +importScripts("https://cdn.jsdelivr.net/npm/xterm-pty@0.9.4/workerTools.js"); + +onmessage = (msg) => { + // We wrap the initialization in an async function to handle the data fetching + async function loadAndStart() { + const buffers = []; + let i = 1; + + // 1. Download all split parts + // It will look for gap.data.part1, part2, etc. until it hits a 404. + while (true) { + const url = location.origin + `/gap.data.part${i}`; + try { + const response = await fetch(url); + if (!response.ok) break; // Stop when we hit 404 + + const buf = await response.arrayBuffer(); + buffers.push(new Uint8Array(buf)); + i++; + } catch (e) { + break; + } + } + + // 2. Prepare the Module object BEFORE importing gap.js + self.Module = self.Module || {}; + + // 2a. MERGE DATA (If parts were found) + if (buffers.length > 0) { + const totalLength = buffers.reduce((acc, b) => acc + b.length, 0); + const mergedData = new Uint8Array(totalLength); + let offset = 0; + for (const buffer of buffers) { + mergedData.set(buffer, offset); + offset += buffer.length; + } + + console.log(`Worker: Loaded ${buffers.length} parts. Total size: ${totalLength} bytes.`); + + // CRITICAL FIX: Override the default downloader. + // When gap.js asks for 'gap.data', we give it our merged array immediately. + // This stops it from trying to fetch 'gap.data' via XHR (which causes the 404). + self.Module.getPreloadedPackage = function(remotePackageName, remotePackageSize) { + if (remotePackageName === 'gap.data') { + return mergedData.buffer; + } + return null; // Let other files download normally if any + }; + + // Just in case: also write it to FS in preRun (redundancy doesn't hurt) + self.Module.preRun = self.Module.preRun || []; + self.Module.preRun.push(() => { + try { + // Create the path just in case + FS.writeFile('/gap.data', mergedData); + } catch(e) { /* ignore if already handled by getPreloadedPackage */ } + }); + } else { + console.warn("Worker: No gap.data parts found. The standard downloader will likely fail with 404."); + } + + // 3. Load GAP + // Now that Module.getPreloadedPackage is defined, gap.js will use it. + importScripts(location.origin + "/gap.js"); + + // 4. Connect xterm-pty + // We pass the TtyClient to the Emscripten TTY interface + emscriptenHack(new TtyClient(msg.data)); + } + + // Start the async process + loadAndStart(); +}; \ No newline at end of file diff --git a/etc/emscripten/web-template/index.html b/etc/emscripten/web-template/index.html index fe23937c26..bc5ede88ed 100755 --- a/etc/emscripten/web-template/index.html +++ b/etc/emscripten/web-template/index.html @@ -1,6 +1,6 @@ - demo + gap-wasm @@ -14,7 +14,7 @@ const { master, slave } = openpty(); xterm.loadAddon(master); - const worker = new Worker("./example.worker.js"); + const worker = new Worker("/gap-worker.js"); new TtyServer(slave).start(worker); From 4aae57e5e045c3f2f37b261b1809af34388de8c9 Mon Sep 17 00:00:00 2001 From: wangyanshu <155622798+wangyenshu@users.noreply.github.com> Date: Sat, 10 Jan 2026 18:13:39 +0800 Subject: [PATCH 072/234] remove redundant remarks --- etc/emscripten/web-template/gap-worker.js | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/etc/emscripten/web-template/gap-worker.js b/etc/emscripten/web-template/gap-worker.js index 45b33a8f5a..8fb35b7856 100755 --- a/etc/emscripten/web-template/gap-worker.js +++ b/etc/emscripten/web-template/gap-worker.js @@ -6,7 +6,7 @@ onmessage = (msg) => { const buffers = []; let i = 1; - // 1. Download all split parts + // Download all split parts // It will look for gap.data.part1, part2, etc. until it hits a 404. while (true) { const url = location.origin + `/gap.data.part${i}`; @@ -22,10 +22,10 @@ onmessage = (msg) => { } } - // 2. Prepare the Module object BEFORE importing gap.js + // Prepare the Module object BEFORE importing gap.js self.Module = self.Module || {}; - // 2a. MERGE DATA (If parts were found) + // Merge data. if (buffers.length > 0) { const totalLength = buffers.reduce((acc, b) => acc + b.length, 0); const mergedData = new Uint8Array(totalLength); @@ -37,9 +37,9 @@ onmessage = (msg) => { console.log(`Worker: Loaded ${buffers.length} parts. Total size: ${totalLength} bytes.`); - // CRITICAL FIX: Override the default downloader. + // Override the default downloader. // When gap.js asks for 'gap.data', we give it our merged array immediately. - // This stops it from trying to fetch 'gap.data' via XHR (which causes the 404). + // This stops it from trying to fetch 'gap.data' via XHR. self.Module.getPreloadedPackage = function(remotePackageName, remotePackageSize) { if (remotePackageName === 'gap.data') { return mergedData.buffer; @@ -47,11 +47,11 @@ onmessage = (msg) => { return null; // Let other files download normally if any }; - // Just in case: also write it to FS in preRun (redundancy doesn't hurt) + // Just in case: also write it to FS in preRun. self.Module.preRun = self.Module.preRun || []; self.Module.preRun.push(() => { try { - // Create the path just in case + FS.writeFile('/gap.data', mergedData); } catch(e) { /* ignore if already handled by getPreloadedPackage */ } }); @@ -59,15 +59,11 @@ onmessage = (msg) => { console.warn("Worker: No gap.data parts found. The standard downloader will likely fail with 404."); } - // 3. Load GAP - // Now that Module.getPreloadedPackage is defined, gap.js will use it. + // Load GAP. importScripts(location.origin + "/gap.js"); - // 4. Connect xterm-pty - // We pass the TtyClient to the Emscripten TTY interface emscriptenHack(new TtyClient(msg.data)); } - // Start the async process loadAndStart(); }; \ No newline at end of file From 959ec1c2cad17be4e192aa40cba9f5563223e93c Mon Sep 17 00:00:00 2001 From: wangyanshu <155622798+wangyenshu@users.noreply.github.com> Date: Sat, 10 Jan 2026 18:33:13 +0800 Subject: [PATCH 073/234] fix url path issue --- etc/emscripten/web-template/gap-worker.js | 4 ++-- etc/emscripten/web-template/index.html | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/etc/emscripten/web-template/gap-worker.js b/etc/emscripten/web-template/gap-worker.js index 8fb35b7856..922457b397 100755 --- a/etc/emscripten/web-template/gap-worker.js +++ b/etc/emscripten/web-template/gap-worker.js @@ -9,7 +9,7 @@ onmessage = (msg) => { // Download all split parts // It will look for gap.data.part1, part2, etc. until it hits a 404. while (true) { - const url = location.origin + `/gap.data.part${i}`; + const url = `gap.data.part${i}`; try { const response = await fetch(url); if (!response.ok) break; // Stop when we hit 404 @@ -60,7 +60,7 @@ onmessage = (msg) => { } // Load GAP. - importScripts(location.origin + "/gap.js"); + importScripts("gap.js"); emscriptenHack(new TtyClient(msg.data)); } diff --git a/etc/emscripten/web-template/index.html b/etc/emscripten/web-template/index.html index bc5ede88ed..4451f7c948 100755 --- a/etc/emscripten/web-template/index.html +++ b/etc/emscripten/web-template/index.html @@ -14,7 +14,7 @@ const { master, slave } = openpty(); xterm.loadAddon(master); - const worker = new Worker("/gap-worker.js"); + const worker = new Worker("gap-worker.js"); new TtyServer(slave).start(worker); From 4b742c13779a8e6df394305863621868b1b59d97 Mon Sep 17 00:00:00 2001 From: Max Horn Date: Fri, 16 Jan 2026 13:04:10 +0100 Subject: [PATCH 074/234] Add MakeConjugatorIsomorphismNC (#6194) --- lib/ghom.gi | 54 +++++++++++++++++++++++++++++------------------------ 1 file changed, 30 insertions(+), 24 deletions(-) diff --git a/lib/ghom.gi b/lib/ghom.gi index 4937da9003..c1a5a89674 100644 --- a/lib/ghom.gi +++ b/lib/ghom.gi @@ -976,6 +976,32 @@ local gi,x,p; end); +############################################################################# +## +#M MakeConjugatorIsomorphismNC( , , ) +## +## Assumes H = G^g +BindGlobal( "MakeConjugatorIsomorphismNC", +function( G, H, g ) + local fam, filter, hom; + + if IsIdenticalObj( G, H ) then + filter:= IsConjugatorAutomorphism; + else + filter:= IsConjugatorIsomorphism; + fi; + fam:= ElementsFamily( FamilyObj( G ) ); + hom:= ObjectifyWithAttributes( rec(), + NewType( GeneralMappingsFamily( fam, fam ), + filter + and IsSPGeneralMapping + and IsAttributeStoringRep ), + ConjugatorOfConjugatorIsomorphism, g, + Source, G, + Range, H ); + return hom; +end ); + ############################################################################# ## #M ConjugatorIsomorphism( , ) @@ -985,18 +1011,9 @@ InstallMethod( ConjugatorIsomorphism, IsCollsElms, [ IsGroup, IsMultiplicativeElementWithInverse ], 0, function( G, g ) - local fam, hom; - - fam:= ElementsFamily( FamilyObj( G ) ); - hom:= Objectify( NewType( GeneralMappingsFamily( fam, fam ), - IsConjugatorIsomorphism - and IsSPGeneralMapping - and IsAttributeStoringRep ), - rec() ); - SetConjugatorOfConjugatorIsomorphism( hom, g ); - SetSource( hom, G ); - SetRange( hom, ConjugateGroup( G, g ) ); - return hom; + local H; + H := ConjugateGroup( G, g ); + return MakeConjugatorIsomorphismNC( G, H, g ); end ); @@ -1009,18 +1026,7 @@ InstallMethod( ConjugatorAutomorphismNC, IsCollsElms, [ IsGroup, IsMultiplicativeElementWithInverse ], 0, function( G, g ) - local fam, hom; - - fam:= ElementsFamily( FamilyObj( G ) ); - hom:= Objectify( NewType( GeneralMappingsFamily( fam, fam ), - IsConjugatorAutomorphism - and IsSPGeneralMapping - and IsAttributeStoringRep ), - rec() ); - SetConjugatorOfConjugatorIsomorphism( hom, g ); - SetSource( hom, G ); - SetRange( hom, G ); - return hom; + return MakeConjugatorIsomorphismNC( G, G, g ); end ); From fee0ba20e7fa7473e5b1ca7b87533cf0a72b835b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lars=20G=C3=B6ttgens?= Date: Fri, 16 Jan 2026 13:07:41 +0100 Subject: [PATCH 075/234] Transfer more properties (such as `IsNaturalSL`, `InvariantQuadraticForm` etc.) when conjugating matrix groups (#6183) --- lib/grpmat.gd | 7 ++- lib/grpmat.gi | 64 +++++++++++++++++++++++++++ tst/testinstall/grp/classic-forms.tst | 20 +++++++++ tst/testinstall/mapping.tst | 2 +- 4 files changed, 90 insertions(+), 3 deletions(-) diff --git a/lib/grpmat.gd b/lib/grpmat.gd index 5ef8db275d..d2c9d0a906 100644 --- a/lib/grpmat.gd +++ b/lib/grpmat.gd @@ -345,7 +345,8 @@ DeclareAttribute( "InvariantBilinearForm", IsMatrixGroup ); ## ## This property tests, whether a matrix group matgrp is the full ## subgroup of GL or SL (the property determines -## which it is) respecting the form stored as the value of +## which it is) in the right dimension over the (smallest) ring which +## contains all entries of its elements, respecting the form stored as the value of ## for matgrp. ## ## @@ -462,7 +463,9 @@ DeclareAttribute( "InvariantQuadraticForm", IsMatrixGroup ); ## ## This property tests, whether the matrix group matgrp is the full ## subgroup of GL or SL (the property determines -## which it is) respecting the value +## which it is) in the right dimension over the (smallest) ring which +## contains all entries of its elements, +## respecting the value ## of matgrp. ## g:= Sp( 2, 3 );; diff --git a/lib/grpmat.gi b/lib/grpmat.gi index 5260a63065..69299d699c 100644 --- a/lib/grpmat.gi +++ b/lib/grpmat.gi @@ -1266,3 +1266,67 @@ InstallMethod( InvariantBilinearForm, Q:= InvariantQuadraticForm( matgrp ).matrix; return rec( matrix:= ( Q + TransposedMat( Q ) ) ); end ); + +############################################################################# +## +#M ConjugateGroup( , ) of a matrix group +## +InstallMethod( ConjugateGroup, ", ", IsCollsElms, + [ IsMatrixGroup, IsMultiplicativeElementWithInverse ], + function( G, g ) + local H, m, ginv, nice, conj; + + H := GroupByGenerators( OnTuples( GeneratorsOfGroup( G ), g ), One( G ) ); + UseIsomorphismRelation( G, H ); + if HasIsGeneralLinearGroup( G ) then + SetIsGeneralLinearGroup( H, IsGeneralLinearGroup( G ) ); + fi; + if HasIsSpecialLinearGroup( G ) then + SetIsSpecialLinearGroup( H, IsSpecialLinearGroup( G ) ); + fi; + if HasIsSubgroupSL( G ) then + SetIsSubgroupSL( H, IsSubgroupSL( G ) ); + fi; + if HasInvariantBilinearForm( G ) then + if not IsBound( ginv ) then + ginv := g^-1; + fi; + m := ginv * InvariantBilinearForm( G ).matrix * TransposedMat( ginv ); + SetInvariantBilinearForm( H, rec( matrix := m ) ); + fi; + if HasInvariantQuadraticForm( G ) then + if not IsBound( ginv ) then + ginv := g^-1; + fi; + m := ginv * InvariantQuadraticForm( G ).matrix * TransposedMat( ginv ); + SetInvariantQuadraticForm( H, rec( matrix := m ) ); + fi; + if IsSubset( FieldOfMatrixGroup( G ), FieldOfMatrixList( [ g ] ) ) then + if HasIsNaturalGL( G ) then + SetIsNaturalGL( H, IsNaturalGL( G ) ); + fi; + if HasIsNaturalSL( G ) then + SetIsNaturalSL( H, IsNaturalSL( G ) ); + fi; + if HasIsFullSubgroupGLorSLRespectingBilinearForm( G ) + and IsFullSubgroupGLorSLRespectingBilinearForm( G ) then + SetIsFullSubgroupGLorSLRespectingBilinearForm( H, true ); + fi; + if HasIsFullSubgroupGLorSLRespectingQuadraticForm( G ) + and IsFullSubgroupGLorSLRespectingQuadraticForm( G ) then + SetIsFullSubgroupGLorSLRespectingQuadraticForm( H, true ); + fi; + fi; + if HasNiceMonomorphism( G ) then + nice := NiceMonomorphism( G ); + if not IsBound( ginv ) then + ginv := g^-1; + fi; + conj := GroupHomomorphismByFunction( H, G, y -> g*y*ginv, x -> ginv*x*g ); + SetNiceMonomorphism( H, conj * nice ); + if HasNiceObject( G ) then + SetNiceObject( H, NiceObject( G ) ); + fi; + fi; + return H; +end ); diff --git a/tst/testinstall/grp/classic-forms.tst b/tst/testinstall/grp/classic-forms.tst index d5e8b696e7..908e0693c4 100644 --- a/tst/testinstall/grp/classic-forms.tst +++ b/tst/testinstall/grp/classic-forms.tst @@ -54,6 +54,8 @@ gap> grps:=[];; gap> for d in [3,5,7] do > for q in [2,3,4,5,7,8,9,16,17,25,27] do > Add(grps, GO(d,q)); +> Add(grps, GO(d,q) ^ RandomInvertibleMat(d,GF(q))); +> Add(grps, GO(d,q) ^ RandomInvertibleMat(d,GF(q^2))); > od; > od; gap> ForAll(grps, CheckGeneratorsInvertible); @@ -71,6 +73,10 @@ gap> for d in [2,4,6,8] do > for q in [2,3,4,5,7,8,9,16,17,25,27] do > Add(grps, GO(+1,d,q)); > Add(grps, GO(-1,d,q)); +> Add(grps, GO(+1,d,q) ^ RandomInvertibleMat(d,GF(q))); +> Add(grps, GO(-1,d,q) ^ RandomInvertibleMat(d,GF(q))); +> Add(grps, GO(+1,d,q) ^ RandomInvertibleMat(d,GF(q^2))); +> Add(grps, GO(-1,d,q) ^ RandomInvertibleMat(d,GF(q^2))); > od; > od; gap> ForAll(grps, CheckGeneratorsInvertible); @@ -87,6 +93,8 @@ gap> grps:=[];; gap> for d in [3,5,7] do > for q in [2,3,4,5,7,8,9,16,17,25,27] do > Add(grps, SO(d,q)); +> Add(grps, SO(d,q) ^ RandomInvertibleMat(d,GF(q))); +> Add(grps, SO(d,q) ^ RandomInvertibleMat(d,GF(q^2))); > od; > od; gap> ForAll(grps, CheckGeneratorsSpecial); @@ -104,6 +112,10 @@ gap> for d in [2,4,6,8] do > for q in [2,3,4,5,7,8,9,16,17,25,27] do > Add(grps, SO(+1,d,q)); > Add(grps, SO(-1,d,q)); +> Add(grps, SO(+1,d,q) ^ RandomInvertibleMat(d,GF(q))); +> Add(grps, SO(-1,d,q) ^ RandomInvertibleMat(d,GF(q))); +> Add(grps, SO(+1,d,q) ^ RandomInvertibleMat(d,GF(q^2))); +> Add(grps, SO(-1,d,q) ^ RandomInvertibleMat(d,GF(q^2))); > od; > od; gap> ForAll(grps, CheckGeneratorsSpecial); @@ -124,6 +136,8 @@ gap> grps:=[];; gap> for d in [3,5,7] do > for q in [2,3,4,5,7,8,9,16,17,25,27] do > Add(grps, Omega(d,q)); +> Add(grps, Omega(d,q) ^ RandomInvertibleMat(d,GF(q))); +> Add(grps, Omega(d,q) ^ RandomInvertibleMat(d,GF(q^2))); > od; > od; gap> ForAll(grps, CheckGeneratorsSpecial); @@ -141,6 +155,10 @@ gap> for d in [2,4,6,8] do > for q in [2,3,4,5,7,8,9,16,17,25,27] do > Add(grps, Omega(+1,d,q)); > Add(grps, Omega(-1,d,q)); +> Add(grps, Omega(+1,d,q) ^ RandomInvertibleMat(d,GF(q))); +> Add(grps, Omega(-1,d,q) ^ RandomInvertibleMat(d,GF(q))); +> Add(grps, Omega(+1,d,q) ^ RandomInvertibleMat(d,GF(q^2))); +> Add(grps, Omega(-1,d,q) ^ RandomInvertibleMat(d,GF(q^2))); > od; > od; gap> ForAll(grps, CheckGeneratorsSpecial); @@ -191,6 +209,8 @@ gap> grps:=[];; gap> for d in [2,4,6,8] do > for q in [2,3,4,5,7,8,9,16,17,25,27] do > Add(grps, Sp(d,q)); +> Add(grps, Sp(d,q) ^ RandomInvertibleMat(d,GF(q))); +> Add(grps, Sp(d,q) ^ RandomInvertibleMat(d,GF(q^2))); > od; > od; gap> ForAll(grps, CheckGeneratorsSpecial); diff --git a/tst/testinstall/mapping.tst b/tst/testinstall/mapping.tst index 66b0d3ef40..e3ac07646f 100644 --- a/tst/testinstall/mapping.tst +++ b/tst/testinstall/mapping.tst @@ -496,7 +496,7 @@ gap> g2:= SubgroupNC( g, [ A, B ] );; # need a parent gap> HasIsHandledByNiceMonomorphism( g2 ); MayBeHandledByNiceMonomorphism( g2 ); false true -gap> g2:= ConjugateGroup( g2, C );; +gap> g2:= ClosureGroup( g2, B );; gap> HasIsHandledByNiceMonomorphism( g2 ); IsHandledByNiceMonomorphism( g2 ); true true From 7c8bb788d741455dc3a12d5ed3ee2b164e6c5d28 Mon Sep 17 00:00:00 2001 From: Thomas Breuer Date: Fri, 16 Jan 2026 13:11:21 +0100 Subject: [PATCH 076/234] Document setter for mutable attributes (#6198) In particular, add an example that shows the differences. (I do not like it at all that setters of mutable attributes replace stored values, but I think it is too late to change this behaviour.) --- doc/ref/types.xml | 28 ++++++++++++++++++++++++++++ lib/oper.g | 7 ++++--- 2 files changed, 32 insertions(+), 3 deletions(-) diff --git a/doc/ref/types.xml b/doc/ref/types.xml index 7783b92f2a..32ffe77b0c 100644 --- a/doc/ref/types.xml +++ b/doc/ref/types.xml @@ -533,6 +533,34 @@ for example, Setter( Size )( obj, val ) sets val as size of the object obj if the size was not yet known.

+Calling the setter an of attribute for an object which stores already +a value for this attribute has no effect, +except if the attribute has been created as a mutable attribute +(see ). +For mutable attributes, each call of the setter +replaces the stored value. +(Usually mutable attributes are used to store a mutable list or record once, +and later add data to this value, and then one should take care not to call +the setter of the attribute again.) +

+ imm_attr:= NewAttribute( "imm_attr", IsGroup );; +gap> mut_attr:= NewAttribute( "mut_attr", IsGroup, "mutable" );; +gap> G:= SymmetricGroup( 4 );; +gap> Setter( imm_attr )( G, 0 ); +gap> imm_attr( G ); +0 +gap> Setter( imm_attr )( G, 1 ); # This call has no effect. +gap> imm_attr( G ); +0 +gap> Setter( mut_attr )( G, 0 ); +gap> mut_attr( G ); +0 +gap> Setter( mut_attr )( G, 1 ); # This call replaces the stored value. +gap> mut_attr( G ); +1 +]]> +

For each attribute attr that is declared with resp. , tester and setter are automatically made accessible by the names diff --git a/lib/oper.g b/lib/oper.g index 92d645aa94..5e72ecefac 100644 --- a/lib/oper.g +++ b/lib/oper.g @@ -1272,9 +1272,10 @@ end ); ## , ## and this list is mutable because one may want to enter groups into it ## as they are computed. -## -## -## +##

+## Mutable and immutable attributes behave differently w. r. t. repeated +## calls of the function that sets the attribute value, +## see . ##

## If no argument for rank is given, then the rank of the tester is 1. ##

From 27737cc14ffdf4a7398a9db0b9985b3d7d0a4bda Mon Sep 17 00:00:00 2001 From: Thomas Breuer Date: Fri, 16 Jan 2026 13:20:46 +0100 Subject: [PATCH 077/234] document objects with memory (#6174) --- doc/ref/debug.xml | 1 + doc/ref/makedocreldata.g | 1 + doc/ref/wordass.xml | 17 ++ lib/memory.gd | 308 +++++++++++++++++++++++++++++- lib/memory.gi | 339 +++++++++++++++------------------ lib/oper.g | 30 ++- tst/testinstall/memory.tst | 120 +++++++++++- tst/teststandard/stabchain.tst | 12 -- 8 files changed, 628 insertions(+), 200 deletions(-) diff --git a/doc/ref/debug.xml b/doc/ref/debug.xml index 4f9882e6f9..66e793c19c 100644 --- a/doc/ref/debug.xml +++ b/doc/ref/debug.xml @@ -73,6 +73,7 @@ afterwards. Inspecting Applicable Methods <#Include Label="ApplicableMethod"> +<#Include Label="MethodsOperation"> diff --git a/doc/ref/makedocreldata.g b/doc/ref/makedocreldata.g index 4da443b05c..2221351de3 100644 --- a/doc/ref/makedocreldata.g +++ b/doc/ref/makedocreldata.g @@ -120,6 +120,7 @@ GAPInfo.ManualDataRef:= rec( "../../lib/matobjplist.gd", "../../lib/matrix.gd", "../../lib/meataxe.gi", + "../../lib/memory.gd", "../../lib/memusage.gd", "../../lib/methsel.g", "../../lib/methsel2.g", diff --git a/doc/ref/wordass.xml b/doc/ref/wordass.xml index ccd0d22108..46ac8f76cd 100644 --- a/doc/ref/wordass.xml +++ b/doc/ref/wordass.xml @@ -154,6 +154,23 @@ free groups usually benefit from using a letter representation. <#Include Label="EvalStraightLineProgElm"> <#Include Label="StretchImportantSLPElement"> + + + + +

+Objects with Memory + +<#Include Label="objwithmemory"> + +<#Include Label="IsObjWithMemory"> +<#Include Label="GeneratorsWithMemory"> +<#Include Label="GroupWithMemory"> +<#Include Label="SLPOfElm"> +<#Include Label="SLPOfElms"> +<#Include Label="StripMemory"> +<#Include Label="MethodsForObjWithMemory"> +
diff --git a/lib/memory.gd b/lib/memory.gd index 366463b03d..f10e54e98e 100644 --- a/lib/memory.gd +++ b/lib/memory.gd @@ -13,20 +13,318 @@ ############################################################################# +############################################################################# +## +## <#GAPDoc Label="objwithmemory"> +## The idea behind objects with memory is as follows. +## One starts with a list of seed objects +## and creates corresponding new objects for them that store how they arise +## from the seed objects (see ). +## Each product, inverse, commutator etc. of the new objects then also +## stores how it was obtained from the seed objects. +## One can use to create a straight line program +## for a given element x such that evaluating this program in the +## seed objects yields x. +##

+## seeds:= [ (1,2,3), (1,2) ];; +## gap> elms:= GeneratorsWithMemory( seeds ); +## [ <(1,2,3) with mem>, <(1,2) with mem> ] +## gap> x:= (elms[1] * elms[2])^-1; +## <(2,3) with mem> +## gap> xslp:= SLPOfElm( x ); +## +## gap> Display( xslp ); +## # input: +## r:= [ g1, g2 ]; +## # program: +## r[3]:= r[1]*r[2]; +## r[4]:= r[3]^-1; +## # return value: +## r[4] +## gap> ResultOfStraightLineProgram( xslp, seeds ); +## (2,3) +## ]]> +##

+## The objects with memory are intended to behave equally to the underlying +## objects without memory, apart from the behaviour concerning the memory +## information. +## In particular, the tests for equality and ordering are delegated to the +## underlying objects. +##

+## seeds = elms; +## true +## gap> ( seeds[1] < seeds[2] ) = ( elms[1] < elms[2] ); +## true +## ]]> +##

+## It may, however, happen that some &GAP; function runs into an error +## when it is called with elements with memory. +## In such cases, probably a method for elements with memory is missing, +## and perhaps some existing methods are installed with too weak +## requirements. +## As a solution, one can then add the missing method, +## or ask &GAP; support for help. +##

+## An overview of the currently supported functionality for objects with +## memory can be computed with , +## this may be helpful for finding code that can be adapted. +## <#/GAPDoc> + + +# This filter is intended to increase the rank of `IsObjWithMemory`. DeclareFilter("IsObjWithMemoryRankFilter",100); + +############################################################################# +## +#F IsObjWithMemory( ) +## +## <#GAPDoc Label="IsObjWithMemory"> +## +## +## +## +## The filter describes objects that can be +## multiplied and store information how they arise from seed objects +## via arithmetic operations. +##

+## seeds:= [ (1,2,3), (1,2) ];; +## gap> elms:= GeneratorsWithMemory( seeds );; +## gap> IsObjWithMemory( elms[1] ); +## true +## gap> IsObjWithMemory( seeds[1] ); +## false +## ]]> +## +## +## <#/GAPDoc> +## DeclareRepresentation("IsObjWithMemory", IsComponentObjectRep and IsObjWithMemoryRankFilter and - IsMultiplicativeElementWithInverse, ["slp","n","el"]); + IsMultiplicativeElementWithInverse); + +############################################################################# +## +#F GeneratorsWithMemory( ) +## +## <#GAPDoc Label="GeneratorsWithMemory"> +## +## +## +## a list of objects with memory +## +## For a list list of multiplicative elements, +## returns a list of corresponding +## objects with memory. +##

+## seeds:= [ (1,2,3), (1,2) ];; +## gap> elms:= GeneratorsWithMemory( seeds ); +## [ <(1,2,3) with mem>, <(1,2) with mem> ] +## gap> seeds = elms; +## true +## gap> ForAll( elms, IsObjWithMemory ); +## true +## ]]> +## +## +## <#/GAPDoc> +## DeclareGlobalFunction( "GeneratorsWithMemory" ); -DeclareOperation( "StripMemory", [IsObject] ); -DeclareOperation( "ForgetMemory", [IsObject] ); -DeclareGlobalFunction( "StripStabChain" ); -DeclareGlobalFunction( "CopyMemory" ); + + +############################################################################# +## +#F GroupWithMemory( ) +#F GroupWithMemory( ) +## +## <#GAPDoc Label="GroupWithMemory"> +## +## GroupWithMemory +## +## +## +## +## Return a group whose value is the +## value of +## GeneratorsOfGroup( G ) or of gens, +## respectively. +##

+## G:= GroupWithMemory( SymmetricGroup( 3 ) ); +## Group([ (1,2,3), (1,2) ]) +## gap> IsObjWithMemory( One( G ) ); +## true +## gap> G:= GroupWithMemory( [ (1,2,3) ] ); +## Group([ (1,2,3) ]) +## gap> IsObjWithMemory( One( G ) ); +## true +## ]]> +## +## +## <#/GAPDoc> +## DeclareGlobalFunction( "GroupWithMemory" ); + + +############################################################################# +## +#F SLPOfElm( ) +## +## <#GAPDoc Label="SLPOfElm"> +## +## +## +## +## For g in the filter , +## return a straight line program that describes g in terms of the +## generators that were used to initialize the memory. +##

+## seeds:= [ (1,2,3), (1,2) ];; +## gap> elms:= GeneratorsWithMemory( seeds ); +## [ <(1,2,3) with mem>, <(1,2) with mem> ] +## gap> g:= (elms[2] * elms[1] * elms[2])^-1; +## <(1,2,3) with mem> +## gap> slp:= SLPOfElm( g ); +## +## gap> g = ResultOfStraightLineProgram( slp, seeds ); +## true +## ]]> +## +## +## <#/GAPDoc> +## DeclareGlobalFunction( "SLPOfElm" ); + + +############################################################################# +## +#F SLPOfElms( ) +## +## <#GAPDoc Label="SLPOfElms"> +## +## +## +## +## For a list list of elements in the filter +## , +## return a straight line program that describes list in terms of the +## generators that were used to initialize the memory. +##

+## seeds:= [ (1,2,3), (1,2) ];; +## gap> elms:= GeneratorsWithMemory( seeds ); +## [ <(1,2,3) with mem>, <(1,2) with mem> ] +## gap> list:= [ elms[2] * elms[1], elms[1] * elms[2] ]; +## [ <(1,3) with mem>, <(2,3) with mem> ] +## gap> slp:= SLPOfElms( list ); +## +## gap> list = ResultOfStraightLineProgram( slp, seeds ); +## true +## ]]> +## +## +## <#/GAPDoc> +## DeclareGlobalFunction( "SLPOfElms" ); + +############################################################################# +## +#F MethodsForObjWithMemory() +## +## <#GAPDoc Label="MethodsForObjWithMemory"> +## +## +## +## +## This function is intended to give an overview of those methods in the +## current &GAP; session for which at least one argument is required to be +## in the filter . +##

+## The return value is a list of records, with the same components as the +## ones returned by . +## In particular, the func component of each record is the method +## itself, and the info component is a string that describes its +## requirements. +##

+## res:= MethodsForObjWithMemory();; +## gap> for r in res{ [ 1 .. 10 ] } do +## > Print( r.info, "\n" ); +## > od; +## ViewObj: [ IsObjWithMemory ] +## =: [ IsObjWithMemory, IsObjWithMemory ] +## =: [ IsMultiplicativeElement, IsObjWithMemory ] +## =: [ IsObjWithMemory, IsMultiplicativeElement ] +## <: [ IsObjWithMemory, IsObjWithMemory ] +## <: [ IsMultiplicativeElement, IsObjWithMemory ] +## <: [ IsObjWithMemory, IsMultiplicativeElement ] +## PrintObj: [ IsObjWithMemory ] +## Length: [ IsMatrix and IsObjWithMemory ] +## Length: [ IsObjWithMemory and IsWord ] +## ]]> +##

+## Note that some functions may provide a special treatment for objects in +## but no arguments of the function are +## objects with memory. +## For example, there is a method for a group +## that checks whether the generators are objects with memory, +## and if yes returns an identity element with memory. +## Such functions do not occur in the output of +## . +## +## +## <#/GAPDoc> +## +DeclareGlobalFunction( "MethodsForObjWithMemory" ); + + +############################################################################# +## +#O StripMemory( ) +## +## <#GAPDoc Label="StripMemory"> +## +## +## +## +## For a list obj, returns a new list +## of the results for the entries of obj. +##

+## If obj is not a list and in the filter +## , returns the +## underlying object without memory. +##

+## Otherwise obj is returned. +##

+## seeds:= [ (1,2,3), (1,2) ];; +## gap> elms:= GeneratorsWithMemory( seeds ); +## [ <(1,2,3) with mem>, <(1,2) with mem> ] +## gap> StripMemory( elms ); +## [ (1,2,3), (1,2) ] +## gap> StripMemory( elms[1] ); +## (1,2,3) +## gap> IsIdenticalObj( seeds[1], StripMemory( seeds[1] ) ); +## true +## ]]> +## +## +## <#/GAPDoc> +## +DeclareOperation( "StripMemory", [ IsObject ] ); + +DeclareOperation( "ForgetMemory", [ IsObject ] ); + +DeclareGlobalFunction( "StripStabChain" ); + +DeclareGlobalFunction( "CopyMemory" ); + DeclareGlobalFunction( "SortFunctionWithMemory" ); diff --git a/lib/memory.gi b/lib/memory.gi index e852f6f8d2..04558f2017 100644 --- a/lib/memory.gi +++ b/lib/memory.gi @@ -12,10 +12,16 @@ ## ############################################################################# + +# low-level construction of an object with memory BindGlobal( "ObjWithMemory", function( slp, n, el ) local filt; filt:= IsObjWithMemory; + + # For permutations, the `IsPerm` filter for the new element + # is inherited from their family. + # This is not the case for matrices, thus we have to work. if IsMatrixOrMatrixObj( el ) then filt:= filt and IsMatrixOrMatrixObj; if IsMatrix( el ) then @@ -33,38 +39,52 @@ BindGlobal( "ObjWithMemory", function( slp, n, el ) rec( slp:= slp, n:= n, el:= el ) ); end ); -InstallGlobalFunction( GeneratorsWithMemory, - function(l) +InstallGlobalFunction( GeneratorsWithMemory, function(l) # l is a list of objects local slp; slp := rec(prog := [],nogens := Length(l)); return List( [ 1 .. Length( l ) ], i -> ObjWithMemory( slp, i, l[i] ) ); end); -InstallMethod( StripMemory, "for an object with memory", - [ IsObjWithMemory ], - function( el ) - return el!.el; - end ); +InstallGlobalFunction( MethodsForObjWithMemory, function() + local flags, methods, op, n; + + flags:= FLAGS_FILTER( IsObjWithMemory ); + methods:= []; + for op in OPERATIONS do + for n in [ 1 .. 6 ] do + Append( methods, + Filtered( MethodsOperation( op, n ), + r -> r.early = false and + ForAny( r.argFilt, fl -> IS_SUBSET_FLAGS( fl, flags ) ) ) ); + od; + od; + return methods; +end ); -InstallMethod( StripMemory, "for a list", - [ IsList ], - function( l ) - return List(l,StripMemory); - end ); +InstallMethod( StripMemory, + [ "IsObjWithMemory" ], + el -> el!.el ); + +InstallMethod( StripMemory, + [ "IsList" ], + l -> List( l, StripMemory ) ); -InstallMethod( StripMemory, "fallback for all objects", - [ IsObject ], - function( ob ) return ob; end ); +InstallMethod( StripMemory, + "fallback for all objects", + [ "IsObject" ], + IdFunc ); -InstallMethod( ForgetMemory, "nice error message for all objects", - [ IsObject ], +InstallMethod( ForgetMemory, + "nice error message for all objects", + [ "IsObject" ], function( ob ) Error( "This object does not allow forgetting memory." ); end ); -InstallMethod( ForgetMemory, "nice error message for memory objects", - [ IsObjWithMemory ], +InstallMethod( ForgetMemory, + "nice error message for memory objects", + [ "IsObjWithMemory" ], function( el ) Error( "You probably mean \"StripMemory\" instead of \"ForgetMemory\"." ); end ); @@ -84,24 +104,10 @@ InstallGlobalFunction( StripStabChain, function(S) # Throws away all memories of elements in the stabchain # Does *not* copy stabchain! - local i,identity; - for i in [1..Length(S.labels)] do - if IsObjWithMemory(S.labels[i]) then - S.labels[i] := S.labels[i]!.el; - fi; - od; - for i in [1..Length(S.generators)] do - if IsObjWithMemory(S.generators[i]) then - S.generators[i] := S.generators[i]!.el; - fi; - od; + ForgetMemory( S.labels ); + ForgetMemory( S.generators ); if IsBound(S.transversal) then - for i in [1..Length(S.transversal)] do - if IsBound(S.transversal[i]) and - IsObjWithMemory(S.transversal[i]) then - S.transversal[i] := S.transversal[i]!.el; - fi; - od; + ForgetMemory( S.transversal ); fi; if IsObjWithMemory(S.identity) then S.identity := S.identity!.el; @@ -146,7 +152,7 @@ InstallGlobalFunction( SLPOfElm, InstallGlobalFunction( SLPOfElms, function(elms) - # Returns a straight line program to write elm as in the original + # Returns a straight line program to write elms as in the original # generators. if ForAny(elms{[2..Length(elms)]}, x -> not IsIdenticalObj(elms[1]!.slp, x!.slp)) then ErrorNoReturn("SLPOfElms: the slp components of all elements must be identical"); @@ -157,8 +163,10 @@ InstallGlobalFunction( SLPOfElms, # Generic methods for group elements with memory: -InstallOtherMethod( One, "partial method for a group (beats to ask family)", - true, [ IsMagmaWithOne and IsGroup ], 101, +InstallMethod( One, + "partial method for a group (beats to ask family)", + # the method for `IsMagmaWithOne` has incremental rank 100 + [ "IsMagmaWithOne and IsGroup" ], 101, function( M ) local gens; gens := GeneratorsOfGroup(M); @@ -169,22 +177,24 @@ InstallOtherMethod( One, "partial method for a group (beats to ask family)", fi; end ); -InstallMethod( ViewObj, "objects with memory", true, [IsObjWithMemory],0, +InstallMethod( ViewObj, + [ "IsObjWithMemory" ], function(o) Print("<"); ViewObj(o!.el); Print(" with mem>"); -end); + end); -InstallMethod( PrintObj, "objects with memory", true, [IsObjWithMemory],0, +InstallMethod( PrintObj, + [ "IsObjWithMemory" ], function(o) Print("<"); PrintObj(o!.el); Print(" with mem>"); -end); + end); -InstallMethod( \*, "objects with memory", true, - [IsObjWithMemory,IsObjWithMemory],0, +InstallMethod( \*, + [ "IsObjWithMemory", "IsObjWithMemory" ], function(a,b) local slp; slp := a!.slp; @@ -192,9 +202,9 @@ InstallMethod( \*, "objects with memory", true, ErrorNoReturn("\\* for objects with memory: a!.slp and b!.slp must be identical"); fi; if a!.n = 0 then # the identity! - return ObjWithMemory( slp, b!.n, b!.el ); + return b; elif b!.n = 0 then # the identity! - return ObjWithMemory( slp, a!.n, a!.el ); + return a; else Add( slp.prog, [ a!.n, 1, b!.n, 1 ] ); return ObjWithMemory( slp, Length( slp.prog ) + slp.nogens, @@ -202,15 +212,16 @@ InstallMethod( \*, "objects with memory", true, fi; end); -InstallMethod( One, "objects with memory", true, - [IsObjWithMemory],0, OneOp); +InstallMethod( One, + [ "IsObjWithMemory" ], + OneOp); -InstallMethod( OneOp, "objects with memory", true, - [IsObjWithMemory],0, +InstallMethod( OneOp, + [ "IsObjWithMemory" ], a -> ObjWithMemory( a!.slp, 0, One( a!.el ) ) ); -InstallMethod( InverseOp, "objects with memory", true, - [IsObjWithMemory],0, +InstallMethod( InverseOp, + [ "IsObjWithMemory" ], function(a) local slp; slp := a!.slp; @@ -219,12 +230,12 @@ InstallMethod( InverseOp, "objects with memory", true, return ObjWithMemory( slp, Length( slp.prog ) + slp.nogens, InverseOp( a!.el ) ); else - return ObjWithMemory( slp, 0, a!.el ); + return a; fi; end); -InstallMethod( \^, "objects with memory", true, - [IsObjWithMemory,IsInt],0, +InstallMethod( \^, + [ "IsObjWithMemory", "IsInt" ], function(a,b) local slp; slp := a!.slp; @@ -238,12 +249,22 @@ InstallMethod( \^, "objects with memory", true, fi; end); -InstallMethod(\=,"two objects with memory",IsIdenticalObj, - [IsObjWithMemory,IsObjWithMemory],0, - function(a,b) - return a!.el = b!.el; - end); +InstallMethod( \=, IsIdenticalObj, + [ "IsObjWithMemory", "IsObjWithMemory" ], + { a, b } -> a!.el = b!.el ); + +InstallMethod( \=, IsIdenticalObj, + [ "IsObjWithMemory", "IsMultiplicativeElement" ], + { a, x } -> a!.el = x ); +InstallMethod( \=, IsIdenticalObj, + [ "IsMultiplicativeElement", "IsObjWithMemory" ], + { x, a } -> x = a!.el ); + +# If the underlying elements are different then consider only their +# < relation. +# If the underlying elements are equal then consider also the positions +# in the straight line program. InstallGlobalFunction( SortFunctionWithMemory, function(a,b) if a!.el < b!.el then @@ -255,155 +276,111 @@ InstallGlobalFunction( SortFunctionWithMemory, fi; end); -InstallMethod(\<,"two objects with memory",IsIdenticalObj, - [IsObjWithMemory,IsObjWithMemory],0, - function(a,b) - return a!.el < b!.el; - end); +InstallMethod( \<, IsIdenticalObj, + [ "IsObjWithMemory", "IsObjWithMemory" ], + { a, b } -> a!.el < b!.el ); -InstallMethod(\=,"objects with memory with x",IsIdenticalObj, - [IsObjWithMemory,IsMultiplicativeElement],0, - function(a,x) - return a!.el=x; - end); +InstallMethod( \<, IsIdenticalObj, + [ "IsObjWithMemory", "IsMultiplicativeElement" ], + { a, x } -> a!.el < x ); -InstallMethod(\=,"x with objects with memory",IsIdenticalObj, - [IsMultiplicativeElement,IsObjWithMemory],0, - function(x,a) - return x=a!.el; - end); +InstallMethod( \<, IsIdenticalObj, + [ "IsMultiplicativeElement", "IsObjWithMemory" ], + { x, a } -> x < a!.el ); -InstallMethod(\<,"objects with memory with x",IsIdenticalObj, - [IsObjWithMemory,IsMultiplicativeElement],0, - function(a,x) - return a!.el Order( a!.el ) ); -InstallMethod(\<,"x with objects with memory",IsIdenticalObj, - [IsObjWithMemory,IsMultiplicativeElement],0, - function(a,x) - return x IsOne( a!.el ) ); -InstallMethod(Order,"object with memory",true, [IsObjWithMemory],0, - function(a) - return Order(a!.el); - end); +# permutation methods -InstallMethod(IsOne,"object with memory",true, [IsObjWithMemory],0, - function(a) - return IsOne(a!.el); - end); +InstallMethod( LargestMovedPoint, + [ "IsObjWithMemory and IsPerm" ], + a -> LargestMovedPoint( a!.el ) ); -# Permutation methods for permutations with memory: +InstallMethod( \^, + [ "IsInt", "IsObjWithMemory and IsPerm" ], + { a, b } -> a^b!.el ); -InstallMethod(LargestMovedPoint,"permutation with memory",true, - [IsObjWithMemory and IsPerm],0, - function(a) - return LargestMovedPoint(a!.el); - end); +InstallMethod( \/, + [ "IsInt", "IsObjWithMemory and IsPerm" ], + { a, b } -> a / b!.el ); -InstallMethod(\^,"integer and permutation with memory", true, - [IsInt, IsObjWithMemory and IsPerm],0, - function(a,b) - return a^b!.el; - end); +InstallOtherMethod( CycleOp, + [ "IsPerm and IsObjWithMemory", "IsInt" ], + { p, i } -> CycleOp( p!.el, i ) ); -InstallMethod(\/,"integer and permutation with memory", true, - [IsInt, IsObjWithMemory and IsPerm],0, - function(a,b) - return a / b!.el; - end); +InstallOtherMethod( CycleLengthOp, + [ "IsPerm and IsObjWithMemory", "IsInt" ], + { p, i } -> CycleLengthOp( p!.el, i ) ); -InstallOtherMethod(CycleLengthOp, - "for a permutation with memory and an integer",true, - [ IsPerm and IsObjWithMemory, IsInt ], 0, - function(p,e) - return CycleLengthOp(p!.el,e); - end); +InstallMethod( CycleStructurePerm, + [ "IsPerm and IsObjWithMemory" ], + p -> CycleStructurePerm( p!.el ) ); -InstallMethod(RestrictedPerm, - "for a permutation with memory and a list of integers",true, - [ IsPerm and IsObjWithMemory, IsList ], 0, - function(a,l) - return ObjWithMemory( a!.slp, a!.n, RestrictedPerm( a!.el, l ) ); - end); +InstallMethod( RestrictedPerm, + [ "IsPerm and IsObjWithMemory", "IsList" ], + { a, l } -> ObjWithMemory( a!.slp, a!.n, RestrictedPerm( a!.el, l ) ) ); -InstallMethod(SignPerm, - "for a permutation with memory",true, - [ IsPerm and IsObjWithMemory ], 0, - function(a) - return SignPerm(a!.el); -end); - -InstallOtherMethod(CycleOp, - "for a permutation with memory and an integer",true, - [ IsPerm and IsObjWithMemory, IsInt ], 0, - function(a,p) - return CycleOp(a!.el,p); - end); - -InstallOtherMethod(CycleStructurePerm, - "for a permutation with memory",true, - [ IsPerm and IsObjWithMemory ], 0, - p->CycleStructurePerm(p!.el)); +InstallMethod( SignPerm, + [ "IsPerm and IsObjWithMemory" ], + a -> SignPerm( a!.el ) ); # MatrixObj methods: -InstallOtherMethod( BaseDomain, "for a matrix with memory", - [ IsMatrixOrMatrixObj and IsObjWithMemory ], - M -> BaseDomain(M!.el) ); +InstallMethod( BaseDomain, + [ "IsMatrixOrMatrixObj and IsObjWithMemory" ], + M -> BaseDomain( M!.el ) ); -InstallOtherMethod( NumberRows, "for a matrix with memory", - [ IsMatrixOrMatrixObj and IsObjWithMemory ], - M -> NumberRows(M!.el) ); +InstallMethod( NumberRows, + [ "IsMatrixOrMatrixObj and IsObjWithMemory" ], + M -> NumberRows( M!.el ) ); -InstallOtherMethod( NumberColumns, "for a matrix with memory", - [ IsMatrixOrMatrixObj and IsObjWithMemory ], - M -> NumberColumns(M!.el) ); +InstallMethod( NumberColumns, + [ "IsMatrixOrMatrixObj and IsObjWithMemory" ], + M -> NumberColumns( M!.el ) ); -InstallOtherMethod( MatElm, "for a matrix with memory", - [ IsMatrixOrMatrixObj and IsObjWithMemory, IsPosInt, IsPosInt ], +InstallMethod( MatElm, + [ "IsMatrixOrMatrixObj and IsObjWithMemory", "IsPosInt", "IsPosInt" ], { M, i, j } -> M!.el[i,j] ); # legacy matrix methods -InstallOtherMethod( Length, "for a matrix with memory", - [ IsMatrix and IsObjWithMemory ], M -> Length(M!.el) ) ; +InstallOtherMethod( Length, + [ "IsMatrix and IsObjWithMemory" ], + M -> Length( M!.el ) ) ; -InstallOtherMethod( ELM_LIST, "for a matrix with memory", - [ IsMatrix and IsObjWithMemory, IsPosInt ], - function(M,i) - return M!.el[i]; - end); +InstallOtherMethod( ELM_LIST, + [ "IsMatrix and IsObjWithMemory", "IsPosInt" ], + { M, i } -> M!.el[i] ); -InstallOtherMethod( \*, "for a row vector and a matrix with memory", - [ IsListDefault and IsSmallList, IsMatrix and IsObjWithMemory ], 0, - function(v,M) - return v * M!.el; - end); +InstallOtherMethod( \*, + [ "IsListDefault and IsSmallList", "IsMatrix and IsObjWithMemory" ], + { v, M } -> v * M!.el ); -InstallOtherMethod( \*, "for a scalar and a matrix with memory", - [ IsScalar, IsMatrixOrMatrixObj and IsObjWithMemory ], 0, - { s, M } -> s * M!.el ); +InstallOtherMethod( \*, + [ "IsScalar", "IsMatrixOrMatrixObj and IsObjWithMemory" ], + { s, M } -> s * M!.el ); -InstallOtherMethod( \*, "for a matrix with memory and a scalar", - [ IsMatrixOrMatrixObj and IsObjWithMemory, IsScalar ], 0, - { M , s} -> M!.el * s ); +InstallOtherMethod( \*, + [ "IsMatrixOrMatrixObj and IsObjWithMemory", "IsScalar" ], + { M , s } -> M!.el * s ); -InstallOtherMethod(ProjectiveOrder,"object with memory", - [IsObjWithMemory],0, - function(a) - return ProjectiveOrder(a!.el); - end); +InstallOtherMethod( ProjectiveOrder, + [ "IsObjWithMemory" ], + a -> ProjectiveOrder( a!.el ) ); -InstallOtherMethod( ImmutableMatrix,"object with memory",[IsField,IsMatrixOrMatrixObj and IsObjWithMemory], -function(f,a) - return ObjWithMemory( a!.slp, a!.n, ImmutableMatrix( f, a!.el ) ); -end); +InstallOtherMethod( ImmutableMatrix, + [ "IsField", "IsMatrixOrMatrixObj and IsObjWithMemory" ], + { f, a } -> ObjWithMemory( a!.slp, a!.n, ImmutableMatrix( f, a!.el ) ) ); -# Free group methods: +# free group element methods -InstallOtherMethod( Length, "for a word with memory", - [ IsObjWithMemory and IsWord ], a -> Length(a!.el) ); +InstallOtherMethod( Length, + [ "IsObjWithMemory and IsWord" ], + a -> Length( a!.el ) ); diff --git a/lib/oper.g b/lib/oper.g index 5e72ecefac..a8ca8eb8d1 100644 --- a/lib/oper.g +++ b/lib/oper.g @@ -2017,7 +2017,35 @@ if BASE_SIZE_METHODS_OPER_ENTRY <> 6 then Error("MethodsOperation must be updated for new BASE_SIZE_METHODS_OPER_ENTRY"); fi; -# TODO: document this?! + +############################################################################# +## +#F MethodsOperation( , ) +## +## <#GAPDoc Label="MethodsOperation"> +## +## +## +## +## Return a list of records that describe the installed methods for the +## operation oper, with n arguments. +##

+## Each record has at least the following components. +##

+## +## func +## the method itself, a &GAP; function, +## rank +## the rank of the method, an integer or infinity, +## info +## a string that describes when the method is applicable, +## location +## filename and start line where the method gets installed. +## +## +## +## <#/GAPDoc> +## BIND_GLOBAL("MethodsOperation", function(oper, nargs) local early, meths, len, result, i, m; diff --git a/tst/testinstall/memory.tst b/tst/testinstall/memory.tst index 8483a958e9..777bdd48c2 100644 --- a/tst/testinstall/memory.tst +++ b/tst/testinstall/memory.tst @@ -1,4 +1,7 @@ -#@local G, H, g, h, tmp, stabChain, s1, s2 +#@local G, H, g, h, tmp, stabChain, s1, s2, a, S, prod, i, v, s, pow, m, mm +gap> START_TEST( "memory.tst" ); + +# gap> G := GroupWithMemory([ (1,2,3,4,5), (1,2) ]);; gap> H := GroupWithMemory(GL(IsMatrixGroup, 3, 3));; gap> g := H.1 ^ 2;; h := H.2 ^ 2;; @@ -36,6 +39,106 @@ gap> g * h; gap> g * G.1; Error, \* for objects with memory: a!.slp and b!.slp must be identical +# permutation methods +gap> G:= SymmetricGroup( 5 );; +gap> H:= GroupWithMemory( G );; +gap> ( H.1 = H.2 ) = ( G.1 = G.2 ); +true +gap> ( H.1 = G.2 ) = ( G.1 = G.2 ); +true +gap> ( G.1 = H.2 ) = ( G.1 = G.2 ); +true +gap> G.1 = H.1; +true +gap> ( H.1 < H.2 ) = ( G.1 < G.2 ); +true +gap> ( H.1 < G.2 ) = ( G.1 < G.2 ); +true +gap> ( G.1 < H.2 ) = ( G.1 < G.2 ); +true +gap> prod:= H.1 * H.2;; +gap> IsObjWithMemory( prod ) and prod = G.1 * G.2; +true +gap> IsObjWithMemory( One( H.1 ) ) and One( H.1 ) = One( G.1 ); +true +gap> IsObjWithMemory( Inverse( H.1 ) ) and Inverse( H.1 ) = Inverse( G.1 ); +true +gap> for i in [ -1 .. 3 ] do +> pow:= H.1^i; +> if not IsObjWithMemory( pow ) then +> Error( "wrong type" ); +> elif pow <> G.1^i then +> Error( "wrong result" ); +> fi; +> od; +gap> Order( G.1 ) = Order( H.1 ); +true +gap> LargestMovedPoint( G.1 ) = LargestMovedPoint( H.1 ); +true +gap> ForAll( [ 1 .. 5 ], i -> i ^ G.1 = i ^ H.1 ); +true +gap> ForAll( [ 1 .. 5 ], i -> i / G.1 = i / H.1 ); +true +gap> ForAll( [ 1 .. 5 ], i -> Cycle( G.1, i ) = Cycle( H.1, i ) ); +true +gap> ForAll( [ 1 .. 5 ], i -> CycleLength( G.1, i ) = CycleLength( H.1, i ) ); +true +gap> CycleStructurePerm( G.1 ) = CycleStructurePerm( H.1 ); +true +gap> RestrictedPerm( G.2, [ 1 .. 3 ] ) = RestrictedPerm( H.2, [ 1 .. 3 ] ); +true +gap> IsObjWithMemory( RestrictedPerm( H.2, [ 1 .. 3 ] ) ); +true +gap> SignPerm( G.2 ) = SignPerm( H.2 ); +true + +# legacy matrix methods +gap> G:= GL(2, 3);; +gap> H:= GroupWithMemory( G );; +gap> Order( G.1 ) = Order( H.1 ); +true +gap> IsOne( G.1 ) = IsOne( H.1 ); +true +gap> IsOne( One( G ) ) = IsOne( One( H ) ); +true +gap> IsObjWithMemory( One( H.1 ) ) and One( H.1 ) = One( G.1 ); +true +gap> IsObjWithMemory( One( H ) ); +true +gap> IsList( G.1 ); +true +gap> Length( G.1 ) = Length( H.1 ); +true +gap> G.1[1] = H.1[1]; +true +gap> v:= [ Z(3), Z(3)^2 ];; +gap> v * G.1 = v * H.1; +true +gap> Z(3) * G.1 = Z(3) * H.1; +true +gap> G.1 * Z(3) = H.1 * Z(3); +true +gap> ProjectiveOrder( G.1 ) = ProjectiveOrder( H.1 ); +true +gap> m:= [ [ Z(2) ] ]; +[ [ Z(2)^0 ] ] +gap> IsPlistRep( m ); +true +gap> s:= GeneratorsWithMemory( [ m ] ); +[ <[ [ Z(2)^0 ] ] with mem> ] +gap> mm:= ImmutableMatrix( GF(4), s[1] ); +<[ [ Z(2)^0 ] ] with mem> +gap> IsMutable( mm ); +false +gap> Is8BitMatrixRep( StripMemory( mm ) ); +true + +# free group element methods +gap> G:= FreeGroup( 2 );; +gap> H:= GroupWithMemory( G );; +gap> Length( G.1 ) = Length( H.1 ); +true + # ImmutableMatrix on a matrix with memory # see https://github.com/gap-system/gap/issues/5872 gap> G:=GroupWithMemory(SL(4,16));; @@ -43,3 +146,18 @@ gap> g:=ImmutableMatrix(GF(4), G.1^5); <[ [ Z(2^2), 0*Z(2), 0*Z(2), 0*Z(2) ], [ 0*Z(2), Z(2^2)^2, 0*Z(2), 0*Z(2) ], [ 0*Z(2), 0*Z(2), Z(2)^0, 0*Z(2) ], [ 0*Z(2), 0*Z(2), 0*Z(2), Z(2)^0 ] ] with mem> + +# 'SCRSift' works also for non-internal permutations, +# by delegating to 'SiftedPermutation'. +gap> G:= GroupWithMemory( MathieuGroup( 11 ) );; +gap> a:= G.1;; +gap> IsPerm( a ); +true +gap> IsInternalRep( a ); +false +gap> S:= StabChain( G );; +gap> SCRSift( S, a ); +<() with mem> + +# +gap> STOP_TEST( "memory.tst" ); diff --git a/tst/teststandard/stabchain.tst b/tst/teststandard/stabchain.tst index b1534505d8..40d7d86165 100644 --- a/tst/teststandard/stabchain.tst +++ b/tst/teststandard/stabchain.tst @@ -48,17 +48,5 @@ gap> SCRSift(S,(1,2)); gap> SCRSift(S,GeneratorsOfGroup(m)[1]); () -# 'SCRSift' works also for non-internal permutations, -# by delegating to 'SiftedPermutation'. -gap> G:= GroupWithMemory( MathieuGroup( 11 ) );; -gap> a:= G.1;; -gap> IsPerm( a ); -true -gap> IsInternalRep( a ); -false -gap> S:= StabChain( G );; -gap> SCRSift( S, a ); -<() with mem> - # gap> STOP_TEST("stabchain.tst"); From 33c59b23a73129b63df73522aa87c7b6dfa1ba95 Mon Sep 17 00:00:00 2001 From: Thomas Breuer Date: Mon, 19 Jan 2026 11:38:18 +0100 Subject: [PATCH 078/234] remove the `ConjugateGroup` method based on nice monom. (#6197) I think that using nice monomorphisms in `ConjugateGroup` methods is a bad idea: When this works (that is, when the conjugating element can be mapped under the nice monomorphism of the group) then one first maps the group and the element under the nice monomorphism, then conjugates in the image, and then pulls back the result under the monomorphism. The group which one gets this way (via `GroupByNiceMonomorphism`) knows almost nothing except the nice monomorphism. And in general this will not work because the conjugating element will not fit. Due to the omission of the `ConjugateGroup` method, we will lose the known `NiceMonomorphism` in the result of `ConjugateGroup`. Eventually this can be "reinserted" by installing a new `ConjugateGroup` method with requirement `IsGroup and HasNiceMonomorphism` that creates a nice monomorphism of the conjugated group. Do we want this? (In certain cases, this will be not what one wants: Perhaps we conjugate the group just in order to get a better behaved group, and then setting a "nice monomorphism" in this group that delegates tasks via the "ugly" original group is a bad idea.) --- lib/grpnice.gi | 8 -------- 1 file changed, 8 deletions(-) diff --git a/lib/grpnice.gi b/lib/grpnice.gi index 710c2a5ef1..6b486d1859 100644 --- a/lib/grpnice.gi +++ b/lib/grpnice.gi @@ -352,14 +352,6 @@ local mon,cl,clg,c,i; end); -############################################################################# -## -#M ConjugateGroup( , ) . . . . . . . . . . . . . . conjugate of -## -GroupMethodByNiceMonomorphismCollElm( ConjugateGroup, - [ IsGroup and HasParent, IsMultiplicativeElementWithInverse ] ); - - ############################################################################# ## #M Core( , ) . . . . . . . . . . . . . . . . core of a in a From e99a21cded308ad74e9af59cb91693472aaa64ec Mon Sep 17 00:00:00 2001 From: stertooy <5571903+stertooy@users.noreply.github.com> Date: Mon, 19 Jan 2026 11:40:39 +0100 Subject: [PATCH 079/234] Remove unused "PC STACK" variables for from the left collectors (this breaks compatibility with polycyclic version 2.16 and older; use 2.17 or newer instead) (#6191) --- lib/package.gi | 20 ++++++++++++++++++++ src/objcftl.c | 10 ---------- src/objcftl.h | 33 ++++++++++----------------------- 3 files changed, 30 insertions(+), 33 deletions(-) diff --git a/lib/package.gi b/lib/package.gi index cfa5a5c68e..22eafe0815 100644 --- a/lib/package.gi +++ b/lib/package.gi @@ -2556,6 +2556,26 @@ GAPInfo.PackagesRestrictions := AtomicRecord(rec( "most recent version, see URL\n", " https://gap-packages.github.io/autpgrp/\n" ); fi; + end )), + + polycyclic := MakeImmutable(rec( + OnInitialization := function( pkginfo ) + if CompareVersionNumbers( pkginfo.Version, "2.17" ) = false then + return false; + fi; + return true; + end, + OnLoad := function( pkginfo ) + if CompareVersionNumbers( pkginfo.Version, "2.17" ) = false then + Print( " The package `polycyclic'", + " should better be upgraded at least to version 2.17,\n", + " the given version (", pkginfo.Version, + ") is known to be incompatible\n", + " with the current version of GAP.\n", + " It is strongly recommended to update to the ", + "most recent version, see URL\n", + " https://gap-packages.github.io/polycyclic/\n" ); + fi; end )) )); diff --git a/src/objcftl.c b/src/objcftl.c index 4393acffb1..557827816f 100644 --- a/src/objcftl.c +++ b/src/objcftl.c @@ -401,18 +401,8 @@ static Int InitLibrary ( ExportAsConstantGVar(PC_DEEP_THOUGHT_POLS); ExportAsConstantGVar(PC_DEEP_THOUGHT_BOUND); ExportAsConstantGVar(PC_ORDERS); - ExportAsConstantGVar(PC_WORD_STACK); - ExportAsConstantGVar(PC_STACK_SIZE); - ExportAsConstantGVar(PC_WORD_EXPONENT_STACK); - ExportAsConstantGVar(PC_SYLLABLE_STACK); - ExportAsConstantGVar(PC_EXPONENT_STACK); - ExportAsConstantGVar(PC_STACK_POINTER); ExportAsConstantGVar(PC_DEFAULT_TYPE); - // signal to polycyclic that 'CollectPolycyclic' does not use resp. - // require stacks inside the collector objects - AssConstantGVar(GVarName("NO_STACKS_INSIDE_COLLECTORS"), True); - // init filters and functions InitGVarFuncsFromTable( GVarFuncs ); diff --git a/src/objcftl.h b/src/objcftl.h index 413b47b156..17ab563ab7 100644 --- a/src/objcftl.h +++ b/src/objcftl.h @@ -30,34 +30,21 @@ #define PC_DEEP_THOUGHT_POLS 12 #define PC_DEEP_THOUGHT_BOUND 13 #define PC_ORDERS 14 - -// TODO: the following stack related positions are not -// used anymore by CollectPolycyc, and will not be used -// anymore in future releases of the polycyclic package. -// We should phase them out for GAP 4.10. -#define PC_WORD_STACK 15 -#define PC_STACK_SIZE 16 -#define PC_WORD_EXPONENT_STACK 17 -#define PC_SYLLABLE_STACK 18 -#define PC_EXPONENT_STACK 19 -#define PC_STACK_POINTER 20 -// TODO: end obsolete - -#define PC_DEFAULT_TYPE 21 +#define PC_DEFAULT_TYPE 15 /* the following are defined in polycyclic: -#define PC_PCP_ELEMENTS_FAMILY 22 -#define PC_PCP_ELEMENTS_TYPE 23 +#define PC_PCP_ELEMENTS_FAMILY 16 +#define PC_PCP_ELEMENTS_TYPE 17 -#define PC_COMMUTATORS 24 -#define PC_INVERSECOMMUTATORS 25 -#define PC_COMMUTATORSINVERSE 26 -#define PC_INVERSECOMMUTATORSINVERSE 27 +#define PC_COMMUTATORS 18 +#define PC_INVERSECOMMUTATORS 19 +#define PC_COMMUTATORSINVERSE 20 +#define PC_INVERSECOMMUTATORSINVERSE 21 -#define PC_NILPOTENT_COMMUTE 28 -#define PC_WEIGHTS 29 -#define PC_ABELIAN_START 30 +#define PC_NILPOTENT_COMMUTE 22 +#define PC_WEIGHTS 23 +#define PC_ABELIAN_START 24 */ /**************************************************************************** From eddc9430034f4e1c9db9c74ace09581bc9b416f8 Mon Sep 17 00:00:00 2001 From: Thomas Breuer Date: Mon, 19 Jan 2026 11:41:42 +0100 Subject: [PATCH 080/234] Fix an inconsistency problem in `IsFinite` for matrix groups over cycl. fields. (#6196) --- lib/grpnice.gi | 19 ++++++++++++------- lib/grpramat.gi | 17 +++++++++++------ tst/testinstall/grpmat.tst | 16 +++++++++++++++- 3 files changed, 38 insertions(+), 14 deletions(-) diff --git a/lib/grpnice.gi b/lib/grpnice.gi index 6b486d1859..ec69eeaf40 100644 --- a/lib/grpnice.gi +++ b/lib/grpnice.gi @@ -105,12 +105,7 @@ end ); ## #M NiceObject( ) . . . . . . . . . . . . . get nice object of group ## -InstallMethod( NiceObject, - true, - [ IsGroup and IsHandledByNiceMonomorphism ], - 0, - -function( G ) +_NiceObject_method:= function( G ) local nice, img, D; nice := NiceMonomorphism( G ); @@ -132,7 +127,17 @@ function( G ) SetBaseOfGroup( img, UnderlyingExternalSet( nice )!.basePermImage ); fi; return img; -end ); +end; + +InstallMethod( NiceObject, + [ IsGroup and IsHandledByNiceMonomorphism ], + _NiceObject_method ); + +InstallMethod( NiceObject, + [ IsGroup and HasNiceMonomorphism ], + _NiceObject_method ); + +Unbind( _NiceObject_method ); ############################################################################# diff --git a/lib/grpramat.gi b/lib/grpramat.gi index 98ad46a51a..ee638c862d 100644 --- a/lib/grpramat.gi +++ b/lib/grpramat.gi @@ -268,12 +268,13 @@ function( G ) # The code below is based on the algorithm described in [DFO13] local badPrimes, n, g, FindPrimesInMatDenominators, p, e, H, phi, gens, rels, nice, inv, Hnice; - # if not rational, use the nice monomorphism into a rational matrix group - if not IsRationalMatrixGroup( G ) then - # the following does not use NiceObject(G) as the only method for - # that currently requires IsHandledByNiceMonomorphism - SetNiceObject( G, Image( NiceMonomorphism( G ), G ) ); - return IsFinite( NiceObject( G ) ); + if HasNiceMonomorphism( G ) then + # Assume that the computation is easier in the image. + return IsFinite( NiceObject( G ) ); + elif not IsRationalMatrixGroup( G ) then + # Use the nice monomorphism into a rational matrix group. + NiceMonomorphism( G ); + return IsFinite( NiceObject( G ) ); fi; # if not integer, choose basis in which it is integer @@ -319,8 +320,12 @@ function( G ) rels := RelatorsOfFpGroup(Range(phi)); if not ForAll(rels, r -> IsOne(MappedWord(r, gens, GeneratorsOfGroup(G)))) then return false; + elif HasNiceMonomorphism( G ) or HasNiceObject( G ) then + # The two values must be consistent, we cannot set them here. + return true; fi; + # Set a nice monomorphism in 'G'. # bypass the finite field matrix group in the middle so that we can # compute preimages more easily inv := GroupHomomorphismByImagesNC(H, G : noassert); diff --git a/tst/testinstall/grpmat.tst b/tst/testinstall/grpmat.tst index bd7f9e8428..31b192e7ba 100644 --- a/tst/testinstall/grpmat.tst +++ b/tst/testinstall/grpmat.tst @@ -1,4 +1,4 @@ -#@local cl,g,gd,gens,hom,i,img,iso,pcgs,u,G,F,o,a +#@local cl,g,gd,gens,hom,i,img,iso,pcgs,u,G,F,o,a,m,nice,H gap> START_TEST("grpmat.tst"); gap> i := E(4);; G := Group([[i,0],[0,-i]],[[0,1],[-1,0]]);; gap> gens := GeneratorsOfGroup( G );; IsSSortedList( gens ); @@ -67,6 +67,20 @@ gap> NiceMonomorphism( G );; gap> G:= Group( [ [ 0, 1 ], [ 1, 0 ] ] );; gap> IsomorphismFpGroup( G );; +# 'NiceMonomorphism' and 'NiceObject' are consistent. +gap> m:= [ [ E(4) ] ];; +gap> G:= Group( m );; # not rational matrix group +gap> nice:= NiceMonomorphism( G );; +gap> H:= SubgroupNC( G, [ m^2 ] );; # rational matrix group +gap> HasNiceMonomorphism( H ); +true +gap> IsIdenticalObj( NiceMonomorphism( H ), nice ); +true +gap> IsFinite( H ); +true +gap> NiceObject( H ) = Image( nice, H ); +true + # gap> TrivialSubgroup( GL(2, 2) ); From 33b09da040dfdcc99bad383d3cc913df7e02da13 Mon Sep 17 00:00:00 2001 From: Max Horn Date: Fri, 23 Jan 2026 10:53:45 +0100 Subject: [PATCH 081/234] dev: reformat with black 26.1.0 (#6204) Alternative would be to pin black to a specific year edition, but rerunning it was easier for me than figuring out how to pin it. --- dev/releases/release_notes.py | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/dev/releases/release_notes.py b/dev/releases/release_notes.py index 88a2fb7a37..58e7119bb9 100755 --- a/dev/releases/release_notes.py +++ b/dev/releases/release_notes.py @@ -150,15 +150,13 @@ def package_updates(relnotes_file: TextIO, new_gap_version: str) -> None: updated = new_json.keys() & old_json.keys() updated = [p for p in updated if old_json[p]["Version"] != new_json[p]["Version"]] if len(updated) > 0: - relnotes_file.write( - f""" + relnotes_file.write(f""" #### Updated packages redistributed with GAP The GAP {new_gap_version} distribution contains {len(new_json)} packages, of which {len(updated)} have been updated since GAP {old_gap_version}. The full list of updated packages is given below: -""".lstrip() - ) +""".lstrip()) for p in sorted(updated): old = old_json[p] new = new_json[p] @@ -263,8 +261,7 @@ def changes_overview( pr for pr in prs if has_label(pr, "release notes: use title") ] # Write out all PRs with 'use title' - relnotes_file.write( - f"""# GAP - history of changes + relnotes_file.write(f"""# GAP - history of changes ## GAP {new_version} ({month} {year}) @@ -273,8 +270,7 @@ def changes_overview( were made, but we tried to only list those changes which we think might affect some users directly. -""" - ) +""") for priorityobject in prioritylist: matches = [ From b647db8cd8a5563869ca35465679335288c26938 Mon Sep 17 00:00:00 2001 From: Thomas Breuer Date: Fri, 23 Jan 2026 18:59:56 +0100 Subject: [PATCH 082/234] Avoid errors due to too large range bounds (#6201) --- lib/morpheus.gi | 14 ++++++++++---- .../2026-01-20-IsomorphismSimpleGroups.tst | 15 +++++++++++++++ 2 files changed, 25 insertions(+), 4 deletions(-) create mode 100644 tst/testbugfix/2026-01-20-IsomorphismSimpleGroups.tst diff --git a/lib/morpheus.gi b/lib/morpheus.gi index 3d22979de6..8aba4da1d9 100644 --- a/lib/morpheus.gi +++ b/lib/morpheus.gi @@ -2627,7 +2627,13 @@ local d,iso,a,b,c,o,s,two,rt,r,z,e,y,re,m,gens,cnt,lim,p, a:=PseudoRandom(gp); fi; e:=Order(a); - if e in r then + # `r` is either a list or a record, + # the latter describing the range + # `[ r.first, r.first + r.offset .. r.last ]`, + # also if this range cannot be created in GAP. + if ( IsList( r ) and e in r ) or + ( IsRecord( r ) and r.first <= e and e <= r.last + and ( e - r.first ) mod r.offset = 0 ) then a:=a^QuoInt(e,o); if z=fail or Size(Centralizer(gp,a))=z then return a; @@ -2731,7 +2737,7 @@ local d,iso,a,b,c,o,s,two,rt,r,z,e,y,re,m,gens,cnt,lim,p, if gens=fail then Info(InfoMorph,1,"Isomorphism simple: ad-hoc"); # not found by table or other -- try a 2/something ad-hoc - rt:=[2,4..Size(g)]; + rt:= rec( first:= 2, offset:= 2, last:= Size(g) ); gens:=[findElm(g,2,fail,rt)]; z:=Size(Centralizer(g,gens[1])); @@ -2740,7 +2746,7 @@ local d,iso,a,b,c,o,s,two,rt,r,z,e,y,re,m,gens,cnt,lim,p, m:=Maximum(Filtered(Factors(Size(g)),x->x<100)); cnt:=0; repeat - gens[2]:=findElm(g,m,fail,[m,2*m..Size(g)]); + gens[2]:=findElm(g,m,fail, rec( first:= m, offset:= m, last:= Size(g) )); if isFull(SubgroupNC(g,gens)) then b:=gens; y:=Size(Centralizer(g,gens[2])); @@ -2765,7 +2771,7 @@ local d,iso,a,b,c,o,s,two,rt,r,z,e,y,re,m,gens,cnt,lim,p, od; gens:=b; e:=Order(gens[2]); - re:=[e,2*e..Size(g)]; + re:= rec( first:= e, offset:= e, last:= Size(g) ); y:=Size(Centralizer(g,gens[2])); fi; Info(InfoMorph,1,"generators ",List(gens,Order)); diff --git a/tst/testbugfix/2026-01-20-IsomorphismSimpleGroups.tst b/tst/testbugfix/2026-01-20-IsomorphismSimpleGroups.tst new file mode 100644 index 0000000000..0f317ce56f --- /dev/null +++ b/tst/testbugfix/2026-01-20-IsomorphismSimpleGroups.tst @@ -0,0 +1,15 @@ +# Fix #6200 IsomorphismSimpleGroups +#@local G, x, H +gap> START_TEST("IsomorphismSimpleGroups.tst"); + +# The runtime depends very much on random choices in the code, +# it can vary from a few milliseconds (rare) to several minutes. +gap> Reset( GlobalMersenneTwister, 2^19 );; +gap> G:= AlternatingGroup( 20 );; +gap> x:= ();; +gap> H:= ConjugateGroup( G, x );; +gap> IsomorphismSimpleGroups( G, H : cheap:= true ) <> fail; +true + +# +gap> STOP_TEST("IsomorphismSimpleGroups.tst"); From 553bcd78d2277ddb98af47a133f2cd162b1b4fbb Mon Sep 17 00:00:00 2001 From: Max Horn Date: Tue, 27 Jan 2026 01:10:04 +0100 Subject: [PATCH 083/234] Don't transfer nice monos when conjugating (#6207) We tried this but then decide against it, because we determined that often you conjugate precisely so that you get a nicer description of a group. But by accident the code implementing it got merged anyway. --- lib/grpmat.gi | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/lib/grpmat.gi b/lib/grpmat.gi index 69299d699c..ac88311858 100644 --- a/lib/grpmat.gi +++ b/lib/grpmat.gi @@ -1274,7 +1274,7 @@ InstallMethod( InvariantBilinearForm, InstallMethod( ConjugateGroup, ", ", IsCollsElms, [ IsMatrixGroup, IsMultiplicativeElementWithInverse ], function( G, g ) - local H, m, ginv, nice, conj; + local H, m, ginv; H := GroupByGenerators( OnTuples( GeneratorsOfGroup( G ), g ), One( G ) ); UseIsomorphismRelation( G, H ); @@ -1317,16 +1317,5 @@ InstallMethod( ConjugateGroup, ", ", IsCollsElms, SetIsFullSubgroupGLorSLRespectingQuadraticForm( H, true ); fi; fi; - if HasNiceMonomorphism( G ) then - nice := NiceMonomorphism( G ); - if not IsBound( ginv ) then - ginv := g^-1; - fi; - conj := GroupHomomorphismByFunction( H, G, y -> g*y*ginv, x -> ginv*x*g ); - SetNiceMonomorphism( H, conj * nice ); - if HasNiceObject( G ) then - SetNiceObject( H, NiceObject( G ) ); - fi; - fi; return H; end ); From 64438ae58ae36776ede2772f8011075909079636 Mon Sep 17 00:00:00 2001 From: Thomas Breuer Date: Tue, 27 Jan 2026 15:08:30 +0100 Subject: [PATCH 084/234] Fix `FieldOfMatrixGroup` for certain classical matrix groups in dimension up to 2, and fix related problems with their invariant forms (#6203) * fix some problems with invariant forms of matrix groups - add a component `baseDomain` to the records that describe invariant forms; note that the field automorphism for sesquilinear forms can in general not be deduced from the matrix group and the matrix of the form (the problematic cases are unitary groups in dimension 2) and the field of definition can be different from (larger than) the field of the matrix entries for some orthogonal groups in dimension 1, see the code lines where `FieldOfMatrixGroup` gets set, - correct or verify the `SetFieldOfMatrixGroup` calls that occur, and add comments, - adjust and extend the tests for groups that store invariant forms, - fix the `\in` and `NrConjugacyClasses` methods that are based on an invariant sesquilinear form, the field automorphism must be derived from the `baseDomain` of the form, not from the `FieldOfMatrixGroup` of the group, - adjust the documentation of `InvariantBilinearForm`, `IsFullSubgroupGLorSLRespectingBilinearForm`, `InvariantSesquilinearForm`, `IsFullSubgroupGLorSLRespectingSesquilinearForm`, `InvariantQuadraticForm`, `IsFullSubgroupGLorSLRespectingQuadraticForm`, - support also sesquilinear forms in the recently added `ConjugateGroup` method for matrix groups (one could transfer the form in more situations, but perhaps it is anyhow a bad idea to allow a too general setup) * address comments --- grp/classic.gi | 139 +++++++++++++------ grp/ree.gi | 2 +- grp/suzuki.gi | 2 +- lib/grpffmat.gi | 35 +---- lib/grpmat.gd | 137 ++++++++++++------ lib/grpmat.gi | 64 +++++++-- tst/testinstall/grp/classic-forms.tst | 193 +++++++++++++++++++++----- 7 files changed, 415 insertions(+), 157 deletions(-) diff --git a/grp/classic.gi b/grp/classic.gi index 1298a58a50..d45c39839f 100644 --- a/grp/classic.gi +++ b/grp/classic.gi @@ -82,6 +82,8 @@ InstallMethod( SymplecticGroupCons, g := GroupWithGenerators( [ mat1, mat2 ] ); SetName( g, Concatenation("Sp(",String(d),",",String(q),")") ); SetDimensionOfMatrixGroup( g, d ); + + # 'mat1' contains a primitive root of 'f'. SetFieldOfMatrixGroup( g, f ); # add the size @@ -101,7 +103,7 @@ InstallMethod( SymplecticGroupCons, c[d/2+i,d/2-i+1] := -o; od; SetInvariantBilinearForm( g, - rec( matrix:= ImmutableMatrix( f, c, true ) ) ); + rec( matrix:= ImmutableMatrix( f, c, true ), baseDomain:= f ) ); SetIsFullSubgroupGLorSLRespectingBilinearForm(g,true); SetIsSubgroupSL(g,true); @@ -200,6 +202,8 @@ InstallMethod( GeneralUnitaryGroupCons, g:= GroupWithGenerators( gens ); SetName( g, Concatenation("GU(",String(n),",",String(q),")") ); SetDimensionOfMatrixGroup( g, n ); + + # 'mat1' contains a primitive root of 'f'. SetFieldOfMatrixGroup( g, f ); # Add the size. @@ -216,7 +220,7 @@ InstallMethod( GeneralUnitaryGroupCons, # construct the form c := Reversed( One( g ) ); SetInvariantSesquilinearForm( g, - rec( matrix:= ImmutableMatrix( f, c, true ) ) ); + rec( matrix:= ImmutableMatrix( f, c, true ), baseDomain:= f ) ); SetIsFullSubgroupGLorSLRespectingSesquilinearForm(g,true); # Return the group. @@ -313,7 +317,13 @@ InstallMethod( SpecialUnitaryGroupCons, g:= GroupWithGenerators( gens ); SetName( g, Concatenation("SU(",String(n),",",String(q),")") ); SetDimensionOfMatrixGroup( g, n ); - SetFieldOfMatrixGroup( g, f ); + if n <= 2 then + # The entries of 'gens' may generate a smaller field than 'f'. + SetFieldOfMatrixGroup( g, FieldOfMatrixList( gens ) ); + else + # 'mat1' contains a primitive root of 'f'. + SetFieldOfMatrixGroup( g, f ); + fi; # Add the size. size := 1; @@ -329,7 +339,7 @@ InstallMethod( SpecialUnitaryGroupCons, # construct the form c := Reversed( One( g ) ); SetInvariantSesquilinearForm( g, - rec( matrix:= ImmutableMatrix( f, c, true ) ) ); + rec( matrix:= ImmutableMatrix( f, c, true ), baseDomain:= f ) ); SetIsFullSubgroupGLorSLRespectingSesquilinearForm(g,true); SetIsSubgroupSL(g,true); @@ -340,15 +350,23 @@ InstallMethod( SpecialUnitaryGroupCons, ############################################################################# ## -#M SetInvariantQuadraticFormFromMatrix( , ) +#M SetInvariantQuadraticFormFromMatrix( , , ) ## -## Set the invariant quadratic form of to the matrix , and also -## set the bilinear form to the value required by the documentation, i.e., -# to + ^T. +## Set the invariant quadratic form of to the matrix . +## Also set the bilinear form to the value required by the documentation, +## i.e., to + ^T. +## In both forms, set the 'baseDomain' component. ## -BindGlobal( "SetInvariantQuadraticFormFromMatrix", function( g, mat ) - SetInvariantQuadraticForm( g, rec( matrix:= mat ) ); - SetInvariantBilinearForm( g, rec( matrix:= mat+TransposedMat(mat) ) ); +BindGlobal( "SetInvariantQuadraticFormFromMatrix", function( g, mat, F... ) + if Length( F ) <> 1 then + # In earlier versions of GAP, no 'baseDomain' was stored. + Error( "only the three argument variant of ", + "SetInvariantQuadraticFormFromMatrix is supported, ", + "the form record needs a 'baseDomain' component" ); + fi; + SetInvariantQuadraticForm( g, rec( matrix:= mat, baseDomain:= F[1] ) ); + SetInvariantBilinearForm( g, rec( matrix:= mat+TransposedMat(mat), + baseDomain:= F[1] ) ); end ); @@ -392,6 +410,8 @@ BindGlobal( "Oplus45", function() g:=List(g,i->ImmutableMatrix(f,i)); g := GroupWithGenerators( g ); SetDimensionOfMatrixGroup( g, 4 ); + + # 'f' is a prime field. SetFieldOfMatrixGroup( g, f ); # set the size @@ -399,7 +419,7 @@ BindGlobal( "Oplus45", function() # construct the forms SetInvariantQuadraticFormFromMatrix( g, ImmutableMatrix( f, - [[0,1,0,0],[0,0,0,0],[0,0,1,0],[0,0,0,1]] * One( f ), true ) ); + [[0,1,0,0],[0,0,0,0],[0,0,1,0],[0,0,0,1]] * One( f ), true ), f ); # and return return g; @@ -451,6 +471,8 @@ BindGlobal( "Opm3", function( s, d ) g:=List(g,i->ImmutableMatrix(f,i,true)); g := GroupWithGenerators( g ); SetDimensionOfMatrixGroup( g, d ); + + # 'f' is a prime field. SetFieldOfMatrixGroup( g, f ); # construct the forms @@ -458,7 +480,7 @@ BindGlobal( "Opm3", function( s, d ) delta{[1,2]}{[1,2]} := [[0,1],[0,0]]*One( f ); delta[3,3] := One( f )*2; delta := ImmutableMatrix( f, delta, true ); - SetInvariantQuadraticFormFromMatrix( g, delta ); + SetInvariantQuadraticFormFromMatrix( g, delta, f ); # set the size delta := 1; @@ -519,6 +541,8 @@ BindGlobal( "OpmSmall", function( s, d, q ) g:=List(g,i->ImmutableMatrix(f,i,true)); g := GroupWithGenerators( g ); SetDimensionOfMatrixGroup( g, d ); + + # 'f' is a prime field. SetFieldOfMatrixGroup( g, f ); # construct the forms @@ -526,7 +550,7 @@ BindGlobal( "OpmSmall", function( s, d, q ) delta{[1,2]}{[1,2]} := [[0,1],[0,0]]*One( f ); delta[3,3] := One( f ); delta := ImmutableMatrix( f, delta, true ); - SetInvariantQuadraticFormFromMatrix( g, delta ); + SetInvariantQuadraticFormFromMatrix( g, delta, f ); # set the size delta := 1; @@ -588,7 +612,7 @@ BindGlobal( "OpmOdd", function( s, d, q ) [[1,0,0,0],[0,1,2,1],[2,0,2,0],[1,0,0,1]]*One( f ), [[0,2,2,2],[0,1,1,2],[1,0,2,0],[1,2,2,0]]*One( f ) ] ); SetInvariantQuadraticFormFromMatrix( g, ImmutableMatrix( f, - [[0,1,0,0],[0,0,0,0],[0,0,2,0],[0,0,0,1]]*One( f ), true ) ); + [[0,1,0,0],[0,0,0,0],[0,0,2,0],[0,0,0,1]]*One( f ), true ), f ); SetSize( g, 1152 ); return g; elif q = 3 and d = 4 and s = -1 then @@ -596,7 +620,7 @@ BindGlobal( "OpmOdd", function( s, d, q ) [[0,2,0,0],[2,1,0,1],[0,2,0,1],[0,0,1,0]]*One( f ), [[2,0,0,0],[1,2,0,2],[1,0,0,1],[0,0,1,0]]*One( f ) ] ); SetInvariantQuadraticFormFromMatrix( g, ImmutableMatrix( f, - [[0,1,0,0],[0,0,0,0],[0,0,1,0],[0,0,0,1]]*One( f ), true ) ); + [[0,1,0,0],[0,0,0,0],[0,0,1,0],[0,0,0,1]]*One( f ), true ), f ); SetSize( g, 1440 ); return g; elif q = 5 and d = 4 and s = +1 then @@ -652,6 +676,8 @@ BindGlobal( "OpmOdd", function( s, d, q ) g:=List(g,i->ImmutableMatrix(f,i,true)); g := GroupWithGenerators( g ); SetDimensionOfMatrixGroup( g, d ); + + # 'phi' contains a primitive root of 'f'. SetFieldOfMatrixGroup( g, f ); # construct the forms @@ -659,7 +685,7 @@ BindGlobal( "OpmOdd", function( s, d, q ) delta{[1,2]}{[1,2]} := [[0,1],[0,0]]*One( f ); delta[3,3] := beta; delta := ImmutableMatrix( f, delta, true ); - SetInvariantQuadraticFormFromMatrix( g, delta ); + SetInvariantQuadraticFormFromMatrix( g, delta, f ); # set the size delta := 1; @@ -697,7 +723,7 @@ BindGlobal( "Oplus2", function( q ) # construct the group, set the order, and return g := GroupWithGenerators( [ m1, m2 ] ); SetInvariantQuadraticFormFromMatrix( g, ImmutableMatrix( f, - [ [ 0, 1 ], [ 0, 0 ] ] * z^0, true ) ); + [ [ 0, 1 ], [ 0, 0 ] ] * z^0, true ), f ); SetSize( g, 2*(q-1) ); return g; end ); @@ -737,6 +763,8 @@ BindGlobal( "Oplus4Even", function( q ) g:=List(g,i->ImmutableMatrix(f,i,true)); g := GroupWithGenerators( g ); SetDimensionOfMatrixGroup( g, 4 ); + + # 'phi*rho' contains a primitive root of 'f'. SetFieldOfMatrixGroup( g, f ); # set the size @@ -744,7 +772,7 @@ BindGlobal( "Oplus4Even", function( q ) # construct the forms SetInvariantQuadraticFormFromMatrix( g, ImmutableMatrix( f, - [[0,1,0,0],[0,0,0,0],[0,0,0,1],[0,0,0,0]] * One( f ), true ) ); + [[0,1,0,0],[0,0,0,0],[0,0,0,1],[0,0,0,0]] * One( f ), true ), f ); # and return return g; @@ -847,6 +875,8 @@ BindGlobal( "OplusEven", function( d, q ) g:=List(g,i->ImmutableMatrix(f,i,true)); g := GroupWithGenerators( g ); SetDimensionOfMatrixGroup( g, d ); + + # 'phi*delta2' contains a primitive root of 'f'. SetFieldOfMatrixGroup( g, f ); # construct the forms @@ -854,7 +884,7 @@ BindGlobal( "OplusEven", function( d, q ) for i in [ 1 .. d/2 ] do delta[2*i-1,2*i] := One( f ); od; - SetInvariantQuadraticFormFromMatrix( g, ImmutableMatrix( f, delta, true ) ); + SetInvariantQuadraticFormFromMatrix( g, ImmutableMatrix( f, delta, true ), f ); # set the size delta := 1; @@ -914,7 +944,7 @@ BindGlobal( "Ominus2", function( q ) m2:=ImmutableMatrix(GF(q),m2,true); g := GroupWithGenerators( [ m1, m2 ] ); SetInvariantQuadraticFormFromMatrix( g, ImmutableMatrix( f, - [ [ 1, 1 ], [ 0, t ] ] * one, true ) ); + [ [ 1, 1 ], [ 0, t ] ] * one, true ), f ); SetSize( g, 2*(q+1) ); return g; @@ -965,6 +995,8 @@ BindGlobal( "Ominus4Even", function( q ) g:=List(g,i->ImmutableMatrix(f,i,true)); g := GroupWithGenerators( g ); SetDimensionOfMatrixGroup( g, 4 ); + + # 'phi*rho' contains a primitive root of 'f'. SetFieldOfMatrixGroup( g, f ); # set the size @@ -972,7 +1004,7 @@ BindGlobal( "Ominus4Even", function( q ) # construct the forms SetInvariantQuadraticFormFromMatrix( g, ImmutableMatrix( f, - [[0,1,0,0],[0,0,0,0],[0,0,t,1],[0,0,0,t]] * One( f ), true ) ); + [[0,1,0,0],[0,0,0,0],[0,0,t,1],[0,0,0,t]] * One( f ), true ), f ); # and return return g; @@ -1083,6 +1115,8 @@ BindGlobal( "OminusEven", function( d, q ) g:=List(g,i->ImmutableMatrix(f,i,true)); g := GroupWithGenerators( g ); SetDimensionOfMatrixGroup( g, d ); + + # 'phi*delta2' contains a primitive root of 'f'. SetFieldOfMatrixGroup( g, f ); # construct the forms @@ -1092,7 +1126,7 @@ BindGlobal( "OminusEven", function( d, q ) od; delta[3,3] := t; delta[4,4] := t; - SetInvariantQuadraticFormFromMatrix( g, ImmutableMatrix( f, delta, true ) ); + SetInvariantQuadraticFormFromMatrix( g, ImmutableMatrix( f, delta, true ), f ); # set the size delta := 1; @@ -1131,9 +1165,9 @@ BindGlobal( "OzeroOdd", function( d, q, b ) s:= ImmutableMatrix( f, [ [ One( f ) ] ], true ); g:= GroupWithGenerators( [ -s ] ); SetDimensionOfMatrixGroup( g, d ); - SetFieldOfMatrixGroup( g, f ); + SetFieldOfMatrixGroup( g, PrimeField( f ) ); SetSize( g, 2 ); - SetInvariantQuadraticFormFromMatrix( g, s ); + SetInvariantQuadraticFormFromMatrix( g, s, f ); return g; fi; @@ -1164,6 +1198,8 @@ BindGlobal( "OzeroOdd", function( d, q, b ) g:=List(g,i->ImmutableMatrix(f,i,true)); g := GroupWithGenerators( g ); SetDimensionOfMatrixGroup( g, d ); + + # 'phi' contains a primitive root of 'f'. SetFieldOfMatrixGroup( g, f ); # and set its size @@ -1179,7 +1215,7 @@ BindGlobal( "OzeroOdd", function( d, q, b ) # construct the forms s := b * IdentityMat( d, f ); s{[1,2]}{[1,2]} := [[0,1],[0,0]]*One( f ); - SetInvariantQuadraticFormFromMatrix( g, ImmutableMatrix( f, s, true ) ); + SetInvariantQuadraticFormFromMatrix( g, ImmutableMatrix( f, s, true ), f ); # and return return g; @@ -1232,9 +1268,9 @@ BindGlobal( "OzeroEven", function( d, q ) s:= ImmutableMatrix( f, [ [ o ] ], true ); g:= GroupWithGenerators( [], s ); SetDimensionOfMatrixGroup( g, d ); - SetFieldOfMatrixGroup( g, f ); + SetFieldOfMatrixGroup( g, PrimeField( f ) ); SetSize( g, 1 ); - SetInvariantQuadraticFormFromMatrix( g, s ); + SetInvariantQuadraticFormFromMatrix( g, s, f ); return g; elif d = 3 then @@ -1290,6 +1326,8 @@ BindGlobal( "OzeroEven", function( d, q ) # avoid to call 'Group' because this would check invertibility ... g:= GroupWithGenerators( [ mat1, mat2 ] ); SetDimensionOfMatrixGroup( g, d ); + + # 'mat1' contains a primitive root of 'f'. SetFieldOfMatrixGroup( g, f ); SetIsSubgroupSL( g, true ); @@ -1309,7 +1347,7 @@ BindGlobal( "OzeroEven", function( d, q ) s[(d-1)/2+i,i]:= o; od; s:= ImmutableMatrix( f, s, true ); - SetInvariantQuadraticFormFromMatrix( g, s ); + SetInvariantQuadraticFormFromMatrix( g, s, f ); # and return return g; @@ -1437,7 +1475,7 @@ InstallMethod( SpecialOrthogonalGroupCons, IsPosInt, IsPosInt ], function( filter, e, d, q ) - local G, gens, U, i; + local G, gens, U, i, F, form; G:= GeneralOrthogonalGroupCons( filter, e, d, q ); if q mod 2 = 1 then @@ -1465,8 +1503,13 @@ InstallMethod( SpecialOrthogonalGroupCons, String(q), ")" ) ); # Set the invariant quadratic form and the symmetric bilinear form. - SetInvariantBilinearForm( U, InvariantBilinearForm( G ) ); - SetInvariantQuadraticForm( U, InvariantQuadraticForm( G ) ); + F:= GF(q); + form:= InvariantBilinearForm( G ); + SetInvariantBilinearForm( U, rec( matrix:= form.matrix, + baseDomain:= F ) ); + form:= InvariantQuadraticForm( G ); + SetInvariantQuadraticForm( U, rec( matrix:= form.matrix, + baseDomain:= F ) ); SetIsFullSubgroupGLorSLRespectingQuadraticForm( U, true ); SetIsFullSubgroupGLorSLRespectingBilinearForm( U, true ); G:= U; @@ -1570,6 +1613,8 @@ BindGlobal( "OmegaZero", function( d, q ) g:= List( g, i -> ImmutableMatrix( f, i, true ) ); g:= GroupWithGenerators( g ); SetDimensionOfMatrixGroup( g, d ); + + # One of the generators contains a primitive root of 'f' or its square. SetFieldOfMatrixGroup( g, f ); # and set its size @@ -1591,7 +1636,7 @@ BindGlobal( "OmegaZero", function( d, q ) x[i,d-i+1] := o; od; x[m+1,m+1] := (Characteristic(f)+1)/4*o; - SetInvariantQuadraticFormFromMatrix(g, ImmutableMatrix( f, x, true ) ); + SetInvariantQuadraticFormFromMatrix(g, ImmutableMatrix( f, x, true ), f ); # and return return g; @@ -1683,6 +1728,11 @@ BindGlobal( "OmegaPlus", function( d, q ) g:= List( g, i -> ImmutableMatrix( f, i, true ) ); g:= GroupWithGenerators( g ); SetDimensionOfMatrixGroup( g, d ); + + # - If 'd = 4' then 'z:= Z(q^2)^(q-1)' generates the field 'GF(q^2)', + # and 'z + z^q' generates the field 'GF(q)' + # because 'z' is a root of 'x^2 - (z + z^q) * x + 1'. + # - If 'd <> 4' then the first generator contains a primitive root of 'f'. SetFieldOfMatrixGroup( g, f ); # and set its size @@ -1704,7 +1754,7 @@ BindGlobal( "OmegaPlus", function( d, q ) x[i,d-i+1] := o; od; x:= ImmutableMatrix( f, x, true ); - SetInvariantQuadraticFormFromMatrix( g, x ); + SetInvariantQuadraticFormFromMatrix( g, x, f ); # and return return g; @@ -1717,7 +1767,9 @@ BindGlobal( "OmegaPlus", function( d, q ) ## BindGlobal( "OmegaMinus", function( d, q ) local f, o, m, xi, mo, nu, nubar, nutrace, nuinvtrace, nunorm, h, x, n, - i, g, s, q2, q2i; + i, g, s, q2, q2i, form; + + f:= GF(q); # must be even if d mod 2 = 1 then @@ -1739,11 +1791,16 @@ BindGlobal( "OmegaMinus", function( d, q ) # and 'Omega(-1,2,q)' is its unique subgroup of index two. s:= GroupWithGenerators( [ h^2 ] ); fi; - SetInvariantBilinearForm( s, InvariantBilinearForm( g ) ); - SetInvariantQuadraticForm( s, InvariantQuadraticForm( g ) ); + form:= InvariantBilinearForm( g ); + SetInvariantBilinearForm( s, rec( matrix:= form.matrix, + baseDomain:= f ) ); + form:= InvariantQuadraticForm( g ); + SetInvariantQuadraticForm( s, rec( matrix:= form.matrix, + baseDomain:= f ) ); + # We do not call 'SetFieldOfMatrixGroup'. return s; fi; - f:= GF(q); + o:= One( f ); m:= d / 2 - 1; xi:= Z(q); @@ -1794,6 +1851,10 @@ BindGlobal( "OmegaMinus", function( d, q ) g:= List( g, i -> ImmutableMatrix( f, i, true ) ); g:= GroupWithGenerators( g ); SetDimensionOfMatrixGroup( g, d ); + + # 'h' contains the entries '-nutrace' and 'nunorm', + # at most one of them can lie in a proper subfield of 'f' + # because 'nu' is a root of 'x^2 - nutrace * x + nunorm'. SetFieldOfMatrixGroup( g, f ); # and set its size @@ -1819,7 +1880,7 @@ BindGlobal( "OmegaMinus", function( d, q ) x[m,d-m] := -o; x[m+1,d-m+1] := -xi; x:= ImmutableMatrix( f, x, true ); - SetInvariantQuadraticFormFromMatrix( g, x ); + SetInvariantQuadraticFormFromMatrix( g, x, f ); # and return return g; diff --git a/grp/ree.gi b/grp/ree.gi index 3fa172b0d3..54b8f95a26 100644 --- a/grp/ree.gi +++ b/grp/ree.gi @@ -76,7 +76,7 @@ local theta, m, f, bas, one, zero, x, h, r, gens, G, i; G:=Group(gens,One(gens[1])); SetName(G,Concatenation("Ree(",String(q),")")); SetDimensionOfMatrixGroup(G,7); - SetFieldOfMatrixGroup(G,f); + SetFieldOfMatrixGroup(G,f); # 'h(PrimitiveRoot(f))' contains a prim. root SetIsFinite(G,true); SetSize(G,q^3*(q-1)*(q^3+1)); SetIsSimpleGroup(G, q > 3); diff --git a/grp/suzuki.gi b/grp/suzuki.gi index 2e8f255bac..f6cb194086 100644 --- a/grp/suzuki.gi +++ b/grp/suzuki.gi @@ -52,7 +52,7 @@ function ( filter, q ) SetName(G,Concatenation("Sz(",String(q),")")); SetDimensionOfMatrixGroup(G,4); - SetFieldOfMatrixGroup(G,f); + SetFieldOfMatrixGroup(G,f); # the first generator contains a prim. root SetIsFinite(G,true); SetSize(G,q^2*(q-1)*(q^2+1)); SetIsSimpleGroup(G, q > 2); diff --git a/lib/grpffmat.gi b/lib/grpffmat.gi index 49aa289ed2..147563c60b 100644 --- a/lib/grpffmat.gi +++ b/lib/grpffmat.gi @@ -701,47 +701,24 @@ end ); ############################################################################# ## -#M NrConjugacyClasses( ) . . . . . . . . . . . . . . Method for GU(n,q) +#M NrConjugacyClasses( ) . . . . . . . . Method for GU(n,q) and SU(n,q) ## InstallMethod( NrConjugacyClasses, - "for GU(n,q)", - true, + "for GU(n,q) and SU(n,q)", [ IsFFEMatrixGroup and IsFinite and IsFullSubgroupGLorSLRespectingSesquilinearForm ], - 0, function ( G ) - local n,q; - if IsSubgroupSL(G) then TryNextMethod(); fi; - n := DimensionOfMatrixGroup(G); - q := RootInt(Size(FieldOfMatrixGroup(G))); + q := RootInt(Size(InvariantSesquilinearForm(G).baseDomain)); + if IsSubgroupSL(G) then + return NrConjugacyClassesSU(n,q); + fi; return NrConjugacyClassesGU(n,q); end ); -############################################################################# -## -#M NrConjugacyClasses( ) . . . . . . . . . . Method for natural SU(n,q) -## -InstallMethod( NrConjugacyClasses, - "for natural SU", - true, - [ IsFFEMatrixGroup and IsFinite - and IsFullSubgroupGLorSLRespectingSesquilinearForm - and IsSubgroupSL ], - 0, -function ( G ) - - local n,q; - - n := DimensionOfMatrixGroup(G); - q := RootInt(Size(FieldOfMatrixGroup(G))); - - return NrConjugacyClassesSU(n,q); -end ); - InstallGlobalFunction(ClassesProjectiveImage,function(act) local G,PG,cl,c,i,sel,p,z,a,x,prop,fus,f,reps,repi,repo,zel,fcl, diff --git a/lib/grpmat.gd b/lib/grpmat.gd index d2c9d0a906..8c9231140f 100644 --- a/lib/grpmat.gd +++ b/lib/grpmat.gd @@ -322,11 +322,20 @@ InstallTrueMethod(IsSubgroupSL,IsNaturalSL); ## ## ## -## This attribute describes a bilinear form that is invariant under the -## matrix group matgrp. -## The form is given by a record with the component matrix -## which is a matrix F such that for every generator g of -## matgrp the equation g \cdot F \cdot g^{tr} = F holds. +## For a matrix group matgrp, +## returns a record containing at least the components matrix, +## whose value is a matrix M, +## and baseDomain, whose value is a field. +##

+## This record describes a bilinear form that is invariant under +## matgrp. +## For every generator g of matgrp, +## the equation g \cdot M \cdot g^{tr} = M holds. +##

+## The attribute value is set for example in groups constructed with +## . +## Together with , +## it can be used for efficient membership tests in matgrp. ## ## ## <#/GAPDoc> @@ -343,11 +352,19 @@ DeclareAttribute( "InvariantBilinearForm", IsMatrixGroup ); ## ## ## -## This property tests, whether a matrix group matgrp is the full -## subgroup of GL or SL (the property determines -## which it is) in the right dimension over the (smallest) ring which -## contains all entries of its elements, respecting the form stored as the value of +## If this property is set then the matrix group matgrp is the full +## subgroup of GL(d, q) or SL(d, q) +## respecting the form stored as the value of ## for matgrp. +##

+## The value d is the value of +## matgrp, +## and q is the size of the baseDomain component of the +## record stored as . +##

+## The property of matgrp determines +## whether GL or SL is meant for +## . ## ## ## <#/GAPDoc> @@ -365,17 +382,25 @@ InstallTrueMethod( IsGroup, IsFullSubgroupGLorSLRespectingBilinearForm ); ## ## ## -## This attribute describes a sesquilinear form that is invariant under the -## matrix group matgrp over the field F with q^2 -## elements. -## The form is given by a record with the component matrix -## which is a matrix M such that for every generator g of -## matgrp +## For a matrix group matgrp, +## returns a record containing at least the components matrix, +## whose value is a matrix M, +## and baseDomain, whose value is a field F. +##

+## This record describes a sesquilinear form that is invariant under +## matgrp. +## For every generator g of matgrp, ## the equation g \cdot M \cdot (g^{tr})^f = M holds, -## where f is the automorphism of F that raises each element -## to its q-th power. +## where f is an automorphism of F. +## If F has q^2 elements then f raises each element +## of F to its q-th power. ## (f can be obtained as a power of the ## value of F.) +##

+## The attribute value is set for example in groups constructed with +## . Together with +## , +## it can be used for efficient membership tests in matgrp. ## ## ## <#/GAPDoc> @@ -392,10 +417,19 @@ DeclareAttribute( "InvariantSesquilinearForm", IsMatrixGroup ); ## ## ## -## This property tests, whether a matrix group matgrp is the full -## subgroup of GL or SL (the property determines -## which it is) respecting the form stored as the value of +## If this property is set then the matrix group matgrp is the full +## subgroup of GL(d, q) or SL(d, q) +## respecting the form stored as the value of ## for matgrp. +##

+## The value d is the value of +## matgrp, +## and q is the size of the baseDomain component of the +## record stored as . +##

+## The property of matgrp determines +## whether GL or SL is meant for +## . ## ## ## <#/GAPDoc> @@ -415,36 +449,41 @@ InstallTrueMethod( IsGroup, IsFullSubgroupGLorSLRespectingSesquilinearForm ); ## ## ## For a matrix group matgrp, -## returns a record containing at least the component matrix -## whose value is a matrix Q. -## The quadratic form q on the natural vector space V on which -## matgrp acts is given by q(v) = v Q v^{tr}, +## returns a record containing at least the components matrix, +## whose value is a matrix Q, +## and baseDomain, whose value is a field F. +##

+## The quadratic form q on the natural F-vector space V +## on which matgrp acts is given by q(v) = v Q v^{tr}, ## and the invariance under matgrp is given by the equation ## q(v) = q(v M) for all v \in V and M in ## matgrp. ## (Note that the invariance of q does not imply that the ## matrix Q is invariant under matgrp.) ##

-## q is defined relative to an invariant symmetric bilinear form -## f (see ), +## The function q is defined relative to an invariant symmetric +## bilinear form b (see ), ## via the equation ## q(\lambda x + \mu y) = -## \lambda^2 q(x) + \lambda \mu f(x,y) + \mu^2 q(y), +## \lambda^2 q(x) + \lambda \mu b(x,y) + \mu^2 q(y), ## see . -## If f is represented by the matrix F then this implies -## F = Q + Q^{tr}. -## In characteristic different from 2, we have q(x) = f(x,x)/2, +## If b is represented by the matrix B then this implies +## B = Q + Q^{tr}. +## In characteristic different from 2, we have q(x) = b(x,x)/2, ## so Q can be chosen as the strictly upper triangular part of -## F plus half of the diagonal part of F. -## In characteristic 2, F does not determine Q +## B plus half of the diagonal part of B. +## In characteristic 2, B does not determine Q ## but still Q can be chosen as an upper (or lower) triangular matrix. ##

## Whenever the value is set in a ## matrix group then also the value ## can be accessed, ## and the two values are compatible in the above sense. -## -## +##

+## The attribute value is set for example in groups constructed with +## . Together with +## , +## it can be used for efficient membership tests in matgrp. ## ## ## <#/GAPDoc> @@ -461,35 +500,45 @@ DeclareAttribute( "InvariantQuadraticForm", IsMatrixGroup ); ## ## ## -## This property tests, whether the matrix group matgrp is the full -## subgroup of GL or SL (the property determines -## which it is) in the right dimension over the (smallest) ring which -## contains all entries of its elements, -## respecting the value -## of matgrp. +## If this property is set then the matrix group matgrp is the full +## subgroup of GL(d, q) or SL(d, q) +## respecting the form stored as the value of +## for matgrp. +##

+## The value d is the value of +## matgrp, +## and q is the size of the baseDomain component of the +## record stored as . +##

+## The property of matgrp determines +## whether GL or SL is meant for +## . +##

## g:= Sp( 2, 3 );; ## gap> m:= InvariantBilinearForm( g ).matrix; ## [ [ 0*Z(3), Z(3)^0 ], [ Z(3), 0*Z(3) ] ] -## gap> [ 0, 1 ] * m * [ 1, -1 ]; # evaluate the bilinear form +## gap> [ 0, 1 ] * m * [ 1, -1 ]; # evaluate the bilinear form ## Z(3) ## gap> IsFullSubgroupGLorSLRespectingBilinearForm( g ); ## true ## gap> g:= SU( 2, 4 );; ## gap> m:= InvariantSesquilinearForm( g ).matrix; ## [ [ 0*Z(2), Z(2)^0 ], [ Z(2)^0, 0*Z(2) ] ] -## gap> [ 0, 1 ] * m * [ 1, 1 ]; # evaluate the bilinear form +## gap> [ 0, 1 ] * m * [ 1, 1 ]; # evaluate the sesquilinear form ## Z(2)^0 ## gap> IsFullSubgroupGLorSLRespectingSesquilinearForm( g ); ## true +## gap> IsSubgroupSL( g ); +## true ## gap> g:= GO( 1, 2, 3 );; ## gap> m:= InvariantBilinearForm( g ).matrix; ## [ [ 0*Z(3), Z(3)^0 ], [ Z(3)^0, 0*Z(3) ] ] -## gap> [ 0, 1 ] * m * [ 1, 1 ]; # evaluate the bilinear form +## gap> [ 0, 1 ] * m * [ 1, 1 ]; # evaluate the bilinear form ## Z(3)^0 ## gap> q:= InvariantQuadraticForm( g ).matrix; ## [ [ 0*Z(3), Z(3)^0 ], [ 0*Z(3), 0*Z(3) ] ] -## gap> [ 0, 1 ] * q * [ 0, 1 ]; # evaluate the quadratic form +## gap> [ 0, 1 ] * q * [ 0, 1 ]; # evaluate the quadratic form ## 0*Z(3) ## gap> IsFullSubgroupGLorSLRespectingQuadraticForm( g ); ## true diff --git a/lib/grpmat.gi b/lib/grpmat.gi index ac88311858..ee86ffcadd 100644 --- a/lib/grpmat.gi +++ b/lib/grpmat.gi @@ -846,6 +846,13 @@ InstallMethod( \in, "respecting quadratic form", IsElmsColls, # bilinear form, which is cheaper to check, # thus we install the current method first function( mat, G ) + # We may use `FieldOfMatrixGroup( G )` instead of `baseDomain` of the form. + # If 'FieldOfMatrixGroup( G )' differs from 'baseDomain' of the form + # then the former is a subset of the latter. + # Since 'mat' must be defined over 'FieldOfMatrixGroup( G )', + # we may check this perhaps stronger condition. + # This way, there are more situations where we get a 'false' result + # without checking whether the form is respected. return IsSubset( FieldOfMatrixGroup( G ), FieldOfMatrixList( [ mat ] ) ) and ( not IsSubgroupSL( G ) or IsOne( DeterminantMat( mat ) ) ) and RespectsQuadraticForm( InvariantQuadraticForm( G ).matrix, mat ); @@ -856,6 +863,8 @@ InstallMethod( \in, "respecting bilinear form", IsElmsColls, {} -> RankFilter( IsHandledByNiceMonomorphism ), # override nice mon. method function( mat, G ) local inv; + # We may use `FieldOfMatrixGroup( G )` instead of `baseDomain` of the form, + # see the comment for the '\in' method above. if not IsSubset( FieldOfMatrixGroup( G ), FieldOfMatrixList( [ mat ] ) ) or ( IsSubgroupSL( G ) and not IsOne( DeterminantMat( mat ) ) ) then return false; @@ -868,13 +877,16 @@ InstallMethod( \in, "respecting sesquilinear form", IsElmsColls, [ IsMatrix, IsFullSubgroupGLorSLRespectingSesquilinearForm ], {} -> RankFilter( IsHandledByNiceMonomorphism ), # override nice mon. method function( mat, G ) - local pow, inv; + local form, pow, inv; + # We may use `FieldOfMatrixGroup( G )` instead of `baseDomain` of the form, + # see the comment for the '\in' method above. if not IsSubset( FieldOfMatrixGroup( G ), FieldOfMatrixList( [ mat ] ) ) or ( IsSubgroupSL( G ) and not IsOne( DeterminantMat( mat ) ) ) then return false; fi; - pow:= RootInt( Size( FieldOfMatrixGroup( G ) ) ); - inv:= InvariantSesquilinearForm(G).matrix; + form:= InvariantSesquilinearForm(G); + pow:= RootInt( Size( form.baseDomain ) ); + inv:= form.matrix; return mat * inv * List( TransposedMat( mat ), row -> List( row, x -> x^pow ) ) = inv; @@ -1274,7 +1286,7 @@ InstallMethod( InvariantBilinearForm, InstallMethod( ConjugateGroup, ", ", IsCollsElms, [ IsMatrixGroup, IsMultiplicativeElementWithInverse ], function( G, g ) - local H, m, ginv; + local H, F, form, m, D, ginv, pow; H := GroupByGenerators( OnTuples( GeneratorsOfGroup( G ), g ), One( G ) ); UseIsomorphismRelation( G, H ); @@ -1287,27 +1299,45 @@ InstallMethod( ConjugateGroup, ", ", IsCollsElms, if HasIsSubgroupSL( G ) then SetIsSubgroupSL( H, IsSubgroupSL( G ) ); fi; + F:= FieldOfMatrixList( [ g ] ); if HasInvariantBilinearForm( G ) then if not IsBound( ginv ) then ginv := g^-1; fi; - m := ginv * InvariantBilinearForm( G ).matrix * TransposedMat( ginv ); - SetInvariantBilinearForm( H, rec( matrix := m ) ); + form := InvariantBilinearForm( G ); + m := ginv * form.matrix * TransposedMat( ginv ); + if not IsBound( D ) then + D:= form.baseDomain; + if not IsSubset( D, F ) then + D:= ClosureField( D, F ); + fi; + fi; + SetInvariantBilinearForm( H, rec( matrix := m, baseDomain := D ) ); fi; if HasInvariantQuadraticForm( G ) then if not IsBound( ginv ) then ginv := g^-1; fi; - m := ginv * InvariantQuadraticForm( G ).matrix * TransposedMat( ginv ); - SetInvariantQuadraticForm( H, rec( matrix := m ) ); + form := InvariantQuadraticForm( G ); + m := ginv * form.matrix * TransposedMat( ginv ); + if not IsBound( D ) then + D:= form.baseDomain; + if not IsSubset( D, F ) then + D:= ClosureField( D, F ); + fi; + fi; + SetInvariantQuadraticForm( H, rec( matrix := m, baseDomain := D ) ); fi; - if IsSubset( FieldOfMatrixGroup( G ), FieldOfMatrixList( [ g ] ) ) then + if IsSubset( FieldOfMatrixGroup( G ), F ) then if HasIsNaturalGL( G ) then SetIsNaturalGL( H, IsNaturalGL( G ) ); fi; if HasIsNaturalSL( G ) then SetIsNaturalSL( H, IsNaturalSL( G ) ); fi; + + # We have in particular that the 'baseDomain' of a stored invariant form + # contains 'F'. if HasIsFullSubgroupGLorSLRespectingBilinearForm( G ) and IsFullSubgroupGLorSLRespectingBilinearForm( G ) then SetIsFullSubgroupGLorSLRespectingBilinearForm( H, true ); @@ -1316,6 +1346,22 @@ InstallMethod( ConjugateGroup, ", ", IsCollsElms, and IsFullSubgroupGLorSLRespectingQuadraticForm( G ) then SetIsFullSubgroupGLorSLRespectingQuadraticForm( H, true ); fi; + + # For a stored sesquilinear form, we have to keep the meaning + # of the involutory field automorphism, + # which is defined by the 'baseDomain' component of the form. + # We transfer the form only if the field of definition does not grow. + if HasInvariantSesquilinearForm( G ) then + if not IsBound( ginv ) then + ginv:= g^-1; + fi; + form:= InvariantSesquilinearForm( G ); + D:= form.baseDomain; + pow:= RootInt( Size( D ) ); + m:= ginv * form.matrix * List( TransposedMat( ginv ), + row -> List( row, x -> x^pow ) ); + SetInvariantSesquilinearForm( H, rec( matrix:= m, baseDomain:= D ) ); + fi; fi; return H; end ); diff --git a/tst/testinstall/grp/classic-forms.tst b/tst/testinstall/grp/classic-forms.tst index 908e0693c4..f4748dd7b4 100644 --- a/tst/testinstall/grp/classic-forms.tst +++ b/tst/testinstall/grp/classic-forms.tst @@ -1,3 +1,10 @@ +#@local CheckGeneratorsInvertible, CheckGeneratorsSpecial, CheckField +#@local CheckBilinearForm, CheckQuadraticForm, frob, CheckSesquilinearForm +#@local CheckSize, CheckClasses, CheckMembershipFromForm +#@local CheckMembershipBilinear, CheckMembershipBilinear2 +#@local CheckMembershipSesquilinear +#@local CheckMembershipQuadratic, CheckMembershipQuadratic2 +#@local grps1, grps2, grps, d, q, G, m # # Tests invariant forms of classic groups # @@ -13,6 +20,12 @@ gap> CheckGeneratorsSpecial := function(G) > g -> IsOne(Determinant(g))); > end;; +# verify `FieldOfMatrixGroup` +gap> CheckField := function(G) +> return FieldOfMatrixGroup( G ) +> = FieldOfMatrixGroup( Group( GeneratorsOfGroup( G ), One( G ) ) ); +> end;; + # verify that forms are given and preserved gap> CheckBilinearForm := function(G) > local M; @@ -34,7 +47,7 @@ gap> frob := function(g,aut) gap> CheckSesquilinearForm := function(G) > local M, F, aut; > M := InvariantSesquilinearForm(G).matrix; -> F := FieldOfMatrixGroup(G); +> F := InvariantSesquilinearForm(G).baseDomain; > aut := FrobeniusAutomorphism(F); > aut := aut^(DegreeOverPrimeField(F)/2); > return ForAll(GeneratorsOfGroup(G), @@ -44,88 +57,167 @@ gap> CheckSesquilinearForm := function(G) # verify group size if the underlying module is small gap> CheckSize := function(g) > if Size(FieldOfMatrixGroup(g))^DimensionOfMatrixGroup(g) < 1000 then -> return Size(g) = Size(Group(GeneratorsOfGroup(g))); +> return Size(g) = Size(Group(GeneratorsOfGroup(g), One(g))); +> fi; +> return true; +> end;; + +# verify class numbers if the group is small +gap> CheckClasses:= function( G ) +> if Size(FieldOfMatrixGroup(G))^DimensionOfMatrixGroup(G) < 1000 then +> return NrConjugacyClasses(G) +> = NrConjugacyClasses(Group(GeneratorsOfGroup(G), One(G))); +> fi; +> return true; +> end;; + +# run some membership tests (there are special methods based on forms) +gap> CheckMembershipFromForm:= function( G, form ) +> local full; +> full:= GL( DimensionOfMatrixGroup( G ), form.baseDomain ); +> return ForAll( [ 1 .. 10 ], i -> PseudoRandom( G ) in G ) and +> ( ForAny( GeneratorsOfGroup( full ), g -> not ( g in G ) ) or +> Size( G ) = Size( full ) ); +> end;; +gap> CheckMembershipBilinear:= function( G ) +> return HasIsFullSubgroupGLorSLRespectingBilinearForm( G ) +> and IsFullSubgroupGLorSLRespectingBilinearForm( G ) +> and CheckMembershipFromForm( G, InvariantBilinearForm( G ) ); +> end;; +gap> CheckMembershipBilinear2:= function( G ) +> if HasIsFullSubgroupGLorSLRespectingBilinearForm( G ) +> and IsFullSubgroupGLorSLRespectingBilinearForm( G ) then +> return CheckMembershipFromForm( G, InvariantBilinearForm( G ) ); +> fi; +> return true; +> end;; +gap> CheckMembershipSesquilinear:= function( G ) +> return HasIsFullSubgroupGLorSLRespectingSesquilinearForm( G ) +> and IsFullSubgroupGLorSLRespectingSesquilinearForm( G ) +> and CheckMembershipFromForm( G, InvariantSesquilinearForm( G ) ); +> end;; +gap> CheckMembershipQuadratic:= function( G ) +> return HasIsFullSubgroupGLorSLRespectingQuadraticForm( G ) +> and IsFullSubgroupGLorSLRespectingQuadraticForm( G ) +> and CheckMembershipFromForm( G, InvariantQuadraticForm( G ) ); +> end;; +gap> CheckMembershipQuadratic2:= function( G ) +> if HasIsFullSubgroupGLorSLRespectingQuadraticForm( G ) +> and IsFullSubgroupGLorSLRespectingQuadraticForm( G ) then +> return CheckMembershipFromForm( G, InvariantQuadraticForm( G ) ); > fi; > return true; > end;; # odd-dimensional general orthogonal groups -gap> grps:=[];; -gap> for d in [3,5,7] do +gap> grps1:=[];; +gap> grps2:=[];; +gap> for d in [1,3,5,7] do > for q in [2,3,4,5,7,8,9,16,17,25,27] do -> Add(grps, GO(d,q)); -> Add(grps, GO(d,q) ^ RandomInvertibleMat(d,GF(q))); -> Add(grps, GO(d,q) ^ RandomInvertibleMat(d,GF(q^2))); +> Add(grps1, GO(d,q)); +> Add(grps2, GO(d,q) ^ RandomInvertibleMat(d,GF(q))); +> Add(grps2, GO(d,q) ^ RandomInvertibleMat(d,GF(q^2))); > od; > od; +gap> grps:= Concatenation( grps1, grps2 );; gap> ForAll(grps, CheckGeneratorsInvertible); true +gap> ForAll(grps, CheckField); +true gap> ForAll(grps, CheckBilinearForm); true gap> ForAll(grps, CheckQuadraticForm); true gap> ForAll(grps, CheckSize); true +gap> ForAll(grps1, CheckMembershipQuadratic); +true +gap> ForAll(grps2, CheckMembershipQuadratic2); +true # even-dimensional general orthogonal groups -gap> grps:=[];; +gap> grps1:=[];; +gap> grps2:=[];; gap> for d in [2,4,6,8] do > for q in [2,3,4,5,7,8,9,16,17,25,27] do -> Add(grps, GO(+1,d,q)); -> Add(grps, GO(-1,d,q)); -> Add(grps, GO(+1,d,q) ^ RandomInvertibleMat(d,GF(q))); -> Add(grps, GO(-1,d,q) ^ RandomInvertibleMat(d,GF(q))); -> Add(grps, GO(+1,d,q) ^ RandomInvertibleMat(d,GF(q^2))); -> Add(grps, GO(-1,d,q) ^ RandomInvertibleMat(d,GF(q^2))); +> Add(grps1, GO(+1,d,q)); +> Add(grps1, GO(-1,d,q)); +> Add(grps2, GO(+1,d,q) ^ RandomInvertibleMat(d,GF(q))); +> Add(grps2, GO(-1,d,q) ^ RandomInvertibleMat(d,GF(q))); +> Add(grps2, GO(+1,d,q) ^ RandomInvertibleMat(d,GF(q^2))); +> Add(grps2, GO(-1,d,q) ^ RandomInvertibleMat(d,GF(q^2))); > od; > od; +gap> grps:= Concatenation( grps1, grps2 );; gap> ForAll(grps, CheckGeneratorsInvertible); true +gap> ForAll(grps, CheckField); +true gap> ForAll(grps, CheckBilinearForm); true gap> ForAll(grps, CheckQuadraticForm); true gap> ForAll(grps, CheckSize); true +gap> ForAll(grps1, CheckMembershipQuadratic); +true +gap> ForAll(grps2, CheckMembershipQuadratic2); +true # odd-dimensional special orthogonal groups -gap> grps:=[];; -gap> for d in [3,5,7] do +gap> grps1:=[];; +gap> grps2:=[];; +gap> for d in [1,3,5,7] do > for q in [2,3,4,5,7,8,9,16,17,25,27] do -> Add(grps, SO(d,q)); -> Add(grps, SO(d,q) ^ RandomInvertibleMat(d,GF(q))); -> Add(grps, SO(d,q) ^ RandomInvertibleMat(d,GF(q^2))); +> Add(grps1, SO(d,q)); +> Add(grps2, SO(d,q) ^ RandomInvertibleMat(d,GF(q))); +> Add(grps2, SO(d,q) ^ RandomInvertibleMat(d,GF(q^2))); > od; > od; +gap> grps:= Concatenation( grps1, grps2 );; gap> ForAll(grps, CheckGeneratorsSpecial); true +gap> ForAll(grps, CheckField); +true gap> ForAll(grps, CheckBilinearForm); true gap> ForAll(grps, CheckQuadraticForm); true gap> ForAll(grps, CheckSize); true +gap> ForAll(grps1, CheckMembershipQuadratic); +true +gap> ForAll(grps2, CheckMembershipQuadratic2); +true # even-dimensional special orthogonal groups -gap> grps:=[];; +gap> grps1:=[];; +gap> grps2:=[];; gap> for d in [2,4,6,8] do > for q in [2,3,4,5,7,8,9,16,17,25,27] do -> Add(grps, SO(+1,d,q)); -> Add(grps, SO(-1,d,q)); -> Add(grps, SO(+1,d,q) ^ RandomInvertibleMat(d,GF(q))); -> Add(grps, SO(-1,d,q) ^ RandomInvertibleMat(d,GF(q))); -> Add(grps, SO(+1,d,q) ^ RandomInvertibleMat(d,GF(q^2))); -> Add(grps, SO(-1,d,q) ^ RandomInvertibleMat(d,GF(q^2))); +> Add(grps1, SO(+1,d,q)); +> Add(grps1, SO(-1,d,q)); +> Add(grps2, SO(+1,d,q) ^ RandomInvertibleMat(d,GF(q))); +> Add(grps2, SO(-1,d,q) ^ RandomInvertibleMat(d,GF(q))); +> Add(grps2, SO(+1,d,q) ^ RandomInvertibleMat(d,GF(q^2))); +> Add(grps2, SO(-1,d,q) ^ RandomInvertibleMat(d,GF(q^2))); > od; > od; +gap> grps:= Concatenation( grps1, grps2 );; gap> ForAll(grps, CheckGeneratorsSpecial); true +gap> ForAll(grps, CheckField); +true gap> ForAll(grps, CheckBilinearForm); true gap> ForAll(grps, CheckQuadraticForm); true gap> ForAll(grps, CheckSize); true +gap> ForAll(grps1, CheckMembershipQuadratic); +true +gap> ForAll(grps2, CheckMembershipQuadratic2); +true # # Omega subgroups of special orthogonal groups @@ -133,7 +225,7 @@ true # odd-dimensional gap> grps:=[];; -gap> for d in [3,5,7] do +gap> for d in [1,3,5,7] do > for q in [2,3,4,5,7,8,9,16,17,25,27] do > Add(grps, Omega(d,q)); > Add(grps, Omega(d,q) ^ RandomInvertibleMat(d,GF(q))); @@ -142,6 +234,8 @@ gap> for d in [3,5,7] do > od; gap> ForAll(grps, CheckGeneratorsSpecial); true +gap> ForAll(grps, CheckField); +true gap> ForAll(grps, CheckBilinearForm); true gap> ForAll(grps, CheckQuadraticForm); @@ -163,6 +257,8 @@ gap> for d in [2,4,6,8] do > od; gap> ForAll(grps, CheckGeneratorsSpecial); true +gap> ForAll(grps, CheckField); +true gap> ForAll(grps, CheckBilinearForm); true gap> ForAll(grps, CheckQuadraticForm); @@ -175,18 +271,26 @@ true # # general unitary groups -gap> grps:=[];; +gap> grps1:=[];; +gap> grps2:=[];; gap> for d in [1..6] do > for q in [2,3,4,5,7,8,9,16,17,25,27] do -> Add(grps, GU(d,q)); +> Add(grps1, GU(d,q)); +> Add(grps1, GU(d,q) ^ RandomInvertibleMat(d,GF(q^2))); +> Add(grps2, GU(d,q) ^ RandomInvertibleMat(d,GF(q^4))); > od; > od; +gap> grps:= Concatenation( grps1, grps2 );; gap> ForAll(grps, CheckGeneratorsInvertible); true -gap> ForAll(grps, CheckSesquilinearForm); +gap> ForAll(grps, CheckField); +true +gap> ForAll(grps1, CheckSesquilinearForm); true gap> ForAll(grps, CheckSize); true +gap> ForAll(grps1, CheckClasses); +true # special unitary groups gap> grps:=[];; @@ -197,28 +301,49 @@ gap> for d in [1..6] do > od; gap> ForAll(grps, CheckGeneratorsInvertible); true +gap> ForAll(grps, CheckField); +true gap> ForAll(grps, CheckSesquilinearForm); true gap> ForAll(grps, CheckSize); true +gap> ForAll(grps, CheckClasses); +true +gap> ForAll(grps, CheckMembershipSesquilinear); +true # # symplectic groups # -gap> grps:=[];; +gap> grps1:=[];; +gap> grps2:=[];; gap> for d in [2,4,6,8] do > for q in [2,3,4,5,7,8,9,16,17,25,27] do -> Add(grps, Sp(d,q)); -> Add(grps, Sp(d,q) ^ RandomInvertibleMat(d,GF(q))); -> Add(grps, Sp(d,q) ^ RandomInvertibleMat(d,GF(q^2))); +> Add(grps1, Sp(d,q)); +> Add(grps2, Sp(d,q) ^ RandomInvertibleMat(d,GF(q))); +> Add(grps2, Sp(d,q) ^ RandomInvertibleMat(d,GF(q^2))); > od; > od; +gap> grps:= Concatenation( grps1, grps2 );; gap> ForAll(grps, CheckGeneratorsSpecial); true +gap> ForAll(grps, CheckField); +true gap> ForAll(grps, CheckBilinearForm); true gap> ForAll(grps, CheckSize); true +gap> ForAll(grps1, CheckMembershipBilinear); +true +gap> ForAll(grps2, CheckMembershipBilinear2); +true + +# an undocumented helper function +gap> G:= GeneralOrthogonalGroup( 3, GF(5) );; +gap> m:= [ [ 0, 1, 0 ], [ 0, 0, 0 ], [ 0, 0, 1 ] ] * Z(5)^0;; +gap> SetInvariantQuadraticFormFromMatrix( G, m ); +Error, only the three argument variant of SetInvariantQuadraticFormFromMatrix \ +is supported, the form record needs a 'baseDomain' component # gap> STOP_TEST("classic-forms.tst"); From 74dd93522c6f223d96bd188c4afe0ebbfe09e9ce Mon Sep 17 00:00:00 2001 From: Max Horn Date: Wed, 28 Jan 2026 09:41:55 +0100 Subject: [PATCH 085/234] Fix two bugs in `IsomorphismPermGroupForMatrixGroup` (#6206) First bug: if the input group G has a nice monomorphism which has G as source, it is always returned, even if it is not surjective. Secondly, if G has a nice monomorphism whose range is not a perm group, then NicomorphismOfGeneralMatrixGroup is called to compute a new morphism into a permutation group. This is then also set as nice monomorphism -- but of course that only has an effect if no nice monomorphism had been set before. But if it was set before, then we might end up restricting the range of the new map produced by NicomorphismOfGeneralMatrixGroup to the wrong group (namely NiceObject(G)). As a bonus, also change IsomorphismPermGroupForMatrixGroup to return maps marked as bijective. --- lib/grpmat.gi | 13 ++- ...-26-IsomorphismPermGroupForMatrixGroup.tst | 108 ++++++++++++++++++ 2 files changed, 118 insertions(+), 3 deletions(-) create mode 100644 tst/testbugfix/2026-01-26-IsomorphismPermGroupForMatrixGroup.tst diff --git a/lib/grpmat.gi b/lib/grpmat.gi index ee86ffcadd..fa78cc88b0 100644 --- a/lib/grpmat.gi +++ b/lib/grpmat.gi @@ -556,7 +556,7 @@ end ); ## BindGlobal( "IsomorphismPermGroupForMatrixGroup", function(G) -local map; +local map,H; if HasNiceMonomorphism(G) and IsPermGroup(Range(NiceMonomorphism(G))) then map:=NiceMonomorphism(G); else @@ -567,10 +567,17 @@ local map; map:=NicomorphismOfGeneralMatrixGroup(G,false,false); SetNiceMonomorphism(G,map); fi; - if IsIdenticalObj(Source(map),G) then + if IsIdenticalObj(Source(map),G) and IsBijective(map) then return map; fi; - return GeneralRestrictedMapping(map,G,NiceObject(G)); + if IsIdenticalObj(map, NiceMonomorphism(G)) then + H:=NiceObject(G); + else + H:=ImagesSet(map,G); + fi; + map:=GeneralRestrictedMapping(map, G, H); + SetIsBijective(map, true); + return map; end); InstallMethod( IsomorphismPermGroup, diff --git a/tst/testbugfix/2026-01-26-IsomorphismPermGroupForMatrixGroup.tst b/tst/testbugfix/2026-01-26-IsomorphismPermGroupForMatrixGroup.tst new file mode 100644 index 0000000000..fffbcb2e72 --- /dev/null +++ b/tst/testbugfix/2026-01-26-IsomorphismPermGroupForMatrixGroup.tst @@ -0,0 +1,108 @@ +# Fix bug in IsomorphismPermGroupForMatrixGroup, see #6205 +#@local G, iso, H, nice +gap> START_TEST("IsomorphismPermGroupForMatrixGroup.tst"); + +# +# test with a nice mono that has a permutation group as range +# + +# Source(nice) = G, IsSurjective(nice) +gap> G:=Group(Z(3)^0*[[2,0],[0,1]]);; +gap> H:=CyclicGroup(IsPermGroup, 2);; +gap> nice:=GroupHomomorphismByFunction(G, H, x -> H.1^(2/Int(DeterminantMat(x))));; +gap> HasNiceMonomorphism(G); # double check: no nice mono has been set so far +false +gap> SetNiceMonomorphism(G, nice); +gap> IsBijective(IsomorphismPermGroupForMatrixGroup(G)); +true + +# Source(nice) = G, not IsSurjective(nice) +gap> G:=Group(Z(3)^0*[[2,0],[0,1]]);; +gap> H:=CyclicGroup(IsPermGroup, 4);; +gap> nice:=GroupHomomorphismByFunction(G, H, x -> H.1^(4/Int(DeterminantMat(x))));; +gap> HasNiceMonomorphism(G); # double check: no nice mono has been set so far +false +gap> SetNiceMonomorphism(G, nice); +gap> IsBijective(IsomorphismPermGroupForMatrixGroup(G)); +true + +# Source(nice) <> G, IsSurjective(nice) +gap> G:=Group(Z(3)^0*[[2,0],[0,1]]);; +gap> H:=CyclicGroup(IsPermGroup, 2);; +gap> nice:=GroupHomomorphismByFunction(GL(2,3), H, x -> H.1^(2/Int(DeterminantMat(x))));; +gap> HasNiceMonomorphism(G); # double check: no nice mono has been set so far +false +gap> SetNiceMonomorphism(G, nice); +gap> IsBijective(IsomorphismPermGroupForMatrixGroup(G)); +true + +# Source(nice) <> G, not IsSurjective(nice) +gap> G:=Group(Z(3)^0*[[2,0],[0,1]]);; +gap> H:=CyclicGroup(IsPermGroup, 4);; +gap> nice:=GroupHomomorphismByFunction(GL(2,3), H, x -> H.1^(4/Int(DeterminantMat(x))));; +gap> HasNiceMonomorphism(G); # double check: no nice mono has been set so far +false +gap> SetNiceMonomorphism(G, nice); +gap> IsBijective(IsomorphismPermGroupForMatrixGroup(G)); +true + +# +# test with a nice mono that does not have a permutation group as range +# + +# Source(nice) = G, IsSurjective(nice) +gap> G:=Group(Z(3)^0*[[2,0],[0,1]]);; +gap> H:=CyclicGroup(IsPcGroup, 2);; +gap> nice:=GroupHomomorphismByFunction(G, H, x -> H.1^(2/Int(DeterminantMat(x))));; +gap> HasNiceMonomorphism(G); # double check: no nice mono has been set so far +false +gap> SetNiceMonomorphism(G, nice); +gap> IsBijective(IsomorphismPermGroupForMatrixGroup(G)); +true + +# Source(nice) = G, not IsSurjective(nice) +gap> G:=Group(Z(3)^0*[[2,0],[0,1]]);; +gap> H:=CyclicGroup(IsPcGroup, 4);; +gap> nice:=GroupHomomorphismByFunction(G, H, x -> H.1^(4/Int(DeterminantMat(x))));; +gap> HasNiceMonomorphism(G); # double check: no nice mono has been set so far +false +gap> SetNiceMonomorphism(G, nice); +gap> IsBijective(IsomorphismPermGroupForMatrixGroup(G)); +true + +# Source(nice) <> G, IsSurjective(nice) +gap> G:=Group(Z(3)^0*[[2,0],[0,1]]);; +gap> H:=CyclicGroup(IsPcGroup, 2);; +gap> nice:=GroupHomomorphismByFunction(GL(2,3), H, x -> H.1^(2/Int(DeterminantMat(x))));; +gap> HasNiceMonomorphism(G); # double check: no nice mono has been set so far +false +gap> SetNiceMonomorphism(G, nice); +gap> IsBijective(IsomorphismPermGroupForMatrixGroup(G)); +true + +# Source(nice) <> G, not IsSurjective(nice) +gap> G:=Group(Z(3)^0*[[2,0],[0,1]]);; +gap> H:=CyclicGroup(IsPcGroup, 4);; +gap> nice:=GroupHomomorphismByFunction(GL(2,3), H, x -> H.1^(4/Int(DeterminantMat(x))));; +gap> HasNiceMonomorphism(G); # double check: no nice mono has been set so far +false +gap> SetNiceMonomorphism(G, nice); +gap> IsBijective(IsomorphismPermGroupForMatrixGroup(G)); +true + +# +# Verify that things that were computed as being isomorphisms +# also *know* they are isomorphisms +# +gap> G:=Group(Z(3)^0*[[2,0],[0,1]]);; +gap> iso:= IsomorphismPermGroupForMatrixGroup( G );; +gap> HasIsBijective( iso ); +true +gap> G:=Group(Z(3)^0*[[2,0],[0,1]]);; +gap> NiceMonomorphism( G );; +gap> iso:= IsomorphismPermGroupForMatrixGroup( G );; +gap> HasIsBijective( iso ); +true + +# +gap> STOP_TEST("IsomorphismPermGroupForMatrixGroup.tst"); From 33f8e8a9e3125d845be7d918b9ad8199f19301ff Mon Sep 17 00:00:00 2001 From: Thomas Breuer Date: Thu, 29 Jan 2026 16:20:25 +0100 Subject: [PATCH 086/234] a little bit better documentation for nice monomorphisms (#6211) --- doc/ref/grphomom.xml | 32 +++++++++++++++++++++++++++----- doc/tut/group.xml | 4 +++- 2 files changed, 30 insertions(+), 6 deletions(-) diff --git a/doc/ref/grphomom.xml b/doc/ref/grphomom.xml index aca92df9a7..9e4536c88a 100644 --- a/doc/ref/grphomom.xml +++ b/doc/ref/grphomom.xml @@ -344,11 +344,33 @@ nice monomorphism of a given group G, for example if G is a matrix group and map describes the faithful action of G on a small set of vectors. In such a case, one can prescribe this monomorphism via -SetNiceMonomorphism( G, map ), -provided that map stores that it is injective. -The latter can be achieved by calling IsInjective( map ) or, -if one is sure that map is injective and one wants to avoid the -overhead of the test, by calling SetIsInjective( map, true ). +SetNiceMonomorphism( G, map ) if certain technical requirements +are satisfied. +

+ + + G does not store a nice monomorphism already + (i.e., HasNiceMonomorphism( G ) returns false). + + + map stores that it is injective. + This can be achieved by calling IsInjective( map ) or, + if one is sure that map is injective and one wants to avoid the + overhead of the test, by calling SetIsInjective( map, true ). + Note that the IsInjective call for map may compute and store + some different nice monomorphism in the source of map, + which is probably G. + + + map knows that it is a group homomorphism, + calling with map and a subgroup of G + returns a group object, and analogously for an + image group returns a group object. + For example, + mappings constructed with will + not be nice enough to serve as nice monomorphisms. + + <#Include Label="IsHandledByNiceMonomorphism"> <#Include Label="NiceMonomorphism"> diff --git a/doc/tut/group.xml b/doc/tut/group.xml index 0eda9362fe..30061d16fe 100644 --- a/doc/tut/group.xml +++ b/doc/tut/group.xml @@ -1219,7 +1219,9 @@ composition of two maps (a nice monomorphism and an isomorphism) which know that they are injective. In general, the injectivity flag of a map map gets set if one tests the property by calling IsInjective( map ); -if one is sure that map is injective and wants to avoid the +note that this call may compute and store some different nice monomorphism +in the source of map. +If one is sure that map is injective and wants to avoid the potentially expensive test then one can set the flag by explicitly calling SetIsInjective( map, true ).

From dce75f7f8ff00beacf0e35c381a3792add249c82 Mon Sep 17 00:00:00 2001 From: Thomas Breuer Date: Sun, 1 Feb 2026 00:13:43 +0100 Subject: [PATCH 087/234] remove `\=` and `IsSubset` methods via nice monomorphism (#6216) * remove `\=` and `IsSubset` methods via nice monomorphism The next applicable methods for these two operations check membership for the generators in question via `\in`, and there is an `\in` method based on nice monomorphisms. Thus the nice monomorphism will still be used for the tasks, *except if* there are better methods for `\in`, which is the case for groups such as `GL(d, q)`, `SL(d, q)`, `Sp(d, q)`. In order to avoid the nice monomorphism for these groups, the alternative would be to install also dedicated `\=` and `IsSubset` methods for them, but I think the proposed removal of methods is better. * fix a test side-effect of the change: The `IsSubset( G, H )` test for a trivial group `H` now triggers the computation of generators of `H`, whereas the nice monomorphism based method did not change `H`. --- lib/grpnice.gi | 16 ---------------- tst/testinstall/morpheus.tst | 2 +- 2 files changed, 1 insertion(+), 17 deletions(-) diff --git a/lib/grpnice.gi b/lib/grpnice.gi index ec69eeaf40..9add52a1ee 100644 --- a/lib/grpnice.gi +++ b/lib/grpnice.gi @@ -191,14 +191,6 @@ InstallMethod( NiceMonomorphism, "via IsomorphismAbelianGroupViaIndependentGener end ); -############################################################################# -## -#M \=( , ) . . . . . . . . . . . . . . test if two groups are equal -## -PropertyMethodByNiceMonomorphismCollColl( \=, - [ IsGroup, IsGroup ] ); - - ############################################################################# ## #M \in( , ) . . . . . . . . . . . . . . . . . test if in @@ -527,14 +519,6 @@ PropertyMethodByNiceMonomorphism( IsSolvableGroup, [ IsGroup ] ); -############################################################################# -## -#M IsSubset( , ) . . . . . . . . . . . . . test for subset of groups -## -PropertyMethodByNiceMonomorphismCollColl( IsSubset, - [ IsGroup, IsGroup ] ); - - ############################################################################# ## #M IsSupersolvableGroup( ) . . . . . . test if a group is supersolvable diff --git a/tst/testinstall/morpheus.tst b/tst/testinstall/morpheus.tst index 56741335b5..79774f46b3 100644 --- a/tst/testinstall/morpheus.tst +++ b/tst/testinstall/morpheus.tst @@ -58,7 +58,7 @@ G (size 6) | C2 S (1 gens, size 3) | C3 -1 (size 1) +1 (0 gens, size 1) # that's all, folks gap> STOP_TEST("morpheus.tst"); From 7dd4916dca38f170320f83ad13749f675afdd09f Mon Sep 17 00:00:00 2001 From: Thomas Breuer Date: Sun, 1 Feb 2026 00:18:14 +0100 Subject: [PATCH 088/234] let `START_TEST` and `STOP_TEST` reset global options (#6215) --- lib/profile.g | 39 +++++++++++++++++++++++++++++++++------ 1 file changed, 33 insertions(+), 6 deletions(-) diff --git a/lib/profile.g b/lib/profile.g index fbb52c8236..afbae2a845 100644 --- a/lib/profile.g +++ b/lib/profile.g @@ -1047,15 +1047,33 @@ end); ## ## ## and may be optionally -## used in files that are read via . If used, -## reinitialize the caches and the global -## random number generator, in order to be independent of the reading -## order of several test files. Furthermore, the assertion level -## (see ) is set to 2 (if it was lower before) by +## used in files that are read via . +## If used, reinitializes +## +## +## the caches (see ), +## +## +## the global random number generators +## (see ), and +## +## +## the global options stack (see Chapter ), +## +## +## in order to be independent of the reading order +## of several test files. +##

+## Furthermore, the assertion level (see ) +## is set to 2 (if it was lower before) by ## and set back to the previous value in the ## subsequent call. ##

-## To use these options, a test file should be started with a line +## Also reinitializes the global options stack, +## otherwise it could happen that options which got set during the tests +## are not reset after the tests. +##

+## To use this feature, a test file should be started with a line ##

## START_TEST( "arbitrary identifier string" ); @@ -1080,6 +1098,11 @@ START_TEST := function( name ) FlushCaches(); Reset(GlobalRandomSource); Reset(GlobalMersenneTwister); + + while not IsEmpty(OptionsStack) do + PopOptions(); + od; + CollectGarbage(true); GAPInfo.TestData.START_TIME := Runtime(); GAPInfo.TestData.START_NAME := name; @@ -1115,6 +1138,10 @@ STOP_TEST_QUIET := function( name, args... ) Unbind( GAPInfo.TestData.START_NAME ); Unbind( GAPInfo.TestData.InfoPerformanceLevel ); + while not IsEmpty(OptionsStack) do + PopOptions(); + od; + return time; end; From 43757f74d5d9011ff014885df035c0ead5aafb03 Mon Sep 17 00:00:00 2001 From: Max Horn Date: Sun, 1 Feb 2026 10:00:54 +0100 Subject: [PATCH 089/234] Merge two DimensionOfMatrixGroup methods (#6212) ... by implementing a suggestion from a code comment. --- lib/grpmat.gi | 27 +++------------------------ 1 file changed, 3 insertions(+), 24 deletions(-) diff --git a/lib/grpmat.gi b/lib/grpmat.gi index fa78cc88b0..d0aa77d091 100644 --- a/lib/grpmat.gi +++ b/lib/grpmat.gi @@ -82,30 +82,9 @@ end ); ## #M DimensionOfMatrixGroup( ) ## -InstallMethod( DimensionOfMatrixGroup, "from generators", - [ IsMatrixGroup and HasGeneratorsOfGroup ], - function( grp ) - if not IsEmpty( GeneratorsOfGroup( grp ) ) then - return NumberRows( GeneratorsOfGroup( grp )[1] ); - else - TryNextMethod(); - fi; -end ); - -InstallMethod( DimensionOfMatrixGroup, "from one", - [ IsMatrixGroup and HasOne ], 1, - grp -> NumberRows( One( grp ) ) ); - -# InstallOtherMethod( DimensionOfMatrixGroup, -# "from source of nice monomorphism", -# [ IsMatrixGroup and HasNiceMonomorphism ], -# grp -> DimensionOfMatrixGroup( Source( NiceMonomorphism( grp ) ) ) ); -#T this was illegal, -#T since it assumes that the source is a different object than the -#T original group; if this fails then we run into an infinite recursion! - -#T why not delegate to `Representative' instead of installing -#T different methods? +InstallMethod( DimensionOfMatrixGroup, + [ IsMatrixGroup ], + grp -> NumberRows( Representative( grp ) ) ); ############################################################################# From d25bfa36b0180338cb443d0dfed560e3c18b90ae Mon Sep 17 00:00:00 2001 From: Max Horn Date: Mon, 2 Feb 2026 11:47:00 +0100 Subject: [PATCH 090/234] Turn RestrictedNiceMonomorphism into an attribute (#6217) --- lib/factgrp.gi | 4 ++-- lib/grpmat.gi | 18 +++++++----------- lib/grpnice.gd | 8 ++++---- lib/grpnice.gi | 46 +++++++++++++++++++++++----------------------- 4 files changed, 36 insertions(+), 40 deletions(-) diff --git a/lib/factgrp.gi b/lib/factgrp.gi index 7fecc44bef..c4f2306c2a 100644 --- a/lib/factgrp.gi +++ b/lib/factgrp.gi @@ -523,7 +523,7 @@ InstallMethod(FactorCosetAction,"by right transversal operation, Niceo", IsIdenticalObj,[IsGroup and IsHandledByNiceMonomorphism,IsGroup],0, function(G,U) local hom; - hom:=RestrictedNiceMonomorphism(NiceMonomorphism(G),G); + hom:=RestrictedNiceMonomorphism(G); return hom*DoFactorCosetAction(NiceObject(G),Image(hom,U)); end); @@ -532,7 +532,7 @@ InstallOtherMethod(FactorCosetAction, [IsGroup and IsHandledByNiceMonomorphism,IsGroup,IsGroup],0, function(G,U,N) local hom; - hom:=RestrictedNiceMonomorphism(NiceMonomorphism(G),G); + hom:=RestrictedNiceMonomorphism(G); return hom*DoFactorCosetAction(NiceObject(G),Image(hom,U),Image(hom,N)); end); diff --git a/lib/grpmat.gi b/lib/grpmat.gi index d0aa77d091..55296d9713 100644 --- a/lib/grpmat.gi +++ b/lib/grpmat.gi @@ -535,10 +535,8 @@ end ); ## BindGlobal( "IsomorphismPermGroupForMatrixGroup", function(G) -local map,H; - if HasNiceMonomorphism(G) and IsPermGroup(Range(NiceMonomorphism(G))) then - map:=NiceMonomorphism(G); - else +local map; + if not HasNiceMonomorphism(G) or not IsPermGroup(Range(NiceMonomorphism(G))) then if not HasIsFinite(G) then Info(InfoWarning,1, "IsomorphismPermGroup: The group is not known to be finite"); @@ -546,15 +544,13 @@ local map,H; map:=NicomorphismOfGeneralMatrixGroup(G,false,false); SetNiceMonomorphism(G,map); fi; - if IsIdenticalObj(Source(map),G) and IsBijective(map) then - return map; + if IsPermGroup(Range(NiceMonomorphism(G))) then + map:=RestrictedNiceMonomorphism(G); fi; - if IsIdenticalObj(map, NiceMonomorphism(G)) then - H:=NiceObject(G); - else - H:=ImagesSet(map,G); + if IsIdenticalObj(Source(map),G) and IsSurjective(map) then + return map; fi; - map:=GeneralRestrictedMapping(map, G, H); + map:=GeneralRestrictedMapping(map, G, ImagesSet(map,G)); SetIsBijective(map, true); return map; end); diff --git a/lib/grpnice.gd b/lib/grpnice.gd index 50986e5a79..b1e10bbbb9 100644 --- a/lib/grpnice.gd +++ b/lib/grpnice.gd @@ -62,13 +62,13 @@ DeclareFilter("IsNiceMonomorphism"); ############################################################################# ## -#O RestrictedNiceMonomorphism(,) +#A RestrictedNiceMonomorphism() ## ## -## +## ## ## -## returns the restriction of the nice monomorphism hom onto +## returns the restriction of the nice monomorphism of G onto ## G. ## In contrast to , ## this operation returns an object which has the filter @@ -89,7 +89,7 @@ DeclareFilter("IsNiceMonomorphism"); ## ## ## -DeclareGlobalFunction("RestrictedNiceMonomorphism"); +DeclareAttribute("RestrictedNiceMonomorphism", IsObject); ############################################################################# ## diff --git a/lib/grpnice.gi b/lib/grpnice.gi index 9add52a1ee..6e3db2bd6f 100644 --- a/lib/grpnice.gi +++ b/lib/grpnice.gi @@ -37,10 +37,16 @@ end); ############################################################################# ## -#O RestrictedNiceMonomorphism(,) +#O RestrictedNiceMonomorphism() ## -InstallGlobalFunction(RestrictedNiceMonomorphism, -function(hom,G) +InstallMethod(RestrictedNiceMonomorphism, + [IsObject], +function(G) + local hom; + hom:=NiceMonomorphism(G); + if IsIdenticalObj(Source(hom),G) and IsSurjective(hom) then + return hom; + fi; hom:=RestrictedMapping(hom,G:surjective); # CompositionMapping methods need this to avoid forming an AsGHBI of an @@ -542,9 +548,9 @@ InstallMethod(IsomorphismPermGroup,"via niceomorphisms",true, [ [ IsGroup and IsFinite ], 1 ], function(g) local mon,iso; - mon:=NiceMonomorphism(g); - if not IsIdenticalObj(Source(mon),g) then - mon:=RestrictedNiceMonomorphism(mon,g); + mon:=RestrictedNiceMonomorphism(g); + if IsPermGroup(Range(mon)) then + return mon; fi; iso:=IsomorphismPermGroup(NiceObject(g)); if iso=fail then @@ -565,9 +571,9 @@ InstallMethod(IsomorphismPcGroup,"via niceomorphisms",true, [IsGroup and IsFinite and IsHandledByNiceMonomorphism],0, function(g) local mon,iso; - mon:=NiceMonomorphism(g); - if not IsIdenticalObj(Source(mon),g) then - mon:=RestrictedNiceMonomorphism(mon,g); + mon:=RestrictedNiceMonomorphism(g); + if IsPcGroup(Range(mon)) then + return mon; fi; iso:=IsomorphismPcGroup(NiceObject(g)); if iso=fail then @@ -588,9 +594,9 @@ InstallOtherMethod(IsomorphismFpGroup,"via niceomorphism",true, [IsGroup and IsHandledByNiceMonomorphism,IsString],0, function(g,nam) local mon,iso; - mon:=NiceMonomorphism(g); - if not IsIdenticalObj(Source(mon),g) then - mon:=RestrictedNiceMonomorphism(mon,g); + mon:=RestrictedNiceMonomorphism(g); + if IsFpGroup(Range(mon)) then + return mon; fi; iso:=IsomorphismFpGroup(NiceObject(g),nam); if iso=fail then @@ -608,11 +614,8 @@ InstallMethod(IsomorphismFpGroupByGeneratorsNC,"via niceomorphism/w. gens", IsFamFamX,[IsGroup and IsHandledByNiceMonomorphism, IsList,IsString],0, function(g,c,nam) local mon,iso; - mon:=NiceMonomorphism(g); + mon:=RestrictedNiceMonomorphism(g); c:=List(c,i->Image(mon,i)); - if not IsIdenticalObj(Source(mon),g) then - mon:=RestrictedNiceMonomorphism(mon,g); - fi; iso:=IsomorphismFpGroupByGeneratorsNC(NiceObject(g),c,nam); if iso=fail then return fail; @@ -909,9 +912,9 @@ InstallMethod( NaturalHomomorphismByNormalSubgroupOp, IsIdenticalObj, function( G, N ) local nice; - nice := RestrictedNiceMonomorphism(NiceMonomorphism( G ),G); - G := ImagesSet( nice,G ); - N := ImagesSet ( nice, N ); + nice := RestrictedNiceMonomorphism(G); + G := ImagesSet( nice, G ); + N := ImagesSet( nice, N ); return CompositionMapping( NaturalHomomorphismByNormalSubgroup( G, N ), nice ); end ); @@ -930,10 +933,7 @@ local nice,geni,map2,tmp; fi; tmp := RUN_IN_GGMBI; RUN_IN_GGMBI:=true; - nice:=NiceMonomorphism(G); - if not IsIdenticalObj(Source(nice),G) then - nice:=RestrictedNiceMonomorphism(nice,G); - fi; + nice:=RestrictedNiceMonomorphism(G); geni:=List(gens,i->ImageElm(nice,i)); map2:=GroupGeneralMappingByImagesNC(NiceObject(G),H,geni,imgs); RUN_IN_GGMBI:=tmp; From 5726045551a573d2ebd4fa0ce2366a47fd524377 Mon Sep 17 00:00:00 2001 From: Thomas Breuer Date: Tue, 3 Feb 2026 12:56:49 +0100 Subject: [PATCH 091/234] Add `ConformalSymplecticGroup` (#6213) * Add `ConformalSymplecticGroup` ... and add some generalizations. - Add `ConformalSymplecticGroup`, essentially analogous to the implementation of `SymplecticGroup`, that is, - introduce a plain function `ConformalSymplecticGroup` and a constructor `ConformalSymplecticGroupCons`, - install various methods for `ConformalSymplecticGroupCons`, - introduce a property `IsFullSubgroupGLRespectingBilinearFormUpToScalars` that is set in the groups returned by `ConformalSymplecticGroup`, - install a `\in` method for a matrix and a group in `IsFullSubgroupGLRespectingBilinearFormUpToScalars`, - add tests for the new code. - In `ConformalSymplecticGroup`, `GeneralLinearGroup`, `SpecialLinearGroup`, and `SymplecticGroup`, support a filter that determines the representation of the matrices constructed as generators of the groups and as matrices of the invariant forms. (Note that `ConformalSymplecticGroup` and `SymplecticGroup` call `GeneralLinearGroup` and `SpecialLinearGroup`, respectively, for `n = 2`.) For that, an "experimental" global option `ConstructingFilter` is used. Currently `IsPlistRep` is the default value, `IsPlistRepMAtrix` is another possible value. (Eventually we want to support such a filter also for the other classical groups.) - Change the delegation between methods of `SymplecticGroup`: Do not delegate from the variant where a finite field is given to the variant with given size of the field, but the other way round. This way, it will be possible to use elements from `StandardFiniteField( p, n )` instead of `GF( p, n )` in the matrices. (Eventually we want to change this also for the other classical groups.) - Admit also `IsMatrixObj` in special `\in` methods (some tests in the Forms package will need this). Once we decide about the setup that we want for `ConformalSymplecticGroup`, implementations for other conformal classical group can be added, and the relevant methods in the Forms package can be adjusted and extended accordingly. --- doc/manualbib.xml | 9 ++ doc/ref/grpmat.xml | 2 + doc/ref/makedocreldata.g | 1 + grp/basicmat.gi | 28 +++-- grp/classic.gd | 64 +++++++--- grp/classic.gi | 161 +++++++++++++++----------- grp/conformal.gd | 140 ++++++++++++++++++++++ grp/conformal.gi | 143 +++++++++++++++++++++++ lib/grpmat.gi | 57 ++++++++- lib/read3.g | 1 + lib/read6.g | 1 + tst/testinstall/grp/classic-forms.tst | 54 ++++++++- 12 files changed, 569 insertions(+), 92 deletions(-) create mode 100644 grp/conformal.gd create mode 100644 grp/conformal.gi diff --git a/doc/manualbib.xml b/doc/manualbib.xml index de742a5709..efaf208565 100644 --- a/doc/manualbib.xml +++ b/doc/manualbib.xml @@ -4901,6 +4901,15 @@ https://arxiv.org/abs/2201.09155 + + + D. E.Taylor + + Conjugacy Classes in Finite Conformal Symplectic Groups + 2021 + https://www.maths.usyd.edu.au/u/don/code/Magma/CSpConjugacy.pdf + + HeikoTheißen diff --git a/doc/ref/grpmat.xml b/doc/ref/grpmat.xml index 7bc7074bb0..385766d71b 100644 --- a/doc/ref/grpmat.xml +++ b/doc/ref/grpmat.xml @@ -91,6 +91,8 @@ that represent a faithful action on vectors. <#Include Label="InvariantBilinearForm"> <#Include Label="IsFullSubgroupGLorSLRespectingBilinearForm"> +<#Include Label="InvariantBilinearFormUpToScalars"> +<#Include Label="IsFullSubgroupGLRespectingBilinearFormUpToScalars"> <#Include Label="InvariantSesquilinearForm"> <#Include Label="IsFullSubgroupGLorSLRespectingSesquilinearForm"> <#Include Label="InvariantQuadraticForm"> diff --git a/doc/ref/makedocreldata.g b/doc/ref/makedocreldata.g index 2221351de3..f2f1697bed 100644 --- a/doc/ref/makedocreldata.g +++ b/doc/ref/makedocreldata.g @@ -13,6 +13,7 @@ GAPInfo.ManualDataRef:= rec( "../../src/sysfiles.c", "../../grp/basic.gd", "../../grp/classic.gd", + "../../grp/conformal.gd", "../../grp/perf.gd", "../../grp/ree.gd", "../../grp/suzuki.gd", diff --git a/grp/basicmat.gi b/grp/basicmat.gi index 2420e81d89..fb05e8e6a9 100644 --- a/grp/basicmat.gi +++ b/grp/basicmat.gi @@ -139,23 +139,29 @@ InstallMethod( GeneralLinearGroupCons, IsInt and IsPosRat, IsField and IsFinite ], function( filter, n, f ) - local q, z, o, mat1, mat2, i, g; + local q, filt, z, o, mat1, mat2, i, g; q:= Size( f ); + # Decide about the internal representation of group generators. + filt:= ValueOption( "ConstructingFilter" ); + if filt = fail then + filt:= IsPlistRep; + fi; + # small cases if q = 2 and 1 < n then #T why 1 < n? - return SL( n, 2 ); + return SL( n, f ); fi; # construct the generators z := PrimitiveRoot( f ); o := One( f ); - mat1 := IdentityMat( n, f ); + mat1 := IdentityMatrix( filt, f, n ); mat1[1,1] := z; - mat2 := List( Zero(o) * mat1, ShallowCopy ); + mat2 := ZeroMatrix( filt, f, n, n ); mat2[1,1] := -o; mat2[1,n] := o; for i in [ 2 .. n ] do mat2[i,i-1]:= -o; od; @@ -189,13 +195,19 @@ InstallMethod( SpecialLinearGroupCons, IsField and IsFinite ], function( filter, n, f ) - local q, g, o, z, mat1, mat2, i, size, qi; + local q, filt, g, o, z, mat1, mat2, i, size, qi; q:= Size( f ); + # Decide about the internal representation of group generators. + filt:= ValueOption( "ConstructingFilter" ); + if filt = fail then + filt:= IsPlistRep; + fi; + # handle the trivial case first if n = 1 then - g := GroupByGenerators( [ ImmutableMatrix( f, [[One(f)]],true ) ] ); + g := GroupByGenerators( [ ImmutableMatrix( f, IdentityMatrix( filt, f, 1 ), true ) ] ); # now the general case else @@ -203,8 +215,8 @@ function( filter, n, f ) # construct the generators o := One(f); z := PrimitiveRoot(f); - mat1 := IdentityMat( n, f ); - mat2 := List( Zero(o) * mat1, ShallowCopy ); + mat1 := IdentityMatrix( filt, f, n ); + mat2 := ZeroMatrix( filt, f, n, n ); mat2[1,n] := o; for i in [ 2 .. n ] do mat2[i,i-1]:= -o; od; diff --git a/grp/classic.gd b/grp/classic.gd index 8562f2ab05..d5383269e3 100644 --- a/grp/classic.gd +++ b/grp/classic.gd @@ -18,20 +18,28 @@ ## <#GAPDoc Label="[1]{classic}"> ## The following functions return classical groups. ##

+## Generators +##

+## +## ## For the linear, symplectic, and unitary groups (the latter in dimension ## at least 3), ## the generators are taken from . +## +## ## For the unitary groups in dimension 2, the isomorphism of ## SU(2,q) and SL(2,q) is used, ## see for example . -##

+## +## ## The generators of the general and special orthogonal groups are taken ## from  and ## , ## except that the generators of the groups in odd dimension in even ## characteristic are constructed via the isomorphism to a symplectic group, ## see for example . -##

+## +## ## The generators of the groups \Omega^\epsilon(d, q) are taken ## from , ## except that in odd dimension and even characteristic, @@ -45,7 +53,8 @@ ## except in the case (d,q) = (5,2), ## where the matrices from  generate ## the simple group S_4(2)' and not the group S_4(2). -##

+## +## ## The generators for the semilinear groups are constructed from the ## generators of the corresponding linear groups plus one additional ## generator that describes the action of the group of field automorphisms; @@ -53,15 +62,36 @@ ## this yields the matrix groups GammaL(d, p^f) and ## SigmaL(d, p^f) as groups of d f \times df matrices ## over the field with p elements. +## +## +## The generators for the conformal symplectic groups are taken +## from . +## +## +##

+## Invariant forms ##

+## +## ## For symplectic and orthogonal matrix groups returned by the functions ## described below, the invariant bilinear form is stored as the value of ## the attribute . -## Analogously, the invariant sesquilinear form defining the unitary groups +## +## +## The invariant sesquilinear form defining the unitary groups ## is stored as the value of the attribute ## ). +## +## ## The defining quadratic form of orthogonal groups is stored as the value ## of the attribute . +## +## +## The bilinear form that is invariant up to scalars under the +## conformal symplectic group is stored as the value of the attribute +## . +## +## ##

## Note that due to the different sources for the generators, ## the invariant forms for the groups \Omega(e,d,q) are in general @@ -707,45 +737,51 @@ DeclareConstructor( "SymplecticGroupCons", [ IsGroup, IsPosInt, IsRing ] ); ############################################################################# ## +#F SymplecticGroup( [, ], [,

] ) . . . . symplectic group #F SymplecticGroup( [, ], [, ] ) . . . . symplectic group #F SymplecticGroup( [, ] ) . . . . . . . . . . symplectic group +#F Sp( [, ], [, ] ) #F Sp( [, ], [, ] ) #F Sp( [, ] ) +#F SP( [, ], [, ] ) #F SP( [, ], [, ] ) #F SP( [, ] ) ## ## <#GAPDoc Label="SymplecticGroup"> ## ## SymplecticGroup +## ## -## ## +## ## -## ## +## ## -## ## ## ## ## constructs a group isomorphic to the symplectic group -## Sp( d, q ) of those d \times d -## matrices over the field with q elements (respectively the ring -## ring) +## Sp( d, R ) of those d \times d +## matrices over the ring R or the field with q elements, +## respectively, ## that respect a fixed nondegenerate symplectic form, ## in the category given by the filter filt. ##

## If filt is not given it defaults to , ## and the returned group is the symplectic group itself. +## Another supported value for filt is +## ; +## in this case, the argument form is not supported. ##

## At the moment finite fields or residue class rings ## Integers mod q, with q an odd prime power, are @@ -759,7 +795,7 @@ DeclareConstructor( "SymplecticGroupCons", [ IsGroup, IsPosInt, IsRing ] ); ## or a group with stored value ## (and then this form is taken). ##

-## A given form determines and d, and also q +## A given form determines d, and also R ## except if form is a matrix that does not store its ## value. ## These parameters can be entered, and an error is signalled if they do diff --git a/grp/classic.gi b/grp/classic.gi index d45c39839f..aeab4095fe 100644 --- a/grp/classic.gi +++ b/grp/classic.gi @@ -12,78 +12,112 @@ ############################################################################# ## -#M SymplecticGroupCons( , , ) +#F GeneratorsAndFormOfSymplecticGroupOverFiniteField( , , , ) +## +## Return '[ , ]'. +## The function is used in 'SymplecticGroupCons' and +## 'ConformalSymplecticGroupCons'. +## +BindGlobal( "GeneratorsAndFormOfSymplecticGroupOverFiniteField", + function( filt, F, d, q ) + local o, mat1, mat2, z, i, c; + + # construct the generators of 'Sp(d, q)' + o:= One( F ); + if d = 4 and q = 2 then + # special case Sp(4,2) + mat1:= Matrix( filt, F, [1,0,1,1,1,0,0,1,0,1,0,1,1,1,1,1] * o, 4 ); + mat2:= Matrix( filt, F, [0,0,1,0,1,0,0,0,0,0,0,1,0,1,0,0] * o, 4 ); + else + z:= PrimitiveRoot( F ); + mat1:= IdentityMatrix( filt, F, d ); + mat2:= ZeroMatrix( filt, F, d, d ); + for i in [ 2 .. d/2 ] do mat2[i,i-1]:= o; od; + for i in [ d/2+1 .. d-1 ] do mat2[i,i+1]:= o; od; + + if q mod 2 = 1 then + mat1[ 1, 1] := z; + mat1[ d, d] := z^-1; + mat2[ 1, 1] := o; + mat2[ 1,d/2+1] := o; + mat2[d-1, d/2] := o; + mat2[ d, d/2] := -o; + elif q <> 2 then + mat1[ 1, 1] := z; + mat1[ d/2, d/2] := z; + mat1[d/2+1,d/2+1] := z^-1; + mat1[ d, d] := z^-1; + mat2[ 1,d/2-1] := o; + mat2[ 1, d/2] := o; + mat2[ 1,d/2+1] := o; + mat2[d/2+1, d/2] := o; + mat2[ d, d/2] := o; + else + mat1[ 1, d/2] := o; + mat1[ 1, d] := o; + mat1[d/2+1, d] := o; + mat2[ 1,d/2+1] := o; + mat2[ d, d/2] := o; + fi; + fi; + + mat1:= ImmutableMatrix( F, mat1, true ); + mat2:= ImmutableMatrix( F, mat2, true ); + + # construct the matrix of the form + c:= ZeroMatrix( filt, F, d, d ); + for i in [ 1 .. d/2 ] do + c[i,d-i+1]:= o; + c[d/2+i,d/2-i+1]:= -o; + od; + + return [ [ mat1, mat2 ], c ]; +end ); + + +############################################################################# +## +#M SymplecticGroupCons( , , ) ## InstallMethod( SymplecticGroupCons, - "matrix group for dimension and finite field size", + "matrix group for dimension and finite field", [ IsMatrixGroup and IsFinite, IsPosInt, - IsPosInt ], - function( filter, d, q ) - local g, f, z, o, mat1, mat2, i, size, qi, c; + IsField and IsFinite ], + function( filter, d, f ) + local q, o, filt, g, c, data, size, qi, i; # the dimension must be even if d mod 2 = 1 then Error( "the dimension must be even" ); fi; - f := GF(q); - z := PrimitiveRoot( f ); + q := Size( f ); o := One( f ); - # if the dimension is two it is a special linear group + # Decide about the internal representation of group generators. + filt:= ValueOption( "ConstructingFilter" ); + if filt = fail then + filt:= IsPlistRep; + fi; + if d = 2 then - g := SL( 2, q ); + # if the dimension is two it is a special linear group + g := SL( 2, f ); + c:= ZeroMatrix( filt, f, 2, 2 ); + c[1,2]:= o; + c[2,1]:= -o; else + data:= GeneratorsAndFormOfSymplecticGroupOverFiniteField( filt, + f, d, q ); + c:= data[2]; - # Sp(4,2) - if d = 4 and q = 2 then - mat1 := [ [1,0,1,1], [1,0,0,1], [0,1,0,1], [1,1,1,1] ] * o; - mat2 := [ [0,0,1,0], [1,0,0,0], [0,0,0,1], [0,1,0,0] ] * o; - - # Sp(d,q) - else - mat1 := IdentityMat( d, f ); - mat2 := NullMat( d, d, f ); - for i in [ 2 .. d/2 ] do mat2[i,i-1]:= o; od; - for i in [ d/2+1 .. d-1 ] do mat2[i,i+1]:= o; od; - - if q mod 2 = 1 then - mat1[ 1, 1] := z; - mat1[ d, d] := z^-1; - mat2[ 1, 1] := o; - mat2[ 1,d/2+1] := o; - mat2[d-1, d/2] := o; - mat2[ d, d/2] := -o; - - elif q <> 2 then - mat1[ 1, 1] := z; - mat1[ d/2, d/2] := z; - mat1[d/2+1,d/2+1] := z^-1; - mat1[ d, d] := z^-1; - mat2[ 1,d/2-1] := o; - mat2[ 1, d/2] := o; - mat2[ 1,d/2+1] := o; - mat2[d/2+1, d/2] := o; - mat2[ d, d/2] := o; - - else - mat1[ 1, d/2] := o; - mat1[ 1, d] := o; - mat1[d/2+1, d] := o; - mat2[ 1,d/2+1] := o; - mat2[ d, d/2] := o; - fi; - fi; - - mat1:=ImmutableMatrix(f,mat1,true); - mat2:=ImmutableMatrix(f,mat2,true); # avoid to call 'Group' because this would check invertibility ... - g := GroupWithGenerators( [ mat1, mat2 ] ); + g := GroupWithGenerators( data[1] ); SetName( g, Concatenation("Sp(",String(d),",",String(q),")") ); SetDimensionOfMatrixGroup( g, d ); - # 'mat1' contains a primitive root of 'f'. + # The first generator contains a primitive root of 'f'. SetFieldOfMatrixGroup( g, f ); # add the size @@ -96,12 +130,7 @@ InstallMethod( SymplecticGroupCons, SetSize( g, q^((d/2)^2) * size ); fi; - # construct the form - c := NullMat( d, d, f ); - for i in [ 1 .. d/2 ] do - c[i,d-i+1] := o; - c[d/2+i,d/2-i+1] := -o; - od; + # set the form SetInvariantBilinearForm( g, rec( matrix:= ImmutableMatrix( f, c, true ), baseDomain:= f ) ); SetIsFullSubgroupGLorSLRespectingBilinearForm(g,true); @@ -111,15 +140,17 @@ InstallMethod( SymplecticGroupCons, return g; end ); + +############################################################################# +## +#M SymplecticGroupCons( , , ) +## InstallMethod( SymplecticGroupCons, - "matrix group for dimension and finite field", + "matrix group for dimension and finite field size", [ IsMatrixGroup and IsFinite, IsPosInt, - IsField and IsFinite ], -function(filt,n,f) - return SymplecticGroupCons(filt,n,Size(f)); -end); - + IsPosInt ], + { filt, n, q } -> SymplecticGroupCons( filt, n, GF(q) ) ); ############################################################################# diff --git a/grp/conformal.gd b/grp/conformal.gd new file mode 100644 index 0000000000..c6d2788f9c --- /dev/null +++ b/grp/conformal.gd @@ -0,0 +1,140 @@ +############################################################################# +## +## conformal.gd +## +## Provide 'ConformalSymplecticGroup' and related functions. +## + + +############################################################################# +## +#A InvariantBilinearFormUpToScalars( ) +## +## <#GAPDoc Label="InvariantBilinearFormUpToScalars"> +## +## +## +## +## This attribute describes a bilinear form that is invariant up to scalars +## under the matrix group matgrp. +## The form is given by a record with the component matrix +## which is a matrix J such that for every generator g of +## matgrp the equation g \cdot J \cdot g^{tr} = \lambda(g) J +## holds, for \lambda(g) in the +## value of matgrp. +## +## +## <#/GAPDoc> +## +DeclareAttribute( "InvariantBilinearFormUpToScalars", IsMatrixGroup ); + + +############################################################################# +## +#P IsFullSubgroupGLRespectingBilinearFormUpToScalars( ) +## +## <#GAPDoc Label="IsFullSubgroupGLRespectingBilinearFormUpToScalars"> +## +## +## +## +## This property tests whether the matrix group matgrp is the full +## subgroup of GL respecting, up to scalars, the form stored as the value of +## for matgrp. +## +## +## <#/GAPDoc> +## +DeclareProperty( "IsFullSubgroupGLRespectingBilinearFormUpToScalars", + IsMatrixGroup ); + +InstallTrueMethod( IsGroup, + IsFullSubgroupGLRespectingBilinearFormUpToScalars ); + + +############################################################################# +## +#O ConformalSymplecticGroupCons( , , ) +#O ConformalSymplecticGroupCons( , , ) +## +DeclareConstructor( "ConformalSymplecticGroupCons", [ IsGroup, IsPosInt, IsRing ] ); +DeclareConstructor( "ConformalSymplecticGroupCons", [ IsGroup, IsPosInt, IsPosInt ] ); + + +############################################################################# +## +#F ConformalSymplecticGroup( [, ], [, ] ) conf. sympl. gp. +#F ConformalSymplecticGroup( [, ], [, ] ) conf. sympl. gp. +#F ConformalSymplecticGroup( [, ] ) conformal symplectic group +#F CSp( [, ], [, ] ) . . . . . conformal symplectic group +#F CSp( [, ], [, ] ) . . . . . conformal symplectic group +#F CSp( [, ] ) . . . . . . . . . . . conformal symplectic group +## +## <#GAPDoc Label="ConformalSymplecticGroup"> +## +## ConformalSymplecticGroup +## +## +## +## +## +## +## +## +## constructs a group isomorphic to the conformal symplectic group +## CSp( d, R ) of those d \times d +## matrices over the ring R or the field with q elements, +## respectively, +## that respect a fixed nondegenerate symplectic form up to scalars, +## in the category given by the filter filt. +##

+## Currently only finite fields R are supported. +##

+## If filt is not given it defaults to , +## and the returned group is the conformal symplectic group itself. +## Another supported value for filt is +## ; +## in this case, the argument form is not supported. +##

+## If version at least 1.2.15 of the Forms package is +## loaded and the arguments describe a matrix group over a finite field then +## the desired bilinear form can be specified via form, +## which can be either a matrix +## or a form object in +## or a group with stored or +## value +## (and then this form is taken). +##

+## A given form determines d, and also R +## except if form is a matrix that does not store its +## value. +## These parameters can be entered, and an error is signalled if they do +## not fit to the given form. +##

+## If form is not given then a default is chosen as described in the +## introduction to Section . +##

+## g:= ConformalSymplecticGroup( 4, 2 ); +## CSp(4,2) +## gap> Size( g ); +## 720 +## gap> StructureDescription( g ); +## "S6" +## gap> ConformalSymplecticGroup( IsPermGroup, 4, 2 ); +## Perm_CSp(4,2) +## ]]> +## +## +## <#/GAPDoc> +## +DeclareGlobalFunction( "ConformalSymplecticGroup" ); + +DeclareSynonym( "CSp", ConformalSymplecticGroup ); diff --git a/grp/conformal.gi b/grp/conformal.gi new file mode 100644 index 0000000000..430753f5c9 --- /dev/null +++ b/grp/conformal.gi @@ -0,0 +1,143 @@ + +# auxiliary function analogous to `DescribesInvariantBilinearForm` +BindGlobal( "DescribesInvariantBilinearFormUpToScalars", + obj -> IsMatrixOrMatrixObj( obj ) or + ( IsBoundGlobal( "IsBilinearForm" ) and + ValueGlobal( "IsBilinearForm" )( obj ) ) or + ( IsGroup( obj ) and HasInvariantBilinearForm( obj ) ) or + ( IsGroup( obj ) and HasInvariantBilinearFormUpToScalars( obj ) ) ); + + +############################################################################# +## +#F ConformalSymplecticGroup( [, ], [, ] ) conf. sympl. gp. +#F ConformalSymplecticGroup( [, ], [, ] ) conf. sympl. gp. +#F ConformalSymplecticGroup( [, ] ) conformal symplectic group +#F CSp( [, ], [, ] ) conformal symplectic group +#F CSp( [, ], [, ] ) conformal symplectic group +#F CSp( [, ] ) conformal symplectic group +## +InstallGlobalFunction( ConformalSymplecticGroup, function ( arg ) + local filt, form; + + if IsFilter( First( arg ) ) then + filt:= Remove( arg, 1 ); + else + filt:= IsMatrixGroup; + fi; + if DescribesInvariantBilinearFormUpToScalars( Last( arg ) ) then + # interpret this argument (matrix or form or group with stored form) + # as "up to scalars" + form:= Remove( arg ); + if Length( arg ) = 0 then + # ( [, ] ) + return ConformalSymplecticGroupCons( filt, form ); + elif Length( arg ) = 2 and IsPosInt( arg[1] ) + and ( IsRing( arg[2] ) or IsPosInt( arg[2] ) ) then + # ( [, ], , ) or ( [, ], , ) + return ConformalSymplecticGroupCons( filt, arg[1], arg[2], form ); + fi; + elif Length( arg ) = 2 and IsPosInt( arg[1] ) + and ( IsRing( arg[2] ) or IsPosInt( arg[2] ) ) then + # ( [, ], ) or ( [, ], ) + return ConformalSymplecticGroupCons( filt, arg[1], arg[2] ); + fi; + Error( "usage: ConformalSymplecticGroup( [, ], [, ] )\n", + "or ConformalSymplecticGroup( [, ], [, ] )\n", + "or ConformalSymplecticGroup( [, ] )" ); +end ); + + +############################################################################# +## +#M ConformalSymplecticGroupCons( , , ) +## +InstallMethod( ConformalSymplecticGroupCons, + "matrix group for dimension and finite field", + [ IsMatrixGroup and IsFinite, + IsPosInt, + IsField and IsFinite ], + function( filter, d, F ) + local q, o, filt, g, c, data, mat1, mat2, mat3, z, i, size, qi; + + # the dimension must be even + if d mod 2 = 1 then + Error( "the dimension must be even" ); + fi; + q:= Size( F ); + o:= One( F ); + + # Decide about the internal representation of group generators. + filt:= ValueOption( "ConstructingFilter" ); + if filt = fail then + filt:= IsPlistRep; + fi; + + if d = 2 then + # the group is a general linear group + g:= GL( 2, F ); + + c:= ZeroMatrix( filt, F, 2, 2 ); + c[1,2]:= o; + c[2,1]:= -o; + else + data:= GeneratorsAndFormOfSymplecticGroupOverFiniteField( filt, + F, d, q ); + c:= data[2]; + mat1:= data[1][1]; + mat2:= data[1][2]; + + mat3:= IdentityMatrix( filt, F, d ); + z:= PrimitiveRoot( F ); + for i in [ 1 .. d/2 ] do + mat3[i, i]:= z; + od; + mat3:= ImmutableMatrix( F, mat3, true ); + + # avoid to call 'Group' because this would check invertibility ... + g:= GroupWithGenerators( [ mat1, mat2, mat3 ] ); + SetName( g, Concatenation( "CSp(", String(d), ",", String(q), ")" ) ); + SetDimensionOfMatrixGroup( g, d ); + + # 'mat1' contains a primitive root of 'F'. + SetFieldOfMatrixGroup( g, F ); + + # add the size + size := 1; + qi := 1; + for i in [ 1 .. d/2 ] do + qi := qi * q^2; + size := size * (qi-1); + od; + SetSize( g, q^((d/2)^2) * size * (q-1) ); + fi; + + # set the form + SetInvariantBilinearFormUpToScalars( g, + rec( matrix:= ImmutableMatrix( F, c, true ), baseDomain:= F ) ); + SetIsFullSubgroupGLRespectingBilinearFormUpToScalars( g, true ); + + # and return + return g; +end ); + + +############################################################################# +## +#M ConformalSymplecticGroupCons( , , ) +## +InstallMethod( ConformalSymplecticGroupCons, + "matrix group for dimension and finite field size", + [ IsMatrixGroup and IsFinite, + IsPosInt, + IsPosInt ], + { filt, n, q } -> ConformalSymplecticGroupCons( filt, n, GF(q) ) ); + + +############################################################################# +## +## Support `IsPermGroup` as first argument in `ConformalSymplecticGroup`. +## +PermConstructor( ConformalSymplecticGroupCons, + [ IsPermGroup, IsInt, IsObject ], + IsMatrixGroup and IsFinite ); diff --git a/lib/grpmat.gi b/lib/grpmat.gi index 55296d9713..24b19cc4d1 100644 --- a/lib/grpmat.gi +++ b/lib/grpmat.gi @@ -821,7 +821,8 @@ BindGlobal( "RespectsQuadraticForm", function( Q, M ) #M in . . . . . . . . . . . . . . . . . . . . is form invariant? ## InstallMethod( \in, "respecting quadratic form", IsElmsColls, - [ IsMatrix, IsFullSubgroupGLorSLRespectingQuadraticForm ], + [ IsMatrixOrMatrixObj, + IsFullSubgroupGLorSLRespectingQuadraticForm ], {} -> RankFilter( IsHandledByNiceMonomorphism ), # override nice mon. method # this method is better than the one using a nice monom.; # it has the same rank as the method based on the inv. @@ -841,7 +842,8 @@ InstallMethod( \in, "respecting quadratic form", IsElmsColls, end ); InstallMethod( \in, "respecting bilinear form", IsElmsColls, - [ IsMatrix, IsFullSubgroupGLorSLRespectingBilinearForm ], + [ IsMatrixOrMatrixObj, + IsFullSubgroupGLorSLRespectingBilinearForm ], {} -> RankFilter( IsHandledByNiceMonomorphism ), # override nice mon. method function( mat, G ) local inv; @@ -856,7 +858,8 @@ function( mat, G ) end ); InstallMethod( \in, "respecting sesquilinear form", IsElmsColls, - [ IsMatrix, IsFullSubgroupGLorSLRespectingSesquilinearForm ], + [ IsMatrixOrMatrixObj, + IsFullSubgroupGLorSLRespectingSesquilinearForm ], {} -> RankFilter( IsHandledByNiceMonomorphism ), # override nice mon. method function( mat, G ) local form, pow, inv; @@ -874,6 +877,54 @@ function( mat, G ) = inv; end ); +# The forms package contains this function with the name '_IsEqualModScalars', +# note that the function 'IsEqualProjective' from the recog package +# cannot be used because the matrices that describe forms can have zero rows. +BindGlobal( "_IsEqualModScalars_GAP", + function( mat1, mat2 ) + local m, n, i, j, s; + + m:= NrRows( mat1 ); + if m <> NrRows( mat2 ) then + return false; + fi; + n:= NrCols( mat1 ); + if n <> NrCols( mat2 ) then + return false; + fi; + for i in [ 1 .. m ] do + for j in [ 1 .. n ] do + if not IsZero( mat1[ i, j ] ) then + s:= mat2[ i, j ] / mat1[ i, j ]; + if IsZero( s ) then + return false; + elif IsRowListMatrix( mat1 ) and IsRowListMatrix( mat2 ) then + # separate case for performance reasons + return ForAll( [ 1 .. m ], i -> s * mat1[i] = mat2[i] ); + fi; + return s * mat1 = mat2; + fi; + od; + od; + return IsZero( mat2 ); +end ); + +InstallMethod( \in, "respecting bilinear form up to scalars", IsElmsColls, + [ IsMatrixOrMatrixObj, + IsFullSubgroupGLRespectingBilinearFormUpToScalars ], + {} -> RankFilter( IsHandledByNiceMonomorphism ), # override nice mon. method +function( mat, G ) + local inv; + # We may use `FieldOfMatrixGroup( G )` instead of `baseDomain` of the form, + # see the comment for the '\in' method above. + if not IsSubset( FieldOfMatrixGroup( G ), + FieldOfMatrixList( [ mat ] ) ) then + return false; + fi; + inv:= InvariantBilinearFormUpToScalars( G ).matrix; + return _IsEqualModScalars_GAP( inv, mat * inv * TransposedMat( mat ) ); +end ); + ############################################################################# ## diff --git a/lib/read3.g b/lib/read3.g index 2aa5319200..baf3cf714c 100644 --- a/lib/read3.g +++ b/lib/read3.g @@ -208,6 +208,7 @@ ReadLib( "grpramat.gd" ); # group library ReadGrp( "basic.gd" ); ReadGrp( "classic.gd" ); +ReadGrp( "conformal.gd" ); ReadGrp( "perf.gd" ); ReadGrp( "suzuki.gd" ); ReadGrp( "ree.gd" ); diff --git a/lib/read6.g b/lib/read6.g index 7bc785bad1..147c352fe0 100644 --- a/lib/read6.g +++ b/lib/read6.g @@ -18,6 +18,7 @@ ReadGrp( "basicmat.gi" ); ReadGrp( "basicfp.gi" ); ReadGrp( "perf.grp" ); ReadGrp( "classic.gi" ); +ReadGrp( "conformal.gi" ); ReadGrp( "suzuki.gi" ); ReadGrp( "ree.gi" ); ReadGrp( "simple.gi" ); diff --git a/tst/testinstall/grp/classic-forms.tst b/tst/testinstall/grp/classic-forms.tst index f4748dd7b4..66c9baf899 100644 --- a/tst/testinstall/grp/classic-forms.tst +++ b/tst/testinstall/grp/classic-forms.tst @@ -1,7 +1,10 @@ #@local CheckGeneratorsInvertible, CheckGeneratorsSpecial, CheckField -#@local CheckBilinearForm, CheckQuadraticForm, frob, CheckSesquilinearForm +#@local CheckBilinearForm, CheckBilinearFormUpToScalars +#@local CheckQuadraticForm, frob, CheckSesquilinearForm #@local CheckSize, CheckClasses, CheckMembershipFromForm #@local CheckMembershipBilinear, CheckMembershipBilinear2 +#@local CheckMembershipBilinearUpToScalars +#@local CheckMembershipBilinearUpToScalars2 #@local CheckMembershipSesquilinear #@local CheckMembershipQuadratic, CheckMembershipQuadratic2 #@local grps1, grps2, grps, d, q, G, m @@ -33,6 +36,12 @@ gap> CheckBilinearForm := function(G) > return ForAll(GeneratorsOfGroup(G), > g -> g*M*TransposedMat(g) = M); > end;; +gap> CheckBilinearFormUpToScalars := function(G) +> local M; +> M := InvariantBilinearFormUpToScalars(G).matrix; +> return ForAll(GeneratorsOfGroup(G), +> g -> _IsEqualModScalars_GAP(g*M*TransposedMat(g), M)); +> end;; gap> CheckQuadraticForm := function(G) > local M, Q; > M := InvariantBilinearForm(G).matrix; @@ -77,7 +86,8 @@ gap> CheckMembershipFromForm:= function( G, form ) > full:= GL( DimensionOfMatrixGroup( G ), form.baseDomain ); > return ForAll( [ 1 .. 10 ], i -> PseudoRandom( G ) in G ) and > ( ForAny( GeneratorsOfGroup( full ), g -> not ( g in G ) ) or -> Size( G ) = Size( full ) ); +> Size( G ) = Size( full ) ) and +> not HasNiceMonomorphism( G ); > end;; gap> CheckMembershipBilinear:= function( G ) > return HasIsFullSubgroupGLorSLRespectingBilinearForm( G ) @@ -91,6 +101,20 @@ gap> CheckMembershipBilinear2:= function( G ) > fi; > return true; > end;; +gap> CheckMembershipBilinearUpToScalars:= function( G ) +> return HasIsFullSubgroupGLRespectingBilinearFormUpToScalars( G ) +> and IsFullSubgroupGLRespectingBilinearFormUpToScalars( G ) +> and CheckMembershipFromForm( G, +> InvariantBilinearFormUpToScalars( G ) ); +> end;; +gap> CheckMembershipBilinearUpToScalars2:= function( G ) +> if HasIsFullSubgroupGLRespectingBilinearFormUpToScalars( G ) +> and IsFullSubgroupGLRespectingBilinearFormUpToScalars( G ) then +> return CheckMembershipFromForm( G, +> InvariantBilinearFormUpToScalars( G ) ); +> fi; +> return true; +> end;; gap> CheckMembershipSesquilinear:= function( G ) > return HasIsFullSubgroupGLorSLRespectingSesquilinearForm( G ) > and IsFullSubgroupGLorSLRespectingSesquilinearForm( G ) @@ -338,6 +362,32 @@ true gap> ForAll(grps2, CheckMembershipBilinear2); true +# +# conformal symplectic groups +# +gap> grps1:=[];; +gap> grps2:=[];; +gap> for d in [2,4,6,8] do +> for q in [2,3,4,5,7,8,9,16,17,25,27] do +> Add(grps1, CSp(d,q)); +> Add(grps2, CSp(d,q) ^ RandomInvertibleMat(d,GF(q))); +> Add(grps2, CSp(d,q) ^ RandomInvertibleMat(d,GF(q^2))); +> od; +> od; +gap> grps:= Concatenation( grps1, grps2 );; +gap> ForAll(grps, CheckGeneratorsInvertible); +true +gap> ForAll(grps, CheckField); +true +gap> ForAll(grps1, CheckBilinearFormUpToScalars); +true +gap> ForAll(grps, CheckSize); +true +gap> ForAll(grps1, CheckMembershipBilinearUpToScalars); +true +gap> ForAll(grps2, CheckMembershipBilinearUpToScalars2); +true + # an undocumented helper function gap> G:= GeneralOrthogonalGroup( 3, GF(5) );; gap> m:= [ [ 0, 1, 0 ], [ 0, 0, 0 ], [ 0, 0, 1 ] ] * Z(5)^0;; From 393c22ae3a37e3566bfe466ff03a7c0e9090ce99 Mon Sep 17 00:00:00 2001 From: Max Horn Date: Mon, 9 Feb 2026 09:57:30 +0100 Subject: [PATCH 092/234] CI: switch some jobs to using ubuntu-slim (#6208) See https://github.blog/changelog/2026-01-22-1-vcpu-linux-runner-now-generally-available-in-github-actions/ --- .github/workflows/lint.yml | 2 +- .github/workflows/release.yml | 4 ++-- .github/workflows/update-gh-pages.yml | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 04502aa792..bbf8e68ac8 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -12,7 +12,7 @@ on: jobs: gaplint: - runs-on: ubuntu-latest + runs-on: ubuntu-slim steps: - name: "Check out the repository" uses: actions/checkout@v6 diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 33cfea1350..ed6f358f39 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -33,7 +33,7 @@ env: jobs: tools: name: "Validate release scripts" - runs-on: ubuntu-latest + runs-on: ubuntu-slim steps: - uses: actions/checkout@v6 @@ -262,7 +262,7 @@ jobs: - unix - cygwin if: ${{ always() && github.event_name != 'pull_request' && github.repository == 'gap-system/gap' }} - runs-on: ubuntu-latest + runs-on: ubuntu-slim steps: - name: Get branch name diff --git a/.github/workflows/update-gh-pages.yml b/.github/workflows/update-gh-pages.yml index 3f1b21e41c..9c82e1d1d4 100644 --- a/.github/workflows/update-gh-pages.yml +++ b/.github/workflows/update-gh-pages.yml @@ -25,7 +25,7 @@ concurrency: jobs: # Build job build: - runs-on: ubuntu-latest + runs-on: ubuntu-slim steps: - name: Install dependencies run: | @@ -76,7 +76,7 @@ jobs: environment: name: github-pages url: ${{ steps.deployment.outputs.page_url }} - runs-on: ubuntu-latest + runs-on: ubuntu-slim needs: build steps: - name: Deploy to GitHub Pages From 51235b2f4cdad951f9f74a37351c595fabcdf540 Mon Sep 17 00:00:00 2001 From: Max Horn Date: Mon, 9 Feb 2026 13:14:09 +0100 Subject: [PATCH 093/234] Fix CoverageLineByLine (#6218) Let it produce output compatible with the `--coverage` command line option. --- lib/newprofile.g | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/newprofile.g b/lib/newprofile.g index 4639d329b4..f78b7da9e1 100644 --- a/lib/newprofile.g +++ b/lib/newprofile.g @@ -115,7 +115,7 @@ end); ## <#/GAPDoc> BIND_GLOBAL("CoverageLineByLine", function(name) - return ProfileLineByLine(name, rec(coverage := true)); + return ProfileLineByLine(name, rec(coverage := true, recordMem := true)); end); ############################################################################# From cba67aada255b6b634baeab35c17ed3e45e80f37 Mon Sep 17 00:00:00 2001 From: stertooy <5571903+stertooy@users.noreply.github.com> Date: Mon, 16 Feb 2026 11:05:27 +0100 Subject: [PATCH 094/234] Fix input for setup-cygwin@v2 in CI.yml (#6233) --- .github/workflows/CI.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index 170c80a564..89e7245119 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -151,7 +151,7 @@ jobs: - uses: gap-actions/setup-cygwin@v2 if: ${{ runner.os == 'Windows' }} with: - PKGS_TO_INSTALL: 'wget,git,gcc-g++,gcc-core,m4,libgmp-devel,make,automake,libtool,autoconf,autoconf2.5,zlib-devel,libreadline-devel,libmpc-devel,libmpfr-devel,xdg-utils,pkg-config' + extra-pkgs-to-install: 'libmpc-devel,libmpfr-devel,pkg-config' # There are two cygwin installs on github actions (ours, # and a preinstalled one which we can't use as not enough packages are installed. From c890f936c9d723c1cc7786fcc2f853a3fe331ece Mon Sep 17 00:00:00 2001 From: Thomas Breuer Date: Sat, 21 Feb 2026 21:21:41 +0100 Subject: [PATCH 095/234] fix the documentation of `NewFamily` (#6220) --- lib/type1.g | 29 +++++++++++++++++------------ 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/lib/type1.g b/lib/type1.g index 9ea3efdb77..95a661b687 100644 --- a/lib/type1.g +++ b/lib/type1.g @@ -61,24 +61,24 @@ InstallAttributeFunction( ## ## ## -## returns a new family fam with name +## returns a new family fam with name ## name. -## The argument req, if present, is a filter of which fam -## shall be a subset. -## If one tries to create an object in fam that does not lie in the -## filter req, an error message is printed. -## Also the argument imp, if present, -## is a filter of which fam shall be a subset. -## Any object that is created in the family fam will lie -## automatically in the filter imp. +## The arguments req and imp, if present, are filters of which +## fam shall be a subset. +## Any type that is created for fam (see ) will +## describe objects in these filters, and thus +## any object that is created in fam (see ) +## will lie automatically in req and imp. +## (Thus it does not matter whether one uses req or imp +## or both in the call, the distinction has only historical reasons.) ##

## The filter famfilter, if given, specifies a filter that will hold -## for the family fam (not for objects in fam). +## for the object fam itself (not for objects in fam). ##

## Families are always represented as component objects ## (see ). -## This means that components can be used to store and access -## useful information about the family. +## This means that individual components can be set in fam +## in order to store and access useful information about it. ## ## ## <#/GAPDoc> @@ -118,6 +118,11 @@ BIND_GLOBAL( "NEW_FAMILY", fi; SET_TYPE_COMOBJ( family, type ); family!.NAME := IMMUTABLE_COPY_OBJ(name); + # The component 'REQ_FLAGS' corresponds to the argument 'req_filter', + # but 'IMP_FLAGS' corresponds to 'AND_FLAGS( imp_filter, req_filter )'. + # In practice, 'REQ_FLAGS' is not used, except for printing the family. + # We cannot get rid of the 'req' argument of 'NewFamily' because of its + # optional fourth argument. family!.REQ_FLAGS := req_filter; family!.IMP_FLAGS := imp_filter; family!.nTYPES := 0; From 2d85105d0957161fcd7cbbba3ba91a040a3053d0 Mon Sep 17 00:00:00 2001 From: Thomas Breuer Date: Wed, 25 Feb 2026 23:59:03 +0100 Subject: [PATCH 096/234] fix a side-effect of `MaximalAbelianQuotient` (#6246) The `MaximalAbelianQuotient` method for f.p. groups sets the `AbelianInvariants` value, but the format of this value was in general not correct --- lib/ghomfp.gi | 2 +- .../2026-02-23-AbelianInvariants.tst | 18 ++++++++++++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) create mode 100644 tst/testbugfix/2026-02-23-AbelianInvariants.tst diff --git a/lib/ghomfp.gi b/lib/ghomfp.gi index d9e46e4a03..0a1b2b5448 100644 --- a/lib/ghomfp.gi +++ b/lib/ghomfp.gi @@ -1084,7 +1084,7 @@ local m,s,g,i,j,gen,img,hom,d,pos; d:=DiagonalOfMat(s.normal); pos:=Filtered([1..Length(d)],x->d[x]<>1); d:=d{pos}; - SetAbelianInvariants(f,d); + SetAbelianInvariants( f, AbelianInvariantsOfList( d ) ); # Make abelian group g:=AbelianGroup(d); diff --git a/tst/testbugfix/2026-02-23-AbelianInvariants.tst b/tst/testbugfix/2026-02-23-AbelianInvariants.tst new file mode 100644 index 0000000000..ae0e4ffbb4 --- /dev/null +++ b/tst/testbugfix/2026-02-23-AbelianInvariants.tst @@ -0,0 +1,18 @@ +# Fix bug in MaximalAbelianQuotient +# (format of the AbelianInvariants value) +#@local G +gap> START_TEST("AbelianInvariants.tst"); + +# +gap> G:= AbelianGroup( IsFpGroup, [ 2, 3, 4 ] );; +gap> AbelianInvariants( G ); +[ 2, 3, 4 ] +gap> G:= AbelianGroup( IsFpGroup, [ 2, 3, 4 ] );; +gap> MaximalAbelianQuotient( G );; # sets the abelian invariants +gap> HasAbelianInvariants( G ); +true +gap> AbelianInvariants( G ); +[ 2, 3, 4 ] + +# +gap> STOP_TEST("AbelianInvariants.tst"); From 1f2808cf3ffa1c17376326ed98689a5b330fd2af Mon Sep 17 00:00:00 2001 From: Thomas Breuer Date: Thu, 26 Feb 2026 00:00:54 +0100 Subject: [PATCH 097/234] Fix `IteratorStabChain` for groups with memory (#6243) --- lib/stbc.gi | 13 ++++++++----- tst/testinstall/memory.tst | 11 ++++++++++- 2 files changed, 18 insertions(+), 6 deletions(-) diff --git a/lib/stbc.gi b/lib/stbc.gi index 8b8bdebd0a..973f6db5db 100644 --- a/lib/stbc.gi +++ b/lib/stbc.gi @@ -1778,7 +1778,7 @@ function(iter) else iter!.state := 1; fi; - return (); + return iter!.one; elif iter!.state = 1 then l := Length(iter!.stack); # Identity is special cased since we only want to @@ -1815,22 +1815,25 @@ end); InstallGlobalFunction(IteratorStabChain, function(S) - local r,lstack; + local r, lstack, one; lstack := ListStabChain(S); + one:= lstack[1].identity; Remove(lstack); while Length(lstack) > 0 and Length(Last(lstack).orbit) = 1 do Remove(lstack); od; r := rec ( - stack := lstack + one:= one + , stack := lstack , pos := List(lstack, x -> 1) , epos := List(lstack, x -> Length(x.orbit)) - , rep := List(lstack, x -> ()) + , rep := List(lstack, x -> one) , state := 0 , NextIterator := NextIterator_StabChain , IsDoneIterator := iter -> (iter!.state = 2) - , ShallowCopy := iter -> rec( stack := iter!.stack + , ShallowCopy := iter -> rec( one := iter!.one + , stack := iter!.stack , pos := ShallowCopy(iter!.pos) , epos := iter!.epos , rep := ShallowCopy(iter!.rep) diff --git a/tst/testinstall/memory.tst b/tst/testinstall/memory.tst index 777bdd48c2..93eececfbc 100644 --- a/tst/testinstall/memory.tst +++ b/tst/testinstall/memory.tst @@ -1,4 +1,5 @@ -#@local G, H, g, h, tmp, stabChain, s1, s2, a, S, prod, i, v, s, pow, m, mm +#@local G, H, g, h, tmp, stabChain, iter, s1, s2, a, S, prod, i, v, s, pow +#@local m, mm gap> START_TEST( "memory.tst" ); # @@ -25,6 +26,14 @@ gap> stabChain.labels[1]; gap> StripStabChain(stabChain);; gap> stabChain.labels[1]; () +gap> tmp := GroupWithMemory(GroupByGenerators([ (1,2,3,4,5), (1,2) ]));; +gap> iter := Iterator(tmp);; +gap> NextIterator(iter); +<() with mem> +gap> iter := IteratorStabChain(StabChain(GroupWithMemory([ () ])));; +gap> iter := ShallowCopy( iter );; +gap> NextIterator(iter); +<() with mem> gap> s1 := SLPOfElm(g);; gap> g = ResultOfStraightLineProgram(s1, GeneratorsOfGroup(H)); true From b16890d62f3d092bb8417d7df87015f82666cb07 Mon Sep 17 00:00:00 2001 From: Thomas Breuer Date: Tue, 3 Mar 2026 09:14:23 +0100 Subject: [PATCH 098/234] Fix `PreImagesRepresentative` for group homomorphisms with `OnLines` action (#6245) fix `LinearActionBasis` for `IsProjectiveActionHomomorphism` --- lib/oprt.gi | 83 ++++++++++++++++++++++++++++------------------------- 1 file changed, 44 insertions(+), 39 deletions(-) diff --git a/lib/oprt.gi b/lib/oprt.gi index 882014725f..a94fffac60 100644 --- a/lib/oprt.gi +++ b/lib/oprt.gi @@ -3508,60 +3508,65 @@ end); ############################################################################# ## -#A LinearActionBasis() +#M LinearActionBasis() +## +## Under certain conditions, a homomorphism for a projective action can use +## linear algebra to compute preimages: +## +## - The set of normed vectors on which the group acts contains a basis of +## the vector space, +## - there is another normed vector whose coefficients w.r.t. this basis +## are all nonzero, +## - either the acting group contains all scalar matrices over the field +## of definition +## or the acting group is contained in the special linear group and +## the determinant of a matrix in the general linear group determines +## uniquely a scalar that multiplies the matrix into the special linear +## group. +## +## 'LinearActionBasis' checks a stronger variant of these conditions. +## If they are satisfied then it returns the vectors of the basis, +## and sets additional components in 'hom'. +## If they are not satisfied then 'fail' is returned. ## InstallOtherMethod(LinearActionBasis,"projective with extra vector",true, [IsProjectiveActionHomomorphism],0, function(hom) -local xset,D,b,t,i,r,binv,pos,kero,dets,roots,dim,f; +local xset,G,D,b,t,i,r,binv,pos,dets,roots,dim,f; xset:=UnderlyingExternalSet(hom); if Size(xset)=0 then return fail; fi; # will the determinants suffice to get suitable scalars? - dim:=DimensionOfMatrixGroup(Source(hom)); - f:=DefaultFieldOfMatrixGroup(Source(hom)); + G:= Source(hom); + dim:=DimensionOfMatrixGroup(G); + f:=DefaultFieldOfMatrixGroup(G); roots:=Set(RootsOfUPol(f,X(f)^dim-1)); - - D:=List(GeneratorsOfGroup(Source(hom)),DeterminantMat); - D:=AsSSortedList(Group(D)); - - if Length(roots)<=1 then - # 1 will always be root - kero:=[One(f)]; - elif HasIsNaturalGL(Source(hom)) and IsNaturalGL(Source(hom)) then - # the full GL clearly will contain the kernel - kero:=roots; # to skip test - elif not IsSubset(D,roots) then - # even the kernel determinants are not reached, so clearly kernel not in - return fail; + D:=List(GeneratorsOfGroup(G),DeterminantMat); + + if ( HasIsNaturalGL(G) and IsNaturalGL(G) ) then + # No correction is necessary. + dets:= fail; + roots:= fail; + elif ForAll( D, IsOne ) and Length( roots ) = 1 then + # Preimages can be computed uniquely from the given data. + dets:=[]; + roots:=[]; + for i in Filtered( AsSSortedList( f ), x -> not IsZero( x ) ) do + b:= i^dim; + if not b in dets then + Add( dets, b ); + Add( roots, i^-1 ); # the factor by which we must correct + fi; + od; + SortParallel( dets, roots ); else - kero:=List(AsSSortedList(KernelOfMultiplicativeGeneralMapping(hom)),x->x[1][1]^dim); - fi; - - if not IsSubset(kero,roots) then - # we cannot fix the scalar with the determinant + # We do not know how to compute preimages from the given data. return fail; fi; - dets:=[]; - roots:=[]; - for i in Filtered(AsSSortedList(f),x->not IsZero(x)) do - b:=i^dim; - if not b in dets then - Add(dets,b); - Add(roots,i^-1); # the factor by which we must correct - fi; - od; - SortParallel(dets,roots); - - if IsSubset(D,dets) then - dets:=fail; # not that we do not need to correct with determinant as all - # values are fine - fi; - # find a basis from the domain. D:=HomeEnumerator(xset); b:=[]; @@ -3580,7 +3585,7 @@ local xset,D,b,t,i,r,binv,pos,kero,dets,roots,dim,f; i:=i+1; od; if Length(b) Date: Tue, 3 Mar 2026 10:14:18 +0100 Subject: [PATCH 099/234] build(deps): bump actions/upload-artifact from 6 to 7 (#6248) Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 6 to 7. - [Release notes](https://github.com/actions/upload-artifact/releases) - [Commits](https://github.com/actions/upload-artifact/compare/v6...v7) --- updated-dependencies: - dependency-name: actions/upload-artifact dependency-version: '7' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/CI.yml | 4 ++-- .github/workflows/release.yml | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index 89e7245119..e219840d8b 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -254,7 +254,7 @@ jobs: run: ${{ matrix.extra }} dev/ci.sh ${{ matrix.test-suites }} - name: "Upload pdf manuals" if: ${{ contains(matrix.test-suites, 'makemanuals') }} - uses: actions/upload-artifact@v6 + uses: actions/upload-artifact@v7 with: if-no-files-found: error name: manuals-pdf @@ -265,7 +265,7 @@ jobs: doc/tut/manual.pdf - name: "Upload html manuals" if: ${{ contains(matrix.test-suites, 'makemanuals') }} - uses: actions/upload-artifact@v6 + uses: actions/upload-artifact@v7 with: if-no-files-found: error name: manuals-html diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index ed6f358f39..1aaf3fa4ba 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -152,7 +152,7 @@ jobs: # # Warning: the result is a single .zip file (so things are compressed twice). - name: "Upload GAP tarball" - uses: actions/upload-artifact@v6 + uses: actions/upload-artifact@v7 with: if-no-files-found: error name: gap @@ -161,7 +161,7 @@ jobs: # Always upload metadata, and keep longer, since it is much smaller. - name: "Upload JSON metadata" - uses: actions/upload-artifact@v6 + uses: actions/upload-artifact@v7 with: if-no-files-found: error name: "JSON metadata" @@ -239,7 +239,7 @@ jobs: # Artifacts live for 1 day, i.e. until the next cron job runs. - name: "Upload the installer as an artifact" if: ${{ github.event_name == 'schedule' }} - uses: actions/upload-artifact@v6 + uses: actions/upload-artifact@v7 with: if-no-files-found: error name: gap-${{ env.GAP_VERSION }}-x86_64.exe From 70a453e739bfe06ede72a441a9d5dfdd9a86159f Mon Sep 17 00:00:00 2001 From: stertooy <5571903+stertooy@users.noreply.github.com> Date: Tue, 3 Mar 2026 18:32:06 +0100 Subject: [PATCH 100/234] Make RestrictedMapping of GHBI use same range as original GHBI (#6230) --- lib/ghom.gi | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/lib/ghom.gi b/lib/ghom.gi index c1a5a89674..38dc1e17ab 100644 --- a/lib/ghom.gi +++ b/lib/ghom.gi @@ -95,23 +95,15 @@ end); InstallMethod(RestrictedMapping,"create new GHBI", CollFamSourceEqFamElms,[IsGroupHomomorphism,IsGroup],0, function(hom,U) -local rest,gens,imgs,imgp; +local rest,gens,imgs; gens:=GeneratorsOfGroup(U); imgs:=List(gens,i->ImageElm(hom,i)); - if HasImagesSource(hom) then - imgp:=ImagesSource(hom); - else - imgp:=Subgroup(Range(hom),imgs); - fi; - rest:=GroupHomomorphismByImagesNC(U,imgp,gens,imgs); + rest:=GroupHomomorphismByImagesNC(U,Range(hom),gens,imgs); if HasIsInjective(hom) and IsInjective(hom) then SetIsInjective(rest,true); fi; - if HasIsTotal(hom) and IsTotal(hom) then - SetIsTotal(rest,true); - fi; return rest; end); From c50db27b9b582644365786363c7dcf8cb7ce165f Mon Sep 17 00:00:00 2001 From: Thomas Breuer Date: Tue, 3 Mar 2026 21:43:24 +0100 Subject: [PATCH 101/234] Problems when multiplying a matrix object with a matrix (#6240) * add `\*` methods for `IsMatrix` and some `IsMatrixObj` `IsGF2MatrixRep` and `Is8BitMatrixRep` describe matrices that are in `IsMatrix and IsMatrixObj`. Thus these matrices must obey the rules of list arithmetics, in particular the multiplication of these matrices with other matrices in `IsMatrix` is defined. Up to now, the methods that are chosen for such matrix multiplications are the generic methods. Now we install `PROD_LIST_SCL_DEFAULT` explicitly as a method. First of all, this removes some overhead. (Note that such multiplications really occur in practice, as one can see in the testfiles: For example, construct a matrix group with `CyclicGroup` or `GL`; the generators are in `IsGF2MatrixRep` or `Is8BitMatrixRep` if possible, due to `ImmutableMatrix`. Then construct a right coset of this group by prescribing a representative that is in `IsPlistRep`, and do some computations with it; multiplications "of mixed type" will happen.) Second, this yields high ranked methods such that it will be possible to install `\*` methods of lower rank that signal an error if one tries to multiply a *non-list* `IsMatrixObj` with an `IsMatrix`. * add some `\*` methods that call `Error` The multiplication of an `IsMatrixObj` that is *not* in `IsMatrix` with an `IsMatrix` shall not be allowed, the result is not defined (and the results without the new methods can be surprising). * fix `ViewString`, `DisplayString` for matrices Up to now, `ViewString` and `DisplayString` returned something that makes sense only for objects in `MatrixObj`, not for `IsMatrix`. (I had introduced this bug in 2021, apparently the two functions are not used, otherwise the problem would have been observed earlier.) * adjust `hpcgap/lib/vecmat.gi` to `lib/vecmat.gi` * add some tests --- hpcgap/lib/vecmat.gi | 15 +++++++++++++++ lib/mat8bit.gi | 15 +++++++++++++++ lib/matobj.gi | 24 ++++++++++++++++++++++-- lib/vecmat.gi | 15 +++++++++++++++ tst/testinstall/MatrixObj/arith.tst | 20 ++++++++++++++++++++ 5 files changed, 87 insertions(+), 2 deletions(-) create mode 100644 tst/testinstall/MatrixObj/arith.tst diff --git a/hpcgap/lib/vecmat.gi b/hpcgap/lib/vecmat.gi index d73d04c554..ecca386723 100644 --- a/hpcgap/lib/vecmat.gi +++ b/hpcgap/lib/vecmat.gi @@ -1212,6 +1212,21 @@ InstallMethod( \*, fi; end); +############################################################################# +## +#M \*( , ) . . . . . product of a GF2 matrix and a matrix +#M \*( , ) . . . . . product of a matrix and a GF2 matrix +## +InstallMethod( \*, + "for GF2 matrix and matrix", + [ IsMatrix and IsListDefault and IsGF2MatrixRep, IsMatrix ], + PROD_LIST_SCL_DEFAULT ); + +InstallMethod( \*, + "for matrix and GF2 matrix", + [ IsMatrix, IsMatrix and IsListDefault and IsGF2MatrixRep ], + PROD_LIST_SCL_DEFAULT ); + ############################################################################# ## #F ConvertToVectorRep() diff --git a/lib/mat8bit.gi b/lib/mat8bit.gi index 18eedcbc3f..34ad8180a9 100644 --- a/lib/mat8bit.gi +++ b/lib/mat8bit.gi @@ -480,6 +480,21 @@ InstallMethod( \*, "8 bit matrix * 8 bit matrix", IsIdenticalObj, ], 0, PROD_MAT8BIT_MAT8BIT); +############################################################################# +## +#M \*( <8bitmat>, ) . . . . product of an 8Bit matrix and a matrix +#M \*( , <8bitmat> ) . . . . product of a matrix and an 8Bit matrix +## +InstallMethod( \*, + "for 8 bit matrix and matrix", + [ IsMatrix and Is8BitMatrixRep, IsMatrix ], + PROD_LIST_SCL_DEFAULT ); + +InstallMethod( \*, + "for matrix and 8 bit matrix", + [ IsMatrix, IsMatrix and Is8BitMatrixRep ], + PROD_LIST_SCL_DEFAULT ); + ############################################################################# ## #M * diff --git a/lib/matobj.gi b/lib/matobj.gi index d397728233..cdde9b9512 100644 --- a/lib/matobj.gi +++ b/lib/matobj.gi @@ -1160,6 +1160,26 @@ InstallMethod( \*, -SUM_FLAGS, { s, M } -> Matrix( s * Unpack( M ), M ) ); +InstallMethod( \*, + "for (non-matrix) matrix object and matrix", + [ IsMatrixObj, IsMatrix ], + function( matobj, mat ) + if IsMatrix( matobj ) then + TryNextMethod(); + fi; + Error( " * is not defined" ); + end ); + +InstallMethod( \*, + "for matrix and (non-matrix) matrix object", + [ IsMatrix, IsMatrixObj ], + function( mat, matobj ) + if IsMatrix( matobj ) then + TryNextMethod(); + fi; + Error( " * is not defined" ); + end ); + InstallMethod( \/, "for matrix object and scalar", [ IsMatrixObj, IsScalar ], @@ -1572,11 +1592,11 @@ BindGlobal( "ViewStringForMatrixObj", " over ", String( BaseDomain( M ) ), ">" ) ); InstallMethod( ViewString, - [ IsMatrixOrMatrixObj ], + [ IsMatrixObj ], ViewStringForMatrixObj ); InstallMethod( DisplayString, - [ IsMatrixOrMatrixObj ], + [ IsMatrixObj ], ViewStringForMatrixObj ); InstallMethod( String, diff --git a/lib/vecmat.gi b/lib/vecmat.gi index 03658bd0d1..6d8addd44d 100644 --- a/lib/vecmat.gi +++ b/lib/vecmat.gi @@ -1212,6 +1212,21 @@ InstallMethod( \*, fi; end); +############################################################################# +## +#M \*( , ) . . . . . product of a GF2 matrix and a matrix +#M \*( , ) . . . . . product of a matrix and a GF2 matrix +## +InstallMethod( \*, + "for GF2 matrix and matrix", + [ IsMatrix and IsListDefault and IsGF2MatrixRep, IsMatrix ], + PROD_LIST_SCL_DEFAULT ); + +InstallMethod( \*, + "for matrix and GF2 matrix", + [ IsMatrix, IsMatrix and IsListDefault and IsGF2MatrixRep ], + PROD_LIST_SCL_DEFAULT ); + ############################################################################# ## #F ConvertToVectorRep() diff --git a/tst/testinstall/MatrixObj/arith.tst b/tst/testinstall/MatrixObj/arith.tst new file mode 100644 index 0000000000..40b646af3f --- /dev/null +++ b/tst/testinstall/MatrixObj/arith.tst @@ -0,0 +1,20 @@ +#@local F, matobj, mat +gap> START_TEST( "arith.tst" ); + +# Multiplying non-list 'IsMatrixObj' with 'IsMatrix' and v. v. are not defined. +gap> F:= GF(2);; +gap> matobj:= Matrix( IsPlistMatrixRep, F, [ [ 1, 1 ], [ 0, 1 ] ] * One( F ) );; +gap> IsMatrixObj( matobj ); IsMatrix( matobj ); +true +false +gap> mat:= IdentityMat( 2, F );; +gap> IsMatrixObj( mat ); IsMatrix( mat ); +false +true +gap> matobj * mat; +Error, * is not defined +gap> mat * matobj; +Error, * is not defined + +# +gap> STOP_TEST( "arith.tst" ); From 6949df8e85e24f15fe5bd965073625ee1f94904f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 3 Mar 2026 21:44:08 +0100 Subject: [PATCH 102/234] build(deps): bump actions/download-artifact from 7 to 8 (#6247) Bumps [actions/download-artifact](https://github.com/actions/download-artifact) from 7 to 8. - [Release notes](https://github.com/actions/download-artifact/releases) - [Commits](https://github.com/actions/download-artifact/compare/v7...v8) --- updated-dependencies: - dependency-name: actions/download-artifact dependency-version: '8' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 1aaf3fa4ba..eef883f07e 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -196,7 +196,7 @@ jobs: # Download the artifact -- for an actual release, this contains the # exact same tarball as was uploaded to the release as an asset - name: "Download GAP archive from previous job" - uses: actions/download-artifact@v7 + uses: actions/download-artifact@v8 with: name: gap From c8e789198779e7ac03b934a213e7514295dfeb19 Mon Sep 17 00:00:00 2001 From: Max Horn Date: Mon, 9 Mar 2026 00:37:46 +0100 Subject: [PATCH 103/234] src: silence addchdir_np deprecation on macOS Co-authored-by: Codex --- src/iostream.c | 33 ++++++++++++++++++++++----------- 1 file changed, 22 insertions(+), 11 deletions(-) diff --git a/src/iostream.c b/src/iostream.c index fa445f6cbb..c108389724 100644 --- a/src/iostream.c +++ b/src/iostream.c @@ -303,16 +303,20 @@ static Obj FuncDEFAULT_SIGCHLD_HANDLER(Obj self) // -// posix_spawn_file_actions_addchdir was only recently added to POSIX, and +// posix_spawn_file_actions_addchdir was only "recently" added to POSIX, and // most implementations therefore do not yet use this final name, but instead // provide the functionality under the alternate name -// posix_spawn_file_actions_addchdir_np. To keep things simple, we detect this -// case and use some preprocessor tricks to make things work in either case. +// posix_spawn_file_actions_addchdir_np. // -// macOS 26 has posix_spawn_file_actions_addchdir, but Xcode generates -// code which uses it even in older versions of macOS. Therefore if both -// functions are defined, we will always use the older _np version. +// For most platforms, configure checks are sufficient to choose between the +// standard and _np names. macOS is trickier: recent SDKs declare the standard +// name, but a binary built against them may still target an older macOS which +// only provides the _np symbol at runtime, possibly leading to crashes. // See issue for details. +// To preserve that compatibility, we continue to prefer the _np API on Apple +// for now and locally suppress its deprecation warning in newer SDKs. If +// Apple ever removes the _np symbol, we can revisit this and switch to a more +// complex runtime selection scheme. #if defined(HAVE_POSIX_SPAWN_FILE_ACTIONS_ADDCHDIR) || \ defined(HAVE_POSIX_SPAWN_FILE_ACTIONS_ADDCHDIR_NP) @@ -320,13 +324,20 @@ static Obj FuncDEFAULT_SIGCHLD_HANDLER(Obj self) #define HAVE_POSIX_SPAWN_FILE_ACTIONS_ADDCHDIR #endif -#if HAVE_POSIX_SPAWN_FILE_ACTIONS_ADDCHDIR_NP -#define posix_spawn_file_actions_addchdir_func(f, d) \ - posix_spawn_file_actions_addchdir_np(f, d) +static int posix_spawn_file_actions_addchdir_func( + posix_spawn_file_actions_t * file_actions, const char * dir) +{ +#if defined(HAVE_POSIX_SPAWN_FILE_ACTIONS_ADDCHDIR_NP) && defined(__APPLE__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wdeprecated-declarations" + return posix_spawn_file_actions_addchdir_np(file_actions, dir); +#pragma GCC diagnostic pop +#elif defined(HAVE_POSIX_SPAWN_FILE_ACTIONS_ADDCHDIR_NP) + return posix_spawn_file_actions_addchdir_np(file_actions, dir); #else -#define posix_spawn_file_actions_addchdir_func(f, d) \ - posix_spawn_file_actions_addchdir(f, d) + return posix_spawn_file_actions_addchdir(file_actions, dir); #endif +} #endif From 88a0efa62c55bab37f6d052b4aa2ac295eeb1125 Mon Sep 17 00:00:00 2001 From: Max Horn Date: Mon, 9 Mar 2026 17:47:52 +0100 Subject: [PATCH 104/234] docs: expand AGENTS.md guidance (#6256) This file helps AI tools work on the GAP codebase, and also sets some ground rules, e.g. demanding that any AI use is disclosed. Co-authored-by: Codex --- AGENTS.md | 116 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 116 insertions(+) create mode 100644 AGENTS.md diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000000..bbff38b0a6 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,116 @@ +# AGENTS.md + +This repository contains the core GAP system sources. + +## AI disclosure + +Any use of AI tools for preparing code, documentation, tests, commit messages, +pull requests, issue comments, or reviews for this repository must be +disclosed. Include a brief note saying which AI tool was used and what kind of +assistance it provided. Add the AI tool as a Git co-author on all commits +created by that tool (e.g. via an `Co-authored-by: ` line). + +## Repository layout + +Important top-level paths: + +- `src/`: GAP kernel sources in C/C++. +- `lib/`: GAP library code. +- `tst/`: test suites, including `testinstall`, `teststandard`, `testextra`, + and `testbugfix`. +- `doc/`: manual sources and generated documentation assets. +- `pkg/`: bundled GAP packages. +- `hpcgap/`: HPC-GAP sources and support files. +- `cnf/`, `configure.ac`, `autogen.sh`, `Makefile.rules`, + `README.buildsys.md`: build system inputs and documentation. +- `dev/`: developer utilities and CI/release scripts. + +## Generated files + +Do not edit generated build outputs such as `configure` directly. For build +system changes, update the source inputs such as `configure.ac`, files in +`cnf/`, or related makefiles, then regenerate derived files with +`./autogen.sh` as needed. If you are working on the build system itself, read +`README.buildsys.md`. + +## Common commands + +Run all commands from the repository root. + +### Build GAP + +For a fresh git checkout, generate `configure` first: + +```sh +./autogen.sh +./configure +make +``` + +If `configure` already exists and you just need to rebuild, use: + +```sh +./configure +make +``` + +### Installing packages + +If you need a package bundle for development or testing, bootstrap it with one +of: + +```sh +make bootstrap-pkg-minimal +make bootstrap-pkg-full +``` + +### Build the manual + +```sh +make html +``` + +### Run tests + +Quick core test suite: +```sh +make check +``` + +Common direct test entry points: +```sh +./gap tst/testinstall.g +./gap tst/teststandard.g +./gap tst/testextra.g +./gap tst/testbugfix.g +``` + +To run a specific test file, pass it to `./gap`, for example: + +```sh +./gap -q tst/testinstall/magma.tst -c 'QUIT;' +``` + +## Commit messages and pull requests + +When writing commit messages, use the title format `component: Brief summary`. +In the body, give a brief prose summary of the purpose of the change. Do not +specifically call out added tests, comments, documentation, and similar +supporting edits unless that is the main purpose of the change. Do not include +the test plan unless it differs from the instructions in this file. If the +change fixes one or more issues, add `Fixes #...` at the end of the commit +message body, not in the title. + +Pull requests should follow the same style: a short summary up top, concise +prose describing the change, issue references when applicable, and an explicit +AI-disclosure note if AI tools were used. + +Pull requests should normally target `master`. Changes intended only for the +current stable release series may target `stable-4.X` when appropriate. + + +## Changelog + +This project keeps a changelog in `CHANGES.md` but that is automatically +updated by scripts, based on pull request titles. So you don't need to +update it. From f62e9b4b5f677f014a314c38632d54d1291b44ce Mon Sep 17 00:00:00 2001 From: Max Horn Date: Wed, 11 Mar 2026 13:27:55 +0100 Subject: [PATCH 105/234] Improve break-loop stack traces (#6257) This reworks break-loop stack traces so the initial traceback and later `Where()` output are driven by the same visible traceback state. The break loop now tracks both the real environment used for local variable lookup and the first visible traceback frame. That makes ordinary errors, kernel-thrown errors, and no-method-found errors behave more consistently: `Where()` now shows the same top visible frame that was shown on entry, while method-not-found still keeps its helper environment available for `ShowArguments`, `ShowDetails`, and `ShowMethods`. This also adds `CurrentEnv()` for inspecting the currently selected break-loop environment and updates the break-loop docs and tests accordingly. On top of that, visible stack frames are now rendered with numbered prefixes in the style `*[1]`, ` [2]`, ` [3]`, where the `*` denotes the active frame. For me, that makes it *much* easier to use `DownEnv`/`UpEnv` correctly, and also increases readability of in longer traces. The manual examples and special REPL transcripts were refreshed to match the new output. AI disclosure: prepared with help from Codex for implementation, tests, and documentation. Co-authored-by: Codex --- AGENTS.md | 13 ++ doc/ref/debug.xml | 6 +- doc/ref/mloop.xml | 37 +-- lib/error.g | 117 +++++++--- lib/methsel2.g | 10 +- src/error.c | 39 +++- tst/testinstall/kernel/gap.tst | 8 +- .../64bit/low-mem-list-types.g.out | 3 + tst/testspecial/64bit/low-mem-plist-1.g.out | 2 + tst/testspecial/64bit/low-mem-plist-2.g.out | 2 + tst/testspecial/backtrace.g.out | 211 +++++++++++++----- tst/testspecial/backtrace2.g.out | 137 +++++++----- tst/testspecial/bad-add.g.out | 5 +- tst/testspecial/bad-array-double-1.g.out | 5 +- tst/testspecial/bad-array-int-0.g.out | 5 +- tst/testspecial/bad-array-int-1.g.out | 5 +- tst/testspecial/bad-array-string.g.out | 5 +- tst/testspecial/bad-array-undef-0.g.out | 5 +- tst/testspecial/bad-array-undef-1.g.out | 5 +- tst/testspecial/bad-minus.g.out | 9 +- tst/testspecial/break-loop-loop.g.out | 4 +- tst/testspecial/broken-test.g.out | 72 +++--- .../bugfix-2019-09-27-LastPV.g.out | 3 +- tst/testspecial/current-env.g | 12 + tst/testspecial/current-env.g.out | 26 +++ tst/testspecial/debug-var.g.out | 87 +++++--- .../error-in-InputTextString.g.out | 6 +- .../func-and-proc-call-trace.g.out | 80 ++++--- tst/testspecial/last-access.g.out | 3 +- tst/testspecial/line-continuation.g.out | 8 +- tst/testspecial/mem-overflow.g.out | 5 +- tst/testspecial/method-not-found-where.g | 6 + tst/testspecial/method-not-found-where.g.out | 19 ++ tst/testspecial/method-not-found.g.out | 5 +- tst/testspecial/print-formatting.g.out | 1 + tst/testspecial/repl-syntax-err.g.out | 3 +- tst/testspecial/stack-depth-func.g.out | 28 +-- tst/testspecial/stack-depth-func2.g.out | 28 +-- tst/testspecial/stack-depth-rec.g.out | 28 +-- tst/testspecial/stack-trace-label.g | 5 + tst/testspecial/stack-trace-label.g.out | 13 ++ tst/testspecial/syntax-tree-error.g.out | 4 +- tst/testspecial/top-level-error.g.out | 3 +- tst/testspecial/trace.g.out | 6 + tst/testspecial/up-down-env.g.out | 18 +- 45 files changed, 739 insertions(+), 363 deletions(-) create mode 100644 tst/testspecial/current-env.g create mode 100644 tst/testspecial/current-env.g.out create mode 100644 tst/testspecial/method-not-found-where.g create mode 100644 tst/testspecial/method-not-found-where.g.out create mode 100644 tst/testspecial/stack-trace-label.g create mode 100644 tst/testspecial/stack-trace-label.g.out diff --git a/AGENTS.md b/AGENTS.md index bbff38b0a6..b9550f9040 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -91,6 +91,19 @@ To run a specific test file, pass it to `./gap`, for example: ./gap -q tst/testinstall/magma.tst -c 'QUIT;' ``` +### REPL / break-loop output tests + +Use `tst/testspecial/` for tests that exercise the interactive REPL, +break loops, or other output that depends on GAP's terminal handling. + +- `./tst/testspecial/run_gap.sh ./gap tst/testspecial/.g [outfile]` + runs a single special test, captures combined output, prevents GAP from + attaching to the terminal, and rewrites local paths in the transcript. +- From `tst/testspecial/`, `GAPDIR=../.. ./run_all.sh` runs the full special + test suite. +- From `tst/testspecial/`, `./regenerate_tests.sh` regenerates all expected + `.out` files. + ## Commit messages and pull requests When writing commit messages, use the title format `component: Brief summary`. diff --git a/doc/ref/debug.xml b/doc/ref/debug.xml index 66e793c19c..857ee5e941 100644 --- a/doc/ref/debug.xml +++ b/doc/ref/debug.xml @@ -41,9 +41,9 @@ error as in the following example occurs and a break loop is entered: IsNormal(2,2); Error, no method found! For debugging hints type ?Recovery from NoMethodFound -Error, no 1st choice method found for `IsNormal' on 2 arguments at GAPROOT/lib/methsel2.g:250 called from -( ) - called from read-eval loop at *stdin*:1 +Error, no 1st choice method found for `IsNormal' on 2 arguments +Stack trace: +called from read-eval loop at *stdin*:1 type 'quit;' to quit to outer loop brk> ]]> diff --git a/doc/ref/mloop.xml b/doc/ref/mloop.xml index 09abd5cebc..a0f844dd4d 100644 --- a/doc/ref/mloop.xml +++ b/doc/ref/mloop.xml @@ -811,6 +811,7 @@ variable at the lowest level can be accessed. DownEnv and UpEnv + moves down nr steps in the environment and @@ -822,39 +823,47 @@ but in the reverse direction (the mnemonic rule to remember the difference between and is the order in which commands on the execution stack are displayed by ). + returns the currently selected environment. At +present this is the local variables bag used by the break loop for local +variable lookup; outside such a context it returns fail.

OnBreak := function() Where(0); end;; # eliminate back-tracing on -gap> # entry to break loop +gap> OnBreak := function() end;; # eliminate back-tracing on entry to break loop gap> test:= function( n ) > if n > 3 then Error( "!\n" ); fi; test( n+1 ); end;; gap> test( 1 ); Error, ! -Entering break read-eval-print loop ... you can 'quit;' to quit to outer loop, or you can 'return;' to continue brk> Where(); - called from -test( n + 1 ); called from -test( n + 1 ); called from -test( n + 1 ); called from -( ) called from read-eval-loop +*[1] Error( "!\n" ); at *stdin*:3 called from + [2] test( n + 1 ); at *stdin*:3 called from + [3] test( n + 1 ); at *stdin*:3 called from + [4] test( n + 1 ); at *stdin*:3 called from +( ) + called from read-eval loop at *errin*:1 brk> n; 4 brk> DownEnv(); brk> n; 3 brk> Where(); - called from -test( n + 1 ); called from -test( n + 1 ); called from -( ) called from read-eval-loop + [1] Error( "!\n" ); at *stdin*:3 called from +*[2] test( n + 1 ); at *stdin*:3 called from + [3] test( n + 1 ); at *stdin*:3 called from + [4] test( n + 1 ); at *stdin*:3 called from +( ) + called from read-eval loop at *errin*:5 brk> DownEnv( 2 ); brk> n; 1 brk> Where(); - called from -( ) called from read-eval-loop + [1] Error( "!\n" ); at *stdin*:3 called from + [2] test( n + 1 ); at *stdin*:3 called from + [3] test( n + 1 ); at *stdin*:3 called from +*[4] test( n + 1 ); at *stdin*:3 called from +( ) + called from read-eval loop at *errin*:8 brk> DownEnv( -2 ); brk> n; 3 diff --git a/lib/error.g b/lib/error.g index 9ad592dd2d..fbaceed8a3 100644 --- a/lib/error.g +++ b/lib/error.g @@ -57,6 +57,40 @@ BIND_GLOBAL("AncestorLVars", function(lv, depth) end); ErrorLVars := fail; +ErrorTracebackLVars := fail; + +BIND_GLOBAL("GET_VISIBLE_ERROR_LVARS", function() + local active, context, bottom; + + if ErrorTracebackLVars = fail then + return fail; + fi; + + active := CurrentEnv(); + if active = fail then + return ErrorTracebackLVars; + fi; + bottom := GetBottomLVars(); + context := ErrorTracebackLVars; + while context <> bottom do + if context = active then + return active; + fi; + context := ParentLVars(context); + od; + return ErrorTracebackLVars; +end); + +BIND_GLOBAL("ERROR_MESSAGE_ENDS_WITH_NEWLINE", function(message) + local last; + + if Length(message) = 0 then + return false; + fi; + + last := Last(message); + return IsString(last) and Length(last) > 0 and Last(last) = '\n'; +end); # In this method the line hint changes in every PrintTo are balanced, because at the moment # PrintTo(ERROR_OUTPUT,...) resets the indentation level every time it is called. @@ -99,16 +133,20 @@ BIND_GLOBAL("PRETTY_PRINT_VARS", function(context) PrintTo(ERROR_OUTPUT,"\n"); end); -BIND_GLOBAL("WHERE", function(depth, context, showlocals) - local bottom, lastcontext, f; +BIND_GLOBAL("WHERE", function(depth, context, activecontext, showlocals) + local bottom, lastcontext, f, level; if depth <= 0 then return; fi; bottom := GetBottomLVars(); + if context = bottom then + PrintTo(ERROR_OUTPUT, "called from read-eval loop "); + return; + fi; lastcontext := context; - context := ParentLVars(context); + level := 1; while depth > 0 and context <> bottom do - PRINT_CURRENT_STATEMENT(ERROR_OUTPUT, context); + PRINT_CURRENT_STATEMENT(ERROR_OUTPUT, context, activecontext, level); if showlocals then PRETTY_PRINT_VARS(context); fi; @@ -117,6 +155,7 @@ BIND_GLOBAL("WHERE", function(depth, context, showlocals) lastcontext := context; context := ParentLVars(context); depth := depth-1; + level := level + 1; od; if depth = 0 then PrintTo(ERROR_OUTPUT, "... "); @@ -129,10 +168,12 @@ end); BIND_GLOBAL("WHERE_INTERNAL", function(depth, showlocals) + local activecontext; if ErrorLVars = fail or ErrorLVars = GetBottomLVars() then PrintTo(ERROR_OUTPUT, "not in any function "); else - WHERE(depth, ErrorLVars, showlocals); + activecontext := GET_VISIBLE_ERROR_LVARS(); + WHERE(depth, ErrorTracebackLVars, activecontext, showlocals); fi; PrintTo(ERROR_OUTPUT, "at ", INPUT_FILENAME(), ":", INPUT_LINENUMBER(), "\n"); end); @@ -172,9 +213,10 @@ end); # Unbind(ErrorInner); BIND_GLOBAL("ErrorInner", function(options, earlyMessage) - local context, mayReturnVoid, mayReturnObj, lateMessage, - x, prompt, res, errorLVars, justQuit, printThisStatement, - printEarlyMessage, printEarlyTraceback, lastErrorStream; + local context, tracebackContext, mayReturnVoid, mayReturnObj, + lateMessage, x, prompt, res, errorLVars, errorTracebackLVars, + kernelErrorLVars, justQuit, printEarlyMessage, + printEarlyTraceback, printAutomaticTraceback, lastErrorStream; context := options.context; if not IsLVarsBag(context) then @@ -216,15 +258,15 @@ BIND_GLOBAL("ErrorInner", function(options, earlyMessage) mayReturnObj := false; fi; - if IsBound(options.printThisStatement) then - printThisStatement := options.printThisStatement; - if not printThisStatement in [false, true] then - PrintTo(ERROR_OUTPUT, "ErrorInner: option printThisStatement must be true or false\n"); + if IsBound(options.tracebackContext) then + tracebackContext := options.tracebackContext; + if not IsLVarsBag(tracebackContext) then + PrintTo(ERROR_OUTPUT, "ErrorInner: option tracebackContext must be a local variables bag\n"); LEAVE_ALL_NAMESPACES(); JUMP_TO_CATCH(1); fi; else - printThisStatement := true; + tracebackContext := context; fi; if IsBound(options.lateMessage) then @@ -248,27 +290,31 @@ BIND_GLOBAL("ErrorInner", function(options, earlyMessage) end; printEarlyTraceback := function(stream) - local location; - if printThisStatement then - if context <> GetBottomLVars() then - PrintTo(stream, " in\n "); - PRINT_CURRENT_STATEMENT(stream, context); - PrintTo(stream, " called from "); - fi; - else - location := CURRENT_STATEMENT_LOCATION(context); - if location <> fail then - PrintTo(stream, " at ", location[1], ":", location[2]); + if not ERROR_MESSAGE_ENDS_WITH_NEWLINE(earlyMessage) then + PrintTo(stream, "\n"); + fi; + end; + + printAutomaticTraceback := function() + if IsBound(OnBreak) and IsFunction(OnBreak) then + if OnBreak = Where or OnBreak = WhereWithVars then + PrintTo(ERROR_OUTPUT, "Stack trace:\n"); fi; - PrintTo(stream, " called from"); + OnBreak(); fi; - PrintTo(ERROR_OUTPUT, "\n"); end; ErrorLevel := ErrorLevel+1; ERROR_COUNT := ERROR_COUNT+1; errorLVars := ErrorLVars; + errorTracebackLVars := ErrorTracebackLVars; + kernelErrorLVars := CurrentEnv(); + if kernelErrorLVars = fail then + kernelErrorLVars := GetBottomLVars(); + fi; ErrorLVars := context; + ErrorTracebackLVars := tracebackContext; + SET_ERROR_LVARS(context); # Do we want to skip the break loop? # BreakOnError is initialized by the `-T` command line flag in init.g if QUITTING or not BreakOnError then @@ -283,9 +329,7 @@ BIND_GLOBAL("ErrorInner", function(options, earlyMessage) printEarlyMessage(ERROR_OUTPUT); if AlwaysPrintTracebackOnError then printEarlyTraceback(ERROR_OUTPUT); - if IsBound(OnBreak) and IsFunction(OnBreak) then - OnBreak(); - fi; + printAutomaticTraceback(); else PrintTo(ERROR_OUTPUT, "\n"); fi; @@ -313,6 +357,8 @@ BIND_GLOBAL("ErrorInner", function(options, earlyMessage) fi; ErrorLevel := ErrorLevel-1; ErrorLVars := errorLVars; + ErrorTracebackLVars := errorTracebackLVars; + SET_ERROR_LVARS(kernelErrorLVars); if ErrorLevel = 0 then LEAVE_ALL_NAMESPACES(); fi; JUMP_TO_CATCH(0); fi; @@ -323,17 +369,14 @@ BIND_GLOBAL("ErrorInner", function(options, earlyMessage) if SHOULD_QUIT_ON_BREAK() then # Again, the default is to not print the rest of the traceback. # If AlwaysPrintTracebackOnError is true we do so anyways. - if AlwaysPrintTracebackOnError - and IsBound(OnBreak) and IsFunction(OnBreak) then - OnBreak(); + if AlwaysPrintTracebackOnError then + printAutomaticTraceback(); fi; ForceQuitGap(1); fi; # OnBreak() is set to Where() by default, which prints the traceback. - if IsBound(OnBreak) and IsFunction(OnBreak) then - OnBreak(); - fi; + printAutomaticTraceback(); # Now print lateMessage and OnBreakMessage a la "press return; to .." if IsString(lateMessage) then @@ -355,6 +398,8 @@ BIND_GLOBAL("ErrorInner", function(options, earlyMessage) fi; ErrorLevel := ErrorLevel-1; ErrorLVars := errorLVars; + ErrorTracebackLVars := errorTracebackLVars; + SET_ERROR_LVARS(kernelErrorLVars); if res = fail then if IsBound(OnQuit) and IsFunction(OnQuit) then OnQuit(); @@ -381,7 +426,6 @@ BIND_GLOBAL("Error", function(arg) context := ParentLVars(GetCurrentLVars()), mayReturnVoid := true, lateMessage := true, - printThisStatement := false, ), arg); end); @@ -395,7 +439,6 @@ BIND_GLOBAL("ErrorNoReturn", function(arg) mayReturnVoid := false, mayReturnObj := false, lateMessage := "type 'quit;' to quit to outer loop", - printThisStatement := false, ), arg); end); diff --git a/lib/methsel2.g b/lib/methsel2.g index f9e5301a3e..51700574ea 100644 --- a/lib/methsel2.g +++ b/lib/methsel2.g @@ -247,7 +247,15 @@ end; APPEND_LIST(no_method_found, " argument is 'fail' which might point to an earlier problem\n" ); fi; od; - ErrorNoReturn(no_method_found); + ErrorInner( + rec( + context := GetCurrentLVars(), + tracebackContext := ParentLVars(GetCurrentLVars()), + mayReturnVoid := false, + mayReturnObj := false, + lateMessage := "type 'quit;' to quit to outer loop" + ), + [ no_method_found ]); end; ## This is the other part of the above mentioned dirty trick: diff --git a/src/error.c b/src/error.c index d064b9698f..32ac420a34 100644 --- a/src/error.c +++ b/src/error.c @@ -135,6 +135,20 @@ static Obj FuncUpEnv(Obj self, Obj args) return (Obj)0; } +static Obj FuncCurrentEnv(Obj self) +{ + if (!STATE(ErrorLVars) || IsBottomLVars(STATE(ErrorLVars))) + return Fail; + MakeHighVars(STATE(ErrorLVars)); + return STATE(ErrorLVars); +} + +static Obj FuncSET_ERROR_LVARS(Obj self, Obj lvars) +{ + STATE(ErrorLVars) = lvars; + return (Obj)0; +} + static Obj FuncCURRENT_STATEMENT_LOCATION(Obj self, Obj context) { if (IsBottomLVars(context)) @@ -170,7 +184,8 @@ static Obj FuncCURRENT_STATEMENT_LOCATION(Obj self, Obj context) return retlist; } -static Obj FuncPRINT_CURRENT_STATEMENT(Obj self, Obj stream, Obj context) +static Obj FuncPRINT_CURRENT_STATEMENT(Obj self, Obj stream, Obj context, + Obj activeContext, Obj level) { if (IsBottomLVars(context)) return 0; @@ -197,6 +212,10 @@ static Obj FuncPRINT_CURRENT_STATEMENT(Obj self, Obj stream, Obj context) Stat call = STAT_LVARS(context); Obj body = BODY_FUNC(func); Obj filename = GET_FILENAME_BODY(body); + if (activeContext != Fail) { + Pr(context == activeContext ? "*[%d] " : " [%d] ", + INT_INTOBJ(level), 0); + } if (IsKernelFunction(func)) { PrintKernelFunction(func); Obj funcname = NAME_FUNC(func); @@ -365,8 +384,7 @@ static Obj CallErrorInner(const Char * msg, UInt justQuit, UInt mayReturnVoid, UInt mayReturnObj, - Obj lateMessage, - UInt printThisStatement) + Obj lateMessage) { // Must do this before creating any other GAP objects, // as one of the args could be a pointer into a Bag. @@ -392,8 +410,6 @@ static Obj CallErrorInner(const Char * msg, AssPRec(r, RNamName("justQuit"), justQuit ? True : False); AssPRec(r, RNamName("mayReturnObj"), mayReturnObj ? True : False); AssPRec(r, RNamName("mayReturnVoid"), mayReturnVoid ? True : False); - AssPRec(r, RNamName("printThisStatement"), - printThisStatement ? True : False); AssPRec(r, RNamName("lateMessage"), lateMessage); l = NewPlistFromArgs(EarlyMsg); MakeImmutableNoRecurse(l); @@ -414,7 +430,7 @@ static Obj CallErrorInner(const Char * msg, void ErrorQuit(const Char * msg, Int arg1, Int arg2) { - CallErrorInner(msg, arg1, arg2, 1, 0, 0, False, 1); + CallErrorInner(msg, arg1, arg2, 1, 0, 0, False); Panic("ErrorQuit must not return"); } @@ -449,7 +465,7 @@ Obj ErrorReturnObj(const Char * msg, Int arg1, Int arg2, const Char * msg2) { Obj LateMsg; LateMsg = MakeString(msg2); - return CallErrorInner(msg, arg1, arg2, 0, 0, 1, LateMsg, 1); + return CallErrorInner(msg, arg1, arg2, 0, 0, 1, LateMsg); } @@ -461,7 +477,7 @@ void ErrorReturnVoid(const Char * msg, Int arg1, Int arg2, const Char * msg2) { Obj LateMsg; LateMsg = MakeString(msg2); - CallErrorInner(msg, arg1, arg2, 0, 1, 0, LateMsg, 1); + CallErrorInner(msg, arg1, arg2, 0, 1, 0, LateMsg); // ErrorMode( msg, arg1, arg2, (Obj)0, msg2, 'x' ); } @@ -472,7 +488,7 @@ void ErrorReturnVoid(const Char * msg, Int arg1, Int arg2, const Char * msg2) void ErrorMayQuit(const Char * msg, Int arg1, Int arg2) { Obj LateMsg = MakeString("type 'quit;' to quit to outer loop"); - CallErrorInner(msg, arg1, arg2, 0, 0, 0, LateMsg, 1); + CallErrorInner(msg, arg1, arg2, 0, 0, 0, LateMsg); Panic("ErrorMayQuit must not return"); } @@ -622,11 +638,14 @@ static StructGVarFunc GVarFuncs[] = { GVAR_FUNC_XARGS(DownEnv, -1, "args"), GVAR_FUNC_XARGS(UpEnv, -1, "args"), + GVAR_FUNC_0ARGS(CurrentEnv), + GVAR_FUNC_1ARGS(SET_ERROR_LVARS, lvars), GVAR_FUNC_2ARGS(CALL_WITH_CATCH, func, args), GVAR_FUNC_1ARGS(JUMP_TO_CATCH, payload), - GVAR_FUNC_2ARGS(PRINT_CURRENT_STATEMENT, stream, context), + GVAR_FUNC_4ARGS(PRINT_CURRENT_STATEMENT, stream, context, activeContext, + level), GVAR_FUNC_1ARGS(CURRENT_STATEMENT_LOCATION, context), GVAR_FUNC_1ARGS(SetUserHasQuit, value), diff --git a/tst/testinstall/kernel/gap.tst b/tst/testinstall/kernel/gap.tst index e9dc5769de..3b025a9ac0 100644 --- a/tst/testinstall/kernel/gap.tst +++ b/tst/testinstall/kernel/gap.tst @@ -105,13 +105,15 @@ gap> UpEnv(1,2); Error, usage: UpEnv( [ ] ) gap> UpEnv(fail); Error, usage: UpEnv( [ ] ) +gap> CurrentEnv(); +fail # gap> CURRENT_STATEMENT_LOCATION(GetCurrentLVars()); fail -gap> PRINT_CURRENT_STATEMENT("*errout*", GetCurrentLVars()); -gap> f:=function() PRINT_CURRENT_STATEMENT("*errout*", GetCurrentLVars()); Print("\n"); end;; f(); -PRINT_CURRENT_STATEMENT( "*errout*", GetCurrentLVars( ) ); at stream:1 +gap> PRINT_CURRENT_STATEMENT("*errout*", GetCurrentLVars(), fail, 1); +gap> f:=function() local l; l:=GetCurrentLVars(); PRINT_CURRENT_STATEMENT("*errout*", l, fail, 1); Print("\n"); end;; f(); +PRINT_CURRENT_STATEMENT( "*errout*", l, fail, 1 ); at stream:1 # gap> CALL_WITH_CATCH(fail,fail); diff --git a/tst/testspecial/64bit/low-mem-list-types.g.out b/tst/testspecial/64bit/low-mem-list-types.g.out index b8c7f74302..086225b90a 100644 --- a/tst/testspecial/64bit/low-mem-list-types.g.out +++ b/tst/testspecial/64bit/low-mem-list-types.g.out @@ -1,15 +1,18 @@ gap> ListWithIdenticalEntries(2^50, 'a'); Error, Cannot allocate 1125899906842633 bytes: cannot extend the workspace any more!! +Stack trace: not in any function at *stdin*:2 type 'quit;' to quit to outer loop brk> quit; gap> ListWithIdenticalEntries(2^50, true); Error, Cannot allocate 140737488355336 bytes: cannot extend the workspace any more!! +Stack trace: not in any function at *stdin*:2 type 'quit;' to quit to outer loop brk> quit; gap> ListWithIdenticalEntries(2^50, 2); Error, Cannot allocate 9007199254741000 bytes: cannot extend the workspace any more!! +Stack trace: not in any function at *stdin*:2 type 'quit;' to quit to outer loop brk> quit; diff --git a/tst/testspecial/64bit/low-mem-plist-1.g.out b/tst/testspecial/64bit/low-mem-plist-1.g.out index f3bdaee9b0..9264df9d43 100644 --- a/tst/testspecial/64bit/low-mem-plist-1.g.out +++ b/tst/testspecial/64bit/low-mem-plist-1.g.out @@ -2,11 +2,13 @@ gap> l := []; [ ] gap> l[2^50] := 1; Error, Cannot allocate 9007199254741000 bytes: cannot extend the workspace any more!!!! +Stack trace: not in any function at *stdin*:3 type 'quit;' to quit to outer loop brk> quit; gap> l[2^50] := 2; Error, Cannot allocate 9007199254741000 bytes: cannot extend the workspace any more!!!! +Stack trace: not in any function at *stdin*:3 type 'quit;' to quit to outer loop brk> quit; diff --git a/tst/testspecial/64bit/low-mem-plist-2.g.out b/tst/testspecial/64bit/low-mem-plist-2.g.out index 3d430e5bb8..d50a3a7ab5 100644 --- a/tst/testspecial/64bit/low-mem-plist-2.g.out +++ b/tst/testspecial/64bit/low-mem-plist-2.g.out @@ -1,10 +1,12 @@ gap> EmptyPlist(2^50); Error, Cannot allocate 9007199254741000 bytes: cannot extend the workspace any more!! +Stack trace: not in any function at *stdin*:2 type 'quit;' to quit to outer loop brk> quit; gap> EmptyPlist(2^50); Error, Cannot allocate 9007199254741000 bytes: cannot extend the workspace any more!! +Stack trace: not in any function at *stdin*:2 type 'quit;' to quit to outer loop brk> quit; diff --git a/tst/testspecial/backtrace.g.out b/tst/testspecial/backtrace.g.out index 27559d1b15..976b2ee066 100644 --- a/tst/testspecial/backtrace.g.out +++ b/tst/testspecial/backtrace.g.out @@ -12,17 +12,18 @@ gap> f := function() function( ) ... end gap> f(); Error, no method found! For debugging hints type ?Recovery from NoMethodFound -Error, no 1st choice method found for `[]:=' on 3 arguments at GAPROOT/lib/methsel2.g:LINE called from -l[[ 1 .. 3 ]] := 1; at *stdin*:11 called from +Error, no 1st choice method found for `[]:=' on 3 arguments +Stack trace: +*[1] l[[ 1 .. 3 ]] := 1; at *stdin*:11 called from ( ) called from read-eval loop at *stdin*:13 type 'quit;' to quit to outer loop brk> Where(); -l[[ 1 .. 3 ]] := 1; at *stdin*:11 called from +*[1] l[[ 1 .. 3 ]] := 1; at *stdin*:11 called from ( ) called from read-eval loop at *errin*:1 brk> WhereWithVars(); -l[[ 1 .. 3 ]] := 1; at *stdin*:11 +*[1] l[[ 1 .. 3 ]] := 1; at *stdin*:11 arguments: local variables: l := [ 0, 0, 0, 0, 0, 0 ] @@ -34,15 +35,21 @@ gap> gap> ############################################################################# gap> f:=function() if true = 1/0 then return 1; fi; return 2; end;; gap> f(); -Error, Rational operations: must not be zero in - 1 / 0 at *stdin*:15 called from +Error, Rational operations: must not be zero +Stack trace: +*[1] 1 / 0 at *stdin*:15 called from ( ) called from read-eval loop at *stdin*:16 type 'quit;' to quit to outer loop brk> Where(); +*[1] 1 / 0 at *stdin*:15 called from ( ) called from read-eval loop at *errin*:1 brk> WhereWithVars(); +*[1] 1 / 0 at *stdin*:15 + arguments: + local variables: + called from ( ) called from read-eval loop at *errin*:2 brk> quit; @@ -50,17 +57,28 @@ gap> gap> ############################################################################# gap> f:=function() local x; if x then return 1; fi; return 2; end;; gap> f(); -Error, Variable: 'x' must have an assigned value in - if x then +Error, Variable: 'x' must have an assigned value +Stack trace: +*[1] if x then return 1; -fi; at *stdin*:18 called from +fi; at *stdin*:18 called from ( ) called from read-eval loop at *stdin*:19 type 'quit;' to quit to outer loop brk> Where(); +*[1] if x then + return 1; +fi; at *stdin*:18 called from ( ) called from read-eval loop at *errin*:1 brk> WhereWithVars(); +*[1] if x then + return 1; +fi; at *stdin*:18 + arguments: + local variables: + x := + called from ( ) called from read-eval loop at *errin*:2 brk> quit; @@ -68,17 +86,27 @@ gap> gap> ############################################################################# gap> f:=function() if 1 then return 1; fi; return 2; end;; gap> f(); -Error, must be 'true' or 'false' (not the integer 1) in - if 1 then +Error, must be 'true' or 'false' (not the integer 1) +Stack trace: +*[1] if 1 then return 1; -fi; at *stdin*:21 called from +fi; at *stdin*:21 called from ( ) called from read-eval loop at *stdin*:22 type 'quit;' to quit to outer loop brk> Where(); +*[1] if 1 then + return 1; +fi; at *stdin*:21 called from ( ) called from read-eval loop at *errin*:1 brk> WhereWithVars(); +*[1] if 1 then + return 1; +fi; at *stdin*:21 + arguments: + local variables: + called from ( ) called from read-eval loop at *errin*:2 brk> quit; @@ -86,19 +114,33 @@ gap> gap> ############################################################################# gap> f:=function() if 1 < 0 then return 1; elif 1 then return 2; fi; return 3; end;; gap> f(); -Error, must be 'true' or 'false' (not the integer 1) in - if 1 < 0 then +Error, must be 'true' or 'false' (not the integer 1) +Stack trace: +*[1] if 1 < 0 then return 1; elif 1 then return 2; -fi; at *stdin*:24 called from +fi; at *stdin*:24 called from ( ) called from read-eval loop at *stdin*:25 type 'quit;' to quit to outer loop brk> Where(); +*[1] if 1 < 0 then + return 1; +elif 1 then + return 2; +fi; at *stdin*:24 called from ( ) called from read-eval loop at *errin*:1 brk> WhereWithVars(); +*[1] if 1 < 0 then + return 1; +elif 1 then + return 2; +fi; at *stdin*:24 + arguments: + local variables: + called from ( ) called from read-eval loop at *errin*:2 brk> quit; @@ -106,17 +148,27 @@ gap> gap> ############################################################################# gap> f:=function() while 1 do return 1; od; return 2; end;; gap> f(); -Error, must be 'true' or 'false' (not the integer 1) in - while 1 do +Error, must be 'true' or 'false' (not the integer 1) +Stack trace: +*[1] while 1 do return 1; -od; at *stdin*:27 called from +od; at *stdin*:27 called from ( ) called from read-eval loop at *stdin*:28 type 'quit;' to quit to outer loop brk> Where(); +*[1] while 1 do + return 1; +od; at *stdin*:27 called from ( ) called from read-eval loop at *errin*:1 brk> WhereWithVars(); +*[1] while 1 do + return 1; +od; at *stdin*:27 + arguments: + local variables: + called from ( ) called from read-eval loop at *errin*:2 brk> quit; @@ -124,8 +176,10 @@ gap> gap> ############################################################################# gap> f:=function() local i; for i in 1 do return 1; od; return 2; end;; gap> f(); -Error, You cannot loop over the integer 1 did you mean the range [1..1] at GAPROOT/lib/integer.gi:LINE called from -for i in 1 do +Error, You cannot loop over the integer 1 did you mean the range [1..1] +Stack trace: +*[1] Error( "You cannot loop over the integer ", n, " did you mean the range [1..", n, "]" ); at GAPROOT/lib/integer.gi:LINE called from + [2] for i in 1 do return 1; od; at *stdin*:30 called from ( ) @@ -133,13 +187,19 @@ od; at *stdin*:30 called from you can 'quit;' to quit to outer loop, or you can 'return;' to continue brk> Where(); -for i in 1 do +*[1] Error( "You cannot loop over the integer ", n, " did you mean the range [1..", n, "]" ); at GAPROOT/lib/integer.gi:LINE called from + [2] for i in 1 do return 1; od; at *stdin*:30 called from ( ) called from read-eval loop at *errin*:1 brk> WhereWithVars(); -for i in 1 do +*[1] Error( "You cannot loop over the integer ", n, " did you mean the range [1..", n, "]" ); at GAPROOT/lib/integer.gi:LINE + arguments: + n := 1 + local variables: + called from + [2] for i in 1 do return 1; od; at *stdin*:30 arguments: @@ -154,21 +214,22 @@ gap> ########################################################################### gap> f:=function() local i; for i in true do return 1; od; return 2; end;; gap> f(); Error, no method found! For debugging hints type ?Recovery from NoMethodFound -Error, no 1st choice method found for `Iterator' on 1 arguments at GAPROOT/lib/methsel2.g:LINE called from -for i in true do +Error, no 1st choice method found for `Iterator' on 1 arguments +Stack trace: +*[1] for i in true do return 1; od; at *stdin*:33 called from ( ) called from read-eval loop at *stdin*:34 type 'quit;' to quit to outer loop brk> Where(); -for i in true do +*[1] for i in true do return 1; od; at *stdin*:33 called from ( ) called from read-eval loop at *errin*:1 brk> WhereWithVars(); -for i in true do +*[1] for i in true do return 1; od; at *stdin*:33 arguments: @@ -182,21 +243,22 @@ gap> gap> f:=function(x) local i,j; for i in true do return 1; od; return 2; end;; gap> f([1,2,3]); Error, no method found! For debugging hints type ?Recovery from NoMethodFound -Error, no 1st choice method found for `Iterator' on 1 arguments at GAPROOT/lib/methsel2.g:LINE called from -for i in true do +Error, no 1st choice method found for `Iterator' on 1 arguments +Stack trace: +*[1] for i in true do return 1; od; at *stdin*:35 called from ( ) called from read-eval loop at *stdin*:36 type 'quit;' to quit to outer loop brk> Where(); -for i in true do +*[1] for i in true do return 1; od; at *stdin*:35 called from ( ) called from read-eval loop at *errin*:1 brk> WhereWithVars(); -for i in true do +*[1] for i in true do return 1; od; at *stdin*:35 arguments: @@ -212,21 +274,22 @@ gap> gap> f:=function(x) local i,j; Unbind(x); for i in true do return 1; od; return 2; end;; gap> f([1,2,3]); Error, no method found! For debugging hints type ?Recovery from NoMethodFound -Error, no 1st choice method found for `Iterator' on 1 arguments at GAPROOT/lib/methsel2.g:LINE called from -for i in true do +Error, no 1st choice method found for `Iterator' on 1 arguments +Stack trace: +*[1] for i in true do return 1; od; at *stdin*:37 called from ( ) called from read-eval loop at *stdin*:38 type 'quit;' to quit to outer loop brk> Where(); -for i in true do +*[1] for i in true do return 1; od; at *stdin*:37 called from ( ) called from read-eval loop at *errin*:1 brk> WhereWithVars(); -for i in true do +*[1] for i in true do return 1; od; at *stdin*:37 arguments: @@ -242,21 +305,22 @@ gap> gap> f:=function(x) local i,j; Unbind(x); j := 4; for i in true do return 1; od; return 2; end;; gap> f([1,2,3]); Error, no method found! For debugging hints type ?Recovery from NoMethodFound -Error, no 1st choice method found for `Iterator' on 1 arguments at GAPROOT/lib/methsel2.g:LINE called from -for i in true do +Error, no 1st choice method found for `Iterator' on 1 arguments +Stack trace: +*[1] for i in true do return 1; od; at *stdin*:39 called from ( ) called from read-eval loop at *stdin*:40 type 'quit;' to quit to outer loop brk> Where(); -for i in true do +*[1] for i in true do return 1; od; at *stdin*:39 called from ( ) called from read-eval loop at *errin*:1 brk> WhereWithVars(); -for i in true do +*[1] for i in true do return 1; od; at *stdin*:39 arguments: @@ -271,17 +335,28 @@ brk> quit; gap> gap> f:=function() local x; repeat x:=1; until 1; return 2; end;; gap> f(); -Error, must be 'true' or 'false' (not the integer 1) in - repeat +Error, must be 'true' or 'false' (not the integer 1) +Stack trace: +*[1] repeat x := 1; -until 1; at *stdin*:41 called from +until 1; at *stdin*:41 called from ( ) called from read-eval loop at *stdin*:42 type 'quit;' to quit to outer loop brk> Where(); +*[1] repeat + x := 1; +until 1; at *stdin*:41 called from ( ) called from read-eval loop at *errin*:1 brk> WhereWithVars(); +*[1] repeat + x := 1; +until 1; at *stdin*:41 + arguments: + local variables: + x := 1 + called from ( ) called from read-eval loop at *errin*:2 brk> quit; @@ -289,15 +364,22 @@ gap> gap> ############################################################################# gap> f:=function() local x; Assert(0, 1); return 2; end;; gap> f(); -Error, Assert: must be 'true' or 'false' (not the integer 1) in - Assert( 0, 1 ); at *stdin*:44 called from +Error, Assert: must be 'true' or 'false' (not the integer 1) +Stack trace: +*[1] Assert( 0, 1 ); at *stdin*:44 called from ( ) called from read-eval loop at *stdin*:45 type 'quit;' to quit to outer loop brk> Where(); +*[1] Assert( 0, 1 ); at *stdin*:44 called from ( ) called from read-eval loop at *errin*:1 brk> WhereWithVars(); +*[1] Assert( 0, 1 ); at *stdin*:44 + arguments: + local variables: + x := + called from ( ) called from read-eval loop at *errin*:2 brk> quit; @@ -305,15 +387,22 @@ gap> gap> ############################################################################# gap> f:=function() local x; Assert(0, 1, "hello"); return 2; end;; gap> f(); -Error, Assert: must be 'true' or 'false' (not the integer 1) in - Assert( 0, 1, "hello" ); at *stdin*:47 called from +Error, Assert: must be 'true' or 'false' (not the integer 1) +Stack trace: +*[1] Assert( 0, 1, "hello" ); at *stdin*:47 called from ( ) called from read-eval loop at *stdin*:48 type 'quit;' to quit to outer loop brk> Where(); +*[1] Assert( 0, 1, "hello" ); at *stdin*:47 called from ( ) called from read-eval loop at *errin*:1 brk> WhereWithVars(); +*[1] Assert( 0, 1, "hello" ); at *stdin*:47 + arguments: + local variables: + x := + called from ( ) called from read-eval loop at *errin*:2 brk> quit; @@ -326,27 +415,36 @@ gap> InstallMethod( \[\,\], [ IsMatrixOrMatrixObj, IsPosInt, IsPosInt ], > { m, row, col } -> ELM_LIST( m, row, col ) ); gap> l := [[1]];; f := {} -> l[2,1];; gap> f(); -Error, List Element: [2] must have an assigned value in - return m[i][j]; at GAPROOT/lib/matrix.gi:LINE called from -ELM_LIST( m, row, col ) at *stdin*:54 called from -return l[2, 1]; at *stdin*:55 called from +Error, List Element: [2] must have an assigned value +Stack trace: +*[1] return m[i][j]; at GAPROOT/lib/matrix.gi:LINE called from + [2] ELM_LIST( m, row, col ) at *stdin*:54 called from + [3] return l[2, 1]; at *stdin*:55 called from ( ) called from read-eval loop at *stdin*:56 type 'quit;' to quit to outer loop brk> Where(); -ELM_LIST( m, row, col ) at *stdin*:54 called from -return l[2, 1]; at *stdin*:55 called from +*[1] return m[i][j]; at GAPROOT/lib/matrix.gi:LINE called from + [2] ELM_LIST( m, row, col ) at *stdin*:54 called from + [3] return l[2, 1]; at *stdin*:55 called from ( ) called from read-eval loop at *errin*:1 brk> WhereWithVars(); -ELM_LIST( m, row, col ) at *stdin*:54 +*[1] return m[i][j]; at GAPROOT/lib/matrix.gi:LINE + arguments: + m := [ [ 1 ] ] + i := 2 + j := 1 + local variables: + called from + [2] ELM_LIST( m, row, col ) at *stdin*:54 arguments: m := [ [ 1 ] ] row := 2 col := 1 local variables: called from -return l[2, 1]; at *stdin*:55 + [3] return l[2, 1]; at *stdin*:55 arguments: local variables: called from @@ -359,9 +457,10 @@ gap> ## gap> ## Verify issue #1373 is fixed gap> ## gap> InstallMethod( Matrix, [IsFilter, IsSemiring, IsMatrixObj], {a,b,c} -> fail ); -Error, FLAGS_FILTER: must be an operation (not a function) in - <> from GAPROOT/lib/oper1.g:LINE in function INSTALL_METHOD called from -<> from GAPROOT/lib/oper1.g:LINE in function InstallMethod called from +Error, FLAGS_FILTER: must be an operation (not a function) +Stack trace: +*[1] <> from GAPROOT/lib/oper1.g:LINE in function INSTALL_METHOD called from + [2] <> from GAPROOT/lib/oper1.g:LINE in function InstallMethod called from ( ) called from read-eval loop at *stdin*:61 type 'quit;' to quit to outer loop diff --git a/tst/testspecial/backtrace2.g.out b/tst/testspecial/backtrace2.g.out index 2909e55eec..547888026a 100644 --- a/tst/testspecial/backtrace2.g.out +++ b/tst/testspecial/backtrace2.g.out @@ -26,53 +26,61 @@ gap> test:= function( n ) > end;; gap> test( 1 ); Error, ! - at *stdin*:24 called from -test( n + 1 ); at *stdin*:26 called from -test( n + 1 ); at *stdin*:26 called from +Stack trace: +*[1] Error( "!\n" ); at *stdin*:24 called from + [2] test( n + 1 ); at *stdin*:26 called from + [3] test( n + 1 ); at *stdin*:26 called from ( ) called from read-eval loop at *stdin*:28 you can 'quit;' to quit to outer loop, or you can 'return;' to continue brk> n; Where(); 3 -test( n + 1 ); at *stdin*:26 called from -test( n + 1 ); at *stdin*:26 called from +*[1] Error( "!\n" ); at *stdin*:24 called from + [2] test( n + 1 ); at *stdin*:26 called from + [3] test( n + 1 ); at *stdin*:26 called from ( ) called from read-eval loop at *errin*:1 brk> DownEnv(); n; Where(); 2 -test( n + 1 ); at *stdin*:26 called from -test( n + 1 ); at *stdin*:26 called from + [1] Error( "!\n" ); at *stdin*:24 called from +*[2] test( n + 1 ); at *stdin*:26 called from + [3] test( n + 1 ); at *stdin*:26 called from ( ) called from read-eval loop at *errin*:2 brk> DownEnv(); n; Where(); 1 -test( n + 1 ); at *stdin*:26 called from -test( n + 1 ); at *stdin*:26 called from + [1] Error( "!\n" ); at *stdin*:24 called from + [2] test( n + 1 ); at *stdin*:26 called from +*[3] test( n + 1 ); at *stdin*:26 called from ( ) called from read-eval loop at *errin*:3 brk> DownEnv(); n; Where(); 1 -test( n + 1 ); at *stdin*:26 called from -test( n + 1 ); at *stdin*:26 called from + [1] Error( "!\n" ); at *stdin*:24 called from + [2] test( n + 1 ); at *stdin*:26 called from +*[3] test( n + 1 ); at *stdin*:26 called from ( ) called from read-eval loop at *errin*:4 brk> UpEnv(); n; Where(); 2 -test( n + 1 ); at *stdin*:26 called from -test( n + 1 ); at *stdin*:26 called from + [1] Error( "!\n" ); at *stdin*:24 called from +*[2] test( n + 1 ); at *stdin*:26 called from + [3] test( n + 1 ); at *stdin*:26 called from ( ) called from read-eval loop at *errin*:5 brk> UpEnv(); n; Where(); 3 -test( n + 1 ); at *stdin*:26 called from -test( n + 1 ); at *stdin*:26 called from +*[1] Error( "!\n" ); at *stdin*:24 called from + [2] test( n + 1 ); at *stdin*:26 called from + [3] test( n + 1 ); at *stdin*:26 called from ( ) called from read-eval loop at *errin*:6 brk> UpEnv(); n; Where(); 3 -test( n + 1 ); at *stdin*:26 called from -test( n + 1 ); at *stdin*:26 called from +*[1] Error( "!\n" ); at *stdin*:24 called from + [2] test( n + 1 ); at *stdin*:26 called from + [3] test( n + 1 ); at *stdin*:26 called from ( ) called from read-eval loop at *errin*:7 brk> quit; @@ -88,53 +96,61 @@ gap> test:= function( n ) > test( n+1 ); > end;; gap> test( 1 ); -Error, Rational operations: must not be zero in - 1 / 0 at *stdin*:35 called from -test( n + 1 ); at *stdin*:37 called from -test( n + 1 ); at *stdin*:37 called from +Error, Rational operations: must not be zero +Stack trace: +*[1] 1 / 0 at *stdin*:35 called from + [2] test( n + 1 ); at *stdin*:37 called from + [3] test( n + 1 ); at *stdin*:37 called from ( ) called from read-eval loop at *stdin*:39 type 'quit;' to quit to outer loop brk> n; Where(); 3 -test( n + 1 ); at *stdin*:37 called from -test( n + 1 ); at *stdin*:37 called from +*[1] 1 / 0 at *stdin*:35 called from + [2] test( n + 1 ); at *stdin*:37 called from + [3] test( n + 1 ); at *stdin*:37 called from ( ) called from read-eval loop at *errin*:1 brk> DownEnv(); n; Where(); 2 -test( n + 1 ); at *stdin*:37 called from -test( n + 1 ); at *stdin*:37 called from + [1] 1 / 0 at *stdin*:35 called from +*[2] test( n + 1 ); at *stdin*:37 called from + [3] test( n + 1 ); at *stdin*:37 called from ( ) called from read-eval loop at *errin*:2 brk> DownEnv(); n; Where(); 1 -test( n + 1 ); at *stdin*:37 called from -test( n + 1 ); at *stdin*:37 called from + [1] 1 / 0 at *stdin*:35 called from + [2] test( n + 1 ); at *stdin*:37 called from +*[3] test( n + 1 ); at *stdin*:37 called from ( ) called from read-eval loop at *errin*:3 brk> DownEnv(); n; Where(); 1 -test( n + 1 ); at *stdin*:37 called from -test( n + 1 ); at *stdin*:37 called from + [1] 1 / 0 at *stdin*:35 called from + [2] test( n + 1 ); at *stdin*:37 called from +*[3] test( n + 1 ); at *stdin*:37 called from ( ) called from read-eval loop at *errin*:4 brk> UpEnv(); n; Where(); 2 -test( n + 1 ); at *stdin*:37 called from -test( n + 1 ); at *stdin*:37 called from + [1] 1 / 0 at *stdin*:35 called from +*[2] test( n + 1 ); at *stdin*:37 called from + [3] test( n + 1 ); at *stdin*:37 called from ( ) called from read-eval loop at *errin*:5 brk> UpEnv(); n; Where(); 3 -test( n + 1 ); at *stdin*:37 called from -test( n + 1 ); at *stdin*:37 called from +*[1] 1 / 0 at *stdin*:35 called from + [2] test( n + 1 ); at *stdin*:37 called from + [3] test( n + 1 ); at *stdin*:37 called from ( ) called from read-eval loop at *errin*:6 brk> UpEnv(); n; Where(); 3 -test( n + 1 ); at *stdin*:37 called from -test( n + 1 ); at *stdin*:37 called from +*[1] 1 / 0 at *stdin*:35 called from + [2] test( n + 1 ); at *stdin*:37 called from + [3] test( n + 1 ); at *stdin*:37 called from ( ) called from read-eval loop at *errin*:7 brk> quit; @@ -152,60 +168,61 @@ gap> test:= function( n ) > end;; gap> test( 1 ); Error, no method found! For debugging hints type ?Recovery from NoMethodFound -Error, no 1st choice method found for `IsCommutative' on 1 arguments at GAPROOT/lib/methsel2.g:LINE called from -IsAbelian( 1 ) at *stdin*:47 called from -test( n + 1 ); at *stdin*:49 called from -test( n + 1 ); at *stdin*:49 called from +Error, no 1st choice method found for `IsCommutative' on 1 arguments +Stack trace: +*[1] IsAbelian( 1 ) at *stdin*:47 called from + [2] test( n + 1 ); at *stdin*:49 called from + [3] test( n + 1 ); at *stdin*:49 called from ( ) called from read-eval loop at *stdin*:51 type 'quit;' to quit to outer loop brk> n; Where(); 3 -IsAbelian( 1 ) at *stdin*:47 called from -test( n + 1 ); at *stdin*:49 called from -test( n + 1 ); at *stdin*:49 called from +*[1] IsAbelian( 1 ) at *stdin*:47 called from + [2] test( n + 1 ); at *stdin*:49 called from + [3] test( n + 1 ); at *stdin*:49 called from ( ) called from read-eval loop at *errin*:1 brk> DownEnv(); n; Where(); 3 -IsAbelian( 1 ) at *stdin*:47 called from -test( n + 1 ); at *stdin*:49 called from -test( n + 1 ); at *stdin*:49 called from +*[1] IsAbelian( 1 ) at *stdin*:47 called from + [2] test( n + 1 ); at *stdin*:49 called from + [3] test( n + 1 ); at *stdin*:49 called from ( ) called from read-eval loop at *errin*:2 brk> DownEnv(); n; Where(); 2 -IsAbelian( 1 ) at *stdin*:47 called from -test( n + 1 ); at *stdin*:49 called from -test( n + 1 ); at *stdin*:49 called from + [1] IsAbelian( 1 ) at *stdin*:47 called from +*[2] test( n + 1 ); at *stdin*:49 called from + [3] test( n + 1 ); at *stdin*:49 called from ( ) called from read-eval loop at *errin*:3 brk> DownEnv(); n; Where(); 1 -IsAbelian( 1 ) at *stdin*:47 called from -test( n + 1 ); at *stdin*:49 called from -test( n + 1 ); at *stdin*:49 called from + [1] IsAbelian( 1 ) at *stdin*:47 called from + [2] test( n + 1 ); at *stdin*:49 called from +*[3] test( n + 1 ); at *stdin*:49 called from ( ) called from read-eval loop at *errin*:4 brk> UpEnv(); n; Where(); 2 -IsAbelian( 1 ) at *stdin*:47 called from -test( n + 1 ); at *stdin*:49 called from -test( n + 1 ); at *stdin*:49 called from + [1] IsAbelian( 1 ) at *stdin*:47 called from +*[2] test( n + 1 ); at *stdin*:49 called from + [3] test( n + 1 ); at *stdin*:49 called from ( ) called from read-eval loop at *errin*:5 brk> UpEnv(); n; Where(); 3 -IsAbelian( 1 ) at *stdin*:47 called from -test( n + 1 ); at *stdin*:49 called from -test( n + 1 ); at *stdin*:49 called from +*[1] IsAbelian( 1 ) at *stdin*:47 called from + [2] test( n + 1 ); at *stdin*:49 called from + [3] test( n + 1 ); at *stdin*:49 called from ( ) called from read-eval loop at *errin*:6 brk> UpEnv(); n; Where(); 3 -IsAbelian( 1 ) at *stdin*:47 called from -test( n + 1 ); at *stdin*:49 called from -test( n + 1 ); at *stdin*:49 called from +*[1] IsAbelian( 1 ) at *stdin*:47 called from + [2] test( n + 1 ); at *stdin*:49 called from + [3] test( n + 1 ); at *stdin*:49 called from ( ) called from read-eval loop at *errin*:7 brk> quit; diff --git a/tst/testspecial/bad-add.g.out b/tst/testspecial/bad-add.g.out index 8e70437ea0..cfa76fecbd 100644 --- a/tst/testspecial/bad-add.g.out +++ b/tst/testspecial/bad-add.g.out @@ -4,8 +4,9 @@ gap> f := function() function( ) ... end gap> f(); Error, no method found! For debugging hints type ?Recovery from NoMethodFound -Error, no 1st choice method found for `+' on 2 arguments at GAPROOT/lib/methsel2.g:LINE called from -1 + "abc" at *stdin*:3 called from +Error, no 1st choice method found for `+' on 2 arguments +Stack trace: +*[1] 1 + "abc" at *stdin*:3 called from ( ) called from read-eval loop at *stdin*:5 type 'quit;' to quit to outer loop diff --git a/tst/testspecial/bad-array-double-1.g.out b/tst/testspecial/bad-array-double-1.g.out index f41aadb2a4..0f77b5cb9a 100644 --- a/tst/testspecial/bad-array-double-1.g.out +++ b/tst/testspecial/bad-array-double-1.g.out @@ -4,8 +4,9 @@ gap> f := function() function( ) ... end gap> f(); Error, no method found! For debugging hints type ?Recovery from NoMethodFound -Error, no 1st choice method found for `[,]' on 3 arguments at GAPROOT/lib/methsel2.g:LINE called from -return "abc"[1, 1]; at *stdin*:3 called from +Error, no 1st choice method found for `[,]' on 3 arguments +Stack trace: +*[1] return "abc"[1, 1]; at *stdin*:3 called from ( ) called from read-eval loop at *stdin*:5 type 'quit;' to quit to outer loop diff --git a/tst/testspecial/bad-array-int-0.g.out b/tst/testspecial/bad-array-int-0.g.out index fe357e625e..06c965e890 100644 --- a/tst/testspecial/bad-array-int-0.g.out +++ b/tst/testspecial/bad-array-int-0.g.out @@ -6,8 +6,9 @@ gap> f := function() function( ) ... end gap> f(); Error, no method found! For debugging hints type ?Recovery from NoMethodFound -Error, no 1st choice method found for `[]' on 2 arguments at GAPROOT/lib/methsel2.g:LINE called from -return l[0]; at *stdin*:5 called from +Error, no 1st choice method found for `[]' on 2 arguments +Stack trace: +*[1] return l[0]; at *stdin*:5 called from ( ) called from read-eval loop at *stdin*:7 type 'quit;' to quit to outer loop diff --git a/tst/testspecial/bad-array-int-1.g.out b/tst/testspecial/bad-array-int-1.g.out index 20d228a5d9..1bb696a6b3 100644 --- a/tst/testspecial/bad-array-int-1.g.out +++ b/tst/testspecial/bad-array-int-1.g.out @@ -3,8 +3,9 @@ gap> f := function() > end; function( ) ... end gap> f(); -Error, List Element: must be a list (not the integer 1) in - return 1[1]; at *stdin*:3 called from +Error, List Element: must be a list (not the integer 1) +Stack trace: +*[1] return 1[1]; at *stdin*:3 called from ( ) called from read-eval loop at *stdin*:5 type 'quit;' to quit to outer loop diff --git a/tst/testspecial/bad-array-string.g.out b/tst/testspecial/bad-array-string.g.out index df96e10d0a..754cc970e6 100644 --- a/tst/testspecial/bad-array-string.g.out +++ b/tst/testspecial/bad-array-string.g.out @@ -4,8 +4,9 @@ gap> f := function() function( ) ... end gap> f(); Error, no method found! For debugging hints type ?Recovery from NoMethodFound -Error, no 1st choice method found for `[]' on 2 arguments at GAPROOT/lib/methsel2.g:LINE called from -return 1["abc"]; at *stdin*:3 called from +Error, no 1st choice method found for `[]' on 2 arguments +Stack trace: +*[1] return 1["abc"]; at *stdin*:3 called from ( ) called from read-eval loop at *stdin*:5 type 'quit;' to quit to outer loop diff --git a/tst/testspecial/bad-array-undef-0.g.out b/tst/testspecial/bad-array-undef-0.g.out index cba1f09070..150bad14b6 100644 --- a/tst/testspecial/bad-array-undef-0.g.out +++ b/tst/testspecial/bad-array-undef-0.g.out @@ -4,8 +4,9 @@ gap> f := function() > end; function( ) ... end gap> f(); -Error, Variable: 'l' must have an assigned value in - return l[1]; at *stdin*:4 called from +Error, Variable: 'l' must have an assigned value +Stack trace: +*[1] return l[1]; at *stdin*:4 called from ( ) called from read-eval loop at *stdin*:6 type 'quit;' to quit to outer loop diff --git a/tst/testspecial/bad-array-undef-1.g.out b/tst/testspecial/bad-array-undef-1.g.out index c8c66d27be..63ff49e3ac 100644 --- a/tst/testspecial/bad-array-undef-1.g.out +++ b/tst/testspecial/bad-array-undef-1.g.out @@ -5,8 +5,9 @@ gap> f := function() > end; function( ) ... end gap> f(); -Error, Variable: 'm' must have an assigned value in - return l[m]; at *stdin*:5 called from +Error, Variable: 'm' must have an assigned value +Stack trace: +*[1] return l[m]; at *stdin*:5 called from ( ) called from read-eval loop at *stdin*:7 type 'quit;' to quit to outer loop diff --git a/tst/testspecial/bad-minus.g.out b/tst/testspecial/bad-minus.g.out index ae0f01ff1b..a8ebc320f6 100644 --- a/tst/testspecial/bad-minus.g.out +++ b/tst/testspecial/bad-minus.g.out @@ -4,10 +4,11 @@ gap> f := function() function( ) ... end gap> f(); Error, no method found! For debugging hints type ?Recovery from NoMethodFound -Error, no 1st choice method found for `AdditiveInverseMutable' on 1 arguments at GAPROOT/lib/methsel2.g:LINE called from -AdditiveInverseMutable( elm ) at GAPROOT/lib/arith.gi:LINE called from -AdditiveInverseImmutable( elm ) at GAPROOT/lib/arith.gi:LINE called from -1 - "abc" at *stdin*:3 called from +Error, no 1st choice method found for `AdditiveInverseMutable' on 1 arguments +Stack trace: +*[1] AdditiveInverseMutable( elm ) at GAPROOT/lib/arith.gi:LINE called from + [2] AdditiveInverseImmutable( elm ) at GAPROOT/lib/arith.gi:LINE called from + [3] 1 - "abc" at *stdin*:3 called from ( ) called from read-eval loop at *stdin*:5 type 'quit;' to quit to outer loop diff --git a/tst/testspecial/break-loop-loop.g.out b/tst/testspecial/break-loop-loop.g.out index 1570e063a1..3159319d09 100644 --- a/tst/testspecial/break-loop-loop.g.out +++ b/tst/testspecial/break-loop-loop.g.out @@ -3,7 +3,9 @@ gap> f:=function(x) local y; y:=42; Error("bar"); end;; gap> i:=0; 0 gap> f(1); -Error, bar at *stdin*:3 called from +Error, bar +Stack trace: +*[1] Error( "bar" ); at *stdin*:3 called from ( ) called from read-eval loop at *stdin*:5 you can 'quit;' to quit to outer loop, or diff --git a/tst/testspecial/broken-test.g.out b/tst/testspecial/broken-test.g.out index 0022813d8c..72dc2a443e 100644 --- a/tst/testspecial/broken-test.g.out +++ b/tst/testspecial/broken-test.g.out @@ -1,71 +1,89 @@ gap> Test("broken-test-2.tst", rec(width := 800)); -Error, Invalid test file: #@ command found in the middle of a single test at broken-test-2.tst:5 at GAPROOT/lib/test.gi:LINE called from -testError( "Invalid test file: #@ command found in the middle of a single test" ); at GAPROOT/lib/test.gi:LINE called from -ParseTestInput( full, opts.ignoreComments, fnam ) at GAPROOT/lib/test.gi:LINE called from +Error, Invalid test file: #@ command found in the middle of a single test at broken-test-2.tst:5 +Stack trace: +*[1] ErrorNoReturn( s, " at ", fnam, ":", i ); at GAPROOT/lib/test.gi:LINE called from + [2] testError( "Invalid test file: #@ command found in the middle of a single test" ); at GAPROOT/lib/test.gi:LINE called from + [3] ParseTestInput( full, opts.ignoreComments, fnam ) at GAPROOT/lib/test.gi:LINE called from ( ) called from read-eval loop at *stdin*:2 type 'quit;' to quit to outer loop brk> quit; gap> Test("broken-test-3.tst", rec(width := 800)); -Error, Invalid test file at broken-test-3.tst:5 at GAPROOT/lib/test.gi:LINE called from -testError( "Invalid test file" ); at GAPROOT/lib/test.gi:LINE called from -ParseTestInput( full, opts.ignoreComments, fnam ) at GAPROOT/lib/test.gi:LINE called from +Error, Invalid test file at broken-test-3.tst:5 +Stack trace: +*[1] ErrorNoReturn( s, " at ", fnam, ":", i ); at GAPROOT/lib/test.gi:LINE called from + [2] testError( "Invalid test file" ); at GAPROOT/lib/test.gi:LINE called from + [3] ParseTestInput( full, opts.ignoreComments, fnam ) at GAPROOT/lib/test.gi:LINE called from ( ) called from read-eval loop at *stdin*:2 type 'quit;' to quit to outer loop brk> quit; gap> Test("broken-test-4.tst", rec(width := 800)); -Error, Invalid test file: Nested #@if at broken-test-4.tst:2 at GAPROOT/lib/test.gi:LINE called from -testError( "Invalid test file: Nested #@if" ); at GAPROOT/lib/test.gi:LINE called from -ParseTestInput( full, opts.ignoreComments, fnam ) at GAPROOT/lib/test.gi:LINE called from +Error, Invalid test file: Nested #@if at broken-test-4.tst:2 +Stack trace: +*[1] ErrorNoReturn( s, " at ", fnam, ":", i ); at GAPROOT/lib/test.gi:LINE called from + [2] testError( "Invalid test file: Nested #@if" ); at GAPROOT/lib/test.gi:LINE called from + [3] ParseTestInput( full, opts.ignoreComments, fnam ) at GAPROOT/lib/test.gi:LINE called from ( ) called from read-eval loop at *stdin*:2 type 'quit;' to quit to outer loop brk> quit; gap> Test("broken-test-5.tst", rec(width := 800)); -Error, Invalid test file: two #@else at broken-test-5.tst:7 at GAPROOT/lib/test.gi:LINE called from -testError( "Invalid test file: two #@else" ); at GAPROOT/lib/test.gi:LINE called from -ParseTestInput( full, opts.ignoreComments, fnam ) at GAPROOT/lib/test.gi:LINE called from +Error, Invalid test file: two #@else at broken-test-5.tst:7 +Stack trace: +*[1] ErrorNoReturn( s, " at ", fnam, ":", i ); at GAPROOT/lib/test.gi:LINE called from + [2] testError( "Invalid test file: two #@else" ); at GAPROOT/lib/test.gi:LINE called from + [3] ParseTestInput( full, opts.ignoreComments, fnam ) at GAPROOT/lib/test.gi:LINE called from ( ) called from read-eval loop at *stdin*:2 type 'quit;' to quit to outer loop brk> quit; gap> Test("broken-test-6.tst", rec(width := 800)); -Error, Invalid test file: Continuation prompt '> ' followed by a tab, expected a regular space at broken-test-6.tst:3 at GAPROOT/lib/test.gi:LINE called from -testError( "Invalid test file: Continuation prompt '> ' followed by a tab, expected a regular space" ); at GAPROOT/lib/test.gi:LINE called from -ParseTestInput( full, opts.ignoreComments, fnam ) at GAPROOT/lib/test.gi:LINE called from +Error, Invalid test file: Continuation prompt '> ' followed by a tab, expected a regular space at broken-test-6.tst:3 +Stack trace: +*[1] ErrorNoReturn( s, " at ", fnam, ":", i ); at GAPROOT/lib/test.gi:LINE called from + [2] testError( "Invalid test file: Continuation prompt '> ' followed by a tab, expected a regular space" ); at GAPROOT/lib/test.gi:LINE called from + [3] ParseTestInput( full, opts.ignoreComments, fnam ) at GAPROOT/lib/test.gi:LINE called from ( ) called from read-eval loop at *stdin*:2 type 'quit;' to quit to outer loop brk> quit; gap> Test("broken-test-7.tst", rec(width := 800)); -Error, Invalid test file: #@elif after #@else at broken-test-7.tst:7 at GAPROOT/lib/test.gi:LINE called from -testError( "Invalid test file: #@elif after #@else" ); at GAPROOT/lib/test.gi:LINE called from -ParseTestInput( full, opts.ignoreComments, fnam ) at GAPROOT/lib/test.gi:LINE called from +Error, Invalid test file: #@elif after #@else at broken-test-7.tst:7 +Stack trace: +*[1] ErrorNoReturn( s, " at ", fnam, ":", i ); at GAPROOT/lib/test.gi:LINE called from + [2] testError( "Invalid test file: #@elif after #@else" ); at GAPROOT/lib/test.gi:LINE called from + [3] ParseTestInput( full, opts.ignoreComments, fnam ) at GAPROOT/lib/test.gi:LINE called from ( ) called from read-eval loop at *stdin*:2 type 'quit;' to quit to outer loop brk> quit; gap> Test("broken-test-8.tst", rec(width := 800)); -Error, Invalid test file: #@elif without #@if at broken-test-8.tst:1 at GAPROOT/lib/test.gi:LINE called from -testError( "Invalid test file: #@elif without #@if" ); at GAPROOT/lib/test.gi:LINE called from -ParseTestInput( full, opts.ignoreComments, fnam ) at GAPROOT/lib/test.gi:LINE called from +Error, Invalid test file: #@elif without #@if at broken-test-8.tst:1 +Stack trace: +*[1] ErrorNoReturn( s, " at ", fnam, ":", i ); at GAPROOT/lib/test.gi:LINE called from + [2] testError( "Invalid test file: #@elif without #@if" ); at GAPROOT/lib/test.gi:LINE called from + [3] ParseTestInput( full, opts.ignoreComments, fnam ) at GAPROOT/lib/test.gi:LINE called from ( ) called from read-eval loop at *stdin*:2 type 'quit;' to quit to outer loop brk> quit; gap> Test("broken-test-9.tst", rec(width := 800)); -Error, Invalid test file: Unterminated #@if at broken-test-9.tst:7 at GAPROOT/lib/test.gi:LINE called from -testError( "Invalid test file: Unterminated #@if" ); at GAPROOT/lib/test.gi:LINE called from -ParseTestInput( full, opts.ignoreComments, fnam ) at GAPROOT/lib/test.gi:LINE called from +Error, Invalid test file: Unterminated #@if at broken-test-9.tst:7 +Stack trace: +*[1] ErrorNoReturn( s, " at ", fnam, ":", i ); at GAPROOT/lib/test.gi:LINE called from + [2] testError( "Invalid test file: Unterminated #@if" ); at GAPROOT/lib/test.gi:LINE called from + [3] ParseTestInput( full, opts.ignoreComments, fnam ) at GAPROOT/lib/test.gi:LINE called from ( ) called from read-eval loop at *stdin*:2 type 'quit;' to quit to outer loop brk> quit; gap> Test("invalidtestfile.tst", rec(width := 800)); -Error, Invalid test file at invalidtestfile.tst:7 at GAPROOT/lib/test.gi:LINE called from -testError( "Invalid test file" ); at GAPROOT/lib/test.gi:LINE called from -ParseTestInput( full, opts.ignoreComments, fnam ) at GAPROOT/lib/test.gi:LINE called from +Error, Invalid test file at invalidtestfile.tst:7 +Stack trace: +*[1] ErrorNoReturn( s, " at ", fnam, ":", i ); at GAPROOT/lib/test.gi:LINE called from + [2] testError( "Invalid test file" ); at GAPROOT/lib/test.gi:LINE called from + [3] ParseTestInput( full, opts.ignoreComments, fnam ) at GAPROOT/lib/test.gi:LINE called from ( ) called from read-eval loop at *stdin*:2 type 'quit;' to quit to outer loop diff --git a/tst/testspecial/bugfix-2019-09-27-LastPV.g.out b/tst/testspecial/bugfix-2019-09-27-LastPV.g.out index 3c3973b6bc..bfb7f37450 100644 --- a/tst/testspecial/bugfix-2019-09-27-LastPV.g.out +++ b/tst/testspecial/bugfix-2019-09-27-LastPV.g.out @@ -6,8 +6,7 @@ gap> SetFilterObj(badgroup, filt); gap> old_OnBreak:=OnBreak;; gap> OnBreak:=fail;; # prevent backtrace with line numbers that keep chaning gap> View([[badgroup]]); # <- trigger break loop -Error, Rational operations: must not be zero in - 0 / 0 at *stdin*:3 called from +Error, Rational operations: must not be zero type 'quit;' to quit to outer loop brk> quit; [ [ diff --git a/tst/testspecial/current-env.g b/tst/testspecial/current-env.g new file mode 100644 index 0000000000..51e0f4179e --- /dev/null +++ b/tst/testspecial/current-env.g @@ -0,0 +1,12 @@ +f := function() + local i; + for i in 1 do + return 1; + od; + return 2; +end;; +f(); +ContentsLVars(CurrentEnv()); +DownEnv(); ContentsLVars(CurrentEnv()); +DownEnv(); ContentsLVars(CurrentEnv()); +quit; diff --git a/tst/testspecial/current-env.g.out b/tst/testspecial/current-env.g.out new file mode 100644 index 0000000000..319c9a58d2 --- /dev/null +++ b/tst/testspecial/current-env.g.out @@ -0,0 +1,26 @@ +gap> f := function() +> local i; +> for i in 1 do +> return 1; +> od; +> return 2; +> end;; +gap> f(); +Error, You cannot loop over the integer 1 did you mean the range [1..1] +Stack trace: +*[1] Error( "You cannot loop over the integer ", n, " did you mean the range [1..", n, "]" ); at GAPROOT/lib/integer.gi:LINE called from + [2] for i in 1 do + return 1; +od; at *stdin*:6 called from +( ) + called from read-eval loop at *stdin*:9 +you can 'quit;' to quit to outer loop, or +you can 'return;' to continue +brk> ContentsLVars(CurrentEnv()); +rec( func := function( n ) ... end, names := [ "n" ], values := [ 1 ] ) +brk> DownEnv(); ContentsLVars(CurrentEnv()); +rec( func := function( ) ... end, names := [ "i" ], values := [ ] ) +brk> DownEnv(); ContentsLVars(CurrentEnv()); +rec( func := function( ) ... end, names := [ "i" ], values := [ ] ) +brk> quit; +gap> QUIT; diff --git a/tst/testspecial/debug-var.g.out b/tst/testspecial/debug-var.g.out index 09fe883a0c..60ec4ed89e 100644 --- a/tst/testspecial/debug-var.g.out +++ b/tst/testspecial/debug-var.g.out @@ -11,8 +11,10 @@ gap> f:=function(a) > return g(10) + y; > end;; gap> f(1); -Error, breakpoint at *stdin*:9 called from -g( 10 ) at *stdin*:12 called from +Error, breakpoint +Stack trace: +*[1] Error( "breakpoint" ); at *stdin*:9 called from + [2] g( 10 ) at *stdin*:12 called from ( ) called from read-eval loop at *stdin*:14 you can 'quit;' to quit to outer loop, or @@ -32,9 +34,10 @@ brk> unbound_global; Syntax warning: Unbound global variable in *errin*:6 unbound_global; ^^^^^^^^^^^^^^ -Error, Variable: 'unbound_global' must have a value in - Error( "breakpoint" ); at *stdin*:9 called from -g( 10 ) at *stdin*:12 called from +Error, Variable: 'unbound_global' must have a value +Stack trace: +*[1] Error( "breakpoint" ); at *stdin*:9 called from + [2] g( 10 ) at *stdin*:12 called from ( ) called from read-eval loop at *errin*:6 brk> @@ -46,9 +49,10 @@ brk> y:=100; brk> IsBound(y); true brk> unbound_higher; -Error, Variable: 'unbound_higher' must have an assigned value in - Error( "breakpoint" ); at *stdin*:9 called from -g( 10 ) at *stdin*:12 called from +Error, Variable: 'unbound_higher' must have an assigned value +Stack trace: +*[1] Error( "breakpoint" ); at *stdin*:9 called from + [2] g( 10 ) at *stdin*:12 called from ( ) called from read-eval loop at *errin*:12 type 'quit;' to quit to outer loop @@ -62,9 +66,10 @@ brk> z:=1000; brk> IsBound(z); true brk> unbound_local; -Error, Variable: 'unbound_local' must have an assigned value in - Error( "breakpoint" ); at *stdin*:9 called from -g( 10 ) at *stdin*:12 called from +Error, Variable: 'unbound_local' must have an assigned value +Stack trace: +*[1] Error( "breakpoint" ); at *stdin*:9 called from + [2] g( 10 ) at *stdin*:12 called from ( ) called from read-eval loop at *errin*:17 type 'quit;' to quit to outer loop @@ -76,6 +81,7 @@ gap> x; 42 gap> y; Error, Variable: 'y' must have a value +Stack trace: not in any function at *stdin*:16 gap> gap> h:=function(p) @@ -85,16 +91,20 @@ gap> h:=function(p) > end; function( p ) ... end gap> f(1); -Error, breakpoint at *stdin*:9 called from -g( 10 ) at *stdin*:12 called from +Error, breakpoint +Stack trace: +*[1] Error( "breakpoint" ); at *stdin*:9 called from + [2] g( 10 ) at *stdin*:12 called from ( ) called from read-eval loop at *stdin*:23 you can 'quit;' to quit to outer loop, or you can 'return;' to continue brk> h(2); -Error, foobar at *stdin*:20 called from -Error( "breakpoint" ); at *stdin*:9 called from -g( 10 ) at *stdin*:12 called from +Error, foobar +Stack trace: +*[1] Error( "foobar" ); at *stdin*:20 called from + [2] Error( "breakpoint" ); at *stdin*:9 called from + [3] g( 10 ) at *stdin*:12 called from ( ) called from read-eval loop at *errin*:1 you can 'quit;' to quit to outer loop, or @@ -108,40 +118,45 @@ brk_2> y:=100; brk_2> IsBound(y); true brk_2> unbound_higher; -Error, Variable: must have a value in - Error( "foobar" ); at *stdin*:20 called from -Error( "breakpoint" ); at *stdin*:9 called from -g( 10 ) at *stdin*:12 called from +Error, Variable: must have a value +Stack trace: +*[1] Error( "foobar" ); at *stdin*:20 called from + [2] Error( "breakpoint" ); at *stdin*:9 called from + [3] g( 10 ) at *stdin*:12 called from ( ) called from read-eval loop at *errin*:6 brk_2> brk_2> # check coding of dvars brk_2> function() return unbound_higher; end; -Error, Variable: cannot be used here in - Error( "foobar" ); at *stdin*:20 called from -Error( "breakpoint" ); at *stdin*:9 called from -g( 10 ) at *stdin*:12 called from +Error, Variable: cannot be used here +Stack trace: +*[1] Error( "foobar" ); at *stdin*:20 called from + [2] Error( "breakpoint" ); at *stdin*:9 called from + [3] g( 10 ) at *stdin*:12 called from ( ) called from read-eval loop at *errin*:9 brk_2> function() return IsBound(unbound_higher); end; -Error, Variable: cannot be used here in - Error( "foobar" ); at *stdin*:20 called from -Error( "breakpoint" ); at *stdin*:9 called from -g( 10 ) at *stdin*:12 called from +Error, Variable: cannot be used here +Stack trace: +*[1] Error( "foobar" ); at *stdin*:20 called from + [2] Error( "breakpoint" ); at *stdin*:9 called from + [3] g( 10 ) at *stdin*:12 called from ( ) called from read-eval loop at *errin*:10 brk_2> function() Unbind(unbound_higher); end; -Error, Variable: cannot be used here in - Error( "foobar" ); at *stdin*:20 called from -Error( "breakpoint" ); at *stdin*:9 called from -g( 10 ) at *stdin*:12 called from +Error, Variable: cannot be used here +Stack trace: +*[1] Error( "foobar" ); at *stdin*:20 called from + [2] Error( "breakpoint" ); at *stdin*:9 called from + [3] g( 10 ) at *stdin*:12 called from ( ) called from read-eval loop at *errin*:11 brk_2> function() unbound_higher:=0; end; -Error, Variable: cannot be used here in - Error( "foobar" ); at *stdin*:20 called from -Error( "breakpoint" ); at *stdin*:9 called from -g( 10 ) at *stdin*:12 called from +Error, Variable: cannot be used here +Stack trace: +*[1] Error( "foobar" ); at *stdin*:20 called from + [2] Error( "breakpoint" ); at *stdin*:9 called from + [3] g( 10 ) at *stdin*:12 called from ( ) called from read-eval loop at *errin*:12 brk_2> QUIT; diff --git a/tst/testspecial/error-in-InputTextString.g.out b/tst/testspecial/error-in-InputTextString.g.out index 67f0f64d13..18aca9b5f0 100644 --- a/tst/testspecial/error-in-InputTextString.g.out +++ b/tst/testspecial/error-in-InputTextString.g.out @@ -1,8 +1,8 @@ gap> Read(InputTextString("Print(1 + [()]);")); Error, no method found! For debugging hints type ?Recovery from NoMethodFound -Error, no 1st choice method found for `+' on 2 arguments at GAPROOT/lib/methsel2.g:LINE called from -( ) - called from read-eval loop at stream:1 +Error, no 1st choice method found for `+' on 2 arguments +Stack trace: +called from read-eval loop at stream:1 type 'quit;' to quit to outer loop brk> quit; gap> QUIT; diff --git a/tst/testspecial/func-and-proc-call-trace.g.out b/tst/testspecial/func-and-proc-call-trace.g.out index 6a02269a1c..8e91f92570 100644 --- a/tst/testspecial/func-and-proc-call-trace.g.out +++ b/tst/testspecial/func-and-proc-call-trace.g.out @@ -4,8 +4,9 @@ gap> informproc0 := function(l) > end;; gap> informproc0([]); Error, no method found! For debugging hints type ?Recovery from NoMethodFound -Error, no 1st choice method found for `CallFuncList' on 2 arguments at GAPROOT/lib/methsel2.g:LINE called from -l( ); at *stdin*:4 called from +Error, no 1st choice method found for `CallFuncList' on 2 arguments +Stack trace: +*[1] l( ); at *stdin*:4 called from ( ) called from read-eval loop at *stdin*:6 type 'quit;' to quit to outer loop @@ -19,8 +20,9 @@ gap> informproc1 := function(l) > end;; gap> informproc1([]); Error, no method found! For debugging hints type ?Recovery from NoMethodFound -Error, no 1st choice method found for `CallFuncList' on 2 arguments at GAPROOT/lib/methsel2.g:LINE called from -l( 1 ); at *stdin*:9 called from +Error, no 1st choice method found for `CallFuncList' on 2 arguments +Stack trace: +*[1] l( 1 ); at *stdin*:9 called from ( ) called from read-eval loop at *stdin*:11 type 'quit;' to quit to outer loop @@ -34,8 +36,9 @@ gap> informproc2 := function(l) > end;; gap> informproc2([]); Error, no method found! For debugging hints type ?Recovery from NoMethodFound -Error, no 1st choice method found for `CallFuncList' on 2 arguments at GAPROOT/lib/methsel2.g:LINE called from -l( 1, 2 ); at *stdin*:14 called from +Error, no 1st choice method found for `CallFuncList' on 2 arguments +Stack trace: +*[1] l( 1, 2 ); at *stdin*:14 called from ( ) called from read-eval loop at *stdin*:16 type 'quit;' to quit to outer loop @@ -49,8 +52,9 @@ gap> informproc3 := function(l) > end;; gap> informproc3([]); Error, no method found! For debugging hints type ?Recovery from NoMethodFound -Error, no 1st choice method found for `CallFuncList' on 2 arguments at GAPROOT/lib/methsel2.g:LINE called from -l( 1, 2, 3 ); at *stdin*:19 called from +Error, no 1st choice method found for `CallFuncList' on 2 arguments +Stack trace: +*[1] l( 1, 2, 3 ); at *stdin*:19 called from ( ) called from read-eval loop at *stdin*:21 type 'quit;' to quit to outer loop @@ -64,8 +68,9 @@ gap> informproc4 := function(l) > end;; gap> informproc4([]); Error, no method found! For debugging hints type ?Recovery from NoMethodFound -Error, no 1st choice method found for `CallFuncList' on 2 arguments at GAPROOT/lib/methsel2.g:LINE called from -l( 1, 2, 3, 4 ); at *stdin*:24 called from +Error, no 1st choice method found for `CallFuncList' on 2 arguments +Stack trace: +*[1] l( 1, 2, 3, 4 ); at *stdin*:24 called from ( ) called from read-eval loop at *stdin*:26 type 'quit;' to quit to outer loop @@ -79,8 +84,9 @@ gap> informproc5 := function(l) > end;; gap> informproc5([]); Error, no method found! For debugging hints type ?Recovery from NoMethodFound -Error, no 1st choice method found for `CallFuncList' on 2 arguments at GAPROOT/lib/methsel2.g:LINE called from -l( 1, 2, 3, 4, 5 ); at *stdin*:29 called from +Error, no 1st choice method found for `CallFuncList' on 2 arguments +Stack trace: +*[1] l( 1, 2, 3, 4, 5 ); at *stdin*:29 called from ( ) called from read-eval loop at *stdin*:31 type 'quit;' to quit to outer loop @@ -94,8 +100,9 @@ gap> informproc6 := function(l) > end;; gap> informproc6([]); Error, no method found! For debugging hints type ?Recovery from NoMethodFound -Error, no 1st choice method found for `CallFuncList' on 2 arguments at GAPROOT/lib/methsel2.g:LINE called from -l( 1, 2, 3, 4, 5, 6 ); at *stdin*:34 called from +Error, no 1st choice method found for `CallFuncList' on 2 arguments +Stack trace: +*[1] l( 1, 2, 3, 4, 5, 6 ); at *stdin*:34 called from ( ) called from read-eval loop at *stdin*:36 type 'quit;' to quit to outer loop @@ -109,8 +116,9 @@ gap> informprocmore := function(l) > end;; gap> informprocmore([]); Error, no method found! For debugging hints type ?Recovery from NoMethodFound -Error, no 1st choice method found for `CallFuncList' on 2 arguments at GAPROOT/lib/methsel2.g:LINE called from -l( 1, 2, 3, 4, 5, 6, 7 ); at *stdin*:39 called from +Error, no 1st choice method found for `CallFuncList' on 2 arguments +Stack trace: +*[1] l( 1, 2, 3, 4, 5, 6, 7 ); at *stdin*:39 called from ( ) called from read-eval loop at *stdin*:41 type 'quit;' to quit to outer loop @@ -124,8 +132,9 @@ gap> informfunc0 := function(l) > end;; gap> informfunc0([]); Error, no method found! For debugging hints type ?Recovery from NoMethodFound -Error, no 1st choice method found for `CallFuncList' on 2 arguments at GAPROOT/lib/methsel2.g:LINE called from -l( ) at *stdin*:44 called from +Error, no 1st choice method found for `CallFuncList' on 2 arguments +Stack trace: +*[1] l( ) at *stdin*:44 called from ( ) called from read-eval loop at *stdin*:46 type 'quit;' to quit to outer loop @@ -139,8 +148,9 @@ gap> informfunc1 := function(l) > end;; gap> informfunc1([]); Error, no method found! For debugging hints type ?Recovery from NoMethodFound -Error, no 1st choice method found for `CallFuncList' on 2 arguments at GAPROOT/lib/methsel2.g:LINE called from -l( 1 ) at *stdin*:49 called from +Error, no 1st choice method found for `CallFuncList' on 2 arguments +Stack trace: +*[1] l( 1 ) at *stdin*:49 called from ( ) called from read-eval loop at *stdin*:51 type 'quit;' to quit to outer loop @@ -154,8 +164,9 @@ gap> informfunc2 := function(l) > end;; gap> informfunc2([]); Error, no method found! For debugging hints type ?Recovery from NoMethodFound -Error, no 1st choice method found for `CallFuncList' on 2 arguments at GAPROOT/lib/methsel2.g:LINE called from -l( 1, 2 ) at *stdin*:54 called from +Error, no 1st choice method found for `CallFuncList' on 2 arguments +Stack trace: +*[1] l( 1, 2 ) at *stdin*:54 called from ( ) called from read-eval loop at *stdin*:56 type 'quit;' to quit to outer loop @@ -169,8 +180,9 @@ gap> informfunc3 := function(l) > end;; gap> informfunc3([]); Error, no method found! For debugging hints type ?Recovery from NoMethodFound -Error, no 1st choice method found for `CallFuncList' on 2 arguments at GAPROOT/lib/methsel2.g:LINE called from -l( 1, 2, 3 ) at *stdin*:59 called from +Error, no 1st choice method found for `CallFuncList' on 2 arguments +Stack trace: +*[1] l( 1, 2, 3 ) at *stdin*:59 called from ( ) called from read-eval loop at *stdin*:61 type 'quit;' to quit to outer loop @@ -184,8 +196,9 @@ gap> informfunc4 := function(l) > end;; gap> informfunc4([]); Error, no method found! For debugging hints type ?Recovery from NoMethodFound -Error, no 1st choice method found for `CallFuncList' on 2 arguments at GAPROOT/lib/methsel2.g:LINE called from -l( 1, 2, 3, 4 ) at *stdin*:64 called from +Error, no 1st choice method found for `CallFuncList' on 2 arguments +Stack trace: +*[1] l( 1, 2, 3, 4 ) at *stdin*:64 called from ( ) called from read-eval loop at *stdin*:66 type 'quit;' to quit to outer loop @@ -199,8 +212,9 @@ gap> informfunc5 := function(l) > end;; gap> informfunc5([]); Error, no method found! For debugging hints type ?Recovery from NoMethodFound -Error, no 1st choice method found for `CallFuncList' on 2 arguments at GAPROOT/lib/methsel2.g:LINE called from -l( 1, 2, 3, 4, 5 ) at *stdin*:69 called from +Error, no 1st choice method found for `CallFuncList' on 2 arguments +Stack trace: +*[1] l( 1, 2, 3, 4, 5 ) at *stdin*:69 called from ( ) called from read-eval loop at *stdin*:71 type 'quit;' to quit to outer loop @@ -214,8 +228,9 @@ gap> informfunc6 := function(l) > end;; gap> informfunc6([]); Error, no method found! For debugging hints type ?Recovery from NoMethodFound -Error, no 1st choice method found for `CallFuncList' on 2 arguments at GAPROOT/lib/methsel2.g:LINE called from -l( 1, 2, 3, 4, 5, 6 ) at *stdin*:74 called from +Error, no 1st choice method found for `CallFuncList' on 2 arguments +Stack trace: +*[1] l( 1, 2, 3, 4, 5, 6 ) at *stdin*:74 called from ( ) called from read-eval loop at *stdin*:76 type 'quit;' to quit to outer loop @@ -229,8 +244,9 @@ gap> informfuncmore := function(l) > end;; gap> informfuncmore([]); Error, no method found! For debugging hints type ?Recovery from NoMethodFound -Error, no 1st choice method found for `CallFuncList' on 2 arguments at GAPROOT/lib/methsel2.g:LINE called from -l( 1, 2, 3, 4, 5, 6, 7 ) at *stdin*:79 called from +Error, no 1st choice method found for `CallFuncList' on 2 arguments +Stack trace: +*[1] l( 1, 2, 3, 4, 5, 6, 7 ) at *stdin*:79 called from ( ) called from read-eval loop at *stdin*:81 type 'quit;' to quit to outer loop diff --git a/tst/testspecial/last-access.g.out b/tst/testspecial/last-access.g.out index 3a9778b633..d958151341 100644 --- a/tst/testspecial/last-access.g.out +++ b/tst/testspecial/last-access.g.out @@ -4,7 +4,8 @@ gap> 1;2;3;[last,last2,last3]; 3 [ 3, 2, 1 ] gap> Error("err"); -Error, err called from +Error, err +Stack trace: not in any function at *stdin*:3 you can 'quit;' to quit to outer loop, or you can 'return;' to continue diff --git a/tst/testspecial/line-continuation.g.out b/tst/testspecial/line-continuation.g.out index 35376d1b09..08a8f3b373 100644 --- a/tst/testspecial/line-continuation.g.out +++ b/tst/testspecial/line-continuation.g.out @@ -4,9 +4,11 @@ gap> # counter only once, so that both examples below report the error in line 2 gap> # gap> EvalString("123\\\n45x;"); Error, Variable: '12345x' must have a value +Stack trace: not in any function at stream:2 Error, Could not evaluate string. - at GAPROOT/lib/string.gi:LINE called from +Stack trace: +*[1] Error( "Could not evaluate string.\n" ); at GAPROOT/lib/string.gi:LINE called from ( ) called from read-eval loop at *stdin*:6 you can 'quit;' to quit to outer loop, or @@ -14,9 +16,11 @@ you can 'return;' to continue brk> quit; gap> EvalString("123\\\r\n45x;"); Error, Variable: '12345x' must have a value +Stack trace: not in any function at stream:2 Error, Could not evaluate string. - at GAPROOT/lib/string.gi:LINE called from +Stack trace: +*[1] Error( "Could not evaluate string.\n" ); at GAPROOT/lib/string.gi:LINE called from ( ) called from read-eval loop at *stdin*:6 you can 'quit;' to quit to outer loop, or diff --git a/tst/testspecial/mem-overflow.g.out b/tst/testspecial/mem-overflow.g.out index 26c78ab9b9..df6e77c763 100644 --- a/tst/testspecial/mem-overflow.g.out +++ b/tst/testspecial/mem-overflow.g.out @@ -1,8 +1,9 @@ gap> # double a list until there is a memory overflow gap> l:=[1];; while true do Append(l,l); od; Error, reached the pre-set memory limit -(change it with the -o command line option) in - Append( l, l ); at *stdin*:3 called from +(change it with the -o command line option) +Stack trace: +*[1] Append( l, l ); at *stdin*:3 called from ( ) called from read-eval loop at *stdin*:3 you can 'return;' diff --git a/tst/testspecial/method-not-found-where.g b/tst/testspecial/method-not-found-where.g new file mode 100644 index 0000000000..16ce4149c4 --- /dev/null +++ b/tst/testspecial/method-not-found-where.g @@ -0,0 +1,6 @@ +# test method-not-found traceback rendering while preserving helper access +f := a -> a + a;; +f(()); +ShowMethods(1); +Where(5); +quit; diff --git a/tst/testspecial/method-not-found-where.g.out b/tst/testspecial/method-not-found-where.g.out new file mode 100644 index 0000000000..e2a843aeb7 --- /dev/null +++ b/tst/testspecial/method-not-found-where.g.out @@ -0,0 +1,19 @@ +gap> # test method-not-found traceback rendering while preserving helper access +gap> f := a -> a + a;; +gap> f(()); +Error, no method found! For debugging hints type ?Recovery from NoMethodFound +Error, no 1st choice method found for `+' on 2 arguments +Stack trace: +*[1] a + a at *stdin*:3 called from +( ) + called from read-eval loop at *stdin*:4 +type 'quit;' to quit to outer loop +brk> ShowMethods(1); +#I Searching Method for + with 2 arguments: +#I Total: 138 entries +brk> Where(5); +*[1] a + a at *stdin*:3 called from +( ) + called from read-eval loop at *errin*:2 +brk> quit; +gap> QUIT; diff --git a/tst/testspecial/method-not-found.g.out b/tst/testspecial/method-not-found.g.out index 8b2720acc4..e982bc5443 100644 --- a/tst/testspecial/method-not-found.g.out +++ b/tst/testspecial/method-not-found.g.out @@ -1,8 +1,9 @@ gap> # test returning from a 'method not found' error gap> f:=a->a+a;; f(()); Error, no method found! For debugging hints type ?Recovery from NoMethodFound -Error, no 1st choice method found for `+' on 2 arguments at GAPROOT/lib/methsel2.g:LINE called from -a + a at *stdin*:3 called from +Error, no 1st choice method found for `+' on 2 arguments +Stack trace: +*[1] a + a at *stdin*:3 called from ( ) called from read-eval loop at *stdin*:3 type 'quit;' to quit to outer loop diff --git a/tst/testspecial/print-formatting.g.out b/tst/testspecial/print-formatting.g.out index 91e7af8741..984e623ac8 100644 --- a/tst/testspecial/print-formatting.g.out +++ b/tst/testspecial/print-formatting.g.out @@ -22,6 +22,7 @@ gap> gap> # test formatting status for errout gap> 1/0; # trigger a break loop Error, Rational operations: must not be zero +Stack trace: not in any function at *stdin*:14 type 'quit;' to quit to outer loop brk> old := PrintFormattingStatus("*errout*"); diff --git a/tst/testspecial/repl-syntax-err.g.out b/tst/testspecial/repl-syntax-err.g.out index a6e595e19b..5e160ce41f 100644 --- a/tst/testspecial/repl-syntax-err.g.out +++ b/tst/testspecial/repl-syntax-err.g.out @@ -6,7 +6,8 @@ gap> # error then is displayed. The next line then contains another syntax gap> # error, which wasn't reported correctly before the above issues was gap> # fixed. gap> Error(""): -Error, called from +Error, +Stack trace: not in any function at *stdin*:9 you can 'quit;' to quit to outer loop, or you can 'return;' to continue diff --git a/tst/testspecial/stack-depth-func.g.out b/tst/testspecial/stack-depth-func.g.out index d4350013f1..584e40e9be 100644 --- a/tst/testspecial/stack-depth-func.g.out +++ b/tst/testspecial/stack-depth-func.g.out @@ -1,23 +1,23 @@ gap> f := function() f(); end; function( ) ... end gap> f(); -Error, recursion depth trap (5000) in - f( ); at *stdin*:2 called from -f( ); at *stdin*:2 called from -f( ); at *stdin*:2 called from -f( ); at *stdin*:2 called from -f( ); at *stdin*:2 called from -f( ); at *stdin*:2 called from +Error, recursion depth trap (5000) +Stack trace: +*[1] f( ); at *stdin*:2 called from + [2] f( ); at *stdin*:2 called from + [3] f( ); at *stdin*:2 called from + [4] f( ); at *stdin*:2 called from + [5] f( ); at *stdin*:2 called from ... at *stdin*:3 you may 'return;' brk> return; # try once more -Error, recursion depth trap (10000) in - f( ); at *stdin*:2 called from -f( ); at *stdin*:2 called from -f( ); at *stdin*:2 called from -f( ); at *stdin*:2 called from -f( ); at *stdin*:2 called from -f( ); at *stdin*:2 called from +Error, recursion depth trap (10000) +Stack trace: +*[1] f( ); at *stdin*:2 called from + [2] f( ); at *stdin*:2 called from + [3] f( ); at *stdin*:2 called from + [4] f( ); at *stdin*:2 called from + [5] f( ); at *stdin*:2 called from ... at *stdin*:3 you may 'return;' brk> QUIT; diff --git a/tst/testspecial/stack-depth-func2.g.out b/tst/testspecial/stack-depth-func2.g.out index ef83b7c3ee..d3dbc9bed8 100644 --- a/tst/testspecial/stack-depth-func2.g.out +++ b/tst/testspecial/stack-depth-func2.g.out @@ -1,23 +1,23 @@ gap> f := function() local x; x := f(); return x; end; function( ) ... end gap> y := f(); -Error, recursion depth trap (5000) in - f( ) at *stdin*:2 called from -f( ) at *stdin*:2 called from -f( ) at *stdin*:2 called from -f( ) at *stdin*:2 called from -f( ) at *stdin*:2 called from -f( ) at *stdin*:2 called from +Error, recursion depth trap (5000) +Stack trace: +*[1] f( ) at *stdin*:2 called from + [2] f( ) at *stdin*:2 called from + [3] f( ) at *stdin*:2 called from + [4] f( ) at *stdin*:2 called from + [5] f( ) at *stdin*:2 called from ... at *stdin*:3 you may 'return;' brk> return; # try once more -Error, recursion depth trap (10000) in - f( ) at *stdin*:2 called from -f( ) at *stdin*:2 called from -f( ) at *stdin*:2 called from -f( ) at *stdin*:2 called from -f( ) at *stdin*:2 called from -f( ) at *stdin*:2 called from +Error, recursion depth trap (10000) +Stack trace: +*[1] f( ) at *stdin*:2 called from + [2] f( ) at *stdin*:2 called from + [3] f( ) at *stdin*:2 called from + [4] f( ) at *stdin*:2 called from + [5] f( ) at *stdin*:2 called from ... at *stdin*:3 you may 'return;' brk> QUIT; diff --git a/tst/testspecial/stack-depth-rec.g.out b/tst/testspecial/stack-depth-rec.g.out index 1f719bc613..e9192f564b 100644 --- a/tst/testspecial/stack-depth-rec.g.out +++ b/tst/testspecial/stack-depth-rec.g.out @@ -69,23 +69,23 @@ rec( printing stopped, too many recursion levels! ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) gap> String(r); -Error, recursion depth trap (5000) in - String( record.(nam) ) at GAPROOT/lib/record.gi:LINE called from -String( record.(nam) ) at GAPROOT/lib/record.gi:LINE called from -String( record.(nam) ) at GAPROOT/lib/record.gi:LINE called from -String( record.(nam) ) at GAPROOT/lib/record.gi:LINE called from -String( record.(nam) ) at GAPROOT/lib/record.gi:LINE called from -String( record.(nam) ) at GAPROOT/lib/record.gi:LINE called from +Error, recursion depth trap (5000) +Stack trace: +*[1] String( record.(nam) ) at GAPROOT/lib/record.gi:LINE called from + [2] String( record.(nam) ) at GAPROOT/lib/record.gi:LINE called from + [3] String( record.(nam) ) at GAPROOT/lib/record.gi:LINE called from + [4] String( record.(nam) ) at GAPROOT/lib/record.gi:LINE called from + [5] String( record.(nam) ) at GAPROOT/lib/record.gi:LINE called from ... at *stdin*:4 you may 'return;' brk> return; # try once more -Error, recursion depth trap (5000) in - String( record.(nam) ) at GAPROOT/lib/record.gi:LINE called from -String( record.(nam) ) at GAPROOT/lib/record.gi:LINE called from -String( record.(nam) ) at GAPROOT/lib/record.gi:LINE called from -String( record.(nam) ) at GAPROOT/lib/record.gi:LINE called from -String( record.(nam) ) at GAPROOT/lib/record.gi:LINE called from -String( record.(nam) ) at GAPROOT/lib/record.gi:LINE called from +Error, recursion depth trap (5000) +Stack trace: +*[1] String( record.(nam) ) at GAPROOT/lib/record.gi:LINE called from + [2] String( record.(nam) ) at GAPROOT/lib/record.gi:LINE called from + [3] String( record.(nam) ) at GAPROOT/lib/record.gi:LINE called from + [4] String( record.(nam) ) at GAPROOT/lib/record.gi:LINE called from + [5] String( record.(nam) ) at GAPROOT/lib/record.gi:LINE called from ... at *stdin*:4 you may 'return;' brk> QUIT; diff --git a/tst/testspecial/stack-trace-label.g b/tst/testspecial/stack-trace-label.g new file mode 100644 index 0000000000..622b29c4c7 --- /dev/null +++ b/tst/testspecial/stack-trace-label.g @@ -0,0 +1,5 @@ +f := function() + Error("foo"); +end;; +f(); +quit; diff --git a/tst/testspecial/stack-trace-label.g.out b/tst/testspecial/stack-trace-label.g.out new file mode 100644 index 0000000000..bd31c1584b --- /dev/null +++ b/tst/testspecial/stack-trace-label.g.out @@ -0,0 +1,13 @@ +gap> f := function() +> Error("foo"); +> end;; +gap> f(); +Error, foo +Stack trace: +*[1] Error( "foo" ); at *stdin*:3 called from +( ) + called from read-eval loop at *stdin*:5 +you can 'quit;' to quit to outer loop, or +you can 'return;' to continue +brk> quit; +gap> QUIT; diff --git a/tst/testspecial/syntax-tree-error.g.out b/tst/testspecial/syntax-tree-error.g.out index 543ae16cd1..16b8ded9f9 100644 --- a/tst/testspecial/syntax-tree-error.g.out +++ b/tst/testspecial/syntax-tree-error.g.out @@ -7,7 +7,9 @@ gap> func := SYNTAX_TREE_CODE( SYNTAX_TREE( func ) ); function( ) ... end gap> gap> func( ); -Error, called from +Error, +Stack trace: +*[1] called from ( ) called from read-eval loop at *stdin*:8 you can 'quit;' to quit to outer loop, or diff --git a/tst/testspecial/top-level-error.g.out b/tst/testspecial/top-level-error.g.out index c025522a63..9ed8d6c077 100644 --- a/tst/testspecial/top-level-error.g.out +++ b/tst/testspecial/top-level-error.g.out @@ -1,5 +1,6 @@ gap> Error("foo"); -Error, foo called from +Error, foo +Stack trace: not in any function at *stdin*:2 you can 'quit;' to quit to outer loop, or you can 'return;' to continue diff --git a/tst/testspecial/trace.g.out b/tst/testspecial/trace.g.out index 844962b4d0..3467715778 100644 --- a/tst/testspecial/trace.g.out +++ b/tst/testspecial/trace.g.out @@ -31,6 +31,7 @@ gap> o(1,2,3,4,5,6); [ 1, 2, 3, 4, 5, 6 ] gap> o(1,2,3,4,5,6,7); # not (yet?) supported Error, sorry: cannot yet have X argument operations +Stack trace: not in any function at *stdin*:25 gap> gap> # with tracing @@ -58,6 +59,7 @@ gap> o(1,2,3,4,5,6); [ 1, 2, 3, 4, 5, 6 ] gap> o(1,2,3,4,5,6,7); Error, sorry: cannot yet have X argument operations +Stack trace: not in any function at *stdin*:36 gap> UntraceMethods( o ); # not (yet?) supported gap> @@ -78,6 +80,7 @@ gap> o(1,2,3,4,5,6); [ 1, 2, 3, 4, 5, 6 ] gap> o(1,2,3,4,5,6,7); # not (yet?) supported Error, sorry: cannot yet have X argument operations +Stack trace: not in any function at *stdin*:47 gap> gap> # @@ -110,6 +113,7 @@ gap> o(IsInt,2,3,4,5,6); [ , 2, 3, 4, 5, 6 ] gap> o(IsInt,2,3,4,5,6,7); # not (yet?) supported Error, sorry: cannot yet have X argument constructors +Stack trace: not in any function at *stdin*:70 gap> gap> # with tracing @@ -134,6 +138,7 @@ gap> o(IsInt,2,3,4,5,6); [ , 2, 3, 4, 5, 6 ] gap> o(IsInt,2,3,4,5,6,7); # not (yet?) supported Error, sorry: cannot yet have X argument constructors +Stack trace: not in any function at *stdin*:80 gap> UntraceMethods( o ); gap> @@ -152,5 +157,6 @@ gap> o(IsInt,2,3,4,5,6); [ , 2, 3, 4, 5, 6 ] gap> o(IsInt,2,3,4,5,6,7); # not (yet?) supported Error, sorry: cannot yet have X argument constructors +Stack trace: not in any function at *stdin*:90 gap> QUIT; diff --git a/tst/testspecial/up-down-env.g.out b/tst/testspecial/up-down-env.g.out index 1984ced4bf..a1e18d2a06 100644 --- a/tst/testspecial/up-down-env.g.out +++ b/tst/testspecial/up-down-env.g.out @@ -6,13 +6,13 @@ gap> ## gap> f:=lvl -> 1/lvl + f(lvl-1); function( lvl ) ... end gap> f(7); -Error, Rational operations: must not be zero in - 1 / lvl at *stdin*:7 called from -f( lvl - 1 ) at *stdin*:7 called from -f( lvl - 1 ) at *stdin*:7 called from -f( lvl - 1 ) at *stdin*:7 called from -f( lvl - 1 ) at *stdin*:7 called from -f( lvl - 1 ) at *stdin*:7 called from +Error, Rational operations: must not be zero +Stack trace: +*[1] 1 / lvl at *stdin*:7 called from + [2] f( lvl - 1 ) at *stdin*:7 called from + [3] f( lvl - 1 ) at *stdin*:7 called from + [4] f( lvl - 1 ) at *stdin*:7 called from + [5] f( lvl - 1 ) at *stdin*:7 called from ... at *stdin*:8 type 'quit;' to quit to outer loop brk> UpEnv(1); lvl; @@ -49,7 +49,8 @@ brk> ## brk> ## start a fresh execution context brk> ## brk> Read("top-level-error.g"); -Error, foo called from +Error, foo +Stack trace: not in any function at top-level-error.g:1 you can 'quit;' to quit to outer loop, or you can 'return;' to continue @@ -57,6 +58,7 @@ brk_2> Where(20); not in any function at *errin*:1 brk_2> lvl; # since `Read` started a fresh execution context, we can't access lvl here Error, Variable: 'lvl' must have a value +Stack trace: not in any function at *errin*:2 brk_2> quit; brk> lvl; From 3b4496f41055a67840550385386ed8f83617271e Mon Sep 17 00:00:00 2001 From: Kamil Zabielski <50334623+limakzi@users.noreply.github.com> Date: Wed, 11 Mar 2026 14:59:04 +0100 Subject: [PATCH 106/234] Add IsSymmetricMatrix & IsSymmetricMat (#6259) --- doc/ref/matrix.xml | 1 + lib/matrix.gd | 33 +++++++++++++++++++++++++++++++++ lib/matrix.gi | 25 +++++++++++++++++++++++++ tst/testinstall/matrix.tst | 24 ++++++++++++++++++++++++ 4 files changed, 83 insertions(+) diff --git a/doc/ref/matrix.xml b/doc/ref/matrix.xml index e5708efcb7..fce1638952 100644 --- a/doc/ref/matrix.xml +++ b/doc/ref/matrix.xml @@ -310,6 +310,7 @@ see . <#Include Label="IsDiagonalMat"> <#Include Label="IsUpperTriangularMat"> <#Include Label="IsLowerTriangularMat"> +<#Include Label="IsSymmetricMat"> diff --git a/lib/matrix.gd b/lib/matrix.gd index 620a961cd6..a064894711 100644 --- a/lib/matrix.gd +++ b/lib/matrix.gd @@ -152,6 +152,39 @@ DeclareProperty( "IsLowerTriangularMatrix", IsMatrixOrMatrixObj ); DeclareSynonym( "IsLowerTriangularMat", IsLowerTriangularMatrix ); +############################################################################# +## +#P IsSymmetricMatrix( ) +#P IsSymmetricMat( ) +## +## <#GAPDoc Label="IsSymmetricMat"> +## +## +## +## +## +## return true if the matrix mat is a square matrix and +## satisfies mat[i,j] = mat[j,i] for all +## i, j, and false otherwise. +## IsSymmetricMatrix( [ [ 1 ] ] ); +## true +## gap> IsSymmetricMatrix( [ [ 1, 2 ], [ 2, 1 ] ] ); +## true +## gap> IsSymmetricMatrix( [ [ 0, 1 ], [ 2, 0 ] ] ); +## false +## gap> IsSymmetricMatrix( [ [ 1, 2, 3 ], [ 2, 4, 5 ] ] ); +## false +## ]]> +## +## +## <#/GAPDoc> +## +DeclareProperty( "IsSymmetricMatrix", IsMatrixOrMatrixObj ); + +DeclareSynonym( "IsSymmetricMat", IsSymmetricMatrix ); + + ############################################################################# ## #F DiagonalOfMatrix( ) diff --git a/lib/matrix.gi b/lib/matrix.gi index eefddce0b8..43549df29e 100644 --- a/lib/matrix.gi +++ b/lib/matrix.gi @@ -249,6 +249,31 @@ InstallMethod( IsLowerTriangularMatrix, end); +############################################################################# +## +#M IsSymmetricMatrix() +## +InstallMethod( IsSymmetricMatrix, + "for a matrix", + [ IsMatrixOrMatrixObj ], + function( mat ) + local i, j; + if NrRows( mat ) <> NrCols( mat ) then + return false; + fi; + for i in [ 1 .. NrRows( mat ) ] do + for j in [ i+1 .. NrCols( mat ) ] do + if mat[i,j] <> mat[j,i] then + return false; + fi; + od; + od; + return true; + end ); + +InstallTrueMethod( IsSymmetricMatrix, IsMatrixOrMatrixObj and IsEmptyMatrix ); + + ############################################################################# ## #M DiagonalOfMatrix() . . . . . . . . . . . . . . . diagonal of matrix diff --git a/tst/testinstall/matrix.tst b/tst/testinstall/matrix.tst index 23fca73b26..ea8dd88a81 100644 --- a/tst/testinstall/matrix.tst +++ b/tst/testinstall/matrix.tst @@ -88,6 +88,30 @@ true gap> IsLowerTriangularMat([[1,0],[1,1],[1,1]]); true +# +gap> IsSymmetricMat(NullMat(3, 3)); +true +gap> IsSymmetricMat(IdentityMat(3)); +true +gap> IsSymmetricMat([[1]]); +true +gap> IsSymmetricMat([[1,2],[2,1]]); +true +gap> IsSymmetricMat([[1,2,3],[2,4,5],[3,5,6]]); +true +gap> IsSymmetricMat([[0,1],[2,0]]); +false +gap> IsSymmetricMat([[1,1],[1,1]]); +true +gap> IsSymmetricMat(NullMat(2, 3)); +false +gap> IsSymmetricMat(NullMat(3, 2)); +false +gap> IsSymmetricMat([[1,2,3],[2,4,5]]); +false +gap> IsSymmetricMat([[1,2],[3,4],[5,6]]); +false + # gap> m := Z(5)^0 * [[0, 1], [1, 0]];; gap> m := GeneratorsWithMemory([m])[1];; From 5fb887da0704b54664d508aa0cfe3f76560962a0 Mon Sep 17 00:00:00 2001 From: Max Horn Date: Thu, 12 Mar 2026 16:47:26 +0100 Subject: [PATCH 107/234] Fix ShortestVectors to return complete list (#6253) Also simplify the code a bit. Co-authored-by: Codex --- lib/zlattice.gi | 31 ++++++++++--------- .../2026-02-26-ShortestVectors-positive.tst | 15 +++++++++ 2 files changed, 32 insertions(+), 14 deletions(-) create mode 100644 tst/testbugfix/2026-02-26-ShortestVectors-positive.tst diff --git a/lib/zlattice.gi b/lib/zlattice.gi index f50bb90c74..6cf0f22791 100644 --- a/lib/zlattice.gi +++ b/lib/zlattice.gi @@ -1244,7 +1244,7 @@ end ); InstallGlobalFunction( ShortestVectors, function( arg ) local # variables - n, checkpositiv, a, llg, nullv, m, c, anz, con, b, v, + n, checkpositiv, a, llg, nullv, m, c, con, b, v, # procedures srt, vschr; @@ -1255,7 +1255,6 @@ InstallGlobalFunction( ShortestVectors, function( arg ) if v = nullv then con := false; else - anz := anz + 1; vschr( dam ); fi; else @@ -1289,26 +1288,31 @@ InstallGlobalFunction( ShortestVectors, function( arg ) # output of vector vschr := function( dam ) - local i, j, w, neg; - c.vectors[anz] := []; - neg := false; + local newvec, i, j, w, haspos, hasneg; + newvec := []; + haspos := false; + hasneg := false; for i in [1..n] do w := 0; for j in [1..n] do w := w + v[j] * llg.transformation[j][i]; od; if w < 0 then - neg := true; -#T better here check testpositiv and return! + hasneg := true; + elif w > 0 then + haspos := true; fi; - c.vectors[anz][i] := w; + newvec[i] := w; od; - if checkpositiv and neg then - Unbind(c.vectors[anz]); - anz := anz - 1; - else - c.norms[anz] := dam; + if checkpositiv then + if haspos and hasneg then + return; + elif hasneg then + newvec := -newvec; + fi; fi; + Add(c.vectors, newvec); + Add(c.norms, dam); end; # main program @@ -1347,7 +1351,6 @@ InstallGlobalFunction( ShortestVectors, function( arg ) #T here check that the matrix is really regular #T (empty relations component) - anz := 0; con := true; srt( n, 0 ); diff --git a/tst/testbugfix/2026-02-26-ShortestVectors-positive.tst b/tst/testbugfix/2026-02-26-ShortestVectors-positive.tst new file mode 100644 index 0000000000..1ade3882f0 --- /dev/null +++ b/tst/testbugfix/2026-02-26-ShortestVectors-positive.tst @@ -0,0 +1,15 @@ +# Fix: ShortestVectors(..., "positive") should also accept vectors +# that are nonpositive by replacing them with their negation. + +gap> E8 := +> [ [ 2, -1, 0, 0, 0, 0, 0, 0 ], [ -1, 2, -1, 0, 0, 0, 0, 0 ], +> [ 0, -1, 2, -1, 0, 0, 0, 0 ], [ 0, 0, -1, 2, -1, 0, 0, 0 ], +> [ 0, 0, 0, -1, 2, -1, 0, -1 ], [ 0, 0, 0, 0, -1, 2, -1, 0 ], +> [ 0, 0, 0, 0, 0, -1, 2, 0 ], [ 0, 0, 0, 0, -1, 0, 0, 2 ] ];; +gap> Length( ShortestVectors( E8, 2 ).vectors ); +120 +gap> sv := ShortestVectors( E8, 2, "positive" );; +gap> Length( sv.vectors ); +120 +gap> ForAll( sv.vectors, x -> ForAll( x, y -> y >= 0 ) ); +true From 508533a12db78166be12ccc636f2644b1a2fcc8d Mon Sep 17 00:00:00 2001 From: marcusc31415 <60084271+marcusc31415@users.noreply.github.com> Date: Fri, 13 Mar 2026 19:31:11 +1100 Subject: [PATCH 108/234] Changed rank of \* for IsDirectProductElement and IsObject so it's called when multiplying a direct product element and an integer. (#6249) --- hpcgap/lib/tuples.gi | 14 ++++++++++++++ lib/tuples.gi | 14 ++++++++++++++ ...irectProductElement-Multiply-Integer-Error.tst | 15 +++++++++++++++ 3 files changed, 43 insertions(+) create mode 100644 tst/testbugfix/2026-03-04-DirectProductElement-Multiply-Integer-Error.tst diff --git a/hpcgap/lib/tuples.gi b/hpcgap/lib/tuples.gi index ab53c7478e..09b4b489ad 100644 --- a/hpcgap/lib/tuples.gi +++ b/hpcgap/lib/tuples.gi @@ -523,6 +523,20 @@ InstallOtherMethod( \*, return DirectProductElement( List( dpelm, entry -> nonlist * entry ) ); end ); +InstallOtherMethod( \*, + "for a direct product element, and an integer", + [ IsDirectProductElement, IsInt ], + function( dpelm, int ) + return DirectProductElement( List( dpelm, entry -> entry * int ) ); + end ); + +InstallOtherMethod( \*, + "for an integer, and a direct product element", + [ IsInt, IsDirectProductElement ], + function( int, dpelm ) + return DirectProductElement( List( dpelm, entry -> int * entry ) ); + end ); + ############################################################################# ## diff --git a/lib/tuples.gi b/lib/tuples.gi index 36af635ef6..d377ee88d5 100644 --- a/lib/tuples.gi +++ b/lib/tuples.gi @@ -516,6 +516,20 @@ InstallOtherMethod( \*, return DirectProductElement( List( dpelm, entry -> nonlist * entry ) ); end ); +InstallOtherMethod( \*, + "for a direct product element, and an integer", + [ IsDirectProductElement, IsInt ], + function( dpelm, int ) + return DirectProductElement( List( dpelm, entry -> entry * int ) ); + end ); + +InstallOtherMethod( \*, + "for an integer, and a direct product element", + [ IsInt, IsDirectProductElement ], + function( int, dpelm ) + return DirectProductElement( List( dpelm, entry -> int * entry ) ); + end ); + ############################################################################# ## diff --git a/tst/testbugfix/2026-03-04-DirectProductElement-Multiply-Integer-Error.tst b/tst/testbugfix/2026-03-04-DirectProductElement-Multiply-Integer-Error.tst new file mode 100644 index 0000000000..d32cd309fe --- /dev/null +++ b/tst/testbugfix/2026-03-04-DirectProductElement-Multiply-Integer-Error.tst @@ -0,0 +1,15 @@ +# Tests that specific method for multiplying IsDirectProductElement +# and IsInt is used (the generic method for IsDirectProductElement +# and IsObject has a lower rank than IsAddetiveElement and IsObject). +#@local d +gap> START_TEST("2026-03-04-DirectProductElement-Multiply-Integer-Error.tst"); + +# +gap> d := DirectProductElement( [ (), () ] );; +gap> ApplicableMethod( \*, [1, d] ); +function( int, dpelm ) ... end +gap> ApplicableMethod( \*, [d, 1] ); +function( dpelm, int ) ... end + +# +gap> STOP_TEST("2026-03-04-DirectProductElement-Multiply-Integer-Error.tst"); From 24c0fd42158f71c0ca628a0375a2901a66c47625 Mon Sep 17 00:00:00 2001 From: Max Horn Date: Tue, 17 Mar 2026 23:00:25 +0100 Subject: [PATCH 109/234] Add error checks to ShortestVectors, cleanup (#6273) --- lib/zlattice.gi | 93 ++++++++++--------- .../2026-02-26-ShortestVectors-positive.tst | 12 +++ 2 files changed, 62 insertions(+), 43 deletions(-) diff --git a/lib/zlattice.gi b/lib/zlattice.gi index 6cf0f22791..07b4e7c5a8 100644 --- a/lib/zlattice.gi +++ b/lib/zlattice.gi @@ -1241,21 +1241,24 @@ end ); ## #F ShortestVectors( , [, \"positive\" ] ) ## -InstallGlobalFunction( ShortestVectors, function( arg ) +InstallGlobalFunction( ShortestVectors, function( a, m, arg... ) local # variables - n, checkpositiv, a, llg, nullv, m, c, con, b, v, + n, positiveOnly, llg, zeroCoeffs, c, continueSearch, b, v, i, j, # procedures - srt, vschr; + search, emitVector; - # search for shortest vectors - srt := function( d, dam ) - local i, j, x, k, k1, q; + # Enumerate coefficient vectors recursively in the LLL-reduced basis, + # starting near the nearest integer to keep the search tree small. + search := function( d, norm ) + local i, j, x, k, nextnorm, q; if d = 0 then - if v = nullv then - con := false; + # Once the zero coefficient vector is reached, the remaining branch + # would only enumerate the already covered opposite vectors. + if v = zeroCoeffs then + continueSearch := false; else - vschr( dam ); + emitVector( norm ); fi; else x := 0; @@ -1267,7 +1270,7 @@ InstallGlobalFunction( ShortestVectors, function( arg ) i := i - SignInt( x ); fi; k := i + x; - q := ( m + 1/1000 - dam ) / llg.B[d]; + q := ( m + 1/1000 - norm ) / llg.B[d]; if k * k < q then repeat i := i + 1; @@ -1275,10 +1278,10 @@ InstallGlobalFunction( ShortestVectors, function( arg ) until k * k >= q and k > 0; i := i - 1; k := k - 1; - while k * k < q and con do + while k * k < q and continueSearch do v[d] := i; - k1 := llg.B[d] * k * k + dam; - srt( d-1, k1 ); + nextnorm := llg.B[d] * k * k + norm; + search( d-1, nextnorm ); i := i - 1; k := k - 1; od; @@ -1286,8 +1289,8 @@ InstallGlobalFunction( ShortestVectors, function( arg ) fi; end; - # output of vector - vschr := function( dam ) + # Convert coefficients back to the original basis before storing them. + emitVector := function( norm ) local newvec, i, j, w, haspos, hasneg; newvec := []; haspos := false; @@ -1304,7 +1307,7 @@ InstallGlobalFunction( ShortestVectors, function( arg ) fi; newvec[i] := w; od; - if checkpositiv then + if positiveOnly then if haspos and hasneg then return; elif hasneg then @@ -1312,47 +1315,47 @@ InstallGlobalFunction( ShortestVectors, function( arg ) fi; fi; Add(c.vectors, newvec); - Add(c.norms, dam); + Add(c.norms, norm); end; # main program # check input - if not IsBound( arg[1] ) - or not IsList( arg[1] ) or not IsList( arg[1][1] ) then - Error ( "first argument must be Gram matrix\n", + if not IsMatrixOrMatrixObj( a ) or NrRows( a ) <> NrCols( a ) then + Error ( "first argument must be a square Gram matrix\n", "usage: ShortestVectors( , [,<\"positive\">] )" ); - elif not IsBound( arg[2] ) or not IsInt( arg[2] ) then - Error ( "second argument must be integer\n", + elif not IsInt( m ) or m < 0 then + Error ( "second argument must be a nonnegative integer\n", "usage: ShortestVectors( , [,<\"positive\">] )"); - elif IsBound( arg[3] ) then - if IsString( arg[3] ) then - if arg[3] = "positive" then - checkpositiv := true; - else - checkpositiv := false; - fi; + elif IsBound( arg[1] ) then + if arg[1] = "positive" then + positiveOnly := true; else - Error ( "third argument must be string\n", + Error ( "third argument, if given, must be \"positive\"\n", "usage: ShortestVectors( , [,<\"positive\">] )"); fi; else - checkpositiv := false; + positiveOnly := false; fi; - a := arg[1]; - m := arg[2]; - n := Length( a ); - b := List( a, ShallowCopy ); + if not IsSymmetricMatrix(a) then + Error ( "first argument must be a symmetric Gram matrix\n", + "usage: ShortestVectors( , [,<\"positive\">] )" ); + fi; + n := NrRows( a ); + b := MutableCopyMatrix( a ); c := rec( vectors:= [], norms:= [] ); v := ListWithIdenticalEntries( n, 0 ); - nullv := ListWithIdenticalEntries( n, 0 ); + zeroCoeffs := ListWithIdenticalEntries( n, 0 ); llg:= LLLReducedGramMat( b ); -#T here check that the matrix is really regular -#T (empty relations component) + if Length( llg.relations ) <> 0 then + Error ( "first argument must be a regular Gram matrix\n", + "usage: ShortestVectors( , [,<\"positive\">] )" ); + fi; - con := true; - srt( n, 0 ); + # The small offset avoids missing vectors on the exact norm boundary. + continueSearch := true; + search( n, 0 ); Info( InfoZLattice, 2, "ShortestVectors: ", Length( c.vectors ), " vectors found" ); @@ -1703,14 +1706,14 @@ l := deca( l-1 ); Error( "first argument must be symmetric Gram matrix\n", "usage : Orthog... ( < gram-matrix > \n", " [, <\"positive\"> ] [, < integer > ] )" ); - elif Length( arg[1] ) <> Length( arg[1][1] ) then + elif NrRows( arg[1] ) <> NrCols( arg[1] ) then Error( "Gram matrix must be quadratic\n", "usage : Orthog... ( < gram-matrix >\n", " [, <\"positive\"> ] [, < integer > ] )" ); fi; g := List( arg[1], ShallowCopy ); checkdim := false; - chpo := "xxx"; + chpo := fail; if IsBound( arg[2] ) then if IsString( arg[2] ) then chpo := arg[2]; @@ -1755,7 +1758,11 @@ l := deca( l-1 ); invg := Symmatinv( g ); m := invg.enuminator; invg := invg.inverse; - x := ShortestVectors( invg, m, chpo ); + if chpo = "positive" then + x := ShortestVectors( invg, m, chpo ); + else + x := ShortestVectors( invg, m ); + fi; t := Length(x.vectors); for i in [1..t] do x.vectors[i][n+1] := x.norms[i]; diff --git a/tst/testbugfix/2026-02-26-ShortestVectors-positive.tst b/tst/testbugfix/2026-02-26-ShortestVectors-positive.tst index 1ade3882f0..777682427d 100644 --- a/tst/testbugfix/2026-02-26-ShortestVectors-positive.tst +++ b/tst/testbugfix/2026-02-26-ShortestVectors-positive.tst @@ -13,3 +13,15 @@ gap> Length( sv.vectors ); 120 gap> ForAll( sv.vectors, x -> ForAll( x, y -> y >= 0 ) ); true +gap> ShortestVectors( [ [ 2 ] ], 2, "bogus" ); +Error, third argument, if given, must be "positive" +usage: ShortestVectors( , [,<"positive">] ) +gap> ShortestVectors( [ [ 2 ] ], -1 ); +Error, second argument must be a nonnegative integer +usage: ShortestVectors( , [,<"positive">] ) +gap> ShortestVectors( [ [ 1, 2 ], [ 0, 1 ] ], 1 ); +Error, first argument must be a symmetric Gram matrix +usage: ShortestVectors( , [,<"positive">] ) +gap> ShortestVectors( [ [ 0 ] ], 1 ); +Error, first argument must be a regular Gram matrix +usage: ShortestVectors( , [,<"positive">] ) From 7cbae7712cebb7dafa5bfaf4030c44814f4fe958 Mon Sep 17 00:00:00 2001 From: Max Horn Date: Mon, 23 Mar 2026 09:37:43 +0100 Subject: [PATCH 110/234] Add `FoldLeft`, `FoldLeftX`; and `ForAllX`, `ForAnyX`, `FilteredX`, `NumberX`, `PerformX` to complement `ListX`, `SetX`, `SumX`, `ProductX` (#3357) --- doc/ref/lists.xml | 19 +- lib/coll.gd | 283 ++++++++++++++++- lib/coll.gi | 650 ++++++++++++--------------------------- src/listfunc.c | 128 ++++++++ src/stats.c | 2 +- src/stats.h | 1 + tst/testinstall/coll.tst | 122 ++++++++ 7 files changed, 755 insertions(+), 450 deletions(-) diff --git a/doc/ref/lists.xml b/doc/ref/lists.xml index b652db8af8..3474429248 100644 --- a/doc/ref/lists.xml +++ b/doc/ref/lists.xml @@ -1688,12 +1688,26 @@ with possibly slightly different meaning for lists and non-list collections. The following functions are generalizations of , -, , and . - +, +, +, +, +, +, +, +and . + +<#Include Label="FoldLeft"> +<#Include Label="FoldLeftX"> <#Include Label="ListX"> <#Include Label="SetX"> <#Include Label="SumX"> <#Include Label="ProductX"> +<#Include Label="ForAllX"> +<#Include Label="ForAnyX"> +<#Include Label="FilteredX"> +<#Include Label="NumberX"> +<#Include Label="PerformX"> @@ -1890,4 +1904,3 @@ such as before objectifying, or calling some kernel functions. - diff --git a/lib/coll.gd b/lib/coll.gd index 878aae400b..c44f1364c4 100644 --- a/lib/coll.gd +++ b/lib/coll.gd @@ -2478,6 +2478,126 @@ DeclareOperation( "AsSSortedListNonstored", [IsListOrCollection] ); DeclareGlobalFunction( "Elements" ); +############################################################################# +## +#O FoldLeft( , [, ] ) +## +## <#GAPDoc Label="FoldLeft"> +## +## +## +## +## applies the binary function func +## left-associatively to the elements of the list or collection C. +##

+## If no initial accumulator init is given, the first element of +## C is used as the initial accumulator and the remaining elements +## are combined with it from left to right. In that case C must not +## be empty. +##

+## If init is given, the accumulator is initialized with +## init. Then an empty list or collection is allowed, and +## init is returned unchanged in that case. +##

+## If C is a list with holes, these holes are ignored, just as when +## iterating over the list with a for-loop. +##

+## This operation can be used to express reductions similar to +## or , but it is more general +## because the accumulator is updated by an arbitrary binary function. +##

+## FoldLeft( [ 1 .. 10 ], \+ ); +## 55 +## gap> FoldLeft( [ 1 .. 4 ], \*, 2 ); +## 48 +## gap> FoldLeft( [ 1,, 3 ], { a, b } -> a + b ); +## 4 +## ]]> +## +## +## <#/GAPDoc> +## +DeclareOperation( "FoldLeft", [ IsListOrCollection, IsFunction ] ); +DeclareOperation( "FoldLeft", [ IsListOrCollection, IsFunction, IsObject ] ); + + +############################################################################# +## +#O FoldLeftX( , , [, ] ) +## +## <#GAPDoc Label="FoldLeftX"> +## +## +## +## +## is a generalization of +## which applies an accumulation function func to a bunch of +## inputs which are derived from gens. +##

+## The argument gens must be a plain list whose entries describe a +## sequence of nested loops and filters. Specifically, let n denote +## the length of gens. Then each of the entries +## gens[1], \ldots gens[n] +## must be one of the following: +## +## a list or collection +## +## this introduces a new for-loop in the sequence of nested +## for-loops and if-statements; +## +## a function returning a list or collection +## +## this introduces a new for-loop in the sequence of nested +## for-loops and if-statements, where the loop-range depends on +## the values of the outer loop-variables; or +## +## a function returning true or false +## +## this introduces a new if-statement in the sequence of nested +## for-loops and if-statements. +## +## +##

+## Each function occurring in gens is called with the values selected +## by the preceding entries of gens, in order. +## Thus the function in gens[k] receives one argument for each +## of gens[1], \ldots, gens[k-1] that +## introduced a loop variable. +##

+## The argument func must be a binary function, whose first +## argument is an accumulator variable, and the second argument is +## the tuple of values of the loop-variables. +##

+## The accumulator is initialized with init. For every tuple that is +## produced by the loops and filters described by gens, +## func is called with the current accumulator and that tuple. +## Its return value becomes the new accumulator. +##

+## If the optional argument abortValue is given, iteration stops as +## soon as the accumulator becomes identical to abortValue. +## This is useful for short-circuiting computations such as +## and . +##

+## FoldLeftX( [ [ 1 .. 3 ], i -> [ 1 .. i ], +## > { i, j } -> i <> j ], +## > { acc, x } -> acc + 1, 0 ); +## 3 +## gap> FoldLeftX( [ [ 1 .. 3 ], [ 1 .. 3 ], \< ], +## > function( acc, x ) +## > Add( acc, ShallowCopy( x ) ); +## > return acc; +## > end, [] ); +## [ [ 1, 2 ], [ 1, 3 ], [ 2, 3 ] ] +## ]]> +## +## +## <#/GAPDoc> +## +DeclareGlobalFunction( "FoldLeftX" ); + + ############################################################################# ## #F Sum( [, ] ) . . . . . . . . . . sum of the elements of a list @@ -2803,6 +2923,8 @@ DeclareOperation( "ForAnyOp", [ IsListOrCollection, IsFunction ] ); ## ## ## returns a new list constructed from the arguments. +## The general mechanism underlying this and the related X-functions +## is described in . ##

## Each of the arguments arg1, arg2, \ldots argn ## must be one of the following: @@ -2825,6 +2947,11 @@ DeclareOperation( "ForAnyOp", [ IsListOrCollection, IsFunction ] ); ## ## ##

+## Each function occurring among the arguments is called with the values +## selected by the preceding arguments, in order. +## Thus the function in the k-th argument position receives one +## argument for each preceding argument that introduced a loop variable. +##

## The last argument func must be a function, ## it is applied to the values of the loop-variables ## and the results are collected. @@ -2864,7 +2991,7 @@ DeclareOperation( "ForAnyOp", [ IsListOrCollection, IsFunction ] ); ## l:= [ 1, 2, 3, 4 ];; ## gap> pair:= function( x, y ) return [ x, y ]; end;; -## gap> ListX( l, l, pair ); +## gap> ListX( l, l, {x,y} -> [x,y] ); ## [ [ 1, 1 ], [ 1, 2 ], [ 1, 3 ], [ 1, 4 ], [ 2, 1 ], [ 2, 2 ], ## [ 2, 3 ], [ 2, 4 ], [ 3, 1 ], [ 3, 2 ], [ 3, 3 ], [ 3, 4 ], ## [ 4, 1 ], [ 4, 2 ], [ 4, 3 ], [ 4, 4 ] ] @@ -2895,6 +3022,11 @@ DeclareGlobalFunction( "ListX" ); ## ## The only difference between and ## is that the result list of is strictly sorted. +##

+## SetX( [ 1 .. 3 ], [ 1 .. 3 ], \+ ); +## [ 2, 3, 4, 5, 6 ] +## ]]> ## ## ## <#/GAPDoc> @@ -2913,6 +3045,11 @@ DeclareGlobalFunction( "SetX" ); ## ## returns the sum of the elements in the list obtained ## by when this is called with the same arguments. +##

+## SumX( [ 1 .. 3 ], [ 1 .. 3 ], \+ ); +## 36 +## ]]> ## ## ## <#/GAPDoc> @@ -2932,6 +3069,11 @@ DeclareGlobalFunction( "SumX" ); ## returns the product of the elements in the list ## obtained by when this is called with the same ## arguments. +##

+## ProductX( [ 1 .. 3 ], [ 1 .. 3 ], \+ ); +## 172800 +## ]]> ## ## ## <#/GAPDoc> @@ -2939,6 +3081,145 @@ DeclareGlobalFunction( "SumX" ); DeclareGlobalFunction( "ProductX" ); +############################################################################# +## +#O ForAllX( , , ... ) +## +## <#GAPDoc Label="ForAllX"> +## +## +## +## +## returns true if all elements are +## true in the list obtained by calling with the +## same arguments. Otherwise false is returned. +## As with , the last argument must return either +## true or false, and evaluation stops as soon as the result +## is known. +##

+## ForAllX( [ 1 .. 3 ], [ 1 .. 3 ], \< ); +## false +## ]]> +## +## +## <#/GAPDoc> +## +DeclareGlobalFunction( "ForAllX" ); + + +############################################################################# +## +#O ForAnyX( , , ... ) +## +## <#GAPDoc Label="ForAnyX"> +## +## +## +## +## returns true if any element is +## true in the list obtained by calling with the +## same arguments. Otherwise false is returned. +## As with , the last argument must return either +## true or false, and evaluation stops as soon as the result +## is known. +##

+## ForAnyX( [ 1 .. 3 ], [ 1 .. 3 ], \< ); +## true +## ]]> +## +## +## <#/GAPDoc> +## +DeclareGlobalFunction( "ForAnyX" ); + + +############################################################################# +## +#O FilteredX( , , ... ) +## +## <#GAPDoc Label="FilteredX"> +## +## +## +## +## returns the tuples of loop-variable values for +## which the last argument returns true. +## In other words, it keeps precisely those tuples that would pass the +## filters when calling with the same arguments. +##

+## Even with only one generator, the result consists of singleton tuples. +## Thus FilteredX( [ 1 .. 4 ], IsEvenInt ) returns +## [ [ 2 ], [ 4 ] ], not [ 2, 4 ]. +## Use if you want to filter the elements of a single +## list or collection directly. +##

+## FilteredX( [ 1 .. 4 ], IsEvenInt ); +## [ [ 2 ], [ 4 ] ] +## gap> FilteredX( [ 1 .. 4 ], [ 1 .. 4 ], \< ); +## [ [ 1, 2 ], [ 1, 3 ], [ 1, 4 ], [ 2, 3 ], [ 2, 4 ], [ 3, 4 ] ] +## ]]> +## +## +## <#/GAPDoc> +## +DeclareGlobalFunction( "FilteredX" ); + + +############################################################################# +## +#O NumberX( , , ... ) +## +## <#GAPDoc Label="NumberX"> +## +## +## +## +## returns the number of tuples selected by the last +## argument, using the same arguments as . +## Equivalently, it counts the entries of the result that +## would return with the same arguments. +##

+## NumberX( [ 1 .. 4 ], IsEvenInt ); +## 2 +## gap> NumberX( [ 1 .. 4 ], [ 1 .. 4 ], \< ); +## 6 +## ]]> +## +## +## <#/GAPDoc> +## +DeclareGlobalFunction( "NumberX" ); + + +############################################################################# +## +#O PerformX( , , ... ) +## +## <#GAPDoc Label="PerformX"> +## +## +## +## +## works like except that it +## returns nothing and ignores the return values of func. +## It is useful for iterating through the tuples described by the arguments +## purely for their side effects. +##

+## PerformX( [ 1 .. 2 ], [ 3 .. 4 ], Print ); Print( "\n" ); +## 13142324 +## ]]> +## +## +## <#/GAPDoc> +## +DeclareGlobalFunction( "PerformX" ); + + ############################################################################# ## #O Perform( , ) diff --git a/lib/coll.gi b/lib/coll.gi index 845fbb231d..d49848c5ca 100644 --- a/lib/coll.gi +++ b/lib/coll.gi @@ -1700,361 +1700,153 @@ InstallMethod( ForAnyOp, ## #M ListX(,...) ## -DeclareGlobalName("ListXHelp"); -BIND_GLOBAL( "ListXHelp", function ( result, gens, i, vals, l ) - local gen, val; - while i+1 < Length(gens) do - gen := gens[i+1]; - if IsFunction( gen ) then - gen := CallFuncList( gen, vals ); - fi; - if gen = true then - i := i + 1; - elif gen = false then - return; - elif IsListOrCollection( gen ) then - for val in gen do - vals[l+1] := val; - ListXHelp( result, gens, i+1, vals, l+1 ); - od; - Unbind( vals[l+1] ); - return; - else - Error( "gens[",i+1,"] must be a collection, a list, a boolean, ", - "or a function" ); - fi; - od; - Add( result, CallFuncList( gens[i+1], vals ) ); +InstallGlobalFunction( ListX, function ( arg ) + local f; + f := Remove(arg); + return FoldLeftX(arg, + function(acc, x) + Add(acc, CallFuncList(f, x)); + return acc; + end, []); end ); -BIND_GLOBAL( "ListXHelp2", function ( result, gens, i, val1, val2 ) - local gen, vals, val3; - while i+1 < Length(gens) do - gen := gens[i+1]; - if IsFunction( gen ) then - gen := gen( val1, val2 ); - fi; - if gen = true then - i := i + 1; - elif gen = false then - return; - elif IsListOrCollection( gen ) then - vals := [ val1, val2 ]; - for val3 in gen do - vals[3] := val3; - ListXHelp( result, gens, i+1, vals, 3 ); - od; - Unbind( vals[3] ); - return; - else - Error( "gens[",i+1,"] must be a collection, a list, a boolean, ", - "or a function" ); - fi; - od; - Add( result, gens[i+1]( val1, val2 ) ); -end ); -BIND_GLOBAL( "ListXHelp1", function ( result, gens, i, val1 ) - local gen, val2; - while i+1 < Length(gens) do - gen := gens[i+1]; - if IsFunction( gen ) then - gen := gen( val1 ); - fi; - if gen = true then - i := i + 1; - elif gen = false then - return; - elif IsListOrCollection( gen ) then - for val2 in gen do - ListXHelp2( result, gens, i+1, val1, val2 ); - od; - return; - else - Error( "gens[",i+1,"] must be a collection, a list, a boolean, ", - "or a function" ); - fi; +############################################################################# +## +#F FoldLeft( , ) +#F FoldLeft( , , ) +## +InstallEarlyMethod( FoldLeft, + function( C, func ) + local tnum, result, found, x; + if not IsFunction( func ) then + Error( "usage: FoldLeft( , [, ] )" ); + fi; + tnum:= TNUM_OBJ( C ); + if not ( FIRST_LIST_TNUM <= tnum and tnum <= LAST_LIST_TNUM ) then + TryNextMethod(); + fi; + found := false; + for x in C do + if found then + result := func( result, x ); + else + result := x; + found := true; + fi; od; - Add( result, gens[i+1]( val1 ) ); -end ); + if not found then + Error("folding an empty collection without initial value is not supported"); + fi; + return result; + end ); -BIND_GLOBAL( "ListXHelp0", function ( result, gens, i ) - local gen, val1; - while i+1 < Length(gens) do - gen := gens[i+1]; - if IsFunction( gen ) then - gen := gen(); - fi; - if gen = true then - i := i + 1; - elif gen = false then - return; - elif IsListOrCollection( gen ) then - for val1 in gen do - ListXHelp1( result, gens, i+1, val1 ); - od; - return; - else - Error( "gens[",i+1,"] must be a collection, a list, a boolean, ", - "or a function" ); - fi; +InstallEarlyMethod( FoldLeft, + function( C, func, init ) + local tnum, result, x; + if not IsFunction( func ) then + Error( "usage: FoldLeft( , [, ] )" ); + fi; + tnum:= TNUM_OBJ( C ); + if not ( FIRST_LIST_TNUM <= tnum and tnum <= LAST_LIST_TNUM ) then + TryNextMethod(); + fi; + result := init; + for x in C do + result := func( result, x ); od; - Add( result, gens[i+1]() ); -end ); - -InstallGlobalFunction( ListX, function ( arg ) - local result; - result := []; - ListXHelp0( result, arg, 0 ); return result; -end ); + end ); ############################################################################# ## -#M SetX(,...) +#M FoldLeft( , ) . . . . . . . . for a list/collection, and a function ## -DeclareGlobalName("SetXHelp"); -BIND_GLOBAL( "SetXHelp", function ( result, gens, i, vals, l ) - local gen, val; - while i+1 < Length(gens) do - gen := gens[i+1]; - if IsFunction( gen ) then - gen := CallFuncList( gen, vals ); - fi; - if gen = true then - i := i + 1; - elif gen = false then - return; - elif IsListOrCollection( gen ) then - for val in gen do - vals[l+1] := val; - SetXHelp( result, gens, i+1, vals, l+1 ); - od; - Unbind( vals[l+1] ); - return; - else - Error( "gens[",i+1,"] must be a collection, a list, a boolean, ", - "or a function" ); - fi; - od; - AddSet( result, CallFuncList( gens[i+1], vals ) ); -end ); - -BIND_GLOBAL( "SetXHelp2", function ( result, gens, i, val1, val2 ) - local gen, vals, val3; - while i+1 < Length(gens) do - gen := gens[i+1]; - if IsFunction( gen ) then - gen := gen( val1, val2 ); - fi; - if gen = true then - i := i + 1; - elif gen = false then - return; - elif IsListOrCollection( gen ) then - vals := [ val1, val2 ]; - for val3 in gen do - vals[3] := val3; - SetXHelp( result, gens, i+1, vals, 3 ); - od; - Unbind( vals[3] ); - return; - else - Error( "gens[",i+1,"] must be a collection, a list, a boolean, ", - "or a function" ); - fi; +InstallMethod( FoldLeft, + "for a list/collection, and a function", + [ IsListOrCollection, IsFunction ], + function ( C, func ) + local iter, result, x; + iter := Iterator( C ); + if IsDoneIterator( iter ) then + Error("folding an empty collection without initial value is not supported"); + fi; + result := NextIterator( iter ); + for x in iter do + result := func( result, x ); od; - AddSet( result, gens[i+1]( val1, val2 ) ); -end ); + return result; + end ); -BIND_GLOBAL( "SetXHelp1", function ( result, gens, i, val1 ) - local gen, val2; - while i+1 < Length(gens) do - gen := gens[i+1]; - if IsFunction( gen ) then - gen := gen( val1 ); - fi; - if gen = true then - i := i + 1; - elif gen = false then - return; - elif IsListOrCollection( gen ) then - for val2 in gen do - SetXHelp2( result, gens, i+1, val1, val2 ); - od; - return; - else - Error( "gens[",i+1,"] must be a collection, a list, a boolean, ", - "or a function" ); - fi; - od; - AddSet( result, gens[i+1]( val1 ) ); -end ); -BIND_GLOBAL( "SetXHelp0", function ( result, gens, i ) - local gen, val1; - while i+1 < Length(gens) do - gen := gens[i+1]; - if IsFunction( gen ) then - gen := gen(); - fi; - if gen = true then - i := i + 1; - elif gen = false then - return; - elif IsListOrCollection( gen ) then - for val1 in gen do - SetXHelp1( result, gens, i+1, val1 ); - od; - return; - else - Error( "gens[",i+1,"] must be a collection, a list, a boolean, ", - "or a function" ); - fi; +############################################################################# +## +#M FoldLeft( , , ) . . for a list/coll., a func., and init. val. +## +InstallMethod( FoldLeft, + "for a list/collection, and a function, and an initial value", + [ IsListOrCollection, IsFunction, IsObject ], + function ( C, func, init ) + local result, x; + result := init; + for x in C do + result := func( result, x ); od; - AddSet( result, gens[i+1]() ); -end ); - -InstallGlobalFunction( SetX, function ( arg ) - local result; - result := []; - SetXHelp0( result, arg, 0 ); return result; -end ); + end ); ############################################################################# ## -#M SumX(,...) +#M FoldLeftX(,...) ## -DeclareGlobalName("SumXHelp"); -BIND_GLOBAL( "SumXHelp", function ( result, gens, i, vals, l ) - local gen, val; - while i+1 < Length(gens) do - gen := gens[i+1]; - if IsFunction( gen ) then - gen := CallFuncList( gen, vals ); - fi; - if gen = true then - i := i + 1; - elif gen = false then - return result; - elif IsListOrCollection( gen ) then - for val in gen do - vals[l+1] := val; - result := SumXHelp( result, gens, i+1, vals, l+1 ); - od; - Unbind( vals[l+1] ); - return result; - else - Error( "gens[",i+1,"] must be a collection, a list, a boolean, ", - "or a function" ); - fi; - od; - if result = fail then - result := CallFuncList( gens[i+1], vals ); - else - result := result + CallFuncList( gens[i+1], vals ); - fi; - return result; -end ); +InstallGlobalFunction( FoldLeftX, function ( gens, f, init, extra... ) + local abortValue; -BIND_GLOBAL( "SumXHelp2", function ( result, gens, i, val1, val2 ) - local gen, vals, val3; - while i+1 < Length(gens) do - gen := gens[i+1]; - if IsFunction( gen ) then - gen := gen( val1, val2 ); - fi; - if gen = true then - i := i + 1; - elif gen = false then - return result; - elif IsListOrCollection( gen ) then - vals := [ val1, val2 ]; - for val3 in gen do - vals[3] := val3; - result := SumXHelp( result, gens, i+1, vals, 3 ); - od; - Unbind( vals[3] ); - return result; - else - Error( "gens[",i+1,"] must be a collection, a list, a boolean, ", - "or a function" ); - fi; - od; - if result = fail then - result := gens[i+1]( val1, val2 ); - else - result := result + gens[i+1]( val1, val2 ); + if not IsPlistRep( gens ) or not IsFunction( f ) or Length(extra) > 1 then + Error( "usage: FoldLeftX( , , [, ] )" ); fi; - return result; -end ); - -BIND_GLOBAL( "SumXHelp1", function ( result, gens, i, val1 ) - local gen, val2; - while i+1 < Length(gens) do - gen := gens[i+1]; - if IsFunction( gen ) then - gen := gen( val1 ); - fi; - if gen = true then - i := i + 1; - elif gen = false then - return result; - elif IsListOrCollection( gen ) then - for val2 in gen do - result := SumXHelp2( result, gens, i+1, val1, val2 ); - od; - return result; - else - Error( "gens[",i+1,"] must be a collection, a list, a boolean, ", - "or a function" ); - fi; - od; - if result = fail then - result := gens[i+1]( val1 ); + if Length(extra) > 0 then + abortValue := extra[1]; else - result := result + gens[i+1]( val1 ); + # assign a globally unique bag: here, we take a new empty + # string, which is guaranteed to be different from any + # other string object + abortValue := ""; fi; - return result; + return FOLD_LEFT_X(gens, f, init, abortValue); end ); -BIND_GLOBAL( "SumXHelp0", function ( result, gens, i ) - local gen, val1; - while i+1 < Length(gens) do - gen := gens[i+1]; - if IsFunction( gen ) then - gen := gen(); - fi; - if gen = true then - i := i + 1; - elif gen = false then - return result; - elif IsListOrCollection( gen ) then - for val1 in gen do - result := SumXHelp1( result, gens, i+1, val1 ); - od; - return result; - else - Error( "gens[",i+1,"] must be a collection, a list, a boolean, ", - "or a function" ); - fi; - od; - if result = fail then - result := gens[i+1](); - else - result := result + gens[i+1](); - fi; - return result; + +############################################################################# +## +#M SetX(,...) +## +InstallGlobalFunction( SetX, function ( arg ) + local f; + f := Remove(arg); + return FoldLeftX(arg, + function(acc, x) + AddSet(acc, CallFuncList(f, x)); + return acc; + end, []); end ); + +############################################################################# +## +#M SumX(,...) +## InstallGlobalFunction( SumX, function ( arg ) - local result; - result := fail; - result := SumXHelp0( result, arg, 0 ); - return result; + local f; + f := Remove(arg); + return FoldLeftX(arg, + function(acc, x) + x := CallFuncList(f, x); + if acc = fail then return x; fi; + return acc + x; + end, fail); end ); @@ -2062,135 +1854,103 @@ end ); ## #M ProductX(,...) ## -DeclareGlobalName("ProductXHelp"); -BIND_GLOBAL( "ProductXHelp", function ( result, gens, i, vals, l ) - local gen, val; - while i+1 < Length(gens) do - gen := gens[i+1]; - if IsFunction( gen ) then - gen := CallFuncList( gen, vals ); - fi; - if gen = true then - i := i + 1; - elif gen = false then - return result; - elif IsListOrCollection( gen ) then - for val in gen do - vals[l+1] := val; - result := ProductXHelp( result, gens, i+1, vals, l+1 ); - od; - Unbind( vals[l+1] ); - return result; - else - Error( "gens[",i+1,"] must be a collection, a list, a boolean, ", - "or a function" ); - fi; - od; - if result = fail then - result := CallFuncList( gens[i+1], vals ); - else - result := result * CallFuncList( gens[i+1], vals ); - fi; - return result; +InstallGlobalFunction( ProductX, function ( arg ) + local f; + f := Remove(arg); + return FoldLeftX(arg, + function(acc, x) + x := CallFuncList(f, x); + if acc = fail then return x; fi; + return acc * x; + end, fail); end ); -BIND_GLOBAL( "ProductXHelp2", function ( result, gens, i, val1, val2 ) - local gen, vals, val3; - while i+1 < Length(gens) do - gen := gens[i+1]; - if IsFunction( gen ) then - gen := gen( val1, val2 ); - fi; - if gen = true then - i := i + 1; - elif gen = false then - return result; - elif IsListOrCollection( gen ) then - vals := [ val1, val2 ]; - for val3 in gen do - vals[3] := val3; - result := ProductXHelp( result, gens, i+1, vals, 3 ); - od; - Unbind( vals[3] ); - return result; - else - Error( "gens[",i+1,"] must be a collection, a list, a boolean, ", - "or a function" ); - fi; - od; - if result = fail then - result := gens[i+1]( val1, val2 ); - else - result := result * gens[i+1]( val1, val2 ); - fi; - return result; -end ); -BIND_GLOBAL( "ProductXHelp1", function ( result, gens, i, val1 ) - local gen, val2; - while i+1 < Length(gens) do - gen := gens[i+1]; - if IsFunction( gen ) then - gen := gen( val1 ); - fi; - if gen = true then - i := i + 1; - elif gen = false then - return result; - elif IsListOrCollection( gen ) then - for val2 in gen do - result := ProductXHelp2( result, gens, i+1, val1, val2 ); - od; - return result; - else - Error( "gens[",i+1,"] must be a collection, a list, a boolean, ", - "or a function" ); - fi; - od; - if result = fail then - result := gens[i+1]( val1 ); - else - result := result * gens[i+1]( val1 ); - fi; - return result; +############################################################################# +## +#M ForAllX(,...) +## +InstallGlobalFunction( ForAllX, function ( arg ) + local f; + f := Remove(arg); + return FoldLeftX(arg, + function(acc, x) + if CallFuncList(f, x) then + return true; + else + return false; + fi; + end, true, false); end ); -BIND_GLOBAL( "ProductXHelp0", function ( result, gens, i ) - local gen, val1; - while i+1 < Length(gens) do - gen := gens[i+1]; - if IsFunction( gen ) then - gen := gen(); - fi; - if gen = true then - i := i + 1; - elif gen = false then - return result; - elif IsListOrCollection( gen ) then - for val1 in gen do - result := ProductXHelp1( result, gens, i+1, val1 ); - od; - return result; - else - Error( "gens[",i+1,"] must be a collection, a list, a boolean, ", - "or a function" ); - fi; - od; - if result = fail then - result := gens[i+1](); - else - result := result * gens[i+1](); - fi; - return result; -end ); -InstallGlobalFunction( ProductX, function ( arg ) - local result; - result := fail; - result := ProductXHelp0( result, arg, 0 ); - return result; +############################################################################# +## +#M ForAnyX(,...) +## +InstallGlobalFunction( ForAnyX, function ( arg ) + local f; + f := Remove(arg); + return FoldLeftX(arg, + function(acc, x) + if CallFuncList(f, x) then + return true; + else + return false; + fi; + end, false, true); end ); + +############################################################################# +## +#M FilteredX(,...) +## +InstallGlobalFunction( FilteredX, function ( arg ) + local f; + f := Remove(arg); + return FoldLeftX(arg, + function(acc, x) + if CallFuncList(f, x) then + Add(acc, ShallowCopy(x)); + fi; + return acc; + end, []); +end); + + +############################################################################# +## +#M NumberX(,...) +## +InstallGlobalFunction( NumberX, function ( arg ) + local f; + f := Remove(arg); + return FoldLeftX(arg, + function(acc, x) + if CallFuncList(f, x) then + return acc + 1; + fi; + return acc; + end, 0); +end); + + +############################################################################# +## +#M PerformX(,...) +## +InstallGlobalFunction( PerformX, function ( arg ) + local f; + f := Remove(arg); + FoldLeftX(arg, + function(acc, x) + CallFuncList(f, x); + return 0; + end, 0); +end); + + ############################################################################# ## #F Perform( , ) diff --git a/src/listfunc.c b/src/listfunc.c index 5da324d25a..297fb0e8fa 100644 --- a/src/listfunc.c +++ b/src/listfunc.c @@ -24,7 +24,10 @@ #include "permutat.h" #include "plist.h" #include "pperm.h" +#include "precord.h" +#include "records.h" #include "set.h" +#include "stats.h" #include "stringobj.h" #include "sysfiles.h" #include "trans.h" @@ -1462,6 +1465,126 @@ static Obj FuncLIST_WITH_IDENTICAL_ENTRIES(Obj self, Obj n, Obj obj) return list; } +static Obj FastCallFuncList(Obj func, Obj list) +{ + switch (LEN_PLIST(list)) { + case 0: + return CALL_0ARGS(func); + case 1: + return CALL_1ARGS(func, ELM_PLIST(list, 1)); + case 2: + return CALL_2ARGS(func, ELM_PLIST(list, 1), ELM_PLIST(list, 2)); + case 3: + return CALL_3ARGS(func, ELM_PLIST(list, 1), ELM_PLIST(list, 2), + ELM_PLIST(list, 3)); + case 4: + return CALL_4ARGS(func, ELM_PLIST(list, 1), ELM_PLIST(list, 2), + ELM_PLIST(list, 3), ELM_PLIST(list, 4)); + case 5: + return CALL_5ARGS(func, ELM_PLIST(list, 1), ELM_PLIST(list, 2), + ELM_PLIST(list, 3), ELM_PLIST(list, 4), + ELM_PLIST(list, 5)); + case 6: + return CALL_6ARGS(func, ELM_PLIST(list, 1), ELM_PLIST(list, 2), + ELM_PLIST(list, 3), ELM_PLIST(list, 4), + ELM_PLIST(list, 5), ELM_PLIST(list, 6)); + default: + return CALL_XARGS(func, list); + } +} + +static Obj IsListOrCollection; + +// Recursively walk the generator/filter description in `gens`, updating +// `args` with the currently selected loop variables and folding each produced +// tuple into `*acc`. Return 1 if folding should stop because `abortValue` +// was reached, and 0 otherwise. +static int FoldLeftXHelp(Obj gens, + Obj foldFunc, + Obj * acc, + Obj abortValue, + Obj args, + int genIndex, + int valIndex) +{ + while (genIndex <= LEN_PLIST(gens)) { + Obj gen = ELM_PLIST(gens, genIndex); + if (IS_FUNC(gen)) + gen = FastCallFuncList(gen, args); + if (gen == True) + genIndex++; + else if (gen == False) + return 0; + else if (IS_LIST(gen)) { + const int len = LEN_LIST(gen); + for (int i = 1; i <= len; i++) { + Obj elm = ELM0_LIST(gen, i); + if (!elm) + continue; // skip holes + AssPlist(args, valIndex, elm); + if (FoldLeftXHelp(gens, foldFunc, acc, abortValue, args, + genIndex + 1, valIndex + 1)) + return 1; + } + UNB_LIST(args, valIndex); + return 0; + } + else if (CALL_1ARGS(IsListOrCollection, gen) == True) { + // get the iterator + Obj iter = CALL_1ARGS(ITERATOR, gen); + + Obj nfun, dfun; + if (IS_PREC_OR_COMOBJ(iter) && + CALL_1ARGS(STD_ITER, iter) == True) { + // this can avoid method selection overhead on iterator + dfun = ElmPRec(iter, RNamName("IsDoneIterator")); + nfun = ElmPRec(iter, RNamName("NextIterator")); + } + else { + dfun = IS_DONE_ITER; + nfun = NEXT_ITER; + } + + // loop over the iterator + while (CALL_1ARGS(dfun, iter) == False) { + + // get the element and assign it to the variable + Obj elm = CALL_1ARGS(nfun, iter); + + AssPlist(args, valIndex, elm); + if (FoldLeftXHelp(gens, foldFunc, acc, abortValue, args, + genIndex + 1, valIndex + 1)) + return 1; + } + UNB_LIST(args, valIndex); + return 0; + } + else { + ErrorMayQuit("gens[%d] must be a collection, a list, a boolean, " + "or a function", + genIndex, 0); + } + } + *acc = CALL_2ARGS(foldFunc, *acc, args); + return abortValue == *acc; +} + +// Kernel entry point for FoldLeftX after GAP-level argument validation. +// It allocates the tuple workspace and delegates the actual traversal to +// FoldLeftXHelp, which performs short-circuiting via `abortValue`. +Obj FuncFOLD_LEFT_X( + Obj self, Obj gens, Obj foldFunc, Obj init, Obj abortValue) +{ + if (!IS_PLIST(gens)) + return Fail; + if (!IS_FUNC(foldFunc)) + return Fail; + + Obj args = NEW_PLIST(T_PLIST, LEN_PLIST(gens)); + FoldLeftXHelp(gens, foldFunc, &init, abortValue, args, 1, 1); + return init; +} + /**************************************************************************** ** *F * * * * * * * * * * * * * initialize module * * * * * * * * * * * * * * * @@ -1515,6 +1638,9 @@ static StructGVarFunc GVarFuncs[] = { "srclist,srcstart,srcinc,dstlist,dststart,dstinc,number"), GVAR_FUNC_1ARGS(STRONGLY_CONNECTED_COMPONENTS_DIGRAPH, digraph), GVAR_FUNC_2ARGS(LIST_WITH_IDENTICAL_ENTRIES, n, obj), + + GVAR_FUNC_4ARGS(FOLD_LEFT_X, gens, foldFunc, init, abortValue), + { 0, 0, 0, 0, 0 } }; @@ -1536,6 +1662,8 @@ static Int InitKernel ( InitHandlerFunc( FuncADD_LIST, "src/listfunc.c:FuncADD_LIST" ); InitHandlerFunc( FuncADD_LIST3, "src/listfunc.c:FuncADD_LIST3" ); + ImportFuncFromLibrary("IsListOrCollection", &IsListOrCollection); + return 0; } diff --git a/src/stats.c b/src/stats.c index 130562ad00..fb2de23a1b 100644 --- a/src/stats.c +++ b/src/stats.c @@ -336,7 +336,7 @@ static ExecStatus ExecIfElifElse(Stat stat) Obj ITERATOR; Obj IS_DONE_ITER; Obj NEXT_ITER; -static Obj STD_ITER; +Obj STD_ITER; static ALWAYS_INLINE ExecStatus ExecForHelper(Stat stat, UInt nr) { diff --git a/src/stats.h b/src/stats.h index ac37b53d6a..e74fe543cf 100644 --- a/src/stats.h +++ b/src/stats.h @@ -125,6 +125,7 @@ void ClearError(void); extern Obj ITERATOR; extern Obj IS_DONE_ITER; extern Obj NEXT_ITER; +extern Obj STD_ITER; /**************************************************************************** diff --git a/tst/testinstall/coll.tst b/tst/testinstall/coll.tst index f3a9bdfd21..88b68bdd7a 100644 --- a/tst/testinstall/coll.tst +++ b/tst/testinstall/coll.tst @@ -315,6 +315,110 @@ gap> List(iter); gap> List(iter, x -> x+1); [ 43 ] +############################################################################# +# +# FoldLeft +# +gap> FoldLeft([1..10], \*) = Factorial(10); +true +gap> FoldLeft([1..10], \+) = Sum([1..10]); +true +gap> FoldLeft([1..10], \+, 5) = Sum([1..10], 5); +true +gap> FoldLeft([1,,3], function(a,b) return a+b; end); +4 +gap> FoldLeft([,2,3], function(a,b) return a+b; end); +5 +gap> FoldLeft([], function(a,b) return a+b; end, 10); +10 +gap> FoldLeft([1..3], \-); +-4 +gap> FoldLeft([1..3], \-, 0); +-6 +gap> FoldLeft([], function(a,b) return a+b; end); +Error, folding an empty collection without initial value is not supported + +############################################################################# +# +# FoldLeftX +# +gap> FoldLeftX([[1..2], [3..4]], +> function(acc, x) +> Display(x); +> return true; +> end, false, true); +[ 1, 3 ] +true +gap> FoldLeftX(123, function(acc, x) return acc; end, 0); +Error, usage: FoldLeftX( , , [, ] ) +gap> FoldLeftX([1], 123, 0); +Error, usage: FoldLeftX( , , [, ] ) +gap> FoldLeftX([1], function(acc, x) return acc; end, 0, false, true); +Error, usage: FoldLeftX( , , [, ] ) + +############################################################################# +# +# ForAllX +# +gap> ForAllX([1..2], [3..4], function(i,j) Display([i,j]); return true; end); +[ 1, 3 ] +[ 1, 4 ] +[ 2, 3 ] +[ 2, 4 ] +true +gap> # verify short circuit works +gap> ForAllX([1..2], [3..4], function(i,j) Display([i,j]); return false; end); +[ 1, 3 ] +false +gap> ForAllX([1], x -> 1); +Error, must be 'true' or 'false' (not the integer 1) + +############################################################################# +# +# ForAnyX +# +gap> ForAnyX([1..2], [3..4], function(i,j) Display([i,j]); return false; end); +[ 1, 3 ] +[ 1, 4 ] +[ 2, 3 ] +[ 2, 4 ] +false +gap> # verify short circuit works +gap> ForAnyX([1..2], [3..4], function(i,j) Display([i,j]); return true; end); +[ 1, 3 ] +true +gap> ForAnyX([1], x -> 1); +Error, must be 'true' or 'false' (not the integer 1) + +############################################################################# +# +# FilteredX +# +gap> FilteredX([1..4], IsEvenInt); +[ [ 2 ], [ 4 ] ] +gap> FilteredX([1..4], [1..4], \=); +[ [ 1, 1 ], [ 2, 2 ], [ 3, 3 ], [ 4, 4 ] ] +gap> FilteredX([1..6],[1..6],[1..6], {a,b,c} -> a+b+c<=4); +[ [ 1, 1, 1 ], [ 1, 1, 2 ], [ 1, 2, 1 ], [ 2, 1, 1 ] ] + +############################################################################# +# +# NumberX +# +gap> NumberX([1..4], IsEvenInt); +2 +gap> NumberX([1..4], [1..4], \=); +4 +gap> NumberX([1..6],[1..6],[1..6], {a,b,c} -> a+b+c<=4); +4 + +############################################################################# +# +# PerformX +# +gap> PerformX([1..2], [3..4], Print); Print("\n"); +13142324 + ############################################################################# # # List @@ -513,6 +617,24 @@ gap> ListX([1..3], n -> [1..n], {a,b}->[a,b]); gap> ListX([1..3], [1..3], \<, {a,b}->[a,b]); [ [ 1, 2 ], [ 1, 3 ], [ 2, 3 ] ] +# +gap> args:=[ [], Identity ];; +gap> CallFuncList(SetX, args); +[ ] +gap> CallFuncList(SumX, args); +fail +gap> CallFuncList(ProductX, args); +fail + +# +gap> args:=[ [1..3], Identity ];; +gap> CallFuncList(SetX, args) = Set(CallFuncList(ListX, args)); +true +gap> CallFuncList(SumX, args) = Sum(CallFuncList(ListX, args)); +true +gap> CallFuncList(ProductX, args) = Product(CallFuncList(ListX, args)); +true + # gap> args:=[ [1..3], [1..3], \+ ];; gap> CallFuncList(SetX, args) = Set(CallFuncList(ListX, args)); From ddf9357fa269f7e1e258c1387d11cd1cf336bc8f Mon Sep 17 00:00:00 2001 From: Thomas Breuer Date: Mon, 23 Mar 2026 10:51:53 +0100 Subject: [PATCH 111/234] Set `InfoText` when computing `Irr` (#6275) Whenever the `Irr` value gets computed for a group or a character table, store in `InfoText` of the table which method was used. And add an `Irr` method for the case that `IrrDixonSchneider` is known. (We have at least one package with a method of higher rank than the `IrrDixonSchneider` based method, so this makes sense.) --- lib/ctblgrp.gi | 28 ++++++++++++++++++++++------ lib/ctblsolv.gi | 17 ++++++++++++----- lib/oprtpcgs.gi | 5 ++++- tst/testinstall/ctbl.tst | 20 +++++++++++++++++++- 4 files changed, 57 insertions(+), 13 deletions(-) diff --git a/lib/ctblgrp.gi b/lib/ctblgrp.gi index 36fb803c3b..914845923f 100644 --- a/lib/ctblgrp.gi +++ b/lib/ctblgrp.gi @@ -290,7 +290,7 @@ local b; b:=List(b,i->i{d.invpermlist}); # permuted back r.niceBasis:=Immutable(b); fi; - Assert(1,Length(r.niceBasis)=Length(r.base)); + Assert(1,Length(r.niceBasis)=Length(r.base), "in DxNiceBasis"); return r.niceBasis; end ); @@ -657,7 +657,7 @@ BindGlobal( "DxEigenbase", function(M) minpol:=MinimalPolynomial(BaseDomain(M),M); - Assert(2,IsDuplicateFree(RootsOfUPol(minpol))); + Assert(2,IsDuplicateFree(RootsOfUPol(minpol)), "in DxEigenbase, 1"); eigenvalues:=Set(RootsOfUPol(minpol)); dim:=0; bases:=[]; @@ -674,7 +674,8 @@ BindGlobal( "DxEigenbase", function(M) Error("Failed to calculate eigenspaces."); fi; - Assert(3, ForAll([1..Length(bases)],j->bases[j]*M = bases[j]*eigenvalues[j])); + Assert(3, ForAll([1..Length(bases)],j->bases[j]*M = bases[j]*eigenvalues[j]), + "in DxEigenbase, 2"); return rec(base:=bases, values:=eigenvalues); end ); @@ -791,7 +792,7 @@ InstallGlobalFunction(SplitStep,function(D,bestMat) base:=Matrix(BaseDomain(base[1]),base); eigenbase:=List(eigen.base,i->List(i,j->j*base)); - Assert(1,Length(eigenbase)>1); + Assert(1,Length(eigenbase)>1, "in SplitStep"); ra:=List(eigenbase,i->rec(base:=i,dim:=Length(i))); @@ -2286,7 +2287,7 @@ local k,C,D,dsp; od; C:=DixontinI(D); - Assert(1,Length(C)=D.klanz); + Assert(1,Length(C)=D.klanz, "in IrrDixonSchneider"); # SetIrr(OrdinaryCharacterTable(G),C); # (if `IrrDixonSchneider' is called explicitly, # we want to ignore the attribute) @@ -2326,6 +2327,19 @@ InstallMethod( Irr, return irr; end ); +InstallMethod( Irr, + "for a group with known `IrrDixonSchneider'", + [ IsGroup and HasIrrDixonSchneider, IsZeroCyc ], + function( G, zero ) + local irr, tbl; + irr:= IrrDixonSchneider( G ); + tbl:= OrdinaryCharacterTable( G ); + SetIrr( tbl, irr ); + ComputeAllPowerMaps( tbl ); + SetInfoText( tbl, "origin: Dixon's Algorithm" ); + return irr; + end ); + ############################################################################# ## @@ -2360,7 +2374,8 @@ InstallMethod( Irr, fi; od; od; - Assert( 1, IsCollection( bijection ) and IsEmpty( cclnice ) ); + Assert( 1, IsCollection( bijection ) and IsEmpty( cclnice ), + "in Irr via niceomorphism" ); # Compute the values of the irreducibles of the nice object. irr:= List( Irr( nice ), ValuesOfClassFunction ); @@ -2374,6 +2389,7 @@ InstallMethod( Irr, od; irr:= List( irr, x -> Character( tbl, x ) ); SetIrr( tbl, irr ); + SetInfoText( tbl, "origin: via the nice monomorphism of the group" ); return irr; end ); diff --git a/lib/ctblsolv.gi b/lib/ctblsolv.gi index d5f909829f..9dbf4b116e 100644 --- a/lib/ctblsolv.gi +++ b/lib/ctblsolv.gi @@ -657,7 +657,8 @@ InstallGlobalFunction( CoveringTriplesCharacters, function( G, z ) CanonicalRepresentativeOfExternalSet( orb ) ); if not zn in k then t:= StabilizerOfExternalSet( orb ); - Assert( 1, IsIdenticalObj( Parent( t ), G ) ); + Assert( 1, IsIdenticalObj( Parent( t ), G ), + "in CoveringTriplesCharacters" ); h:= NaturalHomomorphismByNormalSubgroupNC( t, k ); img:= ImagesSource( h ); Append( r, @@ -823,9 +824,11 @@ InstallMethod( Irr, "for a supersolvable group (Conlon's algorithm)", [ IsGroup and IsSupersolvableGroup, IsZeroCyc ], function( G, zero ) - local irr; + local irr, tbl; irr:= IrrConlon( G ); - SetIrr( OrdinaryCharacterTable( G ), irr ); + tbl:= OrdinaryCharacterTable( G ); + SetIrr( tbl, irr ); + SetInfoText( tbl, "origin: Conlon's Algorithm" ); return irr; end ); @@ -833,9 +836,11 @@ InstallMethod( Irr, "for a supersolvable group with known `IrrConlon'", [ IsGroup and IsSupersolvableGroup and HasIrrConlon, IsZeroCyc ], function( G, zero ) - local irr; + local irr, tbl; irr:= IrrConlon( G ); - SetIrr( OrdinaryCharacterTable( G ), irr ); + tbl:= OrdinaryCharacterTable( G ); + SetIrr( tbl, irr ); + SetInfoText( tbl, "origin: Conlon's Algorithm" ); return irr; end ); @@ -853,6 +858,7 @@ InstallMethod( Irr, tbl:= OrdinaryCharacterTable( G ); SetIrr( tbl, irr ); ComputeAllPowerMaps( tbl ); + SetInfoText( tbl, "origin: Baum-Clausen Algorithm" ); return irr; end ); @@ -865,6 +871,7 @@ InstallMethod( Irr, tbl:= OrdinaryCharacterTable( G ); SetIrr( tbl, irr ); ComputeAllPowerMaps( tbl ); + SetInfoText( tbl, "origin: Baum-Clausen Algorithm" ); return irr; end ); diff --git a/lib/oprtpcgs.gi b/lib/oprtpcgs.gi index e69eef458c..91645f5a70 100644 --- a/lib/oprtpcgs.gi +++ b/lib/oprtpcgs.gi @@ -174,7 +174,10 @@ end ); InstallMethod( OrbitStabilizerAlgorithm,"for pcgs",true, [IsGroup,IsObject,IsObject,IsPcgs, - IsList,IsRecord],0, + IsList,IsRecord], + # rank above the method based on 'DoOrbitStabilizerAlgorithmStabsize' + {} -> RankFilter(IsGroup and IsFinite) - RankFilter(IsGroup), + function(G,D,blist,pcgs,acts,pntact) local S,stab,i,pnt,act; pnt:=pntact.pnt; diff --git a/tst/testinstall/ctbl.tst b/tst/testinstall/ctbl.tst index 072ab96268..47cba12b4e 100644 --- a/tst/testinstall/ctbl.tst +++ b/tst/testinstall/ctbl.tst @@ -1,4 +1,4 @@ -#@local g,t,lin +#@local g,t,lin,G gap> START_TEST("ctbl.tst"); # `ClassPositionsOf...' for the trivial group (which usually causes trouble) @@ -433,5 +433,23 @@ true gap> HasIsIrreducibleCharacter( TrivialCharacter( SymmetricGroup( 4 ) ) ); true +# concurring 'Irr' methods +gap> G:= SmallGroup( 24, 5 );; +gap> IsSupersolvable( G ); +true +gap> Irr( G );; +gap> InfoText( OrdinaryCharacterTable( G ) ); +"origin: Baum-Clausen Algorithm" +gap> G:= SmallGroup( 24, 5 );; +gap> IsSupersolvable( G ); +true +gap> IrrConlon( G );; Irr( G );; +gap> InfoText( OrdinaryCharacterTable( G ) ); +"origin: Conlon's Algorithm" +gap> G:= SmallGroup( 24, 5 );; +gap> IrrDixonSchneider( G );; Irr( G );; +gap> InfoText( OrdinaryCharacterTable( G ) ); +"origin: Dixon's Algorithm" + ## gap> STOP_TEST( "ctbl.tst" ); From 64458634059f55bdd1a9ff3f389b16c6d4bbbdd8 Mon Sep 17 00:00:00 2001 From: Thomas Breuer Date: Mon, 23 Mar 2026 13:59:00 +0100 Subject: [PATCH 112/234] Change `IsomorphismPermGroupForMatrixGroup` (#6244) Use a known `NiceMonomorphism` also in the case that its image is *not* a permutation group. The idea is: We trust GAP that the image is nicer than the given group, in the sense that computing an `IsomorphismPermGroup` for the image is easier. An example is that the given group is a matrix group in characteristic zero and its `NiceMonomorphism` is a reduction to a matrix group over a finite field. (This strategy works only because `NiceMonomorphism` guarantees an image that is really nicer. Note that other functions do not have this property, for example `SmallerDegreePermutationRepresentation` is allowed to return an identity mapping.) --- lib/grpmat.gi | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/lib/grpmat.gi b/lib/grpmat.gi index 24b19cc4d1..f34dfde8c5 100644 --- a/lib/grpmat.gi +++ b/lib/grpmat.gi @@ -536,14 +536,23 @@ end ); BindGlobal( "IsomorphismPermGroupForMatrixGroup", function(G) local map; - if not HasNiceMonomorphism(G) or not IsPermGroup(Range(NiceMonomorphism(G))) then - if not HasIsFinite(G) then - Info(InfoWarning,1, - "IsomorphismPermGroup: The group is not known to be finite"); + + if HasNiceMonomorphism( G ) then + map:= NiceMonomorphism( G ); + if not IsPermGroup( Range( map ) ) then + # Trust GAP that this map is still useful. + map:= CompositionMapping( IsomorphismPermGroup( Image( map ) ), map ); + fi; + else + # We cannot be sure about `IsHandledByNiceMonomorphism` for `G`. + if not HasIsFinite( G ) then + Info( InfoWarning,1, + "IsomorphismPermGroup: The group is not known to be finite" ); fi; map:=NicomorphismOfGeneralMatrixGroup(G,false,false); SetNiceMonomorphism(G,map); fi; + # Now `G` stores a `NiceMonomorphism`. if IsPermGroup(Range(NiceMonomorphism(G))) then map:=RestrictedNiceMonomorphism(G); fi; From 3123fdbe0bdd18597f1c0630f4b01eef7559d6ca Mon Sep 17 00:00:00 2001 From: Kamil Zabielski <50334623+limakzi@users.noreply.github.com> Date: Mon, 23 Mar 2026 15:02:53 +0100 Subject: [PATCH 113/234] Speed up `IsSubset` for cyclotomic semirings and ranges (#6265) --- lib/cyclotom.gi | 20 ++++++++++++++++++++ tst/testinstall/cyclotom.tst | 20 +++++++++++++++++++- 2 files changed, 39 insertions(+), 1 deletion(-) diff --git a/lib/cyclotom.gi b/lib/cyclotom.gi index 5aeefe77fe..427822cbca 100644 --- a/lib/cyclotom.gi +++ b/lib/cyclotom.gi @@ -2065,6 +2065,26 @@ function (A,B) end ); +InstallMethod( IsSubset, "for a cyclotomic semiring and a range", + [IsCyclotomicCollection and IsSemiringWithOne, + IsRange], +function (D, R) + if IsEmpty(R) then return true; fi; + # Since D is a semiring-with-one, and thus in particular an additive magma, + # it suffices to check whether the start and end point of the given range + # are contained in it. Actually it suffices if the smaller one is contained + # in it, but figuring out which end is smaller is more work than just + # directly checking both end points. + return First(R) in D and Last(R) in D; +end ); + + +InstallMethod( IsSubset, "for a finite list and a cyclotomic semiring", + [IsList and IsFinite, + IsCyclotomicCollection and IsSemiringWithOne], + ReturnFalse ); + + InstallMethod( Intersection2, "for certain cyclotomic semirings", [IsCyclotomicCollection and IsSemiringWithOne, IsCyclotomicCollection and IsSemiringWithOne], diff --git a/tst/testinstall/cyclotom.tst b/tst/testinstall/cyclotom.tst index 3763995c43..246b0d7cad 100644 --- a/tst/testinstall/cyclotom.tst +++ b/tst/testinstall/cyclotom.tst @@ -1,4 +1,4 @@ -#@local a,cyc,gm,i,l1,l2,l3,mat,n,r,x,y,z,sets +#@local a,b,cyc,gm,i,l1,l2,l3,mat,n,r,ranges,s,x,y,z,sets,lists gap> START_TEST("cyclotom.tst"); # Check basic arithmetic operations. @@ -353,4 +353,22 @@ gap> SetX(r, r, {i,j} -> (sets[i]=sets[j]) = (i=j)); [ true ] # +# IsSubset for cyclotomic semirings and ranges for large bounds +# +gap> sets:=[ PositiveIntegers, NonnegativeIntegers, Integers, GaussianIntegers, GaussianRationals, Cyclotomics ];; +gap> b:=2^(8*GAPInfo.BytesPerVariable - 6);; +gap> ranges:=[ [-2..-1], [-1..0], [-1..1], [0..1], [1..2], [-b..-1], [-b..0], [-b..1], [-1..b], [0..b], [1..b], [-b..b]];; +gap> SetX(ranges, sets, {r,s} -> IsSubset(s,r) = (IsEmpty(r) or (First(r) in s and Last(r) in s))); +[ true ] +gap> SetX(ranges, sets, {r,s} -> not IsSubset(r,s)); +[ true ] + +# +gap> lists:=[ [-2,-1], [], [-1,0,1], [0,1], [1,2], [-b,-1], [-b,0], [-b,1], [-1,b], [0,b], [1,b], [-b,b]];; + +# +gap> SetX(lists, sets, {l,s} -> IsSubset(s,l) = ForAll(l, x -> x in s)); +[ true ] +gap> SetX(lists, sets, {l,s} -> not IsSubset(l,s)); +[ true ] gap> STOP_TEST("cyclotom.tst"); From 0d8d883e78d6f530fe17f1230afca9e50d3e40c1 Mon Sep 17 00:00:00 2001 From: Max Horn Date: Mon, 23 Mar 2026 17:35:12 +0100 Subject: [PATCH 114/234] Support Order, ProjectiveOrder, etc. for MatrixObj (#6278) --- lib/matrix.gd | 10 ++-- lib/matrix.gi | 67 ++++++++++++++++++++++-- tst/testbugfix/2026-03-23-issue-6270.tst | 14 +++++ 3 files changed, 82 insertions(+), 9 deletions(-) create mode 100644 tst/testbugfix/2026-03-23-issue-6270.tst diff --git a/lib/matrix.gd b/lib/matrix.gd index a064894711..210891dccd 100644 --- a/lib/matrix.gd +++ b/lib/matrix.gd @@ -750,7 +750,7 @@ DeclareOperation( "Eigenvectors", [ IsRing, IsMatrix ] ); ## ## <#/GAPDoc> ## -DeclareAttribute( "ProjectiveOrder", IsMatrix ); +DeclareAttribute( "ProjectiveOrder", IsMatrixOrMatrixObj ); ############################################################################# ## @@ -2120,12 +2120,12 @@ DeclareSynonym("OnSubspacesByCanonicalBasisGF2",OnSubspacesByCanonicalBasis); ## ## <#/GAPDoc> ## -DeclareAttribute( "CharacteristicPolynomial", IsMatrix ); -DeclareOperation( "CharacteristicPolynomial", [ IsMatrix, IsPosInt ] ); +DeclareAttribute( "CharacteristicPolynomial", IsMatrixOrMatrixObj ); +DeclareOperation( "CharacteristicPolynomial", [ IsMatrixOrMatrixObj, IsPosInt ] ); DeclareOperation( "CharacteristicPolynomial", - [ IsRing, IsRing, IsMatrix, IsPosInt ] ); + [ IsRing, IsRing, IsMatrixOrMatrixObj, IsPosInt ] ); DeclareOperation( "CharacteristicPolynomial", - [ IsRing, IsRing, IsMatrix ] ); + [ IsRing, IsRing, IsMatrixOrMatrixObj ] ); ############################################################################# diff --git a/lib/matrix.gi b/lib/matrix.gi index 43549df29e..9134c1840d 100644 --- a/lib/matrix.gi +++ b/lib/matrix.gi @@ -720,7 +720,7 @@ InstallMethod( Display, ## InstallMethod( CharacteristicPolynomial, "supply field and indeterminate 1", - [ IsMatrix ], + [ IsMatrixOrMatrixObj ], mat -> CharacteristicPolynomialMatrixNC( DefaultFieldOfMatrix( mat ), mat, 1 ) ); @@ -739,7 +739,7 @@ InstallMethod( CharacteristicPolynomial, fi; return false; end, - [ IsField, IsField, IsMatrix ], + [ IsField, IsField, IsMatrixOrMatrixObj ], function( F, E, mat ) return CharacteristicPolynomial( F, E, mat, 1); end ); @@ -794,6 +794,39 @@ InstallMethod( CharacteristicPolynomialMatrixNC, "spinning over field", [ IsField, IsOrdinaryMatrix, IsPosInt ], Matrix_CharacteristicPolynomialSameField); +InstallOtherMethod( CharacteristicPolynomial, + "matrix object, supply field", + [ IsMatrixObj, IsPosInt ], + function( mat, indnum ) + local F; + F := DefaultFieldOfMatrix( mat ); + return CharacteristicPolynomial( F, F, mat, indnum ); + end ); + +InstallOtherMethod( CharacteristicPolynomial, + "matrix object, spinning over field", + function( famF, famE, fammat, famid ) + local fam; + if HasElementsFamily( fammat ) then + fam := ElementsFamily( fammat ); + return IsIdenticalObj( famF, fam ) + and IsIdenticalObj( famE, fam ); + fi; + return false; + end, + [ IsField, IsField, IsMatrixObj, IsPosInt ], + function( F, E, mat, inum ) + return CharacteristicPolynomial( F, E, Unpack( mat ), inum ); + end ); + +InstallOtherMethod( CharacteristicPolynomialMatrixNC, + "matrix object, spinning over field", + IsElmsCollsX, + [ IsField, IsMatrixObj, IsPosInt ], + function( F, mat, inum ) + return CharacteristicPolynomialMatrixNC( F, Unpack( mat ), inum ); + end ); + ############################################################################# ## @@ -825,14 +858,14 @@ end ); InstallOtherMethod( MinimalPolynomial, "supply field", - [ IsMatrix,IsPosInt ], + [ IsMatrixOrMatrixObj, IsPosInt ], function(m,n) return MinimalPolynomial( DefaultFieldOfMatrix( m ), m, n ); end); InstallOtherMethod( MinimalPolynomial, "supply field and indeterminate 1", - [ IsMatrix ], + [ IsMatrixOrMatrixObj ], function(m) return MinimalPolynomial( DefaultFieldOfMatrix( m ), m, 1 ); end); @@ -842,6 +875,22 @@ InstallMethod( MinimalPolynomialMatrixNC, "spinning over field", [ IsField, IsOrdinaryMatrix, IsPosInt ], Matrix_MinimalPolynomialSameField); +InstallOtherMethod( MinimalPolynomial, + "matrix object, spinning over field", + IsElmsCollsX, + [ IsField, IsMatrixObj, IsPosInt ], + function( F, mat, inum ) + return MinimalPolynomial( F, Unpack( mat ), inum ); + end ); + +InstallOtherMethod( MinimalPolynomialMatrixNC, + "matrix object, spinning over field", + IsElmsCollsX, + [ IsField, IsMatrixObj, IsPosInt ], + function( F, mat, inum ) + return MinimalPolynomialMatrixNC( F, Unpack( mat ), inum ); + end ); + ############################################################################# ## @@ -882,6 +931,11 @@ function ( mat ) return OrderMatTrial(mat,infinity); end ); +InstallOtherMethod( Order, + "matrix objects", + [ IsMatrixObj ], + mat -> Order( Unpack( mat ) ) ); + ############################################################################# ## @@ -2437,6 +2491,11 @@ function( mat ) return ProjectiveOrder(p); end ); +InstallOtherMethod( ProjectiveOrder, + "matrix objects over finite fields", + [ IsMatrixObj and IsFFECollColl ], + mat -> ProjectiveOrder( Unpack( mat ) ) ); + ############################################################################# ## diff --git a/tst/testbugfix/2026-03-23-issue-6270.tst b/tst/testbugfix/2026-03-23-issue-6270.tst new file mode 100644 index 0000000000..9320988555 --- /dev/null +++ b/tst/testbugfix/2026-03-23-issue-6270.tst @@ -0,0 +1,14 @@ +gap> m := NewMatrix( IsPlistMatrixRep, GF(3), 2, +> [ [ 0*Z(3), Z(3) ], [ Z(3)^0, 0*Z(3) ] ] );; +gap> l := Unpack( m );; +gap> IsMatrix( m ); +false +gap> Order( m ) = Order( l ); +true +gap> ProjectiveOrder( m ) = ProjectiveOrder( l ); +true +gap> MinimalPolynomial( m ) = MinimalPolynomial( l ); +true +gap> MinimalPolynomialMatrixNC( DefaultFieldOfMatrix( m ), m, 1 ) +> = MinimalPolynomialMatrixNC( DefaultFieldOfMatrix( l ), l, 1 ); +true From 5ac0084f9e0dba123f3a420ed971a5265d49f59b Mon Sep 17 00:00:00 2001 From: Max Horn Date: Mon, 23 Mar 2026 21:42:05 +0100 Subject: [PATCH 115/234] Faster high-level Meataxe functions for irreducible modules (e.g. `MTX.IsomorphismModules`, `MTX.Indecomposition`, `MTX.BasisModuleEndomorphisms`, `MTX.BasisModuleHomomorphisms`) (#6276) Several high-level Meataxe functions were much, much slower for irreducible modules than their low-level counterparts (the ones which *only* work for irreducible modules). As an example, consider this test input: n:=10;; # increase this to make the effect even stronger G:=GL(56,GF(25));; H:=Subgroup(G, Concatenation(GeneratorsOfGroup(G),List([1..n],i->PseudoRandom(G))));; Then before these changes, we had: gap> MTX.Indecomposition(NaturalGModule(H));; time; 1818 gap> MTX.IsomorphismModules(NaturalGModule(H),NaturalGModule(H));; time; 5408 After these changes: gap> MTX.Indecomposition(NaturalGModule(H));; time; 22 gap> MTX.IsomorphismModules(NaturalGModule(H),NaturalGModule(H));; time; 23 To some extent this papers over a deeper issue: the general code in MTX.Indecomposition and MTX.BasisModuleEndomorphisms ought to be way faster: it is trivial to take the example here and e.g. form a direct sum of modules to make it slow again. --- lib/meatauto.gi | 8 +++++++- tst/testbugfix/2026-03-23-meataxe.tst | 12 ++++++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) create mode 100644 tst/testbugfix/2026-03-23-meataxe.tst diff --git a/lib/meatauto.gi b/lib/meatauto.gi index 7a37aea8a8..1446f312c6 100644 --- a/lib/meatauto.gi +++ b/lib/meatauto.gi @@ -1320,6 +1320,10 @@ local n, hc1, hc2, nc, b1, b2, map, remain, j, found, hom, i, k; Length(SMTX.BasisEndomorphismsRadical(M2)) ) then # different endomorphism algebra dimensions return fail; + elif MTX.IsIrreducible(M1) and MTX.IsIrreducible(M2) then + return MTX.IsomorphismIrred(M1, M2); + elif MTX.IsIrreducible(M1) <> MTX.IsIrreducible(M2) then + return fail; fi; hc1:=SMTX.HomogeneousComponents(M1); @@ -1637,7 +1641,9 @@ end; SMTX.BasisModuleHomomorphisms:=function(m1,m2) local b; TestModulesFitTogether(m1,m2); - if m1.dimension>5 then + if MTX.IsIrreducible(m1) then + b:=MTX.Homomorphisms(m1,m2); + elif m1.dimension>5 then b:= SpinHom(m1,m2); Assert(1,Length(b)=Length(SmalldimHomomorphismsModules(m1,m2))); else diff --git a/tst/testbugfix/2026-03-23-meataxe.tst b/tst/testbugfix/2026-03-23-meataxe.tst new file mode 100644 index 0000000000..2f93914af9 --- /dev/null +++ b/tst/testbugfix/2026-03-23-meataxe.tst @@ -0,0 +1,12 @@ +# Handling of irreducible Meataxe modules with lots of generators was far +# slower than necessary at least via the "high level" Meataxe APIs. +# See also . +# +# The main test here is for performance: before the fix for issue #6271 this +# would have run for minutes, with the fix it should take far less than a +# second on a modern computer. +gap> n:=200;; # increase this to make the effect even stronger +gap> G:=GL(56,GF(25));; +gap> H:=Subgroup(G, Concatenation(GeneratorsOfGroup(G),List([1..n],i->PseudoRandom(G))));; +gap> MTX.IsomorphismModules(NaturalGModule(H), NaturalGModule(H)) <> fail; +true From 98f7f2ceff33b931c2ec33c1ed5a69475f1cc192 Mon Sep 17 00:00:00 2001 From: Max Horn Date: Tue, 24 Mar 2026 10:03:38 +0100 Subject: [PATCH 116/234] Add DirectSumGModule (#6277) Analogue to TensorProductGModule. Co-authored-by: Codex --- doc/ref/meataxe.xml | 15 ++++++++++++--- lib/meataxe.gd | 12 +++++++++++- lib/meataxe.gi | 17 ++++++++++++++++- tst/testinstall/meataxe.tst | 8 +++++++- 4 files changed, 46 insertions(+), 6 deletions(-) diff --git a/doc/ref/meataxe.xml b/doc/ref/meataxe.xml index 8fc93f3bc4..8cc6b4e5ee 100644 --- a/doc/ref/meataxe.xml +++ b/doc/ref/meataxe.xml @@ -116,7 +116,18 @@ Called with a group G and a field F (F may be infinite), calculates the tensor product of the modules m1 and m2. They are assumed to be modules over the same algebra so, in particular, -they should have the same number of generators. +they should have the same number of generators. + + + + + + + + calculates the direct sum +of the modules m1 and m2. +They are assumed to be modules over the same algebra so, in particular, +they should have the same number of generators. @@ -846,5 +857,3 @@ minimal polynomial of . - - diff --git a/lib/meataxe.gd b/lib/meataxe.gd index 23e5f81dd7..45e85af487 100644 --- a/lib/meataxe.gd +++ b/lib/meataxe.gd @@ -62,6 +62,17 @@ DeclareGlobalFunction("PermutationGModule"); ## DeclareGlobalFunction("TensorProductGModule"); +############################################################################### +## +#F DirectSumGModule ( m1, m2 ) . . direct sum of two G-modules +## +## DirectSumGModule calculates the direct sum of smash +## modules m1 and m2. +## They are assumed to be modules over the same algebra so, in particular, +## they should have the same number of generators. +## +DeclareGlobalFunction("DirectSumGModule"); + ############################################################################### ## #F WedgeGModule ( module ) . . . . . wedge product of a G-module @@ -107,4 +118,3 @@ SMTX.Getter := function(string) fi; end; end; - diff --git a/lib/meataxe.gi b/lib/meataxe.gi index 07dfb0e573..7a7b1096b7 100644 --- a/lib/meataxe.gi +++ b/lib/meataxe.gi @@ -196,6 +196,22 @@ InstallGlobalFunction(TensorProductGModule,function( module1, module2) return GModuleByMats(gens, F1); end); +############################################################################### +## +#F DirectSumGModule( module1, module2 ) . . direct sum of two G-modules +## +## DirectSumGModule calculates the direct sum of smash +## modules module1 and module2. +## They are assumed to be modules over the same algebra so, in particular, +## they should have the same number of generators. +## +InstallGlobalFunction(DirectSumGModule,function(module1, module2) + TestModulesFitTogether(module1, module2); + return GModuleByMats(SMTX.MatrixSum(SMTX.Generators(module1), + SMTX.Generators(module2)), + SMTX.Field(module1)); +end); + ############################################################################### ## #F WedgeGModule( module ) . . . . . wedge product of a G-module @@ -3554,4 +3570,3 @@ SMTX.OrthogonalSign:=function(gm) return -1; fi; end; - diff --git a/tst/testinstall/meataxe.tst b/tst/testinstall/meataxe.tst index c8d3651497..1a83a11b9f 100644 --- a/tst/testinstall/meataxe.tst +++ b/tst/testinstall/meataxe.tst @@ -1,4 +1,4 @@ -#@local G,M,M2,M3,M4,M5,V,bf,bo,cf,homs,m,mat,qf,randM,res,sf,subs,mats,Q,orig,S +#@local G,M,M2,M3,M4,M5,M6,V,bf,bo,cf,homs,m,mat,qf,randM,res,sf,subs,mats,Q,orig,S gap> START_TEST("meataxe.tst"); # @@ -56,6 +56,12 @@ gap> M2:=TensorProductGModule(M,M); rec( IsOverFiniteField := true, dimension := 9, field := GF(2), generators := [ , ], isMTXModule := true ) +gap> M6:=DirectSumGModule(M,M); +rec( IsOverFiniteField := true, dimension := 6, field := GF(2), + generators := [ , + ], isMTXModule := true ) +gap> M6.generators[1] = DirectSumMat(M.generators[1], M.generators[1]); +true gap> IdGroup(MTX.ModuleAutomorphisms(M2)); [ 1344, 11301 ] gap> cf:=MTX.CompositionFactors(M2);; From 91699c2b902ba6b19ca3870b57ef042558963bb7 Mon Sep 17 00:00:00 2001 From: Kamil Zabielski <50334623+limakzi@users.noreply.github.com> Date: Tue, 24 Mar 2026 15:47:46 +0100 Subject: [PATCH 117/234] Improve conjugation test (#6267) --- lib/grp.gi | 5 +++++ lib/oprtperm.gi | 10 ++++++++++ tst/testinstall/ConjNatSym.tst | 11 +++++++++++ 3 files changed, 26 insertions(+) diff --git a/lib/grp.gi b/lib/grp.gi index 5453ba0420..ed3ac936cf 100644 --- a/lib/grp.gi +++ b/lib/grp.gi @@ -2956,6 +2956,11 @@ end); InstallMethod(IsConjugate,"subgroups",IsFamFamFam,[IsGroup, IsGroup,IsGroup], function(g,x,y) + # conjugate subgroups must have the same order + if HasSize(x) and HasSize(y) and Size(x) <> Size(y) then + return false; + fi; + # shortcut for normal subgroups if (HasIsNormalInParent(x) and IsNormalInParent(x) and CanComputeIsSubset(Parent(x),g) and IsSubset(Parent(x),g)) diff --git a/lib/oprtperm.gi b/lib/oprtperm.gi index 71a970deba..a1a1616b7c 100644 --- a/lib/oprtperm.gi +++ b/lib/oprtperm.gi @@ -1374,6 +1374,16 @@ InstallOtherMethod( RepresentativeActionOp, "permgrp",true, [ IsPermGroup, # action on permgroups, use backtrack elif act = OnPoints and IsPermGroup( d ) and IsPermGroup( e ) then + # conjugate subgroups must have the same order + if HasSize(d) and HasSize(e) and Size(d) <> Size(e) then + return fail; + fi; + + # conjugate subgroups must be both abelian or both non-abelian + if HasIsAbelian(d) and HasIsAbelian(e) and IsAbelian(d) <> IsAbelian(e) then + return fail; + fi; + if Size(G)<10^5 or NrMovedPoints(G)<500 # cyclic is handled special by backtrack or IsCyclic(d) or IsCyclic(e) or diff --git a/tst/testinstall/ConjNatSym.tst b/tst/testinstall/ConjNatSym.tst index 2e60313603..34c7176a0d 100644 --- a/tst/testinstall/ConjNatSym.tst +++ b/tst/testinstall/ConjNatSym.tst @@ -5,6 +5,17 @@ true gap> IsConjugate( SymmetricGroup(5), Group((1,2)), Group((3,4,5))); false +# Subgroups with different known orders in a non-natural symmetric group +# (exercises the RepresentativeActionOp shortcut, not the natural sym method) +gap> G:= SymmetricGroup( 1000 );; +gap> H:= Subgroup( G, [ G.1 ] );; Size( H ); +1000 +gap> K:= Subgroup( G, [ G.2 ] );; Size( K ); +2 +gap> G:= Group( GeneratorsOfGroup( G ) );; +gap> IsConjugate( G, H, K ); +false + # This runs into the TryNextMethod case gap> IsConjugate( SymmetricGroup(200),SymmetricGroup(200), AlternatingGroup(200)); false From c05a3141306cf2287c5436725e03f987610c9a00 Mon Sep 17 00:00:00 2001 From: Max Horn Date: Tue, 24 Mar 2026 23:57:06 +0100 Subject: [PATCH 118/234] meataxe: use TestModulesFitTogether in more places (#6283) Also adjust formatting of `function` expression headers. Co-authored-by: Codex --- lib/meatauto.gi | 7 +- lib/meataxe.gi | 134 +++++++++++++++--------------------- tst/testinstall/meataxe.tst | 19 +++++ 3 files changed, 74 insertions(+), 86 deletions(-) diff --git a/lib/meatauto.gi b/lib/meatauto.gi index 1446f312c6..6484251b5f 100644 --- a/lib/meatauto.gi +++ b/lib/meatauto.gi @@ -632,10 +632,8 @@ local nv, nw, F, zero, zeroW, gV, gW, k, U, echu, r, homs, s, work, ans, v0, nv:=V.dimension; nw:=W.dimension; + TestModulesFitTogether(V,W); F:=V.field; - if F<>W.field then - Error("different fields"); - fi; zero:=Zero(F); zeroW:=ListWithIdenticalEntries(nw,zero); @@ -647,9 +645,6 @@ local nv, nw, F, zero, zeroW, gV, gW, k, U, echu, r, homs, s, work, ans, v0, # is the number of generators of the acting group k:=Length(gV); - if k<>Length(gW) then - Error("generator lengths"); - fi; # is the semi-ech basis for the currently known submodule, of # dimension diff --git a/lib/meataxe.gi b/lib/meataxe.gi index 7a7b1096b7..5b4b65646e 100644 --- a/lib/meataxe.gi +++ b/lib/meataxe.gi @@ -12,7 +12,7 @@ ## standard MeatAxe interface. It defines the MeatAxe SMTX. ## -InstallGlobalFunction(GModuleByMats,function(arg) +InstallGlobalFunction(GModuleByMats, function(arg) local l,f,dim,m; if Length(arg)<>2 and Length(arg)<>3 then Error("Usage: GModuleByMats(,[,])"); @@ -52,7 +52,7 @@ end); # variant of Value: if we evaluate the polynomial `f` at a matrix `x`, then it # is usually beneficial to first factor `f` and evaluate at the factors -BindGlobal("SMTX_Value",function(f,x,one) +BindGlobal("SMTX_Value", function(f, x, one) local fa; fa:=Factors(f); if Length(fa)>1 then @@ -67,7 +67,7 @@ end); #F TrivialGModule( g, F ) . . . trivial G-module ## ## g is a finite group, F a field, trivial smash G-module computed. -InstallGlobalFunction(TrivialGModule,function(g, F) +InstallGlobalFunction(TrivialGModule, function(g, F) local mats; mats:=List(GeneratorsOfGroup(g),i->[[One(F)]]); return GModuleByMats(mats,F); @@ -80,7 +80,7 @@ end); ## h should be a subgroup of a finite group g, and m a smash ## GModule for h. ## The induced module for g is calculated. -InstallGlobalFunction(InducedGModule,function(g, h, m) +InstallGlobalFunction(InducedGModule, function(g, h, m) local gensh, mats, ghom, gdim, hdim, F, index, gen, genim, gensim, r, i, j, k, l, elt, im; @@ -139,7 +139,7 @@ end); ## ## g is a matrix group, F a field. ## The corresponding natural module is output. -InstallGlobalFunction(NaturalGModule,function(group, field...) +InstallGlobalFunction(NaturalGModule, function(group, field...) if not IsMatrixGroup(group) then Error(" must be a matrix group"); fi; @@ -159,7 +159,7 @@ end); ## ## g is a permutation group, F a field. ## The corresponding permutation module is output. -InstallGlobalFunction(PermutationGModule,function(g, F) +InstallGlobalFunction(PermutationGModule, function(g, F) local gens, deg; gens:=GeneratorsOfGroup(g); deg:=LargestMovedPoint(gens); @@ -175,25 +175,14 @@ end); ## They are assumed to be modules over the same algebra so, in particular, ## they should have the same number of generators. ## -InstallGlobalFunction(TensorProductGModule,function( module1, module2) - local mat1, mat2, F1, F2, gens, i, l; +InstallGlobalFunction(TensorProductGModule, function(module1, module2) + local mat1, mat2, gens; - mat1:=SMTX.Generators(module1); mat2:=SMTX.Generators(module2); - F1:=SMTX.Field(module1); F2:=SMTX.Field(module2); - if F1 <> F2 then - Error("GModules are defined over different fields.\n"); - fi; - l:=Length(mat1); - if l <> Length(mat2) then - Error("GModules have different numbers of generators."); - fi; - - gens:=[]; - for i in [1..l] do - gens[i]:=KroneckerProduct(mat1[i], mat2[i]); - od; - - return GModuleByMats(gens, F1); + TestModulesFitTogether(module1, module2); + mat1:=SMTX.Generators(module1); + mat2:=SMTX.Generators(module2); + gens:=List([1..Length(mat1)], i -> KroneckerProduct(mat1[i], mat2[i])); + return GModuleByMats(gens, SMTX.Field(module1)); end); ############################################################################### @@ -205,7 +194,7 @@ end); ## They are assumed to be modules over the same algebra so, in particular, ## they should have the same number of generators. ## -InstallGlobalFunction(DirectSumGModule,function(module1, module2) +InstallGlobalFunction(DirectSumGModule, function(module1, module2) TestModulesFitTogether(module1, module2); return GModuleByMats(SMTX.MatrixSum(SMTX.Generators(module1), SMTX.Generators(module2)), @@ -219,7 +208,7 @@ end); ## WedgeGModule calculates the wedge product of a G-module. ## That is the action on antisymmetrix tensors. ## -InstallGlobalFunction(WedgeGModule,function( module) +InstallGlobalFunction(WedgeGModule, function(module) local mats, mat, newmat, row, F, gens, dim, nmats, i, j, k, m, n, x; mats:=SMTX.Generators(module); @@ -288,7 +277,7 @@ SMTX.Generators:=function(module) fi; end; -SMTX.SetIsIrreducible:=function(module,b) +SMTX.SetIsIrreducible:=function(module, b) module.IsIrreducible:=b; end; @@ -307,7 +296,7 @@ SMTX.IsAbsolutelyIrreducible:=function(module) return module.IsAbsolutelyIrreducible; end; -SMTX.SetIsAbsolutelyIrreducible:=function(module,b) +SMTX.SetIsAbsolutelyIrreducible:=function(module, b) module.IsAbsolutelyIrreducible:=b; end; @@ -350,7 +339,7 @@ SMTX.SetDegreeFieldExt:=SMTX.Setter("degreeFieldExt"); ## N.B. subbasis is assumed to consist of normed vectors, ## submodule is assumed proper. ## -SMTX.OrthogonalVector:=function( subbasis ) +SMTX.OrthogonalVector:=function(subbasis) local zero, one, v, i, j, k, x, dim, len; subbasis:=ShallowCopy(subbasis); Sort(subbasis); @@ -406,7 +395,7 @@ end ); ## It is returned as a list of normed vectors. ## If the optional fourth argument is present, then only the first ngens ## matrices in the list are used. -SMTX.SpinnedBasis:=function( v, matrices, F, ngens... ) +SMTX.SpinnedBasis:=function(v, matrices, F, ngens...) local zero, ldim, step, ans, dim, subdim, leadpos, w, i, j, k, l, m; if Length(ngens) > 1 then @@ -674,7 +663,7 @@ end; ## SMTX.InducedActionSubmoduleNB( module, sub ) computes the submodule of ## module for which sub is the basis. ## If sub does not generate a submodule then fail is returned. -SMTX.InducedActionSubmoduleNB:=function( module, sub ) +SMTX.InducedActionSubmoduleNB:=function(module, sub) local ans; if Length(sub) = 0 then @@ -691,7 +680,7 @@ SMTX.InducedActionSubmoduleNB:=function( module, sub ) end; # Ditto, but allowing also unnormed modules -SMTX.InducedActionSubmodule:=function(module,sub) +SMTX.InducedActionSubmodule:=function(module, sub) local nb,ans; nb:=SMTX.NormedBasisAndBaseChange(sub); @@ -759,7 +748,7 @@ end; #F SMTX.InducedActionFactorModuleWithBasis( module, sub ) ## # FIXME: this function is never used and undocumented. Keep it or remove it? -SMTX.InducedActionFactorModuleWithBasis:=function(module,sub) +SMTX.InducedActionFactorModuleWithBasis:=function(module, sub) local ans, qmodule; sub:=TriangulizedMat(sub); @@ -799,7 +788,7 @@ end; ## C B ## corresponding matrices of smodule and qmodule resepctively. ## If sub is not the basis of a submodule then fail is returned. -SMTX.InducedAction:=function(module, sub, typ... ) +SMTX.InducedAction:=function(module, sub, typ...) local ans,erg; if Length(typ)>0 then @@ -839,7 +828,7 @@ end; ## ## as InducedActionSubmoduleNB but for a matrix. # FIXME: this function is never used and undocumented. Keep it or remove it? -SMTX.InducedActionSubMatrixNB:=function( mat, sub ) +SMTX.InducedActionSubMatrixNB:=function(mat, sub) local module, ans; if Length(sub) = 0 then @@ -859,7 +848,7 @@ end; # Ditto, but allowing also unnormed modules # FIXME: this function is never used and undocumented. Keep it or remove it? -SMTX.InducedActionSubMatrix:=function(mat,sub) +SMTX.InducedActionSubMatrix:=function(mat, sub) local nb, module, ans; nb:=SMTX.NormedBasisAndBaseChange(sub); @@ -914,7 +903,7 @@ local module, ans; return ans.qmatrices[1]; end; -SMTX.SMCoRaEl:=function(matrices,ngens,newgenlist,dim,F) +SMTX.SMCoRaEl:=function(matrices, ngens, newgenlist, dim, F) local g1,g2,coefflist,M,pol; g1:=Random(1, ngens); g2:=g1; @@ -995,7 +984,7 @@ SMTX.RAND_ELM_LIMIT:=5000; ## ## This function can also be used to get a random submodule. Therefore it ## is not an end-user function but only called internally -SMTX.IrreducibilityTest:=function( module ) +SMTX.IrreducibilityTest:=function(module) local matrices, tmatrices, ngens, ans, M, mat, g1, g2, maxdeg, newgenlist, coefflist, zero, N, NT, v, subbasis, fac, sfac, pol, orig_pol, q, dim, ndim, i, @@ -1265,7 +1254,7 @@ end; ## submodule of module, and return that basis and the submodule, with all ## the irreducibility flags set. ## Returns false if module is irreducible. -SMTX.RandomIrreducibleSubGModule:=function( module ) +SMTX.RandomIrreducibleSubGModule:=function(module) local ranSub, subbasis, submodule, subbasis2, submodule2, F, el, M, fac, N, i, matrices, genpair; @@ -1350,7 +1339,7 @@ end; ## minimal possible dimension. This dimension is 1 if the module is absolutely ## irreducible, and the degree of the relevant field extension otherwise. ## This is needed for testing for equivalence of modules. -SMTX.GoodElementGModule:=function( module ) +SMTX.GoodElementGModule:=function(module) local matrices, M, mat, N, newgenlist, coefflist, fac, pol, oldpol, q, deg, i, l, trying, dim, mindim, F, R, count, rt0, idmat; @@ -1471,7 +1460,7 @@ end; ## It is based on code of MinPolCoeffsMat. ## The optional fourth argument is for returning the basis for this block. ## -SMTX.FrobeniusAction:=function( fld, A, v, basis... ) +SMTX.FrobeniusAction:=function(fld, A, v, basis...) local L, d, p, M, one, zero, R, h, w, i, j, nd, ans; if Length(basis) = 0 then @@ -1555,7 +1544,7 @@ end; ## true or false according to whether it succeeds. ## It is called by IsAbsolutelyIrreducible() ## -SMTX.CompleteBasis:=function( matrices, basis ) +SMTX.CompleteBasis:=function(matrices, basis) local L, d, subd, subd0, h, v, w, i, bno, gno, vno, newb, ngens; subd:=Length(basis); @@ -1644,7 +1633,7 @@ end; ## The function shouldn't be called if the module has not already been ## shown to be irreducible, using IsIrreducible. ## -SMTX.AbsoluteIrreducibilityTest:=function( module ) +SMTX.AbsoluteIrreducibilityTest:=function(module) local dim, ndim, gcd, div, e, ct, F, q, ok, M, v, M0, v0, C, C0, centmat, one, zero, pow, matrices, newmatrices, looking, @@ -1842,7 +1831,7 @@ end; ## is q^e - 1, where e is the degree of the centralizing field. This is not ## yet used, but maybe in future, if we wish to reduce the group to matrices ## over the larger field. -SMTX.FieldGenCentMat:=function( module ) +SMTX.FieldGenCentMat:=function(module) local e, F, R, q, qe, minpol, pp, centmat, newcentmat, genpol, looking, okd; @@ -1921,7 +1910,7 @@ end; ## where m is an irreducible composition factor of module, and n is the ## number of times it occurs in module. ## -SMTX.CollectedFactors:= function( module ) +SMTX.CollectedFactors:= function(module) local field,dim, factors, factorsout, queue, cmod, new, d, i, j, l, lf, q, smod, ds, homs, mat; if SMTX.IsMTXModule(module) = false then @@ -2030,7 +2019,7 @@ SMTX.CollectedFactors:= function( module ) end; -SMTX.CompositionFactors:=function( module ) +SMTX.CompositionFactors:=function(module) if SMTX.IsIrreducible(module) then return [module]; else @@ -2052,7 +2041,7 @@ end; ## Once this is done, it is easy to find submodules containing this ## composition factor. ## -SMTX.Distinguish:=function( cf, i ) +SMTX.Distinguish:=function(cf, i) local el, genpair, ngens, mat, matsi, mats, M, idmat, dim, F, fac, p, q, oldp, found, extdeg, j, k, lcf, lf, x, y, wno, deg, trying, N, fact, R; @@ -2198,7 +2187,7 @@ end; ## A basis of a minimal submodule of module containing the composition factor ## cf[i][1] is calculated and returned - i.e. if cf[i][2] = 1. ## -SMTX.MinimalSubGModule:=function( module, cf, i ) +SMTX.MinimalSubGModule:=function(module, cf, i) local el, genpair, mat, mats, M, F, k, N, fact; @@ -2249,9 +2238,8 @@ SMTX.IsomorphismComp:=function(module1, module2, action) Error("Argument is not a module."); elif SMTX.IsMTXModule(module2) = false then Error("Argument is not a module."); - elif SMTX.Field(module1) <> SMTX.Field(module2) then - Error("GModules are defined over different fields."); fi; + TestModulesFitTogether(module1, module2); swapped:=false; if not SMTX.HasIsIrreducible(module1) then @@ -2281,9 +2269,6 @@ SMTX.IsomorphismComp:=function(module1, module2, action) SMTX.GoodElementGModule(module1); mats1:=module1.generators; mats2:=ShallowCopy(module2.generators); - if Length(mats1) <> Length(mats2) then - Error("GModules have different numbers of defining matrices."); - fi; # Now we calculate the element in the group algebra of module2 that # corresponds to that in module1. This is done using the AlgEl flag @@ -2349,13 +2334,13 @@ SMTX.IsomorphismComp:=function(module1, module2, action) fi; end; -SMTX.IsomorphismIrred:=function(module1,module2) +SMTX.IsomorphismIrred:=function(module1, module2) return SMTX.IsomorphismComp(module1,module2,true); end; SMTX.Isomorphism:=SMTX.IsomorphismIrred; -SMTX.IsEquivalent:=function(module1,module2) +SMTX.IsEquivalent:=function(module1, module2) return SMTX.IsomorphismComp(module1,module2,false)<>fail; end; @@ -2401,16 +2386,10 @@ SMTX.Homomorphisms:= function(module1, module2) if not SMTX.IsMTXModule(module2) then return Error("Second argument is not a module."); fi; + TestModulesFitTogether(module1, module2); mats1:=module1.generators; mats2:=ShallowCopy(module2.generators); - if Length(mats1) <> Length(mats2) then - return Error("GModules have different numbers of generators."); - fi; - F:=SMTX.Field(module1); - if F <> SMTX.Field(module2) then - return Error("GModules are defined over different fields."); - fi; zero:=Zero(F); dim1:=SMTX.Dimension(module1); dim2:=SMTX.Dimension(module2); @@ -2726,16 +2705,11 @@ end; SMTX.Homomorphism:=function(module1, module2, mat) local F, gens1, gens2, ng, dim1, dim2, i, j; + TestModulesFitTogether(module1, module2); F:=SMTX.Field(module1); - if F <> SMTX.Field(module2) then - Error("Modules are over different fields"); - fi; gens1:=SMTX.Generators(module1); gens2:=SMTX.Generators(module2); dim1:=SMTX.Dimension(module1); dim2:=SMTX.Dimension(module2); ng:=Length(gens1); - if ng <> Length(gens2) then - Error("Modules are not over the same algebra"); - fi; if Length(mat) <> dim1 or Length(mat[1]) <> dim2 then Error("matrix has wrong size for a homomorphism"); fi; @@ -3029,11 +3003,11 @@ end; ## DualGModule calculates the dual of a G-module. ## The matrices of the module are inverted and transposed. ## -InstallGlobalFunction(DualGModule,function( module) +InstallGlobalFunction(DualGModule, function(module) return SMTX.DualModule(module); end); -SMTX.DualizedBasis:=function(module,sub) +SMTX.DualizedBasis:=function(module, sub) local F,M; F:=DefaultFieldOfMatrix(sub); M:=TransposedMatMutable(sub); @@ -3049,7 +3023,7 @@ local d,u; return List(u,i->SMTX.DualizedBasis(d,i)); end; -SMTX.BasesMinimalSupermodules:=function(m,sub) +SMTX.BasesMinimalSupermodules:=function(m, sub) local a,u,i,nb; a:=SMTX.InducedAction(m,sub,2); u:=SMTX.BasesMinimalSubmodules(a[1]); @@ -3139,7 +3113,7 @@ SMTX.funcs:=[SMTX.OrthogonalVector,SMTX.SpinnedBasis,SMTX.SubQuotActions, # The special basis is used for finding invariant quadratic forms when # the characteristic of the field is 2. -SMTX.SetBasisInOrbit:=function(module,b) +SMTX.SetBasisInOrbit:=function(module, b) module.BasisInOrbit:=b; end; @@ -3150,7 +3124,7 @@ end; ## Find a basis of the irrecucible GModule module that is contained in ## an orbit of the action of G. ## The code is similar to that of SpinnedBasis. -SMTX.BasisInOrbit:=function( module ) +SMTX.BasisInOrbit:=function(module) local v, matrices, zero, ans, normedans, dim, subdim, leadpos, w, normedw, i, j, k, m, F; @@ -3207,7 +3181,7 @@ SMTX.BasisInOrbit:=function( module ) return ans; end; -SMTX.SetInvariantBilinearForm:=function(module,b) +SMTX.SetInvariantBilinearForm:=function(module, b) module.InvariantBilinearForm:=b; end; @@ -3217,7 +3191,7 @@ end; ## ## Look for an invariant bilinear form of the absolutely irreducible ## GModule module. Return fail, or the matrix of the form. -SMTX.InvariantBilinearForm:=function( module ) +SMTX.InvariantBilinearForm:=function(module) local DM, iso; if not SMTX.IsMTXModule(module) or @@ -3264,7 +3238,7 @@ SMTX.TwistedDualModule:=function(module) fi; end; -SMTX.SetInvariantSesquilinearForm:=function(module,b) +SMTX.SetInvariantSesquilinearForm:=function(module, b) module.InvariantSesquilinearForm:=b; end; @@ -3274,7 +3248,7 @@ end; ## ## Look for an invariant sesquililinear form of the absolutely irreducible ## GModule module. Return fail, or the matrix of the form. -SMTX.InvariantSesquilinearForm:=function( module ) +SMTX.InvariantSesquilinearForm:=function(module) local DM, q, r, iso, isot, l; if not SMTX.IsMTXModule(module) or @@ -3312,7 +3286,7 @@ SMTX.InvariantSesquilinearForm:=function( module ) end; -SMTX.SetInvariantQuadraticForm:=function(module,b) +SMTX.SetInvariantQuadraticForm:=function(module, b) module.InvariantQuadraticForm:=b; end; @@ -3362,7 +3336,7 @@ end; ## ## <#/GAPDoc> ## -SMTX.InvariantQuadraticForm:=function( module ) +SMTX.InvariantQuadraticForm:=function(module) local iso, bas, cgens, ciso, dim, f, z, x, i, j, qf, g, id, cqf, fix; if not SMTX.IsMTXModule(module) or @@ -3468,7 +3442,7 @@ end; ## ## <#/GAPDoc> ## -SMTX.SetOrthogonalSign:=function(module,s) +SMTX.SetOrthogonalSign:=function(module, s) module.OrthogonalSign:=s; end; diff --git a/tst/testinstall/meataxe.tst b/tst/testinstall/meataxe.tst index 1a83a11b9f..92ab0eac64 100644 --- a/tst/testinstall/meataxe.tst +++ b/tst/testinstall/meataxe.tst @@ -49,6 +49,25 @@ rec( IsOverFiniteField := true, dimension := 1, field := GF(2), generators := [ , ], isMTXModule := true ) +# +# argument compatibility checks +# +gap> M3:=GModuleByMats([[[Z(2)]]], GF(2));; +gap> M4:=GModuleByMats([[[Z(2^2)^0]]], GF(2^2));; +gap> M5:=GModuleByMats([[[Z(2^2)^0]],[[Z(2^2)^0]]], GF(2^2));; + +# +gap> TensorProductGModule(M3, M4); +Error, different fields +gap> TensorProductGModule(M4, M5); +Error, generators are different lengths + +# +gap> DirectSumGModule(M3, M4); +Error, different fields +gap> DirectSumGModule(M4, M5); +Error, generators are different lengths + # # # From 0e0e10e96e7c0efb2df9f99ebd435aab875aec70 Mon Sep 17 00:00:00 2001 From: Max Horn Date: Wed, 25 Mar 2026 01:09:03 +0100 Subject: [PATCH 119/234] Error handling: split stack frames over two lines; adjust more manual examples (#6263) Render visible stack frames with numbered prefixes on one line and an aligned location line below, and give compiled GAP frames a stacktrace-specific format. AI-assisted with Codex for implementation, tests, and documentation. Co-authored-by: Codex --- doc/ref/debug.xml | 96 ++++---- doc/ref/grpperm.xml | 6 +- doc/ref/language.xml | 19 +- doc/ref/methsel.xml | 17 +- doc/ref/mloop.xml | 108 +++++---- doc/tut/group.xml | 10 +- doc/tut/introduc.xml | 4 +- doc/tut/migrat.xml | 44 ++-- doc/tut/opers.xml | 5 +- lib/error.g | 19 +- lib/ffe.gd | 13 +- lib/grpfp.gd | 20 +- lib/integer.gd | 10 +- lib/oper1.g | 11 +- lib/smgideal.gi | 9 +- src/calls.c | 21 ++ src/code.h | 7 +- src/error.c | 57 ++++- tst/testinstall/kernel/gap.tst | 7 +- tst/testspecial/backtrace.g.out | 186 +++++++++------ tst/testspecial/backtrace2.g.out | 216 ++++++++++++------ tst/testspecial/bad-add.g.out | 3 +- tst/testspecial/bad-array-double-1.g.out | 3 +- tst/testspecial/bad-array-int-0.g.out | 3 +- tst/testspecial/bad-array-int-1.g.out | 3 +- tst/testspecial/bad-array-string.g.out | 3 +- tst/testspecial/bad-array-undef-0.g.out | 3 +- tst/testspecial/bad-array-undef-1.g.out | 3 +- tst/testspecial/bad-minus.g.out | 9 +- tst/testspecial/break-loop-loop.g.out | 3 +- tst/testspecial/broken-test.g.out | 81 ++++--- tst/testspecial/current-env.g.out | 6 +- tst/testspecial/debug-var.g.out | 84 ++++--- .../func-and-proc-call-trace.g.out | 48 ++-- tst/testspecial/line-continuation.g.out | 6 +- tst/testspecial/mem-overflow.g.out | 3 +- tst/testspecial/method-not-found-where.g.out | 6 +- tst/testspecial/method-not-found.g.out | 3 +- tst/testspecial/repl-syntax-err.g.out | 2 +- tst/testspecial/stack-depth-func.g.out | 30 ++- tst/testspecial/stack-depth-func2.g.out | 30 ++- tst/testspecial/stack-depth-rec.g.out | 30 ++- tst/testspecial/stack-trace-depth.g | 36 +++ tst/testspecial/stack-trace-depth.g.out | 76 ++++++ tst/testspecial/stack-trace-label.g.out | 3 +- tst/testspecial/syntax-tree-error.g | 2 +- tst/testspecial/syntax-tree-error.g.out | 6 +- tst/testspecial/up-down-env.g.out | 15 +- 48 files changed, 910 insertions(+), 475 deletions(-) create mode 100644 tst/testspecial/stack-trace-depth.g create mode 100644 tst/testspecial/stack-trace-depth.g.out diff --git a/doc/ref/debug.xml b/doc/ref/debug.xml index 857ee5e941..7121efabd7 100644 --- a/doc/ref/debug.xml +++ b/doc/ref/debug.xml @@ -915,41 +915,33 @@ to terminate the calculation, or enter Return; to continue it. gap> dive:= function(depth) if depth>1 then dive(depth-1); fi; return; end; function( depth ) ... end gap> dive(100); -gap> OnBreak:= function() Where(1); end; # shorter traceback -function( ) ... end +gap> OnBreak:= function() Where(2); end;; # shorter traceback gap> dive(6000); -recursion depth trap (5000) - at -dive( depth - 1 ); - called from -dive( depth - 1 ); called from -... -Entering break read-eval-print loop ... -you can 'quit;' to quit to outer loop, or -you may 'return;' to continue +Error, recursion depth trap (5000) +*[1] dive( depth - 1 ); + @ *stdin*:1 + [2] dive( depth - 1 ); + @ *stdin*:1 +... at *stdin*:4 +you may 'return;' brk> return; gap> dive(11000); -recursion depth trap (5000) - at -dive( depth - 1 ); - called from -dive( depth - 1 ); called from -... -Entering break read-eval-print loop ... -you can 'quit;' to quit to outer loop, or -you may 'return;' to continue +Error, recursion depth trap (5000) +*[1] dive( depth - 1 ); + @ *stdin*:1 + [2] dive( depth - 1 ); + @ *stdin*:1 +... at *stdin*:5 +you may 'return;' brk> return; -recursion depth trap (10000) - at -dive( depth - 1 ); - called from -dive( depth - 1 ); called from -... -Entering break read-eval-print loop ... -you can 'quit;' to quit to outer loop, or -you may 'return;' to continue -brk> return; -gap> +Error, recursion depth trap (10000) +*[1] dive( depth - 1 ); + @ *stdin*:1 + [2] dive( depth - 1 ); + @ *stdin*:1 +... at *stdin*:5 +you may 'return;' +brk> return;gap> ]]>

@@ -979,39 +971,29 @@ gap> dive := function(depth) > fi; > end;; gap> SetRecursionTrapInterval(1000); +gap> OnBreak:= function() Where(2); end;; # shorter traceback gap> dive(100); Depth 100 gap> dive(2500); -recursion depth trap (1000) - at -dive( depth - 1 ); - called from -dive( depth - 1 ); called from -... -Entering break read-eval-print loop ... -you can 'quit;' to quit to outer loop, or -you may 'return;' to continue +Error, recursion depth trap (1000) +*[1] dive( depth - 1 ); + @ *stdin*:4 + [2] dive( depth - 1 ); + @ *stdin*:4 +... at *stdin*:12 +you may 'return;' brk> return; -recursion depth trap (2000) - at -dive( depth - 1 ); - called from -dive( depth - 1 ); called from -... -Entering break read-eval-print loop ... -you can 'quit;' to quit to outer loop, or -you may 'return;' to continue +Error, recursion depth trap (2000) +*[1] dive( depth - 1 ); + @ *stdin*:4 + [2] dive( depth - 1 ); + @ *stdin*:4 +... at *stdin*:12 +you may 'return;' brk> GetRecursionDepth(); 0 brk> return; -gap> SetRecursionTrapInterval(-1); -Error, SetRecursionTrapInterval: must be a small integer greater than 5 (n\ -ot the integer -1) -not in any function -Entering break read-eval-print loop ... -you can 'quit;' to quit to outer loop, or -you can replace via 'return ;' to continue -brk> return 0; +gap> SetRecursionTrapInterval(2^50); gap> dive(20000); Depth 20000 gap> dive(2000000); diff --git a/doc/ref/grpperm.xml b/doc/ref/grpperm.xml index bf651a6487..7bc558efbd 100644 --- a/doc/ref/grpperm.xml +++ b/doc/ref/grpperm.xml @@ -652,11 +652,7 @@ gap> h:=Group(permutationlist); gap> StabChainOptions(h).random:=1;; gap> Size(h); -exceeded the permitted memory (`-o' command line option) at -mlimit := 1; called from -SCRMakeStabStrong( S.stabilizer, [ g ], param, orbits, where, basesize, - base, correct, missing, false ); called from - SCRMakeStabStrong( S.stabilizer, [ g ], param, orbits, where, basesize, +exceeded the permitted memory (`-o' command line option) ... ]]>

diff --git a/doc/ref/language.xml b/doc/ref/language.xml index 78b2d1faf4..cab355969b 100644 --- a/doc/ref/language.xml +++ b/doc/ref/language.xml @@ -1556,24 +1556,19 @@ If the expression expr is a function call then this function must return a value. If the function does not return a value an error is signalled and you enter a break loop (see ). As usual you can leave the break loop with quit;. -If you enter return return-expr; the value of the expression -return-expr is assigned to the variable, -and execution continues after the assignment.

f1:= function( x ) Print( "value: ", x, "\n" ); end;; gap> f2:= function( x ) return f1( x ); end;; gap> f2( 4 ); value: 4 -Function Calls: must return a value at -return f1( x ); - called from -( ) called from read-eval-loop -Entering break read-eval-print loop ... -you can 'quit;' to quit to outer loop, or -you can supply one by 'return ;' to continue -brk> return "hello"; -"hello" +Error, Function Calls: must return a value +*[1] f1( x ) + @ *stdin*:2 +( ) + called from read-eval loop at *stdin*:3 +type 'quit;' to quit to outer loop +brk> ]]>

In the above example, the function f2 calls f1 with argument diff --git a/doc/ref/methsel.xml b/doc/ref/methsel.xml index 2083632a97..1ce2674710 100644 --- a/doc/ref/methsel.xml +++ b/doc/ref/methsel.xml @@ -125,19 +125,15 @@ objecty, a "No Method Found" error will be returned. XCons(IsFullTransformationMonoid,4); Error, no method found! For debugging hints type ?Recovery from NoMethodFound -Error, no 1st choice method found for `XCons' on 2 arguments called from -( ) - called from read-eval loop at line 8 of *stdin* -you can 'quit;' to quit to outer loop, or -you can 'return;' to continue +Error, no 1st choice method found for `XCons' on 2 arguments +called from read-eval loop at *stdin*:8 +type 'quit;' to quit to outer loop brk> quit; gap> XCons(IsNilpotentGroup,4); Error, no method found! For debugging hints type ?Recovery from NoMethodFound -Error, no 1st choice method found for `XCons' on 2 arguments called from -( ) - called from read-eval loop at line 9 of *stdin* -you can 'quit;' to quit to outer loop, or -you can 'return;' to continue +Error, no 1st choice method found for `XCons' on 2 arguments +called from read-eval loop at *stdin*:8 +type 'quit;' to quit to outer loop brk> ]]> @@ -435,4 +431,3 @@ the mathematical term centre. - diff --git a/doc/ref/mloop.xml b/doc/ref/mloop.xml index a0f844dd4d..ca1a723482 100644 --- a/doc/ref/mloop.xml +++ b/doc/ref/mloop.xml @@ -476,11 +476,9 @@ indicate that you are in a break loop.

1/0; -Rational operations: must not be zero -not in any function -Entering break read-eval-print loop ... -you can 'quit;' to quit to outer loop, or -you can replace via 'return ;' to continue +Error, Rational operations: must not be zero +not in any function at *stdin*:2 +type 'quit;' to quit to outer loop ]]>

If errors occur within a break loop &GAP; enters another break loop at a @@ -488,12 +486,10 @@ If errors occur within a break loop &GAP; enters another break loop at a

1/0; -Rational operations: must not be zero -not in any function -Entering break read-eval-print loop ... -you can 'quit;' to quit to outer loop, or -you can replace via 'return ;' to continue -brk_02> +Error, Rational operations: must not be zero +not in any function at *stdin*:2 +type 'quit;' to quit to outer loop +brk_2> ]]>

There are two ways to leave a break loop, @@ -511,7 +507,7 @@ Note that &GAP; code between quit; and the end of the input line is ignored.

quit; +brk_2> quit; brk> ]]>

@@ -750,25 +746,30 @@ same as while also showing the arguments and local variables of each function.

StabChain(SymmetricGroup(100)); # After this we typed ^C -user interrupt at -bpt := S.orbit[1]; - called from -SiftedPermutation( S, (g * rep) ^ -1 ) called from -StabChainStrong( S.stabilizer, [ sch ], options ); called from -StabChainStrong( S.stabilizer, [ sch ], options ); called from -StabChainStrong( S, GeneratorsOfGroup( G ), options ); called from -StabChainOp( G, rec( - ) ) called from -... -Entering break read-eval-print loop ... -you can 'quit;' to quit to outer loop, or -you can 'return;' to continue +gap> StabChain(SymmetricGroup(1000)); # After this we typed ^C +Error, user interrupt +*[1] genlabels := Filtered( genlabels, function ( x ) + return pnt ^ sgs[x] = pnt; + end ); + @ GAPROOT/lib/stbc.gi:426 + [2] StabChainBaseStrongGenerators( dom{[ 1 .. Length( dom ) - 1 ]}, sgs, () ) + @ GAPROOT/lib/gpprmsya.gi:2006 + [3] StabChainOp( G, rec( + ) ) + @ GAPROOT/lib/stbc.gi:28 + [4] StabChainImmutable( arg[1] ) + @ GAPROOT/lib/stbc.gi:18 +( ) + called from read-eval loop at *stdin*:2 +you can 'return;' brk> Where(2); - called from -SiftedPermutation( S, (g * rep) ^ -1 ) called from -StabChainStrong( S.stabilizer, [ sch ], options ); called from -... +*[1] genlabels := Filtered( genlabels, function ( x ) + return pnt ^ sgs[x] = pnt; + end ); + @ GAPROOT/lib/stbc.gi:426 + [2] StabChainBaseStrongGenerators( dom{[ 1 .. Length( dom ) - 1 ]}, sgs, () ) + @ GAPROOT/lib/gpprmsya.gi:2006 +... at *errin*:1 ]]>

Note that the variables displayed even in the first line of the @@ -836,10 +837,14 @@ Error, ! you can 'quit;' to quit to outer loop, or you can 'return;' to continue brk> Where(); -*[1] Error( "!\n" ); at *stdin*:3 called from - [2] test( n + 1 ); at *stdin*:3 called from - [3] test( n + 1 ); at *stdin*:3 called from - [4] test( n + 1 ); at *stdin*:3 called from +*[1] Error( "!\n" ); + @ *stdin*:4 + [2] test( n + 1 ); + @ *stdin*:4 + [3] test( n + 1 ); + @ *stdin*:4 + [4] test( n + 1 ); + @ *stdin*:4 ( ) called from read-eval loop at *errin*:1 brk> n; @@ -848,20 +853,28 @@ brk> DownEnv(); brk> n; 3 brk> Where(); - [1] Error( "!\n" ); at *stdin*:3 called from -*[2] test( n + 1 ); at *stdin*:3 called from - [3] test( n + 1 ); at *stdin*:3 called from - [4] test( n + 1 ); at *stdin*:3 called from + [1] Error( "!\n" ); + @ *stdin*:4 +*[2] test( n + 1 ); + @ *stdin*:4 + [3] test( n + 1 ); + @ *stdin*:4 + [4] test( n + 1 ); + @ *stdin*:4 ( ) called from read-eval loop at *errin*:5 brk> DownEnv( 2 ); brk> n; 1 brk> Where(); - [1] Error( "!\n" ); at *stdin*:3 called from - [2] test( n + 1 ); at *stdin*:3 called from - [3] test( n + 1 ); at *stdin*:3 called from -*[4] test( n + 1 ); at *stdin*:3 called from + [1] Error( "!\n" ); + @ *stdin*:4 + [2] test( n + 1 ); + @ *stdin*:4 + [3] test( n + 1 ); + @ *stdin*:4 +*[4] test( n + 1 ); + @ *stdin*:4 ( ) called from read-eval loop at *errin*:8 brk> DownEnv( -2 ); @@ -894,10 +907,13 @@ gap> fun := function() local x; x := 3; bar(); end; function( ) ... end gap> fun(); Error, !! - called from -bar( ); called from -( ) called from read-eval-loop -Entering break read-eval-print loop ... +Stack trace: +*[1] Error( "!!\n" ); + @ *stdin*:4 + [2] bar( ); + @ *stdin*:7 +( ) + called from read-eval loop at *stdin*:8 you can 'quit;' to quit to outer loop, or you can 'return;' to continue brk> x; diff --git a/doc/tut/group.xml b/doc/tut/group.xml index 30061d16fe..739fa0fd5c 100644 --- a/doc/tut/group.xml +++ b/doc/tut/group.xml @@ -926,11 +926,12 @@ gap> Size( Image( hom, DerivedSubgroup(s4) ) );

PreImage( hom, (1,2,3) ); -Error, must be an inj. and surj. mapping called from +Error, must be an injective and surjective mapping +*[1] ErrorNoReturn( " must be an injective and surjective ", "mapping" ); + @ GAPROOT/lib/mapping.gi:262 ( ) - called from read-eval loop at line 4 of *stdin* -you can 'quit;' to quit to outer loop, or -you can 'return;' to continue + called from read-eval loop at *stdin*:7 +type 'quit;' to quit to outer loop brk> quit; ]]>

@@ -1259,4 +1260,3 @@ Chapter . - diff --git a/doc/tut/introduc.xml b/doc/tut/introduc.xml index 212491772e..5b30a56b8a 100644 --- a/doc/tut/introduc.xml +++ b/doc/tut/introduc.xml @@ -253,8 +253,8 @@ We will no longer mention the Return key from now on. break loops Sometimes a syntax error will cause &GAP; to enter a break loop. This is indicated by the special prompt brk>. If another syntax error occurs -while &GAP; is in a break loop, the prompt will change to brk_02>, -brk_03> and so on. You can leave the current break loop and exit to the +while &GAP; is in a break loop, the prompt will change to brk_2>, +brk_3> and so on. You can leave the current break loop and exit to the next outer one by either typing quit; or by hitting Ctrl-D. Eventually &GAP; will return to its normal state and show its normal prompt gap> again. diff --git a/doc/tut/migrat.xml b/doc/tut/migrat.xml index e99e9bee47..bf73228ae0 100644 --- a/doc/tut/migrat.xml +++ b/doc/tut/migrat.xml @@ -857,31 +857,50 @@ gap> test:= function( n ) > if n > 3 then Error( "!\n" ); fi; test( n+1 ); end;; gap> test( 1 ); Error, ! -Entering break read-eval-print loop ... +at *stdin*:6 you can 'quit;' to quit to outer loop, or you can 'return;' to continue brk> Where(); - called from -test( n + 1 ); called from -test( n + 1 ); called from -test( n + 1 ); called from -( ) called from read-eval-loop +*[1] Error( "!\n" ); + @ *stdin*:4 + [2] test( n + 1 ); + @ *stdin*:4 + [3] test( n + 1 ); + @ *stdin*:4 + [4] test( n + 1 ); + @ *stdin*:4 +( ) + called from read-eval loop at *errin*:1 brk> n; 4 brk> DownEnv(); brk> n; 3 brk> Where(); - called from -test( n + 1 ); called from -test( n + 1 ); called from -( ) called from read-eval-loop + [1] Error( "!\n" ); + @ *stdin*:4 +*[2] test( n + 1 ); + @ *stdin*:4 + [3] test( n + 1 ); + @ *stdin*:4 + [4] test( n + 1 ); + @ *stdin*:4 +( ) + called from read-eval loop at *errin*:5 brk> DownEnv( 2 ); brk> n; 1 brk> Where(); - called from -( ) called from read-eval-loop + [1] Error( "!\n" ); + @ *stdin*:4 + [2] test( n + 1 ); + @ *stdin*:4 + [3] test( n + 1 ); + @ *stdin*:4 +*[4] test( n + 1 ); + @ *stdin*:4 +( ) + called from read-eval loop at *errin*:8 brk> DownEnv( -2 ); brk> n; 3 @@ -1205,4 +1224,3 @@ found in the file tst/compat3.tst of the &GAP; 4 distribution. - diff --git a/doc/tut/opers.xml b/doc/tut/opers.xml index 7d1c6ee918..6413348e73 100644 --- a/doc/tut/opers.xml +++ b/doc/tut/opers.xml @@ -216,8 +216,9 @@ If no applicable method (or no next applicable method) is found, &GAP; stops with an error message of the form

You would get an error message as above if you asked for Size( 1 ). diff --git a/lib/error.g b/lib/error.g index fbaceed8a3..fe1040a6ac 100644 --- a/lib/error.g +++ b/lib/error.g @@ -134,7 +134,7 @@ BIND_GLOBAL("PRETTY_PRINT_VARS", function(context) end); BIND_GLOBAL("WHERE", function(depth, context, activecontext, showlocals) - local bottom, lastcontext, f, level; + local bottom, lastcontext, f, level, totaldepth, countcontext; if depth <= 0 then return; fi; @@ -144,14 +144,25 @@ BIND_GLOBAL("WHERE", function(depth, context, activecontext, showlocals) return; fi; lastcontext := context; + totaldepth := 0; + countcontext := context; + while totaldepth < depth and countcontext <> bottom do + totaldepth := totaldepth + 1; + countcontext := ParentLVars(countcontext); + od; level := 1; while depth > 0 and context <> bottom do - PRINT_CURRENT_STATEMENT(ERROR_OUTPUT, context, activecontext, level); + PRINT_CURRENT_STATEMENT( + ERROR_OUTPUT, + context, + activecontext, + level, + totaldepth); if showlocals then PRETTY_PRINT_VARS(context); + else + PrintTo(ERROR_OUTPUT, "\n"); fi; - - PrintTo(ERROR_OUTPUT, " called from\n"); lastcontext := context; context := ParentLVars(context); depth := depth-1; diff --git a/lib/ffe.gd b/lib/ffe.gd index c784120634..3eeddef057 100644 --- a/lib/ffe.gd +++ b/lib/ffe.gd @@ -119,10 +119,15 @@ ## Z(11,40); ## Error, Conway Polynomial 11^40 will need to computed and might be slow -## return to continue called from -## FFECONWAY.ZNC( p, d ) called from -## ( ) called from read-eval-loop -## Entering break read-eval-print loop ... +## return to continue +## *[1] Error( "Conway Polynomial ", p, "^", d, " will need to computed and might be slow\n", "return to continue" ); +## @ GAPROOT/lib/ffeconway.gi:81 +## [2] FFECONWAY.SetUpConwayStuff( p, d ); +## @ GAPROOT/lib/ffeconway.gi:140 +## [3] FFECONWAY.ZNC( p, d ) +## @ GAPROOT/lib/ffeconway.gi:167 +## ( ) +## called from read-eval loop at *stdin*:2 ## you can 'quit;' to quit to outer loop, or ## you can 'return;' to continue ## brk> diff --git a/lib/grpfp.gd b/lib/grpfp.gd index 81552fde8d..eaa41d6421 100644 --- a/lib/grpfp.gd +++ b/lib/grpfp.gd @@ -78,14 +78,18 @@ fi; ## Group([ b ]) ## gap> Index( f, u ); ## Error, the coset enumeration has defined more than 4096000 cosets -## called from -## TCENUM.CosetTableFromGensAndRels( fgens, grels, fsgens ) called from -## CosetTableFromGensAndRels( fgens, grels, fsgens ) called from -## TryCosetTableInWholeGroup( H ) called from -## CosetTableInWholeGroup( H ) called from -## IndexInWholeGroup( H ) called from -## ... -## Entering break read-eval-print loop ... +## Stack trace: +## *[1] Error( "the coset enumeration has defined more ", "than ", limit, " cosets\n" ); +## @ GAPROOT/lib/grpfp.gi:1230 +## [2] TCENUM.CosetTableFromGensAndRels( fgens, grels, fsgens ) +## @ GAPROOT/lib/grpfp.gi:1068 +## [3] CosetTableFromGensAndRels( fgens, grels, fsgens ) +## @ GAPROOT/lib/grpfp.gi:1346 +## [4] TryCosetTableInWholeGroup( H ) +## @ GAPROOT/lib/grpfp.gi:1359 +## [5] CosetTableInWholeGroup( H ) +## @ GAPROOT/lib/grpfp.gi:1733 +## ... at *stdin*:3 ## type 'return;' if you want to continue with a new limit of 8192000 cosets, ## type 'quit;' if you want to quit the coset enumeration, ## type 'maxlimit := 0; return;' in order to continue without a limit diff --git a/lib/integer.gd b/lib/integer.gd index 558a0b90e6..20ca4e07ed 100644 --- a/lib/integer.gd +++ b/lib/integer.gd @@ -248,12 +248,14 @@ DeclareGlobalFunction( "BestQuoInt" ); ## ]]> ## ChineseRem( [ 6, 10, 14 ], [ 1, 2, 3 ] ); -## Error, the residues must be equal modulo 2 called from -## ( ) called from read-eval-loop -## Entering break read-eval-print loop ... +## Error, the residues must be equal modulo 2 +## *[1] Error( "the residues must be equal modulo ", g.gcd ); +## @ GAPROOT/lib/integer.gi:391 +## ( ) +## called from read-eval loop at *stdin*:2 ## you can 'quit;' to quit to outer loop, or ## you can 'return;' to continue -## brk> gap> +## brk> ## ]]> ## ## diff --git a/lib/oper1.g b/lib/oper1.g index faadb4af32..2c25bf1cff 100644 --- a/lib/oper1.g +++ b/lib/oper1.g @@ -928,10 +928,13 @@ end); ##

## SylowSubgroup( s4, 6 ); -## Error, SylowSubgroup:

must be a prime called from -## called from -## ( ) called from read-eval-loop -## Entering break read-eval-print loop ... +## Error, SylowSubgroup:

must be a prime +## *[1] <> +## @ GAPROOT/lib/oper1.g:964 +## [2] <> +## @ GAPROOT/lib/oper1.g:1007 +## ( ) +## called from read-eval loop at *stdin*:3 ## you can 'quit;' to quit to outer loop, or ## you can 'return;' to continue ## brk> quit; diff --git a/lib/smgideal.gi b/lib/smgideal.gi index 3ba57c809f..0069431be9 100644 --- a/lib/smgideal.gi +++ b/lib/smgideal.gi @@ -281,14 +281,7 @@ BindGlobal( "IsBound_SemigroupIdealEnumerator", function( enum, n ) ## s := f/r; ## Size(s); ## -## recursion depth trap (5000) -## at -## return Size( UnderlyingCollection( enum ) ); -## Length( Enumerator( C ) ) called from -## Size( UnderlyingCollection( enum ) ) called from -## Length( Enumerator( C ) ) called from -## Size( UnderlyingCollection( enum ) ) called from -## Length( Enumerator( C ) ) called from +## would otherwise end up in an infinite recursion. ## ############################################################################# diff --git a/src/calls.c b/src/calls.c index 6440cbe3a5..5eb7db9a88 100644 --- a/src/calls.c +++ b/src/calls.c @@ -1081,11 +1081,20 @@ void PrintKernelFunction(Obj func) Obj body = BODY_FUNC(func); Obj filename = body ? GET_FILENAME_BODY(body) : 0; if (filename) { + // A "location" is a string attached exclusively to GAP kernel + // functions; it is derived from the function's "cookie" which has the + // form "FILENAME:FUNCNAME" where `FUNCNAME` is the name of the + // underlying C function. Or at least more or less: in the GAP kernel, + // generally the *real* C function name will be `FuncFUNCNAME`. This + // may be rectified in the future. if ( GET_LOCATION_BODY(body) ) { Pr("<> from %g:%g", (Int)filename, (Int)GET_LOCATION_BODY(body)); } + // When compiling GAP code into C code, the gap compiler ("gac") attaches + // the filename and line number of the GAP code from which the C code was + // produced; that's the case we are running into here. else if ( GET_STARTLINE_BODY(body) ) { Pr("<> from %g:%d", (Int)filename, @@ -1093,6 +1102,18 @@ void PrintKernelFunction(Obj func) } } else { + // Some kernel code produces custom kernel functions (via direct calls + // to NewFunction or one of its relatives), and quite commonly does not + // bother setting a filename, location, or startline. In many cases + // this may be irrelevant as the user cannot see the result; e.g. for + // filters we have custom print/view methods, etc. But one rare exception + // are the bitfield helper: + // gap> Display(MakeBitfields(1).getters[1]); + // function ( data ) + // <> + // end + // TODO: add proper location info there, too, and audit all other uses + // of NewFunction* for this problem Pr("<>", 0, 0); } } diff --git a/src/code.h b/src/code.h index a66c7f40a6..110c673982 100644 --- a/src/code.h +++ b/src/code.h @@ -102,7 +102,8 @@ typedef struct { // if non-zero, this is either an immediate integer encoding the // line number where a function starts, or string describing the // location of a function. Typically this will be the name of a C - // function implementing it. + // function implementing it. See also `SetupFuncInfo` which derives + // it from the "cookie" associated to functions. Obj startline_or_location; // if non-zero, this is an immediate integer encoding the line @@ -127,9 +128,13 @@ void SET_FILENAME_BODY(Obj body, Obj val); UInt GET_GAPNAMEID_BODY(Obj body); void SET_GAPNAMEID_BODY(Obj body, UInt val); +// see documentation of `startline_or_location` for more information about the +// "location" of a body Obj GET_LOCATION_BODY(Obj body); void SET_LOCATION_BODY(Obj body, Obj val); +// see documentation of `startline_or_location` for more information about the +// "startline" of a body UInt GET_STARTLINE_BODY(Obj body); void SET_STARTLINE_BODY(Obj body, UInt val); UInt GET_ENDLINE_BODY(Obj body); diff --git a/src/error.c b/src/error.c index 32ac420a34..2618e32739 100644 --- a/src/error.c +++ b/src/error.c @@ -185,7 +185,8 @@ static Obj FuncCURRENT_STATEMENT_LOCATION(Obj self, Obj context) } static Obj FuncPRINT_CURRENT_STATEMENT(Obj self, Obj stream, Obj context, - Obj activeContext, Obj level) + Obj activeContext, Obj level, + Obj totalDepth) { if (IsBottomLVars(context)) return 0; @@ -207,18 +208,49 @@ static Obj FuncPRINT_CURRENT_STATEMENT(Obj self, Obj stream, Obj context, BOOL rethrow = FALSE; GAP_TRY { + UInt levelInt = INT_INTOBJ(level); + UInt totalDepthInt = INT_INTOBJ(totalDepth); + UInt prefixWidth = 0; + UInt levelWidth = 0; + UInt i; + + char prefix[32]; Obj func = FUNC_LVARS(context); + Obj funcname = NAME_FUNC(func); + Int line = -1; GAP_ASSERT(func); Stat call = STAT_LVARS(context); Obj body = BODY_FUNC(func); Obj filename = GET_FILENAME_BODY(body); + + while (totalDepthInt > 0) { + prefixWidth++; + totalDepthInt /= 10; + } + if (activeContext != Fail) { - Pr(context == activeContext ? "*[%d] " : " [%d] ", - INT_INTOBJ(level), 0); + i = levelInt; + while (i > 0) { + levelWidth++; + i /= 10; + } + snprintf(prefix, sizeof(prefix), "%c%*s[%lu] ", + context == activeContext ? '*' : ' ', + (int)(prefixWidth - levelWidth), "", + (unsigned long)levelInt); + Pr("%s", (Int)prefix, 0); } - if (IsKernelFunction(func)) { + if (IsKernelFunction(func) && filename && GET_STARTLINE_BODY(body)) { + if (funcname) { + Pr("<>", (Int)funcname, 0); + } + else { + Pr("<>", 0, 0); + } + line = GET_STARTLINE_BODY(body); + } + else if (IsKernelFunction(func)) { PrintKernelFunction(func); - Obj funcname = NAME_FUNC(func); if (funcname) { Pr(" in function %g", (Int)funcname, 0); } @@ -233,14 +265,21 @@ static Obj FuncPRINT_CURRENT_STATEMENT(Obj self, Obj stream, Obj context, Int type = TNUM_STAT(call); if (FIRST_STAT_TNUM <= type && type <= LAST_STAT_TNUM) { PrintStat(call); - Pr(" at %g:%d", (Int)filename, LINE_STAT(call)); + line = LINE_STAT(call); } else if (FIRST_EXPR_TNUM <= type && type <= LAST_EXPR_TNUM) { PrintExpr(call); - Pr(" at %g:%d", (Int)filename, LINE_STAT(call)); + line = LINE_STAT(call); } SWITCH_TO_OLD_LVARS(currLVars); } + if (line > 0) { + Pr("\n", 0, 0); + for (i = 0; i < prefixWidth + 2; i++) { + Pr(" ", 0, 0); + } + Pr("@ %g:%d", (Int)filename, line); + } } GAP_CATCH { @@ -644,8 +683,8 @@ static StructGVarFunc GVarFuncs[] = { GVAR_FUNC_2ARGS(CALL_WITH_CATCH, func, args), GVAR_FUNC_1ARGS(JUMP_TO_CATCH, payload), - GVAR_FUNC_4ARGS(PRINT_CURRENT_STATEMENT, stream, context, activeContext, - level), + GVAR_FUNC_5ARGS(PRINT_CURRENT_STATEMENT, stream, context, activeContext, + level, totalDepth), GVAR_FUNC_1ARGS(CURRENT_STATEMENT_LOCATION, context), GVAR_FUNC_1ARGS(SetUserHasQuit, value), diff --git a/tst/testinstall/kernel/gap.tst b/tst/testinstall/kernel/gap.tst index 3b025a9ac0..493afea431 100644 --- a/tst/testinstall/kernel/gap.tst +++ b/tst/testinstall/kernel/gap.tst @@ -111,9 +111,10 @@ fail # gap> CURRENT_STATEMENT_LOCATION(GetCurrentLVars()); fail -gap> PRINT_CURRENT_STATEMENT("*errout*", GetCurrentLVars(), fail, 1); -gap> f:=function() local l; l:=GetCurrentLVars(); PRINT_CURRENT_STATEMENT("*errout*", l, fail, 1); Print("\n"); end;; f(); -PRINT_CURRENT_STATEMENT( "*errout*", l, fail, 1 ); at stream:1 +gap> PRINT_CURRENT_STATEMENT("*errout*", GetCurrentLVars(), fail, 1, 1); +gap> f:=function() local l; l:=GetCurrentLVars(); PRINT_CURRENT_STATEMENT("*errout*", l, fail, 1, 1); Print("\n"); end;; f(); +PRINT_CURRENT_STATEMENT( "*errout*", l, fail, 1, 1 ); + @ stream:1 # gap> CALL_WITH_CATCH(fail,fail); diff --git a/tst/testspecial/backtrace.g.out b/tst/testspecial/backtrace.g.out index 976b2ee066..f2130d7a95 100644 --- a/tst/testspecial/backtrace.g.out +++ b/tst/testspecial/backtrace.g.out @@ -14,20 +14,22 @@ gap> f(); Error, no method found! For debugging hints type ?Recovery from NoMethodFound Error, no 1st choice method found for `[]:=' on 3 arguments Stack trace: -*[1] l[[ 1 .. 3 ]] := 1; at *stdin*:11 called from +*[1] l[[ 1 .. 3 ]] := 1; + @ *stdin*:11 ( ) called from read-eval loop at *stdin*:13 type 'quit;' to quit to outer loop brk> Where(); -*[1] l[[ 1 .. 3 ]] := 1; at *stdin*:11 called from +*[1] l[[ 1 .. 3 ]] := 1; + @ *stdin*:11 ( ) called from read-eval loop at *errin*:1 brk> WhereWithVars(); -*[1] l[[ 1 .. 3 ]] := 1; at *stdin*:11 +*[1] l[[ 1 .. 3 ]] := 1; + @ *stdin*:11 arguments: local variables: l := [ 0, 0, 0, 0, 0, 0 ] - called from ( ) called from read-eval loop at *errin*:2 brk> quit; @@ -37,19 +39,21 @@ gap> f:=function() if true = 1/0 then return 1; fi; return 2; end;; gap> f(); Error, Rational operations: must not be zero Stack trace: -*[1] 1 / 0 at *stdin*:15 called from +*[1] 1 / 0 + @ *stdin*:15 ( ) called from read-eval loop at *stdin*:16 type 'quit;' to quit to outer loop brk> Where(); -*[1] 1 / 0 at *stdin*:15 called from +*[1] 1 / 0 + @ *stdin*:15 ( ) called from read-eval loop at *errin*:1 brk> WhereWithVars(); -*[1] 1 / 0 at *stdin*:15 +*[1] 1 / 0 + @ *stdin*:15 arguments: local variables: - called from ( ) called from read-eval loop at *errin*:2 brk> quit; @@ -61,24 +65,26 @@ Error, Variable: 'x' must have an assigned value Stack trace: *[1] if x then return 1; -fi; at *stdin*:18 called from +fi; + @ *stdin*:18 ( ) called from read-eval loop at *stdin*:19 type 'quit;' to quit to outer loop brk> Where(); *[1] if x then return 1; -fi; at *stdin*:18 called from +fi; + @ *stdin*:18 ( ) called from read-eval loop at *errin*:1 brk> WhereWithVars(); *[1] if x then return 1; -fi; at *stdin*:18 +fi; + @ *stdin*:18 arguments: local variables: x := - called from ( ) called from read-eval loop at *errin*:2 brk> quit; @@ -90,23 +96,25 @@ Error, must be 'true' or 'false' (not the integer 1) Stack trace: *[1] if 1 then return 1; -fi; at *stdin*:21 called from +fi; + @ *stdin*:21 ( ) called from read-eval loop at *stdin*:22 type 'quit;' to quit to outer loop brk> Where(); *[1] if 1 then return 1; -fi; at *stdin*:21 called from +fi; + @ *stdin*:21 ( ) called from read-eval loop at *errin*:1 brk> WhereWithVars(); *[1] if 1 then return 1; -fi; at *stdin*:21 +fi; + @ *stdin*:21 arguments: local variables: - called from ( ) called from read-eval loop at *errin*:2 brk> quit; @@ -120,7 +128,8 @@ Stack trace: return 1; elif 1 then return 2; -fi; at *stdin*:24 called from +fi; + @ *stdin*:24 ( ) called from read-eval loop at *stdin*:25 type 'quit;' to quit to outer loop @@ -129,7 +138,8 @@ brk> Where(); return 1; elif 1 then return 2; -fi; at *stdin*:24 called from +fi; + @ *stdin*:24 ( ) called from read-eval loop at *errin*:1 brk> WhereWithVars(); @@ -137,10 +147,10 @@ brk> WhereWithVars(); return 1; elif 1 then return 2; -fi; at *stdin*:24 +fi; + @ *stdin*:24 arguments: local variables: - called from ( ) called from read-eval loop at *errin*:2 brk> quit; @@ -152,23 +162,25 @@ Error, must be 'true' or 'false' (not the integer 1) Stack trace: *[1] while 1 do return 1; -od; at *stdin*:27 called from +od; + @ *stdin*:27 ( ) called from read-eval loop at *stdin*:28 type 'quit;' to quit to outer loop brk> Where(); *[1] while 1 do return 1; -od; at *stdin*:27 called from +od; + @ *stdin*:27 ( ) called from read-eval loop at *errin*:1 brk> WhereWithVars(); *[1] while 1 do return 1; -od; at *stdin*:27 +od; + @ *stdin*:27 arguments: local variables: - called from ( ) called from read-eval loop at *errin*:2 brk> quit; @@ -178,34 +190,38 @@ gap> f:=function() local i; for i in 1 do return 1; od; return 2; end;; gap> f(); Error, You cannot loop over the integer 1 did you mean the range [1..1] Stack trace: -*[1] Error( "You cannot loop over the integer ", n, " did you mean the range [1..", n, "]" ); at GAPROOT/lib/integer.gi:LINE called from +*[1] Error( "You cannot loop over the integer ", n, " did you mean the range [1..", n, "]" ); + @ GAPROOT/lib/integer.gi:LINE [2] for i in 1 do return 1; -od; at *stdin*:30 called from +od; + @ *stdin*:30 ( ) called from read-eval loop at *stdin*:31 you can 'quit;' to quit to outer loop, or you can 'return;' to continue brk> Where(); -*[1] Error( "You cannot loop over the integer ", n, " did you mean the range [1..", n, "]" ); at GAPROOT/lib/integer.gi:LINE called from +*[1] Error( "You cannot loop over the integer ", n, " did you mean the range [1..", n, "]" ); + @ GAPROOT/lib/integer.gi:LINE [2] for i in 1 do return 1; -od; at *stdin*:30 called from +od; + @ *stdin*:30 ( ) called from read-eval loop at *errin*:1 brk> WhereWithVars(); -*[1] Error( "You cannot loop over the integer ", n, " did you mean the range [1..", n, "]" ); at GAPROOT/lib/integer.gi:LINE +*[1] Error( "You cannot loop over the integer ", n, " did you mean the range [1..", n, "]" ); + @ GAPROOT/lib/integer.gi:LINE arguments: n := 1 local variables: - called from [2] for i in 1 do return 1; -od; at *stdin*:30 +od; + @ *stdin*:30 arguments: local variables: i := - called from ( ) called from read-eval loop at *errin*:2 brk> quit; @@ -218,24 +234,26 @@ Error, no 1st choice method found for `Iterator' on 1 arguments Stack trace: *[1] for i in true do return 1; -od; at *stdin*:33 called from +od; + @ *stdin*:33 ( ) called from read-eval loop at *stdin*:34 type 'quit;' to quit to outer loop brk> Where(); *[1] for i in true do return 1; -od; at *stdin*:33 called from +od; + @ *stdin*:33 ( ) called from read-eval loop at *errin*:1 brk> WhereWithVars(); *[1] for i in true do return 1; -od; at *stdin*:33 +od; + @ *stdin*:33 arguments: local variables: i := - called from ( ) called from read-eval loop at *errin*:2 brk> quit; @@ -247,26 +265,28 @@ Error, no 1st choice method found for `Iterator' on 1 arguments Stack trace: *[1] for i in true do return 1; -od; at *stdin*:35 called from +od; + @ *stdin*:35 ( ) called from read-eval loop at *stdin*:36 type 'quit;' to quit to outer loop brk> Where(); *[1] for i in true do return 1; -od; at *stdin*:35 called from +od; + @ *stdin*:35 ( ) called from read-eval loop at *errin*:1 brk> WhereWithVars(); *[1] for i in true do return 1; -od; at *stdin*:35 +od; + @ *stdin*:35 arguments: x := [ 1, 2, 3 ] local variables: i := j := - called from ( ) called from read-eval loop at *errin*:2 brk> quit; @@ -278,26 +298,28 @@ Error, no 1st choice method found for `Iterator' on 1 arguments Stack trace: *[1] for i in true do return 1; -od; at *stdin*:37 called from +od; + @ *stdin*:37 ( ) called from read-eval loop at *stdin*:38 type 'quit;' to quit to outer loop brk> Where(); *[1] for i in true do return 1; -od; at *stdin*:37 called from +od; + @ *stdin*:37 ( ) called from read-eval loop at *errin*:1 brk> WhereWithVars(); *[1] for i in true do return 1; -od; at *stdin*:37 +od; + @ *stdin*:37 arguments: x := local variables: i := j := - called from ( ) called from read-eval loop at *errin*:2 brk> quit; @@ -309,26 +331,28 @@ Error, no 1st choice method found for `Iterator' on 1 arguments Stack trace: *[1] for i in true do return 1; -od; at *stdin*:39 called from +od; + @ *stdin*:39 ( ) called from read-eval loop at *stdin*:40 type 'quit;' to quit to outer loop brk> Where(); *[1] for i in true do return 1; -od; at *stdin*:39 called from +od; + @ *stdin*:39 ( ) called from read-eval loop at *errin*:1 brk> WhereWithVars(); *[1] for i in true do return 1; -od; at *stdin*:39 +od; + @ *stdin*:39 arguments: x := local variables: i := j := 4 - called from ( ) called from read-eval loop at *errin*:2 brk> quit; @@ -339,24 +363,26 @@ Error, must be 'true' or 'false' (not the integer 1) Stack trace: *[1] repeat x := 1; -until 1; at *stdin*:41 called from +until 1; + @ *stdin*:41 ( ) called from read-eval loop at *stdin*:42 type 'quit;' to quit to outer loop brk> Where(); *[1] repeat x := 1; -until 1; at *stdin*:41 called from +until 1; + @ *stdin*:41 ( ) called from read-eval loop at *errin*:1 brk> WhereWithVars(); *[1] repeat x := 1; -until 1; at *stdin*:41 +until 1; + @ *stdin*:41 arguments: local variables: x := 1 - called from ( ) called from read-eval loop at *errin*:2 brk> quit; @@ -366,20 +392,22 @@ gap> f:=function() local x; Assert(0, 1); return 2; end;; gap> f(); Error, Assert: must be 'true' or 'false' (not the integer 1) Stack trace: -*[1] Assert( 0, 1 ); at *stdin*:44 called from +*[1] Assert( 0, 1 ); + @ *stdin*:44 ( ) called from read-eval loop at *stdin*:45 type 'quit;' to quit to outer loop brk> Where(); -*[1] Assert( 0, 1 ); at *stdin*:44 called from +*[1] Assert( 0, 1 ); + @ *stdin*:44 ( ) called from read-eval loop at *errin*:1 brk> WhereWithVars(); -*[1] Assert( 0, 1 ); at *stdin*:44 +*[1] Assert( 0, 1 ); + @ *stdin*:44 arguments: local variables: x := - called from ( ) called from read-eval loop at *errin*:2 brk> quit; @@ -389,20 +417,22 @@ gap> f:=function() local x; Assert(0, 1, "hello"); return 2; end;; gap> f(); Error, Assert: must be 'true' or 'false' (not the integer 1) Stack trace: -*[1] Assert( 0, 1, "hello" ); at *stdin*:47 called from +*[1] Assert( 0, 1, "hello" ); + @ *stdin*:47 ( ) called from read-eval loop at *stdin*:48 type 'quit;' to quit to outer loop brk> Where(); -*[1] Assert( 0, 1, "hello" ); at *stdin*:47 called from +*[1] Assert( 0, 1, "hello" ); + @ *stdin*:47 ( ) called from read-eval loop at *errin*:1 brk> WhereWithVars(); -*[1] Assert( 0, 1, "hello" ); at *stdin*:47 +*[1] Assert( 0, 1, "hello" ); + @ *stdin*:47 arguments: local variables: x := - called from ( ) called from read-eval loop at *errin*:2 brk> quit; @@ -417,37 +447,43 @@ gap> l := [[1]];; f := {} -> l[2,1];; gap> f(); Error, List Element: [2] must have an assigned value Stack trace: -*[1] return m[i][j]; at GAPROOT/lib/matrix.gi:LINE called from - [2] ELM_LIST( m, row, col ) at *stdin*:54 called from - [3] return l[2, 1]; at *stdin*:55 called from +*[1] return m[i][j]; + @ GAPROOT/lib/matrix.gi:LINE + [2] ELM_LIST( m, row, col ) + @ *stdin*:54 + [3] return l[2, 1]; + @ *stdin*:55 ( ) called from read-eval loop at *stdin*:56 type 'quit;' to quit to outer loop brk> Where(); -*[1] return m[i][j]; at GAPROOT/lib/matrix.gi:LINE called from - [2] ELM_LIST( m, row, col ) at *stdin*:54 called from - [3] return l[2, 1]; at *stdin*:55 called from +*[1] return m[i][j]; + @ GAPROOT/lib/matrix.gi:LINE + [2] ELM_LIST( m, row, col ) + @ *stdin*:54 + [3] return l[2, 1]; + @ *stdin*:55 ( ) called from read-eval loop at *errin*:1 brk> WhereWithVars(); -*[1] return m[i][j]; at GAPROOT/lib/matrix.gi:LINE +*[1] return m[i][j]; + @ GAPROOT/lib/matrix.gi:LINE arguments: m := [ [ 1 ] ] i := 2 j := 1 local variables: - called from - [2] ELM_LIST( m, row, col ) at *stdin*:54 + [2] ELM_LIST( m, row, col ) + @ *stdin*:54 arguments: m := [ [ 1 ] ] row := 2 col := 1 local variables: - called from - [3] return l[2, 1]; at *stdin*:55 + [3] return l[2, 1]; + @ *stdin*:55 arguments: local variables: - called from ( ) called from read-eval loop at *errin*:2 brk> quit; @@ -459,8 +495,10 @@ gap> ## gap> InstallMethod( Matrix, [IsFilter, IsSemiring, IsMatrixObj], {a,b,c} -> fail ); Error, FLAGS_FILTER: must be an operation (not a function) Stack trace: -*[1] <> from GAPROOT/lib/oper1.g:LINE in function INSTALL_METHOD called from - [2] <> from GAPROOT/lib/oper1.g:LINE in function InstallMethod called from +*[1] <> + @ GAPROOT/lib/oper1.g:LINE + [2] <> + @ GAPROOT/lib/oper1.g:LINE ( ) called from read-eval loop at *stdin*:61 type 'quit;' to quit to outer loop diff --git a/tst/testspecial/backtrace2.g.out b/tst/testspecial/backtrace2.g.out index 547888026a..3583cc7588 100644 --- a/tst/testspecial/backtrace2.g.out +++ b/tst/testspecial/backtrace2.g.out @@ -27,60 +27,84 @@ gap> test:= function( n ) gap> test( 1 ); Error, ! Stack trace: -*[1] Error( "!\n" ); at *stdin*:24 called from - [2] test( n + 1 ); at *stdin*:26 called from - [3] test( n + 1 ); at *stdin*:26 called from +*[1] Error( "!\n" ); + @ *stdin*:24 + [2] test( n + 1 ); + @ *stdin*:26 + [3] test( n + 1 ); + @ *stdin*:26 ( ) called from read-eval loop at *stdin*:28 you can 'quit;' to quit to outer loop, or you can 'return;' to continue brk> n; Where(); 3 -*[1] Error( "!\n" ); at *stdin*:24 called from - [2] test( n + 1 ); at *stdin*:26 called from - [3] test( n + 1 ); at *stdin*:26 called from +*[1] Error( "!\n" ); + @ *stdin*:24 + [2] test( n + 1 ); + @ *stdin*:26 + [3] test( n + 1 ); + @ *stdin*:26 ( ) called from read-eval loop at *errin*:1 brk> DownEnv(); n; Where(); 2 - [1] Error( "!\n" ); at *stdin*:24 called from -*[2] test( n + 1 ); at *stdin*:26 called from - [3] test( n + 1 ); at *stdin*:26 called from + [1] Error( "!\n" ); + @ *stdin*:24 +*[2] test( n + 1 ); + @ *stdin*:26 + [3] test( n + 1 ); + @ *stdin*:26 ( ) called from read-eval loop at *errin*:2 brk> DownEnv(); n; Where(); 1 - [1] Error( "!\n" ); at *stdin*:24 called from - [2] test( n + 1 ); at *stdin*:26 called from -*[3] test( n + 1 ); at *stdin*:26 called from + [1] Error( "!\n" ); + @ *stdin*:24 + [2] test( n + 1 ); + @ *stdin*:26 +*[3] test( n + 1 ); + @ *stdin*:26 ( ) called from read-eval loop at *errin*:3 brk> DownEnv(); n; Where(); 1 - [1] Error( "!\n" ); at *stdin*:24 called from - [2] test( n + 1 ); at *stdin*:26 called from -*[3] test( n + 1 ); at *stdin*:26 called from + [1] Error( "!\n" ); + @ *stdin*:24 + [2] test( n + 1 ); + @ *stdin*:26 +*[3] test( n + 1 ); + @ *stdin*:26 ( ) called from read-eval loop at *errin*:4 brk> UpEnv(); n; Where(); 2 - [1] Error( "!\n" ); at *stdin*:24 called from -*[2] test( n + 1 ); at *stdin*:26 called from - [3] test( n + 1 ); at *stdin*:26 called from + [1] Error( "!\n" ); + @ *stdin*:24 +*[2] test( n + 1 ); + @ *stdin*:26 + [3] test( n + 1 ); + @ *stdin*:26 ( ) called from read-eval loop at *errin*:5 brk> UpEnv(); n; Where(); 3 -*[1] Error( "!\n" ); at *stdin*:24 called from - [2] test( n + 1 ); at *stdin*:26 called from - [3] test( n + 1 ); at *stdin*:26 called from +*[1] Error( "!\n" ); + @ *stdin*:24 + [2] test( n + 1 ); + @ *stdin*:26 + [3] test( n + 1 ); + @ *stdin*:26 ( ) called from read-eval loop at *errin*:6 brk> UpEnv(); n; Where(); 3 -*[1] Error( "!\n" ); at *stdin*:24 called from - [2] test( n + 1 ); at *stdin*:26 called from - [3] test( n + 1 ); at *stdin*:26 called from +*[1] Error( "!\n" ); + @ *stdin*:24 + [2] test( n + 1 ); + @ *stdin*:26 + [3] test( n + 1 ); + @ *stdin*:26 ( ) called from read-eval loop at *errin*:7 brk> quit; @@ -98,59 +122,83 @@ gap> test:= function( n ) gap> test( 1 ); Error, Rational operations: must not be zero Stack trace: -*[1] 1 / 0 at *stdin*:35 called from - [2] test( n + 1 ); at *stdin*:37 called from - [3] test( n + 1 ); at *stdin*:37 called from +*[1] 1 / 0 + @ *stdin*:35 + [2] test( n + 1 ); + @ *stdin*:37 + [3] test( n + 1 ); + @ *stdin*:37 ( ) called from read-eval loop at *stdin*:39 type 'quit;' to quit to outer loop brk> n; Where(); 3 -*[1] 1 / 0 at *stdin*:35 called from - [2] test( n + 1 ); at *stdin*:37 called from - [3] test( n + 1 ); at *stdin*:37 called from +*[1] 1 / 0 + @ *stdin*:35 + [2] test( n + 1 ); + @ *stdin*:37 + [3] test( n + 1 ); + @ *stdin*:37 ( ) called from read-eval loop at *errin*:1 brk> DownEnv(); n; Where(); 2 - [1] 1 / 0 at *stdin*:35 called from -*[2] test( n + 1 ); at *stdin*:37 called from - [3] test( n + 1 ); at *stdin*:37 called from + [1] 1 / 0 + @ *stdin*:35 +*[2] test( n + 1 ); + @ *stdin*:37 + [3] test( n + 1 ); + @ *stdin*:37 ( ) called from read-eval loop at *errin*:2 brk> DownEnv(); n; Where(); 1 - [1] 1 / 0 at *stdin*:35 called from - [2] test( n + 1 ); at *stdin*:37 called from -*[3] test( n + 1 ); at *stdin*:37 called from + [1] 1 / 0 + @ *stdin*:35 + [2] test( n + 1 ); + @ *stdin*:37 +*[3] test( n + 1 ); + @ *stdin*:37 ( ) called from read-eval loop at *errin*:3 brk> DownEnv(); n; Where(); 1 - [1] 1 / 0 at *stdin*:35 called from - [2] test( n + 1 ); at *stdin*:37 called from -*[3] test( n + 1 ); at *stdin*:37 called from + [1] 1 / 0 + @ *stdin*:35 + [2] test( n + 1 ); + @ *stdin*:37 +*[3] test( n + 1 ); + @ *stdin*:37 ( ) called from read-eval loop at *errin*:4 brk> UpEnv(); n; Where(); 2 - [1] 1 / 0 at *stdin*:35 called from -*[2] test( n + 1 ); at *stdin*:37 called from - [3] test( n + 1 ); at *stdin*:37 called from + [1] 1 / 0 + @ *stdin*:35 +*[2] test( n + 1 ); + @ *stdin*:37 + [3] test( n + 1 ); + @ *stdin*:37 ( ) called from read-eval loop at *errin*:5 brk> UpEnv(); n; Where(); 3 -*[1] 1 / 0 at *stdin*:35 called from - [2] test( n + 1 ); at *stdin*:37 called from - [3] test( n + 1 ); at *stdin*:37 called from +*[1] 1 / 0 + @ *stdin*:35 + [2] test( n + 1 ); + @ *stdin*:37 + [3] test( n + 1 ); + @ *stdin*:37 ( ) called from read-eval loop at *errin*:6 brk> UpEnv(); n; Where(); 3 -*[1] 1 / 0 at *stdin*:35 called from - [2] test( n + 1 ); at *stdin*:37 called from - [3] test( n + 1 ); at *stdin*:37 called from +*[1] 1 / 0 + @ *stdin*:35 + [2] test( n + 1 ); + @ *stdin*:37 + [3] test( n + 1 ); + @ *stdin*:37 ( ) called from read-eval loop at *errin*:7 brk> quit; @@ -170,59 +218,83 @@ gap> test( 1 ); Error, no method found! For debugging hints type ?Recovery from NoMethodFound Error, no 1st choice method found for `IsCommutative' on 1 arguments Stack trace: -*[1] IsAbelian( 1 ) at *stdin*:47 called from - [2] test( n + 1 ); at *stdin*:49 called from - [3] test( n + 1 ); at *stdin*:49 called from +*[1] IsAbelian( 1 ) + @ *stdin*:47 + [2] test( n + 1 ); + @ *stdin*:49 + [3] test( n + 1 ); + @ *stdin*:49 ( ) called from read-eval loop at *stdin*:51 type 'quit;' to quit to outer loop brk> n; Where(); 3 -*[1] IsAbelian( 1 ) at *stdin*:47 called from - [2] test( n + 1 ); at *stdin*:49 called from - [3] test( n + 1 ); at *stdin*:49 called from +*[1] IsAbelian( 1 ) + @ *stdin*:47 + [2] test( n + 1 ); + @ *stdin*:49 + [3] test( n + 1 ); + @ *stdin*:49 ( ) called from read-eval loop at *errin*:1 brk> DownEnv(); n; Where(); 3 -*[1] IsAbelian( 1 ) at *stdin*:47 called from - [2] test( n + 1 ); at *stdin*:49 called from - [3] test( n + 1 ); at *stdin*:49 called from +*[1] IsAbelian( 1 ) + @ *stdin*:47 + [2] test( n + 1 ); + @ *stdin*:49 + [3] test( n + 1 ); + @ *stdin*:49 ( ) called from read-eval loop at *errin*:2 brk> DownEnv(); n; Where(); 2 - [1] IsAbelian( 1 ) at *stdin*:47 called from -*[2] test( n + 1 ); at *stdin*:49 called from - [3] test( n + 1 ); at *stdin*:49 called from + [1] IsAbelian( 1 ) + @ *stdin*:47 +*[2] test( n + 1 ); + @ *stdin*:49 + [3] test( n + 1 ); + @ *stdin*:49 ( ) called from read-eval loop at *errin*:3 brk> DownEnv(); n; Where(); 1 - [1] IsAbelian( 1 ) at *stdin*:47 called from - [2] test( n + 1 ); at *stdin*:49 called from -*[3] test( n + 1 ); at *stdin*:49 called from + [1] IsAbelian( 1 ) + @ *stdin*:47 + [2] test( n + 1 ); + @ *stdin*:49 +*[3] test( n + 1 ); + @ *stdin*:49 ( ) called from read-eval loop at *errin*:4 brk> UpEnv(); n; Where(); 2 - [1] IsAbelian( 1 ) at *stdin*:47 called from -*[2] test( n + 1 ); at *stdin*:49 called from - [3] test( n + 1 ); at *stdin*:49 called from + [1] IsAbelian( 1 ) + @ *stdin*:47 +*[2] test( n + 1 ); + @ *stdin*:49 + [3] test( n + 1 ); + @ *stdin*:49 ( ) called from read-eval loop at *errin*:5 brk> UpEnv(); n; Where(); 3 -*[1] IsAbelian( 1 ) at *stdin*:47 called from - [2] test( n + 1 ); at *stdin*:49 called from - [3] test( n + 1 ); at *stdin*:49 called from +*[1] IsAbelian( 1 ) + @ *stdin*:47 + [2] test( n + 1 ); + @ *stdin*:49 + [3] test( n + 1 ); + @ *stdin*:49 ( ) called from read-eval loop at *errin*:6 brk> UpEnv(); n; Where(); 3 -*[1] IsAbelian( 1 ) at *stdin*:47 called from - [2] test( n + 1 ); at *stdin*:49 called from - [3] test( n + 1 ); at *stdin*:49 called from +*[1] IsAbelian( 1 ) + @ *stdin*:47 + [2] test( n + 1 ); + @ *stdin*:49 + [3] test( n + 1 ); + @ *stdin*:49 ( ) called from read-eval loop at *errin*:7 brk> quit; diff --git a/tst/testspecial/bad-add.g.out b/tst/testspecial/bad-add.g.out index cfa76fecbd..9259da66d3 100644 --- a/tst/testspecial/bad-add.g.out +++ b/tst/testspecial/bad-add.g.out @@ -6,7 +6,8 @@ gap> f(); Error, no method found! For debugging hints type ?Recovery from NoMethodFound Error, no 1st choice method found for `+' on 2 arguments Stack trace: -*[1] 1 + "abc" at *stdin*:3 called from +*[1] 1 + "abc" + @ *stdin*:3 ( ) called from read-eval loop at *stdin*:5 type 'quit;' to quit to outer loop diff --git a/tst/testspecial/bad-array-double-1.g.out b/tst/testspecial/bad-array-double-1.g.out index 0f77b5cb9a..a68076d65a 100644 --- a/tst/testspecial/bad-array-double-1.g.out +++ b/tst/testspecial/bad-array-double-1.g.out @@ -6,7 +6,8 @@ gap> f(); Error, no method found! For debugging hints type ?Recovery from NoMethodFound Error, no 1st choice method found for `[,]' on 3 arguments Stack trace: -*[1] return "abc"[1, 1]; at *stdin*:3 called from +*[1] return "abc"[1, 1]; + @ *stdin*:3 ( ) called from read-eval loop at *stdin*:5 type 'quit;' to quit to outer loop diff --git a/tst/testspecial/bad-array-int-0.g.out b/tst/testspecial/bad-array-int-0.g.out index 06c965e890..17e703a17a 100644 --- a/tst/testspecial/bad-array-int-0.g.out +++ b/tst/testspecial/bad-array-int-0.g.out @@ -8,7 +8,8 @@ gap> f(); Error, no method found! For debugging hints type ?Recovery from NoMethodFound Error, no 1st choice method found for `[]' on 2 arguments Stack trace: -*[1] return l[0]; at *stdin*:5 called from +*[1] return l[0]; + @ *stdin*:5 ( ) called from read-eval loop at *stdin*:7 type 'quit;' to quit to outer loop diff --git a/tst/testspecial/bad-array-int-1.g.out b/tst/testspecial/bad-array-int-1.g.out index 1bb696a6b3..cd7a87a095 100644 --- a/tst/testspecial/bad-array-int-1.g.out +++ b/tst/testspecial/bad-array-int-1.g.out @@ -5,7 +5,8 @@ function( ) ... end gap> f(); Error, List Element: must be a list (not the integer 1) Stack trace: -*[1] return 1[1]; at *stdin*:3 called from +*[1] return 1[1]; + @ *stdin*:3 ( ) called from read-eval loop at *stdin*:5 type 'quit;' to quit to outer loop diff --git a/tst/testspecial/bad-array-string.g.out b/tst/testspecial/bad-array-string.g.out index 754cc970e6..d0bd81ee20 100644 --- a/tst/testspecial/bad-array-string.g.out +++ b/tst/testspecial/bad-array-string.g.out @@ -6,7 +6,8 @@ gap> f(); Error, no method found! For debugging hints type ?Recovery from NoMethodFound Error, no 1st choice method found for `[]' on 2 arguments Stack trace: -*[1] return 1["abc"]; at *stdin*:3 called from +*[1] return 1["abc"]; + @ *stdin*:3 ( ) called from read-eval loop at *stdin*:5 type 'quit;' to quit to outer loop diff --git a/tst/testspecial/bad-array-undef-0.g.out b/tst/testspecial/bad-array-undef-0.g.out index 150bad14b6..5ea205de9a 100644 --- a/tst/testspecial/bad-array-undef-0.g.out +++ b/tst/testspecial/bad-array-undef-0.g.out @@ -6,7 +6,8 @@ function( ) ... end gap> f(); Error, Variable: 'l' must have an assigned value Stack trace: -*[1] return l[1]; at *stdin*:4 called from +*[1] return l[1]; + @ *stdin*:4 ( ) called from read-eval loop at *stdin*:6 type 'quit;' to quit to outer loop diff --git a/tst/testspecial/bad-array-undef-1.g.out b/tst/testspecial/bad-array-undef-1.g.out index 63ff49e3ac..7efcc85219 100644 --- a/tst/testspecial/bad-array-undef-1.g.out +++ b/tst/testspecial/bad-array-undef-1.g.out @@ -7,7 +7,8 @@ function( ) ... end gap> f(); Error, Variable: 'm' must have an assigned value Stack trace: -*[1] return l[m]; at *stdin*:5 called from +*[1] return l[m]; + @ *stdin*:5 ( ) called from read-eval loop at *stdin*:7 type 'quit;' to quit to outer loop diff --git a/tst/testspecial/bad-minus.g.out b/tst/testspecial/bad-minus.g.out index a8ebc320f6..ec55c46e87 100644 --- a/tst/testspecial/bad-minus.g.out +++ b/tst/testspecial/bad-minus.g.out @@ -6,9 +6,12 @@ gap> f(); Error, no method found! For debugging hints type ?Recovery from NoMethodFound Error, no 1st choice method found for `AdditiveInverseMutable' on 1 arguments Stack trace: -*[1] AdditiveInverseMutable( elm ) at GAPROOT/lib/arith.gi:LINE called from - [2] AdditiveInverseImmutable( elm ) at GAPROOT/lib/arith.gi:LINE called from - [3] 1 - "abc" at *stdin*:3 called from +*[1] AdditiveInverseMutable( elm ) + @ GAPROOT/lib/arith.gi:LINE + [2] AdditiveInverseImmutable( elm ) + @ GAPROOT/lib/arith.gi:LINE + [3] 1 - "abc" + @ *stdin*:3 ( ) called from read-eval loop at *stdin*:5 type 'quit;' to quit to outer loop diff --git a/tst/testspecial/break-loop-loop.g.out b/tst/testspecial/break-loop-loop.g.out index 3159319d09..4da0087abd 100644 --- a/tst/testspecial/break-loop-loop.g.out +++ b/tst/testspecial/break-loop-loop.g.out @@ -5,7 +5,8 @@ gap> i:=0; gap> f(1); Error, bar Stack trace: -*[1] Error( "bar" ); at *stdin*:3 called from +*[1] Error( "bar" ); + @ *stdin*:3 ( ) called from read-eval loop at *stdin*:5 you can 'quit;' to quit to outer loop, or diff --git a/tst/testspecial/broken-test.g.out b/tst/testspecial/broken-test.g.out index 72dc2a443e..bbe429da39 100644 --- a/tst/testspecial/broken-test.g.out +++ b/tst/testspecial/broken-test.g.out @@ -1,9 +1,12 @@ gap> Test("broken-test-2.tst", rec(width := 800)); Error, Invalid test file: #@ command found in the middle of a single test at broken-test-2.tst:5 Stack trace: -*[1] ErrorNoReturn( s, " at ", fnam, ":", i ); at GAPROOT/lib/test.gi:LINE called from - [2] testError( "Invalid test file: #@ command found in the middle of a single test" ); at GAPROOT/lib/test.gi:LINE called from - [3] ParseTestInput( full, opts.ignoreComments, fnam ) at GAPROOT/lib/test.gi:LINE called from +*[1] ErrorNoReturn( s, " at ", fnam, ":", i ); + @ GAPROOT/lib/test.gi:LINE + [2] testError( "Invalid test file: #@ command found in the middle of a single test" ); + @ GAPROOT/lib/test.gi:LINE + [3] ParseTestInput( full, opts.ignoreComments, fnam ) + @ GAPROOT/lib/test.gi:LINE ( ) called from read-eval loop at *stdin*:2 type 'quit;' to quit to outer loop @@ -11,9 +14,12 @@ brk> quit; gap> Test("broken-test-3.tst", rec(width := 800)); Error, Invalid test file at broken-test-3.tst:5 Stack trace: -*[1] ErrorNoReturn( s, " at ", fnam, ":", i ); at GAPROOT/lib/test.gi:LINE called from - [2] testError( "Invalid test file" ); at GAPROOT/lib/test.gi:LINE called from - [3] ParseTestInput( full, opts.ignoreComments, fnam ) at GAPROOT/lib/test.gi:LINE called from +*[1] ErrorNoReturn( s, " at ", fnam, ":", i ); + @ GAPROOT/lib/test.gi:LINE + [2] testError( "Invalid test file" ); + @ GAPROOT/lib/test.gi:LINE + [3] ParseTestInput( full, opts.ignoreComments, fnam ) + @ GAPROOT/lib/test.gi:LINE ( ) called from read-eval loop at *stdin*:2 type 'quit;' to quit to outer loop @@ -21,9 +27,12 @@ brk> quit; gap> Test("broken-test-4.tst", rec(width := 800)); Error, Invalid test file: Nested #@if at broken-test-4.tst:2 Stack trace: -*[1] ErrorNoReturn( s, " at ", fnam, ":", i ); at GAPROOT/lib/test.gi:LINE called from - [2] testError( "Invalid test file: Nested #@if" ); at GAPROOT/lib/test.gi:LINE called from - [3] ParseTestInput( full, opts.ignoreComments, fnam ) at GAPROOT/lib/test.gi:LINE called from +*[1] ErrorNoReturn( s, " at ", fnam, ":", i ); + @ GAPROOT/lib/test.gi:LINE + [2] testError( "Invalid test file: Nested #@if" ); + @ GAPROOT/lib/test.gi:LINE + [3] ParseTestInput( full, opts.ignoreComments, fnam ) + @ GAPROOT/lib/test.gi:LINE ( ) called from read-eval loop at *stdin*:2 type 'quit;' to quit to outer loop @@ -31,9 +40,12 @@ brk> quit; gap> Test("broken-test-5.tst", rec(width := 800)); Error, Invalid test file: two #@else at broken-test-5.tst:7 Stack trace: -*[1] ErrorNoReturn( s, " at ", fnam, ":", i ); at GAPROOT/lib/test.gi:LINE called from - [2] testError( "Invalid test file: two #@else" ); at GAPROOT/lib/test.gi:LINE called from - [3] ParseTestInput( full, opts.ignoreComments, fnam ) at GAPROOT/lib/test.gi:LINE called from +*[1] ErrorNoReturn( s, " at ", fnam, ":", i ); + @ GAPROOT/lib/test.gi:LINE + [2] testError( "Invalid test file: two #@else" ); + @ GAPROOT/lib/test.gi:LINE + [3] ParseTestInput( full, opts.ignoreComments, fnam ) + @ GAPROOT/lib/test.gi:LINE ( ) called from read-eval loop at *stdin*:2 type 'quit;' to quit to outer loop @@ -41,9 +53,12 @@ brk> quit; gap> Test("broken-test-6.tst", rec(width := 800)); Error, Invalid test file: Continuation prompt '> ' followed by a tab, expected a regular space at broken-test-6.tst:3 Stack trace: -*[1] ErrorNoReturn( s, " at ", fnam, ":", i ); at GAPROOT/lib/test.gi:LINE called from - [2] testError( "Invalid test file: Continuation prompt '> ' followed by a tab, expected a regular space" ); at GAPROOT/lib/test.gi:LINE called from - [3] ParseTestInput( full, opts.ignoreComments, fnam ) at GAPROOT/lib/test.gi:LINE called from +*[1] ErrorNoReturn( s, " at ", fnam, ":", i ); + @ GAPROOT/lib/test.gi:LINE + [2] testError( "Invalid test file: Continuation prompt '> ' followed by a tab, expected a regular space" ); + @ GAPROOT/lib/test.gi:LINE + [3] ParseTestInput( full, opts.ignoreComments, fnam ) + @ GAPROOT/lib/test.gi:LINE ( ) called from read-eval loop at *stdin*:2 type 'quit;' to quit to outer loop @@ -51,9 +66,12 @@ brk> quit; gap> Test("broken-test-7.tst", rec(width := 800)); Error, Invalid test file: #@elif after #@else at broken-test-7.tst:7 Stack trace: -*[1] ErrorNoReturn( s, " at ", fnam, ":", i ); at GAPROOT/lib/test.gi:LINE called from - [2] testError( "Invalid test file: #@elif after #@else" ); at GAPROOT/lib/test.gi:LINE called from - [3] ParseTestInput( full, opts.ignoreComments, fnam ) at GAPROOT/lib/test.gi:LINE called from +*[1] ErrorNoReturn( s, " at ", fnam, ":", i ); + @ GAPROOT/lib/test.gi:LINE + [2] testError( "Invalid test file: #@elif after #@else" ); + @ GAPROOT/lib/test.gi:LINE + [3] ParseTestInput( full, opts.ignoreComments, fnam ) + @ GAPROOT/lib/test.gi:LINE ( ) called from read-eval loop at *stdin*:2 type 'quit;' to quit to outer loop @@ -61,9 +79,12 @@ brk> quit; gap> Test("broken-test-8.tst", rec(width := 800)); Error, Invalid test file: #@elif without #@if at broken-test-8.tst:1 Stack trace: -*[1] ErrorNoReturn( s, " at ", fnam, ":", i ); at GAPROOT/lib/test.gi:LINE called from - [2] testError( "Invalid test file: #@elif without #@if" ); at GAPROOT/lib/test.gi:LINE called from - [3] ParseTestInput( full, opts.ignoreComments, fnam ) at GAPROOT/lib/test.gi:LINE called from +*[1] ErrorNoReturn( s, " at ", fnam, ":", i ); + @ GAPROOT/lib/test.gi:LINE + [2] testError( "Invalid test file: #@elif without #@if" ); + @ GAPROOT/lib/test.gi:LINE + [3] ParseTestInput( full, opts.ignoreComments, fnam ) + @ GAPROOT/lib/test.gi:LINE ( ) called from read-eval loop at *stdin*:2 type 'quit;' to quit to outer loop @@ -71,9 +92,12 @@ brk> quit; gap> Test("broken-test-9.tst", rec(width := 800)); Error, Invalid test file: Unterminated #@if at broken-test-9.tst:7 Stack trace: -*[1] ErrorNoReturn( s, " at ", fnam, ":", i ); at GAPROOT/lib/test.gi:LINE called from - [2] testError( "Invalid test file: Unterminated #@if" ); at GAPROOT/lib/test.gi:LINE called from - [3] ParseTestInput( full, opts.ignoreComments, fnam ) at GAPROOT/lib/test.gi:LINE called from +*[1] ErrorNoReturn( s, " at ", fnam, ":", i ); + @ GAPROOT/lib/test.gi:LINE + [2] testError( "Invalid test file: Unterminated #@if" ); + @ GAPROOT/lib/test.gi:LINE + [3] ParseTestInput( full, opts.ignoreComments, fnam ) + @ GAPROOT/lib/test.gi:LINE ( ) called from read-eval loop at *stdin*:2 type 'quit;' to quit to outer loop @@ -81,9 +105,12 @@ brk> quit; gap> Test("invalidtestfile.tst", rec(width := 800)); Error, Invalid test file at invalidtestfile.tst:7 Stack trace: -*[1] ErrorNoReturn( s, " at ", fnam, ":", i ); at GAPROOT/lib/test.gi:LINE called from - [2] testError( "Invalid test file" ); at GAPROOT/lib/test.gi:LINE called from - [3] ParseTestInput( full, opts.ignoreComments, fnam ) at GAPROOT/lib/test.gi:LINE called from +*[1] ErrorNoReturn( s, " at ", fnam, ":", i ); + @ GAPROOT/lib/test.gi:LINE + [2] testError( "Invalid test file" ); + @ GAPROOT/lib/test.gi:LINE + [3] ParseTestInput( full, opts.ignoreComments, fnam ) + @ GAPROOT/lib/test.gi:LINE ( ) called from read-eval loop at *stdin*:2 type 'quit;' to quit to outer loop diff --git a/tst/testspecial/current-env.g.out b/tst/testspecial/current-env.g.out index 319c9a58d2..e90991e7e2 100644 --- a/tst/testspecial/current-env.g.out +++ b/tst/testspecial/current-env.g.out @@ -8,10 +8,12 @@ gap> f := function() gap> f(); Error, You cannot loop over the integer 1 did you mean the range [1..1] Stack trace: -*[1] Error( "You cannot loop over the integer ", n, " did you mean the range [1..", n, "]" ); at GAPROOT/lib/integer.gi:LINE called from +*[1] Error( "You cannot loop over the integer ", n, " did you mean the range [1..", n, "]" ); + @ GAPROOT/lib/integer.gi:LINE [2] for i in 1 do return 1; -od; at *stdin*:6 called from +od; + @ *stdin*:6 ( ) called from read-eval loop at *stdin*:9 you can 'quit;' to quit to outer loop, or diff --git a/tst/testspecial/debug-var.g.out b/tst/testspecial/debug-var.g.out index 60ec4ed89e..c39af18014 100644 --- a/tst/testspecial/debug-var.g.out +++ b/tst/testspecial/debug-var.g.out @@ -13,8 +13,10 @@ gap> f:=function(a) gap> f(1); Error, breakpoint Stack trace: -*[1] Error( "breakpoint" ); at *stdin*:9 called from - [2] g( 10 ) at *stdin*:12 called from +*[1] Error( "breakpoint" ); + @ *stdin*:9 + [2] g( 10 ) + @ *stdin*:12 ( ) called from read-eval loop at *stdin*:14 you can 'quit;' to quit to outer loop, or @@ -36,8 +38,10 @@ unbound_global; ^^^^^^^^^^^^^^ Error, Variable: 'unbound_global' must have a value Stack trace: -*[1] Error( "breakpoint" ); at *stdin*:9 called from - [2] g( 10 ) at *stdin*:12 called from +*[1] Error( "breakpoint" ); + @ *stdin*:9 + [2] g( 10 ) + @ *stdin*:12 ( ) called from read-eval loop at *errin*:6 brk> @@ -51,8 +55,10 @@ true brk> unbound_higher; Error, Variable: 'unbound_higher' must have an assigned value Stack trace: -*[1] Error( "breakpoint" ); at *stdin*:9 called from - [2] g( 10 ) at *stdin*:12 called from +*[1] Error( "breakpoint" ); + @ *stdin*:9 + [2] g( 10 ) + @ *stdin*:12 ( ) called from read-eval loop at *errin*:12 type 'quit;' to quit to outer loop @@ -68,8 +74,10 @@ true brk> unbound_local; Error, Variable: 'unbound_local' must have an assigned value Stack trace: -*[1] Error( "breakpoint" ); at *stdin*:9 called from - [2] g( 10 ) at *stdin*:12 called from +*[1] Error( "breakpoint" ); + @ *stdin*:9 + [2] g( 10 ) + @ *stdin*:12 ( ) called from read-eval loop at *errin*:17 type 'quit;' to quit to outer loop @@ -93,8 +101,10 @@ function( p ) ... end gap> f(1); Error, breakpoint Stack trace: -*[1] Error( "breakpoint" ); at *stdin*:9 called from - [2] g( 10 ) at *stdin*:12 called from +*[1] Error( "breakpoint" ); + @ *stdin*:9 + [2] g( 10 ) + @ *stdin*:12 ( ) called from read-eval loop at *stdin*:23 you can 'quit;' to quit to outer loop, or @@ -102,9 +112,12 @@ you can 'return;' to continue brk> h(2); Error, foobar Stack trace: -*[1] Error( "foobar" ); at *stdin*:20 called from - [2] Error( "breakpoint" ); at *stdin*:9 called from - [3] g( 10 ) at *stdin*:12 called from +*[1] Error( "foobar" ); + @ *stdin*:20 + [2] Error( "breakpoint" ); + @ *stdin*:9 + [3] g( 10 ) + @ *stdin*:12 ( ) called from read-eval loop at *errin*:1 you can 'quit;' to quit to outer loop, or @@ -120,9 +133,12 @@ true brk_2> unbound_higher; Error, Variable: must have a value Stack trace: -*[1] Error( "foobar" ); at *stdin*:20 called from - [2] Error( "breakpoint" ); at *stdin*:9 called from - [3] g( 10 ) at *stdin*:12 called from +*[1] Error( "foobar" ); + @ *stdin*:20 + [2] Error( "breakpoint" ); + @ *stdin*:9 + [3] g( 10 ) + @ *stdin*:12 ( ) called from read-eval loop at *errin*:6 brk_2> @@ -130,33 +146,45 @@ brk_2> # check coding of dvars brk_2> function() return unbound_higher; end; Error, Variable: cannot be used here Stack trace: -*[1] Error( "foobar" ); at *stdin*:20 called from - [2] Error( "breakpoint" ); at *stdin*:9 called from - [3] g( 10 ) at *stdin*:12 called from +*[1] Error( "foobar" ); + @ *stdin*:20 + [2] Error( "breakpoint" ); + @ *stdin*:9 + [3] g( 10 ) + @ *stdin*:12 ( ) called from read-eval loop at *errin*:9 brk_2> function() return IsBound(unbound_higher); end; Error, Variable: cannot be used here Stack trace: -*[1] Error( "foobar" ); at *stdin*:20 called from - [2] Error( "breakpoint" ); at *stdin*:9 called from - [3] g( 10 ) at *stdin*:12 called from +*[1] Error( "foobar" ); + @ *stdin*:20 + [2] Error( "breakpoint" ); + @ *stdin*:9 + [3] g( 10 ) + @ *stdin*:12 ( ) called from read-eval loop at *errin*:10 brk_2> function() Unbind(unbound_higher); end; Error, Variable: cannot be used here Stack trace: -*[1] Error( "foobar" ); at *stdin*:20 called from - [2] Error( "breakpoint" ); at *stdin*:9 called from - [3] g( 10 ) at *stdin*:12 called from +*[1] Error( "foobar" ); + @ *stdin*:20 + [2] Error( "breakpoint" ); + @ *stdin*:9 + [3] g( 10 ) + @ *stdin*:12 ( ) called from read-eval loop at *errin*:11 brk_2> function() unbound_higher:=0; end; Error, Variable: cannot be used here Stack trace: -*[1] Error( "foobar" ); at *stdin*:20 called from - [2] Error( "breakpoint" ); at *stdin*:9 called from - [3] g( 10 ) at *stdin*:12 called from +*[1] Error( "foobar" ); + @ *stdin*:20 + [2] Error( "breakpoint" ); + @ *stdin*:9 + [3] g( 10 ) + @ *stdin*:12 ( ) called from read-eval loop at *errin*:12 brk_2> QUIT; diff --git a/tst/testspecial/func-and-proc-call-trace.g.out b/tst/testspecial/func-and-proc-call-trace.g.out index 8e91f92570..046b27f874 100644 --- a/tst/testspecial/func-and-proc-call-trace.g.out +++ b/tst/testspecial/func-and-proc-call-trace.g.out @@ -6,7 +6,8 @@ gap> informproc0([]); Error, no method found! For debugging hints type ?Recovery from NoMethodFound Error, no 1st choice method found for `CallFuncList' on 2 arguments Stack trace: -*[1] l( ); at *stdin*:4 called from +*[1] l( ); + @ *stdin*:4 ( ) called from read-eval loop at *stdin*:6 type 'quit;' to quit to outer loop @@ -22,7 +23,8 @@ gap> informproc1([]); Error, no method found! For debugging hints type ?Recovery from NoMethodFound Error, no 1st choice method found for `CallFuncList' on 2 arguments Stack trace: -*[1] l( 1 ); at *stdin*:9 called from +*[1] l( 1 ); + @ *stdin*:9 ( ) called from read-eval loop at *stdin*:11 type 'quit;' to quit to outer loop @@ -38,7 +40,8 @@ gap> informproc2([]); Error, no method found! For debugging hints type ?Recovery from NoMethodFound Error, no 1st choice method found for `CallFuncList' on 2 arguments Stack trace: -*[1] l( 1, 2 ); at *stdin*:14 called from +*[1] l( 1, 2 ); + @ *stdin*:14 ( ) called from read-eval loop at *stdin*:16 type 'quit;' to quit to outer loop @@ -54,7 +57,8 @@ gap> informproc3([]); Error, no method found! For debugging hints type ?Recovery from NoMethodFound Error, no 1st choice method found for `CallFuncList' on 2 arguments Stack trace: -*[1] l( 1, 2, 3 ); at *stdin*:19 called from +*[1] l( 1, 2, 3 ); + @ *stdin*:19 ( ) called from read-eval loop at *stdin*:21 type 'quit;' to quit to outer loop @@ -70,7 +74,8 @@ gap> informproc4([]); Error, no method found! For debugging hints type ?Recovery from NoMethodFound Error, no 1st choice method found for `CallFuncList' on 2 arguments Stack trace: -*[1] l( 1, 2, 3, 4 ); at *stdin*:24 called from +*[1] l( 1, 2, 3, 4 ); + @ *stdin*:24 ( ) called from read-eval loop at *stdin*:26 type 'quit;' to quit to outer loop @@ -86,7 +91,8 @@ gap> informproc5([]); Error, no method found! For debugging hints type ?Recovery from NoMethodFound Error, no 1st choice method found for `CallFuncList' on 2 arguments Stack trace: -*[1] l( 1, 2, 3, 4, 5 ); at *stdin*:29 called from +*[1] l( 1, 2, 3, 4, 5 ); + @ *stdin*:29 ( ) called from read-eval loop at *stdin*:31 type 'quit;' to quit to outer loop @@ -102,7 +108,8 @@ gap> informproc6([]); Error, no method found! For debugging hints type ?Recovery from NoMethodFound Error, no 1st choice method found for `CallFuncList' on 2 arguments Stack trace: -*[1] l( 1, 2, 3, 4, 5, 6 ); at *stdin*:34 called from +*[1] l( 1, 2, 3, 4, 5, 6 ); + @ *stdin*:34 ( ) called from read-eval loop at *stdin*:36 type 'quit;' to quit to outer loop @@ -118,7 +125,8 @@ gap> informprocmore([]); Error, no method found! For debugging hints type ?Recovery from NoMethodFound Error, no 1st choice method found for `CallFuncList' on 2 arguments Stack trace: -*[1] l( 1, 2, 3, 4, 5, 6, 7 ); at *stdin*:39 called from +*[1] l( 1, 2, 3, 4, 5, 6, 7 ); + @ *stdin*:39 ( ) called from read-eval loop at *stdin*:41 type 'quit;' to quit to outer loop @@ -134,7 +142,8 @@ gap> informfunc0([]); Error, no method found! For debugging hints type ?Recovery from NoMethodFound Error, no 1st choice method found for `CallFuncList' on 2 arguments Stack trace: -*[1] l( ) at *stdin*:44 called from +*[1] l( ) + @ *stdin*:44 ( ) called from read-eval loop at *stdin*:46 type 'quit;' to quit to outer loop @@ -150,7 +159,8 @@ gap> informfunc1([]); Error, no method found! For debugging hints type ?Recovery from NoMethodFound Error, no 1st choice method found for `CallFuncList' on 2 arguments Stack trace: -*[1] l( 1 ) at *stdin*:49 called from +*[1] l( 1 ) + @ *stdin*:49 ( ) called from read-eval loop at *stdin*:51 type 'quit;' to quit to outer loop @@ -166,7 +176,8 @@ gap> informfunc2([]); Error, no method found! For debugging hints type ?Recovery from NoMethodFound Error, no 1st choice method found for `CallFuncList' on 2 arguments Stack trace: -*[1] l( 1, 2 ) at *stdin*:54 called from +*[1] l( 1, 2 ) + @ *stdin*:54 ( ) called from read-eval loop at *stdin*:56 type 'quit;' to quit to outer loop @@ -182,7 +193,8 @@ gap> informfunc3([]); Error, no method found! For debugging hints type ?Recovery from NoMethodFound Error, no 1st choice method found for `CallFuncList' on 2 arguments Stack trace: -*[1] l( 1, 2, 3 ) at *stdin*:59 called from +*[1] l( 1, 2, 3 ) + @ *stdin*:59 ( ) called from read-eval loop at *stdin*:61 type 'quit;' to quit to outer loop @@ -198,7 +210,8 @@ gap> informfunc4([]); Error, no method found! For debugging hints type ?Recovery from NoMethodFound Error, no 1st choice method found for `CallFuncList' on 2 arguments Stack trace: -*[1] l( 1, 2, 3, 4 ) at *stdin*:64 called from +*[1] l( 1, 2, 3, 4 ) + @ *stdin*:64 ( ) called from read-eval loop at *stdin*:66 type 'quit;' to quit to outer loop @@ -214,7 +227,8 @@ gap> informfunc5([]); Error, no method found! For debugging hints type ?Recovery from NoMethodFound Error, no 1st choice method found for `CallFuncList' on 2 arguments Stack trace: -*[1] l( 1, 2, 3, 4, 5 ) at *stdin*:69 called from +*[1] l( 1, 2, 3, 4, 5 ) + @ *stdin*:69 ( ) called from read-eval loop at *stdin*:71 type 'quit;' to quit to outer loop @@ -230,7 +244,8 @@ gap> informfunc6([]); Error, no method found! For debugging hints type ?Recovery from NoMethodFound Error, no 1st choice method found for `CallFuncList' on 2 arguments Stack trace: -*[1] l( 1, 2, 3, 4, 5, 6 ) at *stdin*:74 called from +*[1] l( 1, 2, 3, 4, 5, 6 ) + @ *stdin*:74 ( ) called from read-eval loop at *stdin*:76 type 'quit;' to quit to outer loop @@ -246,7 +261,8 @@ gap> informfuncmore([]); Error, no method found! For debugging hints type ?Recovery from NoMethodFound Error, no 1st choice method found for `CallFuncList' on 2 arguments Stack trace: -*[1] l( 1, 2, 3, 4, 5, 6, 7 ) at *stdin*:79 called from +*[1] l( 1, 2, 3, 4, 5, 6, 7 ) + @ *stdin*:79 ( ) called from read-eval loop at *stdin*:81 type 'quit;' to quit to outer loop diff --git a/tst/testspecial/line-continuation.g.out b/tst/testspecial/line-continuation.g.out index 08a8f3b373..88f253686c 100644 --- a/tst/testspecial/line-continuation.g.out +++ b/tst/testspecial/line-continuation.g.out @@ -8,7 +8,8 @@ Stack trace: not in any function at stream:2 Error, Could not evaluate string. Stack trace: -*[1] Error( "Could not evaluate string.\n" ); at GAPROOT/lib/string.gi:LINE called from +*[1] Error( "Could not evaluate string.\n" ); + @ GAPROOT/lib/string.gi:LINE ( ) called from read-eval loop at *stdin*:6 you can 'quit;' to quit to outer loop, or @@ -20,7 +21,8 @@ Stack trace: not in any function at stream:2 Error, Could not evaluate string. Stack trace: -*[1] Error( "Could not evaluate string.\n" ); at GAPROOT/lib/string.gi:LINE called from +*[1] Error( "Could not evaluate string.\n" ); + @ GAPROOT/lib/string.gi:LINE ( ) called from read-eval loop at *stdin*:6 you can 'quit;' to quit to outer loop, or diff --git a/tst/testspecial/mem-overflow.g.out b/tst/testspecial/mem-overflow.g.out index df6e77c763..82620ab76a 100644 --- a/tst/testspecial/mem-overflow.g.out +++ b/tst/testspecial/mem-overflow.g.out @@ -3,7 +3,8 @@ gap> l:=[1];; while true do Append(l,l); od; Error, reached the pre-set memory limit (change it with the -o command line option) Stack trace: -*[1] Append( l, l ); at *stdin*:3 called from +*[1] Append( l, l ); + @ *stdin*:3 ( ) called from read-eval loop at *stdin*:3 you can 'return;' diff --git a/tst/testspecial/method-not-found-where.g.out b/tst/testspecial/method-not-found-where.g.out index e2a843aeb7..c7496f32b2 100644 --- a/tst/testspecial/method-not-found-where.g.out +++ b/tst/testspecial/method-not-found-where.g.out @@ -4,7 +4,8 @@ gap> f(()); Error, no method found! For debugging hints type ?Recovery from NoMethodFound Error, no 1st choice method found for `+' on 2 arguments Stack trace: -*[1] a + a at *stdin*:3 called from +*[1] a + a + @ *stdin*:3 ( ) called from read-eval loop at *stdin*:4 type 'quit;' to quit to outer loop @@ -12,7 +13,8 @@ brk> ShowMethods(1); #I Searching Method for + with 2 arguments: #I Total: 138 entries brk> Where(5); -*[1] a + a at *stdin*:3 called from +*[1] a + a + @ *stdin*:3 ( ) called from read-eval loop at *errin*:2 brk> quit; diff --git a/tst/testspecial/method-not-found.g.out b/tst/testspecial/method-not-found.g.out index e982bc5443..fa8a04ad87 100644 --- a/tst/testspecial/method-not-found.g.out +++ b/tst/testspecial/method-not-found.g.out @@ -3,7 +3,8 @@ gap> f:=a->a+a;; f(()); Error, no method found! For debugging hints type ?Recovery from NoMethodFound Error, no 1st choice method found for `+' on 2 arguments Stack trace: -*[1] a + a at *stdin*:3 called from +*[1] a + a + @ *stdin*:3 ( ) called from read-eval loop at *stdin*:3 type 'quit;' to quit to outer loop diff --git a/tst/testspecial/repl-syntax-err.g.out b/tst/testspecial/repl-syntax-err.g.out index 5e160ce41f..9b4f6bc090 100644 --- a/tst/testspecial/repl-syntax-err.g.out +++ b/tst/testspecial/repl-syntax-err.g.out @@ -6,7 +6,7 @@ gap> # error then is displayed. The next line then contains another syntax gap> # error, which wasn't reported correctly before the above issues was gap> # fixed. gap> Error(""): -Error, +Error, Stack trace: not in any function at *stdin*:9 you can 'quit;' to quit to outer loop, or diff --git a/tst/testspecial/stack-depth-func.g.out b/tst/testspecial/stack-depth-func.g.out index 584e40e9be..60ab11d2a3 100644 --- a/tst/testspecial/stack-depth-func.g.out +++ b/tst/testspecial/stack-depth-func.g.out @@ -3,21 +3,31 @@ function( ) ... end gap> f(); Error, recursion depth trap (5000) Stack trace: -*[1] f( ); at *stdin*:2 called from - [2] f( ); at *stdin*:2 called from - [3] f( ); at *stdin*:2 called from - [4] f( ); at *stdin*:2 called from - [5] f( ); at *stdin*:2 called from +*[1] f( ); + @ *stdin*:2 + [2] f( ); + @ *stdin*:2 + [3] f( ); + @ *stdin*:2 + [4] f( ); + @ *stdin*:2 + [5] f( ); + @ *stdin*:2 ... at *stdin*:3 you may 'return;' brk> return; # try once more Error, recursion depth trap (10000) Stack trace: -*[1] f( ); at *stdin*:2 called from - [2] f( ); at *stdin*:2 called from - [3] f( ); at *stdin*:2 called from - [4] f( ); at *stdin*:2 called from - [5] f( ); at *stdin*:2 called from +*[1] f( ); + @ *stdin*:2 + [2] f( ); + @ *stdin*:2 + [3] f( ); + @ *stdin*:2 + [4] f( ); + @ *stdin*:2 + [5] f( ); + @ *stdin*:2 ... at *stdin*:3 you may 'return;' brk> QUIT; diff --git a/tst/testspecial/stack-depth-func2.g.out b/tst/testspecial/stack-depth-func2.g.out index d3dbc9bed8..7027f3df17 100644 --- a/tst/testspecial/stack-depth-func2.g.out +++ b/tst/testspecial/stack-depth-func2.g.out @@ -3,21 +3,31 @@ function( ) ... end gap> y := f(); Error, recursion depth trap (5000) Stack trace: -*[1] f( ) at *stdin*:2 called from - [2] f( ) at *stdin*:2 called from - [3] f( ) at *stdin*:2 called from - [4] f( ) at *stdin*:2 called from - [5] f( ) at *stdin*:2 called from +*[1] f( ) + @ *stdin*:2 + [2] f( ) + @ *stdin*:2 + [3] f( ) + @ *stdin*:2 + [4] f( ) + @ *stdin*:2 + [5] f( ) + @ *stdin*:2 ... at *stdin*:3 you may 'return;' brk> return; # try once more Error, recursion depth trap (10000) Stack trace: -*[1] f( ) at *stdin*:2 called from - [2] f( ) at *stdin*:2 called from - [3] f( ) at *stdin*:2 called from - [4] f( ) at *stdin*:2 called from - [5] f( ) at *stdin*:2 called from +*[1] f( ) + @ *stdin*:2 + [2] f( ) + @ *stdin*:2 + [3] f( ) + @ *stdin*:2 + [4] f( ) + @ *stdin*:2 + [5] f( ) + @ *stdin*:2 ... at *stdin*:3 you may 'return;' brk> QUIT; diff --git a/tst/testspecial/stack-depth-rec.g.out b/tst/testspecial/stack-depth-rec.g.out index e9192f564b..af205e7582 100644 --- a/tst/testspecial/stack-depth-rec.g.out +++ b/tst/testspecial/stack-depth-rec.g.out @@ -71,21 +71,31 @@ rec( gap> String(r); Error, recursion depth trap (5000) Stack trace: -*[1] String( record.(nam) ) at GAPROOT/lib/record.gi:LINE called from - [2] String( record.(nam) ) at GAPROOT/lib/record.gi:LINE called from - [3] String( record.(nam) ) at GAPROOT/lib/record.gi:LINE called from - [4] String( record.(nam) ) at GAPROOT/lib/record.gi:LINE called from - [5] String( record.(nam) ) at GAPROOT/lib/record.gi:LINE called from +*[1] String( record.(nam) ) + @ GAPROOT/lib/record.gi:LINE + [2] String( record.(nam) ) + @ GAPROOT/lib/record.gi:LINE + [3] String( record.(nam) ) + @ GAPROOT/lib/record.gi:LINE + [4] String( record.(nam) ) + @ GAPROOT/lib/record.gi:LINE + [5] String( record.(nam) ) + @ GAPROOT/lib/record.gi:LINE ... at *stdin*:4 you may 'return;' brk> return; # try once more Error, recursion depth trap (5000) Stack trace: -*[1] String( record.(nam) ) at GAPROOT/lib/record.gi:LINE called from - [2] String( record.(nam) ) at GAPROOT/lib/record.gi:LINE called from - [3] String( record.(nam) ) at GAPROOT/lib/record.gi:LINE called from - [4] String( record.(nam) ) at GAPROOT/lib/record.gi:LINE called from - [5] String( record.(nam) ) at GAPROOT/lib/record.gi:LINE called from +*[1] String( record.(nam) ) + @ GAPROOT/lib/record.gi:LINE + [2] String( record.(nam) ) + @ GAPROOT/lib/record.gi:LINE + [3] String( record.(nam) ) + @ GAPROOT/lib/record.gi:LINE + [4] String( record.(nam) ) + @ GAPROOT/lib/record.gi:LINE + [5] String( record.(nam) ) + @ GAPROOT/lib/record.gi:LINE ... at *stdin*:4 you may 'return;' brk> QUIT; diff --git a/tst/testspecial/stack-trace-depth.g b/tst/testspecial/stack-trace-depth.g new file mode 100644 index 0000000000..dde6f2571b --- /dev/null +++ b/tst/testspecial/stack-trace-depth.g @@ -0,0 +1,36 @@ +f11 := function() + Error("foo"); +end;; +f10 := function() + return f11(); +end;; +f9 := function() + return f10(); +end;; +f8 := function() + return f9(); +end;; +f7 := function() + return f8(); +end;; +f6 := function() + return f7(); +end;; +f5 := function() + return f6(); +end;; +f4 := function() + return f5(); +end;; +f3 := function() + return f4(); +end;; +f2 := function() + return f3(); +end;; +f1 := function() + return f2(); +end;; +f1(); +Where(12); +quit; diff --git a/tst/testspecial/stack-trace-depth.g.out b/tst/testspecial/stack-trace-depth.g.out new file mode 100644 index 0000000000..0005d8c5c7 --- /dev/null +++ b/tst/testspecial/stack-trace-depth.g.out @@ -0,0 +1,76 @@ +gap> f11 := function() +> Error("foo"); +> end;; +gap> f10 := function() +> return f11(); +> end;; +gap> f9 := function() +> return f10(); +> end;; +gap> f8 := function() +> return f9(); +> end;; +gap> f7 := function() +> return f8(); +> end;; +gap> f6 := function() +> return f7(); +> end;; +gap> f5 := function() +> return f6(); +> end;; +gap> f4 := function() +> return f5(); +> end;; +gap> f3 := function() +> return f4(); +> end;; +gap> f2 := function() +> return f3(); +> end;; +gap> f1 := function() +> return f2(); +> end;; +gap> f1(); +Error, foo +Stack trace: +*[1] Error( "foo" ); + @ *stdin*:3 + [2] f11( ) + @ *stdin*:6 + [3] f10( ) + @ *stdin*:9 + [4] f9( ) + @ *stdin*:12 + [5] f8( ) + @ *stdin*:15 +... at *stdin*:35 +you can 'quit;' to quit to outer loop, or +you can 'return;' to continue +brk> Where(12); +* [1] Error( "foo" ); + @ *stdin*:3 + [2] f11( ) + @ *stdin*:6 + [3] f10( ) + @ *stdin*:9 + [4] f9( ) + @ *stdin*:12 + [5] f8( ) + @ *stdin*:15 + [6] f7( ) + @ *stdin*:18 + [7] f6( ) + @ *stdin*:21 + [8] f5( ) + @ *stdin*:24 + [9] f4( ) + @ *stdin*:27 + [10] f3( ) + @ *stdin*:30 + [11] f2( ) + @ *stdin*:33 +( ) + called from read-eval loop at *errin*:1 +brk> quit; +gap> QUIT; diff --git a/tst/testspecial/stack-trace-label.g.out b/tst/testspecial/stack-trace-label.g.out index bd31c1584b..a7a71b90c8 100644 --- a/tst/testspecial/stack-trace-label.g.out +++ b/tst/testspecial/stack-trace-label.g.out @@ -4,7 +4,8 @@ gap> f := function() gap> f(); Error, foo Stack trace: -*[1] Error( "foo" ); at *stdin*:3 called from +*[1] Error( "foo" ); + @ *stdin*:3 ( ) called from read-eval loop at *stdin*:5 you can 'quit;' to quit to outer loop, or diff --git a/tst/testspecial/syntax-tree-error.g b/tst/testspecial/syntax-tree-error.g index c2c6880920..f944007879 100644 --- a/tst/testspecial/syntax-tree-error.g +++ b/tst/testspecial/syntax-tree-error.g @@ -1,5 +1,5 @@ func := function ( ) - Error( ); + Error( "oops" ); end; func := SYNTAX_TREE_CODE( SYNTAX_TREE( func ) ); diff --git a/tst/testspecial/syntax-tree-error.g.out b/tst/testspecial/syntax-tree-error.g.out index 16b8ded9f9..96794103f1 100644 --- a/tst/testspecial/syntax-tree-error.g.out +++ b/tst/testspecial/syntax-tree-error.g.out @@ -1,5 +1,5 @@ gap> func := function ( ) -> Error( ); +> Error( "oops" ); > end; function( ) ... end gap> @@ -7,9 +7,9 @@ gap> func := SYNTAX_TREE_CODE( SYNTAX_TREE( func ) ); function( ) ... end gap> gap> func( ); -Error, +Error, oops Stack trace: -*[1] called from +*[1] ( ) called from read-eval loop at *stdin*:8 you can 'quit;' to quit to outer loop, or diff --git a/tst/testspecial/up-down-env.g.out b/tst/testspecial/up-down-env.g.out index a1e18d2a06..f27012aa67 100644 --- a/tst/testspecial/up-down-env.g.out +++ b/tst/testspecial/up-down-env.g.out @@ -8,11 +8,16 @@ function( lvl ) ... end gap> f(7); Error, Rational operations: must not be zero Stack trace: -*[1] 1 / lvl at *stdin*:7 called from - [2] f( lvl - 1 ) at *stdin*:7 called from - [3] f( lvl - 1 ) at *stdin*:7 called from - [4] f( lvl - 1 ) at *stdin*:7 called from - [5] f( lvl - 1 ) at *stdin*:7 called from +*[1] 1 / lvl + @ *stdin*:7 + [2] f( lvl - 1 ) + @ *stdin*:7 + [3] f( lvl - 1 ) + @ *stdin*:7 + [4] f( lvl - 1 ) + @ *stdin*:7 + [5] f( lvl - 1 ) + @ *stdin*:7 ... at *stdin*:8 type 'quit;' to quit to outer loop brk> UpEnv(1); lvl; From 3f5eebe569c1238c1f8e6ae6fd829e97be4d7637 Mon Sep 17 00:00:00 2001 From: Max Horn Date: Wed, 25 Mar 2026 09:50:15 +0100 Subject: [PATCH 120/234] Implemented the method MultVectorRight for lists (#6280) --- lib/listcoef.gd | 23 +++++-- lib/listcoef.gi | 64 +++++++++++++---- tst/testinstall/MatrixObj/MultVector.tst | 87 ++++++++++++++++++++---- 3 files changed, 144 insertions(+), 30 deletions(-) diff --git a/lib/listcoef.gd b/lib/listcoef.gd index a509a219fa..a97e54b8f6 100644 --- a/lib/listcoef.gd +++ b/lib/listcoef.gd @@ -105,15 +105,27 @@ DeclareOperation( ## ## <#GAPDoc Label="MultVector"> ## -## -## +## +## +## ## nothing ## ## -## This operation calculates mul*list1 in-place. +## The operation multiplies the entries of list +## by the scalar mul from the left, in-place. +##

+## The operation multiplies the entries of list +## by the scalar mul from the right, in-place. ##

## Note that MultVector is just a synonym for ## MultVectorLeft. +## A:= FreeAssociativeAlgebraWithOne( Rationals, "a", "b", "c" );; +## gap> l:=[A.1,A.2];; MultVectorLeft(l, A.3); l; +## [ (1)*c*a, (1)*c*b ] +## gap> l:=[A.1,A.2];; MultVectorRight(l, A.3); l; +## [ (1)*a*c, (1)*b*c ] +## ]]> ## ## ## <#/GAPDoc> @@ -122,7 +134,10 @@ DeclareOperation( "MultVectorLeft", [ IsMutable and IsList, IsObject ] ); -# For VectorObj objects there also exists a MultVectorRight operation +DeclareOperation( + "MultVectorRight", + [ IsMutable and IsList, + IsObject ] ); DeclareSynonym( "MultVector", MultVectorLeft ); ############################################################################# diff --git a/lib/listcoef.gi b/lib/listcoef.gi index 2fe2126df0..8519d78cf5 100644 --- a/lib/listcoef.gi +++ b/lib/listcoef.gi @@ -271,36 +271,76 @@ InstallMethod( MultVectorLeft, [ IsDenseList and IsMutable, IsObject ], function( l, m ) - local i; - for i in [ 1 .. Length(l) ] do + local i; + for i in [ 1 .. Length(l) ] do l[i] := m * l[i]; od; end ); + InstallOtherMethod( MultVectorLeft, "error if immutable", [ IsList, IsObject ], - L1_IMMUTABLE_ERROR); + L1_IMMUTABLE_ERROR ); InstallMethod( MultVectorLeft, "kernel method for a mutable dense small list, and an object", IsCollsElms, [ IsSmallList and IsDenseList and IsMutable, IsObject ], - MULT_VECTOR_LEFT_2 -); + MULT_VECTOR_LEFT_2 ); + InstallMethod( MultVectorLeft, - "kernel method for a mutable dense plain list of \ -cyclotomics, and a cyclotomic", + "kernel method for a mutable dense plain list of cyclotomics, and a cyclotomic", IsCollsElms, [ IsDenseList and IsMutable and IsPlistRep and IsCyclotomicCollection, IsCyclotomic ], - MULT_VECTOR_2_FAST -); + MULT_VECTOR_2_FAST ); + InstallMethod( MultVectorLeft, - "kernel method for a mutable row vector of ffes in \ -plain list rep, and an ffe", + "kernel method for a mutable row vector of ffes in plain list rep, and an ffe", + IsCollsElms, + [ IsRowVector and IsMutable and IsPlistRep and IsFFECollection, + IsFFE], + MULT_VECTOR_VECFFES ); + + +############################################################################# +## +#M MultVectorRight( , ) +## +InstallMethod( MultVectorRight, + "for a mutable dense list, and an object", + [ IsDenseList and IsMutable, + IsObject ], +function( l, m ) + local i; + for i in [ 1 .. Length(l) ] do + l[i] := l[i] * m; + od; +end ); + +InstallOtherMethod( MultVectorRight, "error if immutable", + [ IsList, IsObject ], + L1_IMMUTABLE_ERROR); + +InstallMethod( MultVectorRight, + "kernel method for a mutable dense small list, and an object", + IsCollsElms, + [ IsSmallList and IsDenseList and IsMutable, + IsObject ], + MULT_VECTOR_RIGHT_2 ); + +InstallMethod( MultVectorRight, + "kernel method for a mutable dense plain list of cyclotomics, and a cyclotomic", + IsCollsElms, + [ IsDenseList and IsMutable and IsPlistRep and IsCyclotomicCollection, + IsCyclotomic ], + MULT_VECTOR_2_FAST ); + +InstallMethod( MultVectorRight, + "kernel method for a mutable row vector of ffes in plain list rep, and an ffe", IsCollsElms, [ IsRowVector and IsMutable and IsPlistRep and IsFFECollection, - IsFFE],0, + IsFFE], MULT_VECTOR_VECFFES ); diff --git a/tst/testinstall/MatrixObj/MultVector.tst b/tst/testinstall/MatrixObj/MultVector.tst index a13a7b5bf3..f432ad541d 100644 --- a/tst/testinstall/MatrixObj/MultVector.tst +++ b/tst/testinstall/MatrixObj/MultVector.tst @@ -1,26 +1,83 @@ gap> START_TEST("MultVector.tst"); -# Finite Fields -gap> v := NewVector( IsPlistVectorRep, GF(5), [Z(5)^1, Z(5)^2, Z(5)^0, Z(5)^4, 0*Z(5), Z(5)^3 ] ); +# Dense plain lists +gap> li := [ 1, -2, 0, 3 ];; +gap> MultVectorRight(li, -2); +gap> li; +[ -2, 4, 0, -6 ] +gap> MultVectorLeft(li, -1); +gap> li; +[ 2, -4, 0, 6 ] + +# Plain row vectors of ffes +gap> lf := [ Z(5)^0, Z(5)^1, 0*Z(5), Z(5)^3 ];; +gap> IsRowVector(lf); +true +gap> MultVectorLeft(lf, Z(5)^2); +gap> lf; +[ Z(5)^2, Z(5)^3, 0*Z(5), Z(5) ] +gap> MultVectorRight(lf, Z(5)^3); +gap> lf; +[ Z(5), Z(5)^2, 0*Z(5), Z(5)^0 ] + +# Compressed vectors: IsGF2VectorRep +gap> vg2 := NewVector( IsGF2VectorRep, GF(2), +> [ Z(2)^0, 0*Z(2), Z(2)^0, Z(2)^0 ] );; +gap> IsGF2VectorRep(vg2); +true +gap> MultVectorLeft(vg2, Z(2)^0); +gap> Unpack(vg2); +[ Z(2)^0, 0*Z(2), Z(2)^0, Z(2)^0 ] +gap> MultVectorRight(vg2, Z(2)^0); +gap> Unpack(vg2); +[ Z(2)^0, 0*Z(2), Z(2)^0, Z(2)^0 ] + +# Compressed vectors: Is8BitVectorRep +gap> vg5 := NewVector( Is8BitVectorRep, GF(5), +> [ Z(5)^0, Z(5)^1, 0*Z(5), Z(5)^3 ] );; +gap> Is8BitVectorRep(vg5); +true +gap> MultVectorLeft(vg5, Z(5)^2); +gap> Unpack(vg5); +[ Z(5)^2, Z(5)^3, 0*Z(5), Z(5) ] +gap> MultVectorRight(vg5, Z(5)^3); +gap> Unpack(vg5); +[ Z(5), Z(5)^2, 0*Z(5), Z(5)^0 ] + +# IsPlistVectorRep vectors +gap> vp := NewVector( IsPlistVectorRep, GF(5), +> [ Z(5)^1, Z(5)^2, Z(5)^0, Z(5)^4, 0*Z(5), Z(5)^3 ] ); -gap> MultVector(v, Z(5)^3); -gap> Unpack(v); +gap> IsPlistVectorRep(vp); +true +gap> MultVectorLeft(vp, Z(5)^3); +gap> Unpack(vp); [ Z(5)^0, Z(5), Z(5)^3, Z(5)^3, 0*Z(5), Z(5)^2 ] -gap> MultVector(v, -1); -gap> Unpack(v); -[ Z(5)^2, Z(5)^3, Z(5), Z(5), 0*Z(5), Z(5)^0 ] -gap> MultVector(v, Z(5)^3, 3, 4); -gap> Unpack(v); -[ Z(5)^2, Z(5)^3, Z(5)^0, Z(5)^0, 0*Z(5), Z(5)^0 ] - -# Integers -gap> n := NewVector( IsPlistVectorRep, Integers, [1,2,0] ); +gap> vp := NewVector( IsPlistVectorRep, GF(5), +> [ Z(5)^1, Z(5)^2, Z(5)^0, Z(5)^4, 0*Z(5), Z(5)^3 ] );; +gap> MultVectorRight(vp, Z(5)^3); +gap> Unpack(vp); +[ Z(5)^0, Z(5), Z(5)^3, Z(5)^3, 0*Z(5), Z(5)^2 ] +gap> vp := NewVector( IsPlistVectorRep, GF(5), +> [ Z(5)^1, Z(5)^2, Z(5)^0, Z(5)^4, 0*Z(5), Z(5)^3 ] );; +gap> MultVectorLeft(vp, Z(5)^3, 3, 4); +gap> Unpack(vp); +[ Z(5), Z(5)^2, Z(5)^3, Z(5)^3, 0*Z(5), Z(5)^3 ] +gap> vp := NewVector( IsPlistVectorRep, GF(5), +> [ Z(5)^1, Z(5)^2, Z(5)^0, Z(5)^4, 0*Z(5), Z(5)^3 ] );; +gap> MultVectorRight(vp, Z(5)^3, 3, 4); +gap> Unpack(vp); +[ Z(5), Z(5)^2, Z(5)^3, Z(5)^3, 0*Z(5), Z(5)^3 ] +gap> n := NewVector( IsPlistVectorRep, Integers, [ 1, 2, 0 ] ); gap> IsIntVector(n); true -gap> MultVector(n, 2); +gap> MultVectorRight(n, 2); gap> Unpack(n); [ 2, 4, 0 ] +gap> MultVectorLeft(n, -1); +gap> Unpack(n); +[ -2, -4, 0 ] # Quaternions: multiplication from left and right gap> Q := QuaternionAlgebra( Rationals ); @@ -42,4 +99,6 @@ gap> Unpack(q); gap> MultVectorLeft(q, Q.2, 3, 4); gap> Unpack(q); [ (-1)*e, 0*e, i, j ] + +# gap> STOP_TEST("MultVector.tst"); From 4c3b809c2a16e4a06f4104e18029d25c822a4f95 Mon Sep 17 00:00:00 2001 From: Jerry James Date: Wed, 25 Mar 2026 17:43:40 -0600 Subject: [PATCH 121/234] kernel: avoid undefined behavior in be32decode (#6284) --- src/sha256.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sha256.c b/src/sha256.c index 25d1a796a3..65786f1bc3 100644 --- a/src/sha256.c +++ b/src/sha256.c @@ -95,8 +95,8 @@ static void be32decode(UInt4 * dst, const UInt1 * src, UInt len) { UInt i; for (i = 0; i < (len >> 2); i++) { - dst[i] = (src[i * 4] << 24) | (src[i * 4 + 1] << 16) | - (src[i * 4 + 2] << 8) | (src[i * 4 + 3]); + dst[i] = (((UInt4)src[i * 4]) << 24) | (((UInt4)src[i * 4 + 1]) << 16) | + (((UInt4)src[i * 4 + 2]) << 8) | ((UInt4)src[i * 4 + 3]); } } From 31ab95dbeb8cc7f4a1eef03fe7fb93e77e72112b Mon Sep 17 00:00:00 2001 From: Max Horn Date: Thu, 26 Mar 2026 12:15:51 +0100 Subject: [PATCH 122/234] meataxe: simplify some code (#6285) --- lib/meataxe.gi | 44 +++++++++++++++----------------------------- 1 file changed, 15 insertions(+), 29 deletions(-) diff --git a/lib/meataxe.gi b/lib/meataxe.gi index 5b4b65646e..df7f2acf10 100644 --- a/lib/meataxe.gi +++ b/lib/meataxe.gi @@ -1636,7 +1636,7 @@ end; SMTX.AbsoluteIrreducibilityTest:=function(module) local dim, ndim, gcd, div, e, ct, F, q, ok, M, v, M0, v0, C, C0, centmat, one, zero, - pow, matrices, newmatrices, looking, + pow, matrices, newmatrices, basisN, basisB, basisBN, P, Pinv, i, offset, nblocks; if not SMTX.IsMTXModule(module) then @@ -1777,15 +1777,7 @@ local dim, ndim, gcd, div, e, ct, F, q, ok, centmat := ImmutableMatrix(F, centmat); Info(InfoMeatAxe,2,"Checking that it centralises the generators."); # Check centralizing. - looking:=true; - i:=1; - while looking and i <= Length(newmatrices) do - if newmatrices[i] * centmat <> centmat * newmatrices[i] then - looking:=false; - fi; - i:=i + 1; - od; - if looking then + if ForAll(newmatrices, x -> x * centmat = centmat * x) then Info(InfoMeatAxe,2,"It did!"); SMTX.SetDegreeFieldExt(module, e); SMTX.SetCentMat(module, Pinv * centmat * P); # get the base right @@ -1833,7 +1825,7 @@ end; ## over the larger field. SMTX.FieldGenCentMat:=function(module) local e, F, R, q, qe, minpol, pp, - centmat, newcentmat, genpol, looking, + centmat, newcentmat, genpol, okd; if SMTX.FGCentMat(module)=fail then @@ -1870,20 +1862,17 @@ SMTX.FieldGenCentMat:=function(module) genpol:=Indeterminate(F); - looking:=true; - while looking do + while true do if genpol <> minpol then - okd:=FFPOrderKnownDividend(R, genpol, minpol, pp); - if okd[1] * Order(One(F)*okd[2]) = qe then - looking:=false; - fi; - fi; - if looking then - repeat - genpol:=RandomPol(F, e,1); - until DegreeOfUnivariateLaurentPolynomial(genpol) > 0; - genpol:=StandardAssociate(R, genpol); + okd:=FFPOrderKnownDividend(R, genpol, minpol, pp); + if okd[1] * Order(One(F)*okd[2]) = qe then + break; + fi; fi; + repeat + genpol:=RandomPol(F, e, 1); + until DegreeOfUnivariateLaurentPolynomial(genpol) > 0; + genpol:=StandardAssociate(R, genpol); od; # Finally recalculate centmat and its minimal polynomial. centmat:=SMTX.CentMat(module); @@ -2375,7 +2364,7 @@ SMTX.Homomorphisms:= function(module1, module2) local F, mats1, mats2, dim1, dim2, m1bas, imbases, el, genpair, fac, mat, N, imlen, subdim, leadpos, vec, imvecs, numrels, rels, leadposrels, newrels, bno, genno, colno, rowno, - zero, looking, ans, i, j, k; + zero, ans, i, j, k; if not SMTX.IsMTXModule(module1) then return Error("First argument is not a module."); @@ -2533,11 +2522,8 @@ SMTX.Homomorphisms:= function(module1, module2) Info(InfoMeatAxe,2,"Done. Reducing spun up basis."); for colno in [1..dim1] do - rowno:=colno; - looking:=true; - while rowno <= dim1 and looking do + for rowno in [colno..dim1] do if m1bas[rowno,colno] <> zero then - looking:=false; if rowno <> colno then # swap rows rowno and colno SwapMatrixRows(m1bas, rowno, colno); @@ -2556,8 +2542,8 @@ SMTX.Homomorphisms:= function(module1, module2) od; fi; od; + break; fi; - rowno:=rowno + 1; od; od; From 01a5765a089cf5f67ff7908f6d0134b550cb438a Mon Sep 17 00:00:00 2001 From: Pavol <80066546+OldAnchovyTopping@users.noreply.github.com> Date: Thu, 26 Mar 2026 15:41:14 +0000 Subject: [PATCH 123/234] Add `AddMatrix`, `MultMatrix` for in-place modification of matrices (#5980) AI assistance: Codex was used to implement some of the code changes, expand the MatrixObj test coverage, and update the documentation. Co-authored-by: Max Horn Co-authored-by: Codex --- doc/ref/matobj.xml | 3 +- hpcgap/lib/vec8bit.gi | 12 +- lib/matobj.gi | 149 +++++++++++++++++- lib/matobj2.gd | 82 ++++++++++ lib/vec8bit.gi | 12 +- .../MatrixObj/ElementaryMatrices.tst | 56 +++++++ tst/testinstall/MatrixObj/testmatobj.g | 61 +++++++ 7 files changed, 361 insertions(+), 14 deletions(-) diff --git a/doc/ref/matobj.xml b/doc/ref/matobj.xml index 47228c8daa..bc2494903b 100644 --- a/doc/ref/matobj.xml +++ b/doc/ref/matobj.xml @@ -221,6 +221,8 @@ All rows of a matrix must have the same length and the same base domain. <#Include Label="AddMatrixColumnsLeft"> <#Include Label="SwapMatrixRows"> <#Include Label="SwapMatrixColumns"> +<#Include Label="AddMatrix"> +<#Include Label="MultMatrix"> @@ -376,4 +378,3 @@ described in this chapter is supported. - diff --git a/hpcgap/lib/vec8bit.gi b/hpcgap/lib/vec8bit.gi index 821454b345..c867e31592 100644 --- a/hpcgap/lib/vec8bit.gi +++ b/hpcgap/lib/vec8bit.gi @@ -463,7 +463,7 @@ end ); #M = ## -InstallMethod( \=, "for 2 8 bit vectors", +InstallMethod( \=, "for two 8 bit vectors", IsIdenticalObj, [IsRowVector and Is8BitVectorRep, IsRowVector and Is8BitVectorRep], 0, @@ -476,7 +476,7 @@ InstallMethod( \=, "for 2 8 bit vectors", ## Usual lexicographic ordering ## -InstallMethod( \<, "for 2 8 bit vectors", +InstallMethod( \<, "for two 8 bit vectors", IsIdenticalObj, [IsRowVector and Is8BitVectorRep, IsRowVector and Is8BitVectorRep], 0, @@ -488,7 +488,7 @@ InstallMethod( \<, "for 2 8 bit vectors", ## ## scalar product #' -InstallMethod( \*, "for 2 8 bit vectors", +InstallMethod( \*, "for two 8 bit vectors", IsIdenticalObj, [IsRingElementList and Is8BitVectorRep, IsRingElementList and Is8BitVectorRep], 0, @@ -525,7 +525,7 @@ end); ## add * to in place ## -InstallOtherMethod( AddRowVector, "for 2 8 bit vectors and a field element and from and to", +InstallOtherMethod( AddRowVector, "for two 8 bit vectors and a field element and from and to", IsCollsCollsElmsXX, [ IsRowVector and Is8BitVectorRep, IsRowVector and Is8BitVectorRep, IsFFE and IsInternalRep, IsPosInt, IsPosInt ], 0, @@ -538,7 +538,7 @@ InstallOtherMethod( AddRowVector, "for 2 8 bit vectors and a field element and f ## add * to in place ## -InstallOtherMethod( AddRowVector, "for 2 8 bit vectors and a field element", +InstallOtherMethod( AddRowVector, "for two 8 bit vectors and a field element", IsCollsCollsElms, [ IsRowVector and Is8BitVectorRep, IsRowVector and Is8BitVectorRep, IsFFE and IsInternalRep ], 0, @@ -551,7 +551,7 @@ InstallOtherMethod( AddRowVector, "for 2 8 bit vectors and a field element", ## add to in place ## -InstallOtherMethod( AddRowVector, "for 2 8 bit vectors", +InstallOtherMethod( AddRowVector, "for two 8 bit vectors", IsIdenticalObj, [ IsRowVector and Is8BitVectorRep, IsRowVector and Is8BitVectorRep], 0, ADD_ROWVECTOR_VEC8BITS_2); diff --git a/lib/matobj.gi b/lib/matobj.gi index cdde9b9512..5e443e75d6 100644 --- a/lib/matobj.gi +++ b/lib/matobj.gi @@ -1897,11 +1897,158 @@ InstallMethod( SwapMatrixColumns, "for a mutable matrix object, and two column n end ); +############################################################################# +## +#M AddMatrix( , ) +## + +InstallMethod( AddMatrix, "for a mutable matrix object and a matrix object", + [ IsMatrixOrMatrixObj and IsMutable, IsMatrixOrMatrixObj ], + function( dstmat, srcmat ) + local i, j; + if DimensionsMat(dstmat) <> DimensionsMat(srcmat) then + Error("AddMatrix: matrices must have the same dimensions"); + fi; + for i in [1..NrRows(dstmat)] do + for j in [1..NrCols(dstmat)] do + dstmat[i,j] := dstmat[i,j] + srcmat[i,j]; + od; + od; + end ); + +InstallEarlyMethod( AddMatrix, + function( dstmat, srcmat ) + local i; + if IsPlistRep(dstmat) and IsPlistRep(srcmat) then + if DimensionsMat(dstmat) <> DimensionsMat(srcmat) then + Error("AddMatrix: matrices must have the same dimensions"); + fi; + for i in [1..NrRows(dstmat)] do + AddRowVector(dstmat[i], srcmat[i]); + od; + else + TryNextMethod(); + fi; + end ); + +InstallMethod( AddMatrix, "for a mutable 8bit matrix and an 8bit matrix", + [ Is8BitMatrixRep and IsMutable, Is8BitMatrixRep ], + function( dstmat, srcmat ) + local i; + if DimensionsMat(dstmat) <> DimensionsMat(srcmat) then + Error("AddMatrix: matrices must have the same dimensions"); + fi; + for i in [1..NrRows(dstmat)] do + ADD_COEFFS_VEC8BIT_2(dstmat[i], srcmat[i]); + od; + end ); + +############################################################################# +## +#M AddMatrix( , , ) +## + +InstallMethod( AddMatrix, "for a mutable matrix object, a matrix object, and a scalar", + [ IsMatrixOrMatrixObj and IsMutable, IsMatrixOrMatrixObj, IsScalar ], + function( dstmat, srcmat, scalar ) + local i, j; + if DimensionsMat(dstmat) <> DimensionsMat(srcmat) then + Error("AddMatrix: matrices must have the same dimensions"); + fi; + for i in [1..NrRows(dstmat)] do + for j in [1..NrCols(dstmat)] do + dstmat[i,j] := dstmat[i,j] + srcmat[i,j] * scalar; + od; + od; + end ); + +InstallEarlyMethod( AddMatrix, + function( dstmat, srcmat, scalar ) + local i; + if IsPlistRep(dstmat) and IsPlistRep(srcmat) then + if DimensionsMat(dstmat) <> DimensionsMat(srcmat) then + Error("AddMatrix: matrices must have the same dimensions"); + fi; + for i in [1..NrRows(dstmat)] do + AddRowVector(dstmat[i], srcmat[i], scalar); + od; + else + TryNextMethod(); + fi; + end ); + +InstallMethod( AddMatrix, "for a mutable 8bit matrix, an 8bit matrix, and a scalar", + [ Is8BitMatrixRep and IsMutable, Is8BitMatrixRep, IsFFE ], + function( dstmat, srcmat, scalar ) + local i; + if DimensionsMat(dstmat) <> DimensionsMat(srcmat) then + Error("AddMatrix: matrices must have the same dimensions"); + fi; + for i in [1..NrRows(dstmat)] do + ADD_COEFFS_VEC8BIT_3(dstmat[i], srcmat[i], scalar); + od; + end ); + +############################################################################# +## +#M MultMatrixRight( , ) +## + +InstallMethod( MultMatrixRight, "for a mutable matrix object and a scalar", + [ IsMatrixOrMatrixObj and IsMutable, IsScalar ], + function( mat, scalar ) + local i, j; + for i in [1..NrRows(mat)] do + for j in [1..NrCols(mat)] do + mat[i,j] := mat[i,j] * scalar; + od; + od; + end ); + +InstallEarlyMethod( MultMatrixRight, + function( mat, scalar ) + local i; + if IsPlistRep(mat) and IsScalar(scalar) then + for i in [1..NrRows(mat)] do + MultVectorRight(mat[i], scalar); + od; + else + TryNextMethod(); + fi; + end ); + +############################################################################# +## +#M MultMatrixLeft( , ) +## + +InstallMethod( MultMatrixLeft, "for a mutable matrix object and a scalar", + [ IsMatrixOrMatrixObj and IsMutable, IsScalar ], + function( mat, scalar ) + local i, j; + for i in [1..NrRows(mat)] do + for j in [1..NrCols(mat)] do + mat[i,j] := scalar * mat[i,j]; + od; + od; + end ); + +InstallEarlyMethod( MultMatrixLeft, + function( mat, scalar ) + local i; + if IsPlistRep(mat) and IsScalar(scalar) then + for i in [1..NrRows(mat)] do + MultVectorLeft(mat[i], scalar); + od; + else + TryNextMethod(); + fi; + end ); ############################################################################ ## Fallback method for DeterminantMatrix + InstallMethod(DeterminantMatrix, ["IsMatrixObj"], function( mat ) return DeterminantMat( Unpack( mat ) ); end); - diff --git a/lib/matobj2.gd b/lib/matobj2.gd index fc73f88118..f03a76119a 100644 --- a/lib/matobj2.gd +++ b/lib/matobj2.gd @@ -2052,3 +2052,85 @@ DeclareOperationKernel( "SwapMatrixRows", [ IsMatrixOrMatrixObj and IsMutable, I ## <#/GAPDoc> ## DeclareOperationKernel( "SwapMatrixColumns", [ IsMatrixOrMatrixObj and IsMutable, IsInt, IsInt ], SWAP_MAT_COLS ); + +############################################################################ +## +## <#GAPDoc Label="AddMatrix"> +## +## +## +## nothing +## +## +## Computes the calculation M + c \cdot N in-place, storing the result in M. +## If the optional argument c is omitted, then N is added directly. +## If both of the matrices are lists-of-lists, then the operation is delegated +## row by row to . +## mat1 := [ [ 1, 2 ], [ 3, 4 ] ]; +## [ [ 1, 2 ], [ 3, 4 ] ] +## gap> mat2 := [ [ 1, 0 ], [ 3, -1 ] ]; +## [ [ 1, 0 ], [ 3, -1 ] ] +## gap> AddMatrix( mat1, mat2, 2 ); +## gap> mat1; +## [ [ 3, 2 ], [ 9, 2 ] ] +## gap> mat2; +## [ [ 1, 0 ], [ 3, -1 ] ] +## gap> AddMatrix( mat1, [ [ 1, 0], [ 3, -1] ] ); +## gap> mat1; +## [ [ 4, 2 ], [ 12, 1 ] ] +## ]]> +## +## +## <#/GAPDoc> +## +DeclareOperation( "AddMatrix", [ IsMatrixOrMatrixObj and IsMutable, IsMatrixOrMatrixObj ] ); +DeclareOperation( "AddMatrix", [ IsMatrixOrMatrixObj and IsMutable, IsMatrixOrMatrixObj, IsScalar ] ); + +############################################################################ +## +## <#GAPDoc Label="MultMatrix"> +## +## +## +## +## +## nothing +## +## +## These functions multiply the entries of mat by c in-place. +## performs the operation mat*c, +## whereas performs the operation c*mat +## and is an alias for . +## In all of these, if the matrix mat is a lists-of-lists, then the +## operation is delegated row by row to and +## . +## mat1 := [ [ 1, 2 ], [ 3, 4 ] ]; +## [ [ 1, 2 ], [ 3, 4 ] ] +## gap> MultMatrixRight(mat1, -2); +## gap> mat1; +## [ [ -2, -4 ], [ -6, -8 ] ] +## gap> MultMatrix(mat1, -2); # Note that this is the same as calling MultMatrixLeft(mat1, -2) +## gap> mat1; +## [ [ 4, 8 ], [ 12, 16 ] ] +## gap> A := FreeAssociativeAlgebra(Rationals, 2); +## +## gap> mat2 := [ [ A.1, A.2 ], [ A.1 * 2, A.2 * 3 ] ]; +## [ [ (1)*x.1, (1)*x.2 ], [ (2)*x.1, (3)*x.2 ] ] +## gap> MultMatrixLeft(mat2, A.1); +## gap> mat2; +## [ [ (1)*x.1^2, (1)*x.1*x.2 ], [ (2)*x.1^2, (3)*x.1*x.2 ] ] +## gap> mat2 := [ [ A.1, A.2 ], [ A.1 * 2, A.2 * 3 ] ]; +## [ [ (1)*x.1, (1)*x.2 ], [ (2)*x.1, (3)*x.2 ] ] +## gap> MultMatrixRight(mat2, A.1); +## gap> mat2; +## [ [ (1)*x.1^2, (1)*x.2*x.1 ], [ (2)*x.1^2, (3)*x.2*x.1 ] ] +## ]]> +## +## +## <#/GAPDoc> +## +DeclareOperation( "MultMatrixRight", [ IsMatrixOrMatrixObj and IsMutable, IsScalar ] ); +DeclareOperation( "MultMatrixLeft", [ IsMatrixOrMatrixObj and IsMutable, IsScalar ] ); +DeclareSynonym( "MultMatrix", MultMatrixLeft ); diff --git a/lib/vec8bit.gi b/lib/vec8bit.gi index 07ecbe1a08..1ecab5e48e 100644 --- a/lib/vec8bit.gi +++ b/lib/vec8bit.gi @@ -452,7 +452,7 @@ end ); #M = ## -InstallMethod( \=, "for 2 8 bit vectors", +InstallMethod( \=, "for two 8 bit vectors", IsIdenticalObj, [IsRowVector and Is8BitVectorRep, IsRowVector and Is8BitVectorRep], 0, @@ -465,7 +465,7 @@ InstallMethod( \=, "for 2 8 bit vectors", ## Usual lexicographic ordering ## -InstallMethod( \<, "for 2 8 bit vectors", +InstallMethod( \<, "for two 8 bit vectors", IsIdenticalObj, [IsRowVector and Is8BitVectorRep, IsRowVector and Is8BitVectorRep], 0, @@ -477,7 +477,7 @@ InstallMethod( \<, "for 2 8 bit vectors", ## ## scalar product #' -InstallMethod( \*, "for 2 8 bit vectors", +InstallMethod( \*, "for two 8 bit vectors", IsIdenticalObj, [IsRingElementList and Is8BitVectorRep, IsRingElementList and Is8BitVectorRep], 0, @@ -514,7 +514,7 @@ end); ## add * to in place ## -InstallOtherMethod( AddRowVector, "for 2 8 bit vectors and a field element and from and to", +InstallOtherMethod( AddRowVector, "for two 8 bit vectors and a field element and from and to", IsCollsCollsElmsXX, [ IsRowVector and Is8BitVectorRep, IsRowVector and Is8BitVectorRep, IsFFE and IsInternalRep, IsPosInt, IsPosInt ], 0, @@ -527,7 +527,7 @@ InstallOtherMethod( AddRowVector, "for 2 8 bit vectors and a field element and f ## add * to in place ## -InstallOtherMethod( AddRowVector, "for 2 8 bit vectors and a field element", +InstallOtherMethod( AddRowVector, "for two 8 bit vectors and a field element", IsCollsCollsElms, [ IsRowVector and Is8BitVectorRep, IsRowVector and Is8BitVectorRep, IsFFE and IsInternalRep ], 0, @@ -540,7 +540,7 @@ InstallOtherMethod( AddRowVector, "for 2 8 bit vectors and a field element", ## add to in place ## -InstallOtherMethod( AddRowVector, "for 2 8 bit vectors", +InstallOtherMethod( AddRowVector, "for two 8 bit vectors", IsIdenticalObj, [ IsRowVector and Is8BitVectorRep, IsRowVector and Is8BitVectorRep], 0, ADD_ROWVECTOR_VEC8BITS_2); diff --git a/tst/testinstall/MatrixObj/ElementaryMatrices.tst b/tst/testinstall/MatrixObj/ElementaryMatrices.tst index 3567349999..f02e0f62ef 100644 --- a/tst/testinstall/MatrixObj/ElementaryMatrices.tst +++ b/tst/testinstall/MatrixObj/ElementaryMatrices.tst @@ -6,34 +6,66 @@ gap> ReadGapRoot("tst/testinstall/MatrixObj/testmatobj.g"); # gap> TestElementaryTransforms( [[2,4,5],[7,11,-4],[-3,20,0]], -1 ); gap> TestElementaryTransforms( Matrix( [[2,4,5],[7,11,-4],[-3,20,0]]), -1 ); +gap> TestWholeMatrixTransforms( [[2,4,5],[7,11,-4],[-3,20,0]], -1 ); +gap> TestWholeMatrixTransforms( Matrix( [[2,4,5],[7,11,-4],[-3,20,0]]), -1 ); # gap> F := GF(2);; gap> mat := RandomInvertibleMat(4, F);; # list of compressed vectors gap> TestElementaryTransforms( mat, PrimitiveRoot(F) ); +gap> TestWholeMatrixTransforms( mat, PrimitiveRoot(F) ); gap> ConvertToMatrixRep(mat);; # proper matrix obj gap> TestElementaryTransforms( mat, PrimitiveRoot(F) ); +gap> TestWholeMatrixTransforms( mat, PrimitiveRoot(F) ); # gap> F := GF(3);; gap> mat := RandomInvertibleMat(4, F);; # list of compressed vectors gap> TestElementaryTransforms( mat, PrimitiveRoot(F) ); +gap> TestWholeMatrixTransforms( mat, PrimitiveRoot(F) ); gap> ConvertToMatrixRep(mat);; # proper matrix obj gap> TestElementaryTransforms( mat, PrimitiveRoot(F) ); +gap> TestWholeMatrixTransforms( mat, PrimitiveRoot(F) ); # gap> F := GF(4);; gap> mat := RandomInvertibleMat(4, F);; # list of compressed vectors gap> TestElementaryTransforms( mat, PrimitiveRoot(F) ); +gap> TestWholeMatrixTransforms( mat, PrimitiveRoot(F) ); gap> ConvertToMatrixRep(mat);; # proper matrix obj gap> TestElementaryTransforms( mat, PrimitiveRoot(F) ); +gap> TestWholeMatrixTransforms( mat, PrimitiveRoot(F) ); # gap> F := GF(5);; gap> mat := RandomInvertibleMat(4, F);; # list of compressed vectors gap> TestElementaryTransforms( mat, PrimitiveRoot(F) ); +gap> TestWholeMatrixTransforms( mat, PrimitiveRoot(F) ); gap> ConvertToMatrixRep(mat);; # proper matrix obj gap> TestElementaryTransforms( mat, PrimitiveRoot(F) ); +gap> TestWholeMatrixTransforms( mat, PrimitiveRoot(F) ); + +# +gap> F := GF(3);; +gap> mat := [ [ Z(3)^0, 0*Z(3), Z(3) ], +> [ Z(3), Z(3)^0, 0*Z(3) ], +> [ 0*Z(3), Z(3), Z(3)^0 ] ];; +gap> ConvertToMatrixRep(mat, F);; +gap> Is8BitMatrixRep(mat); +true +gap> TestWholeMatrixTransforms( mat, PrimitiveRoot(F) ); +gap> ConvertToMatrixRep(mat);; +gap> Is8BitMatrixRep(mat); +true +gap> TestWholeMatrixTransforms( mat, PrimitiveRoot(F) ); + +# +gap> mat := NewMatrix(IsPlistMatrixRep, Integers, 3, +> [ [ 2, 4, 5 ], [ 7, 11, -4 ], [ -3, 20, 0 ] ] );; +gap> IsPlistMatrixRep(mat); +true +gap> TestElementaryTransforms( mat, -1 ); +gap> TestWholeMatrixTransforms( mat, -1 ); ########## # @@ -119,4 +151,28 @@ gap> mat := Matrix( [[2,4,5],[7,11,-4],[-3,20,0]]);; gap> AddMatrixColumnsLeft(mat,1,3,-3); gap> mat= Matrix( [ [-13,4,5], [19,11,-4], [-3,20,0]]); true + +# +gap> mat := Matrix( [ [ 1, 2 ], [ 3, 4 ] ] );; +gap> AddMatrix( mat, [ [ 1, 0 ], [ 3, -1 ] ], 2 ); +gap> mat = Matrix( [ [ 3, 2 ], [ 9, 2 ] ] ); +true +gap> AddMatrix( mat, [ [ 1, 0 ], [ 3, -1 ] ] ); +gap> mat = Matrix( [ [ 4, 2 ], [ 12, 1 ] ] ); +true + +# +gap> A := FreeAssociativeAlgebraWithOne(Rationals, 2);; +gap> mat := [ [ A.1, A.2 ], [ A.1 * 2, A.2 * 3 ] ];; +gap> MultMatrixLeft(mat, A.1); +gap> mat; +[ [ (1)*x.1^2, (1)*x.1*x.2 ], [ (2)*x.1^2, (3)*x.1*x.2 ] ] +gap> mat := [ [ A.1, A.2 ], [ A.1 * 2, A.2 * 3 ] ];; +gap> MultMatrixRight(mat, A.1); +gap> mat; +[ [ (1)*x.1^2, (1)*x.2*x.1 ], [ (2)*x.1^2, (3)*x.2*x.1 ] ] +gap> mat := [ [ 1, 2 ], [ 3, 4 ] ];; +gap> MultMatrix(mat, -2); +gap> mat; +[ [ -2, -4 ], [ -6, -8 ] ] gap> STOP_TEST("ElementaryMatrices.tst"); diff --git a/tst/testinstall/MatrixObj/testmatobj.g b/tst/testinstall/MatrixObj/testmatobj.g index 8ba65a543d..adc0f5c702 100644 --- a/tst/testinstall/MatrixObj/testmatobj.g +++ b/tst/testinstall/MatrixObj/testmatobj.g @@ -190,3 +190,64 @@ TestElementaryTransforms := function(mat, scalar) od; od; end; + +TestWholeMatrixTransforms := function(mat, scalar) + local i, j, src, srcbefore, copy, srccopy, basedomain, same_entries; + Assert(0, NrRows(mat) >= 1); + Assert(0, NrCols(mat) >= 1); + + copy := []; + src := []; + for i in [1..NrRows(mat)] do + copy[i] := []; + src[i] := []; + for j in [1..NrCols(mat)] do + copy[i,j] := mat[i,j]; + src[i,j] := mat[(i mod NrRows(mat)) + 1, (j mod NrCols(mat)) + 1]; + od; + od; + basedomain := BaseDomain(mat); + if IsPlistMatrixRep(mat) then + src := NewMatrix(IsPlistMatrixRep, basedomain, NrCols(mat), src); + elif Is8BitMatrixRep(mat) then + ConvertToMatrixRep(src, basedomain); + fi; + srcbefore := StructuralCopy(src); + srccopy := StructuralCopy(src); + + # Compare entrywise because these tests mix plain list snapshots with + # matrix objects in specialized representations. + same_entries := function(a, b) + local i, j; + for i in [1..NrRows(a)] do + for j in [1..NrCols(a)] do + if a[i,j] <> b[i,j] then + return false; + fi; + od; + od; + return true; + end; + + AddMatrix(mat, src); + AddMatrix(copy, srccopy); + if not same_entries(mat, copy) then Error("AddMatrix(_,_) failure"); fi; + if not same_entries(src, srcbefore) then Error("AddMatrix(_,_) source modified"); fi; + + AddMatrix(mat, src, scalar); + AddMatrix(copy, srccopy, scalar); + if not same_entries(mat, copy) then Error("AddMatrix(_,_,", scalar, ") failure"); fi; + if not same_entries(src, srcbefore) then Error("AddMatrix(_,_,scalar) source modified"); fi; + + MultMatrixLeft(mat, scalar); + MultMatrixLeft(copy, scalar); + if not same_entries(mat, copy) then Error("MultMatrixLeft(", scalar, ") failure"); fi; + + MultMatrixRight(mat, scalar); + MultMatrixRight(copy, scalar); + if not same_entries(mat, copy) then Error("MultMatrixRight(", scalar, ") failure"); fi; + + MultMatrix(mat, scalar); + MultMatrix(copy, scalar); + if not same_entries(mat, copy) then Error("MultMatrix(", scalar, ") failure"); fi; +end; From 0f1cc6f75975d5d93698e9d23501a190f118f06c Mon Sep 17 00:00:00 2001 From: Max Horn Date: Fri, 27 Mar 2026 18:05:38 +0100 Subject: [PATCH 124/234] Replace many redundant uses of IsContainedInSpan (#6287) Instead use the return value by CloseMutableBasis (which was not always there but added in 2019, which explains why so much code did not make use of it). This essentially avoids doing the same computation twice, and can have a quite noticeable performance benefit in some cases. --- lib/algebra.gi | 12 ++++-------- lib/alghom.gi | 21 +++++++-------------- lib/alglie.gi | 30 +++++++++--------------------- lib/algliess.gi | 4 +--- lib/field.gi | 5 ++--- lib/lierep.gi | 9 +++------ lib/vspchom.gi | 3 +-- 7 files changed, 27 insertions(+), 57 deletions(-) diff --git a/lib/algebra.gi b/lib/algebra.gi index b0a4a29767..df6d32f75f 100644 --- a/lib/algebra.gi +++ b/lib/algebra.gi @@ -3517,9 +3517,8 @@ InstallMethod( CentralIdempotentsOfAlgebra, sp:= MutableBasis( F, vv ); x:= ShallowCopy( e ); - while not IsContainedInSpan( sp, x ) do + while CloseMutableBasis( sp, x ) do Add( vv, x ); - CloseMutableBasis( sp, x ); x:= x*e; od; sp:= UnderlyingLeftModule( ImmutableBasis( sp ) ); @@ -3567,9 +3566,8 @@ InstallMethod( CentralIdempotentsOfAlgebra, # We calculate the minimum polynomial of `e'. x:= ShallowCopy( e ); - while not IsContainedInSpan( sp, x ) do + while CloseMutableBasis( sp, x ) do Add( vv, x ); - CloseMutableBasis( sp, x ); x:= x*e; od; sp:= UnderlyingLeftModule( ImmutableBasis( sp ) ); @@ -3775,9 +3773,8 @@ InstallMethod( LeviMalcevDecomposition, for k in BasisVectors( Basis( L ) ) do if Length( bb ) = s then break; - elif not IsContainedInSpan( sp, k ) then + elif CloseMutableBasis( sp, k ) then Add( bb, k ); - CloseMutableBasis( sp, k ); fi; od; @@ -3814,9 +3811,8 @@ InstallMethod( LeviMalcevDecomposition, k:= 1; else x:= BasisVectors( Basis( ser[i] ) )[k]; - if not IsContainedInSpan( sp, x ) then + if CloseMutableBasis( sp, x ) then Add( Rbas, x ); - CloseMutableBasis( sp, x ); fi; k:= k+1; fi; diff --git a/lib/alghom.gi b/lib/alghom.gi index e502f628d2..780d647796 100644 --- a/lib/alghom.gi +++ b/lib/alghom.gi @@ -364,10 +364,9 @@ InstallMethod( AsLeftModuleGeneralMappingByImages, gen:= origgenerators[i]; for j in [ 1 .. Length( generators ) ] do prod:= generators[j] * gen; - if not IsContainedInSpan( MB, prod ) then + if CloseMutableBasis( MB, prod ) then Add( generators, prod ); Add( genimages, genimages[j] * origgenimages[i] ); - CloseMutableBasis( MB, prod ); fi; od; od; @@ -379,10 +378,9 @@ InstallMethod( AsLeftModuleGeneralMappingByImages, gen:= origgenerators[i]; for j in [ 1 .. Length( generators ) ] do prod:= gen * generators[j]; - if not IsContainedInSpan( MB, prod ) then + if CloseMutableBasis( MB, prod ) then Add( generators, prod ); Add( genimages, origgenimages[i] * genimages[j] ); - CloseMutableBasis( MB, prod ); fi; od; od; @@ -884,10 +882,9 @@ InstallMethod( MakePreImagesInfoOperationAlgebraHomomorphism, gen:= origgenimages[i]; for j in [ 1 .. Length( genimages ) ] do prod:= genimages[j] * gen; - if not IsContainedInSpan( MB, prod ) then + if CloseMutableBasis( MB, prod ) then Add( genimages, prod ); Add( preimages, preimages[j] * origgenerators[i] ); - CloseMutableBasis( MB, prod ); fi; od; od; @@ -1059,10 +1056,9 @@ InstallMethod( MakePreImagesInfoOperationAlgebraHomomorphism, gen:= origgenimages[i]; for j in [ 1 .. Length( genimages ) ] do prod:= genimages[j] * gen; - if not IsContainedInSpan( MB, prod ) then + if CloseMutableBasis( MB, prod ) then Add( genimages, prod ); Add( preimages, preimages[j] * origgenerators[i] ); - CloseMutableBasis( MB, prod ); fi; od; od; @@ -1435,9 +1431,8 @@ InstallMethod( NaturalHomomorphismByIdeal, mb:= MutableBasis( F, Ivectors ); compl:= []; for gen in BasisVectors( Basis( A ) ) do - if not IsContainedInSpan( mb, gen ) then + if CloseMutableBasis( mb, gen ) then Add( compl, gen ); - CloseMutableBasis( mb, gen ); fi; od; B:= BasisNC( A, Concatenation( Ivectors, compl ) ); @@ -1671,10 +1666,9 @@ InstallMethod( IsomorphismFpFLMLOR, gen:= Agens[i]; for j in [ 1 .. Length( generators ) ] do prod:= generators[j] * gen; - if not IsContainedInSpan( MB, prod ) then + if CloseMutableBasis( MB, prod ) then Add( generators, prod ); Add( genimages, genimages[j] * Fgens[i] ); - CloseMutableBasis( MB, prod ); fi; od; od; @@ -1686,10 +1680,9 @@ InstallMethod( IsomorphismFpFLMLOR, gen:= Agens[i]; for j in [ 1 .. Length( generators ) ] do prod:= gen * generators[j]; - if not IsContainedInSpan( MB, prod ) then + if CloseMutableBasis( MB, prod ) then Add( generators, prod ); Add( genimages, Fgens[i] * genimages[j] ); - CloseMutableBasis( MB, prod ); fi; od; od; diff --git a/lib/alglie.gi b/lib/alglie.gi index 2f0ba0ed43..361811bc61 100644 --- a/lib/alglie.gi +++ b/lib/alglie.gi @@ -922,10 +922,9 @@ InstallMethod( AdjointBasis, inds:= []; for i in [1..n] do adi:= AdjointMatrix( B, bb[i] ); - if not IsContainedInSpan( adLsp, adi ) then + if CloseMutableBasis( adLsp, adi ) then Add( adL, adi ); Add( inds, i ); - CloseMutableBasis( adLsp, adi ); fi; od; @@ -1859,8 +1858,7 @@ InstallMethod( DirectSumDecomposition, while k<=Length(bas) do if Length(bas)=Dimension(L)-Dimension(H) then break; fi; M:= bas[ k ]*bas[ l ]; - if not IsContainedInSpan( sp, M ) then - CloseMutableBasis( sp, M ); + if CloseMutableBasis( sp, M ) then Add( bas, M ); fi; if l < Length(bas) then l:=l+1; @@ -1910,11 +1908,7 @@ InstallMethod( DirectSumDecomposition, Add( mat, Coefficients( Basis( B[k], b ), x ) ); od; mat:= TransposedMat( mat ); - - if not IsContainedInSpan( sp, mat ) then - CloseMutableBasis( sp, mat ); - fi; - + CloseMutableBasis( sp, mat ); od; res:= BasisVectors( sp ); @@ -2047,9 +2041,8 @@ InstallMethod( DirectSumDecomposition, BasisVectors( Basis( CD ) ), Zero( CD ) ); while Length( B1 ) + Dimension( CD ) <> Dimension( C ) do x:= bvc[k]; - if not IsContainedInSpan( sp, x ) then + if CloseMutableBasis( sp, x ) then Add( B1, x ); - CloseMutableBasis( sp, x ); fi; k:=k+1; od; @@ -2064,9 +2057,8 @@ InstallMethod( DirectSumDecomposition, sp:= MutableBasis( F, b ); while Length( B2 )+Length( B1 ) <> n do x:= bvl[k]; - if not IsContainedInSpan( sp, x ) then + if CloseMutableBasis( sp, x ) then Add( B2, x ); - CloseMutableBasis( sp, x ); fi; k:= k+1; od; @@ -2392,9 +2384,8 @@ InstallMethod( SemiSimpleType, bvl:= BasisVectors( Basis( L ) ); while Length( bas ) < Dimension( L ) do a:= bvl[k]; - if not IsContainedInSpan( sp, a ) then + if CloseMutableBasis( sp, a ) then Add( bas, a ); - CloseMutableBasis( sp, a ); fi; k:= k+1; od; @@ -2585,9 +2576,8 @@ InstallMethod( SemiSimpleType, r:= R[i]; k:= Position( R, -r ); h:= Rvecs[i] * Rvecs[k]; - if not IsContainedInSpan( sp, h ) then + if CloseMutableBasis( sp, h ) then Add( basH, h ); - CloseMutableBasis( sp, h ); Add( basR, r ); fi; i:= i+1; @@ -2975,8 +2965,7 @@ InstallMethod( RootSystem, a:= S[i]; j:= Position( S, -a ); h:= B[i][1]*B[j][1]; - if not IsContainedInSpan( sp, h ) then - CloseMutableBasis( sp, h ); + if CloseMutableBasis( sp, h ) then Add( basR, a ); Add( basH, h ); fi; @@ -4083,8 +4072,7 @@ InstallMethod( PreImagesRepresentativeNC, if c <> [] then imz:= Image( f, z ); - if not IsContainedInSpan( sp, imz ) then - CloseMutableBasis( sp, imz ); + if CloseMutableBasis( sp, imz ) then Add( b1, z ); Add( newlev, z ); Add( newbracks, c ); diff --git a/lib/algliess.gi b/lib/algliess.gi index 5c0bb5e044..1454c664fd 100644 --- a/lib/algliess.gi +++ b/lib/algliess.gi @@ -950,9 +950,7 @@ BindGlobal( "SimpleLieAlgebraTypeH", function( n, F ) od; if not IsZero(cf) then if IsBound( sp ) then - if not IsContainedInSpan( sp, cf ) then - CloseMutableBasis( sp, cf ); - fi; + CloseMutableBasis( sp, cf ); else sp:= MutableBasis( F, [ cf ] ); fi; diff --git a/lib/field.gi b/lib/field.gi index daa0ffb42f..70b282ca83 100644 --- a/lib/field.gi +++ b/lib/field.gi @@ -911,12 +911,11 @@ InstallMethod( MinimalPolynomial, coe:= Coefficients( B, pow ); mat:= [ coe ]; MB:= MutableBasis( F, [ coe ] ); - repeat - CloseMutableBasis( MB, coe ); + while CloseMutableBasis( MB, coe ) do pow:= pow * z; coe:= Coefficients( B, pow ); Add( mat, coe ); - until IsContainedInSpan( MB, coe ); + od; # The coefficients of the minimal polynomial # are given by the linear relation. diff --git a/lib/lierep.gi b/lib/lierep.gi index d5d4e99efe..17db3e8a80 100644 --- a/lib/lierep.gi +++ b/lib/lierep.gi @@ -3915,7 +3915,7 @@ InstallGlobalFunction( ExtendRepresentation, V:= MutableBasis( F, bb ); fi; - if IsContainedInSpan( V, vv ) then + if not CloseMutableBasis( V, vv ) then # We take the next element of 'orb'. @@ -3928,7 +3928,6 @@ InstallGlobalFunction( ExtendRepresentation, c:= c1; Add( orb1, c ); - CloseMutableBasis( V, vv ); fi; @@ -4129,13 +4128,12 @@ InstallGlobalFunction( ExtendRepresentation, for j in [ Last(w)..Length( mats )] do m:= asbas[i]*mats[j]; - if not IsContainedInSpan( sp, m ) then + if CloseMutableBasis( sp, m ) then ready:= false; Add( asbas, m ); w1:= ShallowCopy(w); Add( w1, j ); Add( wds, w1 ); - CloseMutableBasis( sp, m ); fi; od; @@ -4151,10 +4149,9 @@ InstallGlobalFunction( ExtendRepresentation, cf:= List( asbas, m -> m[j][i] ); - if not IsContainedInSpan( sp, cf ) then + if CloseMutableBasis( sp, cf ) then Add( fcts, cf ); Add( cc, [i,j] ); - CloseMutableBasis( sp, cf ); fi; od; od; diff --git a/lib/vspchom.gi b/lib/vspchom.gi index b2148a5fe6..daf0e145bf 100644 --- a/lib/vspchom.gi +++ b/lib/vspchom.gi @@ -1333,9 +1333,8 @@ InstallGlobalFunction( NaturalHomomorphismBySubspaceOntoFullRowSpace, fi; compl:= []; for gen in BasisVectors( Basis( V ) ) do - if not IsContainedInSpan( mb, gen ) then + if CloseMutableBasis( mb, gen ) then Add( compl, gen ); - CloseMutableBasis( mb, gen ); fi; od; B:= BasisNC( V, Concatenation( Wvectors, compl ) ); From 63989877cdb58739ff754c03652b65784c754ce3 Mon Sep 17 00:00:00 2001 From: Jerry James Date: Fri, 27 Mar 2026 11:39:49 -0600 Subject: [PATCH 125/234] Avoid undefined behavior in integer.c (#6286) --- src/integer.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/integer.c b/src/integer.c index 0d9aa508d6..9690ae30f1 100644 --- a/src/integer.c +++ b/src/integer.c @@ -505,7 +505,7 @@ Obj ObjInt_Int( Int i ) } else if (i < 0 ) { gmp = NewBag( T_INTNEG, sizeof(mp_limb_t) ); - i = -i; + i = (Int)(0U - (UInt)i); } else { gmp = NewBag( T_INTPOS, sizeof(mp_limb_t) ); @@ -620,7 +620,7 @@ Int Int_ObjInt(Obj i) if ((!sign && (val > INT32_MAX)) || (sign && (val > (UInt)INT32_MIN))) #endif ErrorMayQuit("Conversion error: integer too large", 0, 0); - return sign ? -(Int)val : (Int)val; + return (Int)(sign ? (0U - val) : val); } UInt UInt_ObjInt(Obj i) From 27778cd7f5712d48f6de9b8d9f5e3ee15beedd07 Mon Sep 17 00:00:00 2001 From: Max Horn Date: Sun, 29 Mar 2026 23:19:16 +0200 Subject: [PATCH 126/234] Remove dev/smtx.tex (#6291) Its content is subsumed by the Meataxe documentation in the ref manual, as well as code comments --- dev/smtx.tex | 250 --------------------------------------------------- 1 file changed, 250 deletions(-) delete mode 100644 dev/smtx.tex diff --git a/dev/smtx.tex b/dev/smtx.tex deleted file mode 100644 index 188d6e2c3f..0000000000 --- a/dev/smtx.tex +++ /dev/null @@ -1,250 +0,0 @@ -\documentclass[12pt]{article} -\usepackage{fullpage} -\usepackage{palatcm} -\def\smtxcmd#1{\subsubsection*{{\tt #1}}} -\title{The Smash MeatAxe for {\sf GAP4}} -\author{Alexander Hulpke} -\date{November 19, 1996} -\def\SMTX{{\sf SMTX}} -\begin{document} -\maketitle -The {\sf Smash}-MeatAxe {\SMTX} is a modification of the MeatAxe in the {\sf -Smash} share library, originally written by Derek Holt and Sarah Rees. It is -adapted to {\sf GAP4} -(where it is intended to become the standard library MeatAxe -unless someone else is willing to write a better one) and works according to -the standardized MeatAxe interface. This document describes the implemented -features as well as some internal routines that resemble features of the -old {\sf Smash}-MeatAxe.\\ -If you feel that routines for certain functions are missing {\em please ask -me before writing them yourself. There might be some internal feature that -allows easy addition already available!}\\ -The routines will only work if the module given is a full row vector space.\\ -The routines from {\SMTX} are selected by setting {\verb+ MTX:=SMTX;+}. - -\section*{Commands} -\smtxcmd{SMTX.SubQuotActions(matrices,sub,dim,subdim,one,type)} -is the working horse of the basic chopping routines: {\tt matrices} is a -list of matrices in dimension {\tt dim}, {\tt sub} is the basis of a -subspace in dimension {\tt subdim}. The respective one is given by {\tt -one}. The integer {\tt type} finally encodes in its binary decomposition -which actions are to be performed: 1 stands for subspace action, 2 for -factor action and 4 for action of the full module -on a subspace adapted basis. The routine -returns a record with components (if applicable): {\tt smatrices}, {\tt -qmatrices} and {\tt nmatrices} giving new matrices for the three possible -actions and {\tt nbasis} an extension of the basis given in {\tt sub} with -respect to which the action is performed.\\ -The routine returns {\tt fail} if {\tt sub} is not a proper subspace.\\ -The basis given in {\tt sub} must be normed!\\ -There are a couple of further routines that basically just call -SubQuotActions to provide several layers of interfacing (and also return -{\tt fail} if {\tt sub} is not a submodule basis): - -\smtxcmd{SMTX.InducedAction(module,sub[,type])} -just calls {\tt SubQuotActions}, but returns module actions instead of -matrices and returns the computed results in a list in sequence -(sub,quot,both,basis) instead of record components. If no {\tt type} is -given, it is assumed to be 7.\\ -The basis given in {\tt sub} must be normed! - -\smtxcmd{SMTX.SubGModuleAction(sub,matrices)} -computes matrices for just the subspace action. SCHEDULED FOR ELIMINATION! - -\smtxcmd{SMTX.InducedActionSubmodule(module,sub)} -creates a new module corresponding to the action of {\tt module} on {\tt sub}. - -\smtxcmd{SMTX.InducedActionSubmoduleNB(module,sub)} -Dito, but the basis in {\tt sub} must be normed. - -\smtxcmd{SMTX.InducedActionFactorModule(module,sub[,compl])} -creates a new module corresponding to the action of {\tt module} on the -factor of {\tt sub}. If {\tt compl} is given, it has to be a basis of a -(vectorspace-)complement of {\tt sub}. The action then will correspond to -{\tt compl}. - -\smtxcmd{SMTX.ProperSubmoduleBasis(module)} -returns the action on a proper submodule and {\tt fail} if none exists. - -\smtxcmd{SMTX.SMCoRaEl(matrices,ngens,newgenlist,dim,F)} -internally used to create a random element -PROBABLY NOT AN END-USER FUNCTION. JUST LISTED AS PARTS OF SMASH MIGHT STILL -CONTAINED DUPLICATE CODE PUT HEREIN. - -\smtxcmd{SMTX.IrreducibilityTest(module)} -Tests for irreducibility and sets a subbasis if reducible. It neither sets -an irreducibility flag, nor tests it. Thus the routine also can simply be -called to obtain a random submodule. - -\smtxcmd{SMTX.IsIrreducible(module)} -if necessary calls the irreducibility test and sets a flag to be returned -otherwise. The existence of the flag can be checked with -{\tt SMTX.HasIsIrreducible} - -\smtxcmd{SMTX.AbsoluteIrreducibilityTest(module)} -Tests for absolute irreducibility and sets splitting field degree. It -neither sets an absolute irreducibility flag, nor tests it. - -\smtxcmd{SMTX.IsAbsolutelyIrreducible(module)} -if necessary calls the absolute irreducibility test and sets a flag to be -returned otherwise. The existence of the flag can be checked with -{\tt SMTX.HasIsAbsolutelyIrreducible} - -\smtxcmd{SMTX.RandomIrreducibleSubGModule(module)} -returns the module action on a random irreducible submodule. - -\smtxcmd{SMTX.GoodElementGModule(module)} -finds an element with minimal possible nullspace dimension if {\tt module} -is known to be irreducible - -\smtxcmd{SMTX.CompleteBasis(module,pbasis)} -extends {\tt pbasis} to a basis of the full space by action of {\tt module}. -It returns whether it succeeded. - -\smtxcmd{SMTX.DegreeFieldExt(module)} -returns the degree of the splitting field extension. - -\smtxcmd{SMTX.DegreeSplittingField(module)} -returns the degree of the splitting field extension over the prime field - -\smtxcmd{SMTX.CollectedFactors(module)} -returns a list giving all irreducible composition factors with their -frequencies. - -\smtxcmd{SMTX.CompositionFactors(module)} -returns a list of composition factors in ascending order - -\smtxcmd{SMTX.Distinguish(cf,nr)} -Let {\tt cf} be the output of {\tt SMTX.CollectedFactors}. This routine -tries to find a group algebra element that has nullity zero on all -composition factors except {\tt nr}. - -\smtxcmd{SMTX.MinimalSubGModule(module,cf,nr)} -returns the basis of a minimal submodule of {\tt module} containing the -indicated composition factor. It assumes {\tt Distinguish} has been called -already - -\smtxcmd{SMTX.Isomorphism(module1,module2)} -returns an isomorphism from module1 to module2 (if any exists) and {\tt -fail} otherwise. It needs that one of the modules is known to be -ireducible. It implicitly assumes that the same group is acting, otherwise -the results are unpredictable. -The isomorphism is given by a matrix $M$, whose rows give the images of the -standard basis vectors of module2 in the standard basis of module1. That is, -conjugation of the generators of {\tt module2} with $M$ yields the -generators of {\tt module1}. - -\smtxcmd{SMTX.IsEquivalent(module1,module2)} -tests two irreducible modules for equivalence. - -\smtxcmd{SMTX.MatrixSum(matrices1,matrices2)} -creates the direct sum of two matrix lists - -\smtxcmd{SMTX.Homomorphisms(module1,module2)} -returns a basis of all homomorphisms from the irreducible module {\tt -module1} to {\tt module2}. - -\smtxcmd{SMTX.SortHomGModule(module1,module2,homs)} -Function to sort the output of {\tt Homomorphisms} - -\smtxcmd{SMTX.MinimalSubGModules(module1,module2[,max])} -returns (at most {\tt max}) bases of submodules of module2 which are -isomorphic to the irreducible {\tt module1}. - -\smtxcmd{SMTX.BasesCompositionSeries(module)} -returns a list of bases of submodules in a composition series in ascending -order - -\smtxcmd{SMTX.BasesMinimalSubmodules(module)} -returns a list of bases of all minimal submodules - -\smtxcmd{SMTX.BasesMaximalSubmodules(module)} -returns a list of bases of all maximal submodules - -\smtxcmd{SMTX.BasesMinimalSupermodules(module,sub)} -returns a list of bases of all minimal supermodules of the submodule given by -the basis {\tt sub}. - -\smtxcmd{SMTX.BasesSubmodules(module)} -returns a list containing a basis for every submodule - -\smtxcmd{SMTX.Setter(string)} -returns a setter function for the component {\tt smashMeataxe.(string)}. - -\smtxcmd{SMTX.Getter(string)} -returns a getter function for the component {\tt smashMeataxe.(string)}. - -\subsection*{Flags} - -The following getter routines access internal flags. For each routine, the -appropriate setters name is prefixed with {\tt Set}. - -\smtxcmd{SMTX.Subbasis} -Basis of a submodule - -\smtxcmd{SMTX.AlgEl} -list {\tt[newgens,coefflist]} giving an algrebra element used for chopping - -\smtxcmd{SMTX.AlgElMat} -matrix thereof - -\smtxcmd{SMTX.AlgElCharPol} -minimal polynomial thereof - -\smtxcmd{SMTX.AlgElCharPolFac} -used factor thereof - -\smtxcmd{SMTX.AlgElNullspaceVec} -nullspace of the matrix evaluated under this factor - -\smtxcmd{SMTX.AlgElNullspaceDimension} -dimension thereof - -\smtxcmd{SMTX.CentMat} - -\smtxcmd{SMTX.CentMatMinPoly} - -\newpage - -\section*{Translation of old names} -\begin{tabular}{ll} -Old&New\\ -\hline -ChopGMod&SMTX.CollectedFactors\\ -CompleteBasis&SMTX.CompleteBasis\\ -Distinguish&SMTX.Distinguish\\ -EnlargeIrreducibleGModule&${}^\dag$\\ -FieldGenCentMat&${}^\dag$\\ -FrobAction&SMTX.FrobeniusAction\\ -GoodElMod&SMTX.GoodElementGModule\\ -HomGMod&SMTX.Homomorphisms\\ -IsAbsIrredGMod&SMTX.AbsoluteIrreducibilityTest${}^\dag$\\ -&SMTX.IsAbsolutelyIrreducible${}^\dag$\\ -IsIrredGMod&SMTX.IrreducibilityTest${}^\dag$\\ -&SMTX.IsIrreducible${}^\dag$\\ -IsomGMod&SMTX.Isomorphism(module1,module2)\\ -MatSum&SMTX.MatrixSum\\ -MinSub&SMTX.MinimalSubGModule\\ -MinSubGMods&SMTX.MinimalSubGModules\\ -OrthogVec&SMTX.OrthogonalVector\\ -QuotGMod&SMTX.InducedActionFactorModule\\ -RandomIrredSubGMod&SMTX.RandomIrreducibleSubGModule\\ -SetAlgElCharPolFacFlag&SMTX.SetAlgElCharPolFac\\ -SetAlgElCharPolFlag&SMTX.SetAlgElCharPol\\ -SetAlgElFlag&SMTX.SetAlgEl\\ -SetAlgElMatFlag&SMTX.SetAlgElMat\\ -SetAlgElNullspaceDimFlag&SMTX.SetAlgElNullspaceDimension\\ -SetAlgElNullspaceVecFlag&SMTX.SetAlgElNullspaceVec\\ -SetCentMatFlag&SMTX.SetCentMat\\ -SetCentMatMinPolyFlag&SMTX.SetCentMatMinPoly\\ -SetSubbasisFlag&SMTX.SetSubbasis\\ -SortHomGMod&SMTX.SortHomGModule\\ -SpinBasis&SMTX.SpinnedBasis\\ -SubGMod&SMTX.InducedActionSubmodule\\ -SubGModAction&SMTX.SubGModuleAction\\ -SubQuotGMod&SMTX.InducedAction\\ -\end{tabular}\\ -All functions return {\tt fail} to indicate impossibility to perform instead -of {\tt false}.\\ -\dag indicates that the performed functions were slightly changed. -\end{document} From 856031e8c4ad97aff6fefb2a170a3bbc229182ed Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 30 Mar 2026 15:03:21 +0200 Subject: [PATCH 127/234] build(deps): bump actions/configure-pages from 5 to 6 (#6297) Bumps [actions/configure-pages](https://github.com/actions/configure-pages) from 5 to 6. - [Release notes](https://github.com/actions/configure-pages/releases) - [Commits](https://github.com/actions/configure-pages/compare/v5...v6) --- updated-dependencies: - dependency-name: actions/configure-pages dependency-version: '6' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/update-gh-pages.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/update-gh-pages.yml b/.github/workflows/update-gh-pages.yml index 9c82e1d1d4..a7e2cb77ae 100644 --- a/.github/workflows/update-gh-pages.yml +++ b/.github/workflows/update-gh-pages.yml @@ -53,7 +53,7 @@ jobs: make bootstrap-pkg-full - name: Setup Pages id: pages - uses: actions/configure-pages@v5 + uses: actions/configure-pages@v6 - name: Build GAP manuals run: | make html # we are only interested in the HTML version From 47ef59d225d51e1844ff71cce24b1f60a85fc1c4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 30 Mar 2026 13:11:15 +0000 Subject: [PATCH 128/234] build(deps): bump actions/deploy-pages from 4 to 5 (#6296) Bumps [actions/deploy-pages](https://github.com/actions/deploy-pages) from 4 to 5. - [Release notes](https://github.com/actions/deploy-pages/releases) - [Commits](https://github.com/actions/deploy-pages/compare/v4...v5) --- updated-dependencies: - dependency-name: actions/deploy-pages dependency-version: '5' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/update-gh-pages.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/update-gh-pages.yml b/.github/workflows/update-gh-pages.yml index a7e2cb77ae..0029894b91 100644 --- a/.github/workflows/update-gh-pages.yml +++ b/.github/workflows/update-gh-pages.yml @@ -81,4 +81,4 @@ jobs: steps: - name: Deploy to GitHub Pages id: deployment - uses: actions/deploy-pages@v4 + uses: actions/deploy-pages@v5 From 8271c1dfb25823e0a19e72990ef143e15d168307 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 30 Mar 2026 16:41:47 +0200 Subject: [PATCH 129/234] build(deps): bump codecov/codecov-action from 5 to 6 (#6295) Bumps [codecov/codecov-action](https://github.com/codecov/codecov-action) from 5 to 6. - [Release notes](https://github.com/codecov/codecov-action/releases) - [Changelog](https://github.com/codecov/codecov-action/blob/main/CHANGELOG.md) - [Commits](https://github.com/codecov/codecov-action/compare/v5...v6) --- updated-dependencies: - dependency-name: codecov/codecov-action dependency-version: '6' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/CI.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index e219840d8b..4c83ada404 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -276,7 +276,7 @@ jobs: - name: "Gather coverage data" run: ${{ matrix.extra }} dev/ci-gather-coverage.sh - name: "Upload coverage data to Codecov" - uses: codecov/codecov-action@v5 + uses: codecov/codecov-action@v6 with: token: ${{ secrets.CODECOV_TOKEN }} From 87c4d5ce440f289b5b2889eb901010e08e882655 Mon Sep 17 00:00:00 2001 From: Max Horn Date: Tue, 31 Mar 2026 15:35:30 +0200 Subject: [PATCH 130/234] meataxe: cache socle and radical (#6294) --- lib/meataxe.gi | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/lib/meataxe.gi b/lib/meataxe.gi index df7f2acf10..b7949c450c 100644 --- a/lib/meataxe.gi +++ b/lib/meataxe.gi @@ -3064,21 +3064,25 @@ end; SMTX.BasisSocle:=function(module) local cf, mat, i; - cf:=SMTX.CollectedFactors(module); - mat:=Concatenation(List(cf,i->SMTX.SpanOfMinimalSubGModules(i[1],module))); - if Length(cf) = 1 then - return ImmutableMatrix(module.field,mat); + if not IsBound(module.Socle) then + cf:=SMTX.CollectedFactors(module); + mat:=Concatenation(List(cf,i->SMTX.SpanOfMinimalSubGModules(i[1],module))); + if Length(cf) > 1 then + TriangulizeMat(mat); + fi; + module.Socle := ImmutableMatrix(module.field,mat); fi; - TriangulizeMat(mat); - mat:=ImmutableMatrix(module.field,mat); - return mat; + return module.Socle; end; SMTX.BasisRadical:=function(module) local d, bs; - d:=SMTX.DualModule(module); - bs:=SMTX.BasisSocle(d); - return SMTX.DualizedBasis(d,bs); + if not IsBound(module.Radical) then + d:=SMTX.DualModule(module); + bs:=SMTX.BasisSocle(d); + module.Radical := SMTX.DualizedBasis(d,bs); + fi; + return module.Radical; end; # the following assignment is for profiling From 877064d9b756f4c5b2207be71657d2e30a4a45fb Mon Sep 17 00:00:00 2001 From: Max Horn Date: Tue, 31 Mar 2026 17:08:57 +0200 Subject: [PATCH 131/234] Add UserHomeShorten as counterpart of UserHomeExpand (#6262) Co-authored-by: Codex --- doc/ref/files.xml | 1 + lib/string.g | 51 +++++++++++++++++++++++++++++++++++++ tst/testinstall/strings.tst | 22 +++++++++++++++- 3 files changed, 73 insertions(+), 1 deletion(-) diff --git a/doc/ref/files.xml b/doc/ref/files.xml index 75cb5f68b3..6860a41cc1 100644 --- a/doc/ref/files.xml +++ b/doc/ref/files.xml @@ -417,6 +417,7 @@ can be used to get information about the error. <#Include Label="UserHomeExpand"> +<#Include Label="UserHomeShorten"> <#Include Label="Reread"> diff --git a/lib/string.g b/lib/string.g index 0700d64d8b..e14de2f3f7 100644 --- a/lib/string.g +++ b/lib/string.g @@ -326,6 +326,8 @@ InstallMethod( String, ## function returns a new string with the leading '~' substituted by ## the user's home directory as stored in GAPInfo.UserHome. ## Otherwise str is returned unchanged. +##

+## This function is the counterpart of . ## ## ## <#/GAPDoc> @@ -339,6 +341,55 @@ BIND_GLOBAL("UserHomeExpand", function(str) fi; end); +############################################################################# +## +#F UserHomeShorten( ) . . . . . . . . . . shorten leading user home +## +## <#GAPDoc Label="UserHomeShorten"> +## +## +## +## If the string str starts with the user's home directory as stored +## in GAPInfo.UserHome then this function returns a new string with +## that prefix replaced by a leading '~' character. +## Otherwise str is returned unchanged. +##

+## This function is the counterpart of . +## +## +## <#/GAPDoc> +## +BIND_GLOBAL("UserHomeShorten", function(str) + local homeLen; + + if not IsString(str) or Length(str) = 0 + or not IsString(GAPInfo.UserHome) or Length(GAPInfo.UserHome) = 0 then + return str; + fi; + + if not IsMatchingSublist(str, GAPInfo.UserHome) then + return str; + fi; + + homeLen := Length(GAPInfo.UserHome); + if Length(str) = homeLen then + return "~"; + fi; + + # Check that the string starts with GAPInfo.UserHome and that this is separate + # from the rest by a `/`. Otherwise if `GAPInfo.UserHome` is for example + # `/home/john` but str is `/home/johnny` we'd end up with `~ny`). + if str[homeLen + 1] <> '/' then + return str; + fi; + + if Length(str) = homeLen + 1 then + return "~"; + fi; + + return Concatenation("~/", str{[homeLen + 2..Length(str)]}); +end); + # the character set definitions might be needed when processing files, thus # they must come earlier. diff --git a/tst/testinstall/strings.tst b/tst/testinstall/strings.tst index c8bff718cb..2a386b8aee 100644 --- a/tst/testinstall/strings.tst +++ b/tst/testinstall/strings.tst @@ -2,7 +2,7 @@ ## ## This file tests output methods (mainly for strings) ## -#@local x, str, len +#@local hadHome, len, savedHome, str, x gap> START_TEST("strings.tst"); # FFE @@ -225,5 +225,25 @@ gap> Length(x); gap> Print(x, "\n"); abcdef +# UserHomeShorten +gap> hadHome := IsBound(GAPInfo.UserHome);; +gap> if hadHome then savedHome := GAPInfo.UserHome; fi;; +gap> GAPInfo.UserHome := "/tmp/gap-home";; +gap> UserHomeShorten("/tmp/gap-home"); +"~" +gap> UserHomeShorten("/tmp/gap-home/.gap"); +"~/.gap" +gap> UserHomeShorten("/tmp/gap-homedir"); +"/tmp/gap-homedir" +gap> UserHomeShorten("/tmp/gap-home-extra"); +"/tmp/gap-home-extra" +gap> UserHomeShorten("~/already"); +"~/already" +gap> UserHomeExpand(UserHomeShorten("/tmp/gap-home/.gap")); +"/tmp/gap-home/.gap" +gap> UserHomeShorten(1234); +1234 +gap> if hadHome then GAPInfo.UserHome := savedHome; else Unbind(GAPInfo.UserHome); fi;; + # gap> STOP_TEST("strings.tst"); From 34ceee862d67afbf89b6769a8b7be2fb0bca5e0c Mon Sep 17 00:00:00 2001 From: Max Horn Date: Tue, 31 Mar 2026 17:15:25 +0200 Subject: [PATCH 132/234] meataxe: cache dual (#6298) --- lib/meataxe.gi | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/lib/meataxe.gi b/lib/meataxe.gi index b7949c450c..a64617518e 100644 --- a/lib/meataxe.gi +++ b/lib/meataxe.gi @@ -2973,13 +2973,16 @@ local cf; end; SMTX.DualModule:=function(module) +local gens; if SMTX.IsZeroGens(module) then - return GModuleByMats([],module.dimension,SMTX.Field(module)); - else - return GModuleByMats(List(SMTX.Generators(module),i->TransposedMat(i)^-1), - module.dimension, - SMTX.Field(module)); + return module; + fi; + if not IsBound(module.Dual) then + gens := List(SMTX.Generators(module),i->TransposedMat(i)^-1); + module.Dual := GModuleByMats(gens, module.dimension, SMTX.Field(module)); + module.Dual.Dual := module; fi; + return module.Dual; end; ############################################################################### From c186ac1e9bb6e644c24b453fed2314c8920d77b9 Mon Sep 17 00:00:00 2001 From: Max Horn Date: Tue, 31 Mar 2026 22:17:18 +0200 Subject: [PATCH 133/234] Make the meataxe faster by using `AddMatrix`, `AddVector`, `MultMatrix`, `MultVector` (#6289) Consider this setup: gap> n:=10;; # increase this to make the effect even stronger gap> G:=GL(56,GF(25));; gap> H:=Subgroup(G, Concatenation(GeneratorsOfGroup(G),List([1..n],i->PseudoRandom(G))));; gap> dn:=g ->DirectSumGModule(NaturalGModule(g),NaturalGModule(g));; gap> gap> Reset(GlobalMersenneTwister,1);;Reset(GlobalRandomSource,1);; Then before this PR: gap> MTX.Indecomposition(dn(H));; time; 9326 After this PR: gap> MTX.Indecomposition(dn(H));; time; 3845 To achieve a substantial speedup beyond this probably requires algorithmic improvements. --- lib/matobj.gi | 46 ++++++++++++++++++++++- lib/matobj2.gd | 5 ++- lib/meatauto.gi | 74 +++++++++++++++++++++---------------- tst/testinstall/meataxe.tst | 33 +++++++++++++---- 4 files changed, 117 insertions(+), 41 deletions(-) diff --git a/lib/matobj.gi b/lib/matobj.gi index 5e443e75d6..d24b631d5a 100644 --- a/lib/matobj.gi +++ b/lib/matobj.gi @@ -1931,6 +1931,18 @@ InstallEarlyMethod( AddMatrix, fi; end ); +InstallMethod( AddMatrix, "for a mutable IsRowListMatrix and a IsRowListMatrix", + [ IsRowListMatrix and IsMutable, IsRowListMatrix ], + function( dstmat, srcmat ) + local i; + if DimensionsMat(dstmat) <> DimensionsMat(srcmat) then + Error("AddMatrix: matrices must have the same dimensions"); + fi; + for i in [1..NrRows(dstmat)] do + AddRowVector(dstmat[i], srcmat[i]); + od; + end ); + InstallMethod( AddMatrix, "for a mutable 8bit matrix and an 8bit matrix", [ Is8BitMatrixRep and IsMutable, Is8BitMatrixRep ], function( dstmat, srcmat ) @@ -1939,7 +1951,7 @@ InstallMethod( AddMatrix, "for a mutable 8bit matrix and an 8bit matrix", Error("AddMatrix: matrices must have the same dimensions"); fi; for i in [1..NrRows(dstmat)] do - ADD_COEFFS_VEC8BIT_2(dstmat[i], srcmat[i]); + ADD_ROWVECTOR_VEC8BITS_2(dstmat[i], srcmat[i]); od; end ); @@ -1977,6 +1989,18 @@ InstallEarlyMethod( AddMatrix, fi; end ); +InstallMethod( AddMatrix, "for a mutable IsRowListMatrix, an IsRowListMatrix, and a scalar", + [ IsRowListMatrix and IsMutable, IsRowListMatrix, IsScalar ], + function( dstmat, srcmat, scalar ) + local i; + if DimensionsMat(dstmat) <> DimensionsMat(srcmat) then + Error("AddMatrix: matrices must have the same dimensions"); + fi; + for i in [1..NrRows(dstmat)] do + AddRowVector(dstmat[i], srcmat[i], scalar); + od; + end ); + InstallMethod( AddMatrix, "for a mutable 8bit matrix, an 8bit matrix, and a scalar", [ Is8BitMatrixRep and IsMutable, Is8BitMatrixRep, IsFFE ], function( dstmat, srcmat, scalar ) @@ -1985,7 +2009,7 @@ InstallMethod( AddMatrix, "for a mutable 8bit matrix, an 8bit matrix, and a scal Error("AddMatrix: matrices must have the same dimensions"); fi; for i in [1..NrRows(dstmat)] do - ADD_COEFFS_VEC8BIT_3(dstmat[i], srcmat[i], scalar); + ADD_ROWVECTOR_VEC8BITS_3(dstmat[i], srcmat[i], scalar); od; end ); @@ -2017,6 +2041,15 @@ InstallEarlyMethod( MultMatrixRight, fi; end ); +InstallMethod( MultMatrixRight, "for a mutable IsRowListMatrix and a scalar", + [ IsRowListMatrix and IsMutable, IsScalar ], + function( mat, scalar ) + local i; + for i in [1..NrRows(mat)] do + MultVectorRight(mat[i], scalar); + od; + end ); + ############################################################################# ## #M MultMatrixLeft( , ) @@ -2045,6 +2078,15 @@ InstallEarlyMethod( MultMatrixLeft, fi; end ); +InstallMethod( MultMatrixLeft, "for a mutable IsRowListMatrix and a scalar", + [ IsRowListMatrix and IsMutable, IsScalar ], + function( mat, scalar ) + local i; + for i in [1..NrRows(mat)] do + MultVectorLeft(mat[i], scalar); + od; + end ); + ############################################################################ ## Fallback method for DeterminantMatrix diff --git a/lib/matobj2.gd b/lib/matobj2.gd index f03a76119a..83851864b6 100644 --- a/lib/matobj2.gd +++ b/lib/matobj2.gd @@ -2062,8 +2062,11 @@ DeclareOperationKernel( "SwapMatrixColumns", [ IsMatrixOrMatrixObj and IsMutable ## nothing ## ## -## Computes the calculation M + c \cdot N in-place, storing the result in M. +## Computes the calculation M + N \cdot c in-place, storing the result in M. ## If the optional argument c is omitted, then N is added directly. +## The matrices must have the same dimensions, otherwise the result is undefined. +## Specialized methods may be defined only when M and N have the same +## representation. ## If both of the matrices are lists-of-lists, then the operation is delegated ## row by row to . ## n then return rhs; fi; + lhs := ShallowCopy(lhs); for i in [1..Length(weights)] do if weights[i] = lead then z := lhs[lead]; - lhs := lhs - z * mat[i]; rhs := rhs - z * vec[i]; + AddVector(lhs, mat[i], -z); # lhs is a vector + rhs := rhs - z * vec[i]; # rhs is a scalar lead := PositionNonZero(lhs, lead); if lead > n then return rhs; @@ -217,10 +219,10 @@ local m, n, zero, i, c, j, factor; for i in [1..m] do c := eqns.weights[i]; for j in [1..i-1] do - if eqns.mat[j][c] <> zero then + factor := eqns.mat[j,c]; + if factor <> zero then Info(InfoMtxHom,6,"solveEqns: kill mat[",j,",",c,"]"); - factor := eqns.mat[j][c]; - eqns.mat[j] := eqns.mat[j] - factor*eqns.mat[i]; + AddVector(eqns.mat[j], eqns.mat[i], -factor); eqns.vec[j] := eqns.vec[j] - factor*eqns.vec[i]; fi; od; @@ -306,13 +308,13 @@ local n, coeffs, x, zero, z, i; coeffs:=[]; x:=v; else - x:=v; + x:=ShallowCopy(v); zero:=x[1]*0; coeffs:=ListWithIdenticalEntries(n, zero); for i in [1..n] do z:=x[ech[i]]; if z <> zero then - x:=x - z * base[i]; + AddVector(x, base[i], -z); coeffs[i]:=z; fi; od; @@ -552,13 +554,13 @@ end); # If a linearly dependent set of elements is supplied, this # routine will trim it down to a basis. BindGlobal("SMTX_EcheloniseMats",function (gens, F) -local n, m, zero, ech, k, i, j, l; +local n, m, zero, ech, k, i, j, l, entry; if Length(gens) = 0 then return [ [], [] ]; fi; # copy the list to avoid destroying the original list - gens:=ShallowCopy(gens); + gens:=List(gens, MutableCopyMatrix); n:=NrRows(gens[1]); m:=NrCols(gens[1]); @@ -581,12 +583,15 @@ local n, m, zero, ech, k, i, j, l; Add(ech, [i,j]); # First normalise the [i,j] position to 1 - gens[k]:=gens[k] / gens[k][i,j]; + entry := gens[k][i,j]; + if not IsOne(entry) then + MultMatrix(gens[k], 1/entry); + fi; # Now zero position [i,j] in all further generators for l in [k+1..Length(gens)] do if (gens[l][i,j] <> zero) then - gens[l]:=gens[l] - gens[k] * gens[l][i,j]; + AddMatrix(gens[l], gens[k], -gens[l][i,j]); fi; od; k:=k + 1; @@ -617,7 +622,7 @@ end); # The code is heavily commented, and I appreciate suggestions on how to # improve it (particularly bits of code). BindGlobal("SpinHom",function (V, W) -local nv, nw, F, zero, zeroW, gV, gW, k, U, echu, r, homs, s, work, ans, v0, +local nv, nw, F, zero, minusone, zeroW, gV, gW, k, U, echu, r, homs, s, work, ans, v0, M, x, pos, z, echm, t, v, echv, a, u, e, start, oldlen, ag, m, uu, ret, c, s1, X, mat, uuc, uic, newhoms, hom, Uhom, imv0, imv0c, image, i, j, l; @@ -635,6 +640,7 @@ local nv, nw, F, zero, zeroW, gV, gW, k, U, echu, r, homs, s, work, ans, v0, TestModulesFitTogether(V,W); F:=V.field; zero:=Zero(F); + minusone:=-One(F); zeroW:=ListWithIdenticalEntries(nw,zero); zeroW:=ImmutableVector(F,zeroW); @@ -744,14 +750,13 @@ local nv, nw, F, zero, zeroW, gV, gW, k, U, echu, r, homs, s, work, ans, v0, # create new element , with its definition as the # difference between and in . x:=v[i] * gV[j]; - m:=ag; + m:=MutableCopyMat(ag); ConvertToMatrixRep(m, F); uu:=u[i] * gV[j]; ret:=EchResidueCoeffs(U, echu, x,3); x:=ret.residue; - uu:=uu - ret.projection; - + AddVector(uu, ret.projection, minusone); # reduce modulo the new semi-ech basis elements in , # storing the coefficients in # @@ -759,12 +764,12 @@ local nv, nw, F, zero, zeroW, gV, gW, k, U, echu, r, homs, s, work, ans, v0, for l in [1..Length(v)] do z:=x[echv[l]]; if z <> zero then - x:=x - z * v[l]; + AddVector(x, v[l], -z); if Length(m) > 0 then - m:=m - z * a[l]; + AddMatrix(m, a[l], -z); fi; c[l]:=c[l] + z; - uu:=uu - z * u[l]; + AddVector(uu, u[l], -z); fi; od; c:=ImmutableVector(F,c); @@ -797,14 +802,14 @@ local nv, nw, F, zero, zeroW, gV, gW, k, U, echu, r, homs, s, work, ans, v0, for l in [1..Length(v)] do if c[l] <> zero then if Length(X) > 0 then - X:=X + c[l] * a[l]; + AddMatrix(X, a[l], c[l]); fi; - uu:=uu + c[l] * u[l]; + AddVector(uu, u[l], c[l]); fi; od; if Length(X) > 0 then - X:=X - ag; + AddMatrix(X, ag, minusone); fi; mat:=[]; @@ -814,6 +819,7 @@ local nv, nw, F, zero, zeroW, gV, gW, k, U, echu, r, homs, s, work, ans, v0, Add(mat, uuc * homs[l] - uic * homs[l] * gW[j]); od; Append(mat, X); + ConvertToMatrixRep(mat); SMTX_AddEqns(e, TransposedMat(mat), zeroW); fi; od; @@ -848,7 +854,7 @@ local nv, nw, F, zero, zeroW, gV, gW, k, U, echu, r, homs, s, work, ans, v0, ConvertToMatrixRep(Uhom, F); for l in [1..s] do if ans[i][l] <> zero then - Uhom:=Uhom + ans[i][l] * homs[l]; + AddMatrix(Uhom, homs[l], ans[i][l]); fi; od; for l in [1..r] do @@ -856,10 +862,10 @@ local nv, nw, F, zero, zeroW, gV, gW, k, U, echu, r, homs, s, work, ans, v0, od; fi; - imv0:=zeroW * zero; + imv0:=ZeroMutable(zeroW); for l in [1..t] do if ans[i][s+l] <> zero then - imv0:=imv0 + ans[i][s+l] * M[l]; + AddVector(imv0, M[l], ans[i][s+l]); fi; od; imv0c:=EchResidueCoeffs(M, echm, imv0,1); @@ -867,7 +873,7 @@ local nv, nw, F, zero, zeroW, gV, gW, k, U, echu, r, homs, s, work, ans, v0, if Length(imv0c)=0 then image:=[]; else image:=imv0c * a[l];fi; if r > 0 then - image:=image + EchResidueCoeffs(U, echu, u[l],1) * Uhom; + AddVector(image, EchResidueCoeffs(U, echu, u[l],1) * Uhom); fi; Add(hom, image); od; @@ -984,10 +990,12 @@ local proveIndecomposability, addnilpotent, n, F, zero, basis, enddim, local i, r, c, k, done, l; # NB: and and are not local + a := MutableCopyMatrix(a); for i in [1..nildim] do - r:=echelon[nilech[i]][1]; c:=echelon[nilech[i]][2]; + r:=echelon[nilech[i]][1]; + c:=echelon[nilech[i]][2]; if a[r,c] <> zero then - a:=a - a[r,c] * nilbase[i] / nilbase[i][r,c]; + AddMatrix(a, nilbase[i], -a[r,c] / nilbase[i][r,c]); fi; od; @@ -995,7 +1003,8 @@ local proveIndecomposability, addnilpotent, n, F, zero, basis, enddim, k:=1; done:=false; while not done and k <= Length(remain) do l:=remain[k]; - r:=echelon[l][1]; c:=echelon[l][2]; + r:=echelon[l][1]; + c:=echelon[l][2]; if a[r,c] <> zero then done:=true; else @@ -1377,12 +1386,12 @@ SMTX.IsomorphismModules:=SMTX_IsomorphismModules; # running down diagonals below the main diagonal: # [2,1], [3,2], [4,3], ..., [3,1], [4,2], ..., [n-1,1], [n, 2], [n,1] BindGlobal("SMTX_EcheloniseNilpotentMatAlg",function (matalg, F) -local zero, n, base, ech, k, diff, i, j, found, l; +local zero, n, base, ech, k, diff, i, j, found, l, entry; zero:=Zero(F); n := NrCols(matalg[1]); - base := ShallowCopy(matalg); + base := List(matalg, MutableCopyMatrix); ech := []; k := 1; @@ -1409,12 +1418,15 @@ local zero, n, base, ech, k, diff, i, j, found, l; Add(ech, [i,j]); # First normalise the [i,j] position to 1 - base[k] := base[k] / base[k][i,j]; + entry := base[k][i,j]; + if not IsOne(entry) then + MultMatrix(base[k], 1/entry); + fi; # Now zero position [i,j] in all other basis elements for l in [1..Length(base)] do if (l <> k) and (base[l][i,j] <> zero) then - base[l] := base[l] - base[k] * base[l][i,j]; + AddMatrix(base[l], base[k], -base[l][i,j]); fi; od; k := k + 1; diff --git a/tst/testinstall/meataxe.tst b/tst/testinstall/meataxe.tst index 92ab0eac64..55dc6c66b2 100644 --- a/tst/testinstall/meataxe.tst +++ b/tst/testinstall/meataxe.tst @@ -1,4 +1,4 @@ -#@local G,M,M2,M3,M4,M5,M6,V,bf,bo,cf,homs,m,mat,qf,randM,res,sf,subs,mats,Q,orig,S +#@local G,M,M2,M3,M4,M5,M6,V,bf,bo,cf,homs,m,mat,qf,randM,res,sf,subs,mats,Q,orig,S,dim,F,i gap> START_TEST("meataxe.tst"); # @@ -71,16 +71,12 @@ Error, generators are different lengths # # # +gap> G:=SymmetricGroup(3);; +gap> M:=PermutationGModule(G,GF(2));; gap> M2:=TensorProductGModule(M,M); rec( IsOverFiniteField := true, dimension := 9, field := GF(2), generators := [ , ], isMTXModule := true ) -gap> M6:=DirectSumGModule(M,M); -rec( IsOverFiniteField := true, dimension := 6, field := GF(2), - generators := [ , - ], isMTXModule := true ) -gap> M6.generators[1] = DirectSumMat(M.generators[1], M.generators[1]); -true gap> IdGroup(MTX.ModuleAutomorphisms(M2)); [ 1344, 11301 ] gap> cf:=MTX.CompositionFactors(M2);; @@ -91,6 +87,29 @@ gap> List(Filtered(cf, x -> x.dimension=2), MTX.InvariantQuadraticForm); [ , , ] +# +# +# +gap> M6:=DirectSumGModule(M,M); +rec( IsOverFiniteField := true, dimension := 6, field := GF(2), + generators := [ , + ], isMTXModule := true ) +gap> M6.generators[1] = DirectSumMat(M.generators[1], M.generators[1]); +true + +# +# +# +gap> dim:=10;; F:=GF(25);; +gap> G:=Sp(dim,F);; +gap> M:=NaturalGModule(G);; +gap> for i in [1..3] do +> M:=DirectSumGModule(M, NaturalGModule(G^RandomInvertibleMat(dim, F))); +> od; +gap> res:=MTX.Indecomposition(M);; +gap> Length(res); +4 + # # # From e602b4458d6a5b1b83cca18f6b45395040326019 Mon Sep 17 00:00:00 2001 From: Max Horn Date: Wed, 1 Apr 2026 01:38:15 +0200 Subject: [PATCH 134/234] meataxe: simplify using MutableBasis (#6290) Replace most of the custom code for solving equation systems by a user of GAP's MutableBasis machinery. This makes the code easier to understand and also provides a minor speed up. --- lib/meatauto.gi | 185 +++++++---------------------------- tst/testinstall/meatauto.tst | 8 +- 2 files changed, 39 insertions(+), 154 deletions(-) diff --git a/lib/meatauto.gi b/lib/meatauto.gi index b0fbc18736..8a91e4374a 100644 --- a/lib/meatauto.gi +++ b/lib/meatauto.gi @@ -70,126 +70,15 @@ local f, d1, d2, e, z, g1, g2, r, b, n, a, gp, i, j, k; end); -# the following code is essentially due to Michael Smith +BindGlobal("SMTX_AddEqns", function(eqns, newmat) +local newrow; -# These routines are designed to accumulate a system of linear equations -# -# M_1 X = V_1, M_2 X = V_2 ... M_t X = V_t -# -# Where each M_i is an m_i*n matrix, X is the unknown length n vector, and -# each V is an length m_i vector. The equations can be added as each batch -# is calculated. Here is some pseudo-code to demonstrate: -# -# eqns := newEqns (n, field); -# i := 1; -# repeat -# -# addEqns(M_i, V_i) -# increment i; -# until i > t or eqns.failed; -# if not eqns.failed then -# S := solveEqns(eqns); -# fi; -# -# As demonstrated by the example, an early notification of failure is -# available by checking ".failed". All new equations are sifted with respect -# to the current set, and only added if they are independent of the current -# set. If a new equation reduces to the zero row and a nonzero vector -# entry, then there is no solution and this is immediately returned by -# setting eqns.failed to true. The function solveEqns has an already -# triangulised system of equations, so it simply reduces above the pivots -# and returns the solution vector. - - -BindGlobal("SMTX_AddEqns",function ( eqns, newmat, newvec) -local n, weights, mat, vec, ReduceRow, t, - newweight, newrow, newrhs, i, l, k; - -# Add a bunch of equations to the system of equations in . Each -# row of is the left-hand side of a new equation, and the -# corresponding row of the right-hand side. Each equation in -# filtered against the current echelonised system stored in and -# then added if it is independent of the system. As soon as a -# left-hand side reduces to 0 with a non-zero right-hand side, the flag -# is set. - - Info(InfoMtxHom,6,"addEqns: entering" ); - - n := eqns.dim; - weights := eqns.weights; - mat := eqns.mat; - vec := eqns.vec; - - # reduce the (lhs,rhs) against the semi-echelonised current matrix, - # and return either: (1) the reduced rhs if the lhs reduces to zero, - # or (2) a list containing the new echelon weight, the new row and - # the new rhs for the system, and the row number that this - # equation should placed. - ReduceRow := function (lhs, rhs) - local lead, i, z; - lead := PositionNonZero(lhs); - Assert(0, n = Length(lhs)); - if lead > n then - return rhs; - fi; - lhs := ShallowCopy(lhs); - for i in [1..Length(weights)] do - if weights[i] = lead then - z := lhs[lead]; - AddVector(lhs, mat[i], -z); # lhs is a vector - rhs := rhs - z * vec[i]; # rhs is a scalar - lead := PositionNonZero(lhs, lead); - if lead > n then - return rhs; - fi; - elif weights[i] > lead then - return [lead, lhs, rhs, i]; - fi; - od; - return [lead, lhs, rhs, Length(weights)+1]; - end; - - for k in [1..Length(newmat)] do - t := ReduceRow(newmat[k], newvec[k]); - - if IsList(t) then - # new equation - newweight := t[1]; - newrow := t[2]; - newrhs := t[3]; - i := t[4]; # position for new row - - # normalise so that leading entry is 1 - newrhs := newrhs / newrow[newweight]; - newrow := newrow / newrow[newweight]; # NB: in this order - - if i = Length(mat)+1 then - # add new equation to end of list - Add(mat, newrow); - Add(vec, newrhs); - Add(weights, newweight); - else - l := Length(mat); - # move down other rows to make space for this new one... - mat{[i+1..l+1]} := mat{[i..l]}; - vec{[i+1..l+1]} := vec{[i..l]}; - # and then slot it in - mat[i] := newrow; - vec[i] := newrhs; - weights{[i+1..l+1]} := weights{[i..l]}; - weights[i] := newweight; - fi; + Info(InfoMtxHom,6,"addEqns: entering (n = ", eqns.dim, ", rank = ", NrBasisVectors(eqns.mb), ")" ); - else - # no new equation, check whether inconsistent due to - # nonzero rhs reduction - - if not IsZero(t) then - Info(InfoMtxHom,6,"addEqns: FAIL!" ); - eqns.failed := true; - return eqns; # return immediately - fi; - fi; + # reduce each row of newmat against the semi-echelonised current matrix; + # if we find any new pivots, insert them + for newrow in newmat do + CloseMutableBasis(eqns.mb, newrow); od; end); @@ -197,11 +86,7 @@ BindGlobal("SMTX_NewEqns",function (dim, field) return rec( dim := dim, # number of variables field := field, # field over which the equation hold - mat := [], # left-hand sides of system - weights := [], # echelon weights for lhs matrix - vec := [], # right-hand sides of system - failed := false, # flag to indicate inconsistent system - index := [], # index for row ordering + mb := MutableBasis(field, [], ZeroVector(field, dim)), ); end); @@ -209,25 +94,22 @@ BindGlobal("SMTX_KillAbovePivotsEqns",function (eqns) # Eliminate entries above pivots. Note that the pivot entries are # all 1 courtesy of SMTX_AddEqns. -local m, n, zero, i, c, j, factor; +local m, i, c, j, factor; Info(InfoMtxHom,6,"killAbovePivotsEqns: entering" ); + m := Length(eqns.mat); - n := eqns.dim; - if m > 0 then - zero := Zero(eqns.field); - for i in [1..m] do - c := eqns.weights[i]; - for j in [1..i-1] do - factor := eqns.mat[j,c]; - if factor <> zero then - Info(InfoMtxHom,6,"solveEqns: kill mat[",j,",",c,"]"); - AddVector(eqns.mat[j], eqns.mat[i], -factor); - eqns.vec[j] := eqns.vec[j] - factor*eqns.vec[i]; - fi; - od; + for i in [1..m] do + c := eqns.pivots[i]; + Assert(0, IsOne(eqns.mat[i,c])); + for j in [1..i-1] do + factor := eqns.mat[j,c]; + if not IsZero(factor) then + Info(InfoMtxHom,6,"solveEqns: kill mat[",j,",",c,"]"); + AddVector(eqns.mat[j], eqns.mat[i], -factor); + fi; od; - fi; + od; Info(InfoMtxHom,6,"killAbovePivotsEqns: leaving" ); end); @@ -243,6 +125,11 @@ BindGlobal("SMTX_NullspaceEqns",function(e) local mat, n, one, zerovec, i, k, nullspace, row; + # HACK: convert MutableBasis into the "old" format expected by this code + e.mat := ShallowCopy(e.mb!.basisVectors); + e.pivots := List(e.mat, PositionNonZero); + SortParallel(e.pivots, e.mat); + SMTX_KillAbovePivotsEqns(e); mat := e.mat; @@ -624,10 +511,11 @@ end); BindGlobal("SpinHom",function (V, W) local nv, nw, F, zero, minusone, zeroW, gV, gW, k, U, echu, r, homs, s, work, ans, v0, M, x, pos, z, echm, t, v, echv, a, u, e, start, oldlen, ag, m, uu, ret, - c, s1, X, mat, uuc, uic, newhoms, hom, Uhom, imv0, imv0c, image, i, j, l; + c, s1, X, mat, uuc, uic, newhoms, hom, Uhom, imv0, imv0c, image, i, j, l, + nullspace, nullspace_row; # Compute Hom(V,W) for G-modules and . The algorithm starts with -# the trivial submodule of for which Hom(U,V) is trivial. It +# the trivial submodule of for which Hom(U,W) is trivial. It # then computes Hom(U',W) for U' a submodule generated by and a # single element in . This U' becomes the next as the process # is iterated, ending when = . The element is chosen in a @@ -820,7 +708,7 @@ local nv, nw, F, zero, minusone, zeroW, gV, gW, k, U, echu, r, homs, s, work, an od; Append(mat, X); ConvertToMatrixRep(mat); - SMTX_AddEqns(e, TransposedMat(mat), zeroW); + SMTX_AddEqns(e, TransposedMat(mat)); fi; od; od; @@ -833,15 +721,14 @@ local nv, nw, F, zero, minusone, zeroW, gV, gW, k, U, echu, r, homs, s, work, an until oldlen = Length(v); # we have the system of equations, so find its solution space - - ans:=SMTX_NullspaceEqns(e); + nullspace:=SMTX_NullspaceEqns(e); # Now build the homomorphisms newhoms:=[]; - for i in [1..Length(ans)] do + for nullspace_row in nullspace do - # Each row of ans is of the form: + # Each row of nullspace is of the form: # # [ b_1, b_2, ..., b_s, c_1, c_2, ..., c_t ] # @@ -853,8 +740,8 @@ local nv, nw, F, zero, minusone, zeroW, gV, gW, k, U, echu, r, homs, s, work, an Uhom:=NullMat(r, nw, F); ConvertToMatrixRep(Uhom, F); for l in [1..s] do - if ans[i][l] <> zero then - AddMatrix(Uhom, homs[l], ans[i][l]); + if nullspace_row[l] <> zero then + AddMatrix(Uhom, homs[l], nullspace_row[l]); fi; od; for l in [1..r] do @@ -864,8 +751,8 @@ local nv, nw, F, zero, minusone, zeroW, gV, gW, k, U, echu, r, homs, s, work, an imv0:=ZeroMutable(zeroW); for l in [1..t] do - if ans[i][s+l] <> zero then - AddVector(imv0, M[l], ans[i][s+l]); + if nullspace_row[s+l] <> zero then + AddVector(imv0, M[l], nullspace_row[s+l]); fi; od; imv0c:=EchResidueCoeffs(M, echm, imv0,1); diff --git a/tst/testinstall/meatauto.tst b/tst/testinstall/meatauto.tst index 793c4729ce..5f7d064756 100644 --- a/tst/testinstall/meatauto.tst +++ b/tst/testinstall/meatauto.tst @@ -4,12 +4,10 @@ gap> START_TEST("meatauto.tst"); # # SMTX_NewEqns, SMTX_NullspaceEqns # -gap> e := SMTX_NewEqns(3, GF(5)); -rec( dim := 3, failed := false, field := GF(5), index := [ ], mat := [ ], - vec := [ ], weights := [ ] ) +gap> e := SMTX_NewEqns(3, GF(5));; +gap> SMTX_AddEqns(e, [[1,0,0]*Z(5)^0]); gap> SMTX_NullspaceEqns(e); -[ [ Z(5)^0, 0*Z(5), 0*Z(5) ], [ 0*Z(5), Z(5)^0, 0*Z(5) ], - [ 0*Z(5), 0*Z(5), Z(5)^0 ] ] +[ [ 0*Z(5), Z(5)^0, 0*Z(5) ], [ 0*Z(5), 0*Z(5), Z(5)^0 ] ] # # MTX.BasisModuleEndomorphisms From 370b63341ce09ef734312289197aadefc10ba274 Mon Sep 17 00:00:00 2001 From: Max Horn Date: Thu, 9 Apr 2026 22:16:10 +0200 Subject: [PATCH 135/234] Make MutableCopyMat slightly less 'obsolete' (#6304) By having the synonym in lib/obsolete.gd, it is not loaded when the -O option is passed to GAP. But tons of packages still use it (and frankly I am not sure it is worth the effort to change this, considering it breaks compatibility with older GAP versions for no good reason). Anyway: let's move the synonym declaration out there to make -O less problematic again. Also change one accidental use of MutableCopyMat in the library that recently slipped in (my fault). It would not have happened if we had a test using `-O`; this PR is a step towards that by reducing the number of errors the option causes. --- lib/matrix.gd | 17 +++++++++++++++++ lib/meatauto.gi | 2 +- lib/obsolete.gd | 17 ----------------- 3 files changed, 18 insertions(+), 18 deletions(-) diff --git a/lib/matrix.gd b/lib/matrix.gd index 210891dccd..7867782ed9 100644 --- a/lib/matrix.gd +++ b/lib/matrix.gd @@ -1563,6 +1563,23 @@ DeclareGlobalFunction( "IdentityMat" ); DeclareOperation( "MutableCopyMatrix", [ IsList ] ); +############################################################################# +## +#O MutableCopyMat( ) +## +## Declared obsolete in February 2023. +## +## Still used in corelg, crisp, cryst, cubefree, cvec, fining, forms, genss, +## guava, hap, hapcryst, lpres, matricesforhomalg, modisom, polycyclic, +## recog, semigroups, smallsemi, sophus (02/2023) +## +## (We cannot use 'DeclareObsoleteSynonym' because the cvec package wants to +## install a method for 'MutableCopyMat', thus 'MutableCopyMat' must be an +## operation.) +## +DeclareSynonym( "MutableCopyMat", MutableCopyMatrix ); + + ############################################################################# ## #F NullMat( , [, ] ) . . . . . . . . . null matrix of a given size diff --git a/lib/meatauto.gi b/lib/meatauto.gi index 8a91e4374a..b7cf1e1862 100644 --- a/lib/meatauto.gi +++ b/lib/meatauto.gi @@ -638,7 +638,7 @@ local nv, nw, F, zero, minusone, zeroW, gV, gW, k, U, echu, r, homs, s, work, an # create new element , with its definition as the # difference between and in . x:=v[i] * gV[j]; - m:=MutableCopyMat(ag); + m:=MutableCopyMatrix(ag); ConvertToMatrixRep(m, F); uu:=u[i] * gV[j]; diff --git a/lib/obsolete.gd b/lib/obsolete.gd index 65404ffcc3..61e774a0b1 100644 --- a/lib/obsolete.gd +++ b/lib/obsolete.gd @@ -249,23 +249,6 @@ DeclareSynonym( "FirstOp", First ); DeclareObsoleteSynonym( "RadicalGroup", "SolvableRadical" ); -############################################################################# -## -#O MutableCopyMat( ) -## -## Moved to obsoletes in February 2023. -## -## Still used in corelg, crisp, cryst, cubefree, cvec, fining, forms, genss, -## guava, hap, hapcryst, lpres, matricesforhomalg, modisom, polycyclic, -## recog, semigroups, smallsemi, sophus (02/2023) -## -## (We cannot use 'DeclareObsoleteSynonym' because the cvec package wants to -## install a method for 'MutableCopyMat', thus 'MutableCopyMat' must be an -## operation.) -## -DeclareSynonym( "MutableCopyMat", MutableCopyMatrix ); - - ############################################################################# ## #F SCRSiftOld( , ) From 5e741d52a8c2b3afa504a8928811fa33dd791c2e Mon Sep 17 00:00:00 2001 From: Max Horn Date: Thu, 9 Apr 2026 22:31:28 +0200 Subject: [PATCH 136/234] Fix CopySubVector malfunction for GF(2) vectors (#6303) Fix the unaligned carry path in CopyBits so GF(2) section copies read the adjacent source word instead of skipping ahead at a word boundary. Co-authored-by: Codex --- src/bits_intern.h | 2 +- tst/testinstall/MatrixObj/CopySubVector.tst | 36 ++++++++++++++++++++- 2 files changed, 36 insertions(+), 2 deletions(-) diff --git a/src/bits_intern.h b/src/bits_intern.h index c4ca683ccf..4d28e9fe6b 100644 --- a/src/bits_intern.h +++ b/src/bits_intern.h @@ -120,7 +120,7 @@ static ALWAYS_INLINE void CopyBits(const UInt * fromblock, (tobit - frombit)); fromblock++; CopyInWord(toblock, 0, tailbits + frombit - 1 - BIPEB, - fromblock[1], tobit + BIPEB - frombit); + *fromblock, tobit + BIPEB - frombit); frombit += tailbits - BIPEB; } toblock++; diff --git a/tst/testinstall/MatrixObj/CopySubVector.tst b/tst/testinstall/MatrixObj/CopySubVector.tst index 0ff3fdd267..688bca39b4 100644 --- a/tst/testinstall/MatrixObj/CopySubVector.tst +++ b/tst/testinstall/MatrixObj/CopySubVector.tst @@ -1,4 +1,4 @@ -#@local l1, v1, l2, v2, v3, v4 +#@local l1, v1, l2, v2, v3, v4, x, src, dst, expected, from, to, len, one gap> START_TEST("CopySubVector.tst"); # @@ -23,5 +23,39 @@ gap> CopySubVector( v3, v4, [1,2,3], [2,4,6] ); gap> v4; [ Z(5)^0, Z(5)^0, Z(5)^0, Z(5), Z(5), Z(5)^3, Z(5)^3, Z(5)^3, Z(5)^3 ] +# +gap> x := IdentityMat(72, GF(2));; +gap> src := x[72];; +gap> dst := ZeroVector(9, x[1]);; +gap> CopySubVector(src, dst, [64..71], [2..9]); +gap> List(dst{[2..9]}, IntFFE); +[ 0, 0, 0, 0, 0, 0, 0, 0 ] +gap> src := x[64];; +gap> dst := ZeroVector(9, x[1]);; +gap> CopySubVector(src, dst, [63..70], [2..9]); +gap> List(dst{[2..9]}, IntFFE); +[ 0, 1, 0, 0, 0, 0, 0, 0 ] +gap> src := x[65];; +gap> dst := ZeroVector(9, x[1]);; +gap> CopySubVector(src, dst, [64..71], [2..9]); +gap> List(dst{[2..9]}, IntFFE); +[ 0, 1, 0, 0, 0, 0, 0, 0 ] +gap> one := One(GF(2));; +gap> src := Vector(GF(2), List([1..80], i -> one));; +gap> for from in [1,2,63,64,65] do +> for to in [1,2,3,63,64,65] do +> for len in [1,2,7,8,9,16] do +> dst := ZeroVector(90, src);; +> expected := ZeroVector(90, src);; +> CopySubVector(src, dst, [from..from+len-1], [to..to+len-1]); +> expected{[to..to+len-1]} := List([1..len], i -> one); +> if List(dst, IntFFE) <> List(expected, IntFFE) then +> Error("unexpected result for from=", from, +> ", to=", to, ", len=", len); +> fi; +> od; +> od; +> od; + # gap> STOP_TEST("CopySubVector.tst"); From bec6d9644f4c77a48336a4cf4a642e222b40524d Mon Sep 17 00:00:00 2001 From: Max Horn Date: Fri, 10 Apr 2026 06:53:29 +0200 Subject: [PATCH 137/234] CI: fix cross compile tests (#6308) To avoid the workflow running over an hour, tweak the `citests` Makefile target: drop testinstall from it, as it is redundant with testworkspace anyway. Created with assistance by ChatGPT. --- .github/workflows/CI.yml | 44 +++++++++++++++++++++++++++++++++------- Makefile.rules | 2 +- 2 files changed, 38 insertions(+), 8 deletions(-) diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index 4c83ada404..9a7626a9c1 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -283,21 +283,51 @@ jobs: cross_compile: # The host should always be linux - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 timeout-minutes: 60 name: Cross compiler for s390x steps: - - name: Install Cross-Compile Support - uses: cyberjunk/gha-ubuntu-cross@v5 - with: - arch: s390x + - name: Configure APT for amd64 host + s390x foreign arch + shell: bash + run: | + set -euxo pipefail + + sudo dpkg --add-architecture s390x + . /etc/os-release + + # Restrict the default runner sources to amd64, otherwise apt also tries + # to fetch s390x from security.ubuntu.com / archive.ubuntu.com and gets 404s. + if ! grep -q '^Architectures: amd64$' /etc/apt/sources.list.d/ubuntu.sources; then + sudo sed -i '/^Types: deb$/a Architectures: amd64' /etc/apt/sources.list.d/ubuntu.sources + fi + + # Add the foreign-arch repositories from ubuntu-ports. + sudo tee /etc/apt/sources.list.d/s390x.sources >/dev/null < Date: Fri, 10 Apr 2026 11:57:52 +0200 Subject: [PATCH 138/234] Shorten .tst filenames printed by Test and TestDirectory (#6306) Before, one might see this when running `make check` in the GAP root directory: testing: /Users/mhorn/.codex/worktrees/674d/gap/tst/testinstall/declarefunction.tst ########> Diff in /Users/mhorn/.codex/worktrees/674d/gap/tst/testinstall/declarefun\ ction.tst:10 With this PR: testing: tst/testinstall/declarefunction.tst ########> Diff in tst/testinstall/declarefunction.tst:10 --- lib/test.gi | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/lib/test.gi b/lib/test.gi index dca2387589..32addda12d 100644 --- a/lib/test.gi +++ b/lib/test.gi @@ -361,6 +361,19 @@ InstallGlobalFunction(CREATE_LOCAL_VARIABLES_BAG, function(namelist) return EvalString(func); end); +BindGlobal("TEST_NICE_FILENAME", function(path) + local cwd; + cwd := GAP_getcwd(); + if not EndsWith(cwd, "/") then + cwd := Concatenation(cwd, "/"); + fi; + + if StartsWith(path, cwd) then + return path{[Length(cwd)+1 .. Length(path)]}; + fi; + return UserHomeShorten(path); +end); + ## ## <#GAPDoc Label="Test"> ## @@ -607,6 +620,7 @@ BindGlobal("DefaultReportDiff", function(inp, expout, found, fnam, line, time) if IsStream(fnam) then Print("test stream, line ",line,":"); else + fnam:=TEST_NICE_FILENAME(fnam); Print(fnam,":",line); fi; Print(TextAttr.reset, "\n", DefaultReportDiffColors.message); @@ -1008,7 +1022,7 @@ InstallGlobalFunction( "TestDirectory", function(arg) for i in [1..Length(files)] do if opts.showProgress then - Print("testing: ", files[i].name, "\n"); + Print("testing: ", TEST_NICE_FILENAME(files[i].name), "\n"); fi; startTime := Runtime(); From e54fd7a86ed3b207bda23a7439a63283bfb90ef0 Mon Sep 17 00:00:00 2001 From: Thomas Breuer Date: Fri, 10 Apr 2026 13:14:06 +0200 Subject: [PATCH 139/234] Admit the syntax `SymplecticGroup( IsPlistMatrixRep, 4, GF(4) )` (#6299) Up to now, we had to say `SymplecticGroup( IsMatrixGroup, 4, GF(4) : ConstructingFilter:= IsPlistMatrixRep )`. --- doc/ref/matobj.xml | 24 ++++++++++++++++++++++++ grp/basic.gd | 6 ++++++ grp/classic.gd | 22 +++++++++++++++------- hpcgap/lib/vec8bit.gi | 14 ++++++++++++-- hpcgap/lib/vecmat.gi | 15 +++++++++++++-- lib/mat8bit.gd | 2 ++ lib/matobj1.gd | 24 ++++++++++++++++++++++++ lib/matobjnz.gd | 2 ++ lib/matobjplist.gd | 1 + lib/vec8bit.gi | 14 ++++++++++++-- lib/vecmat.gd | 2 ++ lib/vecmat.gi | 15 +++++++++++++-- tst/testinstall/MatrixObj/Matrix.tst | 6 ++++++ tst/testinstall/grp/classic-S.tst | 12 ++++++++++++ 14 files changed, 144 insertions(+), 15 deletions(-) diff --git a/doc/ref/matobj.xml b/doc/ref/matobj.xml index bc2494903b..4ef9fb44ac 100644 --- a/doc/ref/matobj.xml +++ b/doc/ref/matobj.xml @@ -377,4 +377,28 @@ described in this chapter is supported. + +

+Groups Consisting of Matrix Objects + +One application of matrix objects is to construct groups whose elements +are matrix objects. +The following conventions hold for such a group G. + + + + All elements of G have the same + + and the same . + For a given matrix or matrix object M, + a matrix object that can be multiplied with elements of G + can be constructed as Matrix( M, Representative( G ) ), + and the result can be tested for membership in G. + + + +<#Include Label="ConstructingFiltersForMatrixGroupElements"> + +
+ diff --git a/grp/basic.gd b/grp/basic.gd index 0bbd5966f4..6e834b33fc 100644 --- a/grp/basic.gd +++ b/grp/basic.gd @@ -34,6 +34,12 @@ ## constructed over a specified field, which can be given as second argument ## of the function that constructs the group; ## The default field is . +##

+## In the case of matrix groups, also the internal representation of the +## group elements can be prescribed. +## For convenience, one can enter one of the filters in the list +## , +## which then implies . ## <#/GAPDoc> diff --git a/grp/classic.gd b/grp/classic.gd index d5383269e3..0bfd9b3b4b 100644 --- a/grp/classic.gd +++ b/grp/classic.gd @@ -779,9 +779,9 @@ DeclareConstructor( "SymplecticGroupCons", [ IsGroup, IsPosInt, IsRing ] ); ##

## If filt is not given it defaults to , ## and the returned group is the symplectic group itself. -## Another supported value for filt is -## ; -## in this case, the argument form is not supported. +## Other supported values for filt are +## (in this case, the argument form is not supported) +## and the entries of . ##

## At the moment finite fields or residue class rings ## Integers mod q, with q an odd prime power, are @@ -825,27 +825,35 @@ BindGlobal( "DescribesInvariantBilinearForm", ( IsGroup( obj ) and HasInvariantBilinearForm( obj ) ) ); BindGlobal( "SymplecticGroup", function ( arg ) - local filt, form; + local filt, rep, form; if IsFilter( First( arg ) ) then filt:= Remove( arg, 1 ); else filt:= IsMatrixGroup; fi; + if filt in ConstructingFiltersForMatrixGroupElements then + rep:= filt; + filt:= IsMatrixGroup; + else + rep:= fail; + fi; if DescribesInvariantBilinearForm( Last( arg ) ) then form:= Remove( arg ); if Length( arg ) = 0 then # ( [, ] ) - return SymplecticGroupCons( filt, form ); + return SymplecticGroupCons( filt, form : ConstructingFilter:= rep ); elif Length( arg ) = 2 and IsPosInt( arg[1] ) and ( IsPosInt( arg[2] ) or IsRing( arg[2] ) ) then # ( [, ], , ) or ( [, ], , ) - return SymplecticGroupCons( filt, arg[1], arg[2], form ); + return SymplecticGroupCons( filt, arg[1], arg[2], form + : ConstructingFilter:= rep ); fi; elif Length( arg ) = 2 and IsPosInt( arg[1] ) and ( IsPosInt( arg[2] ) or IsRing( arg[2] ) ) then # ( [, ], ) or ( [, ], ) - return SymplecticGroupCons( filt, arg[1], arg[2] ); + return SymplecticGroupCons( filt, arg[1], arg[2] + : ConstructingFilter:= rep ); fi; Error( "usage: SymplecticGroup( [, ], [, ] )\n", "or SymplecticGroup( [, ], [, ] )\n", diff --git a/hpcgap/lib/vec8bit.gi b/hpcgap/lib/vec8bit.gi index c867e31592..23026afd55 100644 --- a/hpcgap/lib/vec8bit.gi +++ b/hpcgap/lib/vec8bit.gi @@ -1161,11 +1161,21 @@ InstallTagBasedMethod( NewZeroVector, InstallTagBasedMethod( NewMatrix, Is8BitMatrixRep, function( filter, f, rl, l ) - local m; + local len, m; if ValueOption( "check" ) <> false and not Size(f) in [3..256] then Error("Is8BitMatrixRep only supports base fields with 3 to 256 elements"); fi; - m := List(l,ShallowCopy); + # If applicable then replace a flat list 'l' by a nested list + # of lists of length 'rl'. + len:= Length( l ); + if len > 0 and not IsList( l[1] ) then + if len mod rl <> 0 then + Error( "NewMatrix: Length of is not a multiple of " ); + fi; + m := List([0, rl .. len-rl], i -> l{[i+1..i+rl]}); + else + m := List(l,ShallowCopy); + fi; ConvertToMatrixRep(m,Size(f)); return m; end ); diff --git a/hpcgap/lib/vecmat.gi b/hpcgap/lib/vecmat.gi index ecca386723..4891a4a068 100644 --- a/hpcgap/lib/vecmat.gi +++ b/hpcgap/lib/vecmat.gi @@ -2559,9 +2559,20 @@ InstallTagBasedMethod( NewZeroVector, InstallTagBasedMethod( NewMatrix, IsGF2MatrixRep, function( filter, f, rl, l ) - local m; + local len, m; if Size(f) <> 2 then Error("IsGF2MatrixRep only supported over GF(2)"); fi; - m := List(l,ShallowCopy); + + # If applicable then replace a flat list 'l' by a nested list + # of lists of length 'rl'. + len:= Length( l ); + if len > 0 and not IsList( l[1] ) then + if len mod rl <> 0 then + Error( "NewMatrix: Length of is not a multiple of " ); + fi; + m := List([0, rl .. len-rl], i -> l{[i+1..i+rl]}); + else + m := List(l,ShallowCopy); + fi; ConvertToMatrixRep(m,2); return m; end ); diff --git a/lib/mat8bit.gd b/lib/mat8bit.gd index b3ac86dbf0..2e8279f9bd 100644 --- a/lib/mat8bit.gd +++ b/lib/mat8bit.gd @@ -51,6 +51,8 @@ DeclareRepresentation( "Is8BitMatrixRep", and HasNumberRows and HasNumberColumns and HasBaseDomain and HasOneOfBaseDomain and HasZeroOfBaseDomain); +Add( ConstructingFiltersForMatrixGroupElements, Is8BitMatrixRep ); + ############################################################################# ## diff --git a/lib/matobj1.gd b/lib/matobj1.gd index afc33a3d15..6b97b19a99 100644 --- a/lib/matobj1.gd +++ b/lib/matobj1.gd @@ -370,3 +370,27 @@ DeclareAttribute( "OneOfBaseDomain", IsVecOrMatObj ); DeclareAttribute( "ZeroOfBaseDomain", IsVecOrMatObj ); #DeclareAttribute( "ZeroOfBaseDomain", IsVectorObj ); #DeclareAttribute( "ZeroOfBaseDomain", IsMatrixOrMatrixObj ); + + +############################################################################# +## +#V ConstructingFiltersForMatrixGroupElements +## +## <#GAPDoc Label="ConstructingFiltersForMatrixGroupElements"> +## +## +## +## +## This is a list of filters f that are supported as +## the first argument of group constructors such as +## , +## meaning that one asks for a matrix group whose elements are in f. +##

+## If one creates a new representation of matrix objects such that it makes +## sense to create matrix groups from them then the underlying filter +## should be added to . +## +## +## <#/GAPDoc> +## +BIND_GLOBAL( "ConstructingFiltersForMatrixGroupElements", [] ); diff --git a/lib/matobjnz.gd b/lib/matobjnz.gd index c5811d2a2f..34e92e6b94 100644 --- a/lib/matobjnz.gd +++ b/lib/matobjnz.gd @@ -98,3 +98,5 @@ DeclareRepresentation( "IsZmodnZMatrixRep", and HasNumberRows and HasNumberColumns and HasBaseDomain and HasOneOfBaseDomain and HasZeroOfBaseDomain, [] ); + +Add( ConstructingFiltersForMatrixGroupElements, IsZmodnZMatrixRep ); diff --git a/lib/matobjplist.gd b/lib/matobjplist.gd index 5bcd6d38db..58d701063d 100644 --- a/lib/matobjplist.gd +++ b/lib/matobjplist.gd @@ -111,6 +111,7 @@ DeclareRepresentation( "IsPlistMatrixRep", and HasBaseDomain and HasOneOfBaseDomain and HasZeroOfBaseDomain, [] ); +Add( ConstructingFiltersForMatrixGroupElements, IsPlistMatrixRep ); # Some constants for matrix access: BindGlobal( "BDPOS", 1 ); diff --git a/lib/vec8bit.gi b/lib/vec8bit.gi index 1ecab5e48e..4766945be6 100644 --- a/lib/vec8bit.gi +++ b/lib/vec8bit.gi @@ -1116,11 +1116,21 @@ InstallTagBasedMethod( NewZeroVector, InstallTagBasedMethod( NewMatrix, Is8BitMatrixRep, function( filter, f, rl, l ) - local m; + local len, m; if ValueOption( "check" ) <> false and not Size(f) in [3..256] then Error("Is8BitMatrixRep only supports base fields with 3 to 256 elements"); fi; - m := List(l,ShallowCopy); + # If applicable then replace a flat list 'l' by a nested list + # of lists of length 'rl'. + len:= Length( l ); + if len > 0 and not IsList( l[1] ) then + if len mod rl <> 0 then + Error( "NewMatrix: Length of is not a multiple of " ); + fi; + m := List([0, rl .. len-rl], i -> l{[i+1..i+rl]}); + else + m := List(l,ShallowCopy); + fi; ConvertToMatrixRep(m,Size(f)); return m; end ); diff --git a/lib/vecmat.gd b/lib/vecmat.gd index 4072950455..393a969f93 100644 --- a/lib/vecmat.gd +++ b/lib/vecmat.gd @@ -260,6 +260,8 @@ DeclareRepresentation( "IsGF2MatrixRep", and HasNumberRows and HasNumberColumns and HasBaseDomain and HasOneOfBaseDomain and HasZeroOfBaseDomain); +Add( ConstructingFiltersForMatrixGroupElements, IsGF2MatrixRep ); + ############################################################################# ## diff --git a/lib/vecmat.gi b/lib/vecmat.gi index 6d8addd44d..98a7ef3a14 100644 --- a/lib/vecmat.gi +++ b/lib/vecmat.gi @@ -2557,9 +2557,20 @@ InstallTagBasedMethod( NewZeroVector, InstallTagBasedMethod( NewMatrix, IsGF2MatrixRep, function( filter, f, rl, l ) - local m; + local len, m; if Size(f) <> 2 then Error("IsGF2MatrixRep only supported over GF(2)"); fi; - m := List(l,ShallowCopy); + + # If applicable then replace a flat list 'l' by a nested list + # of lists of length 'rl'. + len:= Length( l ); + if len > 0 and not IsList( l[1] ) then + if len mod rl <> 0 then + Error( "NewMatrix: Length of is not a multiple of " ); + fi; + m := List([0, rl .. len-rl], i -> l{[i+1..i+rl]}); + else + m := List(l,ShallowCopy); + fi; ConvertToMatrixRep(m,2); return m; end ); diff --git a/tst/testinstall/MatrixObj/Matrix.tst b/tst/testinstall/MatrixObj/Matrix.tst index dcf299f0e8..85d6c9d80f 100644 --- a/tst/testinstall/MatrixObj/Matrix.tst +++ b/tst/testinstall/MatrixObj/Matrix.tst @@ -22,6 +22,8 @@ gap> m := Matrix( IsGF2MatrixRep, GF(2), [[1,2],[3,4]] * Z(2) ); gap> Display(m); 1 . 1 . +gap> m = Matrix( IsGF2MatrixRep, GF(2), [1,2,3,4] * Z(2), 2 ); +true # gap> m := Matrix( Is8BitMatrixRep, GF(4), [[1,2],[3,4]] * Z(2) ); @@ -29,6 +31,8 @@ gap> m := Matrix( Is8BitMatrixRep, GF(4), [[1,2],[3,4]] * Z(2) ); gap> Display(m); 1 . 1 . +gap> m = Matrix( Is8BitMatrixRep, GF(4), [1,2,3,4] * Z(2), 2 ); +true # gap> m := Matrix( IsPlistMatrixRep, GF(2), [[1,2],[3,4]] * Z(2) ); @@ -38,6 +42,8 @@ gap> Display(m); [[ Z(2)^0, 0*Z(2) ] [ Z(2)^0, 0*Z(2) ] ]> +gap> m = Matrix( IsPlistMatrixRep, GF(2), [1,2,3,4] * Z(2), 2 ); +true # gap> STOP_TEST("Matrix.tst"); diff --git a/tst/testinstall/grp/classic-S.tst b/tst/testinstall/grp/classic-S.tst index f570f55851..1a85ed5735 100644 --- a/tst/testinstall/grp/classic-S.tst +++ b/tst/testinstall/grp/classic-S.tst @@ -125,6 +125,18 @@ or SymplecticGroup( [, ], [, ] ) or SymplecticGroup( [, ] ) gap> Sp(4,6); Error, must be a prime or a finite field +gap> for para in [ [ IsGF2MatrixRep, GF(2) ], +> [ Is8BitMatrixRep, GF(3) ], +> # [ IsZmodnZMatrixRep, Integers mod 25 ], # not yet converted +> [ IsPlistMatrixRep, GF(4) ] ] do +> f:= para[1]; +> F:= para[2]; +> G:= Sp( f, 4, F ); +> if not f( G.1 ) or not f( InvariantBilinearForm( G ).matrix ) then +> Error( "wrong internal representation of matrices in Sp( ", +> f, ", 4, ", F, " )" ); +> fi; +> od; # gap> SigmaL(3,5); From 10b016e045c66919c78a42b196ebc03b02962a06 Mon Sep 17 00:00:00 2001 From: Max Horn Date: Fri, 10 Apr 2026 14:09:40 +0200 Subject: [PATCH 140/234] Let ObjWithMemory transfer IsRowListMatrix filter (#6310) Some code has optimizations for IsRowListMatrix matrices. It is desirable to benefit from them even for matrices-with-memory if possible, which this patch ensures. --- lib/memory.gi | 3 +++ tst/testinstall/memory.tst | 6 ++++++ 2 files changed, 9 insertions(+) diff --git a/lib/memory.gi b/lib/memory.gi index 04558f2017..0ffccb80cd 100644 --- a/lib/memory.gi +++ b/lib/memory.gi @@ -30,6 +30,9 @@ BindGlobal( "ObjWithMemory", function( slp, n, el ) if IsMatrixObj( el ) then filt:= filt and IsMatrixObj; fi; + if IsRowListMatrix( el ) then + filt:= filt and IsRowListMatrix; + fi; if HasBaseDomain( el ) then filt:= filt and HasBaseDomain; fi; diff --git a/tst/testinstall/memory.tst b/tst/testinstall/memory.tst index 93eececfbc..ab37cf950a 100644 --- a/tst/testinstall/memory.tst +++ b/tst/testinstall/memory.tst @@ -6,6 +6,12 @@ gap> START_TEST( "memory.tst" ); gap> G := GroupWithMemory([ (1,2,3,4,5), (1,2) ]);; gap> H := GroupWithMemory(GL(IsMatrixGroup, 3, 3));; gap> g := H.1 ^ 2;; h := H.2 ^ 2;; +gap> IsMatrix(g); +true +gap> IsMatrixObj(g); +true +gap> IsRowListMatrix(g); +true gap> StripMemory(g); [ [ Z(3)^0, 0*Z(3), 0*Z(3) ], [ 0*Z(3), Z(3)^0, 0*Z(3) ], [ 0*Z(3), 0*Z(3), Z(3)^0 ] ] From 9ce97a862269d5b027ce8bb801284fe34c458973 Mon Sep 17 00:00:00 2001 From: Max Horn Date: Fri, 10 Apr 2026 14:28:48 +0200 Subject: [PATCH 141/234] Add PositionNonZeroInRow for matrices and matrix objects (#6311) Use it in the generic diagonal and triangular predicates. Resolves #6231 Co-authored-by: Codex --- doc/ref/matobj.xml | 1 + lib/matobj.gi | 40 +++++++++++++++++ lib/matobj2.gd | 21 +++++++++ lib/matrix.gi | 43 +++++++++---------- .../MatrixObj/ElementaryMatrices.tst | 33 ++++++++++++++ tst/testinstall/MatrixObj/testmatobj.g | 27 ++++++++++++ 6 files changed, 143 insertions(+), 22 deletions(-) diff --git a/doc/ref/matobj.xml b/doc/ref/matobj.xml index 4ef9fb44ac..8ed8908e47 100644 --- a/doc/ref/matobj.xml +++ b/doc/ref/matobj.xml @@ -219,6 +219,7 @@ All rows of a matrix must have the same length and the same base domain. <#Include Label="AddMatrixRowsRight"> <#Include Label="AddMatrixColumns"> <#Include Label="AddMatrixColumnsLeft"> +<#Include Label="PositionNonZeroInRow"> <#Include Label="SwapMatrixRows"> <#Include Label="SwapMatrixColumns"> <#Include Label="AddMatrix"> diff --git a/lib/matobj.gi b/lib/matobj.gi index d24b631d5a..8921d8d5d6 100644 --- a/lib/matobj.gi +++ b/lib/matobj.gi @@ -1865,6 +1865,46 @@ InstallEarlyMethod( AddMatrixColumnsLeft, ############################################################################ +InstallMethod( PositionNonZeroInRow, + "for a row list matrix and a row number", + [ IsRowListMatrix, IsPosInt ], + function( mat, row ) + return PositionNonZero( mat[row] ); + end ); + +InstallMethod( PositionNonZeroInRow, + "for a row list matrix, a row number, and a start position", + [ IsRowListMatrix, IsPosInt, IsInt ], + function( mat, row, from ) + return PositionNonZero( mat[row], from ); + end ); + +InstallMethod( PositionNonZeroInRow, + "for a matrix or matrix object and a row number", + [ IsMatrixOrMatrixObj, IsPosInt ], + function( mat, row ) + return PositionNonZeroInRow( mat, row, 0 ); + end ); + +InstallMethod( PositionNonZeroInRow, + "for a matrix or matrix object, a row number, and a start position", + [ IsMatrixOrMatrixObj, IsPosInt, IsInt ], + function( mat, row, from ) + local col, ncols, zero; + + ncols := NrCols( mat ); + zero := ZeroOfBaseDomain( mat ); + for col in [ Maximum( 1, from + 1 ) .. ncols ] do + if mat[row, col] <> zero then + return col; + fi; + od; + + return ncols + 1; + end ); + +############################################################################ + InstallMethod( SwapMatrixRows, "for a mutable matrix object, and two row numbers", [ IsMatrixOrMatrixObj and IsMutable, IsInt, IsInt ], function( mat, row1, row2 ) diff --git a/lib/matobj2.gd b/lib/matobj2.gd index 83851864b6..6b21e5f775 100644 --- a/lib/matobj2.gd +++ b/lib/matobj2.gd @@ -2019,6 +2019,27 @@ DeclareSynonym( "AddMatrixColumns", AddMatrixColumnsRight); ## DeclareOperation( "AddMatrixColumnsLeft", [ IsMatrixOrMatrixObj and IsMutable, IsInt, IsInt, IsObject ] ); +############################################################################ +## +## <#GAPDoc Label="PositionNonZeroInRow"> +## +## +## +## a positive integer +## +## +##

+## Returns the position of the first nonzero entry in the i-th row of +## the matrix M, or NrCols( M ) + 1 if the row is zero. +## If the optional argument from is given, the search starts after +## position from. +## +## +## <#/GAPDoc> +## +DeclareOperation( "PositionNonZeroInRow", [ IsMatrixOrMatrixObj, IsPosInt ] ); +DeclareOperation( "PositionNonZeroInRow", [ IsMatrixOrMatrixObj, IsPosInt, IsInt ] ); + ############################################################################ ## ## <#GAPDoc Label="SwapMatrixRows"> diff --git a/lib/matrix.gi b/lib/matrix.gi index 9134c1840d..958729712c 100644 --- a/lib/matrix.gi +++ b/lib/matrix.gi @@ -174,14 +174,16 @@ InstallMethod( IsDiagonalMatrix, "for a matrix", [ IsMatrixOrMatrixObj ], function( mat ) - local i, j, z; - z:=ZeroOfBaseDomain(mat); + local i, ncols, p; + ncols := NrCols( mat ); for i in [ 1 .. NrRows( mat ) ] do - for j in [ 1 .. NrCols( mat ) ] do - if mat[i,j] <> z and i <> j then - return false; - fi; - od; + p := PositionNonZeroInRow( mat, i ); + if p <= ncols and p <> i then + return false; + fi; + if PositionNonZeroInRow( mat, i, i ) <= ncols then + return false; + fi; od; return true; end); @@ -215,14 +217,13 @@ InstallMethod( IsUpperTriangularMatrix, "for a matrix", [ IsMatrixOrMatrixObj ], function( mat ) - local i, j, z; - z:=ZeroOfBaseDomain(mat); - for j in [ 1 .. NrCols( mat ) ] do - for i in [ j+1 .. NrRows( mat ) ] do - if mat[i,j] <> z then - return false; - fi; - od; + local i, ncols, p; + ncols := NrCols( mat ); + for i in [ 1 .. NrRows( mat ) ] do + p := PositionNonZeroInRow( mat, i ); + if p <= ncols and p < i then + return false; + fi; od; return true; end); @@ -236,14 +237,12 @@ InstallMethod( IsLowerTriangularMatrix, "for a matrix", [ IsMatrixOrMatrixObj ], function( mat ) - local i, j, z; - z:=ZeroOfBaseDomain(mat); + local i, ncols; + ncols := NrCols( mat ); for i in [ 1 .. NrRows( mat ) ] do - for j in [ i+1 .. NrCols( mat ) ] do - if mat[i,j] <> z then - return false; - fi; - od; + if PositionNonZeroInRow( mat, i, i ) <= ncols then + return false; + fi; od; return true; end); diff --git a/tst/testinstall/MatrixObj/ElementaryMatrices.tst b/tst/testinstall/MatrixObj/ElementaryMatrices.tst index f02e0f62ef..e2080c550a 100644 --- a/tst/testinstall/MatrixObj/ElementaryMatrices.tst +++ b/tst/testinstall/MatrixObj/ElementaryMatrices.tst @@ -67,6 +67,39 @@ true gap> TestElementaryTransforms( mat, -1 ); gap> TestWholeMatrixTransforms( mat, -1 ); +# +gap> TestPositionNonZeroInRow([ [ 1 ] ]); +gap> TestPositionNonZeroInRow(Matrix([ [ 1 ] ])); +gap> TestPositionNonZeroInRow(Matrix(GF(2), [ [ 1 ] ] * Z(2))); +gap> TestPositionNonZeroInRow(Matrix(GF(5), [ [ 1 ] ] * Z(5)^0)); + +# +gap> mat := Matrix([ [ 1, 0, 0 ], [ 0, 2, 0 ] ]);; +gap> IsDiagonalMatrix(mat); +true +gap> IsUpperTriangularMatrix(mat); +true +gap> IsLowerTriangularMatrix(mat); +true + +# +gap> mat := Matrix([ [ 1, 2, 0 ], [ 0, 3, 0 ] ]);; +gap> IsDiagonalMatrix(mat); +false +gap> IsUpperTriangularMatrix(mat); +true +gap> IsLowerTriangularMatrix(mat); +false + +# +gap> mat := Matrix([ [ 1, 0, 0 ], [ 4, 3, 0 ] ]);; +gap> IsDiagonalMatrix(mat); +false +gap> IsUpperTriangularMatrix(mat); +false +gap> IsLowerTriangularMatrix(mat); +true + ########## # gap> mat := Matrix( [[2,4,5],[7,11,-4],[-3,20,0]]);; diff --git a/tst/testinstall/MatrixObj/testmatobj.g b/tst/testinstall/MatrixObj/testmatobj.g index adc0f5c702..d017c3a63e 100644 --- a/tst/testinstall/MatrixObj/testmatobj.g +++ b/tst/testinstall/MatrixObj/testmatobj.g @@ -251,3 +251,30 @@ TestWholeMatrixTransforms := function(mat, scalar) MultMatrix(copy, scalar); if not same_entries(mat, copy) then Error("MultMatrix(", scalar, ") failure"); fi; end; + +TestPositionNonZeroInRow := function(mat) + local ncols; + + # Make a matrix with specific patter of the same kind as mat + mat := Matrix([ [ 0, 1, 0, 1 ], [ 0, 0, 0, 0 ], [ 0, 0, 1, 0 ] ], mat); + + ncols := NrCols(mat); + if PositionNonZeroInRow(mat, 1) <> 2 then + Error("PositionNonZeroInRow(_,1) failure"); + fi; + if PositionNonZeroInRow(mat, 1, 2) <> 4 then + Error("PositionNonZeroInRow(_,1,2) failure"); + fi; + if PositionNonZeroInRow(mat, 1, 4) <> ncols + 1 then + Error("PositionNonZeroInRow(_,1,4) failure"); + fi; + if PositionNonZeroInRow(mat, 2) <> ncols + 1 then + Error("PositionNonZeroInRow(_,2) zero-row failure"); + fi; + if PositionNonZeroInRow(mat, 3) <> 3 then + Error("PositionNonZeroInRow(_,3) failure"); + fi; + if PositionNonZeroInRow(mat, 3, 3) <> ncols + 1 then + Error("PositionNonZeroInRow(_,3,3) failure"); + fi; +end; From 59fe45155dd14d9873ec3e7bb2972be78ac835a9 Mon Sep 17 00:00:00 2001 From: Max Horn Date: Sun, 12 Apr 2026 19:07:38 +0200 Subject: [PATCH 142/234] Optimize PositionNonZero, PositionNonZeroInRow (#6312) First off, add early methods for PositionNonZeroInRow to avoid method dispatch overhead when used on plists-of-rows style matrices. Next, add dedicated three-argument method for `PositionNonZero` on IsRowVector. Finally, update the `POSITION_NOT` code to make use of modern GAP features to make the code easier to read. Before: gap> m:=IdentityMat(4500);; gap> List([1..NrRows(m)],i->PositionNonZeroInRow(m,i));; time; 2936 gap> List([1..NrRows(m)],i->PositionNonZero(m[i]));; time; 93 gap> List([1..NrRows(m)],i->PositionNonZero(m[i],0));; time; 161 After: gap> m:=IdentityMat(4500);; gap> List([1..NrRows(m)],i->PositionNonZeroInRow(m,i));; time; 94 gap> List([1..NrRows(m)],i->PositionNonZero(m[i]));; time; 93 gap> List([1..NrRows(m)],i->PositionNonZero(m[i],0));; time; 92 --- hpcgap/lib/vecmat.gi | 16 ++++++++++++++++ lib/kernel.g | 27 ++++++++++++++------------- lib/matobj.gi | 17 +++++++++++++++++ lib/vecmat.gi | 16 ++++++++++++++++ 4 files changed, 63 insertions(+), 13 deletions(-) diff --git a/hpcgap/lib/vecmat.gi b/hpcgap/lib/vecmat.gi index 4891a4a068..e61616fe2d 100644 --- a/hpcgap/lib/vecmat.gi +++ b/hpcgap/lib/vecmat.gi @@ -1926,6 +1926,22 @@ InstallOtherMethod(PositionNonZero, return Length(vec)+1; end); +InstallOtherMethod(PositionNonZero, + "General method for a row vector with start", + true,[IsRowVector, IsInt],0, + function(vec, from) + local i,z; + if Length(vec)=0 then return 1;fi; + z:=Zero(vec[1]); + for i in [from+1..Length(vec)] do + if vec[i]<>z then return i;fi; + od; + if Length(vec) <= from then + return from + 1; + fi; + return Length(vec)+1; +end); + ############################################################################# ## diff --git a/lib/kernel.g b/lib/kernel.g index ec171534d4..95e06c82e8 100644 --- a/lib/kernel.g +++ b/lib/kernel.g @@ -139,36 +139,37 @@ end; ############################################################################# ## -#F POSITION_NOT( , [,] ) . . . . find not +#F POSITION_NOT( , [,] ) . . . . find not ## ## -## +## ## ## ## ## ## -POSITION_NOT := function( arg ) +POSITION_NOT := function( list, val, from... ) local i; - if LENGTH(arg) = 2 then - for i in [ 1 .. LENGTH(arg[1]) ] do - if arg[1][i] <> arg[2] then + if LENGTH(from) = 0 then + for i in [ 1 .. LENGTH(list) ] do + if list[i] <> val then return i; fi; od; - return LENGTH(arg[1]) + 1; + return LENGTH(list) + 1; - elif LENGTH(arg) = 3 then - for i in [ arg[3]+1 .. LENGTH(arg[1]) ] do - if arg[1][i] <> arg[2] then + elif LENGTH(from) = 1 then + from := from[1]; + for i in [ from+1 .. LENGTH(list) ] do + if list[i] <> val then return i; fi; od; - if LENGTH( arg[1] ) <= arg[3] then - return arg[3] + 1; + if LENGTH( list ) <= from then + return from + 1; else - return LENGTH(arg[1]) + 1; + return LENGTH(list) + 1; fi; else Error( "usage: PositionNot( , [, ] )" ); diff --git a/lib/matobj.gi b/lib/matobj.gi index 8921d8d5d6..bc7a49bc1d 100644 --- a/lib/matobj.gi +++ b/lib/matobj.gi @@ -1903,6 +1903,23 @@ InstallMethod( PositionNonZeroInRow, return ncols + 1; end ); +InstallEarlyMethod( PositionNonZeroInRow, + function ( mat, row ) + if IsPlistRep( mat ) then + return PositionNonZero( mat[row] ); + fi; + TryNextMethod(); + end ); + +InstallEarlyMethod( PositionNonZeroInRow, + function ( mat, row, from ) + if IsPlistRep( mat ) then + return PositionNonZero( mat[row], from ); + fi; + TryNextMethod(); + end ); + + ############################################################################ InstallMethod( SwapMatrixRows, "for a mutable matrix object, and two row numbers", diff --git a/lib/vecmat.gi b/lib/vecmat.gi index 98a7ef3a14..821832841e 100644 --- a/lib/vecmat.gi +++ b/lib/vecmat.gi @@ -1924,6 +1924,22 @@ InstallOtherMethod(PositionNonZero, return Length(vec)+1; end); +InstallOtherMethod(PositionNonZero, + "General method for a row vector with start", + true,[IsRowVector, IsInt],0, + function(vec, from) + local i,z; + if Length(vec)=0 then return 1;fi; + z:=Zero(vec[1]); + for i in [from+1..Length(vec)] do + if vec[i]<>z then return i;fi; + od; + if Length(vec) <= from then + return from + 1; + fi; + return Length(vec)+1; +end); + ############################################################################# ## From 43712555704d5618834c5e168654b247147f1cd1 Mon Sep 17 00:00:00 2001 From: Kamil Zabielski <50334623+limakzi@users.noreply.github.com> Date: Mon, 13 Apr 2026 00:19:58 +0200 Subject: [PATCH 143/234] Add `IsSquareMat` and `IsAntisymmetricMat` (#6268) --- doc/ref/matrix.xml | 2 + lib/matrix.gd | 68 ++++++++++++++++++++++++++++++ lib/matrix.gi | 38 ++++++++++++++++- tst/testinstall/matrix.tst | 86 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 192 insertions(+), 2 deletions(-) diff --git a/doc/ref/matrix.xml b/doc/ref/matrix.xml index fce1638952..59f006dbfd 100644 --- a/doc/ref/matrix.xml +++ b/doc/ref/matrix.xml @@ -310,7 +310,9 @@ see . <#Include Label="IsDiagonalMat"> <#Include Label="IsUpperTriangularMat"> <#Include Label="IsLowerTriangularMat"> +<#Include Label="IsSquareMat"> <#Include Label="IsSymmetricMat"> +<#Include Label="IsAntisymmetricMat"> diff --git a/lib/matrix.gd b/lib/matrix.gd index 7867782ed9..8056c80165 100644 --- a/lib/matrix.gd +++ b/lib/matrix.gd @@ -152,6 +152,36 @@ DeclareProperty( "IsLowerTriangularMatrix", IsMatrixOrMatrixObj ); DeclareSynonym( "IsLowerTriangularMat", IsLowerTriangularMatrix ); +############################################################################# +## +#P IsSquareMatrix( ) +#P IsSquareMat( ) +## +## <#GAPDoc Label="IsSquareMat"> +## +## +## +## +## +## return true if the matrix mat has the same number of rows +## and columns, and false otherwise. +## IsSquareMatrix( [ [ 1 ] ] ); +## true +## gap> IsSquareMatrix( [ [ 1, 2 ], [ 3, 4 ] ] ); +## true +## gap> IsSquareMatrix( [ [ 1, 2, 3 ], [ 4, 5, 6 ] ] ); +## false +## ]]> +## +## +## <#/GAPDoc> +## +DeclareProperty( "IsSquareMatrix", IsMatrixOrMatrixObj ); + +DeclareSynonym( "IsSquareMat", IsSquareMatrix ); + + ############################################################################# ## #P IsSymmetricMatrix( ) @@ -184,6 +214,44 @@ DeclareProperty( "IsSymmetricMatrix", IsMatrixOrMatrixObj ); DeclareSynonym( "IsSymmetricMat", IsSymmetricMatrix ); +InstallTrueMethod( IsSquareMatrix, IsSymmetricMatrix ); + + +############################################################################# +## +#P IsAntisymmetricMatrix( ) +#P IsAntisymmetricMat( ) +## +## <#GAPDoc Label="IsAntisymmetricMat"> +## +## +## +## +## +## return true if the matrix mat is a square matrix and +## satisfies mat[i,j] = -mat[j,i] for all +## i, j, and false otherwise. +## (In particular, the diagonal entries must be zero.) +## IsAntisymmetricMatrix( [ [ 0 ] ] ); +## true +## gap> IsAntisymmetricMatrix( [ [ 0, 1 ], [ -1, 0 ] ] ); +## true +## gap> IsAntisymmetricMatrix( [ [ 0, 1 ], [ 1, 0 ] ] ); +## false +## gap> IsAntisymmetricMatrix( [ [ 1, 2, 3 ], [ 4, 5, 6 ] ] ); +## false +## ]]> +## +## +## <#/GAPDoc> +## +DeclareProperty( "IsAntisymmetricMatrix", IsMatrixOrMatrixObj ); + +DeclareSynonym( "IsAntisymmetricMat", IsAntisymmetricMatrix ); + +InstallTrueMethod( IsSquareMatrix, IsAntisymmetricMatrix ); + ############################################################################# ## diff --git a/lib/matrix.gi b/lib/matrix.gi index 958729712c..bd470ef749 100644 --- a/lib/matrix.gi +++ b/lib/matrix.gi @@ -248,6 +248,18 @@ InstallMethod( IsLowerTriangularMatrix, end); +############################################################################# +## +#M IsSquareMatrix() +## +InstallMethod( IsSquareMatrix, + "for a matrix", + [ IsMatrixOrMatrixObj ], + function( mat ) + return NrRows( mat ) = NrCols( mat ); + end ); + + ############################################################################# ## #M IsSymmetricMatrix() @@ -257,7 +269,7 @@ InstallMethod( IsSymmetricMatrix, [ IsMatrixOrMatrixObj ], function( mat ) local i, j; - if NrRows( mat ) <> NrCols( mat ) then + if not IsSquareMatrix( mat ) then return false; fi; for i in [ 1 .. NrRows( mat ) ] do @@ -270,7 +282,29 @@ InstallMethod( IsSymmetricMatrix, return true; end ); -InstallTrueMethod( IsSymmetricMatrix, IsMatrixOrMatrixObj and IsEmptyMatrix ); + + +############################################################################# +## +#M IsAntisymmetricMatrix() +## +InstallMethod( IsAntisymmetricMatrix, + "for a matrix", + [ IsMatrixOrMatrixObj ], + function( mat ) + local i, j; + if not IsSquareMatrix( mat ) then + return false; + fi; + for i in [ 1 .. NrRows( mat ) ] do + for j in [ 1 .. i ] do + if mat[i,j] <> -mat[j,i] then + return false; + fi; + od; + od; + return true; + end ); ############################################################################# diff --git a/tst/testinstall/matrix.tst b/tst/testinstall/matrix.tst index ea8dd88a81..e633885f6f 100644 --- a/tst/testinstall/matrix.tst +++ b/tst/testinstall/matrix.tst @@ -1,3 +1,17 @@ +# +gap> empty_0x2 := NewZeroMatrix(IsPlistMatrixRep, Integers, 0, 2); +<0x2-matrix over Integers> +gap> empty_2x0 := NewZeroMatrix(IsPlistMatrixRep, Integers, 2, 0); +<2x0-matrix over Integers> +gap> empty_0x0 := NewZeroMatrix(IsPlistMatrixRep, Integers, 0, 0); +<0x0-matrix over Integers> +gap> IsEmptyMatrix(empty_0x2); +true +gap> IsEmptyMatrix(empty_2x0); +true +gap> IsEmptyMatrix(empty_0x0); +true + # gap> IsGeneralizedCartanMatrix(NullMat(3, 3)); false @@ -21,6 +35,12 @@ gap> IsGeneralizedCartanMatrix([[2,-2],[-2,2]]); true # +gap> IsDiagonalMat(empty_0x2); +true +gap> IsDiagonalMat(empty_2x0); +true +gap> IsDiagonalMat(empty_0x0); +true gap> IsDiagonalMat(NullMat(3, 3)); true gap> IsDiagonalMat(NullMat(1, 3)); @@ -45,6 +65,12 @@ gap> IsDiagonalMat([[1,0,0],[0,1,0]]); true # +gap> IsUpperTriangularMat(empty_0x2); +true +gap> IsUpperTriangularMat(empty_2x0); +true +gap> IsUpperTriangularMat(empty_0x0); +true gap> IsUpperTriangularMat(NullMat(3, 3)); true gap> IsUpperTriangularMat(NullMat(1, 3)); @@ -67,6 +93,12 @@ gap> IsUpperTriangularMat([[1,1,1],[0,1,1]]); true # +gap> IsLowerTriangularMat(empty_0x2); +true +gap> IsLowerTriangularMat(empty_2x0); +true +gap> IsLowerTriangularMat(empty_0x0); +true gap> IsLowerTriangularMat(NullMat(3, 3)); true gap> IsLowerTriangularMat(NullMat(1, 3)); @@ -89,6 +121,34 @@ gap> IsLowerTriangularMat([[1,0],[1,1],[1,1]]); true # +gap> IsSquareMat(empty_0x2); +false +gap> IsSquareMat(empty_2x0); +false +gap> IsSquareMat(empty_0x0); +true +gap> IsSquareMat(NullMat(3, 3)); +true +gap> IsSquareMat(IdentityMat(3)); +true +gap> IsSquareMat([[1]]); +true +gap> IsSquareMat([[1,2],[3,4]]); +true +gap> IsSquareMat(NullMat(2, 3)); +false +gap> IsSquareMat(NullMat(3, 2)); +false +gap> IsSquareMat([[1,2,3],[4,5,6]]); +false + +# +gap> IsSymmetricMat(empty_0x2); +false +gap> IsSymmetricMat(empty_2x0); +false +gap> IsSymmetricMat(empty_0x0); +true gap> IsSymmetricMat(NullMat(3, 3)); true gap> IsSymmetricMat(IdentityMat(3)); @@ -112,6 +172,32 @@ false gap> IsSymmetricMat([[1,2],[3,4],[5,6]]); false +# +gap> IsAntisymmetricMat(empty_0x2); +false +gap> IsAntisymmetricMat(empty_2x0); +false +gap> IsAntisymmetricMat(empty_0x0); +true +gap> IsAntisymmetricMat(NullMat(3, 3)); +true +gap> IsAntisymmetricMat([[0]]); +true +gap> IsAntisymmetricMat([[0,1],[-1,0]]); +true +gap> IsAntisymmetricMat([[0,2,3],[-2,0,5],[-3,-5,0]]); +true +gap> IsAntisymmetricMat([[0,1],[1,0]]); +false +gap> IsAntisymmetricMat([[1,0],[0,1]]); +false +gap> IsAntisymmetricMat(NullMat(2, 3)); +false +gap> IsAntisymmetricMat(NullMat(3, 2)); +false +gap> IsAntisymmetricMat([[1,2,3],[4,5,6]]); +false + # gap> m := Z(5)^0 * [[0, 1], [1, 0]];; gap> m := GeneratorsWithMemory([m])[1];; From a81ddfd2501c8b7a60706913412b9d126cdb8329 Mon Sep 17 00:00:00 2001 From: Max Horn Date: Mon, 13 Apr 2026 09:03:42 +0200 Subject: [PATCH 144/234] Rename lib/matrobjrowlist.gi to lib/matobjrowlist.gi (#6316) --- lib/{matrobjrowlist.gi => matobjrowlist.gi} | 0 lib/read5.g | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) rename lib/{matrobjrowlist.gi => matobjrowlist.gi} (100%) diff --git a/lib/matrobjrowlist.gi b/lib/matobjrowlist.gi similarity index 100% rename from lib/matrobjrowlist.gi rename to lib/matobjrowlist.gi diff --git a/lib/read5.g b/lib/read5.g index a71bde1a09..e0042c6bf4 100644 --- a/lib/read5.g +++ b/lib/read5.g @@ -109,7 +109,7 @@ ReadLib( "fldabnum.gi" ); ReadLib( "padics.gi" ); ReadLib( "matobj.gi" ); -ReadLib( "matrobjrowlist.gi" ); +ReadLib( "matobjrowlist.gi" ); ReadLib( "vecmat.gi" ); ReadLib( "vec8bit.gi" ); ReadLib( "mat8bit.gi" ); From cfb7e5fe23ff6a5654c68f3f975c2f3c04777c01 Mon Sep 17 00:00:00 2001 From: Max Horn Date: Mon, 13 Apr 2026 09:50:59 +0200 Subject: [PATCH 145/234] Merge IsOne/IsZero methods for IsMatrix and IsMatrixObj (#6314) ... by using PositionNonZeroInRow. Also remove other more specialized methods which are less efficient, or at least not more efficient. Also remove a duplicate PositionNonZero method. Co-authored-by: Codex --- lib/liefam.gi | 5 +++ lib/matobj.gi | 40 -------------------- lib/matobjnz.gi | 26 ------------- lib/matrix.gi | 32 ++++++++-------- tst/testinstall/MatrixObj/IdentityMatrix.tst | 7 ++++ tst/testinstall/MatrixObj/testmatobj.g | 2 + 6 files changed, 30 insertions(+), 82 deletions(-) diff --git a/lib/liefam.gi b/lib/liefam.gi index 54dc6bccb2..ca6c3161c6 100644 --- a/lib/liefam.gi +++ b/lib/liefam.gi @@ -389,6 +389,11 @@ InstallMethod( Position, [ IsLieMatrix and IsPackedElementDefaultRep, IsRowVector, IsInt ], function( mat, v, pos ) return Position( mat![1], v, pos ); end ); +InstallOtherMethod( BaseDomain, + "for Lie matrix in default representation", + [ IsLieMatrix and IsPackedElementDefaultRep ], + mat -> BaseDomain( mat![1] ) ); + ############################################################################# ## diff --git a/lib/matobj.gi b/lib/matobj.gi index bc7a49bc1d..f80b705319 100644 --- a/lib/matobj.gi +++ b/lib/matobj.gi @@ -1497,46 +1497,6 @@ InstallMethod( InverseSameMutability, fi; end ); -InstallMethod( IsZero, - [ IsRowListMatrix and IsMatrixObj ], - function( mat ) - local ncols, row; - - ncols:= NrCols( mat ); - for row in mat do - if PositionNonZero( row ) <= ncols then - return false; - fi; - od; - return true; - end ); - -InstallMethod( IsOne, - [ IsRowListMatrix and IsMatrixObj ], - function( mat ) - local ncols, i, row; - - ncols:= NrCols( mat ); - for i in [1 .. NrRows( mat )] do - row := mat[i]; - if PositionNonZero( row ) <> i or not IsOne( row[i] ) then - return false; - fi; - if PositionNonZero( row, i ) <= ncols then - return false; - fi; - od; - return true; - end ); - -InstallMethod( IsZero, - [ IsMatrixObj ], - M -> IsZero( Unpack( M ) ) ); - -InstallMethod( IsOne, - [ IsMatrixObj ], - M -> IsOne( Unpack( M ) ) ); - InstallMethod( Characteristic, [ IsMatrixOrMatrixObj ], M -> Characteristic( BaseDomain( M ) ) ); diff --git a/lib/matobjnz.gi b/lib/matobjnz.gi index 7c8e0225f5..60fcadff4b 100644 --- a/lib/matobjnz.gi +++ b/lib/matobjnz.gi @@ -232,11 +232,6 @@ InstallMethod( PositionNonZero, "for a zmodnz vector", [ IsZmodnZVectorRep ], return PositionNonZero( v![ELSPOS] ); end ); -InstallMethod( PositionNonZero, "for a zmodnz vector", [ IsZmodnZVectorRep ], - function( v ) - return PositionNonZero( v![ELSPOS] ); - end ); - InstallOtherMethod( PositionNonZero, "for a zmodnz vector and start", [ IsZmodnZVectorRep,IsInt ], function( v,s ) @@ -1228,27 +1223,6 @@ InstallMethod( IsZero, "for a zmodnz matrix", return true; end ); -InstallMethod( IsOne, "for a zmodnz matrix", - [ IsZmodnZMatrixRep ], - function( m ) - local i,j,n; - if Length(m![ROWSPOS]) <> m![RLPOS] then - #Error("IsOne: Matrix must be square"); - return false; - fi; - n := m![RLPOS]; - for i in [1..n] do - if not IsOne(m![ROWSPOS][i]![ELSPOS][i]) then return false; fi; - for j in [1..i-1] do - if not IsZero(m![ROWSPOS][i]![ELSPOS][j]) then return false; fi; - od; - for j in [i+1..n] do - if not IsZero(m![ROWSPOS][i]![ELSPOS][j]) then return false; fi; - od; - od; - return true; - end ); - InstallMethod( OneSameMutability, "for a zmodnz matrix", [ IsZmodnZMatrixRep ], function( m ) diff --git a/lib/matrix.gi b/lib/matrix.gi index bd470ef749..b98e8d9e1d 100644 --- a/lib/matrix.gi +++ b/lib/matrix.gi @@ -1263,15 +1263,15 @@ end ); #M IsZero( ) ## InstallMethod( IsZero, - "method for a matrix", - [ IsMatrix ], + "method for a matrix or matrix object", + [ IsMatrixOrMatrixObj ], function( mat ) - local ncols, # number of columns - row; # loop over rows in 'obj' + local i, + ncols; ncols:= NrCols( mat ); - for row in mat do - if PositionNonZero( row ) <= ncols then + for i in [1 .. NrRows( mat )] do + if PositionNonZeroInRow( mat, i ) <= ncols then return false; fi; od; @@ -1284,20 +1284,20 @@ InstallMethod( IsZero, #M IsOne( ) ## InstallMethod( IsOne, - "method for a matrix", - [ IsMatrix ], + "method for a matrix or matrix object", + [ IsMatrixOrMatrixObj ], function( mat ) - local ncols, # number of columns - i, - row; # loop over rows in 'obj' + local n, i; - ncols:= NrCols( mat ); - for i in [1 .. NrRows( mat )] do - row := mat[i]; - if PositionNonZero( row ) <> i or not IsOne( row[i] ) then + n:= NrCols( mat ); + if NrRows( mat ) <> n then + return false; + fi; + for i in [1 .. n] do + if PositionNonZeroInRow( mat, i ) <> i or not IsOne( mat[i,i] ) then return false; fi; - if PositionNonZero( row, i ) <= ncols then + if PositionNonZeroInRow( mat, i, i ) <= n then return false; fi; od; diff --git a/tst/testinstall/MatrixObj/IdentityMatrix.tst b/tst/testinstall/MatrixObj/IdentityMatrix.tst index fa7b07e327..1cabf541aa 100644 --- a/tst/testinstall/MatrixObj/IdentityMatrix.tst +++ b/tst/testinstall/MatrixObj/IdentityMatrix.tst @@ -118,5 +118,12 @@ Error, Is8BitMatrixRep with zero rows not yet supported gap> IdentityMatrix(GF(4), -1); Error, IdentityMatrix: the dimension must be non-negative +# +gap> m := [ [ 1, 0, 0 ], [ 0, 1, 0 ] ];; +gap> IsOne(m); +false +gap> IsOne(Matrix(IsPlistMatrixRep, Integers, m)); +false + # gap> STOP_TEST("IdentityMatrix.tst"); diff --git a/tst/testinstall/MatrixObj/testmatobj.g b/tst/testinstall/MatrixObj/testmatobj.g index d017c3a63e..bca02e4c1c 100644 --- a/tst/testinstall/MatrixObj/testmatobj.g +++ b/tst/testinstall/MatrixObj/testmatobj.g @@ -21,6 +21,7 @@ TestZeroMatrix := function(filt, ring, rows, cols) Assert(0, BaseDomain(mat) = ring); Assert(0, NrRows(mat) = rows); Assert(0, NrCols(mat) = cols); + Assert(0, IsZero(mat)); for i in [1..rows] do for j in [1..cols] do if not IsZero(mat[i,j]) then Error("entry ", i,",",j," is ", mat[i,j], " and not zero"); fi; @@ -40,6 +41,7 @@ TestIdentityMatrix := function(filt, ring, degree) Assert(0, BaseDomain(mat) = ring); Assert(0, NrRows(mat) = degree); Assert(0, NrCols(mat) = degree); + Assert(0, IsOne(mat)); for i in [1..degree] do for j in [1..degree] do if i<>j and not IsZero(mat[i,j]) then From cfc9260277d73205d96409d1d124c67241e65220 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 13 Apr 2026 09:52:45 +0200 Subject: [PATCH 146/234] build(deps): bump softprops/action-gh-release from 2 to 3 (#6319) Bumps [softprops/action-gh-release](https://github.com/softprops/action-gh-release) from 2 to 3. - [Release notes](https://github.com/softprops/action-gh-release/releases) - [Changelog](https://github.com/softprops/action-gh-release/blob/master/CHANGELOG.md) - [Commits](https://github.com/softprops/action-gh-release/compare/v2...v3) --- updated-dependencies: - dependency-name: softprops/action-gh-release dependency-version: '3' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index eef883f07e..c8de8a0b1e 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -247,7 +247,7 @@ jobs: retention-days: 1 - name: "Upload the installer to tag" - uses: softprops/action-gh-release@v2 + uses: softprops/action-gh-release@v3 if: ${{ startsWith(github.ref, 'refs/tags/v') }} with: files: | From 2cb8eae209743ea14d0622c00e755641fd3a2ca4 Mon Sep 17 00:00:00 2001 From: Max Horn Date: Mon, 13 Apr 2026 09:53:16 +0200 Subject: [PATCH 147/234] Remove ADD_LIST_DEFAULT (#6317) --- lib/coll.gd | 4 ++-- lib/kernel.g | 17 ----------------- lib/list.gi | 4 +++- lib/system.g | 10 +++++----- 4 files changed, 10 insertions(+), 25 deletions(-) diff --git a/lib/coll.gd b/lib/coll.gd index c44f1364c4..18202f6499 100644 --- a/lib/coll.gd +++ b/lib/coll.gd @@ -597,7 +597,7 @@ BIND_GLOBAL( "InstallSubsetMaintenance", atomic readwrite SUBSET_MAINTAINED_INFO, readonly FILTER_REGION do for flag in TRUES_FLAGS( FLAGS_FILTER( sub_req ) ) do if not INFO_FILTERS[flag] in FNUM_CATS_AND_REPS then - ADD_LIST_DEFAULT( filtssub, flag ); + ADD_LIST( filtssub, flag ); fi; od; @@ -633,7 +633,7 @@ BIND_GLOBAL( "InstallSubsetMaintenance", filtsopr:= []; for flag in TRUES_FLAGS( filt1 ) do if not INFO_FILTERS[flag] in FNUM_CATS_AND_REPS then - ADD_LIST_DEFAULT( filtsopr, flag ); + ADD_LIST( filtsopr, flag ); fi; od; for triple in SUBSET_MAINTAINED_INFO[2] do diff --git a/lib/kernel.g b/lib/kernel.g index 95e06c82e8..d247043dae 100644 --- a/lib/kernel.g +++ b/lib/kernel.g @@ -14,23 +14,6 @@ ## -############################################################################# -## -#F ADD_LIST_DEFAULT( , ) . . . . . . add an element to the list -## -## -## -## -## -## -## -## -ADD_LIST_DEFAULT := function ( list, obj ) - list[ LEN_LIST(list)+1 ] := obj; -end; - - - ############################################################################# ## #F AS_LIST_SORTED_LIST( ) . . . . . . . . . . . . . . setify the list diff --git a/lib/list.gi b/lib/list.gi index fb51e5fa71..fe857a3391 100644 --- a/lib/list.gi +++ b/lib/list.gi @@ -1925,7 +1925,9 @@ InstallOtherMethod( IsMatchingSublist, InstallMethod( Add, "for mutable list and list", [ IsList and IsMutable, IsObject ], - ADD_LIST_DEFAULT ); + function ( list, obj ) + list[ LEN_LIST(list)+1 ] := obj; +end ); InstallMethod( Add, "three arguments fast version", [ IsPlistRep and IsList and IsMutable, IsObject, IsPosInt], diff --git a/lib/system.g b/lib/system.g index d3c5e5b110..bc763b0fc8 100644 --- a/lib/system.g +++ b/lib/system.g @@ -334,14 +334,14 @@ CallAndInstallPostRestore( function() for i in [1..LENGTH(GAPInfo.SystemEnvironment.PATH)] do if GAPInfo.SystemEnvironment.PATH[i] = ':' then if i > j then - ADD_LIST_DEFAULT(GAPInfo.DirectoriesSystemPrograms, + ADD_LIST(GAPInfo.DirectoriesSystemPrograms, MakeImmutable(GAPInfo.SystemEnvironment.PATH{[j..i-1]})); fi; j := i+1; fi; od; if j <= LENGTH( GAPInfo.SystemEnvironment.PATH ) then - ADD_LIST_DEFAULT( GAPInfo.DirectoriesSystemPrograms, + ADD_LIST( GAPInfo.DirectoriesSystemPrograms, MakeImmutable(GAPInfo.SystemEnvironment.PATH{ [ j .. LENGTH( GAPInfo.SystemEnvironment.PATH ) ] } )); fi; @@ -385,7 +385,7 @@ CallAndInstallPostRestore( function() CommandLineOptions.( opt ):= CommandLineOptions.( opt ) + 1; elif i <= LENGTH( line ) then if opt = "c" then - ADD_LIST_DEFAULT( InitFiles, rec( command := line[i] ) ); + ADD_LIST( InitFiles, rec( command := line[i] ) ); i := i+1; elif IS_STRING_REP( value ) then # string @@ -393,7 +393,7 @@ CallAndInstallPostRestore( function() i := i+1; elif IS_LIST( value ) then # list of strings, starting from the empty list - ADD_LIST_DEFAULT( CommandLineOptions.( opt ), line[i] ); + ADD_LIST( CommandLineOptions.( opt ), line[i] ); i := i+1; fi; else @@ -401,7 +401,7 @@ CallAndInstallPostRestore( function() fi; fi; else - ADD_LIST_DEFAULT( InitFiles, word ); + ADD_LIST( InitFiles, word ); fi; od; CommandLineOptions.g:= CommandLineOptions.g mod 3; From 8264428e340b55db3dd00b91f7b8185b5067406f Mon Sep 17 00:00:00 2001 From: Max Horn Date: Mon, 13 Apr 2026 13:41:00 +0200 Subject: [PATCH 148/234] Allow CopySubVector on plain row vectors, fix CopySubMatrix (#6309) --- lib/matobj.gi | 20 +++-- lib/matobj2.gd | 6 +- tst/testinstall/MatrixObj/CopySubMatrix.tst | 84 +++++++++++++++++++++ tst/testinstall/MatrixObj/CopySubVector.tst | 24 ++++++ 4 files changed, 125 insertions(+), 9 deletions(-) create mode 100644 tst/testinstall/MatrixObj/CopySubMatrix.tst diff --git a/lib/matobj.gi b/lib/matobj.gi index f80b705319..652dddccad 100644 --- a/lib/matobj.gi +++ b/lib/matobj.gi @@ -775,13 +775,13 @@ function( m, poss1, poss2 ) end ); InstallMethod( CopySubVector, - "generic method for vector objects", - [ IsVectorObj, IsVectorObj and IsMutable, IsList, IsList ], + "generic method for row vectors and vector objects", + [ IsRowVectorOrVectorObj, IsRowVectorOrVectorObj and IsMutable, + IsList, IsList ], function(src, dst, scols, dcols) local i; - if not Length( dcols ) = Length( scols ) then - Error( "source and destination index lists must be of equal length" ); - return; + if Length( dcols ) <> Length( scols ) then + ErrorNoReturn( "source and destination index lists must be of equal length" ); fi; for i in [ 1 .. Length( dcols ) ] do dst[dcols[i]] := src[scols[i]]; @@ -1258,10 +1258,18 @@ InstallMethod( MutableCopyMatrix, #M CopySubMatrix( , , , , , ) ## InstallMethod( CopySubMatrix, - [ IsMatrixOrMatrixObj and IsMutable, IsMatrixOrMatrixObj, IsList, IsList, IsList, IsList ], + [ IsMatrixOrMatrixObj, IsMatrixOrMatrixObj and IsMutable, + IsList, IsList, IsList, IsList ], function( src, dst, srcrows, dstrows, srccols, dstcols ) local i, j; + if Length( dstrows ) <> Length( srcrows ) then + ErrorNoReturn( "source and destination row lists must be of equal length" ); + fi; + if Length( dstcols ) <> Length( srccols ) then + ErrorNoReturn( "source and destination column lists must be of equal length" ); + fi; + for i in [ 1 .. Length( srcrows ) ] do for j in [ 1 .. Length( srccols ) ] do dst[ dstrows[i], dstcols[j] ]:= src[ srcrows[i], srccols[j] ]; diff --git a/lib/matobj2.gd b/lib/matobj2.gd index 6b21e5f775..b564dd01e7 100644 --- a/lib/matobj2.gd +++ b/lib/matobj2.gd @@ -875,7 +875,7 @@ DeclareOperation( "Randomize", [ IsRandomSource, IsMatrixOrMatrixObj and IsMutab ## nothing ## ## -## For two vector objects src and dst, +## For two row vectors or vector objects src and dst, ## such that dst is mutable, ## and two lists scols and dcols of positions, ## assigns the entries @@ -897,8 +897,8 @@ DeclareOperation( "Randomize", [ IsRandomSource, IsMatrixOrMatrixObj and IsMutab ## <#/GAPDoc> ## DeclareOperation( "CopySubVector", - [ IsVectorObj, IsVectorObj and IsMutable, IsList, IsList ] ); - + [ IsRowVectorOrVectorObj, IsRowVectorOrVectorObj and IsMutable, + IsList, IsList ] ); ############################################################################# diff --git a/tst/testinstall/MatrixObj/CopySubMatrix.tst b/tst/testinstall/MatrixObj/CopySubMatrix.tst new file mode 100644 index 0000000000..1563c98495 --- /dev/null +++ b/tst/testinstall/MatrixObj/CopySubMatrix.tst @@ -0,0 +1,84 @@ +#@local m1, m2, m3, m4, m5, AsDummyMatrix, DummyMatrixAsList +gap> START_TEST("CopySubMatrix.tst"); +gap> DeclareRepresentation( "IsDummyCopySubMatrixRep6305", +> IsComponentObjectRep and IsAttributeStoringRep and IsMatrixObj, [] ); +gap> InstallMethod( BaseDomain, +> [ IsDummyCopySubMatrixRep6305 ], +> M -> M!.basedomain ); +gap> InstallMethod( NumberRows, +> [ IsDummyCopySubMatrixRep6305 ], +> M -> Length( M!.entries ) ); +gap> InstallMethod( NumberColumns, +> [ IsDummyCopySubMatrixRep6305 ], +> M -> Length( M!.entries[1] ) ); +gap> InstallMethod( \[\], +> [ IsDummyCopySubMatrixRep6305, IsPosInt, IsPosInt ], +> function( M, row, col ) +> return M!.entries[row][col]; +> end ); +gap> InstallMethod( \[\]\:\=, +> [ IsDummyCopySubMatrixRep6305 and IsMutable, IsPosInt, IsPosInt, IsObject ], +> function( M, row, col, obj ) +> M!.entries[row][col] := obj; +> end ); +gap> AsDummyMatrix := function( entries, mutable ) +> local filt, M; +> filt := IsDummyCopySubMatrixRep6305; +> if mutable then +> filt := filt and IsMutable; +> fi; +> M := Objectify( +> NewType( CollectionsFamily( CollectionsFamily( FamilyObj( Zero( Rationals ) ) ) ), +> filt ), +> rec( +> basedomain := Rationals, +> entries := StructuralCopy( entries ) ) ); +> if not mutable then +> MakeImmutable( M!.entries ); +> fi; +> return M; +> end;; +gap> DummyMatrixAsList := function( M ) +> return List( [ 1 .. NumberRows( M ) ], +> i -> List( [ 1 .. NumberColumns( M ) ], j -> M[i, j] ) ); +> end;; + +# +gap> m1 := [ [ 1, 2, 3 ], [ 4, 5, 6 ] ]; +[ [ 1, 2, 3 ], [ 4, 5, 6 ] ] +gap> m2 := [ [ 0, 0, 0, 0 ], [ 0, 0, 0, 0 ], [ 0, 0, 0, 0 ] ]; +[ [ 0, 0, 0, 0 ], [ 0, 0, 0, 0 ], [ 0, 0, 0, 0 ] ] +gap> CopySubMatrix( m1, m2, [ 2, 1 ], [ 1, 3 ], [ 3, 1 ], [ 2, 4 ] ); +gap> m2; +[ [ 0, 6, 0, 4 ], [ 0, 0, 0, 0 ], [ 0, 3, 0, 1 ] ] + +# +gap> m3 := AsDummyMatrix( +> [ [ 0, 0, 0, 0 ], [ 0, 0, 0, 0 ], [ 0, 0, 0, 0 ] ], true );; +gap> CopySubMatrix( m1, m3, [ 1, 2 ], [ 2, 3 ], [ 2, 3 ], [ 4, 1 ] ); +gap> DummyMatrixAsList(m3); +[ [ 0, 0, 0, 0 ], [ 3, 0, 0, 2 ], [ 6, 0, 0, 5 ] ] + +# +gap> m4 := [ [ 0, 0, 0, 0 ], [ 0, 0, 0, 0 ], [ 0, 0, 0, 0 ] ]; +[ [ 0, 0, 0, 0 ], [ 0, 0, 0, 0 ], [ 0, 0, 0, 0 ] ] +gap> CopySubMatrix( m3, m4, [ 3, 2 ], [ 1, 2 ], [ 1, 4 ], [ 3, 2 ] ); +gap> m4; +[ [ 0, 5, 6, 0 ], [ 0, 2, 3, 0 ], [ 0, 0, 0, 0 ] ] + +# +gap> m5 := AsDummyMatrix( m1, false );; +gap> CopySubMatrix( m5, m4, [ 2, 1 ], [ 2, 3 ], [ 2, 1 ], [ 1, 4 ] ); +gap> m4; +[ [ 0, 5, 6, 0 ], [ 5, 2, 3, 4 ], [ 2, 0, 0, 1 ] ] + +# +gap> CopySubMatrix( m5, m4, [ 1, 2 ], [ 1 ], [ 1 ], [ 1 ] ); +Error, source and destination row lists must be of equal length + +# +gap> CopySubMatrix( m5, m4, [ 1 ], [ 1 ], [ 1, 2 ], [ 1 ] ); +Error, source and destination column lists must be of equal length + +# +gap> STOP_TEST("CopySubMatrix.tst"); diff --git a/tst/testinstall/MatrixObj/CopySubVector.tst b/tst/testinstall/MatrixObj/CopySubVector.tst index 688bca39b4..5c702e6089 100644 --- a/tst/testinstall/MatrixObj/CopySubVector.tst +++ b/tst/testinstall/MatrixObj/CopySubVector.tst @@ -1,4 +1,5 @@ #@local l1, v1, l2, v2, v3, v4, x, src, dst, expected, from, to, len, one +#@local l3, l4 gap> START_TEST("CopySubVector.tst"); # @@ -14,6 +15,18 @@ gap> CopySubVector( v2, v1, [1,2,4], [2,4,6] ); gap> Unpack(v1); [ 1, 1, 3, 1, 5, 2 ] +# +gap> l3 := [10,20,30,40,50,60]; +[ 10, 20, 30, 40, 50, 60 ] +gap> CopySubVector( l1, l3, [1,3,5], [6,4,2] ); +gap> l3; +[ 10, 5, 30, 3, 50, 1 ] + +# +gap> CopySubVector( l1, v1, [2,4,6], [1,3,5] ); +gap> Unpack(v1); +[ 2, 1, 4, 1, 6, 2 ] + # gap> v3 := Vector(GF(5), l1*One(GF(5))); [ Z(5)^0, Z(5), Z(5)^3, Z(5)^2, 0*Z(5), Z(5)^0 ] @@ -57,5 +70,16 @@ gap> for from in [1,2,63,64,65] do > od; > od; +# +gap> l4 := [0,0,0,0,0,0,0,0,0]; +[ 0, 0, 0, 0, 0, 0, 0, 0, 0 ] +gap> CopySubVector( v3, l4, [1,2,3], [2,4,6] ); +gap> l4; +[ 0, Z(5)^0, 0, Z(5), 0, Z(5)^3, 0, 0, 0 ] + +# +gap> CopySubVector( l1, l3, [1,2], [1] ); +Error, source and destination index lists must be of equal length + # gap> STOP_TEST("CopySubVector.tst"); From 9617fe72a0aa0b8a87af49510cec33224e51bedc Mon Sep 17 00:00:00 2001 From: Max Horn Date: Tue, 14 Apr 2026 15:43:47 +0200 Subject: [PATCH 149/234] Declare NumberRows and NumberColumns as kernel attributes (#6318) ... and provide optimized kernel methods for plist matrices Before: gap> m:=IdentityMat(4500);; List([1..10000], i -> NrRows(m));; time; 2044 gap> m:=IdentityMatrix(GF(2), 4500);; List([1..10000], i -> NrRows(m));; time; 1 gap> m:=IdentityMatrix(GF(37), 4500);; List([1..10000], i -> NrRows(m));; time; 1 gap> m:=IdentityMatrix(Rationals, 4500);; List([1..10000], i -> NrRows(m));; time; 1 After: gap> m:=IdentityMat(4500);; List([1..10000], i -> NrRows(m));; time; 1 gap> m:=IdentityMatrix(GF(2), 4500);; List([1..10000], i -> NrRows(m));; time; 1 gap> m:=IdentityMatrix(GF(37), 4500);; List([1..10000], i -> NrRows(m));; time; 1 gap> m:=IdentityMatrix(Rationals, 4500);; List([1..10000], i -> NrRows(m));; time; 1 Co-authored-by: Codex --- lib/matobj1.gd | 6 ++++-- src/lists.c | 39 ++++++++++++++++++++++++++++++++++++++ tst/testinstall/matrix.tst | 4 ++++ 3 files changed, 47 insertions(+), 2 deletions(-) diff --git a/lib/matobj1.gd b/lib/matobj1.gd index 6b97b19a99..ff53201b9c 100644 --- a/lib/matobj1.gd +++ b/lib/matobj1.gd @@ -321,11 +321,13 @@ DeclareAttribute( "BaseDomain", IsVecOrMatObj ); ## ## <#/GAPDoc> ## -DeclareAttribute( "NumberRows", IsMatrixOrMatrixObj ); +DeclareAttributeKernel( "NumberRows", IsMatrixOrMatrixObj, NUMBER_ROWS ); DeclareSynonymAttr( "NrRows", NumberRows ); +InstallTrueMethod( HasNumberRows, IsMatrixOrMatrixObj and IsPlistRep); -DeclareAttribute( "NumberColumns", IsMatrixOrMatrixObj ); +DeclareAttributeKernel( "NumberColumns", IsMatrixOrMatrixObj, NUMBER_COLUMNS ); DeclareSynonymAttr( "NrCols", NumberColumns ); +InstallTrueMethod( HasNumberColumns, IsMatrixOrMatrixObj and IsPlistRep ); ############################################################################# diff --git a/src/lists.c b/src/lists.c index beed2d5149..bc1b4a7589 100644 --- a/src/lists.c +++ b/src/lists.c @@ -81,6 +81,8 @@ BOOL (*IsSmallListFuncs[LAST_REAL_TNUM + 1])(Obj obj); static Obj IsSmallListFilt; static Obj HasIsSmallListFilt; static Obj LengthAttr; +static Obj NumberRowsAttr; +static Obj NumberColumnsAttr; static Obj SetIsSmallList; static BOOL IsSmallListObject(Obj obj) @@ -163,6 +165,41 @@ static Obj AttrLENGTH(Obj self, Obj list) } +/**************************************************************************** +** +*F AttrNUMBER_ROWS( , ) . . . . . . 'NumberRows' interface +*/ +static Obj AttrNUMBER_ROWS(Obj self, Obj mat) +{ + if (IS_PLIST(mat)) { + return ObjInt_Int(LEN_PLIST(mat)); + } + + return DoAttribute(NumberRowsAttr, mat); +} + + +/**************************************************************************** +** +*F AttrNUMBER_COLUMNS( , ) . . . . 'NumberColumns' interface +*/ +static Obj AttrNUMBER_COLUMNS(Obj self, Obj mat) +{ + if (IS_PLIST(mat)) { + if (LEN_PLIST(mat) == 0) { + return INTOBJ_INT(0); + } + + Obj row = ELM_PLIST(mat, 1); + if (row != 0) { + return AttrLENGTH(LengthAttr, row); + } + } + + return DoAttribute(NumberColumnsAttr, mat); +} + + /**************************************************************************** ** *F LEN_LIST() . . . . . . . . . . . . . . . . . . . length of a list @@ -1874,6 +1911,8 @@ static StructGVarFilt GVarFilts [] = { static StructGVarAttr GVarAttrs [] = { GVAR_ATTR(LENGTH, "list", &LengthAttr), + GVAR_ATTR(NUMBER_ROWS, "mat", &NumberRowsAttr), + GVAR_ATTR(NUMBER_COLUMNS, "mat", &NumberColumnsAttr), { 0, 0, 0, 0, 0 } }; diff --git a/tst/testinstall/matrix.tst b/tst/testinstall/matrix.tst index e633885f6f..9876343a2d 100644 --- a/tst/testinstall/matrix.tst +++ b/tst/testinstall/matrix.tst @@ -200,6 +200,10 @@ false # gap> m := Z(5)^0 * [[0, 1], [1, 0]];; +gap> HasNumberRows(m); +true +gap> HasNumberColumns(m); +true gap> m := GeneratorsWithMemory([m])[1];; gap> BaseDomain(m) = GF(5); true From c35d5e9373e3a7e4497592de0f24e089e12a6af4 Mon Sep 17 00:00:00 2001 From: Max Horn Date: Wed, 15 Apr 2026 10:37:21 +0200 Subject: [PATCH 150/234] matobj: remove redundant code, use BindConstant (#6321) --- lib/matobjnz.gi | 18 +++--------------- lib/matobjplist.gd | 12 ++++++------ lib/matobjplist.gi | 4 ---- 3 files changed, 9 insertions(+), 25 deletions(-) diff --git a/lib/matobjnz.gi b/lib/matobjnz.gi index 60fcadff4b..c2edf17d3a 100644 --- a/lib/matobjnz.gi +++ b/lib/matobjnz.gi @@ -688,27 +688,15 @@ InstallTagBasedMethod( NewIdentityMatrix, InstallOtherMethod( BaseDomain, "for a zmodnz matrix", [ IsZmodnZMatrixRep ], - function( m ) - return m![BDPOS]; - end ); + M -> M![BDPOS] ); InstallMethod( NumberRows, "for a zmodnz matrix", [ IsZmodnZMatrixRep ], - function( m ) - return Length(m![ROWSPOS]); - end ); + M -> Length( M![ROWSPOS] ) ); InstallMethod( NumberColumns, "for a zmodnz matrix", [ IsZmodnZMatrixRep ], - function( m ) - return m![RLPOS]; - end ); - -# InstallMethod( DimensionsMat, "for a zmodnz matrix", -# [ IsZmodnZMatrixRep ], -# function( m ) -# return [Length(m![ROWSPOS]),m![RLPOS]]; -# end ); + M -> M![RLPOS] ); ############################################################################ diff --git a/lib/matobjplist.gd b/lib/matobjplist.gd index 58d701063d..087d5b0330 100644 --- a/lib/matobjplist.gd +++ b/lib/matobjplist.gd @@ -114,14 +114,14 @@ DeclareRepresentation( "IsPlistMatrixRep", Add( ConstructingFiltersForMatrixGroupElements, IsPlistMatrixRep ); # Some constants for matrix access: -BindGlobal( "BDPOS", 1 ); -BindGlobal( "EMPOS", 2 ); -BindGlobal( "RLPOS", 3 ); -BindGlobal( "ROWSPOS", 4 ); +BindConstant( "BDPOS", 1 ); +BindConstant( "EMPOS", 2 ); +BindConstant( "RLPOS", 3 ); +BindConstant( "ROWSPOS", 4 ); # For vector access: -#BindGlobal( "BDPOS", 1 ); # see above -BindGlobal( "ELSPOS", 2 ); +#BindConstant( "BDPOS", 1 ); # see above +BindConstant( "ELSPOS", 2 ); # Two filters to speed up some methods: DeclareFilter( "IsIntVector" ); diff --git a/lib/matobjplist.gi b/lib/matobjplist.gi index 7a1b99f4d4..cafe1dd7d6 100644 --- a/lib/matobjplist.gi +++ b/lib/matobjplist.gi @@ -635,10 +635,6 @@ InstallMethod( NumberColumns, [ "IsPlistMatrixRep" ], M -> M![RLPOS] ); -InstallMethod( DimensionsMat, - [ "IsPlistMatrixRep" ], - M -> [ Length( M![ROWSPOS]), M![RLPOS] ] ); - ############################################################################ # Representation preserving constructors: From e2df6905114c011d78b1a3ef2b8f8bf72c91f90d Mon Sep 17 00:00:00 2001 From: Max Horn Date: Thu, 16 Apr 2026 01:39:33 +0200 Subject: [PATCH 151/234] Make RowLength obsolete (#6323) Co-authored-by: Codex --- lib/matobj2.gd | 2 -- lib/obsolete.gd | 9 +++++++++ 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/lib/matobj2.gd b/lib/matobj2.gd index b564dd01e7..c7cd9f0c4a 100644 --- a/lib/matobj2.gd +++ b/lib/matobj2.gd @@ -1790,12 +1790,10 @@ DeclareAttribute( "DimensionsMat", IsMatrixOrMatrixObj ); ############################################################################# ## #A Length( ) -#A RowLength( ) ## ## They had been used in older versions. ## DeclareAttribute( "Length", IsMatrixOrMatrixObj ); -DeclareSynonymAttr( "RowLength", NumberColumns ); ############################################################################# diff --git a/lib/obsolete.gd b/lib/obsolete.gd index 61e774a0b1..aa8fc1880e 100644 --- a/lib/obsolete.gd +++ b/lib/obsolete.gd @@ -249,6 +249,15 @@ DeclareSynonym( "FirstOp", First ); DeclareObsoleteSynonym( "RadicalGroup", "SolvableRadical" ); +############################################################################# +## +#A RowLength( ) +## +## Moved to obsolete in April 2026. +## +DeclareObsoleteSynonymAttr( "RowLength", "NumberColumns", 1 ); + + ############################################################################# ## #F SCRSiftOld( , ) From ee6726767f951085a21cbc4ef39cc348d6f51c28 Mon Sep 17 00:00:00 2001 From: Thomas Breuer Date: Thu, 16 Apr 2026 16:37:13 +0200 Subject: [PATCH 152/234] Add a manual section: how to write code for matrix objects (#6320) --- doc/ref/matobj.xml | 153 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 153 insertions(+) diff --git a/doc/ref/matobj.xml b/doc/ref/matobj.xml index 8ed8908e47..2818815902 100644 --- a/doc/ref/matobj.xml +++ b/doc/ref/matobj.xml @@ -402,4 +402,157 @@ The following conventions hold for such a group G. + +

+How to Write Code for Vector and Matrix Objects + +Vector and matrix objects have a number of different representations in &GAP; +which are optimised for different things; +see the list for +examples of available + values +of matrix objects. +Most &GAP; functions accepting vector or matrix objects as arguments +do not depend on any particular representation for these objects. +If the output of such a function involves vector and matrix objects, +then these are expected to have the same representations as the inputs. +For example, a function that computes the Kronecker product of two +matrix objects mat1, mat2 may take the two inputs, +which must have the same + value, +create a new matrix object which also lies in this filter, +for example by calling ZeroMatrix( m, n, mat1 ), +and then set the entries in this matrix. + +

+ +Functions like +, +, +and +admit different kinds of inputs. +ZeroMatrix( R, m, n ) can be used, for example, +if we want to leave the decision about the representation of the result +to &GAP;. +This might be useful if the result of ZeroMatrix( R, m, n ) is +the first matrix we create, and then later matrices are created +relative to this matrix. +If we already have a matrix object M and want ZeroMatrix +to return a new matrix object that has the same representation as M, +then ZeroMatrix( R, m, n ) may not return a matrix with the expected +representation. +For example, even if we use the same R as before, &GAP; might decide +to use a sparse representation for large enough m and n. +It is possible to create a ZeroMatrix in the same representation +as M by fully specifying this representation as follows +ZeroMatrix( ConstructingFilter( M ), BaseDomain( M ), m, n ). +It is also possible to produce the same result using the more convenient +ZeroMatrix( m, n, M ). + +

+ +This approach works also in many situation where the input involves +the list of list matrices in the filter . +In practice, the question is often the other way round: +one has old &GAP; code that was written for objects in , +and wants to rewrite it such that it works for general matrix objects also. +In such cases, the following guidelines may be useful. + + + + Use M[i, j] not M[i][j] + for accessing/assigning matrix entries. +

+ Reason: + M[i][j] means to fetch or even create M[i] + and then take the j-th entry of it. + + + Use ExtractSubMatrix( M, rows, cols ) not M{ rows }{ cols } + for accessing submatrices, + similarly use CopySubMatrix( src, dst, srows, drows, scols, dcols ). +

+ Reason: + The M{ rows } syntax is supported only for + row-list matrices, see . + + + Use ZeroVector( R, n ) not [ 1 .. n ] * Zero( R ) for + creating a zero vector over a given domain R. +

+ Reason: + The latter syntax creates an unnecessary new object [ 1 .. n ], + multiplies each of its entries with Zero( R ) + (not knowing that the result will be Zero( R ) in each case), + and creates not a vector object but a plain list of the results. + + + Use ZeroVector( n, M ) not 0 * M[1] for a + given matrix object M with n columns. +

+ Reason: + Calling M[1] may have to create an unnecessary new object + M[1]. + + + Use + not . +

+ Reason: + This is just a conceptual issue, the results should in fact coincide. + A matrix object M which is not a list of lists stores its + value. + For convenience, DefaultFieldOfMatrix( M ) is defined + to return this value (although this need not be a field). + On the other hand, a list of lists M in + does not store the two attribute values, + value is computed from the entries + of M, + and for convenience, BaseDomain( M ) is defined to return the + value. + + + Do not use the unary versions of + + and . +

+ Reason: + For example, consider the two matrices M1 = [ [ Z(4) ] ] and + M2 = [ [ Z(4)^3 ] ] over the field with four elements. + The latter is in fact a matrix over the field with two elements, + and ConvertToMatrixRep( M2 ) turns it into a matrix in + , whereas ConvertToMatrixRep( M1 ) + yields a matrix in . + Thus computing products or sums of these matrices is more expensive + than computations with two matrices in . + + + Use and the binary versions of + + and + only when creating initial objects + which need not be compatible with given vectors or matrices. +

+ Reason: + The idea behind these functions is to choose a good representation + for initial data (for example for some expensive MeatAxe computations, + see Chapter ). + The results of computations with these data should then automatically + be in the same representation. + If not then the code in question has problems, + and adjusting the representation of intermediate results by + calling the abovementioned conversion functions just hides these problems. + + + +Conversely, do not use functions for vector and matrix objects +when you want to create an object that shall be used just as a list. +For example, use ListWithIdenticalEntries( n, Zero( R ) ) +not Vector( R, n ) in this case. +For creating a list with n entries, you can also first call + for creating a big enough list, +and then enter the values. + +

+ From e3c15ce053112527170f5574e2f96a80a87ee31f Mon Sep 17 00:00:00 2001 From: Max Horn Date: Fri, 17 Apr 2026 12:07:05 +0200 Subject: [PATCH 153/234] Remove AsPlist (#6327) This was almost the same as PlainListCopy, but slower. Since it was an undocumented internal helper and not used in any package, we simply remove it. --- hpcgap/demo/orbit2.g | 62 +++++++++++++++++++++------------------ hpcgap/lib/vec8bit.gi | 4 +-- hpcgap/lib/vecmat.gi | 4 +-- lib/coll.gi | 4 +-- lib/dicthf.gi | 2 +- lib/list.gd | 17 ----------- lib/list.gi | 28 ++---------------- lib/vec8bit.gi | 4 +-- lib/vecmat.gi | 4 +-- tst/testinstall/range.tst | 2 +- 10 files changed, 48 insertions(+), 83 deletions(-) diff --git a/hpcgap/demo/orbit2.g b/hpcgap/demo/orbit2.g index e23c43321c..8213c50de3 100644 --- a/hpcgap/demo/orbit2.g +++ b/hpcgap/demo/orbit2.g @@ -9,12 +9,12 @@ # For the actually new points and their ids act on them by all the generators # make a list of triples: pt, parent id, gen used and cut it into blocks of # some suitable size. Run task on each block - + # # # dict is a thread-safe data structure (blocked hash table perhaps) -# it supports AddOrLookup(dict, obj) +# it supports AddOrLookup(dict, obj) # if obj is in dict already, it returns the id assigned when obj was added # if obj is not already in dict, it returns -(a new id) # The IDs are small positive ints, and while they may not be contiguous they shouldn't be too huge. @@ -27,12 +27,12 @@ NHASHTABLES := 17; newSplitHashTableDict := function(hash1, hash2, npieces, magic) local r, tables, t, i; - r := rec(npieces := npieces, hash1 := hash1, hash2 := hash2, magic := magic, + r := rec(npieces := npieces, hash1 := hash1, hash2 := hash2, magic := magic, tables := []); for i in [1..npieces] do - r.tables[i] := rec(next := 1 + (i-1)*magic, top := i*magic, table := + r.tables[i] := rec(next := 1 + (i-1)*magic, top := i*magic, table := SparseHashTable(hash2)); - + od; for t in r.tables do ShareObj(t); @@ -42,7 +42,7 @@ newSplitHashTableDict := function(hash1, hash2, npieces, magic) end; # -# Two approaches to managing the hash tables. +# Two approaches to managing the hash tables. # optimum might well be to switch from 1 to 2 # once the rediscovery rate gets high enough. # @@ -78,7 +78,7 @@ SHTaddOrLookup2 := function(dict, obj) if ht = fail then atomic readwrite t do ht := GetHashEntry(t.table,obj); - if ht = fail then + if ht = fail then ht := t.next; t.next := t.next+1; if t.next > t.top then @@ -89,7 +89,7 @@ SHTaddOrLookup2 := function(dict, obj) return -ht; fi; od; - + fi; return ht; end; @@ -105,7 +105,7 @@ task := function( points, parentids, gennos, gens, action, dict, addOrLookup, re MakeImmutable(parents); MakeImmutable(ngennos); ATOMIC_ADDITION(l,1,1); - ATOMIC_ADDITION(l,2,1); + ATOMIC_ADDITION(l,2,1); RunAsyncTask(task, npts, parents, ngennos, gens, action, dict, addOrLookup, record, l, sem); end; npts := []; @@ -130,8 +130,8 @@ task := function( points, parentids, gennos, gens, action, dict, addOrLookup, re od; if Length(parents) > 0 then emit(); - fi; - + fi; + ATOMIC_ADDITION(l,1,-1); if l[1] = 0 then SignalSemaphore(sem); @@ -154,7 +154,7 @@ HTaddOrLookup := function(ht, obj) return res; end; - + seqorb := function( seeds, gens, action, dict, addOrLookup, record) local queue, qids, i, ngens, pt, npt, newid,j ; @@ -177,9 +177,9 @@ seqorb := function( seeds, gens, action, dict, addOrLookup, record) od; end; - - - + + + parorb := function( seeds, gens, action, dict, addOrLookup, record) local l, sem, fakes; l := FixedAtomicList([0,0]); @@ -187,20 +187,24 @@ parorb := function( seeds, gens, action, dict, addOrLookup, record) seeds := Immutable(seeds); fakes := `List(seeds, s->fail); ATOMIC_ADDITION(l, 1, 1); - ATOMIC_ADDITION(l,2,1); + ATOMIC_ADDITION(l,2,1); RunAsyncTask(task, seeds, fakes, fakes, gens, action, dict, addOrLookup, record, l, sem); # while true do Print(l[1]," ",l[2],"\n"); # od; if l[1] > 0 then WaitSemaphore(sem); fi; - + return l[2]; end; -hash := function(s) +hash := function(s) local sp; - sp := AsPlist(s); + if IsPlistRep(x) then + sp := s; + else + sp := PlainListCopy(s); + fi; return HashKeyBag(sp, 0,0,SIZE_OBJ(sp)); end; @@ -252,35 +256,35 @@ actionViaParOrb := function(seeds, gens, action, hash) return realacts; end; - + m24trial := function() local d, gens, orb; orb := AtomicList([]); d := newSplitHashTableDict(x->x, x->x, NHASHTABLES, 100); gens := GeneratorsOfGroup(MathieuGroup(24)); - parorb([1], gens, OnPoints, d, SHTaddOrLookup, function(a,b,c) + parorb([1], gens, OnPoints, d, SHTaddOrLookup, function(a,b,c) end); return keysOfSHT(d); - + end; m24trialn := function(n) local d, gens; d := newSplitHashTableDict(hash, hash, NHASHTABLES, 100); gens := GeneratorsOfGroup(MathieuGroup(24)); - parorb([`[1..n]], gens, OnSets, d, SHTaddOrLookup, function(a,b,c) + parorb([`[1..n]], gens, OnSets, d, SHTaddOrLookup, function(a,b,c) end); return keysOfSHT(d); - + end; m24seqtrialn := function(n) local d, gens, orb; orb := []; - d := SeqDict(hash); + d := SeqDict(hash); gens := GeneratorsOfGroup(MathieuGroup(24)); - seqorb([AsPlist([1..n])], gens, OnSets, d, HTaddOrLookup, function(a,b,c) + seqorb([PlainListCopy([1..n])], gens, OnSets, d, HTaddOrLookup, function(a,b,c) end); return Filtered(d.table!.KeyArray, x->x<>fail); end; @@ -288,8 +292,8 @@ end; m24act := function(n) local gens; gens := GeneratorsOfGroup(MathieuGroup(24)); - return actionViaParOrb([`AsPlist([1..n])], gens, OnSets, hash); + return actionViaParOrb([`PlainListCopy([1..n])], gens, OnSets, hash); end; - - + + diff --git a/hpcgap/lib/vec8bit.gi b/hpcgap/lib/vec8bit.gi index 23026afd55..1e9bdd5b4d 100644 --- a/hpcgap/lib/vec8bit.gi +++ b/hpcgap/lib/vec8bit.gi @@ -1096,11 +1096,11 @@ InstallMethodWithRandomSource( Randomize, InstallMethod( Unpack, "for an 8bit matrix", [Is8BitMatrixRep], function( m ) - return List(m,AsPlist); + return List(m, PlainListCopy); end ); InstallMethod( Unpack, "for an 8bit vector", [Is8BitVectorRep], - AsPlist ); + PlainListCopy ); InstallOtherMethod( KroneckerProduct, "for two 8bit matrices", # priority to kernel code, if matrices have same field [Is8BitMatrixRep and IsMatrix, Is8BitMatrixRep and IsMatrix], 1, diff --git a/hpcgap/lib/vecmat.gi b/hpcgap/lib/vecmat.gi index e61616fe2d..6c24ce83ec 100644 --- a/hpcgap/lib/vecmat.gi +++ b/hpcgap/lib/vecmat.gi @@ -2538,11 +2538,11 @@ InstallMethodWithRandomSource( Randomize, InstallMethod( Unpack, "for a gf2 matrix", [IsGF2MatrixRep], function( m ) - return List(m,AsPlist); + return List(m, PlainListCopy); end ); InstallMethod( Unpack, "for a gf2 vector", [IsGF2VectorRep], - AsPlist ); + PlainListCopy ); InstallOtherMethod( KroneckerProduct, "for two gf2 matrices", [IsGF2MatrixRep and IsMatrix, IsGF2MatrixRep and IsMatrix], diff --git a/lib/coll.gi b/lib/coll.gi index d49848c5ca..6736ccf5a8 100644 --- a/lib/coll.gi +++ b/lib/coll.gi @@ -315,10 +315,10 @@ InstallMethod( AsSSortedList, [ IsCollection ], coll -> ConstantTimeAccessList( EnumeratorSorted( coll ) ) ); -InstallOtherMethod( AsSSortedList, +InstallMethod( AsSSortedList, "for a collection that is a constant time access list", [ IsCollection and IsConstantTimeAccessList ], - l->AsSSortedListList(AsPlist(l)) ); + l->AsSSortedListList(PlainListCopy(l)) ); ############################################################################# ## diff --git a/lib/dicthf.gi b/lib/dicthf.gi index a1a6e8a85e..7347144911 100644 --- a/lib/dicthf.gi +++ b/lib/dicthf.gi @@ -162,7 +162,7 @@ function(m, v) return function(x) Assert(1, IsPositionsList(x)); if not IsPlistRep(x) then - x := AsPlist(x); + x := PlainListCopy(x); fi; return HashKeyBag(x, 1, 0, Length(x) * GAPInfo.BytesPerVariable); end; diff --git a/lib/list.gd b/lib/list.gd index b048bdec72..5a44805bae 100644 --- a/lib/list.gd +++ b/lib/list.gd @@ -362,23 +362,6 @@ DeclareAttribute( "ConstantTimeAccessList", IsList ); DeclareSynonym( "AsSSortedListList", AS_LIST_SORTED_LIST ); -############################################################################# -## -#A AsPlist( ) -## -## -## -## -## -## returns a list in the representation -## that is equal to the list l. -## It is used before calling kernel functions to sort plists. -## -## -## -DeclareOperation( "AsPlist", [IsListOrCollection] ); - - ############################################################################# ## #C IsDenseList( ) diff --git a/lib/list.gi b/lib/list.gi index fe857a3391..883ae09dd4 100644 --- a/lib/list.gi +++ b/lib/list.gi @@ -630,28 +630,6 @@ InstallOtherMethod( AsList, Immutable ); -############################################################################# -## -#M AsPlist( ) -## -InstallOtherMethod( AsPlist, - "for a plist", - [IsList and IsPlistRep], - x -> x ); - -InstallOtherMethod( AsPlist, - "for a list", - [ IsList ], - function(l) - l:=AsList(l); - if not IsPlistRep(l) then - l:=PlainListCopy(l); # explicit copy for objects that claim to - # be constant time access but not plists. - fi; - return l; - end ); - - ############################################################################# ## #M AsSSortedList( ) @@ -672,7 +650,7 @@ InstallOtherMethod(AsSSortedList, InstallOtherMethod(AsSSortedList, "for a list", [ IsList ], - l -> AsSSortedListList( AsPlist( l ) ) ); + l -> AsSSortedListList( PlainListCopy( l ) ) ); InstallMethod( AsSSortedList, "for a strictly sorted list", @@ -710,7 +688,7 @@ function(l) if IsSSortedList(l) then return l; fi; - return AsSSortedListList(AsPlist(l)); + return AsSSortedListList(PlainListCopy(l)); end); @@ -724,7 +702,7 @@ InstallMethod( SSortedList, "for a plist", InstallMethod( SSortedList, "for a list", [ IsList ], - l->SSortedListList(AsPlist(l)) ); + l->SSortedListList(PlainListCopy(l)) ); ############################################################################# diff --git a/lib/vec8bit.gi b/lib/vec8bit.gi index 4766945be6..5d4cddcae1 100644 --- a/lib/vec8bit.gi +++ b/lib/vec8bit.gi @@ -1051,11 +1051,11 @@ InstallMethodWithRandomSource( Randomize, InstallMethod( Unpack, "for an 8bit matrix", [Is8BitMatrixRep], function( m ) - return List(m,AsPlist); + return List(m, PlainListCopy); end ); InstallMethod( Unpack, "for an 8bit vector", [Is8BitVectorRep], - AsPlist ); + PlainListCopy ); InstallOtherMethod( KroneckerProduct, "for two 8bit matrices", # priority to kernel code, if matrices have same field [Is8BitMatrixRep and IsMatrix, Is8BitMatrixRep and IsMatrix], 1, diff --git a/lib/vecmat.gi b/lib/vecmat.gi index 821832841e..2e6b4a4e91 100644 --- a/lib/vecmat.gi +++ b/lib/vecmat.gi @@ -2536,11 +2536,11 @@ InstallMethodWithRandomSource( Randomize, InstallMethod( Unpack, "for a gf2 matrix", [IsGF2MatrixRep], function( m ) - return List(m,AsPlist); + return List(m, PlainListCopy); end ); InstallMethod( Unpack, "for a gf2 vector", [IsGF2VectorRep], - AsPlist ); + PlainListCopy ); InstallOtherMethod( KroneckerProduct, "for two gf2 matrices", [IsGF2MatrixRep and IsMatrix, IsGF2MatrixRep and IsMatrix], diff --git a/tst/testinstall/range.tst b/tst/testinstall/range.tst index 1d65830079..62387c0c96 100644 --- a/tst/testinstall/range.tst +++ b/tst/testinstall/range.tst @@ -273,7 +273,7 @@ gap> SetX(ranges, ranges, > local c; > c:=ShallowCopy(a); > IntersectSet(c,b); -> return c = Intersection(AsPlist(a),AsPlist(b)); +> return c = Intersection(PlainListCopy(a),PlainListCopy(b)); > end); [ true ] From 9ab1937ade2a2661d3b55d17ec76f34a0a769c7e Mon Sep 17 00:00:00 2001 From: Max Horn Date: Fri, 17 Apr 2026 18:01:55 +0200 Subject: [PATCH 154/234] Validate DeterminantMat inputs (#6328) Reject ragged inputs before determinant dispatch. Fixes #5264 Co-authored-by: Codex --- lib/matrix.gi | 10 +++++----- tst/testbugfix/2026-04-16-DeterminantMat.tst | 10 ++++++++++ 2 files changed, 15 insertions(+), 5 deletions(-) create mode 100644 tst/testbugfix/2026-04-16-DeterminantMat.tst diff --git a/lib/matrix.gi b/lib/matrix.gi index b98e8d9e1d..956cd1b41b 100644 --- a/lib/matrix.gi +++ b/lib/matrix.gi @@ -1594,10 +1594,10 @@ InstallMethod( DeterminantMatDestructive, # check that the argument is a square matrix and get the size m := NrRows(mat); - zero := ZeroOfBaseDomain(mat); - if m <> NrCols(mat) then - Error("DeterminantMat: must be a square matrix"); + if m = 0 or not IsRectangularTable(mat) or m <> NrCols(mat) then + Error("DeterminantMat: must be a nonempty square matrix"); fi; + zero := ZeroOfBaseDomain(mat); # run through all columns of the matrix i := 0; det := 1; sgn := 1; @@ -1667,8 +1667,8 @@ function( mat ) # check that the argument is a square matrix, and get the size m := NrRows(mat); - if m = 0 or m <> NrCols(mat) then - Error( " must be a square matrix at least 1x1" ); + if m = 0 or m <> NrCols(mat) or not IsRectangularTable(mat) then + Error( "DeterminantMat: must be a nonempty square matrix" ); fi; zero := ZeroOfBaseDomain(mat); diff --git a/tst/testbugfix/2026-04-16-DeterminantMat.tst b/tst/testbugfix/2026-04-16-DeterminantMat.tst new file mode 100644 index 0000000000..bf75e0a7ab --- /dev/null +++ b/tst/testbugfix/2026-04-16-DeterminantMat.tst @@ -0,0 +1,10 @@ +# Fix inconsistent error handling in DeterminantMat, see #5264 + +gap> DeterminantMat([[1,2,1],[0,1,1],[1,0,1,1]]); +Error, DeterminantMat: must be a nonempty square matrix +gap> DeterminantMat([[1,2,1],[0,1,1],[1,0]]); +Error, DeterminantMat: must be a nonempty square matrix +gap> DeterminantMat([ [ Z(2)^0, 0*Z(2), Z(2)^0 ], +> [ Z(2)^0, Z(2)^0, Z(2)^0 ], +> [ Z(2)^0, Z(2)^0 ] ]); +Error, DeterminantMat: must be a nonempty square matrix From 79bb636c309428bd133db4b53321903d9bc401c2 Mon Sep 17 00:00:00 2001 From: wangyenshu <155622798+wangyenshu@users.noreply.github.com> Date: Thu, 12 Mar 2026 13:57:23 +0800 Subject: [PATCH 155/234] modify build.sh for file lazy loading --- etc/emscripten/build.sh | 71 ++++++++++++++++++++++------------------- 1 file changed, 39 insertions(+), 32 deletions(-) diff --git a/etc/emscripten/build.sh b/etc/emscripten/build.sh index 31bd41f420..9f8b7a0431 100755 --- a/etc/emscripten/build.sh +++ b/etc/emscripten/build.sh @@ -57,22 +57,6 @@ mkdir -p "$AUX_PREFIX" emmake make install ) -# There are two problems with building GAP -# 1) GAP builds some executables (ffgen and gap-nocomp), which it wants to -# execute while building. We get these files from 'native-build'. -# 2) 'configure' gets confused by some of the LDFLAGS we need, so we have to pass -# them in to 'make' -# -# These options are: -# -sASYNCIFY -- we don't care about ASYNC, but this forces the compiler to output -# all variables onto the stack, which is required for GASMAN -# Note we could use 'ALLOW_MEMORY_GROWTH', both we don't currently, we instead set -# a big memory window. -# -O2 : Some optimisation -# EXEEXT=.html -- this is actually a GAP makefile option, it lets us make the -# output 'gap.html', which makes emscripten output a html page we can load -# --preload-file : The directories containing files GAP needs to run - # Run configure if we don't have a makefile, or someone configured this # GAP for standard building (emscripten builds will use 'emcc') if [[ ! -f GNUmakefile ]] || ! grep '/emcc' GNUmakefile > /dev/null; then @@ -83,24 +67,47 @@ if [[ ! -f GNUmakefile ]] || ! grep '/emcc' GNUmakefile > /dev/null; then fi; # Get basic required packages -emmake make bootstrap-pkg-minimal +emmake make bootstrap-pkg-full # Copy in files from native_build cp native-build/build/c_*.c native-build/build/ffdata.* src/ +# Generate lazy_fs.js for on-demand loading +echo "Generating lazy file system map for on-demand loading..." +cat << 'EOF' > lazy_fs.js +Module.preRun = Module.preRun || []; +Module.preRun.push(function() { + var files = [ +EOF + +# Dynamically find and append ALL required files to the JS array +find pkg lib grp tst doc hpcgap dev benchmark -type f | sed -e 's/.*/ "&",/' >> lazy_fs.js + +cat << 'EOF' >> lazy_fs.js + ]; + + var createdDirs = {}; + files.forEach(function(file) { + var parts = file.split('/'); + var name = parts.pop(); + var parent = '/' + parts.join('/'); + + // Create the directory structure if it doesn't exist + if (!createdDirs[parent]) { + try { + FS.mkdirTree(parent); + } catch(e) {} + createdDirs[parent] = true; + } + + // Map the file lazily + FS.createLazyFile(parent, name, file, true, false); + }); +}); +EOF +# ------------------------------------------------------- + # The EXEEXT is usually for windows, but here it lets us set GAP's extension, -# which lets us produce a html page to run GAP in -emmake make -j8 LDFLAGS="--preload-file pkg --preload-file lib --preload-file grp --preload-file tst -s ASYNCIFY=1 -sTOTAL_STACK=32mb -sASYNCIFY_STACK_SIZE=32000000 -sINITIAL_MEMORY=2048mb -O2" EXEEXT=".html" - -# SPLIT THE DATA FILE -echo "Splitting gap.data..." -split -b 75m gap.data "gap.data.part" - -# Rename to .part1, .part2... -i=1 -for f in gap.data.part*; do - mv "$f" "gap.data.part$i" - echo "Created gap.data.part$i" - ((i++)) -done -rm gap.data +# which lets us produce a html page to run GAP in. +# Replaced all --preload-file flags with --pre-js lazy_fs.js +emmake make -j8 LDFLAGS="--pre-js lazy_fs.js -s ASYNCIFY=1 -sTOTAL_STACK=32mb -sASYNCIFY_STACK_SIZE=32000000 -sINITIAL_MEMORY=2048mb -O2" EXEEXT=".html" From ef3c2e7aac0bffd10ebe63968294a2c5ae080935 Mon Sep 17 00:00:00 2001 From: wangyenshu <155622798+wangyenshu@users.noreply.github.com> Date: Thu, 12 Mar 2026 15:08:20 +0800 Subject: [PATCH 156/234] improve comments --- etc/emscripten/build.sh | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/etc/emscripten/build.sh b/etc/emscripten/build.sh index 9f8b7a0431..14072a62f9 100755 --- a/etc/emscripten/build.sh +++ b/etc/emscripten/build.sh @@ -57,6 +57,22 @@ mkdir -p "$AUX_PREFIX" emmake make install ) +# There are two problems with building GAP +# 1) GAP builds some executables (ffgen and gap-nocomp), which it wants to +# execute while building. We get these files from 'native-build'. +# 2) 'configure' gets confused by some of the LDFLAGS we need, so we have to pass +# them in to 'make' +# +# These options are: +# -sASYNCIFY -- we don't care about ASYNC, but this forces the compiler to output +# all variables onto the stack, which is required for GASMAN +# Note we could use 'ALLOW_MEMORY_GROWTH', both we don't currently, we instead set +# a big memory window. +# -O2 : Some optimisation +# EXEEXT=.html -- this is actually a GAP makefile option, it lets us make the +# output 'gap.html', which makes emscripten output a html page we can load +# --pre-js lazy_fs.js : Prepend lazy_fs.js that is generated for lazy loading + # Run configure if we don't have a makefile, or someone configured this # GAP for standard building (emscripten builds will use 'emcc') if [[ ! -f GNUmakefile ]] || ! grep '/emcc' GNUmakefile > /dev/null; then @@ -66,14 +82,13 @@ if [[ ! -f GNUmakefile ]] || ! grep '/emcc' GNUmakefile > /dev/null; then LDFLAGS="-s ASYNCIFY=1 -O2" fi; -# Get basic required packages +# Get full required packages emmake make bootstrap-pkg-full # Copy in files from native_build cp native-build/build/c_*.c native-build/build/ffdata.* src/ -# Generate lazy_fs.js for on-demand loading -echo "Generating lazy file system map for on-demand loading..." +# Generate lazy_fs.js for lazy loading cat << 'EOF' > lazy_fs.js Module.preRun = Module.preRun || []; Module.preRun.push(function() { @@ -81,6 +96,8 @@ Module.preRun.push(function() { EOF # Dynamically find and append ALL required files to the JS array +# The flag -type f is safe because the only symbolic link is 'tst/mockpkg/Makefile.gappkg', +# which is safe to ignore find pkg lib grp tst doc hpcgap dev benchmark -type f | sed -e 's/.*/ "&",/' >> lazy_fs.js cat << 'EOF' >> lazy_fs.js @@ -105,9 +122,7 @@ cat << 'EOF' >> lazy_fs.js }); }); EOF -# ------------------------------------------------------- # The EXEEXT is usually for windows, but here it lets us set GAP's extension, # which lets us produce a html page to run GAP in. -# Replaced all --preload-file flags with --pre-js lazy_fs.js emmake make -j8 LDFLAGS="--pre-js lazy_fs.js -s ASYNCIFY=1 -sTOTAL_STACK=32mb -sASYNCIFY_STACK_SIZE=32000000 -sINITIAL_MEMORY=2048mb -O2" EXEEXT=".html" From daffb937b50cc043d8269b1396b59167aa2c0a52 Mon Sep 17 00:00:00 2001 From: wangyenshu <155622798+wangyenshu@users.noreply.github.com> Date: Thu, 12 Mar 2026 15:11:18 +0800 Subject: [PATCH 157/234] update gap-worker.js since lazy loading is implemented, the merging data part logic is no longer needed --- etc/emscripten/web-template/gap-worker.js | 71 ++--------------------- 1 file changed, 5 insertions(+), 66 deletions(-) diff --git a/etc/emscripten/web-template/gap-worker.js b/etc/emscripten/web-template/gap-worker.js index 922457b397..7f37248f22 100755 --- a/etc/emscripten/web-template/gap-worker.js +++ b/etc/emscripten/web-template/gap-worker.js @@ -1,69 +1,8 @@ importScripts("https://cdn.jsdelivr.net/npm/xterm-pty@0.9.4/workerTools.js"); onmessage = (msg) => { - // We wrap the initialization in an async function to handle the data fetching - async function loadAndStart() { - const buffers = []; - let i = 1; - - // Download all split parts - // It will look for gap.data.part1, part2, etc. until it hits a 404. - while (true) { - const url = `gap.data.part${i}`; - try { - const response = await fetch(url); - if (!response.ok) break; // Stop when we hit 404 - - const buf = await response.arrayBuffer(); - buffers.push(new Uint8Array(buf)); - i++; - } catch (e) { - break; - } - } - - // Prepare the Module object BEFORE importing gap.js - self.Module = self.Module || {}; - - // Merge data. - if (buffers.length > 0) { - const totalLength = buffers.reduce((acc, b) => acc + b.length, 0); - const mergedData = new Uint8Array(totalLength); - let offset = 0; - for (const buffer of buffers) { - mergedData.set(buffer, offset); - offset += buffer.length; - } - - console.log(`Worker: Loaded ${buffers.length} parts. Total size: ${totalLength} bytes.`); - - // Override the default downloader. - // When gap.js asks for 'gap.data', we give it our merged array immediately. - // This stops it from trying to fetch 'gap.data' via XHR. - self.Module.getPreloadedPackage = function(remotePackageName, remotePackageSize) { - if (remotePackageName === 'gap.data') { - return mergedData.buffer; - } - return null; // Let other files download normally if any - }; - - // Just in case: also write it to FS in preRun. - self.Module.preRun = self.Module.preRun || []; - self.Module.preRun.push(() => { - try { - - FS.writeFile('/gap.data', mergedData); - } catch(e) { /* ignore if already handled by getPreloadedPackage */ } - }); - } else { - console.warn("Worker: No gap.data parts found. The standard downloader will likely fail with 404."); - } - - // Load GAP. - importScripts("gap.js"); - - emscriptenHack(new TtyClient(msg.data)); - } - - loadAndStart(); -}; \ No newline at end of file + // Prepare the Module object BEFORE importing gap.js + self.Module = self.Module || {}; + importScripts("gap.js"); + emscriptenHack(new TtyClient(msg.data)); +}; From d46f91b509bde3f02ec62325f5c4bd87167c4f46 Mon Sep 17 00:00:00 2001 From: wangyenshu <155622798+wangyenshu@users.noreply.github.com> Date: Thu, 12 Mar 2026 15:14:45 +0800 Subject: [PATCH 158/234] update run-web-demo.sh --- etc/emscripten/run-web-demo.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/etc/emscripten/run-web-demo.sh b/etc/emscripten/run-web-demo.sh index c5e52107ff..d2c51f99f9 100755 --- a/etc/emscripten/run-web-demo.sh +++ b/etc/emscripten/run-web-demo.sh @@ -6,6 +6,7 @@ echo This script assumes you have already run 'build.sh' mkdir -p web-example cp etc/emscripten/web-template/* web-example -cp gap.js gap.wasm gap.data.part* web-example +cp gap.js gap.wasm gap.worker.js web-example +cp -r pkg lib grp tst doc hpcgap dev benchmark web-example/ cd web-example ../etc/emscripten/server.rb From 7b72a103d28b1bf431e31cae6edf3c8be4097a01 Mon Sep 17 00:00:00 2001 From: wangyenshu <155622798+wangyenshu@users.noreply.github.com> Date: Thu, 12 Mar 2026 16:17:47 +0800 Subject: [PATCH 159/234] Encode special filenames --- etc/emscripten/build.sh | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/etc/emscripten/build.sh b/etc/emscripten/build.sh index 14072a62f9..a0068cb282 100755 --- a/etc/emscripten/build.sh +++ b/etc/emscripten/build.sh @@ -116,9 +116,12 @@ cat << 'EOF' >> lazy_fs.js } catch(e) {} createdDirs[parent] = true; } - + + // Encode filename by replacing special characters with UTF-8 escape sequences (eg., "(S2twistS1)#10.scb") + var encodedURL = file.split('/').map(encodeURIComponent).join('/'); + // Map the file lazily - FS.createLazyFile(parent, name, file, true, false); + FS.createLazyFile(parent, name, encodedURL, true, false); }); }); EOF From abb7d4fc3c785ef1770b3646a3bdcb0586ca7fd1 Mon Sep 17 00:00:00 2001 From: wangyenshu <155622798+wangyenshu@users.noreply.github.com> Date: Thu, 12 Mar 2026 18:02:15 +0800 Subject: [PATCH 160/234] update build.sh to use filename and path hashing Removed lazy loading generation code from build script. --- etc/emscripten/build.sh | 40 ++++++---------------------------------- 1 file changed, 6 insertions(+), 34 deletions(-) diff --git a/etc/emscripten/build.sh b/etc/emscripten/build.sh index a0068cb282..6a92c44464 100755 --- a/etc/emscripten/build.sh +++ b/etc/emscripten/build.sh @@ -88,43 +88,15 @@ emmake make bootstrap-pkg-full # Copy in files from native_build cp native-build/build/c_*.c native-build/build/ffdata.* src/ -# Generate lazy_fs.js for lazy loading -cat << 'EOF' > lazy_fs.js -Module.preRun = Module.preRun || []; -Module.preRun.push(function() { - var files = [ -EOF - # Dynamically find and append ALL required files to the JS array # The flag -type f is safe because the only symbolic link is 'tst/mockpkg/Makefile.gappkg', # which is safe to ignore -find pkg lib grp tst doc hpcgap dev benchmark -type f | sed -e 's/.*/ "&",/' >> lazy_fs.js - -cat << 'EOF' >> lazy_fs.js - ]; - - var createdDirs = {}; - files.forEach(function(file) { - var parts = file.split('/'); - var name = parts.pop(); - var parent = '/' + parts.join('/'); - - // Create the directory structure if it doesn't exist - if (!createdDirs[parent]) { - try { - FS.mkdirTree(parent); - } catch(e) {} - createdDirs[parent] = true; - } - - // Encode filename by replacing special characters with UTF-8 escape sequences (eg., "(S2twistS1)#10.scb") - var encodedURL = file.split('/').map(encodeURIComponent).join('/'); - - // Map the file lazily - FS.createLazyFile(parent, name, encodedURL, true, false); - }); -}); -EOF +find pkg lib grp tst doc hpcgap dev benchmark -type f | python3 etc/emscripten/generate_mapping.py + +if [ $? -ne 0 ]; then + echo "Build aborted: generate_mapping.py failed." + exit 1 +fi # The EXEEXT is usually for windows, but here it lets us set GAP's extension, # which lets us produce a html page to run GAP in. From a5fd4a45e9f606fb8f69859892ca7ac525e2292c Mon Sep 17 00:00:00 2001 From: wangyenshu <155622798+wangyenshu@users.noreply.github.com> Date: Thu, 12 Mar 2026 18:02:48 +0800 Subject: [PATCH 161/234] Update run-web-demo.sh to use filename and path hashing Add asset copying and error handling to run-web-demo.sh --- etc/emscripten/run-web-demo.sh | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/etc/emscripten/run-web-demo.sh b/etc/emscripten/run-web-demo.sh index d2c51f99f9..dd5e13d104 100755 --- a/etc/emscripten/run-web-demo.sh +++ b/etc/emscripten/run-web-demo.sh @@ -4,9 +4,16 @@ set -eux echo This script assumes you have already run 'build.sh' -mkdir -p web-example -cp etc/emscripten/web-template/* web-example -cp gap.js gap.wasm gap.worker.js web-example -cp -r pkg lib grp tst doc hpcgap dev benchmark web-example/ +mkdir -p web-example/assets +cp etc/emscripten/web-template/* web-example/ +cp gap.js gap.wasm gap.worker.js web-example/ + +find pkg lib grp tst doc hpcgap dev benchmark -type f | python3 etc/emscripten/copy_hashed_assets.py web-example/assets + +if [ $? -ne 0 ]; then + echo "Copying failed." + exit 1 +fi + cd web-example ../etc/emscripten/server.rb From 2c708d0cc2b5df1c99a3a8d973681c45dfa9a3cc Mon Sep 17 00:00:00 2001 From: wangyenshu <155622798+wangyenshu@users.noreply.github.com> Date: Thu, 12 Mar 2026 18:03:28 +0800 Subject: [PATCH 162/234] add python scripts for filename and path hashing --- etc/emscripten/copy_hashed_assets.py | 33 +++++++++++++ etc/emscripten/generate_mapping.py | 69 ++++++++++++++++++++++++++++ 2 files changed, 102 insertions(+) create mode 100644 etc/emscripten/copy_hashed_assets.py create mode 100644 etc/emscripten/generate_mapping.py diff --git a/etc/emscripten/copy_hashed_assets.py b/etc/emscripten/copy_hashed_assets.py new file mode 100644 index 0000000000..fe8bf9db69 --- /dev/null +++ b/etc/emscripten/copy_hashed_assets.py @@ -0,0 +1,33 @@ +import sys +import hashlib +import os +import shutil + +def main(): + if len(sys.argv) < 2: + print("Error: Must provide destination directory.", file=sys.stderr) + sys.exit(1) + + dest_dir = sys.argv[1] + os.makedirs(dest_dir, exist_ok=True) + + copied_count = 0 + + for line in sys.stdin: + path = line.strip() + if not path: + continue + + h = hashlib.md5(path.encode('utf-8')).hexdigest() + _, ext = os.path.splitext(path) + hashed_name = f"{h}{ext}" + + dest_path = os.path.join(dest_dir, hashed_name) + + shutil.copy2(path, dest_path) + copied_count += 1 + + print(f"Successfully copied {copied_count} files into {dest_dir}", file=sys.stderr) + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/etc/emscripten/generate_mapping.py b/etc/emscripten/generate_mapping.py new file mode 100644 index 0000000000..a61ab382a8 --- /dev/null +++ b/etc/emscripten/generate_mapping.py @@ -0,0 +1,69 @@ +# issue: +# line.strip() will also remove trailing spaces +# path.replace('"', '\\"') will break if the filename contains the backslash +# Fortunately, there are no files in the directories pkg lib grp tst doc hpcgap dev benchmark +# whose filenames contains spaces, invisible symbols or backslash. + +import sys +import hashlib +import os + +def main(): + seen_hashes = {} + mappings = [] + + for line in sys.stdin: + path = line.strip() + if not path: + continue + + h = hashlib.md5(path.encode('utf-8')).hexdigest() + _, ext = os.path.splitext(path) + hashed_name = f"{h}{ext}" + + if hashed_name in seen_hashes: + print("\nError: Hash collision detected!", file=sys.stderr) + print(f"File 1: {seen_hashes[hashed_name]}", file=sys.stderr) + print(f"File 2: {path}", file=sys.stderr) + sys.exit(1) + + seen_hashes[hashed_name] = path + mappings.append((path, hashed_name)) + + try: + with open('lazy_fs.js', 'w', encoding='utf-8') as f: + f.write("Module.preRun = Module.preRun || [];\n") + f.write("Module.preRun.push(function() {\n") + f.write(" var fileMap = {\n") + + for path, hashed_name in mappings: + safe_path = path.replace('"', '\\"') + f.write(f' "{safe_path}": "{hashed_name}",\n') + + f.write(" };\n\n") + f.write(" var createdDirs = {};\n") + f.write(' var physicalDir = "assets/";\n\n') + + f.write(" Object.keys(fileMap).forEach(function(virtualPath) {\n") + f.write(" var physicalName = fileMap[virtualPath];\n") + f.write(" var parts = virtualPath.split('/');\n") + f.write(" var fileName = parts.pop();\n") + f.write(" var parentDir = '/' + parts.join('/');\n\n") + + f.write(" if (!createdDirs[parentDir]) {\n") + f.write(" try { FS.mkdirTree(parentDir); } catch(e) {}\n") + f.write(" createdDirs[parentDir] = true;\n") + f.write(" }\n\n") + + f.write(" FS.createLazyFile(parentDir, fileName, physicalDir + physicalName, true, false);\n") + f.write(" });\n") + f.write("});\n") + + print(f"Successfully mapped {len(mappings)} files into lazy_fs.js", file=sys.stderr) + + except Exception as e: + print(f"Failed to write lazy_fs.js: {e}", file=sys.stderr) + sys.exit(1) + +if __name__ == "__main__": + main() \ No newline at end of file From b618d7bf8dbef203cc0098f51d48a626d1edadfd Mon Sep 17 00:00:00 2001 From: wangyenshu <155622798+wangyenshu@users.noreply.github.com> Date: Thu, 12 Mar 2026 21:46:54 +0800 Subject: [PATCH 163/234] add nodejs script to build startup manifest --- etc/emscripten/build_startup_manifest.js | 60 ++++++++++++++++++++++++ 1 file changed, 60 insertions(+) create mode 100644 etc/emscripten/build_startup_manifest.js diff --git a/etc/emscripten/build_startup_manifest.js b/etc/emscripten/build_startup_manifest.js new file mode 100644 index 0000000000..18ca176b02 --- /dev/null +++ b/etc/emscripten/build_startup_manifest.js @@ -0,0 +1,60 @@ +#!/usr/bin/env node +"use strict"; + +const http = require('http'); +const fs = require('fs'); +const path = require('path'); + +const PORT = 9999; +const BASE_DIR = process.cwd(); +const LOG_FILE = path.join(BASE_DIR, 'startup_manifest.json'); + +const requestedFiles = new Set(); +fs.writeFileSync(LOG_FILE, '[\n]'); + +const server = http.createServer((req, res) => { + let urlPath = req.url.split('?')[0]; + if (urlPath === '/') { + urlPath = '/index.html'; + } + + const filePath = path.join(BASE_DIR, urlPath); + + fs.readFile(filePath, (err, data) => { + if (err) { + console.error(`[404] Ignored missing file: ${urlPath}`); + res.writeHead(404); + res.end(`404: File not found`); + return; + } + + if (urlPath !== '/favicon.ico' && !requestedFiles.has(urlPath)) { + requestedFiles.add(urlPath); + + const manifest = Array.from(requestedFiles); + fs.writeFileSync(LOG_FILE, JSON.stringify(manifest, null, 4)); + + console.log(`[Loaded & Logged] ${urlPath} (Total: ${requestedFiles.size})`); + } + + let contentType = 'application/octet-stream'; + if (urlPath.endsWith('.html')) contentType = 'text/html'; + else if (urlPath.endsWith('.js')) contentType = 'text/javascript'; + else if (urlPath.endsWith('.wasm')) contentType = 'application/wasm'; + + res.writeHead(200, { + 'Content-Type': contentType, + 'Cross-Origin-Opener-Policy': 'same-origin', + 'Cross-Origin-Embedder-Policy': 'require-corp', + 'Access-Control-Allow-Origin': '*' + }); + + res.end(data); + }); +}); + +server.listen(PORT, '0.0.0.0', () => { + console.log(`\n Tracker running at http://localhost:${PORT}/`); + console.log(`Serving files from: ${BASE_DIR}`); + console.log(`Logging valid loaded files to: ${LOG_FILE}\n`); +}); \ No newline at end of file From 783a3290b753218fa09977528f617c9daab1583b Mon Sep 17 00:00:00 2001 From: wangyenshu <155622798+wangyenshu@users.noreply.github.com> Date: Thu, 12 Mar 2026 21:47:58 +0800 Subject: [PATCH 164/234] add sample startup_manifest.json --- etc/emscripten/web-template/startup_manifest.json | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 etc/emscripten/web-template/startup_manifest.json diff --git a/etc/emscripten/web-template/startup_manifest.json b/etc/emscripten/web-template/startup_manifest.json new file mode 100644 index 0000000000..32960f8ced --- /dev/null +++ b/etc/emscripten/web-template/startup_manifest.json @@ -0,0 +1,2 @@ +[ +] \ No newline at end of file From 2d8fd062b8f61218c5b197e14dffc414e5dcf703 Mon Sep 17 00:00:00 2001 From: wangyenshu <155622798+wangyenshu@users.noreply.github.com> Date: Thu, 12 Mar 2026 21:52:16 +0800 Subject: [PATCH 165/234] modify index.html to preload resources --- etc/emscripten/web-template/index.html | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/etc/emscripten/web-template/index.html b/etc/emscripten/web-template/index.html index 4451f7c948..09f51944e9 100755 --- a/etc/emscripten/web-template/index.html +++ b/etc/emscripten/web-template/index.html @@ -8,6 +8,16 @@ - - - + \ No newline at end of file From de8afce7458a25e5766961e20f905e7659727940 Mon Sep 17 00:00:00 2001 From: wangyenshu <155622798+wangyenshu@users.noreply.github.com> Date: Thu, 12 Mar 2026 21:55:58 +0800 Subject: [PATCH 166/234] Document build_startup_manifest.js in README Added information about build_startup_manifest.js for preloading resources. --- etc/emscripten/README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/etc/emscripten/README.md b/etc/emscripten/README.md index 29517d16f7..161b126ec5 100644 --- a/etc/emscripten/README.md +++ b/etc/emscripten/README.md @@ -6,6 +6,8 @@ Files: - `web-template`: Uses 'xterm-pty' to create a "nice" interface to the Wasm GAP. +- `build_startup_manifest.js`: Build `startup_manifest.json` that contains resources to preload. + See 'run-web-demo.sh' as an example on how to set up a working website. Note that this demo uses xterm-pty, a library which provides a terminal interface From 94a51c546d019b799305fb49cf5110e72d179fd3 Mon Sep 17 00:00:00 2001 From: wangyenshu <155622798+wangyenshu@users.noreply.github.com> Date: Thu, 12 Mar 2026 21:57:42 +0800 Subject: [PATCH 167/234] Update README.md with clearer build_startup_manifest.js usage Clarify instructions for running build_startup_manifest.js. --- etc/emscripten/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/etc/emscripten/README.md b/etc/emscripten/README.md index 161b126ec5..cf5d35ad04 100644 --- a/etc/emscripten/README.md +++ b/etc/emscripten/README.md @@ -6,7 +6,7 @@ Files: - `web-template`: Uses 'xterm-pty' to create a "nice" interface to the Wasm GAP. -- `build_startup_manifest.js`: Build `startup_manifest.json` that contains resources to preload. +- `build_startup_manifest.js`: Run it in the web root directory to build `startup_manifest.json` that contains resources to preload. See 'run-web-demo.sh' as an example on how to set up a working website. From 2f6951b5b32d762a9774756f3ebdaf8ea1cb7f33 Mon Sep 17 00:00:00 2001 From: wangyenshu <155622798+wangyenshu@users.noreply.github.com> Date: Thu, 12 Mar 2026 22:01:39 +0800 Subject: [PATCH 168/234] fix syntax error --- etc/emscripten/web-template/index.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/etc/emscripten/web-template/index.html b/etc/emscripten/web-template/index.html index 09f51944e9..035717b22a 100755 --- a/etc/emscripten/web-template/index.html +++ b/etc/emscripten/web-template/index.html @@ -12,7 +12,7 @@ .then(res => res.json()) .then(manifest => { manifest.forEach(file => { - if file.startsWith("/assets/") { + if (file.startsWith("/assets/")) { fetch(file.substring(1)); } }); @@ -30,4 +30,4 @@ - \ No newline at end of file + From 96544455b095bed77671f8e2c12e3a20dfeb1435 Mon Sep 17 00:00:00 2001 From: wangyenshu <155622798+wangyenshu@users.noreply.github.com> Date: Thu, 12 Mar 2026 23:13:35 +0800 Subject: [PATCH 169/234] wait preloaded resources to be fetched before starting the worker --- etc/emscripten/web-template/index.html | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/etc/emscripten/web-template/index.html b/etc/emscripten/web-template/index.html index 035717b22a..e0d0071479 100755 --- a/etc/emscripten/web-template/index.html +++ b/etc/emscripten/web-template/index.html @@ -8,24 +8,25 @@ From 9149c2bb7418f460dacb248c89ad6c95ff65750d Mon Sep 17 00:00:00 2001 From: Yanshu Wang Date: Fri, 13 Mar 2026 11:56:02 +0800 Subject: [PATCH 170/234] use IDBFS for cache --- etc/emscripten/build.sh | 2 +- etc/emscripten/generate_mapping.py | 77 ++++++++++++++++++----- etc/emscripten/web-template/gap-worker.js | 2 +- etc/emscripten/web-template/index.html | 20 ++---- 4 files changed, 69 insertions(+), 32 deletions(-) diff --git a/etc/emscripten/build.sh b/etc/emscripten/build.sh index 6a92c44464..0dd807bd95 100755 --- a/etc/emscripten/build.sh +++ b/etc/emscripten/build.sh @@ -100,4 +100,4 @@ fi # The EXEEXT is usually for windows, but here it lets us set GAP's extension, # which lets us produce a html page to run GAP in. -emmake make -j8 LDFLAGS="--pre-js lazy_fs.js -s ASYNCIFY=1 -sTOTAL_STACK=32mb -sASYNCIFY_STACK_SIZE=32000000 -sINITIAL_MEMORY=2048mb -O2" EXEEXT=".html" +emmake make -j8 LDFLAGS="-lidbfs.js --pre-js lazy_fs.js -s ASYNCIFY=1 -sTOTAL_STACK=32mb -sASYNCIFY_STACK_SIZE=32000000 -sINITIAL_MEMORY=2048mb -O2" EXEEXT=".html" \ No newline at end of file diff --git a/etc/emscripten/generate_mapping.py b/etc/emscripten/generate_mapping.py index a61ab382a8..c5aacec4cc 100644 --- a/etc/emscripten/generate_mapping.py +++ b/etc/emscripten/generate_mapping.py @@ -1,9 +1,3 @@ -# issue: -# line.strip() will also remove trailing spaces -# path.replace('"', '\\"') will break if the filename contains the backslash -# Fortunately, there are no files in the directories pkg lib grp tst doc hpcgap dev benchmark -# whose filenames contains spaces, invisible symbols or backslash. - import sys import hashlib import os @@ -41,21 +35,76 @@ def main(): f.write(f' "{safe_path}": "{hashed_name}",\n') f.write(" };\n\n") - f.write(" var createdDirs = {};\n") - f.write(' var physicalDir = "assets/";\n\n') + f.write(' var physicalDir = "assets/";\n') + f.write(" var createdDirs = {};\n") f.write(" Object.keys(fileMap).forEach(function(virtualPath) {\n") - f.write(" var physicalName = fileMap[virtualPath];\n") f.write(" var parts = virtualPath.split('/');\n") - f.write(" var fileName = parts.pop();\n") - f.write(" var parentDir = '/' + parts.join('/');\n\n") - + f.write(" parts.pop();\n") + f.write(" var parentDir = '/' + parts.join('/');\n") f.write(" if (!createdDirs[parentDir]) {\n") f.write(" try { FS.mkdirTree(parentDir); } catch(e) {}\n") f.write(" createdDirs[parentDir] = true;\n") - f.write(" }\n\n") + f.write(" }\n") + f.write(" });\n\n") + + f.write(" try { FS.mkdirTree('/gap_idb_cache'); } catch(e) {}\n") + f.write(" FS.mount(IDBFS, {}, '/gap_idb_cache');\n") + f.write(" addRunDependency('idbfs_sync');\n\n") + + f.write(" FS.syncfs(true, async function(err) {\n") + f.write(" var needsSave = false;\n") + f.write(" var startupSet = new Set();\n") + + f.write(" try {\n") + f.write(" const manifestRes = await fetch('startup_manifest.json');\n") + f.write(" if (manifestRes.ok) {\n") + f.write(" const manifest = await manifestRes.json();\n") + f.write(" manifest.forEach(p => {\n") + f.write(" if (p.startsWith('/')) p = p.substring(1);\n") + f.write(" startupSet.add(p);\n") + f.write(" });\n") + f.write(" }\n") + f.write(" } catch (e) {}\n\n") + + f.write(" var fetchPromises = Object.keys(fileMap).map(async function(virtualPath) {\n") + f.write(" var physicalName = fileMap[virtualPath];\n") + f.write(" var physicalPath = physicalDir + physicalName;\n") + f.write(" var cachePath = '/gap_idb_cache/' + physicalName;\n") + f.write(" var finalPath = '/' + virtualPath;\n\n") + + f.write(" if (startupSet.has(physicalPath)) {\n") + f.write(" try {\n") + f.write(" FS.stat(cachePath);\n") + f.write(" FS.writeFile(finalPath, FS.readFile(cachePath));\n") + f.write(" } catch (e) {\n") + f.write(" try {\n") + f.write(" const response = await fetch(physicalPath);\n") + f.write(" if (response.ok) {\n") + f.write(" const buffer = await response.arrayBuffer();\n") + f.write(" const data = new Uint8Array(buffer);\n") + f.write(" FS.writeFile(finalPath, data);\n") + f.write(" FS.writeFile(cachePath, data);\n") + f.write(" needsSave = true;\n") + f.write(" }\n") + f.write(" } catch (fetchErr) {}\n") + f.write(" }\n") + f.write(" } else {\n") + f.write(" var parts = virtualPath.split('/');\n") + f.write(" var fileName = parts.pop();\n") + f.write(" var parentDir = '/' + parts.join('/');\n") + f.write(" FS.createLazyFile(parentDir, fileName, physicalPath, true, false);\n") + f.write(" }\n") + f.write(" });\n\n") - f.write(" FS.createLazyFile(parentDir, fileName, physicalDir + physicalName, true, false);\n") + f.write(" await Promise.all(fetchPromises);\n") + f.write(" if (needsSave) {\n") + f.write(" FS.syncfs(false, function(saveErr) {\n") + f.write(" removeRunDependency('idbfs_sync');\n") + f.write(" });\n") + f.write(" } else {\n") + f.write(" removeRunDependency('idbfs_sync');\n") + f.write(" }\n") f.write(" });\n") f.write("});\n") diff --git a/etc/emscripten/web-template/gap-worker.js b/etc/emscripten/web-template/gap-worker.js index 7f37248f22..0eec06cafc 100755 --- a/etc/emscripten/web-template/gap-worker.js +++ b/etc/emscripten/web-template/gap-worker.js @@ -5,4 +5,4 @@ onmessage = (msg) => { self.Module = self.Module || {}; importScripts("gap.js"); emscriptenHack(new TtyClient(msg.data)); -}; +}; \ No newline at end of file diff --git a/etc/emscripten/web-template/index.html b/etc/emscripten/web-template/index.html index e0d0071479..2e7290ae01 100755 --- a/etc/emscripten/web-template/index.html +++ b/etc/emscripten/web-template/index.html @@ -1,6 +1,7 @@ gap-wasm + @@ -14,21 +15,8 @@ const { master, slave } = openpty(); xterm.loadAddon(master); - fetch("startup_manifest.json") - .then(res => res.json()) - .then(async (manifest) => { - const cache = await caches.open('gap-assets'); - const urls = manifest - .filter(file => file.startsWith("/assets/")) - .map(file => file.substring(1)); - await cache.addAll(urls); - }) - .then(() => { - const worker = new Worker("gap-worker.js"); - new TtyServer(slave).start(worker); - }); + const worker = new Worker("gap-worker.js"); + new TtyServer(slave).start(worker); - - - + \ No newline at end of file From e1017e132d4eb70c6f8cbe169e44cbb00c024998 Mon Sep 17 00:00:00 2001 From: wangyenshu <155622798+wangyenshu@users.noreply.github.com> Date: Fri, 13 Mar 2026 12:06:10 +0800 Subject: [PATCH 171/234] add startup_manifest; previous is empty by mistake --- .../web-template/startup_manifest.json | 1258 +++++++++++++++++ 1 file changed, 1258 insertions(+) diff --git a/etc/emscripten/web-template/startup_manifest.json b/etc/emscripten/web-template/startup_manifest.json index 32960f8ced..b63d64e8e8 100644 --- a/etc/emscripten/web-template/startup_manifest.json +++ b/etc/emscripten/web-template/startup_manifest.json @@ -1,2 +1,1260 @@ [ + "/assets/7b59a49b04346656bd2e8136cb3edbc1.g", + "/assets/4aa642c41d006ba397543ceded3ffbc5.g", + "/assets/b7a794624978346fc60b233e3a36b4c1.g", + "/assets/27006107d901783a4990c551ae988a1f.g", + "/assets/35784f49ea293970e881d8989895de75.g", + "/assets/6703788ec913221e9de60fee486afa0b.g", + "/assets/3ad2c0c2e16ab6570a90f4f7c4486001.g", + "/assets/5f8707e876ee1b5323c75e6b2c16fd77.g", + "/assets/9e1f49d5f90713e878925519afd52c26.g", + "/assets/9c33d1d5c954303561f75cc303575d2e.g", + "/assets/2d54c52d27de02da865197eaa49d73f0.g", + "/assets/7b9bbb6e4d0c426097e93729a6f0bb4d.g", + "/assets/a12a8a2f0cb7710a574a3e49eeb95888.g", + "/assets/0d324ca3c9be8391c9af1c60e3f91ed5.g", + "/assets/f42f83966d0de21c2655bbc8a84417d5.gd", + "/assets/4bfd4177bca1762e652aa47bbe00e16c.gd", + "/assets/ddfc8ce554873ddbdb26c784132f01fa.g", + "/assets/69bae3daffdb69ddbbb6218232bee32c.gd", + "/assets/cffd2a8bd255e90685651a0c1f828d56.gd", + "/assets/dfd45db083eac2ab29b4650435951919.gd", + "/assets/56b18609e58fde04850cfc56ed3f7794.gd", + "/assets/e51d6e046f7691d8d72c15af0b47ab12.gd", + "/assets/d98054f175c3792f389e12d84bbbe928.gd", + "/assets/a5c02b844755760a44b0af942116c81f.gd", + "/assets/d20097ccbe896f32359c8e9c72f92251.g", + "/assets/8d57117f27fad258c4a416ba15331733.g", + "/assets/118e0cc315408c330639ea336e16ccc7.gd", + "/assets/7eaaeef09150cf5f3a46eaa96c70412e.gd", + "/assets/fa798d8ec092fef7f73a8bb0d86d0654.gd", + "/assets/4b02c3fa0b74a5d5d2ebbba96f8e96d2.gi", + "/assets/b3a9c3d1464418773696e375a15966ee.gi", + "/assets/7beaa7d398502184a218ca76b7c489b7.g", + "/assets/f887cb60d851477ebf8341a11618556b.g", + "/assets/a04f66b01d9493fb35c0f709a5c37dab.g", + "/assets/832850f85d6be67a867c041b9f31db90.gi", + "/assets/74cc965118dc7f48ced3a20322f57ae1.g", + "/assets/4c1a780ed754ee016193168478f4f0e2.g", + "/assets/1aff67e93dc523e75f09284840bc4914.g", + "/assets/e4014060c68a7b5f084cb8fda058af36.g", + "/assets/8f2c0274fe78d4d7a815632ca9394ff6.g", + "/assets/9fe30178e167c4951a2d3e4bf3089234.gi", + "/assets/8892927df7e1d6ab0709725910e6c9ce.gi", + "/assets/5ae3485947de971f7422f7676afe279d.gd", + "/assets/9a3a26ba5ddb9e093c974945f454c7b2.gd", + "/assets/5a991f67e05e63e45481e2918d16cd38.gd", + "/assets/3670e70829ef1c430e341ba1197d8584.gd", + "/assets/44fdef3c7d553ce8840a4440db62b17c.gi", + "/assets/0f331abebd03f8b1d64ffbb6d039e9e6.gd", + "/assets/8f9e3a38e1a59fa02f6a1a441e71c1aa.gd", + "/assets/c251fa4c8b45c9ce1b406df6c7c4b105.gd", + "/assets/d97cb149758107bfd5cffc8a83eca1c0.gd", + "/assets/7853c4c27f461db05cce3d6a209cab4a.gd", + "/assets/ec77e1349659a617c444a44665693bad.gi", + "/assets/52dc535abf2095c0716c48b9c63dc00e.gi", + "/assets/7b4a736c9ebcad0b563502365e94cad7.gd", + "/assets/281385738fc27fc4d952aa2705dab8b0.gi", + "/assets/0d5db671613a5d6f3e946a2a90a2884f.gd", + "/assets/81ef838516b6c4ea24a677ffa1dbde88.gi", + "/assets/d8673da61258721d02366078d84f532d.gd", + "/assets/96194441ac26cad02549cbe5b0784fa3.g", + "/assets/6abd9b6548095a1cc08bba418d0c91fd.g", + "/assets/a6f6b3acde8847793de6fd01a9e11066.g", + "/assets/b22ed1c52df6b78fc84e21946fe94365.g", + "/assets/67bec54418dd512af64c66494101113f.gd", + "/assets/17a02323ce47d2b96894fbf4f8ed9fe2.g", + "/assets/09ae5089fce3607ce7c9758f0776431f.g", + "/assets/3e05f9c56ae50056127d2348be2f82ce.g", + "/assets/9cfe2b8b076f28ad3e7402059defbefb.g", + "/assets/f57bccdea4ab67cce4d5c0c509b8af19.g", + "/assets/4b510629f2a609ba0f6640551db5d429.gd", + "/assets/57df29c119bc8f0ed94b85bfb1772c55.gi", + "/assets/2a2f0800029b15fd39643a5d28fbe4f5.gi", + "/assets/12076fadcd03f7e118d396718603f288.gi", + "/assets/c43c04f3fe9d7d0822d426ae255bc193.g", + "/assets/eeb733b6206076f84b7b253ef723010c.gd", + "/assets/317538ee62efb54f865ab5fc7771963c.gd", + "/assets/118799c9ea19f8a1c16526ae49921c3e.gd", + "/assets/c136cdf2db9546a815fd167cbbaa0678.gd", + "/assets/f11702ff9d4d320fa91b687fcfa2e17d.gd", + "/assets/90d776ae54ff0c87100f13836457c5be.gd", + "/assets/091567bedb42a25fe7ce21b651a8fd79.gd", + "/assets/141c81636bd3eed22db8ef8c25a41887.gd", + "/assets/b9783ee351b5d827dcb4ebb95f0ec841.gd", + "/assets/3294918abad6f195447012036e25dee4.gd", + "/assets/c1409e1e84cff226c1c4a8ad316ab2b0.gd", + "/assets/ca8377f1082c122687568db22274fb14.gd", + "/assets/f7b44a218ccad14067c1c316261174d1.gd", + "/assets/e53cdd24acca561e0093369786d4497c.gd", + "/assets/faee5ec15ac0a36672dc9401c6481206.gd", + "/assets/4169c5d964a1b509907623b98d5ad7c6.gd", + "/assets/1c944008853cb29f1bda800411b85963.gd", + "/assets/c1acb27f7e0736781c7cdd6cc59358ab.gd", + "/assets/5c9477bf9a262d717a34ea1eef2cca20.gd", + "/assets/d23ccad6f389d6fd01d72042461a650f.gd", + "/assets/7a56517f7a90c71fc4e7774dc93a5fb2.gd", + "/assets/1bae26ed85f1aa760ed8e0904d9c3d89.gd", + "/assets/6f730c95eaa3df4a45eadf26fef65a41.gd", + "/assets/6f0fb842d6d2cc95adc38a48034fde22.gd", + "/assets/a475b92d539cf9bc61ad8bdbede2f6d5.gd", + "/assets/ede5e5067be030c82effa0c5a97e92b7.gd", + "/assets/800ebd9c68f28be311195c3b527edaae.gd", + "/assets/b2fea3885590181189908e63e09d61c2.gd", + "/assets/5eaac654f0ace86b672da8ca3fa31cc6.gd", + "/assets/de53b9224e948c84792e0ef870d1e318.gd", + "/assets/35462716e3efcda176c5c23b438b3835.gd", + "/assets/d2d261e0194d5bdce976195fb9b37191.gd", + "/assets/9b9ed2314688770026eab59f2b15f988.gd", + "/assets/29e8a51ed97f11bb97b8b01653af65c7.gd", + "/assets/9958ee0fa5528592c1854a8d881a9499.gd", + "/assets/638320b8683d568db2a708964be86124.gd", + "/assets/201b3fcb625063dcb5bcbd4772800f50.gd", + "/assets/c9e1be8621f8db535cb708698bf5b401.gd", + "/assets/b2066fcf3ca4c0965a0fd85e4a062b2f.gd", + "/assets/860aef14d7fd42dcca79a37f9bc11366.gd", + "/assets/98f233191a0b58a241238bb8944031f0.gd", + "/assets/a42e2a06d4ea432a3f34fe8258b0b0c1.gd", + "/assets/c599fdd884e67c83a76feec867a11a94.gd", + "/assets/da901aca8d614ffe29f9f8c260b6d83c.gd", + "/assets/1abcc2a3997e18b6d54a33cfcebc469c.gd", + "/assets/8832274f88905efdd3f67f915ec5b3b9.gd", + "/assets/abb329846d08fa8cab8be2ab49fa2265.gd", + "/assets/38e9b1d79b04808fde9f1f38f7d822bf.gd", + "/assets/54b2e0eaa8cf47fb74003c5ca58836a1.gd", + "/assets/09e321edd47d2fe52889407048092c99.gd", + "/assets/9489107d94425dc2546d2a8e2573cf31.gd", + "/assets/9082e8998896045acf37f0362ce37eca.gd", + "/assets/286ccb1da5c2c84d090c42e1b1a36214.gd", + "/assets/282bd084b2ecad0e48940439afa89f14.gd", + "/assets/80a7797fc314c87bc706262d7c1be5ba.gd", + "/assets/4c0c75fbe75b304df2b4bae0406531f6.gd", + "/assets/6d71790c9314908a5cd94ca07aaed132.g", + "/assets/4c0f110121c75ef3dc23a9a3d0ffd01c.gi", + "/assets/079ce0630215da30b899e0aabe18f0fe.gi", + "/assets/f40937884b0f93132480da6e520fb216.gi", + "/assets/f2c08ddba1434efa53ac450fcbda4b4f.gi", + "/assets/bd7ece9f1f1fe0983733f723884e79a1.gd", + "/assets/61a91dc25befb0214c538ad5d113dd5c.gd", + "/assets/e8bcd4b3e44c713c7984cc889490d1ea.gd", + "/assets/29a3e527be729d3c02d2d17197e68337.gd", + "/assets/423b76cfd87097da7da70d94be8abcc4.gd", + "/assets/6db429a5ad0b3dc169ff843f0a2a28d6.gd", + "/assets/d022d4ea2a8dbf6590cfcfde12662373.gd", + "/assets/07d216f0861ca995b975c1b2b973e919.gd", + "/assets/9efba7c694026aa36afb462c65f86426.gd", + "/assets/ca7e1457a906deb9902b3aa773ae657f.gd", + "/assets/15fc6b7ecd12eb389221f9a9eb840f7b.gd", + "/assets/17a588f3ae11587ab73f2970e27e1283.gd", + "/assets/0883a76a372fc07e78ad0583eb4f46fd.gd", + "/assets/05d951bc1d36a94b9b95206401f7fa97.gd", + "/assets/e91e88eccc685a62c28d6867195f5094.gd", + "/assets/46f19e64e20bf76af0b1a409a436f79e.gd", + "/assets/0f136cf4ea2c21cb308d5f842a9db4c1.gd", + "/assets/0448cf1ee5f90fb6c21b77dd614a0d0b.gd", + "/assets/55484092823a2c0c8ff09e36357ce1db.gd", + "/assets/281eca474f55b63251c76fdaf6708f4c.gd", + "/assets/b2141c0ee739dde01fe4424a34804d75.gd", + "/assets/3b1057fa8934c602cdd38dcdcdb3005d.gd", + "/assets/53633ca6f434dd8d21df990192c0c272.gd", + "/assets/fd1b255ac1f4afdce9e8d1b5aad83cc8.gd", + "/assets/656addc934eae2dcf48d44cd92a24126.gd", + "/assets/9863a7701080e1b2aa17498811132d33.gd", + "/assets/f217a83b4fada8f8f8e0ca4618eebfb8.gd", + "/assets/b469e82f11033bfb2949b8b50a098757.gd", + "/assets/4db6b6d8d1725d415df0222643bbb419.gd", + "/assets/6b9c61acad8a04363967ce27825ee1c1.gd", + "/assets/5420fa7da3da53d9164ae3864407c09b.gd", + "/assets/c422c0871a97a78397a9e9b7d60fed53.gd", + "/assets/fe81ec2616235f5b804eb01cfae81ccb.gd", + "/assets/4b3d59173a9820f902712129de831ee8.gd", + "/assets/6c5c4fdaffd6905ae5b1e2c0cd09100f.gd", + "/assets/be8fb25491a705b586dcb0d74851f537.gd", + "/assets/1e5b579a489e1fb00e301618c8064115.gd", + "/assets/8d40b197acc17347577f55761d9a7acd.gd", + "/assets/6d37de51d6c780cd2df0406ff64a7a6e.gd", + "/assets/2c626fdfa16bb9ab89f4b75f6baff835.gd", + "/assets/e51e0b784dfe4dfcae4c124324cf4dfa.gd", + "/assets/c6d66fed15231f883cc3df7cc779361a.gd", + "/assets/1f4c86ebc2ccc5dc4cfdf9c05dbf5b6b.g", + "/assets/e523bc9fe8696d455d2856fb5aa48715.gd", + "/assets/0eeb3cec00aa25e8ad641d48020c93e2.gd", + "/assets/6b1181cf5ba16578333bb3a63265da52.gd", + "/assets/54f5e7c33432a4d0ea06aaf61d7c2988.gd", + "/assets/cf4bd40749c2858313b59009e29a8a1a.gd", + "/assets/a0104907471effd061cf8a38d18762f6.gd", + "/assets/b5d1daacb6f8861da7afd51119f1e273.gd", + "/assets/f87fdc983be764e123849da612d10245.gd", + "/assets/b312f0f5ba1c2040266acd0e3ca4a36c.gd", + "/assets/9eba61eb18acbe776722ba4ef5c522ad.gd", + "/assets/06d48d76be0efaf148d202ce64d98279.gd", + "/assets/41417923e985aa509f51af8e99154660.gd", + "/assets/0f18621563668c9657aa963a331eea65.gd", + "/assets/fae5d234896f60cdd2e47332c27ae133.gd", + "/assets/5b51d0dfe4d31551112d1186a51024f1.gd", + "/assets/a7ee798f93d6ab7071441855fb9f25f7.gd", + "/assets/8e69473faa3b21c59b4d289c390afa8c.gd", + "/assets/208e4b6d7b0c7f4eff9581f1e7f3ca5c.gd", + "/assets/6450c3127dd03b7c4635f583bcac8968.gd", + "/assets/274d0cb22b59826011d8c42ec000e63f.gd", + "/assets/b98e3e40732da4f56b27ba1d80dcc595.gd", + "/assets/3f5921682e09440b02d49677c7c9349a.gd", + "/assets/71295b39011a50a4dc20832dd6428d68.gd", + "/assets/33aa1022665c8cf9b16ad48901a8d047.gd", + "/assets/1076c16f5b533d93651b880aaeb6685d.gd", + "/assets/860ad9808e3685248f564816ea636e1e.gd", + "/assets/93ec688ad3b83c4ee337812b0f28907f.gd", + "/assets/3162d4af99d285cd6cdad468e8d94a9b.gd", + "/assets/06c62fb4bd6deeeb79a3d67a2c3aa3ac.gd", + "/assets/7c91762275e1fa23d8f9e1dd8e3a76ca.gd", + "/assets/bae4b5b27ef413df23ef697b9379e696.gd", + "/assets/e47d6f24d1513899093870532153b8ad.gd", + "/assets/adcde47ea5e29e447e23b18fae29fdb6.g", + "/assets/2431baf1fb8e0db6dc236121dfdd2161.gi", + "/assets/e0f3132452e207ed11b08bc60ec9917b.gd", + "/assets/d8b316e3aeb6e624b5f136bdf5ca0ab0.gd", + "/assets/3c264291f8feb9128a9ebecb80588dc5.gd", + "/assets/0333decb3182dc45697f0cd2482adf14.gd", + "/assets/6a0b8f3b49feed621d0fc7e0df7ad142.gd", + "/assets/2eeafe7be12d6e5bb946c1843e90d031.gd", + "/assets/52d01368e29b478d39ca3450e086a2cf.gd", + "/assets/d871cfffc3d5777c67e3deb9e9f00584.gd", + "/assets/1997bc1b4714de6b653b20fcbd8cc82f.gd", + "/assets/b1bf372a72902f0799716209f514cc13.gd", + "/assets/c24f086adf5d460d965df52a4dc9ac08.gd", + "/assets/c5b4e12bd51087f3f62b8bef4d60aa63.gd", + "/assets/33a9fca94e3e8e1c66fdaa9dd2777f96.gd", + "/assets/4eb6881b3ecd539c071eeb074a18d674.gd", + "/assets/38db5fa498e9cad7b93e407551cc1081.gd", + "/assets/b49ef0a725890a667b3f543a31bb6f71.grp", + "/assets/717db9a586973990d26433dfa01ee837.gd", + "/assets/e16962f24bdb53f03eeeabbc71bf41a9.gd", + "/assets/6a71fcbbdced6f674392676975ce0edc.gd", + "/assets/925d837056886405f0446a674d888c4e.gd", + "/assets/c863a17dcb389c306a0153c477e93b01.gd", + "/assets/ba05fec4b664dcb59024a98d2f4f747e.gd", + "/assets/3a2567449aa1239d21dde90a3b5e778a.gd", + "/assets/dbaff7fd63df53ec9e568f62791709dc.gd", + "/assets/eaff0a4e525b6c0786912fffe23c4a72.gd", + "/assets/a2a9f423155f76c1c0ab240a3afce927.gd", + "/assets/3ac4247343bdfdfb8e57f7048f641044.gd", + "/assets/bc82f10be0bbe7651dcb02389b4d1655.gd", + "/assets/20e38314f47810065aa4c75d668bf3be.gd", + "/assets/1b871b2d2975dc96d3f12ee5f98ef70e.gd", + "/assets/61dc16291df3d51dba18947ea51a2b9c.gd", + "/assets/be8f1bd0b5eaba87f5b40196df600963.gd", + "/assets/7485664c89137b489660e9322f42a14a.gd", + "/assets/23637debb15a7a772222fff7c2a84220.gd", + "/assets/cf1acb20c877901884ce440e9794ee53.gd", + "/assets/3062713b88797408ee4ef6153b9cadfb.gd", + "/assets/3dadd617ea075f2fdfb937fbdb7ea677.gd", + "/assets/9977cc43724a832fb9e6ef4f23bd0a50.gd", + "/assets/356f592bab3d0ce80a1155e0ab024282.gd", + "/assets/a75c7d5ba623718c442022ed96a6d2bd.gd", + "/assets/18d1997d5f90d569a0dcce53df01958b.gd", + "/assets/47c906a368cb02c7b762b8a61c3e8d1a.gd", + "/assets/7adf2ae3d7764c6e0983b199f3ac9759.gd", + "/assets/ca080e232f1de49cd355502011205ef0.gd", + "/assets/b09bab3c136bb9b429d23dd7a483af77.gd", + "/assets/f92c3d8d6a0efd66cb2d8d49a3f0e9c6.gd", + "/assets/6139a2400b5197d8428bb4909fb5566a.gd", + "/assets/8a50fc12606274564d0850ff33643450.gd", + "/assets/4494ebf38376328f8716e725aeb4e5fb.gd", + "/assets/3866292f69c2a500c32a110df59f1f23.gd", + "/assets/d04410be87921965eac532327952a8fa.gd", + "/assets/7875dab8592ab025a53e33d3c5a53ba5.g", + "/assets/53b06cc161315b38e5be60f142324a56.g", + "/assets/c9a3f9c73606ab9ea3d7f8a463c2cb90.g", + "/assets/0375fd1e360f36c41bc62dd1cc0f81f4.g", + "/assets/70eb7fb0e56d488611afe11268377b53.gi", + "/assets/7c6ea6d9ff683dd8a119efe7672ce0c6.gi", + "/assets/d8ed170f3a66fe9990b46a1a0ae8ec22.gi", + "/assets/17648043c943b79283a5d77ebfed5050.gi", + "/assets/a0e934c5440d62361eb7649189bd2826.gi", + "/assets/3d111a0e4b12dfbee0d5bfffc1481d99.g", + "/assets/5c776a2ebe49a30c315e805b4a33f133.gi", + "/assets/01ef198944fc1544235a50d722707715.gi", + "/assets/18327e68b0b44e0a4a1ed7edefafa1e5.gd", + "/assets/6ed2cb5d383c691da7f5de1bedc18baa.gi", + "/assets/535d31a892b9a486c48a5ad81af00cf9.gd", + "/assets/9524c07a101502562a9173cd7f25407b.gi", + "/assets/413eacc2e555f0667fe4af92867e2046.g", + "/assets/b43266f46644fa7cd81c52230f39e1de.g", + "/assets/691392fda6a9239e4b65064539d64372.gd", + "/assets/ae5f140ad1b79ea7f8227d041b3de56a.g", + "/assets/f354d06f26651762767ed927bf1ac8d7.g", + "/assets/61cf34785f68cf492e6a24df0dc4d964.gi", + "/assets/162603bd5dfc86bdd22a34f0c61ada8a.gi", + "/assets/efe76b858fc938d753b808f254874bdc.gi", + "/assets/2281a8609fc491813783508ffcc83a45.gi", + "/assets/d027ce57387bd98aabd89040f9e0ce3e.gi", + "/assets/49ba549f983bff092e70482f2482c652.gi", + "/assets/d35524c004a3363005d2c04973cc0547.gi", + "/assets/6c6d5c204b67e2eb90c7c2d9618f92e5.gi", + "/assets/463360277db99fab322b7c3836dc34c7.gi", + "/assets/2e7dce114525a7cb088fa1c40d927451.gi", + "/assets/4334c834cd2f2f31a5de3475b1a77805.gi", + "/assets/bdf4c34983c09bc933baf7167d9c2e83.gi", + "/assets/aae5cc427ee67dd2f691cd8cb2295c03.gi", + "/assets/5099b3300549099da9d8bcb5d1d1220f.gi", + "/assets/ad5693cd129ca1413c0bc32781198687.gi", + "/assets/5ec293b1e38763deed3f666de56b24d0.gi", + "/assets/7adc898a54d1ff554fa9f4de6914c753.gi", + "/assets/014631854c313a2dbd83e47624ab7855.gi", + "/assets/994d2b24f910ee253f7e2b13fc3981c3.gi", + "/assets/4fb81bb7310abb99358d065e1bb8f3ac.gi", + "/assets/6ed4e9963932040d9bbde6d07778f03f.gi", + "/assets/6aca41416a4c62b888a2dc869b54380c.gi", + "/assets/22db57e5c8ec9efd6c7f11989b1cfd2c.gi", + "/assets/9d3000b34bb5130007fd17597dd07122.gi", + "/assets/945d8f964e0d67c3f25c5a070fd5d6a3.gi", + "/assets/d12439eae34b70f2dcdb002e513150b1.gi", + "/assets/8705510634743f365bcf1959950ac88d.gi", + "/assets/484597b7cbef78fce7ee41828c3bc707.gi", + "/assets/b35f2fae254339d00f4545b86e58a0e5.gi", + "/assets/92c63fdd2e6133ab66b91abf18d786d3.gi", + "/assets/52c0606cd2243258139cfef2a4ea02db.gi", + "/assets/2d79435d9a21b5026c32e6f04b59eed3.gi", + "/assets/218c13ee1485f454e341c65a5e460707.gi", + "/assets/2c1c8f22e4eb491d5d5a4e5b4ec67fd0.gi", + "/assets/dcd1b56d4899af7eb3e75644c2a28dc6.gi", + "/assets/51a8766470052982ab4a4effb6857caf.gi", + "/assets/f5042fdea364c94c8b547a8070b37581.gi", + "/assets/c5d73f657d2864785184e41fa14410f9.gi", + "/assets/914bba4fefea50758b5a606e2dbbc277.gi", + "/assets/f135a79b20ddeb0b999f991fb42efca3.gi", + "/assets/3a7843d8a41cd4f3fc3ff30c8225671f.gi", + "/assets/5122152b05c73fb74731118fe3b711be.gi", + "/assets/8597ded6f3b2a6987d237799e12daa5b.gi", + "/assets/38dc5576cfce0f1cbf0b66a28f2cd808.gi", + "/assets/91b0a4f1e1925d25f6564c4ef6e3bc93.gi", + "/assets/c9ba82f4f403faddaef80dd6ef95c03a.gi", + "/assets/47aee3024d57de886119f071214a9ba5.gi", + "/assets/c51b2be344a9e2734b090ef236cf1561.gi", + "/assets/82a756492fc6b17fb8bfb4d7d25405da.gi", + "/assets/f00d2857166df987a2a21f3dfb38f0e2.gi", + "/assets/373f17f0ee2781808c07014e4ed54369.gi", + "/assets/d7c6bcc7448f23538a4d74f088a69a7d.gi", + "/assets/dcb219f6e9dc215005912adce4196abe.gi", + "/assets/35f3e2aecfc061f28bbff7918d5df0f6.gi", + "/assets/1fe27d1bf56b4e65c17bbf73502f3090.gi", + "/assets/838b4736447cd75e54663c21642ddd95.gi", + "/assets/39d33d9f108f1cf0053c79c672396f22.gi", + "/assets/a1eb33a73d91086c01fa92f9ab9f7d9e.gi", + "/assets/3891eb42c13bcfae24caf4273a47b79c.gi", + "/assets/44fa558698832fd85de22602dfe5815d.gi", + "/assets/868b80330f7cff0641eddc4b33d96ac9.gi", + "/assets/0517a430bc6629187aec2e4b0d162ffb.gi", + "/assets/cfe05caa8a492d46610d310efd911ee8.gi", + "/assets/79499500b3839e0ac38e6f5f4bf3bc07.gi", + "/assets/419f93c38fe04e91233465e558a5e35e.gi", + "/assets/263bc8abbf6e472ce365b169fe3272f2.gi", + "/assets/092bb3d29a43488f443ddc9075ca6848.gi", + "/assets/bfbc8b997713270458f7249690df78a5.gi", + "/assets/429843578f04f2c084d840bad640539a.gi", + "/assets/eacd75ceee07733c4b36b71daabe8c69.gi", + "/assets/d58f855fe6c7adb155dd267b9e655929.gi", + "/assets/4a9961f6bfb9fd2e356afad29b6ceda6.gi", + "/assets/ad9b87a208203491a6e2654f5a1bed03.gi", + "/assets/b18397084793948af8ab19181fbac950.gi", + "/assets/72c9e9fe70231c45a5b97dc9d70167f7.gi", + "/assets/f47177a23f7b6bf3399722303a49f6c0.gi", + "/assets/b045765012b0554b12cd5fcdd26ea651.gi", + "/assets/a342526b9dd234ab57f8350fd03e9030.gi", + "/assets/08d49a14163f2f02b2af01d588148ed0.gi", + "/assets/8798fb518526d0b50dbf339ff1d119a9.gi", + "/assets/f952a01851ee58239ee0560c041a7935.gi", + "/assets/aca777915740624a4b8f113719d8184e.gi", + "/assets/189df92f178b1195dbdea4a5b3c0e654.gi", + "/assets/d384197d705585fd56216082bbd635dc.gi", + "/assets/0c23fdb71017fc379e4752e9cca73878.gi", + "/assets/2e285d36ef3e88d972bb81cfc36e9a7c.gi", + "/assets/e8f4240b4255f33bbcbe731656f6c953.gi", + "/assets/71472683efb83cb85b6351d3ff63709d.gi", + "/assets/cdbd4cc0d5fcaef2d04bfe391730e731.gi", + "/assets/ac341cff644e84d45ee64919460cdf9f.gi", + "/assets/763b5a0911332ed3c0fa490e63b5fd2b.gi", + "/assets/b2da1793bf3c46dd3230aa0b1a02df7a.gi", + "/assets/43e54511287508363bb50181ec3c595c.gi", + "/assets/3b0f91588bf6eaa1589609d34697dd02.gi", + "/assets/5fc937b3cd5347a87709f8738e29998d.gi", + "/assets/f4f3121e125f0b58b456d8ad983707d9.gi", + "/assets/d52dc7c063b77ff8a26612266ed2f984.gi", + "/assets/f94a26e0780fb2407fc2a061a5194796.gi", + "/assets/158f9c6a3e2841cabb7c93d35f24c5d3.gi", + "/assets/5e4778c1c993dab523e22f9077e9fd87.gi", + "/assets/6256d13458fb2ff6431f04344f96932c.gi", + "/assets/9f6f1f8b0d8af3f146e248089b495a00.gi", + "/assets/37287f1fadf7cf54bd6049f16425897a.gi", + "/assets/a1411c5d9489e28604a2e7589fc681dc.gi", + "/assets/20d865fcfc15d77f22291e11e900abd0.gi", + "/assets/068fa3355a420da3c7b0e96019013133.gi", + "/assets/7a8910be39b6efc0de1b6fac35c085d5.gi", + "/assets/cfb9140d9d55933bfce0dde0a1ff46e5.gi", + "/assets/b7cef165c8b048c45d2c32186bb0bc32.gi", + "/assets/4cbb3e67617c216f22597011aa260653.gi", + "/assets/2581b24ec71bb2f0e975d9dd6ec488c8.gi", + "/assets/523844455f129670df035292e99bf06c.gi", + "/assets/23bb769bd7cd2535b33c4c258b71710a.gi", + "/assets/d0b38cf5f2f5b57d52e2cd7ea78edd42.gi", + "/assets/1560f659de0df9098620ef31b2a0e3ef.gi", + "/assets/8e1290dd7383b958171544a8dbfd328f.gi", + "/assets/25be1cac24b5e8392e6f9d44a486dee4.gi", + "/assets/e2f48639c842cc08127d1adb5a1c4c10.gi", + "/assets/0b4d6330f027c230da69cea36c24b00b.gi", + "/assets/ec17c84f9110cf30578e519510a4b3ae.gi", + "/assets/22c3948e8b09f8123226bec64b16b116.gi", + "/assets/8ebc6b59e82180e91f846e9143062918.gi", + "/assets/a4899c4554b1181547d4cf99b5907d43.gi", + "/assets/ce8541c9324a18e4e7ae76788c92a329.gi", + "/assets/ba9cde3d05eac2d6b1b0e9cdb71d6647.gi", + "/assets/8f738d1e275e806631c65928e66397db.gi", + "/assets/4dbd5887a0f83663b9be8a6aab48f436.gi", + "/assets/6a72fd06eec1d3240e165224cf528fac.gi", + "/assets/b4938d930c65f88b308828d22dc6461a.gi", + "/assets/a4e3175c340dca77aafc5584260c1c18.gi", + "/assets/9ae8be99dca2ee0d74d411220169084f.gi", + "/assets/fad36c5b70bf24164e5d9cf0d068c899.gi", + "/assets/2f5459a11f8df2642c1925366092cef4.gi", + "/assets/51822835ce7fa5faab2210df355daf54.gi", + "/assets/6d06d42daf220b4c6f3c558df27691b5.gi", + "/assets/4a012ce5c9f3e4ba40f9fdfeb10d766a.gi", + "/assets/5cf42baf6c7720fed6e35c2aebe55588.gi", + "/assets/33f5f11e6aec2e31691f9ccbbcfffe5e.gi", + "/assets/138f952d8f03551e89ae65990cf546b9.gi", + "/assets/cb0ccc18710b70a9cda71de9cff221cd.gi", + "/assets/8270e7955bfecae648f5b2694fbf0098.gi", + "/assets/e18163445b1745a4a6843495efc34f83.gi", + "/assets/5720229e1a165587b8fd31f3beaf63de.gi", + "/assets/3dbd22020965c9b641f0660fa65da975.gi", + "/assets/db7e464ccd06eb06cc582ffe0b83511f.gi", + "/assets/6b65dba419754e2a6bd542f5c25ca8d1.gi", + "/assets/bb0068c9fcce75801944c799128c65cd.gi", + "/assets/1c4057c63f2ad5753c8ebe016658001b.gi", + "/assets/b8f9f9d0793df08d62b84884726277d4.gi", + "/assets/5378081c0860b8b6e5c2477cfdecb78e.gi", + "/assets/d5a78134b71d5fb0a03e47005f139794.gi", + "/assets/4055786cc2c64b3aaea35074f1987cc2.gi", + "/assets/fe94cf3cec89784eebe6f3d30bffe543.gi", + "/assets/91889a3c876f9b0bef823dce552080b6.gi", + "/assets/baff17ca4cfe96f18912c8c95d4bb6cb.gi", + "/assets/a5f9564e67e07908e7bf2917309f6917.gi", + "/assets/f8bfddabf55207c8e7edd8769e80a202.gi", + "/assets/a219475f55d753f86bf230020fcf7919.gi", + "/assets/80e2a8b16c2548b7bdb63887860d836f.gi", + "/assets/19fa64333890aec931cc669a1b6e3aea.gi", + "/assets/a660df4d3de22e7f7e22bd3712075f39.gi", + "/assets/70c3838a9a092493a8c5ee8311db1c7f.gi", + "/assets/4b6f5cff2587cad6b32ca571326089cb.gi", + "/assets/c4d75b1a1f8da93d463c97e2da21ab89.gi", + "/assets/3788a9bd6856ab5bb01ef1f523e556ba.gi", + "/assets/e74ae688612ca1bf4dd2fc3a03b41732.gi", + "/assets/cb38d4257e977eb810196016211bcd0a.gi", + "/assets/f2b0250e1b4e624df6399c34b7aa3c81.gi", + "/assets/9f9bfb3507d5e1d40b9cfe0af51f296a.gi", + "/assets/8534cf8cc7e4b4fbbfe96e33b686ad34.gi", + "/assets/2308107f772c30afc63a5ee6fd3e8712.gi", + "/assets/2748fd93ef25cb72f1e67686c34e6f6c.gi", + "/assets/b4113a34e07480d25c62d7773b3c4cdb.gi", + "/assets/57f3e5cacd5d9c44c3ca1b87bdccaace.gi", + "/assets/8838f6babae62e0be1a790df30f0a59f.gi", + "/assets/610f5ec94ca24da072e69ede67242cff.gi", + "/assets/d3ae177a439327e018ea2a63dff0f282.gi", + "/assets/5e9c0ef43ee01c7b047e8c69dda041eb.gi", + "/assets/5630cc584c5533b59ebb9e0047150f43.gi", + "/assets/b98e22b48a07e9b86be4c30fbb82df93.gi", + "/assets/6b4b83040c281f8335908fdaec85ba80.gi", + "/assets/456827522370dea3d0ed41688a6e2272.gi", + "/assets/941f104de48210d8a583cc6a47582885.gi", + "/assets/97c183ac299704f0726357f077bb36e5.gi", + "/assets/b7183953743a52d06faa451586454c43.gi", + "/assets/2f853361b77a086071133388051021c9.gi", + "/assets/cbe2fc9ad848c8a0b65a002a73f4fdf4.gi", + "/assets/09939753dd1d0f7cb59ed6fe9142f5d1.gi", + "/assets/cbbf5260fd359c37964dda893c42f42a.gi", + "/assets/01f23f56d13761088ec5a198bc498e3a.gi", + "/assets/27a0f682b08df3cfb95dc46f2660ce8d.gi", + "/assets/0ef2f4b6918e8852c0a6fdb79f61e108.gi", + "/assets/cab2313fe56134a7196f3447268af644.gi", + "/assets/bb33954a46e1d7ee7eefe628751af959.gi", + "/assets/d4bc27e8e7ce249055753796ee5382b6.gi", + "/assets/e1a11b1ae8153aa062eddff14964b0f9.gi", + "/assets/2d3df1a631b53daf44f5e123784d921e.gi", + "/assets/6ed9d5d6632ebf6bad997eb562578b3f.gi", + "/assets/a9651586ed3d208811a8d3aa9ee79573.gi", + "/assets/a3c2b868cbf525b250eae4a2304b8078.gi", + "/assets/b49ef2d02cb003ad38f1ef77677ca866.gi", + "/assets/8e6c861dcc41bc7d0f125ccc9a98b7ad.gi", + "/assets/bcc6f3f73d65ab7031b947a27fa97206.g", + "/assets/9f3be8c576c0c4127295653d7ce52fa4.g", + "/assets/5629f8d306879daa321260fdc435ec2d.gi", + "/assets/3ed5fd6227346616188611aaff22b7e8.gi", + "/assets/ad908567f557596a3419d52c383a86bd.gi", + "/assets/f66828bf70552fc655dedbcb660ac8da.gi", + "/assets/bfb492b7b82a9df0c68af195a6a2808d.grp", + "/assets/58e5ddbfe67ad90b2351771d09594485.gi", + "/assets/a6cb2e4d4befaa93fd4970b4bb5fb587.gi", + "/assets/f3d51daee9d8bbcc1acad47c4a6f7597.gi", + "/assets/ed95f65d36555301536f98c0110e6ec1.gi", + "/assets/4327ba657f13632391c76618a1df61ca.gi", + "/assets/bcc975e89d56454c2efb39318e77b006.grp", + "/assets/2d46a821485493a17b0c5ba1679008b2.gi", + "/assets/fdf71982356787c4b8d5a1ff393f0609.gi", + "/assets/01f8cd33003ce34889cc56a84766b9bf.g", + "/assets/2a948f8650f04433f8a611f6719ff375.gi", + "/assets/fae13ea8e9bda0cc7a6b42eb64676e69.gi", + "/assets/23b460aef98d9c30e9ae7358b86f1ba6.gi", + "/assets/bac2d2e221c1d7c99c9bfed6ec97cbf8.gi", + "/assets/d0e1db39bc0ee59319696d79a2dd3ecf.gi", + "/assets/348483bb4c3adbd8ad25265997bbfb28.gi", + "/assets/b3a612810d9e29e11062eaef7b83eeee.gi", + "/assets/a1d0a1ad3fb21a668b87ca1b1ec959e5.gi", + "/assets/0826e53a7467e92da00583e4ea911579.gi", + "/assets/a8774f14f243a9c83a9d8054fa821d0f.gi", + "/assets/d21c7cc2f27915f2a3bb064ba738cda2.gi", + "/assets/ceabfbabf64a0fd601bb9adfa983f5dd.gi", + "/assets/087a7a3906a8e2c515f5d52fcd3d8291.gi", + "/assets/3cc2088f83937f39943023714808b0fe.gi", + "/assets/63098ab86b08bff63b7d2637e2d12032.gi", + "/assets/a739c531ee42a0af82ae4d34758730ec.gi", + "/assets/f1fed13939f3289c52de96dcede61a5a.g", + "/assets/d249178334251386025e9e27675039c3.g", + "/assets/d76f437b9d3479838b44f954c98a74bb.gd", + "/assets/23a22712c061ce1422e40e03a7f32635.gi", + "/assets/6422b36ffe0ce03b13f18c7be94e3a5e.g", + "/assets/837ae05116a3566a933608c57795964e.g", + "/assets/055e746f6efefcb538235e15ae5cdfe4.g", + "/assets/ed01a379a4ed3f7e80b78fa547e80d6c.g", + "/assets/e6966e517738d1de6e67fbfaab8eee6c.g", + "/assets/3532086feee3b7f65cb9341a62033c8c.g", + "/assets/2f84b68cbeb5336455e808783fc9a42c.g", + "/assets/aecf7a810d30b63d1787a9777671319a.g", + "/assets/91c553aa9c25db0ac06cf4131017266f.g", + "/assets/339981189c445ddfdd2c3616a87bcefb.g", + "/assets/a94e004a676f6ad054f74a98e3599649.g", + "/assets/66b54c2efe3f036140135c3e06c12cc1.g", + "/assets/2dc1f9ce7d1d7bca469de03f59b7fcda.g", + "/assets/d61b2ed6dbfe0b1d833e5fc546324638.g", + "/assets/8687f72201ee3560f1f76141498a41f3.g", + "/assets/078ad826ccc19c163de95a739f01de92.g", + "/assets/8531026ee51f6b42f457d010d836a417.g", + "/assets/37554afcf9a5f2f044d77353b3469647.g", + "/assets/7f42020875da0f48c75a7f7fe2b7e810.g", + "/assets/fdfcfcfacdbb2bdb6d4bf01476c17020.g", + "/assets/2a4c7d6f27c813a3596f0575f7036578.g", + "/assets/82da3fe0b7ea9e770e134eae35c4779d.g", + "/assets/7bf05edda5b592b74c950095358034f9.g", + "/assets/3851527f06a1610be0a3b83da792f52f.g", + "/assets/aa90965da1817b991f84f72042f36fac.g", + "/assets/be4fe494ab8ef820e001a4b53b965f54.g", + "/assets/3c0ce2d6cb7d925ccf102efbe004ae5d.g", + "/assets/e6a93456f7b8ae6bbc803f5c4b649270.g", + "/assets/4ee648b871ec57a7f00e07de3a737e93.g", + "/assets/0ee173a59ded66e856c4e77d1eb3d3ba.g", + "/assets/915ed9e28533dafa94b8882fd8200591.g", + "/assets/dc76ae5f31532af0a0f858ac3ce89a8c.g", + "/assets/c43f3eff03eef2f47a1b5c07b3f99130.g", + "/assets/9398adaae92d2abb4e7f09e0371ebf91.g", + "/assets/ec8b15ce4ce3b8d1a9dffd4cded7dab9.g", + "/assets/3101acbfa5345302d08cdab0f223316d.g", + "/assets/4adc502944273c251bb8dccc81dce7a0.g", + "/assets/9d78ce21a07a8a1bf2827e21f0b9065e.g", + "/assets/0c0874a60f01368bd1d5bd4f76e66ada.g", + "/assets/f04e6be2a71a0c7e7e2af2942cfffcc6.g", + "/assets/6037cbd195b34805f9a2cb47f9b4465f.g", + "/assets/6c87cdb5cb7e640d20f1f11f14a49a9d.g", + "/assets/2b447908fd540af0122f528860909904.g", + "/assets/778bd42001e29be093b7adb191a2221a.g", + "/assets/3a580f1e07c90f3bf26c0e0b0d4104d5.g", + "/assets/e8a5071078fd62f064788376a2a9ad19.g", + "/assets/7138c56269abb515276089bf611e5139.g", + "/assets/ef70b06b27ca3d3a98258f2c7ea2e172.g", + "/assets/c36d72f9282af5fef24143ecf5f32477.g", + "/assets/18efc500ed9351c27d04da4b82e83e69.g", + "/assets/d02024b4d35c695abec41e193733841c.g", + "/assets/769e59cd46ae135444ec3b13e359cc9a.g", + "/assets/822f040b33537f8f4b96b59c6f166ab1.g", + "/assets/18753b1cdd655bfa4e79a431552bc730.g", + "/assets/1f5245d448dc2680da7d71fe4194818d.g", + "/assets/c266cb87485384369dea671b1ae4a8e8.g", + "/assets/667542e24a3bf673717af5da6f21e33f.g", + "/assets/fcb9e670ffd6be41252d397f0555ee81.g", + "/assets/317b6c1333937a9c05230267d54f5d3b.g", + "/assets/95f6046960dcd2d058ed11c59ade9aa0.g", + "/assets/4778c57be6f64907c04b8eb1a259fcb1.g", + "/assets/ae6e8f066e0995c3e65faa090cf345e4.g", + "/assets/ff1f53ba80d567b09de0dbf62533a89b.g", + "/assets/7747a0a407089ad1e4a713c216c8f60c.g", + "/assets/375822e0255277eec11923ed6f4adca6.g", + "/assets/970be3df1e1ba60ecbfea9f0f06cf446.g", + "/assets/b208e0ef0f98e50ae47cdd1814a5ef3a.g", + "/assets/42c58af1bb2ae17f74433385c2dcf67f.g", + "/assets/02ea1c3674dcc6e15873d3ccd63cc007.g", + "/assets/15b15553217697857a174e0230789c70.g", + "/assets/ff113ef89b15c96ee4d931039909c13e.g", + "/assets/ec7456f33e8ced9ff3bd198185074bc0.g", + "/assets/acbbc035dfc702b6d277b7e1f74f2919.g", + "/assets/d25ad97fbc3a8476806d9bdcaaef7a54.g", + "/assets/be535f897be479668c505ac972fcb4cf.g", + "/assets/9089e0d9148205393e0ad7f98fb66363.g", + "/assets/7a58b3238a56998847cdf6f36dcc9530.g", + "/assets/d659eddc9be4bb81ea41bce82c3eec2b.g", + "/assets/9e979a3e247b3ff0332cbb29cf121c8d.g", + "/assets/9af02224fbabf9cc826bd18635441d79.g", + "/assets/561406a0c210140dcf67a020dccf4978.g", + "/assets/fb32126d066aeeed96a47e27eaf59ce9.g", + "/assets/da3b9212f9b6675b8c2494c77946b942.g", + "/assets/83f5074e0e235d6e4117d2c00ae0bd11.g", + "/assets/45b13217b4a4f24f4cb2123a93af153b.g", + "/assets/aac8a9ea1884fc144b27015a901bd01e.g", + "/assets/5d0055f9f50d982d8cb015cd2c8abb5f.g", + "/assets/da1f9d57995a5d2d5207c36a6005d455.g", + "/assets/7cb88d84d141ff7840883a680ecf976d.g", + "/assets/edd484549de699b34a0d9a89f65a8e7e.g", + "/assets/db3517962828bf71f70a8b789157af28.g", + "/assets/746a188e574d7b0b6a3f2021300aa2ba.g", + "/assets/5e8e7f0a27604e90d0c987b6a2ae1352.g", + "/assets/c022dcd96c1458405aa4fff74f7ca861.g", + "/assets/2e52bcd8a4487f14044e6b9f49673dd1.g", + "/assets/ac67111b6ac08c3b50233bb80070f3e8.g", + "/assets/a910e29ae19c6381cb6ade8f18bc4472.g", + "/assets/1f987a62ad133b9a1c02fe74d8edf208.g", + "/assets/a4999f801d5deca3596e00ed5e8651e0.g", + "/assets/ab66e7e4f062399ef415bba986c6cd78.g", + "/assets/29a599870ad428390972cbdf55332946.g", + "/assets/c41baad40ca70f0e4cb50aa577a32b24.g", + "/assets/2210698a1c3434d51df0cb8c1ed9e0ff.g", + "/assets/222e5a72f220fcc7b00067453248fb53.g", + "/assets/97854aacae11b60c20a6bcd9f84409af.g", + "/assets/5017847c27abec6c2c73a3eafefd46a6.g", + "/assets/050915d5ce7d06f9db2828a1a5ba471b.g", + "/assets/1912bf2b6e55dfc628aa80384d230907.g", + "/assets/a8e8e6b1c09c5c6b439855d2985a3daf.g", + "/assets/7cbe82fd3799e54bdd4159902174a4e5.g", + "/assets/dbb0a2775821a5e188a318f0ef879eda.g", + "/assets/7f4af1227cbaf1f570fedf0b47c8c45b.g", + "/assets/a08903532a249b9a4c0645b6d96b8c31.g", + "/assets/ff2bb4bfe68955035548ab16f9e72085.g", + "/assets/93150d80005e0b6a9599d0576e7510d6.g", + "/assets/8d668b394c974462a65c19d135652949.g", + "/assets/6814933919271aa3f4efb30cfef51a08.g", + "/assets/b61646e7496b9b608b72bb54b5c12340.g", + "/assets/9af4f243f83b5898c84a8005713c30bd.g", + "/assets/9a5dcf862e061660c808c3314a94b021.g", + "/assets/2fbc5fbec922a0c432b9ae0ccb83d2ff.g", + "/assets/4acce36804a4b5a7bb9006dd9124f487.g", + "/assets/8127d0f7d037c92124031d7045a45b9d.g", + "/assets/d21d7d802028b2dd43f1eaf94e78baa5.g", + "/assets/c0f4cb1b53183a429347318cfd0a8024.g", + "/assets/750366cb8c874a0b24fcaef7e1fac168.g", + "/assets/e83578309f44cec2ba910f3a34746c99.g", + "/assets/0e45bfcf86fbf18fd081156554da5dc3.g", + "/assets/1d25d2ac981ecea289323d816e2f830c.g", + "/assets/04f61cf5b376b83bf53f66eae1f65e38.g", + "/assets/50ecd918dce970cb8e9a85f74931781a.g", + "/assets/c93255b63cf7cef0390e21e3de7dc21b.g", + "/assets/c1bbc787c75b0ef16b5a32f305cd46c5.g", + "/assets/3d38855971d57f9313718232dd605a40.g", + "/assets/7b852676ba48d92a2ee0d560d268d9a8.g", + "/assets/c9fa9c0e4d52d2ea7617427c814c68c2.g", + "/assets/a71fafeac8d54a6f6b4eeef631f75738.g", + "/assets/d824dff08fce89c430a9899974a273a2.g", + "/assets/3f47d50db205d1472b7bb4d535e9565a.g", + "/assets/229948dfaf84affdfc820d4fb8cd04f4.g", + "/assets/6e6aa37c52808fecb1654d70d8dba829.g", + "/assets/74ef8ef47f251f37b38b306e1cd34b94.g", + "/assets/6fddace42eda8cf334e736b163d59e76.g", + "/assets/ddc3d357794eee62f86d3db3f85d1cad.g", + "/assets/22fb67325f50c19b937d42e60673d437.g", + "/assets/c5450693c01e0428f14665c31f23f0f4.g", + "/assets/37be298c3ad79e5f7856daa466b3590d.g", + "/assets/cf4b56148876b50b8b6c99cffe44ff4e.g", + "/assets/9e7c097ad72fef85144f12f0fd0285fc.g", + "/assets/d6610ba05c300bb6504ec8273be19d4a.g", + "/assets/8f6b7a0c58cbf426559c3790d451d59a.g", + "/assets/9439fe9763703d272169ce52ee18b6af.g", + "/assets/83265062388d18c9a82bafb4fbdd882b.g", + "/assets/0bf937751578c14d510864a8a97d1beb.g", + "/assets/7cf1050a47a6b52e9679e40886ae0286.g", + "/assets/df64e74aef60bff23b69c61e01e0b68b.g", + "/assets/5ee2a4c4abbc57224d973b706911dc14.g", + "/assets/ce0898cf32b423e601364a6ddc895846.g", + "/assets/38f51294122a720244819b9d549578e1.g", + "/assets/3af7132c3233aaa6c39974e0c14d9140.g", + "/assets/5ee79d30da383f6d3864c6fcbac39e48.g", + "/assets/3a93f2ca5ea78f85abdd9e0ee8b36b2b.g", + "/assets/ac8ce87ceef78d725993204dde60f6d6.g", + "/assets/b420ff8175b4ec3a61a4eb0ae9957530.g", + "/assets/41d9fb9cba23c868f0206bea23789730.g", + "/assets/a329d13c09c661b5864df56070468abe.g", + "/assets/6f99608e3c1e8d5715b6cbb538346130.g", + "/assets/ec5723f85b5ae1fe3cffa3a52942c9a1.g", + "/assets/eed0bb8715296ac07f61065449277884.g", + "/assets/efbc793e746da7f5c8ebdba87e472d54.g", + "/assets/d357af70ede6b78d85192fbb1462a5a8.g", + "/assets/8a0dadb3b7f257887d2bd70361d11793.gd", + "/assets/8056d5dc90a519ebac3678c06a1cb065.gd", + "/assets/9f3a0adfa6937904068e80e17002b3c9.gd", + "/assets/b3592f2b87dae0d5ffbc527a1309d952.gd", + "/assets/72bd6bd68fd1b065eed18e6c4481394b.gd", + "/assets/0ddb91eb203add4bd3d95153a966619e.gd", + "/assets/9204980790c707c36d9e51e5d7a96c82.gd", + "/assets/a5c8d441e8a0f5bc065bcb2a5dc5a53d.gd", + "/assets/1db05f2a8b78ed7ea39b055cd36b4a64.gd", + "/assets/d7193736ebb6cb65a748fce4082c68b5.gd", + "/assets/cbd005751129796d12902a3f6bcc0558.gd", + "/assets/fbcdaf2ecc48fc8825fee8b7d43ad320.g", + "/assets/ea41a96a6a82d6cf75f6ef0e0b0cdbbc.gd", + "/assets/f9f83621d712f08fb0bb3448262e3ccf.g", + "/assets/bc37db673cdcebba7bd9d9e7f73b5517.gi", + "/assets/a4392e3fc1fe5eee941c4e61b57b4b7e.g", + "/assets/4325112549c917c9faf52a2814af2dbc.gi", + "/assets/a2b1005e372fb7802e34214ff3e2725c.gi", + "/assets/bd306466ef02af88d4ca6a8ca6dceb60.gi", + "/assets/6c40d2809e907ce082c5c2ac1f4a5e8d.gi", + "/assets/896dcd6ece0c5618d423c64b3cb9fecb.g", + "/assets/1ad140f121b206fab96707e650fcdda0.gi", + "/assets/80475536378701826769b35b8222c01a.gi", + "/assets/8b245b4ca65d9ea3d8f2470d00bb855e.g", + "/assets/4e4a9a44b8316058c78856f5800cb6f7.gi", + "/assets/2b95e03825044f1b1913c64385ce1d2f.gi", + "/assets/f254fa15850920ce4e498a8706824c9b.tex", + "/assets/4b3abc077949c42a45be95b7aaf9c6de.gi", + "/assets/e2428dfa63ca949b612314234e7d9743.g", + "/assets/d153a2b7f1423ac7e3f5b9bc532bb64e.gi", + "/assets/d38a6bbd9fa5edb792a63995cba35d65.gi", + "/assets/a2d0c36bda91c201077bbed0f4183d3f.g", + "/assets/4664da93d95164c1fb3bbb9958633bc2.g", + "/assets/ff4f96487ee2cf2bab653e1456a9fe92.gd", + "/assets/dc55d3ca4b2f83d93b3c7c52f19b0eab.gd", + "/assets/b26822eb3162912f08242b4b05da5927.g", + "/assets/baa786c859752aabf3195fd2f0776877.grp", + "/assets/25bd816f7e4f9f0e7794a18e528c7a4f.gi", + "/assets/e58d93f1b56362071032d468873b97bf.grp", + "/assets/c7eb1a98ca923ecf2fe99b1ffeb84e53.gi", + "/assets/1b094d784a398ad2704fe6bd4fe04ec8.grp", + "/assets/0dd84b0dba9e12121d8c0420320513df.g", + "/assets/34579016c5f859d74e5705e36944d4a4.gd", + "/assets/367452e8568330996c2fa1d5e8f9e2dd.g", + "/assets/4e8b66af59ae8e4b16d098fe10f595c5.gi", + "/assets/a3ac543070e76d5edc79298c96a4fdeb.g", + "/assets/634eac775c3fe82d3c5e2dda4f88b220.g", + "/assets/f9890ce00d6102230f88aa056863a286.gi", + "/assets/836c8d7ccb3f4a7c48e44c918b0b23c3.gz", + "/assets/ea550e45d94b511875e0303c3a53e762.gz", + "/assets/961ef1d734742c10ad797de45536f471.gz", + "/assets/02abf9c8a2b7e7780080f4f81ff63b98.gz", + "/assets/17d2bae2fefeda4bdf874adec6c96998.gz", + "/assets/15247f2cef1a973cc0f79be4e1cadeda.gz", + "/assets/dffc32eb41bcad978572848cf044f6d3.gz", + "/assets/e116fb6bb8207752a6c971490d1a4e26.gz", + "/assets/ecdd62d81c9814e2581f50917b9d80ed.gz", + "/assets/8b2f9299cd201c1d7aaa226e3679a9ef.gz", + "/assets/612e5509078de7d2ba9a222b6a897581.gz", + "/assets/05c05e91fe55e51e5a9a5575b7c35858.gz", + "/assets/7fc476269f19eaacbd3531167e63608e.gz", + "/assets/4b3153c1623ba549b64c07f09b473880.gz", + "/assets/fda262bc5989a9d855937bb9a139b949.gz", + "/assets/3ba9eee2f30b497c7ad52d82f631463c.gz", + "/assets/1f7a6335eddee78934bce2f9618d5e04.gz", + "/assets/23353298c07d7d9b32c3b6a863900ed9.g", + "/assets/e4c3215f35a43a55796f978702d1877a.gd", + "/assets/b35ac1f1a00ba2bc36aa94745404562b.g", + "/assets/bc748139967a7451e669498064174d92.grp", + "/assets/731a200bcd5cd96d8ae7afeb6302a6e2.gi", + "/assets/aac7c114e1dbce45f3db0abda79407b4.g", + "/assets/e8c94445ccfffa275b1357d56e1650fe.gd", + "/assets/c90f226d52174dc796ce2f8dede35aad.g", + "/assets/fe5aee6fb29c6aeb433b36a7a05f34de.gi", + "/assets/bf9019f9726cdd0716a4ce1dd6f7b22e.gi", + "/assets/8e3fe39eca03ada90de01d05bc607ff0.gi", + "/assets/d619caea27620f52a98943c76fe1136e.gi", + "/assets/6a32359e3fddecc6c232ab407061f528.gi", + "/assets/3ce752a9916a478d026ebf001a26e38d.gi", + "/assets/436af9a7567a76c76c3cb819caebe4a6.gi", + "/assets/004f6fbae2324bbe0da62d90cb977235.gi", + "/assets/524344c2a6c4b41947ee316544b4cf97.gi", + "/assets/80d5bdef3986a95c0aab6ed5539ac12c.gi", + "/assets/6c33b5b41af8d91396e20eccdfec5515.gi", + "/assets/4d36b64a1bbc27e2de7a3ac0cb6875ca.gi", + "/assets/4c35a5d39d1864dfbb014a09daa10edd.g", + "/assets/b5d6986debba9504cae30d760037c5c4.gd", + "/assets/a8a283cda44917c10cb7fa41449ed581.gd", + "/assets/827295e2775428e6b5a3aa7733ef3495.gd", + "/assets/656df33ae822a5cb83453abef6e017d5.gd", + "/assets/83f2ecd7354c0f94f53dd148993eaf83.g", + "/assets/6e82606d9d8fc58106c134c5a189307f.gd", + "/assets/5c73fe33e81f698e2366fb24a60ce747.gd", + "/assets/256e9ed7da7279e9dfd5ae73a46731e4.gd", + "/assets/826f769630b3db40196e0f930ffe08d7.gd", + "/assets/dd53b0bdc61b701494d8d807e6a1ee6b.gd", + "/assets/ff6c85aac42e02d883563acba1f4b8a9.gd", + "/assets/5358bc08b0e0024ea8f3bb66ec3c98db.gd", + "/assets/19ebea60765c35911d14d72cb537edb9.gd", + "/assets/39189304b03370a1dc07c74934bb27d7.gd", + "/assets/3d26f9b6003e20003337e8836638bbb8.gd", + "/assets/220ae011472b92c65848c7ff62edf5b0.gd", + "/assets/84e0bda3f3aa21395cd5e91c9620aadd.gd", + "/assets/b17b49ea2b16d73c193acb3c8449d78e.gd", + "/assets/a553a3b60e029c4c04e89dc3976a4bbc.gd", + "/assets/93196e2d296201f5a35ef16273013f32.gd", + "/assets/8e6bb02d6a476f8e1bb9b752ec3e230e.g", + "/assets/258d0d9a8ed1ec249166dc0e85d0c725.g", + "/assets/9e5a887a39ea3cc1c2524d3a52e47563.gi", + "/assets/dd4b1245f087e70debd880a6db951dfe.gi", + "/assets/7941853f0f80621a105c1f045a254ed6.gi", + "/assets/ab29881797ec13858b342429f9e45040.gi", + "/assets/cbc3f938480168b742b89917d7589997.gi", + "/assets/388c8b0f9886e406f6f334933832f0e0.gi", + "/assets/9ebd4f00192d6c578827b3836031357f.gi", + "/assets/ddd0ee2b6a040789957e609d7bf3da97.gi", + "/assets/a79cd05d7c28b68c408420ed5524d1a1.gi", + "/assets/1b19989cd628d4dbccc61f8496ec0199.gi", + "/assets/19166d636d8d07cf74f02f97981cb8c2.gi", + "/assets/b65a37dc696d3b68e8b36ea8ba25b1c8.gi", + "/assets/b7e73ac975938c528f1bed829c500756.gi", + "/assets/5094ab63b5643680628c68b07d00764d.gi", + "/assets/91c49cfb11bf2fb122b360851897f21b.gi", + "/assets/663c046f14c37b6775dc6c9f4ec5714f.g", + "/assets/74ef11ae89e3df6877b37321bba69839.gi", + "/assets/a42bf7692d3df05b3c3cceb194e07fb7.gi", + "/assets/84fe7fa71f20041009e3a7c20f81901e.gi", + "/assets/0ea2543393b55245109f0cc97e90de71.gi", + "/assets/a1d82ecb4045bd19b599e50ecf4f0d61.gi", + "/assets/7a1d09e6c8bb2e5e3c78c7f64b640ca5.gi", + "/assets/aa69ba1ab1c03d12b559ef20cf141fd1.gi", + "/assets/096296ad426723621f384d77bff67d18.gi", + "/assets/cc4cd0abea7691558753d784bad1b26b.gi", + "/assets/4f9db911256e728a49419a32c6b8fcfd.gi", + "/assets/7dd6f50ca7c98be410e4698df55f6ebf.gi", + "/assets/c11e44dfb8e6a974840281a2b0c76eb9.gi", + "/assets/b60c41fc76d60b9fc58f8377105195be.gi", + "/assets/be0c3aa73f658da18a7b013c9299d450.gi", + "/assets/a12cce81200ddfe4eb47ad6b9b8f7356.gi", + "/assets/4df996436cdea0b39560c6b6e9e49dc9.gi", + "/assets/2f7cc8c06eb88c5fd9ca0540a73a2ab4.gi", + "/assets/7f637ec2b64648364ce0e95d8bea97d6.gi", + "/assets/3b9347fac6c8705be630d4e24512a4dc.gi", + "/assets/5e78675fb241c72bdf4365dd7b4df9db.gi", + "/assets/fa970be4a2edaa292d821b863cdc7774.gi", + "/assets/bc0b9d9ecc7f0dd7e074e1aee270ced0.gi", + "/assets/74e5396fe5e23d030247cf945f97761d.gi", + "/assets/13184ffbdba969bb874744fb70fe6f1e.gi", + "/assets/c1d4dab28faedff17820787a0008c643.gi", + "/assets/908250c1e954d02d3b36678acb92e40a.gi", + "/assets/52cb637668fd54af492a9ac7b8965ccc.gi", + "/assets/75c4f59deba498845f6567bd7f42f247.gi", + "/assets/767faa12e19f276d5c0d5dfcb11b782f.gi", + "/assets/55db0e6b6d9c0e2e06f2b7a6bce253c2.gi", + "/assets/19028eb73e8fcafa5ca0ccddb3a4ac07.gi", + "/assets/0bfb9a0b6aa5177a19db88db1a34b683.gi", + "/assets/e907841fc3ba671c65e3e986659cda39.gi", + "/assets/9fdd5283ff2550cddc39d6b8418551da.gi", + "/assets/f9ac17d4d2b88bcf2ab0ef73be0eb8ad.gi", + "/assets/64f11d9ac4ec2affe087b52faa47c91f.gi", + "/assets/0b33573477bd5d546e0812e51df61718.gi", + "/assets/8affc98647de3e3844d923af13b8fab7.gi", + "/assets/87e221cc81c3c19c1479cc552fb5cd3f.gi", + "/assets/c7ccd54da09202086e5eb1226d8b7842.gi", + "/assets/c7227b1bb61327ba43bc9d78627dd6e8.gi", + "/assets/0a6430c689823cd62a67cc4994ee80a9.gi", + "/assets/4b8c0dd51842814c86438603805d98f8.gi", + "/assets/3ca893b4080d4a5903614ec3d43b00cc.gi", + "/assets/13acf93ccf93e2bea418690b270c1bba.gi", + "/assets/f781386a2a0c73168d4dbb88dc61c3d3.gi", + "/assets/0bd3c2bab74d2b63926682d80555204e.gi", + "/assets/8596801201c58a17688cdf2299fda6aa.gi", + "/assets/352e9fba349e098cc0d440f34cd1c7c6.gi", + "/assets/1cad469da38331de9376ab56a35a88e6.gi", + "/assets/3aa1f680fe12af3421032dc01ee12d6a.gi", + "/assets/832bb2628924d89b00085383a5b144fe.gi", + "/assets/4827cfb29961fc564fc21d0f48a7c090.gi", + "/assets/0d4375dbea831c9daa9930cce562853d.gi", + "/assets/51d44e38d00817fbcc24f71c467c42ea.gi", + "/assets/813e98183cfdbd52232d60b7d1fb1cc3.gi", + "/assets/2bb99d6cd89fb842c3a0613eb8fd45b1.gi", + "/assets/b3ddb7b83513d9b7d498fdde0ddae420.gi", + "/assets/c3c63a07ff5ebaedd5774cea69bc1632.gi", + "/assets/a04afcaf56873fc6d57c2f29992a25c5.gi", + "/assets/b0fa79200ee6d5e53e663a8646a69721.gi", + "/assets/7fddf04350826db5f78e18454d9af572.gi", + "/assets/491c108830e18f992468fd54adcfd342.gi", + "/assets/7eaaa5a74c6b8069ad1ea7cc7d3c945f.gi", + "/assets/7a0e8e4c9fcd9ce4264cd53f56a7c36b.gi", + "/assets/409a22ea4c6aa139f5e54121c1f6258f.gi", + "/assets/b0812cf68ee3ce3d5c0803ab915dc70f.gi", + "/assets/85fd86c91c2425d2db235fe4d9d23370.gi", + "/assets/a829d9a5a80eaa632993c95de45f4bc4.gi", + "/assets/4d2a9120ce933946d9ae954d7ba85307.gi", + "/assets/ebb0fe6e63f47e6cbec9bdda715f4fe8.gi", + "/assets/d914b85797fe28baa1018d52d011735d.gi", + "/assets/61f87a5406cbcf0b26f72dccb0fd8028.g", + "/assets/4490c004238c19daa02e01c6c0a31a99.gd", + "/assets/b5e62387216822b74e141a5bad33994a.gd", + "/assets/99edb876e928571083e33cb0827e9e1a.gd", + "/assets/aead877fe1a973227ab80266dc746c99.gd", + "/assets/797df631ca7dee5434d6a4b4c94cfcde.gd", + "/assets/637299d5b7dfce141875b83bd50a40b3.gd", + "/assets/e918d52c286539dad0172c88f8ba844f.gd", + "/assets/f00189abce1e3009f54800fa5693e6ee.gd", + "/assets/3e3c5bde57efb5fefe40be24a456e020.gd", + "/assets/85b0951df005877245f9ac05c5deddcd.gd", + "/assets/f9a950d9673a6f1bc79af0dea9379fef.gd", + "/assets/0bc3d9f04ec9ff7baa00001c167f11f8.gd", + "/assets/995cae4d8ddbdb781f6ff634094a36f3.gd", + "/assets/2f62ac1c7ab7b6e3433b65cfe8c23a51.gd", + "/assets/6e04d4cb65f5112de72881796d425099.gd", + "/assets/e445013e3d37ec9efdafb4534010ab93.g", + "/assets/c9d32821e444ad58930b9ac62881ed85.gi", + "/assets/c20d2cabd0788d8d994f94d5d9076650.gi", + "/assets/e4e0b6543fc66abe21952af67cd7128f.gi", + "/assets/d99676b868254d43500aaa3ca2ec9eb7.gi", + "/assets/4d5d22426942453139f476e8c3e6425d.gi", + "/assets/84363d080a1056a22424bf96af3ea3d6.gi", + "/assets/a8b920e1b8d3a98054a3bd522dd19ab2.gi", + "/assets/d428a6a26849a5be131b5fa6ed7e3a73.gi", + "/assets/265c849d483aef14de2aa2410ffb4024.gi", + "/assets/c710c5d4f905ec76178a0a47432a89d3.gi", + "/assets/d83c6c15f82830e2dd7e267ddfbd7bda.gi", + "/assets/7f4666a08c4276580e6c68ccc7582a7d.gi", + "/assets/5f142c2c9537cb9ab099ab909df2cfaf.gi", + "/assets/12ee64b5e0fa74257688057767125999.gi", + "/assets/4d5e2b98c4422daec63c101d90aa1f4b.gi", + "/assets/92bbe68249dcd2efb4cd9033783eeaed.g", + "/assets/1273b4a0a97b802290e28eca1f684a1d.gd", + "/assets/67ad872a3dbf51e82c9b0d635d9c198b.g", + "/assets/ae6689cd4ada1df95f6380dfb1b36bd8.g", + "/assets/cc945a9cb3f1ee8a490ed6be9c148120.g", + "/assets/a121bc1374f0faac081e3a2f73820b95.g", + "/assets/ee6165a192d707825361568736f330a5.g", + "/assets/73f2c621d90e1064798ffc092b2b47fb.g", + "/assets/9187f373d79049bca5777bb341f4ecb4.gi", + "/assets/626137ff92162ca12732fb9b3906eaac.gi", + "/assets/e7240f2d1fab6e628eb938018e757ea0.gi", + "/assets/b65d722385b4398114159192b9d73e41.gi", + "/assets/fc64f5858042aa6754fc9e613573a361.gi", + "/assets/0cbf71336e2f4ade43bc90e7dfae3697.gi", + "/assets/b11f3ead0b8721df42c643b3d29a5eee.g", + "/assets/e5bff3002acddc91b5eed3253ccff9b3.gd", + "/assets/c45b6bdc66907dab7e13f5e617ed0e44.gd", + "/assets/a594ce4c424d07a4d87e26c46f728ee6.gd", + "/assets/c768526af2cf4ff0a931a68347406f24.gd", + "/assets/17e7cbd1538c4ef3e748b63a8968133e.gd", + "/assets/4442d8bd860c963b29b85e48a76fa517.gd", + "/assets/7919cfe0ea96f57671705692d613330a.gd", + "/assets/e85a92bec8e2b4aceb3938c155392076.gd", + "/assets/1947e9ed0f555dad81bce1278a94b35c.gd", + "/assets/8c340cecc8ca210a1a133a9146e02fa9.gd", + "/assets/569ce2768b8fb8a45af3a700a297d411.gd", + "/assets/134ce59ad2d2762da7065491dfdedc57.gd", + "/assets/fe05cd0d2f71bcc0c190f877eb3ff057.gd", + "/assets/e1f9e41e672a2bfc768d48430f9d9ea1.gd", + "/assets/20fbd66923db1eee6b7faaf12cf0b6a6.gd", + "/assets/de2f56ecae757d7ce3faa2a28d5844d1.g", + "/assets/2da0ea8f09e94bc3a61558c649236540.gi", + "/assets/4b5ddfc9bba2f41ca03b30c687593b52.gi", + "/assets/9affcac323778f0dbb93190b8bd9446b.gi", + "/assets/e4a66b1e4f13d5d7dbc2a7edc27e73ff.gi", + "/assets/d922c02a362e33435a3450a7cf24f0ab.gi", + "/assets/a892c58b06f66670e48713a897c0742c.gi", + "/assets/ebf07a422bcd0466b31545e6edfd69f5.gi", + "/assets/3c5321614e403496eabb7609d8cf73ec.gi", + "/assets/8140709fe3beef3b06e2206ad1b56a88.gi", + "/assets/c8cfaa2ee97e904ac684fc8980416c8e.gi", + "/assets/efee40843972893a46c912b06adcb533.gi", + "/assets/67dce2a464ea4c1069763db4296e4f78.gi", + "/assets/c74cdf823997ae29095e76d7cc032500.gi", + "/assets/f42f2d8ac70b32babfb2fbd168bbcb06.gi", + "/assets/a67c527296266417931c1a0302b0e0e0.g", + "/assets/51ce8e2a395d3b5534f946bdcd43e9ab.g", + "/assets/70f69e92cd490cf2a85711ebb6b02b09.gd", + "/assets/935664723eadf6a13220bc9c60044411.gd", + "/assets/47fae2a876809fb26ac82d5d9b9df4cd.gd", + "/assets/4af953ac0d535503944c7a690a750386.gi", + "/assets/6adcd3d90f41d3c2634e5040749177a1.gd", + "/assets/f1ca84d44af73d89650e745e13f5f994.gd", + "/assets/2d60fc127859a1e3561b8e035736e4af.gd", + "/assets/33c00bfa492c699ef05681ce80a74b85.gd", + "/assets/7d229e21721ca089e6686bf59b824d02.gd", + "/assets/0e5611b198ce092dd9ed8480e6a1345f.g", + "/assets/18f87791c58249717accf6027ea7bcc0.gd", + "/assets/0f4db7ed620516e7f8a374fcd05047c3.gd", + "/assets/ddfc0934e916557b7a1e55b0dadcf029.gd", + "/assets/2a749dbd2f05a6d1601a71eee436bf93.gd", + "/assets/232f35f222c7b685e5dab7a6cfd1698e.gd", + "/assets/b93e5f984386e7840bbe8d4e5568167e.gd", + "/assets/793fd0dbe07ccc4328818fd51f90f130.gi", + "/assets/ffa9ff58e1d8224a91f4830c3551c25a.g", + "/assets/abda95fd271b65d9d7ff5bdbec65881a.gd", + "/assets/6389ee14fbf1a98e7719813a1356d462.gd", + "/assets/91a959b72d3c14c7c078a71ebdcbbad6.gd", + "/assets/7d8c78aa4a7187372296ea036fb8dc42.g", + "/assets/1e1b767b5ef26a8b6e59cf4a431f395d.gd", + "/assets/a56c1d40fac52ae3354d65dcb57cc08c.gd", + "/assets/f42dc25d2ec5d243fcbf830f42cab828.gd", + "/assets/0278cf03481cba25240fe7d12e86fcca.gd", + "/assets/4e7e6576039101dbaa1fa191b92f9d56.g", + "/assets/a493f26728993c3179a1fd08748b5b88.tmd", + "/assets/19061dd01d0abb32a911723fac34d55e.gd", + "/assets/49f98d12e25dd1a7dc89f19f4ee9e3dd.g", + "/assets/3b8cce2672f0787a52a51f2e16d207b6.gi", + "/assets/184eec868533ecc456b07a074d7e4a69.gi", + "/assets/383f5cdb97f4fc28f31116746f2263e3.gi", + "/assets/3367968b59948b810aa1691591c3ad90.gi", + "/assets/3620a0e3f9b010a67e2211fb57be9795.gi", + "/assets/9afbbc19e27ba0fd7a1b8fee252500a1.g", + "/assets/89fee919a7f5e23a9a82fc21db21ba62.gi", + "/assets/660ae80b3383cc2d962d13a8aed43693.g", + "/assets/b82ec220b60e071be3bf95c9ed4c22af.g", + "/assets/9e54ee21d9ab4f37d2f7879c6b4ac716.gi", + "/assets/4e5b7fc1bb21bbb03c97658f701d2daa.g", + "/assets/ac4afd291bb14c730918af126ba3521c.gi", + "/assets/ce4082d6894341edb3c8cf74597bfc18.g", + "/assets/faea30b87e190175fa708c10fd7100a3.json", + "/assets/af020210038acf60ee174488155ba357.json", + "/assets/4e3f7c04f288d20b3ddad6d53f24901f.json", + "/assets/d9f0b4450767624fa50e3a12699392c6.json", + "/assets/f2637f33470266c1ac1a8024968038a8.tbl", + "/assets/82ba1d81b04e2f136da596bf045ebd47", + "/assets/400dc1410ebbe39bca248fa325768144.json", + "/assets/7228f62fe4348990a632e32ea78fb287.gi", + "/assets/f175381bbfaa6bc9a084bfed735fefa1.gi", + "/assets/c650baff09d4066f58fdc00833b69a72.g", + "/assets/c519ae1edd9b21c1c9dd2823286b8db9.gi", + "/assets/eaba229acd46a8cb5bf564665580f28e.g", + "/assets/1222355135cbaef14af2bd98eca9349f.g", + "/assets/c280c6e64e6f64c2070356eec63568c3.g", + "/assets/433e81b987007d9dad468b3992092c72.json", + "/assets/f4e4fb94afd70a00c165508d8b08bc4f.g", + "/assets/a037e7d94318098cc9338bf161f3b0f7.g", + "/assets/55b1e71dffd19ed10c7d7c4d69056663.g", + "/assets/e4c90f59faf28ba123f022ffe98eb0ce.gi", + "/assets/3feece30ddda8ab8efc5389042082508.gi", + "/assets/291ea97af7079038612acada9cab1584.gi", + "/assets/326ffd641fb5c8ee0f7c2fe2dc2fd07f.g", + "/assets/deb83f35a40f46e65fa692a4d275fdf4.gi", + "/assets/a6f7c2db3faee37937eedac208c2bd3c.gi", + "/assets/7ce2f4d86474cb5de0bc14d8b94b0aad.gi", + "/assets/84fa4e56e027cbceefe0c7a020c90f45.gi", + "/assets/6c040b7bccd75863ed85c8651f446936.g", + "/assets/59d380dc0768aa758201859b7e66e394.g", + "/assets/391fe85e4fee7ca4bb4923c0d625267b.g", + "/assets/947fa7e4f3af1b9a769d285dd4c598b6.tom", + "/assets/6d670dd78f1a6d1ea086b73647a9cdcf.tmi", + "/assets/98a921705a9e83a0ffa1402fcaf3e35c.gi", + "/assets/0e84d7ae8f2c75ad33a65c41f163b4f3.g", + "/assets/2e55a7cde01a792d2dc3c51cb17c0786.g", + "/assets/707626caac65bf363337f2c043eb8f85.g", + "/assets/bc7a2185edf1306d8e555cc20af2a17d.json", + "/assets/a920acd098318c94b9e1844486b79e0f.g", + "/assets/5bb5441ad244bebdac48829687f9e36f.json", + "/assets/af7de883368020b84608737364e8b994.json", + "/assets/558320af72a58ef2c97aee5b8dfec5b4.json", + "/assets/7b8a94aed13c6b127902f3c796732e27.json", + "/assets/17154fc6b7170fb0f98d0768341b7e22.json", + "/assets/26ae25e2ccea23fbe7f220b3859842bf.json", + "/assets/4814ca2498173004ad8447d298778405.json", + "/assets/f31e9513fc8cdcbe1cf7376fc8ef15da.g", + "/assets/1515b67b699b2fd7b3d24469102b96e7.gd", + "/assets/fbeef1780f68513e3fd99c99cfb19024.gd", + "/assets/ae97ee3c295248a712c6d7e47d695217.gd", + "/assets/ad83821325b57f591aad22bb0c4519b0.gd", + "/assets/a80e00dd069485b14cf75f8261961c10.gd", + "/assets/50222dd8947ae3fd28e00e8d81134dea.gd", + "/assets/d58cbf76513d802ef1eeb432a7f36a07.gd", + "/assets/e0f22469a67bbc6d51ca39f312cdab63.gd", + "/assets/289c9e96f4add12f8545b5e0f50e9116.gd", + "/assets/c08b358cd4464840985d225680d85b07.gd", + "/assets/d4f1f86361cf23ca185cda37a9ccbd0b.gd", + "/assets/155d542297c9ce1324cb7f2ed7889353.g", + "/assets/0799295fd44fec73f16882b85f7bb292.gi", + "/assets/17533448c039c794c7c3641ea4e65e55.gi", + "/assets/599b96ed7f9b41b8ec0e6f3acdcf3a91.gi", + "/assets/e78ccf52e76007cb78aff23792b899fd.gi", + "/assets/411e82d574e294d7c694710666993280.gi", + "/assets/5b3e83547272592a50f3bbcfd334d048.gi", + "/assets/5be161b34f65c5132b7b42cc309871eb.gi", + "/assets/37321b0e73e8312a6342adda9f9ee17f.gi", + "/assets/95748f10bd06b092ece44c9e3f051289.gi", + "/assets/694870ff745fed678e1faacf31ef8b38.gi", + "/assets/ca2e6b983706a9f9f804b11ad8c6564b.gi", + "/assets/c162c9c939b371e2a9825258267bb369.gi", + "/assets/ac09401274ad98fb18be3e1d7105c53d.gi", + "/assets/70dbdee759e9ae81b54355c44fa74636.gi", + "/assets/ec7d15db0d4f50aa56f7596a72d8a791.g", + "/assets/17e9bea6202b7c224ec20602df6a5ad3.g", + "/assets/e5d6f0363d4361f66e9779390bde004f.gd", + "/assets/a1e5ef0d758bd15a0e7f38e66a1da0f7.gd", + "/assets/6e268d8c6d3b478cc296ba6a62cd078c.gd", + "/assets/22c317d92e6c603cf87e144748cce337.gd", + "/assets/cdfed668cdc45785ac5b7eca2c854c69.gd", + "/assets/b82ccb7d8579707acd7a5597836dcc15.gd", + "/assets/c192f8b9e645f664a9d4fc8003caaf87.gd", + "/assets/64be778cbfbaa7e1b30e931e65f5bd90.gd", + "/assets/eb57a856c14d52aae743f3a47d7caaaa.gd", + "/assets/a5e9c14d38b6a4a2d5ba2043ae17abf9.gd", + "/assets/95fbb4cc56b21466da74cbc18e4cb926.g", + "/assets/2891433b1988e2acb1932c3bb0011163.gi", + "/assets/4819f45fb545ce929fb251ae7b4688fd.gi", + "/assets/055680c38c42acbc3e03aa68d10fbcaf.gi", + "/assets/4c67bded037d685cc618a3ced1afcdf4.gi", + "/assets/0a68fbcd4e859b2df24f3c5562401a60.gi", + "/assets/d795671677e9906c0dd6aa77994d157c.gi", + "/assets/eac903fa0c43d686c204e6db0dc4597e.gi", + "/assets/b9749b805ea0f6ef89f27873aa4cb93b.gi", + "/assets/36e8667fcf71748e0fb497a9dfa87b40.gi", + "/assets/043eacb7f0b7c2a8da168233548198d0.gi", + "/assets/79691386cc4052c36c6409ab97638d71.g", + "/assets/25e718c5c25e7dfcd827a5b30e0835b7.gd", + "/assets/7d4b95c69e31903045c43cba756bfc86.g", + "/assets/33c2902725baa53d1c96ddfee4a7e064.gi", + "/assets/e6faf3281f6fb49242a7ff039f546aaa.gi", + "/assets/6a71ebb6f70ff95ee63df42230010974.gi", + "/assets/c06d635e7830e411333ebbbf08dd7973.gi", + "/assets/774c151333a9c2e672da7e5cd59cf5d0.gi", + "/assets/9f20993cb62cd5977ab9df29a57321ba.gi", + "/assets/0068fd0e049ae55c2e2bcbd416cfb621.gi", + "/assets/e56f45678ae9d5c70670b5098563d392.gi", + "/assets/ff7446fce1b1b04a9198282b71fad186.gi", + "/assets/5b18ec7ca7a244d3e60705ed53de9fb6.gi", + "/assets/82f0d5321c2bd354561e19dcb8397417.gi", + "/assets/763d0fd9631960700a7ac792512246c8.gi", + "/assets/9eaced858f490fe054106b898fe85485.g", + "/assets/4c99677ad2847db34068998133081f1e.gd", + "/assets/95f2e9f112b640901773744c38307483.g", + "/assets/164be464e4d4c4794b7d471a14dafecc.g", + "/assets/1876c0ad692ca4d49b18d22bfaa0e65f.gi", + "/assets/baf7e5756d7fe7a193f2b4a76a80ca1a.g", + "/assets/50caba7f0821667dd7aefd309d5cbc17.gd", + "/assets/116151e262eb918559febd550d647213.gd", + "/assets/513193ca0ef822c9d2ccccedf77ddefd.gd", + "/assets/c88fd6df04fc82f174521227f84a1b95.gd", + "/assets/23e17b0911ed57fe9813b6c57f4c9fd5.gd", + "/assets/c11126ef8f4f0316a9fa0294cd22bfef.gd", + "/assets/0e0634bfe3ad307ce34a8ced28ce436c.g", + "/assets/74962c3c997fa04ff8c78889a62ff9ae.gi", + "/assets/925e738c5f2b81e48b284fec6b3b008a.gi", + "/assets/ff4f1217cb5dc41dbec4c7101ae5e01a.gi", + "/assets/29033e7b5e35003fdaae65927a69c758.gi", + "/assets/e02a7b9c5eb647b6ec9e080fb88bc7fc.gi", + "/assets/9ba4112d1447cf2da0192d4e5cc6896b.gi", + "/assets/5e8d4cc212cc844f762489fb0d9ee615.g", + "/assets/c6314fc3087fdee9cc2c526e2660b95c.gd", + "/assets/4aa4d263cc3fe9d8739e798113acabaa.gd", + "/assets/b81f106aa8254d5a9049f72f4f10dd70.gd", + "/assets/f052bb025466b450b8a144a1eec23ced.gd", + "/assets/14b8c394951e4b7a25ea5fa135e64d82.gd", + "/assets/4169e6042c3e0385246a720d9310af61.gd", + "/assets/9996adf4761091bbf0f5818d80a81c20.gd", + "/assets/634af410b2c546fb8ca8cddef8968518.gd", + "/assets/93429985d80fd1d64dca619cbe6522c0.gd", + "/assets/2271c54b41b96fa4a531a8d99a142078.gd", + "/assets/ba128b92da9935b52a847f41f05c4e56.gd", + "/assets/7c18f2dba868ae3d4dff8d41275377f6.g", + "/assets/ac6c6f98e981bea62977b7acf47e2d5d.gi", + "/assets/94380176d29fc200732ae427900d2faf.gi", + "/assets/f9eb3cbb09c66bdb03a9c57b20d7face.gi", + "/assets/a28f540b55c3ff50bfa71bc4ad565803.gi", + "/assets/09a85f8086a2139dbb17a8d6e3d4c2c5.gi", + "/assets/7ccd85ce8272b839505faa8db262ed2e.gi", + "/assets/88f300bf3bfecdbdee544607c62c0a02.gi", + "/assets/9fb150f0a8765f270680cb784a0e83ae.gi", + "/assets/f28f080047df6ee328e91026771d37ac.gi", + "/assets/267aea4cccc8818fce5ae67da988b2d7.gi", + "/assets/eba5bb5650b1537b15f7c2a5dea12134.gi", + "/assets/e583fc75e65cf543ea5e40148185d0a9.g", + "/assets/f182f51dabdd077f32b061d9ba849562.gd", + "/assets/9440b1c0d77bcdb19adba99058f28073.gd", + "/assets/c51d13ab25130169749ac9a45eded442.gd", + "/assets/d54913efb2bbbf1b6efc25eac399bdf4.gd", + "/assets/cc1fe55c00b572323afd0207d8028a86.gd", + "/assets/74ac030fb3a0d214a7b70f94708228c1.g", + "/assets/0ea18dd9b7d89a5e2679e1eb508be27f.gi", + "/assets/c52d3b20198d1160a738431faa302121.gi", + "/assets/d094082a0ebbd33c1dd657994d4af559.gi", + "/assets/a02d49075a33cd8b1faaea3cc6f2237d.gi", + "/assets/249cb16552b3a2f54e6d15e408961410.gi", + "/assets/a131b80d0875ea6bb89c529d95a3b8a4.g", + "/assets/a0aeee8824449e241c45ba8859a0dfa7.gd", + "/assets/1dfb717bdc77664f60c98518f959f06c.g", + "/assets/68fbfacc994bbdc80d60d36e2453e4db.gd", + "/assets/fe93ee5c725fb619a0f4f1aa53055211.gd", + "/assets/06e96626ad11e7eb2a532d13f679efc1.gd", + "/assets/54108d6f302f4f2b9c8eab15429ec999.gd", + "/assets/bb2aaec69e355aa7a9d31e7a036c5347.gd", + "/assets/4a0cdc3f23eaea9c1e86558e4fed6f90.gd", + "/assets/485eb74c0088add242830be5aeefee76.gd", + "/assets/9b169ea4392d756a72187f8519caae31.gd", + "/assets/96b1bf0ccf0980c6089d777e318c3773.gd", + "/assets/386188e20b5633785fa030f5124c424b.g", + "/assets/c0898a55547d8784c001adc00b47caf8.gd", + "/assets/0c8d9995d8e8b2141ee3276dfd6c0fcb.g", + "/assets/894ff9d9ec23b07f0f25581d983aa85a.gd", + "/assets/d73a591a7812d1535a85fc0203e0f08e.gd", + "/assets/e2bfe52e8cb3d6589be3d481310233d5.gd", + "/assets/9c75455d8ef563b864c40d55d3354bd2.gd", + "/assets/e7be48dff23b93193fa7738f431a775e.gd", + "/assets/fef96883dab9f8e62c29e738e9f6b7df.gd", + "/assets/b90ce0b1309e00d2ead3837ac6946422.gd", + "/assets/ad0ad302161a8f6b52c8296e350862f1.gd", + "/assets/9eeb43f7d10746604cb6e3c1508db275.gd", + "/assets/d58cfe82ef94b3caa82948e5c5fe903c.gd", + "/assets/27b2bc0721267cce5c968917082d6b34.g", + "/assets/ba4660ca54f16cf617c96210c1bcd9fc.gi", + "/assets/08985e665ce12b993e0fedacac43148c.gi", + "/assets/b5f4e9454b159efc31657effae2989b1.gi", + "/assets/1b541c62f52c6bfbbab40cd9a5b44207.gi", + "/assets/7fc2ac29dac4e4b32f80fad65d74a130.gi", + "/assets/3bbfc3a3968dbe742a6c8037746310fc.gi", + "/assets/83a999881b18bc388f705780465d4612.gi", + "/assets/5e23c0417c7c381603ccca971a65ee55.gi", + "/assets/1f7aa2f9bf07342a712a987475d14e02.gi", + "/assets/0d5138dd8b20cf9ff0f5bbce91288b08.gi", + "/assets/603053187d70930d2f4264a7fe0954d0.g", + "/assets/64942d3a27248c64c1a2b1fb047139bc.gi", + "/assets/10f0e4489064891dd7fbaed4a447611b.gi", + "/assets/874e79cd0ca5b6e2639f20612ddfb177.gi", + "/assets/aea2ca2eabf7447c5a6b04e20be1152b.gi", + "/assets/8023e073b5b112c6c3d8a31925968c75.gi", + "/assets/74c30abb42db36e60e8fb1971dd9b634.gi", + "/assets/412fd9dd648a8c2d9d73ebd8416d5546.gi", + "/assets/5f8e0933c4463712bd7cd8fe6229d7ba.gi", + "/assets/0f6aa1b97006d00f1ffd93d435787a7b.gi", + "/assets/bd5ce9d344017c4584b64fd73f9d9e59.gi", + "/assets/9b6f4615c6f5e7fc3d3b931b5ea6d161.gi", + "/assets/f81e2682f0d32dc84c47b55e048b5ec4.gi", + "/assets/3b032f024ccfb74d72f85e4872272b8d.gi", + "/assets/7bd5e8b383e7c21c273d3d5a0e3798ff.grp", + "/assets/573fa2e13db50f4ebcc31d8470bb060c.gi", + "/assets/a5691f7ac2a03c1f6d88f73721067425.g", + "/assets/81eed32f730faf16efe047eaf1832b56.grp", + "/assets/63780260ffca2e8f2d49fa23770aa47b.gi", + "/assets/76911cda94b64bd9624e7e36ecdfdfbb.gi", + "/assets/b3cb4ffc7ea75a7062083a7ec9a79f94.g", + "/assets/1c304acde8daf77202f7e9430d4722a1.gi", + "/assets/6b8005844b48026fd60263e0e67331b7.gi", + "/assets/3333e75f754a91c6d4df3f2b587e4321.gi", + "/assets/5020b43bb7396613f01bfdc5f1a121eb.gi", + "/assets/66598d78b7e0fff9d024f6059e032fc8.gi", + "/assets/7093cd2a4f40d87be5cab5d41d3c72e1.gi", + "/assets/fcc715bfd6e05aab58467af131fd58b3.gi", + "/assets/09893a06b2e11a35fda0383f78842802.gi", + "/assets/9ce8fd3103d326c010c9688fe64c9c95.gi", + "/assets/5c0647eca873d986e3a1209d97326f81.gi", + "/assets/ae0caccd85d65cc88b547ef4dcb213f8.gi", + "/assets/f5fb67f6572cacfb50adb898e2844a8c.gi", + "/assets/e14162c30eec5547280e76634270c8e9.gi", + "/assets/89091ed7ebe38612781f817a6f188ab9.gi", + "/assets/5a0f34c5fcc9a8d468ff03798dcf7cb6.g", + "/assets/da2c4dccf561bbb319fd964ba11cc9cb.gd", + "/assets/16abbecd77cf3878e46aed940cc15189.gd", + "/assets/eac4ecd2ed96fa097a6e2d9400336ea1.gd", + "/assets/3816965c559e78bbbeecf68e8d6bb139.gd", + "/assets/e42f816f67bad57597999a9c790c2198.g", + "/assets/a75ad79fd5df0c7af2e557e5107cedfa.gi", + "/assets/ecfcb558ccf63586b5dbaa6078879aca.g", + "/assets/6c315cca1d428341fc898c7267e5e528.gi", + "/assets/df717ea416addb3c99ec379fbb6c651d.gi", + "/assets/c7f884e90cddbd44daafc747514212a1.gi", + "/assets/738c6b0c3d39a610cb58e30b5e9485f8.gi" ] \ No newline at end of file From aaa5f3e0b7bbf0ea9fbe12ba9e460b128df17d87 Mon Sep 17 00:00:00 2001 From: Yanshu Wang Date: Thu, 19 Mar 2026 15:06:25 +0800 Subject: [PATCH 172/234] use percentage encoding for special files --- etc/emscripten/README.md | 8 + etc/emscripten/build.sh | 2 +- etc/emscripten/build_manual_manifest.js | 52 + ...ashed_assets.py => copy_encoded_assets.py} | 13 +- ...rate_mapping.py => percentage_encoding.py} | 35 +- etc/emscripten/run-web-demo.sh | 2 +- .../web-template/startup_manifest.json | 1260 ----------------- 7 files changed, 85 insertions(+), 1287 deletions(-) create mode 100644 etc/emscripten/build_manual_manifest.js rename etc/emscripten/{copy_hashed_assets.py => copy_encoded_assets.py} (57%) rename etc/emscripten/{generate_mapping.py => percentage_encoding.py} (84%) delete mode 100644 etc/emscripten/web-template/startup_manifest.json diff --git a/etc/emscripten/README.md b/etc/emscripten/README.md index cf5d35ad04..f828866a80 100644 --- a/etc/emscripten/README.md +++ b/etc/emscripten/README.md @@ -8,6 +8,8 @@ Files: - `build_startup_manifest.js`: Run it in the web root directory to build `startup_manifest.json` that contains resources to preload. +- `build_manual_manifest.js`: Run it in the web root directory to build `manual_manifest.json` that contains all `.six` files to preload. + See 'run-web-demo.sh' as an example on how to set up a working website. Note that this demo uses xterm-pty, a library which provides a terminal interface @@ -24,3 +26,9 @@ For more details, see for [this article](https://developer.mozilla.org/en-US/doc The file "coi-serviceworker.js" works around this problem on Github pages. This won't work locally, so "server.rb" is a simple ruby script, which just starts a web-server which returns the required headers. + +You can combine `startup_manifest.json` and `manual_manifest.json` using the command: +``` +jq -s 'add | unique' startup_manifest.json manual_manifest.json > temp_manifest.json +mv temp_manifest.json startup_manifest.json +``` \ No newline at end of file diff --git a/etc/emscripten/build.sh b/etc/emscripten/build.sh index 0dd807bd95..ded1cfffdf 100755 --- a/etc/emscripten/build.sh +++ b/etc/emscripten/build.sh @@ -91,7 +91,7 @@ cp native-build/build/c_*.c native-build/build/ffdata.* src/ # Dynamically find and append ALL required files to the JS array # The flag -type f is safe because the only symbolic link is 'tst/mockpkg/Makefile.gappkg', # which is safe to ignore -find pkg lib grp tst doc hpcgap dev benchmark -type f | python3 etc/emscripten/generate_mapping.py +find pkg lib grp tst doc hpcgap dev benchmark -type f | python3 etc/emscripten/percentage_encoding.py if [ $? -ne 0 ]; then echo "Build aborted: generate_mapping.py failed." diff --git a/etc/emscripten/build_manual_manifest.js b/etc/emscripten/build_manual_manifest.js new file mode 100644 index 0000000000..b4a951dbd4 --- /dev/null +++ b/etc/emscripten/build_manual_manifest.js @@ -0,0 +1,52 @@ +#!/usr/bin/env node +"use strict"; + +const fs = require('fs'); +const path = require('path'); + +const BASE_DIR = process.cwd(); +const ASSETS_DIR = path.join(BASE_DIR, 'assets'); +const OUTPUT_FILE = path.join(BASE_DIR, 'manual_manifest.json'); + +function findSixFiles(dir, fileList = []) { + const items = fs.readdirSync(dir); + + for (const item of items) { + const itemPath = path.join(dir, item); + const stat = fs.statSync(itemPath); + + if (stat.isDirectory()) { + findSixFiles(itemPath, fileList); + } else if (stat.isFile() && item.endsWith('.six')) { + const relativePath = path.relative(BASE_DIR, itemPath); + + fileList.push(`/${relativePath}`); + } + } + + return fileList; +} + +function main() { + if (!fs.existsSync(ASSETS_DIR)) { + console.error(`Error: Could not find 'assets' directory at ${ASSETS_DIR}`); + process.exit(1); + } + + try { + console.log(`Scanning for .six files in: ${ASSETS_DIR}...`); + + const sixFiles = findSixFiles(ASSETS_DIR); + + fs.writeFileSync(OUTPUT_FILE, JSON.stringify(sixFiles, null, 4)); + + console.log(`\nSuccess! Found ${sixFiles.length} files.`); + console.log(`Wrote manifest to: ${OUTPUT_FILE}`); + + } catch (err) { + console.error("Failed to generate manifest:", err); + process.exit(1); + } +} + +main(); \ No newline at end of file diff --git a/etc/emscripten/copy_hashed_assets.py b/etc/emscripten/copy_encoded_assets.py similarity index 57% rename from etc/emscripten/copy_hashed_assets.py rename to etc/emscripten/copy_encoded_assets.py index fe8bf9db69..be29f39f13 100644 --- a/etc/emscripten/copy_hashed_assets.py +++ b/etc/emscripten/copy_encoded_assets.py @@ -1,12 +1,9 @@ import sys -import hashlib +import urllib.parse import os import shutil def main(): - if len(sys.argv) < 2: - print("Error: Must provide destination directory.", file=sys.stderr) - sys.exit(1) dest_dir = sys.argv[1] os.makedirs(dest_dir, exist_ok=True) @@ -18,11 +15,11 @@ def main(): if not path: continue - h = hashlib.md5(path.encode('utf-8')).hexdigest() - _, ext = os.path.splitext(path) - hashed_name = f"{h}{ext}" + encoded_name = urllib.parse.quote(path, safe='/') - dest_path = os.path.join(dest_dir, hashed_name) + dest_path = os.path.join(dest_dir, encoded_name) + + os.makedirs(os.path.dirname(dest_path), exist_ok=True) shutil.copy2(path, dest_path) copied_count += 1 diff --git a/etc/emscripten/generate_mapping.py b/etc/emscripten/percentage_encoding.py similarity index 84% rename from etc/emscripten/generate_mapping.py rename to etc/emscripten/percentage_encoding.py index c5aacec4cc..9a252c911a 100644 --- a/etc/emscripten/generate_mapping.py +++ b/etc/emscripten/percentage_encoding.py @@ -1,9 +1,8 @@ import sys -import hashlib +import urllib.parse import os def main(): - seen_hashes = {} mappings = [] for line in sys.stdin: @@ -11,18 +10,11 @@ def main(): if not path: continue - h = hashlib.md5(path.encode('utf-8')).hexdigest() - _, ext = os.path.splitext(path) - hashed_name = f"{h}{ext}" + encoded_name = urllib.parse.quote(path, safe='/') + + fetch_name = encoded_name.replace('%', '%25') - if hashed_name in seen_hashes: - print("\nError: Hash collision detected!", file=sys.stderr) - print(f"File 1: {seen_hashes[hashed_name]}", file=sys.stderr) - print(f"File 2: {path}", file=sys.stderr) - sys.exit(1) - - seen_hashes[hashed_name] = path - mappings.append((path, hashed_name)) + mappings.append((path, fetch_name)) try: with open('lazy_fs.js', 'w', encoding='utf-8') as f: @@ -30,9 +22,9 @@ def main(): f.write("Module.preRun.push(function() {\n") f.write(" var fileMap = {\n") - for path, hashed_name in mappings: + for path, fetch_name in mappings: safe_path = path.replace('"', '\\"') - f.write(f' "{safe_path}": "{hashed_name}",\n') + f.write(f' "{safe_path}": "{fetch_name}",\n') f.write(" };\n\n") f.write(' var physicalDir = "assets/";\n') @@ -53,6 +45,14 @@ def main(): f.write(" addRunDependency('idbfs_sync');\n\n") f.write(" FS.syncfs(true, async function(err) {\n") + + f.write(" Object.keys(fileMap).forEach(function(virtualPath) {\n") + f.write(" var parts = virtualPath.split('/');\n") + f.write(" parts.pop();\n") + f.write(" var parentDir = '/' + parts.join('/');\n") + f.write(" try { FS.mkdirTree('/gap_idb_cache' + parentDir); } catch(e) {}\n") + f.write(" });\n\n") + f.write(" var needsSave = false;\n") f.write(" var startupSet = new Set();\n") @@ -69,11 +69,12 @@ def main(): f.write(" var fetchPromises = Object.keys(fileMap).map(async function(virtualPath) {\n") f.write(" var physicalName = fileMap[virtualPath];\n") + f.write(" var physicalPath = physicalDir + physicalName;\n") f.write(" var cachePath = '/gap_idb_cache/' + physicalName;\n") f.write(" var finalPath = '/' + virtualPath;\n\n") - f.write(" if (startupSet.has(physicalPath)) {\n") + f.write(" if (startupSet.has(physicalDir + virtualPath)) {\n") f.write(" try {\n") f.write(" FS.stat(cachePath);\n") f.write(" FS.writeFile(finalPath, FS.readFile(cachePath));\n") @@ -108,7 +109,7 @@ def main(): f.write(" });\n") f.write("});\n") - print(f"Successfully mapped {len(mappings)} files into lazy_fs.js", file=sys.stderr) + print(f"Successfully encoded {len(mappings)} files into lazy_fs.js", file=sys.stderr) except Exception as e: print(f"Failed to write lazy_fs.js: {e}", file=sys.stderr) diff --git a/etc/emscripten/run-web-demo.sh b/etc/emscripten/run-web-demo.sh index dd5e13d104..607b4adc22 100755 --- a/etc/emscripten/run-web-demo.sh +++ b/etc/emscripten/run-web-demo.sh @@ -8,7 +8,7 @@ mkdir -p web-example/assets cp etc/emscripten/web-template/* web-example/ cp gap.js gap.wasm gap.worker.js web-example/ -find pkg lib grp tst doc hpcgap dev benchmark -type f | python3 etc/emscripten/copy_hashed_assets.py web-example/assets +find pkg lib grp tst doc hpcgap dev benchmark -type f | python3 etc/emscripten/copy_encoded_assets.py web-example/assets if [ $? -ne 0 ]; then echo "Copying failed." diff --git a/etc/emscripten/web-template/startup_manifest.json b/etc/emscripten/web-template/startup_manifest.json deleted file mode 100644 index b63d64e8e8..0000000000 --- a/etc/emscripten/web-template/startup_manifest.json +++ /dev/null @@ -1,1260 +0,0 @@ -[ - "/assets/7b59a49b04346656bd2e8136cb3edbc1.g", - "/assets/4aa642c41d006ba397543ceded3ffbc5.g", - "/assets/b7a794624978346fc60b233e3a36b4c1.g", - "/assets/27006107d901783a4990c551ae988a1f.g", - "/assets/35784f49ea293970e881d8989895de75.g", - "/assets/6703788ec913221e9de60fee486afa0b.g", - "/assets/3ad2c0c2e16ab6570a90f4f7c4486001.g", - "/assets/5f8707e876ee1b5323c75e6b2c16fd77.g", - "/assets/9e1f49d5f90713e878925519afd52c26.g", - "/assets/9c33d1d5c954303561f75cc303575d2e.g", - "/assets/2d54c52d27de02da865197eaa49d73f0.g", - "/assets/7b9bbb6e4d0c426097e93729a6f0bb4d.g", - "/assets/a12a8a2f0cb7710a574a3e49eeb95888.g", - "/assets/0d324ca3c9be8391c9af1c60e3f91ed5.g", - "/assets/f42f83966d0de21c2655bbc8a84417d5.gd", - "/assets/4bfd4177bca1762e652aa47bbe00e16c.gd", - "/assets/ddfc8ce554873ddbdb26c784132f01fa.g", - "/assets/69bae3daffdb69ddbbb6218232bee32c.gd", - "/assets/cffd2a8bd255e90685651a0c1f828d56.gd", - "/assets/dfd45db083eac2ab29b4650435951919.gd", - "/assets/56b18609e58fde04850cfc56ed3f7794.gd", - "/assets/e51d6e046f7691d8d72c15af0b47ab12.gd", - "/assets/d98054f175c3792f389e12d84bbbe928.gd", - "/assets/a5c02b844755760a44b0af942116c81f.gd", - "/assets/d20097ccbe896f32359c8e9c72f92251.g", - "/assets/8d57117f27fad258c4a416ba15331733.g", - "/assets/118e0cc315408c330639ea336e16ccc7.gd", - "/assets/7eaaeef09150cf5f3a46eaa96c70412e.gd", - "/assets/fa798d8ec092fef7f73a8bb0d86d0654.gd", - "/assets/4b02c3fa0b74a5d5d2ebbba96f8e96d2.gi", - "/assets/b3a9c3d1464418773696e375a15966ee.gi", - "/assets/7beaa7d398502184a218ca76b7c489b7.g", - "/assets/f887cb60d851477ebf8341a11618556b.g", - "/assets/a04f66b01d9493fb35c0f709a5c37dab.g", - "/assets/832850f85d6be67a867c041b9f31db90.gi", - "/assets/74cc965118dc7f48ced3a20322f57ae1.g", - "/assets/4c1a780ed754ee016193168478f4f0e2.g", - "/assets/1aff67e93dc523e75f09284840bc4914.g", - "/assets/e4014060c68a7b5f084cb8fda058af36.g", - "/assets/8f2c0274fe78d4d7a815632ca9394ff6.g", - "/assets/9fe30178e167c4951a2d3e4bf3089234.gi", - "/assets/8892927df7e1d6ab0709725910e6c9ce.gi", - "/assets/5ae3485947de971f7422f7676afe279d.gd", - "/assets/9a3a26ba5ddb9e093c974945f454c7b2.gd", - "/assets/5a991f67e05e63e45481e2918d16cd38.gd", - "/assets/3670e70829ef1c430e341ba1197d8584.gd", - "/assets/44fdef3c7d553ce8840a4440db62b17c.gi", - "/assets/0f331abebd03f8b1d64ffbb6d039e9e6.gd", - "/assets/8f9e3a38e1a59fa02f6a1a441e71c1aa.gd", - "/assets/c251fa4c8b45c9ce1b406df6c7c4b105.gd", - "/assets/d97cb149758107bfd5cffc8a83eca1c0.gd", - "/assets/7853c4c27f461db05cce3d6a209cab4a.gd", - "/assets/ec77e1349659a617c444a44665693bad.gi", - "/assets/52dc535abf2095c0716c48b9c63dc00e.gi", - "/assets/7b4a736c9ebcad0b563502365e94cad7.gd", - "/assets/281385738fc27fc4d952aa2705dab8b0.gi", - "/assets/0d5db671613a5d6f3e946a2a90a2884f.gd", - "/assets/81ef838516b6c4ea24a677ffa1dbde88.gi", - "/assets/d8673da61258721d02366078d84f532d.gd", - "/assets/96194441ac26cad02549cbe5b0784fa3.g", - "/assets/6abd9b6548095a1cc08bba418d0c91fd.g", - "/assets/a6f6b3acde8847793de6fd01a9e11066.g", - "/assets/b22ed1c52df6b78fc84e21946fe94365.g", - "/assets/67bec54418dd512af64c66494101113f.gd", - "/assets/17a02323ce47d2b96894fbf4f8ed9fe2.g", - "/assets/09ae5089fce3607ce7c9758f0776431f.g", - "/assets/3e05f9c56ae50056127d2348be2f82ce.g", - "/assets/9cfe2b8b076f28ad3e7402059defbefb.g", - "/assets/f57bccdea4ab67cce4d5c0c509b8af19.g", - "/assets/4b510629f2a609ba0f6640551db5d429.gd", - "/assets/57df29c119bc8f0ed94b85bfb1772c55.gi", - "/assets/2a2f0800029b15fd39643a5d28fbe4f5.gi", - "/assets/12076fadcd03f7e118d396718603f288.gi", - "/assets/c43c04f3fe9d7d0822d426ae255bc193.g", - "/assets/eeb733b6206076f84b7b253ef723010c.gd", - "/assets/317538ee62efb54f865ab5fc7771963c.gd", - "/assets/118799c9ea19f8a1c16526ae49921c3e.gd", - "/assets/c136cdf2db9546a815fd167cbbaa0678.gd", - "/assets/f11702ff9d4d320fa91b687fcfa2e17d.gd", - "/assets/90d776ae54ff0c87100f13836457c5be.gd", - "/assets/091567bedb42a25fe7ce21b651a8fd79.gd", - "/assets/141c81636bd3eed22db8ef8c25a41887.gd", - "/assets/b9783ee351b5d827dcb4ebb95f0ec841.gd", - "/assets/3294918abad6f195447012036e25dee4.gd", - "/assets/c1409e1e84cff226c1c4a8ad316ab2b0.gd", - "/assets/ca8377f1082c122687568db22274fb14.gd", - "/assets/f7b44a218ccad14067c1c316261174d1.gd", - "/assets/e53cdd24acca561e0093369786d4497c.gd", - "/assets/faee5ec15ac0a36672dc9401c6481206.gd", - "/assets/4169c5d964a1b509907623b98d5ad7c6.gd", - "/assets/1c944008853cb29f1bda800411b85963.gd", - "/assets/c1acb27f7e0736781c7cdd6cc59358ab.gd", - "/assets/5c9477bf9a262d717a34ea1eef2cca20.gd", - "/assets/d23ccad6f389d6fd01d72042461a650f.gd", - "/assets/7a56517f7a90c71fc4e7774dc93a5fb2.gd", - "/assets/1bae26ed85f1aa760ed8e0904d9c3d89.gd", - "/assets/6f730c95eaa3df4a45eadf26fef65a41.gd", - "/assets/6f0fb842d6d2cc95adc38a48034fde22.gd", - "/assets/a475b92d539cf9bc61ad8bdbede2f6d5.gd", - "/assets/ede5e5067be030c82effa0c5a97e92b7.gd", - "/assets/800ebd9c68f28be311195c3b527edaae.gd", - "/assets/b2fea3885590181189908e63e09d61c2.gd", - "/assets/5eaac654f0ace86b672da8ca3fa31cc6.gd", - "/assets/de53b9224e948c84792e0ef870d1e318.gd", - "/assets/35462716e3efcda176c5c23b438b3835.gd", - "/assets/d2d261e0194d5bdce976195fb9b37191.gd", - "/assets/9b9ed2314688770026eab59f2b15f988.gd", - "/assets/29e8a51ed97f11bb97b8b01653af65c7.gd", - "/assets/9958ee0fa5528592c1854a8d881a9499.gd", - "/assets/638320b8683d568db2a708964be86124.gd", - "/assets/201b3fcb625063dcb5bcbd4772800f50.gd", - "/assets/c9e1be8621f8db535cb708698bf5b401.gd", - "/assets/b2066fcf3ca4c0965a0fd85e4a062b2f.gd", - "/assets/860aef14d7fd42dcca79a37f9bc11366.gd", - "/assets/98f233191a0b58a241238bb8944031f0.gd", - "/assets/a42e2a06d4ea432a3f34fe8258b0b0c1.gd", - "/assets/c599fdd884e67c83a76feec867a11a94.gd", - "/assets/da901aca8d614ffe29f9f8c260b6d83c.gd", - "/assets/1abcc2a3997e18b6d54a33cfcebc469c.gd", - "/assets/8832274f88905efdd3f67f915ec5b3b9.gd", - "/assets/abb329846d08fa8cab8be2ab49fa2265.gd", - "/assets/38e9b1d79b04808fde9f1f38f7d822bf.gd", - "/assets/54b2e0eaa8cf47fb74003c5ca58836a1.gd", - "/assets/09e321edd47d2fe52889407048092c99.gd", - "/assets/9489107d94425dc2546d2a8e2573cf31.gd", - "/assets/9082e8998896045acf37f0362ce37eca.gd", - "/assets/286ccb1da5c2c84d090c42e1b1a36214.gd", - "/assets/282bd084b2ecad0e48940439afa89f14.gd", - "/assets/80a7797fc314c87bc706262d7c1be5ba.gd", - "/assets/4c0c75fbe75b304df2b4bae0406531f6.gd", - "/assets/6d71790c9314908a5cd94ca07aaed132.g", - "/assets/4c0f110121c75ef3dc23a9a3d0ffd01c.gi", - "/assets/079ce0630215da30b899e0aabe18f0fe.gi", - "/assets/f40937884b0f93132480da6e520fb216.gi", - "/assets/f2c08ddba1434efa53ac450fcbda4b4f.gi", - "/assets/bd7ece9f1f1fe0983733f723884e79a1.gd", - "/assets/61a91dc25befb0214c538ad5d113dd5c.gd", - "/assets/e8bcd4b3e44c713c7984cc889490d1ea.gd", - "/assets/29a3e527be729d3c02d2d17197e68337.gd", - "/assets/423b76cfd87097da7da70d94be8abcc4.gd", - "/assets/6db429a5ad0b3dc169ff843f0a2a28d6.gd", - "/assets/d022d4ea2a8dbf6590cfcfde12662373.gd", - "/assets/07d216f0861ca995b975c1b2b973e919.gd", - "/assets/9efba7c694026aa36afb462c65f86426.gd", - "/assets/ca7e1457a906deb9902b3aa773ae657f.gd", - "/assets/15fc6b7ecd12eb389221f9a9eb840f7b.gd", - "/assets/17a588f3ae11587ab73f2970e27e1283.gd", - "/assets/0883a76a372fc07e78ad0583eb4f46fd.gd", - "/assets/05d951bc1d36a94b9b95206401f7fa97.gd", - "/assets/e91e88eccc685a62c28d6867195f5094.gd", - "/assets/46f19e64e20bf76af0b1a409a436f79e.gd", - "/assets/0f136cf4ea2c21cb308d5f842a9db4c1.gd", - "/assets/0448cf1ee5f90fb6c21b77dd614a0d0b.gd", - "/assets/55484092823a2c0c8ff09e36357ce1db.gd", - "/assets/281eca474f55b63251c76fdaf6708f4c.gd", - "/assets/b2141c0ee739dde01fe4424a34804d75.gd", - "/assets/3b1057fa8934c602cdd38dcdcdb3005d.gd", - "/assets/53633ca6f434dd8d21df990192c0c272.gd", - "/assets/fd1b255ac1f4afdce9e8d1b5aad83cc8.gd", - "/assets/656addc934eae2dcf48d44cd92a24126.gd", - "/assets/9863a7701080e1b2aa17498811132d33.gd", - "/assets/f217a83b4fada8f8f8e0ca4618eebfb8.gd", - "/assets/b469e82f11033bfb2949b8b50a098757.gd", - "/assets/4db6b6d8d1725d415df0222643bbb419.gd", - "/assets/6b9c61acad8a04363967ce27825ee1c1.gd", - "/assets/5420fa7da3da53d9164ae3864407c09b.gd", - "/assets/c422c0871a97a78397a9e9b7d60fed53.gd", - "/assets/fe81ec2616235f5b804eb01cfae81ccb.gd", - "/assets/4b3d59173a9820f902712129de831ee8.gd", - "/assets/6c5c4fdaffd6905ae5b1e2c0cd09100f.gd", - "/assets/be8fb25491a705b586dcb0d74851f537.gd", - "/assets/1e5b579a489e1fb00e301618c8064115.gd", - "/assets/8d40b197acc17347577f55761d9a7acd.gd", - "/assets/6d37de51d6c780cd2df0406ff64a7a6e.gd", - "/assets/2c626fdfa16bb9ab89f4b75f6baff835.gd", - "/assets/e51e0b784dfe4dfcae4c124324cf4dfa.gd", - "/assets/c6d66fed15231f883cc3df7cc779361a.gd", - "/assets/1f4c86ebc2ccc5dc4cfdf9c05dbf5b6b.g", - "/assets/e523bc9fe8696d455d2856fb5aa48715.gd", - "/assets/0eeb3cec00aa25e8ad641d48020c93e2.gd", - "/assets/6b1181cf5ba16578333bb3a63265da52.gd", - "/assets/54f5e7c33432a4d0ea06aaf61d7c2988.gd", - "/assets/cf4bd40749c2858313b59009e29a8a1a.gd", - "/assets/a0104907471effd061cf8a38d18762f6.gd", - "/assets/b5d1daacb6f8861da7afd51119f1e273.gd", - "/assets/f87fdc983be764e123849da612d10245.gd", - "/assets/b312f0f5ba1c2040266acd0e3ca4a36c.gd", - "/assets/9eba61eb18acbe776722ba4ef5c522ad.gd", - "/assets/06d48d76be0efaf148d202ce64d98279.gd", - "/assets/41417923e985aa509f51af8e99154660.gd", - "/assets/0f18621563668c9657aa963a331eea65.gd", - "/assets/fae5d234896f60cdd2e47332c27ae133.gd", - "/assets/5b51d0dfe4d31551112d1186a51024f1.gd", - "/assets/a7ee798f93d6ab7071441855fb9f25f7.gd", - "/assets/8e69473faa3b21c59b4d289c390afa8c.gd", - "/assets/208e4b6d7b0c7f4eff9581f1e7f3ca5c.gd", - "/assets/6450c3127dd03b7c4635f583bcac8968.gd", - "/assets/274d0cb22b59826011d8c42ec000e63f.gd", - "/assets/b98e3e40732da4f56b27ba1d80dcc595.gd", - "/assets/3f5921682e09440b02d49677c7c9349a.gd", - "/assets/71295b39011a50a4dc20832dd6428d68.gd", - "/assets/33aa1022665c8cf9b16ad48901a8d047.gd", - "/assets/1076c16f5b533d93651b880aaeb6685d.gd", - "/assets/860ad9808e3685248f564816ea636e1e.gd", - "/assets/93ec688ad3b83c4ee337812b0f28907f.gd", - "/assets/3162d4af99d285cd6cdad468e8d94a9b.gd", - "/assets/06c62fb4bd6deeeb79a3d67a2c3aa3ac.gd", - "/assets/7c91762275e1fa23d8f9e1dd8e3a76ca.gd", - "/assets/bae4b5b27ef413df23ef697b9379e696.gd", - "/assets/e47d6f24d1513899093870532153b8ad.gd", - "/assets/adcde47ea5e29e447e23b18fae29fdb6.g", - "/assets/2431baf1fb8e0db6dc236121dfdd2161.gi", - "/assets/e0f3132452e207ed11b08bc60ec9917b.gd", - "/assets/d8b316e3aeb6e624b5f136bdf5ca0ab0.gd", - "/assets/3c264291f8feb9128a9ebecb80588dc5.gd", - "/assets/0333decb3182dc45697f0cd2482adf14.gd", - "/assets/6a0b8f3b49feed621d0fc7e0df7ad142.gd", - "/assets/2eeafe7be12d6e5bb946c1843e90d031.gd", - "/assets/52d01368e29b478d39ca3450e086a2cf.gd", - "/assets/d871cfffc3d5777c67e3deb9e9f00584.gd", - "/assets/1997bc1b4714de6b653b20fcbd8cc82f.gd", - "/assets/b1bf372a72902f0799716209f514cc13.gd", - "/assets/c24f086adf5d460d965df52a4dc9ac08.gd", - "/assets/c5b4e12bd51087f3f62b8bef4d60aa63.gd", - "/assets/33a9fca94e3e8e1c66fdaa9dd2777f96.gd", - "/assets/4eb6881b3ecd539c071eeb074a18d674.gd", - "/assets/38db5fa498e9cad7b93e407551cc1081.gd", - "/assets/b49ef0a725890a667b3f543a31bb6f71.grp", - "/assets/717db9a586973990d26433dfa01ee837.gd", - "/assets/e16962f24bdb53f03eeeabbc71bf41a9.gd", - "/assets/6a71fcbbdced6f674392676975ce0edc.gd", - "/assets/925d837056886405f0446a674d888c4e.gd", - "/assets/c863a17dcb389c306a0153c477e93b01.gd", - "/assets/ba05fec4b664dcb59024a98d2f4f747e.gd", - "/assets/3a2567449aa1239d21dde90a3b5e778a.gd", - "/assets/dbaff7fd63df53ec9e568f62791709dc.gd", - "/assets/eaff0a4e525b6c0786912fffe23c4a72.gd", - "/assets/a2a9f423155f76c1c0ab240a3afce927.gd", - "/assets/3ac4247343bdfdfb8e57f7048f641044.gd", - "/assets/bc82f10be0bbe7651dcb02389b4d1655.gd", - "/assets/20e38314f47810065aa4c75d668bf3be.gd", - "/assets/1b871b2d2975dc96d3f12ee5f98ef70e.gd", - "/assets/61dc16291df3d51dba18947ea51a2b9c.gd", - "/assets/be8f1bd0b5eaba87f5b40196df600963.gd", - "/assets/7485664c89137b489660e9322f42a14a.gd", - "/assets/23637debb15a7a772222fff7c2a84220.gd", - "/assets/cf1acb20c877901884ce440e9794ee53.gd", - "/assets/3062713b88797408ee4ef6153b9cadfb.gd", - "/assets/3dadd617ea075f2fdfb937fbdb7ea677.gd", - "/assets/9977cc43724a832fb9e6ef4f23bd0a50.gd", - "/assets/356f592bab3d0ce80a1155e0ab024282.gd", - "/assets/a75c7d5ba623718c442022ed96a6d2bd.gd", - "/assets/18d1997d5f90d569a0dcce53df01958b.gd", - "/assets/47c906a368cb02c7b762b8a61c3e8d1a.gd", - "/assets/7adf2ae3d7764c6e0983b199f3ac9759.gd", - "/assets/ca080e232f1de49cd355502011205ef0.gd", - "/assets/b09bab3c136bb9b429d23dd7a483af77.gd", - "/assets/f92c3d8d6a0efd66cb2d8d49a3f0e9c6.gd", - "/assets/6139a2400b5197d8428bb4909fb5566a.gd", - "/assets/8a50fc12606274564d0850ff33643450.gd", - "/assets/4494ebf38376328f8716e725aeb4e5fb.gd", - "/assets/3866292f69c2a500c32a110df59f1f23.gd", - "/assets/d04410be87921965eac532327952a8fa.gd", - "/assets/7875dab8592ab025a53e33d3c5a53ba5.g", - "/assets/53b06cc161315b38e5be60f142324a56.g", - "/assets/c9a3f9c73606ab9ea3d7f8a463c2cb90.g", - "/assets/0375fd1e360f36c41bc62dd1cc0f81f4.g", - "/assets/70eb7fb0e56d488611afe11268377b53.gi", - "/assets/7c6ea6d9ff683dd8a119efe7672ce0c6.gi", - "/assets/d8ed170f3a66fe9990b46a1a0ae8ec22.gi", - "/assets/17648043c943b79283a5d77ebfed5050.gi", - "/assets/a0e934c5440d62361eb7649189bd2826.gi", - "/assets/3d111a0e4b12dfbee0d5bfffc1481d99.g", - "/assets/5c776a2ebe49a30c315e805b4a33f133.gi", - "/assets/01ef198944fc1544235a50d722707715.gi", - "/assets/18327e68b0b44e0a4a1ed7edefafa1e5.gd", - "/assets/6ed2cb5d383c691da7f5de1bedc18baa.gi", - "/assets/535d31a892b9a486c48a5ad81af00cf9.gd", - "/assets/9524c07a101502562a9173cd7f25407b.gi", - "/assets/413eacc2e555f0667fe4af92867e2046.g", - "/assets/b43266f46644fa7cd81c52230f39e1de.g", - "/assets/691392fda6a9239e4b65064539d64372.gd", - "/assets/ae5f140ad1b79ea7f8227d041b3de56a.g", - "/assets/f354d06f26651762767ed927bf1ac8d7.g", - "/assets/61cf34785f68cf492e6a24df0dc4d964.gi", - "/assets/162603bd5dfc86bdd22a34f0c61ada8a.gi", - "/assets/efe76b858fc938d753b808f254874bdc.gi", - "/assets/2281a8609fc491813783508ffcc83a45.gi", - "/assets/d027ce57387bd98aabd89040f9e0ce3e.gi", - "/assets/49ba549f983bff092e70482f2482c652.gi", - "/assets/d35524c004a3363005d2c04973cc0547.gi", - "/assets/6c6d5c204b67e2eb90c7c2d9618f92e5.gi", - "/assets/463360277db99fab322b7c3836dc34c7.gi", - "/assets/2e7dce114525a7cb088fa1c40d927451.gi", - "/assets/4334c834cd2f2f31a5de3475b1a77805.gi", - "/assets/bdf4c34983c09bc933baf7167d9c2e83.gi", - "/assets/aae5cc427ee67dd2f691cd8cb2295c03.gi", - "/assets/5099b3300549099da9d8bcb5d1d1220f.gi", - "/assets/ad5693cd129ca1413c0bc32781198687.gi", - "/assets/5ec293b1e38763deed3f666de56b24d0.gi", - "/assets/7adc898a54d1ff554fa9f4de6914c753.gi", - "/assets/014631854c313a2dbd83e47624ab7855.gi", - "/assets/994d2b24f910ee253f7e2b13fc3981c3.gi", - "/assets/4fb81bb7310abb99358d065e1bb8f3ac.gi", - "/assets/6ed4e9963932040d9bbde6d07778f03f.gi", - "/assets/6aca41416a4c62b888a2dc869b54380c.gi", - "/assets/22db57e5c8ec9efd6c7f11989b1cfd2c.gi", - "/assets/9d3000b34bb5130007fd17597dd07122.gi", - "/assets/945d8f964e0d67c3f25c5a070fd5d6a3.gi", - "/assets/d12439eae34b70f2dcdb002e513150b1.gi", - "/assets/8705510634743f365bcf1959950ac88d.gi", - "/assets/484597b7cbef78fce7ee41828c3bc707.gi", - "/assets/b35f2fae254339d00f4545b86e58a0e5.gi", - "/assets/92c63fdd2e6133ab66b91abf18d786d3.gi", - "/assets/52c0606cd2243258139cfef2a4ea02db.gi", - "/assets/2d79435d9a21b5026c32e6f04b59eed3.gi", - "/assets/218c13ee1485f454e341c65a5e460707.gi", - "/assets/2c1c8f22e4eb491d5d5a4e5b4ec67fd0.gi", - "/assets/dcd1b56d4899af7eb3e75644c2a28dc6.gi", - "/assets/51a8766470052982ab4a4effb6857caf.gi", - "/assets/f5042fdea364c94c8b547a8070b37581.gi", - "/assets/c5d73f657d2864785184e41fa14410f9.gi", - "/assets/914bba4fefea50758b5a606e2dbbc277.gi", - "/assets/f135a79b20ddeb0b999f991fb42efca3.gi", - "/assets/3a7843d8a41cd4f3fc3ff30c8225671f.gi", - "/assets/5122152b05c73fb74731118fe3b711be.gi", - "/assets/8597ded6f3b2a6987d237799e12daa5b.gi", - "/assets/38dc5576cfce0f1cbf0b66a28f2cd808.gi", - "/assets/91b0a4f1e1925d25f6564c4ef6e3bc93.gi", - "/assets/c9ba82f4f403faddaef80dd6ef95c03a.gi", - "/assets/47aee3024d57de886119f071214a9ba5.gi", - "/assets/c51b2be344a9e2734b090ef236cf1561.gi", - "/assets/82a756492fc6b17fb8bfb4d7d25405da.gi", - "/assets/f00d2857166df987a2a21f3dfb38f0e2.gi", - "/assets/373f17f0ee2781808c07014e4ed54369.gi", - "/assets/d7c6bcc7448f23538a4d74f088a69a7d.gi", - "/assets/dcb219f6e9dc215005912adce4196abe.gi", - "/assets/35f3e2aecfc061f28bbff7918d5df0f6.gi", - "/assets/1fe27d1bf56b4e65c17bbf73502f3090.gi", - "/assets/838b4736447cd75e54663c21642ddd95.gi", - "/assets/39d33d9f108f1cf0053c79c672396f22.gi", - "/assets/a1eb33a73d91086c01fa92f9ab9f7d9e.gi", - "/assets/3891eb42c13bcfae24caf4273a47b79c.gi", - "/assets/44fa558698832fd85de22602dfe5815d.gi", - "/assets/868b80330f7cff0641eddc4b33d96ac9.gi", - "/assets/0517a430bc6629187aec2e4b0d162ffb.gi", - "/assets/cfe05caa8a492d46610d310efd911ee8.gi", - "/assets/79499500b3839e0ac38e6f5f4bf3bc07.gi", - "/assets/419f93c38fe04e91233465e558a5e35e.gi", - "/assets/263bc8abbf6e472ce365b169fe3272f2.gi", - "/assets/092bb3d29a43488f443ddc9075ca6848.gi", - "/assets/bfbc8b997713270458f7249690df78a5.gi", - "/assets/429843578f04f2c084d840bad640539a.gi", - "/assets/eacd75ceee07733c4b36b71daabe8c69.gi", - "/assets/d58f855fe6c7adb155dd267b9e655929.gi", - "/assets/4a9961f6bfb9fd2e356afad29b6ceda6.gi", - "/assets/ad9b87a208203491a6e2654f5a1bed03.gi", - "/assets/b18397084793948af8ab19181fbac950.gi", - "/assets/72c9e9fe70231c45a5b97dc9d70167f7.gi", - "/assets/f47177a23f7b6bf3399722303a49f6c0.gi", - "/assets/b045765012b0554b12cd5fcdd26ea651.gi", - "/assets/a342526b9dd234ab57f8350fd03e9030.gi", - "/assets/08d49a14163f2f02b2af01d588148ed0.gi", - "/assets/8798fb518526d0b50dbf339ff1d119a9.gi", - "/assets/f952a01851ee58239ee0560c041a7935.gi", - "/assets/aca777915740624a4b8f113719d8184e.gi", - "/assets/189df92f178b1195dbdea4a5b3c0e654.gi", - "/assets/d384197d705585fd56216082bbd635dc.gi", - "/assets/0c23fdb71017fc379e4752e9cca73878.gi", - "/assets/2e285d36ef3e88d972bb81cfc36e9a7c.gi", - "/assets/e8f4240b4255f33bbcbe731656f6c953.gi", - "/assets/71472683efb83cb85b6351d3ff63709d.gi", - "/assets/cdbd4cc0d5fcaef2d04bfe391730e731.gi", - "/assets/ac341cff644e84d45ee64919460cdf9f.gi", - "/assets/763b5a0911332ed3c0fa490e63b5fd2b.gi", - "/assets/b2da1793bf3c46dd3230aa0b1a02df7a.gi", - "/assets/43e54511287508363bb50181ec3c595c.gi", - "/assets/3b0f91588bf6eaa1589609d34697dd02.gi", - "/assets/5fc937b3cd5347a87709f8738e29998d.gi", - "/assets/f4f3121e125f0b58b456d8ad983707d9.gi", - "/assets/d52dc7c063b77ff8a26612266ed2f984.gi", - "/assets/f94a26e0780fb2407fc2a061a5194796.gi", - "/assets/158f9c6a3e2841cabb7c93d35f24c5d3.gi", - "/assets/5e4778c1c993dab523e22f9077e9fd87.gi", - "/assets/6256d13458fb2ff6431f04344f96932c.gi", - "/assets/9f6f1f8b0d8af3f146e248089b495a00.gi", - "/assets/37287f1fadf7cf54bd6049f16425897a.gi", - "/assets/a1411c5d9489e28604a2e7589fc681dc.gi", - "/assets/20d865fcfc15d77f22291e11e900abd0.gi", - "/assets/068fa3355a420da3c7b0e96019013133.gi", - "/assets/7a8910be39b6efc0de1b6fac35c085d5.gi", - "/assets/cfb9140d9d55933bfce0dde0a1ff46e5.gi", - "/assets/b7cef165c8b048c45d2c32186bb0bc32.gi", - "/assets/4cbb3e67617c216f22597011aa260653.gi", - "/assets/2581b24ec71bb2f0e975d9dd6ec488c8.gi", - "/assets/523844455f129670df035292e99bf06c.gi", - "/assets/23bb769bd7cd2535b33c4c258b71710a.gi", - "/assets/d0b38cf5f2f5b57d52e2cd7ea78edd42.gi", - "/assets/1560f659de0df9098620ef31b2a0e3ef.gi", - "/assets/8e1290dd7383b958171544a8dbfd328f.gi", - "/assets/25be1cac24b5e8392e6f9d44a486dee4.gi", - "/assets/e2f48639c842cc08127d1adb5a1c4c10.gi", - "/assets/0b4d6330f027c230da69cea36c24b00b.gi", - "/assets/ec17c84f9110cf30578e519510a4b3ae.gi", - "/assets/22c3948e8b09f8123226bec64b16b116.gi", - "/assets/8ebc6b59e82180e91f846e9143062918.gi", - "/assets/a4899c4554b1181547d4cf99b5907d43.gi", - "/assets/ce8541c9324a18e4e7ae76788c92a329.gi", - "/assets/ba9cde3d05eac2d6b1b0e9cdb71d6647.gi", - "/assets/8f738d1e275e806631c65928e66397db.gi", - "/assets/4dbd5887a0f83663b9be8a6aab48f436.gi", - "/assets/6a72fd06eec1d3240e165224cf528fac.gi", - "/assets/b4938d930c65f88b308828d22dc6461a.gi", - "/assets/a4e3175c340dca77aafc5584260c1c18.gi", - "/assets/9ae8be99dca2ee0d74d411220169084f.gi", - "/assets/fad36c5b70bf24164e5d9cf0d068c899.gi", - "/assets/2f5459a11f8df2642c1925366092cef4.gi", - "/assets/51822835ce7fa5faab2210df355daf54.gi", - "/assets/6d06d42daf220b4c6f3c558df27691b5.gi", - "/assets/4a012ce5c9f3e4ba40f9fdfeb10d766a.gi", - "/assets/5cf42baf6c7720fed6e35c2aebe55588.gi", - "/assets/33f5f11e6aec2e31691f9ccbbcfffe5e.gi", - "/assets/138f952d8f03551e89ae65990cf546b9.gi", - "/assets/cb0ccc18710b70a9cda71de9cff221cd.gi", - "/assets/8270e7955bfecae648f5b2694fbf0098.gi", - "/assets/e18163445b1745a4a6843495efc34f83.gi", - "/assets/5720229e1a165587b8fd31f3beaf63de.gi", - "/assets/3dbd22020965c9b641f0660fa65da975.gi", - "/assets/db7e464ccd06eb06cc582ffe0b83511f.gi", - "/assets/6b65dba419754e2a6bd542f5c25ca8d1.gi", - "/assets/bb0068c9fcce75801944c799128c65cd.gi", - "/assets/1c4057c63f2ad5753c8ebe016658001b.gi", - "/assets/b8f9f9d0793df08d62b84884726277d4.gi", - "/assets/5378081c0860b8b6e5c2477cfdecb78e.gi", - "/assets/d5a78134b71d5fb0a03e47005f139794.gi", - "/assets/4055786cc2c64b3aaea35074f1987cc2.gi", - "/assets/fe94cf3cec89784eebe6f3d30bffe543.gi", - "/assets/91889a3c876f9b0bef823dce552080b6.gi", - "/assets/baff17ca4cfe96f18912c8c95d4bb6cb.gi", - "/assets/a5f9564e67e07908e7bf2917309f6917.gi", - "/assets/f8bfddabf55207c8e7edd8769e80a202.gi", - "/assets/a219475f55d753f86bf230020fcf7919.gi", - "/assets/80e2a8b16c2548b7bdb63887860d836f.gi", - "/assets/19fa64333890aec931cc669a1b6e3aea.gi", - "/assets/a660df4d3de22e7f7e22bd3712075f39.gi", - "/assets/70c3838a9a092493a8c5ee8311db1c7f.gi", - "/assets/4b6f5cff2587cad6b32ca571326089cb.gi", - "/assets/c4d75b1a1f8da93d463c97e2da21ab89.gi", - "/assets/3788a9bd6856ab5bb01ef1f523e556ba.gi", - "/assets/e74ae688612ca1bf4dd2fc3a03b41732.gi", - "/assets/cb38d4257e977eb810196016211bcd0a.gi", - "/assets/f2b0250e1b4e624df6399c34b7aa3c81.gi", - "/assets/9f9bfb3507d5e1d40b9cfe0af51f296a.gi", - "/assets/8534cf8cc7e4b4fbbfe96e33b686ad34.gi", - "/assets/2308107f772c30afc63a5ee6fd3e8712.gi", - "/assets/2748fd93ef25cb72f1e67686c34e6f6c.gi", - "/assets/b4113a34e07480d25c62d7773b3c4cdb.gi", - "/assets/57f3e5cacd5d9c44c3ca1b87bdccaace.gi", - "/assets/8838f6babae62e0be1a790df30f0a59f.gi", - "/assets/610f5ec94ca24da072e69ede67242cff.gi", - "/assets/d3ae177a439327e018ea2a63dff0f282.gi", - "/assets/5e9c0ef43ee01c7b047e8c69dda041eb.gi", - "/assets/5630cc584c5533b59ebb9e0047150f43.gi", - "/assets/b98e22b48a07e9b86be4c30fbb82df93.gi", - "/assets/6b4b83040c281f8335908fdaec85ba80.gi", - "/assets/456827522370dea3d0ed41688a6e2272.gi", - "/assets/941f104de48210d8a583cc6a47582885.gi", - "/assets/97c183ac299704f0726357f077bb36e5.gi", - "/assets/b7183953743a52d06faa451586454c43.gi", - "/assets/2f853361b77a086071133388051021c9.gi", - "/assets/cbe2fc9ad848c8a0b65a002a73f4fdf4.gi", - "/assets/09939753dd1d0f7cb59ed6fe9142f5d1.gi", - "/assets/cbbf5260fd359c37964dda893c42f42a.gi", - "/assets/01f23f56d13761088ec5a198bc498e3a.gi", - "/assets/27a0f682b08df3cfb95dc46f2660ce8d.gi", - "/assets/0ef2f4b6918e8852c0a6fdb79f61e108.gi", - "/assets/cab2313fe56134a7196f3447268af644.gi", - "/assets/bb33954a46e1d7ee7eefe628751af959.gi", - "/assets/d4bc27e8e7ce249055753796ee5382b6.gi", - "/assets/e1a11b1ae8153aa062eddff14964b0f9.gi", - "/assets/2d3df1a631b53daf44f5e123784d921e.gi", - "/assets/6ed9d5d6632ebf6bad997eb562578b3f.gi", - "/assets/a9651586ed3d208811a8d3aa9ee79573.gi", - "/assets/a3c2b868cbf525b250eae4a2304b8078.gi", - "/assets/b49ef2d02cb003ad38f1ef77677ca866.gi", - "/assets/8e6c861dcc41bc7d0f125ccc9a98b7ad.gi", - "/assets/bcc6f3f73d65ab7031b947a27fa97206.g", - "/assets/9f3be8c576c0c4127295653d7ce52fa4.g", - "/assets/5629f8d306879daa321260fdc435ec2d.gi", - "/assets/3ed5fd6227346616188611aaff22b7e8.gi", - "/assets/ad908567f557596a3419d52c383a86bd.gi", - "/assets/f66828bf70552fc655dedbcb660ac8da.gi", - "/assets/bfb492b7b82a9df0c68af195a6a2808d.grp", - "/assets/58e5ddbfe67ad90b2351771d09594485.gi", - "/assets/a6cb2e4d4befaa93fd4970b4bb5fb587.gi", - "/assets/f3d51daee9d8bbcc1acad47c4a6f7597.gi", - "/assets/ed95f65d36555301536f98c0110e6ec1.gi", - "/assets/4327ba657f13632391c76618a1df61ca.gi", - "/assets/bcc975e89d56454c2efb39318e77b006.grp", - "/assets/2d46a821485493a17b0c5ba1679008b2.gi", - "/assets/fdf71982356787c4b8d5a1ff393f0609.gi", - "/assets/01f8cd33003ce34889cc56a84766b9bf.g", - "/assets/2a948f8650f04433f8a611f6719ff375.gi", - "/assets/fae13ea8e9bda0cc7a6b42eb64676e69.gi", - "/assets/23b460aef98d9c30e9ae7358b86f1ba6.gi", - "/assets/bac2d2e221c1d7c99c9bfed6ec97cbf8.gi", - "/assets/d0e1db39bc0ee59319696d79a2dd3ecf.gi", - "/assets/348483bb4c3adbd8ad25265997bbfb28.gi", - "/assets/b3a612810d9e29e11062eaef7b83eeee.gi", - "/assets/a1d0a1ad3fb21a668b87ca1b1ec959e5.gi", - "/assets/0826e53a7467e92da00583e4ea911579.gi", - "/assets/a8774f14f243a9c83a9d8054fa821d0f.gi", - "/assets/d21c7cc2f27915f2a3bb064ba738cda2.gi", - "/assets/ceabfbabf64a0fd601bb9adfa983f5dd.gi", - "/assets/087a7a3906a8e2c515f5d52fcd3d8291.gi", - "/assets/3cc2088f83937f39943023714808b0fe.gi", - "/assets/63098ab86b08bff63b7d2637e2d12032.gi", - "/assets/a739c531ee42a0af82ae4d34758730ec.gi", - "/assets/f1fed13939f3289c52de96dcede61a5a.g", - "/assets/d249178334251386025e9e27675039c3.g", - "/assets/d76f437b9d3479838b44f954c98a74bb.gd", - "/assets/23a22712c061ce1422e40e03a7f32635.gi", - "/assets/6422b36ffe0ce03b13f18c7be94e3a5e.g", - "/assets/837ae05116a3566a933608c57795964e.g", - "/assets/055e746f6efefcb538235e15ae5cdfe4.g", - "/assets/ed01a379a4ed3f7e80b78fa547e80d6c.g", - "/assets/e6966e517738d1de6e67fbfaab8eee6c.g", - "/assets/3532086feee3b7f65cb9341a62033c8c.g", - "/assets/2f84b68cbeb5336455e808783fc9a42c.g", - "/assets/aecf7a810d30b63d1787a9777671319a.g", - "/assets/91c553aa9c25db0ac06cf4131017266f.g", - "/assets/339981189c445ddfdd2c3616a87bcefb.g", - "/assets/a94e004a676f6ad054f74a98e3599649.g", - "/assets/66b54c2efe3f036140135c3e06c12cc1.g", - "/assets/2dc1f9ce7d1d7bca469de03f59b7fcda.g", - "/assets/d61b2ed6dbfe0b1d833e5fc546324638.g", - "/assets/8687f72201ee3560f1f76141498a41f3.g", - "/assets/078ad826ccc19c163de95a739f01de92.g", - "/assets/8531026ee51f6b42f457d010d836a417.g", - "/assets/37554afcf9a5f2f044d77353b3469647.g", - "/assets/7f42020875da0f48c75a7f7fe2b7e810.g", - "/assets/fdfcfcfacdbb2bdb6d4bf01476c17020.g", - "/assets/2a4c7d6f27c813a3596f0575f7036578.g", - "/assets/82da3fe0b7ea9e770e134eae35c4779d.g", - "/assets/7bf05edda5b592b74c950095358034f9.g", - "/assets/3851527f06a1610be0a3b83da792f52f.g", - "/assets/aa90965da1817b991f84f72042f36fac.g", - "/assets/be4fe494ab8ef820e001a4b53b965f54.g", - "/assets/3c0ce2d6cb7d925ccf102efbe004ae5d.g", - "/assets/e6a93456f7b8ae6bbc803f5c4b649270.g", - "/assets/4ee648b871ec57a7f00e07de3a737e93.g", - "/assets/0ee173a59ded66e856c4e77d1eb3d3ba.g", - "/assets/915ed9e28533dafa94b8882fd8200591.g", - "/assets/dc76ae5f31532af0a0f858ac3ce89a8c.g", - "/assets/c43f3eff03eef2f47a1b5c07b3f99130.g", - "/assets/9398adaae92d2abb4e7f09e0371ebf91.g", - "/assets/ec8b15ce4ce3b8d1a9dffd4cded7dab9.g", - "/assets/3101acbfa5345302d08cdab0f223316d.g", - "/assets/4adc502944273c251bb8dccc81dce7a0.g", - "/assets/9d78ce21a07a8a1bf2827e21f0b9065e.g", - "/assets/0c0874a60f01368bd1d5bd4f76e66ada.g", - "/assets/f04e6be2a71a0c7e7e2af2942cfffcc6.g", - "/assets/6037cbd195b34805f9a2cb47f9b4465f.g", - "/assets/6c87cdb5cb7e640d20f1f11f14a49a9d.g", - "/assets/2b447908fd540af0122f528860909904.g", - "/assets/778bd42001e29be093b7adb191a2221a.g", - "/assets/3a580f1e07c90f3bf26c0e0b0d4104d5.g", - "/assets/e8a5071078fd62f064788376a2a9ad19.g", - "/assets/7138c56269abb515276089bf611e5139.g", - "/assets/ef70b06b27ca3d3a98258f2c7ea2e172.g", - "/assets/c36d72f9282af5fef24143ecf5f32477.g", - "/assets/18efc500ed9351c27d04da4b82e83e69.g", - "/assets/d02024b4d35c695abec41e193733841c.g", - "/assets/769e59cd46ae135444ec3b13e359cc9a.g", - "/assets/822f040b33537f8f4b96b59c6f166ab1.g", - "/assets/18753b1cdd655bfa4e79a431552bc730.g", - "/assets/1f5245d448dc2680da7d71fe4194818d.g", - "/assets/c266cb87485384369dea671b1ae4a8e8.g", - "/assets/667542e24a3bf673717af5da6f21e33f.g", - "/assets/fcb9e670ffd6be41252d397f0555ee81.g", - "/assets/317b6c1333937a9c05230267d54f5d3b.g", - "/assets/95f6046960dcd2d058ed11c59ade9aa0.g", - "/assets/4778c57be6f64907c04b8eb1a259fcb1.g", - "/assets/ae6e8f066e0995c3e65faa090cf345e4.g", - "/assets/ff1f53ba80d567b09de0dbf62533a89b.g", - "/assets/7747a0a407089ad1e4a713c216c8f60c.g", - "/assets/375822e0255277eec11923ed6f4adca6.g", - "/assets/970be3df1e1ba60ecbfea9f0f06cf446.g", - "/assets/b208e0ef0f98e50ae47cdd1814a5ef3a.g", - "/assets/42c58af1bb2ae17f74433385c2dcf67f.g", - "/assets/02ea1c3674dcc6e15873d3ccd63cc007.g", - "/assets/15b15553217697857a174e0230789c70.g", - "/assets/ff113ef89b15c96ee4d931039909c13e.g", - "/assets/ec7456f33e8ced9ff3bd198185074bc0.g", - "/assets/acbbc035dfc702b6d277b7e1f74f2919.g", - "/assets/d25ad97fbc3a8476806d9bdcaaef7a54.g", - "/assets/be535f897be479668c505ac972fcb4cf.g", - "/assets/9089e0d9148205393e0ad7f98fb66363.g", - "/assets/7a58b3238a56998847cdf6f36dcc9530.g", - "/assets/d659eddc9be4bb81ea41bce82c3eec2b.g", - "/assets/9e979a3e247b3ff0332cbb29cf121c8d.g", - "/assets/9af02224fbabf9cc826bd18635441d79.g", - "/assets/561406a0c210140dcf67a020dccf4978.g", - "/assets/fb32126d066aeeed96a47e27eaf59ce9.g", - "/assets/da3b9212f9b6675b8c2494c77946b942.g", - "/assets/83f5074e0e235d6e4117d2c00ae0bd11.g", - "/assets/45b13217b4a4f24f4cb2123a93af153b.g", - "/assets/aac8a9ea1884fc144b27015a901bd01e.g", - "/assets/5d0055f9f50d982d8cb015cd2c8abb5f.g", - "/assets/da1f9d57995a5d2d5207c36a6005d455.g", - "/assets/7cb88d84d141ff7840883a680ecf976d.g", - "/assets/edd484549de699b34a0d9a89f65a8e7e.g", - "/assets/db3517962828bf71f70a8b789157af28.g", - "/assets/746a188e574d7b0b6a3f2021300aa2ba.g", - "/assets/5e8e7f0a27604e90d0c987b6a2ae1352.g", - "/assets/c022dcd96c1458405aa4fff74f7ca861.g", - "/assets/2e52bcd8a4487f14044e6b9f49673dd1.g", - "/assets/ac67111b6ac08c3b50233bb80070f3e8.g", - "/assets/a910e29ae19c6381cb6ade8f18bc4472.g", - "/assets/1f987a62ad133b9a1c02fe74d8edf208.g", - "/assets/a4999f801d5deca3596e00ed5e8651e0.g", - "/assets/ab66e7e4f062399ef415bba986c6cd78.g", - "/assets/29a599870ad428390972cbdf55332946.g", - "/assets/c41baad40ca70f0e4cb50aa577a32b24.g", - "/assets/2210698a1c3434d51df0cb8c1ed9e0ff.g", - "/assets/222e5a72f220fcc7b00067453248fb53.g", - "/assets/97854aacae11b60c20a6bcd9f84409af.g", - "/assets/5017847c27abec6c2c73a3eafefd46a6.g", - "/assets/050915d5ce7d06f9db2828a1a5ba471b.g", - "/assets/1912bf2b6e55dfc628aa80384d230907.g", - "/assets/a8e8e6b1c09c5c6b439855d2985a3daf.g", - "/assets/7cbe82fd3799e54bdd4159902174a4e5.g", - "/assets/dbb0a2775821a5e188a318f0ef879eda.g", - "/assets/7f4af1227cbaf1f570fedf0b47c8c45b.g", - "/assets/a08903532a249b9a4c0645b6d96b8c31.g", - "/assets/ff2bb4bfe68955035548ab16f9e72085.g", - "/assets/93150d80005e0b6a9599d0576e7510d6.g", - "/assets/8d668b394c974462a65c19d135652949.g", - "/assets/6814933919271aa3f4efb30cfef51a08.g", - "/assets/b61646e7496b9b608b72bb54b5c12340.g", - "/assets/9af4f243f83b5898c84a8005713c30bd.g", - "/assets/9a5dcf862e061660c808c3314a94b021.g", - "/assets/2fbc5fbec922a0c432b9ae0ccb83d2ff.g", - "/assets/4acce36804a4b5a7bb9006dd9124f487.g", - "/assets/8127d0f7d037c92124031d7045a45b9d.g", - "/assets/d21d7d802028b2dd43f1eaf94e78baa5.g", - "/assets/c0f4cb1b53183a429347318cfd0a8024.g", - "/assets/750366cb8c874a0b24fcaef7e1fac168.g", - "/assets/e83578309f44cec2ba910f3a34746c99.g", - "/assets/0e45bfcf86fbf18fd081156554da5dc3.g", - "/assets/1d25d2ac981ecea289323d816e2f830c.g", - "/assets/04f61cf5b376b83bf53f66eae1f65e38.g", - "/assets/50ecd918dce970cb8e9a85f74931781a.g", - "/assets/c93255b63cf7cef0390e21e3de7dc21b.g", - "/assets/c1bbc787c75b0ef16b5a32f305cd46c5.g", - "/assets/3d38855971d57f9313718232dd605a40.g", - "/assets/7b852676ba48d92a2ee0d560d268d9a8.g", - "/assets/c9fa9c0e4d52d2ea7617427c814c68c2.g", - "/assets/a71fafeac8d54a6f6b4eeef631f75738.g", - "/assets/d824dff08fce89c430a9899974a273a2.g", - "/assets/3f47d50db205d1472b7bb4d535e9565a.g", - "/assets/229948dfaf84affdfc820d4fb8cd04f4.g", - "/assets/6e6aa37c52808fecb1654d70d8dba829.g", - "/assets/74ef8ef47f251f37b38b306e1cd34b94.g", - "/assets/6fddace42eda8cf334e736b163d59e76.g", - "/assets/ddc3d357794eee62f86d3db3f85d1cad.g", - "/assets/22fb67325f50c19b937d42e60673d437.g", - "/assets/c5450693c01e0428f14665c31f23f0f4.g", - "/assets/37be298c3ad79e5f7856daa466b3590d.g", - "/assets/cf4b56148876b50b8b6c99cffe44ff4e.g", - "/assets/9e7c097ad72fef85144f12f0fd0285fc.g", - "/assets/d6610ba05c300bb6504ec8273be19d4a.g", - "/assets/8f6b7a0c58cbf426559c3790d451d59a.g", - "/assets/9439fe9763703d272169ce52ee18b6af.g", - "/assets/83265062388d18c9a82bafb4fbdd882b.g", - "/assets/0bf937751578c14d510864a8a97d1beb.g", - "/assets/7cf1050a47a6b52e9679e40886ae0286.g", - "/assets/df64e74aef60bff23b69c61e01e0b68b.g", - "/assets/5ee2a4c4abbc57224d973b706911dc14.g", - "/assets/ce0898cf32b423e601364a6ddc895846.g", - "/assets/38f51294122a720244819b9d549578e1.g", - "/assets/3af7132c3233aaa6c39974e0c14d9140.g", - "/assets/5ee79d30da383f6d3864c6fcbac39e48.g", - "/assets/3a93f2ca5ea78f85abdd9e0ee8b36b2b.g", - "/assets/ac8ce87ceef78d725993204dde60f6d6.g", - "/assets/b420ff8175b4ec3a61a4eb0ae9957530.g", - "/assets/41d9fb9cba23c868f0206bea23789730.g", - "/assets/a329d13c09c661b5864df56070468abe.g", - "/assets/6f99608e3c1e8d5715b6cbb538346130.g", - "/assets/ec5723f85b5ae1fe3cffa3a52942c9a1.g", - "/assets/eed0bb8715296ac07f61065449277884.g", - "/assets/efbc793e746da7f5c8ebdba87e472d54.g", - "/assets/d357af70ede6b78d85192fbb1462a5a8.g", - "/assets/8a0dadb3b7f257887d2bd70361d11793.gd", - "/assets/8056d5dc90a519ebac3678c06a1cb065.gd", - "/assets/9f3a0adfa6937904068e80e17002b3c9.gd", - "/assets/b3592f2b87dae0d5ffbc527a1309d952.gd", - "/assets/72bd6bd68fd1b065eed18e6c4481394b.gd", - "/assets/0ddb91eb203add4bd3d95153a966619e.gd", - "/assets/9204980790c707c36d9e51e5d7a96c82.gd", - "/assets/a5c8d441e8a0f5bc065bcb2a5dc5a53d.gd", - "/assets/1db05f2a8b78ed7ea39b055cd36b4a64.gd", - "/assets/d7193736ebb6cb65a748fce4082c68b5.gd", - "/assets/cbd005751129796d12902a3f6bcc0558.gd", - "/assets/fbcdaf2ecc48fc8825fee8b7d43ad320.g", - "/assets/ea41a96a6a82d6cf75f6ef0e0b0cdbbc.gd", - "/assets/f9f83621d712f08fb0bb3448262e3ccf.g", - "/assets/bc37db673cdcebba7bd9d9e7f73b5517.gi", - "/assets/a4392e3fc1fe5eee941c4e61b57b4b7e.g", - "/assets/4325112549c917c9faf52a2814af2dbc.gi", - "/assets/a2b1005e372fb7802e34214ff3e2725c.gi", - "/assets/bd306466ef02af88d4ca6a8ca6dceb60.gi", - "/assets/6c40d2809e907ce082c5c2ac1f4a5e8d.gi", - "/assets/896dcd6ece0c5618d423c64b3cb9fecb.g", - "/assets/1ad140f121b206fab96707e650fcdda0.gi", - "/assets/80475536378701826769b35b8222c01a.gi", - "/assets/8b245b4ca65d9ea3d8f2470d00bb855e.g", - "/assets/4e4a9a44b8316058c78856f5800cb6f7.gi", - "/assets/2b95e03825044f1b1913c64385ce1d2f.gi", - "/assets/f254fa15850920ce4e498a8706824c9b.tex", - "/assets/4b3abc077949c42a45be95b7aaf9c6de.gi", - "/assets/e2428dfa63ca949b612314234e7d9743.g", - "/assets/d153a2b7f1423ac7e3f5b9bc532bb64e.gi", - "/assets/d38a6bbd9fa5edb792a63995cba35d65.gi", - "/assets/a2d0c36bda91c201077bbed0f4183d3f.g", - "/assets/4664da93d95164c1fb3bbb9958633bc2.g", - "/assets/ff4f96487ee2cf2bab653e1456a9fe92.gd", - "/assets/dc55d3ca4b2f83d93b3c7c52f19b0eab.gd", - "/assets/b26822eb3162912f08242b4b05da5927.g", - "/assets/baa786c859752aabf3195fd2f0776877.grp", - "/assets/25bd816f7e4f9f0e7794a18e528c7a4f.gi", - "/assets/e58d93f1b56362071032d468873b97bf.grp", - "/assets/c7eb1a98ca923ecf2fe99b1ffeb84e53.gi", - "/assets/1b094d784a398ad2704fe6bd4fe04ec8.grp", - "/assets/0dd84b0dba9e12121d8c0420320513df.g", - "/assets/34579016c5f859d74e5705e36944d4a4.gd", - "/assets/367452e8568330996c2fa1d5e8f9e2dd.g", - "/assets/4e8b66af59ae8e4b16d098fe10f595c5.gi", - "/assets/a3ac543070e76d5edc79298c96a4fdeb.g", - "/assets/634eac775c3fe82d3c5e2dda4f88b220.g", - "/assets/f9890ce00d6102230f88aa056863a286.gi", - "/assets/836c8d7ccb3f4a7c48e44c918b0b23c3.gz", - "/assets/ea550e45d94b511875e0303c3a53e762.gz", - "/assets/961ef1d734742c10ad797de45536f471.gz", - "/assets/02abf9c8a2b7e7780080f4f81ff63b98.gz", - "/assets/17d2bae2fefeda4bdf874adec6c96998.gz", - "/assets/15247f2cef1a973cc0f79be4e1cadeda.gz", - "/assets/dffc32eb41bcad978572848cf044f6d3.gz", - "/assets/e116fb6bb8207752a6c971490d1a4e26.gz", - "/assets/ecdd62d81c9814e2581f50917b9d80ed.gz", - "/assets/8b2f9299cd201c1d7aaa226e3679a9ef.gz", - "/assets/612e5509078de7d2ba9a222b6a897581.gz", - "/assets/05c05e91fe55e51e5a9a5575b7c35858.gz", - "/assets/7fc476269f19eaacbd3531167e63608e.gz", - "/assets/4b3153c1623ba549b64c07f09b473880.gz", - "/assets/fda262bc5989a9d855937bb9a139b949.gz", - "/assets/3ba9eee2f30b497c7ad52d82f631463c.gz", - "/assets/1f7a6335eddee78934bce2f9618d5e04.gz", - "/assets/23353298c07d7d9b32c3b6a863900ed9.g", - "/assets/e4c3215f35a43a55796f978702d1877a.gd", - "/assets/b35ac1f1a00ba2bc36aa94745404562b.g", - "/assets/bc748139967a7451e669498064174d92.grp", - "/assets/731a200bcd5cd96d8ae7afeb6302a6e2.gi", - "/assets/aac7c114e1dbce45f3db0abda79407b4.g", - "/assets/e8c94445ccfffa275b1357d56e1650fe.gd", - "/assets/c90f226d52174dc796ce2f8dede35aad.g", - "/assets/fe5aee6fb29c6aeb433b36a7a05f34de.gi", - "/assets/bf9019f9726cdd0716a4ce1dd6f7b22e.gi", - "/assets/8e3fe39eca03ada90de01d05bc607ff0.gi", - "/assets/d619caea27620f52a98943c76fe1136e.gi", - "/assets/6a32359e3fddecc6c232ab407061f528.gi", - "/assets/3ce752a9916a478d026ebf001a26e38d.gi", - "/assets/436af9a7567a76c76c3cb819caebe4a6.gi", - "/assets/004f6fbae2324bbe0da62d90cb977235.gi", - "/assets/524344c2a6c4b41947ee316544b4cf97.gi", - "/assets/80d5bdef3986a95c0aab6ed5539ac12c.gi", - "/assets/6c33b5b41af8d91396e20eccdfec5515.gi", - "/assets/4d36b64a1bbc27e2de7a3ac0cb6875ca.gi", - "/assets/4c35a5d39d1864dfbb014a09daa10edd.g", - "/assets/b5d6986debba9504cae30d760037c5c4.gd", - "/assets/a8a283cda44917c10cb7fa41449ed581.gd", - "/assets/827295e2775428e6b5a3aa7733ef3495.gd", - "/assets/656df33ae822a5cb83453abef6e017d5.gd", - "/assets/83f2ecd7354c0f94f53dd148993eaf83.g", - "/assets/6e82606d9d8fc58106c134c5a189307f.gd", - "/assets/5c73fe33e81f698e2366fb24a60ce747.gd", - "/assets/256e9ed7da7279e9dfd5ae73a46731e4.gd", - "/assets/826f769630b3db40196e0f930ffe08d7.gd", - "/assets/dd53b0bdc61b701494d8d807e6a1ee6b.gd", - "/assets/ff6c85aac42e02d883563acba1f4b8a9.gd", - "/assets/5358bc08b0e0024ea8f3bb66ec3c98db.gd", - "/assets/19ebea60765c35911d14d72cb537edb9.gd", - "/assets/39189304b03370a1dc07c74934bb27d7.gd", - "/assets/3d26f9b6003e20003337e8836638bbb8.gd", - "/assets/220ae011472b92c65848c7ff62edf5b0.gd", - "/assets/84e0bda3f3aa21395cd5e91c9620aadd.gd", - "/assets/b17b49ea2b16d73c193acb3c8449d78e.gd", - "/assets/a553a3b60e029c4c04e89dc3976a4bbc.gd", - "/assets/93196e2d296201f5a35ef16273013f32.gd", - "/assets/8e6bb02d6a476f8e1bb9b752ec3e230e.g", - "/assets/258d0d9a8ed1ec249166dc0e85d0c725.g", - "/assets/9e5a887a39ea3cc1c2524d3a52e47563.gi", - "/assets/dd4b1245f087e70debd880a6db951dfe.gi", - "/assets/7941853f0f80621a105c1f045a254ed6.gi", - "/assets/ab29881797ec13858b342429f9e45040.gi", - "/assets/cbc3f938480168b742b89917d7589997.gi", - "/assets/388c8b0f9886e406f6f334933832f0e0.gi", - "/assets/9ebd4f00192d6c578827b3836031357f.gi", - "/assets/ddd0ee2b6a040789957e609d7bf3da97.gi", - "/assets/a79cd05d7c28b68c408420ed5524d1a1.gi", - "/assets/1b19989cd628d4dbccc61f8496ec0199.gi", - "/assets/19166d636d8d07cf74f02f97981cb8c2.gi", - "/assets/b65a37dc696d3b68e8b36ea8ba25b1c8.gi", - "/assets/b7e73ac975938c528f1bed829c500756.gi", - "/assets/5094ab63b5643680628c68b07d00764d.gi", - "/assets/91c49cfb11bf2fb122b360851897f21b.gi", - "/assets/663c046f14c37b6775dc6c9f4ec5714f.g", - "/assets/74ef11ae89e3df6877b37321bba69839.gi", - "/assets/a42bf7692d3df05b3c3cceb194e07fb7.gi", - "/assets/84fe7fa71f20041009e3a7c20f81901e.gi", - "/assets/0ea2543393b55245109f0cc97e90de71.gi", - "/assets/a1d82ecb4045bd19b599e50ecf4f0d61.gi", - "/assets/7a1d09e6c8bb2e5e3c78c7f64b640ca5.gi", - "/assets/aa69ba1ab1c03d12b559ef20cf141fd1.gi", - "/assets/096296ad426723621f384d77bff67d18.gi", - "/assets/cc4cd0abea7691558753d784bad1b26b.gi", - "/assets/4f9db911256e728a49419a32c6b8fcfd.gi", - "/assets/7dd6f50ca7c98be410e4698df55f6ebf.gi", - "/assets/c11e44dfb8e6a974840281a2b0c76eb9.gi", - "/assets/b60c41fc76d60b9fc58f8377105195be.gi", - "/assets/be0c3aa73f658da18a7b013c9299d450.gi", - "/assets/a12cce81200ddfe4eb47ad6b9b8f7356.gi", - "/assets/4df996436cdea0b39560c6b6e9e49dc9.gi", - "/assets/2f7cc8c06eb88c5fd9ca0540a73a2ab4.gi", - "/assets/7f637ec2b64648364ce0e95d8bea97d6.gi", - "/assets/3b9347fac6c8705be630d4e24512a4dc.gi", - "/assets/5e78675fb241c72bdf4365dd7b4df9db.gi", - "/assets/fa970be4a2edaa292d821b863cdc7774.gi", - "/assets/bc0b9d9ecc7f0dd7e074e1aee270ced0.gi", - "/assets/74e5396fe5e23d030247cf945f97761d.gi", - "/assets/13184ffbdba969bb874744fb70fe6f1e.gi", - "/assets/c1d4dab28faedff17820787a0008c643.gi", - "/assets/908250c1e954d02d3b36678acb92e40a.gi", - "/assets/52cb637668fd54af492a9ac7b8965ccc.gi", - "/assets/75c4f59deba498845f6567bd7f42f247.gi", - "/assets/767faa12e19f276d5c0d5dfcb11b782f.gi", - "/assets/55db0e6b6d9c0e2e06f2b7a6bce253c2.gi", - "/assets/19028eb73e8fcafa5ca0ccddb3a4ac07.gi", - "/assets/0bfb9a0b6aa5177a19db88db1a34b683.gi", - "/assets/e907841fc3ba671c65e3e986659cda39.gi", - "/assets/9fdd5283ff2550cddc39d6b8418551da.gi", - "/assets/f9ac17d4d2b88bcf2ab0ef73be0eb8ad.gi", - "/assets/64f11d9ac4ec2affe087b52faa47c91f.gi", - "/assets/0b33573477bd5d546e0812e51df61718.gi", - "/assets/8affc98647de3e3844d923af13b8fab7.gi", - "/assets/87e221cc81c3c19c1479cc552fb5cd3f.gi", - "/assets/c7ccd54da09202086e5eb1226d8b7842.gi", - "/assets/c7227b1bb61327ba43bc9d78627dd6e8.gi", - "/assets/0a6430c689823cd62a67cc4994ee80a9.gi", - "/assets/4b8c0dd51842814c86438603805d98f8.gi", - "/assets/3ca893b4080d4a5903614ec3d43b00cc.gi", - "/assets/13acf93ccf93e2bea418690b270c1bba.gi", - "/assets/f781386a2a0c73168d4dbb88dc61c3d3.gi", - "/assets/0bd3c2bab74d2b63926682d80555204e.gi", - "/assets/8596801201c58a17688cdf2299fda6aa.gi", - "/assets/352e9fba349e098cc0d440f34cd1c7c6.gi", - "/assets/1cad469da38331de9376ab56a35a88e6.gi", - "/assets/3aa1f680fe12af3421032dc01ee12d6a.gi", - "/assets/832bb2628924d89b00085383a5b144fe.gi", - "/assets/4827cfb29961fc564fc21d0f48a7c090.gi", - "/assets/0d4375dbea831c9daa9930cce562853d.gi", - "/assets/51d44e38d00817fbcc24f71c467c42ea.gi", - "/assets/813e98183cfdbd52232d60b7d1fb1cc3.gi", - "/assets/2bb99d6cd89fb842c3a0613eb8fd45b1.gi", - "/assets/b3ddb7b83513d9b7d498fdde0ddae420.gi", - "/assets/c3c63a07ff5ebaedd5774cea69bc1632.gi", - "/assets/a04afcaf56873fc6d57c2f29992a25c5.gi", - "/assets/b0fa79200ee6d5e53e663a8646a69721.gi", - "/assets/7fddf04350826db5f78e18454d9af572.gi", - "/assets/491c108830e18f992468fd54adcfd342.gi", - "/assets/7eaaa5a74c6b8069ad1ea7cc7d3c945f.gi", - "/assets/7a0e8e4c9fcd9ce4264cd53f56a7c36b.gi", - "/assets/409a22ea4c6aa139f5e54121c1f6258f.gi", - "/assets/b0812cf68ee3ce3d5c0803ab915dc70f.gi", - "/assets/85fd86c91c2425d2db235fe4d9d23370.gi", - "/assets/a829d9a5a80eaa632993c95de45f4bc4.gi", - "/assets/4d2a9120ce933946d9ae954d7ba85307.gi", - "/assets/ebb0fe6e63f47e6cbec9bdda715f4fe8.gi", - "/assets/d914b85797fe28baa1018d52d011735d.gi", - "/assets/61f87a5406cbcf0b26f72dccb0fd8028.g", - "/assets/4490c004238c19daa02e01c6c0a31a99.gd", - "/assets/b5e62387216822b74e141a5bad33994a.gd", - "/assets/99edb876e928571083e33cb0827e9e1a.gd", - "/assets/aead877fe1a973227ab80266dc746c99.gd", - "/assets/797df631ca7dee5434d6a4b4c94cfcde.gd", - "/assets/637299d5b7dfce141875b83bd50a40b3.gd", - "/assets/e918d52c286539dad0172c88f8ba844f.gd", - "/assets/f00189abce1e3009f54800fa5693e6ee.gd", - "/assets/3e3c5bde57efb5fefe40be24a456e020.gd", - "/assets/85b0951df005877245f9ac05c5deddcd.gd", - "/assets/f9a950d9673a6f1bc79af0dea9379fef.gd", - "/assets/0bc3d9f04ec9ff7baa00001c167f11f8.gd", - "/assets/995cae4d8ddbdb781f6ff634094a36f3.gd", - "/assets/2f62ac1c7ab7b6e3433b65cfe8c23a51.gd", - "/assets/6e04d4cb65f5112de72881796d425099.gd", - "/assets/e445013e3d37ec9efdafb4534010ab93.g", - "/assets/c9d32821e444ad58930b9ac62881ed85.gi", - "/assets/c20d2cabd0788d8d994f94d5d9076650.gi", - "/assets/e4e0b6543fc66abe21952af67cd7128f.gi", - "/assets/d99676b868254d43500aaa3ca2ec9eb7.gi", - "/assets/4d5d22426942453139f476e8c3e6425d.gi", - "/assets/84363d080a1056a22424bf96af3ea3d6.gi", - "/assets/a8b920e1b8d3a98054a3bd522dd19ab2.gi", - "/assets/d428a6a26849a5be131b5fa6ed7e3a73.gi", - "/assets/265c849d483aef14de2aa2410ffb4024.gi", - "/assets/c710c5d4f905ec76178a0a47432a89d3.gi", - "/assets/d83c6c15f82830e2dd7e267ddfbd7bda.gi", - "/assets/7f4666a08c4276580e6c68ccc7582a7d.gi", - "/assets/5f142c2c9537cb9ab099ab909df2cfaf.gi", - "/assets/12ee64b5e0fa74257688057767125999.gi", - "/assets/4d5e2b98c4422daec63c101d90aa1f4b.gi", - "/assets/92bbe68249dcd2efb4cd9033783eeaed.g", - "/assets/1273b4a0a97b802290e28eca1f684a1d.gd", - "/assets/67ad872a3dbf51e82c9b0d635d9c198b.g", - "/assets/ae6689cd4ada1df95f6380dfb1b36bd8.g", - "/assets/cc945a9cb3f1ee8a490ed6be9c148120.g", - "/assets/a121bc1374f0faac081e3a2f73820b95.g", - "/assets/ee6165a192d707825361568736f330a5.g", - "/assets/73f2c621d90e1064798ffc092b2b47fb.g", - "/assets/9187f373d79049bca5777bb341f4ecb4.gi", - "/assets/626137ff92162ca12732fb9b3906eaac.gi", - "/assets/e7240f2d1fab6e628eb938018e757ea0.gi", - "/assets/b65d722385b4398114159192b9d73e41.gi", - "/assets/fc64f5858042aa6754fc9e613573a361.gi", - "/assets/0cbf71336e2f4ade43bc90e7dfae3697.gi", - "/assets/b11f3ead0b8721df42c643b3d29a5eee.g", - "/assets/e5bff3002acddc91b5eed3253ccff9b3.gd", - "/assets/c45b6bdc66907dab7e13f5e617ed0e44.gd", - "/assets/a594ce4c424d07a4d87e26c46f728ee6.gd", - "/assets/c768526af2cf4ff0a931a68347406f24.gd", - "/assets/17e7cbd1538c4ef3e748b63a8968133e.gd", - "/assets/4442d8bd860c963b29b85e48a76fa517.gd", - "/assets/7919cfe0ea96f57671705692d613330a.gd", - "/assets/e85a92bec8e2b4aceb3938c155392076.gd", - "/assets/1947e9ed0f555dad81bce1278a94b35c.gd", - "/assets/8c340cecc8ca210a1a133a9146e02fa9.gd", - "/assets/569ce2768b8fb8a45af3a700a297d411.gd", - "/assets/134ce59ad2d2762da7065491dfdedc57.gd", - "/assets/fe05cd0d2f71bcc0c190f877eb3ff057.gd", - "/assets/e1f9e41e672a2bfc768d48430f9d9ea1.gd", - "/assets/20fbd66923db1eee6b7faaf12cf0b6a6.gd", - "/assets/de2f56ecae757d7ce3faa2a28d5844d1.g", - "/assets/2da0ea8f09e94bc3a61558c649236540.gi", - "/assets/4b5ddfc9bba2f41ca03b30c687593b52.gi", - "/assets/9affcac323778f0dbb93190b8bd9446b.gi", - "/assets/e4a66b1e4f13d5d7dbc2a7edc27e73ff.gi", - "/assets/d922c02a362e33435a3450a7cf24f0ab.gi", - "/assets/a892c58b06f66670e48713a897c0742c.gi", - "/assets/ebf07a422bcd0466b31545e6edfd69f5.gi", - "/assets/3c5321614e403496eabb7609d8cf73ec.gi", - "/assets/8140709fe3beef3b06e2206ad1b56a88.gi", - "/assets/c8cfaa2ee97e904ac684fc8980416c8e.gi", - "/assets/efee40843972893a46c912b06adcb533.gi", - "/assets/67dce2a464ea4c1069763db4296e4f78.gi", - "/assets/c74cdf823997ae29095e76d7cc032500.gi", - "/assets/f42f2d8ac70b32babfb2fbd168bbcb06.gi", - "/assets/a67c527296266417931c1a0302b0e0e0.g", - "/assets/51ce8e2a395d3b5534f946bdcd43e9ab.g", - "/assets/70f69e92cd490cf2a85711ebb6b02b09.gd", - "/assets/935664723eadf6a13220bc9c60044411.gd", - "/assets/47fae2a876809fb26ac82d5d9b9df4cd.gd", - "/assets/4af953ac0d535503944c7a690a750386.gi", - "/assets/6adcd3d90f41d3c2634e5040749177a1.gd", - "/assets/f1ca84d44af73d89650e745e13f5f994.gd", - "/assets/2d60fc127859a1e3561b8e035736e4af.gd", - "/assets/33c00bfa492c699ef05681ce80a74b85.gd", - "/assets/7d229e21721ca089e6686bf59b824d02.gd", - "/assets/0e5611b198ce092dd9ed8480e6a1345f.g", - "/assets/18f87791c58249717accf6027ea7bcc0.gd", - "/assets/0f4db7ed620516e7f8a374fcd05047c3.gd", - "/assets/ddfc0934e916557b7a1e55b0dadcf029.gd", - "/assets/2a749dbd2f05a6d1601a71eee436bf93.gd", - "/assets/232f35f222c7b685e5dab7a6cfd1698e.gd", - "/assets/b93e5f984386e7840bbe8d4e5568167e.gd", - "/assets/793fd0dbe07ccc4328818fd51f90f130.gi", - "/assets/ffa9ff58e1d8224a91f4830c3551c25a.g", - "/assets/abda95fd271b65d9d7ff5bdbec65881a.gd", - "/assets/6389ee14fbf1a98e7719813a1356d462.gd", - "/assets/91a959b72d3c14c7c078a71ebdcbbad6.gd", - "/assets/7d8c78aa4a7187372296ea036fb8dc42.g", - "/assets/1e1b767b5ef26a8b6e59cf4a431f395d.gd", - "/assets/a56c1d40fac52ae3354d65dcb57cc08c.gd", - "/assets/f42dc25d2ec5d243fcbf830f42cab828.gd", - "/assets/0278cf03481cba25240fe7d12e86fcca.gd", - "/assets/4e7e6576039101dbaa1fa191b92f9d56.g", - "/assets/a493f26728993c3179a1fd08748b5b88.tmd", - "/assets/19061dd01d0abb32a911723fac34d55e.gd", - "/assets/49f98d12e25dd1a7dc89f19f4ee9e3dd.g", - "/assets/3b8cce2672f0787a52a51f2e16d207b6.gi", - "/assets/184eec868533ecc456b07a074d7e4a69.gi", - "/assets/383f5cdb97f4fc28f31116746f2263e3.gi", - "/assets/3367968b59948b810aa1691591c3ad90.gi", - "/assets/3620a0e3f9b010a67e2211fb57be9795.gi", - "/assets/9afbbc19e27ba0fd7a1b8fee252500a1.g", - "/assets/89fee919a7f5e23a9a82fc21db21ba62.gi", - "/assets/660ae80b3383cc2d962d13a8aed43693.g", - "/assets/b82ec220b60e071be3bf95c9ed4c22af.g", - "/assets/9e54ee21d9ab4f37d2f7879c6b4ac716.gi", - "/assets/4e5b7fc1bb21bbb03c97658f701d2daa.g", - "/assets/ac4afd291bb14c730918af126ba3521c.gi", - "/assets/ce4082d6894341edb3c8cf74597bfc18.g", - "/assets/faea30b87e190175fa708c10fd7100a3.json", - "/assets/af020210038acf60ee174488155ba357.json", - "/assets/4e3f7c04f288d20b3ddad6d53f24901f.json", - "/assets/d9f0b4450767624fa50e3a12699392c6.json", - "/assets/f2637f33470266c1ac1a8024968038a8.tbl", - "/assets/82ba1d81b04e2f136da596bf045ebd47", - "/assets/400dc1410ebbe39bca248fa325768144.json", - "/assets/7228f62fe4348990a632e32ea78fb287.gi", - "/assets/f175381bbfaa6bc9a084bfed735fefa1.gi", - "/assets/c650baff09d4066f58fdc00833b69a72.g", - "/assets/c519ae1edd9b21c1c9dd2823286b8db9.gi", - "/assets/eaba229acd46a8cb5bf564665580f28e.g", - "/assets/1222355135cbaef14af2bd98eca9349f.g", - "/assets/c280c6e64e6f64c2070356eec63568c3.g", - "/assets/433e81b987007d9dad468b3992092c72.json", - "/assets/f4e4fb94afd70a00c165508d8b08bc4f.g", - "/assets/a037e7d94318098cc9338bf161f3b0f7.g", - "/assets/55b1e71dffd19ed10c7d7c4d69056663.g", - "/assets/e4c90f59faf28ba123f022ffe98eb0ce.gi", - "/assets/3feece30ddda8ab8efc5389042082508.gi", - "/assets/291ea97af7079038612acada9cab1584.gi", - "/assets/326ffd641fb5c8ee0f7c2fe2dc2fd07f.g", - "/assets/deb83f35a40f46e65fa692a4d275fdf4.gi", - "/assets/a6f7c2db3faee37937eedac208c2bd3c.gi", - "/assets/7ce2f4d86474cb5de0bc14d8b94b0aad.gi", - "/assets/84fa4e56e027cbceefe0c7a020c90f45.gi", - "/assets/6c040b7bccd75863ed85c8651f446936.g", - "/assets/59d380dc0768aa758201859b7e66e394.g", - "/assets/391fe85e4fee7ca4bb4923c0d625267b.g", - "/assets/947fa7e4f3af1b9a769d285dd4c598b6.tom", - "/assets/6d670dd78f1a6d1ea086b73647a9cdcf.tmi", - "/assets/98a921705a9e83a0ffa1402fcaf3e35c.gi", - "/assets/0e84d7ae8f2c75ad33a65c41f163b4f3.g", - "/assets/2e55a7cde01a792d2dc3c51cb17c0786.g", - "/assets/707626caac65bf363337f2c043eb8f85.g", - "/assets/bc7a2185edf1306d8e555cc20af2a17d.json", - "/assets/a920acd098318c94b9e1844486b79e0f.g", - "/assets/5bb5441ad244bebdac48829687f9e36f.json", - "/assets/af7de883368020b84608737364e8b994.json", - "/assets/558320af72a58ef2c97aee5b8dfec5b4.json", - "/assets/7b8a94aed13c6b127902f3c796732e27.json", - "/assets/17154fc6b7170fb0f98d0768341b7e22.json", - "/assets/26ae25e2ccea23fbe7f220b3859842bf.json", - "/assets/4814ca2498173004ad8447d298778405.json", - "/assets/f31e9513fc8cdcbe1cf7376fc8ef15da.g", - "/assets/1515b67b699b2fd7b3d24469102b96e7.gd", - "/assets/fbeef1780f68513e3fd99c99cfb19024.gd", - "/assets/ae97ee3c295248a712c6d7e47d695217.gd", - "/assets/ad83821325b57f591aad22bb0c4519b0.gd", - "/assets/a80e00dd069485b14cf75f8261961c10.gd", - "/assets/50222dd8947ae3fd28e00e8d81134dea.gd", - "/assets/d58cbf76513d802ef1eeb432a7f36a07.gd", - "/assets/e0f22469a67bbc6d51ca39f312cdab63.gd", - "/assets/289c9e96f4add12f8545b5e0f50e9116.gd", - "/assets/c08b358cd4464840985d225680d85b07.gd", - "/assets/d4f1f86361cf23ca185cda37a9ccbd0b.gd", - "/assets/155d542297c9ce1324cb7f2ed7889353.g", - "/assets/0799295fd44fec73f16882b85f7bb292.gi", - "/assets/17533448c039c794c7c3641ea4e65e55.gi", - "/assets/599b96ed7f9b41b8ec0e6f3acdcf3a91.gi", - "/assets/e78ccf52e76007cb78aff23792b899fd.gi", - "/assets/411e82d574e294d7c694710666993280.gi", - "/assets/5b3e83547272592a50f3bbcfd334d048.gi", - "/assets/5be161b34f65c5132b7b42cc309871eb.gi", - "/assets/37321b0e73e8312a6342adda9f9ee17f.gi", - "/assets/95748f10bd06b092ece44c9e3f051289.gi", - "/assets/694870ff745fed678e1faacf31ef8b38.gi", - "/assets/ca2e6b983706a9f9f804b11ad8c6564b.gi", - "/assets/c162c9c939b371e2a9825258267bb369.gi", - "/assets/ac09401274ad98fb18be3e1d7105c53d.gi", - "/assets/70dbdee759e9ae81b54355c44fa74636.gi", - "/assets/ec7d15db0d4f50aa56f7596a72d8a791.g", - "/assets/17e9bea6202b7c224ec20602df6a5ad3.g", - "/assets/e5d6f0363d4361f66e9779390bde004f.gd", - "/assets/a1e5ef0d758bd15a0e7f38e66a1da0f7.gd", - "/assets/6e268d8c6d3b478cc296ba6a62cd078c.gd", - "/assets/22c317d92e6c603cf87e144748cce337.gd", - "/assets/cdfed668cdc45785ac5b7eca2c854c69.gd", - "/assets/b82ccb7d8579707acd7a5597836dcc15.gd", - "/assets/c192f8b9e645f664a9d4fc8003caaf87.gd", - "/assets/64be778cbfbaa7e1b30e931e65f5bd90.gd", - "/assets/eb57a856c14d52aae743f3a47d7caaaa.gd", - "/assets/a5e9c14d38b6a4a2d5ba2043ae17abf9.gd", - "/assets/95fbb4cc56b21466da74cbc18e4cb926.g", - "/assets/2891433b1988e2acb1932c3bb0011163.gi", - "/assets/4819f45fb545ce929fb251ae7b4688fd.gi", - "/assets/055680c38c42acbc3e03aa68d10fbcaf.gi", - "/assets/4c67bded037d685cc618a3ced1afcdf4.gi", - "/assets/0a68fbcd4e859b2df24f3c5562401a60.gi", - "/assets/d795671677e9906c0dd6aa77994d157c.gi", - "/assets/eac903fa0c43d686c204e6db0dc4597e.gi", - "/assets/b9749b805ea0f6ef89f27873aa4cb93b.gi", - "/assets/36e8667fcf71748e0fb497a9dfa87b40.gi", - "/assets/043eacb7f0b7c2a8da168233548198d0.gi", - "/assets/79691386cc4052c36c6409ab97638d71.g", - "/assets/25e718c5c25e7dfcd827a5b30e0835b7.gd", - "/assets/7d4b95c69e31903045c43cba756bfc86.g", - "/assets/33c2902725baa53d1c96ddfee4a7e064.gi", - "/assets/e6faf3281f6fb49242a7ff039f546aaa.gi", - "/assets/6a71ebb6f70ff95ee63df42230010974.gi", - "/assets/c06d635e7830e411333ebbbf08dd7973.gi", - "/assets/774c151333a9c2e672da7e5cd59cf5d0.gi", - "/assets/9f20993cb62cd5977ab9df29a57321ba.gi", - "/assets/0068fd0e049ae55c2e2bcbd416cfb621.gi", - "/assets/e56f45678ae9d5c70670b5098563d392.gi", - "/assets/ff7446fce1b1b04a9198282b71fad186.gi", - "/assets/5b18ec7ca7a244d3e60705ed53de9fb6.gi", - "/assets/82f0d5321c2bd354561e19dcb8397417.gi", - "/assets/763d0fd9631960700a7ac792512246c8.gi", - "/assets/9eaced858f490fe054106b898fe85485.g", - "/assets/4c99677ad2847db34068998133081f1e.gd", - "/assets/95f2e9f112b640901773744c38307483.g", - "/assets/164be464e4d4c4794b7d471a14dafecc.g", - "/assets/1876c0ad692ca4d49b18d22bfaa0e65f.gi", - "/assets/baf7e5756d7fe7a193f2b4a76a80ca1a.g", - "/assets/50caba7f0821667dd7aefd309d5cbc17.gd", - "/assets/116151e262eb918559febd550d647213.gd", - "/assets/513193ca0ef822c9d2ccccedf77ddefd.gd", - "/assets/c88fd6df04fc82f174521227f84a1b95.gd", - "/assets/23e17b0911ed57fe9813b6c57f4c9fd5.gd", - "/assets/c11126ef8f4f0316a9fa0294cd22bfef.gd", - "/assets/0e0634bfe3ad307ce34a8ced28ce436c.g", - "/assets/74962c3c997fa04ff8c78889a62ff9ae.gi", - "/assets/925e738c5f2b81e48b284fec6b3b008a.gi", - "/assets/ff4f1217cb5dc41dbec4c7101ae5e01a.gi", - "/assets/29033e7b5e35003fdaae65927a69c758.gi", - "/assets/e02a7b9c5eb647b6ec9e080fb88bc7fc.gi", - "/assets/9ba4112d1447cf2da0192d4e5cc6896b.gi", - "/assets/5e8d4cc212cc844f762489fb0d9ee615.g", - "/assets/c6314fc3087fdee9cc2c526e2660b95c.gd", - "/assets/4aa4d263cc3fe9d8739e798113acabaa.gd", - "/assets/b81f106aa8254d5a9049f72f4f10dd70.gd", - "/assets/f052bb025466b450b8a144a1eec23ced.gd", - "/assets/14b8c394951e4b7a25ea5fa135e64d82.gd", - "/assets/4169e6042c3e0385246a720d9310af61.gd", - "/assets/9996adf4761091bbf0f5818d80a81c20.gd", - "/assets/634af410b2c546fb8ca8cddef8968518.gd", - "/assets/93429985d80fd1d64dca619cbe6522c0.gd", - "/assets/2271c54b41b96fa4a531a8d99a142078.gd", - "/assets/ba128b92da9935b52a847f41f05c4e56.gd", - "/assets/7c18f2dba868ae3d4dff8d41275377f6.g", - "/assets/ac6c6f98e981bea62977b7acf47e2d5d.gi", - "/assets/94380176d29fc200732ae427900d2faf.gi", - "/assets/f9eb3cbb09c66bdb03a9c57b20d7face.gi", - "/assets/a28f540b55c3ff50bfa71bc4ad565803.gi", - "/assets/09a85f8086a2139dbb17a8d6e3d4c2c5.gi", - "/assets/7ccd85ce8272b839505faa8db262ed2e.gi", - "/assets/88f300bf3bfecdbdee544607c62c0a02.gi", - "/assets/9fb150f0a8765f270680cb784a0e83ae.gi", - "/assets/f28f080047df6ee328e91026771d37ac.gi", - "/assets/267aea4cccc8818fce5ae67da988b2d7.gi", - "/assets/eba5bb5650b1537b15f7c2a5dea12134.gi", - "/assets/e583fc75e65cf543ea5e40148185d0a9.g", - "/assets/f182f51dabdd077f32b061d9ba849562.gd", - "/assets/9440b1c0d77bcdb19adba99058f28073.gd", - "/assets/c51d13ab25130169749ac9a45eded442.gd", - "/assets/d54913efb2bbbf1b6efc25eac399bdf4.gd", - "/assets/cc1fe55c00b572323afd0207d8028a86.gd", - "/assets/74ac030fb3a0d214a7b70f94708228c1.g", - "/assets/0ea18dd9b7d89a5e2679e1eb508be27f.gi", - "/assets/c52d3b20198d1160a738431faa302121.gi", - "/assets/d094082a0ebbd33c1dd657994d4af559.gi", - "/assets/a02d49075a33cd8b1faaea3cc6f2237d.gi", - "/assets/249cb16552b3a2f54e6d15e408961410.gi", - "/assets/a131b80d0875ea6bb89c529d95a3b8a4.g", - "/assets/a0aeee8824449e241c45ba8859a0dfa7.gd", - "/assets/1dfb717bdc77664f60c98518f959f06c.g", - "/assets/68fbfacc994bbdc80d60d36e2453e4db.gd", - "/assets/fe93ee5c725fb619a0f4f1aa53055211.gd", - "/assets/06e96626ad11e7eb2a532d13f679efc1.gd", - "/assets/54108d6f302f4f2b9c8eab15429ec999.gd", - "/assets/bb2aaec69e355aa7a9d31e7a036c5347.gd", - "/assets/4a0cdc3f23eaea9c1e86558e4fed6f90.gd", - "/assets/485eb74c0088add242830be5aeefee76.gd", - "/assets/9b169ea4392d756a72187f8519caae31.gd", - "/assets/96b1bf0ccf0980c6089d777e318c3773.gd", - "/assets/386188e20b5633785fa030f5124c424b.g", - "/assets/c0898a55547d8784c001adc00b47caf8.gd", - "/assets/0c8d9995d8e8b2141ee3276dfd6c0fcb.g", - "/assets/894ff9d9ec23b07f0f25581d983aa85a.gd", - "/assets/d73a591a7812d1535a85fc0203e0f08e.gd", - "/assets/e2bfe52e8cb3d6589be3d481310233d5.gd", - "/assets/9c75455d8ef563b864c40d55d3354bd2.gd", - "/assets/e7be48dff23b93193fa7738f431a775e.gd", - "/assets/fef96883dab9f8e62c29e738e9f6b7df.gd", - "/assets/b90ce0b1309e00d2ead3837ac6946422.gd", - "/assets/ad0ad302161a8f6b52c8296e350862f1.gd", - "/assets/9eeb43f7d10746604cb6e3c1508db275.gd", - "/assets/d58cfe82ef94b3caa82948e5c5fe903c.gd", - "/assets/27b2bc0721267cce5c968917082d6b34.g", - "/assets/ba4660ca54f16cf617c96210c1bcd9fc.gi", - "/assets/08985e665ce12b993e0fedacac43148c.gi", - "/assets/b5f4e9454b159efc31657effae2989b1.gi", - "/assets/1b541c62f52c6bfbbab40cd9a5b44207.gi", - "/assets/7fc2ac29dac4e4b32f80fad65d74a130.gi", - "/assets/3bbfc3a3968dbe742a6c8037746310fc.gi", - "/assets/83a999881b18bc388f705780465d4612.gi", - "/assets/5e23c0417c7c381603ccca971a65ee55.gi", - "/assets/1f7aa2f9bf07342a712a987475d14e02.gi", - "/assets/0d5138dd8b20cf9ff0f5bbce91288b08.gi", - "/assets/603053187d70930d2f4264a7fe0954d0.g", - "/assets/64942d3a27248c64c1a2b1fb047139bc.gi", - "/assets/10f0e4489064891dd7fbaed4a447611b.gi", - "/assets/874e79cd0ca5b6e2639f20612ddfb177.gi", - "/assets/aea2ca2eabf7447c5a6b04e20be1152b.gi", - "/assets/8023e073b5b112c6c3d8a31925968c75.gi", - "/assets/74c30abb42db36e60e8fb1971dd9b634.gi", - "/assets/412fd9dd648a8c2d9d73ebd8416d5546.gi", - "/assets/5f8e0933c4463712bd7cd8fe6229d7ba.gi", - "/assets/0f6aa1b97006d00f1ffd93d435787a7b.gi", - "/assets/bd5ce9d344017c4584b64fd73f9d9e59.gi", - "/assets/9b6f4615c6f5e7fc3d3b931b5ea6d161.gi", - "/assets/f81e2682f0d32dc84c47b55e048b5ec4.gi", - "/assets/3b032f024ccfb74d72f85e4872272b8d.gi", - "/assets/7bd5e8b383e7c21c273d3d5a0e3798ff.grp", - "/assets/573fa2e13db50f4ebcc31d8470bb060c.gi", - "/assets/a5691f7ac2a03c1f6d88f73721067425.g", - "/assets/81eed32f730faf16efe047eaf1832b56.grp", - "/assets/63780260ffca2e8f2d49fa23770aa47b.gi", - "/assets/76911cda94b64bd9624e7e36ecdfdfbb.gi", - "/assets/b3cb4ffc7ea75a7062083a7ec9a79f94.g", - "/assets/1c304acde8daf77202f7e9430d4722a1.gi", - "/assets/6b8005844b48026fd60263e0e67331b7.gi", - "/assets/3333e75f754a91c6d4df3f2b587e4321.gi", - "/assets/5020b43bb7396613f01bfdc5f1a121eb.gi", - "/assets/66598d78b7e0fff9d024f6059e032fc8.gi", - "/assets/7093cd2a4f40d87be5cab5d41d3c72e1.gi", - "/assets/fcc715bfd6e05aab58467af131fd58b3.gi", - "/assets/09893a06b2e11a35fda0383f78842802.gi", - "/assets/9ce8fd3103d326c010c9688fe64c9c95.gi", - "/assets/5c0647eca873d986e3a1209d97326f81.gi", - "/assets/ae0caccd85d65cc88b547ef4dcb213f8.gi", - "/assets/f5fb67f6572cacfb50adb898e2844a8c.gi", - "/assets/e14162c30eec5547280e76634270c8e9.gi", - "/assets/89091ed7ebe38612781f817a6f188ab9.gi", - "/assets/5a0f34c5fcc9a8d468ff03798dcf7cb6.g", - "/assets/da2c4dccf561bbb319fd964ba11cc9cb.gd", - "/assets/16abbecd77cf3878e46aed940cc15189.gd", - "/assets/eac4ecd2ed96fa097a6e2d9400336ea1.gd", - "/assets/3816965c559e78bbbeecf68e8d6bb139.gd", - "/assets/e42f816f67bad57597999a9c790c2198.g", - "/assets/a75ad79fd5df0c7af2e557e5107cedfa.gi", - "/assets/ecfcb558ccf63586b5dbaa6078879aca.g", - "/assets/6c315cca1d428341fc898c7267e5e528.gi", - "/assets/df717ea416addb3c99ec379fbb6c651d.gi", - "/assets/c7f884e90cddbd44daafc747514212a1.gi", - "/assets/738c6b0c3d39a610cb58e30b5e9485f8.gi" -] \ No newline at end of file From 9aa5ac56a05c6017f75a0f31c004a394d6f88942 Mon Sep 17 00:00:00 2001 From: Yanshu Wang Date: Thu, 19 Mar 2026 18:08:00 +0800 Subject: [PATCH 173/234] rename variable in percentage_encoding.py for readability and fix path encoding issue --- etc/emscripten/README.md | 10 +---- etc/emscripten/build_manual_manifest.js | 52 ------------------------ etc/emscripten/build_startup_manifest.js | 27 ++++++++---- etc/emscripten/percentage_encoding.py | 39 ++++++++++-------- 4 files changed, 41 insertions(+), 87 deletions(-) delete mode 100644 etc/emscripten/build_manual_manifest.js diff --git a/etc/emscripten/README.md b/etc/emscripten/README.md index f828866a80..5946302efe 100644 --- a/etc/emscripten/README.md +++ b/etc/emscripten/README.md @@ -8,8 +8,6 @@ Files: - `build_startup_manifest.js`: Run it in the web root directory to build `startup_manifest.json` that contains resources to preload. -- `build_manual_manifest.js`: Run it in the web root directory to build `manual_manifest.json` that contains all `.six` files to preload. - See 'run-web-demo.sh' as an example on how to set up a working website. Note that this demo uses xterm-pty, a library which provides a terminal interface @@ -25,10 +23,4 @@ For more details, see for [this article](https://developer.mozilla.org/en-US/doc The file "coi-serviceworker.js" works around this problem on Github pages. This won't work locally, so "server.rb" is a simple ruby script, which just starts a web-server -which returns the required headers. - -You can combine `startup_manifest.json` and `manual_manifest.json` using the command: -``` -jq -s 'add | unique' startup_manifest.json manual_manifest.json > temp_manifest.json -mv temp_manifest.json startup_manifest.json -``` \ No newline at end of file +which returns the required headers. \ No newline at end of file diff --git a/etc/emscripten/build_manual_manifest.js b/etc/emscripten/build_manual_manifest.js deleted file mode 100644 index b4a951dbd4..0000000000 --- a/etc/emscripten/build_manual_manifest.js +++ /dev/null @@ -1,52 +0,0 @@ -#!/usr/bin/env node -"use strict"; - -const fs = require('fs'); -const path = require('path'); - -const BASE_DIR = process.cwd(); -const ASSETS_DIR = path.join(BASE_DIR, 'assets'); -const OUTPUT_FILE = path.join(BASE_DIR, 'manual_manifest.json'); - -function findSixFiles(dir, fileList = []) { - const items = fs.readdirSync(dir); - - for (const item of items) { - const itemPath = path.join(dir, item); - const stat = fs.statSync(itemPath); - - if (stat.isDirectory()) { - findSixFiles(itemPath, fileList); - } else if (stat.isFile() && item.endsWith('.six')) { - const relativePath = path.relative(BASE_DIR, itemPath); - - fileList.push(`/${relativePath}`); - } - } - - return fileList; -} - -function main() { - if (!fs.existsSync(ASSETS_DIR)) { - console.error(`Error: Could not find 'assets' directory at ${ASSETS_DIR}`); - process.exit(1); - } - - try { - console.log(`Scanning for .six files in: ${ASSETS_DIR}...`); - - const sixFiles = findSixFiles(ASSETS_DIR); - - fs.writeFileSync(OUTPUT_FILE, JSON.stringify(sixFiles, null, 4)); - - console.log(`\nSuccess! Found ${sixFiles.length} files.`); - console.log(`Wrote manifest to: ${OUTPUT_FILE}`); - - } catch (err) { - console.error("Failed to generate manifest:", err); - process.exit(1); - } -} - -main(); \ No newline at end of file diff --git a/etc/emscripten/build_startup_manifest.js b/etc/emscripten/build_startup_manifest.js index 18ca176b02..5edfcc1d51 100644 --- a/etc/emscripten/build_startup_manifest.js +++ b/etc/emscripten/build_startup_manifest.js @@ -18,29 +18,40 @@ const server = http.createServer((req, res) => { urlPath = '/index.html'; } - const filePath = path.join(BASE_DIR, urlPath); + let localDiskPath = urlPath; + try { + localDiskPath = decodeURIComponent(urlPath); + } catch (e) {} + + const filePath = path.join(BASE_DIR, localDiskPath); fs.readFile(filePath, (err, data) => { if (err) { - console.error(`[404] Ignored missing file: ${urlPath}`); + console.error(`[404] Ignored missing file: ${localDiskPath}`); res.writeHead(404); res.end(`404: File not found`); return; } - if (urlPath !== '/favicon.ico' && !requestedFiles.has(urlPath)) { - requestedFiles.add(urlPath); - - const manifest = Array.from(requestedFiles); - fs.writeFileSync(LOG_FILE, JSON.stringify(manifest, null, 4)); + const ignored = ['/favicon.ico', '/index.html', '/lazy_fs.js', '/startup_manifest.json']; + if (!ignored.includes(urlPath)) { + let manifestPath = urlPath.startsWith('/') ? urlPath.substring(1) : urlPath; - console.log(`[Loaded & Logged] ${urlPath} (Total: ${requestedFiles.size})`); + if (!requestedFiles.has(manifestPath)) { + requestedFiles.add(manifestPath); + + const manifest = Array.from(requestedFiles); + fs.writeFileSync(LOG_FILE, JSON.stringify(manifest, null, 4)); + + console.log(`[Loaded & Logged] ${manifestPath} (Total: ${requestedFiles.size})`); + } } let contentType = 'application/octet-stream'; if (urlPath.endsWith('.html')) contentType = 'text/html'; else if (urlPath.endsWith('.js')) contentType = 'text/javascript'; else if (urlPath.endsWith('.wasm')) contentType = 'application/wasm'; + else if (urlPath.endsWith('.css')) contentType = 'text/css'; res.writeHead(200, { 'Content-Type': contentType, diff --git a/etc/emscripten/percentage_encoding.py b/etc/emscripten/percentage_encoding.py index 9a252c911a..3de875c652 100644 --- a/etc/emscripten/percentage_encoding.py +++ b/etc/emscripten/percentage_encoding.py @@ -30,8 +30,8 @@ def main(): f.write(' var physicalDir = "assets/";\n') f.write(" var createdDirs = {};\n") - f.write(" Object.keys(fileMap).forEach(function(virtualPath) {\n") - f.write(" var parts = virtualPath.split('/');\n") + f.write(" Object.keys(fileMap).forEach(function(appPath) {\n") + f.write(" var parts = appPath.split('/');\n") f.write(" parts.pop();\n") f.write(" var parentDir = '/' + parts.join('/');\n") f.write(" if (!createdDirs[parentDir]) {\n") @@ -46,8 +46,8 @@ def main(): f.write(" FS.syncfs(true, async function(err) {\n") - f.write(" Object.keys(fileMap).forEach(function(virtualPath) {\n") - f.write(" var parts = virtualPath.split('/');\n") + f.write(" Object.keys(fileMap).forEach(function(appPath) {\n") + f.write(" var parts = appPath.split('/');\n") f.write(" parts.pop();\n") f.write(" var parentDir = '/' + parts.join('/');\n") f.write(" try { FS.mkdirTree('/gap_idb_cache' + parentDir); } catch(e) {}\n") @@ -55,7 +55,7 @@ def main(): f.write(" var needsSave = false;\n") f.write(" var startupSet = new Set();\n") - + f.write(" try {\n") f.write(" const manifestRes = await fetch('startup_manifest.json');\n") f.write(" if (manifestRes.ok) {\n") @@ -67,34 +67,37 @@ def main(): f.write(" }\n") f.write(" } catch (e) {}\n\n") - f.write(" var fetchPromises = Object.keys(fileMap).map(async function(virtualPath) {\n") - f.write(" var physicalName = fileMap[virtualPath];\n") + f.write(" var fetchPromises = Object.keys(fileMap).map(async function(appPath) {\n") + f.write(" var fetchRelativePath = fileMap[appPath];\n") - f.write(" var physicalPath = physicalDir + physicalName;\n") - f.write(" var cachePath = '/gap_idb_cache/' + physicalName;\n") - f.write(" var finalPath = '/' + virtualPath;\n\n") + f.write(" var fetchPath = physicalDir + fetchRelativePath;\n") + f.write(" var idbfsPath = '/gap_idb_cache/' + appPath;\n") + f.write(" var finalAppPath = '/' + appPath;\n\n") - f.write(" if (startupSet.has(physicalDir + virtualPath)) {\n") + # For example, if appPath is "pkg/jupyterviz/examples/EV Charge Points.json", + # then fetchPath is "pkg/jupyterviz/examples/EV%2520Charge%2520Points.json" + + f.write(" if (startupSet.has(fetchPath)) {\n") f.write(" try {\n") - f.write(" FS.stat(cachePath);\n") - f.write(" FS.writeFile(finalPath, FS.readFile(cachePath));\n") + f.write(" FS.stat(idbfsPath);\n") + f.write(" FS.writeFile(finalAppPath, FS.readFile(idbfsPath));\n") f.write(" } catch (e) {\n") f.write(" try {\n") - f.write(" const response = await fetch(physicalPath);\n") + f.write(" const response = await fetch(fetchPath);\n") f.write(" if (response.ok) {\n") f.write(" const buffer = await response.arrayBuffer();\n") f.write(" const data = new Uint8Array(buffer);\n") - f.write(" FS.writeFile(finalPath, data);\n") - f.write(" FS.writeFile(cachePath, data);\n") + f.write(" FS.writeFile(finalAppPath, data);\n") + f.write(" FS.writeFile(idbfsPath, data);\n") f.write(" needsSave = true;\n") f.write(" }\n") f.write(" } catch (fetchErr) {}\n") f.write(" }\n") f.write(" } else {\n") - f.write(" var parts = virtualPath.split('/');\n") + f.write(" var parts = appPath.split('/');\n") f.write(" var fileName = parts.pop();\n") f.write(" var parentDir = '/' + parts.join('/');\n") - f.write(" FS.createLazyFile(parentDir, fileName, physicalPath, true, false);\n") + f.write(" FS.createLazyFile(parentDir, fileName, fetchPath, true, false);\n") f.write(" }\n") f.write(" });\n\n") From 6853c5d747a0bf37c9a0137b84143eac392746ba Mon Sep 17 00:00:00 2001 From: Yanshu Wang Date: Tue, 31 Mar 2026 10:15:39 +0800 Subject: [PATCH 174/234] remove double percentage encoding; separate gap-fs.js and gap-fs.json --- etc/emscripten/build.sh | 6 +- etc/emscripten/build_startup_manifest.js | 6 +- etc/emscripten/copy_encoded_assets.py | 30 ------ etc/emscripten/generate_gap_fs_json.py | 18 ++++ etc/emscripten/percentage_encoding.py | 122 ---------------------- etc/emscripten/run-web-demo.sh | 12 +-- etc/emscripten/web-template/gap-fs.js | 97 +++++++++++++++++ etc/emscripten/web-template/gap-worker.js | 1 + 8 files changed, 125 insertions(+), 167 deletions(-) mode change 100644 => 100755 etc/emscripten/build_startup_manifest.js delete mode 100644 etc/emscripten/copy_encoded_assets.py create mode 100755 etc/emscripten/generate_gap_fs_json.py delete mode 100644 etc/emscripten/percentage_encoding.py create mode 100644 etc/emscripten/web-template/gap-fs.js diff --git a/etc/emscripten/build.sh b/etc/emscripten/build.sh index ded1cfffdf..4920dfb2c4 100755 --- a/etc/emscripten/build.sh +++ b/etc/emscripten/build.sh @@ -91,13 +91,13 @@ cp native-build/build/c_*.c native-build/build/ffdata.* src/ # Dynamically find and append ALL required files to the JS array # The flag -type f is safe because the only symbolic link is 'tst/mockpkg/Makefile.gappkg', # which is safe to ignore -find pkg lib grp tst doc hpcgap dev benchmark -type f | python3 etc/emscripten/percentage_encoding.py +find pkg lib grp tst doc hpcgap dev benchmark -type f | python3 etc/emscripten/generate_gap_fs_json.py if [ $? -ne 0 ]; then - echo "Build aborted: generate_mapping.py failed." + echo "Build aborted: generate_gap_fs_json.py failed." exit 1 fi # The EXEEXT is usually for windows, but here it lets us set GAP's extension, # which lets us produce a html page to run GAP in. -emmake make -j8 LDFLAGS="-lidbfs.js --pre-js lazy_fs.js -s ASYNCIFY=1 -sTOTAL_STACK=32mb -sASYNCIFY_STACK_SIZE=32000000 -sINITIAL_MEMORY=2048mb -O2" EXEEXT=".html" \ No newline at end of file +emmake make -j8 LDFLAGS="-lidbfs.js -s ASYNCIFY=1 -sTOTAL_STACK=32mb -sASYNCIFY_STACK_SIZE=32000000 -sINITIAL_MEMORY=2048mb -O2" EXEEXT=".html" \ No newline at end of file diff --git a/etc/emscripten/build_startup_manifest.js b/etc/emscripten/build_startup_manifest.js old mode 100644 new mode 100755 index 5edfcc1d51..746b548c31 --- a/etc/emscripten/build_startup_manifest.js +++ b/etc/emscripten/build_startup_manifest.js @@ -33,9 +33,9 @@ const server = http.createServer((req, res) => { return; } - const ignored = ['/favicon.ico', '/index.html', '/lazy_fs.js', '/startup_manifest.json']; - if (!ignored.includes(urlPath)) { - let manifestPath = urlPath.startsWith('/') ? urlPath.substring(1) : urlPath; + const ignored = ['/favicon.ico', '/index.html', '/startup_manifest.json', 'coi-serviceworker.js', 'gap-worker.js', 'gap-fs.js', 'gap.js', 'gap.wasm', 'gap-fs.json']; + if (!ignored.includes(localDiskPath)) { + let manifestPath = localDiskPath.startsWith('/') ? localDiskPath.substring(1) : localDiskPath; if (!requestedFiles.has(manifestPath)) { requestedFiles.add(manifestPath); diff --git a/etc/emscripten/copy_encoded_assets.py b/etc/emscripten/copy_encoded_assets.py deleted file mode 100644 index be29f39f13..0000000000 --- a/etc/emscripten/copy_encoded_assets.py +++ /dev/null @@ -1,30 +0,0 @@ -import sys -import urllib.parse -import os -import shutil - -def main(): - - dest_dir = sys.argv[1] - os.makedirs(dest_dir, exist_ok=True) - - copied_count = 0 - - for line in sys.stdin: - path = line.strip() - if not path: - continue - - encoded_name = urllib.parse.quote(path, safe='/') - - dest_path = os.path.join(dest_dir, encoded_name) - - os.makedirs(os.path.dirname(dest_path), exist_ok=True) - - shutil.copy2(path, dest_path) - copied_count += 1 - - print(f"Successfully copied {copied_count} files into {dest_dir}", file=sys.stderr) - -if __name__ == "__main__": - main() \ No newline at end of file diff --git a/etc/emscripten/generate_gap_fs_json.py b/etc/emscripten/generate_gap_fs_json.py new file mode 100755 index 0000000000..92686371d9 --- /dev/null +++ b/etc/emscripten/generate_gap_fs_json.py @@ -0,0 +1,18 @@ +import sys +import json +import os + +def main(): + paths = [line.strip() for line in sys.stdin if line.strip()] + + try: + with open('gap-fs.json', 'w', encoding='utf-8') as f: + json.dump(paths, f, separators=(',', ':')) + + print(f"Successfully wrote {len(paths)} files to gap-fs.json", file=sys.stderr) + except Exception as e: + print(f"Failed to write gap-fs.json: {e}", file=sys.stderr) + sys.exit(1) + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/etc/emscripten/percentage_encoding.py b/etc/emscripten/percentage_encoding.py deleted file mode 100644 index 3de875c652..0000000000 --- a/etc/emscripten/percentage_encoding.py +++ /dev/null @@ -1,122 +0,0 @@ -import sys -import urllib.parse -import os - -def main(): - mappings = [] - - for line in sys.stdin: - path = line.strip() - if not path: - continue - - encoded_name = urllib.parse.quote(path, safe='/') - - fetch_name = encoded_name.replace('%', '%25') - - mappings.append((path, fetch_name)) - - try: - with open('lazy_fs.js', 'w', encoding='utf-8') as f: - f.write("Module.preRun = Module.preRun || [];\n") - f.write("Module.preRun.push(function() {\n") - f.write(" var fileMap = {\n") - - for path, fetch_name in mappings: - safe_path = path.replace('"', '\\"') - f.write(f' "{safe_path}": "{fetch_name}",\n') - - f.write(" };\n\n") - f.write(' var physicalDir = "assets/";\n') - - f.write(" var createdDirs = {};\n") - f.write(" Object.keys(fileMap).forEach(function(appPath) {\n") - f.write(" var parts = appPath.split('/');\n") - f.write(" parts.pop();\n") - f.write(" var parentDir = '/' + parts.join('/');\n") - f.write(" if (!createdDirs[parentDir]) {\n") - f.write(" try { FS.mkdirTree(parentDir); } catch(e) {}\n") - f.write(" createdDirs[parentDir] = true;\n") - f.write(" }\n") - f.write(" });\n\n") - - f.write(" try { FS.mkdirTree('/gap_idb_cache'); } catch(e) {}\n") - f.write(" FS.mount(IDBFS, {}, '/gap_idb_cache');\n") - f.write(" addRunDependency('idbfs_sync');\n\n") - - f.write(" FS.syncfs(true, async function(err) {\n") - - f.write(" Object.keys(fileMap).forEach(function(appPath) {\n") - f.write(" var parts = appPath.split('/');\n") - f.write(" parts.pop();\n") - f.write(" var parentDir = '/' + parts.join('/');\n") - f.write(" try { FS.mkdirTree('/gap_idb_cache' + parentDir); } catch(e) {}\n") - f.write(" });\n\n") - - f.write(" var needsSave = false;\n") - f.write(" var startupSet = new Set();\n") - - f.write(" try {\n") - f.write(" const manifestRes = await fetch('startup_manifest.json');\n") - f.write(" if (manifestRes.ok) {\n") - f.write(" const manifest = await manifestRes.json();\n") - f.write(" manifest.forEach(p => {\n") - f.write(" if (p.startsWith('/')) p = p.substring(1);\n") - f.write(" startupSet.add(p);\n") - f.write(" });\n") - f.write(" }\n") - f.write(" } catch (e) {}\n\n") - - f.write(" var fetchPromises = Object.keys(fileMap).map(async function(appPath) {\n") - f.write(" var fetchRelativePath = fileMap[appPath];\n") - - f.write(" var fetchPath = physicalDir + fetchRelativePath;\n") - f.write(" var idbfsPath = '/gap_idb_cache/' + appPath;\n") - f.write(" var finalAppPath = '/' + appPath;\n\n") - - # For example, if appPath is "pkg/jupyterviz/examples/EV Charge Points.json", - # then fetchPath is "pkg/jupyterviz/examples/EV%2520Charge%2520Points.json" - - f.write(" if (startupSet.has(fetchPath)) {\n") - f.write(" try {\n") - f.write(" FS.stat(idbfsPath);\n") - f.write(" FS.writeFile(finalAppPath, FS.readFile(idbfsPath));\n") - f.write(" } catch (e) {\n") - f.write(" try {\n") - f.write(" const response = await fetch(fetchPath);\n") - f.write(" if (response.ok) {\n") - f.write(" const buffer = await response.arrayBuffer();\n") - f.write(" const data = new Uint8Array(buffer);\n") - f.write(" FS.writeFile(finalAppPath, data);\n") - f.write(" FS.writeFile(idbfsPath, data);\n") - f.write(" needsSave = true;\n") - f.write(" }\n") - f.write(" } catch (fetchErr) {}\n") - f.write(" }\n") - f.write(" } else {\n") - f.write(" var parts = appPath.split('/');\n") - f.write(" var fileName = parts.pop();\n") - f.write(" var parentDir = '/' + parts.join('/');\n") - f.write(" FS.createLazyFile(parentDir, fileName, fetchPath, true, false);\n") - f.write(" }\n") - f.write(" });\n\n") - - f.write(" await Promise.all(fetchPromises);\n") - f.write(" if (needsSave) {\n") - f.write(" FS.syncfs(false, function(saveErr) {\n") - f.write(" removeRunDependency('idbfs_sync');\n") - f.write(" });\n") - f.write(" } else {\n") - f.write(" removeRunDependency('idbfs_sync');\n") - f.write(" }\n") - f.write(" });\n") - f.write("});\n") - - print(f"Successfully encoded {len(mappings)} files into lazy_fs.js", file=sys.stderr) - - except Exception as e: - print(f"Failed to write lazy_fs.js: {e}", file=sys.stderr) - sys.exit(1) - -if __name__ == "__main__": - main() \ No newline at end of file diff --git a/etc/emscripten/run-web-demo.sh b/etc/emscripten/run-web-demo.sh index 607b4adc22..a82eb948a9 100755 --- a/etc/emscripten/run-web-demo.sh +++ b/etc/emscripten/run-web-demo.sh @@ -4,16 +4,10 @@ set -eux echo This script assumes you have already run 'build.sh' -mkdir -p web-example/assets +mkdir -p web-example cp etc/emscripten/web-template/* web-example/ -cp gap.js gap.wasm gap.worker.js web-example/ - -find pkg lib grp tst doc hpcgap dev benchmark -type f | python3 etc/emscripten/copy_encoded_assets.py web-example/assets - -if [ $? -ne 0 ]; then - echo "Copying failed." - exit 1 -fi +cp gap.js gap.wasm gap.worker.js gap-fs.json web-example/ +cp -r pkg lib grp tst doc hpcgap dev benchmark web-example/ cd web-example ../etc/emscripten/server.rb diff --git a/etc/emscripten/web-template/gap-fs.js b/etc/emscripten/web-template/gap-fs.js new file mode 100644 index 0000000000..a2d76bad40 --- /dev/null +++ b/etc/emscripten/web-template/gap-fs.js @@ -0,0 +1,97 @@ +self.Module = self.Module || {}; +self.Module.preRun = self.Module.preRun || []; + +self.Module.preRun.push(function() { + addRunDependency('gap_fs_init'); + + async function initFS() { + try { + const mapRes = await fetch('gap-fs.json'); + const fileList = await mapRes.json(); + const physicalDir = ""; + + var createdDirs = {}; + fileList.forEach(function(appPath) { + var parts = appPath.split('/'); + parts.pop(); + var parentDir = '/' + parts.join('/'); + if (!createdDirs[parentDir]) { + try { FS.mkdirTree(parentDir); } catch(e) {} + createdDirs[parentDir] = true; + } + }); + + try { FS.mkdirTree('/gap_idb_cache'); } catch(e) {} + FS.mount(IDBFS, {}, '/gap_idb_cache'); + + FS.syncfs(true, async function(err) { + fileList.forEach(function(appPath) { + var parts = appPath.split('/'); + parts.pop(); + var parentDir = '/' + parts.join('/'); + try { FS.mkdirTree('/gap_idb_cache' + parentDir); } catch(e) {} + }); + + var needsSave = false; + var startupSet = new Set(); + + try { + const manifestRes = await fetch('startup_manifest.json'); + if (manifestRes.ok) { + const manifest = await manifestRes.json(); + manifest.forEach(p => { + if (p.startsWith('/')) p = p.substring(1); + startupSet.add(p); + }); + } + } catch (e) {} + + var fetchPromises = fileList.map(async function(appPath) { + var fetchRelativePath = appPath.split('/').map(encodeURIComponent).join('/'); + var fetchPath = physicalDir + fetchRelativePath; + + var idbfsPath = '/gap_idb_cache/' + appPath; + var finalAppPath = '/' + appPath; + + if (startupSet.has(appPath)) { + try { + FS.stat(idbfsPath); + FS.writeFile(finalAppPath, FS.readFile(idbfsPath)); + } catch (e) { + try { + const response = await fetch(fetchPath); + if (response.ok) { + const buffer = await response.arrayBuffer(); + const data = new Uint8Array(buffer); + FS.writeFile(finalAppPath, data); + FS.writeFile(idbfsPath, data); + needsSave = true; + } + } catch (fetchErr) {} + } + } else { + var parts = appPath.split('/'); + var fileName = parts.pop(); + var parentDir = '/' + parts.join('/'); + FS.createLazyFile(parentDir, fileName, fetchPath, true, false); + } + }); + + await Promise.all(fetchPromises); + + if (needsSave) { + FS.syncfs(false, function(saveErr) { + removeRunDependency('gap_fs_init'); + }); + } else { + removeRunDependency('gap_fs_init'); + } + }); + } catch(err) { + console.error("Failed to initialize GAP FS:", err); + removeRunDependency('gap_fs_init'); + } + } + + initFS(); +}); \ No newline at end of file diff --git a/etc/emscripten/web-template/gap-worker.js b/etc/emscripten/web-template/gap-worker.js index 0eec06cafc..9fe8a87cad 100755 --- a/etc/emscripten/web-template/gap-worker.js +++ b/etc/emscripten/web-template/gap-worker.js @@ -3,6 +3,7 @@ importScripts("https://cdn.jsdelivr.net/npm/xterm-pty@0.9.4/workerTools.js"); onmessage = (msg) => { // Prepare the Module object BEFORE importing gap.js self.Module = self.Module || {}; + importScripts("gap-fs.js"); importScripts("gap.js"); emscriptenHack(new TtyClient(msg.data)); }; \ No newline at end of file From 55b1d5619bef0bd344cbcd08d2dfd25122d6f482 Mon Sep 17 00:00:00 2001 From: wangyenshu <155622798+wangyenshu@users.noreply.github.com> Date: Sat, 18 Apr 2026 22:43:38 +0800 Subject: [PATCH 175/234] Update etc/emscripten/web-template/index.html Files should end with a trailing newline Co-authored-by: Max Horn --- etc/emscripten/web-template/index.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/etc/emscripten/web-template/index.html b/etc/emscripten/web-template/index.html index 2e7290ae01..b51df45fb8 100755 --- a/etc/emscripten/web-template/index.html +++ b/etc/emscripten/web-template/index.html @@ -19,4 +19,4 @@ new TtyServer(slave).start(worker); - \ No newline at end of file + From 31e8dc7f19dc980848de534b77139d83e5646791 Mon Sep 17 00:00:00 2001 From: wangyenshu <155622798+wangyenshu@users.noreply.github.com> Date: Sat, 18 Apr 2026 22:44:32 +0800 Subject: [PATCH 176/234] Update etc/emscripten/web-template/gap-worker.js Files should end with a trailing newline Co-authored-by: Max Horn --- etc/emscripten/web-template/gap-worker.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/etc/emscripten/web-template/gap-worker.js b/etc/emscripten/web-template/gap-worker.js index 9fe8a87cad..9b71069a9f 100755 --- a/etc/emscripten/web-template/gap-worker.js +++ b/etc/emscripten/web-template/gap-worker.js @@ -6,4 +6,4 @@ onmessage = (msg) => { importScripts("gap-fs.js"); importScripts("gap.js"); emscriptenHack(new TtyClient(msg.data)); -}; \ No newline at end of file +}; From 11dffb592b76bcb14b1f818d18d681caddbd4795 Mon Sep 17 00:00:00 2001 From: wangyenshu <155622798+wangyenshu@users.noreply.github.com> Date: Sat, 18 Apr 2026 22:45:02 +0800 Subject: [PATCH 177/234] Update etc/emscripten/web-template/gap-fs.js Files should end with a trailing newline Co-authored-by: Max Horn --- etc/emscripten/web-template/gap-fs.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/etc/emscripten/web-template/gap-fs.js b/etc/emscripten/web-template/gap-fs.js index a2d76bad40..f3a1467d42 100644 --- a/etc/emscripten/web-template/gap-fs.js +++ b/etc/emscripten/web-template/gap-fs.js @@ -94,4 +94,4 @@ self.Module.preRun.push(function() { } initFS(); -}); \ No newline at end of file +}); From f334361b4b6a7aa6325ae24c21f221b2d6d47cc5 Mon Sep 17 00:00:00 2001 From: wangyenshu <155622798+wangyenshu@users.noreply.github.com> Date: Sat, 18 Apr 2026 22:45:30 +0800 Subject: [PATCH 178/234] Update etc/emscripten/build.sh Files should end with a trailing newline Co-authored-by: Max Horn --- etc/emscripten/build.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/etc/emscripten/build.sh b/etc/emscripten/build.sh index 4920dfb2c4..a79a843380 100755 --- a/etc/emscripten/build.sh +++ b/etc/emscripten/build.sh @@ -100,4 +100,4 @@ fi # The EXEEXT is usually for windows, but here it lets us set GAP's extension, # which lets us produce a html page to run GAP in. -emmake make -j8 LDFLAGS="-lidbfs.js -s ASYNCIFY=1 -sTOTAL_STACK=32mb -sASYNCIFY_STACK_SIZE=32000000 -sINITIAL_MEMORY=2048mb -O2" EXEEXT=".html" \ No newline at end of file +emmake make -j8 LDFLAGS="-lidbfs.js -s ASYNCIFY=1 -sTOTAL_STACK=32mb -sASYNCIFY_STACK_SIZE=32000000 -sINITIAL_MEMORY=2048mb -O2" EXEEXT=".html" From fcf460d3ab1e215623c32c8cc5be4d092c9a3896 Mon Sep 17 00:00:00 2001 From: wangyenshu <155622798+wangyenshu@users.noreply.github.com> Date: Sat, 18 Apr 2026 22:45:43 +0800 Subject: [PATCH 179/234] Update etc/emscripten/build_startup_manifest.js Files should end with a trailing newline Co-authored-by: Max Horn --- etc/emscripten/build_startup_manifest.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/etc/emscripten/build_startup_manifest.js b/etc/emscripten/build_startup_manifest.js index 746b548c31..edb8594b10 100755 --- a/etc/emscripten/build_startup_manifest.js +++ b/etc/emscripten/build_startup_manifest.js @@ -68,4 +68,4 @@ server.listen(PORT, '0.0.0.0', () => { console.log(`\n Tracker running at http://localhost:${PORT}/`); console.log(`Serving files from: ${BASE_DIR}`); console.log(`Logging valid loaded files to: ${LOG_FILE}\n`); -}); \ No newline at end of file +}); From b0f97bcdeac71882580b467524bfc440c9976e17 Mon Sep 17 00:00:00 2001 From: wangyenshu <155622798+wangyenshu@users.noreply.github.com> Date: Sat, 18 Apr 2026 22:45:54 +0800 Subject: [PATCH 180/234] Update etc/emscripten/generate_gap_fs_json.py Files should end with a trailing newline Co-authored-by: Max Horn --- etc/emscripten/generate_gap_fs_json.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/etc/emscripten/generate_gap_fs_json.py b/etc/emscripten/generate_gap_fs_json.py index 92686371d9..dbf5447bba 100755 --- a/etc/emscripten/generate_gap_fs_json.py +++ b/etc/emscripten/generate_gap_fs_json.py @@ -15,4 +15,4 @@ def main(): sys.exit(1) if __name__ == "__main__": - main() \ No newline at end of file + main() From b4557eb26a771798a1d44a4ccfec767c3355b59f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 20 Apr 2026 09:16:30 +0200 Subject: [PATCH 181/234] build(deps): bump actions/upload-pages-artifact from 4 to 5 (#6336) Bumps [actions/upload-pages-artifact](https://github.com/actions/upload-pages-artifact) from 4 to 5. - [Release notes](https://github.com/actions/upload-pages-artifact/releases) - [Commits](https://github.com/actions/upload-pages-artifact/compare/v4...v5) --- updated-dependencies: - dependency-name: actions/upload-pages-artifact dependency-version: '5' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/update-gh-pages.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/update-gh-pages.yml b/.github/workflows/update-gh-pages.yml index 0029894b91..e1ebb2c57b 100644 --- a/.github/workflows/update-gh-pages.yml +++ b/.github/workflows/update-gh-pages.yml @@ -67,7 +67,7 @@ jobs: mv doc/dev/bigpic.* public/doc/dev/ cp dev/index.html public/ - name: Upload artifact - uses: actions/upload-pages-artifact@v4 + uses: actions/upload-pages-artifact@v5 with: path: ./public From 98fdfa3f4ce1f82d6a3ef23b41c51fe7ea1f35da Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 20 Apr 2026 08:42:07 +0000 Subject: [PATCH 182/234] build(deps): bump julia-actions/setup-julia from 2 to 3 (#6335) Bumps [julia-actions/setup-julia](https://github.com/julia-actions/setup-julia) from 2 to 3. - [Release notes](https://github.com/julia-actions/setup-julia/releases) - [Commits](https://github.com/julia-actions/setup-julia/compare/v2...v3) --- updated-dependencies: - dependency-name: julia-actions/setup-julia dependency-version: '3' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/gapjl.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/gapjl.yml b/.github/workflows/gapjl.yml index f7ff5e2675..5e3a5ae291 100644 --- a/.github/workflows/gapjl.yml +++ b/.github/workflows/gapjl.yml @@ -48,7 +48,7 @@ jobs: with: path: 'GAPROOT' - name: "Set up Julia" - uses: julia-actions/setup-julia@v2 + uses: julia-actions/setup-julia@v3 with: version: ${{ matrix.julia-version }} - name: Install GAP.jl From a522732d6f4d2e1c3358468e4ac9c6b35569cb01 Mon Sep 17 00:00:00 2001 From: Max Horn Date: Mon, 20 Apr 2026 16:06:39 +0200 Subject: [PATCH 183/234] Improve CosetLeadersMatFFE documentation (#6338) Codex wrote most of this and I edited it. Co-authored-by: Codex --- lib/listcoef.gd | 31 ++++++++++++++++++++++++------- 1 file changed, 24 insertions(+), 7 deletions(-) diff --git a/lib/listcoef.gd b/lib/listcoef.gd index a97e54b8f6..c682bfd9f4 100644 --- a/lib/listcoef.gd +++ b/lib/listcoef.gd @@ -684,13 +684,30 @@ DeclareOperation("AClosestVectorCombinationsMatFFEVecFFECoords", ## ## ## -## returns a list of representatives of minimal weight for the cosets of a -## code. -## mat must be a check matrix for the code, -## the code is defined over the finite field f. -## All rows of mat must have the same length, and all elements must -## lie in the field f. -## The rows of mat must be linearly independent. +## Let C be the linear code over f with check matrix +## mat, that is, C is the right null space of mat: +## +## C = \{ v \mid mat \cdot v = 0 \}. +## +## For each syndrome s, the solutions of the non-homogeneous system +## mat * v = s form one coset of C. Equivalently, two vectors +## lie in the same coset if their difference lies in C, just as in +## group theory. +##

+## returns, for each coset of C, a +## vector of smallest Hamming weight in that coset. Such a vector is called +## a coset leader. +##

+## If L := CosetLeadersMatFFE( mat, f ) and +## q := Size( f ), then L[i] is the coset leader whose +## syndrome is the vector with number i-1; in other words, +## NumberFFVector( mat * L[i], q ) = i - 1 +## for all valid indices i. +##

+## Thus the list is indexed by syndromes, not by codewords. +##

+## All rows of mat must have the same length, all entries must lie in +## f, and the rows of mat must be linearly independent. ## ## ## <#/GAPDoc> From c70de2a1cada44a353a652c0307cc8232b507c25 Mon Sep 17 00:00:00 2001 From: Max Horn Date: Mon, 20 Apr 2026 22:29:56 +0200 Subject: [PATCH 184/234] Allow 'shifting' ranges (#6334) So far adding an integer to a range produced a plain list. Add a kernel method to ensure this again produces a range, if possible. If not, fall back to the current behavior. AI-assisted with Codex for the kernel change and tests. Co-authored-by: Codex --- src/range.c | 51 ++++++++++++++++++++++++++++++++ tst/testinstall/kernel/range.tst | 48 ++++++++++++++++++++++++++++++ 2 files changed, 99 insertions(+) diff --git a/src/range.c b/src/range.c index 3c80522a0b..7ae0c93305 100644 --- a/src/range.c +++ b/src/range.c @@ -56,6 +56,8 @@ #include "error.h" #include "gaputils.h" #include "io.h" +#include "integer.h" +#include "listoper.h" #include "lists.h" #include "modules.h" #include "opers.h" @@ -818,6 +820,45 @@ Obj Range3Check ( } +/**************************************************************************** +** +*F ShiftRange( , ) +** +** 'ShiftRange' preserves the range representation when shifting +** by the integer keeps both endpoints in the small integer range. +** Otherwise it falls back to the generic scalar/list implementation. +*/ +static Obj ShiftRange(Obj offset, Obj range) +{ + Obj low; + Obj high; + Obj shifted; + + low = SUM(offset, INTOBJ_INT(GET_LOW_RANGE(range))); + high = SUM(offset, GET_ELM_RANGE(range, GET_LEN_RANGE(range))); + if (!IS_INTOBJ(low) || !IS_INTOBJ(high)) { + return SumSclList(offset, range); + } + + shifted = NEW_RANGE(GET_LEN_RANGE(range), INT_INTOBJ(low), + GET_INC_RANGE(range)); + if (!IS_MUTABLE_OBJ(range)) { + MakeImmutableNoRecurse(shifted); + } + return shifted; +} + +static Obj SumIntRange(Obj opL, Obj opR) +{ + return ShiftRange(opL, opR); +} + +static Obj SumRangeInt(Obj opL, Obj opR) +{ + return ShiftRange(opR, opL); +} + + /**************************************************************************** ** *F * * * * * * * * * * * * * * GAP level functions * * * * * * * * * * * * * @@ -1178,6 +1219,16 @@ static Int InitKernel ( LtFuncs[ T_RANGE_SSORT ][ T_RANGE_NSORT ] = LtRange; LtFuncs[ T_RANGE_SSORT ][ T_RANGE_SSORT ] = LtRange; + SumFuncs[ T_INT ][ T_RANGE_NSORT ] = SumIntRange; + SumFuncs[ T_INT ][ T_RANGE_NSORT + IMMUTABLE ] = SumIntRange; + SumFuncs[ T_INT ][ T_RANGE_SSORT ] = SumIntRange; + SumFuncs[ T_INT ][ T_RANGE_SSORT + IMMUTABLE ] = SumIntRange; + + SumFuncs[ T_RANGE_NSORT ][ T_INT ] = SumRangeInt; + SumFuncs[ T_RANGE_NSORT + IMMUTABLE ][ T_INT ] = SumRangeInt; + SumFuncs[ T_RANGE_SSORT ][ T_INT ] = SumRangeInt; + SumFuncs[ T_RANGE_SSORT + IMMUTABLE ][ T_INT ] = SumRangeInt; + // install the list functions in the tables LenListFuncs [ T_RANGE_NSORT ] = LenRange; LenListFuncs [ T_RANGE_NSORT +IMMUTABLE ] = LenRange; diff --git a/tst/testinstall/kernel/range.tst b/tst/testinstall/kernel/range.tst index ce1b1b3a50..b713bfc4ed 100644 --- a/tst/testinstall/kernel/range.tst +++ b/tst/testinstall/kernel/range.tst @@ -12,6 +12,54 @@ gap> START_TEST("kernel/range.tst"); gap> TNAM_OBJ([1..10]{[]}); "empty plain list" +# +# SumRangeInt / SumIntRange +# +gap> r := 5 + [1..5]; +[ 6 .. 10 ] +gap> IsRangeRep(r); +true +gap> r := [1..5] + 5; +[ 6 .. 10 ] +gap> IsRangeRep(r); +true +gap> r := 5 + [1,3..9]; +[ 6, 8 .. 14 ] +gap> IsRangeRep(r); +true +gap> r := [1,3..9] + 5; +[ 6, 8 .. 14 ] +gap> IsRangeRep(r); +true +gap> r := 5 + [9,7..1]; +[ 14, 12 .. 6 ] +gap> IsRangeRep(r); +true +gap> r := [9,7..1] + 5; +[ 14, 12 .. 6 ] +gap> IsRangeRep(r); +true +gap> r := 1 + [INTOBJ_MAX-1..INTOBJ_MAX];; +gap> r = [INTOBJ_MAX, INTOBJ_MAX+1]; +true +gap> IsRangeRep(r); +false +gap> r := [INTOBJ_MAX-1..INTOBJ_MAX] + 1;; +gap> r = [INTOBJ_MAX, INTOBJ_MAX+1]; +true +gap> IsRangeRep(r); +false +gap> r := -1 + [-INTOBJ_MAX-1..-INTOBJ_MAX];; +gap> r = [-INTOBJ_MAX-2, -INTOBJ_MAX-1]; +true +gap> IsRangeRep(r); +false +gap> r := [-INTOBJ_MAX-1..-INTOBJ_MAX] + -1;; +gap> r = [-INTOBJ_MAX-2, -INTOBJ_MAX-1]; +true +gap> IsRangeRep(r); +false + # # UnbRange # From c1340c8605170e6e30d064ad452805039153a4d3 Mon Sep 17 00:00:00 2001 From: Max Horn Date: Tue, 21 Apr 2026 00:41:23 +0200 Subject: [PATCH 185/234] Re-enable Codecov comments but delay PR notifications (#6332) Switch Codecov to manual notifications and send them once after the coverage-uploading test matrix finishes. This avoids noisy intermediate PR comments and temporary dropped-coverage reports while uploads are still in flight. Co-authored-by: Codex --- .codecov.yml | 6 ++++-- .github/workflows/CI.yml | 12 ++++++++++++ 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/.codecov.yml b/.codecov.yml index a302704acc..32dc8a6220 100644 --- a/.codecov.yml +++ b/.codecov.yml @@ -1,3 +1,7 @@ +codecov: + notify: + manual_trigger: true # needed for codecov-notify CI step + coverage: precision: 2 round: down @@ -14,8 +18,6 @@ coverage: default: informational: true -comment: false - ignore: - "extern" - "hpcgap/extern" diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index 9a7626a9c1..ca0f05b997 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -280,6 +280,18 @@ jobs: with: token: ${{ secrets.CODECOV_TOKEN }} + codecov-notify: + name: Finalize Codecov notifications + runs-on: ubuntu-slim + needs: test + if: ${{ always() }} + + steps: + - name: "Send Codecov notifications" + uses: codecov/codecov-action@v6 + with: + token: ${{ secrets.CODECOV_TOKEN }} + run_command: send-notifications cross_compile: # The host should always be linux From 3c0ebc74c32331d319f430dae2fdbadbfde7c8c2 Mon Sep 17 00:00:00 2001 From: Max Horn Date: Wed, 22 Apr 2026 00:12:07 +0200 Subject: [PATCH 186/234] PlainListCopy for list not knowing they are small (#6333) --- src/lists.c | 3 ++- tst/testbugfix/2026-04-19-PlainListCopy.tst | 6 ++++++ tst/testinstall/list.tst | 8 ++++---- 3 files changed, 12 insertions(+), 5 deletions(-) create mode 100644 tst/testbugfix/2026-04-19-PlainListCopy.tst diff --git a/src/lists.c b/src/lists.c index bc1b4a7589..dc329b0966 100644 --- a/src/lists.c +++ b/src/lists.c @@ -1649,7 +1649,8 @@ Obj PLAIN_LIST_COPY(Obj list) Obj FuncPlainListCopy(Obj self, Obj list) { - RequireSmallList(SELF_NAME, list); + if (!IS_LIST(list)) + RequireArgument(SELF_NAME, list, "must be a list"); return PLAIN_LIST_COPY(list); } diff --git a/tst/testbugfix/2026-04-19-PlainListCopy.tst b/tst/testbugfix/2026-04-19-PlainListCopy.tst new file mode 100644 index 0000000000..9acb71775e --- /dev/null +++ b/tst/testbugfix/2026-04-19-PlainListCopy.tst @@ -0,0 +1,6 @@ +# Fix PlainListCopy for lists which are small but do not know it yet know they +# are in filter `IsSmallList`; this is e.g. needed for the semigroups test +# suite +gap> l:=RightTransversal(Group([ (1,2) ]),Group([ () ]));; +gap> PlainListCopy(l); +[ (), (1,2) ] diff --git a/tst/testinstall/list.tst b/tst/testinstall/list.tst index 65a8e0fcd7..f4742a9834 100644 --- a/tst/testinstall/list.tst +++ b/tst/testinstall/list.tst @@ -336,15 +336,15 @@ true gap> checkPlainListCopy(NewZeroVector(Is8BitVectorRep, GF(3), 10)); true gap> PlainListCopy(6); -Error, PlainListCopy: must be a small list (not the integer 6) +Error, PlainListCopy: must be a list (not the integer 6) gap> PlainListCopy((1,2,3)); -Error, PlainListCopy: must be a small list (not a permutation (small)) +Error, PlainListCopy: must be a list (not a permutation (small)) #@if IsHPCGAP gap> PlainListCopy(Group((1,2))); -Error, PlainListCopy: must be a small list (not an atomic component object) +Error, PlainListCopy: must be a list (not an atomic component object) #@else gap> PlainListCopy(Group((1,2))); -Error, PlainListCopy: must be a small list (not a component object) +Error, PlainListCopy: must be a list (not a component object) #@fi # Check TNUM behaviours From 3e6752ece1ce9dbf58c7d0a36650f76842d840d2 Mon Sep 17 00:00:00 2001 From: Max Horn Date: Wed, 22 Apr 2026 02:25:33 +0200 Subject: [PATCH 187/234] Faster {Copy,Extract}Sub{Matrix,Vector} for plist matrices/vectors (#6329) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ... by avoiding some method dispatch, providing optimized methods using `{...}` syntax, and turning ExtractSubVector, CopySubVector, ExtractSubMatrix, and CopySubMatrix into kernel ops. Then run some benchmarks via `benchmark/matobj/bench-submat.g` and the new `benchmark/matobj/bench-subvec.g`. Before: +----------------------------------------------------------------+ | Testing submatrix extraction for integer matrix: list of lists | +----------------------------------------------------------------+ Testing m{}{}: 129 µs per iteration; 7749 iterations per second; (200 iterations) Testing ExtractSubMatrix: 720 µs per iteration; 1388 iterations per second; (200 iterations) ...now testing submatrix copying... Testing m{}{}:=n{}{}: 342 µs per iteration; 2921 iterations per second; (200 iterations) Testing CopySubMatrix: 1032 µs per iteration; 969 iterations per second; (200 iterations) +------------------------------------------------+ | Testing submatrix extraction for GF(2) rowlist | +------------------------------------------------+ Testing m{}{}: 167 µs per iteration; 5999 iterations per second; (200 iterations) Testing ExtractSubMatrix: 3288 µs per iteration; 304 iterations per second; (92 iterations) ...now testing submatrix copying... Testing m{}{}:=n{}{}: 1992 µs per iteration; 502 iterations per second; (151 iterations) Testing CopySubMatrix: 2606 µs per iteration; 384 iterations per second; (116 iterations) +-------------------------------------------------------------+ | Testing subvector extraction for integer vector: plain list | +-------------------------------------------------------------+ Testing x{}:=v{}: 393 µs per iteration; 2542 iterations per second; (200 iterations) Testing CopySubVector: 2324 µs per iteration; 430 iterations per second; (130 iterations) +---------------------------------------------------+ | Testing subvector extraction for GF(2) row vector | +---------------------------------------------------+ Testing x{}:=v{}: 441 µs per iteration; 2266 iterations per second; (200 iterations) Testing CopySubVector: 2458 µs per iteration; 407 iterations per second; (123 iterations) After: +----------------------------------------------------------------+ | Testing submatrix extraction for integer matrix: list of lists | +----------------------------------------------------------------+ Testing m{}{}: 136 µs per iteration; 7355 iterations per second; (200 iterations) Testing ExtractSubMatrix: 140 µs per iteration; 7135 iterations per second; (200 iterations) ...now testing submatrix copying... Testing m{}{}:=n{}{}: 301 µs per iteration; 3319 iterations per second; (200 iterations) Testing CopySubMatrix: 299 µs per iteration; 3347 iterations per second; (200 iterations) +------------------------------------------------+ | Testing submatrix extraction for GF(2) rowlist | +------------------------------------------------+ Testing m{}{}: 154 µs per iteration; 6490 iterations per second; (200 iterations) Testing ExtractSubMatrix: 146 µs per iteration; 6854 iterations per second; (200 iterations) ...now testing submatrix copying... Testing m{}{}:=n{}{}: 1895 µs per iteration; 528 iterations per second; (159 iterations) Testing CopySubMatrix: 1935 µs per iteration; 517 iterations per second; (156 iterations) +-------------------------------------------------------------+ | Testing subvector extraction for integer vector: plain list | +-------------------------------------------------------------+ Testing x{}:=v{}: 428 µs per iteration; 2336 iterations per second; (200 iterations) Testing CopySubVector: 453 µs per iteration; 2209 iterations per second; (200 iterations) +---------------------------------------------------+ | Testing subvector extraction for GF(2) row vector | +---------------------------------------------------+ Testing x{}:=v{}: 427 µs per iteration; 2344 iterations per second; (200 iterations) Testing CopySubVector: 460 µs per iteration; 2172 iterations per second; (200 iterations) So overall the Copy/Extract methods are now more or less on par with the code using `{...}` syntax. But actually this `ExtractSubMatrix` for a GF(2) rowlist is now *faster* than the optimized one for a compressed GF(2) matrix: +----------------------------------------------------------+ | Testing submatrix extraction for GF(2) compressed matrix | +----------------------------------------------------------+ Testing m{}{}: 1057 µs per iteration; 946 iterations per second; (200 iterations) Testing ExtractSubMatrix: 1618 µs per iteration; 618 iterations per second; (186 iterations) A substantial part of that is due to the the `ExtractSubMatrix` method for `IsGF2MatrixRep` calling `ConvertToMatrixRepNC(mm,2)`; after removing that, it went down from 1618 to 392 µs (which is still worse). --- AI assistance: Codex implemented the kernel plumbing, method cleanup, and test updates. It also created `benchmark/matobj/bench-subvec.g`. Co-authored-by: Codex --- benchmark/matobj/bench-submat.g | 41 ++++--- benchmark/matobj/bench-subvec.g | 81 ++++++++++++++ lib/matobj.gi | 31 +++--- lib/matobj2.gd | 17 +-- src/lists.c | 100 ++++++++++++++++++ tst/testinstall/MatrixObj/CopySubVector.tst | 3 +- .../MatrixObj/ExtractSubMatrix.tst | 13 +++ .../MatrixObj/ExtractSubvector.tst | 2 + 8 files changed, 247 insertions(+), 41 deletions(-) create mode 100644 benchmark/matobj/bench-subvec.g create mode 100644 tst/testinstall/MatrixObj/ExtractSubMatrix.tst diff --git a/benchmark/matobj/bench-submat.g b/benchmark/matobj/bench-submat.g index 0b10bf85b2..b5ee2697de 100644 --- a/benchmark/matobj/bench-submat.g +++ b/benchmark/matobj/bench-submat.g @@ -7,13 +7,15 @@ TestExtractingSubmatrix := function(m) rows := [2..NrRows(m)-2]; cols := [3..NrCols(m)-1]; - PrintHeadline("m{}{}"); - MyBench(function() - local u, x; - for u in [1..QuoInt(100000,NrRows(m)*NrCols(m))] do - x:=m{rows}{cols}; - od; - end); + if not IsPlistMatrixRep(m) then + PrintHeadline("m{}{}"); + MyBench(function() + local u, x; + for u in [1..QuoInt(100000,NrRows(m)*NrCols(m))] do + x:=m{rows}{cols}; + od; + end); + fi; PrintHeadline("ExtractSubMatrix"); MyBench(function() @@ -32,13 +34,15 @@ TestCopyingSubmatrix := function(m) rows := [2..NrRows(m)-2]; cols := [3..NrCols(m)-1]; - PrintHeadline("m{}{}:=n{}{}"); - MyBench(function() - local u; - for u in [1..QuoInt(100000,NrRows(m)*NrCols(m))] do - x{rows}{cols}:=m{rows}{cols}; - od; - end); + if not IsPlistMatrixRep(m) then + PrintHeadline("m{}{}:=n{}{}"); + MyBench(function() + local u; + for u in [1..QuoInt(100000,NrRows(m)*NrCols(m))] do + x{rows}{cols}:=m{rows}{cols}; + od; + end); + fi; PrintHeadline("CopySubMatrix"); MyBench(function() @@ -62,18 +66,21 @@ for dim in [10, 100] do PrintBoxed(Concatenation("Now testing in dimension ", String(dim))); m:=IdentityMat(dim);; - RunMatTest("integer matrix", m); + RunMatTest("integer matrix: list of lists", m); + + m:=IdentityMatrix(Integers, dim);; + RunMatTest("integer matrix: IsPlistMatrixRep", m); m:=IdentityMat(dim,GF(2));; RunMatTest("GF(2) rowlist", m); - m:=IdentityMat(dim,GF(2));; ConvertToMatrixRep(m);; + m:=IdentityMatrix(GF(2), dim);; RunMatTest("GF(2) compressed matrix", m); m:=IdentityMat(dim,GF(7));; RunMatTest("GF(7) rowlist", m); - m:=IdentityMat(dim,GF(7));; ConvertToMatrixRep(m);; + m:=IdentityMatrix(GF(8), dim);; RunMatTest("GF(7) compressed matrix", m); # TODO: also add cvec matrices diff --git a/benchmark/matobj/bench-subvec.g b/benchmark/matobj/bench-subvec.g new file mode 100644 index 0000000000..8e2ede2ea9 --- /dev/null +++ b/benchmark/matobj/bench-subvec.g @@ -0,0 +1,81 @@ +ReadGapRoot("benchmark/matobj/bench.g"); + + +TestExtractingSubvector := function(v) + local cols; + + cols := [3..Length(v)-1]; + + if not IsPlistVectorRep(v) then + PrintHeadline("v{}"); + MyBench(function() + local u, x; + for u in [1..QuoInt(100000, Length(v))] do + x := v{cols}; + od; + end); + fi; + + PrintHeadline("ExtractSubVector"); + MyBench(function() + local u, x; + for u in [1..QuoInt(100000, Length(v))] do + x := ExtractSubVector(v, cols); + od; + end); +end; + +TestCopyingSubvector := function(v) + local x, cols; + + x := ShallowCopy(v); + cols := [3..Length(v)-1]; + + if not IsPlistVectorRep(v) then + PrintHeadline("x{}:=v{}"); + MyBench(function() + local u; + for u in [1..QuoInt(100000, Length(v))] do + x{cols} := v{cols}; + od; + end); + fi; + + PrintHeadline("CopySubVector"); + MyBench(function() + local u; + for u in [1..QuoInt(100000, Length(v))] do + CopySubVector(v, x, cols, cols); + od; + end); +end; + +RunVecTest := function(desc, v) + Print("\n"); + PrintBoxed(Concatenation("Testing subvector extraction for ", desc)); + TestExtractingSubvector(v); + Print(TextAttr.2, "...now testing subvector copying...\n", TextAttr.reset); + TestCopyingSubvector(v); +end; + +for dim in [10, 100] do + PrintBoxed(Concatenation("Now testing in dimension ", String(dim))); + + v := [1..dim] * 0;; + RunVecTest("integer vector: plain list", v); + + v := Vector(IsPlistVectorRep, Integers, [1..dim]);; + RunVecTest("integer vector: IsPlistVectorRep", v); + + v := [1..dim] * One(GF(2));; + RunVecTest("GF(2) row vector", v); + + v := NewVector(IsGF2VectorRep, GF(2), [1..dim] * One(GF(2)));; + RunVecTest("GF(2) compressed vector", v); + + v := [1..dim] * One(GF(7));; + RunVecTest("GF(7) row vector", v); + + v := NewVector(Is8BitVectorRep, GF(7), [1..dim] * One(GF(7)));; + RunVecTest("GF(7) 8-bit vector", v); +od; diff --git a/lib/matobj.gi b/lib/matobj.gi index 652dddccad..35ae1ccbe0 100644 --- a/lib/matobj.gi +++ b/lib/matobj.gi @@ -749,9 +749,9 @@ InstallMethod( \{\}, return Vector( Unpack( v ){ poss }, v ); end ); -InstallMethod( ExtractSubVector, - "generic method for a vector object and a list", - [ IsVectorObj, IsList ], +InstallOtherMethod( ExtractSubVector, + "generic method for a row vector or vector object and a list", + [ IsRowVectorOrVectorObj, IsList ], { v, l } -> v{ l } ); InstallMethod( ExtractSubMatrix, @@ -759,20 +759,10 @@ InstallMethod( ExtractSubMatrix, [ IsMatrixObj, IsList, IsList ], { M, rowpos, colpos } -> Matrix( Unpack( M ){ rowpos }{ colpos }, M ) ); -# Hack from recog package -InstallOtherMethod( ExtractSubMatrix, "hack: for lists of compressed vectors", -[ IsList, IsList, IsList ], -function( m, poss1, poss2 ) - local i,n; - n := []; - for i in poss1 do - Add(n,ShallowCopy(m[i]{poss2})); - od; - if IsFFE(m[1,1]) then - ConvertToMatrixRep(n); - fi; - return n; -end ); +InstallOtherMethod( ExtractSubMatrix, + "generic method for a matrix and two lists", + [ IsMatrix, IsList, IsList ], + { M, rowpos, colpos } -> M{ rowpos }{ colpos } ); InstallMethod( CopySubVector, "generic method for row vectors and vector objects", @@ -788,6 +778,13 @@ InstallMethod( CopySubVector, od; end ); +InstallMethod( CopySubVector, + "generic method for row vectors", + [ IsRowVector, IsRowVector and IsMutable, IsList, IsList ], + function(src, dst, scols, dcols) + dst{dcols} := src{scols}; +end ); + ############################################################################# ## diff --git a/lib/matobj2.gd b/lib/matobj2.gd index c7cd9f0c4a..21f4af9a32 100644 --- a/lib/matobj2.gd +++ b/lib/matobj2.gd @@ -434,7 +434,8 @@ DeclareGlobalFunction( "ConcatenationOfVectors" ); ## ## <#/GAPDoc> ## -DeclareOperation( "ExtractSubVector", [ IsVectorObj, IsList ] ); +DeclareOperationKernel( "ExtractSubVector", + [ IsRowVectorOrVectorObj, IsList ], EXTRACT_SUB_VECTOR ); ############################################################################# @@ -896,9 +897,9 @@ DeclareOperation( "Randomize", [ IsRandomSource, IsMatrixOrMatrixObj and IsMutab ## ## <#/GAPDoc> ## -DeclareOperation( "CopySubVector", +DeclareOperationKernel( "CopySubVector", [ IsRowVectorOrVectorObj, IsRowVectorOrVectorObj and IsMutable, - IsList, IsList ] ); + IsList, IsList ], COPY_SUB_VECTOR ); ############################################################################# @@ -956,7 +957,8 @@ DeclareOperation( "DistanceOfVectors", [ IsVectorObj, IsVectorObj ] ); ## ## <#/GAPDoc> ## -DeclareOperation( "ExtractSubMatrix", [ IsMatrixOrMatrixObj, IsList, IsList ] ); +DeclareOperationKernel( "ExtractSubMatrix", + [ IsMatrixOrMatrixObj, IsList, IsList ], EXTRACT_SUB_MATRIX ); ############################################################################# @@ -1005,8 +1007,11 @@ DeclareOperation( "MutableCopyMatrix", [ IsMatrixOrMatrixObj ] ); ## ## <#/GAPDoc> ## -DeclareOperation( "CopySubMatrix", - [ IsMatrixOrMatrixObj, IsMatrixOrMatrixObj, IsList, IsList, IsList, IsList ] ); +DeclareOperationKernel( "CopySubMatrix", + [ IsMatrixOrMatrixObj, IsMatrixOrMatrixObj, IsList, IsList, IsList, IsList ], + COPY_SUB_MATRIX ); +#T We intentionally keep the second argument declaration broad, mirroring +#T the pre-existing operation declaration for compatibility with packages. ############################################################################# diff --git a/src/lists.c b/src/lists.c index dc329b0966..feb5c1584c 100644 --- a/src/lists.c +++ b/src/lists.c @@ -1611,6 +1611,99 @@ void AsssListLevel ( } +/**************************************************************************** +** +*F FuncEXTRACT_SUB_VECTOR( , , ) . . `EXTRACT_SUB_VECTOR' +*/ +static Obj ExtractSubVectorOper; + +static Obj FuncEXTRACT_SUB_VECTOR(Obj self, Obj vec, Obj poss) +{ + if (IS_PLIST(vec)) { + CheckIsPossList("List Elements", poss); + return ELMS_LIST(vec, poss); + } + + return DoOperation2Args(ExtractSubVectorOper, vec, poss); +} + + +/**************************************************************************** +** +*F FuncCOPY_SUB_VECTOR( , , , , ) +*/ +static Obj CopySubVectorOper; + +static Obj FuncCOPY_SUB_VECTOR( + Obj self, Obj src, Obj dst, Obj scols, Obj dcols) +{ + if (IS_PLIST(src) && IS_PLIST(dst)) { + Obj rhss; + + CheckIsPossList("List Assignments", scols); + CheckIsPossList("List Assignments", dcols); + rhss = ELMS_LIST(src, scols); + AsssListCheck(dst, dcols, rhss); + return 0; + } + + return DoOperation4Args(CopySubVectorOper, src, dst, scols, dcols); +} + + +/**************************************************************************** +** +*F FuncEXTRACT_SUB_MATRIX( , , , ) +*/ +static Obj ExtractSubMatrixOper; + +static Obj FuncEXTRACT_SUB_MATRIX(Obj self, Obj mat, Obj rows, Obj cols) +{ + if (IS_PLIST(mat)) { + Obj submat; + + CheckIsPossList("List Elements", rows); + CheckIsPossList("List Elements", cols); + submat = ELMS_LIST(mat, rows); + ElmsListLevel(submat, cols, 1); + return submat; + } + + return DoOperation3Args(ExtractSubMatrixOper, mat, rows, cols); +} + + +/**************************************************************************** +** +*F FuncCOPY_SUB_MATRIX( , , , , , , +*F ) +*/ +static Obj CopySubMatrixOper; + +static Obj FuncCOPY_SUB_MATRIX( + Obj self, Obj src, Obj dst, Obj srows, Obj drows, Obj scols, Obj dcols) +{ + if (IS_PLIST(src) && IS_PLIST(dst)) { + Obj srcsub; + Obj dstsub; + + CheckIsPossList("List Assignments", srows); + CheckIsPossList("List Assignments", drows); + CheckIsPossList("List Assignments", scols); + CheckIsPossList("List Assignments", dcols); + + srcsub = ELMS_LIST(src, srows); + ElmsListLevel(srcsub, scols, 1); + dstsub = ELMS_LIST(dst, drows); + AsssListLevel(dstsub, dcols, srcsub, 1); + return 0; + } + + return DoOperation6Args(CopySubMatrixOper, src, dst, srows, drows, scols, + dcols); +} + + /**************************************************************************** ** *F PLAIN_LIST() . . . . . . . . . . . convert a list to a plain list @@ -1953,6 +2046,13 @@ static StructGVarOper GVarOpers[] = { GVAR_OPER_4ARGS(ASS_MAT, mat, row, col, obj, &AssMatOper), GVAR_OPER_3ARGS(ELM_MAT, mat, row, col, &ElmMatOper), + GVAR_OPER_2ARGS(EXTRACT_SUB_VECTOR, vec, poss, &ExtractSubVectorOper), + GVAR_OPER_4ARGS(COPY_SUB_VECTOR, src, dst, scols, dcols, + &CopySubVectorOper), + GVAR_OPER_3ARGS(EXTRACT_SUB_MATRIX, mat, rows, cols, + &ExtractSubMatrixOper), + GVAR_OPER_6ARGS(COPY_SUB_MATRIX, src, dst, srows, drows, scols, dcols, + &CopySubMatrixOper), GVAR_OPER_3ARGS(SWAP_MAT_ROWS, mat, row1, row2, &SwapMatRows), GVAR_OPER_3ARGS(SWAP_MAT_COLS, mat, col1, col2, &SwapMatCols), diff --git a/tst/testinstall/MatrixObj/CopySubVector.tst b/tst/testinstall/MatrixObj/CopySubVector.tst index 5c702e6089..33cea42c90 100644 --- a/tst/testinstall/MatrixObj/CopySubVector.tst +++ b/tst/testinstall/MatrixObj/CopySubVector.tst @@ -79,7 +79,8 @@ gap> l4; # gap> CopySubVector( l1, l3, [1,2], [1] ); -Error, source and destination index lists must be of equal length +Error, List Assignments: must have the same length as (lengths a\ +re 2 and 1) # gap> STOP_TEST("CopySubVector.tst"); diff --git a/tst/testinstall/MatrixObj/ExtractSubMatrix.tst b/tst/testinstall/MatrixObj/ExtractSubMatrix.tst new file mode 100644 index 0000000000..35517c5f25 --- /dev/null +++ b/tst/testinstall/MatrixObj/ExtractSubMatrix.tst @@ -0,0 +1,13 @@ +gap> START_TEST("ExtractSubMatrix.tst"); +gap> IsBoundGlobal("EXTRACT_SUB_MATRIX"); +true +gap> EXTRACT_SUB_MATRIX = ExtractSubMatrix; +true +gap> m1 := [ [ 1, 2, 3 ], [ 4, 5, 6 ] ]; +[ [ 1, 2, 3 ], [ 4, 5, 6 ] ] +gap> ExtractSubMatrix( m1, [ 2, 1 ], [ 3, 1 ] ); +[ [ 6, 4 ], [ 3, 1 ] ] +gap> m2 := IdentityMatrix( Integers, 4 );; +gap> Unpack( ExtractSubMatrix( m2, [ 2, 4 ], [ 4, 2 ] ) ); +[ [ 0, 1 ], [ 1, 0 ] ] +gap> STOP_TEST("ExtractSubMatrix.tst"); diff --git a/tst/testinstall/MatrixObj/ExtractSubvector.tst b/tst/testinstall/MatrixObj/ExtractSubvector.tst index 42af85ac22..81224516ab 100644 --- a/tst/testinstall/MatrixObj/ExtractSubvector.tst +++ b/tst/testinstall/MatrixObj/ExtractSubvector.tst @@ -1,6 +1,8 @@ gap> START_TEST("ExtractSubVector.tst"); gap> l1 := [1,2,3,4,5,6]; [ 1, 2, 3, 4, 5, 6 ] +gap> ExtractSubVector( l1, [1,2,4] ); +[ 1, 2, 4 ] gap> v3 := Vector(GF(5), l1*One(GF(5))); [ Z(5)^0, Z(5), Z(5)^3, Z(5)^2, 0*Z(5), Z(5)^0 ] gap> ExtractSubVector( v3, [1,2,4] ); From b7dfed7e18554f96588266566343d00face25b10 Mon Sep 17 00:00:00 2001 From: Matt Van Horn Date: Thu, 23 Apr 2026 15:28:18 -0700 Subject: [PATCH 188/234] doc: fix IrreducibleModules description to say 'at most' dim (#6337) The GAPDoc description for IrreducibleModules claimed the second entry was 'a list of all irreducible modules of G over the field F in dimension dim'. The actual behaviour is to return all irreducible constituents of dimension at most dim, matching: Updated the description to match this, and also added a one-line note that passing 0 imposes no bound (already the implementation behavior, previously only discoverable by reading the code). Co-authored-by: Matt Van Horn <455140+mvanhorn@users.noreply.github.com> Co-authored-by: Claude (Anthropic AI) --- lib/grpreps.gd | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/grpreps.gd b/lib/grpreps.gd index 125cbbaf99..78433fcbf3 100644 --- a/lib/grpreps.gd +++ b/lib/grpreps.gd @@ -49,8 +49,10 @@ DeclareSynonym( "AbsolutelyIrreducibleModules", AbsolutIrreducibleModules ); ## ## returns a list of length 2. The first entry is a generating system of ## G. The second entry is a list of all irreducible modules of -## G over the field F in dimension dim, given as MeatAxe modules +## G over the field F of dimension at most dim, +## given as MeatAxe modules ## (see ). +## Pass 0 for dim to impose no dimension bound. ## ## ## <#/GAPDoc> From a2c4f01c9b1254d14a125973d110bf63f6f4ef8f Mon Sep 17 00:00:00 2001 From: Max Horn Date: Fri, 24 Apr 2026 16:36:36 +0200 Subject: [PATCH 189/234] Fix PartitionsGreatestLE for zero, improve docs (#6341) Return the empty partition from PartitionsGreatestLE(0, m) for every nonnegative m. Also clarify the documentation. Co-authored-by: Codex --- lib/combinat.gd | 22 ++++++++++++++++++++-- lib/combinat.gi | 12 ++++-------- tst/testinstall/combinat.tst | 22 ++++++++++++++++++++++ 3 files changed, 46 insertions(+), 10 deletions(-) diff --git a/lib/combinat.gd b/lib/combinat.gd index fb3ced6991..f89bbc550a 100644 --- a/lib/combinat.gd +++ b/lib/combinat.gd @@ -970,7 +970,7 @@ DeclareGlobalFunction("NrPartitions"); ############################################################################# ## -#F PartitionsGreatestLE( , ) . . . set of partitions of n parts <= n +#F PartitionsGreatestLE( , ) . . . partitions of n with parts <= m ## ## <#GAPDoc Label="PartitionsGreatestLE"> ## @@ -979,6 +979,16 @@ DeclareGlobalFunction("NrPartitions"); ## ## returns the set of all (unordered) partitions of the integer n ## having parts less or equal to the integer m. +## For n = 0 and m \geq 0, this returns the empty partition +## [[]]. +## Negative arguments yield the empty list. +## PartitionsGreatestLE( 6, 3 ); +## [ [ 1, 1, 1, 1, 1, 1 ], [ 2, 1, 1, 1, 1 ], [ 2, 2, 1, 1 ], [ 2, 2, 2 ], +## [ 3, 1, 1, 1 ], [ 3, 2, 1 ], [ 3, 3 ] ] +## gap> List( [ 0 .. 3 ], m -> PartitionsGreatestLE( 0, m ) ); +## [ [ [ ] ], [ [ ] ], [ [ ] ], [ [ ] ] ] +## ]]> ## ## ## <#/GAPDoc> @@ -988,7 +998,7 @@ DeclareGlobalFunction("PartitionsGreatestLE"); ############################################################################# ## -#F PartitionsGreatestEQ( , ) . . . . set of partitions of n parts = n +#F PartitionsGreatestEQ( , ) . . . . partitions of n with max part m ## ## <#GAPDoc Label="PartitionsGreatestEQ"> ## @@ -997,6 +1007,14 @@ DeclareGlobalFunction("PartitionsGreatestLE"); ## ## returns the set of all (unordered) partitions of the integer n ## having greatest part equal to the integer m. +## Since partitions use positive parts, this returns the empty list if +## n \leq 0 or m \leq 0. +## PartitionsGreatestEQ( 6, 3 ); +## [ [ 3, 1, 1, 1 ], [ 3, 2, 1 ], [ 3, 3 ] ] +## gap> PartitionsGreatestEQ( 0, 1 ); +## [ ] +## ]]> ## ## ## <#/GAPDoc> diff --git a/lib/combinat.gi b/lib/combinat.gi index 4973b1a09d..672992d0d5 100644 --- a/lib/combinat.gi +++ b/lib/combinat.gi @@ -1887,7 +1887,7 @@ end); ############################################################################# ## -#F PartitionsGreatestLE( , ) . . . set of partitions of n parts <= m +#F PartitionsGreatestLE( , ) . . . partitions of n with parts <= m ## ## returns the set of all (unordered) partitions of the integer having ## parts less or equal to the integer . @@ -1984,11 +1984,8 @@ function(n,m) parts := []; else if n = 0 then - if m = 0 then - parts := [ [ ] ]; - else - parts := [ ]; - fi; + # The empty partition satisfies every nonnegative upper bound. + parts := [ [ ] ]; else if m = 0 then parts := [ ]; @@ -2003,7 +2000,7 @@ end); ############################################################################# ## -#F PartitionsGreatestEQ( , ) . . . . set of partitions of n parts = n +#F PartitionsGreatestEQ( , ) . . . . partitions of n with max part m ## ## returns the set of all (unordered) partitions of the integer having ## greatest part equal to the integer . @@ -2041,7 +2038,6 @@ BindGlobal( "GPartitionsGreatestEQ", function(n,m) # This works exactly as `GPartitionsGreatestLE' for n-m and m and # adds a part m to all partitions. This is however done effectively # during the work. - # This is the same as `Partitions(n,m)' in the GAP library. # n and m must be a natural numbers >= 1. local B,j,k,l,p,res; if m > n then return []; fi; # a special case diff --git a/tst/testinstall/combinat.tst b/tst/testinstall/combinat.tst index b34d4bbe92..f1bf71034f 100644 --- a/tst/testinstall/combinat.tst +++ b/tst/testinstall/combinat.tst @@ -388,6 +388,28 @@ gap> NrPartitions( 100 ); gap> NrPartitions( 100, 10 ); 2977866 +#F PartitionsGreatestLE( , ) . . . partitions with largest part <= m +gap> List( [0..3], m -> PartitionsGreatestLE( 0, m ) ); +[ [ [ ] ], [ [ ] ], [ [ ] ], [ [ ] ] ] +gap> Print(PartitionsGreatestLE( 6, 3 ),"\n"); +[ [ 1, 1, 1, 1, 1, 1 ], [ 2, 1, 1, 1, 1 ], [ 2, 2, 1, 1 ], [ 2, 2, 2 ], + [ 3, 1, 1, 1 ], [ 3, 2, 1 ], [ 3, 3 ] ] +gap> Partitions( 6 ) = PartitionsGreatestLE( 6, 6 ); +true +gap> List( [1..4], k -> +> Difference( PartitionsGreatestLE( 6, k ), +> PartitionsGreatestLE( 6, k-1 ) ) +> = PartitionsGreatestEQ( 6, k ) ); +[ true, true, true, true ] +gap> Difference( PartitionsGreatestLE( 0, 1 ), +> PartitionsGreatestLE( 0, 0 ) ) +> = PartitionsGreatestEQ( 0, 1 ); +true +gap> Print(PartitionsGreatestEQ( 6, 3 ),"\n"); +[ [ 3, 1, 1, 1 ], [ 3, 2, 1 ], [ 3, 3 ] ] +gap> PartitionsGreatestEQ( 0, 1 ); +[ ] + #F OrderedPartitions( ) . . . . set of ordered partitions of an integer gap> OrderedPartitions( 0 ); [ [ ] ] From 1a27eb114034a90b6e55167c1bda8e934e4476c0 Mon Sep 17 00:00:00 2001 From: Max Horn Date: Tue, 28 Apr 2026 13:44:47 +0200 Subject: [PATCH 190/234] Avoid some uses of IdGroup (#6343) --- grp/clasmax.grp | 2 +- grp/simple.gi | 18 +++++++++--------- lib/grpnames.gi | 2 +- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/grp/clasmax.grp b/grp/clasmax.grp index 4d9daf2c2b..29ba01297a 100644 --- a/grp/clasmax.grp +++ b/grp/clasmax.grp @@ -25895,7 +25895,7 @@ local l,a,gf,conj,r,gp; (r^2=q and IsPrime(r) and r mod 10 in [3,7]) then # are the SL(2,5) in class S included ? (Depends on package status) - if not ForAny(l,x->Size(x)=120 and IdGroup(x)=[120,5]) then + if not ForAny(l,x->Size(x)=120 and IsPerfectGroup(x)) then # An A5, and its GL-conjugate gf:=GF(q); a:=Filtered(IrreducibleModules(TransitiveGroup(24,201),gf)[2], diff --git a/grp/simple.gi b/grp/simple.gi index c27d3078f4..c9a595c680 100644 --- a/grp/simple.gi +++ b/grp/simple.gi @@ -968,15 +968,15 @@ local nam,e,efactors,par,expo,prime,result,aut,i,classical,classaut,shortname, local s; if IsCyclic(gp) then return String(Size(gp)); - elif IdGroup(gp)=[4,2] then + elif Size(gp)=4 then return "2^2"; - elif IdGroup(gp)=[6,1] then + elif Size(gp)=6 then return "3.2"; - elif IdGroup(gp)=[8,3] then + elif Size(gp)=8 and IsDihedralGroup(gp) then return "2^2.2"; - elif IdGroup(gp)=[9,2] then + elif Size(gp)=9 then return "3^2"; - elif IdGroup(gp)=[18,3] then + elif Size(gp)=18 and Size(DerivedSubgroup(gp))=3 then return "3^2.2"; elif Size(gp)<=31 or Size(gp) in [33..47] then s:=StructureDescription(gp); @@ -1163,18 +1163,18 @@ local nam,e,efactors,par,expo,prime,result,aut,i,classical,classaut,shortname, if efactors<>fail and Size(classaut)<>Product(efactors) then Error("outer automorphism efactor fail"); fi; - if IdGroup(classaut)=[4,2] then + if Size(classaut)=4 and not IsCyclic(classaut) then # subgroup classes V4 e:=[[2,"2_1"],[2,"2_2"],[2,"2_3"],[4,"2^2"]]; - elif IdGroup(classaut)=[6,1] then + elif Size(classaut)=6 and not IsCyclic(classaut) then # subgroup classes S_3 e:=[ [ 2, "2" ], [ 3, "3" ], [ 6, "3.2" ] ]; - elif IdGroup(classaut)=[12,4] then + elif Size(classaut)=12 and IsDihedralGroup(classaut) then # subgroup classes 2\times S_3 (since S3 cannot act on C2) e:=[ [ 2, "2_1" ], [ 2, "2_2" ], [ 2, "2_3" ], [ 3, "3" ], [ 4, "2^2" ], [ 6, "3.2_1" ], [ 6, "3.2_2" ], [ 6, "6" ], [ 12, "3.2^2" ] ]; - elif IdGroup(classaut)=[24,12] then + elif Size(classaut)=24 and Size(DerivedSubgroup(classaut))=12 then # subgroup classes S_4 e:=[ [ 2, "2_1" ],[ 2, "2_2" ], [ 3, "3" ], [ 4, "4" ], [ 4, "(2^2)_{111}" ], [4,"(2^2)_{122}"], diff --git a/lib/grpnames.gi b/lib/grpnames.gi index dc207839c0..f3fa6cce4c 100644 --- a/lib/grpnames.gi +++ b/lib/grpnames.gi @@ -1208,7 +1208,7 @@ InstallMethod( IsAlternatingGroup, SetAlternatingDegree(G,0); return true; elif Size(G) = 3 then SetAlternatingDegree(G,3); return true; - elif Size(G) = 12 and IdGroup(G) = [ 12, 3 ] then + elif Size(G) = 12 and Size(DerivedSubgroup(G)) = 4 then SetAlternatingDegree(G,4); return true; else return false; fi; fi; From 3bde7d8672614ae1d09aff773f61b56dbe594985 Mon Sep 17 00:00:00 2001 From: Max Horn Date: Wed, 29 Apr 2026 11:08:55 +0200 Subject: [PATCH 191/234] CompatiblePairs: clarify documentation (#6348) Also fix indentation of part of its code. --- lib/grppcext.gd | 5 +++++ lib/grppcext.gi | 10 +++++----- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/lib/grppcext.gd b/lib/grppcext.gd index 79c40ace6b..9b7b55f59a 100644 --- a/lib/grppcext.gd +++ b/lib/grppcext.gd @@ -127,6 +127,11 @@ DeclareGlobalFunction( "EXReducePermutationActionPairs" ); ## G-module M as subgroup of the direct product ## Aut(G) \times Aut(M). ## Here Aut(M) is considered as subgroup of a general linear group. +## If G is solvable, then the generators of M must correspond +## to the value of G, +## otherwise the generators of M must correspond to the +## value of G. +##

## The optional argument D should be a subgroup of ## Aut(G) \times Aut(M). ## If it is given, then only the compatible pairs in D are computed. diff --git a/lib/grppcext.gi b/lib/grppcext.gi index c1e9fd20f7..7cb594f53d 100644 --- a/lib/grppcext.gi +++ b/lib/grppcext.gi @@ -721,11 +721,11 @@ local G, M, Mgrp, oper, A, B, D, translate, gens, genimgs, triso, K, K1, #return DirectProductElement( [tup[1], gens] ); end; - elif Size(G)>20000 then - # if G is too large we cannot write out elements - elmlist:=fail; - f:=basicact; - else + elif Size(G)>20000 then + # if G is too large we cannot write out elements + elmlist:=fail; + f:=basicact; + else elmlist:=[]; From fa833e72eaf7c0e11c34ba3053a6becb142cfdb4 Mon Sep 17 00:00:00 2001 From: Max Horn Date: Wed, 29 Apr 2026 15:33:02 +0200 Subject: [PATCH 192/234] Uprank {Copy,Extract}SubMatrix for compressed matrices (#6349) ... so that they are actually used. Also remove redundant `CopySubVector` methods. --- hpcgap/lib/vec8bit.gi | 10 +--- hpcgap/lib/vecmat.gi | 12 ++--- lib/vec8bit.gi | 10 +--- lib/vecmat.gi | 12 ++--- tst/testinstall/MatrixObj/CopySubMatrix.tst | 50 +++++++++++++++++++ .../MatrixObj/ExtractSubMatrix.tst | 31 +++++++++--- 6 files changed, 85 insertions(+), 40 deletions(-) diff --git a/hpcgap/lib/vec8bit.gi b/hpcgap/lib/vec8bit.gi index 1e9bdd5b4d..31af64cad8 100644 --- a/hpcgap/lib/vec8bit.gi +++ b/hpcgap/lib/vec8bit.gi @@ -1063,7 +1063,7 @@ InstallMethod( Matrix, "for a list of vecs, an integer, and an 8bit mat", end ); InstallMethod( ExtractSubMatrix, "for an 8bit matrix, and two lists", - [Is8BitMatrixRep, IsList, IsList], + [Is8BitMatrixRep and IsMatrix, IsList, IsList], function( m, rows, cols ) local mm; mm := m{rows}{cols}; @@ -1072,14 +1072,8 @@ InstallMethod( ExtractSubMatrix, "for an 8bit matrix, and two lists", return mm; end ); -InstallMethod( CopySubVector, "for two 8bit vectors, and two lists", - [Is8BitVectorRep, Is8BitVectorRep and IsMutable, IsList, IsList], - function( v, w, f, t ) - w{t} := v{f}; - end ); - InstallMethod( CopySubMatrix, "for two 8bit matrices, and four lists", - [Is8BitMatrixRep, Is8BitMatrixRep, IsList, IsList, IsList, IsList], + [Is8BitMatrixRep and IsMatrix, Is8BitMatrixRep and IsMatrix, IsList, IsList, IsList, IsList], function( a, b, frows, trows, fcols, tcols ) b{trows}{tcols} := a{frows}{fcols}; end ); diff --git a/hpcgap/lib/vecmat.gi b/hpcgap/lib/vecmat.gi index 6c24ce83ec..e582db8b0f 100644 --- a/hpcgap/lib/vecmat.gi +++ b/hpcgap/lib/vecmat.gi @@ -2470,7 +2470,7 @@ InstallMethod( Matrix, "for a list of vecs, an integer, and a gf2 mat", end ); InstallMethod( ExtractSubMatrix, "for a gf2 matrix, and two lists", - [IsGF2MatrixRep, IsList, IsList], + [IsGF2MatrixRep and IsMatrix, IsList, IsList], function( m, rows, cols ) local mm,r; mm := []; @@ -2494,14 +2494,8 @@ InstallMethod( CopySubVector, "for two gf2 vectors, and two ranges", fi; end ); - InstallMethod( CopySubVector, "for two gf2 vectors, and two lists", - [IsGF2VectorRep, IsGF2VectorRep and IsMutable, IsList, IsList], - function( v, w, f, t ) - w{t} := v{f}; - end ); - InstallMethod( CopySubMatrix, "for two gf2 matrices, and four lists", - [IsGF2MatrixRep, IsGF2MatrixRep, IsList, IsList, IsList, IsList], + [IsGF2MatrixRep and IsMatrix, IsGF2MatrixRep and IsMatrix, IsList, IsList, IsList, IsList], function( a, b, frows, trows, fcols, tcols ) local i; for i in [1..Length(frows)] do @@ -2510,7 +2504,7 @@ InstallMethod( CopySubMatrix, "for two gf2 matrices, and four lists", end ); InstallMethod( CopySubMatrix, "for two gf2 matrices, two lists and two ranges", - [IsGF2MatrixRep, IsGF2MatrixRep, IsList, IsList, IsRange, IsRange], + [IsGF2MatrixRep and IsMatrix, IsGF2MatrixRep and IsMatrix, IsList, IsList, IsRange, IsRange], function( a, b, frows, trows, fcols, tcols ) local l, i; l := Length(fcols); diff --git a/lib/vec8bit.gi b/lib/vec8bit.gi index 5d4cddcae1..1602a4ca36 100644 --- a/lib/vec8bit.gi +++ b/lib/vec8bit.gi @@ -1018,7 +1018,7 @@ InstallMethod( Matrix, "for a list of vecs, an integer, and an 8bit mat", end ); InstallMethod( ExtractSubMatrix, "for an 8bit matrix, and two lists", - [Is8BitMatrixRep, IsList, IsList], + [Is8BitMatrixRep and IsMatrix, IsList, IsList], function( m, rows, cols ) local mm; mm := m{rows}{cols}; @@ -1027,14 +1027,8 @@ InstallMethod( ExtractSubMatrix, "for an 8bit matrix, and two lists", return mm; end ); -InstallMethod( CopySubVector, "for two 8bit vectors, and two lists", - [Is8BitVectorRep, Is8BitVectorRep and IsMutable, IsList, IsList], - function( v, w, f, t ) - w{t} := v{f}; - end ); - InstallMethod( CopySubMatrix, "for two 8bit matrices, and four lists", - [Is8BitMatrixRep, Is8BitMatrixRep, IsList, IsList, IsList, IsList], + [Is8BitMatrixRep and IsMatrix, Is8BitMatrixRep and IsMatrix, IsList, IsList, IsList, IsList], function( a, b, frows, trows, fcols, tcols ) b{trows}{tcols} := a{frows}{fcols}; end ); diff --git a/lib/vecmat.gi b/lib/vecmat.gi index 2e6b4a4e91..8e319696b3 100644 --- a/lib/vecmat.gi +++ b/lib/vecmat.gi @@ -2468,7 +2468,7 @@ InstallMethod( Matrix, "for a list of vecs, an integer, and a gf2 mat", end ); InstallMethod( ExtractSubMatrix, "for a gf2 matrix, and two lists", - [IsGF2MatrixRep, IsList, IsList], + [IsGF2MatrixRep and IsMatrix, IsList, IsList], function( m, rows, cols ) local mm,r; mm := []; @@ -2492,14 +2492,8 @@ InstallMethod( CopySubVector, "for two gf2 vectors, and two ranges", fi; end ); - InstallMethod( CopySubVector, "for two gf2 vectors, and two lists", - [IsGF2VectorRep, IsGF2VectorRep and IsMutable, IsList, IsList], - function( v, w, f, t ) - w{t} := v{f}; - end ); - InstallMethod( CopySubMatrix, "for two gf2 matrices, and four lists", - [IsGF2MatrixRep, IsGF2MatrixRep, IsList, IsList, IsList, IsList], + [IsGF2MatrixRep and IsMatrix, IsGF2MatrixRep and IsMatrix, IsList, IsList, IsList, IsList], function( a, b, frows, trows, fcols, tcols ) local i; for i in [1..Length(frows)] do @@ -2508,7 +2502,7 @@ InstallMethod( CopySubMatrix, "for two gf2 matrices, and four lists", end ); InstallMethod( CopySubMatrix, "for two gf2 matrices, two lists and two ranges", - [IsGF2MatrixRep, IsGF2MatrixRep, IsList, IsList, IsRange, IsRange], + [IsGF2MatrixRep and IsMatrix, IsGF2MatrixRep and IsMatrix, IsList, IsList, IsRange, IsRange], function( a, b, frows, trows, fcols, tcols ) local l, i; l := Length(fcols); diff --git a/tst/testinstall/MatrixObj/CopySubMatrix.tst b/tst/testinstall/MatrixObj/CopySubMatrix.tst index 1563c98495..2004a01ab1 100644 --- a/tst/testinstall/MatrixObj/CopySubMatrix.tst +++ b/tst/testinstall/MatrixObj/CopySubMatrix.tst @@ -80,5 +80,55 @@ Error, source and destination row lists must be of equal length gap> CopySubMatrix( m5, m4, [ 1 ], [ 1 ], [ 1, 2 ], [ 1 ] ); Error, source and destination column lists must be of equal length +# IsGF2MatrixRep +gap> m1 := IdentityMatrix( IsPlistMatrixRep, Rationals, 10 ); +<10x10-matrix over Rationals> +gap> m2 := ZeroMatrix( 6, 6, m1 ); +<6x6-matrix over Rationals> +gap> CopySubMatrix( m1, m2, [ 1..3 ], [ 3..5 ], [ 2..4 ], [ 4..6 ] ); +gap> IsOne(m1); +true +gap> Display(m2); +<6x6-matrix over Rationals: +[[ 0, 0, 0, 0, 0, 0 ] + [ 0, 0, 0, 0, 0, 0 ] + [ 0, 0, 0, 0, 0, 0 ] + [ 0, 0, 0, 1, 0, 0 ] + [ 0, 0, 0, 0, 1, 0 ] + [ 0, 0, 0, 0, 0, 0 ] +]> + +# IsGF2MatrixRep +gap> m1 := IdentityMatrix( GF(2), 10 ); + +gap> m2 := ZeroMatrix( 6, 6, m1 ); + +gap> CopySubMatrix( m1, m2, [ 1..3 ], [ 3..5 ], [ 2..4 ], [ 4..6 ] ); +gap> IsOne(m1); +true +gap> Display(m2); + . . . . . . + . . . . . . + . . . . . . + . . . 1 . . + . . . . 1 . + . . . . . . + +# Is8BitMatrixRep +gap> m1 := IdentityMatrix( GF(3), 10 ); +< mutable compressed matrix 10x10 over GF(3) > +gap> m2 := ZeroMatrix( 6, 6, m1 ); +< mutable compressed matrix 6x6 over GF(3) > +gap> CopySubMatrix( m1, m2, [ 1..3 ], [ 3..5 ], [ 2..4 ], [ 4..6 ] ); +gap> IsOne(m1); +true +gap> Display(m2); + . . . . . . + . . . . . . + . . . . . . + . . . 1 . . + . . . . 1 . + . . . . . . + # gap> STOP_TEST("CopySubMatrix.tst"); diff --git a/tst/testinstall/MatrixObj/ExtractSubMatrix.tst b/tst/testinstall/MatrixObj/ExtractSubMatrix.tst index 35517c5f25..eeb77a8213 100644 --- a/tst/testinstall/MatrixObj/ExtractSubMatrix.tst +++ b/tst/testinstall/MatrixObj/ExtractSubMatrix.tst @@ -1,13 +1,32 @@ gap> START_TEST("ExtractSubMatrix.tst"); -gap> IsBoundGlobal("EXTRACT_SUB_MATRIX"); -true -gap> EXTRACT_SUB_MATRIX = ExtractSubMatrix; -true + +# gap> m1 := [ [ 1, 2, 3 ], [ 4, 5, 6 ] ]; [ [ 1, 2, 3 ], [ 4, 5, 6 ] ] gap> ExtractSubMatrix( m1, [ 2, 1 ], [ 3, 1 ] ); [ [ 6, 4 ], [ 3, 1 ] ] -gap> m2 := IdentityMatrix( Integers, 4 );; -gap> Unpack( ExtractSubMatrix( m2, [ 2, 4 ], [ 4, 2 ] ) ); +gap> m2 := IdentityMatrix( Integers, 4 ); +<4x4-matrix over Integers> +gap> m3 := ExtractSubMatrix( m2, [ 2, 4 ], [ 4, 2 ] ); +<2x2-matrix over Integers> +gap> Unpack( m3 ); [ [ 0, 1 ], [ 1, 0 ] ] + +# IsGF2MatrixRep +gap> m1 := IdentityMatrix( GF(2), 100 ); + +gap> m2 := ExtractSubMatrix( m1, [ 11..30 ], [ 11..30 ] ); + +gap> IsOne(m2); +true + +# Is8BitMatrixRep +gap> m1 := IdentityMatrix( GF(3), 100 ); +< mutable compressed matrix 100x100 over GF(3) > +gap> m2 := ExtractSubMatrix( m1, [ 11..30 ], [ 11..30 ] ); +< mutable compressed matrix 20x20 over GF(3) > +gap> IsOne(m2); +true + +# gap> STOP_TEST("ExtractSubMatrix.tst"); From 874e2b25f8082863e665cacb03d0715517b1c03d Mon Sep 17 00:00:00 2001 From: stertooy <5571903+stertooy@users.noreply.github.com> Date: Wed, 29 Apr 2026 18:28:04 +0200 Subject: [PATCH 193/234] Document & validate new package metadata TestPackages, NeededSystempackages (#6292) --- doc/ref/gappkg.xml | 82 +++++++++++++++++++++++++++++++++++++++++++++- lib/package.gi | 10 ++++++ 2 files changed, 91 insertions(+), 1 deletion(-) diff --git a/doc/ref/gappkg.xml b/doc/ref/gappkg.xml index 0eaa2f5bfd..01631f5994 100644 --- a/doc/ref/gappkg.xml +++ b/doc/ref/gappkg.xml @@ -367,10 +367,23 @@ The following components of the record are optional. denoting the other packages which shall be loaded together with the current package if they are available, + TestPackages + + a list of pairs [ pkgname, pkgversion ] of strings, + denoting packages that are needed only to test the package, but not to + load the package, + + NeededSystemPackages + + a record whose contents describe external dependencies of the package + in a machine-readable form (see for + more information), + ExternalConditions a list of strings or of pairs [ text, URL ] of strings, - denoting conditions on external programs, + denoting conditions on external programs in a human-readable form + (see for more information), @@ -1169,6 +1182,19 @@ In this situation, loading A forces an attempt to load also B, but A is loaded even if B is not available.

+If B is not essential for A but is used in the package tests, +(for example because B is a library of groups used to provide +testcases) then the name and the (least) version number of B should +be added to the TestPackages component of the Dependencies +component of the PackageInfo.g file of A. Note that &GAP; +itself does not use this information at all. In particular, no attempts +are made to actually load B, this should be done explicitly as +part of the package tests. The benefit of specifying this component is +for automated test runners (e.g. as part of the &GAP; package distribution) +which can use this information to ensure all packages needed to run +your package's tests are installed and ready. +

+ All package dependencies must be documented explicitly in the PackageInfo.g file. It is important to properly identify package dependencies and make the right decision @@ -1224,6 +1250,60 @@ or what are other ways to disable its loading --> + +

+External Dependencies (System packages needed by a &GAP; Package) + +external dependency +system package +dependencies +It is possible for a &GAP; package to require external software. If this +software is not bundled together with the package, then this dependency +should be documented. To do so, one may add either a string describing the +dependency, or a list [ description, URL ], to the +ExternalConditions component of the Dependencies component of +the PackageInfo.g file of the &GAP; package. + + + +Note that the data in ExternalConditions is purely informational +and meant to be human-readable, not machine-readable. &GAP; itself does +not use it, but for packages distributed with &GAP;, the &GAP; website +displays it in its package list. +

+ +If this dependency is available through a package manager such as apt +or brew, this should also be documented. This can be done by adding +the system package to the relevant component (such as Ubuntu or +Homebrew) of the NeededSystemPackages component of the +PackageInfo.g file of the &GAP; package. Each system package is added +by means of a list whose first component is the name needed by the package +manager. The other elements of this list are reserved for future usage. + + + +Note that this mechanism is primarily intended for consumption by the +&GAP; package distribution and by other testing tooling. It is deliberately +kept very simple. For example, at this point there is no mechanism to +prescribe a distribution version (basically, "Ubuntu" means whatever +`ubuntu-latest` is referring to in GitHub actions), nor to specify a minimal +version of a system package. Despite these strong limitations, this data may +still be useful for people packaging &GAP; and its packages for a distribution, +as it at least gives a hint which system packages may be needed. + +

+ +
Extensions Provided by a Package diff --git a/lib/package.gi b/lib/package.gi index 22eafe0815..fbd23eda01 100644 --- a/lib/package.gi +++ b/lib/package.gi @@ -2433,6 +2433,16 @@ InstallGlobalFunction( ValidatePackageInfo, function( info ) l -> IsList( l ) and Length( l ) = 2 and ForAll( l, IsString ) ), "a list of pairs `[ , ]' of strings" ); + TestOption( record.Dependencies, "TestPackages", + comp -> IsList( comp ) and ForAll( comp, + l -> IsList( l ) and Length( l ) = 2 + and ForAll( l, IsString ) ), + "a list of pairs `[ , ]' of strings" ); + TestOption( record.Dependencies, "NeededSystemPackages", + comp -> IsRecord( comp ) and ForAll( RecNames( comp ), + l -> IsList( comp.( l ) ) and ForAll( comp.( l ), + x -> IsList( x ) and IsString( First( x ) ) ) ), + "a record whose values are lists of lists `[ , ... ]`" ); TestOption( record.Dependencies, "ExternalConditions", comp -> IsList( comp ) and ForAll( comp, l -> IsString( l ) or ( IsList( l ) and Length( l ) = 2 From 80adf0da84da239cff99ba384692afb2e5852604 Mon Sep 17 00:00:00 2001 From: Max Horn Date: Thu, 30 Apr 2026 23:13:19 +0200 Subject: [PATCH 194/234] Refine SetSize and remove some immediate methods (#6347) The removed methods mostly were already obsolete due to the custom SetSize. Only the "non emptiness" was not recorded right, which the new code in `SetSize` now handles. --- lib/coll.gi | 42 +++++++++++++++++++--------------------- lib/modfree.gi | 13 ------------- tst/testinstall/coll.tst | 13 ++++++------- 3 files changed, 26 insertions(+), 42 deletions(-) diff --git a/lib/coll.gi b/lib/coll.gi index 6736ccf5a8..7a53bdbb12 100644 --- a/lib/coll.gi +++ b/lib/coll.gi @@ -92,10 +92,6 @@ InstallMethod( PrintObj, ## #M IsEmpty() . . . . . . . . . . . . . . . test if a collection is empty ## -InstallImmediateMethod( IsEmpty, - IsCollection and HasSize, 0, - C -> Size( C ) = 0 ); - InstallMethod( IsEmpty, "for a collection", [ IsCollection ], @@ -111,10 +107,6 @@ InstallMethod( IsEmpty, ## #M IsTrivial() . . . . . . . . . . . . . test if a collection is trivial ## -InstallImmediateMethod( IsTrivial, - IsCollection and HasSize, 0, - C -> Size( C ) = 1 ); - InstallMethod( IsTrivial, "for a collection", [ IsCollection ], @@ -143,10 +135,6 @@ InstallMethod( IsNonTrivial, ## #M IsFinite() . . . . . . . . . . . . . . test if a collection is finite ## -InstallImmediateMethod( IsFinite, - IsCollection and HasSize, 0, - C -> not IsIdenticalObj( Size( C ), infinity ) ); - InstallMethod( IsFinite, "for a collection", [ IsCollection ], @@ -2879,17 +2867,27 @@ local filt; fi; # some sanity checks - Assert(0, not HasIsEmpty(obj) or (IsEmpty(obj) = (sz=0))); - Assert(0, not HasIsNonTrivial(obj) or (IsNonTrivial(obj) = (sz<>1))); - Assert(0, not HasIsTrivial(obj) or (IsTrivial(obj) = (sz=1))); - Assert(0, not HasIsFinite(obj) or (IsFinite(obj) = (sz<>infinity))); - - if sz=0 then filt:=IsEmpty; - elif sz=1 then filt:=IsTrivial; - elif sz=infinity then filt:=IsNonTrivial and HasIsFinite; - else filt:=IsNonTrivial and IsFinite; + Assert(1, not HasIsEmpty(obj) or (IsEmpty(obj) = (sz=0))); + Assert(1, not HasIsNonTrivial(obj) or (IsNonTrivial(obj) = (sz<>1))); + Assert(1, not HasIsTrivial(obj) or (IsTrivial(obj) = (sz=1))); + Assert(1, not HasIsFinite(obj) or (IsFinite(obj) = (sz<>infinity))); + + filt:=HasSize; + if sz=0 then + filt:=filt and IsEmpty; + else + filt:=filt and HasIsEmpty; + fi; + if sz=1 then + filt:=filt and IsTrivial; + else + filt:=filt and IsNonTrivial; + fi; + if sz=infinity then + filt:=filt and HasIsFinite; + else + filt:=filt and IsFinite; fi; - filt:=filt and HasSize; obj!.Size:=sz; SetFilterObj(obj,filt); end); diff --git a/lib/modfree.gi b/lib/modfree.gi index c88e380f42..86252154e8 100644 --- a/lib/modfree.gi +++ b/lib/modfree.gi @@ -104,16 +104,6 @@ InstallMethod( \in, ## ring is needed since all generator dependent questions are handled in the ## `IsTrivial' call.) ## -InstallImmediateMethod( IsFinite, - IsFreeLeftModule and HasIsFiniteDimensional, 0, - function( V ) - if not IsFiniteDimensional( V ) then - return false; - else - TryNextMethod(); - fi; - end ); - InstallMethod( IsFinite, "for a free left module", [ IsFreeLeftModule ], @@ -136,9 +126,6 @@ InstallMethod( IsFinite, ## #M IsTrivial( ) ## -InstallImmediateMethod( IsTrivial, IsFreeLeftModule and HasDimension, 0, - V -> Dimension( V ) = 0 ); - InstallMethod( IsTrivial, "for a free left module", [ IsFreeLeftModule ], diff --git a/tst/testinstall/coll.tst b/tst/testinstall/coll.tst index 88b68bdd7a..cc30a2ba9f 100644 --- a/tst/testinstall/coll.tst +++ b/tst/testinstall/coll.tst @@ -46,13 +46,12 @@ gap> List(props, p -> p(M0)); gap> N1:=Magma([[[1,0],[0,0]]]);; gap> ForAll(props, prop -> not Tester(prop)(N1)); true - -#gap> Size(N1); -#1 -#gap> ForAll(props, prop -> Tester(prop)(N1)); -#true -#gap> List(props, p -> p(N1)); -#[ false, true, false, true ] +gap> Size(N1); +1 +gap> ForAll(props, prop -> Tester(prop)(N1)); +true +gap> List(props, p -> p(N1)); +[ false, true, false, true ] # ... immediate methods for a collection which knows its size, # applied to collection with size greater than 1 From bdf515e72a40d1729cf70dbd9b6ab3c84a834f2b Mon Sep 17 00:00:00 2001 From: Christopher Jefferson Date: Mon, 4 May 2026 05:43:08 +0800 Subject: [PATCH 195/234] Fix HexSHA256 to always return 64 hex digits (#6358) When the SHA256 digest's leading byte(s) were zero, HexStringInt dropped those leading zero hex digits, so HexSHA256 returned a string shorter than 64 characters. Left-pad the result to 64 hex digits, since a SHA256 digest is always 256 bits. --- lib/files.gi | 8 +++++++- tst/testinstall/sha256.tst | 11 +++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/lib/files.gi b/lib/files.gi index f9c3dfd1f8..d710bc4d81 100644 --- a/lib/files.gi +++ b/lib/files.gi @@ -412,5 +412,11 @@ function(str) GAP_SHA256_UPDATE(s, str); res := GAP_SHA256_FINAL(s); res := Sum([0..7], i -> res[8-i]*2^(32*i));; - return LowercaseString(HexStringInt(res)); + res := LowercaseString(HexStringInt(res)); + # HexStringInt drops leading zero digits, but a SHA256 digest is always + # 256 bits = 64 hex digits, so left-pad with '0' if the top byte(s) were 0. + if Length(res) < 64 then + res := Concatenation(ListWithIdenticalEntries(64 - Length(res), '0'), res); + fi; + return res; end); diff --git a/tst/testinstall/sha256.tst b/tst/testinstall/sha256.tst index 3d0fcc1d0c..7f6988cb3a 100644 --- a/tst/testinstall/sha256.tst +++ b/tst/testinstall/sha256.tst @@ -32,6 +32,17 @@ gap> HexSHA256("abcd\r\n"); gap> HexSHA256(""); "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" +# Inputs whose SHA256 starts with one or more zero hex digits: the result +# must still be 64 hex characters (the digest is always 256 bits). +gap> HexSHA256("39"); +"0b918943df0962bc7a1824c0555a389347b4febdc7cf9d1254406d80ce44e3f9" +gap> HexSHA256("286"); +"00328ce57bbc14b33bd6695bc8eb32cdf2fb5f3a7d89ec14a42825e15d39df60" +gap> HexSHA256("886"); +"000f21ac06aceb9cdd0575e82d0d85fc39bed0a7a1d71970ba1641666a44f530" +gap> ForAll(["", "abcd", "39", "286", "886"], s -> Length(HexSHA256(s)) = 64); +true + # gap> HexSHA256(InputTextString("abcd")); "88d4266fd4e6338d13b845fcf289579d209c897823b9217da3e161936f031589" From de1a83d2989b1d1561114aa44e0866336870741e Mon Sep 17 00:00:00 2001 From: Max Horn Date: Mon, 4 May 2026 16:09:00 +0100 Subject: [PATCH 196/234] Fix garbled result produced by CosetLeadersMatFFE (#6325) When invoked on compressed matrices over small finite fields, CosetLeadersMatFFE sometimes would produce incorrect output with gaps in it (i.e., undefined entries) AI assistance: Codex investigated the 8-bit fast path, added a regression test, and prepared the fix. Co-authored-by: Codex --- src/vec8bit.c | 24 +++++++++++++---- tst/testbugfix/2026-04-15-issue-5923.tst | 33 ++++++++++++++++++++++++ 2 files changed, 52 insertions(+), 5 deletions(-) create mode 100644 tst/testbugfix/2026-04-15-issue-5923.tst diff --git a/src/vec8bit.c b/src/vec8bit.c index 397649b2c3..60243625c4 100644 --- a/src/vec8bit.c +++ b/src/vec8bit.c @@ -2482,6 +2482,7 @@ static UInt CosetLeadersInner8Bits(Obj veclis, UInt elts; UInt1 * ptr, *ptrw; const UInt1 * gettab; + const Obj * gapseq; const UInt1 * feltffe; Obj x; Obj vp; @@ -2491,6 +2492,7 @@ static UInt CosetLeadersInner8Bits(Obj veclis, elts = ELS_BYTE_FIELDINFO_8BIT(info); settab = SETELT_FIELDINFO_8BIT(info); gettab = GETELT_FIELDINFO_8BIT(info); + gapseq = GAPSEQ_FELT_FIELDINFO_8BIT(info); ptrw = BYTES_VEC8BIT(w); if (weight == 1) { for (i = pos; i <= len; i++) { @@ -2498,13 +2500,21 @@ static UInt CosetLeadersInner8Bits(Obj veclis, u = ELM_PLIST(vp, 1); AddVec8BitVec8BitInner(w, w, u, 1, lenw); ptr = BYTES_VEC8BIT(v) + (i - 1) / elts; - *ptr = settab[*ptr + 256 * (elts + ((i - 1) % elts))]; + // Keep the coefficient vector in the same sorted field-element + // order that NumberFFVector uses for list indices. + feltffe = FELT_FFE_FIELDINFO_8BIT(info); + x = ELM_PLIST(felts, 2); + *ptr = settab[*ptr + 256 * (elts * feltffe[VAL_FFE(x)] + + ((i - 1) % elts))]; sy = 0; for (j = 0; j < lenw; j++) { UInt xxxx; sy *= q; xxxx = gettab[ptrw[j / elts] + 256 * (j % elts)]; - sy += xxxx; + // The packed 8-bit representation uses a different internal + // field ordering, so translate back to GAP's sequence before + // using the syndrome number as a plain-list position. + sy += INT_INTOBJ(gapseq[xxxx]); } if ((Obj)0 == ELM_PLIST(leaders, sy + 1)) { UInt k; @@ -2517,10 +2527,13 @@ static UInt CosetLeadersInner8Bits(Obj veclis, wc = ZeroVec8Bit(q, lenw, 1); settab = SETELT_FIELDINFO_8BIT(info); gettab = GETELT_FIELDINFO_8BIT(info); + gapseq = GAPSEQ_FELT_FIELDINFO_8BIT(info); ptr = BYTES_VEC8BIT(v) + (i - 1) / elts; ptrw = BYTES_VEC8BIT(w); - for (k = 2; k < q; k++) { - qk = FFE_FELT_FIELDINFO_8BIT(info, k); + for (k = 3; k <= q; k++) { + // Record scalar multiples in the same order as the GAP + // fallback, namely the sorted field elements in 'felts'. + qk = ELM_PLIST(felts, k); MultVec8BitFFEInner(wc, w, qk, 1, lenw); ptrw = BYTES_VEC8BIT(wc); sy = 0; @@ -2528,11 +2541,12 @@ static UInt CosetLeadersInner8Bits(Obj veclis, UInt xxxx; sy *= q; xxxx = gettab[ptrw[j / elts] + 256 * (j % elts)]; - sy += xxxx; + sy += INT_INTOBJ(gapseq[xxxx]); } vc = ZeroVec8Bit(q, len, 0); settab = SETELT_FIELDINFO_8BIT(info); gettab = GETELT_FIELDINFO_8BIT(info); + gapseq = GAPSEQ_FELT_FIELDINFO_8BIT(info); ptr = BYTES_VEC8BIT(v) + (i - 1) / elts; ptrw = BYTES_VEC8BIT(w); MultVec8BitFFEInner(vc, v, qk, 1, len); diff --git a/tst/testbugfix/2026-04-15-issue-5923.tst b/tst/testbugfix/2026-04-15-issue-5923.tst new file mode 100644 index 0000000000..781733cd55 --- /dev/null +++ b/tst/testbugfix/2026-04-15-issue-5923.tst @@ -0,0 +1,33 @@ +# Regression test for issue #5923: the 8-bit kernel path for +# CosetLeadersMatFFE must not leave holes in the result list. +gap> F := GF(4);; +gap> M := One(F)*[[1,0,Z(4)],[0,1,Z(4)^2]];; +gap> L := CosetLeadersMatFFE(M, F);; +gap> Length(L) = Size(F)^2; +true +gap> ForAll([1..Length(L)], i -> IsBound(L[i])); +true +gap> List(L, v -> NumberFFVector(M * v, Size(F))) = [0..Length(L)-1]; +true + +# some additional tests "because we can" for other cases +gap> F := GF(2);; +gap> M := One(F)*[[1,0,1,0,1,0],[1,1,1,0,0,0]];; +gap> L := CosetLeadersMatFFE(M, F);; +gap> Length(L) = Size(F)^2; +true +gap> ForAll([1..Length(L)], i -> IsBound(L[i])); +true +gap> List(L, v -> NumberFFVector(M * v, Size(F))) = [0..Length(L)-1]; +true + +# some additional tests "because we can" for other cases +gap> F := GF(257);; +gap> M := One(F)*[[1,0,1,0,1,0],[1,1,1,0,0,0]];; +gap> L := CosetLeadersMatFFE(M, F);; +gap> Length(L) = Size(F)^2; +true +gap> ForAll([1..Length(L)], i -> IsBound(L[i])); +true +gap> List(L, v -> NumberFFVector(M * v, Size(F))) = [0..Length(L)-1]; +true From 1e8d8c58888230063bde7e2589d4211d1afa7e1d Mon Sep 17 00:00:00 2001 From: Max Horn Date: Mon, 4 May 2026 16:09:32 +0100 Subject: [PATCH 197/234] Fix crash in `CosetLeadersMatFFE` (#6326) Reject matrices with dependent rows before building the internal search tables for CosetLeadersMatFFE. This avoids a crash in the 8-bit path and restores correct behaviour for square full-rank inputs. AI assistance: Codex reproduced the crash, traced it to the internal row-independence assumption, added a regression test, and prepared the fix. Co-authored-by: Codex --- lib/listcoef.gi | 9 ++++++--- src/vec8bit.c | 2 ++ src/vecgf2.c | 2 ++ tst/testbugfix/2026-04-15-CosetLeadersMatFFE-errors.tst | 8 ++++++++ 4 files changed, 18 insertions(+), 3 deletions(-) create mode 100644 tst/testbugfix/2026-04-15-CosetLeadersMatFFE-errors.tst diff --git a/lib/listcoef.gi b/lib/listcoef.gi index 8519d78cf5..106ab14463 100644 --- a/lib/listcoef.gi +++ b/lib/listcoef.gi @@ -1516,10 +1516,14 @@ InstallMethod(CosetLeadersMatFFE,"generic",IsCollsElms, q := Size(f); n := Length(mat[1]); m := Length(mat); + # The search below assumes the rows form a basis for an m-dimensional + # syndrome space, so reject dependent input before building the column data. + if RankMat(mat) <> m then + Error("CosetLeadersMatFFE: must have linearly independent rows"); + fi; tofind := q^m; t := TransposedMat(mat); - vl := []; - vl[m+1] := false; + vl := EmptyPlist(m); felts := AsSSortedList(f); Assert(2, felts[1] = Zero(f)); nzfelts := felts{[2..q]}; @@ -1537,7 +1541,6 @@ InstallMethod(CosetLeadersMatFFE,"generic",IsCollsElms, Add(vl[i], v*fds[j]); fi; od; - Add(vl[i],false); od; v := ListWithIdenticalEntries(n, felts[1]); w := ZeroOp(t[1]); diff --git a/src/vec8bit.c b/src/vec8bit.c index 60243625c4..9137672f8c 100644 --- a/src/vec8bit.c +++ b/src/vec8bit.c @@ -2604,8 +2604,10 @@ static Obj FuncCOSET_LEADERS_INNER_8BITS( Obj v, w; UInt lenv, lenw, q; + RequirePlainList(SELF_NAME, veclis); RequireSmallInt(SELF_NAME, weight); RequireSmallInt(SELF_NAME, tofind); + RequirePlainList(SELF_NAME, leaders); lenv = LEN_PLIST(veclis); q = LEN_PLIST(felts); diff --git a/src/vecgf2.c b/src/vecgf2.c index 69f1c9e8a1..6c3e64a1c2 100644 --- a/src/vecgf2.c +++ b/src/vecgf2.c @@ -3262,8 +3262,10 @@ static Obj FuncCOSET_LEADERS_INNER_GF2( Obj v, w; UInt lenv, lenw; + RequirePlainList(SELF_NAME, veclis); RequireSmallInt(SELF_NAME, weight); RequireSmallInt(SELF_NAME, tofind); + RequirePlainList(SELF_NAME, leaders); lenv = LEN_PLIST(veclis); NEW_GF2VEC(v, TYPE_LIST_GF2VEC, lenv); diff --git a/tst/testbugfix/2026-04-15-CosetLeadersMatFFE-errors.tst b/tst/testbugfix/2026-04-15-CosetLeadersMatFFE-errors.tst new file mode 100644 index 0000000000..75303e5941 --- /dev/null +++ b/tst/testbugfix/2026-04-15-CosetLeadersMatFFE-errors.tst @@ -0,0 +1,8 @@ +# Regression test for square matrices and invalid dependent input in +# CosetLeadersMatFFE. +gap> M := IdentityMat(2, GF(2));; +gap> L := CosetLeadersMatFFE(M, GF(2));; +gap> Length(L); +4 +gap> CosetLeadersMatFFE(L, GF(2)); +Error, CosetLeadersMatFFE: must have linearly independent rows From 9a3b1b1047eab23f37b26994ed884e39753b57f6 Mon Sep 17 00:00:00 2001 From: Max Horn Date: Mon, 4 May 2026 19:28:42 +0100 Subject: [PATCH 198/234] Fix MinimalGeneratingSet for pc groups (#6340) It sometimes produced incorrect results, where at least one generator was simply redundant. Revisit the pc-group candidates when a layer contracts. This drops generators that were only needed earlier. Later layer adjustments can change the induced pcgs. AI-assisted by Codex for investigation, testing, and implementation. Co-authored-by: Codex --- lib/grppcatr.gi | 29 +++++++++++++++++++++++- tst/testbugfix/2026-04-20-issue-5771.tst | 29 ++++++++++++++++++++++++ 2 files changed, 57 insertions(+), 1 deletion(-) create mode 100644 tst/testbugfix/2026-04-20-issue-5771.tst diff --git a/lib/grppcatr.gi b/lib/grppcatr.gi index b0f171adf7..0f9a42d7bf 100644 --- a/lib/grppcatr.gi +++ b/lib/grppcatr.gi @@ -541,6 +541,27 @@ RedispatchOnCondition( MaximalNormalSubgroups, true, [ IsSolvableGroup ], 0); +############################################################################# +## +#F ReduceMinGens( , , ) +## +BindGlobal( "ReduceMinGens", function( pcgs, pcgsN, min ) + local i, new; + + # Later layer refinements can make a previously appended generator + # redundant. Re-test the current candidates against the bottom layer. + i := 1; + while i <= Length( min ) do + new := min{Filtered([1..Length( min )], j -> j <> i)}; + if Length( InducedPcgsByPcSequenceAndGenerators( pcgs, pcgsN, new ) ) + = Length( pcgs ) then + Remove( min, i ); + else + i := i + 1; + fi; + od; +end ); + ############################################################################# ## #F ModifyMinGens( , , , ) @@ -551,7 +572,8 @@ BindGlobal( "ModifyMinGens", function( pcgs, pcgsS, pcgsL, min ) # set up pcgsF := pcgsS mod pcgsL; - # try to modify mingens + # Try to absorb a generator from the current factor into one of the + # existing candidates before growing the generating set. for g in pcgsF do for i in [1..Length( min )] do new := ShallowCopy( min ); @@ -598,8 +620,13 @@ BindGlobal( "MinimalGensLayer", function( pcgs, pcgsS, pcgsN, min ) pcgsV := InducedPcgsByPcSequenceAndGenerators( pcgs, pcgsL, min ); pcgsU := InducedPcgsByPcSequenceAndGenerators( pcgs, pcgsN, min ); if Length( pcgs ) = Length( pcgsV ) then + # Once the current candidates span the whole layer, continue with + # the next smaller layer and revisit any earlier append decisions. pcgsS := pcgsL; Remove(series); + ReduceMinGens( pcgs, pcgsN, min ); + pcgsV := InducedPcgsByPcSequenceAndGenerators( pcgs, pcgsS, min ); + pcgsU := InducedPcgsByPcSequenceAndGenerators( pcgs, pcgsN, min ); fi; od; return min; diff --git a/tst/testbugfix/2026-04-20-issue-5771.tst b/tst/testbugfix/2026-04-20-issue-5771.tst new file mode 100644 index 0000000000..ea28b64c29 --- /dev/null +++ b/tst/testbugfix/2026-04-20-issue-5771.tst @@ -0,0 +1,29 @@ +## Regression test for #5771. The MinimalGeneratingSet method for pc-groups +## greedily appended a fifth generator, even though later adjustments make +## that generator redundant. The minimal generating set for this group has +## size 4, but GAP gave one of size 5, with one redundant generator. + +gap> START_TEST("2026-04-20-issue-5771.tst"); +gap> G := function() +> local f, g, g1, g2, g3, g4, g5, g6, g7, g8, g9, rws, rels, x; +> f := FreeGroup(IsSyllableWordsFamily, 9); +> g := GeneratorsOfGroup(f); +> g1 := g[1]; g2 := g[2]; g3 := g[3]; g4 := g[4]; g5 := g[5]; +> g6 := g[6]; g7 := g[7]; g8 := g[8]; g9 := g[9]; +> rws := SingleCollector(f, [ 2, 2, 2, 2, 3, 3, 3, 3, 3 ]); +> rels := [ +> [5,1,g5], [9,1,g9], [5,2,g5], [6,2,g6], [7,2,g7], +> [8,2,g8], [9,2,g9], [6,3,g6], [7,3,g7], [8,3,g8], +> [5,4,g5], [6,4,g6], [7,4,g7], [8,4,g8], [9,4,g9] +> ]; +> for x in rels do +> SetCommutator(rws, x[1], x[2], x[3]); +> od; +> return GroupByRwsNC(rws); +> end();; +gap> m := MinimalGeneratingSet(G);; +gap> Length(m) = 4 and +> ForAll([1..Length(m)], +> i -> Index(G, SubgroupNC(G, m{Filtered([1..Length(m)], j -> j <> i)})) > 1); +true +gap> STOP_TEST("2026-04-20-issue-5771.tst"); From 0f408eec37f1a54bfff279565f2793c0285d8f79 Mon Sep 17 00:00:00 2001 From: Kamil Zabielski <50334623+limakzi@users.noreply.github.com> Date: Mon, 4 May 2026 20:48:24 +0100 Subject: [PATCH 199/234] Add `WhereDepth` user preference (#6261) ... to control depth of initial stack trace in break loops --- doc/ref/mloop.xml | 11 ++++++++++- lib/error.g | 7 +++++-- lib/init.g | 10 ++++++++++ tst/testspecial/run_gap.sh | 1 + tst/testspecial/stack-trace-depth.g | 5 ++++- tst/testspecial/stack-trace-depth.g.out | 18 ++++++++++++++++-- 6 files changed, 46 insertions(+), 6 deletions(-) diff --git a/doc/ref/mloop.xml b/doc/ref/mloop.xml index ca1a723482..b39f2f50e8 100644 --- a/doc/ref/mloop.xml +++ b/doc/ref/mloop.xml @@ -739,12 +739,21 @@ is an example in the &GAP; code where the idea is actually used. Backtrace Stack trace shows the last nr commands on the execution stack during whose execution -the error occurred. If not given, nr defaults to 5. (Assume, for the +the error occurred. If not given, nr defaults to the value of the +WhereDepth user preference (initially 5). +If nr or the WhereDepth preference is not a non-negative integer, +it is treated as 5. +(Assume, for the following example, that after the last example has been set back to its default value.). acts the same as while also showing the arguments and local variables of each function.

+ acts the same as while also +showing the arguments and local variables of each function. +

+The following example assumes that is set to its default +value. StabChain(SymmetricGroup(1000)); # After this we typed ^C Error, user interrupt diff --git a/lib/error.g b/lib/error.g index fe1040a6ac..f43ab34778 100644 --- a/lib/error.g +++ b/lib/error.g @@ -180,6 +180,9 @@ end); BIND_GLOBAL("WHERE_INTERNAL", function(depth, showlocals) local activecontext; + if not IsInt(depth) or depth < 0 then + depth := 5; + fi; if ErrorLVars = fail or ErrorLVars = GetBottomLVars() then PrintTo(ERROR_OUTPUT, "not in any function "); else @@ -192,7 +195,7 @@ end); BIND_GLOBAL("WhereWithVars", function(arg) local depth; if LEN_LIST(arg) = 0 then - depth := 5; + depth := UserPreference("WhereDepth"); else depth := arg[1]; fi; @@ -203,7 +206,7 @@ end); BIND_GLOBAL("Where", function(arg) local depth; if LEN_LIST(arg) = 0 then - depth := 5; + depth := UserPreference("WhereDepth"); else depth := arg[1]; fi; diff --git a/lib/init.g b/lib/init.g index 810305951f..03601c810a 100644 --- a/lib/init.g +++ b/lib/init.g @@ -582,6 +582,16 @@ DeclareUserPreference( rec( default:= 3, check:= val -> IsInt( val ) and 0 <= val, ) ); +DeclareUserPreference( rec( + name:= "WhereDepth", + description:= [ + "The number of stack frames shown by Where and WhereWithVars \ +when called without an explicit depth argument, e.g. in the default OnBreak \ +handler." + ], + default:= 5, + check:= val -> IsInt( val ) and 0 <= val, + ) ); DeclareUserPreference( rec( name:= "ReproducibleBehaviour", description:= [ diff --git a/tst/testspecial/run_gap.sh b/tst/testspecial/run_gap.sh index 9ba7c29a65..aa7f088494 100755 --- a/tst/testspecial/run_gap.sh +++ b/tst/testspecial/run_gap.sh @@ -18,6 +18,7 @@ GAPROOT=$("$gap" --print-gaproot) ( echo "LogTo(\"${outfile}.tmp\");" ; cat "$gfile" ; echo "QUIT;" ) | "$gap" -r -A -b -m 256m -o 512m -x 800 \ -c 'SetUserPreference("UseColorsInTerminal",false);' \ + -c 'SetUserPreference("WhereDepth", 5);' \ 2>/dev/null >/dev/null sed -E -e "s:${GAPROOT//:/\\:}:GAPROOT/:g" -e "s;(GAPROOT(/[^/]+)+):[0-9]+;\1:LINE;g" < "${outfile}.tmp" > "${outfile}" rm "${outfile}.tmp" diff --git a/tst/testspecial/stack-trace-depth.g b/tst/testspecial/stack-trace-depth.g index dde6f2571b..28e525dbf2 100644 --- a/tst/testspecial/stack-trace-depth.g +++ b/tst/testspecial/stack-trace-depth.g @@ -32,5 +32,8 @@ f1 := function() return f2(); end;; f1(); -Where(12); +SetUserPreference("WhereDepth", 12); +Where(); +SetUserPreference("WhereDepth", 5); +Where(); quit; diff --git a/tst/testspecial/stack-trace-depth.g.out b/tst/testspecial/stack-trace-depth.g.out index 0005d8c5c7..7a30baca80 100644 --- a/tst/testspecial/stack-trace-depth.g.out +++ b/tst/testspecial/stack-trace-depth.g.out @@ -47,7 +47,8 @@ Stack trace: ... at *stdin*:35 you can 'quit;' to quit to outer loop, or you can 'return;' to continue -brk> Where(12); +brk> SetUserPreference("WhereDepth", 12); +brk> Where(); * [1] Error( "foo" ); @ *stdin*:3 [2] f11( ) @@ -71,6 +72,19 @@ brk> Where(12); [11] f2( ) @ *stdin*:33 ( ) - called from read-eval loop at *errin*:1 + called from read-eval loop at *errin*:2 +brk> SetUserPreference("WhereDepth", 5); +brk> Where(); +*[1] Error( "foo" ); + @ *stdin*:3 + [2] f11( ) + @ *stdin*:6 + [3] f10( ) + @ *stdin*:9 + [4] f9( ) + @ *stdin*:12 + [5] f8( ) + @ *stdin*:15 +... at *errin*:4 brk> quit; gap> QUIT; From 7fab2f8b5858330c2c7bbe253a0e6ef62235baf3 Mon Sep 17 00:00:00 2001 From: Max Horn Date: Mon, 4 May 2026 22:02:55 +0100 Subject: [PATCH 200/234] doc: streamline Matrix argument variants (#6361) --- doc/ref/matobj.xml | 2 +- lib/matobj2.gd | 31 +++++++------------------------ 2 files changed, 8 insertions(+), 25 deletions(-) diff --git a/doc/ref/matobj.xml b/doc/ref/matobj.xml index 2818815902..ddbaa2871d 100644 --- a/doc/ref/matobj.xml +++ b/doc/ref/matobj.xml @@ -429,7 +429,7 @@ and then set the entries in this matrix. Functions like , , -and +and admit different kinds of inputs. ZeroMatrix( R, m, n ) can be used, for example, if we want to leave the decision about the representation of the result diff --git a/lib/matobj2.gd b/lib/matobj2.gd index 21f4af9a32..e2f457d734 100644 --- a/lib/matobj2.gd +++ b/lib/matobj2.gd @@ -1262,28 +1262,11 @@ DeclareOperation( "CompanionMatrix", ## <#GAPDoc Label="MatObj_Matrix"> ## ## Matrix -## -## -## -## -## -## -## -## -## -## -## +## +## +## +## +## ## ## a matrix object ## @@ -1292,7 +1275,7 @@ DeclareOperation( "CompanionMatrix", ## ## value filt, is defined over the base domain R, ## and has the entries given by the list list or the matrix object -## M, respectively. +## matobj, respectively. ## Here list can be either a list of plain lists that describe the ## entries of the rows, or a flat list of the entries in row major order, ## where ncols defines the number of columns. @@ -1324,7 +1307,7 @@ DeclareOperation( "CompanionMatrix", ## If the ## value of the result implies then the result is ## mutable if and only if the argument that determines the entries of the -## result (list, M, M1) is mutable. +## result (list or matobj) is mutable. ##

## In the case of a mutable result, it is guaranteed that the given list ## list is copied in the sense of , From 67cea730476af895b3ab741aedc248ff4d08ef98 Mon Sep 17 00:00:00 2001 From: Kamil Zabielski <50334623+limakzi@users.noreply.github.com> Date: Tue, 5 May 2026 16:16:11 +0100 Subject: [PATCH 201/234] Document DirectProductElement (#6260) --- doc/ref/mapping.xml | 1 + lib/tuples.gd | 53 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 54 insertions(+) diff --git a/doc/ref/mapping.xml b/doc/ref/mapping.xml index cd94676317..e1928ba20a 100644 --- a/doc/ref/mapping.xml +++ b/doc/ref/mapping.xml @@ -40,6 +40,7 @@ section . Direct Products and their Elements <#Include Label="IsDirectProductElement"> +<#Include Label="DirectProductElement"> <#Include Label="DirectProductFamily">

diff --git a/lib/tuples.gd b/lib/tuples.gd index bf644d6751..743a031bcc 100644 --- a/lib/tuples.gd +++ b/lib/tuples.gd @@ -147,13 +147,66 @@ BindGlobal( "EmptyDirectProductElementsFamily", #O DirectProductElementNC( , ) . . . . omits check on object #O families and objlist length ## +## <#GAPDoc Label="DirectProductElement"> ## ## ## ## ## +## returns a direct product element +## whose components are the entries of the list objlist. +## If the optional argument fam is given, it must be the family of +## direct product elements with the appropriate component families; +## otherwise the family is determined from objlist. +##

+## does the same but omits the checks +## that fam is consistent with objlist. +##

+## Direct product elements behave like lists: they can be indexed with +## elm[i] to access the i-th component, and +## returns the number of components. +## Arithmetic operations (multiplication, powering, one, inverse, +## addition, zero, additive inverse) are performed componentwise. +## a := (1,2,3);; b := (1,2);; +## gap> elm := DirectProductElement([a, b]); +## DirectProductElement( [ (1,2,3), (1,2) ] ) +## gap> elm[1]; +## (1,2,3) +## gap> elm[2]; +## (1,2) +## gap> Length(elm); +## 2 +## gap> elm2 := DirectProductElement([b, a]);; +## gap> elm * elm2; +## DirectProductElement( [ (2,3), (1,3) ] ) +## gap> One(elm); +## DirectProductElement( [ (), () ] ) +## gap> Inverse(elm); +## DirectProductElement( [ (1,3,2), (1,2) ] ) +## ]]> +##

+## The following example shows in the +## context of a direct product K = G \times H built with +## , where G is a permutation group and +## H is a pc group. The projections of K are +## used to move between the direct product and its component groups. +## G := DihedralGroup(IsPermGroup, 8);; +## gap> H := CyclicGroup(IsPcGroup, 4);; +## gap> K := DirectProduct(G, H);; +## gap> proj1 := Projection(K, 1);; proj2 := Projection(K, 2);; +## gap> g := (1,2,3,4);; h := GeneratorsOfGroup(H)[1];; +## gap> elm := DirectProductElement([g, h]); +## DirectProductElement( [ (1,2,3,4), f1 ] ) +## gap> Image(proj1, elm) = g; +## true +## gap> Image(proj2, elm) = h; +## true +## ]]> ## ## +## <#/GAPDoc> ## DeclareOperation( "DirectProductElement", [ IsList ]); DeclareOperation( "DirectProductElementNC", From 42a0ea6c2e9b3a4576c130e16fed67dc6cf51087 Mon Sep 17 00:00:00 2001 From: Thomas Breuer Date: Wed, 6 May 2026 01:47:49 +0200 Subject: [PATCH 202/234] Reset the options stack after an error also when the break loop is disabled (`-T` command line option) (#6355) --- lib/error.g | 12 ++++++++---- lib/package.gi | 5 +++-- tst/testinstall/error.tst | 10 ++++++++++ 3 files changed, 21 insertions(+), 6 deletions(-) diff --git a/lib/error.g b/lib/error.g index f43ab34778..de03ee813f 100644 --- a/lib/error.g +++ b/lib/error.g @@ -32,13 +32,14 @@ ERROR_OUTPUT := MakeImmutable("*errout*"); Unbind(OnQuit); BIND_GLOBAL( "OnQuit", function() if not IsEmpty(OptionsStack) then + if IsBound(ResetMethodReordering) and IsFunction(ResetMethodReordering) + and ValueOption( "ReadingPackageFiles" ) = true then + ResetMethodReordering(); + fi; repeat PopOptions(); until IsEmpty(OptionsStack); - Info(InfoWarning,1,"Options stack has been reset"); - fi; - if IsBound(ResetMethodReordering) and IsFunction(ResetMethodReordering) then - ResetMethodReordering(); + Info(InfoWarning,2,"Options stack has been reset"); fi; if REREADING = true then MakeReadWriteGlobal("REREADING"); @@ -373,6 +374,9 @@ BIND_GLOBAL("ErrorInner", function(options, earlyMessage) ErrorLVars := errorLVars; ErrorTracebackLVars := errorTracebackLVars; SET_ERROR_LVARS(kernelErrorLVars); + if IsBound(OnQuit) and IsFunction(OnQuit) then + OnQuit(); + fi; if ErrorLevel = 0 then LEAVE_ALL_NAMESPACES(); fi; JUMP_TO_CATCH(0); fi; diff --git a/lib/package.gi b/lib/package.gi index fbd23eda01..1930c9d6fd 100644 --- a/lib/package.gi +++ b/lib/package.gi @@ -1750,7 +1750,7 @@ InstallGlobalFunction( LoadPackage, function( arg ) "start reading file 'init.g'", info.PackageName ); GAPInfo.PackageCurrent:= info; - ReadPackage( pkgname, "init.g" ); + ReadPackage( pkgname, "init.g" : ReadingPackageFiles:= true ); Unbind( GAPInfo.PackageCurrent ); LogPackageLoadingMessage( PACKAGE_DEBUG, "finish reading file 'init.g'", @@ -1766,7 +1766,8 @@ InstallGlobalFunction( LoadPackage, function( arg ) # (We have delayed this until now because it uses functionality # from the package GAPDoc.) # Note that no banners are printed during autoloading. - LoadPackage_ReadImplementationParts( secondrun, banner ); + LoadPackage_ReadImplementationParts( secondrun, banner + : ReadingPackageFiles:= true ); secondrun:= []; od; diff --git a/tst/testinstall/error.tst b/tst/testinstall/error.tst index 9cb0d353f7..cf590212f9 100644 --- a/tst/testinstall/error.tst +++ b/tst/testinstall/error.tst @@ -34,3 +34,13 @@ gap> if false then Stabilizer; fi; Syntax error: found an expression when a statement was expected in stream:1 if false then Stabilizer; fi; ^ + +# +gap> oldBreakOnError:= BreakOnError;; +gap> BreakOnError:= false;; +gap> PushOptions( rec( test:= true ) ); +gap> Error( "!" ); +Error, ! +gap> Length( OptionsStack ) = 0; +true +gap> BreakOnError:= oldBreakOnError;; From e4f7606b596fa6e60c6a2716c9b7c10de801e750 Mon Sep 17 00:00:00 2001 From: Max Horn Date: Wed, 6 May 2026 01:25:32 +0100 Subject: [PATCH 203/234] Guard some `IdGroup` calls by `ID_AVAILABLE` (#6353) ... instead of hardcoding assumptions about the availability of IdGroup. --- lib/grplatt.gi | 13 ++++++------- lib/grpnames.gi | 2 +- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/lib/grplatt.gi b/lib/grplatt.gi index 6b170d1f82..68eea8dd71 100644 --- a/lib/grplatt.gi +++ b/lib/grplatt.gi @@ -2760,15 +2760,14 @@ local fgi,inducedfactorautos,projs,psubs,info,n,l,nl,emb,u,pos, fi; fgi:=function(gp,nor) - local idx,hom,l,f; - idx:=Index(gp,nor); + local hom,l,f; hom:=NaturalHomomorphismByNormalSubgroup(gp,nor); - if idx>1000 or idx=512 or not uselib then - l:=[idx,fail]; + f:=Image(hom); + if uselib and Size(f) < 1000 and ID_AVAILABLE(Size(f)) <> fail then + l:=ShallowCopy(IdGroup(f)); else - l:=ShallowCopy(IdGroup(gp/nor)); + l:=[Size(f),fail]; fi; - f:=Image(hom,gp); Add(l,hom); Add(l,f); Add(l,AutomorphismGroup(f)); @@ -2836,7 +2835,7 @@ local fgi,inducedfactorautos,projs,psubs,info,n,l,nl,emb,u,pos, for k in no do hom:=NaturalHomomorphismByNormalSubgroup(j[1],k.representative); f:=Image(hom); - if Size(f)<1000 and Size(f)<>512 and uselib then + if uselib and Size(f) < 1000 and ID_AVAILABLE(Size(f)) <> fail then myid:=ShallowCopy(IdGroup(f)); else myid:=[Size(f),fail]; diff --git a/lib/grpnames.gi b/lib/grpnames.gi index f3fa6cce4c..fc9851910e 100644 --- a/lib/grpnames.gi +++ b/lib/grpnames.gi @@ -1861,7 +1861,7 @@ BindGlobal( "StructureDescriptionForFiniteGroups", # for finite groups # fetch name from precomputed list, if available if ValueOption("recompute") <> true and Size(G) <= 2000 then - if IsBound(NAMES_OF_SMALL_GROUPS[Size(G)]) then + if IsBound(NAMES_OF_SMALL_GROUPS[Size(G)]) and ID_AVAILABLE(Size(G)) <> fail then i := IdGroup(G)[2]; if IsBound(NAMES_OF_SMALL_GROUPS[Size(G)][i]) then name := ShallowCopy(NAMES_OF_SMALL_GROUPS[Size(G)][i]); From 537d49ef81729179874eb03dd86a22b3ae80cce6 Mon Sep 17 00:00:00 2001 From: Thomas Breuer Date: Wed, 6 May 2026 02:43:15 +0200 Subject: [PATCH 204/234] Add `RandomMatrix`, `RandomInvertibleMatrix`; and fix a problem with a new feature for matrix groups (#6232) - add a description of the cache `FULLGLNICOCACHE` in the code; it is used only by `NicomorphismFFMatGroupOnFullSpace` - change the keys of `FULLGLNICOCACHE`: take the field of the matrix entries into account (not only its size), take the `ConstructingFilter` of the matrices into account - in `NicomorphismFFMatGroupOnFullSpace`, deal with special cases of matrices in `IsBlockMatrixRep` (which have no `ConstructingFilter`) and in `Is8BitMatrixRep` in the situation that the group itself lives over `GF(2)` - in order to admit the action of `IsMatrixObj` matrices on vectors supported by GAP's `Enumerator`s of vector spaces, add a `\^` method that `Unpack`s the matrix object (Eventually we want to avoid this overhead, but then we need `Enumerator`s consisting of vector objects corresponding to the matrix objects.) - add `Matrix` calls in the function that computes preimages under an action homomorphism with `Source` a matrix group, in order to support matrix group elements of prescribed kinds of `IsMatrixObj`. - add tests for the new supported situations (most of the changes were actually forced by already available tests) * add `\in` methods for matrix object and (`GL` or `SL`) * avoid some `Unpack` hacks - introduce `NormedRowVectors_internal( F, base )`, and `AsListOfFreeLeftModule_internal( F, base, zero )`, in order to admit `IsVectorObj`s in `base` without supporting the whole vector space machinery for these objects - introduce `ExternalSet( G )` for matrix groups `G`, meaning the natural `G`-set (an undocumented method for permutation groups `G` was already available) - change `NicomorphismFFMatGroupOnFullSpace` such that we can act with the `IsMatrixObj` matrices on their `IsVectorObj` vectors, without unpacking the matrices - support `IsMatrixObj` matrices in the `Random` methods for GL and SL * adjust also `IsProjectiveActionHomomorphism` methods * add `RandomMatrix`, `RandomInvertibleMatrix` and fix the `RankMat` method for `IsPlistMatrixRep` --- doc/ref/matrix.xml | 2 + grp/classic.gd | 2 +- lib/grpffmat.gi | 158 +++++++++++++--- lib/matobjplist.gi | 8 +- lib/matrix.gd | 174 +++++++++++++++++- lib/matrix.gi | 111 +++++++++++ lib/methsel.g | 24 +++ lib/modfree.gi | 24 ++- lib/oprt.gi | 100 +++++++--- lib/vspcrow.gi | 60 +++--- tst/testbugfix/2007-07-02-t00180.tst | 2 +- .../MatrixObj/DeterminantMatrix.tst | 29 +++ .../MatrixObj/RandomInvertibleMatrix.tst | 52 ++++++ tst/testinstall/MatrixObj/RandomMatrix.tst | 72 ++++++++ tst/testinstall/MatrixObj/RankMatrix.tst | 23 +++ tst/testinstall/MatrixObj/acthom.tst | 80 ++++++++ tst/testinstall/grpmat.tst | 18 +- 17 files changed, 826 insertions(+), 113 deletions(-) create mode 100644 tst/testinstall/MatrixObj/DeterminantMatrix.tst create mode 100644 tst/testinstall/MatrixObj/RandomInvertibleMatrix.tst create mode 100644 tst/testinstall/MatrixObj/RandomMatrix.tst create mode 100644 tst/testinstall/MatrixObj/RankMatrix.tst create mode 100644 tst/testinstall/MatrixObj/acthom.tst diff --git a/doc/ref/matrix.xml b/doc/ref/matrix.xml index 59f006dbfd..e80f6b2419 100644 --- a/doc/ref/matrix.xml +++ b/doc/ref/matrix.xml @@ -341,7 +341,9 @@ see . Random Matrices <#Include Label="RandomMat"> +<#Include Label="RandomMatrix"> <#Include Label="RandomInvertibleMat"> +<#Include Label="RandomInvertibleMatrix"> <#Include Label="RandomUnimodularMat"> diff --git a/grp/classic.gd b/grp/classic.gd index 0bfd9b3b4b..ae891da7be 100644 --- a/grp/classic.gd +++ b/grp/classic.gd @@ -836,7 +836,7 @@ BindGlobal( "SymplecticGroup", function ( arg ) rep:= filt; filt:= IsMatrixGroup; else - rep:= fail; + rep:= ValueOption( "ConstructingFilter" ); fi; if DescribesInvariantBilinearForm( Last( arg ) ) then form:= Remove( arg ); diff --git a/lib/grpffmat.gi b/lib/grpffmat.gi index 147563c60b..2f63b1c1d3 100644 --- a/lib/grpffmat.gi +++ b/lib/grpffmat.gi @@ -124,31 +124,80 @@ end ); ############################################################################# ## -#M NiceMonomorphism( ) +## the natural G-set of a matrix group consists of the vectors of the +## natural module +## +InstallOtherMethod( ExternalSet, + [ IsFFEMatrixGroup and IsFinite ], + function( G ) + local basis, zero; + + basis:= RowsOfMatrix( One( G ) ); + zero:= Zero( basis[1] ); + return ExternalSet( G, AsListOfFreeLeftModule_internal( + FieldOfMatrixGroup( G ), basis, zero ) ); +end ); + +############################################################################# +## +#V FULLGLNICOCACHE +## +## 'NicomorphismFFMatGroupOnFullSpace' uses a cache of length up to 5, +## as follows. +## +## - If the argument is a matrix group that fits to an entry of this +## cache, in the sense that dimension, field of definition, +## and 'ConstructingFilter' of the matrices in the group are the same as +## for the cached value, the stored mapping is returned. +## - If a new mapping has to be constructed, the first cached entry is +## dropped and the new mapping gets added to the cache. ## MakeThreadLocal("FULLGLNICOCACHE"); # avoid recreating same homom. repeatedly -FULLGLNICOCACHE:=[]; -InstallGlobalFunction( NicomorphismFFMatGroupOnFullSpace, function( grp ) - local field, dim, V, xset, nice; +BindGlobal( "FULLGLNICOCACHE", [] ); - field := FieldOfMatrixGroup( grp ); - dim := DimensionOfMatrixGroup( grp ); + +############################################################################# +## +#M NiceMonomorphism( ) +## +InstallGlobalFunction( NicomorphismFFMatGroupOnFullSpace, function( grp ) + local rep, filt, q, dim, field, xset, nice; + + rep:= Representative( grp ); + field:= FieldOfMatrixGroup( grp ); + q:= Size( field ); + if IsBlockMatrixRep( rep ) then + # There is no support for these matrices acting on vectors. + filt:= IsPlistRep; + elif q = 2 and Is8BitMatrixRep( rep ) then + # We cannot keep both 'field' and 'Is8BitMatrixRep', + # the latter does not admit matrices over GF(2). + filt:= IsGF2MatrixRep; +#TODO: How can we get rid of these hacks? + else + filt:= ConstructingFilter( rep ); + fi; + 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; + nice:= First( FULLGLNICOCACHE, + x -> x[1] = field and x[2] = dim and x[3] = filt ); + + if nice<>fail then return nice[4];fi; if not (HasIsNaturalGL(grp) and IsNaturalGL(grp)) then - grp:=GL(dim,field); # enforce map on full GL + # enforce map on full GL + grp:= GL( dim, field : ConstructingFilter:= filt ); fi; - V := field ^ dim; - xset := ExternalSet( grp, V ); - + xset := ExternalSet( grp ); # STILL: reverse the base to get point sorting compatible with lexicographic # vector arrangement - SetBaseOfGroup( xset, One( grp )); + if IsList( One( grp ) ) then + SetBaseOfGroup( xset, One( grp )); + else + SetBaseOfGroup( xset, RowsOfMatrix( One( grp ) ) ); + fi; nice := ActionHomomorphism( xset,"surjective" ); SetIsInjective( nice, true ); if not HasNiceMonomorphism(grp) then @@ -156,14 +205,14 @@ InstallGlobalFunction( NicomorphismFFMatGroupOnFullSpace, function( grp ) fi; # because we act on the full space we are canonical. SetIsCanonicalNiceMonomorphism(nice,true); - if Size(V)>10^5 then + if q^dim > 10^5 then # store only one big one and have it get thrown out quickly - FULLGLNICOCACHE[1]:=[Size(field),dim,nice]; + FULLGLNICOCACHE[1]:= [ field, dim, filt, nice ]; else if Length(FULLGLNICOCACHE)>4 then - FULLGLNICOCACHE:=FULLGLNICOCACHE{[2..5]}; + Remove( FULLGLNICOCACHE, 1 ); fi; - Add(FULLGLNICOCACHE,[Size(field),dim,nice]); + Add( FULLGLNICOCACHE, [ field, dim, filt, nice ] ); fi; return nice; @@ -190,8 +239,7 @@ local tt; # if the permutation image would be too large, compute the orbit. TryNextMethod(); fi; - return NicomorphismFFMatGroupOnFullSpace( GL( DimensionOfMatrixGroup( grp ), - Size( FieldOfMatrixGroup( Parent(grp) ) ) ) ); + return NicomorphismFFMatGroupOnFullSpace( grp ); end ); ############################################################################# @@ -256,6 +304,25 @@ InstallMethod( \in, "general linear group", IsElmsColls, and Length( mat ) = RankMat( mat ); end ); +InstallMethod( \in, "general linear group", IsElmsColls, + [ IsMatrixObj, IsFFEMatrixGroup and IsFinite and IsNaturalGL ], 0, + function( mat, G ) + local n, F; + n:= NumberRows( mat ); + F:= FieldOfMatrixGroup( G ); + return n = NumberColumns( mat ) + and n = DimensionOfMatrixGroup( G ) + and n = RankMat( mat ) +#TODO: +# Currently we cannot force the rule that all matrices in a matrix +# group consisting of matrix objects have the same 'BaseDomain', +# and that this common 'BaseDomain' is equal to the 'FieldOfMatrixGroup' +# of the group. +# Eventually we want 'true' only if 'F = BaseDomain( mat )' holds. + and ( IsSubset( F, BaseDomain( mat ) ) or + ForAll( Unpack( mat ), row -> IsSubset( F, row ) ) ); +end ); + InstallMethod( \in, "special linear group", IsElmsColls, [ IsMatrix, IsFFEMatrixGroup and IsFinite and IsNaturalSL ], 0, function( mat, G ) @@ -266,6 +333,19 @@ InstallMethod( \in, "special linear group", IsElmsColls, and DeterminantMat(mat)=One(FieldOfMatrixGroup( G )); end ); +InstallMethod( \in, "special linear group", IsElmsColls, + [ IsMatrixObj, IsFFEMatrixGroup and IsFinite and IsNaturalSL ], 0, + function( mat, G ) + local n, F; + n:= NumberRows( mat ); + F:= FieldOfMatrixGroup( G ); + return n = NumberColumns( mat ) + and n = DimensionOfMatrixGroup( G ) + and ( IsSubset( F, BaseDomain( mat ) ) or + ForAll( Unpack( mat ), row -> IsSubset( F, row ) ) ) + and DeterminantMat( mat ) = One( F ); +end ); + ############################################################################# ## @@ -508,10 +588,23 @@ InstallMethodWithRandomSource( Random, "for a random source and natural GL", [ IsRandomSource, IsFFEMatrixGroup and IsFinite and IsNaturalGL ], function(rs, G) - local m; - m := RandomInvertibleMat( rs, DimensionOfMatrixGroup( G ), - FieldOfMatrixGroup( G ) ); - return ImmutableMatrix(FieldOfMatrixGroup(G), m, true); + local d, F, m; + + d:= DimensionOfMatrixGroup( G ); + F:= FieldOfMatrixGroup( G ); + m:= Representative( G ); + if IsMatrix( m ) then + m:= RandomInvertibleMat( rs, d, F ); + m:= ImmutableMatrix(F, m, true); + else + m:= ZeroMatrix( d, d, m ); + repeat + Randomize( rs, m ); + until RankMat( m ) = d; + MakeImmutable( m ); + fi; + + return m; end); @@ -527,11 +620,18 @@ InstallMethodWithRandomSource( Random, "for a random source and natural SL", [ IsRandomSource, IsFFEMatrixGroup and IsFinite and IsNaturalSL ], function(rs, G) - local m; - m:= RandomInvertibleMat( rs, DimensionOfMatrixGroup( G ), - FieldOfMatrixGroup( G ) ); - MultVector(m[1], DeterminantMat(m)^-1); - return ImmutableMatrix(FieldOfMatrixGroup(G), m, true); + local d, m; + + # We assume that all elements in the group have the same + # 'BaseDomain' value, hence we may take any 'Representative'. + # see the section "Groups Consisting of Matrix Objects" + # in the Reference Manual. + d:= DimensionOfMatrixGroup( G ); + m:= RandomInvertibleMatrix( rs, d, Representative( G ) ); + MultMatrixRow( m, 1, DeterminantMatrix( m )^-1 ); + MakeImmutable( m ); + + return m; end); ############################################################################# diff --git a/lib/matobjplist.gi b/lib/matobjplist.gi index cafe1dd7d6..69a5106d54 100644 --- a/lib/matobjplist.gi +++ b/lib/matobjplist.gi @@ -1218,7 +1218,13 @@ InstallMethod( InverseSameMutability, InstallMethod( RankMat, [ "IsPlistMatrixRep" ], - M -> RankMat( List( M![ROWSPOS], x -> x![ELSPOS] ) ) ); + function( M ) + M:= M![ROWSPOS]; + if Length( M ) = 0 then + return 0; + fi; + return RankMat( List( M, x -> x![ELSPOS] ) ); + end ); InstallMethodWithRandomSource( Randomize, "for a random source and a mutable plist matrix", diff --git a/lib/matrix.gd b/lib/matrix.gd index 8056c80165..4fe2262981 100644 --- a/lib/matrix.gd +++ b/lib/matrix.gd @@ -1887,6 +1887,82 @@ DeclareGlobalFunction( "DiagonalMat" ); DeclareGlobalFunction( "ReflectionMat" ); +############################################################################# +## +#O RandomInvertibleMatrix( [, ][, ], ) +#O RandomInvertibleMatrix( [, ], ) +## +## <#GAPDoc Label="RandomInvertibleMatrix"> +## +## +## +## +## +## a matrix or matrix object I with m columns, +## with base domain R or equal to BaseDomain( M ), +## such that I is invertible over its base domain. +## +## +## If a semiring R is given then it will be the base domain +## (see ) +## of the returned matrix. +## In this case, a filter filt can be specified that defines the +## internal representation of the result +## (see ). +## The default value for filt is determined from R. +##

+## If a matrix object M is given then the returned matrix will have +## the same internal representation and the same base domain as M. +##

+## If a random source rs is given (see ) +## then the entries of the result are computed using rs, +## the default random source is . +##

+## If the value +## of the result implies then the result is +## fully mutable. +##

+## m:= RandomInvertibleMatrix( GF(9), 2 );; +## gap> RankMatrix( m ); +## 2 +## gap> DimensionsMat( m ); +## [ 2, 2 ] +## gap> BaseDomain( m ); +## GF(3^2) +## gap> Is8BitMatrixRep( m ); +## true +## gap> m1:= RandomInvertibleMatrix( IsPlistMatrixRep, GF(9), 2 );; +## gap> IsPlistMatrixRep( m1 ); +## true +## gap> m2:= RandomInvertibleMatrix( 2, m1 );; +## gap> IsPlistMatrixRep( m2 ); +## true +## gap> m:= RandomInvertibleMatrix( Integers, 2 );; +## gap> IsUnit( Integers, DeterminantMatrix( m ) ); +## true +## ]]> +## +## +## <#/GAPDoc> +## +DeclareTagBasedOperation( "RandomInvertibleMatrix", + [ IsOperation, IsRandomSource, IsSemiring, IsInt ] ); +DeclareOperation( "RandomInvertibleMatrix", + [ IsRandomSource, IsSemiring, IsInt ] ); +DeclareOperation( "RandomInvertibleMatrix", + [ IsOperation, IsSemiring, IsInt ] ); +DeclareOperation( "RandomInvertibleMatrix", + [ IsSemiring, IsInt ] ); + +DeclareOperation( "RandomInvertibleMatrix", + [ IsRandomSource, IsInt, IsMatrixOrMatrixObj ] ); +DeclareOperation( "RandomInvertibleMatrix", + [ IsInt, IsMatrixOrMatrixObj ] ); + + ############################################################################# ## #F RandomInvertibleMat( [rs ,] [, ] ) . . . random invertible matrix @@ -1900,13 +1976,19 @@ DeclareGlobalFunction( "ReflectionMat" ); ## matrix with m rows and columns with elements taken from the ring ## R, which defaults to . ## Optionally, a random source rs can be supplied. +##

+## Note that the result need not be invertible over +## the prescribed ring R. +## Use +## for creating random matrices with this stronger property. +##

## m := RandomInvertibleMat(4); -## [ [ -4, 1, 0, -1 ], [ -1, -1, 1, -1 ], [ 1, -2, -1, -2 ], -## [ 0, -1, 2, -2 ] ] +## gap> m := RandomInvertibleMat( 4, Integers ); +## [ [ 1, -4, 0, 1 ], [ 0, -2, 3, 1 ], [ 0, -2, -1, -1 ], +## [ 0, -2, 2, 4 ] ] ## gap> m^-1; -## [ [ -1/8, -11/24, 1/24, 1/4 ], [ 1/4, -13/12, -1/12, 1/2 ], -## [ -1/8, 5/24, -7/24, 1/4 ], [ -1/4, 3/4, -1/4, -1/2 ] ] +## [ [ 1, -1/14, -19/14, -4/7 ], [ 0, -1/14, -5/14, -1/14 ], +## [ 0, 5/14, -3/14, -1/7 ], [ 0, -3/14, -1/14, 2/7 ] ] ## ]]> ## ## @@ -1939,6 +2021,78 @@ DeclareGlobalFunction( "RandomInvertibleMat" ); DeclareGlobalFunction( "RandomMat" ); +############################################################################# +## +#O RandomMatrix( [, ][, ], , ) +#O RandomMatrix( [, ], , ) +## +## <#GAPDoc Label="RandomMatrix"> +## +## +## +## +## +## a matrix or matrix object with m rows and n columns, +## with base domain R or equal to BaseDomain( M ). +## +## +## If a semiring R is given then it will be the base domain +## (see ) +## of the returned matrix. +## In this case, a filter filt can be specified that defines the +## internal representation of the result +## (see ). +## The default value for filt is determined from R. +##

+## If a matrix object M is given then the returned matrix will have +## the same internal representation and the same base domain as M. +##

+## If a random source rs is given (see ) +## then the entries of the result are computed using rs, +## the default random source is . +##

+## If the value +## of the result implies then the result is +## fully mutable. +##

+## m:= RandomMatrix( GF(9), 2, 3 );; +## gap> DimensionsMat( m ); +## [ 2, 3 ] +## gap> BaseDomain( m ); +## GF(3^2) +## gap> Is8BitMatrixRep( m ); +## true +## gap> m1:= RandomMatrix( IsPlistMatrixRep, GF(9), 2, 3 );; +## gap> IsPlistMatrixRep( m1 ); +## true +## gap> m2:= RandomMatrix( 3, 4, m1 );; +## gap> DimensionsMat( m2 ); +## [ 3, 4 ] +## gap> IsPlistMatrixRep( m2 ); +## true +## ]]> +## +## +## <#/GAPDoc> +## +DeclareTagBasedOperation( "RandomMatrix", + [ IsOperation, IsRandomSource, IsSemiring, IsInt, IsInt ] ); +DeclareOperation( "RandomMatrix", + [ IsRandomSource, IsSemiring, IsInt, IsInt ] ); +DeclareOperation( "RandomMatrix", + [ IsOperation, IsSemiring, IsInt, IsInt ] ); +DeclareOperation( "RandomMatrix", + [ IsSemiring, IsInt, IsInt ] ); + +DeclareOperation( "RandomMatrix", + [ IsRandomSource, IsInt, IsInt, IsMatrixOrMatrixObj ] ); +DeclareOperation( "RandomMatrix", + [ IsInt, IsInt, IsMatrixOrMatrixObj ] ); + + ############################################################################# ## #F RandomUnimodularMat( [rs ,] ) . . . . . . . . random unimodular matrix @@ -1955,13 +2109,13 @@ DeclareGlobalFunction( "RandomMat" ); ## from Integers ## m := RandomUnimodularMat(3); -## [ [ -5, 1, 0 ], [ 12, -2, -1 ], [ -14, 3, 0 ] ] +## [ [ 1, -5, 26 ], [ 0, 1, -6 ], [ 0, 0, 1 ] ] ## gap> m^-1; -## [ [ -3, 0, 1 ], [ -14, 0, 5 ], [ -8, -1, 2 ] ] +## [ [ 1, 5, 4 ], [ 0, 1, 6 ], [ 0, 0, 1 ] ] ## gap> RandomUnimodularMat(3:domain:=[-1000..1000]); -## [ [ 312330173, 15560030349, -125721926670 ], -## [ -307290, -15309014, 123693281 ], -## [ -684293792, -34090949551, 275448039848 ] ] +## [ [ 6001314, 239514853714734, -44705745791413 ], +## [ -1448123744, -57795200635226587, 10787546189680040 ], +## [ -671, -26780118200, 4998542420 ] ] ## ]]> ## ## diff --git a/lib/matrix.gi b/lib/matrix.gi index 956cd1b41b..b5780f80f4 100644 --- a/lib/matrix.gi +++ b/lib/matrix.gi @@ -3952,6 +3952,71 @@ InstallGlobalFunction( ReflectionMat, function( arg ) end ); +######################################################################### +## +#M RandomInvertibleMatrix( [, ][, ], ) +#M RandomInvertibleMatrix( [, ], ) +## +InstallTagBasedMethod( RandomInvertibleMatrix, + function( filt, rs, R, m ) + local mat, i, j; + + if IsIntegers( R ) then + # We have a dedicated method for this case. + mat:= RandomUnimodularMat( rs, m ); + if filt <> IsPlistRep then + mat:= Matrix( filt, R, mat ); + fi; + else + # The following works if 'R' is a field or a residue class ring. + # If other rings become important, + # we have to think about a better approach. + mat:= ZeroMatrix( filt, R, m, m ); + repeat + # 'Randomize' does not admit 'R' as an argument, + # and we want to cover also 'IsPlistRep'. + for i in [ 1 .. m ] do + for j in [ 1 .. m ] do + mat[i,j]:= Random( rs, R ); + od; + od; + until IsUnit( DeterminantMat( mat ) ); + fi; + + return mat; + end ); + +InstallMethod( RandomInvertibleMatrix, + [ IsRandomSource, IsSemiring, IsInt ], + function( rs, R, m ) + return RandomInvertibleMatrix( DefaultMatrixRepForBaseDomain( R ), rs, R, m ); + end ); + +InstallMethod( RandomInvertibleMatrix, + [ IsOperation, IsSemiring, IsInt ], + function( filt, R, m ) + return RandomInvertibleMatrix( filt, GlobalMersenneTwister, R, m ); + end ); + +InstallMethod( RandomInvertibleMatrix, + [ IsSemiring, IsInt ], + function( R, m ) + return RandomInvertibleMatrix( DefaultMatrixRepForBaseDomain( R ), GlobalMersenneTwister, R, m ); + end ); + +InstallMethod( RandomInvertibleMatrix, + [ IsRandomSource, IsInt, IsMatrixOrMatrixObj ], + function( rs, m, M ) + return RandomInvertibleMatrix( ConstructingFilter( M ), rs, BaseDomain( M ), m ); + end ); + +InstallMethod( RandomInvertibleMatrix, + [ IsInt, IsMatrixOrMatrixObj ], + function( m, M ) + return RandomInvertibleMatrix( ConstructingFilter( M ), GlobalMersenneTwister, BaseDomain( M ), m ); + end ); + + ######################################################################### ## #F RandomInvertibleMat( [rs ,] [, ] ) . . . make a random invertible matrix @@ -4001,6 +4066,52 @@ InstallGlobalFunction( RandomInvertibleMat, function ( arg ) end ); +######################################################################### +## +#M RandomMatrix( [, ][, ], , ) +#M RandomMatrix( [, ], , ) +## +InstallTagBasedMethod( RandomMatrix, + function( filt, rs, R, m, n ) + local mat; + + mat:= ZeroMatrix( filt, R, m, n ); + Randomize( rs, mat ); + + return mat; + end ); + +InstallMethod( RandomMatrix, + [ IsRandomSource, IsSemiring, IsInt, IsInt ], + function( rs, R, m, n ) + return RandomMatrix( DefaultMatrixRepForBaseDomain( R ), rs, R, m, n ); + end ); + +InstallMethod( RandomMatrix, + [ IsOperation, IsSemiring, IsInt, IsInt ], + function( filt, R, m, n ) + return RandomMatrix( filt, GlobalMersenneTwister, R, m, n ); + end ); + +InstallMethod( RandomMatrix, + [ IsSemiring, IsInt, IsInt ], + function( R, m, n ) + return RandomMatrix( DefaultMatrixRepForBaseDomain( R ), GlobalMersenneTwister, R, m, n ); + end ); + +InstallMethod( RandomMatrix, + [ IsRandomSource, IsInt, IsInt, IsMatrixOrMatrixObj ], + function( rs, m, n, M ) + return RandomMatrix( ConstructingFilter( M ), rs, BaseDomain( M ), m, n ); + end ); + +InstallMethod( RandomMatrix, + [ IsInt, IsInt, IsMatrixOrMatrixObj ], + function( m, n, M ) + return RandomMatrix( ConstructingFilter( M ), GlobalMersenneTwister, BaseDomain( M ), m, n ); + end ); + + ############################################################################# ## #F RandomMat( [rs ,] , [, ] ) . . . . . . . . make a random matrix diff --git a/lib/methsel.g b/lib/methsel.g index 54e1e02fd9..1f8634f7c9 100644 --- a/lib/methsel.g +++ b/lib/methsel.g @@ -253,6 +253,30 @@ BIND_GLOBAL( "NewTagBasedOperation", return method( req1, req2, req3, req4 ); end ); + elif LENGTH( requirements ) = 5 then + InstallEarlyMethod( oper, + function( req1, req2, req3, req4, req5 ) + local method; + + if not ( requirements[1]( req1 ) and + requirements[2]( req2 ) and + requirements[3]( req3 ) and + requirements[4]( req4 ) and + requirements[5]( req5 ) ) then + TryNextMethod(); + fi; + + method:= FIND_OBJ_MAP( methods, req1, fail ); + if method = fail then + # Take the default method if there is one. + method:= FIND_OBJ_MAP( methods, IS_OBJECT, fail ); + fi; + if method = fail then + Error( "no default installed for tag based operation " ); + fi; + + return method( req1, req2, req3, req4, req5 ); + end ); else Error( "tag based operations for ", LENGTH( requirements ), " arguments are currently not supported" ); diff --git a/lib/modfree.gi b/lib/modfree.gi index 86252154e8..85928ad44e 100644 --- a/lib/modfree.gi +++ b/lib/modfree.gi @@ -162,23 +162,25 @@ InstallMethod( Size, ## Either this basis has been entered when the space was constructed, or a ## basis is computed together with the elements list. ## -BindGlobal( "AsListOfFreeLeftModule", function( V ) + +## The vectors in 'base' are assumed to be linearly independent. +BindGlobal( "AsListOfFreeLeftModule_internal", function( F, base, zero ) local elms, # elements list, result - B, # $F$-basis of $V$ new, # intermediate elements list v, # one generator of $V$ i; # loop variable - if not IsFinite( V ) then - Error( "cannot compute elements list of infinite domain " ); + elms:= [ zero ]; + + if IsEmpty( base ) then + return elms; + elif not IsFinite( F ) then + Error( "cannot compute elements list over infinite domain " ); fi; - B := Basis( V ); - elms := [ Zero( V ) ]; -#T check whether we have the elements now ? - for v in BasisVectors( B ) do + for v in base do new:= []; - for i in AsList( LeftActingDomain( V ) ) do + for i in AsList( F ) do Append( new, List( elms, x -> x + i * v ) ); od; elms:= new; @@ -189,6 +191,10 @@ BindGlobal( "AsListOfFreeLeftModule", function( V ) return elms; end ); +BindGlobal( "AsListOfFreeLeftModule", + V -> AsListOfFreeLeftModule_internal( LeftActingDomain( V ), + BasisVectors( Basis( V ) ), Zero( V ) ) ); + InstallMethod( AsList, "for a free left module", [ IsFreeLeftModule ], diff --git a/lib/oprt.gi b/lib/oprt.gi index a94fffac60..4714e76a6f 100644 --- a/lib/oprt.gi +++ b/lib/oprt.gi @@ -655,7 +655,7 @@ local xset,surj,G, D, act, fam, filter, hom, i,blockacttest; elif IsExternalSetByActorsRep( xset ) then filter := filter and IsActionHomomorphismByActors; elif IsMatrixGroup( G ) - and IsScalarList( D[ 1 ] ) then + and ( IsScalarList( D[ 1 ] ) or IsVectorObj( D[ 1 ] ) ) then if act in [ OnPoints, OnRight ] then # we act linearly. This might be used to compute preimages by linear # algebra @@ -3380,7 +3380,7 @@ end ); InstallMethod( PreImagesRepresentativeNC,"IsLinearActionHomomorphism", FamRangeEqFamElm, [ IsLinearActionHomomorphism, IsPerm ], 0, function( hom, elm ) - local V, xset,lab,f; + local V, G, Grep, xset,lab,f; # is this method applicable? Test whether the domain contains a vector # space basis (respectively just get this basis). @@ -3393,20 +3393,21 @@ function( hom, elm ) #if not elm in Image( hom ) then return fail; fi; xset:=UnderlyingExternalSet(hom); V := HomeEnumerator(xset); - f:=DefaultFieldOfMatrixGroup(Source(hom)); + G:= Source( hom ); + Grep:= Representative( G ); + f:=DefaultFieldOfMatrixGroup(G); if not IsBound(hom!.linActBasisPositions) then hom!.linActBasisPositions:=List(lab,i->PositionCanonical(V,i)); fi; if not IsBound(hom!.linActInverse) then - lab:=ImmutableMatrix(f,lab); + lab:=ImmutableMatrix(f, Matrix( lab, Grep )); hom!.linActInverse:=Inverse(lab); fi; elm:=OnTuples(hom!.linActBasisPositions,elm); # image points elm:=V{elm}; # the corresponding vectors - f:=DefaultFieldOfMatrixGroup(Source(hom)); - elm:=ImmutableMatrix(f,elm); + elm:=ImmutableMatrix(f, Matrix( elm, Grep )); return hom!.linActInverse*elm; end ); @@ -3415,10 +3416,31 @@ end ); ## #M PreImagesRepresentativeNC( , ) . . . . . . . . . build matrix ## -InstallMethod( PreImagesRepresentativeNC,"IsProjectiveActionHomomorphism", +#### InstallMethod( PreImagesRepresentativeNC,"IsProjectiveActionHomomorphism", +## The idea is as follows. +## We have an $F$-basis $(v_1, \ldots, v_n)$. +## The matrix $M \in GL(n, F)$ acts first by right multiplication, +## let $w_i = v_i M$. +## Due to the projective action, we know only the normed vectors $c_i w_i$, +## where $c_i \in F \setminus \{ 0 \}$. +## The data computed by 'LinearActionBasis' (if its result is not 'fail') +## provide a vector $v = \sum_i a_i v_i$ such that all $a_i \not= 0$, +## and we know the normed vector $c w$ where $w = v M$ and $c \in F$. +## +## We can compute the decomposition $c w = \sum_i b_i (c_i w_i)$, +## and get $\sum_i b_i (c_i w_i) = c v M = c \sum_i a_i w_i$, +## which means $c_i = c a_i/b_i$ for all $i$. +## Thus we can reconstruct the matrix $M$ up to the scalar factor $c$. +## +## In the cases that are supported, either $c$ is irrelevant because the +## matrix group contains all scalar matrices, or we know that the preimage +## has determinant $1$ and taking the root in question is unique. +## +InstallMethod( PreImagesRepresentative,"IsProjectiveActionHomomorphism", +#### >>>>>>> aa52ee29a (Add `RandomMatrix`, .... (#6232)) FamRangeEqFamElm, [ IsProjectiveActionHomomorphism, IsPerm ], 0, function( hom, elm ) - local V, mat, xset,lab,f,dim,sol,i; + local V, G, Grep, mat, xset,lab,dim,sol,i; # is this method applicable? Test whether field # finite, that the domain contains a vector @@ -3435,18 +3457,19 @@ function( hom, elm ) #if not elm in Image( hom ) then return fail; fi; xset:=UnderlyingExternalSet(hom); V := HomeEnumerator(xset); - f:=DefaultFieldOfMatrixGroup(Source(hom)); - dim:=DimensionOfMatrixGroup(Source(hom)); + G:= Source( hom ); + Grep:= Representative( G ); + dim:=DimensionOfMatrixGroup(G); elm:=OnTuples(hom!.projActBasisPositions,elm); # image points elm:=V{elm}; # the corresponding vectors - mat:=elm{[1..dim]}; + mat:= Matrix( List( elm{ [ 1 .. dim ] }, ShallowCopy ), Grep ); sol:=SolutionMat(mat,elm[dim+1]); for i in [1..dim] do - mat[i]:=sol[i]*mat[i]; + MultMatrixRow( mat, i, sol[i] ); od; - mat:=hom!.projActInverse*ImmutableMatrix(f,mat); + mat:= hom!.projActInverse * mat; # correct scalar using determinant if needed if hom!.correctionFactors[1]<>fail then @@ -3457,7 +3480,7 @@ function( hom, elm ) fi; fi; - return mat; + return MakeImmutable( mat ); end); ############################################################################# @@ -3467,18 +3490,24 @@ end); InstallMethod(LinearActionBasis,"find basis in domain",true, [IsLinearActionHomomorphism],0, function(hom) -local xset,D,b,t,i,r,pos; +local xset, base, M, D, b, t, i, r, pos, v; xset:=UnderlyingExternalSet(hom); if Size(xset)=0 then return fail; fi; - pos:=[]; # if there is a base, check whether it's full rank, if yes, take it - if HasBaseOfGroup(xset) - and RankMat(BaseOfGroup(xset))=Length(BaseOfGroup(xset)[1]) then - # this implies injectivity - SetIsInjective(hom,true); - return BaseOfGroup(xset); + if HasBaseOfGroup(xset) then + base:= BaseOfGroup(xset); + if IsMatrix( base ) then + M:= base; + elif ForAll( base, IsVectorObj ) then + M:= Matrix( BaseOfGroup( xset ), One( ActingDomain( xset ) ) ); + fi; + if RankMat( M ) = NrCols( M ) then + # this implies injectivity + SetIsInjective(hom,true); + return base; + fi; fi; # otherwise we've to find a basis from the domain. D:=HomeEnumerator(xset); @@ -3486,12 +3515,15 @@ local xset,D,b,t,i,r,pos; t:=[]; r:=Length(D[1]); i:=1; + pos:=[]; while Length(b)Length(t) then + v:= Unpack( D[i] ); +#TODO: try to get rid of 'Unpack' + if RankMat(Concatenation(t,[v]))>Length(t) then # new indep. vector Add(b,D[i]); Add(pos,i); - Add(t,ShallowCopy(D[i])); + Add(t, v); TriangulizeMat(t); # for faster rank tests fi; i:=i+1; @@ -3532,7 +3564,7 @@ end); InstallOtherMethod(LinearActionBasis,"projective with extra vector",true, [IsProjectiveActionHomomorphism],0, function(hom) -local xset,G,D,b,t,i,r,binv,pos,dets,roots,dim,f; +local xset,G,Grep,D,b,t,i,r,binv,pos,dets,roots,dim,f,v; xset:=UnderlyingExternalSet(hom); if Size(xset)=0 then return fail; @@ -3540,6 +3572,7 @@ local xset,G,D,b,t,i,r,binv,pos,dets,roots,dim,f; # will the determinants suffice to get suitable scalars? G:= Source(hom); + Grep:= Representative( G ); dim:=DimensionOfMatrixGroup(G); f:=DefaultFieldOfMatrixGroup(G); @@ -3575,11 +3608,13 @@ local xset,G,D,b,t,i,r,binv,pos,dets,roots,dim,f; i:=1; pos:=[]; while Length(b)Length(t) then + v:= Unpack( D[i] ); +#TODO: try to get rid of 'Unpack' + if RankMat(Concatenation(t,[v]))>Length(t) then # new indep. vector Add(b,D[i]); Add(pos,i); - Add(t,ShallowCopy(D[i])); + Add(t,v); TriangulizeMat(t); # for faster rank tests fi; i:=i+1; @@ -3589,15 +3624,20 @@ local xset,G,D,b,t,i,r,binv,pos,dets,roots,dim,f; fi; # try to find a vector that has nonzero coefficients for all b - binv:=Inverse(ImmutableMatrix(f,b)); + binv:= Inverse( ImmutableMatrix( f, Matrix( b, Grep ) ) ); while i<=Length(D) do - if ForAll(D[i]*binv,x->not IsZero(x)) then + if ForAll( Unpack( D[i] * binv ), x -> not IsZero(x) ) then +#TODO: get rid of 'Unpack'? Add(b,D[i]); Add(pos,i); hom!.projActBasisPositions:=pos; - hom!.projActInverse:=ImmutableMatrix(f,binv*Inverse(DiagonalMat(D[i]*binv))); + hom!.projActInverse:= ImmutableMatrix( f, + binv * Inverse( DiagonalMatrix( D[i] * binv, binv ) ) ); hom!.correctionFactors:=[dets,roots]; - return ImmutableMatrix(f,b); + if IsScalarList( D[1] ) then + b:= ImmutableMatrix(f,b); + fi; + return b; fi; i:=i+1; od; diff --git a/lib/vspcrow.gi b/lib/vspcrow.gi index 812c16179f..05df43d515 100644 --- a/lib/vspcrow.gi +++ b/lib/vspcrow.gi @@ -1033,44 +1033,26 @@ InstallMethod( Intersection2, ############################################################################# ## -#M NormedRowVectors( ) +#M NormedRowVectors_internal( , ) ## -InstallMethod( NormedRowVectors, - "for Gaussian row space", - [ IsGaussianRowSpace ], - function( V ) - local base, # basis vectors - elms, # element list, result - elms2, # intermediate element list - F, # `LeftActingDomain( V )' - q, # `Size( F )' - fieldelms, # elements of `F' (in other succession) - j, # loop over `base' - new, # intermediate element list - pos, # position in `new' to store the next element - len, # actual length of `elms2' - i, # loop over field elements - toadd, # vector to add to known vectors - k, # loop over `elms2' - v; # one normed row vector - - if not IsFinite( V ) then - Error( "sorry, cannot compute normed vectors of infinite domain " ); - fi; +## Assume that is a list of row vectors or vector objects over +## that is in echelon form. +## +BindGlobal( "NormedRowVectors_internal", function( F, base ) + local elms, elms2, fieldelms, j, new, pos, len, i, toadd, k; - base:= Reversed( BasisVectors( CanonicalBasis( V ) ) ); if Length( base ) = 0 then return []; + elif not IsFinite( F ) then + Error( "sorry, cannot compute normed vectors over infinite domain " ); fi; + base := Reversed( base ); elms := [ base[1] ]; elms2 := [ base[1] ]; - F := LeftActingDomain( V ); - q := Size( F ); fieldelms := List( AsSSortedList( F ), x -> x - 1 ); for j in [ 1 .. Length( base ) - 1 ] do - # Here `elms2' has the form # $b_i + M = b_i + \langle b_{i+1}, \ldots, b_n \rangle$. # Compute $b_{i-1} + \bigcup_{\lambda\in F} \lambda b_i + ( b_i + M )$. @@ -1080,9 +1062,7 @@ InstallMethod( NormedRowVectors, for i in fieldelms do toadd:= base[j+1] + i * base[j]; for k in [ 1 .. len ] do - v:= elms2[k] + toadd; - v:= ImmutableVector( q, v ); - new[ pos + k ]:= v; + new[ pos + k ]:= ImmutableVector( F, elms2[k] + toadd ); od; pos:= pos + len; od; @@ -1090,9 +1070,27 @@ InstallMethod( NormedRowVectors, # `elms2' is a set here. Append( elms, elms2 ); - od; + # Return the result. + return elms; + end ); + + +############################################################################# +## +#M NormedRowVectors( ) +## +InstallMethod( NormedRowVectors, + "for Gaussian row space", + [ IsGaussianRowSpace ], + function( V ) + local base, # basis vectors + elms; # element list, result + + base:= BasisVectors( CanonicalBasis( V ) ); + elms:= NormedRowVectors_internal( LeftActingDomain( V ), base ); + # The list is strictly sorted, so we store this. MakeImmutable( elms ); Assert( 1, IsSSortedList( elms ) ); diff --git a/tst/testbugfix/2007-07-02-t00180.tst b/tst/testbugfix/2007-07-02-t00180.tst index be77f789b5..a7f8e14c7c 100644 --- a/tst/testbugfix/2007-07-02-t00180.tst +++ b/tst/testbugfix/2007-07-02-t00180.tst @@ -1,6 +1,6 @@ # 2007/07/02 (SK) gap> GeneratorsOfRing(Rationals); -Error, cannot compute elements list of infinite domain +Error, cannot compute elements list over infinite domain gap> GeneratorsOfRingWithOne(Rationals); Error, no method found! For debugging hints type ?Recovery from NoMethodFound Error, no 2nd choice method found for `GeneratorsOfRingWithOne' on 1 arguments diff --git a/tst/testinstall/MatrixObj/DeterminantMatrix.tst b/tst/testinstall/MatrixObj/DeterminantMatrix.tst new file mode 100644 index 0000000000..8d9f63eeca --- /dev/null +++ b/tst/testinstall/MatrixObj/DeterminantMatrix.tst @@ -0,0 +1,29 @@ +#@local M, mat +gap> START_TEST( "DeterminantMatrix.tst" ); + +# nonsquare matrix +gap> mat:= [[1,2,1,2],[1,0,1,0],[2,2,2,2]];; +gap> M:= NewMatrix( IsPlistMatrixRep, GF(5), 4, mat*Z(5)^0 );; +gap> DeterminantMatrix( M ); +Error, DeterminantMat: must be a nonempty square matrix + +# 0x0 matrix +gap> M:= ZeroMatrix( IsPlistRep, GF(9), 0, 0 ); +[ ] +gap> DeterminantMatrix( M ); +Error, no method found! For debugging hints type ?Recovery from NoMethodFound +Error, no 1st choice method found for `DeterminantMatrix' on 1 arguments +gap> M:= ZeroMatrix( IsPlistMatrixRep, GF(9), 0, 0 ); +<0x0-matrix over GF(3^2)> +gap> DeterminantMatrix( M ); +Error, no method found! For debugging hints type ?Recovery from NoMethodFound +Error, no 1st choice method found for `DeterminantMatrix' on 1 arguments + +# square nonempty matrix +gap> mat:= [[1,2,1],[1,0,1],[2,2,2]];; +gap> M:= NewMatrix( IsPlistMatrixRep, GF(5), 3, mat*Z(5)^0 );; +gap> DeterminantMatrix( M ); +0*Z(5) + +# +gap> STOP_TEST( "DeterminantMatrix.tst" ); diff --git a/tst/testinstall/MatrixObj/RandomInvertibleMatrix.tst b/tst/testinstall/MatrixObj/RandomInvertibleMatrix.tst new file mode 100644 index 0000000000..258d6c2934 --- /dev/null +++ b/tst/testinstall/MatrixObj/RandomInvertibleMatrix.tst @@ -0,0 +1,52 @@ +#@local rs, M +gap> START_TEST( "RandomInvertibleMatrix.tst" ); + +# with base domain +gap> Is8BitMatrixRep( RandomInvertibleMatrix( GF(9), 10 ) ); +true +gap> IsPlistMatrixRep( RandomInvertibleMatrix( Integers, 10 ) ); +true + +# with constructing filter and base domain +gap> Is8BitMatrixRep( RandomInvertibleMatrix( Is8BitMatrixRep, GF(9), 10 ) ); +true +gap> IsPlistRep( RandomInvertibleMatrix( IsPlistRep, Integers, 10 ) ); +true + +# with random source and base domain +gap> rs:= RandomSource(IsMersenneTwister);; +gap> Is8BitMatrixRep( RandomInvertibleMatrix( Is8BitMatrixRep, GF(9), 10 ) ); +true +gap> IsPlistRep( RandomInvertibleMatrix( IsPlistRep, Integers, 10 ) ); +true + +# with constructing filter, random source, and base domain +gap> Is8BitMatrixRep( RandomInvertibleMatrix( Is8BitMatrixRep, rs, GF(9), 10 ) ); +true +gap> IsPlistRep( RandomInvertibleMatrix( IsPlistRep, rs, Integers, 10 ) ); +true + +# with example matrix +gap> M:= Matrix( IsPlistMatrixRep, Integers, [ 1 ], 1 );; +gap> RandomInvertibleMatrix( 2, M ); +<2x2-matrix over Integers> +gap> M:= [ [ 1 ] ];; +gap> IsPlistRep( RandomInvertibleMatrix( 2, M ) ); +true +gap> M:= Matrix( IsPlistMatrixRep, GF(3), [ Z(3) ], 1 );; +gap> RandomInvertibleMatrix( 2, M ); +<2x2-matrix over GF(3)> + +# with random source and example matrix +gap> M:= Matrix( IsPlistMatrixRep, Integers, [ 1 ], 1 );; +gap> RandomInvertibleMatrix( rs, 2, M ); +<2x2-matrix over Integers> +gap> M:= [ [ 1 ] ];; +gap> IsPlistRep( RandomInvertibleMatrix( rs, 2, M ) ); +true +gap> M:= Matrix( IsPlistMatrixRep, GF(3), [ Z(3) ], 1 );; +gap> RandomInvertibleMatrix( rs, 2, M ); +<2x2-matrix over GF(3)> + +# +gap> STOP_TEST( "RandomInvertibleMatrix.tst" ); diff --git a/tst/testinstall/MatrixObj/RandomMatrix.tst b/tst/testinstall/MatrixObj/RandomMatrix.tst new file mode 100644 index 0000000000..d4460cf9c0 --- /dev/null +++ b/tst/testinstall/MatrixObj/RandomMatrix.tst @@ -0,0 +1,72 @@ +#@local rs, M +gap> START_TEST( "RandomMatrix.tst" ); + +# with base domain +gap> Is8BitMatrixRep( RandomMatrix( GF(9), 10, 5 ) ); +true +gap> RandomMatrix( GF(9), 0, 1 ); +Error, Is8BitMatrixRep with zero rows not yet supported +gap> IsPlistMatrixRep( RandomMatrix( Integers, 10, 5 ) ); +true +gap> IsPlistMatrixRep( RandomMatrix( Integers, 0, 0 ) ); +true + +# with constructing filter and base domain +gap> Is8BitMatrixRep( RandomMatrix( Is8BitMatrixRep, GF(9), 10, 5 ) ); +true +gap> IsPlistMatrixRep( RandomMatrix( IsPlistMatrixRep, GF(9), 0, 0 ) ); +true +gap> IsPlistRep( RandomMatrix( IsPlistRep, Integers, 10, 5 ) ); +true + +# with random source and base domain +gap> rs:= RandomSource(IsMersenneTwister);; +gap> Is8BitMatrixRep( RandomMatrix( Is8BitMatrixRep, GF(9), 10, 5 ) ); +true +gap> IsPlistMatrixRep( RandomMatrix( IsPlistMatrixRep, GF(9), 0, 0 ) ); +true +gap> IsPlistRep( RandomMatrix( IsPlistRep, Integers, 10, 5 ) ); +true + +# with constructing filter, random source, and base domain +gap> Is8BitMatrixRep( RandomMatrix( Is8BitMatrixRep, rs, GF(9), 10, 5 ) ); +true +gap> IsPlistMatrixRep( RandomMatrix( IsPlistMatrixRep, rs, GF(9), 0, 0 ) ); +true +gap> IsPlistRep( RandomMatrix( IsPlistRep, rs, Integers, 10, 5 ) ); +true + +# with example matrix +gap> M:= Matrix( IsPlistMatrixRep, Integers, [ 1 ], 1 );; +gap> RandomMatrix( 2, 2, M ); +<2x2-matrix over Integers> +gap> RandomMatrix( 0, 0, M ); +<0x0-matrix over Integers> +gap> M:= [ [ 1 ] ];; +gap> BaseDomain( M ); +Rationals +gap> IsPlistRep( RandomMatrix( 2, 2, M ) ); +true +gap> ForAll( Flat( RandomMatrix( 1, 2, M ) ), IsRat ); +true +gap> M:= Matrix( IsPlistMatrixRep, GF(3), [ Z(3) ], 1 );; +gap> RandomMatrix( 2, 2, M ); +<2x2-matrix over GF(3)> + +# with random source and example matrix +gap> M:= Matrix( IsPlistMatrixRep, Integers, [ 1 ], 1 );; +gap> RandomMatrix( rs, 2, 2, M ); +<2x2-matrix over Integers> +gap> RandomMatrix( rs, 0, 0, M ); +<0x0-matrix over Integers> +gap> M:= [ [ 1 ] ];; +gap> IsPlistRep( RandomMatrix( rs, 2, 2, M ) ); +true +gap> ForAll( Flat( RandomMatrix( rs, 1, 2, M ) ), IsRat ); +true +gap> M:= Matrix( IsPlistMatrixRep, GF(3), [ Z(3) ], 1 );; +gap> RandomMatrix( rs, 2, 2, M ); +<2x2-matrix over GF(3)> + +# +gap> STOP_TEST( "RandomMatrix.tst" ); diff --git a/tst/testinstall/MatrixObj/RankMatrix.tst b/tst/testinstall/MatrixObj/RankMatrix.tst new file mode 100644 index 0000000000..d8561b2806 --- /dev/null +++ b/tst/testinstall/MatrixObj/RankMatrix.tst @@ -0,0 +1,23 @@ +#@local M, mat +gap> START_TEST( "RankMatrix.tst" ); + +# nonsquare matrix +gap> mat:= [[1,2,1,2],[1,0,1,0],[2,2,2,2]];; +gap> M:= NewMatrix( IsPlistMatrixRep, GF(5), 4, mat*Z(5)^0 ); +<3x4-matrix over GF(5)> +gap> RankMatrix( M ); +2 + +# 0x0 matrix +gap> M:= ZeroMatrix( IsPlistRep, GF(9), 0, 0 ); +[ ] +gap> RankMatrix( M ); +Error, no method found! For debugging hints type ?Recovery from NoMethodFound +Error, no 1st choice method found for `RankMatrix' on 1 arguments +gap> M:= ZeroMatrix( IsPlistMatrixRep, GF(9), 0, 0 ); +<0x0-matrix over GF(3^2)> +gap> RankMatrix( M ); +0 + +# +gap> STOP_TEST( "RankMatrix.tst" ); diff --git a/tst/testinstall/MatrixObj/acthom.tst b/tst/testinstall/MatrixObj/acthom.tst new file mode 100644 index 0000000000..6f7e73ed3e --- /dev/null +++ b/tst/testinstall/MatrixObj/acthom.tst @@ -0,0 +1,80 @@ +#@local right_representation, q, F, d, filt, groups, G, basis, xset, vectors +#@local orbs, len, D1, v, D2, D3, D4, actions, D, hom, i, g, img, pre +gap> START_TEST( "acthom.tst" ); + +# +gap> right_representation:= function( filt, g ) +> return ( filt = IsPlistRep and IsList( g ) ) or +> ( filt <> IsPlistRep and filt( g ) ); +> end;; +gap> for q in [ 2, 3, 4 ] do +> F:= GF(q); +> for d in [ 2 .. 4 ] do +> for filt in [ IsPlistRep, IsPlistMatrixRep ] do +> PushOptions( rec( ConstructingFilter:= filt ) ); +> # Test groups with special methods and a general group. +> groups:= [ GL( d, F ), SL( d, F ) ]; +> # Add( groups, SylowSubgroup( groups[1], 2 ) ); +> # Add( groups, Subgroup( groups[1], +> # [ GeneratorsOfGroup( groups[1] )[1] ] ) ); +> for G in groups do +> # Consider the G-action +> # - given by the nice monomorphism +> # - on an orbit (linear & projective) +> # - on the whole natural G-set (linear & projective) +> basis:= RowsOfMatrix( One( G ) ); +> xset:= ExternalSet( G ); +> vectors:= HomeEnumerator( xset ); +> orbs:= Orbits( G, vectors ); +> len:= Maximum( List( orbs, Length ) ); +> D1:= [ First( orbs, x -> Length( x ) = len ), OnRight ]; +> v:= OnLines( D1[1][1], One( G ) ); +> D2:= [ Orbit( G, v, OnLines ), OnLines ]; +> D3:= [ vectors, OnRight ]; +> D4:= [ NormedRowVectors_internal( F, basis ), OnLines ]; +> +> actions:= [ NiceMonomorphism( G ) ]; +> for D in [ D1, D2, D3, D4 ] do +> if not CompatibleVectorFilter( One( G ) )( D[1][1] ) then +> Error( "wrong repres. of vector for ", [ q, d, filt ] ); +> fi; +> hom:= ActionHomomorphism( G, D[1], D[2] ); +> if D[2] <> OnLines and +> not IsLinearActionHomomorphism( hom ) then +> Error( "unexpected type of action hom. for ", +> [ q, d, filt ] ); +> fi; +> Add( actions, hom ); +> od; +> +> for hom in actions do +> for i in [ 1 .. 5 ] do +> g:= Random( G ); +> if not right_representation( filt, g ) then +> Error( "wrong repres. of random matrix for ", +> [ q, d, filt ] ); +> fi; +> img:= g^hom; +> pre:= PreImagesRepresentative( hom, img ); +> if not right_representation( filt, pre ) then +> Error( "wrong repres. of preimage matrix for ", +> [ q, d, filt ] ); +> fi; +> if FunctionAction( UnderlyingExternalSet( hom ) ) = OnLines then +> if not ( pre / g in Centre( G ) ) then +> Error( "problem with projective action for ", +> [ q, d, filt ] ); +> fi; +> elif pre <> g then +> Error( "problem with linear action for ", +> [ q, d, filt ] ); +> fi; +> od; +> od; +> od; +> od; +> od; +> od; + +# +gap> STOP_TEST( "acthom.tst" ); diff --git a/tst/testinstall/grpmat.tst b/tst/testinstall/grpmat.tst index 31b192e7ba..4c23741723 100644 --- a/tst/testinstall/grpmat.tst +++ b/tst/testinstall/grpmat.tst @@ -1,4 +1,4 @@ -#@local cl,g,gd,gens,hom,i,img,iso,pcgs,u,G,F,o,a,m,nice,H +#@local cl,g,gd,gens,hom,i,img,iso,pcgs,u,G,F,o,a,m,nice,H,G2,nice2 gap> START_TEST("grpmat.tst"); gap> i := E(4);; G := Group([[i,0],[0,-i]],[[0,1],[-1,0]]);; gap> gens := GeneratorsOfGroup( G );; IsSSortedList( gens ); @@ -89,5 +89,21 @@ gap> TrivialSubgroup( GL(2, 2) ); gap> Length( LowIndexSubgroups( GL(2,5), 50 ) ) = 31; true +# 'NiceMonomorphism' behaves well w.r.t. 'ConstructingFilter' +gap> G:= SP( 4, 2 );; +gap> nice:= NiceMonomorphism( G );; +gap> G2:= SP( 4, 2 : ConstructingFilter:= IsPlistMatrixRep );; +gap> nice2:= NiceMonomorphism( G2 );; +gap> IsPlistMatrixRep( One( G ) ); +false +gap> IsPlistMatrixRep( One( G2 ) ); +true +gap> IsIdenticalObj( nice, nice2 ); +false +gap> IsSubset( Source( nice ), G ); +true +gap> IsSubset( Source( nice2 ), G2 ); +true + # gap> STOP_TEST( "grpmat.tst" ); From ac313c7cb1acb5d0626a80fcf066978d53c15e0f Mon Sep 17 00:00:00 2001 From: Max Horn Date: Fri, 8 May 2026 11:34:48 +0100 Subject: [PATCH 205/234] Makefile.rules: add cleanall target, improve cleaning overall (#6378) --- Makefile.rules | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/Makefile.rules b/Makefile.rules index 1aec140fdd..74d62a9ca0 100644 --- a/Makefile.rules +++ b/Makefile.rules @@ -584,9 +584,13 @@ clean: rm -rf .libs rm -f doc/wsp.g rm -f cnf/GAP-* + rm -f configure~ src/config.h.in~ rmdir bin cnf dev doc extern src 2>/dev/null || : # remove dirs if they are now empty -.PHONY: clean distclean +cleanall: clean distclean clean-doc + rm -f src/config.h.in + +.PHONY: clean distclean cleanall ######################################################################## @@ -976,6 +980,7 @@ clean-doc: rm -f doc/*/chooser.html doc/*/manual*.pdf rm -f doc/*/*.{aux,bbl,blg,brf,idx,ilg,ind,lab,log,out,pnr,six,tex,toc} rm -f doc/manualbib.xml.bib + rm -f doc/ref/user_pref_list.xml # FIXME: we currently build the manual inside $srcdir; so we don't want "make clean" # to remove it, as other builds might share the manual. @@ -1007,6 +1012,7 @@ tst/testlibgap/%: build/obj/tst/testlibgap/%.c.o build/obj/tst/testlibgap/common clean: clean-testlibgap clean-testlibgap: rm -f ${LIBGAPTESTS} + rm -f $(addsuffix .out,$(LIBGAPTESTS)) # run all the tests in tst/testlibgap testlibgap: ${LIBGAPTESTS} @@ -1048,6 +1054,7 @@ tst/testkernel/%: build/obj/tst/testkernel/%.c.o libgap$(SHLIB_EXT) clean: clean-testkernel clean-testkernel: rm -f ${KERNELTESTS} + rm -f $(addsuffix .out,$(KERNELTESTS)) # run all the tests in tst/testkernel testkernel: ${KERNELTESTS} From 8068db7f2adb18aa87d4351fb123943f396c5137 Mon Sep 17 00:00:00 2001 From: lhsoicher Date: Fri, 8 May 2026 13:01:14 +0100 Subject: [PATCH 206/234] Improve documentation of several action functions (#6370) Improve the documentation for the action functions - OnTuplesSets - OnTuplesTuples, - OnSetsTuples, - OnSetsSets, - OnSetsDisjointSets. --- lib/oprt.gd | 61 ++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 44 insertions(+), 17 deletions(-) diff --git a/lib/oprt.gd b/lib/oprt.gd index c369951114..20bae46045 100644 --- a/lib/oprt.gd +++ b/lib/oprt.gd @@ -2743,11 +2743,16 @@ DeclareGlobalFunction("OnLines"); ## ## ## implements the action on sets of sets. -## For the special case that the sets are pairwise disjoint, +## set must be a proper set whose entries are again proper sets +## (see ). +##

+## returns the proper set whose elements are +## the images obtained by applying the action function +## to x and g, +## for each element x of set. +##

+## For the special case that the elements of set are pairwise disjoint, ## it is possible to use . -## set must be a sorted list whose entries are again sorted lists, -## otherwise an error is triggered -## (see ). ## OnSetsSets( [ [ 1, 2 ], [ 3, 4 ] ], (1,2,3) ); ## [ [ 1, 4 ], [ 2, 3 ] ] @@ -2774,9 +2779,16 @@ DeclareGlobalFunction( "OnSetsSets" ); ## ## implements the action on sets of pairwise disjoint sets ## (see also ). -## set must be a sorted list whose entries are again sorted lists, -## otherwise an error is triggered -## (see ). +## set must be a proper set whose entries are pairwise +## disjoint proper sets. +## However, it is not checked that the entries of +## set are indeed pairwise disjoint. +##

+## returns the proper +## set whose elements are +## the images obtained by applying the action function +## to x and g, +## for each element x of set. ## ## ## <#/GAPDoc> @@ -2794,9 +2806,13 @@ DeclareGlobalFunction( "OnSetsDisjointSets" ); ## ## ## implements the action on sets of tuples. -## set must be a sorted list, -## otherwise an error is triggered -## (see ). +## set must be a proper set of lists without holes +## (see ). +##

+## returns the proper set whose elements are +## the images obtained by applying the action function +## to x and g, +## for each element x of set. ## OnSetsTuples( [ [ 1, 2 ], [ 3, 4 ] ], (1,2,3) ); ## [ [ 1, 4 ], [ 2, 3 ] ] @@ -2815,17 +2831,21 @@ DeclareGlobalFunction("OnSetsTuples"); ############################################################################# ## -#F OnTuplesSets( , ) +#F OnTuplesSets( , ) ## ## <#GAPDoc Label="OnTuplesSets"> ## -## +## ## ## ## implements the action on tuples of sets. -## set must be a list whose entries are again sorted lists, -## otherwise an error is triggered -## (see ). +## tup must be a list without holes whose entries are proper sets +## (see ). +##

+## returns the list of +## the corresponding images obtained by applying the action function +## to x and g, +## for each entry x of tup. ## OnTuplesSets( [ [ 2, 3 ], [ 3, 4 ] ], (1,2,3) ); ## [ [ 1, 3 ], [ 1, 4 ] ] @@ -2844,14 +2864,21 @@ DeclareGlobalFunction("OnTuplesSets"); ############################################################################# ## -#F OnTuplesTuples( , ) +#F OnTuplesTuples( , ) ## ## <#GAPDoc Label="OnTuplesTuples"> ## -## +## ## ## ## implements the action on tuples of tuples. +## tup must be a list without holes whose entries are again +## lists without holes. +##

+## returns the list of +## the corresponding images obtained by applying the action function +## to x and g, +## for each entry x of the list tup. ## OnTuplesTuples( [ [ 2, 3 ], [ 3, 4 ] ], (1,2,3) ); ## [ [ 3, 1 ], [ 1, 4 ] ] From 362026f7d6756466a18e64cf57cb45df1e0efc69 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lars=20G=C3=B6ttgens?= Date: Fri, 8 May 2026 18:48:30 +0200 Subject: [PATCH 207/234] Fix CI with GAP.jl (#6381) --- .github/workflows/gapjl.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/gapjl.yml b/.github/workflows/gapjl.yml index 5e3a5ae291..626f1a52a1 100644 --- a/.github/workflows/gapjl.yml +++ b/.github/workflows/gapjl.yml @@ -56,7 +56,7 @@ jobs: run: | using Pkg if "${{ matrix.gapjl-version }}" == "latest-release" - Pkg.add("GAP") + Pkg.develop("GAP") else Pkg.add(;name="GAP", rev="${{ matrix.gapjl-version }}") end @@ -77,7 +77,7 @@ jobs: make -j`nproc` - name: "Override bundled GAP" run: | - julia --proj=override $GAPJLPATH/etc/setup_override_dir.jl /tmp/GAPROOT /tmp/gap_jll_override --enable-Werror + julia --project=$GAPJLPATH $GAPJLPATH/etc/setup_override_dir.jl /tmp/GAPROOT /tmp/gap_jll_override --enable-Werror - name: "Run tests" run: | - julia --proj=override $GAPJLPATH/etc/run_with_override.jl /tmp/gap_jll_override --depwarn=error -e "using Pkg; Pkg.test(\"GAP\")" + julia --project=$GAPJLPATH $GAPJLPATH/etc/run_with_override.jl /tmp/gap_jll_override --depwarn=error -e "using Pkg; Pkg.test(\"GAP\")" From ff9595009e4700c044dc7f791753f57f207b05d3 Mon Sep 17 00:00:00 2001 From: Thomas Breuer Date: Sat, 9 May 2026 05:25:06 +0200 Subject: [PATCH 208/234] Fix an inconsistent ordering of conjugacy classes (#6382) --- lib/ctblsymm.gi | 2 +- tst/testinstall/ctbl.tst | 15 ++++++++++++--- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/lib/ctblsymm.gi b/lib/ctblsymm.gi index 74230ddc77..a15ca95f5b 100644 --- a/lib/ctblsymm.gi +++ b/lib/ctblsymm.gi @@ -1232,7 +1232,7 @@ InstallMethod( Irr, # Compute the correspondence of classes. cp:= gentbl.classparam[1]( deg ); perm:= []; - for i in ConjugacyClasses( G ) do + for i in ConjugacyClasses( cG ) do i:= List( Orbits( SubgroupNC( G, [ Representative(i) ] ), dom ), Length ); Sort( i ); diff --git a/tst/testinstall/ctbl.tst b/tst/testinstall/ctbl.tst index 47cba12b4e..f8d23bbc13 100644 --- a/tst/testinstall/ctbl.tst +++ b/tst/testinstall/ctbl.tst @@ -381,6 +381,15 @@ true gap> IsPerfectCharacterTable( t ); false +# test another bugfix +gap> G:= SymmetricGroup( 2 );; +gap> SetConjugacyClasses( G, +> List( [ (1,2), () ], x -> ConjugacyClass( G, x ) ) ); +gap> t:= CharacterTable( G );; +gap> lin:= Irr( t );; +gap> lin[1][1]; +1 + # compute indicators gap> t:= CharacterTable( SymmetricGroup( 4 ) );; gap> Indicator( t, 2 ); @@ -434,19 +443,19 @@ gap> HasIsIrreducibleCharacter( TrivialCharacter( SymmetricGroup( 4 ) ) ); true # concurring 'Irr' methods -gap> G:= SmallGroup( 24, 5 );; +gap> G:= PcGroupCode( 221729, 24 );; gap> IsSupersolvable( G ); true gap> Irr( G );; gap> InfoText( OrdinaryCharacterTable( G ) ); "origin: Baum-Clausen Algorithm" -gap> G:= SmallGroup( 24, 5 );; +gap> G:= PcGroupCode( 221729, 24 );; gap> IsSupersolvable( G ); true gap> IrrConlon( G );; Irr( G );; gap> InfoText( OrdinaryCharacterTable( G ) ); "origin: Conlon's Algorithm" -gap> G:= SmallGroup( 24, 5 );; +gap> G:= PcGroupCode( 221729, 24 );; gap> IrrDixonSchneider( G );; Irr( G );; gap> InfoText( OrdinaryCharacterTable( G ) ); "origin: Dixon's Algorithm" From 5c7953b741a16b8fb666f2ec06592b93bb6e5748 Mon Sep 17 00:00:00 2001 From: Christopher Jefferson Date: Sat, 9 May 2026 13:01:31 +0800 Subject: [PATCH 209/234] scanner: don't print EOF sentinel as line context on syntax error (#6380) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When a syntax error fires after the scanner has advanced past EOF — e.g. parsing `h := ;` via READ_ALL_COMMANDS from a string with no trailing newline — the input-line buffer is refilled with GAP's end-of-input sentinel (\377) before SyntaxErrorOrWarning() runs. SyntaxErrorOrWarning() then printed the buffer verbatim as the line context, leaking a literal 0xFF byte to *errout*. On a tty this is harmless: the byte either gets eaten by the terminal or shown as some replacement glyph. But anything that captures *errout* programmatically — log files, the JupyterKernel package, an OutputTextFile redirect — sees the stray byte. JSON/UTF-8 has no encoding for it, so a Jupyter front-end renders it as a literal `ÿ` just below the error message. Skip the line print (and the corresponding caret) when the line buffer is the bare sentinel. The fix is local to SyntaxErrorOrWarning and doesn't change tty behaviour: the line-context print was already useless in this case, since the scanner had moved past the offending line. Add a testspecial regression that reproduces the leak via READ_ALL_COMMANDS + an ERROR_OUTPUT redirect to a temp file, then checks that the captured bytes contain the error message but not \377. --- src/scanner.c | 22 ++++++++---- tst/testspecial/syntax-err-eof-sentinel.g | 33 +++++++++++++++++ tst/testspecial/syntax-err-eof-sentinel.g.out | 36 +++++++++++++++++++ 3 files changed, 85 insertions(+), 6 deletions(-) create mode 100644 tst/testspecial/syntax-err-eof-sentinel.g create mode 100644 tst/testspecial/syntax-err-eof-sentinel.g.out diff --git a/src/scanner.c b/src/scanner.c index 3620454218..cc607b7582 100644 --- a/src/scanner.c +++ b/src/scanner.c @@ -62,13 +62,23 @@ static void SyntaxErrorOrWarning(ScannerState * s, Pr(" in %g:%d", (Int)name, GetInputLineNumber(s->input)); Pr("\n", 0, 0); - // print the current line + // print the current line — but skip the line print, and the + // caret below, if the buffer has been replaced by the scanner's + // end-of-input sentinel (0xFF). That happens when the syntax + // error fires after parsing has advanced past the offending + // line (e.g. `h := ;` parsed from a string with no trailing + // newline): the line buffer is refilled at EOF before the + // error is reported, so the pretty-printed context would leak + // a literal 0xFF byte to *errout* with no caret to anchor it. const char * line = GetInputLineBuffer(s->input); const UInt len = strlen(line); - if (len > 0 && line[len-1] != '\n') - Pr("%s\n", (Int)line, 0); - else - Pr("%s", (Int)line, 0); + const int line_is_sentinel = (len == 0 || line[0] == '\377'); + if (!line_is_sentinel) { + if (line[len-1] != '\n') + Pr("%s\n", (Int)line, 0); + else + Pr("%s", (Int)line, 0); + } // print a '^' pointing to the current position Int startPos = s->SymbolStartPos[tokenoffset]; @@ -83,7 +93,7 @@ static void SyntaxErrorOrWarning(ScannerState * s, pos = GetInputLinePosition(s->input); } - if (0 < pos && startPos <= pos) { + if (!line_is_sentinel && 0 < pos && startPos <= pos) { Int i; for (i = 0; i < startPos; i++) { if (line[i] == '\t') diff --git a/tst/testspecial/syntax-err-eof-sentinel.g b/tst/testspecial/syntax-err-eof-sentinel.g new file mode 100644 index 0000000000..06ea34bcd4 --- /dev/null +++ b/tst/testspecial/syntax-err-eof-sentinel.g @@ -0,0 +1,33 @@ +# Regression test for a 0xFF byte leak in syntax-error context lines. +# +# When a syntax error fires after the scanner has advanced past EOF +# (e.g. parsing "h := ;" via READ_ALL_COMMANDS from a string with no +# trailing newline), the input-line buffer is replaced with the +# scanner's end-of-input sentinel (0xFF). Before the fix in +# src/scanner.c the SyntaxErrorOrWarning() pretty-printer would dump +# that sentinel verbatim alongside the error message — visible as a +# stray `ÿ` glyph in any UTF-8 / log-file consumer of *errout* +# (e.g. the JupyterKernel package). +errFile := Filename(DirectoryTemporary(), "syntax.log");; +errStream := OutputTextFile(errFile, false);; +SetPrintFormattingStatus(errStream, false);; + +MakeReadWriteGlobal("ERROR_OUTPUT");; +saved := ERROR_OUTPUT;; +ERROR_OUTPUT := errStream;; +MakeReadOnlyGlobal("ERROR_OUTPUT");; + +READ_ALL_COMMANDS(InputTextString("h := ;"), false, false, IdFunc);; + +MakeReadWriteGlobal("ERROR_OUTPUT");; +ERROR_OUTPUT := saved;; +MakeReadOnlyGlobal("ERROR_OUTPUT");; +CloseStream(errStream);; + +inStream := InputTextFile(errFile);; +captured := ReadAll(inStream);; +CloseStream(inStream);; + +Print("contains-eof-sentinel: ", '\377' in captured, "\n"); +Print("contains-error-message: ", + PositionSublist(captured, "expression expected") <> fail, "\n"); diff --git a/tst/testspecial/syntax-err-eof-sentinel.g.out b/tst/testspecial/syntax-err-eof-sentinel.g.out new file mode 100644 index 0000000000..5dc7161cb8 --- /dev/null +++ b/tst/testspecial/syntax-err-eof-sentinel.g.out @@ -0,0 +1,36 @@ +gap> # Regression test for a 0xFF byte leak in syntax-error context lines. +gap> # +gap> # When a syntax error fires after the scanner has advanced past EOF +gap> # (e.g. parsing "h := ;" via READ_ALL_COMMANDS from a string with no +gap> # trailing newline), the input-line buffer is replaced with the +gap> # scanner's end-of-input sentinel (0xFF). Before the fix in +gap> # src/scanner.c the SyntaxErrorOrWarning() pretty-printer would dump +gap> # that sentinel verbatim alongside the error message — visible as a +gap> # stray `ÿ` glyph in any UTF-8 / log-file consumer of *errout* +gap> # (e.g. the JupyterKernel package). +gap> errFile := Filename(DirectoryTemporary(), "syntax.log");; +gap> errStream := OutputTextFile(errFile, false);; +gap> SetPrintFormattingStatus(errStream, false);; +gap> +gap> MakeReadWriteGlobal("ERROR_OUTPUT");; +gap> saved := ERROR_OUTPUT;; +gap> ERROR_OUTPUT := errStream;; +gap> MakeReadOnlyGlobal("ERROR_OUTPUT");; +gap> +gap> READ_ALL_COMMANDS(InputTextString("h := ;"), false, false, IdFunc);; +gap> +gap> MakeReadWriteGlobal("ERROR_OUTPUT");; +gap> ERROR_OUTPUT := saved;; +gap> MakeReadOnlyGlobal("ERROR_OUTPUT");; +gap> CloseStream(errStream);; +gap> +gap> inStream := InputTextFile(errFile);; +gap> captured := ReadAll(inStream);; +gap> CloseStream(inStream);; +gap> +gap> Print("contains-eof-sentinel: ", '\377' in captured, "\n"); +contains-eof-sentinel: false +gap> Print("contains-error-message: ", +> PositionSublist(captured, "expression expected") <> fail, "\n"); +contains-error-message: true +gap> QUIT; From 31b9cafd7a034cf7efa6b8dd866cee0748589821 Mon Sep 17 00:00:00 2001 From: Max Horn Date: Sat, 9 May 2026 06:04:51 +0100 Subject: [PATCH 210/234] dev/releases: ignore dependabot PRs (#6375) Co-authored-by: Codex Co-authored-by: Reinis Cirpons <43414125+reiniscirpons@users.noreply.github.com> --- .github/workflows/release.yml | 4 +- Makefile.rules | 8 +++ dev/releases/release_notes.py | 11 ++- dev/releases/test_release_notes.py | 107 +++++++++++++++++++++++++++++ 4 files changed, 127 insertions(+), 3 deletions(-) create mode 100644 dev/releases/test_release_notes.py diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index c8de8a0b1e..997d172106 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -56,8 +56,8 @@ jobs: #- name: "Validate types" # run: python -m mypy --disallow-untyped-calls --disallow-untyped-defs dev/releases/*.py - #- name: "Run tests" - # run: python -m pytest tools/tests/dev/releases*.py -vv + - name: "Run tests" + run: cd dev/releases && python -m pytest test_release_notes.py unix: name: "Create Unix archives and data" diff --git a/Makefile.rules b/Makefile.rules index 74d62a9ca0..ffe22eb1ba 100644 --- a/Makefile.rules +++ b/Makefile.rules @@ -21,6 +21,14 @@ default: all .PHONY: default +######################################################################## +# Developer helper targets +######################################################################## +test_release_notes: + cd dev/releases && python3 -m pytest test_release_notes.py +.PHONY: test_release_notes + + ######################################################################## # Source files # diff --git a/dev/releases/release_notes.py b/dev/releases/release_notes.py index 58e7119bb9..9d7eaf9cac 100755 --- a/dev/releases/release_notes.py +++ b/dev/releases/release_notes.py @@ -221,7 +221,7 @@ def get_pr_list(date: str, extra: str) -> List[Dict[str, Any]]: "--search", query, "--json", - "number,title,closedAt,labels,mergedAt", + "number,title,closedAt,labels,mergedAt,author", "--limit", "200", ], @@ -245,6 +245,14 @@ def has_label(pr: Dict[str, Any], label: str) -> bool: return any(x["name"] == label for x in pr["labels"]) +def is_dependabot_pr(pr: Dict[str, Any]) -> bool: + author = pr.get("author") or {} + login = author.get("login") + if login in ("app/dependabot", "dependabot[bot]"): + return True + return author.get("is_bot", False) and has_label(pr, "dependencies") + + def changes_overview( prs: List[Dict[str, Any]], startdate: str, new_version: str ) -> None: @@ -361,6 +369,7 @@ def main(new_version: str) -> None: print("Downloading filtered PR list") prs = get_pr_list(startdate, extra) + prs = [pr for pr in prs if not is_dependabot_pr(pr)] # print(json.dumps(prs, sort_keys=True, indent=4)) changes_overview(prs, startdate, new_version) diff --git a/dev/releases/test_release_notes.py b/dev/releases/test_release_notes.py new file mode 100644 index 0000000000..a06161afed --- /dev/null +++ b/dev/releases/test_release_notes.py @@ -0,0 +1,107 @@ +import release_notes + + +def test_is_dependabot_pr_detects_dependabot_author(): + pr = { + "author": {"is_bot": True, "login": "app/dependabot"}, + "labels": [ + {"name": "dependencies"}, + {"name": "github_actions"}, + ], + } + + assert release_notes.is_dependabot_pr(pr) + + pr = { + "author": {"is_bot": True, "login": "app/notdependabot"}, + "labels": [ + {"name": "dependencies"}, + {"name": "github_actions"}, + ], + } + + assert release_notes.is_dependabot_pr(pr) + + pr = { + "author": {"is_bot": False, "login": "app/dependabot"}, + "labels": [ + {"name": "dependencies"}, + {"name": "github_actions"}, + ], + } + + assert release_notes.is_dependabot_pr(pr) + + pr = { + "author": {"is_bot": False, "login": "app/notdependabot"}, + "labels": [ + {"name": "dependencies"}, + {"name": "github_actions"}, + ], + } + + assert not release_notes.is_dependabot_pr(pr) + + pr = { + "author": {"is_bot": False, "login": "app/dependabot"}, + "labels": [ + {"name": "github_actions"}, + ], + } + + assert release_notes.is_dependabot_pr(pr) + + pr = { + "author": {"is_bot": False, "login": "app/notdependabot"}, + "labels": [ + {"name": "github_actions"}, + ], + } + + assert not release_notes.is_dependabot_pr(pr) + + pr = { + "author": {"is_bot": True, "login": "app/notdependabot"}, + "labels": [ + {"name": "github_actions"}, + ], + } + + assert not release_notes.is_dependabot_pr(pr) + + pr = { + "author": {"is_bot": False, "login": "dependabot[bot]"}, + "labels": [ + {"name": "github_actions"}, + ], + } + + assert release_notes.is_dependabot_pr(pr) + + pr = { + "author": {"login": "dependabot[bot]"}, + "labels": [ + {"name": "github_actions"}, + ], + } + + assert release_notes.is_dependabot_pr(pr) + + pr = { + "author": {"login": "app/notdependabot"}, + "labels": [ + {"name": "github_actions"}, + ], + } + + assert not release_notes.is_dependabot_pr(pr) + + pr = { + "author": {"login": "app/notdependabot"}, + "labels": [ + {"name": "dependencies"}, + {"name": "github_actions"}, + ], + } + + assert not release_notes.is_dependabot_pr(pr) From f665358e8d2385abb5f3b163f7fc1cc3314c0640 Mon Sep 17 00:00:00 2001 From: Max Horn Date: Sat, 9 May 2026 10:15:58 +0100 Subject: [PATCH 211/234] Minor cleanup of random suff (#6377) --- lib/clas.gi | 4 ++-- lib/oprt.gi | 9 ++++----- src/ariths.c | 2 +- src/code.c | 10 +++++----- src/dt.c | 21 ++++++++++----------- src/error.h | 14 +++++++------- src/stringobj.c | 4 ++-- 7 files changed, 31 insertions(+), 33 deletions(-) diff --git a/lib/clas.gi b/lib/clas.gi index b2fd2037d0..2a27e3cbba 100644 --- a/lib/clas.gi +++ b/lib/clas.gi @@ -116,7 +116,7 @@ local fam, filter, cl; fi; filter:=filter and HasActingDomain and HasRepresentative and HasFunctionAction; - fam!.defaultClassType:=NewType( FamilyObj( G ), filter ); + fam!.defaultClassType:=NewType( fam, filter ); fi; cl:=rec( start := [ g ] ); @@ -141,7 +141,7 @@ local fam, filter, cl; fi; filter:=filter and HasActingDomain and HasRepresentative and HasFunctionAction and HasStabilizerOfExternalSet; - fam!.defaultClassCentType:=NewType( FamilyObj( G ), filter ); + fam!.defaultClassCentType:=NewType( fam, filter ); fi; cl:=rec( start := [ g ]); diff --git a/lib/oprt.gi b/lib/oprt.gi index 4714e76a6f..1d0b878fb0 100644 --- a/lib/oprt.gi +++ b/lib/oprt.gi @@ -587,10 +587,9 @@ end ); ## #M ActionHomomorphismConstructor( , ) ## -InstallGlobalFunction( ActionHomomorphismConstructor, function(arg) -local xset,surj,G, D, act, fam, filter, hom, i,blockacttest; +InstallGlobalFunction( ActionHomomorphismConstructor, function(xset, surj, arg...) +local G, D, act, fam, filter, hom, i,blockacttest; - xset:=arg[1];surj:=arg[2]; G := ActingDomain( xset ); D := HomeEnumerator( xset ); act := FunctionAction( xset ); @@ -650,8 +649,8 @@ local xset,surj,G, D, act, fam, filter, hom, i,blockacttest; end; hom := rec( ); - if Length(arg)>2 then - filter:=arg[3]; + if Length(arg)>0 then + filter:=arg[1]; elif IsExternalSetByActorsRep( xset ) then filter := filter and IsActionHomomorphismByActors; elif IsMatrixGroup( G ) diff --git a/src/ariths.c b/src/ariths.c index f908e4761a..92201121a3 100644 --- a/src/ariths.c +++ b/src/ariths.c @@ -20,7 +20,7 @@ #define RequireValue(funcname, val) \ do { \ - if (!val) \ + if (!(val)) \ ErrorMayQuit(funcname ": method should have returned a value", \ 0, 0); \ } while (0) diff --git a/src/code.c b/src/code.c index a5daa42082..85c73298ae 100644 --- a/src/code.c +++ b/src/code.c @@ -1755,14 +1755,14 @@ void CodeListExprEnd( } // allocate the list expression - if ( ! range && ! (top && tilde) ) { - list = NewExpr(cs, EXPR_LIST, INT_INTEXPR(pos) * sizeof(Expr)); + if (range) { + list = NewExpr(cs, EXPR_RANGE, INT_INTEXPR(pos) * sizeof(Expr)); } - else if ( ! range && (top && tilde) ) { + else if (top && tilde) { list = NewExpr(cs, EXPR_LIST_TILDE, INT_INTEXPR(pos) * sizeof(Expr)); } - else /* if ( range && ! (top && tilde) ) */ { - list = NewExpr(cs, EXPR_RANGE, INT_INTEXPR(pos) * sizeof(Expr)); + else { + list = NewExpr(cs, EXPR_LIST, INT_INTEXPR(pos) * sizeof(Expr)); } // enter the entries diff --git a/src/dt.c b/src/dt.c index e9f44de22b..67f2912197 100644 --- a/src/dt.c +++ b/src/dt.c @@ -61,7 +61,7 @@ #include "modules.h" #include "plist.h" -static void UnmarkTree(Obj z); +static void UnmarkTree(Obj tree); static UInt Mark(Obj tree, Obj reftree, Int indexx); static Int AlmostEqual(Obj tree1, Int index1, Obj tree2, Int index2); static Int Equal(Obj tree1, Int index1, Obj tree2, Int index2); @@ -726,16 +726,15 @@ static Int Leftof(Obj tree1, Int index1, Obj tree2, Int index2) */ static Int Leftof2(Obj tree1, Int index1, Obj tree2, Int index2) { - if ( DT_GEN(tree2, index2) < DT_GEN(tree1, DT_RIGHT(tree1, index1) ) ) - return 0; - else if (Equal(tree1, DT_RIGHT(tree1, index1), tree2, index2 ) ) - return 0; - else if (DT_GEN(tree2, index2) == DT_GEN(tree1, DT_RIGHT(tree1, index1)) ) - return Leftof(tree1, DT_RIGHT(tree1, index1), tree2, index2 ); - else if (Equal(tree1, DT_LEFT(tree1, index1), tree2, index2) ) - return 0; - else - return Leftof(tree1, DT_LEFT(tree1, index1), tree2, index2); + if (DT_GEN(tree2, index2) < DT_GEN(tree1, DT_RIGHT(tree1, index1))) + return 0; + if (Equal(tree1, DT_RIGHT(tree1, index1), tree2, index2)) + return 0; + if (DT_GEN(tree2, index2) == DT_GEN(tree1, DT_RIGHT(tree1, index1))) + return Leftof(tree1, DT_RIGHT(tree1, index1), tree2, index2); + if (Equal(tree1, DT_LEFT(tree1, index1), tree2, index2)) + return 0; + return Leftof(tree1, DT_LEFT(tree1, index1), tree2, index2); } diff --git a/src/error.h b/src/error.h index 64c3aa5a3f..7915e12756 100644 --- a/src/error.h +++ b/src/error.h @@ -192,13 +192,13 @@ void ErrorBoundedInt(const char * funcname, int min, int max) NORETURN; -#define RequireBoundedIntEx(funcname, op, argname, min, max) \ - do { \ - if (!(IS_INTOBJ(op) && min <= INT_INTOBJ(op) && \ - INT_INTOBJ(op) <= max)) { \ - ErrorBoundedInt(funcname, op, argname, min, max); \ - } \ - } while (0) +EXPORT_INLINE void RequireBoundedIntEx( + const char * funcname, Obj op, const char * argname, int min, int max) +{ + if (!(IS_INTOBJ(op) && min <= INT_INTOBJ(op) && INT_INTOBJ(op) <= max)) { + ErrorBoundedInt(funcname, op, argname, min, max); + } +} #define RequireBoundedInt(funcname, op, min, max) \ RequireBoundedIntEx(funcname, op, NICE_ARGNAME(op), min, max) diff --git a/src/stringobj.c b/src/stringobj.c index 9e70b53f53..c3f659de5b 100644 --- a/src/stringobj.c +++ b/src/stringobj.c @@ -1062,7 +1062,7 @@ static BOOL IsSSortString(Obj list) len = GET_LEN_STRING( list ); ptr = CONST_CHARS_STRING(list); for ( i = 1; i < len; i++ ) { - if ( ! (ptr[i-1] < ptr[i]) ) + if (ptr[i - 1] >= ptr[i]) break; } @@ -1468,7 +1468,7 @@ static Obj FuncPOSITION_SUBSTRING(Obj self, Obj string, Obj substr, Obj off) for (i = ipos; i < max; i++) { if (c == s[i]) { for (j = 1; j < lenss; j++) { - if (! (s[i+j] == ss[j])) + if (s[i + j] != ss[j]) break; } if (j == lenss) From 195a1c4a382ebafdc3db7823ec6dcbc5381c82f3 Mon Sep 17 00:00:00 2001 From: Max Horn Date: Sat, 9 May 2026 19:12:12 +0100 Subject: [PATCH 212/234] Avoid `IdGroup` in `IsSymmetricGroup` (#6383) --- lib/grpnames.gi | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/lib/grpnames.gi b/lib/grpnames.gi index fc9851910e..268109aa1a 100644 --- a/lib/grpnames.gi +++ b/lib/grpnames.gi @@ -1278,12 +1278,23 @@ InstallMethod( IsSymmetricGroup, return true; fi; + # the derived subgroup must be alternating and have index 2 G1 := DerivedSubgroup(G); - if not (IsAlternatingGroup(G1) and Index(G,G1) = 2) - # this requires deg>=4 - or not IsTrivial(Centralizer(G,G1)) - or Size(G) = 720 and IdGroup(G) <> [ 720, 763 ] - then return false; fi; + if not (IsAlternatingGroup(G1) and Index(G,G1) = 2) then + return false; + fi; + # the derived subgroup must have trivial centralizer (since degree >= 4) + if not IsTrivial(Centralizer(G,G1)) then + return false; + fi; + # one more special case: there are three groups of order 720 which satisfy + # the above (those with small group ids 763, 764, 765). So here we need + # extra work to pick the correct one: it is only one in which all elements + # have order <= 6. Conversely, the other two groups contain elements of + # order 8 or 10, but none of order 6 + if Size(G) = 720 and Order(First(G,x->Order(x)>=6)) > 6 then + return false; + fi; SetSymmetricDegree(G,AlternatingDegree(G1)); return true; end ); From 431a765bc42ba950126b0fbd98b7527187b32f7f Mon Sep 17 00:00:00 2001 From: Max Horn Date: Mon, 11 May 2026 10:46:15 +0200 Subject: [PATCH 213/234] kernel: turn global GAP and module states back into static globals (#6376) ... at least in plain GAP; keep them as before in HPC-GAP. The whole concept was invented to allow HPC-GAP to have thread local GAP and module state. In plain GAP, though, it introduced some minor overhead. Changing this here allows us to avoid the overhead, and it also prevents GAPState from becoming larger than 32kb. This can happen on platforms with a large jmp_buf (e.g., powerpc64). --- src/code.c | 16 ++- src/collectors.cc | 114 ++++++++++--------- src/cyclotom.c | 20 ++-- src/exprs.c | 11 +- src/funcs.c | 23 ++-- src/gap.c | 15 ++- src/gapstate.h | 66 ++++++----- src/io.c | 271 ++++++++++++++++++++++++---------------------- src/modules.c | 7 ++ src/modules.h | 6 + src/objcftl.c | 43 +++++--- src/objects.c | 108 +++++++++--------- src/objfgelm.cc | 2 + src/objpcgel.cc | 2 + src/opers.cc | 2 + src/permutat.cc | 10 +- src/pperm.cc | 11 +- src/trans.cc | 23 ++-- 18 files changed, 431 insertions(+), 319 deletions(-) diff --git a/src/code.c b/src/code.c index 85c73298ae..5ff2315c98 100644 --- a/src/code.c +++ b/src/code.c @@ -44,12 +44,15 @@ GAP_STATIC_ASSERT(sizeof(StatHeader) == 8, "StatHeader has wrong size"); +#ifdef HPCGAP struct CodeModuleState { - Bag StackStat; - Int CountStat; +#endif +DECL_MODULE_STATE Bag StackStat; +DECL_MODULE_STATE Int CountStat; - Bag StackExpr; - Int CountExpr; +DECL_MODULE_STATE Bag StackExpr; +DECL_MODULE_STATE Int CountExpr; +#ifdef HPCGAP }; static ModuleStateOffset CodeStateOffset = -1; @@ -60,6 +63,9 @@ extern inline struct CodeModuleState * CShelper(void) } #define CS(x) (CShelper()->x) +#else +#define CS(x) (x) +#endif /**************************************************************************** @@ -3250,8 +3256,10 @@ static StructInitInfo module = { .preSave = PreSave, .postRestore = PostRestore, +#ifdef HPCGAP .moduleStateSize = sizeof(struct CodeModuleState), .moduleStateOffsetPtr = &CodeStateOffset, +#endif .initModuleState = InitModuleState, }; diff --git a/src/collectors.cc b/src/collectors.cc index 9a127eda65..3a8f37b314 100644 --- a/src/collectors.cc +++ b/src/collectors.cc @@ -46,15 +46,19 @@ extern "C" { *F * * * * * * * * * * * * * module specific state * * * * * * * * * * * * * */ +#ifdef HPCGAP struct CollectorsState_ { - Obj SC_NW_STACK; - Obj SC_LW_STACK; - Obj SC_PW_STACK; - Obj SC_EW_STACK; - Obj SC_GE_STACK; - Obj SC_CW_VECTOR; - Obj SC_CW2_VECTOR; - UInt SC_MAX_STACK_SIZE; +#endif + +DECL_MODULE_STATE Obj SC_NW_STACK; +DECL_MODULE_STATE Obj SC_LW_STACK; +DECL_MODULE_STATE Obj SC_PW_STACK; +DECL_MODULE_STATE Obj SC_EW_STACK; +DECL_MODULE_STATE Obj SC_GE_STACK; +DECL_MODULE_STATE Obj SC_CW_VECTOR; +DECL_MODULE_STATE Obj SC_CW2_VECTOR; +DECL_MODULE_STATE UInt SC_MAX_STACK_SIZE; +#ifdef HPCGAP }; static ModuleStateOffset CollectorsStateOffset = -1; @@ -64,6 +68,17 @@ extern inline struct CollectorsState_ * CollectorsState(void) return (struct CollectorsState_ *)StateSlotsAtOffset(CollectorsStateOffset); } +#define SC_NW_STACK (CollectorsState()->SC_NW_STACK) +#define SC_LW_STACK (CollectorsState()->SC_LW_STACK) +#define SC_PW_STACK (CollectorsState()->SC_PW_STACK) +#define SC_EW_STACK (CollectorsState()->SC_EW_STACK) +#define SC_GE_STACK (CollectorsState()->SC_GE_STACK) +#define SC_CW_VECTOR (CollectorsState()->SC_CW_VECTOR) +#define SC_CW2_VECTOR (CollectorsState()->SC_CW2_VECTOR) +#define SC_MAX_STACK_SIZE (CollectorsState()->SC_MAX_STACK_SIZE) + +#endif + /**************************************************************************** ** @@ -84,7 +99,7 @@ extern inline struct CollectorsState_ * CollectorsState(void) */ #define SC_PUSH_WORD( word, exp ) \ if ( ++sp == max ) { \ - CollectorsState()->SC_MAX_STACK_SIZE *= 2; \ + SC_MAX_STACK_SIZE *= 2; \ return -1; \ } \ *++nw = DATA_WORD(word); \ @@ -95,7 +110,7 @@ extern inline struct CollectorsState_ * CollectorsState(void) #define SC_PUSH_GEN( gen, exp ) \ if ( ++sp == max ) { \ - CollectorsState()->SC_MAX_STACK_SIZE *= 2; \ + SC_MAX_STACK_SIZE *= 2; \ return -1; \ } \ *++nw = DATA_WORD(gen); \ @@ -385,22 +400,22 @@ static Int SingleCollectWord(Obj sc, Obj vv, Obj w) exps = (UInt)1 << (ebits-1); // contains the stack of words to insert - vnw = CollectorsState()->SC_NW_STACK; + vnw = SC_NW_STACK; // contains the word end of the word in - vlw = CollectorsState()->SC_LW_STACK; + vlw = SC_LW_STACK; // contains the position of the word in to look at - vpw = CollectorsState()->SC_PW_STACK; + vpw = SC_PW_STACK; // contains the unprocessed exponents at position - vew = CollectorsState()->SC_EW_STACK; + vew = SC_EW_STACK; // contains the global exponent of the word - vge = CollectorsState()->SC_GE_STACK; + vge = SC_GE_STACK; // get the maximal stack size - max = CollectorsState()->SC_MAX_STACK_SIZE; + max = SC_MAX_STACK_SIZE; // ensure that the stacks are large enough const UInt desiredStackSize = sizeof(Obj) * (max + 2); @@ -893,22 +908,22 @@ static Int CombiCollectWord(Obj sc, Obj vv, Obj w) exps = (UInt)1 << (ebits-1); // contains the stack of words to insert - vnw = CollectorsState()->SC_NW_STACK; + vnw = SC_NW_STACK; // contains the word end of the word in - vlw = CollectorsState()->SC_LW_STACK; + vlw = SC_LW_STACK; // contains the position of the word in to look at - vpw = CollectorsState()->SC_PW_STACK; + vpw = SC_PW_STACK; // contains the unprocessed exponents at position - vew = CollectorsState()->SC_EW_STACK; + vew = SC_EW_STACK; // contains the global exponent of the word - vge = CollectorsState()->SC_GE_STACK; + vge = SC_GE_STACK; // get the maximal stack size - max = CollectorsState()->SC_MAX_STACK_SIZE; + max = SC_MAX_STACK_SIZE; // ensure that the stacks are large enough const UInt desiredStackSize = sizeof(Obj) * (max + 2); @@ -1267,7 +1282,7 @@ static Obj ReducedComm(FinPowConjCol * fc, Obj sc, Obj w, Obj u) Obj vc2; // collect vector // use 'cwVector' to collect word * to - vcw = CollectorsState()->SC_CW_VECTOR; + vcw = SC_CW_VECTOR; num = SC_NUMBER_RWS_GENERATORS(sc); // check that it has the correct length, unpack into it @@ -1283,7 +1298,7 @@ static Obj ReducedComm(FinPowConjCol * fc, Obj sc, Obj w, Obj u) } // use 'cw2Vector' to collect word * to - vc2 = CollectorsState()->SC_CW2_VECTOR; + vc2 = SC_CW2_VECTOR; // check that it has the correct length, unpack into it if ( fc->vectorWord( vc2, w, num ) == -1 ) { @@ -1325,7 +1340,7 @@ static Obj ReducedForm(FinPowConjCol * fc, Obj sc, Obj w) Obj type; // type of the return objue // use 'cwVector' to collect word to - vcw = CollectorsState()->SC_CW_VECTOR; + vcw = SC_CW_VECTOR; num = SC_NUMBER_RWS_GENERATORS(sc); // check that it has the correct length @@ -1358,7 +1373,7 @@ static Obj ReducedLeftQuotient(FinPowConjCol * fc, Obj sc, Obj w, Obj u) Obj vc2; // collect vector // use 'cwVector' to collect word to - vcw = CollectorsState()->SC_CW_VECTOR; + vcw = SC_CW_VECTOR; num = SC_NUMBER_RWS_GENERATORS(sc); // check that it has the correct length, unpack into it @@ -1368,7 +1383,7 @@ static Obj ReducedLeftQuotient(FinPowConjCol * fc, Obj sc, Obj w, Obj u) } // use 'cw2Vector' to collect word to - vc2 = CollectorsState()->SC_CW2_VECTOR; + vc2 = SC_CW2_VECTOR; // check that it has the correct length, unpack into it if ( fc->vectorWord( vc2, u, num ) == -1 ) { @@ -1402,7 +1417,7 @@ static Obj ReducedProduct(FinPowConjCol * fc, Obj sc, Obj w, Obj u) Obj vcw; // collect vector // use 'cwVector' to collect word to - vcw = CollectorsState()->SC_CW_VECTOR; + vcw = SC_CW_VECTOR; num = SC_NUMBER_RWS_GENERATORS(sc); // check that it has the correct length, unpack into it @@ -1441,8 +1456,8 @@ static Obj ReducedPowerSmallInt(FinPowConjCol * fc, Obj sc, Obj w, Obj vpow) pow = INT_INTOBJ(vpow); // use 'cwVector' and 'cw2Vector to collect words to - vcw = CollectorsState()->SC_CW_VECTOR; - vc2 = CollectorsState()->SC_CW2_VECTOR; + vcw = SC_CW_VECTOR; + vc2 = SC_CW2_VECTOR; num = SC_NUMBER_RWS_GENERATORS(sc); type = SC_DEFAULT_TYPE(sc); @@ -1528,8 +1543,8 @@ static Obj ReducedQuotient(FinPowConjCol * fc, Obj sc, Obj w, Obj u) Obj vc2; // collect vector // use 'cwVector' to collect word to - vcw = CollectorsState()->SC_CW_VECTOR; - vc2 = CollectorsState()->SC_CW2_VECTOR; + vcw = SC_CW_VECTOR; + vc2 = SC_CW2_VECTOR; num = SC_NUMBER_RWS_GENERATORS(sc); type = SC_DEFAULT_TYPE(sc); @@ -1647,8 +1662,7 @@ static Obj FuncFinPowConjCol_ReducedQuotient ( Obj self, Obj sc, Obj w, Obj u ) */ static Obj FuncSET_SCOBJ_MAX_STACK_SIZE(Obj self, Obj size) { - CollectorsState()->SC_MAX_STACK_SIZE = - GetPositiveSmallInt(SELF_NAME, size); + SC_MAX_STACK_SIZE = GetPositiveSmallInt(SELF_NAME, size); return 0; } @@ -1739,25 +1753,25 @@ static Int InitLibrary ( static Int InitModuleState(void) { // register global bags with the garbage collector - InitGlobalBag( &CollectorsState()->SC_NW_STACK, "SC_NW_STACK" ); - InitGlobalBag( &CollectorsState()->SC_LW_STACK, "SC_LW_STACK" ); - InitGlobalBag( &CollectorsState()->SC_PW_STACK, "SC_PW_STACK" ); - InitGlobalBag( &CollectorsState()->SC_EW_STACK, "SC_EW_STACK" ); - InitGlobalBag( &CollectorsState()->SC_GE_STACK, "SC_GE_STACK" ); - InitGlobalBag( &CollectorsState()->SC_CW_VECTOR, "SC_CW_VECTOR" ); - InitGlobalBag( &CollectorsState()->SC_CW2_VECTOR, "SC_CW2_VECTOR" ); + InitGlobalBag(&SC_NW_STACK, "SC_NW_STACK"); + InitGlobalBag(&SC_LW_STACK, "SC_LW_STACK"); + InitGlobalBag(&SC_PW_STACK, "SC_PW_STACK"); + InitGlobalBag(&SC_EW_STACK, "SC_EW_STACK"); + InitGlobalBag(&SC_GE_STACK, "SC_GE_STACK"); + InitGlobalBag(&SC_CW_VECTOR, "SC_CW_VECTOR"); + InitGlobalBag(&SC_CW2_VECTOR, "SC_CW2_VECTOR"); const UInt maxStackSize = 256; const UInt desiredStackSize = sizeof(Obj) * (maxStackSize + 2); - CollectorsState()->SC_NW_STACK = NewKernelBuffer(desiredStackSize); - CollectorsState()->SC_LW_STACK = NewKernelBuffer(desiredStackSize); - CollectorsState()->SC_PW_STACK = NewKernelBuffer(desiredStackSize); - CollectorsState()->SC_EW_STACK = NewKernelBuffer(desiredStackSize); - CollectorsState()->SC_GE_STACK = NewKernelBuffer(desiredStackSize); + SC_NW_STACK = NewKernelBuffer(desiredStackSize); + SC_LW_STACK = NewKernelBuffer(desiredStackSize); + SC_PW_STACK = NewKernelBuffer(desiredStackSize); + SC_EW_STACK = NewKernelBuffer(desiredStackSize); + SC_GE_STACK = NewKernelBuffer(desiredStackSize); - CollectorsState()->SC_CW_VECTOR = NEW_STRING(0); - CollectorsState()->SC_CW2_VECTOR = NEW_STRING(0); - CollectorsState()->SC_MAX_STACK_SIZE = maxStackSize; + SC_CW_VECTOR = NEW_STRING(0); + SC_CW2_VECTOR = NEW_STRING(0); + SC_MAX_STACK_SIZE = maxStackSize; return 0; } @@ -1779,8 +1793,10 @@ static StructInitInfo module = { /* preSave = */ 0, /* postSave = */ 0, /* postRestore = */ 0, +#ifdef HPCGAP /* moduleStateSize = */ sizeof(CollectorsState_), /* moduleStateOffsetPtr = */ &CollectorsStateOffset, +#endif /* initModuleState = */ InitModuleState, /* destroyModuleState = */ 0, }; diff --git a/src/cyclotom.c b/src/cyclotom.c index 0686e459cd..3025530f94 100644 --- a/src/cyclotom.c +++ b/src/cyclotom.c @@ -142,10 +142,11 @@ static inline void SET_NOF_CYC(Obj cyc, Obj val) // #define XXX_CYC(cyc,len) (EXPOS_CYC(cyc,len)[0]) - +#ifdef HPCGAP static ModuleStateOffset CycStateOffset = -1; struct CycModuleState { +#endif /**************************************************************************** ** @@ -158,7 +159,7 @@ struct CycModuleState { ** It is created in 'InitCyc' with room for up to 1000 coefficients and is ** resized when need arises. */ -Obj ResultCyc; +DECL_MODULE_STATE Obj ResultCyc; /**************************************************************************** ** @@ -178,9 +179,10 @@ Obj ResultCyc; ** is called to compute $e_n^i$ and can then do this easier by just putting ** 1 at the th place in 'ResultCyc' and then calling 'Cyclotomic'. */ -Obj LastECyc; -UInt LastNCyc; +DECL_MODULE_STATE Obj LastECyc; +DECL_MODULE_STATE UInt LastNCyc; +#ifdef HPCGAP }; // end of struct CycModuleState extern inline struct CycModuleState *CycState(void) @@ -189,10 +191,10 @@ extern inline struct CycModuleState *CycState(void) } // For convenience and readability -#define ResultCyc CycState()->ResultCyc -#define LastECyc CycState()->LastECyc -#define LastNCyc CycState()->LastNCyc - +#define ResultCyc (CycState()->ResultCyc) +#define LastECyc (CycState()->LastECyc) +#define LastNCyc (CycState()->LastNCyc) +#endif static void GrowResultCyc(UInt size) { @@ -2201,8 +2203,10 @@ static StructInitInfo module = { .initKernel = InitKernel, .initLibrary = InitLibrary, +#ifdef HPCGAP .moduleStateSize = sizeof(struct CycModuleState), .moduleStateOffsetPtr = &CycStateOffset, +#endif .initModuleState = InitModuleState, }; diff --git a/src/exprs.c b/src/exprs.c index 511188322b..2c234633ad 100644 --- a/src/exprs.c +++ b/src/exprs.c @@ -40,7 +40,9 @@ #include "hpc/aobjects.h" #endif +#ifdef HPCGAP struct ExprsState { +#endif /**************************************************************************** ** @@ -55,10 +57,11 @@ struct ExprsState { ** This sometimes puts in superfluous parenthesis: 2 * f( (3 + 4) ), since it ** doesn't know that a function call adds automatically parenthesis. */ -UInt PrintPrecedence; +DECL_MODULE_STATE UInt PrintPrecedence; -UInt OldPrintPrecedence; +DECL_MODULE_STATE UInt OldPrintPrecedence; +#ifdef HPCGAP }; static ModuleStateOffset ExprsStateOffset = -1; @@ -70,6 +73,7 @@ extern inline struct ExprsState * ExprsState(void) #define PrintPrecedence ExprsState()->PrintPrecedence #define OldPrintPrecedence ExprsState()->OldPrintPrecedence +#endif /**************************************************************************** ** @@ -1814,9 +1818,10 @@ static StructInitInfo module = { .name = "exprs", .initKernel = InitKernel, .initLibrary = InitLibrary, - +#ifdef HPCGAP .moduleStateSize = sizeof(struct ExprsState), .moduleStateOffsetPtr = &ExprsStateOffset, +#endif }; StructInitInfo * InitInfoExprs ( void ) diff --git a/src/funcs.c b/src/funcs.c index 9937ad4699..62919177f5 100644 --- a/src/funcs.c +++ b/src/funcs.c @@ -41,10 +41,13 @@ #endif +#ifdef HPCGAP static ModuleStateOffset FuncsStateOffset = -1; struct FuncsModuleState { - Int RecursionDepth; +#endif + DECL_MODULE_STATE Int RecursionDepth; +#ifdef HPCGAP }; extern inline struct FuncsModuleState *FuncsState(void) @@ -52,32 +55,35 @@ extern inline struct FuncsModuleState *FuncsState(void) return (struct FuncsModuleState *)StateSlotsAtOffset(FuncsStateOffset); } +#define RecursionDepth (FuncsState()->RecursionDepth) +#endif + Int IncRecursionDepth(void) { - int depth = ++(FuncsState()->RecursionDepth); + int depth = ++RecursionDepth; return depth; } void DecRecursionDepth(void) { - FuncsState()->RecursionDepth--; + RecursionDepth--; /* FIXME: According to a comment in the function RecursionDepthTrap below, RecursionDepth can become "slightly" negative. This needs some investigation. - GAP_ASSERT(FuncsState()->RecursionDepth >= 0); + GAP_ASSERT(RecursionDepth >= 0); */ } Int GetRecursionDepth(void) { - return FuncsState()->RecursionDepth; + return RecursionDepth; } void SetRecursionDepth(Int depth) { GAP_ASSERT(depth >= 0); - FuncsState()->RecursionDepth = depth; + RecursionDepth = depth; } /**************************************************************************** @@ -879,7 +885,7 @@ static Int InitKernel ( static Int InitModuleState(void) { - FuncsState()->RecursionDepth = 0; + RecursionDepth = 0; return 0; } @@ -895,9 +901,10 @@ static StructInitInfo module = { .name = "funcs", .initKernel = InitKernel, .initLibrary = InitLibrary, - +#ifdef HPCGAP .moduleStateSize = sizeof(struct FuncsModuleState), .moduleStateOffsetPtr = &FuncsStateOffset, +#endif .initModuleState = InitModuleState, }; diff --git a/src/gap.c b/src/gap.c index a2b02693be..711c0eb142 100644 --- a/src/gap.c +++ b/src/gap.c @@ -18,10 +18,10 @@ #include "compiler.h" #include "error.h" #include "funcs.h" -#include "gapstate.h" #ifdef USE_GASMAN #include "gasman_intern.h" #endif +#include "gapstate.h" #include "gaptime.h" #include "gvars.h" #include "integer.h" @@ -123,11 +123,18 @@ static UInt Time; */ static UInt MemoryAllocated; - #ifndef HPCGAP -GAPState MainGAPState; -#endif +// HACK: include gapstate a second time, but with DECL_GAP_STATE +// defined to be empty, to root the global variables here; i.e., +// `DECL_GAP_STATE Obj Tilde;` is turned into just `Obj Tilde;` +// and so on. +#undef GAP_GAPSTATE_H +#undef DECL_GAP_STATE +#define DECL_GAP_STATE +#include "gapstate.h" + +#endif /**************************************************************************** ** diff --git a/src/gapstate.h b/src/gapstate.h index 16d74d2c8a..4cb6060d63 100644 --- a/src/gapstate.h +++ b/src/gapstate.h @@ -23,31 +23,35 @@ #include +#ifdef HPCGAP enum { STATE_SLOTS_SIZE = 32768 - 1024, }; +#define DECL_GAP_STATE + typedef struct GAPState { -#ifdef HPCGAP // TLS data -- this *must* come first, so that we can safely // cast a GAPState pointer into a ThreadLocalStorage pointer ThreadLocalStorage tls; +#elif !defined(DECL_GAP_STATE) +#define DECL_GAP_STATE extern #endif // for Boehm GC #if defined(USE_BOEHM_GC) #define MAX_GC_PREFIX_DESC 4 - void ** FreeList[MAX_GC_PREFIX_DESC + 2]; + DECL_GAP_STATE void ** FreeList[MAX_GC_PREFIX_DESC + 2]; #endif // From intrprtr.c - Obj Tilde; + DECL_GAP_STATE Obj Tilde; // The current assertion level for use in Assert - Int CurrentAssertionLevel; + DECL_GAP_STATE Int CurrentAssertionLevel; // From gvar.c - Obj CurrNamespace; + DECL_GAP_STATE Obj CurrNamespace; // From vars.c @@ -57,19 +61,19 @@ typedef struct GAPState { // Assignments to the local variables change this bag. We do not call // 'CHANGED_BAG' for each of such change. Instead we wait until a garbage // collection begins and then call 'CHANGED_BAG' in 'BeginCollectBags'. - Bag CurrLVars; + DECL_GAP_STATE Bag CurrLVars; // 'PtrLVars' is a pointer to the 'STATE(CurrLVars)' bag. This makes it // faster to access local variables. // // Since a garbage collection may move this bag around, the pointer // 'PtrLVars' must be recalculated afterwards in 'VarsAfterCollectBags'. - Obj * PtrLVars; + DECL_GAP_STATE Obj * PtrLVars; - Bag LVarsPool[16]; + DECL_GAP_STATE Bag LVarsPool[16]; // From read.c - jmp_buf ReadJmpError; + DECL_GAP_STATE jmp_buf ReadJmpError; // 'Prompt' holds the string that is to be printed if a new line is read // from the interactive files '*stdin*' or '*errin*'. @@ -77,19 +81,19 @@ typedef struct GAPState { // It is set to 'gap> ' or 'brk> ' in the read-eval-print loops and // changed to the partial prompt '> ' in 'Read' after the first symbol is // read. - char Prompt[80]; + DECL_GAP_STATE char Prompt[80]; // From stats.c // `ReturnObjStat` is the result of the return-statement that was last // executed. It is set in `ExecReturnObj` and used in the handlers that // interpret functions. - Obj ReturnObjStat; + DECL_GAP_STATE Obj ReturnObjStat; - ExecStatFunc * CurrExecStatFuncs; + DECL_GAP_STATE ExecStatFunc * CurrExecStatFuncs; // From code.c - void * PtrBody; + DECL_GAP_STATE void * PtrBody; // From opers.c #ifdef HPCGAP @@ -99,36 +103,37 @@ typedef struct GAPState { #endif // for use by GAP_TRY / GAP_CATCH and related code - int TryCatchDepth; + DECL_GAP_STATE int TryCatchDepth; // Set by `FuncJUMP_TO_CATCH` to the value of its second argument, and // and then later extracted by `CALL_WITH_CATCH`. Not currently used by // the GAP kernel itself, as far as I can tell. - Obj ThrownObject; + DECL_GAP_STATE Obj ThrownObject; // Set to TRUE when a read-eval-loop encounters a `quit` statement. - BOOL UserHasQuit; + DECL_GAP_STATE BOOL UserHasQuit; // Set to TRUE when a read-eval-loop encounters a `QUIT` statement. - BOOL UserHasQUIT; + DECL_GAP_STATE BOOL UserHasQUIT; // Set by the primary read-eval loop in `FuncSHELL`, based on the value of // `ErrorLLevel`. Also, `ReadEvalCommand` saves and restores this value // before executing code. - Obj ErrorLVars; + DECL_GAP_STATE Obj ErrorLVars; // Records where on the stack `ErrorLVars` is relative to the top; this is // modified by `FuncDownEnv` / `FuncUpEnv`, and ultimately used and // controlled by the primary read-eval loop in `FuncSHELL`. - Int ErrorLLevel; + DECL_GAP_STATE Int ErrorLLevel; // This callback is called in FuncJUMP_TO_CATCH, this is not used by GAP // itself but by programs that use GAP as a library to handle errors - void (*JumpToCatchCallback)(void); + DECL_GAP_STATE void (*JumpToCatchCallback)(void); // From info.c - Int ShowUsedInfoClassesActive; + DECL_GAP_STATE Int ShowUsedInfoClassesActive; +#ifdef HPCGAP UInt1 StateSlots[STATE_SLOTS_SIZE]; } GAPState; @@ -136,26 +141,25 @@ typedef struct GAPState { // so that all its members can be access with a 16 bit signed offset GAP_STATIC_ASSERT(sizeof(GAPState) < 32768, "GAPState is too big"); -#ifdef HPCGAP +#define DECL_MODULE_STATE EXPORT_INLINE GAPState * ActiveGAPState(void) { return (GAPState *)GetTLS(); } +#define STATE(x) (ActiveGAPState()->x) + #else -extern GAPState MainGAPState; +#define DECL_MODULE_STATE static -EXPORT_INLINE GAPState * ActiveGAPState(void) -{ - return &MainGAPState; -} +#define STATE(x) (x) #endif -#define STATE(x) (ActiveGAPState()->x) +#ifdef HPCGAP // Offset into StateSlots typedef Int ModuleStateOffset; @@ -167,7 +171,9 @@ EXPORT_INLINE void * StateSlotsAtOffset(ModuleStateOffset offset) } // Access a module's registered state -#define MODULE_STATE(module) \ - (*(module ## ModuleState *)StateSlotsAtOffset(module ## StateOffset)) +#define MODULE_STATE(module, ident) \ + (((module ## ModuleState *)StateSlotsAtOffset(module ## StateOffset))->ident) + +#endif #endif // GAP_GAPSTATE_H diff --git a/src/io.c b/src/io.c index d3d24163a8..f17e34e606 100644 --- a/src/io.c +++ b/src/io.c @@ -74,65 +74,73 @@ static Obj SetPrintFormattingStatus; static Obj FilenameCache; static SymbolTable FilenameSymbolTable; -static ModuleStateOffset IOStateOffset = -1; - enum { MAX_OPEN_FILES = 16, }; +#ifdef HPCGAP +static ModuleStateOffset IOStateOffset = -1; + struct IOModuleState { +#endif // A pointer to the current input file - TypInputFile * Input; + DECL_MODULE_STATE TypInputFile * Input; // A pointer to the current output file. It points to the top of the // stack 'OutputFiles'. - TypOutputFile * Output; + DECL_MODULE_STATE TypOutputFile * Output; // - TypOutputFile * IgnoreStdoutErrout; + DECL_MODULE_STATE TypOutputFile * IgnoreStdoutErrout; // The file identifier of the current input logfile. If it is not 0 the // scanner echoes all input from the files '*stdin*' and '*errin*' to // this file. - TypOutputFile * InputLog; + DECL_MODULE_STATE TypOutputFile * InputLog; // The file identifier of the current output logfile. If it is not 0 the // scanner echoes all output to the files '*stdout*' and '*errout*' to // this file. - TypOutputFile * OutputLog; + DECL_MODULE_STATE TypOutputFile * OutputLog; - TypOutputFile InputLogFileOrStream; - TypOutputFile OutputLogFileOrStream; + DECL_MODULE_STATE TypOutputFile InputLogFileOrStream; + DECL_MODULE_STATE TypOutputFile OutputLogFileOrStream; - TypOutputFile DefaultOutput; + DECL_MODULE_STATE TypOutputFile DefaultOutput; #ifdef HPCGAP - Obj DefaultOutputStream; - Obj DefaultInputStream; + DECL_MODULE_STATE Obj DefaultOutputStream; + DECL_MODULE_STATE Obj DefaultInputStream; #endif - Int NoSplitLine; + DECL_MODULE_STATE Int NoSplitLine; - BOOL PrintFormattingForStdout; - BOOL PrintFormattingForErrout; + DECL_MODULE_STATE BOOL PrintFormattingForStdout; + DECL_MODULE_STATE BOOL PrintFormattingForErrout; +#ifdef HPCGAP }; // for debugging from GDB / lldb, we mark this as extern inline -extern inline struct IOModuleState * IO(void) +extern inline struct IOModuleState * IOHelper(void) { return (struct IOModuleState *)StateSlotsAtOffset(IOStateOffset); } +#define IO(x) (IOHelper()->x) +#else +#define IO(x) (x) +#endif + void LockCurrentOutput(BOOL lock) { - IO()->IgnoreStdoutErrout = lock ? IO()->Output : NULL; + IO(IgnoreStdoutErrout) = lock ? IO(Output) : NULL; } TypInputFile * GetCurrentInput(void) { - return IO()->Input; + return IO(Input); } /**************************************************************************** @@ -279,7 +287,7 @@ static GVarDescriptor DEFAULT_OUTPUT_STREAM; static UInt OpenDefaultInput(TypInputFile * input) { Obj func, stream; - stream = IO()->DefaultInputStream; + stream = IO(DefaultInputStream); if (stream) return OpenInputStream(input, stream, FALSE); func = GVarOptFunction(&DEFAULT_INPUT_STREAM); @@ -290,14 +298,14 @@ static UInt OpenDefaultInput(TypInputFile * input) ErrorQuit("DEFAULT_INPUT_STREAM() did not return a stream", 0, 0); if (IsStringConv(stream)) return OpenInput(input, CONST_CSTR_STRING(stream)); - IO()->DefaultInputStream = stream; + IO(DefaultInputStream) = stream; return OpenInputStream(input, stream, FALSE); } static UInt OpenDefaultOutput(TypOutputFile * output) { Obj func, stream; - stream = IO()->DefaultOutputStream; + stream = IO(DefaultOutputStream); if (stream) return OpenOutputStream(output, stream); func = GVarOptFunction(&DEFAULT_OUTPUT_STREAM); @@ -308,7 +316,7 @@ static UInt OpenDefaultOutput(TypOutputFile * output) ErrorQuit("DEFAULT_OUTPUT_STREAM() did not return a stream", 0, 0); if (IsStringConv(stream)) return OpenOutput(output, CONST_CSTR_STRING(stream), FALSE); - IO()->DefaultOutputStream = stream; + IO(DefaultOutputStream) = stream; return OpenOutputStream(output, stream); } #endif @@ -353,7 +361,7 @@ UInt OpenInput(TypInputFile * input, const Char * filename) /* Handle *defin*; redirect *errin* to *defin* if the default * channel is already open. */ if (streq(filename, "*defin*") || - (streq(filename, "*errin*") && IO()->DefaultInputStream)) + (streq(filename, "*errin*") && IO(DefaultInputStream))) return OpenDefaultInput(input); #endif @@ -367,7 +375,7 @@ UInt OpenInput(TypInputFile * input, const Char * filename) // paranoia: fill with garbage, to verify we initialize everything memset(input, 0x47, sizeof(TypInputFile)); #endif - input->prev = IO()->Input; + input->prev = IO(Input); input->stream = 0; input->file = file; @@ -386,7 +394,7 @@ UInt OpenInput(TypInputFile * input, const Char * filename) input->number = 1; input->lastErrorLine = 0; - IO()->Input = input; + IO(Input) = input; // indicate success return 1; @@ -408,7 +416,7 @@ UInt OpenInputStream(TypInputFile * input, Obj stream, BOOL echo) // paranoia: fill with garbage, to verify we initialize everything memset(input, 0x47, sizeof(TypInputFile)); #endif - input->prev = IO()->Input; + input->prev = IO(Input); input->stream = stream; input->file = -1; input->isstringstream = (CALL_1ARGS(IsInputStringStream, stream) == True); @@ -429,7 +437,7 @@ UInt OpenInputStream(TypInputFile * input, Obj stream, BOOL echo) input->number = 1; input->lastErrorLine = 0; - IO()->Input = input; + IO(Input) = input; // indicate success return 1; @@ -454,10 +462,10 @@ UInt OpenInputStream(TypInputFile * input, Obj stream, BOOL echo) UInt CloseInput(TypInputFile * input) { GAP_ASSERT(input); - GAP_ASSERT(input == IO()->Input); + GAP_ASSERT(input == IO(Input)); // revert to previous input - IO()->Input = input->prev; + IO(Input) = input->prev; if (input->stream) { // if the input stream supports seeking, update its position to @@ -515,17 +523,17 @@ UInt OpenLog ( { // refuse to open a logfile if we already log to one - if (IO()->InputLog != 0 || IO()->OutputLog != 0) + if (IO(InputLog) != 0 || IO(OutputLog) != 0) return 0; // try to open the file - IO()->OutputLogFileOrStream.file = SyFopen(filename, "w", FALSE); - IO()->OutputLogFileOrStream.stream = 0; - if (IO()->OutputLogFileOrStream.file == -1) + IO(OutputLogFileOrStream).file = SyFopen(filename, "w", FALSE); + IO(OutputLogFileOrStream).stream = 0; + if (IO(OutputLogFileOrStream).file == -1) return 0; - IO()->InputLog = &IO()->OutputLogFileOrStream; - IO()->OutputLog = &IO()->OutputLogFileOrStream; + IO(InputLog) = &IO(OutputLogFileOrStream); + IO(OutputLog) = &IO(OutputLogFileOrStream); // otherwise indicate success return 1; @@ -543,15 +551,15 @@ UInt OpenLogStream ( { // refuse to open a logfile if we already log to one - if (IO()->InputLog != 0 || IO()->OutputLog != 0) + if (IO(InputLog) != 0 || IO(OutputLog) != 0) return 0; // try to open the file - IO()->OutputLogFileOrStream.stream = stream; - IO()->OutputLogFileOrStream.file = -1; + IO(OutputLogFileOrStream).stream = stream; + IO(OutputLogFileOrStream).file = -1; - IO()->InputLog = &IO()->OutputLogFileOrStream; - IO()->OutputLog = &IO()->OutputLogFileOrStream; + IO(InputLog) = &IO(OutputLogFileOrStream); + IO(OutputLog) = &IO(OutputLogFileOrStream); // otherwise indicate success return 1; @@ -572,16 +580,16 @@ UInt OpenLogStream ( UInt CloseLog ( void ) { // refuse to close a non existent logfile - if (IO()->InputLog == 0 || IO()->OutputLog == 0 || - IO()->InputLog != IO()->OutputLog) + if (IO(InputLog) == 0 || IO(OutputLog) == 0 || + IO(InputLog) != IO(OutputLog)) return 0; // close the logfile - if (!IO()->InputLog->stream) { - SyFclose(IO()->InputLog->file); + if (!IO(InputLog)->stream) { + SyFclose(IO(InputLog)->file); } - IO()->InputLog = 0; - IO()->OutputLog = 0; + IO(InputLog) = 0; + IO(OutputLog) = 0; // indicate success return 1; @@ -608,16 +616,16 @@ UInt OpenInputLog ( { // refuse to open a logfile if we already log to one - if (IO()->InputLog != 0) + if (IO(InputLog) != 0) return 0; // try to open the file - IO()->InputLogFileOrStream.file = SyFopen(filename, "w", FALSE); - IO()->InputLogFileOrStream.stream = 0; - if (IO()->InputLogFileOrStream.file == -1) + IO(InputLogFileOrStream).file = SyFopen(filename, "w", FALSE); + IO(InputLogFileOrStream).stream = 0; + if (IO(InputLogFileOrStream).file == -1) return 0; - IO()->InputLog = &IO()->InputLogFileOrStream; + IO(InputLog) = &IO(InputLogFileOrStream); // otherwise indicate success return 1; @@ -635,14 +643,14 @@ UInt OpenInputLogStream ( { // refuse to open a logfile if we already log to one - if (IO()->InputLog != 0) + if (IO(InputLog) != 0) return 0; // try to open the file - IO()->InputLogFileOrStream.stream = stream; - IO()->InputLogFileOrStream.file = -1; + IO(InputLogFileOrStream).stream = stream; + IO(InputLogFileOrStream).file = -1; - IO()->InputLog = &IO()->InputLogFileOrStream; + IO(InputLog) = &IO(InputLogFileOrStream); // otherwise indicate success return 1; @@ -663,19 +671,19 @@ UInt OpenInputLogStream ( UInt CloseInputLog ( void ) { // refuse to close a non existent logfile - if (IO()->InputLog == 0) + if (IO(InputLog) == 0) return 0; // refuse to close a log opened with LogTo - if (IO()->InputLog == IO()->OutputLog) + if (IO(InputLog) == IO(OutputLog)) return 0; // close the logfile - if (!IO()->InputLog->stream) { - SyFclose(IO()->InputLog->file); + if (!IO(InputLog)->stream) { + SyFclose(IO(InputLog)->file); } - IO()->InputLog = 0; + IO(InputLog) = 0; // indicate success return 1; @@ -702,17 +710,17 @@ UInt OpenOutputLog ( { // refuse to open a logfile if we already log to one - if (IO()->OutputLog != 0) + if (IO(OutputLog) != 0) return 0; // try to open the file - memset(&IO()->OutputLogFileOrStream, 0, sizeof(TypOutputFile)); - IO()->OutputLogFileOrStream.stream = 0; - IO()->OutputLogFileOrStream.file = SyFopen(filename, "w", FALSE); - if (IO()->OutputLogFileOrStream.file == -1) + memset(&IO(OutputLogFileOrStream), 0, sizeof(TypOutputFile)); + IO(OutputLogFileOrStream).stream = 0; + IO(OutputLogFileOrStream).file = SyFopen(filename, "w", FALSE); + if (IO(OutputLogFileOrStream).file == -1) return 0; - IO()->OutputLog = &IO()->OutputLogFileOrStream; + IO(OutputLog) = &IO(OutputLogFileOrStream); // otherwise indicate success return 1; @@ -730,15 +738,15 @@ UInt OpenOutputLogStream ( { // refuse to open a logfile if we already log to one - if (IO()->OutputLog != 0) + if (IO(OutputLog) != 0) return 0; // try to open the file - memset(&IO()->OutputLogFileOrStream, 0, sizeof(TypOutputFile)); - IO()->OutputLogFileOrStream.stream = stream; - IO()->OutputLogFileOrStream.file = -1; + memset(&IO(OutputLogFileOrStream), 0, sizeof(TypOutputFile)); + IO(OutputLogFileOrStream).stream = stream; + IO(OutputLogFileOrStream).file = -1; - IO()->OutputLog = &IO()->OutputLogFileOrStream; + IO(OutputLog) = &IO(OutputLogFileOrStream); // otherwise indicate success return 1; @@ -759,19 +767,19 @@ UInt OpenOutputLogStream ( UInt CloseOutputLog ( void ) { // refuse to close a non existent logfile - if (IO()->OutputLog == 0) + if (IO(OutputLog) == 0) return 0; // refuse to close a log opened with LogTo - if (IO()->OutputLog == IO()->InputLog) + if (IO(OutputLog) == IO(InputLog)) return 0; // close the logfile - if (!IO()->OutputLog->stream) { - SyFclose(IO()->OutputLog->file); + if (!IO(OutputLog)->stream) { + SyFclose(IO(OutputLog)->file); } - IO()->OutputLog = 0; + IO(OutputLog) = 0; // indicate success return 1; @@ -816,7 +824,7 @@ UInt OpenOutput(TypOutputFile * output, const Char * filename, BOOL append) GAP_ASSERT(output); // do nothing for stdout and errout if caught - if (IO()->Output != NULL && IO()->IgnoreStdoutErrout == IO()->Output && + if (IO(Output) != NULL && IO(IgnoreStdoutErrout) == IO(Output) && (streq(filename, "*errout*") || streq(filename, "*stdout*"))) { return 1; } @@ -839,17 +847,17 @@ UInt OpenOutput(TypOutputFile * output, const Char * filename, BOOL append) // paranoia: fill with garbage, to verify we initialize everything memset(output, 0x47, sizeof(TypOutputFile)); #endif - output->prev = IO()->Output; - IO()->Output = output; + output->prev = IO(Output); + IO(Output) = output; output->isstringstream = FALSE; output->stream = 0; output->file = file; output->line[0] = '\0'; output->pos = 0; if (streq(filename, "*stdout*")) - output->format = IO()->PrintFormattingForStdout; + output->format = IO(PrintFormattingForStdout); else if (streq(filename, "*errout*")) - output->format = IO()->PrintFormattingForErrout; + output->format = IO(PrintFormattingForErrout); else output->format = TRUE; output->indent = 0; @@ -879,8 +887,8 @@ UInt OpenOutputStream(TypOutputFile * output, Obj stream) // paranoia: fill with garbage, to verify we initialize everything memset(output, 0x47, sizeof(TypOutputFile)); #endif - output->prev = IO()->Output; - IO()->Output = output; + output->prev = IO(Output); + IO(Output) = output; output->isstringstream = (CALL_1ARGS(IsOutputStringStream, stream) == True); output->stream = stream; output->file = -1; @@ -921,15 +929,15 @@ UInt CloseOutput(TypOutputFile * output) // silently refuse to close the test output file; this is probably an // attempt to close *errout* which is silently not opened, so let's // silently not close it - if (IO()->IgnoreStdoutErrout == IO()->Output) + if (IO(IgnoreStdoutErrout) == IO(Output)) return 1; - GAP_ASSERT(output == IO()->Output); + GAP_ASSERT(output == IO(Output)); // refuse to close the initial output file '*stdout*' #ifdef HPCGAP if (output->prev == 0 && output->stream && - IO()->DefaultOutputStream == output->stream) + IO(DefaultOutputStream) == output->stream) return 0; #else if (output->prev == 0) @@ -943,7 +951,7 @@ UInt CloseOutput(TypOutputFile * output) } // revert to previous output file and indicate success - IO()->Output = output->prev; + IO(Output) = output->prev; // don't keep GAP objects alive unnecessarily output->stream = 0; @@ -1068,7 +1076,7 @@ static Char GetLine(TypInputFile * input) Pr("%c", (Int)'\03', 0); } else if (input->file == 0 || input->file == 2) { - if (IO()->Output->pos > 0) + if (IO(Output)->pos > 0) Pr("\n", 0, 0); if ( PrintPromptHook ) Call0ArgsInNewReader( PrintPromptHook ); @@ -1095,9 +1103,9 @@ static Char GetLine(TypInputFile * input) } // if necessary echo the line to the logfile - if (IO()->InputLog != 0 && input->echo == 1) + if (IO(InputLog) != 0 && input->echo == 1) if (!(input->ptr[0] == '\377' && input->ptr[1] == '\0')) - PutLine2(IO()->InputLog, input->ptr, strlen(input->ptr)); + PutLine2(IO(InputLog), input->ptr, strlen(input->ptr)); // return the current character return *input->ptr; @@ -1156,9 +1164,9 @@ static void PutLineTo(TypOutputFile * stream, UInt len) PutLine2( stream, stream->line, len ); // if necessary echo it to the logfile - if (IO()->OutputLog != 0 && !stream->stream) { + if (IO(OutputLog) != 0 && !stream->stream) { if (stream->file == 1 || stream->file == 3) { - PutLine2(IO()->OutputLog, stream->line, len); + PutLine2(IO(OutputLog), stream->line, len); } } } @@ -1298,9 +1306,9 @@ static void PutChrTo(TypOutputFile * stream, Char ch) /* TODO: For threads other than the main thread, reserve some extra space for the thread id indicator. See issue #136. */ else if (stream->pos < - SyNrCols - 2 - 6 * (TLS(threadID) != 0) - IO()->NoSplitLine) { + SyNrCols - 2 - 6 * (TLS(threadID) != 0) - IO(NoSplitLine)) { #else - else if (stream->pos < SyNrCols - 2 - IO()->NoSplitLine) { + else if (stream->pos < SyNrCols - 2 - IO(NoSplitLine)) { #endif // put the character on this line @@ -1390,7 +1398,7 @@ static void PutChrTo(TypOutputFile * stream, Char ch) */ static Obj FuncToggleEcho(Obj self) { - IO()->Input->echo = !IO()->Input->echo; + IO(Input)->echo = !IO(Input)->echo; return (Obj)0; } @@ -1428,8 +1436,8 @@ static Obj FuncPRINT_CPROMPT(Obj self, Obj prompt) void ResetOutputIndent(void) { - GAP_ASSERT(IO()->Output); - IO()->Output->indent = 0; + GAP_ASSERT(IO(Output)); + IO(Output)->indent = 0; } @@ -1625,14 +1633,14 @@ static inline void FormatOutput( // with null bytes, behavior of 'prec' is undefined. if (*q == '\0') continue; - if (*q == '\\' && IO()->NoSplitLine == 0) { + if (*q == '\\' && IO(NoSplitLine) == 0) { if (*(q + 1) < '8' && *(q + 1) >= '0') - IO()->NoSplitLine = 3; + IO(NoSplitLine) = 3; else - IO()->NoSplitLine = 1; + IO(NoSplitLine) = 1; } - else if (IO()->NoSplitLine > 0) - IO()->NoSplitLine--; + else if (IO(NoSplitLine) > 0) + IO(NoSplitLine)--; put_a_char(state, *q); if (arg1obj) { @@ -1788,11 +1796,11 @@ void Pr ( Int arg2 ) { #ifdef HPCGAP - if (!IO()->Output) { - OpenDefaultOutput(&IO()->DefaultOutput); + if (!IO(Output)) { + OpenDefaultOutput(&IO(DefaultOutput)); } #endif - PrTo(IO()->Output, format, arg1, arg2); + PrTo(IO(Output), format, arg1, arg2); } typedef struct { @@ -1818,52 +1826,52 @@ void SPrTo(Char *buffer, UInt maxlen, const Char *format, Int arg1, Int arg2) static Obj FuncINPUT_FILENAME(Obj self) { - if (IO()->Input == 0) + if (IO(Input) == 0) return MakeImmString("*defin*"); - UInt gapnameid = GetInputFilenameID(IO()->Input); + UInt gapnameid = GetInputFilenameID(IO(Input)); return GetCachedFilename(gapnameid); } static Obj FuncINPUT_LINENUMBER(Obj self) { - return INTOBJ_INT(IO()->Input ? IO()->Input->number : 0); + return INTOBJ_INT(IO(Input) ? IO(Input)->number : 0); } static Obj FuncSET_PRINT_FORMATTING_STDOUT(Obj self, Obj val) { BOOL format = (val != False); - TypOutputFile * output = IO()->Output; + TypOutputFile * output = IO(Output); while (output) { if (!output->stream && output->file == 1) output->format = format; output = output->prev; } - IO()->PrintFormattingForStdout = format; + IO(PrintFormattingForStdout) = format; return 0; } static Obj FuncPRINT_FORMATTING_STDOUT(Obj self) { - return IO()->PrintFormattingForStdout ? True : False; + return IO(PrintFormattingForStdout) ? True : False; } static Obj FuncSET_PRINT_FORMATTING_ERROUT(Obj self, Obj val) { BOOL format = (val != False); - TypOutputFile * output = IO()->Output; + TypOutputFile * output = IO(Output); while (output) { if (!output->stream && output->file == 3) output->format = format; output = output->prev; } - IO()->PrintFormattingForErrout = format; + IO(PrintFormattingForErrout) = format; return 0; } static Obj FuncPRINT_FORMATTING_ERROUT(Obj self) { - return IO()->PrintFormattingForErrout ? True : False; + return IO(PrintFormattingForErrout) ? True : False; } /**************************************************************************** @@ -1878,7 +1886,7 @@ static Obj FuncCALL_WITH_FORMATTING_STATUS(Obj self, Obj status, Obj func, Obj a RequireTrueOrFalse(SELF_NAME, status); RequireSmallList(SELF_NAME, args); - TypOutputFile * output = IO()->Output; + TypOutputFile * output = IO(Output); if (!output) ErrorMayQuit("CALL_WITH_FORMATTING_STATUS called while no output is open", 0, 0); @@ -1902,18 +1910,18 @@ static Obj FuncCALL_WITH_FORMATTING_STATUS(Obj self, Obj status, Obj func, Obj a static Obj FuncIS_INPUT_TTY(Obj self) { - GAP_ASSERT(IO()->Input); - if (IO()->Input->stream) + GAP_ASSERT(IO(Input)); + if (IO(Input)->stream) return False; - return SyBufIsTTY(IO()->Input->file) ? True : False; + return SyBufIsTTY(IO(Input)->file) ? True : False; } static Obj FuncIS_OUTPUT_TTY(Obj self) { - GAP_ASSERT(IO()->Output); - if (IO()->Output->stream) + GAP_ASSERT(IO(Output)); + if (IO(Output)->stream) return False; - return SyBufIsTTY(IO()->Output->file) ? True : False; + return SyBufIsTTY(IO(Output)->file) ? True : False; } static Obj FuncGET_FILENAME_CACHE(Obj self) @@ -1960,14 +1968,14 @@ static Int InitLibrary ( static Int InitKernel ( StructInitInfo * module ) { - IO()->Input = 0; - IO()->Output = 0; - IO()->InputLog = 0; - IO()->OutputLog = 0; - IO()->PrintFormattingForStdout = TRUE; - IO()->PrintFormattingForErrout = TRUE; + IO(Input) = 0; + IO(Output) = 0; + IO(InputLog) = 0; + IO(OutputLog) = 0; + IO(PrintFormattingForStdout) = TRUE; + IO(PrintFormattingForErrout) = TRUE; - OpenOutput(&IO()->DefaultOutput, "*stdout*", FALSE); + OpenOutput(&IO(DefaultOutput), "*stdout*", FALSE); InitSymbolTableKernel(&FilenameSymbolTable, "FilenameSymbolCount", "FilenameSymbolTable", GetCachedFilename, @@ -1982,9 +1990,9 @@ static Int InitKernel ( #else // register global bags with the garbage collector - InitGlobalBag(&(IO()->InputLogFileOrStream.stream), + InitGlobalBag(&(IO(InputLogFileOrStream).stream), "src/io.c:InputLogFileOrStream"); - InitGlobalBag(&(IO()->OutputLogFileOrStream.stream), + InitGlobalBag(&(IO(OutputLogFileOrStream).stream), "src/io.c:OutputLogFileOrStream"); #endif @@ -2014,9 +2022,10 @@ static StructInitInfo module = { .name = "io", .initKernel = InitKernel, .initLibrary = InitLibrary, - +#ifdef HPCGAP .moduleStateSize = sizeof(struct IOModuleState), .moduleStateOffsetPtr = &IOStateOffset, +#endif }; StructInitInfo * InitInfoIO ( void ) diff --git a/src/modules.c b/src/modules.c index 5b7a0f832c..6b1b689c6b 100644 --- a/src/modules.c +++ b/src/modules.c @@ -97,6 +97,8 @@ static Int NrImportedGVars; static StructImportedGVars ImportedFuncs[MAX_IMPORTED_GVARS]; static Int NrImportedFuncs; +#ifdef HPCGAP + static Int StateNextFreeOffset = 0; // Start of next free memory area (as offset into GAPState.StateSlots) static void RegisterModuleState(StructInitInfo * info) @@ -123,6 +125,7 @@ static void RegisterModuleState(StructInitInfo * info) StateNextFreeOffset = (StateNextFreeOffset + sizeof(Obj)-1) & ~(sizeof(Obj)-1); } +#endif /************************************************************************* ** @@ -149,7 +152,9 @@ Int ActivateModule(StructInitInfo * info) { Int res = 0; +#ifdef HPCGAP RegisterModuleState(info); +#endif if (info->initKernel) { res = info->initKernel(info); @@ -941,7 +946,9 @@ void ModulesSetup(void) fputs(")\n", stderr); } +#ifdef HPCGAP RegisterModuleState(info); +#endif } NrBuiltinModules = NrModules; } diff --git a/src/modules.h b/src/modules.h index def31697c2..1c21120aed 100644 --- a/src/modules.h +++ b/src/modules.h @@ -90,12 +90,18 @@ struct init_info { // function to call after restoring workspace Int (*postRestore)(StructInitInfo *); +#ifdef HPCGAP // number of bytes this module needs for its per-thread module state + // Only used in HPC-GAP, but not behind an #ifdef guard to avoid API + // breakage for C++ kernel extensions UInt moduleStateSize; // if this is not zero, then the module state offset is stored into // the address this points at + // Only used in HPC-GAP, but not behind an #ifdef guard to avoid API + // breakage for C++ kernel extensions Int * moduleStateOffsetPtr; +#endif // initialize thread local module state Int (*initModuleState)(void); diff --git a/src/objcftl.c b/src/objcftl.c index 557827816f..472fd33772 100644 --- a/src/objcftl.c +++ b/src/objcftl.c @@ -32,13 +32,16 @@ #include "plist.h" +#ifdef HPCGAP static ModuleStateOffset CFTLStateOffset = -1; struct CFTLModuleState { - Obj WORD_STACK; - Obj WORD_EXPONENT_STACK; - Obj SYLLABLE_STACK; - Obj EXPONENT_STACK; +#endif + DECL_MODULE_STATE Obj WORD_STACK; + DECL_MODULE_STATE Obj WORD_EXPONENT_STACK; + DECL_MODULE_STATE Obj SYLLABLE_STACK; + DECL_MODULE_STATE Obj EXPONENT_STACK; +#ifdef HPCGAP }; extern inline struct CFTLModuleState *CFTLState(void) @@ -46,6 +49,12 @@ extern inline struct CFTLModuleState *CFTLState(void) return (struct CFTLModuleState *)StateSlotsAtOffset(CFTLStateOffset); } +#define WORD_STACK (CFTLState()->WORD_STACK) +#define WORD_EXPONENT_STACK (CFTLState()->WORD_EXPONENT_STACK) +#define SYLLABLE_STACK (CFTLState()->SYLLABLE_STACK) +#define EXPONENT_STACK (CFTLState()->EXPONENT_STACK) +#endif + static inline Obj IncInt(Obj x) { if (IS_INTOBJ(x) && x != INTOBJ_MAX) { @@ -133,10 +142,10 @@ static Obj CollectPolycyc(Obj pcp, Obj list, Obj word) Obj ipow = CONST_ADDR_OBJ(pcp)[ PC_INVERSEPOWERS ]; Obj exp = CONST_ADDR_OBJ(pcp)[ PC_EXPONENTS ]; - Obj wst = CFTLState()->WORD_STACK; - Obj west = CFTLState()->WORD_EXPONENT_STACK; - Obj sst = CFTLState()->SYLLABLE_STACK; - Obj est = CFTLState()->EXPONENT_STACK; + Obj wst = WORD_STACK; + Obj west = WORD_EXPONENT_STACK; + Obj sst = SYLLABLE_STACK; + Obj est = EXPONENT_STACK; Obj conj=0, iconj=0; /*QQ initialize to please compiler */ @@ -411,15 +420,15 @@ static Int InitLibrary ( static Int InitModuleState(void) { - InitGlobalBag( &CFTLState()->WORD_STACK, "WORD_STACK" ); - InitGlobalBag( &CFTLState()->WORD_EXPONENT_STACK, "WORD_EXPONENT_STACK" ); - InitGlobalBag( &CFTLState()->SYLLABLE_STACK, "SYLLABLE_STACK" ); - InitGlobalBag( &CFTLState()->EXPONENT_STACK, "EXPONENT_STACK" ); + InitGlobalBag( &WORD_STACK, "WORD_STACK" ); + InitGlobalBag( &WORD_EXPONENT_STACK, "WORD_EXPONENT_STACK" ); + InitGlobalBag( &SYLLABLE_STACK, "SYLLABLE_STACK" ); + InitGlobalBag( &EXPONENT_STACK, "EXPONENT_STACK" ); - CFTLState()->WORD_STACK = NEW_PLIST( T_PLIST, 4096 ); - CFTLState()->WORD_EXPONENT_STACK = NEW_PLIST( T_PLIST, 4096 ); - CFTLState()->SYLLABLE_STACK = NEW_PLIST( T_PLIST, 4096 ); - CFTLState()->EXPONENT_STACK = NEW_PLIST( T_PLIST, 4096 ); + WORD_STACK = NEW_PLIST( T_PLIST, 4096 ); + WORD_EXPONENT_STACK = NEW_PLIST( T_PLIST, 4096 ); + SYLLABLE_STACK = NEW_PLIST( T_PLIST, 4096 ); + EXPONENT_STACK = NEW_PLIST( T_PLIST, 4096 ); return 0; } @@ -436,8 +445,10 @@ static StructInitInfo module = { .initKernel = InitKernel, .initLibrary = InitLibrary, +#ifdef HPCGAP .moduleStateSize = sizeof(struct CFTLModuleState), .moduleStateOffsetPtr = &CFTLStateOffset, +#endif .initModuleState = InitModuleState, }; diff --git a/src/objects.c b/src/objects.c index d76f74d6bb..8775fc0159 100644 --- a/src/objects.c +++ b/src/objects.c @@ -44,12 +44,14 @@ enum { MAXPRINTDEPTH = 64, }; +#ifdef HPCGAP static ModuleStateOffset ObjectsStateOffset = -1; typedef struct { - UInt PrintObjDepth; - Obj PrintObjThiss[MAXPRINTDEPTH]; - Int PrintObjIndices[MAXPRINTDEPTH]; +#endif + DECL_MODULE_STATE UInt PrintObjDepth; + DECL_MODULE_STATE Obj PrintObjThiss[MAXPRINTDEPTH]; + DECL_MODULE_STATE Int PrintObjIndices[MAXPRINTDEPTH]; // This variable is used to allow a ViewObj method to call PrintObj on the // same object without triggering use of '~'. It contains one of the @@ -57,10 +59,16 @@ typedef struct { // 0: there is no enclosing call to PrintObj or ViewObj still open, or // 1: the innermost such is PrintObj, or // 2: the innermost such is ViewObj. - UInt LastPV; + DECL_MODULE_STATE UInt LastPV; +#ifdef HPCGAP } ObjectsModuleState; +#define PrintObjDepth MODULE_STATE(Objects, PrintObjDepth) +#define PrintObjThiss MODULE_STATE(Objects, PrintObjThiss) +#define PrintObjIndices MODULE_STATE(Objects, PrintObjIndices) +#define LastPV MODULE_STATE(Objects, LastPV) +#endif static Int lastFreePackageTNUM = FIRST_PACKAGE_TNUM; @@ -895,13 +903,13 @@ static Obj FuncGET_TNAM_FROM_TNUM(Obj self, Obj obj) // This function is used to keep track of which objects are already // being printed or viewed to trigger the use of ~ when needed. -static inline BOOL IS_ON_PRINT_STACK(const ObjectsModuleState * os, Obj obj) +static inline BOOL IS_ON_PRINT_STACK(Obj obj) { if (!(FIRST_RECORD_TNUM <= TNUM_OBJ(obj) && TNUM_OBJ(obj) <= LAST_LIST_TNUM)) return FALSE; - for (UInt i = 0; i < os->PrintObjDepth; i++) - if (os->PrintObjThiss[i] == obj) + for (UInt i = 0; i < PrintObjDepth; i++) + if (PrintObjThiss[i] == obj) return TRUE; return FALSE; } @@ -961,46 +969,44 @@ void PrintObj(Obj obj) } #endif - ObjectsModuleState * os = &MODULE_STATE(Objects); - // First check if is actually the current object being viewed, since // ViewObj() may result in a call to PrintObj(); in that case, // we should not put on the print stack - if ((os->PrintObjDepth > 0) && (os->LastPV == 2) && - (obj == os->PrintObjThiss[os->PrintObjDepth - 1])) { - os->LastPV = 1; + if ((PrintObjDepth > 0) && (LastPV == 2) && + (obj == PrintObjThiss[PrintObjDepth - 1])) { + LastPV = 1; PRINT_OBJ(obj); - os->LastPV = 2; + LastPV = 2; } // print the path if is on the stack - else if (IS_ON_PRINT_STACK(os, obj)) { + else if (IS_ON_PRINT_STACK(obj)) { Pr("~", 0, 0); - for (int i = 0; obj != os->PrintObjThiss[i]; i++) { - PRINT_PATH(os->PrintObjThiss[i], os->PrintObjIndices[i]); + for (int i = 0; obj != PrintObjThiss[i]; i++) { + PRINT_PATH(PrintObjThiss[i], PrintObjIndices[i]); } } // dispatch to the appropriate printing function - else if (os->PrintObjDepth < MAXPRINTDEPTH) { + else if (PrintObjDepth < MAXPRINTDEPTH) { - Obj oldThis = os->PrintObjThiss[os->PrintObjDepth]; - Int oldIndx = os->PrintObjIndices[os->PrintObjDepth]; + Obj oldThis = PrintObjThiss[PrintObjDepth]; + Int oldIndx = PrintObjIndices[PrintObjDepth]; // push obj on the stack - os->PrintObjThiss[os->PrintObjDepth] = obj; - os->PrintObjIndices[os->PrintObjDepth] = 0; - os->PrintObjDepth++; + PrintObjThiss[PrintObjDepth] = obj; + PrintObjIndices[PrintObjDepth] = 0; + PrintObjDepth++; - UInt lastPV = os->LastPV; - os->LastPV = 1; + UInt lastPV = LastPV; + LastPV = 1; PRINT_OBJ(obj); - os->LastPV = lastPV; + LastPV = lastPV; // pop from the stack - os->PrintObjDepth--; - os->PrintObjThiss[os->PrintObjDepth] = oldThis; - os->PrintObjIndices[os->PrintObjDepth] = oldIndx; + PrintObjDepth--; + PrintObjThiss[PrintObjDepth] = oldThis; + PrintObjIndices[PrintObjDepth] = oldIndx; } else { Pr("\nprinting stopped, too many recursion levels!\n", 0, 0); @@ -1044,19 +1050,19 @@ static Obj FuncPRINT_OBJ(Obj self, Obj obj) UInt SetPrintObjState(UInt state) { - UInt oldDepth = MODULE_STATE(Objects).PrintObjDepth; - UInt oldLastPV = MODULE_STATE(Objects).LastPV; - MODULE_STATE(Objects).PrintObjDepth = state >> 2; - MODULE_STATE(Objects).LastPV = state & 3; + UInt oldDepth = PrintObjDepth; + UInt oldLastPV = LastPV; + PrintObjDepth = state >> 2; + LastPV = state & 3; return (oldDepth << 2) | oldLastPV; } void SetPrintObjIndex(Int index) { - UInt depth = MODULE_STATE(Objects).PrintObjDepth; + UInt depth = PrintObjDepth; if (depth == 0) ErrorQuit("SetPrintObjIndex: bad state, PrintObjDepth is 0", 0, 0); - MODULE_STATE(Objects).PrintObjIndices[depth - 1] = index; + PrintObjIndices[depth - 1] = index; } static Obj FuncSET_PRINT_OBJ_INDEX(Obj self, Obj index) @@ -1087,36 +1093,34 @@ void ViewObj(Obj obj) } #endif - ObjectsModuleState * os = &MODULE_STATE(Objects); - // print the path if is on the stack - if (IS_ON_PRINT_STACK(os, obj)) { + if (IS_ON_PRINT_STACK(obj)) { Pr("~", 0, 0); - for (int i = 0; obj != os->PrintObjThiss[i]; i++) { - PRINT_PATH(os->PrintObjThiss[i], os->PrintObjIndices[i]); + for (int i = 0; obj != PrintObjThiss[i]; i++) { + PRINT_PATH(PrintObjThiss[i], PrintObjIndices[i]); } } // dispatch to the appropriate viewing function - else if (os->PrintObjDepth < MAXPRINTDEPTH) { + else if (PrintObjDepth < MAXPRINTDEPTH) { - Obj oldThis = os->PrintObjThiss[os->PrintObjDepth]; - Int oldIndx = os->PrintObjIndices[os->PrintObjDepth]; + Obj oldThis = PrintObjThiss[PrintObjDepth]; + Int oldIndx = PrintObjIndices[PrintObjDepth]; // push obj on the stack - os->PrintObjThiss[os->PrintObjDepth] = obj; - os->PrintObjIndices[os->PrintObjDepth] = 0; - os->PrintObjDepth++; + PrintObjThiss[PrintObjDepth] = obj; + PrintObjIndices[PrintObjDepth] = 0; + PrintObjDepth++; - UInt lastPV = os->LastPV; - os->LastPV = 2; + UInt lastPV = LastPV; + LastPV = 2; DoOperation1Args(ViewObjOper, obj); - os->LastPV = lastPV; + LastPV = lastPV; // pop from the stack - os->PrintObjDepth--; - os->PrintObjThiss[os->PrintObjDepth] = oldThis; - os->PrintObjIndices[os->PrintObjDepth] = oldIndx; + PrintObjDepth--; + PrintObjThiss[PrintObjDepth] = oldThis; + PrintObjIndices[PrintObjDepth] = oldIndx; } else { Pr("\nviewing stopped, too many recursion levels!\n", 0, 0); @@ -2341,8 +2345,10 @@ static StructInitInfo module = { .initKernel = InitKernel, .initLibrary = InitLibrary, +#ifdef HPCGAP .moduleStateSize = sizeof(ObjectsModuleState), .moduleStateOffsetPtr = &ObjectsStateOffset, +#endif }; StructInitInfo * InitInfoObjects ( void ) diff --git a/src/objfgelm.cc b/src/objfgelm.cc index 48d21c52b8..633b5f970f 100644 --- a/src/objfgelm.cc +++ b/src/objfgelm.cc @@ -1596,8 +1596,10 @@ static StructInitInfo module = { /* preSave = */ 0, /* postSave = */ 0, /* postRestore = */ 0, +#ifdef HPCGAP /* moduleStateSize = */ 0, /* moduleStateOffsetPtr = */ 0, +#endif /* initModuleState = */ 0, /* destroyModuleState = */ 0, }; diff --git a/src/objpcgel.cc b/src/objpcgel.cc index ec5b0b05f8..358e59330a 100644 --- a/src/objpcgel.cc +++ b/src/objpcgel.cc @@ -381,8 +381,10 @@ static StructInitInfo module = { /* preSave = */ 0, /* postSave = */ 0, /* postRestore = */ 0, +#ifdef HPCGAP /* moduleStateSize = */ 0, /* moduleStateOffsetPtr = */ 0, +#endif /* initModuleState = */ 0, /* destroyModuleState = */ 0, }; diff --git a/src/opers.cc b/src/opers.cc index 546e08d928..ce86f7a99d 100644 --- a/src/opers.cc +++ b/src/opers.cc @@ -3903,8 +3903,10 @@ static StructInitInfo module = { /* preSave = */ 0, /* postSave = */ 0, /* postRestore = */ PostRestore, +#ifdef HPCGAP /* moduleStateSize = */ 0, /* moduleStateOffsetPtr = */ 0, +#endif /* initModuleState = */ InitModuleState, /* destroyModuleState = */ 0, }; diff --git a/src/permutat.cc b/src/permutat.cc index 50a030366d..ccd5cfe976 100644 --- a/src/permutat.cc +++ b/src/permutat.cc @@ -84,9 +84,11 @@ Obj IdentityPerm; static const UInt MAX_DEG_PERM4 = ((Int)1 << (sizeof(UInt) == 8 ? 32 : 28)) - 1; +#ifdef HPCGAP static ModuleStateOffset PermutatStateOffset = -1; typedef struct { +#endif /**************************************************************************** ** @@ -102,11 +104,13 @@ typedef struct { ** costs (particularly when starting new threads). ** Use the UseTmpPerm() utility function to ensure it is constructed! */ -Obj TmpPerm; +DECL_MODULE_STATE Obj TmpPerm; +#ifdef HPCGAP } PermutatModuleState; -#define TmpPerm MODULE_STATE(Permutat).TmpPerm +#define TmpPerm MODULE_STATE(Permutat, TmpPerm) +#endif static UInt1 * UseTmpPerm(UInt size) @@ -3039,8 +3043,10 @@ static StructInitInfo module = { /* preSave = */ 0, /* postSave = */ 0, /* postRestore = */ PostRestore, +#ifdef HPCGAP /* moduleStateSize = */ sizeof(PermutatModuleState), /* moduleStateOffsetPtr = */ &PermutatStateOffset, +#endif /* initModuleState = */ InitModuleState, /* destroyModuleState = */ 0, }; diff --git a/src/pperm.cc b/src/pperm.cc index 921c204d9e..af1fdcb270 100644 --- a/src/pperm.cc +++ b/src/pperm.cc @@ -120,9 +120,11 @@ static Obj EmptyPartialPerm; "must be a partial permutation") +#ifdef HPCGAP static ModuleStateOffset PPermStateOffset = -1; typedef struct { +#endif /************************************************************************** * @@ -136,12 +138,13 @@ typedef struct { * The buffer is *not* guaranteed to have any particular value, routines * that require a zero-initialization need to do this at the start. */ - Obj TmpPPerm; + DECL_MODULE_STATE Obj TmpPPerm; +#ifdef HPCGAP } PPermModuleState; - -#define TmpPPerm MODULE_STATE(PPerm).TmpPPerm +#define TmpPPerm MODULE_STATE(PPerm, TmpPPerm) +#endif static inline void ResizeTmpPPerm(UInt len) { @@ -3995,8 +3998,10 @@ static StructInitInfo module = { /* preSave = */ 0, /* postSave = */ 0, /* postRestore = */ 0, +#ifdef HPCGAP /* moduleStateSize = */ sizeof(PPermModuleState), /* moduleStateOffsetPtr = */ &PPermStateOffset, +#endif /* initModuleState = */ InitModuleState, /* destroyModuleState = */ 0, }; diff --git a/src/trans.cc b/src/trans.cc index 2558a37693..f50a2cfb53 100644 --- a/src/trans.cc +++ b/src/trans.cc @@ -175,21 +175,22 @@ static Int GetPositiveListEntryEx(const char * funcname, GetPositiveListEntryEx(funcname, list, idx, NICE_ARGNAME(list)) +#ifdef HPCGAP static ModuleStateOffset TransStateOffset = -1; typedef struct { +#endif // TmpTrans is essentially the same as TmpPerm - Obj TmpTrans; + DECL_MODULE_STATE Obj TmpTrans; +#ifdef HPCGAP } TransModuleState; -static inline Obj GetTmpTrans(void) -{ - return MODULE_STATE(Trans).TmpTrans; -} +#define TmpTrans MODULE_STATE(Trans, TmpTrans) +#endif static inline UInt4 * AddrTmpTrans(void) { - return ADDR_TRANS4(GetTmpTrans()); + return ADDR_TRANS4(TmpTrans); } @@ -255,9 +256,9 @@ static inline void SET_EXT_TRANS(Obj f, Obj deg) static inline void ResizeTmpTrans(UInt len) { - Obj tmpTrans = GetTmpTrans(); + Obj tmpTrans = TmpTrans; if (tmpTrans == (Obj)0) { - MODULE_STATE(Trans).TmpTrans = NewBag(T_TRANS4, len * sizeof(UInt4) + 3 * sizeof(Obj)); + TmpTrans = NewBag(T_TRANS4, len * sizeof(UInt4) + 3 * sizeof(Obj)); } else if (SIZE_OBJ(tmpTrans) < len * sizeof(UInt4) + 3 * sizeof(Obj)) { ResizeBag(tmpTrans, len * sizeof(UInt4) + 3 * sizeof(Obj)); @@ -4211,7 +4212,7 @@ static Int InitKernel(StructInitInfo * module) InitHdlrFuncsFromTable(GVarFuncs); // register global bags with the garbage collector - InitGlobalBag(&MODULE_STATE(Trans).TmpTrans, "src/trans.c:TmpTrans"); + InitGlobalBag(&TmpTrans, "src/trans.c:TmpTrans"); InitGlobalBag(&IdentityTrans, "src/trans.c:IdentityTrans"); #ifdef GAP_ENABLE_SAVELOAD @@ -4295,7 +4296,7 @@ static Int InitLibrary(StructInitInfo * module) static Int InitModuleState(void) { - MODULE_STATE(Trans).TmpTrans = 0; + TmpTrans = 0; return 0; } @@ -4317,8 +4318,10 @@ static StructInitInfo module = { /* preSave = */ 0, /* postSave = */ 0, /* postRestore = */ 0, +#ifdef HPCGAP /* moduleStateSize = */ sizeof(TransModuleState), /* moduleStateOffsetPtr = */ &TransStateOffset, +#endif /* initModuleState = */ InitModuleState, /* destroyModuleState = */ 0, }; From e02e21de29dafa3510f0658c719f68a86e730d8f Mon Sep 17 00:00:00 2001 From: Max Horn Date: Mon, 11 May 2026 12:13:24 +0200 Subject: [PATCH 214/234] Ensure more tests pass with `gap --bare` (#6387) - remove a bunch of SmallGroup and IdGroup uses in tst files - remove tst/testbugfix/2005-05-03-t00070.tst (an equivalent test was added to the smallgrp package recently) - modify some .tst file to run parts only if certain packages are available, via `#@if IsPackageMarkedForLoading(...)` - don't load `ctbllib` (and all its dependencies) in `ctblmaps.tst` --- tst/testbugfix/00008.tst | 2 +- tst/testbugfix/2005-05-03-t00070.tst | 5 -- tst/testinstall/ctbl.tst | 6 +- tst/testinstall/ctblmaps.tst | 3 +- tst/testinstall/ctblmono.tst | 33 +++++++++++ tst/testinstall/ctblsolv.tst | 9 +-- tst/testinstall/grp/basic.tst | 10 ++-- tst/testinstall/grpfp.tst | 4 ++ tst/testinstall/grpmat.tst | 2 + tst/testinstall/grppc.tst | 4 +- tst/testinstall/interpreter.tst | 2 + tst/testinstall/mapphomo.tst | 2 +- tst/testinstall/matblock.tst | 2 +- tst/testinstall/meatauto.tst | 4 +- tst/testinstall/meataxe.tst | 10 ++-- tst/testinstall/opers/FittingSubgroup.tst | 3 +- tst/testinstall/opers/FrattiniSubgroup.tst | 9 +-- tst/testinstall/opers/HallSubgroup.tst | 9 ++- tst/testinstall/opers/IsSolvableGroup.tst | 2 + .../opers/LatticeByCyclicExtension.tst | 9 ++- .../opers/MinimalNormalSubgroups.tst | 57 ++++++++++++------- tst/testinstall/opers/NormalHallSubgroups.tst | 8 +++ tst/testinstall/opers/SimpleGroup.tst | 12 ++++ tst/testinstall/opers/Socle.tst | 51 +++++++++-------- .../opers/StructureDescription.tst | 21 +++++++ tst/testinstall/opers/SubdirectProducts.tst | 47 +++++++++------ 26 files changed, 225 insertions(+), 101 deletions(-) delete mode 100644 tst/testbugfix/2005-05-03-t00070.tst diff --git a/tst/testbugfix/00008.tst b/tst/testbugfix/00008.tst index 0488c51eca..b9860dcf8d 100644 --- a/tst/testbugfix/00008.tst +++ b/tst/testbugfix/00008.tst @@ -5,7 +5,7 @@ gap> EulerianFunction( CyclicGroup(6), 1 ); 2 gap> EulerianFunction( CyclicGroup(5), 1 ); 4 -gap> g:=SmallGroup(1,1);; +gap> g:=TrivialGroup(IsPcGroup);; gap> ConjugacyClassesSubgroups(g);; gap> g:=Group([ (3,5), (1,3,5) ]);; gap> MaximalSubgroups(g);; diff --git a/tst/testbugfix/2005-05-03-t00070.tst b/tst/testbugfix/2005-05-03-t00070.tst deleted file mode 100644 index 618574eb11..0000000000 --- a/tst/testbugfix/2005-05-03-t00070.tst +++ /dev/null @@ -1,5 +0,0 @@ -# 2005/05/03 (BE) -gap> NumberSmallGroups(5^6); -684 -gap> NumberSmallGroups(5*7*9*11*13); -22 diff --git a/tst/testinstall/ctbl.tst b/tst/testinstall/ctbl.tst index f8d23bbc13..3f5ec76722 100644 --- a/tst/testinstall/ctbl.tst +++ b/tst/testinstall/ctbl.tst @@ -443,19 +443,19 @@ gap> HasIsIrreducibleCharacter( TrivialCharacter( SymmetricGroup( 4 ) ) ); true # concurring 'Irr' methods -gap> G:= PcGroupCode( 221729, 24 );; +gap> G:= PcGroupCode( 221729, 24 );; # = SmallGroup( 24, 5 ) gap> IsSupersolvable( G ); true gap> Irr( G );; gap> InfoText( OrdinaryCharacterTable( G ) ); "origin: Baum-Clausen Algorithm" -gap> G:= PcGroupCode( 221729, 24 );; +gap> G:= PcGroupCode( 221729, 24 );; # = SmallGroup( 24, 5 ) gap> IsSupersolvable( G ); true gap> IrrConlon( G );; Irr( G );; gap> InfoText( OrdinaryCharacterTable( G ) ); "origin: Conlon's Algorithm" -gap> G:= PcGroupCode( 221729, 24 );; +gap> G:= PcGroupCode( 221729, 24 );; # = SmallGroup( 24, 5 ) gap> IrrDixonSchneider( G );; Irr( G );; gap> InfoText( OrdinaryCharacterTable( G ) ); "origin: Dixon's Algorithm" diff --git a/tst/testinstall/ctblmaps.tst b/tst/testinstall/ctblmaps.tst index a40f5bb942..3d36393af9 100644 --- a/tst/testinstall/ctblmaps.tst +++ b/tst/testinstall/ctblmaps.tst @@ -3,8 +3,7 @@ gap> START_TEST( "ctblmaps.tst" ); # `ConsiderStructureConstants` can unexpectedly exclude all candidates. # (Benjamin Sambale found examples for that.) -gap> if TestPackageAvailability("ctbllib") <> fail and -> LoadPackage("ctbllib", false) <> fail then +gap> if IsPackageMarkedForLoading( "ctbllib", "" ) then > s:= CharacterTable( "2.A6" );; > t:= CharacterTable( "Co3" );; > maps:= [ [ 1, 2, 8, 4, 11, 4, 13, 18, 18, 9, 22, 9, 22 ], diff --git a/tst/testinstall/ctblmono.tst b/tst/testinstall/ctblmono.tst index 0b57b930b0..bb9c88e01e 100644 --- a/tst/testinstall/ctblmono.tst +++ b/tst/testinstall/ctblmono.tst @@ -96,6 +96,8 @@ gap> TestMonomial( irr[2] ); rec( comment := "whole group is monomial", isMonomial := true ) gap> IsMonomial( irr[2] ); true + +# gap> irr:= Irr( SL(2,3) );; gap> chi:= First( irr, x -> x[1] = 3 );; gap> TestMonomialQuick( chi ); @@ -104,6 +106,8 @@ gap> TestMonomial( chi ); rec( comment := "codegree is prime power", isMonomial := true ) gap> IsMonomial( chi ); true + +#@if IsPackageMarkedForLoading( "smallgrp", "" ) gap> irr:= Irr( SmallGroup( 120, 15 ) );; gap> chi:= First( irr, x -> x[1] = 3 and > Length( ClassPositionsOfKernel( x ) ) = 2 );; @@ -121,6 +125,9 @@ gap> TestMonomial( chi ); rec( comment := "induced from monomial Hall subgroup", isMonomial := true ) gap> IsMonomial( chi ); true +#@fi + +# gap> g:= DirectProduct( AlternatingGroup(5), SymmetricGroup(3), > SymmetricGroup(3) );; gap> chi:= First( Irr( g ), x -> x[1] = 2 and @@ -131,6 +138,8 @@ gap> TestMonomial( chi ); rec( comment := "kernel factor group is supersolvable", isMonomial := true ) gap> IsMonomial( chi ); true + +#@if IsPackageMarkedForLoading( "smallgrp", "" ) gap> irr:= Irr( SmallGroup( 144, 31 ) );; gap> chi:= First( irr, x -> x[1] = 6 );; gap> TestMonomialQuick( chi ); @@ -139,6 +148,9 @@ gap> TestMonomial( chi ); rec( comment := "kernel factor group is monomial", isMonomial := true ) gap> IsMonomial( chi ); true +#@fi + +# gap> irr:= Irr( SL(2,3) );; gap> chi:= First( irr, x -> x[1] = 2 );; gap> TestMonomialQuick( chi ); @@ -147,6 +159,8 @@ gap> TestMonomial( chi ); rec( comment := "quasiprimitive character", isMonomial := false ) gap> IsMonomial( chi ); false + +# gap> irr:= Irr( AlternatingGroup( 5 ) );; gap> chi:= First( irr, x -> x[1] = 5 );; gap> TestMonomialQuick( chi ); @@ -166,6 +180,8 @@ gap> TestMonomial( chi, true ).comment; "lattice checked" gap> IsMonomial( chi ); false + +#@if IsPackageMarkedForLoading( "smallgrp", "" ) gap> irr:= Irr( SmallGroup( 96, 204 ) );; gap> chi:= First( irr, x -> x[1] = 4 );; gap> TestMonomialQuick( chi ); @@ -174,6 +190,9 @@ gap> TestMonomial( chi ).comment; "induced from 'character'" gap> IsMonomial( chi ); true +#@fi + +#@if IsPackageMarkedForLoading( "smallgrp", "" ) gap> chi:= First( Irr( SmallGroup( 144, 31 ) ), x -> x[1] = 4 );; gap> TestMonomialQuick( chi ); rec( comment := "no decision by cheap tests", isMonomial := "?" ) @@ -183,6 +202,9 @@ gap> TestMonomial( chi, true ).comment; "induced from 'character'" gap> IsMonomial( chi ); true +#@fi + +# gap> chi:= 0 * [ 1 .. NrConjugacyClasses( S4 ) ];; gap> chi[1]:= Size( S4 );; gap> chi:= ClassFunction( S4, chi );; @@ -193,6 +215,8 @@ gap> TestMonomial( chi, true ).comment; gap> IsMonomial( chi ); true gap> TestMonomialUseLattice:= TestMonomialUseLattice_Orig;; + +#@if IsPackageMarkedForLoading( "smallgrp", "" ) gap> chi:= First( Irr( SmallGroup( 48, 28 ) ), x -> x[1] = 4 );; gap> TestMonomialQuick( chi ); rec( comment := "no decision by cheap tests", isMonomial := "?" ) @@ -200,6 +224,7 @@ gap> TestMonomial( chi ).comment; "induced from 'character'" gap> IsMonomial( chi ); true +#@fi ## gap> TestMonomialQuick( S4 ); @@ -214,6 +239,8 @@ gap> TestMonomial( Sl23 ); rec( comment := "list Delta( G ) contains entry > 1", isMonomial := false ) gap> IsMonomial( Sl23 ); false + +#@if IsPackageMarkedForLoading( "smallgrp", "" ) gap> g:= SmallGroup( 96, 204 );; gap> TestMonomialQuick( g ); rec( comment := "no decision by cheap tests", isMonomial := "?" ) @@ -239,6 +266,9 @@ gap> TestMonomial( g ); rec( comment := "was already stored", isMonomial := true ) gap> IsMonomial( g ); true +#@fi + +# gap> g:= AlternatingGroup( 5 );; gap> TestMonomialQuick( g ); rec( comment := "non-solvable group", isMonomial := false ) @@ -246,6 +276,8 @@ gap> TestMonomial( g ); rec( comment := "non-solvable group", isMonomial := false ) gap> IsMonomial( g ); false + +#@if IsPackageMarkedForLoading( "smallgrp", "" ) gap> g:= SmallGroup( 56, 10 );; gap> TestMonomialQuick( g ); rec( comment := "group order is monomial", isMonomial := true ) @@ -274,6 +306,7 @@ gap> TestMonomial( g ); rec( comment := "Sylow abelian by supersolvable group", isMonomial := true ) gap> IsMonomial( g ); true +#@fi ## gap> TestSubnormallyMonomial( S4 ); diff --git a/tst/testinstall/ctblsolv.tst b/tst/testinstall/ctblsolv.tst index 231e87319f..28a6955f0c 100644 --- a/tst/testinstall/ctblsolv.tst +++ b/tst/testinstall/ctblsolv.tst @@ -1,7 +1,7 @@ #@local G, pair, mth, all, rks, tbl gap> START_TEST("ctblsolv.tst"); -## +#@if IsPackageMarkedForLoading( "smallgrp", "" ) gap> CharacterDegrees( SmallGroup( 256, 529 ) ); [ [ 1, 8 ], [ 2, 30 ], [ 4, 8 ] ] gap> for pair in [ [ 18, 3 ], [ 27, 3 ], [ 36, 7 ], [ 50, 3 ], [ 54, 4 ] ] do @@ -11,6 +11,7 @@ gap> for pair in [ [ 18, 3 ], [ 27, 3 ], [ 36, 7 ], [ 50, 3 ], [ 54, 4 ] ] do > Error( IdGroup( G ) ); > fi; > od; +#@fi ## gap> mth:= [];; @@ -18,11 +19,11 @@ gap> G:= AbelianGroup( [ 2, 3, 5 ] );; gap> Add( mth, ApplicableMethod( CharacterDegrees, [ G ] ) ); gap> CharacterDegrees( G ) = [ [ 1, 30 ] ]; true -gap> G:= SmallGroup( 24, 12 );; Irr( G );; +gap> G:= SymmetricGroup(IsPcGroup, 4);; Irr( G );; gap> Add( mth, ApplicableMethod( CharacterDegrees, [ G ] ) ); gap> CharacterDegrees( G ) = [ [ 1, 2 ], [ 2, 1 ], [ 3, 2 ] ]; true -gap> G:= SmallGroup( 24, 12 );; CharacterTable( G );; +gap> G:= SymmetricGroup(IsPcGroup, 4);; CharacterTable( G );; gap> Add( mth, ApplicableMethod( CharacterDegrees, [ G ] ) ); gap> CharacterDegrees( G ) = [ [ 1, 2 ], [ 2, 1 ], [ 3, 2 ] ]; true @@ -34,7 +35,7 @@ gap> G:= Group( [ [ E(3) ] ], [ [ E(4) ] ] );; gap> Add( mth, ApplicableMethod( CharacterDegrees, [ G ] ) ); gap> CharacterDegrees( G ) = [ [ 1, 12 ] ]; true -gap> G:= SmallGroup( 24, 12 );; # hier: auch überaufl.!!! +gap> G:= SymmetricGroup(IsPcGroup, 4);; # hier: auch überaufl.!!! gap> Add( mth, ApplicableMethod( CharacterDegrees, [ G ] ) ); gap> CharacterDegrees( G ) = [ [ 1, 2 ], [ 2, 1 ], [ 3, 2 ] ]; true diff --git a/tst/testinstall/grp/basic.tst b/tst/testinstall/grp/basic.tst index b557cab1be..90254cc625 100644 --- a/tst/testinstall/grp/basic.tst +++ b/tst/testinstall/grp/basic.tst @@ -271,10 +271,10 @@ true # # dicyclic groups # -gap> IdGroup(DicyclicGroup(4)); -[ 4, 1 ] -gap> IdGroup(DicyclicGroup(IsFpGroup,4)); -[ 4, 1 ] +gap> StructureDescription(DicyclicGroup(4)); +"C4" +gap> StructureDescription(DicyclicGroup(IsFpGroup,4)); +"C4" gap> DicyclicGroup(8); gap> DicyclicGroup(IsPcGroup,8); @@ -340,10 +340,12 @@ gap> for n in [ 4, 12, 20, 24 ] do > Error( "gen. quat. group?" ); > fi; > od; +#@if IsPackageMarkedForLoading( "smallgrp", "" ) gap> Number( AllSmallGroups( [ 1 .. 32 ], IsDicyclicGroup ) ); 8 gap> Number( AllSmallGroups( [ 1 .. 32 ], IsGeneralisedQuaternionGroup ) ); 3 +#@fi # gap> Q:= DicyclicGroup( 20 );; diff --git a/tst/testinstall/grpfp.tst b/tst/testinstall/grpfp.tst index 247402f216..0403a75baf 100644 --- a/tst/testinstall/grpfp.tst +++ b/tst/testinstall/grpfp.tst @@ -162,6 +162,7 @@ false Error, the f.p. group is not finite # RWS for G2(3) and S_6(2) +#@if IsPackageMarkedForLoading( "primgrp", "" ) gap> g:=SimpleGroup("G2(3)");; gap> hom:=IsomorphismFpGroupForRewriting(g);; gap> m:=Image(IsomorphismFpMonoid(Image(hom)));; @@ -169,6 +170,9 @@ gap> F:=m!.rewritingSystem;;; gap> ReducedForm(F,UnderlyingElement( > Product(GeneratorsOfMonoid(m){[1,3..19]}))); w1*B5*b6*b7*B8*w2*b1*B3*B4*b5*b6*b7 +#@fi + +# gap> g:=SimpleGroup("S6(2)");; gap> hom:=IsomorphismFpGroupForRewriting(g);; gap> m:=Image(IsomorphismFpMonoid(Image(hom)));; diff --git a/tst/testinstall/grpmat.tst b/tst/testinstall/grpmat.tst index 4c23741723..eea0eb9834 100644 --- a/tst/testinstall/grpmat.tst +++ b/tst/testinstall/grpmat.tst @@ -86,8 +86,10 @@ gap> TrivialSubgroup( GL(2, 2) ); # The following should take less than a second. +#@if IsPackageMarkedForLoading( "primgrp", "" ) gap> Length( LowIndexSubgroups( GL(2,5), 50 ) ) = 31; true +#@fi # 'NiceMonomorphism' behaves well w.r.t. 'ConstructingFilter' gap> G:= SP( 4, 2 );; diff --git a/tst/testinstall/grppc.tst b/tst/testinstall/grppc.tst index b55eac934e..cd2af99324 100644 --- a/tst/testinstall/grppc.tst +++ b/tst/testinstall/grppc.tst @@ -137,7 +137,7 @@ gap> List( sys, Size ); [ 4, 7 ] gap> List(sys,i->Length(AsList(i))); [ 4, 7 ] -gap> G := SmallGroup( 144, 183 );; +gap> G := DirectProduct(SymmetricGroup(IsPcGroup, 3), SymmetricGroup(IsPcGroup, 4));; gap> F := FittingSubgroup( G );; gap> S := SylowSubgroup( F, 2 );; gap> Display(Image(IsomorphismPcGroup(S))); @@ -166,7 +166,7 @@ gap> RepresentativeAction(G,x,x^2)<>fail; true gap> RepresentativeAction(G,x,x^2); f1*f2 -gap> g := SmallGroup(243,27);; +gap> g := PcGroupCode(14055476799225975, 243);; # = SmallGroup(243,27) gap> AsSet(Omega(g,3,1)) = Set(Filtered(g, g -> IsOne(g^3))); true gap> AsSet(Omega(g,3,2)) = Set(Filtered(g, g -> IsOne(g^9))); diff --git a/tst/testinstall/interpreter.tst b/tst/testinstall/interpreter.tst index 5c758de733..e13308ab72 100644 --- a/tst/testinstall/interpreter.tst +++ b/tst/testinstall/interpreter.tst @@ -39,8 +39,10 @@ gap> QUIT; # # help system # +#@if IsPackageMarkedForLoading( "gapdoc", "" ) gap> ?qwert_asdf Help: no matching entry found +#@fi # # function call with options diff --git a/tst/testinstall/mapphomo.tst b/tst/testinstall/mapphomo.tst index 377a1209ad..ca1388b52d 100644 --- a/tst/testinstall/mapphomo.tst +++ b/tst/testinstall/mapphomo.tst @@ -86,7 +86,7 @@ gap> One( hom ); fail # Check that group homomorphisms created by a function can compute preimages. -gap> for G in [ SymmetricGroup(5), SmallGroup( 24, 12 ), GL(2,3) ] do +gap> for G in [ SymmetricGroup(5), DihedralGroup(8), GL(2,3) ] do > hom:= GroupHomomorphismByFunction( G, G, x -> x ); > PreImagesRepresentativeNC( hom, G.1 ); > od; diff --git a/tst/testinstall/matblock.tst b/tst/testinstall/matblock.tst index f646628043..4043a465e8 100644 --- a/tst/testinstall/matblock.tst +++ b/tst/testinstall/matblock.tst @@ -138,7 +138,7 @@ gap> MinimalPolynomial( R, m2 ) = MinimalPolynomial( R, MatrixByBlockMatrix( m2 true # Groups that consist of block matrices -gap> G:= SmallGroup( 24, 12 );; +gap> G:= SymmetricGroup(IsPcGroup, 4);; gap> H:= SylowSubgroup( G, 2 );; gap> reps:= IrreducibleRepresentations( H );; gap> ind:= InducedRepresentation( reps[5], G );; diff --git a/tst/testinstall/meatauto.tst b/tst/testinstall/meatauto.tst index 5f7d064756..a51d6ec0f6 100644 --- a/tst/testinstall/meatauto.tst +++ b/tst/testinstall/meatauto.tst @@ -12,7 +12,7 @@ gap> SMTX_NullspaceEqns(e); # # MTX.BasisModuleEndomorphisms # -gap> G:=SmallGroup(24, 3);; +gap> G:=SL(2, 3);; gap> p:=NextPrimeInt(100);; gap> M:=RegularModule(G, GF(p))[2];; gap> MTX.BasisModuleEndomorphisms(M); @@ -44,7 +44,7 @@ gap> MTX.BasisModuleEndomorphisms(M); # # MTX.HomogeneousComponents # -gap> G:=SmallGroup(24, 3);; +gap> G:=SL(2, 3);; gap> p:=NextPrimeInt(100);; gap> M:=RegularModule(G, GF(p))[2];; gap> hc := MTX.HomogeneousComponents(M);; diff --git a/tst/testinstall/meataxe.tst b/tst/testinstall/meataxe.tst index 55dc6c66b2..7e076f17d9 100644 --- a/tst/testinstall/meataxe.tst +++ b/tst/testinstall/meataxe.tst @@ -77,8 +77,10 @@ gap> M2:=TensorProductGModule(M,M); rec( IsOverFiniteField := true, dimension := 9, field := GF(2), generators := [ , ], isMTXModule := true ) -gap> IdGroup(MTX.ModuleAutomorphisms(M2)); -[ 1344, 11301 ] +gap> G:=MTX.ModuleAutomorphisms(M2); + +gap> StructureDescription(G); +"PSL(3,2) x D8" gap> cf:=MTX.CompositionFactors(M2);; gap> ForAll(cf, MTX.IsAbsolutelyIrreducible); true @@ -138,8 +140,8 @@ false # gap> M2:=First(MTX.CompositionFactors(M), m -> m.dimension = 4);; -gap> IdGroup(MTX.ModuleAutomorphisms(M2)); -[ 48, 2 ] +gap> StructureDescription(MTX.ModuleAutomorphisms(M2)); +"C48" gap> MTX.IsIndecomposable(M2); true gap> MTX.IsAbsolutelyIrreducible(M2); diff --git a/tst/testinstall/opers/FittingSubgroup.tst b/tst/testinstall/opers/FittingSubgroup.tst index 172a085e1f..022d10290c 100644 --- a/tst/testinstall/opers/FittingSubgroup.tst +++ b/tst/testinstall/opers/FittingSubgroup.tst @@ -15,11 +15,12 @@ gap> G := CyclicGroup(IsPcGroup, 12);; gap> IsIdenticalObj(G, FittingSubgroup(G)); true -# +#@if IsPackageMarkedForLoading( "smallgrp", "" ) gap> List(AllSmallGroups(60), g -> Size(FittingSubgroup(g))); [ 30, 30, 30, 60, 1, 15, 15, 15, 20, 30, 30, 30, 60 ] gap> ForAll(AllSmallGroups(60), g -> IsNormal(g, FittingSubgroup(g))); true +#@fi # gap> g := SL(2,5);; diff --git a/tst/testinstall/opers/FrattiniSubgroup.tst b/tst/testinstall/opers/FrattiniSubgroup.tst index 2646c8764c..5064529c1b 100644 --- a/tst/testinstall/opers/FrattiniSubgroup.tst +++ b/tst/testinstall/opers/FrattiniSubgroup.tst @@ -16,12 +16,12 @@ gap> HasIsAbelian(FrattiniSubgroup(G)); true gap> GeneratorsOfGroup(FrattiniSubgroup(G)); [ (x^-195*y^196)^6, (x^-1*y)^630, (x^-1*y)^840 ] -gap> G := DirectProduct(DihedralGroup(IsPcGroup,8), SmallGroup(27,4));; +gap> G := DirectProduct(DihedralGroup(8), ExtraspecialGroup(27,9));; gap> IsNilpotentGroup(G); true gap> F := FrattiniSubgroup(G);; -gap> IdGroup(F); -[ 6, 2 ] +gap> StructureDescription(F); +"C6" gap> HasIsNilpotentGroup(F); true @@ -43,11 +43,12 @@ Group([ ]) gap> AsSet( FrattiniSubgroup(CyclicGroup(IsPcGroup, 9)) ); [ of ..., f2, f2^2 ] -# +#@if IsPackageMarkedForLoading( "smallgrp", "" ) gap> List(AllSmallGroups(60), g -> Size(FrattiniSubgroup(g))); [ 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1 ] gap> ForAll(AllSmallGroups(60), g -> IsNormal(g, FrattiniSubgroup(g))); true +#@fi # gap> g := SL(2,5);; diff --git a/tst/testinstall/opers/HallSubgroup.tst b/tst/testinstall/opers/HallSubgroup.tst index bf05ddecc7..7435808bbf 100644 --- a/tst/testinstall/opers/HallSubgroup.tst +++ b/tst/testinstall/opers/HallSubgroup.tst @@ -2,20 +2,25 @@ gap> START_TEST("HallSubgroup.tst"); gap> G := GL(3,4);; gap> HallSubgroup(G, [2,3]); fail + +#@if IsPackageMarkedForLoading( "smallgrp", "" ) gap> G := PSL(4,2);; gap> IdGroup(HallSubgroup(G, [2,3])); [ 576, 8654 ] gap> G := PSp(4,5);; gap> IdGroup(HallSubgroup(G,[2,3])); [ 576, 8277 ] +#@fi + +# gap> G := Group([ [ [ Z(2)^0, 0*Z(2), 0*Z(2) ], > [ 0*Z(2), Z(2)^0, 0*Z(2) ], > [ 0*Z(2), Z(2)^0, Z(2)^0 ] ], > [ [ 0*Z(2), Z(2)^0, 0*Z(2) ], > [ 0*Z(2), 0*Z(2), Z(2)^0 ], > [ Z(2)^0, 0*Z(2), 0*Z(2) ] ] ]);; -gap> List(HallSubgroup(G, [2,3]), IdGroup); -[ [ 24, 12 ], [ 24, 12 ] ] +gap> List(HallSubgroup(G, [2,3]), StructureDescription); +[ "S4", "S4" ] # gap> G:=PerfectGroup(IsFpGroup,60,1); diff --git a/tst/testinstall/opers/IsSolvableGroup.tst b/tst/testinstall/opers/IsSolvableGroup.tst index d06f79379f..f1e23afd9d 100644 --- a/tst/testinstall/opers/IsSolvableGroup.tst +++ b/tst/testinstall/opers/IsSolvableGroup.tst @@ -1,9 +1,11 @@ gap> START_TEST("IsSolvableGroup.tst"); +#@if IsPackageMarkedForLoading( "smallgrp", "" ) gap> List(AllSmallGroups(120), IsSolvableGroup); [ true, true, true, true, false, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, false, false, true, true, true, true, true, true, true, true, true, true, true, true ] +#@fi gap> grps := [ > [ (1,2,3,4,5,6,7,8) ], [ (1,2,3,8)(4,5,6,7), (1,5)(2,6)(3,7)(4,8) ], > [ (1,8)(2,3)(4,5)(6,7), (1,3)(2,8)(4,6)(5,7), (1,5)(2,6)(3,7)(4,8) ], diff --git a/tst/testinstall/opers/LatticeByCyclicExtension.tst b/tst/testinstall/opers/LatticeByCyclicExtension.tst index 959f788b0c..779b6fd668 100644 --- a/tst/testinstall/opers/LatticeByCyclicExtension.tst +++ b/tst/testinstall/opers/LatticeByCyclicExtension.tst @@ -1,8 +1,13 @@ gap> START_TEST("LatticeByCyclicExtension.tst"); +# construct SmallGroup(500,1) +gap> H:=CyclicGroup(4);; +gap> N:=CyclicGroup(125);; +gap> A:=AutomorphismGroup(N);; +gap> alpha:=GroupHomomorphismByImages(H,A,[H.1],[A.1^50]);; +gap> G:=SemidirectProduct(H, alpha, N);; + # -gap> G:=SmallGroup(500,1); - gap> fun:=g->IsInt(4/Size(g));; gap> LatticeByCyclicExtension(G); , 12 classes, diff --git a/tst/testinstall/opers/MinimalNormalSubgroups.tst b/tst/testinstall/opers/MinimalNormalSubgroups.tst index f5a7ff3ce7..1983bf5b09 100644 --- a/tst/testinstall/opers/MinimalNormalSubgroups.tst +++ b/tst/testinstall/opers/MinimalNormalSubgroups.tst @@ -7,42 +7,49 @@ gap> G := Group(());; NormalSubgroups(G);; MinimalNormalSubgroups(G); gap> D := DihedralGroup(8);; gap> MinimalNormalSubgroups(D) = [ Center(D) ]; true -gap> List(MinimalNormalSubgroups(D), IdGroup); -[ [ 2, 1 ] ] +gap> List(MinimalNormalSubgroups(D), Size); +[ 2 ] gap> D := DihedralGroup(IsFpGroup, 8);; gap> MinimalNormalSubgroups(D) = [ Center(D) ]; true -gap> List(MinimalNormalSubgroups(D), IdGroup); -[ [ 2, 1 ] ] +gap> List(MinimalNormalSubgroups(D), Size); +[ 2 ] gap> D := Group((1,3),(1,2,3,4));; gap> MinimalNormalSubgroups(D) = [ Center(D) ]; true -gap> List(MinimalNormalSubgroups(D), IdGroup); -[ [ 2, 1 ] ] +gap> List(MinimalNormalSubgroups(D), Size); +[ 2 ] gap> DDD := DirectProduct(D, D, D);; -gap> List(MinimalNormalSubgroups(DDD), IdGroup); -[ [ 2, 1 ], [ 2, 1 ], [ 2, 1 ], [ 2, 1 ], [ 2, 1 ], [ 2, 1 ], [ 2, 1 ] ] +gap> List(MinimalNormalSubgroups(DDD), Size); +[ 2, 2, 2, 2, 2, 2, 2 ] gap> Q := QuaternionGroup(8);; gap> MinimalNormalSubgroups(Q) = [ Center(Q) ]; true -gap> List(MinimalNormalSubgroups(Q), IdGroup); -[ [ 2, 1 ] ] +gap> List(MinimalNormalSubgroups(Q), Size); +[ 2 ] gap> MinimalNormalSubgroups(SymmetricGroup(4)) = [ Group((1,2)(3,4),(1,3)(2,4)) ]; true -gap> List(MinimalNormalSubgroups(SymmetricGroup(5)), IdGroup); -[ [ 60, 5 ] ] -gap> List(MinimalNormalSubgroups(AlternatingGroup(5)), IdGroup); -[ [ 60, 5 ] ] +gap> MinimalNormalSubgroups(SymmetricGroup(5)) = [ AlternatingGroup(5) ]; +true +gap> MinimalNormalSubgroups(AlternatingGroup(5)) = [ AlternatingGroup(5) ]; +true + +# gap> G := Group((1,2),(3,4),(5,6),(7,8));; gap> IsElementaryAbelian(G); true gap> Size(MinimalNormalSubgroups(G)); 15 -gap> MinimalNormalSubgroups(PrimitiveGroup(8,3)) = [ Group([ (1,7)(2,8)(3,5)(4,6), (1,3)(2,4)(5,7)(6,8), (1,2)(3,4)(5,6)(7,8) ]) ]; + +# +gap> G := Group((2,7,4,8,6,5,3), (2,3)(6,7), (1,2)(3,4)(5,6)(7,8));; # = PrimitiveGroup(8,3) +gap> MinimalNormalSubgroups(G) = [ Group([ (1,7)(2,8)(3,5)(4,6), (1,3)(2,4)(5,7)(6,8), (1,2)(3,4)(5,6)(7,8) ]) ]; true gap> k := 5;; P := SylowSubgroup(SymmetricGroup(4*k), 2);; A := Group((4*k+1, 4*k+2, 4*k+3));; G := ClosureGroup(P, A);; IsNilpotentGroup(G);; gap> Set(MinimalNormalSubgroups(G)) = Set([ Group([ (1,2)(3,4)(5,6)(7,8)(9,10)(11,12)(13,14)(15,16) ]), Group([ (17,18)(19,20) ]), Group([ (1,2)(3,4)(5,6)(7,8)(9,10)(11,12)(13,14)(15,16)(17,18)(19,20) ]), Group([ (21,22,23) ]) ]); true + +#@if IsPackageMarkedForLoading( "smallgrp", "" ) gap> G := SmallGroup(24,12);; gap> SortedList(List(MinimalNormalSubgroups(G), IdGroup)); [ [ 4, 2 ] ] @@ -50,13 +57,12 @@ gap> A := DihedralGroup(16);; gap> B := SmallGroup(27, 3);; gap> C := SmallGroup(125, 4);; gap> D := DirectProduct(A, B, C, SmallGroup(1536, 2));; -gap> SortedList(List(MinimalNormalSubgroups(D), IdGroup)); -[ [ 2, 1 ], [ 2, 1 ], [ 2, 1 ], [ 2, 1 ], [ 2, 1 ], [ 2, 1 ], [ 2, 1 ], - [ 2, 1 ], [ 2, 1 ], [ 2, 1 ], [ 2, 1 ], [ 2, 1 ], [ 2, 1 ], [ 2, 1 ], - [ 2, 1 ], [ 2, 1 ], [ 2, 1 ], [ 2, 1 ], [ 2, 1 ], [ 2, 1 ], [ 2, 1 ], - [ 2, 1 ], [ 2, 1 ], [ 2, 1 ], [ 2, 1 ], [ 2, 1 ], [ 2, 1 ], [ 2, 1 ], - [ 2, 1 ], [ 2, 1 ], [ 2, 1 ], [ 3, 1 ], [ 3, 1 ], [ 3, 1 ], [ 3, 1 ], - [ 5, 1 ] ] +gap> SortedList(List(MinimalNormalSubgroups(D), Size)); +[ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 5 ] +#@fi + +# gap> G := Group([ (4,8)(6,10), (4,6,10,8,12), (2,4,12)(6,10,8), (3,9)(4,6,10,8,12)(7,11), (3,5)(4,6,10,8,12)(9,11), (1,3,11,9,5)(4,6,10,8,12) ]);; gap> Set(MinimalNormalSubgroups(G)) = Set([ Group([ (6,12)(8,10), (2,10)(4,12), (2,12)(6,10) ]), Group([ (5,11)(7,9), (3,9)(7,11), (1,9,5,11,7) ]) ]); true @@ -69,6 +75,8 @@ gap> G := F/[x^2, y^2, x^(-1)*y^(-1)*x*y, z];; gap> IsFinite(G);; gap> Size(MinimalNormalSubgroups(G)); 3 + +#@if IsPackageMarkedForLoading( "smallgrp", "" ) gap> for G in AllSmallGroups(60) do NormalSubgroups(G);; Print(Collected(List(Set(MinimalNormalSubgroups(G)), IdGroup)), "\n"); od; [ [ [ 2, 1 ], 1 ], [ [ 3, 1 ], 1 ], [ [ 5, 1 ], 1 ] ] [ [ [ 2, 1 ], 1 ], [ [ 3, 1 ], 1 ], [ [ 5, 1 ], 1 ] ] @@ -105,6 +113,9 @@ gap> for G in AllSmallGroups(360) do if not IsSolvable(G) then NormalSubgroups(G [ [ 3, 1 ], [ 60, 5 ] ] [ [ 3, 1 ], [ 60, 5 ] ] [ [ 2, 1 ], [ 3, 1 ], [ 60, 5 ] ] +#@fi + +# gap> G := AbelianGroup([2, 3, 4, 5, 6, 7, 8, 9, 10]);; gap> Collected(List(Set(MinimalNormalSubgroups(G)), Size)); [ [ 2, 31 ], [ 3, 13 ], [ 5, 6 ], [ 7, 1 ] ] @@ -114,4 +125,6 @@ gap> Collected(List(Set(MinimalNormalSubgroups(G)), Size)); gap> G := ElementaryAbelianGroup(7^4);; gap> Collected(List(Set(MinimalNormalSubgroups(G)), Size)); [ [ 7, 400 ] ] + +# gap> STOP_TEST("Socle.tst"); diff --git a/tst/testinstall/opers/NormalHallSubgroups.tst b/tst/testinstall/opers/NormalHallSubgroups.tst index 2278d619dc..63dcf7af29 100644 --- a/tst/testinstall/opers/NormalHallSubgroups.tst +++ b/tst/testinstall/opers/NormalHallSubgroups.tst @@ -1,4 +1,5 @@ gap> START_TEST("NormalHallSubgroups.tst"); +#@if IsPackageMarkedForLoading( "smallgrp", "" ) gap> for G in AllSmallGroups(60) do Print(List(NormalHallSubgroups(G), IdGroup), "\n"); od; [ [ 1, 1 ], [ 5, 1 ], [ 3, 1 ], [ 15, 1 ], [ 12, 1 ], [ 60, 1 ] ] [ [ 1, 1 ], [ 3, 1 ], [ 5, 1 ], [ 15, 1 ], [ 20, 1 ], [ 60, 2 ] ] @@ -40,11 +41,18 @@ gap> List(AllSmallGroups(168), G -> List(NormalHallSubgroups(G), Size)); [ 1, 8, 7, 56, 168 ], [ 1, 3, 7, 56, 21, 168 ], [ 1, 7, 3, 24, 21, 168 ], [ 1, 3, 7, 21, 168 ], [ 1, 8, 3, 24, 7, 56, 21, 168 ] ] gap> for G in AllSmallGroups(168) do primes := PrimeDivisors(Size(G)); l := []; for pi in IteratorOfCombinations(primes) do N := HallSubgroup(G, pi); if N<>fail and IsGroup(N) and IsNormal(G, N) then AddSet(l, N); fi; od; if l <> NormalHallSubgroups(G) then Print(IdGroup(G), "\n"); fi; od; +#@fi + +# +#@if IsPackageMarkedForLoading( "primgrp", "" ) gap> List(AllPrimitiveGroups(DegreeAction, 8), G -> List(NormalHallSubgroups(G), Size)); [ [ 1, 56, 8 ], [ 1, 168, 56, 8 ], [ 1, 1344 ], [ 1, 168 ], [ 1, 336 ], [ 1, 20160 ], [ 1, 40320 ] ] gap> List(NormalHallSubgroups(PrimitiveGroup(8,2)), Size); [ 1, 168, 56, 8 ] +#@fi + +# gap> grps := [ [ (1,2,3,4,5,6) ], [ (1,3,5)(2,4,6), (1,4)(2,3)(5,6) ], > [ (1,2,3,4,5,6), (1,4)(2,3)(5,6) ], [ (1,4)(2,5), (1,3,5)(2,4,6) ], > [ (2,4,6), (1,4)(2,5)(3,6) ], [ (3,6), (1,3,5)(2,4,6) ], diff --git a/tst/testinstall/opers/SimpleGroup.tst b/tst/testinstall/opers/SimpleGroup.tst index cd2940f33d..72494f41d4 100644 --- a/tst/testinstall/opers/SimpleGroup.tst +++ b/tst/testinstall/opers/SimpleGroup.tst @@ -31,6 +31,7 @@ M11 rec( name := "M(11)", series := "Spor", shortname := "M11" ) # +#@if IsPackageMarkedForLoading( "primgrp", "" ) gap> SimpleGroup("J1"); Size(last); IsomorphismTypeInfoFiniteSimpleGroup(last2); J_1 175560 @@ -39,10 +40,12 @@ gap> SimpleGroup("J_2"); Size(last); IsomorphismTypeInfoFiniteSimpleGroup(last2) J_2 604800 rec( name := "HJ = J(2) = F(5-)", series := "Spor", shortname := "J2" ) +#@fi gap> SimpleGroup("J5"); Error, illegal parameter for Janko groups # +#@if IsPackageMarkedForLoading( "primgrp", "" ) gap> SimpleGroup("CO3"); Size(last); IsomorphismTypeInfoFiniteSimpleGroup(last2); Co_3 495766656000 @@ -51,6 +54,7 @@ gap> SimpleGroup("CO(2)"); Size(last); IsomorphismTypeInfoFiniteSimpleGroup(last Co(2) 42305421312000 rec( name := "Co(2)", series := "Spor", shortname := "Co2" ) +#@fi gap> SimpleGroup("CO4"); Error, illegal parameter for Conway groups @@ -59,6 +63,7 @@ gap> SimpleGroup("Fi20"); Error, illegal parameter for Fischer groups # +#@if IsPackageMarkedForLoading( "primgrp", "" ) gap> SimpleGroup("SuZ"); Size(last); IsomorphismTypeInfoFiniteSimpleGroup(last2); Suz 448345497600 @@ -78,6 +83,7 @@ Sz(8) 29120 rec( name := "2B(2,8) = 2C(2,8) = Sz(8)", parameter := 8, series := "2B", shortname := "Sz(8)" ) +#@fi gap> SimpleGroup("Sz(9)"); Error, illegal parameter for Suzuki groups gap> SimpleGroup("Suz(16)"); @@ -105,6 +111,7 @@ gap> SimpleGroup("Ree(16)"); Error, illegal parameter for Ree groups # +#@if IsPackageMarkedForLoading( "primgrp", "" ) gap> SimpleGroup("HE"); Size(last); IsomorphismTypeInfoFiniteSimpleGroup(last2); He 4030387200 @@ -122,6 +129,7 @@ gap> SimpleGroup("T"); Size(last); IsomorphismTypeInfoFiniteSimpleGroup(last2); 17971200 rec( name := "2F(4,2)' = Ree(2)' = Tits", parameter := 2, series := "2F", shortname := "2F4(2)'" ) +#@fi # # linear groups @@ -263,6 +271,7 @@ Error, Can't do yet # gap> SimpleGroup("G3(3)"); Error, G(n,q) needs n=2 +#@if IsPackageMarkedForLoading( "primgrp", "" ) gap> SimpleGroup("G2(2)"); Size(last); IsomorphismTypeInfoFiniteSimpleGroup(last2); PSU(3,3) 6048 @@ -280,15 +289,18 @@ gap> SimpleGroup("G2(5)"); Size(last); IsomorphismTypeInfoFiniteSimpleGroup(last G_2(5) 5859000000 rec( name := "G(2,5)", parameter := 5, series := "G", shortname := "G2(5)" ) +#@fi # gap> SimpleGroup("3D(3,4)"); Error, 3D(n,q) needs n=4 +#@if IsPackageMarkedForLoading( "primgrp", "" ) gap> SimpleGroup("3D(4,2)"); Size(last); IsomorphismTypeInfoFiniteSimpleGroup(last2); 3D(4, 2) 211341312 rec( name := "3D(4,2)", parameter := 2, series := "3D", shortname := "3D4(2)" ) +#@fi gap> g:=SimpleGroup("3D(4,169)"); 3D4(169) gap> Size(g); diff --git a/tst/testinstall/opers/Socle.tst b/tst/testinstall/opers/Socle.tst index af4b16c56c..13d482d33a 100644 --- a/tst/testinstall/opers/Socle.tst +++ b/tst/testinstall/opers/Socle.tst @@ -4,34 +4,34 @@ Group(()) gap> D := DihedralGroup(8);; gap> Socle(D) = ClosureSubgroup(TrivialSubgroup(D), Union(Set(MinimalNormalSubgroups(D), GeneratorsOfGroup))); true -gap> IdGroup(Socle(D)); -[ 2, 1 ] +gap> Size(Socle(D)); +2 gap> Socle(D) = Center(D); true gap> D := DihedralGroup(IsFpGroup, 8);; gap> Socle(D) = ClosureSubgroup(TrivialSubgroup(D), Union(Set(MinimalNormalSubgroups(D), GeneratorsOfGroup))); true -gap> IdGroup(Socle(D)); -[ 2, 1 ] +gap> Size(Socle(D)); +2 gap> Socle(D) = Center(D); true gap> D := DihedralGroup(IsPermGroup, 8);; gap> Socle(D) = ClosureSubgroup(TrivialSubgroup(D), Union(Set(MinimalNormalSubgroups(D), GeneratorsOfGroup))); true -gap> IdGroup(Socle(D)); -[ 2, 1 ] +gap> Size(Socle(D)); +2 gap> Socle(D) = Center(D); true gap> D := Group((1,3),(1,2,3,4));; gap> Socle(D) = ClosureSubgroup(TrivialSubgroup(D), Union(Set(MinimalNormalSubgroups(D), GeneratorsOfGroup))); true -gap> IdGroup(Socle(D)); -[ 2, 1 ] +gap> Size(Socle(D)); +2 gap> Socle(D) = Center(D); true gap> DDD := DirectProduct(D, D, D);; -gap> IdGroup(Socle(DDD)); -[ 8, 5 ] +gap> StructureDescription(Socle(DDD)); +"C2 x C2 x C2" gap> Socle(DDD) = ClosureSubgroup(TrivialSubgroup(DDD), Union(Set(MinimalNormalSubgroups(DDD), GeneratorsOfGroup))); true gap> Socle(DDD) = Center(DDD); @@ -39,22 +39,23 @@ true gap> Q := QuaternionGroup(8);; gap> Socle(Q) = ClosureSubgroup(TrivialSubgroup(Q), Union(Set(MinimalNormalSubgroups(Q), GeneratorsOfGroup))); true -gap> IdGroup(Socle(Q)); -[ 2, 1 ] +gap> Size(Socle(Q)); +2 gap> Socle(Q) = Center(Q); true gap> Socle(SymmetricGroup(4)) = Group((1,2)(3,4),(1,3)(2,4)); true -gap> IdGroup(Socle(SymmetricGroup(5))); -[ 60, 5 ] -gap> IdGroup(Socle(AlternatingGroup(5))); -[ 60, 5 ] +gap> AlternatingGroup(5) = Socle(SymmetricGroup(5)); +true +gap> AlternatingGroup(5) = Socle(AlternatingGroup(5)); +true gap> G := Group((1,2),(3,4),(5,6),(7,8));; gap> IsElementaryAbelian(G); true gap> Socle(G)=G; true -gap> Socle(PrimitiveGroup(8,3)) = Group([ (1,7)(2,8)(3,5)(4,6), (1,3)(2,4)(5,7)(6,8), (1,2)(3,4)(5,6)(7,8) ]); +gap> G:=Group([ (2,7,4,8,6,5,3), (2,3)(6,7), (1,2)(3,4)(5,6)(7,8) ]);; # = PrimitiveGroup(8,3) +gap> Socle(G) = Group([ (1,7)(2,8)(3,5)(4,6), (1,3)(2,4)(5,7)(6,8), (1,2)(3,4)(5,6)(7,8) ]); true gap> k := 5;; P := SylowSubgroup(SymmetricGroup(4*k), 2);; A := Group((4*k+1, 4*k+2, 4*k+3));; G := ClosureGroup(P, A);; gap> Socle(G) = Group([ (21,22,23), (1,2)(3,4)(5,6)(7,8)(9,10)(11,12)(13,14)(15,16), (17,18)(19,20) ]); @@ -62,17 +63,19 @@ true gap> G := Group([ (1,2,3,5,4), (1,3)(2,4)(6,7) ]);; gap> Socle(G) = Group((1,2,3),(3,4,5),(6,7)); true -gap> G := SmallGroup(24,12);; -gap> IdGroup(Socle(G)); -[ 4, 2 ] +gap> G := SymmetricGroup(IsPcGroup, 4);; +gap> StructureDescription(Socle(G)); +"C2 x C2" +#@if IsPackageMarkedForLoading( "smallgrp", "" ) gap> A := DihedralGroup(16);; -gap> B := SmallGroup(27, 3);; -gap> C := SmallGroup(125, 4);; +gap> B := ExtraspecialGroup( 27, 3 );; +gap> C := ExtraspecialGroup( 125, 25 );; gap> D := DirectProduct(A, B, C, SmallGroup(1536, 2));; -gap> IdGroup(Socle(D)); -[ 1440, 5958 ] +gap> StructureDescription(Socle(D)); +"C30 x C6 x C2 x C2 x C2" gap> Socle(D) = Center(D); true +#@fi gap> Socle(FittingSubgroup(SymmetricGroup(4))) = Group([ (1,4)(2,3), (1,3)(2,4) ]); true gap> G := Group([ (4,8)(6,10), (4,6,10,8,12), (2,4,12)(6,10,8), (3,9)(4,6,10,8,12) diff --git a/tst/testinstall/opers/StructureDescription.tst b/tst/testinstall/opers/StructureDescription.tst index 204f6a4b91..ceb2bd0e7c 100644 --- a/tst/testinstall/opers/StructureDescription.tst +++ b/tst/testinstall/opers/StructureDescription.tst @@ -1,6 +1,7 @@ gap> START_TEST("StructureDescription.tst"); ## Examples from manual +#@if IsPackageMarkedForLoading( "smallgrp", "" ) gap> l := AllSmallGroups(12);; gap> List(l, StructureDescription);; l; [ C3 : C4, C12, A4, D12, C6 x C2 ] @@ -42,9 +43,15 @@ gap> List(AllSmallGroups(60), G -> StructureDescription(G:recompute)); [ "C5 x (C3 : C4)", "C3 x (C5 : C4)", "C3 : (C5 : C4)", "C60", "A5", "C3 x (C5 : C4)", "C3 : (C5 : C4)", "S3 x D10", "C5 x A4", "C6 x D10", "C10 x S3", "D60", "C30 x C2" ] +#@fi + +#@if IsPackageMarkedForLoading( "primgrp", "" ) gap> List(AllPrimitiveGroups(DegreeAction, 8), StructureDescription); [ "(C2 x C2 x C2) : C7", "(C2 x C2 x C2) : (C7 : C3)", "(C2 x C2 x C2) : PSL(3,2)", "PSL(3,2)", "PSL(3,2) : C2", "A8", "S8" ] +#@fi + +# gap> StructureDescription(AbelianGroup([0,0,0,2,3,6]):short); "Z^3x6^2" gap> G := Group([ (4,8)(6,10), (4,6,10,8,12), (2,4,12)(6,10,8), (3,9)(4,6,10,8,12)(7,11), (3,5)(4,6,10,8,12)(9,11), (1,3,11,9,5)(4,6,10,8,12) ]);; @@ -71,6 +78,7 @@ gap> G := PerfectGroup(IsPermGroup,1344,1);; StructureDescription(G); "(C2 x C2 x C2) : PSL(3,2)" gap> G := PerfectGroup(IsPermGroup,1344,2);; StructureDescription(G); "(C2 x C2 x C2) . PSL(3,2)" +#@if IsPackageMarkedForLoading( "smallgrp", "" ) gap> StructureDescription(SmallGroup(32,15):recompute); "C4 . D8 = C4 . (C4 x C2)" gap> List(AllSmallNonabelianSimpleGroups([1..1000000]), StructureDescription); @@ -84,6 +92,9 @@ gap> List(AllSmallNonabelianSimpleGroups([1..1000000]), StructureDescription); "PSL(2,89)", "PSL(3,5)", "M22", "PSL(2,97)", "PSL(2,101)", "PSL(2,103)", "HJ", "PSL(2,107)", "PSL(2,109)", "PSL(2,113)", "PSL(2,121)", "PSL(2,125)", "O(5,4)" ] +#@fi + +# gap> G := FactorGroup(Sp(6,3), Center(Sp(6,3)));; gap> StructureDescription(G); "PSp(6,3)" @@ -91,8 +102,13 @@ gap> StructureDescription(Omega(1,8,2)); "O+(8,2)" gap> StructureDescription(Omega(-1,8,2)); "O-(8,2)" + +#@if IsPackageMarkedForLoading( "primgrp", "" ) gap> List(AllPrimitiveGroups(DegreeAction, 819, Size, 211341312, IsSimple, true), StructureDescription); [ "3D(4,2)" ] +#@fi + +# gap> G := Ree(27);; gap> HasIsFinite(G) and IsFinite(G) and HasIsSimpleGroup(G) and IsSimple(G); true @@ -102,6 +118,8 @@ gap> StructureDescription(AbelianGroup([0,0,0,2,3,4,5,6,7,8,9,10])); "Z x Z x Z x C2520 x C60 x C6 x C2 x C2" gap> StructureDescription(AbelianGroup([0,0,0,2,3,4,5,6,7,8,9,10]):short); "Z^3x2520x60x6x2^2" + +#@if IsPackageMarkedForLoading( "smallgrp", "" ) gap> infolevel:=InfoLevel(InfoWarning);; SetInfoLevel(InfoWarning,2); gap> StructureDescription(SmallGroup(48,16):recompute,nice); #I Warning! Non-unique semidirect product: @@ -112,6 +130,9 @@ gap> StructureDescription(SmallGroup(64,17):recompute,nice); #I [ [ "C4 x C2", "C8" ], [ "C8 x C2", "C4" ] ] "(C4 x C2) : C8" gap> SetInfoLevel(InfoWarning,infolevel); +#@fi + +# gap> F := FreeGroup("r", "s");; r := F.1;; s := F.2;; gap> G := F/[s^2, r^3, s*r*s*r];; gap> StructureDescription(G); diff --git a/tst/testinstall/opers/SubdirectProducts.tst b/tst/testinstall/opers/SubdirectProducts.tst index b44c999c4c..98e23013fa 100644 --- a/tst/testinstall/opers/SubdirectProducts.tst +++ b/tst/testinstall/opers/SubdirectProducts.tst @@ -4,30 +4,43 @@ gap> H := SymmetricGroup(4);; gap> A := CyclicGroup(6);; # -gap> Set(SubdirectProducts(G, G), IdGroup); -[ [ 6, 1 ], [ 18, 4 ], [ 36, 10 ] ] -gap> Set(SubdirectProducts(H, H), IdGroup); -[ [ 24, 12 ], [ 96, 227 ], [ 288, 1026 ], [ 576, 8653 ] ] -gap> Set(SubdirectProducts(A, A), IdGroup); -[ [ 6, 2 ], [ 12, 5 ], [ 18, 5 ], [ 36, 14 ] ] +gap> SortedList(List(SubdirectProducts(G, G), StructureDescription)); +[ "(C3 x C3) : C2", "S3", "S3 x S3" ] +gap> SortedList(List(SubdirectProducts(A, A), StructureDescription)); +[ "C6", "C6", "C6 x C2", "C6 x C2", "C6 x C3", "C6 x C6" ] -# -gap> Set(SubdirectProducts(G, H), IdGroup); +# for the next couple tests, StructureDescription gives different outputs +# depending on which packages are loaded; e.g. for SubdirectProducts(H, H): +# [ "((C2 x C2 x C2 x C2) : C3) : C2", "(A4 x A4) : C2", "S4", "S4 x S4" ] +# [ "(C2 x C2) : ((C3 x A4) : C2)", "(C2 x C2) : S4", "S4", "S4 x S4" ] +# thus we use IdGroup if available, and else fall back to a weaker size test. +#@if IsPackageMarkedForLoading( "smallgrp", "" ) +gap> SortedList(List(SubdirectProducts(H, H), IdGroup)); +[ [ 24, 12 ], [ 96, 227 ], [ 288, 1026 ], [ 576, 8653 ] ] +gap> SortedList(List(SubdirectProducts(G, H), IdGroup)); [ [ 24, 12 ], [ 72, 43 ], [ 144, 183 ] ] -gap> Set(SubdirectProducts(H, G), IdGroup); +gap> SortedList(List(SubdirectProducts(H, G), IdGroup)); [ [ 24, 12 ], [ 72, 43 ], [ 144, 183 ] ] +#@else +gap> SortedList(List(SubdirectProducts(H, H), Size)); +[ 24, 96, 288, 576 ] +gap> SortedList(List(SubdirectProducts(G, H), Size)); +[ 24, 72, 144 ] +gap> SortedList(List(SubdirectProducts(H, G), Size)); +[ 24, 72, 144 ] +#@fi # -gap> Set(SubdirectProducts(G, A), IdGroup); -[ [ 18, 3 ], [ 36, 12 ] ] -gap> Set(SubdirectProducts(A, G), IdGroup); -[ [ 18, 3 ], [ 36, 12 ] ] +gap> SortedList(List(SubdirectProducts(G, A), StructureDescription)); +[ "C3 x S3", "C6 x S3" ] +gap> SortedList(List(SubdirectProducts(A, G), StructureDescription)); +[ "C3 x S3", "C6 x S3" ] # -gap> Set(SubdirectProducts(H, A), IdGroup); -[ [ 72, 42 ], [ 144, 188 ] ] -gap> Set(SubdirectProducts(A, H), IdGroup); -[ [ 72, 42 ], [ 144, 188 ] ] +gap> SortedList(List(SubdirectProducts(H, A), StructureDescription)); +[ "C3 x S4", "C6 x S4" ] +gap> SortedList(List(SubdirectProducts(A, H), StructureDescription)); +[ "C3 x S4", "C6 x S4" ] # gap> STOP_TEST("SubdirectProducts.tst"); From 055434e28f0a249436cc07a5e9d6b73f37671ccb Mon Sep 17 00:00:00 2001 From: Thomas Breuer Date: Mon, 11 May 2026 13:19:48 +0200 Subject: [PATCH 215/234] Miscellaneous fixes concerning vector and matrix objects (#6369) * add checks to `NewVector`, `NewMatrix` for the GF(2) and 8 bit repres. in order to catch `fail` results * add a `String` method for rings `Integers mod n` * fix the default `OneMutable` method for `IsMatrixObj` Test that the input is square, as for list-of-lists matrices. * minor fixes for `IsPlistVectorRep` - check the input list for `IsPlistRep` in `MakeIsPlistVectorRep`, let `NewVector` turn the input to `IsPlistRep` if necessary - forbid assignments into a `IsPlistVectorRep` vector beyond its length * fix `SolutionMatDestructive` Conceptually, the solution must be in the same representation as the given vector. (Let us see which other bugs will come to the surface now.) * fix `TestPositionNonZeroInRow` --- hpcgap/lib/vec8bit.gi | 14 +++++++++++--- hpcgap/lib/vecmat.gi | 11 +++++++++-- lib/matobj.gi | 9 ++++++++- lib/matobjplist.gi | 9 +++++++-- lib/matrix.gi | 3 +-- lib/vec8bit.gi | 14 +++++++++++--- lib/vecmat.gi | 11 +++++++++-- lib/zmodnz.gi | 6 ++++++ tst/testinstall/MatrixObj/ListOp.tst | 3 +++ tst/testinstall/MatrixObj/matobjplist.tst | 2 ++ tst/testinstall/MatrixObj/testmatobj.g | 5 +++-- 11 files changed, 70 insertions(+), 17 deletions(-) diff --git a/hpcgap/lib/vec8bit.gi b/hpcgap/lib/vec8bit.gi index 31af64cad8..00d34ac9d1 100644 --- a/hpcgap/lib/vec8bit.gi +++ b/hpcgap/lib/vec8bit.gi @@ -1133,10 +1133,16 @@ InstallMethod( BaseField, "for a compressed 8bit vector", InstallTagBasedMethod( NewVector, Is8BitVectorRep, function( filter, f, l ) - if ValueOption( "check" ) <> false and not Size(f) in [3..256] then + local check, res; + check:= ValueOption( "check" ) <> false; + if check and not Size(f) in [3..256] then Error("Is8BitVectorRep only supports base fields with 3 to 256 elements"); fi; - return CopyToVectorRep(l,Size(f)); + res:= CopyToVectorRep( l, Size( f ) ); + if check and res = fail then + Error( "cannot copy to 'Is8BitVectorRep'" ); + fi; + return res; end ); # This is faster than the default method. @@ -1170,7 +1176,9 @@ InstallTagBasedMethod( NewMatrix, else m := List(l,ShallowCopy); fi; - ConvertToMatrixRep(m,Size(f)); + if ConvertToMatrixRep( m, Size( f ) ) = fail then + Error( "cannot convert to 'Is8BitMatrixRep'" ); + fi; return m; end ); diff --git a/hpcgap/lib/vecmat.gi b/hpcgap/lib/vecmat.gi index e582db8b0f..8291757030 100644 --- a/hpcgap/lib/vecmat.gi +++ b/hpcgap/lib/vecmat.gi @@ -2555,8 +2555,13 @@ InstallMethod( BaseField, "for a compressed gf2 vector", InstallTagBasedMethod( NewVector, IsGF2VectorRep, function( filter, f, l ) + local res; if Size(f) <> 2 then Error("IsGF2VectorRep only supported over GF(2)"); fi; - return CopyToVectorRep(l,2); + res:= CopyToVectorRep( l, 2 ); + if res = fail then + Error( "cannot copy to 'IsGF2VectorRep'" ); + fi; + return res; end ); InstallTagBasedMethod( NewZeroVector, @@ -2583,7 +2588,9 @@ InstallTagBasedMethod( NewMatrix, else m := List(l,ShallowCopy); fi; - ConvertToMatrixRep(m,2); + if ConvertToMatrixRep( m, 2 ) = fail then + Error( "cannot convert to 'IsGF2MatrixRep'" ); + fi; return m; end ); diff --git a/lib/matobj.gi b/lib/matobj.gi index 35ae1ccbe0..712effd553 100644 --- a/lib/matobj.gi +++ b/lib/matobj.gi @@ -1476,7 +1476,14 @@ InstallMethod( ZeroSameMutability, InstallMethod( OneMutable, [ IsMatrixObj ], - M -> IdentityMatrix( NumberRows( M ), M ) ); + function( M ) + local nrows; + nrows:= NrRows( M ); + if nrows <> NrCols( M ) then + Error( " must be square (not ", nrows, " by ", NrCols( M ), ")" ); + fi; + return IdentityMatrix( nrows, M ); + end ); InstallMethod( OneSameMutability, [ IsMatrixOrMatrixObj ], diff --git a/lib/matobjplist.gi b/lib/matobjplist.gi index 69a5106d54..c8b2a3ecbe 100644 --- a/lib/matobjplist.gi +++ b/lib/matobjplist.gi @@ -88,6 +88,8 @@ BindGlobal( "MakeIsPlistVectorRep", if check and ValueOption( "check" ) <> false then if not IsSubset( basedomain, list ) then Error( "the elements in must lie in " ); + elif not IsPlistRep( list ) then + Error( " must be in 'IsPlistRep'" ); fi; fi; @@ -177,7 +179,7 @@ BindGlobal( "MakeIsPlistMatrixRep", InstallTagBasedMethod( NewVector, IsPlistVectorRep, function( filter, basedomain, list ) - return MakeIsPlistVectorRep(basedomain, ShallowCopy(list), true); + return MakeIsPlistVectorRep(basedomain, PlainListCopy( list ), true); end ); InstallTagBasedMethod( NewZeroVector, @@ -343,6 +345,9 @@ InstallMethod( \[\], InstallMethod( \[\]\:\=, [ "IsPlistVectorRep", "IsPosInt", "IsObject" ], function( v, p, ob ) + if ValueOption( "check" ) <> false and Length( v![ELSPOS] ) < p then + Error( "

is out of bounds" ); + fi; v![ELSPOS][p] := ob; end ); @@ -699,7 +704,7 @@ InstallMethod( Matrix, else l := []; fi; - # The result shall be mutable iff 'rows' is mutable. + # The result shall be mutable iff 'list' is mutable. if not IsMutable( list ) then MakeImmutable( l ); fi; diff --git a/lib/matrix.gi b/lib/matrix.gi index b5780f80f4..8deda4ee65 100644 --- a/lib/matrix.gi +++ b/lib/matrix.gi @@ -3040,8 +3040,7 @@ InstallOtherMethod( SolutionMatDestructive, local i,ncols,sem, vno, z,x, sol; ncols := Length(vec); z := ZeroOfBaseDomain(mat); - sol := ListWithIdenticalEntries(NrRows(mat),z); - ConvertToVectorRepNC(sol); + sol:= ZeroVector( NrRows( mat ), vec ); if ncols <> NrCols(mat) then Error("SolutionMat: matrix and vector incompatible"); fi; diff --git a/lib/vec8bit.gi b/lib/vec8bit.gi index 1602a4ca36..5c491f4320 100644 --- a/lib/vec8bit.gi +++ b/lib/vec8bit.gi @@ -1088,10 +1088,16 @@ InstallMethod( BaseField, "for a compressed 8bit vector", InstallTagBasedMethod( NewVector, Is8BitVectorRep, function( filter, f, l ) - if ValueOption( "check" ) <> false and not Size(f) in [3..256] then + local check, res; + check:= ValueOption( "check" ) <> false; + if check and not Size(f) in [3..256] then Error("Is8BitVectorRep only supports base fields with 3 to 256 elements"); fi; - return CopyToVectorRep(l,Size(f)); + res:= CopyToVectorRep( l, Size( f ) ); + if check and res = fail then + Error( "cannot copy to 'Is8BitVectorRep'" ); + fi; + return res; end ); # This is faster than the default method. @@ -1125,7 +1131,9 @@ InstallTagBasedMethod( NewMatrix, else m := List(l,ShallowCopy); fi; - ConvertToMatrixRep(m,Size(f)); + if ConvertToMatrixRep( m, Size( f ) ) = fail then + Error( "cannot convert to 'Is8BitMatrixRep'" ); + fi; return m; end ); diff --git a/lib/vecmat.gi b/lib/vecmat.gi index 8e319696b3..1c83a13c01 100644 --- a/lib/vecmat.gi +++ b/lib/vecmat.gi @@ -2553,8 +2553,13 @@ InstallMethod( BaseField, "for a compressed gf2 vector", InstallTagBasedMethod( NewVector, IsGF2VectorRep, function( filter, f, l ) + local res; if Size(f) <> 2 then Error("IsGF2VectorRep only supported over GF(2)"); fi; - return CopyToVectorRep(l,2); + res:= CopyToVectorRep( l, 2 ); + if res = fail then + Error( "cannot copy to 'IsGF2VectorRep'" ); + fi; + return res; end ); InstallTagBasedMethod( NewZeroVector, @@ -2581,7 +2586,9 @@ InstallTagBasedMethod( NewMatrix, else m := List(l,ShallowCopy); fi; - ConvertToMatrixRep(m,2); + if ConvertToMatrixRep( m, 2 ) = fail then + Error( "cannot convert to 'IsGF2MatrixRep'" ); + fi; return m; end ); diff --git a/lib/zmodnz.gi b/lib/zmodnz.gi index 980652b8f1..2a352eccf0 100644 --- a/lib/zmodnz.gi +++ b/lib/zmodnz.gi @@ -869,6 +869,7 @@ InstallMethod( TriangulizeMat, ## #M ViewObj( ) . . . . . . . . . . . . . . . . method for full ring Z/nZ #M PrintObj( ) . . . . . . . . . . . . . . . . method for full ring Z/nZ +#M String( ) . . . . . . . . . . . . . . . . . method for full ring Z/nZ ## InstallMethod( ViewObj, "for full ring Z/nZ", @@ -884,6 +885,11 @@ InstallMethod( PrintObj, Print( "(Integers mod ", Size( obj ), ")" ); end ); +InstallMethod( String, + "for full ring Z/nZ", + [ IsZmodnZObjNonprimeCollection and IsWholeFamily ], SUM_FLAGS, + obj -> Concatenation( "(Integers mod ", String( Size( obj ) ), ")" ) ); + ############################################################################# ## diff --git a/tst/testinstall/MatrixObj/ListOp.tst b/tst/testinstall/MatrixObj/ListOp.tst index 0c394900f8..e8a6580c23 100644 --- a/tst/testinstall/MatrixObj/ListOp.tst +++ b/tst/testinstall/MatrixObj/ListOp.tst @@ -23,4 +23,7 @@ gap> List( v ); [ ] gap> List( v, DegreeFFE ); [ ] +gap> v1:= Vector( IsPlistVectorRep, Rationals, [] );; +gap> v1[1]:= 0; +Error,

is out of bounds gap> STOP_TEST("ListOp.tst"); diff --git a/tst/testinstall/MatrixObj/matobjplist.tst b/tst/testinstall/MatrixObj/matobjplist.tst index f1099217d9..584ec3da07 100644 --- a/tst/testinstall/MatrixObj/matobjplist.tst +++ b/tst/testinstall/MatrixObj/matobjplist.tst @@ -3,6 +3,8 @@ gap> START_TEST( "matobjplist.tst" ); # gap> e:= MakeIsPlistVectorRep( Integers, [], true );; +gap> MakeIsPlistVectorRep( Integers, [ 1 .. 4 ], true );; +Error, must be in 'IsPlistRep' gap> v:= MakeIsPlistVectorRep( Integers, [ 1 ], true );; gap> MakeIsPlistVectorRep( Integers, [ 1/2 ], true );; Error, the elements in must lie in diff --git a/tst/testinstall/MatrixObj/testmatobj.g b/tst/testinstall/MatrixObj/testmatobj.g index bca02e4c1c..1f5a21ebc2 100644 --- a/tst/testinstall/MatrixObj/testmatobj.g +++ b/tst/testinstall/MatrixObj/testmatobj.g @@ -257,8 +257,9 @@ end; TestPositionNonZeroInRow := function(mat) local ncols; - # Make a matrix with specific patter of the same kind as mat - mat := Matrix([ [ 0, 1, 0, 1 ], [ 0, 0, 0, 0 ], [ 0, 0, 1, 0 ] ], mat); + # Make a matrix with specific pattern of the same kind as mat + mat := Matrix([ [ 0, 1, 0, 1 ], [ 0, 0, 0, 0 ], [ 0, 0, 1, 0 ] ] + * One( BaseDomain( mat ) ), mat); ncols := NrCols(mat); if PositionNonZeroInRow(mat, 1) <> 2 then From 7eff9eb38e0f41d674d132ee0b82bb1a00f4e944 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lars=20G=C3=B6ttgens?= Date: Mon, 11 May 2026 18:12:21 +0200 Subject: [PATCH 216/234] Increase kernel major version (#6390) --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 6d1531a3ca..1c313ffb8a 100644 --- a/configure.ac +++ b/configure.ac @@ -23,7 +23,7 @@ dnl 2. Otherwise (i.e., if no interfaces have been removed or changed), dnl if any interfaces have been added since the last public release, then dnl increment minor. dnl -m4_define([kernel_major_version], [10]) +m4_define([kernel_major_version], [11]) m4_define([kernel_minor_version], [0]) m4_define([GAP_DEFINE], [GAP_DEFINES="$GAP_DEFINES -D$1"]) From 9e28d1d725ceec36e544a5207345194c4626529a Mon Sep 17 00:00:00 2001 From: Max Horn Date: Mon, 11 May 2026 18:55:53 +0200 Subject: [PATCH 217/234] CI: don't rely on primary GNU file server (#6388) Use a mirror is more resilient and often faster, as one close to you is selected. --- .github/workflows/release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 997d172106..36867a212c 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -94,7 +94,7 @@ jobs: - name: "Install autoconf 2.72" # for compatibility with GCC 14 & clang versions run: | - wget https://ftp.gnu.org/gnu/autoconf/autoconf-2.72.tar.xz + wget https://ftpmirror.gnu.org/gnu/autoconf/autoconf-2.72.tar.xz tar xvf autoconf-2.72.tar.xz cd autoconf-2.72 ./configure From f3050a7edbdfb538e3b75ec6169f37afed5c3554 Mon Sep 17 00:00:00 2001 From: Max Horn Date: Tue, 12 May 2026 00:36:05 +0200 Subject: [PATCH 218/234] Avoid IdGroup in IsGL and IsPSL (#6391) In each case, the new code is in fact slightly faster, unless of course IdGroup already happens to be set for the input group. --- lib/grpnames.gi | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/lib/grpnames.gi b/lib/grpnames.gi index 268109aa1a..11dcafd25e 100644 --- a/lib/grpnames.gi +++ b/lib/grpnames.gi @@ -1490,10 +1490,13 @@ InstallMethod( IsPSL, if Size(DerivedSubgroup(G)) <> 4 then return false; fi; SetParametersOfGroupViewedAsPSL(G,npe); return true; - # PSL(3, 4) / PSL(4, 2) + # PSL(3, 4) / PSL(4, 2) \cong A_8 elif npes = [ [ 4, 2, 1 ], [ 3, 2, 2 ] ] then - if IdGroup(SylowSubgroup(G,2)) = [64,138] then npe := npes[1]; - elif IdGroup(SylowSubgroup(G,2)) = [64,242] then npe := npes[2]; fi; + if IsAlternatingGroup(G) then + npe := npes[1]; + else + npe := npes[2]; + fi; SetParametersOfGroupViewedAsPSL(G,npe); return true; # other cases @@ -1650,7 +1653,21 @@ InstallMethod( IsGL, # GL(2, 3) elif npes = [2, 3, 1] then - if IdGroup(G) <> [48,29] then return false; fi; + # necessary condition: must have derived subgroup of index 2 (i.e., SL(2,3)) + if AbelianInvariants(G) <> [2] then return false; fi; + + # there are two groups order 48 with derived subgroup of index 2: + # - SmallGroup(48,28) is C2 . S4 = SL(2,3) . C2 + # - SmallGroup(48,29) is GL(2,3) + # These two groups are quite similar: they have + # - isomorphic centers (C2), + # - isomorphic derived subgroups (SL(2,3)), + # - same number of conjugacy classes (8), + # - same conjugacy class sizes ([ 1, 12, 8, 6, 1, 6, 8, 6 ]) + # One difference is that the conjugacy class of size 12 consists of + # elements of order 4 in one case, and 2 in the other; this is also + # how e.g. IdGroup distinguishes them + if Number(G, g -> Order(g) = 2) < 13 then return false; fi; SetParametersOfGroupViewedAsGL(G,npes); return true; # other cases, in which contained PSL is simple From a4d84347af1d14531b5dd9ef3e924ead01b0af49 Mon Sep 17 00:00:00 2001 From: cdwensley Date: Tue, 12 May 2026 14:05:00 +0100 Subject: [PATCH 219/234] rebuilding my copy of this branch --- lib/oprt.gi | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/oprt.gi b/lib/oprt.gi index 1d0b878fb0..ceda3fd109 100644 --- a/lib/oprt.gi +++ b/lib/oprt.gi @@ -3415,7 +3415,8 @@ end ); ## #M PreImagesRepresentativeNC( , ) . . . . . . . . . build matrix ## -#### InstallMethod( PreImagesRepresentativeNC,"IsProjectiveActionHomomorphism", +##<<<< fixed a clash with #6232 (12/5/26)? +##<< InstallMethod( PreImagesRepresentativeNC,"IsProjectiveActionHomomorphism", ## The idea is as follows. ## We have an $F$-basis $(v_1, \ldots, v_n)$. ## The matrix $M \in GL(n, F)$ acts first by right multiplication, From d784b62d6186973fe843e104bfa18aa604f36ea1 Mon Sep 17 00:00:00 2001 From: Thomas Breuer Date: Wed, 6 May 2026 02:43:15 +0200 Subject: [PATCH 220/234] Add `RandomMatrix`, `RandomInvertibleMatrix`; and fix a problem with a new feature for matrix groups (#6232) - add a description of the cache `FULLGLNICOCACHE` in the code; it is used only by `NicomorphismFFMatGroupOnFullSpace` - change the keys of `FULLGLNICOCACHE`: take the field of the matrix entries into account (not only its size), take the `ConstructingFilter` of the matrices into account - in `NicomorphismFFMatGroupOnFullSpace`, deal with special cases of matrices in `IsBlockMatrixRep` (which have no `ConstructingFilter`) and in `Is8BitMatrixRep` in the situation that the group itself lives over `GF(2)` - in order to admit the action of `IsMatrixObj` matrices on vectors supported by GAP's `Enumerator`s of vector spaces, add a `\^` method that `Unpack`s the matrix object (Eventually we want to avoid this overhead, but then we need `Enumerator`s consisting of vector objects corresponding to the matrix objects.) - add `Matrix` calls in the function that computes preimages under an action homomorphism with `Source` a matrix group, in order to support matrix group elements of prescribed kinds of `IsMatrixObj`. - add tests for the new supported situations (most of the changes were actually forced by already available tests) * add `\in` methods for matrix object and (`GL` or `SL`) * avoid some `Unpack` hacks - introduce `NormedRowVectors_internal( F, base )`, and `AsListOfFreeLeftModule_internal( F, base, zero )`, in order to admit `IsVectorObj`s in `base` without supporting the whole vector space machinery for these objects - introduce `ExternalSet( G )` for matrix groups `G`, meaning the natural `G`-set (an undocumented method for permutation groups `G` was already available) - change `NicomorphismFFMatGroupOnFullSpace` such that we can act with the `IsMatrixObj` matrices on their `IsVectorObj` vectors, without unpacking the matrices - support `IsMatrixObj` matrices in the `Random` methods for GL and SL * adjust also `IsProjectiveActionHomomorphism` methods * add `RandomMatrix`, `RandomInvertibleMatrix` and fix the `RankMat` method for `IsPlistMatrixRep` --- lib/oprt.gi | 19 +++++++++++++++++++ tst/testinstall/grpmat.tst | 16 ++++++++++++++++ 2 files changed, 35 insertions(+) diff --git a/lib/oprt.gi b/lib/oprt.gi index ceda3fd109..2ae61ce158 100644 --- a/lib/oprt.gi +++ b/lib/oprt.gi @@ -3436,6 +3436,25 @@ end ); ## matrix group contains all scalar matrices, or we know that the preimage ## has determinant $1$ and taking the root in question is unique. ## +## The idea is as follows. +## We have an $F$-basis $(v_1, \ldots, v_n)$. +## The matrix $M \in GL(n, F)$ acts first by right multiplication, +## let $w_i = v_i M$. +## Due to the projective action, we know only the normed vectors $c_i w_i$, +## where $c_i \in F \setminus \{ 0 \}$. +## The data computed by 'LinearActionBasis' (if its result is not 'fail') +## provide a vector $v = \sum_i a_i v_i$ such that all $a_i \not= 0$, +## and we know the normed vector $c w$ where $w = v M$ and $c \in F$. +## +## We can compute the decomposition $c w = \sum_i b_i (c_i w_i)$, +## and get $\sum_i b_i (c_i w_i) = c v M = c \sum_i a_i w_i$, +## which means $c_i = c a_i/b_i$ for all $i$. +## Thus we can reconstruct the matrix $M$ up to the scalar factor $c$. +## +## In the cases that are supported, either $c$ is irrelevant because the +## matrix group contains all scalar matrices, or we know that the preimage +## has determinant $1$ and taking the root in question is unique. +## InstallMethod( PreImagesRepresentative,"IsProjectiveActionHomomorphism", #### >>>>>>> aa52ee29a (Add `RandomMatrix`, .... (#6232)) FamRangeEqFamElm, [ IsProjectiveActionHomomorphism, IsPerm ], 0, diff --git a/tst/testinstall/grpmat.tst b/tst/testinstall/grpmat.tst index eea0eb9834..8ac7e4db9e 100644 --- a/tst/testinstall/grpmat.tst +++ b/tst/testinstall/grpmat.tst @@ -107,5 +107,21 @@ true gap> IsSubset( Source( nice2 ), G2 ); true +# 'NiceMonomorphism' behaves well w.r.t. 'ConstructingFilter' +gap> G:= SP( 4, 2 );; +gap> nice:= NiceMonomorphism( G );; +gap> G2:= SP( 4, 2 : ConstructingFilter:= IsPlistMatrixRep );; +gap> nice2:= NiceMonomorphism( G2 );; +gap> IsPlistMatrixRep( One( G ) ); +false +gap> IsPlistMatrixRep( One( G2 ) ); +true +gap> IsIdenticalObj( nice, nice2 ); +false +gap> IsSubset( Source( nice ), G ); +true +gap> IsSubset( Source( nice2 ), G2 ); +true + # gap> STOP_TEST( "grpmat.tst" ); From ad93a3eacf890cba4afae2547cb37062c5c25dbc Mon Sep 17 00:00:00 2001 From: Chris Wensley Date: Wed, 28 Sep 2022 17:21:20 +0100 Subject: [PATCH 221/234] methods for PreImRep renamed PreImRepNC --- lib/alghom.gi | 2 +- lib/ghompcgs.gi | 2 +- lib/ghomperm.gi | 6 +-- lib/mapping.gd | 141 +++++++++++++++++++++++++----------------------- lib/mapping.gi | 28 +++++----- lib/mapprep.gi | 10 ++-- lib/oprt.gi | 22 -------- lib/relation.gi | 2 +- 8 files changed, 98 insertions(+), 115 deletions(-) diff --git a/lib/alghom.gi b/lib/alghom.gi index 780d647796..ec0819b70e 100644 --- a/lib/alghom.gi +++ b/lib/alghom.gi @@ -584,7 +584,7 @@ InstallMethod( PreImagesRepresentativeNC, [ IsGeneralMapping and IsAlgebraGeneralMappingByImagesDefaultRep, IsObject ], function( map, elm ) - return PreImagesRepresentativeNC( + return PreImagesRepresentativeNC( AsLeftModuleGeneralMappingByImages(map), elm ); end ); diff --git a/lib/ghompcgs.gi b/lib/ghompcgs.gi index 78ba75b339..f3fb30ddda 100644 --- a/lib/ghompcgs.gi +++ b/lib/ghompcgs.gi @@ -505,7 +505,7 @@ end); ## #M PreImagesRepresentativeNC( , ) . . . . . . . . . . via images ## -InstallMethod( PreImagesRepresentativeNC, "method for pcgs hom", +InstallMethod( PreImagesRepresentativeNC, "method for pcgs hom", FamRangeEqFamElm, [ IsToPcGroupHomomorphismByImages,IsMultiplicativeElementWithInverse ], 0, function( hom, elm ) diff --git a/lib/ghomperm.gi b/lib/ghomperm.gi index 7f2c626333..38e811426d 100644 --- a/lib/ghomperm.gi +++ b/lib/ghomperm.gi @@ -1579,10 +1579,10 @@ end); ############################################################################# ## -#M PreImagesSetNC( , ) . . . . . . . . . . . . . . . for const hom +#M PreImagesSetNC( , ) . . . . . . . . . . . . . . . . for const hom ## -InstallMethod( PreImagesSetNC, "constituent homomorphism", - CollFamRangeEqFamElms, [ IsConstituentHomomorphism, IsPermGroup ], 0, +InstallMethod( PreImagesSetNC, "constituent homomorphism",CollFamRangeEqFamElms, + [ IsConstituentHomomorphism, IsPermGroup ], 0, function( hom, I ) local H, # preimage of , result K, # kernel of diff --git a/lib/mapping.gd b/lib/mapping.gd index bf3a5a2af6..ffa15c5b08 100644 --- a/lib/mapping.gd +++ b/lib/mapping.gd @@ -982,22 +982,22 @@ DeclareGlobalFunction( "Images" ); ## preimages of elm under map. ##

## Anything may happen if elm is not an element of the range of -## map. -##

-## In order to improve this state of affairs, -## PreImagesElm has been renamed PreImagesElmNC -## throughout the library, and -## PreImagesElm has been declared a synonym for PreImagesElmNC. -##

-## In future versions of &GAP; PreImagesElm -## will perform additional checks and reject invalid inputs. -## These additional checks will slow the computation so, -## when the inputs are known to be valid by construction, -## users are recommended to use PreImagesElmNC. -##

-## Package authors are asked to convert their methods for -## PreImagesElm to methods for PreImagesElmNC. -## Only when this has happened will the additional checks be implemented. +## map. +##

+## In order to improve this state of affairs, +## PreImagesElm has been renamed PreImagesElmNC +## throughout the library, and +## PreImagesElm has been declared a synonym for PreImagesElmNC. +##

+## In future versions of &GAP; PreImagesElm +## will perform additional checks and reject invalid inputs. +## These additional checks will slow the computation so, +## when the inputs are known to be valid by construction, +## users are recommended to use PreImagesElmNC. +##

+## Package authors are asked to convert their methods for +## PreImagesElm to methods for PreImagesElmNC. +## Only when this has happened will the additional checks be implemented. ## ## ## <#/GAPDoc> @@ -1042,29 +1042,29 @@ DeclareOperation( "PreImageElm", ## ## ## If elm is an element of the range of the general mapping -## map then these operations return either a representative -## of the set of preimages of elm under map or fail, +## map then these operations return either a representative +## of the set of preimages of elm under map or fail, ## the latter if and only if elm has no preimages under map. ##

## Anything may happen if elm is not an element of the range of ## map. ##

-## In order to improve this state of affairs, -## PreImagesRepresentative has been renamed -## PreImagesRepresentativeNC throughout the library, -## and PreImagesRepresentative has been declared a synonym for -## PreImagesRepresentativeNC. -##

-## In future versions of &GAP; PreImagesRepresentative -## will perform additional checks and reject invalid inputs. -## These additional checks will slow the computation so, -## when the inputs are known to be valid by construction, -## users are recommended to use PreImagesRepresentativeNC. -##

-## Package authors are asked to convert their methods for -## PreImagesRepresentative to methods for -## PreImagesRepresentativeNC. -## Only when this has happened will the additional checks be implemented. +## In order to improve this state of affairs, +## PreImagesRepresentative has been renamed +## PreImagesRepresentativeNC throughout the library, +## and PreImagesRepresentative has been declared a synonym for +## PreImagesRepresentativeNC. +##

+## In future versions of &GAP; PreImagesRepresentative +## will perform additional checks and reject invalid inputs. +## These additional checks will slow the computation so, +## when the inputs are known to be valid by construction, +## users are recommended to use PreImagesRepresentativeNC. +##

+## Package authors are asked to convert their methods for +## PreImagesRepresentative to methods for +## PreImagesRepresentativeNC. +## Only when this has happened will the additional checks be implemented. ## ## ## <#/GAPDoc> @@ -1076,6 +1076,12 @@ DeclareOperation( "PreImagesRepresentativeNC", [ IsGeneralMapping, IsObject ] ); DeclareSynonym( "PreImagesRepresentative", PreImagesRepresentativeNC ); +## DeclareOperation( "PreImagesRepresentative", +## [ IsGeneralMapping, IsObject ] ); +DeclareOperation( "PreImagesRepresentativeNC", + [ IsGeneralMapping, IsObject ] ); +DeclareSynonym( "PreImagesRepresentative", PreImagesRepresentativeNC ); + ############################################################################# ## #O PreImagesSet( , ) @@ -1094,26 +1100,26 @@ DeclareSynonym( "PreImagesRepresentative", PreImagesRepresentativeNC ); ## Anything may happen if elms is not a subset of the range of ## map. ##

-## In order to improve this state of affairs, -## PreImagesSet has been renamed PreImagesSetNC -## throughout the library, and -## PreImagesSet has been declared a synonym for PreImagesSetNC. +## In order to improve this state of affairs, +## PreImagesSet has been renamed PreImagesSetNC +## throughout the library, and +## PreImagesSet has been declared a synonym for PreImagesSetNC. ##

-## In future versions of &GAP; PreImagesSet -## will perform additional checks and reject invalid inputs. -## These additional checks will slow the computation so, -## when the inputs are known to be valid by construction, -## users are recommended to use PreImagesSetNC. +## In future versions of &GAP; PreImagesSet +## will perform additional checks and reject invalid inputs. +## These additional checks will slow the computation so, +## when the inputs are known to be valid by construction, +## users are recommended to use PreImagesSetNC. ##

-## Package authors are asked to convert their methods for -## PreImagesSet to methods for PreImagesSetNC. -## Only when this has happened will the additional checks be implemented. +## Package authors are asked to convert their methods for +## PreImagesSet to methods for PreImagesSetNC. +## Only when this has happened will the additional checks be implemented. ## ## ## <#/GAPDoc> ## DeclareOperation( "PreImagesSetNC", [ IsGeneralMapping, IsListOrCollection ] ); -DeclareSynonym( "PreImagesSet", PreImagesSetNC ); +DeclareSynonym( "PreImagesSet", PreImagesSetNC ); ############################################################################# @@ -1174,11 +1180,11 @@ DeclareGlobalFunction( "PreImage" ); ############################################################################# ## -#F PreImages() +#F PreImages() #F PreImagesNC() . . . set of preimages of the range of a gen. mapping -#F PreImages(,) +#F PreImages(,) #F PreImagesNC(,) set of preimages of an elm under a gen. mapping -#F PreImages(,) +#F PreImages(,) #F PreImagesNC(,) set of preimages of a coll. under a gen. mapping ## ## <#GAPDoc Label="PreImages"> @@ -1216,37 +1222,36 @@ DeclareGlobalFunction( "PreImage" ); ## (If coll and the result are lists then the positions of ## entries do in general not correspond.) ##

-## ## delegates to when ## called with one argument, ## and to resp. when ## called with two arguments. -## The corresponding PreImagesNC delegates to PreImagesRange +## The corresponding PreImagesNC delegates to PreImagesRange ## and PreImagesSetNC. ##

## If the second argument is not an element or a subset of the range of -## the first argument, incorrect results may be returned. -## In order to improve this state of affairs, -## PreImages has been renamed PreImagesNC throughout the library, -## and PreImages has been declared a synonym for PreImagesNC. -##

-## In future versions of &GAP; PreImages -## will perform additional checks and reject invalid inputs. -## These additional checks will slow the computation so, -## when the inputs are known to be valid by construction, -## users are recommended to use PreImagesNC. -##

-## Package authors are asked to convert their methods for -## PreImages to methods for PreImagesNC. -## Only when this has happened will the additional checks be implemented. +## the first argument, incorrect results may be returned. +## In order to improve this state of affairs, +## PreImages has been renamed PreImagesNC throughout the library, +## and PreImages has been declared a synonym for PreImagesNC. +##

+## In future versions of &GAP; PreImages +## will perform additional checks and reject invalid inputs. +## These additional checks will slow the computation so, +## when the inputs are known to be valid by construction, +## users are recommended to use PreImagesNC. +##

+## Package authors are asked to convert their methods for +## PreImages to methods for PreImagesNC. +## Only when this has happened will the additional checks be implemented. ## ## ## <#/GAPDoc> ## DeclareGlobalFunction( "PreImagesNC" ); -DeclareSynonym( "PreImages", PreImagesNC ); - +DeclareSynonym( "PreImages", PreImagesNC ); ############################################################################# diff --git a/lib/mapping.gi b/lib/mapping.gi index 99beb95a48..26b3d63855 100644 --- a/lib/mapping.gi +++ b/lib/mapping.gi @@ -297,11 +297,11 @@ end ); ############################################################################# ## -#F PreImages() +#F PreImages() #F PreImagesNC() . . . set of preimages of the range of a gen. mapping -#F PreImages(,) +#F PreImages(,) #F PreImagesNC(,) set of preimages of an elm under a gen. mapping -#F PreImages(,) +#F PreImages(,) #F PreImagesNC(,) set of preimages of a coll. under a gen. mapping ## InstallGlobalFunction( PreImagesNC, function ( arg ) @@ -1178,11 +1178,11 @@ InstallMethod( PreImagesRange, ## FamRangeEqFamElm, ## [ IsSPGeneralMapping, IsObject ], 0, ## function( map, elm ) -## test will be included at a later stage of the change of name -## if not elm in Image( map ) then -## return fail; -## fi; -## return PreImagesRepresentativeNC( map, elm ); +## test will be included at a later stage of the change of name +## if not elm in Image( map ) then +## return fail; +## fi; +## return PreImagesRepresentativeNC( map, elm ); ## end ); InstallMethod( PreImagesRepresentativeNC, @@ -1203,12 +1203,12 @@ InstallMethod( PreImagesRepresentativeNC, ## "for total non-s.p. general mapping, and element", ## FamRangeEqFamElm, ## [ IsNonSPGeneralMapping, IsObject ], 0, -## function( map, elm ) -## test will be included at a later stage of the change of name -## if not elm in Image( map ) then -## return fail; -## fi; -## return PreImagesRepresentativeNC( map, elm ); +## function( map, elm ) +## test will be included at a later stage of the change of name +## if not elm in Image( map ) then +## return fail; +## fi; +## return PreImagesRepresentativeNC( map, elm ); ## end ); InstallMethod( PreImagesRepresentativeNC, diff --git a/lib/mapprep.gi b/lib/mapprep.gi index 0c106745f3..b118d11ff7 100644 --- a/lib/mapprep.gi +++ b/lib/mapprep.gi @@ -1067,7 +1067,7 @@ InstallMethod( PreImagesElmNC, ############################################################################# ## -#M PreImagesSetNC( , ) . for inverse mapping and collection +#M PreImagesSetNC( , ) . . for inverse mapping and collection ## InstallMethod( PreImagesSetNC, "for an inverse mapping and a collection", @@ -1293,7 +1293,7 @@ InstallMethod( PreImageElm, ############################################################################# ## -#M PreImagesElmNC( , ) . . . for identity mapping and element +#M PreImagesElmNC( , ) . . . . for identity mapping and element ## InstallMethod( PreImagesElmNC, "for identity mapping and object", @@ -1581,7 +1581,7 @@ InstallMethod( ImagesRepresentative, ############################################################################# ## -#M PreImagesElmNC( , ) . . . . for zero mapping and element +#M PreImagesElmNC( , ) . . . . . for zero mapping and element ## InstallMethod( PreImagesElmNC, "for zero mapping and object", @@ -1817,7 +1817,7 @@ end ); ############################################################################# ## -#M PreImagesElmNC( , ) . . . . . . . . . . for restricted mapping +#M PreImagesElmNC( , ) . . . . . . . . . for restricted mapping ## InstallMethod( PreImagesElmNC, "for a restricted mapping, and an element", @@ -1836,7 +1836,7 @@ end ); ############################################################################# ## -#M PreImagesSetNC( , ) . . . . . . . . . . for restricted mapping +#M PreImagesSetNC( , ) . . . . . . . . . for restricted mapping ## InstallMethod( PreImagesSetNC, "for a restricted mapping, and a collection", diff --git a/lib/oprt.gi b/lib/oprt.gi index 2ae61ce158..214948dcfa 100644 --- a/lib/oprt.gi +++ b/lib/oprt.gi @@ -3415,27 +3415,6 @@ end ); ## #M PreImagesRepresentativeNC( , ) . . . . . . . . . build matrix ## -##<<<< fixed a clash with #6232 (12/5/26)? -##<< InstallMethod( PreImagesRepresentativeNC,"IsProjectiveActionHomomorphism", -## The idea is as follows. -## We have an $F$-basis $(v_1, \ldots, v_n)$. -## The matrix $M \in GL(n, F)$ acts first by right multiplication, -## let $w_i = v_i M$. -## Due to the projective action, we know only the normed vectors $c_i w_i$, -## where $c_i \in F \setminus \{ 0 \}$. -## The data computed by 'LinearActionBasis' (if its result is not 'fail') -## provide a vector $v = \sum_i a_i v_i$ such that all $a_i \not= 0$, -## and we know the normed vector $c w$ where $w = v M$ and $c \in F$. -## -## We can compute the decomposition $c w = \sum_i b_i (c_i w_i)$, -## and get $\sum_i b_i (c_i w_i) = c v M = c \sum_i a_i w_i$, -## which means $c_i = c a_i/b_i$ for all $i$. -## Thus we can reconstruct the matrix $M$ up to the scalar factor $c$. -## -## In the cases that are supported, either $c$ is irrelevant because the -## matrix group contains all scalar matrices, or we know that the preimage -## has determinant $1$ and taking the root in question is unique. -## ## The idea is as follows. ## We have an $F$-basis $(v_1, \ldots, v_n)$. ## The matrix $M \in GL(n, F)$ acts first by right multiplication, @@ -3456,7 +3435,6 @@ end ); ## has determinant $1$ and taking the root in question is unique. ## InstallMethod( PreImagesRepresentative,"IsProjectiveActionHomomorphism", -#### >>>>>>> aa52ee29a (Add `RandomMatrix`, .... (#6232)) FamRangeEqFamElm, [ IsProjectiveActionHomomorphism, IsPerm ], 0, function( hom, elm ) local V, G, Grep, mat, xset,lab,dim,sol,i; diff --git a/lib/relation.gi b/lib/relation.gi index b1b0981dec..4bdac46e50 100644 --- a/lib/relation.gi +++ b/lib/relation.gi @@ -1781,7 +1781,7 @@ InstallMethod( ImagesRepresentative, "equivalence relations", ############################################################################# ## -#M PreImagesRepresentativeNC( , ) . . . for equivalence relations +#M PreImagesRepresentativeNC( , ) . . for equivalence relations ## InstallMethod( PreImagesRepresentativeNC, "equivalence relations", FamRangeEqFamElm, [IsEquivalenceRelation, IsObject], 0, From 12ccf30e4fd458de2da4fcaf61e81e43b19baab2 Mon Sep 17 00:00:00 2001 From: Chris Wensley Date: Wed, 28 Sep 2022 18:24:11 +0100 Subject: [PATCH 222/234] replaced PreImRep by PreImRepNC in files from a... to g... --- lib/alglie.gi | 22 +- lib/autsr.gi | 232 +++++----- lib/clashom.gi | 1163 ++++++++++++++++++++++++----------------------- lib/ctblsolv.gi | 12 +- lib/fitfree.gi | 6 +- lib/gpfpiso.gi | 53 ++- lib/gprd.gi | 16 +- lib/grp.gi | 3 +- lib/grpcompl.gi | 7 +- lib/grpfp.gi | 28 +- lib/grplatt.gi | 58 +-- lib/grpnice.gi | 4 +- lib/grppcaut.gi | 4 +- lib/grppcext.gi | 28 +- lib/grppclat.gi | 8 +- 15 files changed, 824 insertions(+), 820 deletions(-) diff --git a/lib/alglie.gi b/lib/alglie.gi index 361811bc61..db14f21dae 100644 --- a/lib/alglie.gi +++ b/lib/alglie.gi @@ -2091,9 +2091,9 @@ InstallMethod( DirectSumDecomposition, SetCentre( Q, Q ); SetRadicalOfAlgebra( Q, Subalgebra( Q, [ Zero( Q ) ] ) ); - id:= List( CentralIdempotentsOfAlgebra( Q ), + id:= List( CentralIdempotentsOfAlgebra( Q ), x->PreImagesRepresentativeNC(hom,x)); - + # Now we lift the idempotents to the big algebra `A'. The # first idempotent is lifted as follows: # We have that `id[1]^2-id[1]' is an element of `Rad'. @@ -5592,7 +5592,7 @@ InstallMethod( JenningsLieAlgebra, T:= EmptySCTable( dim , Zero(F) , "antisymmetric" ); pimgs := []; for i in [1..dim] do - a:= PreImagesRepresentativeNC( Homs[pos[i]] , + a:= PreImagesRepresentativeNC( Homs[pos[i]] , PreImagesRepresentativeNC( hom_pcg[pos[i]], gens[i] ) ); # calculate the p-th power image of `a': @@ -5610,10 +5610,10 @@ InstallMethod( JenningsLieAlgebra, # Calculate the commutator [a,b], and map the result into # the correct homogeneous component. - b:= PreImagesRepresentativeNC( Homs[pos[j]], + b:= PreImagesRepresentativeNC( Homs[pos[j]], PreImagesRepresentativeNC( hom_pcg[pos[j]], gens[j] )); - c:= Image( hom_pcg[pos[i] + pos[j]], - Image(Homs[pos[i] + pos[j]], a^-1*b^-1*a*b) ); + c:= Image( hom_pcg[pos[i] + pos[j]], + Image(Homs[pos[i] + pos[j]], a^-1*b^-1*a*b) ); e:= ExtRepOfObj(c); co:=[]; for k in [1,3..Length(e)-1] do @@ -5788,7 +5788,7 @@ InstallMethod( PCentralLieAlgebra, T:= EmptySCTable( dim , Zero(F) , "antisymmetric" ); pimgs := []; for i in [1..dim] do - a:= PreImagesRepresentativeNC( Homs[pos[i]] , + a:= PreImagesRepresentativeNC( Homs[pos[i]] , PreImagesRepresentativeNC( hom_pcg[pos[i]], gens[i] ) ); @@ -5807,10 +5807,10 @@ InstallMethod( PCentralLieAlgebra, # Calculate the commutator [a,b], and map the result into # the correct homogeneous component. - b:= PreImagesRepresentativeNC( Homs[pos[j]], - PreImagesRepresentativeNC( hom_pcg[pos[j]], gens[j] )); - c:= Image( hom_pcg[pos[i] + pos[j]], - Image(Homs[pos[i] + pos[j]], a^-1*b^-1*a*b) ); + b:= PreImagesRepresentativeNC( Homs[pos[j]], + PreImagesRepresentativeNC( hom_pcg[pos[j]], gens[j] )); + c:= Image( hom_pcg[pos[i] + pos[j]], + Image(Homs[pos[i] + pos[j]], a^-1*b^-1*a*b) ); e:= ExtRepOfObj(c); co:=[]; for k in [1,3..Length(e)-1] do diff --git a/lib/autsr.gi b/lib/autsr.gi index 704f9093dc..705e1daca8 100644 --- a/lib/autsr.gi +++ b/lib/autsr.gi @@ -141,7 +141,7 @@ local ocr,fphom,fpg,free,len,dim,tmp,L0,R,rels,mat,r,RS,i,g,v,cnt; fpg:=FreeGeneratorsOfFpGroup(Range(fphom)); ocr.factorpres:=[fpg,RelatorsOfFpGroup(Range(fphom))]; ocr.generators:=List(GeneratorsOfGroup(Range(fphom)), - i->PreImagesRepresentativeNC(fphom,i)); + i->PreImagesRepresentativeNC(fphom,i)); OCAddMatrices(ocr,ocr.generators); OCAddRelations(ocr,ocr.generators); OCAddSumMatrices(ocr,ocr.generators); @@ -487,7 +487,7 @@ local S,c,hom,q,a,b,i,t,have,ups,new,u,good,abort,clim,worked,pp, cnt:=0; for b in t do new:=PreImagesRepresentativeNC(hom,b); - if (pp=false or new^pp in S) and locond(new) then + if (pp=false or new^pp in S) and locond(new) then S:=ClosureGroup(S,new); have:=true; cnt:=cnt+1; @@ -1024,31 +1024,39 @@ local ff,r,d,ser,u,v,i,j,k,p,bd,e,gens,lhom,M,N,hom,Q,Mim,q,ocr,split,MPcgs, ocr:=OneCocycles(Q,Mim); split:=ocr.isSplitExtension; if not split then - # test: Semisimple and Frattini - b:=MTX.BasisRadical(mo); - fratsim:=Length(b)=0; - if not fratsim then - b:=List(b,x->PreImagesRepresentativeNC(hom,PcElementByExponents(MPcgs,x))); - for j in b do - N:=ClosureSubgroup(N,b); - od; - # insert in series - for j in [Length(ser),Length(ser)-1..i+1] do - ser[j+1]:=ser[j]; - od; - ser[i+1]:=N; - Info(InfoMorph,2,"insert1"); - else - # Frattini? - fratsim:=IsSubset(FrattiniSubgroup(Q),Mim); - if not fratsim then - N:=Intersection(FrattiniSubgroup(Q),Mim); - # insert - for j in [Length(ser),Length(ser)-1..i+1] do - ser[j+1]:=ser[j]; - od; - ser[i+1]:=PreImage(hom,N); - Info(InfoMorph,2,"insert2"); + # test: Semisimple and Frattini + b:=MTX.BasisRadical(mo); + fratsim:=Length(b)=0; + if not fratsim then + b:=List(b,x->PreImagesRepresentativeNC(hom,PcElementByExponents(MPcgs,x))); + for j in b do + N:=ClosureSubgroup(N,b); + od; + # insert + for j in [Length(ser),Length(ser)-1..i+1] do + ser[j+1]:=ser[j]; + od; + ser[i+1]:=N; + Info(InfoMorph,2,"insert1"); + else + # Frattini? + fratsim:=IsSubset(FrattiniSubgroup(Q),Mim); + if not fratsim then + N:=Intersection(FrattiniSubgroup(Q),Mim); + # insert + for j in [Length(ser),Length(ser)-1..i+1] do + ser[j+1]:=ser[j]; + od; + ser[i+1]:=PreImage(hom,N); + Info(InfoMorph,2,"insert2"); + fi; + N:=ser[i+1]; # the added normal + if rada<>fail + and ForAny(GeneratorsOfGroup(rada),x->N<>Image(x,N)) then + Info(InfoMorph,3,"radical automorphism stabilizer"); + SetIsGroupOfAutomorphismsFiniteGroup(rada,true); + NiceMonomorphism(rada:autactbase:=fail,someCharacteristics:=fail); + rada:=Stabilizer(rada,N,asAutom); fi; N:=ser[i+1]; # the added normal fi; @@ -1127,11 +1135,11 @@ local ff,r,d,ser,u,v,i,j,k,p,bd,e,gens,lhom,M,N,hom,Q,Mim,q,ocr,split,MPcgs, cond:=function(perm) local aut,newgens,mo2,iso,a; if perm in Aperm then - return true; - fi; + return true; + fi; aut:=PreImagesRepresentativeNC(AQiso,perm); - newgens:=List(gens,x->PreImagesRepresentativeNC(comiso, - ImagesRepresentative(aut,ImagesRepresentative(comiso,x)))); + newgens:=List(gens,x->PreImagesRepresentativeNC(comiso, + ImagesRepresentative(aut,ImagesRepresentative(comiso,x)))); mo2:=GModuleByMats(LinearActionLayer(newgens,MPcgs),mo.field); iso:=MTX.IsomorphismModules(mo,mo2); @@ -1161,11 +1169,11 @@ local ff,r,d,ser,u,v,i,j,k,p,bd,e,gens,lhom,M,N,hom,Q,Mim,q,ocr,split,MPcgs, precond:=function(perm) local aut,newgens,mo2; if perm in Aperm then - return true; - fi; + return true; + fi; aut:=PreImagesRepresentativeNC(AQiso,perm); - newgens:=List(GeneratorsOfGroup(Q), - x->PreImagesRepresentativeNC(q,Image(aut,ImagesRepresentative(q,x)))); + newgens:=List(GeneratorsOfGroup(Q), + x->PreImagesRepresentativeNC(q,Image(aut,ImagesRepresentative(q,x)))); mo2:=GModuleByMats(LinearActionLayer(newgens,MPcgs),mo.field); return MTX.IsomorphismModules(mo,mo2)<>fail; end; @@ -1173,11 +1181,11 @@ local ff,r,d,ser,u,v,i,j,k,p,bd,e,gens,lhom,M,N,hom,Q,Mim,q,ocr,split,MPcgs, cond:=function(perm) local aut,newgens,mo2,iso,a; if perm in Aperm then - return true; - fi; + return true; + fi; aut:=PreImagesRepresentativeNC(AQiso,perm); - newgens:=List(GeneratorsOfGroup(Q), - x->PreImagesRepresentativeNC(q,Image(aut,ImagesRepresentative(q,x)))); + newgens:=List(GeneratorsOfGroup(Q), + x->PreImagesRepresentativeNC(q,Image(aut,ImagesRepresentative(q,x)))); mo2:=GModuleByMats(LinearActionLayer(newgens,MPcgs),mo.field); iso:=MTX.IsomorphismModules(mo,mo2); if iso=fail then @@ -1365,10 +1373,10 @@ local ff,r,d,ser,u,v,i,j,k,p,bd,e,gens,lhom,M,N,hom,Q,Mim,q,ocr,split,MPcgs, for j in GeneratorsOfGroup(rada) do k:=GroupHomomorphismByImagesNC(rf,rf, GeneratorsOfGroup(rf), - List(GeneratorsOfGroup(rf), - y->ImagesRepresentative(hom,ImagesRepresentative(j, - PreImagesRepresentativeNC(hom,y))))); - Assert(2,IsBijective(k)); + List(GeneratorsOfGroup(rf), + y->ImagesRepresentative(hom,ImagesRepresentative(j, + PreImagesRepresentativeNC(hom,y))))); + Assert(2,IsBijective(k)); Add(ind,k); od; @@ -1387,81 +1395,81 @@ local ff,r,d,ser,u,v,i,j,k,p,bd,e,gens,lhom,M,N,hom,Q,Mim,q,ocr,split,MPcgs, # reduce to subgroup that induces valid automorphisms Info(InfoMorph,1,"Radical autos reduce by factor ",Size(res)/Size(ind)); resperm:=IsomorphismPermGroup(C); - proj:=GroupHomomorphismByImagesNC(AQP,Image(resperm), - B[2],List(GeneratorsOfGroup(res),x->ImagesRepresentative(resperm,x))); - C:=PreImage(proj,Image(resperm,ind)); - C:=List(SmallGeneratingSet(C),x->PreImagesRepresentativeNC(AQiso,x)); - AQ:=Group(C); - SetIsFinite(AQ,true); - SetIsGroupOfAutomorphismsFiniteGroup(AQ,true); + proj:=GroupHomomorphismByImagesNC(AQP,Image(resperm), + B[2],List(GeneratorsOfGroup(res),x->ImagesRepresentative(resperm,x))); + C:=PreImage(proj,Image(resperm,ind)); + C:=List(SmallGeneratingSet(C),x->PreImagesRepresentativeNC(AQiso,x)); + AQ:=Group(C); + SetIsFinite(AQ,true); + SetIsGroupOfAutomorphismsFiniteGroup(AQ,true); makeaqiso(); fi; # # hook for using existing characteristics to reduce for next step if somechar<>fail then u:=Filtered(Unique(List(somechar,x->Image(hom,x))),x->Size(x)>1); - u:=Filtered(u,s->ForAny(GeneratorsOfGroup(AQ),h->Image(h,s)<>s)); - SortBy(u,Size); - Info(InfoMorph,1,"Forced characteristics ",List(u,Size)); - - if scharorb<>fail then - # these are subgroups for which certain orbits must be stabilized. - C:=List(Reversed(scharorb),x->List(x,y->Image(hom,y))); - C:=Filtered(C,x->Size(x[1])>1 and Size(x[1])Size(x[1]))); - Append(u,C); - fi; - - if Length(u)>0 then - C:=MappingGeneratorsImages(AQiso); - if C[2]<>GeneratorsOfGroup(AQP) then - C:=[List(GeneratorsOfGroup(AQP), - x->PreImagesRepresentativeNC(AQiso,x)), - GeneratorsOfGroup(AQP)]; - fi; - for j in u do - if IsList(j) then - # stabilizer set of subgroups - jorb:=ShallowCopy(Orbit(AQP,j[1],C[2],C[1],asAutom)); - jorpo:=[Position(jorb,j[1]),Position(jorb,j[2])]; - if jorpo[2]=fail then - Append(jorb,Orbit(AQP,j[1],C[2],C[1],asAutom)); - jorpo[2]:=Position(jorb,j[2]); - fi; - if Length(jorb)>Length(j) then - B:=ActionHomomorphism(AQP,jorb,C[2],C[1],asAutom); - substb:=Group(List(C[2],x->ImagesRepresentative(B,x)),()); - substb:=Stabilizer(substb,Set(jorpo),OnSets); - substb:=PreImage(B,substb); - Info(InfoMorph,2,"Stabilize characteristic orbit ",Size(j[1]), - " :",Size(AQP)/Size(substb) ); - else - substb:=AQP; - fi; - - - else - substb:=Stabilizer(AQP,j,C[2],C[1],asAutom); - Info(InfoMorph,2,"Stabilize characteristic subgroup ",Size(j), - " :",Size(AQP)/Size(substb) ); - fi; - if Size(substb)PreImagesRepresentativeNC(AQiso,x)),substb]; - fi; - - od; - AQ:=Group(C[1]); - SetIsFinite(AQ,true); - SetIsGroupOfAutomorphismsFiniteGroup(AQ,true); - SetSize(AQ,Size(AQP)); - #AQP:=Group(C[2]); # ensure small gen set - #SetSize(AQP,Size(AQ)); - makeaqiso(); - fi; + u:=Filtered(u,s->ForAny(GeneratorsOfGroup(AQ),h->Image(h,s)<>s)); + SortBy(u,Size); + Info(InfoMorph,1,"Forced characteristics ",List(u,Size)); + + if scharorb<>fail then + # these are subgroups for which certain orbits must be stabilized. + C:=List(Reversed(scharorb),x->List(x,y->Image(hom,y))); + C:=Filtered(C,x->Size(x[1])>1 and Size(x[1])Size(x[1]))); + Append(u,C); + fi; + + if Length(u)>0 then + C:=MappingGeneratorsImages(AQiso); + if C[2]<>GeneratorsOfGroup(AQP) then + C:=[List(GeneratorsOfGroup(AQP), + x->PreImagesRepresentativeNC(AQiso,x)), + GeneratorsOfGroup(AQP)]; + fi; + for j in u do + if IsList(j) then + # stabilizer set of subgroups + jorb:=ShallowCopy(Orbit(AQP,j[1],C[2],C[1],asAutom)); + jorpo:=[Position(jorb,j[1]),Position(jorb,j[2])]; + if jorpo[2]=fail then + Append(jorb,Orbit(AQP,j[1],C[2],C[1],asAutom)); + jorpo[2]:=Position(jorb,j[2]); + fi; + if Length(jorb)>Length(j) then + B:=ActionHomomorphism(AQP,jorb,C[2],C[1],asAutom); + substb:=Group(List(C[2],x->ImagesRepresentative(B,x)),()); + substb:=Stabilizer(substb,Set(jorpo),OnSets); + substb:=PreImage(B,substb); + Info(InfoMorph,2,"Stabilize characteristic orbit ",Size(j[1]), + " :",Size(AQP)/Size(substb) ); + else + substb:=AQP; + fi; + + + else + substb:=Stabilizer(AQP,j,C[2],C[1],asAutom); + Info(InfoMorph,2,"Stabilize characteristic subgroup ",Size(j), + " :",Size(AQP)/Size(substb) ); + fi; + if Size(substb)PreImagesRepresentativeNC(AQiso,x)),substb]; + fi; + + od; + AQ:=Group(C[1]); + SetIsFinite(AQ,true); + SetIsGroupOfAutomorphismsFiniteGroup(AQ,true); + SetSize(AQ,Size(AQP)); + #AQP:=Group(C[2]); # ensure small gen set + #SetSize(AQP,Size(AQ)); + makeaqiso(); + fi; fi; lastperm:=AQiso; diff --git a/lib/clashom.gi b/lib/clashom.gi index b3e09fa718..3ae0a9f30f 100644 --- a/lib/clashom.gi +++ b/lib/clashom.gi @@ -544,134 +544,134 @@ local clT, # classes T end; for j in [1..Length(reps)] do - scj:=Size(centralizers[j]); - dsz:=0; - centrhom:=ActionHomomorphism(centralizers_r[j],components[i], - "surjective"); - localcent_r:=Image(centrhom); - Info(InfoHomClass,4,i,":",j); - Info(InfoHomClass,3,"acting: ",Size(centralizers[j])," minimum ", - Int(Size(Image(projections[i]))/Size(centralizers[j])), - " orbits."); - # compute C(r)-classes - clTR:=[]; - for l in clT do - Info(InfoHomClass,4,"DC",Index(T,l[2])," ",Index(T,localcent_r)); - dc:=DoubleCosetRepsAndSizes(T,l[2],localcent_r); - clTR:=Concatenation(clTR,List(dc,i->l[1]^i[1])); - od; - - orb:=[]; - for p in [1..Length(clTR)] do - - repres:=PreImagesRepresentativeNC(projections[i],clTR[p]); - if i=1 or isdirprod - or reps[j]*RestrictedPermNC(repres,components[i]) - in Mproj[i] then - stab:=Centralizer(localcent_r,clTR[p]); - if Index(localcent_r,stab)clTR[p] then - genpos:=Position(img,clTR[p]); - img:=Permuted(img,(1,genpos)); - fi; - else - img:=ConjugacyClass(localcent_r,clTR[p],stab); - fi; - Add(orb,[repres,PreImage(centrhom,stab),img,localcent_r]); - fi; - od; - clTR:=orb; - - #was: - #clTR:=List(clTR,i->ConjugacyClass(localcent_r,i)); - #clTR:=List(clTR,j->[PreImagesRepresentative(projections[i], - # Representative(j)), - # PreImage(centrhom,Centralizer(j)), - # j]); - - # put small classes to the top (to be sure to hit them and make - # large local stabilizers) - SortBy(clTR,x->Size(x[3])); - - Info(InfoHomClass,3,Length(clTR)," local classes"); - - cystr:=[]; - for p in [1..Length(clTR)] do - repres:=Immutable(CycleStructurePerm(Representative(clTR[p][3]))); - select:=First(cystr,x->x[1]=repres); - if select=fail then - Add(cystr,[repres,[p]]); - else - AddSet(select[2],p); - fi; - od; - - cengen:=GeneratorsOfGroup(centralizers[j]); - if Length(cengen)>10 then - cengen:=SmallGeneratingSet(centralizers[j]); - fi; - #cengen:=Filtered(cengen,i->not i in localcent_r); - - while Length(clTR)>0 do - - # orbit algorithm on classes - stab:=clTR[1][2]; - orb:=[clTR[1]]; - #repres:=RestrictedPermNC(clTR[1][1],components[i]); - repres:=clTR[1][1]; - trans:=[One(M)]; - select:=[2..Length(clTR)]; - - orpo:=1; - minlen:=Size(orb[1][3]); - possible:=false; - stabtrue:=false; - pf:=infinity; - maxdiff:=Size(T); - again:=0; - trymap:=false; - ug:=[]; - # test whether we have full orbit and full stabilizer - while Size(centralizers[j])>(Sum(orb,i->Size(i[3]))*Size(stab)) do - genpos:=1; - while genpos<=Length(cengen) and - Size(centralizers[j])>(Sum(orb,i->Size(i[3]))*Size(stab)) do - gen:=cengen[genpos]; - skip:=false; - if trymap<>false then - orpo:=trymap[1]; - gen:=trymap[2]; - trymap:=false; - elif again>0 then - if not IsBound(ug[genpos]) then - ug[genpos]:=Intersection(centralizers_r[j], - ConjugateSubgroup(centralizers_r[j],gen^-1)); - fi; - if again<500 and ForAll(GeneratorsOfGroup(centralizers_r[j]), - i->i in ug[genpos]) - then - # the random elements will give us nothing new - skip:=true; - else - # get an element not in ug[genpos] - repeat - img:=Random(centralizers_r[j]); - until not img in ug[genpos] or again>=500; - gen:=img*gen; - fi; - fi; - - if not skip then - - img:=Image(projections[i],opfun(orb[orpo][1],gen)); - - smacla:=select; - - if not stabtrue then - p:=PositionProperty(orb,i->img in i[3]); - ppos:=fail; + scj:=Size(centralizers[j]); + dsz:=0; + centrhom:=ActionHomomorphism(centralizers_r[j],components[i], + "surjective"); + localcent_r:=Image(centrhom); + Info(InfoHomClass,4,i,":",j); + Info(InfoHomClass,3,"acting: ",Size(centralizers[j])," minimum ", + Int(Size(Image(projections[i]))/Size(centralizers[j])), + " orbits."); + # compute C(r)-classes + clTR:=[]; + for l in clT do + Info(InfoHomClass,4,"DC",Index(T,l[2])," ",Index(T,localcent_r)); + dc:=DoubleCosetRepsAndSizes(T,l[2],localcent_r); + clTR:=Concatenation(clTR,List(dc,i->l[1]^i[1])); + od; + + orb:=[]; + for p in [1..Length(clTR)] do + + repres:=PreImagesRepresentativeNC(projections[i],clTR[p]); + if i=1 or isdirprod + or reps[j]*RestrictedPermNC(repres,components[i]) + in Mproj[i] then + stab:=Centralizer(localcent_r,clTR[p]); + if Index(localcent_r,stab)clTR[p] then + genpos:=Position(img,clTR[p]); + img:=Permuted(img,(1,genpos)); + fi; + else + img:=ConjugacyClass(localcent_r,clTR[p],stab); + fi; + Add(orb,[repres,PreImage(centrhom,stab),img,localcent_r]); + fi; + od; + clTR:=orb; + + #was: + #clTR:=List(clTR,i->ConjugacyClass(localcent_r,i)); + #clTR:=List(clTR,j->[PreImagesRepresentative(projections[i], + # Representative(j)), + # PreImage(centrhom,Centralizer(j)), + # j]); + + # put small classes to the top (to be sure to hit them and make + # large local stabilizers) + SortBy(clTR,x->Size(x[3])); + + Info(InfoHomClass,3,Length(clTR)," local classes"); + + cystr:=[]; + for p in [1..Length(clTR)] do + repres:=Immutable(CycleStructurePerm(Representative(clTR[p][3]))); + select:=First(cystr,x->x[1]=repres); + if select=fail then + Add(cystr,[repres,[p]]); + else + AddSet(select[2],p); + fi; + od; + + cengen:=GeneratorsOfGroup(centralizers[j]); + if Length(cengen)>10 then + cengen:=SmallGeneratingSet(centralizers[j]); + fi; + #cengen:=Filtered(cengen,i->not i in localcent_r); + + while Length(clTR)>0 do + + # orbit algorithm on classes + stab:=clTR[1][2]; + orb:=[clTR[1]]; + #repres:=RestrictedPermNC(clTR[1][1],components[i]); + repres:=clTR[1][1]; + trans:=[One(M)]; + select:=[2..Length(clTR)]; + + orpo:=1; + minlen:=Size(orb[1][3]); + possible:=false; + stabtrue:=false; + pf:=infinity; + maxdiff:=Size(T); + again:=0; + trymap:=false; + ug:=[]; + # test whether we have full orbit and full stabilizer + while Size(centralizers[j])>(Sum(orb,i->Size(i[3]))*Size(stab)) do + genpos:=1; + while genpos<=Length(cengen) and + Size(centralizers[j])>(Sum(orb,i->Size(i[3]))*Size(stab)) do + gen:=cengen[genpos]; + skip:=false; + if trymap<>false then + orpo:=trymap[1]; + gen:=trymap[2]; + trymap:=false; + elif again>0 then + if not IsBound(ug[genpos]) then + ug[genpos]:=Intersection(centralizers_r[j], + ConjugateSubgroup(centralizers_r[j],gen^-1)); + fi; + if again<500 and ForAll(GeneratorsOfGroup(centralizers_r[j]), + i->i in ug[genpos]) + then + # the random elements will give us nothing new + skip:=true; + else + # get an element not in ug[genpos] + repeat + img:=Random(centralizers_r[j]); + until not img in ug[genpos] or again>=500; + gen:=img*gen; + fi; + fi; + + if not skip then + + img:=Image(projections[i],opfun(orb[orpo][1],gen)); + + smacla:=select; + + if not stabtrue then + p:=PositionProperty(orb,i->img in i[3]); + ppos:=fail; else # we have the stabilizer and thus are only interested in # getting new elements. @@ -694,50 +694,50 @@ local clT, # classes T return fail; fi; else - p:=ppos; - fi; - - RemoveSet(select,p); - Add(orb,clTR[p]); - - if trans[orpo]=false then - Add(trans,false); - else - #change the transversal element to map to the representative - con:=trans[orpo]*gen; - limg:=opfun(repres,con); - con:=con*PreImagesRepresentativeNC(centrhom, - RepresentativeAction(localcent_r, - Image(projections[i],limg), - Representative(clTR[p][3]))); - Assert(2,Image(projections[i],opfun(repres,con)) - =Representative(clTR[p][3])); - - Add(trans,con); - - for stgen in GeneratorsOfGroup(clTR[p][2]) do - Assert( 2, IsOne( Image( projections[i], - opfun(repres,con*stgen/con)/repres ) ) ); - stab:=ClosureGroup(stab,con*stgen/con); - od; - fi; - - # compute new minimum length - - if Length(select)>0 then - remainlen:=List(clTR{select},i->Size(i[3])); - gcd:=Gcd(remainlen); - diff:=minlen-Sum(orb,i->Size(i[3])); - - if diff<0 then - # only go through this if the orbit actually grew - # larger - minlen:=Sum(orb,i->Size(i[3])); - repeat - if dsz=0 then - dsz:=DivisorsInt(scj); - fi; - while not minlen in dsz do + p:=ppos; + fi; + + RemoveSet(select,p); + Add(orb,clTR[p]); + + if trans[orpo]=false then + Add(trans,false); + else + #change the transversal element to map to the representative + con:=trans[orpo]*gen; + limg:=opfun(repres,con); + con:=con*PreImagesRepresentativeNC(centrhom, + RepresentativeAction(localcent_r, + Image(projections[i],limg), + Representative(clTR[p][3]))); + Assert(2,Image(projections[i],opfun(repres,con)) + =Representative(clTR[p][3])); + + Add(trans,con); + + for stgen in GeneratorsOfGroup(clTR[p][2]) do + Assert( 2, IsOne( Image( projections[i], + opfun(repres,con*stgen/con)/repres ) ) ); + stab:=ClosureGroup(stab,con*stgen/con); + od; + fi; + + # compute new minimum length + + if Length(select)>0 then + remainlen:=List(clTR{select},i->Size(i[3])); + gcd:=Gcd(remainlen); + diff:=minlen-Sum(orb,i->Size(i[3])); + + if diff<0 then + # only go through this if the orbit actually grew + # larger + minlen:=Sum(orb,i->Size(i[3])); + repeat + if dsz=0 then + dsz:=DivisorsInt(scj); + fi; + while not minlen in dsz do # workaround rare problem -- try again if First(dsz,i->i>=minlen)=fail then return ConjugacyClassesSubwreath( @@ -790,149 +790,149 @@ local clT, # classes T stabtrue:=true; fi; - elif not stabtrue then - # we have an element that stabilizes the conjugacy class. - # correct this to an element that fixes the representative. - # (As we have taken already the centralizer in - # centralizers_r, it is sufficient to correct by - # centralizers_r-conjugation.) - con:=trans[orpo]*gen; - limg:=opfun(repres,con); - con:=con*PreImagesRepresentativeNC(centrhom, - RepresentativeAction(localcent_r, - Image(projections[i],limg), - Representative(orb[p][3]))); - stab:=ClosureGroup(stab,con/trans[p]); - if Size(stab)*2*minlen>Size(centralizers[j]) then - Info(InfoHomClass,3, - "true stabilizer found (cannot grow)"); - minlen:=Size(centralizers[j])/Size(stab); - maxdiff:=minlen-Sum(orb,i->Size(i[3])); - stabtrue:=true; - fi; - fi; - - if stabtrue then - - smacla:=Filtered(select,i->Size(clTR[i][3])<=maxdiff); - - if Length(smacla)Size(i[3])); - - CompletionBar(InfoHomClass,3,"trueorb ",1-maxdiff/minlen); - #Info(InfoHomClass,3, - # "This is the true orbit length (missing ", - # maxdiff,")"); - - if Size(stab)*Sum(orb,i->Size(i[3])) - =Size(centralizers[j]) then + elif not stabtrue then + # we have an element that stabilizes the conjugacy class. + # correct this to an element that fixes the representative. + # (As we have taken already the centralizer in + # centralizers_r, it is sufficient to correct by + # centralizers_r-conjugation.) + con:=trans[orpo]*gen; + limg:=opfun(repres,con); + con:=con*PreImagesRepresentativeNC(centrhom, + RepresentativeAction(localcent_r, + Image(projections[i],limg), + Representative(orb[p][3]))); + stab:=ClosureGroup(stab,con/trans[p]); + if Size(stab)*2*minlen>Size(centralizers[j]) then + Info(InfoHomClass,3, + "true stabilizer found (cannot grow)"); + minlen:=Size(centralizers[j])/Size(stab); + maxdiff:=minlen-Sum(orb,i->Size(i[3])); + stabtrue:=true; + fi; + fi; + + if stabtrue then + + smacla:=Filtered(select,i->Size(clTR[i][3])<=maxdiff); + + if Length(smacla)Size(i[3])); + + CompletionBar(InfoHomClass,3,"trueorb ",1-maxdiff/minlen); + #Info(InfoHomClass,3, + # "This is the true orbit length (missing ", + # maxdiff,")"); + + if Size(stab)*Sum(orb,i->Size(i[3])) + =Size(centralizers[j]) then maxdiff:=0; - elif Sum(remainlen)=maxdiff then - Info(InfoHomClass,2, - "Full possible remainder must fuse"); - orb:=Concatenation(orb,clTR{smacla}); - select:=Difference(select,smacla); - - else - # test whether there is only one possibility to get - # this length - if Length(smacla)<20 and - Sum(List([1..Minimum(Length(smacla), - Int(maxdiff/gcd+1))], - x-> NrCombinations(smacla,x)))<10000 then - # get all reasonable combinations - smare:=[1..Length(smacla)]; #range for smacla - combl:=Concatenation(List([1..Int(maxdiff/gcd+1)], - i->Combinations(smare,i))); - # pick those that have the correct length - combl:=Filtered(combl,i->Sum(remainlen{i})=maxdiff); - if Length(combl)>1 then - Info(InfoHomClass,3,"Addendum not unique (", - Length(combl)," possibilities)"); - if (maxdiff<10 or again>0) - and ForAll(combl,i->Length(i)<=5) then - # we have tried often enough, now try to pick the - # right ones - possible:=false; - combl:=Union(combl); - combl:=smacla{combl}; - genpos2:=1; - smacla:=[]; - while possible=false and Length(combl)>0 do - img:=Image(projections[i], - opfun(clTR[combl[1]][1],cengen[genpos2])); - p:=PositionProperty(orb,i->img in i[3]); - if p<>fail then - # it is! - Info(InfoHomClass,4,"got one!"); - - # remember the element to try - trymap:=[p,(cengen[genpos2]* - PreImagesRepresentativeNC( - RestrictedMapping(projections[i], - centralizers[j]), - RepresentativeAction( - orb[p][4], - img,Representative(orb[p][3])) ))^-1]; - - Add(smacla,combl[1]); - combl:=combl{[2..Length(combl)]}; - if Sum(clTR{smacla},i->Size(i[3]))=maxdiff then - # bingo! - possible:=true; - fi; - fi; - genpos2:=genpos2+1; - if genpos2>Length(cengen) then - genpos2:=1; - combl:=combl{[2..Length(combl)]}; - fi; - od; - if possible=false then - Info(InfoHomClass,4,"Even test failed!"); - else - orb:=Concatenation(orb,clTR{smacla}); - select:=Difference(select,smacla); - Info(InfoHomClass,3,"Completed orbit (hard)"); - fi; - fi; - elif Length(combl)>0 then - combl:=combl[1]; - orb:=Concatenation(orb,clTR{smacla{combl}}); - select:=Difference(select,smacla{combl}); - Info(InfoHomClass,3,"Completed orbit"); - fi; - fi; - fi; - fi; - - fi; - else - Info(InfoHomClass,5,"skip"); - fi; # if not skip - - genpos:=genpos+1; - od; - orpo:=orpo+1; - if orpo>Length(orb) then - Info(InfoHomClass,3,"Size factor:",EvalF( - (Sum(orb,i->Size(i[3]))*Size(stab))/Size(centralizers[j])), - " orbit consists of ",Length(orb)," suborbits, iterating"); - - if stabtrue then - pper:=false; - # we know stabilizer, just need to find orbit. As these are - # likely small additions, search in reverse. - for p in select do - for genpos in [1..Length(cengen)] do - gen:=Random(centralizers_r[j])*cengen[genpos]; - img:=Image(projections[i],opfun(clTR[p][1],gen)); - orpo:=CycleStructurePerm(img); - ppos:=First(First(cystr,x->x[1]=orpo)[2], - i->not i in select and - img in clTR[i][3]); + elif Sum(remainlen)=maxdiff then + Info(InfoHomClass,2, + "Full possible remainder must fuse"); + orb:=Concatenation(orb,clTR{smacla}); + select:=Difference(select,smacla); + + else + # test whether there is only one possibility to get + # this length + if Length(smacla)<20 and + Sum(List([1..Minimum(Length(smacla), + Int(maxdiff/gcd+1))], + x-> NrCombinations(smacla,x)))<10000 then + # get all reasonable combinations + smare:=[1..Length(smacla)]; #range for smacla + combl:=Concatenation(List([1..Int(maxdiff/gcd+1)], + i->Combinations(smare,i))); + # pick those that have the correct length + combl:=Filtered(combl,i->Sum(remainlen{i})=maxdiff); + if Length(combl)>1 then + Info(InfoHomClass,3,"Addendum not unique (", + Length(combl)," possibilities)"); + if (maxdiff<10 or again>0) + and ForAll(combl,i->Length(i)<=5) then + # we have tried often enough, now try to pick the + # right ones + possible:=false; + combl:=Union(combl); + combl:=smacla{combl}; + genpos2:=1; + smacla:=[]; + while possible=false and Length(combl)>0 do + img:=Image(projections[i], + opfun(clTR[combl[1]][1],cengen[genpos2])); + p:=PositionProperty(orb,i->img in i[3]); + if p<>fail then + # it is! + Info(InfoHomClass,4,"got one!"); + + # remember the element to try + trymap:=[p,(cengen[genpos2]* + PreImagesRepresentativeNC( + RestrictedMapping(projections[i], + centralizers[j]), + RepresentativeAction( + orb[p][4], + img,Representative(orb[p][3])) ))^-1]; + + Add(smacla,combl[1]); + combl:=combl{[2..Length(combl)]}; + if Sum(clTR{smacla},i->Size(i[3]))=maxdiff then + # bingo! + possible:=true; + fi; + fi; + genpos2:=genpos2+1; + if genpos2>Length(cengen) then + genpos2:=1; + combl:=combl{[2..Length(combl)]}; + fi; + od; + if possible=false then + Info(InfoHomClass,4,"Even test failed!"); + else + orb:=Concatenation(orb,clTR{smacla}); + select:=Difference(select,smacla); + Info(InfoHomClass,3,"Completed orbit (hard)"); + fi; + fi; + elif Length(combl)>0 then + combl:=combl[1]; + orb:=Concatenation(orb,clTR{smacla{combl}}); + select:=Difference(select,smacla{combl}); + Info(InfoHomClass,3,"Completed orbit"); + fi; + fi; + fi; + fi; + + fi; + else + Info(InfoHomClass,5,"skip"); + fi; # if not skip + + genpos:=genpos+1; + od; + orpo:=orpo+1; + if orpo>Length(orb) then + Info(InfoHomClass,3,"Size factor:",EvalF( + (Sum(orb,i->Size(i[3]))*Size(stab))/Size(centralizers[j])), + " orbit consists of ",Length(orb)," suborbits, iterating"); + + if stabtrue then + pper:=false; + # we know stabilizer, just need to find orbit. As these are + # likely small additions, search in reverse. + for p in select do + for genpos in [1..Length(cengen)] do + gen:=Random(centralizers_r[j])*cengen[genpos]; + img:=Image(projections[i],opfun(clTR[p][1],gen)); + orpo:=CycleStructurePerm(img); + ppos:=First(First(cystr,x->x[1]=orpo)[2], + i->not i in select and + img in clTR[i][3]); if ppos<>fail and p in select then # so the image is in clTR[ppos] which must be in orb ppos:=Position(orb,clTR[ppos]); @@ -1141,8 +1141,7 @@ local cs, # chief series of G hom:=NaturalHomomorphismByNormalSubgroupNC(G,lastM); cl:=ConjugacyClasses(Image(hom)); cl:=List(cl,i->[PreImagesRepresentativeNC(hom,Representative(i)), - PreImage(hom,StabilizerOfExternalSet(i))]); - cs:=Concatenation([G],Filtered(cs,x->IsSubset(lastM,x))); + PreImage(hom,StabilizerOfExternalSet(i))]); fi; for i in [2..Length(cs)] do @@ -1183,144 +1182,146 @@ local cs, # chief series of G if IsNormal(G,subN) then - # only one -> Call standard process - - Fhom:=fail; - # is this an almost top factor? - if Index(G,M)<10 then - Thom:=NaturalHomomorphismByNormalSubgroupNC(G,subN); - T1:=Image(Thom,M); - S1:=Image(Thom); - if Size(Centralizer(S1,T1))=1 then - deg1:=NrMovedPoints(S1); - Info(InfoHomClass,2, - "top factor gives conjugating representation, deg ",deg1); - - Fhom:=Thom; - fi; - else - Thom:=NaturalHomomorphismByNormalSubgroupNC(M,subN); - T1:=Image(Thom,M); - fi; - - if Fhom=fail then - autos:=List(GeneratorsOfGroup(G), - i->GroupHomomorphismByImagesNC(T1,T1,GeneratorsOfGroup(T1), - List(GeneratorsOfGroup(T1), - j->Image(Thom,PreImagesRepresentativeNC(Thom,j)^i)))); - - # find (probably another) permutation rep for T1 for which all - # automorphisms can be represented by permutations - arhom:=AutomorphismRepresentingGroup(T1,autos); - S1:=arhom[1]; - deg1:=NrMovedPoints(S1); - Fhom:=GroupHomomorphismByImagesNC(G,S1,GeneratorsOfGroup(G),arhom[3]); - fi; - - - F:=Image(Fhom,G); - - clF:=ClassesFromClassical(F); - if clF=fail then - clF:=ConjugacyClassesByRandomSearch(F); - fi; - - clF:=List(clF,j->[Representative(j),StabilizerOfExternalSet(j)]); + # only one -> Call standard process + + Fhom:=fail; + # is this an almost top factor? + if Index(G,M)<10 then + Thom:=NaturalHomomorphismByNormalSubgroupNC(G,subN); + T1:=Image(Thom,M); + S1:=Image(Thom); + if Size(Centralizer(S1,T1))=1 then + deg1:=NrMovedPoints(S1); + Info(InfoHomClass,2, + "top factor gives conjugating representation, deg ",deg1); + + Fhom:=Thom; + fi; + else + Thom:=NaturalHomomorphismByNormalSubgroupNC(M,subN); + T1:=Image(Thom,M); + fi; + + if Fhom=fail then + autos:=List(GeneratorsOfGroup(G), + i->GroupHomomorphismByImagesNC(T1,T1,GeneratorsOfGroup(T1), + List(GeneratorsOfGroup(T1), + j->Image(Thom,PreImagesRepresentativeNC(Thom,j)^i)))); + + # find (probably another) permutation rep for T1 for which all + # automorphisms can be represented by permutations + arhom:=AutomorphismRepresentingGroup(T1,autos); + S1:=arhom[1]; + deg1:=NrMovedPoints(S1); + Fhom:=GroupHomomorphismByImagesNC(G,S1,GeneratorsOfGroup(G),arhom[3]); + fi; + + + C:=KernelOfMultiplicativeGeneralMapping(Fhom); + F:=Image(Fhom,G); + + clF:=ClassesFromClassical(F); + if clF=fail then + clF:=ConjugacyClassesByRandomSearch(F); + fi; + + clF:=List(clF,j->[Representative(j),StabilizerOfExternalSet(j)]); else - csM:=Orbit(G,subN); # all conjugates - n:=Length(csM); - - if n=1 then - Error("this cannot happen"); - T:=M; - fi; - - T:=Intersection(csM{[2..Length(csM)]}); # one T_i - if Length(GeneratorsOfGroup(T))>5 then - T:=Group(SmallGeneratingSet(T)); - fi; - - T:=Orbit(G,T); # get all the t's - # now T[1] is a complement to csM[1] in G/N. - - # now compute the operation of G on M/N - Qhom:=ActionHomomorphism(G,T,"surjective"); - Q:=Image(Qhom,G); - S:=PreImage(Qhom,Stabilizer(Q,1)); - - # find a permutation rep. for S-action on T[1] - Thom:=NaturalHomomorphismByNormalSubgroupNC(T[1],N); - T1:=Image(Thom); - if not IsSubset([1..NrMovedPoints(T1)], - MovedPoints(T1)) then - Thom:=Thom*ActionHomomorphism(T1,MovedPoints(T1),"surjective"); - fi; - T1:=Image(Thom,T[1]); - if IsPermGroup(T1) and - NrMovedPoints(T1)>SufficientlySmallDegreeSimpleGroupOrder(Size(T1)) then - Thom:=Thom*SmallerDegreePermutationRepresentation(T1:cheap); - Info(InfoHomClass,1,"reduced simple degree ",NrMovedPoints(T1), - " ",NrMovedPoints(Image(Thom))); - T1:=Image(Thom,T[1]); - fi; - - autos:=List(GeneratorsOfGroup(S), - i->GroupHomomorphismByImagesNC(T1,T1,GeneratorsOfGroup(T1), - List(GeneratorsOfGroup(T1), - j->Image(Thom,PreImagesRepresentativeNC(Thom,j)^i)))); - - # find (probably another) permutation rep for T1 for which all - # automorphisms can be represented by permutations - arhom:=AutomorphismRepresentingGroup(T1,autos); - S1:=arhom[1]; - deg1:=NrMovedPoints(S1); - Thom:=GroupHomomorphismByImagesNC(S,S1,GeneratorsOfGroup(S),arhom[3]); - - T1:=Image(Thom,T[1]); - - # now embed into wreath - w:=WreathProduct(S1,Q); - wbas:=DirectProduct(List([1..n],i->S1)); - emb:=List([1..n+1],i->Embedding(w,i)); - proj:=List([1..n],i->Projection(wbas,i)); - components:=WreathProductInfo(w).components; - - # define isomorphisms between the components - reps:=List([1..n],i-> - PreImagesRepresentativeNC(Qhom,RepresentativeAction(Q,1,i))); - - genimages:=[]; - for j in GeneratorsOfGroup(G) do - img:=Image(Qhom,j); - gimg:=Image(emb[n+1],img); - for k in [1..n] do - # look at part of j's action on the k-th factor. - # we get this by looking at the action of - # reps[k] * j * reps[k^img]^-1 - # 1 -> k -> k^img -> 1 - # on the first component. - act:=reps[k]*j*(reps[k^img]^-1); - # this must be multiplied *before* permuting - gimg:=ImageElm(emb[k],ImageElm(Thom,act))*gimg; - gimg:=RestrictedPermNC(gimg,MovedPoints(w)); - od; - Add(genimages,gimg); - od; - - F:=Subgroup(w,genimages); - if AssertionLevel()>=2 then - Fhom:=GroupHomomorphismByImages(G,F,GeneratorsOfGroup(G),genimages); - Assert(1,fail<>Fhom); - else - Fhom:=GroupHomomorphismByImagesNC(G,F,GeneratorsOfGroup(G),genimages); - fi; - - Info(InfoHomClass,1,"constructed Fhom"); - - # 2) compute the classes for F - - if n>1 then + csM:=Orbit(G,subN); # all conjugates + n:=Length(csM); + + if n=1 then + Error("this cannot happen"); + T:=M; + fi; + + T:=Intersection(csM{[2..Length(csM)]}); # one T_i + if Length(GeneratorsOfGroup(T))>5 then + T:=Group(SmallGeneratingSet(T)); + fi; + + T:=Orbit(G,T); # get all the t's + # now T[1] is a complement to csM[1] in G/N. + + # now compute the operation of G on M/N + Qhom:=ActionHomomorphism(G,T,"surjective"); + Q:=Image(Qhom,G); + S:=PreImage(Qhom,Stabilizer(Q,1)); + + # find a permutation rep. for S-action on T[1] + Thom:=NaturalHomomorphismByNormalSubgroupNC(T[1],N); + T1:=Image(Thom); + if not IsSubset([1..NrMovedPoints(T1)], + MovedPoints(T1)) then + Thom:=Thom*ActionHomomorphism(T1,MovedPoints(T1),"surjective"); + fi; + T1:=Image(Thom,T[1]); + if IsPermGroup(T1) and + NrMovedPoints(T1)>SufficientlySmallDegreeSimpleGroupOrder(Size(T1)) then + Thom:=Thom*SmallerDegreePermutationRepresentation(T1:cheap); + Info(InfoHomClass,1,"reduced simple degree ",NrMovedPoints(T1), + " ",NrMovedPoints(Image(Thom))); + T1:=Image(Thom,T[1]); + fi; + + autos:=List(GeneratorsOfGroup(S), + i->GroupHomomorphismByImagesNC(T1,T1,GeneratorsOfGroup(T1), + List(GeneratorsOfGroup(T1), + j->Image(Thom,PreImagesRepresentativeNC(Thom,j)^i)))); + + # find (probably another) permutation rep for T1 for which all + # automorphisms can be represented by permutations + arhom:=AutomorphismRepresentingGroup(T1,autos); + S1:=arhom[1]; + deg1:=NrMovedPoints(S1); + Thom:=GroupHomomorphismByImagesNC(S,S1,GeneratorsOfGroup(S),arhom[3]); + + T1:=Image(Thom,T[1]); + + # now embed into wreath + w:=WreathProduct(S1,Q); + wbas:=DirectProduct(List([1..n],i->S1)); + emb:=List([1..n+1],i->Embedding(w,i)); + proj:=List([1..n],i->Projection(wbas,i)); + components:=WreathProductInfo(w).components; + + # define isomorphisms between the components + reps:=List([1..n],i-> + PreImagesRepresentativeNC(Qhom,RepresentativeAction(Q,1,i))); + + genimages:=[]; + for j in GeneratorsOfGroup(G) do + img:=Image(Qhom,j); + gimg:=Image(emb[n+1],img); + for k in [1..n] do + # look at part of j's action on the k-th factor. + # we get this by looking at the action of + # reps[k] * j * reps[k^img]^-1 + # 1 -> k -> k^img -> 1 + # on the first component. + act:=reps[k]*j*(reps[k^img]^-1); + # this must be multiplied *before* permuting + gimg:=ImageElm(emb[k],ImageElm(Thom,act))*gimg; + gimg:=RestrictedPermNC(gimg,MovedPoints(w)); + od; + Add(genimages,gimg); + od; + + F:=Subgroup(w,genimages); + if AssertionLevel()>=2 then + Fhom:=GroupHomomorphismByImages(G,F,GeneratorsOfGroup(G),genimages); + Assert(1,fail<>Fhom); + else + Fhom:=GroupHomomorphismByImagesNC(G,F,GeneratorsOfGroup(G),genimages); + fi; + C:=KernelOfMultiplicativeGeneralMapping(Fhom); + + Info(InfoHomClass,1,"constructed Fhom"); + + # 2) compute the classes for F + + if n>1 then #if IsPermGroup(F) and NrMovedPoints(F)<18 then # # the old Butler/Theissen approach is still OK # clF:=[]; @@ -1337,30 +1338,30 @@ local cs, # chief series of G clF:=ConjugacyClassesSubwreath(F,FM,n,S1, Action(FM,components[1]),T1,components,emb,proj); if clF=fail then - #Error("failure"); - # weird error happened -- redo - j:=Random(SymmetricGroup(MovedPoints(G))); - FM:=List(GeneratorsOfGroup(G),x->x^j); - F:=Group(FM); - SetSize(F,Size(G)); - FM:=GroupHomomorphismByImagesNC(G,F,GeneratorsOfGroup(G),FM); - clF:=ConjugacyClassesFittingFreeGroup(F); - clF:=List(clF,x->[PreImagesRepresentativeNC(FM,x[1]),PreImage(FM,x[2])]); - return clF; - fi; - #fi; - else - FM:=Image(Fhom,M); - Info(InfoHomClass,1, - "classes by random search in almost simple group"); - - clF:=ClassesFromClassical(F); - if clF=fail then - clF:=ConjugacyClassesByRandomSearch(F); - fi; - - clF:=List(clF,j->[Representative(j),StabilizerOfExternalSet(j)]); - fi; + #Error("failer"); + # weird error happened -- redo + j:=Random(SymmetricGroup(MovedPoints(G))); + FM:=List(GeneratorsOfGroup(G),x->x^j); + F:=Group(FM); + SetSize(F,Size(G)); + FM:=GroupHomomorphismByImagesNC(G,F,GeneratorsOfGroup(G),FM); + clF:=ConjugacyClassesFittingFreeGroup(F); + clF:=List(clF,x->[PreImagesRepresentativeNC(FM,x[1]),PreImage(FM,x[2])]); + return clF; + fi; + #fi; + else + FM:=Image(Fhom,M); + Info(InfoHomClass,1, + "classes by random search in almost simple group"); + + clF:=ClassesFromClassical(F); + if clF=fail then + clF:=ConjugacyClassesByRandomSearch(F); + fi; + + clF:=List(clF,j->[Representative(j),StabilizerOfExternalSet(j)]); + fi; fi; # true orbit of T. Assert(2,Sum(clF,i->Index(F,i[2]))=Size(F)); @@ -1371,106 +1372,106 @@ local cs, # chief series of G # the length(cl)=1 gets rid of solvable stuff on the top we got ``too # early''. if IsSubgroup(N,KernelOfMultiplicativeGeneralMapping(Fhom)) then - Info(InfoHomClass,1, - "homomorphism is faithful for relevant factor, take preimages"); - if Size(N)=1 and onlysizes=true then - cl:=List(clF,i->[PreImagesRepresentativeNC(Fhom,i[1]),Size(i[2])]); - else - cl:=List(clF,i->[PreImagesRepresentativeNC(Fhom,i[1]), - PreImage(Fhom,i[2])]); + Info(InfoHomClass,1, + "homomorphism is faithful for relevant factor, take preimages"); + if Size(N)=1 and onlysizes=true then + cl:=List(clF,i->[PreImagesRepresentativeNC(Fhom,i[1]),Size(i[2])]); + else + cl:=List(clF,i->[PreImagesRepresentativeNC(Fhom,i[1]), + PreImage(Fhom,i[2])]); fi; else - Info(InfoHomClass,1,"forming subdirect products"); - - FM:=Image(Fhom,lastM); - FMhom:=RestrictedMapping(Fhom,lastM); - if Index(F,FM)=1 then - Info(InfoHomClass,1,"degenerated to direct product"); - ncl:=[]; - for j in cl do - for k in clF do - # modify the representative with a kernel elm. to project - # correctly on the second component - elm:=j[1]*PreImagesRepresentativeNC(FMhom, - LeftQuotient(Image(Fhom,j[1]),k[1])); - zentr:=Intersection(j[2],PreImage(Fhom,k[2])); - Assert(3,ForAll(GeneratorsOfGroup(zentr), - i->Comm(i,elm) in N)); - Add(ncl,[elm,zentr]); - od; - od; - - cl:=ncl; - - else - - # first we add the centralizer closures and sort by them - # (this allows to reduce the number of double coset calculations) - ncl:=[]; - for j in cl do - Cim:=Image(Fhom,j[2]); - CimCl:=Cim; - #CimCl:=ClosureGroup(FM,Cim); # should be unnecessary, as we took - # the full preimage - p:=PositionProperty(ncl,i->i[1]=CimCl); - if p=fail then - Add(ncl,[CimCl,[j]]); - else - Add(ncl[p][2],j); - fi; - od; - - Qhom:=NaturalHomomorphismByNormalSubgroupNC(F,FM); - Q:=Image(Qhom); - FQhom:=Fhom*Qhom; - - # now construct the sdp's - cl:=[]; - for j in ncl do - lj:=List(j[2],i->Image(FQhom,i[1])); - for k in clF do - # test whether the classes are potential mates - elm:=Image(Qhom,k[1]); - if not ForAll(lj,i->RepresentativeAction(Q,i,elm)=fail) then - - #l:=Image(Fhom,j[1]); - - if Index(F,j[1])=1 then - dc:=[()]; - else - dc:=List(DoubleCosetRepsAndSizes(F,k[2],j[1]),i->i[1]); - fi; - good:=0; - bad:=0; - for l in j[2] do - jim:=Image(FQhom,l[1]); - for l1 in dc do - elm:=k[1]^l1; - if Image(Qhom,elm)=jim then - # modify the representative with a kernel elm. to project - # correctly on the second component - elm:=l[1]*PreImagesRepresentativeNC(FMhom, - LeftQuotient(Image(Fhom,l[1]),elm)); - zentr:=PreImage(Fhom,k[2]^l1); - zentr:=Intersection(zentr,l[2]); - - Assert(3,ForAll(GeneratorsOfGroup(zentr), - i->Comm(i,elm) in N)); - - Info(InfoHomClass,4,"new class, order ",Order(elm), - ", size=",Index(G,zentr)); - Add(cl,[elm,zentr]); - good:=good+1; - else - Info(InfoHomClass,5,"not in"); - bad:=bad+1; - fi; - od; - od; - Info(InfoHomClass,4,good," good, ",bad," bad of ",Length(dc)); - fi; - od; - od; + Info(InfoHomClass,1,"forming subdirect products"); + + FM:=Image(Fhom,lastM); + FMhom:=RestrictedMapping(Fhom,lastM); + if Index(F,FM)=1 then + Info(InfoHomClass,1,"degenerated to direct product"); + ncl:=[]; + for j in cl do + for k in clF do + # modify the representative with a kernel elm. to project + # correctly on the second component + elm:=j[1]*PreImagesRepresentativeNC(FMhom, + LeftQuotient(Image(Fhom,j[1]),k[1])); + zentr:=Intersection(j[2],PreImage(Fhom,k[2])); + Assert(3,ForAll(GeneratorsOfGroup(zentr), + i->Comm(i,elm) in N)); + Add(ncl,[elm,zentr]); + od; + od; + + cl:=ncl; + + else + + # first we add the centralizer closures and sort by them + # (this allows to reduce the number of double coset calculations) + ncl:=[]; + for j in cl do + Cim:=Image(Fhom,j[2]); + CimCl:=Cim; + #CimCl:=ClosureGroup(FM,Cim); # should be unnecessary, as we took + # the full preimage + p:=PositionProperty(ncl,i->i[1]=CimCl); + if p=fail then + Add(ncl,[CimCl,[j]]); + else + Add(ncl[p][2],j); + fi; + od; + + Qhom:=NaturalHomomorphismByNormalSubgroupNC(F,FM); + Q:=Image(Qhom); + FQhom:=Fhom*Qhom; + + # now construct the sdp's + cl:=[]; + for j in ncl do + lj:=List(j[2],i->Image(FQhom,i[1])); + for k in clF do + # test whether the classes are potential mates + elm:=Image(Qhom,k[1]); + if not ForAll(lj,i->RepresentativeAction(Q,i,elm)=fail) then + + #l:=Image(Fhom,j[1]); + + if Index(F,j[1])=1 then + dc:=[()]; + else + dc:=List(DoubleCosetRepsAndSizes(F,k[2],j[1]),i->i[1]); + fi; + good:=0; + bad:=0; + for l in j[2] do + jim:=Image(FQhom,l[1]); + for l1 in dc do + elm:=k[1]^l1; + if Image(Qhom,elm)=jim then + # modify the representative with a kernel elm. to project + # correctly on the second component + elm:=l[1]*PreImagesRepresentativeNC(FMhom, + LeftQuotient(Image(Fhom,l[1]),elm)); + zentr:=PreImage(Fhom,k[2]^l1); + zentr:=Intersection(zentr,l[2]); + + Assert(3,ForAll(GeneratorsOfGroup(zentr), + i->Comm(i,elm) in N)); + + Info(InfoHomClass,4,"new class, order ",Order(elm), + ", size=",Index(G,zentr)); + Add(cl,[elm,zentr]); + good:=good+1; + else + Info(InfoHomClass,5,"not in"); + bad:=bad+1; + fi; + od; + od; + Info(InfoHomClass,4,good," good, ",bad," bad of ",Length(dc)); + fi; + od; + od; fi; # real subdirect product fi; # else Fhom not faithful on factor @@ -2398,12 +2399,12 @@ local r, #radical if ntrihom then ncl:=[]; for i in cl do - new:=[PreImagesRepresentativeNC(hom,i[1])]; - if not IsInt(i[2]) then - Add(new,[]); # no generators in radical yet - gens:=SmallGeneratingSet(i[2]); - Add(new, - List(gens,x->PreImagesRepresentativeNC(hom,x))); + new:=[PreImagesRepresentativeNC(hom,i[1])]; + if not IsInt(i[2]) then + Add(new,[]); # no generators in radical yet + gens:=SmallGeneratingSet(i[2]); + Add(new, + List(gens,x->PreImagesRepresentativeNC(hom,x))); Add(new,gens); #TODO: PreImage groups? #Add(new,PreImage(hom,i[2])); @@ -2886,7 +2887,7 @@ local r, #radical fi; prereps:=f!.classpreimgs; if not IsBound(prereps[j]) then - prereps[j]:=PreImagesRepresentativeNC(hom,Representative(cl[j])); + prereps[j]:=PreImagesRepresentativeNC(hom,Representative(cl[j])); fi; r:=PreImagesRepresentativeNC(hom,conj); @@ -2898,7 +2899,7 @@ local r, #radical # 6:cenfac, 7:cenfacimgs, 8:censize, 9:cenfacsize Add(nreps,[i,i^r,prereps[j],r,[], List(d,x->PreImagesRepresentativeNC(hom,x)),d, - radsize*Size(Centralizer(cl[j])), Size(Centralizer(cl[j]))]); + radsize*Size(Centralizer(cl[j])), Size(Centralizer(cl[j]))]); od; reps:=nreps; diff --git a/lib/ctblsolv.gi b/lib/ctblsolv.gi index 9dbf4b116e..13a762c9b5 100644 --- a/lib/ctblsolv.gi +++ b/lib/ctblsolv.gi @@ -582,8 +582,8 @@ InstallGlobalFunction( CoveringTriplesCharacters, function( G, z ) h:= NaturalHomomorphismByNormalSubgroupNC( G, P ); r:= List( CoveringTriplesCharacters( ImagesSource( h ), ImageElm( h, z ) ), - x -> [ PreImagesSetNC( h, x[1] ), - PreImagesSetNC( h, x[2] ), + x -> [ PreImagesSet( h, x[1] ), + PreImagesSet( h, x[2] ), PreImagesRepresentativeNC( h, x[3] ) ] ); if p = i then @@ -622,8 +622,8 @@ InstallGlobalFunction( CoveringTriplesCharacters, function( G, z ) c:= Stabilizer( img, zn ); fi; Append( r, List( CoveringTriplesCharacters( c, zn ), - x -> [ PreImagesSetNC( h, x[1] ), - PreImagesSetNC( h, x[2] ), + x -> [ PreImagesSet( h, x[1] ), + PreImagesSet( h, x[2] ), PreImagesRepresentativeNC( h, x[3] ) ] ) ); od; return r; @@ -663,8 +663,8 @@ InstallGlobalFunction( CoveringTriplesCharacters, function( G, z ) img:= ImagesSource( h ); Append( r, List( CoveringTriplesCharacters( img, ImageElm( h, z ) ), - x -> [ PreImagesSetNC( h, x[1] ), - PreImagesSetNC( h, x[2] ), + x -> [ PreImagesSet( h, x[1] ), + PreImagesSet( h, x[2] ), PreImagesRepresentativeNC( h, x[3] ) ] ) ); fi; od; diff --git a/lib/fitfree.gi b/lib/fitfree.gi index 4aa31f6be6..0989708dc1 100644 --- a/lib/fitfree.gi +++ b/lib/fitfree.gi @@ -1195,9 +1195,9 @@ local s,d,c,act,o,i,j,h,p,hf,img,n,k,ns,all,hl,hcomp, norm:=n); for j in [2..Length(i)] do c[i[j]]:=rec(orbit:=i,orbitpos:=j, - rep:=PreImagesRepresentativeNC(act, - RepresentativeAction(Image(act),i[1],i[j])), - component:=d[i[j]],hall:=h, norm:=n); + rep:=PreImagesRepresentativeNC(act, + RepresentativeAction(Image(act),i[1],i[j])), + component:=d[i[j]],hall:=h, norm:=n); od; od; diff --git a/lib/gpfpiso.gi b/lib/gpfpiso.gi index f50ea53b1d..618aa7ab9b 100644 --- a/lib/gpfpiso.gi +++ b/lib/gpfpiso.gi @@ -90,10 +90,10 @@ local l,iso,fp,stbc,gens; if iso<>fail then fp:=IsomorphismFpGroup(l); iso:=GroupHomomorphismByImagesNC(G,Range(fp), - List(MappingGeneratorsImages(fp)[1], - i->PreImagesRepresentativeNC(iso,i)), - MappingGeneratorsImages(fp)[2]); - SetIsBijective(iso,true); + List(MappingGeneratorsImages(fp)[1], + i->PreImagesRepresentativeNC(iso,i)), + MappingGeneratorsImages(fp)[2]); + SetIsBijective(iso,true); return iso; fi; od; @@ -166,12 +166,12 @@ function( G, str ) # 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->PreImagesRepresentativeNC(new,i)); + # compute presentation of H + IsNonabelianSimpleGroup(H); + IsNaturalAlternatingGroup(H); + new:=IsomorphismFpGroup(H,"@"); + gensH:=List(GeneratorsOfGroup(Image(new)), + i->PreImagesRepresentativeNC(new,i)); preiH := List( gensH, x -> PreImagesRepresentativeNC( hom, x ) ); c := Length( gensH ); @@ -396,8 +396,8 @@ function(g,str,N) # calculate automorphisms of f induced by G fgens:=GeneratorsOfGroup(f); auts:=List(GeneratorsOfGroup(g),i-> - GroupHomomorphismByImagesNC(f,f,fgens, - List(fgens,j->Image(hom,PreImagesRepresentativeNC(hom,j)^i)):noassert)); + GroupHomomorphismByImagesNC(f,f,fgens, + List(fgens,j->Image(hom,PreImagesRepresentativeNC(hom,j)^i)):noassert)); for j in auts do SetIsBijective(j,true); od; @@ -426,8 +426,7 @@ function(g,str,N) else a:=IsomorphismFpGroup(sf:noassert); fi; - ad:=List(GeneratorsOfGroup(Range(a)), - i->PreImagesRepresentativeNC(a,i)); + ad:=List(GeneratorsOfGroup(Range(a)),i->PreImagesRepresentativeNC(a,i)); lad:=Length(ad); n:=Length(orb); @@ -1321,8 +1320,7 @@ 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->PreImagesRepresentativeNC(iso,x))<>pcgs then + if List(GeneratorsOfGroup(fp),x->PreImagesRepresentativeNC(iso,x))<>pcgs then Error("pcgs"); fi; gens:=[]; @@ -1730,8 +1728,7 @@ local isob,isos,iso,gens,a,rels,l,i,j,bgens,cb,cs,b,f,k,w,monoid, # 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->PreImagesRepresentativeNC(pciso, - PreImagesRepresentativeNC(cb.fphom,x))); + x->PreImagesRepresentativeNC(pciso,PreImagesRepresentativeNC(cb.fphom,x))); b:=Range(isob); @@ -1969,9 +1966,8 @@ local isob,isos,iso,gens,a,rels,l,i,j,bgens,cb,cs,b,f,k,w,monoid, a:=Group(SmallGeneratingSet(group)); # so nothing stores csetperm:=List(GeneratorsOfGroup(a),x->Permutation(x,rt,OnRight)); iso:=EpimorphismFromFreeGroup(a); - csetperm:=List(bgens,x->MappedWord(PreImagesRepresentativeNC(iso,x), - MappingGeneratorsImages(iso)[1],csetperm)); - act:=Group(csetperm,()); + borela:=List(bgens,x->MappedWord(PreImagesRepresentativeNC(iso,x),MappingGeneratorsImages(iso)[1],borela)); + act:=Group(borela,()); bhom:=GroupHomomorphismByImagesNC(borel,act,bgens,csetperm); #Assert(0,bhom<>fail); @@ -2058,11 +2054,14 @@ local isob,isos,iso,gens,a,rels,l,i,j,bgens,cb,cs,b,f,k,w,monoid, 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]; + #pos:=PositionProperty(dc,y->elm in y); + pos:=rti[PositionCanonical(rt,elm)]; + #rep:=RepresentativeAction(borel,PositionCanonical(rt,elm), + # PositionCanonical(rt,dcreps[pos]),bgens,borela,OnPoints); + rep:=PreImagesRepresentativeNC(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; @@ -2687,7 +2686,7 @@ end); # 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)))); +# PreImagesRepresentativeNC(miso,x)))); # if ForAny(pre,x->Length(x)<>1) then Error("double");fi; # Add(l,Concatenation(pre)); # if IsBound(m!.rewritingSystem) then diff --git a/lib/gprd.gi b/lib/gprd.gi index 49b091d983..c5df0b6f66 100644 --- a/lib/gprd.gi +++ b/lib/gprd.gi @@ -1091,13 +1091,13 @@ local info,map,U,mapfun,P; U:=SubgroupNC(G,info.hgens); fi; map:=GroupHomomorphismByFunction(P,U,mapfun, - function(elm) - elm:=elm![n]; - if n>info.degI then - elm:=PreImagesRepresentativeNC(info.alpha,elm); - fi; - return elm; - end); + function(elm) + elm:=elm![n]; + if n>info.degI then + elm:=PreImagesRepresentativeNC(info.alpha,elm); + fi; + return elm; + end); info.embeddings[n]:=map; fi; return info.embeddings[n]; @@ -1118,7 +1118,7 @@ local info,map,np; map:=GroupHomomorphismByFunction(G,info.groups[2], function(elm) - return PreImagesRepresentativeNC(info.alpha,elm![np]); + return PreImagesRepresentativeNC(info.alpha,elm![np]); end, false, # not bijective function(elm) diff --git a/lib/grp.gi b/lib/grp.gi index ed3ac936cf..27f3644271 100644 --- a/lib/grp.gi +++ b/lib/grp.gi @@ -2091,8 +2091,7 @@ InstallGlobalFunction( SupersolvableResiduumDefault, function( G ) mg:= List( gs, x -> TransposedMat( List( pcgs, y -> one * ExponentsOfPcElement( pcgs, Image( ph, Image( dh, PreImagesRepresentativeNC( - dh, PreImagesRepresentativeNC( - ph,y) )^x ) ) )))^-1); + dh, PreImagesRepresentativeNC(ph,y) )^x ) ) )))^-1); #T inverting is not necessary, or? mg:= Filtered( mg, x -> x <> idm ); diff --git a/lib/grpcompl.gi b/lib/grpcompl.gi index 82acfff647..187222cb0d 100644 --- a/lib/grpcompl.gi +++ b/lib/grpcompl.gi @@ -99,10 +99,9 @@ local G,N,K,s, h, q, fpi, factorpres, com, comgens, cen, ocrels, fpcgs, ncom, Length(MappingGeneratorsImages(fpi)[2])," generators"); factorpres:=[FreeGeneratorsOfFpGroup(Range(fpi)), RelatorsOfFpGroup(Range(fpi)), - List(GeneratorsOfGroup(Range(fpi)), - i->PreImagesRepresentativeNC(fpi,i))]; - Assert(1,ForAll(factorpres[3], - i->Image(h,PreImagesRepresentativeNC(h,i))=i)); + List(GeneratorsOfGroup(Range(fpi)), + i->PreImagesRepresentativeNC(fpi,i))]; + Assert(1,ForAll(factorpres[3],i->Image(h,PreImagesRepresentativeNC(h,i))=i)); # initialize com:=[G]; comgens:=[List(factorpres[3],i->PreImagesRepresentativeNC(h,i))]; diff --git a/lib/grpfp.gi b/lib/grpfp.gi index 0546a1f18a..47c342feb4 100644 --- a/lib/grpfp.gi +++ b/lib/grpfp.gi @@ -5494,10 +5494,10 @@ local G,T,gens,g,reps,ng,index,i,j,ndef,n,iso; IsRightTransversalFpGroupRep and IsList and IsDuplicateFreeList and IsAttributeStoringRep ), rec( group := OG, - subgroup := U, - iso:=iso, - table:=T, - reps:=List(reps,i->PreImagesRepresentativeNC(iso,i)))); + subgroup := U, + iso:=iso, + table:=T, + reps:=List(reps,i->PreImagesRepresentativeNC(iso,i)))); fi; ndef := 1; @@ -5509,16 +5509,16 @@ local G,T,gens,g,reps,ng,index,i,j,ndef,n,iso; #This assumes that reps[j] is already defined - but #this is true because T is 'standardized' ndef := ndef+1; - if ndef=index then - return Objectify( NewType( FamilyObj( OG ), - IsRightTransversalFpGroupRep and IsList and - IsDuplicateFreeList and IsAttributeStoringRep ), - rec( group := OG, - subgroup := U, - iso:=iso, - table:=T, - reps:=List(reps,i->PreImagesRepresentativeNC(iso,i)))); - fi; + if ndef=index then + return Objectify( NewType( FamilyObj( OG ), + IsRightTransversalFpGroupRep and IsList and + IsDuplicateFreeList and IsAttributeStoringRep ), + rec( group := OG, + subgroup := U, + iso:=iso, + table:=T, + reps:=List(reps,i->PreImagesRepresentativeNC(iso,i)))); + fi; fi; od; od; diff --git a/lib/grplatt.gi b/lib/grplatt.gi index 68eea8dd71..9225edfdfa 100644 --- a/lib/grplatt.gi +++ b/lib/grplatt.gi @@ -2780,7 +2780,7 @@ local fgi,inducedfactorautos,projs,psubs,info,n,l,nl,emb,u,pos, auts:=[]; for i in GeneratorsOfGroup(n) do aut:=GroupHomomorphismByImages(f,f,gens,List(gens,x-> - Image(hom,PreImagesRepresentativeNC(hom,x)^i))); + Image(hom,PreImagesRepresentativeNC(hom,x)^i))); SetIsBijective(aut,true); Add(auts,aut); od; @@ -2832,35 +2832,35 @@ local fgi,inducedfactorautos,projs,psubs,info,n,l,nl,emb,u,pos, no:=NormalSubgroups(j[1]); no:=SubgroupsOrbitsAndNormalizers(j[2],no,false); #Print("Try",j," ",Length(no),"\n"); - for k in no do - hom:=NaturalHomomorphismByNormalSubgroup(j[1],k.representative); - f:=Image(hom); - if uselib and Size(f) < 1000 and ID_AVAILABLE(Size(f)) <> fail then - myid:=ShallowCopy(IdGroup(f)); - else - myid:=[Size(f),fail]; - fi; - for s in subs do - for t in s[3] do # look over normals of subgroup + for k in no do + hom:=NaturalHomomorphismByNormalSubgroup(j[1],k.representative); + f:=Image(hom); + if Size(f)<1000 and Size(f)<>512 and uselib then + myid:=ShallowCopy(IdGroup(f)); + else + myid:=[Size(f),fail]; + fi; + for s in subs do + for t in s[3] do # look over normals of subgroup #Print(t,"\n"); - if t{[3,4]}=myid then - if false and myid=[1,1] then - #Print("direct\n"); - g:=Subgroup(D,Concatenation(GeneratorsOfGroup(j[1]),List(GeneratorsOfGroup(s[1]),x->Image(emb,x)))); - Add(nl,[g,Normalizer(D,g)]); - else - iso:=IsomorphismGroups(f,t[6]); - if iso<>fail then - #Found isomorphic factor groups - iso:=hom*iso; - ind:=Subgroup(t[7],inducedfactorautos(k.normalizer,t[6],iso)); - for dc in DoubleCosetRepsAndSizes(t[7],ind,t[8]) do - # form the subdirect product - g:=List(GeneratorsOfGroup(j[1]), - x->x*Image(emb,PreImagesRepresentativeNC(t[5], - Image(dc[1],Image(iso,x))) )); - Append(g,List(GeneratorsOfGroup(t[1]),x->Image(emb,x))); - g:=Subgroup(D,g); + if t{[3,4]}=myid then + if false and myid=[1,1] then + #Print("direct\n"); + g:=Subgroup(D,Concatenation(GeneratorsOfGroup(j[1]),List(GeneratorsOfGroup(s[1]),x->Image(emb,x)))); + Add(nl,[g,Normalizer(D,g)]); + else + iso:=IsomorphismGroups(f,t[6]); + if iso<>fail then + #Found isomorphic factor groups + iso:=hom*iso; + ind:=Subgroup(t[7],inducedfactorautos(k.normalizer,t[6],iso)); + for dc in DoubleCosetRepsAndSizes(t[7],ind,t[8]) do + # form the subdirect product + g:=List(GeneratorsOfGroup(j[1]), + x->x*Image(emb,PreImagesRepresentativeNC(t[5], + Image(dc[1],Image(iso,x))) )); + Append(g,List(GeneratorsOfGroup(t[1]),x->Image(emb,x))); + g:=Subgroup(D,g);>>>>>>> dbb7e8565 (replaced PreImRep by PreImRepNC in files from a... to g...) if Size(g)<>Size(j[1])*Size(s[1])/Size(f) then Error("sudi\n");fi; Add(nl,[g,Normalizer(D,g)]); od; diff --git a/lib/grpnice.gi b/lib/grpnice.gi index 6e3db2bd6f..106afc6a48 100644 --- a/lib/grpnice.gi +++ b/lib/grpnice.gi @@ -284,8 +284,8 @@ function( obj1, obj2 ) img := ImagesRepresentative( nice, obj2:actioncanfail:=true ); if img = fail or not (img in ImagesSource(nice) and - PreImagesRepresentativeNC(nice,img)=obj2) then - TryNextMethod(); + PreImagesRepresentativeNC(nice,img)=obj2) then + TryNextMethod(); fi; no:=NiceObject(obj1); img1 := ClosureGroup( NiceObject(obj1), img ); diff --git a/lib/grppcaut.gi b/lib/grppcaut.gi index 0f3ca0cadc..6a4e5514ed 100644 --- a/lib/grppcaut.gi +++ b/lib/grppcaut.gi @@ -1418,12 +1418,12 @@ InstallGlobalFunction(AutomorphismGroupSolvableGroup,function( G ) hom := ActionHomomorphism( xset, "surjective"); P := Image( hom ); if IsSolvableGroup( P ) then - pcsA := List( Pcgs(P), + pcsA := List( Pcgs(P), x -> PreImagesRepresentativeNC( hom, x )); TransferPcgsInfo( A, pcsA, RelativeOrders( Pcgs(P) ) ); else imgs := SmallGeneratingSet( P ); - gens := List( imgs, + gens := List( imgs, x -> PreImagesRepresentativeNC( hom, x ) ); tmp := Size( A ); A := GroupByGenerators( gens, One( A ) ); diff --git a/lib/grppcext.gi b/lib/grppcext.gi index 7cb594f53d..7bdc1c082d 100644 --- a/lib/grppcext.gi +++ b/lib/grppcext.gi @@ -379,10 +379,10 @@ local ag, p1iso, agp, p2iso, DP, p1, p2, gens, genimgs, triso,s,i,u,opt, genimgs:=List(gens, i->ImagesRepresentative(Embedding(D,1), PreImagesRepresentativeNC(p1iso, - PreImagesRepresentativeNC(pc1,ImagesRepresentative(p1,i)))) - *ImagesRepresentative(Embedding(D,2), - PreImagesRepresentativeNC(p2iso, - PreImagesRepresentativeNC(pc2,ImagesRepresentative(p2,i)))) ); + PreImagesRepresentativeNC(pc1,ImagesRepresentative(p1,i)))) + *ImagesRepresentative(Embedding(D,2), + PreImagesRepresentativeNC(p2iso, + PreImagesRepresentativeNC(pc2,ImagesRepresentative(p2,i)))) ); else opt:=rec(limit:=s,random:=1); @@ -426,9 +426,9 @@ local ag, p1iso, agp, p2iso, DP, p1, p2, gens, genimgs, triso,s,i,u,opt, genimgs:=List(gens, i->ImagesRepresentative(Embedding(D,1), - PreImagesRepresentativeNC(p1iso,ImagesRepresentative(p1,i))) + PreImagesRepresentativeNC(p1iso,ImagesRepresentative(p1,i))) *ImagesRepresentative(Embedding(D,2), - PreImagesRepresentativeNC(p2iso,ImagesRepresentative(p2,i))) ); + PreImagesRepresentativeNC(p2iso,ImagesRepresentative(p2,i))) ); fi; triso:=GroupHomomorphismByImagesNC(DP,D,gens,genimgs); @@ -711,9 +711,9 @@ local G, M, Mgrp, oper, A, B, D, translate, gens, genimgs, triso, K, K1, Assert(1,MappingGeneratorsImages(epi)[2]=Ggens); f:=function( tup, elm ) local gens; - #gens := List( tup[1], x -> PreImagesRepresentative( elm[1], x ) ); + #gens := List( tup[1], x -> PreImagesRepresentativeNC( elm[1], x ) ); #gens := List( gens, x -> MappedPcElement( x, tup[1], tup[2] ) ); - gens := List( Ggens, x->PreImagesRepresentativeNC( elm[1], x ) ); + gens := List( Ggens, x -> PreImagesRepresentativeNC( elm[1], x ) ); gens := List( gens, x -> MappedWord( PreImagesRepresentativeNC(epi,x), GeneratorsOfGroup(Source(epi)), tup ) ); gens := List( gens, x -> x ^ elm[2] ); @@ -730,8 +730,7 @@ local G, M, Mgrp, oper, A, B, D, translate, gens, genimgs, triso, K, K1, elmlist:=[]; tmp:=List(genimgs,x->x[1]); - preimlist:=List(tmp,x->[x,List(Ggens, - y->PreImagesRepresentativeNC(x,y))]); + preimlist:=List(tmp,x->[x,List(Ggens,y->PreImagesRepresentativeNC(x,y))]); f:=function( tup, elm ) local gens,p; @@ -782,8 +781,7 @@ local G, M, Mgrp, oper, A, B, D, translate, gens, genimgs, triso, K, K1, if elmlist<>fail then tmp:=List(genimgs,x->x[1]); - preimlist:=List(tmp,x->[x,List(Ggens, - y->PreImagesRepresentativeNC(x,y))]); + preimlist:=List(tmp,x->[x,List(Ggens,y->PreImagesRepresentativeNC(x,y))]); # ensure we also account for action u:=Group(tup); @@ -1122,7 +1120,7 @@ BindGlobal( "NonSplitExtensions", function( arg ) # if reduction is suppressed elif IsBound( arg[3] ) and not arg[3] then all := NormedRowVectors( Image(cc.cohom) ); - all := List( all, x -> ExtensionSQ(cohom.collector, G, M, + all := List( all, x -> ExtensionSQ(cohom.collector, G, M, PreImagesRepresentativeNC(cc.cohom,x ))); red := false; @@ -1133,7 +1131,7 @@ BindGlobal( "NonSplitExtensions", function( arg ) and not HasAutomorphismGroup( G ) then all := NormedRowVectors( Image(cc.cohom) ); - all := List( all, x -> ExtensionSQ(cc.collector, G, M, + all := List( all, x -> ExtensionSQ(cc.collector, G, M, PreImagesRepresentativeNC(cc.cohom, x ))); red := false; @@ -1152,7 +1150,7 @@ BindGlobal( "NonSplitExtensions", function( arg ) Info( InfoExtReps, 2, " Ext: found ",Length(all)," orbits "); # create extensions and add info - all := List( all, x -> ExtensionSQ(cc.collector, G, M, + all := List( all, x -> ExtensionSQ(cc.collector, G, M, PreImagesRepresentativeNC(cc.cohom, x ))); fi; diff --git a/lib/grppclat.gi b/lib/grppclat.gi index 1476e2bd75..336b5fcef5 100644 --- a/lib/grppclat.gi +++ b/lib/grppclat.gi @@ -85,8 +85,8 @@ local f; Image( epi, ConjugatorOfConjugatorIsomorphism( aut ) ) ); else aut:= GroupHomomorphismByImagesNC(f,f,GeneratorsOfGroup(f), - List(GeneratorsOfGroup(f), - i->Image(epi,Image(aut,PreImagesRepresentativeNC(epi,i))))); + List(GeneratorsOfGroup(f), + i->Image(epi,Image(aut,PreImagesRepresentativeNC(epi,i))))); SetIsInjective(aut,true); SetIsSurjective(aut,true); fi; @@ -672,7 +672,7 @@ local g, # group # hom:=[]; # for i in func do # hom2:=GroupHomomorphismByImagesNC(g,g,g.generators,List(g.generators, -# j->Image(isom,Image(i,PreImagesRepresentativeNC(isom,j))))); +# j->Image(isom,Image(i,PreImagesRepresentative(isom,j))))); # hom2.isMapping:=true; # Add(hom,hom2); # od; @@ -788,7 +788,7 @@ local g, # group hom:= GroupHomomorphismByImagesNC(f,fa,GeneratorsOfGroup(f), List(GeneratorsOfGroup(f),i-> - Image(hom,PreImagesRepresentativeNC(epi,i)))); + Image(hom,PreImagesRepresentativeNC(epi,i)))); Assert(2,KernelOfMultiplicativeGeneralMapping(hom)=n); # lift the known groups From 9dcc205fc695a7d351fa64305abf22f786d6d459 Mon Sep 17 00:00:00 2001 From: Chris Wensley Date: Thu, 29 Sep 2022 16:09:12 +0100 Subject: [PATCH 223/234] some PreImRep -> PreImRepNC in tests --- tst/testextra/makeperfect.g | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tst/testextra/makeperfect.g b/tst/testextra/makeperfect.g index fd68a1560c..b7ed22e898 100644 --- a/tst/testextra/makeperfect.g +++ b/tst/testextra/makeperfect.g @@ -244,8 +244,8 @@ local respp,cf,m,mpos,coh,fgens,comp,reps,v,new,isok,pema,pf,gens,nt,quot, List(GeneratorsOfGroup(new),x->ImagesRepresentative(pema,x)), Concatenation( List(GeneratorsOfGroup(Range(coh.fphom)), - x->PreImagesRepresentative(coh.fphom,x)), - ListWithIdenticalEntries(coh.module.dimension, + x->PreImagesRepresentativeNC(coh.fphom,x)), + ListWithIdenticalEntries(coh.module.dimension, One(coh.group)) )); qk:=KernelOfMultiplicativeGeneralMapping(quot); From e037750badef7fe1b92b7aed484c4ccebde15c6a Mon Sep 17 00:00:00 2001 From: Max Horn Date: Mon, 11 May 2026 12:13:24 +0200 Subject: [PATCH 224/234] Ensure more tests pass with `gap --bare` (#6387) - remove a bunch of SmallGroup and IdGroup uses in tst files - remove tst/testbugfix/2005-05-03-t00070.tst (an equivalent test was added to the smallgrp package recently) - modify some .tst file to run parts only if certain packages are available, via `#@if IsPackageMarkedForLoading(...)` - don't load `ctbllib` (and all its dependencies) in `ctblmaps.tst` --- tst/testinstall/grpmat.tst | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/tst/testinstall/grpmat.tst b/tst/testinstall/grpmat.tst index 8ac7e4db9e..eea0eb9834 100644 --- a/tst/testinstall/grpmat.tst +++ b/tst/testinstall/grpmat.tst @@ -107,21 +107,5 @@ true gap> IsSubset( Source( nice2 ), G2 ); true -# 'NiceMonomorphism' behaves well w.r.t. 'ConstructingFilter' -gap> G:= SP( 4, 2 );; -gap> nice:= NiceMonomorphism( G );; -gap> G2:= SP( 4, 2 : ConstructingFilter:= IsPlistMatrixRep );; -gap> nice2:= NiceMonomorphism( G2 );; -gap> IsPlistMatrixRep( One( G ) ); -false -gap> IsPlistMatrixRep( One( G2 ) ); -true -gap> IsIdenticalObj( nice, nice2 ); -false -gap> IsSubset( Source( nice ), G ); -true -gap> IsSubset( Source( nice2 ), G2 ); -true - # gap> STOP_TEST( "grpmat.tst" ); From 13f07e35f7826f863adb9a7d24b5cef8be816835 Mon Sep 17 00:00:00 2001 From: cdwensley Date: Tue, 12 May 2026 20:37:06 +0100 Subject: [PATCH 225/234] fixing clash in lib/clshom.gi --- lib/clashom.gi | 2 -- 1 file changed, 2 deletions(-) diff --git a/lib/clashom.gi b/lib/clashom.gi index 3ae0a9f30f..374703d844 100644 --- a/lib/clashom.gi +++ b/lib/clashom.gi @@ -1217,7 +1217,6 @@ local cs, # chief series of G fi; - C:=KernelOfMultiplicativeGeneralMapping(Fhom); F:=Image(Fhom,G); clF:=ClassesFromClassical(F); @@ -1315,7 +1314,6 @@ local cs, # chief series of G else Fhom:=GroupHomomorphismByImagesNC(G,F,GeneratorsOfGroup(G),genimages); fi; - C:=KernelOfMultiplicativeGeneralMapping(Fhom); Info(InfoHomClass,1,"constructed Fhom"); From 8603b5b9a698b50f416882ac8f9764438f8ddb92 Mon Sep 17 00:00:00 2001 From: cdwensley Date: Tue, 12 May 2026 20:41:34 +0100 Subject: [PATCH 226/234] fixing clash in lib/grplatt.gi --- lib/grplatt.gi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/grplatt.gi b/lib/grplatt.gi index 24877ce2de..d033e9dcab 100644 --- a/lib/grplatt.gi +++ b/lib/grplatt.gi @@ -2860,7 +2860,7 @@ local fgi,inducedfactorautos,projs,psubs,info,n,l,nl,emb,u,pos, x->x*Image(emb,PreImagesRepresentativeNC(t[5], Image(dc[1],Image(iso,x))) )); Append(g,List(GeneratorsOfGroup(t[1]),x->Image(emb,x))); - g:=Subgroup(D,g);>>>>>>> dbb7e8565 (replaced PreImRep by PreImRepNC in files from a... to g...) + g:=Subgroup(D,g); if Size(g)<>Size(j[1])*Size(s[1])/Size(f) then Error("sudi\n");fi; Add(nl,[g,Normalizer(D,g)]); od; From a89f5b561844720f3c68826ec603948fce789693 Mon Sep 17 00:00:00 2001 From: cdwensley Date: Tue, 12 May 2026 20:57:51 +0100 Subject: [PATCH 227/234] fixing clash in lib/gpfpiso.gi - but check around line 2060 --- lib/gpfpiso.gi | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/lib/gpfpiso.gi b/lib/gpfpiso.gi index 618aa7ab9b..f9325f9f50 100644 --- a/lib/gpfpiso.gi +++ b/lib/gpfpiso.gi @@ -1966,8 +1966,9 @@ local isob,isos,iso,gens,a,rels,l,i,j,bgens,cb,cs,b,f,k,w,monoid, a:=Group(SmallGeneratingSet(group)); # so nothing stores csetperm:=List(GeneratorsOfGroup(a),x->Permutation(x,rt,OnRight)); iso:=EpimorphismFromFreeGroup(a); - borela:=List(bgens,x->MappedWord(PreImagesRepresentativeNC(iso,x),MappingGeneratorsImages(iso)[1],borela)); - act:=Group(borela,()); + 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); @@ -2052,7 +2053,7 @@ local isob,isos,iso,gens,a,rels,l,i,j,bgens,cb,cs,b,f,k,w,monoid, relab:=true; decomp:=function(elm) - local rep,a; + local rep,pos; if elm in borel then return [elm,One(borel),One(borel)];fi; #pos:=PositionProperty(dc,y->elm in y); pos:=rti[PositionCanonical(rt,elm)]; From 83d8341c2887741b07f252b15738ea96d4068fde Mon Sep 17 00:00:00 2001 From: cdwensley Date: Wed, 13 May 2026 09:36:17 +0100 Subject: [PATCH 228/234] fixing whitespace --- lib/alghom.gi | 2 +- lib/alglie.gi | 42 +- lib/autsr.gi | 228 +++++----- lib/clashom.gi | 1160 +++++++++++++++++++++++------------------------ lib/fitfree.gi | 6 +- lib/ghompcgs.gi | 2 +- lib/gpfpiso.gi | 26 +- lib/gprd.gi | 16 +- lib/grpcompl.gi | 4 +- lib/grpfp.gi | 28 +- lib/grplatt.gi | 38 +- lib/grpnice.gi | 4 +- lib/grppcaut.gi | 4 +- lib/grppcext.gi | 6 +- lib/grppclat.gi | 6 +- lib/mapping.gd | 126 ++--- lib/mapping.gi | 28 +- 17 files changed, 863 insertions(+), 863 deletions(-) diff --git a/lib/alghom.gi b/lib/alghom.gi index ec0819b70e..780d647796 100644 --- a/lib/alghom.gi +++ b/lib/alghom.gi @@ -584,7 +584,7 @@ InstallMethod( PreImagesRepresentativeNC, [ IsGeneralMapping and IsAlgebraGeneralMappingByImagesDefaultRep, IsObject ], function( map, elm ) - return PreImagesRepresentativeNC( + return PreImagesRepresentativeNC( AsLeftModuleGeneralMappingByImages(map), elm ); end ); diff --git a/lib/alglie.gi b/lib/alglie.gi index db14f21dae..375414ea0a 100644 --- a/lib/alglie.gi +++ b/lib/alglie.gi @@ -1057,7 +1057,7 @@ InstallMethod( PowerS, F:= LeftActingDomain( L ); p:= Characteristic( F ); - return List( [ 1 .. p-1 ], i -> PowerSi( F , i ) ); + return List( [ 1 .. p-1 ], i -> PowerSi( F, i ) ); end ); @@ -1385,7 +1385,7 @@ InstallMethod( CartanSubalgebra, ## ## This function calculates a basis of the associative matrix algebra ## generated by ad_L K, where is a subalgebra of . -## If {x_1,\ldots ,x_n} is a basis of K, then this algebra is spanned +## If {x_1,\ldots,x_n} is a basis of K, then this algebra is spanned ## by all words ## ad x_{i_1}\cdots ad x_{i_t} ## where t>0. @@ -2091,9 +2091,9 @@ InstallMethod( DirectSumDecomposition, SetCentre( Q, Q ); SetRadicalOfAlgebra( Q, Subalgebra( Q, [ Zero( Q ) ] ) ); - id:= List( CentralIdempotentsOfAlgebra( Q ), + id:= List( CentralIdempotentsOfAlgebra( Q ), x->PreImagesRepresentativeNC(hom,x)); - + # Now we lift the idempotents to the big algebra `A'. The # first idempotent is lifted as follows: # We have that `id[1]^2-id[1]' is an element of `Rad'. @@ -2749,7 +2749,7 @@ InstallMethod( NonNilpotentElement, # Now `char F =0'. # In this case either `L' is nilpotent or one of the - # elements $L.1, \ldots , L.n, L.i + L.j; 1 \leq i < j$ + # elements $L.1, \ldots, L.n, L.i + L.j; 1 \leq i < j$ # is non nilpotent. for i in [ 1 .. n ] do @@ -5567,9 +5567,9 @@ InstallMethod( JenningsLieAlgebra, # Construct the homogeneous components of `L': J:=JenningsSeries ( G ); - Homs:= List ( [1..Length(J)-1] , x -> + Homs:= List ( [1..Length(J)-1], x -> NaturalHomomorphismByNormalSubgroupNC( J[x], J[x+1] )); - grades := List ( Homs , Range ); + grades := List ( Homs, Range ); hom_pcg:= List( grades, IsomorphismSpecialPcGroup ); pcgps:= List( hom_pcg, Range ); gens := []; @@ -5577,11 +5577,11 @@ InstallMethod( JenningsLieAlgebra, pos := []; for i in [1.. Length(grades)] do tempgens:= GeneratorsOfGroup( pcgps[i] ); - Append ( gens , tempgens); + Append ( gens, tempgens); # Record the number that each generator has in extrep. Add( enum_gens, List( tempgens, x -> ExtRepOfObj( x )[1] ) ); - Append ( pos , List ( tempgens , x-> i ) ); + Append ( pos, List ( tempgens, x-> i ) ); od; # Construct the field and the multiplication table: @@ -5589,10 +5589,10 @@ InstallMethod( JenningsLieAlgebra, dim:= Length(gens); p:= PrimePGroup( G ); F:= GF( p ); - T:= EmptySCTable( dim , Zero(F) , "antisymmetric" ); + T:= EmptySCTable( dim, Zero(F), "antisymmetric" ); pimgs := []; for i in [1..dim] do - a:= PreImagesRepresentativeNC( Homs[pos[i]] , + a:= PreImagesRepresentativeNC( Homs[pos[i]], PreImagesRepresentativeNC( hom_pcg[pos[i]], gens[i] ) ); # calculate the p-th power image of `a': @@ -5610,9 +5610,9 @@ InstallMethod( JenningsLieAlgebra, # Calculate the commutator [a,b], and map the result into # the correct homogeneous component. - b:= PreImagesRepresentativeNC( Homs[pos[j]], + b:= PreImagesRepresentativeNC( Homs[pos[j]], PreImagesRepresentativeNC( hom_pcg[pos[j]], gens[j] )); - c:= Image( hom_pcg[pos[i] + pos[j]], + c:= Image( hom_pcg[pos[i] + pos[j]], Image(Homs[pos[i] + pos[j]], a^-1*b^-1*a*b) ); e:= ExtRepOfObj(c); co:=[]; @@ -5764,9 +5764,9 @@ InstallMethod( PCentralLieAlgebra, p:= PrimePGroup( G ); J:= PCentralSeries( G, p ); - Homs:= List ( [1..Length(J)-1] , x -> + Homs:= List ( [1..Length(J)-1], x -> NaturalHomomorphismByNormalSubgroupNC( J[x], J[x+1] )); - grades := List ( Homs , Range ); + grades := List ( Homs, Range ); hom_pcg:= List( grades, IsomorphismSpecialPcGroup ); pcgps:= List( hom_pcg, Range ); gens := []; @@ -5774,21 +5774,21 @@ InstallMethod( PCentralLieAlgebra, pos := []; for i in [1.. Length(grades)] do tempgens:= GeneratorsOfGroup( pcgps[i] ); - Append ( gens , tempgens); + Append ( gens, tempgens); # Record the number that each generator has in extrep. Add( enum_gens, List( tempgens, x -> ExtRepOfObj( x )[1] ) ); - Append ( pos , List ( tempgens , x-> i ) ); + Append ( pos, List ( tempgens, x-> i ) ); od; # Construct the field and the multiplication table: dim:= Length(gens); F:= GF( p ); - T:= EmptySCTable( dim , Zero(F) , "antisymmetric" ); + T:= EmptySCTable( dim, Zero(F), "antisymmetric" ); pimgs := []; for i in [1..dim] do - a:= PreImagesRepresentativeNC( Homs[pos[i]] , + a:= PreImagesRepresentativeNC( Homs[pos[i]], PreImagesRepresentativeNC( hom_pcg[pos[i]], gens[i] ) ); @@ -5807,9 +5807,9 @@ InstallMethod( PCentralLieAlgebra, # Calculate the commutator [a,b], and map the result into # the correct homogeneous component. - b:= PreImagesRepresentativeNC( Homs[pos[j]], + b:= PreImagesRepresentativeNC( Homs[pos[j]], PreImagesRepresentativeNC( hom_pcg[pos[j]], gens[j] )); - c:= Image( hom_pcg[pos[i] + pos[j]], + c:= Image( hom_pcg[pos[i] + pos[j]], Image(Homs[pos[i] + pos[j]], a^-1*b^-1*a*b) ); e:= ExtRepOfObj(c); co:=[]; diff --git a/lib/autsr.gi b/lib/autsr.gi index 705e1daca8..c6ec449f8c 100644 --- a/lib/autsr.gi +++ b/lib/autsr.gi @@ -141,7 +141,7 @@ local ocr,fphom,fpg,free,len,dim,tmp,L0,R,rels,mat,r,RS,i,g,v,cnt; fpg:=FreeGeneratorsOfFpGroup(Range(fphom)); ocr.factorpres:=[fpg,RelatorsOfFpGroup(Range(fphom))]; ocr.generators:=List(GeneratorsOfGroup(Range(fphom)), - i->PreImagesRepresentativeNC(fphom,i)); + i->PreImagesRepresentativeNC(fphom,i)); OCAddMatrices(ocr,ocr.generators); OCAddRelations(ocr,ocr.generators); OCAddSumMatrices(ocr,ocr.generators); @@ -487,7 +487,7 @@ local S,c,hom,q,a,b,i,t,have,ups,new,u,good,abort,clim,worked,pp, cnt:=0; for b in t do new:=PreImagesRepresentativeNC(hom,b); - if (pp=false or new^pp in S) and locond(new) then + if (pp=false or new^pp in S) and locond(new) then S:=ClosureGroup(S,new); have:=true; cnt:=cnt+1; @@ -1024,34 +1024,34 @@ local ff,r,d,ser,u,v,i,j,k,p,bd,e,gens,lhom,M,N,hom,Q,Mim,q,ocr,split,MPcgs, ocr:=OneCocycles(Q,Mim); split:=ocr.isSplitExtension; if not split then - # test: Semisimple and Frattini - b:=MTX.BasisRadical(mo); - fratsim:=Length(b)=0; - if not fratsim then - b:=List(b,x->PreImagesRepresentativeNC(hom,PcElementByExponents(MPcgs,x))); - for j in b do - N:=ClosureSubgroup(N,b); - od; - # insert - for j in [Length(ser),Length(ser)-1..i+1] do - ser[j+1]:=ser[j]; - od; - ser[i+1]:=N; - Info(InfoMorph,2,"insert1"); - else - # Frattini? - fratsim:=IsSubset(FrattiniSubgroup(Q),Mim); - if not fratsim then - N:=Intersection(FrattiniSubgroup(Q),Mim); - # insert - for j in [Length(ser),Length(ser)-1..i+1] do - ser[j+1]:=ser[j]; - od; - ser[i+1]:=PreImage(hom,N); - Info(InfoMorph,2,"insert2"); - fi; + # test: Semisimple and Frattini + b:=MTX.BasisRadical(mo); + fratsim:=Length(b)=0; + if not fratsim then + b:=List(b,x->PreImagesRepresentativeNC(hom,PcElementByExponents(MPcgs,x))); + for j in b do + N:=ClosureSubgroup(N,b); + od; + # insert + for j in [Length(ser),Length(ser)-1..i+1] do + ser[j+1]:=ser[j]; + od; + ser[i+1]:=N; + Info(InfoMorph,2,"insert1"); + else + # Frattini? + fratsim:=IsSubset(FrattiniSubgroup(Q),Mim); + if not fratsim then + N:=Intersection(FrattiniSubgroup(Q),Mim); + # insert + for j in [Length(ser),Length(ser)-1..i+1] do + ser[j+1]:=ser[j]; + od; + ser[i+1]:=PreImage(hom,N); + Info(InfoMorph,2,"insert2"); + fi; N:=ser[i+1]; # the added normal - if rada<>fail + if rada<>fail and ForAny(GeneratorsOfGroup(rada),x->N<>Image(x,N)) then Info(InfoMorph,3,"radical automorphism stabilizer"); SetIsGroupOfAutomorphismsFiniteGroup(rada,true); @@ -1135,11 +1135,11 @@ local ff,r,d,ser,u,v,i,j,k,p,bd,e,gens,lhom,M,N,hom,Q,Mim,q,ocr,split,MPcgs, cond:=function(perm) local aut,newgens,mo2,iso,a; if perm in Aperm then - return true; - fi; + return true; + fi; aut:=PreImagesRepresentativeNC(AQiso,perm); - newgens:=List(gens,x->PreImagesRepresentativeNC(comiso, - ImagesRepresentative(aut,ImagesRepresentative(comiso,x)))); + newgens:=List(gens,x->PreImagesRepresentativeNC(comiso, + ImagesRepresentative(aut,ImagesRepresentative(comiso,x)))); mo2:=GModuleByMats(LinearActionLayer(newgens,MPcgs),mo.field); iso:=MTX.IsomorphismModules(mo,mo2); @@ -1169,11 +1169,11 @@ local ff,r,d,ser,u,v,i,j,k,p,bd,e,gens,lhom,M,N,hom,Q,Mim,q,ocr,split,MPcgs, precond:=function(perm) local aut,newgens,mo2; if perm in Aperm then - return true; - fi; + return true; + fi; aut:=PreImagesRepresentativeNC(AQiso,perm); - newgens:=List(GeneratorsOfGroup(Q), - x->PreImagesRepresentativeNC(q,Image(aut,ImagesRepresentative(q,x)))); + newgens:=List(GeneratorsOfGroup(Q), + x->PreImagesRepresentativeNC(q,Image(aut,ImagesRepresentative(q,x)))); mo2:=GModuleByMats(LinearActionLayer(newgens,MPcgs),mo.field); return MTX.IsomorphismModules(mo,mo2)<>fail; end; @@ -1181,11 +1181,11 @@ local ff,r,d,ser,u,v,i,j,k,p,bd,e,gens,lhom,M,N,hom,Q,Mim,q,ocr,split,MPcgs, cond:=function(perm) local aut,newgens,mo2,iso,a; if perm in Aperm then - return true; - fi; + return true; + fi; aut:=PreImagesRepresentativeNC(AQiso,perm); - newgens:=List(GeneratorsOfGroup(Q), - x->PreImagesRepresentativeNC(q,Image(aut,ImagesRepresentative(q,x)))); + newgens:=List(GeneratorsOfGroup(Q), + x->PreImagesRepresentativeNC(q,Image(aut,ImagesRepresentative(q,x)))); mo2:=GModuleByMats(LinearActionLayer(newgens,MPcgs),mo.field); iso:=MTX.IsomorphismModules(mo,mo2); if iso=fail then @@ -1373,10 +1373,10 @@ local ff,r,d,ser,u,v,i,j,k,p,bd,e,gens,lhom,M,N,hom,Q,Mim,q,ocr,split,MPcgs, for j in GeneratorsOfGroup(rada) do k:=GroupHomomorphismByImagesNC(rf,rf, GeneratorsOfGroup(rf), - List(GeneratorsOfGroup(rf), - y->ImagesRepresentative(hom,ImagesRepresentative(j, - PreImagesRepresentativeNC(hom,y))))); - Assert(2,IsBijective(k)); + List(GeneratorsOfGroup(rf), + y->ImagesRepresentative(hom,ImagesRepresentative(j, + PreImagesRepresentativeNC(hom,y))))); + Assert(2,IsBijective(k)); Add(ind,k); od; @@ -1395,81 +1395,81 @@ local ff,r,d,ser,u,v,i,j,k,p,bd,e,gens,lhom,M,N,hom,Q,Mim,q,ocr,split,MPcgs, # reduce to subgroup that induces valid automorphisms Info(InfoMorph,1,"Radical autos reduce by factor ",Size(res)/Size(ind)); resperm:=IsomorphismPermGroup(C); - proj:=GroupHomomorphismByImagesNC(AQP,Image(resperm), - B[2],List(GeneratorsOfGroup(res),x->ImagesRepresentative(resperm,x))); - C:=PreImage(proj,Image(resperm,ind)); - C:=List(SmallGeneratingSet(C),x->PreImagesRepresentativeNC(AQiso,x)); - AQ:=Group(C); - SetIsFinite(AQ,true); - SetIsGroupOfAutomorphismsFiniteGroup(AQ,true); + proj:=GroupHomomorphismByImagesNC(AQP,Image(resperm), + B[2],List(GeneratorsOfGroup(res),x->ImagesRepresentative(resperm,x))); + C:=PreImage(proj,Image(resperm,ind)); + C:=List(SmallGeneratingSet(C),x->PreImagesRepresentativeNC(AQiso,x)); + AQ:=Group(C); + SetIsFinite(AQ,true); + SetIsGroupOfAutomorphismsFiniteGroup(AQ,true); makeaqiso(); fi; # # hook for using existing characteristics to reduce for next step if somechar<>fail then u:=Filtered(Unique(List(somechar,x->Image(hom,x))),x->Size(x)>1); - u:=Filtered(u,s->ForAny(GeneratorsOfGroup(AQ),h->Image(h,s)<>s)); - SortBy(u,Size); - Info(InfoMorph,1,"Forced characteristics ",List(u,Size)); - - if scharorb<>fail then - # these are subgroups for which certain orbits must be stabilized. - C:=List(Reversed(scharorb),x->List(x,y->Image(hom,y))); - C:=Filtered(C,x->Size(x[1])>1 and Size(x[1])Size(x[1]))); - Append(u,C); - fi; - - if Length(u)>0 then - C:=MappingGeneratorsImages(AQiso); - if C[2]<>GeneratorsOfGroup(AQP) then - C:=[List(GeneratorsOfGroup(AQP), - x->PreImagesRepresentativeNC(AQiso,x)), - GeneratorsOfGroup(AQP)]; - fi; - for j in u do - if IsList(j) then - # stabilizer set of subgroups - jorb:=ShallowCopy(Orbit(AQP,j[1],C[2],C[1],asAutom)); - jorpo:=[Position(jorb,j[1]),Position(jorb,j[2])]; - if jorpo[2]=fail then - Append(jorb,Orbit(AQP,j[1],C[2],C[1],asAutom)); - jorpo[2]:=Position(jorb,j[2]); - fi; - if Length(jorb)>Length(j) then - B:=ActionHomomorphism(AQP,jorb,C[2],C[1],asAutom); - substb:=Group(List(C[2],x->ImagesRepresentative(B,x)),()); - substb:=Stabilizer(substb,Set(jorpo),OnSets); - substb:=PreImage(B,substb); - Info(InfoMorph,2,"Stabilize characteristic orbit ",Size(j[1]), - " :",Size(AQP)/Size(substb) ); - else - substb:=AQP; - fi; - - - else - substb:=Stabilizer(AQP,j,C[2],C[1],asAutom); - Info(InfoMorph,2,"Stabilize characteristic subgroup ",Size(j), - " :",Size(AQP)/Size(substb) ); - fi; - if Size(substb)PreImagesRepresentativeNC(AQiso,x)),substb]; - fi; - - od; - AQ:=Group(C[1]); - SetIsFinite(AQ,true); - SetIsGroupOfAutomorphismsFiniteGroup(AQ,true); - SetSize(AQ,Size(AQP)); - #AQP:=Group(C[2]); # ensure small gen set - #SetSize(AQP,Size(AQ)); - makeaqiso(); - fi; + u:=Filtered(u,s->ForAny(GeneratorsOfGroup(AQ),h->Image(h,s)<>s)); + SortBy(u,Size); + Info(InfoMorph,1,"Forced characteristics ",List(u,Size)); + + if scharorb<>fail then + # these are subgroups for which certain orbits must be stabilized. + C:=List(Reversed(scharorb),x->List(x,y->Image(hom,y))); + C:=Filtered(C,x->Size(x[1])>1 and Size(x[1])Size(x[1]))); + Append(u,C); + fi; + + if Length(u)>0 then + C:=MappingGeneratorsImages(AQiso); + if C[2]<>GeneratorsOfGroup(AQP) then + C:=[List(GeneratorsOfGroup(AQP), + x->PreImagesRepresentativeNC(AQiso,x)), + GeneratorsOfGroup(AQP)]; + fi; + for j in u do + if IsList(j) then + # stabilizer set of subgroups + jorb:=ShallowCopy(Orbit(AQP,j[1],C[2],C[1],asAutom)); + jorpo:=[Position(jorb,j[1]),Position(jorb,j[2])]; + if jorpo[2]=fail then + Append(jorb,Orbit(AQP,j[1],C[2],C[1],asAutom)); + jorpo[2]:=Position(jorb,j[2]); + fi; + if Length(jorb)>Length(j) then + B:=ActionHomomorphism(AQP,jorb,C[2],C[1],asAutom); + substb:=Group(List(C[2],x->ImagesRepresentative(B,x)),()); + substb:=Stabilizer(substb,Set(jorpo),OnSets); + substb:=PreImage(B,substb); + Info(InfoMorph,2,"Stabilize characteristic orbit ",Size(j[1]), + " :",Size(AQP)/Size(substb) ); + else + substb:=AQP; + fi; + + + else + substb:=Stabilizer(AQP,j,C[2],C[1],asAutom); + Info(InfoMorph,2,"Stabilize characteristic subgroup ",Size(j), + " :",Size(AQP)/Size(substb) ); + fi; + if Size(substb)PreImagesRepresentativeNC(AQiso,x)),substb]; + fi; + + od; + AQ:=Group(C[1]); + SetIsFinite(AQ,true); + SetIsGroupOfAutomorphismsFiniteGroup(AQ,true); + SetSize(AQ,Size(AQP)); + #AQP:=Group(C[2]); # ensure small gen set + #SetSize(AQP,Size(AQ)); + makeaqiso(); + fi; fi; lastperm:=AQiso; diff --git a/lib/clashom.gi b/lib/clashom.gi index 374703d844..c7b7bbee71 100644 --- a/lib/clashom.gi +++ b/lib/clashom.gi @@ -544,134 +544,134 @@ local clT, # classes T end; for j in [1..Length(reps)] do - scj:=Size(centralizers[j]); - dsz:=0; - centrhom:=ActionHomomorphism(centralizers_r[j],components[i], - "surjective"); - localcent_r:=Image(centrhom); - Info(InfoHomClass,4,i,":",j); - Info(InfoHomClass,3,"acting: ",Size(centralizers[j])," minimum ", - Int(Size(Image(projections[i]))/Size(centralizers[j])), - " orbits."); - # compute C(r)-classes - clTR:=[]; - for l in clT do - Info(InfoHomClass,4,"DC",Index(T,l[2])," ",Index(T,localcent_r)); - dc:=DoubleCosetRepsAndSizes(T,l[2],localcent_r); - clTR:=Concatenation(clTR,List(dc,i->l[1]^i[1])); - od; - - orb:=[]; - for p in [1..Length(clTR)] do - - repres:=PreImagesRepresentativeNC(projections[i],clTR[p]); - if i=1 or isdirprod - or reps[j]*RestrictedPermNC(repres,components[i]) - in Mproj[i] then - stab:=Centralizer(localcent_r,clTR[p]); - if Index(localcent_r,stab)clTR[p] then - genpos:=Position(img,clTR[p]); - img:=Permuted(img,(1,genpos)); - fi; - else - img:=ConjugacyClass(localcent_r,clTR[p],stab); - fi; - Add(orb,[repres,PreImage(centrhom,stab),img,localcent_r]); - fi; - od; - clTR:=orb; - - #was: - #clTR:=List(clTR,i->ConjugacyClass(localcent_r,i)); - #clTR:=List(clTR,j->[PreImagesRepresentative(projections[i], - # Representative(j)), - # PreImage(centrhom,Centralizer(j)), - # j]); - - # put small classes to the top (to be sure to hit them and make - # large local stabilizers) - SortBy(clTR,x->Size(x[3])); - - Info(InfoHomClass,3,Length(clTR)," local classes"); - - cystr:=[]; - for p in [1..Length(clTR)] do - repres:=Immutable(CycleStructurePerm(Representative(clTR[p][3]))); - select:=First(cystr,x->x[1]=repres); - if select=fail then - Add(cystr,[repres,[p]]); - else - AddSet(select[2],p); - fi; - od; - - cengen:=GeneratorsOfGroup(centralizers[j]); - if Length(cengen)>10 then - cengen:=SmallGeneratingSet(centralizers[j]); - fi; - #cengen:=Filtered(cengen,i->not i in localcent_r); - - while Length(clTR)>0 do - - # orbit algorithm on classes - stab:=clTR[1][2]; - orb:=[clTR[1]]; - #repres:=RestrictedPermNC(clTR[1][1],components[i]); - repres:=clTR[1][1]; - trans:=[One(M)]; - select:=[2..Length(clTR)]; - - orpo:=1; - minlen:=Size(orb[1][3]); - possible:=false; - stabtrue:=false; - pf:=infinity; - maxdiff:=Size(T); - again:=0; - trymap:=false; - ug:=[]; - # test whether we have full orbit and full stabilizer - while Size(centralizers[j])>(Sum(orb,i->Size(i[3]))*Size(stab)) do - genpos:=1; - while genpos<=Length(cengen) and - Size(centralizers[j])>(Sum(orb,i->Size(i[3]))*Size(stab)) do - gen:=cengen[genpos]; - skip:=false; - if trymap<>false then - orpo:=trymap[1]; - gen:=trymap[2]; - trymap:=false; - elif again>0 then - if not IsBound(ug[genpos]) then - ug[genpos]:=Intersection(centralizers_r[j], - ConjugateSubgroup(centralizers_r[j],gen^-1)); - fi; - if again<500 and ForAll(GeneratorsOfGroup(centralizers_r[j]), - i->i in ug[genpos]) - then - # the random elements will give us nothing new - skip:=true; - else - # get an element not in ug[genpos] - repeat - img:=Random(centralizers_r[j]); - until not img in ug[genpos] or again>=500; - gen:=img*gen; - fi; - fi; - - if not skip then - - img:=Image(projections[i],opfun(orb[orpo][1],gen)); - - smacla:=select; - - if not stabtrue then - p:=PositionProperty(orb,i->img in i[3]); - ppos:=fail; + scj:=Size(centralizers[j]); + dsz:=0; + centrhom:=ActionHomomorphism(centralizers_r[j],components[i], + "surjective"); + localcent_r:=Image(centrhom); + Info(InfoHomClass,4,i,":",j); + Info(InfoHomClass,3,"acting: ",Size(centralizers[j])," minimum ", + Int(Size(Image(projections[i]))/Size(centralizers[j])), + " orbits."); + # compute C(r)-classes + clTR:=[]; + for l in clT do + Info(InfoHomClass,4,"DC",Index(T,l[2])," ",Index(T,localcent_r)); + dc:=DoubleCosetRepsAndSizes(T,l[2],localcent_r); + clTR:=Concatenation(clTR,List(dc,i->l[1]^i[1])); + od; + + orb:=[]; + for p in [1..Length(clTR)] do + + repres:=PreImagesRepresentativeNC(projections[i],clTR[p]); + if i=1 or isdirprod + or reps[j]*RestrictedPermNC(repres,components[i]) + in Mproj[i] then + stab:=Centralizer(localcent_r,clTR[p]); + if Index(localcent_r,stab)clTR[p] then + genpos:=Position(img,clTR[p]); + img:=Permuted(img,(1,genpos)); + fi; + else + img:=ConjugacyClass(localcent_r,clTR[p],stab); + fi; + Add(orb,[repres,PreImage(centrhom,stab),img,localcent_r]); + fi; + od; + clTR:=orb; + + #was: + #clTR:=List(clTR,i->ConjugacyClass(localcent_r,i)); + #clTR:=List(clTR,j->[PreImagesRepresentative(projections[i], + # Representative(j)), + # PreImage(centrhom,Centralizer(j)), + # j]); + + # put small classes to the top (to be sure to hit them and make + # large local stabilizers) + SortBy(clTR,x->Size(x[3])); + + Info(InfoHomClass,3,Length(clTR)," local classes"); + + cystr:=[]; + for p in [1..Length(clTR)] do + repres:=Immutable(CycleStructurePerm(Representative(clTR[p][3]))); + select:=First(cystr,x->x[1]=repres); + if select=fail then + Add(cystr,[repres,[p]]); + else + AddSet(select[2],p); + fi; + od; + + cengen:=GeneratorsOfGroup(centralizers[j]); + if Length(cengen)>10 then + cengen:=SmallGeneratingSet(centralizers[j]); + fi; + #cengen:=Filtered(cengen,i->not i in localcent_r); + + while Length(clTR)>0 do + + # orbit algorithm on classes + stab:=clTR[1][2]; + orb:=[clTR[1]]; + #repres:=RestrictedPermNC(clTR[1][1],components[i]); + repres:=clTR[1][1]; + trans:=[One(M)]; + select:=[2..Length(clTR)]; + + orpo:=1; + minlen:=Size(orb[1][3]); + possible:=false; + stabtrue:=false; + pf:=infinity; + maxdiff:=Size(T); + again:=0; + trymap:=false; + ug:=[]; + # test whether we have full orbit and full stabilizer + while Size(centralizers[j])>(Sum(orb,i->Size(i[3]))*Size(stab)) do + genpos:=1; + while genpos<=Length(cengen) and + Size(centralizers[j])>(Sum(orb,i->Size(i[3]))*Size(stab)) do + gen:=cengen[genpos]; + skip:=false; + if trymap<>false then + orpo:=trymap[1]; + gen:=trymap[2]; + trymap:=false; + elif again>0 then + if not IsBound(ug[genpos]) then + ug[genpos]:=Intersection(centralizers_r[j], + ConjugateSubgroup(centralizers_r[j],gen^-1)); + fi; + if again<500 and ForAll(GeneratorsOfGroup(centralizers_r[j]), + i->i in ug[genpos]) + then + # the random elements will give us nothing new + skip:=true; + else + # get an element not in ug[genpos] + repeat + img:=Random(centralizers_r[j]); + until not img in ug[genpos] or again>=500; + gen:=img*gen; + fi; + fi; + + if not skip then + + img:=Image(projections[i],opfun(orb[orpo][1],gen)); + + smacla:=select; + + if not stabtrue then + p:=PositionProperty(orb,i->img in i[3]); + ppos:=fail; else # we have the stabilizer and thus are only interested in # getting new elements. @@ -694,50 +694,50 @@ local clT, # classes T return fail; fi; else - p:=ppos; - fi; - - RemoveSet(select,p); - Add(orb,clTR[p]); - - if trans[orpo]=false then - Add(trans,false); - else - #change the transversal element to map to the representative - con:=trans[orpo]*gen; - limg:=opfun(repres,con); - con:=con*PreImagesRepresentativeNC(centrhom, - RepresentativeAction(localcent_r, - Image(projections[i],limg), - Representative(clTR[p][3]))); - Assert(2,Image(projections[i],opfun(repres,con)) - =Representative(clTR[p][3])); - - Add(trans,con); - - for stgen in GeneratorsOfGroup(clTR[p][2]) do - Assert( 2, IsOne( Image( projections[i], - opfun(repres,con*stgen/con)/repres ) ) ); - stab:=ClosureGroup(stab,con*stgen/con); - od; - fi; - - # compute new minimum length - - if Length(select)>0 then - remainlen:=List(clTR{select},i->Size(i[3])); - gcd:=Gcd(remainlen); - diff:=minlen-Sum(orb,i->Size(i[3])); - - if diff<0 then - # only go through this if the orbit actually grew - # larger - minlen:=Sum(orb,i->Size(i[3])); - repeat - if dsz=0 then - dsz:=DivisorsInt(scj); - fi; - while not minlen in dsz do + p:=ppos; + fi; + + RemoveSet(select,p); + Add(orb,clTR[p]); + + if trans[orpo]=false then + Add(trans,false); + else + #change the transversal element to map to the representative + con:=trans[orpo]*gen; + limg:=opfun(repres,con); + con:=con*PreImagesRepresentativeNC(centrhom, + RepresentativeAction(localcent_r, + Image(projections[i],limg), + Representative(clTR[p][3]))); + Assert(2,Image(projections[i],opfun(repres,con)) + =Representative(clTR[p][3])); + + Add(trans,con); + + for stgen in GeneratorsOfGroup(clTR[p][2]) do + Assert( 2, IsOne( Image( projections[i], + opfun(repres,con*stgen/con)/repres ) ) ); + stab:=ClosureGroup(stab,con*stgen/con); + od; + fi; + + # compute new minimum length + + if Length(select)>0 then + remainlen:=List(clTR{select},i->Size(i[3])); + gcd:=Gcd(remainlen); + diff:=minlen-Sum(orb,i->Size(i[3])); + + if diff<0 then + # only go through this if the orbit actually grew + # larger + minlen:=Sum(orb,i->Size(i[3])); + repeat + if dsz=0 then + dsz:=DivisorsInt(scj); + fi; + while not minlen in dsz do # workaround rare problem -- try again if First(dsz,i->i>=minlen)=fail then return ConjugacyClassesSubwreath( @@ -790,149 +790,149 @@ local clT, # classes T stabtrue:=true; fi; - elif not stabtrue then - # we have an element that stabilizes the conjugacy class. - # correct this to an element that fixes the representative. - # (As we have taken already the centralizer in - # centralizers_r, it is sufficient to correct by - # centralizers_r-conjugation.) - con:=trans[orpo]*gen; - limg:=opfun(repres,con); - con:=con*PreImagesRepresentativeNC(centrhom, - RepresentativeAction(localcent_r, - Image(projections[i],limg), - Representative(orb[p][3]))); - stab:=ClosureGroup(stab,con/trans[p]); - if Size(stab)*2*minlen>Size(centralizers[j]) then - Info(InfoHomClass,3, - "true stabilizer found (cannot grow)"); - minlen:=Size(centralizers[j])/Size(stab); - maxdiff:=minlen-Sum(orb,i->Size(i[3])); - stabtrue:=true; - fi; - fi; - - if stabtrue then - - smacla:=Filtered(select,i->Size(clTR[i][3])<=maxdiff); - - if Length(smacla)Size(i[3])); - - CompletionBar(InfoHomClass,3,"trueorb ",1-maxdiff/minlen); - #Info(InfoHomClass,3, - # "This is the true orbit length (missing ", - # maxdiff,")"); - - if Size(stab)*Sum(orb,i->Size(i[3])) - =Size(centralizers[j]) then + elif not stabtrue then + # we have an element that stabilizes the conjugacy class. + # correct this to an element that fixes the representative. + # (As we have taken already the centralizer in + # centralizers_r, it is sufficient to correct by + # centralizers_r-conjugation.) + con:=trans[orpo]*gen; + limg:=opfun(repres,con); + con:=con*PreImagesRepresentativeNC(centrhom, + RepresentativeAction(localcent_r, + Image(projections[i],limg), + Representative(orb[p][3]))); + stab:=ClosureGroup(stab,con/trans[p]); + if Size(stab)*2*minlen>Size(centralizers[j]) then + Info(InfoHomClass,3, + "true stabilizer found (cannot grow)"); + minlen:=Size(centralizers[j])/Size(stab); + maxdiff:=minlen-Sum(orb,i->Size(i[3])); + stabtrue:=true; + fi; + fi; + + if stabtrue then + + smacla:=Filtered(select,i->Size(clTR[i][3])<=maxdiff); + + if Length(smacla)Size(i[3])); + + CompletionBar(InfoHomClass,3,"trueorb ",1-maxdiff/minlen); + #Info(InfoHomClass,3, + # "This is the true orbit length (missing ", + # maxdiff,")"); + + if Size(stab)*Sum(orb,i->Size(i[3])) + =Size(centralizers[j]) then maxdiff:=0; - elif Sum(remainlen)=maxdiff then - Info(InfoHomClass,2, - "Full possible remainder must fuse"); - orb:=Concatenation(orb,clTR{smacla}); - select:=Difference(select,smacla); - - else - # test whether there is only one possibility to get - # this length - if Length(smacla)<20 and - Sum(List([1..Minimum(Length(smacla), - Int(maxdiff/gcd+1))], - x-> NrCombinations(smacla,x)))<10000 then - # get all reasonable combinations - smare:=[1..Length(smacla)]; #range for smacla - combl:=Concatenation(List([1..Int(maxdiff/gcd+1)], - i->Combinations(smare,i))); - # pick those that have the correct length - combl:=Filtered(combl,i->Sum(remainlen{i})=maxdiff); - if Length(combl)>1 then - Info(InfoHomClass,3,"Addendum not unique (", - Length(combl)," possibilities)"); - if (maxdiff<10 or again>0) - and ForAll(combl,i->Length(i)<=5) then - # we have tried often enough, now try to pick the - # right ones - possible:=false; - combl:=Union(combl); - combl:=smacla{combl}; - genpos2:=1; - smacla:=[]; - while possible=false and Length(combl)>0 do - img:=Image(projections[i], - opfun(clTR[combl[1]][1],cengen[genpos2])); - p:=PositionProperty(orb,i->img in i[3]); - if p<>fail then - # it is! - Info(InfoHomClass,4,"got one!"); - - # remember the element to try - trymap:=[p,(cengen[genpos2]* - PreImagesRepresentativeNC( - RestrictedMapping(projections[i], - centralizers[j]), - RepresentativeAction( - orb[p][4], - img,Representative(orb[p][3])) ))^-1]; - - Add(smacla,combl[1]); - combl:=combl{[2..Length(combl)]}; - if Sum(clTR{smacla},i->Size(i[3]))=maxdiff then - # bingo! - possible:=true; - fi; - fi; - genpos2:=genpos2+1; - if genpos2>Length(cengen) then - genpos2:=1; - combl:=combl{[2..Length(combl)]}; - fi; - od; - if possible=false then - Info(InfoHomClass,4,"Even test failed!"); - else - orb:=Concatenation(orb,clTR{smacla}); - select:=Difference(select,smacla); - Info(InfoHomClass,3,"Completed orbit (hard)"); - fi; - fi; - elif Length(combl)>0 then - combl:=combl[1]; - orb:=Concatenation(orb,clTR{smacla{combl}}); - select:=Difference(select,smacla{combl}); - Info(InfoHomClass,3,"Completed orbit"); - fi; - fi; - fi; - fi; - - fi; - else - Info(InfoHomClass,5,"skip"); - fi; # if not skip - - genpos:=genpos+1; - od; - orpo:=orpo+1; - if orpo>Length(orb) then - Info(InfoHomClass,3,"Size factor:",EvalF( - (Sum(orb,i->Size(i[3]))*Size(stab))/Size(centralizers[j])), - " orbit consists of ",Length(orb)," suborbits, iterating"); - - if stabtrue then - pper:=false; - # we know stabilizer, just need to find orbit. As these are - # likely small additions, search in reverse. - for p in select do - for genpos in [1..Length(cengen)] do - gen:=Random(centralizers_r[j])*cengen[genpos]; - img:=Image(projections[i],opfun(clTR[p][1],gen)); - orpo:=CycleStructurePerm(img); - ppos:=First(First(cystr,x->x[1]=orpo)[2], - i->not i in select and - img in clTR[i][3]); + elif Sum(remainlen)=maxdiff then + Info(InfoHomClass,2, + "Full possible remainder must fuse"); + orb:=Concatenation(orb,clTR{smacla}); + select:=Difference(select,smacla); + + else + # test whether there is only one possibility to get + # this length + if Length(smacla)<20 and + Sum(List([1..Minimum(Length(smacla), + Int(maxdiff/gcd+1))], + x-> NrCombinations(smacla,x)))<10000 then + # get all reasonable combinations + smare:=[1..Length(smacla)]; #range for smacla + combl:=Concatenation(List([1..Int(maxdiff/gcd+1)], + i->Combinations(smare,i))); + # pick those that have the correct length + combl:=Filtered(combl,i->Sum(remainlen{i})=maxdiff); + if Length(combl)>1 then + Info(InfoHomClass,3,"Addendum not unique (", + Length(combl)," possibilities)"); + if (maxdiff<10 or again>0) + and ForAll(combl,i->Length(i)<=5) then + # we have tried often enough, now try to pick the + # right ones + possible:=false; + combl:=Union(combl); + combl:=smacla{combl}; + genpos2:=1; + smacla:=[]; + while possible=false and Length(combl)>0 do + img:=Image(projections[i], + opfun(clTR[combl[1]][1],cengen[genpos2])); + p:=PositionProperty(orb,i->img in i[3]); + if p<>fail then + # it is! + Info(InfoHomClass,4,"got one!"); + + # remember the element to try + trymap:=[p,(cengen[genpos2]* + PreImagesRepresentativeNC( + RestrictedMapping(projections[i], + centralizers[j]), + RepresentativeAction( + orb[p][4], + img,Representative(orb[p][3])) ))^-1]; + + Add(smacla,combl[1]); + combl:=combl{[2..Length(combl)]}; + if Sum(clTR{smacla},i->Size(i[3]))=maxdiff then + # bingo! + possible:=true; + fi; + fi; + genpos2:=genpos2+1; + if genpos2>Length(cengen) then + genpos2:=1; + combl:=combl{[2..Length(combl)]}; + fi; + od; + if possible=false then + Info(InfoHomClass,4,"Even test failed!"); + else + orb:=Concatenation(orb,clTR{smacla}); + select:=Difference(select,smacla); + Info(InfoHomClass,3,"Completed orbit (hard)"); + fi; + fi; + elif Length(combl)>0 then + combl:=combl[1]; + orb:=Concatenation(orb,clTR{smacla{combl}}); + select:=Difference(select,smacla{combl}); + Info(InfoHomClass,3,"Completed orbit"); + fi; + fi; + fi; + fi; + + fi; + else + Info(InfoHomClass,5,"skip"); + fi; # if not skip + + genpos:=genpos+1; + od; + orpo:=orpo+1; + if orpo>Length(orb) then + Info(InfoHomClass,3,"Size factor:",EvalF( + (Sum(orb,i->Size(i[3]))*Size(stab))/Size(centralizers[j])), + " orbit consists of ",Length(orb)," suborbits, iterating"); + + if stabtrue then + pper:=false; + # we know stabilizer, just need to find orbit. As these are + # likely small additions, search in reverse. + for p in select do + for genpos in [1..Length(cengen)] do + gen:=Random(centralizers_r[j])*cengen[genpos]; + img:=Image(projections[i],opfun(clTR[p][1],gen)); + orpo:=CycleStructurePerm(img); + ppos:=First(First(cystr,x->x[1]=orpo)[2], + i->not i in select and + img in clTR[i][3]); if ppos<>fail and p in select then # so the image is in clTR[ppos] which must be in orb ppos:=Position(orb,clTR[ppos]); @@ -1141,7 +1141,7 @@ local cs, # chief series of G hom:=NaturalHomomorphismByNormalSubgroupNC(G,lastM); cl:=ConjugacyClasses(Image(hom)); cl:=List(cl,i->[PreImagesRepresentativeNC(hom,Representative(i)), - PreImage(hom,StabilizerOfExternalSet(i))]); + PreImage(hom,StabilizerOfExternalSet(i))]); fi; for i in [2..Length(cs)] do @@ -1182,144 +1182,144 @@ local cs, # chief series of G if IsNormal(G,subN) then - # only one -> Call standard process - - Fhom:=fail; - # is this an almost top factor? - if Index(G,M)<10 then - Thom:=NaturalHomomorphismByNormalSubgroupNC(G,subN); - T1:=Image(Thom,M); - S1:=Image(Thom); - if Size(Centralizer(S1,T1))=1 then - deg1:=NrMovedPoints(S1); - Info(InfoHomClass,2, - "top factor gives conjugating representation, deg ",deg1); - - Fhom:=Thom; - fi; - else - Thom:=NaturalHomomorphismByNormalSubgroupNC(M,subN); - T1:=Image(Thom,M); - fi; - - if Fhom=fail then - autos:=List(GeneratorsOfGroup(G), - i->GroupHomomorphismByImagesNC(T1,T1,GeneratorsOfGroup(T1), - List(GeneratorsOfGroup(T1), - j->Image(Thom,PreImagesRepresentativeNC(Thom,j)^i)))); - - # find (probably another) permutation rep for T1 for which all - # automorphisms can be represented by permutations - arhom:=AutomorphismRepresentingGroup(T1,autos); - S1:=arhom[1]; - deg1:=NrMovedPoints(S1); - Fhom:=GroupHomomorphismByImagesNC(G,S1,GeneratorsOfGroup(G),arhom[3]); - fi; - - - F:=Image(Fhom,G); - - clF:=ClassesFromClassical(F); - if clF=fail then - clF:=ConjugacyClassesByRandomSearch(F); - fi; - - clF:=List(clF,j->[Representative(j),StabilizerOfExternalSet(j)]); + # only one -> Call standard process + + Fhom:=fail; + # is this an almost top factor? + if Index(G,M)<10 then + Thom:=NaturalHomomorphismByNormalSubgroupNC(G,subN); + T1:=Image(Thom,M); + S1:=Image(Thom); + if Size(Centralizer(S1,T1))=1 then + deg1:=NrMovedPoints(S1); + Info(InfoHomClass,2, + "top factor gives conjugating representation, deg ",deg1); + + Fhom:=Thom; + fi; + else + Thom:=NaturalHomomorphismByNormalSubgroupNC(M,subN); + T1:=Image(Thom,M); + fi; + + if Fhom=fail then + autos:=List(GeneratorsOfGroup(G), + i->GroupHomomorphismByImagesNC(T1,T1,GeneratorsOfGroup(T1), + List(GeneratorsOfGroup(T1), + j->Image(Thom,PreImagesRepresentativeNC(Thom,j)^i)))); + + # find (probably another) permutation rep for T1 for which all + # automorphisms can be represented by permutations + arhom:=AutomorphismRepresentingGroup(T1,autos); + S1:=arhom[1]; + deg1:=NrMovedPoints(S1); + Fhom:=GroupHomomorphismByImagesNC(G,S1,GeneratorsOfGroup(G),arhom[3]); + fi; + + + F:=Image(Fhom,G); + + clF:=ClassesFromClassical(F); + if clF=fail then + clF:=ConjugacyClassesByRandomSearch(F); + fi; + + clF:=List(clF,j->[Representative(j),StabilizerOfExternalSet(j)]); else - csM:=Orbit(G,subN); # all conjugates - n:=Length(csM); - - if n=1 then - Error("this cannot happen"); - T:=M; - fi; - - T:=Intersection(csM{[2..Length(csM)]}); # one T_i - if Length(GeneratorsOfGroup(T))>5 then - T:=Group(SmallGeneratingSet(T)); - fi; - - T:=Orbit(G,T); # get all the t's - # now T[1] is a complement to csM[1] in G/N. - - # now compute the operation of G on M/N - Qhom:=ActionHomomorphism(G,T,"surjective"); - Q:=Image(Qhom,G); - S:=PreImage(Qhom,Stabilizer(Q,1)); - - # find a permutation rep. for S-action on T[1] - Thom:=NaturalHomomorphismByNormalSubgroupNC(T[1],N); - T1:=Image(Thom); - if not IsSubset([1..NrMovedPoints(T1)], - MovedPoints(T1)) then - Thom:=Thom*ActionHomomorphism(T1,MovedPoints(T1),"surjective"); - fi; - T1:=Image(Thom,T[1]); - if IsPermGroup(T1) and - NrMovedPoints(T1)>SufficientlySmallDegreeSimpleGroupOrder(Size(T1)) then - Thom:=Thom*SmallerDegreePermutationRepresentation(T1:cheap); - Info(InfoHomClass,1,"reduced simple degree ",NrMovedPoints(T1), - " ",NrMovedPoints(Image(Thom))); - T1:=Image(Thom,T[1]); - fi; - - autos:=List(GeneratorsOfGroup(S), - i->GroupHomomorphismByImagesNC(T1,T1,GeneratorsOfGroup(T1), - List(GeneratorsOfGroup(T1), - j->Image(Thom,PreImagesRepresentativeNC(Thom,j)^i)))); - - # find (probably another) permutation rep for T1 for which all - # automorphisms can be represented by permutations - arhom:=AutomorphismRepresentingGroup(T1,autos); - S1:=arhom[1]; - deg1:=NrMovedPoints(S1); - Thom:=GroupHomomorphismByImagesNC(S,S1,GeneratorsOfGroup(S),arhom[3]); - - T1:=Image(Thom,T[1]); - - # now embed into wreath - w:=WreathProduct(S1,Q); - wbas:=DirectProduct(List([1..n],i->S1)); - emb:=List([1..n+1],i->Embedding(w,i)); - proj:=List([1..n],i->Projection(wbas,i)); - components:=WreathProductInfo(w).components; - - # define isomorphisms between the components - reps:=List([1..n],i-> - PreImagesRepresentativeNC(Qhom,RepresentativeAction(Q,1,i))); - - genimages:=[]; - for j in GeneratorsOfGroup(G) do - img:=Image(Qhom,j); - gimg:=Image(emb[n+1],img); - for k in [1..n] do - # look at part of j's action on the k-th factor. - # we get this by looking at the action of - # reps[k] * j * reps[k^img]^-1 - # 1 -> k -> k^img -> 1 - # on the first component. - act:=reps[k]*j*(reps[k^img]^-1); - # this must be multiplied *before* permuting - gimg:=ImageElm(emb[k],ImageElm(Thom,act))*gimg; - gimg:=RestrictedPermNC(gimg,MovedPoints(w)); - od; - Add(genimages,gimg); - od; - - F:=Subgroup(w,genimages); - if AssertionLevel()>=2 then - Fhom:=GroupHomomorphismByImages(G,F,GeneratorsOfGroup(G),genimages); - Assert(1,fail<>Fhom); - else - Fhom:=GroupHomomorphismByImagesNC(G,F,GeneratorsOfGroup(G),genimages); - fi; - - Info(InfoHomClass,1,"constructed Fhom"); - - # 2) compute the classes for F - - if n>1 then + csM:=Orbit(G,subN); # all conjugates + n:=Length(csM); + + if n=1 then + Error("this cannot happen"); + T:=M; + fi; + + T:=Intersection(csM{[2..Length(csM)]}); # one T_i + if Length(GeneratorsOfGroup(T))>5 then + T:=Group(SmallGeneratingSet(T)); + fi; + + T:=Orbit(G,T); # get all the t's + # now T[1] is a complement to csM[1] in G/N. + + # now compute the operation of G on M/N + Qhom:=ActionHomomorphism(G,T,"surjective"); + Q:=Image(Qhom,G); + S:=PreImage(Qhom,Stabilizer(Q,1)); + + # find a permutation rep. for S-action on T[1] + Thom:=NaturalHomomorphismByNormalSubgroupNC(T[1],N); + T1:=Image(Thom); + if not IsSubset([1..NrMovedPoints(T1)], + MovedPoints(T1)) then + Thom:=Thom*ActionHomomorphism(T1,MovedPoints(T1),"surjective"); + fi; + T1:=Image(Thom,T[1]); + if IsPermGroup(T1) and + NrMovedPoints(T1)>SufficientlySmallDegreeSimpleGroupOrder(Size(T1)) then + Thom:=Thom*SmallerDegreePermutationRepresentation(T1:cheap); + Info(InfoHomClass,1,"reduced simple degree ",NrMovedPoints(T1), + " ",NrMovedPoints(Image(Thom))); + T1:=Image(Thom,T[1]); + fi; + + autos:=List(GeneratorsOfGroup(S), + i->GroupHomomorphismByImagesNC(T1,T1,GeneratorsOfGroup(T1), + List(GeneratorsOfGroup(T1), + j->Image(Thom,PreImagesRepresentativeNC(Thom,j)^i)))); + + # find (probably another) permutation rep for T1 for which all + # automorphisms can be represented by permutations + arhom:=AutomorphismRepresentingGroup(T1,autos); + S1:=arhom[1]; + deg1:=NrMovedPoints(S1); + Thom:=GroupHomomorphismByImagesNC(S,S1,GeneratorsOfGroup(S),arhom[3]); + + T1:=Image(Thom,T[1]); + + # now embed into wreath + w:=WreathProduct(S1,Q); + wbas:=DirectProduct(List([1..n],i->S1)); + emb:=List([1..n+1],i->Embedding(w,i)); + proj:=List([1..n],i->Projection(wbas,i)); + components:=WreathProductInfo(w).components; + + # define isomorphisms between the components + reps:=List([1..n],i-> + PreImagesRepresentativeNC(Qhom,RepresentativeAction(Q,1,i))); + + genimages:=[]; + for j in GeneratorsOfGroup(G) do + img:=Image(Qhom,j); + gimg:=Image(emb[n+1],img); + for k in [1..n] do + # look at part of j's action on the k-th factor. + # we get this by looking at the action of + # reps[k] * j * reps[k^img]^-1 + # 1 -> k -> k^img -> 1 + # on the first component. + act:=reps[k]*j*(reps[k^img]^-1); + # this must be multiplied *before* permuting + gimg:=ImageElm(emb[k],ImageElm(Thom,act))*gimg; + gimg:=RestrictedPermNC(gimg,MovedPoints(w)); + od; + Add(genimages,gimg); + od; + + F:=Subgroup(w,genimages); + if AssertionLevel()>=2 then + Fhom:=GroupHomomorphismByImages(G,F,GeneratorsOfGroup(G),genimages); + Assert(1,fail<>Fhom); + else + Fhom:=GroupHomomorphismByImagesNC(G,F,GeneratorsOfGroup(G),genimages); + fi; + + Info(InfoHomClass,1,"constructed Fhom"); + + # 2) compute the classes for F + + if n>1 then #if IsPermGroup(F) and NrMovedPoints(F)<18 then # # the old Butler/Theissen approach is still OK # clF:=[]; @@ -1336,30 +1336,30 @@ local cs, # chief series of G clF:=ConjugacyClassesSubwreath(F,FM,n,S1, Action(FM,components[1]),T1,components,emb,proj); if clF=fail then - #Error("failer"); - # weird error happened -- redo - j:=Random(SymmetricGroup(MovedPoints(G))); - FM:=List(GeneratorsOfGroup(G),x->x^j); - F:=Group(FM); - SetSize(F,Size(G)); - FM:=GroupHomomorphismByImagesNC(G,F,GeneratorsOfGroup(G),FM); - clF:=ConjugacyClassesFittingFreeGroup(F); - clF:=List(clF,x->[PreImagesRepresentativeNC(FM,x[1]),PreImage(FM,x[2])]); - return clF; - fi; - #fi; - else - FM:=Image(Fhom,M); - Info(InfoHomClass,1, - "classes by random search in almost simple group"); - - clF:=ClassesFromClassical(F); - if clF=fail then - clF:=ConjugacyClassesByRandomSearch(F); - fi; - - clF:=List(clF,j->[Representative(j),StabilizerOfExternalSet(j)]); - fi; + #Error("failer"); + # weird error happened -- redo + j:=Random(SymmetricGroup(MovedPoints(G))); + FM:=List(GeneratorsOfGroup(G),x->x^j); + F:=Group(FM); + SetSize(F,Size(G)); + FM:=GroupHomomorphismByImagesNC(G,F,GeneratorsOfGroup(G),FM); + clF:=ConjugacyClassesFittingFreeGroup(F); + clF:=List(clF,x->[PreImagesRepresentativeNC(FM,x[1]),PreImage(FM,x[2])]); + return clF; + fi; + #fi; + else + FM:=Image(Fhom,M); + Info(InfoHomClass,1, + "classes by random search in almost simple group"); + + clF:=ClassesFromClassical(F); + if clF=fail then + clF:=ConjugacyClassesByRandomSearch(F); + fi; + + clF:=List(clF,j->[Representative(j),StabilizerOfExternalSet(j)]); + fi; fi; # true orbit of T. Assert(2,Sum(clF,i->Index(F,i[2]))=Size(F)); @@ -1370,106 +1370,106 @@ local cs, # chief series of G # the length(cl)=1 gets rid of solvable stuff on the top we got ``too # early''. if IsSubgroup(N,KernelOfMultiplicativeGeneralMapping(Fhom)) then - Info(InfoHomClass,1, - "homomorphism is faithful for relevant factor, take preimages"); - if Size(N)=1 and onlysizes=true then - cl:=List(clF,i->[PreImagesRepresentativeNC(Fhom,i[1]),Size(i[2])]); - else - cl:=List(clF,i->[PreImagesRepresentativeNC(Fhom,i[1]), - PreImage(Fhom,i[2])]); + Info(InfoHomClass,1, + "homomorphism is faithful for relevant factor, take preimages"); + if Size(N)=1 and onlysizes=true then + cl:=List(clF,i->[PreImagesRepresentativeNC(Fhom,i[1]),Size(i[2])]); + else + cl:=List(clF,i->[PreImagesRepresentativeNC(Fhom,i[1]), + PreImage(Fhom,i[2])]); fi; else - Info(InfoHomClass,1,"forming subdirect products"); - - FM:=Image(Fhom,lastM); - FMhom:=RestrictedMapping(Fhom,lastM); - if Index(F,FM)=1 then - Info(InfoHomClass,1,"degenerated to direct product"); - ncl:=[]; - for j in cl do - for k in clF do - # modify the representative with a kernel elm. to project - # correctly on the second component - elm:=j[1]*PreImagesRepresentativeNC(FMhom, - LeftQuotient(Image(Fhom,j[1]),k[1])); - zentr:=Intersection(j[2],PreImage(Fhom,k[2])); - Assert(3,ForAll(GeneratorsOfGroup(zentr), - i->Comm(i,elm) in N)); - Add(ncl,[elm,zentr]); - od; - od; - - cl:=ncl; - - else - - # first we add the centralizer closures and sort by them - # (this allows to reduce the number of double coset calculations) - ncl:=[]; - for j in cl do - Cim:=Image(Fhom,j[2]); - CimCl:=Cim; - #CimCl:=ClosureGroup(FM,Cim); # should be unnecessary, as we took - # the full preimage - p:=PositionProperty(ncl,i->i[1]=CimCl); - if p=fail then - Add(ncl,[CimCl,[j]]); - else - Add(ncl[p][2],j); - fi; - od; - - Qhom:=NaturalHomomorphismByNormalSubgroupNC(F,FM); - Q:=Image(Qhom); - FQhom:=Fhom*Qhom; - - # now construct the sdp's - cl:=[]; - for j in ncl do - lj:=List(j[2],i->Image(FQhom,i[1])); - for k in clF do - # test whether the classes are potential mates - elm:=Image(Qhom,k[1]); - if not ForAll(lj,i->RepresentativeAction(Q,i,elm)=fail) then - - #l:=Image(Fhom,j[1]); - - if Index(F,j[1])=1 then - dc:=[()]; - else - dc:=List(DoubleCosetRepsAndSizes(F,k[2],j[1]),i->i[1]); - fi; - good:=0; - bad:=0; - for l in j[2] do - jim:=Image(FQhom,l[1]); - for l1 in dc do - elm:=k[1]^l1; - if Image(Qhom,elm)=jim then - # modify the representative with a kernel elm. to project - # correctly on the second component - elm:=l[1]*PreImagesRepresentativeNC(FMhom, - LeftQuotient(Image(Fhom,l[1]),elm)); - zentr:=PreImage(Fhom,k[2]^l1); - zentr:=Intersection(zentr,l[2]); - - Assert(3,ForAll(GeneratorsOfGroup(zentr), - i->Comm(i,elm) in N)); - - Info(InfoHomClass,4,"new class, order ",Order(elm), - ", size=",Index(G,zentr)); - Add(cl,[elm,zentr]); - good:=good+1; - else - Info(InfoHomClass,5,"not in"); - bad:=bad+1; - fi; - od; - od; - Info(InfoHomClass,4,good," good, ",bad," bad of ",Length(dc)); - fi; - od; - od; + Info(InfoHomClass,1,"forming subdirect products"); + + FM:=Image(Fhom,lastM); + FMhom:=RestrictedMapping(Fhom,lastM); + if Index(F,FM)=1 then + Info(InfoHomClass,1,"degenerated to direct product"); + ncl:=[]; + for j in cl do + for k in clF do + # modify the representative with a kernel elm. to project + # correctly on the second component + elm:=j[1]*PreImagesRepresentativeNC(FMhom, + LeftQuotient(Image(Fhom,j[1]),k[1])); + zentr:=Intersection(j[2],PreImage(Fhom,k[2])); + Assert(3,ForAll(GeneratorsOfGroup(zentr), + i->Comm(i,elm) in N)); + Add(ncl,[elm,zentr]); + od; + od; + + cl:=ncl; + + else + + # first we add the centralizer closures and sort by them + # (this allows to reduce the number of double coset calculations) + ncl:=[]; + for j in cl do + Cim:=Image(Fhom,j[2]); + CimCl:=Cim; + #CimCl:=ClosureGroup(FM,Cim); # should be unnecessary, as we took + # the full preimage + p:=PositionProperty(ncl,i->i[1]=CimCl); + if p=fail then + Add(ncl,[CimCl,[j]]); + else + Add(ncl[p][2],j); + fi; + od; + + Qhom:=NaturalHomomorphismByNormalSubgroupNC(F,FM); + Q:=Image(Qhom); + FQhom:=Fhom*Qhom; + + # now construct the sdp's + cl:=[]; + for j in ncl do + lj:=List(j[2],i->Image(FQhom,i[1])); + for k in clF do + # test whether the classes are potential mates + elm:=Image(Qhom,k[1]); + if not ForAll(lj,i->RepresentativeAction(Q,i,elm)=fail) then + + #l:=Image(Fhom,j[1]); + + if Index(F,j[1])=1 then + dc:=[()]; + else + dc:=List(DoubleCosetRepsAndSizes(F,k[2],j[1]),i->i[1]); + fi; + good:=0; + bad:=0; + for l in j[2] do + jim:=Image(FQhom,l[1]); + for l1 in dc do + elm:=k[1]^l1; + if Image(Qhom,elm)=jim then + # modify the representative with a kernel elm. to project + # correctly on the second component + elm:=l[1]*PreImagesRepresentativeNC(FMhom, + LeftQuotient(Image(Fhom,l[1]),elm)); + zentr:=PreImage(Fhom,k[2]^l1); + zentr:=Intersection(zentr,l[2]); + + Assert(3,ForAll(GeneratorsOfGroup(zentr), + i->Comm(i,elm) in N)); + + Info(InfoHomClass,4,"new class, order ",Order(elm), + ", size=",Index(G,zentr)); + Add(cl,[elm,zentr]); + good:=good+1; + else + Info(InfoHomClass,5,"not in"); + bad:=bad+1; + fi; + od; + od; + Info(InfoHomClass,4,good," good, ",bad," bad of ",Length(dc)); + fi; + od; + od; fi; # real subdirect product fi; # else Fhom not faithful on factor @@ -2397,12 +2397,12 @@ local r, #radical if ntrihom then ncl:=[]; for i in cl do - new:=[PreImagesRepresentativeNC(hom,i[1])]; - if not IsInt(i[2]) then - Add(new,[]); # no generators in radical yet - gens:=SmallGeneratingSet(i[2]); - Add(new, - List(gens,x->PreImagesRepresentativeNC(hom,x))); + new:=[PreImagesRepresentativeNC(hom,i[1])]; + if not IsInt(i[2]) then + Add(new,[]); # no generators in radical yet + gens:=SmallGeneratingSet(i[2]); + Add(new, + List(gens,x->PreImagesRepresentativeNC(hom,x))); Add(new,gens); #TODO: PreImage groups? #Add(new,PreImage(hom,i[2])); @@ -2885,7 +2885,7 @@ local r, #radical fi; prereps:=f!.classpreimgs; if not IsBound(prereps[j]) then - prereps[j]:=PreImagesRepresentativeNC(hom,Representative(cl[j])); + prereps[j]:=PreImagesRepresentativeNC(hom,Representative(cl[j])); fi; r:=PreImagesRepresentativeNC(hom,conj); @@ -2897,7 +2897,7 @@ local r, #radical # 6:cenfac, 7:cenfacimgs, 8:censize, 9:cenfacsize Add(nreps,[i,i^r,prereps[j],r,[], List(d,x->PreImagesRepresentativeNC(hom,x)),d, - radsize*Size(Centralizer(cl[j])), Size(Centralizer(cl[j]))]); + radsize*Size(Centralizer(cl[j])), Size(Centralizer(cl[j]))]); od; reps:=nreps; diff --git a/lib/fitfree.gi b/lib/fitfree.gi index 0989708dc1..5090f8a7b2 100644 --- a/lib/fitfree.gi +++ b/lib/fitfree.gi @@ -1195,9 +1195,9 @@ local s,d,c,act,o,i,j,h,p,hf,img,n,k,ns,all,hl,hcomp, norm:=n); for j in [2..Length(i)] do c[i[j]]:=rec(orbit:=i,orbitpos:=j, - rep:=PreImagesRepresentativeNC(act, - RepresentativeAction(Image(act),i[1],i[j])), - component:=d[i[j]],hall:=h, norm:=n); + rep:=PreImagesRepresentativeNC(act, + RepresentativeAction(Image(act),i[1],i[j])), + component:=d[i[j]],hall:=h, norm:=n); od; od; diff --git a/lib/ghompcgs.gi b/lib/ghompcgs.gi index f3fb30ddda..78ba75b339 100644 --- a/lib/ghompcgs.gi +++ b/lib/ghompcgs.gi @@ -505,7 +505,7 @@ end); ## #M PreImagesRepresentativeNC( , ) . . . . . . . . . . via images ## -InstallMethod( PreImagesRepresentativeNC, "method for pcgs hom", +InstallMethod( PreImagesRepresentativeNC, "method for pcgs hom", FamRangeEqFamElm, [ IsToPcGroupHomomorphismByImages,IsMultiplicativeElementWithInverse ], 0, function( hom, elm ) diff --git a/lib/gpfpiso.gi b/lib/gpfpiso.gi index f9325f9f50..491744f28f 100644 --- a/lib/gpfpiso.gi +++ b/lib/gpfpiso.gi @@ -90,10 +90,10 @@ local l,iso,fp,stbc,gens; if iso<>fail then fp:=IsomorphismFpGroup(l); iso:=GroupHomomorphismByImagesNC(G,Range(fp), - List(MappingGeneratorsImages(fp)[1], - i->PreImagesRepresentativeNC(iso,i)), - MappingGeneratorsImages(fp)[2]); - SetIsBijective(iso,true); + List(MappingGeneratorsImages(fp)[1], + i->PreImagesRepresentativeNC(iso,i)), + MappingGeneratorsImages(fp)[2]); + SetIsBijective(iso,true); return iso; fi; od; @@ -166,12 +166,12 @@ function( G, str ) # 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->PreImagesRepresentativeNC(new,i)); + # compute presentation of H + IsNonabelianSimpleGroup(H); + IsNaturalAlternatingGroup(H); + new:=IsomorphismFpGroup(H,"@"); + gensH:=List(GeneratorsOfGroup(Image(new)), + i->PreImagesRepresentativeNC(new,i)); preiH := List( gensH, x -> PreImagesRepresentativeNC( hom, x ) ); c := Length( gensH ); @@ -396,8 +396,8 @@ function(g,str,N) # calculate automorphisms of f induced by G fgens:=GeneratorsOfGroup(f); auts:=List(GeneratorsOfGroup(g),i-> - GroupHomomorphismByImagesNC(f,f,fgens, - List(fgens,j->Image(hom,PreImagesRepresentativeNC(hom,j)^i)):noassert)); + GroupHomomorphismByImagesNC(f,f,fgens, + List(fgens,j->Image(hom,PreImagesRepresentativeNC(hom,j)^i)):noassert)); for j in auts do SetIsBijective(j,true); od; @@ -1320,7 +1320,7 @@ 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->PreImagesRepresentativeNC(iso,x))<>pcgs then + if List(GeneratorsOfGroup(fp),x->PreImagesRepresentativeNC(iso,x))<>pcgs then Error("pcgs"); fi; gens:=[]; diff --git a/lib/gprd.gi b/lib/gprd.gi index c5df0b6f66..0623e77ac6 100644 --- a/lib/gprd.gi +++ b/lib/gprd.gi @@ -1091,13 +1091,13 @@ local info,map,U,mapfun,P; U:=SubgroupNC(G,info.hgens); fi; map:=GroupHomomorphismByFunction(P,U,mapfun, - function(elm) - elm:=elm![n]; - if n>info.degI then - elm:=PreImagesRepresentativeNC(info.alpha,elm); - fi; - return elm; - end); + function(elm) + elm:=elm![n]; + if n>info.degI then + elm:=PreImagesRepresentativeNC(info.alpha,elm); + fi; + return elm; + end); info.embeddings[n]:=map; fi; return info.embeddings[n]; @@ -1118,7 +1118,7 @@ local info,map,np; map:=GroupHomomorphismByFunction(G,info.groups[2], function(elm) - return PreImagesRepresentativeNC(info.alpha,elm![np]); + return PreImagesRepresentativeNC(info.alpha,elm![np]); end, false, # not bijective function(elm) diff --git a/lib/grpcompl.gi b/lib/grpcompl.gi index 187222cb0d..81e845295e 100644 --- a/lib/grpcompl.gi +++ b/lib/grpcompl.gi @@ -99,8 +99,8 @@ local G,N,K,s, h, q, fpi, factorpres, com, comgens, cen, ocrels, fpcgs, ncom, Length(MappingGeneratorsImages(fpi)[2])," generators"); factorpres:=[FreeGeneratorsOfFpGroup(Range(fpi)), RelatorsOfFpGroup(Range(fpi)), - List(GeneratorsOfGroup(Range(fpi)), - i->PreImagesRepresentativeNC(fpi,i))]; + List(GeneratorsOfGroup(Range(fpi)), + i->PreImagesRepresentativeNC(fpi,i))]; Assert(1,ForAll(factorpres[3],i->Image(h,PreImagesRepresentativeNC(h,i))=i)); # initialize com:=[G]; diff --git a/lib/grpfp.gi b/lib/grpfp.gi index 47c342feb4..cc73d6474d 100644 --- a/lib/grpfp.gi +++ b/lib/grpfp.gi @@ -5494,10 +5494,10 @@ local G,T,gens,g,reps,ng,index,i,j,ndef,n,iso; IsRightTransversalFpGroupRep and IsList and IsDuplicateFreeList and IsAttributeStoringRep ), rec( group := OG, - subgroup := U, - iso:=iso, - table:=T, - reps:=List(reps,i->PreImagesRepresentativeNC(iso,i)))); + subgroup := U, + iso:=iso, + table:=T, + reps:=List(reps,i->PreImagesRepresentativeNC(iso,i)))); fi; ndef := 1; @@ -5509,16 +5509,16 @@ local G,T,gens,g,reps,ng,index,i,j,ndef,n,iso; #This assumes that reps[j] is already defined - but #this is true because T is 'standardized' ndef := ndef+1; - if ndef=index then - return Objectify( NewType( FamilyObj( OG ), - IsRightTransversalFpGroupRep and IsList and - IsDuplicateFreeList and IsAttributeStoringRep ), - rec( group := OG, - subgroup := U, - iso:=iso, - table:=T, - reps:=List(reps,i->PreImagesRepresentativeNC(iso,i)))); - fi; + if ndef=index then + return Objectify( NewType( FamilyObj( OG ), + IsRightTransversalFpGroupRep and IsList and + IsDuplicateFreeList and IsAttributeStoringRep ), + rec( group := OG, + subgroup := U, + iso:=iso, + table:=T, + reps:=List(reps,i->PreImagesRepresentativeNC(iso,i)))); + fi; fi; od; od; diff --git a/lib/grplatt.gi b/lib/grplatt.gi index d033e9dcab..ab02af4280 100644 --- a/lib/grplatt.gi +++ b/lib/grplatt.gi @@ -2780,7 +2780,7 @@ local fgi,inducedfactorautos,projs,psubs,info,n,l,nl,emb,u,pos, auts:=[]; for i in GeneratorsOfGroup(n) do aut:=GroupHomomorphismByImages(f,f,gens,List(gens,x-> - Image(hom,PreImagesRepresentativeNC(hom,x)^i))); + Image(hom,PreImagesRepresentativeNC(hom,x)^i))); SetIsBijective(aut,true); Add(auts,aut); od; @@ -2843,24 +2843,24 @@ local fgi,inducedfactorautos,projs,psubs,info,n,l,nl,emb,u,pos, for s in subs do for t in s[3] do # look over normals of subgroup #Print(t,"\n"); - if t{[3,4]}=myid then - if false and myid=[1,1] then - #Print("direct\n"); - g:=Subgroup(D,Concatenation(GeneratorsOfGroup(j[1]),List(GeneratorsOfGroup(s[1]),x->Image(emb,x)))); - Add(nl,[g,Normalizer(D,g)]); - else - iso:=IsomorphismGroups(f,t[6]); - if iso<>fail then - #Found isomorphic factor groups - iso:=hom*iso; - ind:=Subgroup(t[7],inducedfactorautos(k.normalizer,t[6],iso)); - for dc in DoubleCosetRepsAndSizes(t[7],ind,t[8]) do - # form the subdirect product - g:=List(GeneratorsOfGroup(j[1]), - x->x*Image(emb,PreImagesRepresentativeNC(t[5], - Image(dc[1],Image(iso,x))) )); - Append(g,List(GeneratorsOfGroup(t[1]),x->Image(emb,x))); - g:=Subgroup(D,g); + if t{[3,4]}=myid then + if false and myid=[1,1] then + #Print("direct\n"); + g:=Subgroup(D,Concatenation(GeneratorsOfGroup(j[1]),List(GeneratorsOfGroup(s[1]),x->Image(emb,x)))); + Add(nl,[g,Normalizer(D,g)]); + else + iso:=IsomorphismGroups(f,t[6]); + if iso<>fail then + #Found isomorphic factor groups + iso:=hom*iso; + ind:=Subgroup(t[7],inducedfactorautos(k.normalizer,t[6],iso)); + for dc in DoubleCosetRepsAndSizes(t[7],ind,t[8]) do + # form the subdirect product + g:=List(GeneratorsOfGroup(j[1]), + x->x*Image(emb,PreImagesRepresentativeNC(t[5], + Image(dc[1],Image(iso,x))) )); + Append(g,List(GeneratorsOfGroup(t[1]),x->Image(emb,x))); + g:=Subgroup(D,g); if Size(g)<>Size(j[1])*Size(s[1])/Size(f) then Error("sudi\n");fi; Add(nl,[g,Normalizer(D,g)]); od; diff --git a/lib/grpnice.gi b/lib/grpnice.gi index 106afc6a48..6e3db2bd6f 100644 --- a/lib/grpnice.gi +++ b/lib/grpnice.gi @@ -284,8 +284,8 @@ function( obj1, obj2 ) img := ImagesRepresentative( nice, obj2:actioncanfail:=true ); if img = fail or not (img in ImagesSource(nice) and - PreImagesRepresentativeNC(nice,img)=obj2) then - TryNextMethod(); + PreImagesRepresentativeNC(nice,img)=obj2) then + TryNextMethod(); fi; no:=NiceObject(obj1); img1 := ClosureGroup( NiceObject(obj1), img ); diff --git a/lib/grppcaut.gi b/lib/grppcaut.gi index 6a4e5514ed..0f3ca0cadc 100644 --- a/lib/grppcaut.gi +++ b/lib/grppcaut.gi @@ -1418,12 +1418,12 @@ InstallGlobalFunction(AutomorphismGroupSolvableGroup,function( G ) hom := ActionHomomorphism( xset, "surjective"); P := Image( hom ); if IsSolvableGroup( P ) then - pcsA := List( Pcgs(P), + pcsA := List( Pcgs(P), x -> PreImagesRepresentativeNC( hom, x )); TransferPcgsInfo( A, pcsA, RelativeOrders( Pcgs(P) ) ); else imgs := SmallGeneratingSet( P ); - gens := List( imgs, + gens := List( imgs, x -> PreImagesRepresentativeNC( hom, x ) ); tmp := Size( A ); A := GroupByGenerators( gens, One( A ) ); diff --git a/lib/grppcext.gi b/lib/grppcext.gi index 7bdc1c082d..bcc5e554a9 100644 --- a/lib/grppcext.gi +++ b/lib/grppcext.gi @@ -1120,7 +1120,7 @@ BindGlobal( "NonSplitExtensions", function( arg ) # if reduction is suppressed elif IsBound( arg[3] ) and not arg[3] then all := NormedRowVectors( Image(cc.cohom) ); - all := List( all, x -> ExtensionSQ(cohom.collector, G, M, + all := List( all, x -> ExtensionSQ(cohom.collector, G, M, PreImagesRepresentativeNC(cc.cohom,x ))); red := false; @@ -1131,7 +1131,7 @@ BindGlobal( "NonSplitExtensions", function( arg ) and not HasAutomorphismGroup( G ) then all := NormedRowVectors( Image(cc.cohom) ); - all := List( all, x -> ExtensionSQ(cc.collector, G, M, + all := List( all, x -> ExtensionSQ(cc.collector, G, M, PreImagesRepresentativeNC(cc.cohom, x ))); red := false; @@ -1150,7 +1150,7 @@ BindGlobal( "NonSplitExtensions", function( arg ) Info( InfoExtReps, 2, " Ext: found ",Length(all)," orbits "); # create extensions and add info - all := List( all, x -> ExtensionSQ(cc.collector, G, M, + all := List( all, x -> ExtensionSQ(cc.collector, G, M, PreImagesRepresentativeNC(cc.cohom, x ))); fi; diff --git a/lib/grppclat.gi b/lib/grppclat.gi index 336b5fcef5..42785b7f3e 100644 --- a/lib/grppclat.gi +++ b/lib/grppclat.gi @@ -85,8 +85,8 @@ local f; Image( epi, ConjugatorOfConjugatorIsomorphism( aut ) ) ); else aut:= GroupHomomorphismByImagesNC(f,f,GeneratorsOfGroup(f), - List(GeneratorsOfGroup(f), - i->Image(epi,Image(aut,PreImagesRepresentativeNC(epi,i))))); + List(GeneratorsOfGroup(f), + i->Image(epi,Image(aut,PreImagesRepresentativeNC(epi,i))))); SetIsInjective(aut,true); SetIsSurjective(aut,true); fi; @@ -788,7 +788,7 @@ local g, # group hom:= GroupHomomorphismByImagesNC(f,fa,GeneratorsOfGroup(f), List(GeneratorsOfGroup(f),i-> - Image(hom,PreImagesRepresentativeNC(epi,i)))); + Image(hom,PreImagesRepresentativeNC(epi,i)))); Assert(2,KernelOfMultiplicativeGeneralMapping(hom)=n); # lift the known groups diff --git a/lib/mapping.gd b/lib/mapping.gd index ffa15c5b08..381755b0f4 100644 --- a/lib/mapping.gd +++ b/lib/mapping.gd @@ -982,22 +982,22 @@ DeclareGlobalFunction( "Images" ); ## preimages of elm under map. ##

## Anything may happen if elm is not an element of the range of -## map. -##

-## In order to improve this state of affairs, -## PreImagesElm has been renamed PreImagesElmNC -## throughout the library, and -## PreImagesElm has been declared a synonym for PreImagesElmNC. -##

-## In future versions of &GAP; PreImagesElm -## will perform additional checks and reject invalid inputs. -## These additional checks will slow the computation so, -## when the inputs are known to be valid by construction, -## users are recommended to use PreImagesElmNC. -##

-## Package authors are asked to convert their methods for -## PreImagesElm to methods for PreImagesElmNC. -## Only when this has happened will the additional checks be implemented. +## map. +##

+## In order to improve this state of affairs, +## PreImagesElm has been renamed PreImagesElmNC +## throughout the library, and +## PreImagesElm has been declared a synonym for PreImagesElmNC. +##

+## In future versions of &GAP; PreImagesElm +## will perform additional checks and reject invalid inputs. +## These additional checks will slow the computation so, +## when the inputs are known to be valid by construction, +## users are recommended to use PreImagesElmNC. +##

+## Package authors are asked to convert their methods for +## PreImagesElm to methods for PreImagesElmNC. +## Only when this has happened will the additional checks be implemented. ## ## ## <#/GAPDoc> @@ -1043,28 +1043,28 @@ DeclareOperation( "PreImageElm", ## ## If elm is an element of the range of the general mapping ## map then these operations return either a representative -## of the set of preimages of elm under map or fail, +## of the set of preimages of elm under map or fail, ## the latter if and only if elm has no preimages under map. ##

## Anything may happen if elm is not an element of the range of ## map. ##

-## In order to improve this state of affairs, -## PreImagesRepresentative has been renamed -## PreImagesRepresentativeNC throughout the library, -## and PreImagesRepresentative has been declared a synonym for -## PreImagesRepresentativeNC. -##

-## In future versions of &GAP; PreImagesRepresentative -## will perform additional checks and reject invalid inputs. -## These additional checks will slow the computation so, -## when the inputs are known to be valid by construction, -## users are recommended to use PreImagesRepresentativeNC. -##

-## Package authors are asked to convert their methods for -## PreImagesRepresentative to methods for -## PreImagesRepresentativeNC. -## Only when this has happened will the additional checks be implemented. +## In order to improve this state of affairs, +## PreImagesRepresentative has been renamed +## PreImagesRepresentativeNC throughout the library, +## and PreImagesRepresentative has been declared a synonym for +## PreImagesRepresentativeNC. +##

+## In future versions of &GAP; PreImagesRepresentative +## will perform additional checks and reject invalid inputs. +## These additional checks will slow the computation so, +## when the inputs are known to be valid by construction, +## users are recommended to use PreImagesRepresentativeNC. +##

+## Package authors are asked to convert their methods for +## PreImagesRepresentative to methods for +## PreImagesRepresentativeNC. +## Only when this has happened will the additional checks be implemented. ## ## ## <#/GAPDoc> @@ -1100,26 +1100,26 @@ DeclareSynonym( "PreImagesRepresentative", PreImagesRepresentativeNC ); ## Anything may happen if elms is not a subset of the range of ## map. ##

-## In order to improve this state of affairs, -## PreImagesSet has been renamed PreImagesSetNC -## throughout the library, and -## PreImagesSet has been declared a synonym for PreImagesSetNC. +## In order to improve this state of affairs, +## PreImagesSet has been renamed PreImagesSetNC +## throughout the library, and +## PreImagesSet has been declared a synonym for PreImagesSetNC. ##

-## In future versions of &GAP; PreImagesSet -## will perform additional checks and reject invalid inputs. -## These additional checks will slow the computation so, -## when the inputs are known to be valid by construction, -## users are recommended to use PreImagesSetNC. +## In future versions of &GAP; PreImagesSet +## will perform additional checks and reject invalid inputs. +## These additional checks will slow the computation so, +## when the inputs are known to be valid by construction, +## users are recommended to use PreImagesSetNC. ##

-## Package authors are asked to convert their methods for -## PreImagesSet to methods for PreImagesSetNC. -## Only when this has happened will the additional checks be implemented. +## Package authors are asked to convert their methods for +## PreImagesSet to methods for PreImagesSetNC. +## Only when this has happened will the additional checks be implemented. ## ## ## <#/GAPDoc> ## DeclareOperation( "PreImagesSetNC", [ IsGeneralMapping, IsListOrCollection ] ); -DeclareSynonym( "PreImagesSet", PreImagesSetNC ); +DeclareSynonym( "PreImagesSet", PreImagesSetNC ); ############################################################################# @@ -1180,11 +1180,11 @@ DeclareGlobalFunction( "PreImage" ); ############################################################################# ## -#F PreImages() +#F PreImages() #F PreImagesNC() . . . set of preimages of the range of a gen. mapping -#F PreImages(,) +#F PreImages(,) #F PreImagesNC(,) set of preimages of an elm under a gen. mapping -#F PreImages(,) +#F PreImages(,) #F PreImagesNC(,) set of preimages of a coll. under a gen. mapping ## ## <#GAPDoc Label="PreImages"> @@ -1222,36 +1222,36 @@ DeclareGlobalFunction( "PreImage" ); ## (If coll and the result are lists then the positions of ## entries do in general not correspond.) ##

-## ## delegates to when ## called with one argument, ## and to resp. when ## called with two arguments. -## The corresponding PreImagesNC delegates to PreImagesRange +## The corresponding PreImagesNC delegates to PreImagesRange ## and PreImagesSetNC. ##

## If the second argument is not an element or a subset of the range of -## the first argument, incorrect results may be returned. -## In order to improve this state of affairs, +## the first argument, incorrect results may be returned. +## In order to improve this state of affairs, ## PreImages has been renamed PreImagesNC throughout the library, -## and PreImages has been declared a synonym for PreImagesNC. +## and PreImages has been declared a synonym for PreImagesNC. ##

-## In future versions of &GAP; PreImages -## will perform additional checks and reject invalid inputs. -## These additional checks will slow the computation so, -## when the inputs are known to be valid by construction, -## users are recommended to use PreImagesNC. +## In future versions of &GAP; PreImages +## will perform additional checks and reject invalid inputs. +## These additional checks will slow the computation so, +## when the inputs are known to be valid by construction, +## users are recommended to use PreImagesNC. ##

-## Package authors are asked to convert their methods for -## PreImages to methods for PreImagesNC. -## Only when this has happened will the additional checks be implemented. +## Package authors are asked to convert their methods for +## PreImages to methods for PreImagesNC. +## Only when this has happened will the additional checks be implemented. ## ## ## <#/GAPDoc> ## DeclareGlobalFunction( "PreImagesNC" ); -DeclareSynonym( "PreImages", PreImagesNC ); +DeclareSynonym( "PreImages", PreImagesNC ); ############################################################################# diff --git a/lib/mapping.gi b/lib/mapping.gi index 26b3d63855..99beb95a48 100644 --- a/lib/mapping.gi +++ b/lib/mapping.gi @@ -297,11 +297,11 @@ end ); ############################################################################# ## -#F PreImages() +#F PreImages() #F PreImagesNC() . . . set of preimages of the range of a gen. mapping -#F PreImages(,) +#F PreImages(,) #F PreImagesNC(,) set of preimages of an elm under a gen. mapping -#F PreImages(,) +#F PreImages(,) #F PreImagesNC(,) set of preimages of a coll. under a gen. mapping ## InstallGlobalFunction( PreImagesNC, function ( arg ) @@ -1178,11 +1178,11 @@ InstallMethod( PreImagesRange, ## FamRangeEqFamElm, ## [ IsSPGeneralMapping, IsObject ], 0, ## function( map, elm ) -## test will be included at a later stage of the change of name -## if not elm in Image( map ) then -## return fail; -## fi; -## return PreImagesRepresentativeNC( map, elm ); +## test will be included at a later stage of the change of name +## if not elm in Image( map ) then +## return fail; +## fi; +## return PreImagesRepresentativeNC( map, elm ); ## end ); InstallMethod( PreImagesRepresentativeNC, @@ -1203,12 +1203,12 @@ InstallMethod( PreImagesRepresentativeNC, ## "for total non-s.p. general mapping, and element", ## FamRangeEqFamElm, ## [ IsNonSPGeneralMapping, IsObject ], 0, -## function( map, elm ) -## test will be included at a later stage of the change of name -## if not elm in Image( map ) then -## return fail; -## fi; -## return PreImagesRepresentativeNC( map, elm ); +## function( map, elm ) +## test will be included at a later stage of the change of name +## if not elm in Image( map ) then +## return fail; +## fi; +## return PreImagesRepresentativeNC( map, elm ); ## end ); InstallMethod( PreImagesRepresentativeNC, From 6c18d33a0f11404ebadee510be4ea7799fbbf493 Mon Sep 17 00:00:00 2001 From: cdwensley Date: Wed, 13 May 2026 15:01:04 +0100 Subject: [PATCH 229/234] remove duplicate lines --- lib/clashom.gi | 2 +- lib/mapping.gd | 10 ++-------- 2 files changed, 3 insertions(+), 9 deletions(-) diff --git a/lib/clashom.gi b/lib/clashom.gi index c7b7bbee71..7fbcae3ee3 100644 --- a/lib/clashom.gi +++ b/lib/clashom.gi @@ -1298,7 +1298,7 @@ local cs, # chief series of G # we get this by looking at the action of # reps[k] * j * reps[k^img]^-1 # 1 -> k -> k^img -> 1 - # on the first component. + # on the first component. act:=reps[k]*j*(reps[k^img]^-1); # this must be multiplied *before* permuting gimg:=ImageElm(emb[k],ImageElm(Thom,act))*gimg; diff --git a/lib/mapping.gd b/lib/mapping.gd index 381755b0f4..ccfc21d242 100644 --- a/lib/mapping.gd +++ b/lib/mapping.gd @@ -1042,7 +1042,7 @@ DeclareOperation( "PreImageElm", ## ## ## If elm is an element of the range of the general mapping -## map then these operations return either a representative +## map then these operations return either a representative ## of the set of preimages of elm under map or fail, ## the latter if and only if elm has no preimages under map. ##

@@ -1076,12 +1076,6 @@ DeclareOperation( "PreImagesRepresentativeNC", [ IsGeneralMapping, IsObject ] ); DeclareSynonym( "PreImagesRepresentative", PreImagesRepresentativeNC ); -## DeclareOperation( "PreImagesRepresentative", -## [ IsGeneralMapping, IsObject ] ); -DeclareOperation( "PreImagesRepresentativeNC", - [ IsGeneralMapping, IsObject ] ); -DeclareSynonym( "PreImagesRepresentative", PreImagesRepresentativeNC ); - ############################################################################# ## #O PreImagesSet( , ) @@ -1234,7 +1228,7 @@ DeclareGlobalFunction( "PreImage" ); ## If the second argument is not an element or a subset of the range of ## the first argument, incorrect results may be returned. ## In order to improve this state of affairs, -## PreImages has been renamed PreImagesNC throughout the library, +## PreImages has been renamed PreImagesNC throughout the library, ## and PreImages has been declared a synonym for PreImagesNC. ##

## In future versions of &GAP; PreImages From b86a8ec7d60896c5ac45f908a53753b72cc93807 Mon Sep 17 00:00:00 2001 From: cdwensley Date: Wed, 13 May 2026 15:52:37 +0100 Subject: [PATCH 230/234] try to stop infinite recursion in alghom.tst --- lib/alghom.gi | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/lib/alghom.gi b/lib/alghom.gi index 780d647796..86293e194e 100644 --- a/lib/alghom.gi +++ b/lib/alghom.gi @@ -588,15 +588,16 @@ InstallMethod( PreImagesRepresentativeNC, AsLeftModuleGeneralMappingByImages(map), elm ); end ); -InstallMethod( PreImagesRepresentativeNC, - "for algebra g.m.b.i. knowing inverse, and element", - FamRangeEqFamElm, - [ IsGeneralMapping and IsAlgebraGeneralMappingByImagesDefaultRep - and HasInverseGeneralMapping, - IsObject ], - function( map, elm ) - return ImagesRepresentative( InverseGeneralMapping(map), elm ); - end ); +## (13/05/26) commented this out to prevent infinite recursion in alghom.tst +## InstallMethod( PreImagesRepresentativeNC, +## "for algebra g.m.b.i. knowing inverse, and element", +## FamRangeEqFamElm, +## [ IsGeneralMapping and IsAlgebraGeneralMappingByImagesDefaultRep +## and HasInverseGeneralMapping, +## IsObject ], +## function( map, elm ) +## return ImagesRepresentative( InverseGeneralMapping(map), elm ); +## end ); ############################################################################# From 9d4689176c01f3c54b2d4fdf5219c6709e878832 Mon Sep 17 00:00:00 2001 From: cdwensley Date: Wed, 13 May 2026 17:38:53 +0100 Subject: [PATCH 231/234] adding the test in PreImagesRepresentative --- lib/mapping.gd | 6 ++--- lib/mapping.gi | 44 +++++++++++++++++------------------- tst/testinstall/gprdmat.tst | 4 ++-- tst/testinstall/grppc.tst | 2 +- tst/testinstall/mapphomo.tst | 2 +- tst/testinstall/mapping.tst | 4 ++-- tst/testinstall/vspchom.tst | 28 +++++++++++------------ 7 files changed, 44 insertions(+), 46 deletions(-) diff --git a/lib/mapping.gd b/lib/mapping.gd index ccfc21d242..8302a5d009 100644 --- a/lib/mapping.gd +++ b/lib/mapping.gd @@ -1070,11 +1070,11 @@ DeclareOperation( "PreImageElm", ## <#/GAPDoc> ## -## DeclareOperation( "PreImagesRepresentative", -## [ IsGeneralMapping, IsObject ] ); DeclareOperation( "PreImagesRepresentativeNC", [ IsGeneralMapping, IsObject ] ); -DeclareSynonym( "PreImagesRepresentative", PreImagesRepresentativeNC ); +## DeclareSynonym( "PreImagesRepresentative", PreImagesRepresentativeNC ); +DeclareOperation( "PreImagesRepresentative", + [ IsGeneralMapping, IsObject ] ); ############################################################################# ## diff --git a/lib/mapping.gi b/lib/mapping.gi index 99beb95a48..a5ecc6325e 100644 --- a/lib/mapping.gi +++ b/lib/mapping.gi @@ -1173,17 +1173,16 @@ InstallMethod( PreImagesRange, #M PreImagesRepresentative( , ) . . . for s.p. gen. mapping & elm #M PreImagesRepresentativeNC( , ) . . for s.p. gen. mapping & elm ## -## InstallMethod( PreImagesRepresentative, -## "for s.p. general mapping, and element", -## FamRangeEqFamElm, -## [ IsSPGeneralMapping, IsObject ], 0, -## function( map, elm ) -## test will be included at a later stage of the change of name -## if not elm in Image( map ) then -## return fail; -## fi; -## return PreImagesRepresentativeNC( map, elm ); -## end ); +InstallMethod( PreImagesRepresentative, + "for s.p. general mapping, and element", + FamRangeEqFamElm, + [ IsSPGeneralMapping, IsObject ], 0, + function( map, elm ) + if not elm in Image( map ) then + return fail; + fi; + return PreImagesRepresentativeNC( map, elm ); + end ); InstallMethod( PreImagesRepresentativeNC, "for s.p. general mapping, and element", @@ -1198,18 +1197,17 @@ InstallMethod( PreImagesRepresentativeNC, ## #M PreImagesRepresentative( , ) #M PreImagesRepresentativeNC( , ) -## -## InstallMethod( PreImagesRepresentative, -## "for total non-s.p. general mapping, and element", -## FamRangeEqFamElm, -## [ IsNonSPGeneralMapping, IsObject ], 0, -## function( map, elm ) -## test will be included at a later stage of the change of name -## if not elm in Image( map ) then -## return fail; -## fi; -## return PreImagesRepresentativeNC( map, elm ); -## end ); + +InstallMethod( PreImagesRepresentative, + "for total non-s.p. general mapping, and element", + FamRangeEqFamElm, + [ IsNonSPGeneralMapping, IsObject ], 0, + function( map, elm ) + if not elm in Image( map ) then + return fail; + fi; + return PreImagesRepresentativeNC( map, elm ); + end ); InstallMethod( PreImagesRepresentativeNC, "for total non-s.p. general mapping, and element", diff --git a/tst/testinstall/gprdmat.tst b/tst/testinstall/gprdmat.tst index 7e2e3100b2..8af5073eb5 100644 --- a/tst/testinstall/gprdmat.tst +++ b/tst/testinstall/gprdmat.tst @@ -47,9 +47,9 @@ gap> Size(Image(iota2 * pi1)); 1 # -gap> ForAll(G1, g -> PreImagesRepresentativeNC(iota1, ImagesRepresentative(iota1, g)) = g); +gap> ForAll(G1, g -> PreImagesRepresentative(iota1, ImagesRepresentative(iota1, g)) = g); true -gap> ForAll(G2, g -> PreImagesRepresentativeNC(iota2, ImagesRepresentative(iota2, g)) = g); +gap> ForAll(G2, g -> PreImagesRepresentative(iota2, ImagesRepresentative(iota2, g)) = g); true gap> Size(Images(pi1,KernelOfMultiplicativeGeneralMapping(pi1))); 1 diff --git a/tst/testinstall/grppc.tst b/tst/testinstall/grppc.tst index cd2af99324..873257c589 100644 --- a/tst/testinstall/grppc.tst +++ b/tst/testinstall/grppc.tst @@ -28,7 +28,7 @@ g3^g2 = g4 g4^g2 = g3*g4 all other pairs of generators commute gap> pcgs:=Pcgs(hh);; -gap> ForAll(pcgs,i->PreImagesRepresentativeNC(m,i) in h); +gap> ForAll(pcgs,i->PreImagesRepresentative(m,i) in h); true gap> g:=WreathProduct(Group((1,2,3),(1,2)),Group((1,2,3,4,5,6,7)));; gap> i:=IsomorphismPcGroup(g);; diff --git a/tst/testinstall/mapphomo.tst b/tst/testinstall/mapphomo.tst index ca1388b52d..d6468f7834 100644 --- a/tst/testinstall/mapphomo.tst +++ b/tst/testinstall/mapphomo.tst @@ -88,7 +88,7 @@ fail # Check that group homomorphisms created by a function can compute preimages. gap> for G in [ SymmetricGroup(5), DihedralGroup(8), GL(2,3) ] do > hom:= GroupHomomorphismByFunction( G, G, x -> x ); -> PreImagesRepresentativeNC( hom, G.1 ); +> PreImagesRepresentative( hom, G.1 ); > od; # diff --git a/tst/testinstall/mapping.tst b/tst/testinstall/mapping.tst index e3ac07646f..21b7f1b516 100644 --- a/tst/testinstall/mapping.tst +++ b/tst/testinstall/mapping.tst @@ -255,7 +255,7 @@ gap> PreImagesSetNC( map, [ 0*Z(3), Z(3) ] ); [ 0*Z(3), Z(3)^0 ] gap> PreImagesSetNC( map, GF(3) ); [ 0*Z(3), Z(3)^0 ] -gap> PreImagesRepresentativeNC( map, Z(3) ); +gap> PreImagesRepresentative( map, Z(3) ); Z(3)^0 # ImageElm, ImagesSet for IsMapping @@ -310,7 +310,7 @@ gap> PreImagesSetNC( map, [ 0*Z(3), Z(3) ] ); [ 0*Z(3), Z(3)^0 ] gap> PreImagesSetNC( map, GF(3) ); [ 0*Z(3), Z(3)^0, Z(3) ] -gap> PreImagesRepresentativeNC( map, Z(3) ); +gap> PreImagesRepresentative( map, Z(3) ); 0*Z(3) gap> ImagesSource( map ); [ 0*Z(3), Z(3)^0, Z(3) ] diff --git a/tst/testinstall/vspchom.tst b/tst/testinstall/vspchom.tst index 2cedaa8079..69920d91ab 100644 --- a/tst/testinstall/vspchom.tst +++ b/tst/testinstall/vspchom.tst @@ -31,9 +31,9 @@ gap> ImagesRepresentative( map1, 0*Z(3)^0 ); 0*Z(3) gap> ImagesRepresentative( map1, Z(3)^0 ); Z(3^3) -gap> PreImagesRepresentativeNC( map1, 0*Z(3) ); +gap> PreImagesRepresentative( map1, 0*Z(3) ); 0*Z(3) -gap> PreImagesRepresentativeNC( map1, Z(27) ); +gap> PreImagesRepresentative( map1, Z(27) ); Z(3)^0 gap> 2 * map1 = - map1; true @@ -60,9 +60,9 @@ gap> ImagesRepresentative( map2, Z(27) ); [ Z(3)^0, Z(3)^0 ] gap> ImagesRepresentative( map2, Z(9) ); fail -gap> PreImagesRepresentativeNC( map2, [ Z(3)^0, Z(3)^0 ] ); +gap> PreImagesRepresentative( map2, [ Z(3)^0, Z(3)^0 ] ); Z(3^3) -gap> PreImagesRepresentativeNC( map2, [ 0*Z(3)^0, 0*Z(3)^0 ] ); +gap> PreImagesRepresentative( map2, [ 0*Z(3)^0, 0*Z(3)^0 ] ); 0*Z(3) gap> 2 * map2 = - map2; true @@ -89,9 +89,9 @@ gap> ImagesRepresentative( map3, [ Z(3)^0, 0*Z(3)^0 ] ); Z(3)^0 gap> ImagesRepresentative( map3, [ 0*Z(3)^0, Z(3)^0 ] ); Z(3^3)^3 -gap> PreImagesRepresentativeNC( map3, Z(27) ); +gap> PreImagesRepresentative( map3, Z(27) ); [ Z(3)^0, Z(3)^0 ] -gap> PreImagesRepresentativeNC( map3, Z(3)^0 ); +gap> PreImagesRepresentative( map3, Z(3)^0 ); [ Z(3)^0, 0*Z(3) ] gap> 2 * map3 = - map3; true @@ -204,9 +204,9 @@ gap> ImagesRepresentative( map5, 0*Z(3)^0 ); 0*Z(3) gap> ImagesRepresentative( map5, Z(3)^0 ); Z(3^3)^19 -gap> PreImagesRepresentativeNC( map5, 0*Z(3) ); +gap> PreImagesRepresentative( map5, 0*Z(3) ); 0*Z(3) -gap> PreImagesRepresentativeNC( map5, Z(27) ); +gap> PreImagesRepresentative( map5, Z(27) ); fail gap> 2 * map5 = - map5; true @@ -232,9 +232,9 @@ gap> ImagesRepresentative( map6, Z(27) ); [ 0*Z(3), 0*Z(3) ] gap> ImagesRepresentative( map6, Z(9) ); fail -gap> PreImagesRepresentativeNC( map6, [ Z(3)^0, Z(3)^0 ] ); +gap> PreImagesRepresentative( map6, [ Z(3)^0, Z(3)^0 ] ); Z(3) -gap> PreImagesRepresentativeNC( map6, [ 0*Z(3)^0, 0*Z(3)^0 ] ); +gap> PreImagesRepresentative( map6, [ 0*Z(3)^0, 0*Z(3)^0 ] ); 0*Z(3) gap> 2 * map6 = - map6; true @@ -260,9 +260,9 @@ gap> ImagesRepresentative( map7, [ Z(3)^0, 0*Z(3)^0 ] ); Z(3^3)^21 gap> ImagesRepresentative( map7, [ 0*Z(3)^0, Z(3)^0 ] ); Z(3^3)^21 -gap> PreImagesRepresentativeNC( map7, Z(27) ); +gap> PreImagesRepresentative( map7, Z(27) ); fail -gap> PreImagesRepresentativeNC( map7, Z(3)^0 ); +gap> PreImagesRepresentative( map7, Z(3)^0 ); fail gap> 2 * map7 = - map7; true @@ -365,9 +365,9 @@ gap> ImagesRepresentative( nathom, [ Z(3), Z(3)^0 ] ); [ Z(3)^0 ] gap> ImagesRepresentative( nathom, [ Z(3)^0, Z(3)^0 ] ); [ 0*Z(3) ] -gap> PreImagesRepresentativeNC( nathom, [ Z(3)^0 ] ); +gap> PreImagesRepresentative( nathom, [ Z(3)^0 ] ); [ Z(3)^0, 0*Z(3) ] -gap> PreImagesRepresentativeNC( nathom, [ 0*Z(3) ] ); +gap> PreImagesRepresentative( nathom, [ 0*Z(3) ] ); [ 0*Z(3), 0*Z(3) ] gap> 2 * nathom = - nathom; true From fedaabc1f7c193af01dfc8dce86ee2e2712eff92 Mon Sep 17 00:00:00 2001 From: cdwensley Date: Wed, 13 May 2026 19:12:11 +0100 Subject: [PATCH 232/234] added methods for PreImagesSet --- lib/mapping.gd | 3 ++- lib/mapping.gi | 28 +++++++++++++++++++++++++++- 2 files changed, 29 insertions(+), 2 deletions(-) diff --git a/lib/mapping.gd b/lib/mapping.gd index 8302a5d009..4f76df05de 100644 --- a/lib/mapping.gd +++ b/lib/mapping.gd @@ -1113,7 +1113,8 @@ DeclareOperation( "PreImagesRepresentative", ## <#/GAPDoc> ## DeclareOperation( "PreImagesSetNC", [ IsGeneralMapping, IsListOrCollection ] ); -DeclareSynonym( "PreImagesSet", PreImagesSetNC ); +## DeclareSynonym( "PreImagesSet", PreImagesSetNC ); +DeclareOperation( "PreImagesSet", [ IsGeneralMapping, IsListOrCollection ] ); ############################################################################# diff --git a/lib/mapping.gi b/lib/mapping.gi index a5ecc6325e..1055ec1b0b 100644 --- a/lib/mapping.gi +++ b/lib/mapping.gi @@ -1136,12 +1136,38 @@ InstallMethod( PreImagesSetNC, return primgs; end ); +InstallMethod( PreImagesSet, + "for general mapping, and finite collection", + CollFamRangeEqFamElms, + [ IsGeneralMapping, IsCollection ], 0, + function( map, elms ) + local im, elm; + if not IsFinite( elms ) then + TryNextMethod(); + fi; + im:= Image( map ); + for elm in Enumerator( elms ) do + if not (elm in im ) then + return fail; + fi; + od; + return PreImagesSet( map, elms ); + end ); + InstallMethod( PreImagesSetNC, "for general mapping, and empty list", true, [ IsGeneralMapping, IsList and IsEmpty ], 0, function( map, elms ) - return []; + return []; + end ); + +InstallMethod( PreImagesSet, + "for general mapping, and empty list", + true, + [ IsGeneralMapping, IsList and IsEmpty ], 0, + function( map, elms ) + return []; end ); From 201f2b9496d8022ed65c33145eb33339e360b557 Mon Sep 17 00:00:00 2001 From: cdwensley Date: Wed, 13 May 2026 21:19:34 +0100 Subject: [PATCH 233/234] added methods for PreImagesElm and PreImagesSet --- lib/mapping.gd | 3 ++- lib/mapping.gi | 32 ++++++++++++++++++++++++++++---- tst/testinstall/mapping.tst | 8 ++++---- 3 files changed, 34 insertions(+), 9 deletions(-) diff --git a/lib/mapping.gd b/lib/mapping.gd index 4f76df05de..10cdf31da0 100644 --- a/lib/mapping.gd +++ b/lib/mapping.gd @@ -1003,7 +1003,8 @@ DeclareGlobalFunction( "Images" ); ## <#/GAPDoc> ## DeclareOperation( "PreImagesElmNC", [ IsGeneralMapping, IsObject ] ); -DeclareSynonym( "PreImagesElm", PreImagesElmNC ); +## DeclareSynonym( "PreImagesElm", PreImagesElmNC ); +DeclareOperation( "PreImagesElm", [ IsGeneralMapping, IsObject ] ); ############################################################################# diff --git a/lib/mapping.gi b/lib/mapping.gi index 1055ec1b0b..db3756cd02 100644 --- a/lib/mapping.gi +++ b/lib/mapping.gi @@ -1075,6 +1075,7 @@ InstallMethod( PreImageElm, ############################################################################# ## #M PreImagesElmNC( , ) . . . . . for general mapping and element +#M PreImagesElm( , ) . . . . . . for general mapping and element ## ## more or less delegate to `ImagesElm' ## @@ -1095,10 +1096,24 @@ InstallMethod( PreImagesElmNC, fi; end ); +InstallMethod( PreImagesElm, + "for general mapping with finite source, and element", + FamRangeEqFamElm, + [ IsGeneralMapping, IsObject ], 0, + function ( map, elm ) + + if not ( elm in Image( map ) ) then + return fail; + else + return PreImagesElmNC( map, elm ); + fi; + end ); + ############################################################################# ## #M PreImagesElmNC( , ) for const. time access gen. map., and elm. +#M PreImagesElm( , ) . for const. time access gen. map., and elm. ## InstallMethod( PreImagesElmNC, "for constant time access general mapping, and element", @@ -1115,6 +1130,18 @@ InstallMethod( PreImagesElmNC, return preimgs; end ); +InstallMethod( PreImagesElm, + "for constant time access general mapping, and element", + FamRangeEqFamElm, + [ IsGeneralMapping and IsConstantTimeAccessGeneralMapping, IsObject ], 0, + function( map, elm ) + if not ( elm in Image( map ) ) then + return fail; + else + return PreImagesElmNC( map, elm ); + fi; + end ); + ############################################################################# ## @@ -1126,9 +1153,6 @@ InstallMethod( PreImagesSetNC, [ IsGeneralMapping, IsCollection ], 0, function( map, elms ) local primgs, elm; - if not IsFinite( elms ) then - TryNextMethod(); - fi; primgs:= []; for elm in Enumerator( elms ) do UniteSet( primgs, AsList( PreImagesElmNC( map, elm ) ) ); @@ -1151,7 +1175,7 @@ InstallMethod( PreImagesSet, return fail; fi; od; - return PreImagesSet( map, elms ); + return PreImagesSetNC( map, elms ); end ); InstallMethod( PreImagesSetNC, diff --git a/tst/testinstall/mapping.tst b/tst/testinstall/mapping.tst index 21b7f1b516..b91f172626 100644 --- a/tst/testinstall/mapping.tst +++ b/tst/testinstall/mapping.tst @@ -251,9 +251,9 @@ gap> PreImageElm( map, Z(3) ); Z(3)^0 gap> PreImagesElmNC( map, Z(3) ); [ Z(3)^0 ] -gap> PreImagesSetNC( map, [ 0*Z(3), Z(3) ] ); +gap> PreImagesSet( map, [ 0*Z(3), Z(3) ] ); [ 0*Z(3), Z(3)^0 ] -gap> PreImagesSetNC( map, GF(3) ); +gap> PreImagesSet( map, GF(3) ); [ 0*Z(3), Z(3)^0 ] gap> PreImagesRepresentative( map, Z(3) ); Z(3)^0 @@ -306,9 +306,9 @@ gap> PreImageElm( map, Z(3) ); 0*Z(3) gap> PreImagesElmNC( map, Z(3) ); [ 0*Z(3) ] -gap> PreImagesSetNC( map, [ 0*Z(3), Z(3) ] ); +gap> PreImagesSet( map, [ 0*Z(3), Z(3) ] ); [ 0*Z(3), Z(3)^0 ] -gap> PreImagesSetNC( map, GF(3) ); +gap> PreImagesSet( map, GF(3) ); [ 0*Z(3), Z(3)^0, Z(3) ] gap> PreImagesRepresentative( map, Z(3) ); 0*Z(3) From 839af79a7f2e43d6aadcf894db543f8596c4a2fa Mon Sep 17 00:00:00 2001 From: cdwensley Date: Wed, 13 May 2026 21:51:49 +0100 Subject: [PATCH 234/234] added method for PreImages --- lib/mapping.gd | 3 +- lib/mapping.gi | 55 +++++++++++++++++++++++++++++++++++++ tst/testinstall/mapping.tst | 13 ++++++--- 3 files changed, 66 insertions(+), 5 deletions(-) diff --git a/lib/mapping.gd b/lib/mapping.gd index 10cdf31da0..12fa690506 100644 --- a/lib/mapping.gd +++ b/lib/mapping.gd @@ -1247,7 +1247,8 @@ DeclareGlobalFunction( "PreImage" ); ## <#/GAPDoc> ## DeclareGlobalFunction( "PreImagesNC" ); -DeclareSynonym( "PreImages", PreImagesNC ); +## DeclareSynonym( "PreImages", PreImagesNC ); +DeclareGlobalFunction( "PreImages" ); ############################################################################# diff --git a/lib/mapping.gi b/lib/mapping.gi index db3756cd02..75ef3daf93 100644 --- a/lib/mapping.gi +++ b/lib/mapping.gi @@ -359,6 +359,61 @@ InstallGlobalFunction( PreImagesNC, function ( arg ) "PreImagesNC(,)" ); end ); +InstallGlobalFunction( PreImages, function ( arg ) + + local map, # mapping , first argument + img; # element , second argument + + # preimage of the range under + if Length( arg ) = 1 then + + return PreImagesRange( arg[1] ); + + elif Length( arg ) = 2 then + + map := arg[1]; + img := arg[2]; + + if not IsGeneralMapping( map ) then + ErrorNoReturn( " must be a general mapping" ); + fi; + + # preimage of a single element under + if FamRangeEqFamElm( FamilyObj( map ), FamilyObj( img ) ) then + if not img in Range( map ) then + ErrorNoReturn( " must be an element of Range()" ); + fi; + return PreImagesElm( map, img ); + + # preimage of a collection of elements under + elif CollFamRangeEqFamElms( FamilyObj( map ), FamilyObj( img ) ) then + if not IsSubset( Range( map ), img ) then + ErrorNoReturn( "the collection must be contained in ", + "Range()" ); + fi; + + if IsDomain( img ) or IsSSortedList( img ) then + return PreImagesSet( map, img ); + elif IsHomogeneousList( img ) then + return PreImagesSet( map, Set( img ) ); + fi; + + # preimage of the empty list + elif IsList( img ) and IsEmpty( img ) then + + return []; + + else + ErrorNoReturn( "the families of the element or collection ", + "and Range() don't match, ", + "maybe is not contained in Range() or ", + "is not a homogeneous list or collection" ); + fi; + fi; + ErrorNoReturn( "usage: PreImages(), PreImages(,), ", + "PreImages(,)" ); +end ); + ############################################################################# ## #F CompositionMapping(,, ... ) . . . . . composition of mappings diff --git a/tst/testinstall/mapping.tst b/tst/testinstall/mapping.tst index b91f172626..99eab51aa6 100644 --- a/tst/testinstall/mapping.tst +++ b/tst/testinstall/mapping.tst @@ -231,6 +231,11 @@ gap> ImagesRepresentative( map, Z(3) ); Z(3)^0 gap> (0*Z(3)) ^ map; 0*Z(3) +gap> ## test new PreImagesRepresentative +gap> PreImagesRepresentative( map, Z(3) ); +fail +gap> PreImagesRepresentative( map, Z(3)^0 ); +Z(3) # PreImage(s)Elm, PreImagesSet for # bijective but neither IsSingleValued nor IsTotal @@ -389,13 +394,13 @@ match, maybe is not contained in Range() or is not a homogeneous li\ st or collection # PreImages -gap> PreImagesNC(x -> x, 1); +gap> PreImages(x -> x, 1); Error, must be a general mapping -gap> PreImagesNC(mapBijective, Z(9)); +gap> PreImages(mapBijective, Z(9)); Error, must be an element of Range() -gap> PreImagesNC(mapBijective, [Z(3), Z(9)]); +gap> PreImages(mapBijective, [Z(3), Z(9)]); Error, the collection must be contained in Range() -gap> PreImagesNC(mapBijective, Z(5)); +gap> PreImages(mapBijective, Z(5)); Error, the families of the element or collection and Range() don't \ match, maybe is not contained in Range() or is not a homogeneous li\ st or collection