From ab613e38bb595357732c7c30b6f16081c6316325 Mon Sep 17 00:00:00 2001 From: Max Horn Date: Sun, 12 Apr 2026 22:56:40 +0200 Subject: [PATCH 01/23] Add IsFlatPlistMatrixRep matrix object type Store dense matrices as plain row lists for faster entry access. Some microbenchmarks show the benefit, namely that performance for basic arithmetic in many cases matches that of ist-of-list matrices, while IsPlistMatrixRep is basically always slower, sometimes quite substantially so. Setup: R:=GF(257);;n:=20;; M1:=IdentityMat(n,R);; M2:=IdentityMatrix(IsPlistMatrixRep,R,n);; M3:=IdentityMatrix(IsFlatPlistMatrixRep,R,n);; Addition: gap> for i in [1..1000] do x:=M1+M1; od; time; 4 gap> for i in [1..1000] do x:=M2+M2; od; time; 12 gap> for i in [1..1000] do x:=M3+M3; od; time; 4 Multiplication: gap> for i in [1..1000] do x:=M1*M1; od; time; 66 gap> for i in [1..1000] do x:=M2*M2; od; time; 1448 gap> for i in [1..1000] do x:=M3*M3; od; time; 60 Inversion: gap> for i in [1..1000] do x:=Inverse(M1); od; time; 7 gap> for i in [1..1000] do x:=Inverse(M2); od; time; 83 gap> for i in [1..1000] do x:=Inverse(M3); od; time; 4 Powers: gap> gap> for i in [1..1000] do x:=M1^5; od; time; 187 gap> for i in [1..1000] do x:=M2^5; od; time; 4350 gap> for i in [1..1000] do x:=M3^5; od; time; 182 Element access (plist-of-plist benefits from a direct kernel implementation; we could add that for both IsPlistMatrixRep and IsFlatPlistMatrixRep, if so desired) gap> for i in [1..1000000] do x:=M1[1,1]; od; time; 19 gap> for i in [1..1000000] do x:=M2[1,1]; od; time; 78 gap> for i in [1..1000000] do x:=M3[1,1]; od; time; 66 Example of a typical matrix property: IsDiagonalMat gap> for i in [1..10000] do x:=IsDiagonalMat(M1); od; time; 132 gap> for i in [1..10000] do x:=IsDiagonalMat(M2); od; time; 191 gap> for i in [1..10000] do x:=IsDiagonalMat(M3); od; time; 146 IsOne (surprisingly is slower for IsFlatPlistMatrixRep, I do not yet know why) gap> for i in [1..10000] do x:=IsOne(M1); od; time; 144 gap> for i in [1..10000] do x:=IsOne(M2); od; time; 145 gap> for i in [1..10000] do x:=IsOne(M3); od; time; 172 PositionNonZeroInRow is among the core functionality for row reduction: gap> for i in [1..1000000] do x:=PositionNonZeroInRow(M1,1); od; time; 334 gap> for i in [1..1000000] do x:=PositionNonZeroInRow(M2,1); od; time; 486 gap> for i in [1..1000000] do x:=PositionNonZeroInRow(M3,1); od; time; 376 Co-authored-by: Codex --- benchmark/matobj/bench-matelm-access.g | 18 +- benchmark/matobj/bench-matobj-creation.g | 13 +- doc/ref/matobj.xml | 1 + lib/matobjflatplist.gd | 46 ++ lib/matobjflatplist.gi | 509 ++++++++++++++++++ lib/read3.g | 1 + lib/read5.g | 1 + tst/testinstall/MatrixObj/CompanionMatrix.tst | 16 + .../MatrixObj/ElementaryMatrices.tst | 8 + tst/testinstall/MatrixObj/IdentityMatrix.tst | 18 + tst/testinstall/MatrixObj/Matrix.tst | 11 + tst/testinstall/MatrixObj/ZeroMatrix.tst | 18 + tst/testinstall/MatrixObj/matobjflatplist.tst | 191 +++++++ tst/testinstall/MatrixObj/testmatobj.g | 2 + 14 files changed, 843 insertions(+), 10 deletions(-) create mode 100644 lib/matobjflatplist.gd create mode 100644 lib/matobjflatplist.gi create mode 100644 tst/testinstall/MatrixObj/matobjflatplist.tst diff --git a/benchmark/matobj/bench-matelm-access.g b/benchmark/matobj/bench-matelm-access.g index 889ba71801..3ef1f6a9cb 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); # IsFlatPlistMatrixRep +RunMatTest("GF(257) IsFlatPlistMatrixRep", 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..8ce1af3b6a 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) IsFlatPlistMatrixRep", IsFlatPlistMatrixRep, GF(257)); + +RunMatTest("Integers", Integers); RunMatObjTest("integer IsPlistMatrixRep", IsPlistMatrixRep, Integers); +RunMatObjTest("integer IsFlatPlistMatrixRep", IsFlatPlistMatrixRep, Integers); + +RunMatTest("Rationals", Rationals); RunMatObjTest("rational IsPlistMatrixRep", IsPlistMatrixRep, Rationals); +RunMatObjTest("rational IsFlatPlistMatrixRep", IsFlatPlistMatrixRep, Rationals); # TODO: other reps # TODO: other compare with creating plist-of-plist diff --git a/doc/ref/matobj.xml b/doc/ref/matobj.xml index 8ed8908e47..c2eaf6717c 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="IsFlatPlistMatrixRep"> <#Include Label="IsZmodnZMatrixRep"> diff --git a/lib/matobjflatplist.gd b/lib/matobjflatplist.gd new file mode 100644 index 0000000000..b4b801dab3 --- /dev/null +++ b/lib/matobjflatplist.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="IsFlatPlistMatrixRep"> +## +## +## +## +## 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( "IsFlatPlistMatrixRep", + IsMatrixObj and IsPositionalObjectRep + and IsCopyable + and IsNoImmediateMethodsObject + and HasNumberRows and HasNumberColumns + and HasBaseDomain and HasOneOfBaseDomain and HasZeroOfBaseDomain, + [] ); + + +# Internal positions for flat plist matrices. +BindConstant( "FBDPOS", 1 ); +BindConstant( "FCOLSPOS", 2 ); +BindConstant( "FROWSPOS", 3 ); diff --git a/lib/matobjflatplist.gi b/lib/matobjflatplist.gi new file mode 100644 index 0000000000..8343c42552 --- /dev/null +++ b/lib/matobjflatplist.gi @@ -0,0 +1,509 @@ +############################################################################# +## +## 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( "CopyFlatPlistMatrixRow", + function( row ) + local copy, i, len; + len := Length( row ); + copy := []; + if 0 < len then + copy[len] := row[len]; + for i in [ 1 .. len - 1 ] do + copy[i] := row[i]; + od; + fi; + return copy; + end ); + +BindGlobal( "InverseRowsForFlatPlistMatrix", + function( M ) + local bd, rows; + + if NrRows( M ) <> NrCols( M ) then + return fail; + elif NrRows( M ) = 0 then + rows := []; + return rows; + fi; + + bd := BaseDomain( M ); + if IsFinite( bd ) and IsField( bd ) then + return INV_MAT_DEFAULT_MUTABLE( M![FROWSPOS] ); + fi; + return INV_MATRIX_MUTABLE( M![FROWSPOS] ); + end ); + +BindGlobal( "MakeIsFlatPlistMatrixRep", + function( basedomain, ncols, list, check ) + local fam, types, typ, row; + + fam := CollectionsFamily( FamilyObj( basedomain ) ); + if not IsBound( fam!.FlatPlistMatrixRepTypes ) then + fam!.FlatPlistMatrixRepTypes := [ + NewType( fam, IsFlatPlistMatrixRep ), + NewType( fam, IsFlatPlistMatrixRep and IsMutable ), + ]; + fam!.FlatPlistMatrixRepTypesEasyCompare := [ + NewType( fam, IsFlatPlistMatrixRep and CanEasilyCompareElements ), + NewType( fam, IsFlatPlistMatrixRep and CanEasilyCompareElements and IsMutable ), + ]; + fi; + if HasCanEasilyCompareElements( Representative( basedomain ) ) and + CanEasilyCompareElements( Representative( basedomain ) ) then + types := fam!.FlatPlistMatrixRepTypesEasyCompare; + else + types := fam!.FlatPlistMatrixRepTypes; + fi; + if IsMutable( list ) then + typ := types[2]; + else + typ := types[1]; + fi; + + if check and ValueOption( "check" ) <> false then + 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, + IsFlatPlistMatrixRep, + 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 := 0 * [ 1 .. Length( list ) ]; + for i in [ 1 .. Length( list ) ] do + row := list[i]; + if IsVectorObj( row ) then + row := Unpack( row ); + fi; + rows[i] := CopyFlatPlistMatrixRow( row ); + od; + if not IsMutable( list ) then + MakeImmutable( rows ); + fi; + return MakeIsFlatPlistMatrixRep( basedomain, ncols, rows, true ); + end ); + + +InstallTagBasedMethod( NewZeroMatrix, + IsFlatPlistMatrixRep, + function( filter, basedomain, rows, cols ) + local list, row, i, z; + list := 0 * [ 1 .. rows ]; + z := Zero( basedomain ); + for i in [ 1 .. rows ] do + row := ListWithIdenticalEntries( cols, z ); + list[i] := row; + od; + return MakeIsFlatPlistMatrixRep( basedomain, cols, list, false ); + end ); + + +InstallMethod( ConstructingFilter, + [ "IsFlatPlistMatrixRep" ], + M -> IsFlatPlistMatrixRep ); + +InstallMethod( CompatibleVectorFilter, + [ "IsFlatPlistMatrixRep" ], + M -> IsPlistVectorRep ); + + +InstallMethod( BaseDomain, + [ "IsFlatPlistMatrixRep" ], + M -> M![FBDPOS] ); + +InstallMethod( NumberRows, + [ "IsFlatPlistMatrixRep" ], + M -> Length( M![FROWSPOS] ) ); + +InstallMethod( NumberColumns, + [ "IsFlatPlistMatrixRep" ], + M -> M![FCOLSPOS] ); + +InstallMethod( \[\], + [ "IsFlatPlistMatrixRep", "IsPosInt" ], + function( M, pos ) + ErrorNoReturn( "row access unsupported; use M[i,j] or RowsOfMatrix(M)" ); + end ); + +InstallMethod( MatElm, + [ "IsFlatPlistMatrixRep", "IsPosInt", "IsPosInt" ], + { M, row, col } -> M![FROWSPOS][row,col] ); + +InstallMethod( SetMatElm, + [ "IsFlatPlistMatrixRep and IsMutable", "IsPosInt", "IsPosInt", "IsObject" ], + function( M, row, col, ob ) + if ValueOption( "check" ) <> false then + if not ob 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] := ob; + end ); + + +InstallMethod( Unpack, + [ "IsFlatPlistMatrixRep" ], + M -> List( M![FROWSPOS], CopyFlatPlistMatrixRow ) ); + +InstallMethod( ShallowCopy, + [ "IsFlatPlistMatrixRep" ], + M -> MakeIsFlatPlistMatrixRep( BaseDomain(M), NrCols(M), + List( M![FROWSPOS], CopyFlatPlistMatrixRow ), false ) ); + +InstallMethod( MutableCopyMatrix, + [ "IsFlatPlistMatrixRep" ], + M -> MakeIsFlatPlistMatrixRep( BaseDomain(M), NrCols(M), + List( M![FROWSPOS], CopyFlatPlistMatrixRow ), false ) ); + +InstallMethod( ExtractSubMatrix, + [ "IsFlatPlistMatrixRep", "IsList", "IsList" ], + function( M, rowspos, colspos ) + local list, i; + list := M![FROWSPOS]{ rowspos }{ colspos }; + return MakeIsFlatPlistMatrixRep( BaseDomain(M), Length( colspos ), list, false ); + end ); + +InstallMethod( CopySubMatrix, + [ "IsFlatPlistMatrixRep", "IsFlatPlistMatrixRep and IsMutable", + "IsList", "IsList", "IsList", "IsList" ], + function( M, N, srcrows, dstrows, srccols, dstcols ) + local i; + 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, + [ "IsFlatPlistMatrixRep" ], + function( M ) + local list; + list := TransposedMatMutable(M![FROWSPOS]); + return MakeIsFlatPlistMatrixRep( BaseDomain(M), NrRows(M), list, false ); + end ); + +InstallMethod( \+, + [ "IsFlatPlistMatrixRep", "IsFlatPlistMatrixRep" ], + 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 MakeIsFlatPlistMatrixRep( BaseDomain( a ), NrCols( a ), + a![FROWSPOS] + b![FROWSPOS], false ); + end ); + +InstallMethod( \-, + [ "IsFlatPlistMatrixRep", "IsFlatPlistMatrixRep" ], + 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 MakeIsFlatPlistMatrixRep( BaseDomain( a ), NrCols( a ), + a![FROWSPOS] - b![FROWSPOS], false ); + end ); + +InstallMethod( AdditiveInverseMutable, + [ "IsFlatPlistMatrixRep" ], + M -> MakeIsFlatPlistMatrixRep( BaseDomain( M ), NrCols( M ), + AdditiveInverseMutable( M![FROWSPOS] ), false ) ); + +InstallMethod( ZeroMutable, + [ "IsFlatPlistMatrixRep" ], + function( M ) + local z; + z := MakeIsFlatPlistMatrixRep( BaseDomain( M ), NrCols( M ), + ZeroMutable( M![FROWSPOS] ), false ); + SetIsZero( z, true ); + return z; + end ); + +InstallMethod( InverseMutable, + [ "IsFlatPlistMatrixRep" ], + function( M ) + local rows; + + rows := InverseRowsForFlatPlistMatrix( M ); + if rows = fail then + return fail; + fi; + return MakeIsFlatPlistMatrixRep( BaseDomain( M ), NrCols( M ), rows, false ); + end ); + +InstallMethod( \*, + [ "IsFlatPlistMatrixRep", "IsFlatPlistMatrixRep" ], + 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 := 0 * [ 1 .. rowsA ]; + for i in [ 1 .. rowsA ] do + list[i] := ListWithIdenticalEntries( colsB, Zero( bd ) ); + od; + else + list := a![FROWSPOS] * b![FROWSPOS]; + fi; + if not IsMutable( a ) and not IsMutable( b ) then + MakeImmutable( list ); + fi; + return MakeIsFlatPlistMatrixRep( bd, colsB, list, false ); + end ); + +InstallMethod( \*, + [ "IsFlatPlistMatrixRep", "IsVectorObj" ], + function( M, v ) + local rows, cols, bd, res, i, j; + + 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 ); + +InstallMethod( \*, + [ "IsVectorObj", "IsFlatPlistMatrixRep" ], + function( v, M ) + local rows, cols, bd, res, i, j; + + 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, + [ "IsFlatPlistMatrixRep", "IsRing" ], + function( M, r ) + local n; + n := NewMatrix( IsFlatPlistMatrixRep, r, NrCols(M), M![FROWSPOS] ); + if not IsMutable( M ) then + MakeImmutable( n ); + fi; + return n; + end ); + + +InstallMethod( MultMatrixRowLeft, + [ "IsFlatPlistMatrixRep and IsMutable", "IsInt", "IsObject" ], + function( mat, row, scalar ) + MultMatrixRowLeft(mat![FROWSPOS], row, scalar); + end ); + +InstallMethod( MultMatrixRowRight, + [ "IsFlatPlistMatrixRep and IsMutable", "IsInt", "IsObject" ], + function( mat, row, scalar ) + MultMatrixRowRight(mat![FROWSPOS], row, scalar); + end ); + +InstallMethod( AddMatrixRowsLeft, + [ "IsFlatPlistMatrixRep and IsMutable", "IsInt", "IsInt", "IsObject" ], + function( mat, row1, row2, scalar ) + AddMatrixRowsLeft( mat![FROWSPOS], row1, row2, scalar ); + end ); + +InstallMethod( AddMatrixRowsRight, + [ "IsFlatPlistMatrixRep and IsMutable", "IsInt", "IsInt", "IsObject" ], + function( mat, row1, row2, scalar ) + AddMatrixRowsRight( mat![FROWSPOS], row1, row2, scalar ); + end ); + +InstallMethod( PositionNonZeroInRow, + [ "IsFlatPlistMatrixRep", "IsPosInt" ], + function( mat, row ) + return PositionNonZero( mat![FROWSPOS][row] ); + end ); + +InstallMethod( PositionNonZeroInRow, + [ "IsFlatPlistMatrixRep", "IsPosInt", "IsInt" ], + function( mat, row, from ) + return PositionNonZero( mat![FROWSPOS][row], from ); + end ); + +InstallMethod( SwapMatrixRows, + [ "IsFlatPlistMatrixRep and IsMutable", "IsInt", "IsInt" ], + function( mat, row1, row2 ) + SwapMatrixRows(mat![FROWSPOS], row1, row2); + end ); + +InstallMethod( SwapMatrixColumns, + [ "IsFlatPlistMatrixRep and IsMutable", "IsInt", "IsInt" ], + function( mat, col1, col2 ) + SwapMatrixColumns(mat![FROWSPOS], col1, col2); + end ); + + +InstallMethod( PostMakeImmutable, + [ "IsFlatPlistMatrixRep" ], + function( M ) + local row; + MakeImmutable( M![FROWSPOS] ); + end ); + + +InstallMethod( ViewObj, [ "IsFlatPlistMatrixRep" ], + function( M ) + Print( "<" ); + if not IsMutable( M ) then + Print( "immutable " ); + fi; + Print( NrRows(M), "x", NrCols(M), + "-matrix over ", BaseDomain(M), ">" ); + end ); + +InstallMethod( PrintObj, [ "IsFlatPlistMatrixRep" ], + function( M ) + Print( "NewMatrix(IsFlatPlistMatrixRep" ); + 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, [ "IsFlatPlistMatrixRep" ], + 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, [ "IsFlatPlistMatrixRep" ], + function( M ) + local st; + st := "NewMatrix(IsFlatPlistMatrixRep"; + 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/read3.g b/lib/read3.g index baf3cf714c..7d345ae67e 100644 --- a/lib/read3.g +++ b/lib/read3.g @@ -107,6 +107,7 @@ ReadLib( "wordass.gd" ); ReadLib( "matobj2.gd" ); ReadLib( "matobjplist.gd" ); +ReadLib( "matobjflatplist.gd" ); ReadLib( "matobjnz.gd" ); # files dealing with rewriting systems diff --git a/lib/read5.g b/lib/read5.g index e0042c6bf4..94a4132f8b 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( "matobjflatplist.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..5821ec8281 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> +# +# IsFlatPlistMatrixRep +# +gap> F:= GF(251);; x:= X(F);; +gap> TestCompanionMatrix(IsFlatPlistMatrixRep, x+1, F); +<1x1-matrix over GF(251)> +gap> TestCompanionMatrix(IsFlatPlistMatrixRep, x^2+x+1, F); +<2x2-matrix over GF(251)> + +# +gap> F:= Integers;; x:= X(F);; +gap> TestCompanionMatrix(IsFlatPlistMatrixRep, x+1, F); +<1x1-matrix over Integers> +gap> TestCompanionMatrix(IsFlatPlistMatrixRep, 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..ae67b4dd8b 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(IsFlatPlistMatrixRep, Integers, 3, +> [ [ 2, 4, 5 ], [ 7, 11, -4 ], [ -3, 20, 0 ] ] );; +gap> IsFlatPlistMatrixRep(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..c42e7191d0 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 +# +# IsFlatPlistMatrixRep +# +gap> TestIdentityMatrix(IsFlatPlistMatrixRep, GF(2), 2); +<2x2-matrix over GF(2)> +gap> TestIdentityMatrix(IsFlatPlistMatrixRep, GF(2), 0); +<0x0-matrix over GF(2)> +gap> TestIdentityMatrix(IsFlatPlistMatrixRep, GF(2), -1); +Error, IdentityMatrix: the dimension must be non-negative + +# +gap> TestIdentityMatrix(IsFlatPlistMatrixRep, Integers, 2); +<2x2-matrix over Integers> +gap> TestIdentityMatrix(IsFlatPlistMatrixRep, Integers, 0); +<0x0-matrix over Integers> +gap> TestIdentityMatrix(IsFlatPlistMatrixRep, 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..15298ab499 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( IsFlatPlistMatrixRep, 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( IsFlatPlistMatrixRep, 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..8a5c86c4b9 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)> +# +# IsFlatPlistMatrixRep +# +gap> TestZeroMatrix(IsFlatPlistMatrixRep, GF(2), 2, 3); +<2x3-matrix over GF(2)> +gap> TestZeroMatrix(IsFlatPlistMatrixRep, GF(2), 2, 0); +<2x0-matrix over GF(2)> +gap> TestZeroMatrix(IsFlatPlistMatrixRep, GF(2), 0, 3); +<0x3-matrix over GF(2)> + +# +gap> TestZeroMatrix(IsFlatPlistMatrixRep, Integers, 2, 3); +<2x3-matrix over Integers> +gap> TestZeroMatrix(IsFlatPlistMatrixRep, Integers, 2, 0); +<2x0-matrix over Integers> +gap> TestZeroMatrix(IsFlatPlistMatrixRep, Integers, 0, 3); +<0x3-matrix over Integers> + # # Test ZeroMatrix variant which "guesses" a suitable representation, i.e.: # ZeroMatrix( , , ) diff --git a/tst/testinstall/MatrixObj/matobjflatplist.tst b/tst/testinstall/MatrixObj/matobjflatplist.tst new file mode 100644 index 0000000000..6454cd6d8b --- /dev/null +++ b/tst/testinstall/MatrixObj/matobjflatplist.tst @@ -0,0 +1,191 @@ +#@local e, v, v2, w, M, z, rows, a, b, c, d, p, ev, n, ai, inv, zm, zs +gap> START_TEST( "matobjflatplist.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> MakeIsFlatPlistMatrixRep( Integers, 2, [ v ], true ); +Error, the entries of must be plain lists +gap> M:= MakeIsFlatPlistMatrixRep( Integers, 2, [], true ); +<0x2-matrix over Integers> +gap> MakeIsFlatPlistMatrixRep( Integers, 1, [ [ 1 ] ], true ); +<1x1-matrix over Integers> +gap> MakeIsFlatPlistMatrixRep( Integers, 2, [ [ 1 ] ], true ); +Error, the entries of must have length +gap> MakeIsFlatPlistMatrixRep( Integers, 1, [ [ 1/2 ] ], true ); +Error, the elements in must lie in +gap> MakeIsFlatPlistMatrixRep( GF(2), 1, [ [ Z(2) ] ], true ); +<1x1-matrix over GF(2)> +gap> MakeIsFlatPlistMatrixRep( GF(2), 1, [ [ Z(4) ] ], true ); +Error, the elements in must lie in + +# +gap> NewMatrix( IsFlatPlistMatrixRep, Integers, 2, [] ); +<0x2-matrix over Integers> +gap> NewMatrix( IsFlatPlistMatrixRep, Integers, 2, [ 1 ] ); +Error, NewMatrix: Length of is not a multiple of +gap> NewMatrix( IsFlatPlistMatrixRep, Integers, 2, [ [ 1 ] ] ); +Error, the entries of must have length +gap> NewMatrix( IsFlatPlistMatrixRep, Integers, 2, [ [ 1, 2 ] ] ); +<1x2-matrix over Integers> +gap> NewMatrix( IsFlatPlistMatrixRep, Integers, 2, [ v ] ); +Error, the entries of must have length +gap> M:= NewMatrix( IsFlatPlistMatrixRep, 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( IsFlatPlistMatrixRep, Integers, 2, [ v2, v2 ] );; +gap> Unpack( M ); +[ [ 1, 0 ], [ 1, 0 ] ] + +# +# Empty matrices and empty vectors +# +# +gap> a:= NewZeroMatrix( IsFlatPlistMatrixRep, Integers, 2, 0 ); +<2x0-matrix over Integers> +gap> b:= NewZeroMatrix( IsFlatPlistMatrixRep, Integers, 0, 3 ); +<0x3-matrix over Integers> +gap> c:= NewZeroMatrix( IsFlatPlistMatrixRep, Integers, 0, 0 ); +<0x0-matrix over Integers> +gap> d:= NewZeroMatrix( IsFlatPlistMatrixRep, Integers, 0, 2 ); +<0x2-matrix over Integers> +gap> z:= NewZeroMatrix( IsFlatPlistMatrixRep, Integers, 2, 3 ); +<2x3-matrix over Integers> +gap> IsMutable( z ); +true +gap> Unpack( z ); +[ [ 0, 0, 0 ], [ 0, 0, 0 ] ] + +# +gap> M:= NewIdentityMatrix( IsFlatPlistMatrixRep, Integers, 2 );; +gap> Unpack( M ); +[ [ 1, 0 ], [ 0, 1 ] ] + +# +gap> a = NewMatrix( IsFlatPlistMatrixRep, Integers, 0, [ [], [] ] ); +true +gap> b = NewMatrix( IsFlatPlistMatrixRep, Integers, 3, [] ); +true +gap> c = NewMatrix( IsFlatPlistMatrixRep, Integers, 0, [] ); +true +gap> d = NewMatrix( IsFlatPlistMatrixRep, 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:= NewMatrix( IsFlatPlistMatrixRep, Integers, 3, [ [ 0, 0, 2 ], [ 0, 0, 0 ] ] );; +gap> PositionNonZeroInRow( M, 1 ); +3 +gap> PositionNonZeroInRow( M, 1, 2 ); +3 +gap> PositionNonZeroInRow( M, 2 ); +4 + +# +gap> M:= NewMatrix( IsFlatPlistMatrixRep, Integers, 3, +> [ [ 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 ] ] + +# +gap> STOP_TEST( "matobjflatplist.tst" ); diff --git a/tst/testinstall/MatrixObj/testmatobj.g b/tst/testinstall/MatrixObj/testmatobj.g index bca02e4c1c..fdcc53588f 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 IsFlatPlistMatrixRep(mat) then + src := NewMatrix(IsFlatPlistMatrixRep, basedomain, NrCols(mat), src); elif Is8BitMatrixRep(mat) then ConvertToMatrixRep(src, basedomain); fi; From c7ce3773924d4f032ae2a1f62eb463542aca7e9b Mon Sep 17 00:00:00 2001 From: Max Horn Date: Wed, 15 Apr 2026 00:38:12 +0200 Subject: [PATCH 02/23] hook up documentation --- doc/ref/makedocreldata.g | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/ref/makedocreldata.g b/doc/ref/makedocreldata.g index f2f1697bed..c31333eca0 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/matobjflatplist.gd", "../../lib/matrix.gd", "../../lib/meataxe.gi", "../../lib/memory.gd", From cd615d85c28d4b9a1818e74e113d42be2181d4b6 Mon Sep 17 00:00:00 2001 From: Max Horn Date: Wed, 15 Apr 2026 00:39:31 +0200 Subject: [PATCH 03/23] Fix gaplint warnings --- lib/matobjflatplist.gi | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/lib/matobjflatplist.gi b/lib/matobjflatplist.gi index 8343c42552..f489775b32 100644 --- a/lib/matobjflatplist.gi +++ b/lib/matobjflatplist.gi @@ -197,7 +197,7 @@ InstallMethod( MutableCopyMatrix, InstallMethod( ExtractSubMatrix, [ "IsFlatPlistMatrixRep", "IsList", "IsList" ], function( M, rowspos, colspos ) - local list, i; + local list; list := M![FROWSPOS]{ rowspos }{ colspos }; return MakeIsFlatPlistMatrixRep( BaseDomain(M), Length( colspos ), list, false ); end ); @@ -206,7 +206,6 @@ InstallMethod( CopySubMatrix, [ "IsFlatPlistMatrixRep", "IsFlatPlistMatrixRep and IsMutable", "IsList", "IsList", "IsList", "IsList" ], function( M, N, srcrows, dstrows, srccols, dstcols ) - local i; if ValueOption( "check" ) <> false and not IsIdenticalObj( BaseDomain(M), BaseDomain(N) ) then Error( " and are not compatible" ); @@ -313,7 +312,7 @@ InstallMethod( \*, InstallMethod( \*, [ "IsFlatPlistMatrixRep", "IsVectorObj" ], function( M, v ) - local rows, cols, bd, res, i, j; + local rows, cols, bd, res; rows := NumberRows( M ); cols := NumberColumns( M ); @@ -347,7 +346,7 @@ InstallMethod( \*, InstallMethod( \*, [ "IsVectorObj", "IsFlatPlistMatrixRep" ], function( v, M ) - local rows, cols, bd, res, i, j; + local rows, cols, bd, res; rows := NumberRows( M ); cols := NumberColumns( M ); @@ -442,7 +441,6 @@ InstallMethod( SwapMatrixColumns, InstallMethod( PostMakeImmutable, [ "IsFlatPlistMatrixRep" ], function( M ) - local row; MakeImmutable( M![FROWSPOS] ); end ); From 20cb5d9c7c0ddc4e1325777dd21916b961162d7e Mon Sep 17 00:00:00 2001 From: Max Horn Date: Wed, 15 Apr 2026 00:43:31 +0200 Subject: [PATCH 04/23] Make tst/testspecial/method-not-found-where.g more robust The number of methods for + may change quite a lot --- tst/testspecial/method-not-found-where.g | 2 +- tst/testspecial/method-not-found-where.g.out | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) 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 From bfeea740af02fd66ea2c38ae7d70e33f1f473c45 Mon Sep 17 00:00:00 2001 From: Max Horn Date: Wed, 15 Apr 2026 01:46:46 +0200 Subject: [PATCH 05/23] address some review comments --- lib/matobjflatplist.gi | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/lib/matobjflatplist.gi b/lib/matobjflatplist.gi index f489775b32..2ca5804910 100644 --- a/lib/matobjflatplist.gi +++ b/lib/matobjflatplist.gi @@ -17,13 +17,10 @@ BindGlobal( "CopyFlatPlistMatrixRow", function( row ) local copy, i, len; len := Length( row ); - copy := []; - if 0 < len then - copy[len] := row[len]; - for i in [ 1 .. len - 1 ] do - copy[i] := row[i]; - od; - fi; + copy := EmptyPlist( len ); + for i in [ 1 .. len ] do + copy[i] := row[i]; + od; return copy; end ); @@ -104,13 +101,14 @@ InstallTagBasedMethod( NewMatrix, fi; fi; - rows := 0 * [ 1 .. Length( list ) ]; + rows := EmptyPlist( Length( list ) ); for i in [ 1 .. Length( list ) ] do row := list[i]; if IsVectorObj( row ) then - row := Unpack( row ); + rows[i] := Unpack( row ); + else + rows[i] := CopyFlatPlistMatrixRow( row ); fi; - rows[i] := CopyFlatPlistMatrixRow( row ); od; if not IsMutable( list ) then MakeImmutable( rows ); @@ -123,7 +121,7 @@ InstallTagBasedMethod( NewZeroMatrix, IsFlatPlistMatrixRep, function( filter, basedomain, rows, cols ) local list, row, i, z; - list := 0 * [ 1 .. rows ]; + list := EmptyPlist( rows ); z := Zero( basedomain ); for i in [ 1 .. rows ] do row := ListWithIdenticalEntries( cols, z ); @@ -296,7 +294,7 @@ InstallMethod( \*, if rowsA = 0 or colsB = 0 then list := []; elif colsA = 0 then # colsA = rowsB - list := 0 * [ 1 .. rowsA ]; + list := EmptyPlist( rowsA ); for i in [ 1 .. rowsA ] do list[i] := ListWithIdenticalEntries( colsB, Zero( bd ) ); od; From 4c8e15af2ab627aead927fa4f278ead9d23dbe8d Mon Sep 17 00:00:00 2001 From: Max Horn Date: Wed, 15 Apr 2026 01:51:08 +0200 Subject: [PATCH 06/23] Remove CopyFlatPlistMatrixRow --- lib/matobjflatplist.gi | 19 ++++--------------- 1 file changed, 4 insertions(+), 15 deletions(-) diff --git a/lib/matobjflatplist.gi b/lib/matobjflatplist.gi index 2ca5804910..bb502d0dde 100644 --- a/lib/matobjflatplist.gi +++ b/lib/matobjflatplist.gi @@ -13,17 +13,6 @@ # Dense matrix objects backed by plain lists of plain row lists. # -BindGlobal( "CopyFlatPlistMatrixRow", - function( row ) - local copy, i, len; - len := Length( row ); - copy := EmptyPlist( len ); - for i in [ 1 .. len ] do - copy[i] := row[i]; - od; - return copy; - end ); - BindGlobal( "InverseRowsForFlatPlistMatrix", function( M ) local bd, rows; @@ -107,7 +96,7 @@ InstallTagBasedMethod( NewMatrix, if IsVectorObj( row ) then rows[i] := Unpack( row ); else - rows[i] := CopyFlatPlistMatrixRow( row ); + rows[i] := PlainListCopy( row ); fi; od; if not IsMutable( list ) then @@ -180,17 +169,17 @@ InstallMethod( SetMatElm, InstallMethod( Unpack, [ "IsFlatPlistMatrixRep" ], - M -> List( M![FROWSPOS], CopyFlatPlistMatrixRow ) ); + M -> List( M![FROWSPOS], ShallowCopy ) ); InstallMethod( ShallowCopy, [ "IsFlatPlistMatrixRep" ], M -> MakeIsFlatPlistMatrixRep( BaseDomain(M), NrCols(M), - List( M![FROWSPOS], CopyFlatPlistMatrixRow ), false ) ); + List( M![FROWSPOS], ShallowCopy ), false ) ); InstallMethod( MutableCopyMatrix, [ "IsFlatPlistMatrixRep" ], M -> MakeIsFlatPlistMatrixRep( BaseDomain(M), NrCols(M), - List( M![FROWSPOS], CopyFlatPlistMatrixRow ), false ) ); + List( M![FROWSPOS], ShallowCopy ), false ) ); InstallMethod( ExtractSubMatrix, [ "IsFlatPlistMatrixRep", "IsList", "IsList" ], From ec0d2fec190bc36dbe0f4a6076e6f6bfa94fe76f Mon Sep 17 00:00:00 2001 From: Max Horn Date: Thu, 16 Apr 2026 16:19:07 +0200 Subject: [PATCH 07/23] Rename IsFlatPlistMatrixRep to IsGenericMatrixRep --- benchmark/matobj/bench-matelm-access.g | 4 +- benchmark/matobj/bench-matobj-creation.g | 6 +- doc/ref/matobj.xml | 2 +- lib/matobjflatplist.gd | 8 +- lib/matobjflatplist.gi | 118 +++++++++--------- tst/testinstall/MatrixObj/CompanionMatrix.tst | 10 +- .../MatrixObj/ElementaryMatrices.tst | 4 +- tst/testinstall/MatrixObj/IdentityMatrix.tst | 14 +-- tst/testinstall/MatrixObj/Matrix.tst | 4 +- tst/testinstall/MatrixObj/ZeroMatrix.tst | 14 +-- tst/testinstall/MatrixObj/matobjflatplist.tst | 52 ++++---- tst/testinstall/MatrixObj/testmatobj.g | 4 +- 12 files changed, 120 insertions(+), 120 deletions(-) diff --git a/benchmark/matobj/bench-matelm-access.g b/benchmark/matobj/bench-matelm-access.g index 3ef1f6a9cb..f58d365830 100644 --- a/benchmark/matobj/bench-matelm-access.g +++ b/benchmark/matobj/bench-matelm-access.g @@ -142,8 +142,8 @@ RunMatTest("GF(257) plist-of-plist matrix", m); m:=IdentityMatrix(GF(257), 10); # IsPlistMatrixRep RunMatTest("GF(257) IsPlistMatrixRep", m); -m:=IdentityMatrix(GF(257), 10); # IsFlatPlistMatrixRep -RunMatTest("GF(257) IsFlatPlistMatrixRep", 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); diff --git a/benchmark/matobj/bench-matobj-creation.g b/benchmark/matobj/bench-matobj-creation.g index 8ce1af3b6a..fdf568d716 100644 --- a/benchmark/matobj/bench-matobj-creation.g +++ b/benchmark/matobj/bench-matobj-creation.g @@ -99,15 +99,15 @@ end; RunMatTest("GF(257)", GF(257)); RunMatObjTest("GF(257) IsPlistMatrixRep", IsPlistMatrixRep, GF(257)); -RunMatObjTest("GF(257) IsFlatPlistMatrixRep", IsFlatPlistMatrixRep, GF(257)); +RunMatObjTest("GF(257) IsGenericMatrixRep", IsGenericMatrixRep, GF(257)); RunMatTest("Integers", Integers); RunMatObjTest("integer IsPlistMatrixRep", IsPlistMatrixRep, Integers); -RunMatObjTest("integer IsFlatPlistMatrixRep", IsFlatPlistMatrixRep, Integers); +RunMatObjTest("integer IsGenericMatrixRep", IsGenericMatrixRep, Integers); RunMatTest("Rationals", Rationals); RunMatObjTest("rational IsPlistMatrixRep", IsPlistMatrixRep, Rationals); -RunMatObjTest("rational IsFlatPlistMatrixRep", IsFlatPlistMatrixRep, Rationals); +RunMatObjTest("rational IsGenericMatrixRep", IsGenericMatrixRep, Rationals); # TODO: other reps # TODO: other compare with creating plist-of-plist diff --git a/doc/ref/matobj.xml b/doc/ref/matobj.xml index c2eaf6717c..936676d4d4 100644 --- a/doc/ref/matobj.xml +++ b/doc/ref/matobj.xml @@ -374,7 +374,7 @@ described in this chapter is supported. <#Include Label="IsGF2MatrixRep"> <#Include Label="Is8BitMatrixRep"> <#Include Label="IsPlistMatrixRep"> -<#Include Label="IsFlatPlistMatrixRep"> +<#Include Label="IsGenericMatrixRep"> <#Include Label="IsZmodnZMatrixRep"> diff --git a/lib/matobjflatplist.gd b/lib/matobjflatplist.gd index b4b801dab3..a9707baebc 100644 --- a/lib/matobjflatplist.gd +++ b/lib/matobjflatplist.gd @@ -15,12 +15,12 @@ ############################################################################# ## -## <#GAPDoc Label="IsFlatPlistMatrixRep"> +## <#GAPDoc Label="IsGenericMatrixRep"> ## -## +## ## ## -## An object obj in describes +## An object obj in describes ## a matrix object (see ) whose entries are stored ## as a dense plain list of dense plain row lists. ##

@@ -31,7 +31,7 @@ ## ## <#/GAPDoc> ## -DeclareRepresentation( "IsFlatPlistMatrixRep", +DeclareRepresentation( "IsGenericMatrixRep", IsMatrixObj and IsPositionalObjectRep and IsCopyable and IsNoImmediateMethodsObject diff --git a/lib/matobjflatplist.gi b/lib/matobjflatplist.gi index bb502d0dde..bb5a16486d 100644 --- a/lib/matobjflatplist.gi +++ b/lib/matobjflatplist.gi @@ -31,19 +31,19 @@ BindGlobal( "InverseRowsForFlatPlistMatrix", return INV_MATRIX_MUTABLE( M![FROWSPOS] ); end ); -BindGlobal( "MakeIsFlatPlistMatrixRep", +BindGlobal( "MakeIsGenericMatrixRep", function( basedomain, ncols, list, check ) local fam, types, typ, row; fam := CollectionsFamily( FamilyObj( basedomain ) ); if not IsBound( fam!.FlatPlistMatrixRepTypes ) then fam!.FlatPlistMatrixRepTypes := [ - NewType( fam, IsFlatPlistMatrixRep ), - NewType( fam, IsFlatPlistMatrixRep and IsMutable ), + NewType( fam, IsGenericMatrixRep ), + NewType( fam, IsGenericMatrixRep and IsMutable ), ]; fam!.FlatPlistMatrixRepTypesEasyCompare := [ - NewType( fam, IsFlatPlistMatrixRep and CanEasilyCompareElements ), - NewType( fam, IsFlatPlistMatrixRep and CanEasilyCompareElements and IsMutable ), + NewType( fam, IsGenericMatrixRep and CanEasilyCompareElements ), + NewType( fam, IsGenericMatrixRep and CanEasilyCompareElements and IsMutable ), ]; fi; if HasCanEasilyCompareElements( Representative( basedomain ) ) and @@ -75,7 +75,7 @@ BindGlobal( "MakeIsFlatPlistMatrixRep", InstallTagBasedMethod( NewMatrix, - IsFlatPlistMatrixRep, + IsGenericMatrixRep, function( filter, basedomain, ncols, list ) local nd, rows, i, row; @@ -102,12 +102,12 @@ InstallTagBasedMethod( NewMatrix, if not IsMutable( list ) then MakeImmutable( rows ); fi; - return MakeIsFlatPlistMatrixRep( basedomain, ncols, rows, true ); + return MakeIsGenericMatrixRep( basedomain, ncols, rows, true ); end ); InstallTagBasedMethod( NewZeroMatrix, - IsFlatPlistMatrixRep, + IsGenericMatrixRep, function( filter, basedomain, rows, cols ) local list, row, i, z; list := EmptyPlist( rows ); @@ -116,43 +116,43 @@ InstallTagBasedMethod( NewZeroMatrix, row := ListWithIdenticalEntries( cols, z ); list[i] := row; od; - return MakeIsFlatPlistMatrixRep( basedomain, cols, list, false ); + return MakeIsGenericMatrixRep( basedomain, cols, list, false ); end ); InstallMethod( ConstructingFilter, - [ "IsFlatPlistMatrixRep" ], - M -> IsFlatPlistMatrixRep ); + [ "IsGenericMatrixRep" ], + M -> IsGenericMatrixRep ); InstallMethod( CompatibleVectorFilter, - [ "IsFlatPlistMatrixRep" ], + [ "IsGenericMatrixRep" ], M -> IsPlistVectorRep ); InstallMethod( BaseDomain, - [ "IsFlatPlistMatrixRep" ], + [ "IsGenericMatrixRep" ], M -> M![FBDPOS] ); InstallMethod( NumberRows, - [ "IsFlatPlistMatrixRep" ], + [ "IsGenericMatrixRep" ], M -> Length( M![FROWSPOS] ) ); InstallMethod( NumberColumns, - [ "IsFlatPlistMatrixRep" ], + [ "IsGenericMatrixRep" ], M -> M![FCOLSPOS] ); InstallMethod( \[\], - [ "IsFlatPlistMatrixRep", "IsPosInt" ], + [ "IsGenericMatrixRep", "IsPosInt" ], function( M, pos ) ErrorNoReturn( "row access unsupported; use M[i,j] or RowsOfMatrix(M)" ); end ); InstallMethod( MatElm, - [ "IsFlatPlistMatrixRep", "IsPosInt", "IsPosInt" ], + [ "IsGenericMatrixRep", "IsPosInt", "IsPosInt" ], { M, row, col } -> M![FROWSPOS][row,col] ); InstallMethod( SetMatElm, - [ "IsFlatPlistMatrixRep and IsMutable", "IsPosInt", "IsPosInt", "IsObject" ], + [ "IsGenericMatrixRep and IsMutable", "IsPosInt", "IsPosInt", "IsObject" ], function( M, row, col, ob ) if ValueOption( "check" ) <> false then if not ob in BaseDomain( M ) then @@ -168,29 +168,29 @@ InstallMethod( SetMatElm, InstallMethod( Unpack, - [ "IsFlatPlistMatrixRep" ], + [ "IsGenericMatrixRep" ], M -> List( M![FROWSPOS], ShallowCopy ) ); InstallMethod( ShallowCopy, - [ "IsFlatPlistMatrixRep" ], - M -> MakeIsFlatPlistMatrixRep( BaseDomain(M), NrCols(M), + [ "IsGenericMatrixRep" ], + M -> MakeIsGenericMatrixRep( BaseDomain(M), NrCols(M), List( M![FROWSPOS], ShallowCopy ), false ) ); InstallMethod( MutableCopyMatrix, - [ "IsFlatPlistMatrixRep" ], - M -> MakeIsFlatPlistMatrixRep( BaseDomain(M), NrCols(M), + [ "IsGenericMatrixRep" ], + M -> MakeIsGenericMatrixRep( BaseDomain(M), NrCols(M), List( M![FROWSPOS], ShallowCopy ), false ) ); InstallMethod( ExtractSubMatrix, - [ "IsFlatPlistMatrixRep", "IsList", "IsList" ], + [ "IsGenericMatrixRep", "IsList", "IsList" ], function( M, rowspos, colspos ) local list; list := M![FROWSPOS]{ rowspos }{ colspos }; - return MakeIsFlatPlistMatrixRep( BaseDomain(M), Length( colspos ), list, false ); + return MakeIsGenericMatrixRep( BaseDomain(M), Length( colspos ), list, false ); end ); InstallMethod( CopySubMatrix, - [ "IsFlatPlistMatrixRep", "IsFlatPlistMatrixRep and IsMutable", + [ "IsGenericMatrixRep", "IsGenericMatrixRep and IsMutable", "IsList", "IsList", "IsList", "IsList" ], function( M, N, srcrows, dstrows, srccols, dstcols ) if ValueOption( "check" ) <> false and @@ -201,15 +201,15 @@ InstallMethod( CopySubMatrix, end ); InstallMethod( TransposedMatMutable, - [ "IsFlatPlistMatrixRep" ], + [ "IsGenericMatrixRep" ], function( M ) local list; list := TransposedMatMutable(M![FROWSPOS]); - return MakeIsFlatPlistMatrixRep( BaseDomain(M), NrRows(M), list, false ); + return MakeIsGenericMatrixRep( BaseDomain(M), NrRows(M), list, false ); end ); InstallMethod( \+, - [ "IsFlatPlistMatrixRep", "IsFlatPlistMatrixRep" ], + [ "IsGenericMatrixRep", "IsGenericMatrixRep" ], function( a, b ) if ValueOption( "check" ) <> false and ( not IsIdenticalObj( BaseDomain( a ), BaseDomain( b ) ) or @@ -217,12 +217,12 @@ InstallMethod( \+, NrCols( a ) <> NrCols( b ) ) then Error( " and are not compatible" ); fi; - return MakeIsFlatPlistMatrixRep( BaseDomain( a ), NrCols( a ), + return MakeIsGenericMatrixRep( BaseDomain( a ), NrCols( a ), a![FROWSPOS] + b![FROWSPOS], false ); end ); InstallMethod( \-, - [ "IsFlatPlistMatrixRep", "IsFlatPlistMatrixRep" ], + [ "IsGenericMatrixRep", "IsGenericMatrixRep" ], function( a, b ) if ValueOption( "check" ) <> false and ( not IsIdenticalObj( BaseDomain( a ), BaseDomain( b ) ) or @@ -230,27 +230,27 @@ InstallMethod( \-, NrCols( a ) <> NrCols( b ) ) then Error( " and are not compatible" ); fi; - return MakeIsFlatPlistMatrixRep( BaseDomain( a ), NrCols( a ), + return MakeIsGenericMatrixRep( BaseDomain( a ), NrCols( a ), a![FROWSPOS] - b![FROWSPOS], false ); end ); InstallMethod( AdditiveInverseMutable, - [ "IsFlatPlistMatrixRep" ], - M -> MakeIsFlatPlistMatrixRep( BaseDomain( M ), NrCols( M ), + [ "IsGenericMatrixRep" ], + M -> MakeIsGenericMatrixRep( BaseDomain( M ), NrCols( M ), AdditiveInverseMutable( M![FROWSPOS] ), false ) ); InstallMethod( ZeroMutable, - [ "IsFlatPlistMatrixRep" ], + [ "IsGenericMatrixRep" ], function( M ) local z; - z := MakeIsFlatPlistMatrixRep( BaseDomain( M ), NrCols( M ), + z := MakeIsGenericMatrixRep( BaseDomain( M ), NrCols( M ), ZeroMutable( M![FROWSPOS] ), false ); SetIsZero( z, true ); return z; end ); InstallMethod( InverseMutable, - [ "IsFlatPlistMatrixRep" ], + [ "IsGenericMatrixRep" ], function( M ) local rows; @@ -258,11 +258,11 @@ InstallMethod( InverseMutable, if rows = fail then return fail; fi; - return MakeIsFlatPlistMatrixRep( BaseDomain( M ), NrCols( M ), rows, false ); + return MakeIsGenericMatrixRep( BaseDomain( M ), NrCols( M ), rows, false ); end ); InstallMethod( \*, - [ "IsFlatPlistMatrixRep", "IsFlatPlistMatrixRep" ], + [ "IsGenericMatrixRep", "IsGenericMatrixRep" ], function( a, b ) local rowsA, colsA, rowsB, colsB, bd, list, i; @@ -293,11 +293,11 @@ InstallMethod( \*, if not IsMutable( a ) and not IsMutable( b ) then MakeImmutable( list ); fi; - return MakeIsFlatPlistMatrixRep( bd, colsB, list, false ); + return MakeIsGenericMatrixRep( bd, colsB, list, false ); end ); InstallMethod( \*, - [ "IsFlatPlistMatrixRep", "IsVectorObj" ], + [ "IsGenericMatrixRep", "IsVectorObj" ], function( M, v ) local rows, cols, bd, res; @@ -331,7 +331,7 @@ InstallMethod( \*, end ); InstallMethod( \*, - [ "IsVectorObj", "IsFlatPlistMatrixRep" ], + [ "IsVectorObj", "IsGenericMatrixRep" ], function( v, M ) local rows, cols, bd, res; @@ -365,10 +365,10 @@ InstallMethod( \*, end ); InstallMethod( ChangedBaseDomain, - [ "IsFlatPlistMatrixRep", "IsRing" ], + [ "IsGenericMatrixRep", "IsRing" ], function( M, r ) local n; - n := NewMatrix( IsFlatPlistMatrixRep, r, NrCols(M), M![FROWSPOS] ); + n := NewMatrix( IsGenericMatrixRep, r, NrCols(M), M![FROWSPOS] ); if not IsMutable( M ) then MakeImmutable( n ); fi; @@ -377,62 +377,62 @@ InstallMethod( ChangedBaseDomain, InstallMethod( MultMatrixRowLeft, - [ "IsFlatPlistMatrixRep and IsMutable", "IsInt", "IsObject" ], + [ "IsGenericMatrixRep and IsMutable", "IsInt", "IsObject" ], function( mat, row, scalar ) MultMatrixRowLeft(mat![FROWSPOS], row, scalar); end ); InstallMethod( MultMatrixRowRight, - [ "IsFlatPlistMatrixRep and IsMutable", "IsInt", "IsObject" ], + [ "IsGenericMatrixRep and IsMutable", "IsInt", "IsObject" ], function( mat, row, scalar ) MultMatrixRowRight(mat![FROWSPOS], row, scalar); end ); InstallMethod( AddMatrixRowsLeft, - [ "IsFlatPlistMatrixRep and IsMutable", "IsInt", "IsInt", "IsObject" ], + [ "IsGenericMatrixRep and IsMutable", "IsInt", "IsInt", "IsObject" ], function( mat, row1, row2, scalar ) AddMatrixRowsLeft( mat![FROWSPOS], row1, row2, scalar ); end ); InstallMethod( AddMatrixRowsRight, - [ "IsFlatPlistMatrixRep and IsMutable", "IsInt", "IsInt", "IsObject" ], + [ "IsGenericMatrixRep and IsMutable", "IsInt", "IsInt", "IsObject" ], function( mat, row1, row2, scalar ) AddMatrixRowsRight( mat![FROWSPOS], row1, row2, scalar ); end ); InstallMethod( PositionNonZeroInRow, - [ "IsFlatPlistMatrixRep", "IsPosInt" ], + [ "IsGenericMatrixRep", "IsPosInt" ], function( mat, row ) return PositionNonZero( mat![FROWSPOS][row] ); end ); InstallMethod( PositionNonZeroInRow, - [ "IsFlatPlistMatrixRep", "IsPosInt", "IsInt" ], + [ "IsGenericMatrixRep", "IsPosInt", "IsInt" ], function( mat, row, from ) return PositionNonZero( mat![FROWSPOS][row], from ); end ); InstallMethod( SwapMatrixRows, - [ "IsFlatPlistMatrixRep and IsMutable", "IsInt", "IsInt" ], + [ "IsGenericMatrixRep and IsMutable", "IsInt", "IsInt" ], function( mat, row1, row2 ) SwapMatrixRows(mat![FROWSPOS], row1, row2); end ); InstallMethod( SwapMatrixColumns, - [ "IsFlatPlistMatrixRep and IsMutable", "IsInt", "IsInt" ], + [ "IsGenericMatrixRep and IsMutable", "IsInt", "IsInt" ], function( mat, col1, col2 ) SwapMatrixColumns(mat![FROWSPOS], col1, col2); end ); InstallMethod( PostMakeImmutable, - [ "IsFlatPlistMatrixRep" ], + [ "IsGenericMatrixRep" ], function( M ) MakeImmutable( M![FROWSPOS] ); end ); -InstallMethod( ViewObj, [ "IsFlatPlistMatrixRep" ], +InstallMethod( ViewObj, [ "IsGenericMatrixRep" ], function( M ) Print( "<" ); if not IsMutable( M ) then @@ -442,9 +442,9 @@ InstallMethod( ViewObj, [ "IsFlatPlistMatrixRep" ], "-matrix over ", BaseDomain(M), ">" ); end ); -InstallMethod( PrintObj, [ "IsFlatPlistMatrixRep" ], +InstallMethod( PrintObj, [ "IsGenericMatrixRep" ], function( M ) - Print( "NewMatrix(IsFlatPlistMatrixRep" ); + Print( "NewMatrix(IsGenericMatrixRep" ); if IsFinite( BaseDomain(M) ) and IsField( BaseDomain(M) ) then Print( ",GF(", Size( BaseDomain(M) ), ")," ); else @@ -453,7 +453,7 @@ InstallMethod( PrintObj, [ "IsFlatPlistMatrixRep" ], Print( NumberColumns( M ), ",", Unpack( M ), ")" ); end ); -InstallMethod( Display, [ "IsFlatPlistMatrixRep" ], +InstallMethod( Display, [ "IsGenericMatrixRep" ], function( M ) local i; Print( "<" ); @@ -473,10 +473,10 @@ InstallMethod( Display, [ "IsFlatPlistMatrixRep" ], Print( "]>\n" ); end ); -InstallMethod( String, [ "IsFlatPlistMatrixRep" ], +InstallMethod( String, [ "IsGenericMatrixRep" ], function( M ) local st; - st := "NewMatrix(IsFlatPlistMatrixRep"; + st := "NewMatrix(IsGenericMatrixRep"; Add( st, ',' ); if IsFinite( BaseDomain(M) ) and IsField( BaseDomain(M) ) then Append( st, "GF(" ); diff --git a/tst/testinstall/MatrixObj/CompanionMatrix.tst b/tst/testinstall/MatrixObj/CompanionMatrix.tst index 5821ec8281..a2b1330b57 100644 --- a/tst/testinstall/MatrixObj/CompanionMatrix.tst +++ b/tst/testinstall/MatrixObj/CompanionMatrix.tst @@ -68,19 +68,19 @@ gap> TestCompanionMatrix(IsPlistMatrixRep, x^2+x+1, F); <2x2-matrix over Rationals> # -# IsFlatPlistMatrixRep +# IsGenericMatrixRep # gap> F:= GF(251);; x:= X(F);; -gap> TestCompanionMatrix(IsFlatPlistMatrixRep, x+1, F); +gap> TestCompanionMatrix(IsGenericMatrixRep, x+1, F); <1x1-matrix over GF(251)> -gap> TestCompanionMatrix(IsFlatPlistMatrixRep, x^2+x+1, F); +gap> TestCompanionMatrix(IsGenericMatrixRep, x^2+x+1, F); <2x2-matrix over GF(251)> # gap> F:= Integers;; x:= X(F);; -gap> TestCompanionMatrix(IsFlatPlistMatrixRep, x+1, F); +gap> TestCompanionMatrix(IsGenericMatrixRep, x+1, F); <1x1-matrix over Integers> -gap> TestCompanionMatrix(IsFlatPlistMatrixRep, x^2+x+1, F); +gap> TestCompanionMatrix(IsGenericMatrixRep, x^2+x+1, F); <2x2-matrix over Integers> # diff --git a/tst/testinstall/MatrixObj/ElementaryMatrices.tst b/tst/testinstall/MatrixObj/ElementaryMatrices.tst index ae67b4dd8b..2204e66d9c 100644 --- a/tst/testinstall/MatrixObj/ElementaryMatrices.tst +++ b/tst/testinstall/MatrixObj/ElementaryMatrices.tst @@ -68,9 +68,9 @@ gap> TestElementaryTransforms( mat, -1 ); gap> TestWholeMatrixTransforms( mat, -1 ); # -gap> mat := NewMatrix(IsFlatPlistMatrixRep, Integers, 3, +gap> mat := NewMatrix(IsGenericMatrixRep, Integers, 3, > [ [ 2, 4, 5 ], [ 7, 11, -4 ], [ -3, 20, 0 ] ] );; -gap> IsFlatPlistMatrixRep(mat); +gap> IsGenericMatrixRep(mat); true gap> TestElementaryTransforms( mat, -1 ); gap> TestWholeMatrixTransforms( mat, -1 ); diff --git a/tst/testinstall/MatrixObj/IdentityMatrix.tst b/tst/testinstall/MatrixObj/IdentityMatrix.tst index c42e7191d0..74f429b3f2 100644 --- a/tst/testinstall/MatrixObj/IdentityMatrix.tst +++ b/tst/testinstall/MatrixObj/IdentityMatrix.tst @@ -74,21 +74,21 @@ gap> TestIdentityMatrix(IsPlistMatrixRep, Integers mod 4, -1); Error, IdentityMatrix: the dimension must be non-negative # -# IsFlatPlistMatrixRep +# IsGenericMatrixRep # -gap> TestIdentityMatrix(IsFlatPlistMatrixRep, GF(2), 2); +gap> TestIdentityMatrix(IsGenericMatrixRep, GF(2), 2); <2x2-matrix over GF(2)> -gap> TestIdentityMatrix(IsFlatPlistMatrixRep, GF(2), 0); +gap> TestIdentityMatrix(IsGenericMatrixRep, GF(2), 0); <0x0-matrix over GF(2)> -gap> TestIdentityMatrix(IsFlatPlistMatrixRep, GF(2), -1); +gap> TestIdentityMatrix(IsGenericMatrixRep, GF(2), -1); Error, IdentityMatrix: the dimension must be non-negative # -gap> TestIdentityMatrix(IsFlatPlistMatrixRep, Integers, 2); +gap> TestIdentityMatrix(IsGenericMatrixRep, Integers, 2); <2x2-matrix over Integers> -gap> TestIdentityMatrix(IsFlatPlistMatrixRep, Integers, 0); +gap> TestIdentityMatrix(IsGenericMatrixRep, Integers, 0); <0x0-matrix over Integers> -gap> TestIdentityMatrix(IsFlatPlistMatrixRep, Integers, -1); +gap> TestIdentityMatrix(IsGenericMatrixRep, Integers, -1); Error, IdentityMatrix: the dimension must be non-negative # diff --git a/tst/testinstall/MatrixObj/Matrix.tst b/tst/testinstall/MatrixObj/Matrix.tst index 15298ab499..bc07b33465 100644 --- a/tst/testinstall/MatrixObj/Matrix.tst +++ b/tst/testinstall/MatrixObj/Matrix.tst @@ -46,14 +46,14 @@ gap> m = Matrix( IsPlistMatrixRep, GF(2), [1,2,3,4] * Z(2), 2 ); true # -gap> m := Matrix( IsFlatPlistMatrixRep, GF(2), [[1,2],[3,4]] * Z(2) ); +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( IsFlatPlistMatrixRep, GF(2), [1,2,3,4] * Z(2), 2 ); +gap> m = Matrix( IsGenericMatrixRep, GF(2), [1,2,3,4] * Z(2), 2 ); true # diff --git a/tst/testinstall/MatrixObj/ZeroMatrix.tst b/tst/testinstall/MatrixObj/ZeroMatrix.tst index 8a5c86c4b9..a21962bfcf 100644 --- a/tst/testinstall/MatrixObj/ZeroMatrix.tst +++ b/tst/testinstall/MatrixObj/ZeroMatrix.tst @@ -80,21 +80,21 @@ gap> TestZeroMatrix(IsPlistMatrixRep, Integers mod 4, 0, 3); <0x3-matrix over (Integers mod 4)> # -# IsFlatPlistMatrixRep +# IsGenericMatrixRep # -gap> TestZeroMatrix(IsFlatPlistMatrixRep, GF(2), 2, 3); +gap> TestZeroMatrix(IsGenericMatrixRep, GF(2), 2, 3); <2x3-matrix over GF(2)> -gap> TestZeroMatrix(IsFlatPlistMatrixRep, GF(2), 2, 0); +gap> TestZeroMatrix(IsGenericMatrixRep, GF(2), 2, 0); <2x0-matrix over GF(2)> -gap> TestZeroMatrix(IsFlatPlistMatrixRep, GF(2), 0, 3); +gap> TestZeroMatrix(IsGenericMatrixRep, GF(2), 0, 3); <0x3-matrix over GF(2)> # -gap> TestZeroMatrix(IsFlatPlistMatrixRep, Integers, 2, 3); +gap> TestZeroMatrix(IsGenericMatrixRep, Integers, 2, 3); <2x3-matrix over Integers> -gap> TestZeroMatrix(IsFlatPlistMatrixRep, Integers, 2, 0); +gap> TestZeroMatrix(IsGenericMatrixRep, Integers, 2, 0); <2x0-matrix over Integers> -gap> TestZeroMatrix(IsFlatPlistMatrixRep, Integers, 0, 3); +gap> TestZeroMatrix(IsGenericMatrixRep, Integers, 0, 3); <0x3-matrix over Integers> # diff --git a/tst/testinstall/MatrixObj/matobjflatplist.tst b/tst/testinstall/MatrixObj/matobjflatplist.tst index 6454cd6d8b..19d24c17d6 100644 --- a/tst/testinstall/MatrixObj/matobjflatplist.tst +++ b/tst/testinstall/MatrixObj/matobjflatplist.tst @@ -14,33 +14,33 @@ gap> w:= MakeIsPlistVectorRep( Rationals, [ 1 ], true ); # -gap> MakeIsFlatPlistMatrixRep( Integers, 2, [ v ], true ); +gap> MakeIsGenericMatrixRep( Integers, 2, [ v ], true ); Error, the entries of must be plain lists -gap> M:= MakeIsFlatPlistMatrixRep( Integers, 2, [], true ); +gap> M:= MakeIsGenericMatrixRep( Integers, 2, [], true ); <0x2-matrix over Integers> -gap> MakeIsFlatPlistMatrixRep( Integers, 1, [ [ 1 ] ], true ); +gap> MakeIsGenericMatrixRep( Integers, 1, [ [ 1 ] ], true ); <1x1-matrix over Integers> -gap> MakeIsFlatPlistMatrixRep( Integers, 2, [ [ 1 ] ], true ); +gap> MakeIsGenericMatrixRep( Integers, 2, [ [ 1 ] ], true ); Error, the entries of must have length -gap> MakeIsFlatPlistMatrixRep( Integers, 1, [ [ 1/2 ] ], true ); +gap> MakeIsGenericMatrixRep( Integers, 1, [ [ 1/2 ] ], true ); Error, the elements in must lie in -gap> MakeIsFlatPlistMatrixRep( GF(2), 1, [ [ Z(2) ] ], true ); +gap> MakeIsGenericMatrixRep( GF(2), 1, [ [ Z(2) ] ], true ); <1x1-matrix over GF(2)> -gap> MakeIsFlatPlistMatrixRep( GF(2), 1, [ [ Z(4) ] ], true ); +gap> MakeIsGenericMatrixRep( GF(2), 1, [ [ Z(4) ] ], true ); Error, the elements in must lie in # -gap> NewMatrix( IsFlatPlistMatrixRep, Integers, 2, [] ); +gap> NewMatrix( IsGenericMatrixRep, Integers, 2, [] ); <0x2-matrix over Integers> -gap> NewMatrix( IsFlatPlistMatrixRep, Integers, 2, [ 1 ] ); +gap> NewMatrix( IsGenericMatrixRep, Integers, 2, [ 1 ] ); Error, NewMatrix: Length of is not a multiple of -gap> NewMatrix( IsFlatPlistMatrixRep, Integers, 2, [ [ 1 ] ] ); +gap> NewMatrix( IsGenericMatrixRep, Integers, 2, [ [ 1 ] ] ); Error, the entries of must have length -gap> NewMatrix( IsFlatPlistMatrixRep, Integers, 2, [ [ 1, 2 ] ] ); +gap> NewMatrix( IsGenericMatrixRep, Integers, 2, [ [ 1, 2 ] ] ); <1x2-matrix over Integers> -gap> NewMatrix( IsFlatPlistMatrixRep, Integers, 2, [ v ] ); +gap> NewMatrix( IsGenericMatrixRep, Integers, 2, [ v ] ); Error, the entries of must have length -gap> M:= NewMatrix( IsFlatPlistMatrixRep, Integers, 2, [ [ 1, 2 ], [ 3, 4 ] ] ); +gap> M:= NewMatrix( IsGenericMatrixRep, Integers, 2, [ [ 1, 2 ], [ 3, 4 ] ] ); <2x2-matrix over Integers> gap> IsMutable( M ); true @@ -69,7 +69,7 @@ gap> rows[1][1]; 1 # -gap> M:= NewMatrix( IsFlatPlistMatrixRep, Integers, 2, [ v2, v2 ] );; +gap> M:= NewMatrix( IsGenericMatrixRep, Integers, 2, [ v2, v2 ] );; gap> Unpack( M ); [ [ 1, 0 ], [ 1, 0 ] ] @@ -77,15 +77,15 @@ gap> Unpack( M ); # Empty matrices and empty vectors # # -gap> a:= NewZeroMatrix( IsFlatPlistMatrixRep, Integers, 2, 0 ); +gap> a:= NewZeroMatrix( IsGenericMatrixRep, Integers, 2, 0 ); <2x0-matrix over Integers> -gap> b:= NewZeroMatrix( IsFlatPlistMatrixRep, Integers, 0, 3 ); +gap> b:= NewZeroMatrix( IsGenericMatrixRep, Integers, 0, 3 ); <0x3-matrix over Integers> -gap> c:= NewZeroMatrix( IsFlatPlistMatrixRep, Integers, 0, 0 ); +gap> c:= NewZeroMatrix( IsGenericMatrixRep, Integers, 0, 0 ); <0x0-matrix over Integers> -gap> d:= NewZeroMatrix( IsFlatPlistMatrixRep, Integers, 0, 2 ); +gap> d:= NewZeroMatrix( IsGenericMatrixRep, Integers, 0, 2 ); <0x2-matrix over Integers> -gap> z:= NewZeroMatrix( IsFlatPlistMatrixRep, Integers, 2, 3 ); +gap> z:= NewZeroMatrix( IsGenericMatrixRep, Integers, 2, 3 ); <2x3-matrix over Integers> gap> IsMutable( z ); true @@ -93,18 +93,18 @@ gap> Unpack( z ); [ [ 0, 0, 0 ], [ 0, 0, 0 ] ] # -gap> M:= NewIdentityMatrix( IsFlatPlistMatrixRep, Integers, 2 );; +gap> M:= NewIdentityMatrix( IsGenericMatrixRep, Integers, 2 );; gap> Unpack( M ); [ [ 1, 0 ], [ 0, 1 ] ] # -gap> a = NewMatrix( IsFlatPlistMatrixRep, Integers, 0, [ [], [] ] ); +gap> a = NewMatrix( IsGenericMatrixRep, Integers, 0, [ [], [] ] ); true -gap> b = NewMatrix( IsFlatPlistMatrixRep, Integers, 3, [] ); +gap> b = NewMatrix( IsGenericMatrixRep, Integers, 3, [] ); true -gap> c = NewMatrix( IsFlatPlistMatrixRep, Integers, 0, [] ); +gap> c = NewMatrix( IsGenericMatrixRep, Integers, 0, [] ); true -gap> d = NewMatrix( IsFlatPlistMatrixRep, Integers, 2, [] ); +gap> d = NewMatrix( IsGenericMatrixRep, Integers, 2, [] ); true # @@ -160,7 +160,7 @@ gap> InverseSameMutability( c ); <0x0-matrix over Integers> # -gap> M:= NewMatrix( IsFlatPlistMatrixRep, Integers, 3, [ [ 0, 0, 2 ], [ 0, 0, 0 ] ] );; +gap> M:= NewMatrix( IsGenericMatrixRep, Integers, 3, [ [ 0, 0, 2 ], [ 0, 0, 0 ] ] );; gap> PositionNonZeroInRow( M, 1 ); 3 gap> PositionNonZeroInRow( M, 1, 2 ); @@ -169,7 +169,7 @@ gap> PositionNonZeroInRow( M, 2 ); 4 # -gap> M:= NewMatrix( IsFlatPlistMatrixRep, Integers, 3, +gap> M:= NewMatrix( IsGenericMatrixRep, Integers, 3, > [ [ 1, 2, 3 ], [ 4, 5, 6 ] ] );; gap> MultMatrixRowLeft( M, 1, -1 );; gap> Unpack( M ); diff --git a/tst/testinstall/MatrixObj/testmatobj.g b/tst/testinstall/MatrixObj/testmatobj.g index fdcc53588f..811f924485 100644 --- a/tst/testinstall/MatrixObj/testmatobj.g +++ b/tst/testinstall/MatrixObj/testmatobj.g @@ -211,8 +211,8 @@ TestWholeMatrixTransforms := function(mat, scalar) basedomain := BaseDomain(mat); if IsPlistMatrixRep(mat) then src := NewMatrix(IsPlistMatrixRep, basedomain, NrCols(mat), src); - elif IsFlatPlistMatrixRep(mat) then - src := NewMatrix(IsFlatPlistMatrixRep, basedomain, NrCols(mat), src); + elif IsGenericMatrixRep(mat) then + src := NewMatrix(IsGenericMatrixRep, basedomain, NrCols(mat), src); elif Is8BitMatrixRep(mat) then ConvertToMatrixRep(src, basedomain); fi; From ce80685dc8ce61a85e90b58cfe6b5968c8fa40f1 Mon Sep 17 00:00:00 2001 From: Max Horn Date: Thu, 16 Apr 2026 16:21:27 +0200 Subject: [PATCH 08/23] Rename files matobjflatplist -> matobjgeneric --- doc/ref/makedocreldata.g | 2 +- lib/{matobjflatplist.gd => matobjgeneric.gd} | 0 lib/{matobjflatplist.gi => matobjgeneric.gi} | 0 lib/read3.g | 2 +- lib/read5.g | 2 +- .../MatrixObj/{matobjflatplist.tst => matobjgeneric.tst} | 4 ++-- 6 files changed, 5 insertions(+), 5 deletions(-) rename lib/{matobjflatplist.gd => matobjgeneric.gd} (100%) rename lib/{matobjflatplist.gi => matobjgeneric.gi} (100%) rename tst/testinstall/MatrixObj/{matobjflatplist.tst => matobjgeneric.tst} (98%) diff --git a/doc/ref/makedocreldata.g b/doc/ref/makedocreldata.g index c31333eca0..22993e3497 100644 --- a/doc/ref/makedocreldata.g +++ b/doc/ref/makedocreldata.g @@ -119,7 +119,7 @@ GAPInfo.ManualDataRef:= rec( "../../lib/matobj2.gd", "../../lib/matobjnz.gd", "../../lib/matobjplist.gd", - "../../lib/matobjflatplist.gd", + "../../lib/matobjgeneric.gd", "../../lib/matrix.gd", "../../lib/meataxe.gi", "../../lib/memory.gd", diff --git a/lib/matobjflatplist.gd b/lib/matobjgeneric.gd similarity index 100% rename from lib/matobjflatplist.gd rename to lib/matobjgeneric.gd diff --git a/lib/matobjflatplist.gi b/lib/matobjgeneric.gi similarity index 100% rename from lib/matobjflatplist.gi rename to lib/matobjgeneric.gi diff --git a/lib/read3.g b/lib/read3.g index 7d345ae67e..b3fdbbc96a 100644 --- a/lib/read3.g +++ b/lib/read3.g @@ -107,7 +107,7 @@ ReadLib( "wordass.gd" ); ReadLib( "matobj2.gd" ); ReadLib( "matobjplist.gd" ); -ReadLib( "matobjflatplist.gd" ); +ReadLib( "matobjgeneric.gd" ); ReadLib( "matobjnz.gd" ); # files dealing with rewriting systems diff --git a/lib/read5.g b/lib/read5.g index 94a4132f8b..cb4a8365b1 100644 --- a/lib/read5.g +++ b/lib/read5.g @@ -114,7 +114,7 @@ ReadLib( "vecmat.gi" ); ReadLib( "vec8bit.gi" ); ReadLib( "mat8bit.gi" ); ReadLib( "matobjplist.gi" ); -ReadLib( "matobjflatplist.gi" ); +ReadLib( "matobjgeneric.gi" ); ReadLib( "matobjnz.gi" ); ReadLib( "meataxe.gi" ); ReadLib( "meatauto.gi" ); diff --git a/tst/testinstall/MatrixObj/matobjflatplist.tst b/tst/testinstall/MatrixObj/matobjgeneric.tst similarity index 98% rename from tst/testinstall/MatrixObj/matobjflatplist.tst rename to tst/testinstall/MatrixObj/matobjgeneric.tst index 19d24c17d6..7a79bf0146 100644 --- a/tst/testinstall/MatrixObj/matobjflatplist.tst +++ b/tst/testinstall/MatrixObj/matobjgeneric.tst @@ -1,5 +1,5 @@ #@local e, v, v2, w, M, z, rows, a, b, c, d, p, ev, n, ai, inv, zm, zs -gap> START_TEST( "matobjflatplist.tst" ); +gap> START_TEST( "matobjgeneric.tst" ); # # MakeIsPlistVectorRep: test input validation @@ -188,4 +188,4 @@ gap> Unpack( M ); [ [ 54, 66, 78 ], [ 23, 28, 33 ] ] # -gap> STOP_TEST( "matobjflatplist.tst" ); +gap> STOP_TEST( "matobjgeneric.tst" ); From d3850eac93d19a30d830ac5a5b93dfb9377af037 Mon Sep 17 00:00:00 2001 From: Max Horn Date: Fri, 17 Apr 2026 15:24:08 +0200 Subject: [PATCH 09/23] Inline InverseRowsForFlatPlistMatrix --- lib/matobjgeneric.gi | 32 ++++++++++---------------------- 1 file changed, 10 insertions(+), 22 deletions(-) diff --git a/lib/matobjgeneric.gi b/lib/matobjgeneric.gi index bb5a16486d..a7dddd1d03 100644 --- a/lib/matobjgeneric.gi +++ b/lib/matobjgeneric.gi @@ -13,24 +13,6 @@ # Dense matrix objects backed by plain lists of plain row lists. # -BindGlobal( "InverseRowsForFlatPlistMatrix", - function( M ) - local bd, rows; - - if NrRows( M ) <> NrCols( M ) then - return fail; - elif NrRows( M ) = 0 then - rows := []; - return rows; - fi; - - bd := BaseDomain( M ); - if IsFinite( bd ) and IsField( bd ) then - return INV_MAT_DEFAULT_MUTABLE( M![FROWSPOS] ); - fi; - return INV_MATRIX_MUTABLE( M![FROWSPOS] ); - end ); - BindGlobal( "MakeIsGenericMatrixRep", function( basedomain, ncols, list, check ) local fam, types, typ, row; @@ -252,13 +234,19 @@ InstallMethod( ZeroMutable, InstallMethod( InverseMutable, [ "IsGenericMatrixRep" ], function( M ) - local rows; + local bd, rows; - rows := InverseRowsForFlatPlistMatrix( M ); - if rows = fail then + bd := BaseDomain( M ); + if NrRows( M ) <> NrCols( M ) then return fail; + 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( BaseDomain( M ), NrCols( M ), rows, false ); + return MakeIsGenericMatrixRep( bd, NrCols( M ), rows, false ); end ); InstallMethod( \*, From ec8d4ea772249b2fee825b76309ff96dc8d9df12 Mon Sep 17 00:00:00 2001 From: Max Horn Date: Fri, 17 Apr 2026 15:33:03 +0200 Subject: [PATCH 10/23] MakeIsGenericMatrixRep requires plist --- lib/matobjgeneric.gi | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/matobjgeneric.gi b/lib/matobjgeneric.gi index a7dddd1d03..5ec6f8f2a6 100644 --- a/lib/matobjgeneric.gi +++ b/lib/matobjgeneric.gi @@ -41,6 +41,9 @@ BindGlobal( "MakeIsGenericMatrixRep", fi; if check and ValueOption( "check" ) <> false then + if not IsPlistRep( list ) then + Error( " must be a plain list" ); + fi; for row in list do if not IsPlistRep( row ) then Error( "the entries of must be plain lists" ); From 779cd77a510ecb3dcb309c4e70dcb7d6f5359380 Mon Sep 17 00:00:00 2001 From: Max Horn Date: Fri, 17 Apr 2026 15:49:08 +0200 Subject: [PATCH 11/23] Tighten MakeIsGenericMatrixRep --- lib/matobjgeneric.gi | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/lib/matobjgeneric.gi b/lib/matobjgeneric.gi index 5ec6f8f2a6..ab276f37a9 100644 --- a/lib/matobjgeneric.gi +++ b/lib/matobjgeneric.gi @@ -19,21 +19,20 @@ BindGlobal( "MakeIsGenericMatrixRep", fam := CollectionsFamily( FamilyObj( basedomain ) ); if not IsBound( fam!.FlatPlistMatrixRepTypes ) then - fam!.FlatPlistMatrixRepTypes := [ - NewType( fam, IsGenericMatrixRep ), - NewType( fam, IsGenericMatrixRep and IsMutable ), - ]; - fam!.FlatPlistMatrixRepTypesEasyCompare := [ - NewType( fam, IsGenericMatrixRep and CanEasilyCompareElements ), - NewType( fam, IsGenericMatrixRep and CanEasilyCompareElements and IsMutable ), - ]; - fi; - if HasCanEasilyCompareElements( Representative( basedomain ) ) and - CanEasilyCompareElements( Representative( basedomain ) ) then - types := fam!.FlatPlistMatrixRepTypesEasyCompare; - else - types := fam!.FlatPlistMatrixRepTypes; + if HasCanEasilyCompareElements( Representative( basedomain ) ) and + CanEasilyCompareElements( Representative( basedomain ) ) then + fam!.FlatPlistMatrixRepTypes := [ + NewType( fam, IsGenericMatrixRep and CanEasilyCompareElements ), + NewType( fam, IsGenericMatrixRep and CanEasilyCompareElements and IsMutable ), + ]; + else + fam!.FlatPlistMatrixRepTypes := [ + NewType( fam, IsGenericMatrixRep ), + NewType( fam, IsGenericMatrixRep and IsMutable ), + ]; + fi; fi; + types := fam!.FlatPlistMatrixRepTypes; if IsMutable( list ) then typ := types[2]; else From 9b59c1a1253fbe22d5bec517f89f0caad3ab8590 Mon Sep 17 00:00:00 2001 From: Max Horn Date: Fri, 17 Apr 2026 17:46:01 +0200 Subject: [PATCH 12/23] Inverse should error, not return fail --- lib/matobjgeneric.gi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/matobjgeneric.gi b/lib/matobjgeneric.gi index ab276f37a9..5d8ef4b80f 100644 --- a/lib/matobjgeneric.gi +++ b/lib/matobjgeneric.gi @@ -240,7 +240,7 @@ InstallMethod( InverseMutable, bd := BaseDomain( M ); if NrRows( M ) <> NrCols( M ) then - return fail; + ErrorNoReturn( "InverseMutable: matrix must be square" ); elif NrRows( M ) = 0 then rows := []; elif IsFinite( bd ) and IsField( bd ) then From 9021a26d42808267a20d0f45dbcf4210f995915a Mon Sep 17 00:00:00 2001 From: Max Horn Date: Fri, 17 Apr 2026 17:45:50 +0200 Subject: [PATCH 13/23] Generalize vec*mat and mat*vec --- lib/matobjgeneric.gi | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/lib/matobjgeneric.gi b/lib/matobjgeneric.gi index 5d8ef4b80f..f28e7a0eb5 100644 --- a/lib/matobjgeneric.gi +++ b/lib/matobjgeneric.gi @@ -286,8 +286,9 @@ InstallMethod( \*, return MakeIsGenericMatrixRep( bd, colsB, list, false ); end ); -InstallMethod( \*, - [ "IsGenericMatrixRep", "IsVectorObj" ], +InstallOtherMethod( \*, + [ "IsGenericMatrixRep", "IsRowVectorOrVectorObj" ], + {} -> RankFilter(IsPlistVectorRep), # rank above method for [IsScalar, IsPlistVectorRep] function( M, v ) local rows, cols, bd, res; @@ -320,8 +321,9 @@ InstallMethod( \*, return Vector( res, v ); end ); -InstallMethod( \*, - [ "IsVectorObj", "IsGenericMatrixRep" ], +InstallOtherMethod( \*, + [ "IsRowVectorOrVectorObj", "IsGenericMatrixRep" ], + {} -> RankFilter(IsPlistVectorRep), # rank above method for [IsPlistVectorRep, IsScalar] function( v, M ) local rows, cols, bd, res; From 3b20fa9a8e6e0228e36a927dcc717d1a3ee51fa3 Mon Sep 17 00:00:00 2001 From: Max Horn Date: Fri, 17 Apr 2026 17:45:50 +0200 Subject: [PATCH 14/23] More tests --- tst/testinstall/MatrixObj/matobjgeneric.tst | 125 ++++++++++++++++++-- 1 file changed, 116 insertions(+), 9 deletions(-) diff --git a/tst/testinstall/MatrixObj/matobjgeneric.tst b/tst/testinstall/MatrixObj/matobjgeneric.tst index 7a79bf0146..2e2924f7a5 100644 --- a/tst/testinstall/MatrixObj/matobjgeneric.tst +++ b/tst/testinstall/MatrixObj/matobjgeneric.tst @@ -1,4 +1,4 @@ -#@local e, v, v2, w, M, z, rows, a, b, c, d, p, ev, n, ai, inv, zm, zs +#@local e, v, v2, w, M, z, rows, a, b, c, d, p, ev, n, ai, inv, zm, zs, N, T, lp, lp0, s gap> START_TEST( "matobjgeneric.tst" ); # @@ -77,15 +77,15 @@ gap> Unpack( M ); # Empty matrices and empty vectors # # -gap> a:= NewZeroMatrix( IsGenericMatrixRep, Integers, 2, 0 ); +gap> a:= ZeroMatrix( IsGenericMatrixRep, Integers, 2, 0 ); <2x0-matrix over Integers> -gap> b:= NewZeroMatrix( IsGenericMatrixRep, Integers, 0, 3 ); +gap> b:= ZeroMatrix( IsGenericMatrixRep, Integers, 0, 3 ); <0x3-matrix over Integers> -gap> c:= NewZeroMatrix( IsGenericMatrixRep, Integers, 0, 0 ); +gap> c:= ZeroMatrix( IsGenericMatrixRep, Integers, 0, 0 ); <0x0-matrix over Integers> -gap> d:= NewZeroMatrix( IsGenericMatrixRep, Integers, 0, 2 ); +gap> d:= ZeroMatrix( IsGenericMatrixRep, Integers, 0, 2 ); <0x2-matrix over Integers> -gap> z:= NewZeroMatrix( IsGenericMatrixRep, Integers, 2, 3 ); +gap> z:= ZeroMatrix( IsGenericMatrixRep, Integers, 2, 3 ); <2x3-matrix over Integers> gap> IsMutable( z ); true @@ -160,7 +160,7 @@ gap> InverseSameMutability( c ); <0x0-matrix over Integers> # -gap> M:= NewMatrix( IsGenericMatrixRep, Integers, 3, [ [ 0, 0, 2 ], [ 0, 0, 0 ] ] );; +gap> M:= Matrix( IsGenericMatrixRep, Integers, [ [ 0, 0, 2 ], [ 0, 0, 0 ] ] );; gap> PositionNonZeroInRow( M, 1 ); 3 gap> PositionNonZeroInRow( M, 1, 2 ); @@ -169,8 +169,7 @@ gap> PositionNonZeroInRow( M, 2 ); 4 # -gap> M:= NewMatrix( IsGenericMatrixRep, Integers, 3, -> [ [ 1, 2, 3 ], [ 4, 5, 6 ] ] );; +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 ] ] @@ -187,5 +186,113 @@ 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> Display( InverseMutable( M ) ); +<2x2-matrix over GF(2): +[[ 0*Z(2), Z(2)^0 ] + [ Z(2)^0, Z(2)^0 ] +]> +gap> M:= Matrix( IsGenericMatrixRep, Rationals, [ [ 1, 2 ], [ 3, 5 ] ] );; +gap> Display( InverseMutable( M ) ); +<2x2-matrix over Rationals: +[[ -5, 2 ] + [ 3, -1 ] +]> + +# +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 + +# +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 ] ] +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 +gap> Unpack( TransposedMatMutable( M ) ); +[ [ 1, 3 ], [ 2, 4 ] ] +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 +gap> String( Matrix( IsGenericMatrixRep, GF(2), [ [ Z(2)^0, 0*Z(2) ] ] ) ); +"NewMatrix(IsGenericMatrixRep,GF(2),2,[ [ Z(2)^0, 0*Z(2) ] ])" +gap> Print( Matrix( IsGenericMatrixRep, Integers, [ [ 1, 2 ], [ 3, 4 ] ] ), "\n" ); +NewMatrix(IsGenericMatrixRep,Integers,2,[ [ 1, 2 ], [ 3, 4 ] ]) + +# +gap> M:= Matrix( IsGenericMatrixRep, Integers, [ [ 1, 2 ], [ 3, 4 ] ] );; +gap> v:= NewVector( IsPlistVectorRep, Integers, [ 1, 2 ] );; +gap> Unpack( M * v ); +[ 5, 11 ] +gap> Unpack( v * M ); +[ 7, 10 ] +gap> lp:= [ 1, 2 ];; +gap> M * lp; +[ 5, 11 ] +gap> lp * M; +[ 7, 10 ] +gap> a:= ZeroMatrix( IsGenericMatrixRep, Integers, 2, 0 );; +gap> b:= ZeroMatrix( IsGenericMatrixRep, Integers, 0, 3 );; + +# 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 * []; +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 + # gap> STOP_TEST( "matobjgeneric.tst" ); From 8a2fe0cc5f68e1067282f7194520a005ffe26494 Mon Sep 17 00:00:00 2001 From: Max Horn Date: Fri, 17 Apr 2026 20:42:40 +0200 Subject: [PATCH 15/23] Unify matobj family code --- lib/matobjgeneric.gi | 16 +++++++++------- lib/matobjnz.gi | 2 +- lib/matobjplist.gi | 35 ++++++++++++++++------------------- 3 files changed, 26 insertions(+), 27 deletions(-) diff --git a/lib/matobjgeneric.gi b/lib/matobjgeneric.gi index f28e7a0eb5..ba9590400e 100644 --- a/lib/matobjgeneric.gi +++ b/lib/matobjgeneric.gi @@ -15,12 +15,15 @@ BindGlobal( "MakeIsGenericMatrixRep", function( basedomain, ncols, list, check ) - local fam, types, typ, row; + local fam, typ, row; + fam := CollectionsFamily( 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!.FlatPlistMatrixRepTypes ) then - if HasCanEasilyCompareElements( Representative( basedomain ) ) and - CanEasilyCompareElements( Representative( basedomain ) ) then + # initialize type cache + # TODO: make this thread safe for HPC-GAP + if CanEasilyCompareElementsFamily( fam ) then fam!.FlatPlistMatrixRepTypes := [ NewType( fam, IsGenericMatrixRep and CanEasilyCompareElements ), NewType( fam, IsGenericMatrixRep and CanEasilyCompareElements and IsMutable ), @@ -32,11 +35,10 @@ BindGlobal( "MakeIsGenericMatrixRep", ]; fi; fi; - types := fam!.FlatPlistMatrixRepTypes; if IsMutable( list ) then - typ := types[2]; + typ := fam!.FlatPlistMatrixRepTypes[2]; else - typ := types[1]; + typ := fam!.FlatPlistMatrixRepTypes[1]; fi; if check and ValueOption( "check" ) <> false then diff --git a/lib/matobjnz.gi b/lib/matobjnz.gi index 60fcadff4b..3bebd82b8d 100644 --- a/lib/matobjnz.gi +++ b/lib/matobjnz.gi @@ -669,7 +669,7 @@ InstallTagBasedMethod( NewZeroMatrix, m[i] := ZeroVector( cols, e ); od; m := [basedomain,e,cols,m]; - Objectify( NewType(CollectionsFamily(FamilyObj(basedomain)), + Objectify( NewType(CollectionsFamily(ElementsFamily(FamilyObj(basedomain))), filter and IsMutable), m ); return m; end ); diff --git a/lib/matobjplist.gi b/lib/matobjplist.gi index 7a1b99f4d4..ba6a5e2352 100644 --- a/lib/matobjplist.gi +++ b/lib/matobjplist.gi @@ -121,32 +121,29 @@ BindGlobal( "MakeIsPlistVectorRep", BindGlobal( "MakeIsPlistMatrixRep", function( basedomain, emptyvector, ncols, list, check ) local fam, types, typ, row; - fam:= CollectionsFamily( FamilyObj( basedomain ) ); + fam:= CollectionsFamily( ElementsFamily( 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 ), - ]; - fi; - if HasCanEasilyCompareElements( Representative( basedomain ) ) and - CanEasilyCompareElements( Representative( basedomain ) ) then - types:= fam!.PlistMatrixRepTypesEasyCompare; - else - types:= fam!.PlistMatrixRepTypes; + if CanEasilyCompareElementsFamily( fam ) then + fam!.PlistMatrixRepTypes:= [ + NewType( fam, IsPlistMatrixRep and CanEasilyCompareElements ), + NewType( fam, IsPlistMatrixRep and CanEasilyCompareElements and IsMutable ), + ]; + else + fam!.PlistMatrixRepTypes:= [ + NewType( fam, IsPlistMatrixRep ), + NewType( fam, IsPlistMatrixRep and IsMutable ), + ]; + fi; 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 +155,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; From 33779c5748dc73f68d0bfd11945fbf593cfa9bba Mon Sep 17 00:00:00 2001 From: Max Horn Date: Fri, 17 Apr 2026 21:01:56 +0200 Subject: [PATCH 16/23] More tests --- tst/testinstall/MatrixObj/matobjgeneric.tst | 106 ++++++++++++++++++-- 1 file changed, 96 insertions(+), 10 deletions(-) diff --git a/tst/testinstall/MatrixObj/matobjgeneric.tst b/tst/testinstall/MatrixObj/matobjgeneric.tst index 2e2924f7a5..7ed965513e 100644 --- a/tst/testinstall/MatrixObj/matobjgeneric.tst +++ b/tst/testinstall/MatrixObj/matobjgeneric.tst @@ -193,11 +193,24 @@ 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> Display( InverseMutable( M ) ); +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> IsMutable( M * N ); +true +gap> MakeImmutable(M);; +gap> IsMutable( M * N ); +true +gap> MakeImmutable(N);; +gap> IsMutable( M * N ); +false gap> M:= Matrix( IsGenericMatrixRep, Rationals, [ [ 1, 2 ], [ 3, 5 ] ] );; gap> Display( InverseMutable( M ) ); <2x2-matrix over Rationals: @@ -228,6 +241,8 @@ 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 );; @@ -242,6 +257,10 @@ 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 );; @@ -251,8 +270,16 @@ gap> Unpack( T ); 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 @@ -264,29 +291,88 @@ gap> MakeImmutable( M );; gap> N:= ChangedBaseDomain( M, Rationals );; gap> IsMutable( N ); false -gap> String( Matrix( IsGenericMatrixRep, GF(2), [ [ Z(2)^0, 0*Z(2) ] ] ) ); + +# +# 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> Print( Matrix( IsGenericMatrixRep, Integers, [ [ 1, 2 ], [ 3, 4 ] ] ), "\n" ); + +# +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:= NewVector( IsPlistVectorRep, Integers, [ 1, 2 ] );; -gap> Unpack( M * v ); +gap> Display( M * v ); + Unpack( v * M ); +> +gap> Display( v * M ); + lp:= [ 1, 2 ];; -gap> M * lp; +> +gap> M * [ 1, 2 ]; [ 5, 11 ] -gap> lp * M; +gap> [ 1, 2 ] * M; [ 7, 10 ] -gap> a:= ZeroMatrix( IsGenericMatrixRep, Integers, 2, 0 );; -gap> b:= ZeroMatrix( IsGenericMatrixRep, Integers, 0, 3 );; + +# error handling +gap> M * [ 1, 2, 3 ]; +Error, and are not compatible +gap> [ 1, 2, 3 ] * 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 From 0cac33b26513a9fabc20eb3fa51e1b4833d4c710 Mon Sep 17 00:00:00 2001 From: Max Horn Date: Fri, 17 Apr 2026 21:08:18 +0200 Subject: [PATCH 17/23] Simplify code --- lib/matobjgeneric.gi | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/lib/matobjgeneric.gi b/lib/matobjgeneric.gi index ba9590400e..0ba4bb3de6 100644 --- a/lib/matobjgeneric.gi +++ b/lib/matobjgeneric.gi @@ -282,9 +282,6 @@ InstallMethod( \*, else list := a![FROWSPOS] * b![FROWSPOS]; fi; - if not IsMutable( a ) and not IsMutable( b ) then - MakeImmutable( list ); - fi; return MakeIsGenericMatrixRep( bd, colsB, list, false ); end ); @@ -361,12 +358,7 @@ InstallOtherMethod( \*, InstallMethod( ChangedBaseDomain, [ "IsGenericMatrixRep", "IsRing" ], function( M, r ) - local n; - n := NewMatrix( IsGenericMatrixRep, r, NrCols(M), M![FROWSPOS] ); - if not IsMutable( M ) then - MakeImmutable( n ); - fi; - return n; + return NewMatrix( IsGenericMatrixRep, r, NrCols(M), M![FROWSPOS] ); end ); From 7f2e2a4a101b9363e449294a85bc1356975b5cbc Mon Sep 17 00:00:00 2001 From: Max Horn Date: Fri, 17 Apr 2026 21:27:12 +0200 Subject: [PATCH 18/23] Yet more filter/family code simplification --- lib/matobjgeneric.gi | 22 ++-- lib/matobjplist.gi | 107 +++++++++----------- tst/testinstall/MatrixObj/matobjgeneric.tst | 65 ++++++++++-- tst/testinstall/MatrixObj/matobjplist.tst | 74 ++++++++++++-- 4 files changed, 179 insertions(+), 89 deletions(-) diff --git a/lib/matobjgeneric.gi b/lib/matobjgeneric.gi index 0ba4bb3de6..794b723572 100644 --- a/lib/matobjgeneric.gi +++ b/lib/matobjgeneric.gi @@ -15,25 +15,23 @@ BindGlobal( "MakeIsGenericMatrixRep", function( basedomain, ncols, list, check ) - local fam, typ, row; - fam := CollectionsFamily( ElementsFamily( 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!.FlatPlistMatrixRepTypes ) then # initialize type cache # TODO: make this thread safe for HPC-GAP - if CanEasilyCompareElementsFamily( fam ) then - fam!.FlatPlistMatrixRepTypes := [ - NewType( fam, IsGenericMatrixRep and CanEasilyCompareElements ), - NewType( fam, IsGenericMatrixRep and CanEasilyCompareElements and IsMutable ), - ]; - else - fam!.FlatPlistMatrixRepTypes := [ - NewType( fam, IsGenericMatrixRep ), - NewType( fam, IsGenericMatrixRep and IsMutable ), - ]; + filter := IsGenericMatrixRep; + if CanEasilyCompareElementsFamily( efam ) then + filter := filter and CanEasilyCompareElements; fi; + fam!.FlatPlistMatrixRepTypes := [ + NewType( fam, filter ), + NewType( fam, filter and IsMutable ), + ]; fi; if IsMutable( list ) then typ := fam!.FlatPlistMatrixRepTypes[2]; diff --git a/lib/matobjplist.gi b/lib/matobjplist.gi index ba6a5e2352..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,30 +108,29 @@ BindGlobal( "MakeIsPlistVectorRep", ## BindGlobal( "MakeIsPlistMatrixRep", function( basedomain, emptyvector, ncols, list, check ) - local fam, types, typ, row; - fam:= CollectionsFamily( ElementsFamily( 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 - if CanEasilyCompareElementsFamily( fam ) then - fam!.PlistMatrixRepTypes:= [ - NewType( fam, IsPlistMatrixRep and CanEasilyCompareElements ), - NewType( fam, IsPlistMatrixRep and CanEasilyCompareElements and IsMutable ), - ]; - else - fam!.PlistMatrixRepTypes:= [ - NewType( fam, IsPlistMatrixRep ), - NewType( fam, IsPlistMatrixRep 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 IsMutable( list ) then - typ:= fam!.PlistMatrixRepTypes[2]; + typ := fam!.PlistMatrixRepTypes[2]; else - typ:= fam!.PlistMatrixRepTypes[1]; + typ := fam!.PlistMatrixRepTypes[1]; fi; if check and ValueOption( "check" ) <> false then diff --git a/tst/testinstall/MatrixObj/matobjgeneric.tst b/tst/testinstall/MatrixObj/matobjgeneric.tst index 7ed965513e..dcdef45c8f 100644 --- a/tst/testinstall/MatrixObj/matobjgeneric.tst +++ b/tst/testinstall/MatrixObj/matobjgeneric.tst @@ -203,20 +203,49 @@ 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> MakeImmutable(N);; +gap> IsMutable( M + N ); +true +gap> IsMutable( M - N ); +true +gap> N:= InverseSameMutability( M );; +gap> IsMutable(N); +false gap> IsMutable( M * N ); false -gap> M:= Matrix( IsGenericMatrixRep, Rationals, [ [ 1, 2 ], [ 3, 5 ] ] );; -gap> Display( InverseMutable( M ) ); -<2x2-matrix over Rationals: -[[ -5, 2 ] - [ 3, -1 ] -]> +gap> IsMutable( M + N ); +false +gap> IsMutable( M - N ); +false +gap> IsMutable( -M ); +false # gap> M:= Matrix( IsGenericMatrixRep, Integers, [ [ 1, 2 ], [ 3, 4 ] ] );; @@ -380,5 +409,27 @@ 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" ); From f246b18fef4ee7514484efb24488c327a54d8421 Mon Sep 17 00:00:00 2001 From: Max Horn Date: Fri, 17 Apr 2026 22:38:28 +0200 Subject: [PATCH 19/23] more test coverage --- lib/matobjgeneric.gi | 4 +--- tst/testinstall/MatrixObj/matobjgeneric.tst | 23 ++++++++++++++++++++- 2 files changed, 23 insertions(+), 4 deletions(-) diff --git a/lib/matobjgeneric.gi b/lib/matobjgeneric.gi index 794b723572..aafcc3649c 100644 --- a/lib/matobjgeneric.gi +++ b/lib/matobjgeneric.gi @@ -40,9 +40,7 @@ BindGlobal( "MakeIsGenericMatrixRep", fi; if check and ValueOption( "check" ) <> false then - if not IsPlistRep( list ) then - Error( " must be a plain list" ); - fi; + Assert( 0, IsPlistRep( list ) ); for row in list do if not IsPlistRep( row ) then Error( "the entries of must be plain lists" ); diff --git a/tst/testinstall/MatrixObj/matobjgeneric.tst b/tst/testinstall/MatrixObj/matobjgeneric.tst index dcdef45c8f..f6d3e86c11 100644 --- a/tst/testinstall/MatrixObj/matobjgeneric.tst +++ b/tst/testinstall/MatrixObj/matobjgeneric.tst @@ -377,7 +377,8 @@ gap> String(M); # vec * mat, mat * vec # gap> M:= Matrix( IsGenericMatrixRep, Integers, [ [ 1, 2 ], [ 3, 4 ] ] );; -gap> v:= NewVector( IsPlistVectorRep, Integers, [ 1, 2 ] );; +gap> v:= Vector( Integers, [ 1, 2 ] ); + gap> Display( M * v ); 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 From a7ea30951f9dab8c828ceb608a97422dede45ea8 Mon Sep 17 00:00:00 2001 From: Max Horn Date: Fri, 17 Apr 2026 22:55:11 +0200 Subject: [PATCH 20/23] oops --- tst/testinstall/MatrixObj/matobjgeneric.tst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tst/testinstall/MatrixObj/matobjgeneric.tst b/tst/testinstall/MatrixObj/matobjgeneric.tst index f6d3e86c11..5f9b3c5a0e 100644 --- a/tst/testinstall/MatrixObj/matobjgeneric.tst +++ b/tst/testinstall/MatrixObj/matobjgeneric.tst @@ -1,4 +1,4 @@ -#@local e, v, v2, w, M, z, rows, a, b, c, d, p, ev, n, ai, inv, zm, zs, N, T, lp, lp0, s +#@local e, v, v2, w, M, z, rows, a, b, c, d, p, ev, n, ai, inv, zm, zs, N, T, lp, lp0, s, R gap> START_TEST( "matobjgeneric.tst" ); # From 6abd94f417f91542a717534aa7a824e340b38354 Mon Sep 17 00:00:00 2001 From: Max Horn Date: Fri, 17 Apr 2026 22:55:40 +0200 Subject: [PATCH 21/23] cleanup --- tst/testinstall/MatrixObj/matobjgeneric.tst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tst/testinstall/MatrixObj/matobjgeneric.tst b/tst/testinstall/MatrixObj/matobjgeneric.tst index 5f9b3c5a0e..748248ff47 100644 --- a/tst/testinstall/MatrixObj/matobjgeneric.tst +++ b/tst/testinstall/MatrixObj/matobjgeneric.tst @@ -1,4 +1,4 @@ -#@local e, v, v2, w, M, z, rows, a, b, c, d, p, ev, n, ai, inv, zm, zs, N, T, lp, lp0, s, R +#@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" ); # From 1ba59c465ffeebf5caeeb40a00b8e11220b13799 Mon Sep 17 00:00:00 2001 From: Max Horn Date: Tue, 21 Apr 2026 00:16:28 +0200 Subject: [PATCH 22/23] some tweaks --- doc/ref/makedocreldata.g | 2 +- doc/ref/matobj.xml | 2 +- lib/matobjgeneric.gd | 8 ++++---- lib/matobjgeneric.gi | 16 ++++++++-------- 4 files changed, 14 insertions(+), 14 deletions(-) diff --git a/doc/ref/makedocreldata.g b/doc/ref/makedocreldata.g index 22993e3497..7422aa85b4 100644 --- a/doc/ref/makedocreldata.g +++ b/doc/ref/makedocreldata.g @@ -119,7 +119,7 @@ GAPInfo.ManualDataRef:= rec( "../../lib/matobj2.gd", "../../lib/matobjnz.gd", "../../lib/matobjplist.gd", - "../../lib/matobjgeneric.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 936676d4d4..4daef4eab5 100644 --- a/doc/ref/matobj.xml +++ b/doc/ref/matobj.xml @@ -374,7 +374,7 @@ described in this chapter is supported. <#Include Label="IsGF2MatrixRep"> <#Include Label="Is8BitMatrixRep"> <#Include Label="IsPlistMatrixRep"> -<#Include Label="IsGenericMatrixRep"> + <#Include Label="IsZmodnZMatrixRep"> diff --git a/lib/matobjgeneric.gd b/lib/matobjgeneric.gd index a9707baebc..261f5878ca 100644 --- a/lib/matobjgeneric.gd +++ b/lib/matobjgeneric.gd @@ -40,7 +40,7 @@ DeclareRepresentation( "IsGenericMatrixRep", [] ); -# Internal positions for flat plist matrices. -BindConstant( "FBDPOS", 1 ); -BindConstant( "FCOLSPOS", 2 ); -BindConstant( "FROWSPOS", 3 ); +# 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 index aafcc3649c..b73381bceb 100644 --- a/lib/matobjgeneric.gi +++ b/lib/matobjgeneric.gi @@ -21,22 +21,22 @@ BindGlobal( "MakeIsGenericMatrixRep", # Currently there is no special handling depending on 'basedomain', # the types are always cached in 'fam'. - if not IsBound( fam!.FlatPlistMatrixRepTypes ) then + 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!.FlatPlistMatrixRepTypes := [ + fam!.GenericMatrixRepTypes := [ NewType( fam, filter ), NewType( fam, filter and IsMutable ), ]; fi; if IsMutable( list ) then - typ := fam!.FlatPlistMatrixRepTypes[2]; + typ := fam!.GenericMatrixRepTypes[2]; else - typ := fam!.FlatPlistMatrixRepTypes[1]; + typ := fam!.GenericMatrixRepTypes[1]; fi; if check and ValueOption( "check" ) <> false then @@ -135,17 +135,17 @@ InstallMethod( MatElm, InstallMethod( SetMatElm, [ "IsGenericMatrixRep and IsMutable", "IsPosInt", "IsPosInt", "IsObject" ], - function( M, row, col, ob ) + function( M, row, col, val ) if ValueOption( "check" ) <> false then - if not ob in BaseDomain( M ) then - Error( " must lie in the base domain of " ); + 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] := ob; + M![FROWSPOS][row,col] := val; end ); From a2ea205763e824048cfe8b86e9c37df14dbf98cd Mon Sep 17 00:00:00 2001 From: Max Horn Date: Tue, 21 Apr 2026 00:33:25 +0200 Subject: [PATCH 23/23] revert a family change --- lib/matobjnz.gi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/matobjnz.gi b/lib/matobjnz.gi index 3bebd82b8d..60fcadff4b 100644 --- a/lib/matobjnz.gi +++ b/lib/matobjnz.gi @@ -669,7 +669,7 @@ InstallTagBasedMethod( NewZeroMatrix, m[i] := ZeroVector( cols, e ); od; m := [basedomain,e,cols,m]; - Objectify( NewType(CollectionsFamily(ElementsFamily(FamilyObj(basedomain))), + Objectify( NewType(CollectionsFamily(FamilyObj(basedomain)), filter and IsMutable), m ); return m; end );