multipers 2.3.3b6__cp313-cp313-macosx_10_13_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 (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-313-darwin.so +0 -0
  26. multipers/function_rips.pyx +105 -0
  27. multipers/grids.cpython-313-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-313-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-313-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-313-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-313-darwin.so +0 -0
  162. multipers/point_measure.pyx +395 -0
  163. multipers/simplex_tree_multi.cpython-313-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-313-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
@@ -0,0 +1,1038 @@
1
+ /* This file is part of the Gudhi Library - https://gudhi.inria.fr/ - which is released under MIT.
2
+ * See file LICENSE or go to https://gudhi.inria.fr/licensing/ for full license details.
3
+ * Author(s): David Loiseaux
4
+ *
5
+ * Copyright (C) 2023 Inria
6
+ *
7
+ * Modification(s):
8
+ * - 2024/08 Hannah Schreiber: Optimization and correction + numeric_limits + doc
9
+ * - YYYY/MM Author: Description of the modification
10
+ */
11
+
12
+ /**
13
+ * @file Multi_critical_filtration.h
14
+ * @author David Loiseaux
15
+ * @brief Contains the @ref Gudhi::multi_filtration::Multi_critical_filtration class.
16
+ */
17
+
18
+ #ifndef MULTI_CRITICAL_FILTRATIONS_H_
19
+ #define MULTI_CRITICAL_FILTRATIONS_H_
20
+
21
+ #include <algorithm>
22
+ #include <cmath>
23
+ #include <cstddef>
24
+ #include <cstdint>
25
+ #include <cstring>
26
+ #include <iostream>
27
+ #include <limits>
28
+ #include <utility>
29
+ #include <vector>
30
+
31
+ #include <gudhi/Debug_utils.h>
32
+ #include <gudhi/One_critical_filtration.h>
33
+
34
+ namespace Gudhi {
35
+ namespace multi_filtration {
36
+
37
+ /**
38
+ * @class Multi_critical_filtration multi_critical_filtration.h gudhi/multi_critical_filtration.h
39
+ * @ingroup multi_filtration
40
+ *
41
+ * @brief Class encoding the different generators, i.e., apparition times, of a \f$k\f$-critical
42
+ * \f$\mathbb R^n\f$-filtration value, e.g., the filtration of a simplex, or of the algebraic generator of a module
43
+ * presentation. The class can be used as a vector whose indices correspond each to a generator, i.e., a one-critical
44
+ * filtration value. Then, the indices of each generator correspond to a particular parameter.
45
+ * E.g., \f$ f[i][p] \f$ will be \f$ p^{\textit{th}} \f$ parameter of the \f$ i^{\textit{th}} \f$ generator
46
+ * of this filtration value with @ref Multi_critical_filtration \f$ f \f$.
47
+ *
48
+ * @details Overloads `std::numeric_limits` such that:
49
+ * - `std::numeric_limits<Multi_critical_filtration<T,co> >::has_infinity` returns `true`,
50
+ * - `std::numeric_limits<Multi_critical_filtration<T,co> >::infinity()` returns
51
+ * @ref Multi_critical_filtration<T,co>::inf() "",
52
+ * - `std::numeric_limits<Multi_critical_filtration<T,co> >::minus_infinity()` returns
53
+ * @ref Multi_critical_filtration<T,co>::minus_inf() "",
54
+ * - `std::numeric_limits<Multi_critical_filtration<T,co> >::max()` throws,
55
+ * - `std::numeric_limits<Multi_critical_filtration<T,co> >::max(g,n)` returns a @ref Multi_critical_filtration<T,co>
56
+ * with `g` generators of `n` parameters evaluated at value `std::numeric_limits<T>::max()`,
57
+ * - `std::numeric_limits<Multi_critical_filtration<T,co> >::quiet_NaN()` returns
58
+ * @ref Multi_critical_filtration<T,co>::nan() "".
59
+ *
60
+ * Multi-critical filtrations are filtrations such that the lifetime of each object is union of positive cones in
61
+ * \f$\mathbb R^n\f$, e.g.,
62
+ * - \f$ \{ x \in \mathbb R^2 : x \ge (1,2)\} \cap \{ x \in \mathbb R^2 : x \ge (2,1)\} \f$ is finitely critical,
63
+ * and more particularly 2-critical, while
64
+ * - \f$ \{ x \in \mathbb R^2 : x \ge \mathrm{epigraph}(y \mapsto e^{-y})\} \f$ is not.
65
+ *
66
+ * The particular case of 1-critical filtrations is handled by @ref One_critical_filtration "".
67
+ *
68
+ * @tparam T Arithmetic type of an entry for one parameter of a filtration value. Has to be **signed** and
69
+ * to implement `std::isnan(T)`, `std::numeric_limits<T>::has_quiet_NaN`, `std::numeric_limits<T>::quiet_NaN()`,
70
+ * `std::numeric_limits<T>::has_infinity`, `std::numeric_limits<T>::infinity()` and `std::numeric_limits<T>::max()`.
71
+ * If `std::numeric_limits<T>::has_infinity` returns `false`, a call to `std::numeric_limits<T>::infinity()`
72
+ * can simply throw. Examples are the native types `double`, `float` and `int`.
73
+ * @tparam co If `true`, reverses the poset order, i.e., the order \f$ \le \f$ in \f$ \mathbb R^n \f$ becomes
74
+ * \f$ \ge \f$.
75
+ */
76
+ template <typename T, bool co = false>
77
+ class Multi_critical_filtration {
78
+ public:
79
+ /**
80
+ * @brief Type of the origin of a "lifetime cone". Common with @ref One_critical_filtration "".
81
+ */
82
+ using Generator = One_critical_filtration<T>;
83
+ using Generators = std::vector<Generator>; /**< Container type for the filtration values. */
84
+ using iterator = typename Generators::iterator; /**< Iterator type for the generator container. */
85
+ using const_iterator = typename Generators::const_iterator; /**< Const iterator type for the generator container. */
86
+
87
+ // CONSTRUCTORS
88
+
89
+ /**
90
+ * @brief Default constructor. The constructed value will be either at infinity if `co` is true or at minus infinity
91
+ * if `co` is false.
92
+ */
93
+ Multi_critical_filtration() : multi_filtration_(_get_default_filtration_value()) {};
94
+ /**
95
+ * @brief Constructs a filtration value with one generator and @p n parameters.
96
+ * All parameters will be initialized at -inf if `co` is false and at inf if `co` is true.
97
+ *
98
+ * @warning The generator `{-inf, -inf, ...}`/`{inf, inf, ...}` with \f$ n > 1 \f$ entries is not considered as
99
+ * "(minus) infinity" (the resp. methods @ref is_minus_inf() and @ref is_plus_inf() "", as well as the ones of the
100
+ * generator, will not return true). The `-inf/inf` are just meant as placeholders, at least one entry should be
101
+ * modified by the user.
102
+ * Otherwise, either use the static methods @ref minus_inf() or @ref inf(), or set @p n to 1 instead.
103
+ *
104
+ * @param n Number of parameters.
105
+ */
106
+ Multi_critical_filtration(int n) : multi_filtration_(1, Generator(n, _get_default_value())) {};
107
+ /**
108
+ * @brief Constructs a filtration value with one generator and @p n parameters. All parameters will be initialized
109
+ * with @p value.
110
+ *
111
+ * @warning If @p value is `inf`, `-inf`, or `NaN`, the generator `{value, value, ...}` with \f$ n > 1 \f$ entries
112
+ * is not wrong but will not be considered as respectively "infinity", "minus infinity" or "NaN" (the corresponding
113
+ * methods @ref is_plus_inf(), @ref is_minus_inf() and @ref is_nan() will return false). For this purpose, please use
114
+ * the static methods @ref inf(), @ref minus_inf() and @ref nan() instead.
115
+ *
116
+ * @param n Number of parameters.
117
+ * @param value Value which will be used for each entry.
118
+ */
119
+ Multi_critical_filtration(int n, T value) : multi_filtration_(1, Generator(n, value)) {};
120
+ /**
121
+ * @brief Constructs a filtration value with one generator which will be initialzed by the given initializer list.
122
+ *
123
+ * @param init Initializer list with values for each parameter.
124
+ */
125
+ Multi_critical_filtration(std::initializer_list<T> init) : multi_filtration_(1, Generator{init}) {};
126
+ /**
127
+ * @brief Constructs a filtration value with one generator which will be initialzed by the given vector.
128
+ *
129
+ * @param v Vector with values for each parameter.
130
+ */
131
+ Multi_critical_filtration(const std::vector<T> &v) : multi_filtration_(1, Generator{v}) {};
132
+ /**
133
+ * @brief Constructs a filtration value with one generator to which the given vector is moved to.
134
+ *
135
+ * @param v Vector with values for each parameter.
136
+ */
137
+ Multi_critical_filtration(std::vector<T> &&v) : multi_filtration_(1, Generator{std::move(v)}) {};
138
+ /**
139
+ * @brief Constructs filtration value with as many generators than elements in the given vector and initialize
140
+ * them with them.
141
+ * If the vector is empty, then the filtration value is either initialized at infinity if `co` is true or at
142
+ * minus infinity if `co` is false.
143
+ * @pre All generators in the vector have to have the same number of parameters, i.e., size.
144
+ * Furthermore, the generators have to be a minimal generating set.
145
+ *
146
+ * @warning If the set of generators is not minimal or not sorted, the behaviour of most methods is undefined.
147
+ * It is possible to call @ref simplify() after construction if there is a doubt to ensure this property.
148
+ *
149
+ * @param v Vector of generators.
150
+ */
151
+ Multi_critical_filtration(const std::vector<Generator> &v)
152
+ : multi_filtration_(v.empty() ? _get_default_filtration_value() : v) {};
153
+ /**
154
+ * @brief Constructs filtration value with as many generators than elements in the given vector and moves those
155
+ * elements to initialize the generators.
156
+ * If the vector is empty, then the filtration value is either initialized at infinity if `co` is true or at
157
+ * minus infinity if `co` is false.
158
+ * @pre All generators in the vector have to have the same number of parameters, i.e., size.
159
+ * Furthermore, the generators have to be a minimal generating set.
160
+ *
161
+ * @warning If the set of generators is not minimal or not sorted, the behaviour of most methods is undefined.
162
+ * It is possible to call @ref simplify() after construction if there is a doubt to ensure this property.
163
+ *
164
+ * @param v Vector of generators.
165
+ */
166
+ Multi_critical_filtration(std::vector<Generator> &&v)
167
+ : multi_filtration_(v.empty() ? _get_default_filtration_value() : std::move(v)) {};
168
+ /**
169
+ * @brief Constructs a filtration value with one generator initialzed by the range given by the begin and end
170
+ * iterators.
171
+ *
172
+ * @param it_begin Start of the range.
173
+ * @param it_end End of the range.
174
+ */
175
+ Multi_critical_filtration(typename std::vector<T>::iterator it_begin, typename std::vector<T>::iterator it_end)
176
+ : multi_filtration_(Generators(1, {it_begin, it_end})) {};
177
+ /**
178
+ * @brief Constructs a filtration value with one generator initialzed by the range given by the begin and end
179
+ * const iterators.
180
+ *
181
+ * @param it_begin Start of the range.
182
+ * @param it_end End of the range.
183
+ */
184
+ Multi_critical_filtration(typename std::vector<T>::const_iterator it_begin,
185
+ typename std::vector<T>::const_iterator it_end)
186
+ : multi_filtration_(Generator(1, {it_begin, it_end})) {};
187
+
188
+ // VECTOR-LIKE
189
+
190
+ using value_type = T; /**< Entry type. */
191
+
192
+ /**
193
+ * @brief Standard operator[].
194
+ */
195
+ Generator &operator[](std::size_t i) { return multi_filtration_[i]; }
196
+
197
+ /**
198
+ * @brief Standard operator[] const.
199
+ */
200
+ const Generator &operator[](std::size_t i) const { return multi_filtration_[i]; }
201
+
202
+ /**
203
+ * @brief Returns begin iterator of the generator range.
204
+ *
205
+ * @warning If the generator is modified and the new set of generators is not minimal or not sorted, the behaviour
206
+ * of most methods is undefined. It is possible to call @ref simplify() after construction if there is a doubt to
207
+ * ensure this property.
208
+ */
209
+ iterator begin() { return multi_filtration_.begin(); }
210
+
211
+ /**
212
+ * @brief Returns end iterator of the generator range.
213
+ *
214
+ * @warning If the generator is modified and the new set of generators is not minimal or not sorted, the behaviour
215
+ * of most methods is undefined. It is possible to call @ref simplify() after construction if there is a doubt to
216
+ * ensure this property.
217
+ */
218
+ iterator end() { return multi_filtration_.end(); }
219
+
220
+ /**
221
+ * @brief Returns begin const iterator of the generator range.
222
+ */
223
+ const_iterator begin() const { return multi_filtration_.begin(); }
224
+
225
+ /**
226
+ * @brief Returns end const iterator of the generator range.
227
+ */
228
+ const_iterator end() const { return multi_filtration_.end(); }
229
+
230
+ /**
231
+ * @brief Reserves space for the given number of generators in the underlying container.
232
+ *
233
+ * @param n Number of generators.
234
+ */
235
+ void reserve(std::size_t n) { multi_filtration_.reserve(n); }
236
+
237
+ // CONVERTERS
238
+
239
+ /**
240
+ * @brief Casts the object into the type of a generator.
241
+ * @pre The filtration value is 1-critical. If there are more than one generator, only the first will be preserved
242
+ * and if there is no generator, the method will segfault.
243
+ */
244
+ operator Generator() {
245
+ GUDHI_CHECK(num_generators() == 1,
246
+ "Casting a " + std::to_string(num_generators()) +
247
+ "-critical filtration value into an 1-critical filtration value.");
248
+ return multi_filtration_[0];
249
+ }
250
+
251
+ /**
252
+ * @brief Casts the object into the type of a generator.
253
+ * @pre The filtration value is 1-critical. If there are more than one generator, only the first will be preserved
254
+ * and if there is no generator, the method will segfault.
255
+ */
256
+ operator const Generator() const {
257
+ GUDHI_CHECK(num_generators() == 1,
258
+ "Casting a " + std::to_string(num_generators()) +
259
+ "-critical filtration value into an 1-critical filtration value.");
260
+ return multi_filtration_[0];
261
+ }
262
+
263
+ // like numpy
264
+ /**
265
+ * @brief Returns a copy with entries casted into the type given as template parameter.
266
+ *
267
+ * @tparam U New type for the entries.
268
+ * @return Copy with new entry type.
269
+ */
270
+ template <typename U>
271
+ Multi_critical_filtration<U> as_type() const {
272
+ std::vector<One_critical_filtration<U>> out(num_generators());
273
+ for (std::size_t i = 0u; i < num_generators(); ++i) {
274
+ out[i] = multi_filtration_[i].template as_type<U>();
275
+ }
276
+ return Multi_critical_filtration<U>(std::move(out));
277
+ }
278
+
279
+ // ACCESS
280
+
281
+ /**
282
+ * @brief Returns a reference to the underlying container storing the generators.
283
+ *
284
+ * @warning If a generator is modified and the new set of generators is not minimal or not sorted, the behaviour
285
+ * of most methods is undefined. It is possible to call @ref simplify() after construction if there is a doubt to
286
+ * ensure this property.
287
+ */
288
+ const Generators &get_underlying_container() const { return multi_filtration_; }
289
+
290
+ /**
291
+ * @brief Returns the number of parameters.
292
+ */
293
+ std::size_t num_parameters() const { return multi_filtration_[0].num_parameters(); }
294
+
295
+ /**
296
+ * @brief Returns the number of generators.
297
+ */
298
+ std::size_t num_generators() const { return multi_filtration_.size(); }
299
+
300
+ /**
301
+ * @brief Returns a filtration value for which @ref is_plus_inf() returns `true`.
302
+ *
303
+ * @return Infinity.
304
+ */
305
+ constexpr static Multi_critical_filtration inf() { return Multi_critical_filtration(Generator::inf()); }
306
+
307
+ /**
308
+ * @brief Returns a filtration value for which @ref is_minus_inf() returns `true`.
309
+ *
310
+ * @return Minus infinity.
311
+ */
312
+ constexpr static Multi_critical_filtration minus_inf() { return Multi_critical_filtration(Generator::minus_inf()); }
313
+
314
+ /**
315
+ * @brief Returns a filtration value for which @ref is_nan() returns `true`.
316
+ *
317
+ * @return NaN.
318
+ */
319
+ constexpr static Multi_critical_filtration nan() { return Multi_critical_filtration(Generator::nan()); }
320
+
321
+ constexpr static bool is_multicritical() { return true; }
322
+
323
+ // DESCRIPTORS
324
+
325
+ // TODO: Accept {{-inf, -inf, ...},...} / {{inf, inf, ...},...} / {{NaN, NaN, ...},...} as resp. -inf / inf / NaN.
326
+
327
+ /**
328
+ * @brief Returns `true` if and only if the filtration value is considered as infinity.
329
+ */
330
+ bool is_plus_inf() const { return multi_filtration_.size() == 1 && multi_filtration_[0].is_plus_inf(); }
331
+
332
+ /**
333
+ * @brief Returns `true` if and only if the filtration value is considered as minus infinity.
334
+ */
335
+ bool is_minus_inf() const { return multi_filtration_.size() == 1 && multi_filtration_[0].is_minus_inf(); }
336
+
337
+ /**
338
+ * @brief Returns `true` if and only if the filtration value is considered as NaN.
339
+ */
340
+ bool is_nan() const { return multi_filtration_.size() == 1 && multi_filtration_[0].is_nan(); }
341
+
342
+ /**
343
+ * @brief Returns `true` if and only if the filtration value is non-empty and is not considered as infinity,
344
+ * minus infinity or NaN.
345
+ */
346
+ bool is_finite() const {
347
+ if (multi_filtration_.size() > 1) return true;
348
+ return multi_filtration_[0].is_finite();
349
+ }
350
+
351
+ // COMPARAISON OPERATORS
352
+
353
+ // TODO : this costs a lot... optimize / cheat in some way for python ?
354
+
355
+ /**
356
+ * @brief Returns `true` if and only if the positive cones generated by @p b are strictly contained in the
357
+ * positive cones generated by @p a.
358
+ * If @p a and @p b are both not infinite or NaN, they have to have the same number of parameters.
359
+ *
360
+ * Note that not all filtration values are comparable. That is, \f$ a > b \f$ and \f$ b > a \f$ returning both false
361
+ * does **not** imply \f$ a == b \f$.
362
+ */
363
+ friend bool operator<(const Multi_critical_filtration &a, const Multi_critical_filtration &b) {
364
+ for (std::size_t i = 0u; i < b.multi_filtration_.size(); ++i) {
365
+ // for each generator in b, verify if it is strictly in the cone of at least one generator of a
366
+ bool isContained = false;
367
+ for (std::size_t j = 0u; j < a.multi_filtration_.size() && !isContained; ++j) {
368
+ // lexicographical order, so if a[j][0] dom b[j][0], than a[j'] can never strictly contain b[i] for all j' > j.
369
+ if (_first_dominates(a.multi_filtration_[j], b.multi_filtration_[i])) return false;
370
+ isContained = _strictly_contains(a.multi_filtration_[j], b.multi_filtration_[i]);
371
+ }
372
+ if (!isContained) return false;
373
+ }
374
+ return true;
375
+ }
376
+
377
+ /**
378
+ * @brief Returns `true` if and only if the positive cones generated by @p a are strictly contained in the
379
+ * positive cones generated by @p b.
380
+ * If @p a and @p b are both not infinite or NaN, they have to have the same number of parameters.
381
+ *
382
+ * Note that not all filtration values are comparable. That is, \f$ a > b \f$ and \f$ b > a \f$ returning both false
383
+ * does **not** imply \f$ a == b \f$.
384
+ */
385
+ friend bool operator>(const Multi_critical_filtration &a, const Multi_critical_filtration &b) { return b < a; }
386
+
387
+ /**
388
+ * @brief Returns `true` if and only if the positive cones generated by @p b are contained in or are (partially)
389
+ * equal to the positive cones generated by @p a.
390
+ * If @p a and @p b are both not infinite or NaN, they have to have the same number of parameters.
391
+ *
392
+ * Note that not all filtration values are comparable. That is, \f$ a \le b \f$ and \f$ b \le a \f$ can both return
393
+ * `false`.
394
+ */
395
+ friend bool operator<=(const Multi_critical_filtration &a, const Multi_critical_filtration &b) {
396
+ // check if this curves is below other's curve
397
+ // ie for each guy in this, check if there is a guy in other that dominates him
398
+ for (std::size_t i = 0u; i < b.multi_filtration_.size(); ++i) {
399
+ // for each generator in b, verify if it is in the cone of at least one generator of a
400
+ bool isContained = false;
401
+ for (std::size_t j = 0u; j < a.multi_filtration_.size() && !isContained; ++j) {
402
+ // lexicographical order, so if a[j][0] strictly dom b[j][0], than a[j'] can never contain b[i] for all j' > j.
403
+ if (_first_strictly_dominates(a.multi_filtration_[j], b.multi_filtration_[i])) return false;
404
+ isContained = _contains(a.multi_filtration_[j], b.multi_filtration_[i]);
405
+ }
406
+ if (!isContained) return false;
407
+ }
408
+ return true;
409
+ }
410
+
411
+ /**
412
+ * @brief Returns `true` if and only if the positive cones generated by @p a are contained in or are (partially)
413
+ * equal to the positive cones generated by @p b.
414
+ * If @p a and @p b are both not infinite or NaN, they have to have the same number of parameters.
415
+ *
416
+ * Note that not all filtration values are comparable. That is, \f$ a \ge b \f$ and \f$ b \ge a \f$ can both return
417
+ * `false`.
418
+ */
419
+ friend bool operator>=(const Multi_critical_filtration &a, const Multi_critical_filtration &b) { return b <= a; }
420
+
421
+ /**
422
+ * @brief Returns `true` if and only if for each \f$ i \f$, \f$ a[i] \f$ is equal to \f$ b[i] \f$.
423
+ */
424
+ friend bool operator==(const Multi_critical_filtration &a, const Multi_critical_filtration &b) {
425
+ // assumes lexicographical order for both
426
+ return a.multi_filtration_ == b.multi_filtration_;
427
+ }
428
+
429
+ /**
430
+ * @brief Returns `true` if and only if \f$ a == b \f$ returns `false`.
431
+ */
432
+ friend bool operator!=(const Multi_critical_filtration &a, const Multi_critical_filtration &b) { return !(a == b); }
433
+
434
+ // MODIFIERS
435
+
436
+ /**
437
+ * @brief Sets the number of generators. If there were less generators before, new empty generators are constructed.
438
+ * If there were more generators before, the exceed of generators is destroyed (any generator with index higher or
439
+ * equal than @p n to be more precise). If @p n is zero, the methods does nothing. A filtration value should never
440
+ * be empty.
441
+ *
442
+ * @warning All empty generators have 0 parameters. This can be problematic for some methods if there are also
443
+ * non empty generators in the container. Make sure to fill them with real generators or to remove them before
444
+ * using those methods.
445
+ *
446
+ * @warning Be sure to call @ref simplify if necessary after setting all the generators. Most methods will have an
447
+ * undefined behaviour if the set of generators is not minimal or sorted.
448
+ *
449
+ * @param n New number of generators.
450
+ */
451
+ void set_num_generators(std::size_t n) {
452
+ if (n == 0) return;
453
+ multi_filtration_.resize(n);
454
+ }
455
+
456
+ /**
457
+ * @brief Sets all generators to the least common upper bound between the current generator value and the given value.
458
+ *
459
+ * More formally, it pushes the current filtration value to the cone \f$ \{ y \in \mathbb R^n : y \ge x \} \f$
460
+ * originating in \f$ x \f$. The resulting values corresponds to the generators of the intersection of this cone
461
+ * with the union of positive cones generated by the old generators.
462
+ *
463
+ * @param x The target filtration value towards which to push.
464
+ */
465
+ void push_to_least_common_upper_bound(const Generator &x) {
466
+ if (this->is_plus_inf() || this->is_nan() || x.is_nan() || x.is_minus_inf()) return;
467
+
468
+ GUDHI_CHECK(x.is_plus_inf() || x.num_parameters() == multi_filtration_[0].num_parameters() || !is_finite(),
469
+ "Pushing to a filtration value with different number of parameters.");
470
+
471
+ if (x.is_plus_inf() || this->is_minus_inf()) {
472
+ multi_filtration_ = {x};
473
+ return;
474
+ }
475
+ for (auto &g : *this) {
476
+ g.push_to_least_common_upper_bound(x);
477
+ }
478
+
479
+ simplify();
480
+ }
481
+
482
+ /**
483
+ * @brief Sets all generators to the greatest common lower bound between the current generator value and the given
484
+ * value.
485
+ *
486
+ * More formally, it pulls the current filtration value to the cone \f$ \{ y \in \mathbb R^n : y \le x \} \f$
487
+ * originating in \f$ x \f$. The resulting values corresponds to the generators of the intersection of this cone
488
+ * with the union of negative cones generated by the old generators.
489
+ *
490
+ * @param x The target filtration value towards which to pull.
491
+ */
492
+ void pull_to_greatest_common_lower_bound(const Generator &x) {
493
+ if (x.is_plus_inf() || this->is_nan() || x.is_nan() || this->is_minus_inf()) return;
494
+
495
+ GUDHI_CHECK(x.is_minus_inf() || x.num_parameters() == multi_filtration_[0].num_parameters() || !is_finite(),
496
+ "Pulling to a filtration value with different number of parameters.");
497
+
498
+ if (this->is_plus_inf() || x.is_minus_inf()) {
499
+ multi_filtration_ = {x};
500
+ return;
501
+ }
502
+ for (auto &g : *this) {
503
+ g.pull_to_greatest_common_lower_bound(x);
504
+ }
505
+
506
+ simplify();
507
+ }
508
+
509
+ /**
510
+ * @brief Adds the given generator to the filtration value such that the sets remains minimal.
511
+ * It is therefore possible that the generator is ignored if it does not generated any new lifetime or that
512
+ * old generators disappear if they are overshadowed by the new one.
513
+ * @pre If all are finite, the new generator has to have the same number of parameters than the others.
514
+ *
515
+ * @param x New generator to add.
516
+ * @return true If and only if the generator is actually added to the set of generators.
517
+ * @return false Otherwise.
518
+ */
519
+ bool add_generator(const Generator &x) {
520
+ GUDHI_CHECK(x.num_parameters() == multi_filtration_[0].num_parameters() || !is_finite() || !x.is_finite(),
521
+ "Cannot add a generator with different number of parameters.");
522
+
523
+ std::size_t end = multi_filtration_.size();
524
+
525
+ if (_generator_can_be_added(x, 0, end)) {
526
+ multi_filtration_.resize(end);
527
+ multi_filtration_.push_back(x);
528
+ std::sort(multi_filtration_.begin(), multi_filtration_.end(), Is_strictly_smaller_lexicographically());
529
+ return true;
530
+ }
531
+
532
+ return false;
533
+ }
534
+
535
+ /**
536
+ * @brief Adds the given generator to the filtration value without any verifications or simplifications.
537
+ *
538
+ * @warning If the resulting set of generators is not minimal after modification, some methods will have an
539
+ * undefined behaviour. Be sure to call @ref simplify() before using them.
540
+ *
541
+ * @param x
542
+ */
543
+ void add_guaranteed_generator(const Generator &x) { multi_filtration_.push_back(x); }
544
+
545
+ /*
546
+ * Same as `compute_coordinates_in_grid`, but does the operation in-place.
547
+ */
548
+
549
+ /**
550
+ * @brief Projects the filtration value into the given grid. If @p coordinate is false, the entries are set to
551
+ * the nearest upper bound value with the same parameter in the grid and the new generators are simplified and
552
+ * ordered. Otherwise, the entries are set to the indices of those nearest upper bound values. In this case,
553
+ * no simplification or sort are done, such that the new coordinates have a one by one correspondence with the
554
+ * positions of the old generators.
555
+ * The grid has to be represented as a vector of ordered ranges of values convertible into `T`. An index
556
+ * \f$ i \f$ of the vector corresponds to the same parameter as the index \f$ i \f$ in a generator.
557
+ * The ranges correspond to the possible values of the parameters, ordered by increasing value, forming therefore
558
+ * all together a 2D grid.
559
+ *
560
+ * @tparam oned_array A range of values convertible into `T` ordered by increasing value. Has to implement
561
+ * a begin, end and operator[] method.
562
+ * @param grid Vector of @p oned_array with size at least number of filtration parameters.
563
+ * @param coordinate If true, the values are set to the coordinates of the projection in the grid. If false,
564
+ * the values are set to the values at the coordinates of the projection.
565
+ */
566
+ template <typename oned_array>
567
+ void project_onto_grid(const std::vector<oned_array> &grid, bool coordinate = true) {
568
+ GUDHI_CHECK(grid.size() >= num_parameters(),
569
+ "The grid should not be smaller than the number of parameters in the filtration value.");
570
+
571
+ for (auto &x : multi_filtration_) {
572
+ x.project_onto_grid(grid, coordinate);
573
+ }
574
+
575
+ if (!coordinate) simplify();
576
+ }
577
+
578
+ /**
579
+ * @brief Removes all empty generators from the filtration value. If @p include_infinities is true, it also
580
+ * removes the generators at infinity or minus infinity.
581
+ * If the set of generators is empty after removals, it is set to minus infinity if `co` is false or to infinity
582
+ * if `co` is true.
583
+ *
584
+ * @param include_infinities If true, removes also infinity values.
585
+ */
586
+ void remove_empty_generators(bool include_infinities = false) {
587
+ multi_filtration_.erase(std::remove_if(multi_filtration_.begin(),
588
+ multi_filtration_.end(),
589
+ [include_infinities](const Generator &a) {
590
+ return a.empty() ||
591
+ ((include_infinities) && (a.is_plus_inf() || a.is_minus_inf()));
592
+ }),
593
+ multi_filtration_.end());
594
+ std::sort(multi_filtration_.begin(), multi_filtration_.end(), Is_strictly_smaller_lexicographically());
595
+ if (multi_filtration_.empty()) multi_filtration_.push_back(Generator{_get_default_value()});
596
+ }
597
+
598
+ /**
599
+ * @brief Simplifies the current set of generators such that it becomes minimal. Also orders it in increasing
600
+ * lexicographical order. Only necessary if generators were added "by hand" without verification either trough the
601
+ * constructor or with @ref add_guaranteed_generator "", etc.
602
+ */
603
+ void simplify() {
604
+ std::size_t end = 0;
605
+
606
+ for (std::size_t curr = 0; curr < multi_filtration_.size(); ++curr) {
607
+ if (_generator_can_be_added(multi_filtration_[curr], 0, end)) {
608
+ std::swap(multi_filtration_[end], multi_filtration_[curr]);
609
+ ++end;
610
+ }
611
+ }
612
+
613
+ multi_filtration_.resize(end);
614
+ std::sort(multi_filtration_.begin(), multi_filtration_.end(), Is_strictly_smaller_lexicographically());
615
+ }
616
+
617
+ // FONCTIONNALITIES
618
+
619
+ /**
620
+ * @brief Returns a generator with the minimal values of all parameters in any generator of the given filtration
621
+ * value. That is, the greatest lower bound of all generators.
622
+ */
623
+ friend Generator factorize_below(const Multi_critical_filtration &f) {
624
+ if (f.num_generators() == 0) return Generator();
625
+ Generator result(f.num_parameters(), Generator::T_inf);
626
+ for (const auto &g : f) {
627
+ if (g.is_nan() || g.is_minus_inf()) return g;
628
+ if (g.is_plus_inf()) continue;
629
+ for (std::size_t i = 0; i < f.num_parameters(); ++i) {
630
+ result[i] = std::min(result[i], g[i]);
631
+ }
632
+ }
633
+ return result;
634
+ }
635
+
636
+ /**
637
+ * @brief Returns a generator with the maximal values of all parameters in any generator of the given filtration
638
+ * value. That is, the least upper bound of all generators.
639
+ */
640
+ friend Generator factorize_above(const Multi_critical_filtration &f) {
641
+ if (f.num_generators() == 0) return Generator();
642
+ Generator result(f.num_parameters(), -Generator::T_inf);
643
+ for (auto &g : f) {
644
+ if (g.is_nan() || g.is_plus_inf()) return g;
645
+ if (g.is_minus_inf()) continue;
646
+ for (std::size_t i = 0; i < g.num_parameters(); ++i) {
647
+ result[i] = std::max(result[i], g[i]);
648
+ }
649
+ }
650
+ return result;
651
+ }
652
+
653
+ /**
654
+ * @brief Computes the smallest (resp. the greatest if `co` is true) scalar product of the all generators with the
655
+ * given vector.
656
+ *
657
+ * @tparam U Arithmetic type of the result. Default value: `T`.
658
+ * @param f Filtration value.
659
+ * @param x Vector of coefficients.
660
+ * @return Scalar product of @p f with @p x.
661
+ */
662
+ template <typename U = T>
663
+ friend U compute_linear_projection(const Multi_critical_filtration &f, const std::vector<U> &x) {
664
+ if constexpr (co) {
665
+ U projection = std::numeric_limits<U>::lowest();
666
+ for (const auto &y : f) {
667
+ projection = std::max(projection, compute_linear_projection(y, x));
668
+ }
669
+ return projection;
670
+ } else {
671
+ U projection = std::numeric_limits<U>::max();
672
+ for (const auto &y : f) {
673
+ projection = std::min(projection, compute_linear_projection(y, x));
674
+ }
675
+ return projection;
676
+ }
677
+ }
678
+
679
+ /**
680
+ * @brief Computes the coordinates in the given grid, corresponding to the nearest upper bounds of the entries
681
+ * in the given filtration value.
682
+ * The grid has to be represented as a vector of vectors of ordered values convertible into `out_type`. An index
683
+ * \f$ i \f$ of the vector corresponds to the same parameter as the index \f$ i \f$ in a generator.
684
+ * The inner vectors correspond to the possible values of the parameters, ordered by increasing value,
685
+ * forming therefore all together a 2D grid.
686
+ *
687
+ * @tparam out_type Signed arithmetic type. Default value: std::int32_t.
688
+ * @tparam U Type which is convertible into `out_type`.
689
+ * @param f Filtration value to project.
690
+ * @param grid Vector of vectors to project into.
691
+ * @return Filtration value \f$ out \f$ whose entry correspond to the indices of the projected values. That is,
692
+ * the projection of \f$ f[i] \f$ is \f$ grid[i][out[i]] \f$ before simplification (if two generators were
693
+ * projected to the same point, the doubles are removed in the output).
694
+ */
695
+ template <typename out_type = std::int32_t, typename U = T>
696
+ friend Multi_critical_filtration<out_type> compute_coordinates_in_grid(Multi_critical_filtration f,
697
+ const std::vector<std::vector<U>> &grid) {
698
+ // TODO: by replicating the code of the 1-critical "project_onto_grid", this could be done with just one copy
699
+ // instead of two. But it is not clear if it is really worth it, i.e., how much the change in type is really
700
+ // necessary in the use cases. To see later.
701
+ f.project_onto_grid(grid);
702
+ if constexpr (std::is_same_v<out_type, T>) {
703
+ return f;
704
+ } else {
705
+ return f.as_type<out_type>();
706
+ }
707
+ }
708
+
709
+ /**
710
+ * @brief Computes the values in the given grid corresponding to the coordinates given by the given filtration
711
+ * value. That is, if \f$ out \f$ is the result, \f$ out[i] = grid[i][f[i]] \f$. Assumes therefore, that the
712
+ * values stored in the filtration value corresponds to indices existing in the given grid.
713
+ *
714
+ * @tparam U Signed arithmetic type.
715
+ * @param f Filtration value storing coordinates compatible with `grid`.
716
+ * @param grid Vector of vector.
717
+ * @return Filtration value \f$ out \f$ whose entry correspond to \f$ out[i] = grid[i][f[i]] \f$ before
718
+ * simplification (the output is simplified).
719
+ */
720
+ template <typename U>
721
+ friend Multi_critical_filtration<U> evaluate_coordinates_in_grid(const Multi_critical_filtration &f,
722
+ const std::vector<std::vector<U>> &grid) {
723
+ Multi_critical_filtration<U> out;
724
+ out.set_num_generators(f.num_generators());
725
+ for (std::size_t i = 0; i < f.num_generators(); ++i) {
726
+ out[i] = evaluate_coordinates_in_grid(f[i], grid);
727
+ }
728
+ out.simplify();
729
+ return out;
730
+ }
731
+
732
+ // UTILITIES
733
+
734
+ /**
735
+ * @brief Outstream operator.
736
+ */
737
+ friend std::ostream &operator<<(std::ostream &stream, const Multi_critical_filtration &f) {
738
+ if (f.is_plus_inf()) {
739
+ stream << "[inf, ..., inf]";
740
+ return stream;
741
+ }
742
+ if (f.is_minus_inf()) {
743
+ stream << "[-inf, ..., -inf]";
744
+ return stream;
745
+ }
746
+ if (f.is_nan()) {
747
+ stream << "[NaN]";
748
+ return stream;
749
+ }
750
+ stream << "(k=" << f.multi_filtration_.size() << ")[";
751
+ for (const auto &val : f) {
752
+ stream << val << "; ";
753
+ }
754
+ if (f.multi_filtration_.size() > 0) {
755
+ stream << "\b"
756
+ << "\b";
757
+ }
758
+ stream << "]";
759
+ return stream;
760
+ }
761
+
762
+ friend bool unify_lifetimes(Multi_critical_filtration &f1, const Multi_critical_filtration &f2) {
763
+ bool modified = false;
764
+ for (const Generator &g : f2.multi_filtration_) {
765
+ modified |= f1.add_generator(g);
766
+ }
767
+ return modified;
768
+ }
769
+
770
+ friend bool intersect_lifetimes(Multi_critical_filtration &f1, const Multi_critical_filtration &f2) {
771
+ if (f1.is_nan() || f2.is_nan()) return false;
772
+
773
+ if constexpr (co) {
774
+ if (f1.is_plus_inf()) {
775
+ if (f2.is_plus_inf()) return false;
776
+ f1 = f2;
777
+ return true;
778
+ }
779
+ if (f1.is_minus_inf()) {
780
+ return false;
781
+ }
782
+ } else {
783
+ if (f1.is_minus_inf()) {
784
+ if (f2.is_minus_inf()) return false;
785
+ f1 = f2;
786
+ return true;
787
+ }
788
+ if (f1.is_plus_inf()) {
789
+ return false;
790
+ }
791
+ }
792
+
793
+ Multi_critical_filtration res(1, -_get_default_value());
794
+ // TODO: see if the order can be used to avoid n^2 complexity and
795
+ // perhaps even to replace add_generator by add_guaranteed_generator
796
+ for (const Generator &of1 : f1.multi_filtration_) {
797
+ for (const Generator &of2 : f2.multi_filtration_) {
798
+ // TODO: avoid one go-through by constructing nf directly as the max/min
799
+ Generator nf = of1;
800
+ if constexpr (co) {
801
+ nf.pull_to_greatest_common_lower_bound(of2);
802
+ } else {
803
+ nf.push_to_least_common_upper_bound(of2);
804
+ }
805
+ res.add_generator(nf);
806
+ }
807
+ }
808
+ swap(f1, res);
809
+
810
+ return f1 != res;
811
+ }
812
+
813
+ friend char *serialize_trivial(const Multi_critical_filtration &value, char *start) {
814
+ const auto nberOfGenerators = value.num_generators();
815
+ const std::size_t type_size = sizeof(std::size_t);
816
+ memcpy(start, &nberOfGenerators, type_size);
817
+ char *curr = start + type_size;
818
+ for (const Generator &g : value) {
819
+ curr = serialize_trivial(g, curr);
820
+ }
821
+ return curr;
822
+ }
823
+
824
+ friend const char *deserialize_trivial(Multi_critical_filtration &value, const char *start) {
825
+ const std::size_t type_size = sizeof(std::size_t);
826
+ std::size_t nberOfGenerators;
827
+ memcpy(&nberOfGenerators, start, type_size);
828
+ const char *curr = start + type_size;
829
+ value.set_num_generators(nberOfGenerators);
830
+ for (Generator &g : value) {
831
+ curr = deserialize_trivial(g, curr);
832
+ }
833
+ return curr;
834
+ }
835
+
836
+ friend std::size_t get_serialization_size_of(const Multi_critical_filtration &value) {
837
+ std::size_t genSizes = sizeof(std::size_t);
838
+ for (const Generator &g : value) {
839
+ genSizes += get_serialization_size_of(g);
840
+ }
841
+ return genSizes;
842
+ }
843
+
844
+ /**
845
+ * @brief Indicates if the class manages multi-critical filtration values.
846
+ */
847
+ constexpr static const bool is_multi_critical = true;
848
+
849
+ private:
850
+ Generators multi_filtration_; /**< Container for generators. */
851
+
852
+ struct Is_strictly_smaller_lexicographically {
853
+ // assumes both generators have the same length if not infinite/nan.
854
+ bool operator()(const Generator &g1, const Generator &g2) {
855
+ if (g1.is_nan() || g2.is_nan()) return !g1.is_nan();
856
+ if (g1.is_plus_inf()) return false;
857
+ if (g2.is_plus_inf()) return true;
858
+ if (g1.is_minus_inf()) return false;
859
+ if (g2.is_minus_inf()) return true;
860
+
861
+ // g1 and g2 have to finite and of the same size
862
+ for (std::size_t i = 0; i < g1.size(); ++i) {
863
+ if (g1[i] != g2[i]) return g1[i] < g2[i];
864
+ }
865
+ return false;
866
+ }
867
+ };
868
+
869
+ constexpr static T _get_default_value() { return co ? Generator::T_inf : -Generator::T_inf; }
870
+
871
+ constexpr static Generators _get_default_filtration_value() { return Generators{Generator{_get_default_value()}}; }
872
+
873
+ /**
874
+ * @brief Verifies if @p b is strictly contained in the positive cone originating in `a`.
875
+ */
876
+ static bool _strictly_contains(const Generator &a, const Generator &b) {
877
+ if constexpr (co)
878
+ return a > b;
879
+ else {
880
+ return a < b;
881
+ }
882
+ }
883
+
884
+ /**
885
+ * @brief Verifies if @p b is contained in the positive cone originating in `a`.
886
+ */
887
+ static bool _contains(const Generator &a, const Generator &b) {
888
+ if constexpr (co)
889
+ return a >= b;
890
+ else {
891
+ return a <= b;
892
+ }
893
+ }
894
+
895
+ static bool _first_strictly_dominates(const Generator &a, const Generator &b) {
896
+ if constexpr (co) {
897
+ return !a.empty() && !b.empty() && a[0] < b[0];
898
+ } else {
899
+ return !a.empty() && !b.empty() && a[0] > b[0];
900
+ }
901
+ }
902
+
903
+ static bool _first_dominates(const Generator &a, const Generator &b) {
904
+ if constexpr (co) {
905
+ return !a.empty() && !b.empty() && a[0] <= b[0];
906
+ } else {
907
+ return !a.empty() && !b.empty() && a[0] >= b[0];
908
+ }
909
+ }
910
+
911
+ enum class Rel { EQUAL, DOMINATES, IS_DOMINATED, NONE };
912
+
913
+ static Rel _get_domination_relation(const Generator &a, const Generator &b) {
914
+ if (a.is_nan() || b.is_nan()) return Rel::NONE;
915
+
916
+ GUDHI_CHECK(a.size() == b.size(),
917
+ "Two generators in the same k-critical value have to have the same numbers of parameters.");
918
+
919
+ bool equal = true;
920
+ bool allGreater = true;
921
+ bool allSmaller = true;
922
+ for (unsigned int i = 0; i < a.size(); ++i) {
923
+ if (a[i] < b[i]) {
924
+ if (!allSmaller) return Rel::NONE;
925
+ equal = false;
926
+ allGreater = false;
927
+ } else if (a[i] > b[i]) {
928
+ if (!allGreater) return Rel::NONE;
929
+ equal = false;
930
+ allSmaller = false;
931
+ }
932
+ }
933
+ if (equal) return Rel::EQUAL;
934
+
935
+ if constexpr (co) {
936
+ if (allSmaller) return Rel::DOMINATES;
937
+ return Rel::IS_DOMINATED;
938
+ } else {
939
+ if (allGreater) return Rel::DOMINATES;
940
+ return Rel::IS_DOMINATED;
941
+ }
942
+ }
943
+
944
+ // assumes between 'curr' and 'end' everything is simplified:
945
+ // no nan values and if there is an inf/-inf, then 'end - curr == 1'
946
+ // modifies multi_filtration_ only if true is returned.
947
+ bool _generator_can_be_added(const Generator &x, std::size_t curr, std::size_t &end) {
948
+ if (x.empty() || x.is_nan()) return false;
949
+
950
+ // assumes that everything between curr and end is simplified
951
+ // so, only multi_filtration_[curr] can be at inf or -inf.
952
+ if constexpr (co) {
953
+ if (multi_filtration_[curr].is_plus_inf() || (x.is_minus_inf() && end - curr != 0)) {
954
+ return false;
955
+ }
956
+ if (multi_filtration_[curr].is_minus_inf()) {
957
+ if (x.is_minus_inf()) {
958
+ return false;
959
+ }
960
+ end = curr;
961
+ return true;
962
+ }
963
+ if (x.is_plus_inf()) {
964
+ if (multi_filtration_[curr].is_plus_inf()) return false;
965
+ end = curr;
966
+ return true;
967
+ }
968
+ } else {
969
+ if (multi_filtration_[curr].is_minus_inf() || (x.is_plus_inf() && end - curr != 0)) {
970
+ return false;
971
+ }
972
+ if (multi_filtration_[curr].is_plus_inf()) {
973
+ if (x.is_plus_inf()) {
974
+ return false;
975
+ }
976
+ end = curr;
977
+ return true;
978
+ }
979
+ if (x.is_minus_inf()) {
980
+ if (multi_filtration_[curr].is_minus_inf()) return false;
981
+ end = curr;
982
+ return true;
983
+ }
984
+ }
985
+
986
+ while (curr != end) {
987
+ Rel res = _get_domination_relation(multi_filtration_[curr], x);
988
+ if (res == Rel::IS_DOMINATED || res == Rel::EQUAL) return false; // x dominates or is equal
989
+ if (res == Rel::DOMINATES) { // x is dominated
990
+ --end;
991
+ std::swap(multi_filtration_[curr], multi_filtration_[end]);
992
+ } else { // no relation
993
+ ++curr;
994
+ }
995
+ }
996
+ return true;
997
+ }
998
+ };
999
+
1000
+ }} // namespace Gudhi::multi_filtration
1001
+
1002
+ namespace std {
1003
+
1004
+ template <typename T>
1005
+ class numeric_limits<Gudhi::multi_filtration::Multi_critical_filtration<T>> {
1006
+ public:
1007
+ static constexpr bool has_infinity = true;
1008
+
1009
+ static constexpr Gudhi::multi_filtration::Multi_critical_filtration<T> infinity() noexcept {
1010
+ return Gudhi::multi_filtration::Multi_critical_filtration<T>::inf();
1011
+ };
1012
+
1013
+ // non-standard
1014
+ static constexpr Gudhi::multi_filtration::Multi_critical_filtration<T> minus_infinity() noexcept {
1015
+ return Gudhi::multi_filtration::Multi_critical_filtration<T>::minus_inf();
1016
+ };
1017
+
1018
+ static constexpr Gudhi::multi_filtration::Multi_critical_filtration<T> max() noexcept(false) {
1019
+ throw std::logic_error(
1020
+ "The maximal value cannot be represented with no finite numbers of generators."
1021
+ "Use `max(number_of_generators, number_of_parameters)` instead");
1022
+ };
1023
+
1024
+ // non-standard, so I don't want to define default values.
1025
+ static constexpr Gudhi::multi_filtration::Multi_critical_filtration<T> max(unsigned int g, unsigned int n) noexcept {
1026
+ std::vector<typename Gudhi::multi_filtration::Multi_critical_filtration<T>::Generator> v(
1027
+ g, std::vector<T>(n, std::numeric_limits<T>::max()));
1028
+ return Gudhi::multi_filtration::Multi_critical_filtration<T>(std::move(v));
1029
+ };
1030
+
1031
+ static constexpr Gudhi::multi_filtration::Multi_critical_filtration<T> quiet_NaN() noexcept {
1032
+ return Gudhi::multi_filtration::Multi_critical_filtration<T>::nan();
1033
+ };
1034
+ };
1035
+
1036
+ } // namespace std
1037
+
1038
+ #endif // MULTI_CRITICAL_FILTRATIONS_H_