Path: blob/master/src/sage/homology/chain_complex_morphism.py
8818 views
r"""1Morphisms of chain complexes23AUTHORS:45- Benjamin Antieau <[email protected]> (2009.06)67- Travis Scrimshaw (2012-08-18): Made all simplicial complexes immutable to8work with the homset cache.910This module implements morphisms of chain complexes. The input is a dictionary11whose keys are in the grading group of the chain complex and whose values are12matrix morphisms.1314EXAMPLES::1516from sage.matrix.constructor import zero_matrix17sage: S = simplicial_complexes.Sphere(1)18sage: S19Simplicial complex with vertex set (0, 1, 2) and facets {(1, 2), (0, 2), (0, 1)}20sage: C = S.chain_complex()21sage: C.differential()22{0: [], 1: [ 1 1 0]23[ 0 -1 -1]24[-1 0 1], 2: []}25sage: f = {0:zero_matrix(ZZ,3,3),1:zero_matrix(ZZ,3,3)}26sage: G = Hom(C,C)27sage: x = G(f)28sage: x29Chain complex morphism from Chain complex with at most 2 nonzero terms over Integer Ring to Chain complex with at most 2 nonzero terms over Integer Ring30sage: x._matrix_dictionary31{0: [0 0 0]32[0 0 0]33[0 0 0], 1: [0 0 0]34[0 0 0]35[0 0 0]}36"""3738#*****************************************************************************39# Copyright (C) 2009 D. Benjamin Antieau <[email protected]>40#41# Distributed under the terms of the GNU General Public License (GPL)42#43# This code is distributed in the hope that it will be useful,44# but WITHOUT ANY WARRANTY; without even the implied warranty45# of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.46#47# See the GNU General Public License for more details; the full text48# is available at:49#50# http://www.gnu.org/licenses/51#52#*****************************************************************************5354import sage.matrix.all as matrix55from sage.structure.sage_object import SageObject56from sage.rings.integer_ring import ZZ5758def is_ChainComplexMorphism(x):59"""60Returns ``True`` if and only if ``x`` is a chain complex morphism.6162EXAMPLES::6364sage: from sage.homology.chain_complex_morphism import is_ChainComplexMorphism65sage: S = simplicial_complexes.Sphere(14)66sage: H = Hom(S,S)67sage: i = H.identity() # long time (8s on sage.math, 2011)68sage: S = simplicial_complexes.Sphere(6)69sage: H = Hom(S,S)70sage: i = H.identity()71sage: x = i.associated_chain_complex_morphism()72sage: x # indirect doctest73Chain complex morphism from Chain complex with at most 7 nonzero terms over74Integer Ring to Chain complex with at most 7 nonzero terms over Integer Ring75sage: is_ChainComplexMorphism(x)76True77"""78return isinstance(x,ChainComplexMorphism)7980class ChainComplexMorphism(SageObject):81"""82An element of this class is a morphism of chain complexes.83"""84def __init__(self, matrices, C, D, check=True):85"""86Create a morphism from a dictionary of matrices.8788EXAMPLES::8990from sage.matrix.constructor import zero_matrix91sage: S = simplicial_complexes.Sphere(1)92sage: S93Simplicial complex with vertex set (0, 1, 2) and facets {(1, 2), (0, 2), (0, 1)}94sage: C = S.chain_complex()95sage: C.differential()96{0: [], 1: [ 1 1 0]97[ 0 -1 -1]98[-1 0 1], 2: []}99sage: f = {0:zero_matrix(ZZ,3,3),1:zero_matrix(ZZ,3,3)}100sage: G = Hom(C,C)101sage: x = G(f)102sage: x103Chain complex morphism from Chain complex with at most 2 nonzero terms104over Integer Ring to Chain complex with at most 2 nonzero terms over105Integer Ring106sage: x._matrix_dictionary107{0: [0 0 0]108[0 0 0]109[0 0 0], 1: [0 0 0]110[0 0 0]111[0 0 0]}112113Check that the bug in :trac:`13220` has been fixed::114115sage: X = simplicial_complexes.Simplex(1)116sage: Y = simplicial_complexes.Simplex(0)117sage: g = Hom(X,Y)({0:0, 1:0})118sage: g.associated_chain_complex_morphism()119Chain complex morphism from Chain complex with at most 2 nonzero120terms over Integer Ring to Chain complex with at most 1 nonzero terms121over Integer Ring122"""123if not C.base_ring() == D.base_ring():124raise NotImplementedError('morphisms between chain complexes of different'125' base rings are not implemented')126d = C.degree_of_differential()127if d != D.degree_of_differential():128raise ValueError('degree of differential does not match')129130from sage.misc.misc import uniq131degrees = uniq(C.differential().keys() + D.differential().keys())132initial_matrices = dict(matrices)133matrices = dict()134for i in degrees:135if i - d not in degrees:136if not (C.free_module_rank(i) == D.free_module_rank(i) == 0):137raise ValueError('{} and {} are not rank 0 in degree {}'.format(C, D, i))138continue139try:140matrices[i] = initial_matrices.pop(i)141except KeyError:142matrices[i] = matrix.zero_matrix(C.base_ring(),143D.differential(i).ncols(),144C.differential(i).ncols(), sparse=True)145if check:146# all remaining matrices given must be 0x0147if not all(m.ncols() == m.nrows() == 0 for m in initial_matrices.values()):148raise ValueError('the remaining matrices are not empty')149# check commutativity150for i in degrees:151if i - d not in degrees:152if not (C.free_module_rank(i) == D.free_module_rank(i) == 0):153raise ValueError('{} and {} are not rank 0 in degree {}'.format(C, D, i))154continue155if i + d not in degrees:156if not (C.free_module_rank(i+d) == D.free_module_rank(i+d) == 0):157raise ValueError('{} and {} are not rank 0 in degree {}'.format(C, D, i+d))158continue159Dm = D.differential(i) * matrices[i]160mC = matrices[i+d] * C.differential(i)161if mC != Dm:162raise ValueError('matrices must define a chain complex morphism')163self._matrix_dictionary = matrices164self._domain = C165self._codomain = D166167def __neg__(self):168"""169Returns ``-x``.170171EXAMPLES::172173sage: S = simplicial_complexes.Sphere(2)174sage: H = Hom(S,S)175sage: i = H.identity()176sage: x = i.associated_chain_complex_morphism()177sage: w = -x178sage: w._matrix_dictionary179{0: [-1 0 0 0]180[ 0 -1 0 0]181[ 0 0 -1 0]182[ 0 0 0 -1],1831: [-1 0 0 0 0 0]184[ 0 -1 0 0 0 0]185[ 0 0 -1 0 0 0]186[ 0 0 0 -1 0 0]187[ 0 0 0 0 -1 0]188[ 0 0 0 0 0 -1],1892: [-1 0 0 0]190[ 0 -1 0 0]191[ 0 0 -1 0]192[ 0 0 0 -1]}193194"""195f = dict()196for i in self._matrix_dictionary.keys():197f[i] = -self._matrix_dictionary[i]198return ChainComplexMorphism(f, self._domain, self._codomain)199200def __add__(self,x):201"""202Returns ``self + x``.203204EXAMPLES::205206sage: S = simplicial_complexes.Sphere(2)207sage: H = Hom(S,S)208sage: i = H.identity()209sage: x = i.associated_chain_complex_morphism()210sage: z = x+x211sage: z._matrix_dictionary212{0: [2 0 0 0]213[0 2 0 0]214[0 0 2 0]215[0 0 0 2],2161: [2 0 0 0 0 0]217[0 2 0 0 0 0]218[0 0 2 0 0 0]219[0 0 0 2 0 0]220[0 0 0 0 2 0]221[0 0 0 0 0 2],2222: [2 0 0 0]223[0 2 0 0]224[0 0 2 0]225[0 0 0 2]}226227"""228if not isinstance(x,ChainComplexMorphism) or self._codomain != x._codomain or self._domain != x._domain or self._matrix_dictionary.keys() != x._matrix_dictionary.keys():229raise TypeError("Unsupported operation.")230f = dict()231for i in self._matrix_dictionary.keys():232f[i] = self._matrix_dictionary[i] + x._matrix_dictionary[i]233return ChainComplexMorphism(f, self._domain, self._codomain)234235def __mul__(self,x):236"""237Return ``self * x`` if ``self`` and ``x`` are composable morphisms238or if ``x`` is an element of the base ring.239240EXAMPLES::241242sage: S = simplicial_complexes.Sphere(2)243sage: H = Hom(S,S)244sage: i = H.identity()245sage: x = i.associated_chain_complex_morphism()246sage: y = x*2247sage: y._matrix_dictionary248{0: [2 0 0 0]249[0 2 0 0]250[0 0 2 0]251[0 0 0 2],2521: [2 0 0 0 0 0]253[0 2 0 0 0 0]254[0 0 2 0 0 0]255[0 0 0 2 0 0]256[0 0 0 0 2 0]257[0 0 0 0 0 2],2582: [2 0 0 0]259[0 2 0 0]260[0 0 2 0]261[0 0 0 2]}262sage: z = y*y263sage: z._matrix_dictionary264{0: [4 0 0 0]265[0 4 0 0]266[0 0 4 0]267[0 0 0 4],2681: [4 0 0 0 0 0]269[0 4 0 0 0 0]270[0 0 4 0 0 0]271[0 0 0 4 0 0]272[0 0 0 0 4 0]273[0 0 0 0 0 4],2742: [4 0 0 0]275[0 4 0 0]276[0 0 4 0]277[0 0 0 4]}278279"""280if not isinstance(x,ChainComplexMorphism) or self._codomain != x._domain:281try:282y = self._domain.base_ring()(x)283except TypeError:284raise TypeError("multiplication is not defined")285f = dict()286for i in self._matrix_dictionary.keys():287f[i] = self._matrix_dictionary[i] * y288return ChainComplexMorphism(f,self._domain,self._codomain)289f = dict()290for i in self._matrix_dictionary.keys():291f[i] = x._matrix_dictionary[i]*self._matrix_dictionary[i]292return ChainComplexMorphism(f,self._domain,x._codomain)293294def __rmul__(self,x):295"""296Returns ``x * self`` if ``x`` is an element of the base ring.297298EXAMPLES::299300sage: S = simplicial_complexes.Sphere(2)301sage: H = Hom(S,S)302sage: i = H.identity()303sage: x = i.associated_chain_complex_morphism()304sage: 2*x == x*2305True306sage: 3*x == x*2307False308"""309try:310y = self._domain.base_ring()(x)311except TypeError:312raise TypeError("multiplication is not defined")313f = dict()314for i in self._matrix_dictionary.keys():315f[i] = y * self._matrix_dictionary[i]316return ChainComplexMorphism(f,self._domain,self._codomain)317318def __sub__(self,x):319"""320Return ``self - x``.321322EXAMPLES::323324sage: S = simplicial_complexes.Sphere(2)325sage: H = Hom(S,S)326sage: i = H.identity()327sage: x = i.associated_chain_complex_morphism()328sage: y = x-x329sage: y._matrix_dictionary330{0: [0 0 0 0]331[0 0 0 0]332[0 0 0 0]333[0 0 0 0],3341: [0 0 0 0 0 0]335[0 0 0 0 0 0]336[0 0 0 0 0 0]337[0 0 0 0 0 0]338[0 0 0 0 0 0]339[0 0 0 0 0 0],3402: [0 0 0 0]341[0 0 0 0]342[0 0 0 0]343[0 0 0 0]}344345"""346return self + (-x)347348def __eq__(self,x):349"""350Return ``True`` if and only if ``self == x``.351352EXAMPLES::353354sage: S = SimplicialComplex(is_mutable=False)355sage: H = Hom(S,S)356sage: i = H.identity()357sage: x = i.associated_chain_complex_morphism()358sage: x359Chain complex morphism from Trivial chain complex over Integer Ring360to Trivial chain complex over Integer Ring361sage: f = x._matrix_dictionary362sage: C = S.chain_complex()363sage: G = Hom(C,C)364sage: y = G(f)365sage: x == y366True367"""368return isinstance(x,ChainComplexMorphism) \369and self._codomain == x._codomain \370and self._domain == x._domain \371and self._matrix_dictionary == x._matrix_dictionary372373def _repr_(self):374"""375Return the string representation of ``self``.376377EXAMPLES::378379sage: S = SimplicialComplex(is_mutable=False)380sage: H = Hom(S,S)381sage: i = H.identity()382sage: x = i.associated_chain_complex_morphism()383sage: x384Chain complex morphism from Trivial chain complex over Integer Ring385to Trivial chain complex over Integer Ring386sage: x._repr_()387'Chain complex morphism from Trivial chain complex over Integer Ring388to Trivial chain complex over Integer Ring'389"""390return "Chain complex morphism from {} to {}".format(self._domain, self._codomain)391392393394