Loading...
Searching...
No Matches
chain_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
19
20#ifndef PM_CHAIN_VINE_SWAP_H
21#define PM_CHAIN_VINE_SWAP_H
22
23#include <cassert>
24#include <utility> //std::swap & std::move
25#include <functional> //std::function
26#include <stdexcept> //std::invalid_argument
27
29
30namespace Gudhi {
31namespace persistence_matrix {
32
43constexpr bool _no_G_death_comparator([[maybe_unused]] unsigned int columnIndex1,
44 [[maybe_unused]] unsigned int columnIndex2)
45{
46 return false;
47}
48
55struct Dummy_chain_vine_swap {
56 using CP = void;
57
58 friend void swap([[maybe_unused]] Dummy_chain_vine_swap& d1, [[maybe_unused]] Dummy_chain_vine_swap& d2) noexcept {}
59
60 Dummy_chain_vine_swap() = default;
61
62 template <typename BirthComparatorFunction, typename DeathComparatorFunction>
63 Dummy_chain_vine_swap([[maybe_unused]] const BirthComparatorFunction& birthComparator,
64 [[maybe_unused]] const DeathComparatorFunction& deathComparator)
65 {}
66};
67
75 friend void swap([[maybe_unused]] Dummy_chain_vine_pairing& d1,
76 [[maybe_unused]] Dummy_chain_vine_pairing& d2) noexcept
77 {}
78};
79
87template <typename Master_matrix>
88class Chain_barcode_swap : public Chain_pairing<Master_matrix>
89{
90 public:
91 using ID_index = typename Master_matrix::ID_index;
92 using Pos_index = typename Master_matrix::Pos_index;
93 // CP = Chain Pairing
95
99 Chain_barcode_swap() = default;
105 Chain_barcode_swap(const Chain_barcode_swap& toCopy) : CP(static_cast<const CP&>(toCopy)) {};
111 Chain_barcode_swap(Chain_barcode_swap&& other) noexcept : CP(std::move(static_cast<CP&>(other))) {};
112
113 ~Chain_barcode_swap() = default;
114
115 Chain_barcode_swap& operator=(Chain_barcode_swap other)
116 {
117 CP::operator=(other);
118 return *this;
119 }
120
121 Chain_barcode_swap& operator=(Chain_barcode_swap&& other) noexcept
122 {
123 CP::operator=(std::move(other));
124 return *this;
125 }
126
127 friend void swap(Chain_barcode_swap& swap1, Chain_barcode_swap& swap2) noexcept
128 {
129 swap(static_cast<CP&>(swap1), static_cast<CP&>(swap2));
130 }
131
132 protected:
133 bool _is_negative_in_bar(ID_index pivot) const
134 {
135 Pos_index pos = _get_pivot_position(pivot);
136 return _death_val(pivot) == pos;
137 }
138
139 void _positive_transpose_barcode(ID_index pivot1, ID_index pivot2)
140 {
141 Pos_index pos1 = _get_pivot_position(pivot1);
142 Pos_index pos2 = _get_pivot_position(pivot2);
143
144 _birth(pos1) = pos2;
145 _birth(pos2) = pos1;
146 std::swap(CP::indexToBar_.at(pos1), CP::indexToBar_.at(pos2));
147 }
148
149 void _negative_transpose_barcode(ID_index pivot1, ID_index pivot2)
150 {
151 Pos_index pos1 = _get_pivot_position(pivot1);
152 Pos_index pos2 = _get_pivot_position(pivot2);
153
154 _death(pos1) = pos2;
155 _death(pos2) = pos1;
156 std::swap(CP::indexToBar_.at(pos1), CP::indexToBar_.at(pos2));
157 }
158
159 void _positive_negative_transpose_barcode(ID_index pivot1, ID_index pivot2)
160 {
161 Pos_index pos1 = _get_pivot_position(pivot1);
162 Pos_index pos2 = _get_pivot_position(pivot2);
163
164 _birth(pos1) = pos2;
165 _death(pos2) = pos1;
166 std::swap(CP::indexToBar_.at(pos1), CP::indexToBar_.at(pos2));
167 }
168
169 void _negative_positive_transpose_barcode(ID_index pivot1, ID_index pivot2)
170 {
171 Pos_index pos1 = _get_pivot_position(pivot1);
172 Pos_index pos2 = _get_pivot_position(pivot2);
173
174 _death(pos1) = pos2;
175 _birth(pos2) = pos1;
176 std::swap(CP::indexToBar_.at(pos1), CP::indexToBar_.at(pos2));
177 }
178
179 bool _are_adjacent(ID_index pivot1, ID_index pivot2) const
180 {
181 Pos_index pos1 = _get_pivot_position(pivot1);
182 Pos_index pos2 = _get_pivot_position(pivot2);
183 return pos1 < pos2 ? (pos2 - pos1) == 1 : (pos1 - pos2) == 1;
184 }
185
186 Pos_index _death_val(ID_index pivot) const { return CP::_death(_get_pivot_position(pivot)); }
187
188 Pos_index _birth_val(ID_index pivot) const { return CP::_birth(_get_pivot_position(pivot)); }
189
190 void _reset() { CP::_reset(); }
191
192 private:
193 using Master_chain_matrix = typename Master_matrix::Master_chain_matrix;
194
195 Pos_index _get_pivot_position(ID_index pivot) const
196 {
197 const auto& map = static_cast<const Master_chain_matrix*>(this)->map_;
198 if constexpr (Master_matrix::Option_list::has_map_column_container) {
199 // TODO: quite often called, make public and pass position instead of pivot to avoid find() every time?
200 return map.at(pivot);
201 } else {
202 return map[pivot];
203 }
204 }
205
206 Pos_index& _death(Pos_index index)
207 {
208 if constexpr (Master_matrix::Option_list::has_removable_columns) {
209 return CP::indexToBar_.at(index)->death;
210 } else {
211 return CP::barcode_.at(CP::indexToBar_.at(index)).death;
212 }
213 }
214
215 Pos_index& _birth(Pos_index index)
216 {
217 if constexpr (Master_matrix::Option_list::has_removable_columns) {
218 return CP::indexToBar_.at(index)->birth;
219 } else {
220 return CP::barcode_.at(CP::indexToBar_.at(index)).birth;
221 }
222 }
223};
224
233template <class Master_matrix>
235{
236 public:
237 using Index = typename Master_matrix::Index;
238 using ID_index = typename Master_matrix::ID_index;
239 using Pos_index = typename Master_matrix::Pos_index;
240 using Column_container = typename Master_matrix::Column_container;
241 using Column = typename Master_matrix::Column;
243
260 Chain_vine_swap(std::function<bool(Pos_index, Pos_index)> birthComparator,
261 std::function<bool(Pos_index, Pos_index)> deathComparator = _no_G_death_comparator);
262
273 Index vine_swap_with_z_eq_1_case(Index columnIndex1, Index columnIndex2);
289 Index vine_swap(Index columnIndex1, Index columnIndex2);
290
294 friend void swap(Chain_vine_swap& swap1, Chain_vine_swap& swap2) noexcept
295 {
296 std::swap(swap1.birthComp_, swap2.birthComp_);
297 std::swap(swap1.deathComp_, swap2.deathComp_);
298 }
299
300 private:
301 using Master_chain_matrix = typename Master_matrix::Master_chain_matrix;
302
303 std::function<bool(Pos_index, Pos_index)> birthComp_;
304 std::function<bool(Pos_index, Pos_index)> deathComp_;
305
306 bool _is_negative_in_pair(Index columnIndex);
307 Index _positive_vine_swap(Index columnIndex1, Index columnIndex2);
308 Index _positive_negative_vine_swap(Index columnIndex1, Index columnIndex2);
309 Index _negative_positive_vine_swap(Index columnIndex1, Index columnIndex2);
310 Index _negative_vine_swap(Index columnIndex1, Index columnIndex2);
311 void _swap_positions(ID_index pivot1, ID_index pivot2);
312
313 constexpr Master_chain_matrix* _matrix() { return static_cast<Master_chain_matrix*>(this); }
314
315 constexpr const Master_chain_matrix* _matrix() const { return static_cast<const Master_chain_matrix*>(this); }
316};
317
318template <class Master_matrix>
319inline Chain_vine_swap<Master_matrix>::Chain_vine_swap() : birthComp_(), deathComp_()
320{
321 static_assert(Master_matrix::Option_list::has_column_pairings,
322 "If barcode is not stored, at least a birth comparator has to be specified.");
323}
324
325template <class Master_matrix>
326inline Chain_vine_swap<Master_matrix>::Chain_vine_swap(std::function<bool(Pos_index, Pos_index)> birthComparator,
327 std::function<bool(Pos_index, Pos_index)> deathComparator)
328 : birthComp_(std::move(birthComparator)), deathComp_(std::move(deathComparator))
329{}
330
331template <class Master_matrix>
333 Index columnIndex1,
334 Index columnIndex2)
335{
336 const bool col1IsNeg = _is_negative_in_pair(columnIndex1);
337 const bool col2IsNeg = _is_negative_in_pair(columnIndex2);
338
339 if (col1IsNeg && col2IsNeg) return _negative_vine_swap(columnIndex1, columnIndex2);
340
341 if (col1IsNeg) return _negative_positive_vine_swap(columnIndex1, columnIndex2);
342
343 if (col2IsNeg) return _positive_negative_vine_swap(columnIndex1, columnIndex2);
344
345 return _positive_vine_swap(columnIndex1, columnIndex2);
346}
347
348template <class Master_matrix>
350 Index columnIndex2)
351{
352 if constexpr (Master_matrix::Option_list::has_column_pairings) {
353 GUDHI_CHECK(_matrix()->_are_adjacent(_matrix()->get_pivot(columnIndex1), _matrix()->get_pivot(columnIndex2)),
354 std::invalid_argument(
355 "Chain_vine_swap::vine_swap - Columns to be swapped need to be adjacent in the 'real' matrix."));
356 }
357
358 const bool col1IsNeg = _is_negative_in_pair(columnIndex1);
359 const bool col2IsNeg = _is_negative_in_pair(columnIndex2);
360
361 if (col1IsNeg && col2IsNeg) {
362 if (_matrix()->is_zero_entry(columnIndex2, _matrix()->get_pivot(columnIndex1))) {
363 ID_index pivot1 = _matrix()->get_pivot(columnIndex1);
364 ID_index pivot2 = _matrix()->get_pivot(columnIndex2);
365 if constexpr (Master_matrix::Option_list::has_column_pairings) {
366 _matrix()->_negative_transpose_barcode(pivot1, pivot2);
367 }
368 _swap_positions(pivot1, pivot2);
369 return columnIndex1;
370 }
371 return _negative_vine_swap(columnIndex1, columnIndex2);
372 }
373
374 if (col1IsNeg) {
375 if (_matrix()->is_zero_entry(columnIndex2, _matrix()->get_pivot(columnIndex1))) {
376 ID_index pivot1 = _matrix()->get_pivot(columnIndex1);
377 ID_index pivot2 = _matrix()->get_pivot(columnIndex2);
378 if constexpr (Master_matrix::Option_list::has_column_pairings) {
379 _matrix()->_negative_positive_transpose_barcode(pivot1, pivot2);
380 }
381 _swap_positions(pivot1, pivot2);
382 return columnIndex1;
383 }
384 return _negative_positive_vine_swap(columnIndex1, columnIndex2);
385 }
386
387 if (col2IsNeg) {
388 if (_matrix()->is_zero_entry(columnIndex2, _matrix()->get_pivot(columnIndex1))) {
389 ID_index pivot1 = _matrix()->get_pivot(columnIndex1);
390 ID_index pivot2 = _matrix()->get_pivot(columnIndex2);
391 if constexpr (Master_matrix::Option_list::has_column_pairings) {
392 _matrix()->_positive_negative_transpose_barcode(pivot1, pivot2);
393 }
394 _swap_positions(pivot1, pivot2);
395 return columnIndex1;
396 }
397 return _positive_negative_vine_swap(columnIndex1, columnIndex2);
398 }
399
400 if (_matrix()->is_zero_entry(columnIndex2, _matrix()->get_pivot(columnIndex1))) {
401 ID_index pivot1 = _matrix()->get_pivot(columnIndex1);
402 ID_index pivot2 = _matrix()->get_pivot(columnIndex2);
403 if constexpr (Master_matrix::Option_list::has_column_pairings) {
404 _matrix()->_positive_transpose_barcode(pivot1, pivot2);
405 }
406 _swap_positions(pivot1, pivot2);
407 return columnIndex1;
408 }
409 return _positive_vine_swap(columnIndex1, columnIndex2);
410}
411
412template <class Master_matrix>
413inline bool Chain_vine_swap<Master_matrix>::_is_negative_in_pair(Index columnIndex)
414{
415 if constexpr (Master_matrix::Option_list::has_column_pairings) {
416 return _matrix()->_is_negative_in_bar(_matrix()->get_pivot(columnIndex));
417 } else {
418 auto& col = _matrix()->get_column(columnIndex);
419 if (!col.is_paired()) return false;
420 return col.get_pivot() > _matrix()->get_pivot(col.get_paired_chain_index());
421 }
422}
423
424template <class Master_matrix>
425inline typename Chain_vine_swap<Master_matrix>::Index Chain_vine_swap<Master_matrix>::_positive_vine_swap(
426 Index columnIndex1,
427 Index columnIndex2)
428{
429 auto& col1 = _matrix()->get_column(columnIndex1);
430 auto& col2 = _matrix()->get_column(columnIndex2);
431
432 _swap_positions(col1.get_pivot(), col2.get_pivot());
433 // TODO: factorize the cases
434 // But for debug it is much more easier to understand what is happening when split like this
435 if (!col1.is_paired()) { // F x *
436 bool hasSmallerBirth;
437 if constexpr (Master_matrix::Option_list::has_column_pairings) {
438 // this order because position were swapped with swap_positions
439 hasSmallerBirth = (_matrix()->_birth_val(col2.get_pivot()) < _matrix()->_birth_val(col1.get_pivot()));
440 } else {
441 hasSmallerBirth = birthComp_(columnIndex1, columnIndex2);
442 }
443
444 if (!col2.is_paired() && hasSmallerBirth) {
445 _matrix()->add_to(columnIndex1, columnIndex2);
446 if constexpr (Master_matrix::Option_list::has_column_pairings) {
447 _matrix()->_positive_transpose_barcode(col1.get_pivot(), col2.get_pivot());
448 }
449 return columnIndex1;
450 }
451 _matrix()->add_to(columnIndex2, columnIndex1);
452
453 return columnIndex2;
454 }
455
456 if (!col2.is_paired()) { // G x F
457 static_cast<Master_chain_matrix*>(this)->add_to(columnIndex1, columnIndex2);
458 if constexpr (Master_matrix::Option_list::has_column_pairings) {
459 _matrix()->_positive_transpose_barcode(col1.get_pivot(), col2.get_pivot());
460 }
461 return columnIndex1;
462 }
463
464 bool hasSmallerDeath;
465 if constexpr (Master_matrix::Option_list::has_column_pairings) {
466 // this order because position were swapped with swap_positions
467 hasSmallerDeath = (_matrix()->_death_val(col2.get_pivot()) < _matrix()->_death_val(col1.get_pivot()));
468 } else {
469 hasSmallerDeath = deathComp_(columnIndex1, columnIndex2);
470 }
471
472 // G x G
473 if (hasSmallerDeath) {
474 _matrix()->add_to(col1.get_paired_chain_index(), col2.get_paired_chain_index());
475 _matrix()->add_to(columnIndex1, columnIndex2);
476 if constexpr (Master_matrix::Option_list::has_column_pairings) {
477 _matrix()->_positive_transpose_barcode(col1.get_pivot(), col2.get_pivot());
478 }
479 return columnIndex1;
480 }
481
482 _matrix()->add_to(col2.get_paired_chain_index(), col1.get_paired_chain_index());
483 _matrix()->add_to(columnIndex2, columnIndex1);
484
485 return columnIndex2;
486}
487
488template <class Master_matrix>
489inline typename Chain_vine_swap<Master_matrix>::Index Chain_vine_swap<Master_matrix>::_positive_negative_vine_swap(
490 Index columnIndex1,
491 Index columnIndex2)
492{
493 _matrix()->add_to(columnIndex1, columnIndex2);
494
495 ID_index pivot1 = _matrix()->get_pivot(columnIndex1);
496 ID_index pivot2 = _matrix()->get_pivot(columnIndex2);
497 if constexpr (Master_matrix::Option_list::has_column_pairings) {
498 _matrix()->_positive_negative_transpose_barcode(pivot1, pivot2);
499 }
500 _swap_positions(pivot1, pivot2);
501
502 return columnIndex1;
503}
504
505template <class Master_matrix>
506inline typename Chain_vine_swap<Master_matrix>::Index Chain_vine_swap<Master_matrix>::_negative_positive_vine_swap(
507 Index columnIndex1,
508 Index columnIndex2)
509{
510 _matrix()->add_to(columnIndex2, columnIndex1);
511
512 _swap_positions(_matrix()->get_pivot(columnIndex1), _matrix()->get_pivot(columnIndex2));
513
514 return columnIndex2;
515}
516
517template <class Master_matrix>
518inline typename Chain_vine_swap<Master_matrix>::Index Chain_vine_swap<Master_matrix>::_negative_vine_swap(
519 Index columnIndex1,
520 Index columnIndex2)
521{
522 auto& col1 = _matrix()->get_column(columnIndex1);
523 auto& col2 = _matrix()->get_column(columnIndex2);
524
525 Index pairedIndex1 = col1.get_paired_chain_index();
526 Index pairedIndex2 = col2.get_paired_chain_index();
527
528 bool hasSmallerBirth;
529 if constexpr (Master_matrix::Option_list::has_column_pairings) {
530 hasSmallerBirth = (_matrix()->_birth_val(col1.get_pivot()) < _matrix()->_birth_val(col2.get_pivot()));
531 } else {
532 hasSmallerBirth = birthComp_(pairedIndex1, pairedIndex2);
533 }
534
535 _swap_positions(col1.get_pivot(), col2.get_pivot());
536
537 if (hasSmallerBirth) {
538 _matrix()->add_to(pairedIndex1, pairedIndex2);
539 _matrix()->add_to(columnIndex1, columnIndex2);
540
541 if constexpr (Master_matrix::Option_list::has_column_pairings) {
542 _matrix()->_negative_transpose_barcode(col1.get_pivot(), col2.get_pivot());
543 }
544
545 return columnIndex1;
546 }
547
548 _matrix()->add_to(pairedIndex2, pairedIndex1);
549 _matrix()->add_to(columnIndex2, columnIndex1);
550
551 return columnIndex2;
552}
553
554template <class Master_matrix>
555inline void Chain_vine_swap<Master_matrix>::_swap_positions(ID_index pivot1, ID_index pivot2)
556{
557 if constexpr (Master_matrix::Option_list::has_column_pairings ||
558 Master_matrix::Option_list::can_retrieve_representative_cycles) {
559 auto& map = _matrix()->map_;
560 if constexpr (Master_matrix::Option_list::has_map_column_container) {
561 std::swap(map.at(pivot1), map.at(pivot2));
562 } else {
563 std::swap(map[pivot1], map[pivot2]);
564 }
565 }
566}
567
568} // namespace persistence_matrix
569} // namespace Gudhi
570
571#endif // PM_CHAIN_VINE_SWAP_H
Contains the Gudhi::persistence_matrix::Chain_pairing class and Gudhi::persistence_matrix::Dummy_chai...
Class managing the barcode for Chain_vine_swap.
Definition chain_vine_swap.h:89
typename Master_matrix::Pos_index Pos_index
Definition chain_vine_swap.h:92
Chain_barcode_swap()=default
Default constructor.
Chain_barcode_swap(Chain_barcode_swap &&other) noexcept
Move constructor.
Definition chain_vine_swap.h:111
Chain_barcode_swap(const Chain_barcode_swap &toCopy)
Copy constructor.
Definition chain_vine_swap.h:105
typename Master_matrix::ID_index ID_index
Definition chain_vine_swap.h:91
Chain_pairing()=default
Default constructor.
Chain_vine_swap()
Default constructor. Only available if PersistenceMatrixOptions::has_column_pairings is true.
Definition chain_vine_swap.h:319
typename Master_matrix::Pos_index Pos_index
Definition chain_vine_swap.h:239
typename Master_matrix::Column_container Column_container
Definition chain_vine_swap.h:240
friend void swap(Chain_vine_swap &swap1, Chain_vine_swap &swap2) noexcept
Swap operator.
Definition chain_vine_swap.h:294
Index vine_swap(Index columnIndex1, Index columnIndex2)
Does a vine swap between two cells which are consecutive in the filtration. Roughly,...
Definition chain_vine_swap.h:349
typename Master_matrix::Index Index
Definition chain_vine_swap.h:237
typename Master_matrix::ID_index ID_index
Definition chain_vine_swap.h:238
typename Master_matrix::Column Column
Definition chain_vine_swap.h:241
bool(*)(Pos_index, Pos_index) EventCompFuncPointer
Definition chain_vine_swap.h:242
Index vine_swap_with_z_eq_1_case(Index columnIndex1, Index columnIndex2)
Does the same than vine_swap, but assumes that the swap is non trivial and therefore skips a part of ...
Definition chain_vine_swap.h:332
constexpr bool _no_G_death_comparator(unsigned int columnIndex1, unsigned int columnIndex2)
Default death comparator. Simply assumes that two positive paired columns are never swapped....
Definition chain_vine_swap.h:43
Persistence matrix namespace.
Definition FieldOperators.h:18
Gudhi namespace.
Definition SimplicialComplexForAlpha.h:14
STL namespace.
Empty structure. Inherited instead of Chain_barcode_swap, when the barcode is not stored.
Definition chain_vine_swap.h:74