|
#############################################################################
##
## 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.
##
# represent vectors/matrices over Z/nZ by nonnegative integer lists
# in the range [0..n-1], but reduce after
# arithmetic. This way avoid always wrapping all entries separately
BindGlobal("ZNZVECREDUCE",function(v,l,m)
local i;
for i in [1..l] do
if v[i]<0 or v[i]>=m then v[i]:=v[i] mod m;fi;
od;
end);
InstallMethod( ConstructingFilter, "for a zmodnz vector",
[ IsZmodnZVectorRep ],
function( v )
return IsZmodnZVectorRep;
end );
InstallOtherMethod( ConstructingFilter, "for a zmodnz matrix",
[ IsZmodnZMatrixRep ],
function( m )
return IsZmodnZMatrixRep;
end );
InstallMethod( CompatibleVectorFilter, "zmodnz",
[ IsZmodnZMatrixRep ],
M -> IsZmodnZVectorRep );
############################################################################
# Vectors
############################################################################
InstallTagBasedMethod( NewVector,
IsZmodnZVectorRep,
function( filter, basedomain, l )
local check, typ, v;
check:= ValueOption( "check" ) <> false;
if check and not ( IsZmodnZObjNonprimeCollection( basedomain ) or
( IsFinite( basedomain ) and IsPrimeField( basedomain ) ) ) then
Error( "<basedomain> must be Integers mod <n> for some <n>" );
fi;
typ:=NewType(FamilyObj(basedomain),IsZmodnZVectorRep and IsMutable and
CanEasilyCompareElements);
# force list of integers
if FamilyObj(basedomain)=FamilyObj(l) then
l:=List(l,Int);
elif check and not ForAll( l, IsInt ) then
Error( "<l> must be a list of integers or of elements in <basedomain>" );
else
l:=ShallowCopy(l);
fi;
v := [basedomain,l];
Objectify(typ,v);
return v;
end );
InstallTagBasedMethod( NewZeroVector,
IsZmodnZVectorRep,
function( filter, basedomain, l )
local check, typ, v;
check:= ValueOption( "check" ) <> false;
if check and not ( IsZmodnZObjNonprimeCollection( basedomain ) or
( IsFinite( basedomain ) and IsPrimeField( basedomain ) ) ) then
Error( "<basedomain> must be Integers mod <n> for some <n>" );
fi;
typ:=NewType(FamilyObj(basedomain),IsZmodnZVectorRep and IsMutable and
CanEasilyCompareElements);
# represent list as integers
v := [basedomain,0*[1..l]];
Objectify(typ,v);
return v;
end );
InstallMethod( ViewObj, "for a zmodnz vector", [ IsZmodnZVectorRep ],
function( v )
local l;
if not IsMutable(v) then
Print("<immutable ");
else
Print("<");
fi;
Print("vector mod ",Size(v![BDPOS]));
l:=Length(v![ELSPOS]);
if 0<l and l<=8 then
Print(": ",v![ELSPOS],">");
else
Print(" of length ",Length(v![ELSPOS]),">");
fi;
end );
InstallMethod( PrintObj, "for a zmodnz vector", [ IsZmodnZVectorRep ],
function( v )
Print("NewVector(IsZmodnZVectorRep");
if IsField(v![BDPOS]) then
Print(",GF(",Size(v![BDPOS]),"),",v![ELSPOS],")");
else
Print(",",String(v![BDPOS]),",",v![ELSPOS],")");
fi;
end );
InstallMethod( String, "for a zmodnz vector", [ IsZmodnZVectorRep ],
function( v )
local st;
st := "NewVector(IsZmodnZVectorRep";
if IsField(v![BDPOS]) then
Append(st,Concatenation( ",GF(",String(Size(v![BDPOS])),"),",
String(v![ELSPOS]),")" ));
else
Append(st,Concatenation( ",",String(v![BDPOS]),",",
String(v![ELSPOS]),")" ));
fi;
return st;
end );
InstallMethod( Display, "for a zmodnz vector", [ IsZmodnZVectorRep ],
function( v )
Print( "<a " );
Print( "zmodnz vector over ",BaseDomain(v),":\n");
Print(v![ELSPOS],"\n>\n");
end );
InstallMethod( BaseDomain, "for a zmodnz vector", [ IsZmodnZVectorRep ],
function( v )
return v![BDPOS];
end );
InstallMethod( Length, "for a zmodnz vector", [ IsZmodnZVectorRep ],
function( v )
return Length(v![ELSPOS]);
end );
InstallMethod( ShallowCopy, "for a zmodnz vector", [ IsZmodnZVectorRep ],
function( v )
local res;
res := Objectify(TypeObj(v),[v![BDPOS],ShallowCopy(v![ELSPOS])]);
if not IsMutable(v) then SetFilterObj(res,IsMutable); fi;
return res;
end );
# StructuralCopy works automatically
InstallMethod( PostMakeImmutable, "for a zmodnz vector", [ IsZmodnZVectorRep ],
function( v )
MakeImmutable( v![ELSPOS] );
end );
############################################################################
# Representation preserving constructors:
############################################################################
# not needed according to MH
# InstallMethod( ZeroVector, "for an integer and a zmodnz vector",
# [ IsInt, IsZmodnZVectorRep ],
# function( l, t )
# local v;
# v := Objectify(TypeObj(t),
# [t![BDPOS],ListWithIdenticalEntries(l,0)]);
# if not IsMutable(v) then SetFilterObj(v,IsMutable); fi;
# return v;
# end );
#
# InstallMethod( ZeroVector, "for an integer and a zmodnz matrix",
# [ IsInt, IsZmodnZMatrixRep ],
# function( l, m )
# local v;
# v := Objectify(TypeObj(m![EMPOS]),
# [m![BDPOS],ListWithIdenticalEntries(l,0)]);
# if not IsMutable(v) then SetFilterObj(v,IsMutable); fi;
# return v;
# end );
InstallMethod( Vector, "for a plain list and a zmodnz vector",IsIdenticalObj,
[ IsList and IsPlistRep, IsZmodnZVectorRep ],
function( l, t )
local v;
# force list of integers
if FamilyObj(t![BDPOS])=FamilyObj(l) then l:=List(l,Int); fi;
v := Objectify(TypeObj(t),[t![BDPOS],l]);
if not IsMutable(v) then SetFilterObj(v,IsMutable); fi;
return v;
end );
InstallMethod( Vector, "for a list and a zmodnz vector",
[ IsList, IsZmodnZVectorRep ],
function( l, t )
local v;
v := ShallowCopy(l);
if IsGF2VectorRep(l) then
PLAIN_GF2VEC(v);
elif Is8BitVectorRep(l) then
PLAIN_VEC8BIT(v);
fi;
v := Objectify(TypeObj(t),[t![BDPOS],v]);
if not IsMutable(v) then SetFilterObj(v,IsMutable); fi;
return v;
end );
############################################################################
# A selection of list operations:
############################################################################
InstallMethod( \[\], "for a zmodnz vector and a positive integer",
[ IsZmodnZVectorRep, IsPosInt ],
function( v, p )
return ZmodnZObj(ElementsFamily(FamilyObj(v)),v![ELSPOS][p]);
end );
InstallMethod( \[\]\:\=, "for a zmodnz vector, a positive integer, and an obj",
[ IsZmodnZVectorRep, IsPosInt, IsObject ],
function( v, p, ob )
v![ELSPOS][p] := Int(ob);
end );
InstallMethod( \{\}, "for a zmodnz vector and a list",
[ IsZmodnZVectorRep, IsList ],
function( v, l )
return Objectify(TypeObj(v),[v![BDPOS],v![ELSPOS]{l}]);
end );
InstallMethod( PositionNonZero, "for a zmodnz vector", [ IsZmodnZVectorRep ],
function( v )
return PositionNonZero( v![ELSPOS] );
end );
InstallMethod( PositionNonZero, "for a zmodnz vector", [ IsZmodnZVectorRep ],
function( v )
return PositionNonZero( v![ELSPOS] );
end );
InstallOtherMethod( PositionNonZero, "for a zmodnz vector and start",
[ IsZmodnZVectorRep,IsInt ],
function( v,s )
return PositionNonZero( v![ELSPOS],s );
end );
InstallMethod( PositionLastNonZero, "for a zmodnz vector", [ IsZmodnZVectorRep ],
function( v )
local els,i;
els := v![ELSPOS];
i := Length(els);
while i > 0 and IsZero(els[i]) do i := i - 1; od;
return i;
end );
InstallMethod( ListOp, "for a zmodnz vector", [ IsZmodnZVectorRep ],
function( v )
local fam;
fam:=ElementsFamily(FamilyObj(v));
return List([1..Length(v![ELSPOS])],x->ZmodnZObj(fam,v![ELSPOS][x]));
end );
InstallMethod( ListOp, "for a zmodnz vector and a function",
[ IsZmodnZVectorRep, IsFunction ],
function( v, f )
local fam;
fam:=ElementsFamily(FamilyObj(v));
return List(List([1..Length(v![ELSPOS])],x->ZmodnZObj(fam,v![ELSPOS][x])),f);
end );
InstallMethod( Unpack, "for a zmodnz vector",
[ IsZmodnZVectorRep ],
function( v )
local fam;
fam:=ElementsFamily(FamilyObj(v));
return List([1..Length(v![ELSPOS])],x->ZmodnZObj(fam,v![ELSPOS][x]));
end );
############################################################################
# Arithmetical operations:
############################################################################
InstallMethod( \+, "for two zmodnz vectors",IsIdenticalObj,
[ IsZmodnZVectorRep, IsZmodnZVectorRep ],
function( a, b )
local ty,i,m,mu;
if not IsMutable(a) and IsMutable(b) then
ty := TypeObj(b);
else
ty := TypeObj(a);
fi;
m:=Size(a![BDPOS]);
b:=SUM_LIST_LIST_DEFAULT(a![ELSPOS],b![ELSPOS]);
if not IsMutable(b) then mu:=true;b:=ShallowCopy(b);
else mu:=false;fi;
for i in [1..Length(b)] do if b[i]>=m then b[i]:=b[i] mod m;fi;od;
if mu then MakeImmutable(b);fi;
return Objectify(ty,[a![BDPOS],b]);
end );
InstallOtherMethod( \+, "for zmodnz vector and plist",IsIdenticalObj,
[ IsZmodnZVectorRep, IsList ],
function( a, b )
return a+Vector(BaseDomain(a),b);
end );
InstallOtherMethod( \+, "for plist and zmodnz vector",IsIdenticalObj,
[ IsList,IsZmodnZVectorRep ],
function( a, b )
return Vector(BaseDomain(b),a)+b;
end );
InstallMethod( \-, "for two zmodnz vectors",IsIdenticalObj,
[ IsZmodnZVectorRep, IsZmodnZVectorRep ],
function( a, b )
local ty,i,m,mu;
if not IsMutable(a) and IsMutable(b) then
ty := TypeObj(b);
else
ty := TypeObj(a);
fi;
m:=Size(a![BDPOS]);
b:=a![ELSPOS] - b![ELSPOS];
if not IsMutable(b) then mu:=true;b:=ShallowCopy(b);
else mu:=false;fi;
for i in [1..Length(b)] do if b[i]<0 then b[i]:=b[i] mod m;fi;od;
if mu then MakeImmutable(b);fi;
return Objectify(ty,[a![BDPOS],b]);
end );
InstallOtherMethod( \-, "for zmodnz vector and plist",IsIdenticalObj,
[ IsZmodnZVectorRep, IsList ],
function( a, b )
return a-Vector(BaseDomain(a),b);
end );
InstallOtherMethod( \-, "for plist and zmodnz vector",IsIdenticalObj,
[ IsList,IsZmodnZVectorRep ],
function( a, b )
return Vector(BaseDomain(b),a)-b;
end );
InstallMethod( \=, "for two zmodnz vectors",IsIdenticalObj,
[ IsZmodnZVectorRep, IsZmodnZVectorRep ],
function( a, b )
return EQ_LIST_LIST_DEFAULT(a![ELSPOS],b![ELSPOS]);
end );
InstallMethod( \=, "for zmodnz vector and plist",IsIdenticalObj,
[ IsZmodnZVectorRep, IsPlistRep ],
function( a, b )
return a![ELSPOS]=List(b,x->x![1]);
end );
InstallMethod( \=, "for plist an zmodnz vector",IsIdenticalObj,
[ IsPlistRep,IsZmodnZVectorRep],
function(b,a)
return a![ELSPOS]=List(b,x->x![1]);
end );
InstallMethod( \<, "for two zmodnz vectors",IsIdenticalObj,
[ IsZmodnZVectorRep, IsZmodnZVectorRep ],
function( a, b )
return LT_LIST_LIST_DEFAULT(a![ELSPOS],b![ELSPOS]);
end );
InstallMethod( AddRowVector, "for two zmodnz vectors",
[ IsZmodnZVectorRep and IsMutable, IsZmodnZVectorRep ],
function( a, b )
local i,m;
a:=a![ELSPOS];
ADD_ROW_VECTOR_2_FAST( a, b![ELSPOS] );
m:=Size(b![BDPOS]);
for i in [1..Length(a)] do if a[i]>=m then a[i]:=a[i] mod m;fi;od;
end );
InstallMethod( AddRowVector, "for two zmodnz vectors, and a scalar",
[ IsZmodnZVectorRep and IsMutable, IsZmodnZVectorRep, IsObject ],
function( a, b, s )
local i,m;
if IsZmodnZObj(s) then s:=Int(s);fi;
a:=a![ELSPOS];
if IsSmallIntRep(s) then
ADD_ROW_VECTOR_3_FAST( a, b![ELSPOS], s );
else
ADD_ROW_VECTOR_3( a, b![ELSPOS], s );
fi;
m:=Size(b![BDPOS]);
if s>=0 then
for i in [1..Length(a)] do if a[i]>=m then a[i]:=a[i] mod m;fi;od;
else
for i in [1..Length(a)] do if a[i]<0 then a[i]:=a[i] mod m;fi;od;
fi;
end );
InstallOtherMethod( AddRowVector, "for zmodnz vector, plist, and a scalar",
[ IsZmodnZVectorRep and IsMutable, IsPlistRep, IsObject ],
function( a, b, s )
local i,m;
if not ForAll(b,IsModulusRep) then TryNextMethod();fi;
if IsZmodnZObj(s) then s:=Int(s);fi;
m:=Size(a![BDPOS]);
a:=a![ELSPOS];
b:=List(b,x->x![1]);
if IsSmallIntRep(s) then
ADD_ROW_VECTOR_3_FAST( a, b, s );
else
ADD_ROW_VECTOR_3( a, b, s );
fi;
if s>=0 then
for i in [1..Length(a)] do if a[i]>=m then a[i]:=a[i] mod m;fi;od;
else
for i in [1..Length(a)] do if a[i]<0 then a[i]:=a[i] mod m;fi;od;
fi;
end );
InstallOtherMethod( AddRowVector, "for plist, zmodnz vector, and a scalar",
[ IsPlistRep and IsMutable, IsZmodnZVectorRep, IsObject ],
function( a, b, s )
local i;
if not ForAll(a,IsModulusRep) then TryNextMethod();fi;
for i in [1..Length(a)] do
a[i]:=a[i]+b[i]*s;
od;
end);
InstallOtherMethod( AddRowVector, "for plist, plist vector, and a scalar",
[ IsPlistRep and IsMutable, IsPlistVectorRep, IsObject ],
function( a, b, s )
local i;
for i in [1..Length(a)] do
a[i]:=a[i]+b[i]*s;
od;
end);
InstallMethod( AddRowVector,
"for two zmodnz vectors, a scalar, and two positions",
[ IsZmodnZVectorRep and IsMutable, IsZmodnZVectorRep,
IsObject, IsPosInt, IsPosInt ],
function( a, b, s, from, to )
local i,m;
if IsZmodnZObj(s) then s:=Int(s);fi;
a:=a![ELSPOS];
if IsSmallIntRep(s) then
ADD_ROW_VECTOR_5_FAST( a, b![ELSPOS], s, from, to );
else
ADD_ROW_VECTOR_5( a, b![ELSPOS], s, from, to );
fi;
m:=Size(b![BDPOS]);
if s>=0 then
for i in [1..Length(a)] do if a[i]>=m then a[i]:=a[i] mod m;fi;od;
else
for i in [1..Length(a)] do if a[i]<0 then a[i]:=a[i] mod m;fi;od;
fi;
end );
InstallMethod( MultVectorLeft,
"for a zmodnz vector, and an object",
[ IsZmodnZVectorRep and IsMutable, IsObject ],
function( v, s )
local i,m;
m:=Size(v![BDPOS]);
if IsZmodnZObj(s) then s:=Int(s);fi;
v:=v![ELSPOS];
MULT_VECTOR_2_FAST(v,s);
if s>=0 then
for i in [1..Length(v)] do if v[i]>=m then v[i]:=v[i] mod m;fi;od;
else
for i in [1..Length(v)] do if v[i]<0 then v[i]:=v[i] mod m;fi;od;
fi;
end );
# The four argument version of MultVectorLeft / ..Right uses the generic
# implementation in matobj.gi
BindGlobal("ZMODNZVECSCAMULT",
function( w, s )
local i,m,t,b,v;
t:=TypeObj(w);
b:=w![BDPOS];
m:=Size(b);
if IsZmodnZObj(s) then s:=Int(s);fi;
v:=PROD_LIST_SCL_DEFAULT(w![ELSPOS],s);
if not IsMutable(v) then
v:=ShallowCopy(v);
fi;
if s>=0 then
for i in [1..Length(v)] do if v[i]>=m then v[i]:=v[i] mod m;fi;od;
else
for i in [1..Length(v)] do if v[i]<0 then v[i]:=v[i] mod m;fi;od;
fi;
if not IsMutable(w![ELSPOS]) then MakeImmutable(v);fi;
return Objectify(t,[b,v]);
end );
InstallMethod( \*, "for a zmodnz vector and a scalar",
[ IsZmodnZVectorRep, IsScalar ],ZMODNZVECSCAMULT);
InstallMethod( \*, "for a scalar and a zmodnz vector",
[ IsScalar, IsZmodnZVectorRep ],
function( s, v )
return ZMODNZVECSCAMULT(v,s);
end );
InstallMethod( \/, "for a zmodnz vector and a scalar",
[ IsZmodnZVectorRep, IsScalar ],
function( v, s )
return ZMODNZVECSCAMULT(v,s^-1);
end );
BindGlobal("ZMODNZVECADDINVCLEANUP",function(m,l)
local i;
if IsMutable(l) then
for i in [1..Length(l)] do if l[i]<0 then l[i]:=l[i] mod m;fi;od;
else
l:=ShallowCopy(l);
for i in [1..Length(l)] do if l[i]<0 then l[i]:=l[i] mod m;fi;od;
MakeImmutable(l);
fi;
return l;
end);
InstallMethod( AdditiveInverseSameMutability, "for a zmodnz vector",
[ IsZmodnZVectorRep ],
function( v )
return Objectify( TypeObj(v),
[v![BDPOS],ZMODNZVECADDINVCLEANUP(Size(v![BDPOS]),
AdditiveInverseSameMutability(v![ELSPOS]))] );
end );
InstallMethod( AdditiveInverseImmutable, "for a zmodnz vector",
[ IsZmodnZVectorRep ],
function( v )
local res;
res := Objectify( TypeObj(v),
[v![BDPOS],ZMODNZVECADDINVCLEANUP(Size(v![BDPOS]),
AdditiveInverseSameMutability(v![ELSPOS]))] );
MakeImmutable(res);
return res;
end );
InstallMethod( AdditiveInverseMutable, "for a zmodnz vector",
[ IsZmodnZVectorRep ],
function( v )
local res;
res := Objectify(TypeObj(v),
[v![BDPOS],ZMODNZVECADDINVCLEANUP(Size(v![BDPOS]),
AdditiveInverseMutable(v![ELSPOS]))]);
if not IsMutable(v) then SetFilterObj(res,IsMutable); fi;
return res;
end );
# redundant according to MH
# InstallMethod( ZeroSameMutability, "for a zmodnz vector", [ IsZmodnZVectorRep ],
# function( v )
# return Objectify(TypeObj(v),[v![BDPOS],ZeroSameMutability(v![ELSPOS])]);
# end );
#
# InstallMethod( ZeroImmutable, "for a zmodnz vector", [ IsZmodnZVectorRep ],
# function( v )
# local res;
# res := Objectify(TypeObj(v),[v![BDPOS],ZeroImmutable(v![ELSPOS])]);
# MakeImmutable(res);
# return res;
# end );
InstallMethod( ZeroMutable, "for a zmodnz vector", [ IsZmodnZVectorRep ],
function( v )
local res;
res := Objectify(TypeObj(v),
[v![BDPOS],ZeroMutable(v![ELSPOS])]);
if not IsMutable(v) then SetFilterObj(res,IsMutable); fi;
return res;
end );
InstallMethod( IsZero, "for a zmodnz vector", [ IsZmodnZVectorRep ],
function( v )
return IsZero( v![ELSPOS] );
end );
#InstallMethodWithRandomSource( Randomize,
# "for a random source and a mutable zmodnz vector",
# [ IsRandomSource, IsZmodnZVectorRep and IsMutable ],
# function( rs, v )
# local bd,i;
# bd := v![BDPOS];
# for i in [1..Length(v![ELSPOS])] do
# v![ELSPOS][i] := Random( rs, bd );
# od;
# return v;
# end );
InstallMethod( CopySubVector, "for two zmodnz vectors and two lists",
[ IsZmodnZVectorRep, IsZmodnZVectorRep and IsMutable, IsList, IsList ],
function( a,b,pa,pb )
# The following should eventually go into the kernel:
if ValueOption( "check" ) <> false and a![BDPOS] <> b![BDPOS] then
Error( "<a> and <b> have different base domains" );
fi;
b![ELSPOS]{pb} := a![ELSPOS]{pa};
end );
InstallOtherMethod( ProductCoeffs,
"zmodmat: call PRODUCT_COEFFS_GENERIC_LISTS with lengths",
true, [ IsZmodnZVectorRep, IsZmodnZVectorRep], 0,
function( l1, l2 )
return PRODUCT_COEFFS_GENERIC_LISTS(l1,Length(l1),l2,Length(l2));
end);
############################################################################
# Matrices
############################################################################
InstallTagBasedMethod( NewMatrix,
IsZmodnZMatrixRep,
function( filter, basedomain, rl, l )
local check, nd, filterVectors, m, e, filter2, i;
check:= ValueOption( "check" ) <> false;
if check and not ( IsZmodnZObjNonprimeCollection( basedomain ) or
( IsFinite( basedomain ) and IsPrimeField( basedomain ) ) ) then
Error( "<basedomain> must be Integers mod <n> for some <n>" );
fi;
# If applicable then replace a flat list 'l' by a nested list
# of lists of length 'rl'.
if Length(l) > 0 and not IsVectorObj(l[1]) then
nd := NestingDepthA(l);
if nd < 2 or nd mod 2 = 1 then
if Length(l) mod rl <> 0 then
Error( "NewMatrix: Length of l is not a multiple of rl" );
fi;
l := List([0,rl..Length(l)-rl], i -> l{[i+1..i+rl]});
fi;
fi;
filterVectors := IsZmodnZVectorRep;
m := 0*[1..Length(l)];
for i in [1..Length(l)] do
if IsVectorObj(l[i]) and IsZmodnZVectorRep(l[i]) then
m[i] := ShallowCopy(l[i]);
else
m[i] := NewVector( filterVectors, basedomain, l[i] );
fi;
od;
e := NewVector(filterVectors, basedomain, []);
m := [basedomain,e,rl,m];
filter2 := IsZmodnZMatrixRep and IsMutable;
if HasCanEasilyCompareElements(Representative(basedomain)) and
CanEasilyCompareElements(Representative(basedomain)) then
filter2 := filter2 and CanEasilyCompareElements;
fi;
Objectify( NewType(CollectionsFamily(FamilyObj(basedomain)),
filter2), m );
return m;
end );
# This is faster than the default method.
InstallTagBasedMethod( NewZeroMatrix,
IsZmodnZMatrixRep,
function( filter, basedomain, rows, cols )
local check, m,i,e,filter2;
check:= ValueOption( "check" ) <> false;
if check and not ( IsZmodnZObjNonprimeCollection( basedomain ) or
( IsFinite( basedomain ) and IsPrimeField( basedomain ) ) ) then
Error( "<basedomain> must be Integers mod <n> for some <n>" );
fi;
filter2 := IsZmodnZVectorRep;
m := 0*[1..rows];
e := NewVector(filter2, basedomain, []);
for i in [1..rows] do
m[i] := ZeroVector( cols, e );
od;
m := [basedomain,e,cols,m];
Objectify( NewType(CollectionsFamily(FamilyObj(basedomain)),
filter and IsMutable), m );
return m;
end );
# This is faster than the default method.
InstallTagBasedMethod( NewIdentityMatrix,
IsZmodnZMatrixRep,
function( filter, basedomain, dim )
local mat, i;
mat := NewZeroMatrix(filter, basedomain, dim, dim);
for i in [1..dim] do
mat[i,i] := 1;
od;
return mat;
end );
InstallOtherMethod( BaseDomain, "for a zmodnz matrix",
[ IsZmodnZMatrixRep ],
function( m )
return m![BDPOS];
end );
InstallMethod( NumberRows, "for a zmodnz matrix",
[ IsZmodnZMatrixRep ],
function( m )
return Length(m![ROWSPOS]);
end );
InstallMethod( NumberColumns, "for a zmodnz matrix",
[ IsZmodnZMatrixRep ],
function( m )
return m![RLPOS];
end );
# InstallMethod( DimensionsMat, "for a zmodnz matrix",
# [ IsZmodnZMatrixRep ],
# function( m )
# return [Length(m![ROWSPOS]),m![RLPOS]];
# end );
############################################################################
# Representation preserving constructors:
############################################################################
# redundant according to MH
# InstallMethod( ZeroMatrix, "for two integers and a zmodnz matrix",
# [ IsInt, IsInt, IsZmodnZMatrixRep ],
# function( rows,cols,m )
# local l,t,res;
# t := m![EMPOS];
# l := List([1..rows],i->ZeroVector(cols,t));
# res := Objectify( TypeObj(m), [m![BDPOS],t,cols,l] );
# if not IsMutable(m) then
# SetFilterObj(res,IsMutable);
# fi;
# return res;
# end );
InstallMethod( IdentityMatrix, "for an integer and a zmodnz matrix",
[ IsInt, IsZmodnZMatrixRep ],
function( rows,m )
local i,l,o,t,res;
t := m![EMPOS];
l := List([1..rows],i->ZeroVector(rows,t));
o := One(m![BDPOS]);
for i in [1..rows] do
l[i][i] := o;
od;
res := Objectify( TypeObj(m), [m![BDPOS],t,rows,l] );
if not IsMutable(m) then
SetFilterObj(res,IsMutable);
fi;
return res;
end );
InstallMethod( Matrix, "for a list and a zmodnz matrix",
[ IsList, IsInt, IsZmodnZMatrixRep ],
function( rows,rowlen,m )
local i,l,nrrows,res,t;
t := m![EMPOS];
if Length(rows) > 0 then
if IsVectorObj(rows[1]) and IsZmodnZVectorRep(rows[1]) then
nrrows := Length(rows);
l := rows;
elif IsList(rows[1]) then
nrrows := Length(rows);
l := ListWithIdenticalEntries(Length(rows),0);
for i in [1..Length(rows)] do
l[i] := Vector(rows[i],t);
od;
else # a flat initializer:
nrrows := Length(rows)/rowlen;
l := ListWithIdenticalEntries(nrrows,0);
for i in [1..nrrows] do
l[i] := Vector(rows{[(i-1)*rowlen+1..i*rowlen]},t);
od;
fi;
else
l := [];
nrrows := 0;
fi;
res := Objectify( TypeObj(m), [m![BDPOS],t,rowlen,l] );
if not IsMutable(m) then
SetFilterObj(res,IsMutable);
fi;
return res;
end );
############################################################################
# Printing and viewing methods:
############################################################################
InstallMethod( ViewObj, "for a zmodnz matrix", [ IsZmodnZMatrixRep ],
function( m )
local l;
Print("<");
if not IsMutable(m) then Print("immutable "); fi;
l:=[Length(m![ROWSPOS]),m![RLPOS]];
if Product(l)<=9 and Product(l)<>0 then
Print("matrix mod ",Size(m![BDPOS]),": ",
List(m![ROWSPOS],x->x![ELSPOS]),">");
else
Print(l[1],"x",l[2],"-matrix mod ",Size(m![BDPOS]),">");
fi;
end );
InstallMethod( PrintObj, "for a zmodnz matrix", [ IsZmodnZMatrixRep ],
function( m )
Print("NewMatrix(IsZmodnZMatrixRep");
if IsFinite(m![BDPOS]) and IsField(m![BDPOS]) then
Print(",GF(",Size(m![BDPOS]),"),");
else
Print(",",String(m![BDPOS]),",");
fi;
Print(NumberColumns(m),",",Unpack(m),")");
end );
InstallMethod( Display, "for a zmodnz matrix", [ IsZmodnZMatrixRep ],
function( m )
Print("<");
if not IsMutable(m) then Print("immutable "); fi;
Print(Length(m![ROWSPOS]),"x",m![RLPOS],"-matrix over ",m![BDPOS],":\n");
Display(List(m![ROWSPOS],x->x![ELSPOS]));
# for i in [1..Length(m![ROWSPOS])] do
# if i = 1 then
# Print("[");
# else
# Print(" ");
# fi;
# Print(m![ROWSPOS][i]![ELSPOS],"\n");
# od;
Print("]>\n");
end );
InstallMethod( String, "for zmodnz matrix", [ IsZmodnZMatrixRep ],
function( m )
local st;
st := "NewMatrix(IsZmodnZMatrixRep";
Add(st,',');
if IsFinite(m![BDPOS]) and IsField(m![BDPOS]) then
Append(st,"GF(");
Append(st,String(Size(m![BDPOS])));
Append(st,"),");
else
Append(st,String(m![BDPOS]));
Append(st,",");
fi;
Append(st,String(NumberColumns(m)));
Add(st,',');
Append(st,String(Unpack(m)));
Add(st,')');
return st;
end );
############################################################################
# A selection of list operations:
############################################################################
InstallOtherMethod( \[\], "for a zmodnz matrix and a positive integer",
#T Once the declaration of '\[\]' for 'IsMatrixObj' disappears,
#T we can use 'InstallMethod'.
[ IsZmodnZMatrixRep, IsPosInt ],
function( m, p )
return m![ROWSPOS][p];
end );
InstallOtherMethod( \[\]\:\=,
"for a zmodnz matrix, a positive integer, and a zmodnz vector",
[ IsZmodnZMatrixRep and IsMutable, IsPosInt, IsZmodnZVectorRep ],
function( m, p, v )
m![ROWSPOS][p] := v;
end );
InstallOtherMethod( \{\}, "for a zmodnz matrix and a list",
[ IsZmodnZMatrixRep, IsList ],
function( m, p )
local l;
l := m![ROWSPOS]{p};
return Objectify(TypeObj(m),[m![BDPOS],m![EMPOS],m![RLPOS],l]);
end );
InstallMethod( Add, "for a zmodnz matrix and a zmodnz vector",
[ IsZmodnZMatrixRep and IsMutable, IsZmodnZVectorRep ],
function( m, v )
Add(m![ROWSPOS],v);
end );
InstallMethod( Add, "for a zmodnz matrix, a zmodnz vector, and a pos. int",
[ IsZmodnZMatrixRep and IsMutable, IsZmodnZVectorRep, IsPosInt ],
function( m, v, p )
Add(m![ROWSPOS],v,p);
end );
InstallMethod( Remove, "for a zmodnz matrix",
[ IsZmodnZMatrixRep and IsMutable ],
m -> Remove( m![ROWSPOS] ) );
InstallMethod( Remove, "for a zmodnz matrix, and a position",
[ IsZmodnZMatrixRep and IsMutable, IsPosInt ],
function( m, p )
Remove( m![ROWSPOS],p );
end );
#T must return the removed row if it was bound
InstallMethod( IsBound\[\], "for a zmodnz matrix, and a position",
[ IsZmodnZMatrixRep, IsPosInt ],
function( m, p )
return p <= Length(m![ROWSPOS]);
end );
InstallMethod( Unbind\[\], "for a zmodnz matrix, and a position",
[ IsZmodnZMatrixRep and IsMutable, IsPosInt ],
function( m, p )
if p <> Length(m![ROWSPOS]) then
ErrorNoReturn("Unbind\\[\\]: Matrices must stay dense, you cannot Unbind here");
fi;
Unbind( m![ROWSPOS][p] );
end );
InstallMethod( \{\}\:\=, "for a zmodnz matrix, a list, and a zmodnz matrix",
[ IsZmodnZMatrixRep and IsMutable, IsList,
IsZmodnZMatrixRep ],
function( m, pp, n )
m![ROWSPOS]{pp} := n![ROWSPOS];
end );
InstallMethod( Append, "for two zmodnz matrices",
[ IsZmodnZMatrixRep and IsMutable, IsZmodnZMatrixRep ],
function( m, n )
Append(m![ROWSPOS],n![ROWSPOS]);
end );
InstallMethod( ShallowCopy, "for a zmodnz matrix",
[ IsZmodnZMatrixRep ],
function( m )
local res;
res := Objectify(TypeObj(m),[m![BDPOS],m![EMPOS],m![RLPOS],
ShallowCopy(m![ROWSPOS])]);
if not IsMutable(m) then
SetFilterObj(res,IsMutable);
fi;
#T 'ShallowCopy' MUST return a mutable object
#T if such an object exists at all!
return res;
end );
InstallMethod( PostMakeImmutable, "for a zmodnz matrix",
[ IsZmodnZMatrixRep ],
function( m )
MakeImmutable( m![ROWSPOS] );
end );
InstallOtherMethod( ListOp, "for a zmodnz matrix",
[ IsZmodnZMatrixRep ],
function( m )
return List(m![ROWSPOS]);
end );
InstallOtherMethod( ListOp, "for a zmodnz matrix and a function",
[ IsZmodnZMatrixRep, IsFunction ],
function( m, f )
return List(m![ROWSPOS],f);
end );
InstallOtherMethod( Unpack, "for a zmodnz matrix",
[ IsZmodnZMatrixRep ],
function( m )
local fam;
fam:=ElementsFamily(FamilyObj(BaseDomain(m)));
return List(m![ROWSPOS],v->
List([1..Length(v![ELSPOS])],x->ZmodnZObj(fam,v![ELSPOS][x])));
end );
InstallMethod( MutableCopyMatrix, "for a zmodnz matrix",
[ IsZmodnZMatrixRep ],
function( m )
local l,res;
l := List(m![ROWSPOS],ShallowCopy);
res := Objectify(TypeObj(m),[m![BDPOS],m![EMPOS],m![RLPOS],l]);
if not IsMutable(m) then
SetFilterObj(res,IsMutable);
fi;
return res;
end);
InstallMethod( ExtractSubMatrix, "for a zmodnz matrix, and two lists",
[ IsZmodnZMatrixRep, IsList, IsList ],
function( m, p, q )
local i,l;
l := m![ROWSPOS]{p};
for i in [1..Length(l)] do
l[i] := Objectify(TypeObj(l[i]),[l[i]![BDPOS],l[i]![ELSPOS]{q}]);
od;
return Objectify(TypeObj(m),[m![BDPOS],m![EMPOS],Length(q),l]);
end );
InstallMethod( CopySubMatrix, "for two zmodnz matrices and four lists",
[ IsZmodnZMatrixRep, IsZmodnZMatrixRep and IsMutable,
IsList, IsList, IsList, IsList ],
function( m, n, srcrows, dstrows, srccols, dstcols )
local i;
if ValueOption( "check" ) <> false and m![BDPOS] <> n![BDPOS] then
Error( "<m> and <n> have different base domains" );
fi;
# This eventually should go into the kernel without creating
# a intermediate objects:
for i in [1..Length(srcrows)] do
n![ROWSPOS][dstrows[i]]![ELSPOS]{dstcols} :=
m![ROWSPOS][srcrows[i]]![ELSPOS]{srccols};
od;
end );
# InstallOtherMethod( CopySubMatrix,
# "for two zmodnzs -- fallback in case of bad rep.",
# [ IsZmodnZRep, IsZmodnZRep and IsMutable,
# IsList, IsList, IsList, IsList ],
# function( m, n, srcrows, dstrows, srccols, dstcols )
# local i;
# # in this representation all access probably has to go through the
# # generic method selection, so it is not clear whether there is an
# # improvement in moving this into the kernel.
# for i in [1..Length(srcrows)] do
# n[dstrows[i]]{dstcols}:=m[srcrows[i]]{srccols};
# od;
# end );
InstallMethod( MatElm, "for a zmodnz matrix and two positions",
[ IsZmodnZMatrixRep, IsPosInt, IsPosInt ],
function( m, row, col )
return ZmodnZObj(ElementsFamily(FamilyObj(m![BDPOS])),
m![ROWSPOS][row]![ELSPOS][col]);
end );
InstallMethod( SetMatElm, "for a zmodnz matrix, two positions, and an object",
[ IsZmodnZMatrixRep and IsMutable, IsPosInt, IsPosInt, IsObject ],
function( m, row, col, ob )
if ValueOption( "check" ) <> false and
not ( IsInt( ob ) or ob in BaseDomain( m ) ) then
Error( "<ob> must be an integer or in the base domain of <m>" );
fi;
m![ROWSPOS][row]![ELSPOS][col] := Int(ob);
end );
############################################################################
# Arithmetical operations:
############################################################################
InstallMethod( \+, "for two zmodnz matrices",
[ IsZmodnZMatrixRep, IsZmodnZMatrixRep ],
function( a, b )
local ty;
if not IsMutable(a) and IsMutable(b) then
ty := TypeObj(b);
else
ty := TypeObj(a);
fi;
return Objectify(ty,[a![BDPOS],a![EMPOS],a![RLPOS],
SUM_LIST_LIST_DEFAULT(a![ROWSPOS],b![ROWSPOS])]);
end );
InstallMethod( \-, "for two zmodnz matrices",
[ IsZmodnZMatrixRep, IsZmodnZMatrixRep ],
function( a, b )
local ty;
if not IsMutable(a) and IsMutable(b) then
ty := TypeObj(b);
else
ty := TypeObj(a);
fi;
return Objectify(ty,[a![BDPOS],a![EMPOS],a![RLPOS],
DIFF_LIST_LIST_DEFAULT(a![ROWSPOS],b![ROWSPOS])]);
end );
InstallMethod( \*, "for two zmodnz matrices",IsIdenticalObj,
[ IsZmodnZMatrixRep, IsZmodnZMatrixRep ],
function( a, b )
# Here we do full checking since it is rather cheap!
local i,j,l,ty,v,w,m,r;
if not IsMutable(a) and IsMutable(b) then
ty := TypeObj(b);
else
ty := TypeObj(a);
fi;
if not a![RLPOS] = Length(b![ROWSPOS]) then
ErrorNoReturn("\\*: Matrices do not fit together");
fi;
if not IsIdenticalObj(a![BDPOS],b![BDPOS]) then
ErrorNoReturn("\\*: Matrices not over same base domain");
fi;
r:=BaseDomain(a);
m:=Size(r);
l := ListWithIdenticalEntries(Length(a![ROWSPOS]),0);
for i in [1..Length(l)] do
if b![RLPOS] = 0 then
l[i] := b![EMPOS];
else
v := a![ROWSPOS][i];
# do arithmetic over Z first and reduce afterwards
w:=ListWithIdenticalEntries(b![RLPOS],0);
v:=v![ELSPOS];
for j in [1..a![RLPOS]] do
AddRowVector(w,b![ROWSPOS][j]![ELSPOS],v[j]);
#if (j mod 1000=0) and not ForAll(w,IsSmallIntRep) then
# ZNZVECREDUCE(w,b![RLPOS],m);
#fi;
od;
ZNZVECREDUCE(w,b![RLPOS],m);
w:=Vector(r,w);
l[i] := w;
fi;
od;
if not IsMutable(a) and not IsMutable(b) then
MakeImmutable(l);
fi;
return Objectify( ty, [a![BDPOS],a![EMPOS],b![RLPOS],l] );
end );
InstallMethod(\*,"for zmodnz matrix and ordinary matrix",IsIdenticalObj,
[IsZmodnZMatrixRep,IsMatrix],
function(a,b)
return Matrix(BaseDomain(a),List(RowsOfMatrix(a),x->x*b));
end);
InstallMethod( \=, "for two zmodnz matrices",IsIdenticalObj,
[ IsZmodnZMatrixRep, IsZmodnZMatrixRep ],
function( a, b )
return EQ_LIST_LIST_DEFAULT(a![ROWSPOS],b![ROWSPOS]);
end );
InstallMethod( \=, "for zmodnz matrix and matrix",IsIdenticalObj,
[ IsZmodnZMatrixRep, IsMatrix ],
function( a, b )
return Unpack(a)=b;
end );
InstallMethod( \=, "for matrix and zmodnz matrix",IsIdenticalObj,
[ IsMatrix, IsZmodnZMatrixRep ],
function( a, b )
return a=Unpack(b);
end );
InstallMethod( \<, "for two zmodnz matrices",IsIdenticalObj,
[ IsZmodnZMatrixRep, IsZmodnZMatrixRep ],
function( a, b )
return LT_LIST_LIST_DEFAULT(a![ROWSPOS],b![ROWSPOS]);
end );
InstallMethod( AdditiveInverseSameMutability, "for a zmodnz matrix",
[ IsZmodnZMatrixRep ],
function( m )
local l;
l := List(m![ROWSPOS],AdditiveInverseSameMutability);
if not IsMutable(m) then
MakeImmutable(l);
fi;
return Objectify( TypeObj(m), [m![BDPOS],m![EMPOS],m![RLPOS],l] );
end );
InstallMethod( AdditiveInverseImmutable, "for a zmodnz matrix",
[ IsZmodnZMatrixRep ],
function( m )
local l,res;
l := List(m![ROWSPOS],AdditiveInverseImmutable);
res := Objectify( TypeObj(m), [m![BDPOS],m![EMPOS],m![RLPOS],l] );
MakeImmutable(res);
return res;
end );
InstallMethod( AdditiveInverseMutable, "for a zmodnz matrix",
[ IsZmodnZMatrixRep ],
function( m )
local l,res;
l := List(m![ROWSPOS],AdditiveInverseMutable);
res := Objectify( TypeObj(m), [m![BDPOS],m![EMPOS],m![RLPOS],l] );
if not IsMutable(m) then
SetFilterObj(res,IsMutable);
fi;
return res;
end );
InstallMethod( ZeroSameMutability, "for a zmodnz matrix",
[ IsZmodnZMatrixRep ],
function( m )
local l;
l := List(m![ROWSPOS],ZeroSameMutability);
if not IsMutable(m) then
MakeImmutable(l);
fi;
return Objectify( TypeObj(m), [m![BDPOS],m![EMPOS],m![RLPOS],l] );
end );
InstallMethod( ZeroImmutable, "for a zmodnz matrix",
[ IsZmodnZMatrixRep ],
function( m )
local l,res;
l := List(m![ROWSPOS],ZeroImmutable);
res := Objectify( TypeObj(m), [m![BDPOS],m![EMPOS],m![RLPOS],l] );
MakeImmutable(res);
return res;
end );
InstallMethod( ZeroMutable, "for a zmodnz matrix",
[ IsZmodnZMatrixRep ],
function( m )
local l,res;
l := List(m![ROWSPOS],ZeroMutable);
res := Objectify( TypeObj(m), [m![BDPOS],m![EMPOS],m![RLPOS],l] );
if not IsMutable(m) then
SetFilterObj(res,IsMutable);
fi;
return res;
end );
InstallMethod( IsZero, "for a zmodnz matrix",
[ IsZmodnZMatrixRep ],
function( m )
local i;
for i in [1..Length(m![ROWSPOS])] do
if not IsZero(m![ROWSPOS][i]) then
return false;
fi;
od;
return true;
end );
InstallMethod( IsOne, "for a zmodnz matrix",
[ IsZmodnZMatrixRep ],
function( m )
local i,j,n;
if Length(m![ROWSPOS]) <> m![RLPOS] then
#Error("IsOne: Matrix must be square");
return false;
fi;
n := m![RLPOS];
for i in [1..n] do
if not IsOne(m![ROWSPOS][i]![ELSPOS][i]) then return false; fi;
for j in [1..i-1] do
if not IsZero(m![ROWSPOS][i]![ELSPOS][j]) then return false; fi;
od;
for j in [i+1..n] do
if not IsZero(m![ROWSPOS][i]![ELSPOS][j]) then return false; fi;
od;
od;
return true;
end );
InstallMethod( OneSameMutability, "for a zmodnz matrix",
[ IsZmodnZMatrixRep ],
function( m )
local o;
if m![RLPOS] <> Length(m![ROWSPOS]) then
#Error("OneSameMutability: Matrix is not square");
#return;
return fail;
fi;
o := IdentityMatrix(m![RLPOS],m);
if not IsMutable(m) then
MakeImmutable(o);
fi;
return o;
end );
InstallMethod( OneMutable, "for a zmodnz matrix",
[ IsZmodnZMatrixRep ],
function( m )
if m![RLPOS] <> Length(m![ROWSPOS]) then
#Error("OneMutable: Matrix is not square");
#return;
return fail;
fi;
return IdentityMatrix(m![RLPOS],m);
end );
InstallMethod( OneImmutable, "for a zmodnz matrix",
[ IsZmodnZMatrixRep ],
function( m )
local o;
if m![RLPOS] <> Length(m![ROWSPOS]) then
#Error("OneImmutable: Matrix is not square");
#return;
return fail;
fi;
o := IdentityMatrix(m![RLPOS],m);
MakeImmutable(o);
return o;
end );
# For the moment we delegate to the fast kernel arithmetic for plain
# lists of plain lists:
InstallMethod( InverseMutable, "for a zmodnz matrix",
[ IsZmodnZMatrixRep ],
function( m )
local n,modulus;
modulus:=Size(BaseDomain(m));
if m![RLPOS] <> Length(m![ROWSPOS]) then
#Error("InverseMutable: Matrix is not square");
#return;
return fail;
fi;
# Make a plain list of lists:
n := List(m![ROWSPOS],x->x![ELSPOS]);
n := InverseMutable(n); # Invert!
if n = fail then return fail; fi;
n:=List(n,x->List(x,y->y mod modulus));
return Matrix(n,Length(n),m);
end );
InstallMethod( InverseImmutable, "for a zmodnz matrix",
[ IsZmodnZMatrixRep ],
function( m )
local n,modulus;
modulus:=Size(BaseDomain(m));
if m![RLPOS] <> Length(m![ROWSPOS]) then
#Error("InverseMutable: Matrix is not square");
#return;
return fail;
fi;
# Make a plain list of lists:
n := List(m![ROWSPOS],x->x![ELSPOS]);
n := InverseMutable(n); # Invert!
if n = fail then return fail; fi;
n:=List(n,x->List(x,y->y mod modulus));
n := Matrix(n,Length(n),m);
MakeImmutable(n);
return n;
end );
InstallMethod( InverseSameMutability, "for a zmodnz matrix",
[ IsZmodnZMatrixRep ],
function( m )
local n,modulus;
modulus:=Size(BaseDomain(m));
if m![RLPOS] <> Length(m![ROWSPOS]) then
#Error("InverseMutable: Matrix is not square");
#return;
return fail;
fi;
# Make a plain list of lists:
n := List(m![ROWSPOS],x->x![ELSPOS]);
n := InverseMutable(n); # Invert!
if n = fail then return fail; fi;
n:=List(n,x->List(x,y->y mod modulus));
n := Matrix(n,Length(n),m);
if not IsMutable(m) then
MakeImmutable(n);
fi;
return n;
end );
InstallMethod( RankMat, "for a zmodnz matrix", [ IsZmodnZMatrixRep ],
function( m )
m:=MutableCopyMatrix(m);
m:=SemiEchelonMatDestructive(m);
if m<>fail then m:=Length(m.vectors);fi;
return m;
end);
#InstallMethodWithRandomSource( Randomize,
# "for a random source and a mutable zmodnz matrix",
# [ IsRandomSource, IsZmodnZMatrixRep and IsMutable ],
# function( rs, m )
# local v;
# for v in m![ROWSPOS] do
# Randomize( rs, v );
# od;
# return m;
# end );
InstallMethod( TransposedMatMutable, "for a zmodnz matrix",
[ IsZmodnZMatrixRep ],
function( m )
local i,n,v;
n := ListWithIdenticalEntries(m![RLPOS],0);
for i in [1..m![RLPOS]] do
v := Vector(List(m![ROWSPOS],v->v![ELSPOS][i]),m![EMPOS]);
n[i] := v;
od;
return Objectify(TypeObj(m),[m![BDPOS],m![EMPOS],Length(m![ROWSPOS]),n]);
end );
InstallMethod( TransposedMatImmutable, "for a zmodnz matrix",
[ IsZmodnZMatrixRep ],
function( m )
local n;
n := TransposedMatMutable(m);
MakeImmutable(n);
return n;
end );
BindGlobal( "ZMZVECMAT", function( v, m )
local i,res,s,r;
r:=BaseDomain(v);
# do arithmetic over Z first so that we reduce only once
res:=ListWithIdenticalEntries(m![RLPOS],0);
for i in [1..Length(v![ELSPOS])] do
s := v![ELSPOS][i];
if not IsZero(s) then
AddRowVector(res,m![ROWSPOS][i]![ELSPOS],s);
#if (i mod 100=0) and not ForAll(res,IsSmallIntRep) then
# ZNZVECREDUCE(res,Length(res),Size(r));
#fi;
fi;
od;
ZNZVECREDUCE(res,Length(res),Size(r));
res:=Vector(r,res);
if not IsMutable(v) and not IsMutable(m) then
MakeImmutable(res);
fi;
return res;
end );
InstallMethod( \*, "for a zmodnz vector and a zmodnz matrix",
IsElmsColls, [ IsZmodnZVectorRep, IsZmodnZMatrixRep ],
ZMZVECMAT);
InstallOtherMethod( \^, "for a zmodnz vector and a zmodnz matrix",
IsElmsColls, [ IsZmodnZVectorRep, IsZmodnZMatrixRep ],
ZMZVECMAT);
BindGlobal( "PLISTVECZMZMAT", function( v, m )
local i,res,s,r;
r:=BaseDomain(m);
# do arithmetic over Z first so that we reduce only once
res:=ListWithIdenticalEntries(m![RLPOS],0);
for i in [1..Length(v)] do
s := v[i];
if not IsZero(s) then
AddRowVector(res,m![ROWSPOS][i]![ELSPOS],Int(s));
#if (i mod 100=0) and not ForAll(res,IsSmallIntRep) then
# ZNZVECREDUCE(res,Length(res),Size(r));
#fi;
fi;
od;
ZNZVECREDUCE(res,Length(res),Size(r));
res:=Vector(r,res);
if not IsMutable(v) and not IsMutable(m) then
MakeImmutable(res);
fi;
return res;
end );
InstallOtherMethod( \*, "for a plist vector and a zmodnz matrix",
IsElmsColls, [ IsList, IsZmodnZMatrixRep ],
PLISTVECZMZMAT);
InstallOtherMethod( \^, "for a plist vector and a zmodnz matrix",
IsElmsColls, [ IsList, IsZmodnZMatrixRep ],
PLISTVECZMZMAT);
BindGlobal( "ZMZVECTIMESPLISTMAT", function( v, m )
local i,res,s,r;
r:=BaseDomain(v);
# do arithmetic over Z first so that we reduce only once
res:=ListWithIdenticalEntries(Length(m[1]),Zero(r));
for i in [1..Length(v)] do
s := v[i];
if not IsZero(s) then
AddRowVector(res,m[i],s);
fi;
od;
res:=Vector(r,res);
if not IsMutable(v) and not IsMutable(m) then
MakeImmutable(res);
fi;
return res;
end );
InstallOtherMethod( \*, "for a zmodnz vector and plist matrix",
IsElmsColls, [ IsZmodnZVectorRep, IsMatrix ],
ZMZVECTIMESPLISTMAT);
InstallOtherMethod( \^, "for a zmodnz vector and plist matrix",
IsElmsColls, [ IsZmodnZVectorRep, IsMatrix ],
ZMZVECTIMESPLISTMAT);
InstallMethod( CompatibleVector, "for a zmodnz matrix",
[ IsZmodnZMatrixRep ],
function( v )
return NewZeroVector(IsZmodnZVectorRep,BaseDomain(v),NumberRows(v));
end );
InstallMethod( DeterminantMat, "for a zmodnz matrix", [ IsZmodnZMatrixRep ],
function( a )
local m;
m:=Size(BaseDomain(a));
a:=List(a![ROWSPOS],x->x![ELSPOS]);
return ZmodnZObj(DeterminantMat(a),m);
end );
# Minimal/Characteristic Polynomial stuff
#############################################################################
##
## Variant of
#F Matrix_OrderPolynomialInner( <fld>, <mat>, <vec>, <spannedspace> )
##
BindGlobal( "ZModnZMOPI",function( fld, mat, vec, vecs)
local d, w, p, one, zero, zeroes, piv, pols, x, t,i;
Info(InfoMatrix,3,"Order Polynomial Inner on ",NrRows(mat),
" x ",NrCols(mat)," matrix over ",fld," with ",
Number(vecs)," basis vectors already given");
d := Length(vec);
pols := [];
one := One(fld);
zero := Zero(fld);
zeroes := [];
# this loop runs images of <vec> under powers of <mat>
# trying to reduce them with smaller powers (and tracking the polynomial)
# or with vectors from <spannedspace> as passed in
# when we succeed, we know the order polynomial
repeat
w := ShallowCopy(vec);
p := ShallowCopy(zeroes);
Add(p,one);
#p:=ZmodnZVec(fam,p);
p:=Vector(fld,p);
piv := PositionNonZero(w,0);
#
# Strip as far as we can
#
while piv <= d and IsBound(vecs[piv]) do
x := -w[piv];
if IsBound(pols[piv]) then
#AddCoeffs(p, pols[piv], x);
#p:=p+pols[piv]*x;
t:=pols[piv]*x;
for i in [1..Length(t)] do
p[i]:=p[i]+t[i];
od;
fi;
AddRowVector(w, vecs[piv], x, piv, d);
#w:=w+vecs[piv]*x;
piv := PositionNonZero(w,piv);
od;
#
# if something is left then we don't have the order poly yet
# update tables etc.
#
if piv <=d then
x := Inverse(w[piv]);
MultVector(p, x);
#p:=p*x;
#MakeImmutable(p);
pols[piv] := p;
MultVector(w, x );
#w:=w*x;
#MakeImmutable(w);
vecs[piv] := w;
vec := vec*mat;
Add(zeroes,zero);
fi;
until piv > d;
MakeImmutable(p);
Info(InfoMatrix,3,"Order Polynomial returns ",p);
return p;
end );
InstallOtherMethod( MinimalPolynomial, "ZModnZ, spinning over field",
IsElmsCollsX,
[ IsField and IsFinite, IsMatrixObj, IsPosInt ],
function( fld, mat, ind )
local i, n, base, vec, one, fam,
mp, dim, span,op,w, piv,j;
Info(InfoMatrix,1,"Minimal Polynomial called on ",
NrRows(mat)," x ",NrCols(mat)," matrix over ",fld);
n := NrRows(mat);
base := [];
dim := 0; # should be number of bound positions in base
one := One(fld);
fam := ElementsFamily(FamilyObj(fld));
mp:=[one];
#keep coeffs
#mp := UnivariatePolynomialByCoefficients( fam, mp,ind);
while dim < n do
vec:=ZeroVector(n,mat[1]);
for i in [1..n] do
if (not IsBound(base[i])) and Random([0,1])=1 then vec[i]:=one;fi;
od;
if IsZero(vec) then
vec[Random(1,n)] := one; # make sure it's not zero
fi;
span := [];
op := ZModnZMOPI( fld, mat, vec, span);
op:=List(op);
mp:=QUOTREM_LAURPOLS_LISTS(ProductCoeffs(mp,op),GcdCoeffs(mp,AsList(op)))[1];
mp:=mp/Last(mp);
Info(InfoMatrix,2,"So Far ",dim,", Span=",Length(span));
for j in [1..Length(span)] do
if IsBound(span[j]) then
if dim < n then
if not IsBound(base[j]) then
base[j] := span[j];
dim := dim+1;
else
w := ShallowCopy(span[j]);
piv := j;
repeat
AddRowVector(w,base[piv],-w[piv], piv, n);
piv := PositionNonZero(w, piv);
until piv > n or not IsBound(base[piv]);
if piv <= n then
#MultVector(w,Inverse(w[piv]));
w:=w*Inverse(w[piv]);
#MakeImmutable(w);
base[piv] := w;
dim := dim+1;
fi;
fi;
fi;
fi;
od;
od;
mp := UnivariatePolynomialByCoefficients( fam, mp,ind);
Assert(3, IsZero(Value(mp,mat)));
Info(InfoMatrix,1,"Minimal Polynomial returns ", mp);
return mp;
end);
InstallOtherMethod( CharacteristicPolynomialMatrixNC, "zmodnz spinning over field",
IsElmsCollsX,
[ IsField, IsMatrixObj, IsPosInt ], function( fld, mat, ind)
local i, n, base, imat, vec, one,cp,op,zero,fam;
Info(InfoMatrix,1,"Characteristic Polynomial called on ",
NrRows(mat)," x ",NrCols(mat)," matrix over ",fld);
imat := ImmutableMatrix(fld,mat);
n := NrRows(mat);
base := [];
vec := ZeroOp(mat[1]);
one := One(fld);
zero := Zero(fld);
fam := ElementsFamily(FamilyObj(fld));
cp:=[one];
cp := UnivariatePolynomialByCoefficients(fam,cp,ind);
for i in [1..n] do
if not IsBound(base[i]) then
vec[i] := one;
op := Unpack(ZModnZMOPI( fld, imat, vec, base));
cp := cp * UnivariatePolynomialByCoefficients( fam,op,ind);
vec[i] := zero;
fi;
od;
Assert(2, Length(CoefficientsOfUnivariatePolynomial(cp)) = n+1);
if AssertionLevel()>=3 then
# cannot use Value(cp,imat), as this uses characteristic polynomial
n:=Zero(imat);
one:=One(imat);
for i in Reversed(CoefficientsOfUnivariatePolynomial(cp)) do
n:=n*imat+(i*one);
od;
Assert(3,IsZero(n));
fi;
Info(InfoMatrix,1,"Characteristic Polynomial returns ", cp);
return cp;
end );
##
InstallOtherMethod( DegreeFFE,
[ "IsZmodnZVectorRep" ],
function(vec)
# TODO: check that modulus is a prime
return 1;
end);
InstallOtherMethod( DegreeFFE,
[ "IsZmodnZMatrixRep" ],
function(vec)
# TODO: check that modulus is a prime
return 1;
end);
[ Dauer der Verarbeitung: 0.44 Sekunden
(vorverarbeitet)
]
|