Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemath
GitHub Repository: sagemath/sagesmc
Path: blob/master/src/sage/homology/chain_complex_morphism.py
8818 views
1
r"""
2
Morphisms of chain complexes
3
4
AUTHORS:
5
6
- Benjamin Antieau <[email protected]> (2009.06)
7
8
- Travis Scrimshaw (2012-08-18): Made all simplicial complexes immutable to
9
work with the homset cache.
10
11
This module implements morphisms of chain complexes. The input is a dictionary
12
whose keys are in the grading group of the chain complex and whose values are
13
matrix morphisms.
14
15
EXAMPLES::
16
17
from sage.matrix.constructor import zero_matrix
18
sage: S = simplicial_complexes.Sphere(1)
19
sage: S
20
Simplicial complex with vertex set (0, 1, 2) and facets {(1, 2), (0, 2), (0, 1)}
21
sage: C = S.chain_complex()
22
sage: C.differential()
23
{0: [], 1: [ 1 1 0]
24
[ 0 -1 -1]
25
[-1 0 1], 2: []}
26
sage: f = {0:zero_matrix(ZZ,3,3),1:zero_matrix(ZZ,3,3)}
27
sage: G = Hom(C,C)
28
sage: x = G(f)
29
sage: x
30
Chain 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 Ring
31
sage: x._matrix_dictionary
32
{0: [0 0 0]
33
[0 0 0]
34
[0 0 0], 1: [0 0 0]
35
[0 0 0]
36
[0 0 0]}
37
"""
38
39
#*****************************************************************************
40
# Copyright (C) 2009 D. Benjamin Antieau <[email protected]>
41
#
42
# Distributed under the terms of the GNU General Public License (GPL)
43
#
44
# This code is distributed in the hope that it will be useful,
45
# but WITHOUT ANY WARRANTY; without even the implied warranty
46
# of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
47
#
48
# See the GNU General Public License for more details; the full text
49
# is available at:
50
#
51
# http://www.gnu.org/licenses/
52
#
53
#*****************************************************************************
54
55
import sage.matrix.all as matrix
56
from sage.structure.sage_object import SageObject
57
from sage.rings.integer_ring import ZZ
58
59
def is_ChainComplexMorphism(x):
60
"""
61
Returns ``True`` if and only if ``x`` is a chain complex morphism.
62
63
EXAMPLES::
64
65
sage: from sage.homology.chain_complex_morphism import is_ChainComplexMorphism
66
sage: S = simplicial_complexes.Sphere(14)
67
sage: H = Hom(S,S)
68
sage: i = H.identity() # long time (8s on sage.math, 2011)
69
sage: S = simplicial_complexes.Sphere(6)
70
sage: H = Hom(S,S)
71
sage: i = H.identity()
72
sage: x = i.associated_chain_complex_morphism()
73
sage: x # indirect doctest
74
Chain complex morphism from Chain complex with at most 7 nonzero terms over
75
Integer Ring to Chain complex with at most 7 nonzero terms over Integer Ring
76
sage: is_ChainComplexMorphism(x)
77
True
78
"""
79
return isinstance(x,ChainComplexMorphism)
80
81
class ChainComplexMorphism(SageObject):
82
"""
83
An element of this class is a morphism of chain complexes.
84
"""
85
def __init__(self, matrices, C, D, check=True):
86
"""
87
Create a morphism from a dictionary of matrices.
88
89
EXAMPLES::
90
91
from sage.matrix.constructor import zero_matrix
92
sage: S = simplicial_complexes.Sphere(1)
93
sage: S
94
Simplicial complex with vertex set (0, 1, 2) and facets {(1, 2), (0, 2), (0, 1)}
95
sage: C = S.chain_complex()
96
sage: C.differential()
97
{0: [], 1: [ 1 1 0]
98
[ 0 -1 -1]
99
[-1 0 1], 2: []}
100
sage: f = {0:zero_matrix(ZZ,3,3),1:zero_matrix(ZZ,3,3)}
101
sage: G = Hom(C,C)
102
sage: x = G(f)
103
sage: x
104
Chain complex morphism from Chain complex with at most 2 nonzero terms
105
over Integer Ring to Chain complex with at most 2 nonzero terms over
106
Integer Ring
107
sage: x._matrix_dictionary
108
{0: [0 0 0]
109
[0 0 0]
110
[0 0 0], 1: [0 0 0]
111
[0 0 0]
112
[0 0 0]}
113
114
Check that the bug in :trac:`13220` has been fixed::
115
116
sage: X = simplicial_complexes.Simplex(1)
117
sage: Y = simplicial_complexes.Simplex(0)
118
sage: g = Hom(X,Y)({0:0, 1:0})
119
sage: g.associated_chain_complex_morphism()
120
Chain complex morphism from Chain complex with at most 2 nonzero
121
terms over Integer Ring to Chain complex with at most 1 nonzero terms
122
over Integer Ring
123
"""
124
if not C.base_ring() == D.base_ring():
125
raise NotImplementedError('morphisms between chain complexes of different'
126
' base rings are not implemented')
127
d = C.degree_of_differential()
128
if d != D.degree_of_differential():
129
raise ValueError('degree of differential does not match')
130
131
from sage.misc.misc import uniq
132
degrees = uniq(C.differential().keys() + D.differential().keys())
133
initial_matrices = dict(matrices)
134
matrices = dict()
135
for i in degrees:
136
if i - d not in degrees:
137
if not (C.free_module_rank(i) == D.free_module_rank(i) == 0):
138
raise ValueError('{} and {} are not rank 0 in degree {}'.format(C, D, i))
139
continue
140
try:
141
matrices[i] = initial_matrices.pop(i)
142
except KeyError:
143
matrices[i] = matrix.zero_matrix(C.base_ring(),
144
D.differential(i).ncols(),
145
C.differential(i).ncols(), sparse=True)
146
if check:
147
# all remaining matrices given must be 0x0
148
if not all(m.ncols() == m.nrows() == 0 for m in initial_matrices.values()):
149
raise ValueError('the remaining matrices are not empty')
150
# check commutativity
151
for i in degrees:
152
if i - d not in degrees:
153
if not (C.free_module_rank(i) == D.free_module_rank(i) == 0):
154
raise ValueError('{} and {} are not rank 0 in degree {}'.format(C, D, i))
155
continue
156
if i + d not in degrees:
157
if not (C.free_module_rank(i+d) == D.free_module_rank(i+d) == 0):
158
raise ValueError('{} and {} are not rank 0 in degree {}'.format(C, D, i+d))
159
continue
160
Dm = D.differential(i) * matrices[i]
161
mC = matrices[i+d] * C.differential(i)
162
if mC != Dm:
163
raise ValueError('matrices must define a chain complex morphism')
164
self._matrix_dictionary = matrices
165
self._domain = C
166
self._codomain = D
167
168
def __neg__(self):
169
"""
170
Returns ``-x``.
171
172
EXAMPLES::
173
174
sage: S = simplicial_complexes.Sphere(2)
175
sage: H = Hom(S,S)
176
sage: i = H.identity()
177
sage: x = i.associated_chain_complex_morphism()
178
sage: w = -x
179
sage: w._matrix_dictionary
180
{0: [-1 0 0 0]
181
[ 0 -1 0 0]
182
[ 0 0 -1 0]
183
[ 0 0 0 -1],
184
1: [-1 0 0 0 0 0]
185
[ 0 -1 0 0 0 0]
186
[ 0 0 -1 0 0 0]
187
[ 0 0 0 -1 0 0]
188
[ 0 0 0 0 -1 0]
189
[ 0 0 0 0 0 -1],
190
2: [-1 0 0 0]
191
[ 0 -1 0 0]
192
[ 0 0 -1 0]
193
[ 0 0 0 -1]}
194
195
"""
196
f = dict()
197
for i in self._matrix_dictionary.keys():
198
f[i] = -self._matrix_dictionary[i]
199
return ChainComplexMorphism(f, self._domain, self._codomain)
200
201
def __add__(self,x):
202
"""
203
Returns ``self + x``.
204
205
EXAMPLES::
206
207
sage: S = simplicial_complexes.Sphere(2)
208
sage: H = Hom(S,S)
209
sage: i = H.identity()
210
sage: x = i.associated_chain_complex_morphism()
211
sage: z = x+x
212
sage: z._matrix_dictionary
213
{0: [2 0 0 0]
214
[0 2 0 0]
215
[0 0 2 0]
216
[0 0 0 2],
217
1: [2 0 0 0 0 0]
218
[0 2 0 0 0 0]
219
[0 0 2 0 0 0]
220
[0 0 0 2 0 0]
221
[0 0 0 0 2 0]
222
[0 0 0 0 0 2],
223
2: [2 0 0 0]
224
[0 2 0 0]
225
[0 0 2 0]
226
[0 0 0 2]}
227
228
"""
229
if not isinstance(x,ChainComplexMorphism) or self._codomain != x._codomain or self._domain != x._domain or self._matrix_dictionary.keys() != x._matrix_dictionary.keys():
230
raise TypeError("Unsupported operation.")
231
f = dict()
232
for i in self._matrix_dictionary.keys():
233
f[i] = self._matrix_dictionary[i] + x._matrix_dictionary[i]
234
return ChainComplexMorphism(f, self._domain, self._codomain)
235
236
def __mul__(self,x):
237
"""
238
Return ``self * x`` if ``self`` and ``x`` are composable morphisms
239
or if ``x`` is an element of the base ring.
240
241
EXAMPLES::
242
243
sage: S = simplicial_complexes.Sphere(2)
244
sage: H = Hom(S,S)
245
sage: i = H.identity()
246
sage: x = i.associated_chain_complex_morphism()
247
sage: y = x*2
248
sage: y._matrix_dictionary
249
{0: [2 0 0 0]
250
[0 2 0 0]
251
[0 0 2 0]
252
[0 0 0 2],
253
1: [2 0 0 0 0 0]
254
[0 2 0 0 0 0]
255
[0 0 2 0 0 0]
256
[0 0 0 2 0 0]
257
[0 0 0 0 2 0]
258
[0 0 0 0 0 2],
259
2: [2 0 0 0]
260
[0 2 0 0]
261
[0 0 2 0]
262
[0 0 0 2]}
263
sage: z = y*y
264
sage: z._matrix_dictionary
265
{0: [4 0 0 0]
266
[0 4 0 0]
267
[0 0 4 0]
268
[0 0 0 4],
269
1: [4 0 0 0 0 0]
270
[0 4 0 0 0 0]
271
[0 0 4 0 0 0]
272
[0 0 0 4 0 0]
273
[0 0 0 0 4 0]
274
[0 0 0 0 0 4],
275
2: [4 0 0 0]
276
[0 4 0 0]
277
[0 0 4 0]
278
[0 0 0 4]}
279
280
"""
281
if not isinstance(x,ChainComplexMorphism) or self._codomain != x._domain:
282
try:
283
y = self._domain.base_ring()(x)
284
except TypeError:
285
raise TypeError("multiplication is not defined")
286
f = dict()
287
for i in self._matrix_dictionary.keys():
288
f[i] = self._matrix_dictionary[i] * y
289
return ChainComplexMorphism(f,self._domain,self._codomain)
290
f = dict()
291
for i in self._matrix_dictionary.keys():
292
f[i] = x._matrix_dictionary[i]*self._matrix_dictionary[i]
293
return ChainComplexMorphism(f,self._domain,x._codomain)
294
295
def __rmul__(self,x):
296
"""
297
Returns ``x * self`` if ``x`` is an element of the base ring.
298
299
EXAMPLES::
300
301
sage: S = simplicial_complexes.Sphere(2)
302
sage: H = Hom(S,S)
303
sage: i = H.identity()
304
sage: x = i.associated_chain_complex_morphism()
305
sage: 2*x == x*2
306
True
307
sage: 3*x == x*2
308
False
309
"""
310
try:
311
y = self._domain.base_ring()(x)
312
except TypeError:
313
raise TypeError("multiplication is not defined")
314
f = dict()
315
for i in self._matrix_dictionary.keys():
316
f[i] = y * self._matrix_dictionary[i]
317
return ChainComplexMorphism(f,self._domain,self._codomain)
318
319
def __sub__(self,x):
320
"""
321
Return ``self - x``.
322
323
EXAMPLES::
324
325
sage: S = simplicial_complexes.Sphere(2)
326
sage: H = Hom(S,S)
327
sage: i = H.identity()
328
sage: x = i.associated_chain_complex_morphism()
329
sage: y = x-x
330
sage: y._matrix_dictionary
331
{0: [0 0 0 0]
332
[0 0 0 0]
333
[0 0 0 0]
334
[0 0 0 0],
335
1: [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]
340
[0 0 0 0 0 0],
341
2: [0 0 0 0]
342
[0 0 0 0]
343
[0 0 0 0]
344
[0 0 0 0]}
345
346
"""
347
return self + (-x)
348
349
def __eq__(self,x):
350
"""
351
Return ``True`` if and only if ``self == x``.
352
353
EXAMPLES::
354
355
sage: S = SimplicialComplex(is_mutable=False)
356
sage: H = Hom(S,S)
357
sage: i = H.identity()
358
sage: x = i.associated_chain_complex_morphism()
359
sage: x
360
Chain complex morphism from Trivial chain complex over Integer Ring
361
to Trivial chain complex over Integer Ring
362
sage: f = x._matrix_dictionary
363
sage: C = S.chain_complex()
364
sage: G = Hom(C,C)
365
sage: y = G(f)
366
sage: x == y
367
True
368
"""
369
return isinstance(x,ChainComplexMorphism) \
370
and self._codomain == x._codomain \
371
and self._domain == x._domain \
372
and self._matrix_dictionary == x._matrix_dictionary
373
374
def _repr_(self):
375
"""
376
Return the string representation of ``self``.
377
378
EXAMPLES::
379
380
sage: S = SimplicialComplex(is_mutable=False)
381
sage: H = Hom(S,S)
382
sage: i = H.identity()
383
sage: x = i.associated_chain_complex_morphism()
384
sage: x
385
Chain complex morphism from Trivial chain complex over Integer Ring
386
to Trivial chain complex over Integer Ring
387
sage: x._repr_()
388
'Chain complex morphism from Trivial chain complex over Integer Ring
389
to Trivial chain complex over Integer Ring'
390
"""
391
return "Chain complex morphism from {} to {}".format(self._domain, self._codomain)
392
393
394