18#ifndef PM_VECTOR_COLUMN_H
19#define PM_VECTOR_COLUMN_H
26#include <unordered_set>
29#include <boost/iterator/indirect_iterator.hpp>
33namespace persistence_matrix {
48template <
class Master_matrix>
54 using Master = Master_matrix;
55 using Index =
typename Master_matrix::Index;
56 using ID_index =
typename Master_matrix::ID_index;
57 using Dimension =
typename Master_matrix::Dimension;
58 using Field_element =
typename Master_matrix::Element;
59 using Entry =
typename Master_matrix::Matrix_entry;
60 using Column_settings =
typename Master_matrix::Column_settings;
63 using Field_operators =
typename Master_matrix::Field_operators;
64 using Column_support = std::vector<Entry*>;
65 using Entry_constructor =
typename Master_matrix::Entry_constructor;
68 using iterator = boost::indirect_iterator<typename Column_support::iterator>;
69 using const_iterator = boost::indirect_iterator<typename Column_support::const_iterator>;
70 using reverse_iterator = boost::indirect_iterator<typename Column_support::reverse_iterator>;
71 using const_reverse_iterator = boost::indirect_iterator<typename Column_support::const_reverse_iterator>;
74 template <
class Container =
typename Master_matrix::Boundary>
75 Vector_column(
const Container& nonZeroRowIndices, Column_settings* colSettings);
76 template <
class Container =
typename Master_matrix::Boundary,
class Row_container>
78 const Container& nonZeroRowIndices,
79 Row_container* rowContainer,
80 Column_settings* colSettings);
81 template <
class Container =
typename Master_matrix::Boundary>
82 Vector_column(
const Container& nonZeroChainRowIndices, Dimension dimension, Column_settings* colSettings);
83 template <
class Container =
typename Master_matrix::Boundary,
class Row_container>
85 const Container& nonZeroChainRowIndices,
87 Row_container* rowContainer,
88 Column_settings* colSettings);
90 template <
class Row_container>
93 Row_container* rowContainer,
94 Column_settings* colSettings =
nullptr);
98 std::vector<Field_element> get_content(
int columnLength = -1)
const;
99 bool is_non_zero(ID_index rowIndex)
const;
100 bool is_empty()
const;
101 std::size_t size()
const;
103 template <
class Row_index_map>
104 void reorder(
const Row_index_map& valueMap,
105 [[maybe_unused]] Index columnIndex = Master_matrix::template get_null_value<Index>());
108 void clear(ID_index rowIndex);
110 ID_index get_pivot();
111 Field_element get_pivot_value();
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;
122 template <
class Entry_range>
129 template <
class Entry_range>
130 Vector_column& multiply_target_and_add(
const Field_element& val,
const Entry_range& column);
133 template <
class Entry_range>
134 Vector_column& multiply_source_and_add(
const Entry_range& column,
const Field_element& val);
137 void push_back(
const Entry& entry);
139 std::size_t compute_hash_value();
142 if (&c1 == &c2)
return true;
143 if (c1.erasedValues_.empty() && c2.erasedValues_.empty() && c1.column_.size() != c2.column_.size())
return false;
145 auto it1 = c1.column_.begin();
146 auto it2 = c2.column_.begin();
147 while (it1 != c1.column_.end() && it2 != c2.column_.end()) {
148 if constexpr (!Master_matrix::isNonBasic || Master_matrix::Option_list::is_of_boundary_type) {
149 while (it1 != c1.column_.end() && c1.erasedValues_.find((*it1)->get_row_index()) != c1.erasedValues_.end())
151 while (it2 != c2.column_.end() && c2.erasedValues_.find((*it2)->get_row_index()) != c2.erasedValues_.end())
153 if (it1 == c1.column_.end() || it2 == c2.column_.end())
break;
155 if constexpr (Master_matrix::Option_list::is_z2) {
156 if ((*it1)->get_row_index() != (*it2)->get_row_index())
return false;
158 if ((*it1)->get_row_index() != (*it2)->get_row_index() || (*it1)->get_element() != (*it2)->get_element())
165 if constexpr (!Master_matrix::isNonBasic || Master_matrix::Option_list::is_of_boundary_type) {
166 while (it1 != c1.column_.end() && c1.erasedValues_.find((*it1)->get_row_index()) != c1.erasedValues_.end()) ++it1;
167 while (it2 != c2.column_.end() && c2.erasedValues_.find((*it2)->get_row_index()) != c2.erasedValues_.end()) ++it2;
168 return it2 == c2.column_.end() && it1 == c1.column_.end();
175 if (&c1 == &c2)
return false;
177 auto it1 = c1.column_.begin();
178 auto it2 = c2.column_.begin();
179 while (it1 != c1.column_.end() && it2 != c2.column_.end()) {
180 if constexpr (!Master_matrix::isNonBasic || Master_matrix::Option_list::is_of_boundary_type) {
181 while (it1 != c1.column_.end() && c1.erasedValues_.find((*it1)->get_row_index()) != c1.erasedValues_.end())
183 while (it2 != c2.column_.end() && c2.erasedValues_.find((*it2)->get_row_index()) != c2.erasedValues_.end())
185 if (it1 == c1.column_.end() || it2 == c2.column_.end())
break;
188 if ((*it1)->get_row_index() != (*it2)->get_row_index())
return (*it1)->get_row_index() < (*it2)->get_row_index();
189 if constexpr (!Master_matrix::Option_list::is_z2) {
190 if ((*it1)->get_element() != (*it2)->get_element())
return (*it1)->get_element() < (*it2)->get_element();
195 if constexpr (!Master_matrix::isNonBasic || Master_matrix::Option_list::is_of_boundary_type) {
196 while (it1 != c1.column_.end() && c1.erasedValues_.find((*it1)->get_row_index()) != c1.erasedValues_.end()) ++it1;
197 while (it2 != c2.column_.end() && c2.erasedValues_.find((*it2)->get_row_index()) != c2.erasedValues_.end()) ++it2;
199 return it2 != c2.column_.end();
212 col1.column_.swap(col2.column_);
213 col1.erasedValues_.swap(col2.erasedValues_);
214 std::swap(col1.operators_, col2.operators_);
215 std::swap(col1.entryPool_, col2.entryPool_);
223 Column_support column_;
224 std::unordered_set<ID_index> erasedValues_;
226 Field_operators* operators_;
227 Entry_constructor* entryPool_;
229 template <
class Column,
class Entry_iterator,
typename F1,
typename F2,
typename F3,
typename F4>
230 friend void _generic_merge_entry_to_column(Column& targetColumn,
231 Entry_iterator& itSource,
232 typename Column::Column_support::iterator& itTarget,
237 bool& pivotIsZeroed);
239 void _delete_entry(Entry* entry);
240 void _delete_entry(
typename Column_support::iterator& it);
241 Entry* _insert_entry(
const Field_element& value, ID_index rowIndex, Column_support& column);
242 void _insert_entry(ID_index rowIndex, Column_support& column);
243 void _update_entry(
const Field_element& value, ID_index rowIndex, Index position);
244 void _update_entry(ID_index rowIndex, Index position);
245 template <
class Entry_range>
246 bool _add(
const Entry_range& column);
247 template <
class Entry_range>
248 bool _multiply_target_and_add(
const Field_element& val,
const Entry_range& column);
249 template <
class Entry_range>
250 bool _multiply_source_and_add(
const Entry_range& column,
const Field_element& val);
251 template <
class Entry_range,
typename F1,
typename F2,
typename F3,
typename F4>
252 bool _generic_add(
const Entry_range& source,
256 F4&& update_target2);
259template <
class Master_matrix>
265 entryPool_(colSettings == nullptr ? nullptr : &(colSettings->entryConstructor))
267 if (operators_ ==
nullptr && entryPool_ ==
nullptr)
269 if constexpr (!Master_matrix::Option_list::is_z2) {
270 operators_ = &(colSettings->operators);
274template <
class Master_matrix>
275template <
class Container>
276inline Vector_column<Master_matrix>::Vector_column(
const Container& nonZeroRowIndices, Column_settings* colSettings)
278 Dim_opt(nonZeroRowIndices.size() == 0 ? 0 : nonZeroRowIndices.size() - 1),
280 column_(nonZeroRowIndices.size(), nullptr),
282 entryPool_(&(colSettings->entryConstructor))
284 static_assert(!Master_matrix::isNonBasic || Master_matrix::Option_list::is_of_boundary_type,
285 "Constructor not available for chain columns, please specify the dimension of the chain.");
287 if constexpr (!Master_matrix::Option_list::is_z2) {
288 operators_ = &(colSettings->operators);
292 if constexpr (Master_matrix::Option_list::is_z2) {
293 for (ID_index
id : nonZeroRowIndices) {
294 _update_entry(
id, i++);
297 for (
const auto& p : nonZeroRowIndices) {
298 _update_entry(operators_->get_value(p.second), p.first, i++);
303template <
class Master_matrix>
304template <
class Container,
class Row_container>
305inline Vector_column<Master_matrix>::Vector_column(Index columnIndex,
306 const Container& nonZeroRowIndices,
307 Row_container* rowContainer,
308 Column_settings* colSettings)
309 : RA_opt(columnIndex, rowContainer),
310 Dim_opt(nonZeroRowIndices.size() == 0 ? 0 : nonZeroRowIndices.size() - 1),
312 if constexpr (Master_matrix::Option_list::is_z2) {
313 return nonZeroRowIndices.begin() == nonZeroRowIndices.end()
314 ? Master_matrix::template get_null_value<ID_index>()
315 : *
std::prev(nonZeroRowIndices.end());
317 return nonZeroRowIndices.begin() == nonZeroRowIndices.end()
318 ? Master_matrix::template get_null_value<ID_index>()
319 :
std::prev(nonZeroRowIndices.end())->first;
322 column_(nonZeroRowIndices.size(),
nullptr),
324 entryPool_(&(colSettings->entryConstructor))
326 static_assert(!Master_matrix::isNonBasic || Master_matrix::Option_list::is_of_boundary_type,
327 "Constructor not available for chain columns, please specify the dimension of the chain.");
329 if constexpr (!Master_matrix::Option_list::is_z2) {
330 operators_ = &(colSettings->operators);
334 if constexpr (Master_matrix::Option_list::is_z2) {
335 for (ID_index
id : nonZeroRowIndices) {
336 _update_entry(
id, i++);
339 for (
const auto& p : nonZeroRowIndices) {
340 _update_entry(operators_->get_value(p.second), p.first, i++);
345template <
class Master_matrix>
346template <
class Container>
347inline Vector_column<Master_matrix>::Vector_column(
const Container& nonZeroRowIndices,
349 Column_settings* colSettings)
353 if constexpr (Master_matrix::Option_list::is_z2) {
354 return nonZeroRowIndices.begin() == nonZeroRowIndices.end()
355 ? Master_matrix::template get_null_value<ID_index>()
356 : *
std::prev(nonZeroRowIndices.end());
358 return nonZeroRowIndices.begin() == nonZeroRowIndices.end()
359 ? Master_matrix::template get_null_value<ID_index>()
360 :
std::prev(nonZeroRowIndices.end())->first;
363 column_(nonZeroRowIndices.size(),
nullptr),
365 entryPool_(&(colSettings->entryConstructor))
367 if constexpr (!Master_matrix::Option_list::is_z2) {
368 operators_ = &(colSettings->operators);
372 if constexpr (Master_matrix::Option_list::is_z2) {
373 for (ID_index
id : nonZeroRowIndices) {
374 _update_entry(
id, i++);
377 for (
const auto& p : nonZeroRowIndices) {
378 _update_entry(operators_->get_value(p.second), p.first, i++);
383template <
class Master_matrix>
384template <
class Container,
class Row_container>
385inline Vector_column<Master_matrix>::Vector_column(Index columnIndex,
386 const Container& nonZeroRowIndices,
388 Row_container* rowContainer,
389 Column_settings* colSettings)
390 : RA_opt(columnIndex, rowContainer),
393 if constexpr (Master_matrix::Option_list::is_z2) {
394 return nonZeroRowIndices.begin() == nonZeroRowIndices.end()
395 ? Master_matrix::template get_null_value<ID_index>()
396 : *
std::prev(nonZeroRowIndices.end());
398 return nonZeroRowIndices.begin() == nonZeroRowIndices.end()
399 ? Master_matrix::template get_null_value<ID_index>()
400 :
std::prev(nonZeroRowIndices.end())->first;
403 column_(nonZeroRowIndices.size(),
nullptr),
405 entryPool_(&(colSettings->entryConstructor))
407 if constexpr (!Master_matrix::Option_list::is_z2) {
408 operators_ = &(colSettings->operators);
412 if constexpr (Master_matrix::Option_list::is_z2) {
413 for (ID_index
id : nonZeroRowIndices) {
414 _update_entry(
id, i++);
417 for (
const auto& p : nonZeroRowIndices) {
418 _update_entry(operators_->get_value(p.second), p.first, i++);
423template <
class Master_matrix>
424inline Vector_column<Master_matrix>::Vector_column(
const Vector_column& column, Column_settings* colSettings)
426 Dim_opt(static_cast<const Dim_opt&>(column)),
427 Chain_opt(static_cast<const Chain_opt&>(column)),
428 column_(column.column_.size(), nullptr),
429 erasedValues_(column.erasedValues_),
430 operators_(colSettings == nullptr ? column.operators_ : nullptr),
431 entryPool_(colSettings == nullptr ? column.entryPool_ : &(colSettings->entryConstructor))
433 static_assert(!Master_matrix::Option_list::has_row_access,
434 "Simple copy constructor not available when row access option enabled. Please specify the new column "
435 "index and the row container.");
437 if constexpr (!Master_matrix::Option_list::is_z2) {
438 if (colSettings !=
nullptr) operators_ = &(colSettings->operators);
442 for (
const Entry* entry : column.column_) {
443 if constexpr (Master_matrix::Option_list::is_z2) {
444 _update_entry(entry->get_row_index(), i++);
446 _update_entry(entry->get_element(), entry->get_row_index(), i++);
451template <
class Master_matrix>
452template <
class Row_container>
453inline Vector_column<Master_matrix>::Vector_column(
const Vector_column& column,
455 Row_container* rowContainer,
456 Column_settings* colSettings)
457 : RA_opt(columnIndex, rowContainer),
458 Dim_opt(static_cast<const Dim_opt&>(column)),
459 Chain_opt(static_cast<const Chain_opt&>(column)),
460 column_(column.column_.size(), nullptr),
461 erasedValues_(column.erasedValues_),
462 operators_(colSettings == nullptr ? column.operators_ : nullptr),
463 entryPool_(colSettings == nullptr ? column.entryPool_ : &(colSettings->entryConstructor))
465 if constexpr (!Master_matrix::Option_list::is_z2) {
466 if (colSettings !=
nullptr) operators_ = &(colSettings->operators);
470 for (
const Entry* entry : column.column_) {
471 if constexpr (Master_matrix::Option_list::is_z2) {
472 _update_entry(entry->get_row_index(), i++);
474 _update_entry(entry->get_element(), entry->get_row_index(), i++);
479template <
class Master_matrix>
480inline Vector_column<Master_matrix>::Vector_column(Vector_column&& column) noexcept
481 : RA_opt(std::move(
static_cast<RA_opt&
>(column))),
482 Dim_opt(std::move(
static_cast<Dim_opt&
>(column))),
483 Chain_opt(std::move(
static_cast<Chain_opt&
>(column))),
484 column_(std::move(column.column_)),
485 erasedValues_(std::move(column.erasedValues_)),
486 operators_(std::exchange(column.operators_,
nullptr)),
487 entryPool_(std::exchange(column.entryPool_,
nullptr))
490template <
class Master_matrix>
491inline Vector_column<Master_matrix>::~Vector_column()
493 for (
auto* entry : column_) {
494 _delete_entry(entry);
498template <
class Master_matrix>
499inline std::vector<typename Vector_column<Master_matrix>::Field_element> Vector_column<Master_matrix>::get_content(
500 int columnLength)
const
502 if (columnLength < 0 && column_.size() > 0)
503 columnLength = column_.back()->get_row_index() + 1;
504 else if (columnLength < 0)
505 return std::vector<Field_element>();
507 std::vector<Field_element> container(columnLength, 0);
508 for (
auto it = column_.begin(); it != column_.end() && (*it)->get_row_index() <
static_cast<ID_index
>(columnLength);
510 if constexpr (!Master_matrix::isNonBasic || Master_matrix::Option_list::is_of_boundary_type) {
511 if (erasedValues_.find((*it)->get_row_index()) != erasedValues_.end())
continue;
513 if constexpr (Master_matrix::Option_list::is_z2) {
514 container[(*it)->get_row_index()] = 1;
516 container[(*it)->get_row_index()] = (*it)->get_element();
522template <
class Master_matrix>
523inline bool Vector_column<Master_matrix>::is_non_zero(ID_index rowIndex)
const
525 if constexpr (!Master_matrix::isNonBasic || Master_matrix::Option_list::is_of_boundary_type)
526 if (erasedValues_.find(rowIndex) != erasedValues_.end())
return false;
528 Entry entry(rowIndex);
529 return std::binary_search(column_.begin(), column_.end(), &entry, [](
const Entry* a,
const Entry* b) {
530 return a->get_row_index() < b->get_row_index();
534template <
class Master_matrix>
535inline bool Vector_column<Master_matrix>::is_empty()
const
537 if constexpr (!Master_matrix::isNonBasic || Master_matrix::Option_list::is_of_boundary_type) {
538 return column_.size() == erasedValues_.size();
541 return column_.empty();
545template <
class Master_matrix>
546inline std::size_t Vector_column<Master_matrix>::size()
const
548 if constexpr (!Master_matrix::isNonBasic || Master_matrix::Option_list::is_of_boundary_type) {
549 return column_.size() - erasedValues_.size();
552 return column_.size();
556template <
class Master_matrix>
557template <
class Row_index_map>
558inline void Vector_column<Master_matrix>::reorder(
const Row_index_map& valueMap, [[maybe_unused]] Index columnIndex)
560 static_assert(!Master_matrix::isNonBasic || Master_matrix::Option_list::is_of_boundary_type,
561 "Method not available for chain columns.");
563 if (erasedValues_.empty()) {
564 for (Entry* entry : column_) {
565 if constexpr (Master_matrix::Option_list::has_row_access) {
566 RA_opt::unlink(entry);
567 if (columnIndex != Master_matrix::template get_null_value<Index>()) entry->set_column_index(columnIndex);
569 entry->set_row_index(valueMap.at(entry->get_row_index()));
570 if constexpr (Master_matrix::Option_list::has_intrusive_rows && Master_matrix::Option_list::has_row_access)
571 RA_opt::insert_entry(entry->get_row_index(), entry);
575 if constexpr (!Master_matrix::Option_list::has_intrusive_rows && Master_matrix::Option_list::has_row_access) {
576 for (Entry* entry : column_) {
577 RA_opt::insert_entry(entry->get_row_index(), entry);
581 std::sort(column_.begin(), column_.end(), [](
const Entry* c1,
const Entry* c2) { return *c1 < *c2; });
583 Column_support newColumn;
584 for (Entry* entry : column_) {
585 if (erasedValues_.find(entry->get_row_index()) == erasedValues_.end()) {
586 if constexpr (Master_matrix::Option_list::has_row_access) {
587 RA_opt::unlink(entry);
588 if (columnIndex != Master_matrix::template get_null_value<Index>()) entry->set_column_index(columnIndex);
590 entry->set_row_index(valueMap.at(entry->get_row_index()));
591 newColumn.push_back(entry);
592 if constexpr (Master_matrix::Option_list::has_intrusive_rows && Master_matrix::Option_list::has_row_access)
593 RA_opt::insert_entry(entry->get_row_index(), entry);
595 _delete_entry(entry);
599 if constexpr (!Master_matrix::Option_list::has_intrusive_rows && Master_matrix::Option_list::has_row_access) {
600 for (Entry* entry : column_) {
601 RA_opt::insert_entry(entry->get_row_index(), entry);
604 std::sort(newColumn.begin(), newColumn.end(), [](
const Entry* c1,
const Entry* c2) { return *c1 < *c2; });
605 erasedValues_.clear();
606 column_.swap(newColumn);
610template <
class Master_matrix>
611inline void Vector_column<Master_matrix>::clear()
613 static_assert(!Master_matrix::isNonBasic || Master_matrix::Option_list::is_of_boundary_type,
614 "Method not available for chain columns as a base element should not be empty.");
616 for (
auto* entry : column_) {
617 if constexpr (Master_matrix::Option_list::has_row_access) RA_opt::unlink(entry);
618 entryPool_->destroy(entry);
622 erasedValues_.clear();
625template <
class Master_matrix>
626inline void Vector_column<Master_matrix>::clear(ID_index rowIndex)
628 static_assert(!Master_matrix::isNonBasic || Master_matrix::Option_list::is_of_boundary_type,
629 "Method not available for chain columns.");
631 erasedValues_.insert(rowIndex);
634template <
class Master_matrix>
635inline typename Vector_column<Master_matrix>::ID_index Vector_column<Master_matrix>::get_pivot()
637 static_assert(Master_matrix::isNonBasic,
638 "Method not available for base columns.");
640 if constexpr (Master_matrix::Option_list::is_of_boundary_type) {
641 if (column_.empty())
return Master_matrix::template get_null_value<ID_index>();
642 if (erasedValues_.empty())
return column_.back()->get_row_index();
644 auto it = erasedValues_.find(column_.back()->get_row_index());
645 while (!column_.empty() && it != erasedValues_.end()) {
646 erasedValues_.erase(it);
647 _delete_entry(column_.back());
649 if (!column_.empty()) it = erasedValues_.find(column_.back()->get_row_index());
652 if (column_.empty())
return Master_matrix::template get_null_value<ID_index>();
653 return column_.back()->get_row_index();
655 return Chain_opt::get_pivot();
659template <
class Master_matrix>
660inline typename Vector_column<Master_matrix>::Field_element Vector_column<Master_matrix>::get_pivot_value()
662 static_assert(Master_matrix::isNonBasic,
663 "Method not available for base columns.");
665 if constexpr (Master_matrix::Option_list::is_z2) {
668 if constexpr (Master_matrix::Option_list::is_of_boundary_type) {
669 if (column_.empty())
return 0;
670 if (erasedValues_.empty())
return column_.back()->get_element();
672 auto it = erasedValues_.find(column_.back()->get_row_index());
673 while (!column_.empty() && it != erasedValues_.end()) {
674 erasedValues_.erase(it);
675 _delete_entry(column_.back());
677 if (!column_.empty()) it = erasedValues_.find(column_.back()->get_row_index());
680 if (column_.empty())
return 0;
681 return column_.back()->get_element();
683 if (Chain_opt::get_pivot() == Master_matrix::template get_null_value<ID_index>())
return Field_element();
684 for (
const Entry* entry : column_) {
685 if (entry->get_row_index() == Chain_opt::get_pivot())
return entry->get_element();
687 return Field_element();
692template <
class Master_matrix>
693inline typename Vector_column<Master_matrix>::iterator Vector_column<Master_matrix>::begin() noexcept
695 return column_.begin();
698template <
class Master_matrix>
699inline typename Vector_column<Master_matrix>::const_iterator Vector_column<Master_matrix>::begin() const noexcept
701 return column_.begin();
704template <
class Master_matrix>
705inline typename Vector_column<Master_matrix>::iterator Vector_column<Master_matrix>::end() noexcept
707 return column_.end();
710template <
class Master_matrix>
711inline typename Vector_column<Master_matrix>::const_iterator Vector_column<Master_matrix>::end() const noexcept
713 return column_.end();
716template <
class Master_matrix>
717inline typename Vector_column<Master_matrix>::reverse_iterator Vector_column<Master_matrix>::rbegin() noexcept
719 return column_.rbegin();
722template <
class Master_matrix>
723inline typename Vector_column<Master_matrix>::const_reverse_iterator Vector_column<Master_matrix>::rbegin()
726 return column_.rbegin();
729template <
class Master_matrix>
730inline typename Vector_column<Master_matrix>::reverse_iterator Vector_column<Master_matrix>::rend() noexcept
732 return column_.rend();
735template <
class Master_matrix>
736inline typename Vector_column<Master_matrix>::const_reverse_iterator Vector_column<Master_matrix>::rend() const noexcept
738 return column_.rend();
741template <
class Master_matrix>
742template <
class Entry_range>
743inline Vector_column<Master_matrix>& Vector_column<Master_matrix>::operator+=(
const Entry_range& column)
745 static_assert((!Master_matrix::isNonBasic || std::is_same_v<Entry_range, Vector_column>),
746 "For boundary columns, the range has to be a column of same type to help ensure the validity of the "
748 static_assert((!Master_matrix::isNonBasic || Master_matrix::Option_list::is_of_boundary_type),
749 "For chain columns, the given column cannot be constant.");
756template <
class Master_matrix>
757inline Vector_column<Master_matrix>& Vector_column<Master_matrix>::operator+=(Vector_column& column)
759 if constexpr (Master_matrix::isNonBasic && !Master_matrix::Option_list::is_of_boundary_type) {
762 Chain_opt::swap_pivots(column);
763 Dim_opt::swap_dimension(column);
772template <
class Master_matrix>
773inline Vector_column<Master_matrix>& Vector_column<Master_matrix>::operator*=(
unsigned int v)
775 if constexpr (Master_matrix::Option_list::is_z2) {
777 if constexpr (Master_matrix::isNonBasic && !Master_matrix::Option_list::is_of_boundary_type) {
778 throw std::invalid_argument(
"A chain column should not be multiplied by 0.");
784 Field_element val = operators_->get_value(v);
786 if (val == Field_operators::get_additive_identity()) {
787 if constexpr (Master_matrix::isNonBasic && !Master_matrix::Option_list::is_of_boundary_type) {
788 throw std::invalid_argument(
"A chain column should not be multiplied by 0.");
795 if (val == Field_operators::get_multiplicative_identity())
return *
this;
797 for (Entry* entry : column_) {
798 operators_->multiply_inplace(entry->get_element(), val);
799 if constexpr (Master_matrix::Option_list::has_row_access) RA_opt::update_entry(*entry);
806template <
class Master_matrix>
807template <
class Entry_range>
808inline Vector_column<Master_matrix>& Vector_column<Master_matrix>::multiply_target_and_add(
const Field_element& val,
809 const Entry_range& column)
811 static_assert((!Master_matrix::isNonBasic || std::is_same_v<Entry_range, Vector_column>),
812 "For boundary columns, the range has to be a column of same type to help ensure the validity of the "
814 static_assert((!Master_matrix::isNonBasic || Master_matrix::Option_list::is_of_boundary_type),
815 "For chain columns, the given column cannot be constant.");
817 if constexpr (Master_matrix::Option_list::is_z2) {
825 _multiply_target_and_add(val, column);
831template <
class Master_matrix>
832inline Vector_column<Master_matrix>& Vector_column<Master_matrix>::multiply_target_and_add(
const Field_element& val,
833 Vector_column& column)
835 if constexpr (Master_matrix::isNonBasic && !Master_matrix::Option_list::is_of_boundary_type) {
837 if constexpr (Master_matrix::Option_list::is_z2) {
840 Chain_opt::swap_pivots(column);
841 Dim_opt::swap_dimension(column);
844 throw std::invalid_argument(
"A chain column should not be multiplied by 0.");
847 if (_multiply_target_and_add(val, column)) {
848 Chain_opt::swap_pivots(column);
849 Dim_opt::swap_dimension(column);
853 if constexpr (Master_matrix::Option_list::is_z2) {
861 _multiply_target_and_add(val, column);
868template <
class Master_matrix>
869template <
class Entry_range>
870inline Vector_column<Master_matrix>& Vector_column<Master_matrix>::multiply_source_and_add(
const Entry_range& column,
871 const Field_element& val)
873 static_assert((!Master_matrix::isNonBasic || std::is_same_v<Entry_range, Vector_column>),
874 "For boundary columns, the range has to be a column of same type to help ensure the validity of the "
876 static_assert((!Master_matrix::isNonBasic || Master_matrix::Option_list::is_of_boundary_type),
877 "For chain columns, the given column cannot be constant.");
879 if constexpr (Master_matrix::Option_list::is_z2) {
884 _multiply_source_and_add(column, val);
890template <
class Master_matrix>
891inline Vector_column<Master_matrix>& Vector_column<Master_matrix>::multiply_source_and_add(Vector_column& column,
892 const Field_element& val)
894 if constexpr (Master_matrix::isNonBasic && !Master_matrix::Option_list::is_of_boundary_type) {
896 if constexpr (Master_matrix::Option_list::is_z2) {
899 Chain_opt::swap_pivots(column);
900 Dim_opt::swap_dimension(column);
904 if (_multiply_source_and_add(column, val)) {
905 Chain_opt::swap_pivots(column);
906 Dim_opt::swap_dimension(column);
910 if constexpr (Master_matrix::Option_list::is_z2) {
915 _multiply_source_and_add(column, val);
922template <
class Master_matrix>
923inline void Vector_column<Master_matrix>::push_back(
const Entry& entry)
925 static_assert(Master_matrix::Option_list::is_of_boundary_type,
"`push_back` is not available for Chain matrices.");
927 GUDHI_CHECK(entry.get_row_index() > get_pivot(),
"The new row index has to be higher than the current pivot.");
929 if constexpr (Master_matrix::Option_list::is_z2) {
930 _insert_entry(entry.get_row_index(), column_);
932 _insert_entry(entry.get_element(), entry.get_row_index(), column_);
936template <
class Master_matrix>
937inline Vector_column<Master_matrix>& Vector_column<Master_matrix>::operator=(
const Vector_column& other)
939 static_assert(!Master_matrix::Option_list::has_row_access,
"= assignment not enabled with row access option.");
941 Dim_opt::operator=(other);
942 Chain_opt::operator=(other);
944 auto tmpPool = entryPool_;
945 entryPool_ = other.entryPool_;
947 while (column_.size() > other.column_.size()) {
948 if (column_.back() !=
nullptr) {
949 if constexpr (Master_matrix::Option_list::has_row_access) RA_opt::unlink(column_.back());
950 tmpPool->destroy(column_.back());
955 column_.resize(other.column_.size(),
nullptr);
957 for (
const Entry* entry : other.column_) {
958 if (column_[i] !=
nullptr) {
959 if constexpr (Master_matrix::Option_list::has_row_access) RA_opt::unlink(column_[i]);
960 tmpPool->destroy(column_[i]);
962 if constexpr (Master_matrix::Option_list::is_z2) {
963 _update_entry(entry->get_row_index(), i++);
965 _update_entry(entry->get_element(), entry->get_row_index(), i++);
968 erasedValues_ = other.erasedValues_;
969 operators_ = other.operators_;
974template <
class Master_matrix>
975inline std::size_t Vector_column<Master_matrix>::compute_hash_value()
977 std::size_t seed = 0;
978 for (Entry* entry : column_) {
979 if (erasedValues_.find(entry->get_row_index()) == erasedValues_.end()) {
980 seed ^= std::hash<unsigned int>()(entry->get_row_index() *
static_cast<unsigned int>(entry->get_element())) +
981 0x9e3779b9 + (seed << 6) + (seed >> 2);
987template <
class Master_matrix>
988inline void Vector_column<Master_matrix>::_delete_entry(Entry* entry)
990 if constexpr (Master_matrix::Option_list::has_row_access) RA_opt::unlink(entry);
991 entryPool_->destroy(entry);
994template <
class Master_matrix>
995inline void Vector_column<Master_matrix>::_delete_entry(
typename Column_support::iterator& it)
1001template <
class Master_matrix>
1002inline typename Vector_column<Master_matrix>::Entry*
1003Vector_column<Master_matrix>::_insert_entry(
const Field_element& value, ID_index rowIndex, Column_support& column)
1005 if constexpr (Master_matrix::Option_list::has_row_access) {
1006 Entry* newEntry = entryPool_->construct(RA_opt::columnIndex_, rowIndex);
1007 newEntry->set_element(value);
1008 column.push_back(newEntry);
1009 RA_opt::insert_entry(rowIndex, newEntry);
1012 Entry* newEntry = entryPool_->construct(rowIndex);
1013 newEntry->set_element(value);
1014 column.push_back(newEntry);
1019template <
class Master_matrix>
1020inline void Vector_column<Master_matrix>::_insert_entry(ID_index rowIndex, Column_support& column)
1022 if constexpr (Master_matrix::Option_list::has_row_access) {
1023 Entry* newEntry = entryPool_->construct(RA_opt::columnIndex_, rowIndex);
1024 column.push_back(newEntry);
1025 RA_opt::insert_entry(rowIndex, newEntry);
1027 Entry* newEntry = entryPool_->construct(rowIndex);
1028 column.push_back(newEntry);
1032template <
class Master_matrix>
1033inline void Vector_column<Master_matrix>::_update_entry(
const Field_element& value, ID_index rowIndex, Index position)
1035 if constexpr (Master_matrix::Option_list::has_row_access) {
1036 Entry* newEntry = entryPool_->construct(RA_opt::columnIndex_, rowIndex);
1037 newEntry->set_element(value);
1038 column_[position] = newEntry;
1039 RA_opt::insert_entry(rowIndex, newEntry);
1041 column_[position] = entryPool_->construct(rowIndex);
1042 column_[position]->set_element(value);
1046template <
class Master_matrix>
1047inline void Vector_column<Master_matrix>::_update_entry(ID_index rowIndex, Index position)
1049 if constexpr (Master_matrix::Option_list::has_row_access) {
1050 Entry* newEntry = entryPool_->construct(RA_opt::columnIndex_, rowIndex);
1051 column_[position] = newEntry;
1052 RA_opt::insert_entry(rowIndex, newEntry);
1054 column_[position] = entryPool_->construct(rowIndex);
1058template <
class Master_matrix>
1059template <
class Entry_range>
1060inline bool Vector_column<Master_matrix>::_add(
const Entry_range& column)
1062 if (column.begin() == column.end())
return false;
1063 if (column_.empty()) {
1064 column_.resize(column.size());
1066 for (
const Entry& entry : column) {
1067 if constexpr (Master_matrix::Option_list::is_z2) {
1068 _update_entry(entry.get_row_index(), i++);
1070 _update_entry(entry.get_element(), entry.get_row_index(), i++);
1076 Column_support newColumn;
1077 newColumn.reserve(column_.size() + column.size());
1079 auto pivotIsZeroed = _generic_add(
1081 [&](Entry* entryTarget) { newColumn.push_back(entryTarget); },
1082 [&](
typename Entry_range::const_iterator& itSource,
1083 [[maybe_unused]]
const typename Column_support::iterator& itTarget) {
1084 if constexpr (Master_matrix::Option_list::is_z2) {
1085 _insert_entry(itSource->get_row_index(), newColumn);
1087 _insert_entry(itSource->get_element(), itSource->get_row_index(), newColumn);
1090 [&](Field_element& targetElement,
typename Entry_range::const_iterator& itSource) {
1091 if constexpr (!Master_matrix::Option_list::is_z2)
1092 operators_->add_inplace(targetElement, itSource->get_element());
1094 [&](Entry* entryTarget) { newColumn.push_back(entryTarget); }
1097 column_.swap(newColumn);
1099 return pivotIsZeroed;
1102template <
class Master_matrix>
1103template <
class Entry_range>
1104inline bool Vector_column<Master_matrix>::_multiply_target_and_add(
const Field_element& val,
const Entry_range& column)
1107 if constexpr (Master_matrix::isNonBasic && !Master_matrix::Option_list::is_of_boundary_type) {
1108 throw std::invalid_argument(
"A chain column should not be multiplied by 0.");
1114 if (column_.empty()) {
1115 column_.resize(column.size());
1117 for (
const Entry& entry : column) {
1118 if constexpr (Master_matrix::Option_list::is_z2) {
1119 _update_entry(entry.get_row_index(), i++);
1121 _update_entry(entry.get_element(), entry.get_row_index(), i++);
1124 if constexpr (std::is_same_v<Entry_range, Vector_column<Master_matrix> >) erasedValues_ = column.erasedValues_;
1128 Column_support newColumn;
1129 newColumn.reserve(column_.size() + column.size());
1131 auto pivotIsZeroed = _generic_add(
1133 [&](Entry* entryTarget) {
1134 operators_->multiply_inplace(entryTarget->get_element(), val);
1135 if constexpr (Master_matrix::Option_list::has_row_access) RA_opt::update_entry(*entryTarget);
1136 newColumn.push_back(entryTarget);
1138 [&](
typename Entry_range::const_iterator& itSource,
const typename Column_support::iterator& itTarget) {
1139 _insert_entry(itSource->get_element(), itSource->get_row_index(), newColumn);
1141 [&](Field_element& targetElement,
typename Entry_range::const_iterator& itSource) {
1142 operators_->multiply_and_add_inplace_front(targetElement, val, itSource->get_element());
1144 [&](Entry* entryTarget) { newColumn.push_back(entryTarget); }
1147 column_.swap(newColumn);
1149 return pivotIsZeroed;
1152template <
class Master_matrix>
1153template <
class Entry_range>
1154inline bool Vector_column<Master_matrix>::_multiply_source_and_add(
const Entry_range& column,
const Field_element& val)
1156 if (val == 0u || column.begin() == column.end()) {
1160 Column_support newColumn;
1161 newColumn.reserve(column_.size() + column.size());
1163 auto pivotIsZeroed = _generic_add(
1165 [&](Entry* entryTarget) { newColumn.push_back(entryTarget); },
1166 [&](
typename Entry_range::const_iterator& itSource,
const typename Column_support::iterator& itTarget) {
1167 Entry* newEntry = _insert_entry(itSource->get_element(), itSource->get_row_index(), newColumn);
1168 operators_->multiply_inplace(newEntry->get_element(), val);
1169 if constexpr (Master_matrix::Option_list::has_row_access) RA_opt::update_entry(*newEntry);
1171 [&](Field_element& targetElement,
typename Entry_range::const_iterator& itSource) {
1172 operators_->multiply_and_add_inplace_back(itSource->get_element(), val, targetElement);
1174 [&](Entry* entryTarget) { newColumn.push_back(entryTarget); }
1177 column_.swap(newColumn);
1179 return pivotIsZeroed;
1182template <
class Master_matrix>
1183template <
class Entry_range,
typename F1,
typename F2,
typename F3,
typename F4>
1184inline bool Vector_column<Master_matrix>::_generic_add(
const Entry_range& column,
1185 F1&& process_target,
1186 F2&& process_source,
1187 F3&& update_target1,
1188 F4&& update_target2)
1190 auto updateTargetIterator = [&](
typename Column_support::iterator& itTarget) {
1191 if constexpr (!Master_matrix::isNonBasic || Master_matrix::Option_list::is_of_boundary_type) {
1192 while (itTarget != column_.end() && erasedValues_.find((*itTarget)->get_row_index()) != erasedValues_.end()) {
1193 _delete_entry(*itTarget);
1198 auto updateSourceIterator = [&](
typename Entry_range::const_iterator& itSource) {
1199 if constexpr (std::is_same_v<Entry_range, Vector_column<Master_matrix> > &&
1200 (!Master_matrix::isNonBasic || Master_matrix::Option_list::is_of_boundary_type)) {
1201 while (itSource != column.end() &&
1202 column.erasedValues_.find(itSource->get_row_index()) != column.erasedValues_.end())
1207 bool pivotIsZeroed =
false;
1209 auto itTarget = column_.begin();
1210 auto itSource = column.begin();
1211 while (itTarget != column_.end() && itSource != column.end()) {
1212 updateTargetIterator(itTarget);
1213 updateSourceIterator(itSource);
1214 if (itTarget == column_.end() || itSource == column.end())
break;
1216 _generic_merge_entry_to_column(*
this, itSource, itTarget,
1217 process_target, process_source, update_target1, update_target2,
1221 while (itSource != column.end()) {
1222 updateSourceIterator(itSource);
1223 if (itSource == column.end())
break;
1225 process_source(itSource, column_.end());
1229 while (itTarget != column_.end()) {
1230 updateTargetIterator(itTarget);
1231 if (itTarget == column_.end())
break;
1233 process_target(*itTarget);
1237 erasedValues_.clear();
1239 return pivotIsZeroed;
1253template <
class Master_matrix>
1254struct std::hash<
Gudhi::persistence_matrix::Vector_column<Master_matrix> > {
1256 return column.compute_hash_value();
Column class following the PersistenceMatrixColumn concept.
Definition: vector_column.h:52
Contains helper methods for column addition and column hasher.
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