multipers 2.3.3b6__cp311-cp311-manylinux_2_39_x86_64.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.

Files changed (182) hide show
  1. multipers/__init__.py +33 -0
  2. multipers/_signed_measure_meta.py +453 -0
  3. multipers/_slicer_meta.py +211 -0
  4. multipers/array_api/__init__.py +45 -0
  5. multipers/array_api/numpy.py +41 -0
  6. multipers/array_api/torch.py +58 -0
  7. multipers/data/MOL2.py +458 -0
  8. multipers/data/UCR.py +18 -0
  9. multipers/data/__init__.py +1 -0
  10. multipers/data/graphs.py +466 -0
  11. multipers/data/immuno_regions.py +27 -0
  12. multipers/data/minimal_presentation_to_st_bf.py +0 -0
  13. multipers/data/pytorch2simplextree.py +91 -0
  14. multipers/data/shape3d.py +101 -0
  15. multipers/data/synthetic.py +113 -0
  16. multipers/distances.py +202 -0
  17. multipers/filtration_conversions.pxd +229 -0
  18. multipers/filtration_conversions.pxd.tp +84 -0
  19. multipers/filtrations/__init__.py +18 -0
  20. multipers/filtrations/density.py +574 -0
  21. multipers/filtrations/filtrations.py +361 -0
  22. multipers/filtrations.pxd +224 -0
  23. multipers/function_rips.cpython-311-x86_64-linux-gnu.so +0 -0
  24. multipers/function_rips.pyx +105 -0
  25. multipers/grids.cpython-311-x86_64-linux-gnu.so +0 -0
  26. multipers/grids.pyx +433 -0
  27. multipers/gudhi/Persistence_slices_interface.h +132 -0
  28. multipers/gudhi/Simplex_tree_interface.h +239 -0
  29. multipers/gudhi/Simplex_tree_multi_interface.h +551 -0
  30. multipers/gudhi/cubical_to_boundary.h +59 -0
  31. multipers/gudhi/gudhi/Bitmap_cubical_complex.h +450 -0
  32. multipers/gudhi/gudhi/Bitmap_cubical_complex_base.h +1070 -0
  33. multipers/gudhi/gudhi/Bitmap_cubical_complex_periodic_boundary_conditions_base.h +579 -0
  34. multipers/gudhi/gudhi/Debug_utils.h +45 -0
  35. multipers/gudhi/gudhi/Fields/Multi_field.h +484 -0
  36. multipers/gudhi/gudhi/Fields/Multi_field_operators.h +455 -0
  37. multipers/gudhi/gudhi/Fields/Multi_field_shared.h +450 -0
  38. multipers/gudhi/gudhi/Fields/Multi_field_small.h +531 -0
  39. multipers/gudhi/gudhi/Fields/Multi_field_small_operators.h +507 -0
  40. multipers/gudhi/gudhi/Fields/Multi_field_small_shared.h +531 -0
  41. multipers/gudhi/gudhi/Fields/Z2_field.h +355 -0
  42. multipers/gudhi/gudhi/Fields/Z2_field_operators.h +376 -0
  43. multipers/gudhi/gudhi/Fields/Zp_field.h +420 -0
  44. multipers/gudhi/gudhi/Fields/Zp_field_operators.h +400 -0
  45. multipers/gudhi/gudhi/Fields/Zp_field_shared.h +418 -0
  46. multipers/gudhi/gudhi/Flag_complex_edge_collapser.h +337 -0
  47. multipers/gudhi/gudhi/Matrix.h +2107 -0
  48. multipers/gudhi/gudhi/Multi_critical_filtration.h +1038 -0
  49. multipers/gudhi/gudhi/Multi_persistence/Box.h +174 -0
  50. multipers/gudhi/gudhi/Multi_persistence/Line.h +282 -0
  51. multipers/gudhi/gudhi/Off_reader.h +173 -0
  52. multipers/gudhi/gudhi/One_critical_filtration.h +1441 -0
  53. multipers/gudhi/gudhi/Persistence_matrix/Base_matrix.h +769 -0
  54. multipers/gudhi/gudhi/Persistence_matrix/Base_matrix_with_column_compression.h +686 -0
  55. multipers/gudhi/gudhi/Persistence_matrix/Boundary_matrix.h +842 -0
  56. multipers/gudhi/gudhi/Persistence_matrix/Chain_matrix.h +1350 -0
  57. multipers/gudhi/gudhi/Persistence_matrix/Id_to_index_overlay.h +1105 -0
  58. multipers/gudhi/gudhi/Persistence_matrix/Position_to_index_overlay.h +859 -0
  59. multipers/gudhi/gudhi/Persistence_matrix/RU_matrix.h +910 -0
  60. multipers/gudhi/gudhi/Persistence_matrix/allocators/entry_constructors.h +139 -0
  61. multipers/gudhi/gudhi/Persistence_matrix/base_pairing.h +230 -0
  62. multipers/gudhi/gudhi/Persistence_matrix/base_swap.h +211 -0
  63. multipers/gudhi/gudhi/Persistence_matrix/boundary_cell_position_to_id_mapper.h +60 -0
  64. multipers/gudhi/gudhi/Persistence_matrix/boundary_face_position_to_id_mapper.h +60 -0
  65. multipers/gudhi/gudhi/Persistence_matrix/chain_pairing.h +136 -0
  66. multipers/gudhi/gudhi/Persistence_matrix/chain_rep_cycles.h +190 -0
  67. multipers/gudhi/gudhi/Persistence_matrix/chain_vine_swap.h +616 -0
  68. multipers/gudhi/gudhi/Persistence_matrix/columns/chain_column_extra_properties.h +150 -0
  69. multipers/gudhi/gudhi/Persistence_matrix/columns/column_dimension_holder.h +106 -0
  70. multipers/gudhi/gudhi/Persistence_matrix/columns/column_utilities.h +219 -0
  71. multipers/gudhi/gudhi/Persistence_matrix/columns/entry_types.h +327 -0
  72. multipers/gudhi/gudhi/Persistence_matrix/columns/heap_column.h +1140 -0
  73. multipers/gudhi/gudhi/Persistence_matrix/columns/intrusive_list_column.h +934 -0
  74. multipers/gudhi/gudhi/Persistence_matrix/columns/intrusive_set_column.h +934 -0
  75. multipers/gudhi/gudhi/Persistence_matrix/columns/list_column.h +980 -0
  76. multipers/gudhi/gudhi/Persistence_matrix/columns/naive_vector_column.h +1092 -0
  77. multipers/gudhi/gudhi/Persistence_matrix/columns/row_access.h +192 -0
  78. multipers/gudhi/gudhi/Persistence_matrix/columns/set_column.h +921 -0
  79. multipers/gudhi/gudhi/Persistence_matrix/columns/small_vector_column.h +1093 -0
  80. multipers/gudhi/gudhi/Persistence_matrix/columns/unordered_set_column.h +1012 -0
  81. multipers/gudhi/gudhi/Persistence_matrix/columns/vector_column.h +1244 -0
  82. multipers/gudhi/gudhi/Persistence_matrix/matrix_dimension_holders.h +186 -0
  83. multipers/gudhi/gudhi/Persistence_matrix/matrix_row_access.h +164 -0
  84. multipers/gudhi/gudhi/Persistence_matrix/ru_pairing.h +156 -0
  85. multipers/gudhi/gudhi/Persistence_matrix/ru_rep_cycles.h +376 -0
  86. multipers/gudhi/gudhi/Persistence_matrix/ru_vine_swap.h +540 -0
  87. multipers/gudhi/gudhi/Persistent_cohomology/Field_Zp.h +118 -0
  88. multipers/gudhi/gudhi/Persistent_cohomology/Multi_field.h +173 -0
  89. multipers/gudhi/gudhi/Persistent_cohomology/Persistent_cohomology_column.h +128 -0
  90. multipers/gudhi/gudhi/Persistent_cohomology.h +745 -0
  91. multipers/gudhi/gudhi/Points_off_io.h +171 -0
  92. multipers/gudhi/gudhi/Simple_object_pool.h +69 -0
  93. multipers/gudhi/gudhi/Simplex_tree/Simplex_tree_iterators.h +463 -0
  94. multipers/gudhi/gudhi/Simplex_tree/Simplex_tree_node_explicit_storage.h +83 -0
  95. multipers/gudhi/gudhi/Simplex_tree/Simplex_tree_siblings.h +106 -0
  96. multipers/gudhi/gudhi/Simplex_tree/Simplex_tree_star_simplex_iterators.h +277 -0
  97. multipers/gudhi/gudhi/Simplex_tree/hooks_simplex_base.h +62 -0
  98. multipers/gudhi/gudhi/Simplex_tree/indexing_tag.h +27 -0
  99. multipers/gudhi/gudhi/Simplex_tree/serialization_utils.h +62 -0
  100. multipers/gudhi/gudhi/Simplex_tree/simplex_tree_options.h +157 -0
  101. multipers/gudhi/gudhi/Simplex_tree.h +2794 -0
  102. multipers/gudhi/gudhi/Simplex_tree_multi.h +152 -0
  103. multipers/gudhi/gudhi/distance_functions.h +62 -0
  104. multipers/gudhi/gudhi/graph_simplicial_complex.h +104 -0
  105. multipers/gudhi/gudhi/persistence_interval.h +253 -0
  106. multipers/gudhi/gudhi/persistence_matrix_options.h +170 -0
  107. multipers/gudhi/gudhi/reader_utils.h +367 -0
  108. multipers/gudhi/mma_interface_coh.h +256 -0
  109. multipers/gudhi/mma_interface_h0.h +223 -0
  110. multipers/gudhi/mma_interface_matrix.h +293 -0
  111. multipers/gudhi/naive_merge_tree.h +536 -0
  112. multipers/gudhi/scc_io.h +310 -0
  113. multipers/gudhi/truc.h +1403 -0
  114. multipers/io.cpython-311-x86_64-linux-gnu.so +0 -0
  115. multipers/io.pyx +644 -0
  116. multipers/ml/__init__.py +0 -0
  117. multipers/ml/accuracies.py +90 -0
  118. multipers/ml/invariants_with_persistable.py +79 -0
  119. multipers/ml/kernels.py +176 -0
  120. multipers/ml/mma.py +713 -0
  121. multipers/ml/one.py +472 -0
  122. multipers/ml/point_clouds.py +352 -0
  123. multipers/ml/signed_measures.py +1589 -0
  124. multipers/ml/sliced_wasserstein.py +461 -0
  125. multipers/ml/tools.py +113 -0
  126. multipers/mma_structures.cpython-311-x86_64-linux-gnu.so +0 -0
  127. multipers/mma_structures.pxd +128 -0
  128. multipers/mma_structures.pyx +2786 -0
  129. multipers/mma_structures.pyx.tp +1094 -0
  130. multipers/multi_parameter_rank_invariant/diff_helpers.h +84 -0
  131. multipers/multi_parameter_rank_invariant/euler_characteristic.h +97 -0
  132. multipers/multi_parameter_rank_invariant/function_rips.h +322 -0
  133. multipers/multi_parameter_rank_invariant/hilbert_function.h +769 -0
  134. multipers/multi_parameter_rank_invariant/persistence_slices.h +148 -0
  135. multipers/multi_parameter_rank_invariant/rank_invariant.h +369 -0
  136. multipers/multiparameter_edge_collapse.py +41 -0
  137. multipers/multiparameter_module_approximation/approximation.h +2330 -0
  138. multipers/multiparameter_module_approximation/combinatory.h +129 -0
  139. multipers/multiparameter_module_approximation/debug.h +107 -0
  140. multipers/multiparameter_module_approximation/euler_curves.h +0 -0
  141. multipers/multiparameter_module_approximation/format_python-cpp.h +286 -0
  142. multipers/multiparameter_module_approximation/heap_column.h +238 -0
  143. multipers/multiparameter_module_approximation/images.h +79 -0
  144. multipers/multiparameter_module_approximation/list_column.h +174 -0
  145. multipers/multiparameter_module_approximation/list_column_2.h +232 -0
  146. multipers/multiparameter_module_approximation/ru_matrix.h +347 -0
  147. multipers/multiparameter_module_approximation/set_column.h +135 -0
  148. multipers/multiparameter_module_approximation/structure_higher_dim_barcode.h +36 -0
  149. multipers/multiparameter_module_approximation/unordered_set_column.h +166 -0
  150. multipers/multiparameter_module_approximation/utilities.h +403 -0
  151. multipers/multiparameter_module_approximation/vector_column.h +223 -0
  152. multipers/multiparameter_module_approximation/vector_matrix.h +331 -0
  153. multipers/multiparameter_module_approximation/vineyards.h +464 -0
  154. multipers/multiparameter_module_approximation/vineyards_trajectories.h +649 -0
  155. multipers/multiparameter_module_approximation.cpython-311-x86_64-linux-gnu.so +0 -0
  156. multipers/multiparameter_module_approximation.pyx +235 -0
  157. multipers/pickle.py +90 -0
  158. multipers/plots.py +456 -0
  159. multipers/point_measure.cpython-311-x86_64-linux-gnu.so +0 -0
  160. multipers/point_measure.pyx +395 -0
  161. multipers/simplex_tree_multi.cpython-311-x86_64-linux-gnu.so +0 -0
  162. multipers/simplex_tree_multi.pxd +134 -0
  163. multipers/simplex_tree_multi.pyx +10840 -0
  164. multipers/simplex_tree_multi.pyx.tp +2009 -0
  165. multipers/slicer.cpython-311-x86_64-linux-gnu.so +0 -0
  166. multipers/slicer.pxd +3034 -0
  167. multipers/slicer.pxd.tp +234 -0
  168. multipers/slicer.pyx +20481 -0
  169. multipers/slicer.pyx.tp +1088 -0
  170. multipers/tensor/tensor.h +672 -0
  171. multipers/tensor.pxd +13 -0
  172. multipers/test.pyx +44 -0
  173. multipers/tests/__init__.py +62 -0
  174. multipers/torch/__init__.py +1 -0
  175. multipers/torch/diff_grids.py +240 -0
  176. multipers/torch/rips_density.py +310 -0
  177. multipers-2.3.3b6.dist-info/METADATA +128 -0
  178. multipers-2.3.3b6.dist-info/RECORD +182 -0
  179. multipers-2.3.3b6.dist-info/WHEEL +5 -0
  180. multipers-2.3.3b6.dist-info/licenses/LICENSE +21 -0
  181. multipers-2.3.3b6.dist-info/top_level.txt +1 -0
  182. multipers.libs/libtbb-ca48af5c.so.12.16 +0 -0
multipers/io.pyx ADDED
@@ -0,0 +1,644 @@
1
+ import re
2
+ from gudhi import SimplexTree
3
+ import gudhi as gd
4
+ import numpy as np
5
+ import os
6
+ from shutil import which
7
+ from libcpp cimport bool
8
+ from typing import Optional, Literal
9
+ from collections import defaultdict
10
+ import itertools
11
+ import threading
12
+ import cython
13
+ cimport cython
14
+
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
+ current_doc_url = "https://davidlapous.github.io/multipers/"
19
+ doc_soft_urls = {
20
+ "mpfree":"https://bitbucket.org/mkerber/mpfree/",
21
+ "multi_chunk":"https://bitbucket.org/mkerber/multi_chunk/",
22
+ "function_delaunay":"https://bitbucket.org/mkerber/function_delaunay/",
23
+ "2pac":"https://gitlab.com/flenzen/2pac",
24
+ }
25
+ doc_soft_easy_install = {
26
+ "mpfree":f"""
27
+ ```sh
28
+ git clone {doc_soft_urls["mpfree"]}
29
+ cd mpfree
30
+ cmake . --fresh
31
+ make
32
+ cp mpfree $CONDA_PREFIX/bin/
33
+ cd ..
34
+ rm -rf mpfree
35
+ ```
36
+ """,
37
+ "multi_chunk":f"""
38
+ ```sh
39
+ git clone {doc_soft_urls["multi_chunk"]}
40
+ cd multi_chunk
41
+ cmake . --fresh
42
+ make
43
+ cp multi_chunk $CONDA_PREFIX/bin/
44
+ cd ..
45
+ rm -rf multi_chunk
46
+ ```
47
+ """,
48
+ "function_delaunay":f"""
49
+ ```sh
50
+ git clone {doc_soft_urls["function_delaunay"]}
51
+ cd function_delaunay
52
+ cmake . --fresh
53
+ make
54
+ cp main $CONDA_PREFIX/bin/function_delaunay
55
+ cd ..
56
+ rm -rf function_delaunay
57
+ ```
58
+ """,
59
+ "2pac":f"""
60
+ ```sh
61
+ git clone {doc_soft_urls["2pac"]} 2pac
62
+ cd 2pac && mkdir build && cd build
63
+ cmake ..
64
+ make
65
+ cp 2pac $CONDA_PREFIX/bin
66
+ ```
67
+ """,
68
+ }
69
+ doc_soft_urls = defaultdict(lambda:"<Unknown url>", doc_soft_urls)
70
+ doc_soft_easy_install = defaultdict(lambda:"<Unknown>", doc_soft_easy_install)
71
+
72
+ available_reduce_softs = Literal["mpfree","multi_chunk","2pac"]
73
+
74
+ def _path_init(soft:str|os.PathLike):
75
+ a = which(f"./{soft}")
76
+ b = which(f"{soft}")
77
+ if a:
78
+ pathes[soft] = a
79
+ elif b:
80
+ pathes[soft] = b
81
+
82
+ if pathes[soft] is not None:
83
+ verbose_arg = "> /dev/null 2>&1"
84
+ test = os.system(pathes[soft] + " --help " + verbose_arg)
85
+ if test:
86
+ from warnings import warn
87
+ warn(f"""
88
+ Found external software {soft} at {pathes[soft]}
89
+ but may not behave well.
90
+ """)
91
+
92
+
93
+
94
+ cdef dict[str,str|None] pathes = {
95
+ "mpfree":None,
96
+ "2pac":None,
97
+ "function_delaunay":None,
98
+ "multi_chunk":None,
99
+ }
100
+
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
+
120
+
121
+ ## TODO : optimize with Python.h ?
122
+ def scc_parser(path: str| os.PathLike):
123
+ """
124
+ Parse an scc file into the scc python format, aka blocks.
125
+ """
126
+ pass_line_regex = re.compile(r"^\s*$|^#|^scc2020$")
127
+ def valid_line(line):
128
+ return pass_line_regex.match(line) is None
129
+ parse_line_regex = re.compile(r"^(?P<filtration>[^;]+);(?P<boundary>[^;]*)$")
130
+ cdef tuple[tuple[str,str]] clines
131
+ with open(path, "r") as f:
132
+ lines =(x.strip() for x in f if valid_line(x))
133
+ num_parameters = int(next(lines))
134
+ sizes = np.cumsum(np.asarray([0] + next(lines).split(), dtype=np.int32))
135
+ lines = (parse_line_regex.match(a) for a in lines)
136
+ clines = tuple((a.group("filtration"),a.group("boundary")) for a in lines)
137
+ # F = np.fromiter((a[0].split() for a in clines), dtype=np.dtype((np.float64,2)), count = sizes[-1])
138
+ F = np.fromiter((np.fromstring(a[0], sep=r' ', dtype=np.float64) for a in clines), dtype=np.dtype((np.float64,num_parameters)), count = sizes[-1])
139
+
140
+ # B = tuple(np.asarray(a[1].split(), dtype=np.int32) if len(a[1])>0 else np.empty(0, dtype=np.int32) for a in clines) ## TODO : this is very slow : optimize
141
+ B = tuple(np.fromstring(a[1], sep=' ', dtype=np.int32) for a in clines)
142
+ # block_lines = (tuple(get_bf(x, num_parameters) for x in lines[sizes[i]:sizes[i+1]]) for i in range(len(sizes)-1))
143
+
144
+ # blocks = [(np.asarray([x[0] for x in b if len(x)>0], dtype=float),tuple(x[1] for x in b)) for b in block_lines]
145
+ blocks = [(F[sizes[i]:sizes[i+1]], B[sizes[i]:sizes[i+1]]) for i in range(len(sizes)-1)]
146
+
147
+ return blocks
148
+
149
+
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
+
214
+
215
+ def _init_external_softwares(requires=[]):
216
+ global pathes
217
+ cdef bool any = False
218
+ for soft,soft_path in pathes.items():
219
+ if soft_path is None:
220
+ _path_init(soft)
221
+ any = any or (soft in requires)
222
+
223
+ if any:
224
+ _put_temp_files_to_ram()
225
+ for soft in requires:
226
+ if pathes[soft] is None:
227
+ global doc_soft_urls
228
+ raise ValueError(f"""
229
+ Did not find {soft}.
230
+ Install it from {doc_soft_urls[soft]}, and put it in your current directory,
231
+ or in you $PATH.
232
+ Documentation is available here: {current_doc_url}compilation.html#external-libraries
233
+ For instance:
234
+ {doc_soft_easy_install[soft]}
235
+ """)
236
+ _init_external_softwares()
237
+ def _check_available(soft:str):
238
+ _init_external_softwares()
239
+ return pathes.get(soft,None) is not None
240
+
241
+
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
+
306
+ def scc_reduce_from_str_to_slicer(
307
+ path:str|os.PathLike,
308
+ slicer,
309
+ bool full_resolution=True,
310
+ int dimension: int | np.int64 = 1,
311
+ bool clear: bool = True,
312
+ id: Optional[str] = None, # For parallel stuff
313
+ bool verbose:bool=False,
314
+ backend:Literal["mpfree","multi_chunk","twopac"]="mpfree",
315
+ shift_dimension=0
316
+ ):
317
+ """
318
+ Computes a minimal presentation of the file in path,
319
+ using mpfree.
320
+
321
+ path:PathLike
322
+ slicer: empty slicer to fill
323
+ full_resolution: bool
324
+ dimension: int, presentation dimension to consider
325
+ clear: bool, removes temporary files if True
326
+ id: str, temporary files are of this id, allowing for multiprocessing
327
+ verbose: bool
328
+ backend: "mpfree", "multi_chunk" or "2pac"
329
+ """
330
+ global pathes, input_path, output_path
331
+ _init_external_softwares(requires=[backend])
332
+
333
+
334
+ resolution_str = "--resolution" if full_resolution else ""
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
413
+
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
+
424
+
425
+
426
+
427
+ def function_delaunay_presentation(
428
+ point_cloud:np.ndarray,
429
+ function_values:np.ndarray,
430
+ id:Optional[str] = None,
431
+ bool clear:bool = True,
432
+ bool verbose:bool=False,
433
+ int degree = -1,
434
+ bool multi_chunk = False,
435
+ ):
436
+ """
437
+ Computes a function delaunay presentation, and returns it as blocks.
438
+
439
+ points : (num_pts, n) float array
440
+ grades : (num_pts,) float array
441
+ degree (opt) : if given, computes a minimal presentation of this homological degree first
442
+ clear:bool, removes temporary files if true
443
+ degree: computes minimal presentation of this degree if given
444
+ verbose : bool
445
+ """
446
+ if id is None:
447
+ id = str(threading.get_native_id())
448
+ global input_path, output_path, pathes
449
+ backend = "function_delaunay"
450
+ _init_external_softwares(requires=[backend])
451
+
452
+ to_write = np.concatenate([point_cloud, function_values.reshape(-1,1)], axis=1)
453
+ np.savetxt(input_path+id,to_write,delimiter=' ')
454
+ verbose_arg = "> /dev/null 2>&1" if not verbose else ""
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]
470
+
471
+ return blocks
472
+
473
+ def function_delaunay_presentation_to_slicer(
474
+ slicer,
475
+ point_cloud:np.ndarray,
476
+ function_values:np.ndarray,
477
+ id:Optional[str] = None,
478
+ bool clear:bool = True,
479
+ bool verbose:bool=False,
480
+ int degree = -1,
481
+ bool multi_chunk = False,
482
+ ):
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
+ """
494
+ if id is None:
495
+ id = str(threading.get_native_id())
496
+ global input_path, output_path, pathes
497
+ backend = "function_delaunay"
498
+ _init_external_softwares(requires=[backend])
499
+
500
+ to_write = np.concatenate([point_cloud, function_values.reshape(-1,1)], axis=1)
501
+ np.savetxt(input_path+id,to_write,delimiter=' ')
502
+ verbose_arg = "> /dev/null 2>&1" if not verbose else ""
503
+ degree_arg = f"--minpres {degree}" if degree >= 0 else ""
504
+ multi_chunk_arg = "--multi-chunk" if multi_chunk else ""
505
+ if os.path.exists(output_path + id):
506
+ os.remove(output_path+ id)
507
+ command = f"{pathes[backend]} {degree_arg} {multi_chunk_arg} {input_path+id} {output_path+id} {verbose_arg} --no-delaunay-compare"
508
+ if verbose:
509
+ print(command)
510
+ os.system(command)
511
+
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
+
526
+
527
+
528
+
529
+ @cython.boundscheck(False)
530
+ @cython.wraparound(False)
531
+ def scc2disk(
532
+ stuff,
533
+ path:str|os.PathLike,
534
+ int num_parameters = -1,
535
+ bool reverse_block = False,
536
+ bool rivet_compatible = False,
537
+ bool ignore_last_generators = False,
538
+ bool strip_comments = False,
539
+ ):
540
+ """
541
+ Writes a scc python format / blocks into a file.
542
+ """
543
+ if num_parameters == -1:
544
+ for block in stuff:
545
+ if len(block[0]) == 0:
546
+ continue
547
+ num_gens, num_parameters_= np.asarray(block[0]).shape
548
+ num_parameters = num_parameters_
549
+ break
550
+ assert num_parameters > 0, f"Invalid number of parameters {num_parameters}"
551
+
552
+ if reverse_block: stuff.reverse()
553
+ with open(path, "w") as f:
554
+ f.write("scc2020\n") if not rivet_compatible else f.write("firep\n")
555
+ if not strip_comments and not rivet_compatible: f.write("# Number of parameters\n")
556
+ if rivet_compatible:
557
+ assert num_parameters == 2
558
+ f.write("Filtration 1\n")
559
+ f.write("Filtration 2\n")
560
+ else:
561
+ f.write(f"{num_parameters}\n")
562
+
563
+ if not strip_comments: f.write("# Sizes of generating sets\n")
564
+ for block in stuff: f.write(f"{len(block[0])} ")
565
+ f.write("\n")
566
+ for i,block in enumerate(stuff):
567
+ if (rivet_compatible or ignore_last_generators) and i == len(stuff)-1: continue
568
+ if not strip_comments: f.write(f"# Block of dimension {len(stuff)-1-i}\n")
569
+ filtration, boundary = block
570
+ filtration = np.asarray(filtration).astype(str)
571
+ # boundary = tuple(x.astype(str) for x in boundary)
572
+ f.write(" ".join(itertools.chain.from_iterable(
573
+ ((*(f.tolist()), ";", *(np.asarray(b).astype(str).tolist()), "\n")
574
+ for f,b in zip(filtration, boundary))
575
+ )
576
+ ))
577
+ # for j in range(<int>len(filtration)):
578
+ # line = " ".join((
579
+ # *filtration[j],
580
+ # ";",
581
+ # *boundary[j],
582
+ # "\n",
583
+ # ))
584
+ # f.write(line)
585
+
586
+ def scc2disk_old(
587
+ stuff,
588
+ path:str|os.PathLike,
589
+ num_parameters = -1,
590
+ reverse_block = False,
591
+ rivet_compatible = False,
592
+ ignore_last_generators = False,
593
+ strip_comments = False,
594
+ ):
595
+ """
596
+ Writes a scc python format / blocks into a file.
597
+ """
598
+ if num_parameters == -1:
599
+ for block in stuff:
600
+ if len(block[0]) == 0:
601
+ continue
602
+ num_gens, num_parameters_= np.asarray(block[0]).shape
603
+ num_parameters = num_parameters_
604
+ break
605
+ assert num_parameters > 0, f"Invalid number of parameters {num_parameters}"
606
+
607
+ if reverse_block: stuff.reverse()
608
+ out = []
609
+ if rivet_compatible:
610
+ out.append(r"firep")
611
+ else:
612
+ out.append(r"scc2020")
613
+ if not strip_comments and not rivet_compatible:
614
+ out.append(r"# Number of parameters")
615
+ if rivet_compatible:
616
+ out.append("Filtration 1")
617
+ out.append("Filtration 2\n")
618
+ else:
619
+ out.append(f"{num_parameters}")
620
+
621
+ if not strip_comments:
622
+ out.append("# Sizes of generating sets")
623
+
624
+ # for block in stuff:
625
+ # f.write(f"{len(block[0])} ")
626
+ out.append(" ".join(str(len(block[0])) for block in stuff))
627
+ str_blocks = [out]
628
+ for i,block in enumerate(stuff):
629
+ if (rivet_compatible or ignore_last_generators) and i == len(stuff)-1: continue
630
+ if not strip_comments:
631
+ str_blocks.append([f"# Block of dimension {len(stuff)-1-i}"])
632
+ filtration, boundary = block
633
+ if len(filtration) == 0:
634
+ continue
635
+ filtration = filtration.astype(str)
636
+ C = filtration[:,0]
637
+ for i in range(1,filtration.shape[1]):
638
+ C = np.char.add(C," ")
639
+ C = np.char.add(C,filtration[:,i])
640
+ C = np.char.add(C, ";")
641
+ 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
+ str_blocks.append(np.char.add(C,D))
643
+
644
+ np.savetxt("test.scc", np.concatenate(str_blocks), delimiter="", fmt="%s")
File without changes