diff --git a/doc/ref/matobj.xml b/doc/ref/matobj.xml index 2818815902..de2be4121b 100644 --- a/doc/ref/matobj.xml +++ b/doc/ref/matobj.xml @@ -348,6 +348,16 @@ and for those methods of that do not delegate to and , respectively. +

+ +For the implementation of new vector and matrix object types, +we recommend that the low level function gets called +only by some helper functions that handle the choice of the type of +the desired object and the consistency checks for the internal data. +An example can be found in the file lib/matobjplist.gi, +the helper functions are MakeIsPlistVectorRep and +MakeIsPlistMatrixRep. + diff --git a/hpcgap/lib/vec8bit.gi b/hpcgap/lib/vec8bit.gi index 1e9bdd5b4d..3460e4f624 100644 --- a/hpcgap/lib/vec8bit.gi +++ b/hpcgap/lib/vec8bit.gi @@ -1139,10 +1139,16 @@ InstallMethod( BaseField, "for a compressed 8bit vector", InstallTagBasedMethod( NewVector, Is8BitVectorRep, function( filter, f, l ) - if ValueOption( "check" ) <> false and not Size(f) in [3..256] then + local check, res; + check:= ValueOption( "check" ) <> false; + if check and not Size(f) in [3..256] then Error("Is8BitVectorRep only supports base fields with 3 to 256 elements"); fi; - return CopyToVectorRep(l,Size(f)); + res:= CopyToVectorRep( l, Size( f ) ); + if check and res = fail then + Error( "cannot copy to 'Is8BitVectorRep'" ); + fi; + return res; end ); # This is faster than the default method. @@ -1176,7 +1182,9 @@ InstallTagBasedMethod( NewMatrix, else m := List(l,ShallowCopy); fi; - ConvertToMatrixRep(m,Size(f)); + if ConvertToMatrixRep( m, Size( f ) ) = fail then + Error( "cannot convert to 'Is8BitMatrixRep'" ); + fi; return m; end ); diff --git a/hpcgap/lib/vecmat.gi b/hpcgap/lib/vecmat.gi index 6c24ce83ec..c975b70651 100644 --- a/hpcgap/lib/vecmat.gi +++ b/hpcgap/lib/vecmat.gi @@ -2561,8 +2561,13 @@ InstallMethod( BaseField, "for a compressed gf2 vector", InstallTagBasedMethod( NewVector, IsGF2VectorRep, function( filter, f, l ) + local res; if Size(f) <> 2 then Error("IsGF2VectorRep only supported over GF(2)"); fi; - return CopyToVectorRep(l,2); + res:= CopyToVectorRep( l, 2 ); + if res = fail then + Error( "cannot copy to 'IsGF2VectorRep'" ); + fi; + return res; end ); InstallTagBasedMethod( NewZeroVector, @@ -2589,7 +2594,9 @@ InstallTagBasedMethod( NewMatrix, else m := List(l,ShallowCopy); fi; - ConvertToMatrixRep(m,2); + if ConvertToMatrixRep( m, 2 ) = fail then + Error( "cannot convert to 'IsGF2MatrixRep'" ); + fi; return m; end ); diff --git a/lib/matobj.gi b/lib/matobj.gi index 652dddccad..4360902bf7 100644 --- a/lib/matobj.gi +++ b/lib/matobj.gi @@ -1479,7 +1479,14 @@ InstallMethod( ZeroSameMutability, InstallMethod( OneMutable, [ IsMatrixObj ], - M -> IdentityMatrix( NumberRows( M ), M ) ); + function( M ) + local nrows; + nrows:= NrRows( M ); + if nrows <> NrCols( M ) then + Error( " must be square (not ", nrows, " by ", NrCols( M ), ")" ); + fi; + return IdentityMatrix( nrows, M ); + end ); InstallMethod( OneSameMutability, [ IsMatrixOrMatrixObj ], diff --git a/lib/matobjnz.gd b/lib/matobjnz.gd index 34e92e6b94..3f4491b47c 100644 --- a/lib/matobjnz.gd +++ b/lib/matobjnz.gd @@ -8,9 +8,80 @@ ## to list here. Please refer to the COPYRIGHT file for details. ## -# represent vectors/matrices over Z/nZ by nonnegative integer lists -# in the range [0..n-1], but reduce after -# arithmetic. This way avoid always wrapping all entries separately +############################################################################ +## +## Dense vector objects over rings 'Integers mod n', +## backed by plain lists of integers. +## Dense matrix objects over rings 'Integers mod n', +## backed by plain lists of plain lists of integers. +## +## The code for vectors and matrices in the filters +## and +## was adapted from that for the filters +## and . +##

+## the idea is that a vector in is given by +## a plain list of reduced integers, +## and that a matrix in is given by +## a plain list of plain lists of reduced integers. +##

+## In particular, a matrix in does not store +## rows that are in . +##

+## The main differences between and +## +## (and between and +## ) are as follows. +##

+## +## +## The for an +## object is Integers mod n for some positive integer n, +## hence no special handling of certain base domains is needed. +## +## +## The entries of a or +## object are elements of the base domain, +## but integers are stored internally. +## This means that fetching or setting single entries requires a +## conversion from an integer to a or vice versa. +## +## +## Moreover, the stored integers are assumed to lie in range +## [ 0 .. n-1 ]. +## This means that all functions that create or modify the objects must +## perform the necessary reductions. +## In particular, MakeIsZmodnZVectorRep and +## MakeIsZmodnZMatrixRep check this property +## if the argument check is 'true'. +## +## +## The functions , , +## , and admit +## (nested) lists of integers or of objects, +## and the former is actually preferred because it avoids the creation of +## lots of objects. +##

+## Note that the integers in the input must lie in [ 0 .. n-1 ], +## this is checked if the global option "check" is not set to +## false. +## (Always automatically reducing the entries of the input modulo n +## would not be a good idea since the input is often expected to be +## reduced.) +## +## +## We assume that the entries are in +## , hence we need not deal with the +## question whether this filter shall be set (depending on the base domain). +## +## +## In order to do the computations really only with lists of integers +## whenever possible, we have to avoid calls to Unpack as well as +## access to entries of the vectors or matrices. +## This means that many of the default methods must be overloaded. +## +## + ############################################################################# ## @@ -29,7 +100,23 @@ ## of obj. ##

## implies , -## thus matrix objects in this representation can be mutable. +## thus vector objects in this representation can be mutable. +##

+## is the default representation that is +## chosen by and +## if the +## given R +## consists of objects in , that is, +## if R is of the form Integers mod n for some integer +## n that is either not a prime or a prime larger than 2^{16}. +## In the latter case, Integers mod n can be obtained also +## as GF(n). +## For prime n smaller than 2^{16}, +## one can create vector objects in over +## Integers mod n by entering +## as the first argument of +## and +## . ## ## ## <#/GAPDoc> @@ -37,7 +124,8 @@ ## obj is internally represented as a positional object ## (see ) which stores the base domain ## (see ) -## at position 1 and a plain list of integers at position 2. +## at position ZBDPOS and a plain list of reduced integers at position +## ZELSPOS. ## DeclareRepresentation( "IsZmodnZVectorRep", IsVectorObj and IsPositionalObjectRep @@ -57,42 +145,59 @@ DeclareRepresentation( "IsZmodnZVectorRep", ## ## ## An object obj in describes -## a matrix object (see ) that behaves like the -## list of its rows (see ). -## The matrix entries lie in a residue class ring of the ring of integers -## (see ). +## a matrix object (see ) with entries in a +## residue class ring of the ring of integers (see ). ## This ring is the base domain -## (see ) +## (see ) ## of obj. ##

## implies , ## thus matrix objects in this representation can be mutable. +##

+## does not imply +## , +## so direct row access via M[i] is not supported. +##

+## is the default representation that is +## chosen by and +## if the +## given R +## consists of objects in , that is, +## if R is of the form Integers mod n for some integer +## n that is either not a prime or a prime larger than 2^{16}. +## In the latter case, Integers mod n can be obtained also +## as GF(n). +## For prime n smaller than 2^{16}, +## one can create vector objects in over +## Integers mod n by entering +## as the first argument of +## and +## . ## ## ## <#/GAPDoc> ## ## obj is internally represented as a positional object -## (see ) with 4 entries. +## (see ) with 3 entries. ## ## ## its base domain -## (see ), -## -## -## an empty vector in the representation of each row, +## (see ) +## at position ZBDPOS, ## ## ## the number of columns -## (see ), and +## (see ) +## at position ZCOLSPOS, and ## ## -## a plain list (see of its rows, -## each of them being an object in . +## a plain list (see of plain lists, +## each representing a row of the matrix, at position ZROWSPOS. ## ## ## DeclareRepresentation( "IsZmodnZMatrixRep", - IsRowListMatrix and IsPositionalObjectRep + IsMatrixObj and IsPositionalObjectRep and IsCopyable and IsNoImmediateMethodsObject and HasNumberRows and HasNumberColumns @@ -100,3 +205,12 @@ DeclareRepresentation( "IsZmodnZMatrixRep", [] ); Add( ConstructingFiltersForMatrixGroupElements, IsZmodnZMatrixRep ); + +# Internal positions for vector access. +BindConstant( "ZBDPOS", 1 ); +BindConstant( "ZELSPOS", 2 ); + +# Internal positions for matrix access. +#BindConstant( "ZBDPOS", 1 ); +BindConstant( "ZCOLSPOS", 2 ); +BindConstant( "ZROWSPOS", 3 ); diff --git a/lib/matobjnz.gi b/lib/matobjnz.gi index c2edf17d3a..b647a1f90f 100644 --- a/lib/matobjnz.gi +++ b/lib/matobjnz.gi @@ -8,1415 +8,1390 @@ ## to list here. Please refer to the COPYRIGHT file for details. ## -# represent vectors/matrices over Z/nZ by nonnegative integer lists -# in the range [0..n-1], but reduce after -# arithmetic. This way avoid always wrapping all entries separately - -BindGlobal("ZNZVECREDUCE",function(v,l,m) -local i; - for i in [1..l] do - if v[i]<0 or v[i]>=m then v[i]:=v[i] mod m;fi; - od; -end); - -InstallMethod( ConstructingFilter, "for a zmodnz vector", - [ IsZmodnZVectorRep ], - function( v ) - return IsZmodnZVectorRep; - end ); - -InstallOtherMethod( ConstructingFilter, "for a zmodnz matrix", - [ IsZmodnZMatrixRep ], - function( m ) - return IsZmodnZMatrixRep; - end ); - -InstallMethod( CompatibleVectorFilter, "zmodnz", - [ IsZmodnZMatrixRep ], - M -> IsZmodnZVectorRep ); - -############################################################################ -# Vectors ############################################################################ +## +## Dense vector objects over rings 'Integers mod n', +## backed by plain lists of integers. +## +## - Use the default 'ZeroVector( len, vec )' and `ZeroVector( len, mat )' +## methods that delegate to 'NewZeroVector'. +## - Use the default 'Vector( list, example )' method. +## - Use the default 'ZeroSameMutability' and `ZeroImmutable' +## methods that delegate to 'Vector'. -InstallTagBasedMethod( NewVector, - IsZmodnZVectorRep, - function( filter, basedomain, l ) - local check, typ, v; - check:= ValueOption( "check" ) <> false; - if check and not ( IsZmodnZObjNonprimeCollection( basedomain ) or - ( IsFinite( basedomain ) and IsPrimeField( basedomain ) ) ) then - Error( " must be Integers mod for some " ); - fi; - typ:=NewType(FamilyObj(basedomain),IsZmodnZVectorRep and IsMutable and - CanEasilyCompareElements); - # force list of integers - if FamilyObj(basedomain)=FamilyObj(l) then - l:=List(l,Int); - elif check and not ForAll( l, IsInt ) then - Error( " must be a list of integers or of elements in " ); - else - l:=ShallowCopy(l); - fi; - v := [basedomain,l]; - Objectify(typ,v); - return v; - end ); - -InstallTagBasedMethod( NewZeroVector, - IsZmodnZVectorRep, - function( filter, basedomain, l ) - local check, typ, v; - check:= ValueOption( "check" ) <> false; - if check and not ( IsZmodnZObjNonprimeCollection( basedomain ) or - ( IsFinite( basedomain ) and IsPrimeField( basedomain ) ) ) then - Error( " must be Integers mod for some " ); - fi; - typ:=NewType(FamilyObj(basedomain),IsZmodnZVectorRep and IsMutable and - CanEasilyCompareElements); - # represent list as integers - v := [basedomain,0*[1..l]]; - Objectify(typ,v); - return v; - end ); -InstallMethod( ViewObj, "for a zmodnz vector", [ IsZmodnZVectorRep ], -function( v ) -local l; - if not IsMutable(v) then - Print(", , ) +## +## Construct a new vector in the filter 'IsZmodnZVectorRep' with base domain +## and entries in the list (without copying). +## +## If is set to 'true' *and* 'ValueOption( "check" )' is 'true', +## then it is checked that the entries of are either all in +## or integers in the range '[ 0 .. n-1 ]'. +## So whenever you know that the input is guaranteed to satisfy this, +## pass 'false' for to omit these (potentially costly) consistency +## checks. +## +BindGlobal( "MakeIsZmodnZVectorRep", + function( basedomain, list, check ) + local fam, filter, typ; + + fam:= FamilyObj(basedomain); + if not IsBound(fam!.ZmodnZVectorRepTypes) then + # initialize type cache + # TODO: make this thread safe for HPC-GAP + filter:= IsZmodnZVectorRep and CanEasilyCompareElements; + fam!.ZmodnZVectorRepTypes := [ + NewType( fam, filter ), + NewType( fam, filter and IsMutable ), + ]; fi; - Print("vector mod ",Size(v![BDPOS])); - l:=Length(v![ELSPOS]); - if 0"); + if IsMutable(list) then + typ:= fam!.ZmodnZVectorRepTypes[2]; else - Print(" of length ",Length(v![ELSPOS]),">"); + typ:= fam!.ZmodnZVectorRepTypes[1]; fi; - end ); -InstallMethod( PrintObj, "for a zmodnz vector", [ IsZmodnZVectorRep ], - function( v ) - Print("NewVector(IsZmodnZVectorRep"); - if IsField(v![BDPOS]) then - Print(",GF(",Size(v![BDPOS]),"),",v![ELSPOS],")"); - else - Print(",",String(v![BDPOS]),",",v![ELSPOS],")"); + if FamilyObj( basedomain ) = FamilyObj( list ) then + if check and ValueOption( "check" ) <> false then + if not ( IsZmodnZObjNonprimeCollection( basedomain ) or + ( IsFinite( basedomain ) and IsPrimeField( basedomain ) ) ) then + Error( " must be Integers mod for some " ); + elif not IsPlistRep( list ) then + # Some kernel functions really need 'IsPlistRep'. + Error( " must be a plain list" ); + elif not IsSubset( basedomain, list ) then + Error( " must be a list of reduced integers ", + "or of elements in " ); + fi; + fi; + # Here we have to copy. + list:= List( list, Int ); + elif check and ValueOption( "check" ) <> false then + # Here we have to check that the entries are reduced integers. + if not IsPlistRep( list ) then + # Some kernel functions really need 'IsPlistRep'. + Error( " must be a plain list" ); + elif not ( ( IsCyclotomicCollection( list ) or IsEmpty( list ) ) and + IsSubset( [ 0 .. Size( basedomain ) - 1 ], list ) ) then + Error( " must be a list of reduced integers ", + "or of elements in " ); + fi; fi; - end ); -InstallMethod( String, "for a zmodnz vector", [ IsZmodnZVectorRep ], - function( v ) - local st; - st := "NewVector(IsZmodnZVectorRep"; - if IsField(v![BDPOS]) then - Append(st,Concatenation( ",GF(",String(Size(v![BDPOS])),"),", - String(v![ELSPOS]),")" )); - else - Append(st,Concatenation( ",",String(v![BDPOS]),",", - String(v![ELSPOS]),")" )); - fi; - return st; + return Objectify(typ, [ basedomain, list ]); end ); -InstallMethod( Display, "for a zmodnz vector", [ IsZmodnZVectorRep ], - function( v ) - Print( "\n"); - end ); -InstallMethod( BaseDomain, "for a zmodnz vector", [ IsZmodnZVectorRep ], - function( v ) - return v![BDPOS]; +# Reduce 'v' of length 'l' over 'Integers mod m'. +# If 'v' is mutable then work in place. +BindGlobal( "ZNZVECREDUCE", function( v, l, m ) + local res, i; + if IsMutable( v ) then + res:= v; + else + res:= ShallowCopy( v ); + fi; + for i in [ 1 .. l ] do + if res[i] < 0 or res[i] >= m then + res[i]:= res[i] mod m; + fi; + od; + if not IsMutable( v ) then + MakeImmutable( res ); + fi; + return res; end ); -InstallMethod( Length, "for a zmodnz vector", [ IsZmodnZVectorRep ], - function( v ) - return Length(v![ELSPOS]); - end ); -InstallMethod( ShallowCopy, "for a zmodnz vector", [ IsZmodnZVectorRep ], - function( v ) - local res; - res := Objectify(TypeObj(v),[v![BDPOS],ShallowCopy(v![ELSPOS])]); - if not IsMutable(v) then SetFilterObj(res,IsMutable); fi; - return res; +InstallTagBasedMethod( NewVector, + IsZmodnZVectorRep, + function( filter, basedomain, list ) + return MakeIsZmodnZVectorRep(basedomain, PlainListCopy( list ), true); end ); -# StructuralCopy works automatically -InstallMethod( PostMakeImmutable, "for a zmodnz vector", [ IsZmodnZVectorRep ], - function( v ) - MakeImmutable( v![ELSPOS] ); +InstallTagBasedMethod( NewZeroVector, + IsZmodnZVectorRep, + function( filter, basedomain, len ) + local list; + list := ListWithIdenticalEntries(len, 0); + return MakeIsZmodnZVectorRep(basedomain, list, false); end ); -############################################################################ -# Representation preserving constructors: -############################################################################ -# not needed according to MH -# InstallMethod( ZeroVector, "for an integer and a zmodnz vector", -# [ IsInt, IsZmodnZVectorRep ], -# function( l, t ) -# local v; -# v := Objectify(TypeObj(t), -# [t![BDPOS],ListWithIdenticalEntries(l,0)]); -# if not IsMutable(v) then SetFilterObj(v,IsMutable); fi; -# return v; -# end ); -# -# InstallMethod( ZeroVector, "for an integer and a zmodnz matrix", -# [ IsInt, IsZmodnZMatrixRep ], -# function( l, m ) -# local v; -# v := Objectify(TypeObj(m![EMPOS]), -# [m![BDPOS],ListWithIdenticalEntries(l,0)]); -# if not IsMutable(v) then SetFilterObj(v,IsMutable); fi; -# return v; -# end ); - -InstallMethod( Vector, "for a plain list and a zmodnz vector",IsIdenticalObj, - [ IsList and IsPlistRep, IsZmodnZVectorRep ], - function( l, t ) - local v; - # force list of integers - if FamilyObj(t![BDPOS])=FamilyObj(l) then l:=List(l,Int); fi; - v := Objectify(TypeObj(t),[t![BDPOS],l]); - if not IsMutable(v) then SetFilterObj(v,IsMutable); fi; - return v; - end ); +InstallMethod( ConstructingFilter, + [ "IsZmodnZVectorRep" ], + v -> IsZmodnZVectorRep ); -InstallMethod( Vector, "for a list and a zmodnz vector", - [ IsList, IsZmodnZVectorRep ], - function( l, t ) - local v; - v := ShallowCopy(l); - if IsGF2VectorRep(l) then - PLAIN_GF2VEC(v); - elif Is8BitVectorRep(l) then - PLAIN_VEC8BIT(v); - fi; - v := Objectify(TypeObj(t),[t![BDPOS],v]); - if not IsMutable(v) then SetFilterObj(v,IsMutable); fi; - return v; - end ); +InstallMethod( BaseDomain, + [ "IsZmodnZVectorRep" ], + v -> v![ZBDPOS] ); -############################################################################ -# A selection of list operations: -############################################################################ +InstallMethod( Length, + [ "IsZmodnZVectorRep" ], + v -> Length(v![ZELSPOS]) ); -InstallMethod( \[\], "for a zmodnz vector and a positive integer", - [ IsZmodnZVectorRep, IsPosInt ], - function( v, p ) - return ZmodnZObj(ElementsFamily(FamilyObj(v)),v![ELSPOS][p]); - end ); +InstallMethod( \[\], + [ "IsZmodnZVectorRep", "IsPosInt" ], + { v, p } -> ZmodnZObj(ElementsFamily(FamilyObj(v)),v![ZELSPOS][p]) ); -InstallMethod( \[\]\:\=, "for a zmodnz vector, a positive integer, and an obj", - [ IsZmodnZVectorRep, IsPosInt, IsObject ], +InstallMethod( \[\]\:\=, + [ "IsZmodnZVectorRep", "IsPosInt", "IsObject" ], function( v, p, ob ) - v![ELSPOS][p] := Int(ob); - end ); -InstallMethod( \{\}, "for a zmodnz vector and a list", - [ IsZmodnZVectorRep, IsList ], - function( v, l ) - return Objectify(TypeObj(v),[v![BDPOS],v![ELSPOS]{l}]); + if ValueOption( "check" ) <> false then + if not ( IsInt( ob ) or ob in BaseDomain( v ) ) then + Error( " must be an integer or lie in the base domain of " ); + elif Length( v![ZELSPOS] ) < p then + Error( "

is out of bounds" ); + fi; + fi; + if IsInt( ob ) then + v![ZELSPOS][p]:= ob mod Size( v![ZBDPOS] ); + else + v![ZELSPOS][p]:= Int( ob ); + fi; end ); -InstallMethod( PositionNonZero, "for a zmodnz vector", [ IsZmodnZVectorRep ], - function( v ) - return PositionNonZero( v![ELSPOS] ); - end ); +InstallMethod( \{\}, + [ "IsZmodnZVectorRep", "IsList" ], + { v, list } -> MakeIsZmodnZVectorRep( v![ZBDPOS], v![ZELSPOS]{ list }, false ) ); -InstallOtherMethod( PositionNonZero, "for a zmodnz vector and start", - [ IsZmodnZVectorRep,IsInt ], - function( v,s ) - return PositionNonZero( v![ELSPOS],s ); - end ); -InstallMethod( PositionLastNonZero, "for a zmodnz vector", [ IsZmodnZVectorRep ], +InstallMethod( Unpack, + [ "IsZmodnZVectorRep" ], function( v ) - local els,i; - els := v![ELSPOS]; - i := Length(els); - while i > 0 and IsZero(els[i]) do i := i - 1; od; - return i; + local fam; + fam:= ElementsFamily( FamilyObj( v ) ); + return List( v![ZELSPOS], x -> ZmodnZObj( fam, x ) ); end ); -InstallMethod( ListOp, "for a zmodnz vector", [ IsZmodnZVectorRep ], -function( v ) -local fam; - fam:=ElementsFamily(FamilyObj(v)); - return List([1..Length(v![ELSPOS])],x->ZmodnZObj(fam,v![ELSPOS][x])); -end ); - -InstallMethod( ListOp, "for a zmodnz vector and a function", - [ IsZmodnZVectorRep, IsFunction ], -function( v, f ) -local fam; - fam:=ElementsFamily(FamilyObj(v)); - return List(List([1..Length(v![ELSPOS])],x->ZmodnZObj(fam,v![ELSPOS][x])),f); -end ); - -InstallMethod( Unpack, "for a zmodnz vector", - [ IsZmodnZVectorRep ], -function( v ) -local fam; - fam:=ElementsFamily(FamilyObj(v)); - return List([1..Length(v![ELSPOS])],x->ZmodnZObj(fam,v![ELSPOS][x])); -end ); - -############################################################################ -# Arithmetical operations: -############################################################################ - -InstallMethod( \+, "for two zmodnz vectors",IsIdenticalObj, - [ IsZmodnZVectorRep, IsZmodnZVectorRep ], -function( a, b ) -local ty,i,m,mu; - if not IsMutable(a) and IsMutable(b) then - ty := TypeObj(b); - else - ty := TypeObj(a); - fi; - m:=Size(a![BDPOS]); - b:=SUM_LIST_LIST_DEFAULT(a![ELSPOS],b![ELSPOS]); - if not IsMutable(b) then mu:=true;b:=ShallowCopy(b); - else mu:=false;fi; - for i in [1..Length(b)] do if b[i]>=m then b[i]:=b[i] mod m;fi;od; - if mu then MakeImmutable(b);fi; - return Objectify(ty,[a![BDPOS],b]); -end ); - -InstallOtherMethod( \+, "for zmodnz vector and plist",IsIdenticalObj, - [ IsZmodnZVectorRep, IsList ], -function( a, b ) - return a+Vector(BaseDomain(a),b); -end ); +InstallMethod( ShallowCopy, [ "IsZmodnZVectorRep" ], + v -> MakeIsZmodnZVectorRep( v![ZBDPOS], ShallowCopy( v![ZELSPOS] ), false ) ); -InstallOtherMethod( \+, "for plist and zmodnz vector",IsIdenticalObj, - [ IsList,IsZmodnZVectorRep ], -function( a, b ) - return Vector(BaseDomain(b),a)+b; -end ); - -InstallMethod( \-, "for two zmodnz vectors",IsIdenticalObj, - [ IsZmodnZVectorRep, IsZmodnZVectorRep ], -function( a, b ) -local ty,i,m,mu; - if not IsMutable(a) and IsMutable(b) then - ty := TypeObj(b); - else - ty := TypeObj(a); - fi; - m:=Size(a![BDPOS]); - b:=a![ELSPOS] - b![ELSPOS]; - if not IsMutable(b) then mu:=true;b:=ShallowCopy(b); - else mu:=false;fi; - for i in [1..Length(b)] do if b[i]<0 then b[i]:=b[i] mod m;fi;od; - if mu then MakeImmutable(b);fi; - return Objectify(ty,[a![BDPOS],b]); -end ); - -InstallOtherMethod( \-, "for zmodnz vector and plist",IsIdenticalObj, - [ IsZmodnZVectorRep, IsList ], -function( a, b ) - return a-Vector(BaseDomain(a),b); -end ); - -InstallOtherMethod( \-, "for plist and zmodnz vector",IsIdenticalObj, - [ IsList,IsZmodnZVectorRep ], -function( a, b ) - return Vector(BaseDomain(b),a)-b; -end ); - -InstallMethod( \=, "for two zmodnz vectors",IsIdenticalObj, - [ IsZmodnZVectorRep, IsZmodnZVectorRep ], +InstallMethod( \+, + [ "IsZmodnZVectorRep", "IsZmodnZVectorRep" ], function( a, b ) - return EQ_LIST_LIST_DEFAULT(a![ELSPOS],b![ELSPOS]); + local R, mu, n, i; + R:= a![ZBDPOS]; + if ValueOption( "check" ) <> false and + not IsIdenticalObj( R, b![ZBDPOS] ) then + Error( " and are not compatible" ); + fi; + b:= SUM_LIST_LIST_DEFAULT(a![ZELSPOS],b![ZELSPOS]); + if not IsMutable( b ) then + mu:= true; + b:= ShallowCopy( b ); + else + mu:= false; + fi; + n:= Size( R ); + for i in [ 1 .. Length( b ) ] do + if b[i] >= n then + b[i]:= b[i] mod n; + fi; + od; + if mu then + MakeImmutable( b ); + fi; + return MakeIsZmodnZVectorRep( R, b, false ); end ); -InstallMethod( \=, "for zmodnz vector and plist",IsIdenticalObj, - [ IsZmodnZVectorRep, IsPlistRep ], -function( a, b ) - return a![ELSPOS]=List(b,x->x![1]); -end ); +InstallOtherMethod( \+, + IsIdenticalObj, + [ "IsZmodnZVectorRep", "IsList" ], + { a, b } -> a + Vector( BaseDomain( a ), b ) ); +#TODO: Do we want this? If yes then it should be documented. -InstallMethod( \=, "for plist an zmodnz vector",IsIdenticalObj, - [ IsPlistRep,IsZmodnZVectorRep], -function(b,a) - return a![ELSPOS]=List(b,x->x![1]); -end ); +InstallOtherMethod( \+, + IsIdenticalObj, + [ "IsList", "IsZmodnZVectorRep" ], + { a, b } -> Vector( BaseDomain( b ), a ) + b ); +#TODO: Do we want this? If yes then it should be documented. -InstallMethod( \<, "for two zmodnz vectors",IsIdenticalObj, - [ IsZmodnZVectorRep, IsZmodnZVectorRep ], +InstallMethod( \-, + [ "IsZmodnZVectorRep", "IsZmodnZVectorRep" ], function( a, b ) - return LT_LIST_LIST_DEFAULT(a![ELSPOS],b![ELSPOS]); - end ); - -InstallMethod( AddRowVector, "for two zmodnz vectors", - [ IsZmodnZVectorRep and IsMutable, IsZmodnZVectorRep ], -function( a, b ) -local i,m; - a:=a![ELSPOS]; - ADD_ROW_VECTOR_2_FAST( a, b![ELSPOS] ); - m:=Size(b![BDPOS]); - for i in [1..Length(a)] do if a[i]>=m then a[i]:=a[i] mod m;fi;od; -end ); - -InstallMethod( AddRowVector, "for two zmodnz vectors, and a scalar", - [ IsZmodnZVectorRep and IsMutable, IsZmodnZVectorRep, IsObject ], -function( a, b, s ) -local i,m; - if IsZmodnZObj(s) then s:=Int(s);fi; - a:=a![ELSPOS]; - if IsSmallIntRep(s) then - ADD_ROW_VECTOR_3_FAST( a, b![ELSPOS], s ); - else - ADD_ROW_VECTOR_3( a, b![ELSPOS], s ); - fi; - m:=Size(b![BDPOS]); - if s>=0 then - for i in [1..Length(a)] do if a[i]>=m then a[i]:=a[i] mod m;fi;od; + local R, mu, n, i; + R:= a![ZBDPOS]; + if ValueOption( "check" ) <> false and + not IsIdenticalObj( a![ZBDPOS], b![ZBDPOS] ) then + Error( " and are not compatible" ); + fi; + b:= DIFF_LIST_LIST_DEFAULT( a![ZELSPOS], b![ZELSPOS]); + if not IsMutable( b ) then + mu:= true; + b:= ShallowCopy( b ); + else + mu:= false; + fi; + n:= Size( R ); + for i in [ 1 .. Length( b ) ] do + if b[i] < 0 then + b[i]:= b[i] mod n; + fi; + od; + if mu then + MakeImmutable( b ); + fi; + return MakeIsZmodnZVectorRep( R, b, false ); + end ); + +InstallOtherMethod( \-, + IsIdenticalObj, + [ "IsZmodnZVectorRep", "IsList" ], + { a, b } -> a-Vector(BaseDomain(a),b) ); +#TODO: Do we want this? If yes then it should be documented. + +InstallOtherMethod( \-, + IsIdenticalObj, + [ "IsList", "IsZmodnZVectorRep" ], + { a, b } -> Vector(BaseDomain(b),a)-b ); +#TODO: Do we want this? If yes then it should be documented. + +BindGlobal( "ZMODNZVECADDINVCLEANUP", function( m, l ) + local i; + if IsMutable( l ) then + for i in [ 1 .. Length( l ) ] do + if l[i] < 0 then + l[i]:= l[i] mod m; + fi; + od; else - for i in [1..Length(a)] do if a[i]<0 then a[i]:=a[i] mod m;fi;od; + l:= ShallowCopy( l ); + for i in [ 1 .. Length( l ) ] do + if l[i] < 0 then + l[i]:= l[i] mod m; + fi; + od; + MakeImmutable( l ); fi; -end ); + return l; + end ); -InstallOtherMethod( AddRowVector, "for zmodnz vector, plist, and a scalar", - [ IsZmodnZVectorRep and IsMutable, IsPlistRep, IsObject ], -function( a, b, s ) -local i,m; - if not ForAll(b,IsModulusRep) then TryNextMethod();fi; - if IsZmodnZObj(s) then s:=Int(s);fi; - m:=Size(a![BDPOS]); - a:=a![ELSPOS]; - b:=List(b,x->x![1]); - - if IsSmallIntRep(s) then - ADD_ROW_VECTOR_3_FAST( a, b, s ); - else - ADD_ROW_VECTOR_3( a, b, s ); - fi; - if s>=0 then - for i in [1..Length(a)] do if a[i]>=m then a[i]:=a[i] mod m;fi;od; - else - for i in [1..Length(a)] do if a[i]<0 then a[i]:=a[i] mod m;fi;od; - fi; -end ); +# Avoid 'Unpack'. +InstallMethod( AdditiveInverseMutable, + [ "IsZmodnZVectorRep" ], + function( v ) + local res; + res:= MakeIsZmodnZVectorRep( v![ZBDPOS], + ZMODNZVECADDINVCLEANUP(Size(v![ZBDPOS]), + AdditiveInverseMutable(v![ZELSPOS])), true ); + return res; + end ); -InstallOtherMethod( AddRowVector, "for plist, zmodnz vector, and a scalar", - [ IsPlistRep and IsMutable, IsZmodnZVectorRep, IsObject ], -function( a, b, s ) -local i; - if not ForAll(a,IsModulusRep) then TryNextMethod();fi; - for i in [1..Length(a)] do - a[i]:=a[i]+b[i]*s; - od; -end); +InstallMethod( ZeroMutable, [ "IsZmodnZVectorRep" ], + v -> MakeIsZmodnZVectorRep( v![ZBDPOS], ZeroMutable(v![ZELSPOS]), false ) ); + +BindGlobal( "ZMODNZVECSCAMULT", + function( w, s ) + local i,m,b,v; + b:= w![ZBDPOS]; + m:= Size( b ); + if not IsInt( s ) then + if IsRat( s ) then + s:= s mod m; + elif s in b then + s:= Int( s ); + else + Error( "multiplication with is not supported" ); + fi; + fi; + v:= PROD_LIST_SCL_DEFAULT( w![ZELSPOS], s ); + if not IsMutable( v ) then + v:= ShallowCopy( v ); + fi; + if s >= 0 then + for i in [ 1 .. Length( v ) ] do + if v[i] >= m then + v[i]:= v[i] mod m; + fi; + od; + else + for i in [ 1 .. Length( v ) ] do + if v[i] < 0 then + v[i]:= v[i] mod m; + fi; + od; + fi; + if not IsMutable( w![ZELSPOS] ) then + MakeImmutable( v ); + fi; + return MakeIsZmodnZVectorRep( w![ZBDPOS], v, true ); + end ); -InstallOtherMethod( AddRowVector, "for plist, plist vector, and a scalar", - [ IsPlistRep and IsMutable, IsPlistVectorRep, IsObject ], -function( a, b, s ) -local i; - for i in [1..Length(a)] do - a[i]:=a[i]+b[i]*s; - od; -end); +# Requiring 'IsScalar' for scalar multiplication/division is dangerous +# without prescribed family relation if matrix objects are scalars. +# Here the situation is easier than in general +# because we want to restrict the scalars to 'IsRat' or +# elements of the base domain of the vector. +# (We need the 'IsScalar' to get a rank that is higher than the one +# for the generic method that is based on 'Unpack'.) +InstallOtherMethod( \*, + [ "IsZmodnZVectorRep", "IsRat" ], + ZMODNZVECSCAMULT ); -InstallMethod( AddRowVector, - "for two zmodnz vectors, a scalar, and two positions", - [ IsZmodnZVectorRep and IsMutable, IsZmodnZVectorRep, - IsObject, IsPosInt, IsPosInt ], -function( a, b, s, from, to ) -local i,m; - if IsZmodnZObj(s) then s:=Int(s);fi; - a:=a![ELSPOS]; - if IsSmallIntRep(s) then - ADD_ROW_VECTOR_5_FAST( a, b![ELSPOS], s, from, to ); - else - ADD_ROW_VECTOR_5( a, b![ELSPOS], s, from, to ); - fi; - m:=Size(b![BDPOS]); - if s>=0 then - for i in [1..Length(a)] do if a[i]>=m then a[i]:=a[i] mod m;fi;od; - else - for i in [1..Length(a)] do if a[i]<0 then a[i]:=a[i] mod m;fi;od; - fi; -end ); +InstallOtherMethod( \*, + IsCollsElms, + [ "IsZmodnZVectorRep", "IsScalar" ], + ZMODNZVECSCAMULT ); -InstallMethod( MultVectorLeft, - "for a zmodnz vector, and an object", - [ IsZmodnZVectorRep and IsMutable, IsObject ], -function( v, s ) -local i,m; - m:=Size(v![BDPOS]); - if IsZmodnZObj(s) then s:=Int(s);fi; - v:=v![ELSPOS]; - MULT_VECTOR_2_FAST(v,s); - if s>=0 then - for i in [1..Length(v)] do if v[i]>=m then v[i]:=v[i] mod m;fi;od; - else - for i in [1..Length(v)] do if v[i]<0 then v[i]:=v[i] mod m;fi;od; - fi; -end ); +InstallOtherMethod( \*, + [ "IsRat", "IsZmodnZVectorRep" ], + { s, v } -> ZMODNZVECSCAMULT( v, s ) ); -# The four argument version of MultVectorLeft / ..Right uses the generic -# implementation in matobj.gi - -BindGlobal("ZMODNZVECSCAMULT", -function( w, s ) -local i,m,t,b,v; - t:=TypeObj(w); - b:=w![BDPOS]; - m:=Size(b); - if IsZmodnZObj(s) then s:=Int(s);fi; - v:=PROD_LIST_SCL_DEFAULT(w![ELSPOS],s); - if not IsMutable(v) then - v:=ShallowCopy(v); - fi; - if s>=0 then - for i in [1..Length(v)] do if v[i]>=m then v[i]:=v[i] mod m;fi;od; - else - for i in [1..Length(v)] do if v[i]<0 then v[i]:=v[i] mod m;fi;od; - fi; - if not IsMutable(w![ELSPOS]) then MakeImmutable(v);fi; - return Objectify(t,[b,v]); -end ); +InstallOtherMethod( \*, + IsElmsColls, + [ "IsScalar", "IsZmodnZVectorRep" ], + { s, v } -> ZMODNZVECSCAMULT( v, s ) ); -InstallMethod( \*, "for a zmodnz vector and a scalar", - [ IsZmodnZVectorRep, IsScalar ],ZMODNZVECSCAMULT); +InstallOtherMethod( \/, + [ "IsZmodnZVectorRep", "IsRat" ], + { v, s } -> ZMODNZVECSCAMULT( v, s^-1 ) ); -InstallMethod( \*, "for a scalar and a zmodnz vector", - [ IsScalar, IsZmodnZVectorRep ], -function( s, v ) - return ZMODNZVECSCAMULT(v,s); -end ); +InstallOtherMethod( \/, + IsCollsElms, + [ "IsZmodnZVectorRep", "IsScalar" ], + { v, s } -> ZMODNZVECSCAMULT( v, s^-1 ) ); -InstallMethod( \/, "for a zmodnz vector and a scalar", - [ IsZmodnZVectorRep, IsScalar ], -function( v, s ) - return ZMODNZVECSCAMULT(v,s^-1); -end ); -BindGlobal("ZMODNZVECADDINVCLEANUP",function(m,l) -local i; - if IsMutable(l) then - for i in [1..Length(l)] do if l[i]<0 then l[i]:=l[i] mod m;fi;od; - else - l:=ShallowCopy(l); - for i in [1..Length(l)] do if l[i]<0 then l[i]:=l[i] mod m;fi;od; - MakeImmutable(l); - fi; - return l; -end); +InstallMethod( PostMakeImmutable, + [ "IsZmodnZVectorRep" ], + v -> MakeImmutable( v![ZELSPOS] ) ); -InstallMethod( AdditiveInverseSameMutability, "for a zmodnz vector", - [ IsZmodnZVectorRep ], - function( v ) - return Objectify( TypeObj(v), - [v![BDPOS],ZMODNZVECADDINVCLEANUP(Size(v![BDPOS]), - AdditiveInverseSameMutability(v![ELSPOS]))] ); - end ); -InstallMethod( AdditiveInverseImmutable, "for a zmodnz vector", - [ IsZmodnZVectorRep ], +InstallMethod( ViewObj, + [ "IsZmodnZVectorRep" ], function( v ) - local res; - res := Objectify( TypeObj(v), - [v![BDPOS],ZMODNZVECADDINVCLEANUP(Size(v![BDPOS]), - AdditiveInverseSameMutability(v![ELSPOS]))] ); - MakeImmutable(res); - return res; + Print( "<" ); + if not IsMutable( v ) then + Print( "immutable " ); + fi; + Print( "vector over ", v![ZBDPOS], " of length ", Length( v![ZELSPOS] ), + ">" ); end ); -InstallMethod( AdditiveInverseMutable, "for a zmodnz vector", - [ IsZmodnZVectorRep ], +InstallMethod( PrintObj, + [ "IsZmodnZVectorRep" ], function( v ) - local res; - res := Objectify(TypeObj(v), - [v![BDPOS],ZMODNZVECADDINVCLEANUP(Size(v![BDPOS]), - AdditiveInverseMutable(v![ELSPOS]))]); - if not IsMutable(v) then SetFilterObj(res,IsMutable); fi; - return res; + Print( "NewVector(IsZmodnZVectorRep" ); + if IsField( v![ZBDPOS] ) then + Print( ",GF(", Size( v![ZBDPOS] ), "),", v![ZELSPOS], ")" ); + else + Print( ",", String( v![ZBDPOS] ), ",", v![ZELSPOS], ")" ); + fi; end ); -# redundant according to MH -# InstallMethod( ZeroSameMutability, "for a zmodnz vector", [ IsZmodnZVectorRep ], -# function( v ) -# return Objectify(TypeObj(v),[v![BDPOS],ZeroSameMutability(v![ELSPOS])]); -# end ); -# -# InstallMethod( ZeroImmutable, "for a zmodnz vector", [ IsZmodnZVectorRep ], -# function( v ) -# local res; -# res := Objectify(TypeObj(v),[v![BDPOS],ZeroImmutable(v![ELSPOS])]); -# MakeImmutable(res); -# return res; -# end ); - -InstallMethod( ZeroMutable, "for a zmodnz vector", [ IsZmodnZVectorRep ], +InstallMethod( Display, + [ "IsZmodnZVectorRep" ], function( v ) - local res; - res := Objectify(TypeObj(v), - [v![BDPOS],ZeroMutable(v![ELSPOS])]); - if not IsMutable(v) then SetFilterObj(res,IsMutable); fi; - return res; + Print( "\n" ); end ); -InstallMethod( IsZero, "for a zmodnz vector", [ IsZmodnZVectorRep ], +InstallMethod( String, + [ "IsZmodnZVectorRep" ], function( v ) - return IsZero( v![ELSPOS] ); - end ); - -#InstallMethodWithRandomSource( Randomize, -# "for a random source and a mutable zmodnz vector", -# [ IsRandomSource, IsZmodnZVectorRep and IsMutable ], -# function( rs, v ) -# local bd,i; -# bd := v![BDPOS]; -# for i in [1..Length(v![ELSPOS])] do -# v![ELSPOS][i] := Random( rs, bd ); -# od; -# return v; -# end ); - -InstallMethod( CopySubVector, "for two zmodnz vectors and two lists", - [ IsZmodnZVectorRep, IsZmodnZVectorRep and IsMutable, IsList, IsList ], - function( a,b,pa,pb ) - # The following should eventually go into the kernel: - if ValueOption( "check" ) <> false and a![BDPOS] <> b![BDPOS] then - Error( " and have different base domains" ); + local st; + st := "NewVector(IsZmodnZVectorRep,"; + if IsField( v![ZBDPOS] ) then + Append( st, "GF(" ); + Append( st, String( Size( v![ZBDPOS] ) ) ); + Append( st, ")," ); + else + Append( st, String( v![ZBDPOS] ) ); + Append( st, "," ); fi; - b![ELSPOS]{pb} := a![ELSPOS]{pa}; + Append( st, String( v![ZELSPOS] ) ); + Add( st, ')' ); + return st; end ); -InstallOtherMethod( ProductCoeffs, - "zmodmat: call PRODUCT_COEFFS_GENERIC_LISTS with lengths", - true, [ IsZmodnZVectorRep, IsZmodnZVectorRep], 0, -function( l1, l2 ) - return PRODUCT_COEFFS_GENERIC_LISTS(l1,Length(l1),l2,Length(l2)); -end); - -############################################################################ -# Matrices -############################################################################ -InstallTagBasedMethod( NewMatrix, - IsZmodnZMatrixRep, - function( filter, basedomain, rl, l ) - local check, nd, filterVectors, m, e, filter2, i; +# Avoid element access. +InstallMethod( PositionNonZero, + [ "IsZmodnZVectorRep" ], + v -> PositionNonZero( v![ZELSPOS] ) ); - check:= ValueOption( "check" ) <> false; - if check and not ( IsZmodnZObjNonprimeCollection( basedomain ) or - ( IsFinite( basedomain ) and IsPrimeField( basedomain ) ) ) then - Error( " must be Integers mod for some " ); - fi; +InstallOtherMethod( PositionNonZero, + [ "IsZmodnZVectorRep", "IsInt" ], + { v, s } -> PositionNonZero( v![ZELSPOS], s ) ); - # If applicable then replace a flat list 'l' by a nested list - # of lists of length 'rl'. - if Length(l) > 0 and not IsVectorObj(l[1]) then - nd := NestingDepthA(l); - if nd < 2 or nd mod 2 = 1 then - if Length(l) mod rl <> 0 then - Error( "NewMatrix: Length of l is not a multiple of rl" ); - fi; - l := List([0,rl..Length(l)-rl], i -> l{[i+1..i+rl]}); - fi; - fi; - - filterVectors := IsZmodnZVectorRep; - m := 0*[1..Length(l)]; - for i in [1..Length(l)] do - if IsVectorObj(l[i]) and IsZmodnZVectorRep(l[i]) then - m[i] := ShallowCopy(l[i]); - else - m[i] := NewVector( filterVectors, basedomain, l[i] ); - fi; +InstallMethod( PositionLastNonZero, + [ "IsZmodnZVectorRep" ], + function( v ) + local els,i; + els:= v![ZELSPOS]; + i:= Length( els ); + while i > 0 and els[i] = 0 do + i:= i - 1; od; - e := NewVector(filterVectors, basedomain, []); - m := [basedomain,e,rl,m]; - filter2 := IsZmodnZMatrixRep and IsMutable; - if HasCanEasilyCompareElements(Representative(basedomain)) and - CanEasilyCompareElements(Representative(basedomain)) then - filter2 := filter2 and CanEasilyCompareElements; - fi; - Objectify( NewType(CollectionsFamily(FamilyObj(basedomain)), - filter2), m ); - return m; + return i; end ); -# This is faster than the default method. -InstallTagBasedMethod( NewZeroMatrix, - IsZmodnZMatrixRep, - function( filter, basedomain, rows, cols ) - local check, m,i,e,filter2; +InstallMethod( ListOp, + [ "IsZmodnZVectorRep" ], + function( v ) + local fam; + fam:= ElementsFamily( FamilyObj( v ) ); + return List( v![ZELSPOS], x -> ZmodnZObj( fam, x ) ); + end ); + +InstallMethod( ListOp, + [ "IsZmodnZVectorRep", "IsFunction" ], + function( v, f ) + local fam; + fam:= ElementsFamily( FamilyObj( v ) ); + return List( v![ZELSPOS], x -> f( ZmodnZObj( fam, x ) ) ); + end ); + + +# Avoid accessing vector entries. +InstallMethod( \=, + IsIdenticalObj, + [ "IsZmodnZVectorRep", "IsZmodnZVectorRep" ], + { a, b } -> EQ_LIST_LIST_DEFAULT( a![ZELSPOS], b![ZELSPOS] ) ); + +InstallMethod( \=, + IsIdenticalObj, + [ "IsZmodnZVectorRep", "IsPlistRep" ], + { a, b } -> a![ZELSPOS]=List(b,x->x![1]) ); +#TODO: Do we want this? If yes then it should be documented. +#TODO: Fix that this assumes 'b' is a list of 'IsZmodnZObj's. + +InstallMethod( \=, + IsIdenticalObj, + [ "IsPlistRep", "IsZmodnZVectorRep" ], + { b, a } -> a![ZELSPOS]=List(b,x->x![1]) ); +#TODO: Do we want this? If yes then it should be documented. +#TODO: Fix that this assumes 'b' is a list of 'IsZmodnZObj's. + +# Avoid accessing vector entries. +InstallMethod( \<, + IsIdenticalObj, + [ "IsZmodnZVectorRep", "IsZmodnZVectorRep" ], + { a, b } -> LT_LIST_LIST_DEFAULT( a![ZELSPOS], b![ZELSPOS] ) ); - check:= ValueOption( "check" ) <> false; - if check and not ( IsZmodnZObjNonprimeCollection( basedomain ) or - ( IsFinite( basedomain ) and IsPrimeField( basedomain ) ) ) then - Error( " must be Integers mod for some " ); +InstallMethod( AddRowVector, + [ "IsZmodnZVectorRep and IsMutable", "IsZmodnZVectorRep" ], + function( a, b ) + local R, m, i; + R:= a![ZBDPOS]; + if ValueOption( "check" ) <> false and + not IsIdenticalObj( R, b![ZBDPOS] ) then + Error( " and are not compatible" ); fi; - - filter2 := IsZmodnZVectorRep; - m := 0*[1..rows]; - e := NewVector(filter2, basedomain, []); - for i in [1..rows] do - m[i] := ZeroVector( cols, e ); + a:= a![ZELSPOS]; + ADD_ROW_VECTOR_2_FAST( a, b![ZELSPOS] ); + m:= Size( R ); + for i in [ 1 .. Length( a ) ] do + if a[i] >= m then + a[i]:= a[i] mod m; + fi; od; - m := [basedomain,e,cols,m]; - Objectify( NewType(CollectionsFamily(FamilyObj(basedomain)), - filter and IsMutable), m ); - return m; end ); -# This is faster than the default method. -InstallTagBasedMethod( NewIdentityMatrix, - IsZmodnZMatrixRep, - function( filter, basedomain, dim ) - local mat, i; - mat := NewZeroMatrix(filter, basedomain, dim, dim); - for i in [1..dim] do - mat[i,i] := 1; - od; - return mat; +InstallMethod( AddRowVector, + [ "IsZmodnZVectorRep and IsMutable", "IsZmodnZVectorRep", "IsObject" ], + function( a, b, s ) + local bd, i, m; + bd:= a![ZBDPOS]; + if ValueOption( "check" ) <> false then + if not IsIdenticalObj( bd, b![ZBDPOS] ) then + Error( " and are not compatible" ); + fi; + fi; + if not IsInt( s ) then + if IsRat( s ) then + s:= s mod m; + elif s in bd then + s:= Int( s ); + else + Error( "multiplication with is not supported" ); + fi; + fi; + a:= a![ZELSPOS]; + if IsSmallIntRep( s ) then + ADD_ROW_VECTOR_3_FAST( a, b![ZELSPOS], s ); + else + ADD_ROW_VECTOR_3( a, b![ZELSPOS], s ); + fi; + m:= Size( b![ZBDPOS] ); + if s >= 0 then + for i in [ 1 .. Length( a ) ] do + if a[i] >= m then + a[i]:= a[i] mod m; + fi; + od; + else + for i in [ 1 .. Length( a ) ] do + if a[i] < 0 then + a[i]:= a[i] mod m; + fi; + od; + fi; end ); -InstallOtherMethod( BaseDomain, "for a zmodnz matrix", - [ IsZmodnZMatrixRep ], - M -> M![BDPOS] ); - -InstallMethod( NumberRows, "for a zmodnz matrix", - [ IsZmodnZMatrixRep ], - M -> Length( M![ROWSPOS] ) ); - -InstallMethod( NumberColumns, "for a zmodnz matrix", - [ IsZmodnZMatrixRep ], - M -> M![RLPOS] ); - +InstallOtherMethod( AddRowVector, + [ "IsZmodnZVectorRep and IsMutable", "IsPlistRep", "IsObject" ], + function( a, b, s ) + local bd, i, m; + if not ForAll( b, IsModulusRep ) then + TryNextMethod(); + fi; + bd:= a![ZBDPOS]; + if not IsInt( s ) then + if IsRat( s ) then + s:= s mod m; + elif s in bd then + s:= Int( s ); + else + Error( "multiplication with is not supported" ); + fi; + fi; + m:= Size( a![ZBDPOS] ); + a:= a![ZELSPOS]; + b:= List( b, x -> x![1] ); -############################################################################ -# Representation preserving constructors: -############################################################################ + if IsSmallIntRep( s ) then + ADD_ROW_VECTOR_3_FAST( a, b, s ); + else + ADD_ROW_VECTOR_3( a, b, s ); + fi; + if s >= 0 then + for i in [ 1 .. Length( a ) ] do + if a[i] >= m then + a[i]:= a[i] mod m; + fi; + od; + else + for i in [ 1 .. Length( a ) ] do + if a[i] < 0 then + a[i]:= a[i] mod m; + fi; + od; + fi; + end ); +#TODO: Do we want this? If yes then it should be documented. -# redundant according to MH -# InstallMethod( ZeroMatrix, "for two integers and a zmodnz matrix", -# [ IsInt, IsInt, IsZmodnZMatrixRep ], -# function( rows,cols,m ) -# local l,t,res; -# t := m![EMPOS]; -# l := List([1..rows],i->ZeroVector(cols,t)); -# res := Objectify( TypeObj(m), [m![BDPOS],t,cols,l] ); -# if not IsMutable(m) then -# SetFilterObj(res,IsMutable); -# fi; -# return res; -# end ); - -InstallMethod( IdentityMatrix, "for an integer and a zmodnz matrix", - [ IsInt, IsZmodnZMatrixRep ], - function( rows,m ) - local i,l,o,t,res; - t := m![EMPOS]; - l := List([1..rows],i->ZeroVector(rows,t)); - o := One(m![BDPOS]); - for i in [1..rows] do - l[i][i] := o; - od; - res := Objectify( TypeObj(m), [m![BDPOS],t,rows,l] ); - if not IsMutable(m) then - SetFilterObj(res,IsMutable); +InstallOtherMethod( AddRowVector, + [ "IsPlistRep and IsMutable", "IsZmodnZVectorRep", "IsObject" ], + function( a, b, s ) + local i; + if not ForAll( a, IsModulusRep ) then + TryNextMethod(); fi; - return res; + for i in [ 1 .. Length( a ) ] do + a[i]:= a[i] + b[i] * s; + od; end ); +#TODO: Do we want this? If yes then it should be documented. -InstallMethod( Matrix, "for a list and a zmodnz matrix", - [ IsList, IsInt, IsZmodnZMatrixRep ], - function( rows,rowlen,m ) - local i,l,nrrows,res,t; - t := m![EMPOS]; - if Length(rows) > 0 then - if IsVectorObj(rows[1]) and IsZmodnZVectorRep(rows[1]) then - nrrows := Length(rows); - l := rows; - elif IsList(rows[1]) then - nrrows := Length(rows); - l := ListWithIdenticalEntries(Length(rows),0); - for i in [1..Length(rows)] do - l[i] := Vector(rows[i],t); - od; - else # a flat initializer: - nrrows := Length(rows)/rowlen; - l := ListWithIdenticalEntries(nrrows,0); - for i in [1..nrrows] do - l[i] := Vector(rows{[(i-1)*rowlen+1..i*rowlen]},t); - od; - fi; +InstallMethod( AddRowVector, + [ "IsZmodnZVectorRep and IsMutable", "IsZmodnZVectorRep", + "IsObject", "IsPosInt", "IsPosInt" ], + function( a, b, s, from, to ) + local bd, i, m; + bd:= a![ZBDPOS]; + if ValueOption( "check" ) <> false and + not IsIdenticalObj( bd, b![ZBDPOS] ) then + Error( " and are not compatible" ); + fi; + if not IsInt( s ) then + if IsRat( s ) then + s:= s mod m; + elif s in bd then + s:= Int( s ); + else + Error( "multiplication with is not supported" ); + fi; + fi; + a:= a![ZELSPOS]; + if IsSmallIntRep( s ) then + ADD_ROW_VECTOR_5_FAST( a, b![ZELSPOS], s, from, to ); else - l := []; - nrrows := 0; + ADD_ROW_VECTOR_5( a, b![ZELSPOS], s, from, to ); fi; - res := Objectify( TypeObj(m), [m![BDPOS],t,rowlen,l] ); - if not IsMutable(m) then - SetFilterObj(res,IsMutable); + m:= Size( b![ZBDPOS] ); + if s>=0 then + for i in [ 1 .. Length( a ) ] do + if a[i] >= m then + a[i]:= a[i] mod m; + fi; + od; + else + for i in [ 1 .. Length( a ) ] do + if a[i] < 0 then + a[i]:= a[i] mod m; + fi; + od; fi; - return res; end ); -############################################################################ -# Printing and viewing methods: -############################################################################ - -InstallMethod( ViewObj, "for a zmodnz matrix", [ IsZmodnZMatrixRep ], - function( m ) - local l; - Print("<"); - if not IsMutable(m) then Print("immutable "); fi; - l:=[Length(m![ROWSPOS]),m![RLPOS]]; - if Product(l)<=9 and Product(l)<>0 then - Print("matrix mod ",Size(m![BDPOS]),": ", - List(m![ROWSPOS],x->x![ELSPOS]),">"); +InstallMethod( MultVectorLeft, + [ "IsZmodnZVectorRep and IsMutable", "IsObject" ], + function( v, s ) + local b, m, i; + b:= v![ZBDPOS]; + m:= Size( b ); + if not IsInt( s ) then + if IsRat( s ) then + s:= s mod m; + elif s in b then + s:= Int( s ); + else + Error( "multiplication with is not supported" ); + fi; + fi; + v:= v![ZELSPOS]; + MULT_VECTOR_2_FAST( v, s ); + if s >= 0 then + for i in [ 1 .. Length( v ) ] do + if v[i] >= m then + v[i]:= v[i] mod m; + fi; + od; else - Print(l[1],"x",l[2],"-matrix mod ",Size(m![BDPOS]),">"); + for i in [ 1 .. Length( v ) ] do + if v[i] < 0 then + v[i]:= v[i] mod m; + fi; + od; fi; end ); -InstallMethod( PrintObj, "for a zmodnz matrix", [ IsZmodnZMatrixRep ], - function( m ) - Print("NewMatrix(IsZmodnZMatrixRep"); - if IsFinite(m![BDPOS]) and IsField(m![BDPOS]) then - Print(",GF(",Size(m![BDPOS]),"),"); +InstallMethod( MultVectorRight, + [ "IsZmodnZVectorRep and IsMutable", "IsObject" ], + MultVectorLeft ); + +InstallMethod( MultVectorLeft, + [ "IsZmodnZVectorRep and IsMutable", "IsObject", "IsInt", "IsInt" ], + function( v, s, from, to ) + local b, m, i; + b:= v![ZBDPOS]; + m:= Size( b ); + if not IsInt( s ) then + if IsRat( s ) then + s:= s mod m; + elif s in b then + s:= Int( s ); + else + Error( "multiplication with is not supported" ); + fi; + fi; + v:= v![ZELSPOS]; + for i in [ from .. to ] do + v[i]:= s * v[i]; + od; + if s >= 0 then + for i in [ from .. to ] do + if v[i] >= m then + v[i]:= v[i] mod m; + fi; + od; else - Print(",",String(m![BDPOS]),","); + for i in [ from .. to ] do + if v[i] < 0 then + v[i]:= v[i] mod m; + fi; + od; fi; - Print(NumberColumns(m),",",Unpack(m),")"); end ); -InstallMethod( Display, "for a zmodnz matrix", [ IsZmodnZMatrixRep ], - function( m ) - Print("<"); - if not IsMutable(m) then Print("immutable "); fi; - Print(Length(m![ROWSPOS]),"x",m![RLPOS],"-matrix over ",m![BDPOS],":\n"); - Display(List(m![ROWSPOS],x->x![ELSPOS])); -# for i in [1..Length(m![ROWSPOS])] do -# if i = 1 then -# Print("["); -# else -# Print(" "); -# fi; -# Print(m![ROWSPOS][i]![ELSPOS],"\n"); -# od; - Print("]>\n"); - end ); +InstallMethod( MultVectorRight, + [ "IsZmodnZVectorRep and IsMutable", "IsObject", "IsInt", "IsInt" ], + MultVectorLeft ); -InstallMethod( String, "for zmodnz matrix", [ IsZmodnZMatrixRep ], - function( m ) - local st; - st := "NewMatrix(IsZmodnZMatrixRep"; - Add(st,','); - if IsFinite(m![BDPOS]) and IsField(m![BDPOS]) then - Append(st,"GF("); - Append(st,String(Size(m![BDPOS]))); - Append(st,"),"); - else - Append(st,String(m![BDPOS])); - Append(st,","); +InstallMethod( IsZero, [ "IsZmodnZVectorRep" ], + v -> IsZero( v![ZELSPOS] ) ); + +InstallMethod( CopySubVector, + [ "IsZmodnZVectorRep", "IsZmodnZVectorRep and IsMutable", "IsList", "IsList" ], + function( a, b, pa, pb ) + if ValueOption( "check" ) <> false and + not IsIdenticalObj( a![ZBDPOS], b![ZBDPOS] ) then + Error( " and have different base domains" ); fi; - Append(st,String(NumberColumns(m))); - Add(st,','); - Append(st,String(Unpack(m))); - Add(st,')'); - return st; + # The following should eventually go into the kernel: + b![ZELSPOS]{pb}:= a![ZELSPOS]{pa}; end ); +# This is used in the 'MinimalPolynomial' method below. +InstallOtherMethod( ProductCoeffs, + [ "IsZmodnZVectorRep", "IsZmodnZVectorRep" ], + { l1, l2 } -> PRODUCT_COEFFS_GENERIC_LISTS( l1, Length( l1 ), l2, Length( l2 ) ) ); + ############################################################################ -# A selection of list operations: +## +## Dense matrix objects over rings 'Integers mod n', +## backed by plain lists of plain lists of integers. +## +## - Use the default 'Matrix' methods that delegate to 'NewMatrix'. +## - Use the default 'ZeroMatrix( rows, cols, mat )' method +## that delegates to 'NewZeroMatrix'. +## - Use the default 'IdentityMatrix' methods that delegate to +## 'NewIdentityMatrix'. +## - Use the default 'OneMutable', 'OneImmutable', 'OneSameMutability' +## methods, which call 'IdentityMatrix'. +## - Use the default 'InverseImmutable', 'InverseSameMutability' methods. + + ############################################################################ +## +#F MakeIsZmodnZMatrixRep( , , , ) +## +## Construct a new matrix in the filter 'IsZmodnZMatrixRep' with base domain +## and in the list of lists . +## Each entry of must have length . +## +## If is set to 'true' *and* 'ValueOption( "check" )' is 'true', +## then it is checked that the entries of are plain lists of length +## and with entries either all in or integers +## in the range '[ 0 .. n-1 ]'. +## So whenever you know that the input satisfies these conditions, +## pass 'false' for to omit these (potentially costly) consistency +## checks. +## +BindGlobal( "MakeIsZmodnZMatrixRep", + function( basedomain, ncols, list, check ) + local fam, filter, typ, row, copied, i; + + # The types are always cached in 'fam'. + fam:= CollectionsFamily( FamilyObj( basedomain ) ); + if not IsBound( fam!.ZmodnZMatrixRepTypes ) then + # initialize type cache + # TODO: make this thread safe for HPC-GAP + filter:= IsZmodnZMatrixRep and CanEasilyCompareElements; + fam!.ZmodnZMatrixRepTypes:= [ + NewType( fam, filter ), + NewType( fam, filter and IsMutable ), + ]; + fi; + if IsMutable( list ) then + typ:= fam!.ZmodnZMatrixRepTypes[2]; + else + typ:= fam!.ZmodnZMatrixRepTypes[1]; + fi; -InstallOtherMethod( \[\], "for a zmodnz matrix and a positive integer", -#T Once the declaration of '\[\]' for 'IsMatrixObj' disappears, -#T we can use 'InstallMethod'. - [ IsZmodnZMatrixRep, IsPosInt ], - function( m, p ) - return m![ROWSPOS][p]; - end ); + check:= check and ValueOption( "check" ) <> false; -InstallOtherMethod( \[\]\:\=, - "for a zmodnz matrix, a positive integer, and a zmodnz vector", - [ IsZmodnZMatrixRep and IsMutable, IsPosInt, IsZmodnZVectorRep ], - function( m, p, v ) - m![ROWSPOS][p] := v; - end ); + if check then + Assert( 0, IsPlistRep( list ) ); + for row in list do + if not IsPlistRep( row ) then + # Some kernel functions really need 'IsPlistRep'. + Error( "the entries of must be plain lists" ); + elif Length( row ) <> ncols then + Error( "the entries of must have length " ); + fi; + od; + fi; -InstallOtherMethod( \{\}, "for a zmodnz matrix and a list", - [ IsZmodnZMatrixRep, IsList ], - function( m, p ) - local l; - l := m![ROWSPOS]{p}; - return Objectify(TypeObj(m),[m![BDPOS],m![EMPOS],m![RLPOS],l]); - end ); + copied:= false; + for i in [ 1 .. Length( list ) ] do + if FamilyObj( basedomain ) = FamilyObj( list[i] ) then + if check then + if not ( IsZmodnZObjNonprimeCollection( basedomain ) or + ( IsFinite( basedomain ) and IsPrimeField( basedomain ) ) ) then + Error( " must be Integers mod for some " ); + elif not IsSubset( basedomain, list[i] ) then + Error( "[", i, "] must be a list of reduced integers ", + "or of elements in " ); + fi; + fi; + # Here we have to copy. + if not copied then + copied:= true; + list:= ShallowCopy( list ); + fi; + list[i]:= List( list[i], Int ); + elif check then + # Here we have to check that the entries are reduced integers. + if not ( ( IsCyclotomicCollection( list[i] ) or IsEmpty( list[i] ) ) + and + IsSubset( [ 0 .. Size( basedomain ) - 1 ], list[i] ) ) then + Error( "[", i, "] must be a list of reduced integers ", + "or of elements in " ); + fi; + fi; + od; -InstallMethod( Add, "for a zmodnz matrix and a zmodnz vector", - [ IsZmodnZMatrixRep and IsMutable, IsZmodnZVectorRep ], - function( m, v ) - Add(m![ROWSPOS],v); + return Objectify( typ, [ basedomain, ncols, list ] ); end ); -InstallMethod( Add, "for a zmodnz matrix, a zmodnz vector, and a pos. int", - [ IsZmodnZMatrixRep and IsMutable, IsZmodnZVectorRep, IsPosInt ], - function( m, v, p ) - Add(m![ROWSPOS],v,p); - end ); -InstallMethod( Remove, "for a zmodnz matrix", - [ IsZmodnZMatrixRep and IsMutable ], - m -> Remove( m![ROWSPOS] ) ); +InstallTagBasedMethod( NewMatrix, + IsZmodnZMatrixRep, + function( filter, basedomain, ncols, list ) + local len, nd, rows, i, row; + + # If applicable then replace a flat list 'list' by a nested list + # of lists of length 'ncols'. + len:= Length( list ); + if len > 0 and not IsVectorObj( list[1] ) then + nd:= NestingDepthA( list ); + if nd < 2 or nd mod 2 = 1 then + if len mod ncols <> 0 then + Error( "NewMatrix: Length of is not a multiple of " ); + fi; + list:= List( [ 0, ncols .. len - ncols ], + i -> list{ [ i + 1 .. i + ncols ] } ); + fi; + len:= Length( list ); + fi; -InstallMethod( Remove, "for a zmodnz matrix, and a position", - [ IsZmodnZMatrixRep and IsMutable, IsPosInt ], - function( m, p ) - Remove( m![ROWSPOS],p ); + rows:= EmptyPlist( len ); + for i in [ 1 .. len ] do + row:= list[i]; + if IsVectorObj( row ) then + rows[i]:= Unpack( row ); + else + rows[i]:= PlainListCopy( row ); + fi; + od; + return MakeIsZmodnZMatrixRep( basedomain, ncols, rows, true ); end ); -#T must return the removed row if it was bound -InstallMethod( IsBound\[\], "for a zmodnz matrix, and a position", - [ IsZmodnZMatrixRep, IsPosInt ], - function( m, p ) - return p <= Length(m![ROWSPOS]); - end ); -InstallMethod( Unbind\[\], "for a zmodnz matrix, and a position", - [ IsZmodnZMatrixRep and IsMutable, IsPosInt ], - function( m, p ) - if p <> Length(m![ROWSPOS]) then - ErrorNoReturn("Unbind\\[\\]: Matrices must stay dense, you cannot Unbind here"); - fi; - Unbind( m![ROWSPOS][p] ); +InstallTagBasedMethod( NewZeroMatrix, + IsZmodnZMatrixRep, + function( filter, basedomain, rows, ncols ) + local list, z, i; + list := EmptyPlist( rows ); + z := Zero( basedomain ); + for i in [ 1 .. rows ] do + list[i] := ListWithIdenticalEntries( ncols, z ); + od; + return MakeIsZmodnZMatrixRep( basedomain, ncols, list, false ); end ); -InstallMethod( \{\}\:\=, "for a zmodnz matrix, a list, and a zmodnz matrix", - [ IsZmodnZMatrixRep and IsMutable, IsList, - IsZmodnZMatrixRep ], - function( m, pp, n ) - m![ROWSPOS]{pp} := n![ROWSPOS]; - end ); -InstallMethod( Append, "for two zmodnz matrices", - [ IsZmodnZMatrixRep and IsMutable, IsZmodnZMatrixRep ], - function( m, n ) - Append(m![ROWSPOS],n![ROWSPOS]); +# Avoid dealing with 'One( basedomain )'. +InstallTagBasedMethod( NewIdentityMatrix, + IsZmodnZMatrixRep, + function( filter, basedomain, dim ) + local mat, i; + mat:= NewZeroMatrix( filter, basedomain, dim, dim ); + for i in [ 1 .. dim ] do + mat[i,i]:= 1; + od; + return mat; end ); -InstallMethod( ShallowCopy, "for a zmodnz matrix", - [ IsZmodnZMatrixRep ], - function( m ) - local res; - res := Objectify(TypeObj(m),[m![BDPOS],m![EMPOS],m![RLPOS], - ShallowCopy(m![ROWSPOS])]); - if not IsMutable(m) then - SetFilterObj(res,IsMutable); - fi; -#T 'ShallowCopy' MUST return a mutable object -#T if such an object exists at all! - return res; - end ); -InstallMethod( PostMakeImmutable, "for a zmodnz matrix", - [ IsZmodnZMatrixRep ], - function( m ) - MakeImmutable( m![ROWSPOS] ); - end ); +InstallOtherMethod( ConstructingFilter, + [ "IsZmodnZMatrixRep" ], + M -> IsZmodnZMatrixRep ); -InstallOtherMethod( ListOp, "for a zmodnz matrix", - [ IsZmodnZMatrixRep ], - function( m ) - return List(m![ROWSPOS]); - end ); +InstallMethod( CompatibleVectorFilter, + [ "IsZmodnZMatrixRep" ], + M -> IsZmodnZVectorRep ); -InstallOtherMethod( ListOp, "for a zmodnz matrix and a function", - [ IsZmodnZMatrixRep, IsFunction ], - function( m, f ) - return List(m![ROWSPOS],f); +InstallMethod( CompatibleVector, + [ "IsZmodnZMatrixRep" ], + M -> NewZeroVector( IsZmodnZVectorRep, BaseDomain( M ), NumberRows( M ) ) ); + + +InstallOtherMethod( BaseDomain, + [ "IsZmodnZMatrixRep" ], + M -> M![ZBDPOS] ); + +InstallMethod( NumberRows, + [ "IsZmodnZMatrixRep" ], + M -> Length(M![ZROWSPOS]) ); + +InstallMethod( NumberColumns, + [ "IsZmodnZMatrixRep" ], + M -> M![ZCOLSPOS] ); + +InstallMethod( \[\], + [ "IsZmodnZMatrixRep", "IsPosInt" ], + function( M, pos ) + ErrorNoReturn( "row access unsupported; use M[i,j] or RowsOfMatrix(M)" ); + end ); + +InstallMethod( MatElm, + [ "IsZmodnZMatrixRep", "IsPosInt", "IsPosInt" ], + { M, row, col } -> ZmodnZObj( ElementsFamily( FamilyObj( M![ZBDPOS] ) ), + M![ZROWSPOS][row, col] ) ); + +InstallMethod( SetMatElm, + [ "IsZmodnZMatrixRep and IsMutable", "IsPosInt", "IsPosInt", "IsObject" ], + function( M, row, col, ob ) + local R; + if ValueOption( "check" ) <> false then + R:= BaseDomain( M ); + if row > NrRows( M ) then + Error( " is out of bounds" ); + elif col > NrCols( M ) then + Error( " is out of bounds" ); + elif IsInt( ob ) then + ob:= ob mod Size( R ); + elif ob in R then + ob:= Int( ob ); + else + Error( " must be an integer or lie in the base domain of " ); + fi; + M![ZROWSPOS][row, col]:= ob; + else + M![ZROWSPOS][row, col]:= Int( ob ); + fi; end ); -InstallOtherMethod( Unpack, "for a zmodnz matrix", - [ IsZmodnZMatrixRep ], -function( m ) -local fam; - fam:=ElementsFamily(FamilyObj(BaseDomain(m))); - return List(m![ROWSPOS],v-> - List([1..Length(v![ELSPOS])],x->ZmodnZObj(fam,v![ELSPOS][x]))); +# Avoid 'Unpack'. +InstallMethod( RowsOfMatrix, + [ "IsZmodnZMatrixRep" ], + function( M ) + local R; + + R:= BaseDomain( M ); + return List( M![ZROWSPOS], row -> MakeIsZmodnZVectorRep( R, row, false ) ); end ); -InstallMethod( MutableCopyMatrix, "for a zmodnz matrix", - [ IsZmodnZMatrixRep ], - function( m ) - local l,res; - l := List(m![ROWSPOS],ShallowCopy); - res := Objectify(TypeObj(m),[m![BDPOS],m![EMPOS],m![RLPOS],l]); - if not IsMutable(m) then - SetFilterObj(res,IsMutable); - fi; - return res; - end); +InstallMethod( Unpack, + [ "IsZmodnZMatrixRep" ], + function( M ) + local fam; + fam:= ElementsFamily( FamilyObj( BaseDomain( M ) ) ); + return List( M![ZROWSPOS], + v -> List( v, x -> ZmodnZObj( fam, x ) ) ); + end ); -InstallMethod( ExtractSubMatrix, "for a zmodnz matrix, and two lists", - [ IsZmodnZMatrixRep, IsList, IsList ], - function( m, p, q ) - local i,l; - l := m![ROWSPOS]{p}; - for i in [1..Length(l)] do - l[i] := Objectify(TypeObj(l[i]),[l[i]![BDPOS],l[i]![ELSPOS]{q}]); - od; - return Objectify(TypeObj(m),[m![BDPOS],m![EMPOS],Length(q),l]); - end ); +InstallMethod( ShallowCopy, + [ "IsZmodnZMatrixRep" ], + M -> MakeIsZmodnZMatrixRep( M![ZBDPOS], M![ZCOLSPOS], + List( M![ZROWSPOS], ShallowCopy ), false ) ); -InstallMethod( CopySubMatrix, "for two zmodnz matrices and four lists", - [ IsZmodnZMatrixRep, IsZmodnZMatrixRep and IsMutable, - IsList, IsList, IsList, IsList ], - function( m, n, srcrows, dstrows, srccols, dstcols ) - local i; - if ValueOption( "check" ) <> false and m![BDPOS] <> n![BDPOS] then - Error( " and have different base domains" ); - fi; - # This eventually should go into the kernel without creating - # a intermediate objects: - for i in [1..Length(srcrows)] do - n![ROWSPOS][dstrows[i]]![ELSPOS]{dstcols} := - m![ROWSPOS][srcrows[i]]![ELSPOS]{srccols}; - od; - end ); +InstallMethod( MutableCopyMatrix, + [ "IsZmodnZMatrixRep" ], + M -> MakeIsZmodnZMatrixRep( M![ZBDPOS], M![ZCOLSPOS], + List( M![ZROWSPOS], ShallowCopy ), false ) ); -# InstallOtherMethod( CopySubMatrix, -# "for two zmodnzs -- fallback in case of bad rep.", -# [ IsZmodnZRep, IsZmodnZRep and IsMutable, -# IsList, IsList, IsList, IsList ], -# function( m, n, srcrows, dstrows, srccols, dstcols ) -# local i; -# # in this representation all access probably has to go through the -# # generic method selection, so it is not clear whether there is an -# # improvement in moving this into the kernel. -# for i in [1..Length(srcrows)] do -# n[dstrows[i]]{dstcols}:=m[srcrows[i]]{srccols}; -# od; -# end ); - -InstallMethod( MatElm, "for a zmodnz matrix and two positions", - [ IsZmodnZMatrixRep, IsPosInt, IsPosInt ], - function( m, row, col ) - return ZmodnZObj(ElementsFamily(FamilyObj(m![BDPOS])), - m![ROWSPOS][row]![ELSPOS][col]); - end ); +InstallMethod( ExtractSubMatrix, + [ "IsZmodnZMatrixRep", "IsList", "IsList" ], + { M, rowspos, colspos } -> MakeIsZmodnZMatrixRep( M![ZBDPOS], + Length( colspos ), + M![ZROWSPOS]{ rowspos }{ colspos }, false ) ); -InstallMethod( SetMatElm, "for a zmodnz matrix, two positions, and an object", - [ IsZmodnZMatrixRep and IsMutable, IsPosInt, IsPosInt, IsObject ], - function( m, row, col, ob ) +InstallMethod( CopySubMatrix, + [ "IsZmodnZMatrixRep", "IsZmodnZMatrixRep and IsMutable", + "IsList", "IsList", "IsList", "IsList" ], + function( M, N, srcrows, dstrows, srccols, dstcols ) if ValueOption( "check" ) <> false and - not ( IsInt( ob ) or ob in BaseDomain( m ) ) then - Error( " must be an integer or in the base domain of " ); + not IsIdenticalObj( M![ZBDPOS], N![ZBDPOS] ) then + Error( " and are not compatible" ); fi; - m![ROWSPOS][row]![ELSPOS][col] := Int(ob); + N![ZROWSPOS]{ dstrows }{ dstcols }:= M![ZROWSPOS]{ srcrows }{ srccols }; end ); +InstallMethod( TransposedMatMutable, + [ "IsZmodnZMatrixRep" ], + M -> MakeIsZmodnZMatrixRep( M![ZBDPOS], NrRows( M ), + TransposedMatMutable( M![ZROWSPOS] ), false ) ); -############################################################################ -# Arithmetical operations: -############################################################################ - -InstallMethod( \+, "for two zmodnz matrices", - [ IsZmodnZMatrixRep, IsZmodnZMatrixRep ], +InstallMethod( \+, + [ "IsZmodnZMatrixRep", "IsZmodnZMatrixRep" ], function( a, b ) - local ty; - if not IsMutable(a) and IsMutable(b) then - ty := TypeObj(b); + local ncols, bd, modulus, res; + + ncols:= a![ZCOLSPOS]; + bd:= a![ZBDPOS]; + if ValueOption( "check" ) <> false and + ( not IsIdenticalObj( bd, b![ZBDPOS] ) or + NrRows( a ) <> NrRows( b ) or + ncols <> b![ZCOLSPOS] ) then + Error( " and are not compatible" ); + fi; + modulus:= Size( bd ); + res:= SUM_LIST_LIST_DEFAULT( a![ZROWSPOS], b![ZROWSPOS] ); + if IsMutable( res ) then + res:= List( res, row -> ZNZVECREDUCE( row, ncols, modulus ) ); else - ty := TypeObj(a); + res:= MakeImmutable( List( res, + row -> ZNZVECREDUCE( row, ncols, modulus ) ) ); fi; - return Objectify(ty,[a![BDPOS],a![EMPOS],a![RLPOS], - SUM_LIST_LIST_DEFAULT(a![ROWSPOS],b![ROWSPOS])]); + return MakeIsZmodnZMatrixRep( bd, ncols, res, false ); end ); -InstallMethod( \-, "for two zmodnz matrices", - [ IsZmodnZMatrixRep, IsZmodnZMatrixRep ], +InstallMethod( \-, + [ "IsZmodnZMatrixRep", "IsZmodnZMatrixRep" ], function( a, b ) - local ty; - if not IsMutable(a) and IsMutable(b) then - ty := TypeObj(b); + local ncols, bd, modulus, res; + + ncols:= a![ZCOLSPOS]; + bd:= a![ZBDPOS]; + if ValueOption( "check" ) <> false and + ( not IsIdenticalObj( bd, b![ZBDPOS] ) or + NrRows( a ) <> NrRows( b ) or + ncols <> b![ZCOLSPOS] ) then + Error( " and are not compatible" ); + fi; + modulus:= Size( bd ); + res:= DIFF_LIST_LIST_DEFAULT( a![ZROWSPOS], b![ZROWSPOS] ); + if IsMutable( res ) then + res:= List( res, row -> ZNZVECREDUCE( row, ncols, modulus ) ); else - ty := TypeObj(a); + res:= MakeImmutable( List( res, + row -> ZNZVECREDUCE( row, ncols, modulus ) ) ); fi; - return Objectify(ty,[a![BDPOS],a![EMPOS],a![RLPOS], - DIFF_LIST_LIST_DEFAULT(a![ROWSPOS],b![ROWSPOS])]); + return MakeIsZmodnZMatrixRep( bd, ncols, res, false ); + end ); + +InstallMethod( AdditiveInverseMutable, + [ "IsZmodnZMatrixRep" ], + function( M ) + local ncols, bd, modulus, res; + + ncols:= M![ZCOLSPOS]; + bd:= M![ZBDPOS]; + modulus:= Size( bd ); + res:= AdditiveInverseMutable( M![ZROWSPOS] ); + res:= List( res, row -> ZMODNZVECADDINVCLEANUP( modulus, row ) ); + return MakeIsZmodnZMatrixRep( bd, ncols, res, false ); + end ); + +InstallMethod( ZeroMutable, + [ "IsZmodnZMatrixRep" ], + function( M ) + local z; + z := MakeIsZmodnZMatrixRep( M![ZBDPOS], M![ZCOLSPOS], + ZeroMutable( M![ZROWSPOS] ), false ); + SetIsZero( z, true ); + return z; + end ); + +# Avoid 'Unpack'. +InstallMethod( InverseMutable, + [ "IsZmodnZMatrixRep" ], + function( M ) + local nrows, rows, modulus; + + nrows:= NrRows( M ); + if nrows <> NrCols( M ) then + return fail; + elif nrows = 0 then + rows:= []; + else + rows:= INV_MATRIX_MUTABLE( M![ZROWSPOS] ); + fi; + if rows = fail then + return fail; + fi; + modulus:= Size( M![ZBDPOS] ); + # Here the entries can be non-integral rationals, + # so 'ZNZVECREDUCE' is not enough. + rows:= List( rows, v -> MOD_LIST_SCL_DEFAULT( v, modulus ) ); + + return MakeIsZmodnZMatrixRep( M![ZBDPOS], M![ZCOLSPOS], rows, false ); end ); -InstallMethod( \*, "for two zmodnz matrices",IsIdenticalObj, - [ IsZmodnZMatrixRep, IsZmodnZMatrixRep ], +InstallMethod( \*, + [ "IsZmodnZMatrixRep", "IsZmodnZMatrixRep" ], function( a, b ) - # Here we do full checking since it is rather cheap! - local i,j,l,ty,v,w,m,r; - if not IsMutable(a) and IsMutable(b) then - ty := TypeObj(b); + local rowsA, colsA, rowsB, colsB, bd, list, res, m; + + rowsA := NumberRows( a ); + colsA := NumberColumns( a ); + rowsB := NumberRows( b ); + colsB := NumberColumns( b ); + bd := BaseDomain( a ); + + if ValueOption( "check" ) <> false then + if colsA <> rowsB then + ErrorNoReturn( "\\*: Matrices do not fit together" ); + elif not IsIdenticalObj( bd, b![ZBDPOS] ) then + ErrorNoReturn( "\\*: Matrices not over same base domain" ); + fi; + fi; + + if rowsA = 0 or colsB = 0 then + list := []; + elif colsA = 0 then # colsA = rowsB + if IsMutable( a ) or IsMutable( b ) then + return ZeroMatrix( rowsA, colsB, a ); + else + return MakeImmutable( ZeroMatrix( rowsA, colsB, a ) ); + fi; else - ty := TypeObj(a); - fi; - if not a![RLPOS] = Length(b![ROWSPOS]) then - ErrorNoReturn("\\*: Matrices do not fit together"); - fi; - if not IsIdenticalObj(a![BDPOS],b![BDPOS]) then - ErrorNoReturn("\\*: Matrices not over same base domain"); - fi; - r:=BaseDomain(a); - m:=Size(r); - l := ListWithIdenticalEntries(Length(a![ROWSPOS]),0); - for i in [1..Length(l)] do - if b![RLPOS] = 0 then - l[i] := b![EMPOS]; - else - v := a![ROWSPOS][i]; - - # do arithmetic over Z first and reduce afterwards - w:=ListWithIdenticalEntries(b![RLPOS],0); - v:=v![ELSPOS]; - for j in [1..a![RLPOS]] do - AddRowVector(w,b![ROWSPOS][j]![ELSPOS],v[j]); - #if (j mod 1000=0) and not ForAll(w,IsSmallIntRep) then - # ZNZVECREDUCE(w,b![RLPOS],m); - #fi; - od; - ZNZVECREDUCE(w,b![RLPOS],m); - w:=Vector(r,w); - - l[i] := w; - fi; - od; - if not IsMutable(a) and not IsMutable(b) then - MakeImmutable(l); + res:= a![ZROWSPOS] * b![ZROWSPOS]; + m:= Size( bd ); + list:= List( res, row -> ZNZVECREDUCE( row, colsB, m ) ); + if not IsMutable( res ) then + MakeImmutable( list ); + fi; fi; - return Objectify( ty, [a![BDPOS],a![EMPOS],b![RLPOS],l] ); + return MakeIsZmodnZMatrixRep( a![ZBDPOS], b![ZCOLSPOS], list, false ); end ); -InstallMethod(\*,"for zmodnz matrix and ordinary matrix",IsIdenticalObj, - [IsZmodnZMatrixRep,IsMatrix], +InstallMethod(\*, + IsIdenticalObj, + [ "IsZmodnZMatrixRep", "IsMatrix" ], function(a,b) return Matrix(BaseDomain(a),List(RowsOfMatrix(a),x->x*b)); end); +#TODO: Do we want this? If yes then it should be documented. +BindGlobal( "ZMZMATVEC", function( M, v ) + local rows, cols, bd, res; -InstallMethod( \=, "for two zmodnz matrices",IsIdenticalObj, - [ IsZmodnZMatrixRep, IsZmodnZMatrixRep ], - function( a, b ) - return EQ_LIST_LIST_DEFAULT(a![ROWSPOS],b![ROWSPOS]); - end ); + rows := NumberRows( M ); + cols := NumberColumns( M ); + bd := BaseDomain( M ); -InstallMethod( \=, "for zmodnz matrix and matrix",IsIdenticalObj, - [ IsZmodnZMatrixRep, IsMatrix ], - function( a, b ) - return Unpack(a)=b; - end ); + if ValueOption( "check" ) <> false and + ( not IsIdenticalObj( bd, v![ZBDPOS] ) or + cols <> Length( v ) ) then + Error( " and are not compatible" ); + fi; -InstallMethod( \=, "for matrix and zmodnz matrix",IsIdenticalObj, - [ IsMatrix, IsZmodnZMatrixRep ], - function( a, b ) - return a=Unpack(b); - end ); + # special case for empty matrices + if rows = 0 or cols = 0 then + return ZeroVector( rows, v ); + fi; + res:= M![ZROWSPOS] * v![ZELSPOS]; + res:= ZNZVECREDUCE( res, cols, Size( bd ) ); + return Vector( res, v ); +end ); -InstallMethod( \<, "for two zmodnz matrices",IsIdenticalObj, - [ IsZmodnZMatrixRep, IsZmodnZMatrixRep ], - function( a, b ) - return LT_LIST_LIST_DEFAULT(a![ROWSPOS],b![ROWSPOS]); - end ); +InstallMethod( \*, + [ "IsZmodnZMatrixRep", "IsZmodnZVectorRep" ], + ZMZMATVEC ); -InstallMethod( AdditiveInverseSameMutability, "for a zmodnz matrix", - [ IsZmodnZMatrixRep ], - function( m ) - local l; - l := List(m![ROWSPOS],AdditiveInverseSameMutability); - if not IsMutable(m) then - MakeImmutable(l); +BindGlobal( "ZMZVECMAT", function( v, M ) + local rows, cols, bd, res; + + rows := NumberRows( M ); + cols := NumberColumns( M ); + bd := BaseDomain( M ); + + if ValueOption( "check" ) <> false and + ( not IsIdenticalObj( v![ZBDPOS], bd ) or + Length( v ) <> rows ) then + Error( " and are not compatible" ); + fi; + + # special case for empty matrices + if rows = 0 or cols = 0 then + return ZeroVector( cols, v ); fi; - return Objectify( TypeObj(m), [m![BDPOS],m![EMPOS],m![RLPOS],l] ); + + res:= v![ZELSPOS] * M![ZROWSPOS]; + res:= ZNZVECREDUCE( res, rows, Size( bd ) ); + return Vector( res, v ); +end ); + +InstallMethod( \*, + [ "IsZmodnZVectorRep", "IsZmodnZMatrixRep" ], + ZMZVECMAT ); + +InstallOtherMethod( \^, + [ "IsZmodnZVectorRep", "IsZmodnZMatrixRep" ], + ZMZVECMAT ); + +InstallMethod( MultMatrixRowLeft, + [ "IsZmodnZMatrixRep and IsMutable", "IsInt", "IsObject" ], + function( mat, row, scalar ) + MultMatrixRowLeft( mat![ZROWSPOS], row, Int( scalar ) ); + ZNZVECREDUCE( mat![ZROWSPOS][row], mat![ZCOLSPOS], Size( mat![ZBDPOS] ) ); end ); -InstallMethod( AdditiveInverseImmutable, "for a zmodnz matrix", - [ IsZmodnZMatrixRep ], - function( m ) - local l,res; - l := List(m![ROWSPOS],AdditiveInverseImmutable); - res := Objectify( TypeObj(m), [m![BDPOS],m![EMPOS],m![RLPOS],l] ); - MakeImmutable(res); - return res; +InstallMethod( MultMatrixRowRight, + [ "IsZmodnZMatrixRep and IsMutable", "IsInt", "IsObject" ], + function( mat, row, scalar ) + MultMatrixRowRight( mat![ZROWSPOS], row, Int( scalar ) ); + ZNZVECREDUCE( mat![ZROWSPOS][row], mat![ZCOLSPOS], Size( mat![ZBDPOS] ) ); end ); -InstallMethod( AdditiveInverseMutable, "for a zmodnz matrix", - [ IsZmodnZMatrixRep ], - function( m ) - local l,res; - l := List(m![ROWSPOS],AdditiveInverseMutable); - res := Objectify( TypeObj(m), [m![BDPOS],m![EMPOS],m![RLPOS],l] ); - if not IsMutable(m) then - SetFilterObj(res,IsMutable); - fi; - return res; +InstallMethod( AddMatrixRowsLeft, + [ "IsZmodnZMatrixRep and IsMutable", "IsInt", "IsInt", "IsObject" ], + function( mat, row1, row2, scalar ) + AddMatrixRowsLeft( mat![ZROWSPOS], row1, row2, Int( scalar ) ); + ZNZVECREDUCE( mat![ZROWSPOS][row1], mat![ZCOLSPOS], Size( mat![ZBDPOS] ) ); end ); -InstallMethod( ZeroSameMutability, "for a zmodnz matrix", - [ IsZmodnZMatrixRep ], - function( m ) - local l; - l := List(m![ROWSPOS],ZeroSameMutability); - if not IsMutable(m) then - MakeImmutable(l); - fi; - return Objectify( TypeObj(m), [m![BDPOS],m![EMPOS],m![RLPOS],l] ); +InstallMethod( AddMatrixRowsRight, + [ "IsZmodnZMatrixRep and IsMutable", "IsInt", "IsInt", "IsObject" ], + function( mat, row1, row2, scalar ) + AddMatrixRowsRight( mat![ZROWSPOS], row1, row2, Int( scalar ) ); + ZNZVECREDUCE( mat![ZROWSPOS][row1], mat![ZCOLSPOS], Size( mat![ZBDPOS] ) ); end ); -InstallMethod( ZeroImmutable, "for a zmodnz matrix", - [ IsZmodnZMatrixRep ], - function( m ) - local l,res; - l := List(m![ROWSPOS],ZeroImmutable); - res := Objectify( TypeObj(m), [m![BDPOS],m![EMPOS],m![RLPOS],l] ); - MakeImmutable(res); - return res; +InstallMethod( PositionNonZeroInRow, + [ "IsZmodnZMatrixRep", "IsPosInt" ], + { mat, row } -> PositionNonZero( mat![ZROWSPOS][row] ) ); + +InstallMethod( PositionNonZeroInRow, + [ "IsZmodnZMatrixRep", "IsPosInt", "IsInt" ], + { mat, row, from } -> PositionNonZero( mat![ZROWSPOS][row], from ) ); + +InstallMethod( SwapMatrixRows, + [ "IsZmodnZMatrixRep and IsMutable", "IsInt", "IsInt" ], + function( mat, row1, row2 ) + SwapMatrixRows(mat![ZROWSPOS], row1, row2); end ); -InstallMethod( ZeroMutable, "for a zmodnz matrix", - [ IsZmodnZMatrixRep ], - function( m ) - local l,res; - l := List(m![ROWSPOS],ZeroMutable); - res := Objectify( TypeObj(m), [m![BDPOS],m![EMPOS],m![RLPOS],l] ); - if not IsMutable(m) then - SetFilterObj(res,IsMutable); - fi; - return res; +InstallMethod( SwapMatrixColumns, + [ "IsZmodnZMatrixRep and IsMutable", "IsInt", "IsInt" ], + function( mat, col1, col2 ) + SwapMatrixColumns(mat![ZROWSPOS], col1, col2); end ); -InstallMethod( IsZero, "for a zmodnz matrix", - [ IsZmodnZMatrixRep ], - function( m ) - local i; - for i in [1..Length(m![ROWSPOS])] do - if not IsZero(m![ROWSPOS][i]) then - return false; - fi; - od; - return true; + +InstallMethod( PostMakeImmutable, + [ "IsZmodnZMatrixRep" ], + function( M ) + MakeImmutable( M![ZROWSPOS] ); end ); -InstallMethod( OneSameMutability, "for a zmodnz matrix", - [ IsZmodnZMatrixRep ], - function( m ) - local o; - if m![RLPOS] <> Length(m![ROWSPOS]) then - #Error("OneSameMutability: Matrix is not square"); - #return; - return fail; - fi; - o := IdentityMatrix(m![RLPOS],m); - if not IsMutable(m) then - MakeImmutable(o); + +InstallMethod( ViewObj, + [ "IsZmodnZMatrixRep" ], + function( M ) + Print( "<" ); + if not IsMutable( M ) then + Print( "immutable " ); fi; - return o; + Print( NrRows( M ), "x", M![ZCOLSPOS], "-matrix over ", M![ZBDPOS], ">" ); end ); -InstallMethod( OneMutable, "for a zmodnz matrix", - [ IsZmodnZMatrixRep ], - function( m ) - if m![RLPOS] <> Length(m![ROWSPOS]) then - #Error("OneMutable: Matrix is not square"); - #return; - return fail; +InstallMethod( PrintObj, + [ "IsZmodnZMatrixRep" ], + function( M ) + Print( "NewMatrix(IsZmodnZMatrixRep" ); + if IsFinite( M![ZBDPOS] ) and IsField( M![ZBDPOS] ) then + Print( ",GF(", Size( M![ZBDPOS] ), ")," ); + else + Print( ",", String( M![ZBDPOS] ), "," ); fi; - return IdentityMatrix(m![RLPOS],m); + Print( NumberColumns( M ), ",", M![ZROWSPOS], ")" ); end ); -InstallMethod( OneImmutable, "for a zmodnz matrix", - [ IsZmodnZMatrixRep ], +InstallMethod( Display, + [ "IsZmodnZMatrixRep" ], function( m ) - local o; - if m![RLPOS] <> Length(m![ROWSPOS]) then - #Error("OneImmutable: Matrix is not square"); - #return; - return fail; - fi; - o := IdentityMatrix(m![RLPOS],m); - MakeImmutable(o); - return o; + Print( "<" ); + if not IsMutable( m ) then + Print( "immutable "); + fi; + Print( Length( m![ZROWSPOS] ), "x", m![ZCOLSPOS], + "-matrix over ", m![ZBDPOS], ":\n" ); + Display( m![ZROWSPOS] ); + Print( "]>\n" ); end ); -# For the moment we delegate to the fast kernel arithmetic for plain -# lists of plain lists: - -InstallMethod( InverseMutable, "for a zmodnz matrix", - [ IsZmodnZMatrixRep ], - function( m ) - local n,modulus; - modulus:=Size(BaseDomain(m)); - if m![RLPOS] <> Length(m![ROWSPOS]) then - #Error("InverseMutable: Matrix is not square"); - #return; - return fail; - fi; - # Make a plain list of lists: - n := List(m![ROWSPOS],x->x![ELSPOS]); - n := InverseMutable(n); # Invert! - if n = fail then return fail; fi; - n:=List(n,x->List(x,y->y mod modulus)); - return Matrix(n,Length(n),m); +InstallMethod( String, + [ "IsZmodnZMatrixRep" ], + function( M ) + local st; + st := "NewMatrix(IsZmodnZMatrixRep,"; + if IsFinite( M![ZBDPOS] ) and IsField( M![ZBDPOS] ) then + Append( st, "GF(" ); + Append( st, String( Size( M![ZBDPOS] ) ) ); + Append( st, ")," ); + else + Append( st, String( M![ZBDPOS] ) ); + Append( st, "," ); + fi; + Append( st, String( NumberColumns( M ) ) ); + Add( st, ',' ); + Append( st, String( M![ZROWSPOS] ) ); + Add( st, ')' ); + return st; end ); -InstallMethod( InverseImmutable, "for a zmodnz matrix", - [ IsZmodnZMatrixRep ], - function( m ) - local n,modulus; - modulus:=Size(BaseDomain(m)); - if m![RLPOS] <> Length(m![ROWSPOS]) then - #Error("InverseMutable: Matrix is not square"); - #return; - return fail; - fi; - # Make a plain list of lists: - n := List(m![ROWSPOS],x->x![ELSPOS]); - n := InverseMutable(n); # Invert! - if n = fail then return fail; fi; - n:=List(n,x->List(x,y->y mod modulus)); - n := Matrix(n,Length(n),m); - MakeImmutable(n); - return n; - end ); -InstallMethod( InverseSameMutability, "for a zmodnz matrix", - [ IsZmodnZMatrixRep ], - function( m ) - local n,modulus; - modulus:=Size(BaseDomain(m)); - if m![RLPOS] <> Length(m![ROWSPOS]) then - #Error("InverseMutable: Matrix is not square"); - #return; - return fail; - fi; - # Make a plain list of lists: - n := List(m![ROWSPOS],x->x![ELSPOS]); - n := InverseMutable(n); # Invert! - if n = fail then return fail; fi; - n:=List(n,x->List(x,y->y mod modulus)); - n := Matrix(n,Length(n),m); - if not IsMutable(m) then - MakeImmutable(n); - fi; - return n; - end ); +# Avoid 'Unpack' +InstallMethod( \=, IsIdenticalObj, + [ "IsZmodnZMatrixRep", "IsZmodnZMatrixRep" ], + { a, b } -> EQ_LIST_LIST_DEFAULT( a![ZROWSPOS], b![ZROWSPOS] ) ); -InstallMethod( RankMat, "for a zmodnz matrix", [ IsZmodnZMatrixRep ], -function( m ) - m:=MutableCopyMatrix(m); - m:=SemiEchelonMatDestructive(m); - if m<>fail then m:=Length(m.vectors);fi; - return m; -end); +InstallMethod( \=, IsIdenticalObj, + [ "IsZmodnZMatrixRep", "IsMatrix" ], + { a, b } -> Unpack( a ) = b ); +#TODO: Do we want this? If yes then it should be documented. +InstallMethod( \=, IsIdenticalObj, + [ "IsMatrix", "IsZmodnZMatrixRep" ], + { a, b } -> a = Unpack( b ) ); +#TODO: Do we want this? If yes then it should be documented. -#InstallMethodWithRandomSource( Randomize, -# "for a random source and a mutable zmodnz matrix", -# [ IsRandomSource, IsZmodnZMatrixRep and IsMutable ], -# function( rs, m ) -# local v; -# for v in m![ROWSPOS] do -# Randomize( rs, v ); -# od; -# return m; -# end ); +# No default +InstallMethod( \<, IsIdenticalObj, + [ "IsZmodnZMatrixRep", "IsZmodnZMatrixRep" ], + { a, b } -> LT_LIST_LIST_DEFAULT( a![ZROWSPOS], b![ZROWSPOS] ) ); -InstallMethod( TransposedMatMutable, "for a zmodnz matrix", - [ IsZmodnZMatrixRep ], - function( m ) - local i,n,v; - n := ListWithIdenticalEntries(m![RLPOS],0); - for i in [1..m![RLPOS]] do - v := Vector(List(m![ROWSPOS],v->v![ELSPOS][i]),m![EMPOS]); - n[i] := v; +# Avoid 'Unpack' +InstallMethod( IsZero, + [ "IsZmodnZMatrixRep" ], + function( M ) + local row; + for row in M![ZROWSPOS] do + if not IsZero( row ) then + return false; + fi; od; - return Objectify(TypeObj(m),[m![BDPOS],m![EMPOS],Length(m![ROWSPOS]),n]); + return true; end ); -InstallMethod( TransposedMatImmutable, "for a zmodnz matrix", - [ IsZmodnZMatrixRep ], - function( m ) - local n; - n := TransposedMatMutable(m); - MakeImmutable(n); - return n; - end ); +# Avoid element access. +InstallMethod( IsOne, + [ "IsZmodnZMatrixRep" ], + function( M ) + local n, rows, i, row; -BindGlobal( "ZMZVECMAT", function( v, m ) - local i,res,s,r; - r:=BaseDomain(v); - # do arithmetic over Z first so that we reduce only once - res:=ListWithIdenticalEntries(m![RLPOS],0); - for i in [1..Length(v![ELSPOS])] do - s := v![ELSPOS][i]; - if not IsZero(s) then - AddRowVector(res,m![ROWSPOS][i]![ELSPOS],s); - #if (i mod 100=0) and not ForAll(res,IsSmallIntRep) then - # ZNZVECREDUCE(res,Length(res),Size(r)); - #fi; + n:= M![ZCOLSPOS]; + rows:= M![ZROWSPOS]; + if Length( rows ) <> n then + return false; + fi; + for i in [ 1 .. n ] do + row:= rows[i]; + if PositionNonZero( row ) <> i or + not IsOne( row[i] ) or + PositionNonZero( row, i ) <= n then + return false; fi; od; - ZNZVECREDUCE(res,Length(res),Size(r)); - res:=Vector(r,res); - - if not IsMutable(v) and not IsMutable(m) then - MakeImmutable(res); - fi; - return res; -end ); - -InstallMethod( \*, "for a zmodnz vector and a zmodnz matrix", - IsElmsColls, [ IsZmodnZVectorRep, IsZmodnZMatrixRep ], - ZMZVECMAT); + return true; + end ); -InstallOtherMethod( \^, "for a zmodnz vector and a zmodnz matrix", - IsElmsColls, [ IsZmodnZVectorRep, IsZmodnZMatrixRep ], - ZMZVECMAT); +# no good idea for this method, +# 'SemiEchelonMatDestructive' works only for 'IsRowListMatrix' +InstallMethod( RankMat, + [ "IsZmodnZMatrixRep" ], + M -> RankMat( Unpack( M ) ) ); BindGlobal( "PLISTVECZMZMAT", function( v, m ) - local i,res,s,r; - r:=BaseDomain(m); + local r, res; + r:= BaseDomain( m ); # do arithmetic over Z first so that we reduce only once - res:=ListWithIdenticalEntries(m![RLPOS],0); - for i in [1..Length(v)] do - s := v[i]; - if not IsZero(s) then - AddRowVector(res,m![ROWSPOS][i]![ELSPOS],Int(s)); - #if (i mod 100=0) and not ForAll(res,IsSmallIntRep) then - # ZNZVECREDUCE(res,Length(res),Size(r)); - #fi; - fi; - od; - ZNZVECREDUCE(res,Length(res),Size(r)); - res:=Vector(r,res); - - if not IsMutable(v) and not IsMutable(m) then - MakeImmutable(res); - fi; - return res; -end ); + res:= List( v, Int ) * m![ZROWSPOS]; + return Vector( IsZmodnZVectorRep, r, + ZNZVECREDUCE( res, Length( res ), Size( r ) ) ); + end ); -InstallOtherMethod( \*, "for a plist vector and a zmodnz matrix", - IsElmsColls, [ IsList, IsZmodnZMatrixRep ], +InstallOtherMethod( \*, + IsElmsColls, + [ "IsList", "IsZmodnZMatrixRep" ], PLISTVECZMZMAT); +#TODO: Do we want this? If yes then it should be documented. -InstallOtherMethod( \^, "for a plist vector and a zmodnz matrix", - IsElmsColls, [ IsList, IsZmodnZMatrixRep ], +InstallOtherMethod( \^, + IsElmsColls, + [ "IsList", "IsZmodnZMatrixRep" ], PLISTVECZMZMAT); +#TODO: Do we want this? If yes then it should be documented. BindGlobal( "ZMZVECTIMESPLISTMAT", function( v, m ) local i,res,s,r; @@ -1437,30 +1412,28 @@ BindGlobal( "ZMZVECTIMESPLISTMAT", function( v, m ) return res; end ); -InstallOtherMethod( \*, "for a zmodnz vector and plist matrix", - IsElmsColls, [ IsZmodnZVectorRep, IsMatrix ], +InstallOtherMethod( \*, + IsElmsColls, + [ "IsZmodnZVectorRep", "IsMatrix" ], ZMZVECTIMESPLISTMAT); +#TODO: Do we want this? If yes then it should be documented. -InstallOtherMethod( \^, "for a zmodnz vector and plist matrix", - IsElmsColls, [ IsZmodnZVectorRep, IsMatrix ], +InstallOtherMethod( \^, + IsElmsColls, + [ "IsZmodnZVectorRep", "IsMatrix" ], ZMZVECTIMESPLISTMAT); +#TODO: Do we want this? If yes then it should be documented. -InstallMethod( CompatibleVector, "for a zmodnz matrix", - [ IsZmodnZMatrixRep ], - function( v ) - return NewZeroVector(IsZmodnZVectorRep,BaseDomain(v),NumberRows(v)); - end ); +InstallMethod( DeterminantMat, + [ "IsZmodnZMatrixRep" ], + a -> ZmodnZObj( DeterminantMat( a![ZROWSPOS] ), Size( BaseDomain( a ) ) ) ); -InstallMethod( DeterminantMat, "for a zmodnz matrix", [ IsZmodnZMatrixRep ], -function( a ) -local m; - m:=Size(BaseDomain(a)); - a:=List(a![ROWSPOS],x->x![ELSPOS]); - return ZmodnZObj(DeterminantMat(a),m); -end ); +############################################################################# +## +## Minimal/Characteristic Polynomial stuff +## -# Minimal/Characteristic Polynomial stuff ############################################################################# ## ## Variant of @@ -1535,7 +1508,7 @@ end ); InstallOtherMethod( MinimalPolynomial, "ZModnZ, spinning over field", IsElmsCollsX, - [ IsField and IsFinite, IsMatrixObj, IsPosInt ], + [ IsField and IsFinite, IsZmodnZMatrixRep, IsPosInt ], function( fld, mat, ind ) local i, n, base, vec, one, fam, mp, dim, span,op,w, piv,j; @@ -1551,7 +1524,7 @@ function( fld, mat, ind ) #keep coeffs #mp := UnivariatePolynomialByCoefficients( fam, mp,ind); while dim < n do - vec:=ZeroVector(n,mat[1]); + vec:= ZeroVector( n, mat ); for i in [1..n] do if (not IsBound(base[i])) and Random([0,1])=1 then vec[i]:=one;fi; od; @@ -1599,14 +1572,14 @@ end); InstallOtherMethod( CharacteristicPolynomialMatrixNC, "zmodnz spinning over field", IsElmsCollsX, - [ IsField, IsMatrixObj, IsPosInt ], function( fld, mat, ind) + [ IsField, IsZmodnZMatrixRep, IsPosInt ], function( fld, mat, ind) local i, n, base, imat, vec, one,cp,op,zero,fam; Info(InfoMatrix,1,"Characteristic Polynomial called on ", NrRows(mat)," x ",NrCols(mat)," matrix over ",fld); imat := ImmutableMatrix(fld,mat); n := NrRows(mat); base := []; - vec := ZeroOp(mat[1]); + vec := CompatibleVector( mat ); one := One(fld); zero := Zero(fld); fam := ElementsFamily(FamilyObj(fld)); @@ -1635,18 +1608,21 @@ local i, n, base, imat, vec, one,cp,op,zero,fam; end ); +############################################################################# +## +## Compatibility with vectors/matrices over finite fields: ## InstallOtherMethod( DegreeFFE, - [ "IsZmodnZVectorRep" ], -function(vec) - # TODO: check that modulus is a prime + [ "IsZmodnZVectorRep" ], + function(vec) +# TODO: check that modulus is a prime return 1; -end); + end ); InstallOtherMethod( DegreeFFE, - [ "IsZmodnZMatrixRep" ], -function(vec) - # TODO: check that modulus is a prime + [ "IsZmodnZMatrixRep" ], + function(vec) +# TODO: check that modulus is a prime return 1; -end); + end); diff --git a/lib/matobjplist.gi b/lib/matobjplist.gi index cafe1dd7d6..903084e36e 100644 --- a/lib/matobjplist.gi +++ b/lib/matobjplist.gi @@ -88,6 +88,8 @@ BindGlobal( "MakeIsPlistVectorRep", if check and ValueOption( "check" ) <> false then if not IsSubset( basedomain, list ) then Error( "the elements in must lie in " ); + elif not IsPlistRep( list ) then + Error( " must be in 'IsPlistRep'" ); fi; fi; @@ -177,7 +179,7 @@ BindGlobal( "MakeIsPlistMatrixRep", InstallTagBasedMethod( NewVector, IsPlistVectorRep, function( filter, basedomain, list ) - return MakeIsPlistVectorRep(basedomain, ShallowCopy(list), true); + return MakeIsPlistVectorRep(basedomain, PlainListCopy( list ), true); end ); InstallTagBasedMethod( NewZeroVector, @@ -343,6 +345,9 @@ InstallMethod( \[\], InstallMethod( \[\]\:\=, [ "IsPlistVectorRep", "IsPosInt", "IsObject" ], function( v, p, ob ) + if ValueOption( "check" ) <> false and Length( v![ELSPOS] ) < p then + Error( "

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

is out of bounds gap> STOP_TEST("ListOp.tst"); diff --git a/tst/testinstall/MatrixObj/matobjnz.tst b/tst/testinstall/MatrixObj/matobjnz.tst new file mode 100644 index 0000000000..1cdce60061 --- /dev/null +++ b/tst/testinstall/MatrixObj/matobjnz.tst @@ -0,0 +1,458 @@ +#@local R, p, z, pol, M, v, w, s, c, MM, S, T +gap> START_TEST( "matobjnz.tst" ); + +# +gap> ReadGapRoot( "tst/testinstall/MatrixObj/testmatobj.g" ); + +# vectors over a prime field +gap> R:= Integers mod 5;; +gap> TestZeroVector( IsZmodnZVectorRep, R, 0 );; +gap> TestZeroVector( IsZmodnZVectorRep, R, 3 );; +gap> Vector( IsZmodnZVectorRep, GF(5), [ 1/5 ] ); +Error, must be a list of reduced integers or of elements in +gap> Vector( IsZmodnZVectorRep, GF(25), [ Z(5) ] ); +Error, must be Integers mod for some +gap> Vector( IsZmodnZVectorRep, GF(5), [ Z(25) ] ); +Error, must be a list of reduced integers or of elements in +gap> Vector( GF(2), [ 1 ] ); +Error, cannot copy to 'IsGF2VectorRep' +gap> Vector( GF(5), [ 1 ] ); +Error, cannot copy to 'Is8BitVectorRep' +gap> Vector( GF(257), [ 1 ] ); +Error, the elements in must lie in +gap> p:= NextPrimeInt( 2^16 );; +gap> IsZmodnZVectorRep( Vector( IsZmodnZVectorRep, GF( p ), [] ) ); +true +gap> IsZmodnZVectorRep( Vector( IsZmodnZVectorRep, GF( p ), [ 1 ] ) ); +true + +# vectors over a residue class ring that is not a field +gap> R:= Integers mod 6;; +gap> TestZeroVector( IsZmodnZVectorRep, R, 0 );; +gap> TestZeroVector( IsZmodnZVectorRep, R, 3 );; +gap> Vector( IsZmodnZVectorRep, R, [ 1/2 ] ); +Error, must be a list of reduced integers or of elements in +gap> Vector( IsZmodnZVectorRep, R, [ One( Integers mod 4 ) ] ); +Error, must be a list of reduced integers or of elements in +gap> z:= NewZeroVector( IsZmodnZVectorRep, R, 3 );; +gap> Vector( [ 1 .. 10 ], z ); +Error, must be a list of reduced integers or of elements in +gap> IsZmodnZVectorRep( Vector( IsZmodnZVectorRep, R, [ 1 ] ) ); +true + +# matrices over a prime field +gap> R:= Integers mod 5;; +gap> TestZeroMatrix( IsZmodnZMatrixRep, R, 0, 0 );; +gap> TestZeroMatrix( IsZmodnZMatrixRep, R, 3, 4 );; +gap> TestIdentityMatrix( IsZmodnZMatrixRep, R, 3 );; +gap> pol:= X(R)^3 + 1;; +gap> TestCompanionMatrix( IsZmodnZMatrixRep, pol, R );; +gap> M:= Matrix( IsZmodnZMatrixRep, R, [ 1, 2, 3, 4 ], 2 );; +gap> TestElementaryTransforms( M, 3*One(R) ); +gap> TestWholeMatrixTransforms( M, 3*One(R) ); +gap> TestPositionNonZeroInRow( M ); +gap> M:= Matrix( IsZmodnZMatrixRep, GF(5), [ 1, 2, 3, 4 ] / 5, 2 ); +Error, [ +1] must be a list of reduced integers or of elements in +gap> M:= Matrix( IsZmodnZMatrixRep, GF(25), [ 1, 2, 3, 4 ] * Z(5)^0, 2 ); +Error, must be Integers mod for some +gap> M:= Matrix( IsZmodnZMatrixRep, GF(5), [ 1, 2, 3, 4 ] * Z(25), 2 ); +Error, [ +1] must be a list of reduced integers or of elements in +gap> Matrix( IsZmodnZMatrixRep, R, [ [ 1, 2 ], [ 3, 4 ] ], 3 ); +Error, the entries of must have length +gap> Matrix( IsZmodnZMatrixRep, R, [ 1 .. 4 ], 3 ); +Error, NewMatrix: Length of is not a multiple of +gap> Matrix( GF(2), [ [ 1 ] ], 1 ); +Error, cannot convert to 'IsGF2MatrixRep' +gap> Matrix( GF(5), [ [ 1 ] ] ); +Error, cannot convert to 'Is8BitMatrixRep' +gap> Matrix( GF(257), [ [ 1 ] ], 1 ); +Error, the elements in must lie in +gap> IsZmodnZMatrixRep( Matrix( IsZmodnZMatrixRep, GF( p ), [ [] ] ) ); +true +gap> IsZmodnZMatrixRep( Matrix( IsZmodnZMatrixRep, GF( p ), [ [ 1 ] ] ) ); +true + +# matrices over a residue class ring that is not a field +gap> TestZeroMatrix( IsZmodnZMatrixRep, R, 0, 0 );; +gap> TestZeroMatrix( IsZmodnZMatrixRep, R, 3, 4 );; +gap> TestIdentityMatrix( IsZmodnZMatrixRep, R, 3 );; +gap> pol:= X(R)^3 + 1;; +gap> TestCompanionMatrix( IsZmodnZMatrixRep, pol, R );; +gap> M:= Matrix( IsZmodnZMatrixRep, R, [ 1, 2, 3, 4 ], 2 );; +gap> TestElementaryTransforms( M, 3*One(R) ); +gap> TestWholeMatrixTransforms( M, 3*One(R) ); +gap> TestPositionNonZeroInRow( M ); +gap> M:= Matrix( IsZmodnZMatrixRep, R, [ 1, 2, 3, 4 ] / 2, 2 ); +Error, [ +1] must be a list of reduced integers or of elements in +gap> M:= Matrix( IsZmodnZMatrixRep, R, [ One( Integers mod 4 ) ], 1 ); +Error, [ +1] must be a list of reduced integers or of elements in +gap> M:= Matrix( IsZmodnZMatrixRep, Integers, [ 1, 2, 3, 4 ], 2 ); +Error, must be Integers mod for some +gap> Matrix( IsZmodnZMatrixRep, R, [ [ 1, 2 ], [ 3, 4 ] ], 3 ); +Error, the entries of must have length +gap> Matrix( IsZmodnZMatrixRep, R, [ 1 .. 4 ], 3 ); +Error, NewMatrix: Length of is not a multiple of + +# construct/view/print/display/string of vectors +gap> R:= Integers mod 6;; +gap> z:= NewZeroVector( IsZmodnZVectorRep, R, 3 );; +gap> v:= Vector( [ 1, 2, 3 ], z ); + +gap> Print( v, "\n" ); +NewVector(IsZmodnZVectorRep,(Integers mod 6),[ 1, 2, 3 ]) +gap> Display( v ); + +gap> String( v ); +"NewVector(IsZmodnZVectorRep,(Integers mod 6),[ 1, 2, 3 ])" +gap> v:= Vector( List( [ 1 .. 10 ], x -> x mod 6 ), z ); + +gap> Print( v, "\n" ); +NewVector(IsZmodnZVectorRep,(Integers mod 6),[ 1, 2, 3, 4, 5, 0, 1, 2, 3, 4 ]) +gap> Display( v ); + +gap> String( v ); +"NewVector(IsZmodnZVectorRep,(Integers mod 6),[ 1, 2, 3, 4, 5, 0, 1, 2, 3, 4 ]\ +)" + +# construct/view/print/display/string of matrices +gap> R:= Integers mod 6;; +gap> z:= NewZeroMatrix( IsZmodnZMatrixRep, R, 3, 4 );; +gap> M:= Matrix( [ [ 1, 2 ], [ 3, 4 ] ], z ); +<2x2-matrix over (Integers mod 6)> +gap> Print( M, "\n" ); +NewMatrix(IsZmodnZMatrixRep,(Integers mod 6),2,[ [ 1, 2 ], [ 3, 4 ] ]) +gap> Display( M ); +<2x2-matrix over (Integers mod 6): +[ [ 1, 2 ], + [ 3, 4 ] ] +]> +gap> String( M ); +"NewMatrix(IsZmodnZMatrixRep,(Integers mod 6),2,[ [ 1, 2 ], [ 3, 4 ] ])" +gap> Matrix( [ [ 7 ] ], z ); +Error, [ +1] must be a list of reduced integers or of elements in +gap> M:= Matrix( IsZmodnZMatrixRep, R, [ 1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4 ], +> 2 ); +<6x2-matrix over (Integers mod 6)> +gap> Print( M, "\n" ); +NewMatrix(IsZmodnZMatrixRep,(Integers mod 6),2, +[ [ 1, 2 ], [ 3, 4 ], [ 1, 2 ], [ 3, 4 ], [ 1, 2 ], [ 3, 4 ] ]) +gap> Display( M ); +<6x2-matrix over (Integers mod 6): +[ [ 1, 2 ], + [ 3, 4 ], + [ 1, 2 ], + [ 3, 4 ], + [ 1, 2 ], + [ 3, 4 ] ] +]> +gap> String( M ); +"NewMatrix(IsZmodnZMatrixRep,(Integers mod 6),2,[ [ 1, 2 ], [ 3, 4 ], [ 1, 2 ]\ +, [ 3, 4 ], [ 1, 2 ], [ 3, 4 ] ])" + +# vectors: access, arithmetics +gap> R:= Integers mod 6;; +gap> v:= Vector( IsZmodnZVectorRep, R, [ 1, 2, 3 ] ); + +gap> v[1]; +ZmodnZObj( 1, 6 ) +gap> v[1]:= 0;; +gap> v[1]; +ZmodnZObj( 0, 6 ) +gap> v[1]:= One( R );; +gap> v[1]:= Z(2); +Error, must be an integer or lie in the base domain of +gap> v[4]:= 0; +Error,

is out of bounds +gap> Unpack( v ); +[ ZmodnZObj( 1, 6 ), ZmodnZObj( 2, 6 ), ZmodnZObj( 3, 6 ) ] +gap> v{ [ 2, 3 ] }; + +gap> w:= ShallowCopy( v ); + +gap> w = v; +true +gap> s:= v + w;; Print( s, "\n" ); +NewVector(IsZmodnZVectorRep,(Integers mod 6),[ 2, 4, 0 ]) +gap> IsMutable( s ); +true +gap> MakeImmutable( v ); + +gap> Print( v + v, "\n" ); +NewVector(IsZmodnZVectorRep,(Integers mod 6),[ 2, 4, 0 ]) +gap> v + ZeroVector( IsZmodnZVectorRep, Integers mod 4, 3 ); +Error, and are not compatible +gap> s:= v - w;; Print( s, "\n" ); +NewVector(IsZmodnZVectorRep,(Integers mod 6),[ 0, 0, 0 ]) +gap> IsMutable( s ); +true +gap> v - v; + +gap> v - ZeroVector( IsZmodnZVectorRep, Integers mod 4, 3 ); +Error, and are not compatible +gap> Print( AdditiveInverseMutable( v ), "\n" );; +NewVector(IsZmodnZVectorRep,(Integers mod 6),[ 5, 4, 3 ]) +gap> z:= ZeroMutable( v ); + +gap> z = ZeroVector( 3, v ); +true +gap> Print( v * 2, "\n" ); +NewVector(IsZmodnZVectorRep,(Integers mod 6),[ 2, 4, 0 ]) +gap> c:= 2 * One( R );; +gap> Print( v * c, "\n" ); +NewVector(IsZmodnZVectorRep,(Integers mod 6),[ 2, 4, 0 ]) +gap> Print( 2 * v, "\n" ); +NewVector(IsZmodnZVectorRep,(Integers mod 6),[ 2, 4, 0 ]) +gap> Print( c * v, "\n" ); +NewVector(IsZmodnZVectorRep,(Integers mod 6),[ 2, 4, 0 ]) +gap> Print( v / 5, "\n" ); +NewVector(IsZmodnZVectorRep,(Integers mod 6),[ 5, 4, 3 ]) +gap> v / 3; +Error, ModRat: for / mod , /gcd(,) and must be coprime +gap> PositionNonZero( v ); +1 +gap> PositionNonZero( v, 1 ); +2 +gap> PositionLastNonZero( v ); +3 +gap> List( v ); +[ ZmodnZObj( 1, 6 ), ZmodnZObj( 2, 6 ), ZmodnZObj( 3, 6 ) ] +gap> List( v, Zero ); +[ ZmodnZObj( 0, 6 ), ZmodnZObj( 0, 6 ), ZmodnZObj( 0, 6 ) ] +gap> v < 2 * v; +true +gap> v:= ShallowCopy( v );; +gap> AddRowVector( v, ZeroVector( IsZmodnZVectorRep, Integers mod 4, 3 ) ); +Error, and are not compatible +gap> AddRowVector( v, v ); +gap> Print( v, "\n" ); +NewVector(IsZmodnZVectorRep,(Integers mod 6),[ 2, 4, 0 ]) +gap> v:= Vector( IsZmodnZVectorRep, R, [ 1, 2, 3 ] );; +gap> AddRowVector( v, v, 2 ); +gap> Print( v, "\n" ); +NewVector(IsZmodnZVectorRep,(Integers mod 6),[ 3, 0, 3 ]) +gap> v:= Vector( IsZmodnZVectorRep, R, [ 0 .. 5 ] );; Print( v, "\n" ); +NewVector(IsZmodnZVectorRep,(Integers mod 6),[ 0, 1, 2, 3, 4, 5 ]) +gap> AddRowVector( v, v, 2, 3, 4 ); +gap> Print( v, "\n" ); +NewVector(IsZmodnZVectorRep,(Integers mod 6),[ 0, 1, 0, 3, 4, 5 ]) +gap> v:= Vector( IsZmodnZVectorRep, R, [ 1, 2, 3 ] );; +gap> MultVector( v, 2 ); +gap> Print( v, "\n" ); +NewVector(IsZmodnZVectorRep,(Integers mod 6),[ 2, 4, 0 ]) +gap> v:= Vector( IsZmodnZVectorRep, R, [ 0 .. 5 ] );; +gap> MultVector( v, 2, 3, 4 ); +gap> Print( v, "\n" ); +NewVector(IsZmodnZVectorRep,(Integers mod 6),[ 0, 1, 4, 0, 4, 5 ]) +gap> CopySubVector( v, v, [ 1 .. 3 ], [ 4 .. 6 ] ); +gap> Print( v, "\n" ); +NewVector(IsZmodnZVectorRep,(Integers mod 6),[ 0, 1, 4, 0, 1, 4 ]) + +# matrices: access, arithmetics +gap> R:= Integers mod 6;; +gap> M:= Matrix( IsZmodnZMatrixRep, R, [ 1, 2, 3, 4 ], 2 );; +gap> M[1]; +Error, row access unsupported; use M[i,j] or RowsOfMatrix(M) +gap> M[1,1]; +ZmodnZObj( 1, 6 ) +gap> M[1,3]; +Error, List Element: [3] must have an assigned value +gap> M[3,1]; +Error, List Element: [3] must have an assigned value +gap> M[1,1]:= 0;; +gap> M[1,1]; +ZmodnZObj( 0, 6 ) +gap> M[1,1]:= One( R );; +gap> M[1,1]; +ZmodnZObj( 1, 6 ) +gap> M[1,3]:= 0;; +Error, is out of bounds +gap> M[3,1]:= 0;; +Error, is out of bounds +gap> M[1,1]:= Z(2);; +Error, must be an integer or lie in the base domain of +gap> RowsOfMatrix( M ); +[ , + ] +gap> Unpack( M ); +[ [ ZmodnZObj( 1, 6 ), ZmodnZObj( 2, 6 ) ], + [ ZmodnZObj( 3, 6 ), ZmodnZObj( 4, 6 ) ] ] +gap> MM:= ShallowCopy( M );; +gap> MM = M; +true +gap> MM:= MutableCopyMatrix( Immutable( M ) );; +gap> IsMutable( MM ) and MM = M; +true +gap> Print( ExtractSubMatrix( M, [ 1 ], [ 2 ] ), "\n" ); +NewMatrix(IsZmodnZMatrixRep,(Integers mod 6),1,[ [ 2 ] ]) +gap> CopySubMatrix( MM, M, [ 1 ], [ 2 ], [ 1 ], [ 2 ] ); +gap> Print( M, "\n" ); +NewMatrix(IsZmodnZMatrixRep,(Integers mod 6),2,[ [ 1, 2 ], [ 3, 1 ] ]) +gap> Print( TransposedMatMutable( M ), "\n" ); +NewMatrix(IsZmodnZMatrixRep,(Integers mod 6),2,[ [ 1, 3 ], [ 2, 1 ] ]) +gap> S:= M + MM;; Print( S, "\n" ); +NewMatrix(IsZmodnZMatrixRep,(Integers mod 6),2,[ [ 2, 4 ], [ 0, 5 ] ]) +gap> IsMutable( S ); +true +gap> MakeImmutable( M ); + +gap> Print( M + M, "\n" ); +NewMatrix(IsZmodnZMatrixRep,(Integers mod 6),2,[ [ 2, 4 ], [ 0, 2 ] ]) +gap> M + ZeroMatrix( IsZmodnZMatrixRep, R, 3, 3 ); +Error, and are not compatible +gap> Print( M - M, "\n" ); +NewMatrix(IsZmodnZMatrixRep,(Integers mod 6),2,[ [ 0, 0 ], [ 0, 0 ] ]) +gap> M - ZeroMatrix( IsZmodnZMatrixRep, R, 3, 3 ); +Error, and are not compatible +gap> Print( AdditiveInverseMutable( M ), "\n" ); +NewMatrix(IsZmodnZMatrixRep,(Integers mod 6),2,[ [ 5, 4 ], [ 3, 5 ] ]) +gap> z:= ZeroMutable( M );; +gap> z = ZeroMatrix( IsZmodnZMatrixRep, R, 2, 2 ); +true +gap> z < M; +true +gap> Print( InverseMutable( M ), "\n" ); +NewMatrix(IsZmodnZMatrixRep,(Integers mod 6),2,[ [ 1, 4 ], [ 3, 1 ] ]) +gap> InverseMutable( ZeroMatrix( R, 2, 2 ) ); +fail +gap> Print( M * M, "\n" ); +NewMatrix(IsZmodnZMatrixRep,(Integers mod 6),2,[ [ 1, 4 ], [ 0, 1 ] ]) +gap> M * ZeroMatrix( IsZmodnZMatrixRep, R, 1, 1 ); +Error, \*: Matrices do not fit together +gap> M * ZeroMatrix( IsZmodnZMatrixRep, GF(2), 2, 2 ); +Error, \*: Matrices not over same base domain +gap> Print( M * CompatibleVector( M ), "\n" ); +NewVector(IsZmodnZVectorRep,(Integers mod 6),[ 0, 0 ]) +gap> Print( CompatibleVector( M ) * M, "\n" ); +NewVector(IsZmodnZVectorRep,(Integers mod 6),[ 0, 0 ]) +gap> Print( CompatibleVector( M ) ^ M, "\n" ); +NewVector(IsZmodnZVectorRep,(Integers mod 6),[ 0, 0 ]) +gap> M * ZeroVector( 3, M ); +Error, and are not compatible +gap> ZeroVector( 3, M ) * M; +Error, and are not compatible +gap> M:= Matrix( IsZmodnZMatrixRep, R, [[], []], 0 ); +<2x0-matrix over (Integers mod 6)> +gap> v:= CompatibleVector( M );; +gap> v * M; + +gap> M:= Matrix( IsZmodnZMatrixRep, R, [], 3 ); +<0x3-matrix over (Integers mod 6)> +gap> v:= CompatibleVector( M ); + +gap> Print( v * M, "\n" ); +NewVector(IsZmodnZVectorRep,(Integers mod 6),[ 0, 0, 0 ]) +gap> M:= Matrix( IsZmodnZMatrixRep, R, [ 1, 2, 3, 4 ], 2 );; +gap> MultMatrixRowLeft( M, 1, 4 ); +gap> Print( M, "\n" ); +NewMatrix(IsZmodnZMatrixRep,(Integers mod 6),2,[ [ 4, 2 ], [ 3, 4 ] ]) +gap> MultMatrixRowRight( M, 2, 4 ); +gap> Print( M, "\n" ); +NewMatrix(IsZmodnZMatrixRep,(Integers mod 6),2,[ [ 4, 2 ], [ 0, 4 ] ]) +gap> PositionNonZeroInRow( M, 1 ); +1 +gap> PositionNonZeroInRow( M, 1, 1 ); +2 +gap> PositionNonZeroInRow( ZeroMatrix( R, 2, 3 ), 1 ); +4 +gap> SwapMatrixRows( M, 1, 2 ); +gap> Print( M, "\n" ); +NewMatrix(IsZmodnZMatrixRep,(Integers mod 6),2,[ [ 0, 4 ], [ 4, 2 ] ]) +gap> SwapMatrixColumns( M, 1, 2 ); +gap> Print( M, "\n" ); +NewMatrix(IsZmodnZMatrixRep,(Integers mod 6),2,[ [ 4, 0 ], [ 2, 4 ] ]) +gap> IsZero( M ); +false +gap> IsZero( 6 * M ); +true +gap> IsOne( M ); +false +gap> IsOne( M^0 ); +true +gap> RankMat( M ); +fail +gap> RankMat( IdentityMatrix( 3, M ) ); +3 +gap> R:= Integers mod p;; +gap> One( R ); +ZmodpZObj( 1, 65537 ) +gap> M:= Matrix( IsZmodnZMatrixRep, R, [ 1, 2, 3, 4 ], 2 );; +gap> DeterminantMat( M ); +ZmodpZObj( 65535, 65537 ) + +# miscellaneous +gap> MinimalPolynomial( R, M, 1 ) = MinimalPolynomial( R, Unpack( M ), 1 ); +true +gap> CharacteristicPolynomialMatrixNC( R, M, 1 ) = +> CharacteristicPolynomialMatrixNC( R, Unpack( M ), 1 ); +true +gap> R:= Integers mod 6;; +gap> v:= Vector( IsZmodnZVectorRep, R, [ 1, 2, 3 ] );; +gap> ProductCoeffs( v, v ) = ProductCoeffs( Unpack( v ), Unpack( v ) ); +true + +# an issue with the type in earlier code +gap> R:= Integers mod 6;; +gap> z:= NewZeroVector( IsZmodnZVectorRep, R, 3 );; +gap> MakeImmutable( z );; +gap> IsZero(z); +true +gap> HasIsZero(z); +true +gap> v:= Vector( [ 1, 2, 3 ], z );; +gap> IsZero( v ); +false + +# default 'Vector' methods +gap> z:= NewZeroVector( IsZmodnZVectorRep, GF(2), 3 );; +gap> w:= [ 1, 0 ] * Z(2);; +gap> ConvertToVectorRep( w );; +gap> Print( Vector( w, z ), "\n" ); +NewVector(IsZmodnZVectorRep,GF(2),[ 1, 0 ]) +gap> z:= NewZeroVector( IsZmodnZVectorRep, GF(3), 3 );; +gap> w:= [ 1, 0 ] * Z(3)^0;; +gap> ConvertToVectorRep( w );; +gap> Print( Vector( w, z ), "\n" ); +NewVector(IsZmodnZVectorRep,GF(3),[ 1, 0 ]) +gap> w:= [ 1, 0 ];; +gap> Print( Vector( w, z ), "\n" ); +NewVector(IsZmodnZVectorRep,GF(3),[ 1, 0 ]) +gap> Print( Vector( w * Z(3)^0, z ), "\n" ); +NewVector(IsZmodnZVectorRep,GF(3),[ 1, 0 ]) + +# +gap> z:= NewZeroVector( IsZmodnZVectorRep, GF(2), 3 );; +gap> MakeImmutable( z );; +gap> IsMutable( z![ELSPOS] ); +false + +# matrix multiplication +gap> M:= Matrix( IsZmodnZMatrixRep, Integers mod 6, [ [], [] ], 0 ); +<2x0-matrix over (Integers mod 6)> +gap> T:= TransposedMat( M ); + +gap> Print( M * T, "\n" ); +NewMatrix(IsZmodnZMatrixRep,(Integers mod 6),2,[ [ 0, 0 ], [ 0, 0 ] ]) +gap> T * M; +<0x0-matrix over (Integers mod 6)> + +# +gap> M:= Matrix( IsZmodnZMatrixRep, Integers mod 6, [ 1, 2 ], 2 );; +gap> OneMutable( M ); +Error, must be square (not 1 by 2) + +# +gap> STOP_TEST( "matobjnz.tst" ); diff --git a/tst/testinstall/MatrixObj/matobjplist.tst b/tst/testinstall/MatrixObj/matobjplist.tst index f1099217d9..584ec3da07 100644 --- a/tst/testinstall/MatrixObj/matobjplist.tst +++ b/tst/testinstall/MatrixObj/matobjplist.tst @@ -3,6 +3,8 @@ gap> START_TEST( "matobjplist.tst" ); # gap> e:= MakeIsPlistVectorRep( Integers, [], true );; +gap> MakeIsPlistVectorRep( Integers, [ 1 .. 4 ], true );; +Error, must be in 'IsPlistRep' gap> v:= MakeIsPlistVectorRep( Integers, [ 1 ], true );; gap> MakeIsPlistVectorRep( Integers, [ 1/2 ], true );; Error, the elements in must lie in diff --git a/tst/testinstall/MatrixObj/testmatobj.g b/tst/testinstall/MatrixObj/testmatobj.g index bca02e4c1c..1f5a21ebc2 100644 --- a/tst/testinstall/MatrixObj/testmatobj.g +++ b/tst/testinstall/MatrixObj/testmatobj.g @@ -257,8 +257,9 @@ end; TestPositionNonZeroInRow := function(mat) local ncols; - # Make a matrix with specific patter of the same kind as mat - mat := Matrix([ [ 0, 1, 0, 1 ], [ 0, 0, 0, 0 ], [ 0, 0, 1, 0 ] ], mat); + # Make a matrix with specific pattern of the same kind as mat + mat := Matrix([ [ 0, 1, 0, 1 ], [ 0, 0, 0, 0 ], [ 0, 0, 1, 0 ] ] + * One( BaseDomain( mat ) ), mat); ncols := NrCols(mat); if PositionNonZeroInRow(mat, 1) <> 2 then