GAP 4.8.9 installation with standard packages -- copy to your CoCalc project to get it
#############################################################################
##
## Tools.gi MatricesForHomalg package Mohamed Barakat
##
## Copyright 2007-2008 Lehrstuhl B für Mathematik, RWTH Aachen
##
## Implementations of homalg tools.
##
#############################################################################
####################################
#
# methods for operations (you MUST replace for an external CAS):
#
####################################
################################
##
## operations for ring elements:
##
################################
##
InstallMethod( Zero,
"for homalg rings",
[ IsHomalgRing ], 10001,
function( R )
local RP;
RP := homalgTable( R );
if IsBound(RP!.Zero) then
if IsFunction( RP!.Zero ) then
return RP!.Zero( R );
else
return RP!.Zero;
fi;
fi;
TryNextMethod( );
end );
##
InstallMethod( One,
"for homalg rings",
[ IsHomalgRing ], 1001,
function( R )
local RP;
RP := homalgTable( R );
if IsBound(RP!.One) then
if IsFunction( RP!.One ) then
return RP!.One( R );
else
return RP!.One;
fi;
fi;
TryNextMethod( );
end );
##
InstallMethod( MinusOne,
"for homalg rings",
[ IsHomalgRing ],
function( R )
local RP;
RP := homalgTable( R );
if IsBound(RP!.MinusOne) then
if IsFunction( RP!.MinusOne ) then
return RP!.MinusOne( R );
else
return RP!.MinusOne;
fi;
fi;
TryNextMethod( );
end );
##
InstallMethod( IsZero,
"for homalg ring elements",
[ IsHomalgRingElement ],
function( r )
local R, RP;
R := HomalgRing( r );
RP := homalgTable( R );
if IsBound(RP!.IsZero) then
return RP!.IsZero( r );
fi;
TryNextMethod( );
end );
##
InstallMethod( IsOne,
"for homalg ring elements",
[ IsHomalgRingElement ],
function( r )
local R, RP;
R := HomalgRing( r );
RP := homalgTable( R );
if IsBound(RP!.IsOne) then
return RP!.IsOne( r );
fi;
TryNextMethod( );
end );
##
InstallMethod( IsMinusOne,
"for ring elements",
[ IsRingElement ],
function( r )
return IsZero( r + One( r ) );
end );
## a synonym of `-<elm>':
InstallMethod( AdditiveInverseMutable,
"for homalg rings elements",
[ IsHomalgRingElement ],
function( r )
local R, RP;
R := HomalgRing( r );
if not HasRingElementConstructor( R ) then
Error( "no ring element constructor found in the ring\n" );
fi;
RP := homalgTable( R );
if IsBound(RP!.Minus) and IsBound(RP!.Zero) and HasRingElementConstructor( R ) then
return RingElementConstructor( R )( RP!.Minus( Zero( R ), r ), R );
fi;
## never fall back to:
## return Zero( r ) - r;
## this will cause an infinite loop with a method for \- in LIRNG.gi
TryNextMethod( );
end );
##
InstallMethod( \/,
"for homalg ring elements",
[ IsHomalgRingElement, IsHomalgRingElement ],
function( a, u )
local R, RP, au;
R := HomalgRing( a );
if not HasRingElementConstructor( R ) then
Error( "no ring element constructor found in the ring\n" );
fi;
RP := homalgTable( R );
if IsBound(RP!.DivideByUnit) and IsUnit( u ) then
au := RP!.DivideByUnit( a, u );
if au = fail then
return fail;
fi;
return RingElementConstructor( R )( au, R );
fi;
au := RightDivide( HomalgMatrix( [ a ], 1, 1, R ), HomalgMatrix( [ u ], 1, 1, R ) );
if not IsHomalgMatrix( au ) then
return fail;
fi;
return MatElm( au, 1, 1 );
end );
###########################
##
## operations for matrices:
##
###########################
## <#GAPDoc Label="IsZeroMatrix:homalgTable_entry">
## <ManSection>
## <Func Arg="M" Name="IsZeroMatrix" Label="homalgTable entry"/>
## <Returns><C>true</C> or <C>false</C></Returns>
## <Description>
## Let <M>R :=</M> <C>HomalgRing</C><M>( <A>M</A> )</M> and <M>RP :=</M> <C>homalgTable</C><M>( R )</M>.
## If the <C>homalgTable</C> component <M>RP</M>!.<C>IsZeroMatrix</C> is bound then the standard method
## for the property <Ref Prop="IsZero" Label="for matrices"/> shown below returns
## <M>RP</M>!.<C>IsZeroMatrix</C><M>( <A>M</A> )</M>.
## <Listing Type="Code"><![CDATA[
InstallMethod( IsZero,
"for homalg matrices",
[ IsHomalgMatrix ],
function( M )
local R, RP;
R := HomalgRing( M );
RP := homalgTable( R );
if IsBound(RP!.IsZeroMatrix) then
## CAUTION: the external system must be able
## to check zero modulo possible ring relations!
return RP!.IsZeroMatrix( M ); ## with this, \= can fall back to IsZero
fi;
#=====# the fallback method #=====#
## from the GAP4 documentation: ?Zero
## `ZeroSameMutability( <obj> )' is equivalent to `0 * <obj>'.
return M = 0 * M; ## hence, by default, IsZero falls back to \= (see below)
end );
## ]]></Listing>
## </Description>
## </ManSection>
## <#/GAPDoc>
##----------------------
## the methods for Eval:
##----------------------
## <#GAPDoc Label="Eval:IsInitialMatrix">
## <ManSection>
## <Meth Arg="C" Name="Eval" Label="for matrices created with HomalgInitialMatrix"/>
## <Returns>the <C>Eval</C> value of a &homalg; matrix <A>C</A></Returns>
## <Description>
## In case the matrix <A>C</A> was created using
## <Ref Meth="HomalgInitialMatrix" Label="constructor for initial matrices filled with zeros"/>
## then the filter <C>IsInitialMatrix</C> for <A>C</A> is set to true and the <C>homalgTable</C> function
## (&see; <Ref Meth="InitialMatrix" Label="homalgTable entry for initial matrices"/>)
## will be used to set the attribute <C>Eval</C> and resets the filter <C>IsInitialMatrix</C>.
## <Listing Type="Code"><![CDATA[
InstallMethod( Eval,
"for homalg matrices (IsInitialMatrix)",
[ IsHomalgMatrix and IsInitialMatrix and
HasNrRows and HasNrColumns ],
function( C )
local R, RP, z, zz;
R := HomalgRing( C );
RP := homalgTable( R );
if IsBound( RP!.InitialMatrix ) then
ResetFilterObj( C, IsInitialMatrix );
return RP!.InitialMatrix( C );
fi;
if not IsHomalgInternalMatrixRep( C ) then
Error( "could not find a procedure called InitialMatrix in the ",
"homalgTable to evaluate a non-internal initial matrix\n" );
fi;
#=====# can only work for homalg internal matrices #=====#
z := Zero( HomalgRing( C ) );
ResetFilterObj( C, IsInitialMatrix );
zz := ListWithIdenticalEntries( NrColumns( C ), z );
return homalgInternalMatrixHull(
List( [ 1 .. NrRows( C ) ], i -> ShallowCopy( zz ) ) );
end );
## ]]></Listing>
## </Description>
## </ManSection>
## <#/GAPDoc>
## <#GAPDoc Label="InitialMatrix:homalgTable_entry">
## <ManSection>
## <Func Arg="C" Name="InitialMatrix" Label="homalgTable entry for initial matrices"/>
## <Returns>the <C>Eval</C> value of a &homalg; matrix <A>C</A></Returns>
## <Description>
## Let <M>R :=</M> <C>HomalgRing</C><M>( <A>C</A> )</M> and <M>RP :=</M> <C>homalgTable</C><M>( R )</M>.
## If the <C>homalgTable</C> component <M>RP</M>!.<C>InitialMatrix</C> is bound then the method
## <Ref Meth="Eval" Label="for matrices created with HomalgInitialMatrix"/>
## resets the filter <C>IsInitialMatrix</C> and returns <M>RP</M>!.<C>InitialMatrix</C><M>( <A>C</A> )</M>.
## </Description>
## </ManSection>
## <#/GAPDoc>
## <#GAPDoc Label="Eval:IsInitialIdentityMatrix">
## <ManSection>
## <Meth Arg="C" Name="Eval" Label="for matrices created with HomalgInitialIdentityMatrix"/>
## <Returns>the <C>Eval</C> value of a &homalg; matrix <A>C</A></Returns>
## <Description>
## In case the matrix <A>C</A> was created using
## <Ref Meth="HomalgInitialIdentityMatrix" Label="constructor for initial quadratic matrices with ones on the diagonal"/>
## then the filter <C>IsInitialIdentityMatrix</C> for <A>C</A> is set to true and the <C>homalgTable</C> function
## (&see; <Ref Meth="InitialIdentityMatrix" Label="homalgTable entry for initial identity matrices"/>)
## will be used to set the attribute <C>Eval</C> and resets the filter <C>IsInitialIdentityMatrix</C>.
## <Listing Type="Code"><![CDATA[
InstallMethod( Eval,
"for homalg matrices (IsInitialIdentityMatrix)",
[ IsHomalgMatrix and IsInitialIdentityMatrix and
HasNrRows and HasNrColumns ],
function( C )
local R, RP, o, z, zz, id;
R := HomalgRing( C );
RP := homalgTable( R );
if IsBound( RP!.InitialIdentityMatrix ) then
ResetFilterObj( C, IsInitialIdentityMatrix );
return RP!.InitialIdentityMatrix( C );
fi;
if not IsHomalgInternalMatrixRep( C ) then
Error( "could not find a procedure called InitialIdentityMatrix in the ",
"homalgTable to evaluate a non-internal initial identity matrix\n" );
fi;
#=====# can only work for homalg internal matrices #=====#
z := Zero( HomalgRing( C ) );
o := One( HomalgRing( C ) );
ResetFilterObj( C, IsInitialIdentityMatrix );
zz := ListWithIdenticalEntries( NrColumns( C ), z );
id := List( [ 1 .. NrRows( C ) ],
function(i)
local z;
z := ShallowCopy( zz ); z[i] := o; return z;
end );
return homalgInternalMatrixHull( id );
end );
## ]]></Listing>
## </Description>
## </ManSection>
## <#/GAPDoc>
## <#GAPDoc Label="InitialIdentityMatrix:homalgTable_entry">
## <ManSection>
## <Func Arg="C" Name="InitialIdentityMatrix" Label="homalgTable entry for initial identity matrices"/>
## <Returns>the <C>Eval</C> value of a &homalg; matrix <A>C</A></Returns>
## <Description>
## Let <M>R :=</M> <C>HomalgRing</C><M>( <A>C</A> )</M> and <M>RP :=</M> <C>homalgTable</C><M>( R )</M>.
## If the <C>homalgTable</C> component <M>RP</M>!.<C>InitialIdentityMatrix</C> is bound then the method
## <Ref Meth="Eval" Label="for matrices created with HomalgInitialIdentityMatrix"/>
## resets the filter <C>IsInitialIdentityMatrix</C> and returns <M>RP</M>!.<C>InitialIdentityMatrix</C><M>( <A>C</A> )</M>.
## </Description>
## </ManSection>
## <#/GAPDoc>
##
InstallMethod( Eval,
"for homalg matrices (HasEvalMatrixOperation)",
[ IsHomalgMatrix and HasEvalMatrixOperation ],
function( C )
local func_arg;
func_arg := EvalMatrixOperation( C );
ResetFilterObj( C, EvalMatrixOperation );
## delete the component which was left over by GAP
Unbind( C!.EvalMatrixOperation );
return CallFuncList( func_arg[1], func_arg[2] );
end );
## <#GAPDoc Label="Eval:HasEvalInvolution">
## <ManSection>
## <Meth Arg="C" Name="Eval" Label="for matrices created with Involution"/>
## <Returns>the <C>Eval</C> value of a &homalg; matrix <A>C</A></Returns>
## <Description>
## In case the matrix was created using
## <Ref Meth="Involution" Label="for matrices"/>
## then the filter <C>HasEvalInvolution</C> for <A>C</A> is set to true and the <C>homalgTable</C> function
## <Ref Meth="Involution" Label="homalgTable entry"/>
## will be used to set the attribute <C>Eval</C>.
## <Listing Type="Code"><![CDATA[
InstallMethod( Eval,
"for homalg matrices (HasEvalInvolution)",
[ IsHomalgMatrix and HasEvalInvolution ],
function( C )
local R, RP, M;
R := HomalgRing( C );
RP := homalgTable( R );
M := EvalInvolution( C );
if IsBound(RP!.Involution) then
return RP!.Involution( M );
fi;
if not IsHomalgInternalMatrixRep( C ) then
Error( "could not find a procedure called Involution ",
"in the homalgTable of the non-internal ring\n" );
fi;
#=====# can only work for homalg internal matrices #=====#
return homalgInternalMatrixHull( TransposedMat( Eval( M )!.matrix ) );
end );
## ]]></Listing>
## </Description>
## </ManSection>
## <#/GAPDoc>
## <#GAPDoc Label="Involution:homalgTable_entry">
## <ManSection>
## <Func Arg="M" Name="Involution" Label="homalgTable entry"/>
## <Returns>the <C>Eval</C> value of a &homalg; matrix <A>C</A></Returns>
## <Description>
## Let <M>R :=</M> <C>HomalgRing</C><M>( <A>C</A> )</M> and <M>RP :=</M> <C>homalgTable</C><M>( R )</M>.
## If the <C>homalgTable</C> component <M>RP</M>!.<C>Involution</C> is bound then
## the method <Ref Meth="Eval" Label="for matrices created with Involution"/> returns
## <M>RP</M>!.<C>Involution</C> applied to the content of the attribute <C>EvalInvolution</C><M>( <A>C</A> ) = <A>M</A></M>.
## </Description>
## </ManSection>
## <#/GAPDoc>
## <#GAPDoc Label="Eval:HasEvalCertainRows">
## <ManSection>
## <Meth Arg="C" Name="Eval" Label="for matrices created with CertainRows"/>
## <Returns>the <C>Eval</C> value of a &homalg; matrix <A>C</A></Returns>
## <Description>
## In case the matrix was created using
## <Ref Meth="CertainRows" Label="for matrices"/>
## then the filter <C>HasEvalCertainRows</C> for <A>C</A> is set to true and the <C>homalgTable</C> function
## <Ref Meth="CertainRows" Label="homalgTable entry"/>
## will be used to set the attribute <C>Eval</C>.
## <Listing Type="Code"><![CDATA[
InstallMethod( Eval,
"for homalg matrices (HasEvalCertainRows)",
[ IsHomalgMatrix and HasEvalCertainRows ],
function( C )
local R, RP, e, M, plist;
R := HomalgRing( C );
RP := homalgTable( R );
e := EvalCertainRows( C );
M := e[1];
plist := e[2];
if IsBound(RP!.CertainRows) then
return RP!.CertainRows( M, plist );
fi;
if not IsHomalgInternalMatrixRep( C ) then
Error( "could not find a procedure called CertainRows ",
"in the homalgTable of the non-internal ring\n" );
fi;
#=====# can only work for homalg internal matrices #=====#
return homalgInternalMatrixHull( Eval( M )!.matrix{ plist } );
end );
## ]]></Listing>
## </Description>
## </ManSection>
## <#/GAPDoc>
## <#GAPDoc Label="CertainRows:homalgTable_entry">
## <ManSection>
## <Func Arg="M, plist" Name="CertainRows" Label="homalgTable entry"/>
## <Returns>the <C>Eval</C> value of a &homalg; matrix <A>C</A></Returns>
## <Description>
## Let <M>R :=</M> <C>HomalgRing</C><M>( <A>C</A> )</M> and <M>RP :=</M> <C>homalgTable</C><M>( R )</M>.
## If the <C>homalgTable</C> component <M>RP</M>!.<C>CertainRows</C> is bound then
## the method <Ref Meth="Eval" Label="for matrices created with CertainRows"/> returns
## <M>RP</M>!.<C>CertainRows</C> applied to the content of the attribute
## <C>EvalCertainRows</C><M>( <A>C</A> ) = [ <A>M</A>, <A>plist</A> ]</M>.
## </Description>
## </ManSection>
## <#/GAPDoc>
## <#GAPDoc Label="Eval:HasEvalCertainColumns">
## <ManSection>
## <Meth Arg="C" Name="Eval" Label="for matrices created with CertainColumns"/>
## <Returns>the <C>Eval</C> value of a &homalg; matrix <A>C</A></Returns>
## <Description>
## In case the matrix was created using
## <Ref Meth="CertainColumns" Label="for matrices"/>
## then the filter <C>HasEvalCertainColumns</C> for <A>C</A> is set to true and the <C>homalgTable</C> function
## <Ref Meth="CertainColumns" Label="homalgTable entry"/>
## will be used to set the attribute <C>Eval</C>.
## <Listing Type="Code"><![CDATA[
InstallMethod( Eval,
"for homalg matrices (HasEvalCertainColumns)",
[ IsHomalgMatrix and HasEvalCertainColumns ],
function( C )
local R, RP, e, M, plist;
R := HomalgRing( C );
RP := homalgTable( R );
e := EvalCertainColumns( C );
M := e[1];
plist := e[2];
if IsBound(RP!.CertainColumns) then
return RP!.CertainColumns( M, plist );
fi;
if not IsHomalgInternalMatrixRep( C ) then
Error( "could not find a procedure called CertainColumns ",
"in the homalgTable of the non-internal ring\n" );
fi;
#=====# can only work for homalg internal matrices #=====#
return homalgInternalMatrixHull(
Eval( M )!.matrix{[ 1 .. NrRows( M ) ]}{plist} );
end );
## ]]></Listing>
## </Description>
## </ManSection>
## <#/GAPDoc>
## <#GAPDoc Label="CertainColumns:homalgTable_entry">
## <ManSection>
## <Func Arg="M, plist" Name="CertainColumns" Label="homalgTable entry"/>
## <Returns>the <C>Eval</C> value of a &homalg; matrix <A>C</A></Returns>
## <Description>
## Let <M>R :=</M> <C>HomalgRing</C><M>( <A>C</A> )</M> and <M>RP :=</M> <C>homalgTable</C><M>( R )</M>.
## If the <C>homalgTable</C> component <M>RP</M>!.<C>CertainColumns</C> is bound then
## the method <Ref Meth="Eval" Label="for matrices created with CertainColumns"/> returns
## <M>RP</M>!.<C>CertainColumns</C> applied to the content of the attribute
## <C>EvalCertainColumns</C><M>( <A>C</A> ) = [ <A>M</A>, <A>plist</A> ]</M>.
## </Description>
## </ManSection>
## <#/GAPDoc>
## <#GAPDoc Label="Eval:HasEvalUnionOfRows">
## <ManSection>
## <Meth Arg="C" Name="Eval" Label="for matrices created with UnionOfRows"/>
## <Returns>the <C>Eval</C> value of a &homalg; matrix <A>C</A></Returns>
## <Description>
## In case the matrix was created using
## <Ref Meth="UnionOfRows" Label="for matrices"/>
## then the filter <C>HasEvalUnionOfRows</C> for <A>C</A> is set to true and the <C>homalgTable</C> function
## <Ref Meth="UnionOfRows" Label="homalgTable entry"/>
## will be used to set the attribute <C>Eval</C>.
## <Listing Type="Code"><![CDATA[
InstallMethod( Eval,
"for homalg matrices (HasEvalUnionOfRows)",
[ IsHomalgMatrix and HasEvalUnionOfRows ],
function( C )
local R, RP, e, A, B, U;
R := HomalgRing( C );
RP := homalgTable( R );
e := EvalUnionOfRows( C );
A := e[1];
B := e[2];
if IsBound(RP!.UnionOfRows) then
return RP!.UnionOfRows( A, B );
fi;
if not IsHomalgInternalMatrixRep( C ) then
Error( "could not find a procedure called UnionOfRows ",
"in the homalgTable of the non-internal ring\n" );
fi;
#=====# can only work for homalg internal matrices #=====#
U := ShallowCopy( Eval( A )!.matrix );
U{ [ NrRows( A ) + 1 .. NrRows( A ) + NrRows( B ) ] } := Eval( B )!.matrix;
return homalgInternalMatrixHull( U );
end );
## ]]></Listing>
## </Description>
## </ManSection>
## <#/GAPDoc>
## <#GAPDoc Label="UnionOfRows:homalgTable_entry">
## <ManSection>
## <Func Arg="A, B" Name="UnionOfRows" Label="homalgTable entry"/>
## <Returns>the <C>Eval</C> value of a &homalg; matrix <A>C</A></Returns>
## <Description>
## Let <M>R :=</M> <C>HomalgRing</C><M>( <A>C</A> )</M> and <M>RP :=</M> <C>homalgTable</C><M>( R )</M>.
## If the <C>homalgTable</C> component <M>RP</M>!.<C>UnionOfRows</C> is bound then
## the method <Ref Meth="Eval" Label="for matrices created with UnionOfRows"/> returns
## <M>RP</M>!.<C>UnionOfRows</C> applied to the content of the attribute
## <C>EvalUnionOfRows</C><M>( <A>C</A> ) = [ <A>A</A>, <A>B</A> ]</M>.
## </Description>
## </ManSection>
## <#/GAPDoc>
## <#GAPDoc Label="Eval:HasEvalUnionOfColumns">
## <ManSection>
## <Meth Arg="C" Name="Eval" Label="for matrices created with UnionOfColumns"/>
## <Returns>the <C>Eval</C> value of a &homalg; matrix <A>C</A></Returns>
## <Description>
## In case the matrix was created using
## <Ref Meth="UnionOfColumns" Label="for matrices"/>
## then the filter <C>HasEvalUnionOfColumns</C> for <A>C</A> is set to true and the <C>homalgTable</C> function
## <Ref Meth="UnionOfColumns" Label="homalgTable entry"/>
## will be used to set the attribute <C>Eval</C>.
## <Listing Type="Code"><![CDATA[
InstallMethod( Eval,
"for homalg matrices (HasEvalUnionOfColumns)",
[ IsHomalgMatrix and HasEvalUnionOfColumns ],
function( C )
local R, RP, e, A, B, U;
R := HomalgRing( C );
RP := homalgTable( R );
e := EvalUnionOfColumns( C );
A := e[1];
B := e[2];
if IsBound(RP!.UnionOfColumns) then
return RP!.UnionOfColumns( A, B );
fi;
if not IsHomalgInternalMatrixRep( C ) then
Error( "could not find a procedure called UnionOfColumns ",
"in the homalgTable of the non-internal ring\n" );
fi;
#=====# can only work for homalg internal matrices #=====#
U := List( Eval( A )!.matrix, ShallowCopy );
U{ [ 1 .. NrRows( A ) ] }
{ [ NrColumns( A ) + 1 .. NrColumns( A ) + NrColumns( B ) ] }
:= Eval( B )!.matrix;
return homalgInternalMatrixHull( U );
end );
## ]]></Listing>
## </Description>
## </ManSection>
## <#/GAPDoc>
## <#GAPDoc Label="UnionOfColumns:homalgTable_entry">
## <ManSection>
## <Func Arg="A, B" Name="UnionOfColumns" Label="homalgTable entry"/>
## <Returns>the <C>Eval</C> value of a &homalg; matrix <A>C</A></Returns>
## <Description>
## Let <M>R :=</M> <C>HomalgRing</C><M>( <A>C</A> )</M> and <M>RP :=</M> <C>homalgTable</C><M>( R )</M>.
## If the <C>homalgTable</C> component <M>RP</M>!.<C>UnionOfColumns</C> is bound then
## the method <Ref Meth="Eval" Label="for matrices created with UnionOfColumns"/> returns
## <M>RP</M>!.<C>UnionOfColumns</C> applied to the content of the attribute
## <C>EvalUnionOfColumns</C><M>( <A>C</A> ) = [ <A>A</A>, <A>B</A> ]</M>.
## </Description>
## </ManSection>
## <#/GAPDoc>
## <#GAPDoc Label="Eval:HasEvalDiagMat">
## <ManSection>
## <Meth Arg="C" Name="Eval" Label="for matrices created with DiagMat"/>
## <Returns>the <C>Eval</C> value of a &homalg; matrix <A>C</A></Returns>
## <Description>
## In case the matrix was created using
## <Ref Meth="DiagMat" Label="for matrices"/>
## then the filter <C>HasEvalDiagMat</C> for <A>C</A> is set to true and the <C>homalgTable</C> function
## <Ref Meth="DiagMat" Label="homalgTable entry"/>
## will be used to set the attribute <C>Eval</C>.
## <Listing Type="Code"><![CDATA[
InstallMethod( Eval,
"for homalg matrices (HasEvalDiagMat)",
[ IsHomalgMatrix and HasEvalDiagMat ],
function( C )
local R, RP, e, z, m, n, diag, mat;
R := HomalgRing( C );
RP := homalgTable( R );
e := EvalDiagMat( C );
if IsBound(RP!.DiagMat) then
return RP!.DiagMat( e );
fi;
if not IsHomalgInternalMatrixRep( C ) then
Error( "could not find a procedure called DiagMat ",
"in the homalgTable of the non-internal ring\n" );
fi;
#=====# can only work for homalg internal matrices #=====#
z := Zero( R );
m := Sum( List( e, NrRows ) );
n := Sum( List( e, NrColumns ) );
diag := List( [ 1 .. m ], a -> List( [ 1 .. n ], b -> z ) );
m := 0;
n := 0;
for mat in e do
diag{ [ m + 1 .. m + NrRows( mat ) ] }{ [ n + 1 .. n + NrColumns( mat ) ] }
:= Eval( mat )!.matrix;
m := m + NrRows( mat );
n := n + NrColumns( mat );
od;
return homalgInternalMatrixHull( diag );
end );
## ]]></Listing>
## </Description>
## </ManSection>
## <#/GAPDoc>
## <#GAPDoc Label="DiagMat:homalgTable_entry">
## <ManSection>
## <Func Arg="e" Name="DiagMat" Label="homalgTable entry"/>
## <Returns>the <C>Eval</C> value of a &homalg; matrix <A>C</A></Returns>
## <Description>
## Let <M>R :=</M> <C>HomalgRing</C><M>( <A>C</A> )</M> and <M>RP :=</M> <C>homalgTable</C><M>( R )</M>.
## If the <C>homalgTable</C> component <M>RP</M>!.<C>DiagMat</C> is bound then
## the method <Ref Meth="Eval" Label="for matrices created with DiagMat"/> returns
## <M>RP</M>!.<C>DiagMat</C> applied to the content of the attribute
## <C>EvalDiagMat</C><M>( <A>C</A> ) = <A>e</A></M>.
## </Description>
## </ManSection>
## <#/GAPDoc>
## <#GAPDoc Label="Eval:HasEvalKroneckerMat">
## <ManSection>
## <Meth Arg="C" Name="Eval" Label="for matrices created with KroneckerMat"/>
## <Returns>the <C>Eval</C> value of a &homalg; matrix <A>C</A></Returns>
## <Description>
## In case the matrix was created using
## <Ref Meth="KroneckerMat" Label="for matrices"/>
## then the filter <C>HasEvalKroneckerMat</C> for <A>C</A> is set to true and the <C>homalgTable</C> function
## <Ref Meth="KroneckerMat" Label="homalgTable entry"/>
## will be used to set the attribute <C>Eval</C>.
## <Listing Type="Code"><![CDATA[
InstallMethod( Eval,
"for homalg matrices (HasEvalKroneckerMat)",
[ IsHomalgMatrix and HasEvalKroneckerMat ],
function( C )
local R, RP, A, B;
R := HomalgRing( C );
if ( HasIsCommutative( R ) and not IsCommutative( R ) ) and
( HasIsSuperCommutative( R ) and not IsSuperCommutative( R ) ) then
Info( InfoWarning, 1, "\033[01m\033[5;31;47m",
"the Kronecker product is only defined for (super) commutative rings!",
"\033[0m" );
fi;
RP := homalgTable( R );
A := EvalKroneckerMat( C )[1];
B := EvalKroneckerMat( C )[2];
if IsBound(RP!.KroneckerMat) then
return RP!.KroneckerMat( A, B );
fi;
if not IsHomalgInternalMatrixRep( C ) then
Error( "could not find a procedure called KroneckerMat ",
"in the homalgTable of the non-internal ring\n" );
fi;
#=====# can only work for homalg internal matrices #=====#
return homalgInternalMatrixHull(
KroneckerProduct( Eval( A )!.matrix, Eval( B )!.matrix ) );
## this was easy, thanks GAP :)
end );
## ]]></Listing>
## </Description>
## </ManSection>
## <#/GAPDoc>
## <#GAPDoc Label="KroneckerMat:homalgTable_entry">
## <ManSection>
## <Func Arg="A, B" Name="KroneckerMat" Label="homalgTable entry"/>
## <Returns>the <C>Eval</C> value of a &homalg; matrix <A>C</A></Returns>
## <Description>
## Let <M>R :=</M> <C>HomalgRing</C><M>( <A>C</A> )</M> and <M>RP :=</M> <C>homalgTable</C><M>( R )</M>.
## If the <C>homalgTable</C> component <M>RP</M>!.<C>KroneckerMat</C> is bound then
## the method <Ref Meth="Eval" Label="for matrices created with KroneckerMat"/> returns
## <M>RP</M>!.<C>KroneckerMat</C> applied to the content of the attribute
## <C>EvalKroneckerMat</C><M>( <A>C</A> ) = [ <A>A</A>, <A>B</A> ]</M>.
## </Description>
## </ManSection>
## <#/GAPDoc>
## <#GAPDoc Label="Eval:HasEvalMulMat">
## <ManSection>
## <Meth Arg="C" Name="Eval" Label="for matrices created with MulMat"/>
## <Returns>the <C>Eval</C> value of a &homalg; matrix <A>C</A></Returns>
## <Description>
## In case the matrix was created using
## <Ref Meth="\*" Label="for ring elements and matrices"/>
## then the filter <C>HasEvalMulMat</C> for <A>C</A> is set to true and the <C>homalgTable</C> function
## <Ref Meth="MulMat" Label="homalgTable entry"/>
## will be used to set the attribute <C>Eval</C>.
## <Listing Type="Code"><![CDATA[
InstallMethod( Eval,
"for homalg matrices (HasEvalMulMat)",
[ IsHomalgMatrix and HasEvalMulMat ],
function( C )
local R, RP, e, a, A;
R := HomalgRing( C );
RP := homalgTable( R );
e := EvalMulMat( C );
a := e[1];
A := e[2];
if IsBound(RP!.MulMat) then
return RP!.MulMat( a, A );
fi;
if not IsHomalgInternalMatrixRep( C ) then
Error( "could not find a procedure called MulMat ",
"in the homalgTable of the non-internal ring\n" );
fi;
#=====# can only work for homalg internal matrices #=====#
return a * Eval( A );
end );
InstallMethod( Eval,
"for homalg matrices (HasEvalMulMatRight)",
[ IsHomalgMatrix and HasEvalMulMatRight ],
function( C )
local R, RP, e, A, a;
R := HomalgRing( C );
RP := homalgTable( R );
e := EvalMulMatRight( C );
A := e[1];
a := e[2];
if IsBound(RP!.MulMatRight) then
return RP!.MulMatRight( A, a );
fi;
if not IsHomalgInternalMatrixRep( C ) then
Error( "could not find a procedure called MulMatRight ",
"in the homalgTable of the non-internal ring\n" );
fi;
#=====# can only work for homalg internal matrices #=====#
return Eval( A ) * a;
end );
## ]]></Listing>
## </Description>
## </ManSection>
## <#/GAPDoc>
## <#GAPDoc Label="MulMat:homalgTable_entry">
## <ManSection>
## <Func Arg="a, A" Name="MulMat" Label="homalgTable entry"/>
## <Returns>the <C>Eval</C> value of a &homalg; matrix <A>C</A></Returns>
## <Description>
## Let <M>R :=</M> <C>HomalgRing</C><M>( <A>C</A> )</M> and <M>RP :=</M> <C>homalgTable</C><M>( R )</M>.
## If the <C>homalgTable</C> component <M>RP</M>!.<C>MulMat</C> is bound then
## the method <Ref Meth="Eval" Label="for matrices created with MulMat"/> returns
## <M>RP</M>!.<C>MulMat</C> applied to the content of the attribute
## <C>EvalMulMat</C><M>( <A>C</A> ) = [ <A>a</A>, <A>A</A> ]</M>.
## </Description>
## </ManSection>
## <#/GAPDoc>
## <#GAPDoc Label="Eval:HasEvalAddMat">
## <ManSection>
## <Meth Arg="C" Name="Eval" Label="for matrices created with AddMat"/>
## <Returns>the <C>Eval</C> value of a &homalg; matrix <A>C</A></Returns>
## <Description>
## In case the matrix was created using
## <Ref Meth="\+" Label="for matrices"/>
## then the filter <C>HasEvalAddMat</C> for <A>C</A> is set to true and the <C>homalgTable</C> function
## <Ref Meth="AddMat" Label="homalgTable entry"/>
## will be used to set the attribute <C>Eval</C>.
## <Listing Type="Code"><![CDATA[
InstallMethod( Eval,
"for homalg matrices (HasEvalAddMat)",
[ IsHomalgMatrix and HasEvalAddMat ],
function( C )
local R, RP, e, A, B;
R := HomalgRing( C );
RP := homalgTable( R );
e := EvalAddMat( C );
A := e[1];
B := e[2];
if IsBound(RP!.AddMat) then
return RP!.AddMat( A, B );
fi;
if not IsHomalgInternalMatrixRep( C ) then
Error( "could not find a procedure called AddMat ",
"in the homalgTable of the non-internal ring\n" );
fi;
#=====# can only work for homalg internal matrices #=====#
return Eval( A ) + Eval( B );
end );
## ]]></Listing>
## </Description>
## </ManSection>
## <#/GAPDoc>
## <#GAPDoc Label="AddMat:homalgTable_entry">
## <ManSection>
## <Func Arg="A, B" Name="AddMat" Label="homalgTable entry"/>
## <Returns>the <C>Eval</C> value of a &homalg; matrix <A>C</A></Returns>
## <Description>
## Let <M>R :=</M> <C>HomalgRing</C><M>( <A>C</A> )</M> and <M>RP :=</M> <C>homalgTable</C><M>( R )</M>.
## If the <C>homalgTable</C> component <M>RP</M>!.<C>AddMat</C> is bound then
## the method <Ref Meth="Eval" Label="for matrices created with AddMat"/> returns
## <M>RP</M>!.<C>AddMat</C> applied to the content of the attribute
## <C>EvalAddMat</C><M>( <A>C</A> ) = [ <A>A</A>, <A>B</A> ]</M>.
## </Description>
## </ManSection>
## <#/GAPDoc>
## <#GAPDoc Label="Eval:HasEvalSubMat">
## <ManSection>
## <Meth Arg="C" Name="Eval" Label="for matrices created with SubMat"/>
## <Returns>the <C>Eval</C> value of a &homalg; matrix <A>C</A></Returns>
## <Description>
## In case the matrix was created using
## <Ref Meth="\-" Label="for matrices"/>
## then the filter <C>HasEvalSubMat</C> for <A>C</A> is set to true and the <C>homalgTable</C> function
## <Ref Meth="SubMat" Label="homalgTable entry"/>
## will be used to set the attribute <C>Eval</C>.
## <Listing Type="Code"><![CDATA[
InstallMethod( Eval,
"for homalg matrices (HasEvalSubMat)",
[ IsHomalgMatrix and HasEvalSubMat ],
function( C )
local R, RP, e, A, B;
R := HomalgRing( C );
RP := homalgTable( R );
e := EvalSubMat( C );
A := e[1];
B := e[2];
if IsBound(RP!.SubMat) then
return RP!.SubMat( A, B );
fi;
if not IsHomalgInternalMatrixRep( C ) then
Error( "could not find a procedure called SubMat ",
"in the homalgTable of the non-internal ring\n" );
fi;
#=====# can only work for homalg internal matrices #=====#
return Eval( A ) - Eval( B );
end );
## ]]></Listing>
## </Description>
## </ManSection>
## <#/GAPDoc>
## <#GAPDoc Label="SubMat:homalgTable_entry">
## <ManSection>
## <Func Arg="A, B" Name="SubMat" Label="homalgTable entry"/>
## <Returns>the <C>Eval</C> value of a &homalg; matrix <A>C</A></Returns>
## <Description>
## Let <M>R :=</M> <C>HomalgRing</C><M>( <A>C</A> )</M> and <M>RP :=</M> <C>homalgTable</C><M>( R )</M>.
## If the <C>homalgTable</C> component <M>RP</M>!.<C>SubMat</C> is bound then
## the method <Ref Meth="Eval" Label="for matrices created with SubMat"/> returns
## <M>RP</M>!.<C>SubMat</C> applied to the content of the attribute
## <C>EvalSubMat</C><M>( <A>C</A> ) = [ <A>A</A>, <A>B</A> ]</M>.
## </Description>
## </ManSection>
## <#/GAPDoc>
## <#GAPDoc Label="Eval:HasEvalCompose">
## <ManSection>
## <Meth Arg="C" Name="Eval" Label="for matrices created with Compose"/>
## <Returns>the <C>Eval</C> value of a &homalg; matrix <A>C</A></Returns>
## <Description>
## In case the matrix was created using
## <Ref Meth="\*" Label="for composable matrices"/>
## then the filter <C>HasEvalCompose</C> for <A>C</A> is set to true and the <C>homalgTable</C> function
## <Ref Meth="Compose" Label="homalgTable entry"/>
## will be used to set the attribute <C>Eval</C>.
## <Listing Type="Code"><![CDATA[
InstallMethod( Eval,
"for homalg matrices (HasEvalCompose)",
[ IsHomalgMatrix and HasEvalCompose ],
function( C )
local R, RP, e, A, B;
R := HomalgRing( C );
RP := homalgTable( R );
e := EvalCompose( C );
A := e[1];
B := e[2];
if IsBound(RP!.Compose) then
return RP!.Compose( A, B );
fi;
if not IsHomalgInternalMatrixRep( C ) then
Error( "could not find a procedure called Compose ",
"in the homalgTable of the non-internal ring\n" );
fi;
#=====# can only work for homalg internal matrices #=====#
return Eval( A ) * Eval( B );
end );
## ]]></Listing>
## </Description>
## </ManSection>
## <#/GAPDoc>
## <#GAPDoc Label="Compose:homalgTable_entry">
## <ManSection>
## <Func Arg="A, B" Name="Compose" Label="homalgTable entry"/>
## <Returns>the <C>Eval</C> value of a &homalg; matrix <A>C</A></Returns>
## <Description>
## Let <M>R :=</M> <C>HomalgRing</C><M>( <A>C</A> )</M> and <M>RP :=</M> <C>homalgTable</C><M>( R )</M>.
## If the <C>homalgTable</C> component <M>RP</M>!.<C>Compose</C> is bound then
## the method <Ref Meth="Eval" Label="for matrices created with Compose"/> returns
## <M>RP</M>!.<C>Compose</C> applied to the content of the attribute
## <C>EvalCompose</C><M>( <A>C</A> ) = [ <A>A</A>, <A>B</A> ]</M>.
## </Description>
## </ManSection>
## <#/GAPDoc>
## <#GAPDoc Label="Eval:IsIdentityMatrix">
## <ManSection>
## <Meth Arg="C" Name="Eval" Label="for matrices created with HomalgIdentityMatrix"/>
## <Returns>the <C>Eval</C> value of a &homalg; matrix <A>C</A></Returns>
## <Description>
## In case the matrix <A>C</A> was created using
## <Ref Meth="HomalgIdentityMatrix" Label="constructor for identity matrices"/>
## then the filter <C>IsOne</C> for <A>C</A> is set to true and the <C>homalgTable</C> function
## (&see; <Ref Meth="IdentityMatrix" Label="homalgTable entry"/>)
## will be used to set the attribute <C>Eval</C>.
## <Listing Type="Code"><![CDATA[
InstallMethod( Eval,
"for homalg matrices (IsOne)",
[ IsHomalgMatrix and IsOne and HasNrRows and HasNrColumns ], 10,
function( C )
local R, id, RP, o, z, zz;
R := HomalgRing( C );
if IsBound( R!.IdentityMatrices ) then
id := ElmWPObj( R!.IdentityMatrices!.weak_pointers, NrColumns( C ) );
if id <> fail then
R!.IdentityMatrices!.cache_hits := R!.IdentityMatrices!.cache_hits + 1;
return id;
fi;
## we do not count cache_misses as it is equivalent to counter
fi;
RP := homalgTable( R );
if IsBound( RP!.IdentityMatrix ) then
id := RP!.IdentityMatrix( C );
SetElmWPObj( R!.IdentityMatrices!.weak_pointers, NrColumns( C ), id );
R!.IdentityMatrices!.counter := R!.IdentityMatrices!.counter + 1;
return id;
fi;
if not IsHomalgInternalMatrixRep( C ) then
Error( "could not find a procedure called IdentityMatrix ",
"homalgTable to evaluate a non-internal identity matrix\n" );
fi;
#=====# can only work for homalg internal matrices #=====#
z := Zero( HomalgRing( C ) );
o := One( HomalgRing( C ) );
zz := ListWithIdenticalEntries( NrColumns( C ), z );
id := List( [ 1 .. NrRows( C ) ],
function(i)
local z;
z := ShallowCopy( zz ); z[i] := o; return z;
end );
id := homalgInternalMatrixHull( id );
SetElmWPObj( R!.IdentityMatrices!.weak_pointers, NrColumns( C ), id );
return id;
end );
## ]]></Listing>
## </Description>
## </ManSection>
## <#/GAPDoc>
## <#GAPDoc Label="IdentityMatrix:homalgTable_entry">
## <ManSection>
## <Func Arg="C" Name="IdentityMatrix" Label="homalgTable entry"/>
## <Returns>the <C>Eval</C> value of a &homalg; matrix <A>C</A></Returns>
## <Description>
## Let <M>R :=</M> <C>HomalgRing</C><M>( <A>C</A> )</M> and <M>RP :=</M> <C>homalgTable</C><M>( R )</M>.
## If the <C>homalgTable</C> component <M>RP</M>!.<C>IdentityMatrix</C> is bound then the method
## <Ref Meth="Eval" Label="for matrices created with HomalgIdentityMatrix"/> returns
## <M>RP</M>!.<C>IdentityMatrix</C><M>( <A>C</A> )</M>.
## </Description>
## </ManSection>
## <#/GAPDoc>
## <#GAPDoc Label="Eval:IsZeroMatrix">
## <ManSection>
## <Meth Arg="C" Name="Eval" Label="for matrices created with HomalgZeroMatrix"/>
## <Returns>the <C>Eval</C> value of a &homalg; matrix <A>C</A></Returns>
## <Description>
## In case the matrix <A>C</A> was created using
## <Ref Meth="HomalgZeroMatrix" Label="constructor for zero matrices"/>
## then the filter <C>IsZeroMatrix</C> for <A>C</A> is set to true and the <C>homalgTable</C> function
## (&see; <Ref Meth="ZeroMatrix" Label="homalgTable entry"/>)
## will be used to set the attribute <C>Eval</C>.
## <Listing Type="Code"><![CDATA[
InstallMethod( Eval,
"for homalg matrices (IsZero)",
[ IsHomalgMatrix and IsZero and HasNrRows and HasNrColumns ], 20,
function( C )
local R, RP, z;
R := HomalgRing( C );
RP := homalgTable( R );
if ( NrRows( C ) = 0 or NrColumns( C ) = 0 ) and
not ( IsBound( R!.SafeToEvaluateEmptyMatrices ) and
R!.SafeToEvaluateEmptyMatrices = true ) then
Info( InfoWarning, 1, "\033[01m\033[5;31;47m",
"an empty matrix is about to get evaluated!",
"\033[0m" );
fi;
if IsBound( RP!.ZeroMatrix ) then
return RP!.ZeroMatrix( C );
fi;
if not IsHomalgInternalMatrixRep( C ) then
Error( "could not find a procedure called ZeroMatrix ",
"homalgTable to evaluate a non-internal zero matrix\n" );
fi;
#=====# can only work for homalg internal matrices #=====#
z := Zero( HomalgRing( C ) );
## copying the rows saves memory;
## we assume that the entries are never modified!!!
return homalgInternalMatrixHull(
ListWithIdenticalEntries( NrRows( C ),
ListWithIdenticalEntries( NrColumns( C ), z ) ) );
end );
## ]]></Listing>
## </Description>
## </ManSection>
## <#/GAPDoc>
## <#GAPDoc Label="ZeroMatrix:homalgTable_entry">
## <ManSection>
## <Func Arg="C" Name="ZeroMatrix" Label="homalgTable entry"/>
## <Returns>the <C>Eval</C> value of a &homalg; matrix <A>C</A></Returns>
## <Description>
## Let <M>R :=</M> <C>HomalgRing</C><M>( <A>C</A> )</M> and <M>RP :=</M> <C>homalgTable</C><M>( R )</M>.
## If the <C>homalgTable</C> component <M>RP</M>!.<C>ZeroMatrix</C> is bound then the method
## <Ref Meth="Eval" Label="for matrices created with HomalgZeroMatrix"/> returns
## <M>RP</M>!.<C>ZeroMatrix</C><M>( <A>C</A> )</M>.
## </Description>
## </ManSection>
## <#/GAPDoc>
## <#GAPDoc Label="NrRows:homalgTable_entry">
## <ManSection>
## <Func Arg="C" Name="NrRows" Label="homalgTable entry"/>
## <Returns>a nonnegative integer</Returns>
## <Description>
## Let <M>R :=</M> <C>HomalgRing</C><M>( <A>C</A> )</M> and <M>RP :=</M> <C>homalgTable</C><M>( R )</M>.
## If the <C>homalgTable</C> component <M>RP</M>!.<C>NrRows</C> is bound then the standard method
## for the attribute <Ref Attr="NrRows"/> shown below returns
## <M>RP</M>!.<C>NrRows</C><M>( <A>C</A> )</M>.
## <Listing Type="Code"><![CDATA[
InstallMethod( NrRows,
"for homalg matrices",
[ IsHomalgMatrix ],
function( C )
local R, RP;
R := HomalgRing( C );
RP := homalgTable( R );
if IsBound(RP!.NrRows) then
return RP!.NrRows( C );
fi;
if not IsHomalgInternalMatrixRep( C ) then
Error( "could not find a procedure called NrRows ",
"in the homalgTable of the non-internal ring\n" );
fi;
#=====# can only work for homalg internal matrices #=====#
return Length( Eval( C )!.matrix );
end );
## ]]></Listing>
## </Description>
## </ManSection>
## <#/GAPDoc>
## <#GAPDoc Label="NrColumns:homalgTable_entry">
## <ManSection>
## <Func Arg="C" Name="NrColumns" Label="homalgTable entry"/>
## <Returns>a nonnegative integer</Returns>
## <Description>
## Let <M>R :=</M> <C>HomalgRing</C><M>( <A>C</A> )</M> and <M>RP :=</M> <C>homalgTable</C><M>( R )</M>.
## If the <C>homalgTable</C> component <M>RP</M>!.<C>NrColumns</C> is bound then the standard method
## for the attribute <Ref Attr="NrColumns"/> shown below returns
## <M>RP</M>!.<C>NrColumns</C><M>( <A>C</A> )</M>.
## <Listing Type="Code"><![CDATA[
InstallMethod( NrColumns,
"for homalg matrices",
[ IsHomalgMatrix ],
function( C )
local R, RP;
R := HomalgRing( C );
RP := homalgTable( R );
if IsBound(RP!.NrColumns) then
return RP!.NrColumns( C );
fi;
if not IsHomalgInternalMatrixRep( C ) then
Error( "could not find a procedure called NrColumns ",
"in the homalgTable of the non-internal ring\n" );
fi;
#=====# can only work for homalg internal matrices #=====#
return Length( Eval( C )!.matrix[ 1 ] );
end );
## ]]></Listing>
## </Description>
## </ManSection>
## <#/GAPDoc>
## <#GAPDoc Label="Determinant:homalgTable_entry">
## <ManSection>
## <Func Arg="C" Name="Determinant" Label="homalgTable entry"/>
## <Returns>a ring element</Returns>
## <Description>
## Let <M>R :=</M> <C>HomalgRing</C><M>( <A>C</A> )</M> and <M>RP :=</M> <C>homalgTable</C><M>( R )</M>.
## If the <C>homalgTable</C> component <M>RP</M>!.<C>Determinant</C> is bound then the standard method
## for the attribute <Ref Attr="DeterminantMat"/> shown below returns
## <M>RP</M>!.<C>Determinant</C><M>( <A>C</A> )</M>.
## <Listing Type="Code"><![CDATA[
InstallMethod( DeterminantMat,
"for homalg matrices",
[ IsHomalgMatrix ],
function( C )
local R, RP;
R := HomalgRing( C );
RP := homalgTable( R );
if NrRows( C ) <> NrColumns( C ) then
Error( "the matrix is not a square matrix\n" );
fi;
if IsEmptyMatrix( C ) then
return One( R );
elif IsZero( C ) then
return Zero( R );
fi;
if IsBound(RP!.Determinant) then
return RingElementConstructor( R )( RP!.Determinant( C ), R );
fi;
if not IsHomalgInternalMatrixRep( C ) then
Error( "could not find a procedure called Determinant ",
"in the homalgTable of the non-internal ring\n" );
fi;
#=====# can only work for homalg internal matrices #=====#
return Determinant( Eval( C )!.matrix );
end );
##
InstallMethod( Determinant,
"for homalg matrices",
[ IsHomalgMatrix ],
function( C )
return DeterminantMat( C );
end );
## ]]></Listing>
## </Description>
## </ManSection>
## <#/GAPDoc>
####################################
#
# methods for operations (you probably want to replace for an external CAS):
#
####################################
##
InstallMethod( IsUnit,
"for homalg ring elements",
[ IsHomalgRing, IsRingElement ], 100,
function( R, r )
local RP;
if HasIsZero( r ) and IsZero( r ) then
return false;
elif HasIsOne( r ) and IsOne( r ) then
return true;
fi;
return not IsBool( LeftInverse( HomalgMatrix( [ r ], 1, 1, R ) ) );
end );
##
InstallMethod( IsUnit,
"for homalg ring elements",
[ IsHomalgRing, IsHomalgRingElement ], 100,
function( R, r )
local RP;
if HasIsZero( r ) and IsZero( r ) then
return false;
elif HasIsOne( r ) and IsOne( r ) then
return true;
elif HasIsMinusOne( r ) and IsMinusOne( r ) then
return true;
fi;
RP := homalgTable( R );
if IsBound(RP!.IsUnit) then
return RP!.IsUnit( R, r );
fi;
#=====# the fallback method #=====#
return not IsBool( LeftInverse( HomalgMatrix( [ r ], 1, 1, R ) ) );
end );
##
InstallMethod( IsUnit,
"for homalg ring elements",
[ IsHomalgInternalRingRep, IsRingElement ], 100,
function( R, r )
return IsUnit( R!.ring, r );
end );
##
InstallMethod( IsUnit,
"for homalg ring elements",
[ IsHomalgRingElement ],
function( r )
if HasIsZero( r ) and IsZero( r ) then
return false;
elif HasIsOne( r ) and IsOne( r ) then
return true;
elif HasIsMinusOne( r ) and IsMinusOne( r ) then
return true;
fi;
if not IsBound( r!.IsUnit ) then
r!.IsUnit := IsUnit( HomalgRing( r ), r );
fi;
return r!.IsUnit;
end );
## <#GAPDoc Label="ZeroRows:homalgTable_entry">
## <ManSection>
## <Func Arg="C" Name="ZeroRows" Label="homalgTable entry"/>
## <Returns>a (possibly empty) list of positive integers</Returns>
## <Description>
## Let <M>R :=</M> <C>HomalgRing</C><M>( <A>C</A> )</M> and <M>RP :=</M> <C>homalgTable</C><M>( R )</M>.
## If the <C>homalgTable</C> component <M>RP</M>!.<C>ZeroRows</C> is bound then the standard method
## of the attribute <Ref Attr="ZeroRows"/> shown below returns
## <M>RP</M>!.<C>ZeroRows</C><M>( <A>C</A> )</M>.
## <Listing Type="Code"><![CDATA[
InstallMethod( ZeroRows,
"for homalg matrices",
[ IsHomalgMatrix ],
function( C )
local R, RP, z;
R := HomalgRing( C );
RP := homalgTable( R );
if IsBound(RP!.ZeroRows) then
return RP!.ZeroRows( C );
fi;
#=====# the fallback method #=====#
z := HomalgZeroMatrix( 1, NrColumns( C ), R );
return Filtered( [ 1 .. NrRows( C ) ], a -> CertainRows( C, [ a ] ) = z );
end );
## ]]></Listing>
## </Description>
## </ManSection>
## <#/GAPDoc>
## <#GAPDoc Label="ZeroColumns:homalgTable_entry">
## <ManSection>
## <Func Arg="C" Name="ZeroColumns" Label="homalgTable entry"/>
## <Returns>a (possibly empty) list of positive integers</Returns>
## <Description>
## Let <M>R :=</M> <C>HomalgRing</C><M>( <A>C</A> )</M> and <M>RP :=</M> <C>homalgTable</C><M>( R )</M>.
## If the <C>homalgTable</C> component <M>RP</M>!.<C>ZeroColumns</C> is bound then the standard method
## of the attribute <Ref Attr="ZeroColumns"/> shown below returns
## <M>RP</M>!.<C>ZeroColumns</C><M>( <A>C</A> )</M>.
## <Listing Type="Code"><![CDATA[
InstallMethod( ZeroColumns,
"for homalg matrices",
[ IsHomalgMatrix ],
function( C )
local R, RP, z;
R := HomalgRing( C );
RP := homalgTable( R );
if IsBound(RP!.ZeroColumns) then
return RP!.ZeroColumns( C );
fi;
#=====# the fallback method #=====#
z := HomalgZeroMatrix( NrRows( C ), 1, R );
return Filtered( [ 1 .. NrColumns( C ) ], a -> CertainColumns( C, [ a ] ) = z );
end );
## ]]></Listing>
## </Description>
## </ManSection>
## <#/GAPDoc>
##
InstallMethod( GetRidOfObsoleteRows,
"for homalg matrices",
[ IsHomalgMatrix ],
function( C )
local R, RP, M;
R := HomalgRing( C );
RP := homalgTable( R );
if IsBound(RP!.GetRidOfObsoleteRows) then
M := HomalgMatrix( RP!.GetRidOfObsoleteRows( C ), R );
if HasNrColumns( C ) then
SetNrColumns( M, NrColumns( C ) );
fi;
SetZeroRows( M, [ ] );
return M;
fi;
#=====# the fallback method #=====#
## get rid of zero rows
## (e.g. those rows containing the ring relations)
M := CertainRows( C, NonZeroRows( C ) );
SetZeroRows( M, [ ] );
## forgetting C may save memory
if HasEvalCertainRows( M ) then
if not IsEmptyMatrix( M ) then
Eval( M );
fi;
ResetFilterObj( M, EvalCertainRows );
Unbind( M!.EvalCertainRows );
fi;
return M;
end );
##
InstallMethod( GetRidOfObsoleteColumns,
"for homalg matrices",
[ IsHomalgMatrix ],
function( C )
local R, RP, M;
R := HomalgRing( C );
RP := homalgTable( R );
if IsBound(RP!.GetRidOfObsoleteColumns) then
M := HomalgMatrix( RP!.GetRidOfObsoleteColumns( C ), R );
if HasNrRows( C ) then
SetNrRows( M, NrRows( C ) );
fi;
SetZeroColumns( M, [ ] );
return M;
fi;
#=====# the fallback method #=====#
## get rid of zero columns
## (e.g. those columns containing the ring relations)
M := CertainColumns( C, NonZeroColumns( C ) );
SetZeroColumns( M, [ ] );
## forgetting C may save memory
if HasEvalCertainColumns( M ) then
if not IsEmptyMatrix( M ) then
Eval( M );
fi;
ResetFilterObj( M, EvalCertainColumns );
Unbind( M!.EvalCertainColumns );
fi;
return M;
end );
## <#GAPDoc Label="AreEqualMatrices:homalgTable_entry">
## <ManSection>
## <Func Arg="M1,M2" Name="AreEqualMatrices" Label="homalgTable entry"/>
## <Returns><C>true</C> or <C>false</C></Returns>
## <Description>
## Let <M>R :=</M> <C>HomalgRing</C><M>( <A>M1</A> )</M> and <M>RP :=</M> <C>homalgTable</C><M>( R )</M>.
## If the <C>homalgTable</C> component <M>RP</M>!.<C>AreEqualMatrices</C> is bound then the standard method
## for the operation <Ref Oper="\=" Label="for matrices"/> shown below returns
## <M>RP</M>!.<C>AreEqualMatrices</C><M>( <A>M1</A>, <A>M2</A> )</M>.
## <Listing Type="Code"><![CDATA[
InstallMethod( \=,
"for homalg comparable matrices",
[ IsHomalgMatrix, IsHomalgMatrix ],
function( M1, M2 )
local R, RP, are_equal;
## do not touch mutable matrices
if not ( IsMutable( M1 ) or IsMutable( M2 ) ) then
if IsBound( M1!.AreEqual ) then
are_equal := _ElmWPObj_ForHomalg( M1!.AreEqual, M2, fail );
if are_equal <> fail then
return are_equal;
fi;
else
M1!.AreEqual :=
ContainerForWeakPointers(
TheTypeContainerForWeakPointersOnComputedValues,
[ "operation", "AreEqual" ] );
fi;
if IsBound( M2!.AreEqual ) then
are_equal := _ElmWPObj_ForHomalg( M2!.AreEqual, M1, fail );
if are_equal <> fail then
return are_equal;
fi;
fi;
## do not store things symmetrically below to ``save'' memory
fi;
R := HomalgRing( M1 );
RP := homalgTable( R );
if IsBound(RP!.AreEqualMatrices) then
## CAUTION: the external system must be able to check equality
## modulo possible ring relations (known to the external system)!
are_equal := RP!.AreEqualMatrices( M1, M2 );
elif IsBound(RP!.Equal) then
## CAUTION: the external system must be able to check equality
## modulo possible ring relations (known to the external system)!
are_equal := RP!.Equal( M1, M2 );
elif IsBound(RP!.IsZeroMatrix) then ## ensuring this avoids infinite loops
are_equal := IsZero( M1 - M2 );
fi;
if IsBound( are_equal ) then
## do not touch mutable matrices
if not ( IsMutable( M1 ) or IsMutable( M2 ) ) then
if are_equal then
MatchPropertiesAndAttributes( M1, M2,
LIMAT.intrinsic_properties,
LIMAT.intrinsic_attributes,
LIMAT.intrinsic_components
);
fi;
## do not store things symmetrically to ``save'' memory
_AddTwoElmWPObj_ForHomalg( M1!.AreEqual, M2, are_equal );
fi;
return are_equal;
fi;
TryNextMethod( );
end );
## ]]></Listing>
## </Description>
## </ManSection>
## <#/GAPDoc>
## <#GAPDoc Label="IsIdentityMatrix:homalgTable_entry">
## <ManSection>
## <Func Arg="M" Name="IsIdentityMatrix" Label="homalgTable entry"/>
## <Returns><C>true</C> or <C>false</C></Returns>
## <Description>
## Let <M>R :=</M> <C>HomalgRing</C><M>( <A>M</A> )</M> and <M>RP :=</M> <C>homalgTable</C><M>( R )</M>.
## If the <C>homalgTable</C> component <M>RP</M>!.<C>IsIdentityMatrix</C> is bound then the standard method
## for the property <Ref Prop="IsOne"/> shown below returns
## <M>RP</M>!.<C>IsIdentityMatrix</C><M>( <A>M</A> )</M>.
## <Listing Type="Code"><![CDATA[
InstallMethod( IsOne,
"for homalg matrices",
[ IsHomalgMatrix ],
function( M )
local R, RP;
if NrRows( M ) <> NrColumns( M ) then
return false;
fi;
R := HomalgRing( M );
RP := homalgTable( R );
if IsBound(RP!.IsIdentityMatrix) then
return RP!.IsIdentityMatrix( M );
fi;
#=====# the fallback method #=====#
return M = HomalgIdentityMatrix( NrRows( M ), HomalgRing( M ) );
end );
## ]]></Listing>
## </Description>
## </ManSection>
## <#/GAPDoc>
## <#GAPDoc Label="IsDiagonalMatrix:homalgTable_entry">
## <ManSection>
## <Func Arg="M" Name="IsDiagonalMatrix" Label="homalgTable entry"/>
## <Returns><C>true</C> or <C>false</C></Returns>
## <Description>
## Let <M>R :=</M> <C>HomalgRing</C><M>( <A>M</A> )</M> and <M>RP :=</M> <C>homalgTable</C><M>( R )</M>.
## If the <C>homalgTable</C> component <M>RP</M>!.<C>IsDiagonalMatrix</C> is bound then the standard method
## for the property <Ref Meth="IsDiagonalMatrix"/> shown below returns
## <M>RP</M>!.<C>IsDiagonalMatrix</C><M>( <A>M</A> )</M>.
## <Listing Type="Code"><![CDATA[
InstallMethod( IsDiagonalMatrix,
"for homalg matrices",
[ IsHomalgMatrix ],
function( M )
local R, RP, diag;
R := HomalgRing( M );
RP := homalgTable( R );
if IsBound(RP!.IsDiagonalMatrix) then
return RP!.IsDiagonalMatrix( M );
fi;
#=====# the fallback method #=====#
diag := DiagonalEntries( M );
return M = HomalgDiagonalMatrix( diag, NrRows( M ), NrColumns( M ), R );
end );
## ]]></Listing>
## </Description>
## </ManSection>
## <#/GAPDoc>
## <#GAPDoc Label="GetColumnIndependentUnitPositions">
## <ManSection>
## <Oper Arg="A, poslist" Name="GetColumnIndependentUnitPositions" Label="for matrices"/>
## <Returns>a (possibly empty) list of pairs of positive integers</Returns>
## <Description>
## The list of column independet unit position of the matrix <A>A</A>.
## We say that a unit <A>A</A><M>[i,k]</M> is column independet from the unit <A>A</A><M>[l,j]</M>
## if <M>i>l</M> and <A>A</A><M>[l,k]=0</M>.
## The rows are scanned from top to bottom and within each row the columns are
## scanned from right to left searching for new units, column independent from the preceding ones.
## If <A>A</A><M>[i,k]</M> is a new column independent unit then <M>[i,k]</M> is added to the
## output list. If <A>A</A> has no units the empty list is returned.<P/>
## (for the installed standard method see <Ref Meth="GetColumnIndependentUnitPositions" Label="homalgTable entry"/>)
## </Description>
## </ManSection>
## <#/GAPDoc>
## <#GAPDoc Label="GetColumnIndependentUnitPositions:homalgTable_entry">
## <ManSection>
## <Func Arg="M, poslist" Name="GetColumnIndependentUnitPositions" Label="homalgTable entry"/>
## <Returns>a (possibly empty) list of pairs of positive integers</Returns>
## <Description>
## Let <M>R :=</M> <C>HomalgRing</C><M>( <A>M</A> )</M> and <M>RP :=</M> <C>homalgTable</C><M>( R )</M>.
## If the <C>homalgTable</C> component <M>RP</M>!.<C>GetColumnIndependentUnitPositions</C> is bound then the standard method
## of the operation <Ref Meth="GetColumnIndependentUnitPositions" Label="for matrices"/> shown below returns
## <M>RP</M>!.<C>GetColumnIndependentUnitPositions</C><M>( <A>M</A>, <A>poslist</A> )</M>.
## <Listing Type="Code"><![CDATA[
InstallMethod( GetColumnIndependentUnitPositions,
"for homalg matrices",
[ IsHomalgMatrix, IsHomogeneousList ],
function( M, poslist )
local cache, R, RP, rest, pos, i, j, k;
if IsBound( M!.GetColumnIndependentUnitPositions ) then
cache := M!.GetColumnIndependentUnitPositions;
if IsBound( cache.(String( poslist )) ) then
return cache.(String( poslist ));
fi;
else
cache := rec( );
M!.GetColumnIndependentUnitPositions := cache;
fi;
R := HomalgRing( M );
RP := homalgTable( R );
if IsBound(RP!.GetColumnIndependentUnitPositions) then
pos := RP!.GetColumnIndependentUnitPositions( M, poslist );
if pos <> [ ] then
SetIsZero( M, false );
fi;
cache.(String( poslist )) := pos;
return pos;
fi;
#=====# the fallback method #=====#
rest := [ 1 .. NrColumns( M ) ];
pos := [ ];
for i in [ 1 .. NrRows( M ) ] do
for k in Reversed( rest ) do
if not [ i, k ] in poslist and
IsUnit( R, MatElm( M, i, k ) ) then
Add( pos, [ i, k ] );
rest := Filtered( rest,
a -> IsZero( MatElm( M, i, a ) ) );
break;
fi;
od;
od;
if pos <> [ ] then
SetIsZero( M, false );
fi;
cache.(String( poslist )) := pos;
return pos;
end );
## ]]></Listing>
## </Description>
## </ManSection>
## <#/GAPDoc>
## <#GAPDoc Label="GetRowIndependentUnitPositions">
## <ManSection>
## <Oper Arg="A, poslist" Name="GetRowIndependentUnitPositions" Label="for matrices"/>
## <Returns>a (possibly empty) list of pairs of positive integers</Returns>
## <Description>
## The list of row independet unit position of the matrix <A>A</A>.
## We say that a unit <A>A</A><M>[k,j]</M> is row independet from the unit <A>A</A><M>[i,l]</M>
## if <M>j>l</M> and <A>A</A><M>[k,l]=0</M>.
## The columns are scanned from left to right and within each column the rows are
## scanned from bottom to top searching for new units, row independent from the preceding ones.
## If <A>A</A><M>[k,j]</M> is a new row independent unit then <M>[j,k]</M> (yes <M>[j,k]</M>) is added to the
## output list. If <A>A</A> has no units the empty list is returned.<P/>
## (for the installed standard method see <Ref Meth="GetRowIndependentUnitPositions" Label="homalgTable entry"/>)
## </Description>
## </ManSection>
## <#/GAPDoc>
## <#GAPDoc Label="GetRowIndependentUnitPositions:homalgTable_entry">
## <ManSection>
## <Func Arg="M, poslist" Name="GetRowIndependentUnitPositions" Label="homalgTable entry"/>
## <Returns>a (possibly empty) list of pairs of positive integers</Returns>
## <Description>
## Let <M>R :=</M> <C>HomalgRing</C><M>( <A>M</A> )</M> and <M>RP :=</M> <C>homalgTable</C><M>( R )</M>.
## If the <C>homalgTable</C> component <M>RP</M>!.<C>GetRowIndependentUnitPositions</C> is bound then the standard method
## of the operation <Ref Meth="GetRowIndependentUnitPositions" Label="for matrices"/> shown below returns
## <M>RP</M>!.<C>GetRowIndependentUnitPositions</C><M>( <A>M</A>, <A>poslist</A> )</M>.
## <Listing Type="Code"><![CDATA[
InstallMethod( GetRowIndependentUnitPositions,
"for homalg matrices",
[ IsHomalgMatrix, IsHomogeneousList ],
function( M, poslist )
local cache, R, RP, rest, pos, j, i, k;
if IsBound( M!.GetRowIndependentUnitPositions ) then
cache := M!.GetRowIndependentUnitPositions;
if IsBound( cache.(String( poslist )) ) then
return cache.(String( poslist ));
fi;
else
cache := rec( );
M!.GetRowIndependentUnitPositions := cache;
fi;
R := HomalgRing( M );
RP := homalgTable( R );
if IsBound(RP!.GetRowIndependentUnitPositions) then
pos := RP!.GetRowIndependentUnitPositions( M, poslist );
if pos <> [ ] then
SetIsZero( M, false );
fi;
cache.( String( poslist ) ) := pos;
return pos;
fi;
#=====# the fallback method #=====#
rest := [ 1 .. NrRows( M ) ];
pos := [ ];
for j in [ 1 .. NrColumns( M ) ] do
for k in Reversed( rest ) do
if not [ j, k ] in poslist and
IsUnit( R, MatElm( M, k, j ) ) then
Add( pos, [ j, k ] );
rest := Filtered( rest,
a -> IsZero( MatElm( M, a, j ) ) );
break;
fi;
od;
od;
if pos <> [ ] then
SetIsZero( M, false );
fi;
cache.( String( poslist ) ) := pos;
return pos;
end );
## ]]></Listing>
## </Description>
## </ManSection>
## <#/GAPDoc>
## <#GAPDoc Label="GetUnitPosition">
## <ManSection>
## <Oper Arg="A, poslist" Name="GetUnitPosition" Label="for matrices"/>
## <Returns>a (possibly empty) list of pairs of positive integers</Returns>
## <Description>
## The position <M>[i,j]</M> of the first unit <A>A</A><M>[i,j]</M> in the matrix <A>A</A>, where
## the rows are scanned from top to bottom and within each row the columns are
## scanned from left to right. If <A>A</A><M>[i,j]</M> is the first occurrence of a unit
## then the position pair <M>[i,j]</M> is returned. Otherwise <C>fail</C> is returned.<P/>
## (for the installed standard method see <Ref Meth="GetUnitPosition" Label="homalgTable entry"/>)
## </Description>
## </ManSection>
## <#/GAPDoc>
## <#GAPDoc Label="GetUnitPosition:homalgTable_entry">
## <ManSection>
## <Func Arg="M, poslist" Name="GetUnitPosition" Label="homalgTable entry"/>
## <Returns>a (possibly empty) list of pairs of positive integers</Returns>
## <Description>
## Let <M>R :=</M> <C>HomalgRing</C><M>( <A>M</A> )</M> and <M>RP :=</M> <C>homalgTable</C><M>( R )</M>.
## If the <C>homalgTable</C> component <M>RP</M>!.<C>GetUnitPosition</C> is bound then the standard method
## of the operation <Ref Meth="GetUnitPosition" Label="for matrices"/> shown below returns
## <M>RP</M>!.<C>GetUnitPosition</C><M>( <A>M</A>, <A>poslist</A> )</M>.
## <Listing Type="Code"><![CDATA[
InstallMethod( GetUnitPosition,
"for homalg matrices",
[ IsHomalgMatrix, IsHomogeneousList ],
function( M, poslist )
local R, RP, pos, m, n, i, j;
R := HomalgRing( M );
RP := homalgTable( R );
if IsBound(RP!.GetUnitPosition) then
pos := RP!.GetUnitPosition( M, poslist );
if IsList( pos ) and IsPosInt( pos[1] ) and IsPosInt( pos[2] ) then
SetIsZero( M, false );
fi;
return pos;
fi;
#=====# the fallback method #=====#
m := NrRows( M );
n := NrColumns( M );
for i in [ 1 .. m ] do
for j in [ 1 .. n ] do
if not [ i, j ] in poslist and not j in poslist and
IsUnit( R, MatElm( M, i, j ) ) then
SetIsZero( M, false );
return [ i, j ];
fi;
od;
od;
return fail;
end );
## ]]></Listing>
## </Description>
## </ManSection>
## <#/GAPDoc>
## <#GAPDoc Label="PositionOfFirstNonZeroEntryPerRow:homalgTable_entry">
## <ManSection>
## <Func Arg="M, poslist" Name="PositionOfFirstNonZeroEntryPerRow" Label="homalgTable entry"/>
## <Returns>a list of nonnegative integers</Returns>
## <Description>
## Let <M>R :=</M> <C>HomalgRing</C><M>( <A>M</A> )</M> and <M>RP :=</M> <C>homalgTable</C><M>( R )</M>.
## If the <C>homalgTable</C> component <M>RP</M>!.<C>PositionOfFirstNonZeroEntryPerRow</C> is bound then the standard method
## of the attribute <Ref Attr="PositionOfFirstNonZeroEntryPerRow"/> shown below returns
## <M>RP</M>!.<C>PositionOfFirstNonZeroEntryPerRow</C><M>( <A>M</A> )</M>.
## <Listing Type="Code"><![CDATA[
InstallMethod( PositionOfFirstNonZeroEntryPerRow,
"for homalg matrices",
[ IsHomalgMatrix ],
function( M )
local R, RP, pos, entries, r, c, i, k, j;
R := HomalgRing( M );
RP := homalgTable( R );
if IsBound(RP!.PositionOfFirstNonZeroEntryPerRow) then
return RP!.PositionOfFirstNonZeroEntryPerRow( M );
elif IsBound(RP!.PositionOfFirstNonZeroEntryPerColumn) then
return PositionOfFirstNonZeroEntryPerColumn( Involution( M ) );
fi;
#=====# the fallback method #=====#
entries := EntriesOfHomalgMatrix( M );
r := NrRows( M );
c := NrColumns( M );
pos := ListWithIdenticalEntries( r, 0 );
for i in [ 1 .. r ] do
k := (i - 1) * c;
for j in [ 1 .. c ] do
if not IsZero( entries[k + j] ) then
pos[i] := j;
break;
fi;
od;
od;
return pos;
end );
## ]]></Listing>
## </Description>
## </ManSection>
## <#/GAPDoc>
## <#GAPDoc Label="PositionOfFirstNonZeroEntryPerColumn:homalgTable_entry">
## <ManSection>
## <Func Arg="M, poslist" Name="PositionOfFirstNonZeroEntryPerColumn" Label="homalgTable entry"/>
## <Returns>a list of nonnegative integers</Returns>
## <Description>
## Let <M>R :=</M> <C>HomalgRing</C><M>( <A>M</A> )</M> and <M>RP :=</M> <C>homalgTable</C><M>( R )</M>.
## If the <C>homalgTable</C> component <M>RP</M>!.<C>PositionOfFirstNonZeroEntryPerColumn</C> is bound then the standard method
## of the attribute <Ref Attr="PositionOfFirstNonZeroEntryPerColumn"/> shown below returns
## <M>RP</M>!.<C>PositionOfFirstNonZeroEntryPerColumn</C><M>( <A>M</A> )</M>.
## <Listing Type="Code"><![CDATA[
InstallMethod( PositionOfFirstNonZeroEntryPerColumn,
"for homalg matrices",
[ IsHomalgMatrix ],
function( M )
local R, RP, pos, entries, r, c, j, i, k;
R := HomalgRing( M );
RP := homalgTable( R );
if IsBound(RP!.PositionOfFirstNonZeroEntryPerColumn) then
return RP!.PositionOfFirstNonZeroEntryPerColumn( M );
elif IsBound(RP!.PositionOfFirstNonZeroEntryPerRow) then
return PositionOfFirstNonZeroEntryPerRow( Involution( M ) );
fi;
#=====# the fallback method #=====#
entries := EntriesOfHomalgMatrix( M );
r := NrRows( M );
c := NrColumns( M );
pos := ListWithIdenticalEntries( c, 0 );
for j in [ 1 .. c ] do
for i in [ 1 .. r ] do
k := (i - 1) * c;
if not IsZero( entries[k + j] ) then
pos[j] := i;
break;
fi;
od;
od;
return pos;
end );
## ]]></Listing>
## </Description>
## </ManSection>
## <#/GAPDoc>
##
InstallMethod( DivideEntryByUnit,
"for homalg matrices",
[ IsHomalgMatrix, IsPosInt, IsPosInt, IsRingElement ],
function( M, i, j, u )
local R, RP;
if IsEmptyMatrix( M ) then
return;
fi;
R := HomalgRing( M );
RP := homalgTable( R );
if IsBound(RP!.DivideEntryByUnit) then
RP!.DivideEntryByUnit( M, i, j, u );
else
SetMatElm( M, i, j, MatElm( M, i, j ) / u );
fi;
## caution: we deliberately do not return a new hull for Eval( M )
end );
##
InstallMethod( DivideRowByUnit,
"for homalg matrices",
[ IsHomalgMatrix, IsPosInt, IsRingElement, IsInt ],
function( M, i, u, j )
local R, RP, a, mat;
if IsEmptyMatrix( M ) then
return M;
fi;
R := HomalgRing( M );
RP := homalgTable( R );
if IsBound(RP!.DivideRowByUnit) then
RP!.DivideRowByUnit( M, i, u, j );
else
#=====# the fallback method #=====#
if j > 0 then
## the two for's avoid creating non-dense lists:
for a in [ 1 .. j - 1 ] do
DivideEntryByUnit( M, i, a, u );
od;
for a in [ j + 1 .. NrColumns( M ) ] do
DivideEntryByUnit( M, i, a, u );
od;
SetMatElm( M, i, j, One( R ) );
else
for a in [ 1 .. NrColumns( M ) ] do
DivideEntryByUnit( M, i, a, u );
od;
fi;
fi;
## since all what we did had a side effect on Eval( M ) ignoring
## possible other Eval's, e.g. EvalCompose, we want to return
## a new homalg matrix object only containing Eval( M )
mat := HomalgMatrixWithAttributes( [
Eval, Eval( M ),
NrRows, NrRows( M ),
NrColumns, NrColumns( M ),
], R );
if HasIsZero( M ) and not IsZero( M ) then
SetIsZero( mat, false );
fi;
return mat;
end );
##
InstallMethod( DivideColumnByUnit,
"for homalg matrices",
[ IsHomalgMatrix, IsPosInt, IsRingElement, IsInt ],
function( M, j, u, i )
local R, RP, a, mat;
if IsEmptyMatrix( M ) then
return M;
fi;
R := HomalgRing( M );
RP := homalgTable( R );
if IsBound(RP!.DivideColumnByUnit) then
RP!.DivideColumnByUnit( M, j, u, i );
else
#=====# the fallback method #=====#
if i > 0 then
## the two for's avoid creating non-dense lists:
for a in [ 1 .. i - 1 ] do
DivideEntryByUnit( M, a, j, u );
od;
for a in [ i + 1 .. NrRows( M ) ] do
DivideEntryByUnit( M, a, j, u );
od;
SetMatElm( M, i, j, One( R ) );
else
for a in [ 1 .. NrRows( M ) ] do
DivideEntryByUnit( M, a, j, u );
od;
fi;
fi;
## since all what we did had a side effect on Eval( M ) ignoring
## possible other Eval's, e.g. EvalCompose, we want to return
## a new homalg matrix object only containing Eval( M )
mat := HomalgMatrixWithAttributes( [
Eval, Eval( M ),
NrRows, NrRows( M ),
NrColumns, NrColumns( M ),
], R );
if HasIsZero( M ) and not IsZero( M ) then
SetIsZero( mat, false );
fi;
return mat;
end );
##
InstallMethod( CopyRowToIdentityMatrix,
"for homalg matrices",
[ IsHomalgMatrix, IsPosInt, IsList, IsPosInt ],
function( M, i, L, j )
local R, RP, v, vi, l, r;
R := HomalgRing( M );
RP := homalgTable( R );
if IsBound(RP!.CopyRowToIdentityMatrix) then
RP!.CopyRowToIdentityMatrix( M, i, L, j );
else
#=====# the fallback method #=====#
if Length( L ) > 0 and IsHomalgMatrix( L[1] ) then
v := L[1];
fi;
if Length( L ) > 1 and IsHomalgMatrix( L[2] ) then
vi := L[2];
fi;
if IsBound( v ) and IsBound( vi ) then
## the two for's avoid creating non-dense lists:
for l in [ 1 .. j - 1 ] do
r := MatElm( M, i, l );
if not IsZero( r ) then
SetMatElm( v, j, l, -r );
SetMatElm( vi, j, l, r );
fi;
od;
for l in [ j + 1 .. NrColumns( M ) ] do
r := MatElm( M, i, l );
if not IsZero( r ) then
SetMatElm( v, j, l, -r );
SetMatElm( vi, j, l, r );
fi;
od;
elif IsBound( v ) then
## the two for's avoid creating non-dense lists:
for l in [ 1 .. j - 1 ] do
r := MatElm( M, i, l );
SetMatElm( v, j, l, -r );
od;
for l in [ j + 1 .. NrColumns( M ) ] do
r := MatElm( M, i, l );
SetMatElm( v, j, l, -r );
od;
elif IsBound( vi ) then
## the two for's avoid creating non-dense lists:
for l in [ 1 .. j - 1 ] do
r := MatElm( M, i, l );
SetMatElm( vi, j, l, r );
od;
for l in [ j + 1 .. NrColumns( M ) ] do
r := MatElm( M, i, l );
SetMatElm( vi, j, l, r );
od;
fi;
fi;
end );
##
InstallMethod( CopyColumnToIdentityMatrix,
"for homalg matrices",
[ IsHomalgMatrix, IsPosInt, IsList, IsPosInt ],
function( M, j, L, i )
local R, RP, u, ui, m, k, r;
R := HomalgRing( M );
RP := homalgTable( R );
if IsBound(RP!.CopyColumnToIdentityMatrix) then
RP!.CopyColumnToIdentityMatrix( M, j, L, i );
else
#=====# the fallback method #=====#
if Length( L ) > 0 and IsHomalgMatrix( L[1] ) then
u := L[1];
fi;
if Length( L ) > 1 and IsHomalgMatrix( L[2] ) then
ui := L[2];
fi;
if IsBound( u ) and IsBound( ui ) then
## the two for's avoid creating non-dense lists:
for k in [ 1 .. i - 1 ] do
r := MatElm( M, k, j );
if not IsZero( r ) then
SetMatElm( u, k, i, -r );
SetMatElm( ui, k, i, r );
fi;
od;
for k in [ i + 1 .. NrRows( M ) ] do
r := MatElm( M, k, j );
if not IsZero( r ) then
SetMatElm( u, k, i, -r );
SetMatElm( ui, k, i, r );
fi;
od;
elif IsBound( u ) then
## the two for's avoid creating non-dense lists:
for k in [ 1 .. i - 1 ] do
r := MatElm( M, k, j );
SetMatElm( u, k, i, -r );
od;
for k in [ i + 1 .. NrRows( M ) ] do
r := MatElm( M, k, j );
SetMatElm( u, k, i, -r );
od;
elif IsBound( ui ) then
## the two for's avoid creating non-dense lists:
for k in [ 1 .. i - 1 ] do
r := MatElm( M, k, j );
SetMatElm( ui, k, i, r );
od;
for k in [ i + 1 .. NrRows( M ) ] do
r := MatElm( M, k, j );
SetMatElm( ui, k, i, r );
od;
fi;
fi;
end );
##
InstallMethod( SetColumnToZero,
"for homalg matrices",
[ IsHomalgMatrix, IsPosInt, IsPosInt ],
function( M, i, j )
local R, RP, zero, k;
R := HomalgRing( M );
RP := homalgTable( R );
if IsBound(RP!.SetColumnToZero) then
RP!.SetColumnToZero( M, i, j );
else
#=====# the fallback method #=====#
zero := Zero( R );
## the two for's avoid creating non-dense lists:
for k in [ 1 .. i - 1 ] do
SetMatElm( M, k, j, zero );
od;
for k in [ i + 1 .. NrRows( M ) ] do
SetMatElm( M, k, j, zero );
od;
fi;
## since all what we did had a side effect on Eval( M ) ignoring
## possible other Eval's, e.g. EvalCompose, we want to return
## a new homalg matrix object only containing Eval( M )
return HomalgMatrixWithAttributes( [
Eval, Eval( M ),
NrRows, NrRows( M ),
NrColumns, NrColumns( M ),
], R );
end );
##
InstallMethod( GetCleanRowsPositions,
"for homalg matrices",
[ IsHomalgMatrix, IsHomogeneousList ],
function( M, clean_columns )
local R, RP, one, clean_rows, m, j, i;
R := HomalgRing( M );
RP := homalgTable( R );
if IsBound(RP!.GetCleanRowsPositions) then
return RP!.GetCleanRowsPositions( M, clean_columns );
fi;
one := One( R );
#=====# the fallback method #=====#
clean_rows := [ ];
m := NrRows( M );
for j in clean_columns do
for i in [ 1 .. m ] do
if IsOne( MatElm( M, i, j ) ) then
Add( clean_rows, i );
break;
fi;
od;
od;
return clean_rows;
end );
##
InstallMethod( ConvertRowToMatrix,
"for homalg matrices",
[ IsHomalgMatrix, IsInt, IsInt ],
function( M, r, c )
local R, RP, ext_obj, l, mat, j;
if NrRows( M ) <> 1 then
Error( "expecting a single row matrix as a first argument\n" );
fi;
if r = 1 then
return M;
fi;
R := HomalgRing( M );
RP := homalgTable( R );
if IsBound(RP!.ConvertRowToMatrix) then
ext_obj := RP!.ConvertRowToMatrix( M, r, c );
return HomalgMatrix( ext_obj, r, c, R );
fi;
#=====# the fallback method #=====#
## to use
## CreateHomalgMatrixFromString( GetListOfHomalgMatrixAsString( M ), c, r, R )
## we would need a transpose afterwards,
## which differs from Involution in general:
l := List( [ 1 .. c ], j -> CertainColumns( M, [ (j-1) * r + 1 .. j * r ] ) );
l := List( l, GetListOfHomalgMatrixAsString );
l := List( l, a -> CreateHomalgMatrixFromString( a, r, 1, R ) );
mat := HomalgZeroMatrix( r, 0, R );
for j in [ 1 .. c ] do
mat := UnionOfColumns( mat, l[j] );
od;
return mat;
end );
##
InstallMethod( ConvertColumnToMatrix,
"for homalg matrices",
[ IsHomalgMatrix, IsInt, IsInt ],
function( M, r, c )
local R, RP, ext_obj;
if NrColumns( M ) <> 1 then
Error( "expecting a single column matrix as a first argument\n" );
fi;
if c = 1 then
return M;
fi;
R := HomalgRing( M );
RP := homalgTable( R );
if IsBound(RP!.ConvertColumnToMatrix) then
ext_obj := RP!.ConvertColumnToMatrix( M, r, c );
return HomalgMatrix( ext_obj, r, c, R );
fi;
#=====# the fallback method #=====#
return CreateHomalgMatrixFromString( GetListOfHomalgMatrixAsString( M ), r, c, R ); ## delicate
end );
##
InstallMethod( ConvertMatrixToRow,
"for homalg matrices",
[ IsHomalgMatrix ],
function( M )
local R, RP, ext_obj, r, c, l, mat, j;
if NrRows( M ) = 1 then
return M;
fi;
R := HomalgRing( M );
RP := homalgTable( R );
if IsBound(RP!.ConvertMatrixToRow) then
ext_obj := RP!.ConvertMatrixToRow( M );
return HomalgMatrix( ext_obj, 1, NrRows( M ) * NrColumns( M ), R );
fi;
#=====# the fallback method #=====#
r := NrRows( M );
c := NrColumns( M );
## CreateHomalgMatrixFromString( GetListOfHomalgMatrixAsString( "Transpose"( M ) ), 1, r * c, R )
## would require a Transpose operation,
## which differs from Involution in general:
l := List( [ 1 .. c ], j -> CertainColumns( M, [ j ] ) );
l := List( l, GetListOfHomalgMatrixAsString );
l := List( l, a -> CreateHomalgMatrixFromString( a, 1, r, R ) );
mat := HomalgZeroMatrix( 1, 0, R );
for j in [ 1 .. c ] do
mat := UnionOfColumns( mat, l[j] );
od;
return mat;
end );
##
InstallMethod( ConvertMatrixToColumn,
"for homalg matrices",
[ IsHomalgMatrix ],
function( M )
local R, RP, ext_obj;
if NrColumns( M ) = 1 then
return M;
fi;
R := HomalgRing( M );
RP := homalgTable( R );
if IsBound(RP!.ConvertMatrixToColumn) then
ext_obj := RP!.ConvertMatrixToColumn( M );
return HomalgMatrix( ext_obj, NrColumns( M ) * NrRows( M ), 1, R );
fi;
#=====# the fallback method #=====#
return CreateHomalgMatrixFromString( GetListOfHomalgMatrixAsString( M ), NrColumns( M ) * NrRows( M ), 1, R ); ## delicate
end );
##
InstallMethod( Eval,
"for homalg matrices (HasPreEval)",
[ IsHomalgMatrix and HasPreEval ],
function( C )
local R, RP, e;
R := HomalgRing( C );
RP := homalgTable( R );
e := PreEval( C );
if IsBound(RP!.PreEval) then
return RP!.PreEval( e );
fi;
#=====# the fallback method #=====#
return Eval( e );
end );
## <#GAPDoc Label="Eliminate">
## <ManSection>
## <Oper Arg="rel, indets" Name="Eliminate"/>
## <Returns>a &homalg; matrix</Returns>
## <Description>
## Eliminate the independents <A>indets</A> from the matrix (or list of ring elements) <A>rel</A>,
## i.e. compute a generating set
## of the ideal defined as the intersection of the ideal generated by the entries of the list <A>rel</A>
## with the subring generated by all indeterminates except those in <A>indets</A>.
## by the list of indeterminates <A>indets</A>.
## </Description>
## </ManSection>
## <#/GAPDoc>
##
InstallMethod( Eliminate,
"for a homalg matrix and list of homalg ring elements",
[ IsHomalgMatrix, IsList ],
function( rel, indets )
local R, RP, elim;
R := HomalgRing( rel );
if IsZero( rel ) then
return HomalgZeroMatrix( 0, 1, R );
fi;
rel := EntriesOfHomalgMatrix( rel );
RP := homalgTable( R );
if IsBound(RP!.Eliminate) then
elim := RP!.Eliminate( rel, indets, R ); ## the external object
elim := HomalgMatrix( elim, R );
SetNrColumns( elim, 1 );
return elim;
fi;
if not IsHomalgInternalRingRep( R ) then
Error( "could not find a procedure called Eliminate ",
"in the homalgTable of the non-internal ring\n" );
fi;
TryNextMethod( );
end );
InstallMethod( Eliminate,
"for a homalg matrix",
[ IsHomalgMatrix ],
function( rel )
local R, indets, B;
R := HomalgRing( rel );
if HasRelativeIndeterminatesOfPolynomialRing( R ) then
indets := RelativeIndeterminatesOfPolynomialRing( R );
B := BaseRing( R );
elif HasIndeterminatesOfPolynomialRing( R ) then
indets := IndeterminatesOfPolynomialRing( R );
B := CoefficientsRing( R );
else
Error( "the ring is not a polynomial ring" );
fi;
return B * Eliminate( rel, indets );
end );
##
InstallMethod( Eliminate,
"for two lists of ring elements and a homalg ring",
[ IsList, IsList, IsHomalgRing ],
function( rel, indets, R )
rel := HomalgMatrix( rel, Length( rel ), 1, R );
return Eliminate( rel, indets );
end );
##
InstallMethod( Eliminate,
"for two lists of ring elements",
[ IsList, IsList ],
function( rel, indets )
local R;
if not rel = [ ] then
R := HomalgRing( rel[1] );
elif not indets = [ ] then
R := HomalgRing( indets[1] );
else
Error( "cannot extract ring out of two empty input lists\n" );
fi;
return Eliminate( rel, indets, R );
end );
##
InstallMethod( Eliminate,
"for a homalg matrix and ring element",
[ IsHomalgMatrix, IsHomalgRingElement ],
function( rel, v )
return Eliminate( rel, [ v ] );
end );
##
InstallMethod( Eliminate,
"for a list and ring element",
[ IsList, IsHomalgRingElement ],
function( rel, v )
return Eliminate( rel, [ v ] );
end );
##
InstallMethod( Coefficients,
"for a ring element and a list of indeterminates",
[ IsHomalgRingElement, IsList ],
function( poly, var )
local R, RP, both, monomials, coeffs;
R := HomalgRing( poly );
if IsZero( poly ) then
coeffs := HomalgZeroMatrix( 1, 0, R );
coeffs!.monomials := MakeImmutable( [ ] );
return coeffs;
fi;
RP := homalgTable( R );
if IsBound(RP!.Coefficients) then
both := RP!.Coefficients( poly, var ); ## the pair of external objects
monomials := HomalgMatrix( both[1], R );
monomials := EntriesOfHomalgMatrix( monomials );
coeffs := HomalgMatrix( both[2], Length( monomials ), 1, R );
coeffs!.monomials := MakeImmutable( monomials );
return coeffs;
fi;
if not IsHomalgInternalRingRep( R ) then
Error( "could not find a procedure called Coefficients ",
"in the homalgTable of the non-internal ring\n" );
fi;
TryNextMethod( );
end );
##
InstallMethod( Coefficients,
"for a ring element and an indeterminate",
[ IsHomalgRingElement, IsHomalgRingElement ],
function( poly, var )
return Coefficients( poly, [ var ] );
end );
##
InstallMethod( Coefficients,
"for a homalg ring element and a string",
[ IsHomalgRingElement, IsString ],
function( poly, var_name )
return Coefficients( poly, var_name / HomalgRing( poly ) );
end );
##
InstallMethod( Coefficients,
"for a homalg ring element",
[ IsHomalgRingElement ],
function( poly )
local R, indets, coeffs;
R := HomalgRing( poly );
if IsBound( poly!.Coefficients ) then
return poly!.Coefficients;
fi;
if HasRelativeIndeterminatesOfPolynomialRing( R ) then
indets := RelativeIndeterminatesOfPolynomialRing( R );
elif HasIndeterminatesOfPolynomialRing( R ) then
indets := IndeterminatesOfPolynomialRing( R );
elif HasRelativeIndeterminateAntiCommutingVariablesOfExteriorRing( R ) then
indets := RelativeIndeterminateAntiCommutingVariablesOfExteriorRing( R );
elif HasIndeterminateAntiCommutingVariablesOfExteriorRing( R ) then
indets := IndeterminateAntiCommutingVariablesOfExteriorRing( R );
else
TryNextMethod( );
fi;
coeffs := Coefficients( poly, indets );
poly!.Coefficients := coeffs;
return coeffs;
end );
##
InstallMethod( CoefficientsOfUnivariatePolynomial,
"for two homalg ring elements",
[ IsHomalgRingElement, IsHomalgRingElement ],
function( r, var )
local R, RP, ext_obj;
if IsZero( r ) then
return HomalgZeroMatrix( 1, 0, R );
fi;
R := HomalgRing( r );
RP := homalgTable( R );
if IsBound(RP!.CoefficientsOfUnivariatePolynomial) then
ext_obj := RP!.CoefficientsOfUnivariatePolynomial( r, var );
return HomalgMatrix( ext_obj, 1, "unknown_number_of_columns", R );
fi;
TryNextMethod( );
end );
##
InstallMethod( CoefficientsOfUnivariatePolynomial,
"for a homalg ring element and a string",
[ IsHomalgRingElement, IsString ],
function( r, var_name )
return CoefficientsOfUnivariatePolynomial( r, var_name / HomalgRing( r ) );
end );
## for univariate polynomials over arbitrary base rings
InstallMethod( CoefficientsOfUnivariatePolynomial,
"for a homalg ring element",
[ IsHomalgRingElement ],
function( r )
local R, indets;
R := HomalgRing( r );
if HasRelativeIndeterminatesOfPolynomialRing( R ) then
indets := RelativeIndeterminatesOfPolynomialRing( R );
elif HasIndeterminatesOfPolynomialRing( R ) then
indets := IndeterminatesOfPolynomialRing( R );
fi;
if not Length( indets ) = 1 then
TryNextMethod( );
fi;
return CoefficientsOfUnivariatePolynomial( r, indets[1] );
end );
## for univariate polynomials over arbitrary base rings
InstallMethod( CoefficientOfUnivariatePolynomial,
"for a homalg ring element and an integer",
[ IsHomalgRingElement, IsInt ],
function( r, j )
local coeffs;
coeffs := CoefficientsOfUnivariatePolynomial( r );
coeffs := EntriesOfHomalgMatrix( coeffs );
if j > Length( coeffs ) - 1 then
return Zero( r );
fi;
return coeffs[j + 1];
end );
##
InstallMethod( LeadingCoefficient,
"for lists of ring elements",
[ IsHomalgRingElement, IsHomalgRingElement ],
function( poly, var )
return MatElm( Coefficients( poly, var ), 1, 1 );
end );
##
InstallMethod( LeadingCoefficient,
"for a homalg ring element and a string",
[ IsHomalgRingElement, IsString ],
function( r, var_name )
return LeadingCoefficient( r, var_name / HomalgRing( r ) );
end );
##
InstallMethod( LeadingCoefficient,
"for a homalg ring element",
[ IsHomalgRingElement ],
function( poly )
local lc;
if IsBound( poly!.LeadingCoefficient ) then
return poly!.LeadingCoefficient;
fi;
lc := MatElm( Coefficients( poly ), 1, 1 );
poly!.LeadingCoefficient := lc;
return lc;
end );
## FIXME: make this a fallback method
InstallMethod( LeadingMonomial,
"for a homalg ring element",
[ IsHomalgRingElement ],
function( poly )
local lm;
if IsBound( poly!.LeadingMonomial ) then
return poly!.LeadingMonomial;
fi;
if IsZero( poly ) then
lm := poly;
else
lm := Coefficients( poly )!.monomials[1];
fi;
poly!.LeadingMonomial := lm;
return lm;
end );
##
InstallMethod( IndicatorMatrixOfNonZeroEntries,
"for homalg matrices",
[ IsHomalgMatrix ],
function( mat )
local R, RP, result, r, c, i, j;
R := HomalgRing( mat );
RP := homalgTable( R );
if IsBound(RP!.IndicatorMatrixOfNonZeroEntries) then
return RP!.IndicatorMatrixOfNonZeroEntries( mat );
fi;
r := NrRows( mat );
c := NrColumns( mat );
result := List( [ 1 .. r ], a -> ListWithIdenticalEntries( c, 0 ) );
for i in [ 1 .. r ] do
for j in [ 1 .. c ] do
if not IsZero( MatElm( mat, i, j ) ) then
result[i][j] := 1;
fi;
od;
od;
return result;
end );
##
InstallMethod( Pullback,
"for homalg rings",
[ IsHomalgRingMap, IsHomalgMatrix ],
function( phi, M )
local T, r, c, RP;
if not IsIdenticalObj( HomalgRing( Source( phi ) ), HomalgRing( M ) ) then
Error( "the source ring of the ring map and the ring of the matrix are not identical\n" );
fi;
T := HomalgRing( Range( phi ) );
r := NrRows( M );
c := NrColumns( M );
if IsZero( M ) then
return HomalgZeroMatrix( r, c, T );
fi;
RP := homalgTable( T );
if IsBound( RP!.Pullback ) then
return HomalgMatrix( RP!.Pullback( phi, M ), NrRows( M ), NrColumns( M ), T );
fi;
if not IsHomalgInternalRingRep( T ) then
Error( "could not find a procedure called Pullback ",
"in the homalgTable of the non-internal ring\n" );
fi;
TryNextMethod( );
end );
####################################
#
# methods for operations (you probably don't urgently need to replace for an external CAS):
#
####################################
##
InstallMethod( SUM,
"for homalg ring elements",
[ IsHomalgRingElement, IsHomalgRingElement ],
function( r1, r2 )
local R, RP;
R := HomalgRing( r1 );
if not HasRingElementConstructor( R ) then
Error( "no ring element constructor found in the ring\n" );
fi;
if not IsIdenticalObj( R, HomalgRing( r2 ) ) then
return Error( "the two elements are not in the same ring\n" );
fi;
RP := homalgTable( R );
if IsBound(RP!.Sum) then
return RingElementConstructor( R )( RP!.Sum( r1, r2 ), R );
elif IsBound(RP!.Minus) then
return RingElementConstructor( R )( RP!.Minus( r1, RP!.Minus( Zero( R ), r2 ) ), R );
fi;
TryNextMethod( );
end );
##
InstallMethod( PROD,
"for homalg ring elements",
[ IsHomalgRingElement, IsHomalgRingElement ],
function( r1, r2 )
local R, RP;
R := HomalgRing( r1 );
if not HasRingElementConstructor( R ) then
Error( "no ring element constructor found in the ring\n" );
fi;
if not IsIdenticalObj( R, HomalgRing( r2 ) ) then
return Error( "the two elements are not in the same ring\n" );
fi;
RP := homalgTable( R );
if IsBound(RP!.Product) then
return RingElementConstructor( R )( RP!.Product( r1, r2 ), R ) ;
fi;
#=====# the fallback method #=====#
return MatElm( HomalgMatrix( [ r1 ], 1, 1, R ) * HomalgMatrix( [ r2 ], 1, 1, R ), 1, 1 );
end );
##
InstallMethod( Degree,
"for homalg ring elements",
[ IsHomalgRingElement ],
function( r )
local R, RP, deg;
if IsBound( r!.Degree ) then
return r!.Degree;
fi;
R := HomalgRing( r );
## do not delete this
if HasRelativeIndeterminatesOfPolynomialRing( R ) then
TryNextMethod( );
fi;
RP := homalgTable( R );
if not IsBound(RP!.DegreeOfRingElement) then
TryNextMethod( );
fi;
deg := RP!.DegreeOfRingElement( r, R );
r!.Degree := deg;
return deg;
end );
##
InstallMethod( Degree,
"for homalg ring elements",
[ IsHomalgRingElement ],
function( r )
local R, RP, coeffs, deg;
if IsBound( r!.Degree ) then
return r!.Degree;
fi;
if IsZero( r ) then
return -1;
fi;
R := HomalgRing( r );
if not HasRelativeIndeterminatesOfPolynomialRing( R ) then
TryNextMethod( );
fi;
RP := homalgTable( R );
if not ( IsBound(RP!.Coefficients) and IsBound( RP!.DegreeOfRingElement ) ) then
TryNextMethod( );
fi;
coeffs := Coefficients( r );
deg := RP!.DegreeOfRingElement( coeffs!.monomials[1], R );
r!.Degree := deg;
return deg;
end );
##
InstallMethod( MatrixOfSymbols,
"for a homalg matrix",
[ IsHomalgMatrix ],
function( mat )
local S, R, RP, symb;
R := HomalgRing( mat );
S := AssociatedGradedRing( R );
if IsZero( mat ) then
return HomalgZeroMatrix( NrRows( mat ), NrColumns( mat ), S );
elif IsOne( mat ) then
return HomalgIdentityMatrix( NrRows( mat ), S );
fi;
RP := homalgTable( R );
if not IsBound(RP!.MatrixOfSymbols) then
Error( "could not find a procedure called MatrixOfSymbols ",
"in the homalgTable of the ring\n" );
fi;
symb := RP!.MatrixOfSymbols( mat );
symb := S * HomalgMatrix( symb, NrRows( mat ), NrColumns( mat ), R );
## TODO: add more properties and attributes to symb
return symb;
end );
##
InstallMethod( GetRidOfRowsAndColumnsWithUnits,
"for a homalg matrix",
[ IsHomalgMatrix ],
function( M )
local MM, R, RP, rr, cc, r, c, UI, VI, U, V, rows, columns,
deleted_rows, deleted_columns, pos, i, j, e,
column, column_range, row, row_range, IdU, IdV, u, v, U_M_V;
if IsBound( M!.GetRidOfRowsAndColumnsWithUnits ) then
return M!.GetRidOfRowsAndColumnsWithUnits;
fi;
MM := M;
R := HomalgRing( M );
RP := homalgTable( R );
rr := NrRows( M );
cc := NrColumns( M );
r := rr;
c := cc;
UI := HomalgIdentityMatrix( rr, R );
VI := HomalgIdentityMatrix( cc, R );
U := UI;
V := VI;
if IsBound( RP!.GetRidOfRowsAndColumnsWithUnits ) then
M := RP!.GetRidOfRowsAndColumnsWithUnits( M );
rows := M[2];
columns := M[3];
deleted_rows := M[4];
deleted_columns := M[5];
M := M[1];
Assert( 6, IsUnitFree( M ) );
SetIsUnitFree( M, true );
else
rows := [ ];
columns := [ ];
deleted_rows := [ ];
deleted_columns := [ ];
fi;
#=====# the fallback method #=====#
pos := GetUnitPosition( M );
SetIsUnitFree( M, pos = fail );
while not IsUnitFree( M ) do
i := pos[1]; j := pos[2];
e := MatElm( M, i, j );
Assert( 6, IsUnit( e ) );
Assert( 6, not IsZero( e ) );
if IsHomalgRingElement( e ) then
e!.IsUnit := true;
SetIsZero( e, false );
fi;
if IsOne( e ) then
e := HomalgIdentityMatrix( 1, R );
else
e := e^-1;
Assert( 0, not e = fail );
e := HomalgMatrix( [ e ], 1, 1, R );
Assert( 6, not IsZero( e ) );
SetIsZero( e, false );
fi;
Add( rows, i );
Add( columns, j );
column := CertainColumns( M, [ j ] );
column_range := Concatenation( [ 1 .. j - 1 ], [ j + 1 .. c ] );
M := CertainColumns( M, column_range ); c := c - 1;
row := CertainRows( M, [ i ] );
row_range := Concatenation( [ 1 .. i - 1 ], [ i + 1 .. r ] );
column := CertainRows( column, row_range );
M := CertainRows( M, row_range ); r := r - 1;
## the following line breaks the symmetry of the line redefining M,
## which could have been M := M - column * e * row;
## but since the adapted row will be reused in creating
## the trafo matrix V below, I decided to redefine the row
## for effeciency reasons
row := e * row;
M := M - column * row;
column := column * e;
Add( deleted_rows, -row );
Add( deleted_columns, -column );
pos := GetUnitPosition( M );
SetIsUnitFree( M, pos = fail );
od;
r := rr;
c := cc;
for pos in [ 1 .. Length( rows ) ] do
r := r - 1;
c := c - 1;
i := rows[pos]; j := columns[pos];
IdU := HomalgIdentityMatrix( r, R );
IdV := HomalgIdentityMatrix( c, R );
u := CertainColumns( IdU, [ 1 .. i - 1 ] );
u := UnionOfColumns( u, deleted_columns[pos] );
u := UnionOfColumns( u, CertainColumns( IdU, [ i .. r ] ) );
v := CertainRows( IdV, [ 1 .. j - 1 ] );
v := UnionOfRows( v, deleted_rows[pos] );
v := UnionOfRows( v, CertainRows( IdV, [ j .. c ] ) );
U := u * U;
V := V * v;
od;
## now bring rows and columns to absolute positions
rr := [ 1 .. rr ];
cc := [ 1 .. cc ];
Perform( rows, function( i ) Remove( rr, i ); end );
Perform( columns, function( j ) Remove( cc, j ); end );
UI := CertainColumns( UI, rr );
VI := CertainRows( VI, cc );
## 1. Left/RightInverse is better than Left/RightInverseLazy here
## as V and U are known to be a subidentity matrices
## 2. Caution:
## (-) U * MM * V is NOT = M, in general, nor
## (-) UI * M * VI is NOT = MM, in general, but
## (+) U * MM and M generate the same column space
## (+) MM * V and M generate the same row space
## (+) UI * M generate column subspace of MM
## (+) M * VI generate row subspace of MM
Assert( 6, GenerateSameColumnModule( U * MM, M ) );
Assert( 6, GenerateSameRowModule( MM * V, M ) );
Assert( 6, IsZero( DecideZeroColumns( UI * M, BasisOfColumnModule( MM ) ) ) );
Assert( 6, IsZero( DecideZeroRows( M * VI, BasisOfRowModule( MM ) ) ) );
U_M_V := [ U, UI, M, VI, V ];
MM!.GetRidOfRowsAndColumnsWithUnits := U_M_V;
return U_M_V;
end );
##
InstallMethod( Random,
"for a homalg ring and a list",
[ IsHomalgRing, IsList ],
function( R, L )
local RP;
RP := homalgTable( R );
L := Concatenation( [ R ], L );
if IsBound(RP!.RandomPol) then
return RingElementConstructor( R )( CallFuncList( RP!.RandomPol, L ), R );
fi;
TryNextMethod( );
end );
##
InstallMethod( Random,
"for a homalg ring and an integer",
[ IsHomalgRing, IsInt ],
function( R, maxdeg )
return Random( R, [ maxdeg ] );
end );
##
InstallMethod( Random,
"for a homalg ring",
[ IsHomalgRing ],
function( R )
return Random( R, Random( [ 1 .. 10 ] ) );
end );
##
InstallMethod( Value,
"polynomial substitution",
[ IsHomalgRingElement, IsList, IsList ],
function( p, V, O )
local lv, lo, R, i, RP, L;
lv := Length( V );
lo := Length( O );
if not ( lv > 0 and lo = lv ) then
Error( "Second and third parameters should be nonempty lists of same size\n" );
fi;
R := HomalgRing( p );
Perform( [ 1 .. lo ],
function( i )
if not IsHomalgRingElement( O[ i ] ) then
O[ i ] := O[ i ] / R;
fi;
end );
if not ( ForAll( [ 1 .. lv ], i -> IsIdenticalObj( R, HomalgRing( V[ i ] ) ) ) and ForAll( [ 1 .. lo ], i -> IsIdenticalObj( R, HomalgRing( O[ i ] ) ) ) ) then
Error( "All the elements of the list should be in same ring\n" );
fi;
if not ForAll( V, i -> i in Indeterminates( R ) ) then
Error( "entries in the second parameter should be ring variables\n" );
fi;
if not ForAll( O, i -> IsHomalgRingElement( i ) ) then
Error( "entries in the third parameter should be ring elements\n" );
fi;
RP := homalgTable( R );
if not IsBound(RP!.Evaluate) then
Error( "table entry Evaluate not found\n" );
fi;
L := [ ];
for i in [ 1 .. lv ] do
L[ 2*i-1 ] := V[ i ];
L[ 2*i ] := O[ i ];
od;
return RingElementConstructor( R )( RP!.Evaluate( p, L ), R );
end );
##
InstallMethod( Value,
"for a homalg matrix and two lists",
[ IsHomalgMatrix, IsList, IsList ],
function( M, V, O )
local R, RP, r, c, L, lv, MM, i, j;
R := HomalgRing( M );
RP := homalgTable( R );
r := NrRows( M );
c := NrColumns( M );
if IsBound( RP!.EvaluateMatrix ) then
L := [ ];
lv := Length( V );
for i in [ 1 .. lv ] do
L[ 2*i-1 ] := V[ i ];
L[ 2*i ] := O[ i ];
od;
return HomalgMatrix( RP!.EvaluateMatrix( M, L ), r, c, R );
fi;
#=====# the fallback method #=====#
MM := HomalgInitialMatrix( r, c, HomalgRing( M ) );
for i in [ 1 .. r ] do
for j in [ 1 .. c ] do
SetMatElm( MM, i, j, Value( MatElm( M, i, j ), V, O ) );
od;
od;
MakeImmutable( MM );
return MM;
end );
##
InstallMethod( Value,
"polynomial substitution",
[ IsObject, IsHomalgRingElement, IsRingElement ],
function( p, v, o )
return Value( p, [ v ], [ o ] );
end );
##
InstallMethod( Value,
"polynomial substitution",
[ IsObject, IsHomalgRingElement ],
function( p, v )
return o -> Value( p, v, o );
end );
##
InstallMethod( Numerator,
"for homalg ring element",
[ IsHomalgRingElement ],
function( p )
local R, RP, l;
R := HomalgRing( p );
if IsBound( p!.Numerator ) then
return p!.Numerator;
fi;
RP := homalgTable( R );
if not IsBound( RP!.NumeratorAndDenominatorOfPolynomial ) then
Error( "table entry for NumeratorAndDenominatorOfPolynomial not found\n" );
fi;
l := RP!.NumeratorAndDenominatorOfPolynomial( p );
p!.Numerator := l[1];
p!.Denominator := l[2];
return l[1];
end );
##
InstallMethod( Denominator,
"for homalg ring element",
[ IsHomalgRingElement ],
function( p )
if not IsBound( p!.Denominator ) then
## this will trigger setting p!.Denominator
Numerator( p );
fi;
return p!.Denominator;
end );
##
InstallMethod( Denominator,
"for homalg matrices",
[ IsHomalgMatrix ],
function( M )
if not IsBound( M!.Denominator ) then
## this will trigger setting M!.Denominator
Numerator( M );
fi;
return M!.Denominator;
end );
##
InstallMethod( Value,
"for a homalg matrix and two lists",
[ IsHomalgMatrix, IsList, IsList ],
function( M, V, O )
local R, r, c, MM, i, j;
R := HomalgRing( M );
#=====# the fallback method #=====#
r := NrRows( M );
c := NrColumns( M );
MM := HomalgInitialMatrix( r, c, HomalgRing( M ) );
for i in [ 1 .. r ] do
for j in [ 1 .. c ] do
SetMatElm( MM, i, j, Value( MatElm( M, i, j ), V, O ) );
od;
od;
MakeImmutable( MM );
return MM;
end );
##
InstallMethod( MonomialMatrixWeighted,
"for homalg rings",
[ IsInt, IsHomalgRing, IsList ],
function( d, R, weights )
local dd, set_weights, RP, vars, mon;
RP := homalgTable( R );
if not Length( weights ) = Length( Indeterminates( R ) ) then
Error( "there must be as many weights as indeterminates\n" );
fi;
set_weights := Set( weights );
if set_weights = [1] or set_weights = [0,1] then
dd := d;
elif set_weights = [-1] or set_weights = [-1,0] then
dd := -d;
else
Error( "Only weights -1, 0 or 1 are accepted. The weights -1 and 1 must not appear at once." );
fi;
if dd < 0 then
return HomalgZeroMatrix( 0, 1, R );
fi;
vars := Indeterminates( R );
if HasIsExteriorRing( R ) and IsExteriorRing( R ) and dd > Length( vars ) then
return HomalgZeroMatrix( 0, 1, R );
fi;
if not ( set_weights = [ 1 ] or set_weights = [ -1 ] ) then
## the variables of weight 1 or -1
vars := vars{Filtered( [ 1 .. Length( weights ) ], p -> weights[p] <> 0 )};
fi;
if IsBound(RP!.MonomialMatrix) then
mon := RP!.MonomialMatrix( dd, vars, R ); ## the external object
mon := HomalgMatrix( mon, R );
SetNrColumns( mon, 1 );
if d = 0 then
IsOne( mon );
fi;
return mon;
fi;
if not IsHomalgInternalRingRep( R ) then
Error( "could not find a procedure called MonomialMatrix in the homalgTable of the external ring\n" );
fi;
TryNextMethod( );
end );
##
InstallMethod( MonomialMatrixWeighted,
"for homalg rings",
[ IsList, IsHomalgRing, IsList ],
function( d, R, weights )
local l, mon, w;
if not Length( weights ) = Length( Indeterminates( R ) ) then
Error( "there must be as many weights as indeterminates\n" );
fi;
l := Length( d );
w := ListOfDegreesOfMultiGradedRing( l, R, weights );
mon := List( [ 1 .. l ] , i -> MonomialMatrixWeighted( d[i], R, w[i] ) );
return Iterated( mon, KroneckerMat );
end );
##
InstallMethod( ListOfDegreesOfMultiGradedRing,
"for homalg rings",
[ IsInt, IsHomalgRing, IsHomogeneousList ],
function( l, R, weights )
local indets, n, B, j, w, wlist, i, k;
if l < 1 then
Error( "the first argument must be a positiv integer\n" );
fi;
indets := Indeterminates( R );
if not Length( weights ) = Length( indets ) then
Error( "there must be as many weights as indeterminates\n" );
fi;
if IsList( weights[1] ) and Length( weights[1] ) = l then
return List( [ 1 .. l ], i -> List( weights, w -> w[i] ) );
fi;
## the rest handles the (improbable?) case of successive extensions
## without multiple weights
if l = 1 then
return [ weights ];
fi;
n := Length( weights );
if not HasBaseRing( R ) then
Error( "no 1. base ring found\n" );
fi;
B := BaseRing( R );
j := Length( Indeterminates( B ) );
w := Concatenation(
ListWithIdenticalEntries( j, 0 ),
ListWithIdenticalEntries( n - j, 1 )
);
wlist := [ ListN( w, weights, \* ) ];
for i in [ 2 .. l - 1 ] do
if not HasBaseRing( B ) then
Error( "no ", i, ". base ring found\n" );
fi;
B := BaseRing( B );
k := Length( Indeterminates( B ) );
w := Concatenation(
ListWithIdenticalEntries( k, 0 ),
ListWithIdenticalEntries( j - k, 1 ),
ListWithIdenticalEntries( n - j, 0 )
);
Add( wlist, ListN( w, weights, \* ) );
j := k;
od;
w := Concatenation(
ListWithIdenticalEntries( j, 1 ),
ListWithIdenticalEntries( n - j, 0 )
);
Add( wlist, ListN( w, weights, \* ) );
return wlist;
end );
##
InstallMethod( RandomMatrixBetweenGradedFreeLeftModulesWeighted,
"for homalg rings",
[ IsList, IsList, IsHomalgRing, IsList ],
function( degreesS, degreesT, R, weights )
local RP, r, c, rand, i, j, mon;
RP := homalgTable( R );
r := Length( degreesS );
c := Length( degreesT );
if degreesT = [ ] then
return HomalgZeroMatrix( 0, c, R );
elif degreesS = [ ] then
return HomalgZeroMatrix( r, 0, R );
fi;
if IsBound(RP!.RandomMatrix) then
rand := RP!.RandomMatrix( R, degreesT, degreesS, weights ); ## the external object
rand := HomalgMatrix( rand, r, c, R );
return rand;
fi;
#=====# begin of the core procedure #=====#
rand := [ 1 .. r * c ];
for i in [ 1 .. r ] do
for j in [ 1 .. c ] do
mon := MonomialMatrixWeighted( degreesS[i] - degreesT[j], R, weights );
mon := ( R * HomalgMatrix( RandomMat( 1, NrRows( mon ) ), HOMALG_MATRICES.ZZ ) ) * mon;
mon := MatElm( mon, 1, 1 );
rand[ ( i - 1 ) * c + j ] := mon;
od;
od;
return HomalgMatrix( rand, r, c, R );
end );
##
InstallMethod( RandomMatrixBetweenGradedFreeRightModulesWeighted,
"for homalg rings",
[ IsList, IsList, IsHomalgRing, IsList ],
function( degreesT, degreesS, R, weights )
local RP, r, c, rand, i, j, mon;
RP := homalgTable( R );
r := Length( degreesT );
c := Length( degreesS );
if degreesT = [ ] then
return HomalgZeroMatrix( 0, c, R );
elif degreesS = [ ] then
return HomalgZeroMatrix( r, 0, R );
fi;
if IsBound(RP!.RandomMatrix) then
rand := RP!.RandomMatrix( R, degreesT, degreesS, weights ); ## the external object
rand := HomalgMatrix( rand, r, c, R );
return rand;
fi;
#=====# begin of the core procedure #=====#
rand := [ 1 .. r * c ];
for i in [ 1 .. r ] do
for j in [ 1 .. c ] do
mon := MonomialMatrixWeighted( degreesS[j] - degreesT[i], R, weights );
mon := ( R * HomalgMatrix( RandomMat( 1, NrRows( mon ) ), HOMALG_MATRICES.ZZ ) ) * mon;
mon := MatElm( mon, 1, 1 );
rand[ ( i - 1 ) * c + j ] := mon;
od;
od;
return HomalgMatrix( rand, r, c, R );
end );
##
InstallMethod( RandomMatrix,
"for three integers, a homalg ring, and a list",
[ IsInt, IsInt, IsInt, IsHomalgRing, IsList ],
function( r, c, d, R, weights )
local degreesS, degreesT;
degreesS := ListWithIdenticalEntries( r, d );
degreesT := ListWithIdenticalEntries( c, 0 );
return RandomMatrixBetweenGradedFreeLeftModulesWeighted( degreesS, degreesT, R, weights );
end );
##
InstallMethod( RandomMatrix,
"for three integers and a homalg ring",
[ IsInt, IsInt, IsInt, IsHomalgRing ],
function( r, c, d, R )
local weights;
weights := ListWithIdenticalEntries( Length( Indeterminates( R ) ), 1 );
return RandomMatrix( r, c, d, R, weights );
end );
##
InstallMethod( GeneralLinearCombination,
"for a homalg ring, an integer, a list and an integer",
[ IsHomalgRing, IsInt, IsList, IsInt ],
function( R, bound, weights, n )
local mat, m, s, B, A, r, i, indets;
if n = 0 then
return [ ];
fi;
mat := MonomialMatrixWeighted( 0, R, weights );
for i in [ 1 .. bound ] do
mat := UnionOfRows( mat, MonomialMatrixWeighted( i, R, weights ) );
od;
m := NrRows( mat );
# todo: better names for the bi: use the corresponding degree of the monomial
s := List( [ 1 .. n ], i -> Concatenation( "b_", String( i ), "_0..", String( m - 1 ) ) );
s := JoinStringsWithSeparator( s );
if HasRelativeIndeterminatesOfPolynomialRing( R ) then
indets := RelativeIndeterminatesOfPolynomialRing( R );
B := BaseRing( R );
elif HasIndeterminatesOfPolynomialRing( R ) then
indets := IndeterminatesOfPolynomialRing( R );
B := CoefficientsRing( R );
elif HasRingRelations( R ) then
B := CoefficientsRing( AmbientRing( R ) );
indets := Indeterminates( AmbientRing( R ) );
else
indets := [ ];
B := R;
fi;
B := ( B * s );
A := B * indets;
if HasRingRelations( R ) then
A := A / ( A * RingRelations( R ) );
fi;
if HasRelativeIndeterminatesOfPolynomialRing( B ) then
indets := RelativeIndeterminatesOfPolynomialRing( B );
else
indets := IndeterminatesOfPolynomialRing( B );
fi;
indets := List( indets, a -> a / A );
indets := ListToListList( indets, n, m );
indets := List( indets, l -> HomalgMatrix( l, 1, m, A ) );
mat := A * mat;
r := List( indets, i -> MatElm( i * mat, 1, 1 ) );
return List( r, rr -> rr / A );
end );
##
InstallMethod( GetMonic,
"for a homalg matrix and a positive integer",
[ IsHomalgMatrix, IsPosInt ],
function( M, i )
local R, indets, l, B, newR, m, n, p, q, f, coeffs;
R := HomalgRing( M );
if HasRelativeIndeterminatesOfPolynomialRing( R ) then
indets := RelativeIndeterminatesOfPolynomialRing( R );
B := BaseRing( R );
elif HasIndeterminatesOfPolynomialRing( R ) then
indets := IndeterminatesOfPolynomialRing( R );
B := CoefficientsRing( R );
else
Error( "the ring is not a polynomial ring\n" );
fi;
l := [ 1 .. Length( indets ) ];
Remove( l, i );
newR := ( B * indets{l} ) * [ indets[i] ];
M := newR * M;
m := NrRows( M );
n := NrColumns( M );
for p in [ 1 .. m ] do
for q in [ 1 .. n ] do
f := MatElm( M, p, q );
if IsMonic( f ) then
return [ f, [ p, q ] ];
fi;
od;
od;
return fail;
end );
##
InstallMethod( GetMonic,
"for a homalg matrix",
[ IsHomalgMatrix ],
function( M )
local R, indets, i, l;
R := HomalgRing( M );
if HasRelativeIndeterminatesOfPolynomialRing( R ) then
indets := RelativeIndeterminatesOfPolynomialRing( R );
elif HasIndeterminatesOfPolynomialRing( R ) then
indets := IndeterminatesOfPolynomialRing( R );
else
Error( "the ring is not a polynomial ring\n" );
fi;
for i in Reversed( [ 1 .. Length( indets ) ] ) do
l := GetMonic( M, i );
if not l = fail then
return [ l[1], l[2], i ];
fi;
od;
return fail;
end );
##
InstallMethod( GetMonicUptoUnit,
"for a homalg matrix and a positive integer",
[ IsHomalgMatrix, IsPosInt ],
function( M, i )
local R, indets, l, B, newR, m, n, p, q, f, coeffs;
R := HomalgRing( M );
if HasRelativeIndeterminatesOfPolynomialRing( R ) then
indets := RelativeIndeterminatesOfPolynomialRing( R );
B := BaseRing( R );
elif HasIndeterminatesOfPolynomialRing( R ) then
indets := IndeterminatesOfPolynomialRing( R );
B := CoefficientsRing( R );
else
Error( "the ring is not a polynomial ring\n" );
fi;
l := [ 1 .. Length( indets ) ];
Remove( l, i );
newR := ( B * indets{l} ) * [ indets[i] ];
M := newR * M;
m := NrRows( M );
n := NrColumns( M );
for p in [ 1 .. m ] do
for q in [ 1 .. n ] do
f := MatElm( M, p, q );
if IsMonicUptoUnit( f ) then
return [ f, [ p, q ] ];
fi;
od;
od;
return fail;
end );
##
InstallMethod( GetMonicUptoUnit,
"for a homalg matrix",
[ IsHomalgMatrix ],
function( M )
local R, indets, i, l;
R := HomalgRing( M );
if HasRelativeIndeterminatesOfPolynomialRing( R ) then
indets := RelativeIndeterminatesOfPolynomialRing( R );
elif HasIndeterminatesOfPolynomialRing( R ) then
indets := IndeterminatesOfPolynomialRing( R );
else
Error( "the ring is not a polynomial ring\n" );
fi;
for i in Reversed( [ 1 .. Length( indets ) ] ) do
l := GetMonicUptoUnit( M, i );
if not l = fail then
return [ l[1], l[2], i ];
fi;
od;
return fail;
end );
##
InstallMethod( NoetherNormalization,
"for a homalg matrix",
[ IsHomalgMatrix ],
function( M )
local R, r, char, indets, l, k, K, m, rand_mat, rand_inv;
R := HomalgRing( M );
r := CoefficientsRing( R );
char := Characteristic( r );
if char > 0 and not IsPrimeInt( char ) then
TryNextMethod( );
elif not HasIndeterminatesOfPolynomialRing( R ) then
TryNextMethod( );
fi;
indets := Indeterminates( R );
l := Length( indets );
indets := HomalgMatrix( indets, 1, l, R );
if char > 0 then
if HasRationalParameters( r ) then
k := HomalgRingOfIntegers( char );
else
k := HomalgRingOfIntegers( char, DegreeOverPrimeField( r ) );
fi;
K := k!.ring;
else
k := HOMALG_MATRICES.ZZ;
fi;
m := GetMonicUptoUnit( M );
if not m = fail then
return [ M, m, true, true ];
fi;
repeat
if IsPrimeInt( char ) then
rand_mat := Random( SL( l, K ) );
else
if l = 1 then
rand_mat := [ [ 1 ] ];
else
rand_mat := RandomUnimodularMat( l );
fi;
fi;
rand_inv := rand_mat^-1;
rand_mat := HomalgMatrix( rand_mat, k );
rand_inv := HomalgMatrix( rand_inv, k );
rand_mat := R * rand_mat;
rand_inv := R * rand_inv;
SetLeftInverse( rand_mat, rand_inv );
SetRightInverse( rand_mat, rand_inv );
SetLeftInverse( rand_inv, rand_mat );
SetRightInverse( rand_inv, rand_mat );
rand_mat := indets * rand_mat;
rand_inv := indets * rand_inv;
rand_mat := RingMap( rand_mat, R, R );
M := Pullback( rand_mat, M );
m := GetMonicUptoUnit( M );
until not m = fail;
rand_inv := RingMap( rand_inv, R, R );
SetIsIsomorphism( rand_mat, true );
SetIsIsomorphism( rand_inv, true );
return [ M, m, rand_mat, rand_inv ];
end );
##
InstallMethod( Inequalities,
"for a homalg ring",
[ IsHomalgRing ],
function( R )
local r, RP, J;
r := R;
RP := homalgTable( R );
if not IsBound(RP!.Inequalities) then
Error( "could not find a procedure called Inequalities in the homalgTable\n" );
fi;
J := RP!.Inequalities( R );
J := DuplicateFreeList( J );
if HasIsFieldForHomalg( R ) and IsFieldForHomalg( R ) then
r := R;
else
r := CoefficientsRing( R );
fi;
r := AssociatedPolynomialRing( r );
J := List( J, a -> a / r );
if IsBound( R!.Inequalities ) then
Append( J, R!.Inequalities );
fi;
J := DuplicateFreeList( J );
R!.Inequalities := J;
return J;
end );
##
InstallMethod( ClearDenominatorsRowWise,
"for a homalg matrix",
[ IsHomalgMatrix ],
function( M )
local R, RP, m, n, coeffs;
if IsZero( M ) then
return M;
elif IsOne( M ) then
return M;
fi;
R := HomalgRing( M );
RP := homalgTable( R );
m := NrRows( M );
n := NrColumns( M );
if IsBound(RP!.ClearDenominatorsRowWise) then
return HomalgMatrix( RP!.ClearDenominatorsRowWise( M ), m, n, R ); ## the external object
fi;
#=====# begin of the core procedure #=====#
coeffs := EntriesOfHomalgMatrixAsListList( M );
coeffs := List( coeffs, a -> Concatenation( List( a, b -> EntriesOfHomalgMatrix( Coefficients( b ) ) ) ) );
coeffs := List( coeffs, a -> List( a, b -> DenominatorRat( Rat( String( b ) ) ) ) );
coeffs := List( coeffs, Lcm );
coeffs := HomalgDiagonalMatrix( List( coeffs, a -> a / R ) );
return coeffs * M;
end );