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