From 27d453416a768ddb04a211a8a0273459b19bf4e1 Mon Sep 17 00:00:00 2001 From: ThomasBreuer Date: Thu, 22 Jan 2026 14:22:59 +0100 Subject: [PATCH 1/2] 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) --- grp/classic.gi | 138 +++++++++++++------ grp/ree.gi | 2 +- grp/suzuki.gi | 2 +- lib/grpffmat.gi | 35 +---- lib/grpmat.gd | 137 +++++++++++++------ lib/grpmat.gi | 56 ++++++-- tst/testinstall/grp/classic-forms.tst | 186 +++++++++++++++++++++----- 7 files changed, 399 insertions(+), 157 deletions(-) diff --git a/grp/classic.gi b/grp/classic.gi index 1298a58a50..b6c899bab8 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,22 @@ 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 ) = 0 then + # In earlier versions of GAP, no 'baseDomain' was stored. + Error( "the two argument variant of ", + "SetInvariantQuadraticFormFromMatrix is no longer supported" ); + fi; + SetInvariantQuadraticForm( g, rec( matrix:= mat, baseDomain:= F[1] ) ); + SetInvariantBilinearForm( g, rec( matrix:= mat+TransposedMat(mat), + baseDomain:= F[1] ) ); end ); @@ -392,6 +409,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 +418,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 +470,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 +479,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 +540,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 +549,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 +611,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 +619,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 +675,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 +684,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 +722,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 +762,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 +771,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 +874,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 +883,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 +943,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 +994,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 +1003,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 +1114,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 +1125,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 +1164,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 +1197,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 +1214,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 +1267,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 +1325,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 +1346,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 +1474,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 +1502,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 +1612,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 +1635,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 +1727,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 +1753,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 +1766,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 +1790,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 +1850,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 +1879,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 9c00e8c1b7..1ef97e1639 100644 --- a/lib/grpmat.gi +++ b/lib/grpmat.gi @@ -846,6 +846,7 @@ 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. return IsSubset( FieldOfMatrixGroup( G ), FieldOfMatrixList( [ mat ] ) ) and ( not IsSubgroupSL( G ) or IsOne( DeterminantMat( mat ) ) ) and RespectsQuadraticForm( InvariantQuadraticForm( G ).matrix, mat ); @@ -856,6 +857,7 @@ 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. if not IsSubset( FieldOfMatrixGroup( G ), FieldOfMatrixList( [ mat ] ) ) or ( IsSubgroupSL( G ) and not IsOne( DeterminantMat( mat ) ) ) then return false; @@ -868,13 +870,15 @@ 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. 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 +1278,7 @@ InstallMethod( InvariantBilinearForm, InstallMethod( ConjugateGroup, ", ", IsCollsElms, [ IsMatrixGroup, IsMultiplicativeElementWithInverse ], function( G, g ) - local H, m, ginv, nice, conj; + local H, F, form, m, D, ginv, pow, nice, conj; H := GroupByGenerators( OnTuples( GeneratorsOfGroup( G ), g ), One( G ) ); UseIsomorphismRelation( G, H ); @@ -1287,27 +1291,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 +1338,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; if HasNiceMonomorphism( G ) then nice := NiceMonomorphism( G ); diff --git a/tst/testinstall/grp/classic-forms.tst b/tst/testinstall/grp/classic-forms.tst index 908e0693c4..c23c7044df 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 # # 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,42 @@ 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 # gap> STOP_TEST("classic-forms.tst"); From 25fc5e5bf66a2103bd201846d59cd96c72f7a826 Mon Sep 17 00:00:00 2001 From: ThomasBreuer Date: Fri, 23 Jan 2026 16:05:33 +0100 Subject: [PATCH 2/2] address a comment --- grp/classic.gi | 6 +++--- tst/testinstall/grp/classic-forms.tst | 9 ++++++++- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/grp/classic.gi b/grp/classic.gi index b6c899bab8..d6c3b6c614 100644 --- a/grp/classic.gi +++ b/grp/classic.gi @@ -358,10 +358,10 @@ InstallMethod( SpecialUnitaryGroupCons, ## In both forms, set the 'baseDomain' component. ## BindGlobal( "SetInvariantQuadraticFormFromMatrix", function( g, mat, F... ) - if Length( F ) = 0 then + if Length( F ) <> 1 then # In earlier versions of GAP, no 'baseDomain' was stored. - Error( "the two argument variant of ", - "SetInvariantQuadraticFormFromMatrix is no longer supported" ); + Error( "only the three argument variant of ", + "SetInvariantQuadraticFormFromMatrix is supported" ); fi; SetInvariantQuadraticForm( g, rec( matrix:= mat, baseDomain:= F[1] ) ); SetInvariantBilinearForm( g, rec( matrix:= mat+TransposedMat(mat), diff --git a/tst/testinstall/grp/classic-forms.tst b/tst/testinstall/grp/classic-forms.tst index c23c7044df..94339ef7a8 100644 --- a/tst/testinstall/grp/classic-forms.tst +++ b/tst/testinstall/grp/classic-forms.tst @@ -4,7 +4,7 @@ #@local CheckMembershipBilinear, CheckMembershipBilinear2 #@local CheckMembershipSesquilinear #@local CheckMembershipQuadratic, CheckMembershipQuadratic2 -#@local grps1, grps2, grps, d, q +#@local grps1, grps2, grps, d, q, G, m # # Tests invariant forms of classic groups # @@ -338,5 +338,12 @@ 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 + # gap> STOP_TEST("classic-forms.tst");