multipers 2.4.0b1__cp312-cp312-macosx_11_0_arm64.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.
- multipers/.dylibs/libboost_timer.dylib +0 -0
- multipers/.dylibs/libc++.1.0.dylib +0 -0
- multipers/.dylibs/libtbb.12.17.dylib +0 -0
- multipers/__init__.py +33 -0
- multipers/_signed_measure_meta.py +426 -0
- multipers/_slicer_meta.py +231 -0
- multipers/array_api/__init__.py +62 -0
- multipers/array_api/numpy.py +124 -0
- multipers/array_api/torch.py +133 -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 +113 -0
- multipers/distances.py +202 -0
- multipers/filtration_conversions.pxd +736 -0
- multipers/filtration_conversions.pxd.tp +226 -0
- multipers/filtrations/__init__.py +21 -0
- multipers/filtrations/density.py +529 -0
- multipers/filtrations/filtrations.py +480 -0
- multipers/filtrations.pxd +534 -0
- multipers/filtrations.pxd.tp +332 -0
- multipers/function_rips.cpython-312-darwin.so +0 -0
- multipers/function_rips.pyx +104 -0
- multipers/grids.cpython-312-darwin.so +0 -0
- multipers/grids.pyx +538 -0
- multipers/gudhi/Persistence_slices_interface.h +213 -0
- multipers/gudhi/Simplex_tree_interface.h +274 -0
- multipers/gudhi/Simplex_tree_multi_interface.h +648 -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 +52 -0
- multipers/gudhi/gudhi/Degree_rips_bifiltration.h +2307 -0
- multipers/gudhi/gudhi/Dynamic_multi_parameter_filtration.h +2524 -0
- multipers/gudhi/gudhi/Fields/Multi_field.h +453 -0
- multipers/gudhi/gudhi/Fields/Multi_field_operators.h +460 -0
- multipers/gudhi/gudhi/Fields/Multi_field_shared.h +444 -0
- multipers/gudhi/gudhi/Fields/Multi_field_small.h +584 -0
- multipers/gudhi/gudhi/Fields/Multi_field_small_operators.h +490 -0
- multipers/gudhi/gudhi/Fields/Multi_field_small_shared.h +580 -0
- multipers/gudhi/gudhi/Fields/Z2_field.h +391 -0
- multipers/gudhi/gudhi/Fields/Z2_field_operators.h +389 -0
- multipers/gudhi/gudhi/Fields/Zp_field.h +493 -0
- multipers/gudhi/gudhi/Fields/Zp_field_operators.h +384 -0
- multipers/gudhi/gudhi/Fields/Zp_field_shared.h +492 -0
- multipers/gudhi/gudhi/Flag_complex_edge_collapser.h +337 -0
- multipers/gudhi/gudhi/Matrix.h +2200 -0
- multipers/gudhi/gudhi/Multi_filtration/Multi_parameter_generator.h +1712 -0
- multipers/gudhi/gudhi/Multi_filtration/multi_filtration_conversions.h +237 -0
- multipers/gudhi/gudhi/Multi_filtration/multi_filtration_utils.h +225 -0
- multipers/gudhi/gudhi/Multi_parameter_filtered_complex.h +485 -0
- multipers/gudhi/gudhi/Multi_parameter_filtration.h +2643 -0
- multipers/gudhi/gudhi/Multi_persistence/Box.h +233 -0
- multipers/gudhi/gudhi/Multi_persistence/Line.h +309 -0
- multipers/gudhi/gudhi/Multi_persistence/Multi_parameter_filtered_complex_pcoh_interface.h +268 -0
- multipers/gudhi/gudhi/Multi_persistence/Persistence_interface_cohomology.h +159 -0
- multipers/gudhi/gudhi/Multi_persistence/Persistence_interface_matrix.h +463 -0
- multipers/gudhi/gudhi/Multi_persistence/Point.h +853 -0
- multipers/gudhi/gudhi/Off_reader.h +173 -0
- multipers/gudhi/gudhi/Persistence_matrix/Base_matrix.h +834 -0
- multipers/gudhi/gudhi/Persistence_matrix/Base_matrix_with_column_compression.h +838 -0
- multipers/gudhi/gudhi/Persistence_matrix/Boundary_matrix.h +833 -0
- multipers/gudhi/gudhi/Persistence_matrix/Chain_matrix.h +1367 -0
- multipers/gudhi/gudhi/Persistence_matrix/Id_to_index_overlay.h +1157 -0
- multipers/gudhi/gudhi/Persistence_matrix/Position_to_index_overlay.h +869 -0
- multipers/gudhi/gudhi/Persistence_matrix/RU_matrix.h +905 -0
- multipers/gudhi/gudhi/Persistence_matrix/allocators/entry_constructors.h +122 -0
- multipers/gudhi/gudhi/Persistence_matrix/base_pairing.h +260 -0
- multipers/gudhi/gudhi/Persistence_matrix/base_swap.h +288 -0
- multipers/gudhi/gudhi/Persistence_matrix/chain_pairing.h +170 -0
- multipers/gudhi/gudhi/Persistence_matrix/chain_rep_cycles.h +247 -0
- multipers/gudhi/gudhi/Persistence_matrix/chain_vine_swap.h +571 -0
- multipers/gudhi/gudhi/Persistence_matrix/columns/chain_column_extra_properties.h +182 -0
- multipers/gudhi/gudhi/Persistence_matrix/columns/column_dimension_holder.h +130 -0
- multipers/gudhi/gudhi/Persistence_matrix/columns/column_utilities.h +235 -0
- multipers/gudhi/gudhi/Persistence_matrix/columns/entry_types.h +312 -0
- multipers/gudhi/gudhi/Persistence_matrix/columns/heap_column.h +1092 -0
- multipers/gudhi/gudhi/Persistence_matrix/columns/intrusive_list_column.h +923 -0
- multipers/gudhi/gudhi/Persistence_matrix/columns/intrusive_set_column.h +914 -0
- multipers/gudhi/gudhi/Persistence_matrix/columns/list_column.h +930 -0
- multipers/gudhi/gudhi/Persistence_matrix/columns/naive_vector_column.h +1071 -0
- multipers/gudhi/gudhi/Persistence_matrix/columns/row_access.h +203 -0
- multipers/gudhi/gudhi/Persistence_matrix/columns/set_column.h +886 -0
- multipers/gudhi/gudhi/Persistence_matrix/columns/unordered_set_column.h +984 -0
- multipers/gudhi/gudhi/Persistence_matrix/columns/vector_column.h +1213 -0
- multipers/gudhi/gudhi/Persistence_matrix/index_mapper.h +58 -0
- multipers/gudhi/gudhi/Persistence_matrix/matrix_dimension_holders.h +227 -0
- multipers/gudhi/gudhi/Persistence_matrix/matrix_row_access.h +200 -0
- multipers/gudhi/gudhi/Persistence_matrix/ru_pairing.h +166 -0
- multipers/gudhi/gudhi/Persistence_matrix/ru_rep_cycles.h +319 -0
- multipers/gudhi/gudhi/Persistence_matrix/ru_vine_swap.h +562 -0
- multipers/gudhi/gudhi/Persistence_on_a_line.h +152 -0
- multipers/gudhi/gudhi/Persistence_on_rectangle.h +617 -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 +769 -0
- multipers/gudhi/gudhi/Points_off_io.h +171 -0
- multipers/gudhi/gudhi/Projective_cover_kernel.h +379 -0
- multipers/gudhi/gudhi/Simple_object_pool.h +69 -0
- multipers/gudhi/gudhi/Simplex_tree/Simplex_tree_iterators.h +559 -0
- multipers/gudhi/gudhi/Simplex_tree/Simplex_tree_node_explicit_storage.h +83 -0
- multipers/gudhi/gudhi/Simplex_tree/Simplex_tree_siblings.h +121 -0
- multipers/gudhi/gudhi/Simplex_tree/Simplex_tree_star_simplex_iterators.h +277 -0
- multipers/gudhi/gudhi/Simplex_tree/filtration_value_utils.h +155 -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 +60 -0
- multipers/gudhi/gudhi/Simplex_tree/simplex_tree_options.h +105 -0
- multipers/gudhi/gudhi/Simplex_tree.h +3170 -0
- multipers/gudhi/gudhi/Slicer.h +848 -0
- multipers/gudhi/gudhi/Thread_safe_slicer.h +393 -0
- multipers/gudhi/gudhi/distance_functions.h +62 -0
- multipers/gudhi/gudhi/graph_simplicial_complex.h +104 -0
- multipers/gudhi/gudhi/multi_simplex_tree_helpers.h +147 -0
- multipers/gudhi/gudhi/persistence_interval.h +263 -0
- multipers/gudhi/gudhi/persistence_matrix_options.h +188 -0
- multipers/gudhi/gudhi/reader_utils.h +367 -0
- multipers/gudhi/gudhi/simple_mdspan.h +484 -0
- multipers/gudhi/gudhi/slicer_helpers.h +779 -0
- multipers/gudhi/tmp_h0_pers/mma_interface_h0.h +223 -0
- multipers/gudhi/tmp_h0_pers/naive_merge_tree.h +536 -0
- multipers/io.cpython-312-darwin.so +0 -0
- multipers/io.pyx +472 -0
- multipers/ml/__init__.py +0 -0
- multipers/ml/accuracies.py +90 -0
- multipers/ml/invariants_with_persistable.py +79 -0
- multipers/ml/kernels.py +176 -0
- multipers/ml/mma.py +713 -0
- multipers/ml/one.py +472 -0
- multipers/ml/point_clouds.py +352 -0
- multipers/ml/signed_measures.py +1667 -0
- multipers/ml/sliced_wasserstein.py +461 -0
- multipers/ml/tools.py +113 -0
- multipers/mma_structures.cpython-312-darwin.so +0 -0
- multipers/mma_structures.pxd +134 -0
- multipers/mma_structures.pyx +1483 -0
- multipers/mma_structures.pyx.tp +1126 -0
- multipers/multi_parameter_rank_invariant/diff_helpers.h +85 -0
- multipers/multi_parameter_rank_invariant/euler_characteristic.h +95 -0
- multipers/multi_parameter_rank_invariant/function_rips.h +317 -0
- multipers/multi_parameter_rank_invariant/hilbert_function.h +761 -0
- multipers/multi_parameter_rank_invariant/persistence_slices.h +149 -0
- multipers/multi_parameter_rank_invariant/rank_invariant.h +350 -0
- multipers/multiparameter_edge_collapse.py +41 -0
- multipers/multiparameter_module_approximation/approximation.h +2541 -0
- multipers/multiparameter_module_approximation/debug.h +107 -0
- multipers/multiparameter_module_approximation/format_python-cpp.h +292 -0
- multipers/multiparameter_module_approximation/utilities.h +428 -0
- multipers/multiparameter_module_approximation.cpython-312-darwin.so +0 -0
- multipers/multiparameter_module_approximation.pyx +286 -0
- multipers/ops.cpython-312-darwin.so +0 -0
- multipers/ops.pyx +231 -0
- multipers/pickle.py +89 -0
- multipers/plots.py +550 -0
- multipers/point_measure.cpython-312-darwin.so +0 -0
- multipers/point_measure.pyx +409 -0
- multipers/simplex_tree_multi.cpython-312-darwin.so +0 -0
- multipers/simplex_tree_multi.pxd +136 -0
- multipers/simplex_tree_multi.pyx +11719 -0
- multipers/simplex_tree_multi.pyx.tp +2102 -0
- multipers/slicer.cpython-312-darwin.so +0 -0
- multipers/slicer.pxd +2097 -0
- multipers/slicer.pxd.tp +263 -0
- multipers/slicer.pyx +13042 -0
- multipers/slicer.pyx.tp +1259 -0
- multipers/tensor/tensor.h +672 -0
- multipers/tensor.pxd +13 -0
- multipers/test.pyx +44 -0
- multipers/tests/__init__.py +70 -0
- multipers/torch/__init__.py +1 -0
- multipers/torch/diff_grids.py +240 -0
- multipers/torch/rips_density.py +310 -0
- multipers/vector_interface.pxd +46 -0
- multipers-2.4.0b1.dist-info/METADATA +131 -0
- multipers-2.4.0b1.dist-info/RECORD +184 -0
- multipers-2.4.0b1.dist-info/WHEEL +6 -0
- multipers-2.4.0b1.dist-info/licenses/LICENSE +21 -0
- multipers-2.4.0b1.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,409 @@
|
|
|
1
|
+
# cimport multipers.tensor as mt
|
|
2
|
+
from libc.stdint cimport intptr_t, uint16_t, uint32_t, int32_t, int64_t
|
|
3
|
+
from libcpp.vector cimport vector
|
|
4
|
+
from libcpp cimport bool, int, float
|
|
5
|
+
import numpy as np
|
|
6
|
+
cimport numpy as cnp
|
|
7
|
+
import itertools
|
|
8
|
+
from typing import Optional,Iterable
|
|
9
|
+
|
|
10
|
+
from collections import defaultdict
|
|
11
|
+
cnp.import_array()
|
|
12
|
+
from scipy import sparse
|
|
13
|
+
|
|
14
|
+
from multipers.array_api import api_from_tensor, api_from_tensors
|
|
15
|
+
|
|
16
|
+
import multipers.grids as mpg
|
|
17
|
+
|
|
18
|
+
ctypedef fused some_int:
|
|
19
|
+
int32_t
|
|
20
|
+
int64_t
|
|
21
|
+
int
|
|
22
|
+
|
|
23
|
+
ctypedef fused some_float:
|
|
24
|
+
int32_t
|
|
25
|
+
int64_t
|
|
26
|
+
int
|
|
27
|
+
float
|
|
28
|
+
double
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
import cython
|
|
32
|
+
cimport cython
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
# from scipy.sparse import coo_array
|
|
36
|
+
# from scipy.ndimage import convolve1d
|
|
37
|
+
|
|
38
|
+
def signed_betti(hilbert_function:np.ndarray, bool threshold=False):
|
|
39
|
+
cdef int n = hilbert_function.ndim
|
|
40
|
+
# zero out the "end" of the Hilbert function
|
|
41
|
+
if threshold:
|
|
42
|
+
for dimension in range(n):
|
|
43
|
+
slicer = tuple([slice(None) if i != dimension else -1 for i in range(n)])
|
|
44
|
+
hilbert_function[slicer] = 0
|
|
45
|
+
for i in range(n):
|
|
46
|
+
minus = tuple([slice(None) if j!=i else slice(0,-1) for j in range(n)])
|
|
47
|
+
plus = tuple([slice(None) if j!=i else slice(1,None) for j in range(n)])
|
|
48
|
+
hilbert_function[plus] -= hilbert_function[minus]
|
|
49
|
+
return hilbert_function
|
|
50
|
+
|
|
51
|
+
def rank_decomposition_by_rectangles(rank_invariant:np.ndarray, bool threshold=False):
|
|
52
|
+
# takes as input the rank invariant of an n-parameter persistence module
|
|
53
|
+
# M : [0, ..., s_1 - 1] x ... x [0, ..., s_n - 1] ---> Vec
|
|
54
|
+
# on a grid with dimensions of sizes s_1, ..., s_n. The input is assumed to be
|
|
55
|
+
# given as a tensor of dimensions (s_1, ..., s_n, s_1, ..., s_n), so that,
|
|
56
|
+
# at index [i_1, ..., i_n, j_1, ..., j_n] we have the rank of the structure
|
|
57
|
+
# map M(i) -> M(j), where i = (i_1, ..., i_n) and j = (j_1, ..., j_n), and
|
|
58
|
+
# i <= j, meaning that i_1 <= j_1, ..., i_n <= j_n.
|
|
59
|
+
# NOTE :
|
|
60
|
+
# - About the input, we assume that, if not( i <= j ), then at index
|
|
61
|
+
# [i_1, ..., i_n, j_1, ..., j_n] we have a zero.
|
|
62
|
+
# - Similarly, the output at index [i_1, ..., i_n, j_1, ..., j_n] only
|
|
63
|
+
# makes sense when i <= j. For indices where not( i <= j ) the output
|
|
64
|
+
# may take arbitrary values and they should be ignored.
|
|
65
|
+
cdef int n = rank_invariant.ndim // 2
|
|
66
|
+
if threshold:
|
|
67
|
+
# zero out the "end"
|
|
68
|
+
for dimension in range(n):
|
|
69
|
+
slicer = tuple(
|
|
70
|
+
[slice(None) for _ in range(n)]
|
|
71
|
+
+ [slice(None) if i != dimension else -1 for i in range(n)]
|
|
72
|
+
)
|
|
73
|
+
rank_invariant[slicer] = 0
|
|
74
|
+
to_flip = tuple(range(n, 2 * n))
|
|
75
|
+
return np.flip(signed_betti(np.flip(rank_invariant, to_flip)), to_flip)
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
@cython.boundscheck(False)
|
|
84
|
+
@cython.wraparound(False)
|
|
85
|
+
def integrate_measure(
|
|
86
|
+
some_float[:,:] pts,
|
|
87
|
+
some_int[:] weights,
|
|
88
|
+
filtration_grid:Optional[Iterable[np.ndarray]]=None,
|
|
89
|
+
grid_strategy:str="regular",
|
|
90
|
+
resolution:int|list[int]=100,
|
|
91
|
+
bool return_grid=False,
|
|
92
|
+
bool plot=False,
|
|
93
|
+
**get_fitration_kwargs,
|
|
94
|
+
):
|
|
95
|
+
"""
|
|
96
|
+
Integrate a point measure on a grid.
|
|
97
|
+
Measure is a sum of diracs, based on points `pts` and weights `weights`.
|
|
98
|
+
For instance, if the signed measure comes from the hilbert signed measure,
|
|
99
|
+
this integration will return the hilbert function on this grid.
|
|
100
|
+
- pts : array of points (num_pts, D)
|
|
101
|
+
- weights : array of weights (num_pts,)
|
|
102
|
+
- filtration_grid (optional) : list of 1d arrays
|
|
103
|
+
- resolution : int or list of int
|
|
104
|
+
- return_grid : return the grid of the measure
|
|
105
|
+
- **get_fitration_kwargs : arguments to compute the grid,
|
|
106
|
+
if the grid is not given.
|
|
107
|
+
"""
|
|
108
|
+
if filtration_grid is None:
|
|
109
|
+
import multipers.simplex_tree_multi
|
|
110
|
+
filtration_grid = mpg.compute_grid(
|
|
111
|
+
np.asarray(pts).T,
|
|
112
|
+
strategy=grid_strategy,
|
|
113
|
+
resolution=resolution,
|
|
114
|
+
**get_fitration_kwargs
|
|
115
|
+
)
|
|
116
|
+
if pts.size == 0:
|
|
117
|
+
return np.empty()
|
|
118
|
+
resolution = np.asarray([len(f) for f in filtration_grid])
|
|
119
|
+
cdef int num_pts = pts.shape[0]
|
|
120
|
+
cdef int num_parameters = pts.shape[1]
|
|
121
|
+
assert weights.shape[0] == num_pts
|
|
122
|
+
out = np.zeros(shape=resolution, dtype=np.int32) ## dim cannot be known at compiletime
|
|
123
|
+
# cdef some_float[:] filtration_of_parameter
|
|
124
|
+
# cdef cnp.ndarray indices = np.zeros(shape=num_parameters, dtype=int)
|
|
125
|
+
#
|
|
126
|
+
pts_coords = np.empty((num_parameters, num_pts), dtype=np.int64)
|
|
127
|
+
for parameter in range(num_parameters):
|
|
128
|
+
pts_coords[parameter] = np.searchsorted(filtration_grid[parameter], pts[:,parameter])
|
|
129
|
+
for i in range(num_pts):
|
|
130
|
+
cone = tuple(slice(c,r) for r,c in zip(resolution,pts_coords[:,i]))
|
|
131
|
+
out[cone] += weights[i]
|
|
132
|
+
if plot:
|
|
133
|
+
from multipers.plots import plot_surface
|
|
134
|
+
plot_surface(filtration_grid, out, discrete_surface=True)
|
|
135
|
+
if return_grid:
|
|
136
|
+
return out,filtration_grid
|
|
137
|
+
return out
|
|
138
|
+
|
|
139
|
+
## for benchmark purposes
|
|
140
|
+
def integrate_measure_python(pts, weights, filtrations):
|
|
141
|
+
resolution = tuple([len(f) for f in filtrations])
|
|
142
|
+
out = np.zeros(shape=resolution, dtype=pts.dtype)
|
|
143
|
+
num_pts = pts.shape[0]
|
|
144
|
+
num_parameters = pts.shape[1]
|
|
145
|
+
for i in range(num_pts): #this is slow.
|
|
146
|
+
indices = (filtrations[parameter]>=pts[i][parameter] for parameter in range(num_parameters))
|
|
147
|
+
out[np.ix_(*indices)] += weights[i]
|
|
148
|
+
return out
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
@cython.boundscheck(False)
|
|
152
|
+
@cython.wraparound(False)
|
|
153
|
+
def sparsify(x):
|
|
154
|
+
"""
|
|
155
|
+
Given an arbitrary dimensional numpy array, returns (coordinates,data).
|
|
156
|
+
--
|
|
157
|
+
cost : scipy sparse + num_points*num_parameters^2 divisions
|
|
158
|
+
"""
|
|
159
|
+
num_parameters = x.ndim
|
|
160
|
+
sx = sparse.coo_array(x.ravel())
|
|
161
|
+
idx = sx.col
|
|
162
|
+
data = sx.data
|
|
163
|
+
coords = np.empty((data.shape[0], num_parameters), dtype=np.int64)
|
|
164
|
+
for parameter in range(num_parameters-1,-1,-1):
|
|
165
|
+
idx,coord_of_parameter = np.divmod(idx, x.shape[parameter])
|
|
166
|
+
coords[:, parameter] = coord_of_parameter
|
|
167
|
+
return coords,data
|
|
168
|
+
|
|
169
|
+
|
|
170
|
+
|
|
171
|
+
|
|
172
|
+
@cython.boundscheck(False)
|
|
173
|
+
@cython.wraparound(False)
|
|
174
|
+
def clean_signed_measure_old(some_float[:,:] pts, some_int[:] weights, dtype = np.float32):
|
|
175
|
+
"""
|
|
176
|
+
Sum the diracs at the same locations. i.e.,
|
|
177
|
+
returns the minimal sized measure to represent the input.
|
|
178
|
+
Mostly useful for, e.g., euler_characteristic from simplical complexes.
|
|
179
|
+
"""
|
|
180
|
+
cdef dict[tuple, int] out = {}
|
|
181
|
+
cdef int num_diracs
|
|
182
|
+
cdef int num_parameters
|
|
183
|
+
num_diracs, num_parameters = pts.shape[:2]
|
|
184
|
+
for i in range(num_diracs):
|
|
185
|
+
key = tuple(pts[i]) # size cannot be known at compiletime
|
|
186
|
+
out[key] = out.get(key,0)+ weights[i]
|
|
187
|
+
num_keys = len(out)
|
|
188
|
+
new_pts = np.fromiter(out.keys(), dtype=np.dtype((dtype,num_parameters)), count=num_keys)
|
|
189
|
+
new_weights = np.fromiter(out.values(), dtype=np.int32, count=num_keys)
|
|
190
|
+
idx = np.nonzero(new_weights)
|
|
191
|
+
new_pts = new_pts[idx]
|
|
192
|
+
new_weights = new_weights[idx]
|
|
193
|
+
return (new_pts, new_weights)
|
|
194
|
+
|
|
195
|
+
def clean_signed_measure(pts, w, dtype=np.int32):
|
|
196
|
+
api = api_from_tensor(pts)
|
|
197
|
+
_, idx, inv = np.unique(api.asnumpy(pts), return_index=True, return_inverse=True, axis=0)
|
|
198
|
+
new_w = np.bincount(inv, weights=w).astype(w.dtype)
|
|
199
|
+
pts, w = pts[idx], new_w
|
|
200
|
+
idx = w!=0
|
|
201
|
+
return pts[idx],w[idx]
|
|
202
|
+
|
|
203
|
+
def clean_sms(sms):
|
|
204
|
+
"""
|
|
205
|
+
Sum the diracs at the same locations. i.e.,
|
|
206
|
+
returns the minimal sized measure to represent the input.
|
|
207
|
+
Mostly useful for, e.g., euler_characteristic from simplical complexes.
|
|
208
|
+
"""
|
|
209
|
+
return tuple(clean_signed_measure(pts,weights) for pts,weights in sms)
|
|
210
|
+
|
|
211
|
+
def zero_out_sm(pts,weights, mass_default):
|
|
212
|
+
"""
|
|
213
|
+
Zeros out the modules outside of \f$ \{ x\in \mathbb R^n \mid x \le \mathrm{mass_default}\}\f$.
|
|
214
|
+
"""
|
|
215
|
+
from itertools import product
|
|
216
|
+
# merge pts, weights
|
|
217
|
+
PTS = np.concatenate([pts,weights[:,None]], axis=1)[None]
|
|
218
|
+
|
|
219
|
+
num_diracs, num_parameters=pts.shape
|
|
220
|
+
|
|
221
|
+
# corners of the square of dim num_parameters. shape : (num_corners,num_parameters)
|
|
222
|
+
C = np.fromiter(product(*([[1,0]]*num_parameters)), dtype=np.dtype((np.bool_, num_parameters)),)
|
|
223
|
+
Cw = 1-2*((~C).sum(axis=1)%2)
|
|
224
|
+
# add 1 in the end to copy the shape
|
|
225
|
+
C = np.concatenate([C, np.ones((C.shape[0],1))], axis=1).astype(np.bool_)
|
|
226
|
+
|
|
227
|
+
# signs of each corner
|
|
228
|
+
Cw = 1-2*((~C).sum(axis=1) & 1)
|
|
229
|
+
|
|
230
|
+
# something useless in the end to ensure that the shape is correct (as we added 1 in pts)
|
|
231
|
+
mass_default = np.concatenate([mass_default,[np.nan]])
|
|
232
|
+
mass_default = mass_default[None,None,:] ## num c, num_pts, num_params
|
|
233
|
+
# each point `pt` becomes a corner of the square [`pt`, `mass_default`]
|
|
234
|
+
new= np.where(C[:,None,:], PTS,mass_default).reshape(-1,(num_parameters+1))
|
|
235
|
+
new_pts = new[:,:-1]
|
|
236
|
+
new_masses = new[:,-1]*np.repeat(Cw,num_diracs)
|
|
237
|
+
## a bunch of stuff are in the same place, better clean it
|
|
238
|
+
return clean_signed_measure(new_pts.astype(np.float64), new_masses.astype(np.int64), dtype=np.float64)
|
|
239
|
+
|
|
240
|
+
def zero_out_sms(sms, mass_default):
|
|
241
|
+
"""
|
|
242
|
+
Zeros out the modules outside of \f$ \{ x\in \mathbb R^n \mid x \le \mathrm{mass_default}\}\f$.
|
|
243
|
+
"""
|
|
244
|
+
return tuple(zero_out_sm(pts,weights, mass_default) for pts,weights in sms)
|
|
245
|
+
def add_sms(sms):
|
|
246
|
+
if len(sms) == 0:
|
|
247
|
+
return (np.empty((0,2)), np.empty())
|
|
248
|
+
pts = tuple(sm[0][:] for sm in sms)
|
|
249
|
+
api = api_from_tensor(pts[0])
|
|
250
|
+
pts = api.cat(pts)
|
|
251
|
+
|
|
252
|
+
weights = tuple(sm[1][:] for sm in sms)
|
|
253
|
+
api = api_from_tensor(weights[0])
|
|
254
|
+
weights = api.cat(weights)
|
|
255
|
+
|
|
256
|
+
return (pts,weights)
|
|
257
|
+
|
|
258
|
+
@cython.boundscheck(False)
|
|
259
|
+
@cython.wraparound(False)
|
|
260
|
+
def barcode_from_rank_sm(
|
|
261
|
+
sm: tuple[np.ndarray, np.ndarray],
|
|
262
|
+
basepoint: np.ndarray,
|
|
263
|
+
direction: Optional[np.ndarray] = None,
|
|
264
|
+
bool full = False,
|
|
265
|
+
):
|
|
266
|
+
"""
|
|
267
|
+
Given a rank signed measure `sm` and a line with basepoint `basepoint` (1darray) and
|
|
268
|
+
direction `direction` (1darray), projects the rank signed measure on the given line,
|
|
269
|
+
and returns the associated estimated barcode.
|
|
270
|
+
If full is True, the barcode is given as coordinates in R^{`num_parameters`} instead
|
|
271
|
+
of coordinates w.r.t. the line.
|
|
272
|
+
"""
|
|
273
|
+
basepoint = np.asarray(basepoint)
|
|
274
|
+
num_parameters = basepoint.shape[0]
|
|
275
|
+
x, w = sm
|
|
276
|
+
assert (
|
|
277
|
+
x.shape[1] // 2 == num_parameters
|
|
278
|
+
), f"Incoherent number of parameters. sm:{x.shape[1]//2} vs {num_parameters}"
|
|
279
|
+
x, y = x[:, :num_parameters], x[:, num_parameters:]
|
|
280
|
+
if direction is not None:
|
|
281
|
+
direction = np.asarray(direction)
|
|
282
|
+
ok_idx = direction > 0
|
|
283
|
+
if ok_idx.sum() == 0:
|
|
284
|
+
raise ValueError(f"Got invalid direction {direction}")
|
|
285
|
+
zero_idx = None if np.all(ok_idx) else direction == 0
|
|
286
|
+
else:
|
|
287
|
+
direction = np.asarray([1], dtype=int)
|
|
288
|
+
ok_idx = slice(None)
|
|
289
|
+
zero_idx = None
|
|
290
|
+
xa = np.max(
|
|
291
|
+
(x[:, ok_idx] - basepoint[ok_idx]) / direction[ok_idx], axis=1, keepdims=1
|
|
292
|
+
)
|
|
293
|
+
ya = np.min(
|
|
294
|
+
(y[:, ok_idx] - basepoint[ok_idx]) / direction[ok_idx], axis=1, keepdims=1
|
|
295
|
+
)
|
|
296
|
+
if zero_idx is not None:
|
|
297
|
+
xb = np.where(x[:, zero_idx] <= basepoint[zero_idx], -np.inf, np.inf)
|
|
298
|
+
yb = np.where(y[:, zero_idx] <= basepoint[zero_idx], -np.inf, np.inf)
|
|
299
|
+
xs = np.max(np.concatenate([xa, xb], axis=1), axis=1, keepdims=1)
|
|
300
|
+
ys = np.min(np.concatenate([ya, yb], axis=1), axis=1, keepdims=1)
|
|
301
|
+
else:
|
|
302
|
+
xs = xa
|
|
303
|
+
ys = ya
|
|
304
|
+
out = np.concatenate([xs, ys], axis=1,dtype=np.float64)
|
|
305
|
+
|
|
306
|
+
## TODO: check if this is faster than doing a np.repeat on x ?
|
|
307
|
+
cdef dict[dict,tuple] d = {}
|
|
308
|
+
cdef double[:,:] c_out = out # view
|
|
309
|
+
cdef int64_t[:] c_w = np.asarray(w,dtype=np.int64)
|
|
310
|
+
cdef int num_pts = out.shape[0]
|
|
311
|
+
# for i, stuff in enumerate(out):
|
|
312
|
+
# if stuff[0] < np.inf:
|
|
313
|
+
# d[tuple(stuff)] = d.get(tuple(stuff), 0) + w[i]
|
|
314
|
+
for i in range(num_pts):
|
|
315
|
+
if c_out[i][0] < np.inf:
|
|
316
|
+
machin = tuple(c_out[i])
|
|
317
|
+
d[machin] = d.get(machin, 0) + c_w[i]
|
|
318
|
+
|
|
319
|
+
out = np.fromiter(
|
|
320
|
+
itertools.chain.from_iterable(([x] * w for x, w in d.items() if x[0] < x[1])),
|
|
321
|
+
dtype=np.dtype((np.float64, 2)),
|
|
322
|
+
)
|
|
323
|
+
if full:
|
|
324
|
+
out = basepoint[None, None] + out[..., None] * direction[None, None]
|
|
325
|
+
return out
|
|
326
|
+
|
|
327
|
+
|
|
328
|
+
def estimate_rank_from_rank_sm(sm:tuple, a, b)->np.int64:
|
|
329
|
+
"""
|
|
330
|
+
Given a rank signed measure (sm) and two points (a) and (b),
|
|
331
|
+
estimates the rank between these two points.
|
|
332
|
+
"""
|
|
333
|
+
a = np.asarray(a)
|
|
334
|
+
b = np.asarray(b)
|
|
335
|
+
if not (a <= b).all():
|
|
336
|
+
return 0
|
|
337
|
+
x, w = sm
|
|
338
|
+
num_parameters = x.shape[1] // 2
|
|
339
|
+
assert (
|
|
340
|
+
a.shape[0] == b.shape[0] == num_parameters
|
|
341
|
+
), f"Incoherent number of parameters. sm:{num_parameters} vs {a.shape[0]} and {b.shape[0]}"
|
|
342
|
+
idx = (
|
|
343
|
+
(x[:, :num_parameters] <= a[None]).all(1)
|
|
344
|
+
* (x[:, num_parameters:] >= b[None]).all(1)
|
|
345
|
+
).ravel()
|
|
346
|
+
return w[idx].sum()
|
|
347
|
+
|
|
348
|
+
|
|
349
|
+
def rectangle_to_hook_minimal_signed_barcode(pts,w,):
|
|
350
|
+
if pts.shape[1] != 4:
|
|
351
|
+
raise NotImplementedError(
|
|
352
|
+
"Only works for 2-parameter persistence modules for the moment."
|
|
353
|
+
)
|
|
354
|
+
api = api_from_tensor(pts)
|
|
355
|
+
pts = api.astensor(pts)
|
|
356
|
+
w = np.asarray(w)
|
|
357
|
+
## [a,b], [a, a0b1], [a,b0a1], proj, V,H
|
|
358
|
+
|
|
359
|
+
projectives_idx = (pts[:,3] == np.inf) * (pts[:,2] == np.inf)
|
|
360
|
+
pts_proj = pts[projectives_idx]
|
|
361
|
+
w_proj = w[projectives_idx]
|
|
362
|
+
pts = pts[~projectives_idx]
|
|
363
|
+
w = w[~projectives_idx]
|
|
364
|
+
# print("projectives:", pts_proj)
|
|
365
|
+
|
|
366
|
+
vert_blocks_idx = pts[:,3] == np.inf
|
|
367
|
+
pts_V = pts[vert_blocks_idx]
|
|
368
|
+
w_V = w[vert_blocks_idx]
|
|
369
|
+
pts_V[:,3] = pts_V[:,1]
|
|
370
|
+
pts = pts[~vert_blocks_idx]
|
|
371
|
+
w = w[~vert_blocks_idx]
|
|
372
|
+
# print("vertical:", pts_V)
|
|
373
|
+
|
|
374
|
+
h_idx = pts[:,2] == np.inf
|
|
375
|
+
pts_H = pts[h_idx]
|
|
376
|
+
w_H = w[h_idx]
|
|
377
|
+
pts_H[:,2] = pts_H[:,0]
|
|
378
|
+
pts = pts[~h_idx]
|
|
379
|
+
w = w[~h_idx]
|
|
380
|
+
# print("horizontal:", pts_H)
|
|
381
|
+
|
|
382
|
+
|
|
383
|
+
new_w = np.concatenate([-w, w, w, w_proj,w_V,w_H])
|
|
384
|
+
|
|
385
|
+
pts_b0a1 = api.tensor(pts)
|
|
386
|
+
pts_b0a1[:,3] = pts[:,1]
|
|
387
|
+
pts_a0b1 = api.tensor(pts)
|
|
388
|
+
pts_a0b1[:,2] = pts[:,0]
|
|
389
|
+
|
|
390
|
+
new_pts = api.cat([
|
|
391
|
+
pts,
|
|
392
|
+
pts_b0a1,
|
|
393
|
+
pts_a0b1,
|
|
394
|
+
pts_proj,
|
|
395
|
+
pts_V,
|
|
396
|
+
pts_H
|
|
397
|
+
], axis=0)
|
|
398
|
+
# pts,w = new_pts,new_w
|
|
399
|
+
pts,w = clean_signed_measure(new_pts,new_w)
|
|
400
|
+
|
|
401
|
+
# Everything infinite is handled separately anyway
|
|
402
|
+
# inf0 = pts[:,2] == np.inf
|
|
403
|
+
# inf1 = pts[:,3] == np.inf
|
|
404
|
+
# pts[inf0,3] = pts[inf0,1]
|
|
405
|
+
# pts[inf1,2] = pts[inf1,0]
|
|
406
|
+
# pts,w = clean_signed_measure(pts,w)
|
|
407
|
+
|
|
408
|
+
return pts,w
|
|
409
|
+
|
|
Binary file
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
# This file is part of the Gudhi Library - https://gudhi.inria.fr/ - which is released under MIT.
|
|
2
|
+
# See file LICENSE or go to https://gudhi.inria.fr/licensing/ for full license details.
|
|
3
|
+
# Author(s): Vincent Rouvreau
|
|
4
|
+
#
|
|
5
|
+
# Copyright (C) 2016 Inria
|
|
6
|
+
#
|
|
7
|
+
# Modification(s):
|
|
8
|
+
# - 2022 David Loiseaux, Hannah Schreiber: adapt for multipersistence.
|
|
9
|
+
# - YYYY/MM Author: Description of the modification
|
|
10
|
+
|
|
11
|
+
from cython cimport numeric
|
|
12
|
+
from libcpp.vector cimport vector
|
|
13
|
+
from libcpp.utility cimport pair
|
|
14
|
+
from libcpp cimport bool
|
|
15
|
+
from libcpp.string cimport string
|
|
16
|
+
from libcpp.map cimport map
|
|
17
|
+
|
|
18
|
+
from libc.stdint cimport intptr_t, int32_t
|
|
19
|
+
|
|
20
|
+
__author__ = "Vincent Rouvreau"
|
|
21
|
+
__copyright__ = "Copyright (C) 2016 Inria"
|
|
22
|
+
__license__ = "MIT"
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
from multipers.filtrations cimport *
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
ctypedef int dimension_type
|
|
29
|
+
ctypedef vector[int] simplex_type
|
|
30
|
+
ctypedef vector[int] simplex_list
|
|
31
|
+
ctypedef vector[pair[pair[int,int], pair[double, double]]] edge_list
|
|
32
|
+
ctypedef vector[int] euler_char_list
|
|
33
|
+
|
|
34
|
+
ctypedef vector[unsigned int] boundary_type
|
|
35
|
+
ctypedef vector[boundary_type] boundary_matrix
|
|
36
|
+
|
|
37
|
+
cdef extern from "Simplex_tree_multi_interface.h" namespace "Gudhi::multiparameter::python_interface":
|
|
38
|
+
|
|
39
|
+
cdef cppclass Simplex_tree_multi_simplex_handle[F=*]:
|
|
40
|
+
pass
|
|
41
|
+
|
|
42
|
+
cdef cppclass Simplex_tree_multi_simplices_iterator[F=*]:
|
|
43
|
+
Simplex_tree_multi_simplices_iterator() nogil
|
|
44
|
+
Simplex_tree_multi_simplex_handle& operator*() nogil
|
|
45
|
+
Simplex_tree_multi_simplices_iterator operator++() nogil
|
|
46
|
+
bint operator!=(Simplex_tree_multi_simplices_iterator) nogil
|
|
47
|
+
|
|
48
|
+
cdef cppclass Simplex_tree_multi_skeleton_iterator[F=*]:
|
|
49
|
+
Simplex_tree_multi_skeleton_iterator() nogil
|
|
50
|
+
Simplex_tree_multi_simplex_handle& operator*() nogil
|
|
51
|
+
Simplex_tree_multi_skeleton_iterator operator++() nogil
|
|
52
|
+
bint operator!=(Simplex_tree_multi_skeleton_iterator) nogil
|
|
53
|
+
|
|
54
|
+
cdef cppclass Simplex_tree_multi_boundary_iterator[F=*]:
|
|
55
|
+
Simplex_tree_multi_boundary_iterator() nogil
|
|
56
|
+
Simplex_tree_multi_simplex_handle& operator*() nogil
|
|
57
|
+
Simplex_tree_multi_boundary_iterator operator++() nogil
|
|
58
|
+
bint operator!=(Simplex_tree_multi_boundary_iterator) nogil
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
cdef cppclass Simplex_tree_multi_interface[F=*, value_type=*]:
|
|
62
|
+
ctypedef pair[simplex_type, F*] simplex_filtration_type
|
|
63
|
+
Simplex_tree_multi_interface() nogil
|
|
64
|
+
Simplex_tree_multi_interface(Simplex_tree_multi_interface&) nogil
|
|
65
|
+
F* simplex_filtration(const vector[int]& simplex) except + nogil
|
|
66
|
+
void assign_simplex_filtration(vector[int]& simplex, const F& filtration) noexcept nogil
|
|
67
|
+
void initialize_filtration() nogil
|
|
68
|
+
int num_vertices() nogil
|
|
69
|
+
int num_simplices() nogil
|
|
70
|
+
void set_dimension(int dimension) nogil
|
|
71
|
+
dimension_type dimension() nogil
|
|
72
|
+
dimension_type upper_bound_dimension() nogil
|
|
73
|
+
bool find_simplex(vector[int]& simplex) nogil
|
|
74
|
+
bool insert(vector[int]& simplex, F& filtration) noexcept nogil
|
|
75
|
+
bool insert_force(vector[int]& simplex, F& filtration) noexcept nogil
|
|
76
|
+
# vector[simplex_filtration_type] get_star(const vector[int]& simplex) nogil
|
|
77
|
+
# vector[simplex_filtration_type] get_cofaces(const vector[int]& simplex, int dimension) nogil
|
|
78
|
+
void expansion(int max_dim) except + nogil
|
|
79
|
+
void remove_maximal_simplex(simplex_type simplex) nogil
|
|
80
|
+
# bool prune_above_filtration(filtration_type filtration) nogil
|
|
81
|
+
bool prune_above_dimension(int dimension) nogil
|
|
82
|
+
bool make_filtration_non_decreasing() except + nogil
|
|
83
|
+
# void compute_extended_filtration() nogil
|
|
84
|
+
# Simplex_tree_multi_interface* collapse_edges(int nb_collapse_iteration) except + nogil
|
|
85
|
+
void reset_filtration(const F& filtration, int dimension) nogil
|
|
86
|
+
bint operator==(Simplex_tree_multi_interface) nogil
|
|
87
|
+
# Iterators over Simplex tree
|
|
88
|
+
pair[simplex_type,F*] get_simplex_and_filtration(Simplex_tree_multi_simplex_handle f_simplex) nogil
|
|
89
|
+
Simplex_tree_multi_simplices_iterator[F] get_simplices_iterator_begin() nogil
|
|
90
|
+
Simplex_tree_multi_simplices_iterator[F] get_simplices_iterator_end() nogil
|
|
91
|
+
vector[Simplex_tree_multi_simplex_handle[F]].const_iterator get_filtration_iterator_begin() nogil
|
|
92
|
+
vector[Simplex_tree_multi_simplex_handle[F]].const_iterator get_filtration_iterator_end() nogil
|
|
93
|
+
Simplex_tree_multi_skeleton_iterator get_skeleton_iterator_begin(int dimension) nogil
|
|
94
|
+
Simplex_tree_multi_skeleton_iterator get_skeleton_iterator_end(int dimension) nogil
|
|
95
|
+
pair[Simplex_tree_multi_boundary_iterator, Simplex_tree_multi_boundary_iterator] get_boundary_iterators(vector[int] simplex) except + nogil
|
|
96
|
+
# Expansion with blockers
|
|
97
|
+
ctypedef bool (*blocker_func_t)(vector[int], void *user_data)
|
|
98
|
+
void expansion_with_blockers_callback(int dimension, blocker_func_t user_func, void *user_data)
|
|
99
|
+
|
|
100
|
+
## MULTIPERS STUFF
|
|
101
|
+
void set_keys_to_enumerate() nogil const
|
|
102
|
+
int get_key(const simplex_type) nogil
|
|
103
|
+
void set_key(simplex_type, int) nogil
|
|
104
|
+
void fill_lowerstar(vector[value_type]&, int) except+ nogil
|
|
105
|
+
simplex_list get_simplices_of_dimension(int) nogil
|
|
106
|
+
edge_list get_edge_list() nogil
|
|
107
|
+
# euler_char_list euler_char(const vector[filtration_type]&) nogil
|
|
108
|
+
void resize_all_filtrations(int) nogil
|
|
109
|
+
void set_num_parameters(int) nogil
|
|
110
|
+
int num_parameters() nogil
|
|
111
|
+
void serialize(char* buffer, const size_t buffer_size) except + nogil
|
|
112
|
+
void deserialize(const char* buffer, const size_t buffer_size) except + nogil
|
|
113
|
+
size_t get_serialization_size() nogil
|
|
114
|
+
void clear() nogil
|
|
115
|
+
|
|
116
|
+
dimension_type simplex_dimension(const simplex_type&) nogil
|
|
117
|
+
|
|
118
|
+
void from_std(char*, size_t, int, vector[value_type]&) nogil
|
|
119
|
+
void to_std(intptr_t, Line[double],int ) nogil
|
|
120
|
+
void to_std_linear_projection(intptr_t, vector[double]) nogil
|
|
121
|
+
void squeeze_filtration_inplace(vector[vector[double]] &, bool) nogil
|
|
122
|
+
void squeeze_filtration(intptr_t, vector[vector[double]] &) except + nogil
|
|
123
|
+
void unsqueeze_filtration(intptr_t, vector[vector[double]] &) except + nogil
|
|
124
|
+
vector[vector[vector[value_type]]] get_filtration_values(const vector[int]&) nogil
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
pair[boundary_matrix, vector[One_critical_filtration[value_type]]] simplextree_to_boundary_filtration()
|
|
128
|
+
vector[pair[ vector[vector[value_type]],boundary_matrix]] simplextree_to_scc()
|
|
129
|
+
vector[pair[ vector[vector[vector[value_type]]],boundary_matrix]] kcritical_simplextree_to_scc()
|
|
130
|
+
|
|
131
|
+
vector[pair[ vector[vector[vector[value_type]]],boundary_matrix]] function_simplextree_to_scc()
|
|
132
|
+
pair[vector[vector[value_type]],boundary_matrix ] simplextree_to_ordered_bf()
|
|
133
|
+
# vector[map[value_type,int32_t]] build_idx_map(const vector[int]&) nogil
|
|
134
|
+
# pair[vector[vector[int32_t]],vector[vector[int32_t]]] get_pts_indices(const vector[map[value_type,int32_t]]&, const vector[vector[value_type]]&) nogil
|
|
135
|
+
pair[vector[vector[int32_t]],vector[vector[int32_t]]] pts_to_indices(vector[vector[value_type]]&, vector[int]&) nogil
|
|
136
|
+
|