diff --git a/benchmark/matobj/bench-matelm-access.g b/benchmark/matobj/bench-matelm-access.g
index 889ba71801..f58d365830 100644
--- a/benchmark/matobj/bench-matelm-access.g
+++ b/benchmark/matobj/bench-matelm-access.g
@@ -136,17 +136,23 @@ RunMatTest := function(desc, m)
TestWritingMatrix(m);
end;
-m:=IdentityMat(10);;
-RunMatTest("integer matrix", m);
+m:=IdentityMat(10,GF(257));; # plain list of plain lists
+RunMatTest("GF(257) plist-of-plist matrix", m);
-m:=IdentityMat(10,GF(2));;
+m:=IdentityMatrix(GF(257), 10); # IsPlistMatrixRep
+RunMatTest("GF(257) IsPlistMatrixRep", m);
+
+m:=IdentityMatrix(GF(257), 10); # IsGenericMatrixRep
+RunMatTest("GF(257) IsGenericMatrixRep", m);
+
+m:=IdentityMat(10,GF(2));; # plain list of IsGF2VectorRep
RunMatTest("GF(2) rowlist", m);
-m:=IdentityMat(10,GF(2));; ConvertToMatrixRep(m);;
+m:=IdentityMatrix(GF(2), 10); # IsGF2MatrixRep
RunMatTest("GF(2) compressed matrix", m);
-m:=IdentityMat(10,GF(7));;
+m:=IdentityMat(10,GF(7));; # plain list of Is8BitVectorRep
RunMatTest("GF(7) rowlist", m);
-m:=IdentityMat(10,GF(7));; ConvertToMatrixRep(m);;
+m:=IdentityMatrix(GF(7), 10); # Is8BitMatrixRep
RunMatTest("GF(7) compressed matrix", m);
diff --git a/benchmark/matobj/bench-matobj-creation.g b/benchmark/matobj/bench-matobj-creation.g
index d74e5f040e..fdf568d716 100644
--- a/benchmark/matobj/bench-matobj-creation.g
+++ b/benchmark/matobj/bench-matobj-creation.g
@@ -91,18 +91,23 @@ RunMatTest := function(desc, ring)
TestCreatingMatrix(ring);
end;
-RunMatTest("GF(2)", GF(2));
-RunMatTest("Rationals", Rationals);
-
RunMatObjTest := function(desc, filter, ring)
Print("\n");
PrintBoxed(Concatenation("Testing ", desc));
TestCreatingMatrixObj(filter, ring);
end;
-RunMatObjTest("GF(2) IsPlistMatrixRep", IsPlistMatrixRep, GF(2));
+RunMatTest("GF(257)", GF(257));
+RunMatObjTest("GF(257) IsPlistMatrixRep", IsPlistMatrixRep, GF(257));
+RunMatObjTest("GF(257) IsGenericMatrixRep", IsGenericMatrixRep, GF(257));
+
+RunMatTest("Integers", Integers);
RunMatObjTest("integer IsPlistMatrixRep", IsPlistMatrixRep, Integers);
+RunMatObjTest("integer IsGenericMatrixRep", IsGenericMatrixRep, Integers);
+
+RunMatTest("Rationals", Rationals);
RunMatObjTest("rational IsPlistMatrixRep", IsPlistMatrixRep, Rationals);
+RunMatObjTest("rational IsGenericMatrixRep", IsGenericMatrixRep, Rationals);
# TODO: other reps
# TODO: other compare with creating plist-of-plist
diff --git a/doc/ref/makedocreldata.g b/doc/ref/makedocreldata.g
index f2f1697bed..7422aa85b4 100644
--- a/doc/ref/makedocreldata.g
+++ b/doc/ref/makedocreldata.g
@@ -119,6 +119,7 @@ GAPInfo.ManualDataRef:= rec(
"../../lib/matobj2.gd",
"../../lib/matobjnz.gd",
"../../lib/matobjplist.gd",
+ #"../../lib/matobjgeneric.gd", # TODO: enable this if we decide to keep IsGenericMatrixRep
"../../lib/matrix.gd",
"../../lib/meataxe.gi",
"../../lib/memory.gd",
diff --git a/doc/ref/matobj.xml b/doc/ref/matobj.xml
index 8ed8908e47..4daef4eab5 100644
--- a/doc/ref/matobj.xml
+++ b/doc/ref/matobj.xml
@@ -374,6 +374,7 @@ described in this chapter is supported.
<#Include Label="IsGF2MatrixRep">
<#Include Label="Is8BitMatrixRep">
<#Include Label="IsPlistMatrixRep">
+
<#Include Label="IsZmodnZMatrixRep">
diff --git a/lib/matobjgeneric.gd b/lib/matobjgeneric.gd
new file mode 100644
index 0000000000..261f5878ca
--- /dev/null
+++ b/lib/matobjgeneric.gd
@@ -0,0 +1,46 @@
+#############################################################################
+##
+## This file is part of GAP, a system for computational discrete algebra.
+##
+## SPDX-License-Identifier: GPL-2.0-or-later
+##
+## Copyright of GAP belongs to its developers, whose names are too numerous
+## to list here. Please refer to the COPYRIGHT file for details.
+##
+
+############################################################################
+#
+# Dense matrix objects backed by plain lists of plain row lists.
+#
+
+#############################################################################
+##
+## <#GAPDoc Label="IsGenericMatrixRep">
+##
+##
+##
+##
+## An object obj in describes
+## a matrix object (see ) whose entries are stored
+## as a dense plain list of dense plain row lists.
+##
+## This representation is optimized for efficient entry access via
+## M[i,j]. Unlike , it is not a row
+## list matrix, so direct row access via M[i] is not supported.
+##
+##
+## <#/GAPDoc>
+##
+DeclareRepresentation( "IsGenericMatrixRep",
+ IsMatrixObj and IsPositionalObjectRep
+ and IsCopyable
+ and IsNoImmediateMethodsObject
+ and HasNumberRows and HasNumberColumns
+ and HasBaseDomain and HasOneOfBaseDomain and HasZeroOfBaseDomain,
+ [] );
+
+
+# Internal positions for IsGenericMatrixRep:
+BindConstant( "FBDPOS", 1 ); # BaseDomain
+BindConstant( "FCOLSPOS", 2 ); # NumberColumns
+BindConstant( "FROWSPOS", 3 ); # "rows" as a plist-of-plists
diff --git a/lib/matobjgeneric.gi b/lib/matobjgeneric.gi
new file mode 100644
index 0000000000..b73381bceb
--- /dev/null
+++ b/lib/matobjgeneric.gi
@@ -0,0 +1,476 @@
+#############################################################################
+##
+## This file is part of GAP, a system for computational discrete algebra.
+##
+## SPDX-License-Identifier: GPL-2.0-or-later
+##
+## Copyright of GAP belongs to its developers, whose names are too numerous
+## to list here. Please refer to the COPYRIGHT file for details.
+##
+
+############################################################################
+#
+# Dense matrix objects backed by plain lists of plain row lists.
+#
+
+BindGlobal( "MakeIsGenericMatrixRep",
+ function( basedomain, ncols, list, check )
+ local efam, fam, filter, typ, row;
+ efam := ElementsFamily( FamilyObj( basedomain ) );
+ fam := CollectionsFamily( FamilyObj( basedomain ) );
+
+ # Currently there is no special handling depending on 'basedomain',
+ # the types are always cached in 'fam'.
+ if not IsBound( fam!.GenericMatrixRepTypes ) then
+ # initialize type cache
+ # TODO: make this thread safe for HPC-GAP
+ filter := IsGenericMatrixRep;
+ if CanEasilyCompareElementsFamily( efam ) then
+ filter := filter and CanEasilyCompareElements;
+ fi;
+ fam!.GenericMatrixRepTypes := [
+ NewType( fam, filter ),
+ NewType( fam, filter and IsMutable ),
+ ];
+ fi;
+ if IsMutable( list ) then
+ typ := fam!.GenericMatrixRepTypes[2];
+ else
+ typ := fam!.GenericMatrixRepTypes[1];
+ fi;
+
+ if check and ValueOption( "check" ) <> false then
+ Assert( 0, IsPlistRep( list ) );
+ for row in list do
+ if not IsPlistRep( row ) then
+ Error( "the entries of must be plain lists" );
+ elif Length( row ) <> ncols then
+ Error( "the entries of must have length " );
+ elif not IsSubset( basedomain, row ) then
+ Error( "the elements in must lie in " );
+ fi;
+ od;
+ fi;
+
+ return Objectify( typ, [ basedomain, ncols, list ] );
+ end );
+
+
+InstallTagBasedMethod( NewMatrix,
+ IsGenericMatrixRep,
+ function( filter, basedomain, ncols, list )
+ local nd, rows, i, row;
+
+ if Length( list ) > 0 and not IsVectorObj( list[1] ) then
+ nd := NestingDepthA( list );
+ if nd < 2 or nd mod 2 = 1 then
+ if Length( list ) mod ncols <> 0 then
+ Error( "NewMatrix: Length of is not a multiple of " );
+ fi;
+ list := List( [ 0, ncols .. Length( list ) - ncols ],
+ i -> list{ [ i + 1 .. i + ncols ] } );
+ fi;
+ fi;
+
+ rows := EmptyPlist( Length( list ) );
+ for i in [ 1 .. Length( list ) ] do
+ row := list[i];
+ if IsVectorObj( row ) then
+ rows[i] := Unpack( row );
+ else
+ rows[i] := PlainListCopy( row );
+ fi;
+ od;
+ if not IsMutable( list ) then
+ MakeImmutable( rows );
+ fi;
+ return MakeIsGenericMatrixRep( basedomain, ncols, rows, true );
+ end );
+
+
+InstallTagBasedMethod( NewZeroMatrix,
+ IsGenericMatrixRep,
+ function( filter, basedomain, rows, cols )
+ local list, row, i, z;
+ list := EmptyPlist( rows );
+ z := Zero( basedomain );
+ for i in [ 1 .. rows ] do
+ row := ListWithIdenticalEntries( cols, z );
+ list[i] := row;
+ od;
+ return MakeIsGenericMatrixRep( basedomain, cols, list, false );
+ end );
+
+
+InstallMethod( ConstructingFilter,
+ [ "IsGenericMatrixRep" ],
+ M -> IsGenericMatrixRep );
+
+InstallMethod( CompatibleVectorFilter,
+ [ "IsGenericMatrixRep" ],
+ M -> IsPlistVectorRep );
+
+
+InstallMethod( BaseDomain,
+ [ "IsGenericMatrixRep" ],
+ M -> M![FBDPOS] );
+
+InstallMethod( NumberRows,
+ [ "IsGenericMatrixRep" ],
+ M -> Length( M![FROWSPOS] ) );
+
+InstallMethod( NumberColumns,
+ [ "IsGenericMatrixRep" ],
+ M -> M![FCOLSPOS] );
+
+InstallMethod( \[\],
+ [ "IsGenericMatrixRep", "IsPosInt" ],
+ function( M, pos )
+ ErrorNoReturn( "row access unsupported; use M[i,j] or RowsOfMatrix(M)" );
+ end );
+
+InstallMethod( MatElm,
+ [ "IsGenericMatrixRep", "IsPosInt", "IsPosInt" ],
+ { M, row, col } -> M![FROWSPOS][row,col] );
+
+InstallMethod( SetMatElm,
+ [ "IsGenericMatrixRep and IsMutable", "IsPosInt", "IsPosInt", "IsObject" ],
+ function( M, row, col, val )
+ if ValueOption( "check" ) <> false then
+ if not val in BaseDomain( M ) then
+ Error( " must lie in the base domain of " );
+ elif not row in [1..NrRows(M)] then
+ Error( " is out of bounds" );
+ elif not col in [1..NrCols(M)] then
+ Error( " is out of bounds" );
+ fi;
+ fi;
+ M![FROWSPOS][row,col] := val;
+ end );
+
+
+InstallMethod( Unpack,
+ [ "IsGenericMatrixRep" ],
+ M -> List( M![FROWSPOS], ShallowCopy ) );
+
+InstallMethod( ShallowCopy,
+ [ "IsGenericMatrixRep" ],
+ M -> MakeIsGenericMatrixRep( BaseDomain(M), NrCols(M),
+ List( M![FROWSPOS], ShallowCopy ), false ) );
+
+InstallMethod( MutableCopyMatrix,
+ [ "IsGenericMatrixRep" ],
+ M -> MakeIsGenericMatrixRep( BaseDomain(M), NrCols(M),
+ List( M![FROWSPOS], ShallowCopy ), false ) );
+
+InstallMethod( ExtractSubMatrix,
+ [ "IsGenericMatrixRep", "IsList", "IsList" ],
+ function( M, rowspos, colspos )
+ local list;
+ list := M![FROWSPOS]{ rowspos }{ colspos };
+ return MakeIsGenericMatrixRep( BaseDomain(M), Length( colspos ), list, false );
+ end );
+
+InstallMethod( CopySubMatrix,
+ [ "IsGenericMatrixRep", "IsGenericMatrixRep and IsMutable",
+ "IsList", "IsList", "IsList", "IsList" ],
+ function( M, N, srcrows, dstrows, srccols, dstcols )
+ if ValueOption( "check" ) <> false and
+ not IsIdenticalObj( BaseDomain(M), BaseDomain(N) ) then
+ Error( " and are not compatible" );
+ fi;
+ N![FROWSPOS]{dstrows}{dstcols} := M![FROWSPOS]{srcrows}{srccols};
+ end );
+
+InstallMethod( TransposedMatMutable,
+ [ "IsGenericMatrixRep" ],
+ function( M )
+ local list;
+ list := TransposedMatMutable(M![FROWSPOS]);
+ return MakeIsGenericMatrixRep( BaseDomain(M), NrRows(M), list, false );
+ end );
+
+InstallMethod( \+,
+ [ "IsGenericMatrixRep", "IsGenericMatrixRep" ],
+ function( a, b )
+ if ValueOption( "check" ) <> false and
+ ( not IsIdenticalObj( BaseDomain( a ), BaseDomain( b ) ) or
+ NrRows( a ) <> NrRows( b ) or
+ NrCols( a ) <> NrCols( b ) ) then
+ Error( " and are not compatible" );
+ fi;
+ return MakeIsGenericMatrixRep( BaseDomain( a ), NrCols( a ),
+ a![FROWSPOS] + b![FROWSPOS], false );
+ end );
+
+InstallMethod( \-,
+ [ "IsGenericMatrixRep", "IsGenericMatrixRep" ],
+ function( a, b )
+ if ValueOption( "check" ) <> false and
+ ( not IsIdenticalObj( BaseDomain( a ), BaseDomain( b ) ) or
+ NrRows( a ) <> NrRows( b ) or
+ NrCols( a ) <> NrCols( b ) ) then
+ Error( " and are not compatible" );
+ fi;
+ return MakeIsGenericMatrixRep( BaseDomain( a ), NrCols( a ),
+ a![FROWSPOS] - b![FROWSPOS], false );
+ end );
+
+InstallMethod( AdditiveInverseMutable,
+ [ "IsGenericMatrixRep" ],
+ M -> MakeIsGenericMatrixRep( BaseDomain( M ), NrCols( M ),
+ AdditiveInverseMutable( M![FROWSPOS] ), false ) );
+
+InstallMethod( ZeroMutable,
+ [ "IsGenericMatrixRep" ],
+ function( M )
+ local z;
+ z := MakeIsGenericMatrixRep( BaseDomain( M ), NrCols( M ),
+ ZeroMutable( M![FROWSPOS] ), false );
+ SetIsZero( z, true );
+ return z;
+ end );
+
+InstallMethod( InverseMutable,
+ [ "IsGenericMatrixRep" ],
+ function( M )
+ local bd, rows;
+
+ bd := BaseDomain( M );
+ if NrRows( M ) <> NrCols( M ) then
+ ErrorNoReturn( "InverseMutable: matrix must be square" );
+ elif NrRows( M ) = 0 then
+ rows := [];
+ elif IsFinite( bd ) and IsField( bd ) then
+ rows := INV_MAT_DEFAULT_MUTABLE( M![FROWSPOS] );
+ else
+ rows := INV_MATRIX_MUTABLE( M![FROWSPOS] );
+ fi;
+ return MakeIsGenericMatrixRep( bd, NrCols( M ), rows, false );
+ end );
+
+InstallMethod( \*,
+ [ "IsGenericMatrixRep", "IsGenericMatrixRep" ],
+ function( a, b )
+ local rowsA, colsA, rowsB, colsB, bd, list, i;
+
+ 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, BaseDomain( b ) ) then
+ ErrorNoReturn( "\\*: Matrices not over same base domain" );
+ fi;
+ fi;
+
+ if rowsA = 0 or colsB = 0 then
+ list := [];
+ elif colsA = 0 then # colsA = rowsB
+ list := EmptyPlist( rowsA );
+ for i in [ 1 .. rowsA ] do
+ list[i] := ListWithIdenticalEntries( colsB, Zero( bd ) );
+ od;
+ else
+ list := a![FROWSPOS] * b![FROWSPOS];
+ fi;
+ return MakeIsGenericMatrixRep( bd, colsB, list, false );
+ end );
+
+InstallOtherMethod( \*,
+ [ "IsGenericMatrixRep", "IsRowVectorOrVectorObj" ],
+ {} -> RankFilter(IsPlistVectorRep), # rank above method for [IsScalar, IsPlistVectorRep]
+ function( M, v )
+ local rows, cols, bd, res;
+
+ rows := NumberRows( M );
+ cols := NumberColumns( M );
+ bd := BaseDomain( M );
+
+ if ValueOption( "check" ) <> false then
+ if cols <> Length( v ) then
+ Error( " and are not compatible" );
+ elif not IsIdenticalObj( bd, BaseDomain( v ) ) then
+ Error( " and are not compatible" );
+ fi;
+ fi;
+
+ # special case for empty matrices
+ if rows = 0 or cols = 0 then
+ return ZeroVector( rows, v );
+ fi;
+
+ # "unpack" cheaply and then delegate to kernel implementation
+ if IsPlistVectorRep(v) then
+ res := v![ELSPOS];
+ elif IsList(v) then
+ res := v;
+ else
+ res := Unpack(v);
+ fi;
+ res := M![FROWSPOS] * res;
+ return Vector( res, v );
+ end );
+
+InstallOtherMethod( \*,
+ [ "IsRowVectorOrVectorObj", "IsGenericMatrixRep" ],
+ {} -> RankFilter(IsPlistVectorRep), # rank above method for [IsPlistVectorRep, IsScalar]
+ function( v, M )
+ local rows, cols, bd, res;
+
+ rows := NumberRows( M );
+ cols := NumberColumns( M );
+ bd := BaseDomain( M );
+
+ if ValueOption( "check" ) <> false then
+ if Length( v ) <> rows then
+ Error( " and are not compatible" );
+ elif not IsIdenticalObj( BaseDomain( v ), bd ) then
+ Error( " and are not compatible" );
+ fi;
+ fi;
+
+ # special case for empty matrices
+ if rows = 0 or cols = 0 then
+ return ZeroVector( cols, v );
+ fi;
+
+ # "unpack" cheaply and then delegate to kernel implementation
+ if IsPlistVectorRep(v) then
+ res := v![ELSPOS];
+ elif IsList(v) then
+ res := v;
+ else
+ res := Unpack(v);
+ fi;
+ res := res * M![FROWSPOS];
+ return Vector( res, v );
+ end );
+
+InstallMethod( ChangedBaseDomain,
+ [ "IsGenericMatrixRep", "IsRing" ],
+ function( M, r )
+ return NewMatrix( IsGenericMatrixRep, r, NrCols(M), M![FROWSPOS] );
+ end );
+
+
+InstallMethod( MultMatrixRowLeft,
+ [ "IsGenericMatrixRep and IsMutable", "IsInt", "IsObject" ],
+ function( mat, row, scalar )
+ MultMatrixRowLeft(mat![FROWSPOS], row, scalar);
+ end );
+
+InstallMethod( MultMatrixRowRight,
+ [ "IsGenericMatrixRep and IsMutable", "IsInt", "IsObject" ],
+ function( mat, row, scalar )
+ MultMatrixRowRight(mat![FROWSPOS], row, scalar);
+ end );
+
+InstallMethod( AddMatrixRowsLeft,
+ [ "IsGenericMatrixRep and IsMutable", "IsInt", "IsInt", "IsObject" ],
+ function( mat, row1, row2, scalar )
+ AddMatrixRowsLeft( mat![FROWSPOS], row1, row2, scalar );
+ end );
+
+InstallMethod( AddMatrixRowsRight,
+ [ "IsGenericMatrixRep and IsMutable", "IsInt", "IsInt", "IsObject" ],
+ function( mat, row1, row2, scalar )
+ AddMatrixRowsRight( mat![FROWSPOS], row1, row2, scalar );
+ end );
+
+InstallMethod( PositionNonZeroInRow,
+ [ "IsGenericMatrixRep", "IsPosInt" ],
+ function( mat, row )
+ return PositionNonZero( mat![FROWSPOS][row] );
+ end );
+
+InstallMethod( PositionNonZeroInRow,
+ [ "IsGenericMatrixRep", "IsPosInt", "IsInt" ],
+ function( mat, row, from )
+ return PositionNonZero( mat![FROWSPOS][row], from );
+ end );
+
+InstallMethod( SwapMatrixRows,
+ [ "IsGenericMatrixRep and IsMutable", "IsInt", "IsInt" ],
+ function( mat, row1, row2 )
+ SwapMatrixRows(mat![FROWSPOS], row1, row2);
+ end );
+
+InstallMethod( SwapMatrixColumns,
+ [ "IsGenericMatrixRep and IsMutable", "IsInt", "IsInt" ],
+ function( mat, col1, col2 )
+ SwapMatrixColumns(mat![FROWSPOS], col1, col2);
+ end );
+
+
+InstallMethod( PostMakeImmutable,
+ [ "IsGenericMatrixRep" ],
+ function( M )
+ MakeImmutable( M![FROWSPOS] );
+ end );
+
+
+InstallMethod( ViewObj, [ "IsGenericMatrixRep" ],
+ function( M )
+ Print( "<" );
+ if not IsMutable( M ) then
+ Print( "immutable " );
+ fi;
+ Print( NrRows(M), "x", NrCols(M),
+ "-matrix over ", BaseDomain(M), ">" );
+ end );
+
+InstallMethod( PrintObj, [ "IsGenericMatrixRep" ],
+ function( M )
+ Print( "NewMatrix(IsGenericMatrixRep" );
+ if IsFinite( BaseDomain(M) ) and IsField( BaseDomain(M) ) then
+ Print( ",GF(", Size( BaseDomain(M) ), ")," );
+ else
+ Print( ",", String( BaseDomain(M) ), "," );
+ fi;
+ Print( NumberColumns( M ), ",", Unpack( M ), ")" );
+ end );
+
+InstallMethod( Display, [ "IsGenericMatrixRep" ],
+ function( M )
+ local i;
+ Print( "<" );
+ if not IsMutable( M ) then
+ Print( "immutable " );
+ fi;
+ Print( NrRows(M), "x", NrCols(M),
+ "-matrix over ", BaseDomain(M), ":\n" );
+ for i in [ 1 .. NrRows(M) ] do
+ if i = 1 then
+ Print( "[" );
+ else
+ Print( " " );
+ fi;
+ Print( M![FROWSPOS][i], "\n" );
+ od;
+ Print( "]>\n" );
+ end );
+
+InstallMethod( String, [ "IsGenericMatrixRep" ],
+ function( M )
+ local st;
+ st := "NewMatrix(IsGenericMatrixRep";
+ Add( st, ',' );
+ if IsFinite( BaseDomain(M) ) and IsField( BaseDomain(M) ) then
+ Append( st, "GF(" );
+ Append( st, String( Size( BaseDomain(M) ) ) );
+ Append( st, ")," );
+ else
+ Append( st, String( BaseDomain(M) ) );
+ Append( st, "," );
+ fi;
+ Append( st, String( NumberColumns( M ) ) );
+ Add( st, ',' );
+ Append( st, String( Unpack( M ) ) );
+ Add( st, ')' );
+ return st;
+ end );
diff --git a/lib/matobjplist.gi b/lib/matobjplist.gi
index 7a1b99f4d4..4e2e188cd0 100644
--- a/lib/matobjplist.gi
+++ b/lib/matobjplist.gi
@@ -34,55 +34,43 @@
##
BindGlobal( "MakeIsPlistVectorRep",
function( basedomain, list, check )
- local fam, types, typ;
- fam := FamilyObj(basedomain);
- #types := _PlistVectorRepTypeCache(basedomain);
-
- # special case: integers
- if IsIntegers(basedomain) then
- if not IsBound(basedomain!.PlistVectorRepTypes) then
- # initialize type cache
- # TODO: make this thread safe for HPC-GAP
- basedomain!.PlistVectorRepTypes := [
- NewType(fam, IsPlistVectorRep and IsIntVector and CanEasilyCompareElements),
- NewType(fam, IsPlistVectorRep and IsIntVector and CanEasilyCompareElements and IsMutable),
- ];
- fi;
- types := basedomain!.PlistVectorRepTypes;
- elif IsFFECollection(basedomain) then
- if not IsBound(basedomain!.PlistVectorRepTypes) then
- # initialize type cache
- # TODO: make this thread safe for HPC-GAP
- basedomain!.PlistVectorRepTypes := [
- NewType(fam, IsPlistVectorRep and IsFFEVector and CanEasilyCompareElements),
- NewType(fam, IsPlistVectorRep and IsFFEVector and CanEasilyCompareElements and IsMutable),
- ];
- fi;
- types := basedomain!.PlistVectorRepTypes;
+ local efam, fam, filter, types, typ;
+
+ efam := ElementsFamily( FamilyObj( basedomain ) );
+ fam := FamilyObj( basedomain );
+
+ # we store the types in the base domain if the filter carries
+ # information specific to it
+ if IsBound( basedomain!.PlistVectorRepTypes ) then
+ types := basedomain!.PlistVectorRepTypes;
+ elif IsBound( fam!.PlistVectorRepTypes ) and not IsIntegers(basedomain) then
+ types := fam!.PlistVectorRepTypes;
else
- if not IsBound(fam!.PlistVectorRepTypes) then
- # initialize type cache
- # TODO: make this thread safe for HPC-GAP
- fam!.PlistVectorRepTypes := [
- NewType(fam, IsPlistVectorRep),
- NewType(fam, IsPlistVectorRep and IsMutable),
- ];
- fam!.PlistVectorRepTypesEasyCompare := [
- NewType(fam, IsPlistVectorRep and CanEasilyCompareElements),
- NewType(fam, IsPlistVectorRep and CanEasilyCompareElements and IsMutable),
- ];
- fi;
- if HasCanEasilyCompareElements(Representative(basedomain)) and
- CanEasilyCompareElements(Representative(basedomain)) then
- types := fam!.PlistVectorRepTypesEasyCompare;
- else
- types := fam!.PlistVectorRepTypes;
- fi;
+ # initialize type cache
+ # TODO: make this thread safe for HPC-GAP
+ filter := IsPlistVectorRep;
+ if CanEasilyCompareElementsFamily( efam ) then
+ filter := filter and CanEasilyCompareElements;
+ fi;
+ if IsIntegers(basedomain) then
+ filter := filter and IsIntVector;
+ elif IsFFECollection(basedomain) then
+ filter := filter and IsFFEVector;
+ fi;
+ types := [
+ NewType( fam, filter ),
+ NewType( fam, filter and IsMutable ),
+ ];
+ if IsIntegers(basedomain) then
+ basedomain!.PlistVectorRepTypes := types;
+ else
+ fam!.PlistVectorRepTypes := types;
+ fi;
fi;
- if IsMutable(list) then
- typ := types[2];
+ if IsMutable( list ) then
+ typ := types[2];
else
- typ := types[1];
+ typ := types[1];
fi;
if check and ValueOption( "check" ) <> false then
@@ -120,33 +108,29 @@ BindGlobal( "MakeIsPlistVectorRep",
##
BindGlobal( "MakeIsPlistMatrixRep",
function( basedomain, emptyvector, ncols, list, check )
- local fam, types, typ, row;
- fam:= CollectionsFamily( FamilyObj( basedomain ) );
+ local efam, fam, filter, typ, row;
+
+ efam := ElementsFamily( FamilyObj( basedomain ) );
+ fam := CollectionsFamily( FamilyObj( basedomain ) );
# Currently there is no special handling depending on 'basedomain',
# the types are always cached in 'fam'.
if not IsBound( fam!.PlistMatrixRepTypes ) then
# initialize type cache
# TODO: make this thread safe for HPC-GAP
- fam!.PlistMatrixRepTypes:= [
- NewType( fam, IsPlistMatrixRep ),
- NewType( fam, IsPlistMatrixRep and IsMutable ),
- ];
- fam!.PlistMatrixRepTypesEasyCompare:= [
- NewType( fam, IsPlistMatrixRep and CanEasilyCompareElements ),
- NewType( fam, IsPlistMatrixRep and CanEasilyCompareElements and IsMutable ),
+ filter := IsPlistMatrixRep;
+ if CanEasilyCompareElementsFamily( efam ) then
+ filter := filter and CanEasilyCompareElements;
+ fi;
+ fam!.PlistMatrixRepTypes := [
+ NewType( fam, filter ),
+ NewType( fam, filter and IsMutable ),
];
fi;
- if HasCanEasilyCompareElements( Representative( basedomain ) ) and
- CanEasilyCompareElements( Representative( basedomain ) ) then
- types:= fam!.PlistMatrixRepTypesEasyCompare;
- else
- types:= fam!.PlistMatrixRepTypes;
- fi;
if IsMutable( list ) then
- typ:= types[2];
+ typ := fam!.PlistMatrixRepTypes[2];
else
- typ:= types[1];
+ typ := fam!.PlistMatrixRepTypes[1];
fi;
if check and ValueOption( "check" ) <> false then
@@ -158,10 +142,10 @@ BindGlobal( "MakeIsPlistMatrixRep",
for row in list do
if not IsPlistVectorRep( row ) then
Error( "the entries of must be in 'IsPlistVectorRep'" );
- elif not IsIdenticalObj( basedomain, row![BDPOS] ) then
- Error( "the entries of must have the given base domain" );
elif Length( row![ELSPOS] ) <> ncols then
Error( "the entries of must have length " );
+ elif not IsIdenticalObj( basedomain, row![BDPOS] ) then
+ Error( "the entries of must have the given base domain" );
fi;
od;
fi;
diff --git a/lib/read3.g b/lib/read3.g
index baf3cf714c..b3fdbbc96a 100644
--- a/lib/read3.g
+++ b/lib/read3.g
@@ -107,6 +107,7 @@ ReadLib( "wordass.gd" );
ReadLib( "matobj2.gd" );
ReadLib( "matobjplist.gd" );
+ReadLib( "matobjgeneric.gd" );
ReadLib( "matobjnz.gd" );
# files dealing with rewriting systems
diff --git a/lib/read5.g b/lib/read5.g
index e0042c6bf4..cb4a8365b1 100644
--- a/lib/read5.g
+++ b/lib/read5.g
@@ -114,6 +114,7 @@ ReadLib( "vecmat.gi" );
ReadLib( "vec8bit.gi" );
ReadLib( "mat8bit.gi" );
ReadLib( "matobjplist.gi" );
+ReadLib( "matobjgeneric.gi" );
ReadLib( "matobjnz.gi" );
ReadLib( "meataxe.gi" );
ReadLib( "meatauto.gi" );
diff --git a/tst/testinstall/MatrixObj/CompanionMatrix.tst b/tst/testinstall/MatrixObj/CompanionMatrix.tst
index b5e27bbb2c..a2b1330b57 100644
--- a/tst/testinstall/MatrixObj/CompanionMatrix.tst
+++ b/tst/testinstall/MatrixObj/CompanionMatrix.tst
@@ -67,6 +67,22 @@ gap> TestCompanionMatrix(IsPlistMatrixRep, x+1, F);
gap> TestCompanionMatrix(IsPlistMatrixRep, x^2+x+1, F);
<2x2-matrix over Rationals>
+#
+# IsGenericMatrixRep
+#
+gap> F:= GF(251);; x:= X(F);;
+gap> TestCompanionMatrix(IsGenericMatrixRep, x+1, F);
+<1x1-matrix over GF(251)>
+gap> TestCompanionMatrix(IsGenericMatrixRep, x^2+x+1, F);
+<2x2-matrix over GF(251)>
+
+#
+gap> F:= Integers;; x:= X(F);;
+gap> TestCompanionMatrix(IsGenericMatrixRep, x+1, F);
+<1x1-matrix over Integers>
+gap> TestCompanionMatrix(IsGenericMatrixRep, x^2+x+1, F);
+<2x2-matrix over Integers>
+
#
# IsPlistRep
#
diff --git a/tst/testinstall/MatrixObj/ElementaryMatrices.tst b/tst/testinstall/MatrixObj/ElementaryMatrices.tst
index e2080c550a..2204e66d9c 100644
--- a/tst/testinstall/MatrixObj/ElementaryMatrices.tst
+++ b/tst/testinstall/MatrixObj/ElementaryMatrices.tst
@@ -67,6 +67,14 @@ true
gap> TestElementaryTransforms( mat, -1 );
gap> TestWholeMatrixTransforms( mat, -1 );
+#
+gap> mat := NewMatrix(IsGenericMatrixRep, Integers, 3,
+> [ [ 2, 4, 5 ], [ 7, 11, -4 ], [ -3, 20, 0 ] ] );;
+gap> IsGenericMatrixRep(mat);
+true
+gap> TestElementaryTransforms( mat, -1 );
+gap> TestWholeMatrixTransforms( mat, -1 );
+
#
gap> TestPositionNonZeroInRow([ [ 1 ] ]);
gap> TestPositionNonZeroInRow(Matrix([ [ 1 ] ]));
diff --git a/tst/testinstall/MatrixObj/IdentityMatrix.tst b/tst/testinstall/MatrixObj/IdentityMatrix.tst
index 1cabf541aa..74f429b3f2 100644
--- a/tst/testinstall/MatrixObj/IdentityMatrix.tst
+++ b/tst/testinstall/MatrixObj/IdentityMatrix.tst
@@ -73,6 +73,24 @@ gap> TestIdentityMatrix(IsPlistMatrixRep, Integers mod 4, 0);
gap> TestIdentityMatrix(IsPlistMatrixRep, Integers mod 4, -1);
Error, IdentityMatrix: the dimension must be non-negative
+#
+# IsGenericMatrixRep
+#
+gap> TestIdentityMatrix(IsGenericMatrixRep, GF(2), 2);
+<2x2-matrix over GF(2)>
+gap> TestIdentityMatrix(IsGenericMatrixRep, GF(2), 0);
+<0x0-matrix over GF(2)>
+gap> TestIdentityMatrix(IsGenericMatrixRep, GF(2), -1);
+Error, IdentityMatrix: the dimension must be non-negative
+
+#
+gap> TestIdentityMatrix(IsGenericMatrixRep, Integers, 2);
+<2x2-matrix over Integers>
+gap> TestIdentityMatrix(IsGenericMatrixRep, Integers, 0);
+<0x0-matrix over Integers>
+gap> TestIdentityMatrix(IsGenericMatrixRep, Integers, -1);
+Error, IdentityMatrix: the dimension must be non-negative
+
#
# Test IdentityMatrix variant which "guesses" a suitable representation, i.e.:
# IdentityMatrix( , , )
diff --git a/tst/testinstall/MatrixObj/Matrix.tst b/tst/testinstall/MatrixObj/Matrix.tst
index 85d6c9d80f..bc07b33465 100644
--- a/tst/testinstall/MatrixObj/Matrix.tst
+++ b/tst/testinstall/MatrixObj/Matrix.tst
@@ -45,5 +45,16 @@ gap> Display(m);
gap> m = Matrix( IsPlistMatrixRep, GF(2), [1,2,3,4] * Z(2), 2 );
true
+#
+gap> m := Matrix( IsGenericMatrixRep, GF(2), [[1,2],[3,4]] * Z(2) );
+<2x2-matrix over GF(2)>
+gap> Display(m);
+<2x2-matrix over GF(2):
+[[ Z(2)^0, 0*Z(2) ]
+ [ Z(2)^0, 0*Z(2) ]
+]>
+gap> m = Matrix( IsGenericMatrixRep, GF(2), [1,2,3,4] * Z(2), 2 );
+true
+
#
gap> STOP_TEST("Matrix.tst");
diff --git a/tst/testinstall/MatrixObj/ZeroMatrix.tst b/tst/testinstall/MatrixObj/ZeroMatrix.tst
index 2affaa554b..a21962bfcf 100644
--- a/tst/testinstall/MatrixObj/ZeroMatrix.tst
+++ b/tst/testinstall/MatrixObj/ZeroMatrix.tst
@@ -79,6 +79,24 @@ gap> TestZeroMatrix(IsPlistMatrixRep, Integers mod 4, 2, 0);
gap> TestZeroMatrix(IsPlistMatrixRep, Integers mod 4, 0, 3);
<0x3-matrix over (Integers mod 4)>
+#
+# IsGenericMatrixRep
+#
+gap> TestZeroMatrix(IsGenericMatrixRep, GF(2), 2, 3);
+<2x3-matrix over GF(2)>
+gap> TestZeroMatrix(IsGenericMatrixRep, GF(2), 2, 0);
+<2x0-matrix over GF(2)>
+gap> TestZeroMatrix(IsGenericMatrixRep, GF(2), 0, 3);
+<0x3-matrix over GF(2)>
+
+#
+gap> TestZeroMatrix(IsGenericMatrixRep, Integers, 2, 3);
+<2x3-matrix over Integers>
+gap> TestZeroMatrix(IsGenericMatrixRep, Integers, 2, 0);
+<2x0-matrix over Integers>
+gap> TestZeroMatrix(IsGenericMatrixRep, Integers, 0, 3);
+<0x3-matrix over Integers>
+
#
# Test ZeroMatrix variant which "guesses" a suitable representation, i.e.:
# ZeroMatrix( , , )
diff --git a/tst/testinstall/MatrixObj/matobjgeneric.tst b/tst/testinstall/MatrixObj/matobjgeneric.tst
new file mode 100644
index 0000000000..748248ff47
--- /dev/null
+++ b/tst/testinstall/MatrixObj/matobjgeneric.tst
@@ -0,0 +1,456 @@
+#@local e, v, v2, w, M, z, rows, a, b, c, d, p, ev, n, ai, inv, zm, zs, N, T, R
+gap> START_TEST( "matobjgeneric.tst" );
+
+#
+# MakeIsPlistVectorRep: test input validation
+#
+gap> e:= MakeIsPlistVectorRep( Integers, [], true );
+
+gap> v:= MakeIsPlistVectorRep( Integers, [ 1 ], true );
+
+gap> v2:= NewVector( IsPlistVectorRep, Integers, [ 1, 0 ] );
+
+gap> w:= MakeIsPlistVectorRep( Rationals, [ 1 ], true );
+
+
+#
+gap> MakeIsGenericMatrixRep( Integers, 2, [ v ], true );
+Error, the entries of must be plain lists
+gap> M:= MakeIsGenericMatrixRep( Integers, 2, [], true );
+<0x2-matrix over Integers>
+gap> MakeIsGenericMatrixRep( Integers, 1, [ [ 1 ] ], true );
+<1x1-matrix over Integers>
+gap> MakeIsGenericMatrixRep( Integers, 2, [ [ 1 ] ], true );
+Error, the entries of must have length
+gap> MakeIsGenericMatrixRep( Integers, 1, [ [ 1/2 ] ], true );
+Error, the elements in must lie in
+gap> MakeIsGenericMatrixRep( GF(2), 1, [ [ Z(2) ] ], true );
+<1x1-matrix over GF(2)>
+gap> MakeIsGenericMatrixRep( GF(2), 1, [ [ Z(4) ] ], true );
+Error, the elements in must lie in
+
+#
+gap> NewMatrix( IsGenericMatrixRep, Integers, 2, [] );
+<0x2-matrix over Integers>
+gap> NewMatrix( IsGenericMatrixRep, Integers, 2, [ 1 ] );
+Error, NewMatrix: Length of is not a multiple of
+gap> NewMatrix( IsGenericMatrixRep, Integers, 2, [ [ 1 ] ] );
+Error, the entries of must have length
+gap> NewMatrix( IsGenericMatrixRep, Integers, 2, [ [ 1, 2 ] ] );
+<1x2-matrix over Integers>
+gap> NewMatrix( IsGenericMatrixRep, Integers, 2, [ v ] );
+Error, the entries of must have length
+gap> M:= NewMatrix( IsGenericMatrixRep, Integers, 2, [ [ 1, 2 ], [ 3, 4 ] ] );
+<2x2-matrix over Integers>
+gap> IsMutable( M );
+true
+gap> Unpack( M );
+[ [ 1, 2 ], [ 3, 4 ] ]
+gap> M[2,1];
+3
+gap> M[1];
+Error, row access unsupported; use M[i,j] or RowsOfMatrix(M)
+gap> M[2,2] := 5;;
+gap> Unpack( M );
+[ [ 1, 2 ], [ 3, 5 ] ]
+
+#
+gap> rows:= RowsOfMatrix( M );
+[ ,
+ ]
+gap> Length( rows );
+2
+gap> IsPlistVectorRep( rows[1] );
+true
+gap> Unpack( rows[1] );
+[ 1, 2 ]
+gap> M[1,1] := 77;;
+gap> rows[1][1];
+1
+
+#
+gap> M:= NewMatrix( IsGenericMatrixRep, Integers, 2, [ v2, v2 ] );;
+gap> Unpack( M );
+[ [ 1, 0 ], [ 1, 0 ] ]
+
+#
+# Empty matrices and empty vectors
+#
+#
+gap> a:= ZeroMatrix( IsGenericMatrixRep, Integers, 2, 0 );
+<2x0-matrix over Integers>
+gap> b:= ZeroMatrix( IsGenericMatrixRep, Integers, 0, 3 );
+<0x3-matrix over Integers>
+gap> c:= ZeroMatrix( IsGenericMatrixRep, Integers, 0, 0 );
+<0x0-matrix over Integers>
+gap> d:= ZeroMatrix( IsGenericMatrixRep, Integers, 0, 2 );
+<0x2-matrix over Integers>
+gap> z:= ZeroMatrix( IsGenericMatrixRep, Integers, 2, 3 );
+<2x3-matrix over Integers>
+gap> IsMutable( z );
+true
+gap> Unpack( z );
+[ [ 0, 0, 0 ], [ 0, 0, 0 ] ]
+
+#
+gap> M:= NewIdentityMatrix( IsGenericMatrixRep, Integers, 2 );;
+gap> Unpack( M );
+[ [ 1, 0 ], [ 0, 1 ] ]
+
+#
+gap> a = NewMatrix( IsGenericMatrixRep, Integers, 0, [ [], [] ] );
+true
+gap> b = NewMatrix( IsGenericMatrixRep, Integers, 3, [] );
+true
+gap> c = NewMatrix( IsGenericMatrixRep, Integers, 0, [] );
+true
+gap> d = NewMatrix( IsGenericMatrixRep, Integers, 2, [] );
+true
+
+#
+gap> p:= a * b;
+<2x3-matrix over Integers>
+gap> Unpack( p );
+[ [ 0, 0, 0 ], [ 0, 0, 0 ] ]
+gap> p:= d * a;
+<0x0-matrix over Integers>
+gap> Unpack( p );
+[ ]
+gap> p:= c * b;
+<0x3-matrix over Integers>
+gap> Unpack( p );
+[ ]
+
+# empty vector times (necessarily also empty) matrix
+gap> ev:= NewVector( IsPlistVectorRep, Integers, [] );
+
+gap> a * ev;
+
+gap> Unpack( last );
+[ 0, 0 ]
+gap> ev * b;
+
+gap> Unpack( last );
+[ 0, 0, 0 ]
+
+# non-empty vector times empty matrix
+gap> v2:= NewVector( IsPlistVectorRep, Integers, [ 1, 2 ] );
+
+gap> d * v2;
+
+gap> Unpack( last );
+[ ]
+gap> Unpack( v2 * a );
+[ ]
+
+#
+gap> b + b;
+<0x3-matrix over Integers>
+gap> b - b;
+<0x3-matrix over Integers>
+gap> -b;
+<0x3-matrix over Integers>
+gap> ZeroMutable( b );
+<0x3-matrix over Integers>
+
+#
+gap> InverseMutable( c );
+<0x0-matrix over Integers>
+gap> InverseSameMutability( c );
+<0x0-matrix over Integers>
+
+#
+gap> M:= Matrix( IsGenericMatrixRep, Integers, [ [ 0, 0, 2 ], [ 0, 0, 0 ] ] );;
+gap> PositionNonZeroInRow( M, 1 );
+3
+gap> PositionNonZeroInRow( M, 1, 2 );
+3
+gap> PositionNonZeroInRow( M, 2 );
+4
+
+#
+gap> M:= Matrix( IsGenericMatrixRep, Integers, [ [ 1, 2, 3 ], [ 4, 5, 6 ] ] );;
+gap> MultMatrixRowLeft( M, 1, -1 );;
+gap> Unpack( M );
+[ [ -1, -2, -3 ], [ 4, 5, 6 ] ]
+gap> MultMatrixRowRight( M, 2, 2 );;
+gap> Unpack( M );
+[ [ -1, -2, -3 ], [ 8, 10, 12 ] ]
+gap> AddMatrixRowsLeft( M, 1, 2, 3 );;
+gap> Unpack( M );
+[ [ 23, 28, 33 ], [ 8, 10, 12 ] ]
+gap> AddMatrixRowsRight( M, 2, 1, 2 );;
+gap> Unpack( M );
+[ [ 23, 28, 33 ], [ 54, 66, 78 ] ]
+gap> SwapMatrixRows( M, 1, 2 );;
+gap> Unpack( M );
+[ [ 54, 66, 78 ], [ 23, 28, 33 ] ]
+
+#
+# Test Inverse / InverseMutable
+#
+gap> M:= Matrix( IsGenericMatrixRep, Integers, [ [ 1, 2 ], [ 3, 4 ], [ 5, 6 ] ] );;
+gap> InverseMutable( M );
+Error, InverseMutable: matrix must be square
+gap> M:= Matrix( IsGenericMatrixRep, GF(2), [ [ Z(2)^0, Z(2)^0 ], [ Z(2)^0, 0*Z(2) ] ] );;
+gap> N:= InverseMutable( M );;
+gap> Display( N );
+<2x2-matrix over GF(2):
+[[ 0*Z(2), Z(2)^0 ]
+ [ Z(2)^0, Z(2)^0 ]
+]>
+gap> IsOne( N * M );
+true
+gap> IsOne( M * N );
+true
+gap> M:= Matrix( IsGenericMatrixRep, Rationals, [ [ 1, 2 ], [ 3, 5 ] ] );;
+gap> N:= InverseMutable( M );;
+gap> Display( N );
+<2x2-matrix over Rationals:
+[[ -5, 2 ]
+ [ 3, -1 ]
+]>
+
+#
+# mutability after operations
+#
+gap> M:= Matrix( IsGenericMatrixRep, Rationals, [ [ 1, 2 ], [ 3, 5 ] ] );;
+gap> IsMutable(M);
+true
+gap> N:= InverseSameMutability( M );;
+gap> IsMutable(N);
+true
+gap> IsMutable( M * N );
+true
+gap> IsMutable( M + N );
+true
+gap> IsMutable( M - N );
+true
+gap> IsMutable( -M );
+true
+gap> MakeImmutable(M);;
+gap> IsMutable( M * N );
+true
+gap> IsMutable( M + N );
+true
+gap> IsMutable( M - N );
+true
+gap> N:= InverseSameMutability( M );;
+gap> IsMutable(N);
+false
+gap> IsMutable( M * N );
+false
+gap> IsMutable( M + N );
+false
+gap> IsMutable( M - N );
+false
+gap> IsMutable( -M );
+false
+
+#
+gap> M:= Matrix( IsGenericMatrixRep, Integers, [ [ 1, 2 ], [ 3, 4 ] ] );;
+gap> M[1,1] := 1/2;
+Error, must lie in the base domain of
+gap> M[3,1] := 1;
+Error, is out of bounds
+gap> M[1,3] := 1;
+Error, is out of bounds
+
+#
+gap> a:= Matrix( IsGenericMatrixRep, Integers, [ [ 1, 2 ] ] );;
+gap> b:= Matrix( IsGenericMatrixRep, Rationals, [ [ 1, 2 ] ] );;
+gap> a + b;
+Error, and are not compatible
+gap> a - b;
+Error, and are not compatible
+gap> c:= Matrix( IsGenericMatrixRep, Integers, [ [ 1 ], [ 2 ] ] );;
+gap> c * c;
+Error, \*: Matrices do not fit together
+gap> d:= Matrix( IsGenericMatrixRep, Rationals, [ [ 1 ], [ 2 ] ] );;
+gap> a * d;
+Error, \*: Matrices not over same base domain
+
+#
+# ShallowCopy, MutableCopyMatrix
+#
+gap> M:= Matrix( IsGenericMatrixRep, Integers, [ [ 1, 2 ], [ 3, 4 ] ] );;
+gap> N:= ShallowCopy( M );;
+gap> N[1,1] := 99;;
+gap> Unpack( M );
+[ [ 1, 2 ], [ 3, 4 ] ]
+gap> Unpack( N );
+[ [ 99, 2 ], [ 3, 4 ] ]
+gap> N:= MutableCopyMatrix( M );;
+gap> N[1,2] := 77;;
+gap> Unpack( M );
+[ [ 1, 2 ], [ 3, 4 ] ]
+gap> Unpack( N );
+[ [ 1, 77 ], [ 3, 4 ] ]
+
+#
+# ExtractSubMatrix, CopySubMatrix
+#
+gap> Unpack( ExtractSubMatrix( M, [ 2, 1 ], [ 2 ] ) );
+[ [ 4 ], [ 2 ] ]
+gap> T:= ZeroMatrix( IsGenericMatrixRep, Integers, 2, 3 );;
+gap> CopySubMatrix( M, T, [ 2, 1 ], [ 1, 2 ], [ 2 ], [ 3 ] );;
+gap> Unpack( T );
+[ [ 0, 0, 4 ], [ 0, 0, 2 ] ]
+gap> CopySubMatrix( Matrix( IsGenericMatrixRep, Rationals, [ [ 1, 2 ] ] ),
+> T, [ 1 ], [ 1 ], [ 1 ], [ 1 ] );
+Error, and are not compatible
+
+#
+# TransposedMatMutable
+#
+gap> Unpack( TransposedMatMutable( M ) );
+[ [ 1, 3 ], [ 2, 4 ] ]
+
+#
+# ChangedBaseDomain
+#
+gap> N:= ChangedBaseDomain( M, Rationals );;
+gap> BaseDomain( N );
+Rationals
+gap> Unpack( N );
+[ [ 1, 2 ], [ 3, 4 ] ]
+gap> IsMutable( N );
+true
+gap> MakeImmutable( M );;
+gap> N:= ChangedBaseDomain( M, Rationals );;
+gap> IsMutable( N );
+false
+
+#
+# ViewObj, PrintObj, Display, String
+#
+gap> M := Matrix( IsGenericMatrixRep, GF(2), [ [ Z(2)^0, 0*Z(2) ] ] );
+<1x2-matrix over GF(2)>
+gap> Print(M, "\n");
+NewMatrix(IsGenericMatrixRep,GF(2),2,[ [ Z(2)^0, 0*Z(2) ] ])
+gap> Display(M);
+<1x2-matrix over GF(2):
+[[ Z(2)^0, 0*Z(2) ]
+]>
+gap> String(M);
+"NewMatrix(IsGenericMatrixRep,GF(2),2,[ [ Z(2)^0, 0*Z(2) ] ])"
+
+#
+gap> MakeImmutable( M );
+
+gap> Print(M, "\n");
+NewMatrix(IsGenericMatrixRep,GF(2),2,[ [ Z(2)^0, 0*Z(2) ] ])
+gap> Display(M);
+
+gap> String(M);
+"NewMatrix(IsGenericMatrixRep,GF(2),2,[ [ Z(2)^0, 0*Z(2) ] ])"
+
+#
+gap> M :=Matrix( IsGenericMatrixRep, Integers, [ [ 1, 2 ], [ 3, 4 ] ] );
+<2x2-matrix over Integers>
+gap> Print(M, "\n");
+NewMatrix(IsGenericMatrixRep,Integers,2,[ [ 1, 2 ], [ 3, 4 ] ])
+gap> Display(M);
+<2x2-matrix over Integers:
+[[ 1, 2 ]
+ [ 3, 4 ]
+]>
+gap> String(M);
+"NewMatrix(IsGenericMatrixRep,Integers,2,[ [ 1, 2 ], [ 3, 4 ] ])"
+
+#
+gap> MakeImmutable( M );
+
+gap> Print(M, "\n");
+NewMatrix(IsGenericMatrixRep,Integers,2,[ [ 1, 2 ], [ 3, 4 ] ])
+gap> Display(M);
+
+gap> String(M);
+"NewMatrix(IsGenericMatrixRep,Integers,2,[ [ 1, 2 ], [ 3, 4 ] ])"
+
+#
+# vec * mat, mat * vec
+#
+gap> M:= Matrix( IsGenericMatrixRep, Integers, [ [ 1, 2 ], [ 3, 4 ] ] );;
+gap> v:= Vector( Integers, [ 1, 2 ] );
+
+gap> Display( M * v );
+
+gap> Display( v * M );
+
+
+#
+gap> M * [ 1, 2 ];
+[ 5, 11 ]
+gap> [ 1, 2 ] * M;
+[ 7, 10 ]
+
+#
+gap> R:= Integers mod 6;;
+gap> M:= Matrix( IsGenericMatrixRep, R, One(R) * [ [ 1, 2 ], [ 3, 4 ] ] );;
+gap> v:= NewVector( IsZmodnZVectorRep, R, One(R) * [ 1, 2 ] );
+
+gap> Display( M * v );
+
+gap> Display( v * M );
+
+
+# error handling
+gap> M * [ 1, 2, 3 ];
+Error, and are not compatible
+gap> [ 1, 2, 3 ] * M;
+Error, and are not compatible
+gap> M * [ Z(2), Z(2) ];
+Error, and are not compatible
+gap> [ Z(2), Z(2) ] * M;
+Error, and are not compatible
+
+# multiplication with empty list is not well-defined: we don't know if
+# is meant to be a vector of length 0, or something else; so rather
+# error out
+gap> a:= ZeroMatrix( IsGenericMatrixRep, Integers, 2, 0 );;
+gap> b:= ZeroMatrix( IsGenericMatrixRep, Integers, 0, 3 );;
+gap> a * [];
+Error, no method found! For debugging hints type ?Recovery from NoMethodFound
+Error, no 1st choice method found for `BaseDomain' on 1 arguments
+gap> [] * b;
+Error, no method found! For debugging hints type ?Recovery from NoMethodFound
+Error, no 1st choice method found for `BaseDomain' on 1 arguments
+
+#
+# families
+#
+gap> M:= NewZeroMatrix( IsGenericMatrixRep, Integers, 2, 3 );
+<2x3-matrix over Integers>
+gap> IsMutable( M );
+true
+gap> IsCyclotomicCollColl( M );
+true
+gap> IsFFECollColl( M );
+false
+
+#
+gap> M:= NewZeroMatrix( IsGenericMatrixRep, GF(257), 2, 3 );
+<2x3-matrix over GF(257)>
+gap> IsMutable( M );
+true
+gap> IsCyclotomicCollColl( M );
+false
+gap> IsFFECollColl( M );
+true
+
+#
+gap> STOP_TEST( "matobjgeneric.tst" );
diff --git a/tst/testinstall/MatrixObj/matobjplist.tst b/tst/testinstall/MatrixObj/matobjplist.tst
index f1099217d9..fb42f5daba 100644
--- a/tst/testinstall/MatrixObj/matobjplist.tst
+++ b/tst/testinstall/MatrixObj/matobjplist.tst
@@ -37,10 +37,8 @@ gap> NewVector( IsPlistVectorRep, Integers, [ 1/2 ] );;
Error, the elements in must lie in
#
-gap> NewZeroVector( IsPlistVectorRep, Integers, 0 );;
-gap> z:= NewZeroVector( IsPlistVectorRep, Integers, 1 );;
-gap> IsMutable( z );
-true
+gap> NewZeroVector( IsPlistVectorRep, Integers, 0 );
+
#
gap> NewMatrix( IsPlistMatrixRep, Integers, 2, [] );;
@@ -56,18 +54,74 @@ gap> IsMutable( M ) and ForAll( [ 1 .. Length( M ) ], i -> IsMutable( M[i] ) );
true
#
-gap> NewZeroMatrix( IsPlistMatrixRep, Integers, 0, 0 );;
-gap> NewZeroMatrix( IsPlistMatrixRep, Integers, 2, 0 );;
-gap> NewZeroMatrix( IsPlistMatrixRep, Integers, 0, 3 );;
-gap> M:= NewZeroMatrix( IsPlistMatrixRep, Integers, 2, 3 );;
+gap> NewZeroMatrix( IsPlistMatrixRep, Integers, 0, 0 );
+<0x0-matrix over Integers>
+gap> NewZeroMatrix( IsPlistMatrixRep, Integers, 2, 0 );
+<2x0-matrix over Integers>
+gap> NewZeroMatrix( IsPlistMatrixRep, Integers, 0, 3 );
+<0x3-matrix over Integers>
+gap> M:= NewZeroMatrix( IsPlistMatrixRep, Integers, 2, 3 );
+<2x3-matrix over Integers>
gap> IsMutable( M ) and ForAll( [ 1 .. Length( M ) ], i -> IsMutable( M[i] ) );
true
#
-gap> NewIdentityMatrix( IsPlistMatrixRep, Integers, 0 );;
-gap> M:= NewIdentityMatrix( IsPlistMatrixRep, Integers, 2 );;
+gap> NewIdentityMatrix( IsPlistMatrixRep, Integers, 0 );
+<0x0-matrix over Integers>
+gap> M:= NewIdentityMatrix( IsPlistMatrixRep, Integers, 2 );
+<2x2-matrix over Integers>
gap> IsMutable( M ) and ForAll( [ 1 .. Length( M ) ], i -> IsMutable( M[i] ) );
true
+#
+# special filters and families
+#
+gap> v:= NewVector( IsPlistVectorRep, Integers, [ 1, 2, 0 ] );
+
+gap> IsMutable( v );
+true
+gap> IsIntVector( v );
+true
+gap> IsFFEVector( v );
+false
+gap> IsCyclotomicCollection( v );
+true
+gap> IsFFECollection( v );
+false
+
+#
+gap> v:= NewVector( IsPlistVectorRep, GF(257), Z(257)^0 * [ 1, 2, 0 ] );
+
+gap> IsMutable( v );
+true
+gap> IsIntVector( v );
+false
+gap> IsFFEVector( v );
+true
+gap> IsCyclotomicCollection( v );
+false
+gap> IsFFECollection( v );
+true
+
+#
+gap> M:= NewZeroMatrix( IsPlistMatrixRep, Integers, 2, 3 );
+<2x3-matrix over Integers>
+gap> IsMutable( M );
+true
+gap> IsCyclotomicCollColl( M );
+true
+gap> IsFFECollColl( M );
+false
+
+#
+gap> M:= NewZeroMatrix( IsPlistMatrixRep, GF(257), 2, 3 );
+<2x3-matrix over GF(257)>
+gap> IsMutable( M );
+true
+gap> IsCyclotomicCollColl( M );
+false
+gap> IsFFECollColl( M );
+true
+
#
gap> STOP_TEST( "matobjplist.tst" );
diff --git a/tst/testinstall/MatrixObj/testmatobj.g b/tst/testinstall/MatrixObj/testmatobj.g
index bca02e4c1c..811f924485 100644
--- a/tst/testinstall/MatrixObj/testmatobj.g
+++ b/tst/testinstall/MatrixObj/testmatobj.g
@@ -211,6 +211,8 @@ TestWholeMatrixTransforms := function(mat, scalar)
basedomain := BaseDomain(mat);
if IsPlistMatrixRep(mat) then
src := NewMatrix(IsPlistMatrixRep, basedomain, NrCols(mat), src);
+ elif IsGenericMatrixRep(mat) then
+ src := NewMatrix(IsGenericMatrixRep, basedomain, NrCols(mat), src);
elif Is8BitMatrixRep(mat) then
ConvertToMatrixRep(src, basedomain);
fi;
diff --git a/tst/testspecial/method-not-found-where.g b/tst/testspecial/method-not-found-where.g
index 16ce4149c4..49079f4b75 100644
--- a/tst/testspecial/method-not-found-where.g
+++ b/tst/testspecial/method-not-found-where.g
@@ -1,5 +1,5 @@
# test method-not-found traceback rendering while preserving helper access
-f := a -> a + a;;
+f := a -> IsDiagonalMat(a);;
f(());
ShowMethods(1);
Where(5);
diff --git a/tst/testspecial/method-not-found-where.g.out b/tst/testspecial/method-not-found-where.g.out
index c7496f32b2..30601cd166 100644
--- a/tst/testspecial/method-not-found-where.g.out
+++ b/tst/testspecial/method-not-found-where.g.out
@@ -1,19 +1,19 @@
gap> # test method-not-found traceback rendering while preserving helper access
-gap> f := a -> a + a;;
+gap> f := a -> IsDiagonalMat(a);;
gap> f(());
Error, no method found! For debugging hints type ?Recovery from NoMethodFound
-Error, no 1st choice method found for `+' on 2 arguments
+Error, no 1st choice method found for `IsDiagonalMatrix' on 1 arguments
Stack trace:
-*[1] a + a
+*[1] IsDiagonalMat( a )
@ *stdin*:3
( )
called from read-eval loop at *stdin*:4
type 'quit;' to quit to outer loop
brk> ShowMethods(1);
-#I Searching Method for + with 2 arguments:
-#I Total: 138 entries
+#I Searching Method for IsDiagonalMatrix with 1 argument:
+#I Total: 3 entries
brk> Where(5);
-*[1] a + a
+*[1] IsDiagonalMat( a )
@ *stdin*:3
( )
called from read-eval loop at *errin*:2