GAP 4.8.9 installation with standard packages -- copy to your CoCalc project to get it
#############################################################################
##
## BasicFunctors.gi Modules package Mohamed Barakat
##
## Copyright 2007-2010 Mohamed Barakat, RWTH Aachen
##
## Implementation stuff for some tool functors.
##
#############################################################################
####################################
#
# install global functions/variables:
#
####################################
##
## Cokernel
##
##
InstallGlobalFunction( _Functor_Cokernel_OnModules, ### defines: Cokernel(Epi)
function( phi )
local R, T, p, rel, gen, coker, id, epi, gen_iso, img_emb, emb;
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;
return coker;
end );
## <#GAPDoc Label="functor_Cokernel:code">
## <Listing Type="Code"><![CDATA[
InstallValue( functor_Cokernel_for_fp_modules,
CreateHomalgFunctor(
[ "name", "Cokernel" ],
[ "category", HOMALG_MODULES.category ],
[ "operation", "Cokernel" ],
[ "natural_transformation", "CokernelEpi" ],
[ "special", true ],
[ "number_of_arguments", 1 ],
[ "1", [ [ "covariant" ],
[ IsMapOfFinitelyGeneratedModulesRep,
[ IsHomalgChainMorphism, IsImageSquare ] ] ] ],
[ "OnObjects", _Functor_Cokernel_OnModules ]
)
);
## ]]></Listing>
## <#/GAPDoc>
functor_Cokernel_for_fp_modules!.ContainerForWeakPointersOnComputedBasicMorphisms := true;
##
## ImageObject
##
InstallGlobalFunction( _Functor_ImageObject_OnModules, ### defines: ImageObject(Emb)
function( phi )
local T, p, img, emb, coker_epi, img_submodule;
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)
## the image module
img := MatrixOfMap( phi ) / T;
## 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 );
emb := HomalgMap( emb, [ img, 1 ], [ T, p ] );
## check assertion
Assert( 5, IsMonomorphism( emb ) );
SetIsMonomorphism( emb, true );
INSTALL_TODO_LIST_ENTRIES_FOR_MORPHISMS_AND_IMAGE_EMBEDDINGS( phi, emb );
## 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 );
SetUnderlyingSubobject( img, img_submodule );
SetEmbeddingInSuperObject( img_submodule, emb );
MatchPropertiesAndAttributesOfSubobjectAndUnderlyingObject( img_submodule, img );
## save the natural embedding in the image (thanks GAP):
img!.NaturalGeneralizedEmbedding := emb;
return img;
end );
## <#GAPDoc Label="functor_ImageObject:code">
## <Listing Type="Code"><![CDATA[
InstallValue( functor_ImageObject_for_fp_modules,
CreateHomalgFunctor(
[ "name", "ImageObject for modules" ],
[ "category", HOMALG_MODULES.category ],
[ "operation", "ImageObject" ],
[ "natural_transformation", "ImageObjectEmb" ],
[ "number_of_arguments", 1 ],
[ "1", [ [ "covariant" ],
[ IsMapOfFinitelyGeneratedModulesRep and
AdmissibleInputForHomalgFunctors ] ] ],
[ "OnObjects", _Functor_ImageObject_OnModules ]
)
);
## ]]></Listing>
## <#/GAPDoc>
functor_ImageObject_for_fp_modules!.ContainerForWeakPointersOnComputedBasicMorphisms := true;
##
## Hom
##
InstallGlobalFunction( _Functor_Hom_OnModules, ### defines: Hom (object part)
function( M, N )
local s, t, dM, dN, P1, l0, l1, _l0, matM, matN, R, HP0N, HP1N, r, c, idN,
alpha, hom, gen, proc_to_readjust_generators, proc_to_normalize_generators, p;
CheckIfTheyLieInTheSameCategory( M, N );
s := PositionOfTheDefaultSetOfGenerators( M );
t := PositionOfTheDefaultSetOfGenerators( N );
dM := PresentationMorphism( M );
dN := PresentationMorphism( N );
P1 := Source( dM );
l0 := NrGenerators( M );
l1 := NrGenerators( P1 );
_l0 := NrGenerators( N );
matM := MatrixOfMap( dM );
matN := MatrixOfMap( dN );
R := HomalgRing( M );
if l0 = 0 then
HP0N := HomalgZeroMatrix( 0, 0, R );
else
HP0N := DiagMat( ListWithIdenticalEntries( l0, Involution( matN ) ) );
fi;
if l1 = 0 then
HP1N := HomalgZeroMatrix( 0, 0, R );
else
HP1N := DiagMat( ListWithIdenticalEntries( l1, Involution( matN ) ) );
fi;
if IsHomalgLeftObjectOrMorphismOfLeftObjects( M ) then
r := l0;
c := _l0;
proc_to_normalize_generators :=
function( mat, M_with_s, N_with_t )
local M, s, N, t, mor, mat_old;
## for better readability of the code:
M := M_with_s[1];
s := M_with_s[2];
N := N_with_t[1];
t := N_with_t[2];
## we assume mat to be a matrix of a morphism
## w.r.t. the CURRENT generators of source and target:
mor := HomalgMap( mat, M, N );
mat_old := MatrixOfMap( mor, s, t );
return ConvertMatrixToColumn( mat_old );
end;
proc_to_readjust_generators :=
function( gen, M_with_s, N_with_t )
local c, r, mat_old, mor;
## M_with_s = [ M, s ]
## N_with_t = [ N, t ]
r := CallFuncList( NrGenerators, M_with_s );
c := CallFuncList( NrGenerators, N_with_t );
mat_old := ConvertColumnToMatrix( gen, r, c );
## the matrix of the morphism will be displayed
## w.r.t. the CURRENT generators of source and target
mor := HomalgMap( mat_old, M_with_s, N_with_t );
## check assertion
Assert( 3, IsMorphism( mor ) );
SetIsMorphism( mor, true );
return mor;
end;
HP0N := RightPresentation( HP0N );
HP1N := RightPresentation( HP1N );
else
r := _l0;
c := l0;
proc_to_normalize_generators :=
function( mat, M_with_s, N_with_t )
local M, s, N, t, mor, mat_old;
## for better readability of the code:
M := M_with_s[1];
s := M_with_s[2];
N := N_with_t[1];
t := N_with_t[2];
## we assume mat to be a matrix of a morphism
## w.r.t. the CURRENT generators of source and target:
mor := HomalgMap( mat, M, N );
mat_old := MatrixOfMap( mor, s, t );
return ConvertMatrixToRow( mat_old );
end;
proc_to_readjust_generators :=
function( gen, M_with_s, N_with_t )
local c, r, mat_old, mor;
## M_with_s = [ M, s ]
## N_with_t = [ N, t ]
c := CallFuncList( NrGenerators, M_with_s );
r := CallFuncList( NrGenerators, N_with_t );
mat_old := ConvertRowToMatrix( gen, r, c );
## the matrix of the morphism will be displayed
## w.r.t. the CURRENT generators of source and target
mor := HomalgMap( mat_old, M_with_s, N_with_t );
## check assertion
Assert( 3, IsMorphism( mor ) );
SetIsMorphism( mor, true );
return mor;
end;
HP0N := LeftPresentation( HP0N );
HP1N := LeftPresentation( HP1N );
fi;
idN := HomalgIdentityMatrix( _l0, R );
alpha := KroneckerMat( matM, idN );
alpha := HomalgMap( alpha, HP0N, HP1N );
SetIsMorphism( alpha, true );
hom := Kernel( alpha );
#=====# end of the core procedure #=====#
SetProcedureToNormalizeGenerators( hom, [ proc_to_normalize_generators, [ M, s ], [ N, t ] ] );
SetProcedureToReadjustGenerators( hom, [ proc_to_readjust_generators, [ M, s, ], [ N, t ] ] );
return hom;
end );
##
InstallGlobalFunction( _Functor_Hom_OnMaps, ### defines: Hom (morphism part)
function( F_source, F_target, arg_before_pos, phi, arg_behind_pos )
local R, L, idL, hull_phi, covariant, emb_source, emb_target, mor;
R := HomalgRing( phi );
if arg_before_pos = [ ] and Length( arg_behind_pos ) = 1 then
## Hom( phi, L )
L := arg_behind_pos[1];
idL := HomalgIdentityMatrix( NrGenerators( L ), R );
hull_phi := KroneckerMat( MatrixOfMap( phi ), idL );
covariant := false;
elif Length( arg_before_pos ) = 1 and arg_behind_pos = [ ] then
## Hom( L, phi )
L := arg_before_pos[1];
idL := HomalgIdentityMatrix( NrGenerators( L ), R );
hull_phi := Involution( KroneckerMat( idL, MatrixOfMap( phi ) ) );
covariant := true;
else
Error( "wrong input\n" );
fi;
emb_source := NaturalGeneralizedEmbedding( F_source );
emb_target := NaturalGeneralizedEmbedding( F_target );
hull_phi := HomalgMap( hull_phi, Range( emb_source ), Range( emb_target ) );
SetIsMorphism( hull_phi, true );
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 ) );
SetIsEpimorphism( mor, true );
fi;
fi;
return mor;
end );
## <#GAPDoc Label="Functor_Hom:code">
## <Listing Type="Code"><![CDATA[
InstallValue( Functor_Hom_for_fp_modules,
CreateHomalgFunctor(
[ "name", "Hom" ],
[ "category", HOMALG_MODULES.category ],
[ "operation", "Hom" ],
[ "number_of_arguments", 2 ],
[ "1", [ [ "contravariant", "right adjoint", "distinguished" ] ] ],
[ "2", [ [ "covariant", "left exact" ] ] ],
[ "OnObjects", _Functor_Hom_OnModules ],
[ "OnMorphisms", _Functor_Hom_OnMaps ],
[ "MorphismConstructor", HOMALG_MODULES.category.MorphismConstructor ]
)
);
## ]]></Listing>
## <#/GAPDoc>
Functor_Hom_for_fp_modules!.ContainerForWeakPointersOnComputedBasicObjects := true;
Functor_Hom_for_fp_modules!.ContainerForWeakPointersOnComputedBasicMorphisms := true;
##
InstallMethod( NatTrIdToHomHom_R,
"for homalg modules",
[ IsFinitelyPresentedModuleRep ],
function( M )
local HM, iota, HHM, bas, epsilon;
HM := Hom( M );
iota := MatrixOfGenerators( HM );
HHM := Hom( HM );
bas := MatrixOfGenerators( HHM );
if IsHomalgLeftObjectOrMorphismOfLeftObjects( M ) then
epsilon := RightDivide( iota, bas );
else
epsilon := LeftDivide( iota, bas );
fi;
epsilon := HomalgMap( epsilon, M, HHM );
SetPropertiesIfKernelIsTorsionObject( epsilon );
return epsilon;
end );
##
InstallMethod( LeftDualizingFunctor,
"for homalg rings",
[ IsHomalgRing, IsString ],
function( R, name )
return InsertObjectInMultiFunctor( Functor_Hom_for_fp_modules, 2, 1 * R, name );
end );
##
InstallMethod( LeftDualizingFunctor,
"for homalg rings",
[ IsHomalgRing ],
function( R )
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;
return R!.Functor_R_Hom;
end );
##
InstallMethod( RightDualizingFunctor,
"for homalg rings",
[ IsHomalgRing, IsString ],
function( R, name )
return InsertObjectInMultiFunctor( Functor_Hom_for_fp_modules, 2, R * 1, name );
end );
##
InstallMethod( RightDualizingFunctor,
"for homalg rings",
[ IsHomalgRing ],
function( R )
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;
return R!.Functor_Hom_R;
end );
##
InstallMethod( Dualize,
"for homalg modules or submodules",
[ IsFinitelyPresentedModuleOrSubmoduleRep ],
Hom );
##
InstallMethod( Dualize,
"for homalg module maps",
[ IsMapOfFinitelyGeneratedModulesRep ],
Hom );
##
## TensorProduct
##
InstallGlobalFunction( _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;
MN := HomalgMap( MN, "free", F );
return Cokernel( MN );
end );
##
InstallGlobalFunction( _Functor_TensorProduct_OnMaps, ### defines: TensorProduct (morphism part)
function( F_source, F_target, arg_before_pos, phi, arg_behind_pos )
local R, L, M_or_mor, N_or_mor, rl, idL, hull_phi,
emb_source, emb_target, mor;
R := HomalgRing( phi );
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 );
hull_phi := KroneckerMat( idL, MatrixOfMap( phi ) );
fi;
emb_source := NaturalGeneralizedEmbedding( F_source );
emb_target := NaturalGeneralizedEmbedding( F_target );
hull_phi := HomalgMap( hull_phi, Range( emb_source ), Range( emb_target ) );
SetIsMorphism( hull_phi, true );
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 ) );
SetIsMonomorphism( mor, true );
fi;
return mor;
end );
## <#GAPDoc Label="Functor_TensorProduct:code">
## <Listing Type="Code"><![CDATA[
InstallValue( Functor_TensorProduct_for_fp_modules,
CreateHomalgFunctor(
[ "name", "TensorProduct" ],
[ "category", HOMALG_MODULES.category ],
[ "operation", "TensorProductOp" ],
[ "number_of_arguments", 2 ],
[ "1", [ [ "covariant", "left adjoint", "distinguished" ] ] ],
[ "2", [ [ "covariant", "left adjoint" ] ] ],
[ "OnObjects", _Functor_TensorProduct_OnModules ],
[ "OnMorphisms", _Functor_TensorProduct_OnMaps ],
[ "MorphismConstructor", HOMALG_MODULES.category.MorphismConstructor ]
)
);
## ]]></Listing>
## <#/GAPDoc>
Functor_TensorProduct_for_fp_modules!.ContainerForWeakPointersOnComputedBasicObjects := true;
Functor_TensorProduct_for_fp_modules!.ContainerForWeakPointersOnComputedBasicMorphisms := true;
##
## BaseChange
##
##
InstallGlobalFunction( _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 := UnionOfRows( mat );
else
mat := UnionOfColumns( 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;
return N;
end );
##
InstallOtherMethod( BaseChange,
"for homalg maps",
[ IsHomalgRing, IsMapOfFinitelyGeneratedModulesRep ], 1001,
function( R, phi )
return HomalgMap( R * MatrixOfMap( phi ), R * Source( phi ), R * Range( phi ) );
end );
##
InstallOtherMethod( BaseChange,
"for homalg maps",
[ IsHomalgModule, IsMapOfFinitelyGeneratedModulesRep ], 1001,
function( _R, phi )
local R;
return BaseChange( HomalgRing( _R ), phi );
end );
InstallValue( functor_BaseChange_for_fp_modules,
CreateHomalgFunctor(
[ "name", "BaseChange" ],
[ "category", HOMALG_MODULES.category ],
[ "operation", "BaseChange" ],
[ "number_of_arguments", 2 ],
[ "1", [ [ "covariant" ] ] ],
[ "2", [ [ "covariant" ] ] ],
[ "OnObjects", _functor_BaseChange_OnModules ]
)
);
functor_BaseChange_for_fp_modules!.ContainerForWeakPointersOnComputedBasicObjects := true;
#functor_BaseChange_for_fp_modules!.ContainerForWeakPointersOnComputedBasicMorphisms :=
# ContainerForWeakPointers( TheTypeContainerForWeakPointersOnComputedValuesOfFunctor );
####################################
#
# methods for operations & attributes:
#
####################################
##
## Cokernel( phi ) and CokernelEpi( phi )
##
## <#GAPDoc Label="functor_Cokernel">
## <ManSection>
## <Var Name="functor_Cokernel"/>
## <Description>
## The functor that associates to a map its cokernel.
## <#Include Label="functor_Cokernel:code">
## </Description>
## </ManSection>
## <#/GAPDoc>
## <#GAPDoc Label="Cokernel">
## <ManSection>
## <Oper Arg="phi" Name="Cokernel"/>
## <Description>
## The following example also makes use of the natural transformation <C>CokernelEpi</C>.
## <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 := HomalgMatrix( "[ 2, 3, 4, 5, 6, 7, 8, 9 ]", 2, 4, ZZ );;
## gap> N := LeftPresentation( N );
## <A non-torsion left module presented by 2 relations for 4 generators>
## gap> mat := HomalgMatrix( "[ \
## > 1, 0, -3, -6, \
## > 0, 1, 6, 11, \
## > 1, 0, -3, -6 \
## > ]", 3, 4, ZZ );;
## gap> phi := HomalgMap( mat, M, N );;
## gap> IsMorphism( phi );
## true
## gap> phi;
## <A homomorphism of left modules>
## gap> coker := Cokernel( phi );
## <A left module presented by 5 relations for 4 generators>
## gap> ByASmallerPresentation( coker );
## <A rank 1 left module presented by 1 relation for 2 generators>
## gap> Display( coker );
## Z/< 8 > + Z^(1 x 1)
## gap> nu := CokernelEpi( phi );
## <An epimorphism of left modules>
## gap> Display( nu );
## [ [ -5, 0 ],
## [ -6, 1 ],
## [ 1, -2 ],
## [ 0, 1 ] ]
##
## the map is currently represented by the above 4 x 2 matrix
## gap> DefectOfExactness( phi, nu );
## <A zero left module>
## gap> ByASmallerPresentation( nu );
## <A non-zero epimorphism of left modules>
## gap> Display( nu );
## [ [ 2, 0 ],
## [ 1, -2 ],
## [ 0, 1 ] ]
##
## the map is currently represented by the above 3 x 2 matrix
## gap> PreInverse( nu );
## false
## ]]></Example>
## </Description>
## </ManSection>
## <#/GAPDoc>
##
InstallFunctor( functor_Cokernel_for_fp_modules );
##
## ImageObject( phi ) and ImageObjectEmb( phi )
##
## <#GAPDoc Label="functor_ImageObject">
## <ManSection>
## <Var Name="functor_ImageObject"/>
## <Description>
## The functor that associates to a map its image.
## <#Include Label="functor_ImageObject:code">
## </Description>
## </ManSection>
## <#/GAPDoc>
## <#GAPDoc Label="ImageObject">
## <ManSection>
## <Oper Arg="phi" Name="ImageObject"/>
## <Description>
## The following example also makes use of the natural transformations <C>ImageObjectEpi</C>
## and <C>ImageObjectEmb</C>.
## <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 := HomalgMatrix( "[ 2, 3, 4, 5, 6, 7, 8, 9 ]", 2, 4, ZZ );;
## gap> N := LeftPresentation( N );
## <A non-torsion left module presented by 2 relations for 4 generators>
## gap> mat := HomalgMatrix( "[ \
## > 1, 0, -3, -6, \
## > 0, 1, 6, 11, \
## > 1, 0, -3, -6 \
## > ]", 3, 4, ZZ );;
## gap> phi := HomalgMap( mat, M, N );;
## gap> IsMorphism( phi );
## true
## gap> phi;
## <A homomorphism of left modules>
## gap> im := ImageObject( phi );
## <A left module presented by yet unknown relations for 3 generators>
## gap> ByASmallerPresentation( im );
## <A free left module of rank 1 on a free generator>
## gap> pi := ImageObjectEpi( phi );
## <A non-zero split epimorphism of left modules>
## gap> epsilon := ImageObjectEmb( phi );
## <A monomorphism of left modules>
## gap> phi = pi * epsilon;
## true
## ]]></Example>
## </Description>
## </ManSection>
## <#/GAPDoc>
##
InstallFunctorOnObjects( functor_ImageObject_for_fp_modules );
##
## Kernel( phi ) and KernelEmb( phi )
##
## <#GAPDoc Label="Kernel:map">
## <ManSection>
## <Oper Arg="phi" Name="Kernel" Label="for maps"/>
## <Description>
## The following example also makes use of the natural transformation <C>KernelEmb</C>.
## <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 := HomalgMatrix( "[ 2, 3, 4, 5, 6, 7, 8, 9 ]", 2, 4, ZZ );;
## gap> N := LeftPresentation( N );
## <A non-torsion left module presented by 2 relations for 4 generators>
## gap> mat := HomalgMatrix( "[ \
## > 1, 0, -3, -6, \
## > 0, 1, 6, 11, \
## > 1, 0, -3, -6 \
## > ]", 3, 4, ZZ );;
## gap> phi := HomalgMap( mat, M, N );;
## gap> IsMorphism( phi );
## true
## gap> phi;
## <A homomorphism of left modules>
## gap> ker := Kernel( phi );
## <A cyclic left module presented by yet unknown relations for a cyclic generato\
## r>
## gap> Display( ker );
## Z/< -3 >
## gap> ByASmallerPresentation( last );
## <A cyclic torsion left module presented by 1 relation for a cyclic generator>
## gap> Display( ker );
## Z/< 3 >
## gap> iota := KernelEmb( phi );
## <A monomorphism of left modules>
## gap> Display( iota );
## [ [ 0, 2, 4 ] ]
##
## the map is currently represented by the above 1 x 3 matrix
## gap> DefectOfExactness( iota, phi );
## <A zero left module>
## gap> ByASmallerPresentation( iota );
## <A non-zero monomorphism of left modules>
## gap> Display( iota );
## [ [ 2, 0 ] ]
##
## the map is currently represented by the above 1 x 2 matrix
## gap> PostInverse( iota );
## fail
## ]]></Example>
## </Description>
## </ManSection>
## <#/GAPDoc>
##
## DefectOfExactness( cpx_post_pre )
##
## <#GAPDoc Label="DefectOfExactness">
## <ManSection>
## <Oper Arg="phi, psi" Name="DefectOfExactness"/>
## <Description>
## We follow the associative convention for applying maps.
## For left modules <A>phi</A> is applied first and from the right.
## For right modules <A>psi</A> is applied first and from the left.
## <P/>
## The following example also makes use of the natural transformation <C>KernelEmb</C>.
## <Example><![CDATA[
## gap> ZZ := HomalgRingOfIntegers( );
## Z
## gap> M := HomalgMatrix( "[ 2, 3, 4, 0, 5, 6, 7, 0 ]", 2, 4, ZZ );;
## gap> M := LeftPresentation( M );
## <A non-torsion left module presented by 2 relations for 4 generators>
## gap> N := HomalgMatrix( "[ 2, 3, 4, 5, 6, 7, 8, 9 ]", 2, 4, ZZ );;
## gap> N := LeftPresentation( N );
## <A non-torsion left module presented by 2 relations for 4 generators>
## gap> mat := HomalgMatrix( "[ \
## > 1, 3, 3, 3, \
## > 0, 3, 10, 17, \
## > 1, 3, 3, 3, \
## > 0, 0, 0, 0 \
## > ]", 4, 4, ZZ );;
## gap> phi := HomalgMap( mat, M, N );;
## gap> IsMorphism( phi );
## true
## gap> phi;
## <A homomorphism of left modules>
## gap> iota := KernelEmb( phi );
## <A monomorphism of left modules>
## gap> DefectOfExactness( iota, phi );
## <A zero left module>
## gap> hom_iota := Hom( iota ); ## a shorthand for Hom( iota, ZZ );
## <A homomorphism of right modules>
## gap> hom_phi := Hom( phi ); ## a shorthand for Hom( phi, ZZ );
## <A homomorphism of right modules>
## gap> DefectOfExactness( hom_iota, hom_phi );
## <A cyclic right module on a cyclic generator satisfying yet unknown relations>
## gap> ByASmallerPresentation( last );
## <A cyclic torsion right module on a cyclic generator satisfying 1 relation>
## gap> Display( last );
## Z/< 2 >
## ]]></Example>
## </Description>
## </ManSection>
## <#/GAPDoc>
##
## Hom( M, N )
##
## <#GAPDoc Label="Functor_Hom">
## <ManSection>
## <Var Name="Functor_Hom"/>
## <Description>
## The bifunctor <C>Hom</C>.
## <#Include Label="Functor_Hom:code">
## </Description>
## </ManSection>
## <#/GAPDoc>
## <#GAPDoc Label="Hom">
## <ManSection>
## <Oper Arg="o1,o2" Name="Hom"/>
## <Description>
## <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.
## <P/>
## Each generator of a module of homomorphisms 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 := HomalgMatrix( "[ 2, 3, 4, 5, 6, 7, 8, 9 ]", 2, 4, ZZ );;
## gap> N := LeftPresentation( N );
## <A non-torsion left module presented by 2 relations for 4 generators>
## gap> mat := HomalgMatrix( "[ \
## > 1, 0, -3, -6, \
## > 0, 1, 6, 11, \
## > 1, 0, -3, -6 \
## > ]", 3, 4, ZZ );;
## gap> phi := HomalgMap( mat, M, N );;
## gap> IsMorphism( phi );
## true
## gap> phi;
## <A homomorphism of left modules>
## gap> psi := Hom( phi, M );
## <A homomorphism of right modules>
## gap> ByASmallerPresentation( psi );
## <A non-zero homomorphism of right modules>
## gap> Display( psi );
## [ [ 1, 1, 0, 1 ],
## [ 2, 2, 0, 0 ],
## [ 0, 0, 6, 10 ] ]
##
## the map is currently represented by the above 3 x 4 matrix
## gap> homNM := Source( psi );
## <A rank 2 right module on 4 generators satisfying 2 relations>
## gap> IsIdenticalObj( homNM, Hom( N, M ) ); ## the caching at work
## true
## gap> homMM := Range( psi );
## <A rank 1 right module on 3 generators satisfying 2 relations>
## gap> IsIdenticalObj( homMM, Hom( M, M ) ); ## the caching at work
## true
## gap> Display( homNM );
## Z/< 3 > + Z/< 3 > + Z^(2 x 1)
## gap> Display( homMM );
## Z/< 3 > + Z/< 3 > + Z^(1 x 1)
## gap> IsMonomorphism( psi );
## false
## gap> IsEpimorphism( psi );
## false
## gap> GeneratorsOfModule( homMM );
## <A set of 3 generators of a homalg right module>
## gap> Display( last );
## [ [ 0, 0, 0 ],
## [ 0, 1, 2 ],
## [ 0, 0, 0 ] ]
##
## the map is currently represented by the above 3 x 3 matrix
##
## [ [ 0, 2, 4 ],
## [ 0, 0, 0 ],
## [ 0, 2, 4 ] ]
##
## the map is currently represented by the above 3 x 3 matrix
##
## [ [ 0, 1, 3 ],
## [ 0, 0, -2 ],
## [ 0, 1, 3 ] ]
##
## the map is currently represented by the above 3 x 3 matrix
##
## a set of 3 generators given by the the above matrices
## gap> GeneratorsOfModule( homNM );
## <A set of 4 generators of a homalg right module>
## gap> Display( last );
## [ [ 0, 1, 2 ],
## [ 0, 1, 2 ],
## [ 0, 1, 2 ],
## [ 0, 0, 0 ] ]
##
## the map is currently represented by the above 4 x 3 matrix
##
## [ [ 0, 1, 2 ],
## [ 0, 0, 0 ],
## [ 0, 0, 0 ],
## [ 0, 2, 4 ] ]
##
## the map is currently represented by the above 4 x 3 matrix
##
## [ [ 0, 0, -3 ],
## [ 0, 0, 7 ],
## [ 0, 0, -5 ],
## [ 0, 0, 1 ] ]
##
## the map is currently represented by the above 4 x 3 matrix
##
## [ [ 0, 1, -3 ],
## [ 0, 0, 12 ],
## [ 0, 0, -9 ],
## [ 0, 2, 6 ] ]
##
## the map is currently represented by the above 4 x 3 matrix
##
## a set of 4 generators given by the the above matrices
## ]]></Example>
## If for example the source <M>N</M> gets a new presentation, you will see the effect on the generators:
## <Example><![CDATA[
## gap> ByASmallerPresentation( N );
## <A rank 2 left module presented by 1 relation for 3 generators>
## gap> GeneratorsOfModule( homNM );
## <A set of 4 generators of a homalg right module>
## gap> Display( last );
## [ [ 0, 3, 6 ],
## [ 0, 1, 2 ],
## [ 0, 0, 0 ] ]
##
## the map is currently represented by the above 3 x 3 matrix
##
## [ [ 0, 9, 18 ],
## [ 0, 0, 0 ],
## [ 0, 2, 4 ] ]
##
## the map is currently represented by the above 3 x 3 matrix
##
## [ [ 0, 0, 0 ],
## [ 0, 0, -5 ],
## [ 0, 0, 1 ] ]
##
## the map is currently represented by the above 3 x 3 matrix
##
## [ [ 0, 9, 18 ],
## [ 0, 0, -9 ],
## [ 0, 2, 6 ] ]
##
## the map is currently represented by the above 3 x 3 matrix
##
## a set of 4 generators given by the the above matrices
## ]]></Example>
## Now we compute a certain natural filtration on <C>Hom</C><M>(M,M)</M>:
## <Example><![CDATA[
## gap> dM := Resolution( M );
## <A non-zero right acyclic complex containing a single morphism of left modules\
## at degrees [ 0 .. 1 ]>
## gap> hMM := Hom( dM, dM );
## <A non-zero acyclic cocomplex containing a single morphism of right complexes \
## at degrees [ 0 .. 1 ]>
## gap> BMM := HomalgBicomplex( hMM );
## <A non-zero bicocomplex containing right modules at bidegrees [ 0 .. 1 ]x
## [ -1 .. 0 ]>
## gap> II_E := SecondSpectralSequenceWithFiltration( BMM );
## <A stable cohomological spectral sequence with sheets at levels
## [ 0 .. 2 ] each consisting of right modules at bidegrees [ -1 .. 0 ]x
## [ 0 .. 1 ]>
## gap> Display( II_E );
## The associated transposed spectral sequence:
##
## a cohomological spectral sequence at bidegrees
## [ [ 0 .. 1 ], [ -1 .. 0 ] ]
## ---------
## Level 0:
##
## * *
## * *
## ---------
## Level 1:
##
## * *
## . .
## ---------
## Level 2:
##
## s s
## . .
##
## Now the spectral sequence of the bicomplex:
##
## a cohomological spectral sequence at bidegrees
## [ [ -1 .. 0 ], [ 0 .. 1 ] ]
## ---------
## Level 0:
##
## * *
## * *
## ---------
## Level 1:
##
## * *
## * *
## ---------
## Level 2:
##
## s s
## . s
## gap> filt := FiltrationBySpectralSequence( II_E );
## <A descending filtration with degrees [ -1 .. 0 ] and graded parts:
##
## -1: <A non-zero cyclic torsion right module on a cyclic generator satisfying
## yet unknown relations>
## 0: <A rank 1 right module on 3 generators satisfying 2 relations>
## of
## <A right module on 4 generators satisfying yet unknown relations>>
## gap> ByASmallerPresentation( filt );
## <A descending filtration with degrees [ -1 .. 0 ] and graded parts:
##
## -1: <A non-zero cyclic torsion right module on a cyclic generator satisfying 1\
## relation>
## 0: <A rank 1 right module on 2 generators satisfying 1 relation>
## of
## <A rank 1 right module on 3 generators satisfying 2 relations>>
## gap> Display( filt );
## Degree -1:
##
## Z/< 3 >
## ----------
## Degree 0:
##
## Z/< 3 > + Z^(1 x 1)
## gap> Display( homMM );
## Z/< 3 > + Z/< 3 > + Z^(1 x 1)
## ]]></Example>
## </Description>
## </ManSection>
## <#/GAPDoc>
##
InstallFunctor( Functor_Hom_for_fp_modules );
##
## TensorProduct( M, N ) ( M * N )
##
## <#GAPDoc Label="Functor_TensorProduct">
## <ManSection>
## <Var Name="Functor_TensorProduct"/>
## <Description>
## The tensor product bifunctor.
## <#Include Label="Functor_TensorProduct:code">
## </Description>
## </ManSection>
## <#/GAPDoc>
## <#GAPDoc Label="TensorProduct">
## <ManSection>
## <Oper Arg="o1,o2" Name="TensorProduct"/>
## <Oper Arg="o1,o2" Name="\*" Label="TensorProduct"/>
## <Description>
## <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.
## <P/>
## The symbol <C>*</C> is a shorthand for several operations associated with the functor <C>Functor_TensorProduct_for_fp_modules</C>
## installed under the name <C>TensorProduct</C>.
## <Example><![CDATA[
## gap> ZZ := HomalgRingOfIntegers( );
## Z
## gap> M := HomalgMatrix( "[ 2, 3, 4, 5, 6, 7 ]", 2, 3, ZZ );
## <A 2 x 3 matrix over an internal ring>
## gap> M := LeftPresentation( M );
## <A non-torsion left module presented by 2 relations for 3 generators>
## gap> N := HomalgMatrix( "[ 2, 3, 4, 5, 6, 7, 8, 9 ]", 2, 4, ZZ );
## <A 2 x 4 matrix over an internal ring>
## gap> N := LeftPresentation( N );
## <A non-torsion left module presented by 2 relations for 4 generators>
## gap> mat := HomalgMatrix( "[ \
## > 1, 0, -3, -6, \
## > 0, 1, 6, 11, \
## > 1, 0, -3, -6 \
## > ]", 3, 4, ZZ );
## <A 3 x 4 matrix over an internal ring>
## gap> phi := HomalgMap( mat, M, N );
## <A "homomorphism" of left modules>
## gap> IsMorphism( phi );
## true
## gap> phi;
## <A homomorphism of left modules>
## gap> L := Hom( ZZ, M );
## <A rank 1 right module on 3 generators satisfying yet unknown relations>
## gap> ByASmallerPresentation( L );
## <A rank 1 right module on 2 generators satisfying 1 relation>
## gap> Display( L );
## Z/< 3 > + Z^(1 x 1)
## gap> L;
## <A rank 1 right module on 2 generators satisfying 1 relation>
## gap> psi := phi * L;
## <A homomorphism of right modules>
## gap> ByASmallerPresentation( psi );
## <A non-zero homomorphism of right modules>
## gap> Display( psi );
## [ [ 0, 0, 1, 1 ],
## [ 0, 0, 8, 1 ],
## [ 0, 0, 0, -2 ],
## [ 0, 0, 0, 2 ] ]
##
## the map is currently represented by the above 4 x 4 matrix
## gap> ML := Source( psi );
## <A rank 1 right module on 4 generators satisfying 3 relations>
## gap> IsIdenticalObj( ML, M * L ); ## the caching at work
## true
## gap> NL := Range( psi );
## <A rank 2 right module on 4 generators satisfying 2 relations>
## gap> IsIdenticalObj( NL, N * L ); ## the caching at work
## true
## gap> Display( ML );
## Z/< 3 > + Z/< 3 > + Z/< 3 > + Z^(1 x 1)
## gap> Display( NL );
## Z/< 3 > + Z/< 12 > + Z^(2 x 1)
## ]]></Example>
## Now we compute a certain natural filtration on the tensor product <M>M</M><C>*</C><M>L</M>:
## <Example><![CDATA[
## gap> P := Resolution( M );
## <A non-zero right acyclic complex containing a single morphism of left modules\
## at degrees [ 0 .. 1 ]>
## gap> GP := Hom( P );
## <A non-zero acyclic cocomplex containing a single morphism of right modules at\
## degrees [ 0 .. 1 ]>
## gap> CE := Resolution( GP );
## <An acyclic cocomplex containing a single morphism of right complexes at degre\
## es [ 0 .. 1 ]>
## gap> FCE := Hom( CE, L );
## <A non-zero acyclic complex containing a single morphism of left cocomplexes a\
## t degrees [ 0 .. 1 ]>
## gap> BC := HomalgBicomplex( FCE );
## <A non-zero bicomplex containing left modules at bidegrees [ 0 .. 1 ]x
## [ -1 .. 0 ]>
## gap> II_E := SecondSpectralSequenceWithFiltration( BC );
## <A stable homological spectral sequence with sheets at levels
## [ 0 .. 2 ] each consisting of left modules at bidegrees [ -1 .. 0 ]x
## [ 0 .. 1 ]>
## gap> Display( II_E );
## The associated transposed spectral sequence:
##
## a homological spectral sequence at bidegrees
## [ [ 0 .. 1 ], [ -1 .. 0 ] ]
## ---------
## Level 0:
##
## * *
## * *
## ---------
## Level 1:
##
## * *
## . .
## ---------
## Level 2:
##
## s s
## . .
##
## Now the spectral sequence of the bicomplex:
##
## a homological spectral sequence at bidegrees
## [ [ -1 .. 0 ], [ 0 .. 1 ] ]
## ---------
## Level 0:
##
## * *
## * *
## ---------
## Level 1:
##
## * *
## . s
## ---------
## Level 2:
##
## s s
## . s
## gap> filt := FiltrationBySpectralSequence( II_E );
## <An ascending filtration with degrees [ -1 .. 0 ] and graded parts:
## 0: <A rank 1 left module presented by 1 relation for 2 generators>
## -1: <A non-zero left module presented by 2 relations for 2 generators>
## of
## <A non-zero left module presented by 10 relations for 6 generators>>
## gap> ByASmallerPresentation( filt );
## <An ascending filtration with degrees [ -1 .. 0 ] and graded parts:
## 0: <A rank 1 left module presented by 1 relation for 2 generators>
## -1: <A non-zero torsion left module presented by 2 relations
## for 2 generators>
## of
## <A rank 1 left module presented by 3 relations for 4 generators>>
## gap> Display( filt );
## Degree 0:
##
## Z/< 3 > + Z^(1 x 1)
## ----------
## Degree -1:
##
## Z/< 3 > + Z/< 3 >
## gap> Display( ML );
## Z/< 3 > + Z/< 3 > + Z/< 3 > + Z^(1 x 1)
## ]]></Example>
## </Description>
## </ManSection>
## <#/GAPDoc>
##
InstallFunctor( Functor_TensorProduct_for_fp_modules );
## for convenience
InstallOtherMethod( \*,
"for homalg modules",
[ IsStructureObjectOrObjectOrMorphism, IsFinitelyPresentedModuleRep ],
function( M, N )
return TensorProduct( M, N );
end );
## for convenience
InstallOtherMethod( \*,
"for homalg modules",
[ IsFinitelyPresentedModuleRep, IsStructureObjectOrObjectOrMorphism ],
function( M, N )
return TensorProduct( M, N );
end );
## for convenience
InstallOtherMethod( \*,
"for homalg modules",
[ IsHomalgComplex, IsHomalgComplex ],
function( M, N )
return TensorProduct( M, N );
end );
## <#GAPDoc Label="\*:ModuleBaseChange">
## <ManSection>
## <Oper Arg="R, M" Name="\*" Label="transfer a module over a different ring"/>
## <Oper Arg="M, R" Name="\*" Label="transfer a module over a different ring (right)"/>
## <Returns>a &homalg; module</Returns>
## <Description>
## Transfers the <M>S</M>-module <A>M</A> over the &homalg; ring <A>R</A>. This works only in three cases:
## <Enum>
## <Item><M>S</M> is a subring of <A>R</A>.</Item>
## <Item><A>R</A> is a residue class ring of <M>S</M> constructed using <C>/</C>.</Item>
## <Item><A>R</A> is a subring of <M>S</M> and the entries of the current matrix of <M>S</M>-relations of <A>M</A>
## lie in <A>R</A>.</Item>
## </Enum>
## CAUTION: So it is not suited for general base change.
## <Example><![CDATA[
## gap> ZZ := HomalgRingOfIntegers( );
## Z
## gap> Display( ZZ );
## <An internal ring>
## gap> Z4 := ZZ / 4;
## Z/( 4 )
## gap> Display( Z4 );
## <A residue class ring>
## gap> M := HomalgDiagonalMatrix( [ 2 .. 4 ], ZZ );
## <An unevaluated diagonal 3 x 3 matrix over an internal ring>
## gap> M := LeftPresentation( M );
## <A torsion left module presented by 3 relations for 3 generators>
## gap> Display( M );
## Z/< 2 > + Z/< 3 > + Z/< 4 >
## gap> M;
## <A torsion left module presented by 3 relations for 3 generators>
## gap> N := Z4 * M; ## or N := M * Z4;
## <A non-torsion left module presented by 2 relations for 3 generators>
## gap> ByASmallerPresentation( N );
## <A non-torsion left module presented by 1 relation for 2 generators>
## gap> Display( N );
## Z/( 4 )/< |[ 2 ]| > + Z/( 4 )^(1 x 1)
## gap> N;
## <A non-torsion left module presented by 1 relation for 2 generators>
## ]]></Example>
## <Example><![CDATA[
## gap> ZZ := HomalgRingOfIntegers( );
## Z
## gap> M := HomalgMatrix( "[ \
## > 2, 3, 4, \
## > 5, 6, 7 \
## > ]", 2, 3, ZZ );
## <A 2 x 3 matrix over an internal ring>
## gap> M := LeftPresentation( M );
## <A non-torsion left module presented by 2 relations for 3 generators>
## gap> Z4 := ZZ / 4;
## Z/( 4 )
## gap> Display( Z4 );
## <A residue class ring>
## gap> M4 := Z4 * M;
## <A non-torsion left module presented by 2 relations for 3 generators>
## gap> Display( M4 );
## [ [ 2, 3, 4 ],
## [ 5, 6, 7 ] ]
##
## modulo [ 4 ]
##
## Cokernel of the map
##
## Z/( 4 )^(1x2) --> Z/( 4 )^(1x3),
##
## currently represented by the above matrix
## gap> d := Resolution( 2, M4 );
## <A right acyclic complex containing 2 morphisms of left modules at degrees
## [ 0 .. 2 ]>
## gap> dd := Hom( d, Z4 );
## <A cocomplex containing 2 morphisms of right modules at degrees [ 0 .. 2 ]>
## gap> DD := Resolution( 2, dd );
## <A cocomplex containing 2 morphisms of right complexes at degrees [ 0 .. 2 ]>
## gap> D := Hom( DD, Z4 );
## <A complex containing 2 morphisms of left cocomplexes at degrees [ 0 .. 2 ]>
## gap> C := ZZ * D;
## <A "complex" containing 2 morphisms of left cocomplexes at degrees [ 0 .. 2 ]>
## gap> LowestDegreeObject( C );
## <A "cocomplex" containing 2 morphisms of left modules at degrees [ 0 .. 2 ]>
## gap> Display( last );
## -------------------------
## at cohomology degree: 2
## 0
## ------------^------------
## (an empty 1 x 0 matrix)
##
## the map is currently represented by the above 1 x 0 matrix
## -------------------------
## at cohomology degree: 1
## Z/< 4 >
## ------------^------------
## [ [ 0 ],
## [ 1 ],
## [ 2 ],
## [ 1 ] ]
##
## the map is currently represented by the above 4 x 1 matrix
## -------------------------
## at cohomology degree: 0
## Z/< 4 > + Z/< 4 > + Z/< 4 > + Z/< 4 >
## -------------------------
## ]]></Example>
## </Description>
## </ManSection>
## <#/GAPDoc>
##
InstallFunctor( functor_BaseChange_for_fp_modules );
##
## Ext( c, M, N )
##
## <#GAPDoc Label="Functor_Ext">
## <ManSection>
## <Var Name="Functor_Ext"/>
## <Description>
## The bifunctor <C>Ext</C>.
## <P/>
## <#Include Label="Functor_Ext:code">
## </Description>
## </ManSection>
## <#/GAPDoc>
## <#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="RightSatelliteOfCofunctor:example">
## <#Include Label="Functor_Ext:code">
## <#/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 );
## [ [ 2 ] ]
##
## 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>
##
##
## Tor( c, M, N )
##
## <#GAPDoc Label="Functor_Tor">
## <ManSection>
## <Var Name="Functor_Tor"/>
## <Description>
## The bifunctor <C>Tor</C>.
## <P/>
## <#Include Label="Functor_Tor:code">
## </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="LeftSatelliteOfFunctor:example">
## <#Include Label="Functor_Tor:code">
## <#/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>
##
##
## RHom( c, M, N )
##
## <#GAPDoc Label="Functor_RHom">
## <ManSection>
## <Var Name="Functor_RHom"/>
## <Description>
## The bifunctor <C>RHom</C>.
## <P/>
## <#Include Label="Functor_RHom:code">
## </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="RightDerivedCofunctor:example">
## <#Include Label="Functor_RHom:code">
## <#/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>
##
##
## LTensorProduct( c, M, N )
##
## <#GAPDoc Label="Functor_LTensorProduct">
## <ManSection>
## <Var Name="Functor_LTensorProduct"/>
## <Description>
## The bifunctor <C>LTensorProduct</C>.
## <P/>
## <#Include Label="Functor_LTensorProduct:code">
## </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="LeftDerivedFunctor:example">
## <#Include Label="Functor_LTensorProduct:code">
## <#/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">
## <ManSection>
## <Var Name="Functor_HomHom"/>
## <Description>
## The bifunctor <C>HomHom</C>.
## <P/>
## <#Include Label="Functor_HomHom:code">
## </Description>
## </ManSection>
## <#/GAPDoc>
## <#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="ComposeFunctors:example">
## <#Include Label="Functor_HomHom:code">
## <#/GAPDoc>
##
## LHomHom( M, K, N ) = L(Hom( Hom( -, K ), N ))( M )
##
## <#GAPDoc Label="Functor_LHomHom">
## <ManSection>
## <Var Name="Functor_LHomHom"/>
## <Description>
## The bifunctor <C>LHomHom</C>.
## <P/>
## <#Include Label="Functor_LHomHom:code">
## </Description>
## </ManSection>
## <#/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>
## <#GAPDoc Label="LeftDerivedFunctor:example2">
## <#Include Label="Functor_LHomHom:code">
## <#/GAPDoc>