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,617 @@
|
|
|
1
|
+
/* This file is part of the Gudhi Library - https://gudhi.inria.fr/ - which is released under MIT.
|
|
2
|
+
* See file LICENSE or go to https://gudhi.inria.fr/licensing/ for full license details.
|
|
3
|
+
* Author(s): Marc Glisse
|
|
4
|
+
*
|
|
5
|
+
* Copyright (C) 2023 Inria
|
|
6
|
+
*
|
|
7
|
+
* Modification(s):
|
|
8
|
+
* - YYYY/MM Author: Description of the modification
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
// ds_find_set_ is inspired from code in Boost.Graph that is
|
|
12
|
+
//
|
|
13
|
+
// (C) Copyright Jeremy Siek 2004
|
|
14
|
+
// Distributed under the Boost Software License, Version 1.0. (See
|
|
15
|
+
// accompanying file LICENSE_1_0.txt or copy at
|
|
16
|
+
// http://www.boost.org/LICENSE_1_0.txt)
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
#ifndef PERSISTENCE_ON_RECTANGLE_H
|
|
20
|
+
#define PERSISTENCE_ON_RECTANGLE_H
|
|
21
|
+
|
|
22
|
+
#include <gudhi/Debug_utils.h>
|
|
23
|
+
#ifdef GUDHI_DETAILED_TIMES
|
|
24
|
+
#include <gudhi/Clock.h>
|
|
25
|
+
#endif
|
|
26
|
+
|
|
27
|
+
#include <boost/range/adaptor/reversed.hpp>
|
|
28
|
+
|
|
29
|
+
#ifdef GUDHI_USE_TBB
|
|
30
|
+
#include <tbb/parallel_sort.h>
|
|
31
|
+
#endif
|
|
32
|
+
|
|
33
|
+
#ifdef DEBUG_TRACES
|
|
34
|
+
#include <iostream>
|
|
35
|
+
#endif
|
|
36
|
+
#include <vector>
|
|
37
|
+
#include <memory>
|
|
38
|
+
#include <algorithm>
|
|
39
|
+
#include <stdexcept>
|
|
40
|
+
#include <cstddef>
|
|
41
|
+
|
|
42
|
+
namespace Gudhi::cubical_complex {
|
|
43
|
+
|
|
44
|
+
// When building a cubical complex from top-dimensional cells, there are
|
|
45
|
+
// normally more vertices than input top cells ((x+1)*(y+1) instead of x*y).
|
|
46
|
+
// However, the top cells along the boundary turn out to be collapsible, and we
|
|
47
|
+
// only need to work with (x-1)*(y-1) vertices.
|
|
48
|
+
template <class Filtration_value, class Index = std::size_t, bool output_index = false>
|
|
49
|
+
struct Persistence_on_rectangle {
|
|
50
|
+
// If we want to save space, we don't have to store the redundant 'first'
|
|
51
|
+
// field in T_with_index. However, it would slow down the primal pass.
|
|
52
|
+
struct T_with_index {
|
|
53
|
+
Filtration_value first; Index second;
|
|
54
|
+
T_with_index() = default;
|
|
55
|
+
T_with_index(Filtration_value f, Index i) : first(f), second(i) {}
|
|
56
|
+
bool operator<(T_with_index const& other) const {
|
|
57
|
+
return std::tie(first, second) < std::tie(other.first, other.second);
|
|
58
|
+
}
|
|
59
|
+
Index out() const { return second; }
|
|
60
|
+
};
|
|
61
|
+
// Don't store the index if we don't want to output it.
|
|
62
|
+
struct T_no_index {
|
|
63
|
+
Filtration_value first;
|
|
64
|
+
T_no_index() = default;
|
|
65
|
+
T_no_index(Filtration_value f, Index) : first(f) {}
|
|
66
|
+
bool operator<(T_no_index const& other) const { return first < other.first; }
|
|
67
|
+
Filtration_value out() const { return first; }
|
|
68
|
+
};
|
|
69
|
+
typedef std::conditional_t<output_index, T_with_index, T_no_index> T;
|
|
70
|
+
|
|
71
|
+
Filtration_value const* input_p;
|
|
72
|
+
Filtration_value input(Index i) const { return input_p[i]; }
|
|
73
|
+
|
|
74
|
+
// size_* counts the number of vertices in each direction.
|
|
75
|
+
Index size_x, size_y, input_size;
|
|
76
|
+
// The square i + dy is right above i.
|
|
77
|
+
Index dy;
|
|
78
|
+
|
|
79
|
+
// Squares keep their index from the input.
|
|
80
|
+
// Vertices have the same index as the square at their bottom left (smaller x and y)
|
|
81
|
+
// Store the filtration value of vertices that could be critical. We could store them
|
|
82
|
+
// in some map, or recompute them on demand, but this strongly affects performance.
|
|
83
|
+
std::unique_ptr<T[]> data_v_;
|
|
84
|
+
T& data_vertex(Index i){ return data_v_[i]; }
|
|
85
|
+
T data_vertex(Index i) const { return data_v_[i]; }
|
|
86
|
+
|
|
87
|
+
std::conditional_t<output_index, Index, Filtration_value> global_min;
|
|
88
|
+
|
|
89
|
+
// Information on a cluster
|
|
90
|
+
// We do not use the rank/size heuristics, they do not go well with the pre-pairing and end up slowing things down.
|
|
91
|
+
// We thus use the same representative for disjoint-sets and persistence (the minimum).
|
|
92
|
+
std::unique_ptr<Index[]> ds_parent_v_;
|
|
93
|
+
std::vector<Index> ds_parent_s_;
|
|
94
|
+
Index& ds_parent_vertex(Index n) { return ds_parent_v_[n]; }
|
|
95
|
+
Index& ds_parent_square(Index n) { return ds_parent_s_[n]; }
|
|
96
|
+
|
|
97
|
+
template<class Parent>
|
|
98
|
+
Index ds_find_set_(Index v, Parent&&ds_parent) {
|
|
99
|
+
// Experimentally, path halving is currently the fastest. Note that with a
|
|
100
|
+
// different algorithm, full compression was faster, so make sure to check
|
|
101
|
+
// again if the algorithm changes.
|
|
102
|
+
// (the setting is unusual because we start from a forest with broken ranks)
|
|
103
|
+
#if 0
|
|
104
|
+
// Full compression
|
|
105
|
+
Index old = v;
|
|
106
|
+
Index ancestor = ds_parent(v);
|
|
107
|
+
while (ancestor != v)
|
|
108
|
+
{
|
|
109
|
+
v = ancestor;
|
|
110
|
+
ancestor = ds_parent(v);
|
|
111
|
+
}
|
|
112
|
+
v = ds_parent(old);
|
|
113
|
+
while (ancestor != v)
|
|
114
|
+
{
|
|
115
|
+
ds_parent(old) = ancestor;
|
|
116
|
+
old = v;
|
|
117
|
+
v = ds_parent(old);
|
|
118
|
+
}
|
|
119
|
+
return ancestor;
|
|
120
|
+
#elif 1
|
|
121
|
+
// Path halving
|
|
122
|
+
Index parent = ds_parent(v);
|
|
123
|
+
Index grandparent = ds_parent(parent);
|
|
124
|
+
while (parent != grandparent)
|
|
125
|
+
{
|
|
126
|
+
ds_parent(v) = grandparent;
|
|
127
|
+
v = grandparent;
|
|
128
|
+
parent = ds_parent(v);
|
|
129
|
+
grandparent = ds_parent(parent);
|
|
130
|
+
}
|
|
131
|
+
return parent;
|
|
132
|
+
#elif 1
|
|
133
|
+
// Path splitting
|
|
134
|
+
Index parent = ds_parent(v);
|
|
135
|
+
Index grandparent = ds_parent(parent);
|
|
136
|
+
while (parent != grandparent)
|
|
137
|
+
{
|
|
138
|
+
ds_parent(v) = grandparent;
|
|
139
|
+
v = parent;
|
|
140
|
+
parent = grandparent;
|
|
141
|
+
grandparent = ds_parent(parent);
|
|
142
|
+
}
|
|
143
|
+
return parent;
|
|
144
|
+
#elif 1
|
|
145
|
+
// No compression (just for reference)
|
|
146
|
+
Index parent;
|
|
147
|
+
while (v != (parent = ds_parent(v)))
|
|
148
|
+
v = parent;
|
|
149
|
+
return v;
|
|
150
|
+
#endif
|
|
151
|
+
}
|
|
152
|
+
Index ds_find_set_vertex(Index v) {
|
|
153
|
+
return ds_find_set_(v, [this](Index i) -> Index& { return ds_parent_vertex(i); });
|
|
154
|
+
}
|
|
155
|
+
Index ds_find_set_square(Index v) {
|
|
156
|
+
return ds_find_set_(v, [this](Index i) -> Index& { return ds_parent_square(i); });
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
struct Edge {
|
|
160
|
+
T f;
|
|
161
|
+
Index v1, v2; // v1 < v2
|
|
162
|
+
Edge() = default;
|
|
163
|
+
Edge(T f, Index v1, Index v2) : f(f), v1(v1), v2(v2) {}
|
|
164
|
+
Filtration_value filt() const { return f.first; }
|
|
165
|
+
bool operator<(Edge const& other) const { return filt() < other.filt(); }
|
|
166
|
+
};
|
|
167
|
+
void dualize_edge(Edge& e) const {
|
|
168
|
+
Index new_v2 = e.v1 + (dy + 1);
|
|
169
|
+
e.v1 = e.v2;
|
|
170
|
+
e.v2 = new_v2;
|
|
171
|
+
};
|
|
172
|
+
std::vector<Edge> edges;
|
|
173
|
+
|
|
174
|
+
void init(const Filtration_value* input_, Index n_rows, Index n_cols) {
|
|
175
|
+
input_size = n_rows * n_cols;
|
|
176
|
+
input_p = input_;
|
|
177
|
+
#ifdef DEBUG_TRACES
|
|
178
|
+
std::clog << "Input\n";
|
|
179
|
+
for(Index i = 0; i < input_size; ++i) {
|
|
180
|
+
std::clog << i << '\t' << input(i) << '\n';
|
|
181
|
+
}
|
|
182
|
+
#endif
|
|
183
|
+
dy = n_cols;
|
|
184
|
+
size_x = dy - 1;
|
|
185
|
+
size_y = n_rows - 1;
|
|
186
|
+
// The unique_ptr could be std::vector, but the initialization is useless.
|
|
187
|
+
data_v_.reset(new T[input_size - dy - 1]); // 1 row/column less for vertices than squares
|
|
188
|
+
ds_parent_v_.reset(new Index[input_size - dy - 1]);
|
|
189
|
+
// Initializing the boundary squares to 0 is important, it represents the infinite exterior cell.
|
|
190
|
+
ds_parent_s_.resize(input_size);
|
|
191
|
+
// What is a good estimate here? For a random 1000x1000 input, we get ~311k edges. For a checkerboard, ~498k.
|
|
192
|
+
edges.reserve(input_size / 2);
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
bool has_larger_input(Index a, Index b, Filtration_value fb) const {
|
|
196
|
+
// Is passing fb useful, or would the compiler notice that it already has it available?
|
|
197
|
+
GUDHI_CHECK(a != b, std::logic_error("Bug in Gudhi: comparing a cell to itself"));
|
|
198
|
+
Filtration_value fa = input(a);
|
|
199
|
+
if (fb < fa) return true;
|
|
200
|
+
if (fa < fb) return false;
|
|
201
|
+
return a > b; // Arbitrary, but has to be consistent
|
|
202
|
+
}
|
|
203
|
+
void set_parent_vertex(Index child, Index parent) {
|
|
204
|
+
GUDHI_CHECK(child != parent, std::logic_error("Bug in Gudhi: use mark_*_critical instead of set_parent"));
|
|
205
|
+
ds_parent_vertex(child) = parent;
|
|
206
|
+
}
|
|
207
|
+
void set_parent_square(Index child, Index parent) {
|
|
208
|
+
GUDHI_CHECK(child != parent, std::logic_error("Bug in Gudhi: use mark_*_critical instead of set_parent"));
|
|
209
|
+
ds_parent_square(child) = parent;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
// Locally pair simplices around each square.
|
|
213
|
+
// Work implicitly from input, only store the filtration value of critical vertices (squares are already in input).
|
|
214
|
+
// Store critical edges for later processing.
|
|
215
|
+
void fill_and_pair() {
|
|
216
|
+
Index i; // Index of the current square
|
|
217
|
+
Filtration_value f; // input(i)
|
|
218
|
+
auto mark_vertex_critical = [&](Index c) {
|
|
219
|
+
ds_parent_vertex(c) = c;
|
|
220
|
+
data_vertex(c) = T(f, i);
|
|
221
|
+
};
|
|
222
|
+
auto mark_square_critical = [&]() {
|
|
223
|
+
ds_parent_square(i) = i;
|
|
224
|
+
};
|
|
225
|
+
auto mark_edge_critical = [&](Index v1, Index v2) {
|
|
226
|
+
edges.emplace_back(T(f, i), v1, v2);
|
|
227
|
+
};
|
|
228
|
+
auto v_up_left = [&](){ return i - 1; };
|
|
229
|
+
auto v_up_right = [&](){ return i; };
|
|
230
|
+
auto v_down_left = [&](){ return i - dy - 1; };
|
|
231
|
+
auto v_down_right = [&](){ return i - dy; };
|
|
232
|
+
auto pair_square_up = [&](){ set_parent_square(i, i + dy); };
|
|
233
|
+
auto pair_square_down = [&](){ set_parent_square(i, i - dy); };
|
|
234
|
+
auto pair_square_left = [&](){ set_parent_square(i, i - 1); };
|
|
235
|
+
auto pair_square_right = [&](){ set_parent_square(i, i + 1); };
|
|
236
|
+
|
|
237
|
+
// Mark the corners as critical, it will be overwritten if not
|
|
238
|
+
i = 0; f = input(i);
|
|
239
|
+
mark_vertex_critical(v_up_right());
|
|
240
|
+
i = size_x; f = input(i);
|
|
241
|
+
mark_vertex_critical(v_up_left());
|
|
242
|
+
i = dy * size_y; f = input(i);
|
|
243
|
+
mark_vertex_critical(v_down_right());
|
|
244
|
+
i = size_x + dy * size_y; f = input(i);
|
|
245
|
+
mark_vertex_critical(v_down_left());
|
|
246
|
+
|
|
247
|
+
// Boundary nodes, 1st row
|
|
248
|
+
for(Index x = 1; x < size_x; ++x) {
|
|
249
|
+
i = x;
|
|
250
|
+
f = input(x);
|
|
251
|
+
if (has_larger_input(i + dy, i, f)) {
|
|
252
|
+
auto up_left = [&](){ return has_larger_input(i - 1, i, f) && has_larger_input(i + dy - 1, i, f); };
|
|
253
|
+
auto up_right = [&](){ return has_larger_input(i + 1, i, f) && has_larger_input(i + dy + 1, i, f); };
|
|
254
|
+
if (up_left()) {
|
|
255
|
+
set_parent_vertex(v_up_left(), v_up_right());
|
|
256
|
+
if (up_right()) mark_vertex_critical(v_up_right());
|
|
257
|
+
} else if (up_right()) {
|
|
258
|
+
set_parent_vertex(v_up_right(), v_up_left());
|
|
259
|
+
} else {
|
|
260
|
+
mark_edge_critical(v_up_left(), v_up_right());
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
// Internal rows
|
|
265
|
+
for(Index y = 1; y < size_y; ++y) {
|
|
266
|
+
// First column
|
|
267
|
+
{
|
|
268
|
+
i = y * dy;
|
|
269
|
+
f = input(i);
|
|
270
|
+
if (has_larger_input(i + 1, i, f)) {
|
|
271
|
+
auto down_right = [&](){ return has_larger_input(i - dy, i, f) && has_larger_input(i + 1 - dy, i, f); };
|
|
272
|
+
auto up_right = [&](){ return has_larger_input(i + dy, i, f) && has_larger_input(i + 1 + dy, i, f); };
|
|
273
|
+
if (down_right()) {
|
|
274
|
+
set_parent_vertex(v_down_right(), v_up_right());
|
|
275
|
+
if (up_right()) mark_vertex_critical(v_up_right());
|
|
276
|
+
} else if (up_right()) {
|
|
277
|
+
set_parent_vertex(v_up_right(), v_down_right());
|
|
278
|
+
} else {
|
|
279
|
+
mark_edge_critical(v_down_right(), v_up_right());
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
// Internal squares
|
|
284
|
+
for(Index x = 1; x < size_x; ++x) {
|
|
285
|
+
i = x + dy * y;
|
|
286
|
+
f = input(i);
|
|
287
|
+
// See what part of the boundary shares f
|
|
288
|
+
auto left = [&]() { return has_larger_input(i - 1, i, f); };
|
|
289
|
+
auto right = [&]() { return has_larger_input(i + 1, i, f); };
|
|
290
|
+
auto down = [&]() { return has_larger_input(i - dy, i, f); };
|
|
291
|
+
auto up = [&]() { return has_larger_input(i + dy, i, f); };
|
|
292
|
+
auto down_left = [&]() { return has_larger_input(i - dy - 1, i, f); };
|
|
293
|
+
auto up_left = [&]() { return has_larger_input(i + dy - 1, i, f); };
|
|
294
|
+
auto down_right = [&]() { return has_larger_input(i - dy + 1, i, f); };
|
|
295
|
+
auto up_right = [&]() { return has_larger_input(i + dy + 1, i, f); };
|
|
296
|
+
if (up()) { // u
|
|
297
|
+
if (left()) { // u l
|
|
298
|
+
if (up_left()) { // u l ul
|
|
299
|
+
set_parent_vertex(v_up_left(), v_up_right());
|
|
300
|
+
if (down()) { // U l UL d
|
|
301
|
+
if (down_left()) { // U l UL d dl
|
|
302
|
+
set_parent_vertex(v_down_left(), v_up_left());
|
|
303
|
+
if (right()) { // U L UL d DL r
|
|
304
|
+
if (down_right()) { // U L UL d DL r dr
|
|
305
|
+
set_parent_vertex(v_down_right(), v_down_left());
|
|
306
|
+
pair_square_right();
|
|
307
|
+
if (up_right()) { // U L UL D DL R DR ur - cr
|
|
308
|
+
mark_vertex_critical(v_up_right());
|
|
309
|
+
}
|
|
310
|
+
} else { // U L UL d DL r !dr
|
|
311
|
+
pair_square_down();
|
|
312
|
+
if (up_right()) { // U L UL D DL r !dr ur - cd
|
|
313
|
+
set_parent_vertex(v_up_right(), v_down_right());
|
|
314
|
+
} else { // U L UL D DL r !dr !ur - cd
|
|
315
|
+
mark_edge_critical(v_down_right(), v_up_right());
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
} else { // U L UL d DL !r
|
|
319
|
+
pair_square_down();
|
|
320
|
+
}
|
|
321
|
+
} else { // U l UL d !dl
|
|
322
|
+
pair_square_left();
|
|
323
|
+
if (right()) { // U L UL d !dl r - cl
|
|
324
|
+
if (down_right()) { // U L UL d !dl r dr - cl
|
|
325
|
+
set_parent_vertex(v_down_right(), v_down_left());
|
|
326
|
+
} else { // U L UL d !dl r !dr - cl
|
|
327
|
+
mark_edge_critical(v_down_left(), v_down_right());
|
|
328
|
+
}
|
|
329
|
+
if (up_right()) { // U L UL D !dl r ur - cl
|
|
330
|
+
set_parent_vertex(v_up_right(), v_down_right());
|
|
331
|
+
} else { // U L UL D !dl r !ur - cl
|
|
332
|
+
mark_edge_critical(v_down_right(), v_up_right());
|
|
333
|
+
}
|
|
334
|
+
} else { // U L UL d !dl !r - cl
|
|
335
|
+
mark_edge_critical(v_down_left(), v_down_right());
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
} else { // U l UL !d
|
|
339
|
+
pair_square_left();
|
|
340
|
+
if (right()) { // U L UL !d r - cl
|
|
341
|
+
if (up_right()) { // U L UL !d r ur - cl
|
|
342
|
+
set_parent_vertex(v_up_right(), v_down_right());
|
|
343
|
+
} else { // U L UL !d r !ur - cl
|
|
344
|
+
mark_edge_critical(v_down_right(), v_up_right());
|
|
345
|
+
}
|
|
346
|
+
} else {} // U L UL !d !r - cl
|
|
347
|
+
}
|
|
348
|
+
} else { // u l !ul
|
|
349
|
+
pair_square_up();
|
|
350
|
+
if (down()) { // U l !ul d - cu
|
|
351
|
+
if (down_left()) { // U l !ul d dl - cu
|
|
352
|
+
set_parent_vertex(v_down_left(), v_up_left());
|
|
353
|
+
} else { // U l !ul d !dl - cu
|
|
354
|
+
mark_edge_critical(v_down_left(), v_up_left());
|
|
355
|
+
}
|
|
356
|
+
if (right()) { // U L !ul d r - cu
|
|
357
|
+
if (down_right()) { // U L !ul d r dr - cu
|
|
358
|
+
set_parent_vertex(v_down_right(), v_down_left());
|
|
359
|
+
} else { // U L !ul d r !dr - cu
|
|
360
|
+
mark_edge_critical(v_down_left(), v_down_right());
|
|
361
|
+
}
|
|
362
|
+
if (up_right()) { // U L !ul D r ur - cu
|
|
363
|
+
set_parent_vertex(v_up_right(), v_down_right());
|
|
364
|
+
} else { // U L !ul D r !ur - cu
|
|
365
|
+
mark_edge_critical(v_down_right(), v_up_right());
|
|
366
|
+
}
|
|
367
|
+
} else { // U L !ul d !r - cu
|
|
368
|
+
mark_edge_critical(v_down_left(), v_down_right());
|
|
369
|
+
}
|
|
370
|
+
} else { // U l !ul !d - cu
|
|
371
|
+
mark_edge_critical(v_down_left(), v_up_left());
|
|
372
|
+
if (right()) { // U L !ul !d r - cu
|
|
373
|
+
if (up_right()) { // U L !ul !d r ur - cu
|
|
374
|
+
set_parent_vertex(v_up_right(), v_down_right());
|
|
375
|
+
} else { // U L !ul !d r !ur - cu
|
|
376
|
+
mark_edge_critical(v_down_right(), v_up_right());
|
|
377
|
+
}
|
|
378
|
+
} else {} // U L !ul !d !r - cu
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
} else { // u !l
|
|
382
|
+
pair_square_up();
|
|
383
|
+
if (down()) { // U !l d - cu
|
|
384
|
+
if (right()) { // U !l d r - cu
|
|
385
|
+
if (down_right()) { // U !l d r dr - cu
|
|
386
|
+
set_parent_vertex(v_down_right(), v_down_left());
|
|
387
|
+
} else { // U !l d r !dr - cu
|
|
388
|
+
mark_edge_critical(v_down_left(), v_down_right());
|
|
389
|
+
}
|
|
390
|
+
if (up_right()) { // U !l D r ur - cu
|
|
391
|
+
set_parent_vertex(v_up_right(), v_down_right());
|
|
392
|
+
} else { // U !l D r !ur - cu
|
|
393
|
+
mark_edge_critical(v_down_right(), v_up_right());
|
|
394
|
+
}
|
|
395
|
+
} else { // U !l d !r - cu
|
|
396
|
+
mark_edge_critical(v_down_left(), v_down_right());
|
|
397
|
+
}
|
|
398
|
+
} else { // U !l !d - cu
|
|
399
|
+
if (right()) { // U !l !d r - cu
|
|
400
|
+
if (up_right()) { // U !l !d r ur - cu
|
|
401
|
+
set_parent_vertex(v_up_right(), v_down_right());
|
|
402
|
+
} else { // U !l !d r !ur - cu
|
|
403
|
+
mark_edge_critical(v_down_right(), v_up_right());
|
|
404
|
+
}
|
|
405
|
+
} else {} // U !l !d !r - cu
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
} else { // !u
|
|
409
|
+
if (left()) { // !u l
|
|
410
|
+
if (down()) { // !u l d
|
|
411
|
+
if (down_left()) { // !u l d dl
|
|
412
|
+
set_parent_vertex(v_down_left(), v_up_left());
|
|
413
|
+
if (right()) { // !u L d DL r
|
|
414
|
+
if (down_right()) { // !u L d DL r dr
|
|
415
|
+
set_parent_vertex(v_down_right(), v_down_left());
|
|
416
|
+
} else { // !u L d DL r !dr
|
|
417
|
+
mark_edge_critical(v_down_left(), v_down_right());
|
|
418
|
+
}
|
|
419
|
+
pair_square_right();
|
|
420
|
+
} else { // !u L d DL !r
|
|
421
|
+
pair_square_down();
|
|
422
|
+
}
|
|
423
|
+
} else { // !u l d !dl
|
|
424
|
+
pair_square_left();
|
|
425
|
+
if (right()) { // !u L d !dl r - cl
|
|
426
|
+
if (down_right()) { // !u L d !dl r dr - cl
|
|
427
|
+
set_parent_vertex(v_down_right(), v_down_left());
|
|
428
|
+
} else { // !u L d !dl r !dr - cl
|
|
429
|
+
mark_edge_critical(v_down_left(), v_down_right());
|
|
430
|
+
}
|
|
431
|
+
mark_edge_critical(v_down_right(), v_up_right());
|
|
432
|
+
} else { // !u L d !dl !r - cl
|
|
433
|
+
mark_edge_critical(v_down_left(), v_down_right());
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
} else { // !u l !d
|
|
437
|
+
pair_square_left();
|
|
438
|
+
if (right()) { // !u L !d r - cl
|
|
439
|
+
mark_edge_critical(v_down_right(), v_up_right());
|
|
440
|
+
} else {} // !u L !d !r - cl
|
|
441
|
+
}
|
|
442
|
+
} else { // !u !l
|
|
443
|
+
if (down()) { // !u !l d
|
|
444
|
+
pair_square_down();
|
|
445
|
+
if (right()) { // !u !l D r - cd
|
|
446
|
+
if (down_right()) { // !u !l D r dr - cd
|
|
447
|
+
set_parent_vertex(v_down_right(), v_up_right());
|
|
448
|
+
} else { // !u !l D r !dr - cd
|
|
449
|
+
mark_edge_critical(v_down_right(), v_up_right());
|
|
450
|
+
}
|
|
451
|
+
} else {} // !u !l D !r - cd
|
|
452
|
+
} else { // !u !l !d
|
|
453
|
+
if (right()) { // !u !l !d r
|
|
454
|
+
pair_square_right();
|
|
455
|
+
} else { // !u !l !d !r
|
|
456
|
+
mark_square_critical();
|
|
457
|
+
}
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
}
|
|
461
|
+
}
|
|
462
|
+
// Last column
|
|
463
|
+
{
|
|
464
|
+
i = size_x + dy * y;
|
|
465
|
+
f = input(i);
|
|
466
|
+
if (has_larger_input(i - 1, i, f)) {
|
|
467
|
+
auto down_left = [&](){ return has_larger_input(i - dy, i, f) && has_larger_input(i - 1 - dy, i, f); };
|
|
468
|
+
auto up_left = [&](){ return has_larger_input(i + dy, i, f) && has_larger_input(i - 1 + dy, i, f); };
|
|
469
|
+
if (down_left()) {
|
|
470
|
+
set_parent_vertex(v_down_left(), v_up_left());
|
|
471
|
+
if (up_left()) mark_vertex_critical(v_up_left());
|
|
472
|
+
} else if (up_left()) {
|
|
473
|
+
set_parent_vertex(v_up_left(), v_down_left());
|
|
474
|
+
} else {
|
|
475
|
+
mark_edge_critical(v_down_left(), v_up_left());
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
// Boundary nodes, last row
|
|
481
|
+
for(Index x = 1; x < size_x; ++x) {
|
|
482
|
+
i = size_y * dy + x;
|
|
483
|
+
f = input(i);
|
|
484
|
+
if (has_larger_input(i - dy, i, f)) {
|
|
485
|
+
auto down_left = [&](){ return has_larger_input(i - 1, i, f) && has_larger_input(i - dy - 1, i, f); };
|
|
486
|
+
auto down_right = [&](){ return has_larger_input(i + 1, i, f) && has_larger_input(i - dy + 1, i, f); };
|
|
487
|
+
if (down_left()) {
|
|
488
|
+
set_parent_vertex(v_down_left(), v_down_right());
|
|
489
|
+
if (down_right()) mark_vertex_critical(v_down_right());
|
|
490
|
+
} else if (down_right()) {
|
|
491
|
+
set_parent_vertex(v_down_right(), v_down_left());
|
|
492
|
+
} else {
|
|
493
|
+
mark_edge_critical(v_down_left(), v_down_right());
|
|
494
|
+
}
|
|
495
|
+
}
|
|
496
|
+
}
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
void sort_edges(){
|
|
500
|
+
#ifdef GUDHI_USE_TBB
|
|
501
|
+
// Parallelizing just this part is a joke. It would be possible to
|
|
502
|
+
// parallelize the pairing (one edge list per thread) and run the dual in
|
|
503
|
+
// parallel with the primal if we were motivated...
|
|
504
|
+
tbb::parallel_sort(edges.begin(), edges.end());
|
|
505
|
+
#else
|
|
506
|
+
std::sort(edges.begin(), edges.end());
|
|
507
|
+
#endif
|
|
508
|
+
#ifdef DEBUG_TRACES
|
|
509
|
+
std::clog << "edges\n";
|
|
510
|
+
for(auto&e : edges){ std::clog << e.v1 << '\t' << e.v2 << '\t' << e.filt() << '\n'; }
|
|
511
|
+
#endif
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
template<class Out>
|
|
515
|
+
void primal(Out&&out){
|
|
516
|
+
auto it = std::remove_if(edges.begin(), edges.end(), [&](Edge& e) {
|
|
517
|
+
assert(e.v1 < e.v2);
|
|
518
|
+
Index a = ds_find_set_vertex(e.v1);
|
|
519
|
+
Index b = ds_find_set_vertex(e.v2);
|
|
520
|
+
if (a == b) return false;
|
|
521
|
+
if (data_vertex(b) < data_vertex(a)) std::swap(a, b);
|
|
522
|
+
ds_parent_vertex(b) = a;
|
|
523
|
+
out(data_vertex(b).out(), e.f.out());
|
|
524
|
+
return true;
|
|
525
|
+
});
|
|
526
|
+
edges.erase(it, edges.end());
|
|
527
|
+
global_min = data_vertex(ds_find_set_vertex(0)).out();
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
// In the dual, squares behave like vertices, and edges are rotated 90° around their middle.
|
|
531
|
+
// To handle boundaries correctly, we imagine a single exterior cell with filtration +inf.
|
|
532
|
+
template<class Out>
|
|
533
|
+
void dual(Out&&out){
|
|
534
|
+
for (auto e : boost::adaptors::reverse(edges)) {
|
|
535
|
+
dualize_edge(e);
|
|
536
|
+
Index a = ds_find_set_square(e.v1);
|
|
537
|
+
Index b = ds_find_set_square(e.v2);
|
|
538
|
+
GUDHI_CHECK(a != b, std::logic_error("Bug in Gudhi"));
|
|
539
|
+
// This is more robust in case the input contains inf? I used to set the filtration of 0 to inf.
|
|
540
|
+
if (b == 0 || (a != 0 && input(a) < input(b))) std::swap(a, b);
|
|
541
|
+
ds_parent_square(b) = a;
|
|
542
|
+
if constexpr (output_index)
|
|
543
|
+
out(e.f.out(), b);
|
|
544
|
+
else
|
|
545
|
+
out(e.f.out(), input(b));
|
|
546
|
+
}
|
|
547
|
+
}
|
|
548
|
+
};
|
|
549
|
+
// Ideas for improvement:
|
|
550
|
+
// * for large hard (many intervals) inputs, primal/dual dominate the running time because of the random reads in
|
|
551
|
+
// find_set and input(a/b). The input load would be cheaper if we stored it with parents, but then find_set would
|
|
552
|
+
// be slower.
|
|
553
|
+
// * to increase memory locality, maybe pairing, which is currently arbitrary, could use some heuristic to favor
|
|
554
|
+
// some pairs over others.
|
|
555
|
+
// * try to loosen tight dependency chains, load values several instructions before they are needed. Performing 2
|
|
556
|
+
// find_set in lock step surprisingly doesn't help.
|
|
557
|
+
// * To handle very big instances, we could remove data_v_ and recompute it on demand as the min of the inputs of i,
|
|
558
|
+
// i+1, i+dy and i+dy+1. On hard instances, it wouldn't save that much memory (and it is a bit slower). On easy
|
|
559
|
+
// instances, if we also remove the calls to reserve(), the saving is less negligible, but we still have ds_parent_*_
|
|
560
|
+
// that take about as much space as the input. We could, on a subarray, fill a dense ds_parent, then reduce it and
|
|
561
|
+
// export only the critical vertices and boundary to some sparse datastructure, but it doesn't seem worth the trouble
|
|
562
|
+
// for now.
|
|
563
|
+
|
|
564
|
+
/**
|
|
565
|
+
* @private
|
|
566
|
+
* Compute the persistence diagram of a function on a 2d cubical complex, defined as a lower-star filtration of the
|
|
567
|
+
* values at the top-dimensional cells.
|
|
568
|
+
*
|
|
569
|
+
* @tparam output_index If false, each argument of the out functors is a filtration value. If true, it is instead the
|
|
570
|
+
* index of this filtration value in the input.
|
|
571
|
+
* @tparam Filtration_value Must be comparable with `operator<`.
|
|
572
|
+
* @tparam Index This is used to index the elements of `input`, so it must be large enough to represent the size
|
|
573
|
+
* of `input`.
|
|
574
|
+
* @param[in] input Pointer to `n_rows*n_cols` filtration values for the square cells. Note that the values are assumed
|
|
575
|
+
* to be stored in C order, unlike `Gudhi::cubical_complex::Bitmap_cubical_complex` (you can exchange `n_rows` and
|
|
576
|
+
* `n_cols` for compatibility).
|
|
577
|
+
* @param[in] n_rows number of rows of `input`.
|
|
578
|
+
* @param[in] n_cols number of columns of `input`.
|
|
579
|
+
* @param[out] out0 For each interval (b, d) in the persistence diagram of dimension 0, the function calls `out0(b, d)`.
|
|
580
|
+
* @param[out] out1 Same as `out0` for persistence in dimension 1.
|
|
581
|
+
* @returns The global minimum, which is not paired and is thus the birth of an infinite persistence interval of
|
|
582
|
+
* dimension 0.
|
|
583
|
+
*/
|
|
584
|
+
template <bool output_index = false, typename Filtration_value, typename Index, typename Out0, typename Out1>
|
|
585
|
+
auto persistence_on_rectangle_from_top_cells(Filtration_value const* input, Index n_rows, Index n_cols,
|
|
586
|
+
Out0&&out0, Out1&&out1){
|
|
587
|
+
#ifdef GUDHI_DETAILED_TIMES
|
|
588
|
+
Gudhi::Clock clock;
|
|
589
|
+
#endif
|
|
590
|
+
GUDHI_CHECK(n_rows >= 2 && n_cols >= 2,
|
|
591
|
+
std::domain_error("The complex must truly be 2d, i.e. at least 2 rows and 2 columns"));
|
|
592
|
+
Persistence_on_rectangle<Filtration_value, Index, output_index> X;
|
|
593
|
+
X.init(input, n_rows, n_cols);
|
|
594
|
+
#ifdef GUDHI_DETAILED_TIMES
|
|
595
|
+
std::clog << "init: " << clock; clock.begin();
|
|
596
|
+
#endif
|
|
597
|
+
X.fill_and_pair();
|
|
598
|
+
#ifdef GUDHI_DETAILED_TIMES
|
|
599
|
+
std::clog << "fill and pair: " << clock; clock.begin();
|
|
600
|
+
#endif
|
|
601
|
+
X.sort_edges();
|
|
602
|
+
#ifdef GUDHI_DETAILED_TIMES
|
|
603
|
+
std::clog << "sort: " << clock; clock.begin();
|
|
604
|
+
#endif
|
|
605
|
+
X.primal(out0);
|
|
606
|
+
#ifdef GUDHI_DETAILED_TIMES
|
|
607
|
+
std::clog << "primal pass: " << clock; clock.begin();
|
|
608
|
+
#endif
|
|
609
|
+
X.dual(out1);
|
|
610
|
+
#ifdef GUDHI_DETAILED_TIMES
|
|
611
|
+
std::clog << "dual pass: " << clock;
|
|
612
|
+
#endif
|
|
613
|
+
return X.global_min;
|
|
614
|
+
}
|
|
615
|
+
} // namespace Gudhi::cubical_complex
|
|
616
|
+
|
|
617
|
+
#endif // PERSISTENCE_ON_RECTANGLE_H
|