Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemath
GitHub Repository: sagemath/sagesmc
Path: blob/master/src/sage/homology/simplicial_complex_morphism.py
8818 views
1
r"""
2
Morphisms of simplicial 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 simplicial complexes. The input is given
12
by a dictionary on the vertex set of a simplicial complex. The initialization
13
checks that faces are sent to faces.
14
15
There is also the capability to create the fiber product of two morphisms with
16
the same codomain.
17
18
EXAMPLES::
19
20
sage: S = SimplicialComplex([[0,2],[1,5],[3,4]], is_mutable=False)
21
sage: H = Hom(S,S.product(S, is_mutable=False))
22
sage: H.diagonal_morphism()
23
Simplicial complex morphism {0: 'L0R0', 1: 'L1R1', 2: 'L2R2', 3: 'L3R3', 4: 'L4R4', 5: 'L5R5'} from Simplicial complex with vertex set (0, 1, 2, 3, 4, 5) and facets {(3, 4), (1, 5), (0, 2)} to Simplicial complex with 36 vertices and 18 facets
24
25
sage: S = SimplicialComplex([[0,2],[1,5],[3,4]], is_mutable=False)
26
sage: T = SimplicialComplex([[0,2],[1,3]], is_mutable=False)
27
sage: f = {0:0,1:1,2:2,3:1,4:3,5:3}
28
sage: H = Hom(S,T)
29
sage: x = H(f)
30
sage: x.image()
31
Simplicial complex with vertex set (0, 1, 2, 3) and facets {(1, 3), (0, 2)}
32
sage: x.is_surjective()
33
True
34
sage: x.is_injective()
35
False
36
sage: x.is_identity()
37
False
38
39
sage: S = simplicial_complexes.Sphere(2)
40
sage: H = Hom(S,S)
41
sage: i = H.identity()
42
sage: i.image()
43
Simplicial complex with vertex set (0, 1, 2, 3) and facets {(0, 2, 3), (0, 1, 2), (1, 2, 3), (0, 1, 3)}
44
sage: i.is_surjective()
45
True
46
sage: i.is_injective()
47
True
48
sage: i.is_identity()
49
True
50
51
sage: S = simplicial_complexes.Sphere(2)
52
sage: H = Hom(S,S)
53
sage: i = H.identity()
54
sage: j = i.fiber_product(i)
55
sage: j
56
Simplicial complex morphism {'L1R1': 1, 'L3R3': 3, 'L2R2': 2, 'L0R0': 0} from Simplicial complex with 4 vertices and 4 facets to Simplicial complex with vertex set (0, 1, 2, 3) and facets {(0, 2, 3), (0, 1, 2), (1, 2, 3), (0, 1, 3)}
57
58
sage: S = simplicial_complexes.Sphere(2)
59
sage: T = S.product(SimplicialComplex([[0,1]]), rename_vertices = False, is_mutable=False)
60
sage: H = Hom(T,S)
61
sage: T
62
Simplicial complex with 8 vertices and 12 facets
63
sage: T.vertices()
64
((0, 0), (0, 1), (1, 0), (1, 1), (2, 0), (2, 1), (3, 0), (3, 1))
65
sage: f = {(0, 0): 0, (0, 1): 0, (1, 0): 1, (1, 1): 1, (2, 0): 2, (2, 1): 2, (3, 0): 3, (3, 1): 3}
66
sage: x = H(f)
67
sage: U = simplicial_complexes.Sphere(1)
68
sage: G = Hom(U,S)
69
sage: U
70
Simplicial complex with vertex set (0, 1, 2) and facets {(1, 2), (0, 2), (0, 1)}
71
sage: g = {0:0,1:1,2:2}
72
sage: y = G(g)
73
sage: z = y.fiber_product(x)
74
sage: z # this is the mapping path space
75
Simplicial complex morphism {'L2R(2, 0)': 2, 'L2R(2, 1)': 2, 'L0R(0, 0)': 0, 'L0R(0, 1)': 0, 'L1R(1, 0)': 1, 'L1R(1, 1)': 1} from Simplicial complex with 6 vertices and 6 facets to Simplicial complex with vertex set (0, 1, 2, 3) and facets {(0, 2, 3), (0, 1, 2), (1, 2, 3), (0, 1, 3)}
76
"""
77
78
#*****************************************************************************
79
# Copyright (C) 2009 D. Benjamin Antieau <[email protected]>
80
#
81
# Distributed under the terms of the GNU General Public License (GPL)
82
#
83
# This code is distributed in the hope that it will be useful,
84
# but WITHOUT ANY WARRANTY; without even the implied warranty
85
# of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
86
#
87
# See the GNU General Public License for more details; the full text
88
# is available at:
89
#
90
# http://www.gnu.org/licenses/
91
#
92
#*****************************************************************************
93
94
import sage.homology.simplicial_complex as simplicial_complex
95
import sage.matrix.all as matrix
96
from sage.structure.sage_object import SageObject
97
from sage.rings.integer_ring import ZZ
98
from sage.homology.chain_complex_morphism import ChainComplexMorphism
99
from sage.combinat.permutation import Permutation
100
from sage.algebras.steenrod.steenrod_algebra_misc import convert_perm
101
102
def is_SimplicialComplexMorphism(x):
103
"""
104
Returns ``True`` if and only if ``x`` is a morphism of simplicial complexes.
105
106
EXAMPLES::
107
108
sage: from sage.homology.simplicial_complex_morphism import is_SimplicialComplexMorphism
109
sage: S = SimplicialComplex([[0,1],[3,4]], is_mutable=False)
110
sage: H = Hom(S,S)
111
sage: f = {0:0,1:1,3:3,4:4}
112
sage: x = H(f)
113
sage: is_SimplicialComplexMorphism(x)
114
True
115
116
"""
117
return isinstance(x,SimplicialComplexMorphism)
118
119
class SimplicialComplexMorphism(SageObject):
120
"""
121
An element of this class is a morphism of simplicial complexes.
122
"""
123
def __init__(self,f,X,Y):
124
"""
125
Input is a dictionary ``f``, the domain ``X``, and the codomain ``Y``.
126
127
One can define the dictionary on the vertices of `X`.
128
129
EXAMPLES::
130
131
sage: S = SimplicialComplex([[0,1],[2],[3,4],[5]], is_mutable=False)
132
sage: H = Hom(S,S)
133
sage: f = {0:0,1:1,2:2,3:3,4:4,5:5}
134
sage: g = {0:0,1:1,2:0,3:3,4:4,5:0}
135
sage: x = H(f)
136
sage: y = H(g)
137
sage: x == y
138
False
139
sage: x.image()
140
Simplicial complex with vertex set (0, 1, 2, 3, 4, 5) and facets {(3, 4), (5,), (2,), (0, 1)}
141
sage: y.image()
142
Simplicial complex with vertex set (0, 1, 3, 4) and facets {(3, 4), (0, 1)}
143
sage: x.image() == y.image()
144
False
145
"""
146
if not isinstance(X,simplicial_complex.SimplicialComplex) or not isinstance(Y,simplicial_complex.SimplicialComplex):
147
raise ValueError("X and Y must be SimplicialComplexes.")
148
if not set(f.keys()) == X._vertex_set.set():
149
raise ValueError("f must be a dictionary from the vertex set of X to single values in the vertex set of Y.")
150
dim = X.dimension()
151
Y_faces = Y.faces()
152
for k in range(dim+1):
153
for i in X.faces()[k]:
154
tup = i.tuple()
155
fi = []
156
for j in tup:
157
fi.append(f[j])
158
v = simplicial_complex.Simplex(set(fi))
159
if not v in Y_faces[v.dimension()]:
160
raise ValueError("f must be a dictionary from the vertices of X to the vertices of Y.")
161
self._vertex_dictionary = f
162
self._domain = X
163
self._codomain = Y
164
165
def __eq__(self,x):
166
"""
167
Returns ``True`` if and only if ``self == x``.
168
169
EXAMPLES::
170
171
sage: S = simplicial_complexes.Sphere(2)
172
sage: H = Hom(S,S)
173
sage: i = H.identity()
174
sage: i
175
Simplicial complex morphism {0: 0, 1: 1, 2: 2, 3: 3} from Simplicial complex with vertex set (0, 1, 2, 3) and facets {(0, 2, 3), (0, 1, 2), (1, 2, 3), (0, 1, 3)} to Simplicial complex with vertex set (0, 1, 2, 3) and facets {(0, 2, 3), (0, 1, 2), (1, 2, 3), (0, 1, 3)}
176
sage: f = {0:0,1:1,2:2,3:2}
177
sage: j = H(f)
178
sage: i==j
179
False
180
181
sage: T = SimplicialComplex([[1,2]], is_mutable=False)
182
sage: T
183
Simplicial complex with vertex set (1, 2) and facets {(1, 2)}
184
sage: G = Hom(T,T)
185
sage: k = G.identity()
186
sage: g = {1:1,2:2}
187
sage: l = G(g)
188
sage: k == l
189
True
190
191
"""
192
if not isinstance(x,SimplicialComplexMorphism) or self._codomain != x._codomain or self._domain != x._domain or self._vertex_dictionary != x._vertex_dictionary:
193
return False
194
else:
195
return True
196
197
def __call__(self,x,orientation=False):
198
"""
199
Input is a simplex of the domain. Output is the image simplex.
200
201
If the optional argument ``orientation`` is ``True``, then this
202
returns a pair ``(image simplex, oriented)`` where ``oriented``
203
is 1 or `-1` depending on whether the map preserves or reverses
204
the orientation of the image simplex.
205
206
EXAMPLES::
207
208
sage: S = simplicial_complexes.Sphere(2)
209
sage: T = simplicial_complexes.Sphere(3)
210
sage: S
211
Simplicial complex with vertex set (0, 1, 2, 3) and facets {(0, 2, 3), (0, 1, 2), (1, 2, 3), (0, 1, 3)}
212
sage: T
213
Simplicial complex with vertex set (0, 1, 2, 3, 4) and 5 facets
214
sage: f = {0:0,1:1,2:2,3:3}
215
sage: H = Hom(S,T)
216
sage: x = H(f)
217
sage: from sage.homology.simplicial_complex import Simplex
218
sage: x(Simplex([0,2,3]))
219
(0, 2, 3)
220
221
An orientation-reversing example::
222
223
sage: X = SimplicialComplex([[0,1]], is_mutable=False)
224
sage: g = Hom(X,X)({0:1, 1:0})
225
sage: g(Simplex([0,1]))
226
(0, 1)
227
sage: g(Simplex([0,1]), orientation=True)
228
((0, 1), -1)
229
"""
230
dim = self._domain.dimension()
231
if not isinstance(x,simplicial_complex.Simplex) or x.dimension() > dim or not x in self._domain.faces()[x.dimension()]:
232
raise ValueError, "x must be a simplex of the source of f"
233
tup=x.tuple()
234
fx=[]
235
for j in tup:
236
fx.append(self._vertex_dictionary[j])
237
if orientation:
238
if len(set(fx)) == len(tup):
239
oriented = Permutation(convert_perm(fx)).signature()
240
else:
241
oriented = 1
242
return (simplicial_complex.Simplex(set(fx)), oriented)
243
else:
244
return simplicial_complex.Simplex(set(fx))
245
246
def _repr_(self):
247
"""
248
Return a string representation of ``self``.
249
250
EXAMPLES::
251
252
sage: S = simplicial_complexes.Sphere(2)
253
sage: H = Hom(S,S)
254
sage: i = H.identity()
255
sage: i
256
Simplicial complex morphism {0: 0, 1: 1, 2: 2, 3: 3} from Simplicial complex with vertex set (0, 1, 2, 3) and facets {(0, 2, 3), (0, 1, 2), (1, 2, 3), (0, 1, 3)} to Simplicial complex with vertex set (0, 1, 2, 3) and facets {(0, 2, 3), (0, 1, 2), (1, 2, 3), (0, 1, 3)}
257
sage: i._repr_()
258
'Simplicial complex morphism {0: 0, 1: 1, 2: 2, 3: 3} from Simplicial complex with vertex set (0, 1, 2, 3) and facets {(0, 2, 3), (0, 1, 2), (1, 2, 3), (0, 1, 3)} to Simplicial complex with vertex set (0, 1, 2, 3) and facets {(0, 2, 3), (0, 1, 2), (1, 2, 3), (0, 1, 3)}'
259
"""
260
return "Simplicial complex morphism " + str(self._vertex_dictionary) + " from " + self._domain._repr_() + " to " + self._codomain._repr_()
261
262
def associated_chain_complex_morphism(self,base_ring=ZZ,augmented=False,cochain=False):
263
"""
264
Returns the associated chain complex morphism of ``self``.
265
266
EXAMPLES::
267
268
sage: S = simplicial_complexes.Sphere(1)
269
sage: T = simplicial_complexes.Sphere(2)
270
sage: H = Hom(S,T)
271
sage: f = {0:0,1:1,2:2}
272
sage: x = H(f)
273
sage: x
274
Simplicial complex morphism {0: 0, 1: 1, 2: 2} from Simplicial complex with vertex set (0, 1, 2) and facets {(1, 2), (0, 2), (0, 1)} to Simplicial complex with vertex set (0, 1, 2, 3) and facets {(0, 2, 3), (0, 1, 2), (1, 2, 3), (0, 1, 3)}
275
sage: a = x.associated_chain_complex_morphism()
276
sage: a
277
Chain complex morphism from Chain complex with at most 2 nonzero terms over Integer Ring to Chain complex with at most 3 nonzero terms over Integer Ring
278
sage: a._matrix_dictionary
279
{0: [0 0 0]
280
[0 1 0]
281
[0 0 1]
282
[1 0 0],
283
1: [0 0 0]
284
[0 1 0]
285
[0 0 0]
286
[1 0 0]
287
[0 0 0]
288
[0 0 1],
289
2: []}
290
sage: x.associated_chain_complex_morphism(augmented=True)
291
Chain complex morphism from Chain complex with at most 3 nonzero terms over Integer Ring to Chain complex with at most 4 nonzero terms over Integer Ring
292
sage: x.associated_chain_complex_morphism(cochain=True)
293
Chain complex morphism from Chain complex with at most 3 nonzero terms over Integer Ring to Chain complex with at most 2 nonzero terms over Integer Ring
294
sage: x.associated_chain_complex_morphism(augmented=True,cochain=True)
295
Chain complex morphism from Chain complex with at most 4 nonzero terms over Integer Ring to Chain complex with at most 3 nonzero terms over Integer Ring
296
sage: x.associated_chain_complex_morphism(base_ring=GF(11))
297
Chain complex morphism from Chain complex with at most 2 nonzero terms over Finite Field of size 11 to Chain complex with at most 3 nonzero terms over Finite Field of size 11
298
299
Some simplicial maps which reverse the orientation of a few simplices::
300
301
sage: g = {0:1, 1:2, 2:0}
302
sage: H(g).associated_chain_complex_morphism()._matrix_dictionary
303
{0: [0 0 0]
304
[1 0 0]
305
[0 1 0]
306
[0 0 1], 1: [ 0 0 0]
307
[-1 0 0]
308
[ 0 0 0]
309
[ 0 0 1]
310
[ 0 0 0]
311
[ 0 -1 0], 2: []}
312
313
sage: X = SimplicialComplex([[0, 1]], is_mutable=False)
314
sage: Hom(X,X)({0:1, 1:0}).associated_chain_complex_morphism()._matrix_dictionary
315
{0: [0 1]
316
[1 0], 1: [-1]}
317
"""
318
max_dim = max(self._domain.dimension(),self._codomain.dimension())
319
min_dim = min(self._domain.dimension(),self._codomain.dimension())
320
matrices = {}
321
if augmented is True:
322
m = matrix.Matrix(base_ring,1,1,1)
323
if not cochain:
324
matrices[-1] = m
325
else:
326
matrices[-1] = m.transpose()
327
for dim in range(min_dim+1):
328
# X_faces = list(self._domain.faces()[dim])
329
# Y_faces = list(self._codomain.faces()[dim])
330
X_faces = list(self._domain.n_cells(dim))
331
Y_faces = list(self._codomain.n_cells(dim))
332
num_faces_X = len(X_faces)
333
num_faces_Y = len(Y_faces)
334
mval = [0 for i in range(num_faces_X*num_faces_Y)]
335
for i in X_faces:
336
y, oriented = self(i, orientation=True)
337
if y.dimension() < dim:
338
pass
339
else:
340
mval[X_faces.index(i)+(Y_faces.index(y)*num_faces_X)] = oriented
341
m = matrix.Matrix(base_ring,num_faces_Y,num_faces_X,mval,sparse=True)
342
if not cochain:
343
matrices[dim] = m
344
else:
345
matrices[dim] = m.transpose()
346
for dim in range(min_dim+1,max_dim+1):
347
try:
348
l1 = len(self._codomain.n_cells(dim))
349
except KeyError:
350
l1 = 0
351
try:
352
l2 = len(self._domain.n_cells(dim))
353
except KeyError:
354
l2 = 0
355
m = matrix.zero_matrix(base_ring,l1,l2,sparse=True)
356
if not cochain:
357
matrices[dim] = m
358
else:
359
matrices[dim] = m.transpose()
360
if not cochain:
361
return ChainComplexMorphism(matrices,\
362
self._domain.chain_complex(base_ring=base_ring,augmented=augmented,cochain=cochain),\
363
self._codomain.chain_complex(base_ring=base_ring,augmented=augmented,cochain=cochain))
364
else:
365
return ChainComplexMorphism(matrices,\
366
self._codomain.chain_complex(base_ring=base_ring,augmented=augmented,cochain=cochain),\
367
self._domain.chain_complex(base_ring=base_ring,augmented=augmented,cochain=cochain))
368
369
def image(self):
370
"""
371
Computes the image simplicial complex of `f`.
372
373
EXAMPLES::
374
375
sage: S = SimplicialComplex([[0,1],[2,3]], is_mutable=False)
376
sage: T = SimplicialComplex([[0,1]], is_mutable=False)
377
sage: f = {0:0,1:1,2:0,3:1}
378
sage: H = Hom(S,T)
379
sage: x = H(f)
380
sage: x.image()
381
Simplicial complex with vertex set (0, 1) and facets {(0, 1)}
382
383
sage: S = SimplicialComplex(is_mutable=False)
384
sage: H = Hom(S,S)
385
sage: i = H.identity()
386
sage: i.image()
387
Simplicial complex with vertex set () and facets {()}
388
sage: i.is_surjective()
389
True
390
sage: S = SimplicialComplex([[0,1]], is_mutable=False)
391
sage: T = SimplicialComplex([[0,1], [0,2]], is_mutable=False)
392
sage: f = {0:0,1:1}
393
sage: g = {0:0,1:1}
394
sage: k = {0:0,1:2}
395
sage: H = Hom(S,T)
396
sage: x = H(f)
397
sage: y = H(g)
398
sage: z = H(k)
399
sage: x == y
400
True
401
sage: x == z
402
False
403
sage: x.image()
404
Simplicial complex with vertex set (0, 1) and facets {(0, 1)}
405
sage: y.image()
406
Simplicial complex with vertex set (0, 1) and facets {(0, 1)}
407
sage: z.image()
408
Simplicial complex with vertex set (0, 2) and facets {(0, 2)}
409
410
"""
411
fa = [self(i) for i in self._domain.facets()]
412
return simplicial_complex.SimplicialComplex(fa, maximality_check=True)
413
414
def domain(self):
415
"""
416
Returns the domain of the morphism.
417
418
EXAMPLES::
419
420
sage: S = SimplicialComplex([[0,1],[2,3]], is_mutable=False)
421
sage: T = SimplicialComplex([[0,1]], is_mutable=False)
422
sage: f = {0:0,1:1,2:0,3:1}
423
sage: H = Hom(S,T)
424
sage: x = H(f)
425
sage: x.domain()
426
Simplicial complex with vertex set (0, 1, 2, 3) and facets {(2, 3), (0, 1)}
427
"""
428
return self._domain
429
430
def codomain(self):
431
"""
432
Returns the codomain of the morphism.
433
434
EXAMPLES::
435
436
sage: S = SimplicialComplex([[0,1],[2,3]], is_mutable=False)
437
sage: T = SimplicialComplex([[0,1]], is_mutable=False)
438
sage: f = {0:0,1:1,2:0,3:1}
439
sage: H = Hom(S,T)
440
sage: x = H(f)
441
sage: x.codomain()
442
Simplicial complex with vertex set (0, 1) and facets {(0, 1)}
443
444
"""
445
return self._codomain
446
447
def is_surjective(self):
448
"""
449
Returns ``True`` if and only if ``self`` is surjective.
450
451
EXAMPLES::
452
453
sage: S = SimplicialComplex([(0,1,2)], is_mutable=False)
454
sage: S
455
Simplicial complex with vertex set (0, 1, 2) and facets {(0, 1, 2)}
456
sage: T = SimplicialComplex([(0,1)], is_mutable=False)
457
sage: T
458
Simplicial complex with vertex set (0, 1) and facets {(0, 1)}
459
sage: H = Hom(S,T)
460
sage: x = H({0:0,1:1,2:1})
461
sage: x.is_surjective()
462
True
463
464
sage: S = SimplicialComplex([[0,1],[2,3]], is_mutable=False)
465
sage: T = SimplicialComplex([[0,1]], is_mutable=False)
466
sage: f = {0:0,1:1,2:0,3:1}
467
sage: H = Hom(S,T)
468
sage: x = H(f)
469
sage: x.is_surjective()
470
True
471
"""
472
return self._codomain == self.image()
473
474
def is_injective(self):
475
"""
476
Returns ``True`` if and only if ``self`` is injective.
477
478
EXAMPLES::
479
480
sage: S = simplicial_complexes.Sphere(1)
481
sage: T = simplicial_complexes.Sphere(2)
482
sage: U = simplicial_complexes.Sphere(3)
483
sage: H = Hom(T,S)
484
sage: G = Hom(T,U)
485
sage: f = {0:0,1:1,2:0,3:1}
486
sage: x = H(f)
487
sage: g = {0:0,1:1,2:2,3:3}
488
sage: y = G(g)
489
sage: x.is_injective()
490
False
491
sage: y.is_injective()
492
True
493
494
"""
495
v = [self._vertex_dictionary[i[0]] for i in self._domain.faces()[0]]
496
for i in v:
497
if v.count(i) > 1:
498
return False
499
return True
500
501
def is_identity(self):
502
"""
503
If ``self`` is an identity morphism, returns ``True``.
504
Otherwise, ``False``.
505
506
EXAMPLES::
507
508
sage: T = simplicial_complexes.Sphere(1)
509
sage: G = Hom(T,T)
510
sage: T
511
Simplicial complex with vertex set (0, 1, 2) and facets {(1, 2), (0, 2), (0, 1)}
512
sage: j = G({0:0,1:1,2:2})
513
sage: j.is_identity()
514
True
515
516
sage: S = simplicial_complexes.Sphere(2)
517
sage: T = simplicial_complexes.Sphere(3)
518
sage: H = Hom(S,T)
519
sage: f = {0:0,1:1,2:2,3:3}
520
sage: x = H(f)
521
sage: x
522
Simplicial complex morphism {0: 0, 1: 1, 2: 2, 3: 3} from Simplicial complex with vertex set (0, 1, 2, 3) and facets {(0, 2, 3), (0, 1, 2), (1, 2, 3), (0, 1, 3)} to Simplicial complex with vertex set (0, 1, 2, 3, 4) and 5 facets
523
sage: x.is_identity()
524
False
525
526
"""
527
if self._domain != self._codomain:
528
return False
529
else:
530
f = dict()
531
for i in self._domain._vertex_set.set():
532
f[i] = i
533
if self._vertex_dictionary != f:
534
return False
535
else:
536
return True
537
538
def fiber_product(self, other, rename_vertices = True):
539
"""
540
Fiber product of ``self`` and ``other``. Both morphisms should have
541
the same codomain. The method returns a morphism of simplicial
542
complexes, which is the morphism from the space of the fiber product
543
to the codomain.
544
545
EXAMPLES::
546
547
sage: S = SimplicialComplex([[0,1],[1,2]], is_mutable=False)
548
sage: T = SimplicialComplex([[0,2],[1]], is_mutable=False)
549
sage: U = SimplicialComplex([[0,1],[2]], is_mutable=False)
550
sage: H = Hom(S,U)
551
sage: G = Hom(T,U)
552
sage: f = {0:0,1:1,2:0}
553
sage: g = {0:0,1:1,2:1}
554
sage: x = H(f)
555
sage: y = G(g)
556
sage: z = x.fiber_product(y)
557
sage: z
558
Simplicial complex morphism {'L1R2': 1, 'L1R1': 1, 'L2R0': 0, 'L0R0': 0}
559
from Simplicial complex with 4 vertices and facets
560
{('L2R0',), ('L1R1',), ('L0R0', 'L1R2')} to Simplicial complex
561
with vertex set (0, 1, 2) and facets {(2,), (0, 1)}
562
"""
563
if self._codomain != other._codomain:
564
raise ValueError("self and other must have the same codomain.")
565
X = self._domain.product(other._domain,rename_vertices = rename_vertices)
566
v = []
567
f = dict()
568
eff1 = self._domain._vertex_set
569
eff2 = other._domain._vertex_set
570
for i in eff1:
571
for j in eff2:
572
if self(simplicial_complex.Simplex([i])) == other(simplicial_complex.Simplex([j])):
573
if rename_vertices:
574
v.append("L"+str(i)+"R"+str(j))
575
f["L"+str(i)+"R"+str(j)] = self._vertex_dictionary[i]
576
else:
577
v.append((i,j))
578
f[(i,j)] = self._vertex_dictionary[i]
579
return SimplicialComplexMorphism(f, X.generated_subcomplex(v), self._codomain)
580
581
def mapping_torus(self):
582
r"""
583
The mapping torus of a simplicial complex endomorphism
584
585
The mapping torus is the simplicial complex formed by taking
586
the product of the domain of ``self`` with a `4` point
587
interval `[I_0, I_1, I_2, I_3]` and identifying vertices of
588
the form `(I_0, v)` with `(I_3, w)` where `w` is the image of
589
`v` under the given morphism.
590
591
See :wikipedia:`Mapping torus`
592
593
EXAMPLES::
594
595
sage: C = simplicial_complexes.Sphere(1) # Circle
596
sage: T = Hom(C,C).identity().mapping_torus() ; T # Torus
597
Simplicial complex with 9 vertices and 18 facets
598
sage: T.homology() == simplicial_complexes.Torus().homology()
599
True
600
601
sage: f = Hom(C,C)({0:0,1:2,2:1})
602
sage: K = f.mapping_torus() ; K # Klein Bottle
603
Simplicial complex with 9 vertices and 18 facets
604
sage: K.homology() == simplicial_complexes.KleinBottle().homology()
605
True
606
607
TESTS::
608
609
sage: g = Hom(simplicial_complexes.Simplex([1]),C)({1:0})
610
sage: g.mapping_torus()
611
Traceback (most recent call last):
612
...
613
ValueError: self must have the same domain and codomain.
614
"""
615
if self._domain != self._codomain:
616
raise ValueError("self must have the same domain and codomain.")
617
map_dict = self._vertex_dictionary
618
interval = simplicial_complex.SimplicialComplex([["I0","I1"],["I1","I2"]])
619
product = interval.product(self._domain,False)
620
facets = list(product.maximal_faces())
621
for facet in self._domain._facets:
622
left = [ ("I0",v) for v in facet ]
623
right = [ ("I2",map_dict[v]) for v in facet ]
624
for i in range(facet.dimension()+1):
625
facets.append(tuple(left[:i+1]+right[i:]))
626
return simplicial_complex.SimplicialComplex(facets)
627
628