Loading...
Searching...
No Matches
ru_vine_swap.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
18
19#ifndef PM_RU_VINE_SWAP_H
20#define PM_RU_VINE_SWAP_H
21
22#include <cassert>
23#include <utility> //std::move
24#include <stdexcept> //std::invalid_argument
25
27
28namespace Gudhi {
29namespace persistence_matrix {
30
38 using RUP = void;
39
40 friend void swap([[maybe_unused]] Dummy_ru_vine_swap& d1, [[maybe_unused]] Dummy_ru_vine_swap& d2) noexcept {}
41};
42
50 friend void swap([[maybe_unused]] Dummy_ru_vine_pairing& d1, [[maybe_unused]] Dummy_ru_vine_pairing& d2) noexcept {}
51};
52
60template <typename Master_matrix>
61class RU_barcode_swap : public RU_pairing<Master_matrix>
62{
63 public:
64 using Index = typename Master_matrix::Index;
65 using ID_index = typename Master_matrix::ID_index;
66 using Pos_index = typename Master_matrix::Pos_index;
67 // RUP = RU Pairing
68 using RUP = RU_pairing<Master_matrix>;
69
73 RU_barcode_swap() = default;
79 RU_barcode_swap(const RU_barcode_swap& toCopy) : RUP(static_cast<const RUP&>(toCopy)) {};
85 RU_barcode_swap(RU_barcode_swap&& other) noexcept : RUP(std::move(static_cast<RUP&>(other))) {};
86
87 ~RU_barcode_swap() = default;
88
89 RU_barcode_swap& operator=(const RU_barcode_swap& other)
90 {
91 RUP::operator=(other);
92 return *this;
93 }
94
95 RU_barcode_swap& operator=(RU_barcode_swap&& other) noexcept
96 {
97 RUP::operator=(std::move(other));
98 return *this;
99 }
100
101 friend void swap(RU_barcode_swap& swap1, RU_barcode_swap& swap2) noexcept
102 {
103 swap(static_cast<RUP&>(swap1), static_cast<RUP&>(swap2));
104 }
105
106 protected:
107 void _positive_transpose_barcode(Index columnIndex)
108 {
109 _birth(columnIndex) = columnIndex + 1;
110 _birth(columnIndex + 1) = columnIndex;
111 std::swap(RUP::indexToBar_.at(columnIndex), RUP::indexToBar_.at(columnIndex + 1));
112 }
113
114 void _negative_transpose_barcode(Index columnIndex)
115 {
116 _death(columnIndex) = columnIndex + 1;
117 _death(columnIndex + 1) = columnIndex;
118 std::swap(RUP::indexToBar_.at(columnIndex), RUP::indexToBar_.at(columnIndex + 1));
119 }
120
121 void _positive_negative_transpose_barcode(Index columnIndex)
122 {
123 _birth(columnIndex) = columnIndex + 1;
124 _death(columnIndex + 1) = columnIndex;
125 std::swap(RUP::indexToBar_.at(columnIndex), RUP::indexToBar_.at(columnIndex + 1));
126 }
127
128 void _negative_positive_transpose_barcode(Index columnIndex)
129 {
130 _death(columnIndex) = columnIndex + 1;
131 _birth(columnIndex + 1) = columnIndex;
132 std::swap(RUP::indexToBar_.at(columnIndex), RUP::indexToBar_.at(columnIndex + 1));
133 }
134
135 Pos_index _death_val(Pos_index index) const
136 {
137 if constexpr (Master_matrix::Option_list::has_removable_columns) {
138 return RUP::indexToBar_.at(index)->death;
139 } else {
140 return RUP::barcode_.at(RUP::indexToBar_.at(index)).death;
141 }
142 }
143
144 Pos_index _birth_val(Pos_index index) const
145 {
146 if constexpr (Master_matrix::Option_list::has_removable_columns) {
147 return RUP::indexToBar_.at(index)->birth;
148 } else {
149 return RUP::barcode_.at(RUP::indexToBar_.at(index)).birth;
150 }
151 }
152
153 void _reset() { RUP::_reset(); }
154
155 private:
156 Pos_index& _death(Pos_index index)
157 {
158 if constexpr (Master_matrix::Option_list::has_removable_columns) {
159 return RUP::indexToBar_.at(index)->death;
160 } else {
161 return RUP::barcode_.at(RUP::indexToBar_.at(index)).death;
162 }
163 }
164
165 Pos_index& _birth(Pos_index index)
166 {
167 if constexpr (Master_matrix::Option_list::has_removable_columns) {
168 return RUP::indexToBar_.at(index)->birth;
169 } else {
170 return RUP::barcode_.at(RUP::indexToBar_.at(index)).birth;
171 }
172 }
173};
174
183template <class Master_matrix>
185{
186 public:
187 using Index = typename Master_matrix::Index;
188 using ID_index = typename Master_matrix::ID_index;
189 using Pos_index = typename Master_matrix::Pos_index;
190
194 RU_vine_swap() = default;
195
217 bool vine_swap(Pos_index index);
218
222 friend void swap(RU_vine_swap& swap1, RU_vine_swap& swap2) noexcept {}
223
224 private:
225 using Master_RU_matrix = typename Master_matrix::Master_RU_matrix;
226
227 bool _is_paired(Index columnIndex);
228 void _swap_at_index(Index columnIndex);
229 void _add_to(Index sourceIndex, Index targetIndex);
230 void _positive_transpose(Index columnIndex);
231 void _negative_transpose(Index columnIndex);
232 void _positive_negative_transpose(Index columnIndex);
233 void _negative_positive_transpose(Index columnIndex);
234 bool _positive_vine_swap(Index columnIndex);
235 bool _negative_vine_swap(Index columnIndex);
236 bool _positive_negative_vine_swap(Index columnIndex);
237 bool _negative_positive_vine_swap(Index columnIndex);
238 Pos_index _get_death(Index simplexIndex);
239 Pos_index _get_birth(Index simplexIndex);
240 ID_index _get_row_id_from_position(Pos_index position) const;
241
242 constexpr Master_RU_matrix* _matrix() { return static_cast<Master_RU_matrix*>(this); }
243
244 constexpr const Master_RU_matrix* _matrix() const { return static_cast<const Master_RU_matrix*>(this); }
245};
246
247template <class Master_matrix>
249{
250 GUDHI_CHECK(index < _matrix()->reducedMatrixR_.get_number_of_columns() - 1,
251 std::invalid_argument("RU_vine_swap::vine_swap_with_z_eq_1_case - Index to swap out of bound."));
252
253 bool iIsPositive = _matrix()->reducedMatrixR_.is_zero_column(index);
254 bool iiIsPositive = _matrix()->reducedMatrixR_.is_zero_column(index + 1);
255
256 if (iIsPositive && iiIsPositive) {
257 _matrix()->mirrorMatrixU_.zero_entry(index, _get_row_id_from_position(index + 1));
258 return _positive_vine_swap(index);
259 }
260 if (!iIsPositive && !iiIsPositive) {
261 return _negative_vine_swap(index);
262 }
263 if (iIsPositive && !iiIsPositive) {
264 return _positive_negative_vine_swap(index);
265 }
266 return _negative_positive_vine_swap(index);
267}
268
269template <class Master_matrix>
271{
272 GUDHI_CHECK(index < _matrix()->reducedMatrixR_.get_number_of_columns() - 1,
273 std::invalid_argument("RU_vine_swap::vine_swap - Index to swap out of bound."));
274
275 bool iIsPositive = _matrix()->reducedMatrixR_.is_zero_column(index);
276 bool iiIsPositive = _matrix()->reducedMatrixR_.is_zero_column(index + 1);
277
278 if (iIsPositive && iiIsPositive) {
279 if (_matrix()->reducedMatrixR_.get_column_dimension(index) !=
280 _matrix()->reducedMatrixR_.get_column_dimension(index + 1)) {
281 _positive_transpose(index);
282 _swap_at_index(index);
283 return true;
284 }
285 if (!_matrix()->mirrorMatrixU_.is_zero_entry(index, _get_row_id_from_position(index + 1))) {
286 _matrix()->mirrorMatrixU_.zero_entry(index, _get_row_id_from_position(index + 1));
287 }
288 return _positive_vine_swap(index);
289 }
290 if (!iIsPositive && !iiIsPositive) {
291 if (_matrix()->reducedMatrixR_.get_column_dimension(index) !=
292 _matrix()->reducedMatrixR_.get_column_dimension(index + 1) ||
293 _matrix()->mirrorMatrixU_.is_zero_entry(index, _get_row_id_from_position(index + 1))) {
294 _negative_transpose(index);
295 _swap_at_index(index);
296 return true;
297 }
298 return _negative_vine_swap(index);
299 }
300 if (iIsPositive && !iiIsPositive) {
301 if (_matrix()->reducedMatrixR_.get_column_dimension(index) !=
302 _matrix()->reducedMatrixR_.get_column_dimension(index + 1) ||
303 _matrix()->mirrorMatrixU_.is_zero_entry(index, _get_row_id_from_position(index + 1))) {
304 _positive_negative_transpose(index);
305 _swap_at_index(index);
306 return true;
307 }
308 return _positive_negative_vine_swap(index);
309 }
310 if (_matrix()->reducedMatrixR_.get_column_dimension(index) !=
311 _matrix()->reducedMatrixR_.get_column_dimension(index + 1) ||
312 _matrix()->mirrorMatrixU_.is_zero_entry(index, _get_row_id_from_position(index + 1))) {
313 _negative_positive_transpose(index);
314 _swap_at_index(index);
315 return true;
316 }
317 return _negative_positive_vine_swap(index);
318}
319
320template <class Master_matrix>
321inline bool RU_vine_swap<Master_matrix>::_is_paired(Index columnIndex)
322{
323 if constexpr (Master_matrix::Option_list::has_column_pairings) {
324 return _get_death(columnIndex) != Master_matrix::template get_null_value<Pos_index>();
325 } else {
326 if (!_matrix()->reducedMatrixR_.is_zero_column(columnIndex)) return true;
327
328 if constexpr (Master_matrix::Option_list::has_map_column_container) {
329 return _matrix()->pivotToColumnIndex_.find(columnIndex) != _matrix()->pivotToColumnIndex_.end();
330 } else {
331 if (_matrix()->pivotToColumnIndex_.size() <= columnIndex) return false;
332 return _matrix()->pivotToColumnIndex_[columnIndex] != Master_matrix::template get_null_value<Index>();
333 }
334 }
335}
336
337template <class Master_matrix>
338inline void RU_vine_swap<Master_matrix>::_swap_at_index(Index columnIndex)
339{
340 _matrix()->reducedMatrixR_.swap_columns(columnIndex, columnIndex + 1);
341 _matrix()->reducedMatrixR_.swap_rows(_get_row_id_from_position(columnIndex),
342 _get_row_id_from_position(columnIndex + 1));
343 _matrix()->mirrorMatrixU_.swap_columns(columnIndex, columnIndex + 1);
344 _matrix()->mirrorMatrixU_.swap_rows(_get_row_id_from_position(columnIndex),
345 _get_row_id_from_position(columnIndex + 1));
346}
347
348template <class Master_matrix>
349inline void RU_vine_swap<Master_matrix>::_add_to(Index sourceIndex, Index targetIndex)
350{
351 _matrix()->reducedMatrixR_.add_to(sourceIndex, targetIndex);
352 _matrix()->mirrorMatrixU_.add_to(targetIndex, sourceIndex);
353}
354
355template <class Master_matrix>
356inline void RU_vine_swap<Master_matrix>::_positive_transpose(Index columnIndex)
357{
358 if constexpr (Master_matrix::Option_list::has_map_column_container) {
359 if (_is_paired(columnIndex) && _is_paired(columnIndex + 1)) {
360 std::swap(_matrix()->pivotToColumnIndex_.at(columnIndex), _matrix()->pivotToColumnIndex_.at(columnIndex + 1));
361 } else if (_is_paired(columnIndex)) {
362 _matrix()->pivotToColumnIndex_.emplace(columnIndex + 1, _matrix()->pivotToColumnIndex_.at(columnIndex));
363 _matrix()->pivotToColumnIndex_.erase(columnIndex);
364 } else if (_is_paired(columnIndex + 1)) {
365 _matrix()->pivotToColumnIndex_.emplace(columnIndex, _matrix()->pivotToColumnIndex_.at(columnIndex + 1));
366 _matrix()->pivotToColumnIndex_.erase(columnIndex + 1);
367 }
368 } else {
369 if (_is_paired(columnIndex) || _is_paired(columnIndex + 1)) {
370 if (columnIndex + 1 >= _matrix()->pivotToColumnIndex_.size()) {
371 // pivotToColumnIndex_ has at least size columnIndex + 1
372 _matrix()->pivotToColumnIndex_.push_back(Master_matrix::template get_null_value<Index>());
373 }
374 std::swap(_matrix()->pivotToColumnIndex_[columnIndex], _matrix()->pivotToColumnIndex_[columnIndex + 1]);
375 }
376 }
377
378 if constexpr (Master_matrix::Option_list::has_column_pairings) {
379 _matrix()->_positive_transpose_barcode(columnIndex);
380 }
381}
382
383template <class Master_matrix>
384inline void RU_vine_swap<Master_matrix>::_negative_transpose(Index columnIndex)
385{
386 if constexpr (Master_matrix::Option_list::has_column_pairings) {
387 _matrix()->_negative_transpose_barcode(columnIndex);
388 }
389 if constexpr (Master_matrix::Option_list::has_map_column_container) {
390 std::swap(_matrix()->pivotToColumnIndex_.at(_get_birth(columnIndex)),
391 _matrix()->pivotToColumnIndex_.at(_get_birth(columnIndex + 1)));
392 } else {
393 std::swap(_matrix()->pivotToColumnIndex_[_get_birth(columnIndex)],
394 _matrix()->pivotToColumnIndex_[_get_birth(columnIndex + 1)]);
395 }
396}
397
398template <class Master_matrix>
399inline void RU_vine_swap<Master_matrix>::_positive_negative_transpose(Index columnIndex)
400{
401 if constexpr (Master_matrix::Option_list::has_map_column_container) {
402 _matrix()->pivotToColumnIndex_.at(_get_birth(columnIndex + 1)) = columnIndex;
403 if (_is_paired(columnIndex)) {
404 _matrix()->pivotToColumnIndex_.emplace(columnIndex + 1, _matrix()->pivotToColumnIndex_.at(columnIndex));
405 _matrix()->pivotToColumnIndex_.erase(columnIndex);
406 }
407 } else {
408 _matrix()->pivotToColumnIndex_[_get_birth(columnIndex + 1)] = columnIndex;
409 if (_is_paired(columnIndex)){
410 if (columnIndex + 1 >= _matrix()->pivotToColumnIndex_.size()) {
411 // pivotToColumnIndex_ has at least size columnIndex + 1
412 _matrix()->pivotToColumnIndex_.push_back(Master_matrix::template get_null_value<Index>());
413 }
414 _matrix()->pivotToColumnIndex_[columnIndex + 1] = _matrix()->pivotToColumnIndex_[columnIndex];
415 _matrix()->pivotToColumnIndex_[columnIndex] = Master_matrix::template get_null_value<Index>();
416 }
417 }
418
419 if constexpr (Master_matrix::Option_list::has_column_pairings) {
420 _matrix()->_positive_negative_transpose_barcode(columnIndex);
421 }
422}
423
424template <class Master_matrix>
425inline void RU_vine_swap<Master_matrix>::_negative_positive_transpose(Index columnIndex)
426{
427 if constexpr (Master_matrix::Option_list::has_map_column_container) {
428 _matrix()->pivotToColumnIndex_.at(_get_birth(columnIndex)) = columnIndex + 1;
429 if (_is_paired(columnIndex + 1)) {
430 _matrix()->pivotToColumnIndex_.emplace(columnIndex, _matrix()->pivotToColumnIndex_.at(columnIndex + 1));
431 _matrix()->pivotToColumnIndex_.erase(columnIndex + 1);
432 }
433 } else {
434 _matrix()->pivotToColumnIndex_[_get_birth(columnIndex)] = columnIndex + 1;
435 if (_is_paired(columnIndex + 1)){
436 _matrix()->pivotToColumnIndex_[columnIndex] = _matrix()->pivotToColumnIndex_[columnIndex + 1];
437 _matrix()->pivotToColumnIndex_[columnIndex + 1] = Master_matrix::template get_null_value<Index>();
438 }
439 }
440
441 if constexpr (Master_matrix::Option_list::has_column_pairings) {
442 _matrix()->_negative_positive_transpose_barcode(columnIndex);
443 }
444}
445
446template <class Master_matrix>
447inline bool RU_vine_swap<Master_matrix>::_positive_vine_swap(Index columnIndex)
448{
449 const Pos_index iDeath = _get_death(columnIndex);
450 const Pos_index iiDeath = _get_death(columnIndex + 1);
451
452 if (iDeath != Master_matrix::template get_null_value<Pos_index>() &&
453 iiDeath != Master_matrix::template get_null_value<Pos_index>() &&
454 !(_matrix()->reducedMatrixR_.is_zero_entry(iiDeath, _get_row_id_from_position(columnIndex)))) {
455 if (iDeath < iiDeath) {
456 _swap_at_index(columnIndex);
457 _add_to(iDeath, iiDeath);
458 _positive_transpose(columnIndex);
459 return true;
460 }
461
462 _swap_at_index(columnIndex);
463 _add_to(iiDeath, iDeath);
464 return false;
465 }
466
467 _swap_at_index(columnIndex);
468
469 if (iDeath != Master_matrix::template get_null_value<Pos_index>() ||
470 iiDeath == Master_matrix::template get_null_value<Pos_index>() ||
471 _matrix()->reducedMatrixR_.is_zero_entry(iiDeath, _get_row_id_from_position(columnIndex + 1))) {
472 _positive_transpose(columnIndex);
473 return true;
474 }
475 return false;
476}
477
478template <class Master_matrix>
479inline bool RU_vine_swap<Master_matrix>::_negative_vine_swap(Index columnIndex)
480{
481 const Pos_index iBirth = _get_birth(columnIndex);
482 const Pos_index iiBirth = _get_birth(columnIndex + 1);
483
484 _add_to(columnIndex, columnIndex + 1);
485 _swap_at_index(columnIndex);
486
487 if (iBirth < iiBirth) {
488 _negative_transpose(columnIndex);
489 return true;
490 }
491
492 _add_to(columnIndex, columnIndex + 1);
493
494 return false;
495}
496
497template <class Master_matrix>
498inline bool RU_vine_swap<Master_matrix>::_positive_negative_vine_swap(Index columnIndex)
499{
500 _matrix()->mirrorMatrixU_.zero_entry(columnIndex, _get_row_id_from_position(columnIndex + 1));
501
502 _positive_negative_transpose(columnIndex);
503 _swap_at_index(columnIndex);
504
505 return true;
506}
507
508template <class Master_matrix>
509inline bool RU_vine_swap<Master_matrix>::_negative_positive_vine_swap(Index columnIndex)
510{
511 _add_to(columnIndex, columnIndex + 1); // useless for R?
512 _swap_at_index(columnIndex); // if additions not made for R, do not swap R columns, just rows
513 _add_to(columnIndex, columnIndex + 1); // useless for R?
514
515 return false;
516}
517
518template <class Master_matrix>
519inline typename RU_vine_swap<Master_matrix>::Pos_index RU_vine_swap<Master_matrix>::_get_death(Index simplexIndex)
520{
521 if constexpr (Master_matrix::Option_list::has_column_pairings) {
522 return _matrix()->_death_val(simplexIndex);
523 } else {
524 if (!_matrix()->reducedMatrixR_.is_zero_column(simplexIndex))
525 return _matrix()->reducedMatrixR_.get_column(simplexIndex).get_pivot();
526
527 if constexpr (Master_matrix::Option_list::has_map_column_container) {
528 auto it = _matrix()->pivotToColumnIndex_.find(simplexIndex);
529 if (it == _matrix()->pivotToColumnIndex_.end()) return Master_matrix::template get_null_value<Pos_index>();
530 return it->second;
531 } else {
532 if (simplexIndex >= _matrix()->pivotToColumnIndex_.size())
533 return Master_matrix::template get_null_value<Pos_index>();
534 return _matrix()->pivotToColumnIndex_[simplexIndex];
535 }
536 }
537}
538
539template <class Master_matrix>
540inline typename RU_vine_swap<Master_matrix>::Pos_index RU_vine_swap<Master_matrix>::_get_birth(
541 Index negativeSimplexIndex)
542{
543 if constexpr (Master_matrix::Option_list::has_column_pairings) {
544 return _matrix()->_birth_val(negativeSimplexIndex);
545 } else {
546 return _matrix()->reducedMatrixR_.get_pivot(negativeSimplexIndex);
547 }
548}
549
550template <class Master_matrix>
551inline typename RU_vine_swap<Master_matrix>::ID_index RU_vine_swap<Master_matrix>::_get_row_id_from_position(
552 Pos_index position) const
553{
554 const auto& map = _matrix()->positionToID_;
555 auto it = map.find(position);
556 return it == map.end() ? position : it->second;
557}
558
559} // namespace persistence_matrix
560} // namespace Gudhi
561
562#endif // PM_RU_VINE_SWAP_H
Class managing the barcode for RU_vine_swap.
Definition ru_vine_swap.h:62
RU_barcode_swap()=default
Default constructor.
typename Master_matrix::Index Index
Definition ru_vine_swap.h:64
RU_barcode_swap(const RU_barcode_swap &toCopy)
Copy constructor.
Definition ru_vine_swap.h:79
typename Master_matrix::Pos_index Pos_index
Definition ru_vine_swap.h:66
typename Master_matrix::ID_index ID_index
Definition ru_vine_swap.h:65
RU_barcode_swap(RU_barcode_swap &&other) noexcept
Move constructor.
Definition ru_vine_swap.h:85
RU_pairing()=default
Default constructor.
RU_vine_swap()=default
Default constructor.
typename Master_matrix::ID_index ID_index
Definition ru_vine_swap.h:188
friend void swap(RU_vine_swap &swap1, RU_vine_swap &swap2) noexcept
Swap operator.
Definition ru_vine_swap.h:222
typename Master_matrix::Index Index
Definition ru_vine_swap.h:187
bool vine_swap_with_z_eq_1_case(Pos_index index)
Does the same than vine_swap, but assumes that the swap is non trivial and therefore skips a part of ...
Definition ru_vine_swap.h:248
typename Master_matrix::Pos_index Pos_index
Definition ru_vine_swap.h:189
bool vine_swap(Pos_index index)
Does a vine swap between two cells which are consecutive in the filtration. Roughly,...
Definition ru_vine_swap.h:270
Persistence matrix namespace.
Definition FieldOperators.h:18
Gudhi namespace.
Definition SimplicialComplexForAlpha.h:14
Contains the Gudhi::persistence_matrix::RU_pairing class and Gudhi::persistence_matrix::Dummy_ru_pair...
Empty structure. Inherited instead of RU_pairing, when the barcode is not stored.
Definition ru_vine_swap.h:49
Empty structure. Inherited instead of RU_vine_swap, when vine swaps are not enabled.
Definition ru_vine_swap.h:37