18#ifndef PM_VECTOR_COLUMN_H
19#define PM_VECTOR_COLUMN_H
26#include <unordered_set>
29#include <boost/range/iterator_range_core.hpp>
30#include <boost/iterator/indirect_iterator.hpp>
50template <
class Master_matrix>
51class Vector_column :
public Master_matrix::Row_access_option,
52 public Master_matrix::Column_dimension_option,
53 public Master_matrix::Chain_column_option
56 using Master = Master_matrix;
57 using Index =
typename Master_matrix::Index;
58 using ID_index =
typename Master_matrix::ID_index;
59 using Dimension =
typename Master_matrix::Dimension;
60 using Field_element =
typename Master_matrix::Element;
61 using Entry =
typename Master_matrix::Matrix_entry;
62 using Column_settings =
typename Master_matrix::Column_settings;
65 using Field_operators =
typename Master_matrix::Field_operators;
66 using Column_support = std::vector<Entry*>;
67 using Entry_constructor =
typename Master_matrix::Entry_constructor;
69 class Non_zero_element_iterator
70 :
public boost::iterator_facade<Non_zero_element_iterator, const Entry, boost::forward_traversal_tag>
73 Non_zero_element_iterator(std::size_t curr,
74 Column_support
const* column,
75 std::unordered_set<ID_index>
const* erasedValues)
76 : curr_(curr), column_(column), erasedValues_(erasedValues)
79 Non_zero_element_iterator(Column_support
const* column)
80 : curr_(column->size()), column_(column), erasedValues_(
nullptr)
84 friend class boost::iterator_core_access;
86 bool equal(Non_zero_element_iterator
const& other)
const
88 return curr_ == other.curr_ && column_ == other.column_;
91 const Entry& dereference()
const {
return *(*column_)[curr_]; }
96 while (curr_ < column_->size() &&
97 erasedValues_->find((*column_)[curr_]->get_row_index()) != erasedValues_->end()) {
103 Column_support
const* column_;
104 std::unordered_set<ID_index>
const* erasedValues_;
108 using iterator = boost::indirect_iterator<typename Column_support::iterator>;
109 using const_iterator = boost::indirect_iterator<typename Column_support::const_iterator>;
110 using reverse_iterator = boost::indirect_iterator<typename Column_support::reverse_iterator>;
111 using const_reverse_iterator = boost::indirect_iterator<typename Column_support::const_reverse_iterator>;
112 using Content_range = boost::iterator_range<Non_zero_element_iterator>;
114 Vector_column(Column_settings* colSettings =
nullptr);
115 template <
class Container =
typename Master_matrix::Boundary>
116 Vector_column(
const Container& nonZeroRowIndices, Column_settings* colSettings);
117 template <
class Container =
typename Master_matrix::Boundary,
class Row_container>
118 Vector_column(Index columnIndex,
119 const Container& nonZeroRowIndices,
120 Row_container* rowContainer,
121 Column_settings* colSettings);
122 template <
class Container =
typename Master_matrix::Boundary,
123 class = std::enable_if_t<!std::is_arithmetic_v<Container> > >
124 Vector_column(
const Container& nonZeroRowIndices, Dimension dimension, Column_settings* colSettings);
125 template <
class Container =
typename Master_matrix::Boundary,
127 class = std::enable_if_t<!std::is_arithmetic_v<Container> > >
128 Vector_column(Index columnIndex,
129 const Container& nonZeroRowIndices,
131 Row_container* rowContainer,
132 Column_settings* colSettings);
133 Vector_column(ID_index idx, Dimension dimension, Column_settings* colSettings);
134 Vector_column(ID_index idx, Field_element e, Dimension dimension, Column_settings* colSettings);
135 template <
class Row_container>
136 Vector_column(Index columnIndex,
139 Row_container* rowContainer,
140 Column_settings* colSettings);
141 template <
class Row_container>
142 Vector_column(Index columnIndex,
146 Row_container* rowContainer,
147 Column_settings* colSettings);
148 Vector_column(
const Vector_column& column, Column_settings* colSettings =
nullptr);
149 template <
class Row_container>
150 Vector_column(
const Vector_column& column,
152 Row_container* rowContainer,
153 Column_settings* colSettings =
nullptr);
154 Vector_column(Vector_column&& column)
noexcept;
157 std::vector<Field_element> get_content(
int columnLength = -1)
const;
158 bool is_non_zero(ID_index rowIndex)
const;
159 [[nodiscard]]
bool is_empty()
const;
160 [[nodiscard]] std::size_t size()
const;
162 template <
class Row_index_map>
163 void reorder(
const Row_index_map& valueMap,
164 [[maybe_unused]] Index columnIndex = Master_matrix::template get_null_value<Index>());
167 void clear(ID_index rowIndex);
169 ID_index get_pivot();
170 Field_element get_pivot_value();
172 iterator begin()
noexcept;
173 const_iterator begin()
const noexcept;
174 iterator end()
noexcept;
175 const_iterator end()
const noexcept;
176 reverse_iterator rbegin()
noexcept;
177 const_reverse_iterator rbegin()
const noexcept;
178 reverse_iterator rend()
noexcept;
179 const_reverse_iterator rend()
const noexcept;
181 Content_range get_non_zero_content_range()
const;
183 template <
class Entry_range>
184 Vector_column& operator+=(
const Entry_range& column);
185 Vector_column& operator+=(Vector_column& column);
187 Vector_column& operator*=(
const Field_element& v);
190 template <
class Entry_range>
191 Vector_column& multiply_target_and_add(
const Field_element& val,
const Entry_range& column);
192 Vector_column& multiply_target_and_add(
const Field_element& val, Vector_column& column);
194 template <
class Entry_range>
195 Vector_column& multiply_source_and_add(
const Entry_range& column,
const Field_element& val);
196 Vector_column& multiply_source_and_add(Vector_column& column,
const Field_element& val);
198 void push_back(
const Entry& entry);
200 std::size_t compute_hash_value();
202 friend bool operator==(
const Vector_column& c1,
const Vector_column& c2)
204 if (&c1 == &c2)
return true;
205 if (c1.erasedValues_.empty() && c2.erasedValues_.empty() && c1.column_.size() != c2.column_.size())
return false;
207 auto r1 = c1.get_non_zero_content_range();
208 auto r2 = c2.get_non_zero_content_range();
209 return std::equal(r1.begin(), r1.end(), r2.begin(), r2.end(), [](
const Entry& e1,
const Entry& e2) {
210 return e1.get_row_index() == e2.get_row_index() && e1.get_element() == e2.get_element();
214 friend bool operator<(
const Vector_column& c1,
const Vector_column& c2)
216 if (&c1 == &c2)
return false;
218 auto r1 = c1.get_non_zero_content_range();
219 auto r2 = c2.get_non_zero_content_range();
220 return std::lexicographical_compare(
221 r1.begin(), r1.end(), r2.begin(), r2.end(), [](
const Entry& e1,
const Entry& e2) {
222 if (e1.get_row_index() != e2.get_row_index()) return e1.get_row_index() < e2.get_row_index();
223 if (e1.get_element() != e2.get_element()) return e1.get_element() < e2.get_element();
229 Vector_column& operator=(
const Vector_column& other);
230 Vector_column& operator=(Vector_column&& other)
noexcept;
232 friend void swap(Vector_column& col1, Vector_column& col2)
noexcept
234 swap(
static_cast<typename Master_matrix::Row_access_option&
>(col1),
235 static_cast<typename Master_matrix::Row_access_option&
>(col2));
236 swap(
static_cast<typename Master_matrix::Column_dimension_option&
>(col1),
237 static_cast<typename Master_matrix::Column_dimension_option&
>(col2));
238 swap(
static_cast<typename Master_matrix::Chain_column_option&
>(col1),
239 static_cast<typename Master_matrix::Chain_column_option&
>(col2));
240 col1.column_.swap(col2.column_);
241 col1.erasedValues_.swap(col2.erasedValues_);
242 std::swap(col1.operators_, col2.operators_);
243 std::swap(col1.entryPool_, col2.entryPool_);
247 using RA_opt =
typename Master_matrix::Row_access_option;
248 using Dim_opt =
typename Master_matrix::Column_dimension_option;
249 using Chain_opt =
typename Master_matrix::Chain_column_option;
251 Column_support column_;
253 std::unordered_set<ID_index> erasedValues_;
254 Field_operators
const* operators_;
255 Entry_constructor* entryPool_;
257 template <
class Column,
class Entry_iterator,
typename F1,
typename F2,
typename F3,
typename F4>
258 friend void _generic_merge_entry_to_column(Column& targetColumn,
259 Entry_iterator& itSource,
260 typename Column::Column_support::iterator& itTarget,
265 bool& pivotIsZeroed);
267 void _delete_entry(Entry* entry);
268 void _delete_entry(
typename Column_support::iterator& it);
269 Entry* _insert_entry(Column_support& column, ID_index rowIndex,
const Field_element& value);
270 void _update_entry(Index position, ID_index rowIndex,
const Field_element& value);
271 template <
class Entry_range>
272 bool _add(
const Entry_range& column);
273 template <
class Entry_range>
274 bool _multiply_target_and_add(
const Field_element& val,
const Entry_range& column);
275 template <
class Entry_range>
276 bool _multiply_source_and_add(
const Entry_range& column,
const Field_element& val);
277 template <
class Entry_range,
typename F1,
typename F2,
typename F3,
typename F4>
278 bool _generic_add(
const Entry_range& column,
282 F4&& update_target2);
283 bool _is_lazy_erased(
const typename Column_support::const_iterator& it)
const;
284 bool _is_lazy_erased(ID_index rowIndex)
const;
287template <
class Master_matrix>
288inline Vector_column<Master_matrix>::Vector_column(Column_settings* colSettings)
292 operators_(Master_matrix::get_operator_ptr(colSettings)),
293 entryPool_(colSettings == nullptr ? nullptr : &(colSettings->entryConstructor))
296template <
class Master_matrix>
297template <
class Container>
298inline Vector_column<Master_matrix>::Vector_column(
const Container& nonZeroRowIndices, Column_settings* colSettings)
299 : Vector_column(nonZeroRowIndices, nonZeroRowIndices.size() == 0 ? 0 : nonZeroRowIndices.size() - 1, colSettings)
301 static_assert(!Master_matrix::isNonBasic || Master_matrix::Option_list::is_of_boundary_type,
302 "Constructor not available for chain columns, please specify the dimension of the chain.");
305template <
class Master_matrix>
306template <
class Container,
class Row_container>
307inline Vector_column<Master_matrix>::Vector_column(Index columnIndex,
308 const Container& nonZeroRowIndices,
309 Row_container* rowContainer,
310 Column_settings* colSettings)
311 : Vector_column(columnIndex,
313 nonZeroRowIndices.size() == 0 ? 0 : nonZeroRowIndices.size() - 1,
317 static_assert(!Master_matrix::isNonBasic || Master_matrix::Option_list::is_of_boundary_type,
318 "Constructor not available for chain columns, please specify the dimension of the chain.");
321template <
class Master_matrix>
322template <
class Container,
class>
323inline Vector_column<Master_matrix>::Vector_column(
const Container& nonZeroRowIndices,
325 Column_settings* colSettings)
328 Chain_opt(nonZeroRowIndices.begin() == nonZeroRowIndices.end()
329 ? Master_matrix::template get_null_value<ID_index>()
330 : Master_matrix::get_row_index(*std::prev(nonZeroRowIndices.end()))),
331 column_(nonZeroRowIndices.size(), nullptr),
332 operators_(Master_matrix::get_operator_ptr(colSettings)),
333 entryPool_(&(colSettings->entryConstructor))
336 for (
const auto&
id : nonZeroRowIndices) {
338 Master_matrix::get_row_index(
id),
339 Master_matrix::get_coefficient_value(Master_matrix::get_element(
id), operators_));
343template <
class Master_matrix>
344template <
class Container,
class Row_container,
class>
345inline Vector_column<Master_matrix>::Vector_column(Index columnIndex,
346 const Container& nonZeroRowIndices,
348 Row_container* rowContainer,
349 Column_settings* colSettings)
350 : RA_opt(columnIndex, rowContainer),
352 Chain_opt(nonZeroRowIndices.begin() == nonZeroRowIndices.end()
353 ? Master_matrix::template get_null_value<ID_index>()
354 : Master_matrix::get_row_index(*std::prev(nonZeroRowIndices.end()))),
355 column_(nonZeroRowIndices.size(), nullptr),
356 operators_(Master_matrix::get_operator_ptr(colSettings)),
357 entryPool_(&(colSettings->entryConstructor))
360 for (
const auto&
id : nonZeroRowIndices) {
362 Master_matrix::get_row_index(
id),
363 Master_matrix::get_coefficient_value(Master_matrix::get_element(
id), operators_));
367template <
class Master_matrix>
368inline Vector_column<Master_matrix>::Vector_column(ID_index idx, Dimension dimension, Column_settings* colSettings)
374 entryPool_(&(colSettings->entryConstructor))
376 static_assert(Master_matrix::Option_list::is_z2,
377 "Constructor not available for Zp != Z2. Please specify the coefficient.");
378 _update_entry(0, idx, 1);
381template <
class Master_matrix>
382inline Vector_column<Master_matrix>::Vector_column(ID_index idx,
385 Column_settings* colSettings)
390 operators_(&(colSettings->operators)),
391 entryPool_(&(colSettings->entryConstructor))
393 static_assert(!Master_matrix::Option_list::is_z2,
394 "Constructor not available for Zp == Z2. Please do not specify any coefficient.");
395 _update_entry(0, idx, operators_->get_value(e));
398template <
class Master_matrix>
399template <
class Row_container>
400inline Vector_column<Master_matrix>::Vector_column(Index columnIndex,
403 Row_container* rowContainer,
404 Column_settings* colSettings)
405 : RA_opt(columnIndex, rowContainer),
410 entryPool_(&(colSettings->entryConstructor))
412 static_assert(Master_matrix::Option_list::is_z2,
413 "Constructor not available for Zp != Z2. Please specify the coefficient.");
414 _update_entry(0, idx, 1);
417template <
class Master_matrix>
418template <
class Row_container>
419inline Vector_column<Master_matrix>::Vector_column(Index columnIndex,
423 Row_container* rowContainer,
424 Column_settings* colSettings)
425 : RA_opt(columnIndex, rowContainer),
429 operators_(&(colSettings->operators)),
430 entryPool_(&(colSettings->entryConstructor))
432 static_assert(!Master_matrix::Option_list::is_z2,
433 "Constructor not available for Zp == Z2. Please do not specify any coefficient.");
434 _update_entry(0, idx, operators_->get_value(e));
437template <
class Master_matrix>
438inline Vector_column<Master_matrix>::Vector_column(
const Vector_column& column, Column_settings* colSettings)
440 Dim_opt(static_cast<const Dim_opt&>(column)),
441 Chain_opt(static_cast<const Chain_opt&>(column)),
442 column_(column.column_.size(), nullptr),
443 erasedValues_(column.erasedValues_),
444 operators_(colSettings == nullptr ? column.operators_ : Master_matrix::get_operator_ptr(colSettings)),
445 entryPool_(colSettings == nullptr ? column.entryPool_ : &(colSettings->entryConstructor))
447 static_assert(!Master_matrix::Option_list::has_row_access,
448 "Simple copy constructor not available when row access option enabled. Please specify the new column "
449 "index and the row container.");
452 for (
const Entry* entry : column.column_) {
453 _update_entry(i++, entry->get_row_index(), entry->get_element());
457template <
class Master_matrix>
458template <
class Row_container>
459inline Vector_column<Master_matrix>::Vector_column(
const Vector_column& column,
461 Row_container* rowContainer,
462 Column_settings* colSettings)
463 : RA_opt(columnIndex, rowContainer),
464 Dim_opt(static_cast<const Dim_opt&>(column)),
465 Chain_opt(static_cast<const Chain_opt&>(column)),
466 column_(column.column_.size(), nullptr),
467 erasedValues_(column.erasedValues_),
468 operators_(colSettings == nullptr ? column.operators_ : Master_matrix::get_operator_ptr(colSettings)),
469 entryPool_(colSettings == nullptr ? column.entryPool_ : &(colSettings->entryConstructor))
472 for (
const Entry* entry : column.column_) {
473 _update_entry(i++, entry->get_row_index(), entry->get_element());
477template <
class Master_matrix>
478inline Vector_column<Master_matrix>::Vector_column(
Vector_column&& column) noexcept
479 : RA_opt(std::move(
static_cast<RA_opt&
>(column))),
480 Dim_opt(std::move(
static_cast<Dim_opt&
>(column))),
481 Chain_opt(std::move(
static_cast<Chain_opt&
>(column))),
482 column_(std::move(column.column_)),
483 erasedValues_(std::move(column.erasedValues_)),
484 operators_(std::exchange(column.operators_,
nullptr)),
485 entryPool_(std::exchange(column.entryPool_,
nullptr))
488template <
class Master_matrix>
489inline Vector_column<Master_matrix>::~Vector_column()
491 for (
auto* entry : column_) {
492 _delete_entry(entry);
496template <
class Master_matrix>
497inline std::vector<typename Vector_column<Master_matrix>::Field_element> Vector_column<Master_matrix>::get_content(
498 int columnLength)
const
500 if (columnLength < 0 && column_.size() > 0)
501 columnLength = column_.back()->get_row_index() + 1;
502 else if (columnLength < 0)
503 return std::vector<Field_element>();
505 std::vector<Field_element> container(columnLength, 0);
506 auto r = get_non_zero_content_range();
507 for (
auto it = r.begin(); it != r.end() && it->get_row_index() <
static_cast<ID_index
>(columnLength); ++it) {
508 container[it->get_row_index()] = Master_matrix::get_element(*it);
513template <
class Master_matrix>
514inline bool Vector_column<Master_matrix>::is_non_zero(ID_index rowIndex)
const
516 if (_is_lazy_erased(rowIndex))
return false;
518 Entry entry(rowIndex);
519 return std::binary_search(column_.begin(), column_.end(), &entry, [](
const Entry* a,
const Entry* b) {
520 return a->get_row_index() < b->get_row_index();
524template <
class Master_matrix>
525inline bool Vector_column<Master_matrix>::is_empty()
const
527 if constexpr (!Master_matrix::isNonBasic || Master_matrix::Option_list::is_of_boundary_type) {
528 return column_.size() == erasedValues_.size();
531 return column_.empty();
535template <
class Master_matrix>
536inline std::size_t Vector_column<Master_matrix>::size()
const
538 if constexpr (!Master_matrix::isNonBasic || Master_matrix::Option_list::is_of_boundary_type) {
539 return column_.size() - erasedValues_.size();
542 return column_.size();
546template <
class Master_matrix>
547template <
class Row_index_map>
548inline void Vector_column<Master_matrix>::reorder(
const Row_index_map& valueMap, [[maybe_unused]] Index columnIndex)
550 static_assert(!Master_matrix::isNonBasic || Master_matrix::Option_list::is_of_boundary_type,
551 "Method not available for chain columns.");
553 if (erasedValues_.empty()) {
554 for (
Entry* entry : column_) {
555 if constexpr (Master_matrix::Option_list::has_row_access) {
556 RA_opt::unlink(entry);
557 if (columnIndex != Master_matrix::template get_null_value<Index>()) entry->set_column_index(columnIndex);
559 entry->set_row_index(valueMap.at(entry->get_row_index()));
560 if constexpr (Master_matrix::Option_list::has_intrusive_rows && Master_matrix::Option_list::has_row_access)
561 RA_opt::insert_entry(entry->get_row_index(), entry);
565 if constexpr (!Master_matrix::Option_list::has_intrusive_rows && Master_matrix::Option_list::has_row_access) {
566 for (
Entry* entry : column_) {
567 RA_opt::insert_entry(entry->get_row_index(), entry);
571 std::sort(column_.begin(), column_.end(), [](
const Entry* c1,
const Entry* c2) { return *c1 < *c2; });
573 Column_support newColumn;
574 for (
Entry* entry : column_) {
575 if (!_is_lazy_erased(entry->get_row_index())) {
576 if constexpr (Master_matrix::Option_list::has_row_access) {
577 RA_opt::unlink(entry);
578 if (columnIndex != Master_matrix::template get_null_value<Index>()) entry->set_column_index(columnIndex);
580 entry->set_row_index(valueMap.at(entry->get_row_index()));
581 newColumn.push_back(entry);
582 if constexpr (Master_matrix::Option_list::has_intrusive_rows && Master_matrix::Option_list::has_row_access)
583 RA_opt::insert_entry(entry->get_row_index(), entry);
585 _delete_entry(entry);
589 if constexpr (!Master_matrix::Option_list::has_intrusive_rows && Master_matrix::Option_list::has_row_access) {
590 for (
Entry* entry : column_) {
591 RA_opt::insert_entry(entry->get_row_index(), entry);
594 std::sort(newColumn.begin(), newColumn.end(), [](
const Entry* c1,
const Entry* c2) { return *c1 < *c2; });
595 erasedValues_.clear();
596 column_.swap(newColumn);
600template <
class Master_matrix>
601inline void Vector_column<Master_matrix>::clear()
603 static_assert(!Master_matrix::isNonBasic || Master_matrix::Option_list::is_of_boundary_type,
604 "Method not available for chain columns as a base element should not be empty.");
606 for (
auto* entry : column_) {
607 if constexpr (Master_matrix::Option_list::has_row_access) RA_opt::unlink(entry);
608 entryPool_->destroy(entry);
612 erasedValues_.clear();
615template <
class Master_matrix>
616inline void Vector_column<Master_matrix>::clear(ID_index rowIndex)
618 static_assert(!Master_matrix::isNonBasic || Master_matrix::Option_list::is_of_boundary_type,
619 "Method not available for chain columns.");
621 erasedValues_.insert(rowIndex);
624template <
class Master_matrix>
625inline typename Vector_column<Master_matrix>::ID_index Vector_column<Master_matrix>::get_pivot()
627 static_assert(Master_matrix::isNonBasic,
628 "Method not available for base columns.");
630 if constexpr (Master_matrix::Option_list::is_of_boundary_type) {
631 if (column_.empty())
return Master_matrix::template get_null_value<ID_index>();
632 if (erasedValues_.empty())
return column_.back()->get_row_index();
634 auto it = erasedValues_.find(column_.back()->get_row_index());
635 while (!column_.empty() && it != erasedValues_.end()) {
636 erasedValues_.erase(it);
637 _delete_entry(column_.back());
639 if (!column_.empty()) it = erasedValues_.find(column_.back()->get_row_index());
642 if (column_.empty())
return Master_matrix::template get_null_value<ID_index>();
643 return column_.back()->get_row_index();
645 return Chain_opt::_get_pivot();
649template <
class Master_matrix>
650inline typename Vector_column<Master_matrix>::Field_element Vector_column<Master_matrix>::get_pivot_value()
652 static_assert(Master_matrix::isNonBasic,
653 "Method not available for base columns.");
655 if constexpr (Master_matrix::Option_list::is_z2) {
658 if constexpr (Master_matrix::Option_list::is_of_boundary_type) {
659 if (column_.empty())
return 0;
660 if (erasedValues_.empty())
return column_.back()->get_element();
662 auto it = erasedValues_.find(column_.back()->get_row_index());
663 while (!column_.empty() && it != erasedValues_.end()) {
664 erasedValues_.erase(it);
665 _delete_entry(column_.back());
667 if (!column_.empty()) it = erasedValues_.find(column_.back()->get_row_index());
670 if (column_.empty())
return 0;
671 return column_.back()->get_element();
673 if (Chain_opt::_get_pivot() == Master_matrix::template get_null_value<ID_index>())
return Field_element();
674 for (
const Entry* entry : column_) {
675 if (entry->get_row_index() == Chain_opt::_get_pivot())
return entry->get_element();
677 return Field_element();
682template <
class Master_matrix>
683inline typename Vector_column<Master_matrix>::iterator Vector_column<Master_matrix>::begin() noexcept
685 return column_.begin();
688template <
class Master_matrix>
689inline typename Vector_column<Master_matrix>::const_iterator Vector_column<Master_matrix>::begin() const noexcept
691 return column_.begin();
694template <
class Master_matrix>
695inline typename Vector_column<Master_matrix>::iterator Vector_column<Master_matrix>::end() noexcept
697 return column_.end();
700template <
class Master_matrix>
701inline typename Vector_column<Master_matrix>::const_iterator Vector_column<Master_matrix>::end() const noexcept
703 return column_.end();
706template <
class Master_matrix>
707inline typename Vector_column<Master_matrix>::reverse_iterator Vector_column<Master_matrix>::rbegin() noexcept
709 return column_.rbegin();
712template <
class Master_matrix>
713inline typename Vector_column<Master_matrix>::const_reverse_iterator Vector_column<Master_matrix>::rbegin()
716 return column_.rbegin();
719template <
class Master_matrix>
720inline typename Vector_column<Master_matrix>::reverse_iterator Vector_column<Master_matrix>::rend() noexcept
722 return column_.rend();
725template <
class Master_matrix>
726inline typename Vector_column<Master_matrix>::const_reverse_iterator Vector_column<Master_matrix>::rend() const noexcept
728 return column_.rend();
731template <
class Master_matrix>
732inline typename Vector_column<Master_matrix>::Content_range Vector_column<Master_matrix>::get_non_zero_content_range()
735 return Content_range(Non_zero_element_iterator(0, &column_, &erasedValues_), Non_zero_element_iterator(&column_));
738template <
class Master_matrix>
739template <
class Entry_range>
742 static_assert((!Master_matrix::isNonBasic || std::is_same_v<Entry_range, Vector_column>),
743 "For boundary columns, the range has to be a column of same type to help ensure the validity of the "
745 static_assert((!Master_matrix::isNonBasic || Master_matrix::Option_list::is_of_boundary_type),
746 "For chain columns, the given column cannot be constant.");
753template <
class Master_matrix>
756 if constexpr (Master_matrix::isNonBasic && !Master_matrix::Option_list::is_of_boundary_type) {
759 Chain_opt::_swap_pivots(column);
760 Dim_opt::_swap_dimension(column);
769template <
class Master_matrix>
772 Field_element val = Master_matrix::get_coefficient_value(v, operators_);
774 if (val == Field_operators::get_additive_identity()) {
775 if constexpr (Master_matrix::isNonBasic && !Master_matrix::Option_list::is_of_boundary_type) {
776 throw std::invalid_argument(
"A chain column should not be multiplied by 0.");
783 if (val == Field_operators::get_multiplicative_identity())
return *
this;
787 if constexpr (!Master_matrix::Option_list::is_z2) {
788 for (
Entry* entry : column_) {
789 operators_->multiply_inplace(entry->get_element(), val);
790 if constexpr (Master_matrix::Option_list::has_row_access) RA_opt::update_entry(*entry);
797template <
class Master_matrix>
798template <
class Entry_range>
800 const Entry_range& column)
802 static_assert((!Master_matrix::isNonBasic || std::is_same_v<Entry_range, Vector_column>),
803 "For boundary columns, the range has to be a column of same type to help ensure the validity of the "
805 static_assert((!Master_matrix::isNonBasic || Master_matrix::Option_list::is_of_boundary_type),
806 "For chain columns, the given column cannot be constant.");
808 _multiply_target_and_add(Master_matrix::get_coefficient_value(val, operators_), column);
813template <
class Master_matrix>
817 if constexpr (Master_matrix::isNonBasic && !Master_matrix::Option_list::is_of_boundary_type) {
819 if (_multiply_target_and_add(Master_matrix::get_coefficient_value(val, operators_), column)) {
820 Chain_opt::_swap_pivots(column);
821 Dim_opt::_swap_dimension(column);
824 _multiply_target_and_add(Master_matrix::get_coefficient_value(val, operators_), column);
830template <
class Master_matrix>
831template <
class Entry_range>
833 const Field_element& val)
835 static_assert((!Master_matrix::isNonBasic || std::is_same_v<Entry_range, Vector_column>),
836 "For boundary columns, the range has to be a column of same type to help ensure the validity of the "
838 static_assert((!Master_matrix::isNonBasic || Master_matrix::Option_list::is_of_boundary_type),
839 "For chain columns, the given column cannot be constant.");
841 _multiply_source_and_add(column, Master_matrix::get_coefficient_value(val, operators_));
846template <
class Master_matrix>
848 const Field_element& val)
850 if constexpr (Master_matrix::isNonBasic && !Master_matrix::Option_list::is_of_boundary_type) {
852 if (_multiply_source_and_add(column, Master_matrix::get_coefficient_value(val, operators_))) {
853 Chain_opt::_swap_pivots(column);
854 Dim_opt::_swap_dimension(column);
857 _multiply_source_and_add(column, Master_matrix::get_coefficient_value(val, operators_));
863template <
class Master_matrix>
864inline void Vector_column<Master_matrix>::push_back(
const Entry& entry)
866 static_assert(Master_matrix::Option_list::is_of_boundary_type,
"`push_back` is not available for Chain matrices.");
868 GUDHI_CHECK(entry.get_row_index() > get_pivot(),
869 std::invalid_argument(
"The new row index has to be higher than the current pivot."));
871 _insert_entry(column_, entry.get_row_index(), entry.get_element());
874template <
class Master_matrix>
877 static_assert(!Master_matrix::Option_list::has_row_access,
"= assignment not enabled with row access option.");
880 if (
this == &other)
return *
this;
882 Dim_opt::operator=(other);
883 Chain_opt::operator=(other);
885 auto tmpPool = entryPool_;
886 entryPool_ = other.entryPool_;
888 while (column_.size() > other.column_.size()) {
889 if (column_.back() !=
nullptr) {
890 if constexpr (Master_matrix::Option_list::has_row_access) RA_opt::unlink(column_.back());
891 tmpPool->destroy(column_.back());
896 column_.resize(other.column_.size(),
nullptr);
898 for (
const Entry* entry : other.column_) {
899 if (column_[i] !=
nullptr) {
900 if constexpr (Master_matrix::Option_list::has_row_access) RA_opt::unlink(column_[i]);
901 tmpPool->destroy(column_[i]);
903 _update_entry(i++, entry->get_row_index(), entry->get_element());
905 erasedValues_ = other.erasedValues_;
906 operators_ = other.operators_;
911template <
class Master_matrix>
914 static_assert(!Master_matrix::Option_list::has_row_access,
"= assignment not enabled with row access option.");
917 if (&column_ == &(other.column_))
return *
this;
919 Dim_opt::operator=(std::move(other));
920 Chain_opt::operator=(std::move(other));
922 for (
auto* entry : column_) {
923 if (entry !=
nullptr) _delete_entry(entry);
926 column_ = std::move(other.column_);
927 erasedValues_ = std::move(other.erasedValues_);
928 operators_ = std::exchange(other.operators_,
nullptr);
929 entryPool_ = std::exchange(other.entryPool_,
nullptr);
934template <
class Master_matrix>
935inline std::size_t Vector_column<Master_matrix>::compute_hash_value()
937 std::size_t seed = 0;
938 for (
const Entry& entry : get_non_zero_content_range()) {
939 seed ^= std::hash<unsigned int>()(entry.get_row_index() *
static_cast<unsigned int>(entry.get_element())) +
940 0x9e3779b9 + (seed << 6) + (seed >> 2);
945template <
class Master_matrix>
946inline void Vector_column<Master_matrix>::_delete_entry(
Entry* entry)
948 if constexpr (Master_matrix::Option_list::has_row_access) RA_opt::unlink(entry);
949 entryPool_->destroy(entry);
952template <
class Master_matrix>
953inline void Vector_column<Master_matrix>::_delete_entry(
typename Column_support::iterator& it)
959template <
class Master_matrix>
960inline typename Vector_column<Master_matrix>::Entry*
961Vector_column<Master_matrix>::_insert_entry(Column_support& column, ID_index rowIndex,
const Field_element& value)
964 if constexpr (Master_matrix::Option_list::has_row_access) {
965 newEntry = entryPool_->construct(RA_opt::get_column_index(), rowIndex);
967 newEntry = entryPool_->construct(rowIndex);
969 newEntry->set_element(value);
970 column.push_back(newEntry);
971 if constexpr (Master_matrix::Option_list::has_row_access) RA_opt::insert_entry(rowIndex, newEntry);
975template <
class Master_matrix>
976inline void Vector_column<Master_matrix>::_update_entry(Index position, ID_index rowIndex,
const Field_element& value)
978 if constexpr (Master_matrix::Option_list::has_row_access) {
979 column_[position] = entryPool_->construct(RA_opt::get_column_index(), rowIndex);
981 column_[position] = entryPool_->construct(rowIndex);
983 column_[position]->set_element(value);
984 if constexpr (Master_matrix::Option_list::has_row_access) RA_opt::insert_entry(rowIndex, column_[position]);
987template <
class Master_matrix>
988template <
class Entry_range>
989inline bool Vector_column<Master_matrix>::_add(
const Entry_range& column)
991 if (column.begin() == column.end())
return false;
992 if (column_.empty()) {
993 auto get_range = [](
const Entry_range& column) ->
decltype(
auto) {
994 if constexpr (std::is_same_v<Entry_range, Vector_column<Master_matrix> >) {
995 return column.get_non_zero_content_range();
1000 column_.resize(column.size());
1002 for (
const Entry& entry : get_range(column)) {
1003 _update_entry(i++, entry.get_row_index(), entry.get_element());
1006 erasedValues_.clear();
1010 Column_support newColumn;
1011 newColumn.reserve(column_.size() + column.size());
1013 auto pivotIsZeroed = _generic_add(
1015 [&](
Entry* entryTarget) { newColumn.push_back(entryTarget); },
1016 [&](
typename Entry_range::const_iterator& itSource,
const typename Column_support::iterator&) {
1017 _insert_entry(newColumn, itSource->get_row_index(), itSource->get_element());
1019 [&](Field_element& targetElement,
typename Entry_range::const_iterator& itSource) {
1020 if constexpr (!Master_matrix::Option_list::is_z2)
1021 operators_->add_inplace(targetElement, itSource->get_element());
1023 [&](
Entry* entryTarget) { newColumn.push_back(entryTarget); });
1025 column_.swap(newColumn);
1027 return pivotIsZeroed;
1030template <
class Master_matrix>
1031template <
class Entry_range>
1032inline bool Vector_column<Master_matrix>::_multiply_target_and_add(
const Field_element& val,
const Entry_range& column)
1034 if (val == Field_operators::get_additive_identity()) {
1035 if constexpr (Master_matrix::isNonBasic && !Master_matrix::Option_list::is_of_boundary_type) {
1036 throw std::invalid_argument(
"A chain column should not be multiplied by 0.");
1043 if (column_.empty() || val == Field_operators::get_multiplicative_identity()) {
1044 return _add(column);
1049 if constexpr (!Master_matrix::Option_list::is_z2) {
1050 Column_support newColumn;
1051 newColumn.reserve(column_.size() + column.size());
1053 auto pivotIsZeroed = _generic_add(
1055 [&](
Entry* entryTarget) {
1056 operators_->multiply_inplace(entryTarget->get_element(), val);
1057 if constexpr (Master_matrix::Option_list::has_row_access) RA_opt::update_entry(*entryTarget);
1058 newColumn.push_back(entryTarget);
1060 [&](
typename Entry_range::const_iterator& itSource,
const typename Column_support::iterator&) {
1061 _insert_entry(newColumn, itSource->get_row_index(), itSource->get_element());
1063 [&](Field_element& targetElement,
typename Entry_range::const_iterator& itSource) {
1064 operators_->multiply_and_add_inplace_front(targetElement, val, itSource->get_element());
1066 [&](
Entry* entryTarget) { newColumn.push_back(entryTarget); });
1068 column_.swap(newColumn);
1070 return pivotIsZeroed;
1076template <
class Master_matrix>
1077template <
class Entry_range>
1078inline bool Vector_column<Master_matrix>::_multiply_source_and_add(
const Entry_range& column,
const Field_element& val)
1080 if (val == Field_operators::get_additive_identity() || column.begin() == column.end()) {
1084 if (val == Field_operators::get_multiplicative_identity()) {
1085 return _add(column);
1090 if constexpr (!Master_matrix::Option_list::is_z2) {
1091 Column_support newColumn;
1092 newColumn.reserve(column_.size() + column.size());
1094 auto pivotIsZeroed = _generic_add(
1096 [&](
Entry* entryTarget) { newColumn.push_back(entryTarget); },
1097 [&](
typename Entry_range::const_iterator& itSource,
const typename Column_support::iterator&) {
1098 Entry* newEntry = _insert_entry(newColumn, itSource->get_row_index(), itSource->get_element());
1099 operators_->multiply_inplace(newEntry->get_element(), val);
1100 if constexpr (Master_matrix::Option_list::has_row_access) RA_opt::update_entry(*newEntry);
1102 [&](Field_element& targetElement,
typename Entry_range::const_iterator& itSource) {
1103 operators_->multiply_and_add_inplace_back(itSource->get_element(), val, targetElement);
1105 [&](
Entry* entryTarget) { newColumn.push_back(entryTarget); });
1107 column_.swap(newColumn);
1109 return pivotIsZeroed;
1115template <
class Master_matrix>
1116template <
class Entry_range,
typename F1,
typename F2,
typename F3,
typename F4>
1117inline bool Vector_column<Master_matrix>::_generic_add(
const Entry_range& column,
1118 F1&& process_target,
1119 F2&& process_source,
1120 F3&& update_target1,
1121 F4&& update_target2)
1123 auto updateTargetIterator = [&](
typename Column_support::iterator& itTarget) {
1124 while (_is_lazy_erased(itTarget)) {
1125 _delete_entry(*itTarget);
1129 auto updateSourceIterator = [&](
typename Entry_range::const_iterator& itSource) {
1130 if constexpr (std::is_same_v<Entry_range, Vector_column<Master_matrix> >) {
1131 while (itSource != column.end() && column._is_lazy_erased(itSource->get_row_index())) ++itSource;
1135 bool pivotIsZeroed =
false;
1137 auto itTarget = column_.begin();
1138 auto itSource = column.begin();
1139 while (itTarget != column_.end() && itSource != column.end()) {
1140 updateTargetIterator(itTarget);
1141 updateSourceIterator(itSource);
1142 if (itTarget == column_.end() || itSource == column.end())
break;
1144 _generic_merge_entry_to_column(*
this,
1147 std::forward<F1>(process_target),
1148 std::forward<F2>(process_source),
1149 std::forward<F3>(update_target1),
1150 std::forward<F4>(update_target2),
1154 while (itSource != column.end()) {
1155 updateSourceIterator(itSource);
1156 if (itSource == column.end())
break;
1158 std::forward<F2>(process_source)(itSource, column_.end());
1162 while (itTarget != column_.end()) {
1163 updateTargetIterator(itTarget);
1164 if (itTarget == column_.end())
break;
1166 std::forward<F1>(process_target)(*itTarget);
1170 erasedValues_.clear();
1172 return pivotIsZeroed;
1175template <
class Master_matrix>
1176inline bool Vector_column<Master_matrix>::_is_lazy_erased(
const typename Column_support::const_iterator& it)
const
1178 if constexpr (!Master_matrix::isNonBasic || Master_matrix::Option_list::is_of_boundary_type) {
1179 return it != column_.end() && erasedValues_.find((*it)->get_row_index()) != erasedValues_.end();
1185template <
class Master_matrix>
1186inline bool Vector_column<Master_matrix>::_is_lazy_erased(ID_index rowIndex)
const
1188 if constexpr (!Master_matrix::isNonBasic || Master_matrix::Option_list::is_of_boundary_type) {
1189 return erasedValues_.find(rowIndex) != erasedValues_.end();
1206template <
class Master_matrix>
1207struct std::hash<
Gudhi::persistence_matrix::Vector_column<Master_matrix> > {
1210 return column.compute_hash_value();
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 vector_column.h:54
Contains helper methods for column addition and column hasher.
Persistence matrix namespace.
Definition FieldOperators.h:18
Gudhi namespace.
Definition SimplicialComplexForAlpha.h:14