From 1e3b0a5121aa2a353f2ab4e9d6b4b7e9d0ab9df8 Mon Sep 17 00:00:00 2001 From: hschreiber Date: Fri, 19 Dec 2025 14:33:13 +0100 Subject: [PATCH 1/3] c++ matrix update --- multipers/gudhi/gudhi/Fields/Multi_field.h | 28 +- .../gudhi/Fields/Multi_field_operators.h | 10 +- .../gudhi/gudhi/Fields/Multi_field_shared.h | 28 +- .../gudhi/gudhi/Fields/Multi_field_small.h | 34 +- .../Fields/Multi_field_small_operators.h | 10 +- .../gudhi/Fields/Multi_field_small_shared.h | 32 +- multipers/gudhi/gudhi/Fields/Z2_field.h | 2 + multipers/gudhi/gudhi/Fields/Zp_field.h | 2 + .../gudhi/gudhi/Fields/Zp_field_shared.h | 2 + multipers/gudhi/gudhi/Matrix.h | 212 ++++- .../gudhi/Persistence_matrix/Base_matrix.h | 131 ++- .../Base_matrix_with_column_compression.h | 135 +++- .../Persistence_matrix/Boundary_matrix.h | 10 +- .../gudhi/Persistence_matrix/Chain_matrix.h | 80 +- .../Persistence_matrix/Id_to_index_overlay.h | 33 +- .../Position_to_index_overlay.h | 33 +- .../gudhi/Persistence_matrix/RU_matrix.h | 53 +- .../allocators/entry_constructors.h | 3 +- .../gudhi/Persistence_matrix/base_pairing.h | 36 +- .../gudhi/Persistence_matrix/base_swap.h | 2 + .../Persistence_matrix/chain_rep_cycles.h | 126 ++- .../columns/chain_column_extra_properties.h | 2 + .../columns/column_dimension_holder.h | 2 + .../columns/column_utilities.h | 111 +-- .../Persistence_matrix/columns/entry_types.h | 11 +- .../Persistence_matrix/columns/heap_column.h | 654 +++++++-------- .../columns/intrusive_list_column.h | 442 +++++------ .../columns/intrusive_set_column.h | 448 +++++------ .../Persistence_matrix/columns/list_column.h | 490 +++++------- .../columns/naive_vector_column.h | 645 +++++++-------- .../Persistence_matrix/columns/set_column.h | 445 +++++------ .../columns/unordered_set_column.h | 537 ++++++------- .../columns/vector_column.h | 750 ++++++++---------- .../matrix_dimension_holders.h | 4 + .../Persistence_matrix/matrix_row_access.h | 2 + .../gudhi/Persistence_matrix/ru_rep_cycles.h | 185 ++--- .../gudhi/Persistence_matrix/ru_vine_swap.h | 52 +- .../gudhi/gudhi/persistence_matrix_options.h | 37 +- 38 files changed, 2794 insertions(+), 3025 deletions(-) diff --git a/multipers/gudhi/gudhi/Fields/Multi_field.h b/multipers/gudhi/gudhi/Fields/Multi_field.h index b967dc31..3df57b9c 100644 --- a/multipers/gudhi/gudhi/Fields/Multi_field.h +++ b/multipers/gudhi/gudhi/Fields/Multi_field.h @@ -22,6 +22,8 @@ #include #include +#include + namespace Gudhi { namespace persistence_fields { @@ -258,14 +260,14 @@ class Multi_field_element */ friend bool operator!=(const Multi_field_element& f, const Element& v) { return !(v == f); } - /** - * @brief Assign operator. - */ - Multi_field_element& operator=(const Element& value) - { - mpz_mod(element_.get_mpz_t(), value.get_mpz_t(), productOfAllCharacteristics_.get_mpz_t()); - return *this; - } + // /** + // * @brief Assign operator. + // */ + // Multi_field_element& operator=(const Element& value) + // { + // mpz_mod(element_.get_mpz_t(), value.get_mpz_t(), productOfAllCharacteristics_.get_mpz_t()); + // return *this; + // } /** * @brief Swap operator. @@ -302,6 +304,9 @@ class Multi_field_element [[nodiscard]] std::pair get_partial_inverse( const Characteristic& productOfCharacteristics) const { + GUDHI_CHECK(productOfCharacteristics >= 0 && productOfCharacteristics <= productOfAllCharacteristics_, + "The given product is not the product of a subset of the current Multi-field characteristics."); + Characteristic QR; mpz_gcd(QR.get_mpz_t(), element_.get_mpz_t(), productOfCharacteristics.get_mpz_t()); // QR <- gcd(x,QS) @@ -344,8 +349,11 @@ class Multi_field_element */ static Multi_field_element get_partial_multiplicative_identity(const Characteristic& productOfCharacteristics) { - if (productOfCharacteristics == 0) { - return Multi_field_element(multiplicativeID_); + GUDHI_CHECK(productOfCharacteristics >= 0 && productOfCharacteristics <= productOfAllCharacteristics_, + "The given product is not the product of a subset of the current Multi-field characteristics."); + + if (productOfCharacteristics == 0 || productOfCharacteristics == productOfAllCharacteristics_) { + return get_multiplicative_identity(); } Multi_field_element mult; for (unsigned int idx = 0; idx < primes_.size(); ++idx) { diff --git a/multipers/gudhi/gudhi/Fields/Multi_field_operators.h b/multipers/gudhi/gudhi/Fields/Multi_field_operators.h index 81dd0897..22dfd1cc 100644 --- a/multipers/gudhi/gudhi/Fields/Multi_field_operators.h +++ b/multipers/gudhi/gudhi/Fields/Multi_field_operators.h @@ -22,6 +22,8 @@ #include #include +#include + namespace Gudhi { namespace persistence_fields { @@ -363,6 +365,9 @@ class Multi_field_operators const Element& e, const Characteristic& productOfCharacteristics) const { + GUDHI_CHECK(productOfCharacteristics >= 0 && productOfCharacteristics <= productOfAllCharacteristics_, + "The given product is not the product of a subset of the current Multi-field characteristics."); + Characteristic QR; mpz_gcd(QR.get_mpz_t(), e.get_mpz_t(), productOfCharacteristics.get_mpz_t()); // QR <- gcd(x,QS) @@ -403,7 +408,10 @@ class Multi_field_operators */ [[nodiscard]] Element get_partial_multiplicative_identity(const Characteristic& productOfCharacteristics) const { - if (productOfCharacteristics == nullCharacteristic) { + GUDHI_CHECK(productOfCharacteristics >= 0 && productOfCharacteristics <= productOfAllCharacteristics_, + "The given product is not the product of a subset of the current Multi-field characteristics."); + + if (productOfCharacteristics == nullCharacteristic || productOfCharacteristics == productOfAllCharacteristics_) { return get_multiplicative_identity(); } Element multIdentity(0); diff --git a/multipers/gudhi/gudhi/Fields/Multi_field_shared.h b/multipers/gudhi/gudhi/Fields/Multi_field_shared.h index 05ebbecb..cb48c7b0 100644 --- a/multipers/gudhi/gudhi/Fields/Multi_field_shared.h +++ b/multipers/gudhi/gudhi/Fields/Multi_field_shared.h @@ -22,6 +22,8 @@ #include #include +#include + namespace Gudhi { namespace persistence_fields { @@ -297,14 +299,14 @@ class Shared_multi_field_element */ friend bool operator!=(const Shared_multi_field_element& f, const Element& v) { return !(v == f); } - /** - * @brief Assign operator. - */ - Shared_multi_field_element& operator=(const Element& value) - { - mpz_mod(element_.get_mpz_t(), value.get_mpz_t(), productOfAllCharacteristics_.get_mpz_t()); - return *this; - } + // /** + // * @brief Assign operator. + // */ + // Shared_multi_field_element& operator=(const Element& value) + // { + // mpz_mod(element_.get_mpz_t(), value.get_mpz_t(), productOfAllCharacteristics_.get_mpz_t()); + // return *this; + // } /** * @brief Swap operator. @@ -344,6 +346,9 @@ class Shared_multi_field_element [[nodiscard]] std::pair get_partial_inverse( const Characteristic& productOfCharacteristics) const { + GUDHI_CHECK(productOfCharacteristics >= 0 && productOfCharacteristics <= productOfAllCharacteristics_, + "The given product is not the product of a subset of the current Multi-field characteristics."); + Element QR; mpz_gcd(QR.get_mpz_t(), element_.get_mpz_t(), productOfCharacteristics.get_mpz_t()); // QR <- gcd(x,QS) @@ -384,8 +389,11 @@ class Shared_multi_field_element */ static Shared_multi_field_element get_partial_multiplicative_identity(const Characteristic& productOfCharacteristics) { - if (productOfCharacteristics == 0) { - return {multiplicativeID_}; + GUDHI_CHECK(productOfCharacteristics >= 0 && productOfCharacteristics <= productOfAllCharacteristics_, + "The given product is not the product of a subset of the current Multi-field characteristics."); + + if (productOfCharacteristics == 0 || productOfCharacteristics == productOfAllCharacteristics_) { + return get_multiplicative_identity(); } Shared_multi_field_element mult; for (unsigned int idx = 0; idx < primes_.size(); ++idx) { diff --git a/multipers/gudhi/gudhi/Fields/Multi_field_small.h b/multipers/gudhi/gudhi/Fields/Multi_field_small.h index 49098865..432eef1b 100644 --- a/multipers/gudhi/gudhi/Fields/Multi_field_small.h +++ b/multipers/gudhi/gudhi/Fields/Multi_field_small.h @@ -22,6 +22,8 @@ #include #include +#include + namespace Gudhi { namespace persistence_fields { @@ -304,17 +306,17 @@ class Multi_field_element_with_small_characteristics return !(v == f); } - /** - * @brief Assign operator. - * - * @tparam Integer_type A native integer type. Should be able to contain the characteristic if signed. - */ - template > - Multi_field_element_with_small_characteristics& operator=(const Integer_type& value) - { - element_ = _get_value(value); - return *this; - } + // /** + // * @brief Assign operator. + // * + // * @tparam Integer_type A native integer type. Should be able to contain the characteristic if signed. + // */ + // template > + // Multi_field_element_with_small_characteristics& operator=(const Integer_type& value) + // { + // element_ = _get_value(value); + // return *this; + // } /** * @brief Swap operator. @@ -350,6 +352,9 @@ class Multi_field_element_with_small_characteristics std::pair get_partial_inverse( Characteristic productOfCharacteristics) const { + GUDHI_CHECK(productOfCharacteristics >= 0 && productOfCharacteristics <= productOfAllCharacteristics_, + "The given product is not the product of a subset of the current Multi-field characteristics."); + Characteristic gcd = std::gcd(element_, productOfAllCharacteristics_); if (gcd == productOfCharacteristics) @@ -395,8 +400,11 @@ class Multi_field_element_with_small_characteristics static Multi_field_element_with_small_characteristics get_partial_multiplicative_identity( const Characteristic& productOfCharacteristics) { - if (productOfCharacteristics == 0) { - return Multi_field_element_with_small_characteristics(multiplicativeID_); + GUDHI_CHECK(productOfCharacteristics >= 0 && productOfCharacteristics <= productOfAllCharacteristics_, + "The given product is not the product of a subset of the current Multi-field characteristics."); + + if (productOfCharacteristics == 0 || productOfCharacteristics == productOfAllCharacteristics_) { + return get_multiplicative_identity(); } Multi_field_element_with_small_characteristics mult; for (Characteristic idx = 0; idx < primes_.size(); ++idx) { diff --git a/multipers/gudhi/gudhi/Fields/Multi_field_small_operators.h b/multipers/gudhi/gudhi/Fields/Multi_field_small_operators.h index 94fbb22d..15e1534a 100644 --- a/multipers/gudhi/gudhi/Fields/Multi_field_small_operators.h +++ b/multipers/gudhi/gudhi/Fields/Multi_field_small_operators.h @@ -23,6 +23,8 @@ #include #include +#include + namespace Gudhi { namespace persistence_fields { @@ -324,6 +326,9 @@ class Multi_field_operators_with_small_characteristics std::pair get_partial_inverse(const Element& e, const Characteristic& productOfCharacteristics) const { + GUDHI_CHECK(productOfCharacteristics >= 0 && productOfCharacteristics <= productOfAllCharacteristics_, + "The given product is not the product of a subset of the current Multi-field characteristics."); + Characteristic gcd = std::gcd(e, productOfAllCharacteristics_); if (gcd == productOfCharacteristics) return {0, get_multiplicative_identity()}; // partial inverse is 0 @@ -362,7 +367,10 @@ class Multi_field_operators_with_small_characteristics */ [[nodiscard]] Element get_partial_multiplicative_identity(const Characteristic& productOfCharacteristics) const { - if (productOfCharacteristics == nullCharacteristic) { + GUDHI_CHECK(productOfCharacteristics >= 0 && productOfCharacteristics <= productOfAllCharacteristics_, + "The given product is not the product of a subset of the current Multi-field characteristics."); + + if (productOfCharacteristics == nullCharacteristic || productOfCharacteristics == productOfAllCharacteristics_) { return get_multiplicative_identity(); } Element multIdentity = 0; diff --git a/multipers/gudhi/gudhi/Fields/Multi_field_small_shared.h b/multipers/gudhi/gudhi/Fields/Multi_field_small_shared.h index da1025ac..a57a6d77 100644 --- a/multipers/gudhi/gudhi/Fields/Multi_field_small_shared.h +++ b/multipers/gudhi/gudhi/Fields/Multi_field_small_shared.h @@ -23,6 +23,8 @@ #include #include +#include + namespace Gudhi { namespace persistence_fields { @@ -346,17 +348,17 @@ class Shared_multi_field_element_with_small_characteristics return !(v == f); } - /** - * @brief Assign operator. - * - * @tparam Integer_type A native integer type. Should be able to contain the characteristic if signed. - */ - template > - Shared_multi_field_element_with_small_characteristics& operator=(const Integer_type& value) - { - element_ = _get_value(value); - return *this; - } + // /** + // * @brief Assign operator. + // * + // * @tparam Integer_type A native integer type. Should be able to contain the characteristic if signed. + // */ + // template > + // Shared_multi_field_element_with_small_characteristics& operator=(const Integer_type& value) + // { + // element_ = _get_value(value); + // return *this; + // } /** * @brief Swap operator. @@ -392,6 +394,9 @@ class Shared_multi_field_element_with_small_characteristics std::pair get_partial_inverse( Characteristic productOfCharacteristics) const { + GUDHI_CHECK(productOfCharacteristics >= 0 && productOfCharacteristics <= productOfAllCharacteristics_, + "The given product is not the product of a subset of the current Multi-field characteristics."); + Characteristic gcd = std::gcd(element_, productOfAllCharacteristics_); if (gcd == productOfCharacteristics) @@ -437,7 +442,10 @@ class Shared_multi_field_element_with_small_characteristics static Shared_multi_field_element_with_small_characteristics get_partial_multiplicative_identity( const Characteristic& productOfCharacteristics) { - if (productOfCharacteristics == 0) { + GUDHI_CHECK(productOfCharacteristics >= 0 && productOfCharacteristics <= productOfAllCharacteristics_, + "The given product is not the product of a subset of the current Multi-field characteristics."); + + if (productOfCharacteristics == 0 || productOfCharacteristics == productOfAllCharacteristics_) { return Shared_multi_field_element_with_small_characteristics(multiplicativeID_); } Shared_multi_field_element_with_small_characteristics mult; diff --git a/multipers/gudhi/gudhi/Fields/Z2_field.h b/multipers/gudhi/gudhi/Fields/Z2_field.h index 85593f4f..18e309d6 100644 --- a/multipers/gudhi/gudhi/Fields/Z2_field.h +++ b/multipers/gudhi/gudhi/Fields/Z2_field.h @@ -287,6 +287,8 @@ class Z2_field_element */ Z2_field_element& operator=(Z2_field_element&& other) noexcept { + if (this == &other) return *this; + element_ = std::exchange(other.element_, false); return *this; } diff --git a/multipers/gudhi/gudhi/Fields/Zp_field.h b/multipers/gudhi/gudhi/Fields/Zp_field.h index e5e2216f..4998d4ec 100644 --- a/multipers/gudhi/gudhi/Fields/Zp_field.h +++ b/multipers/gudhi/gudhi/Fields/Zp_field.h @@ -295,6 +295,8 @@ class Zp_field_element */ Zp_field_element& operator=(Zp_field_element&& other) noexcept { + if (this == &other) return *this; + element_ = std::exchange(other.element_, 0); return *this; } diff --git a/multipers/gudhi/gudhi/Fields/Zp_field_shared.h b/multipers/gudhi/gudhi/Fields/Zp_field_shared.h index 09143489..ddc29db7 100644 --- a/multipers/gudhi/gudhi/Fields/Zp_field_shared.h +++ b/multipers/gudhi/gudhi/Fields/Zp_field_shared.h @@ -338,6 +338,8 @@ class Shared_Zp_field_element */ Shared_Zp_field_element& operator=(Shared_Zp_field_element&& other) noexcept { + if (this == &other) return *this; + element_ = std::exchange(other.element_, 0); return *this; } diff --git a/multipers/gudhi/gudhi/Matrix.h b/multipers/gudhi/gudhi/Matrix.h index 87f6a17f..82d043e0 100644 --- a/multipers/gudhi/gudhi/Matrix.h +++ b/multipers/gudhi/gudhi/Matrix.h @@ -242,6 +242,54 @@ class Matrix using Entry_representative = std::conditional_t >; + /** + * @private + */ + static ID_index get_row_index(const Matrix_entry& e) + { + return e.get_row_index(); + } + /** + * @private + */ + static ID_index get_row_index(const Entry_representative& e) + { + if constexpr (PersistenceMatrixOptions::is_z2) { + return e; + } else { + return e.first; + } + } + /** + * @private + */ + static ID_index& get_row_index(Entry_representative& e) + { + if constexpr (PersistenceMatrixOptions::is_z2) { + return e; + } else { + return e.first; + } + } + /** + * @private + */ + static Element get_element(const Matrix_entry& e) + { + return e.get_element(); + } + /** + * @private + */ + static Element get_element(const Entry_representative& e) + { + if constexpr (PersistenceMatrixOptions::is_z2) { + return Field_operators::get_multiplicative_identity(); + } else { + return e.second; + } + } + /** * @brief Compares two entries by their position in the row. They are assume to be in the same row. */ @@ -359,6 +407,8 @@ class Matrix } Column_zp_settings& operator=(Column_zp_settings&& other) noexcept { + if (this == &other) return *this; + operators = std::move(other.operators); return *this; } @@ -389,6 +439,35 @@ class Matrix // To prepare a more flexible use of the column types later (custom allocators depending on the column type etc.) using Column_settings = std::conditional_t; + /** + * @private + */ + static Field_operators const* get_operator_ptr(Column_settings const* colSettings) + { + if constexpr (PersistenceMatrixOptions::is_z2) { + return nullptr; + } else { + if (colSettings == nullptr) return nullptr; // used for dummy columns + return &(colSettings->operators); + } + } + /** + * @private + */ + template + static Element get_coefficient_value(T v, [[maybe_unused]] Field_operators const* operators) + { + if constexpr (PersistenceMatrixOptions::is_z2) { + return Field_operators::get_value(v); + } else { + return operators->get_value(v); + } + } + /** + * @private + */ + static Element get_coefficient_value(bool v, [[maybe_unused]] Field_operators const* operators) { return v; } + // using Column_settings = typename std::conditional< // PersistenceMatrixOptions::is_z2, // typename std::conditional; + /** + * @private + */ + template + static Cycle build_cycle_from_range(const EntryRange& entries) + { + Cycle cycle; + if constexpr (RangeTraits::has_size) { + cycle.reserve(entries.size()); + } + for (const auto& c : entries) { + if constexpr (PersistenceMatrixOptions::is_z2) { + cycle.push_back(c.get_row_index()); + } else { + cycle.push_back({c.get_row_index(), c.get_element()}); + } + } + return cycle; + } + // Return types to factorize the corresponding methods // The returned column is `const` if the matrix uses column compression @@ -673,7 +772,7 @@ class Matrix * @tparam Container Range of @ref Entry_representative. Assumed to have a begin(), end() and size() method. * @param column Column to be inserted. */ - template + template > > void insert_column(const Container& column); /** * @brief Inserts a new ordered column at the given index by copying the given range of @ref Entry_representative. @@ -686,8 +785,15 @@ class Matrix * @param column Column to be inserted. * @param columnIndex @ref MatIdx index to which the column has to be inserted. */ - template + template > > void insert_column(const Container& column, Index columnIndex); + /** + * @brief Inserts a new column at the end of the matrix. The column will consist of the given index only. + * + * @param idx Entry ID. + * @param e Entry coefficient. Ignored if the coefficient field is Z2. Default value: 1. + */ + void insert_column(ID_index idx, Element e = 1U); // TODO: for simple boundary matrices, add an index pointing to the first column inserted after the last call of // get_current_barcode to enable several calls to get_current_barcode /** @@ -1303,25 +1409,38 @@ class Matrix */ Index vine_swap(Index columnIndex1, Index columnIndex2); - // TODO: Rethink the interface for representative cycles /** * @brief Only available if @ref PersistenceMatrixOptions::can_retrieve_representative_cycles is true. Pre-computes - * the representative cycles of the current state of the filtration represented by the matrix. It does not need to be - * called before @ref get_representative_cycles is called for the first time, but needs to be called before calling - * @ref get_representative_cycles again if the matrix was modified in between. Otherwise the old cycles will be - * returned. + * the representative cycles of the current state of the filtration represented by the matrix. It needs to be called + * before calling @ref get_representative_cycles if the matrix was modified since last call. Otherwise the old cycles + * will be returned. + * + * @param dim If different from default value, only the cycles of the given dimension are updated. + * All others are erased. + */ + void update_representative_cycles(Dimension dim = get_null_value()); + /** + * @brief Only available if @ref PersistenceMatrixOptions::can_retrieve_representative_cycles is true. Pre-computes + * the representative cycle in the current matrix state of the given bar. It needs to be called + * before calling @ref get_representative_cycle if the matrix was modified since last call. Otherwise the old cycle + * will be returned. + * + * @param bar Bar corresponding to the wanted representative cycle. */ - void update_representative_cycles(); + void update_representative_cycle(const Bar& bar); /** * @brief Only available if @ref PersistenceMatrixOptions::can_retrieve_representative_cycles is true. - * Returns all representative cycles of the current filtration. + * Returns all representative cycles of the current filtration. @ref update_representative_cycles has to be called + * first if a modification to the matrix has to be token into account since last call. * * @return A const reference to the vector of representative cycles. */ const std::vector& get_representative_cycles(); /** * @brief Only available if @ref PersistenceMatrixOptions::can_retrieve_representative_cycles is true. - * Returns the cycle representing the given bar. + * Returns the cycle representing the given bar. @ref update_representative_cycles or + * @ref update_representative_cycle have to be called first if a modification to the matrix has to be token into + * account since last call. * * @param bar A bar from the current barcode. * @return A const reference to the cycle representing @p bar. @@ -1362,6 +1481,8 @@ class Matrix Underlying_matrix matrix_; static constexpr void _assert_options(); + + Element _get_value(int coefficient) const; }; template @@ -1475,7 +1596,7 @@ inline void Matrix::set_characteristic(Characteristic } template -template +template inline void Matrix::insert_column(const Container& column) { if constexpr (!PersistenceMatrixOptions::is_z2) { @@ -1491,7 +1612,7 @@ inline void Matrix::insert_column(const Container& col } template -template +template inline void Matrix::insert_column(const Container& column, Index columnIndex) { if constexpr (!PersistenceMatrixOptions::is_z2) { @@ -1507,6 +1628,23 @@ inline void Matrix::insert_column(const Container& col matrix_.insert_column(column, columnIndex); } +template +inline void Matrix::insert_column(ID_index idx, [[maybe_unused]] Element e) +{ + static_assert( + !isNonBasic, + "'insert_column' not available for the chosen options. The input has to be in the form of a cell boundary."); + + if constexpr (PersistenceMatrixOptions::is_z2) { + matrix_.insert_column(idx); + } else { + GUDHI_CHECK(colSettings_->operators.get_characteristic() != Field_operators::nullCharacteristic, + std::logic_error("Matrix::insert_column - Columns cannot be initialized if the coefficient field " + "characteristic is not specified.")); + matrix_.insert_column(idx, e); + } +} + template template inline typename Matrix::Insertion_return Matrix::insert_boundary( @@ -1722,13 +1860,7 @@ Matrix::multiply_target_and_add_to(Integer_index sourc int coefficient, Integer_index targetColumnIndex) { - if constexpr (PersistenceMatrixOptions::is_z2) { - // coef will be converted to bool, because of Element - matrix_.multiply_target_and_add_to(sourceColumnIndex, coefficient % 2, targetColumnIndex); - } else { - matrix_.multiply_target_and_add_to( - sourceColumnIndex, colSettings_->operators.get_value(coefficient), targetColumnIndex); - } + matrix_.multiply_target_and_add_to(sourceColumnIndex, _get_value(coefficient), targetColumnIndex); } template @@ -1742,12 +1874,7 @@ inline std::enable_if_t > Matrixoperators.get_value(coefficient), targetColumnIndex); - } + matrix_.multiply_target_and_add_to(sourceColumn, _get_value(coefficient), targetColumnIndex); } template @@ -1757,13 +1884,7 @@ Matrix::multiply_source_and_add_to(int coefficient, Integer_index sourceColumnIndex, Integer_index targetColumnIndex) { - if constexpr (PersistenceMatrixOptions::is_z2) { - // coef will be converted to bool, because of Element - matrix_.multiply_source_and_add_to(coefficient % 2, sourceColumnIndex, targetColumnIndex); - } else { - matrix_.multiply_source_and_add_to( - colSettings_->operators.get_value(coefficient), sourceColumnIndex, targetColumnIndex); - } + matrix_.multiply_source_and_add_to(_get_value(coefficient), sourceColumnIndex, targetColumnIndex); } template @@ -1777,12 +1898,7 @@ inline std::enable_if_t > Matrixoperators.get_value(coefficient), sourceColumn, targetColumnIndex); - } + matrix_.multiply_source_and_add_to(_get_value(coefficient), sourceColumn, targetColumnIndex); } template @@ -1900,6 +2016,8 @@ inline Matrix& Matrix::opera template inline Matrix& Matrix::operator=(Matrix&& other) && noexcept { + if (this == &other) return *this; + matrix_ = std::move(other.matrix_); colSettings_ = std::exchange(other.colSettings_, nullptr); @@ -2005,10 +2123,17 @@ inline typename Matrix::Index Matrix -inline void Matrix::update_representative_cycles() +inline void Matrix::update_representative_cycles(Dimension dim) { static_assert(PersistenceMatrixOptions::can_retrieve_representative_cycles, "This method was not enabled."); - matrix_.update_representative_cycles(); + matrix_.update_representative_cycles(dim); +} + +template +inline void Matrix::update_representative_cycle(const Bar& bar) +{ + static_assert(PersistenceMatrixOptions::can_retrieve_representative_cycles, "This method was not enabled."); + matrix_.update_representative_cycle(bar); } template @@ -2062,6 +2187,13 @@ constexpr void Matrix::_assert_options() // "When column compression is used, the removal of columns is not implemented yet."); } +template +inline typename Matrix::Element Matrix::_get_value( + int coefficient) const +{ + return get_coefficient_value(coefficient, get_operator_ptr(colSettings_)); +} + } // namespace persistence_matrix } // namespace Gudhi diff --git a/multipers/gudhi/gudhi/Persistence_matrix/Base_matrix.h b/multipers/gudhi/gudhi/Persistence_matrix/Base_matrix.h index 814af580..5d9c2bc9 100644 --- a/multipers/gudhi/gudhi/Persistence_matrix/Base_matrix.h +++ b/multipers/gudhi/gudhi/Persistence_matrix/Base_matrix.h @@ -111,7 +111,7 @@ class Base_matrix : public Master_matrix::template Base_swap_option + template > > void insert_column(const Container& column); /** * @brief Inserts a new ordered column at the given index by copying the given range of @@ -125,8 +125,15 @@ class Base_matrix : public Master_matrix::template Base_swap_option + template > > void insert_column(const Container& column, Index columnIndex); + /** + * @brief Inserts a new column at the end of the matrix. The column will consist of the given index only. + * + * @param idx Entry ID. + * @param e Entry coefficient. Ignored if the coefficient field is Z2. Default value: 0. + */ + void insert_column(Index idx, Field_element e = 0); /** * @brief Same as @ref insert_column, only for interface purposes. The given dimension is ignored and not stored. * @@ -341,15 +348,18 @@ class Base_matrix : public Master_matrix::template Base_swap_option + template > > void _insert(const Container& column, Index columnIndex, Dimension dim); + void _insert(Index idx, Field_element e, Index columnIndex, Dimension dim); void _orderRowsIfNecessary(); const Column& _get_column(Index columnIndex) const; Column& _get_column(Index columnIndex); Index _get_real_row_index(Index rowIndex) const; template void _container_insert(const Container& column, Index pos, Dimension dim); - void _container_insert(const Column& column, [[maybe_unused]] Index pos = 0); + void _container_insert(Index idx, Field_element e, Index pos, Dimension dim); + template + void _container_insert(const ColumnIterator& rep); }; template @@ -400,11 +410,7 @@ inline Base_matrix::Base_matrix(const Base_matrix& matrixToCopy, { matrix_.reserve(matrixToCopy.matrix_.size()); for (const auto& cont : matrixToCopy.matrix_) { - if constexpr (Master_matrix::Option_list::has_map_column_container) { - _container_insert(cont.second, cont.first); - } else { - _container_insert(cont); - } + _container_insert(cont); } } @@ -419,7 +425,7 @@ inline Base_matrix::Base_matrix(Base_matrix&& other) noexcept } template -template +template inline void Base_matrix::insert_column(const Container& column) { // TODO: dim not actually stored right now, so either get rid of it or store it again @@ -428,7 +434,7 @@ inline void Base_matrix::insert_column(const Container& column) } template -template +template inline void Base_matrix::insert_column(const Container& column, Index columnIndex) { static_assert(!Master_matrix::Option_list::has_row_access, @@ -439,6 +445,14 @@ inline void Base_matrix::insert_column(const Container& column, I _insert(column, columnIndex, column.size() == 0 ? 0 : column.size() - 1); } +template +inline void Base_matrix::insert_column(Index idx, Field_element e) +{ + // TODO: dim not actually stored right now, so either get rid of it or store it again + _insert(idx, e, nextInsertIndex_, 0); + ++nextInsertIndex_; +} + template template inline void Base_matrix::insert_boundary(const Boundary_range& boundary, Dimension dim) @@ -591,11 +605,7 @@ inline Base_matrix& Base_matrix::operator=(const B matrix_.reserve(other.matrix_.size()); for (const auto& cont : other.matrix_) { - if constexpr (Master_matrix::Option_list::has_map_column_container) { - _container_insert(cont.second, cont.first); - } else { - _container_insert(cont); - } + _container_insert(cont); } return *this; @@ -604,6 +614,8 @@ inline Base_matrix& Base_matrix::operator=(const B template inline Base_matrix& Base_matrix::operator=(Base_matrix&& other) noexcept { + if (this == &other) return *this; + Swap_opt::operator=(std::move(other)); RA_opt::operator=(std::move(other)); @@ -644,7 +656,7 @@ inline void Base_matrix::print() } template -template +template inline void Base_matrix::_insert(const Container& column, Index columnIndex, Dimension dim) { _orderRowsIfNecessary(); @@ -653,11 +665,7 @@ inline void Base_matrix::_insert(const Container& column, Index c Index pivot = 0; if (column.begin() != column.end()) { // first, compute pivot of `column` - if constexpr (Master_matrix::Option_list::is_z2) { - pivot = *std::prev(column.end()); - } else { - pivot = std::prev(column.end())->first; - } + pivot = Master_matrix::get_row_index(*std::prev(column.end())); // row container if constexpr (Master_matrix::Option_list::has_row_access && !Master_matrix::Option_list::has_removable_rows) RA_opt::_resize(pivot); @@ -666,14 +674,8 @@ inline void Base_matrix::_insert(const Container& column, Index c // row swap map containers if constexpr (Master_matrix::Option_list::has_map_column_container) { if constexpr (Master_matrix::Option_list::has_column_and_row_swaps || Master_matrix::Option_list::has_vine_update) { - for (auto id : column) { - Index idx; - if constexpr (Master_matrix::Option_list::is_z2) { - idx = id; - } else { - idx = id.first; - } - Swap_opt::_initialize_row_index(idx); + for (const auto& id : column) { + Swap_opt::_initialize_row_index(Master_matrix::get_row_index(id)); } } } else { @@ -691,6 +693,30 @@ inline void Base_matrix::_insert(const Container& column, Index c _container_insert(column, columnIndex, dim); } +template +inline void Base_matrix::_insert(Index idx, Field_element e, Index columnIndex, Dimension dim) +{ + _orderRowsIfNecessary(); + + // resize of containers when necessary: + if constexpr (Master_matrix::Option_list::has_row_access && !Master_matrix::Option_list::has_removable_rows) + RA_opt::_resize(idx); + + // row swap map containers + if constexpr (Master_matrix::Option_list::has_column_and_row_swaps || Master_matrix::Option_list::has_vine_update) { + Swap_opt::_initialize_row_index(idx); + } + + // column container + if constexpr (!Master_matrix::Option_list::has_map_column_container && !Master_matrix::Option_list::has_row_access) { + if (matrix_.size() <= columnIndex) { + matrix_.resize(columnIndex + 1); + } + } + + _container_insert(idx, e, columnIndex, dim); +} + template inline void Base_matrix::_orderRowsIfNecessary() { @@ -750,19 +776,54 @@ inline void Base_matrix::_container_insert(const Container& colum } template -inline void Base_matrix::_container_insert(const Column& column, [[maybe_unused]] Index pos) +inline void Base_matrix::_container_insert(Index idx, [[maybe_unused]] Field_element e, Index pos, Dimension dim){ + if constexpr (Master_matrix::Option_list::has_map_column_container) { + if constexpr (Master_matrix::Option_list::has_row_access) { + if constexpr (Master_matrix::Option_list::is_z2){ + matrix_.try_emplace(pos, Column(pos, idx, dim, RA_opt::_get_rows_ptr(), colSettings_)); + } else { + matrix_.try_emplace(pos, Column(pos, idx, e, dim, RA_opt::_get_rows_ptr(), colSettings_)); + } + } else { + if constexpr (Master_matrix::Option_list::is_z2){ + matrix_.try_emplace(pos, Column(idx, dim, colSettings_)); + } else { + matrix_.try_emplace(pos, Column(idx, e, dim, colSettings_)); + } + } + } else { + if constexpr (Master_matrix::Option_list::has_row_access) { + if constexpr (Master_matrix::Option_list::is_z2){ + matrix_.emplace_back(pos, idx, dim, RA_opt::_get_rows_ptr(), colSettings_); + } else { + matrix_.emplace_back(pos, idx, e, dim, RA_opt::_get_rows_ptr(), colSettings_); + } + } else { + if constexpr (Master_matrix::Option_list::is_z2){ + matrix_[pos] = Column(idx, dim, colSettings_); + } else { + matrix_[pos] = Column(idx, e, dim, colSettings_); + } + } + } +} + +template +template // Pair (pos,Column) if has_map_column_container, Column otherwise +inline void Base_matrix::_container_insert(const ColumnIterator& rep) { if constexpr (Master_matrix::Option_list::has_map_column_container) { + const auto& col = rep.second; if constexpr (Master_matrix::Option_list::has_row_access) { - matrix_.try_emplace(pos, Column(column, column.get_column_index(), RA_opt::_get_rows_ptr(), colSettings_)); + matrix_.try_emplace(rep.first, Column(col, col.get_column_index(), RA_opt::_get_rows_ptr(), colSettings_)); } else { - matrix_.try_emplace(pos, Column(column, colSettings_)); + matrix_.try_emplace(rep.first, Column(col, colSettings_)); } } else { if constexpr (Master_matrix::Option_list::has_row_access) { - matrix_.emplace_back(column, column.get_column_index(), RA_opt::_get_rows_ptr(), colSettings_); + matrix_.emplace_back(rep, rep.get_column_index(), RA_opt::_get_rows_ptr(), colSettings_); } else { - matrix_.emplace_back(column, colSettings_); + matrix_.emplace_back(rep, colSettings_); } } } diff --git a/multipers/gudhi/gudhi/Persistence_matrix/Base_matrix_with_column_compression.h b/multipers/gudhi/gudhi/Persistence_matrix/Base_matrix_with_column_compression.h index 444a89e3..5246736e 100644 --- a/multipers/gudhi/gudhi/Persistence_matrix/Base_matrix_with_column_compression.h +++ b/multipers/gudhi/gudhi/Persistence_matrix/Base_matrix_with_column_compression.h @@ -81,12 +81,12 @@ class Base_matrix_with_column_compression : protected Master_matrix::Matrix_row_ : Base(columnIndex, nonZeroRowIndices, rowContainer, colSettings) {} - template + template > > Column(const Container& nonZeroRowIndices, Dimension dimension, Column_settings* colSettings) : Base(nonZeroRowIndices, dimension, colSettings) {} - template + template > > Column(Index columnIndex, const Container& nonZeroRowIndices, Dimension dimension, @@ -95,6 +95,27 @@ class Base_matrix_with_column_compression : protected Master_matrix::Matrix_row_ : Base(columnIndex, nonZeroRowIndices, dimension, rowContainer, colSettings) {} + Column(Index idx, Dimension dimension, Column_settings* colSettings) : Base(idx, dimension, colSettings) {} + + Column(Index idx, Field_element e, Dimension dimension, Column_settings* colSettings) + : Base(idx, e, dimension, colSettings) + {} + + template + Column(Index columnIndex, Index idx, Dimension dimension, Row_container* rowContainer, Column_settings* colSettings) + : Base(columnIndex, idx, dimension, rowContainer, colSettings) + {} + + template + Column(Index columnIndex, + Index idx, + Field_element e, + Dimension dimension, + Row_container* rowContainer, + Column_settings* colSettings) + : Base(columnIndex, idx, e, dimension, rowContainer, colSettings) + {} + Column(const Column& column, Column_settings* colSettings = nullptr) : Base(static_cast(column), colSettings), rep_(column.rep_) {} @@ -196,8 +217,23 @@ class Base_matrix_with_column_compression : protected Master_matrix::Matrix_row_ * @param column Range of @ref Matrix::Entry_representative from which the column has to be constructed. Assumed to be * ordered by increasing ID value. */ - template + template > > void insert_column(const Container& column); + /** + * @brief Inserts a new column at the end of the matrix. The column will consist of the given index only. + * Only available for Z2 coefficients. Otherwise, add the entry coefficient to the arguments. + * + * @param idx Entry ID. + */ + void insert_column(Index idx); + /** + * @brief Inserts a new column at the end of the matrix. The column will consist of the given index only. + * Only available for Zp coefficients. For Z2, do not specify the last argument. + * + * @param idx Entry ID. + * @param e Entry coefficient. + */ + void insert_column(Index idx, Field_element e); /** * @brief Same as @ref insert_column, only for interface purposes. The given dimension is ignored and not stored. * @@ -391,6 +427,8 @@ class Base_matrix_with_column_compression : protected Master_matrix::Matrix_row_ std::unique_ptr > columnPool_; inline static const Column empty_column_; /**< Representative for empty columns. */ + template + void _initialize_column(F&& get_column); void _insert_column(Index columnIndex); void _insert_double_column(Index columnIndex, typename Col_dict::iterator& doubleIt); }; @@ -478,12 +516,59 @@ inline Base_matrix_with_column_compression::~Base_matrix_with_col } template -template +template inline void Base_matrix_with_column_compression::insert_column(const Container& column) { insert_boundary(column); } +template +inline void Base_matrix_with_column_compression::insert_column(Index idx) +{ + static_assert(Master_matrix::Option_list::is_z2, + "Insertion method not available for Zp != Z2. Please specify the coefficient."); + + if constexpr (Master_matrix::Option_list::has_row_access && !Master_matrix::Option_list::has_removable_rows) { + RA_opt::_resize(idx); + } + + _initialize_column([&]() -> Column* { + if constexpr (Master_matrix::Option_list::has_row_access) { + return columnPool_->construct(nextColumnIndex_, idx, 0, RA_opt::_get_rows_ptr(), colSettings_); + } else { + return columnPool_->construct(idx, 0, colSettings_); + } + }); + + _insert_column(nextColumnIndex_); + + nextColumnIndex_++; +} + +template +inline void Base_matrix_with_column_compression::insert_column(Index idx, + Field_element e) +{ + static_assert(!Master_matrix::Option_list::is_z2, + "Insertion method not available for Zp == Z2. Please do not specify any coefficient."); + + if constexpr (Master_matrix::Option_list::has_row_access && !Master_matrix::Option_list::has_removable_rows) { + RA_opt::_resize(idx); + } + + _initialize_column([&]() -> Column* { + if constexpr (Master_matrix::Option_list::has_row_access) { + return columnPool_->construct(nextColumnIndex_, idx, e, 0, RA_opt::_get_rows_ptr(), colSettings_); + } else { + return columnPool_->construct(idx, e, 0, colSettings_); + } + }); + + _insert_column(nextColumnIndex_); + + nextColumnIndex_++; +} + template template inline void Base_matrix_with_column_compression::insert_boundary(const Boundary_range& boundary, @@ -496,33 +581,18 @@ inline void Base_matrix_with_column_compression::insert_boundary( if constexpr (Master_matrix::Option_list::has_row_access && !Master_matrix::Option_list::has_removable_rows) { if (boundary.begin() != boundary.end()) { - Index pivot; - if constexpr (Master_matrix::Option_list::is_z2) { - pivot = *std::prev(boundary.end()); - } else { - pivot = std::prev(boundary.end())->first; - } - RA_opt::_resize(pivot); + RA_opt::_resize(Master_matrix::get_row_index(*std::prev(boundary.end()))); } } - if (repToColumn_.size() == nextColumnIndex_) { - // could perhaps be avoided, if find_set returns something special when it does not find - columnClasses_.link(nextColumnIndex_, nextColumnIndex_); + _initialize_column([&]() -> Column* { if constexpr (Master_matrix::Option_list::has_row_access) { - repToColumn_.push_back( - columnPool_->construct(nextColumnIndex_, boundary, dim, RA_opt::_get_rows_ptr(), colSettings_)); + return columnPool_->construct(nextColumnIndex_, boundary, dim, RA_opt::_get_rows_ptr(), colSettings_); } else { - repToColumn_.push_back(columnPool_->construct(boundary, dim, colSettings_)); + return columnPool_->construct(boundary, dim, colSettings_); } - } else { - if constexpr (Master_matrix::Option_list::has_row_access) { - repToColumn_[nextColumnIndex_] = - columnPool_->construct(nextColumnIndex_, boundary, dim, RA_opt::_get_rows_ptr(), colSettings_); - } else { - repToColumn_[nextColumnIndex_] = columnPool_->construct(boundary, dim, colSettings_); - } - } + }); + _insert_column(nextColumnIndex_); nextColumnIndex_++; @@ -668,7 +738,7 @@ template inline Base_matrix_with_column_compression& Base_matrix_with_column_compression::operator=(Base_matrix_with_column_compression&& other) noexcept { - if (repToColumn_ == &(other.repToColumn_)) return *this; + if (&repToColumn_ == &(other.repToColumn_)) return *this; RA_opt::operator=(std::move(other)); @@ -713,6 +783,19 @@ inline void Base_matrix_with_column_compression::print() std::cout << "\n"; } +template +template +inline void Base_matrix_with_column_compression::_initialize_column(F&& get_column) +{ + if (repToColumn_.size() == nextColumnIndex_) { + // could perhaps be avoided, if find_set returns something special when it does not find + columnClasses_.link(nextColumnIndex_, nextColumnIndex_); + repToColumn_.push_back(std::forward(get_column)()); + } else { + repToColumn_[nextColumnIndex_] = std::forward(get_column)(); + } +} + template inline void Base_matrix_with_column_compression::_insert_column(Index columnIndex) { diff --git a/multipers/gudhi/gudhi/Persistence_matrix/Boundary_matrix.h b/multipers/gudhi/gudhi/Persistence_matrix/Boundary_matrix.h index 7296c9e1..4d341200 100644 --- a/multipers/gudhi/gudhi/Persistence_matrix/Boundary_matrix.h +++ b/multipers/gudhi/gudhi/Persistence_matrix/Boundary_matrix.h @@ -486,14 +486,8 @@ Boundary_matrix::insert_boundary(ID_index cellIndex, const Bounda // updates container sizes if constexpr (Master_matrix::Option_list::has_row_access && !Master_matrix::Option_list::has_removable_rows) { if (boundary.size() != 0) { - ID_index pivot; - if constexpr (Master_matrix::Option_list::is_z2) { - pivot = *std::prev(boundary.end()); - } else { - pivot = std::prev(boundary.end())->first; - } // row container - RA_opt::_resize(pivot); + RA_opt::_resize(Master_matrix::get_row_index(*std::prev(boundary.end()))); } } @@ -704,6 +698,8 @@ inline Boundary_matrix& Boundary_matrix::operator= template inline Boundary_matrix& Boundary_matrix::operator=(Boundary_matrix&& other) noexcept { + if (this == &other) return *this; + Dim_opt::operator=(std::move(other)); Swap_opt::operator=(std::move(other)); Pair_opt::operator=(std::move(other)); diff --git a/multipers/gudhi/gudhi/Persistence_matrix/Chain_matrix.h b/multipers/gudhi/gudhi/Persistence_matrix/Chain_matrix.h index 23cdf6f6..162bcdb0 100644 --- a/multipers/gudhi/gudhi/Persistence_matrix/Chain_matrix.h +++ b/multipers/gudhi/gudhi/Persistence_matrix/Chain_matrix.h @@ -543,7 +543,10 @@ class Chain_matrix : public Master_matrix::Matrix_dimension_option, void _add_bar(Dimension dim); template void _container_insert(const Container& column, Index pos, Dimension dim); - void _container_insert(const Column& column, [[maybe_unused]] Index pos = 0); + template + void _container_insert(const ColumnIterator& rep); + + static void _insert_in(ID_index cellID, Tmp_column& column); }; template @@ -687,11 +690,7 @@ inline Chain_matrix::Chain_matrix(const Chain_matrix& matrixToCop { matrix_.reserve(matrixToCopy.matrix_.size()); for (const auto& cont : matrixToCopy.matrix_) { - if constexpr (Master_matrix::Option_list::has_map_column_container) { - _container_insert(cont.second, cont.first); - } else { - _container_insert(cont); - } + _container_insert(cont); } } @@ -945,11 +944,7 @@ inline Chain_matrix& Chain_matrix::operator=(const matrix_.reserve(other.matrix_.size()); for (const auto& cont : other.matrix_) { - if constexpr (Master_matrix::Option_list::has_map_column_container) { - _container_insert(cont.second, cont.first); - } else { - _container_insert(cont); - } + _container_insert(cont); } return *this; @@ -958,6 +953,8 @@ inline Chain_matrix& Chain_matrix::operator=(const template inline Chain_matrix& Chain_matrix::operator=(Chain_matrix&& other) noexcept { + if (this == &other) return *this; + Dim_opt::operator=(std::move(other)); Pair_opt::operator=(std::move(other)); Swap_opt::operator=(std::move(other)); @@ -1044,10 +1041,7 @@ Chain_matrix::_reduce_boundary(ID_index cellID, const Boundary_ra }; if (boundary.begin() == boundary.end()) { - if constexpr (Master_matrix::Option_list::is_z2) - column.insert(cellID); - else - column.emplace(cellID, 1); + _insert_in(cellID, column); _insert_chain(column, dim); return chainsInF; } @@ -1085,10 +1079,7 @@ Chain_matrix::_reduce_boundary(ID_index cellID, const Boundary_ra _build_from_H(cellID, column, chainsInH); // Create and insert (\sum col_h) + sigma (in H, paired with chain_fp) in matrix_ - if constexpr (Master_matrix::Option_list::is_z2) - _insert_chain(column, dim, chainsInF[0]); - else - _insert_chain(column, dim, chainsInF[0].first); + _insert_chain(column, dim, Master_matrix::get_row_index(chainsInF[0])); return chainsInF; } @@ -1138,32 +1129,26 @@ inline void Chain_matrix::_build_from_H(ID_index cellID, Tmp_column& column, std::vector& chainsInH) { - if constexpr (Master_matrix::Option_list::is_z2) { - column.insert(cellID); - for (Index idx_h : chainsInH) { - _add_to(get_column(idx_h), column, 1U); - } - } else { - column.emplace(cellID, 1); - for (std::pair& idx_h : chainsInH) { - _add_to(get_column(idx_h.first), column, idx_h.second); - } + _insert_in(cellID, column); + + for (const auto& idx_h : chainsInH) { + _add_to(get_column(Master_matrix::get_row_index(idx_h)), column, Master_matrix::get_element(idx_h)); } } template inline void Chain_matrix::_update_largest_death_in_F(const std::vector& chainsInF) { + Index toUpdate = Master_matrix::get_row_index(chainsInF[0]); if constexpr (Master_matrix::Option_list::is_z2) { - Index toUpdate = chainsInF[0]; for (auto other_col_it = chainsInF.begin() + 1; other_col_it != chainsInF.end(); ++other_col_it) { add_to(*other_col_it, toUpdate); } } else { - Index toUpdate = chainsInF[0].first; - get_column(toUpdate) *= chainsInF[0].second; + get_column(toUpdate) *= Master_matrix::get_element(chainsInF[0]); for (auto other_col_it = chainsInF.begin() + 1; other_col_it != chainsInF.end(); ++other_col_it) { - multiply_source_and_add_to(other_col_it->second, other_col_it->first, toUpdate); + multiply_source_and_add_to( + Master_matrix::get_element(*other_col_it), Master_matrix::get_row_index(*other_col_it), toUpdate); } } } @@ -1328,12 +1313,8 @@ template template inline void Chain_matrix::_container_insert(const Container& column, Index pos, Dimension dim) { - ID_index pivot; - if constexpr (Master_matrix::Option_list::is_z2) { - pivot = *(column.rbegin()); - } else { - pivot = column.rbegin()->first; - } + ID_index pivot = Master_matrix::get_row_index(*(column.rbegin())); + if constexpr (Master_matrix::Option_list::has_map_column_container) { pivotToColumnIndex_.try_emplace(pivot, pos); if constexpr (Master_matrix::Option_list::has_row_access) { @@ -1352,23 +1333,34 @@ inline void Chain_matrix::_container_insert(const Container& colu } template -inline void Chain_matrix::_container_insert(const Column& column, [[maybe_unused]] Index pos) +template // Pair (pos,Column) if has_map_column_container, Column otherwise +inline void Chain_matrix::_container_insert(const ColumnIterator& rep) { if constexpr (Master_matrix::Option_list::has_map_column_container) { + const auto& col = rep.second; if constexpr (Master_matrix::Option_list::has_row_access) { - matrix_.try_emplace(pos, Column(column, column.get_column_index(), RA_opt::_get_rows_ptr(), colSettings_)); + matrix_.try_emplace(rep.first, Column(col, col.get_column_index(), RA_opt::_get_rows_ptr(), colSettings_)); } else { - matrix_.try_emplace(pos, Column(column, colSettings_)); + matrix_.try_emplace(rep.first, Column(col, colSettings_)); } } else { if constexpr (Master_matrix::Option_list::has_row_access) { - matrix_.emplace_back(column, column.get_column_index(), RA_opt::_get_rows_ptr(), colSettings_); + matrix_.emplace_back(rep, rep.get_column_index(), RA_opt::_get_rows_ptr(), colSettings_); } else { - matrix_.emplace_back(column, colSettings_); + matrix_.emplace_back(rep, colSettings_); } } } +template +inline void Chain_matrix::_insert_in(ID_index cellID, Tmp_column& column) +{ + if constexpr (Master_matrix::Option_list::is_z2) + column.insert(cellID); + else + column.emplace(cellID, 1); +} + } // namespace persistence_matrix } // namespace Gudhi diff --git a/multipers/gudhi/gudhi/Persistence_matrix/Id_to_index_overlay.h b/multipers/gudhi/gudhi/Persistence_matrix/Id_to_index_overlay.h index 8ce0309d..ac378193 100644 --- a/multipers/gudhi/gudhi/Persistence_matrix/Id_to_index_overlay.h +++ b/multipers/gudhi/gudhi/Persistence_matrix/Id_to_index_overlay.h @@ -602,12 +602,23 @@ class Id_to_index_overlay /** * @brief Only available if @ref PersistenceMatrixOptions::can_retrieve_representative_cycles is true. Pre-computes - * the representative cycles of the current state of the filtration represented by the matrix. - * It does not need to be called before `get_representative_cycles` is called for the first time, but needs to be - * called before calling `get_representative_cycles` again if the matrix was modified in between. Otherwise the - * old cycles will be returned. + * the representative cycles of the current state of the filtration represented by the matrix. It needs to be called + * before calling @ref get_representative_cycles if the matrix was modified since last call. Otherwise the old cycles + * will be returned. + * + * @param dim If different from default value, only the cycles of the given dimension are updated. + * All others are erased. + */ + void update_representative_cycles(Dimension dim = Master_matrix::template get_null_value()); + /** + * @brief Only available if @ref PersistenceMatrixOptions::can_retrieve_representative_cycles is true. Pre-computes + * the representative cycle in the current matrix state of the given bar. It needs to be called + * before calling @ref get_representative_cycle if the matrix was modified since last call. Otherwise the old cycle + * will be returned. + * + * @param bar Bar corresponding to the wanted representative cycle. */ - void update_representative_cycles(); + void update_representative_cycle(const Bar& bar); /** * @brief Only available if @ref PersistenceMatrixOptions::can_retrieve_representative_cycles is true. * Returns all representative cycles of the current filtration. @@ -993,6 +1004,8 @@ template inline Id_to_index_overlay& Id_to_index_overlay::operator=(Id_to_index_overlay&& other) noexcept { + if (this == &other) return *this; + matrix_ = std::move(other.matrix_); if constexpr (Master_matrix::Option_list::is_of_boundary_type) { delete idToIndex_; @@ -1017,9 +1030,15 @@ Id_to_index_overlay::get_current_barcode() } template -inline void Id_to_index_overlay::update_representative_cycles() +inline void Id_to_index_overlay::update_representative_cycles(Dimension dim) +{ + matrix_.update_representative_cycles(dim); +} + +template +inline void Id_to_index_overlay::update_representative_cycle(const Bar& bar) { - matrix_.update_representative_cycles(); + matrix_.update_representative_cycle(bar); } template diff --git a/multipers/gudhi/gudhi/Persistence_matrix/Position_to_index_overlay.h b/multipers/gudhi/gudhi/Persistence_matrix/Position_to_index_overlay.h index 7d269c39..39373d16 100644 --- a/multipers/gudhi/gudhi/Persistence_matrix/Position_to_index_overlay.h +++ b/multipers/gudhi/gudhi/Persistence_matrix/Position_to_index_overlay.h @@ -439,8 +439,6 @@ class Position_to_index_overlay nextIndex_ = 0; } - // void set_operators(Field_operators* operators) { matrix_.set_operators(operators); } - /** * @brief Assign operator. */ @@ -478,12 +476,23 @@ class Position_to_index_overlay /** * @brief Only available if @ref PersistenceMatrixOptions::can_retrieve_representative_cycles is true. Pre-computes - * the representative cycles of the current state of the filtration represented by the matrix. - * It does not need to be called before `get_representative_cycles` is called for the first time, but needs to be - * called before calling `get_representative_cycles` again if the matrix was modified in between. Otherwise the - * old cycles will be returned. + * the representative cycles of the current state of the filtration represented by the matrix. It needs to be called + * before calling @ref get_representative_cycles if the matrix was modified since last call. Otherwise the old cycles + * will be returned. + * + * @param dim If different from default value, only the cycles of the given dimension are updated. + * All others are erased. + */ + void update_representative_cycles(Dimension dim = Master_matrix::template get_null_value()); + /** + * @brief Only available if @ref PersistenceMatrixOptions::can_retrieve_representative_cycles is true. Pre-computes + * the representative cycle in the current matrix state of the given bar. It needs to be called + * before calling @ref get_representative_cycle if the matrix was modified since last call. Otherwise the old cycle + * will be returned. + * + * @param bar Bar corresponding to the wanted representative cycle. */ - void update_representative_cycles(); + void update_representative_cycle(const Bar& bar); /** * @brief Only available if @ref PersistenceMatrixOptions::can_retrieve_representative_cycles is true. * Returns all representative cycles of the current filtration. @@ -805,9 +814,15 @@ Position_to_index_overlay::get_current_barcode } template -inline void Position_to_index_overlay::update_representative_cycles() +inline void Position_to_index_overlay::update_representative_cycles(Dimension dim) +{ + matrix_.update_representative_cycles(dim); +} + +template +inline void Position_to_index_overlay::update_representative_cycle(const Bar& bar) { - matrix_.update_representative_cycles(); + matrix_.update_representative_cycle(bar); } template diff --git a/multipers/gudhi/gudhi/Persistence_matrix/RU_matrix.h b/multipers/gudhi/gudhi/Persistence_matrix/RU_matrix.h index 34f83ee6..a7774934 100644 --- a/multipers/gudhi/gudhi/Persistence_matrix/RU_matrix.h +++ b/multipers/gudhi/gudhi/Persistence_matrix/RU_matrix.h @@ -17,7 +17,6 @@ #ifndef PM_RU_MATRIX_H #define PM_RU_MATRIX_H -#include //std::conditional #include //std::swap, std::move & std::exchange #include //print() only #include @@ -373,9 +372,7 @@ class RU_matrix : public Master_matrix::RU_pairing_option, pivotToColumnIndex_.clear(); nextEventIndex_ = 0; positionToID_.clear(); - if constexpr (!Master_matrix::Option_list::is_z2) { - operators_ = &(colSettings->operators); - } + operators_ = Master_matrix::get_operator_ptr(colSettings); } /** @@ -424,7 +421,7 @@ class RU_matrix : public Master_matrix::RU_pairing_option, Pivot_dictionary pivotToColumnIndex_; /**< Map from pivot row index to column @ref MatIdx index. */ Pos_index nextEventIndex_; /**< Next birth or death index. */ Position_dictionary positionToID_; /**< Map from @ref MatIdx to @ref IDIdx. */ - Field_operators* operators_; /**< Field operators, can be nullptr if + Field_operators const* operators_; /**< Field operators, can be nullptr if @ref PersistenceMatrixOptions::is_z2 is true. */ void _insert_boundary(Index currentIndex); @@ -447,12 +444,8 @@ inline RU_matrix::RU_matrix(Column_settings* colSettings) reducedMatrixR_(colSettings), mirrorMatrixU_(colSettings), nextEventIndex_(0), - operators_(nullptr) -{ - if constexpr (!Master_matrix::Option_list::is_z2) { - operators_ = &(colSettings->operators); - } -} + operators_(Master_matrix::get_operator_ptr(colSettings)) +{} template template @@ -464,12 +457,8 @@ inline RU_matrix::RU_matrix(const std::vector& or reducedMatrixR_(orderedBoundaries, colSettings), mirrorMatrixU_(orderedBoundaries.size(), colSettings), nextEventIndex_(orderedBoundaries.size()), - operators_(nullptr) + operators_(Master_matrix::get_operator_ptr(colSettings)) { - if constexpr (!Master_matrix::Option_list::is_z2) { - operators_ = &(colSettings->operators); - } - if constexpr (Master_matrix::Option_list::has_map_column_container) { pivotToColumnIndex_.reserve(orderedBoundaries.size()); } else { @@ -489,12 +478,8 @@ inline RU_matrix::RU_matrix(unsigned int numberOfColumns, Column_ mirrorMatrixU_(numberOfColumns, colSettings), nextEventIndex_(0), positionToID_(numberOfColumns), - operators_(nullptr) + operators_(Master_matrix::get_operator_ptr(colSettings)) { - if constexpr (!Master_matrix::Option_list::is_z2) { - operators_ = &(colSettings->operators); - } - if constexpr (Master_matrix::Option_list::has_map_column_container) { pivotToColumnIndex_.reserve(numberOfColumns); } else { @@ -515,12 +500,8 @@ inline RU_matrix::RU_matrix(const RU_matrix& matrixToCopy, Column pivotToColumnIndex_(matrixToCopy.pivotToColumnIndex_), nextEventIndex_(matrixToCopy.nextEventIndex_), positionToID_(matrixToCopy.positionToID_), - operators_(colSettings == nullptr ? matrixToCopy.operators_ : nullptr) -{ - if constexpr (!Master_matrix::Option_list::is_z2) { - if (colSettings != nullptr) operators_ = &(colSettings->operators); - } -} + operators_(colSettings == nullptr ? matrixToCopy.operators_ : Master_matrix::get_operator_ptr(colSettings)) +{} template inline RU_matrix::RU_matrix(RU_matrix&& other) noexcept @@ -756,6 +737,8 @@ inline RU_matrix& RU_matrix::operator=(const RU_ma template inline RU_matrix& RU_matrix::operator=(RU_matrix&& other) noexcept { + if (this == &other) return *this; + Pair_opt::operator=(std::move(other)); Swap_opt::operator=(std::move(other)); Rep_opt::operator=(std::move(other)); @@ -780,11 +763,7 @@ inline void RU_matrix::print() template inline void RU_matrix::_insert_boundary(Index currentIndex) { - if constexpr (Master_matrix::Option_list::is_z2) { - mirrorMatrixU_.insert_column({currentIndex}); - } else { - mirrorMatrixU_.insert_column({{currentIndex, 1}}); - } + mirrorMatrixU_.insert_column(currentIndex, 1); if constexpr (!Master_matrix::Option_list::has_map_column_container) { ID_index pivot = reducedMatrixR_.get_column(currentIndex).get_pivot(); @@ -799,15 +778,8 @@ inline void RU_matrix::_insert_boundary(Index currentIndex) template inline void RU_matrix::_initialize_U() { - typename std::conditional >::type id; - if constexpr (!Master_matrix::Option_list::is_z2) id.second = 1; - for (ID_index i = 0; i < reducedMatrixR_.get_number_of_columns(); i++) { - if constexpr (Master_matrix::Option_list::is_z2) - id = i; - else - id.first = i; - mirrorMatrixU_.insert_column({id}); + mirrorMatrixU_.insert_column(i, 1); } } @@ -898,6 +870,7 @@ inline typename RU_matrix::Index RU_matrix::_get_c if (it == pivotToColumnIndex_.end()) return Master_matrix::template get_null_value(); return it->second; } else { + if (pivot >= pivotToColumnIndex_.size()) return Master_matrix::template get_null_value(); return pivotToColumnIndex_[pivot]; } } diff --git a/multipers/gudhi/gudhi/Persistence_matrix/allocators/entry_constructors.h b/multipers/gudhi/gudhi/Persistence_matrix/allocators/entry_constructors.h index 068d73d0..ace419bb 100644 --- a/multipers/gudhi/gudhi/Persistence_matrix/allocators/entry_constructors.h +++ b/multipers/gudhi/gudhi/Persistence_matrix/allocators/entry_constructors.h @@ -61,7 +61,8 @@ struct New_entry_constructor { /** * @brief Swap operator. */ - friend void swap(New_entry_constructor& col1, New_entry_constructor& col2) noexcept {} + friend void swap([[maybe_unused]] New_entry_constructor& col1, + [[maybe_unused]] New_entry_constructor& col2) noexcept {} }; /** diff --git a/multipers/gudhi/gudhi/Persistence_matrix/base_pairing.h b/multipers/gudhi/gudhi/Persistence_matrix/base_pairing.h index f049abe0..e3c5f711 100644 --- a/multipers/gudhi/gudhi/Persistence_matrix/base_pairing.h +++ b/multipers/gudhi/gudhi/Persistence_matrix/base_pairing.h @@ -65,9 +65,8 @@ class Base_pairing public: using Bar = typename Master_matrix::Bar; /**< Bar type. */ using Barcode = typename Master_matrix::Barcode; /**< Barcode type. */ - using Column_container = typename Master_matrix::Column_container; /**< Column container type. */ + using Column = typename Master_matrix::Column; /**< Column type. */ using Index = typename Master_matrix::Index; /**< Container index type. */ - using Dimension = typename Master_matrix::Dimension; /**< Dimension value type. */ /** * @brief Default constructor. @@ -117,6 +116,7 @@ class Base_pairing std::unordered_map idToPosition_; // TODO: test other map types void _reduce(); + void _reduce_column_with(Column& toReduce, Column& toAdd); // access to inheriting Boundary_matrix class constexpr Base_matrix* _matrix() { return static_cast(this); } @@ -140,6 +140,7 @@ inline void Base_pairing::_reduce() { constexpr const Pos_index nullDeath = Master_matrix::template get_null_value(); constexpr const Index nullIndex = Master_matrix::template get_null_value(); + constexpr const ID_index nullPivot = Master_matrix::template get_null_value(); std::unordered_map negativeColumns(_matrix()->get_number_of_columns()); @@ -164,19 +165,8 @@ inline void Base_pairing::_reduce() auto itNeg = negativeColumns.find(pivotColumnNumber); Index pivotKiller = itNeg == negativeColumns.end() ? nullIndex : itNeg->second; - while (pivot != Master_matrix::template get_null_value() && - pivotKiller != Master_matrix::template get_null_value()) { - if constexpr (Master_matrix::Option_list::is_z2) { - curr += _matrix()->get_column(pivotKiller); - } else { - auto& toadd = _matrix()->get_column(pivotKiller); - typename Master_matrix::Element coef = toadd.get_pivot_value(); - auto& operators = _matrix()->colSettings_->operators; - coef = operators.get_inverse(coef); - operators.multiply_inplace(coef, operators.get_characteristic() - curr.get_pivot_value()); - curr.multiply_source_and_add(toadd, coef); - } - + while (pivot != nullPivot && pivotKiller != nullIndex) { + _reduce_column_with(curr, _matrix()->get_column(pivotKiller)); pivot = curr.get_pivot(); it = idToPosition_.find(pivot); pivotColumnNumber = it == idToPosition_.end() ? pivot : it->second; @@ -184,7 +174,7 @@ inline void Base_pairing::_reduce() pivotKiller = itNeg == negativeColumns.end() ? nullIndex : itNeg->second; } - if (pivot != Master_matrix::template get_null_value()) { + if (pivot != nullPivot) { negativeColumns.emplace(pivotColumnNumber, i); _matrix()->get_column(pivotColumnNumber).clear(); barcode_.emplace_back(pivotColumnNumber, i, dim - 1); @@ -212,6 +202,20 @@ inline void Base_pairing::_reduce() isReduced_ = true; } +template +inline void Base_pairing::_reduce_column_with(Column& toReduce, Column& toAdd) +{ + if constexpr (Master_matrix::Option_list::is_z2) { + toReduce += toAdd; + } else { + typename Master_matrix::Element coeff = toAdd.get_pivot_value(); + auto& operators = _matrix()->colSettings_->operators; + coeff = operators.get_inverse(coeff); + operators.multiply_inplace(coeff, operators.get_characteristic() - toReduce.get_pivot_value()); + toReduce.multiply_source_and_add(toAdd, coeff); + } +} + template inline void Base_pairing::_remove_last(Pos_index columnIndex) { diff --git a/multipers/gudhi/gudhi/Persistence_matrix/base_swap.h b/multipers/gudhi/gudhi/Persistence_matrix/base_swap.h index 44a3f525..66297498 100644 --- a/multipers/gudhi/gudhi/Persistence_matrix/base_swap.h +++ b/multipers/gudhi/gudhi/Persistence_matrix/base_swap.h @@ -205,6 +205,8 @@ template inline Base_swap& Base_swap::operator=( Base_swap&& other) noexcept { + if (this == &other) return *this; + indexToRow_ = std::move(other.indexToRow_); rowToIndex_ = std::move(other.rowToIndex_); rowSwapped_ = std::exchange(other.rowSwapped_, false); diff --git a/multipers/gudhi/gudhi/Persistence_matrix/chain_rep_cycles.h b/multipers/gudhi/gudhi/Persistence_matrix/chain_rep_cycles.h index a160018b..7fa1547e 100644 --- a/multipers/gudhi/gudhi/Persistence_matrix/chain_rep_cycles.h +++ b/multipers/gudhi/gudhi/Persistence_matrix/chain_rep_cycles.h @@ -18,10 +18,12 @@ #ifndef PM_CHAIN_REP_CYCLES_H #define PM_CHAIN_REP_CYCLES_H -#include //std::move -#include //std::sort #include +#ifdef GUDHI_USE_TBB +#include +#endif + #include namespace Gudhi { @@ -57,6 +59,7 @@ class Chain_representative_cycles using Column_container = typename Master_matrix::Column_container; /**< Column container type. */ using Index = typename Master_matrix::Index; /**< @ref MatIdx index type. */ using ID_index = typename Master_matrix::ID_index; /**< @ref IDIdx index type. */ + using Dimension = typename Master_matrix::Dimension; /**< Dimension type. */ /** * @brief Default constructor. @@ -65,11 +68,25 @@ class Chain_representative_cycles /** * @brief Computes the current representative cycles of the matrix. + * + * @param dim If different from default value, only the cycles of the given dimension are updated. + * All others are erased. + */ + void update_representative_cycles(Dimension dim = Master_matrix::template get_null_value()); + + /** + * @brief Computes the current representative cycle of the given bar. All other cycles already computed are left + * untouched (and therefore they could be unvalid for the current matrix). + * + * @note For chain matrices with enabled vine swaps, this method will only be more efficient than + * @ref update_representative_cycles if not called for too many bars. + * + * @param bar Bar corresponding to the wanted representative cycle. */ - void update_representative_cycles(); + void update_representative_cycle(const Bar& bar); /** - * @brief Returns the current representative cycles. If the matrix is modified later after the first call, + * @brief Returns the current representative cycles. If the matrix was modified since the last call, * @ref update_representative_cycles has to be called to update the returned cycles. * * @return A const reference to a vector of @ref Matrix::Cycle containing all representative cycles. @@ -77,8 +94,8 @@ class Chain_representative_cycles const std::vector& get_representative_cycles(); /** * @brief Returns the representative cycle corresponding to the given bar. - * If the matrix is modified later after the first call, - * @ref update_representative_cycles has to be called to update the returned cycles. + * If the matrix was modified since the last call, @ref update_representative_cycles or + * @ref update_representative_cycle has to be called to update the returned cycle. * * @param bar Bar corresponding to the wanted representative cycle. * @return A const reference to the representative cycle. @@ -110,9 +127,9 @@ class Chain_representative_cycles }; template -inline void Chain_representative_cycles::update_representative_cycles() +inline void Chain_representative_cycles::update_representative_cycles(Dimension dim) { - auto nberColumns = _matrix()->get_number_of_columns(); + Index nberColumns = _matrix()->get_number_of_columns(); auto get_position = [&](ID_index pivot) { if constexpr (Master_matrix::Option_list::has_vine_update) { if constexpr (Master_matrix::Option_list::has_map_column_container) { @@ -124,39 +141,82 @@ inline void Chain_representative_cycles::update_representative_cy return pivot; } }; + Index nullValue = Master_matrix::template get_null_value(); birthToCycle_.clear(); - birthToCycle_.resize(nberColumns, Master_matrix::template get_null_value()); + birthToCycle_.resize(nberColumns, nullValue); representativeCycles_.clear(); +#ifdef GUDHI_USE_TBB + Index c = 0; + for (Index i = 0; i < nberColumns; i++) { + auto& col = _matrix()->get_column(_matrix()->get_column_with_pivot(i)); + if ((dim == Master_matrix::template get_null_value() || _matrix()->get_column_dimension(i) == dim) && + (!col.is_paired() || get_position(i) < get_position(_matrix()->get_pivot(col.get_paired_chain_index())))) { + birthToCycle_[get_position(i)] = c; + ++c; + } + } + + representativeCycles_.resize(c); + tbb::parallel_for(static_cast(0), nberColumns, [&](Index i) { + auto idx = get_position(i); + if (birthToCycle_[idx] != nullValue) { + auto& col = _matrix()->get_column(_matrix()->get_column_with_pivot(i)); + representativeCycles_[birthToCycle_[idx]] = + Master_matrix::build_cycle_from_range(col.get_non_zero_content_range()); + } + }); +#else for (ID_index i = 0; i < nberColumns; i++) { auto& col = _matrix()->get_column(_matrix()->get_column_with_pivot(i)); - if (!col.is_paired() || get_position(i) < get_position(_matrix()->get_pivot(col.get_paired_chain_index()))) { - Cycle cycle; - if constexpr (is_well_behaved::value) { - cycle.reserve(col.size()); - for (const auto& c : col) { - if constexpr (Master_matrix::Option_list::is_z2) { - cycle.push_back(c.get_row_index()); - } else { - cycle.push_back({c.get_row_index(), c.get_element()}); - } - } + if ((dim == Master_matrix::template get_null_value() || _matrix()->get_column_dimension(i) == dim) && + (!col.is_paired() || get_position(i) < get_position(_matrix()->get_pivot(col.get_paired_chain_index())))) { + representativeCycles_.push_back(Master_matrix::build_cycle_from_range(col.get_non_zero_content_range())); + birthToCycle_[get_position(i)] = representativeCycles_.size() - 1; + } + } +#endif +} + +template +inline void Chain_representative_cycles::update_representative_cycle(const Bar& bar) +{ + auto nberColumns = _matrix()->get_number_of_columns(); + auto get_position = [&](ID_index pivot) { + if constexpr (Master_matrix::Option_list::has_vine_update) { + if constexpr (Master_matrix::Option_list::has_map_column_container) { + return _matrix()->map_.at(pivot); } else { - auto cont = col.get_content(); - for (Index j = 0; j < cont.size(); ++j) { - if (cont[j] != 0) { - if constexpr (Master_matrix::Option_list::is_z2) { - cycle.push_back(j); - } else { - cycle.push_back({j, cont[j]}); - } - } - } + return _matrix()->map_[pivot]; + } + } else { + return pivot; + } + }; + + Index nullValue = Master_matrix::template get_null_value(); + + if (birthToCycle_.size() <= bar.birth) { + birthToCycle_.resize(bar.birth + 1, nullValue); + } + if (birthToCycle_[bar.birth] == nullValue) { + birthToCycle_[bar.birth] = representativeCycles_.size(); + representativeCycles_.resize(representativeCycles_.size() + 1); + } + + if constexpr (Master_matrix::Option_list::has_vine_update) { + for (ID_index i = 0; i < nberColumns; i++) { + if (get_position(i) == bar.birth) { + auto& col = _matrix()->get_column(_matrix()->get_column_with_pivot(i)); + representativeCycles_[birthToCycle_[bar.birth]] = + Master_matrix::build_cycle_from_range(col.get_non_zero_content_range()); } - representativeCycles_.push_back(std::move(cycle)); - birthToCycle_[get_position(i)] = representativeCycles_.size() - 1; } + } else { + auto& col = _matrix()->get_column(_matrix()->get_column_with_pivot(bar.birth)); + representativeCycles_[birthToCycle_[bar.birth]] = + Master_matrix::build_cycle_from_range(col.get_non_zero_content_range()); } } @@ -164,7 +224,6 @@ template inline const std::vector::Cycle>& Chain_representative_cycles::get_representative_cycles() { - if (representativeCycles_.empty()) update_representative_cycles(); return representativeCycles_; } @@ -172,7 +231,6 @@ template inline const typename Chain_representative_cycles::Cycle& Chain_representative_cycles::get_representative_cycle(const Bar& bar) { - if (representativeCycles_.empty()) update_representative_cycles(); return representativeCycles_[birthToCycle_[bar.birth]]; } diff --git a/multipers/gudhi/gudhi/Persistence_matrix/columns/chain_column_extra_properties.h b/multipers/gudhi/gudhi/Persistence_matrix/columns/chain_column_extra_properties.h index cffb79de..7d18ac73 100644 --- a/multipers/gudhi/gudhi/Persistence_matrix/columns/chain_column_extra_properties.h +++ b/multipers/gudhi/gudhi/Persistence_matrix/columns/chain_column_extra_properties.h @@ -147,6 +147,8 @@ class Chain_column_extra_properties */ Chain_column_extra_properties& operator=(Chain_column_extra_properties&& other) noexcept { + if (this == &other) return *this; + pivot_ = std::exchange(other.pivot_, Master_matrix::template get_null_value()); pairedColumn_ = std::exchange(other.pairedColumn_, Master_matrix::template get_null_value()); return *this; diff --git a/multipers/gudhi/gudhi/Persistence_matrix/columns/column_dimension_holder.h b/multipers/gudhi/gudhi/Persistence_matrix/columns/column_dimension_holder.h index 8fb64b54..72495687 100644 --- a/multipers/gudhi/gudhi/Persistence_matrix/columns/column_dimension_holder.h +++ b/multipers/gudhi/gudhi/Persistence_matrix/columns/column_dimension_holder.h @@ -103,6 +103,8 @@ struct Column_dimension_holder { */ Column_dimension_holder& operator=(Column_dimension_holder&& other) noexcept { + if (this == &other) return *this; + dim_ = std::exchange(other.dim_, Master_matrix::template get_null_value()); return *this; } diff --git a/multipers/gudhi/gudhi/Persistence_matrix/columns/column_utilities.h b/multipers/gudhi/gudhi/Persistence_matrix/columns/column_utilities.h index cad34ddf..d55260d8 100644 --- a/multipers/gudhi/gudhi/Persistence_matrix/columns/column_utilities.h +++ b/multipers/gudhi/gudhi/Persistence_matrix/columns/column_utilities.h @@ -43,8 +43,8 @@ void _generic_merge_entry_to_column(Column& targetColumn, typename Column::Column_support::iterator& itTarget, F1&& process_target, F2&& process_source, - F3&& update_target1, - F4&& update_target2, + [[maybe_unused]] F3&& update_target1, + [[maybe_unused]] F4&& update_target2, bool& pivotIsZeroed) { typename Column::Entry* targetEntry = _get_entry(itTarget); @@ -123,11 +123,7 @@ bool _add_to_column(const Entry_range& source, Column& targetColumn) targetColumn, [&]([[maybe_unused]] typename Column::Entry* entryTarget) {}, [&](typename Entry_range::const_iterator& itSource, const typename Column::Column_support::iterator& itTarget) { - if constexpr (Column::Master::Option_list::is_z2) { - targetColumn._insert_entry(itSource->get_row_index(), itTarget); - } else { - targetColumn._insert_entry(itSource->get_element(), itSource->get_row_index(), itTarget); - } + targetColumn._insert_entry(itTarget, itSource->get_row_index(), itSource->get_element()); }, [&](typename Column::Field_element& targetElement, typename Entry_range::const_iterator& itSource) { if constexpr (!Column::Master::Option_list::is_z2) @@ -142,39 +138,48 @@ bool _multiply_target_and_add_to_column(const typename Column::Field_element& va const Entry_range& source, Column& targetColumn) { - if (val == 0U) { + if (val == Column::Field_operators::get_additive_identity()) { if constexpr (Column::Master::isNonBasic && !Column::Master::Option_list::is_of_boundary_type) { - throw std::invalid_argument("A chain column should not be multiplied by 0."); // this would not only mess up the base, but also the pivots stored. + throw std::invalid_argument("A chain column should not be multiplied by 0."); } else { targetColumn.clear(); + return _add_to_column(source, targetColumn); } } - return _generic_add_to_column( - source, - targetColumn, - [&](typename Column::Entry* entryTarget) { - targetColumn.operators_->multiply_inplace(entryTarget->get_element(), val); - // targetColumn.RA_opt::update_entry(*itTarget) produces an internal compiler error - // even though it works in _generic_add_to_column... Probably because of the lambda. - if constexpr (Column::Master::Option_list::has_row_access) targetColumn.update_entry(*entryTarget); - }, - [&](typename Entry_range::const_iterator& itSource, const typename Column::Column_support::iterator& itTarget) { - targetColumn._insert_entry(itSource->get_element(), itSource->get_row_index(), itTarget); - }, - [&](typename Column::Field_element& targetElement, typename Entry_range::const_iterator& itSource) { - targetColumn.operators_->multiply_and_add_inplace_front(targetElement, val, itSource->get_element()); - }, - [&]([[maybe_unused]] typename Column::Entry* entryTarget) {}, - [&](typename Column::Column_support::iterator& itTarget) { - while (itTarget != targetColumn.column_.end()) { - typename Column::Entry* targetEntry = _get_entry(itTarget); - targetColumn.operators_->multiply_inplace(targetEntry->get_element(), val); - if constexpr (Column::Master::Option_list::has_row_access) targetColumn.update_entry(*targetEntry); - itTarget++; - } - }); + if (val == Column::Field_operators::get_multiplicative_identity()) { + return _add_to_column(source, targetColumn); + } + + if constexpr (!Column::Master::Option_list::is_z2) { + return _generic_add_to_column( + source, + targetColumn, + [&](typename Column::Entry* entryTarget) { + targetColumn.operators_->multiply_inplace(entryTarget->get_element(), val); + // targetColumn.RA_opt::update_entry(*itTarget) produces an internal compiler error + // even though it works in _generic_add_to_column... Probably because of the lambda. + if constexpr (Column::Master::Option_list::has_row_access) targetColumn.update_entry(*entryTarget); + }, + [&](typename Entry_range::const_iterator& itSource, const typename Column::Column_support::iterator& itTarget) { + targetColumn._insert_entry(itTarget, itSource->get_row_index(), itSource->get_element()); + }, + [&](typename Column::Field_element& targetElement, typename Entry_range::const_iterator& itSource) { + targetColumn.operators_->multiply_and_add_inplace_front(targetElement, val, itSource->get_element()); + }, + [&]([[maybe_unused]] typename Column::Entry* entryTarget) {}, + [&](typename Column::Column_support::iterator& itTarget) { + while (itTarget != targetColumn.column_.end()) { + typename Column::Entry* targetEntry = _get_entry(itTarget); + targetColumn.operators_->multiply_inplace(targetEntry->get_element(), val); + if constexpr (Column::Master::Option_list::has_row_access) targetColumn.update_entry(*targetEntry); + itTarget++; + } + }); + } else { + return false; // we should never arrive here, just to suppress the warning + } } template @@ -182,25 +187,33 @@ bool _multiply_source_and_add_to_column(const typename Column::Field_element& va const Entry_range& source, Column& targetColumn) { - if (val == 0U) { + if (val == Column::Field_operators::get_additive_identity()) { return false; } - return _generic_add_to_column( - source, - targetColumn, - []([[maybe_unused]] typename Column::Entry* entryTarget) {}, - [&](typename Entry_range::const_iterator& itSource, const typename Column::Column_support::iterator& itTarget) { - typename Column::Entry* entry = - targetColumn._insert_entry(itSource->get_element(), itSource->get_row_index(), itTarget); - targetColumn.operators_->multiply_inplace(entry->get_element(), val); - if constexpr (Column::Master::Option_list::has_row_access) targetColumn.update_entry(*entry); - }, - [&](typename Column::Field_element& targetElement, typename Entry_range::const_iterator& itSource) { - targetColumn.operators_->multiply_and_add_inplace_back(itSource->get_element(), val, targetElement); - }, - [&]([[maybe_unused]] typename Column::Entry* entryTarget) {}, - []([[maybe_unused]] typename Column::Column_support::iterator& itTarget) {}); + if (val == Column::Field_operators::get_multiplicative_identity()) { + return _add_to_column(source, targetColumn); + } + + if constexpr (!Column::Master::Option_list::is_z2) { + return _generic_add_to_column( + source, + targetColumn, + []([[maybe_unused]] typename Column::Entry* entryTarget) {}, + [&](typename Entry_range::const_iterator& itSource, const typename Column::Column_support::iterator& itTarget) { + typename Column::Entry* entry = + targetColumn._insert_entry(itTarget, itSource->get_row_index(), itSource->get_element()); + targetColumn.operators_->multiply_inplace(entry->get_element(), val); + if constexpr (Column::Master::Option_list::has_row_access) targetColumn.update_entry(*entry); + }, + [&](typename Column::Field_element& targetElement, typename Entry_range::const_iterator& itSource) { + targetColumn.operators_->multiply_and_add_inplace_back(itSource->get_element(), val, targetElement); + }, + [&]([[maybe_unused]] typename Column::Entry* entryTarget) {}, + []([[maybe_unused]] typename Column::Column_support::iterator& itTarget) {}); + } else { + return false; // we should never arrive here, just to suppress the warning + } } // column has to be ordered (ie. not suited for unordered_map and heap) and contain the exact values diff --git a/multipers/gudhi/gudhi/Persistence_matrix/columns/entry_types.h b/multipers/gudhi/gudhi/Persistence_matrix/columns/entry_types.h index 4e9cce35..40f9485a 100644 --- a/multipers/gudhi/gudhi/Persistence_matrix/columns/entry_types.h +++ b/multipers/gudhi/gudhi/Persistence_matrix/columns/entry_types.h @@ -53,6 +53,9 @@ struct Dummy_entry_field_element_mixin { template Dummy_entry_field_element_mixin([[maybe_unused]] Field_element t) {} + + static constexpr bool get_element() { return true; }; + static constexpr void set_element(bool /* element */) {} }; /** @@ -236,6 +239,8 @@ class Entry : public Master_matrix::Entry_column_index_option, */ Entry& operator=(Entry&& other) && noexcept { + if (this == &other) return *this; + col_opt::operator=(std::move(other)); field_opt::operator=(std::move(other)); rowIndex_ = std::exchange(other.rowIndex_, 0); @@ -276,11 +281,7 @@ class Entry : public Master_matrix::Entry_column_index_option, */ operator std::pair() const { - if constexpr (Master_matrix::Option_list::is_z2) { - return {rowIndex_, 1}; - } else { - return {rowIndex_, field_opt::element_}; - } + return {rowIndex_, field_opt::get_element()}; } private: diff --git a/multipers/gudhi/gudhi/Persistence_matrix/columns/heap_column.h b/multipers/gudhi/gudhi/Persistence_matrix/columns/heap_column.h index 8a2325f2..9533d717 100644 --- a/multipers/gudhi/gudhi/Persistence_matrix/columns/heap_column.h +++ b/multipers/gudhi/gudhi/Persistence_matrix/columns/heap_column.h @@ -18,11 +18,12 @@ #ifndef PM_HEAP_COLUMN_H #define PM_HEAP_COLUMN_H -#include #include #include -#include //binary_search -#include //std::swap, std::move & std::exchange +#include // std::size_t +#include // std::make_heap +#include // std::swap, std::move & std::exchange +#include #include @@ -68,12 +69,16 @@ class Heap_column : public Master_matrix::Column_dimension_option, public Master using const_iterator = boost::indirect_iterator; using reverse_iterator = boost::indirect_iterator; using const_reverse_iterator = boost::indirect_iterator; + using Content_range = std::vector; Heap_column(Column_settings* colSettings = nullptr); template Heap_column(const Container& nonZeroRowIndices, Column_settings* colSettings); - template + template > > Heap_column(const Container& nonZeroRowIndices, Dimension dimension, Column_settings* colSettings); + Heap_column(ID_index idx, Dimension dimension, Column_settings* colSettings); + Heap_column(ID_index idx, Field_element e, Dimension dimension, Column_settings* colSettings); Heap_column(const Heap_column& column, Column_settings* colSettings = nullptr); Heap_column(Heap_column&& column) noexcept; ~Heap_column(); @@ -81,20 +86,35 @@ class Heap_column : public Master_matrix::Column_dimension_option, public Master // just for the sake of the interface // row containers and column index are ignored as row access is not implemented for heap columns template - Heap_column(Index columnIndex, + Heap_column([[maybe_unused]] Index columnIndex, const Container& nonZeroRowIndices, - Row_container* rowContainer, + [[maybe_unused]] Row_container* rowContainer, Column_settings* colSettings); - template - Heap_column(Index columnIndex, + template > > + Heap_column([[maybe_unused]] Index columnIndex, const Container& nonZeroRowIndices, Dimension dimension, - Row_container* rowContainer, + [[maybe_unused]] Row_container* rowContainer, + Column_settings* colSettings); + template + Heap_column([[maybe_unused]] Index columnIndex, + ID_index idx, + Dimension dimension, + [[maybe_unused]] Row_container* rowContainer, + Column_settings* colSettings); + template + Heap_column([[maybe_unused]] Index columnIndex, + ID_index idx, + Field_element e, + Dimension dimension, + [[maybe_unused]] Row_container* rowContainer, Column_settings* colSettings); template Heap_column(const Heap_column& column, - Index columnIndex, - Row_container* rowContainer, + [[maybe_unused]] Index columnIndex, + [[maybe_unused]] Row_container* rowContainer, Column_settings* colSettings = nullptr); std::vector get_content(int columnLength = -1) const; @@ -120,11 +140,13 @@ class Heap_column : public Master_matrix::Column_dimension_option, public Master reverse_iterator rend() noexcept; const_reverse_iterator rend() const noexcept; + Content_range get_non_zero_content_range(); + template Heap_column& operator+=(const Entry_range& column); Heap_column& operator+=(Heap_column& column); - Heap_column& operator*=(unsigned int v); + Heap_column& operator*=(const Field_element& v); // this = v * this + column template @@ -147,31 +169,31 @@ class Heap_column : public Master_matrix::Column_dimension_option, public Master Entry* p1 = cc1._pop_pivot(); Entry* p2 = cc2._pop_pivot(); while (p1 != nullptr && p2 != nullptr) { - if (p1->get_row_index() != p2->get_row_index()) { - c1.entryPool_->destroy(p1); - c2.entryPool_->destroy(p2); - return false; - } - if constexpr (!Master_matrix::Option_list::is_z2) { - if (p1->get_element() != p2->get_element()) { - c1.entryPool_->destroy(p1); - c2.entryPool_->destroy(p2); - return false; - } - } + Index r1 = Master_matrix::get_row_index(*p1); + Index r2 = Master_matrix::get_row_index(*p2); + Field_element e1 = Master_matrix::get_element(*p1); + Field_element e2 = Master_matrix::get_element(*p2); c1.entryPool_->destroy(p1); c2.entryPool_->destroy(p2); + + if (r1 != r2 || e1 != e2) { + return false; + } + p1 = cc1._pop_pivot(); p2 = cc2._pop_pivot(); } - if (p1 == nullptr && p2 == nullptr) return true; if (p1 != nullptr) { c1.entryPool_->destroy(p1); return false; } - c2.entryPool_->destroy(p2); - return false; + if (p2 != nullptr) { + c1.entryPool_->destroy(p2); + return false; + } + + return true; } friend bool operator<(const Heap_column& c1, const Heap_column& c2) @@ -183,30 +205,16 @@ class Heap_column : public Master_matrix::Column_dimension_option, public Master Entry* p1 = cc1._pop_pivot(); Entry* p2 = cc2._pop_pivot(); while (p1 != nullptr && p2 != nullptr) { - if (p1->get_row_index() > p2->get_row_index()) { - c1.entryPool_->destroy(p1); - c2.entryPool_->destroy(p2); - return false; - } - if (p1->get_row_index() < p2->get_row_index()) { - c1.entryPool_->destroy(p1); - c2.entryPool_->destroy(p2); - return true; - } - if constexpr (!Master_matrix::Option_list::is_z2) { - if (p1->get_element() > p2->get_element()) { - c1.entryPool_->destroy(p1); - c2.entryPool_->destroy(p2); - return false; - } - if (p1->get_element() < p2->get_element()) { - c1.entryPool_->destroy(p1); - c2.entryPool_->destroy(p2); - return true; - } - } + Index r1 = Master_matrix::get_row_index(*p1); + Index r2 = Master_matrix::get_row_index(*p2); + Field_element e1 = Master_matrix::get_element(*p1); + Field_element e2 = Master_matrix::get_element(*p2); c1.entryPool_->destroy(p1); c2.entryPool_->destroy(p2); + + if (r1 != r2) return r1 < r2; + if (e1 != e2) return e1 < e2; + p1 = cc1._pop_pivot(); p2 = cc2._pop_pivot(); } @@ -245,17 +253,21 @@ class Heap_column : public Master_matrix::Column_dimension_option, public Master Column_support column_; unsigned int insertsSinceLastPrune_; - Field_operators* operators_; + Field_operators const* operators_; Entry_constructor* entryPool_; void _prune(); Entry* _pop_pivot(); template - bool _add(const Entry_range& column); + void _add(const Entry_range& column, Field_element& pivotVal); + template + std::conditional_t _multiply(const Field_element& val); template bool _multiply_target_and_add(const Field_element& val, const Entry_range& column); template bool _multiply_source_and_add(const Entry_range& column, const Field_element& val); + void _add_coefficient(Field_element& e, const Field_element& a) const; + Field_element _multiply_coefficient(const Field_element& e, const Field_element& a) const; }; template @@ -263,109 +275,94 @@ inline Heap_column::Heap_column(Column_settings* colSettings) : Dim_opt(), Chain_opt(), insertsSinceLastPrune_(0), - operators_(nullptr), + operators_(Master_matrix::get_operator_ptr(colSettings)), entryPool_(colSettings == nullptr ? nullptr : &(colSettings->entryConstructor)) -{ - if (colSettings == nullptr) return; // to allow default constructor which gives a dummy column - - if constexpr (!Master_matrix::Option_list::is_z2) { - operators_ = &(colSettings->operators); - } -} +{} template template inline Heap_column::Heap_column(const Container& nonZeroRowIndices, Column_settings* colSettings) - : Dim_opt(nonZeroRowIndices.size() == 0 ? 0 : nonZeroRowIndices.size() - 1), - Chain_opt(), - column_(nonZeroRowIndices.size(), nullptr), - insertsSinceLastPrune_(0), - operators_(nullptr), - entryPool_(&(colSettings->entryConstructor)) + : Heap_column(nonZeroRowIndices, nonZeroRowIndices.size() == 0 ? 0 : nonZeroRowIndices.size() - 1, colSettings) { static_assert(!Master_matrix::isNonBasic || Master_matrix::Option_list::is_of_boundary_type, "Constructor not available for chain columns, please specify the dimension of the chain."); - - if constexpr (!Master_matrix::Option_list::is_z2) { - operators_ = &(colSettings->operators); - } - - Index i = 0; - if constexpr (Master_matrix::Option_list::is_z2) { - for (ID_index id : nonZeroRowIndices) { - column_[i++] = entryPool_->construct(id); - } - } else { - for (const auto& p : nonZeroRowIndices) { - column_[i] = entryPool_->construct(p.first); - column_[i++]->set_element(operators_->get_value(p.second)); - } - } - std::make_heap(column_.begin(), column_.end(), entryPointerComp_); } template -template +template inline Heap_column::Heap_column(const Container& nonZeroRowIndices, Dimension dimension, Column_settings* colSettings) : Dim_opt(dimension), - Chain_opt([&] { - if constexpr (Master_matrix::Option_list::is_z2) { - return nonZeroRowIndices.begin() == nonZeroRowIndices.end() - ? Master_matrix::template get_null_value() - : *std::prev(nonZeroRowIndices.end()); - } else { - return nonZeroRowIndices.begin() == nonZeroRowIndices.end() - ? Master_matrix::template get_null_value() - : std::prev(nonZeroRowIndices.end())->first; - } - }()), + Chain_opt(nonZeroRowIndices.begin() == nonZeroRowIndices.end() + ? Master_matrix::template get_null_value() + : Master_matrix::get_row_index(*std::prev(nonZeroRowIndices.end()))), column_(nonZeroRowIndices.size(), nullptr), insertsSinceLastPrune_(0), - operators_(nullptr), + operators_(Master_matrix::get_operator_ptr(colSettings)), entryPool_(&(colSettings->entryConstructor)) { Index i = 0; - if constexpr (Master_matrix::Option_list::is_z2) { - for (ID_index id : nonZeroRowIndices) { - column_[i++] = entryPool_->construct(id); - } - } else { - operators_ = &(colSettings->operators); - for (const auto& p : nonZeroRowIndices) { - column_[i] = entryPool_->construct(p.first); - column_[i++]->set_element(operators_->get_value(p.second)); - } + + for (const auto& id : nonZeroRowIndices) { + column_[i] = entryPool_->construct(Master_matrix::get_row_index(id)); + column_[i]->set_element(Master_matrix::get_coefficient_value(Master_matrix::get_element(id), operators_)); + ++i; } + std::make_heap(column_.begin(), column_.end(), entryPointerComp_); } +template +inline Heap_column::Heap_column(ID_index idx, Dimension dimension, Column_settings* colSettings) + : Dim_opt(dimension), + Chain_opt(idx), + column_(1, nullptr), + insertsSinceLastPrune_(0), + operators_(nullptr), + entryPool_(&(colSettings->entryConstructor)) +{ + static_assert(Master_matrix::Option_list::is_z2, + "Constructor not available for Zp != Z2. Please specify the coefficient."); + column_[0] = entryPool_->construct(idx); +} + +template +inline Heap_column::Heap_column(ID_index idx, + Field_element e, + Dimension dimension, + Column_settings* colSettings) + : Dim_opt(dimension), + Chain_opt(idx), + column_(1, nullptr), + insertsSinceLastPrune_(0), + operators_(&(colSettings->operators)), + entryPool_(&(colSettings->entryConstructor)) +{ + static_assert(!Master_matrix::Option_list::is_z2, + "Constructor not available for Zp == Z2. Please do not specify any coefficient."); + column_[0] = entryPool_->construct(idx); + column_[0]->set_element(operators_->get_value(e)); +} + template inline Heap_column::Heap_column(const Heap_column& column, Column_settings* colSettings) : Dim_opt(static_cast(column)), Chain_opt(static_cast(column)), column_(column.column_.size(), nullptr), insertsSinceLastPrune_(0), - operators_(colSettings == nullptr ? column.operators_ : nullptr), + operators_(colSettings == nullptr ? column.operators_ : Master_matrix::get_operator_ptr(colSettings)), entryPool_(colSettings == nullptr ? column.entryPool_ : &(colSettings->entryConstructor)) { static_assert(!Master_matrix::Option_list::has_row_access, "Simple copy constructor not available when row access option enabled. Please specify the new column " "index and the row container."); - if constexpr (!Master_matrix::Option_list::is_z2) { - if (colSettings != nullptr) operators_ = &(colSettings->operators); - } - Index i = 0; for (const Entry* entry : column.column_) { - if constexpr (Master_matrix::Option_list::is_z2) { - column_[i++] = entryPool_->construct(entry->get_row_index()); - } else { - column_[i] = entryPool_->construct(entry->get_row_index()); - column_[i++]->set_element(entry->get_element()); - } + column_[i] = entryPool_->construct(entry->get_row_index()); + column_[i]->set_element(entry->get_element()); + ++i; } // column.column_ already ordered as a heap, so no need of make_heap. } @@ -378,117 +375,59 @@ inline Heap_column::Heap_column(Heap_column&& column) noexcept insertsSinceLastPrune_(std::exchange(column.insertsSinceLastPrune_, 0)), operators_(std::exchange(column.operators_, nullptr)), entryPool_(std::exchange(column.entryPool_, nullptr)) -{ -} +{} template template -inline Heap_column::Heap_column(Index columnIndex, +inline Heap_column::Heap_column([[maybe_unused]] Index columnIndex, const Container& nonZeroRowIndices, - Row_container* rowContainer, + [[maybe_unused]] Row_container* rowContainer, Column_settings* colSettings) - : Dim_opt(nonZeroRowIndices.size() == 0 ? 0 : nonZeroRowIndices.size() - 1), - Chain_opt([&] { - if constexpr (Master_matrix::Option_list::is_z2) { - return nonZeroRowIndices.begin() == nonZeroRowIndices.end() - ? Master_matrix::template get_null_value() - : *std::prev(nonZeroRowIndices.end()); - } else { - return nonZeroRowIndices.begin() == nonZeroRowIndices.end() - ? Master_matrix::template get_null_value() - : std::prev(nonZeroRowIndices.end())->first; - } - }()), - column_(nonZeroRowIndices.size(), nullptr), - insertsSinceLastPrune_(0), - operators_(nullptr), - entryPool_(&(colSettings->entryConstructor)) + : Heap_column(nonZeroRowIndices, colSettings) { static_assert(!Master_matrix::isNonBasic || Master_matrix::Option_list::is_of_boundary_type, "Constructor not available for chain columns, please specify the dimension of the chain."); - - Index i = 0; - if constexpr (Master_matrix::Option_list::is_z2) { - for (ID_index id : nonZeroRowIndices) { - column_[i++] = entryPool_->construct(id); - } - } else { - operators_ = &(colSettings->operators); - for (const auto& p : nonZeroRowIndices) { - column_[i] = entryPool_->construct(p.first); - column_[i++]->set_element(operators_->get_value(p.second)); - } - } - std::make_heap(column_.begin(), column_.end(), entryPointerComp_); } template -template -inline Heap_column::Heap_column(Index columnIndex, +template +inline Heap_column::Heap_column([[maybe_unused]] Index columnIndex, const Container& nonZeroRowIndices, Dimension dimension, - Row_container* rowContainer, + [[maybe_unused]] Row_container* rowContainer, Column_settings* colSettings) - : Dim_opt(dimension), - Chain_opt([&] { - if constexpr (Master_matrix::Option_list::is_z2) { - return nonZeroRowIndices.begin() == nonZeroRowIndices.end() - ? Master_matrix::template get_null_value() - : *std::prev(nonZeroRowIndices.end()); - } else { - return nonZeroRowIndices.begin() == nonZeroRowIndices.end() - ? Master_matrix::template get_null_value() - : std::prev(nonZeroRowIndices.end())->first; - } - }()), - column_(nonZeroRowIndices.size(), nullptr), - insertsSinceLastPrune_(0), - operators_(nullptr), - entryPool_(&(colSettings->entryConstructor)) -{ - Index i = 0; - if constexpr (Master_matrix::Option_list::is_z2) { - for (ID_index id : nonZeroRowIndices) { - column_[i++] = entryPool_->construct(id); - } - } else { - operators_ = &(colSettings->operators); - for (const auto& p : nonZeroRowIndices) { - column_[i] = entryPool_->construct(p.first); - column_[i++]->set_element(operators_->get_value(p.second)); - } - } - std::make_heap(column_.begin(), column_.end(), entryPointerComp_); -} + : Heap_column(nonZeroRowIndices, dimension, colSettings) +{} template template inline Heap_column::Heap_column(const Heap_column& column, - Index columnIndex, - Row_container* rowContainer, + [[maybe_unused]] Index columnIndex, + [[maybe_unused]] Row_container* rowContainer, Column_settings* colSettings) - : Dim_opt(static_cast(column)), - Chain_opt(static_cast(column)), - column_(column.column_.size(), nullptr), - insertsSinceLastPrune_(0), - operators_(colSettings == nullptr ? column.operators_ : nullptr), - entryPool_(colSettings == nullptr ? column.entryPool_ : &(colSettings->entryConstructor)) -{ - if constexpr (!Master_matrix::Option_list::is_z2) { - if (colSettings != nullptr) operators_ = &(colSettings->operators); - } + : Heap_column(column, colSettings) +{} - Index i = 0; - for (const Entry* entry : column.column_) { - if constexpr (Master_matrix::Option_list::is_z2) { - column_[i++] = entryPool_->construct(entry->get_row_index()); - } else { - column_[i] = entryPool_->construct(entry->get_row_index()); - column_[i++]->set_element(entry->get_element()); - } - } - // column.column_ already ordered as a heap, so no need of make_heap. -} +template +template +inline Heap_column::Heap_column([[maybe_unused]] Index columnIndex, + ID_index idx, + Dimension dimension, + [[maybe_unused]] Row_container* rowContainer, + Column_settings* colSettings) + : Heap_column(idx, dimension, colSettings) +{} + +template +template +inline Heap_column::Heap_column([[maybe_unused]] Index columnIndex, + ID_index idx, + Field_element e, + Dimension dimension, + [[maybe_unused]] Row_container* rowContainer, + Column_settings* colSettings) + : Heap_column(idx, e, dimension, colSettings) +{} template inline Heap_column::~Heap_column() @@ -510,11 +449,14 @@ inline std::vector::Field_element> Heap_colu std::vector container(columnLength, 0); for (auto it = column_.begin(); it != column_.end(); ++it) { - if ((*it)->get_row_index() < static_cast(columnLength)) { + auto idx = (*it)->get_row_index(); + if (idx < static_cast(columnLength)) { + // Cannot use _add_coefficient because of vector + // I would have to do a special case for it, but it only happens here, so... if constexpr (Master_matrix::Option_list::is_z2) { - container[(*it)->get_row_index()] = !container[(*it)->get_row_index()]; + container[idx] = !container[idx]; } else { - operators_->add_inplace(container[(*it)->get_row_index()], (*it)->get_element()); + operators_->add_inplace(container[idx], (*it)->get_element()); } } } @@ -532,10 +474,7 @@ inline bool Heap_column::is_non_zero(ID_index rowIndex) const Field_element c(0); for (const Entry* entry : column_) { if (entry->get_row_index() == rowIndex) { - if constexpr (Master_matrix::Option_list::is_z2) - c = !c; - else - operators_->add_inplace(c, entry->get_element()); + _add_coefficient(c, entry->get_element()); } } return c != Field_operators::get_additive_identity(); @@ -709,6 +648,16 @@ inline typename Heap_column::const_reverse_iterator Heap_column +inline typename Heap_column::Content_range Heap_column::get_non_zero_content_range() +{ + _prune(); + Content_range res(column_.size()); + for (std::size_t i = 0; i < column_.size(); ++i) res[i] = *column_[i]; + std::sort(res.begin(), res.end()); + return res; +} + template template inline Heap_column& Heap_column::operator+=(const Entry_range& column) @@ -719,7 +668,8 @@ inline Heap_column& Heap_column::operator+=(const static_assert((!Master_matrix::isNonBasic || Master_matrix::Option_list::is_of_boundary_type), "For chain columns, the given column cannot be constant."); - _add(column); + Field_element dummy(0); + _add(column, dummy); return *this; } @@ -728,47 +678,25 @@ template inline Heap_column& Heap_column::operator+=(Heap_column& column) { if constexpr (Master_matrix::isNonBasic && !Master_matrix::Option_list::is_of_boundary_type) { + Field_element v = get_pivot_value(); + _add(column, v); // assumes that the addition never zeros out this column. - if (_add(column)) { + if (v == Field_operators::get_additive_identity()) { Chain_opt::_swap_pivots(column); Dim_opt::_swap_dimension(column); } } else { - _add(column); + Field_element dummy(0); + _add(column, dummy); } return *this; } template -inline Heap_column& Heap_column::operator*=(unsigned int v) +inline Heap_column& Heap_column::operator*=(const Field_element& v) { - if constexpr (Master_matrix::Option_list::is_z2) { - if (v % 2 == 0) { - if constexpr (Master_matrix::isNonBasic && !Master_matrix::Option_list::is_of_boundary_type) { - throw std::invalid_argument("A chain column should not be multiplied by 0."); - } else { - clear(); - } - } - } else { - Field_element val = operators_->get_value(v); - - if (val == Field_operators::get_additive_identity()) { - if constexpr (Master_matrix::isNonBasic && !Master_matrix::Option_list::is_of_boundary_type) { - throw std::invalid_argument("A chain column should not be multiplied by 0."); - } else { - clear(); - } - return *this; - } - - if (val == Field_operators::get_multiplicative_identity()) return *this; - - for (Entry* entry : column_) { - operators_->multiply_inplace(entry->get_element(), val); - } - } + _multiply(Master_matrix::get_coefficient_value(v, operators_)); return *this; } @@ -784,16 +712,7 @@ inline Heap_column& Heap_column::multiply_target_a static_assert((!Master_matrix::isNonBasic || Master_matrix::Option_list::is_of_boundary_type), "For chain columns, the given column cannot be constant."); - if constexpr (Master_matrix::Option_list::is_z2) { - if (val) { - _add(column); - } else { - clear(); - _add(column); - } - } else { - _multiply_target_and_add(val, column); - } + _multiply_target_and_add(Master_matrix::get_coefficient_value(val, operators_), column); return *this; } @@ -804,32 +723,12 @@ inline Heap_column& Heap_column::multiply_target_a { if constexpr (Master_matrix::isNonBasic && !Master_matrix::Option_list::is_of_boundary_type) { // assumes that the addition never zeros out this column. - if constexpr (Master_matrix::Option_list::is_z2) { - if (val) { - if (_add(column)) { - Chain_opt::_swap_pivots(column); - Dim_opt::_swap_dimension(column); - } - } else { - throw std::invalid_argument("A chain column should not be multiplied by 0."); - } - } else { - if (_multiply_target_and_add(val, column)) { - Chain_opt::_swap_pivots(column); - Dim_opt::_swap_dimension(column); - } + if (_multiply_target_and_add(Master_matrix::get_coefficient_value(val, operators_), column)) { + Chain_opt::_swap_pivots(column); + Dim_opt::_swap_dimension(column); } } else { - if constexpr (Master_matrix::Option_list::is_z2) { - if (val) { - _add(column); - } else { - clear(); - _add(column); - } - } else { - _multiply_target_and_add(val, column); - } + _multiply_target_and_add(Master_matrix::get_coefficient_value(val, operators_), column); } return *this; @@ -846,13 +745,7 @@ inline Heap_column& Heap_column::multiply_source_a static_assert((!Master_matrix::isNonBasic || Master_matrix::Option_list::is_of_boundary_type), "For chain columns, the given column cannot be constant."); - if constexpr (Master_matrix::Option_list::is_z2) { - if (val) { - _add(column); - } - } else { - _multiply_source_and_add(column, val); - } + _multiply_source_and_add(column, Master_matrix::get_coefficient_value(val, operators_)); return *this; } @@ -863,27 +756,12 @@ inline Heap_column& Heap_column::multiply_source_a { if constexpr (Master_matrix::isNonBasic && !Master_matrix::Option_list::is_of_boundary_type) { // assumes that the addition never zeros out this column. - if constexpr (Master_matrix::Option_list::is_z2) { - if (val) { - if (_add(column)) { - Chain_opt::_swap_pivots(column); - Dim_opt::_swap_dimension(column); - } - } - } else { - if (_multiply_source_and_add(column, val)) { - Chain_opt::_swap_pivots(column); - Dim_opt::_swap_dimension(column); - } + if (_multiply_source_and_add(column, Master_matrix::get_coefficient_value(val, operators_))) { + Chain_opt::_swap_pivots(column); + Dim_opt::_swap_dimension(column); } } else { - if constexpr (Master_matrix::Option_list::is_z2) { - if (val) { - _add(column); - } - } else { - _multiply_source_and_add(column, val); - } + _multiply_source_and_add(column, Master_matrix::get_coefficient_value(val, operators_)); } return *this; @@ -897,9 +775,7 @@ inline void Heap_column::push_back(const Entry& entry) GUDHI_CHECK(entry.get_row_index() > get_pivot(), "The new row index has to be higher than the current pivot."); Entry* newEntry = entryPool_->construct(entry.get_row_index()); - if constexpr (!Master_matrix::Option_list::is_z2) { - newEntry->set_element(operators_->get_value(entry.get_element())); - } + newEntry->set_element(Master_matrix::get_coefficient_value(entry.get_element(), operators_)); column_.push_back(newEntry); std::push_heap(column_.begin(), column_.end(), entryPointerComp_); } @@ -927,9 +803,7 @@ inline Heap_column& Heap_column::operator=(const H entryPool_->destroy(column_[i]); } column_[i] = other.entryPool_->construct(entry->get_row_index()); - if constexpr (!Master_matrix::Option_list::is_z2) { - column_[i]->set_element(entry->get_element()); - } + column_[i]->set_element(entry->get_element()); ++i; } insertsSinceLastPrune_ = other.insertsSinceLastPrune_; @@ -1028,142 +902,172 @@ inline typename Heap_column::Entry* Heap_column::_ template template -inline bool Heap_column::_add(const Entry_range& column) +inline void Heap_column::_add(const Entry_range& column, [[maybe_unused]] Field_element& pivotVal) { - if (column.begin() == column.end()) return false; + if (column.begin() == column.end()) return; + if (column_.empty()) { // chain should never enter here. column_.resize(column.size()); Index i = 0; for (const Entry& entry : column) { column_[i] = entryPool_->construct(entry.get_row_index()); - if constexpr (!Master_matrix::Option_list::is_z2) { - column_[i]->set_element(entry.get_element()); - } + column_[i]->set_element(entry.get_element()); ++i; } insertsSinceLastPrune_ = column_.size(); - return true; + return; } - Field_element pivotVal(1); - - if constexpr (Master_matrix::isNonBasic && !Master_matrix::Option_list::is_of_boundary_type) - pivotVal = get_pivot_value(); - for (const Entry& entry : column) { ++insertsSinceLastPrune_; - if constexpr (Master_matrix::Option_list::is_z2) { - if constexpr (Master_matrix::isNonBasic && !Master_matrix::Option_list::is_of_boundary_type) { - if (entry.get_row_index() == Chain_opt::_get_pivot()) pivotVal = !pivotVal; - } - column_.push_back(entryPool_->construct(entry.get_row_index())); - } else { - if constexpr (Master_matrix::isNonBasic && !Master_matrix::Option_list::is_of_boundary_type) { - if (entry.get_row_index() == Chain_opt::_get_pivot()) operators_->add_inplace(pivotVal, entry.get_element()); + + if constexpr (Master_matrix::isNonBasic && !Master_matrix::Option_list::is_of_boundary_type) { + if (entry.get_row_index() == Chain_opt::_get_pivot()) { + _add_coefficient(pivotVal, entry.get_element()); } - column_.push_back(entryPool_->construct(entry.get_row_index())); - column_.back()->set_element(entry.get_element()); } + + column_.push_back(entryPool_->construct(entry.get_row_index())); + column_.back()->set_element(entry.get_element()); + std::push_heap(column_.begin(), column_.end(), entryPointerComp_); } if (2 * insertsSinceLastPrune_ > column_.size()) _prune(); - - if constexpr (Master_matrix::Option_list::is_z2) - return !pivotVal; - else - return pivotVal == Field_operators::get_additive_identity(); } template -template -inline bool Heap_column::_multiply_target_and_add(const Field_element& val, const Entry_range& column) +template +inline std::conditional_t::Field_element, void> +Heap_column::_multiply(const Field_element& val) { - if (val == 0U) { + Field_element pivotVal(0); + + if (val == Field_operators::get_additive_identity()) { if constexpr (Master_matrix::isNonBasic && !Master_matrix::Option_list::is_of_boundary_type) { - throw std::invalid_argument("A chain column should not be multiplied by 0."); // this would not only mess up the base, but also the pivots stored. + throw std::invalid_argument("A chain column should not be multiplied by 0."); } else { clear(); + if constexpr (computePivotVal) + return pivotVal; + else + return; } } - if (column_.empty()) { // chain should never enter here. - column_.resize(column.size()); - Index i = 0; - for (const Entry& entry : column) { - column_[i] = entryPool_->construct(entry.get_row_index()); - column_[i++]->set_element(entry.get_element()); - } - insertsSinceLastPrune_ = column_.size(); - return true; - } - Field_element pivotVal(0); + if (val == Field_operators::get_multiplicative_identity()) { + if constexpr (computePivotVal) + return get_pivot_value(); + else + return; + } - for (Entry* entry : column_) { - operators_->multiply_inplace(entry->get_element(), val); - if constexpr (Master_matrix::isNonBasic && !Master_matrix::Option_list::is_of_boundary_type) { - if (entry->get_row_index() == Chain_opt::_get_pivot()) operators_->add_inplace(pivotVal, entry->get_element()); + // multiply_inplace needs a non-const reference to element, so even if Z2 never reaches here, it won't compile + // without the constexpr, as we are not storing a dummy value just for this purpose. + if constexpr (!Master_matrix::Option_list::is_z2) { + for (Entry* entry : column_) { + operators_->multiply_inplace(entry->get_element(), val); + if constexpr (computePivotVal) { + // computePivotVal is only true for chain columns, so Chain_opt is not a dummy for sure + if (entry->get_row_index() == Chain_opt::_get_pivot()) { + operators_->add_inplace(pivotVal, entry->get_element()); + } + } } } - for (const Entry& entry : column) { - ++insertsSinceLastPrune_; - if constexpr (Master_matrix::isNonBasic && !Master_matrix::Option_list::is_of_boundary_type) { - if (entry.get_row_index() == Chain_opt::_get_pivot()) operators_->add_inplace(pivotVal, entry.get_element()); - } - column_.push_back(entryPool_->construct(entry.get_row_index())); - column_.back()->set_element(entry.get_element()); - std::push_heap(column_.begin(), column_.end(), entryPointerComp_); + if constexpr (computePivotVal) + return pivotVal; + else + return; +} + +template +template +inline bool Heap_column::_multiply_target_and_add(const Field_element& val, const Entry_range& column) +{ + Field_element pivotVal(0); + + if constexpr (Master_matrix::isNonBasic && !Master_matrix::Option_list::is_of_boundary_type) { + pivotVal = _multiply(val); + } else { + _multiply(val); } - if (2 * insertsSinceLastPrune_ > column_.size()) _prune(); + _add(column, pivotVal); - if constexpr (Master_matrix::Option_list::is_z2) - return !pivotVal; - else - return pivotVal == Field_operators::get_additive_identity(); + return pivotVal == Field_operators::get_additive_identity(); } +// TODO: could be factorized with _add template template inline bool Heap_column::_multiply_source_and_add(const Entry_range& column, const Field_element& val) { - if (val == 0U || column.begin() == column.end()) { + if (val == Field_operators::get_additive_identity() || column.begin() == column.end()) { return false; } + if (column_.empty()) { // chain should never enter here. column_.resize(column.size()); Index i = 0; for (const Entry& entry : column) { column_[i] = entryPool_->construct(entry.get_row_index()); - column_[i++]->set_element(entry.get_element()); + column_[i]->set_element(_multiply_coefficient(entry.get_element(), val)); + ++i; } insertsSinceLastPrune_ = column_.size(); return true; } - Field_element pivotVal(1); + Field_element pivotVal(0); if constexpr (Master_matrix::isNonBasic && !Master_matrix::Option_list::is_of_boundary_type) pivotVal = get_pivot_value(); for (const Entry& entry : column) { ++insertsSinceLastPrune_; + column_.push_back(entryPool_->construct(entry.get_row_index())); - column_.back()->set_element(entry.get_element()); - operators_->multiply_inplace(column_.back()->get_element(), val); + column_.back()->set_element(_multiply_coefficient(entry.get_element(), val)); + if constexpr (Master_matrix::isNonBasic && !Master_matrix::Option_list::is_of_boundary_type) { if (entry.get_row_index() == Chain_opt::_get_pivot()) { - operators_->add_inplace(pivotVal, column_.back()->get_element()); + _add_coefficient(pivotVal, column_.back()->get_element()); } } + std::push_heap(column_.begin(), column_.end(), entryPointerComp_); } if (2 * insertsSinceLastPrune_ > column_.size()) _prune(); - return pivotVal == 0U; + return pivotVal == Field_operators::get_additive_identity(); +} + +template +inline void Heap_column::_add_coefficient(Field_element& e, + [[maybe_unused]] const Field_element& a) const +{ + if constexpr (Master_matrix::Option_list::is_z2) { + // a has to be 1 + e = !e; + } else { + operators_->add_inplace(e, a); + } +} + +template +inline typename Heap_column::Field_element Heap_column::_multiply_coefficient( + const Field_element& e, + [[maybe_unused]] const Field_element& a) const +{ + if constexpr (Master_matrix::Option_list::is_z2) { + return e; // a has to be 1 + } else { + return operators_->multiply(e, a); + } } } // namespace persistence_matrix diff --git a/multipers/gudhi/gudhi/Persistence_matrix/columns/intrusive_list_column.h b/multipers/gudhi/gudhi/Persistence_matrix/columns/intrusive_list_column.h index f7e164fd..7ec34360 100644 --- a/multipers/gudhi/gudhi/Persistence_matrix/columns/intrusive_list_column.h +++ b/multipers/gudhi/gudhi/Persistence_matrix/columns/intrusive_list_column.h @@ -18,6 +18,7 @@ #ifndef PM_INTRUSIVE_LIST_COLUMN_H #define PM_INTRUSIVE_LIST_COLUMN_H +#include #include #include #include @@ -69,6 +70,7 @@ class Intrusive_list_column : public Master_matrix::Row_access_option, using const_iterator = typename Column_support::const_iterator; using reverse_iterator = typename Column_support::reverse_iterator; using const_reverse_iterator = typename Column_support::const_reverse_iterator; + using Content_range = const Column_support&; Intrusive_list_column(Column_settings* colSettings = nullptr); template @@ -78,20 +80,41 @@ class Intrusive_list_column : public Master_matrix::Row_access_option, const Container& nonZeroRowIndices, Row_container* rowContainer, Column_settings* colSettings); - template + template > > Intrusive_list_column(const Container& nonZeroRowIndices, Dimension dimension, Column_settings* colSettings); - template + template > > Intrusive_list_column(Index columnIndex, const Container& nonZeroRowIndices, Dimension dimension, Row_container* rowContainer, Column_settings* colSettings); - Intrusive_list_column(const Intrusive_list_column& column, Column_settings* colSettings = nullptr); + Intrusive_list_column(ID_index idx, Dimension dimension, Column_settings* colSettings); + Intrusive_list_column(ID_index idx, + Field_element e, + Dimension dimension, + Column_settings* colSettings); + template + Intrusive_list_column(Index columnIndex, + ID_index idx, + Dimension dimension, + Row_container* rowContainer, + Column_settings* colSettings); + template + Intrusive_list_column(Index columnIndex, + ID_index idx, + Field_element e, + Dimension dimension, + Row_container* rowContainer, + Column_settings* colSettings); template Intrusive_list_column(const Intrusive_list_column& column, Index columnIndex, Row_container* rowContainer, Column_settings* colSettings = nullptr); + Intrusive_list_column(const Intrusive_list_column& column, Column_settings* colSettings = nullptr); Intrusive_list_column(Intrusive_list_column&& column) noexcept; ~Intrusive_list_column(); @@ -118,6 +141,8 @@ class Intrusive_list_column : public Master_matrix::Row_access_option, reverse_iterator rend() noexcept; const_reverse_iterator rend() const noexcept; + Content_range get_non_zero_content_range() const; + template Intrusive_list_column& operator+=(const Entry_range& column); Intrusive_list_column& operator+=(Intrusive_list_column& column); @@ -139,38 +164,30 @@ class Intrusive_list_column : public Master_matrix::Row_access_option, { if (&c1 == &c2) return true; - if constexpr (Master_matrix::Option_list::is_z2) { - return c1.column_ == c2.column_; - } else { - auto it1 = c1.column_.begin(); - auto it2 = c2.column_.begin(); - if (c1.column_.size() != c2.column_.size()) return false; - while (it1 != c1.column_.end() && it2 != c2.column_.end()) { - if (it1->get_row_index() != it2->get_row_index() || it1->get_element() != it2->get_element()) return false; - ++it1; - ++it2; - } - return true; - } + return std::equal(c1.column_.begin(), + c1.column_.end(), + c2.column_.begin(), + c2.column_.end(), + [](const Entry& e1, const Entry& e2) { + return e1.get_row_index() == e2.get_row_index() && e1.get_element() == e2.get_element(); + }); } friend bool operator<(const Intrusive_list_column& c1, const Intrusive_list_column& c2) { if (&c1 == &c2) return false; - if constexpr (Master_matrix::Option_list::is_z2) { - return c1.column_ < c2.column_; - } else { - auto it1 = c1.column_.begin(); - auto it2 = c2.column_.begin(); - while (it1 != c1.column_.end() && it2 != c2.column_.end()) { - if (it1->get_row_index() != it2->get_row_index()) return it1->get_row_index() < it2->get_row_index(); - if (it1->get_element() != it2->get_element()) return it1->get_element() < it2->get_element(); - ++it1; - ++it2; - } - return it2 != c2.column_.end(); - } + return std::lexicographical_compare(c1.column_.begin(), + c1.column_.end(), + c2.column_.begin(), + c2.column_.end(), + [](const Entry& e1, const Entry& e2) { + if (e1.get_row_index() != e2.get_row_index()) + return e1.get_row_index() < e2.get_row_index(); + if (e1.get_element() != e2.get_element()) + return e1.get_element() < e2.get_element(); + return false; + }); } // Disabled with row access. @@ -218,7 +235,7 @@ class Intrusive_list_column : public Master_matrix::Row_access_option, Intrusive_list_column* col_; }; - Field_operators* operators_; + Field_operators const* operators_; Entry_constructor* entryPool_; Column_support column_; @@ -251,8 +268,7 @@ class Intrusive_list_column : public Master_matrix::Row_access_option, Column& targetColumn); void _delete_entry(iterator& it); - Entry* _insert_entry(const Field_element& value, ID_index rowIndex, const iterator& position); - void _insert_entry(ID_index rowIndex, const iterator& position); + Entry* _insert_entry(const iterator& position, ID_index rowIndex, const Field_element& value); template bool _add(const Entry_range& column); template @@ -266,148 +282,153 @@ inline Intrusive_list_column::Intrusive_list_column(Column_settin : RA_opt(), Dim_opt(), Chain_opt(), - operators_(nullptr), + operators_(Master_matrix::get_operator_ptr(colSettings)), entryPool_(colSettings == nullptr ? nullptr : &(colSettings->entryConstructor)), column_() +{} + +template +template +inline Intrusive_list_column::Intrusive_list_column(const Container& nonZeroRowIndices, + Column_settings* colSettings) + : Intrusive_list_column(nonZeroRowIndices, + nonZeroRowIndices.size() == 0 ? 0 : nonZeroRowIndices.size() - 1, + colSettings) { - if (colSettings == nullptr) return; // to allow default constructor which gives a dummy column - if constexpr (!Master_matrix::Option_list::is_z2) { - operators_ = &(colSettings->operators); - } + static_assert(!Master_matrix::isNonBasic || Master_matrix::Option_list::is_of_boundary_type, + "Constructor not available for chain columns, please specify the dimension of the chain."); } template -template +template +inline Intrusive_list_column::Intrusive_list_column(Index columnIndex, + const Container& nonZeroRowIndices, + Row_container* rowContainer, + Column_settings* colSettings) + : Intrusive_list_column(columnIndex, + nonZeroRowIndices, + nonZeroRowIndices.size() == 0 ? 0 : nonZeroRowIndices.size() - 1, + rowContainer, + colSettings) +{ + static_assert(!Master_matrix::isNonBasic || Master_matrix::Option_list::is_of_boundary_type, + "Constructor not available for chain columns, please specify the dimension of the chain."); +} + +template +template inline Intrusive_list_column::Intrusive_list_column(const Container& nonZeroRowIndices, + Dimension dimension, Column_settings* colSettings) : RA_opt(), - Dim_opt(nonZeroRowIndices.size() == 0 ? 0 : nonZeroRowIndices.size() - 1), - Chain_opt(), - operators_(nullptr), + Dim_opt(dimension), + Chain_opt(nonZeroRowIndices.begin() == nonZeroRowIndices.end() + ? Master_matrix::template get_null_value() + : Master_matrix::get_row_index(*std::prev(nonZeroRowIndices.end()))), + operators_(Master_matrix::get_operator_ptr(colSettings)), entryPool_(&(colSettings->entryConstructor)), column_() { - static_assert(!Master_matrix::isNonBasic || Master_matrix::Option_list::is_of_boundary_type, - "Constructor not available for chain columns, please specify the dimension of the chain."); - - if constexpr (Master_matrix::Option_list::is_z2) { - for (ID_index id : nonZeroRowIndices) { - _insert_entry(id, column_.end()); - } - } else { - operators_ = &(colSettings->operators); - for (const auto& p : nonZeroRowIndices) { - _insert_entry(operators_->get_value(p.second), p.first, column_.end()); - } + for (const auto& id : nonZeroRowIndices) { + _insert_entry(column_.end(), + Master_matrix::get_row_index(id), + Master_matrix::get_coefficient_value(Master_matrix::get_element(id), operators_)); } } template -template +template inline Intrusive_list_column::Intrusive_list_column(Index columnIndex, const Container& nonZeroRowIndices, + Dimension dimension, Row_container* rowContainer, Column_settings* colSettings) : RA_opt(columnIndex, rowContainer), - Dim_opt(nonZeroRowIndices.size() == 0 ? 0 : nonZeroRowIndices.size() - 1), - Chain_opt([&] { - if constexpr (Master_matrix::Option_list::is_z2) { - return nonZeroRowIndices.begin() == nonZeroRowIndices.end() - ? Master_matrix::template get_null_value() - : *std::prev(nonZeroRowIndices.end()); - } else { - return nonZeroRowIndices.begin() == nonZeroRowIndices.end() - ? Master_matrix::template get_null_value() - : std::prev(nonZeroRowIndices.end())->first; - } - }()), - operators_(nullptr), + Dim_opt(dimension), + Chain_opt(nonZeroRowIndices.begin() == nonZeroRowIndices.end() + ? Master_matrix::template get_null_value() + : Master_matrix::get_row_index(*std::prev(nonZeroRowIndices.end()))), + operators_(Master_matrix::get_operator_ptr(colSettings)), entryPool_(&(colSettings->entryConstructor)), column_() { - static_assert(!Master_matrix::isNonBasic || Master_matrix::Option_list::is_of_boundary_type, - "Constructor not available for chain columns, please specify the dimension of the chain."); - - if constexpr (Master_matrix::Option_list::is_z2) { - for (ID_index id : nonZeroRowIndices) { - _insert_entry(id, column_.end()); - } - } else { - operators_ = &(colSettings->operators); - for (const auto& p : nonZeroRowIndices) { - _insert_entry(operators_->get_value(p.second), p.first, column_.end()); - } + for (const auto& id : nonZeroRowIndices) { + _insert_entry(column_.end(), + Master_matrix::get_row_index(id), + Master_matrix::get_coefficient_value(Master_matrix::get_element(id), operators_)); } } template -template -inline Intrusive_list_column::Intrusive_list_column(const Container& nonZeroRowIndices, +inline Intrusive_list_column::Intrusive_list_column(ID_index idx, Dimension dimension, Column_settings* colSettings) : RA_opt(), Dim_opt(dimension), - Chain_opt([&] { - if constexpr (Master_matrix::Option_list::is_z2) { - return nonZeroRowIndices.begin() == nonZeroRowIndices.end() - ? Master_matrix::template get_null_value() - : *std::prev(nonZeroRowIndices.end()); - } else { - return nonZeroRowIndices.begin() == nonZeroRowIndices.end() - ? Master_matrix::template get_null_value() - : std::prev(nonZeroRowIndices.end())->first; - } - }()), + Chain_opt(idx), operators_(nullptr), entryPool_(&(colSettings->entryConstructor)), column_() { - if constexpr (Master_matrix::Option_list::is_z2) { - for (ID_index id : nonZeroRowIndices) { - _insert_entry(id, column_.end()); - } - } else { - operators_ = &(colSettings->operators); - for (const auto& p : nonZeroRowIndices) { - _insert_entry(operators_->get_value(p.second), p.first, column_.end()); - } - } + static_assert(Master_matrix::Option_list::is_z2, + "Constructor not available for Zp != Z2. Please specify the coefficient."); + _insert_entry(column_.end(), idx, 1); } template -template +inline Intrusive_list_column::Intrusive_list_column(ID_index idx, + Field_element e, + Dimension dimension, + Column_settings* colSettings) + : RA_opt(), + Dim_opt(dimension), + Chain_opt(idx), + operators_(&(colSettings->operators)), + entryPool_(&(colSettings->entryConstructor)), + column_() +{ + static_assert(!Master_matrix::Option_list::is_z2, + "Constructor not available for Zp == Z2. Please do not specify any coefficient."); + _insert_entry(column_.end(), idx, operators_->get_value(e)); +} + +template +template inline Intrusive_list_column::Intrusive_list_column(Index columnIndex, - const Container& nonZeroRowIndices, + ID_index idx, Dimension dimension, Row_container* rowContainer, Column_settings* colSettings) : RA_opt(columnIndex, rowContainer), Dim_opt(dimension), - Chain_opt([&] { - if constexpr (Master_matrix::Option_list::is_z2) { - return nonZeroRowIndices.begin() == nonZeroRowIndices.end() - ? Master_matrix::template get_null_value() - : *std::prev(nonZeroRowIndices.end()); - } else { - return nonZeroRowIndices.begin() == nonZeroRowIndices.end() - ? Master_matrix::template get_null_value() - : std::prev(nonZeroRowIndices.end())->first; - } - }()), + Chain_opt(idx), operators_(nullptr), entryPool_(&(colSettings->entryConstructor)), column_() { - if constexpr (Master_matrix::Option_list::is_z2) { - for (ID_index id : nonZeroRowIndices) { - _insert_entry(id, column_.end()); - } - } else { - operators_ = &(colSettings->operators); - for (const auto& p : nonZeroRowIndices) { - _insert_entry(operators_->get_value(p.second), p.first, column_.end()); - } - } + static_assert(Master_matrix::Option_list::is_z2, + "Constructor not available for Zp != Z2. Please specify the coefficient."); + _insert_entry(column_.end(), idx, 1); +} + +template +template +inline Intrusive_list_column::Intrusive_list_column(Index columnIndex, + ID_index idx, + Field_element e, + Dimension dimension, + Row_container* rowContainer, + Column_settings* colSettings) + : RA_opt(columnIndex, rowContainer), + Dim_opt(dimension), + Chain_opt(idx), + operators_(&(colSettings->operators)), + entryPool_(&(colSettings->entryConstructor)), + column_() +{ + static_assert(!Master_matrix::Option_list::is_z2, + "Constructor not available for Zp == Z2. Please do not specify any coefficient."); + _insert_entry(column_.end(), idx, operators_->get_value(e)); } template @@ -416,16 +437,13 @@ inline Intrusive_list_column::Intrusive_list_column(const Intrusi : RA_opt(), Dim_opt(static_cast(column)), Chain_opt(static_cast(column)), - operators_(colSettings == nullptr ? column.operators_ : nullptr), + operators_(colSettings == nullptr ? column.operators_ : Master_matrix::get_operator_ptr(colSettings)), entryPool_(colSettings == nullptr ? column.entryPool_ : &(colSettings->entryConstructor)), column_() { static_assert(!Master_matrix::Option_list::has_row_access, "Simple copy constructor not available when row access option enabled. Please specify the new column " "index and the row container."); - if constexpr (!Master_matrix::Option_list::is_z2) { - if (colSettings != nullptr) operators_ = &(colSettings->operators); - } column_.clone_from(column.column_, New_cloner(entryPool_), Delete_disposer(this)); } @@ -439,20 +457,12 @@ inline Intrusive_list_column::Intrusive_list_column(const Intrusi : RA_opt(columnIndex, rowContainer), Dim_opt(static_cast(column)), Chain_opt(static_cast(column)), - operators_(colSettings == nullptr ? column.operators_ : nullptr), + operators_(colSettings == nullptr ? column.operators_ : Master_matrix::get_operator_ptr(colSettings)), entryPool_(colSettings == nullptr ? column.entryPool_ : &(colSettings->entryConstructor)), column_() { - if constexpr (!Master_matrix::Option_list::is_z2) { - if (colSettings != nullptr) operators_ = &(colSettings->operators); - } - for (const Entry& entry : column.column_) { - if constexpr (Master_matrix::Option_list::is_z2) { - _insert_entry(entry.get_row_index(), column_.end()); - } else { - _insert_entry(entry.get_element(), entry.get_row_index(), column_.end()); - } + _insert_entry(column_.end(), entry.get_row_index(), entry.get_element()); } } @@ -485,11 +495,7 @@ Intrusive_list_column::get_content(int columnLength) const std::vector container(columnLength); for (auto it = column_.begin(); it != column_.end() && it->get_row_index() < static_cast(columnLength); ++it) { - if constexpr (Master_matrix::Option_list::is_z2) { - container[it->get_row_index()] = 1; - } else { - container[it->get_row_index()] = it->get_element(); - } + container[it->get_row_index()] = Master_matrix::get_element(*it); } return container; } @@ -659,6 +665,13 @@ Intrusive_list_column::rend() const noexcept return column_.rend(); } +template +inline typename Intrusive_list_column::Content_range +Intrusive_list_column::get_non_zero_content_range() const +{ + return column_; +} + template template inline Intrusive_list_column& Intrusive_list_column::operator+=(const Entry_range& column) @@ -694,28 +707,22 @@ inline Intrusive_list_column& Intrusive_list_column inline Intrusive_list_column& Intrusive_list_column::operator*=(const Field_element& val) { - if constexpr (Master_matrix::Option_list::is_z2) { - if (val % 2 == 0) { - if constexpr (Master_matrix::isNonBasic && !Master_matrix::Option_list::is_of_boundary_type) { - throw std::invalid_argument("A chain column should not be multiplied by 0."); - } else { - clear(); - } - } - } else { - Field_element realVal = operators_->get_value(val); + Field_element realVal = Master_matrix::get_coefficient_value(val, operators_); - if (realVal == Field_operators::get_additive_identity()) { - if constexpr (Master_matrix::isNonBasic && !Master_matrix::Option_list::is_of_boundary_type) { - throw std::invalid_argument("A chain column should not be multiplied by 0."); - } else { - clear(); - } - return *this; + if (realVal == Field_operators::get_additive_identity()) { + if constexpr (Master_matrix::isNonBasic && !Master_matrix::Option_list::is_of_boundary_type) { + throw std::invalid_argument("A chain column should not be multiplied by 0."); + } else { + clear(); } + return *this; + } - if (realVal == Field_operators::get_multiplicative_identity()) return *this; + if (realVal == Field_operators::get_multiplicative_identity()) return *this; + // multiply_inplace needs a non-const reference to element, so even if Z2 never reaches here, it won't compile + // without the constexpr, as we are not storing a dummy value just for this purpose. + if constexpr (!Master_matrix::Option_list::is_z2) { for (Entry& entry : column_) { operators_->multiply_inplace(entry.get_element(), realVal); if constexpr (Master_matrix::Option_list::has_row_access) RA_opt::update_entry(entry); @@ -737,16 +744,7 @@ inline Intrusive_list_column& Intrusive_list_column& Intrusive_list_column& Intrusive_list_column& Intrusive_list_column::push_back(const Entry& entry) GUDHI_CHECK(entry.get_row_index() > get_pivot(), "The new row index has to be higher than the current pivot."); - if constexpr (Master_matrix::Option_list::is_z2) { - _insert_entry(entry.get_row_index(), column_.end()); - } else { - _insert_entry(entry.get_element(), entry.get_row_index(), column_.end()); - } + _insert_entry(column_.end(), entry.get_row_index(), entry.get_element()); } template @@ -897,6 +850,8 @@ inline Intrusive_list_column& Intrusive_list_column @@ -907,35 +862,20 @@ inline void Intrusive_list_column::_delete_entry(iterator& it) template inline typename Intrusive_list_column::Entry* Intrusive_list_column::_insert_entry( - const Field_element& value, + const iterator& position, ID_index rowIndex, - const iterator& position) -{ - if constexpr (Master_matrix::Option_list::has_row_access) { - Entry* newEntry = entryPool_->construct(RA_opt::get_column_index(), rowIndex); - newEntry->set_element(value); - column_.insert(position, *newEntry); - RA_opt::insert_entry(rowIndex, newEntry); - return newEntry; - } else { - Entry* newEntry = entryPool_->construct(rowIndex); - newEntry->set_element(value); - column_.insert(position, *newEntry); - return newEntry; - } -} - -template -inline void Intrusive_list_column::_insert_entry(ID_index rowIndex, const iterator& position) + const Field_element& value) { + Entry* newEntry; if constexpr (Master_matrix::Option_list::has_row_access) { - Entry* newEntry = entryPool_->construct(RA_opt::get_column_index(), rowIndex); - column_.insert(position, *newEntry); - RA_opt::insert_entry(rowIndex, newEntry); + newEntry = entryPool_->construct(RA_opt::get_column_index(), rowIndex); } else { - Entry* newEntry = entryPool_->construct(rowIndex); - column_.insert(position, *newEntry); + newEntry = entryPool_->construct(rowIndex); } + newEntry->set_element(value); + column_.insert(position, *newEntry); + if constexpr (Master_matrix::Option_list::has_row_access) RA_opt::insert_entry(rowIndex, newEntry); + return newEntry; } template diff --git a/multipers/gudhi/gudhi/Persistence_matrix/columns/intrusive_set_column.h b/multipers/gudhi/gudhi/Persistence_matrix/columns/intrusive_set_column.h index 8da5d672..0ee5ded2 100644 --- a/multipers/gudhi/gudhi/Persistence_matrix/columns/intrusive_set_column.h +++ b/multipers/gudhi/gudhi/Persistence_matrix/columns/intrusive_set_column.h @@ -70,6 +70,7 @@ class Intrusive_set_column : public Master_matrix::Row_access_option, using const_iterator = typename Column_support::const_iterator; using reverse_iterator = typename Column_support::reverse_iterator; using const_reverse_iterator = typename Column_support::const_reverse_iterator; + using Content_range = const Column_support&; Intrusive_set_column(Column_settings* colSettings = nullptr); template @@ -79,14 +80,35 @@ class Intrusive_set_column : public Master_matrix::Row_access_option, const Container& nonZeroRowIndices, Row_container* rowContainer, Column_settings* colSettings); - template + template > > Intrusive_set_column(const Container& nonZeroRowIndices, Dimension dimension, Column_settings* colSettings); - template + template > > Intrusive_set_column(Index columnIndex, const Container& nonZeroRowIndices, Dimension dimension, Row_container* rowContainer, Column_settings* colSettings); + Intrusive_set_column(ID_index idx, Dimension dimension, Column_settings* colSettings); + Intrusive_set_column(ID_index idx, + Field_element e, + Dimension dimension, + Column_settings* colSettings); + template + Intrusive_set_column(Index columnIndex, + ID_index idx, + Dimension dimension, + Row_container* rowContainer, + Column_settings* colSettings); + template + Intrusive_set_column(Index columnIndex, + ID_index idx, + Field_element e, + Dimension dimension, + Row_container* rowContainer, + Column_settings* colSettings); Intrusive_set_column(const Intrusive_set_column& column, Column_settings* colSettings = nullptr); template Intrusive_set_column(const Intrusive_set_column& column, @@ -119,11 +141,13 @@ class Intrusive_set_column : public Master_matrix::Row_access_option, reverse_iterator rend() noexcept; const_reverse_iterator rend() const noexcept; + Content_range get_non_zero_content_range() const; + template Intrusive_set_column& operator+=(const Entry_range& column); Intrusive_set_column& operator+=(Intrusive_set_column& column); - Intrusive_set_column& operator*=(unsigned int v); + Intrusive_set_column& operator*=(const Field_element& v); // this = v * this + column template @@ -140,38 +164,30 @@ class Intrusive_set_column : public Master_matrix::Row_access_option, { if (&c1 == &c2) return true; - if constexpr (Master_matrix::Option_list::is_z2) { - return c1.column_ == c2.column_; - } else { - auto it1 = c1.column_.begin(); - auto it2 = c2.column_.begin(); - if (c1.column_.size() != c2.column_.size()) return false; - while (it1 != c1.column_.end() && it2 != c2.column_.end()) { - if (it1->get_row_index() != it2->get_row_index() || it1->get_element() != it2->get_element()) return false; - ++it1; - ++it2; - } - return true; - } + return std::equal(c1.column_.begin(), + c1.column_.end(), + c2.column_.begin(), + c2.column_.end(), + [](const Entry& e1, const Entry& e2) { + return e1.get_row_index() == e2.get_row_index() && e1.get_element() == e2.get_element(); + }); } friend bool operator<(const Intrusive_set_column& c1, const Intrusive_set_column& c2) { if (&c1 == &c2) return false; - if constexpr (Master_matrix::Option_list::is_z2) { - return c1.column_ < c2.column_; - } else { - auto it1 = c1.column_.begin(); - auto it2 = c2.column_.begin(); - while (it1 != c1.column_.end() && it2 != c2.column_.end()) { - if (it1->get_row_index() != it2->get_row_index()) return it1->get_row_index() < it2->get_row_index(); - if (it1->get_element() != it2->get_element()) return it1->get_element() < it2->get_element(); - ++it1; - ++it2; - } - return it2 != c2.column_.end(); - } + return std::lexicographical_compare(c1.column_.begin(), + c1.column_.end(), + c2.column_.begin(), + c2.column_.end(), + [](const Entry& e1, const Entry& e2) { + if (e1.get_row_index() != e2.get_row_index()) + return e1.get_row_index() < e2.get_row_index(); + if (e1.get_element() != e2.get_element()) + return e1.get_element() < e2.get_element(); + return false; + }); } // Disabled with row access. @@ -220,7 +236,7 @@ class Intrusive_set_column : public Master_matrix::Row_access_option, }; Column_support column_; - Field_operators* operators_; + Field_operators const* operators_; Entry_constructor* entryPool_; template @@ -252,8 +268,7 @@ class Intrusive_set_column : public Master_matrix::Row_access_option, Column& targetColumn); void _delete_entry(iterator& it); - Entry* _insert_entry(const Field_element& value, ID_index rowIndex, const iterator& position); - void _insert_entry(ID_index rowIndex, const iterator& position); + Entry* _insert_entry(const iterator& position, ID_index rowIndex, const Field_element& value); template bool _add(const Entry_range& column); template @@ -267,39 +282,20 @@ inline Intrusive_set_column::Intrusive_set_column(Column_settings : RA_opt(), Dim_opt(), Chain_opt(), - operators_(nullptr), + operators_(Master_matrix::get_operator_ptr(colSettings)), entryPool_(colSettings == nullptr ? nullptr : &(colSettings->entryConstructor)) -{ - if (operators_ == nullptr && entryPool_ == nullptr) - return; // to allow default constructor which gives a dummy column - if constexpr (!Master_matrix::Option_list::is_z2) { - operators_ = &(colSettings->operators); - } -} +{} template template inline Intrusive_set_column::Intrusive_set_column(const Container& nonZeroRowIndices, Column_settings* colSettings) - : RA_opt(), - Dim_opt(nonZeroRowIndices.size() == 0 ? 0 : nonZeroRowIndices.size() - 1), - Chain_opt(), - operators_(nullptr), - entryPool_(&(colSettings->entryConstructor)) + : Intrusive_set_column(nonZeroRowIndices, + nonZeroRowIndices.size() == 0 ? 0 : nonZeroRowIndices.size() - 1, + colSettings) { static_assert(!Master_matrix::isNonBasic || Master_matrix::Option_list::is_of_boundary_type, "Constructor not available for chain columns, please specify the dimension of the chain."); - - if constexpr (Master_matrix::Option_list::is_z2) { - for (ID_index id : nonZeroRowIndices) { - _insert_entry(id, column_.end()); - } - } else { - operators_ = &(colSettings->operators); - for (const auto& p : nonZeroRowIndices) { - _insert_entry(operators_->get_value(p.second), p.first, column_.end()); - } - } } template @@ -308,72 +304,38 @@ inline Intrusive_set_column::Intrusive_set_column(Index columnInd const Container& nonZeroRowIndices, Row_container* rowContainer, Column_settings* colSettings) - : RA_opt(columnIndex, rowContainer), - Dim_opt(nonZeroRowIndices.size() == 0 ? 0 : nonZeroRowIndices.size() - 1), - Chain_opt([&] { - if constexpr (Master_matrix::Option_list::is_z2) { - return nonZeroRowIndices.begin() == nonZeroRowIndices.end() - ? Master_matrix::template get_null_value() - : *std::prev(nonZeroRowIndices.end()); - } else { - return nonZeroRowIndices.begin() == nonZeroRowIndices.end() - ? Master_matrix::template get_null_value() - : std::prev(nonZeroRowIndices.end())->first; - } - }()), - operators_(nullptr), - entryPool_(&(colSettings->entryConstructor)) + : Intrusive_set_column(columnIndex, + nonZeroRowIndices, + nonZeroRowIndices.size() == 0 ? 0 : nonZeroRowIndices.size() - 1, + rowContainer, + colSettings) { static_assert(!Master_matrix::isNonBasic || Master_matrix::Option_list::is_of_boundary_type, "Constructor not available for chain columns, please specify the dimension of the chain."); - - if constexpr (Master_matrix::Option_list::is_z2) { - for (ID_index id : nonZeroRowIndices) { - _insert_entry(id, column_.end()); - } - } else { - operators_ = &(colSettings->operators); - for (const auto& p : nonZeroRowIndices) { - _insert_entry(operators_->get_value(p.second), p.first, column_.end()); - } - } } template -template +template inline Intrusive_set_column::Intrusive_set_column(const Container& nonZeroRowIndices, Dimension dimension, Column_settings* colSettings) : RA_opt(), Dim_opt(dimension), - Chain_opt([&] { - if constexpr (Master_matrix::Option_list::is_z2) { - return nonZeroRowIndices.begin() == nonZeroRowIndices.end() - ? Master_matrix::template get_null_value() - : *std::prev(nonZeroRowIndices.end()); - } else { - return nonZeroRowIndices.begin() == nonZeroRowIndices.end() - ? Master_matrix::template get_null_value() - : std::prev(nonZeroRowIndices.end())->first; - } - }()), - operators_(nullptr), + Chain_opt(nonZeroRowIndices.begin() == nonZeroRowIndices.end() + ? Master_matrix::template get_null_value() + : Master_matrix::get_row_index(*std::prev(nonZeroRowIndices.end()))), + operators_(Master_matrix::get_operator_ptr(colSettings)), entryPool_(&(colSettings->entryConstructor)) { - if constexpr (Master_matrix::Option_list::is_z2) { - for (ID_index id : nonZeroRowIndices) { - _insert_entry(id, column_.end()); - } - } else { - operators_ = &(colSettings->operators); - for (const auto& p : nonZeroRowIndices) { - _insert_entry(operators_->get_value(p.second), p.first, column_.end()); - } + for (const auto& id : nonZeroRowIndices) { + _insert_entry(column_.end(), + Master_matrix::get_row_index(id), + Master_matrix::get_coefficient_value(Master_matrix::get_element(id), operators_)); } } template -template +template inline Intrusive_set_column::Intrusive_set_column(Index columnIndex, const Container& nonZeroRowIndices, Dimension dimension, @@ -381,49 +343,96 @@ inline Intrusive_set_column::Intrusive_set_column(Index columnInd Column_settings* colSettings) : RA_opt(columnIndex, rowContainer), Dim_opt(dimension), - Chain_opt([&] { - if constexpr (Master_matrix::Option_list::is_z2) { - return nonZeroRowIndices.begin() == nonZeroRowIndices.end() - ? Master_matrix::template get_null_value() - : *std::prev(nonZeroRowIndices.end()); - } else { - return nonZeroRowIndices.begin() == nonZeroRowIndices.end() - ? Master_matrix::template get_null_value() - : std::prev(nonZeroRowIndices.end())->first; - } - }()), - operators_(nullptr), + Chain_opt(nonZeroRowIndices.begin() == nonZeroRowIndices.end() + ? Master_matrix::template get_null_value() + : Master_matrix::get_row_index(*std::prev(nonZeroRowIndices.end()))), + operators_(Master_matrix::get_operator_ptr(colSettings)), entryPool_(&(colSettings->entryConstructor)) { - if constexpr (Master_matrix::Option_list::is_z2) { - for (ID_index id : nonZeroRowIndices) { - _insert_entry(id, column_.end()); - } - } else { - operators_ = &(colSettings->operators); - for (const auto& p : nonZeroRowIndices) { - _insert_entry(operators_->get_value(p.second), p.first, column_.end()); - } + for (const auto& id : nonZeroRowIndices) { + _insert_entry(column_.end(), + Master_matrix::get_row_index(id), + Master_matrix::get_coefficient_value(Master_matrix::get_element(id), operators_)); } } +template +inline Intrusive_set_column::Intrusive_set_column(ID_index idx, + Dimension dimension, + Column_settings* colSettings) + : RA_opt(), Dim_opt(dimension), Chain_opt(idx), operators_(nullptr), entryPool_(&(colSettings->entryConstructor)) +{ + static_assert(Master_matrix::Option_list::is_z2, + "Constructor not available for Zp != Z2. Please specify the coefficient."); + _insert_entry(column_.end(), idx, 1); +} + +template +inline Intrusive_set_column::Intrusive_set_column(ID_index idx, + Field_element e, + Dimension dimension, + Column_settings* colSettings) + : RA_opt(), + Dim_opt(dimension), + Chain_opt(idx), + operators_(&(colSettings->operators)), + entryPool_(&(colSettings->entryConstructor)) +{ + static_assert(!Master_matrix::Option_list::is_z2, + "Constructor not available for Zp == Z2. Please do not specify any coefficient."); + _insert_entry(column_.end(), idx, operators_->get_value(e)); +} + +template +template +inline Intrusive_set_column::Intrusive_set_column(Index columnIndex, + ID_index idx, + Dimension dimension, + Row_container* rowContainer, + Column_settings* colSettings) + : RA_opt(columnIndex, rowContainer), + Dim_opt(dimension), + Chain_opt(idx), + operators_(nullptr), + entryPool_(&(colSettings->entryConstructor)) +{ + static_assert(Master_matrix::Option_list::is_z2, + "Constructor not available for Zp != Z2. Please specify the coefficient."); + _insert_entry(column_.end(), idx, 1); +} + +template +template +inline Intrusive_set_column::Intrusive_set_column(Index columnIndex, + ID_index idx, + Field_element e, + Dimension dimension, + Row_container* rowContainer, + Column_settings* colSettings) + : RA_opt(columnIndex, rowContainer), + Dim_opt(dimension), + Chain_opt(idx), + operators_(&(colSettings->operators)), + entryPool_(&(colSettings->entryConstructor)) +{ + static_assert(!Master_matrix::Option_list::is_z2, + "Constructor not available for Zp == Z2. Please do not specify any coefficient."); + _insert_entry(column_.end(), idx, operators_->get_value(e)); +} + template inline Intrusive_set_column::Intrusive_set_column(const Intrusive_set_column& column, Column_settings* colSettings) : RA_opt(), Dim_opt(static_cast(column)), Chain_opt(static_cast(column)), - operators_(colSettings == nullptr ? column.operators_ : nullptr), + operators_(colSettings == nullptr ? column.operators_ : Master_matrix::get_operator_ptr(colSettings)), entryPool_(colSettings == nullptr ? column.entryPool_ : &(colSettings->entryConstructor)) { static_assert(!Master_matrix::Option_list::has_row_access, "Simple copy constructor not available when row access option enabled. Please specify the new column " "index and the row container."); - if constexpr (!Master_matrix::Option_list::is_z2) { - if (colSettings != nullptr) operators_ = &(colSettings->operators); - } - column_.clone_from(column.column_, New_cloner(entryPool_), Delete_disposer(this)); } @@ -436,19 +445,11 @@ inline Intrusive_set_column::Intrusive_set_column(const Intrusive : RA_opt(columnIndex, rowContainer), Dim_opt(static_cast(column)), Chain_opt(static_cast(column)), - operators_(colSettings == nullptr ? column.operators_ : nullptr), + operators_(colSettings == nullptr ? column.operators_ : Master_matrix::get_operator_ptr(colSettings)), entryPool_(colSettings == nullptr ? column.entryPool_ : &(colSettings->entryConstructor)) { - if constexpr (!Master_matrix::Option_list::is_z2) { - if (colSettings != nullptr) operators_ = &(colSettings->operators); - } - for (const Entry& entry : column.column_) { - if constexpr (Master_matrix::Option_list::is_z2) { - _insert_entry(entry.get_row_index(), column_.end()); - } else { - _insert_entry(entry.get_element(), entry.get_row_index(), column_.end()); - } + _insert_entry(column_.end(), entry.get_row_index(), entry.get_element()); } } @@ -460,8 +461,7 @@ inline Intrusive_set_column::Intrusive_set_column(Intrusive_set_c column_(std::move(column.column_)), operators_(std::exchange(column.operators_, nullptr)), entryPool_(std::exchange(column.entryPool_, nullptr)) -{ -} +{} template inline Intrusive_set_column::~Intrusive_set_column() @@ -481,11 +481,7 @@ Intrusive_set_column::get_content(int columnLength) const std::vector container(columnLength); for (auto it = column_.begin(); it != column_.end() && it->get_row_index() < static_cast(columnLength); ++it) { - if constexpr (Master_matrix::Option_list::is_z2) { - container[it->get_row_index()] = 1; - } else { - container[it->get_row_index()] = it->get_element(); - } + container[it->get_row_index()] = Master_matrix::get_element(*it); } return container; } @@ -523,9 +519,7 @@ inline void Intrusive_set_column::reorder(const Row_index_map& va Entry* newEntry = entryPool_->construct( columnIndex == Master_matrix::template get_null_value() ? RA_opt::get_column_index() : columnIndex, valueMap.at(it->get_row_index())); - if constexpr (!Master_matrix::Option_list::is_z2) { - newEntry->set_element(it->get_element()); - } + newEntry->set_element(it->get_element()); newSet.insert(newSet.end(), *newEntry); _delete_entry(it); // increases it if constexpr (Master_matrix::Option_list::has_intrusive_rows) // intrusive list @@ -541,9 +535,7 @@ inline void Intrusive_set_column::reorder(const Row_index_map& va } else { for (auto it = column_.begin(); it != column_.end();) { Entry* newEntry = entryPool_->construct(valueMap.at(it->get_row_index())); - if constexpr (!Master_matrix::Option_list::is_z2) { - newEntry->set_element(it->get_element()); - } + newEntry->set_element(it->get_element()); newSet.insert(newSet.end(), *newEntry); _delete_entry(it); // increases it } @@ -664,6 +656,13 @@ inline typename Intrusive_set_column::const_reverse_iterator Intr return column_.rend(); } +template +inline typename Intrusive_set_column::Content_range +Intrusive_set_column::get_non_zero_content_range() const +{ + return column_; +} + template template inline Intrusive_set_column& Intrusive_set_column::operator+=(const Entry_range& column) @@ -697,30 +696,24 @@ inline Intrusive_set_column& Intrusive_set_column: } template -inline Intrusive_set_column& Intrusive_set_column::operator*=(unsigned int v) +inline Intrusive_set_column& Intrusive_set_column::operator*=(const Field_element& v) { - if constexpr (Master_matrix::Option_list::is_z2) { - if (v % 2 == 0) { - if constexpr (Master_matrix::isNonBasic && !Master_matrix::Option_list::is_of_boundary_type) { - throw std::invalid_argument("A chain column should not be multiplied by 0."); - } else { - clear(); - } - } - } else { - Field_element val = operators_->get_value(v); + Field_element val = Master_matrix::get_coefficient_value(v, operators_); - if (val == Field_operators::get_additive_identity()) { - if constexpr (Master_matrix::isNonBasic && !Master_matrix::Option_list::is_of_boundary_type) { - throw std::invalid_argument("A chain column should not be multiplied by 0."); - } else { - clear(); - } - return *this; + if (val == Field_operators::get_additive_identity()) { + if constexpr (Master_matrix::isNonBasic && !Master_matrix::Option_list::is_of_boundary_type) { + throw std::invalid_argument("A chain column should not be multiplied by 0."); + } else { + clear(); } + return *this; + } - if (val == Field_operators::get_multiplicative_identity()) return *this; + if (val == Field_operators::get_multiplicative_identity()) return *this; + // multiply_inplace needs a non-const reference to element, so even if Z2 never reaches here, it won't compile + // without the constexpr, as we are not storing a dummy value just for this purpose. + if constexpr (!Master_matrix::Option_list::is_z2) { for (Entry& entry : column_) { operators_->multiply_inplace(entry.get_element(), val); if constexpr (Master_matrix::Option_list::has_row_access) RA_opt::update_entry(entry); @@ -742,16 +735,7 @@ inline Intrusive_set_column& Intrusive_set_column: static_assert((!Master_matrix::isNonBasic || Master_matrix::Option_list::is_of_boundary_type), "For chain columns, the given column cannot be constant."); - if constexpr (Master_matrix::Option_list::is_z2) { - if (val) { - _add(column); - } else { - clear(); - _add(column); - } - } else { - _multiply_target_and_add(val, column); - } + _multiply_target_and_add(Master_matrix::get_coefficient_value(val, operators_), column); return *this; } @@ -763,32 +747,12 @@ inline Intrusive_set_column& Intrusive_set_column: { if constexpr (Master_matrix::isNonBasic && !Master_matrix::Option_list::is_of_boundary_type) { // assumes that the addition never zeros out this column. - if constexpr (Master_matrix::Option_list::is_z2) { - if (val) { - if (_add(column)) { - Chain_opt::_swap_pivots(column); - Dim_opt::_swap_dimension(column); - } - } else { - throw std::invalid_argument("A chain column should not be multiplied by 0."); - } - } else { - if (_multiply_target_and_add(val, column)) { - Chain_opt::_swap_pivots(column); - Dim_opt::_swap_dimension(column); - } + if (_multiply_target_and_add(Master_matrix::get_coefficient_value(val, operators_), column)) { + Chain_opt::_swap_pivots(column); + Dim_opt::_swap_dimension(column); } } else { - if constexpr (Master_matrix::Option_list::is_z2) { - if (val) { - _add(column); - } else { - clear(); - _add(column); - } - } else { - _multiply_target_and_add(val, column); - } + _multiply_target_and_add(Master_matrix::get_coefficient_value(val, operators_), column); } return *this; @@ -806,13 +770,7 @@ inline Intrusive_set_column& Intrusive_set_column: static_assert((!Master_matrix::isNonBasic || Master_matrix::Option_list::is_of_boundary_type), "For chain columns, the given column cannot be constant."); - if constexpr (Master_matrix::Option_list::is_z2) { - if (val) { - _add(column); - } - } else { - _multiply_source_and_add(column, val); - } + _multiply_source_and_add(column, Master_matrix::get_coefficient_value(val, operators_)); return *this; } @@ -824,27 +782,12 @@ inline Intrusive_set_column& Intrusive_set_column: { if constexpr (Master_matrix::isNonBasic && !Master_matrix::Option_list::is_of_boundary_type) { // assumes that the addition never zeros out this column. - if constexpr (Master_matrix::Option_list::is_z2) { - if (val) { - if (_add(column)) { - Chain_opt::_swap_pivots(column); - Dim_opt::_swap_dimension(column); - } - } - } else { - if (_multiply_source_and_add(column, val)) { - Chain_opt::_swap_pivots(column); - Dim_opt::_swap_dimension(column); - } + if (_multiply_source_and_add(column, Master_matrix::get_coefficient_value(val, operators_))) { + Chain_opt::_swap_pivots(column); + Dim_opt::_swap_dimension(column); } } else { - if constexpr (Master_matrix::Option_list::is_z2) { - if (val) { - _add(column); - } - } else { - _multiply_source_and_add(column, val); - } + _multiply_source_and_add(column, Master_matrix::get_coefficient_value(val, operators_)); } return *this; @@ -857,11 +800,7 @@ inline void Intrusive_set_column::push_back(const Entry& entry) GUDHI_CHECK(entry.get_row_index() > get_pivot(), "The new row index has to be higher than the current pivot."); - if constexpr (Master_matrix::Option_list::is_z2) { - _insert_entry(entry.get_row_index(), column_.end()); - } else { - _insert_entry(entry.get_element(), entry.get_row_index(), column_.end()); - } + _insert_entry(column_.end(), entry.get_row_index(), entry.get_element()); } template @@ -914,35 +853,20 @@ inline void Intrusive_set_column::_delete_entry(iterator& it) template inline typename Intrusive_set_column::Entry* Intrusive_set_column::_insert_entry( - const Field_element& value, + const iterator& position, ID_index rowIndex, - const iterator& position) -{ - if constexpr (Master_matrix::Option_list::has_row_access) { - Entry* newEntry = entryPool_->construct(RA_opt::get_column_index(), rowIndex); - newEntry->set_element(value); - column_.insert(position, *newEntry); - RA_opt::insert_entry(rowIndex, newEntry); - return newEntry; - } else { - Entry* newEntry = entryPool_->construct(rowIndex); - newEntry->set_element(value); - column_.insert(position, *newEntry); - return newEntry; - } -} - -template -inline void Intrusive_set_column::_insert_entry(ID_index rowIndex, const iterator& position) + const Field_element& value) { + Entry* newEntry; if constexpr (Master_matrix::Option_list::has_row_access) { - Entry* newEntry = entryPool_->construct(RA_opt::get_column_index(), rowIndex); - column_.insert(position, *newEntry); - RA_opt::insert_entry(rowIndex, newEntry); + newEntry = entryPool_->construct(RA_opt::get_column_index(), rowIndex); } else { - Entry* newEntry = entryPool_->construct(rowIndex); - column_.insert(position, *newEntry); + newEntry = entryPool_->construct(rowIndex); } + newEntry->set_element(value); + column_.insert(position, *newEntry); + if constexpr (Master_matrix::Option_list::has_row_access) RA_opt::insert_entry(rowIndex, newEntry); + return newEntry; } template diff --git a/multipers/gudhi/gudhi/Persistence_matrix/columns/list_column.h b/multipers/gudhi/gudhi/Persistence_matrix/columns/list_column.h index 8d37d5b2..9699e151 100644 --- a/multipers/gudhi/gudhi/Persistence_matrix/columns/list_column.h +++ b/multipers/gudhi/gudhi/Persistence_matrix/columns/list_column.h @@ -24,6 +24,7 @@ #include #include //std::swap, std::move & std::exchange +#include #include #include @@ -67,6 +68,7 @@ class List_column : public Master_matrix::Row_access_option, using const_iterator = boost::indirect_iterator; using reverse_iterator = boost::indirect_iterator; using const_reverse_iterator = boost::indirect_iterator; + using Content_range = boost::iterator_range; List_column(Column_settings* colSettings = nullptr); template @@ -76,14 +78,32 @@ class List_column : public Master_matrix::Row_access_option, const Container& nonZeroRowIndices, Row_container* rowContainer, Column_settings* colSettings); - template + template > > List_column(const Container& nonZeroRowIndices, Dimension dimension, Column_settings* colSettings); - template + template > > List_column(Index columnIndex, const Container& nonZeroRowIndices, Dimension dimension, Row_container* rowContainer, Column_settings* colSettings); + List_column(ID_index idx, Dimension dimension, Column_settings* colSettings); + List_column(ID_index idx, Field_element e, Dimension dimension, Column_settings* colSettings); + template + List_column(Index columnIndex, + ID_index idx, + Dimension dimension, + Row_container* rowContainer, + Column_settings* colSettings); + template + List_column(Index columnIndex, + ID_index idx, + Field_element e, + Dimension dimension, + Row_container* rowContainer, + Column_settings* colSettings); List_column(const List_column& column, Column_settings* colSettings = nullptr); template List_column(const List_column& column, @@ -116,11 +136,13 @@ class List_column : public Master_matrix::Row_access_option, reverse_iterator rend() noexcept; const_reverse_iterator rend() const noexcept; + Content_range get_non_zero_content_range() const; + template List_column& operator+=(const Entry_range& column); List_column& operator+=(List_column& column); - List_column& operator*=(unsigned int v); + List_column& operator*=(const Field_element& v); // this = v * this + column template @@ -136,38 +158,32 @@ class List_column : public Master_matrix::Row_access_option, friend bool operator==(const List_column& c1, const List_column& c2) { if (&c1 == &c2) return true; - - auto it1 = c1.column_.begin(); - auto it2 = c2.column_.begin(); if (c1.column_.size() != c2.column_.size()) return false; - while (it1 != c1.column_.end() && it2 != c2.column_.end()) { - if constexpr (Master_matrix::Option_list::is_z2) { - if ((*it1)->get_row_index() != (*it2)->get_row_index()) return false; - } else { - if ((*it1)->get_row_index() != (*it2)->get_row_index() || (*it1)->get_element() != (*it2)->get_element()) - return false; - } - ++it1; - ++it2; - } - return true; + + return std::equal(c1.column_.begin(), + c1.column_.end(), + c2.column_.begin(), + c2.column_.end(), + [](const Entry* e1, const Entry* e2) { + return e1->get_row_index() == e2->get_row_index() && e1->get_element() == e2->get_element(); + }); } friend bool operator<(const List_column& c1, const List_column& c2) { if (&c1 == &c2) return false; - auto it1 = c1.column_.begin(); - auto it2 = c2.column_.begin(); - while (it1 != c1.column_.end() && it2 != c2.column_.end()) { - if ((*it1)->get_row_index() != (*it2)->get_row_index()) return (*it1)->get_row_index() < (*it2)->get_row_index(); - if constexpr (!Master_matrix::Option_list::is_z2) { - if ((*it1)->get_element() != (*it2)->get_element()) return (*it1)->get_element() < (*it2)->get_element(); - } - ++it1; - ++it2; - } - return it2 != c2.column_.end(); + return std::lexicographical_compare(c1.column_.begin(), + c1.column_.end(), + c2.column_.begin(), + c2.column_.end(), + [](const Entry* e1, const Entry* e2) { + if (e1->get_row_index() != e2->get_row_index()) + return e1->get_row_index() < e2->get_row_index(); + if (e1->get_element() != e2->get_element()) + return e1->get_element() < e2->get_element(); + return false; + }); } // Disabled with row access. @@ -193,7 +209,7 @@ class List_column : public Master_matrix::Row_access_option, using Chain_opt = typename Master_matrix::Chain_column_option; Column_support column_; - Field_operators* operators_; + Field_operators const* operators_; Entry_constructor* entryPool_; template @@ -225,12 +241,10 @@ class List_column : public Master_matrix::Row_access_option, Column& targetColumn); void _delete_entry(typename Column_support::iterator& it); - Entry* _insert_entry(const Field_element& value, + Entry* _insert_entry(const typename Column_support::iterator& position, ID_index rowIndex, - const typename Column_support::iterator& position); - void _insert_entry(ID_index rowIndex, const typename Column_support::iterator& position); - void _update_entry(const Field_element& value, ID_index rowIndex, const typename Column_support::iterator& position); - void _update_entry(ID_index rowIndex, const typename Column_support::iterator& position); + const Field_element& value); + void _update_entry(const typename Column_support::iterator& position, ID_index rowIndex, const Field_element& value); template bool _add(const Entry_range& column); template @@ -244,40 +258,17 @@ inline List_column::List_column(Column_settings* colSettings) : RA_opt(), Dim_opt(), Chain_opt(), - operators_(nullptr), + operators_(Master_matrix::get_operator_ptr(colSettings)), entryPool_(colSettings == nullptr ? nullptr : &(colSettings->entryConstructor)) -{ - if (operators_ == nullptr && entryPool_ == nullptr) - return; // to allow default constructor which gives a dummy column - if constexpr (!Master_matrix::Option_list::is_z2) { - operators_ = &(colSettings->operators); - } -} +{} template template inline List_column::List_column(const Container& nonZeroRowIndices, Column_settings* colSettings) - : RA_opt(), - Dim_opt(nonZeroRowIndices.size() == 0 ? 0 : nonZeroRowIndices.size() - 1), - Chain_opt(), - column_(nonZeroRowIndices.size()), - operators_(nullptr), - entryPool_(&(colSettings->entryConstructor)) + : List_column(nonZeroRowIndices, nonZeroRowIndices.size() == 0 ? 0 : nonZeroRowIndices.size() - 1, colSettings) { static_assert(!Master_matrix::isNonBasic || Master_matrix::Option_list::is_of_boundary_type, "Constructor not available for chain columns, please specify the dimension of the chain."); - - auto it = column_.begin(); - if constexpr (Master_matrix::Option_list::is_z2) { - for (ID_index id : nonZeroRowIndices) { - _update_entry(id, it++); - } - } else { - operators_ = &(colSettings->operators); - for (const auto& p : nonZeroRowIndices) { - _update_entry(operators_->get_value(p.second), p.first, it++); - } - } } template @@ -286,76 +277,40 @@ inline List_column::List_column(Index columnIndex, const Container& nonZeroRowIndices, Row_container* rowContainer, Column_settings* colSettings) - : RA_opt(columnIndex, rowContainer), - Dim_opt(nonZeroRowIndices.size() == 0 ? 0 : nonZeroRowIndices.size() - 1), - Chain_opt([&] { - if constexpr (Master_matrix::Option_list::is_z2) { - return nonZeroRowIndices.begin() == nonZeroRowIndices.end() - ? Master_matrix::template get_null_value() - : *std::prev(nonZeroRowIndices.end()); - } else { - return nonZeroRowIndices.begin() == nonZeroRowIndices.end() - ? Master_matrix::template get_null_value() - : std::prev(nonZeroRowIndices.end())->first; - } - }()), - column_(nonZeroRowIndices.size()), - operators_(nullptr), - entryPool_(&(colSettings->entryConstructor)) + : List_column(columnIndex, + nonZeroRowIndices, + nonZeroRowIndices.size() == 0 ? 0 : nonZeroRowIndices.size() - 1, + rowContainer, + colSettings) { static_assert(!Master_matrix::isNonBasic || Master_matrix::Option_list::is_of_boundary_type, "Constructor not available for chain columns, please specify the dimension of the chain."); - - auto it = column_.begin(); - if constexpr (Master_matrix::Option_list::is_z2) { - for (ID_index id : nonZeroRowIndices) { - _update_entry(id, it++); - } - } else { - operators_ = &(colSettings->operators); - for (const auto& p : nonZeroRowIndices) { - _update_entry(operators_->get_value(p.second), p.first, it++); - } - } } template -template +template inline List_column::List_column(const Container& nonZeroRowIndices, Dimension dimension, Column_settings* colSettings) : RA_opt(), Dim_opt(dimension), - Chain_opt([&] { - if constexpr (Master_matrix::Option_list::is_z2) { - return nonZeroRowIndices.begin() == nonZeroRowIndices.end() - ? Master_matrix::template get_null_value() - : *std::prev(nonZeroRowIndices.end()); - } else { - return nonZeroRowIndices.begin() == nonZeroRowIndices.end() - ? Master_matrix::template get_null_value() - : std::prev(nonZeroRowIndices.end())->first; - } - }()), + Chain_opt(nonZeroRowIndices.begin() == nonZeroRowIndices.end() + ? Master_matrix::template get_null_value() + : Master_matrix::get_row_index(*std::prev(nonZeroRowIndices.end()))), column_(nonZeroRowIndices.size()), - operators_(nullptr), + operators_(Master_matrix::get_operator_ptr(colSettings)), entryPool_(&(colSettings->entryConstructor)) { auto it = column_.begin(); - if constexpr (Master_matrix::Option_list::is_z2) { - for (ID_index id : nonZeroRowIndices) { - _update_entry(id, it++); - } - } else { - operators_ = &(colSettings->operators); - for (const auto& p : nonZeroRowIndices) { - _update_entry(operators_->get_value(p.second), p.first, it++); - } + for (const auto& id : nonZeroRowIndices) { + _update_entry(it++, + Master_matrix::get_row_index(id), + Master_matrix::get_coefficient_value(Master_matrix::get_element(id), operators_)); } } template -template +template inline List_column::List_column(Index columnIndex, const Container& nonZeroRowIndices, Dimension dimension, @@ -363,58 +318,107 @@ inline List_column::List_column(Index columnIndex, Column_settings* colSettings) : RA_opt(columnIndex, rowContainer), Dim_opt(dimension), - Chain_opt([&] { - if constexpr (Master_matrix::Option_list::is_z2) { - return nonZeroRowIndices.begin() == nonZeroRowIndices.end() - ? Master_matrix::template get_null_value() - : *std::prev(nonZeroRowIndices.end()); - } else { - return nonZeroRowIndices.begin() == nonZeroRowIndices.end() - ? Master_matrix::template get_null_value() - : std::prev(nonZeroRowIndices.end())->first; - } - }()), + Chain_opt(nonZeroRowIndices.begin() == nonZeroRowIndices.end() + ? Master_matrix::template get_null_value() + : Master_matrix::get_row_index(*std::prev(nonZeroRowIndices.end()))), column_(nonZeroRowIndices.size()), - operators_(nullptr), + operators_(Master_matrix::get_operator_ptr(colSettings)), entryPool_(&(colSettings->entryConstructor)) { auto it = column_.begin(); - if constexpr (Master_matrix::Option_list::is_z2) { - for (ID_index id : nonZeroRowIndices) { - _update_entry(id, it++); - } - } else { - operators_ = &(colSettings->operators); - for (const auto& p : nonZeroRowIndices) { - _update_entry(operators_->get_value(p.second), p.first, it++); - } + for (const auto& id : nonZeroRowIndices) { + _update_entry(it++, + Master_matrix::get_row_index(id), + Master_matrix::get_coefficient_value(Master_matrix::get_element(id), operators_)); } } +template +inline List_column::List_column(ID_index idx, Dimension dimension, Column_settings* colSettings) + : RA_opt(), + Dim_opt(dimension), + Chain_opt(idx), + column_(1), + operators_(nullptr), + entryPool_(&(colSettings->entryConstructor)) +{ + static_assert(Master_matrix::Option_list::is_z2, + "Constructor not available for Zp != Z2. Please specify the coefficient."); + _update_entry(column_.begin(), idx, 1); +} + +template +inline List_column::List_column(ID_index idx, + Field_element e, + Dimension dimension, + Column_settings* colSettings) + : RA_opt(), + Dim_opt(dimension), + Chain_opt(idx), + column_(1), + operators_(&(colSettings->operators)), + entryPool_(&(colSettings->entryConstructor)) +{ + static_assert(!Master_matrix::Option_list::is_z2, + "Constructor not available for Zp == Z2. Please do not specify any coefficient."); + _update_entry(column_.begin(), idx, operators_->get_value(e)); +} + +template +template +inline List_column::List_column(Index columnIndex, + ID_index idx, + Dimension dimension, + Row_container* rowContainer, + Column_settings* colSettings) + : RA_opt(columnIndex, rowContainer), + Dim_opt(dimension), + Chain_opt(idx), + column_(1), + operators_(nullptr), + entryPool_(&(colSettings->entryConstructor)) +{ + static_assert(Master_matrix::Option_list::is_z2, + "Constructor not available for Zp != Z2. Please specify the coefficient."); + _update_entry(column_.begin(), idx, 1); +} + +template +template +inline List_column::List_column(Index columnIndex, + ID_index idx, + Field_element e, + Dimension dimension, + Row_container* rowContainer, + Column_settings* colSettings) + : RA_opt(columnIndex, rowContainer), + Dim_opt(dimension), + Chain_opt(idx), + column_(1), + operators_(&(colSettings->operators)), + entryPool_(&(colSettings->entryConstructor)) +{ + static_assert(!Master_matrix::Option_list::is_z2, + "Constructor not available for Zp == Z2. Please do not specify any coefficient."); + _update_entry(column_.begin(), idx, operators_->get_value(e)); +} + template inline List_column::List_column(const List_column& column, Column_settings* colSettings) : RA_opt(), Dim_opt(static_cast(column)), Chain_opt(static_cast(column)), column_(column.column_.size()), - operators_(colSettings == nullptr ? column.operators_ : nullptr), + operators_(colSettings == nullptr ? column.operators_ : Master_matrix::get_operator_ptr(colSettings)), entryPool_(colSettings == nullptr ? column.entryPool_ : &(colSettings->entryConstructor)) { static_assert(!Master_matrix::Option_list::has_row_access, "Simple copy constructor not available when row access option enabled. Please specify the new column " "index and the row container."); - if constexpr (!Master_matrix::Option_list::is_z2) { - if (colSettings != nullptr) operators_ = &(colSettings->operators); - } - auto it = column_.begin(); for (const Entry* entry : column.column_) { - if constexpr (Master_matrix::Option_list::is_z2) { - _update_entry(entry->get_row_index(), it++); - } else { - _update_entry(entry->get_element(), entry->get_row_index(), it++); - } + _update_entry(it++, entry->get_row_index(), entry->get_element()); } } @@ -428,20 +432,12 @@ inline List_column::List_column(const List_column& column, Dim_opt(static_cast(column)), Chain_opt(static_cast(column)), column_(column.column_.size()), - operators_(colSettings == nullptr ? column.operators_ : nullptr), + operators_(colSettings == nullptr ? column.operators_ : Master_matrix::get_operator_ptr(colSettings)), entryPool_(colSettings == nullptr ? column.entryPool_ : &(colSettings->entryConstructor)) { - if constexpr (!Master_matrix::Option_list::is_z2) { - if (colSettings != nullptr) operators_ = &(colSettings->operators); - } - auto it = column_.begin(); for (const Entry* entry : column.column_) { - if constexpr (Master_matrix::Option_list::is_z2) { - _update_entry(entry->get_row_index(), it++); - } else { - _update_entry(entry->get_element(), entry->get_row_index(), it++); - } + _update_entry(it++, entry->get_row_index(), entry->get_element()); } } @@ -453,8 +449,7 @@ inline List_column::List_column(List_column&& column) noexcept column_(std::move(column.column_)), operators_(std::exchange(column.operators_, nullptr)), entryPool_(std::exchange(column.entryPool_, nullptr)) -{ -} +{} template inline List_column::~List_column() @@ -477,11 +472,7 @@ inline std::vector::Field_element> List_colu std::vector container(columnLength, 0); for (auto it = column_.begin(); it != column_.end() && (*it)->get_row_index() < static_cast(columnLength); ++it) { - if constexpr (Master_matrix::Option_list::is_z2) { - container[(*it)->get_row_index()] = 1; - } else { - container[(*it)->get_row_index()] = (*it)->get_element(); - } + container[(*it)->get_row_index()] = Master_matrix::get_element(**it); } return container; } @@ -648,6 +639,12 @@ inline typename List_column::const_reverse_iterator List_column +inline typename List_column::Content_range List_column::get_non_zero_content_range() const +{ + return Content_range(column_.begin(), column_.end()); +} + template template inline List_column& List_column::operator+=(const Entry_range& column) @@ -680,30 +677,24 @@ inline List_column& List_column::operator+=(List_c } template -inline List_column& List_column::operator*=(unsigned int v) +inline List_column& List_column::operator*=(const Field_element& v) { - if constexpr (Master_matrix::Option_list::is_z2) { - if (v % 2 == 0) { - if constexpr (Master_matrix::isNonBasic && !Master_matrix::Option_list::is_of_boundary_type) { - throw std::invalid_argument("A chain column should not be multiplied by 0."); - } else { - clear(); - } - } - } else { - Field_element val = operators_->get_value(v); + Field_element val = Master_matrix::get_coefficient_value(v, operators_); - if (val == 0U) { - if constexpr (Master_matrix::isNonBasic && !Master_matrix::Option_list::is_of_boundary_type) { - throw std::invalid_argument("A chain column should not be multiplied by 0."); - } else { - clear(); - } - return *this; + if (val == Field_operators::get_additive_identity()) { + if constexpr (Master_matrix::isNonBasic && !Master_matrix::Option_list::is_of_boundary_type) { + throw std::invalid_argument("A chain column should not be multiplied by 0."); + } else { + clear(); } + return *this; + } - if (val == 1U) return *this; + if (val == Field_operators::get_multiplicative_identity()) return *this; + // multiply_inplace needs a non-const reference to element, so even if Z2 never reaches here, it won't compile + // without the constexpr, as we are not storing a dummy value just for this purpose. + if constexpr (!Master_matrix::Option_list::is_z2) { for (Entry* entry : column_) { operators_->multiply_inplace(entry->get_element(), val); if constexpr (Master_matrix::Option_list::has_row_access) RA_opt::update_entry(*entry); @@ -724,16 +715,7 @@ inline List_column& List_column::multiply_target_a static_assert((!Master_matrix::isNonBasic || Master_matrix::Option_list::is_of_boundary_type), "For chain columns, the given column cannot be constant."); - if constexpr (Master_matrix::Option_list::is_z2) { - if (val) { - _add(column); - } else { - clear(); - _add(column); - } - } else { - _multiply_target_and_add(val, column); - } + _multiply_target_and_add(Master_matrix::get_coefficient_value(val, operators_), column); return *this; } @@ -744,32 +726,12 @@ inline List_column& List_column::multiply_target_a { if constexpr (Master_matrix::isNonBasic && !Master_matrix::Option_list::is_of_boundary_type) { // assumes that the addition never zeros out this column. - if constexpr (Master_matrix::Option_list::is_z2) { - if (val) { - if (_add(column)) { - Chain_opt::_swap_pivots(column); - Dim_opt::_swap_dimension(column); - } - } else { - throw std::invalid_argument("A chain column should not be multiplied by 0."); - } - } else { - if (_multiply_target_and_add(val, column)) { - Chain_opt::_swap_pivots(column); - Dim_opt::_swap_dimension(column); - } + if (_multiply_target_and_add(Master_matrix::get_coefficient_value(val, operators_), column)) { + Chain_opt::_swap_pivots(column); + Dim_opt::_swap_dimension(column); } } else { - if constexpr (Master_matrix::Option_list::is_z2) { - if (val) { - _add(column); - } else { - clear(); - _add(column); - } - } else { - _multiply_target_and_add(val, column); - } + _multiply_target_and_add(Master_matrix::get_coefficient_value(val, operators_), column); } return *this; @@ -786,13 +748,7 @@ inline List_column& List_column::multiply_source_a static_assert((!Master_matrix::isNonBasic || Master_matrix::Option_list::is_of_boundary_type), "For chain columns, the given column cannot be constant."); - if constexpr (Master_matrix::Option_list::is_z2) { - if (val) { - _add(column); - } - } else { - _multiply_source_and_add(column, val); - } + _multiply_source_and_add(column, Master_matrix::get_coefficient_value(val, operators_)); return *this; } @@ -803,27 +759,12 @@ inline List_column& List_column::multiply_source_a { if constexpr (Master_matrix::isNonBasic && !Master_matrix::Option_list::is_of_boundary_type) { // assumes that the addition never zeros out this column. - if constexpr (Master_matrix::Option_list::is_z2) { - if (val) { - if (_add(column)) { - Chain_opt::_swap_pivots(column); - Dim_opt::_swap_dimension(column); - } - } - } else { - if (_multiply_source_and_add(column, val)) { - Chain_opt::_swap_pivots(column); - Dim_opt::_swap_dimension(column); - } + if (_multiply_source_and_add(column, Master_matrix::get_coefficient_value(val, operators_))) { + Chain_opt::_swap_pivots(column); + Dim_opt::_swap_dimension(column); } } else { - if constexpr (Master_matrix::Option_list::is_z2) { - if (val) { - _add(column); - } - } else { - _multiply_source_and_add(column, val); - } + _multiply_source_and_add(column, Master_matrix::get_coefficient_value(val, operators_)); } return *this; @@ -836,11 +777,7 @@ inline void List_column::push_back(const Entry& entry) GUDHI_CHECK(entry.get_row_index() > get_pivot(), "The new row index has to be higher than the current pivot."); - if constexpr (Master_matrix::Option_list::is_z2) { - _insert_entry(entry.get_row_index(), column_.end()); - } else { - _insert_entry(entry.get_element(), entry.get_row_index(), column_.end()); - } + _insert_entry(column_.end(), entry.get_row_index(), entry.get_element()); } template @@ -870,11 +807,7 @@ inline List_column& List_column::operator=(const L if (*it != nullptr) { tmpPool->destroy(*it); } - if constexpr (Master_matrix::Option_list::is_z2) { - _update_entry(entry->get_row_index(), it++); - } else { - _update_entry(entry->get_element(), entry->get_row_index(), it++); - } + _update_entry(it++, entry->get_row_index(), entry->get_element()); } operators_ = other.operators_; @@ -914,63 +847,34 @@ inline void List_column::_delete_entry(typename Column_support::i template inline typename List_column::Entry* List_column::_insert_entry( - const Field_element& value, + const typename Column_support::iterator& position, ID_index rowIndex, - const typename Column_support::iterator& position) -{ - if constexpr (Master_matrix::Option_list::has_row_access) { - Entry* newEntry = entryPool_->construct(RA_opt::get_column_index(), rowIndex); - newEntry->set_element(value); - column_.insert(position, newEntry); - RA_opt::insert_entry(rowIndex, newEntry); - return newEntry; - } else { - Entry* newEntry = entryPool_->construct(rowIndex); - newEntry->set_element(value); - column_.insert(position, newEntry); - return newEntry; - } -} - -template -inline void List_column::_insert_entry(ID_index rowIndex, - const typename Column_support::iterator& position) + const Field_element& value) { + Entry* newEntry; if constexpr (Master_matrix::Option_list::has_row_access) { - Entry* newEntry = entryPool_->construct(RA_opt::get_column_index(), rowIndex); - column_.insert(position, newEntry); - RA_opt::insert_entry(rowIndex, newEntry); + newEntry = entryPool_->construct(RA_opt::get_column_index(), rowIndex); } else { - Entry* newEntry = entryPool_->construct(rowIndex); - column_.insert(position, newEntry); + newEntry = entryPool_->construct(rowIndex); } + newEntry->set_element(value); + column_.insert(position, newEntry); + if constexpr (Master_matrix::Option_list::has_row_access) RA_opt::insert_entry(rowIndex, newEntry); + return newEntry; } template -inline void List_column::_update_entry(const Field_element& value, +inline void List_column::_update_entry(const typename Column_support::iterator& position, ID_index rowIndex, - const typename Column_support::iterator& position) + const Field_element& value) { if constexpr (Master_matrix::Option_list::has_row_access) { *position = entryPool_->construct(RA_opt::get_column_index(), rowIndex); - (*position)->set_element(value); - RA_opt::insert_entry(rowIndex, *position); - } else { - *position = entryPool_->construct(rowIndex); - (*position)->set_element(value); - } -} - -template -inline void List_column::_update_entry(ID_index rowIndex, - const typename Column_support::iterator& position) -{ - if constexpr (Master_matrix::Option_list::has_row_access) { - *position = entryPool_->construct(RA_opt::get_column_index(), rowIndex); - RA_opt::insert_entry(rowIndex, *position); } else { *position = entryPool_->construct(rowIndex); } + (*position)->set_element(value); + if constexpr (Master_matrix::Option_list::has_row_access) RA_opt::insert_entry(rowIndex, *position); } template @@ -982,11 +886,7 @@ inline bool List_column::_add(const Entry_range& column) column_.resize(column.size()); auto it = column_.begin(); for (const Entry& entry : column) { - if constexpr (Master_matrix::Option_list::is_z2) { - _update_entry(entry.get_row_index(), it++); - } else { - _update_entry(entry.get_element(), entry.get_row_index(), it++); - } + _update_entry(it++, entry.get_row_index(), entry.get_element()); } return true; } diff --git a/multipers/gudhi/gudhi/Persistence_matrix/columns/naive_vector_column.h b/multipers/gudhi/gudhi/Persistence_matrix/columns/naive_vector_column.h index 0ee3d7d2..225d6b22 100644 --- a/multipers/gudhi/gudhi/Persistence_matrix/columns/naive_vector_column.h +++ b/multipers/gudhi/gudhi/Persistence_matrix/columns/naive_vector_column.h @@ -24,6 +24,7 @@ #include //binary_search #include //std::swap, std::move & std::exchange +#include #include #include @@ -68,6 +69,7 @@ class Naive_vector_column : public Master_matrix::Row_access_option, using const_iterator = boost::indirect_iterator; using reverse_iterator = boost::indirect_iterator; using const_reverse_iterator = boost::indirect_iterator; + using Content_range = boost::iterator_range; Naive_vector_column(Column_settings* colSettings = nullptr); template @@ -77,14 +79,35 @@ class Naive_vector_column : public Master_matrix::Row_access_option, const Container& nonZeroRowIndices, Row_container* rowContainer, Column_settings* colSettings); - template + template > > Naive_vector_column(const Container& nonZeroRowIndices, Dimension dimension, Column_settings* colSettings); - template + template > > Naive_vector_column(Index columnIndex, const Container& nonZeroRowIndices, Dimension dimension, Row_container* rowContainer, Column_settings* colSettings); + Naive_vector_column(ID_index idx, Dimension dimension, Column_settings* colSettings); + Naive_vector_column(ID_index idx, + Field_element e, + Dimension dimension, + Column_settings* colSettings); + template + Naive_vector_column(Index columnIndex, + ID_index idx, + Dimension dimension, + Row_container* rowContainer, + Column_settings* colSettings); + template + Naive_vector_column(Index columnIndex, + ID_index idx, + Field_element e, + Dimension dimension, + Row_container* rowContainer, + Column_settings* colSettings); Naive_vector_column(const Naive_vector_column& column, Column_settings* colSettings = nullptr); template Naive_vector_column(const Naive_vector_column& column, @@ -117,11 +140,13 @@ class Naive_vector_column : public Master_matrix::Row_access_option, reverse_iterator rend() noexcept; const_reverse_iterator rend() const noexcept; + Content_range get_non_zero_content_range() const; + template Naive_vector_column& operator+=(const Entry_range& column); Naive_vector_column& operator+=(Naive_vector_column& column); - Naive_vector_column& operator*=(unsigned int v); + Naive_vector_column& operator*=(const Field_element& v); // this = v * this + column template @@ -139,36 +164,30 @@ class Naive_vector_column : public Master_matrix::Row_access_option, if (&c1 == &c2) return true; if (c1.column_.size() != c2.column_.size()) return false; - auto it1 = c1.column_.begin(); - auto it2 = c2.column_.begin(); - while (it1 != c1.column_.end() && it2 != c2.column_.end()) { - if constexpr (Master_matrix::Option_list::is_z2) { - if ((*it1)->get_row_index() != (*it2)->get_row_index()) return false; - } else { - if ((*it1)->get_row_index() != (*it2)->get_row_index() || (*it1)->get_element() != (*it2)->get_element()) - return false; - } - ++it1; - ++it2; - } - return true; + return std::equal(c1.column_.begin(), + c1.column_.end(), + c2.column_.begin(), + c2.column_.end(), + [](const Entry* e1, const Entry* e2) { + return e1->get_row_index() == e2->get_row_index() && e1->get_element() == e2->get_element(); + }); } friend bool operator<(const Naive_vector_column& c1, const Naive_vector_column& c2) { if (&c1 == &c2) return false; - auto it1 = c1.column_.begin(); - auto it2 = c2.column_.begin(); - while (it1 != c1.column_.end() && it2 != c2.column_.end()) { - if ((*it1)->get_row_index() != (*it2)->get_row_index()) return (*it1)->get_row_index() < (*it2)->get_row_index(); - if constexpr (!Master_matrix::Option_list::is_z2) { - if ((*it1)->get_element() != (*it2)->get_element()) return (*it1)->get_element() < (*it2)->get_element(); - } - ++it1; - ++it2; - } - return it2 != c2.column_.end(); + return std::lexicographical_compare(c1.column_.begin(), + c1.column_.end(), + c2.column_.begin(), + c2.column_.end(), + [](const Entry* e1, const Entry* e2) { + if (e1->get_row_index() != e2->get_row_index()) + return e1->get_row_index() < e2->get_row_index(); + if (e1->get_element() != e2->get_element()) + return e1->get_element() < e2->get_element(); + return false; + }); } // Disabled with row access. @@ -194,7 +213,7 @@ class Naive_vector_column : public Master_matrix::Row_access_option, using Chain_opt = typename Master_matrix::Chain_column_option; Column_support column_; - Field_operators* operators_; + Field_operators const* operators_; Entry_constructor* entryPool_; template @@ -217,10 +236,8 @@ class Naive_vector_column : public Master_matrix::Row_access_option, void _delete_entry(Entry* entry); void _delete_entry(typename Column_support::iterator& it); - Entry* _insert_entry(const Field_element& value, ID_index rowIndex, Column_support& column); - void _insert_entry(ID_index rowIndex, Column_support& column); - void _update_entry(const Field_element& value, ID_index rowIndex, Index position); - void _update_entry(ID_index rowIndex, Index position); + Entry* _insert_entry(Column_support& column, ID_index rowIndex, const Field_element& value); + void _update_entry(Index position, ID_index rowIndex, const Field_element& value); template bool _add(const Entry_range& column); template @@ -240,41 +257,20 @@ inline Naive_vector_column::Naive_vector_column(Column_s : RA_opt(), Dim_opt(), Chain_opt(), - operators_(nullptr), + operators_(Master_matrix::get_operator_ptr(colSettings)), entryPool_(colSettings == nullptr ? nullptr : &(colSettings->entryConstructor)) -{ - if (operators_ == nullptr && entryPool_ == nullptr) - return; // to allow default constructor which gives a dummy column - if constexpr (!Master_matrix::Option_list::is_z2) { - operators_ = &(colSettings->operators); - } -} +{} template template inline Naive_vector_column::Naive_vector_column(const Container& nonZeroRowIndices, Column_settings* colSettings) - : RA_opt(), - Dim_opt(nonZeroRowIndices.size() == 0 ? 0 : nonZeroRowIndices.size() - 1), - Chain_opt(), - column_(nonZeroRowIndices.size(), nullptr), - operators_(nullptr), - entryPool_(&(colSettings->entryConstructor)) + : Naive_vector_column(nonZeroRowIndices, + nonZeroRowIndices.size() == 0 ? 0 : nonZeroRowIndices.size() - 1, + colSettings) { static_assert(!Master_matrix::isNonBasic || Master_matrix::Option_list::is_of_boundary_type, "Constructor not available for chain columns, please specify the dimension of the chain."); - - Index i = 0; - if constexpr (Master_matrix::Option_list::is_z2) { - for (ID_index id : nonZeroRowIndices) { - _update_entry(id, i++); - } - } else { - operators_ = &(colSettings->operators); - for (const auto& p : nonZeroRowIndices) { - _update_entry(operators_->get_value(p.second), p.first, i++); - } - } } template @@ -283,76 +279,40 @@ inline Naive_vector_column::Naive_vector_column(Index co const Container& nonZeroRowIndices, Row_container* rowContainer, Column_settings* colSettings) - : RA_opt(columnIndex, rowContainer), - Dim_opt(nonZeroRowIndices.size() == 0 ? 0 : nonZeroRowIndices.size() - 1), - Chain_opt([&] { - if constexpr (Master_matrix::Option_list::is_z2) { - return nonZeroRowIndices.begin() == nonZeroRowIndices.end() - ? Master_matrix::template get_null_value() - : *std::prev(nonZeroRowIndices.end()); - } else { - return nonZeroRowIndices.begin() == nonZeroRowIndices.end() - ? Master_matrix::template get_null_value() - : std::prev(nonZeroRowIndices.end())->first; - } - }()), - column_(nonZeroRowIndices.size(), nullptr), - operators_(nullptr), - entryPool_(&(colSettings->entryConstructor)) + : Naive_vector_column(columnIndex, + nonZeroRowIndices, + nonZeroRowIndices.size() == 0 ? 0 : nonZeroRowIndices.size() - 1, + rowContainer, + colSettings) { static_assert(!Master_matrix::isNonBasic || Master_matrix::Option_list::is_of_boundary_type, "Constructor not available for chain columns, please specify the dimension of the chain."); - - Index i = 0; - if constexpr (Master_matrix::Option_list::is_z2) { - for (ID_index id : nonZeroRowIndices) { - _update_entry(id, i++); - } - } else { - operators_ = &(colSettings->operators); - for (const auto& p : nonZeroRowIndices) { - _update_entry(operators_->get_value(p.second), p.first, i++); - } - } } template -template +template inline Naive_vector_column::Naive_vector_column(const Container& nonZeroRowIndices, Dimension dimension, Column_settings* colSettings) : RA_opt(), Dim_opt(dimension), - Chain_opt([&] { - if constexpr (Master_matrix::Option_list::is_z2) { - return nonZeroRowIndices.begin() == nonZeroRowIndices.end() - ? Master_matrix::template get_null_value() - : *std::prev(nonZeroRowIndices.end()); - } else { - return nonZeroRowIndices.begin() == nonZeroRowIndices.end() - ? Master_matrix::template get_null_value() - : std::prev(nonZeroRowIndices.end())->first; - } - }()), + Chain_opt(nonZeroRowIndices.begin() == nonZeroRowIndices.end() + ? Master_matrix::template get_null_value() + : Master_matrix::get_row_index(*std::prev(nonZeroRowIndices.end()))), column_(nonZeroRowIndices.size(), nullptr), - operators_(nullptr), + operators_(Master_matrix::get_operator_ptr(colSettings)), entryPool_(&(colSettings->entryConstructor)) { Index i = 0; - if constexpr (Master_matrix::Option_list::is_z2) { - for (ID_index id : nonZeroRowIndices) { - _update_entry(id, i++); - } - } else { - operators_ = &(colSettings->operators); - for (const auto& p : nonZeroRowIndices) { - _update_entry(operators_->get_value(p.second), p.first, i++); - } + for (const auto& id : nonZeroRowIndices) { + _update_entry(i++, + Master_matrix::get_row_index(id), + Master_matrix::get_coefficient_value(Master_matrix::get_element(id), operators_)); } } template -template +template inline Naive_vector_column::Naive_vector_column(Index columnIndex, const Container& nonZeroRowIndices, Dimension dimension, @@ -360,34 +320,93 @@ inline Naive_vector_column::Naive_vector_column(Index co Column_settings* colSettings) : RA_opt(columnIndex, rowContainer), Dim_opt(dimension), - Chain_opt([&] { - if constexpr (Master_matrix::Option_list::is_z2) { - return nonZeroRowIndices.begin() == nonZeroRowIndices.end() - ? Master_matrix::template get_null_value() - : *std::prev(nonZeroRowIndices.end()); - } else { - return nonZeroRowIndices.begin() == nonZeroRowIndices.end() - ? Master_matrix::template get_null_value() - : std::prev(nonZeroRowIndices.end())->first; - } - }()), + Chain_opt(nonZeroRowIndices.begin() == nonZeroRowIndices.end() + ? Master_matrix::template get_null_value() + : Master_matrix::get_row_index(*std::prev(nonZeroRowIndices.end()))), column_(nonZeroRowIndices.size(), nullptr), - operators_(nullptr), + operators_(Master_matrix::get_operator_ptr(colSettings)), entryPool_(&(colSettings->entryConstructor)) { Index i = 0; - if constexpr (Master_matrix::Option_list::is_z2) { - for (ID_index id : nonZeroRowIndices) { - _update_entry(id, i++); - } - } else { - operators_ = &(colSettings->operators); - for (const auto& p : nonZeroRowIndices) { - _update_entry(operators_->get_value(p.second), p.first, i++); - } + for (const auto& id : nonZeroRowIndices) { + _update_entry(i++, + Master_matrix::get_row_index(id), + Master_matrix::get_coefficient_value(Master_matrix::get_element(id), operators_)); } } +template +inline Naive_vector_column::Naive_vector_column(ID_index idx, + Dimension dimension, + Column_settings* colSettings) + : RA_opt(), + Dim_opt(dimension), + Chain_opt(idx), + column_(1, nullptr), + operators_(nullptr), + entryPool_(&(colSettings->entryConstructor)) +{ + static_assert(Master_matrix::Option_list::is_z2, + "Constructor not available for Zp != Z2. Please specify the coefficient."); + _update_entry(0, idx, 1); +} + +template +inline Naive_vector_column::Naive_vector_column(ID_index idx, + Field_element e, + Dimension dimension, + Column_settings* colSettings) + : RA_opt(), + Dim_opt(dimension), + Chain_opt(idx), + column_(1, nullptr), + operators_(&(colSettings->operators)), + entryPool_(&(colSettings->entryConstructor)) +{ + static_assert(!Master_matrix::Option_list::is_z2, + "Constructor not available for Zp == Z2. Please do not specify any coefficient."); + _update_entry(0, idx, operators_->get_value(e)); +} + +template +template +inline Naive_vector_column::Naive_vector_column(Index columnIndex, + ID_index idx, + Dimension dimension, + Row_container* rowContainer, + Column_settings* colSettings) + : RA_opt(columnIndex, rowContainer), + Dim_opt(dimension), + Chain_opt(idx), + column_(1, nullptr), + operators_(nullptr), + entryPool_(&(colSettings->entryConstructor)) +{ + static_assert(Master_matrix::Option_list::is_z2, + "Constructor not available for Zp != Z2. Please specify the coefficient."); + _update_entry(0, idx, 1); +} + +template +template +inline Naive_vector_column::Naive_vector_column(Index columnIndex, + ID_index idx, + Field_element e, + Dimension dimension, + Row_container* rowContainer, + Column_settings* colSettings) + : RA_opt(columnIndex, rowContainer), + Dim_opt(dimension), + Chain_opt(idx), + column_(1, nullptr), + operators_(&(colSettings->operators)), + entryPool_(&(colSettings->entryConstructor)) +{ + static_assert(!Master_matrix::Option_list::is_z2, + "Constructor not available for Zp == Z2. Please do not specify any coefficient."); + _update_entry(0, idx, operators_->get_value(e)); +} + template inline Naive_vector_column::Naive_vector_column(const Naive_vector_column& column, Column_settings* colSettings) @@ -395,24 +414,16 @@ inline Naive_vector_column::Naive_vector_column(const Na Dim_opt(static_cast(column)), Chain_opt(static_cast(column)), column_(column.column_.size(), nullptr), - operators_(colSettings == nullptr ? column.operators_ : nullptr), + operators_(colSettings == nullptr ? column.operators_ : Master_matrix::get_operator_ptr(colSettings)), entryPool_(colSettings == nullptr ? column.entryPool_ : &(colSettings->entryConstructor)) { static_assert(!Master_matrix::Option_list::has_row_access, "Simple copy constructor not available when row access option enabled. Please specify the new column " "index and the row container."); - if constexpr (!Master_matrix::Option_list::is_z2) { - if (colSettings != nullptr) operators_ = &(colSettings->operators); - } - Index i = 0; for (const Entry* entry : column.column_) { - if constexpr (Master_matrix::Option_list::is_z2) { - _update_entry(entry->get_row_index(), i++); - } else { - _update_entry(entry->get_element(), entry->get_row_index(), i++); - } + _update_entry(i++, entry->get_row_index(), entry->get_element()); } } @@ -426,20 +437,12 @@ inline Naive_vector_column::Naive_vector_column(const Na Dim_opt(static_cast(column)), Chain_opt(static_cast(column)), column_(column.column_.size(), nullptr), - operators_(colSettings == nullptr ? column.operators_ : nullptr), + operators_(colSettings == nullptr ? column.operators_ : Master_matrix::get_operator_ptr(colSettings)), entryPool_(colSettings == nullptr ? column.entryPool_ : &(colSettings->entryConstructor)) { - if constexpr (!Master_matrix::Option_list::is_z2) { - if (colSettings != nullptr) operators_ = &(colSettings->operators); - } - Index i = 0; for (const Entry* entry : column.column_) { - if constexpr (Master_matrix::Option_list::is_z2) { - _update_entry(entry->get_row_index(), i++); - } else { - _update_entry(entry->get_element(), entry->get_row_index(), i++); - } + _update_entry(i++, entry->get_row_index(), entry->get_element()); } } @@ -451,8 +454,7 @@ inline Naive_vector_column::Naive_vector_column(Naive_ve column_(std::move(column.column_)), operators_(std::exchange(column.operators_, nullptr)), entryPool_(std::exchange(column.entryPool_, nullptr)) -{ -} +{} template inline Naive_vector_column::~Naive_vector_column() @@ -474,11 +476,7 @@ Naive_vector_column::get_content(int columnLength) const std::vector container(columnLength, 0); for (auto it = column_.begin(); it != column_.end() && (*it)->get_row_index() < static_cast(columnLength); ++it) { - if constexpr (Master_matrix::Option_list::is_z2) { - container[(*it)->get_row_index()] = 1; - } else { - container[(*it)->get_row_index()] = (*it)->get_element(); - } + container[(*it)->get_row_index()] = Master_matrix::get_element(**it); } return container; } @@ -652,6 +650,13 @@ Naive_vector_column::rend() const noexcept return column_.rend(); } +template +inline typename Naive_vector_column::Content_range +Naive_vector_column::get_non_zero_content_range() const +{ + return Content_range(column_.begin(), column_.end()); +} + template template inline Naive_vector_column& Naive_vector_column::operator+=( @@ -687,30 +692,24 @@ inline Naive_vector_column& Naive_vector_column inline Naive_vector_column& Naive_vector_column::operator*=( - unsigned int v) + const Field_element& v) { - if constexpr (Master_matrix::Option_list::is_z2) { - if (v % 2 == 0) { - if constexpr (Master_matrix::isNonBasic && !Master_matrix::Option_list::is_of_boundary_type) { - throw std::invalid_argument("A chain column should not be multiplied by 0."); - } else { - clear(); - } - } - } else { - Field_element val = operators_->get_value(v); + Field_element val = Master_matrix::get_coefficient_value(v, operators_); - if (val == Field_operators::get_additive_identity()) { - if constexpr (Master_matrix::isNonBasic && !Master_matrix::Option_list::is_of_boundary_type) { - throw std::invalid_argument("A chain column should not be multiplied by 0."); - } else { - clear(); - } - return *this; + if (val == Field_operators::get_additive_identity()) { + if constexpr (Master_matrix::isNonBasic && !Master_matrix::Option_list::is_of_boundary_type) { + throw std::invalid_argument("A chain column should not be multiplied by 0."); + } else { + clear(); } + return *this; + } - if (val == Field_operators::get_multiplicative_identity()) return *this; + if (val == Field_operators::get_multiplicative_identity()) return *this; + // multiply_inplace needs a non-const reference to element, so even if Z2 never reaches here, it won't compile + // without the constexpr, as we are not storing a dummy value just for this purpose. + if constexpr (!Master_matrix::Option_list::is_z2) { for (Entry* entry : column_) { operators_->multiply_inplace(entry->get_element(), val); if constexpr (Master_matrix::Option_list::has_row_access) RA_opt::update_entry(*entry); @@ -732,16 +731,7 @@ Naive_vector_column::multiply_target_and_add(const Field static_assert((!Master_matrix::isNonBasic || Master_matrix::Option_list::is_of_boundary_type), "For chain columns, the given column cannot be constant."); - if constexpr (Master_matrix::Option_list::is_z2) { - if (val) { - _add(column); - } else { - clear(); - _add(column); - } - } else { - _multiply_target_and_add(val, column); - } + _multiply_target_and_add(Master_matrix::get_coefficient_value(val, operators_), column); return *this; } @@ -753,32 +743,12 @@ Naive_vector_column::multiply_target_and_add(const Field { if constexpr (Master_matrix::isNonBasic && !Master_matrix::Option_list::is_of_boundary_type) { // assumes that the addition never zeros out this column. - if constexpr (Master_matrix::Option_list::is_z2) { - if (val) { - if (_add(column)) { - Chain_opt::_swap_pivots(column); - Dim_opt::_swap_dimension(column); - } - } else { - throw std::invalid_argument("A chain column should not be multiplied by 0."); - } - } else { - if (_multiply_target_and_add(val, column)) { - Chain_opt::_swap_pivots(column); - Dim_opt::_swap_dimension(column); - } + if (_multiply_target_and_add(Master_matrix::get_coefficient_value(val, operators_), column)) { + Chain_opt::_swap_pivots(column); + Dim_opt::_swap_dimension(column); } } else { - if constexpr (Master_matrix::Option_list::is_z2) { - if (val) { - _add(column); - } else { - clear(); - _add(column); - } - } else { - _multiply_target_and_add(val, column); - } + _multiply_target_and_add(Master_matrix::get_coefficient_value(val, operators_), column); } return *this; @@ -796,13 +766,7 @@ Naive_vector_column::multiply_source_and_add(const Entry static_assert((!Master_matrix::isNonBasic || Master_matrix::Option_list::is_of_boundary_type), "For chain columns, the given column cannot be constant."); - if constexpr (Master_matrix::Option_list::is_z2) { - if (val) { - _add(column); - } - } else { - _multiply_source_and_add(column, val); - } + _multiply_source_and_add(column, Master_matrix::get_coefficient_value(val, operators_)); return *this; } @@ -814,27 +778,12 @@ Naive_vector_column::multiply_source_and_add(Naive_vecto { if constexpr (Master_matrix::isNonBasic && !Master_matrix::Option_list::is_of_boundary_type) { // assumes that the addition never zeros out this column. - if constexpr (Master_matrix::Option_list::is_z2) { - if (val) { - if (_add(column)) { - Chain_opt::_swap_pivots(column); - Dim_opt::_swap_dimension(column); - } - } - } else { - if (_multiply_source_and_add(column, val)) { - Chain_opt::_swap_pivots(column); - Dim_opt::_swap_dimension(column); - } + if (_multiply_source_and_add(column, Master_matrix::get_coefficient_value(val, operators_))) { + Chain_opt::_swap_pivots(column); + Dim_opt::_swap_dimension(column); } } else { - if constexpr (Master_matrix::Option_list::is_z2) { - if (val) { - _add(column); - } - } else { - _multiply_source_and_add(column, val); - } + _multiply_source_and_add(column, Master_matrix::get_coefficient_value(val, operators_)); } return *this; @@ -847,11 +796,7 @@ inline void Naive_vector_column::push_back(const Entry& GUDHI_CHECK(entry.get_row_index() > get_pivot(), "The new row index has to be higher than the current pivot."); - if constexpr (Master_matrix::Option_list::is_z2) { - _insert_entry(entry.get_row_index(), column_); - } else { - _insert_entry(entry.get_element(), entry.get_row_index(), column_); - } + _insert_entry(column_, entry.get_row_index(), entry.get_element()); } template @@ -882,11 +827,7 @@ inline Naive_vector_column& Naive_vector_columndestroy(column_[i]); } - if constexpr (Master_matrix::Option_list::is_z2) { - _update_entry(entry->get_row_index(), i++); - } else { - _update_entry(entry->get_element(), entry->get_row_index(), i++); - } + _update_entry(i++, entry->get_row_index(), entry->get_element()); } operators_ = other.operators_; @@ -933,62 +874,34 @@ inline void Naive_vector_column::_delete_entry(typename template inline typename Naive_vector_column::Entry* -Naive_vector_column::_insert_entry(const Field_element& value, +Naive_vector_column::_insert_entry(Column_support& column, ID_index rowIndex, - Column_support& column) + const Field_element& value) { + Entry* newEntry; if constexpr (Master_matrix::Option_list::has_row_access) { - Entry* newEntry = entryPool_->construct(RA_opt::get_column_index(), rowIndex); - newEntry->set_element(value); - column.push_back(newEntry); - RA_opt::insert_entry(rowIndex, newEntry); - return newEntry; + newEntry = entryPool_->construct(RA_opt::get_column_index(), rowIndex); } else { - Entry* newEntry = entryPool_->construct(rowIndex); - column.push_back(newEntry); - newEntry->set_element(value); - return newEntry; + newEntry = entryPool_->construct(rowIndex); } + column.push_back(newEntry); + newEntry->set_element(value); + if constexpr (Master_matrix::Option_list::has_row_access) RA_opt::insert_entry(rowIndex, newEntry); + return newEntry; } template -inline void Naive_vector_column::_insert_entry(ID_index rowIndex, Column_support& column) -{ - if constexpr (Master_matrix::Option_list::has_row_access) { - Entry* newEntry = entryPool_->construct(RA_opt::get_column_index(), rowIndex); - column.push_back(newEntry); - RA_opt::insert_entry(rowIndex, newEntry); - } else { - column.push_back(entryPool_->construct(rowIndex)); - } -} - -template -inline void Naive_vector_column::_update_entry(const Field_element& value, +inline void Naive_vector_column::_update_entry(Index position, ID_index rowIndex, - Index position) + const Field_element& value) { if constexpr (Master_matrix::Option_list::has_row_access) { - Entry* newEntry = entryPool_->construct(RA_opt::get_column_index(), rowIndex); - newEntry->set_element(value); - column_[position] = newEntry; - RA_opt::insert_entry(rowIndex, newEntry); - } else { - column_[position] = entryPool_->construct(rowIndex); - column_[position]->set_element(value); - } -} - -template -inline void Naive_vector_column::_update_entry(ID_index rowIndex, Index position) -{ - if constexpr (Master_matrix::Option_list::has_row_access) { - Entry* newEntry = entryPool_->construct(RA_opt::get_column_index(), rowIndex); - column_[position] = newEntry; - RA_opt::insert_entry(rowIndex, newEntry); + column_[position] = entryPool_->construct(RA_opt::get_column_index(), rowIndex); } else { column_[position] = entryPool_->construct(rowIndex); } + column_[position]->set_element(value); + if constexpr (Master_matrix::Option_list::has_row_access) RA_opt::insert_entry(rowIndex, column_[position]); } template @@ -1000,11 +913,7 @@ inline bool Naive_vector_column::_add(const Entry_range& column_.resize(column.size()); Index i = 0; for (const Entry& entry : column) { - if constexpr (Master_matrix::Option_list::is_z2) { - _update_entry(entry.get_row_index(), i++); - } else { - _update_entry(entry.get_element(), entry.get_row_index(), i++); - } + _update_entry(i++, entry.get_row_index(), entry.get_element()); } return true; } @@ -1018,11 +927,7 @@ inline bool Naive_vector_column::_add(const Entry_range& [&](Entry* entryTarget) { newColumn.push_back(entryTarget); }, [&](typename Entry_range::const_iterator& itSource, [[maybe_unused]] const typename Column_support::iterator& itTarget) { - if constexpr (Master_matrix::Option_list::is_z2) { - _insert_entry(itSource->get_row_index(), newColumn); - } else { - _insert_entry(itSource->get_element(), itSource->get_row_index(), newColumn); - } + _insert_entry(newColumn, itSource->get_row_index(), itSource->get_element()); }, [&](Field_element& targetElement, typename Entry_range::const_iterator& itSource) { if constexpr (!Master_matrix::Option_list::is_z2) @@ -1046,7 +951,7 @@ template inline bool Naive_vector_column::_multiply_target_and_add(const Field_element& val, const Entry_range& column) { - if (val == 0U) { + if (val == Field_operators::get_additive_identity()) { if constexpr (Master_matrix::isNonBasic && !Master_matrix::Option_list::is_of_boundary_type) { throw std::invalid_argument("A chain column should not be multiplied by 0."); // this would not only mess up the base, but also the pivots stored. @@ -1054,49 +959,47 @@ inline bool Naive_vector_column::_multiply_target_and_ad clear(); } } - if (column_.empty()) { // chain should never enter here. - column_.resize(column.size()); - Index i = 0; - for (const Entry& entry : column) { - if constexpr (Master_matrix::Option_list::is_z2) { - _update_entry(entry.get_row_index(), i++); - } else { - _update_entry(entry.get_element(), entry.get_row_index(), i++); - } - } - return true; - } - - Column_support newColumn; - newColumn.reserve(column_.size() + column.size()); // safe upper bound - - auto pivotIsZeroed = _generic_add_to_column( - column, - *this, - [&](Entry* entryTarget) { - operators_->multiply_inplace(entryTarget->get_element(), val); - if constexpr (Master_matrix::Option_list::has_row_access) RA_opt::update_entry(*entryTarget); - newColumn.push_back(entryTarget); - }, - [&](typename Entry_range::const_iterator& itSource, const typename Column_support::iterator& itTarget) { - _insert_entry(itSource->get_element(), itSource->get_row_index(), newColumn); - }, - [&](Field_element& targetElement, typename Entry_range::const_iterator& itSource) { - operators_->multiply_and_add_inplace_front(targetElement, val, itSource->get_element()); - }, - [&](Entry* entryTarget) { newColumn.push_back(entryTarget); }, - [&](typename Column_support::iterator& itTarget) { - while (itTarget != column_.end()) { - operators_->multiply_inplace((*itTarget)->get_element(), val); - if constexpr (Master_matrix::Option_list::has_row_access) RA_opt::update_entry(**itTarget); - newColumn.push_back(*itTarget); - itTarget++; - } - }); - column_.swap(newColumn); + if (column_.empty() || val == Field_operators::get_multiplicative_identity()) { + return _add(column); + } - return pivotIsZeroed; + // multiply_inplace needs a non-const reference to element, so even if Z2 never reaches here, it won't compile + // without the constexpr, as we are not storing a dummy value just for this purpose. + if constexpr (!Master_matrix::Option_list::is_z2) { + Column_support newColumn; + newColumn.reserve(column_.size() + column.size()); // safe upper bound + + auto pivotIsZeroed = _generic_add_to_column( + column, + *this, + [&](Entry* entryTarget) { + operators_->multiply_inplace(entryTarget->get_element(), val); + if constexpr (Master_matrix::Option_list::has_row_access) RA_opt::update_entry(*entryTarget); + newColumn.push_back(entryTarget); + }, + [&](typename Entry_range::const_iterator& itSource, const typename Column_support::iterator& itTarget) { + _insert_entry(newColumn, itSource->get_row_index(), itSource->get_element()); + }, + [&](Field_element& targetElement, typename Entry_range::const_iterator& itSource) { + operators_->multiply_and_add_inplace_front(targetElement, val, itSource->get_element()); + }, + [&](Entry* entryTarget) { newColumn.push_back(entryTarget); }, + [&](typename Column_support::iterator& itTarget) { + while (itTarget != column_.end()) { + operators_->multiply_inplace((*itTarget)->get_element(), val); + if constexpr (Master_matrix::Option_list::has_row_access) RA_opt::update_entry(**itTarget); + newColumn.push_back(*itTarget); + itTarget++; + } + }); + + column_.swap(newColumn); + + return pivotIsZeroed; + } else { + return false; // we should never arrive here, just to suppress the warning + } } template @@ -1104,36 +1007,46 @@ template inline bool Naive_vector_column::_multiply_source_and_add(const Entry_range& column, const Field_element& val) { - if (val == 0U || column.begin() == column.end()) { + if (val == Field_operators::get_additive_identity() || column.begin() == column.end()) { return false; } - Column_support newColumn; - newColumn.reserve(column_.size() + column.size()); // safe upper bound - - auto pivotIsZeroed = _generic_add_to_column( - column, - *this, - [&](Entry* entryTarget) { newColumn.push_back(entryTarget); }, - [&](typename Entry_range::const_iterator& itSource, const typename Column_support::iterator& itTarget) { - Entry* newEntry = _insert_entry(itSource->get_element(), itSource->get_row_index(), newColumn); - operators_->multiply_inplace(newEntry->get_element(), val); - if constexpr (Master_matrix::Option_list::has_row_access) RA_opt::update_entry(*newEntry); - }, - [&](Field_element& targetElement, typename Entry_range::const_iterator& itSource) { - operators_->multiply_and_add_inplace_back(itSource->get_element(), val, targetElement); - }, - [&](Entry* entryTarget) { newColumn.push_back(entryTarget); }, - [&](typename Column_support::iterator& itTarget) { - while (itTarget != column_.end()) { - newColumn.push_back(*itTarget); - itTarget++; - } - }); - - column_.swap(newColumn); + if (val == Field_operators::get_multiplicative_identity()) { + return _add(column); + } - return pivotIsZeroed; + // multiply_inplace needs a non-const reference to element, so even if Z2 never reaches here, it won't compile + // without the constexpr, as we are not storing a dummy value just for this purpose. + if constexpr (!Master_matrix::Option_list::is_z2) { + Column_support newColumn; + newColumn.reserve(column_.size() + column.size()); // safe upper bound + + auto pivotIsZeroed = _generic_add_to_column( + column, + *this, + [&](Entry* entryTarget) { newColumn.push_back(entryTarget); }, + [&](typename Entry_range::const_iterator& itSource, const typename Column_support::iterator& itTarget) { + Entry* newEntry = _insert_entry(newColumn, itSource->get_row_index(), itSource->get_element()); + operators_->multiply_inplace(newEntry->get_element(), val); + if constexpr (Master_matrix::Option_list::has_row_access) RA_opt::update_entry(*newEntry); + }, + [&](Field_element& targetElement, typename Entry_range::const_iterator& itSource) { + operators_->multiply_and_add_inplace_back(itSource->get_element(), val, targetElement); + }, + [&](Entry* entryTarget) { newColumn.push_back(entryTarget); }, + [&](typename Column_support::iterator& itTarget) { + while (itTarget != column_.end()) { + newColumn.push_back(*itTarget); + itTarget++; + } + }); + + column_.swap(newColumn); + + return pivotIsZeroed; + } else { + return false; // we should never arrive here, just to suppress the warning + } } } // namespace persistence_matrix diff --git a/multipers/gudhi/gudhi/Persistence_matrix/columns/set_column.h b/multipers/gudhi/gudhi/Persistence_matrix/columns/set_column.h index 39986ec3..c1b53523 100644 --- a/multipers/gudhi/gudhi/Persistence_matrix/columns/set_column.h +++ b/multipers/gudhi/gudhi/Persistence_matrix/columns/set_column.h @@ -25,6 +25,7 @@ #include //std::swap, std::move & std::exchange #include +#include #include #include @@ -72,6 +73,7 @@ class Set_column : public Master_matrix::Row_access_option, using const_iterator = boost::indirect_iterator; using reverse_iterator = boost::indirect_iterator; using const_reverse_iterator = boost::indirect_iterator; + using Content_range = boost::iterator_range; Set_column(Column_settings* colSettings = nullptr); template @@ -81,14 +83,32 @@ class Set_column : public Master_matrix::Row_access_option, const Container& nonZeroRowIndices, Row_container* rowContainer, Column_settings* colSettings); - template + template > > Set_column(const Container& nonZeroRowIndices, Dimension dimension, Column_settings* colSettings); - template + template > > Set_column(Index columnIndex, const Container& nonZeroRowIndices, Dimension dimension, Row_container* rowContainer, Column_settings* colSettings); + Set_column(ID_index idx, Dimension dimension, Column_settings* colSettings); + Set_column(ID_index idx, Field_element e, Dimension dimension, Column_settings* colSettings); + template + Set_column(Index columnIndex, + ID_index idx, + Dimension dimension, + Row_container* rowContainer, + Column_settings* colSettings); + template + Set_column(Index columnIndex, + ID_index idx, + Field_element e, + Dimension dimension, + Row_container* rowContainer, + Column_settings* colSettings); Set_column(const Set_column& column, Column_settings* colSettings = nullptr); template Set_column(const Set_column& column, @@ -121,11 +141,13 @@ class Set_column : public Master_matrix::Row_access_option, reverse_iterator rend() noexcept; const_reverse_iterator rend() const noexcept; + Content_range get_non_zero_content_range() const; + template Set_column& operator+=(const Entry_range& column); Set_column& operator+=(Set_column& column); - Set_column& operator*=(unsigned int v); + Set_column& operator*=(const Field_element& v); // this = v * this + column template @@ -141,38 +163,32 @@ class Set_column : public Master_matrix::Row_access_option, friend bool operator==(const Set_column& c1, const Set_column& c2) { if (&c1 == &c2) return true; - - auto it1 = c1.column_.begin(); - auto it2 = c2.column_.begin(); if (c1.column_.size() != c2.column_.size()) return false; - while (it1 != c1.column_.end() && it2 != c2.column_.end()) { - if constexpr (Master_matrix::Option_list::is_z2) { - if ((*it1)->get_row_index() != (*it2)->get_row_index()) return false; - } else { - if ((*it1)->get_row_index() != (*it2)->get_row_index() || (*it1)->get_element() != (*it2)->get_element()) - return false; - } - ++it1; - ++it2; - } - return true; + + return std::equal(c1.column_.begin(), + c1.column_.end(), + c2.column_.begin(), + c2.column_.end(), + [](const Entry* e1, const Entry* e2) { + return e1->get_row_index() == e2->get_row_index() && e1->get_element() == e2->get_element(); + }); } friend bool operator<(const Set_column& c1, const Set_column& c2) { if (&c1 == &c2) return false; - auto it1 = c1.column_.begin(); - auto it2 = c2.column_.begin(); - while (it1 != c1.column_.end() && it2 != c2.column_.end()) { - if ((*it1)->get_row_index() != (*it2)->get_row_index()) return (*it1)->get_row_index() < (*it2)->get_row_index(); - if constexpr (!Master_matrix::Option_list::is_z2) { - if ((*it1)->get_element() != (*it2)->get_element()) return (*it1)->get_element() < (*it2)->get_element(); - } - ++it1; - ++it2; - } - return it2 != c2.column_.end(); + return std::lexicographical_compare(c1.column_.begin(), + c1.column_.end(), + c2.column_.begin(), + c2.column_.end(), + [](const Entry* e1, const Entry* e2) { + if (e1->get_row_index() != e2->get_row_index()) + return e1->get_row_index() < e2->get_row_index(); + if (e1->get_element() != e2->get_element()) + return e1->get_element() < e2->get_element(); + return false; + }); } // Disabled with row access. @@ -198,7 +214,7 @@ class Set_column : public Master_matrix::Row_access_option, using Chain_opt = typename Master_matrix::Chain_column_option; Column_support column_; - Field_operators* operators_; + Field_operators const* operators_; Entry_constructor* entryPool_; template @@ -230,10 +246,9 @@ class Set_column : public Master_matrix::Row_access_option, Column& targetColumn); void _delete_entry(typename Column_support::iterator& it); - Entry* _insert_entry(const Field_element& value, + Entry* _insert_entry(const typename Column_support::iterator& position, ID_index rowIndex, - const typename Column_support::iterator& position); - void _insert_entry(ID_index rowIndex, const typename Column_support::iterator& position); + const Field_element& value); template bool _add(const Entry_range& column); template @@ -247,38 +262,17 @@ inline Set_column::Set_column(Column_settings* colSettings) : RA_opt(), Dim_opt(), Chain_opt(), - operators_(nullptr), + operators_(Master_matrix::get_operator_ptr(colSettings)), entryPool_(colSettings == nullptr ? nullptr : &(colSettings->entryConstructor)) -{ - if (operators_ == nullptr && entryPool_ == nullptr) - return; // to allow default constructor which gives a dummy column - if constexpr (!Master_matrix::Option_list::is_z2) { - operators_ = &(colSettings->operators); - } -} +{} template template inline Set_column::Set_column(const Container& nonZeroRowIndices, Column_settings* colSettings) - : RA_opt(), - Dim_opt(nonZeroRowIndices.size() == 0 ? 0 : nonZeroRowIndices.size() - 1), - Chain_opt(), - operators_(nullptr), - entryPool_(&(colSettings->entryConstructor)) + : Set_column(nonZeroRowIndices, nonZeroRowIndices.size() == 0 ? 0 : nonZeroRowIndices.size() - 1, colSettings) { static_assert(!Master_matrix::isNonBasic || Master_matrix::Option_list::is_of_boundary_type, "Constructor not available for chain columns, please specify the dimension of the chain."); - - if constexpr (Master_matrix::Option_list::is_z2) { - for (ID_index id : nonZeroRowIndices) { - _insert_entry(id, column_.end()); - } - } else { - operators_ = &(colSettings->operators); - for (const auto& p : nonZeroRowIndices) { - _insert_entry(operators_->get_value(p.second), p.first, column_.end()); - } - } } template @@ -287,72 +281,38 @@ inline Set_column::Set_column(Index columnIndex, const Container& nonZeroRowIndices, Row_container* rowContainer, Column_settings* colSettings) - : RA_opt(columnIndex, rowContainer), - Dim_opt(nonZeroRowIndices.size() == 0 ? 0 : nonZeroRowIndices.size() - 1), - Chain_opt([&] { - if constexpr (Master_matrix::Option_list::is_z2) { - return nonZeroRowIndices.begin() == nonZeroRowIndices.end() - ? Master_matrix::template get_null_value() - : *std::prev(nonZeroRowIndices.end()); - } else { - return nonZeroRowIndices.begin() == nonZeroRowIndices.end() - ? Master_matrix::template get_null_value() - : std::prev(nonZeroRowIndices.end())->first; - } - }()), - operators_(nullptr), - entryPool_(&(colSettings->entryConstructor)) + : Set_column(columnIndex, + nonZeroRowIndices, + nonZeroRowIndices.size() == 0 ? 0 : nonZeroRowIndices.size() - 1, + rowContainer, + colSettings) { static_assert(!Master_matrix::isNonBasic || Master_matrix::Option_list::is_of_boundary_type, "Constructor not available for chain columns, please specify the dimension of the chain."); - - if constexpr (Master_matrix::Option_list::is_z2) { - for (ID_index id : nonZeroRowIndices) { - _insert_entry(id, column_.end()); - } - } else { - operators_ = &(colSettings->operators); - for (const auto& p : nonZeroRowIndices) { - _insert_entry(operators_->get_value(p.second), p.first, column_.end()); - } - } } template -template +template inline Set_column::Set_column(const Container& nonZeroRowIndices, Dimension dimension, Column_settings* colSettings) : RA_opt(), Dim_opt(dimension), - Chain_opt([&] { - if constexpr (Master_matrix::Option_list::is_z2) { - return nonZeroRowIndices.begin() == nonZeroRowIndices.end() - ? Master_matrix::template get_null_value() - : *std::prev(nonZeroRowIndices.end()); - } else { - return nonZeroRowIndices.begin() == nonZeroRowIndices.end() - ? Master_matrix::template get_null_value() - : std::prev(nonZeroRowIndices.end())->first; - } - }()), - operators_(nullptr), + Chain_opt(nonZeroRowIndices.begin() == nonZeroRowIndices.end() + ? Master_matrix::template get_null_value() + : Master_matrix::get_row_index(*std::prev(nonZeroRowIndices.end()))), + operators_(Master_matrix::get_operator_ptr(colSettings)), entryPool_(&(colSettings->entryConstructor)) { - if constexpr (Master_matrix::Option_list::is_z2) { - for (ID_index id : nonZeroRowIndices) { - _insert_entry(id, column_.end()); - } - } else { - operators_ = &(colSettings->operators); - for (const auto& p : nonZeroRowIndices) { - _insert_entry(operators_->get_value(p.second), p.first, column_.end()); - } + for (const auto& id : nonZeroRowIndices) { + _insert_entry(column_.end(), + Master_matrix::get_row_index(id), + Master_matrix::get_coefficient_value(Master_matrix::get_element(id), operators_)); } } template -template +template inline Set_column::Set_column(Index columnIndex, const Container& nonZeroRowIndices, Dimension dimension, @@ -360,54 +320,95 @@ inline Set_column::Set_column(Index columnIndex, Column_settings* colSettings) : RA_opt(columnIndex, rowContainer), Dim_opt(dimension), - Chain_opt([&] { - if constexpr (Master_matrix::Option_list::is_z2) { - return nonZeroRowIndices.begin() == nonZeroRowIndices.end() - ? Master_matrix::template get_null_value() - : *std::prev(nonZeroRowIndices.end()); - } else { - return nonZeroRowIndices.begin() == nonZeroRowIndices.end() - ? Master_matrix::template get_null_value() - : std::prev(nonZeroRowIndices.end())->first; - } - }()), - operators_(nullptr), + Chain_opt(nonZeroRowIndices.begin() == nonZeroRowIndices.end() + ? Master_matrix::template get_null_value() + : Master_matrix::get_row_index(*std::prev(nonZeroRowIndices.end()))), + operators_(Master_matrix::get_operator_ptr(colSettings)), entryPool_(&(colSettings->entryConstructor)) { - if constexpr (Master_matrix::Option_list::is_z2) { - for (ID_index id : nonZeroRowIndices) { - _insert_entry(id, column_.end()); - } - } else { - operators_ = &(colSettings->operators); - for (const auto& p : nonZeroRowIndices) { - _insert_entry(operators_->get_value(p.second), p.first, column_.end()); - } + for (const auto& id : nonZeroRowIndices) { + _insert_entry(column_.end(), + Master_matrix::get_row_index(id), + Master_matrix::get_coefficient_value(Master_matrix::get_element(id), operators_)); } } +template +inline Set_column::Set_column(ID_index idx, Dimension dimension, Column_settings* colSettings) + : RA_opt(), Dim_opt(dimension), Chain_opt(idx), operators_(nullptr), entryPool_(&(colSettings->entryConstructor)) +{ + static_assert(Master_matrix::Option_list::is_z2, + "Constructor not available for Zp != Z2. Please specify the coefficient."); + _insert_entry(column_.end(), idx, 1); +} + +template +inline Set_column::Set_column(ID_index idx, + Field_element e, + Dimension dimension, + Column_settings* colSettings) + : RA_opt(), + Dim_opt(dimension), + Chain_opt(idx), + operators_(&(colSettings->operators)), + entryPool_(&(colSettings->entryConstructor)) +{ + static_assert(!Master_matrix::Option_list::is_z2, + "Constructor not available for Zp == Z2. Please do not specify any coefficient."); + _insert_entry(column_.end(), idx, operators_->get_value(e)); +} + +template +template +inline Set_column::Set_column(Index columnIndex, + ID_index idx, + Dimension dimension, + Row_container* rowContainer, + Column_settings* colSettings) + : RA_opt(columnIndex, rowContainer), + Dim_opt(dimension), + Chain_opt(idx), + operators_(nullptr), + entryPool_(&(colSettings->entryConstructor)) +{ + static_assert(Master_matrix::Option_list::is_z2, + "Constructor not available for Zp != Z2. Please specify the coefficient."); + _insert_entry(column_.end(), idx, 1); +} + +template +template +inline Set_column::Set_column(Index columnIndex, + ID_index idx, + Field_element e, + Dimension dimension, + Row_container* rowContainer, + Column_settings* colSettings) + : RA_opt(columnIndex, rowContainer), + Dim_opt(dimension), + Chain_opt(idx), + operators_(&(colSettings->operators)), + entryPool_(&(colSettings->entryConstructor)) +{ + static_assert(!Master_matrix::Option_list::is_z2, + "Constructor not available for Zp == Z2. Please do not specify any coefficient."); + _insert_entry(column_.end(), idx, operators_->get_value(e)); +} + template inline Set_column::Set_column(const Set_column& column, Column_settings* colSettings) : RA_opt(), Dim_opt(static_cast(column)), Chain_opt(static_cast(column)), - operators_(colSettings == nullptr ? column.operators_ : nullptr), + operators_(colSettings == nullptr ? column.operators_ : Master_matrix::get_operator_ptr(colSettings)), entryPool_(colSettings == nullptr ? column.entryPool_ : &(colSettings->entryConstructor)) { static_assert(!Master_matrix::Option_list::has_row_access, "Simple copy constructor not available when row access option enabled. Please specify the new column " "index and the row container."); - if constexpr (!Master_matrix::Option_list::is_z2) { - if (colSettings != nullptr) operators_ = &(colSettings->operators); - } - for (const Entry* entry : column.column_) { - if constexpr (Master_matrix::Option_list::is_z2) { - _insert_entry(entry->get_row_index(), column_.end()); - } else { - _insert_entry(entry->get_element(), entry->get_row_index(), column_.end()); - } + _insert_entry(column_.end(), entry->get_row_index(), entry->get_element()); } } @@ -420,19 +421,11 @@ inline Set_column::Set_column(const Set_column& column, : RA_opt(columnIndex, rowContainer), Dim_opt(static_cast(column)), Chain_opt(static_cast(column)), - operators_(colSettings == nullptr ? column.operators_ : nullptr), + operators_(colSettings == nullptr ? column.operators_ : Master_matrix::get_operator_ptr(colSettings)), entryPool_(colSettings == nullptr ? column.entryPool_ : &(colSettings->entryConstructor)) { - if constexpr (!Master_matrix::Option_list::is_z2) { - if (colSettings != nullptr) operators_ = &(colSettings->operators); - } - for (const Entry* entry : column.column_) { - if constexpr (Master_matrix::Option_list::is_z2) { - _insert_entry(entry->get_row_index(), column_.end()); - } else { - _insert_entry(entry->get_element(), entry->get_row_index(), column_.end()); - } + _insert_entry(column_.end(), entry->get_row_index(), entry->get_element()); } } @@ -468,11 +461,7 @@ inline std::vector::Field_element> Set_column std::vector container(columnLength, 0); for (auto it = column_.begin(); it != column_.end() && (*it)->get_row_index() < static_cast(columnLength); ++it) { - if constexpr (Master_matrix::Option_list::is_z2) { - container[(*it)->get_row_index()] = 1; - } else { - container[(*it)->get_row_index()] = (*it)->get_element(); - } + container[(*it)->get_row_index()] = Master_matrix::get_element(**it); } return container; } @@ -639,6 +628,12 @@ inline typename Set_column::const_reverse_iterator Set_column +inline typename Set_column::Content_range Set_column::get_non_zero_content_range() const +{ + return Content_range(column_.begin(), column_.end()); +} + template template inline Set_column& Set_column::operator+=(const Entry_range& column) @@ -671,30 +666,24 @@ inline Set_column& Set_column::operator+=(Set_colu } template -inline Set_column& Set_column::operator*=(unsigned int v) +inline Set_column& Set_column::operator*=(const Field_element& v) { - if constexpr (Master_matrix::Option_list::is_z2) { - if (v % 2 == 0) { - if constexpr (Master_matrix::isNonBasic && !Master_matrix::Option_list::is_of_boundary_type) { - throw std::invalid_argument("A chain column should not be multiplied by 0."); - } else { - clear(); - } - } - } else { - Field_element val = operators_->get_value(v); + Field_element val = Master_matrix::get_coefficient_value(v, operators_); - if (val == Field_operators::get_additive_identity()) { - if constexpr (Master_matrix::isNonBasic && !Master_matrix::Option_list::is_of_boundary_type) { - throw std::invalid_argument("A chain column should not be multiplied by 0."); - } else { - clear(); - } - return *this; + if (val == Field_operators::get_additive_identity()) { + if constexpr (Master_matrix::isNonBasic && !Master_matrix::Option_list::is_of_boundary_type) { + throw std::invalid_argument("A chain column should not be multiplied by 0."); + } else { + clear(); } + return *this; + } - if (val == Field_operators::get_multiplicative_identity()) return *this; + if (val == Field_operators::get_multiplicative_identity()) return *this; + // multiply_inplace needs a non-const reference to element, so even if Z2 never reaches here, it won't compile + // without the constexpr, as we are not storing a dummy value just for this purpose. + if constexpr (!Master_matrix::Option_list::is_z2) { for (Entry* entry : column_) { operators_->multiply_inplace(entry->get_element(), val); if constexpr (Master_matrix::Option_list::has_row_access) RA_opt::update_entry(*entry); @@ -715,16 +704,7 @@ inline Set_column& Set_column::multiply_target_and static_assert((!Master_matrix::isNonBasic || Master_matrix::Option_list::is_of_boundary_type), "For chain columns, the given column cannot be constant."); - if constexpr (Master_matrix::Option_list::is_z2) { - if (val) { - _add(column); - } else { - clear(); - _add(column); - } - } else { - _multiply_target_and_add(val, column); - } + _multiply_target_and_add(Master_matrix::get_coefficient_value(val, operators_), column); return *this; } @@ -735,32 +715,12 @@ inline Set_column& Set_column::multiply_target_and { if constexpr (Master_matrix::isNonBasic && !Master_matrix::Option_list::is_of_boundary_type) { // assumes that the addition never zeros out this column. - if constexpr (Master_matrix::Option_list::is_z2) { - if (val) { - if (_add(column)) { - Chain_opt::_swap_pivots(column); - Dim_opt::_swap_dimension(column); - } - } else { - throw std::invalid_argument("A chain column should not be multiplied by 0."); - } - } else { - if (_multiply_target_and_add(val, column)) { - Chain_opt::_swap_pivots(column); - Dim_opt::_swap_dimension(column); - } + if (_multiply_target_and_add(Master_matrix::get_coefficient_value(val, operators_), column)) { + Chain_opt::_swap_pivots(column); + Dim_opt::_swap_dimension(column); } } else { - if constexpr (Master_matrix::Option_list::is_z2) { - if (val) { - _add(column); - } else { - clear(); - _add(column); - } - } else { - _multiply_target_and_add(val, column); - } + _multiply_target_and_add(Master_matrix::get_coefficient_value(val, operators_), column); } return *this; @@ -777,13 +737,7 @@ inline Set_column& Set_column::multiply_source_and static_assert((!Master_matrix::isNonBasic || Master_matrix::Option_list::is_of_boundary_type), "For chain columns, the given column cannot be constant."); - if constexpr (Master_matrix::Option_list::is_z2) { - if (val) { - _add(column); - } - } else { - _multiply_source_and_add(column, val); - } + _multiply_source_and_add(column, Master_matrix::get_coefficient_value(val, operators_)); return *this; } @@ -794,27 +748,12 @@ inline Set_column& Set_column::multiply_source_and { if constexpr (Master_matrix::isNonBasic && !Master_matrix::Option_list::is_of_boundary_type) { // assumes that the addition never zeros out this column. - if constexpr (Master_matrix::Option_list::is_z2) { - if (val) { - if (_add(column)) { - Chain_opt::_swap_pivots(column); - Dim_opt::_swap_dimension(column); - } - } - } else { - if (_multiply_source_and_add(column, val)) { - Chain_opt::_swap_pivots(column); - Dim_opt::_swap_dimension(column); - } + if (_multiply_source_and_add(column, Master_matrix::get_coefficient_value(val, operators_))) { + Chain_opt::_swap_pivots(column); + Dim_opt::_swap_dimension(column); } } else { - if constexpr (Master_matrix::Option_list::is_z2) { - if (val) { - _add(column); - } - } else { - _multiply_source_and_add(column, val); - } + _multiply_source_and_add(column, Master_matrix::get_coefficient_value(val, operators_)); } return *this; @@ -827,11 +766,7 @@ inline void Set_column::push_back(const Entry& entry) GUDHI_CHECK(entry.get_row_index() > get_pivot(), "The new row index has to be higher than the current pivot."); - if constexpr (Master_matrix::Option_list::is_z2) { - _insert_entry(entry.get_row_index(), column_.end()); - } else { - _insert_entry(entry.get_element(), entry.get_row_index(), column_.end()); - } + _insert_entry(column_.end(), entry.get_row_index(), entry.get_element()); } template @@ -854,11 +789,7 @@ inline Set_column& Set_column::operator=(const Set operators_ = other.operators_; for (const Entry* entry : other.column_) { - if constexpr (Master_matrix::Option_list::is_z2) { - _insert_entry(entry->get_row_index(), column_.end()); - } else { - _insert_entry(entry->get_element(), entry->get_row_index(), column_.end()); - } + _insert_entry(column_.end(), entry->get_row_index(), entry->get_element()); } return *this; @@ -896,36 +827,20 @@ inline void Set_column::_delete_entry(typename Column_support::it template inline typename Set_column::Entry* Set_column::_insert_entry( - const Field_element& value, + const typename Column_support::iterator& position, ID_index rowIndex, - const typename Column_support::iterator& position) -{ - if constexpr (Master_matrix::Option_list::has_row_access) { - Entry* newEntry = entryPool_->construct(RA_opt::get_column_index(), rowIndex); - newEntry->set_element(value); - column_.insert(position, newEntry); - RA_opt::insert_entry(rowIndex, newEntry); - return newEntry; - } else { - Entry* newEntry = entryPool_->construct(rowIndex); - newEntry->set_element(value); - column_.insert(position, newEntry); - return newEntry; - } -} - -template -inline void Set_column::_insert_entry(ID_index rowIndex, - const typename Column_support::iterator& position) + const Field_element& value) { + Entry* newEntry; if constexpr (Master_matrix::Option_list::has_row_access) { - Entry* newEntry = entryPool_->construct(RA_opt::get_column_index(), rowIndex); - column_.insert(position, newEntry); - RA_opt::insert_entry(rowIndex, newEntry); + newEntry = entryPool_->construct(RA_opt::get_column_index(), rowIndex); } else { - Entry* newEntry = entryPool_->construct(rowIndex); - column_.insert(position, newEntry); + newEntry = entryPool_->construct(rowIndex); } + newEntry->set_element(value); + column_.insert(position, newEntry); + if constexpr (Master_matrix::Option_list::has_row_access) RA_opt::insert_entry(rowIndex, newEntry); + return newEntry; } template diff --git a/multipers/gudhi/gudhi/Persistence_matrix/columns/unordered_set_column.h b/multipers/gudhi/gudhi/Persistence_matrix/columns/unordered_set_column.h index b48c76a5..16997317 100644 --- a/multipers/gudhi/gudhi/Persistence_matrix/columns/unordered_set_column.h +++ b/multipers/gudhi/gudhi/Persistence_matrix/columns/unordered_set_column.h @@ -18,11 +18,12 @@ #ifndef PM_UNORDERED_SET_COLUMN_H #define PM_UNORDERED_SET_COLUMN_H -#include #include #include +#include // std::lexicographical_compare +#include //std::swap, std::move & std::exchange #include -#include //std::swap, std::move & std::exchange +#include #include #if BOOST_VERSION >= 108100 @@ -91,6 +92,7 @@ class Unordered_set_column : public Master_matrix::Row_access_option, public: using iterator = boost::indirect_iterator; using const_iterator = boost::indirect_iterator; + using Content_range = std::vector; Unordered_set_column(Column_settings* colSettings = nullptr); template @@ -100,14 +102,35 @@ class Unordered_set_column : public Master_matrix::Row_access_option, const Container& nonZeroRowIndices, Row_container* rowContainer, Column_settings* colSettings); - template + template >> Unordered_set_column(const Container& nonZeroRowIndices, Dimension dimension, Column_settings* colSettings); - template + template >> Unordered_set_column(Index columnIndex, const Container& nonZeroRowIndices, Dimension dimension, Row_container* rowContainer, Column_settings* colSettings); + Unordered_set_column(ID_index idx, Dimension dimension, Column_settings* colSettings); + Unordered_set_column(ID_index idx, + Field_element e, + Dimension dimension, + Column_settings* colSettings); + template + Unordered_set_column(Index columnIndex, + ID_index idx, + Dimension dimension, + Row_container* rowContainer, + Column_settings* colSettings); + template + Unordered_set_column(Index columnIndex, + ID_index idx, + Field_element e, + Dimension dimension, + Row_container* rowContainer, + Column_settings* colSettings); Unordered_set_column(const Unordered_set_column& column, Column_settings* colSettings = nullptr); template Unordered_set_column(const Unordered_set_column& column, @@ -136,11 +159,13 @@ class Unordered_set_column : public Master_matrix::Row_access_option, iterator end() noexcept; const_iterator end() const noexcept; + Content_range get_non_zero_content_range() const; + template Unordered_set_column& operator+=(const Entry_range& column); Unordered_set_column& operator+=(Unordered_set_column& column); - Unordered_set_column& operator*=(unsigned int v); + Unordered_set_column& operator*=(const Field_element& v); // this = v * this + column template @@ -161,8 +186,7 @@ class Unordered_set_column : public Master_matrix::Row_access_option, for (Entry* entry : c1.column_) { auto it = c2.column_.find(entry); if (it == c2.column_.end()) return false; - if constexpr (!Master_matrix::Option_list::is_z2) - if ((*it)->get_element() != entry->get_element()) return false; + if (Master_matrix::get_element(**it) != Master_matrix::get_element(*entry)) return false; } return true; } @@ -171,41 +195,23 @@ class Unordered_set_column : public Master_matrix::Row_access_option, { if (&c1 == &c2) return false; - using ID_index = Unordered_set_column::ID_index; - using Entry_rep = - std::conditional_t>; + auto comp = [](const Entry* n1, const Entry* n2) -> bool { + Index r1 = Master_matrix::get_row_index(*n1); + Index r2 = Master_matrix::get_row_index(*n2); + Field_element e1 = Master_matrix::get_element(*n1); + Field_element e2 = Master_matrix::get_element(*n2); - auto it1 = c1.column_.begin(); - auto it2 = c2.column_.begin(); - std::set entries1, entries2; - while (it1 != c1.column_.end() && it2 != c2.column_.end()) { - if constexpr (Master_matrix::Option_list::is_z2) { - entries1.insert((*it1)->get_row_index()); - entries2.insert((*it2)->get_row_index()); - } else { - entries1.emplace((*it1)->get_row_index(), (*it1)->get_element()); - entries2.emplace((*it2)->get_row_index(), (*it2)->get_element()); - } - ++it1; - ++it2; - } - while (it1 != c1.column_.end()) { - if constexpr (Master_matrix::Option_list::is_z2) { - entries1.insert((*it1)->get_row_index()); - } else { - entries1.emplace((*it1)->get_row_index(), (*it1)->get_element()); - } - ++it1; - } - while (it2 != c2.column_.end()) { - if constexpr (Master_matrix::Option_list::is_z2) { - entries2.insert((*it2)->get_row_index()); - } else { - entries2.emplace((*it2)->get_row_index(), (*it2)->get_element()); - } - ++it2; - } - return entries1 < entries2; + if (r1 != r2) return r1 < r2; + if (e1 != e2) return e1 < e2; + + return false; + }; + + std::set entries1(comp), entries2(comp); + entries1.insert(c1.column_.begin(), c1.column_.end()); + entries2.insert(c2.column_.begin(), c2.column_.end()); + + return std::lexicographical_compare(entries1.begin(), entries1.end(), entries2.begin(), entries2.end(), comp); } // Disabled with row access. @@ -231,12 +237,11 @@ class Unordered_set_column : public Master_matrix::Row_access_option, using Chain_opt = typename Master_matrix::Chain_column_option; Column_support column_; - Field_operators* operators_; + Field_operators const* operators_; Entry_constructor* entryPool_; void _delete_entry(typename Column_support::iterator& it); - Entry* _insert_entry(const Field_element& value, ID_index rowIndex); - void _insert_entry(ID_index rowIndex); + Entry* _insert_entry(ID_index rowIndex, const Field_element& value); template bool _add(const Entry_range& column); template @@ -252,40 +257,20 @@ inline Unordered_set_column::Unordered_set_column(Column_settings : RA_opt(), Dim_opt(), Chain_opt(), - operators_(nullptr), + operators_(Master_matrix::get_operator_ptr(colSettings)), entryPool_(colSettings == nullptr ? nullptr : &(colSettings->entryConstructor)) -{ - if (operators_ == nullptr && entryPool_ == nullptr) - return; // to allow default constructor which gives a dummy column - if constexpr (!Master_matrix::Option_list::is_z2) { - operators_ = &(colSettings->operators); - } -} +{} template template inline Unordered_set_column::Unordered_set_column(const Container& nonZeroRowIndices, Column_settings* colSettings) - : RA_opt(), - Dim_opt(nonZeroRowIndices.size() == 0 ? 0 : nonZeroRowIndices.size() - 1), - Chain_opt(), - column_(nonZeroRowIndices.size()), - operators_(nullptr), - entryPool_(&(colSettings->entryConstructor)) + : Unordered_set_column(nonZeroRowIndices, + nonZeroRowIndices.size() == 0 ? 0 : nonZeroRowIndices.size() - 1, + colSettings) { static_assert(!Master_matrix::isNonBasic || Master_matrix::Option_list::is_of_boundary_type, "Constructor not available for chain columns, please specify the dimension of the chain."); - - if constexpr (Master_matrix::Option_list::is_z2) { - for (ID_index id : nonZeroRowIndices) { - _insert_entry(id); - } - } else { - operators_ = &(colSettings->operators); - for (const auto& p : nonZeroRowIndices) { - _insert_entry(operators_->get_value(p.second), p.first); - } - } } template @@ -294,74 +279,38 @@ inline Unordered_set_column::Unordered_set_column(Index columnInd const Container& nonZeroRowIndices, Row_container* rowContainer, Column_settings* colSettings) - : RA_opt(columnIndex, rowContainer), - Dim_opt(nonZeroRowIndices.size() == 0 ? 0 : nonZeroRowIndices.size() - 1), - Chain_opt([&] { - if constexpr (Master_matrix::Option_list::is_z2) { - return nonZeroRowIndices.begin() == nonZeroRowIndices.end() - ? Master_matrix::template get_null_value() - : *std::prev(nonZeroRowIndices.end()); - } else { - return nonZeroRowIndices.begin() == nonZeroRowIndices.end() - ? Master_matrix::template get_null_value() - : std::prev(nonZeroRowIndices.end())->first; - } - }()), - column_(nonZeroRowIndices.size()), - operators_(nullptr), - entryPool_(&(colSettings->entryConstructor)) + : Unordered_set_column(columnIndex, + nonZeroRowIndices, + nonZeroRowIndices.size() == 0 ? 0 : nonZeroRowIndices.size() - 1, + rowContainer, + colSettings) { static_assert(!Master_matrix::isNonBasic || Master_matrix::Option_list::is_of_boundary_type, "Constructor not available for chain columns, please specify the dimension of the chain."); - - if constexpr (Master_matrix::Option_list::is_z2) { - for (ID_index id : nonZeroRowIndices) { - _insert_entry(id); - } - } else { - operators_ = &(colSettings->operators); - for (const auto& p : nonZeroRowIndices) { - _insert_entry(operators_->get_value(p.second), p.first); - } - } } template -template +template inline Unordered_set_column::Unordered_set_column(const Container& nonZeroRowIndices, Dimension dimension, Column_settings* colSettings) : RA_opt(), Dim_opt(dimension), - Chain_opt([&] { - if constexpr (Master_matrix::Option_list::is_z2) { - return nonZeroRowIndices.begin() == nonZeroRowIndices.end() - ? Master_matrix::template get_null_value() - : *std::prev(nonZeroRowIndices.end()); - } else { - return nonZeroRowIndices.begin() == nonZeroRowIndices.end() - ? Master_matrix::template get_null_value() - : std::prev(nonZeroRowIndices.end())->first; - } - }()), + Chain_opt(nonZeroRowIndices.begin() == nonZeroRowIndices.end() + ? Master_matrix::template get_null_value() + : Master_matrix::get_row_index(*std::prev(nonZeroRowIndices.end()))), column_(nonZeroRowIndices.size()), - operators_(nullptr), + operators_(Master_matrix::get_operator_ptr(colSettings)), entryPool_(&(colSettings->entryConstructor)) { - if constexpr (Master_matrix::Option_list::is_z2) { - for (ID_index id : nonZeroRowIndices) { - _insert_entry(id); - } - } else { - operators_ = &(colSettings->operators); - for (const auto& p : nonZeroRowIndices) { - _insert_entry(operators_->get_value(p.second), p.first); - } + for (const auto& id : nonZeroRowIndices) { + _insert_entry(Master_matrix::get_row_index(id), + Master_matrix::get_coefficient_value(Master_matrix::get_element(id), operators_)); } } template -template +template inline Unordered_set_column::Unordered_set_column(Index columnIndex, const Container& nonZeroRowIndices, Dimension dimension, @@ -369,33 +318,91 @@ inline Unordered_set_column::Unordered_set_column(Index columnInd Column_settings* colSettings) : RA_opt(columnIndex, rowContainer), Dim_opt(dimension), - Chain_opt([&] { - if constexpr (Master_matrix::Option_list::is_z2) { - return nonZeroRowIndices.begin() == nonZeroRowIndices.end() - ? Master_matrix::template get_null_value() - : *std::prev(nonZeroRowIndices.end()); - } else { - return nonZeroRowIndices.begin() == nonZeroRowIndices.end() - ? Master_matrix::template get_null_value() - : std::prev(nonZeroRowIndices.end())->first; - } - }()), + Chain_opt(nonZeroRowIndices.begin() == nonZeroRowIndices.end() + ? Master_matrix::template get_null_value() + : Master_matrix::get_row_index(*std::prev(nonZeroRowIndices.end()))), column_(nonZeroRowIndices.size()), - operators_(nullptr), + operators_(Master_matrix::get_operator_ptr(colSettings)), entryPool_(&(colSettings->entryConstructor)) { - if constexpr (Master_matrix::Option_list::is_z2) { - for (ID_index id : nonZeroRowIndices) { - _insert_entry(id); - } - } else { - operators_ = &(colSettings->operators); - for (const auto& p : nonZeroRowIndices) { - _insert_entry(operators_->get_value(p.second), p.first); - } + for (const auto& id : nonZeroRowIndices) { + _insert_entry(Master_matrix::get_row_index(id), + Master_matrix::get_coefficient_value(Master_matrix::get_element(id), operators_)); } } +template +inline Unordered_set_column::Unordered_set_column(ID_index idx, + Dimension dimension, + Column_settings* colSettings) + : RA_opt(), + Dim_opt(dimension), + Chain_opt(idx), + column_(1), + operators_(nullptr), + entryPool_(&(colSettings->entryConstructor)) +{ + static_assert(Master_matrix::Option_list::is_z2, + "Constructor not available for Zp != Z2. Please specify the coefficient."); + _insert_entry(idx, 1); +} + +template +inline Unordered_set_column::Unordered_set_column(ID_index idx, + Field_element e, + Dimension dimension, + Column_settings* colSettings) + : RA_opt(), + Dim_opt(dimension), + Chain_opt(idx), + column_(1), + operators_(&(colSettings->operators)), + entryPool_(&(colSettings->entryConstructor)) +{ + static_assert(!Master_matrix::Option_list::is_z2, + "Constructor not available for Zp == Z2. Please do not specify any coefficient."); + _insert_entry(idx, operators_->get_value(e)); +} + +template +template +inline Unordered_set_column::Unordered_set_column(Index columnIndex, + ID_index idx, + Dimension dimension, + Row_container* rowContainer, + Column_settings* colSettings) + : RA_opt(columnIndex, rowContainer), + Dim_opt(dimension), + Chain_opt(idx), + column_(1), + operators_(nullptr), + entryPool_(&(colSettings->entryConstructor)) +{ + static_assert(Master_matrix::Option_list::is_z2, + "Constructor not available for Zp != Z2. Please specify the coefficient."); + _insert_entry(idx, 1); +} + +template +template +inline Unordered_set_column::Unordered_set_column(Index columnIndex, + ID_index idx, + Field_element e, + Dimension dimension, + Row_container* rowContainer, + Column_settings* colSettings) + : RA_opt(columnIndex, rowContainer), + Dim_opt(dimension), + Chain_opt(idx), + column_(1), + operators_(&(colSettings->operators)), + entryPool_(&(colSettings->entryConstructor)) +{ + static_assert(!Master_matrix::Option_list::is_z2, + "Constructor not available for Zp == Z2. Please do not specify any coefficient."); + _insert_entry(idx, operators_->get_value(e)); +} + template inline Unordered_set_column::Unordered_set_column(const Unordered_set_column& column, Column_settings* colSettings) @@ -403,23 +410,15 @@ inline Unordered_set_column::Unordered_set_column(const Unordered Dim_opt(static_cast(column)), Chain_opt(static_cast(column)), column_(column.column_.bucket_count()), - operators_(colSettings == nullptr ? column.operators_ : nullptr), + operators_(colSettings == nullptr ? column.operators_ : Master_matrix::get_operator_ptr(colSettings)), entryPool_(colSettings == nullptr ? column.entryPool_ : &(colSettings->entryConstructor)) { static_assert(!Master_matrix::Option_list::has_row_access, "Simple copy constructor not available when row access option enabled. Please specify the new column " "index and the row container."); - if constexpr (!Master_matrix::Option_list::is_z2) { - if (colSettings != nullptr) operators_ = &(colSettings->operators); - } - for (const Entry* entry : column.column_) { - if constexpr (Master_matrix::Option_list::is_z2) { - _insert_entry(entry->get_row_index()); - } else { - _insert_entry(entry->get_element(), entry->get_row_index()); - } + _insert_entry(entry->get_row_index(), entry->get_element()); } } @@ -433,19 +432,11 @@ inline Unordered_set_column::Unordered_set_column(const Unordered Dim_opt(static_cast(column)), Chain_opt(static_cast(column)), column_(column.column_.bucket_count()), - operators_(colSettings == nullptr ? column.operators_ : nullptr), + operators_(colSettings == nullptr ? column.operators_ : Master_matrix::get_operator_ptr(colSettings)), entryPool_(colSettings == nullptr ? column.entryPool_ : &(colSettings->entryConstructor)) { - if constexpr (!Master_matrix::Option_list::is_z2) { - if (colSettings != nullptr) operators_ = &(colSettings->operators); - } - for (const Entry* entry : column.column_) { - if constexpr (Master_matrix::Option_list::is_z2) { - _insert_entry(entry->get_row_index()); - } else { - _insert_entry(entry->get_element(), entry->get_row_index()); - } + _insert_entry(entry->get_row_index(), entry->get_element()); } } @@ -457,8 +448,7 @@ inline Unordered_set_column::Unordered_set_column(Unordered_set_c column_(std::move(column.column_)), operators_(std::exchange(column.operators_, nullptr)), entryPool_(std::exchange(column.entryPool_, nullptr)) -{ -} +{} template inline Unordered_set_column::~Unordered_set_column() @@ -481,11 +471,7 @@ Unordered_set_column::get_content(int columnLength) const std::vector container(columnLength, 0); for (auto it = column_.begin(); it != column_.end(); ++it) { if ((*it)->get_row_index() < static_cast(columnLength)) { - if constexpr (Master_matrix::Option_list::is_z2) { - container[(*it)->get_row_index()] = 1; - } else { - container[(*it)->get_row_index()] = (*it)->get_element(); - } + container[(*it)->get_row_index()] = Master_matrix::get_element(**it); } } return container; @@ -635,6 +621,17 @@ inline typename Unordered_set_column::const_iterator Unordered_se return column_.end(); } +template +inline typename Unordered_set_column::Content_range +Unordered_set_column::get_non_zero_content_range() const +{ + Content_range res(column_.size()); + std::size_t i = 0; + for (const auto& entry : column_) res[i++] = *entry; + std::sort(res.begin(), res.end()); + return res; +} + template template inline Unordered_set_column& Unordered_set_column::operator+=(const Entry_range& column) @@ -668,30 +665,24 @@ inline Unordered_set_column& Unordered_set_column: } template -inline Unordered_set_column& Unordered_set_column::operator*=(unsigned int v) +inline Unordered_set_column& Unordered_set_column::operator*=(const Field_element& v) { - if constexpr (Master_matrix::Option_list::is_z2) { - if (v % 2 == 0) { - if constexpr (Master_matrix::isNonBasic && !Master_matrix::Option_list::is_of_boundary_type) { - throw std::invalid_argument("A chain column should not be multiplied by 0."); - } else { - clear(); - } - } - } else { - Field_element val = operators_->get_value(v); + Field_element val = Master_matrix::get_coefficient_value(v, operators_); - if (val == Field_operators::get_additive_identity()) { - if constexpr (Master_matrix::isNonBasic && !Master_matrix::Option_list::is_of_boundary_type) { - throw std::invalid_argument("A chain column should not be multiplied by 0."); - } else { - clear(); - } - return *this; + if (val == Field_operators::get_additive_identity()) { + if constexpr (Master_matrix::isNonBasic && !Master_matrix::Option_list::is_of_boundary_type) { + throw std::invalid_argument("A chain column should not be multiplied by 0."); + } else { + clear(); } + return *this; + } - if (val == Field_operators::get_multiplicative_identity()) return *this; + if (val == Field_operators::get_multiplicative_identity()) return *this; + // multiply_inplace needs a non-const reference to element, so even if Z2 never reaches here, it won't compile + // without the constexpr, as we are not storing a dummy value just for this purpose. + if constexpr (!Master_matrix::Option_list::is_z2) { for (Entry* entry : column_) { operators_->multiply_inplace(entry->get_element(), val); if constexpr (Master_matrix::Option_list::has_row_access) RA_opt::update_entry(*entry); @@ -713,16 +704,7 @@ inline Unordered_set_column& Unordered_set_column: static_assert((!Master_matrix::isNonBasic || Master_matrix::Option_list::is_of_boundary_type), "For chain columns, the given column cannot be constant."); - if constexpr (Master_matrix::Option_list::is_z2) { - if (val) { - _add(column); - } else { - clear(); - _add(column); - } - } else { - _multiply_target_and_add(val, column); - } + _multiply_target_and_add(Master_matrix::get_coefficient_value(val, operators_), column); return *this; } @@ -734,32 +716,12 @@ inline Unordered_set_column& Unordered_set_column: { if constexpr (Master_matrix::isNonBasic && !Master_matrix::Option_list::is_of_boundary_type) { // assumes that the addition never zeros out this column. - if constexpr (Master_matrix::Option_list::is_z2) { - if (val) { - if (_add(column)) { - Chain_opt::_swap_pivots(column); - Dim_opt::_swap_dimension(column); - } - } else { - throw std::invalid_argument("A chain column should not be multiplied by 0."); - } - } else { - if (_multiply_target_and_add(val, column)) { - Chain_opt::_swap_pivots(column); - Dim_opt::_swap_dimension(column); - } + if (_multiply_target_and_add(Master_matrix::get_coefficient_value(val, operators_), column)) { + Chain_opt::_swap_pivots(column); + Dim_opt::_swap_dimension(column); } } else { - if constexpr (Master_matrix::Option_list::is_z2) { - if (val) { - _add(column); - } else { - clear(); - _add(column); - } - } else { - _multiply_target_and_add(val, column); - } + _multiply_target_and_add(Master_matrix::get_coefficient_value(val, operators_), column); } return *this; @@ -777,13 +739,7 @@ inline Unordered_set_column& Unordered_set_column: static_assert((!Master_matrix::isNonBasic || Master_matrix::Option_list::is_of_boundary_type), "For chain columns, the given column cannot be constant."); - if constexpr (Master_matrix::Option_list::is_z2) { - if (val) { - _add(column); - } - } else { - _multiply_source_and_add(column, val); - } + _multiply_source_and_add(column, Master_matrix::get_coefficient_value(val, operators_)); return *this; } @@ -795,27 +751,12 @@ inline Unordered_set_column& Unordered_set_column: { if constexpr (Master_matrix::isNonBasic && !Master_matrix::Option_list::is_of_boundary_type) { // assumes that the addition never zeros out this column. - if constexpr (Master_matrix::Option_list::is_z2) { - if (val) { - if (_add(column)) { - Chain_opt::_swap_pivots(column); - Dim_opt::_swap_dimension(column); - } - } - } else { - if (_multiply_source_and_add(column, val)) { - Chain_opt::_swap_pivots(column); - Dim_opt::_swap_dimension(column); - } + if (_multiply_source_and_add(column, Master_matrix::get_coefficient_value(val, operators_))) { + Chain_opt::_swap_pivots(column); + Dim_opt::_swap_dimension(column); } } else { - if constexpr (Master_matrix::Option_list::is_z2) { - if (val) { - _add(column); - } - } else { - _multiply_source_and_add(column, val); - } + _multiply_source_and_add(column, Master_matrix::get_coefficient_value(val, operators_)); } return *this; @@ -828,11 +769,7 @@ inline void Unordered_set_column::push_back(const Entry& entry) GUDHI_CHECK(entry.get_row_index() > get_pivot(), "The new row index has to be higher than the current pivot."); - if constexpr (Master_matrix::Option_list::is_z2) { - _insert_entry(entry.get_row_index()); - } else { - _insert_entry(entry.get_element(), entry.get_row_index()); - } + _insert_entry(entry.get_row_index(), entry.get_element()); } template @@ -857,11 +794,7 @@ inline Unordered_set_column& Unordered_set_column: entryPool_ = other.entryPool_; for (const Entry* entry : other.column_) { - if constexpr (Master_matrix::Option_list::is_z2) { - _insert_entry(entry->get_row_index()); - } else { - _insert_entry(entry->get_element(), entry->get_row_index()); - } + _insert_entry(entry->get_row_index(), entry->get_element()); } return *this; @@ -902,44 +835,37 @@ inline void Unordered_set_column::_delete_entry(typename Column_s template inline typename Unordered_set_column::Entry* Unordered_set_column::_insert_entry( - const Field_element& value, - ID_index rowIndex) -{ - if constexpr (Master_matrix::Option_list::has_row_access) { - Entry* newEntry = entryPool_->construct(RA_opt::get_column_index(), rowIndex); - newEntry->set_element(value); - column_.insert(newEntry); - RA_opt::insert_entry(rowIndex, newEntry); - return newEntry; - } else { - Entry* newEntry = entryPool_->construct(rowIndex); - newEntry->set_element(value); - column_.insert(newEntry); - return newEntry; - } -} - -template -inline void Unordered_set_column::_insert_entry(ID_index rowIndex) + ID_index rowIndex, + const Field_element& value) { + Entry* newEntry; if constexpr (Master_matrix::Option_list::has_row_access) { - Entry* newEntry = entryPool_->construct(RA_opt::get_column_index(), rowIndex); - column_.insert(newEntry); - RA_opt::insert_entry(rowIndex, newEntry); + newEntry = entryPool_->construct(RA_opt::get_column_index(), rowIndex); } else { - Entry* newEntry = entryPool_->construct(rowIndex); - column_.insert(newEntry); + newEntry = entryPool_->construct(rowIndex); } + newEntry->set_element(value); + column_.insert(newEntry); + if constexpr (Master_matrix::Option_list::has_row_access) RA_opt::insert_entry(rowIndex, newEntry); + return newEntry; } template template inline bool Unordered_set_column::_add(const Entry_range& column) { + if (column.begin() == column.end()) return false; + if (column_.empty()) { // chain should never enter here. + for (const Entry& entry : column) { + _insert_entry(entry.get_row_index(), entry.get_element()); + } + return true; + } + return _generic_add( column, [&](const Entry& oldEntry, Entry* newEntry) { - if constexpr (!Master_matrix::Option_list::is_z2) newEntry->set_element(oldEntry.get_element()); + newEntry->set_element(oldEntry.get_element()); }, [&](Entry* targetEntry, const Entry& sourceEntry) { if constexpr (!Master_matrix::Option_list::is_z2) @@ -952,23 +878,10 @@ template inline bool Unordered_set_column::_multiply_target_and_add(const Field_element& val, const Entry_range& column) { - if (val == 0U) { - if constexpr (Master_matrix::isNonBasic && !Master_matrix::Option_list::is_of_boundary_type) { - throw std::invalid_argument("A chain column should not be multiplied by 0."); - // this would not only mess up the base, but also the pivots stored. - } else { - clear(); - for (const Entry& v : column) { - _insert_entry(v.get_element(), v.get_row_index()); - } - return true; - } - } - // because the column is unordered, I don't see a way to do both operations in one go // without guarantees on the entry range... operator*=(val); - return _add(column); + return _add(column) || val == Field_operators::get_additive_identity(); } template @@ -976,26 +889,36 @@ template inline bool Unordered_set_column::_multiply_source_and_add(const Entry_range& column, const Field_element& val) { - if (val == 0U) { + if (val == Field_operators::get_additive_identity() || column.begin() == column.end()) { return false; } - return _generic_add( - column, - [&](const Entry& oldEntry, Entry* newEntry) { - newEntry->set_element(oldEntry.get_element()); - operators_->multiply_inplace(newEntry->get_element(), val); - }, - [&](Entry* targetEntry, const Entry& sourceEntry) { - operators_->multiply_and_add_inplace_back(sourceEntry.get_element(), val, targetEntry->get_element()); - }); + if (val == Field_operators::get_multiplicative_identity()) { + return _add(column); + } + + // multiply_inplace needs a non-const reference to element, so even if Z2 never reaches here, it won't compile + // without the constexpr, as we are not storing a dummy value just for this purpose. + if constexpr (!Master_matrix::Option_list::is_z2) { + return _generic_add( + column, + [&](const Entry& oldEntry, Entry* newEntry) { + newEntry->set_element(oldEntry.get_element()); + operators_->multiply_inplace(newEntry->get_element(), val); + }, + [&](Entry* targetEntry, const Entry& sourceEntry) { + operators_->multiply_and_add_inplace_back(sourceEntry.get_element(), val, targetEntry->get_element()); + }); + } else { + return false; // we should never arrive here, just to suppress the warning + } } template template inline bool Unordered_set_column::_generic_add(const Entry_range& source, - F1&& process_source, - F2&& update_target) + [[maybe_unused]] F1&& process_source, + [[maybe_unused]] F2&& update_target) { bool pivotIsZeroed = false; diff --git a/multipers/gudhi/gudhi/Persistence_matrix/columns/vector_column.h b/multipers/gudhi/gudhi/Persistence_matrix/columns/vector_column.h index b73ce453..8db84f61 100644 --- a/multipers/gudhi/gudhi/Persistence_matrix/columns/vector_column.h +++ b/multipers/gudhi/gudhi/Persistence_matrix/columns/vector_column.h @@ -18,14 +18,15 @@ #ifndef PM_VECTOR_COLUMN_H #define PM_VECTOR_COLUMN_H -#include -#include -#include -#include -#include //binary_search +#include // std::size_t +#include // std::invalid_argument +#include // std::is_same_v +#include // std::binary_search, std::sort +#include // std::swap, std::move & std::exchange #include -#include //std::swap, std::move & std::exchange +#include +#include #include #include @@ -65,11 +66,50 @@ class Vector_column : public Master_matrix::Row_access_option, using Column_support = std::vector; using Entry_constructor = typename Master_matrix::Entry_constructor; + class Non_zero_element_iterator + : public boost::iterator_facade + { + public: + Non_zero_element_iterator(std::size_t curr, + Column_support const* column, + std::unordered_set const* erasedValues) + : curr_(curr), column_(column), erasedValues_(erasedValues) + {} + + Non_zero_element_iterator(Column_support const* column) + : curr_(column->size()), column_(column), erasedValues_(nullptr) + {} + + private: + friend class boost::iterator_core_access; + + bool equal(Non_zero_element_iterator const& other) const + { + return curr_ == other.curr_ && column_ == other.column_; + } + + const Entry& dereference() const { return *(*column_)[curr_]; } + + void increment() + { + ++curr_; + while (curr_ < column_->size() && + erasedValues_->find((*column_)[curr_]->get_row_index()) != erasedValues_->end()) { + ++curr_; + } + } + + std::size_t curr_; + Column_support const* column_; + std::unordered_set const* erasedValues_; + }; + public: using iterator = boost::indirect_iterator; using const_iterator = boost::indirect_iterator; using reverse_iterator = boost::indirect_iterator; using const_reverse_iterator = boost::indirect_iterator; + using Content_range = boost::iterator_range; Vector_column(Column_settings* colSettings = nullptr); template @@ -79,14 +119,32 @@ class Vector_column : public Master_matrix::Row_access_option, const Container& nonZeroRowIndices, Row_container* rowContainer, Column_settings* colSettings); - template + template > > Vector_column(const Container& nonZeroRowIndices, Dimension dimension, Column_settings* colSettings); - template + template > > Vector_column(Index columnIndex, const Container& nonZeroRowIndices, Dimension dimension, Row_container* rowContainer, Column_settings* colSettings); + Vector_column(ID_index idx, Dimension dimension, Column_settings* colSettings); + Vector_column(ID_index idx, Field_element e, Dimension dimension, Column_settings* colSettings); + template + Vector_column(Index columnIndex, + ID_index idx, + Dimension dimension, + Row_container* rowContainer, + Column_settings* colSettings); + template + Vector_column(Index columnIndex, + ID_index idx, + Field_element e, + Dimension dimension, + Row_container* rowContainer, + Column_settings* colSettings); Vector_column(const Vector_column& column, Column_settings* colSettings = nullptr); template Vector_column(const Vector_column& column, @@ -120,11 +178,13 @@ class Vector_column : public Master_matrix::Row_access_option, reverse_iterator rend() noexcept; const_reverse_iterator rend() const noexcept; + Content_range get_non_zero_content_range() const; + template Vector_column& operator+=(const Entry_range& column); Vector_column& operator+=(Vector_column& column); - Vector_column& operator*=(unsigned int v); + Vector_column& operator*=(const Field_element& v); // this = v * this + column template @@ -144,62 +204,25 @@ class Vector_column : public Master_matrix::Row_access_option, if (&c1 == &c2) return true; if (c1.erasedValues_.empty() && c2.erasedValues_.empty() && c1.column_.size() != c2.column_.size()) return false; - auto it1 = c1.column_.begin(); - auto it2 = c2.column_.begin(); - while (it1 != c1.column_.end() && it2 != c2.column_.end()) { - if constexpr (!Master_matrix::isNonBasic || Master_matrix::Option_list::is_of_boundary_type) { - while (it1 != c1.column_.end() && c1.erasedValues_.find((*it1)->get_row_index()) != c1.erasedValues_.end()) - ++it1; - while (it2 != c2.column_.end() && c2.erasedValues_.find((*it2)->get_row_index()) != c2.erasedValues_.end()) - ++it2; - if (it1 == c1.column_.end() || it2 == c2.column_.end()) break; - } - if constexpr (Master_matrix::Option_list::is_z2) { - if ((*it1)->get_row_index() != (*it2)->get_row_index()) return false; - } else { - if ((*it1)->get_row_index() != (*it2)->get_row_index() || (*it1)->get_element() != (*it2)->get_element()) - return false; - } - ++it1; - ++it2; - } - - if constexpr (!Master_matrix::isNonBasic || Master_matrix::Option_list::is_of_boundary_type) { - while (it1 != c1.column_.end() && c1.erasedValues_.find((*it1)->get_row_index()) != c1.erasedValues_.end()) ++it1; - while (it2 != c2.column_.end() && c2.erasedValues_.find((*it2)->get_row_index()) != c2.erasedValues_.end()) ++it2; - return it2 == c2.column_.end() && it1 == c1.column_.end(); - } else { - return true; - } + auto r1 = c1.get_non_zero_content_range(); + auto r2 = c2.get_non_zero_content_range(); + return std::equal(r1.begin(), r1.end(), r2.begin(), r2.end(), [](const Entry& e1, const Entry& e2) { + return e1.get_row_index() == e2.get_row_index() && e1.get_element() == e2.get_element(); + }); } friend bool operator<(const Vector_column& c1, const Vector_column& c2) { if (&c1 == &c2) return false; - auto it1 = c1.column_.begin(); - auto it2 = c2.column_.begin(); - while (it1 != c1.column_.end() && it2 != c2.column_.end()) { - if constexpr (!Master_matrix::isNonBasic || Master_matrix::Option_list::is_of_boundary_type) { - while (it1 != c1.column_.end() && c1.erasedValues_.find((*it1)->get_row_index()) != c1.erasedValues_.end()) - ++it1; - while (it2 != c2.column_.end() && c2.erasedValues_.find((*it2)->get_row_index()) != c2.erasedValues_.end()) - ++it2; - if (it1 == c1.column_.end() || it2 == c2.column_.end()) break; - } - - if ((*it1)->get_row_index() != (*it2)->get_row_index()) return (*it1)->get_row_index() < (*it2)->get_row_index(); - if constexpr (!Master_matrix::Option_list::is_z2) { - if ((*it1)->get_element() != (*it2)->get_element()) return (*it1)->get_element() < (*it2)->get_element(); - } - ++it1; - ++it2; - } - if constexpr (!Master_matrix::isNonBasic || Master_matrix::Option_list::is_of_boundary_type) { - while (it1 != c1.column_.end() && c1.erasedValues_.find((*it1)->get_row_index()) != c1.erasedValues_.end()) ++it1; - while (it2 != c2.column_.end() && c2.erasedValues_.find((*it2)->get_row_index()) != c2.erasedValues_.end()) ++it2; - } - return it2 != c2.column_.end(); + auto r1 = c1.get_non_zero_content_range(); + auto r2 = c2.get_non_zero_content_range(); + return std::lexicographical_compare( + r1.begin(), r1.end(), r2.begin(), r2.end(), [](const Entry& e1, const Entry& e2) { + if (e1.get_row_index() != e2.get_row_index()) return e1.get_row_index() < e2.get_row_index(); + if (e1.get_element() != e2.get_element()) return e1.get_element() < e2.get_element(); + return false; + }); } // Disabled with row access. @@ -228,7 +251,7 @@ class Vector_column : public Master_matrix::Row_access_option, Column_support column_; // TODO: test other containers? Useless when clear(Index) is never called, how much is it worth it? std::unordered_set erasedValues_; - Field_operators* operators_; + Field_operators const* operators_; Entry_constructor* entryPool_; template @@ -243,10 +266,8 @@ class Vector_column : public Master_matrix::Row_access_option, void _delete_entry(Entry* entry); void _delete_entry(typename Column_support::iterator& it); - Entry* _insert_entry(const Field_element& value, ID_index rowIndex, Column_support& column); - void _insert_entry(ID_index rowIndex, Column_support& column); - void _update_entry(const Field_element& value, ID_index rowIndex, Index position); - void _update_entry(ID_index rowIndex, Index position); + Entry* _insert_entry(Column_support& column, ID_index rowIndex, const Field_element& value); + void _update_entry(Index position, ID_index rowIndex, const Field_element& value); template bool _add(const Entry_range& column); template @@ -259,6 +280,8 @@ class Vector_column : public Master_matrix::Row_access_option, F2&& process_source, F3&& update_target1, F4&& update_target2); + bool _is_lazy_erased(const typename Column_support::const_iterator& it) const; + bool _is_lazy_erased(ID_index rowIndex) const; }; template @@ -266,43 +289,17 @@ inline Vector_column::Vector_column(Column_settings* colSettings) : RA_opt(), Dim_opt(), Chain_opt(), - operators_(nullptr), + operators_(Master_matrix::get_operator_ptr(colSettings)), entryPool_(colSettings == nullptr ? nullptr : &(colSettings->entryConstructor)) -{ - if (operators_ == nullptr && entryPool_ == nullptr) - return; // to allow default constructor which gives a dummy column - if constexpr (!Master_matrix::Option_list::is_z2) { - operators_ = &(colSettings->operators); - } -} +{} template template inline Vector_column::Vector_column(const Container& nonZeroRowIndices, Column_settings* colSettings) - : RA_opt(), - Dim_opt(nonZeroRowIndices.size() == 0 ? 0 : nonZeroRowIndices.size() - 1), - Chain_opt(), - column_(nonZeroRowIndices.size(), nullptr), - operators_(nullptr), - entryPool_(&(colSettings->entryConstructor)) + : Vector_column(nonZeroRowIndices, nonZeroRowIndices.size() == 0 ? 0 : nonZeroRowIndices.size() - 1, colSettings) { static_assert(!Master_matrix::isNonBasic || Master_matrix::Option_list::is_of_boundary_type, "Constructor not available for chain columns, please specify the dimension of the chain."); - - if constexpr (!Master_matrix::Option_list::is_z2) { - operators_ = &(colSettings->operators); - } - - Index i = 0; - if constexpr (Master_matrix::Option_list::is_z2) { - for (ID_index id : nonZeroRowIndices) { - _update_entry(id, i++); - } - } else { - for (const auto& p : nonZeroRowIndices) { - _update_entry(operators_->get_value(p.second), p.first, i++); - } - } } template @@ -311,82 +308,40 @@ inline Vector_column::Vector_column(Index columnIndex, const Container& nonZeroRowIndices, Row_container* rowContainer, Column_settings* colSettings) - : RA_opt(columnIndex, rowContainer), - Dim_opt(nonZeroRowIndices.size() == 0 ? 0 : nonZeroRowIndices.size() - 1), - Chain_opt([&] { - if constexpr (Master_matrix::Option_list::is_z2) { - return nonZeroRowIndices.begin() == nonZeroRowIndices.end() - ? Master_matrix::template get_null_value() - : *std::prev(nonZeroRowIndices.end()); - } else { - return nonZeroRowIndices.begin() == nonZeroRowIndices.end() - ? Master_matrix::template get_null_value() - : std::prev(nonZeroRowIndices.end())->first; - } - }()), - column_(nonZeroRowIndices.size(), nullptr), - operators_(nullptr), - entryPool_(&(colSettings->entryConstructor)) + : Vector_column(columnIndex, + nonZeroRowIndices, + nonZeroRowIndices.size() == 0 ? 0 : nonZeroRowIndices.size() - 1, + rowContainer, + colSettings) { static_assert(!Master_matrix::isNonBasic || Master_matrix::Option_list::is_of_boundary_type, "Constructor not available for chain columns, please specify the dimension of the chain."); - - if constexpr (!Master_matrix::Option_list::is_z2) { - operators_ = &(colSettings->operators); - } - - Index i = 0; - if constexpr (Master_matrix::Option_list::is_z2) { - for (ID_index id : nonZeroRowIndices) { - _update_entry(id, i++); - } - } else { - for (const auto& p : nonZeroRowIndices) { - _update_entry(operators_->get_value(p.second), p.first, i++); - } - } } template -template +template inline Vector_column::Vector_column(const Container& nonZeroRowIndices, Dimension dimension, Column_settings* colSettings) : RA_opt(), Dim_opt(dimension), - Chain_opt([&] { - if constexpr (Master_matrix::Option_list::is_z2) { - return nonZeroRowIndices.begin() == nonZeroRowIndices.end() - ? Master_matrix::template get_null_value() - : *std::prev(nonZeroRowIndices.end()); - } else { - return nonZeroRowIndices.begin() == nonZeroRowIndices.end() - ? Master_matrix::template get_null_value() - : std::prev(nonZeroRowIndices.end())->first; - } - }()), + Chain_opt(nonZeroRowIndices.begin() == nonZeroRowIndices.end() + ? Master_matrix::template get_null_value() + : Master_matrix::get_row_index(*std::prev(nonZeroRowIndices.end()))), column_(nonZeroRowIndices.size(), nullptr), - operators_(nullptr), + operators_(Master_matrix::get_operator_ptr(colSettings)), entryPool_(&(colSettings->entryConstructor)) { - if constexpr (!Master_matrix::Option_list::is_z2) { - operators_ = &(colSettings->operators); - } - Index i = 0; - if constexpr (Master_matrix::Option_list::is_z2) { - for (ID_index id : nonZeroRowIndices) { - _update_entry(id, i++); - } - } else { - for (const auto& p : nonZeroRowIndices) { - _update_entry(operators_->get_value(p.second), p.first, i++); - } + for (const auto& id : nonZeroRowIndices) { + _update_entry(i++, + Master_matrix::get_row_index(id), + Master_matrix::get_coefficient_value(Master_matrix::get_element(id), operators_)); } } template -template +template inline Vector_column::Vector_column(Index columnIndex, const Container& nonZeroRowIndices, Dimension dimension, @@ -394,37 +349,91 @@ inline Vector_column::Vector_column(Index columnIndex, Column_settings* colSettings) : RA_opt(columnIndex, rowContainer), Dim_opt(dimension), - Chain_opt([&] { - if constexpr (Master_matrix::Option_list::is_z2) { - return nonZeroRowIndices.begin() == nonZeroRowIndices.end() - ? Master_matrix::template get_null_value() - : *std::prev(nonZeroRowIndices.end()); - } else { - return nonZeroRowIndices.begin() == nonZeroRowIndices.end() - ? Master_matrix::template get_null_value() - : std::prev(nonZeroRowIndices.end())->first; - } - }()), + Chain_opt(nonZeroRowIndices.begin() == nonZeroRowIndices.end() + ? Master_matrix::template get_null_value() + : Master_matrix::get_row_index(*std::prev(nonZeroRowIndices.end()))), column_(nonZeroRowIndices.size(), nullptr), - operators_(nullptr), + operators_(Master_matrix::get_operator_ptr(colSettings)), entryPool_(&(colSettings->entryConstructor)) { - if constexpr (!Master_matrix::Option_list::is_z2) { - operators_ = &(colSettings->operators); - } - Index i = 0; - if constexpr (Master_matrix::Option_list::is_z2) { - for (ID_index id : nonZeroRowIndices) { - _update_entry(id, i++); - } - } else { - for (const auto& p : nonZeroRowIndices) { - _update_entry(operators_->get_value(p.second), p.first, i++); - } + for (const auto& id : nonZeroRowIndices) { + _update_entry(i++, + Master_matrix::get_row_index(id), + Master_matrix::get_coefficient_value(Master_matrix::get_element(id), operators_)); } } +template +inline Vector_column::Vector_column(ID_index idx, Dimension dimension, Column_settings* colSettings) + : RA_opt(), + Dim_opt(dimension), + Chain_opt(idx), + column_(1, nullptr), + operators_(nullptr), + entryPool_(&(colSettings->entryConstructor)) +{ + static_assert(Master_matrix::Option_list::is_z2, + "Constructor not available for Zp != Z2. Please specify the coefficient."); + _update_entry(0, idx, 1); +} + +template +inline Vector_column::Vector_column(ID_index idx, + Field_element e, + Dimension dimension, + Column_settings* colSettings) + : RA_opt(), + Dim_opt(dimension), + Chain_opt(idx), + column_(1, nullptr), + operators_(&(colSettings->operators)), + entryPool_(&(colSettings->entryConstructor)) +{ + static_assert(!Master_matrix::Option_list::is_z2, + "Constructor not available for Zp == Z2. Please do not specify any coefficient."); + _update_entry(0, idx, operators_->get_value(e)); +} + +template +template +inline Vector_column::Vector_column(Index columnIndex, + ID_index idx, + Dimension dimension, + Row_container* rowContainer, + Column_settings* colSettings) + : RA_opt(columnIndex, rowContainer), + Dim_opt(dimension), + Chain_opt(idx), + column_(1, nullptr), + operators_(nullptr), + entryPool_(&(colSettings->entryConstructor)) +{ + static_assert(Master_matrix::Option_list::is_z2, + "Constructor not available for Zp != Z2. Please specify the coefficient."); + _update_entry(0, idx, 1); +} + +template +template +inline Vector_column::Vector_column(Index columnIndex, + ID_index idx, + Field_element e, + Dimension dimension, + Row_container* rowContainer, + Column_settings* colSettings) + : RA_opt(columnIndex, rowContainer), + Dim_opt(dimension), + Chain_opt(idx), + column_(1, nullptr), + operators_(&(colSettings->operators)), + entryPool_(&(colSettings->entryConstructor)) +{ + static_assert(!Master_matrix::Option_list::is_z2, + "Constructor not available for Zp == Z2. Please do not specify any coefficient."); + _update_entry(0, idx, operators_->get_value(e)); +} + template inline Vector_column::Vector_column(const Vector_column& column, Column_settings* colSettings) : RA_opt(), @@ -432,24 +441,16 @@ inline Vector_column::Vector_column(const Vector_column& column, Chain_opt(static_cast(column)), column_(column.column_.size(), nullptr), erasedValues_(column.erasedValues_), - operators_(colSettings == nullptr ? column.operators_ : nullptr), + operators_(colSettings == nullptr ? column.operators_ : Master_matrix::get_operator_ptr(colSettings)), entryPool_(colSettings == nullptr ? column.entryPool_ : &(colSettings->entryConstructor)) { static_assert(!Master_matrix::Option_list::has_row_access, "Simple copy constructor not available when row access option enabled. Please specify the new column " "index and the row container."); - if constexpr (!Master_matrix::Option_list::is_z2) { - if (colSettings != nullptr) operators_ = &(colSettings->operators); - } - Index i = 0; for (const Entry* entry : column.column_) { - if constexpr (Master_matrix::Option_list::is_z2) { - _update_entry(entry->get_row_index(), i++); - } else { - _update_entry(entry->get_element(), entry->get_row_index(), i++); - } + _update_entry(i++, entry->get_row_index(), entry->get_element()); } } @@ -464,20 +465,12 @@ inline Vector_column::Vector_column(const Vector_column& column, Chain_opt(static_cast(column)), column_(column.column_.size(), nullptr), erasedValues_(column.erasedValues_), - operators_(colSettings == nullptr ? column.operators_ : nullptr), + operators_(colSettings == nullptr ? column.operators_ : Master_matrix::get_operator_ptr(colSettings)), entryPool_(colSettings == nullptr ? column.entryPool_ : &(colSettings->entryConstructor)) { - if constexpr (!Master_matrix::Option_list::is_z2) { - if (colSettings != nullptr) operators_ = &(colSettings->operators); - } - Index i = 0; for (const Entry* entry : column.column_) { - if constexpr (Master_matrix::Option_list::is_z2) { - _update_entry(entry->get_row_index(), i++); - } else { - _update_entry(entry->get_element(), entry->get_row_index(), i++); - } + _update_entry(i++, entry->get_row_index(), entry->get_element()); } } @@ -490,8 +483,7 @@ inline Vector_column::Vector_column(Vector_column&& column) noexc erasedValues_(std::move(column.erasedValues_)), operators_(std::exchange(column.operators_, nullptr)), entryPool_(std::exchange(column.entryPool_, nullptr)) -{ -} +{} template inline Vector_column::~Vector_column() @@ -511,16 +503,9 @@ inline std::vector::Field_element> Vector_ return std::vector(); std::vector container(columnLength, 0); - for (auto it = column_.begin(); it != column_.end() && (*it)->get_row_index() < static_cast(columnLength); - ++it) { - if constexpr (!Master_matrix::isNonBasic || Master_matrix::Option_list::is_of_boundary_type) { - if (erasedValues_.find((*it)->get_row_index()) != erasedValues_.end()) continue; - } - if constexpr (Master_matrix::Option_list::is_z2) { - container[(*it)->get_row_index()] = 1; - } else { - container[(*it)->get_row_index()] = (*it)->get_element(); - } + auto r = get_non_zero_content_range(); + for (auto it = r.begin(); it != r.end() && it->get_row_index() < static_cast(columnLength); ++it) { + container[it->get_row_index()] = Master_matrix::get_element(*it); } return container; } @@ -528,8 +513,7 @@ inline std::vector::Field_element> Vector_ template inline bool Vector_column::is_non_zero(ID_index rowIndex) const { - if constexpr (!Master_matrix::isNonBasic || Master_matrix::Option_list::is_of_boundary_type) - if (erasedValues_.find(rowIndex) != erasedValues_.end()) return false; + if (_is_lazy_erased(rowIndex)) return false; Entry entry(rowIndex); return std::binary_search(column_.begin(), column_.end(), &entry, [](const Entry* a, const Entry* b) { @@ -588,7 +572,7 @@ inline void Vector_column::reorder(const Row_index_map& valueMap, } else { Column_support newColumn; for (Entry* entry : column_) { - if (erasedValues_.find(entry->get_row_index()) == erasedValues_.end()) { + if (!_is_lazy_erased(entry->get_row_index())) { if constexpr (Master_matrix::Option_list::has_row_access) { RA_opt::unlink(entry); if (columnIndex != Master_matrix::template get_null_value()) entry->set_column_index(columnIndex); @@ -744,6 +728,13 @@ inline typename Vector_column::const_reverse_iterator Vector_colu return column_.rend(); } +template +inline typename Vector_column::Content_range Vector_column::get_non_zero_content_range() + const +{ + return Content_range(Non_zero_element_iterator(0, &column_, &erasedValues_), Non_zero_element_iterator(&column_)); +} + template template inline Vector_column& Vector_column::operator+=(const Entry_range& column) @@ -776,30 +767,24 @@ inline Vector_column& Vector_column::operator+=(Ve } template -inline Vector_column& Vector_column::operator*=(unsigned int v) +inline Vector_column& Vector_column::operator*=(const Field_element& v) { - if constexpr (Master_matrix::Option_list::is_z2) { - if (v % 2 == 0) { - if constexpr (Master_matrix::isNonBasic && !Master_matrix::Option_list::is_of_boundary_type) { - throw std::invalid_argument("A chain column should not be multiplied by 0."); - } else { - clear(); - } - } - } else { - Field_element val = operators_->get_value(v); + Field_element val = Master_matrix::get_coefficient_value(v, operators_); - if (val == Field_operators::get_additive_identity()) { - if constexpr (Master_matrix::isNonBasic && !Master_matrix::Option_list::is_of_boundary_type) { - throw std::invalid_argument("A chain column should not be multiplied by 0."); - } else { - clear(); - } - return *this; + if (val == Field_operators::get_additive_identity()) { + if constexpr (Master_matrix::isNonBasic && !Master_matrix::Option_list::is_of_boundary_type) { + throw std::invalid_argument("A chain column should not be multiplied by 0."); + } else { + clear(); } + return *this; + } - if (val == Field_operators::get_multiplicative_identity()) return *this; + if (val == Field_operators::get_multiplicative_identity()) return *this; + // multiply_inplace needs a non-const reference to element, so even if Z2 never reaches here, it won't compile + // without the constexpr, as we are not storing a dummy value just for this purpose. + if constexpr (!Master_matrix::Option_list::is_z2) { for (Entry* entry : column_) { operators_->multiply_inplace(entry->get_element(), val); if constexpr (Master_matrix::Option_list::has_row_access) RA_opt::update_entry(*entry); @@ -820,16 +805,7 @@ inline Vector_column& Vector_column::multiply_targ static_assert((!Master_matrix::isNonBasic || Master_matrix::Option_list::is_of_boundary_type), "For chain columns, the given column cannot be constant."); - if constexpr (Master_matrix::Option_list::is_z2) { - if (val) { - _add(column); - } else { - clear(); - _add(column); - } - } else { - _multiply_target_and_add(val, column); - } + _multiply_target_and_add(Master_matrix::get_coefficient_value(val, operators_), column); return *this; } @@ -840,32 +816,12 @@ inline Vector_column& Vector_column::multiply_targ { if constexpr (Master_matrix::isNonBasic && !Master_matrix::Option_list::is_of_boundary_type) { // assumes that the addition never zeros out this column. - if constexpr (Master_matrix::Option_list::is_z2) { - if (val) { - if (_add(column)) { - Chain_opt::_swap_pivots(column); - Dim_opt::_swap_dimension(column); - } - } else { - throw std::invalid_argument("A chain column should not be multiplied by 0."); - } - } else { - if (_multiply_target_and_add(val, column)) { - Chain_opt::_swap_pivots(column); - Dim_opt::_swap_dimension(column); - } + if (_multiply_target_and_add(Master_matrix::get_coefficient_value(val, operators_), column)) { + Chain_opt::_swap_pivots(column); + Dim_opt::_swap_dimension(column); } } else { - if constexpr (Master_matrix::Option_list::is_z2) { - if (val) { - _add(column); - } else { - clear(); - _add(column); - } - } else { - _multiply_target_and_add(val, column); - } + _multiply_target_and_add(Master_matrix::get_coefficient_value(val, operators_), column); } return *this; @@ -882,13 +838,7 @@ inline Vector_column& Vector_column::multiply_sour static_assert((!Master_matrix::isNonBasic || Master_matrix::Option_list::is_of_boundary_type), "For chain columns, the given column cannot be constant."); - if constexpr (Master_matrix::Option_list::is_z2) { - if (val) { - _add(column); - } - } else { - _multiply_source_and_add(column, val); - } + _multiply_source_and_add(column, Master_matrix::get_coefficient_value(val, operators_)); return *this; } @@ -899,27 +849,12 @@ inline Vector_column& Vector_column::multiply_sour { if constexpr (Master_matrix::isNonBasic && !Master_matrix::Option_list::is_of_boundary_type) { // assumes that the addition never zeros out this column. - if constexpr (Master_matrix::Option_list::is_z2) { - if (val) { - if (_add(column)) { - Chain_opt::_swap_pivots(column); - Dim_opt::_swap_dimension(column); - } - } - } else { - if (_multiply_source_and_add(column, val)) { - Chain_opt::_swap_pivots(column); - Dim_opt::_swap_dimension(column); - } + if (_multiply_source_and_add(column, Master_matrix::get_coefficient_value(val, operators_))) { + Chain_opt::_swap_pivots(column); + Dim_opt::_swap_dimension(column); } } else { - if constexpr (Master_matrix::Option_list::is_z2) { - if (val) { - _add(column); - } - } else { - _multiply_source_and_add(column, val); - } + _multiply_source_and_add(column, Master_matrix::get_coefficient_value(val, operators_)); } return *this; @@ -932,11 +867,7 @@ inline void Vector_column::push_back(const Entry& entry) GUDHI_CHECK(entry.get_row_index() > get_pivot(), "The new row index has to be higher than the current pivot."); - if constexpr (Master_matrix::Option_list::is_z2) { - _insert_entry(entry.get_row_index(), column_); - } else { - _insert_entry(entry.get_element(), entry.get_row_index(), column_); - } + _insert_entry(column_, entry.get_row_index(), entry.get_element()); } template @@ -968,11 +899,7 @@ inline Vector_column& Vector_column::operator=(con if constexpr (Master_matrix::Option_list::has_row_access) RA_opt::unlink(column_[i]); tmpPool->destroy(column_[i]); } - if constexpr (Master_matrix::Option_list::is_z2) { - _update_entry(entry->get_row_index(), i++); - } else { - _update_entry(entry->get_element(), entry->get_row_index(), i++); - } + _update_entry(i++, entry->get_row_index(), entry->get_element()); } erasedValues_ = other.erasedValues_; operators_ = other.operators_; @@ -1007,11 +934,9 @@ template inline std::size_t Vector_column::compute_hash_value() { std::size_t seed = 0; - for (Entry* entry : column_) { - if (erasedValues_.find(entry->get_row_index()) == erasedValues_.end()) { - seed ^= std::hash()(entry->get_row_index() * static_cast(entry->get_element())) + - 0x9e3779b9 + (seed << 6) + (seed >> 2); - } + for (const Entry& entry : get_non_zero_content_range()) { + seed ^= std::hash()(entry.get_row_index() * static_cast(entry.get_element())) + + 0x9e3779b9 + (seed << 6) + (seed >> 2); } return seed; } @@ -1032,59 +957,30 @@ inline void Vector_column::_delete_entry(typename Column_support: template inline typename Vector_column::Entry* -Vector_column::_insert_entry(const Field_element& value, ID_index rowIndex, Column_support& column) +Vector_column::_insert_entry(Column_support& column, ID_index rowIndex, const Field_element& value) { + Entry* newEntry; if constexpr (Master_matrix::Option_list::has_row_access) { - Entry* newEntry = entryPool_->construct(RA_opt::get_column_index(), rowIndex); - newEntry->set_element(value); - column.push_back(newEntry); - RA_opt::insert_entry(rowIndex, newEntry); - return newEntry; + newEntry = entryPool_->construct(RA_opt::get_column_index(), rowIndex); } else { - Entry* newEntry = entryPool_->construct(rowIndex); - newEntry->set_element(value); - column.push_back(newEntry); - return newEntry; + newEntry = entryPool_->construct(rowIndex); } + newEntry->set_element(value); + column.push_back(newEntry); + if constexpr (Master_matrix::Option_list::has_row_access) RA_opt::insert_entry(rowIndex, newEntry); + return newEntry; } template -inline void Vector_column::_insert_entry(ID_index rowIndex, Column_support& column) +inline void Vector_column::_update_entry(Index position, ID_index rowIndex, const Field_element& value) { if constexpr (Master_matrix::Option_list::has_row_access) { - Entry* newEntry = entryPool_->construct(RA_opt::get_column_index(), rowIndex); - column.push_back(newEntry); - RA_opt::insert_entry(rowIndex, newEntry); - } else { - Entry* newEntry = entryPool_->construct(rowIndex); - column.push_back(newEntry); - } -} - -template -inline void Vector_column::_update_entry(const Field_element& value, ID_index rowIndex, Index position) -{ - if constexpr (Master_matrix::Option_list::has_row_access) { - Entry* newEntry = entryPool_->construct(RA_opt::get_column_index(), rowIndex); - newEntry->set_element(value); - column_[position] = newEntry; - RA_opt::insert_entry(rowIndex, newEntry); - } else { - column_[position] = entryPool_->construct(rowIndex); - column_[position]->set_element(value); - } -} - -template -inline void Vector_column::_update_entry(ID_index rowIndex, Index position) -{ - if constexpr (Master_matrix::Option_list::has_row_access) { - Entry* newEntry = entryPool_->construct(RA_opt::get_column_index(), rowIndex); - column_[position] = newEntry; - RA_opt::insert_entry(rowIndex, newEntry); + column_[position] = entryPool_->construct(RA_opt::get_column_index(), rowIndex); } else { column_[position] = entryPool_->construct(rowIndex); } + column_[position]->set_element(value); + if constexpr (Master_matrix::Option_list::has_row_access) RA_opt::insert_entry(rowIndex, column_[position]); } template @@ -1093,15 +989,20 @@ inline bool Vector_column::_add(const Entry_range& column) { if (column.begin() == column.end()) return false; if (column_.empty()) { // chain should never enter here. - column_.resize(column.size()); - Index i = 0; - for (const Entry& entry : column) { - if constexpr (Master_matrix::Option_list::is_z2) { - _update_entry(entry.get_row_index(), i++); + auto get_range = [](const Entry_range& column) -> decltype(auto) { + if constexpr (std::is_same_v >) { + return column.get_non_zero_content_range(); } else { - _update_entry(entry.get_element(), entry.get_row_index(), i++); + return column; } + }; + column_.resize(column.size()); + Index i = 0; + for (const Entry& entry : get_range(column)) { + _update_entry(i++, entry.get_row_index(), entry.get_element()); } + column_.resize(i); // i <= column.size(), so it should not trigger a reallocation + erasedValues_.clear(); return true; } @@ -1111,13 +1012,8 @@ inline bool Vector_column::_add(const Entry_range& column) auto pivotIsZeroed = _generic_add( column, [&](Entry* entryTarget) { newColumn.push_back(entryTarget); }, - [&](typename Entry_range::const_iterator& itSource, - [[maybe_unused]] const typename Column_support::iterator& itTarget) { - if constexpr (Master_matrix::Option_list::is_z2) { - _insert_entry(itSource->get_row_index(), newColumn); - } else { - _insert_entry(itSource->get_element(), itSource->get_row_index(), newColumn); - } + [&](typename Entry_range::const_iterator& itSource, const typename Column_support::iterator&) { + _insert_entry(newColumn, itSource->get_row_index(), itSource->get_element()); }, [&](Field_element& targetElement, typename Entry_range::const_iterator& itSource) { if constexpr (!Master_matrix::Option_list::is_z2) @@ -1134,7 +1030,7 @@ template template inline bool Vector_column::_multiply_target_and_add(const Field_element& val, const Entry_range& column) { - if (val == 0U) { + if (val == Field_operators::get_additive_identity()) { if constexpr (Master_matrix::isNonBasic && !Master_matrix::Option_list::is_of_boundary_type) { throw std::invalid_argument("A chain column should not be multiplied by 0."); // this would not only mess up the base, but also the pivots stored. @@ -1142,70 +1038,77 @@ inline bool Vector_column::_multiply_target_and_add(const Field_e clear(); } } - if (column_.empty()) { // chain should never enter here. - column_.resize(column.size()); - Index i = 0; - for (const Entry& entry : column) { - if constexpr (Master_matrix::Option_list::is_z2) { - _update_entry(entry.get_row_index(), i++); - } else { - _update_entry(entry.get_element(), entry.get_row_index(), i++); - } - } - if constexpr (std::is_same_v >) erasedValues_ = column.erasedValues_; - return true; - } - Column_support newColumn; - newColumn.reserve(column_.size() + column.size()); // safe upper bound + if (column_.empty() || val == Field_operators::get_multiplicative_identity()) { + return _add(column); + } - auto pivotIsZeroed = _generic_add( - column, - [&](Entry* entryTarget) { - operators_->multiply_inplace(entryTarget->get_element(), val); - if constexpr (Master_matrix::Option_list::has_row_access) RA_opt::update_entry(*entryTarget); - newColumn.push_back(entryTarget); - }, - [&](typename Entry_range::const_iterator& itSource, const typename Column_support::iterator& itTarget) { - _insert_entry(itSource->get_element(), itSource->get_row_index(), newColumn); - }, - [&](Field_element& targetElement, typename Entry_range::const_iterator& itSource) { - operators_->multiply_and_add_inplace_front(targetElement, val, itSource->get_element()); - }, - [&](Entry* entryTarget) { newColumn.push_back(entryTarget); }); + // multiply_inplace needs a non-const reference to element, so even if Z2 never reaches here, it won't compile + // without the constexpr, as we are not storing a dummy value just for this purpose. + if constexpr (!Master_matrix::Option_list::is_z2) { + Column_support newColumn; + newColumn.reserve(column_.size() + column.size()); // safe upper bound + + auto pivotIsZeroed = _generic_add( + column, + [&](Entry* entryTarget) { + operators_->multiply_inplace(entryTarget->get_element(), val); + if constexpr (Master_matrix::Option_list::has_row_access) RA_opt::update_entry(*entryTarget); + newColumn.push_back(entryTarget); + }, + [&](typename Entry_range::const_iterator& itSource, const typename Column_support::iterator&) { + _insert_entry(newColumn, itSource->get_row_index(), itSource->get_element()); + }, + [&](Field_element& targetElement, typename Entry_range::const_iterator& itSource) { + operators_->multiply_and_add_inplace_front(targetElement, val, itSource->get_element()); + }, + [&](Entry* entryTarget) { newColumn.push_back(entryTarget); }); - column_.swap(newColumn); + column_.swap(newColumn); - return pivotIsZeroed; + return pivotIsZeroed; + } else { + return false; // we should never arrive here, just to suppress the warning + } } template template inline bool Vector_column::_multiply_source_and_add(const Entry_range& column, const Field_element& val) { - if (val == 0U || column.begin() == column.end()) { + if (val == Field_operators::get_additive_identity() || column.begin() == column.end()) { return false; } - Column_support newColumn; - newColumn.reserve(column_.size() + column.size()); // safe upper bound + if (val == Field_operators::get_multiplicative_identity()) { + return _add(column); + } - auto pivotIsZeroed = _generic_add( - column, - [&](Entry* entryTarget) { newColumn.push_back(entryTarget); }, - [&](typename Entry_range::const_iterator& itSource, const typename Column_support::iterator& itTarget) { - Entry* newEntry = _insert_entry(itSource->get_element(), itSource->get_row_index(), newColumn); - operators_->multiply_inplace(newEntry->get_element(), val); - if constexpr (Master_matrix::Option_list::has_row_access) RA_opt::update_entry(*newEntry); - }, - [&](Field_element& targetElement, typename Entry_range::const_iterator& itSource) { - operators_->multiply_and_add_inplace_back(itSource->get_element(), val, targetElement); - }, - [&](Entry* entryTarget) { newColumn.push_back(entryTarget); }); + // multiply_inplace needs a non-const reference to element, so even if Z2 never reaches here, it won't compile + // without the constexpr, as we are not storing a dummy value just for this purpose. + if constexpr (!Master_matrix::Option_list::is_z2) { + Column_support newColumn; + newColumn.reserve(column_.size() + column.size()); // safe upper bound + + auto pivotIsZeroed = _generic_add( + column, + [&](Entry* entryTarget) { newColumn.push_back(entryTarget); }, + [&](typename Entry_range::const_iterator& itSource, const typename Column_support::iterator&) { + Entry* newEntry = _insert_entry(newColumn, itSource->get_row_index(), itSource->get_element()); + operators_->multiply_inplace(newEntry->get_element(), val); + if constexpr (Master_matrix::Option_list::has_row_access) RA_opt::update_entry(*newEntry); + }, + [&](Field_element& targetElement, typename Entry_range::const_iterator& itSource) { + operators_->multiply_and_add_inplace_back(itSource->get_element(), val, targetElement); + }, + [&](Entry* entryTarget) { newColumn.push_back(entryTarget); }); - column_.swap(newColumn); + column_.swap(newColumn); - return pivotIsZeroed; + return pivotIsZeroed; + } else { + return false; // we should never arrive here, just to suppress the warning + } } template @@ -1217,19 +1120,14 @@ inline bool Vector_column::_generic_add(const Entry_range& column F4&& update_target2) { auto updateTargetIterator = [&](typename Column_support::iterator& itTarget) { - if constexpr (!Master_matrix::isNonBasic || Master_matrix::Option_list::is_of_boundary_type) { - while (itTarget != column_.end() && erasedValues_.find((*itTarget)->get_row_index()) != erasedValues_.end()) { - _delete_entry(*itTarget); - ++itTarget; - } + while (_is_lazy_erased(itTarget)) { + _delete_entry(*itTarget); + ++itTarget; } }; auto updateSourceIterator = [&](typename Entry_range::const_iterator& itSource) { - if constexpr (std::is_same_v > && - (!Master_matrix::isNonBasic || Master_matrix::Option_list::is_of_boundary_type)) { - while (itSource != column.end() && - column.erasedValues_.find(itSource->get_row_index()) != column.erasedValues_.end()) - ++itSource; + if constexpr (std::is_same_v >) { + while (itSource != column.end() && column._is_lazy_erased(itSource->get_row_index())) ++itSource; } }; @@ -1273,6 +1171,26 @@ inline bool Vector_column::_generic_add(const Entry_range& column return pivotIsZeroed; } +template +inline bool Vector_column::_is_lazy_erased(const typename Column_support::const_iterator& it) const +{ + if constexpr (!Master_matrix::isNonBasic || Master_matrix::Option_list::is_of_boundary_type) { + return it != column_.end() && erasedValues_.find((*it)->get_row_index()) != erasedValues_.end(); + } else { + return false; + } +} + +template +inline bool Vector_column::_is_lazy_erased(ID_index rowIndex) const +{ + if constexpr (!Master_matrix::isNonBasic || Master_matrix::Option_list::is_of_boundary_type) { + return erasedValues_.find(rowIndex) != erasedValues_.end(); + } else { + return false; + } +} + } // namespace persistence_matrix } // namespace Gudhi diff --git a/multipers/gudhi/gudhi/Persistence_matrix/matrix_dimension_holders.h b/multipers/gudhi/gudhi/Persistence_matrix/matrix_dimension_holders.h index 6cb98d18..c1720ff2 100644 --- a/multipers/gudhi/gudhi/Persistence_matrix/matrix_dimension_holders.h +++ b/multipers/gudhi/gudhi/Persistence_matrix/matrix_dimension_holders.h @@ -96,6 +96,8 @@ class Matrix_max_dimension_holder */ Matrix_max_dimension_holder& operator=(Matrix_max_dimension_holder&& other) noexcept { + if (this == &other) return *this; + maxDim_ = std::exchange(other.maxDim_, -1); return *this; }; @@ -177,6 +179,8 @@ class Matrix_all_dimension_holder */ Matrix_all_dimension_holder& operator=(Matrix_all_dimension_holder&& other) noexcept { + if (this == &other) return *this; + dimensions_ = std::move(other.dimensions_); maxDim_ = std::exchange(other.maxDim_, -1); return *this; diff --git a/multipers/gudhi/gudhi/Persistence_matrix/matrix_row_access.h b/multipers/gudhi/gudhi/Persistence_matrix/matrix_row_access.h index 3f6fce21..c1f5be0c 100644 --- a/multipers/gudhi/gudhi/Persistence_matrix/matrix_row_access.h +++ b/multipers/gudhi/gudhi/Persistence_matrix/matrix_row_access.h @@ -162,6 +162,8 @@ class Matrix_row_access */ Matrix_row_access& operator=(Matrix_row_access&& other) noexcept { + if (this == &other) return *this; + rows_ = std::exchange(other.rows_, nullptr); return *this; } diff --git a/multipers/gudhi/gudhi/Persistence_matrix/ru_rep_cycles.h b/multipers/gudhi/gudhi/Persistence_matrix/ru_rep_cycles.h index b5e1aa81..b074de3f 100644 --- a/multipers/gudhi/gudhi/Persistence_matrix/ru_rep_cycles.h +++ b/multipers/gudhi/gudhi/Persistence_matrix/ru_rep_cycles.h @@ -22,6 +22,10 @@ #include //std::sort #include +#ifdef GUDHI_USE_TBB +#include +#endif + #include namespace Gudhi { @@ -40,7 +44,6 @@ struct Dummy_ru_representative_cycles { {} }; -// TODO: add coefficients ? Only Z2 token into account for now. /** * @class RU_representative_cycles ru_rep_cycles.h gudhi/Persistence_matrix/ru_rep_cycles.h * @ingroup persistence_matrix @@ -53,9 +56,10 @@ template class RU_representative_cycles { public: - using Index = typename Master_matrix::Index; /**< @ref MatIdx index type. */ - using Bar = typename Master_matrix::Bar; /**< Bar type. */ - using Cycle = typename Master_matrix::Cycle; /**< Cycle type. */ + using Index = typename Master_matrix::Index; /**< @ref MatIdx index type. */ + using Bar = typename Master_matrix::Bar; /**< Bar type. */ + using Cycle = typename Master_matrix::Cycle; /**< Cycle type. */ + using Dimension = typename Master_matrix::Dimension; /**< Dimension type. */ /** * @brief Default constructor. @@ -64,11 +68,22 @@ class RU_representative_cycles /** * @brief Computes the current representative cycles of the matrix. + * + * @param dim If different from default value, only the cycles of the given dimension are updated. + * All others are erased. + */ + void update_representative_cycles(Dimension dim = Master_matrix::template get_null_value()); + + /** + * @brief Computes the current representative cycle of the given bar. All other cycles already computed are left + * untouched (and therefore they could be unvalid for the current matrix). + * + * @param bar Bar corresponding to the wanted representative cycle. */ - void update_representative_cycles(); + void update_representative_cycle(const Bar& bar); /** - * @brief Returns the current representative cycles. If the matrix is modified later after the first call, + * @brief Returns the current representative cycles. If the matrix was modified since the last call, * @ref update_representative_cycles has to be called to update the returned cycles. * * @return A const reference to a vector of @ref Matrix::Cycle containing all representative cycles. @@ -76,8 +91,8 @@ class RU_representative_cycles const std::vector& get_representative_cycles(); /** * @brief Returns the representative cycle corresponding to the given bar. - * If the matrix is modified later after the first call, - * @ref update_representative_cycles has to be called to update the returned cycles. + * If the matrix was modified since the last call, @ref update_representative_cycles or + * @ref update_representative_cycle has to be called to update the returned cycle. * * @param bar Bar corresponding to the wanted representative cycle. * @return A const reference to the representative cycle. @@ -99,12 +114,12 @@ class RU_representative_cycles private: using Master_RU_matrix = typename Master_matrix::Master_RU_matrix; using Inverse_column = Cycle; + using Content_range = typename Master_matrix::Column::Content_range; std::vector representativeCycles_; /**< Cycle container. */ std::vector birthToCycle_; /**< Map from birth index to cycle index. */ constexpr Master_RU_matrix* _matrix() { return static_cast(this); } - constexpr const Master_RU_matrix* _matrix() const { return static_cast(this); } void _retrieve_cycle_from_r(Index colIdx, Index repIdx); @@ -113,9 +128,9 @@ class RU_representative_cycles }; template -inline void RU_representative_cycles::update_representative_cycles() +inline void RU_representative_cycles::update_representative_cycles(Dimension dim) { - auto nberColumns = _matrix()->reducedMatrixR_.get_number_of_columns(); + Index nberColumns = _matrix()->reducedMatrixR_.get_number_of_columns(); Index nullValue = Master_matrix::template get_null_value(); representativeCycles_.clear(); birthToCycle_.clear(); @@ -123,13 +138,27 @@ inline void RU_representative_cycles::update_representative_cycle Index c = 0; for (Index i = 0; i < nberColumns; i++) { - if (_matrix()->reducedMatrixR_.is_zero_column(i)) { + if ((dim == Master_matrix::template get_null_value() || + _matrix()->reducedMatrixR_.get_column_dimension(i) == dim) && + _matrix()->reducedMatrixR_.is_zero_column(i)) { birthToCycle_[i] = c; ++c; } } representativeCycles_.resize(c); +#ifdef GUDHI_USE_TBB + tbb::parallel_for(static_cast(0), nberColumns, [&](Index i) { + if (birthToCycle_[i] != nullValue) { + Index colIdx = _matrix()->_get_column_with_pivot(i); + if (colIdx == nullValue) { + _retrieve_cycle_from_u(i, birthToCycle_[i]); + } else { + _retrieve_cycle_from_r(colIdx, birthToCycle_[i]); + } + } + }); +#else for (Index i = 0; i < nberColumns; ++i) { if (birthToCycle_[i] != nullValue) { Index colIdx = _matrix()->_get_column_with_pivot(i); @@ -140,13 +169,34 @@ inline void RU_representative_cycles::update_representative_cycle } } } +#endif +} + +template +inline void RU_representative_cycles::update_representative_cycle(const Bar& bar) +{ + Index nullValue = Master_matrix::template get_null_value(); + + if (birthToCycle_.size() <= bar.birth) { + birthToCycle_.resize(bar.birth + 1, nullValue); + } + if (birthToCycle_[bar.birth] == nullValue) { + birthToCycle_[bar.birth] = representativeCycles_.size(); + representativeCycles_.resize(representativeCycles_.size() + 1); + } + + Index colIdx = _matrix()->_get_column_with_pivot(bar.birth); + if (colIdx == nullValue) { + _retrieve_cycle_from_u(bar.birth, birthToCycle_[bar.birth]); + } else { + _retrieve_cycle_from_r(colIdx, birthToCycle_[bar.birth]); + } } template inline const std::vector::Cycle>& RU_representative_cycles::get_representative_cycles() { - if (representativeCycles_.empty()) update_representative_cycles(); return representativeCycles_; } @@ -154,38 +204,14 @@ template inline const typename RU_representative_cycles::Cycle& RU_representative_cycles::get_representative_cycle(const Bar& bar) { - if (representativeCycles_.empty()) update_representative_cycles(); return representativeCycles_[birthToCycle_[bar.birth]]; } template inline void RU_representative_cycles::_retrieve_cycle_from_r(Index colIdx, Index repIdx) { - if constexpr (is_well_behaved::value) { - const auto& col = _matrix()->reducedMatrixR_.get_column(colIdx); - representativeCycles_[repIdx].resize(col.size()); - Index j = 0; - for (const auto& cell : col) { - if constexpr (Master_matrix::Option_list::is_z2) { - representativeCycles_[repIdx][j] = cell.get_row_index(); - } else { - representativeCycles_[repIdx][j].first = cell.get_row_index(); - representativeCycles_[repIdx][j].second = cell.get_element(); - } - ++j; - } - } else { - auto col = _matrix()->reducedMatrixR_.get_column(colIdx).get_content(); - for (Index j = 0; j < col.size(); ++j) { - if (col[j] != 0) { - if constexpr (Master_matrix::Option_list::is_z2) { - representativeCycles_[repIdx].push_back(j); - } else { - representativeCycles_[repIdx].push_back({j, col[j]}); - } - } - } - } + auto& col = _matrix()->reducedMatrixR_.get_column(colIdx); + representativeCycles_[repIdx] = Master_matrix::build_cycle_from_range(col.get_non_zero_content_range()); } template @@ -225,19 +251,12 @@ RU_representative_cycles::_get_inverse(Index c) }; auto _substract = [&](E& e, auto resIt, const auto& cell) -> void { - if constexpr (Master_matrix::Option_list::is_z2) { - if (resIt != res.rend() && *resIt == cell.get_row_index()) e = !e; - } else { - if (resIt != res.rend() && resIt->first == cell.get_row_index()) - op->subtract_inplace_front(e, cell.get_element() * resIt->second); - } - }; - - auto _substract_vec = [&](E& e, auto p, auto line) -> void { - if constexpr (Master_matrix::Option_list::is_z2) { - if (line[p]) e = !e; - } else { - if (line[p.first]) op->subtract_inplace_front(e, line[p.first] * p.second); + if (resIt != res.rend() && Master_matrix::get_row_index(*resIt) == cell.get_row_index()) { + if constexpr (Master_matrix::Option_list::is_z2) { + e = !e; + } else { + op->subtract_inplace_front(e, cell.get_element() * Master_matrix::get_element(*resIt)); + } } }; @@ -249,59 +268,31 @@ RU_representative_cycles::_get_inverse(Index c) } }; - auto _assign = [&](E& e, const auto& cell) -> void { - if constexpr (Master_matrix::Option_list::is_z2) { - e = !e; - } else { - e = cell.get_element(); - } - }; - - auto _get_index = [&](auto resIt) { - if constexpr (Master_matrix::Option_list::is_z2) { - return *resIt; - } else { - return resIt->first; - } - }; - auto _translate = [&](std::size_t i) -> void { const auto& map = _matrix()->positionToID_; - if constexpr (Master_matrix::Option_list::is_z2) { - auto it = map.find(res[i]); - if (it != map.end()) res[i] = it->second; - } else { - auto it = map.find(res[i].first); - if (it != map.end()) res[i].first = it->second; - } + auto& idx = Master_matrix::get_row_index(res[i]); + auto it = map.find(idx); + if (it != map.end()) idx = it->second; }; if (c == size - 1) _push_cell(size - 1, _last_diagonal_value()); for (int i = size - 2; i >= 0; --i) { E e = static_cast(c) == i; - // ugly...... - if constexpr (is_well_behaved::value) { - const auto& line = matrix.get_column(i); - auto resIt = res.rbegin(); - auto lineIt = line.begin(); - E diag(0); - if (static_cast(lineIt->get_row_index()) == i) { - _assign(diag, *lineIt); - ++lineIt; - } - while (lineIt != line.end() && resIt != res.rend()) { - while (resIt != res.rend() && _get_index(resIt) < lineIt->get_row_index()) ++resIt; - _substract(e, resIt, *lineIt); - ++lineIt; - } - _multiply(e, diag); - } else { - auto line = matrix.get_column(i).get_content(size); // linear... - for (const auto& p : res) { - _substract_vec(e, p, line); - } - _multiply(e, line[i]); + auto& line = matrix.get_column(i); + Content_range r = line.get_non_zero_content_range(); + auto resIt = res.rbegin(); + auto lineIt = r.begin(); + E diag(0); + if (static_cast(lineIt->get_row_index()) == i) { + diag = lineIt->get_element(); + ++lineIt; + } + while (lineIt != r.end() && resIt != res.rend()) { + while (resIt != res.rend() && Master_matrix::get_row_index(*resIt) < lineIt->get_row_index()) ++resIt; + _substract(e, resIt, *lineIt); + ++lineIt; } + _multiply(e, diag); _push_cell(i, e); } diff --git a/multipers/gudhi/gudhi/Persistence_matrix/ru_vine_swap.h b/multipers/gudhi/gudhi/Persistence_matrix/ru_vine_swap.h index d073a770..08b2700d 100644 --- a/multipers/gudhi/gudhi/Persistence_matrix/ru_vine_swap.h +++ b/multipers/gudhi/gudhi/Persistence_matrix/ru_vine_swap.h @@ -19,8 +19,8 @@ #ifndef PM_RU_VINE_SWAP_H #define PM_RU_VINE_SWAP_H -#include //std::move #include +#include //std::move #include //std::invalid_argument #include @@ -326,12 +326,11 @@ inline bool RU_vine_swap::_is_paired(Index columnIndex) if (!_matrix()->reducedMatrixR_.is_zero_column(columnIndex)) return true; if constexpr (Master_matrix::Option_list::has_map_column_container) { - if (_matrix()->pivotToColumnIndex_.find(columnIndex) == _matrix()->pivotToColumnIndex_.end()) return false; + return _matrix()->pivotToColumnIndex_.find(columnIndex) != _matrix()->pivotToColumnIndex_.end(); } else { - if (_matrix()->pivotToColumnIndex_[columnIndex] == Master_matrix::template get_null_value()) return false; + if (_matrix()->pivotToColumnIndex_.size() <= columnIndex) return false; + return _matrix()->pivotToColumnIndex_[columnIndex] != Master_matrix::template get_null_value(); } - - return true; } } @@ -367,7 +366,13 @@ inline void RU_vine_swap::_positive_transpose(Index columnIndex) _matrix()->pivotToColumnIndex_.erase(columnIndex + 1); } } else { - std::swap(_matrix()->pivotToColumnIndex_[columnIndex], _matrix()->pivotToColumnIndex_[columnIndex + 1]); + if (_is_paired(columnIndex) || _is_paired(columnIndex + 1)) { + if (columnIndex + 1 >= _matrix()->pivotToColumnIndex_.size()) { + // pivotToColumnIndex_ has at least size columnIndex + 1 + _matrix()->pivotToColumnIndex_.push_back(Master_matrix::template get_null_value()); + } + std::swap(_matrix()->pivotToColumnIndex_[columnIndex], _matrix()->pivotToColumnIndex_[columnIndex + 1]); + } } if constexpr (Master_matrix::Option_list::has_column_pairings) { @@ -381,22 +386,34 @@ inline void RU_vine_swap::_negative_transpose(Index columnIndex) if constexpr (Master_matrix::Option_list::has_column_pairings) { _matrix()->_negative_transpose_barcode(columnIndex); } - std::swap(_matrix()->pivotToColumnIndex_.at(_get_birth(columnIndex)), - _matrix()->pivotToColumnIndex_.at(_get_birth(columnIndex + 1))); + if constexpr (Master_matrix::Option_list::has_map_column_container) { + std::swap(_matrix()->pivotToColumnIndex_.at(_get_birth(columnIndex)), + _matrix()->pivotToColumnIndex_.at(_get_birth(columnIndex + 1))); + } else { + std::swap(_matrix()->pivotToColumnIndex_[_get_birth(columnIndex)], + _matrix()->pivotToColumnIndex_[_get_birth(columnIndex + 1)]); + } } template inline void RU_vine_swap::_positive_negative_transpose(Index columnIndex) { - _matrix()->pivotToColumnIndex_.at(_get_birth(columnIndex + 1)) = columnIndex; if constexpr (Master_matrix::Option_list::has_map_column_container) { + _matrix()->pivotToColumnIndex_.at(_get_birth(columnIndex + 1)) = columnIndex; if (_is_paired(columnIndex)) { _matrix()->pivotToColumnIndex_.emplace(columnIndex + 1, _matrix()->pivotToColumnIndex_.at(columnIndex)); _matrix()->pivotToColumnIndex_.erase(columnIndex); } } else { - _matrix()->pivotToColumnIndex_[columnIndex + 1] = _matrix()->pivotToColumnIndex_[columnIndex]; - _matrix()->pivotToColumnIndex_[columnIndex] = Master_matrix::template get_null_value(); + _matrix()->pivotToColumnIndex_[_get_birth(columnIndex + 1)] = columnIndex; + if (_is_paired(columnIndex)){ + if (columnIndex + 1 >= _matrix()->pivotToColumnIndex_.size()) { + // pivotToColumnIndex_ has at least size columnIndex + 1 + _matrix()->pivotToColumnIndex_.push_back(Master_matrix::template get_null_value()); + } + _matrix()->pivotToColumnIndex_[columnIndex + 1] = _matrix()->pivotToColumnIndex_[columnIndex]; + _matrix()->pivotToColumnIndex_[columnIndex] = Master_matrix::template get_null_value(); + } } if constexpr (Master_matrix::Option_list::has_column_pairings) { @@ -407,15 +424,18 @@ inline void RU_vine_swap::_positive_negative_transpose(Index colu template inline void RU_vine_swap::_negative_positive_transpose(Index columnIndex) { - _matrix()->pivotToColumnIndex_.at(_get_birth(columnIndex)) = columnIndex + 1; if constexpr (Master_matrix::Option_list::has_map_column_container) { + _matrix()->pivotToColumnIndex_.at(_get_birth(columnIndex)) = columnIndex + 1; if (_is_paired(columnIndex + 1)) { _matrix()->pivotToColumnIndex_.emplace(columnIndex, _matrix()->pivotToColumnIndex_.at(columnIndex + 1)); _matrix()->pivotToColumnIndex_.erase(columnIndex + 1); } } else { - _matrix()->pivotToColumnIndex_[columnIndex] = _matrix()->pivotToColumnIndex_[columnIndex + 1]; - _matrix()->pivotToColumnIndex_[columnIndex + 1] = Master_matrix::template get_null_value(); + _matrix()->pivotToColumnIndex_[_get_birth(columnIndex)] = columnIndex + 1; + if (_is_paired(columnIndex + 1)){ + _matrix()->pivotToColumnIndex_[columnIndex] = _matrix()->pivotToColumnIndex_[columnIndex + 1]; + _matrix()->pivotToColumnIndex_[columnIndex + 1] = Master_matrix::template get_null_value(); + } } if constexpr (Master_matrix::Option_list::has_column_pairings) { @@ -479,8 +499,8 @@ inline bool RU_vine_swap::_positive_negative_vine_swap(Index colu { _matrix()->mirrorMatrixU_.zero_entry(columnIndex, _get_row_id_from_position(columnIndex + 1)); - _swap_at_index(columnIndex); _positive_negative_transpose(columnIndex); + _swap_at_index(columnIndex); return true; } @@ -509,6 +529,8 @@ inline typename RU_vine_swap::Pos_index RU_vine_swappivotToColumnIndex_.end()) return Master_matrix::template get_null_value(); return it->second; } else { + if (simplexIndex >= _matrix()->pivotToColumnIndex_.size()) + return Master_matrix::template get_null_value(); return _matrix()->pivotToColumnIndex_[simplexIndex]; } } diff --git a/multipers/gudhi/gudhi/persistence_matrix_options.h b/multipers/gudhi/gudhi/persistence_matrix_options.h index d349b344..3fcadc02 100644 --- a/multipers/gudhi/gudhi/persistence_matrix_options.h +++ b/multipers/gudhi/gudhi/persistence_matrix_options.h @@ -17,8 +17,7 @@ #ifndef PM_OPTIONS_INCLUDED #define PM_OPTIONS_INCLUDED -#include -#include +#include // std::uint8_t #include @@ -45,20 +44,6 @@ enum class Column_types : std::uint8_t { INTRUSIVE_SET /**< @ref Intrusive_set_column "": Underlying container is a boost::intrusive::set<@ref Entry>. */ }; -// a column is said to behave well if its underlying content is alway ordered by increasing row index -// and iterators cannot iterate over zero cells. -template -struct is_well_behaved : std::true_type {}; - -template <> -struct is_well_behaved : std::false_type {}; // non ordered - -template <> -struct is_well_behaved : std::false_type {}; // lazy row clear - -template <> -struct is_well_behaved : std::false_type {}; // non ordered - /** * @ingroup persistence_matrix * @@ -177,6 +162,26 @@ struct Cohomology_persistence_options : Default_options +class RangeTraits +{ + private: + static auto check_begin(...) -> std::false_type; + template + static auto check_begin(const U& x) -> decltype(x.begin(), std::true_type{}); + + static auto check_size(...) -> std::false_type; + template + static auto check_size(const U& x) -> decltype(x.size(), std::true_type{}); + + public: + static constexpr bool has_begin = decltype(check_begin(std::declval()))::value; + static constexpr bool has_size = decltype(check_size(std::declval()))::value; +}; + } // namespace persistence_matrix } // namespace Gudhi From afb184606b13ab405fc5818e7f647e555742585a Mon Sep 17 00:00:00 2001 From: hschreiber Date: Fri, 19 Dec 2025 16:36:28 +0100 Subject: [PATCH 2/3] update c++ filtration values --- multipers/gudhi/gudhi/Degree_rips_bifiltration.h | 9 +++++---- .../gudhi/gudhi/Dynamic_multi_parameter_filtration.h | 9 +++++---- .../Multi_filtration/Multi_parameter_generator.h | 9 +++++---- .../Multi_filtration/multi_filtration_conversions.h | 2 +- multipers/gudhi/gudhi/Multi_parameter_filtration.h | 12 +++++------- 5 files changed, 21 insertions(+), 20 deletions(-) diff --git a/multipers/gudhi/gudhi/Degree_rips_bifiltration.h b/multipers/gudhi/gudhi/Degree_rips_bifiltration.h index 711fc376..14cb11ef 100644 --- a/multipers/gudhi/gudhi/Degree_rips_bifiltration.h +++ b/multipers/gudhi/gudhi/Degree_rips_bifiltration.h @@ -1710,10 +1710,11 @@ class Degree_rips_bifiltration for (size_type g = 0; g < num_generators(); ++g) { GUDHI_CHECK_code(GUDHI_CHECK(static_cast(indices[g]) == g, std::invalid_argument("Unvalid grid."))); - auto d = std::distance( - values.begin(), - std::lower_bound( - values.begin(), values.end(), static_cast(generators_[g]))); + auto v = static_cast(generators_[g]); + auto d = std::distance(values.begin(), std::lower_bound(values.begin(), values.end(), v)); + if (d != 0 && std::abs(v - values[d]) > std::abs(v - values[d - 1])) { + --d; + } generators_[g] = coordinate ? static_cast(d) : static_cast(values[d]); } } diff --git a/multipers/gudhi/gudhi/Dynamic_multi_parameter_filtration.h b/multipers/gudhi/gudhi/Dynamic_multi_parameter_filtration.h index f0d49f37..7694727d 100644 --- a/multipers/gudhi/gudhi/Dynamic_multi_parameter_filtration.h +++ b/multipers/gudhi/gudhi/Dynamic_multi_parameter_filtration.h @@ -46,9 +46,10 @@ namespace Gudhi::multi_filtration { * \f$\mathbb R^n\f$-filtration value. E.g., the filtration value of a simplex, or, of the algebraic generator of a * module presentation. Different from @ref Multi_parameter_filtration, the underlying container is a vector of vectors * and therefore less memory efficient, but much more flexible when modifying the filtration value. So, this class is - * preferable if a lot of generators need to be added on the fly or removed. When the filtration values are fixed or - * 1-critical, we recommend @ref Multi_parameter_filtration instead. Implements the concept @ref FiltrationValue of the - * @ref Gudhi::Simplex_tree and the concept @ref Gudhi::multi_persistence::MultiFiltrationValue. + * preferable if a lot of generators need to be added on the fly or removed. But when the filtration value is more or + * less fixed, e.g. for 1-critical filtrations, we recommend @ref Multi_parameter_filtration instead. Implements + * the concept @ref FiltrationValue of the @ref Gudhi::Simplex_tree and the concept + * @ref Gudhi::multi_persistence::MultiFiltrationValue. * * @details Overloads `std::numeric_limits` such that: * - `std::numeric_limits::has_infinity` returns `true`, @@ -513,7 +514,7 @@ class Dynamic_multi_parameter_filtration * @brief Returns the total number of values in the filtration value, that is, * @ref num_parameters() * @ref num_generators(). */ - size_type num_entries() const { return num_generators() * num_parameters(); } + size_type num_entries() const { return generators_.size() * number_of_parameters_; } /** * @brief Returns a filtration value with given number of parameters for which @ref is_plus_inf() returns `true` diff --git a/multipers/gudhi/gudhi/Multi_filtration/Multi_parameter_generator.h b/multipers/gudhi/gudhi/Multi_filtration/Multi_parameter_generator.h index be279faf..a309705d 100644 --- a/multipers/gudhi/gudhi/Multi_filtration/Multi_parameter_generator.h +++ b/multipers/gudhi/gudhi/Multi_filtration/Multi_parameter_generator.h @@ -1370,10 +1370,11 @@ class Multi_parameter_generator for (size_type p = 0; p < generator_.size(); ++p) { const auto &filtration = grid[p]; - auto d = std::distance( - filtration.begin(), - std::lower_bound( - filtration.begin(), filtration.end(), static_cast(generator_[p]))); + auto v = static_cast(generator_[p]); + auto d = std::distance(filtration.begin(), std::lower_bound(filtration.begin(), filtration.end(), v)); + if (d != 0 && std::abs(v - filtration[d]) > std::abs(v - filtration[d - 1])) { + --d; + } generator_[p] = coordinate ? static_cast(d) : static_cast(filtration[d]); } } diff --git a/multipers/gudhi/gudhi/Multi_filtration/multi_filtration_conversions.h b/multipers/gudhi/gudhi/Multi_filtration/multi_filtration_conversions.h index 6d140d28..f3968f1a 100644 --- a/multipers/gudhi/gudhi/Multi_filtration/multi_filtration_conversions.h +++ b/multipers/gudhi/gudhi/Multi_filtration/multi_filtration_conversions.h @@ -66,7 +66,7 @@ Out_multi_filtration as_type(const Multi_parameter_filtration values(maxIndex + 1, inf); for (std::size_t g = 0; g < f.num_generators(); ++g) { values[f(g, 1)] = f(g, 0); diff --git a/multipers/gudhi/gudhi/Multi_parameter_filtration.h b/multipers/gudhi/gudhi/Multi_parameter_filtration.h index b1c1b053..a9667903 100644 --- a/multipers/gudhi/gudhi/Multi_parameter_filtration.h +++ b/multipers/gudhi/gudhi/Multi_parameter_filtration.h @@ -18,7 +18,7 @@ #define MF_MULTI_PARAMETER_FILTRATION_H_ #include //std::lower_bound -#include //std::isnan, std::min +#include //std::isnan, std::min, std::abs #include //std::size_t #include //std::int32_t, std::uint8_t #include //memcpy @@ -1776,13 +1776,11 @@ class Multi_parameter_filtration std::invalid_argument("The grid should not be smaller than the number of parameters in the filtration value.")); auto project_generator_value = [&](T &val, const OneDimArray &filtration) { - typename OneDimArray::value_type _val = static_cast(val); - auto d = std::distance( - filtration.begin(), - std::lower_bound(filtration.begin(), filtration.end(), _val)); - if (std::abs(_val - filtration[d]) > - std::abs(_val - filtration[d == 0 ? 0 : d - 1])) + auto v = static_cast(val); + auto d = std::distance(filtration.begin(), std::lower_bound(filtration.begin(), filtration.end(), v)); + if (d != 0 && std::abs(v - filtration[d]) > std::abs(v - filtration[d - 1])) { --d; + } val = coordinate ? static_cast(d) : static_cast(filtration[d]); }; From 5fa2ddcb43696e1327dff400ddc8f8769bd7c5f6 Mon Sep 17 00:00:00 2001 From: hschreiber Date: Fri, 19 Dec 2025 20:06:37 +0100 Subject: [PATCH 3/3] update C++ + slicer constructor with different templates --- .../gudhi/Multi_parameter_filtered_complex.h | 102 ++++++++++++++---- multipers/gudhi/gudhi/Multi_persistence/Box.h | 63 +++++++---- .../Persistence_interface_matrix.h | 2 +- .../gudhi/gudhi/Projective_cover_kernel.h | 16 +-- multipers/gudhi/gudhi/Slicer.h | 31 +++++- multipers/gudhi/gudhi/Thread_safe_slicer.h | 5 + .../approximation.h | 8 +- 7 files changed, 174 insertions(+), 53 deletions(-) diff --git a/multipers/gudhi/gudhi/Multi_parameter_filtered_complex.h b/multipers/gudhi/gudhi/Multi_parameter_filtered_complex.h index ed7df0c8..82ce35ad 100644 --- a/multipers/gudhi/gudhi/Multi_parameter_filtered_complex.h +++ b/multipers/gudhi/gudhi/Multi_parameter_filtered_complex.h @@ -22,13 +22,13 @@ #include #include #include -#include #include #include #include #include #include //for lex order +#include namespace Gudhi { namespace multi_persistence { @@ -108,6 +108,67 @@ class Multi_parameter_filtered_complex _initialize_dimension_utils(); } + /** + * @brief Copy constructor. + */ + Multi_parameter_filtered_complex(const Multi_parameter_filtered_complex& complex) = default; + + /** + * @brief Copy constructor. + */ + template + Multi_parameter_filtered_complex(const Multi_parameter_filtered_complex& complex) + : boundaries_(complex.get_boundaries()), + dimensions_(complex.get_dimensions()), + filtrationValues_(complex.get_filtration_values().size()), + maxDimension_(complex.get_max_dimension()), + isOrderedByDimension_(complex.is_ordered_by_dimension()) + { + const auto& fils = complex.get_filtration_values(); + for (Index i = 0; i < filtrationValues_.size(); ++i) { + filtrationValues_[i] = multi_filtration::as_type(fils[i]); + } + } + + /** + * @brief Move constructor. + */ + Multi_parameter_filtered_complex(Multi_parameter_filtered_complex&& complex) noexcept = default; + + /** + * @brief Destructor. + */ + ~Multi_parameter_filtered_complex() = default; + + /** + * @brief Assign operator. + */ + Multi_parameter_filtered_complex& operator=(const Multi_parameter_filtered_complex& other) = default; + + /** + * @brief Assign operator. + */ + template + Multi_parameter_filtered_complex& operator=(const Multi_parameter_filtered_complex& other) + { + boundaries_ = other.get_boundaries(); + dimensions_ = other.get_dimensions(); + const auto& fils = other.get_filtration_values(); + filtrationValues_ = Filtration_value_container(fils.size()); + for (Index i = 0; i < filtrationValues_.size(); ++i) { + filtrationValues_[i] = multi_filtration::as_type(fils[i]); + } + maxDimension_ = other.get_max_dimension(); + isOrderedByDimension_ = other.is_ordered_by_dimension(); + + return *this; + } + + /** + * @brief Move assign operator. + */ + Multi_parameter_filtered_complex& operator=(Multi_parameter_filtered_complex&& other) noexcept = default; + /** * @brief Returns the number of cells in the complex. */ @@ -265,32 +326,35 @@ class Multi_parameter_filtered_complex * @brief Builds a new complex by reordering the cells in the given complex with the given permutation map. */ friend Multi_parameter_filtered_complex build_permuted_complex(const Multi_parameter_filtered_complex& complex, - const std::vector& permutation) { + const std::vector& permutation) + { if (permutation.size() > complex.get_number_of_cycle_generators()) - throw std::invalid_argument("Invalid permutation size. Got perm size: " + std::to_string(permutation.size()) + - " while complex size: " + std::to_string(complex.get_number_of_cycle_generators())); + throw std::invalid_argument("Invalid permutation size."); - const Index flag = -1; - std::vector inv(complex.get_number_of_cycle_generators(), flag); + const Index nullIndex = -1; + std::vector inv(complex.get_number_of_cycle_generators(), nullIndex); for (Index i = 0; i < permutation.size(); ++i) inv[permutation[i]] = i; - Boundary_container newGenerators(permutation.size()); - Dimension_container newGeneratorDimensions(permutation.size()); - Filtration_value_container newFiltrationValues(permutation.size()); - - for (Index i = 0; i < permutation.size(); ++i) { - const auto& boundary = complex.boundaries_[permutation[i]]; - newGenerators[i].reserve(boundary.size()); - for (Index b : boundary) { - if (inv[b] != flag) newGenerators[i].push_back(inv[b]); + Boundary_container newBoundaries; + newBoundaries.reserve(permutation.size()); + Dimension_container newDimensions; + newDimensions.reserve(permutation.size()); + Filtration_value_container newFiltrationValues; + newBoundaries.reserve(permutation.size()); + + for (Index i : permutation) { + Boundary boundary; + for (Index b : complex.boundaries_[i]) { + if (inv[b] != nullIndex) boundary.push_back(inv[b]); } - std::sort(newGenerators[i].begin(), newGenerators[i].end()); - newGeneratorDimensions[i] = complex.dimensions_[permutation[i]]; - newFiltrationValues[i] = complex.filtrationValues_[permutation[i]]; + std::sort(boundary.begin(), boundary.end()); + newBoundaries.emplace_back(std::move(boundary)); + newDimensions.push_back(complex.dimensions_[i]); + newFiltrationValues.emplace_back(complex.filtrationValues_[i]); } return Multi_parameter_filtered_complex( - std::move(newGenerators), std::move(newGeneratorDimensions), std::move(newFiltrationValues)); + std::move(newBoundaries), std::move(newDimensions), std::move(newFiltrationValues)); } /** diff --git a/multipers/gudhi/gudhi/Multi_persistence/Box.h b/multipers/gudhi/gudhi/Multi_persistence/Box.h index a300cd96..4bb18459 100644 --- a/multipers/gudhi/gudhi/Multi_persistence/Box.h +++ b/multipers/gudhi/gudhi/Multi_persistence/Box.h @@ -37,7 +37,8 @@ namespace multi_persistence { * @tparam T Type of the coordinates of the Box. */ template -class Box { +class Box +{ public: using Point_t = Point; /**< Type of a point in \f$\mathbb R^n\f$. */ @@ -53,7 +54,8 @@ class Box { * @param lowerCorner First corner of the box. Has to be smaller than `upperCorner`. * @param upperCorner Second corner of the box. Has to be greater than `lowerCorner`. */ - Box(const Point_t &lowerCorner, const Point_t &upperCorner) : lowerCorner_(lowerCorner), upperCorner_(upperCorner) { + Box(const Point_t &lowerCorner, const Point_t &upperCorner) : lowerCorner_(lowerCorner), upperCorner_(upperCorner) + { GUDHI_CHECK(lowerCorner.size() == upperCorner.size(), std::invalid_argument("The two corners of the box don't have the same dimension.")); // GUDHI_CHECK(lowerCorner <= upperCorner, std::invalid_argument("The first corner is not smaller than the @@ -107,7 +109,8 @@ class Box { * * Throws if both corners don't have the same dimension. */ - [[nodiscard]] bool is_trivial() const { + [[nodiscard]] bool is_trivial() const + { if (lowerCorner_.size() == 0 || upperCorner_.size() == 0) return true; if (lowerCorner_.size() != upperCorner_.size()) throw std::logic_error("Upper and lower corner do not have the same dimension"); @@ -133,7 +136,8 @@ class Box { /** * @brief Returns true if and only if the given point is inside the box. */ - bool contains(const Point_t &point) const { + bool contains(const Point_t &point) const + { GUDHI_CHECK(point.size() == lowerCorner_.size(), std::invalid_argument("Point should not have a different dimension than the box.")); @@ -152,14 +156,15 @@ class Box { /** * @brief Returns the dimension of the box. */ - [[nodiscard]] std::size_t dimension() const { return lowerCorner_.size(); } + [[nodiscard]] std::size_t get_dimension() const { return lowerCorner_.size(); } /** * @brief Inflates the box by delta. * * @param delta Inflation coefficient. */ - void inflate(T delta) { + void inflate(T delta) + { lowerCorner_ -= delta; upperCorner_ += delta; } @@ -167,7 +172,8 @@ class Box { /** * @brief Equality operator. Two boxes are equal if and only if both defining corners are equal. */ - friend bool operator==(const Box &a, const Box &b) { + friend bool operator==(const Box &a, const Box &b) + { return a.upperCorner_ == b.upperCorner_ && a.lowerCorner_ == b.lowerCorner_; } @@ -179,7 +185,8 @@ class Box { /** * @brief Outstream operator. */ - friend std::ostream &operator<<(std::ostream &os, const Box &box) { + friend std::ostream &operator<<(std::ostream &os, const Box &box) + { os << "Box -- Bottom corner : "; os << box.get_lower_corner(); os << ", Top corner : "; @@ -187,25 +194,39 @@ class Box { return os; } - template - friend Box smallest_enclosing_box(const Box &a, const Box &b); + /** + * @brief Returns the smallest box enclosing both given boxes. Both boxes have to have the same dimension. + * If one of the boxes is trivial, returns the other box. If both are trivial, returns an empty box. + */ + friend Box get_smallest_enclosing_box(const Box &a, const Box &b) + { + if (a.is_trivial()) { + if (b.is_trivial()) return Box(); + return b; + } + if (b.is_trivial()) return a; + + GUDHI_CHECK(a.get_dimension() == b.get_dimension(), "Both boxes to enclose do not have the same dimension."); + + Point_t lower(a.get_dimension()); + Point_t upper(a.get_dimension()); + const auto &aLower = a.get_lower_corner(); + const auto &aUpper = a.get_upper_corner(); + const auto &bLower = b.get_lower_corner(); + const auto &bUpper = b.get_upper_corner(); + for (unsigned int i = 0; i < a.get_dimension(); ++i) { + lower[i] = std::min(aLower[i], bLower[i]); + upper[i] = std::max(aUpper[i], bUpper[i]); + } + + return Box(lower, upper); + } private: Point_t lowerCorner_; /**< Lowest of defining corners. */ Point_t upperCorner_; /**< Greatest of defining corners. */ }; -template -Box smallest_enclosing_box(const Box &a, const Box &b) { - Box box; - auto &lower = box.get_lower_corner(); - auto &upper = box.get_upper_corner(); - for (unsigned int i = 0; i < a.dimension(); ++i) { - lower[i] = std::min(a.get_lower_corner()[i], b.get_lower_corner()[i]); - upper[i] = std::max(a.get_upper_corner()[i], b.get_upper_corner()[i]); - } - return box; -} } // namespace multi_persistence } // namespace Gudhi diff --git a/multipers/gudhi/gudhi/Multi_persistence/Persistence_interface_matrix.h b/multipers/gudhi/gudhi/Multi_persistence/Persistence_interface_matrix.h index 3b9d90f6..be772506 100644 --- a/multipers/gudhi/gudhi/Multi_persistence/Persistence_interface_matrix.h +++ b/multipers/gudhi/gudhi/Multi_persistence/Persistence_interface_matrix.h @@ -312,7 +312,7 @@ class Persistence_interface_matrix matrix_ = Matrix(); permutation_ = nullptr; if constexpr (Options::has_vine_update && !Options::is_of_boundary_type) { - idToPos_->clear(); + if (idToPos_) idToPos_->clear(); } } diff --git a/multipers/gudhi/gudhi/Projective_cover_kernel.h b/multipers/gudhi/gudhi/Projective_cover_kernel.h index c490b8b6..aff972d7 100644 --- a/multipers/gudhi/gudhi/Projective_cover_kernel.h +++ b/multipers/gudhi/gudhi/Projective_cover_kernel.h @@ -18,8 +18,8 @@ #ifndef MP_PROJECTIVE_COVER_KERNEL_H_INCLUDED #define MP_PROJECTIVE_COVER_KERNEL_H_INCLUDED -#include -#include //std::move +#include //std::invalid_argument, std::runtime_error +#include //std::move #include #include @@ -84,13 +84,16 @@ class Projective_cover_kernel GUDHI_CHECK_code( Index i = 0; for (; i < complex.get_number_of_cycle_generators() - 1; ++i) { - GUDHI_CHECK(filtValues[i].num_generators() == 1, std::invalid_argument("Only available for 1-critical modules.")); - GUDHI_CHECK(dimensions[i] <= dimensions[i + 1], std::invalid_argument("Cells have to be ordered by dimension.")); + GUDHI_CHECK(filtValues[i].num_generators() == 1, + std::invalid_argument("Only available for 1-critical modules.")); + GUDHI_CHECK(dimensions[i] <= dimensions[i + 1], + std::invalid_argument("Cells have to be ordered by dimension.")); if (dimensions[i] == dimensions[i + 1]) GUDHI_CHECK(is_less_or_equal_than_lexicographically(filtValues[i], filtValues[i + 1]), std::invalid_argument("Cells with same dimension have to be ordered co-lexicographically.")); } - GUDHI_CHECK(filtValues[i].num_generators() == 1, std::invalid_argument("Only available for 1-critical modules.")); + GUDHI_CHECK(filtValues[i].num_generators() == 1, + std::invalid_argument("Only available for 1-critical modules.")); ) Index startDim1, startDim2, end; @@ -286,7 +289,8 @@ class Projective_cover_kernel it++; for (; it != pivotCache[pivot].end(); ++it) { int colIdx = *it; - GUDHI_CHECK(static_cast(colIdx) > i, std::runtime_error("(update) Column not registered in the right order.")); + GUDHI_CHECK(static_cast(colIdx) > i, + std::runtime_error("(update) Column not registered in the right order.")); auto prev = filtValues[colIdx]; if (!(prev >= filtValues[i])) { prev.push_to_least_common_upper_bound(filtValues[i]); diff --git a/multipers/gudhi/gudhi/Slicer.h b/multipers/gudhi/gudhi/Slicer.h index 41b32e09..8ab00df9 100644 --- a/multipers/gudhi/gudhi/Slicer.h +++ b/multipers/gudhi/gudhi/Slicer.h @@ -136,6 +136,17 @@ class Slicer : complex_(other.complex_), slice_(other.slice_), generatorOrder_(other.generatorOrder_), persistence_() {} + /** + * @brief Copy constructor. Persistence computation initialization is not updated. + */ + template + Slicer(const Slicer& other) + : complex_(other.get_filtered_complex()), + slice_(other.get_slice().begin(), other.get_slice().end()), + generatorOrder_(other.get_current_order()), + persistence_() + {} + /** * @brief Move constructor. Persistence computation initialization is not updated. */ @@ -161,6 +172,20 @@ class Slicer return *this; } + /** + * @brief Assign operator. Persistence computation initialization is not updated. + */ + template + Slicer& operator=(const Slicer& other) + { + complex_ = other.get_filtered_complex(); + slice_ = std::vector(other.get_slice().begin(), other.get_slice().end()); + generatorOrder_ = other.get_current_order(); + persistence_.reset(); + + return *this; + } + /** * @brief Move assign operator. Persistence computation initialization is not updated. */ @@ -195,8 +220,10 @@ class Slicer */ Index get_number_of_parameters() const { return complex_.get_number_of_parameters(); } - // // only used for scc io for now - // const Complex& get_chain_complex() const { return complex_; } + /** + * @brief Returns the underlying complex. + */ + const Complex& get_filtered_complex() const { return complex_; } /** * @brief Returns a const reference to the current permutation map, indicating in which order are the generators diff --git a/multipers/gudhi/gudhi/Thread_safe_slicer.h b/multipers/gudhi/gudhi/Thread_safe_slicer.h index e64d7c15..115f64e5 100644 --- a/multipers/gudhi/gudhi/Thread_safe_slicer.h +++ b/multipers/gudhi/gudhi/Thread_safe_slicer.h @@ -349,6 +349,11 @@ class Thread_safe_slicer : private Slicer return Slicer::_get_representative_cycles(slicer_->complex_, update); } + Cycle get_most_persistent_cycle(Dimension dim = 1, bool update = true) + { + return Slicer::get_most_persistent_cycle(dim, update); + } + // FRIENDS /** diff --git a/multipers/multiparameter_module_approximation/approximation.h b/multipers/multiparameter_module_approximation/approximation.h index a69e3544..ecc6d105 100644 --- a/multipers/multiparameter_module_approximation/approximation.h +++ b/multipers/multiparameter_module_approximation/approximation.h @@ -170,7 +170,7 @@ class Module { Module permute_summands(const std::vector &permutation){ Module out; out.set_box(this->get_box()); - out.resize(this->size(), this->box_.dimension()); + out.resize(this->size(), this->box_.get_dimension()); for (size_t i = 0; i < permutation.size(); ++i) { out[i] = this->module_[permutation[i]]; } @@ -590,7 +590,7 @@ Module multiparameter_module_approximation(Slicer &slicer, /* using Filtration_value = Slicer::Filtration_value; */ typename Box::Point_t basepoint = box.get_lower_corner(); - const std::size_t num_parameters = box.dimension(); + const std::size_t num_parameters = box.get_dimension(); std::vector grid_size(num_parameters); std::vector signs(num_parameters); int signs_shifts = 0; @@ -2346,7 +2346,7 @@ inline value_type Summand::_get_max_diagonal(const filtration_type & const Box &box) const { // assumes birth and death to be never NaN assert(birth.num_parameters() == death.num_parameters() && "Inputs must be of the same size !"); - assert((box.is_trivial() || birth.num_parameters() == box.dimension()) && "Inputs must be of the same size !"); + assert((box.is_trivial() || birth.num_parameters() == box.get_dimension()) && "Inputs must be of the same size !"); value_type s = inf; bool threshold_flag = !box.is_trivial(); @@ -2434,7 +2434,7 @@ Module direct_sum(const Module &a, const Module