passagemath-graphs 10.6.1rc1__cp310-cp310-musllinux_1_2_aarch64.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (260) hide show
  1. passagemath_graphs-10.6.1rc1.dist-info/METADATA +292 -0
  2. passagemath_graphs-10.6.1rc1.dist-info/RECORD +260 -0
  3. passagemath_graphs-10.6.1rc1.dist-info/WHEEL +5 -0
  4. passagemath_graphs-10.6.1rc1.dist-info/top_level.txt +2 -0
  5. passagemath_graphs.libs/libgcc_s-69c45f16.so.1 +0 -0
  6. passagemath_graphs.libs/libgmp-8e78bd9b.so.10.5.0 +0 -0
  7. passagemath_graphs.libs/libstdc++-1f1a71be.so.6.0.33 +0 -0
  8. sage/all__sagemath_graphs.py +39 -0
  9. sage/combinat/abstract_tree.py +2723 -0
  10. sage/combinat/all__sagemath_graphs.py +34 -0
  11. sage/combinat/binary_tree.py +5306 -0
  12. sage/combinat/cluster_algebra_quiver/all.py +22 -0
  13. sage/combinat/cluster_algebra_quiver/cluster_seed.py +5208 -0
  14. sage/combinat/cluster_algebra_quiver/interact.py +124 -0
  15. sage/combinat/cluster_algebra_quiver/mutation_class.py +625 -0
  16. sage/combinat/cluster_algebra_quiver/mutation_type.py +1555 -0
  17. sage/combinat/cluster_algebra_quiver/quiver.py +2290 -0
  18. sage/combinat/cluster_algebra_quiver/quiver_mutation_type.py +2468 -0
  19. sage/combinat/designs/MOLS_handbook_data.py +570 -0
  20. sage/combinat/designs/all.py +58 -0
  21. sage/combinat/designs/bibd.py +1655 -0
  22. sage/combinat/designs/block_design.py +1071 -0
  23. sage/combinat/designs/covering_array.py +269 -0
  24. sage/combinat/designs/covering_design.py +530 -0
  25. sage/combinat/designs/database.py +5615 -0
  26. sage/combinat/designs/design_catalog.py +122 -0
  27. sage/combinat/designs/designs_pyx.cpython-310-aarch64-linux-gnu.so +0 -0
  28. sage/combinat/designs/designs_pyx.pxd +21 -0
  29. sage/combinat/designs/designs_pyx.pyx +993 -0
  30. sage/combinat/designs/difference_family.py +3951 -0
  31. sage/combinat/designs/difference_matrices.py +279 -0
  32. sage/combinat/designs/evenly_distributed_sets.cpython-310-aarch64-linux-gnu.so +0 -0
  33. sage/combinat/designs/evenly_distributed_sets.pyx +661 -0
  34. sage/combinat/designs/ext_rep.py +1064 -0
  35. sage/combinat/designs/gen_quadrangles_with_spread.cpython-310-aarch64-linux-gnu.so +0 -0
  36. sage/combinat/designs/gen_quadrangles_with_spread.pyx +339 -0
  37. sage/combinat/designs/group_divisible_designs.py +361 -0
  38. sage/combinat/designs/incidence_structures.py +2357 -0
  39. sage/combinat/designs/latin_squares.py +581 -0
  40. sage/combinat/designs/orthogonal_arrays.py +2244 -0
  41. sage/combinat/designs/orthogonal_arrays_build_recursive.py +1780 -0
  42. sage/combinat/designs/orthogonal_arrays_find_recursive.cpython-310-aarch64-linux-gnu.so +0 -0
  43. sage/combinat/designs/orthogonal_arrays_find_recursive.pyx +967 -0
  44. sage/combinat/designs/resolvable_bibd.py +815 -0
  45. sage/combinat/designs/steiner_quadruple_systems.py +1306 -0
  46. sage/combinat/designs/subhypergraph_search.cpython-310-aarch64-linux-gnu.so +0 -0
  47. sage/combinat/designs/subhypergraph_search.pyx +530 -0
  48. sage/combinat/designs/twographs.py +306 -0
  49. sage/combinat/finite_state_machine.py +14874 -0
  50. sage/combinat/finite_state_machine_generators.py +2006 -0
  51. sage/combinat/graph_path.py +448 -0
  52. sage/combinat/interval_posets.py +3908 -0
  53. sage/combinat/nu_tamari_lattice.py +269 -0
  54. sage/combinat/ordered_tree.py +1446 -0
  55. sage/combinat/posets/all.py +46 -0
  56. sage/combinat/posets/bubble_shuffle.py +247 -0
  57. sage/combinat/posets/cartesian_product.py +493 -0
  58. sage/combinat/posets/d_complete.py +182 -0
  59. sage/combinat/posets/elements.py +273 -0
  60. sage/combinat/posets/forest.py +30 -0
  61. sage/combinat/posets/hasse_cython.cpython-310-aarch64-linux-gnu.so +0 -0
  62. sage/combinat/posets/hasse_cython.pyx +174 -0
  63. sage/combinat/posets/hasse_diagram.py +3672 -0
  64. sage/combinat/posets/hochschild_lattice.py +158 -0
  65. sage/combinat/posets/incidence_algebras.py +794 -0
  66. sage/combinat/posets/lattices.py +5117 -0
  67. sage/combinat/posets/linear_extension_iterator.cpython-310-aarch64-linux-gnu.so +0 -0
  68. sage/combinat/posets/linear_extension_iterator.pyx +292 -0
  69. sage/combinat/posets/linear_extensions.py +1037 -0
  70. sage/combinat/posets/mobile.py +275 -0
  71. sage/combinat/posets/moebius_algebra.py +776 -0
  72. sage/combinat/posets/poset_examples.py +2178 -0
  73. sage/combinat/posets/posets.py +9360 -0
  74. sage/combinat/rooted_tree.py +1070 -0
  75. sage/combinat/shard_order.py +239 -0
  76. sage/combinat/tamari_lattices.py +384 -0
  77. sage/combinat/yang_baxter_graph.py +923 -0
  78. sage/databases/all__sagemath_graphs.py +1 -0
  79. sage/databases/knotinfo_db.py +1231 -0
  80. sage/ext_data/all__sagemath_graphs.py +1 -0
  81. sage/ext_data/graphs/graph_plot_js.html +330 -0
  82. sage/ext_data/kenzo/CP2.txt +45 -0
  83. sage/ext_data/kenzo/CP3.txt +349 -0
  84. sage/ext_data/kenzo/CP4.txt +4774 -0
  85. sage/ext_data/kenzo/README.txt +49 -0
  86. sage/ext_data/kenzo/S4.txt +20 -0
  87. sage/graphs/all.py +42 -0
  88. sage/graphs/asteroidal_triples.cpython-310-aarch64-linux-gnu.so +0 -0
  89. sage/graphs/asteroidal_triples.pyx +320 -0
  90. sage/graphs/base/all.py +1 -0
  91. sage/graphs/base/boost_graph.cpython-310-aarch64-linux-gnu.so +0 -0
  92. sage/graphs/base/boost_graph.pxd +106 -0
  93. sage/graphs/base/boost_graph.pyx +3045 -0
  94. sage/graphs/base/c_graph.cpython-310-aarch64-linux-gnu.so +0 -0
  95. sage/graphs/base/c_graph.pxd +106 -0
  96. sage/graphs/base/c_graph.pyx +5096 -0
  97. sage/graphs/base/dense_graph.cpython-310-aarch64-linux-gnu.so +0 -0
  98. sage/graphs/base/dense_graph.pxd +28 -0
  99. sage/graphs/base/dense_graph.pyx +801 -0
  100. sage/graphs/base/graph_backends.cpython-310-aarch64-linux-gnu.so +0 -0
  101. sage/graphs/base/graph_backends.pxd +5 -0
  102. sage/graphs/base/graph_backends.pyx +797 -0
  103. sage/graphs/base/overview.py +85 -0
  104. sage/graphs/base/sparse_graph.cpython-310-aarch64-linux-gnu.so +0 -0
  105. sage/graphs/base/sparse_graph.pxd +90 -0
  106. sage/graphs/base/sparse_graph.pyx +1653 -0
  107. sage/graphs/base/static_dense_graph.cpython-310-aarch64-linux-gnu.so +0 -0
  108. sage/graphs/base/static_dense_graph.pxd +5 -0
  109. sage/graphs/base/static_dense_graph.pyx +1032 -0
  110. sage/graphs/base/static_sparse_backend.cpython-310-aarch64-linux-gnu.so +0 -0
  111. sage/graphs/base/static_sparse_backend.pxd +27 -0
  112. sage/graphs/base/static_sparse_backend.pyx +1583 -0
  113. sage/graphs/base/static_sparse_graph.cpython-310-aarch64-linux-gnu.so +0 -0
  114. sage/graphs/base/static_sparse_graph.pxd +37 -0
  115. sage/graphs/base/static_sparse_graph.pyx +1375 -0
  116. sage/graphs/bipartite_graph.py +2732 -0
  117. sage/graphs/centrality.cpython-310-aarch64-linux-gnu.so +0 -0
  118. sage/graphs/centrality.pyx +1038 -0
  119. sage/graphs/cographs.py +519 -0
  120. sage/graphs/comparability.cpython-310-aarch64-linux-gnu.so +0 -0
  121. sage/graphs/comparability.pyx +851 -0
  122. sage/graphs/connectivity.cpython-310-aarch64-linux-gnu.so +0 -0
  123. sage/graphs/connectivity.pxd +157 -0
  124. sage/graphs/connectivity.pyx +4813 -0
  125. sage/graphs/convexity_properties.cpython-310-aarch64-linux-gnu.so +0 -0
  126. sage/graphs/convexity_properties.pxd +16 -0
  127. sage/graphs/convexity_properties.pyx +870 -0
  128. sage/graphs/digraph.py +4754 -0
  129. sage/graphs/digraph_generators.py +1993 -0
  130. sage/graphs/distances_all_pairs.cpython-310-aarch64-linux-gnu.so +0 -0
  131. sage/graphs/distances_all_pairs.pxd +12 -0
  132. sage/graphs/distances_all_pairs.pyx +2938 -0
  133. sage/graphs/domination.py +1363 -0
  134. sage/graphs/dot2tex_utils.py +100 -0
  135. sage/graphs/edge_connectivity.cpython-310-aarch64-linux-gnu.so +0 -0
  136. sage/graphs/edge_connectivity.pyx +1215 -0
  137. sage/graphs/generators/all.py +1 -0
  138. sage/graphs/generators/basic.py +1769 -0
  139. sage/graphs/generators/chessboard.py +538 -0
  140. sage/graphs/generators/classical_geometries.py +1611 -0
  141. sage/graphs/generators/degree_sequence.py +235 -0
  142. sage/graphs/generators/distance_regular.cpython-310-aarch64-linux-gnu.so +0 -0
  143. sage/graphs/generators/distance_regular.pyx +2846 -0
  144. sage/graphs/generators/families.py +4759 -0
  145. sage/graphs/generators/intersection.py +565 -0
  146. sage/graphs/generators/platonic_solids.py +262 -0
  147. sage/graphs/generators/random.py +2623 -0
  148. sage/graphs/generators/smallgraphs.py +5741 -0
  149. sage/graphs/generators/world_map.py +724 -0
  150. sage/graphs/generic_graph.py +26867 -0
  151. sage/graphs/generic_graph_pyx.cpython-310-aarch64-linux-gnu.so +0 -0
  152. sage/graphs/generic_graph_pyx.pxd +34 -0
  153. sage/graphs/generic_graph_pyx.pyx +1673 -0
  154. sage/graphs/genus.cpython-310-aarch64-linux-gnu.so +0 -0
  155. sage/graphs/genus.pyx +622 -0
  156. sage/graphs/graph.py +9645 -0
  157. sage/graphs/graph_coloring.cpython-310-aarch64-linux-gnu.so +0 -0
  158. sage/graphs/graph_coloring.pyx +2284 -0
  159. sage/graphs/graph_database.py +1177 -0
  160. sage/graphs/graph_decompositions/all.py +1 -0
  161. sage/graphs/graph_decompositions/bandwidth.cpython-310-aarch64-linux-gnu.so +0 -0
  162. sage/graphs/graph_decompositions/bandwidth.pyx +428 -0
  163. sage/graphs/graph_decompositions/clique_separators.cpython-310-aarch64-linux-gnu.so +0 -0
  164. sage/graphs/graph_decompositions/clique_separators.pyx +616 -0
  165. sage/graphs/graph_decompositions/cutwidth.cpython-310-aarch64-linux-gnu.so +0 -0
  166. sage/graphs/graph_decompositions/cutwidth.pyx +753 -0
  167. sage/graphs/graph_decompositions/fast_digraph.cpython-310-aarch64-linux-gnu.so +0 -0
  168. sage/graphs/graph_decompositions/fast_digraph.pxd +13 -0
  169. sage/graphs/graph_decompositions/fast_digraph.pyx +212 -0
  170. sage/graphs/graph_decompositions/graph_products.cpython-310-aarch64-linux-gnu.so +0 -0
  171. sage/graphs/graph_decompositions/graph_products.pyx +508 -0
  172. sage/graphs/graph_decompositions/modular_decomposition.cpython-310-aarch64-linux-gnu.so +0 -0
  173. sage/graphs/graph_decompositions/modular_decomposition.pxd +27 -0
  174. sage/graphs/graph_decompositions/modular_decomposition.pyx +1536 -0
  175. sage/graphs/graph_decompositions/slice_decomposition.cpython-310-aarch64-linux-gnu.so +0 -0
  176. sage/graphs/graph_decompositions/slice_decomposition.pxd +18 -0
  177. sage/graphs/graph_decompositions/slice_decomposition.pyx +1106 -0
  178. sage/graphs/graph_decompositions/tree_decomposition.cpython-310-aarch64-linux-gnu.so +0 -0
  179. sage/graphs/graph_decompositions/tree_decomposition.pxd +17 -0
  180. sage/graphs/graph_decompositions/tree_decomposition.pyx +1996 -0
  181. sage/graphs/graph_decompositions/vertex_separation.cpython-310-aarch64-linux-gnu.so +0 -0
  182. sage/graphs/graph_decompositions/vertex_separation.pxd +5 -0
  183. sage/graphs/graph_decompositions/vertex_separation.pyx +1963 -0
  184. sage/graphs/graph_editor.py +82 -0
  185. sage/graphs/graph_generators.py +3314 -0
  186. sage/graphs/graph_generators_pyx.cpython-310-aarch64-linux-gnu.so +0 -0
  187. sage/graphs/graph_generators_pyx.pyx +95 -0
  188. sage/graphs/graph_input.py +812 -0
  189. sage/graphs/graph_latex.py +2064 -0
  190. sage/graphs/graph_list.py +410 -0
  191. sage/graphs/graph_plot.py +1756 -0
  192. sage/graphs/graph_plot_js.py +338 -0
  193. sage/graphs/hyperbolicity.cpython-310-aarch64-linux-gnu.so +0 -0
  194. sage/graphs/hyperbolicity.pyx +1704 -0
  195. sage/graphs/hypergraph_generators.py +364 -0
  196. sage/graphs/independent_sets.cpython-310-aarch64-linux-gnu.so +0 -0
  197. sage/graphs/independent_sets.pxd +13 -0
  198. sage/graphs/independent_sets.pyx +402 -0
  199. sage/graphs/isgci.py +1033 -0
  200. sage/graphs/isoperimetric_inequalities.cpython-310-aarch64-linux-gnu.so +0 -0
  201. sage/graphs/isoperimetric_inequalities.pyx +489 -0
  202. sage/graphs/line_graph.cpython-310-aarch64-linux-gnu.so +0 -0
  203. sage/graphs/line_graph.pyx +743 -0
  204. sage/graphs/lovasz_theta.py +77 -0
  205. sage/graphs/matching.py +1633 -0
  206. sage/graphs/matching_covered_graph.py +3590 -0
  207. sage/graphs/orientations.py +1489 -0
  208. sage/graphs/partial_cube.py +459 -0
  209. sage/graphs/path_enumeration.cpython-310-aarch64-linux-gnu.so +0 -0
  210. sage/graphs/path_enumeration.pyx +2040 -0
  211. sage/graphs/pq_trees.py +1129 -0
  212. sage/graphs/print_graphs.py +201 -0
  213. sage/graphs/schnyder.py +865 -0
  214. sage/graphs/spanning_tree.cpython-310-aarch64-linux-gnu.so +0 -0
  215. sage/graphs/spanning_tree.pyx +1457 -0
  216. sage/graphs/strongly_regular_db.cpython-310-aarch64-linux-gnu.so +0 -0
  217. sage/graphs/strongly_regular_db.pyx +3340 -0
  218. sage/graphs/traversals.cpython-310-aarch64-linux-gnu.so +0 -0
  219. sage/graphs/traversals.pxd +9 -0
  220. sage/graphs/traversals.pyx +1872 -0
  221. sage/graphs/trees.cpython-310-aarch64-linux-gnu.so +0 -0
  222. sage/graphs/trees.pxd +15 -0
  223. sage/graphs/trees.pyx +310 -0
  224. sage/graphs/tutte_polynomial.py +713 -0
  225. sage/graphs/views.cpython-310-aarch64-linux-gnu.so +0 -0
  226. sage/graphs/views.pyx +794 -0
  227. sage/graphs/weakly_chordal.cpython-310-aarch64-linux-gnu.so +0 -0
  228. sage/graphs/weakly_chordal.pyx +604 -0
  229. sage/groups/all__sagemath_graphs.py +1 -0
  230. sage/groups/perm_gps/all__sagemath_graphs.py +1 -0
  231. sage/groups/perm_gps/partn_ref/all__sagemath_graphs.py +1 -0
  232. sage/groups/perm_gps/partn_ref/refinement_graphs.cpython-310-aarch64-linux-gnu.so +0 -0
  233. sage/groups/perm_gps/partn_ref/refinement_graphs.pxd +38 -0
  234. sage/groups/perm_gps/partn_ref/refinement_graphs.pyx +1666 -0
  235. sage/knots/all.py +6 -0
  236. sage/knots/free_knotinfo_monoid.py +507 -0
  237. sage/knots/gauss_code.py +291 -0
  238. sage/knots/knot.py +682 -0
  239. sage/knots/knot_table.py +284 -0
  240. sage/knots/knotinfo.py +2900 -0
  241. sage/knots/link.py +4715 -0
  242. sage/sandpiles/all.py +13 -0
  243. sage/sandpiles/examples.py +225 -0
  244. sage/sandpiles/sandpile.py +6365 -0
  245. sage/topology/all.py +22 -0
  246. sage/topology/cell_complex.py +1214 -0
  247. sage/topology/cubical_complex.py +1976 -0
  248. sage/topology/delta_complex.py +1806 -0
  249. sage/topology/filtered_simplicial_complex.py +744 -0
  250. sage/topology/moment_angle_complex.py +823 -0
  251. sage/topology/simplicial_complex.py +5160 -0
  252. sage/topology/simplicial_complex_catalog.py +92 -0
  253. sage/topology/simplicial_complex_examples.py +1680 -0
  254. sage/topology/simplicial_complex_homset.py +205 -0
  255. sage/topology/simplicial_complex_morphism.py +836 -0
  256. sage/topology/simplicial_set.py +4102 -0
  257. sage/topology/simplicial_set_catalog.py +55 -0
  258. sage/topology/simplicial_set_constructions.py +2954 -0
  259. sage/topology/simplicial_set_examples.py +865 -0
  260. sage/topology/simplicial_set_morphism.py +1464 -0
@@ -0,0 +1,1464 @@
1
+ # sage_setup: distribution = sagemath-graphs
2
+ # sage.doctest: needs sage.graphs
3
+ r"""
4
+ Morphisms and homsets for simplicial sets
5
+
6
+ .. NOTE::
7
+
8
+ Morphisms with infinite domain are not implemented in general:
9
+ only constant maps and identity maps are currently implemented.
10
+
11
+ AUTHORS:
12
+
13
+ - John H. Palmieri (2016-07)
14
+
15
+ This module implements morphisms and homsets of simplicial sets.
16
+ """
17
+
18
+ # ****************************************************************************
19
+ # Copyright (C) 2016 John H. Palmieri <palmieri at math.washington.edu>
20
+ #
21
+ # Distributed under the terms of the GNU General Public License (GPL)
22
+ # https://www.gnu.org/licenses/
23
+ #
24
+ # This code is distributed in the hope that it will be useful,
25
+ # but WITHOUT ANY WARRANTY; without even the implied warranty
26
+ # of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
27
+ #
28
+ # See the GNU General Public License for more details; the full text
29
+ # is available at:
30
+ #
31
+ # https://www.gnu.org/licenses/
32
+ #
33
+ # ****************************************************************************
34
+
35
+ import itertools
36
+
37
+ from sage.categories.homset import Hom, Homset
38
+ from sage.categories.morphism import Morphism
39
+ from sage.categories.simplicial_sets import SimplicialSets
40
+ from sage.misc.latex import latex
41
+ from sage.misc.lazy_import import lazy_import
42
+ from sage.rings.integer_ring import ZZ
43
+
44
+ from .simplicial_set import SimplicialSet_arbitrary
45
+
46
+ lazy_import('sage.matrix.constructor', ['matrix', 'zero_matrix'])
47
+
48
+
49
+ class SimplicialSetHomset(Homset):
50
+ r"""
51
+ A set of morphisms between simplicial sets.
52
+
53
+ Once a homset has been constructed in Sage, typically via
54
+ ``Hom(X,Y)`` or ``X.Hom(Y)``, one can use it to construct a
55
+ morphism `f` by specifying a dictionary, the keys of which are the
56
+ nondegenerate simplices in the domain, and the value corresponding
57
+ to `\sigma` is the simplex `f(\sigma)` in the codomain.
58
+
59
+ EXAMPLES::
60
+
61
+ sage: from sage.topology.simplicial_set import AbstractSimplex, SimplicialSet
62
+ sage: v = AbstractSimplex(0, name='v')
63
+ sage: w = AbstractSimplex(0, name='w')
64
+ sage: e = AbstractSimplex(1, name='e')
65
+ sage: f = AbstractSimplex(1, name='f')
66
+ sage: X = SimplicialSet({e: (v, w), f: (w, v)})
67
+ sage: Y = SimplicialSet({e: (v, v)})
68
+
69
+ Define the homset::
70
+
71
+ sage: H = Hom(X, Y)
72
+
73
+ Now define a morphism by specifying a dictionary::
74
+
75
+ sage: H({v: v, w: v, e: e, f: e})
76
+ Simplicial set morphism:
77
+ From: Simplicial set with 4 non-degenerate simplices
78
+ To: Simplicial set with 2 non-degenerate simplices
79
+ Defn: [v, w, e, f] --> [v, v, e, e]
80
+ """
81
+ def __call__(self, f, check=True):
82
+ r"""
83
+ INPUT:
84
+
85
+ - ``f`` -- dictionary with keys the simplices of the domain
86
+ and values simplices of the codomain
87
+
88
+ - ``check`` -- boolean (default ``True``); pass this to the
89
+ morphism constructor
90
+
91
+ EXAMPLES::
92
+
93
+ sage: S1 = simplicial_sets.Sphere(1)
94
+ sage: v0 = S1.n_cells(0)[0]
95
+ sage: e = S1.n_cells(1)[0]
96
+ sage: f = {v0: v0, e: v0.apply_degeneracies(0)} # constant map
97
+ sage: Hom(S1, S1)(f)
98
+ Simplicial set endomorphism of S^1
99
+ Defn: Constant map at v_0
100
+ """
101
+ return SimplicialSetMorphism(f, self.domain(), self.codomain(), check=check)
102
+
103
+ def diagonal_morphism(self):
104
+ r"""
105
+ Return the diagonal morphism in `\operatorname{Hom}(S, S \times S)`.
106
+
107
+ EXAMPLES::
108
+
109
+ sage: RP2 = simplicial_sets.RealProjectiveSpace(2) # needs sage.groups
110
+ sage: Hom(RP2, RP2.product(RP2)).diagonal_morphism() # needs sage.groups
111
+ Simplicial set morphism:
112
+ From: RP^2
113
+ To: RP^2 x RP^2
114
+ Defn: [1, f, f * f] --> [(1, 1), (f, f), (f * f, f * f)]
115
+ """
116
+ domain = self.domain()
117
+ codomain = self.codomain()
118
+ if not hasattr(codomain, 'factors'):
119
+ raise ValueError('diagonal morphism is only defined for Hom(X, XxX)')
120
+ factors = codomain.factors()
121
+ if len(factors) != 2 or factors[0] != domain or factors[1] != domain:
122
+ raise ValueError('diagonal morphism is only defined for Hom(X, XxX)')
123
+ f = {}
124
+ for i in range(domain.dimension()+1):
125
+ for s in domain.n_cells(i):
126
+ f[s] = dict(codomain._translation)[((s, ()), (s, ()))]
127
+ return self(f)
128
+
129
+ def identity(self):
130
+ r"""
131
+ Return the identity morphism in `\operatorname{Hom}(S, S)`.
132
+
133
+ EXAMPLES::
134
+
135
+ sage: S1 = simplicial_sets.Sphere(1)
136
+ sage: Hom(S1, S1).identity()
137
+ Simplicial set endomorphism of S^1
138
+ Defn: Identity map
139
+ sage: T = simplicial_sets.Torus()
140
+ sage: Hom(S1, T).identity()
141
+ Traceback (most recent call last):
142
+ ...
143
+ TypeError: identity map is only defined for endomorphism sets
144
+ """
145
+ return SimplicialSetMorphism(domain=self.domain(),
146
+ codomain=self.codomain(),
147
+ identity=True)
148
+
149
+ def constant_map(self, point=None):
150
+ r"""
151
+ Return the constant map in this homset.
152
+
153
+ INPUT:
154
+
155
+ - ``point`` -- (default: ``None``) if specified, it must be a 0-simplex
156
+ in the codomain, and it will be the target of the constant map
157
+
158
+ If ``point`` is specified, it is the target of the constant
159
+ map. Otherwise, if the codomain is pointed, the target is its
160
+ base point. If the codomain is not pointed and ``point`` is
161
+ not specified, raise an error.
162
+
163
+ EXAMPLES::
164
+
165
+ sage: S3 = simplicial_sets.Sphere(3)
166
+ sage: T = simplicial_sets.Torus()
167
+ sage: T.n_cells(0)[0].rename('w')
168
+ sage: Hom(S3,T).constant_map()
169
+ Simplicial set morphism:
170
+ From: S^3
171
+ To: Torus
172
+ Defn: Constant map at w
173
+
174
+ sage: S0 = simplicial_sets.Sphere(0)
175
+ sage: v, w = S0.n_cells(0)
176
+ sage: Hom(S3, S0).constant_map(v)
177
+ Simplicial set morphism:
178
+ From: S^3
179
+ To: S^0
180
+ Defn: Constant map at v_0
181
+ sage: Hom(S3, S0).constant_map(w)
182
+ Simplicial set morphism:
183
+ From: S^3
184
+ To: S^0
185
+ Defn: Constant map at w_0
186
+
187
+ This constant map is not pointed, since it doesn't send the
188
+ base point of `S^3` to the base point of `S^0`::
189
+
190
+ sage: Hom(S3, S0).constant_map(w).is_pointed()
191
+ False
192
+
193
+ TESTS::
194
+
195
+ sage: S0 = S0.unset_base_point()
196
+ sage: Hom(S3, S0).constant_map()
197
+ Traceback (most recent call last):
198
+ ...
199
+ ValueError: codomain is not pointed, so specify a target for the constant map
200
+ """
201
+ codomain = self.codomain()
202
+ if point is None:
203
+ if codomain.is_pointed():
204
+ point = codomain.base_point()
205
+ else:
206
+ raise ValueError('codomain is not pointed, so specify a '
207
+ 'target for the constant map')
208
+ return SimplicialSetMorphism(domain=self.domain(),
209
+ codomain=self.codomain(),
210
+ constant=point)
211
+
212
+ def an_element(self):
213
+ """
214
+ Return an element of this homset: a constant map.
215
+
216
+ EXAMPLES::
217
+
218
+ sage: S1 = simplicial_sets.Sphere(1)
219
+ sage: S2 = simplicial_sets.Sphere(2)
220
+ sage: Hom(S2, S1).an_element()
221
+ Simplicial set morphism:
222
+ From: S^2
223
+ To: S^1
224
+ Defn: Constant map at v_0
225
+
226
+ sage: K = simplicial_sets.Simplex(3)
227
+ sage: L = simplicial_sets.Simplex(4)
228
+ sage: d = {K.n_cells(3)[0]: L.n_cells(0)[0].apply_degeneracies(2, 1, 0)}
229
+ sage: Hom(K,L)(d) == Hom(K,L).an_element()
230
+ True
231
+ """
232
+ codomain = self.codomain()
233
+ if codomain.is_pointed():
234
+ target = codomain.base_point()
235
+ else:
236
+ target = codomain.n_cells(0)[0]
237
+ return self.constant_map(target)
238
+
239
+ def __iter__(self):
240
+ """
241
+ Iterate through all morphisms in this homset.
242
+
243
+ This is very slow: it tries all possible targets for the
244
+ maximal nondegenerate simplices and yields those which are
245
+ valid morphisms of simplicial sets. ("Maximal" means
246
+ nondegenerate simplices which are not the faces of other
247
+ nondegenerate simplices.) So if either the domain or the
248
+ codomain has many simplices, the number of possibilities may
249
+ be quite large.
250
+
251
+ This is only implemented when the domain is finite.
252
+
253
+ EXAMPLES::
254
+
255
+ sage: S1 = simplicial_sets.Sphere(1)
256
+ sage: T = simplicial_sets.Torus()
257
+ sage: H = Hom(S1, T)
258
+ sage: list(H)
259
+ [Simplicial set morphism:
260
+ From: S^1
261
+ To: Torus
262
+ Defn: [v_0, sigma_1] --> [(v_0, v_0), (s_0 v_0, sigma_1)],
263
+ Simplicial set morphism:
264
+ From: S^1
265
+ To: Torus
266
+ Defn: [v_0, sigma_1] --> [(v_0, v_0), (sigma_1, s_0 v_0)],
267
+ Simplicial set morphism:
268
+ From: S^1
269
+ To: Torus
270
+ Defn: [v_0, sigma_1] --> [(v_0, v_0), (sigma_1, sigma_1)],
271
+ Simplicial set morphism:
272
+ From: S^1
273
+ To: Torus
274
+ Defn: Constant map at (v_0, v_0)]
275
+ sage: [f.induced_homology_morphism().to_matrix() for f in H] # needs sage.modules
276
+ [
277
+ [ 1| 0] [1|0] [1|0] [1|0]
278
+ [--+--] [-+-] [-+-] [-+-]
279
+ [ 0|-1] [0|1] [0|0] [0|0]
280
+ [ 0| 1] [0|0] [0|1] [0|0]
281
+ [--+--] [-+-] [-+-] [-+-]
282
+ [ 0| 0], [0|0], [0|0], [0|0]
283
+ ]
284
+ """
285
+ if not self.domain().is_finite():
286
+ raise NotImplementedError('domain must be finite to iterate '
287
+ 'through all morphisms')
288
+ codomain = self.codomain()
289
+ facets = self.domain()._facets_()
290
+ dims = [f.dimension() for f in facets]
291
+ # Record all of the n-simplices in the codomain once for each
292
+ # relevant dimension.
293
+ all_n_simplices = {d: codomain.all_n_simplices(d) for d in set(dims)}
294
+ for target in itertools.product(*[all_n_simplices[d] for d in dims]):
295
+ try:
296
+ yield self(dict(zip(facets, target)))
297
+ except ValueError:
298
+ # Not a valid morphism.
299
+ pass
300
+
301
+ def _latex_(self):
302
+ r"""
303
+ LaTeX representation.
304
+
305
+ EXAMPLES::
306
+
307
+ sage: S1 = simplicial_sets.Sphere(1)
308
+ sage: T = simplicial_sets.Torus()
309
+ sage: H = Hom(S1, T)
310
+ sage: latex(H)
311
+ \operatorname{Map} (S^{1}, S^{1} \times S^{1})
312
+ """
313
+ return '\\operatorname{{Map}} ({}, {})'.format(latex(self.domain()), latex(self.codomain()))
314
+
315
+
316
+ class SimplicialSetMorphism(Morphism):
317
+ def __init__(self, data=None, domain=None, codomain=None,
318
+ constant=None, identity=False, check=True):
319
+ r"""
320
+ Return a morphism of simplicial sets.
321
+
322
+ INPUT:
323
+
324
+ - ``data`` -- (optional) dictionary defining the map
325
+ - ``domain`` -- simplicial set
326
+ - ``codomain`` -- simplicial set
327
+ - ``constant`` -- (default: ``None``) if not ``None``, then this should
328
+ be a vertex in the codomain, in which case return the
329
+ constant map with this vertex as the target
330
+ - ``identity`` -- boolean (default: ``False``); if ``True``, return the
331
+ identity morphism
332
+ - ``check`` -- boolean (default: ``True``); if ``True``, check
333
+ that this is actually a morphism: it commutes with the face maps
334
+
335
+ So to define a map, you must specify ``domain`` and
336
+ ``codomain``. If the map is constant, specify the target (a
337
+ vertex in the codomain) as ``constant``. If the map is the
338
+ identity map, specify ``identity=True``. Otherwise, pass a
339
+ dictionary, ``data``. The keys of the dictionary are the
340
+ nondegenerate simplices of the domain, the corresponding
341
+ values are simplices in the codomain.
342
+
343
+ In fact, the keys in ``data`` do not need to include all of
344
+ the nondegenerate simplices, only those which are not faces of
345
+ other nondegenerate simplices: if `\sigma` is a face of
346
+ `\tau`, then the image of `\sigma` need not be specified.
347
+
348
+ EXAMPLES::
349
+
350
+ sage: from sage.topology.simplicial_set_morphism import SimplicialSetMorphism
351
+ sage: K = simplicial_sets.Simplex(1)
352
+ sage: S1 = simplicial_sets.Sphere(1)
353
+ sage: v0 = K.n_cells(0)[0]
354
+ sage: v1 = K.n_cells(0)[1]
355
+ sage: e01 = K.n_cells(1)[0]
356
+ sage: w = S1.n_cells(0)[0]
357
+ sage: sigma = S1.n_cells(1)[0]
358
+
359
+ sage: f = {v0: w, v1: w, e01: sigma}
360
+ sage: SimplicialSetMorphism(f, K, S1)
361
+ Simplicial set morphism:
362
+ From: 1-simplex
363
+ To: S^1
364
+ Defn: [(0,), (1,), (0, 1)] --> [v_0, v_0, sigma_1]
365
+
366
+ The same map can be defined as follows::
367
+
368
+ sage: H = Hom(K, S1)
369
+ sage: H(f)
370
+ Simplicial set morphism:
371
+ From: 1-simplex
372
+ To: S^1
373
+ Defn: [(0,), (1,), (0, 1)] --> [v_0, v_0, sigma_1]
374
+
375
+ Also, this map can be defined by specifying where the
376
+ 1-simplex goes; the vertices then go where they have to, to
377
+ satisfy the condition `d_i \circ f = f \circ d_i`::
378
+
379
+ sage: H = Hom(K, S1)
380
+ sage: H({e01: sigma})
381
+ Simplicial set morphism:
382
+ From: 1-simplex
383
+ To: S^1
384
+ Defn: [(0,), (1,), (0, 1)] --> [v_0, v_0, sigma_1]
385
+
386
+ A constant map::
387
+
388
+ sage: g = {e01: w.apply_degeneracies(0)}
389
+ sage: SimplicialSetMorphism(g, K, S1)
390
+ Simplicial set morphism:
391
+ From: 1-simplex
392
+ To: S^1
393
+ Defn: Constant map at v_0
394
+
395
+ The same constant map::
396
+
397
+ sage: SimplicialSetMorphism(domain=K, codomain=S1, constant=w)
398
+ Simplicial set morphism:
399
+ From: 1-simplex
400
+ To: S^1
401
+ Defn: Constant map at v_0
402
+
403
+ An identity map::
404
+
405
+ sage: SimplicialSetMorphism(domain=K, codomain=K, identity=True)
406
+ Simplicial set endomorphism of 1-simplex
407
+ Defn: Identity map
408
+
409
+ Defining a map by specifying it on only some of the simplices
410
+ in the domain::
411
+
412
+ sage: S5 = simplicial_sets.Sphere(5)
413
+ sage: s = S5.n_cells(5)[0]
414
+ sage: one = S5.Hom(S5)({s: s})
415
+ sage: one
416
+ Simplicial set endomorphism of S^5
417
+ Defn: Identity map
418
+
419
+ TESTS:
420
+
421
+ A non-map::
422
+
423
+ sage: h = {w: v0, sigma: e01}
424
+ sage: SimplicialSetMorphism(h, S1, K)
425
+ Traceback (most recent call last):
426
+ ...
427
+ ValueError: the dictionary does not define a map of simplicial sets
428
+
429
+ Another non-map::
430
+
431
+ sage: h = {w: v0, v0: w, sigma: e01}
432
+ sage: SimplicialSetMorphism(h, S1, K)
433
+ Traceback (most recent call last):
434
+ ...
435
+ ValueError: at least one simplex in the defining dictionary is not in the domain
436
+
437
+ A non-identity map::
438
+
439
+ sage: SimplicialSetMorphism(domain=K, codomain=S1, identity=True)
440
+ Traceback (most recent call last):
441
+ ...
442
+ TypeError: identity map is only defined for endomorphism sets
443
+
444
+ An improperly partially defined map::
445
+
446
+ sage: h = {w: v0}
447
+ sage: SimplicialSetMorphism(h, S1, K)
448
+ Traceback (most recent call last):
449
+ ...
450
+ ValueError: the image of at least one simplex in the domain is not defined
451
+ """
452
+ self._is_identity = False
453
+ if not domain.is_finite():
454
+ if identity:
455
+ if codomain is None:
456
+ codomain = domain
457
+ elif domain is not codomain:
458
+ raise TypeError("identity map is only defined for endomorphism sets")
459
+ self._is_identity = True
460
+ Morphism.__init__(self, Hom(domain, codomain, SimplicialSets()))
461
+ return
462
+ if constant is not None:
463
+ # If self._constant is set, it should be a vertex in
464
+ # the codomain, the target of the constant map.
465
+ self._constant = constant
466
+ Morphism.__init__(self, Hom(domain, codomain, SimplicialSets()))
467
+ return
468
+ raise NotImplementedError('morphisms with infinite domain '
469
+ 'are not implemented in general')
470
+ else:
471
+ if identity:
472
+ self._is_identity = True
473
+ check = False
474
+ if domain is not codomain:
475
+ raise TypeError("identity map is only defined for endomorphism sets")
476
+ data = {}
477
+ for i in range(domain.dimension() + 1):
478
+ for s in domain.n_cells(i):
479
+ data[s] = s
480
+ if constant is not None:
481
+ self._constant = constant
482
+ check = False
483
+ data = {sigma: constant.apply_degeneracies(*range(sigma.dimension()-1, -1, -1))
484
+ for sigma in domain.nondegenerate_simplices()}
485
+
486
+ if (not isinstance(domain, SimplicialSet_arbitrary)
487
+ or not isinstance(codomain, SimplicialSet_arbitrary)):
488
+ raise TypeError('the domain and codomain must be simplicial sets')
489
+ if any(x.nondegenerate() not in
490
+ domain.nondegenerate_simplices() for x in data.keys()):
491
+ raise ValueError('at least one simplex in the defining '
492
+ 'dictionary is not in the domain')
493
+ # Remove degenerate simplices from the domain specification.
494
+ d = {sigma: data[sigma] for sigma in data if sigma.is_nondegenerate()}
495
+ # For each simplex in d.keys(), add its faces, and the faces
496
+ # of its faces, etc., to d.
497
+ for simplex in list(d):
498
+ faces = domain.faces(simplex)
499
+ add = []
500
+ if faces:
501
+ for (i, sigma) in enumerate(faces):
502
+ nondegen = sigma.nondegenerate()
503
+ if nondegen not in d:
504
+ add.append((sigma, i, simplex))
505
+ while add:
506
+ (sigma, i, tau) = add.pop()
507
+ # sigma is the ith face of tau.
508
+ face_f = codomain.face(d[tau], i)
509
+ degens = sigma.degeneracies()
510
+ x = face_f
511
+ for j in degens:
512
+ x = codomain.face(x, j)
513
+ d[sigma.nondegenerate()] = x
514
+ faces = domain.faces(sigma.nondegenerate())
515
+ if faces:
516
+ for i, rho in enumerate(faces):
517
+ nondegen = rho.nondegenerate()
518
+ if nondegen not in d:
519
+ add.append((rho, i, sigma))
520
+ # Now check that the proposed map commutes with the face
521
+ # maps. (The degeneracy maps should work automatically.)
522
+ if check:
523
+ for simplex in d:
524
+ # Compare d[d_i (simplex)] to d_i d[simplex]. Since
525
+ # d_i(simplex) may be degenerate, we have to be careful
526
+ # when applying f to it. We can skip vertices and start
527
+ # with 1-simplices.
528
+ bad = False
529
+ for i in range(simplex.dimension()+1):
530
+ face_f = codomain.face(d[simplex], i)
531
+ face = domain.face(simplex, i)
532
+ if face is None:
533
+ f_face = None
534
+ elif face.is_nondegenerate():
535
+ f_face = d[face]
536
+ else:
537
+ nondegen = face.nondegenerate()
538
+ f_face = d[nondegen].apply_degeneracies(*face.degeneracies())
539
+ if face_f != f_face:
540
+ bad = True
541
+ break
542
+ if bad:
543
+ raise ValueError('the dictionary does not define a map of simplicial sets')
544
+ if any(x not in d.keys() for x in domain.nondegenerate_simplices()):
545
+ raise ValueError('the image of at least one simplex in '
546
+ 'the domain is not defined')
547
+ self._dictionary = d
548
+ Morphism.__init__(self, Hom(domain, codomain, SimplicialSets()))
549
+
550
+ def __eq__(self, other):
551
+ """
552
+ Two morphisms are equal iff their domains are the same, their
553
+ codomains are the same, and their defining dictionaries are
554
+ the same.
555
+
556
+ EXAMPLES::
557
+
558
+ sage: S = simplicial_sets.Sphere(1)
559
+ sage: T = simplicial_sets.Torus()
560
+ sage: T_c = T.constant_map() * T.base_point_map()
561
+ sage: S_c = S.constant_map() * S.base_point_map()
562
+ sage: T_c == S_c
563
+ True
564
+ sage: T.constant_map() == S.constant_map()
565
+ False
566
+ sage: K = simplicial_sets.Sphere(1)
567
+ sage: K.constant_map() == S.constant_map()
568
+ False
569
+
570
+ sage: Point = simplicial_sets.Point()
571
+ sage: f = Point._map_from_empty_set()
572
+ sage: Empty = f.domain()
573
+ sage: g = Empty.constant_map()
574
+ sage: f == g
575
+ True
576
+ """
577
+ if self.domain().is_finite() and other.domain().is_finite():
578
+ return (self.domain() == other.domain()
579
+ and self.codomain() == other.codomain()
580
+ and self._dictionary == other._dictionary)
581
+ else:
582
+ return False
583
+
584
+ def __ne__(self, other):
585
+ """
586
+ The negation of ``__eq__``.
587
+
588
+ EXAMPLES::
589
+
590
+ sage: S0 = simplicial_sets.Sphere(0)
591
+ sage: v,w = S0.n_cells(0)
592
+ sage: H = Hom(S0, S0)
593
+ sage: H({v:v, w:w}) != H({v:w, w:v})
594
+ True
595
+ sage: H({v:v, w:w}) != H({w:w, v:v})
596
+ False
597
+ """
598
+ return not self == other
599
+
600
+ def __call__(self, x):
601
+ """
602
+ Return the image of ``x`` under this morphism.
603
+
604
+ INPUT:
605
+
606
+ - ``x`` -- a simplex of the domain
607
+
608
+ EXAMPLES::
609
+
610
+ sage: K = simplicial_sets.Simplex(1)
611
+ sage: S1 = simplicial_sets.Sphere(1)
612
+ sage: v0 = K.n_cells(0)[0]
613
+ sage: v1 = K.n_cells(0)[1]
614
+ sage: e01 = K.n_cells(1)[0]
615
+ sage: w = S1.n_cells(0)[0]
616
+ sage: sigma = S1.n_cells(1)[0]
617
+ sage: d = {v0: w, v1: w, e01: sigma}
618
+ sage: f = Hom(K, S1)(d)
619
+ sage: f(e01) # indirect doctest
620
+ sigma_1
621
+
622
+ sage: one = Hom(S1, S1).identity()
623
+ sage: e = S1.n_cells(1)[0]
624
+ sage: one(e) == e
625
+ True
626
+
627
+ sage: B = AbelianGroup([2]).nerve() # needs sage.groups
628
+ sage: c = B.constant_map() # needs sage.groups
629
+ sage: c(B.n_cells(2)[0]) # needs sage.groups
630
+ s_1 s_0 *
631
+ """
632
+ if x not in self.domain():
633
+ raise ValueError('element is not a simplex in the domain')
634
+ if self.is_constant():
635
+ target = self._constant
636
+ return target.apply_degeneracies(*range(x.dimension()-1, -1, -1))
637
+ if self._is_identity:
638
+ return x
639
+ return self._dictionary[x.nondegenerate()].apply_degeneracies(*x.degeneracies())
640
+
641
+ def _composition_(self, right, homset):
642
+ """
643
+ Return the composition of two morphisms.
644
+
645
+ INPUT:
646
+
647
+ - ``self``, ``right`` -- maps
648
+ - ``homset`` -- a homset
649
+
650
+ ASSUMPTION:
651
+
652
+ The codomain of ``right`` is contained in the domain of
653
+ ``self``. This assumption should be verified by the
654
+ ``Map.__mul__`` method in ``categories/map.pyx``, so we don't
655
+ need to check it here.
656
+
657
+ EXAMPLES::
658
+
659
+ sage: S1 = simplicial_sets.Sphere(1)
660
+ sage: f = S1.Hom(S1).identity()
661
+ sage: f * f # indirect doctest
662
+ Simplicial set endomorphism of S^1
663
+ Defn: Identity map
664
+ sage: T = S1.product(S1)
665
+ sage: K = T.factor(0, as_subset=True)
666
+ sage: g = S1.Hom(T)({S1.n_cells(0)[0]:K.n_cells(0)[0], S1.n_cells(1)[0]:K.n_cells(1)[0]})
667
+ sage: g
668
+ Simplicial set morphism:
669
+ From: S^1
670
+ To: S^1 x S^1
671
+ Defn: [v_0, sigma_1] --> [(v_0, v_0), (sigma_1, s_0 v_0)]
672
+ sage: (g*f).image()
673
+ Simplicial set with 2 non-degenerate simplices
674
+ sage: f.image().homology() # needs sage.modules
675
+ {0: 0, 1: Z}
676
+ """
677
+ if self.is_identity():
678
+ return right
679
+ if right.is_identity():
680
+ return self
681
+ d = {}
682
+ for sigma in right._dictionary:
683
+ d[sigma] = self(right(sigma))
684
+ return homset(d)
685
+
686
+ def image(self):
687
+ """
688
+ Return the image of this morphism as a subsimplicial set of the
689
+ codomain.
690
+
691
+ EXAMPLES::
692
+
693
+ sage: S1 = simplicial_sets.Sphere(1)
694
+ sage: T = S1.product(S1)
695
+ sage: K = T.factor(0, as_subset=True)
696
+ sage: f = S1.Hom(T)({S1.n_cells(0)[0]: K.n_cells(0)[0],
697
+ ....: S1.n_cells(1)[0]: K.n_cells(1)[0]}); f
698
+ Simplicial set morphism:
699
+ From: S^1
700
+ To: S^1 x S^1
701
+ Defn: [v_0, sigma_1] --> [(v_0, v_0), (sigma_1, s_0 v_0)]
702
+ sage: f.image()
703
+ Simplicial set with 2 non-degenerate simplices
704
+ sage: f.image().homology() # needs sage.modules
705
+ {0: 0, 1: Z}
706
+
707
+ sage: # needs sage.groups
708
+ sage: G = groups.misc.MultiplicativeAbelian([2])
709
+ sage: B = simplicial_sets.ClassifyingSpace(G)
710
+ sage: B.constant_map().image()
711
+ Point
712
+ sage: Hom(B,B).identity().image() == B
713
+ True
714
+ """
715
+ if self._is_identity:
716
+ return self.codomain()
717
+ if self.is_constant():
718
+ return self.codomain().subsimplicial_set([self._constant])
719
+ simplices = self._dictionary.values()
720
+ if set(simplices) == set(self.codomain().nondegenerate_simplices()):
721
+ return self.codomain()
722
+ return self.codomain().subsimplicial_set(simplices)
723
+
724
+ def is_identity(self):
725
+ """
726
+ Return ``True`` if this morphism is an identity map.
727
+
728
+ EXAMPLES::
729
+
730
+ sage: K = simplicial_sets.Simplex(1)
731
+ sage: v0 = K.n_cells(0)[0]
732
+ sage: v1 = K.n_cells(0)[1]
733
+ sage: e01 = K.n_cells(1)[0]
734
+ sage: L = simplicial_sets.Simplex(2).n_skeleton(1)
735
+ sage: w0 = L.n_cells(0)[0]
736
+ sage: w1 = L.n_cells(0)[1]
737
+ sage: w2 = L.n_cells(0)[2]
738
+ sage: f01 = L.n_cells(1)[0]
739
+ sage: f02 = L.n_cells(1)[1]
740
+ sage: f12 = L.n_cells(1)[2]
741
+
742
+ sage: d = {v0:w0, v1:w1, e01:f01}
743
+ sage: f = K.Hom(L)(d)
744
+ sage: f.is_identity()
745
+ False
746
+ sage: d = {w0:v0, w1:v1, w2:v1, f01:e01, f02:e01, f12: v1.apply_degeneracies(0,)}
747
+ sage: g = L.Hom(K)(d)
748
+ sage: (g*f).is_identity()
749
+ True
750
+ sage: (f*g).is_identity()
751
+ False
752
+ sage: (f*g).induced_homology_morphism().to_matrix(1) # needs sage.modules
753
+ [0]
754
+
755
+ sage: RP5 = simplicial_sets.RealProjectiveSpace(5) # needs sage.groups
756
+ sage: RP5.n_skeleton(2).inclusion_map().is_identity() # needs sage.groups
757
+ False
758
+ sage: RP5.n_skeleton(5).inclusion_map().is_identity() # needs sage.groups
759
+ True
760
+
761
+ sage: # needs sage.groups
762
+ sage: G = groups.misc.MultiplicativeAbelian([2])
763
+ sage: B = simplicial_sets.ClassifyingSpace(G)
764
+ sage: Hom(B,B).identity().is_identity()
765
+ True
766
+ sage: Hom(B,B).constant_map().is_identity()
767
+ False
768
+ """
769
+ ans = (self._is_identity or
770
+ (self.domain() == self.codomain()
771
+ and self.domain().is_finite()
772
+ and all(a == b for a, b in self._dictionary.items())))
773
+ self._is_identity = ans
774
+ return ans
775
+
776
+ def is_surjective(self):
777
+ """
778
+ Return ``True`` if this map is surjective.
779
+
780
+ EXAMPLES::
781
+
782
+ sage: RP5 = simplicial_sets.RealProjectiveSpace(5) # needs sage.groups
783
+ sage: RP2 = RP5.n_skeleton(2) # needs sage.groups
784
+ sage: RP2.inclusion_map().is_surjective() # needs sage.groups
785
+ False
786
+
787
+ sage: RP5_2 = RP5.quotient(RP2) # needs sage.groups
788
+ sage: RP5_2.quotient_map().is_surjective() # needs sage.groups
789
+ True
790
+
791
+ sage: K = RP5_2.pullback(RP5_2.quotient_map(), RP5_2.base_point_map()) # needs sage.groups
792
+ sage: f = K.universal_property(RP2.inclusion_map(), RP2.constant_map()) # needs sage.groups
793
+ sage: f.is_surjective() # needs sage.groups
794
+ True
795
+ """
796
+ return self._is_identity or self.image() == self.codomain()
797
+
798
+ def is_injective(self):
799
+ """
800
+ Return ``True`` if this map is injective.
801
+
802
+ EXAMPLES::
803
+
804
+ sage: RP5 = simplicial_sets.RealProjectiveSpace(5) # needs sage.groups
805
+ sage: RP2 = RP5.n_skeleton(2) # needs sage.groups
806
+ sage: RP2.inclusion_map().is_injective() # needs sage.groups
807
+ True
808
+
809
+ sage: RP5_2 = RP5.quotient(RP2) # needs sage.groups
810
+ sage: RP5_2.quotient_map().is_injective() # needs sage.groups
811
+ False
812
+
813
+ sage: K = RP5_2.pullback(RP5_2.quotient_map(), RP5_2.base_point_map()) # needs sage.groups
814
+ sage: f = K.universal_property(RP2.inclusion_map(), RP2.constant_map()) # needs sage.groups
815
+ sage: f.is_injective() # needs sage.groups
816
+ True
817
+ """
818
+ if self._is_identity:
819
+ return True
820
+ domain = self.domain()
821
+ for n in range(domain.dimension() + 1):
822
+ domain_cells = domain.n_cells(n)
823
+ output = {self(sigma) for sigma in domain_cells
824
+ if self(sigma).is_nondegenerate()}
825
+ if len(domain_cells) > len(output):
826
+ return False
827
+ return True
828
+
829
+ def is_bijective(self):
830
+ """
831
+ Return ``True`` if this map is bijective.
832
+
833
+ EXAMPLES::
834
+
835
+ sage: RP5 = simplicial_sets.RealProjectiveSpace(5) # needs sage.groups
836
+ sage: RP2 = RP5.n_skeleton(2) # needs sage.groups
837
+ sage: RP2.inclusion_map().is_bijective() # needs sage.groups
838
+ False
839
+
840
+ sage: RP5_2 = RP5.quotient(RP2) # needs sage.groups
841
+ sage: RP5_2.quotient_map().is_bijective() # needs sage.groups
842
+ False
843
+
844
+ sage: K = RP5_2.pullback(RP5_2.quotient_map(), RP5_2.base_point_map()) # needs sage.groups
845
+ sage: f = K.universal_property(RP2.inclusion_map(), RP2.constant_map()) # needs sage.groups
846
+ sage: f.is_bijective() # needs sage.groups
847
+ True
848
+ """
849
+ return self.is_injective() and self.is_surjective()
850
+
851
+ def is_pointed(self):
852
+ """
853
+ Return ``True`` if this is a pointed map.
854
+
855
+ That is, return ``True`` if the domain and codomain are
856
+ pointed and this morphism preserves the base point.
857
+
858
+ EXAMPLES::
859
+
860
+ sage: S0 = simplicial_sets.Sphere(0)
861
+ sage: f = Hom(S0,S0).identity()
862
+ sage: f.is_pointed()
863
+ True
864
+ sage: v = S0.n_cells(0)[0]
865
+ sage: w = S0.n_cells(0)[1]
866
+ sage: g = Hom(S0,S0)({v:v, w:v})
867
+ sage: g.is_pointed()
868
+ True
869
+ sage: t = Hom(S0,S0)({v:w, w:v})
870
+ sage: t.is_pointed()
871
+ False
872
+ """
873
+ return (self.domain().is_pointed() and self.codomain().is_pointed()
874
+ and self(self.domain().base_point()) == self.codomain().base_point())
875
+
876
+ def is_constant(self):
877
+ """
878
+ Return ``True`` if this morphism is a constant map.
879
+
880
+ EXAMPLES::
881
+
882
+ sage: K = simplicial_sets.KleinBottle()
883
+ sage: S4 = simplicial_sets.Sphere(4)
884
+ sage: c = Hom(K, S4).constant_map()
885
+ sage: c.is_constant()
886
+ True
887
+ sage: X = S4.n_skeleton(3) # a point
888
+ sage: X.inclusion_map().is_constant()
889
+ True
890
+ sage: eta = simplicial_sets.HopfMap()
891
+ sage: eta.is_constant()
892
+ False
893
+ """
894
+ try:
895
+ return self._constant is not None
896
+ except AttributeError:
897
+ pass
898
+ if not self.domain().is_finite():
899
+ # The domain is infinite, so there is no safe way to
900
+ # determine if the map is constant.
901
+ return False
902
+ targets = [tau.nondegenerate() for tau in self._dictionary.values()]
903
+ if len(set(targets)) == 1:
904
+ # It's constant, so save the target.
905
+ self._constant = targets[0]
906
+ return True
907
+ return False
908
+
909
+ def pushout(self, *others):
910
+ """
911
+ Return the pushout of this morphism along with ``others``.
912
+
913
+ INPUT:
914
+
915
+ - ``others`` -- morphisms of simplicial sets, the domains of
916
+ which must all equal that of ``self``
917
+
918
+ This returns the pushout as a simplicial set. See
919
+ :class:`sage.topology.simplicial_set_constructions.PushoutOfSimplicialSets`
920
+ for more documentation and examples.
921
+
922
+ EXAMPLES::
923
+
924
+ sage: T = simplicial_sets.Torus()
925
+ sage: K = simplicial_sets.KleinBottle()
926
+ sage: init_T = T._map_from_empty_set()
927
+ sage: init_K = K._map_from_empty_set()
928
+ sage: D = init_T.pushout(init_K); D # the disjoint union as a pushout
929
+ Pushout of maps:
930
+ Simplicial set morphism:
931
+ From: Empty simplicial set
932
+ To: Torus
933
+ Defn: [] --> []
934
+ Simplicial set morphism:
935
+ From: Empty simplicial set
936
+ To: Klein bottle
937
+ Defn: [] --> []
938
+ """
939
+ domain = self.domain()
940
+ if any(domain != f.domain() for f in others):
941
+ raise ValueError('the domains of the maps must be equal')
942
+ return self.domain().pushout(*(self,) + others)
943
+
944
+ def pullback(self, *others):
945
+ """
946
+ Return the pullback of this morphism along with ``others``.
947
+
948
+ INPUT:
949
+
950
+ - ``others`` -- morphisms of simplicial sets, the codomains of
951
+ which must all equal that of ``self``
952
+
953
+ This returns the pullback as a simplicial set. See
954
+ :class:`sage.topology.simplicial_set_constructions.PullbackOfSimplicialSets`
955
+ for more documentation and examples.
956
+
957
+ EXAMPLES::
958
+
959
+ sage: T = simplicial_sets.Torus()
960
+ sage: K = simplicial_sets.KleinBottle()
961
+ sage: term_T = T.constant_map()
962
+ sage: term_K = K.constant_map()
963
+ sage: P = term_T.pullback(term_K); P # the product as a pullback
964
+ Pullback of maps:
965
+ Simplicial set morphism:
966
+ From: Torus
967
+ To: Point
968
+ Defn: Constant map at *
969
+ Simplicial set morphism:
970
+ From: Klein bottle
971
+ To: Point
972
+ Defn: Constant map at *
973
+ """
974
+ codomain = self.codomain()
975
+ if any(codomain != f.codomain() for f in others):
976
+ raise ValueError('the codomains of the maps must be equal')
977
+ return self.codomain().pullback(*(self,) + others)
978
+
979
+ def equalizer(self, other):
980
+ r"""
981
+ Return the equalizer of this map with ``other``.
982
+
983
+ INPUT:
984
+
985
+ - ``other`` -- a morphism with the same domain and codomain as this map
986
+
987
+ If the two maps are `f, g: X \to Y`, then the equalizer `P` is
988
+ constructed as the pullback ::
989
+
990
+ P ----> X
991
+ | |
992
+ V V
993
+ X --> X x Y
994
+
995
+ where the two maps `X \to X \times Y` are `(1,f)` and `(1,g)`.
996
+
997
+ EXAMPLES::
998
+
999
+ sage: from sage.topology.simplicial_set import AbstractSimplex, SimplicialSet
1000
+ sage: v = AbstractSimplex(0, name='v')
1001
+ sage: w = AbstractSimplex(0, name='w')
1002
+ sage: x = AbstractSimplex(0, name='x')
1003
+ sage: evw = AbstractSimplex(1, name='vw')
1004
+ sage: evx = AbstractSimplex(1, name='vx')
1005
+ sage: ewx = AbstractSimplex(1, name='wx')
1006
+ sage: X = SimplicialSet({evw: (w, v), evx: (x, v)})
1007
+ sage: Y = SimplicialSet({evw: (w, v), evx: (x, v), ewx: (x, w)})
1008
+
1009
+ Here `X` is a wedge of two 1-simplices (a horn, that is), and
1010
+ `Y` is the boundary of a 2-simplex. The map `f` includes the
1011
+ two 1-simplices into `Y`, while the map `g` maps both
1012
+ 1-simplices to the same edge in `Y`. ::
1013
+
1014
+ sage: f = Hom(X, Y)({v:v, w:w, x:x, evw:evw, evx:evx})
1015
+ sage: g = Hom(X, Y)({v:v, w:x, x:x, evw:evx, evx:evx})
1016
+ sage: P = f.equalizer(g)
1017
+ sage: P
1018
+ Pullback of maps:
1019
+ Simplicial set morphism:
1020
+ From: Simplicial set with 5 non-degenerate simplices
1021
+ To: Simplicial set with 5 non-degenerate simplices x Simplicial set with 6 non-degenerate simplices
1022
+ Defn: [v, w, x, vw, vx] --> [(v, v), (w, w), (x, x), (vw, vw), (vx, vx)]
1023
+ Simplicial set morphism:
1024
+ From: Simplicial set with 5 non-degenerate simplices
1025
+ To: Simplicial set with 5 non-degenerate simplices x Simplicial set with 6 non-degenerate simplices
1026
+ Defn: [v, w, x, vw, vx] --> [(v, v), (w, x), (x, x), (vw, vx), (vx, vx)]
1027
+ """
1028
+ domain = self.domain()
1029
+ codomain = self.codomain()
1030
+ if domain != other.domain() or codomain != other.codomain():
1031
+ raise ValueError('the maps must have the same domain and the same codomain')
1032
+ prod = domain.product(codomain)
1033
+ one = domain.Hom(domain).identity()
1034
+ f = prod.universal_property(one, self)
1035
+ g = prod.universal_property(one, other)
1036
+ return f.pullback(g)
1037
+
1038
+ def coequalizer(self, other):
1039
+ r"""
1040
+ Return the coequalizer of this map with ``other``.
1041
+
1042
+ INPUT:
1043
+
1044
+ - ``other`` -- a morphism with the same domain and codomain as this map
1045
+
1046
+ If the two maps are `f, g: X \to Y`, then the coequalizer `P` is
1047
+ constructed as the pushout ::
1048
+
1049
+ X v Y --> Y
1050
+ | |
1051
+ V V
1052
+ Y ----> P
1053
+
1054
+ where the upper left corner is the coproduct of `X` and `Y`
1055
+ (the wedge if they are pointed, the disjoint union otherwise),
1056
+ and the two maps `X \amalg Y \to Y` are `f \amalg 1` and `g
1057
+ \amalg 1`.
1058
+
1059
+ EXAMPLES::
1060
+
1061
+ sage: L = simplicial_sets.Simplex(2)
1062
+ sage: pt = L.n_cells(0)[0]
1063
+ sage: e = L.n_cells(1)[0]
1064
+ sage: K = L.subsimplicial_set([e])
1065
+ sage: f = K.inclusion_map()
1066
+ sage: v,w = K.n_cells(0)
1067
+ sage: g = Hom(K,L)({v:pt, w:pt, e:pt.apply_degeneracies(0)})
1068
+ sage: P = f.coequalizer(g); P
1069
+ Pushout of maps:
1070
+ Simplicial set morphism:
1071
+ From: Disjoint union: (Simplicial set with 3 non-degenerate simplices u 2-simplex)
1072
+ To: 2-simplex
1073
+ Defn: ...
1074
+ Simplicial set morphism:
1075
+ From: Disjoint union: (Simplicial set with 3 non-degenerate simplices u 2-simplex)
1076
+ To: 2-simplex
1077
+ Defn: ...
1078
+ """
1079
+ domain = self.domain()
1080
+ codomain = self.codomain()
1081
+ if domain != other.domain() or codomain != other.codomain():
1082
+ raise ValueError('the maps must have the same domain and the same codomain')
1083
+ coprod = domain.coproduct(codomain)
1084
+ one = codomain.Hom(codomain).identity()
1085
+ f = coprod.universal_property(self, one)
1086
+ g = coprod.universal_property(other, one)
1087
+ return f.pushout(g)
1088
+
1089
+ def mapping_cone(self):
1090
+ r"""
1091
+ Return the mapping cone defined by this map.
1092
+
1093
+ EXAMPLES::
1094
+
1095
+ sage: S1 = simplicial_sets.Sphere(1)
1096
+ sage: v_0, sigma_1 = S1.nondegenerate_simplices()
1097
+ sage: K = simplicial_sets.Simplex(2).n_skeleton(1)
1098
+
1099
+ The mapping cone will be a little smaller if we use only
1100
+ pointed simplicial sets. `S^1` is already pointed, but not
1101
+ `K`. ::
1102
+
1103
+ sage: L = K.set_base_point(K.n_cells(0)[0])
1104
+ sage: u,v,w = L.n_cells(0)
1105
+ sage: e,f,g = L.n_cells(1)
1106
+ sage: h = L.Hom(S1)({u:v_0, v:v_0, w:v_0, e:sigma_1,
1107
+ ....: f:v_0.apply_degeneracies(0), g:sigma_1})
1108
+ sage: h
1109
+ Simplicial set morphism:
1110
+ From: Simplicial set with 6 non-degenerate simplices
1111
+ To: S^1
1112
+ Defn: [(0,), (1,), (2,), (0, 1), (0, 2), (1, 2)]
1113
+ --> [v_0, v_0, v_0, sigma_1, s_0 v_0, sigma_1]
1114
+ sage: h.induced_homology_morphism().to_matrix() # needs sage.modules
1115
+ [1|0]
1116
+ [-+-]
1117
+ [0|2]
1118
+ sage: X = h.mapping_cone()
1119
+ sage: X.homology() == simplicial_sets.RealProjectiveSpace(2).homology() # needs sage.groups sage.modules
1120
+ True
1121
+ """
1122
+ dom = self.domain()
1123
+ cone = dom.cone()
1124
+ i = cone.map_from_base()
1125
+ return self.pushout(i)
1126
+
1127
+ def product(self, *others):
1128
+ r"""
1129
+ Return the product of this map with ``others``.
1130
+
1131
+ - ``others`` -- morphisms of simplicial sets
1132
+
1133
+ If the relevant maps are `f_i: X_i \to Y_i`, this returns the
1134
+ natural map `\prod X_i \to \prod Y_i`.
1135
+
1136
+ EXAMPLES::
1137
+
1138
+ sage: S1 = simplicial_sets.Sphere(1)
1139
+ sage: f = Hom(S1,S1).identity()
1140
+ sage: f.product(f).is_bijective()
1141
+ True
1142
+ sage: g = S1.constant_map(S1)
1143
+ sage: g.product(g).is_bijective()
1144
+ False
1145
+ """
1146
+ domain = self.domain().product(*[g.domain() for g in others])
1147
+ codomain = self.codomain().product(*[g.codomain() for g in others])
1148
+ factors = []
1149
+ for i, f in enumerate([self] + list(others)):
1150
+ factors.append(f * domain.projection_map(i))
1151
+ return codomain.universal_property(*factors)
1152
+
1153
+ def coproduct(self, *others):
1154
+ r"""
1155
+ Return the coproduct of this map with ``others``.
1156
+
1157
+ - ``others`` -- morphisms of simplicial sets
1158
+
1159
+ If the relevant maps are `f_i: X_i \to Y_i`, this returns the
1160
+ natural map `\amalg X_i \to \amalg Y_i`.
1161
+
1162
+ EXAMPLES::
1163
+
1164
+ sage: S1 = simplicial_sets.Sphere(1)
1165
+ sage: f = Hom(S1,S1).identity()
1166
+ sage: f.coproduct(f).is_bijective()
1167
+ True
1168
+ sage: g = S1.constant_map(S1)
1169
+ sage: g.coproduct(g).is_bijective()
1170
+ False
1171
+ """
1172
+ codomain = self.codomain().coproduct(*[g.codomain() for g in others])
1173
+ factors = []
1174
+ for i, f in enumerate([self] + list(others)):
1175
+ factors.append(codomain.inclusion_map(i) * f)
1176
+ return codomain.universal_property(*factors)
1177
+
1178
+ def suspension(self, n=1):
1179
+ """
1180
+ Return the `n`-th suspension of this morphism of simplicial sets.
1181
+
1182
+ INPUT:
1183
+
1184
+ - ``n`` -- nonnegative integer (default: 1)
1185
+
1186
+ EXAMPLES::
1187
+
1188
+ sage: eta = simplicial_sets.HopfMap()
1189
+ sage: mc_susp_eta = eta.suspension().mapping_cone()
1190
+ sage: susp_mc_eta = eta.mapping_cone().suspension()
1191
+ sage: mc_susp_eta.homology() == susp_mc_eta.homology() # needs sage.modules
1192
+ True
1193
+
1194
+ This uses reduced suspensions if the original morphism is
1195
+ pointed, unreduced otherwise. So for example, if a constant
1196
+ map is not pointed, its suspension is not a constant map::
1197
+
1198
+ sage: L = simplicial_sets.Simplex(1)
1199
+ sage: L.constant_map().is_pointed()
1200
+ False
1201
+ sage: f = L.constant_map().suspension()
1202
+ sage: f.is_constant()
1203
+ False
1204
+
1205
+ sage: K = simplicial_sets.Sphere(3)
1206
+ sage: K.constant_map().is_pointed()
1207
+ True
1208
+ sage: g = K.constant_map().suspension()
1209
+ sage: g.is_constant()
1210
+ True
1211
+
1212
+ sage: h = K.identity().suspension()
1213
+ sage: h.is_identity()
1214
+ True
1215
+ """
1216
+ domain = self.domain()
1217
+ codomain = self.codomain()
1218
+ if not self.is_pointed():
1219
+ # Make sure to use unreduced suspensions for both domain
1220
+ # and codomain.
1221
+ if domain.is_pointed():
1222
+ domain = domain.unset_base_point()
1223
+ if codomain.is_pointed():
1224
+ codomain = codomain.unset_base_point()
1225
+ f = self
1226
+ for i in range(n):
1227
+ new_dom = domain.suspension()
1228
+ new_cod = codomain.suspension()
1229
+ data = {new_dom.base_point(): new_cod.base_point()}
1230
+ for sigma in f._dictionary:
1231
+ target = f(sigma)
1232
+ underlying = target.nondegenerate()
1233
+ degens = target.degeneracies()
1234
+ data[new_dom._suspensions[sigma]] = new_cod._suspensions[underlying].apply_degeneracies(*degens)
1235
+ f = new_dom.Hom(new_cod)(data)
1236
+ domain = f.domain()
1237
+ codomain = f.codomain()
1238
+ return f
1239
+
1240
+ def n_skeleton(self, n, domain=None, codomain=None):
1241
+ """
1242
+ Return the restriction of this morphism to the n-skeleta of the
1243
+ domain and codomain
1244
+
1245
+ INPUT:
1246
+
1247
+ - ``n`` -- the dimension
1248
+
1249
+ - ``domain`` -- (optional) the domain. Specify this to
1250
+ explicitly specify the domain; otherwise, Sage will attempt
1251
+ to compute it. Specifying this can be useful if the domain
1252
+ is built as a pushout or pullback, so trying to compute it
1253
+ may lead to computing the `n`-skeleton of a map, causing an
1254
+ infinite recursion. (Users should not have to specify this,
1255
+ but it may be useful for developers.)
1256
+
1257
+ - ``codomain`` -- (optional) the codomain
1258
+
1259
+ EXAMPLES::
1260
+
1261
+ sage: # needs sage.groups
1262
+ sage: G = groups.misc.MultiplicativeAbelian([2])
1263
+ sage: B = simplicial_sets.ClassifyingSpace(G)
1264
+ sage: one = Hom(B,B).identity()
1265
+ sage: one.n_skeleton(3)
1266
+ Simplicial set endomorphism of Simplicial set with 4 non-degenerate simplices
1267
+ Defn: Identity map
1268
+ sage: c = Hom(B,B).constant_map()
1269
+ sage: c.n_skeleton(3)
1270
+ Simplicial set endomorphism of Simplicial set with 4 non-degenerate simplices
1271
+ Defn: Constant map at 1
1272
+
1273
+ sage: K = simplicial_sets.Simplex(2)
1274
+ sage: L = K.subsimplicial_set(K.n_cells(0)[:2])
1275
+ sage: L.nondegenerate_simplices()
1276
+ [(0,), (1,)]
1277
+ sage: L.inclusion_map()
1278
+ Simplicial set morphism:
1279
+ From: Simplicial set with 2 non-degenerate simplices
1280
+ To: 2-simplex
1281
+ Defn: [(0,), (1,)] --> [(0,), (1,)]
1282
+ sage: L.inclusion_map().n_skeleton(1)
1283
+ Simplicial set morphism:
1284
+ From: Simplicial set with 2 non-degenerate simplices
1285
+ To: Simplicial set with 6 non-degenerate simplices
1286
+ Defn: [(0,), (1,)] --> [(0,), (1,)]
1287
+ """
1288
+ if domain is None:
1289
+ domain = self.domain().n_skeleton(n)
1290
+ if codomain is None:
1291
+ codomain = self.codomain().n_skeleton(n)
1292
+ if self.is_constant():
1293
+ return Hom(domain, codomain).constant_map(self._constant)
1294
+ if self.is_identity():
1295
+ return Hom(domain, domain).identity()
1296
+ old = self._dictionary
1297
+ new = {d: old[d] for d in old if d.dimension() <= n}
1298
+ return Hom(domain, codomain)(new)
1299
+
1300
+ def associated_chain_complex_morphism(self, base_ring=ZZ,
1301
+ augmented=False, cochain=False):
1302
+ """
1303
+ Return the associated chain complex morphism of ``self``.
1304
+
1305
+ INPUT:
1306
+
1307
+ - ``base_ring`` -- default ``ZZ``
1308
+ - ``augmented`` -- boolean (default: ``False``); if ``True``,
1309
+ return the augmented complex
1310
+ - ``cochain`` -- boolean (default: ``False``); if ``True``,
1311
+ return the cochain complex
1312
+
1313
+ EXAMPLES::
1314
+
1315
+ sage: S1 = simplicial_sets.Sphere(1)
1316
+ sage: v0 = S1.n_cells(0)[0]
1317
+ sage: e = S1.n_cells(1)[0]
1318
+ sage: f = {v0: v0, e: v0.apply_degeneracies(0)} # constant map
1319
+ sage: g = Hom(S1, S1)(f)
1320
+ sage: g.associated_chain_complex_morphism().to_matrix() # needs sage.modules
1321
+ [1|0]
1322
+ [-+-]
1323
+ [0|0]
1324
+ """
1325
+ from sage.homology.chain_complex_morphism import ChainComplexMorphism
1326
+
1327
+ # One or the other chain complex is trivial between these
1328
+ # dimensions:
1329
+ max_dim = max(self.domain().dimension(), self.codomain().dimension())
1330
+ min_dim = min(self.domain().dimension(), self.codomain().dimension())
1331
+ matrices = {}
1332
+ if augmented is True:
1333
+ m = matrix(base_ring, 1, 1, 1)
1334
+ if not cochain:
1335
+ matrices[-1] = m
1336
+ else:
1337
+ matrices[-1] = m.transpose()
1338
+ for dim in range(min_dim+1):
1339
+ X_faces = list(self.domain().n_cells(dim))
1340
+ Y_faces = list(self.codomain().n_cells(dim))
1341
+ num_faces_X = len(X_faces)
1342
+ num_faces_Y = len(Y_faces)
1343
+ mval = [0 for _ in range(num_faces_X * num_faces_Y)]
1344
+ for idx, x in enumerate(X_faces):
1345
+ y = self(x)
1346
+ if y.is_nondegenerate():
1347
+ mval[idx + (Y_faces.index(y) * num_faces_X)] = 1
1348
+ m = matrix(base_ring, num_faces_Y, num_faces_X, mval, sparse=True)
1349
+ if not cochain:
1350
+ matrices[dim] = m
1351
+ else:
1352
+ matrices[dim] = m.transpose()
1353
+ for dim in range(min_dim+1, max_dim+1):
1354
+ try:
1355
+ l1 = len(self.codomain().n_cells(dim))
1356
+ except KeyError:
1357
+ l1 = 0
1358
+ try:
1359
+ l2 = len(self.domain().n_cells(dim))
1360
+ except KeyError:
1361
+ l2 = 0
1362
+ m = zero_matrix(base_ring, l1, l2, sparse=True)
1363
+ if not cochain:
1364
+ matrices[dim] = m
1365
+ else:
1366
+ matrices[dim] = m.transpose()
1367
+ if not cochain:
1368
+ return ChainComplexMorphism(matrices,
1369
+ self.domain().chain_complex(base_ring=base_ring, augmented=augmented, cochain=False),
1370
+ self.codomain().chain_complex(base_ring=base_ring, augmented=augmented, cochain=False))
1371
+ else:
1372
+ return ChainComplexMorphism(matrices,
1373
+ self.codomain().chain_complex(base_ring=base_ring, augmented=augmented, cochain=True),
1374
+ self.domain().chain_complex(base_ring=base_ring, augmented=augmented, cochain=True))
1375
+
1376
+ def induced_homology_morphism(self, base_ring=None, cohomology=False):
1377
+ """
1378
+ Return the map in (co)homology induced by this map.
1379
+
1380
+ INPUT:
1381
+
1382
+ - ``base_ring`` -- must be a field (default: ``QQ``)
1383
+
1384
+ - ``cohomology`` -- boolean (default: ``False``); if
1385
+ ``True``, the map induced in cohomology rather than homology
1386
+
1387
+ EXAMPLES::
1388
+
1389
+ sage: # needs sage.modules
1390
+ sage: from sage.topology.simplicial_set import AbstractSimplex, SimplicialSet
1391
+ sage: v = AbstractSimplex(0, name='v')
1392
+ sage: w = AbstractSimplex(0, name='w')
1393
+ sage: e = AbstractSimplex(1, name='e')
1394
+ sage: f = AbstractSimplex(1, name='f')
1395
+ sage: X = SimplicialSet({e: (v, w), f: (w, v)})
1396
+ sage: Y = SimplicialSet({e: (v, v)})
1397
+ sage: H = Hom(X, Y)
1398
+ sage: f = H({v: v, w: v, e: e, f: e})
1399
+ sage: g = f.induced_homology_morphism()
1400
+ sage: g.to_matrix()
1401
+ [1|0]
1402
+ [-+-]
1403
+ [0|2]
1404
+ sage: g3 = f.induced_homology_morphism(base_ring=GF(3), cohomology=True)
1405
+ sage: g3.to_matrix()
1406
+ [1|0]
1407
+ [-+-]
1408
+ [0|2]
1409
+ """
1410
+ from sage.homology.homology_morphism import InducedHomologyMorphism
1411
+
1412
+ return InducedHomologyMorphism(self, base_ring, cohomology)
1413
+
1414
+ def _repr_type(self):
1415
+ """
1416
+ EXAMPLES::
1417
+
1418
+ sage: S1 = simplicial_sets.Sphere(1)
1419
+ sage: f = Hom(S1,S1).identity()
1420
+ sage: f._repr_type()
1421
+ 'Simplicial set'
1422
+ """
1423
+ return "Simplicial set"
1424
+
1425
+ def _repr_defn(self):
1426
+ """
1427
+ EXAMPLES::
1428
+
1429
+ sage: K1 = simplicial_sets.Simplex(1)
1430
+ sage: v = K1.n_cells(0)[0]
1431
+ sage: e = K1.n_cells(1)[0]
1432
+ sage: f = Hom(K1,K1)({e:v.apply_degeneracies(0)})
1433
+ sage: f._repr_defn()
1434
+ 'Constant map at (0,)'
1435
+
1436
+ sage: K2 = simplicial_sets.Simplex(2)
1437
+ sage: tau = K2.n_cells(1)[0]
1438
+ sage: Hom(K1, K2)({e:tau})._repr_defn()
1439
+ '[(0,), (1,), (0, 1)] --> [(0,), (1,), (0, 1)]'
1440
+
1441
+ sage: S1 = simplicial_sets.Sphere(1)
1442
+ sage: Hom(S1,S1).identity()._repr_defn()
1443
+ 'Identity map'
1444
+ """
1445
+ if self.is_identity():
1446
+ return 'Identity map'
1447
+ if self.is_constant():
1448
+ return 'Constant map at {}'.format(self._constant)
1449
+ d = self._dictionary
1450
+ keys = sorted(d.keys())
1451
+ return "{} --> {}".format(keys, [d[x] for x in keys])
1452
+
1453
+ def _latex_(self):
1454
+ r"""
1455
+ LaTeX representation.
1456
+
1457
+ EXAMPLES::
1458
+
1459
+ sage: eta = simplicial_sets.HopfMap()
1460
+ sage: eta.domain().rename_latex('S^{3}')
1461
+ sage: latex(eta)
1462
+ S^{3} \to S^{2}
1463
+ """
1464
+ return '{} \\to {}'.format(latex(self.domain()), latex(self.codomain()))