intrusive_list_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-24 Inria
6 *
7 * Modification(s):
8 * - YYYY/MM Author: Description of the modification
9 */
10
18#ifndef PM_INTRUSIVE_LIST_COLUMN_H
19#define PM_INTRUSIVE_LIST_COLUMN_H
20
21#include <vector>
22#include <stdexcept>
23#include <type_traits>
24#include <utility> //std::swap, std::move & std::exchange
25
26#include <boost/intrusive/list.hpp>
27
30
31namespace Gudhi {
32namespace persistence_matrix {
33
45template <class Master_matrix>
49{
50 public:
51 using Master = Master_matrix;
52 using Index = typename Master_matrix::Index;
53 using ID_index = typename Master_matrix::ID_index;
54 using Dimension = typename Master_matrix::Dimension;
55 using Field_element = typename Master_matrix::Element;
56 using Entry = typename Master_matrix::Matrix_entry;
57 using Column_settings = typename Master_matrix::Column_settings;
58
59 private:
60 using Field_operators = typename Master_matrix::Field_operators;
61 using Column_support =
62 boost::intrusive::list<Entry,
63 boost::intrusive::constant_time_size<false>,
64 boost::intrusive::base_hook<typename Master_matrix::Base_hook_matrix_list_column> >;
65 using Entry_constructor = typename Master_matrix::Entry_constructor;
66
67 public:
68 using iterator = typename Column_support::iterator;
69 using const_iterator = typename Column_support::const_iterator;
70 using reverse_iterator = typename Column_support::reverse_iterator;
71 using const_reverse_iterator = typename Column_support::const_reverse_iterator;
72
73 Intrusive_list_column(Column_settings* colSettings = nullptr);
74 template <class Container = typename Master_matrix::Boundary>
75 Intrusive_list_column(const Container& nonZeroRowIndices, Column_settings* colSettings);
76 template <class Container = typename Master_matrix::Boundary, class Row_container>
77 Intrusive_list_column(Index columnIndex,
78 const Container& nonZeroRowIndices,
79 Row_container* rowContainer,
80 Column_settings* colSettings);
81 template <class Container = typename Master_matrix::Boundary>
82 Intrusive_list_column(const Container& nonZeroChainRowIndices, Dimension dimension, Column_settings* colSettings);
83 template <class Container = typename Master_matrix::Boundary, class Row_container>
84 Intrusive_list_column(Index columnIndex,
85 const Container& nonZeroChainRowIndices,
86 Dimension dimension,
87 Row_container* rowContainer,
88 Column_settings* colSettings);
89 Intrusive_list_column(const Intrusive_list_column& column, Column_settings* colSettings = nullptr);
90 template <class Row_container>
92 Index columnIndex,
93 Row_container* rowContainer,
94 Column_settings* colSettings = nullptr);
97
98 std::vector<Field_element> get_content(int columnLength = -1) const;
99 bool is_non_zero(ID_index rowIndex) const;
100 bool is_empty() const;
101 std::size_t size() const;
102
103 template <class Row_index_map>
104 void reorder(const Row_index_map& valueMap,
105 [[maybe_unused]] Index columnIndex = Master_matrix::template get_null_value<Index>());
106 void clear();
107 void clear(ID_index rowIndex);
108
109 ID_index get_pivot() const;
110 Field_element get_pivot_value() const;
111
112 iterator begin() noexcept;
113 const_iterator begin() const noexcept;
114 iterator end() noexcept;
115 const_iterator end() const noexcept;
116 reverse_iterator rbegin() noexcept;
117 const_reverse_iterator rbegin() const noexcept;
118 reverse_iterator rend() noexcept;
119 const_reverse_iterator rend() const noexcept;
120
121 template <class Entry_range>
122 Intrusive_list_column& operator+=(const Entry_range& column);
123 Intrusive_list_column& operator+=(Intrusive_list_column& column);
124
125 Intrusive_list_column& operator*=(const Field_element& val);
126
127 // this = v * this + column
128 template <class Entry_range>
129 Intrusive_list_column& multiply_target_and_add(const Field_element& val, const Entry_range& column);
130 Intrusive_list_column& multiply_target_and_add(const Field_element& val, Intrusive_list_column& column);
131 // this = this + column * v
132 template <class Entry_range>
133 Intrusive_list_column& multiply_source_and_add(const Entry_range& column, const Field_element& val);
134 Intrusive_list_column& multiply_source_and_add(Intrusive_list_column& column, const Field_element& val);
135
136 void push_back(const Entry& entry);
137
138 friend bool operator==(const Intrusive_list_column& c1, const Intrusive_list_column& c2) {
139 if (&c1 == &c2) return true;
140
141 if constexpr (Master_matrix::Option_list::is_z2) {
142 return c1.column_ == c2.column_;
143 } else {
144 auto it1 = c1.column_.begin();
145 auto it2 = c2.column_.begin();
146 if (c1.column_.size() != c2.column_.size()) return false;
147 while (it1 != c1.column_.end() && it2 != c2.column_.end()) {
148 if (it1->get_row_index() != it2->get_row_index() || it1->get_element() != it2->get_element()) return false;
149 ++it1;
150 ++it2;
151 }
152 return true;
153 }
154 }
155
156 friend bool operator<(const Intrusive_list_column& c1, const Intrusive_list_column& c2) {
157 if (&c1 == &c2) return false;
158
159 if constexpr (Master_matrix::Option_list::is_z2) {
160 return c1.column_ < c2.column_;
161 } else {
162 auto it1 = c1.column_.begin();
163 auto it2 = c2.column_.begin();
164 while (it1 != c1.column_.end() && it2 != c2.column_.end()) {
165 if (it1->get_row_index() != it2->get_row_index()) return it1->get_row_index() < it2->get_row_index();
166 if (it1->get_element() != it2->get_element()) return it1->get_element() < it2->get_element();
167 ++it1;
168 ++it2;
169 }
170 return it2 != c2.column_.end();
171 }
172 }
173
174 // Disabled with row access.
175 Intrusive_list_column& operator=(const Intrusive_list_column& other);
176
177 friend void swap(Intrusive_list_column& col1, Intrusive_list_column& col2) {
178 swap(static_cast<typename Master_matrix::Row_access_option&>(col1),
179 static_cast<typename Master_matrix::Row_access_option&>(col2));
180 swap(static_cast<typename Master_matrix::Column_dimension_option&>(col1),
181 static_cast<typename Master_matrix::Column_dimension_option&>(col2));
182 swap(static_cast<typename Master_matrix::Chain_column_option&>(col1),
183 static_cast<typename Master_matrix::Chain_column_option&>(col2));
184 col1.column_.swap(col2.column_);
185 std::swap(col1.operators_, col2.operators_);
186 std::swap(col1.entryPool_, col2.entryPool_);
187 }
188
189 private:
190 using RA_opt = typename Master_matrix::Row_access_option;
191 using Dim_opt = typename Master_matrix::Column_dimension_option;
192 using Chain_opt = typename Master_matrix::Chain_column_option;
193
194 // Cloner object function for boost intrusive container
195 struct New_cloner {
196 New_cloner(Entry_constructor* entryPool) : entryPool_(entryPool) {};
197
198 Entry* operator()(const Entry& clone_this) { return entryPool_->construct(clone_this); }
199
200 Entry_constructor* entryPool_;
201 };
202
203 // The disposer object function for boost intrusive container
204 struct Delete_disposer {
205 Delete_disposer() {};
206 Delete_disposer(Intrusive_list_column* col) : col_(col) {};
207
208 void operator()(Entry* delete_this) {
209 if constexpr (Master_matrix::Option_list::has_row_access) col_->unlink(delete_this);
210 col_->entryPool_->destroy(delete_this);
211 }
212
214 };
215
216 Field_operators* operators_;
217 Entry_constructor* entryPool_;
218 Column_support column_;
219
220 template <class Column, class Entry_iterator, typename F1, typename F2, typename F3, typename F4>
221 friend void _generic_merge_entry_to_column(Column& targetColumn,
222 Entry_iterator& itSource,
223 typename Column::Column_support::iterator& itTarget,
224 F1&& process_target,
225 F2&& process_source,
226 F3&& update_target1,
227 F4&& update_target2,
228 bool& pivotIsZeroed);
229 template <class Column, class Entry_range, typename F1, typename F2, typename F3, typename F4, typename F5>
230 friend bool _generic_add_to_column(const Entry_range& source,
231 Column& targetColumn,
232 F1&& process_target,
233 F2&& process_source,
234 F3&& update_target1,
235 F4&& update_target2,
236 F5&& finish_target);
237 template <class Column, class Entry_range>
238 friend bool _add_to_column(const Entry_range& source, Column& targetColumn);
239 template <class Column, class Entry_range>
240 friend bool _multiply_target_and_add_to_column(const typename Column::Field_element& val,
241 const Entry_range& source,
242 Column& targetColumn);
243 template <class Column, class Entry_range>
244 friend bool _multiply_source_and_add_to_column(const typename Column::Field_element& val,
245 const Entry_range& source,
246 Column& targetColumn);
247
248 void _delete_entry(iterator& it);
249 Entry* _insert_entry(const Field_element& value, ID_index rowIndex, const iterator& position);
250 void _insert_entry(ID_index rowIndex, const iterator& position);
251 template <class Entry_range>
252 bool _add(const Entry_range& column);
253 template <class Entry_range>
254 bool _multiply_target_and_add(const Field_element& val, const Entry_range& column);
255 template <class Entry_range>
256 bool _multiply_source_and_add(const Entry_range& column, const Field_element& val);
257};
258
259template <class Master_matrix>
260inline Intrusive_list_column<Master_matrix>::Intrusive_list_column(Column_settings* colSettings)
261 : RA_opt(),
262 Dim_opt(),
263 Chain_opt(),
264 operators_(nullptr),
265 entryPool_(colSettings == nullptr ? nullptr : &(colSettings->entryConstructor)),
266 column_()
267{
268 if (colSettings == nullptr) return; // to allow default constructor which gives a dummy column
269 if constexpr (!Master_matrix::Option_list::is_z2) {
270 operators_ = &(colSettings->operators);
271 }
272}
273
274template <class Master_matrix>
275template <class Container>
276inline Intrusive_list_column<Master_matrix>::Intrusive_list_column(const Container& nonZeroRowIndices,
277 Column_settings* colSettings)
278 : RA_opt(),
279 Dim_opt(nonZeroRowIndices.size() == 0 ? 0 : nonZeroRowIndices.size() - 1),
280 Chain_opt(),
281 operators_(nullptr),
282 entryPool_(&(colSettings->entryConstructor)),
283 column_()
284{
285 static_assert(!Master_matrix::isNonBasic || Master_matrix::Option_list::is_of_boundary_type,
286 "Constructor not available for chain columns, please specify the dimension of the chain.");
287
288 if constexpr (Master_matrix::Option_list::is_z2) {
289 for (ID_index id : nonZeroRowIndices) {
290 _insert_entry(id, column_.end());
291 }
292 } else {
293 operators_ = &(colSettings->operators);
294 for (const auto& p : nonZeroRowIndices) {
295 _insert_entry(operators_->get_value(p.second), p.first, column_.end());
296 }
297 }
298}
299
300template <class Master_matrix>
301template <class Container, class Row_container>
302inline Intrusive_list_column<Master_matrix>::Intrusive_list_column(Index columnIndex,
303 const Container& nonZeroRowIndices,
304 Row_container* rowContainer,
305 Column_settings* colSettings)
306 : RA_opt(columnIndex, rowContainer),
307 Dim_opt(nonZeroRowIndices.size() == 0 ? 0 : nonZeroRowIndices.size() - 1),
308 Chain_opt([&] {
309 if constexpr (Master_matrix::Option_list::is_z2) {
310 return nonZeroRowIndices.begin() == nonZeroRowIndices.end()
311 ? Master_matrix::template get_null_value<ID_index>()
312 : *std::prev(nonZeroRowIndices.end());
313 } else {
314 return nonZeroRowIndices.begin() == nonZeroRowIndices.end()
315 ? Master_matrix::template get_null_value<ID_index>()
316 : std::prev(nonZeroRowIndices.end())->first;
317 }
318 }()),
319 operators_(nullptr),
320 entryPool_(&(colSettings->entryConstructor)),
321 column_()
322{
323 static_assert(!Master_matrix::isNonBasic || Master_matrix::Option_list::is_of_boundary_type,
324 "Constructor not available for chain columns, please specify the dimension of the chain.");
325
326 if constexpr (Master_matrix::Option_list::is_z2) {
327 for (ID_index id : nonZeroRowIndices) {
328 _insert_entry(id, column_.end());
329 }
330 } else {
331 operators_ = &(colSettings->operators);
332 for (const auto& p : nonZeroRowIndices) {
333 _insert_entry(operators_->get_value(p.second), p.first, column_.end());
334 }
335 }
336}
337
338template <class Master_matrix>
339template <class Container>
340inline Intrusive_list_column<Master_matrix>::Intrusive_list_column(const Container& nonZeroRowIndices,
341 Dimension dimension,
342 Column_settings* colSettings)
343 : RA_opt(),
344 Dim_opt(dimension),
345 Chain_opt([&] {
346 if constexpr (Master_matrix::Option_list::is_z2) {
347 return nonZeroRowIndices.begin() == nonZeroRowIndices.end()
348 ? Master_matrix::template get_null_value<ID_index>()
349 : *std::prev(nonZeroRowIndices.end());
350 } else {
351 return nonZeroRowIndices.begin() == nonZeroRowIndices.end()
352 ? Master_matrix::template get_null_value<ID_index>()
353 : std::prev(nonZeroRowIndices.end())->first;
354 }
355 }()),
356 operators_(nullptr),
357 entryPool_(&(colSettings->entryConstructor)),
358 column_()
359{
360 if constexpr (Master_matrix::Option_list::is_z2) {
361 for (ID_index id : nonZeroRowIndices) {
362 _insert_entry(id, column_.end());
363 }
364 } else {
365 operators_ = &(colSettings->operators);
366 for (const auto& p : nonZeroRowIndices) {
367 _insert_entry(operators_->get_value(p.second), p.first, column_.end());
368 }
369 }
370}
371
372template <class Master_matrix>
373template <class Container, class Row_container>
374inline Intrusive_list_column<Master_matrix>::Intrusive_list_column(Index columnIndex,
375 const Container& nonZeroRowIndices,
376 Dimension dimension,
377 Row_container* rowContainer,
378 Column_settings* colSettings)
379 : RA_opt(columnIndex, rowContainer),
380 Dim_opt(dimension),
381 Chain_opt([&] {
382 if constexpr (Master_matrix::Option_list::is_z2) {
383 return nonZeroRowIndices.begin() == nonZeroRowIndices.end()
384 ? Master_matrix::template get_null_value<ID_index>()
385 : *std::prev(nonZeroRowIndices.end());
386 } else {
387 return nonZeroRowIndices.begin() == nonZeroRowIndices.end()
388 ? Master_matrix::template get_null_value<ID_index>()
389 : std::prev(nonZeroRowIndices.end())->first;
390 }
391 }()),
392 operators_(nullptr),
393 entryPool_(&(colSettings->entryConstructor)),
394 column_()
395{
396 if constexpr (Master_matrix::Option_list::is_z2) {
397 for (ID_index id : nonZeroRowIndices) {
398 _insert_entry(id, column_.end());
399 }
400 } else {
401 operators_ = &(colSettings->operators);
402 for (const auto& p : nonZeroRowIndices) {
403 _insert_entry(operators_->get_value(p.second), p.first, column_.end());
404 }
405 }
406}
407
408template <class Master_matrix>
409inline Intrusive_list_column<Master_matrix>::Intrusive_list_column(const Intrusive_list_column& column,
410 Column_settings* colSettings)
411 : RA_opt(),
412 Dim_opt(static_cast<const Dim_opt&>(column)),
413 Chain_opt(static_cast<const Chain_opt&>(column)),
414 operators_(colSettings == nullptr ? column.operators_ : nullptr),
415 entryPool_(colSettings == nullptr ? column.entryPool_ : &(colSettings->entryConstructor)),
416 column_()
417{
418 static_assert(!Master_matrix::Option_list::has_row_access,
419 "Simple copy constructor not available when row access option enabled. Please specify the new column "
420 "index and the row container.");
421 if constexpr (!Master_matrix::Option_list::is_z2) {
422 if (colSettings != nullptr) operators_ = &(colSettings->operators);
423 }
424
425 column_.clone_from(column.column_, New_cloner(entryPool_), Delete_disposer(this));
426}
427
428template <class Master_matrix>
429template <class Row_container>
430inline Intrusive_list_column<Master_matrix>::Intrusive_list_column(const Intrusive_list_column& column,
431 Index columnIndex,
432 Row_container* rowContainer,
433 Column_settings* colSettings)
434 : RA_opt(columnIndex, rowContainer),
435 Dim_opt(static_cast<const Dim_opt&>(column)),
436 Chain_opt(static_cast<const Chain_opt&>(column)),
437 operators_(colSettings == nullptr ? column.operators_ : nullptr),
438 entryPool_(colSettings == nullptr ? column.entryPool_ : &(colSettings->entryConstructor)),
439 column_()
440{
441 if constexpr (!Master_matrix::Option_list::is_z2) {
442 if (colSettings != nullptr) operators_ = &(colSettings->operators);
443 }
444
445 for (const Entry& entry : column.column_) {
446 if constexpr (Master_matrix::Option_list::is_z2) {
447 _insert_entry(entry.get_row_index(), column_.end());
448 } else {
449 _insert_entry(entry.get_element(), entry.get_row_index(), column_.end());
450 }
451 }
452}
453
454template <class Master_matrix>
455inline Intrusive_list_column<Master_matrix>::Intrusive_list_column(Intrusive_list_column&& column) noexcept
456 : RA_opt(std::move(static_cast<RA_opt&>(column))),
457 Dim_opt(std::move(static_cast<Dim_opt&>(column))),
458 Chain_opt(std::move(static_cast<Chain_opt&>(column))),
459 operators_(std::exchange(column.operators_, nullptr)),
460 entryPool_(std::exchange(column.entryPool_, nullptr)),
461 column_(std::move(column.column_))
462{}
463
464template <class Master_matrix>
465inline Intrusive_list_column<Master_matrix>::~Intrusive_list_column()
466{
467 column_.clear_and_dispose(Delete_disposer(this));
468}
469
470template <class Master_matrix>
471inline std::vector<typename Intrusive_list_column<Master_matrix>::Field_element>
472Intrusive_list_column<Master_matrix>::get_content(int columnLength) const
473{
474 if (columnLength < 0 && column_.size() > 0)
475 columnLength = column_.back().get_row_index() + 1;
476 else if (columnLength < 0)
477 return std::vector<Field_element>();
478
479 std::vector<Field_element> container(columnLength);
480 for (auto it = column_.begin(); it != column_.end() && it->get_row_index() < static_cast<ID_index>(columnLength);
481 ++it) {
482 if constexpr (Master_matrix::Option_list::is_z2) {
483 container[it->get_row_index()] = 1;
484 } else {
485 container[it->get_row_index()] = it->get_element();
486 }
487 }
488 return container;
489}
490
491template <class Master_matrix>
492inline bool Intrusive_list_column<Master_matrix>::is_non_zero(ID_index rowIndex) const
493{
494 // could be changed to dichotomic search as column is ordered by row index,
495 // but I am not sure if it is really worth it as there is no random access
496 // and the columns should not be that long anyway.
497 for (const Entry& entry : column_)
498 if (entry.get_row_index() == rowIndex) return true;
499
500 return false;
501}
502
503template <class Master_matrix>
504inline bool Intrusive_list_column<Master_matrix>::is_empty() const
505{
506 return column_.empty();
507}
508
509template <class Master_matrix>
510inline std::size_t Intrusive_list_column<Master_matrix>::size() const
511{
512 return column_.size();
513}
514
515template <class Master_matrix>
516template <class Row_index_map>
517inline void Intrusive_list_column<Master_matrix>::reorder(const Row_index_map& valueMap,
518 [[maybe_unused]] Index columnIndex)
519{
520 static_assert(!Master_matrix::isNonBasic || Master_matrix::Option_list::is_of_boundary_type,
521 "Method not available for chain columns.");
522
523 for (auto it = column_.begin(); it != column_.end(); ++it) {
524 Entry* entry = &(*it);
525 if constexpr (Master_matrix::Option_list::has_row_access) {
526 RA_opt::unlink(entry);
527 if (columnIndex != Master_matrix::template get_null_value<Index>()) entry->set_column_index(columnIndex);
528 }
529 entry->set_row_index(valueMap.at(entry->get_row_index()));
530 if constexpr (Master_matrix::Option_list::has_intrusive_rows && Master_matrix::Option_list::has_row_access)
531 RA_opt::insert_entry(entry->get_row_index(), entry);
532 }
533
534 // all entries have to be deleted first, to avoid problem with insertion when row is a set
535 if constexpr (!Master_matrix::Option_list::has_intrusive_rows && Master_matrix::Option_list::has_row_access) {
536 for (auto it = column_.begin(); it != column_.end(); ++it) {
537 Entry* entry = &(*it);
538 RA_opt::insert_entry(entry->get_row_index(), entry);
539 }
540 }
541
542 column_.sort();
543}
544
545template <class Master_matrix>
546inline void Intrusive_list_column<Master_matrix>::clear()
547{
548 static_assert(!Master_matrix::isNonBasic || Master_matrix::Option_list::is_of_boundary_type,
549 "Method not available for chain columns as a base element should not be empty.");
550
551 column_.clear_and_dispose(Delete_disposer(this));
552}
553
554template <class Master_matrix>
555inline void Intrusive_list_column<Master_matrix>::clear(ID_index rowIndex)
556{
557 static_assert(!Master_matrix::isNonBasic || Master_matrix::Option_list::is_of_boundary_type,
558 "Method not available for chain columns.");
559
560 auto it = column_.begin();
561 while (it != column_.end() && it->get_row_index() != rowIndex) it++;
562 if (it != column_.end()) _delete_entry(it);
563}
564
565template <class Master_matrix>
566inline typename Intrusive_list_column<Master_matrix>::ID_index Intrusive_list_column<Master_matrix>::get_pivot() const
567{
568 static_assert(Master_matrix::isNonBasic,
569 "Method not available for base columns."); // could technically be, but is the notion useful then?
570
571 if constexpr (Master_matrix::Option_list::is_of_boundary_type) {
572 if (column_.empty()) return Master_matrix::template get_null_value<ID_index>();
573 return column_.back().get_row_index();
574 } else {
575 return Chain_opt::get_pivot();
576 }
577}
578
579template <class Master_matrix>
580inline typename Intrusive_list_column<Master_matrix>::Field_element
581Intrusive_list_column<Master_matrix>::get_pivot_value() const
582{
583 static_assert(Master_matrix::isNonBasic,
584 "Method not available for base columns."); // could technically be, but is the notion useful then?
585
586 if constexpr (Master_matrix::Option_list::is_z2) {
587 return 1;
588 } else {
589 if constexpr (Master_matrix::Option_list::is_of_boundary_type) {
590 if (column_.empty()) return 0;
591 return column_.back().get_element();
592 } else {
593 if (Chain_opt::get_pivot() == Master_matrix::template get_null_value<ID_index>()) return Field_element();
594 for (const Entry& entry : column_) {
595 if (entry.get_row_index() == Chain_opt::get_pivot()) return entry.get_element();
596 }
597 return Field_element(); // should never happen if chain column is used properly
598 }
599 }
600}
601
602template <class Master_matrix>
603inline typename Intrusive_list_column<Master_matrix>::iterator Intrusive_list_column<Master_matrix>::begin() noexcept
604{
605 return column_.begin();
606}
607
608template <class Master_matrix>
609inline typename Intrusive_list_column<Master_matrix>::const_iterator Intrusive_list_column<Master_matrix>::begin()
610 const noexcept
611{
612 return column_.begin();
613}
614
615template <class Master_matrix>
616inline typename Intrusive_list_column<Master_matrix>::iterator Intrusive_list_column<Master_matrix>::end() noexcept
617{
618 return column_.end();
619}
620
621template <class Master_matrix>
622inline typename Intrusive_list_column<Master_matrix>::const_iterator Intrusive_list_column<Master_matrix>::end()
623 const noexcept
624{
625 return column_.end();
626}
627
628template <class Master_matrix>
629inline typename Intrusive_list_column<Master_matrix>::reverse_iterator
630Intrusive_list_column<Master_matrix>::rbegin() noexcept
631{
632 return column_.rbegin();
633}
634
635template <class Master_matrix>
636inline typename Intrusive_list_column<Master_matrix>::const_reverse_iterator
637Intrusive_list_column<Master_matrix>::rbegin() const noexcept
638{
639 return column_.rbegin();
640}
641
642template <class Master_matrix>
643inline typename Intrusive_list_column<Master_matrix>::reverse_iterator
644Intrusive_list_column<Master_matrix>::rend() noexcept
645{
646 return column_.rend();
647}
648
649template <class Master_matrix>
650inline typename Intrusive_list_column<Master_matrix>::const_reverse_iterator
651Intrusive_list_column<Master_matrix>::rend() const noexcept
652{
653 return column_.rend();
654}
655
656template <class Master_matrix>
657template <class Entry_range>
658inline Intrusive_list_column<Master_matrix>& Intrusive_list_column<Master_matrix>::operator+=(const Entry_range& column)
659{
660 static_assert((!Master_matrix::isNonBasic || std::is_same_v<Entry_range, Intrusive_list_column>),
661 "For boundary columns, the range has to be a column of same type to help ensure the validity of the "
662 "base element."); // could be removed, if we give the responsibility to the user.
663 static_assert((!Master_matrix::isNonBasic || Master_matrix::Option_list::is_of_boundary_type),
664 "For chain columns, the given column cannot be constant.");
665
666 _add(column);
667
668 return *this;
669}
670
671template <class Master_matrix>
672inline Intrusive_list_column<Master_matrix>& Intrusive_list_column<Master_matrix>::operator+=(
673 Intrusive_list_column& column)
674{
675 if constexpr (Master_matrix::isNonBasic && !Master_matrix::Option_list::is_of_boundary_type) {
676 // assumes that the addition never zeros out this column.
677 if (_add(column)) {
678 Chain_opt::swap_pivots(column);
679 Dim_opt::swap_dimension(column);
680 }
681 } else {
682 _add(column);
683 }
684
685 return *this;
686}
687
688template <class Master_matrix>
689inline Intrusive_list_column<Master_matrix>& Intrusive_list_column<Master_matrix>::operator*=(const Field_element& val)
690{
691 if constexpr (Master_matrix::Option_list::is_z2) {
692 if (val % 2 == 0) {
693 if constexpr (Master_matrix::isNonBasic && !Master_matrix::Option_list::is_of_boundary_type) {
694 throw std::invalid_argument("A chain column should not be multiplied by 0.");
695 } else {
696 clear();
697 }
698 }
699 } else {
700 Field_element realVal = operators_->get_value(val);
701
702 if (realVal == Field_operators::get_additive_identity()) {
703 if constexpr (Master_matrix::isNonBasic && !Master_matrix::Option_list::is_of_boundary_type) {
704 throw std::invalid_argument("A chain column should not be multiplied by 0.");
705 } else {
706 clear();
707 }
708 return *this;
709 }
710
711 if (realVal == Field_operators::get_multiplicative_identity()) return *this;
712
713 for (Entry& entry : column_) {
714 operators_->multiply_inplace(entry.get_element(), realVal);
715 if constexpr (Master_matrix::Option_list::has_row_access) RA_opt::update_entry(entry);
716 }
717 }
718
719 return *this;
720}
721
722template <class Master_matrix>
723template <class Entry_range>
724inline Intrusive_list_column<Master_matrix>& Intrusive_list_column<Master_matrix>::multiply_target_and_add(
725 const Field_element& val,
726 const Entry_range& column)
727{
728 static_assert((!Master_matrix::isNonBasic || std::is_same_v<Entry_range, Intrusive_list_column>),
729 "For boundary columns, the range has to be a column of same type to help ensure the validity of the "
730 "base element."); // could be removed, if we give the responsibility to the user.
731 static_assert((!Master_matrix::isNonBasic || Master_matrix::Option_list::is_of_boundary_type),
732 "For chain columns, the given column cannot be constant.");
733
734 if constexpr (Master_matrix::Option_list::is_z2) {
735 if (val) {
736 _add(column);
737 } else {
738 clear();
739 _add(column);
740 }
741 } else {
742 _multiply_target_and_add(val, column);
743 }
744
745 return *this;
746}
747
748template <class Master_matrix>
749inline Intrusive_list_column<Master_matrix>& Intrusive_list_column<Master_matrix>::multiply_target_and_add(
750 const Field_element& val,
751 Intrusive_list_column& column)
752{
753 if constexpr (Master_matrix::isNonBasic && !Master_matrix::Option_list::is_of_boundary_type) {
754 // assumes that the addition never zeros out this column.
755 if constexpr (Master_matrix::Option_list::is_z2) {
756 if (val) {
757 if (_add(column)) {
758 Chain_opt::swap_pivots(column);
759 Dim_opt::swap_dimension(column);
760 }
761 } else {
762 throw std::invalid_argument("A chain column should not be multiplied by 0.");
763 }
764 } else {
765 if (_multiply_target_and_add(val, column)) {
766 Chain_opt::swap_pivots(column);
767 Dim_opt::swap_dimension(column);
768 }
769 }
770 } else {
771 if constexpr (Master_matrix::Option_list::is_z2) {
772 if (val) {
773 _add(column);
774 } else {
775 clear();
776 _add(column);
777 }
778 } else {
779 _multiply_target_and_add(val, column);
780 }
781 }
782
783 return *this;
784}
785
786template <class Master_matrix>
787template <class Entry_range>
788inline Intrusive_list_column<Master_matrix>& Intrusive_list_column<Master_matrix>::multiply_source_and_add(
789 const Entry_range& column,
790 const Field_element& val)
791{
792 static_assert((!Master_matrix::isNonBasic || std::is_same_v<Entry_range, Intrusive_list_column>),
793 "For boundary columns, the range has to be a column of same type to help ensure the validity of the "
794 "base element."); // could be removed, if we give the responsibility to the user.
795 static_assert((!Master_matrix::isNonBasic || Master_matrix::Option_list::is_of_boundary_type),
796 "For chain columns, the given column cannot be constant.");
797
798 if constexpr (Master_matrix::Option_list::is_z2) {
799 if (val) {
800 _add(column);
801 }
802 } else {
803 _multiply_source_and_add(column, val);
804 }
805
806 return *this;
807}
808
809template <class Master_matrix>
810inline Intrusive_list_column<Master_matrix>& Intrusive_list_column<Master_matrix>::multiply_source_and_add(
811 Intrusive_list_column& column,
812 const Field_element& val)
813{
814 if constexpr (Master_matrix::isNonBasic && !Master_matrix::Option_list::is_of_boundary_type) {
815 // assumes that the addition never zeros out this column.
816 if constexpr (Master_matrix::Option_list::is_z2) {
817 if (val) {
818 if (_add(column)) {
819 Chain_opt::swap_pivots(column);
820 Dim_opt::swap_dimension(column);
821 }
822 }
823 } else {
824 if (_multiply_source_and_add(column, val)) {
825 Chain_opt::swap_pivots(column);
826 Dim_opt::swap_dimension(column);
827 }
828 }
829 } else {
830 if constexpr (Master_matrix::Option_list::is_z2) {
831 if (val) {
832 _add(column);
833 }
834 } else {
835 _multiply_source_and_add(column, val);
836 }
837 }
838
839 return *this;
840}
841
842template <class Master_matrix>
843inline void Intrusive_list_column<Master_matrix>::push_back(const Entry& entry)
844{
845 static_assert(Master_matrix::Option_list::is_of_boundary_type, "`push_back` is not available for Chain matrices.");
846
847 GUDHI_CHECK(entry.get_row_index() > get_pivot(), "The new row index has to be higher than the current pivot.");
848
849 if constexpr (Master_matrix::Option_list::is_z2) {
850 _insert_entry(entry.get_row_index(), column_.end());
851 } else {
852 _insert_entry(entry.get_element(), entry.get_row_index(), column_.end());
853 }
854}
855
856template <class Master_matrix>
857inline Intrusive_list_column<Master_matrix>& Intrusive_list_column<Master_matrix>::operator=(
858 const Intrusive_list_column& other)
859{
860 static_assert(!Master_matrix::Option_list::has_row_access, "= assignment not enabled with row access option.");
861
862 Dim_opt::operator=(other);
863 Chain_opt::operator=(other);
864
865 // order is important
866 column_.clear_and_dispose(Delete_disposer(this));
867 operators_ = other.operators_;
868 entryPool_ = other.entryPool_;
869 column_.clone_from(other.column_, New_cloner(entryPool_), Delete_disposer(this));
870
871 return *this;
872}
873
874template <class Master_matrix>
875inline void Intrusive_list_column<Master_matrix>::_delete_entry(iterator& it)
876{
877 it = column_.erase_and_dispose(it, Delete_disposer(this));
878}
879
880template <class Master_matrix>
881inline typename Intrusive_list_column<Master_matrix>::Entry* Intrusive_list_column<Master_matrix>::_insert_entry(
882 const Field_element& value,
883 ID_index rowIndex,
884 const iterator& position)
885{
886 if constexpr (Master_matrix::Option_list::has_row_access) {
887 Entry* newEntry = entryPool_->construct(RA_opt::columnIndex_, rowIndex);
888 newEntry->set_element(value);
889 column_.insert(position, *newEntry);
890 RA_opt::insert_entry(rowIndex, newEntry);
891 return newEntry;
892 } else {
893 Entry* newEntry = entryPool_->construct(rowIndex);
894 newEntry->set_element(value);
895 column_.insert(position, *newEntry);
896 return newEntry;
897 }
898}
899
900template <class Master_matrix>
901inline void Intrusive_list_column<Master_matrix>::_insert_entry(ID_index rowIndex, const iterator& position)
902{
903 if constexpr (Master_matrix::Option_list::has_row_access) {
904 Entry* newEntry = entryPool_->construct(RA_opt::columnIndex_, rowIndex);
905 column_.insert(position, *newEntry);
906 RA_opt::insert_entry(rowIndex, newEntry);
907 } else {
908 Entry* newEntry = entryPool_->construct(rowIndex);
909 column_.insert(position, *newEntry);
910 }
911}
912
913template <class Master_matrix>
914template <class Entry_range>
915inline bool Intrusive_list_column<Master_matrix>::_add(const Entry_range& column)
916{
917 return _add_to_column(column, *this);
918}
919
920template <class Master_matrix>
921template <class Entry_range>
922inline bool Intrusive_list_column<Master_matrix>::_multiply_target_and_add(const Field_element& val,
923 const Entry_range& column)
924{
925 return _multiply_target_and_add_to_column(val, column, *this);
926}
927
928template <class Master_matrix>
929template <class Entry_range>
930inline bool Intrusive_list_column<Master_matrix>::_multiply_source_and_add(const Entry_range& column,
931 const Field_element& val)
932{
933 return _multiply_source_and_add_to_column(val, column, *this);
934}
935
936} // namespace persistence_matrix
937} // namespace Gudhi
938
947template <class Master_matrix>
948struct std::hash<Gudhi::persistence_matrix::Intrusive_list_column<Master_matrix> > {
949 std::size_t operator()(const Gudhi::persistence_matrix::Intrusive_list_column<Master_matrix>& column) const {
950 return Gudhi::persistence_matrix::hash_column(column);
951 }
952};
953
954#endif // PM_INTRUSIVE_LIST_COLUMN_H
Column class following the PersistenceMatrixColumn concept.
Definition: intrusive_list_column.h:49
Contains helper methods for column addition and column hasher.
Contains different versions of Gudhi::persistence_matrix::Entry factories.
Chain_column_extra_properties Chain_column_option
If PersistenceMatrixOptions::is_of_boundary_type is false, and, PersistenceMatrixOptions::has_column_...
Definition: PersistenceMatrixColumn.h:45
Row_access Row_access_option
If PersistenceMatrixOptions::has_row_access is true, then Row_access. Otherwise Dummy_row_access....
Definition: PersistenceMatrixColumn.h:28
Column_dimension_holder Column_dimension_option
If PersistenceMatrixOptions::has_column_pairings or PersistenceMatrixOptions::has_vine_update or Pers...
Definition: PersistenceMatrixColumn.h:36
Gudhi namespace.
Definition: SimplicialComplexForAlpha.h:14
STL namespace.