multipers 2.3.3b6__cp311-cp311-macosx_11_0_arm64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of multipers might be problematic. Click here for more details.
- multipers/.dylibs/libc++.1.0.dylib +0 -0
- multipers/.dylibs/libtbb.12.16.dylib +0 -0
- multipers/__init__.py +33 -0
- multipers/_signed_measure_meta.py +453 -0
- multipers/_slicer_meta.py +211 -0
- multipers/array_api/__init__.py +45 -0
- multipers/array_api/numpy.py +41 -0
- multipers/array_api/torch.py +58 -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 +229 -0
- multipers/filtration_conversions.pxd.tp +84 -0
- multipers/filtrations/__init__.py +18 -0
- multipers/filtrations/density.py +574 -0
- multipers/filtrations/filtrations.py +361 -0
- multipers/filtrations.pxd +224 -0
- multipers/function_rips.cpython-311-darwin.so +0 -0
- multipers/function_rips.pyx +105 -0
- multipers/grids.cpython-311-darwin.so +0 -0
- multipers/grids.pyx +433 -0
- multipers/gudhi/Persistence_slices_interface.h +132 -0
- multipers/gudhi/Simplex_tree_interface.h +239 -0
- multipers/gudhi/Simplex_tree_multi_interface.h +551 -0
- multipers/gudhi/cubical_to_boundary.h +59 -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 +45 -0
- multipers/gudhi/gudhi/Fields/Multi_field.h +484 -0
- multipers/gudhi/gudhi/Fields/Multi_field_operators.h +455 -0
- multipers/gudhi/gudhi/Fields/Multi_field_shared.h +450 -0
- multipers/gudhi/gudhi/Fields/Multi_field_small.h +531 -0
- multipers/gudhi/gudhi/Fields/Multi_field_small_operators.h +507 -0
- multipers/gudhi/gudhi/Fields/Multi_field_small_shared.h +531 -0
- multipers/gudhi/gudhi/Fields/Z2_field.h +355 -0
- multipers/gudhi/gudhi/Fields/Z2_field_operators.h +376 -0
- multipers/gudhi/gudhi/Fields/Zp_field.h +420 -0
- multipers/gudhi/gudhi/Fields/Zp_field_operators.h +400 -0
- multipers/gudhi/gudhi/Fields/Zp_field_shared.h +418 -0
- multipers/gudhi/gudhi/Flag_complex_edge_collapser.h +337 -0
- multipers/gudhi/gudhi/Matrix.h +2107 -0
- multipers/gudhi/gudhi/Multi_critical_filtration.h +1038 -0
- multipers/gudhi/gudhi/Multi_persistence/Box.h +174 -0
- multipers/gudhi/gudhi/Multi_persistence/Line.h +282 -0
- multipers/gudhi/gudhi/Off_reader.h +173 -0
- multipers/gudhi/gudhi/One_critical_filtration.h +1441 -0
- multipers/gudhi/gudhi/Persistence_matrix/Base_matrix.h +769 -0
- multipers/gudhi/gudhi/Persistence_matrix/Base_matrix_with_column_compression.h +686 -0
- multipers/gudhi/gudhi/Persistence_matrix/Boundary_matrix.h +842 -0
- multipers/gudhi/gudhi/Persistence_matrix/Chain_matrix.h +1350 -0
- multipers/gudhi/gudhi/Persistence_matrix/Id_to_index_overlay.h +1105 -0
- multipers/gudhi/gudhi/Persistence_matrix/Position_to_index_overlay.h +859 -0
- multipers/gudhi/gudhi/Persistence_matrix/RU_matrix.h +910 -0
- multipers/gudhi/gudhi/Persistence_matrix/allocators/entry_constructors.h +139 -0
- multipers/gudhi/gudhi/Persistence_matrix/base_pairing.h +230 -0
- multipers/gudhi/gudhi/Persistence_matrix/base_swap.h +211 -0
- multipers/gudhi/gudhi/Persistence_matrix/boundary_cell_position_to_id_mapper.h +60 -0
- multipers/gudhi/gudhi/Persistence_matrix/boundary_face_position_to_id_mapper.h +60 -0
- multipers/gudhi/gudhi/Persistence_matrix/chain_pairing.h +136 -0
- multipers/gudhi/gudhi/Persistence_matrix/chain_rep_cycles.h +190 -0
- multipers/gudhi/gudhi/Persistence_matrix/chain_vine_swap.h +616 -0
- multipers/gudhi/gudhi/Persistence_matrix/columns/chain_column_extra_properties.h +150 -0
- multipers/gudhi/gudhi/Persistence_matrix/columns/column_dimension_holder.h +106 -0
- multipers/gudhi/gudhi/Persistence_matrix/columns/column_utilities.h +219 -0
- multipers/gudhi/gudhi/Persistence_matrix/columns/entry_types.h +327 -0
- multipers/gudhi/gudhi/Persistence_matrix/columns/heap_column.h +1140 -0
- multipers/gudhi/gudhi/Persistence_matrix/columns/intrusive_list_column.h +934 -0
- multipers/gudhi/gudhi/Persistence_matrix/columns/intrusive_set_column.h +934 -0
- multipers/gudhi/gudhi/Persistence_matrix/columns/list_column.h +980 -0
- multipers/gudhi/gudhi/Persistence_matrix/columns/naive_vector_column.h +1092 -0
- multipers/gudhi/gudhi/Persistence_matrix/columns/row_access.h +192 -0
- multipers/gudhi/gudhi/Persistence_matrix/columns/set_column.h +921 -0
- multipers/gudhi/gudhi/Persistence_matrix/columns/small_vector_column.h +1093 -0
- multipers/gudhi/gudhi/Persistence_matrix/columns/unordered_set_column.h +1012 -0
- multipers/gudhi/gudhi/Persistence_matrix/columns/vector_column.h +1244 -0
- multipers/gudhi/gudhi/Persistence_matrix/matrix_dimension_holders.h +186 -0
- multipers/gudhi/gudhi/Persistence_matrix/matrix_row_access.h +164 -0
- multipers/gudhi/gudhi/Persistence_matrix/ru_pairing.h +156 -0
- multipers/gudhi/gudhi/Persistence_matrix/ru_rep_cycles.h +376 -0
- multipers/gudhi/gudhi/Persistence_matrix/ru_vine_swap.h +540 -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 +745 -0
- multipers/gudhi/gudhi/Points_off_io.h +171 -0
- multipers/gudhi/gudhi/Simple_object_pool.h +69 -0
- multipers/gudhi/gudhi/Simplex_tree/Simplex_tree_iterators.h +463 -0
- multipers/gudhi/gudhi/Simplex_tree/Simplex_tree_node_explicit_storage.h +83 -0
- multipers/gudhi/gudhi/Simplex_tree/Simplex_tree_siblings.h +106 -0
- multipers/gudhi/gudhi/Simplex_tree/Simplex_tree_star_simplex_iterators.h +277 -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 +62 -0
- multipers/gudhi/gudhi/Simplex_tree/simplex_tree_options.h +157 -0
- multipers/gudhi/gudhi/Simplex_tree.h +2794 -0
- multipers/gudhi/gudhi/Simplex_tree_multi.h +152 -0
- multipers/gudhi/gudhi/distance_functions.h +62 -0
- multipers/gudhi/gudhi/graph_simplicial_complex.h +104 -0
- multipers/gudhi/gudhi/persistence_interval.h +253 -0
- multipers/gudhi/gudhi/persistence_matrix_options.h +170 -0
- multipers/gudhi/gudhi/reader_utils.h +367 -0
- multipers/gudhi/mma_interface_coh.h +256 -0
- multipers/gudhi/mma_interface_h0.h +223 -0
- multipers/gudhi/mma_interface_matrix.h +293 -0
- multipers/gudhi/naive_merge_tree.h +536 -0
- multipers/gudhi/scc_io.h +310 -0
- multipers/gudhi/truc.h +1403 -0
- multipers/io.cpython-311-darwin.so +0 -0
- multipers/io.pyx +644 -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 +1589 -0
- multipers/ml/sliced_wasserstein.py +461 -0
- multipers/ml/tools.py +113 -0
- multipers/mma_structures.cpython-311-darwin.so +0 -0
- multipers/mma_structures.pxd +128 -0
- multipers/mma_structures.pyx +2786 -0
- multipers/mma_structures.pyx.tp +1094 -0
- multipers/multi_parameter_rank_invariant/diff_helpers.h +84 -0
- multipers/multi_parameter_rank_invariant/euler_characteristic.h +97 -0
- multipers/multi_parameter_rank_invariant/function_rips.h +322 -0
- multipers/multi_parameter_rank_invariant/hilbert_function.h +769 -0
- multipers/multi_parameter_rank_invariant/persistence_slices.h +148 -0
- multipers/multi_parameter_rank_invariant/rank_invariant.h +369 -0
- multipers/multiparameter_edge_collapse.py +41 -0
- multipers/multiparameter_module_approximation/approximation.h +2330 -0
- multipers/multiparameter_module_approximation/combinatory.h +129 -0
- multipers/multiparameter_module_approximation/debug.h +107 -0
- multipers/multiparameter_module_approximation/euler_curves.h +0 -0
- multipers/multiparameter_module_approximation/format_python-cpp.h +286 -0
- multipers/multiparameter_module_approximation/heap_column.h +238 -0
- multipers/multiparameter_module_approximation/images.h +79 -0
- multipers/multiparameter_module_approximation/list_column.h +174 -0
- multipers/multiparameter_module_approximation/list_column_2.h +232 -0
- multipers/multiparameter_module_approximation/ru_matrix.h +347 -0
- multipers/multiparameter_module_approximation/set_column.h +135 -0
- multipers/multiparameter_module_approximation/structure_higher_dim_barcode.h +36 -0
- multipers/multiparameter_module_approximation/unordered_set_column.h +166 -0
- multipers/multiparameter_module_approximation/utilities.h +403 -0
- multipers/multiparameter_module_approximation/vector_column.h +223 -0
- multipers/multiparameter_module_approximation/vector_matrix.h +331 -0
- multipers/multiparameter_module_approximation/vineyards.h +464 -0
- multipers/multiparameter_module_approximation/vineyards_trajectories.h +649 -0
- multipers/multiparameter_module_approximation.cpython-311-darwin.so +0 -0
- multipers/multiparameter_module_approximation.pyx +235 -0
- multipers/pickle.py +90 -0
- multipers/plots.py +456 -0
- multipers/point_measure.cpython-311-darwin.so +0 -0
- multipers/point_measure.pyx +395 -0
- multipers/simplex_tree_multi.cpython-311-darwin.so +0 -0
- multipers/simplex_tree_multi.pxd +134 -0
- multipers/simplex_tree_multi.pyx +10840 -0
- multipers/simplex_tree_multi.pyx.tp +2009 -0
- multipers/slicer.cpython-311-darwin.so +0 -0
- multipers/slicer.pxd +3034 -0
- multipers/slicer.pxd.tp +234 -0
- multipers/slicer.pyx +20481 -0
- multipers/slicer.pyx.tp +1088 -0
- multipers/tensor/tensor.h +672 -0
- multipers/tensor.pxd +13 -0
- multipers/test.pyx +44 -0
- multipers/tests/__init__.py +62 -0
- multipers/torch/__init__.py +1 -0
- multipers/torch/diff_grids.py +240 -0
- multipers/torch/rips_density.py +310 -0
- multipers-2.3.3b6.dist-info/METADATA +128 -0
- multipers-2.3.3b6.dist-info/RECORD +183 -0
- multipers-2.3.3b6.dist-info/WHEEL +6 -0
- multipers-2.3.3b6.dist-info/licenses/LICENSE +21 -0
- multipers-2.3.3b6.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,2330 @@
|
|
|
1
|
+
|
|
2
|
+
/* This file is part of the MMA Library -
|
|
3
|
+
* https://gitlab.inria.fr/dloiseau/multipers - which is released under MIT. See
|
|
4
|
+
* file LICENSE for full license details. Author(s): David Loiseaux
|
|
5
|
+
*
|
|
6
|
+
* Copyright (C) 2021 Inria
|
|
7
|
+
*
|
|
8
|
+
* Modification(s):
|
|
9
|
+
* - 2022/03 Hannah Schreiber: Integration of the new Vineyard_persistence
|
|
10
|
+
* class, renaming and cleanup.
|
|
11
|
+
* - 2022/05 Hannah Schreiber: Addition of Summand class and Module class.
|
|
12
|
+
*/
|
|
13
|
+
/**
|
|
14
|
+
* @file approximation.h
|
|
15
|
+
* @author David Loiseaux, Hannah Schreiber
|
|
16
|
+
* @brief Contains the functions related to the approximation of n-modules.
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
#ifndef APPROXIMATION_H_INCLUDED
|
|
20
|
+
#define APPROXIMATION_H_INCLUDED
|
|
21
|
+
|
|
22
|
+
#include <algorithm>
|
|
23
|
+
#include <cmath>
|
|
24
|
+
#include <cstddef>
|
|
25
|
+
#include <cstdint>
|
|
26
|
+
#include <iostream>
|
|
27
|
+
#include <iterator>
|
|
28
|
+
#include <limits>
|
|
29
|
+
#include <oneapi/tbb/parallel_for.h>
|
|
30
|
+
#include <string>
|
|
31
|
+
#include <type_traits>
|
|
32
|
+
#include <utility>
|
|
33
|
+
#include <vector>
|
|
34
|
+
|
|
35
|
+
#include "utilities.h"
|
|
36
|
+
|
|
37
|
+
#include "debug.h"
|
|
38
|
+
#include <Persistence_slices_interface.h>
|
|
39
|
+
#include <gudhi/One_critical_filtration.h>
|
|
40
|
+
#include <gudhi/Multi_critical_filtration.h>
|
|
41
|
+
#include <gudhi/Multi_persistence/Box.h>
|
|
42
|
+
#include <gudhi/Multi_persistence/Line.h>
|
|
43
|
+
#include <tbb/parallel_for.h>
|
|
44
|
+
#include <tensor/tensor.h>
|
|
45
|
+
|
|
46
|
+
namespace Gudhi {
|
|
47
|
+
namespace multiparameter {
|
|
48
|
+
namespace mma {
|
|
49
|
+
|
|
50
|
+
using Debug::Timer;
|
|
51
|
+
using Gudhi::multi_persistence::Box;
|
|
52
|
+
using Gudhi::multi_persistence::Line;
|
|
53
|
+
template <typename T>
|
|
54
|
+
class Module;
|
|
55
|
+
template <typename T>
|
|
56
|
+
class Summand;
|
|
57
|
+
|
|
58
|
+
void threshold_filters_list(std::vector<value_type> &filtersList, const Box<value_type> &box);
|
|
59
|
+
|
|
60
|
+
template <typename value_type>
|
|
61
|
+
class Module {
|
|
62
|
+
public:
|
|
63
|
+
using filtration_type = Gudhi::multi_filtration::One_critical_filtration<value_type>;
|
|
64
|
+
using module_type = std::vector<Summand<value_type>>;
|
|
65
|
+
using image_type = std::vector<std::vector<value_type>>;
|
|
66
|
+
using get_2dpixel_value_function_type = std::function<value_type(const typename module_type::const_iterator,
|
|
67
|
+
const typename module_type::const_iterator,
|
|
68
|
+
value_type,
|
|
69
|
+
value_type)>;
|
|
70
|
+
using get_pixel_value_function_type = std::function<value_type(const typename module_type::const_iterator,
|
|
71
|
+
const typename module_type::const_iterator,
|
|
72
|
+
std::vector<value_type> &)>;
|
|
73
|
+
|
|
74
|
+
Module();
|
|
75
|
+
Module(Box<value_type> &box);
|
|
76
|
+
|
|
77
|
+
void resize(unsigned int size);
|
|
78
|
+
Summand<value_type> &at(unsigned int index);
|
|
79
|
+
Summand<value_type> &operator[](size_t index);
|
|
80
|
+
|
|
81
|
+
const Summand<value_type> &operator[](const size_t index) const;
|
|
82
|
+
template <class Barcode>
|
|
83
|
+
void add_barcode(const Barcode &barcode);
|
|
84
|
+
void add_barcode(const Line<value_type> &line,
|
|
85
|
+
const std::vector<std::pair<int, std::pair<value_type, value_type>>> &barcode,
|
|
86
|
+
const bool threshold);
|
|
87
|
+
void add_barcode(const Line<value_type> &line,
|
|
88
|
+
const std::vector<std::pair<value_type, value_type>> &barcode,
|
|
89
|
+
const bool threshold);
|
|
90
|
+
typename module_type::iterator begin();
|
|
91
|
+
typename module_type::iterator end();
|
|
92
|
+
typename module_type::const_iterator begin() const;
|
|
93
|
+
typename module_type::const_iterator end() const;
|
|
94
|
+
|
|
95
|
+
void clean();
|
|
96
|
+
void fill(const value_type precision);
|
|
97
|
+
|
|
98
|
+
std::vector<image_type> get_vectorization(const value_type delta,
|
|
99
|
+
const value_type p,
|
|
100
|
+
const bool normalize,
|
|
101
|
+
const Gudhi::multi_persistence::Box<value_type> &box,
|
|
102
|
+
unsigned int horizontalResolution,
|
|
103
|
+
unsigned int verticalResolution);
|
|
104
|
+
std::vector<image_type> get_vectorization(unsigned int horizontalResolution,
|
|
105
|
+
unsigned int verticalResolution,
|
|
106
|
+
get_2dpixel_value_function_type get_pixel_value) const;
|
|
107
|
+
image_type get_vectorization_in_dimension(const dimension_type dimension,
|
|
108
|
+
const value_type delta,
|
|
109
|
+
const value_type p,
|
|
110
|
+
const bool normalize,
|
|
111
|
+
const Gudhi::multi_persistence::Box<value_type> &box,
|
|
112
|
+
unsigned int horizontalResolution,
|
|
113
|
+
unsigned int verticalResolution);
|
|
114
|
+
image_type get_vectorization_in_dimension(const dimension_type dimension,
|
|
115
|
+
unsigned int horizontalResolution,
|
|
116
|
+
unsigned int verticalResolution,
|
|
117
|
+
get_2dpixel_value_function_type get_pixel_value) const;
|
|
118
|
+
std::vector<value_type> get_landscape_values(const std::vector<value_type> &x, const dimension_type dimension) const;
|
|
119
|
+
image_type get_landscape(const dimension_type dimension,
|
|
120
|
+
const unsigned int k,
|
|
121
|
+
const Box<value_type> &box,
|
|
122
|
+
const std::vector<unsigned int> &resolution) const;
|
|
123
|
+
std::vector<image_type> get_landscapes(const dimension_type dimension,
|
|
124
|
+
const std::vector<unsigned int> ks,
|
|
125
|
+
const Box<value_type> &box,
|
|
126
|
+
const std::vector<unsigned int> &resolution) const;
|
|
127
|
+
void add_summand(Summand<value_type> summand, int degree = -1);
|
|
128
|
+
Box<value_type> get_box() const;
|
|
129
|
+
void set_box(Box<value_type> box);
|
|
130
|
+
unsigned int size() const;
|
|
131
|
+
void infer_box(std::vector<filtration_type> &filters_list);
|
|
132
|
+
dimension_type get_dimension() const;
|
|
133
|
+
module_type get_summands_of_dimension(const int dimension) const;
|
|
134
|
+
std::vector<std::pair<std::vector<std::vector<value_type>>, std::vector<std::vector<value_type>>>>
|
|
135
|
+
get_corners_of_dimension(const int dimension) const;
|
|
136
|
+
MultiDiagram<filtration_type, value_type> get_barcode(const Line<value_type> &l,
|
|
137
|
+
const dimension_type dimension = -1,
|
|
138
|
+
const bool threshold = false) const;
|
|
139
|
+
std::vector<std::vector<std::pair<value_type, value_type>>> get_barcode2(const Line<value_type> &l,
|
|
140
|
+
const dimension_type dimension) const;
|
|
141
|
+
std::vector<std::vector<std::vector<std::pair<value_type, value_type>>>> get_barcodes2(
|
|
142
|
+
const std::vector<Line<value_type>> &lines,
|
|
143
|
+
const dimension_type dimension = -1) const;
|
|
144
|
+
MultiDiagrams<filtration_type, value_type> get_barcodes(const std::vector<Line<value_type>> &lines,
|
|
145
|
+
const dimension_type dimension = -1,
|
|
146
|
+
const bool threshold = false) const;
|
|
147
|
+
MultiDiagrams<filtration_type, value_type> get_barcodes(const std::vector<filtration_type> &basepoints,
|
|
148
|
+
const dimension_type dimension = -1,
|
|
149
|
+
const bool threshold = false) const;
|
|
150
|
+
std::vector<int> euler_curve(const std::vector<filtration_type> &points) const;
|
|
151
|
+
|
|
152
|
+
inline Box<value_type> get_bounds() const;
|
|
153
|
+
inline void rescale(const std::vector<value_type> &rescale_factors, int degree);
|
|
154
|
+
inline void translate(const std::vector<value_type> &translation, int degree);
|
|
155
|
+
|
|
156
|
+
std::vector<std::vector<value_type>> compute_pixels(const std::vector<std::vector<value_type>> &coordinates,
|
|
157
|
+
const std::vector<int> °rees,
|
|
158
|
+
const Box<value_type> &box = {},
|
|
159
|
+
const value_type delta = 0.1,
|
|
160
|
+
const value_type p = 1,
|
|
161
|
+
const bool normalize = true,
|
|
162
|
+
const int n_jobs = 0);
|
|
163
|
+
|
|
164
|
+
std::vector<value_type> get_interleavings(const Box<value_type> &box);
|
|
165
|
+
using distance_to_idx_type = std::vector<std::vector<int>>;
|
|
166
|
+
distance_to_idx_type compute_distance_idx_to(const std::vector<value_type> &pt, bool full) const;
|
|
167
|
+
std::vector<value_type> compute_distance_to(const std::vector<value_type> &pt, bool negative) const;
|
|
168
|
+
std::vector<std::vector<value_type>> compute_distances_to(const std::vector<std::vector<value_type>> &pt,
|
|
169
|
+
bool negative,
|
|
170
|
+
int n_jobs) const;
|
|
171
|
+
template <typename dtype = value_type, typename indices_type = int32_t>
|
|
172
|
+
void inline compute_distances_to(dtype *data_ptr,
|
|
173
|
+
const std::vector<std::vector<value_type>> &pts,
|
|
174
|
+
bool negative,
|
|
175
|
+
int n_jobs) const;
|
|
176
|
+
using distances_to_idx_type = std::vector<distance_to_idx_type>;
|
|
177
|
+
distances_to_idx_type compute_distances_idx_to(const std::vector<std::vector<value_type>> &pt,
|
|
178
|
+
bool full,
|
|
179
|
+
int n_jobs) const;
|
|
180
|
+
std::vector<value_type> compute_pixels_of_degree(const typename module_type::iterator start,
|
|
181
|
+
const typename module_type::iterator end,
|
|
182
|
+
const value_type delta,
|
|
183
|
+
const value_type p,
|
|
184
|
+
const bool normalize,
|
|
185
|
+
const Box<value_type> &box,
|
|
186
|
+
const std::vector<std::vector<value_type>> &coordinates,
|
|
187
|
+
const int n_jobs = 0);
|
|
188
|
+
|
|
189
|
+
using idx_dump_type =
|
|
190
|
+
std::vector<std::vector<std::pair<std::vector<std::vector<int>>, std::vector<std::vector<int>>>>>;
|
|
191
|
+
idx_dump_type to_idx(const std::vector<std::vector<value_type>> &grid) const;
|
|
192
|
+
Module<int64_t> grid_squeeze(const std::vector<std::vector<value_type>> &grid) const;
|
|
193
|
+
|
|
194
|
+
std::vector<std::vector<std::vector<int>>> to_flat_idx(const std::vector<std::vector<value_type>> &grid) const;
|
|
195
|
+
|
|
196
|
+
std::vector<int> inline get_degree_splits() const;
|
|
197
|
+
|
|
198
|
+
inline friend bool operator==(const Module &a, const Module &b) {
|
|
199
|
+
if (a.get_dimension() != b.get_dimension()) return false;
|
|
200
|
+
if (a.box_ != b.box_) return false;
|
|
201
|
+
if (a.size() != b.size()) return false;
|
|
202
|
+
for (auto i : std::views::iota(0u, a.size())) {
|
|
203
|
+
if (a[i] != b[i]) return false;
|
|
204
|
+
}
|
|
205
|
+
return true;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
private:
|
|
209
|
+
module_type module_;
|
|
210
|
+
Box<value_type> box_;
|
|
211
|
+
void _compute_2D_image(image_type &image,
|
|
212
|
+
const typename module_type::iterator start,
|
|
213
|
+
const typename module_type::iterator end,
|
|
214
|
+
const value_type delta = 0.1,
|
|
215
|
+
const value_type p = 1,
|
|
216
|
+
const bool normalize = true,
|
|
217
|
+
const Box<value_type> &box = Box<value_type>(),
|
|
218
|
+
const unsigned int horizontalResolution = 100,
|
|
219
|
+
const unsigned int verticalResolution = 100);
|
|
220
|
+
void _compute_2D_image(image_type &image,
|
|
221
|
+
const typename module_type::const_iterator start,
|
|
222
|
+
const typename module_type::const_iterator end,
|
|
223
|
+
unsigned int horizontalResolution,
|
|
224
|
+
unsigned int verticalResolution,
|
|
225
|
+
get_2dpixel_value_function_type get_pixel_value) const;
|
|
226
|
+
|
|
227
|
+
value_type _get_pixel_value(const typename module_type::iterator start,
|
|
228
|
+
const typename module_type::iterator end,
|
|
229
|
+
const filtration_type x,
|
|
230
|
+
const value_type delta,
|
|
231
|
+
const value_type p,
|
|
232
|
+
const bool normalize,
|
|
233
|
+
const value_type moduleWeight) const;
|
|
234
|
+
|
|
235
|
+
void _add_bar_with_threshold(const Line<value_type> &line,
|
|
236
|
+
const std::pair<value_type, value_type> &bar,
|
|
237
|
+
const bool threshold_in,
|
|
238
|
+
Summand<value_type> &summand);
|
|
239
|
+
};
|
|
240
|
+
|
|
241
|
+
template <typename value_type>
|
|
242
|
+
class Summand {
|
|
243
|
+
public:
|
|
244
|
+
using births_type = Gudhi::multi_filtration::Multi_critical_filtration<value_type, false>;
|
|
245
|
+
using deaths_type = Gudhi::multi_filtration::Multi_critical_filtration<value_type, true>;
|
|
246
|
+
using filtration_type = typename births_type::Generator; // same for death
|
|
247
|
+
using dimension_type = int;
|
|
248
|
+
Summand();
|
|
249
|
+
Summand(const births_type &birth_corners, const deaths_type &death_corners, dimension_type dimension);
|
|
250
|
+
Summand(const std::vector<filtration_type> &birth_corners,
|
|
251
|
+
const std::vector<filtration_type> &death_corners,
|
|
252
|
+
dimension_type dimension);
|
|
253
|
+
|
|
254
|
+
value_type get_interleaving() const;
|
|
255
|
+
value_type get_interleaving(const Box<value_type> &box);
|
|
256
|
+
value_type get_local_weight(const filtration_type &x, const value_type delta) const;
|
|
257
|
+
|
|
258
|
+
value_type distance_to_upper(const filtration_type &x, bool negative) const;
|
|
259
|
+
value_type distance_to_lower(const filtration_type &x, bool negative) const;
|
|
260
|
+
value_type distance_to(const filtration_type &x, bool negative) const;
|
|
261
|
+
std::tuple<int, int> distance_idx_to_upper(const filtration_type &x) const;
|
|
262
|
+
std::tuple<int, int> distance_idx_to_lower(const filtration_type &x) const;
|
|
263
|
+
std::vector<int> distance_idx_to(const filtration_type &x, bool full) const;
|
|
264
|
+
std::pair<filtration_type, filtration_type> get_bar(const Line<value_type> &line) const;
|
|
265
|
+
std::pair<value_type, value_type> get_bar2(const Line<value_type> &l) const;
|
|
266
|
+
void add_bar(value_type baseBirth,
|
|
267
|
+
value_type baseDeath,
|
|
268
|
+
const filtration_type &basepoint,
|
|
269
|
+
filtration_type &birth,
|
|
270
|
+
filtration_type &death,
|
|
271
|
+
const bool threshold,
|
|
272
|
+
const Box<value_type> &box);
|
|
273
|
+
void add_bar(const filtration_type &birth, const filtration_type &death);
|
|
274
|
+
void add_bar(const filtration_type &basepoint, value_type birth, value_type death, const Box<value_type> &);
|
|
275
|
+
|
|
276
|
+
const std::vector<filtration_type> &get_birth_list() const;
|
|
277
|
+
const std::vector<filtration_type> &get_death_list() const;
|
|
278
|
+
const Gudhi::multi_filtration::Multi_critical_filtration<value_type> &get_upset() const;
|
|
279
|
+
const Gudhi::multi_filtration::Multi_critical_filtration<value_type> &get_downset() const;
|
|
280
|
+
void clean();
|
|
281
|
+
|
|
282
|
+
void complete_birth(const value_type precision);
|
|
283
|
+
void complete_death(const value_type precision);
|
|
284
|
+
|
|
285
|
+
dimension_type get_dimension() const;
|
|
286
|
+
void set_dimension(dimension_type dimension);
|
|
287
|
+
|
|
288
|
+
value_type get_landscape_value(const std::vector<value_type> &x) const;
|
|
289
|
+
|
|
290
|
+
friend void swap(Summand &sum1, Summand &sum2) {
|
|
291
|
+
std::swap(sum1.birth_corners_, sum2.birth_corners_);
|
|
292
|
+
std::swap(sum1.death_corners_, sum2.death_corners_);
|
|
293
|
+
std::swap(sum1.distanceTo0_, sum2.distanceTo0_);
|
|
294
|
+
// std::swap(sum1.updateDistance_, sum2.updateDistance_);
|
|
295
|
+
};
|
|
296
|
+
|
|
297
|
+
friend bool operator==(const Summand &a, const Summand &b) {
|
|
298
|
+
return a.dimension_ == b.dimension_ && a.birth_corners_ == b.birth_corners_ && a.death_corners_ == b.death_corners_;
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
bool contains(const filtration_type &x) const;
|
|
302
|
+
|
|
303
|
+
inline Box<value_type> get_bounds() const {
|
|
304
|
+
if (birth_corners_.num_generators() == 0) return Box<value_type>();
|
|
305
|
+
auto dimension = birth_corners_.num_parameters();
|
|
306
|
+
filtration_type m(dimension, std::numeric_limits<value_type>::infinity());
|
|
307
|
+
filtration_type M(dimension, -std::numeric_limits<value_type>::infinity());
|
|
308
|
+
for (const auto &corner : birth_corners_) {
|
|
309
|
+
for (auto parameter = 0u; parameter < dimension; parameter++) {
|
|
310
|
+
m[parameter] = std::min(m[parameter], corner[parameter]);
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
for (const auto &corner : death_corners_) {
|
|
314
|
+
for (auto parameter = 0u; parameter < dimension; parameter++) {
|
|
315
|
+
auto corner_i = corner[parameter];
|
|
316
|
+
if (corner_i != std::numeric_limits<value_type>::infinity())
|
|
317
|
+
M[parameter] = std::max(M[parameter], corner[parameter]);
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
return Box(m, M);
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
inline void rescale(const std::vector<value_type> &rescale_factors) {
|
|
324
|
+
if (birth_corners_.num_generators() == 0) return;
|
|
325
|
+
auto dimension = birth_corners_.num_parameters();
|
|
326
|
+
for (auto &corner : birth_corners_) {
|
|
327
|
+
for (auto parameter = 0u; parameter < dimension; parameter++) {
|
|
328
|
+
corner[parameter] *= rescale_factors.at(parameter);
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
for (auto &corner : death_corners_) {
|
|
332
|
+
for (auto parameter = 0u; parameter < dimension; parameter++) {
|
|
333
|
+
corner[parameter] *= rescale_factors.at(parameter);
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
inline void translate(const std::vector<value_type> &translation) {
|
|
339
|
+
if (birth_corners_.num_generators() == 0) return;
|
|
340
|
+
auto dimension = birth_corners_.num_parameters();
|
|
341
|
+
for (auto &corner : birth_corners_) {
|
|
342
|
+
for (auto parameter = 0u; parameter < dimension; parameter++) {
|
|
343
|
+
corner[parameter] += translation.at(parameter);
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
for (auto &corner : death_corners_) {
|
|
347
|
+
for (auto parameter = 0u; parameter < dimension; parameter++) {
|
|
348
|
+
corner[parameter] += translation.at(parameter);
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
inline Summand<int64_t> grid_squeeze(const std::vector<std::vector<value_type>> &grid) const;
|
|
354
|
+
|
|
355
|
+
private:
|
|
356
|
+
Gudhi::multi_filtration::Multi_critical_filtration<value_type, false>
|
|
357
|
+
birth_corners_; // TODO : use Multi_critical_filtration
|
|
358
|
+
Gudhi::multi_filtration::Multi_critical_filtration<value_type, true> death_corners_;
|
|
359
|
+
value_type distanceTo0_;
|
|
360
|
+
dimension_type dimension_;
|
|
361
|
+
|
|
362
|
+
void _compute_interleaving(const Box<value_type> &box);
|
|
363
|
+
void _add_birth(const filtration_type &birth);
|
|
364
|
+
void _add_death(const filtration_type &death);
|
|
365
|
+
value_type _rectangle_volume(const filtration_type &a, const filtration_type &b) const;
|
|
366
|
+
value_type _get_max_diagonal(const filtration_type &a, const filtration_type &b, const Box<value_type> &box) const;
|
|
367
|
+
value_type d_inf(const filtration_type &a, const filtration_type &b) const;
|
|
368
|
+
void _factorize_min(filtration_type &a, const filtration_type &b);
|
|
369
|
+
void _factorize_max(filtration_type &a, const filtration_type &b);
|
|
370
|
+
static void _clean(std::vector<filtration_type> &list, bool keep_inf = true);
|
|
371
|
+
|
|
372
|
+
static inline void _clean(births_type &list, bool keep_inf = true) { list.remove_empty_generators(keep_inf); }
|
|
373
|
+
|
|
374
|
+
static inline void _clean(deaths_type &list, bool keep_inf = true) { list.remove_empty_generators(keep_inf); }
|
|
375
|
+
};
|
|
376
|
+
|
|
377
|
+
inline void threshold_filters_list(std::vector<filtration_type> &filtersList, const Box<value_type> &box) {
|
|
378
|
+
return;
|
|
379
|
+
for (unsigned int i = 0; i < filtersList.size(); i++) {
|
|
380
|
+
for (value_type &value : filtersList[i]) {
|
|
381
|
+
value = std::min(std::max(value, box.get_lower_corner()[i]), box.get_upper_corner()[i]);
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
template <class Filtration_value, int axis = 0, bool sign = true>
|
|
387
|
+
class LineIterator {
|
|
388
|
+
public:
|
|
389
|
+
using value_type = typename Filtration_value::value_type;
|
|
390
|
+
LineIterator(const Filtration_value &basepoint,
|
|
391
|
+
const Filtration_value &direction,
|
|
392
|
+
value_type precision,
|
|
393
|
+
int num_iterations)
|
|
394
|
+
: precision(precision), remaining_iterations(num_iterations), current_line(std::move(basepoint), direction) {};
|
|
395
|
+
|
|
396
|
+
inline LineIterator<Filtration_value, axis, sign> &operator++() {
|
|
397
|
+
//
|
|
398
|
+
auto &basepoint = current_line.base_point();
|
|
399
|
+
if (this->is_finished()) return *this;
|
|
400
|
+
// If we didn't reached the end, go to the next line
|
|
401
|
+
basepoint[axis] += sign ? precision : -precision;
|
|
402
|
+
--remaining_iterations;
|
|
403
|
+
return *this;
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
inline const Line<value_type> &operator*() const { return current_line; }
|
|
407
|
+
|
|
408
|
+
inline LineIterator<Filtration_value, axis, sign> &next(std::size_t i) {
|
|
409
|
+
auto &basepoint = current_line.base_point();
|
|
410
|
+
if (this->is_finished()) return *this;
|
|
411
|
+
// If we didn't reached the end, go to the next line
|
|
412
|
+
basepoint[i] += sign ? precision : -precision;
|
|
413
|
+
--remaining_iterations;
|
|
414
|
+
return *this;
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
inline bool is_finished() const { return remaining_iterations <= 0; }
|
|
418
|
+
|
|
419
|
+
private:
|
|
420
|
+
const value_type precision;
|
|
421
|
+
int remaining_iterations;
|
|
422
|
+
Line<value_type> current_line;
|
|
423
|
+
};
|
|
424
|
+
|
|
425
|
+
template <class Filtration_value, int axis_ = 0, bool sign = true, class Slicer>
|
|
426
|
+
inline void __add_vineyard_trajectory_to_module(Module<typename Filtration_value::value_type> &module,
|
|
427
|
+
Slicer &&slicer,
|
|
428
|
+
LineIterator<Filtration_value, axis_, sign> &line_iterator,
|
|
429
|
+
const bool threshold,
|
|
430
|
+
int axis = 0) {
|
|
431
|
+
static_assert(std::is_same_v<typename Filtration_value::value_type, typename Slicer::Filtration_value::value_type>);
|
|
432
|
+
using value_type = typename Filtration_value::value_type;
|
|
433
|
+
// Line iterator should be on the biggest axis
|
|
434
|
+
constexpr const bool verbose = false;
|
|
435
|
+
constexpr const bool verbose2 = false;
|
|
436
|
+
while (!line_iterator.is_finished()) {
|
|
437
|
+
const Line<value_type> &new_line = (axis_ >= 0) ? *(++line_iterator) : *line_iterator.next(axis);
|
|
438
|
+
// if constexpr (axis_ >= 0) {
|
|
439
|
+
// new_line = *(++line_iterator); // first line is always a persistence
|
|
440
|
+
// } else {
|
|
441
|
+
// new_line = *line_iterator.next(axis);
|
|
442
|
+
// }
|
|
443
|
+
// copy, no need to add it
|
|
444
|
+
if constexpr (verbose) std::cout << "----------------------------------------------" << std::endl;
|
|
445
|
+
if constexpr (verbose) std::cout << "Line basepoint " << new_line.base_point() << std::endl;
|
|
446
|
+
slicer.push_to(new_line);
|
|
447
|
+
|
|
448
|
+
slicer.vineyard_update();
|
|
449
|
+
if constexpr (verbose2) std::cout << slicer << std::endl;
|
|
450
|
+
const auto &diagram = slicer.get_flat_nodim_barcode();
|
|
451
|
+
module.add_barcode(new_line, std::move(diagram), threshold);
|
|
452
|
+
};
|
|
453
|
+
};
|
|
454
|
+
|
|
455
|
+
template <class Filtration_value, class Slicer = SimplicialVineMatrixTruc<>>
|
|
456
|
+
void _rec_mma(Module<typename Filtration_value::value_type> &module,
|
|
457
|
+
Filtration_value &basepoint,
|
|
458
|
+
const std::vector<int> &grid_size,
|
|
459
|
+
int dim_to_iterate,
|
|
460
|
+
Slicer &¤t_persistence,
|
|
461
|
+
const value_type precision,
|
|
462
|
+
bool threshold) {
|
|
463
|
+
if (dim_to_iterate <= 0) {
|
|
464
|
+
LineIterator<Filtration_value, 0> line_iterator(std::move(basepoint), precision, grid_size[0]);
|
|
465
|
+
__add_vineyard_trajectory_to_module<Filtration_value, 0, Slicer>(
|
|
466
|
+
module, std::move(current_persistence), line_iterator, threshold);
|
|
467
|
+
return;
|
|
468
|
+
}
|
|
469
|
+
Slicer pers_copy;
|
|
470
|
+
Filtration_value basepoint_copy;
|
|
471
|
+
for (int i = 0; i < grid_size[dim_to_iterate]; ++i) {
|
|
472
|
+
// TODO : multithread, but needs matrix to be thread safe + put mutex on
|
|
473
|
+
// module
|
|
474
|
+
pers_copy = current_persistence;
|
|
475
|
+
basepoint_copy = basepoint;
|
|
476
|
+
_rec_mma(module, basepoint_copy, grid_size, dim_to_iterate - 1, pers_copy, precision, threshold);
|
|
477
|
+
basepoint[dim_to_iterate] += precision;
|
|
478
|
+
// current_persistence.push_to(Line(basepoint));
|
|
479
|
+
// current_persistence.vineyard_update();
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
template <int axis, class Filtration_value, class Slicer>
|
|
484
|
+
void _rec_mma2(Module<typename Filtration_value::value_type> &module,
|
|
485
|
+
Filtration_value &&basepoint,
|
|
486
|
+
const Filtration_value &direction,
|
|
487
|
+
const std::vector<int> &grid_size,
|
|
488
|
+
const std::vector<bool> &signs,
|
|
489
|
+
int dim_to_iterate,
|
|
490
|
+
Slicer &¤t_persistence,
|
|
491
|
+
const value_type precision,
|
|
492
|
+
bool threshold) {
|
|
493
|
+
static_assert(std::is_same_v<typename Filtration_value::value_type, typename Slicer::value_type>);
|
|
494
|
+
|
|
495
|
+
if (dim_to_iterate <= axis) {
|
|
496
|
+
if (signs[axis]) {
|
|
497
|
+
LineIterator<Filtration_value, axis, true> line_iterator(
|
|
498
|
+
std::move(basepoint), direction, precision, grid_size[axis]);
|
|
499
|
+
__add_vineyard_trajectory_to_module<Filtration_value, axis, true, Slicer>(
|
|
500
|
+
module, std::move(current_persistence), line_iterator, threshold);
|
|
501
|
+
} else {
|
|
502
|
+
LineIterator<Filtration_value, axis, false> line_iterator(
|
|
503
|
+
std::move(basepoint), direction, precision, grid_size[axis]);
|
|
504
|
+
__add_vineyard_trajectory_to_module<Filtration_value, axis, false, Slicer>(
|
|
505
|
+
module, std::move(current_persistence), line_iterator, threshold);
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
return;
|
|
509
|
+
}
|
|
510
|
+
if (grid_size[dim_to_iterate] == 0) {
|
|
511
|
+
// no need to copy basepoint, we just skip the dim here
|
|
512
|
+
_rec_mma2<axis, Filtration_value, Slicer>(module,
|
|
513
|
+
std::move(basepoint),
|
|
514
|
+
direction,
|
|
515
|
+
grid_size,
|
|
516
|
+
signs,
|
|
517
|
+
dim_to_iterate - 1,
|
|
518
|
+
std::move(current_persistence),
|
|
519
|
+
precision,
|
|
520
|
+
threshold);
|
|
521
|
+
return;
|
|
522
|
+
}
|
|
523
|
+
for (int i = 0; i < grid_size[dim_to_iterate]; ++i) {
|
|
524
|
+
// TODO : multithread, but needs matrix to be thread safe + put mutex on
|
|
525
|
+
// module
|
|
526
|
+
_rec_mma2<axis, Filtration_value, typename Slicer::ThreadSafe>(module,
|
|
527
|
+
Filtration_value(basepoint),
|
|
528
|
+
direction,
|
|
529
|
+
grid_size,
|
|
530
|
+
signs,
|
|
531
|
+
dim_to_iterate - 1,
|
|
532
|
+
current_persistence.weak_copy(),
|
|
533
|
+
precision,
|
|
534
|
+
threshold);
|
|
535
|
+
basepoint[dim_to_iterate] += signs[dim_to_iterate] ? precision : -precision;
|
|
536
|
+
// current_persistence.push_to(Line(basepoint));
|
|
537
|
+
// current_persistence.vineyard_update();
|
|
538
|
+
}
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
template <class Slicer, typename value_type>
|
|
542
|
+
Module<value_type> multiparameter_module_approximation(
|
|
543
|
+
Slicer &slicer,
|
|
544
|
+
const Gudhi::multi_filtration::One_critical_filtration<value_type> &direction,
|
|
545
|
+
const value_type precision,
|
|
546
|
+
Box<value_type> &box,
|
|
547
|
+
const bool threshold,
|
|
548
|
+
const bool complete,
|
|
549
|
+
const bool verbose) {
|
|
550
|
+
static_assert(std::is_same_v<typename Slicer::Filtration_value::value_type,
|
|
551
|
+
value_type>); // Value type can be exposed to python interface.
|
|
552
|
+
if (verbose) std::cout << "Starting Module Approximation" << std::endl;
|
|
553
|
+
/* using Filtration_value = Slicer::Filtration_value; */
|
|
554
|
+
|
|
555
|
+
Gudhi::multi_filtration::One_critical_filtration<value_type> basepoint = box.get_lower_corner();
|
|
556
|
+
const std::size_t num_parameters = box.dimension();
|
|
557
|
+
std::vector<int> grid_size(num_parameters);
|
|
558
|
+
std::vector<bool> signs(num_parameters);
|
|
559
|
+
int signs_shifts = 0;
|
|
560
|
+
int arg_max_signs_shifts = -1;
|
|
561
|
+
for (std::size_t i = 0; i < num_parameters; i++) {
|
|
562
|
+
auto &a = box.get_lower_corner()[i];
|
|
563
|
+
auto &b = box.get_upper_corner()[i];
|
|
564
|
+
grid_size[i] = static_cast<int>(std::ceil((std::fabs(b - a) / precision))) + 1;
|
|
565
|
+
signs[i] = b > a;
|
|
566
|
+
if (b < a) {
|
|
567
|
+
std::swap(a, b);
|
|
568
|
+
int local_shift;
|
|
569
|
+
if (!direction.num_parameters())
|
|
570
|
+
local_shift = grid_size[i];
|
|
571
|
+
else {
|
|
572
|
+
local_shift = direction[i] > 0 ? static_cast<int>(std::ceil(grid_size[i] / direction[i])) : 0;
|
|
573
|
+
}
|
|
574
|
+
if (local_shift > signs_shifts) {
|
|
575
|
+
signs_shifts = std::max(signs_shifts, local_shift);
|
|
576
|
+
arg_max_signs_shifts = i;
|
|
577
|
+
}
|
|
578
|
+
}
|
|
579
|
+
|
|
580
|
+
// fix the box
|
|
581
|
+
}
|
|
582
|
+
if (signs_shifts > 0) {
|
|
583
|
+
for (std::size_t i = 0; i < num_parameters; i++)
|
|
584
|
+
grid_size[i] += signs_shifts; // this may be too much for large num_parameters
|
|
585
|
+
grid_size[arg_max_signs_shifts] = 1;
|
|
586
|
+
if (verbose)
|
|
587
|
+
std::cout << "Had to flatten/shift coordinate " << arg_max_signs_shifts << " by " << signs_shifts << std::endl;
|
|
588
|
+
}
|
|
589
|
+
Module<value_type> out(box);
|
|
590
|
+
box.inflate(2 * precision); // for infinte summands
|
|
591
|
+
|
|
592
|
+
if (verbose) std::cout << "Num parameters : " << num_parameters << std::endl;
|
|
593
|
+
if (verbose) std::cout << "Box : " << box << std::endl;
|
|
594
|
+
if (num_parameters < 1) return out;
|
|
595
|
+
|
|
596
|
+
// first line to compute
|
|
597
|
+
// TODO: change here
|
|
598
|
+
// for (auto i = 0u; i < basepoint.size() - 1; i++)
|
|
599
|
+
// basepoint[i] -= box.get_upper_corner().back();
|
|
600
|
+
// basepoint.back() = 0;
|
|
601
|
+
Line<value_type> current_line(basepoint, direction);
|
|
602
|
+
if (verbose) std::cout << "First line basepoint " << basepoint << std::endl;
|
|
603
|
+
|
|
604
|
+
{
|
|
605
|
+
Timer timer("Initializing mma...\n", verbose);
|
|
606
|
+
// fills the first barcode
|
|
607
|
+
slicer.push_to(current_line);
|
|
608
|
+
slicer.compute_persistence();
|
|
609
|
+
auto barcode = slicer.get_flat_barcode();
|
|
610
|
+
auto num_bars = barcode.size();
|
|
611
|
+
out.resize(num_bars);
|
|
612
|
+
/* Filtration_value birthContainer(num_parameters), */
|
|
613
|
+
/* deathContainer(num_parameters); */
|
|
614
|
+
for (std::size_t i = 0; i < num_bars; i++) {
|
|
615
|
+
const auto &[dim, bar] = barcode[i];
|
|
616
|
+
/* const auto &[birth, death] = bar; */
|
|
617
|
+
out[i].set_dimension(dim);
|
|
618
|
+
/* out[i].add_bar(birth, death, basepoint, birthContainer, deathContainer,
|
|
619
|
+
*/
|
|
620
|
+
/* threshold, box); */
|
|
621
|
+
}
|
|
622
|
+
|
|
623
|
+
out.add_barcode(current_line, barcode, threshold);
|
|
624
|
+
|
|
625
|
+
if (verbose) std::cout << "Instantiated " << num_bars << " summands" << std::endl;
|
|
626
|
+
}
|
|
627
|
+
// TODO : change here
|
|
628
|
+
// std::vector<int> grid_size(num_parameters - 1);
|
|
629
|
+
// auto h = box.get_upper_corner().back() - box.get_lower_corner().back();
|
|
630
|
+
// for (int i = 0; i < num_parameters - 1; i++) {
|
|
631
|
+
// auto a = box.get_lower_corner()[i];
|
|
632
|
+
// auto b = box.get_upper_corner()[i];
|
|
633
|
+
// grid_size[i] =
|
|
634
|
+
// static_cast<unsigned int>(std::ceil((std::abs(b - a + h) /
|
|
635
|
+
// precision)));
|
|
636
|
+
// }
|
|
637
|
+
// TODO : change here
|
|
638
|
+
if (verbose) {
|
|
639
|
+
std::cout << "Grid size " << Gudhi::multi_filtration::One_critical_filtration(grid_size) << " Signs ";
|
|
640
|
+
if (signs.empty()) {
|
|
641
|
+
std::cout << "[]";
|
|
642
|
+
} else {
|
|
643
|
+
std::cout << "[";
|
|
644
|
+
for (std::size_t i = 0; i < signs.size() - 1; i++) {
|
|
645
|
+
std::cout << signs[i] << ", ";
|
|
646
|
+
}
|
|
647
|
+
std::cout << signs.back() << "]";
|
|
648
|
+
}
|
|
649
|
+
std::cout << std::endl;
|
|
650
|
+
std::cout << "Max error " << precision << std::endl;
|
|
651
|
+
}
|
|
652
|
+
|
|
653
|
+
{
|
|
654
|
+
Timer timer("Computing mma...", verbose);
|
|
655
|
+
// actual computation. -1 as line grid is n-1 dim, -1 as we start from 0
|
|
656
|
+
// _rec_mma(out, basepoint, grid_size, num_parameters - 2, slicer,
|
|
657
|
+
// precision,
|
|
658
|
+
// threshold);
|
|
659
|
+
// TODO : change here
|
|
660
|
+
|
|
661
|
+
for (std::size_t i = 1; i < num_parameters; i++) {
|
|
662
|
+
// the loop is on the faces of the lower box
|
|
663
|
+
// should be parallelizable, up to a mutex on out
|
|
664
|
+
if (direction.num_parameters() && direction[i] == 0.0) continue; // skip faces with codim d_i=0
|
|
665
|
+
auto temp_grid_size = grid_size;
|
|
666
|
+
temp_grid_size[i] = 0;
|
|
667
|
+
if (verbose)
|
|
668
|
+
std::cout << "Face " << i << "/" << num_parameters << " with grid size "
|
|
669
|
+
<< Gudhi::multi_filtration::One_critical_filtration(temp_grid_size) << std::endl;
|
|
670
|
+
// if (!direction.size() || direction[0] > 0)
|
|
671
|
+
_rec_mma2<0>(out,
|
|
672
|
+
Gudhi::multi_filtration::One_critical_filtration<value_type>(basepoint),
|
|
673
|
+
direction,
|
|
674
|
+
temp_grid_size,
|
|
675
|
+
signs,
|
|
676
|
+
num_parameters - 1,
|
|
677
|
+
slicer.weak_copy(),
|
|
678
|
+
precision,
|
|
679
|
+
threshold);
|
|
680
|
+
}
|
|
681
|
+
// last one, we can destroy basepoint & cie
|
|
682
|
+
if (!direction.num_parameters() || direction[0] > 0) {
|
|
683
|
+
grid_size[0] = 0;
|
|
684
|
+
if (verbose)
|
|
685
|
+
std::cout << "Face " << num_parameters << "/" << num_parameters << " with grid size "
|
|
686
|
+
<< Gudhi::multi_filtration::One_critical_filtration(grid_size) << std::endl;
|
|
687
|
+
_rec_mma2<1>(out,
|
|
688
|
+
std::move(basepoint),
|
|
689
|
+
direction,
|
|
690
|
+
grid_size,
|
|
691
|
+
signs,
|
|
692
|
+
num_parameters - 1,
|
|
693
|
+
std::move(slicer),
|
|
694
|
+
precision,
|
|
695
|
+
threshold);
|
|
696
|
+
}
|
|
697
|
+
}
|
|
698
|
+
|
|
699
|
+
{ // for Timer
|
|
700
|
+
Timer timer("Cleaning output ... ", verbose);
|
|
701
|
+
out.clean();
|
|
702
|
+
if (complete) {
|
|
703
|
+
if (verbose) std::cout << "Completing output ...";
|
|
704
|
+
for (std::size_t i = 0; i < num_parameters; i++) out.fill(precision);
|
|
705
|
+
}
|
|
706
|
+
} // Timer death
|
|
707
|
+
return out;
|
|
708
|
+
};
|
|
709
|
+
|
|
710
|
+
template <typename value_type>
|
|
711
|
+
template <class Barcode>
|
|
712
|
+
inline void Module<value_type>::add_barcode(const Barcode &barcode) {
|
|
713
|
+
constexpr const bool verbose = false;
|
|
714
|
+
if (barcode.size() != module_.size()) {
|
|
715
|
+
std::cerr << "Barcode sizes doesn't match. Module is " << std::to_string(module_.size()) << " and barcode is "
|
|
716
|
+
<< std::to_string(barcode.size()) << std::endl;
|
|
717
|
+
}
|
|
718
|
+
unsigned int count = 0;
|
|
719
|
+
for (const auto &bar_ : barcode) {
|
|
720
|
+
auto &summand = this->operator[](count++);
|
|
721
|
+
auto &[dim, bar] = bar_;
|
|
722
|
+
auto &[birth_filtration, death_filtration] = bar;
|
|
723
|
+
if constexpr (verbose) std::cout << "Birth " << birth_filtration << " Death " << death_filtration << std::endl;
|
|
724
|
+
summand.add_bar(birth_filtration, death_filtration);
|
|
725
|
+
}
|
|
726
|
+
}
|
|
727
|
+
|
|
728
|
+
template <typename value_type>
|
|
729
|
+
inline void Module<value_type>::add_barcode(
|
|
730
|
+
const Line<value_type> &line,
|
|
731
|
+
const std::vector<std::pair<int, std::pair<value_type, value_type>>> &barcode,
|
|
732
|
+
const bool threshold_in) {
|
|
733
|
+
assert(barcode.size() == module_.size() && "Barcode sizes doesn't match.");
|
|
734
|
+
|
|
735
|
+
auto count = 0U;
|
|
736
|
+
for (const auto &extBar : barcode) {
|
|
737
|
+
auto &[dim, bar] = extBar;
|
|
738
|
+
_add_bar_with_threshold(line, bar, threshold_in, this->operator[](count++));
|
|
739
|
+
}
|
|
740
|
+
}
|
|
741
|
+
|
|
742
|
+
template <typename value_type>
|
|
743
|
+
inline void Module<value_type>::add_barcode(const Line<value_type> &line,
|
|
744
|
+
const std::vector<std::pair<value_type, value_type>> &barcode,
|
|
745
|
+
const bool threshold_in) {
|
|
746
|
+
assert(barcode.size() == module_.size() && "Barcode sizes doesn't match.");
|
|
747
|
+
|
|
748
|
+
auto count = 0U;
|
|
749
|
+
for (const auto &bar : barcode) {
|
|
750
|
+
_add_bar_with_threshold(line, bar, threshold_in, this->operator[](count++));
|
|
751
|
+
}
|
|
752
|
+
}
|
|
753
|
+
|
|
754
|
+
template <typename value_type>
|
|
755
|
+
inline void Module<value_type>::_add_bar_with_threshold(const Line<value_type> &line,
|
|
756
|
+
const std::pair<value_type, value_type> &bar,
|
|
757
|
+
const bool threshold_in,
|
|
758
|
+
Summand<value_type> &summand) {
|
|
759
|
+
constexpr const bool verbose = false;
|
|
760
|
+
auto [birth_filtration, death_filtration] = bar;
|
|
761
|
+
|
|
762
|
+
if (birth_filtration >= death_filtration) return;
|
|
763
|
+
|
|
764
|
+
if constexpr (verbose) {
|
|
765
|
+
std::cout << "--BAR (" << birth_filtration << ", " << death_filtration << ") at basepoint " << line.base_point()
|
|
766
|
+
<< " direction " << line.direction() << std::endl;
|
|
767
|
+
}
|
|
768
|
+
|
|
769
|
+
auto birth_container = line[birth_filtration];
|
|
770
|
+
if constexpr (verbose) std::cout << " B: " << birth_container << " B*d: " << birth_filtration * line.direction();
|
|
771
|
+
if (birth_container.is_minus_inf()) {
|
|
772
|
+
if (threshold_in) birth_container = box_.get_lower_corner();
|
|
773
|
+
} else {
|
|
774
|
+
bool allInf = true;
|
|
775
|
+
for (std::size_t i = 0U; i < birth_container.num_parameters(); i++) {
|
|
776
|
+
auto t = box_.get_lower_corner()[i];
|
|
777
|
+
if (birth_container[i] < t - 1e-10) birth_container[i] = threshold_in ? t : -filtration_type::T_inf;
|
|
778
|
+
if (birth_container[i] != -filtration_type::T_inf) allInf = false;
|
|
779
|
+
}
|
|
780
|
+
if (allInf) birth_container = filtration_type::minus_inf();
|
|
781
|
+
}
|
|
782
|
+
|
|
783
|
+
auto death_container = line[death_filtration];
|
|
784
|
+
if constexpr (verbose) std::cout << " D: " << death_container;
|
|
785
|
+
if (death_container.is_plus_inf()) {
|
|
786
|
+
if (threshold_in) death_container = box_.get_upper_corner();
|
|
787
|
+
} else {
|
|
788
|
+
bool allInf = true;
|
|
789
|
+
for (std::size_t i = 0U; i < death_container.num_parameters(); i++) {
|
|
790
|
+
auto t = box_.get_upper_corner()[i];
|
|
791
|
+
if (death_container[i] > t + 1e-10) death_container[i] = threshold_in ? t : filtration_type::T_inf;
|
|
792
|
+
if (death_container[i] != filtration_type::T_inf) allInf = false;
|
|
793
|
+
}
|
|
794
|
+
if (allInf) death_container = filtration_type::inf();
|
|
795
|
+
}
|
|
796
|
+
|
|
797
|
+
if constexpr (verbose) std::cout << " BT: " << birth_container << " DT: " << death_container << std::endl;
|
|
798
|
+
summand.add_bar(birth_container, death_container);
|
|
799
|
+
}
|
|
800
|
+
|
|
801
|
+
template <typename value_type>
|
|
802
|
+
inline Module<value_type>::Module() {}
|
|
803
|
+
|
|
804
|
+
template <typename value_type>
|
|
805
|
+
inline Module<value_type>::Module(Box<value_type> &box) : box_(box) {}
|
|
806
|
+
|
|
807
|
+
template <typename value_type>
|
|
808
|
+
inline void Module<value_type>::resize(const unsigned int size) {
|
|
809
|
+
module_.resize(size);
|
|
810
|
+
}
|
|
811
|
+
|
|
812
|
+
template <typename value_type>
|
|
813
|
+
inline Summand<value_type> &Module<value_type>::at(const unsigned int index) {
|
|
814
|
+
return module_.at(index);
|
|
815
|
+
}
|
|
816
|
+
|
|
817
|
+
template <typename value_type>
|
|
818
|
+
inline Summand<value_type> &Module<value_type>::operator[](const size_t index) {
|
|
819
|
+
return this->module_[index];
|
|
820
|
+
}
|
|
821
|
+
|
|
822
|
+
template <typename value_type>
|
|
823
|
+
inline const Summand<value_type> &Module<value_type>::operator[](const size_t index) const {
|
|
824
|
+
return this->module_[index];
|
|
825
|
+
}
|
|
826
|
+
|
|
827
|
+
template <typename value_type>
|
|
828
|
+
inline typename Module<value_type>::module_type::iterator Module<value_type>::begin() {
|
|
829
|
+
return module_.begin();
|
|
830
|
+
}
|
|
831
|
+
|
|
832
|
+
template <typename value_type>
|
|
833
|
+
inline typename Module<value_type>::module_type::const_iterator Module<value_type>::begin() const {
|
|
834
|
+
return module_.cbegin();
|
|
835
|
+
}
|
|
836
|
+
|
|
837
|
+
template <typename value_type>
|
|
838
|
+
inline typename Module<value_type>::module_type::iterator Module<value_type>::end() {
|
|
839
|
+
return module_.end();
|
|
840
|
+
}
|
|
841
|
+
|
|
842
|
+
template <typename value_type>
|
|
843
|
+
inline typename Module<value_type>::module_type::const_iterator Module<value_type>::end() const {
|
|
844
|
+
return module_.cend();
|
|
845
|
+
}
|
|
846
|
+
|
|
847
|
+
template <typename value_type>
|
|
848
|
+
inline void Module<value_type>::add_summand(Summand<value_type> summand, int degree) {
|
|
849
|
+
if (degree >= 0) summand.set_dimension(degree);
|
|
850
|
+
module_.push_back(summand);
|
|
851
|
+
}
|
|
852
|
+
|
|
853
|
+
/**
|
|
854
|
+
* @brief Remove the empty summands of the output
|
|
855
|
+
*
|
|
856
|
+
* @param output p_output:...
|
|
857
|
+
* @param keep_order p_keep_order:... Defaults to false.
|
|
858
|
+
*/
|
|
859
|
+
|
|
860
|
+
template <typename value_type>
|
|
861
|
+
inline void Module<value_type>::clean() {
|
|
862
|
+
module_type tmp;
|
|
863
|
+
for (size_t i = 0u; i < module_.size(); i++) {
|
|
864
|
+
module_[i].clean();
|
|
865
|
+
}
|
|
866
|
+
module_.erase(
|
|
867
|
+
std::remove_if(
|
|
868
|
+
module_.begin(), module_.end(), [](const Summand<value_type> &s) { return s.get_upset().is_plus_inf(); }),
|
|
869
|
+
module_.end());
|
|
870
|
+
}
|
|
871
|
+
|
|
872
|
+
template <typename value_type>
|
|
873
|
+
inline void Module<value_type>::fill(const value_type precision) {
|
|
874
|
+
if (module_.empty()) return;
|
|
875
|
+
|
|
876
|
+
for (Summand<value_type> &sum : module_) {
|
|
877
|
+
sum.complete_birth(precision);
|
|
878
|
+
sum.complete_death(precision);
|
|
879
|
+
}
|
|
880
|
+
}
|
|
881
|
+
|
|
882
|
+
template <typename value_type>
|
|
883
|
+
std::vector<value_type> inline Module<value_type>::get_interleavings(const Box<value_type> &box) {
|
|
884
|
+
std::vector<value_type> out(this->size());
|
|
885
|
+
for (auto i = 0u; i < out.size(); ++i) {
|
|
886
|
+
out[i] = module_[i].get_interleaving(box);
|
|
887
|
+
}
|
|
888
|
+
return out;
|
|
889
|
+
}
|
|
890
|
+
|
|
891
|
+
template <typename value_type>
|
|
892
|
+
typename Module<value_type>::distance_to_idx_type inline Module<value_type>::compute_distance_idx_to(
|
|
893
|
+
const std::vector<value_type> &pt,
|
|
894
|
+
bool full) const {
|
|
895
|
+
typename Module<value_type>::distance_to_idx_type out(module_.size(), std::vector<int>(full ? 4 : 2));
|
|
896
|
+
for (auto i = 0u; i < module_.size(); ++i) {
|
|
897
|
+
out[i] = module_[i].distance_idx_to(pt, full);
|
|
898
|
+
}
|
|
899
|
+
return out;
|
|
900
|
+
}
|
|
901
|
+
|
|
902
|
+
template <typename value_type>
|
|
903
|
+
std::vector<value_type> inline Module<value_type>::compute_distance_to(const std::vector<value_type> &pt,
|
|
904
|
+
bool negative) const {
|
|
905
|
+
std::vector<value_type> out(this->size());
|
|
906
|
+
for (auto i = 0u; i < this->size(); ++i) {
|
|
907
|
+
out[i] = module_[i].distance_to(pt, negative);
|
|
908
|
+
}
|
|
909
|
+
return out;
|
|
910
|
+
}
|
|
911
|
+
|
|
912
|
+
template <typename value_type>
|
|
913
|
+
std::vector<std::vector<value_type>> inline Module<value_type>::compute_distances_to(
|
|
914
|
+
const std::vector<std::vector<value_type>> &pts,
|
|
915
|
+
bool negative,
|
|
916
|
+
int n_jobs) const {
|
|
917
|
+
std::vector<std::vector<value_type>> out(pts.size(), std::vector<value_type>(this->size()));
|
|
918
|
+
oneapi::tbb::task_arena arena(n_jobs); // limits the number of threads
|
|
919
|
+
arena.execute([&] {
|
|
920
|
+
tbb::parallel_for(std::size_t(0u), pts.size(), [&](std::size_t i) {
|
|
921
|
+
tbb::parallel_for(std::size_t(0u), std::size_t(this->size()), [&](std::size_t j) {
|
|
922
|
+
out[i][j] = module_[j].distance_to(pts[i], negative);
|
|
923
|
+
});
|
|
924
|
+
});
|
|
925
|
+
});
|
|
926
|
+
return out;
|
|
927
|
+
}
|
|
928
|
+
|
|
929
|
+
template <typename value_type>
|
|
930
|
+
template <typename dtype, typename indices_type>
|
|
931
|
+
void inline Module<value_type>::compute_distances_to(dtype *data_ptr,
|
|
932
|
+
const std::vector<std::vector<value_type>> &pts,
|
|
933
|
+
bool negative,
|
|
934
|
+
int n_jobs) const {
|
|
935
|
+
tensor::static_tensor_view<dtype, indices_type> container(
|
|
936
|
+
data_ptr, {static_cast<int>(pts.size()), static_cast<int>(this->size())});
|
|
937
|
+
oneapi::tbb::task_arena arena(n_jobs); // limits the number of threads
|
|
938
|
+
arena.execute([&] {
|
|
939
|
+
tbb::parallel_for(std::size_t(0u), pts.size(), [&](std::size_t i) {
|
|
940
|
+
// tbb::parallel_for(std::size_t(0u), std::size_t(this->size()), [&](std::size_t j) {
|
|
941
|
+
dtype *current_ptr = &container[{static_cast<int>(i), 0}];
|
|
942
|
+
for (std::size_t j = 0u; j < this->size(); ++j) {
|
|
943
|
+
*(current_ptr + j) = module_[j].distance_to(pts[i], negative);
|
|
944
|
+
}
|
|
945
|
+
});
|
|
946
|
+
// });
|
|
947
|
+
});
|
|
948
|
+
}
|
|
949
|
+
|
|
950
|
+
template <typename value_type>
|
|
951
|
+
typename Module<value_type>::distances_to_idx_type inline Module<value_type>::compute_distances_idx_to(
|
|
952
|
+
const std::vector<std::vector<value_type>> &pts,
|
|
953
|
+
bool full,
|
|
954
|
+
int n_jobs) const {
|
|
955
|
+
Module::distances_to_idx_type out(pts.size(),
|
|
956
|
+
Module::distance_to_idx_type(module_.size(), std::vector<int>(full ? 4 : 2)));
|
|
957
|
+
|
|
958
|
+
oneapi::tbb::task_arena arena(n_jobs); // limits the number of threads
|
|
959
|
+
arena.execute([&] {
|
|
960
|
+
tbb::parallel_for(std::size_t(0u), pts.size(), [&](std::size_t i) {
|
|
961
|
+
tbb::parallel_for(std::size_t(0u), std::size_t(this->size()), [&](std::size_t j) {
|
|
962
|
+
out[i][j] = module_[j].distance_idx_to(pts[i], full);
|
|
963
|
+
});
|
|
964
|
+
});
|
|
965
|
+
});
|
|
966
|
+
return out;
|
|
967
|
+
}
|
|
968
|
+
|
|
969
|
+
template <typename value_type>
|
|
970
|
+
inline std::vector<std::vector<value_type>> Module<value_type>::compute_pixels(
|
|
971
|
+
const std::vector<std::vector<value_type>> &coordinates,
|
|
972
|
+
const std::vector<int> °rees,
|
|
973
|
+
const Box<value_type> &box,
|
|
974
|
+
const value_type delta,
|
|
975
|
+
const value_type p,
|
|
976
|
+
const bool normalize,
|
|
977
|
+
const int n_jobs) {
|
|
978
|
+
auto num_degrees = degrees.size();
|
|
979
|
+
auto num_pts = coordinates.size();
|
|
980
|
+
std::vector<std::vector<value_type>> out(num_degrees, std::vector<value_type>(num_pts));
|
|
981
|
+
|
|
982
|
+
typename module_type::iterator start;
|
|
983
|
+
typename module_type::iterator end = module_.begin();
|
|
984
|
+
for (auto degree_idx = 0u; degree_idx < num_degrees; degree_idx++) {
|
|
985
|
+
{ // for Timer
|
|
986
|
+
auto d = degrees[degree_idx];
|
|
987
|
+
Debug::Timer timer("Computing image of dimension " + std::to_string(d) + " ...", verbose);
|
|
988
|
+
start = end;
|
|
989
|
+
while (start != module_.end() && start->get_dimension() != d) start++;
|
|
990
|
+
if (start == module_.end()) break;
|
|
991
|
+
end = start;
|
|
992
|
+
while (end != module_.end() && end->get_dimension() == d) end++;
|
|
993
|
+
out[degree_idx] = compute_pixels_of_degree(start, end, delta, p, normalize, box, coordinates, n_jobs);
|
|
994
|
+
} // Timer death
|
|
995
|
+
}
|
|
996
|
+
return out;
|
|
997
|
+
}
|
|
998
|
+
|
|
999
|
+
template <typename value_type>
|
|
1000
|
+
inline typename std::vector<typename Module<value_type>::image_type> Module<value_type>::get_vectorization(
|
|
1001
|
+
const value_type delta,
|
|
1002
|
+
const value_type p,
|
|
1003
|
+
const bool normalize,
|
|
1004
|
+
const Box<value_type> &box,
|
|
1005
|
+
unsigned int horizontalResolution,
|
|
1006
|
+
unsigned int verticalResolution) {
|
|
1007
|
+
dimension_type maxDim = module_.back().get_dimension();
|
|
1008
|
+
std::vector<Module::image_type> image_vector(maxDim + 1);
|
|
1009
|
+
typename module_type::iterator start;
|
|
1010
|
+
typename module_type::iterator end = module_.begin();
|
|
1011
|
+
for (dimension_type d = 0; d <= maxDim; d++) {
|
|
1012
|
+
{ // for Timer
|
|
1013
|
+
Debug::Timer timer("Computing image of dimension " + std::to_string(d) + " ...", verbose);
|
|
1014
|
+
start = end;
|
|
1015
|
+
while (end != module_.end() && end->get_dimension() == d) end++;
|
|
1016
|
+
_compute_2D_image(
|
|
1017
|
+
image_vector.at(d), start, end, delta, p, normalize, box, horizontalResolution, verticalResolution);
|
|
1018
|
+
} // Timer death
|
|
1019
|
+
}
|
|
1020
|
+
return image_vector;
|
|
1021
|
+
}
|
|
1022
|
+
|
|
1023
|
+
template <typename value_type>
|
|
1024
|
+
inline std::vector<typename Module<value_type>::image_type> Module<value_type>::get_vectorization(
|
|
1025
|
+
unsigned int horizontalResolution,
|
|
1026
|
+
unsigned int verticalResolution,
|
|
1027
|
+
get_2dpixel_value_function_type get_pixel_value) const {
|
|
1028
|
+
dimension_type maxDim = module_.back().get_dimension();
|
|
1029
|
+
std::vector<Module::image_type> image_vector(maxDim + 1);
|
|
1030
|
+
typename module_type::const_iterator start;
|
|
1031
|
+
typename module_type::const_iterator end = module_.begin();
|
|
1032
|
+
for (dimension_type d = 0; d <= maxDim; d++) {
|
|
1033
|
+
{ // for Timer
|
|
1034
|
+
Debug::Timer timer("Computing image of dimension " + std::to_string(d) + " ...", verbose);
|
|
1035
|
+
start = end;
|
|
1036
|
+
while (end != module_.end() && end->get_dimension() == d) end++;
|
|
1037
|
+
_compute_2D_image(image_vector.at(d), start, end, horizontalResolution, verticalResolution, get_pixel_value);
|
|
1038
|
+
} // Timer death
|
|
1039
|
+
}
|
|
1040
|
+
return image_vector;
|
|
1041
|
+
}
|
|
1042
|
+
|
|
1043
|
+
template <typename value_type>
|
|
1044
|
+
inline typename Module<value_type>::image_type Module<value_type>::get_vectorization_in_dimension(
|
|
1045
|
+
const dimension_type dimension,
|
|
1046
|
+
const value_type delta,
|
|
1047
|
+
const value_type p,
|
|
1048
|
+
const bool normalize,
|
|
1049
|
+
const Box<value_type> &box,
|
|
1050
|
+
unsigned int horizontalResolution,
|
|
1051
|
+
unsigned int verticalResolution) {
|
|
1052
|
+
Debug::Timer timer("Computing image of dimension " + std::to_string(dimension) + " ...", verbose);
|
|
1053
|
+
|
|
1054
|
+
Module::image_type image;
|
|
1055
|
+
typename module_type::iterator start = module_.begin();
|
|
1056
|
+
while (start != module_.end() && start->get_dimension() < dimension) start++;
|
|
1057
|
+
typename module_type::iterator end = start;
|
|
1058
|
+
while (end != module_.end() && end->get_dimension() == dimension) end++;
|
|
1059
|
+
_compute_2D_image(image, start, end, delta, p, normalize, box, horizontalResolution, verticalResolution);
|
|
1060
|
+
|
|
1061
|
+
return image;
|
|
1062
|
+
}
|
|
1063
|
+
|
|
1064
|
+
template <typename value_type>
|
|
1065
|
+
inline typename Module<value_type>::image_type Module<value_type>::get_vectorization_in_dimension(
|
|
1066
|
+
const dimension_type dimension,
|
|
1067
|
+
unsigned int horizontalResolution,
|
|
1068
|
+
unsigned int verticalResolution,
|
|
1069
|
+
get_2dpixel_value_function_type get_pixel_value) const {
|
|
1070
|
+
Debug::Timer timer("Computing image of dimension " + std::to_string(dimension) + " ...", verbose);
|
|
1071
|
+
|
|
1072
|
+
typename Module::image_type image;
|
|
1073
|
+
typename module_type::const_iterator start = module_.begin();
|
|
1074
|
+
while (start != module_.end() && start->get_dimension() < dimension) start++;
|
|
1075
|
+
typename module_type::const_iterator end = start;
|
|
1076
|
+
while (end != module_.end() && end->get_dimension() == dimension) end++;
|
|
1077
|
+
_compute_2D_image(image, start, end, horizontalResolution, verticalResolution, get_pixel_value);
|
|
1078
|
+
|
|
1079
|
+
return image;
|
|
1080
|
+
}
|
|
1081
|
+
|
|
1082
|
+
template <typename value_type>
|
|
1083
|
+
std::vector<value_type> Module<value_type>::get_landscape_values(const std::vector<value_type> &x,
|
|
1084
|
+
const dimension_type dimension) const {
|
|
1085
|
+
std::vector<value_type> out;
|
|
1086
|
+
out.reserve(this->size());
|
|
1087
|
+
for (unsigned int i = 0; i < this->size(); i++) {
|
|
1088
|
+
const Summand<value_type> &summand = this->module_[i];
|
|
1089
|
+
if (summand.get_dimension() == dimension) out.push_back(summand.get_landscape_value(x));
|
|
1090
|
+
}
|
|
1091
|
+
std::sort(out.begin(), out.end(), [](const value_type x, const value_type y) { return x > y; });
|
|
1092
|
+
return out;
|
|
1093
|
+
}
|
|
1094
|
+
|
|
1095
|
+
template <typename value_type>
|
|
1096
|
+
typename Module<value_type>::image_type Module<value_type>::get_landscape(
|
|
1097
|
+
const dimension_type dimension,
|
|
1098
|
+
const unsigned int k,
|
|
1099
|
+
const Box<value_type> &box,
|
|
1100
|
+
const std::vector<unsigned int> &resolution) const {
|
|
1101
|
+
// TODO extend in higher dimension (ie, change the image type to a template
|
|
1102
|
+
// class)
|
|
1103
|
+
Module::image_type image;
|
|
1104
|
+
image.resize(resolution[0], std::vector<value_type>(resolution[1]));
|
|
1105
|
+
value_type stepX = (box.get_upper_corner()[0] - box.get_lower_corner()[0]) / resolution[0];
|
|
1106
|
+
value_type stepY = (box.get_upper_corner()[1] - box.get_lower_corner()[1]) / resolution[1];
|
|
1107
|
+
tbb::parallel_for(0U, resolution[0], [&](unsigned int i) {
|
|
1108
|
+
tbb::parallel_for(0U, resolution[1], [&](unsigned int j) {
|
|
1109
|
+
auto landscape = this->get_landscape_values(
|
|
1110
|
+
{box.get_lower_corner()[0] + stepX * i, box.get_lower_corner()[1] + stepY * j}, dimension);
|
|
1111
|
+
image[i][j] = k < landscape.size() ? landscape[k] : 0;
|
|
1112
|
+
});
|
|
1113
|
+
});
|
|
1114
|
+
return image;
|
|
1115
|
+
}
|
|
1116
|
+
|
|
1117
|
+
template <typename value_type>
|
|
1118
|
+
std::vector<typename Module<value_type>::image_type> Module<value_type>::get_landscapes(
|
|
1119
|
+
const dimension_type dimension,
|
|
1120
|
+
const std::vector<unsigned int> ks,
|
|
1121
|
+
const Box<value_type> &box,
|
|
1122
|
+
const std::vector<unsigned int> &resolution) const {
|
|
1123
|
+
std::vector<Module::image_type> images(ks.size());
|
|
1124
|
+
for (auto &image : images) image.resize(resolution[0], std::vector<value_type>(resolution[1]));
|
|
1125
|
+
value_type stepX = (box.get_upper_corner()[0] - box.get_lower_corner()[0]) / resolution[0];
|
|
1126
|
+
value_type stepY = (box.get_upper_corner()[1] - box.get_lower_corner()[1]) / resolution[1];
|
|
1127
|
+
|
|
1128
|
+
tbb::parallel_for(0U, resolution[0], [&](unsigned int i) {
|
|
1129
|
+
tbb::parallel_for(0U, resolution[1], [&](unsigned int j) {
|
|
1130
|
+
std::vector<value_type> landscapes = this->get_landscape_values(
|
|
1131
|
+
{box.get_lower_corner()[0] + stepX * i, box.get_lower_corner()[1] + stepY * j}, dimension);
|
|
1132
|
+
for (const auto k : ks) {
|
|
1133
|
+
images[k][i][j] = k < landscapes.size() ? landscapes[k] : 0;
|
|
1134
|
+
}
|
|
1135
|
+
});
|
|
1136
|
+
});
|
|
1137
|
+
return images;
|
|
1138
|
+
}
|
|
1139
|
+
|
|
1140
|
+
template <typename value_type>
|
|
1141
|
+
inline Box<value_type> Module<value_type>::get_box() const {
|
|
1142
|
+
return this->box_;
|
|
1143
|
+
}
|
|
1144
|
+
|
|
1145
|
+
template <typename value_type>
|
|
1146
|
+
inline void Module<value_type>::set_box(Box<value_type> box) {
|
|
1147
|
+
this->box_ = box;
|
|
1148
|
+
}
|
|
1149
|
+
|
|
1150
|
+
template <typename value_type>
|
|
1151
|
+
inline unsigned int Module<value_type>::size() const {
|
|
1152
|
+
return this->module_.size();
|
|
1153
|
+
}
|
|
1154
|
+
|
|
1155
|
+
template <typename value_type>
|
|
1156
|
+
inline void Module<value_type>::infer_box(std::vector<filtration_type> &f) {
|
|
1157
|
+
this->box_.infer_from_filters(f);
|
|
1158
|
+
}
|
|
1159
|
+
|
|
1160
|
+
template <typename value_type>
|
|
1161
|
+
inline dimension_type Module<value_type>::get_dimension() const {
|
|
1162
|
+
return this->module_.empty() ? -1 : this->module_.back().get_dimension();
|
|
1163
|
+
}
|
|
1164
|
+
|
|
1165
|
+
template <typename value_type>
|
|
1166
|
+
inline std::vector<Summand<value_type>> Module<value_type>::get_summands_of_dimension(const int dimension) const {
|
|
1167
|
+
std::vector<Summand<value_type>> list;
|
|
1168
|
+
for (const Summand<value_type> &summand : this->module_) {
|
|
1169
|
+
if (summand.get_dimension() == dimension) list.push_back(summand);
|
|
1170
|
+
}
|
|
1171
|
+
return list;
|
|
1172
|
+
}
|
|
1173
|
+
|
|
1174
|
+
template <typename value_type>
|
|
1175
|
+
inline std::vector<std::pair<std::vector<std::vector<value_type>>, std::vector<std::vector<value_type>>>>
|
|
1176
|
+
Module<value_type>::get_corners_of_dimension(const int dimension) const {
|
|
1177
|
+
std::vector<std::pair<std::vector<std::vector<value_type>>, std::vector<std::vector<value_type>>>> list;
|
|
1178
|
+
for (const Summand<value_type> &summand : this->module_) {
|
|
1179
|
+
if (summand.get_dimension() == dimension)
|
|
1180
|
+
list.push_back(std::make_pair(
|
|
1181
|
+
std::vector<std::vector<value_type>>(summand.get_birth_list().begin(), summand.get_birth_list().end()),
|
|
1182
|
+
std::vector<std::vector<value_type>>(summand.get_death_list().begin(), summand.get_death_list().end())));
|
|
1183
|
+
}
|
|
1184
|
+
return list;
|
|
1185
|
+
}
|
|
1186
|
+
|
|
1187
|
+
template <typename value_type>
|
|
1188
|
+
std::vector<std::vector<std::pair<value_type, value_type>>> Module<value_type>::get_barcode2(
|
|
1189
|
+
const Line<value_type> &l,
|
|
1190
|
+
const dimension_type dimension) const {
|
|
1191
|
+
constexpr const bool verbose = false;
|
|
1192
|
+
std::vector<std::vector<std::pair<value_type, value_type>>> barcode(this->get_dimension() + 1);
|
|
1193
|
+
for (auto i = 0; i < this->get_dimension(); ++i) {
|
|
1194
|
+
barcode[i].reserve(this->size());
|
|
1195
|
+
}
|
|
1196
|
+
for (unsigned int i = 0; i < this->size(); i++) {
|
|
1197
|
+
const Summand<value_type> &summand = this->module_[i];
|
|
1198
|
+
if constexpr (verbose) std::cout << "Summand of dimension " << summand.get_dimension() << std::endl;
|
|
1199
|
+
|
|
1200
|
+
if (dimension != -1 && summand.get_dimension() != dimension) continue;
|
|
1201
|
+
/* if (dimension != -1 && summand.get_dimension() > dimension) */
|
|
1202
|
+
/* break; */
|
|
1203
|
+
const auto &pushed_summand = summand.get_bar2(l);
|
|
1204
|
+
|
|
1205
|
+
barcode[summand.get_dimension()].push_back(pushed_summand);
|
|
1206
|
+
}
|
|
1207
|
+
return barcode;
|
|
1208
|
+
}
|
|
1209
|
+
|
|
1210
|
+
template <typename value_type>
|
|
1211
|
+
MultiDiagram<typename Module<value_type>::filtration_type, value_type>
|
|
1212
|
+
Module<value_type>::get_barcode(const Line<value_type> &l, const dimension_type dimension, const bool threshold) const {
|
|
1213
|
+
constexpr const bool verbose = false;
|
|
1214
|
+
if constexpr (verbose)
|
|
1215
|
+
std::cout << "Computing barcode of dimension " << dimension << " and threshold " << threshold << std::endl;
|
|
1216
|
+
std::vector<MultiDiagram_point<filtration_type>> barcode(this->size());
|
|
1217
|
+
std::pair<value_type, value_type> threshold_bounds;
|
|
1218
|
+
if (threshold) threshold_bounds = l.get_bounds(this->box_);
|
|
1219
|
+
unsigned int summand_idx = 0;
|
|
1220
|
+
for (unsigned int i = 0; i < this->size(); i++) {
|
|
1221
|
+
const Summand<value_type> &summand = this->module_[i];
|
|
1222
|
+
if constexpr (verbose) std::cout << "Summand of dimension " << summand.get_dimension() << std::endl;
|
|
1223
|
+
|
|
1224
|
+
if (dimension != -1 && summand.get_dimension() != dimension) continue;
|
|
1225
|
+
/* if (dimension != -1 && summand.get_dimension() > dimension) */
|
|
1226
|
+
/* break; */
|
|
1227
|
+
auto pushed_summand = summand.get_bar(l);
|
|
1228
|
+
|
|
1229
|
+
filtration_type &pbirth = pushed_summand.first;
|
|
1230
|
+
filtration_type &pdeath = pushed_summand.second;
|
|
1231
|
+
if constexpr (verbose) std::cout << "BAR : " << pbirth << " " << pdeath << std::endl;
|
|
1232
|
+
if (threshold) {
|
|
1233
|
+
auto min = l[threshold_bounds.first];
|
|
1234
|
+
auto max = l[threshold_bounds.second];
|
|
1235
|
+
if (!(pbirth < max) || !(pdeath > min)) {
|
|
1236
|
+
/* continue; */ // We still need summands to be aligned. The price to
|
|
1237
|
+
// pay is some memory.
|
|
1238
|
+
pbirth = std::numeric_limits<filtration_type>::infinity();
|
|
1239
|
+
pdeath = pbirth;
|
|
1240
|
+
}
|
|
1241
|
+
pbirth.push_to_least_common_upper_bound(min);
|
|
1242
|
+
pdeath.pull_to_greatest_common_lower_bound(max);
|
|
1243
|
+
}
|
|
1244
|
+
barcode[summand_idx++] = MultiDiagram_point(summand.get_dimension(), pbirth, pdeath);
|
|
1245
|
+
}
|
|
1246
|
+
barcode.resize(summand_idx);
|
|
1247
|
+
return MultiDiagram<filtration_type, value_type>(barcode);
|
|
1248
|
+
}
|
|
1249
|
+
|
|
1250
|
+
template <typename value_type>
|
|
1251
|
+
MultiDiagrams<typename Module<value_type>::filtration_type, value_type> Module<value_type>::get_barcodes(
|
|
1252
|
+
const std::vector<Line<value_type>> &lines,
|
|
1253
|
+
const dimension_type dimension,
|
|
1254
|
+
const bool threshold) const {
|
|
1255
|
+
unsigned int nlines = lines.size();
|
|
1256
|
+
MultiDiagrams<typename Module<value_type>::filtration_type, value_type> out(nlines);
|
|
1257
|
+
tbb::parallel_for(0U, nlines, [&](unsigned int i) {
|
|
1258
|
+
const Line<value_type> &l = lines[i];
|
|
1259
|
+
out[i] = this->get_barcode(l, dimension, threshold);
|
|
1260
|
+
});
|
|
1261
|
+
return out;
|
|
1262
|
+
}
|
|
1263
|
+
|
|
1264
|
+
template <typename value_type>
|
|
1265
|
+
std::vector<std::vector<std::vector<std::pair<value_type, value_type>>>> Module<value_type>::get_barcodes2(
|
|
1266
|
+
const std::vector<Line<value_type>> &lines,
|
|
1267
|
+
const dimension_type dimension) const {
|
|
1268
|
+
unsigned int nlines = lines.size();
|
|
1269
|
+
std::vector<std::vector<std::vector<std::pair<value_type, value_type>>>> out(
|
|
1270
|
+
this->get_dimension() + 1, std::vector<std::vector<std::pair<value_type, value_type>>>(nlines));
|
|
1271
|
+
tbb::parallel_for(0U, nlines, [&](unsigned int i) {
|
|
1272
|
+
const Line<value_type> &l = lines[i];
|
|
1273
|
+
for (const auto &summand : module_) {
|
|
1274
|
+
if (dimension != -1 && summand.get_dimension() != dimension) continue;
|
|
1275
|
+
const auto &bar = summand.get_bar2(l);
|
|
1276
|
+
out[summand.get_dimension()][i].push_back(bar);
|
|
1277
|
+
}
|
|
1278
|
+
});
|
|
1279
|
+
return out;
|
|
1280
|
+
}
|
|
1281
|
+
|
|
1282
|
+
template <typename value_type>
|
|
1283
|
+
MultiDiagrams<typename Module<value_type>::filtration_type, value_type> Module<value_type>::get_barcodes(
|
|
1284
|
+
const std::vector<filtration_type> &basepoints,
|
|
1285
|
+
const dimension_type dimension,
|
|
1286
|
+
const bool threshold) const {
|
|
1287
|
+
unsigned int nlines = basepoints.size();
|
|
1288
|
+
MultiDiagrams<typename Module<value_type>::filtration_type, value_type> out(nlines);
|
|
1289
|
+
// for (unsigned int i = 0; i < nlines; i++){
|
|
1290
|
+
tbb::parallel_for(0U, nlines, [&](unsigned int i) {
|
|
1291
|
+
const Line<value_type> &l = Line<value_type>(basepoints[i]);
|
|
1292
|
+
out[i] = this->get_barcode(l, dimension, threshold);
|
|
1293
|
+
});
|
|
1294
|
+
return out;
|
|
1295
|
+
}
|
|
1296
|
+
|
|
1297
|
+
template <typename value_type>
|
|
1298
|
+
std::vector<int> Module<value_type>::euler_curve(const std::vector<filtration_type> &points) const {
|
|
1299
|
+
unsigned int npts = points.size();
|
|
1300
|
+
std::vector<int> out(npts);
|
|
1301
|
+
// #pragma omp parallel for
|
|
1302
|
+
tbb::parallel_for(0U, static_cast<unsigned int>(out.size()), [&](unsigned int i) {
|
|
1303
|
+
auto &euler_char = out[i];
|
|
1304
|
+
const filtration_type &point = points[i];
|
|
1305
|
+
/* #pragma omp parallel for reduction(+ : euler_char) */
|
|
1306
|
+
for (const Summand<value_type> &I : this->module_) {
|
|
1307
|
+
if (I.contains(point)) {
|
|
1308
|
+
int sign = I.get_dimension() % 2 ? -1 : 1;
|
|
1309
|
+
euler_char += sign;
|
|
1310
|
+
}
|
|
1311
|
+
}
|
|
1312
|
+
});
|
|
1313
|
+
return out;
|
|
1314
|
+
}
|
|
1315
|
+
|
|
1316
|
+
template <typename value_type>
|
|
1317
|
+
inline Box<value_type> Module<value_type>::get_bounds() const {
|
|
1318
|
+
dimension_type num_parameters = box_.get_lower_corner().num_parameters();
|
|
1319
|
+
filtration_type lower_bound(num_parameters, std::numeric_limits<value_type>::infinity());
|
|
1320
|
+
filtration_type upper_bound(num_parameters, -std::numeric_limits<value_type>::infinity());
|
|
1321
|
+
for (const auto &summand : module_) {
|
|
1322
|
+
const auto &summand_bounds = summand.get_bounds();
|
|
1323
|
+
const auto &[m, M] = summand_bounds.get_bounding_corners();
|
|
1324
|
+
for (auto parameter = 0; parameter < num_parameters; parameter++) {
|
|
1325
|
+
lower_bound[parameter] = std::min(m[parameter], lower_bound[parameter]);
|
|
1326
|
+
upper_bound[parameter] = std::min(M[parameter], upper_bound[parameter]);
|
|
1327
|
+
}
|
|
1328
|
+
}
|
|
1329
|
+
return Box(lower_bound, upper_bound);
|
|
1330
|
+
}
|
|
1331
|
+
|
|
1332
|
+
template <typename value_type>
|
|
1333
|
+
inline void Module<value_type>::rescale(const std::vector<value_type> &rescale_factors, int degree) {
|
|
1334
|
+
for (auto &summand : module_) {
|
|
1335
|
+
if (degree == -1 or summand.get_dimension() == degree) summand.rescale(rescale_factors);
|
|
1336
|
+
}
|
|
1337
|
+
}
|
|
1338
|
+
|
|
1339
|
+
template <typename value_type>
|
|
1340
|
+
inline void Module<value_type>::translate(const std::vector<value_type> &translation, int degree) {
|
|
1341
|
+
for (auto &summand : module_) {
|
|
1342
|
+
if (degree == -1 or summand.get_dimension() == degree) summand.translate(translation);
|
|
1343
|
+
}
|
|
1344
|
+
}
|
|
1345
|
+
|
|
1346
|
+
template <typename value_type>
|
|
1347
|
+
inline std::vector<value_type> Module<value_type>::compute_pixels_of_degree(
|
|
1348
|
+
const typename module_type::iterator start,
|
|
1349
|
+
const typename module_type::iterator end,
|
|
1350
|
+
const value_type delta,
|
|
1351
|
+
const value_type p,
|
|
1352
|
+
const bool normalize,
|
|
1353
|
+
const Box<value_type> &box,
|
|
1354
|
+
const std::vector<std::vector<value_type>> &coordinates,
|
|
1355
|
+
const int n_jobs) {
|
|
1356
|
+
unsigned int num_pixels = coordinates.size();
|
|
1357
|
+
std::vector<value_type> out(num_pixels);
|
|
1358
|
+
value_type moduleWeight = 0;
|
|
1359
|
+
{ // for Timer
|
|
1360
|
+
Debug::Timer timer("Computing module weight ...", verbose);
|
|
1361
|
+
for (auto it = start; it != end; it++) // precomputes interleaving restricted to box for all summands.
|
|
1362
|
+
it->get_interleaving(box);
|
|
1363
|
+
if (p == 0) {
|
|
1364
|
+
// #pragma omp parallel for reduction(+ : moduleWeight)
|
|
1365
|
+
for (auto it = start; it != end; it++) {
|
|
1366
|
+
moduleWeight += it->get_interleaving() > 0;
|
|
1367
|
+
}
|
|
1368
|
+
} else if (p != inf) {
|
|
1369
|
+
// #pragma omp parallel for reduction(+ : moduleWeight)
|
|
1370
|
+
for (auto it = start; it != end; it++) {
|
|
1371
|
+
// /!\ TODO deal with inf summands (for the moment, depends on the box
|
|
1372
|
+
// ...)
|
|
1373
|
+
if (it->get_interleaving() > 0 && it->get_interleaving() != inf)
|
|
1374
|
+
moduleWeight += std::pow(it->get_interleaving(), p);
|
|
1375
|
+
}
|
|
1376
|
+
} else {
|
|
1377
|
+
// #pragma omp parallel for reduction(std::max : moduleWeight)
|
|
1378
|
+
for (auto it = start; it != end; it++) {
|
|
1379
|
+
if (it->get_interleaving() > 0 && it->get_interleaving() != inf)
|
|
1380
|
+
moduleWeight = std::max(moduleWeight, it->get_interleaving());
|
|
1381
|
+
}
|
|
1382
|
+
}
|
|
1383
|
+
} // Timer death
|
|
1384
|
+
if (verbose) std::cout << "Module " << start->get_dimension() << " has weight : " << moduleWeight << "\n";
|
|
1385
|
+
if (!moduleWeight) return out;
|
|
1386
|
+
|
|
1387
|
+
if constexpr (Debug::debug)
|
|
1388
|
+
if (moduleWeight < 0) {
|
|
1389
|
+
if constexpr (Debug::debug) std::cout << "!! Negative weight !!" << std::endl;
|
|
1390
|
+
// image.clear();
|
|
1391
|
+
return {};
|
|
1392
|
+
}
|
|
1393
|
+
|
|
1394
|
+
oneapi::tbb::task_arena arena(n_jobs); // limits the number of threads
|
|
1395
|
+
arena.execute([&] {
|
|
1396
|
+
tbb::parallel_for(0u, num_pixels, [&](unsigned int i) {
|
|
1397
|
+
out[i] = _get_pixel_value(start, end, coordinates[i], delta, p, normalize, moduleWeight);
|
|
1398
|
+
});
|
|
1399
|
+
});
|
|
1400
|
+
return out;
|
|
1401
|
+
}
|
|
1402
|
+
|
|
1403
|
+
template <typename value_type>
|
|
1404
|
+
inline Module<int64_t> Module<value_type>::grid_squeeze(const std::vector<std::vector<value_type>> &grid) const {
|
|
1405
|
+
auto dimension = this->get_dimension();
|
|
1406
|
+
Module<int64_t> out(this->size());
|
|
1407
|
+
for (auto i = 0u; i < this->size(); ++i) {
|
|
1408
|
+
const auto &interval = this->operator[](i);
|
|
1409
|
+
out[i] = interval.grid_squeeze(grid);
|
|
1410
|
+
}
|
|
1411
|
+
return out;
|
|
1412
|
+
}
|
|
1413
|
+
|
|
1414
|
+
template <typename value_type>
|
|
1415
|
+
inline Summand<int64_t> Summand<value_type>::grid_squeeze(const std::vector<std::vector<value_type>> &grid) const {
|
|
1416
|
+
auto dimension = this->get_dimension();
|
|
1417
|
+
Summand<int64_t> out(
|
|
1418
|
+
compute_coordinates_in_grid(birth_corners_, grid), compute_coordinates_in_grid(death_corners_, grid), dimension_);
|
|
1419
|
+
return out;
|
|
1420
|
+
}
|
|
1421
|
+
|
|
1422
|
+
/**
|
|
1423
|
+
* dim, summand, (birth/death), num_pts, num_parameters
|
|
1424
|
+
*/
|
|
1425
|
+
template <typename value_type>
|
|
1426
|
+
inline typename Module<value_type>::idx_dump_type Module<value_type>::to_idx(
|
|
1427
|
+
const std::vector<std::vector<value_type>> &grid) const {
|
|
1428
|
+
unsigned int num_parameters = grid.size();
|
|
1429
|
+
auto dimension = this->get_dimension();
|
|
1430
|
+
idx_dump_type out(dimension + 1);
|
|
1431
|
+
for (auto i = 0u; i < this->size(); ++i) {
|
|
1432
|
+
auto &interval = this->operator[](i);
|
|
1433
|
+
auto &out_of_dim = out[interval.get_dimension()];
|
|
1434
|
+
out_of_dim.reserve(this->size());
|
|
1435
|
+
std::pair<std::vector<std::vector<int>>, std::vector<std::vector<int>>> interval_idx;
|
|
1436
|
+
|
|
1437
|
+
auto &birth_idx = interval_idx.first;
|
|
1438
|
+
birth_idx.reserve(interval.get_birth_list().size());
|
|
1439
|
+
auto &death_idx = interval_idx.second;
|
|
1440
|
+
death_idx.reserve(interval.get_death_list().size());
|
|
1441
|
+
|
|
1442
|
+
for (const auto &pt : interval.get_birth_list()) {
|
|
1443
|
+
std::vector<int> pt_idx(pt.size());
|
|
1444
|
+
for (auto i = 0u; i < num_parameters; ++i) {
|
|
1445
|
+
pt_idx[i] = std::distance(grid[i].begin(), std::lower_bound(grid[i].begin(), grid[i].end(), pt[i]));
|
|
1446
|
+
}
|
|
1447
|
+
birth_idx.push_back(pt_idx);
|
|
1448
|
+
}
|
|
1449
|
+
for (const auto &pt : interval.get_death_list()) {
|
|
1450
|
+
std::vector<int> pt_idx(pt.size());
|
|
1451
|
+
for (auto i = 0u; i < num_parameters; ++i) {
|
|
1452
|
+
pt_idx[i] = std::distance(grid[i].begin(), std::lower_bound(grid[i].begin(), grid[i].end(), pt[i]));
|
|
1453
|
+
}
|
|
1454
|
+
death_idx.push_back(pt_idx);
|
|
1455
|
+
}
|
|
1456
|
+
out_of_dim.push_back(interval_idx);
|
|
1457
|
+
}
|
|
1458
|
+
return out;
|
|
1459
|
+
}
|
|
1460
|
+
|
|
1461
|
+
template <typename value_type>
|
|
1462
|
+
std::vector<int> inline to_grid_coord(const Gudhi::multi_filtration::One_critical_filtration<value_type> &pt,
|
|
1463
|
+
const std::vector<std::vector<value_type>> &grid) {
|
|
1464
|
+
std::size_t num_parameters = grid.size();
|
|
1465
|
+
std::vector<int> out(num_parameters);
|
|
1466
|
+
if (pt.is_plus_inf() || pt.is_nan()) [[unlikely]] {
|
|
1467
|
+
for (size_t i = 0; i < num_parameters; ++i) out[i] = grid[i].size() - 1;
|
|
1468
|
+
return out;
|
|
1469
|
+
}
|
|
1470
|
+
if (pt.is_minus_inf()) [[unlikely]] {
|
|
1471
|
+
for (size_t i = 0; i < num_parameters; ++i) out[i] = 0;
|
|
1472
|
+
return out;
|
|
1473
|
+
}
|
|
1474
|
+
// pt has to be of size num_parameters now
|
|
1475
|
+
for (size_t i = 0u; i < num_parameters; ++i) {
|
|
1476
|
+
if (pt[i] >= grid[i].back()) [[unlikely]]
|
|
1477
|
+
out[i] = grid[i].size() - 1;
|
|
1478
|
+
else if (pt[i] <= grid[i][0]) [[unlikely]] {
|
|
1479
|
+
out[i] = 0;
|
|
1480
|
+
} else
|
|
1481
|
+
out[i] = std::distance(grid[i].begin(), std::lower_bound(grid[i].begin(), grid[i].end(), pt[i]));
|
|
1482
|
+
}
|
|
1483
|
+
return out;
|
|
1484
|
+
}
|
|
1485
|
+
|
|
1486
|
+
template <typename value_type>
|
|
1487
|
+
std::vector<std::vector<std::vector<int>>> inline Module<value_type>::to_flat_idx(
|
|
1488
|
+
const std::vector<std::vector<value_type>> &grid) const {
|
|
1489
|
+
std::vector<std::vector<std::vector<int>>> out(3);
|
|
1490
|
+
auto &idx = out[0];
|
|
1491
|
+
auto &births = out[1];
|
|
1492
|
+
auto &deaths = out[2];
|
|
1493
|
+
|
|
1494
|
+
idx.resize(2);
|
|
1495
|
+
idx[0].resize(this->size());
|
|
1496
|
+
idx[1].resize(this->size());
|
|
1497
|
+
|
|
1498
|
+
// some heuristic: usually
|
|
1499
|
+
births.reserve(2 * this->size());
|
|
1500
|
+
deaths.reserve(2 * this->size());
|
|
1501
|
+
for (auto i = 0u; i < this->size(); ++i) {
|
|
1502
|
+
auto &interval = this->operator[](i);
|
|
1503
|
+
idx[0][i] = interval.get_birth_list().size();
|
|
1504
|
+
for (const auto &pt : interval.get_birth_list()) {
|
|
1505
|
+
births.push_back(to_grid_coord(pt, grid));
|
|
1506
|
+
}
|
|
1507
|
+
idx[1][i] = interval.get_death_list().size();
|
|
1508
|
+
for (const auto &pt : interval.get_death_list()) {
|
|
1509
|
+
deaths.push_back(to_grid_coord(pt, grid));
|
|
1510
|
+
}
|
|
1511
|
+
}
|
|
1512
|
+
return out;
|
|
1513
|
+
}
|
|
1514
|
+
|
|
1515
|
+
template <typename value_type>
|
|
1516
|
+
std::vector<int> inline Module<value_type>::get_degree_splits() const {
|
|
1517
|
+
std::vector<int> splits = {};
|
|
1518
|
+
int current_degree = 0;
|
|
1519
|
+
for (auto i = 0u; i < this->size(); ++i) {
|
|
1520
|
+
const auto &summand = this->operator[](i);
|
|
1521
|
+
while (summand.get_dimension() > current_degree) [[unlikely]] {
|
|
1522
|
+
current_degree++;
|
|
1523
|
+
splits.push_back(i);
|
|
1524
|
+
}
|
|
1525
|
+
}
|
|
1526
|
+
return splits;
|
|
1527
|
+
}
|
|
1528
|
+
|
|
1529
|
+
template <typename value_type>
|
|
1530
|
+
inline void Module<value_type>::_compute_2D_image(Module::image_type &image,
|
|
1531
|
+
const typename module_type::iterator start,
|
|
1532
|
+
const typename module_type::iterator end,
|
|
1533
|
+
const value_type delta,
|
|
1534
|
+
const value_type p,
|
|
1535
|
+
const bool normalize,
|
|
1536
|
+
const Box<value_type> &box,
|
|
1537
|
+
const unsigned int horizontalResolution,
|
|
1538
|
+
const unsigned int verticalResolution) {
|
|
1539
|
+
image.resize(horizontalResolution, std::vector<value_type>(verticalResolution));
|
|
1540
|
+
value_type moduleWeight = 0;
|
|
1541
|
+
{ // for Timer
|
|
1542
|
+
Debug::Timer timer("Computing module weight ...", verbose);
|
|
1543
|
+
for (auto it = start; it != end; it++) // precomputes interleaving restricted to box for all summands.
|
|
1544
|
+
it->get_interleaving(box);
|
|
1545
|
+
if (p == 0) {
|
|
1546
|
+
/* #pragma omp parallel for reduction(+ : moduleWeight) */
|
|
1547
|
+
for (auto it = start; it != end; it++) {
|
|
1548
|
+
moduleWeight += it->get_interleaving() > 0;
|
|
1549
|
+
}
|
|
1550
|
+
} else if (p != inf) {
|
|
1551
|
+
/* #pragma omp parallel for reduction(+ : moduleWeight) */
|
|
1552
|
+
for (auto it = start; it != end; it++) {
|
|
1553
|
+
// /!\ TODO deal with inf summands (for the moment, depends on the box
|
|
1554
|
+
// ...)
|
|
1555
|
+
if (it->get_interleaving() > 0 && it->get_interleaving() != inf)
|
|
1556
|
+
moduleWeight += std::pow(it->get_interleaving(), p);
|
|
1557
|
+
}
|
|
1558
|
+
} else {
|
|
1559
|
+
/* #pragma omp parallel for reduction(std::max : moduleWeight) */
|
|
1560
|
+
for (auto it = start; it != end; it++) {
|
|
1561
|
+
if (it->get_interleaving() > 0 && it->get_interleaving() != inf)
|
|
1562
|
+
moduleWeight = std::max(moduleWeight, it->get_interleaving());
|
|
1563
|
+
}
|
|
1564
|
+
}
|
|
1565
|
+
} // Timer death
|
|
1566
|
+
if (verbose) std::cout << "Module " << start->get_dimension() << " has weight : " << moduleWeight << "\n";
|
|
1567
|
+
if (!moduleWeight) return;
|
|
1568
|
+
|
|
1569
|
+
if constexpr (Debug::debug)
|
|
1570
|
+
if (moduleWeight < 0) {
|
|
1571
|
+
if constexpr (Debug::debug) std::cout << "!! Negative weight !!" << std::endl;
|
|
1572
|
+
// image.clear();
|
|
1573
|
+
return;
|
|
1574
|
+
}
|
|
1575
|
+
|
|
1576
|
+
value_type stepX = (box.get_upper_corner()[0] - box.get_lower_corner()[0]) / horizontalResolution;
|
|
1577
|
+
value_type stepY = (box.get_upper_corner()[1] - box.get_lower_corner()[1]) / verticalResolution;
|
|
1578
|
+
|
|
1579
|
+
{ // for Timer
|
|
1580
|
+
Debug::Timer timer("Computing pixel values ...", verbose);
|
|
1581
|
+
|
|
1582
|
+
tbb::parallel_for(0U, horizontalResolution, [&](unsigned int i) {
|
|
1583
|
+
tbb::parallel_for(0U, verticalResolution, [&](unsigned int j) {
|
|
1584
|
+
image[i][j] = _get_pixel_value(start,
|
|
1585
|
+
end,
|
|
1586
|
+
{box.get_lower_corner()[0] + stepX * i, box.get_lower_corner()[1] + stepY * j},
|
|
1587
|
+
delta,
|
|
1588
|
+
p,
|
|
1589
|
+
normalize,
|
|
1590
|
+
moduleWeight);
|
|
1591
|
+
});
|
|
1592
|
+
});
|
|
1593
|
+
} // Timer death
|
|
1594
|
+
}
|
|
1595
|
+
|
|
1596
|
+
template <typename value_type>
|
|
1597
|
+
inline void Module<value_type>::_compute_2D_image(Module::image_type &image,
|
|
1598
|
+
const typename module_type::const_iterator start,
|
|
1599
|
+
const typename module_type::const_iterator end,
|
|
1600
|
+
unsigned int horizontalResolution,
|
|
1601
|
+
unsigned int verticalResolution,
|
|
1602
|
+
get_2dpixel_value_function_type get_pixel_value) const {
|
|
1603
|
+
image.resize(horizontalResolution, std::vector<value_type>(verticalResolution));
|
|
1604
|
+
const Box<value_type> &box = this->box_;
|
|
1605
|
+
value_type stepX = (box.get_upper_corner()[0] - box.get_lower_corner()[0]) / horizontalResolution;
|
|
1606
|
+
value_type stepY = (box.get_upper_corner()[1] - box.get_lower_corner()[1]) / verticalResolution;
|
|
1607
|
+
|
|
1608
|
+
{ // for Timer
|
|
1609
|
+
Debug::Timer timer("Computing pixel values ...", verbose);
|
|
1610
|
+
|
|
1611
|
+
// #pragma omp parallel for collapse(2)
|
|
1612
|
+
// for (unsigned int i = 0; i < horizontalResolution; i++)
|
|
1613
|
+
// {
|
|
1614
|
+
// for (unsigned int j = 0; j < verticalResolution;
|
|
1615
|
+
// j++)
|
|
1616
|
+
// {
|
|
1617
|
+
// image[i][j] = get_pixel_value(
|
|
1618
|
+
// start,
|
|
1619
|
+
// end,
|
|
1620
|
+
// box.get_lower_corner()[0] +
|
|
1621
|
+
// stepX * i,
|
|
1622
|
+
// box.get_lower_corner()[1] + stepY * j);
|
|
1623
|
+
// }
|
|
1624
|
+
// }
|
|
1625
|
+
tbb::parallel_for(0U, horizontalResolution, [&](unsigned int i) {
|
|
1626
|
+
tbb::parallel_for(0U, verticalResolution, [&](unsigned int j) {
|
|
1627
|
+
image[i][j] =
|
|
1628
|
+
get_pixel_value(start, end, box.get_lower_corner()[0] + stepX * i, box.get_lower_corner()[1] + stepY * j);
|
|
1629
|
+
});
|
|
1630
|
+
});
|
|
1631
|
+
|
|
1632
|
+
} // Timer death
|
|
1633
|
+
}
|
|
1634
|
+
|
|
1635
|
+
template <typename value_type>
|
|
1636
|
+
inline value_type Module<value_type>::_get_pixel_value(const typename module_type::iterator start,
|
|
1637
|
+
const typename module_type::iterator end,
|
|
1638
|
+
const filtration_type x,
|
|
1639
|
+
const value_type delta,
|
|
1640
|
+
const value_type p,
|
|
1641
|
+
const bool normalize,
|
|
1642
|
+
const value_type moduleWeight) const {
|
|
1643
|
+
value_type value = 0;
|
|
1644
|
+
if (p == 0) {
|
|
1645
|
+
/* #pragma omp parallel for reduction(+ : value) */
|
|
1646
|
+
for (auto it = start; it != end; it++) {
|
|
1647
|
+
value += it->get_local_weight(x, delta);
|
|
1648
|
+
}
|
|
1649
|
+
if (normalize) value /= moduleWeight;
|
|
1650
|
+
return value;
|
|
1651
|
+
}
|
|
1652
|
+
if (p != inf) {
|
|
1653
|
+
/* #pragma omp parallel for reduction(+ : value) */
|
|
1654
|
+
for (auto it = start; it != end; it++) {
|
|
1655
|
+
value_type summandWeight = it->get_interleaving();
|
|
1656
|
+
value_type summandXWeight = it->get_local_weight(x, delta);
|
|
1657
|
+
value += std::pow(summandWeight, p) * summandXWeight;
|
|
1658
|
+
}
|
|
1659
|
+
if (normalize) value /= moduleWeight;
|
|
1660
|
+
return value;
|
|
1661
|
+
}
|
|
1662
|
+
|
|
1663
|
+
/* #pragma omp parallel for reduction(std::max : value) */
|
|
1664
|
+
for (auto it = start; it != end; it++) {
|
|
1665
|
+
value = std::max(value, it->get_local_weight(x, delta));
|
|
1666
|
+
}
|
|
1667
|
+
return value;
|
|
1668
|
+
}
|
|
1669
|
+
|
|
1670
|
+
/////////////////////////////////////////////////
|
|
1671
|
+
|
|
1672
|
+
template <typename value_type>
|
|
1673
|
+
inline Summand<value_type>::Summand()
|
|
1674
|
+
: birth_corners_(1, births_type::Generator::T_inf),
|
|
1675
|
+
death_corners_(1, -births_type::Generator::T_inf),
|
|
1676
|
+
distanceTo0_(-1),
|
|
1677
|
+
dimension_(-1) {}
|
|
1678
|
+
|
|
1679
|
+
template <typename value_type>
|
|
1680
|
+
inline Summand<value_type>::Summand(
|
|
1681
|
+
const typename std::vector<typename Summand<value_type>::filtration_type> &birth_corners,
|
|
1682
|
+
const typename std::vector<typename Summand<value_type>::filtration_type> &death_corners,
|
|
1683
|
+
dimension_type dimension)
|
|
1684
|
+
: birth_corners_(birth_corners), death_corners_(death_corners), distanceTo0_(-1), dimension_(dimension) {}
|
|
1685
|
+
|
|
1686
|
+
template <typename value_type>
|
|
1687
|
+
inline bool Summand<value_type>::contains(const filtration_type &x) const {
|
|
1688
|
+
bool out = false;
|
|
1689
|
+
for (const auto &birth : this->birth_corners_) { // checks if there exists a birth smaller than x
|
|
1690
|
+
if (birth <= x) {
|
|
1691
|
+
out = true;
|
|
1692
|
+
break;
|
|
1693
|
+
}
|
|
1694
|
+
}
|
|
1695
|
+
if (!out) return false;
|
|
1696
|
+
out = false;
|
|
1697
|
+
for (const auto &death : this->death_corners_) {
|
|
1698
|
+
if (x <= death) {
|
|
1699
|
+
out = true;
|
|
1700
|
+
break;
|
|
1701
|
+
}
|
|
1702
|
+
}
|
|
1703
|
+
return out;
|
|
1704
|
+
}
|
|
1705
|
+
|
|
1706
|
+
template <typename value_type>
|
|
1707
|
+
inline Summand<value_type>::Summand(const typename Summand<value_type>::births_type &birth_corners,
|
|
1708
|
+
const typename Summand<value_type>::deaths_type &death_corners,
|
|
1709
|
+
dimension_type dimension)
|
|
1710
|
+
: birth_corners_(birth_corners), death_corners_(death_corners), distanceTo0_(-1), dimension_(dimension) {}
|
|
1711
|
+
|
|
1712
|
+
template <typename value_type>
|
|
1713
|
+
inline value_type Summand<value_type>::get_interleaving(const Box<value_type> &box) {
|
|
1714
|
+
_compute_interleaving(box);
|
|
1715
|
+
return distanceTo0_;
|
|
1716
|
+
}
|
|
1717
|
+
|
|
1718
|
+
template <typename value_type>
|
|
1719
|
+
inline value_type Summand<value_type>::get_interleaving() const {
|
|
1720
|
+
return distanceTo0_;
|
|
1721
|
+
}
|
|
1722
|
+
|
|
1723
|
+
template <typename value_type>
|
|
1724
|
+
inline value_type Summand<value_type>::get_local_weight(const filtration_type &x, const value_type delta) const {
|
|
1725
|
+
bool rectangle = delta <= 0;
|
|
1726
|
+
|
|
1727
|
+
// TODO: add assert to verify that x.size == birth.size/death.size
|
|
1728
|
+
// if they are not infinite.
|
|
1729
|
+
|
|
1730
|
+
filtration_type mini(x.num_parameters());
|
|
1731
|
+
filtration_type maxi(x.num_parameters());
|
|
1732
|
+
|
|
1733
|
+
// box on which to compute the local weight
|
|
1734
|
+
for (unsigned int i = 0; i < x.size(); i++) {
|
|
1735
|
+
mini[i] = delta <= 0 ? x[i] + delta : x[i] - delta;
|
|
1736
|
+
maxi[i] = delta <= 0 ? x[i] - delta : x[i] + delta;
|
|
1737
|
+
}
|
|
1738
|
+
|
|
1739
|
+
// Pre-allocating
|
|
1740
|
+
std::vector<filtration_type> birthList(birth_corners_.num_generators());
|
|
1741
|
+
std::vector<filtration_type> deathList(death_corners_.num_generators());
|
|
1742
|
+
unsigned int lastEntry = 0;
|
|
1743
|
+
for (const filtration_type &birth : birth_corners_) {
|
|
1744
|
+
if (birth <= maxi) {
|
|
1745
|
+
unsigned int dim = std::max(birth.num_parameters(), mini.num_parameters());
|
|
1746
|
+
filtration_type tmpBirth(dim);
|
|
1747
|
+
for (unsigned int i = 0; i < dim; i++) {
|
|
1748
|
+
auto birthi = birth.num_parameters() > i ? birth[i] : birth[0];
|
|
1749
|
+
auto minii = mini.num_parameters() > i ? mini[i] : mini[0];
|
|
1750
|
+
tmpBirth[i] = std::max(birthi, minii);
|
|
1751
|
+
}
|
|
1752
|
+
|
|
1753
|
+
birthList[lastEntry].swap(tmpBirth);
|
|
1754
|
+
lastEntry++;
|
|
1755
|
+
}
|
|
1756
|
+
}
|
|
1757
|
+
birthList.resize(lastEntry);
|
|
1758
|
+
|
|
1759
|
+
// Thresholds birthlist & deathlist to B_inf(x,delta)
|
|
1760
|
+
lastEntry = 0;
|
|
1761
|
+
for (const filtration_type &death : death_corners_) {
|
|
1762
|
+
if (death >= mini) {
|
|
1763
|
+
unsigned int dim = std::max(death.num_parameters(), maxi.num_parameters());
|
|
1764
|
+
filtration_type tmpDeath(dim);
|
|
1765
|
+
for (unsigned int i = 0; i < dim; i++) {
|
|
1766
|
+
auto deathi = death.num_parameters() > i ? death[i] : death[0];
|
|
1767
|
+
auto maxii = maxi.num_parameters() > i ? maxi[i] : maxi[0];
|
|
1768
|
+
tmpDeath[i] = std::min(deathi, maxii);
|
|
1769
|
+
}
|
|
1770
|
+
|
|
1771
|
+
deathList[lastEntry].swap(tmpDeath);
|
|
1772
|
+
lastEntry++;
|
|
1773
|
+
}
|
|
1774
|
+
}
|
|
1775
|
+
deathList.resize(lastEntry);
|
|
1776
|
+
value_type local_weight = 0;
|
|
1777
|
+
if (!rectangle) {
|
|
1778
|
+
// Local weight is inteleaving to 0 of module restricted to the square
|
|
1779
|
+
// #pragma omp parallel for reduction(std::max: local_weight)
|
|
1780
|
+
Box<value_type> trivial_box;
|
|
1781
|
+
for (const filtration_type &birth : birthList) {
|
|
1782
|
+
if (birth.num_parameters() == 0) continue;
|
|
1783
|
+
for (const filtration_type &death : deathList) {
|
|
1784
|
+
if (death.num_parameters() > 0)
|
|
1785
|
+
local_weight = std::max(local_weight,
|
|
1786
|
+
_get_max_diagonal(birth,
|
|
1787
|
+
death,
|
|
1788
|
+
trivial_box)); // if box is empty, does not thredhold
|
|
1789
|
+
// (already done before).
|
|
1790
|
+
}
|
|
1791
|
+
}
|
|
1792
|
+
return local_weight / (2 * std::abs(delta));
|
|
1793
|
+
} else {
|
|
1794
|
+
// local weight is the volume of the largest rectangle in the restricted
|
|
1795
|
+
// module #pragma omp parallel for reduction(std::max: local_weight)
|
|
1796
|
+
for (const filtration_type &birth : birthList) {
|
|
1797
|
+
if (birth.num_parameters() == 0) continue;
|
|
1798
|
+
for (const filtration_type &death : deathList) {
|
|
1799
|
+
if (death.num_parameters() > 0) local_weight = std::max(local_weight, _rectangle_volume(birth, death));
|
|
1800
|
+
}
|
|
1801
|
+
}
|
|
1802
|
+
return local_weight / std::pow(2 * std::abs(delta), x.num_parameters());
|
|
1803
|
+
}
|
|
1804
|
+
}
|
|
1805
|
+
|
|
1806
|
+
template <typename value_type>
|
|
1807
|
+
inline std::tuple<int, int> Summand<value_type>::distance_idx_to_lower(const filtration_type &x) const {
|
|
1808
|
+
value_type distance_to_lower = std::numeric_limits<value_type>::infinity();
|
|
1809
|
+
int b_idx = -1; // argmin_b max_i (b-x)_x
|
|
1810
|
+
int param = 0;
|
|
1811
|
+
auto count = 0u;
|
|
1812
|
+
for (const auto &birth : birth_corners_) {
|
|
1813
|
+
value_type temp = -std::numeric_limits<value_type>::infinity(); // max_i(birth - x)_+
|
|
1814
|
+
int temp_idx = 0;
|
|
1815
|
+
for (auto i = 0u; i < birth.size(); ++i) {
|
|
1816
|
+
auto plus = birth[i] - x[i];
|
|
1817
|
+
if (plus > temp) {
|
|
1818
|
+
temp_idx = i;
|
|
1819
|
+
temp = plus;
|
|
1820
|
+
}
|
|
1821
|
+
}
|
|
1822
|
+
if (temp < distance_to_lower) {
|
|
1823
|
+
distance_to_lower = temp;
|
|
1824
|
+
param = temp_idx;
|
|
1825
|
+
b_idx = count;
|
|
1826
|
+
}
|
|
1827
|
+
++count;
|
|
1828
|
+
}
|
|
1829
|
+
return {b_idx, param};
|
|
1830
|
+
}
|
|
1831
|
+
|
|
1832
|
+
template <typename value_type>
|
|
1833
|
+
inline std::tuple<int, int> Summand<value_type>::distance_idx_to_upper(const filtration_type &x) const {
|
|
1834
|
+
value_type distance_to_upper = std::numeric_limits<value_type>::infinity();
|
|
1835
|
+
int d_idx = -1; // argmin_d max_i (x-death)
|
|
1836
|
+
int param = 0;
|
|
1837
|
+
auto count = 0u;
|
|
1838
|
+
for (const auto &death : death_corners_) {
|
|
1839
|
+
value_type temp = -std::numeric_limits<value_type>::infinity(); // max_i(death-x)_+
|
|
1840
|
+
int temp_idx = 0;
|
|
1841
|
+
for (auto i = 0u; i < death.size(); ++i) {
|
|
1842
|
+
auto plus = x[i] - death[i];
|
|
1843
|
+
if (plus > temp) {
|
|
1844
|
+
temp_idx = i;
|
|
1845
|
+
temp = plus;
|
|
1846
|
+
}
|
|
1847
|
+
}
|
|
1848
|
+
if (temp < distance_to_upper) {
|
|
1849
|
+
distance_to_upper = temp;
|
|
1850
|
+
param = temp_idx;
|
|
1851
|
+
d_idx = count;
|
|
1852
|
+
}
|
|
1853
|
+
++count;
|
|
1854
|
+
}
|
|
1855
|
+
return {d_idx, param};
|
|
1856
|
+
}
|
|
1857
|
+
|
|
1858
|
+
template <typename value_type>
|
|
1859
|
+
inline std::vector<int> Summand<value_type>::distance_idx_to(const filtration_type &x, bool full) const {
|
|
1860
|
+
const auto &[a, b] = Summand::distance_idx_to_lower(x);
|
|
1861
|
+
const auto &[c, d] = Summand::distance_idx_to_upper(x);
|
|
1862
|
+
if (full) [[unlikely]]
|
|
1863
|
+
return {a, b, c, d};
|
|
1864
|
+
else {
|
|
1865
|
+
return {a, c};
|
|
1866
|
+
}
|
|
1867
|
+
}
|
|
1868
|
+
|
|
1869
|
+
template <typename value_type>
|
|
1870
|
+
inline value_type Summand<value_type>::distance_to_lower(const filtration_type &x, bool negative) const {
|
|
1871
|
+
value_type distance_to_lower = std::numeric_limits<value_type>::infinity();
|
|
1872
|
+
for (const auto &birth : birth_corners_) {
|
|
1873
|
+
value_type temp = negative ? -std::numeric_limits<value_type>::infinity() : 0;
|
|
1874
|
+
for (auto i = 0u; i < birth.size(); ++i) {
|
|
1875
|
+
temp = std::max(temp, birth[i] - x[i]);
|
|
1876
|
+
}
|
|
1877
|
+
distance_to_lower = std::min(distance_to_lower, temp);
|
|
1878
|
+
}
|
|
1879
|
+
return distance_to_lower;
|
|
1880
|
+
}
|
|
1881
|
+
|
|
1882
|
+
template <typename value_type>
|
|
1883
|
+
inline value_type Summand<value_type>::distance_to_upper(const filtration_type &x, bool negative) const {
|
|
1884
|
+
value_type distance_to_upper = std::numeric_limits<value_type>::infinity();
|
|
1885
|
+
for (const auto &death : death_corners_) {
|
|
1886
|
+
value_type temp = negative ? -std::numeric_limits<value_type>::infinity() : 0;
|
|
1887
|
+
for (auto i = 0u; i < death.size(); ++i) {
|
|
1888
|
+
temp = std::max(temp, x[i] - death[i]);
|
|
1889
|
+
}
|
|
1890
|
+
distance_to_upper = std::min(distance_to_upper, temp);
|
|
1891
|
+
}
|
|
1892
|
+
return distance_to_upper;
|
|
1893
|
+
}
|
|
1894
|
+
|
|
1895
|
+
template <typename value_type>
|
|
1896
|
+
inline value_type Summand<value_type>::distance_to(const filtration_type &x, bool negative) const {
|
|
1897
|
+
return std::max(Summand::distance_to_lower(x, negative), Summand::distance_to_upper(x, negative));
|
|
1898
|
+
}
|
|
1899
|
+
|
|
1900
|
+
template <typename value_type>
|
|
1901
|
+
inline std::pair<value_type, value_type> Summand<value_type>::get_bar2(const Line<value_type> &l) const {
|
|
1902
|
+
constexpr const bool verbose = false;
|
|
1903
|
+
if constexpr (verbose)
|
|
1904
|
+
std::cout << "Computing bar of this summand of dimension " << this->get_dimension() << std::endl;
|
|
1905
|
+
value_type pushed_birth = std::numeric_limits<value_type>::infinity();
|
|
1906
|
+
value_type pushed_death = -pushed_birth;
|
|
1907
|
+
for (filtration_type birth : this->get_birth_list()) {
|
|
1908
|
+
value_type pb = l.compute_forward_intersection(birth);
|
|
1909
|
+
pushed_birth = std::min(pb, pushed_birth);
|
|
1910
|
+
}
|
|
1911
|
+
//
|
|
1912
|
+
for (const filtration_type &death : this->get_death_list()) {
|
|
1913
|
+
value_type pd = l.compute_backward_intersection(death);
|
|
1914
|
+
pushed_death = std::max(pd, pushed_death);
|
|
1915
|
+
}
|
|
1916
|
+
|
|
1917
|
+
if (!(pushed_birth <= pushed_death)) {
|
|
1918
|
+
if constexpr (verbose) std::cout << "Birth <!= Death ! Ignoring this value" << std::endl;
|
|
1919
|
+
return {inf, inf};
|
|
1920
|
+
}
|
|
1921
|
+
if constexpr (verbose) {
|
|
1922
|
+
std::cout << "Final values" << pushed_birth << " ----- " << pushed_death << std::endl;
|
|
1923
|
+
}
|
|
1924
|
+
return {pushed_birth, pushed_death};
|
|
1925
|
+
}
|
|
1926
|
+
|
|
1927
|
+
template <typename value_type>
|
|
1928
|
+
inline std::pair<typename Summand<value_type>::filtration_type, typename Summand<value_type>::filtration_type>
|
|
1929
|
+
Summand<value_type>::get_bar(const Line<value_type> &l) const {
|
|
1930
|
+
constexpr const bool verbose = false;
|
|
1931
|
+
if constexpr (verbose)
|
|
1932
|
+
std::cout << "Computing bar of this summand of dimension " << this->get_dimension() << std::endl;
|
|
1933
|
+
filtration_type pushed_birth = std::numeric_limits<filtration_type>::infinity();
|
|
1934
|
+
filtration_type pushed_death = std::numeric_limits<filtration_type>::minus_infinity();
|
|
1935
|
+
for (filtration_type birth : this->get_birth_list()) {
|
|
1936
|
+
filtration_type pb = l[l.compute_forward_intersection(birth)];
|
|
1937
|
+
if constexpr (verbose)
|
|
1938
|
+
std::cout << "Updating birth " << pushed_birth << " with " << pb << " pushed at " << birth << " "
|
|
1939
|
+
<< pushed_birth.is_plus_inf();
|
|
1940
|
+
if ((pb <= pushed_birth) || pushed_birth.is_plus_inf()) {
|
|
1941
|
+
pushed_birth.swap(pb);
|
|
1942
|
+
if constexpr (verbose) std::cout << " swapped !";
|
|
1943
|
+
}
|
|
1944
|
+
if constexpr (verbose) std::cout << std::endl;
|
|
1945
|
+
}
|
|
1946
|
+
//
|
|
1947
|
+
for (const filtration_type &death : this->get_death_list()) {
|
|
1948
|
+
filtration_type pd = l[l.compute_backward_intersection(death)];
|
|
1949
|
+
if constexpr (verbose)
|
|
1950
|
+
std::cout << "Updating death " << pushed_death << " with " << pd << " pushed at " << death << " "
|
|
1951
|
+
<< pushed_death.is_minus_inf() << pushed_death[0];
|
|
1952
|
+
if ((pd >= pushed_death) || pushed_death.is_minus_inf()) {
|
|
1953
|
+
pushed_death.swap(pd);
|
|
1954
|
+
if constexpr (verbose) std::cout << " swapped !";
|
|
1955
|
+
}
|
|
1956
|
+
if constexpr (verbose) std::cout << std::endl;
|
|
1957
|
+
}
|
|
1958
|
+
|
|
1959
|
+
if (!(pushed_birth <= pushed_death)) {
|
|
1960
|
+
if constexpr (verbose) std::cout << "Birth <!= Death ! Ignoring this value" << std::endl;
|
|
1961
|
+
return {std::numeric_limits<filtration_type>::infinity(), std::numeric_limits<filtration_type>::infinity()};
|
|
1962
|
+
}
|
|
1963
|
+
if constexpr (verbose) {
|
|
1964
|
+
std::cout << "Final values" << pushed_birth << " ----- " << pushed_death << std::endl;
|
|
1965
|
+
}
|
|
1966
|
+
return {pushed_birth, pushed_death};
|
|
1967
|
+
}
|
|
1968
|
+
|
|
1969
|
+
/**
|
|
1970
|
+
* @brief Adds the bar @p bar to the indicator module @p summand if @p bar
|
|
1971
|
+
* is non-trivial (ie. not reduced to a point or, if @p threshold is true,
|
|
1972
|
+
* its thresholded version should not be reduced to a point) .
|
|
1973
|
+
*
|
|
1974
|
+
* @param bar p_bar: to add to the support of the summand
|
|
1975
|
+
* @param summand p_summand: indicator module which is being completed
|
|
1976
|
+
* @param basepoint p_basepoint: basepoint of the line of the bar
|
|
1977
|
+
* @param birth p_birth: birth container (for memory optimization purposes).
|
|
1978
|
+
* Has to be of the size @p basepoint.size()+1.
|
|
1979
|
+
* @param death p_death: death container. Same purpose as @p birth but for
|
|
1980
|
+
* deathpoint.
|
|
1981
|
+
* @param threshold p_threshold: If true, will threshold the bar with @p box.
|
|
1982
|
+
* @param box p_box: Only useful if @p threshold is set to true.
|
|
1983
|
+
*/
|
|
1984
|
+
|
|
1985
|
+
template <typename value_type>
|
|
1986
|
+
inline void Summand<value_type>::add_bar(value_type baseBirth,
|
|
1987
|
+
value_type baseDeath,
|
|
1988
|
+
const filtration_type &basepoint,
|
|
1989
|
+
filtration_type &birth,
|
|
1990
|
+
filtration_type &death,
|
|
1991
|
+
const bool threshold,
|
|
1992
|
+
const Box<value_type> &box) {
|
|
1993
|
+
// bar is trivial in that case
|
|
1994
|
+
if (baseBirth >= baseDeath) return;
|
|
1995
|
+
// #pragma omp simd
|
|
1996
|
+
// for (unsigned int j = 0; j < birth.size() - 1; j++)
|
|
1997
|
+
// {
|
|
1998
|
+
// birth[j] = basepoint[j] + baseBirth;
|
|
1999
|
+
// death[j] = basepoint[j] + baseDeath;
|
|
2000
|
+
// }
|
|
2001
|
+
// birth.back() = baseBirth;
|
|
2002
|
+
// death.back() = baseDeath;
|
|
2003
|
+
|
|
2004
|
+
/* #pragma omp simd */
|
|
2005
|
+
for (unsigned int j = 0; j < birth.size() - 1; j++) {
|
|
2006
|
+
value_type temp = basepoint[j] + baseBirth;
|
|
2007
|
+
// The box is assumed to contain all of the filtration values, if its
|
|
2008
|
+
// outside, its inf.
|
|
2009
|
+
birth[j] = temp < box.get_lower_corner()[j] ? negInf : temp;
|
|
2010
|
+
temp = basepoint[j] + baseDeath;
|
|
2011
|
+
death[j] = temp > box.get_upper_corner()[j] ? inf : temp;
|
|
2012
|
+
}
|
|
2013
|
+
birth.back() = baseBirth < box.get_lower_corner().back() ? negInf : baseBirth;
|
|
2014
|
+
death.back() = baseDeath > box.get_upper_corner().back() ? inf : baseDeath;
|
|
2015
|
+
|
|
2016
|
+
if (threshold) {
|
|
2017
|
+
// std::cout << box;
|
|
2018
|
+
threshold_down(birth, box, basepoint);
|
|
2019
|
+
threshold_up(death, box, basepoint);
|
|
2020
|
+
}
|
|
2021
|
+
_add_birth(birth);
|
|
2022
|
+
_add_death(death);
|
|
2023
|
+
}
|
|
2024
|
+
|
|
2025
|
+
template <typename value_type>
|
|
2026
|
+
inline void Summand<value_type>::add_bar(const filtration_type &birth, const filtration_type &death) {
|
|
2027
|
+
_add_birth(birth);
|
|
2028
|
+
_add_death(death);
|
|
2029
|
+
}
|
|
2030
|
+
|
|
2031
|
+
template <typename value_type>
|
|
2032
|
+
inline void Summand<value_type>::add_bar(const filtration_type &basepoint,
|
|
2033
|
+
value_type birth,
|
|
2034
|
+
value_type death,
|
|
2035
|
+
const Box<value_type> &box) {
|
|
2036
|
+
constexpr const bool verbose = false;
|
|
2037
|
+
if (birth >= death) return;
|
|
2038
|
+
if constexpr (verbose) {
|
|
2039
|
+
std::cout << "Bar : " << basepoint + birth << "--" << basepoint + death << std::endl;
|
|
2040
|
+
}
|
|
2041
|
+
auto inf = std::numeric_limits<value_type>::infinity();
|
|
2042
|
+
auto container = basepoint + birth;
|
|
2043
|
+
for (auto i = 0u; i < container.size(); i++) {
|
|
2044
|
+
if (container[i] < box.get_lower_corner()[i]) container[i] = -inf;
|
|
2045
|
+
}
|
|
2046
|
+
_add_birth(container);
|
|
2047
|
+
container = basepoint + death;
|
|
2048
|
+
for (auto i = 0u; i < container.size(); i++) {
|
|
2049
|
+
if (container[i] > box.get_upper_corner()[i]) container[i] = inf;
|
|
2050
|
+
}
|
|
2051
|
+
_add_death(container);
|
|
2052
|
+
}
|
|
2053
|
+
|
|
2054
|
+
template <typename value_type>
|
|
2055
|
+
inline const std::vector<typename Summand<value_type>::filtration_type> &Summand<value_type>::get_birth_list() const {
|
|
2056
|
+
return birth_corners_.get_underlying_container();
|
|
2057
|
+
}
|
|
2058
|
+
|
|
2059
|
+
template <typename value_type>
|
|
2060
|
+
inline const std::vector<typename Summand<value_type>::filtration_type> &Summand<value_type>::get_death_list() const {
|
|
2061
|
+
return death_corners_.get_underlying_container();
|
|
2062
|
+
}
|
|
2063
|
+
|
|
2064
|
+
template <typename value_type>
|
|
2065
|
+
const Gudhi::multi_filtration::Multi_critical_filtration<value_type> &Summand<value_type>::get_upset() const {
|
|
2066
|
+
return birth_corners_;
|
|
2067
|
+
}
|
|
2068
|
+
|
|
2069
|
+
template <typename value_type>
|
|
2070
|
+
const Gudhi::multi_filtration::Multi_critical_filtration<value_type> &Summand<value_type>::get_downset() const {
|
|
2071
|
+
return death_corners_;
|
|
2072
|
+
};
|
|
2073
|
+
|
|
2074
|
+
template <typename value_type>
|
|
2075
|
+
inline void Summand<value_type>::clean() {
|
|
2076
|
+
// birth_corners_.erase(std::remove_if(birth_corners_.begin(),
|
|
2077
|
+
// birth_corners_.end(),
|
|
2078
|
+
// [](const std::vector<value_type> &bp) {
|
|
2079
|
+
// // return std::any_of(
|
|
2080
|
+
// // bp.begin(), bp.end(),
|
|
2081
|
+
// // [](float value) { return !std::isfinite(value); });
|
|
2082
|
+
// bp.size() == 0;
|
|
2083
|
+
// }),
|
|
2084
|
+
// birth_corners_.end());
|
|
2085
|
+
// birth_corners_.simplify();
|
|
2086
|
+
// TODO : clean
|
|
2087
|
+
}
|
|
2088
|
+
|
|
2089
|
+
template <typename value_type>
|
|
2090
|
+
inline void Summand<value_type>::complete_birth(const value_type precision) {
|
|
2091
|
+
if (!birth_corners_.is_finite()) return;
|
|
2092
|
+
|
|
2093
|
+
for (std::size_t i = 0; i < birth_corners_.num_generators(); i++) {
|
|
2094
|
+
for (std::size_t j = i + 1; j < birth_corners_.num_generators(); j++) {
|
|
2095
|
+
value_type dinf = d_inf(birth_corners_[i], birth_corners_[j]);
|
|
2096
|
+
if (dinf < .99 * precision) { // for machine error ?
|
|
2097
|
+
_factorize_min(birth_corners_[i], birth_corners_[j]);
|
|
2098
|
+
birth_corners_[j] = std::remove_reference_t<decltype(birth_corners_[j])>::inf();
|
|
2099
|
+
i++;
|
|
2100
|
+
}
|
|
2101
|
+
}
|
|
2102
|
+
}
|
|
2103
|
+
birth_corners_.simplify();
|
|
2104
|
+
// _clean(birth_corners_);
|
|
2105
|
+
}
|
|
2106
|
+
|
|
2107
|
+
template <typename value_type>
|
|
2108
|
+
inline void Summand<value_type>::complete_death(const value_type precision) {
|
|
2109
|
+
if (!death_corners_.is_finite()) return;
|
|
2110
|
+
|
|
2111
|
+
for (std::size_t i = 0; i < death_corners_.num_generators(); i++) {
|
|
2112
|
+
for (std::size_t j = i + 1; j < death_corners_.num_generators(); j++) {
|
|
2113
|
+
value_type d = d_inf(death_corners_[i], death_corners_[j]);
|
|
2114
|
+
if (d < .99 * precision) {
|
|
2115
|
+
_factorize_max(death_corners_[i], death_corners_[j]);
|
|
2116
|
+
death_corners_[j] = std::remove_reference_t<decltype(death_corners_[j])>::minus_inf();
|
|
2117
|
+
i++;
|
|
2118
|
+
}
|
|
2119
|
+
}
|
|
2120
|
+
}
|
|
2121
|
+
|
|
2122
|
+
death_corners_.simplify();
|
|
2123
|
+
// _clean(death_corners_);
|
|
2124
|
+
}
|
|
2125
|
+
|
|
2126
|
+
template <typename value_type>
|
|
2127
|
+
inline dimension_type Summand<value_type>::get_dimension() const {
|
|
2128
|
+
return dimension_;
|
|
2129
|
+
}
|
|
2130
|
+
|
|
2131
|
+
template <typename value_type>
|
|
2132
|
+
inline value_type Summand<value_type>::get_landscape_value(const std::vector<value_type> &x) const {
|
|
2133
|
+
value_type out = 0;
|
|
2134
|
+
Box<value_type> trivial_box;
|
|
2135
|
+
for (const filtration_type &b : this->birth_corners_) {
|
|
2136
|
+
for (const filtration_type &d : this->death_corners_) {
|
|
2137
|
+
value_type value =
|
|
2138
|
+
std::min(this->_get_max_diagonal(b, x, trivial_box), this->_get_max_diagonal(x, d, trivial_box));
|
|
2139
|
+
out = std::max(out, value);
|
|
2140
|
+
}
|
|
2141
|
+
}
|
|
2142
|
+
return out;
|
|
2143
|
+
}
|
|
2144
|
+
|
|
2145
|
+
template <typename value_type>
|
|
2146
|
+
inline void Summand<value_type>::set_dimension(dimension_type dimension) {
|
|
2147
|
+
dimension_ = dimension;
|
|
2148
|
+
}
|
|
2149
|
+
|
|
2150
|
+
template <typename value_type>
|
|
2151
|
+
inline void Summand<value_type>::_compute_interleaving(const Box<value_type> &box) {
|
|
2152
|
+
distanceTo0_ = 0;
|
|
2153
|
+
/* #pragma omp parallel for reduction(max : distanceTo0_) */
|
|
2154
|
+
for (const std::vector<value_type> &birth : birth_corners_) {
|
|
2155
|
+
for (const std::vector<value_type> &death : death_corners_) {
|
|
2156
|
+
distanceTo0_ = std::max(distanceTo0_, _get_max_diagonal(birth, death, box));
|
|
2157
|
+
}
|
|
2158
|
+
}
|
|
2159
|
+
}
|
|
2160
|
+
|
|
2161
|
+
/**
|
|
2162
|
+
* @brief Adds @p birth to the summand's @p birth_list if it is not induced
|
|
2163
|
+
* from the @p birth_list (ie. not comparable or smaller than another birth),
|
|
2164
|
+
* and removes unnecessary birthpoints (ie. birthpoints that are induced
|
|
2165
|
+
* by @p birth).
|
|
2166
|
+
*
|
|
2167
|
+
* @param birth_list p_birth_list: birthpoint list of a summand
|
|
2168
|
+
* @param birth p_birth: birth to add to the summand
|
|
2169
|
+
*/
|
|
2170
|
+
|
|
2171
|
+
template <typename value_type>
|
|
2172
|
+
inline void Summand<value_type>::_add_birth(const filtration_type &birth) {
|
|
2173
|
+
birth_corners_.add_generator(birth);
|
|
2174
|
+
return;
|
|
2175
|
+
|
|
2176
|
+
// // TODO : DEPRECATE THIS OLD CODE
|
|
2177
|
+
// if (birth_corners_.empty()) {
|
|
2178
|
+
// birth_corners_.push_back(birth);
|
|
2179
|
+
// return;
|
|
2180
|
+
// }
|
|
2181
|
+
|
|
2182
|
+
// for (const auto ¤t_birth : birth_corners_) {
|
|
2183
|
+
// if (birth >= current_birth) {
|
|
2184
|
+
// return;
|
|
2185
|
+
// }
|
|
2186
|
+
// }
|
|
2187
|
+
// // this birth value is useful, we can now remove useless other filtrations
|
|
2188
|
+
// for (auto ¤t_birth : birth_corners_) {
|
|
2189
|
+
// if ((!current_birth.empty()) && (birth <= current_birth)) {
|
|
2190
|
+
// current_birth.clear();
|
|
2191
|
+
// }
|
|
2192
|
+
// }
|
|
2193
|
+
|
|
2194
|
+
// _clean(birth_corners_);
|
|
2195
|
+
// birth_corners_.push_back(birth);
|
|
2196
|
+
}
|
|
2197
|
+
|
|
2198
|
+
/**
|
|
2199
|
+
* @brief Adds @p death to the summand's @p death_list if it is not induced
|
|
2200
|
+
* from the @p death_list (ie. not comparable or greater than another death),
|
|
2201
|
+
* and removes unnecessary deathpoints (ie. deathpoints that are induced
|
|
2202
|
+
* by @p death)
|
|
2203
|
+
*
|
|
2204
|
+
* @param death_list p_death_list: List of deathpoints of a summand
|
|
2205
|
+
* @param death p_death: deathpoint to add to this list
|
|
2206
|
+
*/
|
|
2207
|
+
|
|
2208
|
+
template <typename value_type>
|
|
2209
|
+
inline void Summand<value_type>::_add_death(const filtration_type &death) {
|
|
2210
|
+
death_corners_.add_generator(death);
|
|
2211
|
+
return;
|
|
2212
|
+
// // TODO: Deprecate this old code
|
|
2213
|
+
// if (death_corners_.empty()) {
|
|
2214
|
+
// death_corners_.push_back(death);
|
|
2215
|
+
// return;
|
|
2216
|
+
// }
|
|
2217
|
+
|
|
2218
|
+
// for (const auto ¤t_death : death_corners_) {
|
|
2219
|
+
// if (death <= current_death) {
|
|
2220
|
+
// return;
|
|
2221
|
+
// }
|
|
2222
|
+
// }
|
|
2223
|
+
// // this death value is useful, we can now remove useless other filtrations
|
|
2224
|
+
// for (auto ¤t_death : death_corners_) {
|
|
2225
|
+
// if (!current_death.empty() && (death >= current_death)) {
|
|
2226
|
+
// current_death.clear();
|
|
2227
|
+
// }
|
|
2228
|
+
// }
|
|
2229
|
+
// _clean(death_corners_);
|
|
2230
|
+
// death_corners_.push_back(death);
|
|
2231
|
+
}
|
|
2232
|
+
|
|
2233
|
+
template <typename value_type>
|
|
2234
|
+
inline value_type Summand<value_type>::_get_max_diagonal(const filtration_type &birth,
|
|
2235
|
+
const filtration_type &death,
|
|
2236
|
+
const Box<value_type> &box) const {
|
|
2237
|
+
// assumes birth and death to be never NaN
|
|
2238
|
+
if constexpr (Debug::debug)
|
|
2239
|
+
assert(!birth.is_finite || !death.is_finite || birth.size() == death.size() && "Inputs must be of the same size !");
|
|
2240
|
+
|
|
2241
|
+
value_type s = inf;
|
|
2242
|
+
bool threshold_flag = !box.is_trivial();
|
|
2243
|
+
if (threshold_flag) {
|
|
2244
|
+
unsigned int dim = std::max(birth.size(), box.dimension());
|
|
2245
|
+
for (unsigned int i = 0; i < dim; ++i) {
|
|
2246
|
+
value_type max_i = box.get_upper_corner().size() > i ? box.get_upper_corner()[i] : inf;
|
|
2247
|
+
value_type min_i = box.get_lower_corner().size() > i ? box.get_lower_corner()[i] : negInf;
|
|
2248
|
+
value_type t_death = death.is_plus_inf() ? max_i : (death.is_minus_inf() ? -inf : std::min(death[i], max_i));
|
|
2249
|
+
value_type t_birth = birth.is_plus_inf() ? inf : (birth.is_minus_inf() ? min_i : std::max(birth[i], min_i));
|
|
2250
|
+
s = std::min(s, t_death - t_birth);
|
|
2251
|
+
}
|
|
2252
|
+
} else {
|
|
2253
|
+
unsigned int dim = std::max(birth.size(), death.size());
|
|
2254
|
+
for (unsigned int i = 0; i < dim; i++) {
|
|
2255
|
+
// if they don't have the same size, then one of them has to (+/-)infinite.
|
|
2256
|
+
value_type t_death = death.size() > i ? death[i] : death[0]; // assumes death is never empty
|
|
2257
|
+
value_type t_birth = birth.size() > i ? birth[i] : birth[0]; // assumes birth is never empty
|
|
2258
|
+
s = std::min(s, t_death - t_birth);
|
|
2259
|
+
}
|
|
2260
|
+
}
|
|
2261
|
+
|
|
2262
|
+
return s;
|
|
2263
|
+
}
|
|
2264
|
+
|
|
2265
|
+
template <typename value_type>
|
|
2266
|
+
inline value_type Summand<value_type>::_rectangle_volume(const filtration_type &a, const filtration_type &b) const {
|
|
2267
|
+
if constexpr (Debug::debug) assert(a.size() == b.size() && "Inputs must be of the same size !");
|
|
2268
|
+
value_type s = b[0] - a[0];
|
|
2269
|
+
for (unsigned int i = 1; i < a.size(); i++) {
|
|
2270
|
+
s = s * (b[i] - a[i]);
|
|
2271
|
+
}
|
|
2272
|
+
return s;
|
|
2273
|
+
}
|
|
2274
|
+
|
|
2275
|
+
template <typename value_type>
|
|
2276
|
+
inline value_type Summand<value_type>::d_inf(const filtration_type &a, const filtration_type &b) const {
|
|
2277
|
+
if (a.empty() || b.empty() || a.size() != b.size()) return inf;
|
|
2278
|
+
|
|
2279
|
+
value_type d = std::abs(a[0] - b[0]);
|
|
2280
|
+
for (unsigned int i = 1; i < a.size(); i++) d = std::max(d, std::abs(a[i] - b[i]));
|
|
2281
|
+
|
|
2282
|
+
return d;
|
|
2283
|
+
}
|
|
2284
|
+
|
|
2285
|
+
template <typename value_type>
|
|
2286
|
+
inline void Summand<value_type>::_factorize_min(filtration_type &a, const filtration_type &b) {
|
|
2287
|
+
/* if (Debug::debug && (a.empty() || b.empty())) */
|
|
2288
|
+
/* { */
|
|
2289
|
+
/* std::cout << "Empty corners ??\n"; */
|
|
2290
|
+
/* return; */
|
|
2291
|
+
/* } */
|
|
2292
|
+
|
|
2293
|
+
for (unsigned int i = 0; i < std::min(b.size(), a.size()); i++) a[i] = std::min(a[i], b[i]);
|
|
2294
|
+
}
|
|
2295
|
+
|
|
2296
|
+
template <typename value_type>
|
|
2297
|
+
inline void Summand<value_type>::_factorize_max(filtration_type &a, const filtration_type &b) {
|
|
2298
|
+
/* if (Debug::debug && (a.empty() || b.empty())) */
|
|
2299
|
+
/* { */
|
|
2300
|
+
/* std::cout << "Empty corners ??\n"; */
|
|
2301
|
+
/* return; */
|
|
2302
|
+
/* } */
|
|
2303
|
+
|
|
2304
|
+
for (unsigned int i = 0; i < std::min(b.size(), a.size()); i++) a[i] = std::max(a[i], b[i]);
|
|
2305
|
+
}
|
|
2306
|
+
|
|
2307
|
+
/**
|
|
2308
|
+
* @brief Cleans empty entries of a corner list
|
|
2309
|
+
*
|
|
2310
|
+
* @param list corner list to clean
|
|
2311
|
+
* @param keep_sort If true, will keep the order of the corners,
|
|
2312
|
+
* with a computational overhead. Defaults to false.
|
|
2313
|
+
*/
|
|
2314
|
+
// WARNING Does permute the output.
|
|
2315
|
+
|
|
2316
|
+
template <typename value_type>
|
|
2317
|
+
inline void Summand<value_type>::_clean(std::vector<filtration_type> &list, bool keep_inf) {
|
|
2318
|
+
list.erase(std::remove_if(list.begin(),
|
|
2319
|
+
list.end(),
|
|
2320
|
+
[keep_inf](filtration_type &a) {
|
|
2321
|
+
return a.empty() || ((!keep_inf) && (a.is_plus_inf() || a.is_minus_inf()));
|
|
2322
|
+
}),
|
|
2323
|
+
list.end());
|
|
2324
|
+
}
|
|
2325
|
+
|
|
2326
|
+
} // namespace mma
|
|
2327
|
+
} // namespace multiparameter
|
|
2328
|
+
} // namespace Gudhi
|
|
2329
|
+
|
|
2330
|
+
#endif // APPR
|