multipers 2.3.3b6__cp310-cp310-macosx_11_0_arm64.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 (183) hide show
  1. multipers/.dylibs/libc++.1.0.dylib +0 -0
  2. multipers/.dylibs/libtbb.12.16.dylib +0 -0
  3. multipers/__init__.py +33 -0
  4. multipers/_signed_measure_meta.py +453 -0
  5. multipers/_slicer_meta.py +211 -0
  6. multipers/array_api/__init__.py +45 -0
  7. multipers/array_api/numpy.py +41 -0
  8. multipers/array_api/torch.py +58 -0
  9. multipers/data/MOL2.py +458 -0
  10. multipers/data/UCR.py +18 -0
  11. multipers/data/__init__.py +1 -0
  12. multipers/data/graphs.py +466 -0
  13. multipers/data/immuno_regions.py +27 -0
  14. multipers/data/minimal_presentation_to_st_bf.py +0 -0
  15. multipers/data/pytorch2simplextree.py +91 -0
  16. multipers/data/shape3d.py +101 -0
  17. multipers/data/synthetic.py +113 -0
  18. multipers/distances.py +202 -0
  19. multipers/filtration_conversions.pxd +229 -0
  20. multipers/filtration_conversions.pxd.tp +84 -0
  21. multipers/filtrations/__init__.py +18 -0
  22. multipers/filtrations/density.py +574 -0
  23. multipers/filtrations/filtrations.py +361 -0
  24. multipers/filtrations.pxd +224 -0
  25. multipers/function_rips.cpython-310-darwin.so +0 -0
  26. multipers/function_rips.pyx +105 -0
  27. multipers/grids.cpython-310-darwin.so +0 -0
  28. multipers/grids.pyx +433 -0
  29. multipers/gudhi/Persistence_slices_interface.h +132 -0
  30. multipers/gudhi/Simplex_tree_interface.h +239 -0
  31. multipers/gudhi/Simplex_tree_multi_interface.h +551 -0
  32. multipers/gudhi/cubical_to_boundary.h +59 -0
  33. multipers/gudhi/gudhi/Bitmap_cubical_complex.h +450 -0
  34. multipers/gudhi/gudhi/Bitmap_cubical_complex_base.h +1070 -0
  35. multipers/gudhi/gudhi/Bitmap_cubical_complex_periodic_boundary_conditions_base.h +579 -0
  36. multipers/gudhi/gudhi/Debug_utils.h +45 -0
  37. multipers/gudhi/gudhi/Fields/Multi_field.h +484 -0
  38. multipers/gudhi/gudhi/Fields/Multi_field_operators.h +455 -0
  39. multipers/gudhi/gudhi/Fields/Multi_field_shared.h +450 -0
  40. multipers/gudhi/gudhi/Fields/Multi_field_small.h +531 -0
  41. multipers/gudhi/gudhi/Fields/Multi_field_small_operators.h +507 -0
  42. multipers/gudhi/gudhi/Fields/Multi_field_small_shared.h +531 -0
  43. multipers/gudhi/gudhi/Fields/Z2_field.h +355 -0
  44. multipers/gudhi/gudhi/Fields/Z2_field_operators.h +376 -0
  45. multipers/gudhi/gudhi/Fields/Zp_field.h +420 -0
  46. multipers/gudhi/gudhi/Fields/Zp_field_operators.h +400 -0
  47. multipers/gudhi/gudhi/Fields/Zp_field_shared.h +418 -0
  48. multipers/gudhi/gudhi/Flag_complex_edge_collapser.h +337 -0
  49. multipers/gudhi/gudhi/Matrix.h +2107 -0
  50. multipers/gudhi/gudhi/Multi_critical_filtration.h +1038 -0
  51. multipers/gudhi/gudhi/Multi_persistence/Box.h +174 -0
  52. multipers/gudhi/gudhi/Multi_persistence/Line.h +282 -0
  53. multipers/gudhi/gudhi/Off_reader.h +173 -0
  54. multipers/gudhi/gudhi/One_critical_filtration.h +1441 -0
  55. multipers/gudhi/gudhi/Persistence_matrix/Base_matrix.h +769 -0
  56. multipers/gudhi/gudhi/Persistence_matrix/Base_matrix_with_column_compression.h +686 -0
  57. multipers/gudhi/gudhi/Persistence_matrix/Boundary_matrix.h +842 -0
  58. multipers/gudhi/gudhi/Persistence_matrix/Chain_matrix.h +1350 -0
  59. multipers/gudhi/gudhi/Persistence_matrix/Id_to_index_overlay.h +1105 -0
  60. multipers/gudhi/gudhi/Persistence_matrix/Position_to_index_overlay.h +859 -0
  61. multipers/gudhi/gudhi/Persistence_matrix/RU_matrix.h +910 -0
  62. multipers/gudhi/gudhi/Persistence_matrix/allocators/entry_constructors.h +139 -0
  63. multipers/gudhi/gudhi/Persistence_matrix/base_pairing.h +230 -0
  64. multipers/gudhi/gudhi/Persistence_matrix/base_swap.h +211 -0
  65. multipers/gudhi/gudhi/Persistence_matrix/boundary_cell_position_to_id_mapper.h +60 -0
  66. multipers/gudhi/gudhi/Persistence_matrix/boundary_face_position_to_id_mapper.h +60 -0
  67. multipers/gudhi/gudhi/Persistence_matrix/chain_pairing.h +136 -0
  68. multipers/gudhi/gudhi/Persistence_matrix/chain_rep_cycles.h +190 -0
  69. multipers/gudhi/gudhi/Persistence_matrix/chain_vine_swap.h +616 -0
  70. multipers/gudhi/gudhi/Persistence_matrix/columns/chain_column_extra_properties.h +150 -0
  71. multipers/gudhi/gudhi/Persistence_matrix/columns/column_dimension_holder.h +106 -0
  72. multipers/gudhi/gudhi/Persistence_matrix/columns/column_utilities.h +219 -0
  73. multipers/gudhi/gudhi/Persistence_matrix/columns/entry_types.h +327 -0
  74. multipers/gudhi/gudhi/Persistence_matrix/columns/heap_column.h +1140 -0
  75. multipers/gudhi/gudhi/Persistence_matrix/columns/intrusive_list_column.h +934 -0
  76. multipers/gudhi/gudhi/Persistence_matrix/columns/intrusive_set_column.h +934 -0
  77. multipers/gudhi/gudhi/Persistence_matrix/columns/list_column.h +980 -0
  78. multipers/gudhi/gudhi/Persistence_matrix/columns/naive_vector_column.h +1092 -0
  79. multipers/gudhi/gudhi/Persistence_matrix/columns/row_access.h +192 -0
  80. multipers/gudhi/gudhi/Persistence_matrix/columns/set_column.h +921 -0
  81. multipers/gudhi/gudhi/Persistence_matrix/columns/small_vector_column.h +1093 -0
  82. multipers/gudhi/gudhi/Persistence_matrix/columns/unordered_set_column.h +1012 -0
  83. multipers/gudhi/gudhi/Persistence_matrix/columns/vector_column.h +1244 -0
  84. multipers/gudhi/gudhi/Persistence_matrix/matrix_dimension_holders.h +186 -0
  85. multipers/gudhi/gudhi/Persistence_matrix/matrix_row_access.h +164 -0
  86. multipers/gudhi/gudhi/Persistence_matrix/ru_pairing.h +156 -0
  87. multipers/gudhi/gudhi/Persistence_matrix/ru_rep_cycles.h +376 -0
  88. multipers/gudhi/gudhi/Persistence_matrix/ru_vine_swap.h +540 -0
  89. multipers/gudhi/gudhi/Persistent_cohomology/Field_Zp.h +118 -0
  90. multipers/gudhi/gudhi/Persistent_cohomology/Multi_field.h +173 -0
  91. multipers/gudhi/gudhi/Persistent_cohomology/Persistent_cohomology_column.h +128 -0
  92. multipers/gudhi/gudhi/Persistent_cohomology.h +745 -0
  93. multipers/gudhi/gudhi/Points_off_io.h +171 -0
  94. multipers/gudhi/gudhi/Simple_object_pool.h +69 -0
  95. multipers/gudhi/gudhi/Simplex_tree/Simplex_tree_iterators.h +463 -0
  96. multipers/gudhi/gudhi/Simplex_tree/Simplex_tree_node_explicit_storage.h +83 -0
  97. multipers/gudhi/gudhi/Simplex_tree/Simplex_tree_siblings.h +106 -0
  98. multipers/gudhi/gudhi/Simplex_tree/Simplex_tree_star_simplex_iterators.h +277 -0
  99. multipers/gudhi/gudhi/Simplex_tree/hooks_simplex_base.h +62 -0
  100. multipers/gudhi/gudhi/Simplex_tree/indexing_tag.h +27 -0
  101. multipers/gudhi/gudhi/Simplex_tree/serialization_utils.h +62 -0
  102. multipers/gudhi/gudhi/Simplex_tree/simplex_tree_options.h +157 -0
  103. multipers/gudhi/gudhi/Simplex_tree.h +2794 -0
  104. multipers/gudhi/gudhi/Simplex_tree_multi.h +152 -0
  105. multipers/gudhi/gudhi/distance_functions.h +62 -0
  106. multipers/gudhi/gudhi/graph_simplicial_complex.h +104 -0
  107. multipers/gudhi/gudhi/persistence_interval.h +253 -0
  108. multipers/gudhi/gudhi/persistence_matrix_options.h +170 -0
  109. multipers/gudhi/gudhi/reader_utils.h +367 -0
  110. multipers/gudhi/mma_interface_coh.h +256 -0
  111. multipers/gudhi/mma_interface_h0.h +223 -0
  112. multipers/gudhi/mma_interface_matrix.h +293 -0
  113. multipers/gudhi/naive_merge_tree.h +536 -0
  114. multipers/gudhi/scc_io.h +310 -0
  115. multipers/gudhi/truc.h +1403 -0
  116. multipers/io.cpython-310-darwin.so +0 -0
  117. multipers/io.pyx +644 -0
  118. multipers/ml/__init__.py +0 -0
  119. multipers/ml/accuracies.py +90 -0
  120. multipers/ml/invariants_with_persistable.py +79 -0
  121. multipers/ml/kernels.py +176 -0
  122. multipers/ml/mma.py +713 -0
  123. multipers/ml/one.py +472 -0
  124. multipers/ml/point_clouds.py +352 -0
  125. multipers/ml/signed_measures.py +1589 -0
  126. multipers/ml/sliced_wasserstein.py +461 -0
  127. multipers/ml/tools.py +113 -0
  128. multipers/mma_structures.cpython-310-darwin.so +0 -0
  129. multipers/mma_structures.pxd +128 -0
  130. multipers/mma_structures.pyx +2786 -0
  131. multipers/mma_structures.pyx.tp +1094 -0
  132. multipers/multi_parameter_rank_invariant/diff_helpers.h +84 -0
  133. multipers/multi_parameter_rank_invariant/euler_characteristic.h +97 -0
  134. multipers/multi_parameter_rank_invariant/function_rips.h +322 -0
  135. multipers/multi_parameter_rank_invariant/hilbert_function.h +769 -0
  136. multipers/multi_parameter_rank_invariant/persistence_slices.h +148 -0
  137. multipers/multi_parameter_rank_invariant/rank_invariant.h +369 -0
  138. multipers/multiparameter_edge_collapse.py +41 -0
  139. multipers/multiparameter_module_approximation/approximation.h +2330 -0
  140. multipers/multiparameter_module_approximation/combinatory.h +129 -0
  141. multipers/multiparameter_module_approximation/debug.h +107 -0
  142. multipers/multiparameter_module_approximation/euler_curves.h +0 -0
  143. multipers/multiparameter_module_approximation/format_python-cpp.h +286 -0
  144. multipers/multiparameter_module_approximation/heap_column.h +238 -0
  145. multipers/multiparameter_module_approximation/images.h +79 -0
  146. multipers/multiparameter_module_approximation/list_column.h +174 -0
  147. multipers/multiparameter_module_approximation/list_column_2.h +232 -0
  148. multipers/multiparameter_module_approximation/ru_matrix.h +347 -0
  149. multipers/multiparameter_module_approximation/set_column.h +135 -0
  150. multipers/multiparameter_module_approximation/structure_higher_dim_barcode.h +36 -0
  151. multipers/multiparameter_module_approximation/unordered_set_column.h +166 -0
  152. multipers/multiparameter_module_approximation/utilities.h +403 -0
  153. multipers/multiparameter_module_approximation/vector_column.h +223 -0
  154. multipers/multiparameter_module_approximation/vector_matrix.h +331 -0
  155. multipers/multiparameter_module_approximation/vineyards.h +464 -0
  156. multipers/multiparameter_module_approximation/vineyards_trajectories.h +649 -0
  157. multipers/multiparameter_module_approximation.cpython-310-darwin.so +0 -0
  158. multipers/multiparameter_module_approximation.pyx +235 -0
  159. multipers/pickle.py +90 -0
  160. multipers/plots.py +456 -0
  161. multipers/point_measure.cpython-310-darwin.so +0 -0
  162. multipers/point_measure.pyx +395 -0
  163. multipers/simplex_tree_multi.cpython-310-darwin.so +0 -0
  164. multipers/simplex_tree_multi.pxd +134 -0
  165. multipers/simplex_tree_multi.pyx +10840 -0
  166. multipers/simplex_tree_multi.pyx.tp +2009 -0
  167. multipers/slicer.cpython-310-darwin.so +0 -0
  168. multipers/slicer.pxd +3034 -0
  169. multipers/slicer.pxd.tp +234 -0
  170. multipers/slicer.pyx +20481 -0
  171. multipers/slicer.pyx.tp +1088 -0
  172. multipers/tensor/tensor.h +672 -0
  173. multipers/tensor.pxd +13 -0
  174. multipers/test.pyx +44 -0
  175. multipers/tests/__init__.py +62 -0
  176. multipers/torch/__init__.py +1 -0
  177. multipers/torch/diff_grids.py +240 -0
  178. multipers/torch/rips_density.py +310 -0
  179. multipers-2.3.3b6.dist-info/METADATA +128 -0
  180. multipers-2.3.3b6.dist-info/RECORD +183 -0
  181. multipers-2.3.3b6.dist-info/WHEEL +6 -0
  182. multipers-2.3.3b6.dist-info/licenses/LICENSE +21 -0
  183. multipers-2.3.3b6.dist-info/top_level.txt +1 -0
Binary file
Binary file
multipers/__init__.py ADDED
@@ -0,0 +1,33 @@
1
+ from importlib.metadata import version as _version
2
+
3
+ __version__ = _version("multipers")
4
+ # Doc
5
+ from multipers import (
6
+ data,
7
+ filtrations,
8
+ grids,
9
+ io,
10
+ multiparameter_module_approximation,
11
+ simplex_tree_multi,
12
+ slicer,
13
+ )
14
+ from multipers._signed_measure_meta import signed_measure
15
+
16
+ # Shortcuts
17
+ from multipers._slicer_meta import Slicer
18
+ from multipers.multiparameter_module_approximation import module_approximation
19
+ from multipers.simplex_tree_multi import SimplexTreeMulti
20
+
21
+ __all__ = [
22
+ "data",
23
+ "filtrations",
24
+ "grids",
25
+ "io",
26
+ "multiparameter_module_approximation",
27
+ "simplex_tree_multi",
28
+ "slicer",
29
+ "signed_measure",
30
+ "Slicer",
31
+ "module_approximation",
32
+ "SimplexTreeMulti",
33
+ ]
@@ -0,0 +1,453 @@
1
+ from collections.abc import Iterable, Sequence
2
+ from typing import Optional, Union
3
+
4
+ import numpy as np
5
+
6
+ from multipers.grids import compute_grid, sms_in_grid
7
+ from multipers.plots import plot_signed_measures
8
+ from multipers.point_measure import clean_sms, zero_out_sms
9
+ from multipers.simplex_tree_multi import (
10
+ SimplexTreeMulti_type,
11
+ _available_strategies,
12
+ is_simplextree_multi,
13
+ )
14
+ from multipers.slicer import (
15
+ Slicer_type,
16
+ _hilbert_signed_measure,
17
+ _rank_from_slicer,
18
+ is_slicer,
19
+ )
20
+
21
+
22
+ def signed_measure(
23
+ filtered_complex: Union[SimplexTreeMulti_type, Slicer_type],
24
+ degree: Optional[int] = None,
25
+ degrees: Sequence[int | None] = [],
26
+ mass_default=None,
27
+ grid_strategy: _available_strategies = "exact",
28
+ invariant: Optional[str] = None,
29
+ plot: bool = False,
30
+ verbose: bool = False,
31
+ n_jobs: int = -1,
32
+ expand_collapse: bool = False,
33
+ backend: Optional[str] = None, # deprecated
34
+ grid: Optional[Iterable] = None,
35
+ coordinate_measure: bool = False,
36
+ num_collapses: int = 0, # TODO : deprecate
37
+ clean: Optional[bool] = None,
38
+ vineyard: bool = False,
39
+ grid_conversion: Optional[Iterable] = None,
40
+ ignore_infinite_filtration_values: bool = True,
41
+ **infer_grid_kwargs,
42
+ ) -> list[tuple[np.ndarray, np.ndarray]]:
43
+ r"""
44
+ Computes the signed measures given by the decomposition of the hilbert
45
+ function or the euler characteristic, or the rank invariant.
46
+
47
+ Input
48
+ -----
49
+ - filtered_complex: given by a simplextree or a slicer.
50
+ - degree:int|None / degrees:list[int] the degrees to compute.
51
+ None represents the euler characteristic.
52
+ - mass_default: Either None, or 'auto' or 'inf', or array-like of floats.
53
+ Where to put the default mass to get a zero-mass measure.
54
+ This corresponds to zero-out the filtered complex outside of $\{ x\in \mathbb R^n \mid x\le `mass_default`\}$
55
+ - invariant: The invariant to use, either "hilbert", "rank", or "euler".
56
+ - plot:bool, plots the computed measures if true.
57
+ - n_jobs:int, number of jobs. Defaults to #cpu.
58
+ - verbose:bool, prints c++ logs.
59
+ - expand_collapse: when the input is a simplextree,
60
+ only expands the complex when computing 1-dimensional slices.
61
+ Meant to reduce memory footprint at some computational expense.
62
+ - backend:str reduces first the filtered complex using an external library `backend`,
63
+ see ``backend`` in :func:`multipers.io.reduce_complex`.
64
+ - grid: If given, the computations will be done on the restriction of the filtered complex to this grid.
65
+ It can also be used for auto-differentiation, i.e., if the grid is a list of pytorch tensors,
66
+ then the output measure will be pytorch-differentiable.
67
+ - grid_strategy: If not squeezed yet, and no grid is given,
68
+ the strategy to coarsen the grid; see ``strategy`` in :func:`multipers.grids.compute_grid`.
69
+ - coordinate_measure: bool, if True, compute the signed measure as a coordinates given in grid.
70
+ - num_collapses: int, if `filtered_complex` is a simplextree, does some collapses if possible.
71
+ - clean: if True, reduces the measure. It is not necessary in general.
72
+ - ignore_infinite_filtration_values: Backend optimization.
73
+
74
+ Output
75
+ ------
76
+
77
+ `[signed_measure_of_degree for degree in degrees]`
78
+ with `signed_measure_of_degree` of the form `(dirac location, dirac weights)`.
79
+
80
+ Notes on computational backends
81
+ -------------------------------
82
+ There are several backends for each of these computations.
83
+ The backend for computations used can be displayed with `verbose=True`, use it!
84
+ Also note that if `backend` is given, then the input will be converted to a slicer.
85
+ - Euler: is always computed by summing the weights of the simplices
86
+ - Hilbert: is computed by computing persistence on slices, and a Möbius inversion,
87
+ unless the detected input is a minimal presentation (i.e., `filtered_complex.is_minpres`),
88
+ which in that case, doesn't need any computation.
89
+ - If the input is a simplextree, this is done via a the standard Gudhi implementation,
90
+ with parallel (TBB) computations of slices.
91
+ - If the input is a slicer then
92
+ - If the input is vineyard-capable, then slices are computed via vineyards updates.
93
+ It is slower in general, but faster if single threaded.
94
+ In particular, it is usually faster to use this backend if you want to compute the
95
+ signed measure of multiple datasets in a parallel context.
96
+ - Otherwise, slices are computed in parallel.
97
+ It is usually faster to use this backend if not in a parallel context.
98
+ - Rank: Same as Hilbert.
99
+ """
100
+ if backend is not None:
101
+ raise ValueError(
102
+ "backend is deprecated. reduce the complex before this function."
103
+ )
104
+ if num_collapses > 0:
105
+ raise ValueError(
106
+ "num_collapses is deprecated. reduce the complex before this function."
107
+ )
108
+ ## TODO : add timings in verbose
109
+ if len(filtered_complex) == 0:
110
+ return [
111
+ (
112
+ np.empty((0, 2), dtype=filtered_complex.dtype),
113
+ np.empty(shape=(0,), dtype=int),
114
+ )
115
+ ]
116
+ if grid_conversion is not None:
117
+ grid = tuple(f for f in grid_conversion)
118
+ raise DeprecationWarning(
119
+ """
120
+ Parameter `grid_conversion` is deprecated. Use `grid` instead.
121
+ Most of the time there is no conversion anymore.
122
+ """
123
+ )
124
+
125
+ if degree is not None or len(degrees) == 0:
126
+ degrees = list(degrees) + [degree]
127
+ if None in degrees:
128
+ assert (
129
+ len(degrees) == 1
130
+ ), f"Can only compute one invariant at the time. Got {degrees=}, {invariant=}."
131
+ assert invariant is None or not (
132
+ "hilbert" in invariant or "rank" in invariant
133
+ ), f"Hilbert and Rank cannot compute `None` degree. got {degrees=}, {invariant=}."
134
+ invariant = "euler"
135
+ if clean is None:
136
+ clean = True if None in degrees else False
137
+
138
+ assert invariant is None or invariant in [
139
+ "hilbert",
140
+ "rank_invariant",
141
+ "euler",
142
+ "rank",
143
+ "euler_characteristic",
144
+ "hilbert_function",
145
+ "rectangle",
146
+ "hook",
147
+ ]
148
+
149
+ assert (
150
+ not plot or filtered_complex.num_parameters == 2
151
+ ), f"Can only plot 2d measures. Got {filtered_complex.num_parameters=}."
152
+
153
+ if grid is None:
154
+ if not filtered_complex.is_squeezed:
155
+ grid = compute_grid(
156
+ filtered_complex, strategy=grid_strategy, **infer_grid_kwargs
157
+ )
158
+ else:
159
+ grid = filtered_complex.filtration_grid
160
+
161
+ if mass_default is None:
162
+ mass_default = mass_default
163
+ elif isinstance(mass_default, str):
164
+ if mass_default == "auto":
165
+ mass_default = np.array([1.1 * np.max(f) - 0.1 * np.min(f) for f in grid])
166
+ elif mass_default == "inf":
167
+ mass_default = np.array([np.inf] * filtered_complex.num_parameters)
168
+ else:
169
+ raise NotImplementedError
170
+ else:
171
+ mass_default = np.asarray(mass_default)
172
+ assert (
173
+ mass_default.ndim == 1
174
+ and mass_default.shape[0] == filtered_complex.num_parameters
175
+ )
176
+
177
+ if not filtered_complex.is_squeezed:
178
+ if verbose:
179
+ print("Coarsening complex...", end="")
180
+ filtered_complex_ = filtered_complex.grid_squeeze(grid)
181
+ if verbose:
182
+ print("Done.")
183
+ else:
184
+ filtered_complex_ = filtered_complex.copy()
185
+
186
+ # assert filtered_complex_.is_squeezed
187
+ if None not in degrees:
188
+ if is_slicer(filtered_complex_) and filtered_complex_.is_minpres:
189
+ pass
190
+ else:
191
+ max_degree = np.max(degrees) + 1
192
+ if verbose:
193
+ print(f"Pruning simplicies up to {max_degree}...", end="")
194
+ if filtered_complex_.dimension > max_degree:
195
+ filtered_complex_.prune_above_dimension(max_degree)
196
+ if verbose:
197
+ print("Done.")
198
+
199
+ num_parameters = filtered_complex.num_parameters
200
+ assert num_parameters == len(
201
+ grid
202
+ ), f"Number of parameter do not coincide. Got (grid) {len(grid)} and (filtered complex) {num_parameters}."
203
+
204
+ # if is_simplextree_multi(filtered_complex_):
205
+ # # if num_collapses != 0:
206
+ # # if verbose:
207
+ # # print("Collapsing edges...", end="")
208
+ # # filtered_complex_.collapse_edges(num_collapses)
209
+ # # if verbose:
210
+ # # print("Done.")
211
+ # # if backend is not None:
212
+ # # filtered_complex_ = mp.Slicer(filtered_complex_, vineyard=vineyard)
213
+
214
+ fix_mass_default = mass_default is not None
215
+ if is_slicer(filtered_complex_):
216
+ if verbose:
217
+ print("Input is a slicer.")
218
+ if backend is not None and not filtered_complex_.is_minpres:
219
+ raise ValueError("giving a backend to this function is deprecated")
220
+ # from multipers.slicer import minimal_presentation
221
+ #
222
+ # assert (
223
+ # invariant != "euler"
224
+ # ), "Euler Characteristic cannot be speed up by a backend"
225
+ # # This returns a list of reduced complexes
226
+ # if verbose:
227
+ # print("Reducing complex...", end="")
228
+ # reduced_complex = minimal_presentation(
229
+ # filtered_complex_,
230
+ # degrees=degrees,
231
+ # backend=backend,
232
+ # vineyard=vineyard,
233
+ # verbose=verbose,
234
+ # )
235
+ # if verbose:
236
+ # print("Done.")
237
+ # if invariant is not None and "rank" in invariant:
238
+ # if verbose:
239
+ # print("Computing rank...", end="")
240
+ # sms = [
241
+ # _rank_from_slicer(
242
+ # s,
243
+ # degrees=[d],
244
+ # n_jobs=n_jobs,
245
+ # # grid_shape=tuple(len(g) for g in grid),
246
+ # zero_pad=fix_mass_default,
247
+ # ignore_inf=ignore_infinite_filtration_values,
248
+ # )[0]
249
+ # for s, d in zip(reduced_complex, degrees)
250
+ # ]
251
+ # fix_mass_default = False
252
+ # if verbose:
253
+ # print("Done.")
254
+ # else:
255
+ # if verbose:
256
+ # print("Reduced slicer. Retrieving measure from it...", end="")
257
+ # sms = [
258
+ # _signed_measure_from_slicer(
259
+ # s,
260
+ # shift=(
261
+ # reduced_complex.minpres_degree & 1 if d is None else d & 1
262
+ # ),
263
+ # )[0]
264
+ # for s, d in zip(reduced_complex, degrees)
265
+ # ]
266
+ # if verbose:
267
+ # print("Done.")
268
+ else: # No backend
269
+ if invariant is not None and ("rank" in invariant or "hook" in invariant or "rectangle" in invariant):
270
+ degrees = np.asarray(degrees, dtype=int)
271
+ if verbose:
272
+ print("Computing rank...", end="")
273
+ sms = _rank_from_slicer(
274
+ filtered_complex_,
275
+ degrees=degrees,
276
+ n_jobs=n_jobs,
277
+ zero_pad=fix_mass_default,
278
+ # grid_shape=tuple(len(g) for g in grid),
279
+ ignore_inf=ignore_infinite_filtration_values,
280
+ )
281
+ fix_mass_default = False
282
+
283
+ if "hook" in invariant:
284
+ from multipers.point_measure import rectangle_to_hook_minimal_signed_barcode
285
+ sms = [rectangle_to_hook_minimal_signed_barcode(pts,w) for pts,w in sms]
286
+ if verbose:
287
+ print("Done.")
288
+ elif filtered_complex_.is_minpres:
289
+ if verbose:
290
+ print("Reduced slicer. Retrieving measure from it...", end="")
291
+ sms = [
292
+ _signed_measure_from_slicer(
293
+ filtered_complex_,
294
+ shift=(
295
+ filtered_complex_.minpres_degree & 1 if d is None else d & 1
296
+ ),
297
+ )[0]
298
+ for d in degrees
299
+ ]
300
+ if verbose:
301
+ print("Done.")
302
+ elif (invariant is None or "euler" in invariant) and (
303
+ len(degrees) == 1 and degrees[0] is None
304
+ ):
305
+ if verbose:
306
+ print("Retrieving measure from slicer...", end="")
307
+ sms = _signed_measure_from_slicer(
308
+ filtered_complex_,
309
+ shift=0, # no minpres
310
+ )
311
+ if verbose:
312
+ print("Done.")
313
+ else:
314
+ if verbose:
315
+ print("Computing Hilbert function...", end="")
316
+ sms = _hilbert_signed_measure(
317
+ filtered_complex_,
318
+ degrees=degrees,
319
+ zero_pad=fix_mass_default,
320
+ n_jobs=n_jobs,
321
+ verbose=verbose,
322
+ ignore_inf=ignore_infinite_filtration_values,
323
+ )
324
+ fix_mass_default = False
325
+ if verbose:
326
+ print("Done.")
327
+
328
+ elif is_simplextree_multi(filtered_complex_):
329
+ if verbose:
330
+ print("Input is a simplextree.")
331
+ ## we still have a simplextree here
332
+ if invariant in ["rank_invariant", "rank", "hook", "rectangle"]:
333
+ if verbose:
334
+ print("Computing rank invariant...", end="")
335
+ assert (
336
+ num_parameters == 2
337
+ ), "Rank invariant only implemented for 2-parameter modules."
338
+ assert not coordinate_measure, "Not implemented"
339
+ from multipers.simplex_tree_multi import _rank_signed_measure as smri
340
+
341
+ sms = smri(
342
+ filtered_complex_,
343
+ mass_default=mass_default,
344
+ degrees=degrees,
345
+ expand_collapse=expand_collapse,
346
+ )
347
+ fix_mass_default = False
348
+ if "hook" in invariant:
349
+ from multipers.point_measure import rectangle_to_hook_minimal_signed_barcode
350
+ sms = [rectangle_to_hook_minimal_signed_barcode(pts,w) for pts,w in sms]
351
+ if verbose:
352
+ print("Done.")
353
+ elif len(degrees) == 1 and degrees[0] is None:
354
+ if verbose:
355
+ print("Computing Euler Characteristic...", end="")
356
+ assert invariant is None or invariant in [
357
+ "euler",
358
+ "euler_characteristic",
359
+ ], "Provide a degree to compute hilbert function."
360
+ # assert not coordinate_measure, "Not implemented"
361
+ from multipers.simplex_tree_multi import _euler_signed_measure
362
+
363
+ sms = [
364
+ _euler_signed_measure(
365
+ filtered_complex_,
366
+ mass_default=mass_default,
367
+ verbose=verbose,
368
+ )
369
+ ]
370
+ fix_mass_default = False
371
+ if verbose:
372
+ print("Done.")
373
+ else:
374
+ if verbose:
375
+ print("Computing Hilbert Function...", end="")
376
+ assert invariant is None or invariant in [
377
+ "hilbert",
378
+ "hilbert_function",
379
+ ], "Found homological degrees for euler computation."
380
+ from multipers.simplex_tree_multi import (
381
+ _hilbert_signed_measure as hilbert_signed_measure,
382
+ )
383
+
384
+ sms = hilbert_signed_measure(
385
+ filtered_complex_,
386
+ degrees=degrees,
387
+ mass_default=mass_default,
388
+ verbose=verbose,
389
+ n_jobs=n_jobs,
390
+ expand_collapse=expand_collapse,
391
+ )
392
+ fix_mass_default = False
393
+ if verbose:
394
+ print("Done.")
395
+ else:
396
+ raise ValueError("Filtered complex has to be a SimplexTree or a Slicer.")
397
+
398
+ if clean:
399
+ if verbose:
400
+ print("Cleaning measure...", end="")
401
+ sms = clean_sms(sms)
402
+ if verbose:
403
+ print("Done.")
404
+ if grid is not None and not coordinate_measure:
405
+ if verbose:
406
+ print("Pushing back the measure to the grid...", end="")
407
+ sms = sms_in_grid(
408
+ sms,
409
+ grid=grid,
410
+ mass_default=mass_default,
411
+ # num_parameters=num_parameters,
412
+ )
413
+ if verbose:
414
+ print("Done.")
415
+
416
+ if fix_mass_default:
417
+ # TODO : some methods need to use this, this could be optimized
418
+ if verbose:
419
+ print("Seems that fixing mass default is necessary...", end="")
420
+ sms = zero_out_sms(sms, mass_default=mass_default)
421
+ if verbose:
422
+ print("Done.")
423
+ if plot:
424
+ plot_signed_measures(sms)
425
+ return sms
426
+
427
+
428
+ def _signed_measure_from_scc(
429
+ minimal_presentation,
430
+ ) -> list[tuple[np.ndarray, np.ndarray]]:
431
+ pts = np.concatenate([b[0] for b in minimal_presentation])
432
+ weights = np.concatenate(
433
+ [
434
+ (1 - 2 * (i & 1)) * np.ones(len(b[0]))
435
+ for i, b in enumerate(minimal_presentation)
436
+ ]
437
+ )
438
+ sm = [(pts, weights)]
439
+ return sm
440
+
441
+
442
+ def _signed_measure_from_slicer(
443
+ slicer: Slicer_type,
444
+ shift: int = 0,
445
+ ) -> list[tuple[np.ndarray, np.ndarray]]:
446
+ assert not slicer.is_kcritical, "Not implemented for k-critical filtrations yet."
447
+ pts = np.array(slicer.get_filtrations())
448
+ dims = slicer.get_dimensions()
449
+ if shift:
450
+ dims += shift
451
+ weights = 1 - 2 * (dims % 2)
452
+ sm = [(pts, weights)]
453
+ return sm
@@ -0,0 +1,211 @@
1
+ from copy import deepcopy
2
+ from typing import Optional
3
+
4
+ import numpy as np
5
+
6
+ import multipers.slicer as mps
7
+ from multipers.simplex_tree_multi import is_simplextree_multi
8
+ from multipers.slicer import _column_type, _valid_dtype, _valid_pers_backend, is_slicer
9
+
10
+
11
+ ## TODO : maybe optimize this with cython
12
+ def _blocks2boundary_dimension_grades(
13
+ blocks,
14
+ filtration_type=np.float64,
15
+ num_parameters: int = -1,
16
+ inplace: bool = False,
17
+ is_kcritical: bool = False,
18
+ ):
19
+ """
20
+ Turns blocks, aka scc, into the input of non-simplicial slicers.
21
+ """
22
+ if num_parameters < 0:
23
+ for b in blocks:
24
+ if len(b[0]) > 0:
25
+ if is_kcritical:
26
+ num_parameters = np.asarray(b[0][0]).shape[1]
27
+ else:
28
+ num_parameters = np.asarray(b[0]).shape[1]
29
+ break
30
+ if num_parameters < 0:
31
+ raise ValueError("Empty Filtration")
32
+ rblocks = blocks if inplace else deepcopy(blocks)
33
+ rblocks.reverse()
34
+ block_sizes = [len(b[0]) for b in rblocks]
35
+ S = np.cumsum([0, 0] + block_sizes)
36
+ if is_kcritical:
37
+ multifiltration = tuple(
38
+ stuff
39
+ for b in rblocks
40
+ for stuff in (b[0] if len(b[0]) > 0 else [np.empty((0, num_parameters))])
41
+ )
42
+
43
+ else:
44
+ multifiltration = np.concatenate(
45
+ tuple(
46
+ b[0] if len(b[0]) > 0 else np.empty((0, num_parameters))
47
+ for b in rblocks
48
+ ),
49
+ dtype=filtration_type,
50
+ )
51
+ boundary = tuple(x + S[i] for i, b in enumerate(rblocks) for x in b[1])
52
+ dimensions = np.fromiter(
53
+ (i for i, b in enumerate(rblocks) for _ in range(len(b[0]))), dtype=int
54
+ )
55
+ return boundary, dimensions, multifiltration
56
+
57
+
58
+ def _slicer_from_simplextree(st, backend, vineyard):
59
+ if vineyard:
60
+ if backend == "matrix":
61
+ slicer = mps._SlicerVineSimplicial(st)
62
+ elif backend == "clement":
63
+ raise ValueError("This one takes a minpres")
64
+ elif backend == "graph":
65
+ slicer = mps._SlicerVineGraph(st)
66
+ else:
67
+ raise ValueError(f"Inimplemented backend {backend}.")
68
+ else:
69
+ if backend == "matrix":
70
+ slicer = mps._SlicerNoVineSimplicial(st)
71
+ elif backend == "clement":
72
+ raise ValueError("Clement is Vineyard")
73
+ elif backend == "graph":
74
+ raise ValueError("Graph is Vineyard")
75
+ else:
76
+ raise ValueError(f"Inimplemented backend {backend}.")
77
+ return slicer
78
+
79
+
80
+ def _slicer_from_blocks(
81
+ blocks,
82
+ pers_backend: _valid_pers_backend,
83
+ vineyard: bool,
84
+ is_kcritical: bool,
85
+ dtype: type,
86
+ col: _column_type,
87
+ ):
88
+ boundary, dimensions, multifiltrations = _blocks2boundary_dimension_grades(
89
+ blocks,
90
+ inplace=False,
91
+ is_kcritical=is_kcritical,
92
+ )
93
+ slicer = mps.get_matrix_slicer(vineyard, is_kcritical, dtype, col, pers_backend)(
94
+ boundary, dimensions, multifiltrations
95
+ )
96
+ return slicer
97
+
98
+
99
+ def Slicer(
100
+ st=None,
101
+ vineyard: Optional[bool] = None,
102
+ reduce: bool = False,
103
+ reduce_backend: Optional[str] = None,
104
+ dtype: Optional[_valid_dtype] = None,
105
+ kcritical: Optional[bool] = None,
106
+ column_type: Optional[_column_type] = None,
107
+ backend: Optional[_valid_pers_backend] = None,
108
+ max_dim: Optional[int] = None,
109
+ return_type_only: bool = False,
110
+ ) -> mps.Slicer_type:
111
+ """
112
+ Given a simplextree or blocks (a.k.a scc for python),
113
+ returns a structure that can compute persistence on line (or more)
114
+ slices, eventually vineyard update, etc.
115
+
116
+ This can be used to compute interval-decomposable module approximations
117
+ or signed measures, using, e.g.
118
+ - `multipers.module_approximation(this, *args)`
119
+ - `multipers.signed_measure(this, *args)`
120
+
121
+ Note : it is recommended and sometime required to apply
122
+ a minimal presentation before computing these functions !
123
+ `mp.slicer.minimal_presentation(slicer, *args, **kwargs)`
124
+
125
+ Input
126
+ -----
127
+ - st : SimplexTreeMulti or scc-like blocks or path to scc file
128
+ - backend: slicer backend, e.g, "matrix", "clement", "graph"
129
+ - vineyard: vineyard capable (may slow down computations if true)
130
+ Output
131
+ ------
132
+ The corresponding slicer.
133
+ """
134
+
135
+ if is_slicer(st, allow_minpres=False) or is_simplextree_multi(st):
136
+ dtype = st.dtype if dtype is None else dtype
137
+ is_kcritical = st.is_kcritical if kcritical is None else kcritical
138
+ else:
139
+ dtype = np.float64 if dtype is None else dtype
140
+ is_kcritical = False if kcritical is None else kcritical
141
+
142
+ if is_slicer(st, allow_minpres=False):
143
+ vineyard = st.is_vine if vineyard is None else vineyard
144
+ column_type = st.col_type if column_type is None else column_type
145
+ backend = st.pers_backend if backend is None else backend
146
+ else:
147
+ vineyard = False if vineyard is None else vineyard
148
+ column_type = "INTRUSIVE_SET" if column_type is None else column_type
149
+ backend = "Matrix" if backend is None else backend
150
+
151
+ _Slicer = mps.get_matrix_slicer(
152
+ is_vineyard=vineyard,
153
+ is_k_critical=is_kcritical,
154
+ dtype=dtype,
155
+ col=column_type,
156
+ pers_backend=backend,
157
+ )
158
+ if return_type_only:
159
+ return _Slicer
160
+ if st is None:
161
+ return _Slicer()
162
+ elif mps.is_slicer(st):
163
+ max_dim_idx = (
164
+ None
165
+ if max_dim is None
166
+ else np.searchsorted(st.get_dimensions(), max_dim + 1)
167
+ )
168
+ slicer = _Slicer(
169
+ st.get_boundaries()[slice(None, max_dim_idx)],
170
+ st.get_dimensions()[slice(None, max_dim_idx)],
171
+ st.get_filtrations()[slice(None, max_dim_idx)],
172
+ )
173
+ if st.is_squeezed:
174
+ slicer.filtration_grid = st.filtration_grid
175
+ slicer.minpres_degree = st.minpres_degree
176
+ elif is_simplextree_multi(st) and backend == "Graph":
177
+ slicer = _slicer_from_simplextree(st, backend, vineyard)
178
+ if st.is_squeezed:
179
+ slicer.filtration_grid = st.filtration_grid
180
+ elif backend == "Graph":
181
+ raise ValueError(
182
+ """
183
+ Graph is simplicial, incompatible with minpres.
184
+ You can try using `multipers.slicer.to_simplextree`."""
185
+ )
186
+ else:
187
+ filtration_grid = None
188
+ if max_dim is not None: # no test for simplex tree?
189
+ st.prune_above_dimension(max_dim)
190
+ if isinstance(st, str): # is_kcritical should be false
191
+ slicer = _Slicer()._build_from_scc_file(st)
192
+ else:
193
+ if is_simplextree_multi(st):
194
+ blocks = st._to_scc()
195
+ if st.is_squeezed:
196
+ filtration_grid = st.filtration_grid
197
+ else:
198
+ blocks = st
199
+ slicer = _slicer_from_blocks(
200
+ blocks, backend, vineyard, is_kcritical, dtype, column_type
201
+ )
202
+ if filtration_grid is not None:
203
+ slicer.filtration_grid = filtration_grid
204
+ if reduce:
205
+ slicer = mps.minimal_presentation(
206
+ slicer,
207
+ backend=reduce_backend,
208
+ slicer_backend=backend,
209
+ vineyard=vineyard,
210
+ )
211
+ return slicer