
| Current Path : /usr/share/gap/lib/ |
Linux ift1.ift-informatik.de 5.4.0-216-generic #236-Ubuntu SMP Fri Apr 11 19:53:21 UTC 2025 x86_64 |
| Current File : //usr/share/gap/lib/matobj.gi |
############################################################################
#
# matobj.gi
# by Max Neunhöffer
#
## Copyright (C) 2007 Max Neunhöffer, University of St Andrews
## This file is free software, see license information at the end.
#
# This file contains some generic methods for the vector/matrix interface
# defined in matobj1.gd and matobj2.gd.
#
############################################################################
# Install fallback methods for m[i,j] which delegate MatElm resp. SetMatElm,
# for old MatrixObj implementation which don't provide them. We lower the rank
# so that these are only used as a last resort.
InstallMethod( \[\], "for a matrix object and two positions",
[ IsMatrixObj, IsPosInt, IsPosInt ],
-RankFilter(IsMatrixObj),
function( m, row, col )
return MatElm( m, row, col );
end );
InstallMethod( \[\]\:\=, "for a matrix object, two positions, and an object",
[ IsMatrixObj and IsMutable, IsPosInt, IsPosInt, IsObject ],
-RankFilter(IsMatrixObj),
function( m, row, col, obj )
SetMatElm( m, row, col, obj );
end );
InstallMethod( OneOfBaseDomain,
"generic method for IsVectorObj",
[ IsVectorObj ],
v -> One( BaseDomain( v ) ) );
InstallMethod( ZeroOfBaseDomain,
"generic method for IsVectorObj",
[ IsVectorObj ],
v -> Zero( BaseDomain( v ) ) );
InstallMethod( OneOfBaseDomain,
"generic method for IsMatrixObj",
[ IsMatrixObj ],
M -> One( BaseDomain( M ) ) );
InstallMethod( ZeroOfBaseDomain,
"generic method for IsMatrixObj",
[ IsMatrixObj ],
M -> Zero( BaseDomain( M ) ) );
InstallMethod( WeightOfVector, "generic method",
[IsVectorObj],
function(v)
local i,n;
n := 0;
for i in [1..Length(v)] do
if not IsZero(v[i]) then
n := n + 1;
fi;
od;
return n;
end );
InstallMethod( DistanceOfVectors, "generic method",
[IsVectorObj, IsVectorObj],
function( v, w)
local i,n;
if Length(v) <> Length(w) then
Error("vectors must have same length");
return fail;
fi;
n := 0;
for i in [1..Length(v)] do
if v[i] <> w[i] then
n := n + 1;
fi;
od;
return n;
end );
#
# TODO: possibly rename the following
#
BindGlobal( "DefaultVectorRepForBaseDomain",
function( basedomain )
if IsFinite(basedomain) and IsField(basedomain) and Size(basedomain) = 2 then
return IsGF2VectorRep;
elif IsFinite(basedomain) and IsField(basedomain) and Size(basedomain) <= 256 then
return Is8BitVectorRep;
fi;
return IsPlistVectorRep;
end);
BindGlobal( "DefaultMatrixRepForBaseDomain",
function( basedomain )
if IsFinite(basedomain) and IsField(basedomain) and Size(basedomain) = 2 then
return IsGF2MatrixRep;
elif IsFinite(basedomain) and IsField(basedomain) and Size(basedomain) <= 256 then
return Is8BitMatrixRep;
fi;
return IsPlistMatrixRep;
end);
# methods to create vectors
InstallMethod( Vector,
[IsOperation, IsSemiring, IsList],
function(rep, base, l)
return NewVector(rep, base, l);
end);
InstallMethod( Vector,
[IsOperation, IsSemiring, IsVectorObj],
function(rep, base, v)
return NewVector(rep, base, Unpack(v));
end);
InstallMethod( Vector,
[IsSemiring, IsList],
function(base, l)
return NewVector(DefaultVectorRepForBaseDomain(base), base, l);
end);
InstallMethod( Vector,
[IsSemiring, IsVectorObj],
function(base, v)
return NewVector(DefaultVectorRepForBaseDomain(base), base, Unpack(v));
end);
InstallMethod( Vector,
[IsList, IsVectorObj],
function(l, example)
return NewVector(ConstructingFilter(example), BaseDomain(example), l);
end);
InstallMethod( Vector,
[IsVectorObj, IsVectorObj],
function(v, example)
return NewVector(ConstructingFilter(example), BaseDomain(example), Unpack(v));
end);
InstallMethod( Vector,
[IsList],
function(l)
local dom;
dom := DefaultScalarDomainOfMatrixList([[l]]);
return NewVector(DefaultVectorRepForBaseDomain(dom), dom, l);
end);
#
#
#
InstallMethod( Matrix,
[IsOperation, IsSemiring, IsList, IsInt],
function( rep, basedomain, list, nrCols )
# TODO: adjust NewMatrix to use same arg order as Matrix (or vice-versa)
return NewMatrix( rep, basedomain, nrCols, list );
end );
InstallMethod( Matrix,
[IsOperation, IsSemiring, IsList],
function( rep, basedomain, list )
if Length(list) = 0 then Error("list must be not empty; to create empty matrices, please specify nrCols"); fi;
return NewMatrix( rep, basedomain, Length(list[1]), list );
end );
InstallMethod( Matrix,
[IsOperation, IsSemiring, IsMatrixObj],
function( rep, basedomain, mat )
# TODO: can we do better? encourage MatrixObj implementors to overload this?
return NewMatrix( rep, basedomain, NrCols(mat), Unpack(mat) );
end );
#
#
#
InstallMethod( Matrix,
[IsSemiring, IsList, IsInt],
# FIXME: Remove this downranking, it was introduced to prevent
# Semigroups from breaking ahead of the 4.10 release
-SUM_FLAGS,
function( basedomain, list, nrCols )
local rep;
rep := DefaultMatrixRepForBaseDomain(basedomain);
return NewMatrix( rep, basedomain, nrCols, list );
end );
InstallMethod( Matrix,
[IsSemiring, IsList],
# FIXME: Remove this downranking, it was introduced to prevent
# Semigroups from breaking ahead of the 4.10 release
-SUM_FLAGS,
function( basedomain, list )
local rep;
if Length(list) = 0 then Error("list must be not empty"); fi;
rep := DefaultMatrixRepForBaseDomain(basedomain);
return NewMatrix( rep, basedomain, Length(list[1]), list );
end );
InstallMethod( Matrix,
[IsSemiring, IsMatrixObj],
# FIXME: Remove this downranking, it was introduced to prevent
# Semigroups from breaking ahead of the 4.10 release
-SUM_FLAGS,
function( basedomain, mat )
# TODO: can we do better? encourage MatrixObj implementors to overload this?
return NewMatrix( DefaultMatrixRepForBaseDomain(basedomain), basedomain, NrCols(mat), Unpack(mat) );
end );
#
#
#
InstallMethod( Matrix,
[IsList, IsInt],
function( list, nrCols )
local basedomain, rep;
if Length(list) = 0 then Error("list must be not empty"); fi;
if Length(list[1]) = 0 then Error("list[1] must be not empty, please specify base domain explicitly"); fi;
basedomain := DefaultScalarDomainOfMatrixList([list]);
rep := DefaultMatrixRepForBaseDomain(basedomain);
return NewMatrix( rep, basedomain, nrCols, list );
end );
InstallMethod( Matrix,
[IsList],
function( list )
local rep, basedomain;
if Length(list) = 0 then Error("list must be not empty"); fi;
if Length(list[1]) = 0 then Error("list[1] must be not empty, please specify base domain explicitly"); fi;
basedomain := DefaultScalarDomainOfMatrixList([list]);
rep := DefaultMatrixRepForBaseDomain(basedomain);
return NewMatrix( rep, basedomain, Length(list[1]), list );
end );
#
# matrix constructors using example objects (as last argument)
#
InstallMethod( Matrix,
[IsList, IsInt, IsMatrixObj],
function( list, nrCols, example )
return NewMatrix( ConstructingFilter(example), BaseDomain(example), nrCols, list );
end );
InstallMethod( Matrix, "generic convenience method with 2 args",
[IsList, IsMatrixObj],
function( list, example )
if Length(list) = 0 then
ErrorNoReturn("Matrix: two-argument version not allowed with empty first arg");
fi;
if not (IsList(list[1]) or IsVectorObj(list[1])) then
ErrorNoReturn("Matrix: flat data not supported in two-argument version");
fi;
return NewMatrix( ConstructingFilter(example), BaseDomain(example), Length(list[1]), list );
end );
InstallMethod( Matrix,
[IsMatrixObj, IsMatrixObj],
function( mat, example )
# TODO: can we avoid using Unpack? resp. make this more efficient
# perhaps adjust NewMatrix to take an IsMatrixObj?
return NewMatrix( ConstructingFilter(example), BaseDomain(example), NrCols(mat), Unpack(mat) );
end );
#
#
#
InstallMethod( ZeroMatrix,
[IsInt, IsInt, IsMatrixObj],
function( rows, cols, example )
return ZeroMatrix( ConstructingFilter(example), BaseDomain(example), rows, cols );
end );
InstallMethod( ZeroMatrix,
[IsSemiring, IsInt, IsInt],
function( basedomain, rows, cols )
return ZeroMatrix( DefaultMatrixRepForBaseDomain(basedomain), basedomain, rows, cols );
end );
InstallMethod( ZeroMatrix,
[IsOperation, IsSemiring, IsInt, IsInt],
function( rep, basedomain, rows, cols )
# TODO: urge matrixobj implementors to overload this
return NewMatrix( rep, basedomain, cols, ListWithIdenticalEntries( rows * cols, Zero(basedomain) ) );
end );
#
#
#
InstallMethod( IdentityMatrix,
[IsInt, IsMatrixObj],
function( dim, example )
return IdentityMatrix( ConstructingFilter(example), BaseDomain(example), dim );
end );
InstallMethod( IdentityMatrix,
[IsSemiring, IsInt],
function( basedomain, dim )
return IdentityMatrix( DefaultMatrixRepForBaseDomain(basedomain), basedomain, dim );
end );
InstallMethod( IdentityMatrix,
[IsOperation, IsSemiring, IsInt],
function( rep, basedomain, dim )
# TODO: avoid using IdentityMat eventually
return NewMatrix( rep, basedomain, dim, IdentityMat( dim, basedomain ) );
end );
InstallMethod( Unfold, "for a matrix object, and a vector object",
[ IsMatrixObj, IsVectorObj ],
function( m, w )
local v,i,l;
if Length(m) = 0 then
return ZeroVector(0,w);
else
l := NumberColumns(m);
v := ZeroVector(Length(m)*l,w);
for i in [1..Length(m)] do
CopySubVector( m[i], v, [1..l], [(i-1)*l+1..i*l] );
od;
return v;
fi;
end );
InstallMethod( Fold, "for a vector, a positive int, and a matrix",
[ IsVectorObj, IsPosInt, IsMatrixObj ],
function( v, rl, t )
local rows,i,tt,m;
m := Matrix([],rl,t);
tt := ZeroVector(rl,v);
for i in [1..Length(v)/rl] do
CopySubVector(v,tt,[(i-1)*rl+1..i*rl],[1..rl]);
Add(m,ShallowCopy(tt));
od;
return m;
end );
InstallMethod( CompanionMatrix, "for a polynomial and a matrix",
[ IsUnivariatePolynomial, IsMatrixObj ],
function( po, m )
local l, n, q, ll, i, one;
one := OneOfBaseDomain( m );
l := CoefficientsOfUnivariatePolynomial(po);
n := Length(l)-1;
if not IsOne(l[n+1]) then
Error("CompanionMatrix: polynomial is not monic");
return fail;
fi;
l := Vector(-l{[1..n]},CompatibleVector(m));
ll := 0*[1..n];
ll[n] := l;
for i in [1..n-1] do
ll[i] := ZeroMutable(l);
ll[i][i+1] := one;
od;
return Matrix(ll,n,m);
end );
InstallMethod( KroneckerProduct, "for two matrices",
[ IsMatrixObj, IsMatrixObj ],
function( A, B )
local rowsA, rowsB, colsA, colsB, newclass, AxB, i, j;
if not IsIdenticalObj(BaseDomain(A),BaseDomain(B)) then
ErrorNoReturn("KroneckerProduct: Matrices not over same base domain");
fi;
rowsA := NumberRows(A);
colsA := NumberColumns(A);
rowsB := NumberRows(B);
colsB := NumberColumns(B);
AxB := ZeroMatrix( rowsA * rowsB, colsA * colsB, A );
# Cache matrices
# not implemented yet
for i in [1..rowsA] do
for j in [1..colsA] do
CopySubMatrix( A[i][j] * B, AxB,
[ 1 .. rowsB ], [ rowsB * (i-1) + 1 .. rowsB * i ],
[ 1 .. colsB ], [ (j-1) * colsB + 1 .. j * colsB ] );
od;
od;
if not IsMutable(A) and not IsMutable(B) then
MakeImmutable(AxB);
fi;
return AxB;
end );
InstallGlobalFunction( ConcatenationOfVectors,
function( arg )
local i,len,pos,res,total;
if Length( arg ) = 1 and IsList( arg[1] ) then
arg := arg[1];
fi;
if Length(arg) = 0 then
Error("must have at least one vector to concatenate");
fi;
total := Sum(arg,Length);
res := ZeroVector(total,arg[1]);
pos := 1;
for i in [1..Length(arg)] do
len := Length(arg[i]);
CopySubVector(arg[i],res,[1..len],[pos..pos+len-1]);
pos := pos + len;
od;
return res;
end );
InstallGlobalFunction( MakeVector,
function( arg )
local bd,l,ty;
if Length(arg) = 1 then
l := arg[1];
bd := DefaultField(l);
elif Length(arg) <> 2 then
Error("usage: MakeVector( <list> [,<basedomain>] )");
return fail;
else
l := arg[1];
bd := arg[2];
fi;
if IsFinite(bd) and IsField(bd) and Size(bd) = 2 then
ty := IsGF2VectorRep;
elif IsFinite(bd) and IsField(bd) and Size(bd) <= 256 then
ty := Is8BitVectorRep;
else
ty := IsPlistVectorRep;
fi;
return NewVector(ty,bd,l);
end );
InstallMethod( ExtractSubVector, "generic method",
[ IsVectorObj, IsList ],
function( v, l )
return v{l};
end );
InstallOtherMethod( ScalarProduct, "generic method",
[ IsVectorObj, IsVectorObj ],
function( v, w )
local i,s;
if Length(v) <> Length(w) then
Error("vectors must have equal length");
return fail;
fi;
s:= ZeroOfBaseDomain( v );
for i in [1..Length(v)] do
s := s + v[i]*w[i];
od;
return s;
end );
InstallMethod( TraceMat, "generic method",
[ IsMatrixObj ],
function( m )
local i,s;
if NumberRows(m) <> NumberColumns(m) then
Error("matrix must be square");
return fail;
fi;
s := ZeroOfBaseDomain( m );
for i in [1..NumberRows(m)] do
s := s + m[ i, i ];
od;
return s;
end );
InstallMethod(PositionNonZero,
"generic method for a row vector",
[IsRowVector],
function(vec)
local i;
for i in [1..Length(vec)] do
if not IsZero(vec[i]) then return i; fi;
od;
return i+1;
end);
#T superfluous?
InstallMethod(PositionNonZero,
"generic method for a vector object",
[ IsVectorObj ],
function(vec)
local i;
for i in [1..Length(vec)] do
if not IsZero(vec[i]) then return i; fi;
od;
return i+1;
end);
InstallMethod( ListOp,
"generic method for a vector object",
[ IsVectorObj ],
function(vec)
local result, i, len;
len := Length(vec);
result := [];
result[len] := vec[len];
for i in [ 1 .. len - 1 ] do
result[i] := vec[i];
od;
return result;
end );
InstallMethod( ListOp,
"generic method for a vector object and a function",
[ IsVectorObj, IsFunction ],
function(vec,func)
local result, i, len;
len := Length(vec);
result := [];
result[len] := func(vec[len]);
for i in [ 1 .. len - 1 ] do
result[i] := func(vec[i]);
od;
return result;
end );
InstallMethod( Unpack,
"generic method for a vector object",
[ IsVectorObj ],
ListOp ); ## Potentially slower than a direct implementation,
## but avoids code duplication.
InstallMethod( \{\},
"generic method for a vector object and a list",
[ IsVectorObj, IsList ],
function(vec,poss)
local vec_list;
vec_list := ListOp(vec);
vec_list := vec_list{poss};
return Vector(vec_list,vec);
end );
InstallMethod( CopySubVector,
"generic method for vectors",
[ IsVectorObj and IsMutable, IsList, IsVectorObj, IsList ],
function(dst, dcols, src, scols)
local i;
if not Length( dcols ) = Length( scols ) then
Error( "source and destination index lists must be of equal length" );
return;
fi;
for i in [ 1 .. Length( dcols ) ] do
dst[dcols[i]] := src[scols[i]];
od;
end );
## Backwards compatible version
InstallMethod( CopySubVector,
"generic method for vectors",
[ IsVectorObj, IsVectorObj and IsMutable, IsList, IsList ],
function(src, dst, scols, dcols)
CopySubVector(dst,dcols,src,scols);
end );
InstallMethod( Randomize,
"generic method for a vector",
[ IsVectorObj and IsMutable ],
function(vec)
local basedomain, i;
basedomain := BaseDomain( vec );
for i in [ 1 .. Length( vec ) ] do
vec[ i ] := Random( basedomain );
od;
end );
InstallMethod( Randomize,
"generic method for a vector and a random source",
[ IsVectorObj and IsMutable, IsRandomSource ],
function(vec, rs)
local basedomain, i;
basedomain := BaseDomain( vec );
for i in [ 1 .. Length( vec ) ] do
vec[ i ] := Random( rs, basedomain );
od;
end );
#
# Compatibility code: Install MatrixObj methods for IsMatrix.
#
InstallOtherMethod( NumberRows, "for a plist matrix",
[ IsMatrix ], Length);
InstallOtherMethod( NumberColumns, "for a plist matrix",
[ IsMatrix ], m -> Length(m[1]) );
#
# Compatibility code: Generic methods for IsMatrixObj
#
InstallOtherMethod( DimensionsMat, "for a matrix in IsMatrixObj",
[ IsMatrixObj ], m -> [ NumberRows( m ), NumberColumns( m ) ] );