Loading...
Searching...
No Matches
heap_column.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_HEAP_COLUMN_H
19#define PM_HEAP_COLUMN_H
20
21#include <stdexcept>
22#include <type_traits>
23#include <cstddef> // std::size_t
24#include <algorithm> // std::make_heap
25#include <utility> // std::swap, std::move & std::exchange
26#include <vector>
27
28#include <boost/iterator/indirect_iterator.hpp>
29
30#include <gudhi/Debug_utils.h>
32
33namespace Gudhi {
34namespace persistence_matrix {
35
50template <class Master_matrix>
51class Heap_column : public Master_matrix::Column_dimension_option, public Master_matrix::Chain_column_option
52{
53 public:
54 using Master = Master_matrix;
55 using Index = typename Master_matrix::Index;
56 using ID_index = typename Master_matrix::ID_index;
57 using Dimension = typename Master_matrix::Dimension;
58 using Field_element = typename Master_matrix::Element;
59 using Entry = typename Master_matrix::Matrix_entry;
60 using Column_settings = typename Master_matrix::Column_settings;
61
62 private:
63 using Field_operators = typename Master_matrix::Field_operators;
64 using Column_support = std::vector<Entry*>;
65 using Entry_constructor = typename Master_matrix::Entry_constructor;
66
67 public:
68 using iterator = boost::indirect_iterator<typename Column_support::iterator>;
69 using const_iterator = boost::indirect_iterator<typename Column_support::const_iterator>;
70 using reverse_iterator = boost::indirect_iterator<typename Column_support::reverse_iterator>;
71 using const_reverse_iterator = boost::indirect_iterator<typename Column_support::const_reverse_iterator>;
72 using Content_range = std::vector<Entry>;
73
74 Heap_column(Column_settings* colSettings = nullptr);
75 template <class Container = typename Master_matrix::Boundary>
76 Heap_column(const Container& nonZeroRowIndices, Column_settings* colSettings);
77 template <class Container = typename Master_matrix::Boundary,
78 class = std::enable_if_t<!std::is_arithmetic_v<Container> > >
79 Heap_column(const Container& nonZeroRowIndices, Dimension dimension, Column_settings* colSettings);
80 Heap_column(ID_index idx, Dimension dimension, Column_settings* colSettings);
81 Heap_column(ID_index idx, Field_element e, Dimension dimension, Column_settings* colSettings);
82 Heap_column(const Heap_column& column, Column_settings* colSettings = nullptr);
83 Heap_column(Heap_column&& column) noexcept;
84 ~Heap_column();
85
86 // just for the sake of the interface
87 // row containers and column index are ignored as row access is not implemented for heap columns
88 template <class Container = typename Master_matrix::Boundary, class Row_container>
89 Heap_column([[maybe_unused]] Index columnIndex,
90 const Container& nonZeroRowIndices,
91 [[maybe_unused]] Row_container* rowContainer,
92 Column_settings* colSettings);
93 template <class Container = typename Master_matrix::Boundary,
94 class Row_container,
95 class = std::enable_if_t<!std::is_arithmetic_v<Container> > >
96 Heap_column([[maybe_unused]] Index columnIndex,
97 const Container& nonZeroRowIndices,
98 Dimension dimension,
99 [[maybe_unused]] Row_container* rowContainer,
100 Column_settings* colSettings);
101 template <class Row_container>
102 Heap_column([[maybe_unused]] Index columnIndex,
103 ID_index idx,
104 Dimension dimension,
105 [[maybe_unused]] Row_container* rowContainer,
106 Column_settings* colSettings);
107 template <class Row_container>
108 Heap_column([[maybe_unused]] Index columnIndex,
109 ID_index idx,
110 Field_element e,
111 Dimension dimension,
112 [[maybe_unused]] Row_container* rowContainer,
113 Column_settings* colSettings);
114 template <class Row_container>
115 Heap_column(const Heap_column& column,
116 [[maybe_unused]] Index columnIndex,
117 [[maybe_unused]] Row_container* rowContainer,
118 Column_settings* colSettings = nullptr);
119
120 std::vector<Field_element> get_content(int columnLength = -1) const;
121 bool is_non_zero(ID_index rowIndex) const;
122 bool is_empty();
123 [[nodiscard]] std::size_t size() const;
124
125 template <class Row_index_map>
126 void reorder(const Row_index_map& valueMap,
127 [[maybe_unused]] Index columnIndex = Master_matrix::template get_null_value<Index>());
128 void clear();
129 void clear(ID_index rowIndex);
130
131 ID_index get_pivot();
132 Field_element get_pivot_value();
133
134 iterator begin() noexcept;
135 const_iterator begin() const noexcept;
136 iterator end() noexcept;
137 const_iterator end() const noexcept;
138 reverse_iterator rbegin() noexcept;
139 const_reverse_iterator rbegin() const noexcept;
140 reverse_iterator rend() noexcept;
141 const_reverse_iterator rend() const noexcept;
142
143 Content_range get_non_zero_content_range();
144
145 template <class Entry_range>
146 Heap_column& operator+=(const Entry_range& column);
147 Heap_column& operator+=(Heap_column& column);
148
149 Heap_column& operator*=(const Field_element& v);
150
151 // this = v * this + column
152 template <class Entry_range>
153 Heap_column& multiply_target_and_add(const Field_element& val, const Entry_range& column);
154 Heap_column& multiply_target_and_add(const Field_element& val, Heap_column& column);
155 // this = this + column * v
156 template <class Entry_range>
157 Heap_column& multiply_source_and_add(const Entry_range& column, const Field_element& val);
158 Heap_column& multiply_source_and_add(Heap_column& column, const Field_element& val);
159
160 void push_back(const Entry& entry);
161
162 std::size_t compute_hash_value();
163
164 friend bool operator==(const Heap_column& c1, const Heap_column& c2)
165 {
166 if (&c1 == &c2) return true;
167
168 Heap_column cc1(c1), cc2(c2);
169 Entry* p1 = cc1._pop_pivot();
170 Entry* p2 = cc2._pop_pivot();
171 while (p1 != nullptr && p2 != nullptr) {
172 Index r1 = Master_matrix::get_row_index(*p1);
173 Index r2 = Master_matrix::get_row_index(*p2);
174 Field_element e1 = Master_matrix::get_element(*p1);
175 Field_element e2 = Master_matrix::get_element(*p2);
176 c1.entryPool_->destroy(p1);
177 c2.entryPool_->destroy(p2);
178
179 if (r1 != r2 || e1 != e2) {
180 return false;
181 }
182
183 p1 = cc1._pop_pivot();
184 p2 = cc2._pop_pivot();
185 }
186
187 if (p1 != nullptr) {
188 c1.entryPool_->destroy(p1);
189 return false;
190 }
191 if (p2 != nullptr) {
192 c1.entryPool_->destroy(p2);
193 return false;
194 }
195
196 return true;
197 }
198
199 friend bool operator<(const Heap_column& c1, const Heap_column& c2)
200 {
201 if (&c1 == &c2) return false;
202
203 // lexicographical order but starting from last value and not first
204 Heap_column cc1(c1), cc2(c2);
205 Entry* p1 = cc1._pop_pivot();
206 Entry* p2 = cc2._pop_pivot();
207 while (p1 != nullptr && p2 != nullptr) {
208 Index r1 = Master_matrix::get_row_index(*p1);
209 Index r2 = Master_matrix::get_row_index(*p2);
210 Field_element e1 = Master_matrix::get_element(*p1);
211 Field_element e2 = Master_matrix::get_element(*p2);
212 c1.entryPool_->destroy(p1);
213 c2.entryPool_->destroy(p2);
214
215 if (r1 != r2) return r1 < r2;
216 if (e1 != e2) return e1 < e2;
217
218 p1 = cc1._pop_pivot();
219 p2 = cc2._pop_pivot();
220 }
221
222 if (p2 == nullptr) {
223 c1.entryPool_->destroy(p1);
224 return false;
225 }
226 c2.entryPool_->destroy(p2);
227 return true;
228 }
229
230 // Disabled with row access.
231 Heap_column& operator=(const Heap_column& other);
232 Heap_column& operator=(Heap_column&& other) noexcept;
233
234 friend void swap(Heap_column& col1, Heap_column& col2) noexcept
235 {
236 swap(static_cast<typename Master_matrix::Column_dimension_option&>(col1),
237 static_cast<typename Master_matrix::Column_dimension_option&>(col2));
238 swap(static_cast<typename Master_matrix::Chain_column_option&>(col1),
239 static_cast<typename Master_matrix::Chain_column_option&>(col2));
240 col1.column_.swap(col2.column_);
241 std::swap(col1.insertsSinceLastPrune_, col2.insertsSinceLastPrune_);
242 std::swap(col1.operators_, col2.operators_);
243 std::swap(col1.entryPool_, col2.entryPool_);
244 }
245
246 private:
247 using Dim_opt = typename Master_matrix::Column_dimension_option;
248 using Chain_opt = typename Master_matrix::Chain_column_option;
249
250 struct EntryPointerComp {
251 bool operator()(const Entry* c1, const Entry* c2) const { return *c1 < *c2; }
252 } entryPointerComp_;
253
254 Column_support column_;
255 unsigned int insertsSinceLastPrune_;
256 Field_operators const* operators_;
257 Entry_constructor* entryPool_;
258
259 void _prune();
260 Entry* _pop_pivot();
261 template <class Entry_range>
262 void _add(const Entry_range& column, Field_element& pivotVal);
263 template<bool computePivotVal>
264 std::conditional_t<computePivotVal, Field_element, void> _multiply(const Field_element& val);
265 template <class Entry_range>
266 bool _multiply_target_and_add(const Field_element& val, const Entry_range& column);
267 template <class Entry_range>
268 bool _multiply_source_and_add(const Entry_range& column, const Field_element& val);
269 void _add_coefficient(Field_element& e, const Field_element& a) const;
270 Field_element _multiply_coefficient(const Field_element& e, const Field_element& a) const;
271};
272
273template <class Master_matrix>
274inline Heap_column<Master_matrix>::Heap_column(Column_settings* colSettings)
275 : Dim_opt(),
276 Chain_opt(),
277 insertsSinceLastPrune_(0),
278 operators_(Master_matrix::get_operator_ptr(colSettings)),
279 entryPool_(colSettings == nullptr ? nullptr : &(colSettings->entryConstructor))
280{}
281
282template <class Master_matrix>
283template <class Container>
284inline Heap_column<Master_matrix>::Heap_column(const Container& nonZeroRowIndices, Column_settings* colSettings)
285 : Heap_column(nonZeroRowIndices, nonZeroRowIndices.size() == 0 ? 0 : nonZeroRowIndices.size() - 1, colSettings)
286{
287 static_assert(!Master_matrix::isNonBasic || Master_matrix::Option_list::is_of_boundary_type,
288 "Constructor not available for chain columns, please specify the dimension of the chain.");
289}
290
291template <class Master_matrix>
292template <class Container, class>
293inline Heap_column<Master_matrix>::Heap_column(const Container& nonZeroRowIndices,
294 Dimension dimension,
295 Column_settings* colSettings)
296 : Dim_opt(dimension),
297 Chain_opt(nonZeroRowIndices.begin() == nonZeroRowIndices.end()
298 ? Master_matrix::template get_null_value<ID_index>()
299 : Master_matrix::get_row_index(*std::prev(nonZeroRowIndices.end()))),
300 column_(nonZeroRowIndices.size(), nullptr),
301 insertsSinceLastPrune_(0),
302 operators_(Master_matrix::get_operator_ptr(colSettings)),
303 entryPool_(&(colSettings->entryConstructor))
304{
305 Index i = 0;
306
307 for (const auto& id : nonZeroRowIndices) {
308 column_[i] = entryPool_->construct(Master_matrix::get_row_index(id));
309 column_[i]->set_element(Master_matrix::get_coefficient_value(Master_matrix::get_element(id), operators_));
310 ++i;
311 }
312
313 std::make_heap(column_.begin(), column_.end(), entryPointerComp_);
314}
315
316template <class Master_matrix>
317inline Heap_column<Master_matrix>::Heap_column(ID_index idx, Dimension dimension, Column_settings* colSettings)
318 : Dim_opt(dimension),
319 Chain_opt(idx),
320 column_(1, nullptr),
321 insertsSinceLastPrune_(0),
322 operators_(nullptr),
323 entryPool_(&(colSettings->entryConstructor))
324{
325 static_assert(Master_matrix::Option_list::is_z2,
326 "Constructor not available for Zp != Z2. Please specify the coefficient.");
327 column_[0] = entryPool_->construct(idx);
328}
329
330template <class Master_matrix>
331inline Heap_column<Master_matrix>::Heap_column(ID_index idx,
332 Field_element e,
333 Dimension dimension,
334 Column_settings* colSettings)
335 : Dim_opt(dimension),
336 Chain_opt(idx),
337 column_(1, nullptr),
338 insertsSinceLastPrune_(0),
339 operators_(&(colSettings->operators)),
340 entryPool_(&(colSettings->entryConstructor))
341{
342 static_assert(!Master_matrix::Option_list::is_z2,
343 "Constructor not available for Zp == Z2. Please do not specify any coefficient.");
344 column_[0] = entryPool_->construct(idx);
345 column_[0]->set_element(operators_->get_value(e));
346}
347
348template <class Master_matrix>
349inline Heap_column<Master_matrix>::Heap_column(const Heap_column& column, Column_settings* colSettings)
350 : Dim_opt(static_cast<const Dim_opt&>(column)),
351 Chain_opt(static_cast<const Chain_opt&>(column)),
352 column_(column.column_.size(), nullptr),
353 insertsSinceLastPrune_(0),
354 operators_(colSettings == nullptr ? column.operators_ : Master_matrix::get_operator_ptr(colSettings)),
355 entryPool_(colSettings == nullptr ? column.entryPool_ : &(colSettings->entryConstructor))
356{
357 static_assert(!Master_matrix::Option_list::has_row_access,
358 "Simple copy constructor not available when row access option enabled. Please specify the new column "
359 "index and the row container.");
360
361 Index i = 0;
362 for (const Entry* entry : column.column_) {
363 column_[i] = entryPool_->construct(entry->get_row_index());
364 column_[i]->set_element(entry->get_element());
365 ++i;
366 }
367 // column.column_ already ordered as a heap, so no need of make_heap.
368}
369
370template <class Master_matrix>
371inline Heap_column<Master_matrix>::Heap_column(Heap_column&& column) noexcept
372 : Dim_opt(std::move(static_cast<Dim_opt&>(column))),
373 Chain_opt(std::move(static_cast<Chain_opt&>(column))),
374 column_(std::move(column.column_)),
375 insertsSinceLastPrune_(std::exchange(column.insertsSinceLastPrune_, 0)),
376 operators_(std::exchange(column.operators_, nullptr)),
377 entryPool_(std::exchange(column.entryPool_, nullptr))
378{}
379
380template <class Master_matrix>
381template <class Container, class Row_container>
382inline Heap_column<Master_matrix>::Heap_column([[maybe_unused]] Index columnIndex,
383 const Container& nonZeroRowIndices,
384 [[maybe_unused]] Row_container* rowContainer,
385 Column_settings* colSettings)
386 : Heap_column(nonZeroRowIndices, colSettings)
387{
388 static_assert(!Master_matrix::isNonBasic || Master_matrix::Option_list::is_of_boundary_type,
389 "Constructor not available for chain columns, please specify the dimension of the chain.");
390}
391
392template <class Master_matrix>
393template <class Container, class Row_container, class>
394inline Heap_column<Master_matrix>::Heap_column([[maybe_unused]] Index columnIndex,
395 const Container& nonZeroRowIndices,
396 Dimension dimension,
397 [[maybe_unused]] Row_container* rowContainer,
398 Column_settings* colSettings)
399 : Heap_column(nonZeroRowIndices, dimension, colSettings)
400{}
401
402template <class Master_matrix>
403template <class Row_container>
404inline Heap_column<Master_matrix>::Heap_column(const Heap_column& column,
405 [[maybe_unused]] Index columnIndex,
406 [[maybe_unused]] Row_container* rowContainer,
407 Column_settings* colSettings)
408 : Heap_column(column, colSettings)
409{}
410
411template <class Master_matrix>
412template <class Row_container>
413inline Heap_column<Master_matrix>::Heap_column([[maybe_unused]] Index columnIndex,
414 ID_index idx,
415 Dimension dimension,
416 [[maybe_unused]] Row_container* rowContainer,
417 Column_settings* colSettings)
418 : Heap_column(idx, dimension, colSettings)
419{}
420
421template <class Master_matrix>
422template <class Row_container>
423inline Heap_column<Master_matrix>::Heap_column([[maybe_unused]] Index columnIndex,
424 ID_index idx,
425 Field_element e,
426 Dimension dimension,
427 [[maybe_unused]] Row_container* rowContainer,
428 Column_settings* colSettings)
429 : Heap_column(idx, e, dimension, colSettings)
430{}
431
432template <class Master_matrix>
433inline Heap_column<Master_matrix>::~Heap_column()
434{
435 for (auto* entry : column_) {
436 entryPool_->destroy(entry);
437 }
438}
439
440template <class Master_matrix>
441inline std::vector<typename Heap_column<Master_matrix>::Field_element> Heap_column<Master_matrix>::get_content(
442 int columnLength) const
443{
444 bool pivotLength = (columnLength < 0);
445 if (columnLength < 0 && column_.size() > 0)
446 columnLength = column_.front()->get_row_index() + 1;
447 else if (columnLength < 0)
448 return std::vector<Field_element>();
449
450 std::vector<Field_element> container(columnLength, 0);
451 for (auto it = column_.begin(); it != column_.end(); ++it) {
452 auto idx = (*it)->get_row_index();
453 if (idx < static_cast<ID_index>(columnLength)) {
454 // Cannot use _add_coefficient because of vector<bool>
455 // I would have to do a special case for it, but it only happens here, so...
456 if constexpr (Master_matrix::Option_list::is_z2) {
457 container[idx] = !container[idx];
458 } else {
459 operators_->add_inplace(container[idx], (*it)->get_element());
460 }
461 }
462 }
463
464 if (pivotLength) {
465 while (!container.empty() && container.back() == 0U) container.pop_back();
466 }
467
468 return container;
469}
470
471template <class Master_matrix>
472inline bool Heap_column<Master_matrix>::is_non_zero(ID_index rowIndex) const
473{
474 Field_element c(0);
475 for (const Entry* entry : column_) {
476 if (entry->get_row_index() == rowIndex) {
477 _add_coefficient(c, entry->get_element());
478 }
479 }
480 return c != Field_operators::get_additive_identity();
481}
482
483template <class Master_matrix>
484inline bool Heap_column<Master_matrix>::is_empty()
485{
486 Entry* pivot = _pop_pivot();
487 if (pivot != nullptr) {
488 column_.push_back(pivot);
489 std::push_heap(column_.begin(), column_.end(), entryPointerComp_);
490 return false;
491 }
492 return true;
493}
494
495template <class Master_matrix>
496inline std::size_t Heap_column<Master_matrix>::size() const
497{
498 return column_.size();
499}
500
501template <class Master_matrix>
502template <class Row_index_map>
503inline void Heap_column<Master_matrix>::reorder(const Row_index_map& valueMap, [[maybe_unused]] Index columnIndex)
504{
505 static_assert(!Master_matrix::isNonBasic || Master_matrix::Option_list::is_of_boundary_type,
506 "Method not available for chain columns.");
507
508 Column_support tempCol;
509 Entry* pivot = _pop_pivot();
510 while (pivot != nullptr) {
511 pivot->set_row_index(valueMap.at(pivot->get_row_index()));
512 tempCol.push_back(pivot);
513 pivot = _pop_pivot();
514 }
515 column_.swap(tempCol);
516 std::make_heap(column_.begin(), column_.end(), entryPointerComp_);
517
518 insertsSinceLastPrune_ = 0;
519}
520
521template <class Master_matrix>
522inline void Heap_column<Master_matrix>::clear()
523{
524 static_assert(!Master_matrix::isNonBasic || Master_matrix::Option_list::is_of_boundary_type,
525 "Method not available for chain columns as a base element should not be empty.");
526
527 for (auto* entry : column_) {
528 entryPool_->destroy(entry);
529 }
530
531 column_.clear();
532 insertsSinceLastPrune_ = 0;
533}
534
535template <class Master_matrix>
536inline void Heap_column<Master_matrix>::clear(ID_index rowIndex)
537{
538 static_assert(!Master_matrix::isNonBasic || Master_matrix::Option_list::is_of_boundary_type,
539 "Method not available for chain columns.");
540
541 Column_support tempCol;
542 Entry* pivot = _pop_pivot();
543 while (pivot != nullptr) {
544 if (pivot->get_row_index() != rowIndex) {
545 tempCol.push_back(pivot);
546 } else {
547 entryPool_->destroy(pivot);
548 }
549 pivot = _pop_pivot();
550 }
551 column_.swap(tempCol);
552
553 insertsSinceLastPrune_ = 0;
554}
555
556template <class Master_matrix>
557inline typename Heap_column<Master_matrix>::ID_index Heap_column<Master_matrix>::get_pivot()
558{
559 static_assert(Master_matrix::isNonBasic,
560 "Method not available for base columns."); // could technically be, but is the notion useful then?
561
562 if constexpr (Master_matrix::Option_list::is_of_boundary_type) {
563 Entry* pivot = _pop_pivot();
564 if (pivot != nullptr) {
565 column_.push_back(pivot);
566 std::push_heap(column_.begin(), column_.end(), entryPointerComp_);
567 return pivot->get_row_index();
568 }
569 return Master_matrix::template get_null_value<ID_index>();
570 } else {
571 return Chain_opt::_get_pivot();
572 }
573}
574
575template <class Master_matrix>
576inline typename Heap_column<Master_matrix>::Field_element Heap_column<Master_matrix>::get_pivot_value()
577{
578 static_assert(Master_matrix::isNonBasic,
579 "Method not available for base columns."); // could technically be, but is the notion useful then?
580
581 if constexpr (Master_matrix::Option_list::is_z2) {
582 return 1;
583 } else {
584 if constexpr (Master_matrix::Option_list::is_of_boundary_type) {
585 Entry* pivot = _pop_pivot();
586 if (pivot != nullptr) {
587 column_.push_back(pivot);
588 std::push_heap(column_.begin(), column_.end(), entryPointerComp_);
589 return pivot->get_element();
590 }
591 return 0;
592 } else {
593 Field_element sum(0);
594 if (Chain_opt::_get_pivot() == Master_matrix::template get_null_value<ID_index>()) return sum;
595 for (const Entry* entry : column_) {
596 if (entry->get_row_index() == Chain_opt::_get_pivot()) operators_->add_inplace(sum, entry->get_element());
597 }
598 return sum; // should not be 0 if properly used.
599 }
600 }
601}
602
603template <class Master_matrix>
604inline typename Heap_column<Master_matrix>::iterator Heap_column<Master_matrix>::begin() noexcept
605{
606 return column_.begin();
607}
608
609template <class Master_matrix>
610inline typename Heap_column<Master_matrix>::const_iterator Heap_column<Master_matrix>::begin() const noexcept
611{
612 return column_.begin();
613}
614
615template <class Master_matrix>
616inline typename Heap_column<Master_matrix>::iterator Heap_column<Master_matrix>::end() noexcept
617{
618 return column_.end();
619}
620
621template <class Master_matrix>
622inline typename Heap_column<Master_matrix>::const_iterator Heap_column<Master_matrix>::end() const noexcept
623{
624 return column_.end();
625}
626
627template <class Master_matrix>
628inline typename Heap_column<Master_matrix>::reverse_iterator Heap_column<Master_matrix>::rbegin() noexcept
629{
630 return column_.rbegin();
631}
632
633template <class Master_matrix>
634inline typename Heap_column<Master_matrix>::const_reverse_iterator Heap_column<Master_matrix>::rbegin() const noexcept
635{
636 return column_.rbegin();
637}
638
639template <class Master_matrix>
640inline typename Heap_column<Master_matrix>::reverse_iterator Heap_column<Master_matrix>::rend() noexcept
641{
642 return column_.rend();
643}
644
645template <class Master_matrix>
646inline typename Heap_column<Master_matrix>::const_reverse_iterator Heap_column<Master_matrix>::rend() const noexcept
647{
648 return column_.rend();
649}
650
651template <class Master_matrix>
652inline typename Heap_column<Master_matrix>::Content_range Heap_column<Master_matrix>::get_non_zero_content_range()
653{
654 _prune();
655 Content_range res(column_.size());
656 for (std::size_t i = 0; i < column_.size(); ++i) res[i] = *column_[i];
657 std::sort(res.begin(), res.end());
658 return res;
659}
660
661template <class Master_matrix>
662template <class Entry_range>
663inline Heap_column<Master_matrix>& Heap_column<Master_matrix>::operator+=(const Entry_range& column)
664{
665 static_assert((!Master_matrix::isNonBasic || std::is_same_v<Entry_range, Heap_column>),
666 "For boundary columns, the range has to be a column of same type to help ensure the validity of the "
667 "base element."); // could be removed, if we give the responsibility to the user.
668 static_assert((!Master_matrix::isNonBasic || Master_matrix::Option_list::is_of_boundary_type),
669 "For chain columns, the given column cannot be constant.");
670
671 Field_element dummy(0);
672 _add(column, dummy);
673
674 return *this;
675}
676
677template <class Master_matrix>
678inline Heap_column<Master_matrix>& Heap_column<Master_matrix>::operator+=(Heap_column& column)
679{
680 if constexpr (Master_matrix::isNonBasic && !Master_matrix::Option_list::is_of_boundary_type) {
681 Field_element v = get_pivot_value();
682 _add(column, v);
683 // assumes that the addition never zeros out this column.
684 if (v == Field_operators::get_additive_identity()) {
685 Chain_opt::_swap_pivots(column);
686 Dim_opt::_swap_dimension(column);
687 }
688 } else {
689 Field_element dummy(0);
690 _add(column, dummy);
691 }
692
693 return *this;
694}
695
696template <class Master_matrix>
697inline Heap_column<Master_matrix>& Heap_column<Master_matrix>::operator*=(const Field_element& v)
698{
699 _multiply<false>(Master_matrix::get_coefficient_value(v, operators_));
700
701 return *this;
702}
703
704template <class Master_matrix>
705template <class Entry_range>
706inline Heap_column<Master_matrix>& Heap_column<Master_matrix>::multiply_target_and_add(const Field_element& val,
707 const Entry_range& column)
708{
709 static_assert((!Master_matrix::isNonBasic || std::is_same_v<Entry_range, Heap_column>),
710 "For boundary columns, the range has to be a column of same type to help ensure the validity of the "
711 "base element."); // could be removed, if we give the responsibility to the user.
712 static_assert((!Master_matrix::isNonBasic || Master_matrix::Option_list::is_of_boundary_type),
713 "For chain columns, the given column cannot be constant.");
714
715 _multiply_target_and_add(Master_matrix::get_coefficient_value(val, operators_), column);
716
717 return *this;
718}
719
720template <class Master_matrix>
721inline Heap_column<Master_matrix>& Heap_column<Master_matrix>::multiply_target_and_add(const Field_element& val,
722 Heap_column& column)
723{
724 if constexpr (Master_matrix::isNonBasic && !Master_matrix::Option_list::is_of_boundary_type) {
725 // assumes that the addition never zeros out this column.
726 if (_multiply_target_and_add(Master_matrix::get_coefficient_value(val, operators_), column)) {
727 Chain_opt::_swap_pivots(column);
728 Dim_opt::_swap_dimension(column);
729 }
730 } else {
731 _multiply_target_and_add(Master_matrix::get_coefficient_value(val, operators_), column);
732 }
733
734 return *this;
735}
736
737template <class Master_matrix>
738template <class Entry_range>
739inline Heap_column<Master_matrix>& Heap_column<Master_matrix>::multiply_source_and_add(const Entry_range& column,
740 const Field_element& val)
741{
742 static_assert((!Master_matrix::isNonBasic || std::is_same_v<Entry_range, Heap_column>),
743 "For boundary columns, the range has to be a column of same type to help ensure the validity of the "
744 "base element."); // could be removed, if we give the responsibility to the user.
745 static_assert((!Master_matrix::isNonBasic || Master_matrix::Option_list::is_of_boundary_type),
746 "For chain columns, the given column cannot be constant.");
747
748 _multiply_source_and_add(column, Master_matrix::get_coefficient_value(val, operators_));
749
750 return *this;
751}
752
753template <class Master_matrix>
754inline Heap_column<Master_matrix>& Heap_column<Master_matrix>::multiply_source_and_add(Heap_column& column,
755 const Field_element& val)
756{
757 if constexpr (Master_matrix::isNonBasic && !Master_matrix::Option_list::is_of_boundary_type) {
758 // assumes that the addition never zeros out this column.
759 if (_multiply_source_and_add(column, Master_matrix::get_coefficient_value(val, operators_))) {
760 Chain_opt::_swap_pivots(column);
761 Dim_opt::_swap_dimension(column);
762 }
763 } else {
764 _multiply_source_and_add(column, Master_matrix::get_coefficient_value(val, operators_));
765 }
766
767 return *this;
768}
769
770template <class Master_matrix>
771inline void Heap_column<Master_matrix>::push_back(const Entry& entry)
772{
773 static_assert(Master_matrix::Option_list::is_of_boundary_type, "`push_back` is not available for Chain matrices.");
774
775 GUDHI_CHECK(entry.get_row_index() > get_pivot(),
776 std::invalid_argument("The new row index has to be higher than the current pivot."));
777
778 Entry* newEntry = entryPool_->construct(entry.get_row_index());
779 newEntry->set_element(Master_matrix::get_coefficient_value(entry.get_element(), operators_));
780 column_.push_back(newEntry);
781 std::push_heap(column_.begin(), column_.end(), entryPointerComp_);
782}
783
784template <class Master_matrix>
785inline Heap_column<Master_matrix>& Heap_column<Master_matrix>::operator=(const Heap_column& other)
786{
787 static_assert(!Master_matrix::Option_list::has_row_access, "= assignment not enabled with row access option.");
788
789 // to avoid destroying the column when building from it-self in the for loop below...
790 if (this == &other) return *this;
791
792 Dim_opt::operator=(other);
793 Chain_opt::operator=(other);
794
795 while (column_.size() > other.column_.size()) {
796 if (column_.back() != nullptr) entryPool_->destroy(column_.back());
797 column_.pop_back();
798 }
799
800 column_.resize(other.column_.size(), nullptr);
801 Index i = 0;
802 for (const Entry* entry : other.column_) {
803 if (column_[i] != nullptr) {
804 entryPool_->destroy(column_[i]);
805 }
806 column_[i] = other.entryPool_->construct(entry->get_row_index());
807 column_[i]->set_element(entry->get_element());
808 ++i;
809 }
810 insertsSinceLastPrune_ = other.insertsSinceLastPrune_;
811 operators_ = other.operators_;
812 entryPool_ = other.entryPool_;
813
814 return *this;
815}
816
817template <class Master_matrix>
818inline Heap_column<Master_matrix>& Heap_column<Master_matrix>::operator=(Heap_column&& other) noexcept
819{
820 static_assert(!Master_matrix::Option_list::has_row_access, "= assignment not enabled with row access option.");
821
822 // to avoid destroying the column before building from it-self...
823 if (&column_ == &(other.column_)) return *this;
824
825 Dim_opt::operator=(std::move(other));
826 Chain_opt::operator=(std::move(other));
827
828 for (auto* entry : column_) {
829 if (entry != nullptr) entryPool_->destroy(entry);
830 }
831
832 column_ = std::move(other.column_);
833 insertsSinceLastPrune_ = std::exchange(other.insertsSinceLastPrune_, 0);
834 operators_ = std::exchange(other.operators_, nullptr);
835 entryPool_ = std::exchange(other.entryPool_, nullptr);
836
837 return *this;
838}
839
840template <class Master_matrix>
841inline std::size_t Heap_column<Master_matrix>::compute_hash_value()
842{
843 _prune();
844 return hash_column(*this);
845}
846
847template <class Master_matrix>
848inline void Heap_column<Master_matrix>::_prune()
849{
850 if (insertsSinceLastPrune_ == 0) return;
851
852 Column_support tempCol;
853 Entry* pivot = _pop_pivot();
854 while (pivot != nullptr) {
855 tempCol.push_back(pivot);
856 pivot = _pop_pivot();
857 }
858 column_.swap(tempCol);
859
860 insertsSinceLastPrune_ = 0;
861}
862
863template <class Master_matrix>
864inline typename Heap_column<Master_matrix>::Entry* Heap_column<Master_matrix>::_pop_pivot()
865{
866 if (column_.empty()) {
867 return nullptr;
868 }
869
870 Entry* pivot = column_.front();
871 std::pop_heap(column_.begin(), column_.end(), entryPointerComp_);
872 column_.pop_back();
873 if constexpr (Master_matrix::Option_list::is_z2) {
874 while (!column_.empty() && column_.front()->get_row_index() == pivot->get_row_index()) {
875 std::pop_heap(column_.begin(), column_.end(), entryPointerComp_);
876 entryPool_->destroy(column_.back());
877 column_.pop_back();
878
879 entryPool_->destroy(pivot);
880 if (column_.empty()) {
881 return nullptr;
882 }
883 pivot = column_.front();
884 std::pop_heap(column_.begin(), column_.end(), entryPointerComp_);
885 column_.pop_back();
886 }
887 } else {
888 while (!column_.empty() && column_.front()->get_row_index() == pivot->get_row_index()) {
889 operators_->add_inplace(pivot->get_element(), column_.front()->get_element());
890 std::pop_heap(column_.begin(), column_.end(), entryPointerComp_);
891 entryPool_->destroy(column_.back());
892 column_.pop_back();
893 }
894
895 if (pivot->get_element() == Field_operators::get_additive_identity()) {
896 entryPool_->destroy(pivot);
897 return _pop_pivot();
898 }
899 }
900
901 return pivot;
902}
903
904template <class Master_matrix>
905template <class Entry_range>
906inline void Heap_column<Master_matrix>::_add(const Entry_range& column, [[maybe_unused]] Field_element& pivotVal)
907{
908 if (column.begin() == column.end()) return;
909
910 if (column_.empty()) { // chain should never enter here.
911 column_.resize(column.size());
912 Index i = 0;
913 for (const Entry& entry : column) {
914 column_[i] = entryPool_->construct(entry.get_row_index());
915 column_[i]->set_element(entry.get_element());
916 ++i;
917 }
918 insertsSinceLastPrune_ = column_.size();
919 return;
920 }
921
922 for (const Entry& entry : column) {
923 ++insertsSinceLastPrune_;
924
925 if constexpr (Master_matrix::isNonBasic && !Master_matrix::Option_list::is_of_boundary_type) {
926 if (entry.get_row_index() == Chain_opt::_get_pivot()) {
927 _add_coefficient(pivotVal, entry.get_element());
928 }
929 }
930
931 column_.push_back(entryPool_->construct(entry.get_row_index()));
932 column_.back()->set_element(entry.get_element());
933
934 std::push_heap(column_.begin(), column_.end(), entryPointerComp_);
935 }
936
937 if (2 * insertsSinceLastPrune_ > column_.size()) _prune();
938}
939
940template <class Master_matrix>
941template <bool computePivotVal>
942inline std::conditional_t<computePivotVal, typename Heap_column<Master_matrix>::Field_element, void>
943Heap_column<Master_matrix>::_multiply(const Field_element& val)
944{
945 Field_element pivotVal(0);
946
947 if (val == Field_operators::get_additive_identity()) {
948 if constexpr (Master_matrix::isNonBasic && !Master_matrix::Option_list::is_of_boundary_type) {
949 // this would not only mess up the base, but also the pivots stored.
950 throw std::invalid_argument("A chain column should not be multiplied by 0.");
951 } else {
952 clear();
953 if constexpr (computePivotVal)
954 return pivotVal;
955 else
956 return;
957 }
958 }
959
960 if (val == Field_operators::get_multiplicative_identity()) {
961 if constexpr (computePivotVal)
962 return get_pivot_value();
963 else
964 return;
965 }
966
967 // multiply_inplace needs a non-const reference to element, so even if Z2 never reaches here, it won't compile
968 // without the constexpr, as we are not storing a dummy value just for this purpose.
969 if constexpr (!Master_matrix::Option_list::is_z2) {
970 for (Entry* entry : column_) {
971 operators_->multiply_inplace(entry->get_element(), val);
972 if constexpr (computePivotVal) {
973 // computePivotVal is only true for chain columns, so Chain_opt is not a dummy for sure
974 if (entry->get_row_index() == Chain_opt::_get_pivot()) {
975 operators_->add_inplace(pivotVal, entry->get_element());
976 }
977 }
978 }
979 }
980
981 if constexpr (computePivotVal)
982 return pivotVal;
983 else
984 return;
985}
986
987template <class Master_matrix>
988template <class Entry_range>
989inline bool Heap_column<Master_matrix>::_multiply_target_and_add(const Field_element& val, const Entry_range& column)
990{
991 Field_element pivotVal(0);
992
993 if constexpr (Master_matrix::isNonBasic && !Master_matrix::Option_list::is_of_boundary_type) {
994 pivotVal = _multiply<true>(val);
995 } else {
996 _multiply<false>(val);
997 }
998
999 _add(column, pivotVal);
1000
1001 return pivotVal == Field_operators::get_additive_identity();
1002}
1003
1004// TODO: could be factorized with _add
1005template <class Master_matrix>
1006template <class Entry_range>
1007inline bool Heap_column<Master_matrix>::_multiply_source_and_add(const Entry_range& column, const Field_element& val)
1008{
1009 if (val == Field_operators::get_additive_identity() || column.begin() == column.end()) {
1010 return false;
1011 }
1012
1013 if (column_.empty()) { // chain should never enter here.
1014 column_.resize(column.size());
1015 Index i = 0;
1016 for (const Entry& entry : column) {
1017 column_[i] = entryPool_->construct(entry.get_row_index());
1018 column_[i]->set_element(_multiply_coefficient(entry.get_element(), val));
1019 ++i;
1020 }
1021 insertsSinceLastPrune_ = column_.size();
1022 return true;
1023 }
1024
1025 Field_element pivotVal(0);
1026
1027 if constexpr (Master_matrix::isNonBasic && !Master_matrix::Option_list::is_of_boundary_type)
1028 pivotVal = get_pivot_value();
1029
1030 for (const Entry& entry : column) {
1031 ++insertsSinceLastPrune_;
1032
1033 column_.push_back(entryPool_->construct(entry.get_row_index()));
1034 column_.back()->set_element(_multiply_coefficient(entry.get_element(), val));
1035
1036 if constexpr (Master_matrix::isNonBasic && !Master_matrix::Option_list::is_of_boundary_type) {
1037 if (entry.get_row_index() == Chain_opt::_get_pivot()) {
1038 _add_coefficient(pivotVal, column_.back()->get_element());
1039 }
1040 }
1041
1042 std::push_heap(column_.begin(), column_.end(), entryPointerComp_);
1043 }
1044
1045 if (2 * insertsSinceLastPrune_ > column_.size()) _prune();
1046
1047 return pivotVal == Field_operators::get_additive_identity();
1048}
1049
1050template <class Master_matrix>
1051inline void Heap_column<Master_matrix>::_add_coefficient(Field_element& e,
1052 [[maybe_unused]] const Field_element& a) const
1053{
1054 if constexpr (Master_matrix::Option_list::is_z2) {
1055 // a has to be 1
1056 e = !e;
1057 } else {
1058 operators_->add_inplace(e, a);
1059 }
1060}
1061
1062template <class Master_matrix>
1063inline typename Heap_column<Master_matrix>::Field_element Heap_column<Master_matrix>::_multiply_coefficient(
1064 const Field_element& e,
1065 [[maybe_unused]] const Field_element& a) const
1066{
1067 if constexpr (Master_matrix::Option_list::is_z2) {
1068 return e; // a has to be 1
1069 } else {
1070 return operators_->multiply(e, a);
1071 }
1072}
1073
1074} // namespace persistence_matrix
1075} // namespace Gudhi
1076
1085template <class Master_matrix>
1086struct std::hash<Gudhi::persistence_matrix::Heap_column<Master_matrix> > {
1087 size_t operator()(Gudhi::persistence_matrix::Heap_column<Master_matrix>& column) const
1088 {
1089 return column.compute_hash_value();
1090 }
1091};
1092
1093#endif // PM_HEAP_COLUMN_H
Matrix entry class. Stores by default only the row index it belongs to, but can also store its column...
Definition entry_types.h:163
Column class following the PersistenceMatrixColumn concept. Not compatible with row access.
Definition heap_column.h:52
Contains different versions of Gudhi::persistence_matrix::Entry factories.
Persistence matrix namespace.
Definition FieldOperators.h:18
Gudhi namespace.
Definition SimplicialComplexForAlpha.h:14
STL namespace.