# SPDX-License-Identifier: GPL-2.0-or-later
# Modules: A homalg based package for the Abelian category of finitely presented modules over computable rings
#
# Implementations
#
## Implementation stuff for some tool functors.
####################################
#
# install global functions/variables:
#
####################################
if HasCokernelEpi( phi ) then
return Range( CokernelEpi( phi ) );
fi;
R := HomalgRing( phi );
T := Range( phi );
## this is probably obsolete but clarifies our idea:
p := PositionOfTheDefaultSetOfGenerators( T ); ## avoid future possible side effects of the following command(s)
rel := UnionOfRelations( phi );
gen := GeneratorsOfModule( T );
gen := UnionOfRelations( gen, rel * gen );
coker := Presentation( gen, rel );
## the identity matrix is the matrix of the natural epimorphism
## w.r.t. the p-th set of relations of T and the first set of relations of coker:
id := HomalgIdentityMatrix( NrGenerators( gen ), R );
## the natural epimorphism:
epi := HomalgMap( id, [ T, p ], [ coker, 1 ] );
## for graded modules we need to know on which presentation the cokernel was computed
epi!.DefaultPresentationOfCokernelEpi := [ p, 1 ];
## even if IsMorphism( phi ) = false, in this data structure IsMorphism( epi ) = true
SetIsMorphism( epi, true );
## we cannot check this assertion, since
## checking it would cause an infinite loop
SetIsEpimorphism( epi, true );
## set the attribute CokernelEpi (specific for Cokernel):
SetCokernelEpi( phi, epi );
## the generalized inverse of the natural epimorphism
## (cf. [Bar, Cor. 4.8])
gen_iso := HomalgMap( id, [ coker, 1 ], [ T, p ] );
## set the morphism aid map
SetMorphismAid( gen_iso, phi );
## set the generalized inverse of the natural epimorphism
SetInverseOfGeneralizedMorphismWithFullDomain( epi, gen_iso );
## we cannot check this assertion, since
## checking it would cause an infinite loop
SetIsGeneralizedIsomorphism( gen_iso, true );
#=====# end of the core procedure #=====#
## abelian category: [HS, Prop. II.9.6]
if HasImageObjectEmb( phi ) then
img_emb := ImageObjectEmb( phi );
SetKernelEmb( epi, img_emb );
if not HasCokernelEpi( img_emb ) then
SetCokernelEpi( img_emb, epi );
fi;
elif HasIsMonomorphism( phi ) and IsMonomorphism( phi ) then
SetKernelEmb( epi, phi );
fi;
## this is in general NOT a morphism,
## BUT it is one modulo the image of phi in T, and then even a monomorphism:
## this is enough for us since we will always view it this way (cf. [BR08, 3.1.1,(2), 3.1.2] )
emb := HomalgMap( id, [ coker, 1 ], [ T, p ] );
SetMorphismAid( emb, phi );
## we cannot check this assertion, since
## checking it would cause an infinite loop
SetIsGeneralizedIsomorphism( emb, true );
## save the natural embedding in the cokernel (thanks GAP):
coker!.NaturalGeneralizedEmbedding := emb;
if HasImageObjectEmb( phi ) then
return Source( ImageObjectEmb( phi ) );
fi;
T := Range( phi );
## this is probably obsolete but clarifies our idea:
p := PositionOfTheDefaultSetOfGenerators( T ); ## avoid future possible side effects of the following command(s)
## emb is the matrix of the natural embedding
## w.r.t. the first set of relations of img and the p-th set of relations of T
emb := MatrixOfGenerators( img, 1 );
## set the attribute ImageObjectEmb (specific for ImageObject):
## (since ImageObjectEmb is listed below as a natural transformation
## for the functor ImageObject, a method will be automatically installed
## by InstallFunctor to fetch it by first invoking the main operation ImageObject)
SetImageObjectEmb( phi, emb );
#=====# end of the core procedure #=====#
## abelian category: [HS, Prop. II.9.6]
if HasCokernelEpi( phi ) then
coker_epi := CokernelEpi( phi );
SetCokernelEpi( emb, coker_epi );
if not HasKernelEmb( coker_epi ) then
SetKernelEmb( coker_epi, emb );
fi;
fi;
## at last define the image submodule
img_submodule := ImageSubobject( phi );
SetProcedureToNormalizeGenerators( hom, [ proc_to_normalize_generators, [ M, s ], [ N, t ] ] );
SetProcedureToReadjustGenerators( hom, [ proc_to_readjust_generators, [ M, s, ], [ N, t ] ] );
mor := CompleteImageSquare( emb_source, hull_phi, emb_target );
## HasIsIsomorphism( phi ) and IsIsomorphism( phi ), resp.
## HasIsMorphism( phi ) and IsMorphism( phi ), and
## UpdateObjectsByMorphism( mor )
## will be taken care of in FunctorMap
if covariant then
## Hom( L, - )
if HasIsMonomorphism( phi ) and IsMonomorphism( phi ) then
## check assertion
Assert( 3, IsMonomorphism( mor ) );
SetIsMonomorphism( mor, true );
fi;
if HasIsEpimorphism( phi ) and IsEpimorphism( phi ) and
HasIsProjective( L ) and IsProjective( L ) then
## check assertion
Assert( 3, IsEpimorphism( mor ) );
SetIsEpimorphism( mor, true );
fi;
else
## Hom( -, L )
if HasIsEpimorphism( phi ) and IsEpimorphism( phi ) then
## check assertion
Assert( 3, IsMonomorphism( mor ) );
SetIsMonomorphism( mor, true );
fi;
if HasIsMonomorphism( phi ) and IsMonomorphism( phi ) and
HasIsInjective( L ) and IsInjective( L ) then
## check assertion
Assert( 3, IsEpimorphism( mor ) );
if not IsBound( R!.Functor_R_Hom ) then
if IsBound( R!.creation_number ) then
R!.Functor_R_Hom := LeftDualizingFunctor( R, Concatenation( "R", String( R!.creation_number ), "_Hom" ) );
else
Error( "the homalg ring doesn't have a creation number\n" );
fi;
fi;
if not IsBound( R!.Functor_Hom_R ) then
if IsBound( R!.creation_number ) then
R!.Functor_Hom_R := RightDualizingFunctor( R, Concatenation( "Hom_R", String( R!.creation_number ) ) );
else
Error( "the homalg ring doesn't have a creation number\n" );
fi;
fi;
BindGlobal( "_Functor_TensorProduct_OnModules", ### defines: TensorProduct (object part)
function( M, N )
local R, rl, l0, _l0, matM, matN, idM, idN, MN,
F, gen, proc_to_readjust_generators, proc_to_normalize_generators, p;
R := HomalgRing( M );
## do not use CheckIfTheyLieInTheSameCategory here
if not IsIdenticalObj( R, HomalgRing( N ) ) then
Error( "the rings of the source and target modules are not identical\n" );
fi;
if IsHomalgRightObjectOrMorphismOfRightObjects( M ) then
if IsHomalgLeftObjectOrMorphismOfLeftObjects( N ) then
rl := [ true, true ];
else
rl := [ true, false ];
fi;
else
if IsHomalgLeftObjectOrMorphismOfLeftObjects( N ) then
rl := [ false, true ];
else
rl := [ false, false ];
fi;
fi;
l0 := NrGenerators( M );
_l0 := NrGenerators( N );
matM := MatrixOfMap( PresentationMorphism( M ) );
matN := MatrixOfMap( PresentationMorphism( N ) );
if rl = [ true, true ] or rl = [ false, false ] then
matM := Involution( matM ); ## the first module follows the second
fi;
idM := HomalgIdentityMatrix( l0, R );
idN := HomalgIdentityMatrix( _l0, R );
matM := KroneckerMat( matM, idN );
matN := KroneckerMat( idM, matN );
## the result has the parity of the second module
if rl[2] then
MN := UnionOfRows( matM, matN );
F := HomalgFreeLeftModule( NrGenerators( M ) * NrGenerators( N ), R );
else
MN := UnionOfColumns( matM, matN );
F := HomalgFreeRightModule( NrGenerators( M ) * NrGenerators( N ), R );
fi;
if arg_before_pos = [ ] and Length( arg_behind_pos ) = 1 then
## phi \tensor L
L := arg_behind_pos[1];
M_or_mor := phi;
N_or_mor := L;
elif Length( arg_before_pos ) = 1 and arg_behind_pos = [ ] then
## L \tensor phi
L := arg_before_pos[1];
M_or_mor := L;
N_or_mor := phi;
else
Error( "wrong input\n" );
fi;
## do not use CheckIfTheyLieInTheSameCategory here
if not IsIdenticalObj( R, HomalgRing( L ) ) then
Error( "the module and the morphism are not defined over identically the same ring\n" );
fi;
## decide whether the output module is left/right depending on the input
if IsHomalgRightObjectOrMorphismOfRightObjects( M_or_mor ) then
if IsHomalgLeftObjectOrMorphismOfLeftObjects( N_or_mor ) then
rl := [ true, true ];
else
rl := [ true, false ];
fi;
else
if IsHomalgLeftObjectOrMorphismOfLeftObjects( N_or_mor ) then
rl := [ false, true ];
else
rl := [ false, false ];
fi;
fi;
if IsMapOfFinitelyGeneratedModulesRep( M_or_mor )
and IsFinitelyPresentedModuleRep( N_or_mor ) then
phi := M_or_mor;
L := N_or_mor;
idL := HomalgIdentityMatrix( NrGenerators( L ), R );
if rl = [ true, true ] or rl = [ false, false ] then
phi := Involution( MatrixOfMap( phi ) ); ## the first module follows the second
else
phi := MatrixOfMap( phi );
fi;
hull_phi := KroneckerMat( phi, idL );
elif IsMapOfFinitelyGeneratedModulesRep( N_or_mor )
and IsFinitelyPresentedModuleRep( M_or_mor ) then
phi := N_or_mor;
L := M_or_mor;
idL := HomalgIdentityMatrix( NrGenerators( L ), R );
mor := CompleteImageSquare( emb_source, hull_phi, emb_target );
## HasIsIsomorphism( phi ) and IsIsomorphism( phi ), resp.
## HasIsMorphism( phi ) and IsMorphism( phi ), and
## UpdateObjectsByMorphism( mor )
## will be taken care of in FunctorMap
if HasIsEpimorphism( phi ) and IsEpimorphism( phi ) then
## check assertion
Assert( 3, IsEpimorphism( mor ) );
SetIsEpimorphism( mor, true );
fi;
if HasIsMonomorphism( phi ) and IsMonomorphism( phi ) and
HasIsProjective( L ) and IsProjective( L ) then
## check assertion
Assert( 3, IsMonomorphism( mor ) );
##
BindGlobal( "_functor_BaseChange_OnModules", ### defines: BaseChange (object part)
function( _R, M )
local R, S, lift, mat, left, distinguished, N;
R := HomalgRing( _R );
if IsIdenticalObj( HomalgRing( M ), R ) then
return M;
fi;
S := HomalgRing( M );
lift := HasRingRelations( S ) and IsIdenticalObj( R, AmbientRing( S ) );
mat := MatrixOfRelations( M );
left := IsHomalgLeftObjectOrMorphismOfLeftObjects( M );
distinguished := IsBound( M!.distinguished ) and M!.distinguished = true;
distinguished := distinguished and not lift;
if not distinguished then
if lift then
if left then
mat := StackedRelations( mat );
else
mat := AugmentedRelations( mat );
fi;
else
mat := R * mat;
if HasRingRelations( R ) then
if left then
mat := GetRidOfObsoleteRows( mat );
else
mat := GetRidOfObsoleteColumns( mat );
fi;
fi;
fi;
fi;
if left then
if distinguished then
if HasIsZero( M ) and IsZero( M ) then
N := 0 * R;
else
N := 1 * R;
fi;
else
N := LeftPresentation( mat );
fi;
else
if distinguished then
if HasIsZero( M ) and IsZero( M ) then
N := R * 0;
else
N := R * 1;
fi;
else
N := RightPresentation( mat );
fi;
fi;
## <#GAPDoc Label="Functor_Ext:code">
## Below is the only <E>specific</E> line of code used to define <C>Functor_Ext_for_fp_modules</C>
## and all the different operations <C>Ext</C> in &homalg;.
## <Listing Type="Code"><![CDATA[
RightSatelliteOfCofunctor( Functor_Hom_for_fp_modules, "Ext" );
## ]]></Listing>
## <#/GAPDoc>
## <#GAPDoc Label="Ext">
## <ManSection>
## <Oper Arg="[c,]o1,o2[,str]" Name="Ext"/>
## <Description>
## Compute the <A>c</A>-th extension object of <A>o1</A> with <A>o2</A> where <A>c</A> is a nonnegative integer
## and <A>o1</A> resp. <A>o2</A> could be a module, a map, a complex (of modules or of again of complexes),
## or a chain morphism. If <A>str</A>=<Q>a</Q> then the (cohomologically) graded object
## <M>Ext^i(</M><A>o1</A>,<A>o2</A><M>)</M> for <M>0 \leq i \leq</M><A>c</A> is computed.
## If neither <A>c</A> nor <A>str</A> is specified then the cohomologically graded object
## <M>Ext^i(</M><A>o1</A>,<A>o2</A><M>)</M> for <M>0 \leq i \leq d</M> is computed,
## where <M>d</M> is the length of the internally computed free resolution of <A>o1</A>.
## <P/>
## Each generator of a module of extensions is displayed as a matrix of appropriate dimensions.
## <Example><![CDATA[
## gap> zz := HomalgRingOfIntegers( );
## Z
## gap> M := HomalgMatrix( "[ 2, 3, 4, 5, 6, 7 ]", 2, 3, zz );;
## gap> M := LeftPresentation( M );
## <A non-torsion left module presented by 2 relations for 3 generators>
## gap> N := TorsionObject( M );
## <A cyclic torsion left module presented by yet unknown relations for a cyclic \
## generator>
## gap> iota := TorsionObjectEmb( M );
## <A monomorphism of left modules>
## gap> psi := Ext( 1, iota, N );
## <A homomorphism of right modules>
## gap> ByASmallerPresentation( psi );
## <A non-zero homomorphism of right modules>
## gap> Display( psi );
## [ [ 1 ] ]
##
## the map is currently represented by the above 1 x 1 matrix
## gap> extNN := Range( psi );
## <A non-zero cyclic torsion right module on a cyclic generator satisfying 1 rel\
## ation>
## gap> IsIdenticalObj( extNN, Ext( 1, N, N ) ); ## the caching at work
## true
## gap> extMN := Source( psi );
## <A non-zero cyclic torsion right module on a cyclic generator satisfying 1 rel\
## ation>
## gap> IsIdenticalObj( extMN, Ext( 1, M, N ) ); ## the caching at work
## true
## gap> Display( extNN );
## Z/< 3 >
## gap> Display( extMN );
## Z/< 3 >
## ]]></Example>
## </Description>
## </ManSection>
## <#/GAPDoc>
##
## <#GAPDoc Label="Functor_Tor:code">
## Below is the only <E>specific</E> line of code used to define <C>Functor_Tor_for_fp_modules</C>
## and all the different operations <C>Tor</C> in &homalg;.
## <Listing Type="Code"><![CDATA[
LeftSatelliteOfFunctor( Functor_TensorProduct_for_fp_modules, "Tor" );
## ]]></Listing>
## <#/GAPDoc>
## <#GAPDoc Label="Tor">
## <ManSection>
## <Oper Arg="[c,]o1,o2[,str]" Name="Tor"/>
## <Description>
## Compute the <A>c</A>-th torsion object of <A>o1</A> with <A>o2</A> where <A>c</A> is a nonnegative integer
## and <A>o1</A> resp. <A>o2</A> could be a module, a map, a complex (of modules or of again of complexes),
## or a chain morphism. If <A>str</A>=<Q>a</Q> then the (cohomologically) graded object
## <M>Tor_i(</M><A>o1</A>,<A>o2</A><M>)</M> for <M>0 \leq i \leq</M><A>c</A> is computed.
## If neither <A>c</A> nor <A>str</A> is specified then the cohomologically graded object
## <M>Tor_i(</M><A>o1</A>,<A>o2</A><M>)</M> for <M>0 \leq i \leq d</M> is computed,
## where <M>d</M> is the length of the internally computed free resolution of <A>o1</A>.
## <Example><![CDATA[
## gap> zz := HomalgRingOfIntegers( );
## Z
## gap> M := HomalgMatrix( "[ 2, 3, 4, 5, 6, 7 ]", 2, 3, zz );;
## gap> M := LeftPresentation( M );
## <A non-torsion left module presented by 2 relations for 3 generators>
## gap> N := TorsionObject( M );
## <A cyclic torsion left module presented by yet unknown relations for a cyclic \
## generator>
## gap> iota := TorsionObjectEmb( M );
## <A monomorphism of left modules>
## gap> psi := Tor( 1, iota, N );
## <A homomorphism of left modules>
## gap> ByASmallerPresentation( psi );
## <A non-zero homomorphism of left modules>
## gap> Display( psi );
## [ [ 1 ] ]
##
## the map is currently represented by the above 1 x 1 matrix
## gap> torNN := Source( psi );
## <A non-zero cyclic torsion left module presented by 1 relation for a cyclic ge\
## nerator>
## gap> IsIdenticalObj( torNN, Tor( 1, N, N ) ); ## the caching at work
## true
## gap> torMN := Range( psi );
## <A non-zero cyclic torsion left module presented by 1 relation for a cyclic ge\
## nerator>
## gap> IsIdenticalObj( torMN, Tor( 1, M, N ) ); ## the caching at work
## true
## gap> Display( torNN );
## Z/< 3 >
## gap> Display( torMN );
## Z/< 3 >
## ]]></Example>
## </Description>
## </ManSection>
## <#/GAPDoc>
##
## <#GAPDoc Label="Functor_RHom:code">
## Below is the only <E>specific</E> line of code used to define <C>Functor_RHom_for_fp_modules</C>
## and all the different operations <C>RHom</C> in &homalg;.
## <Listing Type="Code"><![CDATA[
RightDerivedCofunctor( Functor_Hom_for_fp_modules );
## ]]></Listing>
## <#/GAPDoc>
## <#GAPDoc Label="RHom">
## <ManSection>
## <Oper Arg="[c,]o1,o2[,str]" Name="RHom"/>
## <Description>
## Compute the <A>c</A>-th extension object of <A>o1</A> with <A>o2</A> where <A>c</A> is a nonnegative integer
## and <A>o1</A> resp. <A>o2</A> could be a module, a map, a complex (of modules or of again of complexes),
## or a chain morphism. The string <A>str</A> may take different values:
## <List>
## <Item>If <A>str</A>=<Q>a</Q> then <M>R^i Hom(</M><A>o1</A>,<A>o2</A><M>)</M> for <M>0 \leq i \leq</M><A>c</A>
## is computed.</Item>
## <Item>If <A>str</A>=<Q>c</Q> then the <A>c</A>-th connecting homomorphism with respect to
## the short exact sequence <A>o1</A> is computed.</Item>
## <Item>If <A>str</A>=<Q>t</Q> then the exact triangle upto cohomological degree <A>c</A> with respect to
## the short exact sequence <A>o1</A> is computed.</Item>
## </List>
## If neither <A>c</A> nor <A>str</A> is specified then the cohomologically graded object
## <M>R^i Hom(</M><A>o1</A>,<A>o2</A><M>)</M> for <M>0 \leq i \leq d</M> is computed,
## where <M>d</M> is the length of the internally computed free resolution of <A>o1</A>.
## <P/>
## Each generator of a module of derived homomorphisms is displayed as a matrix of appropriate dimensions.
## <#Include Label="RHom_Z">
## </Description>
## </ManSection>
## <#/GAPDoc>
##
## <#GAPDoc Label="Functor_LTensorProduct:code">
## Below is the only <E>specific</E> line of code used to define <C>Functor_LTensorProduct_for_fp_modules</C>
## and all the different operations <C>LTensorProduct</C> in &homalg;.
## <Listing Type="Code"><![CDATA[
LeftDerivedFunctor( Functor_TensorProduct_for_fp_modules );
## ]]></Listing>
## <#/GAPDoc>
## <#GAPDoc Label="LTensorProduct">
## <ManSection>
## <Oper Arg="[c,]o1,o2[,str]" Name="LTensorProduct"/>
## <Description>
## Compute the <A>c</A>-th torsion object of <A>o1</A> with <A>o2</A> where <A>c</A> is a nonnegative integer
## and <A>o1</A> resp. <A>o2</A> could be a module, a map, a complex (of modules or of again of complexes),
## or a chain morphism. The string <A>str</A> may take different values:
## <List>
## <Item>If <A>str</A>=<Q>a</Q> then <M>L_i TensorProduct(</M><A>o1</A>,<A>o2</A><M>)</M> for <M>0 \leq i \leq</M><A>c</A>
## is computed.</Item>
## <Item>If <A>str</A>=<Q>c</Q> then the <A>c</A>-th connecting homomorphism with respect to
## the short exact sequence <A>o1</A> is computed.</Item>
## <Item>If <A>str</A>=<Q>t</Q> then the exact triangle upto cohomological degree <A>c</A> with respect to
## the short exact sequence <A>o1</A> is computed.</Item>
## </List>
## If neither <A>c</A> nor <A>str</A> is specified then the cohomologically graded object
## <M>L_i TensorProduct(</M><A>o1</A>,<A>o2</A><M>)</M> for <M>0 \leq i \leq d</M> is computed,
## where <M>d</M> is the length of the internally computed free resolution of <A>o1</A>.
## <P/>
## Each generator of a module of derived homomorphisms is displayed as a matrix of appropriate dimensions.
## <#Include Label="LTensorProduct_Z">
## </Description>
## </ManSection>
## <#/GAPDoc>
##
##
## HomHom( M, K, N ) = Hom( Hom( M, K ), N )
##
## <#GAPDoc Label="Functor_HomHom:code">
## Below is the only <E>specific</E> line of code used to define <C>Functor_HomHom_for_fp_modules</C>
## and all the different operations <C>HomHom</C> in &homalg;.
## <Listing Type="Code"><![CDATA[
Functor_Hom_for_fp_modules * Functor_Hom_for_fp_modules;
## ]]></Listing>
## <#/GAPDoc>
## <#GAPDoc Label="Functor_LHomHom:code">
## Below is the only <E>specific</E> line of code used to define <C>Functor_LHomHom_for_fp_modules</C>
## and all the different operations <C>LHomHom</C> in &homalg;.
## <Listing Type="Code"><![CDATA[
LeftDerivedFunctor( Functor_HomHom_for_fp_modules );
## ]]></Listing>
## <#/GAPDoc>
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.