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.
- passagemath_graphs-10.6.1rc1.dist-info/METADATA +292 -0
- passagemath_graphs-10.6.1rc1.dist-info/RECORD +260 -0
- passagemath_graphs-10.6.1rc1.dist-info/WHEEL +5 -0
- passagemath_graphs-10.6.1rc1.dist-info/top_level.txt +2 -0
- passagemath_graphs.libs/libgcc_s-69c45f16.so.1 +0 -0
- passagemath_graphs.libs/libgmp-8e78bd9b.so.10.5.0 +0 -0
- passagemath_graphs.libs/libstdc++-1f1a71be.so.6.0.33 +0 -0
- sage/all__sagemath_graphs.py +39 -0
- sage/combinat/abstract_tree.py +2723 -0
- sage/combinat/all__sagemath_graphs.py +34 -0
- sage/combinat/binary_tree.py +5306 -0
- sage/combinat/cluster_algebra_quiver/all.py +22 -0
- sage/combinat/cluster_algebra_quiver/cluster_seed.py +5208 -0
- sage/combinat/cluster_algebra_quiver/interact.py +124 -0
- sage/combinat/cluster_algebra_quiver/mutation_class.py +625 -0
- sage/combinat/cluster_algebra_quiver/mutation_type.py +1555 -0
- sage/combinat/cluster_algebra_quiver/quiver.py +2290 -0
- sage/combinat/cluster_algebra_quiver/quiver_mutation_type.py +2468 -0
- sage/combinat/designs/MOLS_handbook_data.py +570 -0
- sage/combinat/designs/all.py +58 -0
- sage/combinat/designs/bibd.py +1655 -0
- sage/combinat/designs/block_design.py +1071 -0
- sage/combinat/designs/covering_array.py +269 -0
- sage/combinat/designs/covering_design.py +530 -0
- sage/combinat/designs/database.py +5615 -0
- sage/combinat/designs/design_catalog.py +122 -0
- sage/combinat/designs/designs_pyx.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/combinat/designs/designs_pyx.pxd +21 -0
- sage/combinat/designs/designs_pyx.pyx +993 -0
- sage/combinat/designs/difference_family.py +3951 -0
- sage/combinat/designs/difference_matrices.py +279 -0
- sage/combinat/designs/evenly_distributed_sets.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/combinat/designs/evenly_distributed_sets.pyx +661 -0
- sage/combinat/designs/ext_rep.py +1064 -0
- sage/combinat/designs/gen_quadrangles_with_spread.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/combinat/designs/gen_quadrangles_with_spread.pyx +339 -0
- sage/combinat/designs/group_divisible_designs.py +361 -0
- sage/combinat/designs/incidence_structures.py +2357 -0
- sage/combinat/designs/latin_squares.py +581 -0
- sage/combinat/designs/orthogonal_arrays.py +2244 -0
- sage/combinat/designs/orthogonal_arrays_build_recursive.py +1780 -0
- sage/combinat/designs/orthogonal_arrays_find_recursive.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/combinat/designs/orthogonal_arrays_find_recursive.pyx +967 -0
- sage/combinat/designs/resolvable_bibd.py +815 -0
- sage/combinat/designs/steiner_quadruple_systems.py +1306 -0
- sage/combinat/designs/subhypergraph_search.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/combinat/designs/subhypergraph_search.pyx +530 -0
- sage/combinat/designs/twographs.py +306 -0
- sage/combinat/finite_state_machine.py +14874 -0
- sage/combinat/finite_state_machine_generators.py +2006 -0
- sage/combinat/graph_path.py +448 -0
- sage/combinat/interval_posets.py +3908 -0
- sage/combinat/nu_tamari_lattice.py +269 -0
- sage/combinat/ordered_tree.py +1446 -0
- sage/combinat/posets/all.py +46 -0
- sage/combinat/posets/bubble_shuffle.py +247 -0
- sage/combinat/posets/cartesian_product.py +493 -0
- sage/combinat/posets/d_complete.py +182 -0
- sage/combinat/posets/elements.py +273 -0
- sage/combinat/posets/forest.py +30 -0
- sage/combinat/posets/hasse_cython.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/combinat/posets/hasse_cython.pyx +174 -0
- sage/combinat/posets/hasse_diagram.py +3672 -0
- sage/combinat/posets/hochschild_lattice.py +158 -0
- sage/combinat/posets/incidence_algebras.py +794 -0
- sage/combinat/posets/lattices.py +5117 -0
- sage/combinat/posets/linear_extension_iterator.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/combinat/posets/linear_extension_iterator.pyx +292 -0
- sage/combinat/posets/linear_extensions.py +1037 -0
- sage/combinat/posets/mobile.py +275 -0
- sage/combinat/posets/moebius_algebra.py +776 -0
- sage/combinat/posets/poset_examples.py +2178 -0
- sage/combinat/posets/posets.py +9360 -0
- sage/combinat/rooted_tree.py +1070 -0
- sage/combinat/shard_order.py +239 -0
- sage/combinat/tamari_lattices.py +384 -0
- sage/combinat/yang_baxter_graph.py +923 -0
- sage/databases/all__sagemath_graphs.py +1 -0
- sage/databases/knotinfo_db.py +1231 -0
- sage/ext_data/all__sagemath_graphs.py +1 -0
- sage/ext_data/graphs/graph_plot_js.html +330 -0
- sage/ext_data/kenzo/CP2.txt +45 -0
- sage/ext_data/kenzo/CP3.txt +349 -0
- sage/ext_data/kenzo/CP4.txt +4774 -0
- sage/ext_data/kenzo/README.txt +49 -0
- sage/ext_data/kenzo/S4.txt +20 -0
- sage/graphs/all.py +42 -0
- sage/graphs/asteroidal_triples.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/asteroidal_triples.pyx +320 -0
- sage/graphs/base/all.py +1 -0
- sage/graphs/base/boost_graph.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/base/boost_graph.pxd +106 -0
- sage/graphs/base/boost_graph.pyx +3045 -0
- sage/graphs/base/c_graph.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/base/c_graph.pxd +106 -0
- sage/graphs/base/c_graph.pyx +5096 -0
- sage/graphs/base/dense_graph.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/base/dense_graph.pxd +28 -0
- sage/graphs/base/dense_graph.pyx +801 -0
- sage/graphs/base/graph_backends.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/base/graph_backends.pxd +5 -0
- sage/graphs/base/graph_backends.pyx +797 -0
- sage/graphs/base/overview.py +85 -0
- sage/graphs/base/sparse_graph.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/base/sparse_graph.pxd +90 -0
- sage/graphs/base/sparse_graph.pyx +1653 -0
- sage/graphs/base/static_dense_graph.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/base/static_dense_graph.pxd +5 -0
- sage/graphs/base/static_dense_graph.pyx +1032 -0
- sage/graphs/base/static_sparse_backend.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/base/static_sparse_backend.pxd +27 -0
- sage/graphs/base/static_sparse_backend.pyx +1583 -0
- sage/graphs/base/static_sparse_graph.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/base/static_sparse_graph.pxd +37 -0
- sage/graphs/base/static_sparse_graph.pyx +1375 -0
- sage/graphs/bipartite_graph.py +2732 -0
- sage/graphs/centrality.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/centrality.pyx +1038 -0
- sage/graphs/cographs.py +519 -0
- sage/graphs/comparability.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/comparability.pyx +851 -0
- sage/graphs/connectivity.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/connectivity.pxd +157 -0
- sage/graphs/connectivity.pyx +4813 -0
- sage/graphs/convexity_properties.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/convexity_properties.pxd +16 -0
- sage/graphs/convexity_properties.pyx +870 -0
- sage/graphs/digraph.py +4754 -0
- sage/graphs/digraph_generators.py +1993 -0
- sage/graphs/distances_all_pairs.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/distances_all_pairs.pxd +12 -0
- sage/graphs/distances_all_pairs.pyx +2938 -0
- sage/graphs/domination.py +1363 -0
- sage/graphs/dot2tex_utils.py +100 -0
- sage/graphs/edge_connectivity.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/edge_connectivity.pyx +1215 -0
- sage/graphs/generators/all.py +1 -0
- sage/graphs/generators/basic.py +1769 -0
- sage/graphs/generators/chessboard.py +538 -0
- sage/graphs/generators/classical_geometries.py +1611 -0
- sage/graphs/generators/degree_sequence.py +235 -0
- sage/graphs/generators/distance_regular.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/generators/distance_regular.pyx +2846 -0
- sage/graphs/generators/families.py +4759 -0
- sage/graphs/generators/intersection.py +565 -0
- sage/graphs/generators/platonic_solids.py +262 -0
- sage/graphs/generators/random.py +2623 -0
- sage/graphs/generators/smallgraphs.py +5741 -0
- sage/graphs/generators/world_map.py +724 -0
- sage/graphs/generic_graph.py +26867 -0
- sage/graphs/generic_graph_pyx.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/generic_graph_pyx.pxd +34 -0
- sage/graphs/generic_graph_pyx.pyx +1673 -0
- sage/graphs/genus.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/genus.pyx +622 -0
- sage/graphs/graph.py +9645 -0
- sage/graphs/graph_coloring.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/graph_coloring.pyx +2284 -0
- sage/graphs/graph_database.py +1177 -0
- sage/graphs/graph_decompositions/all.py +1 -0
- sage/graphs/graph_decompositions/bandwidth.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/graph_decompositions/bandwidth.pyx +428 -0
- sage/graphs/graph_decompositions/clique_separators.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/graph_decompositions/clique_separators.pyx +616 -0
- sage/graphs/graph_decompositions/cutwidth.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/graph_decompositions/cutwidth.pyx +753 -0
- sage/graphs/graph_decompositions/fast_digraph.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/graph_decompositions/fast_digraph.pxd +13 -0
- sage/graphs/graph_decompositions/fast_digraph.pyx +212 -0
- sage/graphs/graph_decompositions/graph_products.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/graph_decompositions/graph_products.pyx +508 -0
- sage/graphs/graph_decompositions/modular_decomposition.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/graph_decompositions/modular_decomposition.pxd +27 -0
- sage/graphs/graph_decompositions/modular_decomposition.pyx +1536 -0
- sage/graphs/graph_decompositions/slice_decomposition.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/graph_decompositions/slice_decomposition.pxd +18 -0
- sage/graphs/graph_decompositions/slice_decomposition.pyx +1106 -0
- sage/graphs/graph_decompositions/tree_decomposition.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/graph_decompositions/tree_decomposition.pxd +17 -0
- sage/graphs/graph_decompositions/tree_decomposition.pyx +1996 -0
- sage/graphs/graph_decompositions/vertex_separation.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/graph_decompositions/vertex_separation.pxd +5 -0
- sage/graphs/graph_decompositions/vertex_separation.pyx +1963 -0
- sage/graphs/graph_editor.py +82 -0
- sage/graphs/graph_generators.py +3314 -0
- sage/graphs/graph_generators_pyx.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/graph_generators_pyx.pyx +95 -0
- sage/graphs/graph_input.py +812 -0
- sage/graphs/graph_latex.py +2064 -0
- sage/graphs/graph_list.py +410 -0
- sage/graphs/graph_plot.py +1756 -0
- sage/graphs/graph_plot_js.py +338 -0
- sage/graphs/hyperbolicity.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/hyperbolicity.pyx +1704 -0
- sage/graphs/hypergraph_generators.py +364 -0
- sage/graphs/independent_sets.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/independent_sets.pxd +13 -0
- sage/graphs/independent_sets.pyx +402 -0
- sage/graphs/isgci.py +1033 -0
- sage/graphs/isoperimetric_inequalities.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/isoperimetric_inequalities.pyx +489 -0
- sage/graphs/line_graph.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/line_graph.pyx +743 -0
- sage/graphs/lovasz_theta.py +77 -0
- sage/graphs/matching.py +1633 -0
- sage/graphs/matching_covered_graph.py +3590 -0
- sage/graphs/orientations.py +1489 -0
- sage/graphs/partial_cube.py +459 -0
- sage/graphs/path_enumeration.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/path_enumeration.pyx +2040 -0
- sage/graphs/pq_trees.py +1129 -0
- sage/graphs/print_graphs.py +201 -0
- sage/graphs/schnyder.py +865 -0
- sage/graphs/spanning_tree.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/spanning_tree.pyx +1457 -0
- sage/graphs/strongly_regular_db.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/strongly_regular_db.pyx +3340 -0
- sage/graphs/traversals.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/traversals.pxd +9 -0
- sage/graphs/traversals.pyx +1872 -0
- sage/graphs/trees.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/trees.pxd +15 -0
- sage/graphs/trees.pyx +310 -0
- sage/graphs/tutte_polynomial.py +713 -0
- sage/graphs/views.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/views.pyx +794 -0
- sage/graphs/weakly_chordal.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/weakly_chordal.pyx +604 -0
- sage/groups/all__sagemath_graphs.py +1 -0
- sage/groups/perm_gps/all__sagemath_graphs.py +1 -0
- sage/groups/perm_gps/partn_ref/all__sagemath_graphs.py +1 -0
- sage/groups/perm_gps/partn_ref/refinement_graphs.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/groups/perm_gps/partn_ref/refinement_graphs.pxd +38 -0
- sage/groups/perm_gps/partn_ref/refinement_graphs.pyx +1666 -0
- sage/knots/all.py +6 -0
- sage/knots/free_knotinfo_monoid.py +507 -0
- sage/knots/gauss_code.py +291 -0
- sage/knots/knot.py +682 -0
- sage/knots/knot_table.py +284 -0
- sage/knots/knotinfo.py +2900 -0
- sage/knots/link.py +4715 -0
- sage/sandpiles/all.py +13 -0
- sage/sandpiles/examples.py +225 -0
- sage/sandpiles/sandpile.py +6365 -0
- sage/topology/all.py +22 -0
- sage/topology/cell_complex.py +1214 -0
- sage/topology/cubical_complex.py +1976 -0
- sage/topology/delta_complex.py +1806 -0
- sage/topology/filtered_simplicial_complex.py +744 -0
- sage/topology/moment_angle_complex.py +823 -0
- sage/topology/simplicial_complex.py +5160 -0
- sage/topology/simplicial_complex_catalog.py +92 -0
- sage/topology/simplicial_complex_examples.py +1680 -0
- sage/topology/simplicial_complex_homset.py +205 -0
- sage/topology/simplicial_complex_morphism.py +836 -0
- sage/topology/simplicial_set.py +4102 -0
- sage/topology/simplicial_set_catalog.py +55 -0
- sage/topology/simplicial_set_constructions.py +2954 -0
- sage/topology/simplicial_set_examples.py +865 -0
- 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()))
|