|
# SPDX-License-Identifier: GPL-2.0-or-later
# homalg: A homological algebra meta-package for computable Abelian categories
#
# Implementations
#
## Implementations for basic functors.
####################################
#
# install global functions/variables:
#
####################################
##
## additive functors [HS. Prop. II.9.5] preserves chain complexes [HS. p. 118]
## half exact functors are additive [HS. p. 132 & Ex. IV.5.8]
## a right adjoint functor is left exact [W. Thm. 2.6.1]
## a left adjoint functor is right exact [W. Thm. 2.6.1]
##
##
## Cokernel
##
##
InstallMethod( CokernelNaturalGeneralizedIsomorphism,
"for homalg static morphisms",
[ IsStaticMorphismOfFinitelyGeneratedObjectsRep ],
function( phi )
local coker, emb;
coker := Cokernel( phi );
## sometimes an object is automatically assigned to a morphism as its Cokernel:
## this happens when M is resolved with F_0 --(d_0)--> M --> 0,
## then M is automatically assigned as the cokernel of d_0,
## and the component coker!.NaturalGeneralizedEmbedding is not set
if IsBound( coker!.NaturalGeneralizedEmbedding ) then
emb := NaturalGeneralizedEmbedding( coker );
fi;
## since the cokernel object can very well be predefined as the outcome of a different functor than Cokernel
## (for example Resolution (of objects and complexes) sets CokernelEpi automatically!):
if not ( IsBound( emb ) and IsIdenticalObj( Range( emb ), Source( phi ) ) ) then
emb := InverseOfGeneralizedMorphismWithFullDomain( CokernelEpi( phi ) );
fi;
return emb;
end );
##
## ImageObject
##
##
InstallMethod( ImageObjectEpi,
"for homalg static morphisms",
[ IsStaticMorphismOfFinitelyGeneratedObjectsRep ],
function( phi )
local emb, epi, ker_emb;
emb := ImageObjectEmb( phi );
epi := phi / emb; ## lift
## check assertion
Assert( 5, IsMorphism( epi ) );
SetIsMorphism( epi, true );
Assert( 5, IsEpimorphism( epi ) );
SetIsEpimorphism( epi, true );
## Abelian category: [HS, Prop. II.9.6]
if HasKernelEmb( phi ) then
ker_emb := KernelEmb( phi );
SetKernelEmb( epi, ker_emb );
if not HasCokernelEpi( ker_emb ) then
SetCokernelEpi( ker_emb, epi );
fi;
fi;
if HasIsMonomorphism( phi ) then
## check assertion
Assert( 5, IsIsomorphism( epi ) = IsMonomorphism( phi ) );
SetIsIsomorphism( epi, IsMonomorphism( phi ) );
fi;
return epi;
end );
##
## Kernel
##
##
InstallMethod( Kernel,
"LIMOR: for homalg morphisms",
[ IsHomalgStaticMorphism ], 10001,
function( psi )
if HasKernelEmb( psi ) then
return Source( KernelEmb( psi ) );
fi;
TryNextMethod( );
end );
##
BindGlobal( "_Functor_Kernel_OnObjects", ### defines: Kernel(Emb)
function( psi )
local S, ker_subobject, ker, emb, img_epi, T, coker, im;
S := Source( psi );
## in case of modules: this involves computing relative syzygies:
ker_subobject := KernelSubobject( psi );
## in case of f.p. modules: this involves a second syzygies computation:
## (the number of generators of ker might be less than the number of generators of ker_subobject)
ker := UnderlyingObject( ker_subobject );
## IsMonomorphism?
if HasIsZero( ker ) then
SetIsMonomorphism( psi, IsZero( ker ) );
fi;
## the natural embedding of ker in Source( psi ):
emb := EmbeddingInSuperObject( ker_subobject );
## set the attribute KernelEmb (specific for Kernel):
SetKernelEmb( psi, emb );
#=====# end of the core procedure #=====#
## Abelian category: [HS, Prop. II.9.6]
if HasImageObjectEpi( psi ) then
img_epi := ImageObjectEpi( psi );
SetCokernelEpi( emb, img_epi );
if not HasKernelEmb( img_epi ) then
SetKernelEmb( img_epi, emb );
fi;
elif HasIsEpimorphism( psi ) and IsEpimorphism( psi ) then
SetCokernelEpi( emb, psi );
fi;
## save the natural embedding in the kernel (thanks GAP):
ker!.NaturalGeneralizedEmbedding := emb;
## figure out an upper bound for the projective dimension of ker:
if not HasProjectiveDimension( ker ) and HasIsProjective( S ) and IsProjective( S ) then
T := Range( psi );
if HasIsProjective( T ) and IsProjective( T ) then ## typical for M^* which is a K_2(D(M)) (up to projective equivalence)
SetUpperBoundForProjectiveDimension( ker, -2 ); ## since ker = K_2( coker )
if HasCokernelEpi( psi ) then
coker := Range( CokernelEpi( psi ) ); ## S & T projective, then pd( ker ) = pd( coker ) - 2
if HasProjectiveDimension( coker ) then
SetProjectiveDimension( ker, Maximum( 0, ProjectiveDimension( coker ) - 2 ) );
elif IsBound( coker!.UpperBoundForProjectiveDimension ) then
SetUpperBoundForProjectiveDimension( ker, coker!.UpperBoundForProjectiveDimension - 2 );
fi;
elif HasImageObjectEmb( psi ) then
im := Source( ImageObjectEmb( psi ) ); ## S projective, then pd( ker ) = pd( im ) - 1
if HasProjectiveDimension( im ) then
SetProjectiveDimension( ker, Maximum( 0, ProjectiveDimension( im ) - 1 ) );
elif IsBound( im!.UpperBoundForProjectiveDimension ) then
SetUpperBoundForProjectiveDimension( ker, im!.UpperBoundForProjectiveDimension - 1 );
fi;
fi;
else
SetUpperBoundForProjectiveDimension( ker, -1 ); ## since ker = K_1( im )
if HasImageObjectEmb( psi ) then
im := Source( ImageObjectEmb( psi ) ); ## S projective, then pd( ker ) = pd( im ) - 1
if HasProjectiveDimension( im ) then
SetProjectiveDimension( ker, Maximum( 0, ProjectiveDimension( im ) - 1 ) );
elif IsBound( im!.UpperBoundForProjectiveDimension ) then
SetUpperBoundForProjectiveDimension( ker, im!.UpperBoundForProjectiveDimension - 1 );
fi;
fi;
fi;
fi;
return ker;
end );
## <#GAPDoc Label="functor_Kernel:code">
## <Listing Type="Code"><![CDATA[
BindGlobal( "functor_Kernel",
CreateHomalgFunctor(
[ "name", "Kernel" ],
[ "category", HOMALG.category ],
[ "operation", "Kernel" ],
[ "natural_transformation", "KernelEmb" ],
[ "special", true ],
[ "number_of_arguments", 1 ],
[ "1", [ [ "covariant" ],
[ IsStaticMorphismOfFinitelyGeneratedObjectsRep,
[ IsHomalgChainMorphism, IsKernelSquare ] ] ] ],
[ "OnObjects", _Functor_Kernel_OnObjects ]
)
);
## ]]></Listing>
## <#/GAPDoc>
functor_Kernel!.ContainerForWeakPointersOnComputedBasicMorphisms :=
ContainerForWeakPointers( TheTypeContainerForWeakPointersOnComputedValuesOfFunctor );
##
## DefectOfExactness
##
BindGlobal( "_Functor_DefectOfExactness_OnObjects", ### defines: DefectOfExactness (DefectOfHoms)
function( phi, psi )
local pre, post;
if IsHomalgLeftObjectOrMorphismOfLeftObjects( phi ) and IsHomalgLeftObjectOrMorphismOfLeftObjects( psi ) then
pre := phi;
post := psi;
if not AreComposableMorphisms( pre, post ) then
Error( "the two morphisms are not composable, ",
"since the target of the left one and ",
"the source of right one are not \033[01midentical\033[0m\n" );
fi;
elif IsHomalgRightObjectOrMorphismOfRightObjects( phi ) and IsHomalgRightObjectOrMorphismOfRightObjects( psi ) then
pre := psi;
post := phi;
if not AreComposableMorphisms( post, pre ) then
Error( "the two morphisms are not composable, ",
"since the source of the left one and ",
"the target of the right one are not \033[01midentical\033[0m\n" );
fi;
else
Error( "the two morphisms must either be both left or both right morphisms\n" );
fi;
return KernelSubobject( post ) / ImageSubobject( pre );
end );
## <#GAPDoc Label="Functor_DefectOfExactness:code">
## <Listing Type="Code"><![CDATA[
BindGlobal( "functor_DefectOfExactness",
CreateHomalgFunctor(
[ "name", "DefectOfExactness" ],
[ "category", HOMALG.category ],
[ "operation", "DefectOfExactness" ],
[ "special", true ],
[ "number_of_arguments", 2 ],
[ "1", [ [ "covariant" ],
[ IsStaticMorphismOfFinitelyGeneratedObjectsRep,
[ IsHomalgChainMorphism, IsLambekPairOfSquares ] ] ] ],
[ "2", [ [ "covariant" ],
[ IsStaticMorphismOfFinitelyGeneratedObjectsRep ] ] ],
[ "OnObjects", _Functor_DefectOfExactness_OnObjects ]
)
);
## ]]></Listing>
## <#/GAPDoc>
functor_DefectOfExactness!.ContainerForWeakPointersOnComputedBasicObjects :=
ContainerForWeakPointers( TheTypeContainerForWeakPointersOnComputedValuesOfFunctor );
functor_DefectOfExactness!.ContainerForWeakPointersOnComputedBasicMorphisms :=
ContainerForWeakPointers( TheTypeContainerForWeakPointersOnComputedValuesOfFunctor );
## for convenience
InstallMethod( DefectOfExactness,
"for homalg two-morphisms complexes",
[ IsHomalgComplex and IsATwoSequence ],
function( cpx_post_pre )
local pre, post;
pre := HighestDegreeMorphism( cpx_post_pre );
post := LowestDegreeMorphism( cpx_post_pre );
if IsHomalgLeftObjectOrMorphismOfLeftObjects( cpx_post_pre ) then
return DefectOfExactness( pre, post );
else
return DefectOfExactness( post, pre );
fi;
end );
##
InstallMethod( InternalHom,
"for two homalg objects or morphisms",
[ IsHomalgObjectOrMorphism, IsHomalgObjectOrMorphism ],
function( obj_or_mor_1, obj_or_mor_2 )
return CallOperationFromCategory( "InternalHom", [ obj_or_mor_1, obj_or_mor_2 ] );
end );
##
InstallMethod( InternalHom,
"for a homalg object or morphism",
[ IsHomalgObjectOrMorphism ],
function( obj_or_mor )
return CallOperationFromCategory( "InternalHom", [ obj_or_mor ] );
end );
##
InstallMethod( InternalExt,
"for an integer and two homalg objects or morphisms",
[ IsInt, IsHomalgObjectOrMorphism, IsHomalgObjectOrMorphism ],
function( c, obj_or_mor_1, obj_or_mor_2 )
return CallOperationFromCategory( "InternalExt", [ c, obj_or_mor_1, obj_or_mor_2 ] );
end );
##
InstallMethod( InternalExt,
"for two homalg objects or morphisms",
[ IsHomalgObjectOrMorphism, IsHomalgObjectOrMorphism ],
function( obj_or_mor_1, obj_or_mor_2 )
return CallOperationFromCategory( "InternalExt", [ obj_or_mor_1, obj_or_mor_2 ] );
end );
##
InstallMethod( InternalExt,
"for an integer and a homalg object or morphism",
[ IsInt, IsHomalgObjectOrMorphism ],
function( c, obj_or_mor )
return CallOperationFromCategory( "InternalExt", [ c, obj_or_mor ] );
end );
##
InstallMethod( InternalExt,
"for a homalg object or morphism",
[ IsHomalgObjectOrMorphism ],
function( obj_or_mor )
return CallOperationFromCategory( "InternalExt", [ obj_or_mor ] );
end );
## <#GAPDoc Label="Functor_Dualize:code">
## <Listing Type="Code"><![CDATA[
BindGlobal( "Functor_Dualize",
CreateHomalgFunctor(
[ "name", "Dualize" ],
[ "category", HOMALG.category ],
[ "operation", "Dualize" ],
[ "number_of_arguments", 1 ],
[ "1", [ [ "contravariant", "right adjoint", "distinguished" ] ] ]
)
);
## ]]></Listing>
## <#/GAPDoc>
##
## TensorProduct
##
## TensorProduct might have been defined elsewhere
if not IsBound( TensorProduct ) then
DeclareGlobalFunction( "TensorProduct" );
##
InstallGlobalFunction( TensorProduct,
function ( arg )
local d;
if Length( arg ) = 0 then
Error( "<arg> must be nonempty" );
elif Length( arg ) = 1 and IsList( arg[1] ) then
if IsEmpty( arg[1] ) then
Error( "<arg>[1] must be nonempty" );
fi;
arg := arg[1];
fi;
d := TensorProductOp( arg, arg[1] );
if ForAll( arg, HasSize ) then
if ForAll( arg, IsFinite ) then
SetSize( d, Product( List( arg, Size ) ) );
else
SetSize( d, infinity );
fi;
fi;
return d;
end );
fi;
####################################
#
# methods for operations & attributes:
#
####################################
##
## Kernel( phi ) and KernelEmb( phi )
##
## <#GAPDoc Label="functor_Kernel">
## <ManSection>
## <Var Name="functor_Kernel"/>
## <Description>
## The functor that associates to a map its kernel.
## <#Include Label="functor_Kernel:code">
## </Description>
## </ManSection>
## <#/GAPDoc>
##
InstallFunctor( functor_Kernel );
##
## DefectOfExactness( cpx_post_pre )
##
## <#GAPDoc Label="functor_DefectOfExactness">
## <ManSection>
## <Var Name="functor_DefectOfExactness"/>
## <Description>
## The functor that associates to a pair of composable maps with a zero compositum the defect of exactness,
## i.e. the kernel of the outer map modulo the image of the inner map.
## <#Include Label="Functor_DefectOfExactness:code">
## </Description>
## </ManSection>
## <#/GAPDoc>
##
InstallFunctor( functor_DefectOfExactness );
##
## Dualize( M )
##
##
InstallFunctor( Functor_Dualize );
##
## TensorProduct( M, N ) ( M * N )
##
if not IsOperation( TensorProduct ) then
## GAP 4.5 style
##
InstallMethod( TensorProductOp,
"for homalg objects",
[ IsList, IsStructureObjectOrObjectOrMorphism ],
function( L, M )
return Iterated( L, TensorProductOp );
end );
fi;
[ Dauer der Verarbeitung: 0.11 Sekunden
(vorverarbeitet)
]
|