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.
- multipers/.dylibs/libboost_timer.dylib +0 -0
- multipers/.dylibs/libc++.1.0.dylib +0 -0
- multipers/.dylibs/libtbb.12.17.dylib +0 -0
- multipers/__init__.py +33 -0
- multipers/_signed_measure_meta.py +426 -0
- multipers/_slicer_meta.py +231 -0
- multipers/array_api/__init__.py +62 -0
- multipers/array_api/numpy.py +124 -0
- multipers/array_api/torch.py +133 -0
- multipers/data/MOL2.py +458 -0
- multipers/data/UCR.py +18 -0
- multipers/data/__init__.py +1 -0
- multipers/data/graphs.py +466 -0
- multipers/data/immuno_regions.py +27 -0
- multipers/data/minimal_presentation_to_st_bf.py +0 -0
- multipers/data/pytorch2simplextree.py +91 -0
- multipers/data/shape3d.py +101 -0
- multipers/data/synthetic.py +113 -0
- multipers/distances.py +202 -0
- multipers/filtration_conversions.pxd +736 -0
- multipers/filtration_conversions.pxd.tp +226 -0
- multipers/filtrations/__init__.py +21 -0
- multipers/filtrations/density.py +529 -0
- multipers/filtrations/filtrations.py +480 -0
- multipers/filtrations.pxd +534 -0
- multipers/filtrations.pxd.tp +332 -0
- multipers/function_rips.cpython-312-darwin.so +0 -0
- multipers/function_rips.pyx +104 -0
- multipers/grids.cpython-312-darwin.so +0 -0
- multipers/grids.pyx +538 -0
- multipers/gudhi/Persistence_slices_interface.h +213 -0
- multipers/gudhi/Simplex_tree_interface.h +274 -0
- multipers/gudhi/Simplex_tree_multi_interface.h +648 -0
- multipers/gudhi/gudhi/Bitmap_cubical_complex.h +450 -0
- multipers/gudhi/gudhi/Bitmap_cubical_complex_base.h +1070 -0
- multipers/gudhi/gudhi/Bitmap_cubical_complex_periodic_boundary_conditions_base.h +579 -0
- multipers/gudhi/gudhi/Debug_utils.h +52 -0
- multipers/gudhi/gudhi/Degree_rips_bifiltration.h +2307 -0
- multipers/gudhi/gudhi/Dynamic_multi_parameter_filtration.h +2524 -0
- multipers/gudhi/gudhi/Fields/Multi_field.h +453 -0
- multipers/gudhi/gudhi/Fields/Multi_field_operators.h +460 -0
- multipers/gudhi/gudhi/Fields/Multi_field_shared.h +444 -0
- multipers/gudhi/gudhi/Fields/Multi_field_small.h +584 -0
- multipers/gudhi/gudhi/Fields/Multi_field_small_operators.h +490 -0
- multipers/gudhi/gudhi/Fields/Multi_field_small_shared.h +580 -0
- multipers/gudhi/gudhi/Fields/Z2_field.h +391 -0
- multipers/gudhi/gudhi/Fields/Z2_field_operators.h +389 -0
- multipers/gudhi/gudhi/Fields/Zp_field.h +493 -0
- multipers/gudhi/gudhi/Fields/Zp_field_operators.h +384 -0
- multipers/gudhi/gudhi/Fields/Zp_field_shared.h +492 -0
- multipers/gudhi/gudhi/Flag_complex_edge_collapser.h +337 -0
- multipers/gudhi/gudhi/Matrix.h +2200 -0
- multipers/gudhi/gudhi/Multi_filtration/Multi_parameter_generator.h +1712 -0
- multipers/gudhi/gudhi/Multi_filtration/multi_filtration_conversions.h +237 -0
- multipers/gudhi/gudhi/Multi_filtration/multi_filtration_utils.h +225 -0
- multipers/gudhi/gudhi/Multi_parameter_filtered_complex.h +485 -0
- multipers/gudhi/gudhi/Multi_parameter_filtration.h +2643 -0
- multipers/gudhi/gudhi/Multi_persistence/Box.h +233 -0
- multipers/gudhi/gudhi/Multi_persistence/Line.h +309 -0
- multipers/gudhi/gudhi/Multi_persistence/Multi_parameter_filtered_complex_pcoh_interface.h +268 -0
- multipers/gudhi/gudhi/Multi_persistence/Persistence_interface_cohomology.h +159 -0
- multipers/gudhi/gudhi/Multi_persistence/Persistence_interface_matrix.h +463 -0
- multipers/gudhi/gudhi/Multi_persistence/Point.h +853 -0
- multipers/gudhi/gudhi/Off_reader.h +173 -0
- multipers/gudhi/gudhi/Persistence_matrix/Base_matrix.h +834 -0
- multipers/gudhi/gudhi/Persistence_matrix/Base_matrix_with_column_compression.h +838 -0
- multipers/gudhi/gudhi/Persistence_matrix/Boundary_matrix.h +833 -0
- multipers/gudhi/gudhi/Persistence_matrix/Chain_matrix.h +1367 -0
- multipers/gudhi/gudhi/Persistence_matrix/Id_to_index_overlay.h +1157 -0
- multipers/gudhi/gudhi/Persistence_matrix/Position_to_index_overlay.h +869 -0
- multipers/gudhi/gudhi/Persistence_matrix/RU_matrix.h +905 -0
- multipers/gudhi/gudhi/Persistence_matrix/allocators/entry_constructors.h +122 -0
- multipers/gudhi/gudhi/Persistence_matrix/base_pairing.h +260 -0
- multipers/gudhi/gudhi/Persistence_matrix/base_swap.h +288 -0
- multipers/gudhi/gudhi/Persistence_matrix/chain_pairing.h +170 -0
- multipers/gudhi/gudhi/Persistence_matrix/chain_rep_cycles.h +247 -0
- multipers/gudhi/gudhi/Persistence_matrix/chain_vine_swap.h +571 -0
- multipers/gudhi/gudhi/Persistence_matrix/columns/chain_column_extra_properties.h +182 -0
- multipers/gudhi/gudhi/Persistence_matrix/columns/column_dimension_holder.h +130 -0
- multipers/gudhi/gudhi/Persistence_matrix/columns/column_utilities.h +235 -0
- multipers/gudhi/gudhi/Persistence_matrix/columns/entry_types.h +312 -0
- multipers/gudhi/gudhi/Persistence_matrix/columns/heap_column.h +1092 -0
- multipers/gudhi/gudhi/Persistence_matrix/columns/intrusive_list_column.h +923 -0
- multipers/gudhi/gudhi/Persistence_matrix/columns/intrusive_set_column.h +914 -0
- multipers/gudhi/gudhi/Persistence_matrix/columns/list_column.h +930 -0
- multipers/gudhi/gudhi/Persistence_matrix/columns/naive_vector_column.h +1071 -0
- multipers/gudhi/gudhi/Persistence_matrix/columns/row_access.h +203 -0
- multipers/gudhi/gudhi/Persistence_matrix/columns/set_column.h +886 -0
- multipers/gudhi/gudhi/Persistence_matrix/columns/unordered_set_column.h +984 -0
- multipers/gudhi/gudhi/Persistence_matrix/columns/vector_column.h +1213 -0
- multipers/gudhi/gudhi/Persistence_matrix/index_mapper.h +58 -0
- multipers/gudhi/gudhi/Persistence_matrix/matrix_dimension_holders.h +227 -0
- multipers/gudhi/gudhi/Persistence_matrix/matrix_row_access.h +200 -0
- multipers/gudhi/gudhi/Persistence_matrix/ru_pairing.h +166 -0
- multipers/gudhi/gudhi/Persistence_matrix/ru_rep_cycles.h +319 -0
- multipers/gudhi/gudhi/Persistence_matrix/ru_vine_swap.h +562 -0
- multipers/gudhi/gudhi/Persistence_on_a_line.h +152 -0
- multipers/gudhi/gudhi/Persistence_on_rectangle.h +617 -0
- multipers/gudhi/gudhi/Persistent_cohomology/Field_Zp.h +118 -0
- multipers/gudhi/gudhi/Persistent_cohomology/Multi_field.h +173 -0
- multipers/gudhi/gudhi/Persistent_cohomology/Persistent_cohomology_column.h +128 -0
- multipers/gudhi/gudhi/Persistent_cohomology.h +769 -0
- multipers/gudhi/gudhi/Points_off_io.h +171 -0
- multipers/gudhi/gudhi/Projective_cover_kernel.h +379 -0
- multipers/gudhi/gudhi/Simple_object_pool.h +69 -0
- multipers/gudhi/gudhi/Simplex_tree/Simplex_tree_iterators.h +559 -0
- multipers/gudhi/gudhi/Simplex_tree/Simplex_tree_node_explicit_storage.h +83 -0
- multipers/gudhi/gudhi/Simplex_tree/Simplex_tree_siblings.h +121 -0
- multipers/gudhi/gudhi/Simplex_tree/Simplex_tree_star_simplex_iterators.h +277 -0
- multipers/gudhi/gudhi/Simplex_tree/filtration_value_utils.h +155 -0
- multipers/gudhi/gudhi/Simplex_tree/hooks_simplex_base.h +62 -0
- multipers/gudhi/gudhi/Simplex_tree/indexing_tag.h +27 -0
- multipers/gudhi/gudhi/Simplex_tree/serialization_utils.h +60 -0
- multipers/gudhi/gudhi/Simplex_tree/simplex_tree_options.h +105 -0
- multipers/gudhi/gudhi/Simplex_tree.h +3170 -0
- multipers/gudhi/gudhi/Slicer.h +848 -0
- multipers/gudhi/gudhi/Thread_safe_slicer.h +393 -0
- multipers/gudhi/gudhi/distance_functions.h +62 -0
- multipers/gudhi/gudhi/graph_simplicial_complex.h +104 -0
- multipers/gudhi/gudhi/multi_simplex_tree_helpers.h +147 -0
- multipers/gudhi/gudhi/persistence_interval.h +263 -0
- multipers/gudhi/gudhi/persistence_matrix_options.h +188 -0
- multipers/gudhi/gudhi/reader_utils.h +367 -0
- multipers/gudhi/gudhi/simple_mdspan.h +484 -0
- multipers/gudhi/gudhi/slicer_helpers.h +779 -0
- multipers/gudhi/tmp_h0_pers/mma_interface_h0.h +223 -0
- multipers/gudhi/tmp_h0_pers/naive_merge_tree.h +536 -0
- multipers/io.cpython-312-darwin.so +0 -0
- multipers/io.pyx +472 -0
- multipers/ml/__init__.py +0 -0
- multipers/ml/accuracies.py +90 -0
- multipers/ml/invariants_with_persistable.py +79 -0
- multipers/ml/kernels.py +176 -0
- multipers/ml/mma.py +713 -0
- multipers/ml/one.py +472 -0
- multipers/ml/point_clouds.py +352 -0
- multipers/ml/signed_measures.py +1667 -0
- multipers/ml/sliced_wasserstein.py +461 -0
- multipers/ml/tools.py +113 -0
- multipers/mma_structures.cpython-312-darwin.so +0 -0
- multipers/mma_structures.pxd +134 -0
- multipers/mma_structures.pyx +1483 -0
- multipers/mma_structures.pyx.tp +1126 -0
- multipers/multi_parameter_rank_invariant/diff_helpers.h +85 -0
- multipers/multi_parameter_rank_invariant/euler_characteristic.h +95 -0
- multipers/multi_parameter_rank_invariant/function_rips.h +317 -0
- multipers/multi_parameter_rank_invariant/hilbert_function.h +761 -0
- multipers/multi_parameter_rank_invariant/persistence_slices.h +149 -0
- multipers/multi_parameter_rank_invariant/rank_invariant.h +350 -0
- multipers/multiparameter_edge_collapse.py +41 -0
- multipers/multiparameter_module_approximation/approximation.h +2541 -0
- multipers/multiparameter_module_approximation/debug.h +107 -0
- multipers/multiparameter_module_approximation/format_python-cpp.h +292 -0
- multipers/multiparameter_module_approximation/utilities.h +428 -0
- multipers/multiparameter_module_approximation.cpython-312-darwin.so +0 -0
- multipers/multiparameter_module_approximation.pyx +286 -0
- multipers/ops.cpython-312-darwin.so +0 -0
- multipers/ops.pyx +231 -0
- multipers/pickle.py +89 -0
- multipers/plots.py +550 -0
- multipers/point_measure.cpython-312-darwin.so +0 -0
- multipers/point_measure.pyx +409 -0
- multipers/simplex_tree_multi.cpython-312-darwin.so +0 -0
- multipers/simplex_tree_multi.pxd +136 -0
- multipers/simplex_tree_multi.pyx +11719 -0
- multipers/simplex_tree_multi.pyx.tp +2102 -0
- multipers/slicer.cpython-312-darwin.so +0 -0
- multipers/slicer.pxd +2097 -0
- multipers/slicer.pxd.tp +263 -0
- multipers/slicer.pyx +13042 -0
- multipers/slicer.pyx.tp +1259 -0
- multipers/tensor/tensor.h +672 -0
- multipers/tensor.pxd +13 -0
- multipers/test.pyx +44 -0
- multipers/tests/__init__.py +70 -0
- multipers/torch/__init__.py +1 -0
- multipers/torch/diff_grids.py +240 -0
- multipers/torch/rips_density.py +310 -0
- multipers/vector_interface.pxd +46 -0
- multipers-2.4.0b1.dist-info/METADATA +131 -0
- multipers-2.4.0b1.dist-info/RECORD +184 -0
- multipers-2.4.0b1.dist-info/WHEEL +6 -0
- multipers-2.4.0b1.dist-info/licenses/LICENSE +21 -0
- multipers-2.4.0b1.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,2524 @@
|
|
|
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
|
+
* @file Dynamic_multi_parameter_filtration.h
|
|
13
|
+
* @author Hannah Schreiber, David Loiseaux
|
|
14
|
+
* @brief Contains the @ref Gudhi::multi_filtration::Dynamic_multi_parameter_filtration class.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
#ifndef MF_DYNAMIC_MULTI_PARAMETER_FILTRATION_H_
|
|
18
|
+
#define MF_DYNAMIC_MULTI_PARAMETER_FILTRATION_H_
|
|
19
|
+
|
|
20
|
+
#include <algorithm> //std::lower_bound
|
|
21
|
+
#include <cmath> //std::isnan, std::min
|
|
22
|
+
#include <cstddef> //std::size_t
|
|
23
|
+
#include <cstdint> //std::int32_t, std::uint8_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/Multi_filtration/Multi_parameter_generator.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
|
+
/**
|
|
42
|
+
* @class Dynamic_multi_parameter_filtration Dynamic_multi_parameter_filtration.h
|
|
43
|
+
* gudhi/Dynamic_multi_parameter_filtration.h
|
|
44
|
+
* @ingroup multi_filtration
|
|
45
|
+
*
|
|
46
|
+
* @brief Class encoding the different generators, i.e., apparition times, of a \f$ k \f$-critical
|
|
47
|
+
* \f$\mathbb R^n\f$-filtration value. E.g., the filtration value of a simplex, or, of the algebraic generator of a
|
|
48
|
+
* module presentation. Different from @ref Multi_parameter_filtration, the underlying container is a vector of vectors
|
|
49
|
+
* and therefore less memory efficient, but much more flexible when modifying the filtration value. So, this class is
|
|
50
|
+
* preferable if a lot of generators need to be added on the fly or removed. But when the filtration value is more or
|
|
51
|
+
* less fixed, e.g. for 1-critical filtrations, we recommend @ref Multi_parameter_filtration instead. Implements
|
|
52
|
+
* the concept @ref FiltrationValue of the @ref Gudhi::Simplex_tree and the concept
|
|
53
|
+
* @ref Gudhi::multi_persistence::MultiFiltrationValue.
|
|
54
|
+
*
|
|
55
|
+
* @details Overloads `std::numeric_limits` such that:
|
|
56
|
+
* - `std::numeric_limits<Dynamic_multi_parameter_filtration>::has_infinity` returns `true`,
|
|
57
|
+
* - `std::numeric_limits<Dynamic_multi_parameter_filtration>::has_quiet_NaN` returns `true`,
|
|
58
|
+
* - `std::numeric_limits<Dynamic_multi_parameter_filtration>::infinity(int)` returns
|
|
59
|
+
* @ref Dynamic_multi_parameter_filtration::inf(int) "",
|
|
60
|
+
* - `std::numeric_limits<Dynamic_multi_parameter_filtration>::minus_infinity(int)` returns
|
|
61
|
+
* @ref Dynamic_multi_parameter_filtration::minus_inf(int) "",
|
|
62
|
+
* - `std::numeric_limits<Dynamic_multi_parameter_filtration>::max(int num_param)` returns a @ref
|
|
63
|
+
* Dynamic_multi_parameter_filtration with one generator of `num_param` parameters evaluated at value
|
|
64
|
+
* `std::numeric_limits<T>::max()`,
|
|
65
|
+
* - `std::numeric_limits<Dynamic_multi_parameter_filtration>::quiet_NaN(int)` returns
|
|
66
|
+
* @ref Dynamic_multi_parameter_filtration::nan(int).
|
|
67
|
+
*
|
|
68
|
+
* Multi-critical filtrations are filtrations such that the lifetime of each object is a union of positive cones in
|
|
69
|
+
* \f$\mathbb R^n\f$, e.g.,
|
|
70
|
+
* - \f$ \{ x \in \mathbb R^2 : x \ge (1,2)\} \cap \{ x \in \mathbb R^2 : x \ge (2,1)\} \f$ is finitely critical,
|
|
71
|
+
* and more particularly 2-critical, while
|
|
72
|
+
* - \f$ \{ x \in \mathbb R^2 : x \ge \mathrm{epigraph}(y \mapsto e^{-y})\} \f$ is not.
|
|
73
|
+
*
|
|
74
|
+
* @tparam T Arithmetic type of an entry for one parameter of a filtration value. Has to be **signed** and
|
|
75
|
+
* to implement `std::isnan(T)`, `std::numeric_limits<T>::has_quiet_NaN`, `std::numeric_limits<T>::quiet_NaN()`,
|
|
76
|
+
* `std::numeric_limits<T>::has_infinity`, `std::numeric_limits<T>::infinity()` and `std::numeric_limits<T>::max()`.
|
|
77
|
+
* If `std::numeric_limits<T>::has_infinity` returns `false`, a call to `std::numeric_limits<T>::infinity()`
|
|
78
|
+
* can simply throw. Examples are the native types `double`, `float` and `int`.
|
|
79
|
+
* @tparam Co If `true`, reverses the poset order, i.e., the order \f$ \le \f$ in \f$ \mathbb R^n \f$ becomes
|
|
80
|
+
* \f$ \ge \f$. That is, the positive cones representing a lifetime become all negative instead.
|
|
81
|
+
* @tparam Ensure1Criticality If `true`, the methods ensure that the filtration value is always 1-critical by throwing
|
|
82
|
+
* or refusing to compile if a modification increases the number of generators.
|
|
83
|
+
*/
|
|
84
|
+
template <typename T, bool Co = false, bool Ensure1Criticality = false>
|
|
85
|
+
class Dynamic_multi_parameter_filtration
|
|
86
|
+
{
|
|
87
|
+
public:
|
|
88
|
+
using Generator = Multi_parameter_generator<T>; /**< Generator type. */
|
|
89
|
+
using Underlying_container = std::vector<Generator>; /**< Underlying container for values. */
|
|
90
|
+
|
|
91
|
+
// CONSTRUCTORS
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* @brief Default constructor. Builds filtration value with one generator and given number of parameters.
|
|
95
|
+
* If Co is false, initializes at -inf, if Co is true, at +inf.
|
|
96
|
+
*
|
|
97
|
+
* @param number_of_parameters If negative, takes the default value instead. Default value: 2.
|
|
98
|
+
*/
|
|
99
|
+
Dynamic_multi_parameter_filtration(int number_of_parameters = 2)
|
|
100
|
+
: number_of_parameters_(number_of_parameters < 0 ? 2 : number_of_parameters),
|
|
101
|
+
generators_(1, Generator(1, Co ? T_inf : T_m_inf))
|
|
102
|
+
{}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* @brief Builds filtration value with one generator and given number of parameters.
|
|
106
|
+
* All values are initialized at the given value.
|
|
107
|
+
*
|
|
108
|
+
* @warning The generator `{-inf, -inf, ...}`/`{inf, inf, ...}` with \f$ number_of_parameters > 1 \f$ entries is
|
|
109
|
+
* valid but will not benefit from possible optimizations. If those values are not planed to be replaced, it is
|
|
110
|
+
* recommended to use the static methods @ref minus_inf() or @ref inf(), or set `number_of_parameters` to 1, instead.
|
|
111
|
+
*
|
|
112
|
+
* @param number_of_parameters If negative, is set to 2 instead.
|
|
113
|
+
* @param value Initialization value for every value in the generator.
|
|
114
|
+
*/
|
|
115
|
+
Dynamic_multi_parameter_filtration(int number_of_parameters, T value)
|
|
116
|
+
: number_of_parameters_(number_of_parameters < 0 ? 2 : number_of_parameters),
|
|
117
|
+
generators_(1, Generator(number_of_parameters_, value))
|
|
118
|
+
{}
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* @brief Builds filtration value with one generator that is initialized with the given range. The number of
|
|
122
|
+
* parameters are therefore deduced from the length of the range.
|
|
123
|
+
*
|
|
124
|
+
* @tparam ValueRange Range of types convertible to `T`. Should have a begin() and end() method.
|
|
125
|
+
* @param range Values of the generator.
|
|
126
|
+
*/
|
|
127
|
+
template <class ValueRange = std::initializer_list<T>, class = std::enable_if_t<RangeTraits<ValueRange>::has_begin> >
|
|
128
|
+
Dynamic_multi_parameter_filtration(const ValueRange &range) : generators_(1, Generator(range.begin(), range.end()))
|
|
129
|
+
{
|
|
130
|
+
number_of_parameters_ = generators_[0].size();
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* @brief Builds filtration value with one generator that is initialized with the given range. The range is
|
|
135
|
+
* determined from the two given iterators. The number of parameters are therefore deduced from the distance
|
|
136
|
+
* between the two.
|
|
137
|
+
*
|
|
138
|
+
* @tparam Iterator Iterator type that has to satisfy the requirements of standard LegacyInputIterator and
|
|
139
|
+
* dereferenced elements have to be convertible to `T`.
|
|
140
|
+
* @param it_begin Iterator pointing to the start of the range.
|
|
141
|
+
* @param it_end Iterator pointing to the end of the range.
|
|
142
|
+
*/
|
|
143
|
+
template <class Iterator>
|
|
144
|
+
Dynamic_multi_parameter_filtration(Iterator it_begin, Iterator it_end) : generators_(1, Generator(it_begin, it_end))
|
|
145
|
+
{
|
|
146
|
+
number_of_parameters_ = generators_[0].size();
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* @brief Builds filtration value with given number of parameters and values from the given range. Lets \f$ p \f$
|
|
151
|
+
* be the number of parameters. The \f$ p \f$ first elements of the range have to correspond to the first generator,
|
|
152
|
+
* the \f$ p \f$ next elements to the second generator and so on... So the length of the range has to be a multiple
|
|
153
|
+
* of \f$ p \f$ and the number of generators will be \f$ length / p \f$. The range is represented by two iterators.
|
|
154
|
+
*
|
|
155
|
+
* @tparam Iterator Iterator type that has to satisfy the requirements of standard LegacyForwardIterator and
|
|
156
|
+
* dereferenced elements have to be convertible to `T`.
|
|
157
|
+
* @param it_begin Iterator pointing to the start of the range.
|
|
158
|
+
* @param it_end Iterator pointing to the end of the range.
|
|
159
|
+
* @param number_of_parameters Negative values are associated to 0.
|
|
160
|
+
*/
|
|
161
|
+
template <class Iterator, class = std::enable_if_t<!std::is_arithmetic_v<Iterator> > >
|
|
162
|
+
Dynamic_multi_parameter_filtration(Iterator it_begin, Iterator it_end, int number_of_parameters)
|
|
163
|
+
: number_of_parameters_(number_of_parameters < 0 ? 0 : number_of_parameters), generators_()
|
|
164
|
+
{
|
|
165
|
+
// Will discard any value at the end which does not fit into a complete generator.
|
|
166
|
+
const size_type num_gen = std::distance(it_begin, it_end) / number_of_parameters;
|
|
167
|
+
|
|
168
|
+
if constexpr (Ensure1Criticality) {
|
|
169
|
+
if (num_gen != 1) throw std::logic_error("Multiparameter filtration value is not 1-critical.");
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
Iterator it = it_begin;
|
|
173
|
+
for (size_type i = 0; i < num_gen; ++i) {
|
|
174
|
+
Iterator endIt = it;
|
|
175
|
+
std::advance(endIt, number_of_parameters);
|
|
176
|
+
generators_.emplace_back(it, endIt);
|
|
177
|
+
it = endIt;
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* @brief Builds filtration value with given number of parameters and values copied from the given
|
|
183
|
+
* @ref Dynamic_multi_parameter_filtration::Underlying_container container.
|
|
184
|
+
*
|
|
185
|
+
* @param generators Values.
|
|
186
|
+
* @param number_of_parameters Negative values are associated to 0.
|
|
187
|
+
*/
|
|
188
|
+
Dynamic_multi_parameter_filtration(const Underlying_container &generators, int number_of_parameters)
|
|
189
|
+
: number_of_parameters_(number_of_parameters < 0 ? 0 : number_of_parameters), generators_(generators)
|
|
190
|
+
{
|
|
191
|
+
GUDHI_CHECK(number_of_parameters > 0 || generators_.empty(),
|
|
192
|
+
std::invalid_argument("Number of parameters cannot be 0 if the container is not empty."));
|
|
193
|
+
|
|
194
|
+
if constexpr (Ensure1Criticality) {
|
|
195
|
+
if (generators_.size() != 1) throw std::logic_error("Multiparameter filtration value is not 1-critical.");
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
/**
|
|
200
|
+
* @brief Builds filtration value with given number of parameters and values moved from the given
|
|
201
|
+
* @ref Dynamic_multi_parameter_filtration::Underlying_container container.
|
|
202
|
+
*
|
|
203
|
+
* @param generators Values to move.
|
|
204
|
+
* @param number_of_parameters Negative values are associated to 0.
|
|
205
|
+
*/
|
|
206
|
+
Dynamic_multi_parameter_filtration(Underlying_container &&generators, int number_of_parameters)
|
|
207
|
+
: number_of_parameters_(number_of_parameters < 0 ? 0 : number_of_parameters), generators_(std::move(generators))
|
|
208
|
+
{
|
|
209
|
+
GUDHI_CHECK(number_of_parameters > 0 || generators_.empty(),
|
|
210
|
+
std::invalid_argument("Number of parameters cannot be 0 if the container is not empty."));
|
|
211
|
+
|
|
212
|
+
if constexpr (Ensure1Criticality) {
|
|
213
|
+
if (generators_.size() != 1) throw std::logic_error("Multiparameter filtration value is not 1-critical.");
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
/**
|
|
218
|
+
* @brief Copy constructor.
|
|
219
|
+
*/
|
|
220
|
+
Dynamic_multi_parameter_filtration(const Dynamic_multi_parameter_filtration &other) = default;
|
|
221
|
+
|
|
222
|
+
/**
|
|
223
|
+
* @brief Copy constructor.
|
|
224
|
+
*
|
|
225
|
+
* @tparam U Type convertible into `T`.
|
|
226
|
+
*/
|
|
227
|
+
template <typename U, bool OtherCo, bool OtherEnsure1Criticality>
|
|
228
|
+
Dynamic_multi_parameter_filtration(
|
|
229
|
+
const Dynamic_multi_parameter_filtration<U, OtherCo, OtherEnsure1Criticality> &other)
|
|
230
|
+
: number_of_parameters_(other.num_parameters()), generators_(other.begin(), other.end())
|
|
231
|
+
{
|
|
232
|
+
if constexpr (Ensure1Criticality && !OtherEnsure1Criticality) {
|
|
233
|
+
if (generators_.size() != 1) throw std::logic_error("Multiparameter filtration value is not 1-critical.");
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
/**
|
|
238
|
+
* @brief Move constructor.
|
|
239
|
+
*/
|
|
240
|
+
Dynamic_multi_parameter_filtration(Dynamic_multi_parameter_filtration &&other) noexcept = default;
|
|
241
|
+
|
|
242
|
+
~Dynamic_multi_parameter_filtration() = default;
|
|
243
|
+
|
|
244
|
+
/**
|
|
245
|
+
* @brief Assign operator.
|
|
246
|
+
*/
|
|
247
|
+
Dynamic_multi_parameter_filtration &operator=(const Dynamic_multi_parameter_filtration &other) = default;
|
|
248
|
+
|
|
249
|
+
/**
|
|
250
|
+
* @brief Move assign operator.
|
|
251
|
+
*/
|
|
252
|
+
Dynamic_multi_parameter_filtration &operator=(Dynamic_multi_parameter_filtration &&other) noexcept = default;
|
|
253
|
+
|
|
254
|
+
/**
|
|
255
|
+
* @brief Assign operator.
|
|
256
|
+
*
|
|
257
|
+
* @tparam U Type convertible into `T`.
|
|
258
|
+
*/
|
|
259
|
+
template <typename U, bool OtherCo, bool OtherEnsure1Criticality>
|
|
260
|
+
Dynamic_multi_parameter_filtration &operator=(
|
|
261
|
+
const Dynamic_multi_parameter_filtration<U, OtherCo, OtherEnsure1Criticality> &other)
|
|
262
|
+
{
|
|
263
|
+
if constexpr (Ensure1Criticality && !OtherEnsure1Criticality) {
|
|
264
|
+
if (other.num_generators() != 1) throw std::logic_error("Multiparameter filtration value is not 1-critical.");
|
|
265
|
+
}
|
|
266
|
+
generators_ = Underlying_container(other.begin(), other.end());
|
|
267
|
+
number_of_parameters_ = other.num_parameters();
|
|
268
|
+
return *this;
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
/**
|
|
272
|
+
* @brief Swap operator.
|
|
273
|
+
*/
|
|
274
|
+
friend void swap(Dynamic_multi_parameter_filtration &f1, Dynamic_multi_parameter_filtration &f2) noexcept
|
|
275
|
+
{
|
|
276
|
+
f1.generators_.swap(f2.generators_);
|
|
277
|
+
std::swap(f1.number_of_parameters_, f2.number_of_parameters_);
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
// VECTOR-LIKE
|
|
281
|
+
|
|
282
|
+
using value_type = T; /**< Value type. */
|
|
283
|
+
using size_type = typename Underlying_container::size_type; /**< Size type. */
|
|
284
|
+
using difference_type = typename Underlying_container::difference_type; /**< Difference type. */
|
|
285
|
+
using reference = value_type &; /**< Reference type. */
|
|
286
|
+
using const_reference = const value_type &; /**< Const reference type. */
|
|
287
|
+
using pointer = typename Underlying_container::pointer; /**< Pointer type. */
|
|
288
|
+
using const_pointer = typename Underlying_container::const_pointer; /**< Const pointer type. */
|
|
289
|
+
using iterator = typename Underlying_container::iterator; /**< Iterator type. */
|
|
290
|
+
using const_iterator = typename Underlying_container::const_iterator; /**< Const iterator type. */
|
|
291
|
+
using reverse_iterator = typename Underlying_container::reverse_iterator; /**< Reverse iterator type. */
|
|
292
|
+
using const_reverse_iterator = typename Underlying_container::const_reverse_iterator; /**< Const reverse iterator. */
|
|
293
|
+
|
|
294
|
+
/**
|
|
295
|
+
* @brief Returns reference to value of parameter `p` of generator `g`.
|
|
296
|
+
* If the value is at +/- inf or NaN and it needs to be modified, @ref force_generator_size_to_number_of_parameters
|
|
297
|
+
* needs potentially to be called first such that this methods returns the right reference.
|
|
298
|
+
*/
|
|
299
|
+
reference operator()(size_type g, size_type p)
|
|
300
|
+
{
|
|
301
|
+
GUDHI_CHECK(g < generators_.size() && p < number_of_parameters_, std::out_of_range("Out of bound index."));
|
|
302
|
+
if (generators_[g].size() < number_of_parameters_) return generators_[g][0];
|
|
303
|
+
return generators_[g][p];
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
/**
|
|
307
|
+
* @brief Returns const reference to value of parameter `p` of generator `g`.
|
|
308
|
+
*/
|
|
309
|
+
const_reference operator()(size_type g, size_type p) const
|
|
310
|
+
{
|
|
311
|
+
GUDHI_CHECK(g < generators_.size() && p < number_of_parameters_, std::out_of_range("Out of bound index."));
|
|
312
|
+
if (generators_[g].size() < number_of_parameters_) return generators_[g][0];
|
|
313
|
+
return generators_[g][p];
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
/**
|
|
317
|
+
* @brief Returns const reference to the requested generator.
|
|
318
|
+
*
|
|
319
|
+
* @param g Index of the generator.
|
|
320
|
+
*/
|
|
321
|
+
const Generator &operator[](size_type g) const
|
|
322
|
+
{
|
|
323
|
+
GUDHI_CHECK(g < generators_.size(), std::out_of_range("Out of bound index."));
|
|
324
|
+
return generators_[g];
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
/**
|
|
328
|
+
* @brief Returns reference to the requested generator.
|
|
329
|
+
*
|
|
330
|
+
* @param g Index of the generator.
|
|
331
|
+
*/
|
|
332
|
+
Generator &operator[](size_type g)
|
|
333
|
+
{
|
|
334
|
+
GUDHI_CHECK(g < generators_.size(), std::out_of_range("Out of bound index."));
|
|
335
|
+
return generators_[g];
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
/**
|
|
339
|
+
* @brief Let \f$ g \f$ be the first value in `indices` and \f$ p \f$ the second value.
|
|
340
|
+
* Returns reference to value of parameter \f$ p \f$ of generator \f$ g \f$.
|
|
341
|
+
* If the value is at +/- inf or NaN and it needs to be modified, @ref force_generator_size_to_number_of_parameters
|
|
342
|
+
* needs potentially to be called first such that this methods returns the right reference.
|
|
343
|
+
*
|
|
344
|
+
* @tparam IndexRange Range with a begin() and size() method.
|
|
345
|
+
* @param indices Range with at least two elements. The first element should correspond to the generator number and
|
|
346
|
+
* the second element to the parameter number.
|
|
347
|
+
*/
|
|
348
|
+
template <class IndexRange = std::initializer_list<size_type>,
|
|
349
|
+
class = std::enable_if_t<RangeTraits<IndexRange>::has_begin> >
|
|
350
|
+
reference operator[](const IndexRange &indices)
|
|
351
|
+
{
|
|
352
|
+
GUDHI_CHECK(indices.size() >= 2,
|
|
353
|
+
std::invalid_argument(
|
|
354
|
+
"Exactly 2 indices allowed only: first the generator number, second the parameter number."));
|
|
355
|
+
auto it = indices.begin();
|
|
356
|
+
size_type g = *it;
|
|
357
|
+
return this->operator()(g, *(++it));
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
/**
|
|
361
|
+
* @brief Let \f$ g \f$ be the first value in `indices` and \f$ p \f$ the second value.
|
|
362
|
+
* Returns reference to value of parameter \f$ p \f$ of generator \f$ g \f$.
|
|
363
|
+
*
|
|
364
|
+
* @tparam IndexRange Range with a begin() and size() method.
|
|
365
|
+
* @param indices Range with at least two elements. The first element should correspond to the generator number and
|
|
366
|
+
* the second element to the parameter number.
|
|
367
|
+
*/
|
|
368
|
+
template <class IndexRange = std::initializer_list<size_type>,
|
|
369
|
+
class = std::enable_if_t<RangeTraits<IndexRange>::has_begin> >
|
|
370
|
+
const_reference operator[](const IndexRange &indices) const
|
|
371
|
+
{
|
|
372
|
+
GUDHI_CHECK(indices.size() >= 2,
|
|
373
|
+
std::invalid_argument(
|
|
374
|
+
"Exactly 2 indices allowed only: first the generator number, second the parameter number."));
|
|
375
|
+
auto it = indices.begin();
|
|
376
|
+
size_type g = *it;
|
|
377
|
+
return this->operator()(g, *(++it));
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
/**
|
|
381
|
+
* @brief Returns an iterator pointing the begining of the underlying container. Each element stored is a whole
|
|
382
|
+
* generator with a size() and a operator[].
|
|
383
|
+
*
|
|
384
|
+
* @warning If a generator is modified and the new set of generators is not minimal or not sorted, the behaviour
|
|
385
|
+
* of most methods is undefined. It is possible to call @ref simplify() after construction if there is a doubt to
|
|
386
|
+
* ensure this property.
|
|
387
|
+
*/
|
|
388
|
+
iterator begin() noexcept { return generators_.begin(); }
|
|
389
|
+
|
|
390
|
+
/**
|
|
391
|
+
* @brief Returns an iterator pointing the begining of the underlying container. Each element stored is a whole
|
|
392
|
+
* generator with a size() and a operator[].
|
|
393
|
+
*/
|
|
394
|
+
const_iterator begin() const noexcept { return generators_.begin(); }
|
|
395
|
+
|
|
396
|
+
/**
|
|
397
|
+
* @brief Returns an iterator pointing the begining of the underlying container. Each element stored is a whole
|
|
398
|
+
* generator with a size() and a operator[].
|
|
399
|
+
*/
|
|
400
|
+
const_iterator cbegin() const noexcept { return generators_.cbegin(); }
|
|
401
|
+
|
|
402
|
+
/**
|
|
403
|
+
* @brief Returns an iterator pointing the end of the underlying container.
|
|
404
|
+
*/
|
|
405
|
+
iterator end() noexcept { return generators_.end(); }
|
|
406
|
+
|
|
407
|
+
/**
|
|
408
|
+
* @brief Returns an iterator pointing the end of the underlying container.
|
|
409
|
+
*/
|
|
410
|
+
const_iterator end() const noexcept { return generators_.end(); }
|
|
411
|
+
|
|
412
|
+
/**
|
|
413
|
+
* @brief Returns an iterator pointing the end of the underlying container.
|
|
414
|
+
*/
|
|
415
|
+
const_iterator cend() const noexcept { return generators_.cend(); }
|
|
416
|
+
|
|
417
|
+
/**
|
|
418
|
+
* @brief Returns a reverse iterator pointing to the first element from the back of the underlying container.
|
|
419
|
+
* Each element stored is a whole generator with a size() and a operator[].
|
|
420
|
+
*
|
|
421
|
+
* @warning If a generator is modified and the new set of generators is not minimal or not sorted, the behaviour
|
|
422
|
+
* of most methods is undefined. It is possible to call @ref simplify() after construction if there is a doubt to
|
|
423
|
+
* ensure this property.
|
|
424
|
+
*/
|
|
425
|
+
reverse_iterator rbegin() noexcept { return generators_.rbegin(); }
|
|
426
|
+
|
|
427
|
+
/**
|
|
428
|
+
* @brief Returns a reverse iterator pointing to the first element from the back of the underlying container.
|
|
429
|
+
* Each element stored is a whole generator with a size() and a operator[].
|
|
430
|
+
*/
|
|
431
|
+
const_reverse_iterator rbegin() const noexcept { return generators_.rbegin(); }
|
|
432
|
+
|
|
433
|
+
/**
|
|
434
|
+
* @brief Returns a reverse iterator pointing to the first element from the back of the underlying container.
|
|
435
|
+
* Each element stored is a whole generator with a size() and a operator[].
|
|
436
|
+
*/
|
|
437
|
+
const_reverse_iterator crbegin() const noexcept { return generators_.crbegin(); }
|
|
438
|
+
|
|
439
|
+
/**
|
|
440
|
+
* @brief Returns a reverse iterator pointing to the end of the reversed underlying container.
|
|
441
|
+
*/
|
|
442
|
+
reverse_iterator rend() noexcept { return generators_.rend(); }
|
|
443
|
+
|
|
444
|
+
/**
|
|
445
|
+
* @brief Returns a reverse iterator pointing to the end of the reversed underlying container.
|
|
446
|
+
*/
|
|
447
|
+
const_reverse_iterator rend() const noexcept { return generators_.rend(); }
|
|
448
|
+
|
|
449
|
+
/**
|
|
450
|
+
* @brief Returns a reverse iterator pointing to the end of the reversed underlying container.
|
|
451
|
+
*/
|
|
452
|
+
const_reverse_iterator crend() const noexcept { return generators_.crend(); }
|
|
453
|
+
|
|
454
|
+
/**
|
|
455
|
+
* @brief Returns the size of the underlying container. Corresponds exactly to @ref num_generators(), but enables to
|
|
456
|
+
* use the class as a classic range with a `begin`, `end` and `size` method.
|
|
457
|
+
*/
|
|
458
|
+
size_type size() const noexcept { return generators_.size(); }
|
|
459
|
+
|
|
460
|
+
/**
|
|
461
|
+
* @brief Reserves space for the given number of generators in the underlying container. Does nothing if
|
|
462
|
+
* `Ensure1Criticality` is true.
|
|
463
|
+
*/
|
|
464
|
+
void reserve([[maybe_unused]] size_type number_of_generators)
|
|
465
|
+
{
|
|
466
|
+
if constexpr (Ensure1Criticality) {
|
|
467
|
+
return;
|
|
468
|
+
} else {
|
|
469
|
+
generators_.reserve(number_of_generators);
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
// CONVERTERS
|
|
474
|
+
|
|
475
|
+
// like numpy
|
|
476
|
+
/**
|
|
477
|
+
* @brief Returns a copy with entries casted into the type given as template parameter.
|
|
478
|
+
*
|
|
479
|
+
* @tparam U New type for the entries.
|
|
480
|
+
* @tparam OCo New value for `Co`. Default value: `Co`.
|
|
481
|
+
* @tparam OEns New value for `Ensure1Criticality`. Note that if `OEns` is set to true and the value is not
|
|
482
|
+
* 1-critical, the method will throw. Default value: `Ensure1Criticality`.
|
|
483
|
+
* @return Copy with new entry type.
|
|
484
|
+
*/
|
|
485
|
+
template <typename U, bool OCo = Co, bool OEns = Ensure1Criticality>
|
|
486
|
+
Dynamic_multi_parameter_filtration<U, OCo, OEns> as_type() const
|
|
487
|
+
{
|
|
488
|
+
std::vector<Multi_parameter_generator<U> > out(num_generators());
|
|
489
|
+
for (size_type g = 0; g < num_generators(); ++g) {
|
|
490
|
+
out[g] = generators_[g].template as_type<U>();
|
|
491
|
+
}
|
|
492
|
+
return Dynamic_multi_parameter_filtration<U, OCo, OEns>(std::move(out), num_parameters());
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
// ACCESS
|
|
496
|
+
|
|
497
|
+
/**
|
|
498
|
+
* @brief Returns the number of parameters in the filtration value.
|
|
499
|
+
*/
|
|
500
|
+
size_type num_parameters() const { return number_of_parameters_; }
|
|
501
|
+
|
|
502
|
+
/**
|
|
503
|
+
* @brief Returns the number of generators in the filtration value, i.e. the criticality of the element.
|
|
504
|
+
*/
|
|
505
|
+
size_type num_generators() const
|
|
506
|
+
{
|
|
507
|
+
if constexpr (Ensure1Criticality) {
|
|
508
|
+
return 1; // for possible optimizations? If there is none, we can just keep the other version
|
|
509
|
+
} else {
|
|
510
|
+
return generators_.size();
|
|
511
|
+
}
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
/**
|
|
515
|
+
* @brief Returns the total number of values in the filtration value, that is,
|
|
516
|
+
* @ref num_parameters() * @ref num_generators().
|
|
517
|
+
*/
|
|
518
|
+
size_type num_entries() const { return generators_.size() * number_of_parameters_; }
|
|
519
|
+
|
|
520
|
+
/**
|
|
521
|
+
* @brief Returns a filtration value with given number of parameters for which @ref is_plus_inf() returns `true`
|
|
522
|
+
* or an empty filtration value if `number_of_parameters` is 0.
|
|
523
|
+
*/
|
|
524
|
+
static Dynamic_multi_parameter_filtration inf(int number_of_parameters)
|
|
525
|
+
{
|
|
526
|
+
if (number_of_parameters == 0) return Dynamic_multi_parameter_filtration();
|
|
527
|
+
Underlying_container out(1, Generator::inf());
|
|
528
|
+
return Dynamic_multi_parameter_filtration(std::move(out), number_of_parameters);
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
/**
|
|
532
|
+
* @brief Returns a filtration value with given number of parameters for which @ref is_minus_inf() returns `true`
|
|
533
|
+
* or an empty filtration value if `number_of_parameters` is 0.
|
|
534
|
+
*/
|
|
535
|
+
static Dynamic_multi_parameter_filtration minus_inf(int number_of_parameters)
|
|
536
|
+
{
|
|
537
|
+
if (number_of_parameters == 0) return Dynamic_multi_parameter_filtration();
|
|
538
|
+
Underlying_container out(1, Generator::minus_inf());
|
|
539
|
+
return Dynamic_multi_parameter_filtration(std::move(out), number_of_parameters);
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
/**
|
|
543
|
+
* @brief Returns a filtration value with given number of parameters for which @ref is_nan() returns `true`
|
|
544
|
+
* or an empty filtration value if `number_of_parameters` is 0.
|
|
545
|
+
*/
|
|
546
|
+
static Dynamic_multi_parameter_filtration nan(int number_of_parameters)
|
|
547
|
+
{
|
|
548
|
+
if (number_of_parameters == 0) return Dynamic_multi_parameter_filtration();
|
|
549
|
+
Underlying_container out(1, Generator::nan());
|
|
550
|
+
return Dynamic_multi_parameter_filtration(std::move(out), number_of_parameters);
|
|
551
|
+
}
|
|
552
|
+
|
|
553
|
+
// DESCRIPTORS
|
|
554
|
+
|
|
555
|
+
/**
|
|
556
|
+
* @brief Returns value of `Ensure1Criticality`.
|
|
557
|
+
*/
|
|
558
|
+
static constexpr bool ensures_1_criticality() { return Ensure1Criticality; }
|
|
559
|
+
|
|
560
|
+
/**
|
|
561
|
+
* @brief Returns value of `Co`.
|
|
562
|
+
*/
|
|
563
|
+
static constexpr bool has_negative_cones() { return Co; }
|
|
564
|
+
|
|
565
|
+
/**
|
|
566
|
+
* @brief Returns `true` if and only if the filtration value is considered as plus infinity.
|
|
567
|
+
*/
|
|
568
|
+
[[nodiscard]] bool is_plus_inf() const
|
|
569
|
+
{
|
|
570
|
+
for (const Generator &g : generators_) {
|
|
571
|
+
if (!g.is_plus_inf()) return false;
|
|
572
|
+
}
|
|
573
|
+
return !generators_.empty();
|
|
574
|
+
}
|
|
575
|
+
|
|
576
|
+
/**
|
|
577
|
+
* @brief Returns `true` if and only if the filtration value is considered as minus infinity.
|
|
578
|
+
*/
|
|
579
|
+
[[nodiscard]] bool is_minus_inf() const
|
|
580
|
+
{
|
|
581
|
+
for (const Generator &g : generators_) {
|
|
582
|
+
if (!g.is_minus_inf()) return false;
|
|
583
|
+
}
|
|
584
|
+
return !generators_.empty();
|
|
585
|
+
}
|
|
586
|
+
|
|
587
|
+
/**
|
|
588
|
+
* @brief Returns `true` if and only if the filtration value is considered as NaN.
|
|
589
|
+
*/
|
|
590
|
+
[[nodiscard]] bool is_nan() const
|
|
591
|
+
{
|
|
592
|
+
if (generators_.empty()) return false;
|
|
593
|
+
for (const Generator &g : generators_) {
|
|
594
|
+
if (!g.is_nan()) return false;
|
|
595
|
+
}
|
|
596
|
+
return true;
|
|
597
|
+
}
|
|
598
|
+
|
|
599
|
+
/**
|
|
600
|
+
* @brief Returns `true` if and only if the filtration value is non-empty and is not considered as plus infinity,
|
|
601
|
+
* minus infinity or NaN.
|
|
602
|
+
*/
|
|
603
|
+
[[nodiscard]] bool is_finite() const
|
|
604
|
+
{
|
|
605
|
+
bool isInf = true, isMinusInf = true, isNan = true;
|
|
606
|
+
for (const Generator &g : generators_) {
|
|
607
|
+
if (!g.is_plus_inf()) isInf = false;
|
|
608
|
+
if (!g.is_minus_inf()) isMinusInf = false;
|
|
609
|
+
if (!g.is_nan()) isNan = false;
|
|
610
|
+
if (!isInf && !isMinusInf && !isNan) return true;
|
|
611
|
+
}
|
|
612
|
+
return false;
|
|
613
|
+
}
|
|
614
|
+
|
|
615
|
+
// COMPARAISON OPERATORS
|
|
616
|
+
|
|
617
|
+
/**
|
|
618
|
+
* @brief Returns `true` if and only if the first argument is lexicographically strictly less than the second
|
|
619
|
+
* argument. The "words" considered for the lexicographical order are all the generators concatenated together
|
|
620
|
+
* in order of generator index and then in order of parameter index. Different from @ref operator< "", this order
|
|
621
|
+
* is total.
|
|
622
|
+
*
|
|
623
|
+
* @tparam inverse If true, the parameter index and generator index order is inverted.
|
|
624
|
+
*/
|
|
625
|
+
template <bool inverse = false>
|
|
626
|
+
friend bool is_strict_less_than_lexicographically(const Dynamic_multi_parameter_filtration &a,
|
|
627
|
+
const Dynamic_multi_parameter_filtration &b)
|
|
628
|
+
{
|
|
629
|
+
if (&a == &b) return false;
|
|
630
|
+
|
|
631
|
+
GUDHI_CHECK(a.num_parameters() == b.num_parameters(),
|
|
632
|
+
std::invalid_argument("Only filtration values with same number of parameters can be compared."));
|
|
633
|
+
|
|
634
|
+
// line order matters
|
|
635
|
+
if (a.is_nan()) return false;
|
|
636
|
+
if (b.is_nan()) return true;
|
|
637
|
+
if (a.is_plus_inf() || b.is_minus_inf()) return false;
|
|
638
|
+
if (a.is_minus_inf() || b.is_plus_inf()) return true;
|
|
639
|
+
|
|
640
|
+
// TODO: verify if this really makes a differences in the 1-critical case, otherwise just keep the general case
|
|
641
|
+
if constexpr (Ensure1Criticality) {
|
|
642
|
+
for (std::size_t p = 0U; p < a.num_parameters(); ++p) {
|
|
643
|
+
if constexpr (inverse) p = a.num_parameters() - 1 - p;
|
|
644
|
+
if (_is_nan(a.generators_[0][p]) && !_is_nan(b.generators_[0][p])) return false;
|
|
645
|
+
if (_is_nan(b.generators_[0][p])) return true;
|
|
646
|
+
if (a.generators_[0][p] < b.generators_[0][p]) return true;
|
|
647
|
+
if (b.generators_[0][p] < a.generators_[0][p]) return false;
|
|
648
|
+
if constexpr (inverse) p = a.num_parameters() - 1 - p;
|
|
649
|
+
}
|
|
650
|
+
return false;
|
|
651
|
+
} else {
|
|
652
|
+
for (std::size_t g = 0U; g < std::min(a.num_generators(), b.num_generators()); ++g) {
|
|
653
|
+
std::size_t gA = g;
|
|
654
|
+
std::size_t gB = g;
|
|
655
|
+
if constexpr (inverse) {
|
|
656
|
+
gA = a.num_generators() - 1 - g;
|
|
657
|
+
gB = b.num_generators() - 1 - g;
|
|
658
|
+
}
|
|
659
|
+
for (std::size_t p = 0U; p < a.num_parameters(); ++p) {
|
|
660
|
+
if constexpr (inverse) p = a.num_parameters() - 1 - p;
|
|
661
|
+
if (_is_nan(a.generators_[gA][p]) && !_is_nan(b.generators_[gB][p])) return false;
|
|
662
|
+
if (_is_nan(b.generators_[gB][p])) return true;
|
|
663
|
+
if (a.generators_[gA][p] < b.generators_[gB][p]) return true;
|
|
664
|
+
if (b.generators_[gB][p] < a.generators_[gA][p]) return false;
|
|
665
|
+
if constexpr (inverse) p = a.num_parameters() - 1 - p;
|
|
666
|
+
}
|
|
667
|
+
}
|
|
668
|
+
return a.num_generators() < b.num_generators();
|
|
669
|
+
}
|
|
670
|
+
}
|
|
671
|
+
|
|
672
|
+
/**
|
|
673
|
+
* @brief Returns `true` if and only if the first argument is lexicographically less than or equal to the second
|
|
674
|
+
* argument. The "words" considered for the lexicographical order are all the generators concatenated together
|
|
675
|
+
* in order of generator index and then in order of parameter index. Different from @ref operator<= "", this order
|
|
676
|
+
* is total.
|
|
677
|
+
*
|
|
678
|
+
* @tparam inverse If true, the parameter index and generator index order is inverted.
|
|
679
|
+
*/
|
|
680
|
+
template <bool inverse = false>
|
|
681
|
+
friend bool is_less_or_equal_than_lexicographically(const Dynamic_multi_parameter_filtration &a,
|
|
682
|
+
const Dynamic_multi_parameter_filtration &b)
|
|
683
|
+
{
|
|
684
|
+
if (&a == &b) return true;
|
|
685
|
+
|
|
686
|
+
GUDHI_CHECK(a.num_parameters() == b.num_parameters(),
|
|
687
|
+
std::invalid_argument("Only filtration values with same number of parameters can be compared."));
|
|
688
|
+
|
|
689
|
+
// line order matters
|
|
690
|
+
if (b.is_nan()) return true;
|
|
691
|
+
if (a.is_nan()) return false;
|
|
692
|
+
if (a.is_minus_inf() || b.is_plus_inf()) return true;
|
|
693
|
+
if (a.is_plus_inf() || b.is_minus_inf()) return false;
|
|
694
|
+
|
|
695
|
+
// TODO: verify if this really makes a differences in the 1-critical case, otherwise just keep the general case
|
|
696
|
+
if constexpr (Ensure1Criticality) {
|
|
697
|
+
for (std::size_t p = 0U; p < a.num_parameters(); ++p) {
|
|
698
|
+
if constexpr (inverse) p = a.num_parameters() - 1 - p;
|
|
699
|
+
if (_is_nan(a.generators_[0][p]) && !_is_nan(b.generators_[0][p])) return false;
|
|
700
|
+
if (_is_nan(b.generators_[0][p])) return true;
|
|
701
|
+
if (a.generators_[0][p] < b.generators_[0][p]) return true;
|
|
702
|
+
if (b.generators_[0][p] < a.generators_[0][p]) return false;
|
|
703
|
+
if constexpr (inverse) p = a.num_parameters() - 1 - p;
|
|
704
|
+
}
|
|
705
|
+
return true;
|
|
706
|
+
} else {
|
|
707
|
+
for (std::size_t g = 0U; g < std::min(a.num_generators(), b.num_generators()); ++g) {
|
|
708
|
+
std::size_t gA = g;
|
|
709
|
+
std::size_t gB = g;
|
|
710
|
+
if constexpr (inverse) {
|
|
711
|
+
gA = a.num_generators() - 1 - g;
|
|
712
|
+
gB = b.num_generators() - 1 - g;
|
|
713
|
+
}
|
|
714
|
+
for (std::size_t p = 0U; p < a.num_parameters(); ++p) {
|
|
715
|
+
if constexpr (inverse) p = a.num_parameters() - 1 - p;
|
|
716
|
+
if (_is_nan(a.generators_[gA][p]) && !_is_nan(b.generators_[gB][p])) return false;
|
|
717
|
+
if (_is_nan(b.generators_[gB][p])) return true;
|
|
718
|
+
if (a.generators_[gA][p] < b.generators_[gB][p]) return true;
|
|
719
|
+
if (b.generators_[gB][p] < a.generators_[gA][p]) return false;
|
|
720
|
+
if constexpr (inverse) p = a.num_parameters() - 1 - p;
|
|
721
|
+
}
|
|
722
|
+
}
|
|
723
|
+
return a.num_generators() <= b.num_generators();
|
|
724
|
+
}
|
|
725
|
+
}
|
|
726
|
+
|
|
727
|
+
/**
|
|
728
|
+
* @brief Returns `true` if and only if the cones generated by @p b are strictly contained in the
|
|
729
|
+
* cones generated by @p a (recall that the cones are positive if `Co` is false and negative if `Co` is true).
|
|
730
|
+
* Both @p a and @p b have to have the same number of parameters.
|
|
731
|
+
*
|
|
732
|
+
* Note that not all filtration values are comparable. That is, \f$ a < b \f$ and \f$ b < a \f$ returning both false
|
|
733
|
+
* does **not** imply \f$ a == b \f$. If a total order is needed, use @ref is_strict_less_than_lexicographically
|
|
734
|
+
* instead.
|
|
735
|
+
*/
|
|
736
|
+
friend bool operator<(const Dynamic_multi_parameter_filtration &a, const Dynamic_multi_parameter_filtration &b)
|
|
737
|
+
{
|
|
738
|
+
if (&a == &b) return false;
|
|
739
|
+
|
|
740
|
+
GUDHI_CHECK(a.num_parameters() == b.num_parameters(),
|
|
741
|
+
std::invalid_argument("Only filtration values with same number of parameters can be compared."));
|
|
742
|
+
|
|
743
|
+
if (a.num_generators() == 0 || b.num_generators() == 0) return false;
|
|
744
|
+
|
|
745
|
+
// TODO: verify if this really makes a differences in the 1-critical case, otherwise just keep the general case
|
|
746
|
+
if constexpr (Ensure1Criticality) {
|
|
747
|
+
if (_first_dominates(a.generators_[0], b.generators_[0])) return false;
|
|
748
|
+
return _strictly_contains(a.generators_[0], b.generators_[0]);
|
|
749
|
+
} else {
|
|
750
|
+
for (std::size_t i = 0U; i < b.num_generators(); ++i) {
|
|
751
|
+
// for each generator in b, verify if it is strictly in the cone of at least one generator of a
|
|
752
|
+
bool isContained = false;
|
|
753
|
+
for (std::size_t j = 0U; j < a.num_generators() && !isContained; ++j) {
|
|
754
|
+
// lexicographical order, so if a[j][0] dom b[j][0], than a[j'] can never strictly contain b[i] for all
|
|
755
|
+
// j' > j.
|
|
756
|
+
if (_first_dominates(a.generators_[j], b.generators_[i])) return false;
|
|
757
|
+
isContained = _strictly_contains(a.generators_[j], b.generators_[i]);
|
|
758
|
+
}
|
|
759
|
+
if (!isContained) return false;
|
|
760
|
+
}
|
|
761
|
+
return true;
|
|
762
|
+
}
|
|
763
|
+
}
|
|
764
|
+
|
|
765
|
+
/**
|
|
766
|
+
* @brief Returns `true` if and only if the cones generated by @p a are strictly contained in the
|
|
767
|
+
* cones generated by @p b (recall that the cones are positive if `Co` is false and negative if `Co` is true).
|
|
768
|
+
* Both @p a and @p b have to have the same number of parameters.
|
|
769
|
+
*
|
|
770
|
+
* Note that not all filtration values are comparable. That is, \f$ a \le b \f$ and \f$ b \le a \f$ can both return
|
|
771
|
+
* `false`. If a total order is needed, use @ref is_less_or_equal_than_lexicographically instead.
|
|
772
|
+
*/
|
|
773
|
+
friend bool operator<=(const Dynamic_multi_parameter_filtration &a, const Dynamic_multi_parameter_filtration &b)
|
|
774
|
+
{
|
|
775
|
+
GUDHI_CHECK(a.num_parameters() == b.num_parameters(),
|
|
776
|
+
std::invalid_argument("Only filtration values with same number of parameters can be compared."));
|
|
777
|
+
|
|
778
|
+
if (a.num_generators() == 0 || b.num_generators() == 0) return false;
|
|
779
|
+
if (a.is_nan() || b.is_nan()) return false;
|
|
780
|
+
if (&a == &b) return true;
|
|
781
|
+
|
|
782
|
+
// TODO: verify if this really makes a differences in the 1-critical case, otherwise just keep the general case
|
|
783
|
+
if constexpr (Ensure1Criticality) {
|
|
784
|
+
if (_first_strictly_dominates(a.generators_[0], b.generators_[0])) return false;
|
|
785
|
+
return _contains(a.generators_[0], b.generators_[0]);
|
|
786
|
+
} else {
|
|
787
|
+
// check if this curves is below other's curve
|
|
788
|
+
// ie for each guy in this, check if there is a guy in other that dominates him
|
|
789
|
+
for (std::size_t i = 0U; i < b.num_generators(); ++i) {
|
|
790
|
+
// for each generator in b, verify if it is in the cone of at least one generator of a
|
|
791
|
+
bool isContained = false;
|
|
792
|
+
for (std::size_t j = 0U; j < a.num_generators() && !isContained; ++j) {
|
|
793
|
+
// lexicographical order, so if a[j][0] strictly dom b[j][0], than a[j'] can never contain b[i] for all
|
|
794
|
+
// j' > j.
|
|
795
|
+
if (_first_strictly_dominates(a.generators_[j], b.generators_[i])) return false;
|
|
796
|
+
isContained = _contains(a.generators_[j], b.generators_[i]);
|
|
797
|
+
}
|
|
798
|
+
if (!isContained) return false;
|
|
799
|
+
}
|
|
800
|
+
return true;
|
|
801
|
+
}
|
|
802
|
+
}
|
|
803
|
+
|
|
804
|
+
/**
|
|
805
|
+
* @brief Returns `true` if and only if the cones generated by @p b are contained in or are (partially)
|
|
806
|
+
* equal to the cones generated by @p a (recall that the cones are positive if `Co` is false and negative if `Co` is
|
|
807
|
+
* true).
|
|
808
|
+
* Both @p a and @p b have to have the same number of parameters.
|
|
809
|
+
*
|
|
810
|
+
* Note that not all filtration values are comparable. That is, \f$ a > b \f$ and \f$ b > a \f$ returning both false
|
|
811
|
+
* does **not** imply \f$ a == b \f$. If a total order is needed, use @ref is_strict_less_than_lexicographically
|
|
812
|
+
* instead.
|
|
813
|
+
*/
|
|
814
|
+
friend bool operator>(const Dynamic_multi_parameter_filtration &a, const Dynamic_multi_parameter_filtration &b)
|
|
815
|
+
{
|
|
816
|
+
return b < a;
|
|
817
|
+
}
|
|
818
|
+
|
|
819
|
+
/**
|
|
820
|
+
* @brief Returns `true` if and only if the cones generated by @p a are contained in or are (partially)
|
|
821
|
+
* equal to the cones generated by @p b (recall that the cones are positive if `Co` is false and negative if `Co` is
|
|
822
|
+
* true).
|
|
823
|
+
* Both @p a and @p b have to have the same number of parameters.
|
|
824
|
+
*
|
|
825
|
+
* Note that not all filtration values are comparable. That is, \f$ a \ge b \f$ and \f$ b \ge a \f$ can both return
|
|
826
|
+
* `false`. If a total order is needed, use @ref is_less_or_equal_than_lexicographically instead.
|
|
827
|
+
*/
|
|
828
|
+
friend bool operator>=(const Dynamic_multi_parameter_filtration &a, const Dynamic_multi_parameter_filtration &b)
|
|
829
|
+
{
|
|
830
|
+
return b <= a;
|
|
831
|
+
}
|
|
832
|
+
|
|
833
|
+
/**
|
|
834
|
+
* @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$.
|
|
835
|
+
*/
|
|
836
|
+
friend bool operator==(const Dynamic_multi_parameter_filtration &a, const Dynamic_multi_parameter_filtration &b)
|
|
837
|
+
{
|
|
838
|
+
if (a.is_nan() || b.is_nan()) return false;
|
|
839
|
+
if (&a == &b) return true;
|
|
840
|
+
if (a.number_of_parameters_ != b.number_of_parameters_) return false;
|
|
841
|
+
// assumes lexicographical order for both
|
|
842
|
+
return a.generators_ == b.generators_;
|
|
843
|
+
}
|
|
844
|
+
|
|
845
|
+
/**
|
|
846
|
+
* @brief Returns `true` if and only if \f$ a == b \f$ returns `false`.
|
|
847
|
+
*/
|
|
848
|
+
friend bool operator!=(const Dynamic_multi_parameter_filtration &a, const Dynamic_multi_parameter_filtration &b)
|
|
849
|
+
{
|
|
850
|
+
return !(a == b);
|
|
851
|
+
}
|
|
852
|
+
|
|
853
|
+
// ARITHMETIC OPERATORS
|
|
854
|
+
|
|
855
|
+
// opposite
|
|
856
|
+
/**
|
|
857
|
+
* @brief Returns a filtration value such that an entry at index \f$ i,j \f$ is equal to \f$ -f(i,j) \f$.
|
|
858
|
+
*
|
|
859
|
+
* Used conventions:
|
|
860
|
+
* - \f$ -NaN = NaN \f$.
|
|
861
|
+
*
|
|
862
|
+
* @param f Value to opposite.
|
|
863
|
+
* @return The opposite of @p f.
|
|
864
|
+
*/
|
|
865
|
+
friend Dynamic_multi_parameter_filtration operator-(const Dynamic_multi_parameter_filtration &f)
|
|
866
|
+
{
|
|
867
|
+
Underlying_container result(f.generators_);
|
|
868
|
+
std::for_each(result.begin(), result.end(), [](Generator &v) { v = -v; });
|
|
869
|
+
return Dynamic_multi_parameter_filtration(std::move(result), f.num_parameters());
|
|
870
|
+
}
|
|
871
|
+
|
|
872
|
+
// subtraction
|
|
873
|
+
/**
|
|
874
|
+
* @brief Returns a filtration value such that an entry at index \f$ (g,p) \f$, with
|
|
875
|
+
* \f$ 0 \leq g \leq num_generators \f$ and \f$ 0 \leq p \leq num_parameters \f$ is equal to \f$ f(g,p) - r(p) \f$
|
|
876
|
+
* if \f$ p < length_r \f$ and to \f$ f(g,p) \f$ otherwise.
|
|
877
|
+
*
|
|
878
|
+
* Used conventions:
|
|
879
|
+
* - \f$ inf - inf = NaN \f$,
|
|
880
|
+
* - \f$ -inf - (-inf) = NaN \f$,
|
|
881
|
+
* - \f$ NaN - b = NaN \f$,
|
|
882
|
+
* - \f$ a - NaN = NaN \f$.
|
|
883
|
+
*
|
|
884
|
+
* All NaN values are represented by `std::numeric_limits<T>::quiet_NaN()` independently if
|
|
885
|
+
* `std::numeric_limits<T>::has_quiet_NaN` is true or not.
|
|
886
|
+
*
|
|
887
|
+
* @warning The operator accepts @ref Dynamic_multi_parameter_filtration with the same or different template
|
|
888
|
+
* parameters as `ValueRange`. But if the number of generators is higher than 1, only the first generator will be
|
|
889
|
+
* used for the operation.
|
|
890
|
+
*
|
|
891
|
+
* @tparam ValueRange Either a range of into `T` convertible elements with a begin() and end() method,
|
|
892
|
+
* or @ref Dynamic_multi_parameter_filtration<U,...> with `U` convertible into `T`.
|
|
893
|
+
* @param f First element of the subtraction.
|
|
894
|
+
* @param r Second element of the subtraction.
|
|
895
|
+
*/
|
|
896
|
+
template <class ValueRange, class = std::enable_if_t<RangeTraits<ValueRange>::has_begin> >
|
|
897
|
+
friend Dynamic_multi_parameter_filtration operator-(Dynamic_multi_parameter_filtration f, const ValueRange &r)
|
|
898
|
+
{
|
|
899
|
+
f -= r;
|
|
900
|
+
return f;
|
|
901
|
+
}
|
|
902
|
+
|
|
903
|
+
/**
|
|
904
|
+
* @brief Returns a filtration value such that an entry at index \f$ (g,p) \f$, with
|
|
905
|
+
* \f$ 0 \leq g \leq num_generators \f$ and \f$ 0 \leq p \leq num_parameters \f$ is equal to \f$ r(p) - f(g,p) \f$
|
|
906
|
+
* if \f$ p < length_r \f$ and to \f$ -f(g,p) \f$ otherwise.
|
|
907
|
+
*
|
|
908
|
+
* Used conventions:
|
|
909
|
+
* - \f$ inf - inf = NaN \f$,
|
|
910
|
+
* - \f$ -inf - (-inf) = NaN \f$,
|
|
911
|
+
* - \f$ NaN - b = NaN \f$,
|
|
912
|
+
* - \f$ a - NaN = NaN \f$.
|
|
913
|
+
*
|
|
914
|
+
* All NaN values are represented by `std::numeric_limits<T>::quiet_NaN()` independently if
|
|
915
|
+
* `std::numeric_limits<T>::has_quiet_NaN` is true or not.
|
|
916
|
+
*
|
|
917
|
+
* @warning The operator accepts @ref Dynamic_multi_parameter_filtration with the same or different template
|
|
918
|
+
* parameters as `ValueRange`. But if the number of generators is higher than 1, only the first generator will be
|
|
919
|
+
* used for the operation.
|
|
920
|
+
*
|
|
921
|
+
* @tparam ValueRange Either a range of into `T` convertible elements with a begin() and end() method,
|
|
922
|
+
* or @ref Dynamic_multi_parameter_filtration<U,...> with `U` convertible into `T`.
|
|
923
|
+
* @param r First element of the subtraction.
|
|
924
|
+
* @param f Second element of the subtraction.
|
|
925
|
+
*/
|
|
926
|
+
template <class ValueRange,
|
|
927
|
+
class = std::enable_if_t<RangeTraits<ValueRange>::has_begin &&
|
|
928
|
+
!std::is_same_v<ValueRange, Dynamic_multi_parameter_filtration> > >
|
|
929
|
+
friend Dynamic_multi_parameter_filtration operator-(const ValueRange &r, Dynamic_multi_parameter_filtration f)
|
|
930
|
+
{
|
|
931
|
+
for (Generator &g : f.generators_) {
|
|
932
|
+
g = r - g;
|
|
933
|
+
}
|
|
934
|
+
|
|
935
|
+
return f;
|
|
936
|
+
}
|
|
937
|
+
|
|
938
|
+
/**
|
|
939
|
+
* @brief Returns a filtration value such that an entry at index \f$ (g,p) \f$ is equal to \f$ f(g,p) - val \f$.
|
|
940
|
+
*
|
|
941
|
+
* Used conventions:
|
|
942
|
+
* - \f$ inf - inf = NaN \f$,
|
|
943
|
+
* - \f$ -inf - (-inf) = NaN \f$,
|
|
944
|
+
* - \f$ NaN - b = NaN \f$,
|
|
945
|
+
* - \f$ a - NaN = NaN \f$.
|
|
946
|
+
*
|
|
947
|
+
* All NaN values are represented by `std::numeric_limits<T>::quiet_NaN()` independently if
|
|
948
|
+
* `std::numeric_limits<T>::has_quiet_NaN` is true or not.
|
|
949
|
+
*
|
|
950
|
+
* @param f First element of the subtraction.
|
|
951
|
+
* @param val Second element of the subtraction.
|
|
952
|
+
*/
|
|
953
|
+
friend Dynamic_multi_parameter_filtration operator-(Dynamic_multi_parameter_filtration f, const T &val)
|
|
954
|
+
{
|
|
955
|
+
f -= val;
|
|
956
|
+
return f;
|
|
957
|
+
}
|
|
958
|
+
|
|
959
|
+
/**
|
|
960
|
+
* @brief Returns a filtration value such that an entry at index \f$ (g,p) \f$ is equal to \f$ val - f(g,p) \f$.
|
|
961
|
+
*
|
|
962
|
+
* Used conventions:
|
|
963
|
+
* - \f$ inf - inf = NaN \f$,
|
|
964
|
+
* - \f$ -inf - (-inf) = NaN \f$,
|
|
965
|
+
* - \f$ NaN - b = NaN \f$,
|
|
966
|
+
* - \f$ a - NaN = NaN \f$.
|
|
967
|
+
*
|
|
968
|
+
* All NaN values are represented by `std::numeric_limits<T>::quiet_NaN()` independently if
|
|
969
|
+
* `std::numeric_limits<T>::has_quiet_NaN` is true or not.
|
|
970
|
+
*
|
|
971
|
+
* @param val First element of the subtraction.
|
|
972
|
+
* @param f Second element of the subtraction.
|
|
973
|
+
*/
|
|
974
|
+
friend Dynamic_multi_parameter_filtration operator-(const T &val, Dynamic_multi_parameter_filtration f)
|
|
975
|
+
{
|
|
976
|
+
for (Generator &g : f.generators_) {
|
|
977
|
+
g = val - g;
|
|
978
|
+
}
|
|
979
|
+
return f;
|
|
980
|
+
}
|
|
981
|
+
|
|
982
|
+
/**
|
|
983
|
+
* @brief Modifies the first parameter such that an entry at index \f$ (g,p) \f$, with
|
|
984
|
+
* \f$ 0 \leq g \leq num_generators \f$ and \f$ 0 \leq p \leq num_parameters \f$ is equal to \f$ f(g,p) - r(p) \f$
|
|
985
|
+
* if \f$ p < length_r \f$ and to \f$ f(g,p) \f$ otherwise.
|
|
986
|
+
*
|
|
987
|
+
* Used conventions:
|
|
988
|
+
* - \f$ inf - inf = NaN \f$,
|
|
989
|
+
* - \f$ -inf - (-inf) = NaN \f$,
|
|
990
|
+
* - \f$ NaN - b = NaN \f$,
|
|
991
|
+
* - \f$ a - NaN = NaN \f$.
|
|
992
|
+
*
|
|
993
|
+
* All NaN values are represented by `std::numeric_limits<T>::quiet_NaN()` independently if
|
|
994
|
+
* `std::numeric_limits<T>::has_quiet_NaN` is true or not.
|
|
995
|
+
*
|
|
996
|
+
* @warning The operator accepts @ref Dynamic_multi_parameter_filtration with the same or different template
|
|
997
|
+
* parameters as `ValueRange`. But if the number of generators is higher than 1, only the first generator will be
|
|
998
|
+
* used for the operation.
|
|
999
|
+
*
|
|
1000
|
+
* @tparam ValueRange Either a range of into `T` convertible elements with a begin() and end() method,
|
|
1001
|
+
* or @ref Dynamic_multi_parameter_filtration<U,...> with `U` convertible into `T`.
|
|
1002
|
+
* @param f First element of the subtraction.
|
|
1003
|
+
* @param r Second element of the subtraction.
|
|
1004
|
+
*/
|
|
1005
|
+
template <class ValueRange, class = std::enable_if_t<RangeTraits<ValueRange>::has_begin> >
|
|
1006
|
+
friend Dynamic_multi_parameter_filtration &operator-=(Dynamic_multi_parameter_filtration &f, const ValueRange &r)
|
|
1007
|
+
{
|
|
1008
|
+
for (Generator &g : f.generators_) {
|
|
1009
|
+
g -= r;
|
|
1010
|
+
}
|
|
1011
|
+
return f;
|
|
1012
|
+
}
|
|
1013
|
+
|
|
1014
|
+
/**
|
|
1015
|
+
* @brief Modifies the first parameter such that an entry at index \f$ (g,p) \f$ is equal to \f$ f(g,p) - val \f$.
|
|
1016
|
+
*
|
|
1017
|
+
* Used conventions:
|
|
1018
|
+
* - \f$ inf - inf = NaN \f$,
|
|
1019
|
+
* - \f$ -inf - (-inf) = NaN \f$,
|
|
1020
|
+
* - \f$ NaN - b = NaN \f$,
|
|
1021
|
+
* - \f$ a - NaN = NaN \f$.
|
|
1022
|
+
*
|
|
1023
|
+
* All NaN values are represented by `std::numeric_limits<T>::quiet_NaN()` independently if
|
|
1024
|
+
* `std::numeric_limits<T>::has_quiet_NaN` is true or not.
|
|
1025
|
+
*
|
|
1026
|
+
* @param f First element of the subtraction.
|
|
1027
|
+
* @param val Second element of the subtraction.
|
|
1028
|
+
*/
|
|
1029
|
+
friend Dynamic_multi_parameter_filtration &operator-=(Dynamic_multi_parameter_filtration &f, const T &val)
|
|
1030
|
+
{
|
|
1031
|
+
for (Generator &g : f.generators_) {
|
|
1032
|
+
g -= val;
|
|
1033
|
+
}
|
|
1034
|
+
return f;
|
|
1035
|
+
}
|
|
1036
|
+
|
|
1037
|
+
// addition
|
|
1038
|
+
/**
|
|
1039
|
+
* @brief Returns a filtration value such that an entry at index \f$ (g,p) \f$, with
|
|
1040
|
+
* \f$ 0 \leq g \leq num_generators \f$ and \f$ 0 \leq p \leq num_parameters \f$ is equal to \f$ f(g,p) + r(p) \f$
|
|
1041
|
+
* if \f$ p < length_r \f$ and to \f$ f(g,p) \f$ otherwise.
|
|
1042
|
+
*
|
|
1043
|
+
* Used conventions:
|
|
1044
|
+
* - \f$ inf + (-inf) = NaN \f$,
|
|
1045
|
+
* - \f$ -inf + inf = NaN \f$,
|
|
1046
|
+
* - \f$ NaN + b = NaN \f$,
|
|
1047
|
+
* - \f$ a + NaN = NaN \f$.
|
|
1048
|
+
*
|
|
1049
|
+
* All NaN values are represented by `std::numeric_limits<T>::quiet_NaN()` independently if
|
|
1050
|
+
* `std::numeric_limits<T>::has_quiet_NaN` is true or not.
|
|
1051
|
+
*
|
|
1052
|
+
* @warning The operator accepts @ref Dynamic_multi_parameter_filtration with the same or different template
|
|
1053
|
+
* parameters as `ValueRange`. But if the number of generators is higher than 1, only the first generator will be
|
|
1054
|
+
* used for the operation.
|
|
1055
|
+
*
|
|
1056
|
+
* @tparam ValueRange Either a range of into `T` convertible elements with a begin() and end() method,
|
|
1057
|
+
* or @ref Dynamic_multi_parameter_filtration<U,...> with `U` convertible into `T`.
|
|
1058
|
+
* @param f First element of the addition.
|
|
1059
|
+
* @param r Second element of the addition.
|
|
1060
|
+
*/
|
|
1061
|
+
template <class ValueRange, class = std::enable_if_t<RangeTraits<ValueRange>::has_begin> >
|
|
1062
|
+
friend Dynamic_multi_parameter_filtration operator+(Dynamic_multi_parameter_filtration f, const ValueRange &r)
|
|
1063
|
+
{
|
|
1064
|
+
f += r;
|
|
1065
|
+
return f;
|
|
1066
|
+
}
|
|
1067
|
+
|
|
1068
|
+
/**
|
|
1069
|
+
* @brief Returns a filtration value such that an entry at index \f$ (g,p) \f$, with
|
|
1070
|
+
* \f$ 0 \leq g \leq num_generators \f$ and \f$ 0 \leq p \leq num_parameters \f$ is equal to \f$ r(p) + f(g,p) \f$
|
|
1071
|
+
* if \f$ p < length_r \f$ and to \f$ f(g,p) \f$ otherwise.
|
|
1072
|
+
*
|
|
1073
|
+
* Used conventions:
|
|
1074
|
+
* - \f$ inf + (-inf) = NaN \f$,
|
|
1075
|
+
* - \f$ -inf + inf = NaN \f$,
|
|
1076
|
+
* - \f$ NaN + b = NaN \f$,
|
|
1077
|
+
* - \f$ a + NaN = NaN \f$.
|
|
1078
|
+
*
|
|
1079
|
+
* All NaN values are represented by `std::numeric_limits<T>::quiet_NaN()` independently if
|
|
1080
|
+
* `std::numeric_limits<T>::has_quiet_NaN` is true or not.
|
|
1081
|
+
*
|
|
1082
|
+
* @warning The operator accepts @ref Dynamic_multi_parameter_filtration with the same or different template
|
|
1083
|
+
* parameters as `ValueRange`. But if the number of generators is higher than 1, only the first generator will be
|
|
1084
|
+
* used for the operation.
|
|
1085
|
+
*
|
|
1086
|
+
* @tparam ValueRange Either a range of into `T` convertible elements with a begin() and end() method,
|
|
1087
|
+
* or @ref Dynamic_multi_parameter_filtration<U,...> with `U` convertible into `T`.
|
|
1088
|
+
* @param r First element of the addition.
|
|
1089
|
+
* @param f Second element of the addition.
|
|
1090
|
+
*/
|
|
1091
|
+
template <class ValueRange,
|
|
1092
|
+
class = std::enable_if_t<RangeTraits<ValueRange>::has_begin &&
|
|
1093
|
+
!std::is_same_v<ValueRange, Dynamic_multi_parameter_filtration> > >
|
|
1094
|
+
friend Dynamic_multi_parameter_filtration operator+(const ValueRange &r, Dynamic_multi_parameter_filtration f)
|
|
1095
|
+
{
|
|
1096
|
+
f += r;
|
|
1097
|
+
return f;
|
|
1098
|
+
}
|
|
1099
|
+
|
|
1100
|
+
/**
|
|
1101
|
+
* @brief Returns a filtration value such that an entry at index \f$ (g,p) \f$ is equal to \f$ f(g,p) + val \f$.
|
|
1102
|
+
*
|
|
1103
|
+
* Used conventions:
|
|
1104
|
+
* - \f$ inf + (-inf) = NaN \f$,
|
|
1105
|
+
* - \f$ -inf + inf = NaN \f$,
|
|
1106
|
+
* - \f$ NaN + b = NaN \f$,
|
|
1107
|
+
* - \f$ a + NaN = NaN \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 f First element of the addition.
|
|
1113
|
+
* @param val Second element of the addition.
|
|
1114
|
+
*/
|
|
1115
|
+
friend Dynamic_multi_parameter_filtration operator+(Dynamic_multi_parameter_filtration f, const T &val)
|
|
1116
|
+
{
|
|
1117
|
+
f += val;
|
|
1118
|
+
return f;
|
|
1119
|
+
}
|
|
1120
|
+
|
|
1121
|
+
/**
|
|
1122
|
+
* @brief Returns a filtration value such that an entry at index \f$ (g,p) \f$ is equal to \f$ val + f(g,p) \f$.
|
|
1123
|
+
*
|
|
1124
|
+
* Used conventions:
|
|
1125
|
+
* - \f$ inf + (-inf) = NaN \f$,
|
|
1126
|
+
* - \f$ -inf + inf = NaN \f$,
|
|
1127
|
+
* - \f$ NaN + b = NaN \f$,
|
|
1128
|
+
* - \f$ a + NaN = NaN \f$.
|
|
1129
|
+
*
|
|
1130
|
+
* All NaN values are represented by `std::numeric_limits<T>::quiet_NaN()` independently if
|
|
1131
|
+
* `std::numeric_limits<T>::has_quiet_NaN` is true or not.
|
|
1132
|
+
*
|
|
1133
|
+
* @param val First element of the addition.
|
|
1134
|
+
* @param f Second element of the addition.
|
|
1135
|
+
*/
|
|
1136
|
+
friend Dynamic_multi_parameter_filtration operator+(const T &val, Dynamic_multi_parameter_filtration f)
|
|
1137
|
+
{
|
|
1138
|
+
f += val;
|
|
1139
|
+
return f;
|
|
1140
|
+
}
|
|
1141
|
+
|
|
1142
|
+
/**
|
|
1143
|
+
* @brief Modifies the first parameter such that an entry at index \f$ (g,p) \f$, with
|
|
1144
|
+
* \f$ 0 \leq g \leq num_generators \f$ and \f$ 0 \leq p \leq num_parameters \f$ is equal to \f$ f(g,p) + r(p) \f$
|
|
1145
|
+
* if \f$ p < length_r \f$ and to \f$ f(g,p) \f$ otherwise.
|
|
1146
|
+
*
|
|
1147
|
+
* Used conventions:
|
|
1148
|
+
* - \f$ inf + (-inf) = NaN \f$,
|
|
1149
|
+
* - \f$ -inf + inf = NaN \f$,
|
|
1150
|
+
* - \f$ NaN + b = NaN \f$,
|
|
1151
|
+
* - \f$ a + NaN = NaN \f$.
|
|
1152
|
+
*
|
|
1153
|
+
* All NaN values are represented by `std::numeric_limits<T>::quiet_NaN()` independently if
|
|
1154
|
+
* `std::numeric_limits<T>::has_quiet_NaN` is true or not.
|
|
1155
|
+
*
|
|
1156
|
+
* @warning The operator accepts @ref Dynamic_multi_parameter_filtration with the same or different template
|
|
1157
|
+
* parameters as `ValueRange`. But if the number of generators is higher than 1, only the first generator will be
|
|
1158
|
+
* used for the operation.
|
|
1159
|
+
*
|
|
1160
|
+
* @tparam ValueRange Either a range of into `T` convertible elements with a begin() and end() method,
|
|
1161
|
+
* or @ref Dynamic_multi_parameter_filtration<U,...> with `U` convertible into `T`.
|
|
1162
|
+
* @param f First element of the addition.
|
|
1163
|
+
* @param r Second element of the addition.
|
|
1164
|
+
*/
|
|
1165
|
+
template <class ValueRange, class = std::enable_if_t<RangeTraits<ValueRange>::has_begin> >
|
|
1166
|
+
friend Dynamic_multi_parameter_filtration &operator+=(Dynamic_multi_parameter_filtration &f, const ValueRange &r)
|
|
1167
|
+
{
|
|
1168
|
+
for (Generator &g : f.generators_) {
|
|
1169
|
+
g += r;
|
|
1170
|
+
}
|
|
1171
|
+
return f;
|
|
1172
|
+
}
|
|
1173
|
+
|
|
1174
|
+
/**
|
|
1175
|
+
* @brief Modifies the first parameter such that an entry at index \f$ (g,p) \f$ is equal to \f$ f(g,p) + val \f$.
|
|
1176
|
+
*
|
|
1177
|
+
* Used conventions:
|
|
1178
|
+
* - \f$ inf + (-inf) = NaN \f$,
|
|
1179
|
+
* - \f$ -inf + inf = NaN \f$,
|
|
1180
|
+
* - \f$ NaN + b = NaN \f$,
|
|
1181
|
+
* - \f$ a + NaN = NaN \f$.
|
|
1182
|
+
*
|
|
1183
|
+
* All NaN values are represented by `std::numeric_limits<T>::quiet_NaN()` independently if
|
|
1184
|
+
* `std::numeric_limits<T>::has_quiet_NaN` is true or not.
|
|
1185
|
+
*
|
|
1186
|
+
* @param f First element of the addition.
|
|
1187
|
+
* @param val Second element of the addition.
|
|
1188
|
+
*/
|
|
1189
|
+
friend Dynamic_multi_parameter_filtration &operator+=(Dynamic_multi_parameter_filtration &f, const T &val)
|
|
1190
|
+
{
|
|
1191
|
+
for (Generator &g : f.generators_) {
|
|
1192
|
+
g += val;
|
|
1193
|
+
}
|
|
1194
|
+
return f;
|
|
1195
|
+
}
|
|
1196
|
+
|
|
1197
|
+
// multiplication
|
|
1198
|
+
/**
|
|
1199
|
+
* @brief Returns a filtration value such that an entry at index \f$ (g,p) \f$, with
|
|
1200
|
+
* \f$ 0 \leq g \leq num_generators \f$ and \f$ 0 \leq p \leq num_parameters \f$ is equal to \f$ f(g,p) * r(p) \f$
|
|
1201
|
+
* if \f$ p < length_r \f$ and to \f$ f(g,p) \f$ otherwise.
|
|
1202
|
+
*
|
|
1203
|
+
* Used conventions:
|
|
1204
|
+
* - \f$ inf * 0 = NaN \f$,
|
|
1205
|
+
* - \f$ 0 * inf = NaN \f$,
|
|
1206
|
+
* - \f$ -inf * 0 = NaN \f$,
|
|
1207
|
+
* - \f$ 0 * (-inf) = NaN \f$,
|
|
1208
|
+
* - \f$ NaN * b = NaN \f$,
|
|
1209
|
+
* - \f$ a * NaN = NaN \f$.
|
|
1210
|
+
*
|
|
1211
|
+
* All NaN values are represented by `std::numeric_limits<T>::quiet_NaN()` independently if
|
|
1212
|
+
* `std::numeric_limits<T>::has_quiet_NaN` is true or not.
|
|
1213
|
+
*
|
|
1214
|
+
* @warning The operator accepts @ref Dynamic_multi_parameter_filtration with the same or different template
|
|
1215
|
+
* parameters as `ValueRange`. But if the number of generators is higher than 1, only the first generator will be
|
|
1216
|
+
* used for the operation.
|
|
1217
|
+
*
|
|
1218
|
+
* @tparam ValueRange Either a range of into `T` convertible elements with a begin() and end() method,
|
|
1219
|
+
* or @ref Dynamic_multi_parameter_filtration<U,...> with `U` convertible into `T`.
|
|
1220
|
+
* @param f First element of the multiplication.
|
|
1221
|
+
* @param r Second element of the multiplication.
|
|
1222
|
+
*/
|
|
1223
|
+
template <class ValueRange, class = std::enable_if_t<RangeTraits<ValueRange>::has_begin> >
|
|
1224
|
+
friend Dynamic_multi_parameter_filtration operator*(Dynamic_multi_parameter_filtration f, const ValueRange &r)
|
|
1225
|
+
{
|
|
1226
|
+
f *= r;
|
|
1227
|
+
return f;
|
|
1228
|
+
}
|
|
1229
|
+
|
|
1230
|
+
/**
|
|
1231
|
+
* @brief Returns a filtration value such that an entry at index \f$ (g,p) \f$, with
|
|
1232
|
+
* \f$ 0 \leq g \leq num_generators \f$ and \f$ 0 \leq p \leq num_parameters \f$ is equal to \f$ r(p) * f(g,p) \f$
|
|
1233
|
+
* if \f$ p < length_r \f$ and to \f$ f(g,p) \f$ otherwise.
|
|
1234
|
+
*
|
|
1235
|
+
* Used conventions:
|
|
1236
|
+
* - \f$ inf * 0 = NaN \f$,
|
|
1237
|
+
* - \f$ 0 * inf = NaN \f$,
|
|
1238
|
+
* - \f$ -inf * 0 = NaN \f$,
|
|
1239
|
+
* - \f$ 0 * (-inf) = NaN \f$,
|
|
1240
|
+
* - \f$ NaN * b = NaN \f$,
|
|
1241
|
+
* - \f$ a * NaN = NaN \f$.
|
|
1242
|
+
*
|
|
1243
|
+
* All NaN values are represented by `std::numeric_limits<T>::quiet_NaN()` independently if
|
|
1244
|
+
* `std::numeric_limits<T>::has_quiet_NaN` is true or not.
|
|
1245
|
+
*
|
|
1246
|
+
* @warning The operator accepts @ref Dynamic_multi_parameter_filtration with the same or different template
|
|
1247
|
+
* parameters as `ValueRange`. But if the number of generators is higher than 1, only the first generator will be
|
|
1248
|
+
* used for the operation.
|
|
1249
|
+
*
|
|
1250
|
+
* @tparam ValueRange Either a range of into `T` convertible elements with a begin() and end() method,
|
|
1251
|
+
* or @ref Dynamic_multi_parameter_filtration<U,...> with `U` convertible into `T`.
|
|
1252
|
+
* @param r First element of the multiplication.
|
|
1253
|
+
* @param f Second element of the multiplication.
|
|
1254
|
+
*/
|
|
1255
|
+
template <class ValueRange,
|
|
1256
|
+
class = std::enable_if_t<RangeTraits<ValueRange>::has_begin &&
|
|
1257
|
+
!std::is_same_v<ValueRange, Dynamic_multi_parameter_filtration> > >
|
|
1258
|
+
friend Dynamic_multi_parameter_filtration operator*(const ValueRange &r, Dynamic_multi_parameter_filtration f)
|
|
1259
|
+
{
|
|
1260
|
+
f *= r;
|
|
1261
|
+
return f;
|
|
1262
|
+
}
|
|
1263
|
+
|
|
1264
|
+
/**
|
|
1265
|
+
* @brief Returns a filtration value such that an entry at index \f$ (g,p) \f$ is equal to \f$ f(g,p) * val \f$.
|
|
1266
|
+
*
|
|
1267
|
+
* Used conventions:
|
|
1268
|
+
* - \f$ inf * 0 = NaN \f$,
|
|
1269
|
+
* - \f$ 0 * inf = NaN \f$,
|
|
1270
|
+
* - \f$ -inf * 0 = NaN \f$,
|
|
1271
|
+
* - \f$ 0 * (-inf) = NaN \f$,
|
|
1272
|
+
* - \f$ NaN * b = NaN \f$,
|
|
1273
|
+
* - \f$ a * NaN = NaN \f$.
|
|
1274
|
+
*
|
|
1275
|
+
* All NaN values are represented by `std::numeric_limits<T>::quiet_NaN()` independently if
|
|
1276
|
+
* `std::numeric_limits<T>::has_quiet_NaN` is true or not.
|
|
1277
|
+
*
|
|
1278
|
+
* @param f First element of the multiplication.
|
|
1279
|
+
* @param val Second element of the multiplication.
|
|
1280
|
+
*/
|
|
1281
|
+
friend Dynamic_multi_parameter_filtration operator*(Dynamic_multi_parameter_filtration f, const T &val)
|
|
1282
|
+
{
|
|
1283
|
+
f *= val;
|
|
1284
|
+
return f;
|
|
1285
|
+
}
|
|
1286
|
+
|
|
1287
|
+
/**
|
|
1288
|
+
* @brief Returns a filtration value such that an entry at index \f$ (g,p) \f$ is equal to \f$ val * f(g,p) \f$.
|
|
1289
|
+
*
|
|
1290
|
+
* Used conventions:
|
|
1291
|
+
* - \f$ inf * 0 = NaN \f$,
|
|
1292
|
+
* - \f$ 0 * inf = NaN \f$,
|
|
1293
|
+
* - \f$ -inf * 0 = NaN \f$,
|
|
1294
|
+
* - \f$ 0 * (-inf) = NaN \f$,
|
|
1295
|
+
* - \f$ NaN * b = NaN \f$,
|
|
1296
|
+
* - \f$ a * NaN = NaN \f$.
|
|
1297
|
+
*
|
|
1298
|
+
* All NaN values are represented by `std::numeric_limits<T>::quiet_NaN()` independently if
|
|
1299
|
+
* `std::numeric_limits<T>::has_quiet_NaN` is true or not.
|
|
1300
|
+
*
|
|
1301
|
+
* @param val First element of the multiplication.
|
|
1302
|
+
* @param f Second element of the multiplication.
|
|
1303
|
+
*/
|
|
1304
|
+
friend Dynamic_multi_parameter_filtration operator*(const T &val, Dynamic_multi_parameter_filtration f)
|
|
1305
|
+
{
|
|
1306
|
+
f *= val;
|
|
1307
|
+
return f;
|
|
1308
|
+
}
|
|
1309
|
+
|
|
1310
|
+
/**
|
|
1311
|
+
* @brief Modifies the first parameter such that an entry at index \f$ (g,p) \f$, with
|
|
1312
|
+
* \f$ 0 \leq g \leq num_generators \f$ and \f$ 0 \leq p \leq num_parameters \f$ is equal to \f$ f(g,p) * r(p) \f$
|
|
1313
|
+
* if \f$ p < length_r \f$ and to \f$ f(g,p) \f$ otherwise.
|
|
1314
|
+
*
|
|
1315
|
+
* Used conventions:
|
|
1316
|
+
* - \f$ inf * 0 = NaN \f$,
|
|
1317
|
+
* - \f$ 0 * inf = NaN \f$,
|
|
1318
|
+
* - \f$ -inf * 0 = NaN \f$,
|
|
1319
|
+
* - \f$ 0 * (-inf) = NaN \f$,
|
|
1320
|
+
* - \f$ NaN * b = NaN \f$,
|
|
1321
|
+
* - \f$ a * NaN = NaN \f$.
|
|
1322
|
+
*
|
|
1323
|
+
* All NaN values are represented by `std::numeric_limits<T>::quiet_NaN()` independently if
|
|
1324
|
+
* `std::numeric_limits<T>::has_quiet_NaN` is true or not.
|
|
1325
|
+
*
|
|
1326
|
+
* @warning The operator accepts @ref Dynamic_multi_parameter_filtration with the same or different template
|
|
1327
|
+
* parameters as `ValueRange`. But if the number of generators is higher than 1, only the first generator will be
|
|
1328
|
+
* used for the operation.
|
|
1329
|
+
*
|
|
1330
|
+
* @tparam ValueRange Either a range of into `T` convertible elements with a begin() and end() method,
|
|
1331
|
+
* or @ref Dynamic_multi_parameter_filtration<U,...> with `U` convertible into `T`.
|
|
1332
|
+
* @param f First element of the multiplication.
|
|
1333
|
+
* @param r Second element of the multiplication.
|
|
1334
|
+
*/
|
|
1335
|
+
template <class ValueRange, class = std::enable_if_t<RangeTraits<ValueRange>::has_begin> >
|
|
1336
|
+
friend Dynamic_multi_parameter_filtration &operator*=(Dynamic_multi_parameter_filtration &f, const ValueRange &r)
|
|
1337
|
+
{
|
|
1338
|
+
for (Generator &g : f.generators_) {
|
|
1339
|
+
g *= r;
|
|
1340
|
+
}
|
|
1341
|
+
return f;
|
|
1342
|
+
}
|
|
1343
|
+
|
|
1344
|
+
/**
|
|
1345
|
+
* @brief Modifies the first parameter such that an entry at index \f$ (g,p) \f$ is equal to \f$ f(g,p) * val \f$.
|
|
1346
|
+
*
|
|
1347
|
+
* Used conventions:
|
|
1348
|
+
* - \f$ inf * 0 = NaN \f$,
|
|
1349
|
+
* - \f$ 0 * inf = NaN \f$,
|
|
1350
|
+
* - \f$ -inf * 0 = NaN \f$,
|
|
1351
|
+
* - \f$ 0 * (-inf) = NaN \f$,
|
|
1352
|
+
* - \f$ NaN * b = NaN \f$,
|
|
1353
|
+
* - \f$ a * NaN = NaN \f$.
|
|
1354
|
+
*
|
|
1355
|
+
* All NaN values are represented by `std::numeric_limits<T>::quiet_NaN()` independently if
|
|
1356
|
+
* `std::numeric_limits<T>::has_quiet_NaN` is true or not.
|
|
1357
|
+
*
|
|
1358
|
+
* @param f First element of the multiplication.
|
|
1359
|
+
* @param val Second element of the multiplication.
|
|
1360
|
+
*/
|
|
1361
|
+
friend Dynamic_multi_parameter_filtration &operator*=(Dynamic_multi_parameter_filtration &f, const T &val)
|
|
1362
|
+
{
|
|
1363
|
+
for (Generator &g : f.generators_) {
|
|
1364
|
+
g *= val;
|
|
1365
|
+
}
|
|
1366
|
+
return f;
|
|
1367
|
+
}
|
|
1368
|
+
|
|
1369
|
+
// division
|
|
1370
|
+
/**
|
|
1371
|
+
* @brief Returns a filtration value such that an entry at index \f$ (g,p) \f$, with
|
|
1372
|
+
* \f$ 0 \leq g \leq num_generators \f$ and \f$ 0 \leq p \leq num_parameters \f$ is equal to \f$ f(g,p) / r(p) \f$
|
|
1373
|
+
* if \f$ p < length_r \f$ and to \f$ f(g,p) \f$ otherwise.
|
|
1374
|
+
*
|
|
1375
|
+
* Used conventions:
|
|
1376
|
+
* - \f$ a / 0 = NaN \f$,
|
|
1377
|
+
* - \f$ inf / inf = NaN \f$,
|
|
1378
|
+
* - \f$ -inf / inf = NaN \f$,
|
|
1379
|
+
* - \f$ inf / -inf = NaN \f$,
|
|
1380
|
+
* - \f$ -inf / -inf = NaN \f$,
|
|
1381
|
+
* - \f$ NaN / b = NaN \f$,
|
|
1382
|
+
* - \f$ a / NaN = NaN \f$,
|
|
1383
|
+
* - \f$ a / inf = 0 \f$,
|
|
1384
|
+
* - \f$ a / -inf = 0 \f$.
|
|
1385
|
+
*
|
|
1386
|
+
* All NaN values are represented by `std::numeric_limits<T>::quiet_NaN()` independently if
|
|
1387
|
+
* `std::numeric_limits<T>::has_quiet_NaN` is true or not.
|
|
1388
|
+
*
|
|
1389
|
+
* @warning The operator accepts @ref Dynamic_multi_parameter_filtration with the same or different template
|
|
1390
|
+
* parameters as `ValueRange`. But if the number of generators is higher than 1, only the first generator will be
|
|
1391
|
+
* used for the operation.
|
|
1392
|
+
*
|
|
1393
|
+
* @tparam ValueRange Either a range of into `T` convertible elements with a begin() and end() method,
|
|
1394
|
+
* or @ref Dynamic_multi_parameter_filtration<U,...> with `U` convertible into `T`.
|
|
1395
|
+
* @param f First element of the division.
|
|
1396
|
+
* @param r Second element of the division.
|
|
1397
|
+
*/
|
|
1398
|
+
template <class ValueRange, class = std::enable_if_t<RangeTraits<ValueRange>::has_begin> >
|
|
1399
|
+
friend Dynamic_multi_parameter_filtration operator/(Dynamic_multi_parameter_filtration f, const ValueRange &r)
|
|
1400
|
+
{
|
|
1401
|
+
f /= r;
|
|
1402
|
+
return f;
|
|
1403
|
+
}
|
|
1404
|
+
|
|
1405
|
+
/**
|
|
1406
|
+
* @brief Returns a filtration value such that an entry at index \f$ (g,p) \f$, with
|
|
1407
|
+
* \f$ 0 \leq g \leq num_generators \f$ and \f$ 0 \leq p \leq num_parameters \f$ is equal to \f$ r(p) / f(g,p) \f$
|
|
1408
|
+
* if \f$ p < length_r \f$ and to \f$ f(g,p) \f$ otherwise.
|
|
1409
|
+
*
|
|
1410
|
+
* Used conventions:
|
|
1411
|
+
* - \f$ a / 0 = NaN \f$,
|
|
1412
|
+
* - \f$ inf / inf = NaN \f$,
|
|
1413
|
+
* - \f$ -inf / inf = NaN \f$,
|
|
1414
|
+
* - \f$ inf / -inf = NaN \f$,
|
|
1415
|
+
* - \f$ -inf / -inf = NaN \f$,
|
|
1416
|
+
* - \f$ NaN / b = NaN \f$,
|
|
1417
|
+
* - \f$ a / NaN = NaN \f$,
|
|
1418
|
+
* - \f$ a / inf = 0 \f$,
|
|
1419
|
+
* - \f$ a / -inf = 0 \f$.
|
|
1420
|
+
*
|
|
1421
|
+
* All NaN values are represented by `std::numeric_limits<T>::quiet_NaN()` independently if
|
|
1422
|
+
* `std::numeric_limits<T>::has_quiet_NaN` is true or not.
|
|
1423
|
+
*
|
|
1424
|
+
* @warning The operator accepts @ref Dynamic_multi_parameter_filtration with the same or different template
|
|
1425
|
+
* parameters as `ValueRange`. But if the number of generators is higher than 1, only the first generator will be
|
|
1426
|
+
* used for the operation.
|
|
1427
|
+
*
|
|
1428
|
+
* @tparam ValueRange Either a range of into `T` convertible elements with a begin() and end() method,
|
|
1429
|
+
* or @ref Dynamic_multi_parameter_filtration<U,...> with `U` convertible into `T`.
|
|
1430
|
+
* @param r First element of the division.
|
|
1431
|
+
* @param f Second element of the division.
|
|
1432
|
+
*/
|
|
1433
|
+
template <class ValueRange,
|
|
1434
|
+
class = std::enable_if_t<RangeTraits<ValueRange>::has_begin &&
|
|
1435
|
+
!std::is_same_v<ValueRange, Dynamic_multi_parameter_filtration> > >
|
|
1436
|
+
friend Dynamic_multi_parameter_filtration operator/(const ValueRange &r, Dynamic_multi_parameter_filtration f)
|
|
1437
|
+
{
|
|
1438
|
+
for (Generator &g : f.generators_) {
|
|
1439
|
+
g = r / g;
|
|
1440
|
+
}
|
|
1441
|
+
return f;
|
|
1442
|
+
}
|
|
1443
|
+
|
|
1444
|
+
/**
|
|
1445
|
+
* @brief Returns a filtration value such that an entry at index \f$ (g,p) \f$ is equal to \f$ f(g,p) / val \f$.
|
|
1446
|
+
*
|
|
1447
|
+
* Used conventions:
|
|
1448
|
+
* - \f$ a / 0 = NaN \f$,
|
|
1449
|
+
* - \f$ inf / inf = NaN \f$,
|
|
1450
|
+
* - \f$ -inf / inf = NaN \f$,
|
|
1451
|
+
* - \f$ inf / -inf = NaN \f$,
|
|
1452
|
+
* - \f$ -inf / -inf = NaN \f$,
|
|
1453
|
+
* - \f$ NaN / b = NaN \f$,
|
|
1454
|
+
* - \f$ a / NaN = NaN \f$,
|
|
1455
|
+
* - \f$ a / inf = 0 \f$,
|
|
1456
|
+
* - \f$ a / -inf = 0 \f$.
|
|
1457
|
+
*
|
|
1458
|
+
* All NaN values are represented by `std::numeric_limits<T>::quiet_NaN()` independently if
|
|
1459
|
+
* `std::numeric_limits<T>::has_quiet_NaN` is true or not.
|
|
1460
|
+
*
|
|
1461
|
+
* @param f First element of the division.
|
|
1462
|
+
* @param val Second element of the division.
|
|
1463
|
+
*/
|
|
1464
|
+
friend Dynamic_multi_parameter_filtration operator/(Dynamic_multi_parameter_filtration f, const T &val)
|
|
1465
|
+
{
|
|
1466
|
+
f /= val;
|
|
1467
|
+
return f;
|
|
1468
|
+
}
|
|
1469
|
+
|
|
1470
|
+
/**
|
|
1471
|
+
* @brief Returns a filtration value such that an entry at index \f$ (g,p) \f$ is equal to \f$ val / f(g,p) \f$.
|
|
1472
|
+
*
|
|
1473
|
+
* Used conventions:
|
|
1474
|
+
* - \f$ a / 0 = NaN \f$,
|
|
1475
|
+
* - \f$ inf / inf = NaN \f$,
|
|
1476
|
+
* - \f$ -inf / inf = NaN \f$,
|
|
1477
|
+
* - \f$ inf / -inf = NaN \f$,
|
|
1478
|
+
* - \f$ -inf / -inf = NaN \f$,
|
|
1479
|
+
* - \f$ NaN / b = NaN \f$,
|
|
1480
|
+
* - \f$ a / NaN = NaN \f$,
|
|
1481
|
+
* - \f$ a / inf = 0 \f$,
|
|
1482
|
+
* - \f$ a / -inf = 0 \f$.
|
|
1483
|
+
*
|
|
1484
|
+
* All NaN values are represented by `std::numeric_limits<T>::quiet_NaN()` independently if
|
|
1485
|
+
* `std::numeric_limits<T>::has_quiet_NaN` is true or not.
|
|
1486
|
+
*
|
|
1487
|
+
* @param val First element of the division.
|
|
1488
|
+
* @param f Second element of the division.
|
|
1489
|
+
*/
|
|
1490
|
+
friend Dynamic_multi_parameter_filtration operator/(const T &val, Dynamic_multi_parameter_filtration f)
|
|
1491
|
+
{
|
|
1492
|
+
for (Generator &g : f.generators_) {
|
|
1493
|
+
g = val / g;
|
|
1494
|
+
}
|
|
1495
|
+
return f;
|
|
1496
|
+
}
|
|
1497
|
+
|
|
1498
|
+
/**
|
|
1499
|
+
* @brief Modifies the first parameter such that an entry at index \f$ (g,p) \f$, with
|
|
1500
|
+
* \f$ 0 \leq g \leq num_generators \f$ and \f$ 0 \leq p \leq num_parameters \f$ is equal to \f$ f(g,p) / r(p) \f$
|
|
1501
|
+
* if \f$ p < length_r \f$ and to \f$ f(g,p) \f$ otherwise.
|
|
1502
|
+
*
|
|
1503
|
+
* Used conventions:
|
|
1504
|
+
* - \f$ a / 0 = NaN \f$,
|
|
1505
|
+
* - \f$ inf / inf = NaN \f$,
|
|
1506
|
+
* - \f$ -inf / inf = NaN \f$,
|
|
1507
|
+
* - \f$ inf / -inf = NaN \f$,
|
|
1508
|
+
* - \f$ -inf / -inf = NaN \f$,
|
|
1509
|
+
* - \f$ NaN / b = NaN \f$,
|
|
1510
|
+
* - \f$ a / NaN = NaN \f$,
|
|
1511
|
+
* - \f$ a / inf = 0 \f$,
|
|
1512
|
+
* - \f$ a / -inf = 0 \f$.
|
|
1513
|
+
*
|
|
1514
|
+
* All NaN values are represented by `std::numeric_limits<T>::quiet_NaN()` independently if
|
|
1515
|
+
* `std::numeric_limits<T>::has_quiet_NaN` is true or not.
|
|
1516
|
+
*
|
|
1517
|
+
* @warning The operator accepts @ref Dynamic_multi_parameter_filtration with the same or different template
|
|
1518
|
+
* parameters as `ValueRange`. But if the number of generators is higher than 1, only the first generator will be
|
|
1519
|
+
* used for the operation.
|
|
1520
|
+
*
|
|
1521
|
+
* @tparam ValueRange Either a range of into `T` convertible elements with a begin() and end() method,
|
|
1522
|
+
* or @ref Dynamic_multi_parameter_filtration<U,...> with `U` convertible into `T`.
|
|
1523
|
+
* @param f First element of the division.
|
|
1524
|
+
* @param r Second element of the division.
|
|
1525
|
+
*/
|
|
1526
|
+
template <class ValueRange, class = std::enable_if_t<RangeTraits<ValueRange>::has_begin> >
|
|
1527
|
+
friend Dynamic_multi_parameter_filtration &operator/=(Dynamic_multi_parameter_filtration &f, const ValueRange &r)
|
|
1528
|
+
{
|
|
1529
|
+
for (Generator &g : f.generators_) {
|
|
1530
|
+
g /= r;
|
|
1531
|
+
}
|
|
1532
|
+
return f;
|
|
1533
|
+
}
|
|
1534
|
+
|
|
1535
|
+
/**
|
|
1536
|
+
* @brief Modifies the first parameter such that an entry at index \f$ (g,p) \f$ is equal to \f$ f(g,p) / val \f$.
|
|
1537
|
+
*
|
|
1538
|
+
* Used conventions:
|
|
1539
|
+
* - \f$ a / 0 = NaN \f$,
|
|
1540
|
+
* - \f$ inf / inf = NaN \f$,
|
|
1541
|
+
* - \f$ -inf / inf = NaN \f$,
|
|
1542
|
+
* - \f$ inf / -inf = NaN \f$,
|
|
1543
|
+
* - \f$ -inf / -inf = NaN \f$,
|
|
1544
|
+
* - \f$ NaN / b = NaN \f$,
|
|
1545
|
+
* - \f$ a / NaN = NaN \f$,
|
|
1546
|
+
* - \f$ a / inf = 0 \f$,
|
|
1547
|
+
* - \f$ a / -inf = 0 \f$.
|
|
1548
|
+
*
|
|
1549
|
+
* All NaN values are represented by `std::numeric_limits<T>::quiet_NaN()` independently if
|
|
1550
|
+
* `std::numeric_limits<T>::has_quiet_NaN` is true or not.
|
|
1551
|
+
*
|
|
1552
|
+
* @param f First element of the division.
|
|
1553
|
+
* @param val Second element of the division.
|
|
1554
|
+
*/
|
|
1555
|
+
friend Dynamic_multi_parameter_filtration &operator/=(Dynamic_multi_parameter_filtration &f, const T &val)
|
|
1556
|
+
{
|
|
1557
|
+
for (Generator &g : f.generators_) {
|
|
1558
|
+
g /= val;
|
|
1559
|
+
}
|
|
1560
|
+
return f;
|
|
1561
|
+
}
|
|
1562
|
+
|
|
1563
|
+
// MODIFIERS
|
|
1564
|
+
|
|
1565
|
+
/**
|
|
1566
|
+
* @brief Sets the number of generators. If there were less generators before, new generators with default values are
|
|
1567
|
+
* constructed. If there were more generators before, the exceed of generators is destroyed (any generator with index
|
|
1568
|
+
* higher or equal to @p g to be more precise). If @p g is zero, the methods does nothing.
|
|
1569
|
+
*
|
|
1570
|
+
* Fails to compile if `Ensure1Criticality` is true.
|
|
1571
|
+
*
|
|
1572
|
+
* @warning All new generators will be set to infinity (`Co` is true) or -infinity (`Co` is false). That is, the new
|
|
1573
|
+
* filtration value is not minimal anymore. Make sure to fill them with real generators or to remove them before
|
|
1574
|
+
* using other methods.
|
|
1575
|
+
*
|
|
1576
|
+
* @warning Be sure to call @ref simplify if necessary after initializing all the generators. Most methods will have
|
|
1577
|
+
* an undefined behaviour if the set of generators is not minimal or sorted.
|
|
1578
|
+
*
|
|
1579
|
+
* @param g New number of generators.
|
|
1580
|
+
*/
|
|
1581
|
+
void set_num_generators(size_type g)
|
|
1582
|
+
{
|
|
1583
|
+
static_assert(!Ensure1Criticality, "Number of generators cannot be set for a 1-critical only filtration value.");
|
|
1584
|
+
|
|
1585
|
+
if (g == 0) return;
|
|
1586
|
+
|
|
1587
|
+
generators_.resize(g);
|
|
1588
|
+
}
|
|
1589
|
+
|
|
1590
|
+
/**
|
|
1591
|
+
* @brief If a generator is at +/- infinity or NaN, the underlying container can potentially (surely if just
|
|
1592
|
+
* constructed with default values) only contain one element, representing the value, instead of number of parameters
|
|
1593
|
+
* elements. This method forces the underlying container of the given generator to contain explicitly
|
|
1594
|
+
* an elements for each parameter, if it was not already the case.
|
|
1595
|
+
*/
|
|
1596
|
+
void force_generator_size_to_number_of_parameters(size_type g)
|
|
1597
|
+
{
|
|
1598
|
+
if (g > num_generators()) return;
|
|
1599
|
+
generators_[g].force_size_to_number_of_parameters(number_of_parameters_);
|
|
1600
|
+
}
|
|
1601
|
+
|
|
1602
|
+
/**
|
|
1603
|
+
* @brief Adds the given generator to the filtration value such that the set remains minimal and sorted.
|
|
1604
|
+
* It is therefore possible that the generator is ignored if it does not generated any new lifetime or that
|
|
1605
|
+
* old generators disappear if they are overshadowed by the new one.
|
|
1606
|
+
*
|
|
1607
|
+
* @tparam GeneratorRange Range of elements convertible to `T`. Must have a begin(), end() method and the iterator
|
|
1608
|
+
* type should satisfy the requirements of the standard `LegacyForwardIterator`.
|
|
1609
|
+
* @param x New generator to add. Has to have the same number of parameters than @ref num_parameters().
|
|
1610
|
+
* @return true If and only if the generator is actually added to the set of generators.
|
|
1611
|
+
* @return false Otherwise.
|
|
1612
|
+
*/
|
|
1613
|
+
template <class GeneratorRange = std::initializer_list<T>,
|
|
1614
|
+
class = std::enable_if_t<RangeTraits<GeneratorRange>::has_begin> >
|
|
1615
|
+
bool add_generator(const GeneratorRange &x)
|
|
1616
|
+
{
|
|
1617
|
+
if constexpr (std::is_same_v<GeneratorRange, Generator>) {
|
|
1618
|
+
if (x.is_nan()) return false;
|
|
1619
|
+
bool xIsPlusInf = x.is_plus_inf();
|
|
1620
|
+
bool xIsMinusInf = x.is_minus_inf();
|
|
1621
|
+
if (!Co && xIsPlusInf) return false;
|
|
1622
|
+
if (Co && xIsMinusInf) return false;
|
|
1623
|
+
if (xIsPlusInf) {
|
|
1624
|
+
if (is_plus_inf()) return false;
|
|
1625
|
+
*this = inf(number_of_parameters_);
|
|
1626
|
+
return true;
|
|
1627
|
+
}
|
|
1628
|
+
if (xIsMinusInf) {
|
|
1629
|
+
if (is_minus_inf()) return false;
|
|
1630
|
+
*this = minus_inf(number_of_parameters_);
|
|
1631
|
+
return true;
|
|
1632
|
+
}
|
|
1633
|
+
}
|
|
1634
|
+
return add_generator(x.begin(), x.end());
|
|
1635
|
+
}
|
|
1636
|
+
|
|
1637
|
+
/**
|
|
1638
|
+
* @brief Adds the given generator to the filtration value such that the set remains minimal and sorted.
|
|
1639
|
+
* It is therefore possible that the generator is ignored if it does not generated any new lifetime or that
|
|
1640
|
+
* old generators disappear if they are overshadowed by the new one.
|
|
1641
|
+
*
|
|
1642
|
+
* @tparam Iterator Iterator class satisfying the requirements of the standard `LegacyForwardIterator`.
|
|
1643
|
+
* The dereferenced type has to be convertible to `T`.
|
|
1644
|
+
* @param genStart Iterator pointing to the begining of the range.
|
|
1645
|
+
* @param genEnd Iterator pointing to the end of the range.
|
|
1646
|
+
* @return true If and only if the generator is actually added to the set of generators.
|
|
1647
|
+
* @return false Otherwise.
|
|
1648
|
+
*/
|
|
1649
|
+
template <class Iterator>
|
|
1650
|
+
bool add_generator(Iterator genStart, Iterator genEnd)
|
|
1651
|
+
{
|
|
1652
|
+
GUDHI_CHECK(std::distance(genStart, genEnd) == static_cast<int>(num_parameters()),
|
|
1653
|
+
std::invalid_argument("Wrong range size. Should correspond to the number of parameters."));
|
|
1654
|
+
|
|
1655
|
+
size_type end = num_generators();
|
|
1656
|
+
|
|
1657
|
+
if (_generator_can_be_added(genStart, 0, end)) {
|
|
1658
|
+
generators_.resize(end);
|
|
1659
|
+
generators_.emplace_back(genStart, genEnd);
|
|
1660
|
+
if constexpr (Ensure1Criticality) {
|
|
1661
|
+
if (generators_.size() != 1)
|
|
1662
|
+
throw std::logic_error("Multiparameter filtration value is not 1-critical anymore.");
|
|
1663
|
+
}
|
|
1664
|
+
std::sort(generators_.begin(), generators_.end(), Is_strictly_smaller_lexicographically());
|
|
1665
|
+
return true;
|
|
1666
|
+
}
|
|
1667
|
+
|
|
1668
|
+
return false;
|
|
1669
|
+
}
|
|
1670
|
+
|
|
1671
|
+
/**
|
|
1672
|
+
* @brief Adds the given generator to the filtration value without any verifications or simplifications at the end
|
|
1673
|
+
* of the set.
|
|
1674
|
+
*
|
|
1675
|
+
* Fails to compile if `Ensure1Criticality` is true.
|
|
1676
|
+
*
|
|
1677
|
+
* @warning If the resulting set of generators is not minimal or sorted after modification, some methods will have an
|
|
1678
|
+
* undefined behaviour. Be sure to call @ref simplify() before using them.
|
|
1679
|
+
*
|
|
1680
|
+
* @tparam GeneratorRange Range of elements convertible to `T`. Must have a begin(), end() and size() method.
|
|
1681
|
+
* @param x New generator to add. Must have the same number of parameters than @ref num_parameters().
|
|
1682
|
+
*/
|
|
1683
|
+
template <class GeneratorRange = std::initializer_list<T>,
|
|
1684
|
+
class = std::enable_if_t<RangeTraits<GeneratorRange>::has_begin> >
|
|
1685
|
+
void add_guaranteed_generator(const GeneratorRange &x)
|
|
1686
|
+
{
|
|
1687
|
+
static_assert(!Ensure1Criticality, "Cannot add additional generator to a 1-critical only filtration value.");
|
|
1688
|
+
|
|
1689
|
+
if constexpr (std::is_same_v<GeneratorRange, Generator>) {
|
|
1690
|
+
generators_.push_back(x);
|
|
1691
|
+
} else {
|
|
1692
|
+
GUDHI_CHECK(x.size() == num_parameters(),
|
|
1693
|
+
std::invalid_argument("Wrong range size. Should correspond to the number of parameters."));
|
|
1694
|
+
generators_.emplace_back(x.begin(), x.end());
|
|
1695
|
+
}
|
|
1696
|
+
}
|
|
1697
|
+
|
|
1698
|
+
/**
|
|
1699
|
+
* @brief Simplifies the current set of generators such that it becomes minimal. Also orders it in increasing
|
|
1700
|
+
* lexicographical order. Only necessary if generators were added "by hand" without verification either trough the
|
|
1701
|
+
* constructor or with @ref add_guaranteed_generator "", etc.
|
|
1702
|
+
*/
|
|
1703
|
+
void simplify()
|
|
1704
|
+
{
|
|
1705
|
+
if constexpr (Ensure1Criticality) {
|
|
1706
|
+
return;
|
|
1707
|
+
} else {
|
|
1708
|
+
size_type end = 0;
|
|
1709
|
+
|
|
1710
|
+
for (std::size_t curr = 0; curr < generators_.size(); ++curr) {
|
|
1711
|
+
if (!generators_[curr].is_finite()) {
|
|
1712
|
+
if constexpr (Co) {
|
|
1713
|
+
if (generators_[curr].is_plus_inf()) {
|
|
1714
|
+
*this = inf(number_of_parameters_);
|
|
1715
|
+
return;
|
|
1716
|
+
}
|
|
1717
|
+
} else {
|
|
1718
|
+
if (generators_[curr].is_minus_inf()) {
|
|
1719
|
+
*this = minus_inf(number_of_parameters_);
|
|
1720
|
+
return;
|
|
1721
|
+
}
|
|
1722
|
+
}
|
|
1723
|
+
if (end == 0) ++end; // if first element is +/-inf or nan, it should be kept at first
|
|
1724
|
+
} else {
|
|
1725
|
+
if (_generator_can_be_added(generators_[curr].begin(), 0, end)) {
|
|
1726
|
+
swap(generators_[end], generators_[curr]);
|
|
1727
|
+
++end;
|
|
1728
|
+
}
|
|
1729
|
+
}
|
|
1730
|
+
}
|
|
1731
|
+
|
|
1732
|
+
generators_.resize(end);
|
|
1733
|
+
std::sort(generators_.begin(), generators_.end(), Is_strictly_smaller_lexicographically());
|
|
1734
|
+
}
|
|
1735
|
+
}
|
|
1736
|
+
|
|
1737
|
+
/**
|
|
1738
|
+
* @brief Removes all empty generators from the filtration value. If @p include_infinities is true, it also
|
|
1739
|
+
* removes the generators at infinity or minus infinity (or with NaN value).
|
|
1740
|
+
* If the set of generators is empty after removals, it is set to minus infinity if `Co` is false or to infinity
|
|
1741
|
+
* if `Co` is true.
|
|
1742
|
+
*
|
|
1743
|
+
* @warning If the resulting set of generators is not minimal after the removals/sorting, some methods will have an
|
|
1744
|
+
* undefined behaviour. Be sure to call @ref simplify() before using them.
|
|
1745
|
+
*
|
|
1746
|
+
* @param include_infinities If true, removes also infinity values.
|
|
1747
|
+
*/
|
|
1748
|
+
void remove_empty_generators(bool include_infinities = false)
|
|
1749
|
+
{
|
|
1750
|
+
// TODO: verify if this really makes a differences in the 1-critical case, otherwise just keep the general case
|
|
1751
|
+
if constexpr (Ensure1Criticality) {
|
|
1752
|
+
const Generator &g = generators_[0];
|
|
1753
|
+
if (g.size() == 0 || (include_infinities && !g.is_finite())) generators_.clear();
|
|
1754
|
+
} else {
|
|
1755
|
+
generators_.erase(std::remove_if(generators_.begin(),
|
|
1756
|
+
generators_.end(),
|
|
1757
|
+
[include_infinities](const Generator &a) {
|
|
1758
|
+
return a.size() == 0 || (include_infinities && !a.is_finite());
|
|
1759
|
+
}),
|
|
1760
|
+
generators_.end());
|
|
1761
|
+
std::sort(generators_.begin(), generators_.end(), Is_strictly_smaller_lexicographically());
|
|
1762
|
+
}
|
|
1763
|
+
|
|
1764
|
+
if (generators_.empty()) {
|
|
1765
|
+
generators_ = {Generator(1, Co ? T_inf : T_m_inf)};
|
|
1766
|
+
}
|
|
1767
|
+
}
|
|
1768
|
+
|
|
1769
|
+
/**
|
|
1770
|
+
* @brief Sets each generator of the filtration value to the least common upper bound between it and the given value.
|
|
1771
|
+
*
|
|
1772
|
+
* More formally, it pushes the current generator to the cone \f$ \{ y \in \mathbb R^n : y \ge x \} \f$
|
|
1773
|
+
* originating in \f$ x \f$. The resulting value corresponds to the intersection of both
|
|
1774
|
+
* cones: \f$ \mathrm{this} = \min \{ y \in \mathbb R^n : y \ge this \} \cap \{ y \in \mathbb R^n : y \ge x \} \f$.
|
|
1775
|
+
*
|
|
1776
|
+
* @warning The operator accepts @ref Dynamic_multi_parameter_filtration with the same or different template
|
|
1777
|
+
* parameters as `GeneratorRange`. But if the number of generators is higher than 1, only the first generator will be
|
|
1778
|
+
* used for the operation.
|
|
1779
|
+
*
|
|
1780
|
+
* @tparam GeneratorRange Either a range of into `T` convertible elements with a begin(), end() and size() method,
|
|
1781
|
+
* or @ref Dynamic_multi_parameter_filtration<U,...> with `U` convertible into `T`.
|
|
1782
|
+
* @param x Range towards to push. Has to have as many elements than @ref num_parameters().
|
|
1783
|
+
* @param exclude_infinite_values If true, values at infinity or minus infinity are not affected.
|
|
1784
|
+
* @return true If the filtration value was actually modified.
|
|
1785
|
+
* @return false Otherwise.
|
|
1786
|
+
*/
|
|
1787
|
+
template <class GeneratorRange = std::initializer_list<value_type>,
|
|
1788
|
+
class = std::enable_if_t<RangeTraits<GeneratorRange>::has_begin> >
|
|
1789
|
+
bool push_to_least_common_upper_bound(const GeneratorRange &x, bool exclude_infinite_values = false)
|
|
1790
|
+
{
|
|
1791
|
+
bool modified = false;
|
|
1792
|
+
|
|
1793
|
+
for (Generator &g : generators_) {
|
|
1794
|
+
modified |= g.push_to_least_common_upper_bound(x, exclude_infinite_values);
|
|
1795
|
+
}
|
|
1796
|
+
|
|
1797
|
+
if (modified && num_generators() > 1) simplify();
|
|
1798
|
+
|
|
1799
|
+
return modified;
|
|
1800
|
+
}
|
|
1801
|
+
|
|
1802
|
+
/**
|
|
1803
|
+
* @brief Sets each generator of the filtration value to the greatest common lower bound between it and the given
|
|
1804
|
+
* value.
|
|
1805
|
+
*
|
|
1806
|
+
* More formally, it pulls the current generator to the cone \f$ \{ y \in \mathbb R^n : y \le x \} \f$
|
|
1807
|
+
* originating in \f$ x \f$. The resulting value corresponds to the intersection of both
|
|
1808
|
+
* cones: \f$ \mathrm{this} = \min \{ y \in \mathbb R^n : y \le this \} \cap \{ y \in \mathbb R^n : y \le x \} \f$.
|
|
1809
|
+
*
|
|
1810
|
+
* @warning The operator accepts @ref Dynamic_multi_parameter_filtration with the same or different template
|
|
1811
|
+
* parameters as `GeneratorRange`. But if the number of generators is higher than 1, only the first generator will be
|
|
1812
|
+
* used for the operation.
|
|
1813
|
+
*
|
|
1814
|
+
* @tparam GeneratorRange Either a range of into `T` convertible elements with a begin(), end() and size() method,
|
|
1815
|
+
* or @ref Dynamic_multi_parameter_filtration<U,...> with `U` convertible into `T`.
|
|
1816
|
+
* @param x Range towards to pull. Has to have as many elements than @ref num_parameters().
|
|
1817
|
+
* @param exclude_infinite_values If true, values at infinity or minus infinity are not affected.
|
|
1818
|
+
* @return true If the filtration value was actually modified.
|
|
1819
|
+
* @return false Otherwise.
|
|
1820
|
+
*/
|
|
1821
|
+
template <class GeneratorRange = std::initializer_list<value_type>,
|
|
1822
|
+
class = std::enable_if_t<RangeTraits<GeneratorRange>::has_begin> >
|
|
1823
|
+
bool pull_to_greatest_common_lower_bound(const GeneratorRange &x, bool exclude_infinite_values = false)
|
|
1824
|
+
{
|
|
1825
|
+
bool modified = false;
|
|
1826
|
+
|
|
1827
|
+
for (Generator &g : generators_) {
|
|
1828
|
+
modified |= g.pull_to_greatest_common_lower_bound(x, exclude_infinite_values);
|
|
1829
|
+
}
|
|
1830
|
+
|
|
1831
|
+
if (modified && num_generators() > 1) simplify();
|
|
1832
|
+
|
|
1833
|
+
return modified;
|
|
1834
|
+
}
|
|
1835
|
+
|
|
1836
|
+
/**
|
|
1837
|
+
* @brief Projects the filtration value into the given grid. If @p coordinate is false, the entries are set to
|
|
1838
|
+
* the nearest upper bound value with the same parameter in the grid. Otherwise, the entries are set to the indices
|
|
1839
|
+
* of those nearest upper bound values.
|
|
1840
|
+
* The grid has to be represented as a vector of ordered ranges of values convertible into `T`. An index
|
|
1841
|
+
* \f$ i \f$ of the vector corresponds to the same parameter as the index \f$ i \f$ in a generator of the filtration
|
|
1842
|
+
* value. The ranges correspond to the possible values of the parameters, ordered by increasing value, forming
|
|
1843
|
+
* therefore all together a 2D grid.
|
|
1844
|
+
*
|
|
1845
|
+
* @tparam OneDimArray A range of values convertible into `T` ordered by increasing value. Has to implement
|
|
1846
|
+
* a begin, end and operator[] method.
|
|
1847
|
+
* @param grid Vector of @p OneDimArray with size at least number of filtration parameters.
|
|
1848
|
+
* @param coordinate If true, the values are set to the coordinates of the projection in the grid. If false,
|
|
1849
|
+
* the values are set to the values at the coordinates of the projection.
|
|
1850
|
+
*/
|
|
1851
|
+
template <typename OneDimArray>
|
|
1852
|
+
void project_onto_grid(const std::vector<OneDimArray> &grid, bool coordinate = true)
|
|
1853
|
+
{
|
|
1854
|
+
GUDHI_CHECK(
|
|
1855
|
+
grid.size() >= num_parameters(),
|
|
1856
|
+
std::invalid_argument("The grid should not be smaller than the number of parameters in the filtration value."));
|
|
1857
|
+
|
|
1858
|
+
#ifdef GUDHI_USE_TBB
|
|
1859
|
+
tbb::parallel_for(size_type(0), num_generators(), [&](size_type i){
|
|
1860
|
+
generators_[i].project_onto_grid(grid, coordinate);
|
|
1861
|
+
});
|
|
1862
|
+
#else
|
|
1863
|
+
for (Generator &g : generators_) {
|
|
1864
|
+
g.project_onto_grid(grid, coordinate);
|
|
1865
|
+
}
|
|
1866
|
+
#endif
|
|
1867
|
+
|
|
1868
|
+
if (!coordinate && num_generators() > 1) simplify();
|
|
1869
|
+
}
|
|
1870
|
+
|
|
1871
|
+
// FONCTIONNALITIES
|
|
1872
|
+
|
|
1873
|
+
/**
|
|
1874
|
+
* @brief Returns a generator with the minimal values of all parameters in any generator of the given filtration
|
|
1875
|
+
* value. That is, the greatest lower bound of all generators.
|
|
1876
|
+
*/
|
|
1877
|
+
friend Dynamic_multi_parameter_filtration factorize_below(const Dynamic_multi_parameter_filtration &f)
|
|
1878
|
+
{
|
|
1879
|
+
if (f.num_generators() <= 1) return f;
|
|
1880
|
+
|
|
1881
|
+
bool isMinusInf = true;
|
|
1882
|
+
bool nan = true;
|
|
1883
|
+
Underlying_container result(1, Generator(f.num_parameters(), T_inf));
|
|
1884
|
+
for (size_type p = 0; p < f.num_parameters(); ++p) {
|
|
1885
|
+
for (size_type g = 0; g < f.num_generators(); ++g) {
|
|
1886
|
+
T val = f(g, p);
|
|
1887
|
+
if (!_is_nan(val)) {
|
|
1888
|
+
nan = false;
|
|
1889
|
+
result[0][p] = val < result[0][p] ? val : result[0][p];
|
|
1890
|
+
}
|
|
1891
|
+
}
|
|
1892
|
+
if (nan)
|
|
1893
|
+
result[0][p] = std::numeric_limits<T>::quiet_NaN();
|
|
1894
|
+
else
|
|
1895
|
+
nan = true;
|
|
1896
|
+
if (result[0][p] != T_m_inf) isMinusInf = false;
|
|
1897
|
+
}
|
|
1898
|
+
|
|
1899
|
+
if (isMinusInf) result = {Generator::minus_inf()};
|
|
1900
|
+
|
|
1901
|
+
return Dynamic_multi_parameter_filtration(std::move(result), f.num_parameters());
|
|
1902
|
+
}
|
|
1903
|
+
|
|
1904
|
+
/**
|
|
1905
|
+
* @brief Returns a generator with the maximal values of all parameters in any generator of the given filtration
|
|
1906
|
+
* value. That is, the least upper bound of all generators.
|
|
1907
|
+
*/
|
|
1908
|
+
friend Dynamic_multi_parameter_filtration factorize_above(const Dynamic_multi_parameter_filtration &f)
|
|
1909
|
+
{
|
|
1910
|
+
if (f.num_generators() <= 1) return f;
|
|
1911
|
+
|
|
1912
|
+
bool isPlusInf = true;
|
|
1913
|
+
bool nan = true;
|
|
1914
|
+
Underlying_container result(1, Generator(f.num_parameters(), T_m_inf));
|
|
1915
|
+
for (size_type p = 0; p < f.num_parameters(); ++p) {
|
|
1916
|
+
for (size_type g = 0; g < f.num_generators(); ++g) {
|
|
1917
|
+
T val = f(g, p);
|
|
1918
|
+
if (!_is_nan(val)) {
|
|
1919
|
+
nan = false;
|
|
1920
|
+
result[0][p] = val > result[0][p] ? val : result[0][p];
|
|
1921
|
+
}
|
|
1922
|
+
}
|
|
1923
|
+
if (nan)
|
|
1924
|
+
result[0][p] = std::numeric_limits<T>::quiet_NaN();
|
|
1925
|
+
else
|
|
1926
|
+
nan = true;
|
|
1927
|
+
if (result[0][p] != T_inf) isPlusInf = false;
|
|
1928
|
+
}
|
|
1929
|
+
|
|
1930
|
+
if (isPlusInf) result = {Generator::inf()};
|
|
1931
|
+
|
|
1932
|
+
return Dynamic_multi_parameter_filtration(std::move(result), f.num_parameters());
|
|
1933
|
+
}
|
|
1934
|
+
|
|
1935
|
+
/**
|
|
1936
|
+
* @brief Computes the smallest (resp. the greatest if `Co` is true) scalar product of the all generators with the
|
|
1937
|
+
* given vector.
|
|
1938
|
+
*
|
|
1939
|
+
* @tparam U Arithmetic type of the result. Default value: `T`.
|
|
1940
|
+
* @param f Filtration value.
|
|
1941
|
+
* @param x Vector of coefficients.
|
|
1942
|
+
* @return Scalar product of @p f with @p x.
|
|
1943
|
+
*/
|
|
1944
|
+
template <typename U = T>
|
|
1945
|
+
friend U compute_linear_projection(const Dynamic_multi_parameter_filtration &f, const std::vector<U> &x)
|
|
1946
|
+
{
|
|
1947
|
+
if (f.num_generators() == 1) return compute_linear_projection(f.generators_[0], x);
|
|
1948
|
+
|
|
1949
|
+
if constexpr (Co) {
|
|
1950
|
+
U projection = std::numeric_limits<U>::lowest();
|
|
1951
|
+
for (const Generator &g : f.generators_) {
|
|
1952
|
+
// Order in the max important to spread possible NaNs
|
|
1953
|
+
projection = std::max(compute_linear_projection(g, x), projection);
|
|
1954
|
+
}
|
|
1955
|
+
return projection;
|
|
1956
|
+
} else {
|
|
1957
|
+
U projection = std::numeric_limits<U>::max();
|
|
1958
|
+
for (const Generator &g : f.generators_) {
|
|
1959
|
+
// Order in the min important to spread possible NaNs
|
|
1960
|
+
projection = std::min(compute_linear_projection(g, x), projection);
|
|
1961
|
+
}
|
|
1962
|
+
return projection;
|
|
1963
|
+
}
|
|
1964
|
+
}
|
|
1965
|
+
|
|
1966
|
+
/**
|
|
1967
|
+
* @brief Computes the euclidean distance from the first parameter to the second parameter as the minimum of
|
|
1968
|
+
* all Euclidean distances between a generator of @p f and a generator of @p other.
|
|
1969
|
+
*
|
|
1970
|
+
* @param f Source filtration value.
|
|
1971
|
+
* @param other Target filtration value.
|
|
1972
|
+
* @return Euclidean distance between @p f and @p other.
|
|
1973
|
+
*/
|
|
1974
|
+
template <typename U = T>
|
|
1975
|
+
friend U compute_euclidean_distance_to(const Dynamic_multi_parameter_filtration &f,
|
|
1976
|
+
const Dynamic_multi_parameter_filtration &other)
|
|
1977
|
+
{
|
|
1978
|
+
GUDHI_CHECK(f.num_parameters() == other.num_parameters(),
|
|
1979
|
+
std::invalid_argument("We cannot compute the distance between two points of different dimensions."));
|
|
1980
|
+
|
|
1981
|
+
// TODO: verify if this really makes a differences in the 1-critical case, otherwise just keep the general case
|
|
1982
|
+
if constexpr (Ensure1Criticality) {
|
|
1983
|
+
return compute_euclidean_distance_to(f.generators_[0], other.generators_[0]);
|
|
1984
|
+
} else {
|
|
1985
|
+
U res = std::numeric_limits<U>::max();
|
|
1986
|
+
for (const Generator &g1 : f.generators_) {
|
|
1987
|
+
for (const Generator &g2 : other.generators_) {
|
|
1988
|
+
// Order in the min important to spread possible NaNs
|
|
1989
|
+
res = std::min(compute_euclidean_distance_to(g1, g2), res);
|
|
1990
|
+
}
|
|
1991
|
+
}
|
|
1992
|
+
return res;
|
|
1993
|
+
}
|
|
1994
|
+
}
|
|
1995
|
+
|
|
1996
|
+
/**
|
|
1997
|
+
* @brief Computes the norm of the given filtration value.
|
|
1998
|
+
*
|
|
1999
|
+
* The filtration value is seen as a \f$ num_generators x num_parameters \f$ matrix and a standard Frobenius norm
|
|
2000
|
+
* is computed from it: the square root of the sum of the squares of all elements in the matrix.
|
|
2001
|
+
*
|
|
2002
|
+
* @param f Filtration value.
|
|
2003
|
+
* @return The norm of @p f.
|
|
2004
|
+
*/
|
|
2005
|
+
template <typename U = T>
|
|
2006
|
+
friend U compute_norm(const Dynamic_multi_parameter_filtration &f)
|
|
2007
|
+
{
|
|
2008
|
+
// Frobenius norm with matrix g x p based on Euclidean norm
|
|
2009
|
+
U out = 0;
|
|
2010
|
+
for (const Generator &g : f.generators_) {
|
|
2011
|
+
out += compute_squares(g);
|
|
2012
|
+
}
|
|
2013
|
+
if constexpr (std::is_integral_v<U>) {
|
|
2014
|
+
// to avoid Windows issue that don't know how to cast integers for cmath methods
|
|
2015
|
+
return std::sqrt(static_cast<double>(out));
|
|
2016
|
+
} else {
|
|
2017
|
+
return std::sqrt(out);
|
|
2018
|
+
}
|
|
2019
|
+
}
|
|
2020
|
+
|
|
2021
|
+
/**
|
|
2022
|
+
* @brief Computes the coordinates in the given grid, corresponding to the nearest upper bounds of the entries
|
|
2023
|
+
* in the given filtration value.
|
|
2024
|
+
* The grid has to be represented as a vector of vectors of ordered values convertible into `OutValue`. An index
|
|
2025
|
+
* \f$ i \f$ of the vector corresponds to the same parameter as the index \f$ i \f$ in a generator of the filtration
|
|
2026
|
+
* value. The ranges correspond to the possible values of the parameters, ordered by increasing value, forming
|
|
2027
|
+
* therefore all together a 2D grid.
|
|
2028
|
+
*
|
|
2029
|
+
* @tparam OutValue Signed arithmetic type. Default value: std::int32_t.
|
|
2030
|
+
* @tparam U Type which is convertible into `OutValue`.
|
|
2031
|
+
* @param f Filtration value to project.
|
|
2032
|
+
* @param grid Vector of vectors to project into.
|
|
2033
|
+
* @return Filtration value \f$ out \f$ whose entry correspond to the indices of the projected values. That is,
|
|
2034
|
+
* the projection of \f$ f(g,p) \f$ is \f$ grid[p][out(g,p)] \f$.
|
|
2035
|
+
*/
|
|
2036
|
+
template <typename OutValue = std::int32_t, typename U = T>
|
|
2037
|
+
friend Dynamic_multi_parameter_filtration<OutValue, Co, Ensure1Criticality> compute_coordinates_in_grid(
|
|
2038
|
+
Dynamic_multi_parameter_filtration f,
|
|
2039
|
+
const std::vector<std::vector<U> > &grid)
|
|
2040
|
+
{
|
|
2041
|
+
// TODO: by replicating the code of "project_onto_grid", this could be done with just one copy
|
|
2042
|
+
// instead of two. But it is not clear if it is really worth it, i.e., how much the change in type is really
|
|
2043
|
+
// necessary in the use cases. To see later.
|
|
2044
|
+
f.project_onto_grid(grid);
|
|
2045
|
+
if constexpr (std::is_same_v<OutValue, T>) {
|
|
2046
|
+
return f;
|
|
2047
|
+
} else {
|
|
2048
|
+
return f.as_type<OutValue>();
|
|
2049
|
+
}
|
|
2050
|
+
}
|
|
2051
|
+
|
|
2052
|
+
/**
|
|
2053
|
+
* @brief Computes the values in the given grid corresponding to the coordinates given by the given filtration
|
|
2054
|
+
* value. That is, if \f$ out \f$ is the result, \f$ out(g,p) = grid[p][f(g,p)] \f$. Assumes therefore, that the
|
|
2055
|
+
* values stored in the filtration value corresponds to indices existing in the given grid.
|
|
2056
|
+
*
|
|
2057
|
+
* @tparam U Signed arithmetic type.
|
|
2058
|
+
* @param f Filtration value storing coordinates compatible with `grid`.
|
|
2059
|
+
* @param grid Vector of vector.
|
|
2060
|
+
* @return Filtration value \f$ out \f$ whose entry correspond to \f$ out(g,p) = grid[p][f(g,p)] \f$.
|
|
2061
|
+
*/
|
|
2062
|
+
template <typename U>
|
|
2063
|
+
friend Dynamic_multi_parameter_filtration<U, Co, Ensure1Criticality> evaluate_coordinates_in_grid(
|
|
2064
|
+
const Dynamic_multi_parameter_filtration &f,
|
|
2065
|
+
const std::vector<std::vector<U> > &grid)
|
|
2066
|
+
{
|
|
2067
|
+
GUDHI_CHECK(grid.size() >= f.num_parameters(),
|
|
2068
|
+
std::invalid_argument(
|
|
2069
|
+
"The size of the grid should correspond to the number of parameters in the filtration value."));
|
|
2070
|
+
|
|
2071
|
+
std::vector<Multi_parameter_generator<U> > outVec(f.num_generators());
|
|
2072
|
+
|
|
2073
|
+
size_type i = 0;
|
|
2074
|
+
for (const Generator &g : f.generators_) {
|
|
2075
|
+
outVec[i] = evaluate_coordinates_in_grid(g, grid);
|
|
2076
|
+
++i;
|
|
2077
|
+
}
|
|
2078
|
+
|
|
2079
|
+
Dynamic_multi_parameter_filtration<U, Co, Ensure1Criticality> out(std::move(outVec), f.num_parameters());
|
|
2080
|
+
if constexpr (!Ensure1Criticality)
|
|
2081
|
+
if (out.num_generators() > 1) out.simplify();
|
|
2082
|
+
return out;
|
|
2083
|
+
}
|
|
2084
|
+
|
|
2085
|
+
// UTILITIES
|
|
2086
|
+
|
|
2087
|
+
/**
|
|
2088
|
+
* @brief Outstream operator.
|
|
2089
|
+
*/
|
|
2090
|
+
friend std::ostream &operator<<(std::ostream &stream, const Dynamic_multi_parameter_filtration &f)
|
|
2091
|
+
{
|
|
2092
|
+
const size_type num_gen = f.num_generators();
|
|
2093
|
+
const size_type num_param = f.num_parameters();
|
|
2094
|
+
|
|
2095
|
+
stream << "( k = " << num_gen << " ) ( p = " << num_param << " ) [ ";
|
|
2096
|
+
for (size_type g = 0; g < num_gen; ++g) {
|
|
2097
|
+
stream << f.generators_[g];
|
|
2098
|
+
if (g < num_gen - 1) stream << "; ";
|
|
2099
|
+
}
|
|
2100
|
+
stream << " ]";
|
|
2101
|
+
|
|
2102
|
+
return stream;
|
|
2103
|
+
}
|
|
2104
|
+
|
|
2105
|
+
/**
|
|
2106
|
+
* @brief Instream operator.
|
|
2107
|
+
*/
|
|
2108
|
+
friend std::istream &operator>>(std::istream &stream, Dynamic_multi_parameter_filtration &f)
|
|
2109
|
+
{
|
|
2110
|
+
size_type num_gen;
|
|
2111
|
+
size_type num_param;
|
|
2112
|
+
char delimiter;
|
|
2113
|
+
stream >> delimiter; // (
|
|
2114
|
+
stream >> delimiter; // k
|
|
2115
|
+
stream >> delimiter; // =
|
|
2116
|
+
stream >> num_gen;
|
|
2117
|
+
if (!stream.good())
|
|
2118
|
+
throw std::invalid_argument("Invalid incoming stream format for Dynamic_multi_parameter_filtration (num_gen).");
|
|
2119
|
+
f.generators_.resize(num_gen);
|
|
2120
|
+
stream >> delimiter; // )
|
|
2121
|
+
stream >> delimiter; // (
|
|
2122
|
+
stream >> delimiter; // p
|
|
2123
|
+
stream >> delimiter; // =
|
|
2124
|
+
stream >> num_param;
|
|
2125
|
+
if (!stream.good())
|
|
2126
|
+
throw std::invalid_argument("Invalid incoming stream format for Dynamic_multi_parameter_filtration (num_param).");
|
|
2127
|
+
f.number_of_parameters_ = num_param;
|
|
2128
|
+
stream >> delimiter; // )
|
|
2129
|
+
stream >> delimiter; // [
|
|
2130
|
+
if (delimiter != '[')
|
|
2131
|
+
throw std::invalid_argument("Invalid incoming stream format for Dynamic_multi_parameter_filtration ([).");
|
|
2132
|
+
if (num_gen == 0) return stream;
|
|
2133
|
+
for (size_type i = 0; i < num_gen; ++i) {
|
|
2134
|
+
stream >> f.generators_[i];
|
|
2135
|
+
stream >> delimiter; // ; or last ]
|
|
2136
|
+
}
|
|
2137
|
+
if (delimiter != ']')
|
|
2138
|
+
throw std::invalid_argument("Invalid incoming stream format for Dynamic_multi_parameter_filtration (]).");
|
|
2139
|
+
|
|
2140
|
+
return stream;
|
|
2141
|
+
}
|
|
2142
|
+
|
|
2143
|
+
/**
|
|
2144
|
+
* @brief Returns true if and only if the given filtration value is at plus infinity.
|
|
2145
|
+
*/
|
|
2146
|
+
friend bool is_positive_infinity(const Dynamic_multi_parameter_filtration &f)
|
|
2147
|
+
{
|
|
2148
|
+
return f.is_plus_inf();
|
|
2149
|
+
}
|
|
2150
|
+
|
|
2151
|
+
/**
|
|
2152
|
+
* @brief Adds the generators of the second argument to the first argument. If `Ensure1Criticality` is true,
|
|
2153
|
+
* the method assumes that the two filtration values are comparable, that is, that the result of the union is also
|
|
2154
|
+
* 1-critical. A check for this is only done in Debug Mode, as it is costly.
|
|
2155
|
+
*
|
|
2156
|
+
* @param f1 Filtration value to modify.
|
|
2157
|
+
* @param f2 Filtration value to merge with the first one. Should have the same number of parameters than the other.
|
|
2158
|
+
* @return true If the first argument was actually modified.
|
|
2159
|
+
* @return false Otherwise.
|
|
2160
|
+
*/
|
|
2161
|
+
friend bool unify_lifetimes(Dynamic_multi_parameter_filtration &f1, const Dynamic_multi_parameter_filtration &f2)
|
|
2162
|
+
{
|
|
2163
|
+
GUDHI_CHECK(f1.num_parameters() == f2.num_parameters() || !f1.is_finite() || !f2.is_finite(),
|
|
2164
|
+
"Cannot unify two filtration values with different number of parameters.");
|
|
2165
|
+
|
|
2166
|
+
// TODO: verify if this really makes a differences in the 1-critical case, otherwise just keep the general case
|
|
2167
|
+
// if general case is kept: add (num_gen == 1) test to throw if unification is not 1-critical anymore.
|
|
2168
|
+
if constexpr (Ensure1Criticality) {
|
|
2169
|
+
// WARNING: costly check
|
|
2170
|
+
GUDHI_CHECK(f1 <= f2 || f2 <= f1,
|
|
2171
|
+
"When 1-critical only, two non-comparable filtration values cannot be unified.");
|
|
2172
|
+
|
|
2173
|
+
if constexpr (Co) {
|
|
2174
|
+
return f1.push_to_least_common_upper_bound(f2);
|
|
2175
|
+
} else {
|
|
2176
|
+
return f1.pull_to_greatest_common_lower_bound(f2);
|
|
2177
|
+
}
|
|
2178
|
+
} else {
|
|
2179
|
+
bool modified = false;
|
|
2180
|
+
for (const Generator &g : f2.generators_) {
|
|
2181
|
+
modified |= f1.add_generator(g);
|
|
2182
|
+
}
|
|
2183
|
+
return modified;
|
|
2184
|
+
}
|
|
2185
|
+
}
|
|
2186
|
+
|
|
2187
|
+
/**
|
|
2188
|
+
* @brief Stores in the first argument the origins of the cones in the intersection of the positive
|
|
2189
|
+
* (negative if `Co` is true) cones generated by the two arguments.
|
|
2190
|
+
*
|
|
2191
|
+
* @param f1 First set of cones which will be modified.
|
|
2192
|
+
* @param f2 Second set of cones. Should have the same number of parameters than the first one.
|
|
2193
|
+
* @return true If the first argument was actually modified.
|
|
2194
|
+
* @return false Otherwise.
|
|
2195
|
+
*/
|
|
2196
|
+
friend bool intersect_lifetimes(Dynamic_multi_parameter_filtration &f1, const Dynamic_multi_parameter_filtration &f2)
|
|
2197
|
+
{
|
|
2198
|
+
if (f1.is_nan() || f2.is_nan()) return false;
|
|
2199
|
+
|
|
2200
|
+
if constexpr (Co) {
|
|
2201
|
+
if (f1.is_plus_inf()) {
|
|
2202
|
+
if (f2.is_plus_inf()) return false;
|
|
2203
|
+
f1 = f2;
|
|
2204
|
+
return true;
|
|
2205
|
+
}
|
|
2206
|
+
if (f1.is_minus_inf()) {
|
|
2207
|
+
return false;
|
|
2208
|
+
}
|
|
2209
|
+
} else {
|
|
2210
|
+
if (f1.is_minus_inf()) {
|
|
2211
|
+
if (f2.is_minus_inf()) return false;
|
|
2212
|
+
f1 = f2;
|
|
2213
|
+
return true;
|
|
2214
|
+
}
|
|
2215
|
+
if (f1.is_plus_inf()) {
|
|
2216
|
+
return false;
|
|
2217
|
+
}
|
|
2218
|
+
}
|
|
2219
|
+
|
|
2220
|
+
GUDHI_CHECK(f1.num_parameters() == f2.num_parameters(),
|
|
2221
|
+
"Cannot intersect two filtration values with different number of parameters.");
|
|
2222
|
+
|
|
2223
|
+
if constexpr (Ensure1Criticality) {
|
|
2224
|
+
if constexpr (Co) {
|
|
2225
|
+
return f1.pull_to_greatest_common_lower_bound(f2);
|
|
2226
|
+
} else {
|
|
2227
|
+
return f1.push_to_least_common_upper_bound(f2);
|
|
2228
|
+
}
|
|
2229
|
+
} else {
|
|
2230
|
+
const size_type num_param = f1.num_parameters();
|
|
2231
|
+
Dynamic_multi_parameter_filtration res = Co ? minus_inf(num_param) : inf(num_param);
|
|
2232
|
+
std::vector<T> newGen(num_param);
|
|
2233
|
+
// TODO: see if the order can be used to avoid g1 * g2 add_generator and
|
|
2234
|
+
// perhaps even to replace add_generator by add_guaranteed_generator
|
|
2235
|
+
for (size_type g1 = 0; g1 < f1.num_generators(); ++g1) {
|
|
2236
|
+
for (size_type g2 = 0; g2 < f2.num_generators(); ++g2) {
|
|
2237
|
+
GUDHI_CHECK(f1.generators_[g1].size() == num_param, "Filtration value f1 is not minimal.");
|
|
2238
|
+
GUDHI_CHECK(f2.generators_[g2].size() == num_param, "Filtration value f2 is not minimal.");
|
|
2239
|
+
for (size_type p = 0; p < num_param; ++p) {
|
|
2240
|
+
if constexpr (Co) {
|
|
2241
|
+
newGen[p] = std::min(f1(g1, p), f2(g2, p));
|
|
2242
|
+
} else {
|
|
2243
|
+
newGen[p] = std::max(f1(g1, p), f2(g2, p));
|
|
2244
|
+
}
|
|
2245
|
+
}
|
|
2246
|
+
res.add_generator(newGen);
|
|
2247
|
+
}
|
|
2248
|
+
}
|
|
2249
|
+
swap(f1, res);
|
|
2250
|
+
|
|
2251
|
+
return f1 != res;
|
|
2252
|
+
}
|
|
2253
|
+
}
|
|
2254
|
+
|
|
2255
|
+
/**
|
|
2256
|
+
* @brief Serialize given value into the buffer at given pointer.
|
|
2257
|
+
*
|
|
2258
|
+
* @param value Value to serialize.
|
|
2259
|
+
* @param start Pointer to the start of the space in the buffer where to store the serialization.
|
|
2260
|
+
* @return End position of the serialization in the buffer.
|
|
2261
|
+
*/
|
|
2262
|
+
friend char *serialize_value_to_char_buffer(const Dynamic_multi_parameter_filtration &value, char *start)
|
|
2263
|
+
{
|
|
2264
|
+
const std::size_t nberOfGenerators = value.generators_.size();
|
|
2265
|
+
const std::size_t type_size = sizeof(std::size_t);
|
|
2266
|
+
memcpy(start, &value.number_of_parameters_, type_size);
|
|
2267
|
+
memcpy(start + type_size, &nberOfGenerators, type_size);
|
|
2268
|
+
char *curr = start + type_size + type_size;
|
|
2269
|
+
for (const Generator &g : value) {
|
|
2270
|
+
curr = serialize_value_to_char_buffer(g, curr);
|
|
2271
|
+
}
|
|
2272
|
+
return curr;
|
|
2273
|
+
}
|
|
2274
|
+
|
|
2275
|
+
/**
|
|
2276
|
+
* @brief Deserialize the value from a buffer at given pointer and stores it in given value.
|
|
2277
|
+
*
|
|
2278
|
+
* @param value Value to fill with the deserialized filtration value.
|
|
2279
|
+
* @param start Pointer to the start of the space in the buffer where the serialization is stored.
|
|
2280
|
+
* @return End position of the serialization in the buffer.
|
|
2281
|
+
*/
|
|
2282
|
+
friend const char *deserialize_value_from_char_buffer(Dynamic_multi_parameter_filtration &value, const char *start)
|
|
2283
|
+
{
|
|
2284
|
+
const std::size_t type_size = sizeof(std::size_t);
|
|
2285
|
+
std::size_t nberOfGenerators;
|
|
2286
|
+
memcpy(&value.number_of_parameters_, start, type_size);
|
|
2287
|
+
memcpy(&nberOfGenerators, start + type_size, type_size);
|
|
2288
|
+
value.generators_.resize(nberOfGenerators);
|
|
2289
|
+
const char *curr = start + type_size + type_size;
|
|
2290
|
+
for (Generator &g : value) {
|
|
2291
|
+
curr = deserialize_value_from_char_buffer(g, curr);
|
|
2292
|
+
}
|
|
2293
|
+
return curr;
|
|
2294
|
+
}
|
|
2295
|
+
|
|
2296
|
+
/**
|
|
2297
|
+
* @brief Returns the serialization size of the given filtration value.
|
|
2298
|
+
*/
|
|
2299
|
+
friend std::size_t get_serialization_size_of(const Dynamic_multi_parameter_filtration &value)
|
|
2300
|
+
{
|
|
2301
|
+
std::size_t genSizes = sizeof(std::size_t) * 2;
|
|
2302
|
+
for (const Generator &g : value) {
|
|
2303
|
+
genSizes += get_serialization_size_of(g);
|
|
2304
|
+
}
|
|
2305
|
+
return genSizes;
|
|
2306
|
+
}
|
|
2307
|
+
|
|
2308
|
+
/**
|
|
2309
|
+
* @brief Plus infinity value of an entry of the filtration value.
|
|
2310
|
+
*/
|
|
2311
|
+
constexpr static const T T_inf = Generator::T_inf;
|
|
2312
|
+
|
|
2313
|
+
/**
|
|
2314
|
+
* @brief Minus infinity value of an entry of the filtration value.
|
|
2315
|
+
*/
|
|
2316
|
+
constexpr static const T T_m_inf = Generator::T_m_inf;
|
|
2317
|
+
|
|
2318
|
+
private:
|
|
2319
|
+
size_type number_of_parameters_; /**< Number of parameters. */
|
|
2320
|
+
Underlying_container generators_; /**< Container of the filtration value elements. */
|
|
2321
|
+
|
|
2322
|
+
constexpr static bool _is_nan(T val)
|
|
2323
|
+
{
|
|
2324
|
+
if constexpr (std::is_integral_v<T>) {
|
|
2325
|
+
// to avoid Windows issue which don't know how to cast integers for cmath methods
|
|
2326
|
+
return false;
|
|
2327
|
+
} else {
|
|
2328
|
+
return std::isnan(val);
|
|
2329
|
+
}
|
|
2330
|
+
}
|
|
2331
|
+
|
|
2332
|
+
/**
|
|
2333
|
+
* @brief Verifies if @p b is strictly contained in the positive cone originating in `a`.
|
|
2334
|
+
*/
|
|
2335
|
+
static bool _strictly_contains(const Generator &a, const Generator &b)
|
|
2336
|
+
{
|
|
2337
|
+
if constexpr (Co)
|
|
2338
|
+
return a > b;
|
|
2339
|
+
else {
|
|
2340
|
+
return a < b;
|
|
2341
|
+
}
|
|
2342
|
+
}
|
|
2343
|
+
|
|
2344
|
+
/**
|
|
2345
|
+
* @brief Verifies if @p b is contained in the positive cone originating in `a`.
|
|
2346
|
+
*/
|
|
2347
|
+
static bool _contains(const Generator &a, const Generator &b)
|
|
2348
|
+
{
|
|
2349
|
+
if constexpr (Co)
|
|
2350
|
+
return a >= b;
|
|
2351
|
+
else {
|
|
2352
|
+
return a <= b;
|
|
2353
|
+
}
|
|
2354
|
+
}
|
|
2355
|
+
|
|
2356
|
+
/**
|
|
2357
|
+
* @brief Verifies if the first element of @p b strictly dominates the first element of `a`.
|
|
2358
|
+
*/
|
|
2359
|
+
static bool _first_strictly_dominates(const Generator &a, const Generator &b)
|
|
2360
|
+
{
|
|
2361
|
+
if constexpr (Co) {
|
|
2362
|
+
return a.size() != 0 && b.size() != 0 && a[0] < b[0];
|
|
2363
|
+
} else {
|
|
2364
|
+
return a.size() != 0 && b.size() != 0 && a[0] > b[0];
|
|
2365
|
+
}
|
|
2366
|
+
}
|
|
2367
|
+
|
|
2368
|
+
/**
|
|
2369
|
+
* @brief Verifies if the first element of @p b dominates the first element of `a`.
|
|
2370
|
+
*/
|
|
2371
|
+
static bool _first_dominates(const Generator &a, const Generator &b)
|
|
2372
|
+
{
|
|
2373
|
+
if constexpr (Co) {
|
|
2374
|
+
return a.size() != 0 && b.size() != 0 && a[0] <= b[0];
|
|
2375
|
+
} else {
|
|
2376
|
+
return a.size() != 0 && b.size() != 0 && a[0] >= b[0];
|
|
2377
|
+
}
|
|
2378
|
+
}
|
|
2379
|
+
|
|
2380
|
+
enum class Rel : std::uint8_t { EQUAL, DOMINATES, IS_DOMINATED, NONE };
|
|
2381
|
+
|
|
2382
|
+
template <class Iterator>
|
|
2383
|
+
static Rel _get_domination_relation(const Generator &a, Iterator itB)
|
|
2384
|
+
{
|
|
2385
|
+
if (a.is_nan()) return Rel::NONE;
|
|
2386
|
+
|
|
2387
|
+
bool equal = true;
|
|
2388
|
+
bool allGreater = true;
|
|
2389
|
+
bool allSmaller = true;
|
|
2390
|
+
bool allNaNA = true;
|
|
2391
|
+
bool allNaNB = true;
|
|
2392
|
+
for (unsigned int i = 0; i < a.size(); ++i) {
|
|
2393
|
+
if (a[i] < *itB) {
|
|
2394
|
+
if (!allSmaller) return Rel::NONE;
|
|
2395
|
+
equal = false;
|
|
2396
|
+
allGreater = false;
|
|
2397
|
+
} else if (a[i] > *itB) {
|
|
2398
|
+
if (!allGreater) return Rel::NONE;
|
|
2399
|
+
equal = false;
|
|
2400
|
+
allSmaller = false;
|
|
2401
|
+
}
|
|
2402
|
+
if (!_is_nan(a[i])) allNaNA = false;
|
|
2403
|
+
if (!_is_nan(*itB)) allNaNB = false;
|
|
2404
|
+
++itB;
|
|
2405
|
+
}
|
|
2406
|
+
if (allNaNA || allNaNB) return Rel::IS_DOMINATED;
|
|
2407
|
+
if (equal) return Rel::EQUAL;
|
|
2408
|
+
|
|
2409
|
+
if constexpr (Co) {
|
|
2410
|
+
if (allSmaller) return Rel::DOMINATES;
|
|
2411
|
+
return Rel::IS_DOMINATED;
|
|
2412
|
+
} else {
|
|
2413
|
+
if (allGreater) return Rel::DOMINATES;
|
|
2414
|
+
return Rel::IS_DOMINATED;
|
|
2415
|
+
}
|
|
2416
|
+
}
|
|
2417
|
+
|
|
2418
|
+
/**
|
|
2419
|
+
* @brief Verifies how x can be added as a new generator with respect to an already existing generator, represented
|
|
2420
|
+
* by `generators_[curr]`. If x is dominated by or is equal to `generators_[curr]`, it cannot be added. If it
|
|
2421
|
+
* dominates `generators_[curr]`, it has to replace `generators_[curr]`. If there is no relation between both,
|
|
2422
|
+
* `generators_[curr]` has no influence on the addition of x.
|
|
2423
|
+
*
|
|
2424
|
+
* Assumes between 'curr' and 'end' everything is simplified:
|
|
2425
|
+
* no nan values and if there is an inf/-inf, then 'end - curr == 1'.
|
|
2426
|
+
*/
|
|
2427
|
+
template <class Iterator>
|
|
2428
|
+
bool _generator_can_be_added(Iterator x, size_type curr, size_type &end)
|
|
2429
|
+
{
|
|
2430
|
+
// assumes that everything between curr and end is simplified
|
|
2431
|
+
// so, only generators_[curr] can be at inf or -inf.
|
|
2432
|
+
if constexpr (Co) {
|
|
2433
|
+
if (generators_[curr].is_plus_inf()) {
|
|
2434
|
+
return false;
|
|
2435
|
+
}
|
|
2436
|
+
if (generators_[curr].is_minus_inf()) {
|
|
2437
|
+
end = curr;
|
|
2438
|
+
return true;
|
|
2439
|
+
}
|
|
2440
|
+
} else {
|
|
2441
|
+
if (generators_[curr].is_minus_inf()) {
|
|
2442
|
+
return false;
|
|
2443
|
+
}
|
|
2444
|
+
if (generators_[curr].is_plus_inf()) {
|
|
2445
|
+
end = curr;
|
|
2446
|
+
return true;
|
|
2447
|
+
}
|
|
2448
|
+
}
|
|
2449
|
+
|
|
2450
|
+
while (curr != end) {
|
|
2451
|
+
Rel res = _get_domination_relation(generators_[curr], x);
|
|
2452
|
+
if (res == Rel::IS_DOMINATED || res == Rel::EQUAL) return false; // x dominates or is equal
|
|
2453
|
+
if (res == Rel::DOMINATES) { // x is dominated
|
|
2454
|
+
--end;
|
|
2455
|
+
swap(generators_[curr], generators_[end]);
|
|
2456
|
+
} else { // no relation
|
|
2457
|
+
++curr;
|
|
2458
|
+
}
|
|
2459
|
+
}
|
|
2460
|
+
return true;
|
|
2461
|
+
}
|
|
2462
|
+
|
|
2463
|
+
struct Is_strictly_smaller_lexicographically {
|
|
2464
|
+
// assumes both generators have the same length if not infinite/nan.
|
|
2465
|
+
bool operator()(const Generator &g1, const Generator &g2)
|
|
2466
|
+
{
|
|
2467
|
+
// orders such that -inf < 'finite values' < inf < NaN.
|
|
2468
|
+
|
|
2469
|
+
if (g1.is_nan() || g2.is_nan()) return !g1.is_nan();
|
|
2470
|
+
if (g1.is_plus_inf()) return false;
|
|
2471
|
+
if (g2.is_plus_inf()) return true;
|
|
2472
|
+
if (g2.is_minus_inf()) return false;
|
|
2473
|
+
if (g1.is_minus_inf()) return true;
|
|
2474
|
+
|
|
2475
|
+
// g1 and g2 have to be finite and of the same size
|
|
2476
|
+
for (std::size_t i = 0; i < g1.size(); ++i) {
|
|
2477
|
+
if (g1[i] != g2[i]) return g1[i] < g2[i];
|
|
2478
|
+
}
|
|
2479
|
+
return false;
|
|
2480
|
+
}
|
|
2481
|
+
};
|
|
2482
|
+
};
|
|
2483
|
+
|
|
2484
|
+
} // namespace Gudhi::multi_filtration
|
|
2485
|
+
|
|
2486
|
+
namespace std {
|
|
2487
|
+
|
|
2488
|
+
template <typename T, bool Co, bool Ensure1Criticality>
|
|
2489
|
+
class numeric_limits<Gudhi::multi_filtration::Dynamic_multi_parameter_filtration<T, Co, Ensure1Criticality> >
|
|
2490
|
+
{
|
|
2491
|
+
public:
|
|
2492
|
+
using Filtration_value = Gudhi::multi_filtration::Dynamic_multi_parameter_filtration<T, Co, Ensure1Criticality>;
|
|
2493
|
+
|
|
2494
|
+
static constexpr bool has_infinity = true;
|
|
2495
|
+
static constexpr bool has_quiet_NaN = true;
|
|
2496
|
+
|
|
2497
|
+
static constexpr Filtration_value infinity(std::size_t p = 1) noexcept { return Filtration_value::inf(p); };
|
|
2498
|
+
|
|
2499
|
+
// non-standard
|
|
2500
|
+
static constexpr Filtration_value minus_infinity(std::size_t p = 1) noexcept
|
|
2501
|
+
{
|
|
2502
|
+
return Filtration_value::minus_inf(p);
|
|
2503
|
+
};
|
|
2504
|
+
|
|
2505
|
+
static constexpr Filtration_value max() noexcept(false)
|
|
2506
|
+
{
|
|
2507
|
+
throw std::logic_error(
|
|
2508
|
+
"The max value cannot be represented with no finite numbers of parameters."
|
|
2509
|
+
"Use `max(number_of_parameters)` instead");
|
|
2510
|
+
};
|
|
2511
|
+
|
|
2512
|
+
static constexpr Filtration_value max(std::size_t p) noexcept
|
|
2513
|
+
{
|
|
2514
|
+
return Filtration_value(p, std::numeric_limits<T>::max());
|
|
2515
|
+
};
|
|
2516
|
+
|
|
2517
|
+
static constexpr Filtration_value lowest(std::size_t p = 1) noexcept { return Filtration_value::minus_inf(p); };
|
|
2518
|
+
|
|
2519
|
+
static constexpr Filtration_value quiet_NaN(std::size_t p = 1) noexcept { return Filtration_value::nan(p); };
|
|
2520
|
+
};
|
|
2521
|
+
|
|
2522
|
+
} // namespace std
|
|
2523
|
+
|
|
2524
|
+
#endif // MF_DYNAMIC_MULTI_PARAMETER_FILTRATION_H_
|