multipers 2.2.3__cp310-cp310-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.cp310-win_amd64.pyd +0 -0
- multipers/function_rips.pyx +105 -0
- multipers/grids.cp310-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.cp310-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.cp310-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.cp310-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.cp310-win_amd64.pyd +0 -0
- multipers/point_measure.pyx +320 -0
- multipers/simplex_tree_multi.cp310-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.cp310-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
multipers/test.pyx
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# cimport multipers.tensor as mt
|
|
2
|
+
from libc.stdint cimport intptr_t, uint16_t
|
|
3
|
+
from libcpp.vector cimport vector
|
|
4
|
+
from libcpp cimport bool, int, float
|
|
5
|
+
from libcpp.utility cimport pair
|
|
6
|
+
from typing import Optional,Iterable,Callable
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
ctypedef float value_type
|
|
10
|
+
# ctypedef uint16_t index_type
|
|
11
|
+
|
|
12
|
+
import numpy as np
|
|
13
|
+
# cimport numpy as cnp
|
|
14
|
+
# cnp.import_array()
|
|
15
|
+
|
|
16
|
+
# cdef extern from "multi_parameter_rank_invariant/rank_invariant.h" namespace "Gudhi::rank_invariant":
|
|
17
|
+
# void get_hilbert_surface(const intptr_t, mt.static_tensor_view, const vector[index_type], const vector[index_type], index_type, index_type, const vector[index_type], bool, bool) except + nogil
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
from multipers.simplex_tree_multi import SimplexTreeMulti
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def numpy_to_tensor(array:np.ndarray):
|
|
24
|
+
cdef vector[index_type] shape = array.shape
|
|
25
|
+
cdef dtype[::1] contigus_array_view = np.ascontiguousarray(array)
|
|
26
|
+
cdef dtype* dtype_ptr = &contigus_array_view[0]
|
|
27
|
+
cdef mt.static_tensor_view tensor
|
|
28
|
+
with nogil:
|
|
29
|
+
tensor = mt.static_tensor_view(dtype_ptr, shape)
|
|
30
|
+
return tensor.get_resolution()
|
|
31
|
+
|
|
32
|
+
# def hilbert2d(simplextree:SimplexTreeMulti, grid_shape:np.ndarray|list, vector[index_type] degrees, bool mobius_inversion):
|
|
33
|
+
# # assert simplextree.num_parameters == 2
|
|
34
|
+
# cdef intptr_t ptr = simplextree.thisptr
|
|
35
|
+
# cdef vector[index_type] c_grid_shape = grid_shape
|
|
36
|
+
# cdef dtype[::1] container = np.zeros(grid_shape, dtype=np.float32).flatten()
|
|
37
|
+
# cdef dtype* container_ptr = &container[0]
|
|
38
|
+
# cdef mt.static_tensor_view c_container = mt.static_tensor_view(container_ptr, c_grid_shape)
|
|
39
|
+
# cdef index_type i = 0
|
|
40
|
+
# cdef index_type j = 1
|
|
41
|
+
# cdef vector[index_type] fixed_values = [[],[]]
|
|
42
|
+
# # get_hilbert_surface(ptr, c_container, c_grid_shape, degrees,i,j,fixed_values, False, False)
|
|
43
|
+
# return container.reshape(grid_shape)
|
|
44
|
+
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
def assert_st_simplices(st, dump):
|
|
5
|
+
"""
|
|
6
|
+
Checks that the simplextree has the same
|
|
7
|
+
filtration as the dump.
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
assert np.all(
|
|
11
|
+
[
|
|
12
|
+
np.isclose(a, b).all()
|
|
13
|
+
for x, y in zip(st.get_simplices(), dump, strict=True)
|
|
14
|
+
for a, b in zip(x, y, strict=True)
|
|
15
|
+
]
|
|
16
|
+
)
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def sort_sm(sms):
|
|
20
|
+
idx = np.argsort([sm[0][:, 0] for sm in sms])
|
|
21
|
+
return tuple((sm[0][idx], sm[1][idx]) for sm in sms)
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def assert_sm_pair(sm1, sm2, exact=True, max_error=1e-3, reg=0.1):
|
|
25
|
+
if not exact:
|
|
26
|
+
from multipers.distances import sm_distance
|
|
27
|
+
|
|
28
|
+
d = sm_distance(sm1, sm2, reg=0.1)
|
|
29
|
+
assert d < max_error, f"Failed comparison:\n{sm1}\n{sm2},\n with distance {d}."
|
|
30
|
+
return
|
|
31
|
+
assert np.all(
|
|
32
|
+
[
|
|
33
|
+
np.isclose(a, b).all()
|
|
34
|
+
for x, y in zip(sm1, sm2, strict=True)
|
|
35
|
+
for a, b in zip(x, y, strict=True)
|
|
36
|
+
]
|
|
37
|
+
), f"Failed comparison:\n-----------------\n{sm1}\n-----------------\n{sm2}"
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def assert_sm(*args, exact=True, max_error=1e-5, reg=0.1):
|
|
41
|
+
sms = tuple(args)
|
|
42
|
+
for i in range(len(sms) - 1):
|
|
43
|
+
assert_sm_pair(sms[i], sms[i + 1], exact=exact, max_error=max_error, reg=reg)
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def random_st(npts=100, num_parameters=2, max_dim=2):
|
|
47
|
+
import gudhi as gd
|
|
48
|
+
|
|
49
|
+
import multipers as mp
|
|
50
|
+
from multipers.data import noisy_annulus
|
|
51
|
+
|
|
52
|
+
x = noisy_annulus(npts // 2, npts - npts // 2, dim=max_dim)
|
|
53
|
+
st = gd.AlphaComplex(points=x).create_simplex_tree()
|
|
54
|
+
st = mp.SimplexTreeMulti(st, num_parameters=num_parameters)
|
|
55
|
+
for p in range(num_parameters):
|
|
56
|
+
st.fill_lowerstar(np.random.uniform(size=npts), p)
|
|
57
|
+
return st
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import gudhi as gd
|
|
2
|
+
import numpy as np
|
|
3
|
+
|
|
4
|
+
import multipers as mp
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def test_h1_rips_density():
|
|
9
|
+
num_pts = 100
|
|
10
|
+
dim = 2
|
|
11
|
+
pts = np.random.uniform(size=(num_pts, dim))
|
|
12
|
+
weights = np.random.uniform(size=num_pts)
|
|
13
|
+
st = gd.RipsComplex(points=pts).create_simplex_tree()
|
|
14
|
+
st = mp.SimplexTreeMulti(st, num_parameters=2)
|
|
15
|
+
st.fill_lowerstar(weights, parameter=1)
|
|
16
|
+
st.collapse_edges(num=100)
|
|
17
|
+
st.expansion(2)
|
|
18
|
+
# F=st.get_filtration_grid()
|
|
19
|
+
# st.grid_squeeze(F, coordinate_values=True)
|
|
20
|
+
(sm,) = mp.signed_measure(st, degree=1, plot=True, mass_default=None)
|
|
21
|
+
pts, weights = sm
|
|
22
|
+
sm_indices, unmappable_points = st.pts_to_indices(pts, simplices_dimensions=[1, 0])
|
|
23
|
+
assert len(unmappable_points) == 0, "Found unmappable points in Rips edges ?"
|
|
24
|
+
filtration_values = np.array([f for _, f in st.get_simplices()])
|
|
25
|
+
reconstructed_measure = np.asarray(
|
|
26
|
+
[
|
|
27
|
+
[filtration_values[i][parameter] for parameter, i in enumerate(indices)]
|
|
28
|
+
for indices in sm_indices
|
|
29
|
+
]
|
|
30
|
+
)
|
|
31
|
+
assert np.array_equal(
|
|
32
|
+
reconstructed_measure, pts
|
|
33
|
+
), "Reconstructed measure is not equal to original measure ?"
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def test_h0_rips_density():
|
|
37
|
+
num_pts = 100
|
|
38
|
+
dim = 2
|
|
39
|
+
pts = np.random.uniform(size=(num_pts, dim))
|
|
40
|
+
weights = np.random.uniform(size=num_pts)
|
|
41
|
+
st = gd.RipsComplex(points=pts).create_simplex_tree()
|
|
42
|
+
st = mp.SimplexTreeMulti(st, num_parameters=2)
|
|
43
|
+
st.fill_lowerstar(weights, parameter=1)
|
|
44
|
+
st.collapse_edges(full=True)
|
|
45
|
+
# F=st.get_filtration_grid()
|
|
46
|
+
# st.grid_squeeze(F, coordinate_values=True)
|
|
47
|
+
(sm,) = mp.signed_measure(st, degree=0, plot=True, mass_default=None)
|
|
48
|
+
pts, weights = sm
|
|
49
|
+
_, unmappable_points = st.pts_to_indices(pts, simplices_dimensions=[1, 0])
|
|
50
|
+
assert (
|
|
51
|
+
pts[unmappable_points[:, 0]][:, 0] == 0
|
|
52
|
+
).all(), "Unmapped points of H0 have to be the nodes of the rips."
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
# def test_h1_rips_density_rank():
|
|
56
|
+
# num_pts = 100
|
|
57
|
+
# dim=2
|
|
58
|
+
# pts = np.random.uniform(size=(num_pts,dim))
|
|
59
|
+
# weights = np.random.uniform(size=num_pts)
|
|
60
|
+
# st = gd.RipsComplex(points=pts).create_simplex_tree()
|
|
61
|
+
# st = mp.SimplexTreeMulti(st, num_parameters=2)
|
|
62
|
+
# st.fill_lowerstar(weights, parameter=1)
|
|
63
|
+
# st.collapse_edges(full=True)
|
|
64
|
+
# st.expansion(2)
|
|
65
|
+
# # F=st.get_filtration_grid()
|
|
66
|
+
# # st.grid_squeeze(F, coordinate_values=True)
|
|
67
|
+
# sm, = mp.signed_measure(st, degree=1, plot=True, mass_default=None, invariant="rank_invariant", resolution=20, grid_strategy="quantile")
|
|
68
|
+
# pts, weights = sm
|
|
69
|
+
# sm_indices, unmappable_points = signed_measure_indices(st,pts, simplices_dimensions = [1,0])
|
|
70
|
+
# assert len(unmappable_points) == 0, 'Found unmappable points in Rips edges ?'
|
|
71
|
+
# filtration_values = np.array([f for _,f in st.get_simplices()])
|
|
72
|
+
# reconstructed_measure = np.asarray([[filtration_values[i][parameter%2] for parameter,i in enumerate(indices)] for indices in sm_indices])
|
|
73
|
+
# assert np.array_equal(reconstructed_measure, pts), 'Reconstructed measure is not equal to original measure ?'
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
|
|
3
|
+
import multipers as mp
|
|
4
|
+
from multipers import signed_measure
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
# def test_1(): # TODO: test integrate_measure instead
|
|
10
|
+
# st = mp.SimplexTreeMulti(num_parameters=3)
|
|
11
|
+
# st.insert([0], [1, 0, 0])
|
|
12
|
+
# st.insert([1], [0, 1, 0])
|
|
13
|
+
# st.insert([2], [0, 0, 1])
|
|
14
|
+
# st.insert([0, 1, 2], [2, 2, 2])
|
|
15
|
+
# st.make_filtration_non_decreasing()
|
|
16
|
+
# st = st.grid_squeeze(grid_strategy="exact")
|
|
17
|
+
# assert np.array_equal(
|
|
18
|
+
# hilbert_surface(st, degrees=[0])[1],
|
|
19
|
+
# np.array(
|
|
20
|
+
# [
|
|
21
|
+
# [
|
|
22
|
+
# [[0, 1, 1], [1, 2, 2], [1, 2, 2]],
|
|
23
|
+
# [[1, 2, 2], [2, 3, 3], [2, 3, 3]],
|
|
24
|
+
# [[1, 2, 2], [2, 3, 3], [2, 3, 1]],
|
|
25
|
+
# ]
|
|
26
|
+
# ]
|
|
27
|
+
# ),
|
|
28
|
+
# )
|
|
29
|
+
# assert np.array_equal(hilbert_surface(st, degrees=[0])[1][0], euler_surface(st)[1])
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
# def test_2():
|
|
33
|
+
# st = mp.SimplexTreeMulti(num_parameters=4)
|
|
34
|
+
# st.insert([0], [1, 0, 0, 0])
|
|
35
|
+
# st.insert([1], [0, 1, 0, 0])
|
|
36
|
+
# st.insert([2], [0, 0, 1, 0])
|
|
37
|
+
# st.insert([3], [0, 0, 0, 1])
|
|
38
|
+
# st.insert([0, 1, 2, 3], [2, 2, 2, 2])
|
|
39
|
+
# st.make_filtration_non_decreasing()
|
|
40
|
+
# # list(st.get_simplices())
|
|
41
|
+
# st.grid_squeeze(grid_strategy="exact")
|
|
42
|
+
# assert np.array_equal(
|
|
43
|
+
# hilbert_surface(st, degrees=[0])[1][0], (euler_surface(st)[1])
|
|
44
|
+
# )
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def test_3():
|
|
48
|
+
st = mp.SimplexTreeMulti(num_parameters=2)
|
|
49
|
+
st.insert([0, 1, 2], [1] * st.num_parameters)
|
|
50
|
+
st.remove_maximal_simplex([0, 1, 2])
|
|
51
|
+
st = st.grid_squeeze(grid_strategy="exact")
|
|
52
|
+
((a, b),) = mp.signed_measure(st, degrees=[1], mass_default=None)
|
|
53
|
+
assert np.array_equal(a, [[1, 1]]) and np.array_equal(b, [1])
|
|
54
|
+
assert mp.signed_measure(st, degrees=[1], mass_default="inf")[0][1].sum() == 0
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def test_4():
|
|
58
|
+
st = mp.SimplexTreeMulti(num_parameters=3)
|
|
59
|
+
st.insert([0], [1, 0, 0])
|
|
60
|
+
st.insert([1], [0, 1, 0])
|
|
61
|
+
st.insert([2], [0, 0, 1])
|
|
62
|
+
st.insert([0, 1, 2], [2, 2, 2])
|
|
63
|
+
st.make_filtration_non_decreasing()
|
|
64
|
+
# list(st.get_simplices())
|
|
65
|
+
st.grid_squeeze(grid_strategy="exact")
|
|
66
|
+
assert signed_measure(st, degrees=[0], mass_default="inf")[0][1].sum() == 0
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
def test_5():
|
|
70
|
+
num_param = 7
|
|
71
|
+
st = mp.SimplexTreeMulti(num_parameters=num_param)
|
|
72
|
+
for i in range(num_param):
|
|
73
|
+
f = np.zeros(num_param)
|
|
74
|
+
f[i] = 1
|
|
75
|
+
st.insert([i], f)
|
|
76
|
+
st.insert(np.arange(num_param), [2] * num_param)
|
|
77
|
+
assert not st.make_filtration_non_decreasing()
|
|
78
|
+
st.grid_squeeze()
|
|
79
|
+
(a, b), (c, d) = signed_measure(st, degrees=[0, 1])
|
|
80
|
+
assert np.all(a[-1] == 2)
|
|
81
|
+
assert np.sum(b) == 1 and b[-1] == -(num_param - 1)
|
|
82
|
+
assert c.shape == (0, num_param)
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
import pytest
|
|
3
|
+
|
|
4
|
+
import multipers as mp
|
|
5
|
+
import multipers.ml.mma as mma
|
|
6
|
+
from multipers.tests import random_st
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def test_1():
|
|
11
|
+
st = mp.SimplexTreeMulti(num_parameters=2)
|
|
12
|
+
st.insert([0], [0, 1])
|
|
13
|
+
st.insert([1], [1, 0])
|
|
14
|
+
st.insert([0, 1], [1, 1])
|
|
15
|
+
mma_pymodule = st.persistence_approximation()
|
|
16
|
+
assert np.array_equal(mma_pymodule[0].get_birth_list(), [[0.0, 1.0], [1.0, 0.0]])
|
|
17
|
+
assert np.array_equal(mma_pymodule[0].get_death_list(), [[np.inf, np.inf]])
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def test_img():
|
|
21
|
+
simplextree = mp.SimplexTreeMulti(num_parameters=4)
|
|
22
|
+
simplextree.insert([0], [1, 2, 3, 4])
|
|
23
|
+
mod = simplextree.persistence_approximation(
|
|
24
|
+
box=[[0, 0, 0, 0], [5, 5, 5, 5]], max_error=1.0
|
|
25
|
+
)
|
|
26
|
+
img = mod.representation(resolution=6, kernel="linear")
|
|
27
|
+
assert np.isclose(img[0, 2, 3, 4, 5], 0.5)
|
|
28
|
+
assert np.isclose(img[0, 1, 1, 1, 1], 0)
|
|
29
|
+
assert np.isclose(img[0, 3, 4, 5, 5], 1)
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
@pytest.mark.parametrize("n_jobs", [1, 2])
|
|
33
|
+
@pytest.mark.parametrize("prune_degrees_above", [0, 1, None])
|
|
34
|
+
def test_pipeline1(prune_degrees_above, n_jobs):
|
|
35
|
+
args = locals()
|
|
36
|
+
st = random_st(npts=50, max_dim=1).collapse_edges(-2)
|
|
37
|
+
st.expansion(2)
|
|
38
|
+
(truc1,) = mma.FilteredComplex2MMA(**args).fit_transform([[st]])[0]
|
|
39
|
+
(truc2,) = mma.FilteredComplex2MMA(**args).fit_transform([[mp.Slicer(st)]])[0]
|
|
40
|
+
box = st.filtration_bounds()
|
|
41
|
+
st_copy = st.copy()
|
|
42
|
+
if prune_degrees_above is not None:
|
|
43
|
+
st_copy.prune_above_dimension(prune_degrees_above)
|
|
44
|
+
output = mp.module_approximation(st_copy, box=box).representation(
|
|
45
|
+
bandwidth=0.1, kernel="linear"
|
|
46
|
+
)
|
|
47
|
+
assert np.sum(output) > 0, "Invalid mma rpz"
|
|
48
|
+
assert np.array_equal(
|
|
49
|
+
truc1.representation(bandwidth=0.1, kernel="linear"),
|
|
50
|
+
truc2.representation(bandwidth=0.1, kernel="linear"),
|
|
51
|
+
), "Slicer == Simplextree not satisfied"
|
|
52
|
+
assert np.array_equal(truc1.representation(bandwidth=0.1, kernel="linear"), output)
|
|
53
|
+
|
|
54
|
+
st = [random_st(npts=50).collapse_edges(-2, ignore_warning=True) for _ in range(5)]
|
|
55
|
+
some_fited_pipeline = mma.FilteredComplex2MMA(**args).fit([st])
|
|
56
|
+
truc1 = some_fited_pipeline.transform([st])
|
|
57
|
+
truc2 = mma.FilteredComplex2MMA(**args).fit_transform(
|
|
58
|
+
[[mp.Slicer(truc) for truc in st]]
|
|
59
|
+
)
|
|
60
|
+
for a, b in zip(truc1, truc2):
|
|
61
|
+
assert np.array_equal(
|
|
62
|
+
a[0].representation(bandwidth=0.01, kernel="linear"),
|
|
63
|
+
b[0].representation(bandwidth=0.01, kernel="linear"),
|
|
64
|
+
), "Slicer == Simplextree not satisfied"
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
@pytest.mark.parametrize("n_jobs", [1, 2])
|
|
68
|
+
@pytest.mark.parametrize("prune_degrees_above", [1, None])
|
|
69
|
+
@pytest.mark.parametrize("expand_dim", [None, 2, 3])
|
|
70
|
+
def test_pipeline2(prune_degrees_above, n_jobs, expand_dim):
|
|
71
|
+
args = locals()
|
|
72
|
+
st = random_st(max_dim=1)
|
|
73
|
+
st.collapse_edges(-2)
|
|
74
|
+
truc = mma.FilteredComplex2MMA(**args).fit_transform([[st]])[0]
|
|
75
|
+
box = st.filtration_bounds()
|
|
76
|
+
st_copy = st.copy()
|
|
77
|
+
# if prune_degrees_above is not None:
|
|
78
|
+
# st_copy.prune_above_dimension(prune_degrees_above)
|
|
79
|
+
if expand_dim is not None:
|
|
80
|
+
st_copy.expansion(expand_dim)
|
|
81
|
+
|
|
82
|
+
output = mp.module_approximation(st_copy, box=box).representation(bandwidth=0.01)
|
|
83
|
+
assert np.array_equal(truc[0].representation(bandwidth=-0.01), output)
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
|
|
3
|
+
import multipers as mp
|
|
4
|
+
import pytest
|
|
5
|
+
import platform
|
|
6
|
+
np.random.seed(0)
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
@pytest.mark.skipif(
|
|
10
|
+
platform.system() == "Windows",
|
|
11
|
+
reason="Detected windows. Pykeops is not compatible with windows yet. Skipping this ftm.",
|
|
12
|
+
)
|
|
13
|
+
def test_throw_test():
|
|
14
|
+
import multipers.ml.point_clouds as mmp
|
|
15
|
+
pts = np.array([[1, 1], [2, 2]], dtype=np.float32)
|
|
16
|
+
st = mmp.PointCloud2FilteredComplex(masses=[0.1]).fit_transform([pts])[0][0]
|
|
17
|
+
assert isinstance(st, mp.simplex_tree_multi.SimplexTreeMulti_type)
|
|
18
|
+
st = mmp.PointCloud2FilteredComplex(bandwidths=[-0.1], complex="alpha").fit_transform(
|
|
19
|
+
[pts]
|
|
20
|
+
)[0][0]
|
|
21
|
+
assert isinstance(st, mp.simplex_tree_multi.SimplexTreeMulti_type)
|
|
22
|
+
|
|
23
|
+
st = mmp.PointCloud2FilteredComplex(masses=[0.1], complex="alpha", output_type="slicer_novine").fit_transform(
|
|
24
|
+
[pts]
|
|
25
|
+
)[0][0]
|
|
26
|
+
assert isinstance(st, mp.slicer.Slicer_type)
|
|
27
|
+
assert st.is_vine is False
|
|
28
|
+
|
|
29
|
+
st = mmp.PointCloud2FilteredComplex(masses=[0.1], complex="alpha", output_type="slicer").fit_transform(
|
|
30
|
+
[pts]
|
|
31
|
+
)[0][0]
|
|
32
|
+
assert isinstance(st, mp.slicer.Slicer_type)
|
|
33
|
+
assert st.is_vine
|
|
34
|
+
|
|
35
|
+
st1, st2 = mmp.PointCloud2FilteredComplex(bandwidths=[0.1], masses=[0.1]).fit_transform(
|
|
36
|
+
[pts]
|
|
37
|
+
)[0]
|
|
38
|
+
assert isinstance(st1, mp.simplex_tree_multi.SimplexTreeMulti_type)
|
|
39
|
+
assert isinstance(st2, mp.simplex_tree_multi.SimplexTreeMulti_type)
|
|
40
|
+
## ensures it doesn't throw
|
|
41
|
+
assert isinstance(
|
|
42
|
+
mp.module_approximation(st),
|
|
43
|
+
mp.multiparameter_module_approximation.PyModule_type,
|
|
44
|
+
)
|
|
45
|
+
assert mp.signed_measure(st, degree=None, invariant="euler")[0][0].ndim == 2
|
|
46
|
+
assert mp.signed_measure(st, degree=0, invariant="hilbert")[0][0].ndim == 2
|
|
47
|
+
assert mp.signed_measure(st, degree=0, invariant="rank")[0][0].ndim == 2
|
|
48
|
+
assert mp.signed_measure(st, degree=0, invariant="rank")[0][0].shape[1] == 4
|
|
49
|
+
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
import multipers as mp
|
|
3
|
+
import gudhi as gd
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
mp.simplex_tree_multi.SAFE_CONVERSION = False
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def test_random_alpha_safe_conversion():
|
|
10
|
+
x = np.random.uniform(size=(200, 2))
|
|
11
|
+
num_parameter = 4
|
|
12
|
+
st_gudhi = gd.AlphaComplex(points=x).create_simplex_tree()
|
|
13
|
+
st_multi = mp.SimplexTreeMulti(
|
|
14
|
+
st_gudhi, num_parameters=num_parameter, safe_conversion=True
|
|
15
|
+
)
|
|
16
|
+
assert (
|
|
17
|
+
np.all([s in st_multi for s, f in st_gudhi.get_simplices()])
|
|
18
|
+
and st_gudhi.num_simplices() == st_multi.num_simplices
|
|
19
|
+
), "Simplices conversion failed."
|
|
20
|
+
assert np.all(
|
|
21
|
+
[f.shape[0] == num_parameter for _, f in st_multi.get_simplices()]
|
|
22
|
+
), "Number of parameters is inconcistent"
|
|
23
|
+
assert np.all(
|
|
24
|
+
[np.isclose(st_multi.filtration(s)[0], f) for s, f in st_gudhi.get_simplices()]
|
|
25
|
+
), "Filtration values conversion failed."
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def test_random_alpha_unsafe_conversion():
|
|
29
|
+
x = np.random.uniform(size=(200, 2))
|
|
30
|
+
num_parameter = 4
|
|
31
|
+
st_gudhi = gd.AlphaComplex(points=x).create_simplex_tree()
|
|
32
|
+
st_multi = mp.SimplexTreeMulti(
|
|
33
|
+
st_gudhi, num_parameters=num_parameter, safe_conversion=False
|
|
34
|
+
)
|
|
35
|
+
assert (
|
|
36
|
+
np.all([s in st_multi for s, f in st_gudhi.get_simplices()])
|
|
37
|
+
and st_gudhi.num_simplices() == st_multi.num_simplices
|
|
38
|
+
), "Simplices conversion failed."
|
|
39
|
+
assert np.all(
|
|
40
|
+
[f.shape[0] == num_parameter for _, f in st_multi.get_simplices()]
|
|
41
|
+
), "Number of parameters is inconcistent"
|
|
42
|
+
assert np.all(
|
|
43
|
+
[np.isclose(st_multi.filtration(s)[0], f) for s, f in st_gudhi.get_simplices()]
|
|
44
|
+
), "Filtration values conversion failed."
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def test_random_rips_safe_conversion():
|
|
48
|
+
x = np.random.uniform(size=(100, 2))
|
|
49
|
+
num_parameter = 4
|
|
50
|
+
st_gudhi = gd.RipsComplex(points=x).create_simplex_tree()
|
|
51
|
+
st_multi = mp.SimplexTreeMulti(
|
|
52
|
+
st_gudhi, num_parameters=num_parameter, safe_conversion=True
|
|
53
|
+
)
|
|
54
|
+
assert (
|
|
55
|
+
np.all([s in st_multi for s, f in st_gudhi.get_simplices()])
|
|
56
|
+
and st_gudhi.num_simplices() == st_multi.num_simplices
|
|
57
|
+
), "Simplices conversion failed."
|
|
58
|
+
assert np.all(
|
|
59
|
+
[f.shape[0] == num_parameter for _, f in st_multi.get_simplices()]
|
|
60
|
+
), "Number of parameters is inconcistent"
|
|
61
|
+
assert np.all(
|
|
62
|
+
[np.isclose(st_multi.filtration(s)[0], f) for s, f in st_gudhi.get_simplices()]
|
|
63
|
+
), "Filtration values conversion failed."
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def test_random_alpha_unsafe_conversion():
|
|
67
|
+
x = np.random.uniform(size=(100, 2))
|
|
68
|
+
num_parameter = 4
|
|
69
|
+
st_gudhi = gd.RipsComplex(points=x).create_simplex_tree()
|
|
70
|
+
st_multi = mp.SimplexTreeMulti(
|
|
71
|
+
st_gudhi, num_parameters=num_parameter, safe_conversion=False
|
|
72
|
+
)
|
|
73
|
+
assert (
|
|
74
|
+
np.all([s in st_multi for s, f in st_gudhi.get_simplices()])
|
|
75
|
+
and st_gudhi.num_simplices() == st_multi.num_simplices
|
|
76
|
+
), "Simplices conversion failed."
|
|
77
|
+
assert np.all(
|
|
78
|
+
[f.shape[0] == num_parameter for _, f in st_multi.get_simplices()]
|
|
79
|
+
), "Number of parameters is inconcistent"
|
|
80
|
+
assert np.all(
|
|
81
|
+
[np.isclose(st_multi.filtration(s)[0], f) for s, f in st_gudhi.get_simplices()]
|
|
82
|
+
), "Filtration values conversion failed."
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
from multipers.point_measure import signed_betti, rank_decomposition_by_rectangles
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
# only tests rank functions with 1 and 2 parameters
|
|
6
|
+
def test_rank_decomposition():
|
|
7
|
+
# rank of an interval module in 1D on a grid with 2 elements
|
|
8
|
+
ri = np.array(
|
|
9
|
+
[
|
|
10
|
+
[
|
|
11
|
+
1, # 0,0
|
|
12
|
+
1, # 0,1
|
|
13
|
+
],
|
|
14
|
+
[0, 1], # 1,0 # 1,1
|
|
15
|
+
]
|
|
16
|
+
)
|
|
17
|
+
expected_rd = np.array(
|
|
18
|
+
[
|
|
19
|
+
[
|
|
20
|
+
0, # 0,0
|
|
21
|
+
1, # 0,1
|
|
22
|
+
],
|
|
23
|
+
[0, 0], # 1,0 # 1,1
|
|
24
|
+
]
|
|
25
|
+
)
|
|
26
|
+
rd = rank_decomposition_by_rectangles(ri)
|
|
27
|
+
for i in range(2):
|
|
28
|
+
for i_ in range(i, 2):
|
|
29
|
+
assert rd[i, i_] == expected_rd[i, i_]
|
|
30
|
+
|
|
31
|
+
# rank of a sum of two rectangles in 2D on a grid of 2 elements
|
|
32
|
+
ri = np.array(
|
|
33
|
+
[
|
|
34
|
+
[
|
|
35
|
+
[
|
|
36
|
+
[1, 1], # (0,0), (0,0) # (0,0), (0,1)
|
|
37
|
+
[1, 1], # (0,0), (1,0) # (0,0), (1,1)
|
|
38
|
+
],
|
|
39
|
+
[
|
|
40
|
+
[0, 1], # (0,1), (0,0) # (0,1), (0,1)
|
|
41
|
+
[0, 1], # (0,1), (1,0) # (0,1), (1,1)
|
|
42
|
+
],
|
|
43
|
+
],
|
|
44
|
+
[
|
|
45
|
+
[
|
|
46
|
+
[0, 0], # (1,0), (0,0) # (1,0), (0,1)
|
|
47
|
+
[2, 2], # (1,0), (1,0) # (1,0), (1,1)
|
|
48
|
+
],
|
|
49
|
+
[
|
|
50
|
+
[0, 0], # (1,1), (0,0) # (1,1), (0,1)
|
|
51
|
+
[0, 2], # (1,1), (1,0) # (1,1), (1,1)
|
|
52
|
+
],
|
|
53
|
+
],
|
|
54
|
+
]
|
|
55
|
+
)
|
|
56
|
+
expected_rd = np.array(
|
|
57
|
+
[
|
|
58
|
+
[
|
|
59
|
+
[
|
|
60
|
+
[0, 0], # (0,0), (0,0) # (0,0), (0,1)
|
|
61
|
+
[0, 1], # (0,0), (1,0) # (0,0), (1,1)
|
|
62
|
+
],
|
|
63
|
+
[
|
|
64
|
+
[0, 0], # (0,1), (0,0) # (0,1), (0,1)
|
|
65
|
+
[0, 0], # (0,1), (1,0) # (0,1), (1,1)
|
|
66
|
+
],
|
|
67
|
+
],
|
|
68
|
+
[
|
|
69
|
+
[
|
|
70
|
+
[0, 0], # (1,0), (0,0) # (1,0), (0,1)
|
|
71
|
+
[0, 1], # (1,0), (1,0) # (1,0), (1,1)
|
|
72
|
+
],
|
|
73
|
+
[
|
|
74
|
+
[0, 0], # (1,1), (0,0) # (1,1), (0,1)
|
|
75
|
+
[0, 0], # (1,1), (1,0) # (1,1), (1,1)
|
|
76
|
+
],
|
|
77
|
+
],
|
|
78
|
+
]
|
|
79
|
+
)
|
|
80
|
+
|
|
81
|
+
rd = rank_decomposition_by_rectangles(ri)
|
|
82
|
+
for i in range(2):
|
|
83
|
+
for i_ in range(i, 2):
|
|
84
|
+
for j in range(2):
|
|
85
|
+
for j_ in range(j, 2):
|
|
86
|
+
assert rd[i, j, i_, j_] == expected_rd[i, j, i_, j_]
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
# only tests Hilbert functions with 1, 2, 3, and 4 parameters
|
|
90
|
+
def _test_signed_betti():
|
|
91
|
+
np.random.seed(0)
|
|
92
|
+
N = 4
|
|
93
|
+
|
|
94
|
+
# test 1D
|
|
95
|
+
for _ in range(N):
|
|
96
|
+
a = np.random.randint(10, 30)
|
|
97
|
+
|
|
98
|
+
f = np.random.randint(0, 40, size=(a))
|
|
99
|
+
sb = signed_betti(f)
|
|
100
|
+
|
|
101
|
+
check = np.zeros(f.shape)
|
|
102
|
+
for i in range(f.shape[0]):
|
|
103
|
+
for i_ in range(0, i + 1):
|
|
104
|
+
check[i] += sb[i_]
|
|
105
|
+
|
|
106
|
+
assert np.allclose(check, f)
|
|
107
|
+
|
|
108
|
+
# test 2D
|
|
109
|
+
for _ in range(N):
|
|
110
|
+
a = np.random.randint(10, 30)
|
|
111
|
+
b = np.random.randint(10, 30)
|
|
112
|
+
|
|
113
|
+
f = np.random.randint(0, 40, size=(a, b))
|
|
114
|
+
sb = signed_betti(f)
|
|
115
|
+
|
|
116
|
+
check = np.zeros(f.shape)
|
|
117
|
+
for i in range(f.shape[0]):
|
|
118
|
+
for j in range(f.shape[1]):
|
|
119
|
+
for i_ in range(0, i + 1):
|
|
120
|
+
for j_ in range(0, j + 1):
|
|
121
|
+
check[i, j] += sb[i_, j_]
|
|
122
|
+
|
|
123
|
+
assert np.allclose(check, f)
|
|
124
|
+
|
|
125
|
+
# test 3D
|
|
126
|
+
for _ in range(N):
|
|
127
|
+
a = np.random.randint(10, 20)
|
|
128
|
+
b = np.random.randint(10, 20)
|
|
129
|
+
c = np.random.randint(10, 20)
|
|
130
|
+
|
|
131
|
+
f = np.random.randint(0, 40, size=(a, b, c))
|
|
132
|
+
sb = signed_betti(f)
|
|
133
|
+
|
|
134
|
+
check = np.zeros(f.shape)
|
|
135
|
+
for i in range(f.shape[0]):
|
|
136
|
+
for j in range(f.shape[1]):
|
|
137
|
+
for k in range(f.shape[2]):
|
|
138
|
+
for i_ in range(0, i + 1):
|
|
139
|
+
for j_ in range(0, j + 1):
|
|
140
|
+
for k_ in range(0, k + 1):
|
|
141
|
+
check[i, j, k] += sb[i_, j_, k_]
|
|
142
|
+
|
|
143
|
+
assert np.allclose(check, f)
|
|
144
|
+
|
|
145
|
+
# test 4D
|
|
146
|
+
for _ in range(N):
|
|
147
|
+
a = np.random.randint(5, 10)
|
|
148
|
+
b = np.random.randint(5, 10)
|
|
149
|
+
c = np.random.randint(5, 10)
|
|
150
|
+
d = np.random.randint(5, 10)
|
|
151
|
+
|
|
152
|
+
f = np.random.randint(0, 40, size=(a, b, c, d))
|
|
153
|
+
sb = signed_betti(f)
|
|
154
|
+
|
|
155
|
+
check = np.zeros(f.shape)
|
|
156
|
+
for i in range(f.shape[0]):
|
|
157
|
+
for j in range(f.shape[1]):
|
|
158
|
+
for k in range(f.shape[2]):
|
|
159
|
+
for l in range(f.shape[3]):
|
|
160
|
+
for i_ in range(0, i + 1):
|
|
161
|
+
for j_ in range(0, j + 1):
|
|
162
|
+
for k_ in range(0, k + 1):
|
|
163
|
+
for l_ in range(0, l + 1):
|
|
164
|
+
check[i, j, k, l] += sb[i_, j_, k_, l_]
|
|
165
|
+
|
|
166
|
+
assert np.allclose(check, f)
|
|
167
|
+
|
|
168
|
+
for threshold in [True, False]:
|
|
169
|
+
for _ in range(N):
|
|
170
|
+
a = np.random.randint(5, 10)
|
|
171
|
+
b = np.random.randint(5, 10)
|
|
172
|
+
c = np.random.randint(5, 10)
|
|
173
|
+
d = np.random.randint(5, 10)
|
|
174
|
+
e = np.random.randint(5, 10)
|
|
175
|
+
f = np.random.randint(5, 10)
|
|
176
|
+
|
|
177
|
+
f = np.random.randint(0, 40, size=(a, b, c, d,e,f))
|
|
178
|
+
sb = signed_betti(f, threshold=threshold)
|
|
179
|
+
sb_ = signed_betti(f, threshold=threshold)
|
|
180
|
+
|
|
181
|
+
assert np.allclose(sb, sb_)
|