multipers 2.3.1__cp312-cp312-win_amd64.whl → 2.3.2__cp312-cp312-win_amd64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of multipers might be problematic. Click here for more details.
- multipers/_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/filtrations/density.py +23 -12
- multipers/filtrations/filtrations.py +74 -15
- multipers/function_rips.cp312-win_amd64.pyd +0 -0
- multipers/grids.cp312-win_amd64.pyd +0 -0
- multipers/grids.pyx +144 -61
- multipers/gudhi/Simplex_tree_multi_interface.h +35 -0
- multipers/gudhi/gudhi/Multi_persistence/Box.h +3 -0
- multipers/gudhi/gudhi/One_critical_filtration.h +17 -9
- multipers/gudhi/mma_interface_matrix.h +5 -3
- multipers/gudhi/truc.h +488 -42
- multipers/io.cp312-win_amd64.pyd +0 -0
- multipers/io.pyx +16 -86
- multipers/ml/mma.py +4 -4
- multipers/ml/signed_measures.py +60 -62
- multipers/mma_structures.cp312-win_amd64.pyd +0 -0
- multipers/mma_structures.pxd +2 -1
- multipers/mma_structures.pyx +56 -12
- multipers/mma_structures.pyx.tp +14 -3
- multipers/multiparameter_module_approximation/approximation.h +45 -13
- multipers/multiparameter_module_approximation.cp312-win_amd64.pyd +0 -0
- multipers/multiparameter_module_approximation.pyx +24 -7
- multipers/plots.py +1 -0
- multipers/point_measure.cp312-win_amd64.pyd +0 -0
- multipers/point_measure.pyx +6 -2
- multipers/simplex_tree_multi.cp312-win_amd64.pyd +0 -0
- multipers/simplex_tree_multi.pxd +1 -0
- multipers/simplex_tree_multi.pyx +535 -113
- multipers/simplex_tree_multi.pyx.tp +79 -19
- multipers/slicer.cp312-win_amd64.pyd +0 -0
- multipers/slicer.pxd +699 -217
- multipers/slicer.pxd.tp +22 -6
- multipers/slicer.pyx +5315 -1365
- multipers/slicer.pyx.tp +202 -46
- multipers/tbb12.dll +0 -0
- multipers/tbbbind_2_5.dll +0 -0
- multipers/tbbmalloc.dll +0 -0
- multipers/tbbmalloc_proxy.dll +0 -0
- multipers/tests/__init__.py +9 -4
- multipers/torch/diff_grids.py +30 -7
- {multipers-2.3.1.dist-info → multipers-2.3.2.dist-info}/METADATA +4 -25
- {multipers-2.3.1.dist-info → multipers-2.3.2.dist-info}/RECORD +49 -46
- {multipers-2.3.1.dist-info → multipers-2.3.2.dist-info}/WHEEL +1 -1
- {multipers-2.3.1.dist-info → multipers-2.3.2.dist-info/licenses}/LICENSE +0 -0
- {multipers-2.3.1.dist-info → multipers-2.3.2.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,8 +82,8 @@ 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)
|
|
@@ -153,7 +154,7 @@ cdef class SimplexTreeMulti_KFi32:
|
|
|
153
154
|
self.thisptr = <intptr_t>(new Simplex_tree_multi_interface[KFi32, int32_t]())
|
|
154
155
|
self.set_num_parameter(num_parameters)
|
|
155
156
|
self._is_function_simplextree = False
|
|
156
|
-
self.filtration_grid=[
|
|
157
|
+
self.filtration_grid=[]
|
|
157
158
|
|
|
158
159
|
def __dealloc__(self):
|
|
159
160
|
cdef Simplex_tree_multi_interface[KFi32,int32_t]* ptr = self.get_ptr()
|
|
@@ -821,11 +822,26 @@ cdef class SimplexTreeMulti_KFi32:
|
|
|
821
822
|
out = self.get_ptr().get_filtration_values(degrees)
|
|
822
823
|
filtrations_values = [np.asarray(filtration) for filtration in out]
|
|
823
824
|
# Removes infs
|
|
824
|
-
if inf_to_nan:
|
|
825
|
+
if inf_to_nan and np.dtype(filtrations_values[0].dtype).kind == 'f':
|
|
825
826
|
for i,f in enumerate(filtrations_values):
|
|
826
827
|
filtrations_values[i][f == np.inf] = np.nan
|
|
827
828
|
filtrations_values[i][f == - np.inf] = np.nan
|
|
828
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
|
+
|
|
829
845
|
|
|
830
846
|
|
|
831
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]:
|
|
@@ -861,8 +877,16 @@ cdef class SimplexTreeMulti_KFi32:
|
|
|
861
877
|
return compute_grid(filtrations_values, resolution=resolution,strategy=grid_strategy,drop_quantiles=drop_quantiles)
|
|
862
878
|
|
|
863
879
|
|
|
864
|
-
|
|
865
|
-
|
|
880
|
+
def grid_squeeze(
|
|
881
|
+
self,
|
|
882
|
+
filtration_grid:np.ndarray|list|None=None,
|
|
883
|
+
bool coordinate_values=True,
|
|
884
|
+
bool force=False,
|
|
885
|
+
str strategy:_available_strategies = "exact",
|
|
886
|
+
grid_strategy=None,
|
|
887
|
+
bool inplace=False,
|
|
888
|
+
**filtration_grid_kwargs
|
|
889
|
+
)->SimplexTreeMulti_KFi32 | SimplexTreeMulti_KFi32:
|
|
866
890
|
"""
|
|
867
891
|
Fit the filtration of the simplextree to a grid.
|
|
868
892
|
|
|
@@ -873,26 +897,50 @@ cdef class SimplexTreeMulti_KFi32:
|
|
|
873
897
|
"""
|
|
874
898
|
if not force and self.is_squeezed:
|
|
875
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
|
+
|
|
876
911
|
#TODO : multi-critical
|
|
877
912
|
if filtration_grid is None:
|
|
878
|
-
filtration_grid = self.get_filtration_grid(grid_strategy=
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
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
|
|
882
920
|
if coordinate_values and inplace:
|
|
883
|
-
self.filtration_grid =
|
|
921
|
+
self.filtration_grid = filtration_grid
|
|
884
922
|
if inplace or not coordinate_values:
|
|
885
923
|
self.get_ptr().squeeze_filtration_inplace(c_filtration_grid, coordinate_values)
|
|
886
924
|
else:
|
|
887
925
|
out = SimplexTreeMulti_KFi32(num_parameters=self.num_parameters)
|
|
888
926
|
self.get_ptr().squeeze_filtration(out.thisptr, c_filtration_grid)
|
|
889
|
-
out.filtration_grid =
|
|
927
|
+
out.filtration_grid = filtration_grid
|
|
890
928
|
return out
|
|
891
929
|
return self
|
|
892
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
|
+
|
|
893
941
|
@property
|
|
894
942
|
def is_squeezed(self)->bool:
|
|
895
|
-
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
|
|
896
944
|
|
|
897
945
|
@property
|
|
898
946
|
def dtype(self)->type:
|
|
@@ -1185,8 +1233,8 @@ cdef class SimplexTreeMulti_Fi32:
|
|
|
1185
1233
|
"""
|
|
1186
1234
|
cdef public intptr_t thisptr
|
|
1187
1235
|
|
|
1188
|
-
cdef public
|
|
1189
|
-
cdef public bool _is_function_simplextree
|
|
1236
|
+
cdef public object filtration_grid
|
|
1237
|
+
cdef public bool _is_function_simplextree # TODO : deprecate
|
|
1190
1238
|
# Get the pointer casted as it should be
|
|
1191
1239
|
cdef Simplex_tree_multi_interface[Fi32, int32_t]* get_ptr(self) noexcept nogil:
|
|
1192
1240
|
return <Simplex_tree_multi_interface[Fi32, int32_t]*>(self.thisptr)
|
|
@@ -1257,7 +1305,7 @@ cdef class SimplexTreeMulti_Fi32:
|
|
|
1257
1305
|
self.thisptr = <intptr_t>(new Simplex_tree_multi_interface[Fi32, int32_t]())
|
|
1258
1306
|
self.set_num_parameter(num_parameters)
|
|
1259
1307
|
self._is_function_simplextree = False
|
|
1260
|
-
self.filtration_grid=[
|
|
1308
|
+
self.filtration_grid=[]
|
|
1261
1309
|
|
|
1262
1310
|
def __dealloc__(self):
|
|
1263
1311
|
cdef Simplex_tree_multi_interface[Fi32,int32_t]* ptr = self.get_ptr()
|
|
@@ -1934,7 +1982,16 @@ cdef class SimplexTreeMulti_Fi32:
|
|
|
1934
1982
|
out = self.get_ptr().get_edge_list()
|
|
1935
1983
|
return out
|
|
1936
1984
|
|
|
1937
|
-
def collapse_edges(
|
|
1985
|
+
def collapse_edges(
|
|
1986
|
+
self,
|
|
1987
|
+
int num=1,
|
|
1988
|
+
int max_dimension = 0,
|
|
1989
|
+
bool progress=False,
|
|
1990
|
+
bool strong=True,
|
|
1991
|
+
bool full=False,
|
|
1992
|
+
bool ignore_warning=False,
|
|
1993
|
+
bool auto_clean=True,
|
|
1994
|
+
)->SimplexTreeMulti_Fi32:
|
|
1938
1995
|
"""Edge collapse for 1-critical 2-parameter clique complex (see https://arxiv.org/abs/2211.05574).
|
|
1939
1996
|
It uses the code from the github repository https://github.com/aj-alonso/filtration_domination .
|
|
1940
1997
|
|
|
@@ -1984,6 +2041,8 @@ cdef class SimplexTreeMulti_Fi32:
|
|
|
1984
2041
|
edges = _collapse_edge_list(edges, num=num, full=full, strong=strong, progress=progress)
|
|
1985
2042
|
# Retrieves the collapsed simplicial complex
|
|
1986
2043
|
self._reconstruct_from_edge_list(edges, swap=True, expand_dimension=max_dimension)
|
|
2044
|
+
if self.is_squeezed and auto_clean:
|
|
2045
|
+
self._clean_filtration_grid()
|
|
1987
2046
|
return self
|
|
1988
2047
|
|
|
1989
2048
|
@cython.inline
|
|
@@ -2202,11 +2261,26 @@ cdef class SimplexTreeMulti_Fi32:
|
|
|
2202
2261
|
out = self.get_ptr().get_filtration_values(degrees)
|
|
2203
2262
|
filtrations_values = [np.asarray(filtration) for filtration in out]
|
|
2204
2263
|
# Removes infs
|
|
2205
|
-
if inf_to_nan:
|
|
2264
|
+
if inf_to_nan and np.dtype(filtrations_values[0].dtype).kind == 'f':
|
|
2206
2265
|
for i,f in enumerate(filtrations_values):
|
|
2207
2266
|
filtrations_values[i][f == np.inf] = np.nan
|
|
2208
2267
|
filtrations_values[i][f == - np.inf] = np.nan
|
|
2209
2268
|
return filtrations_values
|
|
2269
|
+
def _clean_filtration_grid(self):
|
|
2270
|
+
"""
|
|
2271
|
+
Removes the values in filtration_grid that are not linked to any splx.
|
|
2272
|
+
"""
|
|
2273
|
+
if not self.is_squeezed:
|
|
2274
|
+
raise ValueError("No grid to clean.")
|
|
2275
|
+
F = self.filtration_grid
|
|
2276
|
+
self.filtration_grid=None
|
|
2277
|
+
cleaned_coordinates = compute_grid(self)
|
|
2278
|
+
new_st = self.grid_squeeze(cleaned_coordinates)
|
|
2279
|
+
|
|
2280
|
+
self.thisptr, new_st.thisptr = new_st.thisptr, self.thisptr
|
|
2281
|
+
self.filtration_grid = tuple(f[g] for f,g in zip(F,cleaned_coordinates))
|
|
2282
|
+
return self
|
|
2283
|
+
|
|
2210
2284
|
|
|
2211
2285
|
|
|
2212
2286
|
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]:
|
|
@@ -2242,8 +2316,16 @@ cdef class SimplexTreeMulti_Fi32:
|
|
|
2242
2316
|
return compute_grid(filtrations_values, resolution=resolution,strategy=grid_strategy,drop_quantiles=drop_quantiles)
|
|
2243
2317
|
|
|
2244
2318
|
|
|
2245
|
-
|
|
2246
|
-
|
|
2319
|
+
def grid_squeeze(
|
|
2320
|
+
self,
|
|
2321
|
+
filtration_grid:np.ndarray|list|None=None,
|
|
2322
|
+
bool coordinate_values=True,
|
|
2323
|
+
bool force=False,
|
|
2324
|
+
str strategy:_available_strategies = "exact",
|
|
2325
|
+
grid_strategy=None,
|
|
2326
|
+
bool inplace=False,
|
|
2327
|
+
**filtration_grid_kwargs
|
|
2328
|
+
)->SimplexTreeMulti_Fi32 | SimplexTreeMulti_Fi32:
|
|
2247
2329
|
"""
|
|
2248
2330
|
Fit the filtration of the simplextree to a grid.
|
|
2249
2331
|
|
|
@@ -2254,26 +2336,50 @@ cdef class SimplexTreeMulti_Fi32:
|
|
|
2254
2336
|
"""
|
|
2255
2337
|
if not force and self.is_squeezed:
|
|
2256
2338
|
raise Exception("SimplexTree already squeezed, use `force=True` if that's really what you want to do.")
|
|
2339
|
+
|
|
2340
|
+
if grid_strategy is not None:
|
|
2341
|
+
warn("`grid_strategy` is deprecated, use `strategy` instead.",DeprecationWarning)
|
|
2342
|
+
strategy=grid_strategy
|
|
2343
|
+
|
|
2344
|
+
if self.is_squeezed:
|
|
2345
|
+
warn("(copy warning) Squeezing an already squeezed slicer.")
|
|
2346
|
+
temp = self.unsqueeze()
|
|
2347
|
+
subgrid = compute_grid(self.filtration_grid, strategy=strategy, resolution=resolution)
|
|
2348
|
+
return temp.grid_squeeze(subgrid, coordinates=coordinates, inplace=inplace)
|
|
2349
|
+
|
|
2257
2350
|
#TODO : multi-critical
|
|
2258
2351
|
if filtration_grid is None:
|
|
2259
|
-
filtration_grid = self.get_filtration_grid(grid_strategy=
|
|
2260
|
-
|
|
2261
|
-
|
|
2262
|
-
|
|
2352
|
+
filtration_grid = self.get_filtration_grid(grid_strategy=strategy, **filtration_grid_kwargs)
|
|
2353
|
+
else:
|
|
2354
|
+
filtration_grid = sanitize_grid(filtration_grid)
|
|
2355
|
+
if len(filtration_grid) != self.num_parameters:
|
|
2356
|
+
raise ValueError(f"Invalid grid to squeeze onto. Got {len(filtration_grid)=} != {self.num_parameters=}.")
|
|
2357
|
+
api = api_from_tensor(filtration_grid[0])
|
|
2358
|
+
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
|
|
2263
2359
|
if coordinate_values and inplace:
|
|
2264
|
-
self.filtration_grid =
|
|
2360
|
+
self.filtration_grid = filtration_grid
|
|
2265
2361
|
if inplace or not coordinate_values:
|
|
2266
2362
|
self.get_ptr().squeeze_filtration_inplace(c_filtration_grid, coordinate_values)
|
|
2267
2363
|
else:
|
|
2268
2364
|
out = SimplexTreeMulti_Fi32(num_parameters=self.num_parameters)
|
|
2269
2365
|
self.get_ptr().squeeze_filtration(out.thisptr, c_filtration_grid)
|
|
2270
|
-
out.filtration_grid =
|
|
2366
|
+
out.filtration_grid = filtration_grid
|
|
2271
2367
|
return out
|
|
2272
2368
|
return self
|
|
2273
2369
|
|
|
2370
|
+
def unsqueeze(self, grid=None)->SimplexTreeMulti_Ff64:
|
|
2371
|
+
from multipers.grids import sanitize_grid
|
|
2372
|
+
grid = self.filtration_grid if grid is None else grid
|
|
2373
|
+
|
|
2374
|
+
cdef vector[vector[double]] cgrid = sanitize_grid(grid, numpyfy=True)
|
|
2375
|
+
new_slicer = SimplexTreeMulti_Ff64()
|
|
2376
|
+
new_slicer.get_ptr().unsqueeze_filtration(self.thisptr, cgrid)
|
|
2377
|
+
|
|
2378
|
+
return new_slicer
|
|
2379
|
+
|
|
2274
2380
|
@property
|
|
2275
2381
|
def is_squeezed(self)->bool:
|
|
2276
|
-
return self.num_vertices > 0 and len(self.filtration_grid)>0 and len(self.filtration_grid[0]) > 0
|
|
2382
|
+
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
|
|
2277
2383
|
|
|
2278
2384
|
@property
|
|
2279
2385
|
def dtype(self)->type:
|
|
@@ -2564,8 +2670,8 @@ cdef class SimplexTreeMulti_KFi64:
|
|
|
2564
2670
|
"""
|
|
2565
2671
|
cdef public intptr_t thisptr
|
|
2566
2672
|
|
|
2567
|
-
cdef public
|
|
2568
|
-
cdef public bool _is_function_simplextree
|
|
2673
|
+
cdef public object filtration_grid
|
|
2674
|
+
cdef public bool _is_function_simplextree # TODO : deprecate
|
|
2569
2675
|
# Get the pointer casted as it should be
|
|
2570
2676
|
cdef Simplex_tree_multi_interface[KFi64, int64_t]* get_ptr(self) noexcept nogil:
|
|
2571
2677
|
return <Simplex_tree_multi_interface[KFi64, int64_t]*>(self.thisptr)
|
|
@@ -2636,7 +2742,7 @@ cdef class SimplexTreeMulti_KFi64:
|
|
|
2636
2742
|
self.thisptr = <intptr_t>(new Simplex_tree_multi_interface[KFi64, int64_t]())
|
|
2637
2743
|
self.set_num_parameter(num_parameters)
|
|
2638
2744
|
self._is_function_simplextree = False
|
|
2639
|
-
self.filtration_grid=[
|
|
2745
|
+
self.filtration_grid=[]
|
|
2640
2746
|
|
|
2641
2747
|
def __dealloc__(self):
|
|
2642
2748
|
cdef Simplex_tree_multi_interface[KFi64,int64_t]* ptr = self.get_ptr()
|
|
@@ -3304,11 +3410,26 @@ cdef class SimplexTreeMulti_KFi64:
|
|
|
3304
3410
|
out = self.get_ptr().get_filtration_values(degrees)
|
|
3305
3411
|
filtrations_values = [np.asarray(filtration) for filtration in out]
|
|
3306
3412
|
# Removes infs
|
|
3307
|
-
if inf_to_nan:
|
|
3413
|
+
if inf_to_nan and np.dtype(filtrations_values[0].dtype).kind == 'f':
|
|
3308
3414
|
for i,f in enumerate(filtrations_values):
|
|
3309
3415
|
filtrations_values[i][f == np.inf] = np.nan
|
|
3310
3416
|
filtrations_values[i][f == - np.inf] = np.nan
|
|
3311
3417
|
return filtrations_values
|
|
3418
|
+
def _clean_filtration_grid(self):
|
|
3419
|
+
"""
|
|
3420
|
+
Removes the values in filtration_grid that are not linked to any splx.
|
|
3421
|
+
"""
|
|
3422
|
+
if not self.is_squeezed:
|
|
3423
|
+
raise ValueError("No grid to clean.")
|
|
3424
|
+
F = self.filtration_grid
|
|
3425
|
+
self.filtration_grid=None
|
|
3426
|
+
cleaned_coordinates = compute_grid(self)
|
|
3427
|
+
new_st = self.grid_squeeze(cleaned_coordinates)
|
|
3428
|
+
|
|
3429
|
+
self.thisptr, new_st.thisptr = new_st.thisptr, self.thisptr
|
|
3430
|
+
self.filtration_grid = tuple(f[g] for f,g in zip(F,cleaned_coordinates))
|
|
3431
|
+
return self
|
|
3432
|
+
|
|
3312
3433
|
|
|
3313
3434
|
|
|
3314
3435
|
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]:
|
|
@@ -3344,8 +3465,16 @@ cdef class SimplexTreeMulti_KFi64:
|
|
|
3344
3465
|
return compute_grid(filtrations_values, resolution=resolution,strategy=grid_strategy,drop_quantiles=drop_quantiles)
|
|
3345
3466
|
|
|
3346
3467
|
|
|
3347
|
-
|
|
3348
|
-
|
|
3468
|
+
def grid_squeeze(
|
|
3469
|
+
self,
|
|
3470
|
+
filtration_grid:np.ndarray|list|None=None,
|
|
3471
|
+
bool coordinate_values=True,
|
|
3472
|
+
bool force=False,
|
|
3473
|
+
str strategy:_available_strategies = "exact",
|
|
3474
|
+
grid_strategy=None,
|
|
3475
|
+
bool inplace=False,
|
|
3476
|
+
**filtration_grid_kwargs
|
|
3477
|
+
)->SimplexTreeMulti_KFi32 | SimplexTreeMulti_KFi64:
|
|
3349
3478
|
"""
|
|
3350
3479
|
Fit the filtration of the simplextree to a grid.
|
|
3351
3480
|
|
|
@@ -3356,26 +3485,50 @@ cdef class SimplexTreeMulti_KFi64:
|
|
|
3356
3485
|
"""
|
|
3357
3486
|
if not force and self.is_squeezed:
|
|
3358
3487
|
raise Exception("SimplexTree already squeezed, use `force=True` if that's really what you want to do.")
|
|
3488
|
+
|
|
3489
|
+
if grid_strategy is not None:
|
|
3490
|
+
warn("`grid_strategy` is deprecated, use `strategy` instead.",DeprecationWarning)
|
|
3491
|
+
strategy=grid_strategy
|
|
3492
|
+
|
|
3493
|
+
if self.is_squeezed:
|
|
3494
|
+
warn("(copy warning) Squeezing an already squeezed slicer.")
|
|
3495
|
+
temp = self.unsqueeze()
|
|
3496
|
+
subgrid = compute_grid(self.filtration_grid, strategy=strategy, resolution=resolution)
|
|
3497
|
+
return temp.grid_squeeze(subgrid, coordinates=coordinates, inplace=inplace)
|
|
3498
|
+
|
|
3359
3499
|
#TODO : multi-critical
|
|
3360
3500
|
if filtration_grid is None:
|
|
3361
|
-
filtration_grid = self.get_filtration_grid(grid_strategy=
|
|
3362
|
-
|
|
3363
|
-
|
|
3364
|
-
|
|
3501
|
+
filtration_grid = self.get_filtration_grid(grid_strategy=strategy, **filtration_grid_kwargs)
|
|
3502
|
+
else:
|
|
3503
|
+
filtration_grid = sanitize_grid(filtration_grid)
|
|
3504
|
+
if len(filtration_grid) != self.num_parameters:
|
|
3505
|
+
raise ValueError(f"Invalid grid to squeeze onto. Got {len(filtration_grid)=} != {self.num_parameters=}.")
|
|
3506
|
+
api = api_from_tensor(filtration_grid[0])
|
|
3507
|
+
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
|
|
3365
3508
|
if coordinate_values and inplace:
|
|
3366
|
-
self.filtration_grid =
|
|
3509
|
+
self.filtration_grid = filtration_grid
|
|
3367
3510
|
if inplace or not coordinate_values:
|
|
3368
3511
|
self.get_ptr().squeeze_filtration_inplace(c_filtration_grid, coordinate_values)
|
|
3369
3512
|
else:
|
|
3370
3513
|
out = SimplexTreeMulti_KFi32(num_parameters=self.num_parameters)
|
|
3371
3514
|
self.get_ptr().squeeze_filtration(out.thisptr, c_filtration_grid)
|
|
3372
|
-
out.filtration_grid =
|
|
3515
|
+
out.filtration_grid = filtration_grid
|
|
3373
3516
|
return out
|
|
3374
3517
|
return self
|
|
3375
3518
|
|
|
3519
|
+
def unsqueeze(self, grid=None)->SimplexTreeMulti_KFf64:
|
|
3520
|
+
from multipers.grids import sanitize_grid
|
|
3521
|
+
grid = self.filtration_grid if grid is None else grid
|
|
3522
|
+
|
|
3523
|
+
cdef vector[vector[double]] cgrid = sanitize_grid(grid, numpyfy=True)
|
|
3524
|
+
new_slicer = SimplexTreeMulti_KFf64()
|
|
3525
|
+
new_slicer.get_ptr().unsqueeze_filtration(self.thisptr, cgrid)
|
|
3526
|
+
|
|
3527
|
+
return new_slicer
|
|
3528
|
+
|
|
3376
3529
|
@property
|
|
3377
3530
|
def is_squeezed(self)->bool:
|
|
3378
|
-
return self.num_vertices > 0 and len(self.filtration_grid)>0 and len(self.filtration_grid[0]) > 0
|
|
3531
|
+
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
|
|
3379
3532
|
|
|
3380
3533
|
@property
|
|
3381
3534
|
def dtype(self)->type:
|
|
@@ -3668,8 +3821,8 @@ cdef class SimplexTreeMulti_Fi64:
|
|
|
3668
3821
|
"""
|
|
3669
3822
|
cdef public intptr_t thisptr
|
|
3670
3823
|
|
|
3671
|
-
cdef public
|
|
3672
|
-
cdef public bool _is_function_simplextree
|
|
3824
|
+
cdef public object filtration_grid
|
|
3825
|
+
cdef public bool _is_function_simplextree # TODO : deprecate
|
|
3673
3826
|
# Get the pointer casted as it should be
|
|
3674
3827
|
cdef Simplex_tree_multi_interface[Fi64, int64_t]* get_ptr(self) noexcept nogil:
|
|
3675
3828
|
return <Simplex_tree_multi_interface[Fi64, int64_t]*>(self.thisptr)
|
|
@@ -3740,7 +3893,7 @@ cdef class SimplexTreeMulti_Fi64:
|
|
|
3740
3893
|
self.thisptr = <intptr_t>(new Simplex_tree_multi_interface[Fi64, int64_t]())
|
|
3741
3894
|
self.set_num_parameter(num_parameters)
|
|
3742
3895
|
self._is_function_simplextree = False
|
|
3743
|
-
self.filtration_grid=[
|
|
3896
|
+
self.filtration_grid=[]
|
|
3744
3897
|
|
|
3745
3898
|
def __dealloc__(self):
|
|
3746
3899
|
cdef Simplex_tree_multi_interface[Fi64,int64_t]* ptr = self.get_ptr()
|
|
@@ -4417,7 +4570,16 @@ cdef class SimplexTreeMulti_Fi64:
|
|
|
4417
4570
|
out = self.get_ptr().get_edge_list()
|
|
4418
4571
|
return out
|
|
4419
4572
|
|
|
4420
|
-
def collapse_edges(
|
|
4573
|
+
def collapse_edges(
|
|
4574
|
+
self,
|
|
4575
|
+
int num=1,
|
|
4576
|
+
int max_dimension = 0,
|
|
4577
|
+
bool progress=False,
|
|
4578
|
+
bool strong=True,
|
|
4579
|
+
bool full=False,
|
|
4580
|
+
bool ignore_warning=False,
|
|
4581
|
+
bool auto_clean=True,
|
|
4582
|
+
)->SimplexTreeMulti_Fi64:
|
|
4421
4583
|
"""Edge collapse for 1-critical 2-parameter clique complex (see https://arxiv.org/abs/2211.05574).
|
|
4422
4584
|
It uses the code from the github repository https://github.com/aj-alonso/filtration_domination .
|
|
4423
4585
|
|
|
@@ -4467,6 +4629,8 @@ cdef class SimplexTreeMulti_Fi64:
|
|
|
4467
4629
|
edges = _collapse_edge_list(edges, num=num, full=full, strong=strong, progress=progress)
|
|
4468
4630
|
# Retrieves the collapsed simplicial complex
|
|
4469
4631
|
self._reconstruct_from_edge_list(edges, swap=True, expand_dimension=max_dimension)
|
|
4632
|
+
if self.is_squeezed and auto_clean:
|
|
4633
|
+
self._clean_filtration_grid()
|
|
4470
4634
|
return self
|
|
4471
4635
|
|
|
4472
4636
|
@cython.inline
|
|
@@ -4685,11 +4849,26 @@ cdef class SimplexTreeMulti_Fi64:
|
|
|
4685
4849
|
out = self.get_ptr().get_filtration_values(degrees)
|
|
4686
4850
|
filtrations_values = [np.asarray(filtration) for filtration in out]
|
|
4687
4851
|
# Removes infs
|
|
4688
|
-
if inf_to_nan:
|
|
4852
|
+
if inf_to_nan and np.dtype(filtrations_values[0].dtype).kind == 'f':
|
|
4689
4853
|
for i,f in enumerate(filtrations_values):
|
|
4690
4854
|
filtrations_values[i][f == np.inf] = np.nan
|
|
4691
4855
|
filtrations_values[i][f == - np.inf] = np.nan
|
|
4692
4856
|
return filtrations_values
|
|
4857
|
+
def _clean_filtration_grid(self):
|
|
4858
|
+
"""
|
|
4859
|
+
Removes the values in filtration_grid that are not linked to any splx.
|
|
4860
|
+
"""
|
|
4861
|
+
if not self.is_squeezed:
|
|
4862
|
+
raise ValueError("No grid to clean.")
|
|
4863
|
+
F = self.filtration_grid
|
|
4864
|
+
self.filtration_grid=None
|
|
4865
|
+
cleaned_coordinates = compute_grid(self)
|
|
4866
|
+
new_st = self.grid_squeeze(cleaned_coordinates)
|
|
4867
|
+
|
|
4868
|
+
self.thisptr, new_st.thisptr = new_st.thisptr, self.thisptr
|
|
4869
|
+
self.filtration_grid = tuple(f[g] for f,g in zip(F,cleaned_coordinates))
|
|
4870
|
+
return self
|
|
4871
|
+
|
|
4693
4872
|
|
|
4694
4873
|
|
|
4695
4874
|
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]:
|
|
@@ -4725,8 +4904,16 @@ cdef class SimplexTreeMulti_Fi64:
|
|
|
4725
4904
|
return compute_grid(filtrations_values, resolution=resolution,strategy=grid_strategy,drop_quantiles=drop_quantiles)
|
|
4726
4905
|
|
|
4727
4906
|
|
|
4728
|
-
|
|
4729
|
-
|
|
4907
|
+
def grid_squeeze(
|
|
4908
|
+
self,
|
|
4909
|
+
filtration_grid:np.ndarray|list|None=None,
|
|
4910
|
+
bool coordinate_values=True,
|
|
4911
|
+
bool force=False,
|
|
4912
|
+
str strategy:_available_strategies = "exact",
|
|
4913
|
+
grid_strategy=None,
|
|
4914
|
+
bool inplace=False,
|
|
4915
|
+
**filtration_grid_kwargs
|
|
4916
|
+
)->SimplexTreeMulti_Fi32 | SimplexTreeMulti_Fi64:
|
|
4730
4917
|
"""
|
|
4731
4918
|
Fit the filtration of the simplextree to a grid.
|
|
4732
4919
|
|
|
@@ -4737,26 +4924,50 @@ cdef class SimplexTreeMulti_Fi64:
|
|
|
4737
4924
|
"""
|
|
4738
4925
|
if not force and self.is_squeezed:
|
|
4739
4926
|
raise Exception("SimplexTree already squeezed, use `force=True` if that's really what you want to do.")
|
|
4927
|
+
|
|
4928
|
+
if grid_strategy is not None:
|
|
4929
|
+
warn("`grid_strategy` is deprecated, use `strategy` instead.",DeprecationWarning)
|
|
4930
|
+
strategy=grid_strategy
|
|
4931
|
+
|
|
4932
|
+
if self.is_squeezed:
|
|
4933
|
+
warn("(copy warning) Squeezing an already squeezed slicer.")
|
|
4934
|
+
temp = self.unsqueeze()
|
|
4935
|
+
subgrid = compute_grid(self.filtration_grid, strategy=strategy, resolution=resolution)
|
|
4936
|
+
return temp.grid_squeeze(subgrid, coordinates=coordinates, inplace=inplace)
|
|
4937
|
+
|
|
4740
4938
|
#TODO : multi-critical
|
|
4741
4939
|
if filtration_grid is None:
|
|
4742
|
-
filtration_grid = self.get_filtration_grid(grid_strategy=
|
|
4743
|
-
|
|
4744
|
-
|
|
4745
|
-
|
|
4940
|
+
filtration_grid = self.get_filtration_grid(grid_strategy=strategy, **filtration_grid_kwargs)
|
|
4941
|
+
else:
|
|
4942
|
+
filtration_grid = sanitize_grid(filtration_grid)
|
|
4943
|
+
if len(filtration_grid) != self.num_parameters:
|
|
4944
|
+
raise ValueError(f"Invalid grid to squeeze onto. Got {len(filtration_grid)=} != {self.num_parameters=}.")
|
|
4945
|
+
api = api_from_tensor(filtration_grid[0])
|
|
4946
|
+
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
|
|
4746
4947
|
if coordinate_values and inplace:
|
|
4747
|
-
self.filtration_grid =
|
|
4948
|
+
self.filtration_grid = filtration_grid
|
|
4748
4949
|
if inplace or not coordinate_values:
|
|
4749
4950
|
self.get_ptr().squeeze_filtration_inplace(c_filtration_grid, coordinate_values)
|
|
4750
4951
|
else:
|
|
4751
4952
|
out = SimplexTreeMulti_Fi32(num_parameters=self.num_parameters)
|
|
4752
4953
|
self.get_ptr().squeeze_filtration(out.thisptr, c_filtration_grid)
|
|
4753
|
-
out.filtration_grid =
|
|
4954
|
+
out.filtration_grid = filtration_grid
|
|
4754
4955
|
return out
|
|
4755
4956
|
return self
|
|
4756
4957
|
|
|
4958
|
+
def unsqueeze(self, grid=None)->SimplexTreeMulti_Ff64:
|
|
4959
|
+
from multipers.grids import sanitize_grid
|
|
4960
|
+
grid = self.filtration_grid if grid is None else grid
|
|
4961
|
+
|
|
4962
|
+
cdef vector[vector[double]] cgrid = sanitize_grid(grid, numpyfy=True)
|
|
4963
|
+
new_slicer = SimplexTreeMulti_Ff64()
|
|
4964
|
+
new_slicer.get_ptr().unsqueeze_filtration(self.thisptr, cgrid)
|
|
4965
|
+
|
|
4966
|
+
return new_slicer
|
|
4967
|
+
|
|
4757
4968
|
@property
|
|
4758
4969
|
def is_squeezed(self)->bool:
|
|
4759
|
-
return self.num_vertices > 0 and len(self.filtration_grid)>0 and len(self.filtration_grid[0]) > 0
|
|
4970
|
+
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
|
|
4760
4971
|
|
|
4761
4972
|
@property
|
|
4762
4973
|
def dtype(self)->type:
|
|
@@ -5047,8 +5258,8 @@ cdef class SimplexTreeMulti_KFf32:
|
|
|
5047
5258
|
"""
|
|
5048
5259
|
cdef public intptr_t thisptr
|
|
5049
5260
|
|
|
5050
|
-
cdef public
|
|
5051
|
-
cdef public bool _is_function_simplextree
|
|
5261
|
+
cdef public object filtration_grid
|
|
5262
|
+
cdef public bool _is_function_simplextree # TODO : deprecate
|
|
5052
5263
|
# Get the pointer casted as it should be
|
|
5053
5264
|
cdef Simplex_tree_multi_interface[KFf32, float]* get_ptr(self) noexcept nogil:
|
|
5054
5265
|
return <Simplex_tree_multi_interface[KFf32, float]*>(self.thisptr)
|
|
@@ -5119,7 +5330,7 @@ cdef class SimplexTreeMulti_KFf32:
|
|
|
5119
5330
|
self.thisptr = <intptr_t>(new Simplex_tree_multi_interface[KFf32, float]())
|
|
5120
5331
|
self.set_num_parameter(num_parameters)
|
|
5121
5332
|
self._is_function_simplextree = False
|
|
5122
|
-
self.filtration_grid=[
|
|
5333
|
+
self.filtration_grid=[]
|
|
5123
5334
|
|
|
5124
5335
|
def __dealloc__(self):
|
|
5125
5336
|
cdef Simplex_tree_multi_interface[KFf32,float]* ptr = self.get_ptr()
|
|
@@ -5787,11 +5998,26 @@ cdef class SimplexTreeMulti_KFf32:
|
|
|
5787
5998
|
out = self.get_ptr().get_filtration_values(degrees)
|
|
5788
5999
|
filtrations_values = [np.asarray(filtration) for filtration in out]
|
|
5789
6000
|
# Removes infs
|
|
5790
|
-
if inf_to_nan:
|
|
6001
|
+
if inf_to_nan and np.dtype(filtrations_values[0].dtype).kind == 'f':
|
|
5791
6002
|
for i,f in enumerate(filtrations_values):
|
|
5792
6003
|
filtrations_values[i][f == np.inf] = np.nan
|
|
5793
6004
|
filtrations_values[i][f == - np.inf] = np.nan
|
|
5794
6005
|
return filtrations_values
|
|
6006
|
+
def _clean_filtration_grid(self):
|
|
6007
|
+
"""
|
|
6008
|
+
Removes the values in filtration_grid that are not linked to any splx.
|
|
6009
|
+
"""
|
|
6010
|
+
if not self.is_squeezed:
|
|
6011
|
+
raise ValueError("No grid to clean.")
|
|
6012
|
+
F = self.filtration_grid
|
|
6013
|
+
self.filtration_grid=None
|
|
6014
|
+
cleaned_coordinates = compute_grid(self)
|
|
6015
|
+
new_st = self.grid_squeeze(cleaned_coordinates)
|
|
6016
|
+
|
|
6017
|
+
self.thisptr, new_st.thisptr = new_st.thisptr, self.thisptr
|
|
6018
|
+
self.filtration_grid = tuple(f[g] for f,g in zip(F,cleaned_coordinates))
|
|
6019
|
+
return self
|
|
6020
|
+
|
|
5795
6021
|
|
|
5796
6022
|
|
|
5797
6023
|
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]:
|
|
@@ -5827,8 +6053,16 @@ cdef class SimplexTreeMulti_KFf32:
|
|
|
5827
6053
|
return compute_grid(filtrations_values, resolution=resolution,strategy=grid_strategy,drop_quantiles=drop_quantiles)
|
|
5828
6054
|
|
|
5829
6055
|
|
|
5830
|
-
|
|
5831
|
-
|
|
6056
|
+
def grid_squeeze(
|
|
6057
|
+
self,
|
|
6058
|
+
filtration_grid:np.ndarray|list|None=None,
|
|
6059
|
+
bool coordinate_values=True,
|
|
6060
|
+
bool force=False,
|
|
6061
|
+
str strategy:_available_strategies = "exact",
|
|
6062
|
+
grid_strategy=None,
|
|
6063
|
+
bool inplace=False,
|
|
6064
|
+
**filtration_grid_kwargs
|
|
6065
|
+
)->SimplexTreeMulti_KFi32 | SimplexTreeMulti_KFf32:
|
|
5832
6066
|
"""
|
|
5833
6067
|
Fit the filtration of the simplextree to a grid.
|
|
5834
6068
|
|
|
@@ -5839,26 +6073,50 @@ cdef class SimplexTreeMulti_KFf32:
|
|
|
5839
6073
|
"""
|
|
5840
6074
|
if not force and self.is_squeezed:
|
|
5841
6075
|
raise Exception("SimplexTree already squeezed, use `force=True` if that's really what you want to do.")
|
|
6076
|
+
|
|
6077
|
+
if grid_strategy is not None:
|
|
6078
|
+
warn("`grid_strategy` is deprecated, use `strategy` instead.",DeprecationWarning)
|
|
6079
|
+
strategy=grid_strategy
|
|
6080
|
+
|
|
6081
|
+
if self.is_squeezed:
|
|
6082
|
+
warn("(copy warning) Squeezing an already squeezed slicer.")
|
|
6083
|
+
temp = self.unsqueeze()
|
|
6084
|
+
subgrid = compute_grid(self.filtration_grid, strategy=strategy, resolution=resolution)
|
|
6085
|
+
return temp.grid_squeeze(subgrid, coordinates=coordinates, inplace=inplace)
|
|
6086
|
+
|
|
5842
6087
|
#TODO : multi-critical
|
|
5843
6088
|
if filtration_grid is None:
|
|
5844
|
-
filtration_grid = self.get_filtration_grid(grid_strategy=
|
|
5845
|
-
|
|
5846
|
-
|
|
5847
|
-
|
|
6089
|
+
filtration_grid = self.get_filtration_grid(grid_strategy=strategy, **filtration_grid_kwargs)
|
|
6090
|
+
else:
|
|
6091
|
+
filtration_grid = sanitize_grid(filtration_grid)
|
|
6092
|
+
if len(filtration_grid) != self.num_parameters:
|
|
6093
|
+
raise ValueError(f"Invalid grid to squeeze onto. Got {len(filtration_grid)=} != {self.num_parameters=}.")
|
|
6094
|
+
api = api_from_tensor(filtration_grid[0])
|
|
6095
|
+
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
|
|
5848
6096
|
if coordinate_values and inplace:
|
|
5849
|
-
self.filtration_grid =
|
|
6097
|
+
self.filtration_grid = filtration_grid
|
|
5850
6098
|
if inplace or not coordinate_values:
|
|
5851
6099
|
self.get_ptr().squeeze_filtration_inplace(c_filtration_grid, coordinate_values)
|
|
5852
6100
|
else:
|
|
5853
6101
|
out = SimplexTreeMulti_KFi32(num_parameters=self.num_parameters)
|
|
5854
6102
|
self.get_ptr().squeeze_filtration(out.thisptr, c_filtration_grid)
|
|
5855
|
-
out.filtration_grid =
|
|
6103
|
+
out.filtration_grid = filtration_grid
|
|
5856
6104
|
return out
|
|
5857
6105
|
return self
|
|
5858
6106
|
|
|
6107
|
+
def unsqueeze(self, grid=None)->SimplexTreeMulti_KFf64:
|
|
6108
|
+
from multipers.grids import sanitize_grid
|
|
6109
|
+
grid = self.filtration_grid if grid is None else grid
|
|
6110
|
+
|
|
6111
|
+
cdef vector[vector[double]] cgrid = sanitize_grid(grid, numpyfy=True)
|
|
6112
|
+
new_slicer = SimplexTreeMulti_KFf64()
|
|
6113
|
+
new_slicer.get_ptr().unsqueeze_filtration(self.thisptr, cgrid)
|
|
6114
|
+
|
|
6115
|
+
return new_slicer
|
|
6116
|
+
|
|
5859
6117
|
@property
|
|
5860
6118
|
def is_squeezed(self)->bool:
|
|
5861
|
-
return self.num_vertices > 0 and len(self.filtration_grid)>0 and len(self.filtration_grid[0]) > 0
|
|
6119
|
+
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
|
|
5862
6120
|
|
|
5863
6121
|
@property
|
|
5864
6122
|
def dtype(self)->type:
|
|
@@ -6151,8 +6409,8 @@ cdef class SimplexTreeMulti_Ff32:
|
|
|
6151
6409
|
"""
|
|
6152
6410
|
cdef public intptr_t thisptr
|
|
6153
6411
|
|
|
6154
|
-
cdef public
|
|
6155
|
-
cdef public bool _is_function_simplextree
|
|
6412
|
+
cdef public object filtration_grid
|
|
6413
|
+
cdef public bool _is_function_simplextree # TODO : deprecate
|
|
6156
6414
|
# Get the pointer casted as it should be
|
|
6157
6415
|
cdef Simplex_tree_multi_interface[Ff32, float]* get_ptr(self) noexcept nogil:
|
|
6158
6416
|
return <Simplex_tree_multi_interface[Ff32, float]*>(self.thisptr)
|
|
@@ -6223,7 +6481,7 @@ cdef class SimplexTreeMulti_Ff32:
|
|
|
6223
6481
|
self.thisptr = <intptr_t>(new Simplex_tree_multi_interface[Ff32, float]())
|
|
6224
6482
|
self.set_num_parameter(num_parameters)
|
|
6225
6483
|
self._is_function_simplextree = False
|
|
6226
|
-
self.filtration_grid=[
|
|
6484
|
+
self.filtration_grid=[]
|
|
6227
6485
|
|
|
6228
6486
|
def __dealloc__(self):
|
|
6229
6487
|
cdef Simplex_tree_multi_interface[Ff32,float]* ptr = self.get_ptr()
|
|
@@ -6900,7 +7158,16 @@ cdef class SimplexTreeMulti_Ff32:
|
|
|
6900
7158
|
out = self.get_ptr().get_edge_list()
|
|
6901
7159
|
return out
|
|
6902
7160
|
|
|
6903
|
-
def collapse_edges(
|
|
7161
|
+
def collapse_edges(
|
|
7162
|
+
self,
|
|
7163
|
+
int num=1,
|
|
7164
|
+
int max_dimension = 0,
|
|
7165
|
+
bool progress=False,
|
|
7166
|
+
bool strong=True,
|
|
7167
|
+
bool full=False,
|
|
7168
|
+
bool ignore_warning=False,
|
|
7169
|
+
bool auto_clean=True,
|
|
7170
|
+
)->SimplexTreeMulti_Ff32:
|
|
6904
7171
|
"""Edge collapse for 1-critical 2-parameter clique complex (see https://arxiv.org/abs/2211.05574).
|
|
6905
7172
|
It uses the code from the github repository https://github.com/aj-alonso/filtration_domination .
|
|
6906
7173
|
|
|
@@ -6950,6 +7217,8 @@ cdef class SimplexTreeMulti_Ff32:
|
|
|
6950
7217
|
edges = _collapse_edge_list(edges, num=num, full=full, strong=strong, progress=progress)
|
|
6951
7218
|
# Retrieves the collapsed simplicial complex
|
|
6952
7219
|
self._reconstruct_from_edge_list(edges, swap=True, expand_dimension=max_dimension)
|
|
7220
|
+
if self.is_squeezed and auto_clean:
|
|
7221
|
+
self._clean_filtration_grid()
|
|
6953
7222
|
return self
|
|
6954
7223
|
|
|
6955
7224
|
@cython.inline
|
|
@@ -7168,11 +7437,26 @@ cdef class SimplexTreeMulti_Ff32:
|
|
|
7168
7437
|
out = self.get_ptr().get_filtration_values(degrees)
|
|
7169
7438
|
filtrations_values = [np.asarray(filtration) for filtration in out]
|
|
7170
7439
|
# Removes infs
|
|
7171
|
-
if inf_to_nan:
|
|
7440
|
+
if inf_to_nan and np.dtype(filtrations_values[0].dtype).kind == 'f':
|
|
7172
7441
|
for i,f in enumerate(filtrations_values):
|
|
7173
7442
|
filtrations_values[i][f == np.inf] = np.nan
|
|
7174
7443
|
filtrations_values[i][f == - np.inf] = np.nan
|
|
7175
7444
|
return filtrations_values
|
|
7445
|
+
def _clean_filtration_grid(self):
|
|
7446
|
+
"""
|
|
7447
|
+
Removes the values in filtration_grid that are not linked to any splx.
|
|
7448
|
+
"""
|
|
7449
|
+
if not self.is_squeezed:
|
|
7450
|
+
raise ValueError("No grid to clean.")
|
|
7451
|
+
F = self.filtration_grid
|
|
7452
|
+
self.filtration_grid=None
|
|
7453
|
+
cleaned_coordinates = compute_grid(self)
|
|
7454
|
+
new_st = self.grid_squeeze(cleaned_coordinates)
|
|
7455
|
+
|
|
7456
|
+
self.thisptr, new_st.thisptr = new_st.thisptr, self.thisptr
|
|
7457
|
+
self.filtration_grid = tuple(f[g] for f,g in zip(F,cleaned_coordinates))
|
|
7458
|
+
return self
|
|
7459
|
+
|
|
7176
7460
|
|
|
7177
7461
|
|
|
7178
7462
|
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]:
|
|
@@ -7208,8 +7492,16 @@ cdef class SimplexTreeMulti_Ff32:
|
|
|
7208
7492
|
return compute_grid(filtrations_values, resolution=resolution,strategy=grid_strategy,drop_quantiles=drop_quantiles)
|
|
7209
7493
|
|
|
7210
7494
|
|
|
7211
|
-
|
|
7212
|
-
|
|
7495
|
+
def grid_squeeze(
|
|
7496
|
+
self,
|
|
7497
|
+
filtration_grid:np.ndarray|list|None=None,
|
|
7498
|
+
bool coordinate_values=True,
|
|
7499
|
+
bool force=False,
|
|
7500
|
+
str strategy:_available_strategies = "exact",
|
|
7501
|
+
grid_strategy=None,
|
|
7502
|
+
bool inplace=False,
|
|
7503
|
+
**filtration_grid_kwargs
|
|
7504
|
+
)->SimplexTreeMulti_Fi32 | SimplexTreeMulti_Ff32:
|
|
7213
7505
|
"""
|
|
7214
7506
|
Fit the filtration of the simplextree to a grid.
|
|
7215
7507
|
|
|
@@ -7220,26 +7512,50 @@ cdef class SimplexTreeMulti_Ff32:
|
|
|
7220
7512
|
"""
|
|
7221
7513
|
if not force and self.is_squeezed:
|
|
7222
7514
|
raise Exception("SimplexTree already squeezed, use `force=True` if that's really what you want to do.")
|
|
7515
|
+
|
|
7516
|
+
if grid_strategy is not None:
|
|
7517
|
+
warn("`grid_strategy` is deprecated, use `strategy` instead.",DeprecationWarning)
|
|
7518
|
+
strategy=grid_strategy
|
|
7519
|
+
|
|
7520
|
+
if self.is_squeezed:
|
|
7521
|
+
warn("(copy warning) Squeezing an already squeezed slicer.")
|
|
7522
|
+
temp = self.unsqueeze()
|
|
7523
|
+
subgrid = compute_grid(self.filtration_grid, strategy=strategy, resolution=resolution)
|
|
7524
|
+
return temp.grid_squeeze(subgrid, coordinates=coordinates, inplace=inplace)
|
|
7525
|
+
|
|
7223
7526
|
#TODO : multi-critical
|
|
7224
7527
|
if filtration_grid is None:
|
|
7225
|
-
filtration_grid = self.get_filtration_grid(grid_strategy=
|
|
7226
|
-
|
|
7227
|
-
|
|
7228
|
-
|
|
7528
|
+
filtration_grid = self.get_filtration_grid(grid_strategy=strategy, **filtration_grid_kwargs)
|
|
7529
|
+
else:
|
|
7530
|
+
filtration_grid = sanitize_grid(filtration_grid)
|
|
7531
|
+
if len(filtration_grid) != self.num_parameters:
|
|
7532
|
+
raise ValueError(f"Invalid grid to squeeze onto. Got {len(filtration_grid)=} != {self.num_parameters=}.")
|
|
7533
|
+
api = api_from_tensor(filtration_grid[0])
|
|
7534
|
+
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
|
|
7229
7535
|
if coordinate_values and inplace:
|
|
7230
|
-
self.filtration_grid =
|
|
7536
|
+
self.filtration_grid = filtration_grid
|
|
7231
7537
|
if inplace or not coordinate_values:
|
|
7232
7538
|
self.get_ptr().squeeze_filtration_inplace(c_filtration_grid, coordinate_values)
|
|
7233
7539
|
else:
|
|
7234
7540
|
out = SimplexTreeMulti_Fi32(num_parameters=self.num_parameters)
|
|
7235
7541
|
self.get_ptr().squeeze_filtration(out.thisptr, c_filtration_grid)
|
|
7236
|
-
out.filtration_grid =
|
|
7542
|
+
out.filtration_grid = filtration_grid
|
|
7237
7543
|
return out
|
|
7238
7544
|
return self
|
|
7239
7545
|
|
|
7546
|
+
def unsqueeze(self, grid=None)->SimplexTreeMulti_Ff64:
|
|
7547
|
+
from multipers.grids import sanitize_grid
|
|
7548
|
+
grid = self.filtration_grid if grid is None else grid
|
|
7549
|
+
|
|
7550
|
+
cdef vector[vector[double]] cgrid = sanitize_grid(grid, numpyfy=True)
|
|
7551
|
+
new_slicer = SimplexTreeMulti_Ff64()
|
|
7552
|
+
new_slicer.get_ptr().unsqueeze_filtration(self.thisptr, cgrid)
|
|
7553
|
+
|
|
7554
|
+
return new_slicer
|
|
7555
|
+
|
|
7240
7556
|
@property
|
|
7241
7557
|
def is_squeezed(self)->bool:
|
|
7242
|
-
return self.num_vertices > 0 and len(self.filtration_grid)>0 and len(self.filtration_grid[0]) > 0
|
|
7558
|
+
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
|
|
7243
7559
|
|
|
7244
7560
|
@property
|
|
7245
7561
|
def dtype(self)->type:
|
|
@@ -7530,8 +7846,8 @@ cdef class SimplexTreeMulti_KFf64:
|
|
|
7530
7846
|
"""
|
|
7531
7847
|
cdef public intptr_t thisptr
|
|
7532
7848
|
|
|
7533
|
-
cdef public
|
|
7534
|
-
cdef public bool _is_function_simplextree
|
|
7849
|
+
cdef public object filtration_grid
|
|
7850
|
+
cdef public bool _is_function_simplextree # TODO : deprecate
|
|
7535
7851
|
# Get the pointer casted as it should be
|
|
7536
7852
|
cdef Simplex_tree_multi_interface[KFf64, double]* get_ptr(self) noexcept nogil:
|
|
7537
7853
|
return <Simplex_tree_multi_interface[KFf64, double]*>(self.thisptr)
|
|
@@ -7602,7 +7918,7 @@ cdef class SimplexTreeMulti_KFf64:
|
|
|
7602
7918
|
self.thisptr = <intptr_t>(new Simplex_tree_multi_interface[KFf64, double]())
|
|
7603
7919
|
self.set_num_parameter(num_parameters)
|
|
7604
7920
|
self._is_function_simplextree = False
|
|
7605
|
-
self.filtration_grid=[
|
|
7921
|
+
self.filtration_grid=[]
|
|
7606
7922
|
|
|
7607
7923
|
def __dealloc__(self):
|
|
7608
7924
|
cdef Simplex_tree_multi_interface[KFf64,double]* ptr = self.get_ptr()
|
|
@@ -8270,11 +8586,26 @@ cdef class SimplexTreeMulti_KFf64:
|
|
|
8270
8586
|
out = self.get_ptr().get_filtration_values(degrees)
|
|
8271
8587
|
filtrations_values = [np.asarray(filtration) for filtration in out]
|
|
8272
8588
|
# Removes infs
|
|
8273
|
-
if inf_to_nan:
|
|
8589
|
+
if inf_to_nan and np.dtype(filtrations_values[0].dtype).kind == 'f':
|
|
8274
8590
|
for i,f in enumerate(filtrations_values):
|
|
8275
8591
|
filtrations_values[i][f == np.inf] = np.nan
|
|
8276
8592
|
filtrations_values[i][f == - np.inf] = np.nan
|
|
8277
8593
|
return filtrations_values
|
|
8594
|
+
def _clean_filtration_grid(self):
|
|
8595
|
+
"""
|
|
8596
|
+
Removes the values in filtration_grid that are not linked to any splx.
|
|
8597
|
+
"""
|
|
8598
|
+
if not self.is_squeezed:
|
|
8599
|
+
raise ValueError("No grid to clean.")
|
|
8600
|
+
F = self.filtration_grid
|
|
8601
|
+
self.filtration_grid=None
|
|
8602
|
+
cleaned_coordinates = compute_grid(self)
|
|
8603
|
+
new_st = self.grid_squeeze(cleaned_coordinates)
|
|
8604
|
+
|
|
8605
|
+
self.thisptr, new_st.thisptr = new_st.thisptr, self.thisptr
|
|
8606
|
+
self.filtration_grid = tuple(f[g] for f,g in zip(F,cleaned_coordinates))
|
|
8607
|
+
return self
|
|
8608
|
+
|
|
8278
8609
|
|
|
8279
8610
|
|
|
8280
8611
|
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]:
|
|
@@ -8310,8 +8641,16 @@ cdef class SimplexTreeMulti_KFf64:
|
|
|
8310
8641
|
return compute_grid(filtrations_values, resolution=resolution,strategy=grid_strategy,drop_quantiles=drop_quantiles)
|
|
8311
8642
|
|
|
8312
8643
|
|
|
8313
|
-
|
|
8314
|
-
|
|
8644
|
+
def grid_squeeze(
|
|
8645
|
+
self,
|
|
8646
|
+
filtration_grid:np.ndarray|list|None=None,
|
|
8647
|
+
bool coordinate_values=True,
|
|
8648
|
+
bool force=False,
|
|
8649
|
+
str strategy:_available_strategies = "exact",
|
|
8650
|
+
grid_strategy=None,
|
|
8651
|
+
bool inplace=False,
|
|
8652
|
+
**filtration_grid_kwargs
|
|
8653
|
+
)->SimplexTreeMulti_KFi32 | SimplexTreeMulti_KFf64:
|
|
8315
8654
|
"""
|
|
8316
8655
|
Fit the filtration of the simplextree to a grid.
|
|
8317
8656
|
|
|
@@ -8322,26 +8661,50 @@ cdef class SimplexTreeMulti_KFf64:
|
|
|
8322
8661
|
"""
|
|
8323
8662
|
if not force and self.is_squeezed:
|
|
8324
8663
|
raise Exception("SimplexTree already squeezed, use `force=True` if that's really what you want to do.")
|
|
8664
|
+
|
|
8665
|
+
if grid_strategy is not None:
|
|
8666
|
+
warn("`grid_strategy` is deprecated, use `strategy` instead.",DeprecationWarning)
|
|
8667
|
+
strategy=grid_strategy
|
|
8668
|
+
|
|
8669
|
+
if self.is_squeezed:
|
|
8670
|
+
warn("(copy warning) Squeezing an already squeezed slicer.")
|
|
8671
|
+
temp = self.unsqueeze()
|
|
8672
|
+
subgrid = compute_grid(self.filtration_grid, strategy=strategy, resolution=resolution)
|
|
8673
|
+
return temp.grid_squeeze(subgrid, coordinates=coordinates, inplace=inplace)
|
|
8674
|
+
|
|
8325
8675
|
#TODO : multi-critical
|
|
8326
8676
|
if filtration_grid is None:
|
|
8327
|
-
filtration_grid = self.get_filtration_grid(grid_strategy=
|
|
8328
|
-
|
|
8329
|
-
|
|
8330
|
-
|
|
8677
|
+
filtration_grid = self.get_filtration_grid(grid_strategy=strategy, **filtration_grid_kwargs)
|
|
8678
|
+
else:
|
|
8679
|
+
filtration_grid = sanitize_grid(filtration_grid)
|
|
8680
|
+
if len(filtration_grid) != self.num_parameters:
|
|
8681
|
+
raise ValueError(f"Invalid grid to squeeze onto. Got {len(filtration_grid)=} != {self.num_parameters=}.")
|
|
8682
|
+
api = api_from_tensor(filtration_grid[0])
|
|
8683
|
+
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
|
|
8331
8684
|
if coordinate_values and inplace:
|
|
8332
|
-
self.filtration_grid =
|
|
8685
|
+
self.filtration_grid = filtration_grid
|
|
8333
8686
|
if inplace or not coordinate_values:
|
|
8334
8687
|
self.get_ptr().squeeze_filtration_inplace(c_filtration_grid, coordinate_values)
|
|
8335
8688
|
else:
|
|
8336
8689
|
out = SimplexTreeMulti_KFi32(num_parameters=self.num_parameters)
|
|
8337
8690
|
self.get_ptr().squeeze_filtration(out.thisptr, c_filtration_grid)
|
|
8338
|
-
out.filtration_grid =
|
|
8691
|
+
out.filtration_grid = filtration_grid
|
|
8339
8692
|
return out
|
|
8340
8693
|
return self
|
|
8341
8694
|
|
|
8695
|
+
def unsqueeze(self, grid=None)->SimplexTreeMulti_KFf64:
|
|
8696
|
+
from multipers.grids import sanitize_grid
|
|
8697
|
+
grid = self.filtration_grid if grid is None else grid
|
|
8698
|
+
|
|
8699
|
+
cdef vector[vector[double]] cgrid = sanitize_grid(grid, numpyfy=True)
|
|
8700
|
+
new_slicer = SimplexTreeMulti_KFf64()
|
|
8701
|
+
new_slicer.get_ptr().unsqueeze_filtration(self.thisptr, cgrid)
|
|
8702
|
+
|
|
8703
|
+
return new_slicer
|
|
8704
|
+
|
|
8342
8705
|
@property
|
|
8343
8706
|
def is_squeezed(self)->bool:
|
|
8344
|
-
return self.num_vertices > 0 and len(self.filtration_grid)>0 and len(self.filtration_grid[0]) > 0
|
|
8707
|
+
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
|
|
8345
8708
|
|
|
8346
8709
|
@property
|
|
8347
8710
|
def dtype(self)->type:
|
|
@@ -8634,8 +8997,8 @@ cdef class SimplexTreeMulti_Ff64:
|
|
|
8634
8997
|
"""
|
|
8635
8998
|
cdef public intptr_t thisptr
|
|
8636
8999
|
|
|
8637
|
-
cdef public
|
|
8638
|
-
cdef public bool _is_function_simplextree
|
|
9000
|
+
cdef public object filtration_grid
|
|
9001
|
+
cdef public bool _is_function_simplextree # TODO : deprecate
|
|
8639
9002
|
# Get the pointer casted as it should be
|
|
8640
9003
|
cdef Simplex_tree_multi_interface[Ff64, double]* get_ptr(self) noexcept nogil:
|
|
8641
9004
|
return <Simplex_tree_multi_interface[Ff64, double]*>(self.thisptr)
|
|
@@ -8706,7 +9069,7 @@ cdef class SimplexTreeMulti_Ff64:
|
|
|
8706
9069
|
self.thisptr = <intptr_t>(new Simplex_tree_multi_interface[Ff64, double]())
|
|
8707
9070
|
self.set_num_parameter(num_parameters)
|
|
8708
9071
|
self._is_function_simplextree = False
|
|
8709
|
-
self.filtration_grid=[
|
|
9072
|
+
self.filtration_grid=[]
|
|
8710
9073
|
|
|
8711
9074
|
def __dealloc__(self):
|
|
8712
9075
|
cdef Simplex_tree_multi_interface[Ff64,double]* ptr = self.get_ptr()
|
|
@@ -9383,7 +9746,16 @@ cdef class SimplexTreeMulti_Ff64:
|
|
|
9383
9746
|
out = self.get_ptr().get_edge_list()
|
|
9384
9747
|
return out
|
|
9385
9748
|
|
|
9386
|
-
def collapse_edges(
|
|
9749
|
+
def collapse_edges(
|
|
9750
|
+
self,
|
|
9751
|
+
int num=1,
|
|
9752
|
+
int max_dimension = 0,
|
|
9753
|
+
bool progress=False,
|
|
9754
|
+
bool strong=True,
|
|
9755
|
+
bool full=False,
|
|
9756
|
+
bool ignore_warning=False,
|
|
9757
|
+
bool auto_clean=True,
|
|
9758
|
+
)->SimplexTreeMulti_Ff64:
|
|
9387
9759
|
"""Edge collapse for 1-critical 2-parameter clique complex (see https://arxiv.org/abs/2211.05574).
|
|
9388
9760
|
It uses the code from the github repository https://github.com/aj-alonso/filtration_domination .
|
|
9389
9761
|
|
|
@@ -9433,6 +9805,8 @@ cdef class SimplexTreeMulti_Ff64:
|
|
|
9433
9805
|
edges = _collapse_edge_list(edges, num=num, full=full, strong=strong, progress=progress)
|
|
9434
9806
|
# Retrieves the collapsed simplicial complex
|
|
9435
9807
|
self._reconstruct_from_edge_list(edges, swap=True, expand_dimension=max_dimension)
|
|
9808
|
+
if self.is_squeezed and auto_clean:
|
|
9809
|
+
self._clean_filtration_grid()
|
|
9436
9810
|
return self
|
|
9437
9811
|
|
|
9438
9812
|
@cython.inline
|
|
@@ -9651,11 +10025,26 @@ cdef class SimplexTreeMulti_Ff64:
|
|
|
9651
10025
|
out = self.get_ptr().get_filtration_values(degrees)
|
|
9652
10026
|
filtrations_values = [np.asarray(filtration) for filtration in out]
|
|
9653
10027
|
# Removes infs
|
|
9654
|
-
if inf_to_nan:
|
|
10028
|
+
if inf_to_nan and np.dtype(filtrations_values[0].dtype).kind == 'f':
|
|
9655
10029
|
for i,f in enumerate(filtrations_values):
|
|
9656
10030
|
filtrations_values[i][f == np.inf] = np.nan
|
|
9657
10031
|
filtrations_values[i][f == - np.inf] = np.nan
|
|
9658
10032
|
return filtrations_values
|
|
10033
|
+
def _clean_filtration_grid(self):
|
|
10034
|
+
"""
|
|
10035
|
+
Removes the values in filtration_grid that are not linked to any splx.
|
|
10036
|
+
"""
|
|
10037
|
+
if not self.is_squeezed:
|
|
10038
|
+
raise ValueError("No grid to clean.")
|
|
10039
|
+
F = self.filtration_grid
|
|
10040
|
+
self.filtration_grid=None
|
|
10041
|
+
cleaned_coordinates = compute_grid(self)
|
|
10042
|
+
new_st = self.grid_squeeze(cleaned_coordinates)
|
|
10043
|
+
|
|
10044
|
+
self.thisptr, new_st.thisptr = new_st.thisptr, self.thisptr
|
|
10045
|
+
self.filtration_grid = tuple(f[g] for f,g in zip(F,cleaned_coordinates))
|
|
10046
|
+
return self
|
|
10047
|
+
|
|
9659
10048
|
|
|
9660
10049
|
|
|
9661
10050
|
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]:
|
|
@@ -9691,8 +10080,16 @@ cdef class SimplexTreeMulti_Ff64:
|
|
|
9691
10080
|
return compute_grid(filtrations_values, resolution=resolution,strategy=grid_strategy,drop_quantiles=drop_quantiles)
|
|
9692
10081
|
|
|
9693
10082
|
|
|
9694
|
-
|
|
9695
|
-
|
|
10083
|
+
def grid_squeeze(
|
|
10084
|
+
self,
|
|
10085
|
+
filtration_grid:np.ndarray|list|None=None,
|
|
10086
|
+
bool coordinate_values=True,
|
|
10087
|
+
bool force=False,
|
|
10088
|
+
str strategy:_available_strategies = "exact",
|
|
10089
|
+
grid_strategy=None,
|
|
10090
|
+
bool inplace=False,
|
|
10091
|
+
**filtration_grid_kwargs
|
|
10092
|
+
)->SimplexTreeMulti_Fi32 | SimplexTreeMulti_Ff64:
|
|
9696
10093
|
"""
|
|
9697
10094
|
Fit the filtration of the simplextree to a grid.
|
|
9698
10095
|
|
|
@@ -9703,26 +10100,50 @@ cdef class SimplexTreeMulti_Ff64:
|
|
|
9703
10100
|
"""
|
|
9704
10101
|
if not force and self.is_squeezed:
|
|
9705
10102
|
raise Exception("SimplexTree already squeezed, use `force=True` if that's really what you want to do.")
|
|
10103
|
+
|
|
10104
|
+
if grid_strategy is not None:
|
|
10105
|
+
warn("`grid_strategy` is deprecated, use `strategy` instead.",DeprecationWarning)
|
|
10106
|
+
strategy=grid_strategy
|
|
10107
|
+
|
|
10108
|
+
if self.is_squeezed:
|
|
10109
|
+
warn("(copy warning) Squeezing an already squeezed slicer.")
|
|
10110
|
+
temp = self.unsqueeze()
|
|
10111
|
+
subgrid = compute_grid(self.filtration_grid, strategy=strategy, resolution=resolution)
|
|
10112
|
+
return temp.grid_squeeze(subgrid, coordinates=coordinates, inplace=inplace)
|
|
10113
|
+
|
|
9706
10114
|
#TODO : multi-critical
|
|
9707
10115
|
if filtration_grid is None:
|
|
9708
|
-
filtration_grid = self.get_filtration_grid(grid_strategy=
|
|
9709
|
-
|
|
9710
|
-
|
|
9711
|
-
|
|
10116
|
+
filtration_grid = self.get_filtration_grid(grid_strategy=strategy, **filtration_grid_kwargs)
|
|
10117
|
+
else:
|
|
10118
|
+
filtration_grid = sanitize_grid(filtration_grid)
|
|
10119
|
+
if len(filtration_grid) != self.num_parameters:
|
|
10120
|
+
raise ValueError(f"Invalid grid to squeeze onto. Got {len(filtration_grid)=} != {self.num_parameters=}.")
|
|
10121
|
+
api = api_from_tensor(filtration_grid[0])
|
|
10122
|
+
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
|
|
9712
10123
|
if coordinate_values and inplace:
|
|
9713
|
-
self.filtration_grid =
|
|
10124
|
+
self.filtration_grid = filtration_grid
|
|
9714
10125
|
if inplace or not coordinate_values:
|
|
9715
10126
|
self.get_ptr().squeeze_filtration_inplace(c_filtration_grid, coordinate_values)
|
|
9716
10127
|
else:
|
|
9717
10128
|
out = SimplexTreeMulti_Fi32(num_parameters=self.num_parameters)
|
|
9718
10129
|
self.get_ptr().squeeze_filtration(out.thisptr, c_filtration_grid)
|
|
9719
|
-
out.filtration_grid =
|
|
10130
|
+
out.filtration_grid = filtration_grid
|
|
9720
10131
|
return out
|
|
9721
10132
|
return self
|
|
9722
10133
|
|
|
10134
|
+
def unsqueeze(self, grid=None)->SimplexTreeMulti_Ff64:
|
|
10135
|
+
from multipers.grids import sanitize_grid
|
|
10136
|
+
grid = self.filtration_grid if grid is None else grid
|
|
10137
|
+
|
|
10138
|
+
cdef vector[vector[double]] cgrid = sanitize_grid(grid, numpyfy=True)
|
|
10139
|
+
new_slicer = SimplexTreeMulti_Ff64()
|
|
10140
|
+
new_slicer.get_ptr().unsqueeze_filtration(self.thisptr, cgrid)
|
|
10141
|
+
|
|
10142
|
+
return new_slicer
|
|
10143
|
+
|
|
9723
10144
|
@property
|
|
9724
10145
|
def is_squeezed(self)->bool:
|
|
9725
|
-
return self.num_vertices > 0 and len(self.filtration_grid)>0 and len(self.filtration_grid[0]) > 0
|
|
10146
|
+
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
|
|
9726
10147
|
|
|
9727
10148
|
@property
|
|
9728
10149
|
def dtype(self)->type:
|
|
@@ -10243,7 +10664,8 @@ def _euler_signed_measure(simplextree, mass_default=None, bool verbose=False):
|
|
|
10243
10664
|
`[signed_measure_of_degree for degree in degrees]`
|
|
10244
10665
|
with `signed_measure_of_degree` of the form `(dirac location, dirac weights)`.
|
|
10245
10666
|
"""
|
|
10246
|
-
|
|
10667
|
+
if not simplextree.is_squeezed:
|
|
10668
|
+
raise ValueError("Squeeze grid first.")
|
|
10247
10669
|
cdef bool zero_pad = mass_default is not None
|
|
10248
10670
|
# assert simplextree.num_parameters == 2
|
|
10249
10671
|
grid_shape = np.array([len(f) for f in simplextree.filtration_grid])
|
|
@@ -10361,9 +10783,9 @@ def _rank_signed_measure(simplextree, vector[indices_type] degrees, mass_default
|
|
|
10361
10783
|
else:
|
|
10362
10784
|
mass_default = np.asarray(mass_default)
|
|
10363
10785
|
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,)"
|
|
10364
|
-
if zero_pad:
|
|
10365
|
-
|
|
10366
|
-
|
|
10786
|
+
# if zero_pad:
|
|
10787
|
+
# for i, _ in enumerate(grid_shape):
|
|
10788
|
+
# grid_shape[i] += 1 # adds a 0
|
|
10367
10789
|
# grid_conversion = tuple(np.concatenate([f, [mass_default[i]]]) for i,f in enumerate(grid_conversion))
|
|
10368
10790
|
|
|
10369
10791
|
assert len(grid_shape) == simplextree.num_parameters, "Grid shape size has to be the number of parameters."
|