Loading...
Searching...
No Matches
ru_rep_cycles.h
Go to the documentation of this file.
1/* This file is part of the Gudhi Library - https://gudhi.inria.fr/ - which is released under MIT.
2 * See file LICENSE or go to https://gudhi.inria.fr/licensing/ for full license details.
3 * Author(s): Hannah Schreiber
4 *
5 * Copyright (C) 2022 Inria
6 *
7 * Modification(s):
8 * - YYYY/MM Author: Description of the modification
9 */
10
17
18#ifndef PM_RU_REP_CYCLES_H
19#define PM_RU_REP_CYCLES_H
20
21#include <utility> //std::move
22#include <algorithm> //std::sort
23#include <vector>
24
25#ifdef GUDHI_USE_TBB
26#include <tbb/parallel_for.h>
27#endif
28
30
31namespace Gudhi {
32namespace persistence_matrix {
33
42 friend void swap([[maybe_unused]] Dummy_ru_representative_cycles& d1,
43 [[maybe_unused]] Dummy_ru_representative_cycles& d2) noexcept
44 {}
45};
46
55template <class Master_matrix>
57{
58 public:
59 using Index = typename Master_matrix::Index;
60 using Bar = typename Master_matrix::Bar;
61 using Cycle = typename Master_matrix::Cycle;
62 using Dimension = typename Master_matrix::Dimension;
63
68
75 void update_all_representative_cycles(Dimension dim = Master_matrix::template get_null_value<Dimension>());
76
83 void update_representative_cycle(const Bar& bar);
84
91 const std::vector<Cycle>& get_all_representative_cycles() const;
100 const Cycle& get_representative_cycle(const Bar& bar) const;
101
105 friend void swap(RU_representative_cycles& base1, RU_representative_cycles& base2) noexcept
106 {
107 base1.representativeCycles_.swap(base2.representativeCycles_);
108 base1.birthToCycle_.swap(base2.birthToCycle_);
109 }
110
111 protected:
112 void _reset();
113
114 private:
115 using Master_RU_matrix = typename Master_matrix::Master_RU_matrix;
116 using Inverse_column = Cycle;
117 using Content_range = typename Master_matrix::Column::Content_range;
118
119 std::vector<Cycle> representativeCycles_;
120 std::vector<Index> birthToCycle_;
121
122 constexpr Master_RU_matrix* _matrix() { return static_cast<Master_RU_matrix*>(this); }
123 constexpr const Master_RU_matrix* _matrix() const { return static_cast<const Master_RU_matrix*>(this); }
124
125 void _retrieve_cycle_from_r(Index colIdx, Index repIdx);
126 void _retrieve_cycle_from_u(Index colIdx, Index repIdx);
127 Inverse_column _get_inverse(Index c);
128};
129
130template <class Master_matrix>
132{
133 Index nberColumns = _matrix()->reducedMatrixR_.get_number_of_columns();
134 Index nullValue = Master_matrix::template get_null_value<Index>();
135 representativeCycles_.clear();
136 birthToCycle_.clear();
137 birthToCycle_.resize(nberColumns, nullValue);
138
139 Index c = 0;
140 for (Index i = 0; i < nberColumns; i++) {
141 if ((dim == Master_matrix::template get_null_value<Dimension>() ||
142 _matrix()->reducedMatrixR_.get_column_dimension(i) == dim) &&
143 _matrix()->reducedMatrixR_.is_zero_column(i)) {
144 birthToCycle_[i] = c;
145 ++c;
146 }
147 }
148
149 representativeCycles_.resize(c);
150#ifdef GUDHI_USE_TBB
151 if (nberColumns > 0) {
152 // force row reordering before parallelization to avoid data race
153 _matrix()->reducedMatrixR_.get_column(0);
154 _matrix()->mirrorMatrixU_.get_column(0);
155 }
156 tbb::parallel_for(static_cast<Index>(0), nberColumns, [&](Index i) {
157 if (birthToCycle_[i] != nullValue) {
158 Index colIdx = _matrix()->_get_column_with_pivot(i);
159 if (colIdx == nullValue) {
160 _retrieve_cycle_from_u(i, birthToCycle_[i]);
161 } else {
162 _retrieve_cycle_from_r(colIdx, birthToCycle_[i]);
163 }
164 }
165 });
166#else
167 for (Index i = 0; i < nberColumns; ++i) {
168 if (birthToCycle_[i] != nullValue) {
169 Index colIdx = _matrix()->_get_column_with_pivot(i);
170 if (colIdx == nullValue) {
171 _retrieve_cycle_from_u(i, birthToCycle_[i]);
172 } else {
173 _retrieve_cycle_from_r(colIdx, birthToCycle_[i]);
174 }
175 }
176 }
177#endif
178}
179
180template <class Master_matrix>
182{
183 Index nullValue = Master_matrix::template get_null_value<Index>();
184
185 if (birthToCycle_.size() <= bar.birth) {
186 birthToCycle_.resize(bar.birth + 1, nullValue);
187 }
188 if (birthToCycle_[bar.birth] == nullValue) {
189 birthToCycle_[bar.birth] = representativeCycles_.size();
190 representativeCycles_.resize(representativeCycles_.size() + 1);
191 }
192
193 Index colIdx = _matrix()->_get_column_with_pivot(bar.birth);
194 if (colIdx == nullValue) {
195 _retrieve_cycle_from_u(bar.birth, birthToCycle_[bar.birth]);
196 } else {
197 _retrieve_cycle_from_r(colIdx, birthToCycle_[bar.birth]);
198 }
199}
200
201template <class Master_matrix>
202inline const std::vector<typename RU_representative_cycles<Master_matrix>::Cycle>&
204{
205 return representativeCycles_;
206}
207
208template <class Master_matrix>
211{
212 return representativeCycles_[birthToCycle_[bar.birth]];
213}
214
215template <class Master_matrix>
216inline void RU_representative_cycles<Master_matrix>::_retrieve_cycle_from_r(Index colIdx, Index repIdx)
217{
218 auto& col = _matrix()->reducedMatrixR_.get_column(colIdx);
219 representativeCycles_[repIdx] = Master_matrix::build_cycle_from_range(col.get_non_zero_content_range());
220}
221
222template <class Master_matrix>
223inline void RU_representative_cycles<Master_matrix>::_retrieve_cycle_from_u(Index colIdx, Index repIdx)
224{
225 // TODO: if rep_cycles true but not vineyards, this could be avoided by directly computing V instead of U
226 representativeCycles_[repIdx] = _get_inverse(colIdx);
227}
228
229template <class Master_matrix>
230inline typename RU_representative_cycles<Master_matrix>::Inverse_column
231RU_representative_cycles<Master_matrix>::_get_inverse(Index c)
232{
233 using E = typename Master_matrix::Element;
234 auto& matrix = _matrix()->mirrorMatrixU_;
235 auto size = matrix.get_number_of_columns();
236 [[maybe_unused]] const auto& op = _matrix()->operators_;
237 Inverse_column res;
238
239 auto _last_diagonal_value = [&]() -> E {
240 auto& col = matrix.get_column(size - 1);
241 if (col.is_empty()) return 0; // happens only if the user multiplied by 0 a column in R
242 // if column not empty, pivot has to be on the diagonal
243 if constexpr (Master_matrix::Option_list::is_z2) {
244 return 1;
245 } else {
246 return op->get_inverse(matrix.get_column(size - 1).get_pivot_value());
247 }
248 };
249
250 auto _push_cell = [&](auto i, E e) -> void {
251 if constexpr (Master_matrix::Option_list::is_z2) {
252 if (e) res.push_back(i);
253 } else {
254 if (e != op->get_additive_identity()) res.push_back({i, e});
255 }
256 };
257
258 auto _substract = [&](E& e, auto resIt, const auto& cell) -> void {
259 if (resIt != res.rend() && Master_matrix::get_row_index(*resIt) == cell.get_row_index()) {
260 if constexpr (Master_matrix::Option_list::is_z2) {
261 e = !e;
262 } else {
263 op->subtract_inplace_front(e, cell.get_element() * Master_matrix::get_element(*resIt));
264 }
265 }
266 };
267
268 auto _multiply = [&](E& e, E m) -> void {
269 if constexpr (Master_matrix::Option_list::is_z2) {
270 e = m && e; // just in case, but m is only possibly 0 if the user multiplied by 0 a column in R
271 } else {
272 op->multiply_inplace(e, op->get_inverse(m));
273 }
274 };
275
276 auto _translate = [&](std::size_t i) -> void {
277 const auto& map = _matrix()->positionToID_;
278 auto& idx = Master_matrix::get_row_index(res[i]);
279 auto it = map.find(idx);
280 if (it != map.end()) idx = it->second;
281 };
282
283 if (c == size - 1) _push_cell(size - 1, _last_diagonal_value());
284 for (int i = size - 2; i >= 0; --i) {
285 E e = static_cast<int>(c) == i;
286 auto& line = matrix.get_column(i);
287 Content_range r = line.get_non_zero_content_range();
288 auto resIt = res.rbegin();
289 auto lineIt = r.begin();
290 E diag(0);
291 if (static_cast<int>(lineIt->get_row_index()) == i) {
292 diag = lineIt->get_element();
293 ++lineIt;
294 }
295 while (lineIt != r.end() && resIt != res.rend()) {
296 while (resIt != res.rend() && Master_matrix::get_row_index(*resIt) < lineIt->get_row_index()) ++resIt;
297 _substract(e, resIt, *lineIt);
298 ++lineIt;
299 }
300 _multiply(e, diag);
301 _push_cell(i, e);
302 }
303
304 // reverse order + PosIdx to IDIdx translation
305 for (std::size_t incr = 0, decr = res.size() - 1; incr < decr; ++incr, --decr) {
306 _translate(incr);
307 _translate(decr);
308 std::swap(res[incr], res[decr]);
309 }
310
311 return res;
312}
313
314template <class Master_matrix>
315inline void RU_representative_cycles<Master_matrix>::_reset()
316{
317 representativeCycles_.clear();
318 birthToCycle_.clear();
319}
320
321} // namespace persistence_matrix
322} // namespace Gudhi
323
324#endif // PM_RU_REP_CYCLES_H
void update_representative_cycle(const Bar &bar)
Computes the current representative cycle of the given bar. All other cycles already computed are lef...
Definition ru_rep_cycles.h:181
typename Master_matrix::Index Index
Definition ru_rep_cycles.h:59
const Cycle & get_representative_cycle(const Bar &bar) const
Returns the representative cycle corresponding to the given bar. If the matrix was modified since the...
Definition ru_rep_cycles.h:210
typename Master_matrix::Bar Bar
Definition ru_rep_cycles.h:60
typename Master_matrix::Dimension Dimension
Definition ru_rep_cycles.h:62
RU_representative_cycles()=default
Default constructor.
typename Master_matrix::Cycle Cycle
Definition ru_rep_cycles.h:61
const std::vector< Cycle > & get_all_representative_cycles() const
Returns the current representative cycles. If the matrix was modified since the last call,...
Definition ru_rep_cycles.h:203
friend void swap(RU_representative_cycles &base1, RU_representative_cycles &base2) noexcept
Swap operator.
Definition ru_rep_cycles.h:105
void update_all_representative_cycles(Dimension dim=Master_matrix::template get_null_value< Dimension >())
Computes the current representative cycles of the matrix.
Definition ru_rep_cycles.h:131
Persistence matrix namespace.
Definition FieldOperators.h:18
Gudhi namespace.
Definition SimplicialComplexForAlpha.h:14
Contains the options for the matrix template.
Empty structure. Inherited instead of RU_representative_cycles, when the computation of the represent...
Definition ru_rep_cycles.h:41