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