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