diff --git a/benchmark/matobj/bench-matelm-access.g b/benchmark/matobj/bench-matelm-access.g index 889ba71801..f58d365830 100644 --- a/benchmark/matobj/bench-matelm-access.g +++ b/benchmark/matobj/bench-matelm-access.g @@ -136,17 +136,23 @@ RunMatTest := function(desc, m) TestWritingMatrix(m); end; -m:=IdentityMat(10);; -RunMatTest("integer matrix", m); +m:=IdentityMat(10,GF(257));; # plain list of plain lists +RunMatTest("GF(257) plist-of-plist matrix", m); -m:=IdentityMat(10,GF(2));; +m:=IdentityMatrix(GF(257), 10); # IsPlistMatrixRep +RunMatTest("GF(257) IsPlistMatrixRep", m); + +m:=IdentityMatrix(GF(257), 10); # IsGenericMatrixRep +RunMatTest("GF(257) IsGenericMatrixRep", m); + +m:=IdentityMat(10,GF(2));; # plain list of IsGF2VectorRep RunMatTest("GF(2) rowlist", m); -m:=IdentityMat(10,GF(2));; ConvertToMatrixRep(m);; +m:=IdentityMatrix(GF(2), 10); # IsGF2MatrixRep RunMatTest("GF(2) compressed matrix", m); -m:=IdentityMat(10,GF(7));; +m:=IdentityMat(10,GF(7));; # plain list of Is8BitVectorRep RunMatTest("GF(7) rowlist", m); -m:=IdentityMat(10,GF(7));; ConvertToMatrixRep(m);; +m:=IdentityMatrix(GF(7), 10); # Is8BitMatrixRep RunMatTest("GF(7) compressed matrix", m); diff --git a/benchmark/matobj/bench-matobj-creation.g b/benchmark/matobj/bench-matobj-creation.g index d74e5f040e..fdf568d716 100644 --- a/benchmark/matobj/bench-matobj-creation.g +++ b/benchmark/matobj/bench-matobj-creation.g @@ -91,18 +91,23 @@ RunMatTest := function(desc, ring) TestCreatingMatrix(ring); end; -RunMatTest("GF(2)", GF(2)); -RunMatTest("Rationals", Rationals); - RunMatObjTest := function(desc, filter, ring) Print("\n"); PrintBoxed(Concatenation("Testing ", desc)); TestCreatingMatrixObj(filter, ring); end; -RunMatObjTest("GF(2) IsPlistMatrixRep", IsPlistMatrixRep, GF(2)); +RunMatTest("GF(257)", GF(257)); +RunMatObjTest("GF(257) IsPlistMatrixRep", IsPlistMatrixRep, GF(257)); +RunMatObjTest("GF(257) IsGenericMatrixRep", IsGenericMatrixRep, GF(257)); + +RunMatTest("Integers", Integers); RunMatObjTest("integer IsPlistMatrixRep", IsPlistMatrixRep, Integers); +RunMatObjTest("integer IsGenericMatrixRep", IsGenericMatrixRep, Integers); + +RunMatTest("Rationals", Rationals); RunMatObjTest("rational IsPlistMatrixRep", IsPlistMatrixRep, Rationals); +RunMatObjTest("rational IsGenericMatrixRep", IsGenericMatrixRep, Rationals); # TODO: other reps # TODO: other compare with creating plist-of-plist diff --git a/doc/ref/makedocreldata.g b/doc/ref/makedocreldata.g index f2f1697bed..7422aa85b4 100644 --- a/doc/ref/makedocreldata.g +++ b/doc/ref/makedocreldata.g @@ -119,6 +119,7 @@ GAPInfo.ManualDataRef:= rec( "../../lib/matobj2.gd", "../../lib/matobjnz.gd", "../../lib/matobjplist.gd", + #"../../lib/matobjgeneric.gd", # TODO: enable this if we decide to keep IsGenericMatrixRep "../../lib/matrix.gd", "../../lib/meataxe.gi", "../../lib/memory.gd", diff --git a/doc/ref/matobj.xml b/doc/ref/matobj.xml index 8ed8908e47..4daef4eab5 100644 --- a/doc/ref/matobj.xml +++ b/doc/ref/matobj.xml @@ -374,6 +374,7 @@ described in this chapter is supported. <#Include Label="IsGF2MatrixRep"> <#Include Label="Is8BitMatrixRep"> <#Include Label="IsPlistMatrixRep"> + <#Include Label="IsZmodnZMatrixRep"> diff --git a/lib/matobjgeneric.gd b/lib/matobjgeneric.gd new file mode 100644 index 0000000000..261f5878ca --- /dev/null +++ b/lib/matobjgeneric.gd @@ -0,0 +1,46 @@ +############################################################################# +## +## This file is part of GAP, a system for computational discrete algebra. +## +## SPDX-License-Identifier: GPL-2.0-or-later +## +## Copyright of GAP belongs to its developers, whose names are too numerous +## to list here. Please refer to the COPYRIGHT file for details. +## + +############################################################################ +# +# Dense matrix objects backed by plain lists of plain row lists. +# + +############################################################################# +## +## <#GAPDoc Label="IsGenericMatrixRep"> +## +## +## +## +## An object obj in describes +## a matrix object (see ) whose entries are stored +## as a dense plain list of dense plain row lists. +##

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