multipers 2.3.5b1__cp311-cp311-win_amd64.whl → 2.3.5b3__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/array_api/numpy.py +9 -0
- multipers/array_api/torch.py +5 -0
- multipers/function_rips.cp311-win_amd64.pyd +0 -0
- multipers/grids.cp311-win_amd64.pyd +0 -0
- multipers/grids.pyx +24 -0
- multipers/io.cp311-win_amd64.pyd +0 -0
- multipers/io.pyx +80 -305
- multipers/mma_structures.cp311-win_amd64.pyd +0 -0
- multipers/multiparameter_module_approximation.cp311-win_amd64.pyd +0 -0
- multipers/plots.py +2 -1
- multipers/point_measure.cp311-win_amd64.pyd +0 -0
- multipers/simplex_tree_multi.cp311-win_amd64.pyd +0 -0
- multipers/slicer.cp311-win_amd64.pyd +0 -0
- multipers/slicer.pyx +69 -109
- multipers/slicer.pyx.tp +18 -19
- {multipers-2.3.5b1.dist-info → multipers-2.3.5b3.dist-info}/METADATA +1 -1
- {multipers-2.3.5b1.dist-info → multipers-2.3.5b3.dist-info}/RECORD +20 -20
- {multipers-2.3.5b1.dist-info → multipers-2.3.5b3.dist-info}/WHEEL +0 -0
- {multipers-2.3.5b1.dist-info → multipers-2.3.5b3.dist-info}/licenses/LICENSE +0 -0
- {multipers-2.3.5b1.dist-info → multipers-2.3.5b3.dist-info}/top_level.txt +0 -0
multipers/array_api/numpy.py
CHANGED
|
@@ -22,6 +22,15 @@ unique = _np.unique
|
|
|
22
22
|
inf = _np.inf
|
|
23
23
|
searchsorted = _np.searchsorted
|
|
24
24
|
LazyTensor = None
|
|
25
|
+
abs = _np.abs
|
|
26
|
+
exp = _np.exp
|
|
27
|
+
sin = _np.sin
|
|
28
|
+
cos = _np.cos
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def relu(x):
|
|
32
|
+
return _np.where(x >= 0, x, 0)
|
|
33
|
+
|
|
25
34
|
|
|
26
35
|
# Test keops
|
|
27
36
|
_is_keops_available = None
|
multipers/array_api/torch.py
CHANGED
|
Binary file
|
|
Binary file
|
multipers/grids.pyx
CHANGED
|
@@ -493,3 +493,27 @@ def _push_pts_to_lines(pts, basepoints, directions=None, api=None):
|
|
|
493
493
|
return out
|
|
494
494
|
|
|
495
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
|
multipers/io.pyx
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import re
|
|
2
|
+
import tempfile
|
|
2
3
|
from gudhi import SimplexTree
|
|
3
4
|
import gudhi as gd
|
|
4
5
|
import numpy as np
|
|
@@ -12,15 +13,13 @@ import threading
|
|
|
12
13
|
import cython
|
|
13
14
|
cimport cython
|
|
14
15
|
|
|
15
|
-
# from multipers.filtration_conversions cimport *
|
|
16
|
-
# from multipers.mma_structures cimport boundary_matrix,float,pair,vector,intptr_t
|
|
17
|
-
# cimport numpy as cnp
|
|
18
16
|
current_doc_url = "https://davidlapous.github.io/multipers/"
|
|
19
17
|
doc_soft_urls = {
|
|
20
18
|
"mpfree":"https://bitbucket.org/mkerber/mpfree/",
|
|
21
19
|
"multi_chunk":"https://bitbucket.org/mkerber/multi_chunk/",
|
|
22
20
|
"function_delaunay":"https://bitbucket.org/mkerber/function_delaunay/",
|
|
23
21
|
"2pac":"https://gitlab.com/flenzen/2pac",
|
|
22
|
+
"rhomboid_tiling":"https://github.com/odinhg/rhomboidtiling_newer_cgal_version",
|
|
24
23
|
}
|
|
25
24
|
doc_soft_easy_install = {
|
|
26
25
|
"mpfree":f"""
|
|
@@ -65,6 +64,11 @@ make
|
|
|
65
64
|
cp 2pac $CONDA_PREFIX/bin
|
|
66
65
|
```
|
|
67
66
|
""",
|
|
67
|
+
"rhomboid_tiling":f"""
|
|
68
|
+
git clone {doc_soft_urls["rhomboid_tiling"]} rhomboid_tiling
|
|
69
|
+
sh build.sh
|
|
70
|
+
cp orderk $CONDA_PREFIX/bin/rhomboid_tiling
|
|
71
|
+
"""
|
|
68
72
|
}
|
|
69
73
|
doc_soft_urls = defaultdict(lambda:"<Unknown url>", doc_soft_urls)
|
|
70
74
|
doc_soft_easy_install = defaultdict(lambda:"<Unknown>", doc_soft_easy_install)
|
|
@@ -98,24 +102,6 @@ cdef dict[str,str|None] pathes = {
|
|
|
98
102
|
"multi_chunk":None,
|
|
99
103
|
}
|
|
100
104
|
|
|
101
|
-
# mpfree_in_path:str|os.PathLike = "multipers_mpfree_input.scc"
|
|
102
|
-
# mpfree_out_path:str|os.PathLike = "multipers_mpfree_output.scc"
|
|
103
|
-
# twopac_in_path:str|os.PathLike = "multipers_twopac_input.scc"
|
|
104
|
-
# twopac_out_path:str|os.PathLike = "multipers_twopac_output.scc"
|
|
105
|
-
# multi_chunk_in_path:str|os.PathLike = "multipers_multi_chunk_input.scc"
|
|
106
|
-
# multi_chunk_out_path:str|os.PathLike = "multipers_multi_chunk_output.scc"
|
|
107
|
-
# function_delaunay_out_path:str|os.PathLike = "function_delaunay_output.scc"
|
|
108
|
-
# function_delaunay_in_path:str|os.PathLike = "function_delaunay_input.txt" # point cloud
|
|
109
|
-
input_path:str|os.PathLike = "multipers_input.scc"
|
|
110
|
-
output_path:str|os.PathLike = "multipers_output.scc"
|
|
111
|
-
|
|
112
|
-
def _put_temp_files_to_ram():
|
|
113
|
-
global input_path,output_path
|
|
114
|
-
shm_memory = "/tmp/" # on unix, we can write in RAM instead of disk.
|
|
115
|
-
if os.access(shm_memory, os.W_OK) and not input_path.startswith(shm_memory):
|
|
116
|
-
input_path = shm_memory + input_path
|
|
117
|
-
output_path = shm_memory + output_path
|
|
118
|
-
_put_temp_files_to_ram()
|
|
119
105
|
|
|
120
106
|
|
|
121
107
|
## TODO : optimize with Python.h ?
|
|
@@ -147,69 +133,6 @@ def scc_parser(path: str| os.PathLike):
|
|
|
147
133
|
return blocks
|
|
148
134
|
|
|
149
135
|
|
|
150
|
-
def scc_parser__old(path: str):
|
|
151
|
-
"""
|
|
152
|
-
Parse an scc file into the scc python format, aka blocks.
|
|
153
|
-
"""
|
|
154
|
-
with open(path, "r") as f:
|
|
155
|
-
lines = f.readlines()
|
|
156
|
-
# Find scc2020
|
|
157
|
-
while lines[0].strip() != "scc2020":
|
|
158
|
-
lines = lines[1:]
|
|
159
|
-
lines = lines[1:]
|
|
160
|
-
# stripped scc2020 we can start
|
|
161
|
-
|
|
162
|
-
def pass_line(line):
|
|
163
|
-
return re.match(r"^\s*$|^#", line) is not None
|
|
164
|
-
|
|
165
|
-
for i, line in enumerate(lines):
|
|
166
|
-
line = line.strip()
|
|
167
|
-
if pass_line(line):
|
|
168
|
-
continue
|
|
169
|
-
num_parameters = int(line)
|
|
170
|
-
lines = lines[i + 1 :]
|
|
171
|
-
break
|
|
172
|
-
|
|
173
|
-
block_sizes = []
|
|
174
|
-
|
|
175
|
-
for i, line in enumerate(lines):
|
|
176
|
-
line = line.strip()
|
|
177
|
-
if pass_line(line):
|
|
178
|
-
continue
|
|
179
|
-
block_sizes = tuple(int(i) for i in line.split(" "))
|
|
180
|
-
lines = lines[i + 1 :]
|
|
181
|
-
break
|
|
182
|
-
blocks = []
|
|
183
|
-
cdef int counter
|
|
184
|
-
for block_size in block_sizes:
|
|
185
|
-
counter = block_size
|
|
186
|
-
block_filtrations = []
|
|
187
|
-
block_boundaries = []
|
|
188
|
-
for i, line in enumerate(lines):
|
|
189
|
-
if counter == 0:
|
|
190
|
-
lines = lines[i:]
|
|
191
|
-
break
|
|
192
|
-
line = line.strip()
|
|
193
|
-
if pass_line(line):
|
|
194
|
-
continue
|
|
195
|
-
splitted_line = re.match(r"^(?P<floats>[^;]+);(?P<ints>[^;]*)$", line)
|
|
196
|
-
filtrations = np.asarray(splitted_line.group("floats").split(), dtype=float)
|
|
197
|
-
boundary = np.asarray(splitted_line.group("ints").split(), dtype=int)
|
|
198
|
-
block_filtrations.append(filtrations)
|
|
199
|
-
block_boundaries.append(boundary)
|
|
200
|
-
# filtration_boundary = line.split(";")
|
|
201
|
-
# if len(filtration_boundary) == 1:
|
|
202
|
-
# # happens when last generators do not have a ";" in the end
|
|
203
|
-
# filtration_boundary.append(" ")
|
|
204
|
-
# filtration, boundary = filtration_boundary
|
|
205
|
-
# block_filtrations.append(
|
|
206
|
-
# tuple(float(x) for x in filtration.split(" ") if len(x) > 0)
|
|
207
|
-
# )
|
|
208
|
-
# block_boundaries.append(tuple(int(x) for x in boundary.split(" ") if len(x) > 0))
|
|
209
|
-
counter -= 1
|
|
210
|
-
blocks.append((np.asarray(block_filtrations, dtype=float), tuple(block_boundaries)))
|
|
211
|
-
|
|
212
|
-
return blocks
|
|
213
136
|
|
|
214
137
|
|
|
215
138
|
def _init_external_softwares(requires=[]):
|
|
@@ -221,7 +144,6 @@ def _init_external_softwares(requires=[]):
|
|
|
221
144
|
any = any or (soft in requires)
|
|
222
145
|
|
|
223
146
|
if any:
|
|
224
|
-
_put_temp_files_to_ram()
|
|
225
147
|
for soft in requires:
|
|
226
148
|
if pathes[soft] is None:
|
|
227
149
|
global doc_soft_urls
|
|
@@ -239,69 +161,6 @@ def _check_available(soft:str):
|
|
|
239
161
|
return pathes.get(soft,None) is not None
|
|
240
162
|
|
|
241
163
|
|
|
242
|
-
def scc_reduce_from_str(
|
|
243
|
-
path:str|os.PathLike,
|
|
244
|
-
bool full_resolution=True,
|
|
245
|
-
int dimension: int | np.int64 = 1,
|
|
246
|
-
bool clear: bool = True,
|
|
247
|
-
id: Optional[str] = None, # For parallel stuff
|
|
248
|
-
bool verbose:bool=False,
|
|
249
|
-
backend:Literal["mpfree","multi_chunk","twopac"]="mpfree"
|
|
250
|
-
):
|
|
251
|
-
"""
|
|
252
|
-
Computes a minimal presentation of the file in path,
|
|
253
|
-
using mpfree.
|
|
254
|
-
|
|
255
|
-
path:PathLike
|
|
256
|
-
full_resolution: bool
|
|
257
|
-
dimension: int, presentation dimension to consider
|
|
258
|
-
clear: bool, removes temporary files if True
|
|
259
|
-
id: str, temporary files are of this id, allowing for multiprocessing
|
|
260
|
-
verbose: bool
|
|
261
|
-
backend: "mpfree", "multi_chunk" or "2pac"
|
|
262
|
-
"""
|
|
263
|
-
global pathes, input_path, output_path
|
|
264
|
-
_init_external_softwares(requires=[backend])
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
resolution_str = "--resolution" if full_resolution else ""
|
|
268
|
-
# print(mpfree_in_path + id, mpfree_out_path + id)
|
|
269
|
-
if id is None:
|
|
270
|
-
id = str(threading.get_native_id())
|
|
271
|
-
if not os.path.exists(path):
|
|
272
|
-
raise ValueError(f"No file found at {path}.")
|
|
273
|
-
if os.path.exists(output_path + id):
|
|
274
|
-
os.remove(output_path + id)
|
|
275
|
-
verbose_arg = "> /dev/null 2>&1" if not verbose else ""
|
|
276
|
-
if backend == "mpfree":
|
|
277
|
-
more_verbose = "-v" if verbose else ""
|
|
278
|
-
command = (
|
|
279
|
-
f"{pathes[backend]} {more_verbose} {resolution_str} --dim={dimension} {path} {output_path+id} {verbose_arg}"
|
|
280
|
-
)
|
|
281
|
-
elif backend == "multi_chunk":
|
|
282
|
-
command = (
|
|
283
|
-
f"{pathes[backend]} {path} {output_path+id} {verbose_arg}"
|
|
284
|
-
)
|
|
285
|
-
elif backend in ["twopac", "2pac"]:
|
|
286
|
-
command = (
|
|
287
|
-
f"{pathes[backend]} -f {path} --scc-input -n{dimension} --save-resolution-scc {output_path+id} {verbose_arg}"
|
|
288
|
-
)
|
|
289
|
-
else:
|
|
290
|
-
raise ValueError(f"Unsupported backend {backend}.")
|
|
291
|
-
if verbose:
|
|
292
|
-
print(f"Calling :\n\n {command}")
|
|
293
|
-
os.system(command)
|
|
294
|
-
|
|
295
|
-
blocks = scc_parser(output_path + id)
|
|
296
|
-
if clear:
|
|
297
|
-
clear_io(input_path+id, output_path + id)
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
## mpfree workaround: last size is 0 but shouldn't...
|
|
301
|
-
if len(blocks) and not len(blocks[-1][1]):
|
|
302
|
-
blocks=blocks[:-1]
|
|
303
|
-
|
|
304
|
-
return blocks
|
|
305
164
|
|
|
306
165
|
def scc_reduce_from_str_to_slicer(
|
|
307
166
|
path:str|os.PathLike,
|
|
@@ -309,7 +168,6 @@ def scc_reduce_from_str_to_slicer(
|
|
|
309
168
|
bool full_resolution=True,
|
|
310
169
|
int dimension: int | np.int64 = 1,
|
|
311
170
|
bool clear: bool = True,
|
|
312
|
-
id: Optional[str] = None, # For parallel stuff
|
|
313
171
|
bool verbose:bool=False,
|
|
314
172
|
backend:Literal["mpfree","multi_chunk","twopac"]="mpfree",
|
|
315
173
|
shift_dimension=0
|
|
@@ -327,115 +185,56 @@ def scc_reduce_from_str_to_slicer(
|
|
|
327
185
|
verbose: bool
|
|
328
186
|
backend: "mpfree", "multi_chunk" or "2pac"
|
|
329
187
|
"""
|
|
330
|
-
global pathes
|
|
188
|
+
global pathes
|
|
331
189
|
_init_external_softwares(requires=[backend])
|
|
332
190
|
|
|
191
|
+
with tempfile.TemporaryDirectory(prefix="multipers", delete=clear) as tmpdir:
|
|
192
|
+
output_path = os.path.join(tmpdir, "multipers_output.scc")
|
|
193
|
+
|
|
194
|
+
resolution_str = "--resolution" if full_resolution else ""
|
|
195
|
+
|
|
196
|
+
if not os.path.exists(path):
|
|
197
|
+
raise ValueError(f"No file found at {path}.")
|
|
198
|
+
|
|
199
|
+
verbose_arg = "> /dev/null 2>&1" if not verbose else ""
|
|
200
|
+
if backend == "mpfree":
|
|
201
|
+
more_verbose = "-v" if verbose else ""
|
|
202
|
+
command = (
|
|
203
|
+
f"{pathes[backend]} {more_verbose} {resolution_str} --dim={dimension} {path} {output_path} {verbose_arg}"
|
|
204
|
+
)
|
|
205
|
+
elif backend == "multi_chunk":
|
|
206
|
+
command = (
|
|
207
|
+
f"{pathes[backend]} {path} {output_path} {verbose_arg}"
|
|
208
|
+
)
|
|
209
|
+
elif backend in ["twopac", "2pac"]:
|
|
210
|
+
command = (
|
|
211
|
+
f"{pathes[backend]} -f {path} --scc-input -n{dimension} --save-resolution-scc {output_path} {verbose_arg}"
|
|
212
|
+
)
|
|
213
|
+
else:
|
|
214
|
+
raise ValueError(f"Unsupported backend {backend}.")
|
|
215
|
+
if verbose:
|
|
216
|
+
print(f"Calling :\n\n {command}")
|
|
217
|
+
os.system(command)
|
|
333
218
|
|
|
334
|
-
|
|
335
|
-
# print(mpfree_in_path + id, mpfree_out_path + id)
|
|
336
|
-
if id is None:
|
|
337
|
-
id = str(threading.get_native_id())
|
|
338
|
-
if not os.path.exists(path):
|
|
339
|
-
raise ValueError(f"No file found at {path}.")
|
|
340
|
-
if os.path.exists(output_path + id):
|
|
341
|
-
os.remove(output_path + id)
|
|
342
|
-
verbose_arg = "> /dev/null 2>&1" if not verbose else ""
|
|
343
|
-
if backend == "mpfree":
|
|
344
|
-
more_verbose = "-v" if verbose else ""
|
|
345
|
-
command = (
|
|
346
|
-
f"{pathes[backend]} {more_verbose} {resolution_str} --dim={dimension} {path} {output_path+id} {verbose_arg}"
|
|
347
|
-
)
|
|
348
|
-
elif backend == "multi_chunk":
|
|
349
|
-
command = (
|
|
350
|
-
f"{pathes[backend]} {path} {output_path+id} {verbose_arg}"
|
|
351
|
-
)
|
|
352
|
-
elif backend in ["twopac", "2pac"]:
|
|
353
|
-
command = (
|
|
354
|
-
f"{pathes[backend]} -f {path} --scc-input -n{dimension} --save-resolution-scc {output_path+id} {verbose_arg}"
|
|
355
|
-
)
|
|
356
|
-
else:
|
|
357
|
-
raise ValueError(f"Unsupported backend {backend}.")
|
|
358
|
-
if verbose:
|
|
359
|
-
print(f"Calling :\n\n {command}")
|
|
360
|
-
os.system(command)
|
|
361
|
-
|
|
362
|
-
slicer._build_from_scc_file(path=output_path+id, shift_dimension=shift_dimension)
|
|
363
|
-
|
|
364
|
-
if clear:
|
|
365
|
-
clear_io(input_path+id, output_path + id)
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
def reduce_complex(
|
|
369
|
-
complex, # Simplextree, Slicer, or str
|
|
370
|
-
bool full_resolution: bool = True,
|
|
371
|
-
int dimension: int | np.int64 = 1,
|
|
372
|
-
bool clear: bool = True,
|
|
373
|
-
id: Optional[str]=None, # For parallel stuff
|
|
374
|
-
bool verbose:bool=False,
|
|
375
|
-
backend:available_reduce_softs="mpfree"
|
|
376
|
-
):
|
|
377
|
-
"""
|
|
378
|
-
Computes a minimal presentation of the file in path,
|
|
379
|
-
using `backend`.
|
|
380
|
-
|
|
381
|
-
simplextree
|
|
382
|
-
full_resolution: bool
|
|
383
|
-
dimension: int, presentation dimension to consider
|
|
384
|
-
clear: bool, removes temporary files if True
|
|
385
|
-
id: str, temporary files are of this id, allowing for multiprocessing
|
|
386
|
-
verbose: bool
|
|
387
|
-
"""
|
|
388
|
-
|
|
389
|
-
from multipers.simplex_tree_multi import is_simplextree_multi
|
|
390
|
-
from multipers.slicer import slicer2blocks
|
|
391
|
-
if id is None:
|
|
392
|
-
id = str(threading.get_native_id())
|
|
393
|
-
path = input_path+id
|
|
394
|
-
if is_simplextree_multi(complex):
|
|
395
|
-
complex.to_scc(
|
|
396
|
-
path=path,
|
|
397
|
-
rivet_compatible=False,
|
|
398
|
-
strip_comments=False,
|
|
399
|
-
ignore_last_generators=False,
|
|
400
|
-
overwrite=True,
|
|
401
|
-
reverse_block=False,
|
|
402
|
-
)
|
|
403
|
-
dimension = complex.dimension - dimension
|
|
404
|
-
elif isinstance(complex,str):
|
|
405
|
-
path = complex
|
|
406
|
-
elif isinstance(complex, list) or isinstance(complex, tuple):
|
|
407
|
-
scc2disk(complex,path=path)
|
|
408
|
-
else:
|
|
409
|
-
# Assumes its a slicer
|
|
410
|
-
blocks = slicer2blocks(complex)
|
|
411
|
-
scc2disk(blocks,path=path)
|
|
412
|
-
dimension = len(blocks) -2 -dimension
|
|
219
|
+
slicer._build_from_scc_file(path=output_path, shift_dimension=shift_dimension)
|
|
413
220
|
|
|
414
|
-
return scc_reduce_from_str(
|
|
415
|
-
path=path,
|
|
416
|
-
full_resolution=full_resolution,
|
|
417
|
-
dimension=dimension,
|
|
418
|
-
clear=clear,
|
|
419
|
-
id=id,
|
|
420
|
-
verbose=verbose,
|
|
421
|
-
backend=backend
|
|
422
|
-
)
|
|
423
221
|
|
|
424
222
|
|
|
425
223
|
|
|
426
224
|
|
|
427
|
-
def
|
|
225
|
+
def function_delaunay_presentation_to_slicer(
|
|
226
|
+
slicer,
|
|
428
227
|
point_cloud:np.ndarray,
|
|
429
228
|
function_values:np.ndarray,
|
|
430
|
-
id:Optional[str] = None,
|
|
431
229
|
bool clear:bool = True,
|
|
432
230
|
bool verbose:bool=False,
|
|
433
231
|
int degree = -1,
|
|
434
232
|
bool multi_chunk = False,
|
|
435
233
|
):
|
|
436
234
|
"""
|
|
437
|
-
Computes a function delaunay presentation, and returns it as
|
|
235
|
+
Computes a function delaunay presentation, and returns it as a slicer.
|
|
438
236
|
|
|
237
|
+
slicer: empty slicer to fill
|
|
439
238
|
points : (num_pts, n) float array
|
|
440
239
|
grades : (num_pts,) float array
|
|
441
240
|
degree (opt) : if given, computes a minimal presentation of this homological degree first
|
|
@@ -443,85 +242,61 @@ def function_delaunay_presentation(
|
|
|
443
242
|
degree: computes minimal presentation of this degree if given
|
|
444
243
|
verbose : bool
|
|
445
244
|
"""
|
|
446
|
-
|
|
447
|
-
id = str(threading.get_native_id())
|
|
448
|
-
global input_path, output_path, pathes
|
|
449
|
-
backend = "function_delaunay"
|
|
450
|
-
_init_external_softwares(requires=[backend])
|
|
245
|
+
global pathes
|
|
451
246
|
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
degree_arg = f"--minpres {degree}" if degree >= 0 else ""
|
|
456
|
-
multi_chunk_arg = "--multi-chunk" if multi_chunk else ""
|
|
457
|
-
if os.path.exists(output_path + id):
|
|
458
|
-
os.remove(output_path+ id)
|
|
459
|
-
command = f"{pathes[backend]} {degree_arg} {multi_chunk_arg} {input_path+id} {output_path+id} {verbose_arg} --no-delaunay-compare"
|
|
460
|
-
if verbose:
|
|
461
|
-
print(command)
|
|
462
|
-
os.system(command)
|
|
463
|
-
|
|
464
|
-
blocks = scc_parser(output_path + id)
|
|
465
|
-
if clear:
|
|
466
|
-
clear_io(output_path + id, input_path + id)
|
|
467
|
-
## Function Delaunay workaround: last size is 0 but shouldn't...
|
|
468
|
-
if degree<0 and len(blocks) and not len(blocks[-1][1]):
|
|
469
|
-
blocks=blocks[:-1]
|
|
247
|
+
with tempfile.TemporaryDirectory(prefix="multipers", delete=clear) as tmpdir:
|
|
248
|
+
input_path = os.path.join(tmpdir, "multipers_input.scc")
|
|
249
|
+
output_path = os.path.join(tmpdir, "multipers_output.scc")
|
|
470
250
|
|
|
471
|
-
|
|
251
|
+
backend = "function_delaunay"
|
|
252
|
+
_init_external_softwares(requires=[backend])
|
|
472
253
|
|
|
473
|
-
|
|
254
|
+
to_write = np.concatenate([point_cloud, function_values.reshape(-1,1)], axis=1)
|
|
255
|
+
np.savetxt(input_path,to_write,delimiter=' ')
|
|
256
|
+
verbose_arg = "> /dev/null 2>&1" if not verbose else ""
|
|
257
|
+
degree_arg = f"--minpres {degree}" if degree >= 0 else ""
|
|
258
|
+
multi_chunk_arg = "--multi-chunk" if multi_chunk else ""
|
|
259
|
+
command = f"{pathes[backend]} {degree_arg} {multi_chunk_arg} {input_path} {output_path} {verbose_arg} --no-delaunay-compare"
|
|
260
|
+
if verbose:
|
|
261
|
+
print(command)
|
|
262
|
+
os.system(command)
|
|
263
|
+
|
|
264
|
+
slicer._build_from_scc_file(path=output_path, shift_dimension=-1 if degree <= 0 else degree-1 )
|
|
265
|
+
|
|
266
|
+
|
|
267
|
+
def rhomboid_tiling_to_slicer(
|
|
474
268
|
slicer,
|
|
475
269
|
point_cloud:np.ndarray,
|
|
476
|
-
|
|
270
|
+
int k_max,
|
|
271
|
+
int degree = -1,
|
|
272
|
+
bool reduce=True,
|
|
477
273
|
id:Optional[str] = None,
|
|
478
274
|
bool clear:bool = True,
|
|
479
275
|
bool verbose:bool=False,
|
|
480
|
-
int degree = -1,
|
|
481
276
|
bool multi_chunk = False,
|
|
482
277
|
):
|
|
483
|
-
"""
|
|
484
|
-
Computes a function delaunay presentation, and returns it as a slicer.
|
|
485
|
-
|
|
486
|
-
slicer: empty slicer to fill
|
|
487
|
-
points : (num_pts, n) float array
|
|
488
|
-
grades : (num_pts,) float array
|
|
489
|
-
degree (opt) : if given, computes a minimal presentation of this homological degree first
|
|
490
|
-
clear:bool, removes temporary files if true
|
|
491
|
-
degree: computes minimal presentation of this degree if given
|
|
492
|
-
verbose : bool
|
|
493
|
-
"""
|
|
278
|
+
"""TODO"""
|
|
494
279
|
if id is None:
|
|
495
280
|
id = str(threading.get_native_id())
|
|
496
281
|
global input_path, output_path, pathes
|
|
497
|
-
backend = "
|
|
282
|
+
backend = "rhomboid_tiling"
|
|
498
283
|
_init_external_softwares(requires=[backend])
|
|
284
|
+
if point_cloud.ndim != 2 or not point_cloud.shape[1] in [2,3]:
|
|
285
|
+
raise ValueError("point_cloud should be a 2d array of shape (-,2) or (-,3). Got {point_cloud.shape=}")
|
|
286
|
+
with tempfile.TemporaryDirectory(prefix="multipers", delete=clear) as tmpdir:
|
|
287
|
+
input_path = os.path.join(tmpdir, "point_cloud.txt")
|
|
288
|
+
output_path = os.path.join(tmpdir, "multipers_output.scc")
|
|
289
|
+
np.savetxt(input_path,point_cloud,delimiter=' ')
|
|
499
290
|
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
os.
|
|
507
|
-
|
|
508
|
-
if verbose:
|
|
509
|
-
print(command)
|
|
510
|
-
os.system(command)
|
|
291
|
+
verbose_arg = "> /dev/null 2>&1" if not verbose else ""
|
|
292
|
+
degree_arg = f"--minpres {degree}" if degree >= 0 else ""
|
|
293
|
+
multi_chunk_arg = "--multi-chunk" if multi_chunk else ""
|
|
294
|
+
command = f"{pathes[backend]} {input_path} {output_path} {point_cloud.shape[1]} {k_max} scc {degree}"
|
|
295
|
+
if verbose:
|
|
296
|
+
print(command)
|
|
297
|
+
os.system(command)
|
|
298
|
+
slicer._build_from_scc_file(path=output_path+id, shift_dimension=-1 if degree <= 0 else degree-1 )
|
|
511
299
|
|
|
512
|
-
slicer._build_from_scc_file(path=output_path+id, shift_dimension=-1 if degree <= 0 else degree-1 )
|
|
513
|
-
|
|
514
|
-
if clear:
|
|
515
|
-
clear_io(output_path + id, input_path + id)
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
def clear_io(*args):
|
|
520
|
-
"""Removes temporary files"""
|
|
521
|
-
global input_path,output_path
|
|
522
|
-
for x in [input_path,output_path] + list(args):
|
|
523
|
-
if os.path.exists(x):
|
|
524
|
-
os.remove(x)
|
|
525
300
|
|
|
526
301
|
|
|
527
302
|
|
|
@@ -640,5 +415,5 @@ def scc2disk_old(
|
|
|
640
415
|
C = np.char.add(C, ";")
|
|
641
416
|
D = np.fromiter((" ".join(b.astype(str).tolist()) for b in boundary), dtype="<U11") #int32-> str is "<U11" #check np.array(1, dtype=np.int32).astype(str)
|
|
642
417
|
str_blocks.append(np.char.add(C,D))
|
|
643
|
-
|
|
418
|
+
|
|
644
419
|
np.savetxt("test.scc", np.concatenate(str_blocks), delimiter="", fmt="%s")
|
|
Binary file
|
|
Binary file
|
multipers/plots.py
CHANGED
|
Binary file
|
|
Binary file
|
|
Binary file
|