multipers 2.2.3__cp310-cp310-win_amd64.whl → 2.3.1__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.

Files changed (182) hide show
  1. multipers/__init__.py +33 -31
  2. multipers/_signed_measure_meta.py +430 -430
  3. multipers/_slicer_meta.py +211 -212
  4. multipers/data/MOL2.py +458 -458
  5. multipers/data/UCR.py +18 -18
  6. multipers/data/graphs.py +466 -466
  7. multipers/data/immuno_regions.py +27 -27
  8. multipers/data/pytorch2simplextree.py +90 -90
  9. multipers/data/shape3d.py +101 -101
  10. multipers/data/synthetic.py +113 -111
  11. multipers/distances.py +198 -198
  12. multipers/filtration_conversions.pxd.tp +84 -84
  13. multipers/filtrations/__init__.py +18 -0
  14. multipers/{ml/convolutions.py → filtrations/density.py} +563 -520
  15. multipers/filtrations/filtrations.py +289 -0
  16. multipers/filtrations.pxd +224 -224
  17. multipers/function_rips.cp310-win_amd64.pyd +0 -0
  18. multipers/function_rips.pyx +105 -105
  19. multipers/grids.cp310-win_amd64.pyd +0 -0
  20. multipers/grids.pyx +350 -350
  21. multipers/gudhi/Persistence_slices_interface.h +132 -132
  22. multipers/gudhi/Simplex_tree_interface.h +239 -245
  23. multipers/gudhi/Simplex_tree_multi_interface.h +516 -561
  24. multipers/gudhi/cubical_to_boundary.h +59 -59
  25. multipers/gudhi/gudhi/Bitmap_cubical_complex.h +450 -450
  26. multipers/gudhi/gudhi/Bitmap_cubical_complex_base.h +1070 -1070
  27. multipers/gudhi/gudhi/Bitmap_cubical_complex_periodic_boundary_conditions_base.h +579 -579
  28. multipers/gudhi/gudhi/Debug_utils.h +45 -45
  29. multipers/gudhi/gudhi/Fields/Multi_field.h +484 -484
  30. multipers/gudhi/gudhi/Fields/Multi_field_operators.h +455 -455
  31. multipers/gudhi/gudhi/Fields/Multi_field_shared.h +450 -450
  32. multipers/gudhi/gudhi/Fields/Multi_field_small.h +531 -531
  33. multipers/gudhi/gudhi/Fields/Multi_field_small_operators.h +507 -507
  34. multipers/gudhi/gudhi/Fields/Multi_field_small_shared.h +531 -531
  35. multipers/gudhi/gudhi/Fields/Z2_field.h +355 -355
  36. multipers/gudhi/gudhi/Fields/Z2_field_operators.h +376 -376
  37. multipers/gudhi/gudhi/Fields/Zp_field.h +420 -420
  38. multipers/gudhi/gudhi/Fields/Zp_field_operators.h +400 -400
  39. multipers/gudhi/gudhi/Fields/Zp_field_shared.h +418 -418
  40. multipers/gudhi/gudhi/Flag_complex_edge_collapser.h +337 -337
  41. multipers/gudhi/gudhi/Matrix.h +2107 -2107
  42. multipers/gudhi/gudhi/Multi_critical_filtration.h +1038 -1038
  43. multipers/gudhi/gudhi/Multi_persistence/Box.h +171 -171
  44. multipers/gudhi/gudhi/Multi_persistence/Line.h +282 -282
  45. multipers/gudhi/gudhi/Off_reader.h +173 -173
  46. multipers/gudhi/gudhi/One_critical_filtration.h +1433 -1431
  47. multipers/gudhi/gudhi/Persistence_matrix/Base_matrix.h +769 -769
  48. multipers/gudhi/gudhi/Persistence_matrix/Base_matrix_with_column_compression.h +686 -686
  49. multipers/gudhi/gudhi/Persistence_matrix/Boundary_matrix.h +842 -842
  50. multipers/gudhi/gudhi/Persistence_matrix/Chain_matrix.h +1350 -1350
  51. multipers/gudhi/gudhi/Persistence_matrix/Id_to_index_overlay.h +1105 -1105
  52. multipers/gudhi/gudhi/Persistence_matrix/Position_to_index_overlay.h +859 -859
  53. multipers/gudhi/gudhi/Persistence_matrix/RU_matrix.h +910 -910
  54. multipers/gudhi/gudhi/Persistence_matrix/allocators/entry_constructors.h +139 -139
  55. multipers/gudhi/gudhi/Persistence_matrix/base_pairing.h +230 -230
  56. multipers/gudhi/gudhi/Persistence_matrix/base_swap.h +211 -211
  57. multipers/gudhi/gudhi/Persistence_matrix/boundary_cell_position_to_id_mapper.h +60 -60
  58. multipers/gudhi/gudhi/Persistence_matrix/boundary_face_position_to_id_mapper.h +60 -60
  59. multipers/gudhi/gudhi/Persistence_matrix/chain_pairing.h +136 -136
  60. multipers/gudhi/gudhi/Persistence_matrix/chain_rep_cycles.h +190 -190
  61. multipers/gudhi/gudhi/Persistence_matrix/chain_vine_swap.h +616 -616
  62. multipers/gudhi/gudhi/Persistence_matrix/columns/chain_column_extra_properties.h +150 -150
  63. multipers/gudhi/gudhi/Persistence_matrix/columns/column_dimension_holder.h +106 -106
  64. multipers/gudhi/gudhi/Persistence_matrix/columns/column_utilities.h +219 -219
  65. multipers/gudhi/gudhi/Persistence_matrix/columns/entry_types.h +327 -327
  66. multipers/gudhi/gudhi/Persistence_matrix/columns/heap_column.h +1140 -1140
  67. multipers/gudhi/gudhi/Persistence_matrix/columns/intrusive_list_column.h +934 -934
  68. multipers/gudhi/gudhi/Persistence_matrix/columns/intrusive_set_column.h +934 -934
  69. multipers/gudhi/gudhi/Persistence_matrix/columns/list_column.h +980 -980
  70. multipers/gudhi/gudhi/Persistence_matrix/columns/naive_vector_column.h +1092 -1092
  71. multipers/gudhi/gudhi/Persistence_matrix/columns/row_access.h +192 -192
  72. multipers/gudhi/gudhi/Persistence_matrix/columns/set_column.h +921 -921
  73. multipers/gudhi/gudhi/Persistence_matrix/columns/small_vector_column.h +1093 -1093
  74. multipers/gudhi/gudhi/Persistence_matrix/columns/unordered_set_column.h +1012 -1012
  75. multipers/gudhi/gudhi/Persistence_matrix/columns/vector_column.h +1244 -1244
  76. multipers/gudhi/gudhi/Persistence_matrix/matrix_dimension_holders.h +186 -186
  77. multipers/gudhi/gudhi/Persistence_matrix/matrix_row_access.h +164 -164
  78. multipers/gudhi/gudhi/Persistence_matrix/ru_pairing.h +156 -156
  79. multipers/gudhi/gudhi/Persistence_matrix/ru_rep_cycles.h +376 -376
  80. multipers/gudhi/gudhi/Persistence_matrix/ru_vine_swap.h +540 -540
  81. multipers/gudhi/gudhi/Persistent_cohomology/Field_Zp.h +118 -118
  82. multipers/gudhi/gudhi/Persistent_cohomology/Multi_field.h +173 -173
  83. multipers/gudhi/gudhi/Persistent_cohomology/Persistent_cohomology_column.h +128 -128
  84. multipers/gudhi/gudhi/Persistent_cohomology.h +745 -745
  85. multipers/gudhi/gudhi/Points_off_io.h +171 -171
  86. multipers/gudhi/gudhi/Simple_object_pool.h +69 -69
  87. multipers/gudhi/gudhi/Simplex_tree/Simplex_tree_iterators.h +463 -463
  88. multipers/gudhi/gudhi/Simplex_tree/Simplex_tree_node_explicit_storage.h +83 -83
  89. multipers/gudhi/gudhi/Simplex_tree/Simplex_tree_siblings.h +106 -106
  90. multipers/gudhi/gudhi/Simplex_tree/Simplex_tree_star_simplex_iterators.h +277 -277
  91. multipers/gudhi/gudhi/Simplex_tree/hooks_simplex_base.h +62 -62
  92. multipers/gudhi/gudhi/Simplex_tree/indexing_tag.h +27 -27
  93. multipers/gudhi/gudhi/Simplex_tree/serialization_utils.h +62 -62
  94. multipers/gudhi/gudhi/Simplex_tree/simplex_tree_options.h +157 -157
  95. multipers/gudhi/gudhi/Simplex_tree.h +2794 -2794
  96. multipers/gudhi/gudhi/Simplex_tree_multi.h +152 -163
  97. multipers/gudhi/gudhi/distance_functions.h +62 -62
  98. multipers/gudhi/gudhi/graph_simplicial_complex.h +104 -104
  99. multipers/gudhi/gudhi/persistence_interval.h +253 -253
  100. multipers/gudhi/gudhi/persistence_matrix_options.h +170 -170
  101. multipers/gudhi/gudhi/reader_utils.h +367 -367
  102. multipers/gudhi/mma_interface_coh.h +256 -255
  103. multipers/gudhi/mma_interface_h0.h +223 -231
  104. multipers/gudhi/mma_interface_matrix.h +291 -282
  105. multipers/gudhi/naive_merge_tree.h +536 -575
  106. multipers/gudhi/scc_io.h +310 -289
  107. multipers/gudhi/truc.h +957 -888
  108. multipers/io.cp310-win_amd64.pyd +0 -0
  109. multipers/io.pyx +714 -711
  110. multipers/ml/accuracies.py +90 -90
  111. multipers/ml/invariants_with_persistable.py +79 -79
  112. multipers/ml/kernels.py +176 -176
  113. multipers/ml/mma.py +713 -714
  114. multipers/ml/one.py +472 -472
  115. multipers/ml/point_clouds.py +352 -346
  116. multipers/ml/signed_measures.py +1589 -1589
  117. multipers/ml/sliced_wasserstein.py +461 -461
  118. multipers/ml/tools.py +113 -113
  119. multipers/mma_structures.cp310-win_amd64.pyd +0 -0
  120. multipers/mma_structures.pxd +127 -127
  121. multipers/mma_structures.pyx +4 -8
  122. multipers/mma_structures.pyx.tp +1083 -1085
  123. multipers/multi_parameter_rank_invariant/diff_helpers.h +84 -93
  124. multipers/multi_parameter_rank_invariant/euler_characteristic.h +97 -97
  125. multipers/multi_parameter_rank_invariant/function_rips.h +322 -322
  126. multipers/multi_parameter_rank_invariant/hilbert_function.h +769 -769
  127. multipers/multi_parameter_rank_invariant/persistence_slices.h +148 -148
  128. multipers/multi_parameter_rank_invariant/rank_invariant.h +369 -369
  129. multipers/multiparameter_edge_collapse.py +41 -41
  130. multipers/multiparameter_module_approximation/approximation.h +2298 -2295
  131. multipers/multiparameter_module_approximation/combinatory.h +129 -129
  132. multipers/multiparameter_module_approximation/debug.h +107 -107
  133. multipers/multiparameter_module_approximation/format_python-cpp.h +286 -286
  134. multipers/multiparameter_module_approximation/heap_column.h +238 -238
  135. multipers/multiparameter_module_approximation/images.h +79 -79
  136. multipers/multiparameter_module_approximation/list_column.h +174 -174
  137. multipers/multiparameter_module_approximation/list_column_2.h +232 -232
  138. multipers/multiparameter_module_approximation/ru_matrix.h +347 -347
  139. multipers/multiparameter_module_approximation/set_column.h +135 -135
  140. multipers/multiparameter_module_approximation/structure_higher_dim_barcode.h +36 -36
  141. multipers/multiparameter_module_approximation/unordered_set_column.h +166 -166
  142. multipers/multiparameter_module_approximation/utilities.h +403 -419
  143. multipers/multiparameter_module_approximation/vector_column.h +223 -223
  144. multipers/multiparameter_module_approximation/vector_matrix.h +331 -331
  145. multipers/multiparameter_module_approximation/vineyards.h +464 -464
  146. multipers/multiparameter_module_approximation/vineyards_trajectories.h +649 -649
  147. multipers/multiparameter_module_approximation.cp310-win_amd64.pyd +0 -0
  148. multipers/multiparameter_module_approximation.pyx +218 -217
  149. multipers/pickle.py +90 -53
  150. multipers/plots.py +342 -334
  151. multipers/point_measure.cp310-win_amd64.pyd +0 -0
  152. multipers/point_measure.pyx +322 -320
  153. multipers/simplex_tree_multi.cp310-win_amd64.pyd +0 -0
  154. multipers/simplex_tree_multi.pxd +133 -133
  155. multipers/simplex_tree_multi.pyx +115 -48
  156. multipers/simplex_tree_multi.pyx.tp +1947 -1935
  157. multipers/slicer.cp310-win_amd64.pyd +0 -0
  158. multipers/slicer.pxd +301 -120
  159. multipers/slicer.pxd.tp +218 -214
  160. multipers/slicer.pyx +1570 -507
  161. multipers/slicer.pyx.tp +931 -914
  162. multipers/tensor/tensor.h +672 -672
  163. multipers/tensor.pxd +13 -13
  164. multipers/test.pyx +44 -44
  165. multipers/tests/__init__.py +57 -57
  166. multipers/torch/diff_grids.py +217 -217
  167. multipers/torch/rips_density.py +310 -304
  168. {multipers-2.2.3.dist-info → multipers-2.3.1.dist-info}/LICENSE +21 -21
  169. {multipers-2.2.3.dist-info → multipers-2.3.1.dist-info}/METADATA +21 -11
  170. multipers-2.3.1.dist-info/RECORD +182 -0
  171. {multipers-2.2.3.dist-info → multipers-2.3.1.dist-info}/WHEEL +1 -1
  172. multipers/tests/test_diff_helper.py +0 -73
  173. multipers/tests/test_hilbert_function.py +0 -82
  174. multipers/tests/test_mma.py +0 -83
  175. multipers/tests/test_point_clouds.py +0 -49
  176. multipers/tests/test_python-cpp_conversion.py +0 -82
  177. multipers/tests/test_signed_betti.py +0 -181
  178. multipers/tests/test_signed_measure.py +0 -89
  179. multipers/tests/test_simplextreemulti.py +0 -221
  180. multipers/tests/test_slicer.py +0 -221
  181. multipers-2.2.3.dist-info/RECORD +0 -189
  182. {multipers-2.2.3.dist-info → multipers-2.3.1.dist-info}/top_level.txt +0 -0
@@ -1,217 +1,218 @@
1
- """!
2
- @package mma
3
- @brief Files containing the C++ cythonized functions.
4
- @author David Loiseaux
5
- @copyright Copyright (c) 2022 Inria.
6
- """
7
-
8
- # distutils: language = c++
9
-
10
- ###########################################################################
11
- ## PYTHON LIBRARIES
12
- import gudhi as gd
13
- import numpy as np
14
- from typing import List
15
- from joblib import Parallel, delayed
16
- import sys
17
-
18
- ###########################################################################
19
- ## CPP CLASSES
20
- from libc.stdint cimport intptr_t
21
- from libc.stdint cimport uintptr_t
22
-
23
- ###########################################################################
24
- ## CYTHON TYPES
25
- from libcpp.vector cimport vector
26
- from libcpp.utility cimport pair
27
- #from libcpp.list cimport list as clist
28
- from libcpp cimport bool
29
- from libcpp cimport int
30
- from typing import Iterable,Optional, Literal
31
- from cython.operator import dereference
32
- #########################################################################
33
- ## Multipersistence Module Approximation Classes
34
- from multipers.mma_structures cimport *
35
- from multipers.filtrations cimport *
36
- from multipers.filtration_conversions cimport *
37
- cimport numpy as cnp
38
-
39
-
40
- #########################################################################
41
- ## Small hack for typing
42
- from multipers.simplex_tree_multi import is_simplextree_multi, SimplexTreeMulti_type
43
- from multipers.slicer import Slicer_type, is_slicer
44
- from multipers._slicer_meta import Slicer
45
- from multipers.mma_structures import *
46
- from multipers.mma_structures import PyModule_type
47
- from typing import Union
48
- import multipers
49
- import multipers.io as mio
50
- from multipers.slicer cimport _multiparameter_module_approximation_f32, _multiparameter_module_approximation_f64
51
-
52
-
53
-
54
- def module_approximation_from_slicer(
55
- slicer:Slicer_type,
56
- box:Optional[np.ndarray]=None,
57
- max_error=-1,
58
- bool complete=True,
59
- bool threshold=False,
60
- bool verbose=False,
61
- list[float] direction = [],
62
- )->PyModule_type:
63
-
64
- cdef Module[float] mod_f32
65
- cdef Module[double] mod_f64
66
- cdef intptr_t ptr
67
- if not slicer.is_vine:
68
- print(r"Got a non-vine slicer as an input. Use `vineyard=True` to remove this copy.", file=sys.stderr)
69
- slicer = Slicer(slicer, vineyard=True)
70
- direction_ = np.asarray(direction, dtype=slicer.dtype)
71
- if slicer.dtype == np.float32:
72
- approx_mod = PyModule_f32()
73
- if box is None:
74
- box = slicer.filtration_bounds()
75
- mod_f32 = _multiparameter_module_approximation_f32(slicer,_py21c_f32(direction_), max_error,Box[float](box),threshold, complete, verbose)
76
- ptr = <intptr_t>(&mod_f32)
77
- elif slicer.dtype == np.float64:
78
- approx_mod = PyModule_f64()
79
- if box is None:
80
- box = slicer.filtration_bounds()
81
- mod_f64 = _multiparameter_module_approximation_f64(slicer,_py21c_f64(direction_), max_error,Box[double](box),threshold, complete, verbose)
82
- ptr = <intptr_t>(&mod_f64)
83
- else:
84
- raise ValueError(f"Slicer must be float-like. Got {slicer.dtype}.")
85
-
86
- approx_mod._set_from_ptr(ptr)
87
-
88
- return approx_mod
89
-
90
- def module_approximation(
91
- input:Union[SimplexTreeMulti_type,Slicer_type, tuple],
92
- box:Optional[np.ndarray]=None,
93
- float max_error=-1,
94
- int nlines=500,
95
- slicer_backend:Literal["matrix","clement","graph"]="matrix",
96
- minpres:Optional[Literal["mpfree"]]=None,
97
- degree:Optional[int]=None,
98
- bool complete=True,
99
- bool threshold=False,
100
- bool verbose=False,
101
- bool ignore_warning=False,
102
- id="",
103
- list[float] direction = [],
104
- list[int] swap_box_coords = [],
105
- *,
106
- int n_jobs = -1,
107
- )->PyModule_type:
108
- """Computes an interval module approximation of a multiparameter filtration.
109
-
110
- Parameters
111
- ----------
112
- input: SimplexTreeMulti or Slicer-like.
113
- Holds the multifiltered complex.
114
- max_error: positive float
115
- Trade-off between approximation and computational complexity.
116
- Upper bound of the module approximation, in bottleneck distance,
117
- for interval-decomposable modules.
118
- nlines: int = 200
119
- Alternative to max_error;
120
- specifies the number of persistence computation used for the approximation.
121
- box : (Optional) pair of list of floats
122
- Defines a rectangle on which to compute the approximation.
123
- Format : [x,y], This defines a rectangle on which we draw the lines,
124
- uniformly drawn (with a max_error step).
125
- The first line is `x`.
126
- **Warning**: For custom boxes, and directions, you **must** ensure
127
- that the first line captures a generic barcode.
128
- direction: float[:] = []
129
- If given, the line are drawn with this angle.
130
- **Warning**: You must ensure that the first line, defined by box,
131
- captures a generic barcode.
132
- slicer_backend: Either "matrix","clement", or "graph".
133
- If a simplextree is given, it is first converted to this structure,
134
- with different choices of backends.
135
- minpres: (Optional) "mpfree" only for the moment.
136
- If given, and the input is a simplextree,
137
- computes a minimal presentation before starting the computation.
138
- A degree has to be given.
139
- degree: int Only required when minpres is given.
140
- Homological degree of the minimal degree.
141
- threshold: bool
142
- When true, intersects the module support with the box,
143
- i.e. no more infinite summands.
144
- verbose: bool
145
- Prints C++ infos.
146
- ignore_warning : bool
147
- Unless set to true, prevents computing on more than 10k lines.
148
- Useful to prevent a segmentation fault due to "infinite" recursion.
149
- Returns
150
- -------
151
- PyModule
152
- An interval decomposable module approximation of the module defined by the
153
- homology of this multi-filtration.
154
- """
155
- if isinstance(input, tuple) or isinstance(input, list):
156
- assert all(s.is_minpres for s in input), "Modules cannot be merged unless they are minimal presentations."
157
- assert np.unique([s.minpres_degree for s in input]).shape[0] == len(input), "Multiple modules are at the same degree, cannot merge modules"
158
- if len(input) == 0:
159
- return PyModule_f64()
160
- if n_jobs <= 1:
161
- modules = tuple(module_approximation(slicer, box, max_error, nlines, slicer_backend, minpres, degree, complete, threshold, verbose, ignore_warning, id, direction, swap_box_coords) for slicer in input)
162
- else:
163
- modules = tuple(Parallel(n_jobs=n_jobs, prefer="threads")(
164
- delayed(module_approximation)(slicer, box, max_error, nlines, slicer_backend, minpres, degree, complete, threshold, verbose, ignore_warning, id, direction, swap_box_coords)
165
- for slicer in input
166
- ))
167
- mod = PyModule_f64().set_box(PyBox_f64(*modules[0].get_box()))
168
- for i,m in enumerate(modules):
169
- mod.merge(m, input[i].minpres_degree)
170
- return mod
171
- if box is None:
172
- if is_simplextree_multi(input):
173
- box = input.filtration_bounds()
174
- else:
175
- box = input.filtration_bounds()
176
- box = np.asarray(box)
177
-
178
- # empty coords
179
- zero_idx = box[1] == box[0]
180
- if np.any(zero_idx):
181
- box[1] += zero_idx
182
-
183
- for i in swap_box_coords:
184
- box[0,i], box[1,i] = box[1,i], box[0,i]
185
- num_parameters = box.shape[1]
186
- if num_parameters <=0:
187
- num_parameters = box.shape[1]
188
- assert len(direction) == 0 or len(direction) == len(box[0]), f"Invalid line direction, has to be 0 or {num_parameters=}"
189
-
190
- prod = sum(np.abs(box[1] - box[0])[:i].prod() * np.abs(box[1] - box[0])[i+1:].prod() for i in range(0,num_parameters))
191
-
192
- if max_error <= 0:
193
- max_error = (prod/nlines)**(1/(num_parameters-1))
194
-
195
- if not ignore_warning and prod >= 10_000:
196
- raise ValueError(f"""
197
- Warning : the number of lines (around {np.round(prod)}) may be too high.
198
- Try to increase the precision parameter, or set `ignore_warning=True` to compute this module.
199
- Returning the trivial module."""
200
- )
201
- if is_simplextree_multi(input):
202
- input = multipers.Slicer(input,backend=slicer_backend, vineyard=True)
203
- assert is_slicer(input), "First argument must be a simplextree or a slicer !"
204
- return module_approximation_from_slicer(
205
- slicer=input,
206
- box=box,
207
- max_error=max_error,
208
- complete=complete,
209
- threshold=threshold,
210
- verbose=verbose,
211
- direction=direction,
212
- )
213
-
214
-
215
-
216
-
217
-
1
+ """!
2
+ @package mma
3
+ @brief Files containing the C++ cythonized functions.
4
+ @author David Loiseaux
5
+ @copyright Copyright (c) 2022 Inria.
6
+ """
7
+
8
+ # distutils: language = c++
9
+
10
+ ###########################################################################
11
+ ## PYTHON LIBRARIES
12
+ import gudhi as gd
13
+ import numpy as np
14
+ from typing import List
15
+ from joblib import Parallel, delayed
16
+ import sys
17
+
18
+ ###########################################################################
19
+ ## CPP CLASSES
20
+ from libc.stdint cimport intptr_t
21
+ from libc.stdint cimport uintptr_t
22
+
23
+ ###########################################################################
24
+ ## CYTHON TYPES
25
+ from libcpp.vector cimport vector
26
+ from libcpp.utility cimport pair
27
+ #from libcpp.list cimport list as clist
28
+ from libcpp cimport bool
29
+ from libcpp cimport int
30
+ from typing import Iterable,Optional, Literal
31
+ from cython.operator import dereference
32
+ #########################################################################
33
+ ## Multipersistence Module Approximation Classes
34
+ from multipers.mma_structures cimport *
35
+ from multipers.filtrations cimport *
36
+ from multipers.filtration_conversions cimport *
37
+ cimport numpy as cnp
38
+
39
+
40
+ #########################################################################
41
+ ## Small hack for typing
42
+ from multipers.simplex_tree_multi import is_simplextree_multi, SimplexTreeMulti_type
43
+ from multipers.slicer import Slicer_type, is_slicer
44
+ from multipers.mma_structures import *
45
+ from multipers.mma_structures import PyModule_type
46
+ from typing import Union
47
+ from multipers.slicer cimport _multiparameter_module_approximation_f32, _multiparameter_module_approximation_f64
48
+
49
+
50
+
51
+ def module_approximation_from_slicer(
52
+ slicer:Slicer_type,
53
+ box:Optional[np.ndarray]=None,
54
+ max_error=-1,
55
+ bool complete=True,
56
+ bool threshold=False,
57
+ bool verbose=False,
58
+ list[float] direction = [],
59
+ )->PyModule_type:
60
+
61
+ cdef Module[float] mod_f32
62
+ cdef Module[double] mod_f64
63
+ cdef intptr_t ptr
64
+ if not slicer.is_vine:
65
+ print(r"Got a non-vine slicer as an input. Use `vineyard=True` to remove this copy.", file=sys.stderr)
66
+ from multipers._slicer_meta import Slicer
67
+ slicer = Slicer(slicer, vineyard=True, backend="matrix")
68
+ direction_ = np.asarray(direction, dtype=slicer.dtype)
69
+ if slicer.dtype == np.float32:
70
+ approx_mod = PyModule_f32()
71
+ if box is None:
72
+ box = slicer.filtration_bounds()
73
+ mod_f32 = _multiparameter_module_approximation_f32(slicer,_py21c_f32(direction_), max_error,Box[float](box),threshold, complete, verbose)
74
+ ptr = <intptr_t>(&mod_f32)
75
+ elif slicer.dtype == np.float64:
76
+ approx_mod = PyModule_f64()
77
+ if box is None:
78
+ box = slicer.filtration_bounds()
79
+ mod_f64 = _multiparameter_module_approximation_f64(slicer,_py21c_f64(direction_), max_error,Box[double](box),threshold, complete, verbose)
80
+ ptr = <intptr_t>(&mod_f64)
81
+ else:
82
+ raise ValueError(f"Slicer must be float-like. Got {slicer.dtype}.")
83
+
84
+ approx_mod._set_from_ptr(ptr)
85
+
86
+ return approx_mod
87
+
88
+ def module_approximation(
89
+ input:Union[SimplexTreeMulti_type,Slicer_type, tuple],
90
+ box:Optional[np.ndarray]=None,
91
+ float max_error=-1,
92
+ int nlines=557,
93
+ slicer_backend:Literal["matrix","clement","graph"]="matrix",
94
+ minpres:Optional[Literal["mpfree"]]=None,
95
+ degree:Optional[int]=None,
96
+ bool complete=True,
97
+ bool threshold=False,
98
+ bool verbose=False,
99
+ bool ignore_warning=False,
100
+ id="",
101
+ list[float] direction = [],
102
+ list[int] swap_box_coords = [],
103
+ *,
104
+ int n_jobs = -1,
105
+ )->PyModule_type:
106
+ """Computes an interval module approximation of a multiparameter filtration.
107
+
108
+ Parameters
109
+ ----------
110
+ input: SimplexTreeMulti or Slicer-like.
111
+ Holds the multifiltered complex.
112
+ max_error: positive float
113
+ Trade-off between approximation and computational complexity.
114
+ Upper bound of the module approximation, in bottleneck distance,
115
+ for interval-decomposable modules.
116
+ nlines: int = 200
117
+ Alternative to max_error;
118
+ specifies the number of persistence computation used for the approximation.
119
+ box : (Optional) pair of list of floats
120
+ Defines a rectangle on which to compute the approximation.
121
+ Format : [x,y], This defines a rectangle on which we draw the lines,
122
+ uniformly drawn (with a max_error step).
123
+ The first line is `x`.
124
+ **Warning**: For custom boxes, and directions, you **must** ensure
125
+ that the first line captures a generic barcode.
126
+ direction: float[:] = []
127
+ If given, the line are drawn with this angle.
128
+ **Warning**: You must ensure that the first line, defined by box,
129
+ captures a generic barcode.
130
+ slicer_backend: Either "matrix","clement", or "graph".
131
+ If a simplextree is given, it is first converted to this structure,
132
+ with different choices of backends.
133
+ minpres: (Optional) "mpfree" only for the moment.
134
+ If given, and the input is a simplextree,
135
+ computes a minimal presentation before starting the computation.
136
+ A degree has to be given.
137
+ degree: int Only required when minpres is given.
138
+ Homological degree of the minimal degree.
139
+ threshold: bool
140
+ When true, intersects the module support with the box,
141
+ i.e. no more infinite summands.
142
+ verbose: bool
143
+ Prints C++ infos.
144
+ ignore_warning : bool
145
+ Unless set to true, prevents computing on more than 10k lines.
146
+ Useful to prevent a segmentation fault due to "infinite" recursion.
147
+ Returns
148
+ -------
149
+ PyModule
150
+ An interval decomposable module approximation of the module defined by the
151
+ homology of this multi-filtration.
152
+ """
153
+ if isinstance(input, tuple) or isinstance(input, list):
154
+ assert all(s.is_minpres for s in input), "Modules cannot be merged unless they are minimal presentations."
155
+ assert np.unique([s.minpres_degree for s in input]).shape[0] == len(input), "Multiple modules are at the same degree, cannot merge modules"
156
+ if len(input) == 0:
157
+ return PyModule_f64()
158
+ if n_jobs <= 1:
159
+ modules = tuple(module_approximation(slicer, box, max_error, nlines, slicer_backend, minpres, degree, complete, threshold, verbose, ignore_warning, id, direction, swap_box_coords) for slicer in input)
160
+ else:
161
+ modules = tuple(Parallel(n_jobs=n_jobs, prefer="threads")(
162
+ delayed(module_approximation)(slicer, box, max_error, nlines, slicer_backend, minpres, degree, complete, threshold, verbose, ignore_warning, id, direction, swap_box_coords)
163
+ for slicer in input
164
+ ))
165
+ mod = PyModule_f64().set_box(PyBox_f64(*modules[0].get_box()))
166
+ for i,m in enumerate(modules):
167
+ mod.merge(m, input[i].minpres_degree)
168
+ return mod
169
+ if len(input) == 0:
170
+ return PyModule_f64()
171
+ if box is None:
172
+ if is_simplextree_multi(input):
173
+ box = input.filtration_bounds()
174
+ else:
175
+ box = input.filtration_bounds()
176
+ box = np.asarray(box)
177
+
178
+ # empty coords
179
+ zero_idx = box[1] == box[0]
180
+ if np.any(zero_idx):
181
+ box[1] += zero_idx
182
+
183
+ for i in swap_box_coords:
184
+ box[0,i], box[1,i] = box[1,i], box[0,i]
185
+ num_parameters = box.shape[1]
186
+ if num_parameters <=0:
187
+ num_parameters = box.shape[1]
188
+ assert len(direction) == 0 or len(direction) == len(box[0]), f"Invalid line direction, has to be 0 or {num_parameters=}"
189
+
190
+ prod = sum(np.abs(box[1] - box[0])[:i].prod() * np.abs(box[1] - box[0])[i+1:].prod() for i in range(0,num_parameters))
191
+
192
+ if max_error <= 0:
193
+ max_error = (prod/nlines)**(1/(num_parameters-1))
194
+
195
+ if not ignore_warning and prod >= 10_000:
196
+ raise ValueError(f"""
197
+ Warning : the number of lines (around {np.round(prod)}) may be too high.
198
+ Try to increase the precision parameter, or set `ignore_warning=True` to compute this module.
199
+ Returning the trivial module."""
200
+ )
201
+ if is_simplextree_multi(input):
202
+ from multipers._slicer_meta import Slicer
203
+ input = Slicer(input,backend=slicer_backend, vineyard=True)
204
+ assert is_slicer(input), "First argument must be a simplextree or a slicer !"
205
+ return module_approximation_from_slicer(
206
+ slicer=input,
207
+ box=box,
208
+ max_error=max_error,
209
+ complete=complete,
210
+ threshold=threshold,
211
+ verbose=verbose,
212
+ direction=direction,
213
+ )
214
+
215
+
216
+
217
+
218
+
multipers/pickle.py CHANGED
@@ -1,53 +1,90 @@
1
- import numpy as np
2
-
3
- def save_with_axis(path:str, signed_measures):
4
- np.savez(path,
5
- **{f"{i}_{axis}_{degree}":np.c_[sm_of_degree[0],sm_of_degree[1][:,np.newaxis]] for i,sm in enumerate(signed_measures) for axis,sm_of_axis in enumerate(sm) for degree,sm_of_degree in enumerate(sm_of_axis)},
6
- )
7
-
8
- def save_without_axis(path:str, signed_measures):
9
- np.savez(path,
10
- **{f"{i}_{degree}":np.c_[sm_of_degree[0],sm_of_degree[1][:,np.newaxis]] for i,sm in enumerate(signed_measures) for degree,sm_of_degree in enumerate(sm)},
11
- )
12
-
13
- def get_sm_with_axis(sms,idx,axis,degree):
14
- sm = sms[f"{idx}_{axis}_{degree}"]
15
- return (sm[:,:-1],sm[:,-1])
16
- def get_sm_without_axis(sms,idx,degree):
17
- sm = sms[f"{idx}_{degree}"]
18
- return (sm[:,:-1],sm[:,-1])
19
-
20
-
21
- def load_without_axis(sms):
22
- indices = np.array([[int(i) for i in key.split('_')] for key in sms.keys()], dtype=int)
23
- num_data,num_degrees = indices.max(axis=0)+1
24
- signed_measures_reconstructed = [[get_sm_without_axis(sms,idx,degree) for degree in range(num_degrees)] for idx in range(num_data)]
25
- return signed_measures_reconstructed
26
- # test : np.all([np.array_equal(a[0],b[0]) and np.array_equal(a[1],b[1]) and len(a) == len(b) == 2 for x,y in zip(signed_measures_reconstructed,signed_measures_reconstructed) for a,b in zip(x,y)])
27
-
28
- def load_with_axis(sms):
29
- indices = np.array([[int(i) for i in key.split('_')] for key in sms.keys()], dtype=int)
30
- num_data,num_axis,num_degrees = indices.max(axis=0)+1
31
- signed_measures_reconstructed = [[[get_sm_with_axis(sms,idx,axis,degree) for degree in range(num_degrees)] for axis in range(num_axis)] for idx in range(num_data)]
32
- return signed_measures_reconstructed
33
-
34
- def save(path:str, signed_measures):
35
- if isinstance(signed_measures[0][0], tuple):
36
- save_without_axis(path=path,signed_measures=signed_measures)
37
- else:
38
- save_with_axis(path=path,signed_measures=signed_measures)
39
-
40
- def load(path:str):
41
- sms = np.load(path)
42
- item=None
43
- for i in sms.keys():
44
- item=i
45
- break
46
- n = len(item.split('_'))
47
- match n:
48
- case 2:
49
- return load_without_axis(sms)
50
- case 3:
51
- return load_with_axis(sms)
52
- case _:
53
- raise Exception("Invalid Signed Measure !")
1
+ import numpy as np
2
+
3
+
4
+ def save_with_axis(path: str, signed_measures):
5
+ np.savez(
6
+ path,
7
+ **{
8
+ f"{i}_{axis}_{degree}": np.c_[
9
+ sm_of_degree[0], sm_of_degree[1][:, np.newaxis]
10
+ ]
11
+ for i, sm in enumerate(signed_measures)
12
+ for axis, sm_of_axis in enumerate(sm)
13
+ for degree, sm_of_degree in enumerate(sm_of_axis)
14
+ },
15
+ )
16
+
17
+
18
+ def save_without_axis(path: str, signed_measures):
19
+ np.savez(
20
+ path,
21
+ **{
22
+ f"{i}_{degree}": np.c_[sm_of_degree[0], sm_of_degree[1][:, np.newaxis]]
23
+ for i, sm in enumerate(signed_measures)
24
+ for degree, sm_of_degree in enumerate(sm)
25
+ },
26
+ )
27
+
28
+
29
+ def get_sm_with_axis(sms, idx, axis, degree):
30
+ sm = sms[f"{idx}_{axis}_{degree}"]
31
+ return (sm[:, :-1], sm[:, -1])
32
+
33
+
34
+ def get_sm_without_axis(sms, idx, degree):
35
+ sm = sms[f"{idx}_{degree}"]
36
+ return (sm[:, :-1], sm[:, -1])
37
+
38
+
39
+ def load_without_axis(sms):
40
+ indices = np.array(
41
+ [[int(i) for i in key.split("_")] for key in sms.keys()], dtype=int
42
+ )
43
+ num_data, num_degrees = indices.max(axis=0) + 1
44
+ signed_measures_reconstructed = [
45
+ [get_sm_without_axis(sms, idx, degree) for degree in range(num_degrees)]
46
+ for idx in range(num_data)
47
+ ]
48
+ return signed_measures_reconstructed
49
+
50
+
51
+ # test : np.all([np.array_equal(a[0],b[0]) and np.array_equal(a[1],b[1]) and len(a) == len(b) == 2 for x,y in zip(signed_measures_reconstructed,signed_measures_reconstructed) for a,b in zip(x,y)])
52
+
53
+
54
+ def load_with_axis(sms):
55
+ indices = np.array(
56
+ [[int(i) for i in key.split("_")] for key in sms.keys()], dtype=int
57
+ )
58
+ num_data, num_axis, num_degrees = indices.max(axis=0) + 1
59
+ signed_measures_reconstructed = [
60
+ [
61
+ [get_sm_with_axis(sms, idx, axis, degree) for degree in range(num_degrees)]
62
+ for axis in range(num_axis)
63
+ ]
64
+ for idx in range(num_data)
65
+ ]
66
+ return signed_measures_reconstructed
67
+
68
+
69
+ def save(path: str, signed_measures):
70
+ if isinstance(signed_measures[0][0], tuple):
71
+ save_without_axis(path=path, signed_measures=signed_measures)
72
+ else:
73
+ save_with_axis(path=path, signed_measures=signed_measures)
74
+
75
+
76
+ def load(path: str):
77
+ sms = np.load(path)
78
+ item = None
79
+ for i in sms.keys():
80
+ item = i
81
+ break
82
+ n = len(item.split("_"))
83
+ match n:
84
+ case 2:
85
+ return load_without_axis(sms)
86
+ case 3:
87
+ return load_with_axis(sms)
88
+ case _:
89
+ raise Exception("Invalid Signed Measure !")
90
+