multipers 2.3.4__cp311-cp311-win_amd64.whl → 2.3.5b2__cp311-cp311-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 +50 -84
- multipers/array_api/numpy.py +7 -0
- multipers/array_api/torch.py +7 -2
- multipers/filtrations/filtrations.py +2 -0
- multipers/function_rips.cp311-win_amd64.pyd +0 -0
- multipers/grids.cp311-win_amd64.pyd +0 -0
- multipers/grids.pyx +57 -19
- multipers/io.cp311-win_amd64.pyd +0 -0
- multipers/mma_structures.cp311-win_amd64.pyd +0 -0
- multipers/multi_parameter_rank_invariant/function_rips.h +1 -1
- multipers/multiparameter_module_approximation/approximation.h +8 -2
- multipers/multiparameter_module_approximation.cp311-win_amd64.pyd +0 -0
- multipers/plots.py +3 -2
- multipers/point_measure.cp311-win_amd64.pyd +0 -0
- multipers/point_measure.pyx +1 -1
- multipers/simplex_tree_multi.cp311-win_amd64.pyd +0 -0
- multipers/simplex_tree_multi.pyx +88 -56
- multipers/simplex_tree_multi.pyx.tp +23 -7
- multipers/slicer.cp311-win_amd64.pyd +0 -0
- multipers/slicer.pxd +60 -60
- multipers/slicer.pxd.tp +1 -1
- multipers/slicer.pyx +2052 -1137
- multipers/slicer.pyx.tp +100 -43
- multipers/tbb12.dll +0 -0
- multipers/tbbbind_2_5.dll +0 -0
- multipers/tbbmalloc.dll +0 -0
- multipers/tbbmalloc_proxy.dll +0 -0
- {multipers-2.3.4.dist-info → multipers-2.3.5b2.dist-info}/METADATA +1 -1
- {multipers-2.3.4.dist-info → multipers-2.3.5b2.dist-info}/RECORD +32 -32
- {multipers-2.3.4.dist-info → multipers-2.3.5b2.dist-info}/WHEEL +0 -0
- {multipers-2.3.4.dist-info → multipers-2.3.5b2.dist-info}/licenses/LICENSE +0 -0
- {multipers-2.3.4.dist-info → multipers-2.3.5b2.dist-info}/top_level.txt +0 -0
|
@@ -2,6 +2,7 @@ from collections.abc import Iterable, Sequence
|
|
|
2
2
|
from typing import Optional, Union
|
|
3
3
|
|
|
4
4
|
import numpy as np
|
|
5
|
+
import time
|
|
5
6
|
|
|
6
7
|
from multipers.grids import compute_grid, sms_in_grid
|
|
7
8
|
from multipers.plots import plot_signed_measures
|
|
@@ -176,10 +177,12 @@ def signed_measure(
|
|
|
176
177
|
|
|
177
178
|
if not filtered_complex.is_squeezed:
|
|
178
179
|
if verbose:
|
|
179
|
-
print("Coarsening complex...", end="")
|
|
180
|
+
print("Coarsening complex...", end="",flush=True)
|
|
181
|
+
t0 = time.time()
|
|
180
182
|
filtered_complex_ = filtered_complex.grid_squeeze(grid)
|
|
183
|
+
|
|
181
184
|
if verbose:
|
|
182
|
-
print("Done.")
|
|
185
|
+
print(f"Done. ({time.time() - t0:.3f}s)")
|
|
183
186
|
else:
|
|
184
187
|
filtered_complex_ = filtered_complex.copy()
|
|
185
188
|
|
|
@@ -190,26 +193,18 @@ def signed_measure(
|
|
|
190
193
|
else:
|
|
191
194
|
max_degree = np.max(degrees) + 1
|
|
192
195
|
if verbose:
|
|
193
|
-
print(f"Pruning simplicies up to {max_degree}...", end="")
|
|
196
|
+
print(f"Pruning simplicies up to {max_degree}...", end="", flush=True)
|
|
197
|
+
t0 = time.time()
|
|
194
198
|
if filtered_complex_.dimension > max_degree:
|
|
195
199
|
filtered_complex_.prune_above_dimension(max_degree)
|
|
196
200
|
if verbose:
|
|
197
|
-
print("Done.")
|
|
201
|
+
print(f"Done. ({time.time() - t0:.3f}s)")
|
|
198
202
|
|
|
199
203
|
num_parameters = filtered_complex.num_parameters
|
|
200
204
|
assert num_parameters == len(
|
|
201
205
|
grid
|
|
202
206
|
), f"Number of parameter do not coincide. Got (grid) {len(grid)} and (filtered complex) {num_parameters}."
|
|
203
207
|
|
|
204
|
-
# if is_simplextree_multi(filtered_complex_):
|
|
205
|
-
# # if num_collapses != 0:
|
|
206
|
-
# # if verbose:
|
|
207
|
-
# # print("Collapsing edges...", end="")
|
|
208
|
-
# # filtered_complex_.collapse_edges(num_collapses)
|
|
209
|
-
# # if verbose:
|
|
210
|
-
# # print("Done.")
|
|
211
|
-
# # if backend is not None:
|
|
212
|
-
# # filtered_complex_ = mp.Slicer(filtered_complex_, vineyard=vineyard)
|
|
213
208
|
|
|
214
209
|
fix_mass_default = mass_default is not None
|
|
215
210
|
if is_slicer(filtered_complex_):
|
|
@@ -217,59 +212,14 @@ def signed_measure(
|
|
|
217
212
|
print("Input is a slicer.")
|
|
218
213
|
if backend is not None and not filtered_complex_.is_minpres:
|
|
219
214
|
raise ValueError("giving a backend to this function is deprecated")
|
|
220
|
-
# from multipers.slicer import minimal_presentation
|
|
221
|
-
#
|
|
222
|
-
# assert (
|
|
223
|
-
# invariant != "euler"
|
|
224
|
-
# ), "Euler Characteristic cannot be speed up by a backend"
|
|
225
|
-
# # This returns a list of reduced complexes
|
|
226
|
-
# if verbose:
|
|
227
|
-
# print("Reducing complex...", end="")
|
|
228
|
-
# reduced_complex = minimal_presentation(
|
|
229
|
-
# filtered_complex_,
|
|
230
|
-
# degrees=degrees,
|
|
231
|
-
# backend=backend,
|
|
232
|
-
# vineyard=vineyard,
|
|
233
|
-
# verbose=verbose,
|
|
234
|
-
# )
|
|
235
|
-
# if verbose:
|
|
236
|
-
# print("Done.")
|
|
237
|
-
# if invariant is not None and "rank" in invariant:
|
|
238
|
-
# if verbose:
|
|
239
|
-
# print("Computing rank...", end="")
|
|
240
|
-
# sms = [
|
|
241
|
-
# _rank_from_slicer(
|
|
242
|
-
# s,
|
|
243
|
-
# degrees=[d],
|
|
244
|
-
# n_jobs=n_jobs,
|
|
245
|
-
# # grid_shape=tuple(len(g) for g in grid),
|
|
246
|
-
# zero_pad=fix_mass_default,
|
|
247
|
-
# ignore_inf=ignore_infinite_filtration_values,
|
|
248
|
-
# )[0]
|
|
249
|
-
# for s, d in zip(reduced_complex, degrees)
|
|
250
|
-
# ]
|
|
251
|
-
# fix_mass_default = False
|
|
252
|
-
# if verbose:
|
|
253
|
-
# print("Done.")
|
|
254
|
-
# else:
|
|
255
|
-
# if verbose:
|
|
256
|
-
# print("Reduced slicer. Retrieving measure from it...", end="")
|
|
257
|
-
# sms = [
|
|
258
|
-
# _signed_measure_from_slicer(
|
|
259
|
-
# s,
|
|
260
|
-
# shift=(
|
|
261
|
-
# reduced_complex.minpres_degree & 1 if d is None else d & 1
|
|
262
|
-
# ),
|
|
263
|
-
# )[0]
|
|
264
|
-
# for s, d in zip(reduced_complex, degrees)
|
|
265
|
-
# ]
|
|
266
|
-
# if verbose:
|
|
267
|
-
# print("Done.")
|
|
268
215
|
else: # No backend
|
|
269
|
-
if invariant is not None and (
|
|
216
|
+
if invariant is not None and (
|
|
217
|
+
"rank" in invariant or "hook" in invariant or "rectangle" in invariant
|
|
218
|
+
):
|
|
270
219
|
degrees = np.asarray(degrees, dtype=int)
|
|
271
220
|
if verbose:
|
|
272
|
-
print("Computing rank...", end="")
|
|
221
|
+
print("Computing rank...", end="", flush=True)
|
|
222
|
+
t0 = time.time()
|
|
273
223
|
sms = _rank_from_slicer(
|
|
274
224
|
filtered_complex_,
|
|
275
225
|
degrees=degrees,
|
|
@@ -280,10 +230,11 @@ def signed_measure(
|
|
|
280
230
|
)
|
|
281
231
|
fix_mass_default = False
|
|
282
232
|
if verbose:
|
|
283
|
-
print("Done.")
|
|
233
|
+
print(f"Done. ({time.time() - t0:.3f}s)")
|
|
284
234
|
elif filtered_complex_.is_minpres:
|
|
285
235
|
if verbose:
|
|
286
|
-
print("Reduced slicer. Retrieving measure from it...", end="")
|
|
236
|
+
print("Reduced slicer. Retrieving measure from it...", end="",flush=True)
|
|
237
|
+
t0 = time.time()
|
|
287
238
|
sms = [
|
|
288
239
|
_signed_measure_from_slicer(
|
|
289
240
|
filtered_complex_,
|
|
@@ -294,21 +245,23 @@ def signed_measure(
|
|
|
294
245
|
for d in degrees
|
|
295
246
|
]
|
|
296
247
|
if verbose:
|
|
297
|
-
print("Done.")
|
|
248
|
+
print(f"Done. ({time.time() - t0:.3f}s)")
|
|
298
249
|
elif (invariant is None or "euler" in invariant) and (
|
|
299
250
|
len(degrees) == 1 and degrees[0] is None
|
|
300
251
|
):
|
|
301
252
|
if verbose:
|
|
302
|
-
print("Retrieving measure from slicer...", end="")
|
|
253
|
+
print("Retrieving measure from slicer...", end="",flush=True)
|
|
254
|
+
t0 = time.time()
|
|
303
255
|
sms = _signed_measure_from_slicer(
|
|
304
256
|
filtered_complex_,
|
|
305
257
|
shift=0, # no minpres
|
|
306
258
|
)
|
|
307
259
|
if verbose:
|
|
308
|
-
print("Done.")
|
|
260
|
+
print(f"Done. ({time.time() - t0:.3f}s)")
|
|
309
261
|
else:
|
|
310
262
|
if verbose:
|
|
311
|
-
print("Computing Hilbert function...", end="")
|
|
263
|
+
print("Computing Hilbert function...", end="", flush=True)
|
|
264
|
+
t0 = time.time()
|
|
312
265
|
sms = _hilbert_signed_measure(
|
|
313
266
|
filtered_complex_,
|
|
314
267
|
degrees=degrees,
|
|
@@ -319,7 +272,7 @@ def signed_measure(
|
|
|
319
272
|
)
|
|
320
273
|
fix_mass_default = False
|
|
321
274
|
if verbose:
|
|
322
|
-
print("Done.")
|
|
275
|
+
print(f"Done. ({time.time() - t0:.3f}s)")
|
|
323
276
|
|
|
324
277
|
elif is_simplextree_multi(filtered_complex_):
|
|
325
278
|
if verbose:
|
|
@@ -327,7 +280,9 @@ def signed_measure(
|
|
|
327
280
|
## we still have a simplextree here
|
|
328
281
|
if invariant in ["rank_invariant", "rank", "hook", "rectangle"]:
|
|
329
282
|
if verbose:
|
|
330
|
-
print("Computing rank invariant...", end="")
|
|
283
|
+
print("Computing rank invariant...", end="", flush=True)
|
|
284
|
+
t0 = time.time()
|
|
285
|
+
|
|
331
286
|
assert (
|
|
332
287
|
num_parameters == 2
|
|
333
288
|
), "Rank invariant only implemented for 2-parameter modules."
|
|
@@ -342,10 +297,11 @@ def signed_measure(
|
|
|
342
297
|
)
|
|
343
298
|
fix_mass_default = False
|
|
344
299
|
if verbose:
|
|
345
|
-
print("Done.")
|
|
300
|
+
print(f"Done. ({time.time() - t0:.3f}s)")
|
|
346
301
|
elif len(degrees) == 1 and degrees[0] is None:
|
|
347
302
|
if verbose:
|
|
348
|
-
print("Computing Euler Characteristic...", end="")
|
|
303
|
+
print("Computing Euler Characteristic...", end="", flush=True)
|
|
304
|
+
t0 = time.time()
|
|
349
305
|
assert invariant is None or invariant in [
|
|
350
306
|
"euler",
|
|
351
307
|
"euler_characteristic",
|
|
@@ -362,10 +318,11 @@ def signed_measure(
|
|
|
362
318
|
]
|
|
363
319
|
fix_mass_default = False
|
|
364
320
|
if verbose:
|
|
365
|
-
print("Done.")
|
|
321
|
+
print(f"Done. ({time.time() - t0:.3f}s)")
|
|
366
322
|
else:
|
|
367
323
|
if verbose:
|
|
368
|
-
print("Computing Hilbert Function...", end="")
|
|
324
|
+
print("Computing Hilbert Function...", end="", flush=True)
|
|
325
|
+
t0 = time.time()
|
|
369
326
|
assert invariant is None or invariant in [
|
|
370
327
|
"hilbert",
|
|
371
328
|
"hilbert_function",
|
|
@@ -384,19 +341,21 @@ def signed_measure(
|
|
|
384
341
|
)
|
|
385
342
|
fix_mass_default = False
|
|
386
343
|
if verbose:
|
|
387
|
-
print("Done.")
|
|
344
|
+
print(f"Done. ({time.time() - t0:.3f}s)")
|
|
388
345
|
else:
|
|
389
346
|
raise ValueError("Filtered complex has to be a SimplexTree or a Slicer.")
|
|
390
347
|
|
|
391
348
|
if clean:
|
|
392
349
|
if verbose:
|
|
393
|
-
print("Cleaning measure...", end="")
|
|
350
|
+
print("Cleaning measure...", end="",flush=True)
|
|
351
|
+
t0 = time.time()
|
|
394
352
|
sms = clean_sms(sms)
|
|
395
353
|
if verbose:
|
|
396
|
-
print("Done.")
|
|
354
|
+
print(f"Done. ({time.time() - t0:.3f}s)")
|
|
397
355
|
if grid is not None and not coordinate_measure:
|
|
398
356
|
if verbose:
|
|
399
|
-
print("Pushing back the measure to the grid...", end="")
|
|
357
|
+
print("Pushing back the measure to the grid...", end="", flush=True)
|
|
358
|
+
t0 = time.time()
|
|
400
359
|
sms = sms_in_grid(
|
|
401
360
|
sms,
|
|
402
361
|
grid=grid,
|
|
@@ -404,21 +363,28 @@ def signed_measure(
|
|
|
404
363
|
# num_parameters=num_parameters,
|
|
405
364
|
)
|
|
406
365
|
if verbose:
|
|
407
|
-
print("Done.")
|
|
366
|
+
print(f"Done. ({time.time() - t0:.3f}s)")
|
|
408
367
|
|
|
409
368
|
if fix_mass_default:
|
|
410
369
|
# TODO : some methods need to use this, this could be optimized
|
|
411
370
|
if verbose:
|
|
412
|
-
print("Seems that fixing mass default is necessary...", end="")
|
|
371
|
+
print("Seems that fixing mass default is necessary...", end="", flush=True)
|
|
372
|
+
t0 = time.time()
|
|
413
373
|
sms = zero_out_sms(sms, mass_default=mass_default)
|
|
414
374
|
if verbose:
|
|
415
|
-
print("Done.")
|
|
375
|
+
print(f"Done. ({time.time() - t0:.3f}s)")
|
|
416
376
|
|
|
417
377
|
if invariant == "hook":
|
|
378
|
+
if verbose:
|
|
379
|
+
print("Converting rank decomposition to hook decomposition...", end="",flush=True)
|
|
380
|
+
t0 = time.time()
|
|
418
381
|
from multipers.point_measure import rectangle_to_hook_minimal_signed_barcode
|
|
419
|
-
|
|
382
|
+
|
|
383
|
+
sms = [rectangle_to_hook_minimal_signed_barcode(pts, w) for pts, w in sms]
|
|
384
|
+
if verbose:
|
|
385
|
+
print(f"Done. ({time.time() - t0:.3f}s)")
|
|
420
386
|
if plot:
|
|
421
|
-
plot_signed_measures(sms)
|
|
387
|
+
plot_signed_measures(sms, alpha=1 if invariant == "hook" else None)
|
|
422
388
|
return sms
|
|
423
389
|
|
|
424
390
|
|
multipers/array_api/numpy.py
CHANGED
multipers/array_api/torch.py
CHANGED
|
@@ -20,6 +20,9 @@ cartesian_product = _t.cartesian_prod
|
|
|
20
20
|
inf = _t.inf
|
|
21
21
|
searchsorted = _t.searchsorted
|
|
22
22
|
LazyTensor = None
|
|
23
|
+
relu = _t.relu
|
|
24
|
+
abs = _t.abs
|
|
25
|
+
exp = _t.exp
|
|
23
26
|
|
|
24
27
|
|
|
25
28
|
_is_keops_available = None
|
|
@@ -53,6 +56,8 @@ def check_keops():
|
|
|
53
56
|
_is_keops_available = False
|
|
54
57
|
|
|
55
58
|
return _is_keops_available
|
|
59
|
+
|
|
60
|
+
|
|
56
61
|
check_keops()
|
|
57
62
|
|
|
58
63
|
|
|
@@ -101,8 +106,8 @@ def maxvalues(x: _t.Tensor, **kwargs):
|
|
|
101
106
|
return _t.max(x, **kwargs).values
|
|
102
107
|
|
|
103
108
|
|
|
104
|
-
def asnumpy(x):
|
|
105
|
-
return x.detach().numpy()
|
|
109
|
+
def asnumpy(x: _t.Tensor):
|
|
110
|
+
return x.cpu().detach().numpy()
|
|
106
111
|
|
|
107
112
|
|
|
108
113
|
def is_tensor(x):
|
|
@@ -79,6 +79,7 @@ def RipsLowerstar(
|
|
|
79
79
|
filtration_values = [D.ravel(), *[f for f in function.T]]
|
|
80
80
|
grid = compute_grid(filtration_values)
|
|
81
81
|
st = st.grid_squeeze(grid)
|
|
82
|
+
st._clean_filtration_grid()
|
|
82
83
|
return st
|
|
83
84
|
|
|
84
85
|
|
|
@@ -239,6 +240,7 @@ def Cubical(image: ArrayLike, **slicer_kwargs):
|
|
|
239
240
|
).reshape(slice_shape)
|
|
240
241
|
slicer = from_bitmap(coord_img, **slicer_kwargs)
|
|
241
242
|
slicer.filtration_grid = grid
|
|
243
|
+
slicer._clean_filtration_grid()
|
|
242
244
|
return slicer
|
|
243
245
|
|
|
244
246
|
return from_bitmap(image, **slicer_kwargs)
|
|
Binary file
|
|
Binary file
|
multipers/grids.pyx
CHANGED
|
@@ -369,7 +369,7 @@ def _inf_value(array):
|
|
|
369
369
|
return torch.iinfo(dtype).max
|
|
370
370
|
raise ValueError(f"Dtype must be integer or floating like (got {dtype})")
|
|
371
371
|
|
|
372
|
-
def evaluate_in_grid(pts, grid, mass_default=None):
|
|
372
|
+
def evaluate_in_grid(pts, grid, mass_default=None, input_inf_value=None, output_inf_value=None):
|
|
373
373
|
"""
|
|
374
374
|
Input
|
|
375
375
|
-----
|
|
@@ -379,28 +379,21 @@ def evaluate_in_grid(pts, grid, mass_default=None):
|
|
|
379
379
|
assert pts.ndim == 2
|
|
380
380
|
first_filtration = grid[0]
|
|
381
381
|
dtype = first_filtration.dtype
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
else:
|
|
388
|
-
import torch
|
|
389
|
-
# assert isinstance(first_filtration, torch.Tensor), f"Invalid grid type. Got {type(grid[0])}, expected numpy or torch array."
|
|
390
|
-
if mass_default is not None:
|
|
391
|
-
grid = tuple(torch.cat([g, torch.tensor(m)[None]]) for g,m in zip(grid, mass_default))
|
|
392
|
-
def empty_like(x):
|
|
393
|
-
return torch.empty(x.shape,dtype=dtype)
|
|
382
|
+
api = api_from_tensors(*grid)
|
|
383
|
+
if mass_default is not None:
|
|
384
|
+
grid = tuple(api.cat([g, api.astensor(m)[None]]) for g,m in zip(grid, mass_default))
|
|
385
|
+
def empty_like(x):
|
|
386
|
+
return api.empty(x.shape, dtype=dtype)
|
|
394
387
|
|
|
395
388
|
coords=empty_like(pts)
|
|
396
389
|
cdef int dim = coords.shape[1]
|
|
397
|
-
pts_inf = _inf_value(pts)
|
|
398
|
-
coords_inf = _inf_value(coords)
|
|
390
|
+
pts_inf = _inf_value(pts) if input_inf_value is None else input_inf_value
|
|
391
|
+
coords_inf = _inf_value(coords) if output_inf_value is None else output_inf_value
|
|
399
392
|
idx = np.argwhere(pts == pts_inf)
|
|
400
|
-
pts[idx]
|
|
393
|
+
pts[idx[:,0],idx[:,1]] = 0
|
|
401
394
|
for i in range(dim):
|
|
402
395
|
coords[:,i] = grid[i][pts[:,i]]
|
|
403
|
-
coords[idx] = coords_inf
|
|
396
|
+
coords[idx[:,0],idx[:,1]] = coords_inf
|
|
404
397
|
return coords
|
|
405
398
|
|
|
406
399
|
def sm_in_grid(pts, weights, grid, mass_default=None):
|
|
@@ -452,8 +445,9 @@ def sms_in_grid(sms, grid, mass_default=None):
|
|
|
452
445
|
return sms
|
|
453
446
|
|
|
454
447
|
|
|
455
|
-
def _push_pts_to_line(pts, basepoint, direction=None):
|
|
456
|
-
api
|
|
448
|
+
def _push_pts_to_line(pts, basepoint, direction=None, api=None):
|
|
449
|
+
if api is None:
|
|
450
|
+
api = api_from_tensors(pts, basepoint)
|
|
457
451
|
pts = api.astensor(pts)
|
|
458
452
|
basepoint = api.astensor(basepoint)
|
|
459
453
|
num_parameters = basepoint.shape[0]
|
|
@@ -479,3 +473,47 @@ def _push_pts_to_line(pts, basepoint, direction=None):
|
|
|
479
473
|
else:
|
|
480
474
|
xs = xa
|
|
481
475
|
return xs.squeeze()
|
|
476
|
+
|
|
477
|
+
def _push_pts_to_lines(pts, basepoints, directions=None, api=None):
|
|
478
|
+
if api is None:
|
|
479
|
+
api = api_from_tensors(pts,basepoints)
|
|
480
|
+
cdef int num_lines = len(basepoints)
|
|
481
|
+
cdef int num_pts = len(pts)
|
|
482
|
+
|
|
483
|
+
pts = api.astensor(pts)
|
|
484
|
+
basepoints = api.astensor(basepoints)
|
|
485
|
+
if directions is None:
|
|
486
|
+
directions = [None]*num_lines
|
|
487
|
+
else:
|
|
488
|
+
directions = api.astensor(directions)
|
|
489
|
+
|
|
490
|
+
out = api.empty((num_lines, num_pts), dtype=pts.dtype)
|
|
491
|
+
for i in range(num_lines):
|
|
492
|
+
out[i] = _push_pts_to_line(pts, basepoints[i], directions[i], api=api)[None]
|
|
493
|
+
return out
|
|
494
|
+
|
|
495
|
+
|
|
496
|
+
def evaluate_mod_in_grid(mod, grid, box=None):
|
|
497
|
+
"""Given an MMA module, pushes it into the specified grid.
|
|
498
|
+
Useful for e.g., make it differentiable.
|
|
499
|
+
|
|
500
|
+
Input
|
|
501
|
+
-----
|
|
502
|
+
- mod: PyModule
|
|
503
|
+
- grid: Iterable of 1d array, for num_parameters
|
|
504
|
+
Ouput
|
|
505
|
+
-----
|
|
506
|
+
torch-compatible module in the format:
|
|
507
|
+
(num_degrees) x (num_interval of degree) x ((num_birth, num_parameter), (num_death, num_parameters))
|
|
508
|
+
|
|
509
|
+
"""
|
|
510
|
+
(birth_sizes, death_sizes), births, deaths = mod.to_flat_idx(grid)
|
|
511
|
+
births = evaluate_in_grid(births, grid)
|
|
512
|
+
deaths = evaluate_in_grid(deaths, grid)
|
|
513
|
+
diff_mod = tuple(
|
|
514
|
+
zip(
|
|
515
|
+
births.split_with_sizes(birth_sizes.tolist()),
|
|
516
|
+
deaths.split_with_sizes(death_sizes.tolist()),
|
|
517
|
+
)
|
|
518
|
+
)
|
|
519
|
+
return diff_mod
|
multipers/io.cp311-win_amd64.pyd
CHANGED
|
Binary file
|
|
Binary file
|
|
@@ -61,7 +61,7 @@ inline get_degree_filtrations( // also return max_degree,filtration_values
|
|
|
61
61
|
// preprocess
|
|
62
62
|
filtration_lists edge_filtration_of_nodes(st.num_vertices());
|
|
63
63
|
for (auto sh : st.complex_simplex_range()) {
|
|
64
|
-
if (st.dimension() == 0)
|
|
64
|
+
if (st.dimension(sh) == 0)
|
|
65
65
|
continue;
|
|
66
66
|
value_type filtration = st.filtration(sh);
|
|
67
67
|
for (auto node : st.simplex_vertex_range(sh)) {
|
|
@@ -1477,8 +1477,14 @@ std::vector<int> inline to_grid_coord(const Gudhi::multi_filtration::One_critica
|
|
|
1477
1477
|
out[i] = grid[i].size() - 1;
|
|
1478
1478
|
else if (pt[i] <= grid[i][0]) [[unlikely]] {
|
|
1479
1479
|
out[i] = 0;
|
|
1480
|
-
} else
|
|
1481
|
-
|
|
1480
|
+
} else {
|
|
1481
|
+
auto temp = std::distance(grid[i].begin(), std::lower_bound(grid[i].begin(), grid[i].end(), pt[i]));
|
|
1482
|
+
if (std::abs(grid[i][temp] - pt[i]) < std::abs(grid[i][temp - 1] - pt[i])) {
|
|
1483
|
+
out[i] = temp;
|
|
1484
|
+
} else {
|
|
1485
|
+
out[i] = temp - 1;
|
|
1486
|
+
}
|
|
1487
|
+
}
|
|
1482
1488
|
}
|
|
1483
1489
|
return out;
|
|
1484
1490
|
}
|
|
Binary file
|
multipers/plots.py
CHANGED
|
@@ -162,7 +162,7 @@ def plot_signed_measure(signed_measure, threshold=None, ax=None, **plt_kwargs):
|
|
|
162
162
|
)
|
|
163
163
|
|
|
164
164
|
|
|
165
|
-
def plot_signed_measures(signed_measures, threshold=None, size=4):
|
|
165
|
+
def plot_signed_measures(signed_measures, threshold=None, size=4, alpha=None):
|
|
166
166
|
num_degrees = len(signed_measures)
|
|
167
167
|
if num_degrees <= 1:
|
|
168
168
|
axes = [plt.gca()]
|
|
@@ -172,7 +172,8 @@ def plot_signed_measures(signed_measures, threshold=None, size=4):
|
|
|
172
172
|
)
|
|
173
173
|
for ax, signed_measure in zip(axes, signed_measures):
|
|
174
174
|
plot_signed_measure(signed_measure=signed_measure,
|
|
175
|
-
ax=ax, threshold=threshold
|
|
175
|
+
ax=ax, threshold=threshold,
|
|
176
|
+
alpha=alpha)
|
|
176
177
|
plt.tight_layout()
|
|
177
178
|
|
|
178
179
|
|
|
Binary file
|
multipers/point_measure.pyx
CHANGED
|
@@ -366,7 +366,7 @@ def rectangle_to_hook_minimal_signed_barcode(pts,w,):
|
|
|
366
366
|
# print("horizontal:", pts_H)
|
|
367
367
|
|
|
368
368
|
|
|
369
|
-
new_w =
|
|
369
|
+
new_w = np.concatenate([-w, w, w, w_proj,w_V,w_H])
|
|
370
370
|
|
|
371
371
|
pts_b0a1 = api.tensor(pts)
|
|
372
372
|
pts_b0a1[:,3] = pts[:,1]
|
|
Binary file
|