multipers 2.3.0__cp310-cp310-win_amd64.whl → 2.3.2b1__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/_signed_measure_meta.py +71 -65
- multipers/array_api/__init__.py +39 -0
- multipers/array_api/numpy.py +34 -0
- multipers/array_api/torch.py +35 -0
- multipers/distances.py +6 -2
- multipers/{ml/convolutions.py → filtrations/density.py} +67 -13
- multipers/filtrations/filtrations.py +76 -17
- multipers/function_rips.cp310-win_amd64.pyd +0 -0
- multipers/grids.cp310-win_amd64.pyd +0 -0
- multipers/grids.pyx +144 -61
- multipers/gudhi/Simplex_tree_multi_interface.h +36 -1
- multipers/gudhi/gudhi/Multi_persistence/Box.h +3 -0
- multipers/gudhi/gudhi/One_critical_filtration.h +18 -9
- multipers/gudhi/mma_interface_h0.h +1 -1
- multipers/gudhi/mma_interface_matrix.h +10 -1
- multipers/gudhi/naive_merge_tree.h +1 -1
- multipers/gudhi/truc.h +555 -42
- multipers/io.cp310-win_amd64.pyd +0 -0
- multipers/io.pyx +26 -93
- multipers/ml/mma.py +3 -3
- multipers/ml/point_clouds.py +2 -2
- multipers/ml/signed_measures.py +63 -65
- multipers/mma_structures.cp310-win_amd64.pyd +0 -0
- multipers/mma_structures.pxd +2 -1
- multipers/mma_structures.pyx +56 -16
- multipers/mma_structures.pyx.tp +14 -5
- multipers/multiparameter_module_approximation/approximation.h +48 -14
- multipers/multiparameter_module_approximation.cp310-win_amd64.pyd +0 -0
- multipers/multiparameter_module_approximation.pyx +25 -7
- multipers/plots.py +2 -1
- multipers/point_measure.cp310-win_amd64.pyd +0 -0
- multipers/point_measure.pyx +6 -2
- multipers/simplex_tree_multi.cp310-win_amd64.pyd +0 -0
- multipers/simplex_tree_multi.pxd +1 -0
- multipers/simplex_tree_multi.pyx +584 -142
- multipers/simplex_tree_multi.pyx.tp +80 -23
- multipers/slicer.cp310-win_amd64.pyd +0 -0
- multipers/slicer.pxd +799 -197
- multipers/slicer.pxd.tp +24 -5
- multipers/slicer.pyx +5653 -1426
- multipers/slicer.pyx.tp +208 -48
- 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 +1 -1
- multipers/tests/__init__.py +9 -4
- multipers/torch/diff_grids.py +30 -7
- multipers/torch/rips_density.py +1 -1
- {multipers-2.3.0.dist-info → multipers-2.3.2b1.dist-info}/METADATA +4 -25
- {multipers-2.3.0.dist-info → multipers-2.3.2b1.dist-info}/RECORD +54 -51
- {multipers-2.3.0.dist-info → multipers-2.3.2b1.dist-info}/WHEEL +1 -1
- {multipers-2.3.0.dist-info → multipers-2.3.2b1.dist-info/licenses}/LICENSE +0 -0
- {multipers-2.3.0.dist-info → multipers-2.3.2b1.dist-info}/top_level.txt +0 -0
multipers/simplex_tree_multi.pyx
CHANGED
|
@@ -51,7 +51,8 @@ cimport cython
|
|
|
51
51
|
from gudhi.simplex_tree import SimplexTree ## Small hack for typing
|
|
52
52
|
from typing import Iterable,Literal,Optional
|
|
53
53
|
from tqdm import tqdm
|
|
54
|
-
from multipers.grids import Lstrategies, compute_grid
|
|
54
|
+
from multipers.grids import Lstrategies, compute_grid, sanitize_grid
|
|
55
|
+
from multipers.array_api import api_from_tensor
|
|
55
56
|
from multipers.point_measure import signed_betti, rank_decomposition_by_rectangles, sparsify
|
|
56
57
|
|
|
57
58
|
from warnings import warn
|
|
@@ -81,15 +82,15 @@ cdef class SimplexTreeMulti_KFi32:
|
|
|
81
82
|
"""
|
|
82
83
|
cdef public intptr_t thisptr
|
|
83
84
|
|
|
84
|
-
cdef public
|
|
85
|
-
cdef public bool _is_function_simplextree
|
|
85
|
+
cdef public object filtration_grid
|
|
86
|
+
cdef public bool _is_function_simplextree # TODO : deprecate
|
|
86
87
|
# Get the pointer casted as it should be
|
|
87
88
|
cdef Simplex_tree_multi_interface[KFi32, int32_t]* get_ptr(self) noexcept nogil:
|
|
88
89
|
return <Simplex_tree_multi_interface[KFi32, int32_t]*>(self.thisptr)
|
|
89
90
|
|
|
90
91
|
# cdef Simplex_tree_persistence_interface * pcohptr
|
|
91
92
|
# Fake constructor that does nothing but documenting the constructor
|
|
92
|
-
def __init__(self, other = None, num_parameters:int
|
|
93
|
+
def __init__(self, other = None, num_parameters:int=-1,default_values=[], safe_conversion=False):
|
|
93
94
|
"""SimplexTreeMulti constructor.
|
|
94
95
|
|
|
95
96
|
:param other: If `other` is `None` (default value), an empty `SimplexTreeMulti` is created.
|
|
@@ -114,7 +115,7 @@ cdef class SimplexTreeMulti_KFi32:
|
|
|
114
115
|
def is_kcritical(self)->bool:
|
|
115
116
|
return True
|
|
116
117
|
# The real cython constructor
|
|
117
|
-
def __cinit__(self, other = None, int num_parameters
|
|
118
|
+
def __cinit__(self, other = None, int num_parameters=-1,
|
|
118
119
|
default_values=np.asarray([SimplexTreeMulti_KFi32.T_minus_inf()]), # I'm not sure why `[]` does not work. Cython bug ?
|
|
119
120
|
bool safe_conversion=False,
|
|
120
121
|
): #TODO doc
|
|
@@ -127,10 +128,13 @@ cdef class SimplexTreeMulti_KFi32:
|
|
|
127
128
|
if isinstance(other, SimplexTreeMulti_KFi32):
|
|
128
129
|
other_ptr = other.thisptr
|
|
129
130
|
self.thisptr = <intptr_t>(new Simplex_tree_multi_interface[KFi32, int32_t](dereference(<Simplex_tree_multi_interface[KFi32, int32_t]*>other_ptr))) ## prevents calling destructor of other
|
|
130
|
-
num_parameters
|
|
131
|
+
if num_parameters <=0:
|
|
132
|
+
num_parameters = other.num_parameters
|
|
131
133
|
self.filtration_grid = other.filtration_grid
|
|
132
134
|
elif isinstance(other, SimplexTree): # Constructs a SimplexTreeMulti from a SimplexTree
|
|
133
135
|
self.thisptr = <intptr_t>(new Simplex_tree_multi_interface[KFi32, int32_t]())
|
|
136
|
+
if num_parameters <= 0:
|
|
137
|
+
num_parameters = 1
|
|
134
138
|
if safe_conversion or SAFE_CONVERSION:
|
|
135
139
|
new_st_multi = _safe_simplextree_multify_KFi32(other, num_parameters = num_parameters, default_values=np.asarray(default_values))
|
|
136
140
|
self.thisptr, new_st_multi.thisptr = new_st_multi.thisptr, self.thisptr
|
|
@@ -145,10 +149,12 @@ cdef class SimplexTreeMulti_KFi32:
|
|
|
145
149
|
else:
|
|
146
150
|
raise TypeError("`other` argument requires to be of type `SimplexTree`, `SimplexTreeMulti`, or `None`.")
|
|
147
151
|
else:
|
|
152
|
+
if num_parameters <=0:
|
|
153
|
+
num_parameters = 2 # I don't know how dangerous this is, but this is mostly used.
|
|
148
154
|
self.thisptr = <intptr_t>(new Simplex_tree_multi_interface[KFi32, int32_t]())
|
|
149
|
-
self.
|
|
155
|
+
self.set_num_parameter(num_parameters)
|
|
150
156
|
self._is_function_simplextree = False
|
|
151
|
-
self.filtration_grid=[
|
|
157
|
+
self.filtration_grid=[]
|
|
152
158
|
|
|
153
159
|
def __dealloc__(self):
|
|
154
160
|
cdef Simplex_tree_multi_interface[KFi32,int32_t]* ptr = self.get_ptr()
|
|
@@ -158,6 +164,9 @@ cdef class SimplexTreeMulti_KFi32:
|
|
|
158
164
|
|
|
159
165
|
def __repr__(self):
|
|
160
166
|
return f"SimplexTreeMulti[dtype={np.dtype(self.dtype).name},num_param={self.num_parameters},kcritical={self.is_kcritical},is_squeezed={self.is_squeezed},max_dim={self.dimension}]"
|
|
167
|
+
def __len__(self):
|
|
168
|
+
return self.num_simplices
|
|
169
|
+
|
|
161
170
|
def __getstate__(self):
|
|
162
171
|
""":returns: Serialized (or flattened) SimplexTree data structure in order to pickle SimplexTree.
|
|
163
172
|
:rtype: numpy.array of shape (n,)
|
|
@@ -813,11 +822,26 @@ cdef class SimplexTreeMulti_KFi32:
|
|
|
813
822
|
out = self.get_ptr().get_filtration_values(degrees)
|
|
814
823
|
filtrations_values = [np.asarray(filtration) for filtration in out]
|
|
815
824
|
# Removes infs
|
|
816
|
-
if inf_to_nan:
|
|
825
|
+
if inf_to_nan and np.dtype(filtrations_values[0].dtype).kind == 'f':
|
|
817
826
|
for i,f in enumerate(filtrations_values):
|
|
818
827
|
filtrations_values[i][f == np.inf] = np.nan
|
|
819
828
|
filtrations_values[i][f == - np.inf] = np.nan
|
|
820
829
|
return filtrations_values
|
|
830
|
+
def _clean_filtration_grid(self):
|
|
831
|
+
"""
|
|
832
|
+
Removes the values in filtration_grid that are not linked to any splx.
|
|
833
|
+
"""
|
|
834
|
+
if not self.is_squeezed:
|
|
835
|
+
raise ValueError("No grid to clean.")
|
|
836
|
+
F = self.filtration_grid
|
|
837
|
+
self.filtration_grid=None
|
|
838
|
+
cleaned_coordinates = compute_grid(self)
|
|
839
|
+
new_st = self.grid_squeeze(cleaned_coordinates)
|
|
840
|
+
|
|
841
|
+
self.thisptr, new_st.thisptr = new_st.thisptr, self.thisptr
|
|
842
|
+
self.filtration_grid = tuple(f[g] for f,g in zip(F,cleaned_coordinates))
|
|
843
|
+
return self
|
|
844
|
+
|
|
821
845
|
|
|
822
846
|
|
|
823
847
|
def get_filtration_grid(self, resolution:Iterable[int]|None=None, degrees:Iterable[int]|None=None, drop_quantiles:float|tuple=0, grid_strategy:_available_strategies="exact")->Iterable[np.ndarray]:
|
|
@@ -853,8 +877,16 @@ cdef class SimplexTreeMulti_KFi32:
|
|
|
853
877
|
return compute_grid(filtrations_values, resolution=resolution,strategy=grid_strategy,drop_quantiles=drop_quantiles)
|
|
854
878
|
|
|
855
879
|
|
|
856
|
-
|
|
857
|
-
|
|
880
|
+
def grid_squeeze(
|
|
881
|
+
self,
|
|
882
|
+
filtration_grid:np.ndarray|list|None=None,
|
|
883
|
+
bool coordinate_values=True,
|
|
884
|
+
force=False,
|
|
885
|
+
strategy:_available_strategies = "exact",
|
|
886
|
+
grid_strategy=None,
|
|
887
|
+
inplace=False,
|
|
888
|
+
**filtration_grid_kwargs
|
|
889
|
+
)->SimplexTreeMulti_KFi32 | SimplexTreeMulti_KFi32:
|
|
858
890
|
"""
|
|
859
891
|
Fit the filtration of the simplextree to a grid.
|
|
860
892
|
|
|
@@ -865,26 +897,50 @@ cdef class SimplexTreeMulti_KFi32:
|
|
|
865
897
|
"""
|
|
866
898
|
if not force and self.is_squeezed:
|
|
867
899
|
raise Exception("SimplexTree already squeezed, use `force=True` if that's really what you want to do.")
|
|
900
|
+
|
|
901
|
+
if grid_strategy is not None:
|
|
902
|
+
warn("`grid_strategy` is deprecated, use `strategy` instead.",DeprecationWarning)
|
|
903
|
+
strategy=grid_strategy
|
|
904
|
+
|
|
905
|
+
if self.is_squeezed:
|
|
906
|
+
warn("(copy warning) Squeezing an already squeezed slicer.")
|
|
907
|
+
temp = self.unsqueeze()
|
|
908
|
+
subgrid = compute_grid(self.filtration_grid, strategy=strategy, resolution=resolution)
|
|
909
|
+
return temp.grid_squeeze(subgrid, coordinates=coordinates, inplace=inplace)
|
|
910
|
+
|
|
868
911
|
#TODO : multi-critical
|
|
869
912
|
if filtration_grid is None:
|
|
870
|
-
filtration_grid = self.get_filtration_grid(grid_strategy=
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
913
|
+
filtration_grid = self.get_filtration_grid(grid_strategy=strategy, **filtration_grid_kwargs)
|
|
914
|
+
else:
|
|
915
|
+
filtration_grid = sanitize_grid(filtration_grid)
|
|
916
|
+
if len(filtration_grid) != self.num_parameters:
|
|
917
|
+
raise ValueError(f"Invalid grid to squeeze onto. Got {len(filtration_grid)=} != {self.num_parameters=}.")
|
|
918
|
+
api = api_from_tensor(filtration_grid[0])
|
|
919
|
+
cdef vector[vector[double]] c_filtration_grid = tuple(api.asnumpy(f).astype(np.float64) for f in filtration_grid) # may be faster with loop on views
|
|
874
920
|
if coordinate_values and inplace:
|
|
875
|
-
self.filtration_grid =
|
|
921
|
+
self.filtration_grid = filtration_grid
|
|
876
922
|
if inplace or not coordinate_values:
|
|
877
923
|
self.get_ptr().squeeze_filtration_inplace(c_filtration_grid, coordinate_values)
|
|
878
924
|
else:
|
|
879
925
|
out = SimplexTreeMulti_KFi32(num_parameters=self.num_parameters)
|
|
880
926
|
self.get_ptr().squeeze_filtration(out.thisptr, c_filtration_grid)
|
|
881
|
-
out.filtration_grid =
|
|
927
|
+
out.filtration_grid = filtration_grid
|
|
882
928
|
return out
|
|
883
929
|
return self
|
|
884
930
|
|
|
931
|
+
def unsqueeze(self, grid=None)->SimplexTreeMulti_KFf64:
|
|
932
|
+
from multipers.grids import sanitize_grid
|
|
933
|
+
grid = self.filtration_grid if grid is None else grid
|
|
934
|
+
|
|
935
|
+
cdef vector[vector[double]] cgrid = sanitize_grid(grid, numpyfy=True)
|
|
936
|
+
new_slicer = SimplexTreeMulti_KFf64()
|
|
937
|
+
new_slicer.get_ptr().unsqueeze_filtration(self.thisptr, cgrid)
|
|
938
|
+
|
|
939
|
+
return new_slicer
|
|
940
|
+
|
|
885
941
|
@property
|
|
886
942
|
def is_squeezed(self)->bool:
|
|
887
|
-
return self.num_vertices > 0 and len(self.filtration_grid)>0 and len(self.filtration_grid[0]) > 0
|
|
943
|
+
return self.num_vertices > 0 and self.filtration_grid is not None and len(self.filtration_grid)>0 and len(self.filtration_grid[0]) > 0
|
|
888
944
|
|
|
889
945
|
@property
|
|
890
946
|
def dtype(self)->type:
|
|
@@ -1177,15 +1233,15 @@ cdef class SimplexTreeMulti_Fi32:
|
|
|
1177
1233
|
"""
|
|
1178
1234
|
cdef public intptr_t thisptr
|
|
1179
1235
|
|
|
1180
|
-
cdef public
|
|
1181
|
-
cdef public bool _is_function_simplextree
|
|
1236
|
+
cdef public object filtration_grid
|
|
1237
|
+
cdef public bool _is_function_simplextree # TODO : deprecate
|
|
1182
1238
|
# Get the pointer casted as it should be
|
|
1183
1239
|
cdef Simplex_tree_multi_interface[Fi32, int32_t]* get_ptr(self) noexcept nogil:
|
|
1184
1240
|
return <Simplex_tree_multi_interface[Fi32, int32_t]*>(self.thisptr)
|
|
1185
1241
|
|
|
1186
1242
|
# cdef Simplex_tree_persistence_interface * pcohptr
|
|
1187
1243
|
# Fake constructor that does nothing but documenting the constructor
|
|
1188
|
-
def __init__(self, other = None, num_parameters:int
|
|
1244
|
+
def __init__(self, other = None, num_parameters:int=-1,default_values=[], safe_conversion=False):
|
|
1189
1245
|
"""SimplexTreeMulti constructor.
|
|
1190
1246
|
|
|
1191
1247
|
:param other: If `other` is `None` (default value), an empty `SimplexTreeMulti` is created.
|
|
@@ -1210,7 +1266,7 @@ cdef class SimplexTreeMulti_Fi32:
|
|
|
1210
1266
|
def is_kcritical(self)->bool:
|
|
1211
1267
|
return False
|
|
1212
1268
|
# The real cython constructor
|
|
1213
|
-
def __cinit__(self, other = None, int num_parameters
|
|
1269
|
+
def __cinit__(self, other = None, int num_parameters=-1,
|
|
1214
1270
|
default_values=np.asarray([SimplexTreeMulti_Fi32.T_minus_inf()]), # I'm not sure why `[]` does not work. Cython bug ?
|
|
1215
1271
|
bool safe_conversion=False,
|
|
1216
1272
|
): #TODO doc
|
|
@@ -1223,10 +1279,13 @@ cdef class SimplexTreeMulti_Fi32:
|
|
|
1223
1279
|
if isinstance(other, SimplexTreeMulti_Fi32):
|
|
1224
1280
|
other_ptr = other.thisptr
|
|
1225
1281
|
self.thisptr = <intptr_t>(new Simplex_tree_multi_interface[Fi32, int32_t](dereference(<Simplex_tree_multi_interface[Fi32, int32_t]*>other_ptr))) ## prevents calling destructor of other
|
|
1226
|
-
num_parameters
|
|
1282
|
+
if num_parameters <=0:
|
|
1283
|
+
num_parameters = other.num_parameters
|
|
1227
1284
|
self.filtration_grid = other.filtration_grid
|
|
1228
1285
|
elif isinstance(other, SimplexTree): # Constructs a SimplexTreeMulti from a SimplexTree
|
|
1229
1286
|
self.thisptr = <intptr_t>(new Simplex_tree_multi_interface[Fi32, int32_t]())
|
|
1287
|
+
if num_parameters <= 0:
|
|
1288
|
+
num_parameters = 1
|
|
1230
1289
|
if safe_conversion or SAFE_CONVERSION:
|
|
1231
1290
|
new_st_multi = _safe_simplextree_multify_Fi32(other, num_parameters = num_parameters, default_values=np.asarray(default_values))
|
|
1232
1291
|
self.thisptr, new_st_multi.thisptr = new_st_multi.thisptr, self.thisptr
|
|
@@ -1241,10 +1300,12 @@ cdef class SimplexTreeMulti_Fi32:
|
|
|
1241
1300
|
else:
|
|
1242
1301
|
raise TypeError("`other` argument requires to be of type `SimplexTree`, `SimplexTreeMulti`, or `None`.")
|
|
1243
1302
|
else:
|
|
1303
|
+
if num_parameters <=0:
|
|
1304
|
+
num_parameters = 2 # I don't know how dangerous this is, but this is mostly used.
|
|
1244
1305
|
self.thisptr = <intptr_t>(new Simplex_tree_multi_interface[Fi32, int32_t]())
|
|
1245
|
-
self.
|
|
1306
|
+
self.set_num_parameter(num_parameters)
|
|
1246
1307
|
self._is_function_simplextree = False
|
|
1247
|
-
self.filtration_grid=[
|
|
1308
|
+
self.filtration_grid=[]
|
|
1248
1309
|
|
|
1249
1310
|
def __dealloc__(self):
|
|
1250
1311
|
cdef Simplex_tree_multi_interface[Fi32,int32_t]* ptr = self.get_ptr()
|
|
@@ -1254,6 +1315,9 @@ cdef class SimplexTreeMulti_Fi32:
|
|
|
1254
1315
|
|
|
1255
1316
|
def __repr__(self):
|
|
1256
1317
|
return f"SimplexTreeMulti[dtype={np.dtype(self.dtype).name},num_param={self.num_parameters},kcritical={self.is_kcritical},is_squeezed={self.is_squeezed},max_dim={self.dimension}]"
|
|
1318
|
+
def __len__(self):
|
|
1319
|
+
return self.num_simplices
|
|
1320
|
+
|
|
1257
1321
|
def __getstate__(self):
|
|
1258
1322
|
""":returns: Serialized (or flattened) SimplexTree data structure in order to pickle SimplexTree.
|
|
1259
1323
|
:rtype: numpy.array of shape (n,)
|
|
@@ -2186,11 +2250,26 @@ cdef class SimplexTreeMulti_Fi32:
|
|
|
2186
2250
|
out = self.get_ptr().get_filtration_values(degrees)
|
|
2187
2251
|
filtrations_values = [np.asarray(filtration) for filtration in out]
|
|
2188
2252
|
# Removes infs
|
|
2189
|
-
if inf_to_nan:
|
|
2253
|
+
if inf_to_nan and np.dtype(filtrations_values[0].dtype).kind == 'f':
|
|
2190
2254
|
for i,f in enumerate(filtrations_values):
|
|
2191
2255
|
filtrations_values[i][f == np.inf] = np.nan
|
|
2192
2256
|
filtrations_values[i][f == - np.inf] = np.nan
|
|
2193
2257
|
return filtrations_values
|
|
2258
|
+
def _clean_filtration_grid(self):
|
|
2259
|
+
"""
|
|
2260
|
+
Removes the values in filtration_grid that are not linked to any splx.
|
|
2261
|
+
"""
|
|
2262
|
+
if not self.is_squeezed:
|
|
2263
|
+
raise ValueError("No grid to clean.")
|
|
2264
|
+
F = self.filtration_grid
|
|
2265
|
+
self.filtration_grid=None
|
|
2266
|
+
cleaned_coordinates = compute_grid(self)
|
|
2267
|
+
new_st = self.grid_squeeze(cleaned_coordinates)
|
|
2268
|
+
|
|
2269
|
+
self.thisptr, new_st.thisptr = new_st.thisptr, self.thisptr
|
|
2270
|
+
self.filtration_grid = tuple(f[g] for f,g in zip(F,cleaned_coordinates))
|
|
2271
|
+
return self
|
|
2272
|
+
|
|
2194
2273
|
|
|
2195
2274
|
|
|
2196
2275
|
def get_filtration_grid(self, resolution:Iterable[int]|None=None, degrees:Iterable[int]|None=None, drop_quantiles:float|tuple=0, grid_strategy:_available_strategies="exact")->Iterable[np.ndarray]:
|
|
@@ -2226,8 +2305,16 @@ cdef class SimplexTreeMulti_Fi32:
|
|
|
2226
2305
|
return compute_grid(filtrations_values, resolution=resolution,strategy=grid_strategy,drop_quantiles=drop_quantiles)
|
|
2227
2306
|
|
|
2228
2307
|
|
|
2229
|
-
|
|
2230
|
-
|
|
2308
|
+
def grid_squeeze(
|
|
2309
|
+
self,
|
|
2310
|
+
filtration_grid:np.ndarray|list|None=None,
|
|
2311
|
+
bool coordinate_values=True,
|
|
2312
|
+
force=False,
|
|
2313
|
+
strategy:_available_strategies = "exact",
|
|
2314
|
+
grid_strategy=None,
|
|
2315
|
+
inplace=False,
|
|
2316
|
+
**filtration_grid_kwargs
|
|
2317
|
+
)->SimplexTreeMulti_Fi32 | SimplexTreeMulti_Fi32:
|
|
2231
2318
|
"""
|
|
2232
2319
|
Fit the filtration of the simplextree to a grid.
|
|
2233
2320
|
|
|
@@ -2238,26 +2325,50 @@ cdef class SimplexTreeMulti_Fi32:
|
|
|
2238
2325
|
"""
|
|
2239
2326
|
if not force and self.is_squeezed:
|
|
2240
2327
|
raise Exception("SimplexTree already squeezed, use `force=True` if that's really what you want to do.")
|
|
2328
|
+
|
|
2329
|
+
if grid_strategy is not None:
|
|
2330
|
+
warn("`grid_strategy` is deprecated, use `strategy` instead.",DeprecationWarning)
|
|
2331
|
+
strategy=grid_strategy
|
|
2332
|
+
|
|
2333
|
+
if self.is_squeezed:
|
|
2334
|
+
warn("(copy warning) Squeezing an already squeezed slicer.")
|
|
2335
|
+
temp = self.unsqueeze()
|
|
2336
|
+
subgrid = compute_grid(self.filtration_grid, strategy=strategy, resolution=resolution)
|
|
2337
|
+
return temp.grid_squeeze(subgrid, coordinates=coordinates, inplace=inplace)
|
|
2338
|
+
|
|
2241
2339
|
#TODO : multi-critical
|
|
2242
2340
|
if filtration_grid is None:
|
|
2243
|
-
filtration_grid = self.get_filtration_grid(grid_strategy=
|
|
2244
|
-
|
|
2245
|
-
|
|
2246
|
-
|
|
2341
|
+
filtration_grid = self.get_filtration_grid(grid_strategy=strategy, **filtration_grid_kwargs)
|
|
2342
|
+
else:
|
|
2343
|
+
filtration_grid = sanitize_grid(filtration_grid)
|
|
2344
|
+
if len(filtration_grid) != self.num_parameters:
|
|
2345
|
+
raise ValueError(f"Invalid grid to squeeze onto. Got {len(filtration_grid)=} != {self.num_parameters=}.")
|
|
2346
|
+
api = api_from_tensor(filtration_grid[0])
|
|
2347
|
+
cdef vector[vector[double]] c_filtration_grid = tuple(api.asnumpy(f).astype(np.float64) for f in filtration_grid) # may be faster with loop on views
|
|
2247
2348
|
if coordinate_values and inplace:
|
|
2248
|
-
self.filtration_grid =
|
|
2349
|
+
self.filtration_grid = filtration_grid
|
|
2249
2350
|
if inplace or not coordinate_values:
|
|
2250
2351
|
self.get_ptr().squeeze_filtration_inplace(c_filtration_grid, coordinate_values)
|
|
2251
2352
|
else:
|
|
2252
2353
|
out = SimplexTreeMulti_Fi32(num_parameters=self.num_parameters)
|
|
2253
2354
|
self.get_ptr().squeeze_filtration(out.thisptr, c_filtration_grid)
|
|
2254
|
-
out.filtration_grid =
|
|
2355
|
+
out.filtration_grid = filtration_grid
|
|
2255
2356
|
return out
|
|
2256
2357
|
return self
|
|
2257
2358
|
|
|
2359
|
+
def unsqueeze(self, grid=None)->SimplexTreeMulti_Ff64:
|
|
2360
|
+
from multipers.grids import sanitize_grid
|
|
2361
|
+
grid = self.filtration_grid if grid is None else grid
|
|
2362
|
+
|
|
2363
|
+
cdef vector[vector[double]] cgrid = sanitize_grid(grid, numpyfy=True)
|
|
2364
|
+
new_slicer = SimplexTreeMulti_Ff64()
|
|
2365
|
+
new_slicer.get_ptr().unsqueeze_filtration(self.thisptr, cgrid)
|
|
2366
|
+
|
|
2367
|
+
return new_slicer
|
|
2368
|
+
|
|
2258
2369
|
@property
|
|
2259
2370
|
def is_squeezed(self)->bool:
|
|
2260
|
-
return self.num_vertices > 0 and len(self.filtration_grid)>0 and len(self.filtration_grid[0]) > 0
|
|
2371
|
+
return self.num_vertices > 0 and self.filtration_grid is not None and len(self.filtration_grid)>0 and len(self.filtration_grid[0]) > 0
|
|
2261
2372
|
|
|
2262
2373
|
@property
|
|
2263
2374
|
def dtype(self)->type:
|
|
@@ -2548,15 +2659,15 @@ cdef class SimplexTreeMulti_KFi64:
|
|
|
2548
2659
|
"""
|
|
2549
2660
|
cdef public intptr_t thisptr
|
|
2550
2661
|
|
|
2551
|
-
cdef public
|
|
2552
|
-
cdef public bool _is_function_simplextree
|
|
2662
|
+
cdef public object filtration_grid
|
|
2663
|
+
cdef public bool _is_function_simplextree # TODO : deprecate
|
|
2553
2664
|
# Get the pointer casted as it should be
|
|
2554
2665
|
cdef Simplex_tree_multi_interface[KFi64, int64_t]* get_ptr(self) noexcept nogil:
|
|
2555
2666
|
return <Simplex_tree_multi_interface[KFi64, int64_t]*>(self.thisptr)
|
|
2556
2667
|
|
|
2557
2668
|
# cdef Simplex_tree_persistence_interface * pcohptr
|
|
2558
2669
|
# Fake constructor that does nothing but documenting the constructor
|
|
2559
|
-
def __init__(self, other = None, num_parameters:int
|
|
2670
|
+
def __init__(self, other = None, num_parameters:int=-1,default_values=[], safe_conversion=False):
|
|
2560
2671
|
"""SimplexTreeMulti constructor.
|
|
2561
2672
|
|
|
2562
2673
|
:param other: If `other` is `None` (default value), an empty `SimplexTreeMulti` is created.
|
|
@@ -2581,7 +2692,7 @@ cdef class SimplexTreeMulti_KFi64:
|
|
|
2581
2692
|
def is_kcritical(self)->bool:
|
|
2582
2693
|
return True
|
|
2583
2694
|
# The real cython constructor
|
|
2584
|
-
def __cinit__(self, other = None, int num_parameters
|
|
2695
|
+
def __cinit__(self, other = None, int num_parameters=-1,
|
|
2585
2696
|
default_values=np.asarray([SimplexTreeMulti_KFi64.T_minus_inf()]), # I'm not sure why `[]` does not work. Cython bug ?
|
|
2586
2697
|
bool safe_conversion=False,
|
|
2587
2698
|
): #TODO doc
|
|
@@ -2594,10 +2705,13 @@ cdef class SimplexTreeMulti_KFi64:
|
|
|
2594
2705
|
if isinstance(other, SimplexTreeMulti_KFi64):
|
|
2595
2706
|
other_ptr = other.thisptr
|
|
2596
2707
|
self.thisptr = <intptr_t>(new Simplex_tree_multi_interface[KFi64, int64_t](dereference(<Simplex_tree_multi_interface[KFi64, int64_t]*>other_ptr))) ## prevents calling destructor of other
|
|
2597
|
-
num_parameters
|
|
2708
|
+
if num_parameters <=0:
|
|
2709
|
+
num_parameters = other.num_parameters
|
|
2598
2710
|
self.filtration_grid = other.filtration_grid
|
|
2599
2711
|
elif isinstance(other, SimplexTree): # Constructs a SimplexTreeMulti from a SimplexTree
|
|
2600
2712
|
self.thisptr = <intptr_t>(new Simplex_tree_multi_interface[KFi64, int64_t]())
|
|
2713
|
+
if num_parameters <= 0:
|
|
2714
|
+
num_parameters = 1
|
|
2601
2715
|
if safe_conversion or SAFE_CONVERSION:
|
|
2602
2716
|
new_st_multi = _safe_simplextree_multify_KFi64(other, num_parameters = num_parameters, default_values=np.asarray(default_values))
|
|
2603
2717
|
self.thisptr, new_st_multi.thisptr = new_st_multi.thisptr, self.thisptr
|
|
@@ -2612,10 +2726,12 @@ cdef class SimplexTreeMulti_KFi64:
|
|
|
2612
2726
|
else:
|
|
2613
2727
|
raise TypeError("`other` argument requires to be of type `SimplexTree`, `SimplexTreeMulti`, or `None`.")
|
|
2614
2728
|
else:
|
|
2729
|
+
if num_parameters <=0:
|
|
2730
|
+
num_parameters = 2 # I don't know how dangerous this is, but this is mostly used.
|
|
2615
2731
|
self.thisptr = <intptr_t>(new Simplex_tree_multi_interface[KFi64, int64_t]())
|
|
2616
|
-
self.
|
|
2732
|
+
self.set_num_parameter(num_parameters)
|
|
2617
2733
|
self._is_function_simplextree = False
|
|
2618
|
-
self.filtration_grid=[
|
|
2734
|
+
self.filtration_grid=[]
|
|
2619
2735
|
|
|
2620
2736
|
def __dealloc__(self):
|
|
2621
2737
|
cdef Simplex_tree_multi_interface[KFi64,int64_t]* ptr = self.get_ptr()
|
|
@@ -2625,6 +2741,9 @@ cdef class SimplexTreeMulti_KFi64:
|
|
|
2625
2741
|
|
|
2626
2742
|
def __repr__(self):
|
|
2627
2743
|
return f"SimplexTreeMulti[dtype={np.dtype(self.dtype).name},num_param={self.num_parameters},kcritical={self.is_kcritical},is_squeezed={self.is_squeezed},max_dim={self.dimension}]"
|
|
2744
|
+
def __len__(self):
|
|
2745
|
+
return self.num_simplices
|
|
2746
|
+
|
|
2628
2747
|
def __getstate__(self):
|
|
2629
2748
|
""":returns: Serialized (or flattened) SimplexTree data structure in order to pickle SimplexTree.
|
|
2630
2749
|
:rtype: numpy.array of shape (n,)
|
|
@@ -3280,11 +3399,26 @@ cdef class SimplexTreeMulti_KFi64:
|
|
|
3280
3399
|
out = self.get_ptr().get_filtration_values(degrees)
|
|
3281
3400
|
filtrations_values = [np.asarray(filtration) for filtration in out]
|
|
3282
3401
|
# Removes infs
|
|
3283
|
-
if inf_to_nan:
|
|
3402
|
+
if inf_to_nan and np.dtype(filtrations_values[0].dtype).kind == 'f':
|
|
3284
3403
|
for i,f in enumerate(filtrations_values):
|
|
3285
3404
|
filtrations_values[i][f == np.inf] = np.nan
|
|
3286
3405
|
filtrations_values[i][f == - np.inf] = np.nan
|
|
3287
3406
|
return filtrations_values
|
|
3407
|
+
def _clean_filtration_grid(self):
|
|
3408
|
+
"""
|
|
3409
|
+
Removes the values in filtration_grid that are not linked to any splx.
|
|
3410
|
+
"""
|
|
3411
|
+
if not self.is_squeezed:
|
|
3412
|
+
raise ValueError("No grid to clean.")
|
|
3413
|
+
F = self.filtration_grid
|
|
3414
|
+
self.filtration_grid=None
|
|
3415
|
+
cleaned_coordinates = compute_grid(self)
|
|
3416
|
+
new_st = self.grid_squeeze(cleaned_coordinates)
|
|
3417
|
+
|
|
3418
|
+
self.thisptr, new_st.thisptr = new_st.thisptr, self.thisptr
|
|
3419
|
+
self.filtration_grid = tuple(f[g] for f,g in zip(F,cleaned_coordinates))
|
|
3420
|
+
return self
|
|
3421
|
+
|
|
3288
3422
|
|
|
3289
3423
|
|
|
3290
3424
|
def get_filtration_grid(self, resolution:Iterable[int]|None=None, degrees:Iterable[int]|None=None, drop_quantiles:float|tuple=0, grid_strategy:_available_strategies="exact")->Iterable[np.ndarray]:
|
|
@@ -3320,8 +3454,16 @@ cdef class SimplexTreeMulti_KFi64:
|
|
|
3320
3454
|
return compute_grid(filtrations_values, resolution=resolution,strategy=grid_strategy,drop_quantiles=drop_quantiles)
|
|
3321
3455
|
|
|
3322
3456
|
|
|
3323
|
-
|
|
3324
|
-
|
|
3457
|
+
def grid_squeeze(
|
|
3458
|
+
self,
|
|
3459
|
+
filtration_grid:np.ndarray|list|None=None,
|
|
3460
|
+
bool coordinate_values=True,
|
|
3461
|
+
force=False,
|
|
3462
|
+
strategy:_available_strategies = "exact",
|
|
3463
|
+
grid_strategy=None,
|
|
3464
|
+
inplace=False,
|
|
3465
|
+
**filtration_grid_kwargs
|
|
3466
|
+
)->SimplexTreeMulti_KFi32 | SimplexTreeMulti_KFi64:
|
|
3325
3467
|
"""
|
|
3326
3468
|
Fit the filtration of the simplextree to a grid.
|
|
3327
3469
|
|
|
@@ -3332,26 +3474,50 @@ cdef class SimplexTreeMulti_KFi64:
|
|
|
3332
3474
|
"""
|
|
3333
3475
|
if not force and self.is_squeezed:
|
|
3334
3476
|
raise Exception("SimplexTree already squeezed, use `force=True` if that's really what you want to do.")
|
|
3477
|
+
|
|
3478
|
+
if grid_strategy is not None:
|
|
3479
|
+
warn("`grid_strategy` is deprecated, use `strategy` instead.",DeprecationWarning)
|
|
3480
|
+
strategy=grid_strategy
|
|
3481
|
+
|
|
3482
|
+
if self.is_squeezed:
|
|
3483
|
+
warn("(copy warning) Squeezing an already squeezed slicer.")
|
|
3484
|
+
temp = self.unsqueeze()
|
|
3485
|
+
subgrid = compute_grid(self.filtration_grid, strategy=strategy, resolution=resolution)
|
|
3486
|
+
return temp.grid_squeeze(subgrid, coordinates=coordinates, inplace=inplace)
|
|
3487
|
+
|
|
3335
3488
|
#TODO : multi-critical
|
|
3336
3489
|
if filtration_grid is None:
|
|
3337
|
-
filtration_grid = self.get_filtration_grid(grid_strategy=
|
|
3338
|
-
|
|
3339
|
-
|
|
3340
|
-
|
|
3490
|
+
filtration_grid = self.get_filtration_grid(grid_strategy=strategy, **filtration_grid_kwargs)
|
|
3491
|
+
else:
|
|
3492
|
+
filtration_grid = sanitize_grid(filtration_grid)
|
|
3493
|
+
if len(filtration_grid) != self.num_parameters:
|
|
3494
|
+
raise ValueError(f"Invalid grid to squeeze onto. Got {len(filtration_grid)=} != {self.num_parameters=}.")
|
|
3495
|
+
api = api_from_tensor(filtration_grid[0])
|
|
3496
|
+
cdef vector[vector[double]] c_filtration_grid = tuple(api.asnumpy(f).astype(np.float64) for f in filtration_grid) # may be faster with loop on views
|
|
3341
3497
|
if coordinate_values and inplace:
|
|
3342
|
-
self.filtration_grid =
|
|
3498
|
+
self.filtration_grid = filtration_grid
|
|
3343
3499
|
if inplace or not coordinate_values:
|
|
3344
3500
|
self.get_ptr().squeeze_filtration_inplace(c_filtration_grid, coordinate_values)
|
|
3345
3501
|
else:
|
|
3346
3502
|
out = SimplexTreeMulti_KFi32(num_parameters=self.num_parameters)
|
|
3347
3503
|
self.get_ptr().squeeze_filtration(out.thisptr, c_filtration_grid)
|
|
3348
|
-
out.filtration_grid =
|
|
3504
|
+
out.filtration_grid = filtration_grid
|
|
3349
3505
|
return out
|
|
3350
3506
|
return self
|
|
3351
3507
|
|
|
3508
|
+
def unsqueeze(self, grid=None)->SimplexTreeMulti_KFf64:
|
|
3509
|
+
from multipers.grids import sanitize_grid
|
|
3510
|
+
grid = self.filtration_grid if grid is None else grid
|
|
3511
|
+
|
|
3512
|
+
cdef vector[vector[double]] cgrid = sanitize_grid(grid, numpyfy=True)
|
|
3513
|
+
new_slicer = SimplexTreeMulti_KFf64()
|
|
3514
|
+
new_slicer.get_ptr().unsqueeze_filtration(self.thisptr, cgrid)
|
|
3515
|
+
|
|
3516
|
+
return new_slicer
|
|
3517
|
+
|
|
3352
3518
|
@property
|
|
3353
3519
|
def is_squeezed(self)->bool:
|
|
3354
|
-
return self.num_vertices > 0 and len(self.filtration_grid)>0 and len(self.filtration_grid[0]) > 0
|
|
3520
|
+
return self.num_vertices > 0 and self.filtration_grid is not None and len(self.filtration_grid)>0 and len(self.filtration_grid[0]) > 0
|
|
3355
3521
|
|
|
3356
3522
|
@property
|
|
3357
3523
|
def dtype(self)->type:
|
|
@@ -3644,15 +3810,15 @@ cdef class SimplexTreeMulti_Fi64:
|
|
|
3644
3810
|
"""
|
|
3645
3811
|
cdef public intptr_t thisptr
|
|
3646
3812
|
|
|
3647
|
-
cdef public
|
|
3648
|
-
cdef public bool _is_function_simplextree
|
|
3813
|
+
cdef public object filtration_grid
|
|
3814
|
+
cdef public bool _is_function_simplextree # TODO : deprecate
|
|
3649
3815
|
# Get the pointer casted as it should be
|
|
3650
3816
|
cdef Simplex_tree_multi_interface[Fi64, int64_t]* get_ptr(self) noexcept nogil:
|
|
3651
3817
|
return <Simplex_tree_multi_interface[Fi64, int64_t]*>(self.thisptr)
|
|
3652
3818
|
|
|
3653
3819
|
# cdef Simplex_tree_persistence_interface * pcohptr
|
|
3654
3820
|
# Fake constructor that does nothing but documenting the constructor
|
|
3655
|
-
def __init__(self, other = None, num_parameters:int
|
|
3821
|
+
def __init__(self, other = None, num_parameters:int=-1,default_values=[], safe_conversion=False):
|
|
3656
3822
|
"""SimplexTreeMulti constructor.
|
|
3657
3823
|
|
|
3658
3824
|
:param other: If `other` is `None` (default value), an empty `SimplexTreeMulti` is created.
|
|
@@ -3677,7 +3843,7 @@ cdef class SimplexTreeMulti_Fi64:
|
|
|
3677
3843
|
def is_kcritical(self)->bool:
|
|
3678
3844
|
return False
|
|
3679
3845
|
# The real cython constructor
|
|
3680
|
-
def __cinit__(self, other = None, int num_parameters
|
|
3846
|
+
def __cinit__(self, other = None, int num_parameters=-1,
|
|
3681
3847
|
default_values=np.asarray([SimplexTreeMulti_Fi64.T_minus_inf()]), # I'm not sure why `[]` does not work. Cython bug ?
|
|
3682
3848
|
bool safe_conversion=False,
|
|
3683
3849
|
): #TODO doc
|
|
@@ -3690,10 +3856,13 @@ cdef class SimplexTreeMulti_Fi64:
|
|
|
3690
3856
|
if isinstance(other, SimplexTreeMulti_Fi64):
|
|
3691
3857
|
other_ptr = other.thisptr
|
|
3692
3858
|
self.thisptr = <intptr_t>(new Simplex_tree_multi_interface[Fi64, int64_t](dereference(<Simplex_tree_multi_interface[Fi64, int64_t]*>other_ptr))) ## prevents calling destructor of other
|
|
3693
|
-
num_parameters
|
|
3859
|
+
if num_parameters <=0:
|
|
3860
|
+
num_parameters = other.num_parameters
|
|
3694
3861
|
self.filtration_grid = other.filtration_grid
|
|
3695
3862
|
elif isinstance(other, SimplexTree): # Constructs a SimplexTreeMulti from a SimplexTree
|
|
3696
3863
|
self.thisptr = <intptr_t>(new Simplex_tree_multi_interface[Fi64, int64_t]())
|
|
3864
|
+
if num_parameters <= 0:
|
|
3865
|
+
num_parameters = 1
|
|
3697
3866
|
if safe_conversion or SAFE_CONVERSION:
|
|
3698
3867
|
new_st_multi = _safe_simplextree_multify_Fi64(other, num_parameters = num_parameters, default_values=np.asarray(default_values))
|
|
3699
3868
|
self.thisptr, new_st_multi.thisptr = new_st_multi.thisptr, self.thisptr
|
|
@@ -3708,10 +3877,12 @@ cdef class SimplexTreeMulti_Fi64:
|
|
|
3708
3877
|
else:
|
|
3709
3878
|
raise TypeError("`other` argument requires to be of type `SimplexTree`, `SimplexTreeMulti`, or `None`.")
|
|
3710
3879
|
else:
|
|
3880
|
+
if num_parameters <=0:
|
|
3881
|
+
num_parameters = 2 # I don't know how dangerous this is, but this is mostly used.
|
|
3711
3882
|
self.thisptr = <intptr_t>(new Simplex_tree_multi_interface[Fi64, int64_t]())
|
|
3712
|
-
self.
|
|
3883
|
+
self.set_num_parameter(num_parameters)
|
|
3713
3884
|
self._is_function_simplextree = False
|
|
3714
|
-
self.filtration_grid=[
|
|
3885
|
+
self.filtration_grid=[]
|
|
3715
3886
|
|
|
3716
3887
|
def __dealloc__(self):
|
|
3717
3888
|
cdef Simplex_tree_multi_interface[Fi64,int64_t]* ptr = self.get_ptr()
|
|
@@ -3721,6 +3892,9 @@ cdef class SimplexTreeMulti_Fi64:
|
|
|
3721
3892
|
|
|
3722
3893
|
def __repr__(self):
|
|
3723
3894
|
return f"SimplexTreeMulti[dtype={np.dtype(self.dtype).name},num_param={self.num_parameters},kcritical={self.is_kcritical},is_squeezed={self.is_squeezed},max_dim={self.dimension}]"
|
|
3895
|
+
def __len__(self):
|
|
3896
|
+
return self.num_simplices
|
|
3897
|
+
|
|
3724
3898
|
def __getstate__(self):
|
|
3725
3899
|
""":returns: Serialized (or flattened) SimplexTree data structure in order to pickle SimplexTree.
|
|
3726
3900
|
:rtype: numpy.array of shape (n,)
|
|
@@ -4653,11 +4827,26 @@ cdef class SimplexTreeMulti_Fi64:
|
|
|
4653
4827
|
out = self.get_ptr().get_filtration_values(degrees)
|
|
4654
4828
|
filtrations_values = [np.asarray(filtration) for filtration in out]
|
|
4655
4829
|
# Removes infs
|
|
4656
|
-
if inf_to_nan:
|
|
4830
|
+
if inf_to_nan and np.dtype(filtrations_values[0].dtype).kind == 'f':
|
|
4657
4831
|
for i,f in enumerate(filtrations_values):
|
|
4658
4832
|
filtrations_values[i][f == np.inf] = np.nan
|
|
4659
4833
|
filtrations_values[i][f == - np.inf] = np.nan
|
|
4660
4834
|
return filtrations_values
|
|
4835
|
+
def _clean_filtration_grid(self):
|
|
4836
|
+
"""
|
|
4837
|
+
Removes the values in filtration_grid that are not linked to any splx.
|
|
4838
|
+
"""
|
|
4839
|
+
if not self.is_squeezed:
|
|
4840
|
+
raise ValueError("No grid to clean.")
|
|
4841
|
+
F = self.filtration_grid
|
|
4842
|
+
self.filtration_grid=None
|
|
4843
|
+
cleaned_coordinates = compute_grid(self)
|
|
4844
|
+
new_st = self.grid_squeeze(cleaned_coordinates)
|
|
4845
|
+
|
|
4846
|
+
self.thisptr, new_st.thisptr = new_st.thisptr, self.thisptr
|
|
4847
|
+
self.filtration_grid = tuple(f[g] for f,g in zip(F,cleaned_coordinates))
|
|
4848
|
+
return self
|
|
4849
|
+
|
|
4661
4850
|
|
|
4662
4851
|
|
|
4663
4852
|
def get_filtration_grid(self, resolution:Iterable[int]|None=None, degrees:Iterable[int]|None=None, drop_quantiles:float|tuple=0, grid_strategy:_available_strategies="exact")->Iterable[np.ndarray]:
|
|
@@ -4693,8 +4882,16 @@ cdef class SimplexTreeMulti_Fi64:
|
|
|
4693
4882
|
return compute_grid(filtrations_values, resolution=resolution,strategy=grid_strategy,drop_quantiles=drop_quantiles)
|
|
4694
4883
|
|
|
4695
4884
|
|
|
4696
|
-
|
|
4697
|
-
|
|
4885
|
+
def grid_squeeze(
|
|
4886
|
+
self,
|
|
4887
|
+
filtration_grid:np.ndarray|list|None=None,
|
|
4888
|
+
bool coordinate_values=True,
|
|
4889
|
+
force=False,
|
|
4890
|
+
strategy:_available_strategies = "exact",
|
|
4891
|
+
grid_strategy=None,
|
|
4892
|
+
inplace=False,
|
|
4893
|
+
**filtration_grid_kwargs
|
|
4894
|
+
)->SimplexTreeMulti_Fi32 | SimplexTreeMulti_Fi64:
|
|
4698
4895
|
"""
|
|
4699
4896
|
Fit the filtration of the simplextree to a grid.
|
|
4700
4897
|
|
|
@@ -4705,26 +4902,50 @@ cdef class SimplexTreeMulti_Fi64:
|
|
|
4705
4902
|
"""
|
|
4706
4903
|
if not force and self.is_squeezed:
|
|
4707
4904
|
raise Exception("SimplexTree already squeezed, use `force=True` if that's really what you want to do.")
|
|
4905
|
+
|
|
4906
|
+
if grid_strategy is not None:
|
|
4907
|
+
warn("`grid_strategy` is deprecated, use `strategy` instead.",DeprecationWarning)
|
|
4908
|
+
strategy=grid_strategy
|
|
4909
|
+
|
|
4910
|
+
if self.is_squeezed:
|
|
4911
|
+
warn("(copy warning) Squeezing an already squeezed slicer.")
|
|
4912
|
+
temp = self.unsqueeze()
|
|
4913
|
+
subgrid = compute_grid(self.filtration_grid, strategy=strategy, resolution=resolution)
|
|
4914
|
+
return temp.grid_squeeze(subgrid, coordinates=coordinates, inplace=inplace)
|
|
4915
|
+
|
|
4708
4916
|
#TODO : multi-critical
|
|
4709
4917
|
if filtration_grid is None:
|
|
4710
|
-
filtration_grid = self.get_filtration_grid(grid_strategy=
|
|
4711
|
-
|
|
4712
|
-
|
|
4713
|
-
|
|
4918
|
+
filtration_grid = self.get_filtration_grid(grid_strategy=strategy, **filtration_grid_kwargs)
|
|
4919
|
+
else:
|
|
4920
|
+
filtration_grid = sanitize_grid(filtration_grid)
|
|
4921
|
+
if len(filtration_grid) != self.num_parameters:
|
|
4922
|
+
raise ValueError(f"Invalid grid to squeeze onto. Got {len(filtration_grid)=} != {self.num_parameters=}.")
|
|
4923
|
+
api = api_from_tensor(filtration_grid[0])
|
|
4924
|
+
cdef vector[vector[double]] c_filtration_grid = tuple(api.asnumpy(f).astype(np.float64) for f in filtration_grid) # may be faster with loop on views
|
|
4714
4925
|
if coordinate_values and inplace:
|
|
4715
|
-
self.filtration_grid =
|
|
4926
|
+
self.filtration_grid = filtration_grid
|
|
4716
4927
|
if inplace or not coordinate_values:
|
|
4717
4928
|
self.get_ptr().squeeze_filtration_inplace(c_filtration_grid, coordinate_values)
|
|
4718
4929
|
else:
|
|
4719
4930
|
out = SimplexTreeMulti_Fi32(num_parameters=self.num_parameters)
|
|
4720
4931
|
self.get_ptr().squeeze_filtration(out.thisptr, c_filtration_grid)
|
|
4721
|
-
out.filtration_grid =
|
|
4932
|
+
out.filtration_grid = filtration_grid
|
|
4722
4933
|
return out
|
|
4723
4934
|
return self
|
|
4724
4935
|
|
|
4936
|
+
def unsqueeze(self, grid=None)->SimplexTreeMulti_Ff64:
|
|
4937
|
+
from multipers.grids import sanitize_grid
|
|
4938
|
+
grid = self.filtration_grid if grid is None else grid
|
|
4939
|
+
|
|
4940
|
+
cdef vector[vector[double]] cgrid = sanitize_grid(grid, numpyfy=True)
|
|
4941
|
+
new_slicer = SimplexTreeMulti_Ff64()
|
|
4942
|
+
new_slicer.get_ptr().unsqueeze_filtration(self.thisptr, cgrid)
|
|
4943
|
+
|
|
4944
|
+
return new_slicer
|
|
4945
|
+
|
|
4725
4946
|
@property
|
|
4726
4947
|
def is_squeezed(self)->bool:
|
|
4727
|
-
return self.num_vertices > 0 and len(self.filtration_grid)>0 and len(self.filtration_grid[0]) > 0
|
|
4948
|
+
return self.num_vertices > 0 and self.filtration_grid is not None and len(self.filtration_grid)>0 and len(self.filtration_grid[0]) > 0
|
|
4728
4949
|
|
|
4729
4950
|
@property
|
|
4730
4951
|
def dtype(self)->type:
|
|
@@ -5015,15 +5236,15 @@ cdef class SimplexTreeMulti_KFf32:
|
|
|
5015
5236
|
"""
|
|
5016
5237
|
cdef public intptr_t thisptr
|
|
5017
5238
|
|
|
5018
|
-
cdef public
|
|
5019
|
-
cdef public bool _is_function_simplextree
|
|
5239
|
+
cdef public object filtration_grid
|
|
5240
|
+
cdef public bool _is_function_simplextree # TODO : deprecate
|
|
5020
5241
|
# Get the pointer casted as it should be
|
|
5021
5242
|
cdef Simplex_tree_multi_interface[KFf32, float]* get_ptr(self) noexcept nogil:
|
|
5022
5243
|
return <Simplex_tree_multi_interface[KFf32, float]*>(self.thisptr)
|
|
5023
5244
|
|
|
5024
5245
|
# cdef Simplex_tree_persistence_interface * pcohptr
|
|
5025
5246
|
# Fake constructor that does nothing but documenting the constructor
|
|
5026
|
-
def __init__(self, other = None, num_parameters:int
|
|
5247
|
+
def __init__(self, other = None, num_parameters:int=-1,default_values=[], safe_conversion=False):
|
|
5027
5248
|
"""SimplexTreeMulti constructor.
|
|
5028
5249
|
|
|
5029
5250
|
:param other: If `other` is `None` (default value), an empty `SimplexTreeMulti` is created.
|
|
@@ -5048,7 +5269,7 @@ cdef class SimplexTreeMulti_KFf32:
|
|
|
5048
5269
|
def is_kcritical(self)->bool:
|
|
5049
5270
|
return True
|
|
5050
5271
|
# The real cython constructor
|
|
5051
|
-
def __cinit__(self, other = None, int num_parameters
|
|
5272
|
+
def __cinit__(self, other = None, int num_parameters=-1,
|
|
5052
5273
|
default_values=np.asarray([SimplexTreeMulti_KFf32.T_minus_inf()]), # I'm not sure why `[]` does not work. Cython bug ?
|
|
5053
5274
|
bool safe_conversion=False,
|
|
5054
5275
|
): #TODO doc
|
|
@@ -5061,10 +5282,13 @@ cdef class SimplexTreeMulti_KFf32:
|
|
|
5061
5282
|
if isinstance(other, SimplexTreeMulti_KFf32):
|
|
5062
5283
|
other_ptr = other.thisptr
|
|
5063
5284
|
self.thisptr = <intptr_t>(new Simplex_tree_multi_interface[KFf32, float](dereference(<Simplex_tree_multi_interface[KFf32, float]*>other_ptr))) ## prevents calling destructor of other
|
|
5064
|
-
num_parameters
|
|
5285
|
+
if num_parameters <=0:
|
|
5286
|
+
num_parameters = other.num_parameters
|
|
5065
5287
|
self.filtration_grid = other.filtration_grid
|
|
5066
5288
|
elif isinstance(other, SimplexTree): # Constructs a SimplexTreeMulti from a SimplexTree
|
|
5067
5289
|
self.thisptr = <intptr_t>(new Simplex_tree_multi_interface[KFf32, float]())
|
|
5290
|
+
if num_parameters <= 0:
|
|
5291
|
+
num_parameters = 1
|
|
5068
5292
|
if safe_conversion or SAFE_CONVERSION:
|
|
5069
5293
|
new_st_multi = _safe_simplextree_multify_KFf32(other, num_parameters = num_parameters, default_values=np.asarray(default_values))
|
|
5070
5294
|
self.thisptr, new_st_multi.thisptr = new_st_multi.thisptr, self.thisptr
|
|
@@ -5079,10 +5303,12 @@ cdef class SimplexTreeMulti_KFf32:
|
|
|
5079
5303
|
else:
|
|
5080
5304
|
raise TypeError("`other` argument requires to be of type `SimplexTree`, `SimplexTreeMulti`, or `None`.")
|
|
5081
5305
|
else:
|
|
5306
|
+
if num_parameters <=0:
|
|
5307
|
+
num_parameters = 2 # I don't know how dangerous this is, but this is mostly used.
|
|
5082
5308
|
self.thisptr = <intptr_t>(new Simplex_tree_multi_interface[KFf32, float]())
|
|
5083
|
-
self.
|
|
5309
|
+
self.set_num_parameter(num_parameters)
|
|
5084
5310
|
self._is_function_simplextree = False
|
|
5085
|
-
self.filtration_grid=[
|
|
5311
|
+
self.filtration_grid=[]
|
|
5086
5312
|
|
|
5087
5313
|
def __dealloc__(self):
|
|
5088
5314
|
cdef Simplex_tree_multi_interface[KFf32,float]* ptr = self.get_ptr()
|
|
@@ -5092,6 +5318,9 @@ cdef class SimplexTreeMulti_KFf32:
|
|
|
5092
5318
|
|
|
5093
5319
|
def __repr__(self):
|
|
5094
5320
|
return f"SimplexTreeMulti[dtype={np.dtype(self.dtype).name},num_param={self.num_parameters},kcritical={self.is_kcritical},is_squeezed={self.is_squeezed},max_dim={self.dimension}]"
|
|
5321
|
+
def __len__(self):
|
|
5322
|
+
return self.num_simplices
|
|
5323
|
+
|
|
5095
5324
|
def __getstate__(self):
|
|
5096
5325
|
""":returns: Serialized (or flattened) SimplexTree data structure in order to pickle SimplexTree.
|
|
5097
5326
|
:rtype: numpy.array of shape (n,)
|
|
@@ -5747,11 +5976,26 @@ cdef class SimplexTreeMulti_KFf32:
|
|
|
5747
5976
|
out = self.get_ptr().get_filtration_values(degrees)
|
|
5748
5977
|
filtrations_values = [np.asarray(filtration) for filtration in out]
|
|
5749
5978
|
# Removes infs
|
|
5750
|
-
if inf_to_nan:
|
|
5979
|
+
if inf_to_nan and np.dtype(filtrations_values[0].dtype).kind == 'f':
|
|
5751
5980
|
for i,f in enumerate(filtrations_values):
|
|
5752
5981
|
filtrations_values[i][f == np.inf] = np.nan
|
|
5753
5982
|
filtrations_values[i][f == - np.inf] = np.nan
|
|
5754
5983
|
return filtrations_values
|
|
5984
|
+
def _clean_filtration_grid(self):
|
|
5985
|
+
"""
|
|
5986
|
+
Removes the values in filtration_grid that are not linked to any splx.
|
|
5987
|
+
"""
|
|
5988
|
+
if not self.is_squeezed:
|
|
5989
|
+
raise ValueError("No grid to clean.")
|
|
5990
|
+
F = self.filtration_grid
|
|
5991
|
+
self.filtration_grid=None
|
|
5992
|
+
cleaned_coordinates = compute_grid(self)
|
|
5993
|
+
new_st = self.grid_squeeze(cleaned_coordinates)
|
|
5994
|
+
|
|
5995
|
+
self.thisptr, new_st.thisptr = new_st.thisptr, self.thisptr
|
|
5996
|
+
self.filtration_grid = tuple(f[g] for f,g in zip(F,cleaned_coordinates))
|
|
5997
|
+
return self
|
|
5998
|
+
|
|
5755
5999
|
|
|
5756
6000
|
|
|
5757
6001
|
def get_filtration_grid(self, resolution:Iterable[int]|None=None, degrees:Iterable[int]|None=None, drop_quantiles:float|tuple=0, grid_strategy:_available_strategies="exact")->Iterable[np.ndarray]:
|
|
@@ -5787,8 +6031,16 @@ cdef class SimplexTreeMulti_KFf32:
|
|
|
5787
6031
|
return compute_grid(filtrations_values, resolution=resolution,strategy=grid_strategy,drop_quantiles=drop_quantiles)
|
|
5788
6032
|
|
|
5789
6033
|
|
|
5790
|
-
|
|
5791
|
-
|
|
6034
|
+
def grid_squeeze(
|
|
6035
|
+
self,
|
|
6036
|
+
filtration_grid:np.ndarray|list|None=None,
|
|
6037
|
+
bool coordinate_values=True,
|
|
6038
|
+
force=False,
|
|
6039
|
+
strategy:_available_strategies = "exact",
|
|
6040
|
+
grid_strategy=None,
|
|
6041
|
+
inplace=False,
|
|
6042
|
+
**filtration_grid_kwargs
|
|
6043
|
+
)->SimplexTreeMulti_KFi32 | SimplexTreeMulti_KFf32:
|
|
5792
6044
|
"""
|
|
5793
6045
|
Fit the filtration of the simplextree to a grid.
|
|
5794
6046
|
|
|
@@ -5799,26 +6051,50 @@ cdef class SimplexTreeMulti_KFf32:
|
|
|
5799
6051
|
"""
|
|
5800
6052
|
if not force and self.is_squeezed:
|
|
5801
6053
|
raise Exception("SimplexTree already squeezed, use `force=True` if that's really what you want to do.")
|
|
6054
|
+
|
|
6055
|
+
if grid_strategy is not None:
|
|
6056
|
+
warn("`grid_strategy` is deprecated, use `strategy` instead.",DeprecationWarning)
|
|
6057
|
+
strategy=grid_strategy
|
|
6058
|
+
|
|
6059
|
+
if self.is_squeezed:
|
|
6060
|
+
warn("(copy warning) Squeezing an already squeezed slicer.")
|
|
6061
|
+
temp = self.unsqueeze()
|
|
6062
|
+
subgrid = compute_grid(self.filtration_grid, strategy=strategy, resolution=resolution)
|
|
6063
|
+
return temp.grid_squeeze(subgrid, coordinates=coordinates, inplace=inplace)
|
|
6064
|
+
|
|
5802
6065
|
#TODO : multi-critical
|
|
5803
6066
|
if filtration_grid is None:
|
|
5804
|
-
filtration_grid = self.get_filtration_grid(grid_strategy=
|
|
5805
|
-
|
|
5806
|
-
|
|
5807
|
-
|
|
6067
|
+
filtration_grid = self.get_filtration_grid(grid_strategy=strategy, **filtration_grid_kwargs)
|
|
6068
|
+
else:
|
|
6069
|
+
filtration_grid = sanitize_grid(filtration_grid)
|
|
6070
|
+
if len(filtration_grid) != self.num_parameters:
|
|
6071
|
+
raise ValueError(f"Invalid grid to squeeze onto. Got {len(filtration_grid)=} != {self.num_parameters=}.")
|
|
6072
|
+
api = api_from_tensor(filtration_grid[0])
|
|
6073
|
+
cdef vector[vector[double]] c_filtration_grid = tuple(api.asnumpy(f).astype(np.float64) for f in filtration_grid) # may be faster with loop on views
|
|
5808
6074
|
if coordinate_values and inplace:
|
|
5809
|
-
self.filtration_grid =
|
|
6075
|
+
self.filtration_grid = filtration_grid
|
|
5810
6076
|
if inplace or not coordinate_values:
|
|
5811
6077
|
self.get_ptr().squeeze_filtration_inplace(c_filtration_grid, coordinate_values)
|
|
5812
6078
|
else:
|
|
5813
6079
|
out = SimplexTreeMulti_KFi32(num_parameters=self.num_parameters)
|
|
5814
6080
|
self.get_ptr().squeeze_filtration(out.thisptr, c_filtration_grid)
|
|
5815
|
-
out.filtration_grid =
|
|
6081
|
+
out.filtration_grid = filtration_grid
|
|
5816
6082
|
return out
|
|
5817
6083
|
return self
|
|
5818
6084
|
|
|
6085
|
+
def unsqueeze(self, grid=None)->SimplexTreeMulti_KFf64:
|
|
6086
|
+
from multipers.grids import sanitize_grid
|
|
6087
|
+
grid = self.filtration_grid if grid is None else grid
|
|
6088
|
+
|
|
6089
|
+
cdef vector[vector[double]] cgrid = sanitize_grid(grid, numpyfy=True)
|
|
6090
|
+
new_slicer = SimplexTreeMulti_KFf64()
|
|
6091
|
+
new_slicer.get_ptr().unsqueeze_filtration(self.thisptr, cgrid)
|
|
6092
|
+
|
|
6093
|
+
return new_slicer
|
|
6094
|
+
|
|
5819
6095
|
@property
|
|
5820
6096
|
def is_squeezed(self)->bool:
|
|
5821
|
-
return self.num_vertices > 0 and len(self.filtration_grid)>0 and len(self.filtration_grid[0]) > 0
|
|
6097
|
+
return self.num_vertices > 0 and self.filtration_grid is not None and len(self.filtration_grid)>0 and len(self.filtration_grid[0]) > 0
|
|
5822
6098
|
|
|
5823
6099
|
@property
|
|
5824
6100
|
def dtype(self)->type:
|
|
@@ -6111,15 +6387,15 @@ cdef class SimplexTreeMulti_Ff32:
|
|
|
6111
6387
|
"""
|
|
6112
6388
|
cdef public intptr_t thisptr
|
|
6113
6389
|
|
|
6114
|
-
cdef public
|
|
6115
|
-
cdef public bool _is_function_simplextree
|
|
6390
|
+
cdef public object filtration_grid
|
|
6391
|
+
cdef public bool _is_function_simplextree # TODO : deprecate
|
|
6116
6392
|
# Get the pointer casted as it should be
|
|
6117
6393
|
cdef Simplex_tree_multi_interface[Ff32, float]* get_ptr(self) noexcept nogil:
|
|
6118
6394
|
return <Simplex_tree_multi_interface[Ff32, float]*>(self.thisptr)
|
|
6119
6395
|
|
|
6120
6396
|
# cdef Simplex_tree_persistence_interface * pcohptr
|
|
6121
6397
|
# Fake constructor that does nothing but documenting the constructor
|
|
6122
|
-
def __init__(self, other = None, num_parameters:int
|
|
6398
|
+
def __init__(self, other = None, num_parameters:int=-1,default_values=[], safe_conversion=False):
|
|
6123
6399
|
"""SimplexTreeMulti constructor.
|
|
6124
6400
|
|
|
6125
6401
|
:param other: If `other` is `None` (default value), an empty `SimplexTreeMulti` is created.
|
|
@@ -6144,7 +6420,7 @@ cdef class SimplexTreeMulti_Ff32:
|
|
|
6144
6420
|
def is_kcritical(self)->bool:
|
|
6145
6421
|
return False
|
|
6146
6422
|
# The real cython constructor
|
|
6147
|
-
def __cinit__(self, other = None, int num_parameters
|
|
6423
|
+
def __cinit__(self, other = None, int num_parameters=-1,
|
|
6148
6424
|
default_values=np.asarray([SimplexTreeMulti_Ff32.T_minus_inf()]), # I'm not sure why `[]` does not work. Cython bug ?
|
|
6149
6425
|
bool safe_conversion=False,
|
|
6150
6426
|
): #TODO doc
|
|
@@ -6157,10 +6433,13 @@ cdef class SimplexTreeMulti_Ff32:
|
|
|
6157
6433
|
if isinstance(other, SimplexTreeMulti_Ff32):
|
|
6158
6434
|
other_ptr = other.thisptr
|
|
6159
6435
|
self.thisptr = <intptr_t>(new Simplex_tree_multi_interface[Ff32, float](dereference(<Simplex_tree_multi_interface[Ff32, float]*>other_ptr))) ## prevents calling destructor of other
|
|
6160
|
-
num_parameters
|
|
6436
|
+
if num_parameters <=0:
|
|
6437
|
+
num_parameters = other.num_parameters
|
|
6161
6438
|
self.filtration_grid = other.filtration_grid
|
|
6162
6439
|
elif isinstance(other, SimplexTree): # Constructs a SimplexTreeMulti from a SimplexTree
|
|
6163
6440
|
self.thisptr = <intptr_t>(new Simplex_tree_multi_interface[Ff32, float]())
|
|
6441
|
+
if num_parameters <= 0:
|
|
6442
|
+
num_parameters = 1
|
|
6164
6443
|
if safe_conversion or SAFE_CONVERSION:
|
|
6165
6444
|
new_st_multi = _safe_simplextree_multify_Ff32(other, num_parameters = num_parameters, default_values=np.asarray(default_values))
|
|
6166
6445
|
self.thisptr, new_st_multi.thisptr = new_st_multi.thisptr, self.thisptr
|
|
@@ -6175,10 +6454,12 @@ cdef class SimplexTreeMulti_Ff32:
|
|
|
6175
6454
|
else:
|
|
6176
6455
|
raise TypeError("`other` argument requires to be of type `SimplexTree`, `SimplexTreeMulti`, or `None`.")
|
|
6177
6456
|
else:
|
|
6457
|
+
if num_parameters <=0:
|
|
6458
|
+
num_parameters = 2 # I don't know how dangerous this is, but this is mostly used.
|
|
6178
6459
|
self.thisptr = <intptr_t>(new Simplex_tree_multi_interface[Ff32, float]())
|
|
6179
|
-
self.
|
|
6460
|
+
self.set_num_parameter(num_parameters)
|
|
6180
6461
|
self._is_function_simplextree = False
|
|
6181
|
-
self.filtration_grid=[
|
|
6462
|
+
self.filtration_grid=[]
|
|
6182
6463
|
|
|
6183
6464
|
def __dealloc__(self):
|
|
6184
6465
|
cdef Simplex_tree_multi_interface[Ff32,float]* ptr = self.get_ptr()
|
|
@@ -6188,6 +6469,9 @@ cdef class SimplexTreeMulti_Ff32:
|
|
|
6188
6469
|
|
|
6189
6470
|
def __repr__(self):
|
|
6190
6471
|
return f"SimplexTreeMulti[dtype={np.dtype(self.dtype).name},num_param={self.num_parameters},kcritical={self.is_kcritical},is_squeezed={self.is_squeezed},max_dim={self.dimension}]"
|
|
6472
|
+
def __len__(self):
|
|
6473
|
+
return self.num_simplices
|
|
6474
|
+
|
|
6191
6475
|
def __getstate__(self):
|
|
6192
6476
|
""":returns: Serialized (or flattened) SimplexTree data structure in order to pickle SimplexTree.
|
|
6193
6477
|
:rtype: numpy.array of shape (n,)
|
|
@@ -7120,11 +7404,26 @@ cdef class SimplexTreeMulti_Ff32:
|
|
|
7120
7404
|
out = self.get_ptr().get_filtration_values(degrees)
|
|
7121
7405
|
filtrations_values = [np.asarray(filtration) for filtration in out]
|
|
7122
7406
|
# Removes infs
|
|
7123
|
-
if inf_to_nan:
|
|
7407
|
+
if inf_to_nan and np.dtype(filtrations_values[0].dtype).kind == 'f':
|
|
7124
7408
|
for i,f in enumerate(filtrations_values):
|
|
7125
7409
|
filtrations_values[i][f == np.inf] = np.nan
|
|
7126
7410
|
filtrations_values[i][f == - np.inf] = np.nan
|
|
7127
7411
|
return filtrations_values
|
|
7412
|
+
def _clean_filtration_grid(self):
|
|
7413
|
+
"""
|
|
7414
|
+
Removes the values in filtration_grid that are not linked to any splx.
|
|
7415
|
+
"""
|
|
7416
|
+
if not self.is_squeezed:
|
|
7417
|
+
raise ValueError("No grid to clean.")
|
|
7418
|
+
F = self.filtration_grid
|
|
7419
|
+
self.filtration_grid=None
|
|
7420
|
+
cleaned_coordinates = compute_grid(self)
|
|
7421
|
+
new_st = self.grid_squeeze(cleaned_coordinates)
|
|
7422
|
+
|
|
7423
|
+
self.thisptr, new_st.thisptr = new_st.thisptr, self.thisptr
|
|
7424
|
+
self.filtration_grid = tuple(f[g] for f,g in zip(F,cleaned_coordinates))
|
|
7425
|
+
return self
|
|
7426
|
+
|
|
7128
7427
|
|
|
7129
7428
|
|
|
7130
7429
|
def get_filtration_grid(self, resolution:Iterable[int]|None=None, degrees:Iterable[int]|None=None, drop_quantiles:float|tuple=0, grid_strategy:_available_strategies="exact")->Iterable[np.ndarray]:
|
|
@@ -7160,8 +7459,16 @@ cdef class SimplexTreeMulti_Ff32:
|
|
|
7160
7459
|
return compute_grid(filtrations_values, resolution=resolution,strategy=grid_strategy,drop_quantiles=drop_quantiles)
|
|
7161
7460
|
|
|
7162
7461
|
|
|
7163
|
-
|
|
7164
|
-
|
|
7462
|
+
def grid_squeeze(
|
|
7463
|
+
self,
|
|
7464
|
+
filtration_grid:np.ndarray|list|None=None,
|
|
7465
|
+
bool coordinate_values=True,
|
|
7466
|
+
force=False,
|
|
7467
|
+
strategy:_available_strategies = "exact",
|
|
7468
|
+
grid_strategy=None,
|
|
7469
|
+
inplace=False,
|
|
7470
|
+
**filtration_grid_kwargs
|
|
7471
|
+
)->SimplexTreeMulti_Fi32 | SimplexTreeMulti_Ff32:
|
|
7165
7472
|
"""
|
|
7166
7473
|
Fit the filtration of the simplextree to a grid.
|
|
7167
7474
|
|
|
@@ -7172,26 +7479,50 @@ cdef class SimplexTreeMulti_Ff32:
|
|
|
7172
7479
|
"""
|
|
7173
7480
|
if not force and self.is_squeezed:
|
|
7174
7481
|
raise Exception("SimplexTree already squeezed, use `force=True` if that's really what you want to do.")
|
|
7482
|
+
|
|
7483
|
+
if grid_strategy is not None:
|
|
7484
|
+
warn("`grid_strategy` is deprecated, use `strategy` instead.",DeprecationWarning)
|
|
7485
|
+
strategy=grid_strategy
|
|
7486
|
+
|
|
7487
|
+
if self.is_squeezed:
|
|
7488
|
+
warn("(copy warning) Squeezing an already squeezed slicer.")
|
|
7489
|
+
temp = self.unsqueeze()
|
|
7490
|
+
subgrid = compute_grid(self.filtration_grid, strategy=strategy, resolution=resolution)
|
|
7491
|
+
return temp.grid_squeeze(subgrid, coordinates=coordinates, inplace=inplace)
|
|
7492
|
+
|
|
7175
7493
|
#TODO : multi-critical
|
|
7176
7494
|
if filtration_grid is None:
|
|
7177
|
-
filtration_grid = self.get_filtration_grid(grid_strategy=
|
|
7178
|
-
|
|
7179
|
-
|
|
7180
|
-
|
|
7495
|
+
filtration_grid = self.get_filtration_grid(grid_strategy=strategy, **filtration_grid_kwargs)
|
|
7496
|
+
else:
|
|
7497
|
+
filtration_grid = sanitize_grid(filtration_grid)
|
|
7498
|
+
if len(filtration_grid) != self.num_parameters:
|
|
7499
|
+
raise ValueError(f"Invalid grid to squeeze onto. Got {len(filtration_grid)=} != {self.num_parameters=}.")
|
|
7500
|
+
api = api_from_tensor(filtration_grid[0])
|
|
7501
|
+
cdef vector[vector[double]] c_filtration_grid = tuple(api.asnumpy(f).astype(np.float64) for f in filtration_grid) # may be faster with loop on views
|
|
7181
7502
|
if coordinate_values and inplace:
|
|
7182
|
-
self.filtration_grid =
|
|
7503
|
+
self.filtration_grid = filtration_grid
|
|
7183
7504
|
if inplace or not coordinate_values:
|
|
7184
7505
|
self.get_ptr().squeeze_filtration_inplace(c_filtration_grid, coordinate_values)
|
|
7185
7506
|
else:
|
|
7186
7507
|
out = SimplexTreeMulti_Fi32(num_parameters=self.num_parameters)
|
|
7187
7508
|
self.get_ptr().squeeze_filtration(out.thisptr, c_filtration_grid)
|
|
7188
|
-
out.filtration_grid =
|
|
7509
|
+
out.filtration_grid = filtration_grid
|
|
7189
7510
|
return out
|
|
7190
7511
|
return self
|
|
7191
7512
|
|
|
7513
|
+
def unsqueeze(self, grid=None)->SimplexTreeMulti_Ff64:
|
|
7514
|
+
from multipers.grids import sanitize_grid
|
|
7515
|
+
grid = self.filtration_grid if grid is None else grid
|
|
7516
|
+
|
|
7517
|
+
cdef vector[vector[double]] cgrid = sanitize_grid(grid, numpyfy=True)
|
|
7518
|
+
new_slicer = SimplexTreeMulti_Ff64()
|
|
7519
|
+
new_slicer.get_ptr().unsqueeze_filtration(self.thisptr, cgrid)
|
|
7520
|
+
|
|
7521
|
+
return new_slicer
|
|
7522
|
+
|
|
7192
7523
|
@property
|
|
7193
7524
|
def is_squeezed(self)->bool:
|
|
7194
|
-
return self.num_vertices > 0 and len(self.filtration_grid)>0 and len(self.filtration_grid[0]) > 0
|
|
7525
|
+
return self.num_vertices > 0 and self.filtration_grid is not None and len(self.filtration_grid)>0 and len(self.filtration_grid[0]) > 0
|
|
7195
7526
|
|
|
7196
7527
|
@property
|
|
7197
7528
|
def dtype(self)->type:
|
|
@@ -7482,15 +7813,15 @@ cdef class SimplexTreeMulti_KFf64:
|
|
|
7482
7813
|
"""
|
|
7483
7814
|
cdef public intptr_t thisptr
|
|
7484
7815
|
|
|
7485
|
-
cdef public
|
|
7486
|
-
cdef public bool _is_function_simplextree
|
|
7816
|
+
cdef public object filtration_grid
|
|
7817
|
+
cdef public bool _is_function_simplextree # TODO : deprecate
|
|
7487
7818
|
# Get the pointer casted as it should be
|
|
7488
7819
|
cdef Simplex_tree_multi_interface[KFf64, double]* get_ptr(self) noexcept nogil:
|
|
7489
7820
|
return <Simplex_tree_multi_interface[KFf64, double]*>(self.thisptr)
|
|
7490
7821
|
|
|
7491
7822
|
# cdef Simplex_tree_persistence_interface * pcohptr
|
|
7492
7823
|
# Fake constructor that does nothing but documenting the constructor
|
|
7493
|
-
def __init__(self, other = None, num_parameters:int
|
|
7824
|
+
def __init__(self, other = None, num_parameters:int=-1,default_values=[], safe_conversion=False):
|
|
7494
7825
|
"""SimplexTreeMulti constructor.
|
|
7495
7826
|
|
|
7496
7827
|
:param other: If `other` is `None` (default value), an empty `SimplexTreeMulti` is created.
|
|
@@ -7515,7 +7846,7 @@ cdef class SimplexTreeMulti_KFf64:
|
|
|
7515
7846
|
def is_kcritical(self)->bool:
|
|
7516
7847
|
return True
|
|
7517
7848
|
# The real cython constructor
|
|
7518
|
-
def __cinit__(self, other = None, int num_parameters
|
|
7849
|
+
def __cinit__(self, other = None, int num_parameters=-1,
|
|
7519
7850
|
default_values=np.asarray([SimplexTreeMulti_KFf64.T_minus_inf()]), # I'm not sure why `[]` does not work. Cython bug ?
|
|
7520
7851
|
bool safe_conversion=False,
|
|
7521
7852
|
): #TODO doc
|
|
@@ -7528,10 +7859,13 @@ cdef class SimplexTreeMulti_KFf64:
|
|
|
7528
7859
|
if isinstance(other, SimplexTreeMulti_KFf64):
|
|
7529
7860
|
other_ptr = other.thisptr
|
|
7530
7861
|
self.thisptr = <intptr_t>(new Simplex_tree_multi_interface[KFf64, double](dereference(<Simplex_tree_multi_interface[KFf64, double]*>other_ptr))) ## prevents calling destructor of other
|
|
7531
|
-
num_parameters
|
|
7862
|
+
if num_parameters <=0:
|
|
7863
|
+
num_parameters = other.num_parameters
|
|
7532
7864
|
self.filtration_grid = other.filtration_grid
|
|
7533
7865
|
elif isinstance(other, SimplexTree): # Constructs a SimplexTreeMulti from a SimplexTree
|
|
7534
7866
|
self.thisptr = <intptr_t>(new Simplex_tree_multi_interface[KFf64, double]())
|
|
7867
|
+
if num_parameters <= 0:
|
|
7868
|
+
num_parameters = 1
|
|
7535
7869
|
if safe_conversion or SAFE_CONVERSION:
|
|
7536
7870
|
new_st_multi = _safe_simplextree_multify_KFf64(other, num_parameters = num_parameters, default_values=np.asarray(default_values))
|
|
7537
7871
|
self.thisptr, new_st_multi.thisptr = new_st_multi.thisptr, self.thisptr
|
|
@@ -7546,10 +7880,12 @@ cdef class SimplexTreeMulti_KFf64:
|
|
|
7546
7880
|
else:
|
|
7547
7881
|
raise TypeError("`other` argument requires to be of type `SimplexTree`, `SimplexTreeMulti`, or `None`.")
|
|
7548
7882
|
else:
|
|
7883
|
+
if num_parameters <=0:
|
|
7884
|
+
num_parameters = 2 # I don't know how dangerous this is, but this is mostly used.
|
|
7549
7885
|
self.thisptr = <intptr_t>(new Simplex_tree_multi_interface[KFf64, double]())
|
|
7550
|
-
self.
|
|
7886
|
+
self.set_num_parameter(num_parameters)
|
|
7551
7887
|
self._is_function_simplextree = False
|
|
7552
|
-
self.filtration_grid=[
|
|
7888
|
+
self.filtration_grid=[]
|
|
7553
7889
|
|
|
7554
7890
|
def __dealloc__(self):
|
|
7555
7891
|
cdef Simplex_tree_multi_interface[KFf64,double]* ptr = self.get_ptr()
|
|
@@ -7559,6 +7895,9 @@ cdef class SimplexTreeMulti_KFf64:
|
|
|
7559
7895
|
|
|
7560
7896
|
def __repr__(self):
|
|
7561
7897
|
return f"SimplexTreeMulti[dtype={np.dtype(self.dtype).name},num_param={self.num_parameters},kcritical={self.is_kcritical},is_squeezed={self.is_squeezed},max_dim={self.dimension}]"
|
|
7898
|
+
def __len__(self):
|
|
7899
|
+
return self.num_simplices
|
|
7900
|
+
|
|
7562
7901
|
def __getstate__(self):
|
|
7563
7902
|
""":returns: Serialized (or flattened) SimplexTree data structure in order to pickle SimplexTree.
|
|
7564
7903
|
:rtype: numpy.array of shape (n,)
|
|
@@ -8214,11 +8553,26 @@ cdef class SimplexTreeMulti_KFf64:
|
|
|
8214
8553
|
out = self.get_ptr().get_filtration_values(degrees)
|
|
8215
8554
|
filtrations_values = [np.asarray(filtration) for filtration in out]
|
|
8216
8555
|
# Removes infs
|
|
8217
|
-
if inf_to_nan:
|
|
8556
|
+
if inf_to_nan and np.dtype(filtrations_values[0].dtype).kind == 'f':
|
|
8218
8557
|
for i,f in enumerate(filtrations_values):
|
|
8219
8558
|
filtrations_values[i][f == np.inf] = np.nan
|
|
8220
8559
|
filtrations_values[i][f == - np.inf] = np.nan
|
|
8221
8560
|
return filtrations_values
|
|
8561
|
+
def _clean_filtration_grid(self):
|
|
8562
|
+
"""
|
|
8563
|
+
Removes the values in filtration_grid that are not linked to any splx.
|
|
8564
|
+
"""
|
|
8565
|
+
if not self.is_squeezed:
|
|
8566
|
+
raise ValueError("No grid to clean.")
|
|
8567
|
+
F = self.filtration_grid
|
|
8568
|
+
self.filtration_grid=None
|
|
8569
|
+
cleaned_coordinates = compute_grid(self)
|
|
8570
|
+
new_st = self.grid_squeeze(cleaned_coordinates)
|
|
8571
|
+
|
|
8572
|
+
self.thisptr, new_st.thisptr = new_st.thisptr, self.thisptr
|
|
8573
|
+
self.filtration_grid = tuple(f[g] for f,g in zip(F,cleaned_coordinates))
|
|
8574
|
+
return self
|
|
8575
|
+
|
|
8222
8576
|
|
|
8223
8577
|
|
|
8224
8578
|
def get_filtration_grid(self, resolution:Iterable[int]|None=None, degrees:Iterable[int]|None=None, drop_quantiles:float|tuple=0, grid_strategy:_available_strategies="exact")->Iterable[np.ndarray]:
|
|
@@ -8254,8 +8608,16 @@ cdef class SimplexTreeMulti_KFf64:
|
|
|
8254
8608
|
return compute_grid(filtrations_values, resolution=resolution,strategy=grid_strategy,drop_quantiles=drop_quantiles)
|
|
8255
8609
|
|
|
8256
8610
|
|
|
8257
|
-
|
|
8258
|
-
|
|
8611
|
+
def grid_squeeze(
|
|
8612
|
+
self,
|
|
8613
|
+
filtration_grid:np.ndarray|list|None=None,
|
|
8614
|
+
bool coordinate_values=True,
|
|
8615
|
+
force=False,
|
|
8616
|
+
strategy:_available_strategies = "exact",
|
|
8617
|
+
grid_strategy=None,
|
|
8618
|
+
inplace=False,
|
|
8619
|
+
**filtration_grid_kwargs
|
|
8620
|
+
)->SimplexTreeMulti_KFi32 | SimplexTreeMulti_KFf64:
|
|
8259
8621
|
"""
|
|
8260
8622
|
Fit the filtration of the simplextree to a grid.
|
|
8261
8623
|
|
|
@@ -8266,26 +8628,50 @@ cdef class SimplexTreeMulti_KFf64:
|
|
|
8266
8628
|
"""
|
|
8267
8629
|
if not force and self.is_squeezed:
|
|
8268
8630
|
raise Exception("SimplexTree already squeezed, use `force=True` if that's really what you want to do.")
|
|
8631
|
+
|
|
8632
|
+
if grid_strategy is not None:
|
|
8633
|
+
warn("`grid_strategy` is deprecated, use `strategy` instead.",DeprecationWarning)
|
|
8634
|
+
strategy=grid_strategy
|
|
8635
|
+
|
|
8636
|
+
if self.is_squeezed:
|
|
8637
|
+
warn("(copy warning) Squeezing an already squeezed slicer.")
|
|
8638
|
+
temp = self.unsqueeze()
|
|
8639
|
+
subgrid = compute_grid(self.filtration_grid, strategy=strategy, resolution=resolution)
|
|
8640
|
+
return temp.grid_squeeze(subgrid, coordinates=coordinates, inplace=inplace)
|
|
8641
|
+
|
|
8269
8642
|
#TODO : multi-critical
|
|
8270
8643
|
if filtration_grid is None:
|
|
8271
|
-
filtration_grid = self.get_filtration_grid(grid_strategy=
|
|
8272
|
-
|
|
8273
|
-
|
|
8274
|
-
|
|
8644
|
+
filtration_grid = self.get_filtration_grid(grid_strategy=strategy, **filtration_grid_kwargs)
|
|
8645
|
+
else:
|
|
8646
|
+
filtration_grid = sanitize_grid(filtration_grid)
|
|
8647
|
+
if len(filtration_grid) != self.num_parameters:
|
|
8648
|
+
raise ValueError(f"Invalid grid to squeeze onto. Got {len(filtration_grid)=} != {self.num_parameters=}.")
|
|
8649
|
+
api = api_from_tensor(filtration_grid[0])
|
|
8650
|
+
cdef vector[vector[double]] c_filtration_grid = tuple(api.asnumpy(f).astype(np.float64) for f in filtration_grid) # may be faster with loop on views
|
|
8275
8651
|
if coordinate_values and inplace:
|
|
8276
|
-
self.filtration_grid =
|
|
8652
|
+
self.filtration_grid = filtration_grid
|
|
8277
8653
|
if inplace or not coordinate_values:
|
|
8278
8654
|
self.get_ptr().squeeze_filtration_inplace(c_filtration_grid, coordinate_values)
|
|
8279
8655
|
else:
|
|
8280
8656
|
out = SimplexTreeMulti_KFi32(num_parameters=self.num_parameters)
|
|
8281
8657
|
self.get_ptr().squeeze_filtration(out.thisptr, c_filtration_grid)
|
|
8282
|
-
out.filtration_grid =
|
|
8658
|
+
out.filtration_grid = filtration_grid
|
|
8283
8659
|
return out
|
|
8284
8660
|
return self
|
|
8285
8661
|
|
|
8662
|
+
def unsqueeze(self, grid=None)->SimplexTreeMulti_KFf64:
|
|
8663
|
+
from multipers.grids import sanitize_grid
|
|
8664
|
+
grid = self.filtration_grid if grid is None else grid
|
|
8665
|
+
|
|
8666
|
+
cdef vector[vector[double]] cgrid = sanitize_grid(grid, numpyfy=True)
|
|
8667
|
+
new_slicer = SimplexTreeMulti_KFf64()
|
|
8668
|
+
new_slicer.get_ptr().unsqueeze_filtration(self.thisptr, cgrid)
|
|
8669
|
+
|
|
8670
|
+
return new_slicer
|
|
8671
|
+
|
|
8286
8672
|
@property
|
|
8287
8673
|
def is_squeezed(self)->bool:
|
|
8288
|
-
return self.num_vertices > 0 and len(self.filtration_grid)>0 and len(self.filtration_grid[0]) > 0
|
|
8674
|
+
return self.num_vertices > 0 and self.filtration_grid is not None and len(self.filtration_grid)>0 and len(self.filtration_grid[0]) > 0
|
|
8289
8675
|
|
|
8290
8676
|
@property
|
|
8291
8677
|
def dtype(self)->type:
|
|
@@ -8578,15 +8964,15 @@ cdef class SimplexTreeMulti_Ff64:
|
|
|
8578
8964
|
"""
|
|
8579
8965
|
cdef public intptr_t thisptr
|
|
8580
8966
|
|
|
8581
|
-
cdef public
|
|
8582
|
-
cdef public bool _is_function_simplextree
|
|
8967
|
+
cdef public object filtration_grid
|
|
8968
|
+
cdef public bool _is_function_simplextree # TODO : deprecate
|
|
8583
8969
|
# Get the pointer casted as it should be
|
|
8584
8970
|
cdef Simplex_tree_multi_interface[Ff64, double]* get_ptr(self) noexcept nogil:
|
|
8585
8971
|
return <Simplex_tree_multi_interface[Ff64, double]*>(self.thisptr)
|
|
8586
8972
|
|
|
8587
8973
|
# cdef Simplex_tree_persistence_interface * pcohptr
|
|
8588
8974
|
# Fake constructor that does nothing but documenting the constructor
|
|
8589
|
-
def __init__(self, other = None, num_parameters:int
|
|
8975
|
+
def __init__(self, other = None, num_parameters:int=-1,default_values=[], safe_conversion=False):
|
|
8590
8976
|
"""SimplexTreeMulti constructor.
|
|
8591
8977
|
|
|
8592
8978
|
:param other: If `other` is `None` (default value), an empty `SimplexTreeMulti` is created.
|
|
@@ -8611,7 +8997,7 @@ cdef class SimplexTreeMulti_Ff64:
|
|
|
8611
8997
|
def is_kcritical(self)->bool:
|
|
8612
8998
|
return False
|
|
8613
8999
|
# The real cython constructor
|
|
8614
|
-
def __cinit__(self, other = None, int num_parameters
|
|
9000
|
+
def __cinit__(self, other = None, int num_parameters=-1,
|
|
8615
9001
|
default_values=np.asarray([SimplexTreeMulti_Ff64.T_minus_inf()]), # I'm not sure why `[]` does not work. Cython bug ?
|
|
8616
9002
|
bool safe_conversion=False,
|
|
8617
9003
|
): #TODO doc
|
|
@@ -8624,10 +9010,13 @@ cdef class SimplexTreeMulti_Ff64:
|
|
|
8624
9010
|
if isinstance(other, SimplexTreeMulti_Ff64):
|
|
8625
9011
|
other_ptr = other.thisptr
|
|
8626
9012
|
self.thisptr = <intptr_t>(new Simplex_tree_multi_interface[Ff64, double](dereference(<Simplex_tree_multi_interface[Ff64, double]*>other_ptr))) ## prevents calling destructor of other
|
|
8627
|
-
num_parameters
|
|
9013
|
+
if num_parameters <=0:
|
|
9014
|
+
num_parameters = other.num_parameters
|
|
8628
9015
|
self.filtration_grid = other.filtration_grid
|
|
8629
9016
|
elif isinstance(other, SimplexTree): # Constructs a SimplexTreeMulti from a SimplexTree
|
|
8630
9017
|
self.thisptr = <intptr_t>(new Simplex_tree_multi_interface[Ff64, double]())
|
|
9018
|
+
if num_parameters <= 0:
|
|
9019
|
+
num_parameters = 1
|
|
8631
9020
|
if safe_conversion or SAFE_CONVERSION:
|
|
8632
9021
|
new_st_multi = _safe_simplextree_multify_Ff64(other, num_parameters = num_parameters, default_values=np.asarray(default_values))
|
|
8633
9022
|
self.thisptr, new_st_multi.thisptr = new_st_multi.thisptr, self.thisptr
|
|
@@ -8642,10 +9031,12 @@ cdef class SimplexTreeMulti_Ff64:
|
|
|
8642
9031
|
else:
|
|
8643
9032
|
raise TypeError("`other` argument requires to be of type `SimplexTree`, `SimplexTreeMulti`, or `None`.")
|
|
8644
9033
|
else:
|
|
9034
|
+
if num_parameters <=0:
|
|
9035
|
+
num_parameters = 2 # I don't know how dangerous this is, but this is mostly used.
|
|
8645
9036
|
self.thisptr = <intptr_t>(new Simplex_tree_multi_interface[Ff64, double]())
|
|
8646
|
-
self.
|
|
9037
|
+
self.set_num_parameter(num_parameters)
|
|
8647
9038
|
self._is_function_simplextree = False
|
|
8648
|
-
self.filtration_grid=[
|
|
9039
|
+
self.filtration_grid=[]
|
|
8649
9040
|
|
|
8650
9041
|
def __dealloc__(self):
|
|
8651
9042
|
cdef Simplex_tree_multi_interface[Ff64,double]* ptr = self.get_ptr()
|
|
@@ -8655,6 +9046,9 @@ cdef class SimplexTreeMulti_Ff64:
|
|
|
8655
9046
|
|
|
8656
9047
|
def __repr__(self):
|
|
8657
9048
|
return f"SimplexTreeMulti[dtype={np.dtype(self.dtype).name},num_param={self.num_parameters},kcritical={self.is_kcritical},is_squeezed={self.is_squeezed},max_dim={self.dimension}]"
|
|
9049
|
+
def __len__(self):
|
|
9050
|
+
return self.num_simplices
|
|
9051
|
+
|
|
8658
9052
|
def __getstate__(self):
|
|
8659
9053
|
""":returns: Serialized (or flattened) SimplexTree data structure in order to pickle SimplexTree.
|
|
8660
9054
|
:rtype: numpy.array of shape (n,)
|
|
@@ -9587,11 +9981,26 @@ cdef class SimplexTreeMulti_Ff64:
|
|
|
9587
9981
|
out = self.get_ptr().get_filtration_values(degrees)
|
|
9588
9982
|
filtrations_values = [np.asarray(filtration) for filtration in out]
|
|
9589
9983
|
# Removes infs
|
|
9590
|
-
if inf_to_nan:
|
|
9984
|
+
if inf_to_nan and np.dtype(filtrations_values[0].dtype).kind == 'f':
|
|
9591
9985
|
for i,f in enumerate(filtrations_values):
|
|
9592
9986
|
filtrations_values[i][f == np.inf] = np.nan
|
|
9593
9987
|
filtrations_values[i][f == - np.inf] = np.nan
|
|
9594
9988
|
return filtrations_values
|
|
9989
|
+
def _clean_filtration_grid(self):
|
|
9990
|
+
"""
|
|
9991
|
+
Removes the values in filtration_grid that are not linked to any splx.
|
|
9992
|
+
"""
|
|
9993
|
+
if not self.is_squeezed:
|
|
9994
|
+
raise ValueError("No grid to clean.")
|
|
9995
|
+
F = self.filtration_grid
|
|
9996
|
+
self.filtration_grid=None
|
|
9997
|
+
cleaned_coordinates = compute_grid(self)
|
|
9998
|
+
new_st = self.grid_squeeze(cleaned_coordinates)
|
|
9999
|
+
|
|
10000
|
+
self.thisptr, new_st.thisptr = new_st.thisptr, self.thisptr
|
|
10001
|
+
self.filtration_grid = tuple(f[g] for f,g in zip(F,cleaned_coordinates))
|
|
10002
|
+
return self
|
|
10003
|
+
|
|
9595
10004
|
|
|
9596
10005
|
|
|
9597
10006
|
def get_filtration_grid(self, resolution:Iterable[int]|None=None, degrees:Iterable[int]|None=None, drop_quantiles:float|tuple=0, grid_strategy:_available_strategies="exact")->Iterable[np.ndarray]:
|
|
@@ -9627,8 +10036,16 @@ cdef class SimplexTreeMulti_Ff64:
|
|
|
9627
10036
|
return compute_grid(filtrations_values, resolution=resolution,strategy=grid_strategy,drop_quantiles=drop_quantiles)
|
|
9628
10037
|
|
|
9629
10038
|
|
|
9630
|
-
|
|
9631
|
-
|
|
10039
|
+
def grid_squeeze(
|
|
10040
|
+
self,
|
|
10041
|
+
filtration_grid:np.ndarray|list|None=None,
|
|
10042
|
+
bool coordinate_values=True,
|
|
10043
|
+
force=False,
|
|
10044
|
+
strategy:_available_strategies = "exact",
|
|
10045
|
+
grid_strategy=None,
|
|
10046
|
+
inplace=False,
|
|
10047
|
+
**filtration_grid_kwargs
|
|
10048
|
+
)->SimplexTreeMulti_Fi32 | SimplexTreeMulti_Ff64:
|
|
9632
10049
|
"""
|
|
9633
10050
|
Fit the filtration of the simplextree to a grid.
|
|
9634
10051
|
|
|
@@ -9639,26 +10056,50 @@ cdef class SimplexTreeMulti_Ff64:
|
|
|
9639
10056
|
"""
|
|
9640
10057
|
if not force and self.is_squeezed:
|
|
9641
10058
|
raise Exception("SimplexTree already squeezed, use `force=True` if that's really what you want to do.")
|
|
10059
|
+
|
|
10060
|
+
if grid_strategy is not None:
|
|
10061
|
+
warn("`grid_strategy` is deprecated, use `strategy` instead.",DeprecationWarning)
|
|
10062
|
+
strategy=grid_strategy
|
|
10063
|
+
|
|
10064
|
+
if self.is_squeezed:
|
|
10065
|
+
warn("(copy warning) Squeezing an already squeezed slicer.")
|
|
10066
|
+
temp = self.unsqueeze()
|
|
10067
|
+
subgrid = compute_grid(self.filtration_grid, strategy=strategy, resolution=resolution)
|
|
10068
|
+
return temp.grid_squeeze(subgrid, coordinates=coordinates, inplace=inplace)
|
|
10069
|
+
|
|
9642
10070
|
#TODO : multi-critical
|
|
9643
10071
|
if filtration_grid is None:
|
|
9644
|
-
filtration_grid = self.get_filtration_grid(grid_strategy=
|
|
9645
|
-
|
|
9646
|
-
|
|
9647
|
-
|
|
10072
|
+
filtration_grid = self.get_filtration_grid(grid_strategy=strategy, **filtration_grid_kwargs)
|
|
10073
|
+
else:
|
|
10074
|
+
filtration_grid = sanitize_grid(filtration_grid)
|
|
10075
|
+
if len(filtration_grid) != self.num_parameters:
|
|
10076
|
+
raise ValueError(f"Invalid grid to squeeze onto. Got {len(filtration_grid)=} != {self.num_parameters=}.")
|
|
10077
|
+
api = api_from_tensor(filtration_grid[0])
|
|
10078
|
+
cdef vector[vector[double]] c_filtration_grid = tuple(api.asnumpy(f).astype(np.float64) for f in filtration_grid) # may be faster with loop on views
|
|
9648
10079
|
if coordinate_values and inplace:
|
|
9649
|
-
self.filtration_grid =
|
|
10080
|
+
self.filtration_grid = filtration_grid
|
|
9650
10081
|
if inplace or not coordinate_values:
|
|
9651
10082
|
self.get_ptr().squeeze_filtration_inplace(c_filtration_grid, coordinate_values)
|
|
9652
10083
|
else:
|
|
9653
10084
|
out = SimplexTreeMulti_Fi32(num_parameters=self.num_parameters)
|
|
9654
10085
|
self.get_ptr().squeeze_filtration(out.thisptr, c_filtration_grid)
|
|
9655
|
-
out.filtration_grid =
|
|
10086
|
+
out.filtration_grid = filtration_grid
|
|
9656
10087
|
return out
|
|
9657
10088
|
return self
|
|
9658
10089
|
|
|
10090
|
+
def unsqueeze(self, grid=None)->SimplexTreeMulti_Ff64:
|
|
10091
|
+
from multipers.grids import sanitize_grid
|
|
10092
|
+
grid = self.filtration_grid if grid is None else grid
|
|
10093
|
+
|
|
10094
|
+
cdef vector[vector[double]] cgrid = sanitize_grid(grid, numpyfy=True)
|
|
10095
|
+
new_slicer = SimplexTreeMulti_Ff64()
|
|
10096
|
+
new_slicer.get_ptr().unsqueeze_filtration(self.thisptr, cgrid)
|
|
10097
|
+
|
|
10098
|
+
return new_slicer
|
|
10099
|
+
|
|
9659
10100
|
@property
|
|
9660
10101
|
def is_squeezed(self)->bool:
|
|
9661
|
-
return self.num_vertices > 0 and len(self.filtration_grid)>0 and len(self.filtration_grid[0]) > 0
|
|
10102
|
+
return self.num_vertices > 0 and self.filtration_grid is not None and len(self.filtration_grid)>0 and len(self.filtration_grid[0]) > 0
|
|
9662
10103
|
|
|
9663
10104
|
@property
|
|
9664
10105
|
def dtype(self)->type:
|
|
@@ -9968,7 +10409,7 @@ def is_simplextree_multi(input)->bool:
|
|
|
9968
10409
|
|
|
9969
10410
|
|
|
9970
10411
|
|
|
9971
|
-
def SimplexTreeMulti(input=None, int num_parameters
|
|
10412
|
+
def SimplexTreeMulti(input=None, int num_parameters=-1, dtype:type = np.float64, bool kcritical = False,**kwargs) -> SimplexTreeMulti_type:
|
|
9972
10413
|
"""SimplexTreeMulti constructor.
|
|
9973
10414
|
|
|
9974
10415
|
:param other: If `other` is `None` (default value), an empty `SimplexTreeMulti` is created.
|
|
@@ -10179,7 +10620,8 @@ def _euler_signed_measure(simplextree, mass_default=None, bool verbose=False):
|
|
|
10179
10620
|
`[signed_measure_of_degree for degree in degrees]`
|
|
10180
10621
|
with `signed_measure_of_degree` of the form `(dirac location, dirac weights)`.
|
|
10181
10622
|
"""
|
|
10182
|
-
|
|
10623
|
+
if not simplextree.is_squeezed:
|
|
10624
|
+
raise ValueError("Squeeze grid first.")
|
|
10183
10625
|
cdef bool zero_pad = mass_default is not None
|
|
10184
10626
|
# assert simplextree.num_parameters == 2
|
|
10185
10627
|
grid_shape = np.array([len(f) for f in simplextree.filtration_grid])
|
|
@@ -10297,9 +10739,9 @@ def _rank_signed_measure(simplextree, vector[indices_type] degrees, mass_default
|
|
|
10297
10739
|
else:
|
|
10298
10740
|
mass_default = np.asarray(mass_default)
|
|
10299
10741
|
assert mass_default.ndim == 1 and mass_default.shape[0] == simplextree.num_parameters, "Mass default has to be an array like of shape (num_parameters,)"
|
|
10300
|
-
if zero_pad:
|
|
10301
|
-
|
|
10302
|
-
|
|
10742
|
+
# if zero_pad:
|
|
10743
|
+
# for i, _ in enumerate(grid_shape):
|
|
10744
|
+
# grid_shape[i] += 1 # adds a 0
|
|
10303
10745
|
# grid_conversion = tuple(np.concatenate([f, [mass_default[i]]]) for i,f in enumerate(grid_conversion))
|
|
10304
10746
|
|
|
10305
10747
|
assert len(grid_shape) == simplextree.num_parameters, "Grid shape size has to be the number of parameters."
|