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 tbb::parallel_for(static_cast<Index>(0), nberColumns, [&](Index i) {
152 if (birthToCycle_[i] != nullValue) {
153 Index colIdx = _matrix()->_get_column_with_pivot(i);
154 if (colIdx == nullValue) {
155 _retrieve_cycle_from_u(i, birthToCycle_[i]);
156 } else {
157 _retrieve_cycle_from_r(colIdx, birthToCycle_[i]);
158 }
159 }
160 });
161#else
162 for (Index i = 0; i < nberColumns; ++i) {
163 if (birthToCycle_[i] != nullValue) {
164 Index colIdx = _matrix()->_get_column_with_pivot(i);
165 if (colIdx == nullValue) {
166 _retrieve_cycle_from_u(i, birthToCycle_[i]);
167 } else {
168 _retrieve_cycle_from_r(colIdx, birthToCycle_[i]);
169 }
170 }
171 }
172#endif
173}
174
175template <class Master_matrix>
177{
178 Index nullValue = Master_matrix::template get_null_value<Index>();
179
180 if (birthToCycle_.size() <= bar.birth) {
181 birthToCycle_.resize(bar.birth + 1, nullValue);
182 }
183 if (birthToCycle_[bar.birth] == nullValue) {
184 birthToCycle_[bar.birth] = representativeCycles_.size();
185 representativeCycles_.resize(representativeCycles_.size() + 1);
186 }
187
188 Index colIdx = _matrix()->_get_column_with_pivot(bar.birth);
189 if (colIdx == nullValue) {
190 _retrieve_cycle_from_u(bar.birth, birthToCycle_[bar.birth]);
191 } else {
192 _retrieve_cycle_from_r(colIdx, birthToCycle_[bar.birth]);
193 }
194}
195
196template <class Master_matrix>
197inline const std::vector<typename RU_representative_cycles<Master_matrix>::Cycle>&
199{
200 return representativeCycles_;
201}
202
203template <class Master_matrix>
206{
207 return representativeCycles_[birthToCycle_[bar.birth]];
208}
209
210template <class Master_matrix>
211inline void RU_representative_cycles<Master_matrix>::_retrieve_cycle_from_r(Index colIdx, Index repIdx)
212{
213 auto& col = _matrix()->reducedMatrixR_.get_column(colIdx);
214 representativeCycles_[repIdx] = Master_matrix::build_cycle_from_range(col.get_non_zero_content_range());
215}
216
217template <class Master_matrix>
218inline void RU_representative_cycles<Master_matrix>::_retrieve_cycle_from_u(Index colIdx, Index repIdx)
219{
220 // TODO: if rep_cycles true but not vineyards, this could be avoided by directly computing V instead of U
221 representativeCycles_[repIdx] = _get_inverse(colIdx);
222}
223
224template <class Master_matrix>
225inline typename RU_representative_cycles<Master_matrix>::Inverse_column
226RU_representative_cycles<Master_matrix>::_get_inverse(Index c)
227{
228 using E = typename Master_matrix::Element;
229 auto& matrix = _matrix()->mirrorMatrixU_;
230 auto size = matrix.get_number_of_columns();
231 [[maybe_unused]] const auto& op = _matrix()->operators_;
232 Inverse_column res;
233
234 auto _last_diagonal_value = [&]() -> E {
235 auto& col = matrix.get_column(size - 1);
236 if (col.is_empty()) return 0; // happens only if the user multiplied by 0 a column in R
237 // if column not empty, pivot has to be on the diagonal
238 if constexpr (Master_matrix::Option_list::is_z2) {
239 return 1;
240 } else {
241 return op->get_inverse(matrix.get_column(size - 1).get_pivot_value());
242 }
243 };
244
245 auto _push_cell = [&](auto i, E e) -> void {
246 if constexpr (Master_matrix::Option_list::is_z2) {
247 if (e) res.push_back(i);
248 } else {
249 if (e != op->get_additive_identity()) res.push_back({i, e});
250 }
251 };
252
253 auto _substract = [&](E& e, auto resIt, const auto& cell) -> void {
254 if (resIt != res.rend() && Master_matrix::get_row_index(*resIt) == cell.get_row_index()) {
255 if constexpr (Master_matrix::Option_list::is_z2) {
256 e = !e;
257 } else {
258 op->subtract_inplace_front(e, cell.get_element() * Master_matrix::get_element(*resIt));
259 }
260 }
261 };
262
263 auto _multiply = [&](E& e, E m) -> void {
264 if constexpr (Master_matrix::Option_list::is_z2) {
265 e = m && e; // just in case, but m is only possibly 0 if the user multiplied by 0 a column in R
266 } else {
267 op->multiply_inplace(e, op->get_inverse(m));
268 }
269 };
270
271 auto _translate = [&](std::size_t i) -> void {
272 const auto& map = _matrix()->positionToID_;
273 auto& idx = Master_matrix::get_row_index(res[i]);
274 auto it = map.find(idx);
275 if (it != map.end()) idx = it->second;
276 };
277
278 if (c == size - 1) _push_cell(size - 1, _last_diagonal_value());
279 for (int i = size - 2; i >= 0; --i) {
280 E e = static_cast<int>(c) == i;
281 auto& line = matrix.get_column(i);
282 Content_range r = line.get_non_zero_content_range();
283 auto resIt = res.rbegin();
284 auto lineIt = r.begin();
285 E diag(0);
286 if (static_cast<int>(lineIt->get_row_index()) == i) {
287 diag = lineIt->get_element();
288 ++lineIt;
289 }
290 while (lineIt != r.end() && resIt != res.rend()) {
291 while (resIt != res.rend() && Master_matrix::get_row_index(*resIt) < lineIt->get_row_index()) ++resIt;
292 _substract(e, resIt, *lineIt);
293 ++lineIt;
294 }
295 _multiply(e, diag);
296 _push_cell(i, e);
297 }
298
299 // reverse order + PosIdx to IDIdx translation
300 for (std::size_t incr = 0, decr = res.size() - 1; incr < decr; ++incr, --decr) {
301 _translate(incr);
302 _translate(decr);
303 std::swap(res[incr], res[decr]);
304 }
305
306 return res;
307}
308
309template <class Master_matrix>
310inline void RU_representative_cycles<Master_matrix>::_reset()
311{
312 representativeCycles_.clear();
313 birthToCycle_.clear();
314}
315
316} // namespace persistence_matrix
317} // namespace Gudhi
318
319#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:176
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:205
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:198
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