multipers 2.4.0b1__cp312-cp312-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.
Files changed (184) hide show
  1. multipers/.dylibs/libboost_timer.dylib +0 -0
  2. multipers/.dylibs/libc++.1.0.dylib +0 -0
  3. multipers/.dylibs/libtbb.12.17.dylib +0 -0
  4. multipers/__init__.py +33 -0
  5. multipers/_signed_measure_meta.py +426 -0
  6. multipers/_slicer_meta.py +231 -0
  7. multipers/array_api/__init__.py +62 -0
  8. multipers/array_api/numpy.py +124 -0
  9. multipers/array_api/torch.py +133 -0
  10. multipers/data/MOL2.py +458 -0
  11. multipers/data/UCR.py +18 -0
  12. multipers/data/__init__.py +1 -0
  13. multipers/data/graphs.py +466 -0
  14. multipers/data/immuno_regions.py +27 -0
  15. multipers/data/minimal_presentation_to_st_bf.py +0 -0
  16. multipers/data/pytorch2simplextree.py +91 -0
  17. multipers/data/shape3d.py +101 -0
  18. multipers/data/synthetic.py +113 -0
  19. multipers/distances.py +202 -0
  20. multipers/filtration_conversions.pxd +736 -0
  21. multipers/filtration_conversions.pxd.tp +226 -0
  22. multipers/filtrations/__init__.py +21 -0
  23. multipers/filtrations/density.py +529 -0
  24. multipers/filtrations/filtrations.py +480 -0
  25. multipers/filtrations.pxd +534 -0
  26. multipers/filtrations.pxd.tp +332 -0
  27. multipers/function_rips.cpython-312-darwin.so +0 -0
  28. multipers/function_rips.pyx +104 -0
  29. multipers/grids.cpython-312-darwin.so +0 -0
  30. multipers/grids.pyx +538 -0
  31. multipers/gudhi/Persistence_slices_interface.h +213 -0
  32. multipers/gudhi/Simplex_tree_interface.h +274 -0
  33. multipers/gudhi/Simplex_tree_multi_interface.h +648 -0
  34. multipers/gudhi/gudhi/Bitmap_cubical_complex.h +450 -0
  35. multipers/gudhi/gudhi/Bitmap_cubical_complex_base.h +1070 -0
  36. multipers/gudhi/gudhi/Bitmap_cubical_complex_periodic_boundary_conditions_base.h +579 -0
  37. multipers/gudhi/gudhi/Debug_utils.h +52 -0
  38. multipers/gudhi/gudhi/Degree_rips_bifiltration.h +2307 -0
  39. multipers/gudhi/gudhi/Dynamic_multi_parameter_filtration.h +2524 -0
  40. multipers/gudhi/gudhi/Fields/Multi_field.h +453 -0
  41. multipers/gudhi/gudhi/Fields/Multi_field_operators.h +460 -0
  42. multipers/gudhi/gudhi/Fields/Multi_field_shared.h +444 -0
  43. multipers/gudhi/gudhi/Fields/Multi_field_small.h +584 -0
  44. multipers/gudhi/gudhi/Fields/Multi_field_small_operators.h +490 -0
  45. multipers/gudhi/gudhi/Fields/Multi_field_small_shared.h +580 -0
  46. multipers/gudhi/gudhi/Fields/Z2_field.h +391 -0
  47. multipers/gudhi/gudhi/Fields/Z2_field_operators.h +389 -0
  48. multipers/gudhi/gudhi/Fields/Zp_field.h +493 -0
  49. multipers/gudhi/gudhi/Fields/Zp_field_operators.h +384 -0
  50. multipers/gudhi/gudhi/Fields/Zp_field_shared.h +492 -0
  51. multipers/gudhi/gudhi/Flag_complex_edge_collapser.h +337 -0
  52. multipers/gudhi/gudhi/Matrix.h +2200 -0
  53. multipers/gudhi/gudhi/Multi_filtration/Multi_parameter_generator.h +1712 -0
  54. multipers/gudhi/gudhi/Multi_filtration/multi_filtration_conversions.h +237 -0
  55. multipers/gudhi/gudhi/Multi_filtration/multi_filtration_utils.h +225 -0
  56. multipers/gudhi/gudhi/Multi_parameter_filtered_complex.h +485 -0
  57. multipers/gudhi/gudhi/Multi_parameter_filtration.h +2643 -0
  58. multipers/gudhi/gudhi/Multi_persistence/Box.h +233 -0
  59. multipers/gudhi/gudhi/Multi_persistence/Line.h +309 -0
  60. multipers/gudhi/gudhi/Multi_persistence/Multi_parameter_filtered_complex_pcoh_interface.h +268 -0
  61. multipers/gudhi/gudhi/Multi_persistence/Persistence_interface_cohomology.h +159 -0
  62. multipers/gudhi/gudhi/Multi_persistence/Persistence_interface_matrix.h +463 -0
  63. multipers/gudhi/gudhi/Multi_persistence/Point.h +853 -0
  64. multipers/gudhi/gudhi/Off_reader.h +173 -0
  65. multipers/gudhi/gudhi/Persistence_matrix/Base_matrix.h +834 -0
  66. multipers/gudhi/gudhi/Persistence_matrix/Base_matrix_with_column_compression.h +838 -0
  67. multipers/gudhi/gudhi/Persistence_matrix/Boundary_matrix.h +833 -0
  68. multipers/gudhi/gudhi/Persistence_matrix/Chain_matrix.h +1367 -0
  69. multipers/gudhi/gudhi/Persistence_matrix/Id_to_index_overlay.h +1157 -0
  70. multipers/gudhi/gudhi/Persistence_matrix/Position_to_index_overlay.h +869 -0
  71. multipers/gudhi/gudhi/Persistence_matrix/RU_matrix.h +905 -0
  72. multipers/gudhi/gudhi/Persistence_matrix/allocators/entry_constructors.h +122 -0
  73. multipers/gudhi/gudhi/Persistence_matrix/base_pairing.h +260 -0
  74. multipers/gudhi/gudhi/Persistence_matrix/base_swap.h +288 -0
  75. multipers/gudhi/gudhi/Persistence_matrix/chain_pairing.h +170 -0
  76. multipers/gudhi/gudhi/Persistence_matrix/chain_rep_cycles.h +247 -0
  77. multipers/gudhi/gudhi/Persistence_matrix/chain_vine_swap.h +571 -0
  78. multipers/gudhi/gudhi/Persistence_matrix/columns/chain_column_extra_properties.h +182 -0
  79. multipers/gudhi/gudhi/Persistence_matrix/columns/column_dimension_holder.h +130 -0
  80. multipers/gudhi/gudhi/Persistence_matrix/columns/column_utilities.h +235 -0
  81. multipers/gudhi/gudhi/Persistence_matrix/columns/entry_types.h +312 -0
  82. multipers/gudhi/gudhi/Persistence_matrix/columns/heap_column.h +1092 -0
  83. multipers/gudhi/gudhi/Persistence_matrix/columns/intrusive_list_column.h +923 -0
  84. multipers/gudhi/gudhi/Persistence_matrix/columns/intrusive_set_column.h +914 -0
  85. multipers/gudhi/gudhi/Persistence_matrix/columns/list_column.h +930 -0
  86. multipers/gudhi/gudhi/Persistence_matrix/columns/naive_vector_column.h +1071 -0
  87. multipers/gudhi/gudhi/Persistence_matrix/columns/row_access.h +203 -0
  88. multipers/gudhi/gudhi/Persistence_matrix/columns/set_column.h +886 -0
  89. multipers/gudhi/gudhi/Persistence_matrix/columns/unordered_set_column.h +984 -0
  90. multipers/gudhi/gudhi/Persistence_matrix/columns/vector_column.h +1213 -0
  91. multipers/gudhi/gudhi/Persistence_matrix/index_mapper.h +58 -0
  92. multipers/gudhi/gudhi/Persistence_matrix/matrix_dimension_holders.h +227 -0
  93. multipers/gudhi/gudhi/Persistence_matrix/matrix_row_access.h +200 -0
  94. multipers/gudhi/gudhi/Persistence_matrix/ru_pairing.h +166 -0
  95. multipers/gudhi/gudhi/Persistence_matrix/ru_rep_cycles.h +319 -0
  96. multipers/gudhi/gudhi/Persistence_matrix/ru_vine_swap.h +562 -0
  97. multipers/gudhi/gudhi/Persistence_on_a_line.h +152 -0
  98. multipers/gudhi/gudhi/Persistence_on_rectangle.h +617 -0
  99. multipers/gudhi/gudhi/Persistent_cohomology/Field_Zp.h +118 -0
  100. multipers/gudhi/gudhi/Persistent_cohomology/Multi_field.h +173 -0
  101. multipers/gudhi/gudhi/Persistent_cohomology/Persistent_cohomology_column.h +128 -0
  102. multipers/gudhi/gudhi/Persistent_cohomology.h +769 -0
  103. multipers/gudhi/gudhi/Points_off_io.h +171 -0
  104. multipers/gudhi/gudhi/Projective_cover_kernel.h +379 -0
  105. multipers/gudhi/gudhi/Simple_object_pool.h +69 -0
  106. multipers/gudhi/gudhi/Simplex_tree/Simplex_tree_iterators.h +559 -0
  107. multipers/gudhi/gudhi/Simplex_tree/Simplex_tree_node_explicit_storage.h +83 -0
  108. multipers/gudhi/gudhi/Simplex_tree/Simplex_tree_siblings.h +121 -0
  109. multipers/gudhi/gudhi/Simplex_tree/Simplex_tree_star_simplex_iterators.h +277 -0
  110. multipers/gudhi/gudhi/Simplex_tree/filtration_value_utils.h +155 -0
  111. multipers/gudhi/gudhi/Simplex_tree/hooks_simplex_base.h +62 -0
  112. multipers/gudhi/gudhi/Simplex_tree/indexing_tag.h +27 -0
  113. multipers/gudhi/gudhi/Simplex_tree/serialization_utils.h +60 -0
  114. multipers/gudhi/gudhi/Simplex_tree/simplex_tree_options.h +105 -0
  115. multipers/gudhi/gudhi/Simplex_tree.h +3170 -0
  116. multipers/gudhi/gudhi/Slicer.h +848 -0
  117. multipers/gudhi/gudhi/Thread_safe_slicer.h +393 -0
  118. multipers/gudhi/gudhi/distance_functions.h +62 -0
  119. multipers/gudhi/gudhi/graph_simplicial_complex.h +104 -0
  120. multipers/gudhi/gudhi/multi_simplex_tree_helpers.h +147 -0
  121. multipers/gudhi/gudhi/persistence_interval.h +263 -0
  122. multipers/gudhi/gudhi/persistence_matrix_options.h +188 -0
  123. multipers/gudhi/gudhi/reader_utils.h +367 -0
  124. multipers/gudhi/gudhi/simple_mdspan.h +484 -0
  125. multipers/gudhi/gudhi/slicer_helpers.h +779 -0
  126. multipers/gudhi/tmp_h0_pers/mma_interface_h0.h +223 -0
  127. multipers/gudhi/tmp_h0_pers/naive_merge_tree.h +536 -0
  128. multipers/io.cpython-312-darwin.so +0 -0
  129. multipers/io.pyx +472 -0
  130. multipers/ml/__init__.py +0 -0
  131. multipers/ml/accuracies.py +90 -0
  132. multipers/ml/invariants_with_persistable.py +79 -0
  133. multipers/ml/kernels.py +176 -0
  134. multipers/ml/mma.py +713 -0
  135. multipers/ml/one.py +472 -0
  136. multipers/ml/point_clouds.py +352 -0
  137. multipers/ml/signed_measures.py +1667 -0
  138. multipers/ml/sliced_wasserstein.py +461 -0
  139. multipers/ml/tools.py +113 -0
  140. multipers/mma_structures.cpython-312-darwin.so +0 -0
  141. multipers/mma_structures.pxd +134 -0
  142. multipers/mma_structures.pyx +1483 -0
  143. multipers/mma_structures.pyx.tp +1126 -0
  144. multipers/multi_parameter_rank_invariant/diff_helpers.h +85 -0
  145. multipers/multi_parameter_rank_invariant/euler_characteristic.h +95 -0
  146. multipers/multi_parameter_rank_invariant/function_rips.h +317 -0
  147. multipers/multi_parameter_rank_invariant/hilbert_function.h +761 -0
  148. multipers/multi_parameter_rank_invariant/persistence_slices.h +149 -0
  149. multipers/multi_parameter_rank_invariant/rank_invariant.h +350 -0
  150. multipers/multiparameter_edge_collapse.py +41 -0
  151. multipers/multiparameter_module_approximation/approximation.h +2541 -0
  152. multipers/multiparameter_module_approximation/debug.h +107 -0
  153. multipers/multiparameter_module_approximation/format_python-cpp.h +292 -0
  154. multipers/multiparameter_module_approximation/utilities.h +428 -0
  155. multipers/multiparameter_module_approximation.cpython-312-darwin.so +0 -0
  156. multipers/multiparameter_module_approximation.pyx +286 -0
  157. multipers/ops.cpython-312-darwin.so +0 -0
  158. multipers/ops.pyx +231 -0
  159. multipers/pickle.py +89 -0
  160. multipers/plots.py +550 -0
  161. multipers/point_measure.cpython-312-darwin.so +0 -0
  162. multipers/point_measure.pyx +409 -0
  163. multipers/simplex_tree_multi.cpython-312-darwin.so +0 -0
  164. multipers/simplex_tree_multi.pxd +136 -0
  165. multipers/simplex_tree_multi.pyx +11719 -0
  166. multipers/simplex_tree_multi.pyx.tp +2102 -0
  167. multipers/slicer.cpython-312-darwin.so +0 -0
  168. multipers/slicer.pxd +2097 -0
  169. multipers/slicer.pxd.tp +263 -0
  170. multipers/slicer.pyx +13042 -0
  171. multipers/slicer.pyx.tp +1259 -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 +70 -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/vector_interface.pxd +46 -0
  180. multipers-2.4.0b1.dist-info/METADATA +131 -0
  181. multipers-2.4.0b1.dist-info/RECORD +184 -0
  182. multipers-2.4.0b1.dist-info/WHEEL +6 -0
  183. multipers-2.4.0b1.dist-info/licenses/LICENSE +21 -0
  184. multipers-2.4.0b1.dist-info/top_level.txt +1 -0
@@ -0,0 +1,1712 @@
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): Hannah Schreiber, David Loiseaux
4
+ *
5
+ * Copyright (C) 2024-25 Inria
6
+ *
7
+ * Modification(s):
8
+ * - YYYY/MM Author: Description of the modification
9
+ */
10
+
11
+ /**
12
+ * @private
13
+ * @file Multi_parameter_generator.h
14
+ * @author Hannah Schreiber, David Loiseaux
15
+ * @brief Contains the @ref Gudhi::multi_filtration::Multi_parameter_generator class.
16
+ */
17
+
18
+ #ifndef MF_MULTI_PARAMETER_GENERATOR_H_
19
+ #define MF_MULTI_PARAMETER_GENERATOR_H_
20
+
21
+ #include <algorithm> //std::lower_bound
22
+ #include <cmath> //std::isnan, std::min
23
+ #include <cstddef> //std::size_t
24
+ #include <cstring> //memcpy
25
+ #include <iterator> //std::distance
26
+ #include <ostream> //std::ostream
27
+ #include <limits> //std::numerical_limits
28
+ #include <stdexcept> //std::logic_error
29
+ #include <type_traits> //std::is_arithmetic
30
+ #include <utility> //std::swap, std::move
31
+ #include <vector>
32
+ #include <initializer_list>
33
+
34
+ #include <gudhi/Debug_utils.h>
35
+ #include <gudhi/simple_mdspan.h>
36
+ #include <gudhi/Multi_filtration/multi_filtration_utils.h>
37
+ #include <oneapi/tbb/parallel_for.h>
38
+
39
+ namespace Gudhi::multi_filtration {
40
+
41
+ // declaration needed pre C++20 for friends with templates defined inside a class
42
+ template <typename U>
43
+ U compute_euclidean_distance_to();
44
+ template <typename U>
45
+ U compute_norm();
46
+
47
+ /**
48
+ * private
49
+ * @class Multi_parameter_generator Multi_parameter_generator.h gudhi/Multi_parameter_generator.h
50
+ * @ingroup multi_filtration
51
+ *
52
+ * @brief Class encoding a single generator of @ref Dynamic_multi_parameter_filtration "".
53
+ *
54
+ * @tparam T Arithmetic type of an entry for one parameter of a filtration value. Has to be **signed** and
55
+ * to implement `std::isnan(T)`, `std::numeric_limits<T>::has_quiet_NaN`, `std::numeric_limits<T>::quiet_NaN()`,
56
+ * `std::numeric_limits<T>::has_infinity`, `std::numeric_limits<T>::infinity()` and `std::numeric_limits<T>::max()`.
57
+ * If `std::numeric_limits<T>::has_infinity` returns `false`, a call to `std::numeric_limits<T>::infinity()`
58
+ * can simply throw. Examples are the native types `double`, `float` and `int`.
59
+ */
60
+ template <typename T>
61
+ class Multi_parameter_generator
62
+ {
63
+ public:
64
+ using Underlying_container = std::vector<T>; /**< Underlying container for values. */
65
+
66
+ // CONSTRUCTORS
67
+
68
+ /**
69
+ * @brief Default constructor. Builds generator with given number of parameters.
70
+ * All values are set at -inf.
71
+ *
72
+ * @param number_of_parameters If negative, takes the default value instead. Default value: 1.
73
+ */
74
+ Multi_parameter_generator(int number_of_parameters = 1)
75
+ : generator_(number_of_parameters < 0 ? 1 : number_of_parameters, _get_default_value())
76
+ {}
77
+
78
+ /**
79
+ * @brief Builds generator with given number of parameters. All values are initialized at the given value.
80
+ *
81
+ * @param number_of_parameters If negative, is set to 1 instead.
82
+ * @param value Initialization value for every value in the generator.
83
+ */
84
+ Multi_parameter_generator(int number_of_parameters, T value)
85
+ : generator_(number_of_parameters < 0 ? 1 : number_of_parameters, value)
86
+ {}
87
+
88
+ /**
89
+ * @brief Builds generator that is initialized with the given range. The number of
90
+ * parameters are therefore deduced from the length of the range.
91
+ *
92
+ * @tparam ValueRange Range of types convertible to `T`. Should have a begin() and end() method.
93
+ * @param range Values of the generator.
94
+ */
95
+ template <class ValueRange = std::initializer_list<T>, class = std::enable_if_t<RangeTraits<ValueRange>::has_begin> >
96
+ Multi_parameter_generator(const ValueRange &range) : generator_(range.begin(), range.end())
97
+ {}
98
+
99
+ /**
100
+ * @brief Builds generator that is initialized with the given range. The range is
101
+ * determined from the two given iterators. The number of parameters are therefore deduced from the distance
102
+ * between the two.
103
+ *
104
+ * @tparam Iterator Iterator type that has to satisfy the requirements of standard LegacyInputIterator and
105
+ * dereferenced elements have to be convertible to `T`.
106
+ * @param it_begin Iterator pointing to the start of the range.
107
+ * @param it_end Iterator pointing to the end of the range.
108
+ */
109
+ template <class Iterator>
110
+ Multi_parameter_generator(Iterator it_begin, Iterator it_end) : generator_(it_begin, it_end)
111
+ {}
112
+
113
+ /**
114
+ * @brief Builds generator with given number of parameters and values from the given range.
115
+ * The range is represented by @ref Multi_parameter_generator::Underlying_container "" and **moved** into the
116
+ * underlying container of the class.
117
+ *
118
+ * @param generators Values to move.
119
+ */
120
+ Multi_parameter_generator(Underlying_container &&generators) : generator_(std::move(generators)) {}
121
+
122
+ /**
123
+ * @brief Copy constructor.
124
+ */
125
+ Multi_parameter_generator(const Multi_parameter_generator &other) = default;
126
+
127
+ /**
128
+ * @brief Copy constructor.
129
+ *
130
+ * @tparam U Type convertible into `T`.
131
+ */
132
+ template <typename U>
133
+ Multi_parameter_generator(const Multi_parameter_generator<U> &other) : generator_(other.begin(), other.end())
134
+ {}
135
+
136
+ /**
137
+ * @brief Move constructor.
138
+ */
139
+ Multi_parameter_generator(Multi_parameter_generator &&other) noexcept = default;
140
+
141
+ ~Multi_parameter_generator() = default;
142
+
143
+ /**
144
+ * @brief Assign operator.
145
+ */
146
+ Multi_parameter_generator &operator=(const Multi_parameter_generator &other) = default;
147
+
148
+ /**
149
+ * @brief Move assign operator.
150
+ */
151
+ Multi_parameter_generator &operator=(Multi_parameter_generator &&other) noexcept = default;
152
+
153
+ /**
154
+ * @brief Assign operator.
155
+ *
156
+ * @tparam U Type convertible into `T`.
157
+ */
158
+ template <typename U>
159
+ Multi_parameter_generator &operator=(const Multi_parameter_generator<U> &other)
160
+ {
161
+ generator_ = Underlying_container(other.begin(), other.end());
162
+ return *this;
163
+ }
164
+
165
+ /**
166
+ * @brief Swap operator.
167
+ */
168
+ friend void swap(Multi_parameter_generator &g1, Multi_parameter_generator &g2) noexcept
169
+ {
170
+ g1.generator_.swap(g2.generator_);
171
+ }
172
+
173
+ // VECTOR-LIKE
174
+
175
+ using value_type = T; /**< Value type. */
176
+ using size_type = typename Underlying_container::size_type; /**< Size type. */
177
+ using difference_type = typename Underlying_container::difference_type; /**< Difference type. */
178
+ using reference = value_type &; /**< Reference type. */
179
+ using const_reference = const value_type &; /**< Const reference type. */
180
+ using pointer = typename Underlying_container::pointer; /**< Pointer type. */
181
+ using const_pointer = typename Underlying_container::const_pointer; /**< Const pointer type. */
182
+ using iterator = typename Underlying_container::iterator; /**< Iterator type. */
183
+ using const_iterator = typename Underlying_container::const_iterator; /**< Const iterator type. */
184
+ using reverse_iterator = typename Underlying_container::reverse_iterator; /**< Reverse iterator type. */
185
+ using const_reverse_iterator = typename Underlying_container::const_reverse_iterator; /**< Const reverse iterator. */
186
+
187
+ /**
188
+ * @brief Returns reference to the value of parameter `p`.
189
+ */
190
+ reference operator[](size_type p)
191
+ {
192
+ GUDHI_CHECK(p < generator_.size(), std::out_of_range("Out of bound parameter."));
193
+ return generator_[p];
194
+ }
195
+
196
+ /**
197
+ * @brief Returns const reference to the value of parameter `p`.
198
+ */
199
+ const_reference operator[](size_type p) const
200
+ {
201
+ GUDHI_CHECK(p < generator_.size(), std::out_of_range("Out of bound parameter."));
202
+ return generator_[p];
203
+ }
204
+
205
+ /**
206
+ * @brief Returns an iterator pointing the begining of the underlying container.
207
+ */
208
+ iterator begin() noexcept { return generator_.begin(); }
209
+
210
+ /**
211
+ * @brief Returns an iterator pointing the begining of the underlying container.
212
+ */
213
+ const_iterator begin() const noexcept { return generator_.begin(); }
214
+
215
+ /**
216
+ * @brief Returns an iterator pointing the begining of the underlying container.
217
+ */
218
+ const_iterator cbegin() const noexcept { return generator_.cbegin(); }
219
+
220
+ /**
221
+ * @brief Returns an iterator pointing the end of the underlying container.
222
+ */
223
+ iterator end() noexcept { return generator_.end(); }
224
+
225
+ /**
226
+ * @brief Returns an iterator pointing the end of the underlying container.
227
+ */
228
+ const_iterator end() const noexcept { return generator_.end(); }
229
+
230
+ /**
231
+ * @brief Returns an iterator pointing the end of the underlying container.
232
+ */
233
+ const_iterator cend() const noexcept { return generator_.cend(); }
234
+
235
+ /**
236
+ * @brief Returns a reverse iterator pointing to the first element from the back of the underlying container.
237
+ */
238
+ reverse_iterator rbegin() noexcept { return generator_.rbegin(); }
239
+
240
+ /**
241
+ * @brief Returns a reverse iterator pointing to the first element from the back of the underlying container.
242
+ */
243
+ const_reverse_iterator rbegin() const noexcept { return generator_.rbegin(); }
244
+
245
+ /**
246
+ * @brief Returns a reverse iterator pointing to the first element from the back of the underlying container.
247
+ */
248
+ const_reverse_iterator crbegin() const noexcept { return generator_.crbegin(); }
249
+
250
+ /**
251
+ * @brief Returns a reverse iterator pointing to the end of the reversed underlying container.
252
+ */
253
+ reverse_iterator rend() noexcept { return generator_.rend(); }
254
+
255
+ /**
256
+ * @brief Returns a reverse iterator pointing to the end of the reversed underlying container.
257
+ */
258
+ const_reverse_iterator rend() const noexcept { return generator_.rend(); }
259
+
260
+ /**
261
+ * @brief Returns a reverse iterator pointing to the end of the reversed underlying container.
262
+ */
263
+ const_reverse_iterator crend() const noexcept { return generator_.crend(); }
264
+
265
+ /**
266
+ * @brief Returns the size of the underlying container. Corresponds exactly to @ref num_parameters(), but enables to
267
+ * use the class as a classic range with a `begin`, `end` and `size` method.
268
+ */
269
+ size_type size() const noexcept { return generator_.size(); }
270
+
271
+ // CONVERTERS
272
+
273
+ // like numpy
274
+ /**
275
+ * @brief Returns a copy with entries casted into the type given as template parameter.
276
+ *
277
+ * @tparam U New type for the entries.
278
+ * @return Copy with new entry type.
279
+ */
280
+ template <typename U>
281
+ Multi_parameter_generator<U> as_type() const
282
+ {
283
+ std::vector<U> out(generator_.begin(), generator_.end());
284
+ return Multi_parameter_generator<U>(std::move(out));
285
+ }
286
+
287
+ // ACCESS
288
+
289
+ /**
290
+ * @brief Returns the number of parameters in the filtration value.
291
+ */
292
+ size_type num_parameters() const { return generator_.size(); }
293
+
294
+ /**
295
+ * @brief Returns a generator for which @ref is_plus_inf() returns `true`.
296
+ */
297
+ static Multi_parameter_generator inf() { return Multi_parameter_generator(1, T_inf); }
298
+
299
+ /**
300
+ * @brief Returns a generator for which @ref is_minus_inf() returns `true`.
301
+ */
302
+ static Multi_parameter_generator minus_inf() { return Multi_parameter_generator(1, T_m_inf); }
303
+
304
+ /**
305
+ * @brief Returns a generator for which @ref is_nan() returns `true`.
306
+ */
307
+ static Multi_parameter_generator nan()
308
+ {
309
+ if constexpr (std::numeric_limits<T>::has_quiet_NaN) {
310
+ return Multi_parameter_generator(1, std::numeric_limits<T>::quiet_NaN());
311
+ } else {
312
+ return Multi_parameter_generator(0);
313
+ }
314
+ }
315
+
316
+ // DESCRIPTORS
317
+
318
+ /**
319
+ * @brief Returns `true` if and only if the generator is considered as plus infinity.
320
+ */
321
+ [[nodiscard]] bool is_plus_inf() const
322
+ {
323
+ for (const T &v : generator_) {
324
+ if (v != T_inf) return false;
325
+ }
326
+ return !generator_.empty();
327
+ }
328
+
329
+ /**
330
+ * @brief Returns `true` if and only if the generator is considered as minus infinity.
331
+ */
332
+ [[nodiscard]] bool is_minus_inf() const
333
+ {
334
+ for (const T &v : generator_) {
335
+ if (v != T_m_inf) return false;
336
+ }
337
+ return !generator_.empty();
338
+ }
339
+
340
+ /**
341
+ * @brief Returns `true` if and only if the generator is considered as NaN.
342
+ */
343
+ [[nodiscard]] bool is_nan() const
344
+ {
345
+ if constexpr (std::numeric_limits<T>::has_quiet_NaN) {
346
+ for (const T &v : generator_) {
347
+ if (!std::isnan(v)) return false;
348
+ }
349
+ return true;
350
+ } else {
351
+ return generator_.empty();
352
+ }
353
+ }
354
+
355
+ /**
356
+ * @brief Returns `true` if and only if the generator is non-empty and is not considered as plus infinity,
357
+ * minus infinity or NaN.
358
+ */
359
+ [[nodiscard]] bool is_finite() const
360
+ {
361
+ bool isInf = true, isMinusInf = true, isNan = true;
362
+ for (const auto &v : generator_) {
363
+ if (v != T_inf) isInf = false;
364
+ if (v != T_m_inf) isMinusInf = false;
365
+ if (!_is_nan(v)) isNan = false;
366
+ if (!isInf && !isMinusInf && !isNan) return true;
367
+ }
368
+ return false;
369
+ }
370
+
371
+ // COMPARAISON OPERATORS
372
+
373
+ /**
374
+ * @brief Returns `true` if and only if the positive cone generated by @p b is strictly contained in the
375
+ * cone generated by @p a. Both @p a and @p b have to have the same number of parameters.
376
+ *
377
+ * Note that not all filtration values are comparable. That is, \f$ a < b \f$ and \f$ b < a \f$ returning both false
378
+ * does **not** imply \f$ a == b \f$.
379
+ */
380
+ friend bool operator<(const Multi_parameter_generator &a, const Multi_parameter_generator &b)
381
+ {
382
+ if (&a == &b) return false;
383
+ if (a.is_nan() || b.is_nan()) return false;
384
+ if (a.is_minus_inf() || b.is_plus_inf()) return true;
385
+ if (b.is_minus_inf() || a.is_plus_inf()) return false;
386
+
387
+ GUDHI_CHECK(a.num_parameters() == b.num_parameters(),
388
+ std::invalid_argument("Only generators with same number of parameters can be compared."));
389
+
390
+ bool isSame = true;
391
+ auto n = a.size();
392
+ for (size_type i = 0U; i < n; ++i) {
393
+ if (a[i] > b[i]) return false;
394
+ if (isSame && a[i] != b[i]) isSame = false;
395
+ }
396
+ return !isSame;
397
+ }
398
+
399
+ /**
400
+ * @brief Returns `true` if and only if the positive cone generated by @p a is strictly contained in the
401
+ * cone generated by @p b. Both @p a and @p b have to have the same number of parameters.
402
+ *
403
+ * Note that not all filtration values are comparable. That is, \f$ a \le b \f$ and \f$ b \le a \f$ can both return
404
+ * `false`.
405
+ */
406
+ friend bool operator<=(const Multi_parameter_generator &a, const Multi_parameter_generator &b)
407
+ {
408
+ if (a.is_nan() || b.is_nan()) return false;
409
+ if (&a == &b) return true;
410
+ const bool aIsMinusInf = a.is_minus_inf();
411
+ const bool aIsPlusInf = a.is_plus_inf();
412
+ const bool bIsMinusInf = b.is_minus_inf();
413
+ const bool bIsPlusInf = b.is_plus_inf();
414
+ if ((aIsMinusInf && bIsMinusInf) || (aIsPlusInf && bIsPlusInf)) return true;
415
+ if (aIsMinusInf || bIsPlusInf) return true;
416
+ if (bIsMinusInf || aIsPlusInf) return false;
417
+
418
+ GUDHI_CHECK(a.num_parameters() == b.num_parameters(),
419
+ std::invalid_argument("Only generators with same number of parameters can be compared."));
420
+
421
+ auto n = a.size();
422
+ for (std::size_t i = 0U; i < n; ++i) {
423
+ if (a[i] > b[i]) return false;
424
+ }
425
+ return true;
426
+ }
427
+
428
+ /**
429
+ * @brief Returns `true` if and only if the positive cone generated by @p b is contained in or are (partially)
430
+ * equal to the positive cone generated by @p a.
431
+ * Both @p a and @p b have to have the same number of parameters.
432
+ *
433
+ * Note that not all filtration values are comparable. That is, \f$ a > b \f$ and \f$ b > a \f$ returning both false
434
+ * does **not** imply \f$ a == b \f$.
435
+ */
436
+ friend bool operator>(const Multi_parameter_generator &a, const Multi_parameter_generator &b) { return b < a; }
437
+
438
+ /**
439
+ * @brief Returns `true` if and only if the positive cone generated by @p a is contained in or are (partially)
440
+ * equal to the positive cone generated by @p b.
441
+ * Both @p a and @p b have to have the same number of parameters.
442
+ *
443
+ * Note that not all filtration values are comparable. That is, \f$ a \ge b \f$ and \f$ b \ge a \f$ can both return
444
+ * `false`.
445
+ */
446
+ friend bool operator>=(const Multi_parameter_generator &a, const Multi_parameter_generator &b) { return b <= a; }
447
+
448
+ /**
449
+ * @brief Returns `true` if and only if for each \f$ i,j \f$, \f$ a(i,j) \f$ is equal to \f$ b(i,j) \f$.
450
+ */
451
+ friend bool operator==(const Multi_parameter_generator &a, const Multi_parameter_generator &b)
452
+ {
453
+ if (a.is_nan() || b.is_nan()) return false;
454
+ if (&a == &b) return true;
455
+ if (a.is_plus_inf()) {
456
+ return b.is_plus_inf();
457
+ }
458
+ if (a.is_minus_inf()) {
459
+ return b.is_minus_inf();
460
+ }
461
+ return a.generator_ == b.generator_;
462
+ }
463
+
464
+ /**
465
+ * @brief Returns `true` if and only if \f$ a == b \f$ returns `false`.
466
+ */
467
+ friend bool operator!=(const Multi_parameter_generator &a, const Multi_parameter_generator &b) { return !(a == b); }
468
+
469
+ // ARITHMETIC OPERATORS
470
+
471
+ // opposite
472
+ /**
473
+ * @brief Returns a generator such that an entry at index \f$ i \f$ is equal to \f$ -g(i) \f$.
474
+ *
475
+ * Used conventions:
476
+ * - \f$ -NaN = NaN \f$.
477
+ *
478
+ * @param g Value to opposite.
479
+ * @return The opposite of @p f.
480
+ */
481
+ friend Multi_parameter_generator operator-(const Multi_parameter_generator &g)
482
+ {
483
+ using F = Multi_parameter_generator;
484
+
485
+ std::vector<T> result(g.generator_);
486
+ std::for_each(result.begin(), result.end(), [](T &v) {
487
+ if (v == F::T_inf)
488
+ v = F::T_m_inf;
489
+ else if (v == F::T_m_inf)
490
+ v = F::T_inf;
491
+ else
492
+ v = -v;
493
+ });
494
+ return Multi_parameter_generator(std::move(result));
495
+ }
496
+
497
+ // subtraction
498
+ /**
499
+ * @brief Returns a generator such that an entry at index \f$ p \f$, with
500
+ * \f$ 0 \leq p \leq num_parameters \f$ is equal to \f$ g(p) - r(p) \f$
501
+ * if \f$ p < length_r \f$ and to \f$ g(p) \f$ otherwise.
502
+ *
503
+ * Used conventions:
504
+ * - \f$ inf - inf = NaN \f$,
505
+ * - \f$ -inf - (-inf) = NaN \f$,
506
+ * - \f$ NaN - b = NaN \f$,
507
+ * - \f$ a - NaN = NaN \f$.
508
+ *
509
+ * All NaN values are represented by `std::numeric_limits<T>::quiet_NaN()` independently if
510
+ * `std::numeric_limits<T>::has_quiet_NaN` is true or not.
511
+ *
512
+ * @tparam ValueRange Range with a begin(), end() and size() method.
513
+ * @param g First element of the subtraction.
514
+ * @param r Second element of the subtraction.
515
+ */
516
+ template <class ValueRange, class = std::enable_if_t<RangeTraits<ValueRange>::has_begin> >
517
+ friend Multi_parameter_generator operator-(Multi_parameter_generator g, const ValueRange &r)
518
+ {
519
+ g -= r;
520
+ return g;
521
+ }
522
+
523
+ /**
524
+ * @brief Returns a generator such that an entry at index \f$ p \f$, with
525
+ * \f$ 0 \leq p \leq num_parameters \f$ is equal to \f$ r(p) - g(p) \f$
526
+ * if \f$ p < length_r \f$ and to \f$ g(p) \f$ otherwise.
527
+ *
528
+ * Used conventions:
529
+ * - \f$ inf - inf = NaN \f$,
530
+ * - \f$ -inf - (-inf) = NaN \f$,
531
+ * - \f$ NaN - b = NaN \f$,
532
+ * - \f$ a - NaN = NaN \f$.
533
+ *
534
+ * All NaN values are represented by `std::numeric_limits<T>::quiet_NaN()` independently if
535
+ * `std::numeric_limits<T>::has_quiet_NaN` is true or not.
536
+ *
537
+ * @tparam ValueRange Range with a begin(), end() and size() method.
538
+ * @param r First element of the subtraction.
539
+ * @param g Second element of the subtraction.
540
+ */
541
+ template <class ValueRange,
542
+ class = std::enable_if_t<RangeTraits<ValueRange>::has_begin &&
543
+ !std::is_same_v<ValueRange, Multi_parameter_generator> > >
544
+ friend Multi_parameter_generator operator-(const ValueRange &r, const Multi_parameter_generator &g)
545
+ {
546
+ if (g.num_parameters() == 0) return g;
547
+ if (g.is_nan()) return nan();
548
+
549
+ if constexpr (RangeTraits<ValueRange>::is_dynamic_multi_filtration) {
550
+ if (r[0].is_finite()) {
551
+ return g -= r[0];
552
+ }
553
+ if constexpr (!std::numeric_limits<T>::has_quiet_NaN)
554
+ if (r[0].size() == 0) return nan();
555
+ return g -= r[0][0];
556
+ } else {
557
+ if (g.is_finite()) {
558
+ Multi_parameter_generator res = g;
559
+ res._apply_operation(r, [](T &valF, const T &valR) -> bool {
560
+ valF = -valF;
561
+ return _add(valF, valR);
562
+ });
563
+ return res;
564
+ }
565
+ Multi_parameter_generator res(r.begin(), r.end());
566
+ res._apply_operation(g[0], [](T &valRes, const T &valF) -> bool { return _subtract(valRes, valF); });
567
+ return res;
568
+ }
569
+ }
570
+
571
+ /**
572
+ * @brief Returns a filtration value such that an entry at index \f$ p \f$ is equal to \f$ g(p) - val \f$.
573
+ *
574
+ * Used conventions:
575
+ * - \f$ inf - inf = NaN \f$,
576
+ * - \f$ -inf - (-inf) = NaN \f$,
577
+ * - \f$ NaN - b = NaN \f$,
578
+ * - \f$ a - NaN = NaN \f$.
579
+ *
580
+ * All NaN values are represented by `std::numeric_limits<T>::quiet_NaN()` independently if
581
+ * `std::numeric_limits<T>::has_quiet_NaN` is true or not.
582
+ *
583
+ * @param g First element of the subtraction.
584
+ * @param val Second element of the subtraction.
585
+ */
586
+ friend Multi_parameter_generator operator-(Multi_parameter_generator g, const T &val)
587
+ {
588
+ g -= val;
589
+ return g;
590
+ }
591
+
592
+ /**
593
+ * @brief Returns a filtration value such that an entry at index \f$ p \f$ is equal to \f$ val - g(p) \f$.
594
+ *
595
+ * Used conventions:
596
+ * - \f$ inf - inf = NaN \f$,
597
+ * - \f$ -inf - (-inf) = NaN \f$,
598
+ * - \f$ NaN - b = NaN \f$,
599
+ * - \f$ a - NaN = NaN \f$.
600
+ *
601
+ * All NaN values are represented by `std::numeric_limits<T>::quiet_NaN()` independently if
602
+ * `std::numeric_limits<T>::has_quiet_NaN` is true or not.
603
+ *
604
+ * @param val First element of the subtraction.
605
+ * @param g Second element of the subtraction.
606
+ */
607
+ friend Multi_parameter_generator operator-(const T &val, Multi_parameter_generator g)
608
+ {
609
+ g._apply_operation(val, [](T &valF, const T &valR) -> bool {
610
+ valF = -valF;
611
+ return _add(valF, valR);
612
+ });
613
+ return g;
614
+ }
615
+
616
+ /**
617
+ * @brief Modifies the first argument such that an entry at index \f$ p \f$, with
618
+ * \f$ 0 \leq p \leq num_parameters \f$ is equal to \f$ g(p) - r(p) \f$
619
+ * if \f$ p < length_r \f$ and to \f$ g(p) \f$ otherwise.
620
+ *
621
+ * Used conventions:
622
+ * - \f$ inf - inf = NaN \f$,
623
+ * - \f$ -inf - (-inf) = NaN \f$,
624
+ * - \f$ NaN - b = NaN \f$,
625
+ * - \f$ a - NaN = NaN \f$.
626
+ *
627
+ * All NaN values are represented by `std::numeric_limits<T>::quiet_NaN()` independently if
628
+ * `std::numeric_limits<T>::has_quiet_NaN` is true or not.
629
+ *
630
+ * @tparam ValueRange Range with a begin(), end() and size() method.
631
+ * @param g First element of the subtraction.
632
+ * @param r Second element of the subtraction.
633
+ */
634
+ template <class ValueRange, class = std::enable_if_t<RangeTraits<ValueRange>::has_begin> >
635
+ friend Multi_parameter_generator &operator-=(Multi_parameter_generator &g, const ValueRange &r)
636
+ {
637
+ if (g.num_parameters() == 0 || g.is_nan()) return g;
638
+
639
+ if constexpr (RangeTraits<ValueRange>::is_dynamic_multi_filtration) {
640
+ if (r[0].is_finite()) {
641
+ return g -= r[0];
642
+ }
643
+ if constexpr (!std::numeric_limits<T>::has_quiet_NaN)
644
+ if (r[0].size() == 0) {
645
+ g = nan();
646
+ return g;
647
+ }
648
+ return g -= r[0][0];
649
+ } else {
650
+ if (!g.is_finite()) {
651
+ g.generator_.resize(r.size(), g[0]);
652
+ }
653
+ g._apply_operation(r, [](T &valF, const T &valR) -> bool { return _subtract(valF, valR); });
654
+ }
655
+
656
+ return g;
657
+ }
658
+
659
+ /**
660
+ * @brief Modifies the first parameter such that an entry at index \f$ p \f$ is equal to \f$ g(p) - val \f$.
661
+ *
662
+ * Used conventions:
663
+ * - \f$ inf - inf = NaN \f$,
664
+ * - \f$ -inf - (-inf) = NaN \f$,
665
+ * - \f$ NaN - b = NaN \f$,
666
+ * - \f$ a - NaN = NaN \f$.
667
+ *
668
+ * All NaN values are represented by `std::numeric_limits<T>::quiet_NaN()` independently if
669
+ * `std::numeric_limits<T>::has_quiet_NaN` is true or not.
670
+ *
671
+ * @param g First element of the subtraction.
672
+ * @param val Second element of the subtraction.
673
+ */
674
+ friend Multi_parameter_generator &operator-=(Multi_parameter_generator &g, const T &val)
675
+ {
676
+ g._apply_operation(val, [](T &valF, const T &valR) -> bool { return _subtract(valF, valR); });
677
+ return g;
678
+ }
679
+
680
+ // addition
681
+ /**
682
+ * @brief Returns a generator such that an entry at index \f$ p \f$, with
683
+ * \f$ 0 \leq p \leq num_parameters \f$ is equal to \f$ g(p) + r(p) \f$
684
+ * if \f$ p < length_r \f$ and to \f$ g(p) \f$ otherwise.
685
+ *
686
+ * Used conventions:
687
+ * - \f$ inf + (-inf) = NaN \f$,
688
+ * - \f$ -inf + inf = NaN \f$,
689
+ * - \f$ NaN + b = NaN \f$,
690
+ * - \f$ a + NaN = NaN \f$.
691
+ *
692
+ * All NaN values are represented by `std::numeric_limits<T>::quiet_NaN()` independently if
693
+ * `std::numeric_limits<T>::has_quiet_NaN` is true or not.
694
+ *
695
+ * @tparam ValueRange Range with a begin(), end() and size() method.
696
+ * @param g First element of the addition.
697
+ * @param r Second element of the addition.
698
+ */
699
+ template <class ValueRange, class = std::enable_if_t<RangeTraits<ValueRange>::has_begin> >
700
+ friend Multi_parameter_generator operator+(Multi_parameter_generator g, const ValueRange &r)
701
+ {
702
+ g += r;
703
+ return g;
704
+ }
705
+
706
+ /**
707
+ * @brief Returns a generator such that an entry at index \f$ p \f$, with
708
+ * \f$ 0 \leq p \leq num_parameters \f$ is equal to \f$ r(p) + g(p) \f$
709
+ * if \f$ p < length_r \f$ and to \f$ g(p) \f$ otherwise.
710
+ *
711
+ * Used conventions:
712
+ * - \f$ inf + (-inf) = NaN \f$,
713
+ * - \f$ -inf + inf = NaN \f$,
714
+ * - \f$ NaN + b = NaN \f$,
715
+ * - \f$ a + NaN = NaN \f$.
716
+ *
717
+ * All NaN values are represented by `std::numeric_limits<T>::quiet_NaN()` independently if
718
+ * `std::numeric_limits<T>::has_quiet_NaN` is true or not.
719
+ *
720
+ * @tparam ValueRange Range with a begin(), end() and size() method.
721
+ * @param r First element of the addition.
722
+ * @param g Second element of the addition.
723
+ */
724
+ template <class ValueRange,
725
+ class = std::enable_if_t<RangeTraits<ValueRange>::has_begin &&
726
+ !std::is_same_v<ValueRange, Multi_parameter_generator> > >
727
+ friend Multi_parameter_generator operator+(const ValueRange &r, Multi_parameter_generator g)
728
+ {
729
+ g += r;
730
+ return g;
731
+ }
732
+
733
+ /**
734
+ * @brief Returns a filtration value such that an entry at index \f$ p \f$ is equal to \f$ g(p) + val \f$.
735
+ *
736
+ * Used conventions:
737
+ * - \f$ inf + (-inf) = NaN \f$,
738
+ * - \f$ -inf + inf = NaN \f$,
739
+ * - \f$ NaN + b = NaN \f$,
740
+ * - \f$ a + NaN = NaN \f$.
741
+ *
742
+ * All NaN values are represented by `std::numeric_limits<T>::quiet_NaN()` independently if
743
+ * `std::numeric_limits<T>::has_quiet_NaN` is true or not.
744
+ *
745
+ * @param g First element of the addition.
746
+ * @param val Second element of the addition.
747
+ */
748
+ friend Multi_parameter_generator operator+(Multi_parameter_generator g, const T &val)
749
+ {
750
+ g += val;
751
+ return g;
752
+ }
753
+
754
+ /**
755
+ * @brief Returns a filtration value such that an entry at index \f$ p \f$ is equal to \f$ g(p) + val \f$.
756
+ *
757
+ * Used conventions:
758
+ * - \f$ inf + (-inf) = NaN \f$,
759
+ * - \f$ -inf + inf = NaN \f$,
760
+ * - \f$ NaN + b = NaN \f$,
761
+ * - \f$ a + NaN = NaN \f$.
762
+ *
763
+ * All NaN values are represented by `std::numeric_limits<T>::quiet_NaN()` independently if
764
+ * `std::numeric_limits<T>::has_quiet_NaN` is true or not.
765
+ *
766
+ * @param val First element of the addition.
767
+ * @param g Second element of the addition.
768
+ */
769
+ friend Multi_parameter_generator operator+(const T &val, Multi_parameter_generator g)
770
+ {
771
+ g += val;
772
+ return g;
773
+ }
774
+
775
+ /**
776
+ * @brief Modifies the first argument such that an entry at index \f$ p \f$, with
777
+ * \f$ 0 \leq p \leq num_parameters \f$ is equal to \f$ g(p) + r(p) \f$
778
+ * if \f$ p < length_r \f$ and to \f$ g(p) \f$ otherwise.
779
+ *
780
+ * Used conventions:
781
+ * - \f$ inf + (-inf) = NaN \f$,
782
+ * - \f$ -inf + inf = NaN \f$,
783
+ * - \f$ NaN + b = NaN \f$,
784
+ * - \f$ a + NaN = NaN \f$.
785
+ *
786
+ * All NaN values are represented by `std::numeric_limits<T>::quiet_NaN()` independently if
787
+ * `std::numeric_limits<T>::has_quiet_NaN` is true or not.
788
+ *
789
+ * @tparam ValueRange Range with a begin(), end() and size() method.
790
+ * @param g First element of the addition.
791
+ * @param r Second element of the addition.
792
+ */
793
+ template <class ValueRange, class = std::enable_if_t<RangeTraits<ValueRange>::has_begin> >
794
+ friend Multi_parameter_generator &operator+=(Multi_parameter_generator &g, const ValueRange &r)
795
+ {
796
+ if (g.num_parameters() == 0 || g.is_nan()) return g;
797
+
798
+ if constexpr (RangeTraits<ValueRange>::is_dynamic_multi_filtration) {
799
+ if (r[0].is_finite()) {
800
+ return g += r[0];
801
+ }
802
+ if constexpr (!std::numeric_limits<T>::has_quiet_NaN)
803
+ if (r[0].size() == 0) {
804
+ g = nan();
805
+ return g;
806
+ }
807
+ return g += r[0][0];
808
+ } else {
809
+ if (!g.is_finite()) {
810
+ g.generator_.resize(r.size(), g[0]);
811
+ }
812
+ g._apply_operation(r, [](T &valF, const T &valR) -> bool { return _add(valF, valR); });
813
+ }
814
+
815
+ return g;
816
+ }
817
+
818
+ /**
819
+ * @brief Modifies the first parameter such that an entry at index \f$ p \f$ is equal to \f$ g(p) + val \f$.
820
+ *
821
+ * Used conventions:
822
+ * - \f$ inf + (-inf) = NaN \f$,
823
+ * - \f$ -inf + inf = NaN \f$,
824
+ * - \f$ NaN + b = NaN \f$,
825
+ * - \f$ a + NaN = NaN \f$.
826
+ *
827
+ * All NaN values are represented by `std::numeric_limits<T>::quiet_NaN()` independently if
828
+ * `std::numeric_limits<T>::has_quiet_NaN` is true or not.
829
+ *
830
+ * @param g First element of the addition.
831
+ * @param val Second element of the addition.
832
+ */
833
+ friend Multi_parameter_generator &operator+=(Multi_parameter_generator &g, const T &val)
834
+ {
835
+ g._apply_operation(val, [](T &valF, const T &valR) -> bool { return _add(valF, valR); });
836
+ return g;
837
+ }
838
+
839
+ // multiplication
840
+ /**
841
+ * @brief Returns a generator such that an entry at index \f$ p \f$, with
842
+ * \f$ 0 \leq p \leq num_parameters \f$ is equal to \f$ g(p) * r(p) \f$
843
+ * if \f$ p < length_r \f$ and to \f$ g(p) \f$ otherwise.
844
+ *
845
+ * Used conventions:
846
+ * - \f$ inf * 0 = NaN \f$,
847
+ * - \f$ 0 * inf = NaN \f$,
848
+ * - \f$ -inf * 0 = NaN \f$,
849
+ * - \f$ 0 * (-inf) = NaN \f$,
850
+ * - \f$ NaN * b = NaN \f$,
851
+ * - \f$ a * NaN = NaN \f$.
852
+ *
853
+ * All NaN values are represented by `std::numeric_limits<T>::quiet_NaN()` independently if
854
+ * `std::numeric_limits<T>::has_quiet_NaN` is true or not.
855
+ *
856
+ * @tparam ValueRange Range with a begin(), end() and size() method.
857
+ * @param g First element of the multiplication.
858
+ * @param r Second element of the multiplication.
859
+ */
860
+ template <class ValueRange, class = std::enable_if_t<RangeTraits<ValueRange>::has_begin> >
861
+ friend Multi_parameter_generator operator*(Multi_parameter_generator g, const ValueRange &r)
862
+ {
863
+ g *= r;
864
+ return g;
865
+ }
866
+
867
+ /**
868
+ * @brief Returns a generator such that an entry at index \f$ p \f$, with
869
+ * \f$ 0 \leq p \leq num_parameters \f$ is equal to \f$ g(p) * r(p) \f$
870
+ * if \f$ p < length_r \f$ and to \f$ g(p) \f$ otherwise.
871
+ *
872
+ * Used conventions:
873
+ * - \f$ inf * 0 = NaN \f$,
874
+ * - \f$ 0 * inf = NaN \f$,
875
+ * - \f$ -inf * 0 = NaN \f$,
876
+ * - \f$ 0 * (-inf) = NaN \f$,
877
+ * - \f$ NaN * b = NaN \f$,
878
+ * - \f$ a * NaN = NaN \f$.
879
+ *
880
+ * All NaN values are represented by `std::numeric_limits<T>::quiet_NaN()` independently if
881
+ * `std::numeric_limits<T>::has_quiet_NaN` is true or not.
882
+ *
883
+ * @tparam ValueRange Range with a begin(), end() and size() method.
884
+ * @param r First element of the multiplication.
885
+ * @param g Second element of the multiplication.
886
+ */
887
+ template <class ValueRange,
888
+ class = std::enable_if_t<RangeTraits<ValueRange>::has_begin &&
889
+ !std::is_same_v<ValueRange, Multi_parameter_generator> > >
890
+ friend Multi_parameter_generator operator*(const ValueRange &r, Multi_parameter_generator g)
891
+ {
892
+ g *= r;
893
+ return g;
894
+ }
895
+
896
+ /**
897
+ * @brief Returns a filtration value such that an entry at index \f$ p \f$ is equal to \f$ g(p) * val \f$.
898
+ *
899
+ * Used conventions:
900
+ * - \f$ inf * 0 = NaN \f$,
901
+ * - \f$ 0 * inf = NaN \f$,
902
+ * - \f$ -inf * 0 = NaN \f$,
903
+ * - \f$ 0 * (-inf) = NaN \f$,
904
+ * - \f$ NaN * b = NaN \f$,
905
+ * - \f$ a * NaN = NaN \f$.
906
+ *
907
+ * All NaN values are represented by `std::numeric_limits<T>::quiet_NaN()` independently if
908
+ * `std::numeric_limits<T>::has_quiet_NaN` is true or not.
909
+ *
910
+ * @param g First element of the multiplication.
911
+ * @param val Second element of the multiplication.
912
+ */
913
+ friend Multi_parameter_generator operator*(Multi_parameter_generator g, const T &val)
914
+ {
915
+ g *= val;
916
+ return g;
917
+ }
918
+
919
+ /**
920
+ * @brief Returns a filtration value such that an entry at index \f$ p \f$ is equal to \f$ g(p) * val \f$.
921
+ *
922
+ * Used conventions:
923
+ * - \f$ inf * 0 = NaN \f$,
924
+ * - \f$ 0 * inf = NaN \f$,
925
+ * - \f$ -inf * 0 = NaN \f$,
926
+ * - \f$ 0 * (-inf) = NaN \f$,
927
+ * - \f$ NaN * b = NaN \f$,
928
+ * - \f$ a * NaN = NaN \f$.
929
+ *
930
+ * All NaN values are represented by `std::numeric_limits<T>::quiet_NaN()` independently if
931
+ * `std::numeric_limits<T>::has_quiet_NaN` is true or not.
932
+ *
933
+ * @param val First element of the multiplication.
934
+ * @param g Second element of the multiplication.
935
+ */
936
+ friend Multi_parameter_generator operator*(const T &val, Multi_parameter_generator g)
937
+ {
938
+ g *= val;
939
+ return g;
940
+ }
941
+
942
+ /**
943
+ * @brief Modifies the first argument such that an entry at index \f$ p \f$, with
944
+ * \f$ 0 \leq p \leq num_parameters \f$ is equal to \f$ g(p) * r(p) \f$
945
+ * if \f$ p < length_r \f$ and to \f$ g(p) \f$ otherwise.
946
+ *
947
+ * Used conventions:
948
+ * - \f$ inf * 0 = NaN \f$,
949
+ * - \f$ 0 * inf = NaN \f$,
950
+ * - \f$ -inf * 0 = NaN \f$,
951
+ * - \f$ 0 * (-inf) = NaN \f$,
952
+ * - \f$ NaN * b = NaN \f$,
953
+ * - \f$ a * NaN = NaN \f$.
954
+ *
955
+ * All NaN values are represented by `std::numeric_limits<T>::quiet_NaN()` independently if
956
+ * `std::numeric_limits<T>::has_quiet_NaN` is true or not.
957
+ *
958
+ * @tparam ValueRange Range with a begin(), end() and size() method.
959
+ * @param g First element of the multiplication.
960
+ * @param r Second element of the multiplication.
961
+ */
962
+ template <class ValueRange, class = std::enable_if_t<RangeTraits<ValueRange>::has_begin> >
963
+ friend Multi_parameter_generator &operator*=(Multi_parameter_generator &g, const ValueRange &r)
964
+ {
965
+ if (g.num_parameters() == 0 || g.is_nan()) return g;
966
+
967
+ if constexpr (RangeTraits<ValueRange>::is_dynamic_multi_filtration) {
968
+ if (r[0].is_finite()) {
969
+ return g *= r[0];
970
+ }
971
+ if constexpr (!std::numeric_limits<T>::has_quiet_NaN)
972
+ if (r[0].size() == 0) {
973
+ g = nan();
974
+ return g;
975
+ }
976
+ return g *= r[0][0];
977
+ } else {
978
+ if (!g.is_finite()) {
979
+ g.generator_.resize(r.size(), g[0]);
980
+ }
981
+ g._apply_operation(r, [](T &valF, const T &valR) -> bool { return _multiply(valF, valR); });
982
+ }
983
+
984
+ return g;
985
+ }
986
+
987
+ /**
988
+ * @brief Modifies the first parameter such that an entry at index \f$ p \f$ is equal to \f$ g(p) * val \f$.
989
+ *
990
+ * Used conventions:
991
+ * - \f$ inf * 0 = NaN \f$,
992
+ * - \f$ 0 * inf = NaN \f$,
993
+ * - \f$ -inf * 0 = NaN \f$,
994
+ * - \f$ 0 * (-inf) = NaN \f$,
995
+ * - \f$ NaN * b = NaN \f$,
996
+ * - \f$ a * NaN = NaN \f$.
997
+ *
998
+ * All NaN values are represented by `std::numeric_limits<T>::quiet_NaN()` independently if
999
+ * `std::numeric_limits<T>::has_quiet_NaN` is true or not.
1000
+ *
1001
+ * @param g First element of the multiplication.
1002
+ * @param val Second element of the multiplication.
1003
+ */
1004
+ friend Multi_parameter_generator &operator*=(Multi_parameter_generator &g, const T &val)
1005
+ {
1006
+ g._apply_operation(val, [](T &valF, const T &valR) -> bool { return _multiply(valF, valR); });
1007
+ return g;
1008
+ }
1009
+
1010
+ // division
1011
+ /**
1012
+ * @brief Returns a generator such that an entry at index \f$ p \f$, with
1013
+ * \f$ 0 \leq p \leq num_parameters \f$ is equal to \f$ g(p) / r(p) \f$
1014
+ * if \f$ p < length_r \f$ and to \f$ g(p) \f$ otherwise.
1015
+ *
1016
+ * Used conventions:
1017
+ * - \f$ a / 0 = NaN \f$,
1018
+ * - \f$ inf / inf = NaN \f$,
1019
+ * - \f$ -inf / inf = NaN \f$,
1020
+ * - \f$ inf / -inf = NaN \f$,
1021
+ * - \f$ -inf / -inf = NaN \f$,
1022
+ * - \f$ NaN / b = NaN \f$,
1023
+ * - \f$ a / NaN = NaN \f$,
1024
+ * - \f$ a / inf = 0 \f$,
1025
+ * - \f$ a / -inf = 0 \f$.
1026
+ *
1027
+ * All NaN values are represented by `std::numeric_limits<T>::quiet_NaN()` independently if
1028
+ * `std::numeric_limits<T>::has_quiet_NaN` is true or not.
1029
+ *
1030
+ * @tparam ValueRange Range with a begin(), end() and size() method.
1031
+ * @param g First element of the division.
1032
+ * @param r Second element of the division.
1033
+ */
1034
+ template <class ValueRange, class = std::enable_if_t<RangeTraits<ValueRange>::has_begin> >
1035
+ friend Multi_parameter_generator operator/(Multi_parameter_generator g, const ValueRange &r)
1036
+ {
1037
+ g /= r;
1038
+ return g;
1039
+ }
1040
+
1041
+ /**
1042
+ * @brief Returns a generator such that an entry at index \f$ p \f$, with
1043
+ * \f$ 0 \leq p \leq num_parameters \f$ is equal to \f$ r(p) / g(p) \f$
1044
+ * if \f$ p < length_r \f$ and to \f$ g(p) \f$ otherwise.
1045
+ *
1046
+ * Used conventions:
1047
+ * - \f$ a / 0 = NaN \f$,
1048
+ * - \f$ inf / inf = NaN \f$,
1049
+ * - \f$ -inf / inf = NaN \f$,
1050
+ * - \f$ inf / -inf = NaN \f$,
1051
+ * - \f$ -inf / -inf = NaN \f$,
1052
+ * - \f$ NaN / b = NaN \f$,
1053
+ * - \f$ a / NaN = NaN \f$,
1054
+ * - \f$ a / inf = 0 \f$,
1055
+ * - \f$ a / -inf = 0 \f$.
1056
+ *
1057
+ * All NaN values are represented by `std::numeric_limits<T>::quiet_NaN()` independently if
1058
+ * `std::numeric_limits<T>::has_quiet_NaN` is true or not.
1059
+ *
1060
+ * @tparam ValueRange Range with a begin(), end() and size() method.
1061
+ * @param r First element of the division.
1062
+ * @param g Second element of the division.
1063
+ */
1064
+ template <class ValueRange,
1065
+ class = std::enable_if_t<RangeTraits<ValueRange>::has_begin &&
1066
+ !std::is_same_v<ValueRange, Multi_parameter_generator> > >
1067
+ friend Multi_parameter_generator operator/(const ValueRange &r, const Multi_parameter_generator &g)
1068
+ {
1069
+ if (g.num_parameters() == 0) return g;
1070
+ if (g.is_nan()) return nan();
1071
+
1072
+ if constexpr (RangeTraits<ValueRange>::is_dynamic_multi_filtration) {
1073
+ if (r[0].is_finite()) {
1074
+ return r[0] / g;
1075
+ }
1076
+ if constexpr (!std::numeric_limits<T>::has_quiet_NaN)
1077
+ if (r[0].size() == 0) return nan();
1078
+ return r[0][0] / g;
1079
+ } else {
1080
+ if (g.is_finite()) {
1081
+ Multi_parameter_generator res = g;
1082
+ res._apply_operation(r, [](T &valF, const T &valR) -> bool {
1083
+ T tmp = valF;
1084
+ valF = valR;
1085
+ return _divide(valF, tmp);
1086
+ });
1087
+ return res;
1088
+ }
1089
+ Multi_parameter_generator res(r.begin(), r.end());
1090
+ res._apply_operation(g[0], [](T &valRes, const T &valF) -> bool { return _divide(valRes, valF); });
1091
+ return res;
1092
+ }
1093
+ }
1094
+
1095
+ /**
1096
+ * @brief Returns a filtration value such that an entry at index \f$ p \f$ is equal to \f$ g(p) / val \f$.
1097
+ *
1098
+ * Used conventions:
1099
+ * - \f$ a / 0 = NaN \f$,
1100
+ * - \f$ inf / inf = NaN \f$,
1101
+ * - \f$ -inf / inf = NaN \f$,
1102
+ * - \f$ inf / -inf = NaN \f$,
1103
+ * - \f$ -inf / -inf = NaN \f$,
1104
+ * - \f$ NaN / b = NaN \f$,
1105
+ * - \f$ a / NaN = NaN \f$,
1106
+ * - \f$ a / inf = 0 \f$,
1107
+ * - \f$ a / -inf = 0 \f$.
1108
+ *
1109
+ * All NaN values are represented by `std::numeric_limits<T>::quiet_NaN()` independently if
1110
+ * `std::numeric_limits<T>::has_quiet_NaN` is true or not.
1111
+ *
1112
+ * @param g First element of the division.
1113
+ * @param val Second element of the division.
1114
+ */
1115
+ friend Multi_parameter_generator operator/(Multi_parameter_generator g, const T &val)
1116
+ {
1117
+ g /= val;
1118
+ return g;
1119
+ }
1120
+
1121
+ /**
1122
+ * @brief Returns a filtration value such that an entry at index \f$ p \f$ is equal to \f$ val / g(p) \f$.
1123
+ *
1124
+ * Used conventions:
1125
+ * - \f$ a / 0 = NaN \f$,
1126
+ * - \f$ inf / inf = NaN \f$,
1127
+ * - \f$ -inf / inf = NaN \f$,
1128
+ * - \f$ inf / -inf = NaN \f$,
1129
+ * - \f$ -inf / -inf = NaN \f$,
1130
+ * - \f$ NaN / b = NaN \f$,
1131
+ * - \f$ a / NaN = NaN \f$,
1132
+ * - \f$ a / inf = 0 \f$,
1133
+ * - \f$ a / -inf = 0 \f$.
1134
+ *
1135
+ * All NaN values are represented by `std::numeric_limits<T>::quiet_NaN()` independently if
1136
+ * `std::numeric_limits<T>::has_quiet_NaN` is true or not.
1137
+ *
1138
+ * @param val First element of the division.
1139
+ * @param g Second element of the division.
1140
+ */
1141
+ friend Multi_parameter_generator operator/(const T &val, Multi_parameter_generator g)
1142
+ {
1143
+ g._apply_operation(val, [](T &valF, const T &valR) -> bool {
1144
+ T tmp = valF;
1145
+ valF = valR;
1146
+ return _divide(valF, tmp);
1147
+ });
1148
+ return g;
1149
+ }
1150
+
1151
+ /**
1152
+ * @brief Modifies the first argument such that an entry at index \f$ p \f$, with
1153
+ * \f$ 0 \leq p \leq num_parameters \f$ is equal to \f$ g(p) / r(p) \f$
1154
+ * if \f$ p < length_r \f$ and to \f$ g(p) \f$ otherwise.
1155
+ *
1156
+ * Used conventions:
1157
+ * - \f$ a / 0 = NaN \f$,
1158
+ * - \f$ inf / inf = NaN \f$,
1159
+ * - \f$ -inf / inf = NaN \f$,
1160
+ * - \f$ inf / -inf = NaN \f$,
1161
+ * - \f$ -inf / -inf = NaN \f$,
1162
+ * - \f$ NaN / b = NaN \f$,
1163
+ * - \f$ a / NaN = NaN \f$,
1164
+ * - \f$ a / inf = 0 \f$,
1165
+ * - \f$ a / -inf = 0 \f$.
1166
+ *
1167
+ * All NaN values are represented by `std::numeric_limits<T>::quiet_NaN()` independently if
1168
+ * `std::numeric_limits<T>::has_quiet_NaN` is true or not.
1169
+ *
1170
+ * @tparam ValueRange Range with a begin(), end() and size() method.
1171
+ * @param g First element of the division.
1172
+ * @param r Second element of the division.
1173
+ */
1174
+ template <class ValueRange, class = std::enable_if_t<RangeTraits<ValueRange>::has_begin> >
1175
+ friend Multi_parameter_generator &operator/=(Multi_parameter_generator &g, const ValueRange &r)
1176
+ {
1177
+ if (g.num_parameters() == 0 || g.is_nan()) return g;
1178
+
1179
+ if constexpr (RangeTraits<ValueRange>::is_dynamic_multi_filtration) {
1180
+ if (r[0].is_finite()) {
1181
+ return g /= r[0];
1182
+ }
1183
+ if constexpr (!std::numeric_limits<T>::has_quiet_NaN)
1184
+ if (r[0].size() == 0) {
1185
+ g = nan();
1186
+ return g;
1187
+ }
1188
+ return g /= r[0][0];
1189
+ } else {
1190
+ if (!g.is_finite()) {
1191
+ g.generator_.resize(r.size(), g[0]);
1192
+ }
1193
+ g._apply_operation(r, [](T &valF, const T &valR) -> bool { return _divide(valF, valR); });
1194
+ }
1195
+
1196
+ return g;
1197
+ }
1198
+
1199
+ /**
1200
+ * @brief Modifies the first parameter such that an entry at index \f$ p \f$ is equal to \f$ g(p) / val \f$.
1201
+ *
1202
+ * Used conventions:
1203
+ * - \f$ a / 0 = NaN \f$,
1204
+ * - \f$ inf / inf = NaN \f$,
1205
+ * - \f$ -inf / inf = NaN \f$,
1206
+ * - \f$ inf / -inf = NaN \f$,
1207
+ * - \f$ -inf / -inf = NaN \f$,
1208
+ * - \f$ NaN / b = NaN \f$,
1209
+ * - \f$ a / NaN = NaN \f$,
1210
+ * - \f$ a / inf = 0 \f$,
1211
+ * - \f$ a / -inf = 0 \f$.
1212
+ *
1213
+ * All NaN values are represented by `std::numeric_limits<T>::quiet_NaN()` independently if
1214
+ * `std::numeric_limits<T>::has_quiet_NaN` is true or not.
1215
+ *
1216
+ * @param g First element of the division.
1217
+ * @param val Second element of the division.
1218
+ */
1219
+ friend Multi_parameter_generator &operator/=(Multi_parameter_generator &g, const T &val)
1220
+ {
1221
+ g._apply_operation(val, [](T &valF, const T &valR) -> bool { return _divide(valF, valR); });
1222
+ return g;
1223
+ }
1224
+
1225
+ // MODIFIERS
1226
+
1227
+ /**
1228
+ * @brief If the filtration value is at +/- infinity or NaN, the underlying container will probably only contain
1229
+ * one element, representing the value. This method forces the underlying container to contain explicitly
1230
+ * `number_of_parameters` elements. If the container is empty, it will fill all new elements with the default
1231
+ * value -inf. If the container had more than one element, it does nothing and fails in Debug Mode if the number was
1232
+ * different from `number_of_parameters`.
1233
+ */
1234
+ void force_size_to_number_of_parameters(int number_of_parameters)
1235
+ {
1236
+ if (number_of_parameters < 1) return;
1237
+
1238
+ if (generator_.size() > 1) {
1239
+ GUDHI_CHECK(static_cast<std::size_t>(number_of_parameters) == generator_.size(),
1240
+ std::invalid_argument("Cannot force size to another number of parameters than set."));
1241
+ return;
1242
+ }
1243
+
1244
+ auto val = generator_.empty() ? _get_default_value() : generator_[0];
1245
+ generator_.resize(number_of_parameters, val);
1246
+ }
1247
+
1248
+ /**
1249
+ * @brief Sets the generator to the least common upper bound between it and the given value.
1250
+ *
1251
+ * @tparam GeneratorRange Range of elements convertible to `T`. Must have a begin(), end() and size() method.
1252
+ * @param x Range towards to push. Has to have as many elements than @ref num_parameters().
1253
+ * @param exclude_infinite_values If true, values at infinity or minus infinity are not affected.
1254
+ * @return true If the filtration value was actually modified.
1255
+ * @return false Otherwise.
1256
+ */
1257
+ template <class GeneratorRange = std::initializer_list<value_type>,
1258
+ class = std::enable_if_t<RangeTraits<GeneratorRange>::has_begin> >
1259
+ bool push_to_least_common_upper_bound(const GeneratorRange &x, bool exclude_infinite_values = false)
1260
+ {
1261
+ if (is_nan() || is_plus_inf()) return false;
1262
+ if (x.size() == 0) {
1263
+ *this = nan();
1264
+ return true;
1265
+ }
1266
+
1267
+ if constexpr (RangeTraits<GeneratorRange>::is_dynamic_multi_filtration) {
1268
+ return push_to_least_common_upper_bound(x[0], exclude_infinite_values);
1269
+ } else {
1270
+ if (is_minus_inf()) {
1271
+ generator_ = Underlying_container(x.begin(), x.end());
1272
+ if (is_minus_inf()) {
1273
+ *this = minus_inf();
1274
+ return false;
1275
+ }
1276
+ if (is_nan()) *this = nan();
1277
+ if (is_plus_inf()) *this = inf();
1278
+ return true;
1279
+ }
1280
+
1281
+ bool modified = false;
1282
+
1283
+ auto it = x.begin();
1284
+ for (size_type p = 0; p < generator_.size(); ++p) {
1285
+ T valX = *it;
1286
+ if (!exclude_infinite_values || (valX != T_inf && valX != T_m_inf)) {
1287
+ modified |= generator_[p] < valX;
1288
+ generator_[p] = valX > generator_[p] ? valX : generator_[p];
1289
+ }
1290
+ if (it + 1 != x.end()) ++it;
1291
+ }
1292
+
1293
+ return modified;
1294
+ }
1295
+ }
1296
+
1297
+ /**
1298
+ * @brief Sets each the generator to the greatest common lower bound between it and the given value.
1299
+ *
1300
+ * @tparam GeneratorRange Range of elements convertible to `T`. Must have a begin(), end() and size() method.
1301
+ * @param x Range towards to pull. Has to have as many elements than @ref num_parameters().
1302
+ * @param exclude_infinite_values If true, values at infinity or minus infinity are not affected.
1303
+ * @return true If the filtration value was actually modified.
1304
+ * @return false Otherwise.
1305
+ */
1306
+ template <class GeneratorRange = std::initializer_list<value_type>,
1307
+ class = std::enable_if_t<RangeTraits<GeneratorRange>::has_begin> >
1308
+ bool pull_to_greatest_common_lower_bound(const GeneratorRange &x, bool exclude_infinite_values = false)
1309
+ {
1310
+ if (is_nan() || is_minus_inf()) return false;
1311
+ if (x.size() == 0) {
1312
+ *this = nan();
1313
+ return true;
1314
+ }
1315
+
1316
+ if constexpr (RangeTraits<GeneratorRange>::is_dynamic_multi_filtration) {
1317
+ return pull_to_greatest_common_lower_bound(x[0], exclude_infinite_values);
1318
+ } else {
1319
+ if (is_plus_inf()) {
1320
+ generator_ = Underlying_container(x.begin(), x.end());
1321
+ if (is_plus_inf()) {
1322
+ *this = inf();
1323
+ return false;
1324
+ }
1325
+ if (is_nan()) *this = nan();
1326
+ if (is_minus_inf()) *this = minus_inf();
1327
+ return true;
1328
+ }
1329
+
1330
+ bool modified = false;
1331
+
1332
+ auto it = x.begin();
1333
+ for (size_type p = 0; p < generator_.size() && it != x.end(); ++p) {
1334
+ T valX = *it;
1335
+ if (!exclude_infinite_values || (valX != T_inf && valX != T_m_inf)) {
1336
+ modified |= generator_[p] > valX;
1337
+ generator_[p] = valX < generator_[p] ? valX : generator_[p];
1338
+ }
1339
+ if (it + 1 != x.end()) ++it;
1340
+ }
1341
+
1342
+ return modified;
1343
+ }
1344
+ }
1345
+
1346
+ /**
1347
+ * @brief Projects the generator into the given grid. If @p coordinate is false, the entries are set to
1348
+ * the nearest upper bound value with the same parameter in the grid. Otherwise, the entries are set to the indices
1349
+ * of those nearest upper bound values.
1350
+ * The grid has to be represented as a vector of ordered ranges of values convertible into `T`. An index
1351
+ * \f$ i \f$ of the vector corresponds to the same parameter as the index \f$ i \f$ in a generator of the filtration
1352
+ * value. The ranges correspond to the possible values of the parameters, ordered by increasing value, forming
1353
+ * therefore all together a 2D grid.
1354
+ *
1355
+ * @tparam OneDimArray A range of values convertible into `T` ordered by increasing value. Has to implement
1356
+ * a begin, end and operator[] method.
1357
+ * @param grid Vector of @p OneDimArray with size at least number of filtration parameters.
1358
+ * @param coordinate If true, the values are set to the coordinates of the projection in the grid. If false,
1359
+ * the values are set to the values at the coordinates of the projection.
1360
+ */
1361
+ template <typename OneDimArray>
1362
+ void project_onto_grid(const std::vector<OneDimArray> &grid, bool coordinate = true) {
1363
+ GUDHI_CHECK(
1364
+ grid.size() >= generator_.size(),
1365
+ std::invalid_argument("The grid should not be smaller than the number of parameters in the filtration value."));
1366
+
1367
+ if (is_nan() || generator_.empty()) return;
1368
+
1369
+ if (!is_finite()) generator_.resize(grid.size(), generator_[0]);
1370
+
1371
+ auto todo = [&](size_type p) {
1372
+ const auto &filtration = grid[p];
1373
+ auto v = static_cast<typename OneDimArray::value_type>(generator_[p]);
1374
+ auto d = std::distance(filtration.begin(), std::lower_bound(filtration.begin(), filtration.end(), v));
1375
+ if (d != 0 && std::abs(v - filtration[d]) > std::abs(v - filtration[d - 1])) {
1376
+ --d;
1377
+ }
1378
+ generator_[p] = coordinate ? static_cast<T>(d) : static_cast<T>(filtration[d]);
1379
+ };
1380
+ #ifdef GUDHI_USE_TBB
1381
+ tbb::parallel_for(size_type(0), generator_.size(), todo);
1382
+ #else
1383
+ for (size_type p = 0; p < generator_.size(); ++p) {
1384
+ todo(p);
1385
+ }
1386
+ #endif
1387
+ }
1388
+
1389
+ // FONCTIONNALITIES
1390
+
1391
+ /**
1392
+ * @brief Computes the scalar product of the generator with the given vector.
1393
+ *
1394
+ * @tparam U Arithmetic type of the result. Default value: `T`.
1395
+ * @param g Filtration value.
1396
+ * @param x Vector of coefficients.
1397
+ * @return Scalar product of @p f with @p x.
1398
+ */
1399
+ template <typename U = T>
1400
+ friend U compute_linear_projection(const Multi_parameter_generator &g, const std::vector<U> &x)
1401
+ {
1402
+ U projection = 0;
1403
+ std::size_t size = std::min(x.size(), g.num_parameters());
1404
+ for (std::size_t i = 0; i < size; i++) projection += x[i] * static_cast<U>(g[i]);
1405
+ return projection;
1406
+ }
1407
+
1408
+ /**
1409
+ * @brief Computes the euclidean distance from the first parameter to the second parameter.
1410
+ *
1411
+ * @param g Source filtration value.
1412
+ * @param other Target filtration value.
1413
+ * @return Euclidean distance between @p f and @p other.
1414
+ */
1415
+ template <typename U = T>
1416
+ friend U compute_euclidean_distance_to(const Multi_parameter_generator &g, const Multi_parameter_generator &other)
1417
+ {
1418
+ if (!g.is_finite() || !other.is_finite()) {
1419
+ if constexpr (std::numeric_limits<T>::has_quiet_NaN)
1420
+ return std::numeric_limits<T>::quiet_NaN();
1421
+ else
1422
+ return T_inf;
1423
+ }
1424
+
1425
+ GUDHI_CHECK(g.num_parameters() == other.num_parameters(),
1426
+ std::invalid_argument("We cannot compute the distance between two points of different dimensions."));
1427
+
1428
+ if (g.num_parameters() == 1) return g[0] - other[0];
1429
+
1430
+ U out = 0;
1431
+ for (size_type p = 0; p < g.num_parameters(); ++p) {
1432
+ T v = g[p] - other[p];
1433
+ out += v * v;
1434
+ }
1435
+ if constexpr (std::is_integral_v<U>) {
1436
+ // to avoid Windows issue that don't know how to cast integers for cmath methods
1437
+ return std::sqrt(static_cast<double>(out));
1438
+ } else {
1439
+ return std::sqrt(out);
1440
+ }
1441
+ }
1442
+
1443
+ /**
1444
+ * @brief Computes the sum of the squares of all values in the given generator.
1445
+ *
1446
+ * @param g Filtration value.
1447
+ * @return The norm of @p f.
1448
+ */
1449
+ template <typename U = T>
1450
+ friend U compute_squares(const Multi_parameter_generator &g)
1451
+ {
1452
+ U out = 0;
1453
+ for (size_type p = 0; p < g.num_parameters(); ++p) {
1454
+ out += g[p] * g[p];
1455
+ }
1456
+ return out;
1457
+ }
1458
+
1459
+ /**
1460
+ * @brief Computes the values in the given grid corresponding to the coordinates given by the given generator.
1461
+ * That is, if \f$ out \f$ is the result, \f$ out(g,p) = grid[p][f(g,p)] \f$. Assumes therefore, that the
1462
+ * values stored in the filtration value corresponds to indices existing in the given grid.
1463
+ *
1464
+ * @tparam U Signed arithmetic type.
1465
+ * @param g Filtration value storing coordinates compatible with `grid`.
1466
+ * @param grid Vector of vector.
1467
+ * @return Filtration value \f$ out \f$ whose entry correspond to \f$ out(g,p) = grid[p][f(g,p)] \f$.
1468
+ */
1469
+ template <typename U>
1470
+ friend Multi_parameter_generator<U> evaluate_coordinates_in_grid(const Multi_parameter_generator &g,
1471
+ const std::vector<std::vector<U> > &grid)
1472
+ {
1473
+ GUDHI_CHECK(grid.size() >= g.num_parameters(),
1474
+ std::invalid_argument(
1475
+ "The size of the grid should correspond to the number of parameters in the filtration value."));
1476
+
1477
+ U grid_inf = Multi_parameter_generator<U>::T_inf;
1478
+ std::vector<U> outVec(g.num_parameters());
1479
+
1480
+ for (size_type p = 0; p < g.num_parameters(); ++p) {
1481
+ outVec[p] = (g[p] == T_inf ? grid_inf : grid[p][g[p]]);
1482
+ }
1483
+
1484
+ return Multi_parameter_generator<U>(std::move(outVec));
1485
+ }
1486
+
1487
+ // UTILITIES
1488
+
1489
+ /**
1490
+ * @brief Outstream operator.
1491
+ */
1492
+ friend std::ostream &operator<<(std::ostream &stream, const Multi_parameter_generator &g)
1493
+ {
1494
+ if (g.is_plus_inf()) {
1495
+ stream << "[inf, ..., inf]";
1496
+ return stream;
1497
+ }
1498
+ if (g.is_minus_inf()) {
1499
+ stream << "[-inf, ..., -inf]";
1500
+ return stream;
1501
+ }
1502
+ if (g.is_nan()) {
1503
+ stream << "[NaN]";
1504
+ return stream;
1505
+ }
1506
+
1507
+ const size_type num_param = g.num_parameters();
1508
+
1509
+ stream << "[";
1510
+ for (size_type p = 0; p < num_param; ++p) {
1511
+ stream << g[p];
1512
+ if (p < num_param - 1) stream << ", ";
1513
+ }
1514
+ stream << "]";
1515
+
1516
+ return stream;
1517
+ }
1518
+
1519
+ /**
1520
+ * @brief Instream operator.
1521
+ */
1522
+ friend std::istream &operator>>(std::istream &stream, Multi_parameter_generator &g)
1523
+ {
1524
+ char firstCharacter;
1525
+ stream >> firstCharacter;
1526
+ if (firstCharacter != '[')
1527
+ throw std::invalid_argument("Invalid incoming stream format for Multi_parameter_generator.");
1528
+ g.generator_.clear();
1529
+ auto pos = stream.tellg();
1530
+ stream >> firstCharacter;
1531
+ if (firstCharacter == ']') return stream;
1532
+ if (firstCharacter == 'i') {
1533
+ while (firstCharacter != ']') {
1534
+ stream >> firstCharacter;
1535
+ }
1536
+ g = Multi_parameter_generator::inf();
1537
+ return stream;
1538
+ }
1539
+ if (firstCharacter == '-') {
1540
+ stream >> firstCharacter;
1541
+ if (firstCharacter == 'i') {
1542
+ while (firstCharacter != ']') {
1543
+ stream >> firstCharacter;
1544
+ }
1545
+ g = Multi_parameter_generator::minus_inf();
1546
+ return stream;
1547
+ } // else could be a negative number
1548
+ }
1549
+ if (firstCharacter == 'N') {
1550
+ while (firstCharacter != ']') {
1551
+ stream >> firstCharacter;
1552
+ }
1553
+ g = Multi_parameter_generator::nan();
1554
+ return stream;
1555
+ }
1556
+
1557
+ stream.seekg(pos, std::ios_base::beg);
1558
+ char delimiter = '\0';
1559
+ while (delimiter != ']') {
1560
+ g.generator_.push_back(_get_value<T>(stream));
1561
+ if (!stream.good()) throw std::invalid_argument("Invalid incoming stream format for Multi_parameter_generator.");
1562
+ stream >> delimiter;
1563
+ }
1564
+
1565
+ return stream;
1566
+ }
1567
+
1568
+ /**
1569
+ * @brief Serialize given value into the buffer at given pointer.
1570
+ *
1571
+ * @param value Value to serialize.
1572
+ * @param start Pointer to the start of the space in the buffer where to store the serialization.
1573
+ * @return End position of the serialization in the buffer.
1574
+ */
1575
+ friend char *serialize_value_to_char_buffer(const Multi_parameter_generator &value, char *start)
1576
+ {
1577
+ const size_type length = value.generator_.size();
1578
+ const std::size_t arg_size = sizeof(T) * length;
1579
+ const std::size_t type_size = sizeof(size_type);
1580
+ memcpy(start, &length, type_size);
1581
+ memcpy(start + type_size, value.generator_.data(), arg_size);
1582
+ return start + arg_size + type_size;
1583
+ }
1584
+
1585
+ /**
1586
+ * @brief Deserialize the value from a buffer at given pointer and stores it in given value.
1587
+ *
1588
+ * @param value Value to fill with the deserialized filtration value.
1589
+ * @param start Pointer to the start of the space in the buffer where the serialization is stored.
1590
+ * @return End position of the serialization in the buffer.
1591
+ */
1592
+ friend const char *deserialize_value_from_char_buffer(Multi_parameter_generator &value, const char *start)
1593
+ {
1594
+ const std::size_t type_size = sizeof(size_type);
1595
+ size_type length;
1596
+ memcpy(&length, start, type_size);
1597
+ std::size_t arg_size = sizeof(T) * length;
1598
+ value.generator_.resize(length);
1599
+ memcpy(value.generator_.data(), start + type_size, arg_size);
1600
+ return start + arg_size + type_size;
1601
+ }
1602
+
1603
+ /**
1604
+ * @brief Returns the serialization size of the given filtration value.
1605
+ */
1606
+ friend std::size_t get_serialization_size_of(const Multi_parameter_generator &value)
1607
+ {
1608
+ return sizeof(size_type) + (sizeof(T) * value.generator_.size());
1609
+ }
1610
+
1611
+ /**
1612
+ * @brief Plus infinity value of an entry of the filtration value.
1613
+ */
1614
+ constexpr static const T T_inf = MF_T_inf<T>;
1615
+
1616
+ /**
1617
+ * @brief Minus infinity value of an entry of the filtration value.
1618
+ */
1619
+ constexpr static const T T_m_inf = MF_T_m_inf<T>;
1620
+
1621
+ private:
1622
+ Underlying_container generator_; /**< Container of the filtration value elements. */
1623
+
1624
+ /**
1625
+ * @brief Default value of an element in the filtration value.
1626
+ */
1627
+ constexpr static T _get_default_value() { return T_m_inf; }
1628
+
1629
+ /**
1630
+ * @brief Applies operation on the elements of the filtration value.
1631
+ */
1632
+ template <class ValueRange, class F>
1633
+ void _apply_operation(const ValueRange &range, F &&operate)
1634
+ {
1635
+ if (range.size() < generator_.size()) {
1636
+ auto it = range.begin();
1637
+ for (size_type p = 0; p < generator_.size() && it != range.end(); ++p) {
1638
+ std::forward<F>(operate)(generator_[p], *it);
1639
+ ++it;
1640
+ }
1641
+ } else {
1642
+ bool allPlusInf = true;
1643
+ bool allMinusInf = true;
1644
+ bool allNaN = true;
1645
+
1646
+ auto it = range.begin();
1647
+ for (size_type p = 0; p < generator_.size() && it != range.end(); ++p) {
1648
+ bool isNotNaN = std::forward<F>(operate)(generator_[p], *it);
1649
+ if (generator_[p] != T_inf) allPlusInf = false;
1650
+ if (generator_[p] != T_m_inf) allMinusInf = false;
1651
+ if (isNotNaN) allNaN = false;
1652
+ ++it;
1653
+ }
1654
+
1655
+ if (allPlusInf)
1656
+ *this = inf();
1657
+ else if (allMinusInf)
1658
+ *this = minus_inf();
1659
+ else if (allNaN)
1660
+ *this = nan();
1661
+ }
1662
+ }
1663
+
1664
+ /**
1665
+ * @brief Applies operation on the elements of the filtration value.
1666
+ */
1667
+ template <class F>
1668
+ void _apply_operation(const T &val, F &&operate)
1669
+ {
1670
+ bool allNaN = true;
1671
+
1672
+ for (auto &p : generator_) {
1673
+ if (std::forward<F>(operate)(p, val)) allNaN = false;
1674
+ }
1675
+
1676
+ if (allNaN) *this = nan();
1677
+ }
1678
+ };
1679
+
1680
+ } // namespace Gudhi::multi_filtration
1681
+
1682
+ namespace std {
1683
+
1684
+ template <typename T>
1685
+ class numeric_limits<Gudhi::multi_filtration::Multi_parameter_generator<T> >
1686
+ {
1687
+ public:
1688
+ using Generator = Gudhi::multi_filtration::Multi_parameter_generator<T>;
1689
+
1690
+ static constexpr bool has_infinity = true;
1691
+ static constexpr bool has_quiet_NaN = true;
1692
+
1693
+ static constexpr Generator infinity() noexcept { return Generator::inf(); };
1694
+
1695
+ // non-standard
1696
+ static constexpr Generator minus_infinity() noexcept { return Generator::minus_inf(); };
1697
+
1698
+ static constexpr Generator max() noexcept(false)
1699
+ {
1700
+ throw std::logic_error(
1701
+ "The max value cannot be represented with no finite numbers of parameters."
1702
+ "Use `max(number_of_parameters)` instead");
1703
+ };
1704
+
1705
+ static constexpr Generator max(std::size_t p) noexcept { return Generator(p, std::numeric_limits<T>::max()); };
1706
+
1707
+ static constexpr Generator quiet_NaN() noexcept { return Generator::nan(); };
1708
+ };
1709
+
1710
+ } // namespace std
1711
+
1712
+ #endif // MF_MULTI_PARAMETER_GENERATOR_H_