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..8acaffc207 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,19 @@ 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 ) + 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 +327,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 +582,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 +614,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 7a1b99f4d4..ee52f8d303 100644 --- a/lib/matobjplist.gi +++ b/lib/matobjplist.gi @@ -1222,7 +1222,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 b98e8d9e1d..9853a7c978 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 c88e380f42..7483942761 100644 --- a/lib/modfree.gi +++ b/lib/modfree.gi @@ -175,23 +175,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; @@ -202,6 +204,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 fe1acea79d..d9d6b34a81 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( PreImagesRepresentative,"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,29 @@ end ); ## #M PreImagesRepresentative( , ) . . . . . . . . . . build matrix ## +## 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", 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 +3455,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 +3478,7 @@ function( hom, elm ) fi; fi; - return mat; + return MakeImmutable( mat ); end); ############################################################################# @@ -3467,18 +3488,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 +3513,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 +3562,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 +3570,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 +3606,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 +3622,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" );