From 7d3d0bba98357beca1411f9e21b6265891057f0f Mon Sep 17 00:00:00 2001 From: Max Horn Date: Wed, 10 Dec 2025 16:11:38 +0100 Subject: [PATCH] Reduce number of arguments of recognition methods Right now recognition methods take two arguments: `ri` and `G`. But `G` is always identical to `Grp(ri)`. Alas, not everyone will know this, e.g. I am re-discovering this every time I start digging into recog again. This can be very confusing ("why are both these groups around? Is there any subtle difference????"). One could solve that by trying to document this, but I think it is much better to just remove the second argument. --- gap/base/methods.gi | 4 ++- gap/base/methsel.gd | 7 ++--- gap/base/methsel.gi | 4 +-- gap/base/recognition.gi | 2 +- gap/matrix.gi | 57 ++++++++++++++++++----------------- gap/matrix/classical.gi | 67 +++++++++++++++++++++-------------------- 6 files changed, 71 insertions(+), 70 deletions(-) diff --git a/gap/base/methods.gi b/gap/base/methods.gi index 41400462c..2cf45cc51 100644 --- a/gap/base/methods.gi +++ b/gap/base/methods.gi @@ -86,8 +86,10 @@ end); InstallGlobalFunction(CallRecogMethod, function(m, args) + local f; if not IsRecogMethod(m) then ErrorNoReturn(" must be a RecogMethod, but is ", m); fi; - return CallFuncList(UnpackRecogMethod(m), args); + f := UnpackRecogMethod(m); + return f(ri) end); diff --git a/gap/base/methsel.gd b/gap/base/methsel.gd index 3f91b3e43..e59a22ba5 100644 --- a/gap/base/methsel.gd +++ b/gap/base/methsel.gd @@ -43,16 +43,13 @@ DeclareGlobalFunction( "AddMethod" ); ## <#GAPDoc Label="CallMethods"> ## -## +## ## a record ms describing this method selection procedure. ## ## ## The argument db must be a method database in the sense of ## Section . limit must be a non-negative -## integer. furtherargs stands for an arbitrary number of additional -## arguments, which are handed down to the called methods. Of course they -## must fulfill the conventions defined for the methods in the database -## db.

+## integer. Finally ri is a recognition node.

## The function first creates a method selection record keeping track ## of the things that happened during the method trying procedure, ## which is also used during this procedure. Then it calls methods with diff --git a/gap/base/methsel.gi b/gap/base/methsel.gi index 14485aceb..364016b63 100644 --- a/gap/base/methsel.gi +++ b/gap/base/methsel.gi @@ -50,7 +50,7 @@ end); # result : either fail or true # -InstallGlobalFunction( "CallMethods", function(db, tolerancelimit, methargs...) +InstallGlobalFunction( "CallMethods", function(db, tolerancelimit, ri) # First argument is a method database, i.e. list of records # describing recognition methods. # Second argument is a number, the tolerance limit. @@ -86,7 +86,7 @@ InstallGlobalFunction( "CallMethods", function(db, tolerancelimit, methargs...) # apply the method Info(InfoMethSel, 3, "Calling rank ", db[i].rank, " method \"", Stamp(db[i].method), "\"..."); - result := CallRecogMethod(db[i].method, methargs); + result := CallRecogMethod(db[i].method, ri); # evaluate the result if result = NeverApplicable then diff --git a/gap/base/recognition.gi b/gap/base/recognition.gi index a75e9ae19..f75cb7b25 100644 --- a/gap/base/recognition.gi +++ b/gap/base/recognition.gi @@ -486,7 +486,7 @@ InstallGlobalFunction( RecogniseGeneric, Assert(0, Length(Set(allmethods, m->m.rank)) = Length(allmethods)); # Find a possible homomorphism (or recognise this group as leaf) - Setfhmethsel(ri, CallMethods( allmethods, 10, ri, H )); + Setfhmethsel(ri, CallMethods( allmethods, 10, ri )); # TODO: extract the value 10 into a named constant, and / or make it # an option parameter to the func diff --git a/gap/matrix.gi b/gap/matrix.gi index 40d4df7b9..ed6ab9daa 100644 --- a/gap/matrix.gi +++ b/gap/matrix.gi @@ -26,16 +26,16 @@ end; #! @EndChunk BindRecogMethod(FindHomMethodsMatrix, "DiagonalMatrices", "check whether all generators are diagonal matrices", -function(ri, G) +function(ri) local H,d,f,gens,hom,i,isscalars,j,newgens,upperleft; d := ri!.dimension; if d = 1 then Info(InfoRecog,2,"Found dimension 1, going to Scalars method"); - return FindHomMethodsMatrix.Scalar(ri,G); + return FindHomMethodsMatrix.Scalar(ri); fi; - gens := GeneratorsOfGroup(G); + gens := GeneratorsOfGroup(Grp(ri)); if not ForAll(gens, IsDiagonalMat) then return NeverApplicable; fi; @@ -61,13 +61,13 @@ function(ri, G) # Note that we cannot tell the upper levels that they should better # have made some more generators for the kernel! - return FindHomMethodsMatrix.BlockScalar(ri,G); + return FindHomMethodsMatrix.BlockScalar(ri); fi; # Scalar matrices, so go to dimension 1: newgens := List(gens,x->ExtractSubMatrix(x,[1],[1])); H := Group(newgens); - hom := GroupHomByFuncWithData(G,H,RECOG.HomToScalars,rec(poss := [1])); + hom := GroupHomByFuncWithData(Grp(ri),H,RECOG.HomToScalars,rec(poss := [1])); SetHomom(ri,hom); findgensNmeth(ri).method := FindKernelDoNothing; @@ -128,7 +128,7 @@ end; #! @EndChunk BindRecogMethod(FindHomMethodsMatrix, "Scalar", "Hint TODO", -function(ri, G) +function(ri) local f,gcd,generator,gens,i,l,o,pows,q,rep,slp,subset,z; if ri!.dimension > 1 then return NotEnoughInformation; @@ -137,10 +137,10 @@ function(ri, G) # FIXME: FieldOfMatrixGroup f := ri!.field; o := One(f); - gens := List(GeneratorsOfGroup(G),x->x[1,1]); + gens := List(GeneratorsOfGroup(Grp(ri)),x->x[1,1]); subset := Filtered([1..Length(gens)], i -> not IsOne(gens[i])); if subset = [] then - return FindHomMethodsGeneric.TrivialGroup(ri,G); + return FindHomMethodsGeneric.TrivialGroup(ri); fi; gens := gens{subset}; q := Size(f); @@ -163,7 +163,7 @@ function(ri, G) Add(l,rep[i]); fi; od; - slp := StraightLineProgramNC([[l]],Length(GeneratorsOfGroup(G))); + slp := StraightLineProgramNC([[l]],Length(GeneratorsOfGroup(Grp(ri)))); Setslptonice(ri,slp); # this sets the nice generators Setslpforelement(ri,SLPforElementFuncsMatrix.DiscreteLog); ri!.generator := z^gcd; @@ -219,7 +219,7 @@ end; #! @EndChunk BindRecogMethod(FindHomMethodsMatrix, "BlockScalar", "Hint TODO", -function(ri, G) +function(ri) # We assume that ri!.blocks is a list of ranges where the non-trivial # scalar blocks are. Note that their length does not have to sum up to # the dimension, because some blocks at the end might already be trivial. @@ -228,9 +228,9 @@ function(ri, G) if nrblocks <= 2 then # the image is only one block # go directly to scalars in that case: data := rec(poss := ri!.blocks[nrblocks]); - newgens := List(GeneratorsOfGroup(G),x->RECOG.HomToDiagonalBlock(data,x)); + newgens := List(GeneratorsOfGroup(Grp(ri)),x->RECOG.HomToDiagonalBlock(data,x)); H := GroupWithGenerators(newgens); - hom := GroupHomByFuncWithData(G,H,RECOG.HomToDiagonalBlock,data); + hom := GroupHomByFuncWithData(Grp(ri),H,RECOG.HomToDiagonalBlock,data); SetHomom(ri,hom); AddMethod(InitialDataForImageRecogNode(ri).hints, FindHomMethodsMatrix.Scalar, 2000); @@ -255,9 +255,9 @@ function(ri, G) middle := QuoInt(nrblocks,2)+1; # the first one taken topblock := ri!.blocks[nrblocks]; data := rec(poss := [ri!.blocks[middle][1]..topblock[Length(topblock)]]); - newgens := List(GeneratorsOfGroup(G),x->RECOG.HomToDiagonalBlock(data,x)); + newgens := List(GeneratorsOfGroup(Grp(ri)),x->RECOG.HomToDiagonalBlock(data,x)); H := GroupWithGenerators(newgens); - hom := GroupHomByFuncWithData(G,H,RECOG.HomToDiagonalBlock,data); + hom := GroupHomByFuncWithData(Grp(ri),H,RECOG.HomToDiagonalBlock,data); SetHomom(ri,hom); # the image are the last few blocks: @@ -378,11 +378,11 @@ BindRecogMethod(FindHomMethodsMatrix, "ReducibleIso", "use the MeatAxe to find invariant subspaces", # alternative comment: #"use MeatAxe to find a composition series, do base change", -function(ri,G) +function(ri) # First we use the MeatAxe to find an invariant subspace: local H,bc,compseries,f,hom,isirred,m,newgens; - RECOG.SetPseudoRandomStamp(G,"ReducibleIso"); + RECOG.SetPseudoRandomStamp(Grp(ri),"ReducibleIso"); if IsBound(ri!.isabsolutelyirred) and ri!.isabsolutelyirred then # this information is coming from above @@ -409,9 +409,9 @@ function(ri,G) List(bc.blocks,Length)," (dim=",ri!.dimension,")"); # Do the base change: - newgens := List(GeneratorsOfGroup(G),x->bc.base*x*bc.baseinv); + newgens := List(GeneratorsOfGroup(Grp(ri)),x->bc.base*x*bc.baseinv); H := GroupWithGenerators(newgens); - hom := GroupHomByFuncWithData(G,H,RECOG.HomDoBaseChange, + hom := GroupHomByFuncWithData(Grp(ri),H,RECOG.HomDoBaseChange, rec(t := bc.base,ti := bc.baseinv)); # Now report back: @@ -481,17 +481,17 @@ end; #! @EndChunk BindRecogMethod(FindHomMethodsMatrix, "BlockLowerTriangular", "for a group generated by block lower triangular matrices", -function(ri,G) +function(ri) # This is only used coming from a hint, we know what to do: # A base change was done to get block lower triangular shape. # We first do the diagonal blocks, then the lower p-part: local H,data,hom,newgens; data := rec( blocks := ri!.blocks ); - newgens := List(GeneratorsOfGroup(G), + newgens := List(GeneratorsOfGroup(Grp(ri)), x->RECOG.HomOntoBlockDiagonal(data,x)); Assert(0, not fail in newgens); H := GroupWithGenerators(newgens); - hom := GroupHomByFuncWithData(G,H,RECOG.HomOntoBlockDiagonal,data); + hom := GroupHomByFuncWithData(Grp(ri),H,RECOG.HomOntoBlockDiagonal,data); SetHomom(ri,hom); # Now give hints downward: @@ -526,12 +526,12 @@ end); #! @EndChunk BindRecogMethod(FindHomMethodsMatrix, "BlockDiagonal", "for groups generated by block diagonal matrices", -function(ri,G) +function(ri) # This is only called by a hint, so we know what we have to do: # We do all the blocks projectively and thus are left with scalar blocks. # In the projective case we still do the same, the BlocksModScalars # will automatically take care of the projectiveness! - SetHomom(ri, IdentityMapping(G)); + SetHomom(ri, IdentityMapping(Grp(ri))); # Now give hints downward: InitialDataForImageRecogNode(ri).blocks := ri!.blocks; AddMethod(InitialDataForImageRecogNode(ri).hints, FindHomMethodsProjective.BlocksModScalars, 2000); @@ -782,7 +782,7 @@ end; #! @EndChunk BindRecogMethod(FindHomMethodsMatrix, "LowerLeftPGroup", "Hint TODO", -function(ri,G) +function(ri) local f,p; # Do we really have our favorite situation? if not (IsBound(ri!.blocks) and @@ -812,10 +812,10 @@ end); #! @EndChunk BindRecogMethod(FindHomMethodsMatrix, "GoProjective", "divide out scalars and recognise projectively", -function(ri,G) +function(ri) local hom,q; Info(InfoRecog,2,"Going projective..."); - hom := IdentityMapping(G); + hom := IdentityMapping(Grp(ri)); SetHomom(ri,hom); # Now give hints downward: Setmethodsforimage(ri,FindHomDbProjective); @@ -841,8 +841,9 @@ end); #! @EndChunk BindRecogMethod(FindHomMethodsMatrix, "KnownStabilizerChain", "use an already known stabilizer chain for this group", -function(ri,G) - local S,hom; +function(ri) + local S,hom,G; + G := Grp(ri); if HasStoredStabilizerChain(G) then Info(InfoRecog,2,"Already know stabilizer chain, using 1st orbit."); S := StoredStabilizerChain(G); diff --git a/gap/matrix/classical.gi b/gap/matrix/classical.gi index c51ae28c6..d574fb857 100644 --- a/gap/matrix/classical.gi +++ b/gap/matrix/classical.gi @@ -144,7 +144,7 @@ end; # TODO: Better comments... BindRecogMethod(FindHomMethodsClassical, "IsGenericParameters", "tests whether group has generic parameters", -function( recognise, grp ) +function( recognise ) local fact, d, q, hint; hint := recognise.hint; @@ -217,7 +217,7 @@ end); BindRecogMethod(FindHomMethodsClassical, "IsGeneric", "tests whether group is generic", -function (recognise, grp) +function(recognise) if recognise.isGeneric = false then return NeverApplicable; fi; @@ -236,7 +236,7 @@ end); #TODO: comments... BindRecogMethod(FindHomMethodsClassical, "RuledOutExtField", "tests whether extension field case is ruled out", -function (recognise, grp) +function(recognise) local differmodfour, d, q, E, b, bx, hint; hint := recognise.hint; @@ -341,7 +341,7 @@ end); BindRecogMethod(FindHomMethodsClassical, "IsNotAlternating", "tests whether alternating groups are ruled out", -function( recognise, grp ) +function(recognise) local V, P, i, g ,q, o; q := recognise.q; @@ -365,7 +365,7 @@ function( recognise, grp ) fi; if q = 2 then - if Size(grp) <> 2520 then # 2520 = 3*4*5*6*7 = |A7| + if Size(recognise.grp) <> 2520 then # 2520 = 3*4*5*6*7 = |A7| Info( InfoClassical, 2, "G is not an alternating group" ); recognise.isNotAlternating := true; return false; @@ -409,7 +409,7 @@ end); BindRecogMethod(FindHomMethodsClassical, "IsNotMathieu", "tests whether Mathieu groups are ruled out", -function( recognise, grp ) +function(recognise) local i, fn, g, d, q, E, ord; d := recognise.d; @@ -480,7 +480,7 @@ end); BindRecogMethod(FindHomMethodsClassical, "IsNotPSL", "tests whether PSL groups are ruled out", -function (recognise, grp) +function(recognise) local i, E, LE, d, p, a, q, str, fn, ord; E := recognise.E; @@ -620,11 +620,11 @@ end; # generate the next random element and its char polynomial BindRecogMethod(FindHomMethodsClassical, "TestRandomElement", "makes new random element and stores it and its char poly", -function(recognise, grp) +function(recognise) local g, ppd, bppd, d, q, cpol, f, deg, facs, r, s, h, gmod, str, ord, bc, phi, kf, o1, o2, cf, i, found, p; - recognise.g := PseudoRandom(grp); + recognise.g := PseudoRandom(recognise.grp); recognise.cpol := CharacteristicPolynomial(recognise.g); recognise.n := recognise.n + 1; @@ -846,7 +846,7 @@ end); # the characteristic polynomial BindRecogMethod(FindHomMethodsClassical, "IsReducible", "tests whether current random element rules out reducible", -function( recognise, grp ) +function(recognise) local deg, dims, g; # compute the degrees of the irreducible factors @@ -876,9 +876,9 @@ end); BindRecogMethod(FindHomMethodsClassical, "NoClassicalForms", "tests whether we can rule out certain forms", -function( recognise, grp ) +function(recognise) local d,field; - PossibleClassicalForms( grp, recognise.g, recognise ); + PossibleClassicalForms( recognise.grp, recognise.g, recognise ); d := recognise.d; field := recognise.field; @@ -899,7 +899,7 @@ end); BindRecogMethod(FindHomMethodsClassical, "ClassicalForms", "Find the invariant forms", -function( recognise, grp) +function(recognise) local field, z, d, i, qq, A, c, I, t, i0, a, l, g, module, forms, dmodule, fmodule, form; @@ -939,7 +939,7 @@ function( recognise, grp) # now try to find an invariant form if recognise.maybeDual then - dmodule := ClassicalForms_GeneratorsWithoutScalarsDual(grp); + dmodule := ClassicalForms_GeneratorsWithoutScalarsDual(recognise.grp); if dmodule <> false then form := ClassicalForms_InvariantFormDual(module,dmodule); if form <> false then @@ -957,7 +957,7 @@ function( recognise, grp) fi; if recognise.maybeFrobenius then - fmodule := ClassicalForms_GeneratorsWithoutScalarsFrobenius(grp); + fmodule := ClassicalForms_GeneratorsWithoutScalarsFrobenius(recognise.grp); if fmodule <> false then form := ClassicalForms_InvariantFormFrobenius(module,fmodule); if form <> false then @@ -987,7 +987,7 @@ end); BindRecogMethod(FindHomMethodsClassical, "MeatAxe", "Test irreducibility", -function( recognise, grp ) +function(recognise) if recognise.n > 15 then recognise.needMeataxe := true; fi; @@ -1015,7 +1015,7 @@ end); ## Main function to test whether group contains SL BindRecogMethod(FindHomMethodsClassical, "IsSLContained", "tests whether group contains SL", -function( recognise, grp ) +function(recognise) if recognise.isGeneric <> true or recognise.isNotExt <> true or recognise.isNotPSL <> true or @@ -1058,7 +1058,7 @@ end); ## Main function to test whether group contains Sp BindRecogMethod(FindHomMethodsClassical, "IsSpContained", "tests whether group contains Sp", -function( recognise, grp ) +function(recognise) local isSpForm; isSpForm := f -> IsSesquilinearForm(f) and IsSymplecticForm(f); @@ -1116,7 +1116,7 @@ end); ## Main function to test whether group contains SU BindRecogMethod(FindHomMethodsClassical, "IsSUContained", "tests whether group contains SU", -function( recognise, grp ) +function(recognise) local f, isHermForm, q0; isHermForm := f -> IsSesquilinearForm(f) and IsHermitianForm(f); @@ -1180,7 +1180,7 @@ end); ## Main function to test whether group contains SO BindRecogMethod(FindHomMethodsClassical, "IsSOContained", "tests whether group contains SO", -function( recognise, grp ) +function(recognise) local f, isParForm, isEllForm, isHypForm; isParForm := f -> IsSesquilinearForm(f) and IsParabolicForm(f); @@ -1292,7 +1292,7 @@ end; ############################################################################/ ## -## NonGenericLinear (recognise, grp) . . . . . . . non-generic linear case +## NonGenericLinear ## ## Recognise non-generic linear matrix groups over finite fields: ## In order to prove that a group G <= GL( 3, 2^s-1) contains SL, we need to @@ -1301,7 +1301,7 @@ end; ## BindRecogMethod(FindHomMethodsClassical, "NonGenericLinear", "tests whether group is non-generic Linear", -function( recognise, grp ) +function(recognise) local CheckFlag; CheckFlag := function( ) @@ -1358,7 +1358,7 @@ end); ## BindRecogMethod(FindHomMethodsClassical, "NonGenericSymplectic", "tests whether group is non-generic Symplectic", -function(recognise, grp) +function(recognise) local d, q, CheckFlag, isSpForm; isSpForm := f -> IsSesquilinearForm(f) and IsSymplecticForm(f); @@ -1429,7 +1429,7 @@ function(recognise, grp) return fail; fi; elif d = 4 and q = 2 then - if Size(grp) mod 720 <> 0 then + if Size(recognise.grp) mod 720 <> 0 then Info(InfoClassical,2,"group does not contain Sp(", recognise.d, ", ", recognise.q, ");"); recognise.isSpContained := false; @@ -1478,7 +1478,7 @@ end); ## BindRecogMethod(FindHomMethodsClassical, "NonGenericUnitary", "tests whether group is non-generic Unitary", -function(recognise, grp) +function(recognise) local d, q, g, f1, f2, o, CheckFlag, isHermForm, str; isHermForm := f -> IsSesquilinearForm(f) and IsHermitianForm(f); @@ -1596,7 +1596,7 @@ function(recognise, grp) return CheckFlag(); fi; elif d = 3 and q = 4 then - if Order(grp) mod 216 = 0 then + if Order(recognise.grp) mod 216 = 0 then return CheckFlag(); else recognise.isSUContained := false; @@ -1610,7 +1610,7 @@ function(recognise, grp) if not Order( recognise.g ) mod 6 = 0 then return fail; fi; - if ForAny( GeneratorsOfGroup(grp), + if ForAny( GeneratorsOfGroup(recognise.grp), h -> not IsOne(Comm(h,recognise.g^3))) then Info( InfoClassical,2, "Cube of element of order div by 6 is not central" ); @@ -1627,7 +1627,7 @@ function(recognise, grp) if not Order(recognise.g) mod 5 = 0 then return fail; fi; - if ForAny(GeneratorsOfGroup(grp), h -> not IsOne(Comm(h,recognise.g))) then + if ForAny(GeneratorsOfGroup(recognise.grp), h -> not IsOne(Comm(h,recognise.g))) then Info( InfoClassical,2, "The element of order 5 is not central" ); recognise.hasSpecialEle := true; @@ -1644,7 +1644,7 @@ function(recognise, grp) return fail; fi; g := recognise.g^(Order(recognise.g)/2); - if ForAny(GeneratorsOfGroup(grp), h -> not IsOne(Comm(h,g))) then + if ForAny(GeneratorsOfGroup(recognise.grp), h -> not IsOne(Comm(h,g))) then Info( InfoClassical,2, "involution in cyclic subgroup of order 8 is not central" ); recognise.hasSpecialEle := true; @@ -1686,7 +1686,7 @@ end); BindRecogMethod(FindHomMethodsClassical, "NonGenericOrthogonalPlus", "tests whether group is non-generic O+", -function(recognise,grp) +function(recognise) local d, q, gp1, gp2, CheckFlag, pgrp, orbs, isHypForm; isHypForm := f -> IsSesquilinearForm(f) and IsHyperbolicForm(f); @@ -1920,7 +1920,7 @@ end); BindRecogMethod(FindHomMethodsClassical, "NonGenericOrthogonalMinus", "tests whether group is non-generic O-", -function(recognise, grp) +function(recognise) local d, q, orbs, pgrp, h, g, ppd, CheckFlag, isEllForm; @@ -2029,7 +2029,7 @@ end); BindRecogMethod(FindHomMethodsClassical, "NonGenericOrthogonalCircle", "tests whether group is non-generic Oo", -function( recognise, grp ) +function(recognise) local d, q, g, s, CheckFlag, isParForm; isParForm := f -> IsSesquilinearForm(f) and IsParabolicForm(f); @@ -2263,6 +2263,7 @@ function( arg ) f := FieldOfMatrixGroup(grp); q := Characteristic(f)^DegreeOverPrimeField(f); recognise := rec( field := f, + grp := grp, d := DimensionOfMatrixGroup(grp), p := Characteristic(f), a := DegreeOverPrimeField(f), @@ -2316,7 +2317,7 @@ function( arg ) ); merkinfolevel := InfoLevel(InfoMethSel); SetInfoLevel(InfoMethSel,0); - ret := CallMethods( ClassicalMethDb, nrrandels, recognise, grp ); + ret := CallMethods( ClassicalMethDb, nrrandels, recognise ); SetInfoLevel(InfoMethSel,merkinfolevel); # fail: bedeutet, dass entnervt aufgegeben wurde # true: bedeutet, dass eine Methode "erfolgreich" war