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,2307 @@
|
|
|
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 Degree_rips_bifiltration.h
|
|
13
|
+
* @author Hannah Schreiber, David Loiseaux
|
|
14
|
+
* @brief Contains the @ref Gudhi::multi_filtration::Degree_rips_bifiltration class.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
#ifndef MF_DEGREE_RIPS_BIFILTRATION_H_
|
|
18
|
+
#define MF_DEGREE_RIPS_BIFILTRATION_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
|
|
24
|
+
#include <cstring> //memcpy
|
|
25
|
+
#include <iterator> //std::distance
|
|
26
|
+
#include <ostream> //std::ostream
|
|
27
|
+
#include <limits> //std::numerical_limits
|
|
28
|
+
#include <stdexcept> //std::logic_error
|
|
29
|
+
#include <type_traits> //std::is_arithmetic
|
|
30
|
+
#include <utility> //std::swap, std::move
|
|
31
|
+
#include <vector>
|
|
32
|
+
#include <initializer_list>
|
|
33
|
+
|
|
34
|
+
#include <gudhi/Debug_utils.h>
|
|
35
|
+
#include <gudhi/simple_mdspan.h>
|
|
36
|
+
#include <gudhi/Multi_filtration/multi_filtration_utils.h>
|
|
37
|
+
#include <gudhi/Simplex_tree/filtration_value_utils.h>
|
|
38
|
+
#include <gudhi/Multi_parameter_filtration.h>
|
|
39
|
+
#include <gudhi/Dynamic_multi_parameter_filtration.h>
|
|
40
|
+
#include <oneapi/tbb/concurrent_vector.h>
|
|
41
|
+
|
|
42
|
+
namespace Gudhi::multi_filtration {
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* @class Degree_rips_bifiltration Degree_rips_bifiltration.h gudhi/Degree_rips_bifiltration.h
|
|
46
|
+
* @ingroup multi_filtration
|
|
47
|
+
*
|
|
48
|
+
* @brief Class encoding the different generators, i.e., apparition times, of a \f$ k \f$-critical
|
|
49
|
+
* \f$\mathbb R^2\f$-filtration value in a degree-Rips filtration. That is, a \f$ k \f$-critical filtration value is
|
|
50
|
+
* always of the form: \f$ [(v_0,0), (v_1,1), (v_2,2), ..., (v_{k-1},k-1)] \f$, where all pairs \f$ (v_i,i) \f$
|
|
51
|
+
* represent a generator with two parameters: the radius and the degree. More precisely: let \f$ d \f$ be the max
|
|
52
|
+
* degree of a vertex in the complex. A vertex will be \f$ k \f$-critical if it has degree \f$ d - k + 1 \f$ and an
|
|
53
|
+
* edge is \f$ k \f$-critical if one of its end vertices is \f$ k \f$-critical and the other one \f$ j \f$-critical,
|
|
54
|
+
* \f$ j \geq k \f$. The first parameter is the more standard radius parameter of a Rips filtration.
|
|
55
|
+
* Note that the set of generators does not have to be minimal (contrary to @ref Multi_parameter_filtration e.g.),
|
|
56
|
+
* neither ordered lexicographically.
|
|
57
|
+
* Implements the concept @ref FiltrationValue of the @ref Gudhi::Simplex_tree and the concept
|
|
58
|
+
* @ref Gudhi::multi_persistence::MultiFiltrationValue.
|
|
59
|
+
*
|
|
60
|
+
* @details Overloads `std::numeric_limits` such that:
|
|
61
|
+
* - `std::numeric_limits<Degree_rips_bifiltration>::has_infinity` returns `true` if and only if `Co` is false,
|
|
62
|
+
* - `std::numeric_limits<Degree_rips_bifiltration>::has_quiet_NaN` returns `true`,
|
|
63
|
+
* - `std::numeric_limits<Degree_rips_bifiltration>::infinity()` returns
|
|
64
|
+
* @ref Degree_rips_bifiltration::inf() "",
|
|
65
|
+
* - `std::numeric_limits<Degree_rips_bifiltration>::minus_infinity()` returns
|
|
66
|
+
* @ref Degree_rips_bifiltration::minus_inf() "",
|
|
67
|
+
* - `std::numeric_limits<Degree_rips_bifiltration>::max(num_param)` throws if `Co` is true and otherwise returns a
|
|
68
|
+
* @ref Degree_rips_bifiltration with 1 generators with first parameter 0 and second parameter
|
|
69
|
+
*`std::numeric_limits<T>::max()`,
|
|
70
|
+
* - `std::numeric_limits<Degree_rips_bifiltration>::quiet_NaN()` returns @ref Degree_rips_bifiltration::nan().
|
|
71
|
+
*
|
|
72
|
+
* @tparam T Arithmetic type of an entry of the second parameter of a filtration value. Has to be **signed** and
|
|
73
|
+
* to implement `std::isnan(T)`, `std::numeric_limits<T>::has_quiet_NaN`, `std::numeric_limits<T>::quiet_NaN()`,
|
|
74
|
+
* `std::numeric_limits<T>::has_infinity`, `std::numeric_limits<T>::infinity()` and `std::numeric_limits<T>::max()`.
|
|
75
|
+
* If `std::numeric_limits<T>::has_infinity` returns `false`, a call to `std::numeric_limits<T>::infinity()`
|
|
76
|
+
* can simply throw. Examples are the native types `double`, `float` and `int`.
|
|
77
|
+
* @tparam Co If `true`, reverses the poset order, i.e., the order \f$ \le \f$ in \f$ \mathbb R^n \f$ becomes
|
|
78
|
+
* \f$ \ge \f$. That is, the positive cones representing a lifetime become all negative instead.
|
|
79
|
+
* @tparam Ensure1Criticality If `true`, the methods ensure that the filtration value is always 1-critical by throwing
|
|
80
|
+
* or refusing to compile if a modification increases the number of generators.
|
|
81
|
+
*/
|
|
82
|
+
template <typename T, bool Co = false, bool Ensure1Criticality = false>
|
|
83
|
+
class Degree_rips_bifiltration
|
|
84
|
+
{
|
|
85
|
+
public:
|
|
86
|
+
using Underlying_container = std::vector<T>; /**< Underlying container for values. */
|
|
87
|
+
|
|
88
|
+
// CONSTRUCTORS
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* @brief Default constructor. Builds filtration value with one generator `(val, 0)`.
|
|
92
|
+
* If Co is false, `val` is -inf, if Co is true, `val` is at +inf.
|
|
93
|
+
*
|
|
94
|
+
* @param number_of_parameters Ignored, the number of parameters is always 2. For interface purposes only.
|
|
95
|
+
*/
|
|
96
|
+
Degree_rips_bifiltration([[maybe_unused]] int number_of_parameters = 2) : generators_(1, _get_default_value()) {}
|
|
97
|
+
|
|
98
|
+
explicit Degree_rips_bifiltration(Gudhi::simplex_tree::empty_filtration_value_t /*e*/) : generators_(0) {}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* @brief Builds a filtration value with one generator `(value, 0)`.
|
|
102
|
+
*
|
|
103
|
+
* @param number_of_parameters Ignored, the number of parameters is always 2. For interface purposes only.
|
|
104
|
+
* @param value Initialization value for the second parameter.
|
|
105
|
+
*/
|
|
106
|
+
Degree_rips_bifiltration([[maybe_unused]] int number_of_parameters, T value) : generators_(1, value) {}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* @brief Builds filtration value with one generator `(val, i)`, where `val` and `i` are the two first elements
|
|
110
|
+
* of the given range. Note that `i` has to be 0.
|
|
111
|
+
*
|
|
112
|
+
* @tparam ValueRange Range of types convertible to `T`. Should have a begin() method.
|
|
113
|
+
* @param range Values of the generator. The range has to have at least two elements.
|
|
114
|
+
*/
|
|
115
|
+
template <class ValueRange = std::initializer_list<T>, class = std::enable_if_t<RangeTraits<ValueRange>::has_begin> >
|
|
116
|
+
Degree_rips_bifiltration(const ValueRange &range) : generators_(1, *(range.begin()))
|
|
117
|
+
{
|
|
118
|
+
GUDHI_CHECK(*(range.begin() + 1) == 0, std::invalid_argument("Second value of the range has to be 0"));
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* @brief Builds filtration value with one generator `(val, i)`, where `val` and `i` are the two first elements
|
|
123
|
+
* of the given range. Note that `i` has to be 0.
|
|
124
|
+
*
|
|
125
|
+
* @tparam Iterator Iterator type that has to satisfy the requirements of standard LegacyInputIterator and
|
|
126
|
+
* dereferenced elements have to be convertible to `T`.
|
|
127
|
+
* @param it_begin Iterator pointing to the start of the range.
|
|
128
|
+
* @param it_end Iterator pointing to the end of the range.
|
|
129
|
+
*/
|
|
130
|
+
template <class Iterator, class = std::enable_if_t<!std::is_arithmetic_v<Iterator> > >
|
|
131
|
+
Degree_rips_bifiltration(Iterator it_begin, [[maybe_unused]] Iterator it_end) : generators_(1, *it_begin)
|
|
132
|
+
{
|
|
133
|
+
GUDHI_CHECK(*(it_begin + 1) == 0, std::invalid_argument("Second value of the range has to be 0"));
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* @brief Builds a filtration value with given values from the given range. The two first elements of the range have
|
|
138
|
+
* to correspond to the first generator, the two next elements to the second generator and so on... So the length of
|
|
139
|
+
* the range has to be a multiple of 2 and the number of generators will be \f$ k = length / 2 \f$. Note that starting
|
|
140
|
+
* from the second element, every second element has to represent the continuous sequence from 0 to \f$ k \f$.
|
|
141
|
+
* The range is represented by two iterators.
|
|
142
|
+
*
|
|
143
|
+
* @tparam Iterator Iterator type that has to satisfy the requirements of standard LegacyForwardIterator and
|
|
144
|
+
* dereferenced elements have to be convertible to `T`.
|
|
145
|
+
* @param it_begin Iterator pointing to the start of the range.
|
|
146
|
+
* @param it_end Iterator pointing to the end of the range.
|
|
147
|
+
* @param number_of_parameters Ignored, the number of parameters is always 2. For interface purposes only.
|
|
148
|
+
*/
|
|
149
|
+
template <class Iterator, class = std::enable_if_t<!std::is_arithmetic_v<Iterator> > >
|
|
150
|
+
Degree_rips_bifiltration(Iterator it_begin, Iterator it_end, [[maybe_unused]] int number_of_parameters)
|
|
151
|
+
: generators_()
|
|
152
|
+
{
|
|
153
|
+
size_type num_gen = std::distance(it_begin, it_end) / 2;
|
|
154
|
+
if constexpr (Ensure1Criticality) {
|
|
155
|
+
if (num_gen > 1) throw std::logic_error("Multiparameter filtration value is not 1-critical.");
|
|
156
|
+
}
|
|
157
|
+
generators_.resize(num_gen);
|
|
158
|
+
Iterator it = it_begin;
|
|
159
|
+
for (size_type i = 0; i < num_gen; ++i) {
|
|
160
|
+
generators_[i] = *it;
|
|
161
|
+
++it;
|
|
162
|
+
GUDHI_CHECK(
|
|
163
|
+
static_cast<size_type>(*it) == i,
|
|
164
|
+
std::invalid_argument(
|
|
165
|
+
"Every second value of the range has to correspond to a contiguous sequence of integers starting at 0."));
|
|
166
|
+
++it;
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* @brief Builds filtration value with given values from the given range. The range only represent the values of the
|
|
172
|
+
* first parameter. So `(generators[0], 0)` is the first generator, `(generators[1], 1)` is the second generator and
|
|
173
|
+
* so on... The range is represented by @ref Degree_rips_bifiltration::Underlying_container "" and copied into the
|
|
174
|
+
* underlying container of the class.
|
|
175
|
+
*
|
|
176
|
+
* @param generators Values for the second parameter.
|
|
177
|
+
* @param number_of_parameters Ignored, the number of parameters is always 2. For interface purposes only.
|
|
178
|
+
*/
|
|
179
|
+
Degree_rips_bifiltration(const Underlying_container &generators, [[maybe_unused]] int number_of_parameters)
|
|
180
|
+
: generators_(generators)
|
|
181
|
+
{
|
|
182
|
+
if constexpr (Ensure1Criticality) {
|
|
183
|
+
if (generators_.size() > 1) throw std::logic_error("Multiparameter filtration value is not 1-critical.");
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* @brief Builds filtration value with given values from the given range. The range only represent the values of the
|
|
189
|
+
* first parameter. So `(generators[0], 0)` is the first generator, `(generators[1], 1)` is the second generator and
|
|
190
|
+
* so on... The range is represented by @ref Degree_rips_bifiltration::Underlying_container "" and **moved** into
|
|
191
|
+
* the underlying container of the class.
|
|
192
|
+
*
|
|
193
|
+
* @param generators Values to move.
|
|
194
|
+
* @param number_of_parameters Ignored, the number of parameters is always 2. For interface purposes only.
|
|
195
|
+
*/
|
|
196
|
+
Degree_rips_bifiltration(Underlying_container &&generators, [[maybe_unused]] int number_of_parameters)
|
|
197
|
+
: generators_(std::move(generators))
|
|
198
|
+
{
|
|
199
|
+
if constexpr (Ensure1Criticality) {
|
|
200
|
+
if (generators_.size() > 1) throw std::logic_error("Multiparameter filtration value is not 1-critical.");
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
// cannot use = default as it triggers "dummy_g_ may be used uninitialized" compiler warning for nothing
|
|
205
|
+
/**
|
|
206
|
+
* @brief Copy constructor.
|
|
207
|
+
*/
|
|
208
|
+
Degree_rips_bifiltration(const Degree_rips_bifiltration &other) : generators_(other.generators_) {}
|
|
209
|
+
|
|
210
|
+
// cannot use = default as it triggers "dummy_g_ may be used uninitialized" compiler warning for nothing
|
|
211
|
+
/**
|
|
212
|
+
* @brief Move constructor.
|
|
213
|
+
*/
|
|
214
|
+
Degree_rips_bifiltration(Degree_rips_bifiltration &&other) noexcept : generators_(std::move(other.generators_)) {}
|
|
215
|
+
|
|
216
|
+
/**
|
|
217
|
+
* @brief Copy constructor.
|
|
218
|
+
*
|
|
219
|
+
* @tparam U Type convertible into `T`.
|
|
220
|
+
*/
|
|
221
|
+
template <typename U, bool OtherCo, bool OtherEnsure1Criticality>
|
|
222
|
+
Degree_rips_bifiltration(const Degree_rips_bifiltration<U, OtherCo, OtherEnsure1Criticality> &other)
|
|
223
|
+
: generators_(other.begin(), other.end())
|
|
224
|
+
{
|
|
225
|
+
if constexpr (Ensure1Criticality && !OtherEnsure1Criticality) {
|
|
226
|
+
if (generators_.size() > 1) throw std::logic_error("Multiparameter filtration value is not 1-critical.");
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
~Degree_rips_bifiltration() = default;
|
|
231
|
+
|
|
232
|
+
// cannot use = default as it triggers "dummy_g_ may be used uninitialized" compiler warning for nothing
|
|
233
|
+
/**
|
|
234
|
+
* @brief Assign operator.
|
|
235
|
+
*/
|
|
236
|
+
Degree_rips_bifiltration &operator=(const Degree_rips_bifiltration &other) {
|
|
237
|
+
generators_ = other.generators_;
|
|
238
|
+
return *this;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
// cannot use = default as it triggers "dummy_g_ may be used uninitialized" compiler warning for nothing
|
|
242
|
+
/**
|
|
243
|
+
* @brief Move assign operator.
|
|
244
|
+
*/
|
|
245
|
+
Degree_rips_bifiltration &operator=(Degree_rips_bifiltration &&other) noexcept {
|
|
246
|
+
generators_ = std::move(other.generators_);
|
|
247
|
+
return *this;
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
/**
|
|
251
|
+
* @brief Assign operator.
|
|
252
|
+
*
|
|
253
|
+
* @tparam U Type convertible into `T`.
|
|
254
|
+
*/
|
|
255
|
+
template <typename U, bool OtherCo, bool OtherEnsure1Criticality>
|
|
256
|
+
Degree_rips_bifiltration &operator=(const Degree_rips_bifiltration<U, OtherCo, OtherEnsure1Criticality> &other)
|
|
257
|
+
{
|
|
258
|
+
if constexpr (Ensure1Criticality && !OtherEnsure1Criticality) {
|
|
259
|
+
if (other.num_generators() > 1) throw std::logic_error("Multiparameter filtration value is not 1-critical.");
|
|
260
|
+
}
|
|
261
|
+
generators_ = Underlying_container(other.begin(), other.end());
|
|
262
|
+
return *this;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
/**
|
|
266
|
+
* @brief Swap operator.
|
|
267
|
+
*/
|
|
268
|
+
friend void swap(Degree_rips_bifiltration &f1, Degree_rips_bifiltration &f2) noexcept
|
|
269
|
+
{
|
|
270
|
+
f1.generators_.swap(f2.generators_);
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
// VECTOR-LIKE
|
|
274
|
+
|
|
275
|
+
using value_type = T; /**< Value type. */
|
|
276
|
+
using size_type = typename Underlying_container::size_type; /**< Size type. */
|
|
277
|
+
using difference_type = typename Underlying_container::difference_type; /**< Difference type. */
|
|
278
|
+
using reference = value_type &; /**< Reference type. */
|
|
279
|
+
using const_reference = const value_type &; /**< Const reference type. */
|
|
280
|
+
using pointer = typename Underlying_container::pointer; /**< Pointer type. */
|
|
281
|
+
using const_pointer = typename Underlying_container::const_pointer; /**< Const pointer type. */
|
|
282
|
+
using iterator = typename Underlying_container::iterator; /**< Iterator type. */
|
|
283
|
+
using const_iterator = typename Underlying_container::const_iterator; /**< Const iterator type. */
|
|
284
|
+
using reverse_iterator = typename Underlying_container::reverse_iterator; /**< Reverse iterator type. */
|
|
285
|
+
using const_reverse_iterator = typename Underlying_container::const_reverse_iterator; /**< Const reverse iterator. */
|
|
286
|
+
|
|
287
|
+
/**
|
|
288
|
+
* @brief Returns reference to value of parameter `p` of generator `g`.
|
|
289
|
+
*
|
|
290
|
+
* The reference returned when `p` is 1 can be modified but will have no impact on the value of the second parameter
|
|
291
|
+
* represented on the class and is shared by the second parameter of all generators. If there is a need to store this
|
|
292
|
+
* value, a copy should be stored instead.
|
|
293
|
+
*/
|
|
294
|
+
reference operator()(size_type g, size_type p)
|
|
295
|
+
{
|
|
296
|
+
GUDHI_CHECK(g < generators_.size() && p < 2, std::out_of_range("Out of bound index."));
|
|
297
|
+
if (p == 1) {
|
|
298
|
+
dummy_g_ = g;
|
|
299
|
+
return dummy_g_;
|
|
300
|
+
}
|
|
301
|
+
return generators_[g];
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
/**
|
|
305
|
+
* @brief Returns const reference to value of parameter `p` of generator `g`.
|
|
306
|
+
*/
|
|
307
|
+
const_reference operator()(size_type g, size_type p) const
|
|
308
|
+
{
|
|
309
|
+
GUDHI_CHECK(g < generators_.size() && p < 2, std::out_of_range("Out of bound index."));
|
|
310
|
+
if (p == 1) {
|
|
311
|
+
dummy_g_ = g;
|
|
312
|
+
return dummy_g_;
|
|
313
|
+
}
|
|
314
|
+
return generators_[g];
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
/**
|
|
318
|
+
* @brief Let \f$ g \f$ be the first value in `indices` and \f$ p \f$ the second value.
|
|
319
|
+
* Returns reference to value of parameter \f$ p \f$ of generator \f$ g \f$.
|
|
320
|
+
*
|
|
321
|
+
* The reference returned when `p` is 1 can be modified but will have no impact on the value of the second parameter
|
|
322
|
+
* represented on the class and is shared by the second parameter of all generators. If there is a need to store this
|
|
323
|
+
* value, a copy should be stored instead.
|
|
324
|
+
*
|
|
325
|
+
* @tparam IndexRange Range with a begin() and size() method.
|
|
326
|
+
* @param indices Range with at least two elements. The first element should correspond to the generator number and
|
|
327
|
+
* the second element to the parameter number.
|
|
328
|
+
*/
|
|
329
|
+
template <class IndexRange = std::initializer_list<size_type>,
|
|
330
|
+
class = std::enable_if_t<RangeTraits<IndexRange>::has_begin> >
|
|
331
|
+
reference operator[](const IndexRange &indices)
|
|
332
|
+
{
|
|
333
|
+
GUDHI_CHECK(indices.size() == 2,
|
|
334
|
+
std::invalid_argument(
|
|
335
|
+
"Exactly 2 indices allowed only: first the generator number, second the parameter number."));
|
|
336
|
+
auto it = indices.begin();
|
|
337
|
+
size_type g = *it;
|
|
338
|
+
return this->operator()(g, *(++it));
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
/**
|
|
342
|
+
* @brief Let \f$ g \f$ be the first value in `indices` and \f$ p \f$ the second value.
|
|
343
|
+
* Returns reference to value of parameter \f$ p \f$ of generator \f$ g \f$.
|
|
344
|
+
*
|
|
345
|
+
* @tparam IndexRange Range with a begin() and size() method.
|
|
346
|
+
* @param indices Range with at least two elements. The first element should correspond to the generator number and
|
|
347
|
+
* the second element to the parameter number.
|
|
348
|
+
*/
|
|
349
|
+
template <class IndexRange = std::initializer_list<size_type>,
|
|
350
|
+
class = std::enable_if_t<RangeTraits<IndexRange>::has_begin> >
|
|
351
|
+
const_reference operator[](const IndexRange &indices) const
|
|
352
|
+
{
|
|
353
|
+
GUDHI_CHECK(indices.size() == 2,
|
|
354
|
+
std::invalid_argument(
|
|
355
|
+
"Exactly 2 indices allowed only: first the generator number, second the parameter number."));
|
|
356
|
+
auto it = indices.begin();
|
|
357
|
+
size_type g = *it;
|
|
358
|
+
return this->operator()(g, *(++it));
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
/**
|
|
362
|
+
* @brief Returns an iterator pointing the begining of the underlying container. The element `val_i` at index `i`
|
|
363
|
+
* corresponds to the first parameter of the generator `(val_i, i)`.
|
|
364
|
+
*/
|
|
365
|
+
iterator begin() noexcept { return generators_.begin(); }
|
|
366
|
+
|
|
367
|
+
/**
|
|
368
|
+
* @brief Returns an iterator pointing the begining of the underlying container. The element `val_i` at index `i`
|
|
369
|
+
* corresponds to the first parameter of the generator `(val_i, i)`.
|
|
370
|
+
*/
|
|
371
|
+
const_iterator begin() const noexcept { return generators_.begin(); }
|
|
372
|
+
|
|
373
|
+
/**
|
|
374
|
+
* @brief Returns an iterator pointing the begining of the underlying container. The element `val_i` at index `i`
|
|
375
|
+
* corresponds to the first parameter of the generator `(val_i, i)`.
|
|
376
|
+
*/
|
|
377
|
+
const_iterator cbegin() const noexcept { return generators_.cbegin(); }
|
|
378
|
+
|
|
379
|
+
/**
|
|
380
|
+
* @brief Returns an iterator pointing the end of the underlying container.
|
|
381
|
+
*/
|
|
382
|
+
iterator end() noexcept { return generators_.end(); }
|
|
383
|
+
|
|
384
|
+
/**
|
|
385
|
+
* @brief Returns an iterator pointing the end of the underlying container.
|
|
386
|
+
*/
|
|
387
|
+
const_iterator end() const noexcept { return generators_.end(); }
|
|
388
|
+
|
|
389
|
+
/**
|
|
390
|
+
* @brief Returns an iterator pointing the end of the underlying container.
|
|
391
|
+
*/
|
|
392
|
+
const_iterator cend() const noexcept { return generators_.cend(); }
|
|
393
|
+
|
|
394
|
+
/**
|
|
395
|
+
* @brief Returns a reverse iterator pointing to the first element from the back of the underlying container.
|
|
396
|
+
* The element `val_i` at index `i` corresponds to the first parameter of the generator `(val_i, i)`.
|
|
397
|
+
*/
|
|
398
|
+
reverse_iterator rbegin() noexcept { return generators_.rbegin(); }
|
|
399
|
+
|
|
400
|
+
/**
|
|
401
|
+
* @brief Returns a reverse iterator pointing to the first element from the back of the underlying container.
|
|
402
|
+
* The element `val_i` at index `i` corresponds to the first parameter of the generator `(val_i, i)`.
|
|
403
|
+
*/
|
|
404
|
+
const_reverse_iterator rbegin() const noexcept { return generators_.rbegin(); }
|
|
405
|
+
|
|
406
|
+
/**
|
|
407
|
+
* @brief Returns a reverse iterator pointing to the first element from the back of the underlying container.
|
|
408
|
+
* The element `val_i` at index `i` corresponds to the first parameter of the generator `(val_i, i)`.
|
|
409
|
+
*/
|
|
410
|
+
const_reverse_iterator crbegin() const noexcept { return generators_.crbegin(); }
|
|
411
|
+
|
|
412
|
+
/**
|
|
413
|
+
* @brief Returns a reverse iterator pointing to the end of the reversed underlying container.
|
|
414
|
+
*/
|
|
415
|
+
reverse_iterator rend() noexcept { return generators_.rend(); }
|
|
416
|
+
|
|
417
|
+
/**
|
|
418
|
+
* @brief Returns a reverse iterator pointing to the end of the reversed underlying container.
|
|
419
|
+
*/
|
|
420
|
+
const_reverse_iterator rend() const noexcept { return generators_.rend(); }
|
|
421
|
+
|
|
422
|
+
/**
|
|
423
|
+
* @brief Returns a reverse iterator pointing to the end of the reversed underlying container.
|
|
424
|
+
*/
|
|
425
|
+
const_reverse_iterator crend() const noexcept { return generators_.crend(); }
|
|
426
|
+
|
|
427
|
+
/**
|
|
428
|
+
* @brief Returns the size of the underlying container. Corresponds exactly to @ref num_generators(), but enables
|
|
429
|
+
* to use the class as a classic range with a `begin`, `end` and `size` method.
|
|
430
|
+
*/
|
|
431
|
+
size_type size() const noexcept { return generators_.size(); }
|
|
432
|
+
|
|
433
|
+
/**
|
|
434
|
+
* @brief Reserves space for the given number of generators in the underlying container. Does nothing if
|
|
435
|
+
* `Ensure1Criticality` is true.
|
|
436
|
+
*/
|
|
437
|
+
void reserve([[maybe_unused]] size_type number_of_generators)
|
|
438
|
+
{
|
|
439
|
+
if constexpr (Ensure1Criticality) {
|
|
440
|
+
return;
|
|
441
|
+
} else {
|
|
442
|
+
generators_.reserve(number_of_generators);
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
// CONVERTERS
|
|
447
|
+
|
|
448
|
+
// like numpy
|
|
449
|
+
/**
|
|
450
|
+
* @brief Returns a copy with entries casted into the type given as template parameter.
|
|
451
|
+
*
|
|
452
|
+
* @tparam U New type for the entries.
|
|
453
|
+
* @tparam OCo New value for `Co`. Default value: `Co`.
|
|
454
|
+
* @tparam OEns New value for `Ensure1Criticality`. Note that if `OEns` is set to true and the value is not
|
|
455
|
+
* 1-critical, the method will throw. Default value: `Ensure1Criticality`.
|
|
456
|
+
* @return Copy with new entry type.
|
|
457
|
+
*/
|
|
458
|
+
template <typename U, bool OCo = Co, bool OEns = Ensure1Criticality>
|
|
459
|
+
Degree_rips_bifiltration<U, OCo, OEns> as_type() const
|
|
460
|
+
{
|
|
461
|
+
std::vector<U> out(generators_.begin(), generators_.end());
|
|
462
|
+
return Degree_rips_bifiltration<U, OCo, OEns>(std::move(out), num_parameters());
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
/**
|
|
466
|
+
* @brief Converts the filtration value to @ref Multi_parameter_filtration without any set simplification.
|
|
467
|
+
* @warning The filtration value is converted one to one and is not simplified to a minimal set of generators or
|
|
468
|
+
* ordered by lexicographical order, that undefines the behaviour of some methods of the class.
|
|
469
|
+
* Use @ref as_type(const Degree_rips_bifiltration&) instead if needed.
|
|
470
|
+
*/
|
|
471
|
+
Multi_parameter_filtration<T, Co, Ensure1Criticality> convert_to_non_simplified_multi_parameter_filtration() const
|
|
472
|
+
{
|
|
473
|
+
std::vector<T> out(generators_.size() * 2);
|
|
474
|
+
size_type i = 0;
|
|
475
|
+
for (size_type g = 0; g < generators_.size(); ++g) {
|
|
476
|
+
out[i] = generators_[g];
|
|
477
|
+
out[i + 1] = g;
|
|
478
|
+
i += 2;
|
|
479
|
+
}
|
|
480
|
+
return Multi_parameter_filtration<T, Co, Ensure1Criticality>(std::move(out), 2);
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
/**
|
|
484
|
+
* @brief Converts the filtration value to @ref Dynamic_multi_parameter_filtration without any set simplification.
|
|
485
|
+
* @warning The filtration value is converted one to one and is not simplified to a minimal set of generators or
|
|
486
|
+
* ordered by lexicographical order, that undefines the behaviour of some methods of the class.
|
|
487
|
+
* Use @ref as_type(const Degree_rips_bifiltration&) instead if needed.
|
|
488
|
+
*/
|
|
489
|
+
Dynamic_multi_parameter_filtration<T, Co, Ensure1Criticality>
|
|
490
|
+
convert_to_non_simplified_dynamic_multi_parameter_filtration() const
|
|
491
|
+
{
|
|
492
|
+
std::vector<Multi_parameter_generator<T> > out;
|
|
493
|
+
out.reserve(generators_.size());
|
|
494
|
+
for (size_type g = 0; g < generators_.size(); ++g) {
|
|
495
|
+
std::vector<T> v = {generators_[g], static_cast<T>(g)};
|
|
496
|
+
out.emplace_back(std::move(v));
|
|
497
|
+
}
|
|
498
|
+
return Dynamic_multi_parameter_filtration<T, Co, Ensure1Criticality>(std::move(out), 2);
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
// ACCESS
|
|
502
|
+
|
|
503
|
+
/**
|
|
504
|
+
* @brief Returns the number of parameters in the filtration value.
|
|
505
|
+
*/
|
|
506
|
+
static constexpr size_type num_parameters() { return 2; }
|
|
507
|
+
|
|
508
|
+
/**
|
|
509
|
+
* @brief Returns the number of generators in the filtration value, i.e. the criticality of the element.
|
|
510
|
+
*/
|
|
511
|
+
size_type num_generators() const { return generators_.size(); }
|
|
512
|
+
|
|
513
|
+
/**
|
|
514
|
+
* @brief Returns the total number of values in the filtration value, that is,
|
|
515
|
+
* @ref num_parameters() * @ref num_generators().
|
|
516
|
+
*/
|
|
517
|
+
size_type num_entries() const { return generators_.size() * 2; }
|
|
518
|
+
|
|
519
|
+
/**
|
|
520
|
+
* @brief Returns a filtration value for which @ref is_plus_inf() returns `true`. Throws if `Co` is true.
|
|
521
|
+
*/
|
|
522
|
+
static Degree_rips_bifiltration inf(int number_of_parameters = 2)
|
|
523
|
+
{
|
|
524
|
+
if constexpr (Co) {
|
|
525
|
+
throw std::logic_error("No biggest value possible for Co-filtrations yet.");
|
|
526
|
+
} else {
|
|
527
|
+
return Degree_rips_bifiltration(number_of_parameters, T_inf);
|
|
528
|
+
}
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
/**
|
|
532
|
+
* @brief Returns a filtration value for which @ref is_minus_inf() returns `true`.
|
|
533
|
+
*/
|
|
534
|
+
static Degree_rips_bifiltration minus_inf(int number_of_parameters = 2)
|
|
535
|
+
{
|
|
536
|
+
return Degree_rips_bifiltration(number_of_parameters, T_m_inf);
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
/**
|
|
540
|
+
* @brief Returns a filtration value for which @ref is_nan() returns `true`.
|
|
541
|
+
*/
|
|
542
|
+
static constexpr Degree_rips_bifiltration nan([[maybe_unused]] int number_of_parameters = 2)
|
|
543
|
+
{
|
|
544
|
+
return Degree_rips_bifiltration(Gudhi::simplex_tree::empty_filtration_value_t());
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
// DESCRIPTORS
|
|
548
|
+
|
|
549
|
+
/**
|
|
550
|
+
* @brief Returns value of `Ensure1Criticality`.
|
|
551
|
+
*/
|
|
552
|
+
static constexpr bool ensures_1_criticality() { return Ensure1Criticality; }
|
|
553
|
+
|
|
554
|
+
/**
|
|
555
|
+
* @brief Returns value of `Co`.
|
|
556
|
+
*/
|
|
557
|
+
static constexpr bool has_negative_cones() { return Co; }
|
|
558
|
+
|
|
559
|
+
/**
|
|
560
|
+
* @brief Returns `true` if and only if the filtration value is considered as plus infinity.
|
|
561
|
+
*/
|
|
562
|
+
constexpr bool is_plus_inf() const
|
|
563
|
+
{
|
|
564
|
+
if constexpr (Co) {
|
|
565
|
+
return false;
|
|
566
|
+
} else {
|
|
567
|
+
if (generators_.empty()) return false;
|
|
568
|
+
for (const T &v : generators_) {
|
|
569
|
+
if (v != T_inf) return false;
|
|
570
|
+
}
|
|
571
|
+
return true;
|
|
572
|
+
}
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
/**
|
|
576
|
+
* @brief Returns `true` if and only if the filtration value is considered as minus infinity.
|
|
577
|
+
*/
|
|
578
|
+
constexpr bool is_minus_inf() const
|
|
579
|
+
{
|
|
580
|
+
if constexpr (Co) {
|
|
581
|
+
return generators_.size() == 1 && generators_[0] == T_m_inf;
|
|
582
|
+
} else {
|
|
583
|
+
return !generators_.empty() && generators_[0] == T_m_inf;
|
|
584
|
+
}
|
|
585
|
+
}
|
|
586
|
+
|
|
587
|
+
/**
|
|
588
|
+
* @brief Returns `true` if and only if the filtration value is considered as NaN.
|
|
589
|
+
*/
|
|
590
|
+
constexpr bool is_nan() const { return generators_.empty(); }
|
|
591
|
+
|
|
592
|
+
/**
|
|
593
|
+
* @brief Returns `true` if and only if the filtration value is non-empty and is not considered as plus infinity,
|
|
594
|
+
* minus infinity or NaN.
|
|
595
|
+
*/
|
|
596
|
+
bool is_finite() const
|
|
597
|
+
{
|
|
598
|
+
if constexpr (Co) {
|
|
599
|
+
return !generators_.empty() && (generators_.size() != 1 || generators_[0] != T_m_inf);
|
|
600
|
+
} else {
|
|
601
|
+
if (generators_.empty() || generators_[0] == T_m_inf) return false;
|
|
602
|
+
for (const T &v : generators_) {
|
|
603
|
+
if (v != T_inf) return true;
|
|
604
|
+
}
|
|
605
|
+
return false;
|
|
606
|
+
}
|
|
607
|
+
}
|
|
608
|
+
|
|
609
|
+
// COMPARAISON OPERATORS
|
|
610
|
+
|
|
611
|
+
/**
|
|
612
|
+
* @brief Returns `true` if and only if the first argument is lexicographically strictly less than the second
|
|
613
|
+
* argument. The "words" considered for the lexicographical order are all the generators concatenated together
|
|
614
|
+
* in order of generator index and then in order of parameter index. Different from @ref operator< "", this order
|
|
615
|
+
* is total.
|
|
616
|
+
*
|
|
617
|
+
* @tparam inverse If true, the parameter index and generator index order is inverted.
|
|
618
|
+
*/
|
|
619
|
+
template <bool inverse = false>
|
|
620
|
+
friend bool is_strict_less_than_lexicographically(const Degree_rips_bifiltration &a,
|
|
621
|
+
const Degree_rips_bifiltration &b)
|
|
622
|
+
{
|
|
623
|
+
if (&a == &b) return false;
|
|
624
|
+
if (a.is_nan()) return false;
|
|
625
|
+
if (b.is_nan()) return true;
|
|
626
|
+
|
|
627
|
+
if constexpr (inverse) {
|
|
628
|
+
if (a.num_generators() != b.num_generators()) {
|
|
629
|
+
if (a.num_generators() == 0) return true;
|
|
630
|
+
if (b.num_generators() == 0) return false;
|
|
631
|
+
if (a.generators_[0] < b.generators_[0]) return true;
|
|
632
|
+
if (b.generators_[0] < a.generators_[0]) return false;
|
|
633
|
+
return a.num_generators() < b.num_generators();
|
|
634
|
+
}
|
|
635
|
+
}
|
|
636
|
+
|
|
637
|
+
for (std::size_t i = 0U; i < std::min(a.num_generators(), b.num_generators()); ++i) {
|
|
638
|
+
if constexpr (inverse) i = std::min(a.num_generators(), b.num_generators()) - 1 - i;
|
|
639
|
+
if (_is_nan(a.generators_[i]) && !_is_nan(b.generators_[i])) return false;
|
|
640
|
+
if (_is_nan(b.generators_[i])) return true;
|
|
641
|
+
if (a.generators_[i] < b.generators_[i]) return true;
|
|
642
|
+
if (b.generators_[i] < a.generators_[i]) return false;
|
|
643
|
+
if constexpr (inverse) i = std::min(a.num_generators(), b.num_generators()) - 1 - i;
|
|
644
|
+
}
|
|
645
|
+
return a.num_generators() < b.num_generators();
|
|
646
|
+
}
|
|
647
|
+
|
|
648
|
+
/**
|
|
649
|
+
* @brief Returns `true` if and only if the first argument is lexicographically less than or equal to the second
|
|
650
|
+
* argument. The "words" considered for the lexicographical order are all the generators concatenated together
|
|
651
|
+
* in order of generator index and then in order of parameter index. Different from @ref operator<= "", this order
|
|
652
|
+
* is total.
|
|
653
|
+
*
|
|
654
|
+
* @tparam inverse If true, the parameter index and generator index order is inverted.
|
|
655
|
+
*/
|
|
656
|
+
template <bool inverse = false>
|
|
657
|
+
friend bool is_less_or_equal_than_lexicographically(const Degree_rips_bifiltration &a,
|
|
658
|
+
const Degree_rips_bifiltration &b)
|
|
659
|
+
{
|
|
660
|
+
if (&a == &b) return true;
|
|
661
|
+
if (b.is_nan()) return true;
|
|
662
|
+
if (a.is_nan()) return false;
|
|
663
|
+
|
|
664
|
+
if constexpr (inverse) {
|
|
665
|
+
if (a.num_generators() != b.num_generators()) {
|
|
666
|
+
if (a.num_generators() == 0) return true;
|
|
667
|
+
if (b.num_generators() == 0) return false;
|
|
668
|
+
if (a.generators_[0] < b.generators_[0]) return true;
|
|
669
|
+
if (b.generators_[0] < a.generators_[0]) return false;
|
|
670
|
+
return a.num_generators() < b.num_generators();
|
|
671
|
+
}
|
|
672
|
+
}
|
|
673
|
+
|
|
674
|
+
for (std::size_t i = 0U; i < std::min(a.num_generators(), b.num_generators()); ++i) {
|
|
675
|
+
if constexpr (inverse) i = std::min(a.num_generators(), b.num_generators()) - 1 - i;
|
|
676
|
+
if (_is_nan(a.generators_[i]) && !_is_nan(b.generators_[i])) return false;
|
|
677
|
+
if (_is_nan(b.generators_[i])) return true;
|
|
678
|
+
if (a.generators_[i] < b.generators_[i]) return true;
|
|
679
|
+
if (b.generators_[i] < a.generators_[i]) return false;
|
|
680
|
+
if constexpr (inverse) i = std::min(a.num_generators(), b.num_generators()) - 1 - i;
|
|
681
|
+
}
|
|
682
|
+
return a.num_generators() <= b.num_generators();
|
|
683
|
+
}
|
|
684
|
+
|
|
685
|
+
/**
|
|
686
|
+
* @brief Returns `true` if and only if the cones generated by @p b are strictly contained in the
|
|
687
|
+
* cones generated by @p a (recall that the cones are positive if `Co` is false and negative if `Co` is true).
|
|
688
|
+
*
|
|
689
|
+
* Note that not all filtration values are comparable. That is, \f$ a < b \f$ and \f$ b < a \f$ returning both false
|
|
690
|
+
* does **not** imply \f$ a == b \f$. If a total order is needed, use @ref is_strict_less_than_lexicographically
|
|
691
|
+
* instead.
|
|
692
|
+
*/
|
|
693
|
+
friend bool operator<(const Degree_rips_bifiltration &a, const Degree_rips_bifiltration &b)
|
|
694
|
+
{
|
|
695
|
+
if (&a == &b) return false;
|
|
696
|
+
if (a.generators_.size() == 0 || b.generators_.size() == 0) return false;
|
|
697
|
+
return _compare_strict(0, a.generators_, b.generators_, a.generators_[0]);
|
|
698
|
+
}
|
|
699
|
+
|
|
700
|
+
/**
|
|
701
|
+
* @brief Returns `true` if and only if the cones generated by @p a are strictly contained in the
|
|
702
|
+
* cones generated by @p b (recall that the cones are positive if `Co` is false and negative if `Co` is true).
|
|
703
|
+
*
|
|
704
|
+
* Note that not all filtration values are comparable. That is, \f$ a \le b \f$ and \f$ b \le a \f$ can both return
|
|
705
|
+
* `false`. If a total order is needed, use @ref is_less_or_equal_than_lexicographically instead.
|
|
706
|
+
*/
|
|
707
|
+
friend bool operator<=(const Degree_rips_bifiltration &a, const Degree_rips_bifiltration &b)
|
|
708
|
+
{
|
|
709
|
+
if (a.generators_.size() == 0 || b.generators_.size() == 0) return false;
|
|
710
|
+
if (&a == &b) return true;
|
|
711
|
+
return _compare(0, a.generators_, b.generators_, a.generators_[0]);
|
|
712
|
+
}
|
|
713
|
+
|
|
714
|
+
/**
|
|
715
|
+
* @brief Returns `true` if and only if the cones generated by @p b are contained in or are (partially)
|
|
716
|
+
* equal to the cones generated by @p a (recall that the cones are positive if `Co` is false and negative if `Co` is
|
|
717
|
+
* true).
|
|
718
|
+
*
|
|
719
|
+
* Note that not all filtration values are comparable. That is, \f$ a > b \f$ and \f$ b > a \f$ returning both false
|
|
720
|
+
* does **not** imply \f$ a == b \f$. If a total order is needed, use @ref is_strict_less_than_lexicographically
|
|
721
|
+
* instead.
|
|
722
|
+
*/
|
|
723
|
+
friend bool operator>(const Degree_rips_bifiltration &a, const Degree_rips_bifiltration &b) { return b < a; }
|
|
724
|
+
|
|
725
|
+
/**
|
|
726
|
+
* @brief Returns `true` if and only if the cones generated by @p a are contained in or are (partially)
|
|
727
|
+
* equal to the cones generated by @p b (recall that the cones are positive if `Co` is false and negative if `Co` is
|
|
728
|
+
* true).
|
|
729
|
+
*
|
|
730
|
+
* Note that not all filtration values are comparable. That is, \f$ a \ge b \f$ and \f$ b \ge a \f$ can both return
|
|
731
|
+
* `false`. If a total order is needed, use @ref is_less_or_equal_than_lexicographically instead.
|
|
732
|
+
*/
|
|
733
|
+
friend bool operator>=(const Degree_rips_bifiltration &a, const Degree_rips_bifiltration &b) { return b <= a; }
|
|
734
|
+
|
|
735
|
+
/**
|
|
736
|
+
* @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$.
|
|
737
|
+
*
|
|
738
|
+
* @warning The method considers different two filtration values with different generators, but as the set of
|
|
739
|
+
* generators is rarely minimal, it is still possible that those two values are equivalent.
|
|
740
|
+
*/
|
|
741
|
+
friend bool operator==(const Degree_rips_bifiltration &a, const Degree_rips_bifiltration &b)
|
|
742
|
+
{
|
|
743
|
+
if (a.is_nan() || b.is_nan()) return false;
|
|
744
|
+
if (&a == &b) return true;
|
|
745
|
+
return a.generators_ == b.generators_;
|
|
746
|
+
}
|
|
747
|
+
|
|
748
|
+
/**
|
|
749
|
+
* @brief Returns `true` if and only if \f$ a == b \f$ returns `false`.
|
|
750
|
+
*/
|
|
751
|
+
friend bool operator!=(const Degree_rips_bifiltration &a, const Degree_rips_bifiltration &b) { return !(a == b); }
|
|
752
|
+
|
|
753
|
+
// ARITHMETIC OPERATORS
|
|
754
|
+
|
|
755
|
+
// opposite
|
|
756
|
+
/**
|
|
757
|
+
* @brief Returns a filtration value such that an entry at index \f$ i,0 \f$ is equal to \f$ -f(i,0) \f$.
|
|
758
|
+
*
|
|
759
|
+
* Used conventions:
|
|
760
|
+
* - \f$ -NaN = NaN \f$.
|
|
761
|
+
*
|
|
762
|
+
* @param f Value to opposite.
|
|
763
|
+
* @return The opposite of @p f.
|
|
764
|
+
*/
|
|
765
|
+
friend Degree_rips_bifiltration operator-(const Degree_rips_bifiltration &f)
|
|
766
|
+
{
|
|
767
|
+
using F = Degree_rips_bifiltration;
|
|
768
|
+
|
|
769
|
+
Underlying_container result(f.generators_);
|
|
770
|
+
std::for_each(result.begin(), result.end(), [](T &v) {
|
|
771
|
+
if (v == F::T_inf)
|
|
772
|
+
v = F::T_m_inf;
|
|
773
|
+
else if (v == F::T_m_inf)
|
|
774
|
+
v = F::T_inf;
|
|
775
|
+
else
|
|
776
|
+
v = -v;
|
|
777
|
+
});
|
|
778
|
+
return Degree_rips_bifiltration(std::move(result), Degree_rips_bifiltration::num_parameters());
|
|
779
|
+
}
|
|
780
|
+
|
|
781
|
+
// subtraction
|
|
782
|
+
/**
|
|
783
|
+
* @brief Returns a filtration value such that an entry at index \f$ (g,0) \f$, with
|
|
784
|
+
* \f$ 0 \leq g \leq num_generators \f$ is equal to \f$ f(g,0) - r(0) \f$
|
|
785
|
+
* if \f$ 0 < length_r \f$ and to \f$ f(g,0) \f$ otherwise.
|
|
786
|
+
*
|
|
787
|
+
* Used conventions:
|
|
788
|
+
* - \f$ inf - inf = NaN \f$,
|
|
789
|
+
* - \f$ -inf - (-inf) = NaN \f$,
|
|
790
|
+
* - \f$ NaN - b = NaN \f$,
|
|
791
|
+
* - \f$ a - NaN = NaN \f$.
|
|
792
|
+
*
|
|
793
|
+
* All NaN values are represented by `std::numeric_limits<T>::quiet_NaN()` independently if
|
|
794
|
+
* `std::numeric_limits<T>::has_quiet_NaN` is true or not.
|
|
795
|
+
*
|
|
796
|
+
* @tparam ValueRange Range with a begin() and end() method.
|
|
797
|
+
* @param f First element of the subtraction.
|
|
798
|
+
* @param r Second element of the subtraction.
|
|
799
|
+
*/
|
|
800
|
+
template <class ValueRange, class = std::enable_if_t<RangeTraits<ValueRange>::has_begin> >
|
|
801
|
+
friend Degree_rips_bifiltration operator-(Degree_rips_bifiltration f, const ValueRange &r)
|
|
802
|
+
{
|
|
803
|
+
f -= r;
|
|
804
|
+
return f;
|
|
805
|
+
}
|
|
806
|
+
|
|
807
|
+
/**
|
|
808
|
+
* @brief Returns a filtration value such that an entry at index \f$ (g,0) \f$, with
|
|
809
|
+
* \f$ 0 \leq g \leq num_generators \f$ is equal to \f$ r(0) - f(g,0) \f$
|
|
810
|
+
* if \f$ 0 < length_r \f$ and to -\f$ f(g,0) \f$ otherwise.
|
|
811
|
+
*
|
|
812
|
+
* Used conventions:
|
|
813
|
+
* - \f$ inf - inf = NaN \f$,
|
|
814
|
+
* - \f$ -inf - (-inf) = NaN \f$,
|
|
815
|
+
* - \f$ NaN - b = NaN \f$,
|
|
816
|
+
* - \f$ a - NaN = NaN \f$.
|
|
817
|
+
*
|
|
818
|
+
* All NaN values are represented by `std::numeric_limits<T>::quiet_NaN()` independently if
|
|
819
|
+
* `std::numeric_limits<T>::has_quiet_NaN` is true or not.
|
|
820
|
+
*
|
|
821
|
+
* @tparam ValueRange Range with a begin() and end() method.
|
|
822
|
+
* @param r First element of the subtraction.
|
|
823
|
+
* @param f Second element of the subtraction.
|
|
824
|
+
*/
|
|
825
|
+
template <class ValueRange,
|
|
826
|
+
class = std::enable_if_t<RangeTraits<ValueRange>::has_begin &&
|
|
827
|
+
!std::is_same_v<ValueRange, Degree_rips_bifiltration> > >
|
|
828
|
+
friend Degree_rips_bifiltration operator-(const ValueRange &r, Degree_rips_bifiltration f)
|
|
829
|
+
{
|
|
830
|
+
if (r.begin() == r.end()) return -f;
|
|
831
|
+
return *(r.begin()) - f;
|
|
832
|
+
}
|
|
833
|
+
|
|
834
|
+
/**
|
|
835
|
+
* @brief Returns a filtration value such that an entry at index \f$ (g,0) \f$ is equal to \f$ f(g,0) - val \f$.
|
|
836
|
+
*
|
|
837
|
+
* Used conventions:
|
|
838
|
+
* - \f$ inf - inf = NaN \f$,
|
|
839
|
+
* - \f$ -inf - (-inf) = NaN \f$,
|
|
840
|
+
* - \f$ NaN - b = NaN \f$,
|
|
841
|
+
* - \f$ a - NaN = NaN \f$.
|
|
842
|
+
*
|
|
843
|
+
* All NaN values are represented by `std::numeric_limits<T>::quiet_NaN()` independently if
|
|
844
|
+
* `std::numeric_limits<T>::has_quiet_NaN` is true or not.
|
|
845
|
+
*
|
|
846
|
+
* @param f First element of the subtraction.
|
|
847
|
+
* @param val Second element of the subtraction.
|
|
848
|
+
*/
|
|
849
|
+
friend Degree_rips_bifiltration operator-(Degree_rips_bifiltration f, const T &val)
|
|
850
|
+
{
|
|
851
|
+
f -= val;
|
|
852
|
+
return f;
|
|
853
|
+
}
|
|
854
|
+
|
|
855
|
+
/**
|
|
856
|
+
* @brief Returns a filtration value such that an entry at index \f$ (g,0) \f$ is equal to \f$ val - f(g,0) \f$.
|
|
857
|
+
*
|
|
858
|
+
* Used conventions:
|
|
859
|
+
* - \f$ inf - inf = NaN \f$,
|
|
860
|
+
* - \f$ -inf - (-inf) = NaN \f$,
|
|
861
|
+
* - \f$ NaN - b = NaN \f$,
|
|
862
|
+
* - \f$ a - NaN = NaN \f$.
|
|
863
|
+
*
|
|
864
|
+
* All NaN values are represented by `std::numeric_limits<T>::quiet_NaN()` independently if
|
|
865
|
+
* `std::numeric_limits<T>::has_quiet_NaN` is true or not.
|
|
866
|
+
*
|
|
867
|
+
* @param val First element of the subtraction.
|
|
868
|
+
* @param f Second element of the subtraction.
|
|
869
|
+
*/
|
|
870
|
+
friend Degree_rips_bifiltration operator-(const T &val, Degree_rips_bifiltration f)
|
|
871
|
+
{
|
|
872
|
+
f._apply_operation(val, [](T &valF, const T &valR) {
|
|
873
|
+
valF = -valF;
|
|
874
|
+
_add(valF, valR);
|
|
875
|
+
});
|
|
876
|
+
return f;
|
|
877
|
+
}
|
|
878
|
+
|
|
879
|
+
/**
|
|
880
|
+
* @brief Modifies the first parameter such that an entry at index \f$ (g,0) \f$, with
|
|
881
|
+
* \f$ 0 \leq g \leq num_generators \f$ is equal to \f$ f(g,0) - r(0) \f$
|
|
882
|
+
* if \f$ 0 < length_r \f$ and to \f$ f(g,0) \f$ otherwise.
|
|
883
|
+
*
|
|
884
|
+
* Used conventions:
|
|
885
|
+
* - \f$ inf - inf = NaN \f$,
|
|
886
|
+
* - \f$ -inf - (-inf) = NaN \f$,
|
|
887
|
+
* - \f$ NaN - b = NaN \f$,
|
|
888
|
+
* - \f$ a - NaN = NaN \f$.
|
|
889
|
+
*
|
|
890
|
+
* All NaN values are represented by `std::numeric_limits<T>::quiet_NaN()` independently if
|
|
891
|
+
* `std::numeric_limits<T>::has_quiet_NaN` is true or not.
|
|
892
|
+
*
|
|
893
|
+
* @tparam ValueRange Range with a begin() and end() method.
|
|
894
|
+
* @param f First element of the subtraction.
|
|
895
|
+
* @param r Second element of the subtraction.
|
|
896
|
+
*/
|
|
897
|
+
template <class ValueRange, class = std::enable_if_t<RangeTraits<ValueRange>::has_begin> >
|
|
898
|
+
friend Degree_rips_bifiltration &operator-=(Degree_rips_bifiltration &f, const ValueRange &r)
|
|
899
|
+
{
|
|
900
|
+
if (r.begin() == r.end()) return f;
|
|
901
|
+
f -= *(r.begin());
|
|
902
|
+
return f;
|
|
903
|
+
}
|
|
904
|
+
|
|
905
|
+
/**
|
|
906
|
+
* @brief Modifies the first parameter such that an entry at index \f$ (g,0) \f$ is equal to \f$ f(g,0) - val \f$.
|
|
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
|
+
* @param f First element of the subtraction.
|
|
918
|
+
* @param val Second element of the subtraction.
|
|
919
|
+
*/
|
|
920
|
+
friend Degree_rips_bifiltration &operator-=(Degree_rips_bifiltration &f, const T &val)
|
|
921
|
+
{
|
|
922
|
+
f._apply_operation(val, [](T &valF, const T &valR) { _subtract(valF, valR); });
|
|
923
|
+
return f;
|
|
924
|
+
}
|
|
925
|
+
|
|
926
|
+
// addition
|
|
927
|
+
/**
|
|
928
|
+
* @brief Returns a filtration value such that an entry at index \f$ (g,0) \f$, with
|
|
929
|
+
* \f$ 0 \leq g \leq num_generators \f$ is equal to \f$ f(g,0) + r(0) \f$
|
|
930
|
+
* if \f$ 0 < length_r \f$ and to \f$ f(g,0) \f$ otherwise.
|
|
931
|
+
*
|
|
932
|
+
* Used conventions:
|
|
933
|
+
* - \f$ inf + (-inf) = NaN \f$,
|
|
934
|
+
* - \f$ -inf + inf = NaN \f$,
|
|
935
|
+
* - \f$ NaN + b = NaN \f$,
|
|
936
|
+
* - \f$ a + NaN = NaN \f$.
|
|
937
|
+
*
|
|
938
|
+
* All NaN values are represented by `std::numeric_limits<T>::quiet_NaN()` independently if
|
|
939
|
+
* `std::numeric_limits<T>::has_quiet_NaN` is true or not.
|
|
940
|
+
*
|
|
941
|
+
* @tparam ValueRange Range with a begin() and end() method.
|
|
942
|
+
* @param f First element of the addition.
|
|
943
|
+
* @param r Second element of the addition.
|
|
944
|
+
*/
|
|
945
|
+
template <class ValueRange, class = std::enable_if_t<RangeTraits<ValueRange>::has_begin> >
|
|
946
|
+
friend Degree_rips_bifiltration operator+(Degree_rips_bifiltration f, const ValueRange &r)
|
|
947
|
+
{
|
|
948
|
+
f += r;
|
|
949
|
+
return f;
|
|
950
|
+
}
|
|
951
|
+
|
|
952
|
+
/**
|
|
953
|
+
* @brief Returns a filtration value such that an entry at index \f$ (g,0) \f$, with
|
|
954
|
+
* \f$ 0 \leq g \leq num_generators \f$ is equal to \f$ r(0) + f(g,0) \f$
|
|
955
|
+
* if \f$ 0 < length_r \f$ and to \f$ f(g,0) \f$ otherwise.
|
|
956
|
+
*
|
|
957
|
+
* Used conventions:
|
|
958
|
+
* - \f$ inf + (-inf) = NaN \f$,
|
|
959
|
+
* - \f$ -inf + inf = NaN \f$,
|
|
960
|
+
* - \f$ NaN + b = NaN \f$,
|
|
961
|
+
* - \f$ a + NaN = NaN \f$.
|
|
962
|
+
*
|
|
963
|
+
* All NaN values are represented by `std::numeric_limits<T>::quiet_NaN()` independently if
|
|
964
|
+
* `std::numeric_limits<T>::has_quiet_NaN` is true or not.
|
|
965
|
+
*
|
|
966
|
+
* @tparam ValueRange Range with a begin() and end() method.
|
|
967
|
+
* @param r First element of the addition.
|
|
968
|
+
* @param f Second element of the addition.
|
|
969
|
+
*/
|
|
970
|
+
template <class ValueRange,
|
|
971
|
+
class = std::enable_if_t<RangeTraits<ValueRange>::has_begin &&
|
|
972
|
+
!std::is_same_v<ValueRange, Degree_rips_bifiltration> > >
|
|
973
|
+
friend Degree_rips_bifiltration operator+(const ValueRange &r, Degree_rips_bifiltration f)
|
|
974
|
+
{
|
|
975
|
+
f += r;
|
|
976
|
+
return f;
|
|
977
|
+
}
|
|
978
|
+
|
|
979
|
+
/**
|
|
980
|
+
* @brief Returns a filtration value such that an entry at index \f$ (g,0) \f$ is equal to \f$ f(g,0) + val \f$.
|
|
981
|
+
*
|
|
982
|
+
* Used conventions:
|
|
983
|
+
* - \f$ inf + (-inf) = NaN \f$,
|
|
984
|
+
* - \f$ -inf + inf = NaN \f$,
|
|
985
|
+
* - \f$ NaN + b = NaN \f$,
|
|
986
|
+
* - \f$ a + NaN = NaN \f$.
|
|
987
|
+
*
|
|
988
|
+
* All NaN values are represented by `std::numeric_limits<T>::quiet_NaN()` independently if
|
|
989
|
+
* `std::numeric_limits<T>::has_quiet_NaN` is true or not.
|
|
990
|
+
*
|
|
991
|
+
* @param f First element of the addition.
|
|
992
|
+
* @param val Second element of the addition.
|
|
993
|
+
*/
|
|
994
|
+
friend Degree_rips_bifiltration operator+(Degree_rips_bifiltration f, const T &val)
|
|
995
|
+
{
|
|
996
|
+
f += val;
|
|
997
|
+
return f;
|
|
998
|
+
}
|
|
999
|
+
|
|
1000
|
+
/**
|
|
1001
|
+
* @brief Returns a filtration value such that an entry at index \f$ (g,0) \f$ is equal to \f$ val + f(g,0) \f$.
|
|
1002
|
+
*
|
|
1003
|
+
* Used conventions:
|
|
1004
|
+
* - \f$ inf + (-inf) = NaN \f$,
|
|
1005
|
+
* - \f$ -inf + inf = NaN \f$,
|
|
1006
|
+
* - \f$ NaN + b = NaN \f$,
|
|
1007
|
+
* - \f$ a + NaN = NaN \f$.
|
|
1008
|
+
*
|
|
1009
|
+
* All NaN values are represented by `std::numeric_limits<T>::quiet_NaN()` independently if
|
|
1010
|
+
* `std::numeric_limits<T>::has_quiet_NaN` is true or not.
|
|
1011
|
+
*
|
|
1012
|
+
* @param val First element of the addition.
|
|
1013
|
+
* @param f Second element of the addition.
|
|
1014
|
+
*/
|
|
1015
|
+
friend Degree_rips_bifiltration operator+(const T &val, Degree_rips_bifiltration f)
|
|
1016
|
+
{
|
|
1017
|
+
f += val;
|
|
1018
|
+
return f;
|
|
1019
|
+
}
|
|
1020
|
+
|
|
1021
|
+
/**
|
|
1022
|
+
* @brief Modifies the first parameter such that an entry at index \f$ (g,0) \f$, with
|
|
1023
|
+
* \f$ 0 \leq g \leq num_generators \f$ is equal to \f$ f(g,0) + r(0) \f$
|
|
1024
|
+
* if \f$ 0 < length_r \f$ and to \f$ f(g,0) \f$ otherwise.
|
|
1025
|
+
*
|
|
1026
|
+
* Used conventions:
|
|
1027
|
+
* - \f$ inf + (-inf) = NaN \f$,
|
|
1028
|
+
* - \f$ -inf + inf = NaN \f$,
|
|
1029
|
+
* - \f$ NaN + b = NaN \f$,
|
|
1030
|
+
* - \f$ a + NaN = NaN \f$.
|
|
1031
|
+
*
|
|
1032
|
+
* All NaN values are represented by `std::numeric_limits<T>::quiet_NaN()` independently if
|
|
1033
|
+
* `std::numeric_limits<T>::has_quiet_NaN` is true or not.
|
|
1034
|
+
*
|
|
1035
|
+
* @tparam ValueRange Range with a begin() and end() method.
|
|
1036
|
+
* @param f First element of the addition.
|
|
1037
|
+
* @param r Second element of the addition.
|
|
1038
|
+
*/
|
|
1039
|
+
template <class ValueRange, class = std::enable_if_t<RangeTraits<ValueRange>::has_begin> >
|
|
1040
|
+
friend Degree_rips_bifiltration &operator+=(Degree_rips_bifiltration &f, const ValueRange &r)
|
|
1041
|
+
{
|
|
1042
|
+
if (r.begin() == r.end()) return f;
|
|
1043
|
+
f += *(r.begin());
|
|
1044
|
+
return f;
|
|
1045
|
+
}
|
|
1046
|
+
|
|
1047
|
+
/**
|
|
1048
|
+
* @brief Modifies the first parameter such that an entry at index \f$ (g,0) \f$ is equal to \f$ f(g,0) + val \f$.
|
|
1049
|
+
*
|
|
1050
|
+
* Used conventions:
|
|
1051
|
+
* - \f$ inf + (-inf) = NaN \f$,
|
|
1052
|
+
* - \f$ -inf + inf = NaN \f$,
|
|
1053
|
+
* - \f$ NaN + b = NaN \f$,
|
|
1054
|
+
* - \f$ a + NaN = NaN \f$.
|
|
1055
|
+
*
|
|
1056
|
+
* All NaN values are represented by `std::numeric_limits<T>::quiet_NaN()` independently if
|
|
1057
|
+
* `std::numeric_limits<T>::has_quiet_NaN` is true or not.
|
|
1058
|
+
*
|
|
1059
|
+
* @param f First element of the addition.
|
|
1060
|
+
* @param val Second element of the addition.
|
|
1061
|
+
*/
|
|
1062
|
+
friend Degree_rips_bifiltration &operator+=(Degree_rips_bifiltration &f, const T &val)
|
|
1063
|
+
{
|
|
1064
|
+
f._apply_operation(val, [](T &valF, const T &valR) { _add(valF, valR); });
|
|
1065
|
+
return f;
|
|
1066
|
+
}
|
|
1067
|
+
|
|
1068
|
+
// multiplication
|
|
1069
|
+
/**
|
|
1070
|
+
* @brief Returns a filtration value such that an entry at index \f$ (g,0) \f$, with
|
|
1071
|
+
* \f$ 0 \leq g \leq num_generators \f$ is equal to \f$ f(g,0) * r(0) \f$
|
|
1072
|
+
* if \f$ 0 < length_r \f$ and to \f$ f(g,0) \f$ otherwise.
|
|
1073
|
+
*
|
|
1074
|
+
* Used conventions:
|
|
1075
|
+
* - \f$ inf * 0 = NaN \f$,
|
|
1076
|
+
* - \f$ 0 * inf = NaN \f$,
|
|
1077
|
+
* - \f$ -inf * 0 = NaN \f$,
|
|
1078
|
+
* - \f$ 0 * (-inf) = NaN \f$,
|
|
1079
|
+
* - \f$ NaN * b = NaN \f$,
|
|
1080
|
+
* - \f$ a * NaN = NaN \f$.
|
|
1081
|
+
*
|
|
1082
|
+
* All NaN values are represented by `std::numeric_limits<T>::quiet_NaN()` independently if
|
|
1083
|
+
* `std::numeric_limits<T>::has_quiet_NaN` is true or not.
|
|
1084
|
+
*
|
|
1085
|
+
* @tparam ValueRange Range with a begin() and end() method.
|
|
1086
|
+
* @param f First element of the multiplication.
|
|
1087
|
+
* @param r Second element of the multiplication.
|
|
1088
|
+
*/
|
|
1089
|
+
template <class ValueRange, class = std::enable_if_t<RangeTraits<ValueRange>::has_begin> >
|
|
1090
|
+
friend Degree_rips_bifiltration operator*(Degree_rips_bifiltration f, const ValueRange &r)
|
|
1091
|
+
{
|
|
1092
|
+
f *= r;
|
|
1093
|
+
return f;
|
|
1094
|
+
}
|
|
1095
|
+
|
|
1096
|
+
/**
|
|
1097
|
+
* @brief Returns a filtration value such that an entry at index \f$ (g,0) \f$, with
|
|
1098
|
+
* \f$ 0 \leq g \leq num_generators \f$ is equal to \f$ r(0) * f(g,0) \f$
|
|
1099
|
+
* if \f$ 0 < length_r \f$ and to \f$ f(g,0) \f$ otherwise.
|
|
1100
|
+
*
|
|
1101
|
+
* Used conventions:
|
|
1102
|
+
* - \f$ inf * 0 = NaN \f$,
|
|
1103
|
+
* - \f$ 0 * inf = NaN \f$,
|
|
1104
|
+
* - \f$ -inf * 0 = NaN \f$,
|
|
1105
|
+
* - \f$ 0 * (-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
|
+
* @tparam ValueRange Range with a begin() and end() method.
|
|
1113
|
+
* @param r First element of the multiplication.
|
|
1114
|
+
* @param f Second element of the multiplication.
|
|
1115
|
+
*/
|
|
1116
|
+
template <class ValueRange,
|
|
1117
|
+
class = std::enable_if_t<RangeTraits<ValueRange>::has_begin &&
|
|
1118
|
+
!std::is_same_v<ValueRange, Degree_rips_bifiltration> > >
|
|
1119
|
+
friend Degree_rips_bifiltration operator*(const ValueRange &r, Degree_rips_bifiltration f)
|
|
1120
|
+
{
|
|
1121
|
+
f *= r;
|
|
1122
|
+
return f;
|
|
1123
|
+
}
|
|
1124
|
+
|
|
1125
|
+
/**
|
|
1126
|
+
* @brief Returns a filtration value such that an entry at index \f$ (g,0) \f$ is equal to \f$ f(g,0) * val \f$.
|
|
1127
|
+
*
|
|
1128
|
+
* Used conventions:
|
|
1129
|
+
* - \f$ inf * 0 = NaN \f$,
|
|
1130
|
+
* - \f$ 0 * inf = NaN \f$,
|
|
1131
|
+
* - \f$ -inf * 0 = NaN \f$,
|
|
1132
|
+
* - \f$ 0 * (-inf) = NaN \f$,
|
|
1133
|
+
* - \f$ NaN * b = NaN \f$,
|
|
1134
|
+
* - \f$ a * NaN = NaN \f$.
|
|
1135
|
+
*
|
|
1136
|
+
* All NaN values are represented by `std::numeric_limits<T>::quiet_NaN()` independently if
|
|
1137
|
+
* `std::numeric_limits<T>::has_quiet_NaN` is true or not.
|
|
1138
|
+
*
|
|
1139
|
+
* @param f First element of the multiplication.
|
|
1140
|
+
* @param val Second element of the multiplication.
|
|
1141
|
+
*/
|
|
1142
|
+
friend Degree_rips_bifiltration operator*(Degree_rips_bifiltration f, const T &val)
|
|
1143
|
+
{
|
|
1144
|
+
f *= val;
|
|
1145
|
+
return f;
|
|
1146
|
+
}
|
|
1147
|
+
|
|
1148
|
+
/**
|
|
1149
|
+
* @brief Returns a filtration value such that an entry at index \f$ (g,0) \f$ is equal to \f$ val * f(g,0) \f$.
|
|
1150
|
+
*
|
|
1151
|
+
* Used conventions:
|
|
1152
|
+
* - \f$ inf * 0 = NaN \f$,
|
|
1153
|
+
* - \f$ 0 * inf = NaN \f$,
|
|
1154
|
+
* - \f$ -inf * 0 = NaN \f$,
|
|
1155
|
+
* - \f$ 0 * (-inf) = NaN \f$,
|
|
1156
|
+
* - \f$ NaN * b = NaN \f$,
|
|
1157
|
+
* - \f$ a * NaN = NaN \f$.
|
|
1158
|
+
*
|
|
1159
|
+
* All NaN values are represented by `std::numeric_limits<T>::quiet_NaN()` independently if
|
|
1160
|
+
* `std::numeric_limits<T>::has_quiet_NaN` is true or not.
|
|
1161
|
+
*
|
|
1162
|
+
* @param val First element of the multiplication.
|
|
1163
|
+
* @param f Second element of the multiplication.
|
|
1164
|
+
*/
|
|
1165
|
+
friend Degree_rips_bifiltration operator*(const T &val, Degree_rips_bifiltration f)
|
|
1166
|
+
{
|
|
1167
|
+
f *= val;
|
|
1168
|
+
return f;
|
|
1169
|
+
}
|
|
1170
|
+
|
|
1171
|
+
/**
|
|
1172
|
+
* @brief Modifies the first parameter such that an entry at index \f$ (g,0) \f$, with
|
|
1173
|
+
* \f$ 0 \leq g \leq num_generators \f$ is equal to \f$ f(g,0) + r(0) \f$
|
|
1174
|
+
* if \f$ 0 < length_r \f$ and to \f$ f(g,0) \f$ otherwise.
|
|
1175
|
+
*
|
|
1176
|
+
* Used conventions:
|
|
1177
|
+
* - \f$ inf * 0 = NaN \f$,
|
|
1178
|
+
* - \f$ 0 * inf = NaN \f$,
|
|
1179
|
+
* - \f$ -inf * 0 = NaN \f$,
|
|
1180
|
+
* - \f$ 0 * (-inf) = NaN \f$,
|
|
1181
|
+
* - \f$ NaN * b = NaN \f$,
|
|
1182
|
+
* - \f$ a * NaN = NaN \f$.
|
|
1183
|
+
*
|
|
1184
|
+
* All NaN values are represented by `std::numeric_limits<T>::quiet_NaN()` independently if
|
|
1185
|
+
* `std::numeric_limits<T>::has_quiet_NaN` is true or not.
|
|
1186
|
+
*
|
|
1187
|
+
* @tparam ValueRange Range with a begin() and end() method.
|
|
1188
|
+
* @param f First element of the multiplication.
|
|
1189
|
+
* @param r Second element of the multiplication.
|
|
1190
|
+
*/
|
|
1191
|
+
template <class ValueRange, class = std::enable_if_t<RangeTraits<ValueRange>::has_begin> >
|
|
1192
|
+
friend Degree_rips_bifiltration &operator*=(Degree_rips_bifiltration &f, const ValueRange &r)
|
|
1193
|
+
{
|
|
1194
|
+
if (r.begin() == r.end()) return f;
|
|
1195
|
+
f *= *(r.begin());
|
|
1196
|
+
return f;
|
|
1197
|
+
}
|
|
1198
|
+
|
|
1199
|
+
/**
|
|
1200
|
+
* @brief Modifies the first parameter such that an entry at index \f$ (g,0) \f$ is equal to \f$ f(g,0) * val \f$.
|
|
1201
|
+
*
|
|
1202
|
+
* Used conventions:
|
|
1203
|
+
* - \f$ inf * 0 = NaN \f$,
|
|
1204
|
+
* - \f$ 0 * inf = NaN \f$,
|
|
1205
|
+
* - \f$ -inf * 0 = NaN \f$,
|
|
1206
|
+
* - \f$ 0 * (-inf) = NaN \f$,
|
|
1207
|
+
* - \f$ NaN * b = NaN \f$,
|
|
1208
|
+
* - \f$ a * NaN = NaN \f$.
|
|
1209
|
+
*
|
|
1210
|
+
* All NaN values are represented by `std::numeric_limits<T>::quiet_NaN()` independently if
|
|
1211
|
+
* `std::numeric_limits<T>::has_quiet_NaN` is true or not.
|
|
1212
|
+
*
|
|
1213
|
+
* @param f First element of the multiplication.
|
|
1214
|
+
* @param val Second element of the multiplication.
|
|
1215
|
+
*/
|
|
1216
|
+
friend Degree_rips_bifiltration &operator*=(Degree_rips_bifiltration &f, const T &val)
|
|
1217
|
+
{
|
|
1218
|
+
f._apply_operation(val, [](T &valF, const T &valR) { _multiply(valF, valR); });
|
|
1219
|
+
return f;
|
|
1220
|
+
}
|
|
1221
|
+
|
|
1222
|
+
// division
|
|
1223
|
+
/**
|
|
1224
|
+
* @brief Returns a filtration value such that an entry at index \f$ (g,0) \f$, with
|
|
1225
|
+
* \f$ 0 \leq g \leq num_generators \f$ is equal to \f$ f(g,0) / r(0) \f$
|
|
1226
|
+
* if \f$ 0 < length_r \f$ and to \f$ f(g,0) \f$ otherwise.
|
|
1227
|
+
*
|
|
1228
|
+
* Used conventions:
|
|
1229
|
+
* - \f$ a / 0 = NaN \f$,
|
|
1230
|
+
* - \f$ inf / inf = NaN \f$,
|
|
1231
|
+
* - \f$ -inf / inf = NaN \f$,
|
|
1232
|
+
* - \f$ inf / -inf = NaN \f$,
|
|
1233
|
+
* - \f$ -inf / -inf = NaN \f$,
|
|
1234
|
+
* - \f$ NaN / b = NaN \f$,
|
|
1235
|
+
* - \f$ a / NaN = NaN \f$,
|
|
1236
|
+
* - \f$ a / inf = 0 \f$,
|
|
1237
|
+
* - \f$ a / -inf = 0 \f$.
|
|
1238
|
+
*
|
|
1239
|
+
* All NaN values are represented by `std::numeric_limits<T>::quiet_NaN()` independently if
|
|
1240
|
+
* `std::numeric_limits<T>::has_quiet_NaN` is true or not.
|
|
1241
|
+
*
|
|
1242
|
+
* @tparam ValueRange Range with a begin() and end() method.
|
|
1243
|
+
* @param f First element of the division.
|
|
1244
|
+
* @param r Second element of the division.
|
|
1245
|
+
*/
|
|
1246
|
+
template <class ValueRange, class = std::enable_if_t<RangeTraits<ValueRange>::has_begin> >
|
|
1247
|
+
friend Degree_rips_bifiltration operator/(Degree_rips_bifiltration f, const ValueRange &r)
|
|
1248
|
+
{
|
|
1249
|
+
f /= r;
|
|
1250
|
+
return f;
|
|
1251
|
+
}
|
|
1252
|
+
|
|
1253
|
+
/**
|
|
1254
|
+
* @brief Returns a filtration value such that an entry at index \f$ (g,0) \f$, with
|
|
1255
|
+
* \f$ 0 \leq g \leq num_generators \f$ is equal to \f$ r(0) / f(g,0) \f$
|
|
1256
|
+
* if \f$ 0 < length_r \f$ and to \f$ 1 / f(g,0) \f$ otherwise.
|
|
1257
|
+
*
|
|
1258
|
+
* Used conventions:
|
|
1259
|
+
* - \f$ a / 0 = NaN \f$,
|
|
1260
|
+
* - \f$ inf / inf = NaN \f$,
|
|
1261
|
+
* - \f$ -inf / inf = NaN \f$,
|
|
1262
|
+
* - \f$ inf / -inf = NaN \f$,
|
|
1263
|
+
* - \f$ -inf / -inf = NaN \f$,
|
|
1264
|
+
* - \f$ NaN / b = NaN \f$,
|
|
1265
|
+
* - \f$ a / NaN = NaN \f$,
|
|
1266
|
+
* - \f$ a / inf = 0 \f$,
|
|
1267
|
+
* - \f$ a / -inf = 0 \f$.
|
|
1268
|
+
*
|
|
1269
|
+
* All NaN values are represented by `std::numeric_limits<T>::quiet_NaN()` independently if
|
|
1270
|
+
* `std::numeric_limits<T>::has_quiet_NaN` is true or not.
|
|
1271
|
+
*
|
|
1272
|
+
* @tparam ValueRange Range with a begin() and end() method.
|
|
1273
|
+
* @param r First element of the division.
|
|
1274
|
+
* @param f Second element of the division.
|
|
1275
|
+
*/
|
|
1276
|
+
template <class ValueRange,
|
|
1277
|
+
class = std::enable_if_t<RangeTraits<ValueRange>::has_begin &&
|
|
1278
|
+
!std::is_same_v<ValueRange, Degree_rips_bifiltration> > >
|
|
1279
|
+
friend Degree_rips_bifiltration operator/(const ValueRange &r, Degree_rips_bifiltration f)
|
|
1280
|
+
{
|
|
1281
|
+
if (r.begin() == r.end()) return 1 / f;
|
|
1282
|
+
return *(r.begin()) / f;
|
|
1283
|
+
}
|
|
1284
|
+
|
|
1285
|
+
/**
|
|
1286
|
+
* @brief Returns a filtration value such that an entry at index \f$ (g,0) \f$ is equal to \f$ f(g,0) / val \f$.
|
|
1287
|
+
*
|
|
1288
|
+
* Used conventions:
|
|
1289
|
+
* - \f$ a / 0 = NaN \f$,
|
|
1290
|
+
* - \f$ inf / inf = NaN \f$,
|
|
1291
|
+
* - \f$ -inf / inf = NaN \f$,
|
|
1292
|
+
* - \f$ inf / -inf = NaN \f$,
|
|
1293
|
+
* - \f$ -inf / -inf = NaN \f$,
|
|
1294
|
+
* - \f$ NaN / b = NaN \f$,
|
|
1295
|
+
* - \f$ a / NaN = NaN \f$,
|
|
1296
|
+
* - \f$ a / inf = 0 \f$,
|
|
1297
|
+
* - \f$ a / -inf = 0 \f$.
|
|
1298
|
+
*
|
|
1299
|
+
* All NaN values are represented by `std::numeric_limits<T>::quiet_NaN()` independently if
|
|
1300
|
+
* `std::numeric_limits<T>::has_quiet_NaN` is true or not.
|
|
1301
|
+
*
|
|
1302
|
+
* @param f First element of the division.
|
|
1303
|
+
* @param val Second element of the division.
|
|
1304
|
+
*/
|
|
1305
|
+
friend Degree_rips_bifiltration operator/(Degree_rips_bifiltration f, const T &val)
|
|
1306
|
+
{
|
|
1307
|
+
f /= val;
|
|
1308
|
+
return f;
|
|
1309
|
+
}
|
|
1310
|
+
|
|
1311
|
+
/**
|
|
1312
|
+
* @brief Returns a filtration value such that an entry at index \f$ (g,0) \f$ is equal to \f$ val / f(g,0) \f$.
|
|
1313
|
+
*
|
|
1314
|
+
* Used conventions:
|
|
1315
|
+
* - \f$ a / 0 = NaN \f$,
|
|
1316
|
+
* - \f$ inf / inf = NaN \f$,
|
|
1317
|
+
* - \f$ -inf / inf = NaN \f$,
|
|
1318
|
+
* - \f$ inf / -inf = NaN \f$,
|
|
1319
|
+
* - \f$ -inf / -inf = NaN \f$,
|
|
1320
|
+
* - \f$ NaN / b = NaN \f$,
|
|
1321
|
+
* - \f$ a / NaN = NaN \f$,
|
|
1322
|
+
* - \f$ a / inf = 0 \f$,
|
|
1323
|
+
* - \f$ a / -inf = 0 \f$.
|
|
1324
|
+
*
|
|
1325
|
+
* All NaN values are represented by `std::numeric_limits<T>::quiet_NaN()` independently if
|
|
1326
|
+
* `std::numeric_limits<T>::has_quiet_NaN` is true or not.
|
|
1327
|
+
*
|
|
1328
|
+
* @param val First element of the division.
|
|
1329
|
+
* @param f Second element of the division.
|
|
1330
|
+
*/
|
|
1331
|
+
friend Degree_rips_bifiltration operator/(const T &val, Degree_rips_bifiltration f)
|
|
1332
|
+
{
|
|
1333
|
+
f._apply_operation(val, [](T &valF, const T &valR) {
|
|
1334
|
+
T tmp = valF;
|
|
1335
|
+
valF = valR;
|
|
1336
|
+
_divide(valF, tmp);
|
|
1337
|
+
});
|
|
1338
|
+
return f;
|
|
1339
|
+
}
|
|
1340
|
+
|
|
1341
|
+
/**
|
|
1342
|
+
* @brief Modifies the first parameter such that an entry at index \f$ (g,0) \f$, with
|
|
1343
|
+
* \f$ 0 \leq g \leq num_generators \f$ is equal to \f$ f(g,0) / r(0) \f$
|
|
1344
|
+
* if \f$ 0 < length_r \f$ and to \f$ f(g,0) \f$ otherwise.
|
|
1345
|
+
*
|
|
1346
|
+
* Used conventions:
|
|
1347
|
+
* - \f$ a / 0 = NaN \f$,
|
|
1348
|
+
* - \f$ inf / inf = NaN \f$,
|
|
1349
|
+
* - \f$ -inf / inf = NaN \f$,
|
|
1350
|
+
* - \f$ inf / -inf = NaN \f$,
|
|
1351
|
+
* - \f$ -inf / -inf = NaN \f$,
|
|
1352
|
+
* - \f$ NaN / b = NaN \f$,
|
|
1353
|
+
* - \f$ a / NaN = NaN \f$,
|
|
1354
|
+
* - \f$ a / inf = 0 \f$,
|
|
1355
|
+
* - \f$ a / -inf = 0 \f$.
|
|
1356
|
+
*
|
|
1357
|
+
* All NaN values are represented by `std::numeric_limits<T>::quiet_NaN()` independently if
|
|
1358
|
+
* `std::numeric_limits<T>::has_quiet_NaN` is true or not.
|
|
1359
|
+
*
|
|
1360
|
+
* @tparam ValueRange Range with a begin() and end() method.
|
|
1361
|
+
* @param f First element of the division.
|
|
1362
|
+
* @param r Second element of the division.
|
|
1363
|
+
*/
|
|
1364
|
+
template <class ValueRange, class = std::enable_if_t<RangeTraits<ValueRange>::has_begin> >
|
|
1365
|
+
friend Degree_rips_bifiltration &operator/=(Degree_rips_bifiltration &f, const ValueRange &r)
|
|
1366
|
+
{
|
|
1367
|
+
if (r.begin() == r.end()) return f;
|
|
1368
|
+
f /= *(r.begin());
|
|
1369
|
+
return f;
|
|
1370
|
+
}
|
|
1371
|
+
|
|
1372
|
+
/**
|
|
1373
|
+
* @brief Modifies the first parameter such that an entry at index \f$ (g,0) \f$ is equal to \f$ f(g,0) / val \f$.
|
|
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
|
+
* @param f First element of the division.
|
|
1390
|
+
* @param val Second element of the division.
|
|
1391
|
+
*/
|
|
1392
|
+
friend Degree_rips_bifiltration &operator/=(Degree_rips_bifiltration &f, const T &val)
|
|
1393
|
+
{
|
|
1394
|
+
f._apply_operation(val, [](T &valF, const T &valR) { _divide(valF, valR); });
|
|
1395
|
+
return f;
|
|
1396
|
+
}
|
|
1397
|
+
|
|
1398
|
+
// MODIFIERS
|
|
1399
|
+
|
|
1400
|
+
/**
|
|
1401
|
+
* @brief Sets the number of generators. If there were less generators before, new generators with default values are
|
|
1402
|
+
* constructed. If there were more generators before, the exceed of generators is destroyed (any generator with index
|
|
1403
|
+
* higher or equal to @p g to be more precise). If @p g is zero, the methods does nothing.
|
|
1404
|
+
*
|
|
1405
|
+
* Fails to compile if `Ensure1Criticality` is true.
|
|
1406
|
+
*
|
|
1407
|
+
* @param g New number of generators.
|
|
1408
|
+
*/
|
|
1409
|
+
void set_num_generators(size_type g)
|
|
1410
|
+
{
|
|
1411
|
+
static_assert(!Ensure1Criticality, "Number of generators cannot be set for a 1-critical only filtration value.");
|
|
1412
|
+
|
|
1413
|
+
if (g == 0) return;
|
|
1414
|
+
generators_.resize(g, _get_default_value());
|
|
1415
|
+
}
|
|
1416
|
+
|
|
1417
|
+
/**
|
|
1418
|
+
* @brief Adds the given generator to the filtration value.
|
|
1419
|
+
*
|
|
1420
|
+
* It is possible that the generator is ignored if the first parameter is overshadowed by an already existing
|
|
1421
|
+
* generator with same second parameter. This would mean that adding the given generator will not span more
|
|
1422
|
+
* "lifetime" and therefore there is no need to store it.
|
|
1423
|
+
*
|
|
1424
|
+
* Let \f$ max_idx \$f be the highest second parameter stored so far. If the given second parameter \f$ i \$f to add
|
|
1425
|
+
* is strictly higher than \f$ max_idx + 1 \$f, all possible values between \f$ max_idx \$f and \f$ i \$f will also
|
|
1426
|
+
* be added and the corresponding first parameters will be initialized with -inf if `Co` is false and with +inf
|
|
1427
|
+
* if `Co` is true.
|
|
1428
|
+
*
|
|
1429
|
+
* @tparam GeneratorRange Range of elements convertible to `T`. Must have a begin(), end() method and the iterator
|
|
1430
|
+
* type should satisfy the requirements of the standard `LegacyForwardIterator`.
|
|
1431
|
+
* @param x New generator to add. Has to have the 2 parameters.
|
|
1432
|
+
* @return true If and only if the generator is actually added to the set of generators.
|
|
1433
|
+
* @return false Otherwise.
|
|
1434
|
+
*/
|
|
1435
|
+
template <class GeneratorRange = std::initializer_list<T>,
|
|
1436
|
+
class = std::enable_if_t<RangeTraits<GeneratorRange>::has_begin> >
|
|
1437
|
+
bool add_generator(const GeneratorRange &x)
|
|
1438
|
+
{
|
|
1439
|
+
return add_generator(x.begin(), x.end());
|
|
1440
|
+
}
|
|
1441
|
+
|
|
1442
|
+
/**
|
|
1443
|
+
* @brief Adds the given generator to the filtration value.
|
|
1444
|
+
*
|
|
1445
|
+
* It is possible that the generator is ignored if the first parameter is overshadowed by an already existing
|
|
1446
|
+
* generator with same second parameter. This would mean that adding the given generator will not span more
|
|
1447
|
+
* "lifetime" and therefore there is no need to store it.
|
|
1448
|
+
*
|
|
1449
|
+
* Let \f$ max_idx \$f be the highest second parameter stored so far. If the given second parameter \f$ i \$f to add
|
|
1450
|
+
* is strictly higher than \f$ max_idx + 1 \$f, all possible values between \f$ max_idx \$f and \f$ i \$f will also
|
|
1451
|
+
* be added and the corresponding first parameters will be initialized with inf if `Co` is false and with -inf
|
|
1452
|
+
* if `Co` is true.
|
|
1453
|
+
*
|
|
1454
|
+
* @tparam Iterator Iterator class satisfying the requirements of the standard `LegacyForwardIterator`.
|
|
1455
|
+
* The dereferenced type has to be convertible to `T`.
|
|
1456
|
+
* @param genStart Iterator pointing to the begining of the range of two elements.
|
|
1457
|
+
* @param genEnd Iterator pointing to the end of the range.
|
|
1458
|
+
* @return true If and only if the generator is actually added to the set of generators.
|
|
1459
|
+
* @return false Otherwise.
|
|
1460
|
+
*/
|
|
1461
|
+
template <class Iterator>
|
|
1462
|
+
bool add_generator(Iterator genStart, [[maybe_unused]] Iterator genEnd)
|
|
1463
|
+
{
|
|
1464
|
+
GUDHI_CHECK(std::distance(genStart, genEnd) == 2,
|
|
1465
|
+
std::invalid_argument("Wrong range size. Should correspond to the number of parameters."));
|
|
1466
|
+
|
|
1467
|
+
const T val = *genStart;
|
|
1468
|
+
++genStart;
|
|
1469
|
+
const size_type index = *genStart;
|
|
1470
|
+
|
|
1471
|
+
GUDHI_CHECK(index >= 0, std::invalid_argument("Second parameter has to be a positive index."));
|
|
1472
|
+
|
|
1473
|
+
if (_is_nan(val)) return false;
|
|
1474
|
+
|
|
1475
|
+
if (index < generators_.size()) {
|
|
1476
|
+
if (_dominates(val, generators_[index])) return false;
|
|
1477
|
+
generators_[index] = val;
|
|
1478
|
+
return true;
|
|
1479
|
+
}
|
|
1480
|
+
|
|
1481
|
+
if constexpr (Ensure1Criticality) {
|
|
1482
|
+
if (index != 0) throw std::logic_error("Cannot add additional generator to a 1-critical only filtration value.");
|
|
1483
|
+
}
|
|
1484
|
+
|
|
1485
|
+
generators_.resize(index + 1, _get_default_minus_value());
|
|
1486
|
+
generators_[index] = val;
|
|
1487
|
+
return true;
|
|
1488
|
+
}
|
|
1489
|
+
|
|
1490
|
+
/**
|
|
1491
|
+
* @brief Same as @ref add_generator "".
|
|
1492
|
+
*/
|
|
1493
|
+
template <class GeneratorRange = std::initializer_list<T>,
|
|
1494
|
+
class = std::enable_if_t<RangeTraits<GeneratorRange>::has_begin> >
|
|
1495
|
+
void add_guaranteed_generator(const GeneratorRange &x)
|
|
1496
|
+
{
|
|
1497
|
+
add_generator(x.begin(), x.end());
|
|
1498
|
+
}
|
|
1499
|
+
|
|
1500
|
+
/**
|
|
1501
|
+
* @brief Does nothing, only for interface purposes.
|
|
1502
|
+
*/
|
|
1503
|
+
void simplify() {}
|
|
1504
|
+
|
|
1505
|
+
/**
|
|
1506
|
+
* @brief Does nothing, only for interface purposes.
|
|
1507
|
+
*/
|
|
1508
|
+
void remove_empty_generators([[maybe_unused]] bool include_infinities = false) {}
|
|
1509
|
+
|
|
1510
|
+
/**
|
|
1511
|
+
* @brief Let \f$ g_c \f$ be the positive cone generated by the generator \f$ g \f$ of the filtration value. And let
|
|
1512
|
+
* \f$ x_c \f$ be the positive cone generated by the given point \f$ x \f$. For each generator \f$ g \f$ of the
|
|
1513
|
+
* filtration value such that \f$ g_c \f$ strictly contains \f$ x_c \f$, pushes it to the border of \f$ x_c \f$.
|
|
1514
|
+
*
|
|
1515
|
+
* Say \f$ x = (val, idx) \f$. The second parameter \f$ idx \f$ is assumed to be positive.
|
|
1516
|
+
* Note also that, if `Co` is true, the filtration value cannot be pushed to \f$ (*,inf) \f$, and that,
|
|
1517
|
+
* if `Ensure1Criticality` is true, \f$ idx \f$ has to be \f$ 0 \f$.
|
|
1518
|
+
*
|
|
1519
|
+
* @tparam GeneratorRange Either a range of into `T` convertible elements with a begin(), end() and size() method,
|
|
1520
|
+
* or @ref Degree_rips_bifiltration<U,...> with `U` convertible into `T`.
|
|
1521
|
+
* @param x Range towards to push. Has to have 2 elements (all other elements above that count are ignored). If the
|
|
1522
|
+
* range is a @ref Degree_rips_bifiltration, the generator at second parameter 0 is chosen.
|
|
1523
|
+
* @param exclude_infinite_values If true, values at infinity or minus infinity are not affected.
|
|
1524
|
+
* @return true If the filtration value was actually modified.
|
|
1525
|
+
* @return false Otherwise.
|
|
1526
|
+
*/
|
|
1527
|
+
template <class GeneratorRange = std::initializer_list<value_type>,
|
|
1528
|
+
class = std::enable_if_t<RangeTraits<GeneratorRange>::has_begin> >
|
|
1529
|
+
bool push_to_least_common_upper_bound(const GeneratorRange &x, bool exclude_infinite_values = false)
|
|
1530
|
+
{
|
|
1531
|
+
if (is_nan()) return false;
|
|
1532
|
+
|
|
1533
|
+
size_type start = 0;
|
|
1534
|
+
T startVal = 0;
|
|
1535
|
+
T xVal;
|
|
1536
|
+
|
|
1537
|
+
if constexpr (RangeTraits<GeneratorRange>::is_multi_filtration) {
|
|
1538
|
+
if (x.size() == 0) return false; // nan
|
|
1539
|
+
xVal = x(0,0);
|
|
1540
|
+
} else {
|
|
1541
|
+
GUDHI_CHECK(x.size() == 2,
|
|
1542
|
+
std::invalid_argument("Wrong range size. Should correspond to the number of parameters."));
|
|
1543
|
+
|
|
1544
|
+
auto it = x.begin();
|
|
1545
|
+
xVal = *it;
|
|
1546
|
+
++it;
|
|
1547
|
+
startVal = *it;
|
|
1548
|
+
if (startVal < 0) throw std::invalid_argument("Second parameter has to be a positive integer.");
|
|
1549
|
+
}
|
|
1550
|
+
|
|
1551
|
+
if (startVal == T_inf) {
|
|
1552
|
+
if constexpr (Co) {
|
|
1553
|
+
throw std::invalid_argument("Filtration values with negative cones cannot be pushed to (*,inf).");
|
|
1554
|
+
}
|
|
1555
|
+
if (is_plus_inf()) return false;
|
|
1556
|
+
// not exactly true, but the closest feasible representation
|
|
1557
|
+
*this = inf();
|
|
1558
|
+
return true;
|
|
1559
|
+
}
|
|
1560
|
+
start = startVal;
|
|
1561
|
+
if ((start == 0 && xVal == T_m_inf) || _is_nan(xVal)) return false;
|
|
1562
|
+
|
|
1563
|
+
if constexpr (Ensure1Criticality) {
|
|
1564
|
+
// TODO: we could at some point allow [(inf,0),...,(inf,n-1),(v,n)] as 1-critical, but it would make everything
|
|
1565
|
+
// more complicated and this class does not seem to be the right option to handle those cases anyway...
|
|
1566
|
+
if (start != 0)
|
|
1567
|
+
throw std::invalid_argument(
|
|
1568
|
+
"Pushing to an index other than 0 or inf is not permitted with Ensure1Criticality at true.");
|
|
1569
|
+
}
|
|
1570
|
+
|
|
1571
|
+
bool modified = false;
|
|
1572
|
+
T newVal = _get_default_minus_value();
|
|
1573
|
+
|
|
1574
|
+
for (size_type i = 0; i < std::min(start, generators_.size()); ++i){
|
|
1575
|
+
auto& v = generators_[i];
|
|
1576
|
+
if (!_is_nan(v) && (!exclude_infinite_values || (v != T_inf && v != T_m_inf))){
|
|
1577
|
+
T threshold = std::max(v, xVal);
|
|
1578
|
+
if (_dominates(newVal, threshold)) newVal = threshold;
|
|
1579
|
+
if (v != _get_default_minus_value()) {
|
|
1580
|
+
modified = true;
|
|
1581
|
+
v = _get_default_minus_value();
|
|
1582
|
+
}
|
|
1583
|
+
}
|
|
1584
|
+
}
|
|
1585
|
+
|
|
1586
|
+
if (start < generators_.size()){
|
|
1587
|
+
auto& vs = generators_[start];
|
|
1588
|
+
T threshold = std::max(vs, xVal);
|
|
1589
|
+
if (_dominates(newVal, threshold)) newVal = threshold;
|
|
1590
|
+
if (newVal != vs) {
|
|
1591
|
+
modified = true;
|
|
1592
|
+
vs = newVal;
|
|
1593
|
+
}
|
|
1594
|
+
|
|
1595
|
+
for (size_type i = start + 1; i < generators_.size(); ++i) {
|
|
1596
|
+
auto& v = generators_[i];
|
|
1597
|
+
if (!_is_nan(v) && v < xVal && (!exclude_infinite_values || (v != T_inf && v != T_m_inf))) {
|
|
1598
|
+
modified = true;
|
|
1599
|
+
v = xVal;
|
|
1600
|
+
}
|
|
1601
|
+
}
|
|
1602
|
+
} else {
|
|
1603
|
+
modified = true;
|
|
1604
|
+
generators_.resize(start + 1, _get_default_minus_value());
|
|
1605
|
+
generators_[start] = newVal;
|
|
1606
|
+
}
|
|
1607
|
+
|
|
1608
|
+
if (is_plus_inf()) *this = inf();
|
|
1609
|
+
|
|
1610
|
+
return modified;
|
|
1611
|
+
}
|
|
1612
|
+
|
|
1613
|
+
/**
|
|
1614
|
+
* @brief Let \f$ g_c \f$ be the negative cone generated by the generator \f$ g \f$ of the filtration value. And let
|
|
1615
|
+
* \f$ x_c \f$ be the negative cone generated by the given point \f$ x \f$. For each generator \f$ g \f$ of the
|
|
1616
|
+
* filtration value such that \f$ g_c \f$ strictly contains \f$ x_c \f$, pulls it to the border of \f$ x_c \f$.
|
|
1617
|
+
*
|
|
1618
|
+
* Say \f$ x = (val, idx) \f$. The second parameter \f$ idx \f$ is assumed to be positive.
|
|
1619
|
+
*
|
|
1620
|
+
* @tparam GeneratorRange Either a range of into `T` convertible elements with a begin(), end() and size() method,
|
|
1621
|
+
* or @ref Degree_rips_bifiltration<U,...> with `U` convertible into `T`.
|
|
1622
|
+
* @param x Range towards to push. Has to have 2 elements (all other elements above that count are ignored). If the
|
|
1623
|
+
* range is a @ref Degree_rips_bifiltration, the generator at second parameter 0 is chosen.
|
|
1624
|
+
* @param exclude_infinite_values If true, values at infinity or minus infinity are not affected.
|
|
1625
|
+
* @return true If the filtration value was actually modified.
|
|
1626
|
+
* @return false Otherwise.
|
|
1627
|
+
*/
|
|
1628
|
+
template <class GeneratorRange = std::initializer_list<value_type>,
|
|
1629
|
+
class = std::enable_if_t<RangeTraits<GeneratorRange>::has_begin> >
|
|
1630
|
+
bool pull_to_greatest_common_lower_bound(const GeneratorRange &x, bool exclude_infinite_values = false)
|
|
1631
|
+
{
|
|
1632
|
+
if (is_nan()) return false;
|
|
1633
|
+
|
|
1634
|
+
size_type end;
|
|
1635
|
+
T endVal = 0;
|
|
1636
|
+
T xVal;
|
|
1637
|
+
|
|
1638
|
+
if constexpr (RangeTraits<GeneratorRange>::is_multi_filtration) {
|
|
1639
|
+
if (x.size() == 0) return false; // nan
|
|
1640
|
+
xVal = x(0,0);
|
|
1641
|
+
} else {
|
|
1642
|
+
GUDHI_CHECK(x.size() == 2,
|
|
1643
|
+
std::invalid_argument("Wrong range size. Should correspond to the number of parameters."));
|
|
1644
|
+
|
|
1645
|
+
auto it = x.begin();
|
|
1646
|
+
xVal = *it;
|
|
1647
|
+
++it;
|
|
1648
|
+
endVal = *it;
|
|
1649
|
+
}
|
|
1650
|
+
|
|
1651
|
+
if (endVal < 0) throw std::invalid_argument("Second parameter has to be a positive integer.");
|
|
1652
|
+
if (endVal == T_inf) end = generators_.size();
|
|
1653
|
+
else end = endVal;
|
|
1654
|
+
|
|
1655
|
+
if ((end >= generators_.size() - 1 && xVal == T_inf) || _is_nan(xVal)) return false;
|
|
1656
|
+
|
|
1657
|
+
bool modified = false;
|
|
1658
|
+
T newVal = _get_default_minus_value();
|
|
1659
|
+
|
|
1660
|
+
for (size_type i = 0; i < std::min(end, generators_.size()); ++i) {
|
|
1661
|
+
auto &v = generators_[i];
|
|
1662
|
+
if (!_is_nan(v) && v > xVal && (!exclude_infinite_values || (v != T_inf && v != T_m_inf))) {
|
|
1663
|
+
modified = true;
|
|
1664
|
+
v = xVal;
|
|
1665
|
+
}
|
|
1666
|
+
}
|
|
1667
|
+
|
|
1668
|
+
if (end < generators_.size()) {
|
|
1669
|
+
for (size_type i = end; i < generators_.size(); ++i) {
|
|
1670
|
+
auto v = generators_[i];
|
|
1671
|
+
if (!_is_nan(v) && (!exclude_infinite_values || (v != T_inf && v != T_m_inf))){
|
|
1672
|
+
T threshold = std::min(v, xVal);
|
|
1673
|
+
if (_dominates(newVal, threshold)) newVal = threshold;
|
|
1674
|
+
}
|
|
1675
|
+
}
|
|
1676
|
+
|
|
1677
|
+
modified |= (end + 1) != generators_.size();
|
|
1678
|
+
generators_.resize(end + 1);
|
|
1679
|
+
|
|
1680
|
+
modified |= generators_[end] != newVal;
|
|
1681
|
+
generators_[end] = newVal;
|
|
1682
|
+
}
|
|
1683
|
+
|
|
1684
|
+
return modified;
|
|
1685
|
+
}
|
|
1686
|
+
|
|
1687
|
+
/**
|
|
1688
|
+
* @brief Projects the filtration value into the given grid. If @p coordinate is false, the entries are set to
|
|
1689
|
+
* the nearest upper bound value with the same parameter in the grid. Otherwise, the entries are set to the indices
|
|
1690
|
+
* of those nearest upper bound values.
|
|
1691
|
+
* The grid has to be represented as a vector of ordered ranges of values convertible into `T`. An index
|
|
1692
|
+
* \f$ i \f$ of the vector corresponds to the same parameter as the index \f$ i \f$ in a generator of the filtration
|
|
1693
|
+
* value. The ranges correspond to the possible values of the parameters, ordered by increasing value, forming
|
|
1694
|
+
* therefore all together a 2D grid. The range of the second parameter has to start at 0 and continue continuously.
|
|
1695
|
+
*
|
|
1696
|
+
* @tparam OneDimArray A range of values convertible into `T` ordered by increasing value. Has to implement
|
|
1697
|
+
* a begin, end and operator[] method.
|
|
1698
|
+
* @param grid Vector of @p OneDimArray with size at least 2.
|
|
1699
|
+
* @param coordinate If true, the values are set to the coordinates of the projection in the grid. If false,
|
|
1700
|
+
* the values are set to the values at the coordinates of the projection.
|
|
1701
|
+
*/
|
|
1702
|
+
template <typename OneDimArray>
|
|
1703
|
+
void project_onto_grid(const std::vector<OneDimArray> &grid, bool coordinate = true)
|
|
1704
|
+
{
|
|
1705
|
+
GUDHI_CHECK(
|
|
1706
|
+
grid.size() >= 2,
|
|
1707
|
+
std::invalid_argument("The grid should not be smaller than the number of parameters in the filtration value."));
|
|
1708
|
+
|
|
1709
|
+
GUDHI_CHECK_code(const OneDimArray &indices = grid[1]);
|
|
1710
|
+
const OneDimArray &values = grid[0];
|
|
1711
|
+
auto todo = [&](size_type g) {
|
|
1712
|
+
GUDHI_CHECK_code(GUDHI_CHECK(static_cast<size_type>(indices[g]) == g, std::invalid_argument("Unvalid grid.")));
|
|
1713
|
+
|
|
1714
|
+
auto v = static_cast<typename OneDimArray::value_type>(generators_[g]);
|
|
1715
|
+
auto d = std::distance(values.begin(), std::lower_bound(values.begin(), values.end(), v));
|
|
1716
|
+
if (d != 0 && std::abs(v - values[d]) > std::abs(v - values[d - 1])) {
|
|
1717
|
+
--d;
|
|
1718
|
+
}
|
|
1719
|
+
generators_[g] = coordinate ? static_cast<T>(d) : static_cast<T>(values[d]);
|
|
1720
|
+
};
|
|
1721
|
+
#ifdef GUDHI_USE_TBB
|
|
1722
|
+
tbb::parallel_for(size_type{0}, num_generators(), [&](size_type g) { todo(g); });
|
|
1723
|
+
#else
|
|
1724
|
+
for (size_type g = 0; g < num_generators(); ++g) {
|
|
1725
|
+
todo(g);
|
|
1726
|
+
}
|
|
1727
|
+
#endif
|
|
1728
|
+
}
|
|
1729
|
+
|
|
1730
|
+
// FONCTIONNALITIES
|
|
1731
|
+
|
|
1732
|
+
/**
|
|
1733
|
+
* @brief Returns the filtration value that is the greatest lower bound of all generators.
|
|
1734
|
+
*/
|
|
1735
|
+
friend Degree_rips_bifiltration factorize_below(const Degree_rips_bifiltration &f)
|
|
1736
|
+
{
|
|
1737
|
+
if (f.num_generators() <= 1) return f;
|
|
1738
|
+
|
|
1739
|
+
bool nan = true;
|
|
1740
|
+
size_type idx = f.num_generators();
|
|
1741
|
+
T val = T_inf;
|
|
1742
|
+
|
|
1743
|
+
if constexpr (Co) {
|
|
1744
|
+
// -inf are "non existing" generators if not all of them are at -inf
|
|
1745
|
+
bool inf = true;
|
|
1746
|
+
for (size_type g = 0; g < f.num_generators(); ++g) {
|
|
1747
|
+
T v = f.generators_[g];
|
|
1748
|
+
if (!_is_nan(v) && v != T_m_inf) {
|
|
1749
|
+
nan = false;
|
|
1750
|
+
inf = false;
|
|
1751
|
+
val = v < val ? v : val;
|
|
1752
|
+
idx = g < idx ? g : idx;
|
|
1753
|
+
} else if (_is_nan(v)) {
|
|
1754
|
+
inf = false;
|
|
1755
|
+
} else {
|
|
1756
|
+
nan = false;
|
|
1757
|
+
}
|
|
1758
|
+
}
|
|
1759
|
+
if (inf) return Degree_rips_bifiltration::minus_inf();
|
|
1760
|
+
} else {
|
|
1761
|
+
idx = 0;
|
|
1762
|
+
for (const T &v : f.generators_) {
|
|
1763
|
+
if (!_is_nan(v)) {
|
|
1764
|
+
nan = false;
|
|
1765
|
+
val = v < val ? v : val;
|
|
1766
|
+
}
|
|
1767
|
+
}
|
|
1768
|
+
}
|
|
1769
|
+
|
|
1770
|
+
if (nan) return Degree_rips_bifiltration::nan();
|
|
1771
|
+
|
|
1772
|
+
Underlying_container result(idx + 1, _get_default_minus_value());
|
|
1773
|
+
result[idx] = val;
|
|
1774
|
+
return Degree_rips_bifiltration(std::move(result), 2);
|
|
1775
|
+
}
|
|
1776
|
+
|
|
1777
|
+
/**
|
|
1778
|
+
* @brief Returns the filtration value that is the least upper bound of all generators.
|
|
1779
|
+
*/
|
|
1780
|
+
friend Degree_rips_bifiltration factorize_above(const Degree_rips_bifiltration &f)
|
|
1781
|
+
{
|
|
1782
|
+
if (f.num_generators() <= 1) return f;
|
|
1783
|
+
|
|
1784
|
+
bool nan = true;
|
|
1785
|
+
size_type idx = 0;
|
|
1786
|
+
T val = T_m_inf;
|
|
1787
|
+
|
|
1788
|
+
if constexpr (Co) {
|
|
1789
|
+
idx = f.num_generators() - 1;
|
|
1790
|
+
for (const T &v : f.generators_) {
|
|
1791
|
+
if (!_is_nan(v)) {
|
|
1792
|
+
nan = false;
|
|
1793
|
+
val = v > val ? v : val;
|
|
1794
|
+
}
|
|
1795
|
+
}
|
|
1796
|
+
} else {
|
|
1797
|
+
// inf are "non existing" generators if not all of them are at inf
|
|
1798
|
+
bool inf = true;
|
|
1799
|
+
for (size_type g = 0; g < f.num_generators(); ++g) {
|
|
1800
|
+
T v = f.generators_[g];
|
|
1801
|
+
if (!_is_nan(v) && v != T_inf) {
|
|
1802
|
+
nan = false;
|
|
1803
|
+
inf = false;
|
|
1804
|
+
val = v > val ? v : val;
|
|
1805
|
+
idx = g > idx ? g : idx;
|
|
1806
|
+
} else if (_is_nan(v)) {
|
|
1807
|
+
inf = false;
|
|
1808
|
+
} else {
|
|
1809
|
+
nan = false;
|
|
1810
|
+
}
|
|
1811
|
+
}
|
|
1812
|
+
if (inf) return Degree_rips_bifiltration::inf();
|
|
1813
|
+
}
|
|
1814
|
+
|
|
1815
|
+
if (nan) return Degree_rips_bifiltration::nan();
|
|
1816
|
+
|
|
1817
|
+
Underlying_container result(idx + 1, _get_default_minus_value());
|
|
1818
|
+
result[idx] = val;
|
|
1819
|
+
return Degree_rips_bifiltration(std::move(result), 2);
|
|
1820
|
+
}
|
|
1821
|
+
|
|
1822
|
+
/**
|
|
1823
|
+
* @brief Computes the smallest (resp. the greatest if `Co` is true) scalar product of the all generators with the
|
|
1824
|
+
* given vector.
|
|
1825
|
+
*
|
|
1826
|
+
* @tparam U Arithmetic type of the result. Default value: `T`.
|
|
1827
|
+
* @param f Filtration value.
|
|
1828
|
+
* @param x Vector of coefficients.
|
|
1829
|
+
* @return Scalar product of @p f with @p x.
|
|
1830
|
+
*/
|
|
1831
|
+
template <typename U = T>
|
|
1832
|
+
friend U compute_linear_projection(const Degree_rips_bifiltration &f, const std::vector<U> &x)
|
|
1833
|
+
{
|
|
1834
|
+
auto project_generator = [&](size_type g) -> U {
|
|
1835
|
+
U projection = 0;
|
|
1836
|
+
std::size_t size = std::min(x.size(), Degree_rips_bifiltration::num_parameters());
|
|
1837
|
+
for (std::size_t i = 0; i < size; i++) projection += x[i] * static_cast<U>(f(g, i));
|
|
1838
|
+
return projection;
|
|
1839
|
+
};
|
|
1840
|
+
|
|
1841
|
+
if (f.num_generators() == 1) return project_generator(0);
|
|
1842
|
+
|
|
1843
|
+
#ifdef GUDHI_USE_TBB
|
|
1844
|
+
std::vector<U> projections(f.num_generators());
|
|
1845
|
+
tbb::parallel_for(size_type{0}, f.num_generators(), [&](size_type g) {
|
|
1846
|
+
projections[g] = project_generator(g);
|
|
1847
|
+
});
|
|
1848
|
+
if constexpr (Co) {
|
|
1849
|
+
return *std::max_element(projections.begin(), projections.end());
|
|
1850
|
+
} else {
|
|
1851
|
+
return *std::min_element(projections.begin(), projections.end());
|
|
1852
|
+
}
|
|
1853
|
+
#else
|
|
1854
|
+
if constexpr (Co) {
|
|
1855
|
+
U projection = std::numeric_limits<U>::lowest();
|
|
1856
|
+
for (size_type g = 0; g < f.num_generators(); ++g) {
|
|
1857
|
+
// Order in the max important to spread possible NaNs
|
|
1858
|
+
projection = std::max(project_generator(g), projection);
|
|
1859
|
+
}
|
|
1860
|
+
return projection;
|
|
1861
|
+
} else {
|
|
1862
|
+
U projection = std::numeric_limits<U>::max();
|
|
1863
|
+
for (size_type g = 0; g < f.num_generators(); ++g) {
|
|
1864
|
+
// Order in the min important to spread possible NaNs
|
|
1865
|
+
projection = std::min(project_generator(g), projection);
|
|
1866
|
+
}
|
|
1867
|
+
return projection;
|
|
1868
|
+
}
|
|
1869
|
+
#endif
|
|
1870
|
+
}
|
|
1871
|
+
|
|
1872
|
+
/**
|
|
1873
|
+
* @brief Computes the euclidean distance from the first parameter to the second parameter as the minimum of
|
|
1874
|
+
* all Euclidean distances between a generator of @p f and a generator of @p other.
|
|
1875
|
+
*
|
|
1876
|
+
* @param f Source filtration value.
|
|
1877
|
+
* @param other Target filtration value.
|
|
1878
|
+
* @return Euclidean distance between @p f and @p other.
|
|
1879
|
+
*/
|
|
1880
|
+
template <typename U = T>
|
|
1881
|
+
friend U compute_euclidean_distance_to(const Degree_rips_bifiltration &f, const Degree_rips_bifiltration &other)
|
|
1882
|
+
{
|
|
1883
|
+
// TODO: verify if this really makes a differences in the 1-critical case, otherwise just keep the general case
|
|
1884
|
+
if constexpr (Ensure1Criticality) {
|
|
1885
|
+
return _compute_frobenius_norm(Degree_rips_bifiltration::num_parameters(),
|
|
1886
|
+
[&](size_type p) -> T { return f(0, p) - other(0, p); });
|
|
1887
|
+
} else {
|
|
1888
|
+
U res = std::numeric_limits<U>::max();
|
|
1889
|
+
for (size_type g1 = 0; g1 < f.num_generators(); ++g1) {
|
|
1890
|
+
for (size_type g2 = 0; g2 < other.num_generators(); ++g2) {
|
|
1891
|
+
// Euclidean distance as a Frobenius norm with matrix 1 x p and values 'f(g1, p) - other(g2, p)'
|
|
1892
|
+
// Order in the min important to spread possible NaNs
|
|
1893
|
+
res = std::min(_compute_frobenius_norm(Degree_rips_bifiltration::num_parameters(),
|
|
1894
|
+
[&](size_type p) -> T { return f(g1, p) - other(g2, p); }),
|
|
1895
|
+
res);
|
|
1896
|
+
}
|
|
1897
|
+
}
|
|
1898
|
+
return res;
|
|
1899
|
+
}
|
|
1900
|
+
}
|
|
1901
|
+
|
|
1902
|
+
/**
|
|
1903
|
+
* @brief Computes the norm of the given filtration value.
|
|
1904
|
+
*
|
|
1905
|
+
* The filtration value is seen as a \f$ num_generators x num_parameters \f$ matrix and a standard Frobenius norm
|
|
1906
|
+
* is computed from it: the square root of the sum of the squares of all elements in the matrix.
|
|
1907
|
+
*
|
|
1908
|
+
* @param f Filtration value.
|
|
1909
|
+
* @return The norm of @p f.
|
|
1910
|
+
*/
|
|
1911
|
+
template <typename U = T>
|
|
1912
|
+
friend U compute_norm(const Degree_rips_bifiltration &f)
|
|
1913
|
+
{
|
|
1914
|
+
// Frobenius norm with matrix g x p based on Euclidean norm
|
|
1915
|
+
|
|
1916
|
+
if (f.num_generators() == 1) return f.generators_[0];
|
|
1917
|
+
|
|
1918
|
+
U out = 0;
|
|
1919
|
+
for (size_type g = 0; g < f.num_generators(); ++g) {
|
|
1920
|
+
out += g * g;
|
|
1921
|
+
out += f.generators_[g] * f.generators_[g];
|
|
1922
|
+
}
|
|
1923
|
+
|
|
1924
|
+
if constexpr (std::is_integral_v<U>) {
|
|
1925
|
+
// to avoid Windows issue that don't know how to cast integers for cmath methods
|
|
1926
|
+
return std::sqrt(static_cast<double>(out));
|
|
1927
|
+
} else {
|
|
1928
|
+
return std::sqrt(out);
|
|
1929
|
+
}
|
|
1930
|
+
}
|
|
1931
|
+
|
|
1932
|
+
/**
|
|
1933
|
+
* @brief Computes the coordinates in the given grid, corresponding to the nearest upper bounds of the entries
|
|
1934
|
+
* in the given filtration value.
|
|
1935
|
+
* The grid has to be represented as a vector of vectors of ordered values convertible into `OutValue`. An index
|
|
1936
|
+
* \f$ i \f$ of the vector corresponds to the same parameter as the index \f$ i \f$ in a generator of the filtration
|
|
1937
|
+
* value. The ranges correspond to the possible values of the parameters, ordered by increasing value, forming
|
|
1938
|
+
* therefore all together a 2D grid. The range of the second parameter has to start at 0 and continue continuously.
|
|
1939
|
+
*
|
|
1940
|
+
* @tparam OutValue Signed arithmetic type. Default value: std::int32_t.
|
|
1941
|
+
* @tparam U Type which is convertible into `OutValue`.
|
|
1942
|
+
* @param f Filtration value to project.
|
|
1943
|
+
* @param grid Vector of vectors to project into.
|
|
1944
|
+
* @return Filtration value \f$ out \f$ whose entry correspond to the indices of the projected values. That is,
|
|
1945
|
+
* the projection of \f$ f(g,p) \f$ is \f$ grid[p][out(g,p)] \f$.
|
|
1946
|
+
*/
|
|
1947
|
+
template <typename OutValue = std::int32_t, typename U = T>
|
|
1948
|
+
friend Degree_rips_bifiltration<OutValue, Co, Ensure1Criticality> compute_coordinates_in_grid(
|
|
1949
|
+
Degree_rips_bifiltration f,
|
|
1950
|
+
const std::vector<std::vector<U> > &grid)
|
|
1951
|
+
{
|
|
1952
|
+
// TODO: by replicating the code of "project_onto_grid", this could be done with just one copy
|
|
1953
|
+
// instead of two. But it is not clear if it is really worth it, i.e., how much the change in type is really
|
|
1954
|
+
// necessary in the use cases. To see later.
|
|
1955
|
+
f.project_onto_grid(grid);
|
|
1956
|
+
if constexpr (std::is_same_v<OutValue, T>) {
|
|
1957
|
+
return f;
|
|
1958
|
+
} else {
|
|
1959
|
+
return f.as_type<OutValue>();
|
|
1960
|
+
}
|
|
1961
|
+
}
|
|
1962
|
+
|
|
1963
|
+
/**
|
|
1964
|
+
* @brief Computes the values in the given grid corresponding to the coordinates given by the given filtration
|
|
1965
|
+
* value. That is, if \f$ out \f$ is the result, \f$ out(g,p) = grid[p][f(g,p)] \f$. Assumes therefore, that the
|
|
1966
|
+
* values stored in the filtration value corresponds to indices existing in the given grid.
|
|
1967
|
+
*
|
|
1968
|
+
* @tparam U Signed arithmetic type.
|
|
1969
|
+
* @param f Filtration value storing coordinates compatible with `grid`.
|
|
1970
|
+
* @param grid Vector of vector.
|
|
1971
|
+
* @return Filtration value \f$ out \f$ whose entry correspond to \f$ out(g,p) = grid[p][f(g,p)] \f$.
|
|
1972
|
+
*/
|
|
1973
|
+
template <typename U>
|
|
1974
|
+
friend Degree_rips_bifiltration<U, Co, Ensure1Criticality> evaluate_coordinates_in_grid(
|
|
1975
|
+
const Degree_rips_bifiltration &f,
|
|
1976
|
+
const std::vector<std::vector<U> > &grid)
|
|
1977
|
+
{
|
|
1978
|
+
GUDHI_CHECK(grid.size() >= f.num_parameters(),
|
|
1979
|
+
std::invalid_argument(
|
|
1980
|
+
"The size of the grid should correspond to the number of parameters in the filtration value."));
|
|
1981
|
+
|
|
1982
|
+
U grid_inf = Degree_rips_bifiltration<U, Co, Ensure1Criticality>::T_inf;
|
|
1983
|
+
std::vector<U> outVec(f.num_generators());
|
|
1984
|
+
|
|
1985
|
+
GUDHI_CHECK_code(const std::vector<U> &indices = grid[1]);
|
|
1986
|
+
const std::vector<U> &values = grid[0];
|
|
1987
|
+
for (size_type g = 0; g < f.num_generators(); ++g) {
|
|
1988
|
+
GUDHI_CHECK_code(GUDHI_CHECK(static_cast<size_type>(indices[g]) == g, std::invalid_argument("Unvalid grid.")));
|
|
1989
|
+
|
|
1990
|
+
const T &c = f.generators_[g];
|
|
1991
|
+
outVec[g] = (c == T_inf ? grid_inf : values[c]);
|
|
1992
|
+
}
|
|
1993
|
+
|
|
1994
|
+
return Degree_rips_bifiltration<U, Co, Ensure1Criticality>(std::move(outVec),
|
|
1995
|
+
Degree_rips_bifiltration::num_parameters());
|
|
1996
|
+
}
|
|
1997
|
+
|
|
1998
|
+
// UTILITIES
|
|
1999
|
+
|
|
2000
|
+
/**
|
|
2001
|
+
* @brief Outstream operator.
|
|
2002
|
+
*/
|
|
2003
|
+
friend std::ostream &operator<<(std::ostream &stream, const Degree_rips_bifiltration &f)
|
|
2004
|
+
{
|
|
2005
|
+
const size_type num_gen = f.num_generators();
|
|
2006
|
+
const size_type num_param = Degree_rips_bifiltration::num_parameters();
|
|
2007
|
+
|
|
2008
|
+
stream << "( k = " << num_gen << " ) [ ";
|
|
2009
|
+
for (size_type g = 0; g < num_gen; ++g) {
|
|
2010
|
+
stream << "[";
|
|
2011
|
+
for (size_type p = 0; p < num_param; ++p) {
|
|
2012
|
+
stream << f(g, p);
|
|
2013
|
+
if (p < num_param - 1) stream << ", ";
|
|
2014
|
+
}
|
|
2015
|
+
stream << "]";
|
|
2016
|
+
if (g < num_gen - 1) stream << "; ";
|
|
2017
|
+
}
|
|
2018
|
+
stream << " ]";
|
|
2019
|
+
|
|
2020
|
+
return stream;
|
|
2021
|
+
}
|
|
2022
|
+
|
|
2023
|
+
/**
|
|
2024
|
+
* @brief Instream operator.
|
|
2025
|
+
*/
|
|
2026
|
+
friend std::istream &operator>>(std::istream &stream, Degree_rips_bifiltration &f)
|
|
2027
|
+
{
|
|
2028
|
+
size_type num_gen;
|
|
2029
|
+
char delimiter;
|
|
2030
|
+
stream >> delimiter; // (
|
|
2031
|
+
stream >> delimiter; // k
|
|
2032
|
+
stream >> delimiter; // =
|
|
2033
|
+
if (delimiter != '=') throw std::invalid_argument("Invalid incoming stream format for Multi_parameter_generator.");
|
|
2034
|
+
stream >> num_gen;
|
|
2035
|
+
if (!stream.good()) throw std::invalid_argument("Invalid incoming stream format for Multi_parameter_generator.");
|
|
2036
|
+
f.generators_.resize(num_gen);
|
|
2037
|
+
stream >> delimiter; // )
|
|
2038
|
+
stream >> delimiter; // [
|
|
2039
|
+
if (delimiter != '[') throw std::invalid_argument("Invalid incoming stream format for Multi_parameter_generator.");
|
|
2040
|
+
if (num_gen == 0) return stream;
|
|
2041
|
+
T val;
|
|
2042
|
+
for (size_type i = 0; i < num_gen; ++i) {
|
|
2043
|
+
stream >> delimiter; // [
|
|
2044
|
+
val = _get_value<T>(stream);
|
|
2045
|
+
f.generators_[i] = val;
|
|
2046
|
+
stream >> delimiter; // ,
|
|
2047
|
+
stream >> val;
|
|
2048
|
+
if (val != static_cast<T>(i))
|
|
2049
|
+
throw std::invalid_argument("Invalid incoming stream format for Multi_parameter_generator.");
|
|
2050
|
+
if (!stream.good()) throw std::invalid_argument("Invalid incoming stream format for Multi_parameter_generator.");
|
|
2051
|
+
stream >> delimiter; // ]
|
|
2052
|
+
stream >> delimiter; // ; or last ]
|
|
2053
|
+
}
|
|
2054
|
+
if (delimiter != ']') throw std::invalid_argument("Invalid incoming stream format for Multi_parameter_generator.");
|
|
2055
|
+
|
|
2056
|
+
return stream;
|
|
2057
|
+
}
|
|
2058
|
+
|
|
2059
|
+
/**
|
|
2060
|
+
* @brief Returns true if and only if the given filtration value is at plus infinity.
|
|
2061
|
+
*/
|
|
2062
|
+
friend bool is_positive_infinity(const Degree_rips_bifiltration &f)
|
|
2063
|
+
{
|
|
2064
|
+
return f.is_plus_inf();
|
|
2065
|
+
}
|
|
2066
|
+
|
|
2067
|
+
/**
|
|
2068
|
+
* @brief Adds the generators of the second argument to the first argument.
|
|
2069
|
+
*
|
|
2070
|
+
* @param f1 Filtration value to modify.
|
|
2071
|
+
* @param f2 Filtration value to merge with the first one. Should have the same number of parameters than the other.
|
|
2072
|
+
* @return true If the first argument was actually modified.
|
|
2073
|
+
* @return false Otherwise.
|
|
2074
|
+
*/
|
|
2075
|
+
friend bool unify_lifetimes(Degree_rips_bifiltration &f1, const Degree_rips_bifiltration &f2)
|
|
2076
|
+
{
|
|
2077
|
+
bool modified = false;
|
|
2078
|
+
for (size_type g = 0; g < f2.num_generators(); ++g) {
|
|
2079
|
+
modified |= f1.add_generator({f2.generators_[g], static_cast<T>(g)});
|
|
2080
|
+
}
|
|
2081
|
+
return modified;
|
|
2082
|
+
}
|
|
2083
|
+
|
|
2084
|
+
/**
|
|
2085
|
+
* @brief Stores in the first argument the origins of the cones in the intersection of the positive
|
|
2086
|
+
* (negative if `Co` is true) cones generated by the two arguments.
|
|
2087
|
+
*
|
|
2088
|
+
* @param f1 First set of cones which will be modified.
|
|
2089
|
+
* @param f2 Second set of cones. Should have the same number of parameters than the first one.
|
|
2090
|
+
* @return true If the first argument was actually modified.
|
|
2091
|
+
* @return false Otherwise.
|
|
2092
|
+
*/
|
|
2093
|
+
friend bool intersect_lifetimes(Degree_rips_bifiltration &f1, const Degree_rips_bifiltration &f2)
|
|
2094
|
+
{
|
|
2095
|
+
if (f2.num_generators() == 0 || f1.num_generators() == 0) {
|
|
2096
|
+
Degree_rips_bifiltration res(2, _get_default_minus_value());
|
|
2097
|
+
swap(f1, res);
|
|
2098
|
+
return f1 != res;
|
|
2099
|
+
}
|
|
2100
|
+
|
|
2101
|
+
bool modified = false;
|
|
2102
|
+
T threshold1 = f1.generators_[0];
|
|
2103
|
+
T threshold2 = f2.generators_[0];
|
|
2104
|
+
for (size_type g = 0; g < std::max(f1.num_generators(), f2.num_generators()); ++g) {
|
|
2105
|
+
if (g < f1.num_generators())
|
|
2106
|
+
threshold1 = _strictly_dominates(threshold1, f1.generators_[g]) ? f1.generators_[g] : threshold1;
|
|
2107
|
+
else {
|
|
2108
|
+
f1.generators_.push_back(0);
|
|
2109
|
+
modified = true;
|
|
2110
|
+
}
|
|
2111
|
+
if (g < f2.num_generators())
|
|
2112
|
+
threshold2 = _strictly_dominates(threshold2, f2.generators_[g]) ? f2.generators_[g] : threshold2;
|
|
2113
|
+
if (_strictly_dominates(threshold2, threshold1)) {
|
|
2114
|
+
if (f1.generators_[g] != threshold2) modified = true;
|
|
2115
|
+
f1.generators_[g] = threshold2;
|
|
2116
|
+
} else {
|
|
2117
|
+
if (f1.generators_[g] != threshold1) modified = true;
|
|
2118
|
+
f1.generators_[g] = threshold1;
|
|
2119
|
+
}
|
|
2120
|
+
}
|
|
2121
|
+
|
|
2122
|
+
return modified;
|
|
2123
|
+
}
|
|
2124
|
+
|
|
2125
|
+
/**
|
|
2126
|
+
* @brief Serialize given value into the buffer at given pointer.
|
|
2127
|
+
*
|
|
2128
|
+
* @param value Value to serialize.
|
|
2129
|
+
* @param start Pointer to the start of the space in the buffer where to store the serialization.
|
|
2130
|
+
* @return End position of the serialization in the buffer.
|
|
2131
|
+
*/
|
|
2132
|
+
friend char *serialize_value_to_char_buffer(const Degree_rips_bifiltration &value, char *start)
|
|
2133
|
+
{
|
|
2134
|
+
const size_type length = value.generators_.size();
|
|
2135
|
+
const std::size_t arg_size = sizeof(T) * length;
|
|
2136
|
+
const std::size_t type_size = sizeof(size_type);
|
|
2137
|
+
memcpy(start, &length, type_size);
|
|
2138
|
+
memcpy(start + type_size, value.generators_.data(), arg_size);
|
|
2139
|
+
return start + arg_size + type_size;
|
|
2140
|
+
}
|
|
2141
|
+
|
|
2142
|
+
/**
|
|
2143
|
+
* @brief Deserialize the value from a buffer at given pointer and stores it in given value.
|
|
2144
|
+
*
|
|
2145
|
+
* @param value Value to fill with the deserialized filtration value.
|
|
2146
|
+
* @param start Pointer to the start of the space in the buffer where the serialization is stored.
|
|
2147
|
+
* @return End position of the serialization in the buffer.
|
|
2148
|
+
*/
|
|
2149
|
+
friend const char *deserialize_value_from_char_buffer(Degree_rips_bifiltration &value, const char *start)
|
|
2150
|
+
{
|
|
2151
|
+
const std::size_t type_size = sizeof(size_type);
|
|
2152
|
+
size_type length;
|
|
2153
|
+
memcpy(&length, start, type_size);
|
|
2154
|
+
std::size_t arg_size = sizeof(T) * length;
|
|
2155
|
+
value.generators_.resize(length);
|
|
2156
|
+
memcpy(value.generators_.data(), start + type_size, arg_size);
|
|
2157
|
+
return start + arg_size + type_size;
|
|
2158
|
+
}
|
|
2159
|
+
|
|
2160
|
+
/**
|
|
2161
|
+
* @brief Returns the serialization size of the given filtration value.
|
|
2162
|
+
*/
|
|
2163
|
+
friend std::size_t get_serialization_size_of(const Degree_rips_bifiltration &value)
|
|
2164
|
+
{
|
|
2165
|
+
return sizeof(size_type) + (sizeof(T) * value.generators_.size());
|
|
2166
|
+
}
|
|
2167
|
+
|
|
2168
|
+
/**
|
|
2169
|
+
* @brief Plus infinity value of an entry of the filtration value.
|
|
2170
|
+
*/
|
|
2171
|
+
constexpr static const T T_inf = MF_T_inf<T>;
|
|
2172
|
+
|
|
2173
|
+
/**
|
|
2174
|
+
* @brief Minus infinity value of an entry of the filtration value.
|
|
2175
|
+
*/
|
|
2176
|
+
constexpr static const T T_m_inf = MF_T_m_inf<T>;
|
|
2177
|
+
|
|
2178
|
+
private:
|
|
2179
|
+
Underlying_container generators_; /**< Container of the filtration value elements. */
|
|
2180
|
+
mutable T dummy_g_; /**< Dummy value for the first parameter, such that a reference can be returned. */
|
|
2181
|
+
|
|
2182
|
+
/**
|
|
2183
|
+
* @brief Default value of an element in the filtration value.
|
|
2184
|
+
*/
|
|
2185
|
+
constexpr static T _get_default_value() { return Co ? T_inf : T_m_inf; }
|
|
2186
|
+
constexpr static T _get_default_minus_value() { return Co ? T_m_inf : T_inf; }
|
|
2187
|
+
|
|
2188
|
+
// <
|
|
2189
|
+
static bool _compare_strict(size_type i, const Underlying_container &a, const Underlying_container &b, T threshold)
|
|
2190
|
+
{
|
|
2191
|
+
if (i >= b.size()) return true;
|
|
2192
|
+
if (_is_nan(b[i])) return false;
|
|
2193
|
+
|
|
2194
|
+
if (i >= a.size() && _strictly_dominates(threshold, b[i])) return false;
|
|
2195
|
+
if (i < a.size()) {
|
|
2196
|
+
if (_is_nan(a[i])) return false;
|
|
2197
|
+
threshold = _strictly_dominates(threshold, a[i]) ? a[i] : threshold;
|
|
2198
|
+
if (a[i] == threshold && b[i] == threshold) return false;
|
|
2199
|
+
}
|
|
2200
|
+
if (_strictly_dominates(threshold, b[i])) return false;
|
|
2201
|
+
|
|
2202
|
+
return _compare_strict(i + 1, a, b, threshold);
|
|
2203
|
+
}
|
|
2204
|
+
|
|
2205
|
+
// <=
|
|
2206
|
+
static bool _compare(size_type i, const Underlying_container &a, const Underlying_container &b, T threshold)
|
|
2207
|
+
{
|
|
2208
|
+
if (i >= b.size()) return true;
|
|
2209
|
+
if (_is_nan(b[i])) return false;
|
|
2210
|
+
|
|
2211
|
+
if (i >= a.size() && _strictly_dominates(threshold, b[i])) return false;
|
|
2212
|
+
if (i < a.size()) {
|
|
2213
|
+
if (_is_nan(a[i])) return false;
|
|
2214
|
+
threshold = _strictly_dominates(threshold, a[i]) ? a[i] : threshold;
|
|
2215
|
+
}
|
|
2216
|
+
if (_strictly_dominates(threshold, b[i])) return false;
|
|
2217
|
+
|
|
2218
|
+
return _compare(i + 1, a, b, threshold);
|
|
2219
|
+
}
|
|
2220
|
+
|
|
2221
|
+
static bool _strictly_dominates(T a, T b)
|
|
2222
|
+
{
|
|
2223
|
+
if constexpr (Co) {
|
|
2224
|
+
return a < b;
|
|
2225
|
+
} else {
|
|
2226
|
+
return a > b;
|
|
2227
|
+
}
|
|
2228
|
+
}
|
|
2229
|
+
|
|
2230
|
+
static bool _dominates(T a, T b)
|
|
2231
|
+
{
|
|
2232
|
+
if constexpr (Co) {
|
|
2233
|
+
return a <= b;
|
|
2234
|
+
} else {
|
|
2235
|
+
return a >= b;
|
|
2236
|
+
}
|
|
2237
|
+
}
|
|
2238
|
+
|
|
2239
|
+
/**
|
|
2240
|
+
* @brief Applies operation on the elements of the filtration value.
|
|
2241
|
+
*/
|
|
2242
|
+
template <class F>
|
|
2243
|
+
void _apply_operation(const T &val, F &&operate)
|
|
2244
|
+
{
|
|
2245
|
+
auto &gens = generators_;
|
|
2246
|
+
for (unsigned int i = 0; i < gens.size(); ++i) {
|
|
2247
|
+
std::forward<F>(operate)(gens[i], val);
|
|
2248
|
+
}
|
|
2249
|
+
}
|
|
2250
|
+
|
|
2251
|
+
template <class F, typename U = T>
|
|
2252
|
+
static U _compute_frobenius_norm(size_type number_of_elements, F &&norm)
|
|
2253
|
+
{
|
|
2254
|
+
if (number_of_elements == 1) return norm(0);
|
|
2255
|
+
|
|
2256
|
+
U out = 0;
|
|
2257
|
+
for (size_type p = 0; p < number_of_elements; ++p) {
|
|
2258
|
+
T v = std::forward<F>(norm)(p);
|
|
2259
|
+
out += v * v;
|
|
2260
|
+
}
|
|
2261
|
+
if constexpr (std::is_integral_v<U>) {
|
|
2262
|
+
// to avoid Windows issue that don't know how to cast integers for cmath methods
|
|
2263
|
+
return std::sqrt(static_cast<double>(out));
|
|
2264
|
+
} else {
|
|
2265
|
+
return std::sqrt(out);
|
|
2266
|
+
}
|
|
2267
|
+
}
|
|
2268
|
+
};
|
|
2269
|
+
|
|
2270
|
+
} // namespace Gudhi::multi_filtration
|
|
2271
|
+
|
|
2272
|
+
namespace std {
|
|
2273
|
+
|
|
2274
|
+
template <typename T, bool Co, bool Ensure1Criticality>
|
|
2275
|
+
class numeric_limits<Gudhi::multi_filtration::Degree_rips_bifiltration<T, Co, Ensure1Criticality> >
|
|
2276
|
+
{
|
|
2277
|
+
public:
|
|
2278
|
+
using Filtration_value = Gudhi::multi_filtration::Degree_rips_bifiltration<T, Co, Ensure1Criticality>;
|
|
2279
|
+
|
|
2280
|
+
static constexpr bool has_infinity = !Co;
|
|
2281
|
+
static constexpr bool has_quiet_NaN = true;
|
|
2282
|
+
|
|
2283
|
+
static constexpr Filtration_value infinity(std::size_t p = 2) noexcept(!Co) { return Filtration_value::inf(p); };
|
|
2284
|
+
|
|
2285
|
+
// non-standard
|
|
2286
|
+
static constexpr Filtration_value minus_infinity(std::size_t p = 2) noexcept
|
|
2287
|
+
{
|
|
2288
|
+
return Filtration_value::minus_inf(p);
|
|
2289
|
+
};
|
|
2290
|
+
|
|
2291
|
+
static constexpr Filtration_value max(std::size_t p = 2) noexcept(!Co)
|
|
2292
|
+
{
|
|
2293
|
+
if constexpr (Co) {
|
|
2294
|
+
throw std::logic_error("No biggest value possible for Co-filtrations yet.");
|
|
2295
|
+
} else {
|
|
2296
|
+
return Filtration_value(p, std::numeric_limits<T>::max());
|
|
2297
|
+
}
|
|
2298
|
+
};
|
|
2299
|
+
|
|
2300
|
+
static constexpr Filtration_value lowest(std::size_t p = 2) noexcept { return Filtration_value::minus_inf(p); };
|
|
2301
|
+
|
|
2302
|
+
static constexpr Filtration_value quiet_NaN(std::size_t p = 2) noexcept { return Filtration_value::nan(p); };
|
|
2303
|
+
};
|
|
2304
|
+
|
|
2305
|
+
} // namespace std
|
|
2306
|
+
|
|
2307
|
+
#endif // MF_DEGREE_RIPS_BIFILTRATION_H_
|