multipers 2.3.0__cp310-cp310-win_amd64.whl → 2.3.2__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 +4 -4
- 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 +27 -8
- 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 +632 -146
- multipers/simplex_tree_multi.pyx.tp +92 -24
- multipers/slicer.cp310-win_amd64.pyd +0 -0
- multipers/slicer.pxd +779 -177
- multipers/slicer.pxd.tp +24 -5
- multipers/slicer.pyx +5657 -1427
- multipers/slicer.pyx.tp +211 -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.2.dist-info}/METADATA +4 -25
- {multipers-2.3.0.dist-info → multipers-2.3.2.dist-info}/RECORD +54 -51
- {multipers-2.3.0.dist-info → multipers-2.3.2.dist-info}/WHEEL +1 -1
- {multipers-2.3.0.dist-info → multipers-2.3.2.dist-info/licenses}/LICENSE +0 -0
- {multipers-2.3.0.dist-info → multipers-2.3.2.dist-info}/top_level.txt +0 -0
|
@@ -66,7 +66,8 @@ cimport cython
|
|
|
66
66
|
from gudhi.simplex_tree import SimplexTree ## Small hack for typing
|
|
67
67
|
from typing import Iterable,Literal,Optional
|
|
68
68
|
from tqdm import tqdm
|
|
69
|
-
from multipers.grids import Lstrategies, compute_grid
|
|
69
|
+
from multipers.grids import Lstrategies, compute_grid, sanitize_grid
|
|
70
|
+
from multipers.array_api import api_from_tensor
|
|
70
71
|
from multipers.point_measure import signed_betti, rank_decomposition_by_rectangles, sparsify
|
|
71
72
|
|
|
72
73
|
from warnings import warn
|
|
@@ -98,15 +99,15 @@ cdef class SimplexTreeMulti_{{FSHORT}}:
|
|
|
98
99
|
"""
|
|
99
100
|
cdef public intptr_t thisptr
|
|
100
101
|
|
|
101
|
-
cdef public
|
|
102
|
-
cdef public bool _is_function_simplextree
|
|
102
|
+
cdef public object filtration_grid
|
|
103
|
+
cdef public bool _is_function_simplextree # TODO : deprecate
|
|
103
104
|
# Get the pointer casted as it should be
|
|
104
105
|
cdef Simplex_tree_multi_interface[{{FSHORT}}, {{CTYPE}}]* get_ptr(self) noexcept nogil:
|
|
105
106
|
return <Simplex_tree_multi_interface[{{FSHORT}}, {{CTYPE}}]*>(self.thisptr)
|
|
106
107
|
|
|
107
108
|
# cdef Simplex_tree_persistence_interface * pcohptr
|
|
108
109
|
# Fake constructor that does nothing but documenting the constructor
|
|
109
|
-
def __init__(self, other = None, num_parameters:int
|
|
110
|
+
def __init__(self, other = None, num_parameters:int=-1,default_values=[], safe_conversion=False):
|
|
110
111
|
"""SimplexTreeMulti constructor.
|
|
111
112
|
|
|
112
113
|
:param other: If `other` is `None` (default value), an empty `SimplexTreeMulti` is created.
|
|
@@ -139,7 +140,7 @@ cdef class SimplexTreeMulti_{{FSHORT}}:
|
|
|
139
140
|
def is_kcritical(self)->bool:
|
|
140
141
|
return {{is_kcritical}}
|
|
141
142
|
# The real cython constructor
|
|
142
|
-
def __cinit__(self, other = None, int num_parameters
|
|
143
|
+
def __cinit__(self, other = None, int num_parameters=-1,
|
|
143
144
|
default_values=np.asarray([SimplexTreeMulti_{{FSHORT}}.T_minus_inf()]), # I'm not sure why `[]` does not work. Cython bug ?
|
|
144
145
|
bool safe_conversion=False,
|
|
145
146
|
): #TODO doc
|
|
@@ -156,10 +157,13 @@ cdef class SimplexTreeMulti_{{FSHORT}}:
|
|
|
156
157
|
if isinstance(other, SimplexTreeMulti_{{FSHORT}}):
|
|
157
158
|
other_ptr = other.thisptr
|
|
158
159
|
self.thisptr = <intptr_t>(new Simplex_tree_multi_interface[{{FSHORT}}, {{CTYPE}}](dereference(<Simplex_tree_multi_interface[{{FSHORT}}, {{CTYPE}}]*>other_ptr))) ## prevents calling destructor of other
|
|
159
|
-
num_parameters
|
|
160
|
+
if num_parameters <=0:
|
|
161
|
+
num_parameters = other.num_parameters
|
|
160
162
|
self.filtration_grid = other.filtration_grid
|
|
161
163
|
elif isinstance(other, SimplexTree): # Constructs a SimplexTreeMulti from a SimplexTree
|
|
162
164
|
self.thisptr = <intptr_t>(new Simplex_tree_multi_interface[{{FSHORT}}, {{CTYPE}}]())
|
|
165
|
+
if num_parameters <= 0:
|
|
166
|
+
num_parameters = 1
|
|
163
167
|
if safe_conversion or SAFE_CONVERSION:
|
|
164
168
|
new_st_multi = _safe_simplextree_multify_{{FSHORT}}(other, num_parameters = num_parameters, default_values=np.asarray(default_values))
|
|
165
169
|
self.thisptr, new_st_multi.thisptr = new_st_multi.thisptr, self.thisptr
|
|
@@ -174,10 +178,12 @@ cdef class SimplexTreeMulti_{{FSHORT}}:
|
|
|
174
178
|
else:
|
|
175
179
|
raise TypeError("`other` argument requires to be of type `SimplexTree`, `SimplexTreeMulti`, or `None`.")
|
|
176
180
|
else:
|
|
181
|
+
if num_parameters <=0:
|
|
182
|
+
num_parameters = 2 # I don't know how dangerous this is, but this is mostly used.
|
|
177
183
|
self.thisptr = <intptr_t>(new Simplex_tree_multi_interface[{{FSHORT}}, {{CTYPE}}]())
|
|
178
|
-
self.
|
|
184
|
+
self.set_num_parameter(num_parameters)
|
|
179
185
|
self._is_function_simplextree = False
|
|
180
|
-
self.filtration_grid=[
|
|
186
|
+
self.filtration_grid=[]
|
|
181
187
|
|
|
182
188
|
def __dealloc__(self):
|
|
183
189
|
cdef Simplex_tree_multi_interface[{{FSHORT}},{{CTYPE}}]* ptr = self.get_ptr()
|
|
@@ -187,6 +193,9 @@ cdef class SimplexTreeMulti_{{FSHORT}}:
|
|
|
187
193
|
|
|
188
194
|
def __repr__(self):
|
|
189
195
|
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}]"
|
|
196
|
+
def __len__(self):
|
|
197
|
+
return self.num_simplices
|
|
198
|
+
|
|
190
199
|
def __getstate__(self):
|
|
191
200
|
""":returns: Serialized (or flattened) SimplexTree data structure in order to pickle SimplexTree.
|
|
192
201
|
:rtype: numpy.array of shape (n,)
|
|
@@ -963,7 +972,16 @@ cdef class SimplexTreeMulti_{{FSHORT}}:
|
|
|
963
972
|
out = self.get_ptr().get_edge_list()
|
|
964
973
|
return out
|
|
965
974
|
|
|
966
|
-
def collapse_edges(
|
|
975
|
+
def collapse_edges(
|
|
976
|
+
self,
|
|
977
|
+
int num=1,
|
|
978
|
+
int max_dimension = 0,
|
|
979
|
+
bool progress=False,
|
|
980
|
+
bool strong=True,
|
|
981
|
+
bool full=False,
|
|
982
|
+
bool ignore_warning=False,
|
|
983
|
+
bool auto_clean=True,
|
|
984
|
+
)->SimplexTreeMulti_{{FSHORT}}:
|
|
967
985
|
"""Edge collapse for 1-critical 2-parameter clique complex (see https://arxiv.org/abs/2211.05574).
|
|
968
986
|
It uses the code from the github repository https://github.com/aj-alonso/filtration_domination .
|
|
969
987
|
|
|
@@ -1013,6 +1031,8 @@ cdef class SimplexTreeMulti_{{FSHORT}}:
|
|
|
1013
1031
|
edges = _collapse_edge_list(edges, num=num, full=full, strong=strong, progress=progress)
|
|
1014
1032
|
# Retrieves the collapsed simplicial complex
|
|
1015
1033
|
self._reconstruct_from_edge_list(edges, swap=True, expand_dimension=max_dimension)
|
|
1034
|
+
if self.is_squeezed and auto_clean:
|
|
1035
|
+
self._clean_filtration_grid()
|
|
1016
1036
|
return self
|
|
1017
1037
|
|
|
1018
1038
|
@cython.inline
|
|
@@ -1249,11 +1269,26 @@ cdef class SimplexTreeMulti_{{FSHORT}}:
|
|
|
1249
1269
|
out = self.get_ptr().get_filtration_values(degrees)
|
|
1250
1270
|
filtrations_values = [np.asarray(filtration) for filtration in out]
|
|
1251
1271
|
# Removes infs
|
|
1252
|
-
if inf_to_nan:
|
|
1272
|
+
if inf_to_nan and np.dtype(filtrations_values[0].dtype).kind == 'f':
|
|
1253
1273
|
for i,f in enumerate(filtrations_values):
|
|
1254
1274
|
filtrations_values[i][f == np.inf] = np.nan
|
|
1255
1275
|
filtrations_values[i][f == - np.inf] = np.nan
|
|
1256
1276
|
return filtrations_values
|
|
1277
|
+
def _clean_filtration_grid(self):
|
|
1278
|
+
"""
|
|
1279
|
+
Removes the values in filtration_grid that are not linked to any splx.
|
|
1280
|
+
"""
|
|
1281
|
+
if not self.is_squeezed:
|
|
1282
|
+
raise ValueError("No grid to clean.")
|
|
1283
|
+
F = self.filtration_grid
|
|
1284
|
+
self.filtration_grid=None
|
|
1285
|
+
cleaned_coordinates = compute_grid(self)
|
|
1286
|
+
new_st = self.grid_squeeze(cleaned_coordinates)
|
|
1287
|
+
|
|
1288
|
+
self.thisptr, new_st.thisptr = new_st.thisptr, self.thisptr
|
|
1289
|
+
self.filtration_grid = tuple(f[g] for f,g in zip(F,cleaned_coordinates))
|
|
1290
|
+
return self
|
|
1291
|
+
|
|
1257
1292
|
|
|
1258
1293
|
|
|
1259
1294
|
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]:
|
|
@@ -1289,8 +1324,16 @@ cdef class SimplexTreeMulti_{{FSHORT}}:
|
|
|
1289
1324
|
return compute_grid(filtrations_values, resolution=resolution,strategy=grid_strategy,drop_quantiles=drop_quantiles)
|
|
1290
1325
|
|
|
1291
1326
|
|
|
1292
|
-
|
|
1293
|
-
|
|
1327
|
+
def grid_squeeze(
|
|
1328
|
+
self,
|
|
1329
|
+
filtration_grid:np.ndarray|list|None=None,
|
|
1330
|
+
bool coordinate_values=True,
|
|
1331
|
+
bool force=False,
|
|
1332
|
+
str strategy:_available_strategies = "exact",
|
|
1333
|
+
grid_strategy=None,
|
|
1334
|
+
bool inplace=False,
|
|
1335
|
+
**filtration_grid_kwargs
|
|
1336
|
+
)->SimplexTreeMulti_{{FSHORT[:-3] + "i32"}} | SimplexTreeMulti_{{FSHORT}}:
|
|
1294
1337
|
"""
|
|
1295
1338
|
Fit the filtration of the simplextree to a grid.
|
|
1296
1339
|
|
|
@@ -1301,26 +1344,50 @@ cdef class SimplexTreeMulti_{{FSHORT}}:
|
|
|
1301
1344
|
"""
|
|
1302
1345
|
if not force and self.is_squeezed:
|
|
1303
1346
|
raise Exception("SimplexTree already squeezed, use `force=True` if that's really what you want to do.")
|
|
1347
|
+
|
|
1348
|
+
if grid_strategy is not None:
|
|
1349
|
+
warn("`grid_strategy` is deprecated, use `strategy` instead.",DeprecationWarning)
|
|
1350
|
+
strategy=grid_strategy
|
|
1351
|
+
|
|
1352
|
+
if self.is_squeezed:
|
|
1353
|
+
warn("(copy warning) Squeezing an already squeezed slicer.")
|
|
1354
|
+
temp = self.unsqueeze()
|
|
1355
|
+
subgrid = compute_grid(self.filtration_grid, strategy=strategy, resolution=resolution)
|
|
1356
|
+
return temp.grid_squeeze(subgrid, coordinates=coordinates, inplace=inplace)
|
|
1357
|
+
|
|
1304
1358
|
#TODO : multi-critical
|
|
1305
1359
|
if filtration_grid is None:
|
|
1306
|
-
filtration_grid = self.get_filtration_grid(grid_strategy=
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1360
|
+
filtration_grid = self.get_filtration_grid(grid_strategy=strategy, **filtration_grid_kwargs)
|
|
1361
|
+
else:
|
|
1362
|
+
filtration_grid = sanitize_grid(filtration_grid)
|
|
1363
|
+
if len(filtration_grid) != self.num_parameters:
|
|
1364
|
+
raise ValueError(f"Invalid grid to squeeze onto. Got {len(filtration_grid)=} != {self.num_parameters=}.")
|
|
1365
|
+
api = api_from_tensor(filtration_grid[0])
|
|
1366
|
+
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
|
|
1310
1367
|
if coordinate_values and inplace:
|
|
1311
|
-
self.filtration_grid =
|
|
1368
|
+
self.filtration_grid = filtration_grid
|
|
1312
1369
|
if inplace or not coordinate_values:
|
|
1313
1370
|
self.get_ptr().squeeze_filtration_inplace(c_filtration_grid, coordinate_values)
|
|
1314
1371
|
else:
|
|
1315
1372
|
out = SimplexTreeMulti_{{FSHORT[:-3] + "i32"}}(num_parameters=self.num_parameters)
|
|
1316
1373
|
self.get_ptr().squeeze_filtration(out.thisptr, c_filtration_grid)
|
|
1317
|
-
out.filtration_grid =
|
|
1374
|
+
out.filtration_grid = filtration_grid
|
|
1318
1375
|
return out
|
|
1319
1376
|
return self
|
|
1320
1377
|
|
|
1378
|
+
def unsqueeze(self, grid=None)->SimplexTreeMulti_{{FSHORT[:-3] + "f64"}}:
|
|
1379
|
+
from multipers.grids import sanitize_grid
|
|
1380
|
+
grid = self.filtration_grid if grid is None else grid
|
|
1381
|
+
|
|
1382
|
+
cdef vector[vector[double]] cgrid = sanitize_grid(grid, numpyfy=True)
|
|
1383
|
+
new_slicer = SimplexTreeMulti_{{FSHORT[:-3] + "f64"}}()
|
|
1384
|
+
new_slicer.get_ptr().unsqueeze_filtration(self.thisptr, cgrid)
|
|
1385
|
+
|
|
1386
|
+
return new_slicer
|
|
1387
|
+
|
|
1321
1388
|
@property
|
|
1322
1389
|
def is_squeezed(self)->bool:
|
|
1323
|
-
return self.num_vertices > 0 and len(self.filtration_grid)>0 and len(self.filtration_grid[0]) > 0
|
|
1390
|
+
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
|
|
1324
1391
|
|
|
1325
1392
|
@property
|
|
1326
1393
|
def dtype(self)->type:
|
|
@@ -1632,7 +1699,7 @@ def is_simplextree_multi(input)->bool:
|
|
|
1632
1699
|
|
|
1633
1700
|
|
|
1634
1701
|
|
|
1635
|
-
def SimplexTreeMulti(input=None, int num_parameters
|
|
1702
|
+
def SimplexTreeMulti(input=None, int num_parameters=-1, dtype:type = np.float64, bool kcritical = False,**kwargs) -> SimplexTreeMulti_type:
|
|
1636
1703
|
"""SimplexTreeMulti constructor.
|
|
1637
1704
|
|
|
1638
1705
|
:param other: If `other` is `None` (default value), an empty `SimplexTreeMulti` is created.
|
|
@@ -1804,7 +1871,8 @@ def _euler_signed_measure(simplextree, mass_default=None, bool verbose=False):
|
|
|
1804
1871
|
`[signed_measure_of_degree for degree in degrees]`
|
|
1805
1872
|
with `signed_measure_of_degree` of the form `(dirac location, dirac weights)`.
|
|
1806
1873
|
"""
|
|
1807
|
-
|
|
1874
|
+
if not simplextree.is_squeezed:
|
|
1875
|
+
raise ValueError("Squeeze grid first.")
|
|
1808
1876
|
cdef bool zero_pad = mass_default is not None
|
|
1809
1877
|
# assert simplextree.num_parameters == 2
|
|
1810
1878
|
grid_shape = np.array([len(f) for f in simplextree.filtration_grid])
|
|
@@ -1898,9 +1966,9 @@ def _rank_signed_measure(simplextree, vector[indices_type] degrees, mass_default
|
|
|
1898
1966
|
else:
|
|
1899
1967
|
mass_default = np.asarray(mass_default)
|
|
1900
1968
|
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,)"
|
|
1901
|
-
if zero_pad:
|
|
1902
|
-
|
|
1903
|
-
|
|
1969
|
+
# if zero_pad:
|
|
1970
|
+
# for i, _ in enumerate(grid_shape):
|
|
1971
|
+
# grid_shape[i] += 1 # adds a 0
|
|
1904
1972
|
# grid_conversion = tuple(np.concatenate([f, [mass_default[i]]]) for i,f in enumerate(grid_conversion))
|
|
1905
1973
|
|
|
1906
1974
|
assert len(grid_shape) == simplextree.num_parameters, "Grid shape size has to be the number of parameters."
|
|
Binary file
|