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);
288 Index vine_swap(Index columnIndex1, Index columnIndex2);
289
293 friend void swap(Chain_vine_swap& swap1, Chain_vine_swap& swap2) noexcept
294 {
295 std::swap(swap1.birthComp_, swap2.birthComp_);
296 std::swap(swap1.deathComp_, swap2.deathComp_);
297 }
298
299 private:
300 using Master_chain_matrix = typename Master_matrix::Master_chain_matrix;
301
302 std::function<bool(Pos_index, Pos_index)> birthComp_;
303 std::function<bool(Pos_index, Pos_index)> deathComp_;
304
305 bool _is_negative_in_pair(Index columnIndex);
306 Index _positive_vine_swap(Index columnIndex1, Index columnIndex2);
307 Index _positive_negative_vine_swap(Index columnIndex1, Index columnIndex2);
308 Index _negative_positive_vine_swap(Index columnIndex1, Index columnIndex2);
309 Index _negative_vine_swap(Index columnIndex1, Index columnIndex2);
310 void _swap_positions(ID_index pivot1, ID_index pivot2);
311
312 constexpr Master_chain_matrix* _matrix() { return static_cast<Master_chain_matrix*>(this); }
313
314 constexpr const Master_chain_matrix* _matrix() const { return static_cast<const Master_chain_matrix*>(this); }
315};
316
317template <class Master_matrix>
318inline Chain_vine_swap<Master_matrix>::Chain_vine_swap() : birthComp_(), deathComp_()
319{
320 static_assert(Master_matrix::Option_list::has_column_pairings,
321 "If barcode is not stored, at least a birth comparator has to be specified.");
322}
323
324template <class Master_matrix>
325inline Chain_vine_swap<Master_matrix>::Chain_vine_swap(std::function<bool(Pos_index, Pos_index)> birthComparator,
326 std::function<bool(Pos_index, Pos_index)> deathComparator)
327 : birthComp_(std::move(birthComparator)), deathComp_(std::move(deathComparator))
328{}
329
330template <class Master_matrix>
332 Index columnIndex1,
333 Index columnIndex2)
334{
335 const bool col1IsNeg = _is_negative_in_pair(columnIndex1);
336 const bool col2IsNeg = _is_negative_in_pair(columnIndex2);
337
338 if (col1IsNeg && col2IsNeg) return _negative_vine_swap(columnIndex1, columnIndex2);
339
340 if (col1IsNeg) return _negative_positive_vine_swap(columnIndex1, columnIndex2);
341
342 if (col2IsNeg) return _positive_negative_vine_swap(columnIndex1, columnIndex2);
343
344 return _positive_vine_swap(columnIndex1, columnIndex2);
345}
346
347template <class Master_matrix>
349 Index columnIndex2)
350{
351 if constexpr (Master_matrix::Option_list::has_column_pairings) {
352 GUDHI_CHECK(_matrix()->_are_adjacent(_matrix()->get_pivot(columnIndex1), _matrix()->get_pivot(columnIndex2)),
353 std::invalid_argument(
354 "Chain_vine_swap::vine_swap - Columns to be swapped need to be adjacent in the 'real' matrix."));
355 }
356
357 const bool col1IsNeg = _is_negative_in_pair(columnIndex1);
358 const bool col2IsNeg = _is_negative_in_pair(columnIndex2);
359
360 if (col1IsNeg && col2IsNeg) {
361 if (_matrix()->is_zero_entry(columnIndex2, _matrix()->get_pivot(columnIndex1))) {
362 ID_index pivot1 = _matrix()->get_pivot(columnIndex1);
363 ID_index pivot2 = _matrix()->get_pivot(columnIndex2);
364 if constexpr (Master_matrix::Option_list::has_column_pairings) {
365 _matrix()->_negative_transpose_barcode(pivot1, pivot2);
366 }
367 _swap_positions(pivot1, pivot2);
368 return columnIndex1;
369 }
370 return _negative_vine_swap(columnIndex1, columnIndex2);
371 }
372
373 if (col1IsNeg) {
374 if (_matrix()->is_zero_entry(columnIndex2, _matrix()->get_pivot(columnIndex1))) {
375 ID_index pivot1 = _matrix()->get_pivot(columnIndex1);
376 ID_index pivot2 = _matrix()->get_pivot(columnIndex2);
377 if constexpr (Master_matrix::Option_list::has_column_pairings) {
378 _matrix()->_negative_positive_transpose_barcode(pivot1, pivot2);
379 }
380 _swap_positions(pivot1, pivot2);
381 return columnIndex1;
382 }
383 return _negative_positive_vine_swap(columnIndex1, columnIndex2);
384 }
385
386 if (col2IsNeg) {
387 if (_matrix()->is_zero_entry(columnIndex2, _matrix()->get_pivot(columnIndex1))) {
388 ID_index pivot1 = _matrix()->get_pivot(columnIndex1);
389 ID_index pivot2 = _matrix()->get_pivot(columnIndex2);
390 if constexpr (Master_matrix::Option_list::has_column_pairings) {
391 _matrix()->_positive_negative_transpose_barcode(pivot1, pivot2);
392 }
393 _swap_positions(pivot1, pivot2);
394 return columnIndex1;
395 }
396 return _positive_negative_vine_swap(columnIndex1, columnIndex2);
397 }
398
399 if (_matrix()->is_zero_entry(columnIndex2, _matrix()->get_pivot(columnIndex1))) {
400 ID_index pivot1 = _matrix()->get_pivot(columnIndex1);
401 ID_index pivot2 = _matrix()->get_pivot(columnIndex2);
402 if constexpr (Master_matrix::Option_list::has_column_pairings) {
403 _matrix()->_positive_transpose_barcode(pivot1, pivot2);
404 }
405 _swap_positions(pivot1, pivot2);
406 return columnIndex1;
407 }
408 return _positive_vine_swap(columnIndex1, columnIndex2);
409}
410
411template <class Master_matrix>
412inline bool Chain_vine_swap<Master_matrix>::_is_negative_in_pair(Index columnIndex)
413{
414 if constexpr (Master_matrix::Option_list::has_column_pairings) {
415 return _matrix()->_is_negative_in_bar(_matrix()->get_pivot(columnIndex));
416 } else {
417 auto& col = _matrix()->get_column(columnIndex);
418 if (!col.is_paired()) return false;
419 return col.get_pivot() > _matrix()->get_pivot(col.get_paired_chain_index());
420 }
421}
422
423template <class Master_matrix>
424inline typename Chain_vine_swap<Master_matrix>::Index Chain_vine_swap<Master_matrix>::_positive_vine_swap(
425 Index columnIndex1,
426 Index columnIndex2)
427{
428 auto& col1 = _matrix()->get_column(columnIndex1);
429 auto& col2 = _matrix()->get_column(columnIndex2);
430
431 _swap_positions(col1.get_pivot(), col2.get_pivot());
432 // TODO: factorize the cases
433 // But for debug it is much more easier to understand what is happening when split like this
434 if (!col1.is_paired()) { // F x *
435 bool hasSmallerBirth;
436 if constexpr (Master_matrix::Option_list::has_column_pairings) {
437 // this order because position were swapped with swap_positions
438 hasSmallerBirth = (_matrix()->_birth_val(col2.get_pivot()) < _matrix()->_birth_val(col1.get_pivot()));
439 } else {
440 hasSmallerBirth = birthComp_(columnIndex1, columnIndex2);
441 }
442
443 if (!col2.is_paired() && hasSmallerBirth) {
444 _matrix()->add_to(columnIndex1, columnIndex2);
445 if constexpr (Master_matrix::Option_list::has_column_pairings) {
446 _matrix()->_positive_transpose_barcode(col1.get_pivot(), col2.get_pivot());
447 }
448 return columnIndex1;
449 }
450 _matrix()->add_to(columnIndex2, columnIndex1);
451
452 return columnIndex2;
453 }
454
455 if (!col2.is_paired()) { // G x F
456 static_cast<Master_chain_matrix*>(this)->add_to(columnIndex1, columnIndex2);
457 if constexpr (Master_matrix::Option_list::has_column_pairings) {
458 _matrix()->_positive_transpose_barcode(col1.get_pivot(), col2.get_pivot());
459 }
460 return columnIndex1;
461 }
462
463 bool hasSmallerDeath;
464 if constexpr (Master_matrix::Option_list::has_column_pairings) {
465 // this order because position were swapped with swap_positions
466 hasSmallerDeath = (_matrix()->_death_val(col2.get_pivot()) < _matrix()->_death_val(col1.get_pivot()));
467 } else {
468 hasSmallerDeath = deathComp_(columnIndex1, columnIndex2);
469 }
470
471 // G x G
472 if (hasSmallerDeath) {
473 _matrix()->add_to(col1.get_paired_chain_index(), col2.get_paired_chain_index());
474 _matrix()->add_to(columnIndex1, columnIndex2);
475 if constexpr (Master_matrix::Option_list::has_column_pairings) {
476 _matrix()->_positive_transpose_barcode(col1.get_pivot(), col2.get_pivot());
477 }
478 return columnIndex1;
479 }
480
481 _matrix()->add_to(col2.get_paired_chain_index(), col1.get_paired_chain_index());
482 _matrix()->add_to(columnIndex2, columnIndex1);
483
484 return columnIndex2;
485}
486
487template <class Master_matrix>
488inline typename Chain_vine_swap<Master_matrix>::Index Chain_vine_swap<Master_matrix>::_positive_negative_vine_swap(
489 Index columnIndex1,
490 Index columnIndex2)
491{
492 _matrix()->add_to(columnIndex1, columnIndex2);
493
494 ID_index pivot1 = _matrix()->get_pivot(columnIndex1);
495 ID_index pivot2 = _matrix()->get_pivot(columnIndex2);
496 if constexpr (Master_matrix::Option_list::has_column_pairings) {
497 _matrix()->_positive_negative_transpose_barcode(pivot1, pivot2);
498 }
499 _swap_positions(pivot1, pivot2);
500
501 return columnIndex1;
502}
503
504template <class Master_matrix>
505inline typename Chain_vine_swap<Master_matrix>::Index Chain_vine_swap<Master_matrix>::_negative_positive_vine_swap(
506 Index columnIndex1,
507 Index columnIndex2)
508{
509 _matrix()->add_to(columnIndex2, columnIndex1);
510
511 _swap_positions(_matrix()->get_pivot(columnIndex1), _matrix()->get_pivot(columnIndex2));
512
513 return columnIndex2;
514}
515
516template <class Master_matrix>
517inline typename Chain_vine_swap<Master_matrix>::Index Chain_vine_swap<Master_matrix>::_negative_vine_swap(
518 Index columnIndex1,
519 Index columnIndex2)
520{
521 auto& col1 = _matrix()->get_column(columnIndex1);
522 auto& col2 = _matrix()->get_column(columnIndex2);
523
524 Index pairedIndex1 = col1.get_paired_chain_index();
525 Index pairedIndex2 = col2.get_paired_chain_index();
526
527 bool hasSmallerBirth;
528 if constexpr (Master_matrix::Option_list::has_column_pairings) {
529 hasSmallerBirth = (_matrix()->_birth_val(col1.get_pivot()) < _matrix()->_birth_val(col2.get_pivot()));
530 } else {
531 hasSmallerBirth = birthComp_(pairedIndex1, pairedIndex2);
532 }
533
534 _swap_positions(col1.get_pivot(), col2.get_pivot());
535
536 if (hasSmallerBirth) {
537 _matrix()->add_to(pairedIndex1, pairedIndex2);
538 _matrix()->add_to(columnIndex1, columnIndex2);
539
540 if constexpr (Master_matrix::Option_list::has_column_pairings) {
541 _matrix()->_negative_transpose_barcode(col1.get_pivot(), col2.get_pivot());
542 }
543
544 return columnIndex1;
545 }
546
547 _matrix()->add_to(pairedIndex2, pairedIndex1);
548 _matrix()->add_to(columnIndex2, columnIndex1);
549
550 return columnIndex2;
551}
552
553template <class Master_matrix>
554inline void Chain_vine_swap<Master_matrix>::_swap_positions(ID_index pivot1, ID_index pivot2)
555{
556 if constexpr (Master_matrix::Option_list::has_column_pairings ||
557 Master_matrix::Option_list::can_retrieve_representative_cycles) {
558 auto& map = _matrix()->map_;
559 if constexpr (Master_matrix::Option_list::has_map_column_container) {
560 std::swap(map.at(pivot1), map.at(pivot2));
561 } else {
562 std::swap(map[pivot1], map[pivot2]);
563 }
564 }
565}
566
567} // namespace persistence_matrix
568} // namespace Gudhi
569
570#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:318
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:293
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:348
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:331
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