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,744 @@
|
|
1
|
+
# sage_setup: distribution = sagemath-graphs
|
2
|
+
# sage.doctest: needs sage.graphs
|
3
|
+
r"""
|
4
|
+
Finite filtered complexes
|
5
|
+
|
6
|
+
AUTHORS:
|
7
|
+
|
8
|
+
- Guillaume Rousseau (2021-05)
|
9
|
+
|
10
|
+
This module implements the basic structures of finite filtered complexes.
|
11
|
+
A filtered complex is a simplicial complex, where each simplex is given
|
12
|
+
a weight, or "filtration value", such that the weight of a simplex is
|
13
|
+
greater than the weight of each of its faces.
|
14
|
+
|
15
|
+
The algorithm used in this module comes from [ZC2005]_.
|
16
|
+
|
17
|
+
EXAMPLES::
|
18
|
+
|
19
|
+
sage: FilteredSimplicialComplex([([0], 0), ([1], 0), ([0, 1], 1)])
|
20
|
+
Filtered complex on vertex set (0, 1) and
|
21
|
+
with simplices ((0,) : 0), ((1,) : 0), ((0, 1) : 1)
|
22
|
+
|
23
|
+
Sage can compute persistent homology of simplicial complexes::
|
24
|
+
|
25
|
+
sage: X = FilteredSimplicialComplex([([0], 0), ([1], 0), ([0, 1], 1)])
|
26
|
+
sage: X.persistence_intervals(0) # needs sage.modules
|
27
|
+
[(0, 1), (0, +Infinity)]
|
28
|
+
|
29
|
+
FilteredSimplicialComplex objects are mutable. Filtration values can be
|
30
|
+
set with the ``filtration`` method as follows::
|
31
|
+
|
32
|
+
sage: X = FilteredSimplicialComplex() # returns an empty complex
|
33
|
+
sage: X.persistence_intervals(1) # needs sage.modules
|
34
|
+
[]
|
35
|
+
sage: X.filtration(Simplex([0, 2]), 0) # recursively adds faces
|
36
|
+
sage: X.filtration(Simplex([0, 1]), 0)
|
37
|
+
sage: X.filtration(Simplex([1, 2]), 0)
|
38
|
+
sage: X.filtration(Simplex([0, 1, 2]), 1) # closes the circle
|
39
|
+
sage: X.persistence_intervals(1) # needs sage.modules
|
40
|
+
[(0, 1)]
|
41
|
+
|
42
|
+
The filtration value of a simplex can be accessed as well with the
|
43
|
+
``filtration`` method, by not specifying a filtration value in
|
44
|
+
the arguments. If the simplex is not in the complex, this returns
|
45
|
+
``None``::
|
46
|
+
|
47
|
+
sage: X = FilteredSimplicialComplex([([0], 0), ([1], 0), ([0,1], 1)])
|
48
|
+
sage: X.filtration(Simplex([0]))
|
49
|
+
0
|
50
|
+
sage: X.filtration(Simplex([1,2])) is None
|
51
|
+
True
|
52
|
+
|
53
|
+
Filtration values can be accessed with function call and list
|
54
|
+
syntax as follows::
|
55
|
+
|
56
|
+
sage: X = FilteredSimplicialComplex([([0], 0), ([1], 0), ([0,1], 1)])
|
57
|
+
sage: s_1 = Simplex([0])
|
58
|
+
sage: X[s_1]
|
59
|
+
0
|
60
|
+
sage: X(Simplex([0,1]))
|
61
|
+
1
|
62
|
+
sage: X(Simplex(['baba']))
|
63
|
+
<BLANKLINE>
|
64
|
+
|
65
|
+
It is also possible to set the filtration value of a simplex with
|
66
|
+
the ``insert`` method, which takes as argument a list of vertices
|
67
|
+
rather than a ``Simplex``. This can make code more readable / clear::
|
68
|
+
|
69
|
+
sage: X = FilteredSimplicialComplex()
|
70
|
+
sage: X.insert(['a'], 0)
|
71
|
+
sage: X.insert(['b', 'c'], 1)
|
72
|
+
sage: X
|
73
|
+
Filtered complex on vertex set ('a', 'b', 'c') and with simplices
|
74
|
+
(('a',) : 0), (('c',) : 1), (('b',) : 1), (('b', 'c') : 1)
|
75
|
+
"""
|
76
|
+
|
77
|
+
# ****************************************************************************
|
78
|
+
# Copyright (C) 2013 GUILLAUME ROUSSEAU <guillaume.rousseau@ens-lyon.fr>
|
79
|
+
#
|
80
|
+
# This program is free software: you can redistribute it and/or modify
|
81
|
+
# it under the terms of the GNU General Public License as published by
|
82
|
+
# the Free Software Foundation, either version 2 of the License, or
|
83
|
+
# (at your option) any later version.
|
84
|
+
# https://www.gnu.org/licenses/
|
85
|
+
# ****************************************************************************
|
86
|
+
|
87
|
+
from sage.misc.cachefunc import cached_method
|
88
|
+
from sage.misc.lazy_import import lazy_import
|
89
|
+
from sage.rings.integer import Integer
|
90
|
+
from sage.rings.infinity import infinity
|
91
|
+
from sage.structure.sage_object import SageObject
|
92
|
+
from sage.topology.simplicial_complex import Simplex, SimplicialComplex
|
93
|
+
|
94
|
+
lazy_import('sage.modules.free_module', 'FreeModule')
|
95
|
+
lazy_import('sage.rings.finite_rings.finite_field_constructor', 'GF')
|
96
|
+
|
97
|
+
|
98
|
+
class FilteredSimplicialComplex(SageObject):
|
99
|
+
r"""
|
100
|
+
Define a filtered complex.
|
101
|
+
|
102
|
+
INPUT:
|
103
|
+
|
104
|
+
- ``simplices`` -- list of simplices and filtration values
|
105
|
+
- ``verbose`` -- boolean (default: ``False``); if ``True``, any change to
|
106
|
+
the filtration value of a simplex will be printed
|
107
|
+
|
108
|
+
``simplices`` should be a list of tuples ``(l, v)``, where
|
109
|
+
``l`` is a list of vertices and ``v`` is the corresponding
|
110
|
+
filtration value.
|
111
|
+
|
112
|
+
EXAMPLES::
|
113
|
+
|
114
|
+
sage: FilteredSimplicialComplex([([0], 0), ([1], 0), ([2], 1), ([0,1], 2.27)])
|
115
|
+
Filtered complex on vertex set (0, 1, 2) and with simplices
|
116
|
+
((0,) : 0), ((1,) : 0), ((2,) : 1), ((0, 1) : 2.27000000000000)
|
117
|
+
"""
|
118
|
+
def __init__(self, simplices=[], verbose=False):
|
119
|
+
"""
|
120
|
+
Initialize ``self``.
|
121
|
+
|
122
|
+
EXAMPLES::
|
123
|
+
|
124
|
+
sage: X = FilteredSimplicialComplex([([0], 0), ([1], 0), ([2], 1), ([0,1], 2.27)])
|
125
|
+
sage: TestSuite(X).run()
|
126
|
+
"""
|
127
|
+
# _vertices is the set of vertices on which the complex
|
128
|
+
# is constructed
|
129
|
+
self._vertices = set()
|
130
|
+
|
131
|
+
# _filtration_dict has simplices as keys
|
132
|
+
# and entries are corresponding filtration values
|
133
|
+
self._filtration_dict = {}
|
134
|
+
self._dimension = 0
|
135
|
+
self._max_value = 0
|
136
|
+
|
137
|
+
# when _verbose is set to True, insertion
|
138
|
+
# will warn the user when something non-trivial
|
139
|
+
# happens.
|
140
|
+
self._verbose = verbose
|
141
|
+
|
142
|
+
# Insert all simplices in the initial list
|
143
|
+
for l, v in simplices:
|
144
|
+
self.insert(l, v)
|
145
|
+
|
146
|
+
def __eq__(self, other):
|
147
|
+
"""
|
148
|
+
Check equality.
|
149
|
+
|
150
|
+
EXAMPLES::
|
151
|
+
|
152
|
+
sage: X = FilteredSimplicialComplex([([0], 0), ([1], 0), ([2], 1), ([0,1], 2.27)])
|
153
|
+
sage: Y = FilteredSimplicialComplex()
|
154
|
+
sage: Y.insert([0], 0)
|
155
|
+
sage: Y.insert([1], 0)
|
156
|
+
sage: Y.insert([2], 1)
|
157
|
+
sage: Y.insert([0,1], 2.27)
|
158
|
+
sage: X == Y
|
159
|
+
True
|
160
|
+
sage: Y.filtration([1,2], 2)
|
161
|
+
sage: X == Y
|
162
|
+
False
|
163
|
+
|
164
|
+
sage: Y = FilteredSimplicialComplex([([0], 0), ([1], 0), ([2], 1), ([0,1], 2)])
|
165
|
+
sage: X == Y
|
166
|
+
False
|
167
|
+
"""
|
168
|
+
return (isinstance(other, FilteredSimplicialComplex)
|
169
|
+
and self._vertices == other._vertices
|
170
|
+
and self._filtration_dict == other._filtration_dict)
|
171
|
+
|
172
|
+
def __ne__(self, other):
|
173
|
+
"""
|
174
|
+
Check inequality.
|
175
|
+
|
176
|
+
EXAMPLES::
|
177
|
+
|
178
|
+
sage: X = FilteredSimplicialComplex([([0], 0), ([1], 0), ([2], 1), ([0,1], 2.27)])
|
179
|
+
sage: Y = FilteredSimplicialComplex([([0], 0), ([1], 0), ([2], 1), ([0,1], 3)])
|
180
|
+
sage: X != Y
|
181
|
+
True
|
182
|
+
sage: Y.filtration([0,1], 2.27)
|
183
|
+
sage: X != Y
|
184
|
+
False
|
185
|
+
"""
|
186
|
+
return not (self == other)
|
187
|
+
|
188
|
+
def _get_value(self, s):
|
189
|
+
r"""
|
190
|
+
Return the filtration value of a simplex ``s`` in the complex.
|
191
|
+
|
192
|
+
EXAMPLES::
|
193
|
+
|
194
|
+
sage: X = FilteredSimplicialComplex([([0], 1), ([1], 2)])
|
195
|
+
sage: X._get_value(Simplex([0]))
|
196
|
+
1
|
197
|
+
|
198
|
+
This also works for the call and getitem syntax as a shorthand::
|
199
|
+
|
200
|
+
sage: X(Simplex([0]))
|
201
|
+
1
|
202
|
+
sage: X[Simplex([0])]
|
203
|
+
1
|
204
|
+
"""
|
205
|
+
if s in self._filtration_dict:
|
206
|
+
return self._filtration_dict[s]
|
207
|
+
else:
|
208
|
+
return None
|
209
|
+
|
210
|
+
__call__ = _get_value
|
211
|
+
__getitem__ = _get_value
|
212
|
+
|
213
|
+
def _insert(self, simplex, filtration_value):
|
214
|
+
r"""
|
215
|
+
Add a simplex to the complex.
|
216
|
+
|
217
|
+
All faces of the simplex are added recursively if they are
|
218
|
+
not already present, with the same value.
|
219
|
+
If the simplex is already present, and the new value is lower
|
220
|
+
than its current value in the complex, the value gets updated,
|
221
|
+
otherwise it does not change. This propagates recursively to faces.
|
222
|
+
|
223
|
+
If verbose has been enabled, this method will describe what it
|
224
|
+
is doing during an insertion.
|
225
|
+
|
226
|
+
INPUT:
|
227
|
+
|
228
|
+
- ``simplex`` -- :class:`Simplex`; simplex to be inserted
|
229
|
+
- ``filtration_value`` -- value of the simplex
|
230
|
+
|
231
|
+
EXAMPLES::
|
232
|
+
|
233
|
+
sage: X = FilteredSimplicialComplex()
|
234
|
+
sage: X._insert(Simplex([0]), 3)
|
235
|
+
sage: X
|
236
|
+
Filtered complex on vertex set (0,) and with simplices ((0,) : 3)
|
237
|
+
"""
|
238
|
+
# Keep track of whether the simplex is already in the complex
|
239
|
+
# and if it should be updated or not
|
240
|
+
curr_value = self[simplex]
|
241
|
+
if curr_value is not None:
|
242
|
+
if self._verbose:
|
243
|
+
print("Face {} is already in the complex.".format(simplex))
|
244
|
+
if curr_value > filtration_value:
|
245
|
+
if self._verbose:
|
246
|
+
verbose_string = "However its value is {}".format(curr_value)
|
247
|
+
verbose_string += ": updating it to {}".format(filtration_value)
|
248
|
+
print(verbose_string)
|
249
|
+
self._filtration_dict.pop(simplex)
|
250
|
+
else:
|
251
|
+
if self._verbose:
|
252
|
+
print("Its value is {}: keeping it that way".format(curr_value))
|
253
|
+
return
|
254
|
+
|
255
|
+
# check that all faces are in the complex already.
|
256
|
+
# If not, warn the user and add faces (recursively)
|
257
|
+
faces = simplex.faces()
|
258
|
+
if simplex.dimension() > 0:
|
259
|
+
for f in faces:
|
260
|
+
if self._verbose:
|
261
|
+
print("Also inserting face {} with value {}".format(f, filtration_value))
|
262
|
+
self._insert(f, filtration_value)
|
263
|
+
|
264
|
+
self._filtration_dict[simplex] = filtration_value
|
265
|
+
self._dimension = max(self._dimension, simplex.dimension())
|
266
|
+
self._max_value = max(self._max_value, filtration_value)
|
267
|
+
self._vertices.update(simplex.set())
|
268
|
+
self._persistent_homology.clear_cache()
|
269
|
+
|
270
|
+
def insert(self, vertex_list, filtration_value):
|
271
|
+
r"""
|
272
|
+
Add a simplex to the complex.
|
273
|
+
|
274
|
+
All faces of the simplex are added recursively if they are
|
275
|
+
not already present, with the same value.
|
276
|
+
If the simplex is already present, and the new value is lower
|
277
|
+
than its current value in the complex, the value gets updated,
|
278
|
+
otherwise it does not change. This propagates recursively to faces.
|
279
|
+
|
280
|
+
If verbose has been enabled, this method will describe what it
|
281
|
+
is doing during an insertion.
|
282
|
+
|
283
|
+
INPUT:
|
284
|
+
|
285
|
+
- ``vertex_list`` -- list of vertices
|
286
|
+
- ``filtration_value`` -- desired value of the simplex to be added
|
287
|
+
|
288
|
+
EXAMPLES::
|
289
|
+
|
290
|
+
sage: X = FilteredSimplicialComplex()
|
291
|
+
sage: X.insert(Simplex([0]),3)
|
292
|
+
sage: X
|
293
|
+
Filtered complex on vertex set (0,) and with simplices ((0,) : 3)
|
294
|
+
|
295
|
+
If the verbose parameter was set to true, this method will print
|
296
|
+
some info::
|
297
|
+
|
298
|
+
sage: X = FilteredSimplicialComplex(verbose=True)
|
299
|
+
sage: X.insert(Simplex([0, 1]), 2)
|
300
|
+
Also inserting face (1,) with value 2
|
301
|
+
Also inserting face (0,) with value 2
|
302
|
+
sage: X.insert(Simplex([0]),1)
|
303
|
+
Face (0,) is already in the complex.
|
304
|
+
However its value is 2: updating it to 1
|
305
|
+
sage: X.insert(Simplex([0]), 77)
|
306
|
+
Face (0,) is already in the complex.
|
307
|
+
Its value is 1: keeping it that way
|
308
|
+
"""
|
309
|
+
self._insert(Simplex(vertex_list), filtration_value)
|
310
|
+
|
311
|
+
def filtration(self, s, filtration_value=None):
|
312
|
+
r"""
|
313
|
+
Set filtration value of a simplex, or return value
|
314
|
+
of existing simplex.
|
315
|
+
|
316
|
+
INPUT:
|
317
|
+
|
318
|
+
- ``s`` -- :class:`Simplex` for which to set or obtain the
|
319
|
+
value of
|
320
|
+
- ``filtration_value`` -- (optional) filtration value
|
321
|
+
for the simplex
|
322
|
+
|
323
|
+
If no filtration value is specified, this returns the value of
|
324
|
+
the simplex in the complex. If the simplex is not in the complex,
|
325
|
+
this returns ``None``.
|
326
|
+
|
327
|
+
If ``filtration_value`` is set, this function inserts the
|
328
|
+
simplex into the complex with the specified value.
|
329
|
+
See documentation of :meth:`insert` for more details.
|
330
|
+
|
331
|
+
EXAMPLES::
|
332
|
+
|
333
|
+
sage: X = FilteredSimplicialComplex([([0], 0), ([1], 1)])
|
334
|
+
sage: X.filtration(Simplex([0, 1])) is None
|
335
|
+
True
|
336
|
+
sage: X.filtration(Simplex([0, 1]), 2)
|
337
|
+
sage: X.filtration([0, 1])
|
338
|
+
2
|
339
|
+
"""
|
340
|
+
s = Simplex(s)
|
341
|
+
if filtration_value is None:
|
342
|
+
return self._get_value(s)
|
343
|
+
else:
|
344
|
+
self._insert(s, filtration_value)
|
345
|
+
|
346
|
+
def prune(self, threshold):
|
347
|
+
r"""
|
348
|
+
Return a copy of the filtered complex, where simplices above
|
349
|
+
the threshold value have been removed.
|
350
|
+
|
351
|
+
INPUT:
|
352
|
+
|
353
|
+
- ``threshold`` -- a real value, above which simplices are discarded
|
354
|
+
|
355
|
+
Simplices with filtration value exactly equal to ``threshold``
|
356
|
+
are kept in the result.
|
357
|
+
|
358
|
+
EXAMPLES::
|
359
|
+
|
360
|
+
sage: a = FilteredSimplicialComplex()
|
361
|
+
sage: a.insert([0], 0)
|
362
|
+
sage: a.insert([0, 1], 1)
|
363
|
+
sage: a.insert([0, 2], 2)
|
364
|
+
sage: b = a.prune(1)
|
365
|
+
sage: b
|
366
|
+
Filtered complex on vertex set (0, 1) and
|
367
|
+
with simplices ((0,) : 0), ((1,) : 1), ((0, 1) : 1)
|
368
|
+
"""
|
369
|
+
result_complex = FilteredSimplicialComplex()
|
370
|
+
for s in self._filtration_dict:
|
371
|
+
if self[s] <= threshold:
|
372
|
+
result_complex._insert(s, self[s])
|
373
|
+
|
374
|
+
return result_complex
|
375
|
+
|
376
|
+
@cached_method(key=lambda self, f, s, v: (f, s))
|
377
|
+
def _persistent_homology(self, field=2, strict=True, verbose=False):
|
378
|
+
"""
|
379
|
+
Compute the homology intervals of the complex.
|
380
|
+
|
381
|
+
INPUT:
|
382
|
+
|
383
|
+
- ``field`` -- (default: 2) prime number modulo which the homology
|
384
|
+
is computed
|
385
|
+
- ``strict`` -- boolean (default: ``True``); if ``False``, takes into account
|
386
|
+
intervals of persistence 0
|
387
|
+
- ``verbose`` -- boolean (default: ``False``); if ``True``, prints the
|
388
|
+
progress of computation
|
389
|
+
|
390
|
+
This method is called whenever Betti numbers or intervals are
|
391
|
+
computed, and the result is cached. It returns the list of
|
392
|
+
intervals.
|
393
|
+
|
394
|
+
ALGORITHM:
|
395
|
+
|
396
|
+
The computation behind persistent homology is a matrix reduction.
|
397
|
+
The algorithm implemented is described in [ZC2005]_.
|
398
|
+
|
399
|
+
EXAMPLES::
|
400
|
+
|
401
|
+
sage: X = FilteredSimplicialComplex([([0], 0), ([1], 0), ([0,1], 2)])
|
402
|
+
sage: X._persistent_homology()[0] # needs sage.modules
|
403
|
+
[(0, 2), (0, +Infinity)]
|
404
|
+
|
405
|
+
Some homology elements may have a lifespan or persistence of 0.
|
406
|
+
They are usually discarded, but can be kept if necessary::
|
407
|
+
|
408
|
+
sage: X = FilteredSimplicialComplex()
|
409
|
+
sage: X.insert([0,1],1) # opens a hole and closes it instantly
|
410
|
+
sage: X._persistent_homology(strict=False)[0] # needs sage.modules
|
411
|
+
[(1, 1), (1, +Infinity)]
|
412
|
+
|
413
|
+
REFERENCES:
|
414
|
+
|
415
|
+
- [ZC2005]_
|
416
|
+
|
417
|
+
TESTS:
|
418
|
+
|
419
|
+
This complex is used as a running example in [ZC2005]_::
|
420
|
+
|
421
|
+
sage: l = [([0], 0), ([1], 0), ([2], 1), ([3], 1), ([0, 1], 1),
|
422
|
+
....: ([1, 2], 1), ([0, 3], 2), ([2, 3], 2), ([0, 2], 3),
|
423
|
+
....: ([0, 1, 2], 4), ([0, 2, 3], 5)]
|
424
|
+
sage: X = FilteredSimplicialComplex(l)
|
425
|
+
sage: X.persistence_intervals(0) # needs sage.modules
|
426
|
+
[(0, 1), (1, 2), (0, +Infinity)]
|
427
|
+
sage: X.persistence_intervals(1) # needs sage.modules
|
428
|
+
[(3, 4), (2, 5)]
|
429
|
+
sage: X.persistence_intervals(0, strict=False) # needs sage.modules
|
430
|
+
[(0, 1), (1, 1), (1, 2), (0, +Infinity)]
|
431
|
+
"""
|
432
|
+
# first, order the simplices in lexico order
|
433
|
+
# on dimension, value and then arbitrary order
|
434
|
+
# defined by the Simplex class.
|
435
|
+
def key(s):
|
436
|
+
d = self._get_value(s)
|
437
|
+
return (s.dimension(), d, s)
|
438
|
+
simplices = list(self._filtration_dict)
|
439
|
+
simplices.sort(key=key)
|
440
|
+
|
441
|
+
# remember the index of each simplex in a dict
|
442
|
+
self._index_of_simplex = {}
|
443
|
+
n = len(simplices)
|
444
|
+
for i in range(n):
|
445
|
+
self._index_of_simplex[simplices[i]] = i
|
446
|
+
|
447
|
+
self._field_int = field
|
448
|
+
self._field = GF(field)
|
449
|
+
self._chaingroup = FreeModule(self._field, rank_or_basis_keys=simplices)
|
450
|
+
|
451
|
+
# Initialize data structures for the algo
|
452
|
+
self._marked = [False] * n
|
453
|
+
self._T = [None] * n
|
454
|
+
intervals = [[] for i in range(self._dimension + 1)]
|
455
|
+
self.pairs = []
|
456
|
+
|
457
|
+
self._strict = strict
|
458
|
+
self._verbose = verbose
|
459
|
+
|
460
|
+
if self._verbose:
|
461
|
+
print("Beginning first pass")
|
462
|
+
|
463
|
+
for j in range(n):
|
464
|
+
# if being verbose, print progress
|
465
|
+
# every 1000 simplices.
|
466
|
+
if self._verbose and j % 1000 == 0:
|
467
|
+
print('{}/{}'.format(j, n))
|
468
|
+
|
469
|
+
s = simplices[j]
|
470
|
+
d = self._remove_pivot_rows(s, simplices)
|
471
|
+
|
472
|
+
if d == 0:
|
473
|
+
self._marked[j] = True
|
474
|
+
else:
|
475
|
+
max_index = self._max_index(d)
|
476
|
+
t = simplices[max_index]
|
477
|
+
self._T[max_index] = (s, d)
|
478
|
+
self._add_interval(t, s, intervals)
|
479
|
+
|
480
|
+
if self._verbose:
|
481
|
+
print("First pass over, beginning second pass")
|
482
|
+
|
483
|
+
for j in range(n):
|
484
|
+
if self._verbose and j % 1000 == 0:
|
485
|
+
print('{}/{}'.format(j, n))
|
486
|
+
|
487
|
+
s = simplices[j]
|
488
|
+
if self._marked[j] and not self._T[j]:
|
489
|
+
self._add_interval(s, None, intervals)
|
490
|
+
|
491
|
+
if self._verbose:
|
492
|
+
print("Second pass over")
|
493
|
+
return intervals
|
494
|
+
|
495
|
+
def _add_interval(self, s, t, intervals):
|
496
|
+
r"""
|
497
|
+
Add a new interval (i.e. homology element).
|
498
|
+
|
499
|
+
This method should not be called by users, it is used in
|
500
|
+
the :meth:`_persistent_homology` method. The simplex of
|
501
|
+
death may be ``None``, in which case the interval is infinite.
|
502
|
+
|
503
|
+
INPUT:
|
504
|
+
|
505
|
+
- ``s`` -- birth simplex
|
506
|
+
- ``t`` -- death simplex
|
507
|
+
- ``intervals`` -- list of current intervals
|
508
|
+
|
509
|
+
If ``t`` is not ``None``, its dimension should be
|
510
|
+
one more than the dimension of ``s``.
|
511
|
+
|
512
|
+
TESTS::
|
513
|
+
|
514
|
+
sage: # needs sage.modules
|
515
|
+
sage: X = FilteredSimplicialComplex([([0], 0), ([1, 2], 10)])
|
516
|
+
sage: int_list = X._persistent_homology()
|
517
|
+
sage: int_list[0]
|
518
|
+
[(0, +Infinity), (10, +Infinity)]
|
519
|
+
sage: X._add_interval(Simplex([0]), Simplex([1, 2]), int_list)
|
520
|
+
sage: int_list[0]
|
521
|
+
[(0, +Infinity), (10, +Infinity), (0, 10)]
|
522
|
+
|
523
|
+
Infinite interval::
|
524
|
+
|
525
|
+
sage: int_list2 = [[],[]]
|
526
|
+
sage: X._add_interval(Simplex([1, 2]), None, int_list2) # needs sage.modules
|
527
|
+
sage: int_list2[1]
|
528
|
+
[(10, +Infinity)]
|
529
|
+
"""
|
530
|
+
# figure out dimension of homology element
|
531
|
+
# and indices of the two simplices. If the
|
532
|
+
# closing simplex is None, then the interval
|
533
|
+
# is infinite.
|
534
|
+
k = s.dimension()
|
535
|
+
i = self._filtration_dict[s]
|
536
|
+
if not t:
|
537
|
+
j = infinity
|
538
|
+
else:
|
539
|
+
j = self._filtration_dict[t]
|
540
|
+
|
541
|
+
# Only add intervals of length 0 if
|
542
|
+
# strict mode is not enabled.
|
543
|
+
if i != j or (not self._strict):
|
544
|
+
intervals[k].append((i, j))
|
545
|
+
self.pairs.append((s, t))
|
546
|
+
|
547
|
+
def _remove_pivot_rows(self, s, simplices):
|
548
|
+
r"""
|
549
|
+
Return the boundary chain of a simplex,
|
550
|
+
from which pivot elements have been removed.
|
551
|
+
|
552
|
+
This method implements the subroutine of the same name
|
553
|
+
in [ZC2005]_. This method should not be called by users,
|
554
|
+
it is used in the :meth:`_persistent_homology` method.
|
555
|
+
|
556
|
+
TESTS::
|
557
|
+
|
558
|
+
sage: l = [([0], 0), ([1], 0), ([2], 1), ([3], 1), ([0, 1], 1), ([1, 2], 1),
|
559
|
+
....: ([0, 3], 2), ([2, 3], 2), ([0, 2], 3), ([0, 1, 2], 4)]
|
560
|
+
sage: X = FilteredSimplicialComplex(l)
|
561
|
+
sage: X._persistent_homology() # needs sage.modules
|
562
|
+
[[(0, 1), (1, 2), (0, +Infinity)], [(3, 4), (2, +Infinity)], []]
|
563
|
+
sage: X._remove_pivot_rows(Simplex([0,1,2]), list(X._filtration_dict)) # needs sage.modules
|
564
|
+
0
|
565
|
+
sage: X.insert([0,2,3],5)
|
566
|
+
sage: X._remove_pivot_rows(Simplex([0,2,3]), list(X._filtration_dict)) # needs sage.modules
|
567
|
+
B[(2, 3)]
|
568
|
+
"""
|
569
|
+
d = self._chaingroup()
|
570
|
+
# Handle the case when the simplex is a vertex
|
571
|
+
if s.dimension() == 0:
|
572
|
+
return d
|
573
|
+
|
574
|
+
# Initialize the boundary chain
|
575
|
+
for i, f in enumerate(s.faces()):
|
576
|
+
d += (-1)**i * self._chaingroup(f)
|
577
|
+
|
578
|
+
# Remove all unmarked elements
|
579
|
+
for s, x_s in d:
|
580
|
+
j = self._index_of_simplex[s]
|
581
|
+
if not self._marked[j]:
|
582
|
+
d = d - x_s * self._chaingroup(s)
|
583
|
+
|
584
|
+
# Reduce d until it is empty or until the simplex
|
585
|
+
# with maximum index in the complex among all
|
586
|
+
# nonzero terms is not in T.
|
587
|
+
while d != 0:
|
588
|
+
max_index = self._max_index(d)
|
589
|
+
t = simplices[max_index]
|
590
|
+
|
591
|
+
if not self._T[max_index]:
|
592
|
+
break
|
593
|
+
|
594
|
+
c = self._T[max_index][1]
|
595
|
+
q = c[t]
|
596
|
+
d = d - ((q**(-1)) * c)
|
597
|
+
|
598
|
+
return d
|
599
|
+
|
600
|
+
def _max_index(self, d):
|
601
|
+
r"""
|
602
|
+
Return the maximal index of all simplices with nonzero
|
603
|
+
coefficient in ``d``.
|
604
|
+
|
605
|
+
This method is called in :meth:`_remove_pivot_rows` and
|
606
|
+
:meth:`_persistent_homology`. It should not be called by users
|
607
|
+
outside of those methods.
|
608
|
+
|
609
|
+
TESTS::
|
610
|
+
|
611
|
+
sage: # needs sage.modules
|
612
|
+
sage: X = FilteredSimplicialComplex([([0], 0), ([1], 5), ([0, 1], 18), ([0, 2, 3], 32)])
|
613
|
+
sage: X._persistent_homology()
|
614
|
+
[[(5, 18), (0, +Infinity)], [], []]
|
615
|
+
sage: a = X._chaingroup(Simplex([0, 1]))
|
616
|
+
sage: b = X._chaingroup(Simplex([0, 3]))
|
617
|
+
sage: d = a + b
|
618
|
+
sage: X._max_index(d)
|
619
|
+
6
|
620
|
+
"""
|
621
|
+
currmax = -1
|
622
|
+
for s, x_s in d:
|
623
|
+
j = self._index_of_simplex[s]
|
624
|
+
currmax = max(j, currmax)
|
625
|
+
return currmax
|
626
|
+
|
627
|
+
def persistence_intervals(self, dimension, field=2, strict=True, verbose=None):
|
628
|
+
r"""
|
629
|
+
Return the list of `d`-dimensional homology elements.
|
630
|
+
|
631
|
+
INPUT:
|
632
|
+
|
633
|
+
- ``dimension`` -- integer; dimension `d` for which to
|
634
|
+
return intervals
|
635
|
+
- ``field`` -- prime number (default: 2); modulo which persistent
|
636
|
+
homology is computed
|
637
|
+
- ``strict`` -- boolean (default: ``True``); if ``False``, takes into account
|
638
|
+
intervals of persistence 0
|
639
|
+
- ``verbose`` -- (optional) if ``True``, print the steps of the
|
640
|
+
persistent homology computation; the default is the verbosity
|
641
|
+
of ``self``
|
642
|
+
|
643
|
+
EXAMPLES::
|
644
|
+
|
645
|
+
sage: X = FilteredSimplicialComplex([([0], 0), ([1], 1), ([0,1], 2)])
|
646
|
+
sage: X.persistence_intervals(0) # needs sage.modules
|
647
|
+
[(1, 2), (0, +Infinity)]
|
648
|
+
"""
|
649
|
+
if verbose is None:
|
650
|
+
verbose = self._verbose
|
651
|
+
intervals = self._persistent_homology(field, strict, verbose=verbose)
|
652
|
+
if dimension < len(intervals):
|
653
|
+
return intervals[dimension][:]
|
654
|
+
else:
|
655
|
+
return []
|
656
|
+
|
657
|
+
def betti_number(self, k, a, b, field=2, strict=True, verbose=None):
|
658
|
+
r"""
|
659
|
+
Return the ``k``-dimensional Betti number from ``a`` to ``a + b``.
|
660
|
+
|
661
|
+
INPUT:
|
662
|
+
|
663
|
+
- ``k`` -- the dimension for the Betti number
|
664
|
+
- ``a`` -- the lower filtration value
|
665
|
+
- ``b`` -- the size of the interval
|
666
|
+
- ``field`` -- prime number (default: 2); modulo which persistent
|
667
|
+
homology is computed
|
668
|
+
- ``strict`` -- boolean (default: ``True``); if ``False``, takes into account
|
669
|
+
intervals of persistence 0
|
670
|
+
- ``verbose`` -- (optional) if ``True``, print the steps of the
|
671
|
+
persistent homology computation; the default is the verbosity
|
672
|
+
of ``self``
|
673
|
+
|
674
|
+
The Betti number `\beta_k^{a,a+b}` counts the number of
|
675
|
+
homology elements which are alive throughout the whole
|
676
|
+
duration ``[a, a+b]``.
|
677
|
+
|
678
|
+
EXAMPLES::
|
679
|
+
|
680
|
+
sage: X = FilteredSimplicialComplex([([0], 0), ([1], 0), ([0,1], 2)])
|
681
|
+
sage: X.betti_number(0, 0.5, 1) # needs sage.modules
|
682
|
+
2
|
683
|
+
sage: X.betti_number(0, 1.5, 1) # needs sage.modules
|
684
|
+
1
|
685
|
+
|
686
|
+
If an element vanishes at time ``a + b`` exactly,
|
687
|
+
it does not count towards the Betti number::
|
688
|
+
|
689
|
+
sage: X = FilteredSimplicialComplex([([0], 0), ([1], 0), ([0,1], 2)])
|
690
|
+
sage: X.betti_number(0, 1.5, 0.5) # needs sage.modules
|
691
|
+
1
|
692
|
+
"""
|
693
|
+
if verbose is None:
|
694
|
+
verbose = self._verbose
|
695
|
+
intervals = self._persistent_homology(field, strict, verbose=verbose)
|
696
|
+
return Integer(sum(1 for i, j in intervals[k]
|
697
|
+
if (i <= a and a + b < j) and a >= 0))
|
698
|
+
|
699
|
+
def _repr_(self):
|
700
|
+
"""
|
701
|
+
Print representation.
|
702
|
+
|
703
|
+
If there are more than 10 simplices or vertices, only prints the
|
704
|
+
count for each.
|
705
|
+
|
706
|
+
EXAMPLES::
|
707
|
+
|
708
|
+
sage: X = FilteredSimplicialComplex([([0], 0), ([1], 0), ([0, 1], 1)])
|
709
|
+
sage: X
|
710
|
+
Filtered complex on vertex set (0, 1) and with simplices ((0,) : 0), ((1,) : 0), ((0, 1) : 1)
|
711
|
+
sage: X.insert([0, 1, 2, 3, 4], 8)
|
712
|
+
sage: X
|
713
|
+
Filtered complex on 5 vertices and with 31 simplices
|
714
|
+
"""
|
715
|
+
vert_count = len(self._vertices)
|
716
|
+
simp_count = len(self._filtration_dict)
|
717
|
+
if simp_count > 10 or vert_count > 10:
|
718
|
+
vertex_string = "on {} vertices".format(vert_count)
|
719
|
+
simplex_string = "with {} simplices".format(simp_count)
|
720
|
+
else:
|
721
|
+
vertex_string = "on vertex set {}".format(tuple(sorted(self._vertices)))
|
722
|
+
simplex_string = "with simplices "
|
723
|
+
simplex_list = ["({} : {})".format(s, self._filtration_dict[s]) for s in self._filtration_dict]
|
724
|
+
simplex_string += ", ".join(simplex_list)
|
725
|
+
|
726
|
+
return "Filtered complex " + vertex_string + " and " + simplex_string
|
727
|
+
|
728
|
+
def _simplicial_(self):
|
729
|
+
"""
|
730
|
+
Return the associated simplicial complex.
|
731
|
+
|
732
|
+
All simplices of the filtered simplicial complex are
|
733
|
+
included in the resulting simplicial complex.
|
734
|
+
|
735
|
+
EXAMPLES::
|
736
|
+
|
737
|
+
sage: l = [([0],0), ([1],0), ([2],1), ([3],1), ([0, 1],1), ([1, 2],1), ([0, 3],2),
|
738
|
+
....: ([2, 3],2), ([0, 2],3), ([0, 1, 2],4), ([0, 2, 3],5)]
|
739
|
+
sage: a = FilteredSimplicialComplex(l)
|
740
|
+
sage: b = SimplicialComplex(a)
|
741
|
+
sage: b
|
742
|
+
Simplicial complex with vertex set (0, 1, 2, 3) and facets {(0, 1, 2), (0, 2, 3)}
|
743
|
+
"""
|
744
|
+
return SimplicialComplex(self._filtration_dict)
|