multipers 2.2.3__cp312-cp312-win_amd64.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.
Potentially problematic release.
This version of multipers might be problematic. Click here for more details.
- multipers/__init__.py +31 -0
- multipers/_signed_measure_meta.py +430 -0
- multipers/_slicer_meta.py +212 -0
- multipers/data/MOL2.py +458 -0
- multipers/data/UCR.py +18 -0
- multipers/data/__init__.py +1 -0
- multipers/data/graphs.py +466 -0
- multipers/data/immuno_regions.py +27 -0
- multipers/data/minimal_presentation_to_st_bf.py +0 -0
- multipers/data/pytorch2simplextree.py +91 -0
- multipers/data/shape3d.py +101 -0
- multipers/data/synthetic.py +111 -0
- multipers/distances.py +198 -0
- multipers/filtration_conversions.pxd +229 -0
- multipers/filtration_conversions.pxd.tp +84 -0
- multipers/filtrations.pxd +224 -0
- multipers/function_rips.cp312-win_amd64.pyd +0 -0
- multipers/function_rips.pyx +105 -0
- multipers/grids.cp312-win_amd64.pyd +0 -0
- multipers/grids.pyx +350 -0
- multipers/gudhi/Persistence_slices_interface.h +132 -0
- multipers/gudhi/Simplex_tree_interface.h +245 -0
- multipers/gudhi/Simplex_tree_multi_interface.h +561 -0
- multipers/gudhi/cubical_to_boundary.h +59 -0
- multipers/gudhi/gudhi/Bitmap_cubical_complex.h +450 -0
- multipers/gudhi/gudhi/Bitmap_cubical_complex_base.h +1070 -0
- multipers/gudhi/gudhi/Bitmap_cubical_complex_periodic_boundary_conditions_base.h +579 -0
- multipers/gudhi/gudhi/Debug_utils.h +45 -0
- multipers/gudhi/gudhi/Fields/Multi_field.h +484 -0
- multipers/gudhi/gudhi/Fields/Multi_field_operators.h +455 -0
- multipers/gudhi/gudhi/Fields/Multi_field_shared.h +450 -0
- multipers/gudhi/gudhi/Fields/Multi_field_small.h +531 -0
- multipers/gudhi/gudhi/Fields/Multi_field_small_operators.h +507 -0
- multipers/gudhi/gudhi/Fields/Multi_field_small_shared.h +531 -0
- multipers/gudhi/gudhi/Fields/Z2_field.h +355 -0
- multipers/gudhi/gudhi/Fields/Z2_field_operators.h +376 -0
- multipers/gudhi/gudhi/Fields/Zp_field.h +420 -0
- multipers/gudhi/gudhi/Fields/Zp_field_operators.h +400 -0
- multipers/gudhi/gudhi/Fields/Zp_field_shared.h +418 -0
- multipers/gudhi/gudhi/Flag_complex_edge_collapser.h +337 -0
- multipers/gudhi/gudhi/Matrix.h +2107 -0
- multipers/gudhi/gudhi/Multi_critical_filtration.h +1038 -0
- multipers/gudhi/gudhi/Multi_persistence/Box.h +171 -0
- multipers/gudhi/gudhi/Multi_persistence/Line.h +282 -0
- multipers/gudhi/gudhi/Off_reader.h +173 -0
- multipers/gudhi/gudhi/One_critical_filtration.h +1431 -0
- multipers/gudhi/gudhi/Persistence_matrix/Base_matrix.h +769 -0
- multipers/gudhi/gudhi/Persistence_matrix/Base_matrix_with_column_compression.h +686 -0
- multipers/gudhi/gudhi/Persistence_matrix/Boundary_matrix.h +842 -0
- multipers/gudhi/gudhi/Persistence_matrix/Chain_matrix.h +1350 -0
- multipers/gudhi/gudhi/Persistence_matrix/Id_to_index_overlay.h +1105 -0
- multipers/gudhi/gudhi/Persistence_matrix/Position_to_index_overlay.h +859 -0
- multipers/gudhi/gudhi/Persistence_matrix/RU_matrix.h +910 -0
- multipers/gudhi/gudhi/Persistence_matrix/allocators/entry_constructors.h +139 -0
- multipers/gudhi/gudhi/Persistence_matrix/base_pairing.h +230 -0
- multipers/gudhi/gudhi/Persistence_matrix/base_swap.h +211 -0
- multipers/gudhi/gudhi/Persistence_matrix/boundary_cell_position_to_id_mapper.h +60 -0
- multipers/gudhi/gudhi/Persistence_matrix/boundary_face_position_to_id_mapper.h +60 -0
- multipers/gudhi/gudhi/Persistence_matrix/chain_pairing.h +136 -0
- multipers/gudhi/gudhi/Persistence_matrix/chain_rep_cycles.h +190 -0
- multipers/gudhi/gudhi/Persistence_matrix/chain_vine_swap.h +616 -0
- multipers/gudhi/gudhi/Persistence_matrix/columns/chain_column_extra_properties.h +150 -0
- multipers/gudhi/gudhi/Persistence_matrix/columns/column_dimension_holder.h +106 -0
- multipers/gudhi/gudhi/Persistence_matrix/columns/column_utilities.h +219 -0
- multipers/gudhi/gudhi/Persistence_matrix/columns/entry_types.h +327 -0
- multipers/gudhi/gudhi/Persistence_matrix/columns/heap_column.h +1140 -0
- multipers/gudhi/gudhi/Persistence_matrix/columns/intrusive_list_column.h +934 -0
- multipers/gudhi/gudhi/Persistence_matrix/columns/intrusive_set_column.h +934 -0
- multipers/gudhi/gudhi/Persistence_matrix/columns/list_column.h +980 -0
- multipers/gudhi/gudhi/Persistence_matrix/columns/naive_vector_column.h +1092 -0
- multipers/gudhi/gudhi/Persistence_matrix/columns/row_access.h +192 -0
- multipers/gudhi/gudhi/Persistence_matrix/columns/set_column.h +921 -0
- multipers/gudhi/gudhi/Persistence_matrix/columns/small_vector_column.h +1093 -0
- multipers/gudhi/gudhi/Persistence_matrix/columns/unordered_set_column.h +1012 -0
- multipers/gudhi/gudhi/Persistence_matrix/columns/vector_column.h +1244 -0
- multipers/gudhi/gudhi/Persistence_matrix/matrix_dimension_holders.h +186 -0
- multipers/gudhi/gudhi/Persistence_matrix/matrix_row_access.h +164 -0
- multipers/gudhi/gudhi/Persistence_matrix/ru_pairing.h +156 -0
- multipers/gudhi/gudhi/Persistence_matrix/ru_rep_cycles.h +376 -0
- multipers/gudhi/gudhi/Persistence_matrix/ru_vine_swap.h +540 -0
- multipers/gudhi/gudhi/Persistent_cohomology/Field_Zp.h +118 -0
- multipers/gudhi/gudhi/Persistent_cohomology/Multi_field.h +173 -0
- multipers/gudhi/gudhi/Persistent_cohomology/Persistent_cohomology_column.h +128 -0
- multipers/gudhi/gudhi/Persistent_cohomology.h +745 -0
- multipers/gudhi/gudhi/Points_off_io.h +171 -0
- multipers/gudhi/gudhi/Simple_object_pool.h +69 -0
- multipers/gudhi/gudhi/Simplex_tree/Simplex_tree_iterators.h +463 -0
- multipers/gudhi/gudhi/Simplex_tree/Simplex_tree_node_explicit_storage.h +83 -0
- multipers/gudhi/gudhi/Simplex_tree/Simplex_tree_siblings.h +106 -0
- multipers/gudhi/gudhi/Simplex_tree/Simplex_tree_star_simplex_iterators.h +277 -0
- multipers/gudhi/gudhi/Simplex_tree/hooks_simplex_base.h +62 -0
- multipers/gudhi/gudhi/Simplex_tree/indexing_tag.h +27 -0
- multipers/gudhi/gudhi/Simplex_tree/serialization_utils.h +62 -0
- multipers/gudhi/gudhi/Simplex_tree/simplex_tree_options.h +157 -0
- multipers/gudhi/gudhi/Simplex_tree.h +2794 -0
- multipers/gudhi/gudhi/Simplex_tree_multi.h +163 -0
- multipers/gudhi/gudhi/distance_functions.h +62 -0
- multipers/gudhi/gudhi/graph_simplicial_complex.h +104 -0
- multipers/gudhi/gudhi/persistence_interval.h +253 -0
- multipers/gudhi/gudhi/persistence_matrix_options.h +170 -0
- multipers/gudhi/gudhi/reader_utils.h +367 -0
- multipers/gudhi/mma_interface_coh.h +255 -0
- multipers/gudhi/mma_interface_h0.h +231 -0
- multipers/gudhi/mma_interface_matrix.h +282 -0
- multipers/gudhi/naive_merge_tree.h +575 -0
- multipers/gudhi/scc_io.h +289 -0
- multipers/gudhi/truc.h +888 -0
- multipers/io.cp312-win_amd64.pyd +0 -0
- multipers/io.pyx +711 -0
- multipers/ml/__init__.py +0 -0
- multipers/ml/accuracies.py +90 -0
- multipers/ml/convolutions.py +520 -0
- multipers/ml/invariants_with_persistable.py +79 -0
- multipers/ml/kernels.py +176 -0
- multipers/ml/mma.py +714 -0
- multipers/ml/one.py +472 -0
- multipers/ml/point_clouds.py +346 -0
- multipers/ml/signed_measures.py +1589 -0
- multipers/ml/sliced_wasserstein.py +461 -0
- multipers/ml/tools.py +113 -0
- multipers/mma_structures.cp312-win_amd64.pyd +0 -0
- multipers/mma_structures.pxd +127 -0
- multipers/mma_structures.pyx +2746 -0
- multipers/mma_structures.pyx.tp +1085 -0
- multipers/multi_parameter_rank_invariant/diff_helpers.h +93 -0
- multipers/multi_parameter_rank_invariant/euler_characteristic.h +97 -0
- multipers/multi_parameter_rank_invariant/function_rips.h +322 -0
- multipers/multi_parameter_rank_invariant/hilbert_function.h +769 -0
- multipers/multi_parameter_rank_invariant/persistence_slices.h +148 -0
- multipers/multi_parameter_rank_invariant/rank_invariant.h +369 -0
- multipers/multiparameter_edge_collapse.py +41 -0
- multipers/multiparameter_module_approximation/approximation.h +2295 -0
- multipers/multiparameter_module_approximation/combinatory.h +129 -0
- multipers/multiparameter_module_approximation/debug.h +107 -0
- multipers/multiparameter_module_approximation/euler_curves.h +0 -0
- multipers/multiparameter_module_approximation/format_python-cpp.h +286 -0
- multipers/multiparameter_module_approximation/heap_column.h +238 -0
- multipers/multiparameter_module_approximation/images.h +79 -0
- multipers/multiparameter_module_approximation/list_column.h +174 -0
- multipers/multiparameter_module_approximation/list_column_2.h +232 -0
- multipers/multiparameter_module_approximation/ru_matrix.h +347 -0
- multipers/multiparameter_module_approximation/set_column.h +135 -0
- multipers/multiparameter_module_approximation/structure_higher_dim_barcode.h +36 -0
- multipers/multiparameter_module_approximation/unordered_set_column.h +166 -0
- multipers/multiparameter_module_approximation/utilities.h +419 -0
- multipers/multiparameter_module_approximation/vector_column.h +223 -0
- multipers/multiparameter_module_approximation/vector_matrix.h +331 -0
- multipers/multiparameter_module_approximation/vineyards.h +464 -0
- multipers/multiparameter_module_approximation/vineyards_trajectories.h +649 -0
- multipers/multiparameter_module_approximation.cp312-win_amd64.pyd +0 -0
- multipers/multiparameter_module_approximation.pyx +217 -0
- multipers/pickle.py +53 -0
- multipers/plots.py +334 -0
- multipers/point_measure.cp312-win_amd64.pyd +0 -0
- multipers/point_measure.pyx +320 -0
- multipers/simplex_tree_multi.cp312-win_amd64.pyd +0 -0
- multipers/simplex_tree_multi.pxd +133 -0
- multipers/simplex_tree_multi.pyx +10335 -0
- multipers/simplex_tree_multi.pyx.tp +1935 -0
- multipers/slicer.cp312-win_amd64.pyd +0 -0
- multipers/slicer.pxd +2371 -0
- multipers/slicer.pxd.tp +214 -0
- multipers/slicer.pyx +15467 -0
- multipers/slicer.pyx.tp +914 -0
- multipers/tbb12.dll +0 -0
- multipers/tbbbind_2_5.dll +0 -0
- multipers/tbbmalloc.dll +0 -0
- multipers/tbbmalloc_proxy.dll +0 -0
- multipers/tensor/tensor.h +672 -0
- multipers/tensor.pxd +13 -0
- multipers/test.pyx +44 -0
- multipers/tests/__init__.py +57 -0
- multipers/tests/test_diff_helper.py +73 -0
- multipers/tests/test_hilbert_function.py +82 -0
- multipers/tests/test_mma.py +83 -0
- multipers/tests/test_point_clouds.py +49 -0
- multipers/tests/test_python-cpp_conversion.py +82 -0
- multipers/tests/test_signed_betti.py +181 -0
- multipers/tests/test_signed_measure.py +89 -0
- multipers/tests/test_simplextreemulti.py +221 -0
- multipers/tests/test_slicer.py +221 -0
- multipers/torch/__init__.py +1 -0
- multipers/torch/diff_grids.py +217 -0
- multipers/torch/rips_density.py +304 -0
- multipers-2.2.3.dist-info/LICENSE +21 -0
- multipers-2.2.3.dist-info/METADATA +134 -0
- multipers-2.2.3.dist-info/RECORD +189 -0
- multipers-2.2.3.dist-info/WHEEL +5 -0
- multipers-2.2.3.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
import pytest
|
|
3
|
+
|
|
4
|
+
import multipers as mp
|
|
5
|
+
import multipers.io as mio
|
|
6
|
+
from multipers.tests import assert_sm, random_st
|
|
7
|
+
|
|
8
|
+
np.random.seed(0)
|
|
9
|
+
|
|
10
|
+
st = random_st(npts=50).collapse_edges(-2, ignore_warning=True)
|
|
11
|
+
|
|
12
|
+
invariants = ["euler", "hilbert", "rank"]
|
|
13
|
+
degrees = [0, 1]
|
|
14
|
+
mass_defaults = [None, "auto"]
|
|
15
|
+
strats = [("regular_closest", 20), ("quantile", 20), ("regular", 17)]
|
|
16
|
+
|
|
17
|
+
mio._init_external_softwares()
|
|
18
|
+
mpfree_flag = mio._check_available("mpfree")
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
@pytest.mark.parametrize("invariant", invariants)
|
|
22
|
+
@pytest.mark.parametrize("degree", degrees)
|
|
23
|
+
@pytest.mark.parametrize("mass_default", mass_defaults)
|
|
24
|
+
@pytest.mark.parametrize("S", strats)
|
|
25
|
+
def test_backends(invariant, degree, mass_default, S):
|
|
26
|
+
degree = None if invariant == "euler" else degree
|
|
27
|
+
strat, r = S
|
|
28
|
+
sms = []
|
|
29
|
+
sms.append(
|
|
30
|
+
mp.signed_measure(
|
|
31
|
+
st,
|
|
32
|
+
degree=degree,
|
|
33
|
+
grid_strategy=strat,
|
|
34
|
+
resolution=r,
|
|
35
|
+
mass_default=mass_default,
|
|
36
|
+
invariant=invariant,
|
|
37
|
+
)[0]
|
|
38
|
+
)
|
|
39
|
+
sms.append(
|
|
40
|
+
mp.signed_measure(
|
|
41
|
+
st.grid_squeeze(grid_strategy=strat, resolution=r),
|
|
42
|
+
degree=degree,
|
|
43
|
+
mass_default=mass_default,
|
|
44
|
+
invariant=invariant,
|
|
45
|
+
)[0]
|
|
46
|
+
)
|
|
47
|
+
snv = mp.Slicer(st, vineyard=False)
|
|
48
|
+
sv = mp.Slicer(st, vineyard=True)
|
|
49
|
+
for s in [sv, snv]:
|
|
50
|
+
sms.append(
|
|
51
|
+
mp.signed_measure(
|
|
52
|
+
s,
|
|
53
|
+
degree=1,
|
|
54
|
+
grid_strategy=strat,
|
|
55
|
+
resolution=r,
|
|
56
|
+
mass_default=mass_default,
|
|
57
|
+
invariant=invariant,
|
|
58
|
+
)[0]
|
|
59
|
+
)
|
|
60
|
+
if invariant != "euler":
|
|
61
|
+
if not mpfree_flag:
|
|
62
|
+
pytest.skip(r"Skipping next test, as `mpfree` was not found.")
|
|
63
|
+
else:
|
|
64
|
+
for s in [sv, snv]:
|
|
65
|
+
assert s.minpres(degree=degree).is_minpres, "minpres is not minpres"
|
|
66
|
+
sms.append(
|
|
67
|
+
mp.signed_measure(
|
|
68
|
+
s.minpres(degree=degree),
|
|
69
|
+
degree=degree,
|
|
70
|
+
grid_strategy=strat,
|
|
71
|
+
resolution=r,
|
|
72
|
+
mass_default=mass_default,
|
|
73
|
+
invariant=invariant,
|
|
74
|
+
)[0]
|
|
75
|
+
)
|
|
76
|
+
sms.append(
|
|
77
|
+
mp.signed_measure(
|
|
78
|
+
st,
|
|
79
|
+
grid_strategy=strat,
|
|
80
|
+
degree=degree,
|
|
81
|
+
resolution=r,
|
|
82
|
+
mass_default=mass_default,
|
|
83
|
+
backend="mpfree",
|
|
84
|
+
invariant=invariant,
|
|
85
|
+
)[0]
|
|
86
|
+
)
|
|
87
|
+
if mass_default is not None and invariant != "rank":
|
|
88
|
+
assert sms[0][1].sum() == 0, "Did not remove all of the mass"
|
|
89
|
+
assert_sm(*sms, exact=False, max_error=0.5)
|
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
import pickle as pkl
|
|
2
|
+
|
|
3
|
+
import gudhi as gd
|
|
4
|
+
import numpy as np
|
|
5
|
+
from numpy import array
|
|
6
|
+
|
|
7
|
+
import multipers as mp
|
|
8
|
+
import pytest
|
|
9
|
+
from multipers.tests import assert_st_simplices, random_st
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def test_1():
|
|
14
|
+
st = mp.SimplexTreeMulti(num_parameters=2)
|
|
15
|
+
st.insert([0], [0, 1])
|
|
16
|
+
st.insert([1], [1, 0])
|
|
17
|
+
st.insert([0, 1], [1, 1])
|
|
18
|
+
it = [([0, 1], [1.0, 1.0]), ([0], [0.0, 1.0]), ([1], [1.0, 0.0])]
|
|
19
|
+
assert_st_simplices(st, it)
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def test_2():
|
|
23
|
+
from gudhi.rips_complex import RipsComplex
|
|
24
|
+
|
|
25
|
+
st2 = RipsComplex(points=[[0, 1], [1, 0], [0, 0]]).create_simplex_tree()
|
|
26
|
+
st2 = mp.SimplexTreeMulti(
|
|
27
|
+
st2, num_parameters=3, default_values=[1, 2]
|
|
28
|
+
) # the gudhi filtration is placed on axis 0
|
|
29
|
+
|
|
30
|
+
it = (
|
|
31
|
+
([0, 1], [np.sqrt(2), 1.0, 2.0]),
|
|
32
|
+
([0, 2], [1.0, 1.0, 2.0]),
|
|
33
|
+
([0], [0.0, 1.0, 2.0]),
|
|
34
|
+
([1, 2], [1.0, 1.0, 2.0]),
|
|
35
|
+
([1], [0.0, 1.0, 2.0]),
|
|
36
|
+
([2], [0.0, 1.0, 2.0]),
|
|
37
|
+
)
|
|
38
|
+
assert_st_simplices(st2, it)
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def test_3():
|
|
42
|
+
st = gd.SimplexTree() # usual gudhi simplextree
|
|
43
|
+
st.insert([0, 1], 1)
|
|
44
|
+
st.insert([1], 0)
|
|
45
|
+
# converts the simplextree into a multiparameter simplextree
|
|
46
|
+
for dtype in [np.int32, np.int64, np.float32, np.float64]:
|
|
47
|
+
try:
|
|
48
|
+
st_multi = mp.SimplexTreeMulti(st, num_parameters=4, dtype=dtype)
|
|
49
|
+
except KeyError:
|
|
50
|
+
import sys
|
|
51
|
+
|
|
52
|
+
print(f"type {dtype} not compiled, skipping.", file=sys.stderr)
|
|
53
|
+
continue ## dtype not compiled
|
|
54
|
+
minf = -np.inf if isinstance(dtype(1), np.floating) else np.iinfo(dtype).min
|
|
55
|
+
it = [
|
|
56
|
+
(array([0, 1]), array([1.0, minf, minf, minf])),
|
|
57
|
+
(array([0]), array([1.0, minf, minf, minf])),
|
|
58
|
+
(array([1]), array([0.0, minf, minf, minf])),
|
|
59
|
+
]
|
|
60
|
+
assert_st_simplices(st_multi, it)
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
has_kcritical = np.any([a().is_kcritical for a in mp.simplex_tree_multi.available_simplextrees])
|
|
64
|
+
@pytest.mark.skipif(
|
|
65
|
+
not has_kcritical,
|
|
66
|
+
reason="kcritical simplextree not compiled, skipping this test",
|
|
67
|
+
)
|
|
68
|
+
def test_4():
|
|
69
|
+
st = mp.SimplexTreeMulti(num_parameters=2, kcritical=True, dtype=np.float64)
|
|
70
|
+
st.insert([0, 1, 2], [0, 1])
|
|
71
|
+
st.insert([0, 1, 2], [1, 0])
|
|
72
|
+
st.remove_maximal_simplex([0, 1, 2])
|
|
73
|
+
st.insert([0, 1, 2], [1, 2])
|
|
74
|
+
st.insert([0, 1, 2], [2, 1])
|
|
75
|
+
st.insert([0, 1, 2], [1.5, 1.5])
|
|
76
|
+
st.insert([0, 1, 2], [2.5, 0.5])
|
|
77
|
+
st.insert([0, 1, 2], [0.5, 2.5])
|
|
78
|
+
|
|
79
|
+
s = mp.Slicer(st, vineyard=True)
|
|
80
|
+
|
|
81
|
+
assert np.array_equal(
|
|
82
|
+
s.get_filtrations_values(),
|
|
83
|
+
array(
|
|
84
|
+
[
|
|
85
|
+
[0.0, 1.0],
|
|
86
|
+
[1.0, 0.0],
|
|
87
|
+
[0.0, 1.0],
|
|
88
|
+
[1.0, 0.0],
|
|
89
|
+
[0.0, 1.0],
|
|
90
|
+
[1.0, 0.0],
|
|
91
|
+
[0.0, 1.0],
|
|
92
|
+
[1.0, 0.0],
|
|
93
|
+
[0.0, 1.0],
|
|
94
|
+
[1.0, 0.0],
|
|
95
|
+
[0.0, 1.0],
|
|
96
|
+
[1.0, 0.0],
|
|
97
|
+
[0.5, 2.5],
|
|
98
|
+
[1.0, 2.0],
|
|
99
|
+
[1.5, 1.5],
|
|
100
|
+
[2.0, 1.0],
|
|
101
|
+
[2.5, 0.5],
|
|
102
|
+
]
|
|
103
|
+
),
|
|
104
|
+
), "Invalid conversion from kcritical st to kcritical slicer."
|
|
105
|
+
death_curve = np.asarray(
|
|
106
|
+
mp.module_approximation(s, box=[[0, 0], [3, 3]])
|
|
107
|
+
.get_module_of_degree(1)[0]
|
|
108
|
+
.get_death_list()
|
|
109
|
+
)
|
|
110
|
+
assert np.array_equal(
|
|
111
|
+
death_curve,
|
|
112
|
+
array(
|
|
113
|
+
[
|
|
114
|
+
[0.5, np.inf],
|
|
115
|
+
[1.0, 2.5],
|
|
116
|
+
[1.5, 2.0],
|
|
117
|
+
[2.0, 1.5],
|
|
118
|
+
[2.5, 1.0],
|
|
119
|
+
[np.inf, 0.5],
|
|
120
|
+
]
|
|
121
|
+
),
|
|
122
|
+
)
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
def test_make_filtration_non_decreasing():
|
|
126
|
+
st = mp.SimplexTreeMulti(num_parameters=2)
|
|
127
|
+
st.insert([0], [1, 2])
|
|
128
|
+
st.insert([1], [2, 3])
|
|
129
|
+
st.insert([2], [3, 2])
|
|
130
|
+
|
|
131
|
+
st.insert([0, 1], [10, 21])
|
|
132
|
+
st.insert([2, 0], [11, 20])
|
|
133
|
+
|
|
134
|
+
st.insert([0, 1, 2], [-np.inf, -np.inf])
|
|
135
|
+
assert (st.filtration([1, 2]) == 3).all()
|
|
136
|
+
assert (st.filtration([0, 1, 2]) == [11, 21]).all()
|
|
137
|
+
st.make_filtration_non_decreasing()
|
|
138
|
+
assert (st.filtration([1, 2]) == 3).all()
|
|
139
|
+
assert (st.filtration([0, 1, 2]) == [11, 21]).all()
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
def test_flagify():
|
|
143
|
+
st = mp.SimplexTreeMulti(num_parameters=2)
|
|
144
|
+
|
|
145
|
+
st.insert([0], [1, 4])
|
|
146
|
+
st.insert([1], [2, 3])
|
|
147
|
+
st.insert([2], [3, 2])
|
|
148
|
+
|
|
149
|
+
st.insert([0, 1], [21, 20])
|
|
150
|
+
st.insert([2, 0], [20, 21])
|
|
151
|
+
st.insert([1, 2])
|
|
152
|
+
st.insert([0, 1, 2], [41, 55])
|
|
153
|
+
|
|
154
|
+
st.flagify(2)
|
|
155
|
+
assert (st.filtration([0, 1, 2]) == 21).all()
|
|
156
|
+
st.flagify(1)
|
|
157
|
+
assert (np.array([f for s, f in st]).max(axis=0) == [3, 4]).all()
|
|
158
|
+
st.flagify(0)
|
|
159
|
+
assert (np.array([f for s, f in st]) == -np.inf).all()
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
def test_distance_matrix_filling():
|
|
163
|
+
X = np.random.uniform(size=(200, 2))
|
|
164
|
+
D = np.sqrt(((X[None] - X[:, None]) ** 2).sum(axis=-1))
|
|
165
|
+
st = gd.RipsComplex(distance_matrix=D).create_simplex_tree()
|
|
166
|
+
st = mp.SimplexTreeMulti(st, num_parameters=1)
|
|
167
|
+
st2 = mp.SimplexTreeMulti(st)
|
|
168
|
+
assert st2.num_parameters == 1
|
|
169
|
+
st2.fill_lowerstar(np.zeros(st.num_vertices), 0)
|
|
170
|
+
assert st2 != st
|
|
171
|
+
st2.fill_distance_matrix(D, 0)
|
|
172
|
+
assert st2 == st
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
def test_serialize():
|
|
176
|
+
stm = random_st(num_parameters=4)
|
|
177
|
+
stm2 = pkl.loads(pkl.dumps(stm))
|
|
178
|
+
assert stm == stm2
|
|
179
|
+
stm2[[0]][:] = stm2[[0]] + 1
|
|
180
|
+
assert not stm == stm2
|
|
181
|
+
st1 = stm.project_on_line(parameter=0)
|
|
182
|
+
stm = mp.SimplexTreeMulti(st1, num_parameters=3)
|
|
183
|
+
assert st1 == stm.project_on_line(
|
|
184
|
+
parameter=0
|
|
185
|
+
), "Gudhi<->Multipers conversion failed"
|
|
186
|
+
|
|
187
|
+
|
|
188
|
+
@pytest.mark.skipif(
|
|
189
|
+
not has_kcritical,
|
|
190
|
+
reason="kcritical simplextree not compiled, skipping this test",
|
|
191
|
+
)
|
|
192
|
+
def test_kcritical_batch_insert():
|
|
193
|
+
|
|
194
|
+
st = mp.SimplexTreeMulti(num_parameters=2, kcritical=True, dtype=np.float64)
|
|
195
|
+
|
|
196
|
+
vertices = [[0,1]]
|
|
197
|
+
vertices_filtrations = np.array([[[-1, -2]],[[-2, -1]]])
|
|
198
|
+
st.insert_batch(vertices,vertices_filtrations)
|
|
199
|
+
|
|
200
|
+
edges = np.array([[0, 1],[1, 2], [2,0]]).T
|
|
201
|
+
edges_filtrations = np.array([
|
|
202
|
+
[[1,0],[0,1], [np.inf,np.inf]],
|
|
203
|
+
[[1,0],[0,1], [np.inf,np.inf]],
|
|
204
|
+
[[1,0],[0,1], [-1,3]],
|
|
205
|
+
])
|
|
206
|
+
st.insert_batch(edges, edges_filtrations)
|
|
207
|
+
|
|
208
|
+
triangle = np.array([[0,1,2]]).T
|
|
209
|
+
triangle_filration = [[[2,2]]]
|
|
210
|
+
st.insert_batch(triangle, triangle_filration)
|
|
211
|
+
|
|
212
|
+
from numpy import array
|
|
213
|
+
goal = [(array([0, 1, 2]), [array([2., 2.])]),
|
|
214
|
+
(array([0, 1]), [array([0., 1.]), array([1., 0.])]),
|
|
215
|
+
(array([0, 2]), [array([-1., 3.]), array([0., 1.]), array([1., 0.])]),
|
|
216
|
+
(array([0]), [array([-1., -2.])]),
|
|
217
|
+
(array([1, 2]), [array([0., 1.]), array([1., 0.])]),
|
|
218
|
+
(array([1]), [array([-2., -1.])]),
|
|
219
|
+
(array([2]), [array([0., 1.]), array([1., 0.])])
|
|
220
|
+
]
|
|
221
|
+
assert_st_simplices(st, goal)
|
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
import pytest
|
|
3
|
+
from numpy import array
|
|
4
|
+
|
|
5
|
+
import multipers as mp
|
|
6
|
+
import multipers.slicer as mps
|
|
7
|
+
from multipers.tests import assert_sm
|
|
8
|
+
import pickle as pkl
|
|
9
|
+
|
|
10
|
+
mpfree_flag = mp.io._check_available("mpfree")
|
|
11
|
+
fd_flag = mp.io._check_available("function_delaunay")
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def test_1():
|
|
15
|
+
st = mp.SimplexTreeMulti(num_parameters=2)
|
|
16
|
+
st.insert([0], [0, 1])
|
|
17
|
+
st.insert([1], [1, 0])
|
|
18
|
+
st.insert([0, 1], [1, 1])
|
|
19
|
+
for S in mps.available_slicers:
|
|
20
|
+
if not S().is_vine or not S().col_type or S().is_kcritical:
|
|
21
|
+
continue
|
|
22
|
+
from multipers._slicer_meta import _blocks2boundary_dimension_grades
|
|
23
|
+
|
|
24
|
+
generator_maps, generator_dimensions, filtration_values = (
|
|
25
|
+
_blocks2boundary_dimension_grades(
|
|
26
|
+
st._to_scc(),
|
|
27
|
+
inplace=False,
|
|
28
|
+
)
|
|
29
|
+
)
|
|
30
|
+
it = S(
|
|
31
|
+
generator_maps, generator_dimensions, filtration_values
|
|
32
|
+
).persistence_on_line([0, 0])
|
|
33
|
+
assert (
|
|
34
|
+
len(it) == 2
|
|
35
|
+
), "There are simplices of dim 0 and 1, but no pers ? got {}".format(len(it))
|
|
36
|
+
assert len(it[1]) == 0, "Pers of dim 1 is not empty ? got {}".format(it[1])
|
|
37
|
+
for x in it[0]:
|
|
38
|
+
if np.any(np.asarray(x)):
|
|
39
|
+
continue
|
|
40
|
+
assert x[0] == 1 and x[1] > 45, "pers should be [1,inf], got {}".format(x)
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def test_2():
|
|
44
|
+
st = mp.SimplexTreeMulti(num_parameters=2)
|
|
45
|
+
st.insert([0], [0, 1])
|
|
46
|
+
st.insert([1], [1, 0])
|
|
47
|
+
st.insert([0, 1], [1, 1])
|
|
48
|
+
st.insert([0, 1, 2], [2, 2])
|
|
49
|
+
assert mp.slicer.to_simplextree(mp.Slicer(st, dtype=st.dtype)) == st
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def test_3():
|
|
53
|
+
st = mp.SimplexTreeMulti(num_parameters=2)
|
|
54
|
+
st.insert([0], [0, 1])
|
|
55
|
+
st.insert([1], [1, 0])
|
|
56
|
+
st.insert([0, 1], [1, 1])
|
|
57
|
+
sm = mp.signed_measure(st, invariant="rank", degree=0)
|
|
58
|
+
sm2 = mp.signed_measure(mp.Slicer(st, dtype=np.int32), invariant="rank", degree=0)
|
|
59
|
+
sm3 = mp.signed_measure(mp.Slicer(st, dtype=np.float64), invariant="rank", degree=0)
|
|
60
|
+
it = [
|
|
61
|
+
(
|
|
62
|
+
array([[0.0, 1.0, 1.0, 1.0], [1.0, 0.0, 1.0, 1.0], [1.0, 1.0, 1.0, 1.0]]),
|
|
63
|
+
array([1, 1, -1]),
|
|
64
|
+
)
|
|
65
|
+
]
|
|
66
|
+
assert_sm(sm, it)
|
|
67
|
+
assert_sm(sm2, it)
|
|
68
|
+
assert_sm(sm3, it)
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
def test_representative_cycles():
|
|
72
|
+
truc = [
|
|
73
|
+
{},
|
|
74
|
+
{},
|
|
75
|
+
{},
|
|
76
|
+
{},
|
|
77
|
+
{},
|
|
78
|
+
{},
|
|
79
|
+
{},
|
|
80
|
+
{2, 3},
|
|
81
|
+
{4, 5},
|
|
82
|
+
{0, 2},
|
|
83
|
+
{0, 1},
|
|
84
|
+
{1, 3},
|
|
85
|
+
{1, 2},
|
|
86
|
+
{7, 11, 12},
|
|
87
|
+
{9, 10, 12},
|
|
88
|
+
{5, 6},
|
|
89
|
+
{2, 4},
|
|
90
|
+
{4, 6},
|
|
91
|
+
{8, 15, 17},
|
|
92
|
+
{3, 6},
|
|
93
|
+
]
|
|
94
|
+
truc = [list(machin) for machin in truc]
|
|
95
|
+
slicer = mp.slicer._Slicer_Matrix0_vine_f64(
|
|
96
|
+
truc,
|
|
97
|
+
np.array([max(len(x) - 1, 0) for x in truc]),
|
|
98
|
+
np.array([list(range(len(truc))), list(range(len(truc)))]).T,
|
|
99
|
+
)
|
|
100
|
+
slicer.compute_persistence(one_filtration=list(range(len(truc))))
|
|
101
|
+
cycles = slicer.get_representative_cycles()
|
|
102
|
+
assert len(cycles) == 3, f"There should be 3 dimensions here, found {len(cycles)}"
|
|
103
|
+
assert (
|
|
104
|
+
np.asarray(cycles[0]).shape[0] == 7
|
|
105
|
+
), f"Invalid number of 0-cycles, got {np.asarray(cycles[0]).size}"
|
|
106
|
+
for c in cycles[1]:
|
|
107
|
+
assert (
|
|
108
|
+
np.unique(cycles[1][0], return_counts=True)[1] == 2
|
|
109
|
+
).all(), f"Found a non-cycle, {cycles[1][0]}"
|
|
110
|
+
assert len(cycles[2]) == 0, "Found a 2-cycle, which should not exist"
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
def test_pruning():
|
|
114
|
+
from multipers.tests import random_st
|
|
115
|
+
|
|
116
|
+
st = random_st(num_parameters=3, max_dim=4)
|
|
117
|
+
s = mp.Slicer(st)
|
|
118
|
+
s.prune_above_dimension(2)
|
|
119
|
+
s2 = mp.Slicer(s, max_dim=2)
|
|
120
|
+
assert s.get_dimensions()[-1] == 2, "Failed to prune dimension"
|
|
121
|
+
st.prune_above_dimension(2)
|
|
122
|
+
assert (
|
|
123
|
+
s.get_dimensions() == s2.get_dimensions()
|
|
124
|
+
).all(), "pruned dimensions do not coincide"
|
|
125
|
+
assert s.get_boundaries() == s2.get_boundaries(), "Boundaries changed"
|
|
126
|
+
assert (
|
|
127
|
+
s.get_filtrations_values() == s2.get_filtrations_values()
|
|
128
|
+
).all(), "Filtrations have changed"
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
def test_scc():
|
|
132
|
+
import numpy as np
|
|
133
|
+
|
|
134
|
+
import multipers as mp
|
|
135
|
+
from multipers.distances import sm_distance
|
|
136
|
+
from multipers.io import _check_available
|
|
137
|
+
from multipers.tests import random_st
|
|
138
|
+
|
|
139
|
+
st = random_st(npts=500, num_parameters=2)
|
|
140
|
+
s = mp.Slicer(st, dtype=np.float64)
|
|
141
|
+
s.to_scc("truc.scc", degree=1)
|
|
142
|
+
s2 = mp.Slicer("truc.scc")
|
|
143
|
+
(a,) = mp.signed_measure(s)
|
|
144
|
+
(b,) = mp.signed_measure(s2)
|
|
145
|
+
assert sm_distance(a, b) < np.finfo(np.float64).resolution * s.num_generators
|
|
146
|
+
|
|
147
|
+
st = random_st(npts=500)
|
|
148
|
+
s = mp.Slicer(st).grid_squeeze(inplace=True)
|
|
149
|
+
s.filtration_grid = []
|
|
150
|
+
s.to_scc("truc.scc", degree=1)
|
|
151
|
+
s2 = mp.Slicer("truc.scc", dtype=np.float64)
|
|
152
|
+
(a,) = mp.signed_measure(s)
|
|
153
|
+
(b,) = mp.signed_measure(s2)
|
|
154
|
+
assert sm_distance(a, b) == 0
|
|
155
|
+
|
|
156
|
+
st = random_st(npts=200)
|
|
157
|
+
s = mp.Slicer(st).grid_squeeze(inplace=True)
|
|
158
|
+
s.filtration_grid = []
|
|
159
|
+
s.to_scc(
|
|
160
|
+
"truc.scc",
|
|
161
|
+
)
|
|
162
|
+
if _check_available("mpfree"):
|
|
163
|
+
s2 = mp.Slicer("truc.scc", dtype=np.float64).minpres(1)
|
|
164
|
+
(a,) = mp.signed_measure(s, degree=1)
|
|
165
|
+
(b,) = mp.signed_measure(s2, degree=1)
|
|
166
|
+
assert sm_distance(a, b) == 0
|
|
167
|
+
else:
|
|
168
|
+
pytest.skip("Skipped a test bc `mpfree` was not found.")
|
|
169
|
+
|
|
170
|
+
|
|
171
|
+
def test_bitmap():
|
|
172
|
+
img = np.random.uniform(size=(12, 10, 11, 2))
|
|
173
|
+
num_parameters = img.shape[-1]
|
|
174
|
+
s = mp.slicer.from_bitmap(img)
|
|
175
|
+
num_vertices = np.searchsorted(s.get_dimensions(), 1)
|
|
176
|
+
assert num_vertices == np.prod(img.shape[:-1])
|
|
177
|
+
assert s.num_parameters == num_parameters
|
|
178
|
+
assert s.dimension == img.ndim - 1
|
|
179
|
+
assert np.all(
|
|
180
|
+
np.asarray(s.get_filtrations()[:num_vertices])
|
|
181
|
+
== img.reshape(-1, num_parameters)
|
|
182
|
+
)
|
|
183
|
+
|
|
184
|
+
|
|
185
|
+
@pytest.mark.skipif(
|
|
186
|
+
not fd_flag or not mpfree_flag,
|
|
187
|
+
reason="Skipped external test as `function_delaunay`, `mpfree` were not found.",
|
|
188
|
+
)
|
|
189
|
+
@pytest.mark.parametrize("dim", [1, 2, 3, 4])
|
|
190
|
+
@pytest.mark.parametrize("degree", [1, 2, 3])
|
|
191
|
+
def test_external(dim, degree):
|
|
192
|
+
if degree >= dim:
|
|
193
|
+
return
|
|
194
|
+
X = np.random.uniform(size=(100, dim))
|
|
195
|
+
f = np.random.uniform(size=(X.shape[0]))
|
|
196
|
+
fd = mps.from_function_delaunay(X, f)
|
|
197
|
+
assert np.array_equal(np.unique(fd.get_dimensions()), np.arange(dim + 2))
|
|
198
|
+
fd_ = mps.from_function_delaunay(X, f, degree=degree)
|
|
199
|
+
assert np.array_equal(
|
|
200
|
+
np.unique(fd_.get_dimensions()), [degree, degree + 1]
|
|
201
|
+
) ## only does presentations
|
|
202
|
+
fd_ = fd.minpres(degree=degree)
|
|
203
|
+
assert np.array_equal(
|
|
204
|
+
np.unique(fd_.get_dimensions()), [degree, degree + 1, degree + 2]
|
|
205
|
+
) ## resolution by default
|
|
206
|
+
|
|
207
|
+
def test_pkl():
|
|
208
|
+
for num_params in range(1,4):
|
|
209
|
+
img = np.random.uniform(size=(20,20,num_params))
|
|
210
|
+
img2 = np.array(img)
|
|
211
|
+
img2[0,0,0]+=1
|
|
212
|
+
s = mp.slicer.from_bitmap(img)
|
|
213
|
+
s2 = mp.slicer.from_bitmap(img2)
|
|
214
|
+
s3 = type(s)(s.get_boundaries()[:-1], s.get_dimensions()[:-1], s.get_filtrations()[:-1])
|
|
215
|
+
s4 = type(s)(s.get_boundaries(), s.get_dimensions()+1, s.get_filtrations())
|
|
216
|
+
assert len(s)> np.prod(img.shape[:-1])+1
|
|
217
|
+
assert s == s.copy()
|
|
218
|
+
assert s != s2
|
|
219
|
+
assert s != s3
|
|
220
|
+
assert s != s4
|
|
221
|
+
assert s == pkl.loads(pkl.dumps(s))
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
from .rips_density import *
|