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>
30namespace persistence_matrix {
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;
65 :
public Master_matrix::Column,
66 public boost::intrusive::set_base_hook<boost::intrusive::link_mode<boost::intrusive::normal_link> >
69 using Base =
typename Master_matrix::Column;
72 : Base(colSettings) {}
73 template <
class Container>
75 : Base(nonZeroRowIndices, colSettings) {}
76 template <
class Container,
class Row_container>
77 Column(
Index columnIndex,
const Container& nonZeroRowIndices, Row_container& rowContainer,
79 : Base(columnIndex, nonZeroRowIndices, rowContainer, colSettings) {}
80 template <
class Container>
82 : Base(nonZeroRowIndices, dimension, colSettings) {}
83 template <
class Container,
class Row_container>
86 : Base(columnIndex, nonZeroRowIndices, dimension, rowContainer, colSettings) {}
88 : Base(
static_cast<const Base&
>(column), colSettings) {}
89 template <
class Row_container>
92 : Base(
static_cast<const Base&
>(column), columnIndex, rowContainer, colSettings) {}
93 Column(
Column&& column) noexcept : Base(std::move(
static_cast<Base&
>(column))) {}
99 Index get_rep()
const {
return rep_; }
100 void set_rep(
const Index& rep) { rep_ = rep; }
103 size_t operator()(
const Column& c)
const {
return std::hash<Base>()(
static_cast<Base
>(c)); }
129 template <
class Container>
171 template <
class Container>
182 template <
class Boundary_range>
184 Dimension dim = Master_matrix::template get_null_value<Dimension>());
239 template <
class Entry_range_or_column_index>
240 void add_to(
const Entry_range_or_column_index& sourceColumn,
Index targetColumnIndex);
254 template <
class Entry_range_or_column_index>
257 Index targetColumnIndex);
271 template <
class Entry_range_or_column_index>
273 const Entry_range_or_column_index& sourceColumn,
274 Index targetColumnIndex);
300 columnToRep_.clear_and_dispose(Delete_disposer(
this));
301 columnClasses_ = boost::disjoint_sets_with_storage<>();
302 repToColumn_.clear();
303 nextColumnIndex_ = 0;
304 colSettings_ = colSettings;
315 matrix1.columnToRep_.swap(matrix2.columnToRep_);
316 std::swap(matrix1.columnClasses_, matrix2.columnClasses_);
317 matrix1.repToColumn_.swap(matrix2.repToColumn_);
318 std::swap(matrix1.nextColumnIndex_, matrix2.nextColumnIndex_);
319 std::swap(matrix1.colSettings_, matrix2.colSettings_);
320 std::swap(matrix1.columnPool_, matrix2.columnPool_);
322 if constexpr (Master_matrix::Option_list::has_row_access) {
323 swap(
static_cast<typename Master_matrix::Matrix_row_access_option&
>(matrix1),
324 static_cast<typename Master_matrix::Matrix_row_access_option&
>(matrix2));
334 struct Delete_disposer {
337 void operator()(Column* delete_this) { matrix_->columnPool_->destroy(delete_this); }
342 using RA_opt =
typename Master_matrix::Matrix_row_access_option;
343 using Col_dict = boost::intrusive::set<Column, boost::intrusive::constant_time_size<false> >;
345 Col_dict columnToRep_;
346 boost::disjoint_sets_with_storage<> columnClasses_;
348 std::vector<Column*> repToColumn_;
350 Index nextColumnIndex_;
356 std::unique_ptr<Simple_object_pool<Column> > columnPool_;
357 inline static const Column empty_column_;
359 void _insert_column(Index columnIndex);
360 void _insert_double_column(Index columnIndex,
typename Col_dict::iterator& doubleIt);
363template <
class Master_matrix>
366 : RA_opt(), nextColumnIndex_(0), colSettings_(colSettings), columnPool_(new Simple_object_pool<
Column>)
369template <
class Master_matrix>
370template <
class Container>
373 : RA_opt(columns.size()),
374 columnClasses_(columns.size()),
375 repToColumn_(columns.size(), nullptr),
377 colSettings_(colSettings),
378 columnPool_(new Simple_object_pool<
Column>)
380 for (
const Container& c : columns) {
385template <
class Master_matrix>
388 : RA_opt(numberOfColumns),
389 columnClasses_(numberOfColumns),
390 repToColumn_(numberOfColumns, nullptr),
392 colSettings_(colSettings),
393 columnPool_(new Simple_object_pool<
Column>)
396template <
class Master_matrix>
399 : RA_opt(static_cast<const RA_opt&>(matrixToCopy)),
400 columnClasses_(matrixToCopy.columnClasses_),
401 repToColumn_(matrixToCopy.repToColumn_.size(), nullptr),
403 colSettings_(colSettings == nullptr ? matrixToCopy.colSettings_ : colSettings),
404 columnPool_(new Simple_object_pool<
Column>)
406 for (
const Column* col : matrixToCopy.repToColumn_) {
407 if (col !=
nullptr) {
408 if constexpr (Master_matrix::Option_list::has_row_access) {
409 repToColumn_[nextColumnIndex_] =
410 columnPool_->construct(*col, col->get_column_index(), RA_opt::rows_, colSettings_);
412 repToColumn_[nextColumnIndex_] = columnPool_->construct(*col, colSettings_);
414 columnToRep_.insert(columnToRep_.end(), *repToColumn_[nextColumnIndex_]);
415 repToColumn_[nextColumnIndex_]->set_rep(nextColumnIndex_);
421template <
class Master_matrix>
424 : RA_opt(std::move(
static_cast<RA_opt&
>(other))),
425 columnToRep_(std::move(other.columnToRep_)),
426 columnClasses_(std::move(other.columnClasses_)),
427 repToColumn_(std::move(other.repToColumn_)),
428 nextColumnIndex_(std::exchange(other.nextColumnIndex_, 0)),
429 colSettings_(std::exchange(other.colSettings_,
nullptr)),
430 columnPool_(std::exchange(other.columnPool_,
nullptr))
433template <
class Master_matrix>
436 columnToRep_.clear_and_dispose(Delete_disposer(
this));
439template <
class Master_matrix>
440template <
class Container>
443 insert_boundary(column);
446template <
class Master_matrix>
447template <
class Boundary_range>
454 if (dim == Master_matrix::template get_null_value<Dimension>()) dim = boundary.size() == 0 ? 0 : boundary.size() - 1;
456 if constexpr (Master_matrix::Option_list::has_row_access && !Master_matrix::Option_list::has_removable_rows) {
457 if (boundary.begin() != boundary.end()) {
459 if constexpr (Master_matrix::Option_list::is_z2) {
460 pivot = *std::prev(boundary.end());
462 pivot = std::prev(boundary.end())->first;
464 if (RA_opt::rows_->size() <= pivot) RA_opt::rows_->resize(pivot + 1);
468 if (repToColumn_.size() == nextColumnIndex_) {
470 columnClasses_.link(nextColumnIndex_, nextColumnIndex_);
471 if constexpr (Master_matrix::Option_list::has_row_access) {
472 repToColumn_.push_back(
473 columnPool_->construct(nextColumnIndex_, boundary, dim, RA_opt::rows_, colSettings_));
475 repToColumn_.push_back(columnPool_->construct(boundary, dim, colSettings_));
478 if constexpr (Master_matrix::Option_list::has_row_access) {
479 repToColumn_[nextColumnIndex_] =
480 columnPool_->construct(nextColumnIndex_, boundary, dim, RA_opt::rows_, colSettings_);
482 repToColumn_[nextColumnIndex_] = columnPool_->construct(boundary, dim, colSettings_);
485 _insert_column(nextColumnIndex_);
490template <
class Master_matrix>
494 auto col = repToColumn_[columnClasses_.find_set(columnIndex)];
495 if (col ==
nullptr)
return empty_column_;
499template <
class Master_matrix>
503 static_assert(Master_matrix::Option_list::has_row_access,
"Row access has to be enabled for this method.");
505 return RA_opt::get_row(rowIndex);
508template <
class Master_matrix>
511 if constexpr (Master_matrix::Option_list::has_row_access && Master_matrix::Option_list::has_removable_rows) {
512 RA_opt::erase_empty_row(rowIndex);
516template <
class Master_matrix>
520 return nextColumnIndex_;
523template <
class Master_matrix>
524template <
class Entry_range_or_column_index>
526 Index targetColumnIndex)
529 Index targetRep = columnClasses_.find_set(targetColumnIndex);
530 Column& target = *repToColumn_[targetRep];
531 columnToRep_.erase(target);
532 if constexpr (std::is_integral_v<Entry_range_or_column_index>) {
533 target += get_column(sourceColumn);
535 target += sourceColumn;
537 _insert_column(targetRep);
540template <
class Master_matrix>
541template <
class Entry_range_or_column_index>
543 const Entry_range_or_column_index& sourceColumn,
const Field_element& coefficient,
Index targetColumnIndex)
546 Index targetRep = columnClasses_.find_set(targetColumnIndex);
547 Column& target = *repToColumn_[targetRep];
548 columnToRep_.erase(target);
549 if constexpr (std::is_integral_v<Entry_range_or_column_index>) {
550 target.multiply_target_and_add(coefficient, get_column(sourceColumn));
552 target.multiply_target_and_add(coefficient, sourceColumn);
554 _insert_column(targetRep);
557template <
class Master_matrix>
558template <
class Entry_range_or_column_index>
560 const Field_element& coefficient,
const Entry_range_or_column_index& sourceColumn,
Index targetColumnIndex)
563 Index targetRep = columnClasses_.find_set(targetColumnIndex);
564 Column& target = *repToColumn_[targetRep];
565 columnToRep_.erase(target);
566 if constexpr (std::is_integral_v<Entry_range_or_column_index>) {
567 target.multiply_source_and_add(get_column(sourceColumn), coefficient);
569 target.multiply_source_and_add(sourceColumn, coefficient);
571 _insert_column(targetRep);
574template <
class Master_matrix>
577 auto col = repToColumn_[columnClasses_.find_set(columnIndex)];
578 if (col ==
nullptr)
return true;
579 return !col->is_non_zero(rowIndex);
582template <
class Master_matrix>
585 auto col = repToColumn_[columnClasses_.find_set(columnIndex)];
586 if (col ==
nullptr)
return true;
587 return col->is_empty();
590template <
class Master_matrix>
594 for (
auto col : repToColumn_) {
595 if (col !=
nullptr) {
596 columnPool_->destroy(col);
600 RA_opt::operator=(other);
601 columnClasses_ = other.columnClasses_;
602 columnToRep_.reserve(other.columnToRep_.size());
603 repToColumn_.resize(other.repToColumn_.size(),
nullptr);
604 nextColumnIndex_ = 0;
605 colSettings_ = other.colSettings_;
606 for (
const Column* col : other.repToColumn_) {
607 if constexpr (Master_matrix::Option_list::has_row_access) {
608 repToColumn_[nextColumnIndex_] =
609 columnPool_->construct(*col, col->get_column_index(), RA_opt::rows_, colSettings_);
611 repToColumn_[nextColumnIndex_] = columnPool_->construct(*col, colSettings_);
613 columnToRep_.insert(columnToRep_.end(), *repToColumn_[nextColumnIndex_]);
614 repToColumn_[nextColumnIndex_]->set_rep(nextColumnIndex_);
620template <
class Master_matrix>
623 std::cout <<
"Compressed_matrix:\n";
624 for (Column& col : columnToRep_) {
625 for (
auto e : col->get_content(nextColumnIndex_)) {
629 std::cout << e <<
" ";
632 for (Index i = 0; i < nextColumnIndex_; ++i) {
633 if (columnClasses_.find_set(i) == col.get_rep()) std::cout << i <<
" ";
638 std::cout <<
"Row Matrix:\n";
639 for (Index i = 0; i < RA_opt::rows_->size(); ++i) {
640 const Row& row = RA_opt::rows_[i];
641 for (
const auto& entry : row) {
642 std::cout << entry.get_column_index() <<
" ";
644 std::cout <<
"(" << i <<
")\n";
649template <
class Master_matrix>
650inline void Base_matrix_with_column_compression<Master_matrix>::_insert_column(Index columnIndex)
652 Column& col = *repToColumn_[columnIndex];
654 if (col.is_empty()) {
655 columnPool_->destroy(&col);
656 repToColumn_[columnIndex] =
nullptr;
660 col.set_rep(columnIndex);
661 auto res = columnToRep_.insert(col);
662 if (res.first->get_rep() != columnIndex) {
663 _insert_double_column(columnIndex, res.first);
667template <
class Master_matrix>
668inline void Base_matrix_with_column_compression<Master_matrix>::_insert_double_column(
669 Index columnIndex,
typename Col_dict::iterator& doubleIt)
671 Index doubleRep = doubleIt->get_rep();
672 columnClasses_.link(columnIndex, doubleRep);
673 Index newRep = columnClasses_.find_set(columnIndex);
675 columnPool_->destroy(repToColumn_[columnIndex]);
676 repToColumn_[columnIndex] =
nullptr;
678 if (newRep == columnIndex) {
679 std::swap(repToColumn_[doubleRep], repToColumn_[columnIndex]);
680 doubleIt->set_rep(columnIndex);
Type for columns. Only one for each "column class" is explicitly constructed.
Definition: Base_matrix_with_column_compression.h:67
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:56
void reset(Column_settings *colSettings)
Resets the matrix to an empty matrix.
Definition: Base_matrix_with_column_compression.h:299
typename Master_matrix::Column_settings Column_settings
Definition: Base_matrix_with_column_compression.h:59
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:501
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:525
Base_matrix_with_column_compression(Column_settings *colSettings)
Constructs an empty matrix.
Definition: Base_matrix_with_column_compression.h:364
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:583
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:518
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:559
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:542
friend void swap(Base_matrix_with_column_compression &matrix1, Base_matrix_with_column_compression &matrix2)
Swap operator.
Definition: Base_matrix_with_column_compression.h:314
~Base_matrix_with_column_compression()
Destructor.
Definition: Base_matrix_with_column_compression.h:434
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:441
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:509
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:492
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:448
Base_matrix_with_column_compression & operator=(const Base_matrix_with_column_compression &other)
Assign operator.
Definition: Base_matrix_with_column_compression.h:592
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:575
Gudhi namespace.
Definition: SimplicialComplexForAlpha.h:14