diff --git a/doc/ref/matobj.xml b/doc/ref/matobj.xml
index bcf39d27d82..2b5a387a251 100644
--- a/doc/ref/matobj.xml
+++ b/doc/ref/matobj.xml
@@ -173,10 +173,10 @@ for these matrix objects.
-One implementation of such matrices is given by the
+Two implementation of such matrices is given by the
value
-,
-and any row of these matrices is a vector object in
+,
+and any row of these matrices can be accessed as a vector object in
.
Note that these objects do not lie in
(and in particular not in ),
@@ -190,8 +190,9 @@ in the last position,
that is, the vector and matrix objects insist on being dense.
All rows of a matrix must have the same length and the same base domain.
-<#Include Label="IsPlistVectorRep">
-<#Include Label="IsPlistMatrixRep">
+<#Include Label="IsRowPlistMatrixRep">
+<#Include Label="IsPlistVectorRep">
+<#Include Label="IsPlistMatrixRep">
<#Include Label="RowListMatObj_[]">
<#Include Label="RowListMatObj_[]_ASS">
<#Include Label="RowListMatObj_{}">
diff --git a/lib/matobjplist.gd b/lib/matobjplist.gd
index d19c20e60c7..8df44cc9ded 100644
--- a/lib/matobjplist.gd
+++ b/lib/matobjplist.gd
@@ -56,35 +56,45 @@ DeclareRepresentation( "IsPlistVectorRep",
##
##
## An object obj in describes
+## a matrix object (see ) that internal stores its
+## entries as a classic GAP matrix, that is as a plain list (see
+## ) of plain lists. Therefore any such GAP matrix
+## can be represented as a , making this
+## representation very versatile, and a good place to start if one wants to
+## adapt code which previously produced such classic GAP matrices to instead
+## produce matrix objects.
+##
+##
+## <#/GAPDoc>
+##
+## Implementation note: a matrix in IsPlistMatrixRep is internally
+## represented as a positional object that stores four entries:
+## - its base domain
+# - the number of rows
+## - the number of columns
+## - a plain list of its rows, each also a plain list
+DeclareRepresentation( "IsPlistMatrixRep",
+ IsMatrixObj and IsPositionalObjectRep and IsNoImmediateMethodsObject, [] );
+
+
+#############################################################################
+##
+## <#GAPDoc Label="IsRowPlistMatrixRep">
+##
+##
+##
+##
+## An object obj in describes
## a matrix object (see ) that behaves similar to
## a list of its rows, in the sense defined in
## Section .
-## It is internally represented as a positional object
-## (see that stores four entries:
-##
-## -
-## its base domain
-## (see
),
-##
-## -
-## the number of rows
-## (see
), and
-##
-## -
-## the number of columns
-## (see
), and
-##
-## -
-## a plain list (see
of its rows,
-## each of them being an object in .
-##
-##
+## Its rows can be accessed as objects in ,
##
##
## <#/GAPDoc>
##
-DeclareRepresentation( "IsPlistMatrixRep",
- IsRowListMatrix and IsPositionalObjectRep and IsNoImmediateMethodsObject, [] );
+DeclareRepresentation( "IsRowPlistMatrixRep",
+ IsRowListMatrix and IsPlistMatrixRep, [] );
# Some constants for matrix access:
diff --git a/lib/matobjplist.gi b/lib/matobjplist.gi
index dd0e9a48476..f8fd6ee8280 100644
--- a/lib/matobjplist.gi
+++ b/lib/matobjplist.gi
@@ -18,10 +18,9 @@
# Constructors:
############################################################################
-InstallMethod( NewVector, "for IsPlistVectorRep, a semiring, and a list",
- [ IsPlistVectorRep, IsSemiring, IsList ],
- function( filter, basedomain, l )
- local typ;
+BindGlobal( "MakeIsPlistVectorRep",
+ function( basedomain, list )
+ local filter, typ;
filter := IsPlistVectorRep and IsMutable;
if HasCanEasilyCompareElements(Representative(basedomain)) and
CanEasilyCompareElements(Representative(basedomain)) then
@@ -33,14 +32,23 @@ InstallMethod( NewVector, "for IsPlistVectorRep, a semiring, and a list",
filter := filter and IsFFEVector;
fi;
typ := NewType(FamilyObj(basedomain), filter);
- return Objectify(typ, [ basedomain, ShallowCopy(l) ]);
+ return Objectify(typ, [ basedomain, list ]);
+ end );
+
+
+InstallMethod( NewVector, "for IsPlistVectorRep, a semiring, and a list",
+ [ IsPlistVectorRep, IsSemiring, IsList ],
+ function( filter, basedomain, list )
+ list := ShallowCopy( list );
+ return MakeIsPlistVectorRep( basedomain, list );
end );
InstallMethod( NewZeroVector, "for IsPlistVectorRep, a semiring, and an int",
[ IsPlistVectorRep, IsSemiring, IsInt ],
- function( filter, basedomain, l )
- l := ListWithIdenticalEntries(l,Zero(basedomain));
- return NewVector( filter, basedomain, l );
+ function( filter, basedomain, len )
+ local list;
+ list := ListWithIdenticalEntries(len, Zero(basedomain));
+ return MakeIsPlistVectorRep( basedomain, list );
end );
InstallMethod( NewMatrix,
@@ -549,9 +557,97 @@ InstallMethod( IdentityMatrix, "for an integer and a plist matrix",
return res;
end );
-# FIXME: does ShallowCopy even make sense for a matrixobj???
+
+############################################################################
+# A selection of list operations:
+############################################################################
+
+InstallOtherMethod( \[\], "for a plist matrix and a positive integer",
+#T Once the declaration of '\[\]' for 'IsMatrixObj' disappears,
+#T we can use 'InstallMethod'.
+ [ IsRowPlistMatrixRep, IsPosInt ],
+ function( m, i )
+ Info(InfoPerformance, 1, "for best performance avoid m[i]; e.g. use m[i,j] instead of m[i][j]");
+ # TODO: should we cache these row vectors?
+ return MakeIsPlistVectorRep( m![BDPOS], m![ROWSPOS][i] );
+ end );
+
+InstallMethod( \[\]\:\=,
+ "for a plist matrix, a positive integer, and a plist vector",
+ [ IsRowPlistMatrixRep and IsMutable, IsPosInt, IsPlistVectorRep ],
+ function( m, i, v )
+ # TODO: verify that basedomain matches and that Length(v) = NrCols(m) ?
+ m![ROWSPOS][i] := v![ELSPOS];
+ # FIXME: really just assign the content, so that from now on any change to
+ # the vector object will modify the i-th row of ??? yes, this
+ # emulates the old way of things, but it's also dangerous, and often leads to
+ # bugs; perhaps we should instead make a copy / copy over the data only?
+ end );
+
+InstallMethod( \{\}, "for a plist matrix and a list",
+ [ IsRowPlistMatrixRep, IsList ],
+ function( m, p )
+ local l;
+ l := m![ROWSPOS]{p};
+ return Objectify(TypeObj(m),[m![BDPOS],m![NUM_ROWS_POS],m![NUM_COLS_POS],l]);
+ end );
+
+InstallMethod( Add, "for a plist matrix and a plist vector",
+ [ IsRowPlistMatrixRep and IsMutable, IsPlistVectorRep ],
+ function( m, v )
+ Add(m![ROWSPOS],v);
+ end );
+
+InstallMethod( Add, "for a plist matrix, a plist vector, and a pos. int",
+ [ IsRowPlistMatrixRep and IsMutable, IsPlistVectorRep, IsPosInt ],
+ function( m, v, p )
+ Add(m![ROWSPOS],v,p);
+ end );
+
+InstallMethod( Remove, "for a plist matrix",
+ [ IsRowPlistMatrixRep and IsMutable ],
+ m -> Remove( m![ROWSPOS] ) );
+
+InstallMethod( Remove, "for a plist matrix, and a position",
+ [ IsRowPlistMatrixRep and IsMutable, IsPosInt ],
+ function( m, p )
+ Remove( m![ROWSPOS],p );
+ end );
+#T must return the removed row if it was bound
+
+InstallMethod( IsBound\[\], "for a plist matrix, and a position",
+ [ IsRowPlistMatrixRep, IsPosInt ],
+ function( m, p )
+ # TODO: move this to the generic IsRowListMatrix interface?
+ return p <= NrRows(m);
+ end );
+
+InstallMethod( Unbind\[\], "for a plist matrix, and a position",
+ [ IsRowPlistMatrixRep and IsMutable, IsPosInt ],
+ function( m, p )
+ # TODO: move this to the generic IsRowListMatrix interface?
+ if p <> NrRows(m) then
+ ErrorNoReturn("Unbind\\[\\]: Matrices must stay dense, you cannot Unbind here");
+ fi;
+ Remove(m);
+ end );
+
+InstallMethod( \{\}\:\=, "for a plist matrix, a list, and a plist matrix",
+ [ IsRowPlistMatrixRep and IsMutable, IsList,
+ IsRowPlistMatrixRep ],
+ function( m, pp, n )
+ # TODO: verify that basedomain matches and that Length(v) = NrCols(m) ?
+ m![ROWSPOS]{pp} := n![ROWSPOS];
+ end );
+
+InstallMethod( Append, "for two plist matrices",
+ [ IsRowPlistMatrixRep and IsMutable, IsRowPlistMatrixRep ],
+ function( m, n )
+ Append(m![ROWSPOS],n![ROWSPOS]);
+ end );
+
InstallMethod( ShallowCopy, "for a plist matrix",
- [ IsPlistMatrixRep ],
+ [ IsRowPlistMatrixRep ],
function( m )
local res;
res := Objectify(TypeObj(m),[m![BDPOS],m![NUM_ROWS_POS],m![NUM_COLS_POS],