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,836 @@
|
|
1
|
+
# sage_setup: distribution = sagemath-graphs
|
2
|
+
# sage.doctest: needs sage.graphs
|
3
|
+
r"""
|
4
|
+
Morphisms of simplicial complexes
|
5
|
+
|
6
|
+
AUTHORS:
|
7
|
+
|
8
|
+
- Benjamin Antieau <d.ben.antieau@gmail.com> (2009.06)
|
9
|
+
|
10
|
+
- Travis Scrimshaw (2012-08-18): Made all simplicial complexes immutable to
|
11
|
+
work with the homset cache.
|
12
|
+
|
13
|
+
This module implements morphisms of simplicial complexes. The input is given
|
14
|
+
by a dictionary on the vertex set of a simplicial complex. The initialization
|
15
|
+
checks that faces are sent to faces.
|
16
|
+
|
17
|
+
There is also the capability to create the fiber product of two morphisms with
|
18
|
+
the same codomain.
|
19
|
+
|
20
|
+
EXAMPLES::
|
21
|
+
|
22
|
+
sage: S = SimplicialComplex([[0,2],[1,5],[3,4]], is_mutable=False)
|
23
|
+
sage: H = Hom(S,S.product(S, is_mutable=False))
|
24
|
+
sage: H.diagonal_morphism()
|
25
|
+
Simplicial complex morphism:
|
26
|
+
From: Simplicial complex with vertex set (0, 1, 2, 3, 4, 5) and facets {(0, 2), (1, 5), (3, 4)}
|
27
|
+
To: Simplicial complex with 36 vertices and 18 facets
|
28
|
+
Defn: [0, 1, 2, 3, 4, 5] --> ['L0R0', 'L1R1', 'L2R2', 'L3R3', 'L4R4', 'L5R5']
|
29
|
+
|
30
|
+
sage: S = SimplicialComplex([[0,2],[1,5],[3,4]], is_mutable=False)
|
31
|
+
sage: T = SimplicialComplex([[0,2],[1,3]], is_mutable=False)
|
32
|
+
sage: f = {0:0,1:1,2:2,3:1,4:3,5:3}
|
33
|
+
sage: H = Hom(S,T)
|
34
|
+
sage: x = H(f)
|
35
|
+
sage: x.image()
|
36
|
+
Simplicial complex with vertex set (0, 1, 2, 3) and facets {(0, 2), (1, 3)}
|
37
|
+
sage: x.is_surjective()
|
38
|
+
True
|
39
|
+
sage: x.is_injective()
|
40
|
+
False
|
41
|
+
sage: x.is_identity()
|
42
|
+
False
|
43
|
+
|
44
|
+
sage: S = simplicial_complexes.Sphere(2)
|
45
|
+
sage: H = Hom(S,S)
|
46
|
+
sage: i = H.identity()
|
47
|
+
sage: i.image()
|
48
|
+
Simplicial complex with vertex set (0, 1, 2, 3) and facets {(0, 1, 2), (0, 1, 3), (0, 2, 3), (1, 2, 3)}
|
49
|
+
sage: i.is_surjective()
|
50
|
+
True
|
51
|
+
sage: i.is_injective()
|
52
|
+
True
|
53
|
+
sage: i.is_identity()
|
54
|
+
True
|
55
|
+
|
56
|
+
sage: S = simplicial_complexes.Sphere(2)
|
57
|
+
sage: H = Hom(S,S)
|
58
|
+
sage: i = H.identity()
|
59
|
+
sage: j = i.fiber_product(i)
|
60
|
+
sage: j
|
61
|
+
Simplicial complex morphism:
|
62
|
+
From: Simplicial complex with 4 vertices and 4 facets
|
63
|
+
To: Minimal triangulation of the 2-sphere
|
64
|
+
Defn: L0R0 |--> 0
|
65
|
+
L1R1 |--> 1
|
66
|
+
L2R2 |--> 2
|
67
|
+
L3R3 |--> 3
|
68
|
+
sage: S = simplicial_complexes.Sphere(2)
|
69
|
+
sage: T = S.product(SimplicialComplex([[0,1]]), rename_vertices = False, is_mutable=False)
|
70
|
+
sage: H = Hom(T,S)
|
71
|
+
sage: T
|
72
|
+
Simplicial complex with 8 vertices and 12 facets
|
73
|
+
sage: sorted(T.vertices())
|
74
|
+
[(0, 0), (0, 1), (1, 0), (1, 1), (2, 0), (2, 1), (3, 0), (3, 1)]
|
75
|
+
sage: f = {(0, 0): 0, (0, 1): 0, (1, 0): 1, (1, 1): 1, (2, 0): 2, (2, 1): 2, (3, 0): 3, (3, 1): 3}
|
76
|
+
sage: x = H(f)
|
77
|
+
sage: U = simplicial_complexes.Sphere(1)
|
78
|
+
sage: G = Hom(U,S)
|
79
|
+
sage: U
|
80
|
+
Minimal triangulation of the 1-sphere
|
81
|
+
sage: g = {0:0,1:1,2:2}
|
82
|
+
sage: y = G(g)
|
83
|
+
sage: z = y.fiber_product(x)
|
84
|
+
sage: z # this is the mapping path space
|
85
|
+
Simplicial complex morphism:
|
86
|
+
From: Simplicial complex with 6 vertices and ... facets
|
87
|
+
To: Minimal triangulation of the 2-sphere
|
88
|
+
Defn: ['L0R(0, 0)', 'L0R(0, 1)', 'L1R(1, 0)', 'L1R(1, 1)', 'L2R(2, 0)', 'L2R(2, 1)'] --> [0, 0, 1, 1, 2, 2]
|
89
|
+
"""
|
90
|
+
|
91
|
+
# ****************************************************************************
|
92
|
+
# Copyright (C) 2009 D. Benjamin Antieau <d.ben.antieau@gmail.com>
|
93
|
+
#
|
94
|
+
# Distributed under the terms of the GNU General Public License (GPL)
|
95
|
+
#
|
96
|
+
# This code is distributed in the hope that it will be useful,
|
97
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty
|
98
|
+
# of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
99
|
+
#
|
100
|
+
# See the GNU General Public License for more details; the full text
|
101
|
+
# is available at:
|
102
|
+
#
|
103
|
+
# https://www.gnu.org/licenses/
|
104
|
+
#
|
105
|
+
# ****************************************************************************
|
106
|
+
|
107
|
+
from sage.categories.homset import Hom
|
108
|
+
from sage.categories.morphism import Morphism
|
109
|
+
from sage.categories.simplicial_complexes import SimplicialComplexes
|
110
|
+
from sage.misc.lazy_import import lazy_import
|
111
|
+
from sage.rings.integer_ring import ZZ
|
112
|
+
|
113
|
+
from .simplicial_complex import Simplex, SimplicialComplex
|
114
|
+
|
115
|
+
lazy_import('sage.matrix.constructor', ['matrix', 'zero_matrix'])
|
116
|
+
|
117
|
+
|
118
|
+
def is_SimplicialComplexMorphism(x):
|
119
|
+
"""
|
120
|
+
Return ``True`` if and only if ``x`` is a morphism of simplicial complexes.
|
121
|
+
|
122
|
+
EXAMPLES::
|
123
|
+
|
124
|
+
sage: from sage.topology.simplicial_complex_morphism import is_SimplicialComplexMorphism
|
125
|
+
sage: S = SimplicialComplex([[0,1],[3,4]], is_mutable=False)
|
126
|
+
sage: H = Hom(S,S)
|
127
|
+
sage: f = {0:0,1:1,3:3,4:4}
|
128
|
+
sage: x = H(f)
|
129
|
+
sage: is_SimplicialComplexMorphism(x)
|
130
|
+
doctest:warning...
|
131
|
+
DeprecationWarning: The function is_SimplicialComplexMorphism is deprecated;
|
132
|
+
use 'isinstance(..., SimplicialComplexMorphism)' instead.
|
133
|
+
See https://github.com/sagemath/sage/issues/38103 for details.
|
134
|
+
True
|
135
|
+
"""
|
136
|
+
from sage.misc.superseded import deprecation
|
137
|
+
deprecation(38103,
|
138
|
+
"The function is_SimplicialComplexMorphism is deprecated; "
|
139
|
+
"use 'isinstance(..., SimplicialComplexMorphism)' instead.")
|
140
|
+
return isinstance(x, SimplicialComplexMorphism)
|
141
|
+
|
142
|
+
|
143
|
+
class SimplicialComplexMorphism(Morphism):
|
144
|
+
"""
|
145
|
+
An element of this class is a morphism of simplicial complexes.
|
146
|
+
"""
|
147
|
+
def __init__(self, f, X, Y):
|
148
|
+
"""
|
149
|
+
Input is a dictionary ``f``, the domain ``X``, and the codomain ``Y``.
|
150
|
+
|
151
|
+
One can define the dictionary on the vertices of `X`.
|
152
|
+
|
153
|
+
EXAMPLES::
|
154
|
+
|
155
|
+
sage: S = SimplicialComplex([[0,1],[2],[3,4],[5]], is_mutable=False)
|
156
|
+
sage: H = Hom(S,S)
|
157
|
+
sage: f = {0:0,1:1,2:2,3:3,4:4,5:5}
|
158
|
+
sage: g = {0:0,1:1,2:0,3:3,4:4,5:0}
|
159
|
+
sage: x = H(f)
|
160
|
+
sage: y = H(g)
|
161
|
+
sage: x == y
|
162
|
+
False
|
163
|
+
sage: x.image()
|
164
|
+
Simplicial complex with vertex set (0, 1, 2, 3, 4, 5) and facets {(2,), (5,), (0, 1), (3, 4)}
|
165
|
+
sage: y.image()
|
166
|
+
Simplicial complex with vertex set (0, 1, 3, 4) and facets {(0, 1), (3, 4)}
|
167
|
+
sage: x.image() == y.image()
|
168
|
+
False
|
169
|
+
"""
|
170
|
+
if not isinstance(X, SimplicialComplex) or not isinstance(Y, SimplicialComplex):
|
171
|
+
raise ValueError("X and Y must be SimplicialComplexes")
|
172
|
+
if set(f.keys()) != set(X.vertices()):
|
173
|
+
raise ValueError("f must be a dictionary from the vertex set of X to single values in the vertex set of Y")
|
174
|
+
dim = X.dimension()
|
175
|
+
Y_faces = Y.faces()
|
176
|
+
for k in range(dim + 1):
|
177
|
+
for i in X.faces()[k]:
|
178
|
+
fi = {f[j] for j in i.tuple()}
|
179
|
+
v = Simplex(fi)
|
180
|
+
if v not in Y_faces[v.dimension()]:
|
181
|
+
raise ValueError("f must be a dictionary from the vertices of X to the vertices of Y")
|
182
|
+
self._vertex_dictionary = f
|
183
|
+
Morphism.__init__(self, Hom(X, Y, SimplicialComplexes()))
|
184
|
+
|
185
|
+
def __eq__(self, x):
|
186
|
+
"""
|
187
|
+
Return ``True`` if and only if ``self == x``.
|
188
|
+
|
189
|
+
EXAMPLES::
|
190
|
+
|
191
|
+
sage: S = simplicial_complexes.Sphere(2)
|
192
|
+
sage: H = Hom(S,S)
|
193
|
+
sage: i = H.identity()
|
194
|
+
sage: i
|
195
|
+
Simplicial complex endomorphism of Minimal triangulation of the 2-sphere
|
196
|
+
Defn: 0 |--> 0
|
197
|
+
1 |--> 1
|
198
|
+
2 |--> 2
|
199
|
+
3 |--> 3
|
200
|
+
sage: f = {0:0,1:1,2:2,3:2}
|
201
|
+
sage: j = H(f)
|
202
|
+
sage: i==j
|
203
|
+
False
|
204
|
+
|
205
|
+
sage: T = SimplicialComplex([[1,2]], is_mutable=False)
|
206
|
+
sage: T
|
207
|
+
Simplicial complex with vertex set (1, 2) and facets {(1, 2)}
|
208
|
+
sage: G = Hom(T,T)
|
209
|
+
sage: k = G.identity()
|
210
|
+
sage: g = {1:1,2:2}
|
211
|
+
sage: l = G(g)
|
212
|
+
sage: k == l
|
213
|
+
True
|
214
|
+
"""
|
215
|
+
if not isinstance(x, SimplicialComplexMorphism) or self.codomain() != x.codomain() or self.domain() != x.domain() or self._vertex_dictionary != x._vertex_dictionary:
|
216
|
+
return False
|
217
|
+
else:
|
218
|
+
return True
|
219
|
+
|
220
|
+
def __call__(self, x, orientation=False):
|
221
|
+
"""
|
222
|
+
Input is a simplex of the domain. Output is the image simplex.
|
223
|
+
|
224
|
+
If the optional argument ``orientation`` is ``True``, then this
|
225
|
+
returns a pair ``(image simplex, oriented)`` where ``oriented``
|
226
|
+
is 1 or `-1` depending on whether the map preserves or reverses
|
227
|
+
the orientation of the image simplex.
|
228
|
+
|
229
|
+
EXAMPLES::
|
230
|
+
|
231
|
+
sage: S = simplicial_complexes.Sphere(2)
|
232
|
+
sage: T = simplicial_complexes.Sphere(3)
|
233
|
+
sage: S
|
234
|
+
Minimal triangulation of the 2-sphere
|
235
|
+
sage: T
|
236
|
+
Minimal triangulation of the 3-sphere
|
237
|
+
sage: f = {0:0,1:1,2:2,3:3}
|
238
|
+
sage: H = Hom(S,T)
|
239
|
+
sage: x = H(f)
|
240
|
+
sage: from sage.topology.simplicial_complex import Simplex
|
241
|
+
sage: x(Simplex([0,2,3]))
|
242
|
+
(0, 2, 3)
|
243
|
+
|
244
|
+
An orientation-reversing example::
|
245
|
+
|
246
|
+
sage: X = SimplicialComplex([[0,1]], is_mutable=False)
|
247
|
+
sage: g = Hom(X,X)({0:1, 1:0})
|
248
|
+
sage: g(Simplex([0,1]))
|
249
|
+
(0, 1)
|
250
|
+
sage: g(Simplex([0,1]), orientation=True) # needs sage.modules
|
251
|
+
((0, 1), -1)
|
252
|
+
|
253
|
+
TESTS:
|
254
|
+
|
255
|
+
Test that the problem in :issue:`36849` has been fixed::
|
256
|
+
|
257
|
+
sage: S = SimplicialComplex([[1,2]],is_mutable=False).barycentric_subdivision()
|
258
|
+
sage: T = SimplicialComplex([[1,2],[2,3],[1,3]],is_mutable=False).barycentric_subdivision()
|
259
|
+
sage: f = {x[0]:x[0] for x in S.cells()[0]}
|
260
|
+
sage: H = Hom(S,T)
|
261
|
+
sage: z = H(f)
|
262
|
+
sage: z.associated_chain_complex_morphism() # needs sage.modules
|
263
|
+
Chain complex morphism:
|
264
|
+
From: Chain complex with at most 2 nonzero terms over Integer Ring
|
265
|
+
To: Chain complex with at most 2 nonzero terms over Integer Ring
|
266
|
+
"""
|
267
|
+
dim = self.domain().dimension()
|
268
|
+
if not isinstance(x, Simplex) or x.dimension() > dim or x not in self.domain().faces()[x.dimension()]:
|
269
|
+
raise ValueError("x must be a simplex of the source of f")
|
270
|
+
tup = x.tuple()
|
271
|
+
fx = [self._vertex_dictionary[j] for j in tup]
|
272
|
+
if orientation:
|
273
|
+
from sage.algebras.steenrod.steenrod_algebra_misc import convert_perm
|
274
|
+
from sage.combinat.permutation import Permutation
|
275
|
+
|
276
|
+
if len(set(fx)) == len(tup):
|
277
|
+
# We need to compare the image simplex, as given in
|
278
|
+
# the order specified by self, with its orientation in
|
279
|
+
# the codomain.
|
280
|
+
image = Simplex(set(fx))
|
281
|
+
Y_faces = self.codomain()._n_cells_sorted(image.dimension())
|
282
|
+
idx = Y_faces.index(image)
|
283
|
+
actual_image = Y_faces[idx]
|
284
|
+
# The signature of the permutation specified by self:
|
285
|
+
sign_image = Permutation(convert_perm(fx)).signature()
|
286
|
+
# The signature of the permutation of the simplex in the domain:
|
287
|
+
sign_simplex = Permutation(convert_perm(actual_image)).signature()
|
288
|
+
oriented = sign_image * sign_simplex
|
289
|
+
else:
|
290
|
+
oriented = 1
|
291
|
+
return (Simplex(set(fx)), oriented)
|
292
|
+
else:
|
293
|
+
return Simplex(set(fx))
|
294
|
+
|
295
|
+
def _repr_type(self):
|
296
|
+
"""
|
297
|
+
EXAMPLES::
|
298
|
+
|
299
|
+
sage: S = simplicial_complexes.Sphere(1)
|
300
|
+
sage: T = simplicial_complexes.Sphere(2)
|
301
|
+
sage: H = Hom(S,T)
|
302
|
+
sage: f = {0:0,1:1,2:2}
|
303
|
+
sage: H(f)._repr_type()
|
304
|
+
'Simplicial complex'
|
305
|
+
"""
|
306
|
+
return "Simplicial complex"
|
307
|
+
|
308
|
+
def _repr_defn(self):
|
309
|
+
"""
|
310
|
+
If there are fewer than 5 vertices, print the image of each vertex
|
311
|
+
on a separate line. Otherwise, print the map as a single line.
|
312
|
+
|
313
|
+
EXAMPLES::
|
314
|
+
|
315
|
+
sage: S = simplicial_complexes.Simplex(1)
|
316
|
+
sage: print(Hom(S,S).identity()._repr_defn())
|
317
|
+
0 |--> 0
|
318
|
+
1 |--> 1
|
319
|
+
sage: T = simplicial_complexes.Torus()
|
320
|
+
sage: print(Hom(T,T).identity()._repr_defn())
|
321
|
+
[0, 1, 2, 3, 4, 5, 6] --> [0, 1, 2, 3, 4, 5, 6]
|
322
|
+
"""
|
323
|
+
vd = self._vertex_dictionary
|
324
|
+
try:
|
325
|
+
keys = sorted(vd.keys())
|
326
|
+
except TypeError:
|
327
|
+
keys = sorted(vd.keys(), key=str)
|
328
|
+
if len(vd) < 5:
|
329
|
+
return '\n'.join("{} |--> {}".format(v, vd[v]) for v in keys)
|
330
|
+
domain = list(vd.keys())
|
331
|
+
try:
|
332
|
+
domain = sorted(domain)
|
333
|
+
except TypeError:
|
334
|
+
domain = sorted(domain, key=str)
|
335
|
+
codomain = [vd[v] for v in domain]
|
336
|
+
return "{} --> {}".format(domain, codomain)
|
337
|
+
|
338
|
+
def associated_chain_complex_morphism(self, base_ring=ZZ,
|
339
|
+
augmented=False, cochain=False):
|
340
|
+
"""
|
341
|
+
Return the associated chain complex morphism of ``self``.
|
342
|
+
|
343
|
+
EXAMPLES::
|
344
|
+
|
345
|
+
sage: # needs sage.modules
|
346
|
+
sage: S = simplicial_complexes.Sphere(1)
|
347
|
+
sage: T = simplicial_complexes.Sphere(2)
|
348
|
+
sage: H = Hom(S, T)
|
349
|
+
sage: f = {0:0, 1:1, 2:2}
|
350
|
+
sage: x = H(f); x
|
351
|
+
Simplicial complex morphism:
|
352
|
+
From: Minimal triangulation of the 1-sphere
|
353
|
+
To: Minimal triangulation of the 2-sphere
|
354
|
+
Defn: 0 |--> 0
|
355
|
+
1 |--> 1
|
356
|
+
2 |--> 2
|
357
|
+
sage: a = x.associated_chain_complex_morphism(); a
|
358
|
+
Chain complex morphism:
|
359
|
+
From: Chain complex with at most 2 nonzero terms over Integer Ring
|
360
|
+
To: Chain complex with at most 3 nonzero terms over Integer Ring
|
361
|
+
sage: a._matrix_dictionary
|
362
|
+
{0: [1 0 0]
|
363
|
+
[0 1 0]
|
364
|
+
[0 0 1]
|
365
|
+
[0 0 0],
|
366
|
+
1: [1 0 0]
|
367
|
+
[0 1 0]
|
368
|
+
[0 0 0]
|
369
|
+
[0 0 1]
|
370
|
+
[0 0 0]
|
371
|
+
[0 0 0],
|
372
|
+
2: []}
|
373
|
+
sage: x.associated_chain_complex_morphism(augmented=True)
|
374
|
+
Chain complex morphism:
|
375
|
+
From: Chain complex with at most 3 nonzero terms over Integer Ring
|
376
|
+
To: Chain complex with at most 4 nonzero terms over Integer Ring
|
377
|
+
sage: x.associated_chain_complex_morphism(cochain=True)
|
378
|
+
Chain complex morphism:
|
379
|
+
From: Chain complex with at most 3 nonzero terms over Integer Ring
|
380
|
+
To: Chain complex with at most 2 nonzero terms over Integer Ring
|
381
|
+
sage: x.associated_chain_complex_morphism(augmented=True, cochain=True)
|
382
|
+
Chain complex morphism:
|
383
|
+
From: Chain complex with at most 4 nonzero terms over Integer Ring
|
384
|
+
To: Chain complex with at most 3 nonzero terms over Integer Ring
|
385
|
+
sage: x.associated_chain_complex_morphism(base_ring=GF(11))
|
386
|
+
Chain complex morphism:
|
387
|
+
From: Chain complex with at most 2 nonzero terms over Finite Field of size 11
|
388
|
+
To: Chain complex with at most 3 nonzero terms over Finite Field of size 11
|
389
|
+
|
390
|
+
Some simplicial maps which reverse the orientation of a few simplices::
|
391
|
+
|
392
|
+
sage: # needs sage.modules
|
393
|
+
sage: g = {0:1, 1:2, 2:0}
|
394
|
+
sage: H(g).associated_chain_complex_morphism()._matrix_dictionary
|
395
|
+
{0: [0 0 1]
|
396
|
+
[1 0 0]
|
397
|
+
[0 1 0]
|
398
|
+
[0 0 0],
|
399
|
+
1: [ 0 -1 0]
|
400
|
+
[ 0 0 -1]
|
401
|
+
[ 0 0 0]
|
402
|
+
[ 1 0 0]
|
403
|
+
[ 0 0 0]
|
404
|
+
[ 0 0 0],
|
405
|
+
2: []}
|
406
|
+
sage: X = SimplicialComplex([[0, 1]], is_mutable=False)
|
407
|
+
sage: Hom(X,X)({0:1, 1:0}).associated_chain_complex_morphism()._matrix_dictionary
|
408
|
+
{0: [0 1]
|
409
|
+
[1 0],
|
410
|
+
1: [-1]}
|
411
|
+
"""
|
412
|
+
from sage.homology.chain_complex_morphism import ChainComplexMorphism
|
413
|
+
|
414
|
+
max_dim = max(self.domain().dimension(), self.codomain().dimension())
|
415
|
+
min_dim = min(self.domain().dimension(), self.codomain().dimension())
|
416
|
+
matrices = {}
|
417
|
+
if augmented is True:
|
418
|
+
m = matrix(base_ring, 1, 1, 1)
|
419
|
+
if not cochain:
|
420
|
+
matrices[-1] = m
|
421
|
+
else:
|
422
|
+
matrices[-1] = m.transpose()
|
423
|
+
for dim in range(min_dim+1):
|
424
|
+
X_faces = self.domain()._n_cells_sorted(dim)
|
425
|
+
Y_faces = self.codomain()._n_cells_sorted(dim)
|
426
|
+
num_faces_X = len(X_faces)
|
427
|
+
num_faces_Y = len(Y_faces)
|
428
|
+
mval = [0 for i in range(num_faces_X*num_faces_Y)]
|
429
|
+
for i in X_faces:
|
430
|
+
y, oriented = self(i, orientation=True)
|
431
|
+
if y.dimension() < dim:
|
432
|
+
pass
|
433
|
+
else:
|
434
|
+
mval[X_faces.index(i)+(Y_faces.index(y)*num_faces_X)] = oriented
|
435
|
+
m = matrix(base_ring, num_faces_Y, num_faces_X, mval, sparse=True)
|
436
|
+
if not cochain:
|
437
|
+
matrices[dim] = m
|
438
|
+
else:
|
439
|
+
matrices[dim] = m.transpose()
|
440
|
+
for dim in range(min_dim+1, max_dim+1):
|
441
|
+
try:
|
442
|
+
l1 = len(self.codomain().n_cells(dim))
|
443
|
+
except KeyError:
|
444
|
+
l1 = 0
|
445
|
+
try:
|
446
|
+
l2 = len(self.domain().n_cells(dim))
|
447
|
+
except KeyError:
|
448
|
+
l2 = 0
|
449
|
+
m = zero_matrix(base_ring, l1, l2, sparse=True)
|
450
|
+
if not cochain:
|
451
|
+
matrices[dim] = m
|
452
|
+
else:
|
453
|
+
matrices[dim] = m.transpose()
|
454
|
+
if not cochain:
|
455
|
+
return ChainComplexMorphism(matrices,
|
456
|
+
self.domain().chain_complex(base_ring=base_ring, augmented=augmented, cochain=cochain),
|
457
|
+
self.codomain().chain_complex(base_ring=base_ring, augmented=augmented, cochain=cochain))
|
458
|
+
return ChainComplexMorphism(matrices,
|
459
|
+
self.codomain().chain_complex(base_ring=base_ring, augmented=augmented, cochain=cochain),
|
460
|
+
self.domain().chain_complex(base_ring=base_ring, augmented=augmented, cochain=cochain))
|
461
|
+
|
462
|
+
def image(self):
|
463
|
+
"""
|
464
|
+
Compute the image simplicial complex of `f`.
|
465
|
+
|
466
|
+
EXAMPLES::
|
467
|
+
|
468
|
+
sage: S = SimplicialComplex([[0,1],[2,3]], is_mutable=False)
|
469
|
+
sage: T = SimplicialComplex([[0,1]], is_mutable=False)
|
470
|
+
sage: f = {0:0,1:1,2:0,3:1}
|
471
|
+
sage: H = Hom(S,T)
|
472
|
+
sage: x = H(f)
|
473
|
+
sage: x.image()
|
474
|
+
Simplicial complex with vertex set (0, 1) and facets {(0, 1)}
|
475
|
+
|
476
|
+
sage: S = SimplicialComplex(is_mutable=False)
|
477
|
+
sage: H = Hom(S,S)
|
478
|
+
sage: i = H.identity()
|
479
|
+
sage: i.image()
|
480
|
+
Simplicial complex with vertex set () and facets {()}
|
481
|
+
sage: i.is_surjective()
|
482
|
+
True
|
483
|
+
sage: S = SimplicialComplex([[0,1]], is_mutable=False)
|
484
|
+
sage: T = SimplicialComplex([[0,1], [0,2]], is_mutable=False)
|
485
|
+
sage: f = {0:0,1:1}
|
486
|
+
sage: g = {0:0,1:1}
|
487
|
+
sage: k = {0:0,1:2}
|
488
|
+
sage: H = Hom(S,T)
|
489
|
+
sage: x = H(f)
|
490
|
+
sage: y = H(g)
|
491
|
+
sage: z = H(k)
|
492
|
+
sage: x == y
|
493
|
+
True
|
494
|
+
sage: x == z
|
495
|
+
False
|
496
|
+
sage: x.image()
|
497
|
+
Simplicial complex with vertex set (0, 1) and facets {(0, 1)}
|
498
|
+
sage: y.image()
|
499
|
+
Simplicial complex with vertex set (0, 1) and facets {(0, 1)}
|
500
|
+
sage: z.image()
|
501
|
+
Simplicial complex with vertex set (0, 2) and facets {(0, 2)}
|
502
|
+
"""
|
503
|
+
fa = [self(i) for i in self.domain().facets()]
|
504
|
+
return SimplicialComplex(fa, maximality_check=True)
|
505
|
+
|
506
|
+
def is_surjective(self):
|
507
|
+
"""
|
508
|
+
Return ``True`` if and only if ``self`` is surjective.
|
509
|
+
|
510
|
+
EXAMPLES::
|
511
|
+
|
512
|
+
sage: S = SimplicialComplex([(0,1,2)], is_mutable=False)
|
513
|
+
sage: S
|
514
|
+
Simplicial complex with vertex set (0, 1, 2) and facets {(0, 1, 2)}
|
515
|
+
sage: T = SimplicialComplex([(0,1)], is_mutable=False)
|
516
|
+
sage: T
|
517
|
+
Simplicial complex with vertex set (0, 1) and facets {(0, 1)}
|
518
|
+
sage: H = Hom(S,T)
|
519
|
+
sage: x = H({0:0,1:1,2:1})
|
520
|
+
sage: x.is_surjective()
|
521
|
+
True
|
522
|
+
|
523
|
+
sage: S = SimplicialComplex([[0,1],[2,3]], is_mutable=False)
|
524
|
+
sage: T = SimplicialComplex([[0,1]], is_mutable=False)
|
525
|
+
sage: f = {0:0,1:1,2:0,3:1}
|
526
|
+
sage: H = Hom(S,T)
|
527
|
+
sage: x = H(f)
|
528
|
+
sage: x.is_surjective()
|
529
|
+
True
|
530
|
+
"""
|
531
|
+
return self.codomain() == self.image()
|
532
|
+
|
533
|
+
def is_injective(self):
|
534
|
+
"""
|
535
|
+
Return ``True`` if and only if ``self`` is injective.
|
536
|
+
|
537
|
+
EXAMPLES::
|
538
|
+
|
539
|
+
sage: S = simplicial_complexes.Sphere(1)
|
540
|
+
sage: T = simplicial_complexes.Sphere(2)
|
541
|
+
sage: U = simplicial_complexes.Sphere(3)
|
542
|
+
sage: H = Hom(T,S)
|
543
|
+
sage: G = Hom(T,U)
|
544
|
+
sage: f = {0:0,1:1,2:0,3:1}
|
545
|
+
sage: x = H(f)
|
546
|
+
sage: g = {0:0,1:1,2:2,3:3}
|
547
|
+
sage: y = G(g)
|
548
|
+
sage: x.is_injective()
|
549
|
+
False
|
550
|
+
sage: y.is_injective()
|
551
|
+
True
|
552
|
+
"""
|
553
|
+
v = [self._vertex_dictionary[i[0]] for i in self.domain().faces()[0]]
|
554
|
+
for i in v:
|
555
|
+
if v.count(i) > 1:
|
556
|
+
return False
|
557
|
+
return True
|
558
|
+
|
559
|
+
def is_identity(self) -> bool:
|
560
|
+
"""
|
561
|
+
If ``self`` is an identity morphism, returns ``True``.
|
562
|
+
Otherwise, ``False``.
|
563
|
+
|
564
|
+
EXAMPLES::
|
565
|
+
|
566
|
+
sage: T = simplicial_complexes.Sphere(1)
|
567
|
+
sage: G = Hom(T,T)
|
568
|
+
sage: T
|
569
|
+
Minimal triangulation of the 1-sphere
|
570
|
+
sage: j = G({0:0,1:1,2:2})
|
571
|
+
sage: j.is_identity()
|
572
|
+
True
|
573
|
+
|
574
|
+
sage: S = simplicial_complexes.Sphere(2)
|
575
|
+
sage: T = simplicial_complexes.Sphere(3)
|
576
|
+
sage: H = Hom(S,T)
|
577
|
+
sage: f = {0:0,1:1,2:2,3:3}
|
578
|
+
sage: x = H(f)
|
579
|
+
sage: x
|
580
|
+
Simplicial complex morphism:
|
581
|
+
From: Minimal triangulation of the 2-sphere
|
582
|
+
To: Minimal triangulation of the 3-sphere
|
583
|
+
Defn: 0 |--> 0
|
584
|
+
1 |--> 1
|
585
|
+
2 |--> 2
|
586
|
+
3 |--> 3
|
587
|
+
sage: x.is_identity()
|
588
|
+
False
|
589
|
+
"""
|
590
|
+
if self.domain() != self.codomain():
|
591
|
+
return False
|
592
|
+
|
593
|
+
f = {i: i for i in self.domain().vertices()}
|
594
|
+
return self._vertex_dictionary == f
|
595
|
+
|
596
|
+
def fiber_product(self, other, rename_vertices=True):
|
597
|
+
"""
|
598
|
+
Fiber product of ``self`` and ``other``.
|
599
|
+
|
600
|
+
Both morphisms should have
|
601
|
+
the same codomain. The method returns a morphism of simplicial
|
602
|
+
complexes, which is the morphism from the space of the fiber product
|
603
|
+
to the codomain.
|
604
|
+
|
605
|
+
EXAMPLES::
|
606
|
+
|
607
|
+
sage: S = SimplicialComplex([[0,1],[1,2]], is_mutable=False)
|
608
|
+
sage: T = SimplicialComplex([[0,2],[1]], is_mutable=False)
|
609
|
+
sage: U = SimplicialComplex([[0,1],[2]], is_mutable=False)
|
610
|
+
sage: H = Hom(S,U)
|
611
|
+
sage: G = Hom(T,U)
|
612
|
+
sage: f = {0:0,1:1,2:0}
|
613
|
+
sage: g = {0:0,1:1,2:1}
|
614
|
+
sage: x = H(f)
|
615
|
+
sage: y = G(g)
|
616
|
+
sage: z = x.fiber_product(y)
|
617
|
+
sage: z
|
618
|
+
Simplicial complex morphism:
|
619
|
+
From: Simplicial complex with 4 vertices and facets {...}
|
620
|
+
To: Simplicial complex with vertex set (0, 1, 2) and facets {(2,), (0, 1)}
|
621
|
+
Defn: L0R0 |--> 0
|
622
|
+
L1R1 |--> 1
|
623
|
+
L1R2 |--> 1
|
624
|
+
L2R0 |--> 0
|
625
|
+
"""
|
626
|
+
if self.codomain() != other.codomain():
|
627
|
+
raise ValueError("self and other must have the same codomain")
|
628
|
+
X = self.domain().product(other.domain(), rename_vertices=rename_vertices)
|
629
|
+
v = []
|
630
|
+
f = {}
|
631
|
+
eff1 = self.domain().vertices()
|
632
|
+
eff2 = other.domain().vertices()
|
633
|
+
for i in eff1:
|
634
|
+
for j in eff2:
|
635
|
+
if self(Simplex([i])) == other(Simplex([j])):
|
636
|
+
if rename_vertices:
|
637
|
+
v.append("L"+str(i)+"R"+str(j))
|
638
|
+
f["L"+str(i)+"R"+str(j)] = self._vertex_dictionary[i]
|
639
|
+
else:
|
640
|
+
v.append((i, j))
|
641
|
+
f[(i, j)] = self._vertex_dictionary[i]
|
642
|
+
return SimplicialComplexMorphism(f, X.generated_subcomplex(v), self.codomain())
|
643
|
+
|
644
|
+
def mapping_torus(self):
|
645
|
+
r"""
|
646
|
+
The mapping torus of a simplicial complex endomorphism.
|
647
|
+
|
648
|
+
The mapping torus is the simplicial complex formed by taking
|
649
|
+
the product of the domain of ``self`` with a `4` point
|
650
|
+
interval `[I_0, I_1, I_2, I_3]` and identifying vertices of
|
651
|
+
the form `(I_0, v)` with `(I_3, w)` where `w` is the image of
|
652
|
+
`v` under the given morphism.
|
653
|
+
|
654
|
+
See :wikipedia:`Mapping torus`
|
655
|
+
|
656
|
+
EXAMPLES::
|
657
|
+
|
658
|
+
sage: C = simplicial_complexes.Sphere(1) # Circle
|
659
|
+
sage: T = Hom(C,C).identity().mapping_torus() ; T # Torus
|
660
|
+
Simplicial complex with 9 vertices and 18 facets
|
661
|
+
sage: T.homology() == simplicial_complexes.Torus().homology() # needs sage.modules
|
662
|
+
True
|
663
|
+
|
664
|
+
sage: f = Hom(C,C)({0:0, 1:2, 2:1})
|
665
|
+
sage: K = f.mapping_torus(); K # Klein Bottle
|
666
|
+
Simplicial complex with 9 vertices and 18 facets
|
667
|
+
sage: K.homology() == simplicial_complexes.KleinBottle().homology() # needs sage.modules
|
668
|
+
True
|
669
|
+
|
670
|
+
TESTS::
|
671
|
+
|
672
|
+
sage: g = Hom(simplicial_complexes.Simplex([1]),C)({1:0})
|
673
|
+
sage: g.mapping_torus()
|
674
|
+
Traceback (most recent call last):
|
675
|
+
...
|
676
|
+
ValueError: self must have the same domain and codomain
|
677
|
+
"""
|
678
|
+
if self.domain() != self.codomain():
|
679
|
+
raise ValueError("self must have the same domain and codomain")
|
680
|
+
map_dict = self._vertex_dictionary
|
681
|
+
interval = SimplicialComplex([["I0", "I1"], ["I1", "I2"]])
|
682
|
+
product = interval.product(self.domain(), False)
|
683
|
+
facets = list(product.maximal_faces())
|
684
|
+
for facet in self.domain()._facets:
|
685
|
+
left = [("I0", v) for v in facet]
|
686
|
+
right = [("I2", map_dict[v]) for v in facet]
|
687
|
+
facets.extend(tuple(left[:i + 1] + right[i:])
|
688
|
+
for i in range(facet.dimension() + 1))
|
689
|
+
return SimplicialComplex(facets)
|
690
|
+
|
691
|
+
def induced_homology_morphism(self, base_ring=None, cohomology=False):
|
692
|
+
"""
|
693
|
+
Return the map in (co)homology induced by this map.
|
694
|
+
|
695
|
+
INPUT:
|
696
|
+
|
697
|
+
- ``base_ring`` -- must be a field (default: ``QQ``)
|
698
|
+
|
699
|
+
- ``cohomology`` -- boolean (default: ``False``); if
|
700
|
+
``True``, the map induced in cohomology rather than homology
|
701
|
+
|
702
|
+
EXAMPLES::
|
703
|
+
|
704
|
+
sage: S = simplicial_complexes.Sphere(1)
|
705
|
+
sage: T = S.product(S, is_mutable=False)
|
706
|
+
sage: H = Hom(S,T)
|
707
|
+
sage: diag = H.diagonal_morphism()
|
708
|
+
sage: h = diag.induced_homology_morphism(QQ); h # needs sage.modules
|
709
|
+
Graded vector space morphism:
|
710
|
+
From: Homology module of
|
711
|
+
Minimal triangulation of the 1-sphere over Rational Field
|
712
|
+
To: Homology module of
|
713
|
+
Simplicial complex with 9 vertices and 18 facets over Rational Field
|
714
|
+
Defn: induced by:
|
715
|
+
Simplicial complex morphism:
|
716
|
+
From: Minimal triangulation of the 1-sphere
|
717
|
+
To: Simplicial complex with 9 vertices and 18 facets
|
718
|
+
Defn: 0 |--> L0R0
|
719
|
+
1 |--> L1R1
|
720
|
+
2 |--> L2R2
|
721
|
+
|
722
|
+
We can view the matrix form for the homomorphism::
|
723
|
+
|
724
|
+
sage: h.to_matrix(0) # in degree 0 # needs sage.modules
|
725
|
+
[1]
|
726
|
+
sage: h.to_matrix(1) # in degree 1 # needs sage.modules
|
727
|
+
[1]
|
728
|
+
[1]
|
729
|
+
sage: h.to_matrix() # the entire homomorphism # needs sage.modules
|
730
|
+
[1|0]
|
731
|
+
[-+-]
|
732
|
+
[0|1]
|
733
|
+
[0|1]
|
734
|
+
[-+-]
|
735
|
+
[0|0]
|
736
|
+
|
737
|
+
The map on cohomology should be dual to the map on homology::
|
738
|
+
|
739
|
+
sage: coh = diag.induced_homology_morphism(QQ, cohomology=True) # needs sage.modules
|
740
|
+
sage: coh.to_matrix(1) # needs sage.modules
|
741
|
+
[1 1]
|
742
|
+
sage: h.to_matrix() == coh.to_matrix().transpose() # needs sage.modules
|
743
|
+
True
|
744
|
+
|
745
|
+
We can evaluate the map on (co)homology classes::
|
746
|
+
|
747
|
+
sage: x,y = list(T.cohomology_ring(QQ).basis(1)) # needs sage.modules
|
748
|
+
sage: coh(x) # needs sage.modules
|
749
|
+
h^{1,0}
|
750
|
+
sage: coh(2*x + 3*y) # needs sage.modules
|
751
|
+
5*h^{1,0}
|
752
|
+
|
753
|
+
Note that the complexes must be immutable for this to
|
754
|
+
work. Many, but not all, complexes are immutable when
|
755
|
+
constructed::
|
756
|
+
|
757
|
+
sage: S.is_immutable()
|
758
|
+
True
|
759
|
+
sage: S.barycentric_subdivision().is_immutable()
|
760
|
+
False
|
761
|
+
sage: S2 = S.suspension()
|
762
|
+
sage: S2.is_immutable()
|
763
|
+
False
|
764
|
+
sage: h = Hom(S, S2)({0: 0, 1: 1, 2: 2}).induced_homology_morphism() # needs sage.modules
|
765
|
+
Traceback (most recent call last):
|
766
|
+
...
|
767
|
+
ValueError: the domain and codomain complexes must be immutable
|
768
|
+
sage: S2.set_immutable(); S2.is_immutable()
|
769
|
+
True
|
770
|
+
sage: h = Hom(S, S2)({0: 0, 1: 1, 2: 2}).induced_homology_morphism() # needs sage.modules
|
771
|
+
"""
|
772
|
+
from sage.homology.homology_morphism import InducedHomologyMorphism
|
773
|
+
return InducedHomologyMorphism(self, base_ring, cohomology)
|
774
|
+
|
775
|
+
def is_contiguous_to(self, other):
|
776
|
+
r"""
|
777
|
+
Return ``True`` if ``self`` is contiguous to ``other``.
|
778
|
+
|
779
|
+
Two morphisms `f_0, f_1: K \to L` are *contiguous* if for any
|
780
|
+
simplex `\sigma \in K`, the union `f_0(\sigma) \cup
|
781
|
+
f_1(\sigma)` is a simplex in `L`. This is not a transitive
|
782
|
+
relation, but it induces an equivalence relation on simplicial
|
783
|
+
maps: `f` is equivalent to `g` if there is a finite sequence
|
784
|
+
`f_0 = f`, `f_1`, ..., `f_n = g` such that `f_i` and `f_{i+1}`
|
785
|
+
are contiguous for each `i`.
|
786
|
+
|
787
|
+
This is related to maps being homotopic: if they are
|
788
|
+
contiguous, then they induce homotopic maps on the geometric
|
789
|
+
realizations. Given two homotopic maps on the geometric
|
790
|
+
realizations, then after barycentrically subdividing `n` times
|
791
|
+
for some `n`, the maps have simplicial approximations which
|
792
|
+
are in the same contiguity class. (This last fact is only true
|
793
|
+
if the domain is a *finite* simplicial complex, by the way.)
|
794
|
+
|
795
|
+
See Section 3.5 of Spanier [Spa1966]_ for details.
|
796
|
+
|
797
|
+
ALGORITHM:
|
798
|
+
|
799
|
+
It is enough to check when `\sigma` ranges over the facets.
|
800
|
+
|
801
|
+
INPUT:
|
802
|
+
|
803
|
+
- ``other`` -- a simplicial complex morphism with the same
|
804
|
+
domain and codomain as ``self``
|
805
|
+
|
806
|
+
EXAMPLES::
|
807
|
+
|
808
|
+
sage: K = simplicial_complexes.Simplex(1)
|
809
|
+
sage: L = simplicial_complexes.Sphere(1)
|
810
|
+
sage: H = Hom(K, L)
|
811
|
+
sage: f = H({0: 0, 1: 1})
|
812
|
+
sage: g = H({0: 0, 1: 0})
|
813
|
+
sage: f.is_contiguous_to(f)
|
814
|
+
True
|
815
|
+
sage: f.is_contiguous_to(g)
|
816
|
+
True
|
817
|
+
sage: h = H({0: 1, 1: 2})
|
818
|
+
sage: f.is_contiguous_to(h)
|
819
|
+
False
|
820
|
+
|
821
|
+
TESTS::
|
822
|
+
|
823
|
+
sage: one = Hom(K,K).identity()
|
824
|
+
sage: one.is_contiguous_to(f)
|
825
|
+
False
|
826
|
+
sage: one.is_contiguous_to(3) # nonsensical input
|
827
|
+
False
|
828
|
+
"""
|
829
|
+
if not isinstance(other, SimplicialComplexMorphism):
|
830
|
+
return False
|
831
|
+
if self.codomain() != other.codomain() or self.domain() != other.domain():
|
832
|
+
return False
|
833
|
+
domain = self.domain()
|
834
|
+
codomain = self.codomain()
|
835
|
+
return all(Simplex(self(sigma).set().union(other(sigma))) in codomain
|
836
|
+
for sigma in domain.facets())
|