17#ifndef PM_BASE_MATRIX_COMPRESSION_H
18#define PM_BASE_MATRIX_COMPRESSION_H
24#include <boost/intrusive/set.hpp>
25#include <boost/pending/disjoint_sets.hpp>
27#include <gudhi/Simple_object_pool.h>
44template <
class Master_matrix>
48 using Index =
typename Master_matrix::Index;
49 using Dimension =
typename Master_matrix::Dimension;
55 using Row =
typename Master_matrix::Row;
64 class Column :
public Master_matrix::Column,
65 public boost::intrusive::set_base_hook<boost::intrusive::link_mode<boost::intrusive::normal_link> >
68 using Base =
typename Master_matrix::Column;
72 template <
class Container>
73 Column(
const Container& nonZeroRowIndices,
Column_settings* colSettings) : Base(nonZeroRowIndices, colSettings)
76 template <
class Container,
class Row_container>
77 Column(
Index columnIndex,
78 const Container& nonZeroRowIndices,
79 Row_container* rowContainer,
81 : Base(columnIndex, nonZeroRowIndices, rowContainer, colSettings)
84 template <
class Container,
class = std::enable_if_t<!std::is_arithmetic_v<Container> > >
86 : Base(nonZeroRowIndices, dimension, colSettings)
89 template <
class Container,
class Row_container,
class = std::enable_if_t<!std::is_arithmetic_v<Container> > >
90 Column(
Index columnIndex,
91 const Container& nonZeroRowIndices,
93 Row_container* rowContainer,
95 : Base(columnIndex, nonZeroRowIndices, dimension, rowContainer, colSettings)
101 : Base(idx, e, dimension, colSettings)
104 template <
class Row_container>
106 : Base(columnIndex, idx, dimension, rowContainer, colSettings)
109 template <
class Row_container>
110 Column(
Index columnIndex,
114 Row_container* rowContainer,
116 : Base(columnIndex, idx, e, dimension, rowContainer, colSettings)
120 : Base(
static_cast<const Base&
>(column), colSettings), rep_(column.rep_)
123 template <
class Row_container>
124 Column(
const Column& column,
Index columnIndex, Row_container* rowContainer,
Column_settings* colSettings =
nullptr)
125 : Base(
static_cast<const Base&
>(column), columnIndex, rowContainer, colSettings), rep_(column.rep_)
128 Column(Column&& column) noexcept : Base(std::move(
static_cast<Base&
>(column))), rep_(std::exchange(column.rep_, 0))
137 Index get_rep()
const {
return rep_; }
139 void set_rep(
const Index& rep) { rep_ = rep; }
141 Column& operator=(
const Column& other)
143 Base::operator=(other);
147 Column& operator=(Column&& other)
noexcept
149 Base::operator=(std::move(other));
150 rep_ = std::exchange(other.rep_, 0);
154 size_t operator()(
const Column& c)
const {
return std::hash<Base>()(
static_cast<Base
>(c)); }
180 template <
class Container>
220 template <
class Container,
class = std::enable_if_t<!std::is_arithmetic_v<Container> > >
246 template <
class Boundary_range>
248 Dimension dim = Master_matrix::template get_null_value<Dimension>());
303 template <
class Entry_range_or_column_index>
304 void add_to(
const Entry_range_or_column_index& sourceColumn,
Index targetColumnIndex);
318 template <
class Entry_range_or_column_index>
321 Index targetColumnIndex);
335 template <
class Entry_range_or_column_index>
337 const Entry_range_or_column_index& sourceColumn,
338 Index targetColumnIndex);
365 columnToRep_.clear_and_dispose(Delete_disposer(
this));
366 columnClasses_ = boost::disjoint_sets_with_storage<>();
367 repToColumn_.clear();
368 nextColumnIndex_ = 0;
369 colSettings_ = colSettings;
386 matrix1.columnToRep_.swap(matrix2.columnToRep_);
387 std::swap(matrix1.columnClasses_, matrix2.columnClasses_);
388 matrix1.repToColumn_.swap(matrix2.repToColumn_);
389 std::swap(matrix1.nextColumnIndex_, matrix2.nextColumnIndex_);
390 std::swap(matrix1.colSettings_, matrix2.colSettings_);
391 std::swap(matrix1.columnPool_, matrix2.columnPool_);
393 if constexpr (Master_matrix::Option_list::has_row_access) {
394 swap(
static_cast<typename Master_matrix::Matrix_row_access_option&
>(matrix1),
395 static_cast<typename Master_matrix::Matrix_row_access_option&
>(matrix2));
405 struct Delete_disposer {
408 void operator()(Column* delete_this) { matrix_->columnPool_->destroy(delete_this); }
413 using RA_opt =
typename Master_matrix::Matrix_row_access_option;
414 using Col_dict = boost::intrusive::set<Column, boost::intrusive::constant_time_size<false> >;
416 Col_dict columnToRep_;
417 boost::disjoint_sets_with_storage<> columnClasses_;
419 std::vector<Column*> repToColumn_;
421 Index nextColumnIndex_;
427 std::unique_ptr<Simple_object_pool<Column> > columnPool_;
428 inline static const Column empty_column_;
432 void _insert_column(
Index columnIndex);
433 void _insert_double_column(
Index columnIndex,
typename Col_dict::iterator& doubleIt);
436template <
class Master_matrix>
439 : RA_opt(), nextColumnIndex_(0), colSettings_(colSettings), columnPool_(new Simple_object_pool<
Column>)
443template <
class Master_matrix>
444template <
class Container>
446 const std::vector<Container>& columns,
448 : RA_opt(columns.size()),
449 columnClasses_(columns.size()),
450 repToColumn_(columns.size(), nullptr),
452 colSettings_(colSettings),
453 columnPool_(new Simple_object_pool<
Column>)
455 for (
const Container& c : columns) {
460template <
class Master_matrix>
462 unsigned int numberOfColumns,
464 : RA_opt(numberOfColumns),
465 columnClasses_(numberOfColumns),
466 repToColumn_(numberOfColumns, nullptr),
468 colSettings_(colSettings),
469 columnPool_(new Simple_object_pool<
Column>)
473template <
class Master_matrix>
477 : RA_opt(static_cast<const RA_opt&>(matrixToCopy)),
478 columnClasses_(matrixToCopy.columnClasses_),
479 repToColumn_(matrixToCopy.repToColumn_.size(), nullptr),
481 colSettings_(colSettings == nullptr ? matrixToCopy.colSettings_ : colSettings),
482 columnPool_(new Simple_object_pool<
Column>)
484 for (
const Column* col : matrixToCopy.repToColumn_) {
485 if (col != nullptr) {
486 if constexpr (Master_matrix::Option_list::has_row_access) {
487 repToColumn_[nextColumnIndex_] =
488 columnPool_->construct(*col, col->get_column_index(), RA_opt::_get_rows_ptr(), colSettings_);
490 repToColumn_[nextColumnIndex_] = columnPool_->construct(*col, colSettings_);
492 columnToRep_.insert(columnToRep_.end(), *repToColumn_[nextColumnIndex_]);
493 repToColumn_[nextColumnIndex_]->set_rep(nextColumnIndex_);
499template <
class Master_matrix>
502 : RA_opt(std::move(
static_cast<RA_opt&
>(other))),
503 columnToRep_(std::move(other.columnToRep_)),
504 columnClasses_(std::move(other.columnClasses_)),
505 repToColumn_(std::move(other.repToColumn_)),
506 nextColumnIndex_(std::exchange(other.nextColumnIndex_, 0)),
507 colSettings_(std::exchange(other.colSettings_,
nullptr)),
508 columnPool_(std::exchange(other.columnPool_,
nullptr))
512template <
class Master_matrix>
515 columnToRep_.clear_and_dispose(Delete_disposer(
this));
518template <
class Master_matrix>
519template <
class Container,
class>
525template <
class Master_matrix>
528 static_assert(Master_matrix::Option_list::is_z2,
529 "Insertion method not available for Zp != Z2. Please specify the coefficient.");
531 if constexpr (Master_matrix::Option_list::has_row_access && !Master_matrix::Option_list::has_removable_rows) {
532 RA_opt::_resize(idx);
535 _initialize_column([&]() ->
Column* {
536 if constexpr (Master_matrix::Option_list::has_row_access) {
537 return columnPool_->construct(nextColumnIndex_, idx, 0, RA_opt::_get_rows_ptr(), colSettings_);
539 return columnPool_->construct(idx, 0, colSettings_);
543 _insert_column(nextColumnIndex_);
548template <
class Master_matrix>
552 static_assert(!Master_matrix::Option_list::is_z2,
553 "Insertion method not available for Zp == Z2. Please do not specify any coefficient.");
555 if constexpr (Master_matrix::Option_list::has_row_access && !Master_matrix::Option_list::has_removable_rows) {
556 RA_opt::_resize(idx);
559 _initialize_column([&]() ->
Column* {
560 if constexpr (Master_matrix::Option_list::has_row_access) {
561 return columnPool_->construct(nextColumnIndex_, idx, e, 0, RA_opt::_get_rows_ptr(), colSettings_);
563 return columnPool_->construct(idx, e, 0, colSettings_);
567 _insert_column(nextColumnIndex_);
572template <
class Master_matrix>
573template <
class Boundary_range>
580 if (dim == Master_matrix::template get_null_value<Dimension>()) dim = boundary.size() == 0 ? 0 : boundary.size() - 1;
582 if constexpr (Master_matrix::Option_list::has_row_access && !Master_matrix::Option_list::has_removable_rows) {
583 if (boundary.begin() != boundary.end()) {
584 RA_opt::_resize(Master_matrix::get_row_index(*std::prev(boundary.end())));
588 _initialize_column([&]() ->
Column* {
589 if constexpr (Master_matrix::Option_list::has_row_access) {
590 return columnPool_->construct(nextColumnIndex_, boundary, dim, RA_opt::_get_rows_ptr(), colSettings_);
592 return columnPool_->construct(boundary, dim, colSettings_);
596 _insert_column(nextColumnIndex_);
601template <
class Master_matrix>
605 auto col = repToColumn_[columnClasses_.find_set(columnIndex)];
606 if (col ==
nullptr)
return empty_column_;
610template <
class Master_matrix>
614 static_assert(Master_matrix::Option_list::has_row_access,
"Row access has to be enabled for this method.");
616 return RA_opt::get_row(rowIndex);
619template <
class Master_matrix>
622 if constexpr (Master_matrix::Option_list::has_row_access && Master_matrix::Option_list::has_removable_rows) {
623 RA_opt::erase_empty_row(rowIndex);
627template <
class Master_matrix>
631 return nextColumnIndex_;
634template <
class Master_matrix>
635template <
class Entry_range_or_column_index>
637 Index targetColumnIndex)
640 Index targetRep = columnClasses_.find_set(targetColumnIndex);
641 Column& target = *repToColumn_[targetRep];
642 columnToRep_.erase(target);
643 if constexpr (std::is_integral_v<Entry_range_or_column_index>) {
646 target += sourceColumn;
648 _insert_column(targetRep);
651template <
class Master_matrix>
652template <
class Entry_range_or_column_index>
654 const Entry_range_or_column_index& sourceColumn,
656 Index targetColumnIndex)
659 Index targetRep = columnClasses_.find_set(targetColumnIndex);
660 Column& target = *repToColumn_[targetRep];
661 columnToRep_.erase(target);
662 if constexpr (std::is_integral_v<Entry_range_or_column_index>) {
663 target.multiply_target_and_add(coefficient,
get_column(sourceColumn));
665 target.multiply_target_and_add(coefficient, sourceColumn);
667 _insert_column(targetRep);
670template <
class Master_matrix>
671template <
class Entry_range_or_column_index>
674 const Entry_range_or_column_index& sourceColumn,
675 Index targetColumnIndex)
678 Index targetRep = columnClasses_.find_set(targetColumnIndex);
679 Column& target = *repToColumn_[targetRep];
680 columnToRep_.erase(target);
681 if constexpr (std::is_integral_v<Entry_range_or_column_index>) {
682 target.multiply_source_and_add(
get_column(sourceColumn), coefficient);
684 target.multiply_source_and_add(sourceColumn, coefficient);
686 _insert_column(targetRep);
689template <
class Master_matrix>
692 auto col = repToColumn_[columnClasses_.find_set(columnIndex)];
693 if (col ==
nullptr)
return true;
694 return !col->is_non_zero(rowIndex);
697template <
class Master_matrix>
700 auto col = repToColumn_[columnClasses_.find_set(columnIndex)];
701 if (col ==
nullptr)
return true;
702 return col->is_empty();
705template <
class Master_matrix>
709 if (
this == &other)
return *
this;
711 for (
auto col : repToColumn_) {
712 if (col !=
nullptr) {
713 columnPool_->destroy(col);
717 RA_opt::operator=(other);
718 columnClasses_ = other.columnClasses_;
719 columnToRep_.reserve(other.columnToRep_.size());
720 repToColumn_.resize(other.repToColumn_.size(),
nullptr);
721 nextColumnIndex_ = 0;
722 colSettings_ = other.colSettings_;
723 for (
const Column* col : other.repToColumn_) {
724 if constexpr (Master_matrix::Option_list::has_row_access) {
725 repToColumn_[nextColumnIndex_] =
726 columnPool_->construct(*col, col->get_column_index(), RA_opt::_get_rows_ptr(), colSettings_);
728 repToColumn_[nextColumnIndex_] = columnPool_->construct(*col, colSettings_);
730 columnToRep_.insert(columnToRep_.end(), *repToColumn_[nextColumnIndex_]);
731 repToColumn_[nextColumnIndex_]->set_rep(nextColumnIndex_);
737template <
class Master_matrix>
741 if (&repToColumn_ == &(other.repToColumn_))
return *
this;
743 RA_opt::operator=(std::move(other));
745 columnToRep_.clear_and_dispose(Delete_disposer(
this));
747 columnToRep_ = std::move(other.columnToRep_);
748 columnClasses_ = std::move(other.columnClasses_);
749 repToColumn_ = std::move(other.repToColumn_);
750 nextColumnIndex_ = std::exchange(other.nextColumnIndex_, 0);
751 colSettings_ = std::exchange(other.colSettings_,
nullptr);
752 columnPool_ = std::exchange(other.columnPool_,
nullptr);
757template <
class Master_matrix>
758inline void Base_matrix_with_column_compression<Master_matrix>::print()
760 std::cout <<
"Compressed_matrix:\n";
761 for (Column& col : columnToRep_) {
762 for (
auto e : col->get_content(nextColumnIndex_)) {
766 std::cout << e <<
" ";
769 for (Index i = 0; i < nextColumnIndex_; ++i) {
770 if (columnClasses_.find_set(i) == col.get_rep()) std::cout << i <<
" ";
775 std::cout <<
"Row Matrix:\n";
776 for (Index i = 0; i < RA_opt::_get_rows_ptr()->size(); ++i) {
777 const Row& row = RA_opt::get_row(i);
778 for (
const auto& entry : row) {
779 std::cout << entry.get_column_index() <<
" ";
781 std::cout <<
"(" << i <<
")\n";
786template <
class Master_matrix>
788inline void Base_matrix_with_column_compression<Master_matrix>::_initialize_column(F&& get_column)
790 if (repToColumn_.size() == nextColumnIndex_) {
792 columnClasses_.link(nextColumnIndex_, nextColumnIndex_);
793 repToColumn_.push_back(std::forward<F>(get_column)());
795 repToColumn_[nextColumnIndex_] = std::forward<F>(get_column)();
799template <
class Master_matrix>
800inline void Base_matrix_with_column_compression<Master_matrix>::_insert_column(Index columnIndex)
802 Column& col = *repToColumn_[columnIndex];
804 if (col.is_empty()) {
805 columnPool_->destroy(&col);
806 repToColumn_[columnIndex] =
nullptr;
810 col.set_rep(columnIndex);
811 auto res = columnToRep_.insert(col);
812 if (res.first->get_rep() != columnIndex) {
813 _insert_double_column(columnIndex, res.first);
817template <
class Master_matrix>
818inline void Base_matrix_with_column_compression<Master_matrix>::_insert_double_column(
820 typename Col_dict::iterator& doubleIt)
822 Index doubleRep = doubleIt->get_rep();
823 columnClasses_.link(columnIndex, doubleRep);
824 Index newRep = columnClasses_.find_set(columnIndex);
826 columnPool_->destroy(repToColumn_[columnIndex]);
827 repToColumn_[columnIndex] =
nullptr;
829 if (newRep == columnIndex) {
830 std::swap(repToColumn_[doubleRep], repToColumn_[columnIndex]);
831 doubleIt->set_rep(columnIndex);
Type for columns. Only one for each "column class" is explicitly constructed.
Definition Base_matrix_with_column_compression.h:66
A base matrix (also see Base_matrix), but with column compression. That is, all identical columns in ...
Definition Base_matrix_with_column_compression.h:46
typename Master_matrix::Index Index
Definition Base_matrix_with_column_compression.h:48
typename Master_matrix::Row Row
Definition Base_matrix_with_column_compression.h:55
void reset(Column_settings *colSettings)
Resets the matrix to an empty matrix.
Definition Base_matrix_with_column_compression.h:363
typename Master_matrix::Column_settings Column_settings
Definition Base_matrix_with_column_compression.h:58
friend void swap(Base_matrix_with_column_compression &matrix1, Base_matrix_with_column_compression &matrix2) noexcept
Swap operator.
Definition Base_matrix_with_column_compression.h:384
typename Master_matrix::Dimension Dimension
Definition Base_matrix_with_column_compression.h:49
const Row & get_row(Index rowIndex) const
Only available if PersistenceMatrixOptions::has_row_access is true. Returns the row at the given row ...
Definition Base_matrix_with_column_compression.h:612
void add_to(const Entry_range_or_column_index &sourceColumn, Index targetColumnIndex)
Adds column represented by sourceColumn onto the column at targetColumnIndex in the matrix.
Definition Base_matrix_with_column_compression.h:636
Base_matrix_with_column_compression(Column_settings *colSettings)
Constructs an empty matrix.
Definition Base_matrix_with_column_compression.h:437
typename Master_matrix::Field_operators Field_operators
Field operators class. Necessary only if PersistenceMatrixOptions::is_z2 is false.
Definition Base_matrix_with_column_compression.h:53
bool is_zero_column(Index columnIndex)
Indicates if the column at given index has value zero.
Definition Base_matrix_with_column_compression.h:698
Index get_number_of_columns() const
Returns the current number of columns in the matrix, counting also the redundant columns.
Definition Base_matrix_with_column_compression.h:629
void multiply_source_and_add_to(const Field_element &coefficient, const Entry_range_or_column_index &sourceColumn, Index targetColumnIndex)
Multiplies the source column with the coefficient before adding it to the target column....
Definition Base_matrix_with_column_compression.h:672
void multiply_target_and_add_to(const Entry_range_or_column_index &sourceColumn, const Field_element &coefficient, Index targetColumnIndex)
Multiplies the target column with the coefficient and then adds the source column to it....
Definition Base_matrix_with_column_compression.h:653
~Base_matrix_with_column_compression()
Destructor.
Definition Base_matrix_with_column_compression.h:513
void erase_empty_row(Index rowIndex)
If PersistenceMatrixOptions::has_row_access and PersistenceMatrixOptions::has_removable_rows are true...
Definition Base_matrix_with_column_compression.h:620
typename Master_matrix::Entry_constructor Entry_constructor
Definition Base_matrix_with_column_compression.h:57
typename Master_matrix::Element Field_element
Definition Base_matrix_with_column_compression.h:54
const Column & get_column(Index columnIndex)
Returns the column at the given MatIdx index. The type of the column depends on the chosen options,...
Definition Base_matrix_with_column_compression.h:603
void insert_boundary(const Boundary_range &boundary, Dimension dim=Master_matrix::template get_null_value< Dimension >())
Same as insert_column, only for interface purposes. The given dimension is ignored and not stored.
Definition Base_matrix_with_column_compression.h:574
void insert_column(const Container &column)
Inserts a new ordered column at the end of the matrix by copying the given range of Matrix::Entry_rep...
Definition Base_matrix_with_column_compression.h:520
Base_matrix_with_column_compression & operator=(const Base_matrix_with_column_compression &other)
Assign operator.
Definition Base_matrix_with_column_compression.h:707
bool is_zero_entry(Index columnIndex, Index rowIndex)
Indicates if the entry at given coordinates has value zero.
Definition Base_matrix_with_column_compression.h:690
Persistence matrix namespace.
Definition FieldOperators.h:18
Gudhi namespace.
Definition SimplicialComplexForAlpha.h:14