diff --git a/src/Persistence_matrix/include/gudhi/Persistence_matrix/base_pairing.h b/src/Persistence_matrix/include/gudhi/Persistence_matrix/base_pairing.h index 3e156888b0..8d43b5e222 100644 --- a/src/Persistence_matrix/include/gudhi/Persistence_matrix/base_pairing.h +++ b/src/Persistence_matrix/include/gudhi/Persistence_matrix/base_pairing.h @@ -23,6 +23,8 @@ #include #include +#include "boundary_face_position_to_id_mapper.h" + namespace Gudhi { namespace persistence_matrix { @@ -46,7 +48,11 @@ struct Dummy_base_pairing { * @tparam Master_matrix An instantiation of @ref Matrix from which all types and options are deduced. */ template -class Base_pairing +class Base_pairing : public std::conditional< + Master_matrix::Option_list::has_removable_columns, + Face_position_to_ID_mapper, + Dummy_pos_mapper + >::type { public: using Bar = typename Master_matrix::Bar; /**< Bar type. */ @@ -59,18 +65,6 @@ class Base_pairing * @brief Default constructor. */ Base_pairing(); - /** - * @brief Copy constructor. - * - * @param matrixToCopy Matrix to copy. - */ - Base_pairing(const Base_pairing& matrixToCopy); - /** - * @brief Move constructor. - * - * @param other Matrix to move. - */ - Base_pairing(Base_pairing&& other) noexcept; /** * @brief Reduces the matrix stored in @ref Boundary_matrix and computes the corresponding barcode. @@ -83,26 +77,37 @@ class Base_pairing */ const barcode_type& get_current_barcode(); - /** - * @brief Assign operator. - */ - Base_pairing& operator=(Base_pairing other); /** * @brief Swap operator. */ friend void swap(Base_pairing& pairing1, Base_pairing& pairing2) { + if constexpr (Master_matrix::Option_list::has_removable_columns) { + swap(static_cast&>(pairing1), + static_cast&>(pairing2)); + } pairing1.barcode_.swap(pairing2.barcode_); pairing1.deathToBar_.swap(pairing2.deathToBar_); + pairing1.idToPosition_.swap(pairing2.idToPosition_); std::swap(pairing1.isReduced_, pairing2.isReduced_); } protected: using pos_index = typename Master_matrix::pos_index; + using id_index = typename Master_matrix::id_index; using dictionary_type = typename Master_matrix::bar_dictionary_type; using base_matrix = typename Master_matrix::Boundary_matrix_type; + //PIDM = Position to ID Map + using PIDM = typename std::conditional, + Dummy_pos_mapper + >::type; barcode_type barcode_; /**< Bar container. */ dictionary_type deathToBar_; /**< Map from death index to bar index. */ + /** + * @brief Map from face ID to face position. Only stores a pair if ID != position. + */ + std::unordered_map idToPosition_; //TODO: test other map types bool isReduced_; /**< True if `_reduce()` was called. */ void _reduce(); @@ -114,19 +119,7 @@ class Base_pairing }; template -inline Base_pairing::Base_pairing() : isReduced_(false) -{} - -template -inline Base_pairing::Base_pairing(const Base_pairing& matrixToCopy) - : barcode_(matrixToCopy.barcode_), deathToBar_(matrixToCopy.deathToBar_), isReduced_(matrixToCopy.isReduced_) -{} - -template -inline Base_pairing::Base_pairing(Base_pairing&& other) noexcept - : barcode_(std::move(other.barcode_)), - deathToBar_(std::move(other.deathToBar_)), - isReduced_(std::move(other.isReduced_)) +inline Base_pairing::Base_pairing() : PIDM(), isReduced_(false) {} template @@ -139,7 +132,6 @@ inline const typename Base_pairing::barcode_type& Base_pairing inline void Base_pairing::_reduce() { - using id_index = typename Master_matrix::index; std::unordered_map pivotsToColumn(_matrix()->get_number_of_columns()); auto dim = _matrix()->get_max_dimension(); @@ -175,8 +167,10 @@ inline void Base_pairing::_reduce() if (pivot != static_cast(-1)) { pivotsToColumn.emplace(pivot, i); - _matrix()->get_column(pivot).clear(); - barcode_.emplace_back(pivot, i, dim - 1); + auto it = idToPosition_.find(pivot); + auto pivotColumnNumber = it == idToPosition_.end() ? pivot : it->second; + _matrix()->get_column(pivotColumnNumber).clear(); + barcode_.emplace_back(pivotColumnNumber, i, dim - 1); } else { curr.clear(); barcode_.emplace_back(i, -1, dim); @@ -216,15 +210,12 @@ inline void Base_pairing::_remove_last(pos_index columnIndex) deathToBar_.erase(it); }; } -} -template -inline Base_pairing& Base_pairing::operator=(Base_pairing other) -{ - barcode_.swap(other.barcode_); - deathToBar_.swap(other.deathToBar_); - std::swap(isReduced_, other.isReduced_); - return *this; + auto it = PIDM::map_.find(columnIndex); + if (it != PIDM::map_.end()){ + idToPosition_.erase(it->second); + PIDM::map_.erase(it); + } } } // namespace persistence_matrix diff --git a/src/Persistence_matrix/include/gudhi/Persistence_matrix/boundary_face_position_to_id_mapper.h b/src/Persistence_matrix/include/gudhi/Persistence_matrix/boundary_face_position_to_id_mapper.h new file mode 100644 index 0000000000..711f06e1c4 --- /dev/null +++ b/src/Persistence_matrix/include/gudhi/Persistence_matrix/boundary_face_position_to_id_mapper.h @@ -0,0 +1,60 @@ +/* This file is part of the Gudhi Library - https://gudhi.inria.fr/ - which is released under MIT. + * See file LICENSE or go to https://gudhi.inria.fr/licensing/ for full license details. + * Author(s): Hannah Schreiber + * + * Copyright (C) 2022-24 Inria + * + * Modification(s): + * - YYYY/MM Author: Description of the modification + */ + +/** + * @file base_pairing.h + * @author Hannah Schreiber + * @brief Contains the @ref Gudhi::persistence_matrix::Base_pairing class and + * @ref Gudhi::persistence_matrix::Dummy_base_pairing structure. + */ + +#ifndef PM_ID_POS_MAPPER_H +#define PM_ID_POS_MAPPER_H + +#include + +namespace Gudhi { +namespace persistence_matrix { + +/** + * @private + * @ingroup persistence_matrix + * + * @brief Empty structure. + * Inherited instead of @ref Face_position_to_ID_mapper. + */ +struct Dummy_pos_mapper { + friend void swap([[maybe_unused]] Dummy_pos_mapper& d1, [[maybe_unused]] Dummy_pos_mapper& d2) {} +}; + +/** + * @private + * @ingroup persistence_matrix + * + * @brief Map from face position to face ID. Only stores a pair if ID != position and has_removable_column is true. + * + * @tparam id_index @ref IDIdx index type + * @tparam pos_index @ref PosIdx index type + */ +template +struct Face_position_to_ID_mapper { + using map_type = std::unordered_map; //TODO: test other map types + + map_type map_; + + friend void swap(Face_position_to_ID_mapper& mapper1, Face_position_to_ID_mapper& mapper2) { + mapper1.map_.swap(mapper2.map_); + } +}; + +} // namespace persistence_matrix +} // namespace Gudhi + +#endif // PM_ID_POS_MAPPER_H diff --git a/src/Persistence_matrix/include/gudhi/Persistence_matrix/boundary_matrix.h b/src/Persistence_matrix/include/gudhi/Persistence_matrix/boundary_matrix.h index 04995aa7a9..19558dc58d 100644 --- a/src/Persistence_matrix/include/gudhi/Persistence_matrix/boundary_matrix.h +++ b/src/Persistence_matrix/include/gudhi/Persistence_matrix/boundary_matrix.h @@ -474,14 +474,16 @@ inline typename Boundary_matrix::index Boundary_matrixfirst; + 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 + if (ra_opt::rows_->size() <= pivot) ra_opt::rows_->resize(pivot + 1); } - //row container - if (ra_opt::rows_->size() <= pivot) ra_opt::rows_->resize(pivot + 1); } //row swap map containers @@ -499,6 +501,16 @@ inline typename Boundary_matrix::index Boundary_matrix public: using id_index = typename Master_matrix::id_index; /**< @ref IDIdx index type. */ using pos_index = typename Master_matrix::pos_index; /**< @ref PosIdx index type. */ + //CP = Chain Pairing using CP = Chain_pairing; /** diff --git a/src/Persistence_matrix/include/gudhi/Persistence_matrix/overlay_ididx_to_matidx.h b/src/Persistence_matrix/include/gudhi/Persistence_matrix/overlay_ididx_to_matidx.h index b2dbead4bd..c1bb010152 100644 --- a/src/Persistence_matrix/include/gudhi/Persistence_matrix/overlay_ididx_to_matidx.h +++ b/src/Persistence_matrix/include/gudhi/Persistence_matrix/overlay_ididx_to_matidx.h @@ -622,6 +622,7 @@ class Id_to_index_overlay void _initialize_map(unsigned int size); index _id_to_index(id_index id) const; + index& _id_to_index(id_index id); }; template @@ -640,7 +641,7 @@ inline Id_to_index_overlay::Id_to_index_overlay _initialize_map(orderedBoundaries.size()); if constexpr (Master_matrix_type::Option_list::is_of_boundary_type) { for (unsigned int i = 0; i < orderedBoundaries.size(); i++) { - idToIndex_->operator[](i) = i; + _id_to_index(i) = i; } } } @@ -678,7 +679,7 @@ inline Id_to_index_overlay::Id_to_index_overlay _initialize_map(orderedBoundaries.size()); if constexpr (Master_matrix_type::Option_list::is_of_boundary_type) { for (unsigned int i = 0; i < orderedBoundaries.size(); i++) { - idToIndex_->operator[](i) = i; + _id_to_index(i) = i; } } } @@ -739,7 +740,7 @@ inline void Id_to_index_overlay::insert_boundar if (idToIndex_->size() == nextIndex_) { idToIndex_->push_back(nextIndex_); } else { - idToIndex_->operator[](nextIndex_) = nextIndex_; + _id_to_index(nextIndex_) = nextIndex_; } } ++nextIndex_; @@ -756,7 +757,7 @@ inline void Id_to_index_overlay::insert_boundar GUDHI_CHECK(idToIndex_->find(faceIndex) == idToIndex_->end(), std::invalid_argument("Id_to_index_overlay::insert_boundary - Index for simplex already chosen!")); } else { - GUDHI_CHECK((idToIndex_->size() <= faceIndex || idToIndex_[faceIndex] == static_cast(-1)), + GUDHI_CHECK((idToIndex_->size() <= faceIndex || _id_to_index(faceIndex) == static_cast(-1)), std::invalid_argument("Id_to_index_overlay::insert_boundary - Index for simplex already chosen!")); } matrix_.insert_boundary(faceIndex, boundary, dim); @@ -767,7 +768,7 @@ inline void Id_to_index_overlay::insert_boundar if (idToIndex_->size() <= faceIndex) { idToIndex_->resize(faceIndex + 1, -1); } - idToIndex_->operator[](faceIndex) = nextIndex_; + _id_to_index(faceIndex) = nextIndex_; } ++nextIndex_; } @@ -804,7 +805,7 @@ inline void Id_to_index_overlay::remove_maximal } } else { for (id_index i = 0; i < idToIndex_->size(); ++i) { - if (idToIndex_->operator[](i) != static_cast(-1)) indexToID[idToIndex_->operator[](i)] = i; + if (_id_to_index(i) != static_cast(-1)) indexToID[_id_to_index(i)] = i; } } --nextIndex_; @@ -819,7 +820,7 @@ inline void Id_to_index_overlay::remove_maximal if constexpr (Master_matrix_type::Option_list::has_map_column_container) { idToIndex_->erase(faceID); } else { - idToIndex_->operator[](faceID) = -1; + _id_to_index(faceID) = -1; } } else { matrix_.remove_maximal_face(faceID); @@ -853,10 +854,10 @@ inline void Id_to_index_overlay::remove_last() idToIndex_->erase(it); } else { index id = idToIndex_->size() - 1; - while (idToIndex_->operator[](id) == static_cast(-1)) --id; // should always stop before reaching -1 - GUDHI_CHECK(idToIndex_->operator[](id) == nextIndex_, + while (_id_to_index(id) == static_cast(-1)) --id; // should always stop before reaching -1 + GUDHI_CHECK(_id_to_index(id) == nextIndex_, std::logic_error("Id_to_index_overlay::remove_last - Indexation problem.")); - idToIndex_->operator[](id) = -1; + _id_to_index(id) = -1; } } } @@ -1088,6 +1089,13 @@ Id_to_index_overlay::_id_to_index(id_index id) } } +template +inline typename Id_to_index_overlay::index& +Id_to_index_overlay::_id_to_index(id_index id) +{ + return idToIndex_->operator[](id); //for maps, the entry is created if not existing as needed in the constructors +} + } // namespace persistence_matrix } // namespace Gudhi diff --git a/src/Persistence_matrix/include/gudhi/Persistence_matrix/ru_matrix.h b/src/Persistence_matrix/include/gudhi/Persistence_matrix/ru_matrix.h index 8b256caafe..882e8b23cd 100644 --- a/src/Persistence_matrix/include/gudhi/Persistence_matrix/ru_matrix.h +++ b/src/Persistence_matrix/include/gudhi/Persistence_matrix/ru_matrix.h @@ -413,10 +413,10 @@ class RU_matrix : public Master_matrix::RU_pairing_option, void _reduce_last_column(index lastIndex); void _reduce_column(index target, index eventIndex); void _reduce_column_by(index target, index source); - void _update_barcode(pos_index birth, pos_index death); + void _update_barcode(id_index birthPivot, pos_index death); void _add_bar(dimension_type dim, pos_index birth); + void _remove_last_in_barcode(pos_index eventIndex); - constexpr barcode_type& _barcode(); constexpr bar_dictionary_type& _indexToBar(); }; @@ -485,7 +485,7 @@ inline RU_matrix::RU_matrix(unsigned int numberOfColumns, _indexToBar().reserve(numberOfColumns); } if constexpr (Master_matrix::Option_list::has_vine_update) { - swap_opt::positionToRowIdx_.reserve(numberOfColumns); + swap_opt::_positionToRowIdx().reserve(numberOfColumns); } } @@ -522,9 +522,7 @@ template template inline void RU_matrix::insert_boundary(const Boundary_type& boundary, dimension_type dim) { - auto id = reducedMatrixR_.insert_boundary(boundary, dim); - if constexpr (Master_matrix::Option_list::has_vine_update) swap_opt::positionToRowIdx_.push_back(id); - _insert_boundary(id); + _insert_boundary(reducedMatrixR_.insert_boundary(boundary, dim)); } template @@ -533,8 +531,22 @@ inline void RU_matrix::insert_boundary(id_index faceIndex, const Boundary_type& boundary, dimension_type dim) { + //maps for possible shifting between column content and position indices used for birth events + if constexpr (Master_matrix::Option_list::has_column_pairings && !Master_matrix::Option_list::has_vine_update){ + if (faceIndex != nextEventIndex_){ + pair_opt::idToPosition_.emplace(faceIndex, nextEventIndex_); + if constexpr (Master_matrix::Option_list::has_removable_columns){ + pair_opt::PIDM::map_.emplace(nextEventIndex_, faceIndex); + } + } + } if constexpr (Master_matrix::Option_list::has_vine_update) { - swap_opt::positionToRowIdx_.push_back(faceIndex); + if (faceIndex != nextEventIndex_){ + swap_opt::_positionToRowIdx().emplace(nextEventIndex_, faceIndex); + if (Master_matrix::Option_list::has_column_pairings){ + swap_opt::template RU_pairing::idToPosition_.emplace(faceIndex, nextEventIndex_); + } + } } _insert_boundary(reducedMatrixR_.insert_boundary(faceIndex, boundary, dim)); } @@ -591,27 +603,7 @@ inline void RU_matrix::remove_last() --nextEventIndex_; // assumes PosIdx == MatIdx for boundary matrices. - if constexpr (Master_matrix::Option_list::has_column_pairings) { - if constexpr (Master_matrix::hasFixedBarcode) { - auto& bar = _barcode()[_indexToBar()[nextEventIndex_]]; - if (bar.death == static_cast(-1)) { // birth - _barcode().pop_back(); // sorted by birth and nextEventIndex_ has to be the highest one - } else { // death - bar.death = -1; - }; - _indexToBar().pop_back(); - } else { // birth order eventually shuffled by vine updates. No sort possible to keep the matchings. - auto it = _indexToBar().find(nextEventIndex_); - typename barcode_type::iterator bar = it->second; - - if (bar->death == static_cast(-1)) - _barcode().erase(bar); - else - bar->death = -1; - - _indexToBar().erase(it); - } - } + _remove_last_in_barcode(nextEventIndex_); mirrorMatrixU_.remove_last(); if constexpr (Master_matrix::Option_list::has_map_column_container) { @@ -621,8 +613,10 @@ inline void RU_matrix::remove_last() if (lastPivot != static_cast(-1)) pivotToColumnIndex_[lastPivot] = -1; } - if constexpr (Master_matrix::Option_list::has_vine_update) { - swap_opt::positionToRowIdx_.pop_back(); + // if has_vine_update and has_column_pairings are both true, + // then the element is already removed in _remove_last_in_barcode + if constexpr (Master_matrix::Option_list::has_vine_update && !Master_matrix::Option_list::has_column_pairings) { + swap_opt::_positionToRowIdx().erase(nextEventIndex_); } } @@ -760,8 +754,9 @@ inline void RU_matrix::_insert_boundary(index currentIndex) } if constexpr (!Master_matrix::Option_list::has_map_column_container) { - while (pivotToColumnIndex_.size() <= currentIndex) - pivotToColumnIndex_.resize((pivotToColumnIndex_.size() + 1) * 2, -1); + id_index pivot = reducedMatrixR_.get_column(currentIndex).get_pivot(); + if (pivot != static_cast(-1) && pivotToColumnIndex_.size() <= pivot) + pivotToColumnIndex_.resize((pivot + 1) * 2, -1); } _reduce_last_column(currentIndex); @@ -789,14 +784,8 @@ inline void RU_matrix::_reduce() if constexpr (Master_matrix::Option_list::has_column_pairings) { _indexToBar().reserve(reducedMatrixR_.get_number_of_columns()); } - if constexpr (Master_matrix::Option_list::has_vine_update) { - swap_opt::positionToRowIdx_.reserve(reducedMatrixR_.get_number_of_columns()); - } for (index i = 0; i < reducedMatrixR_.get_number_of_columns(); i++) { - if constexpr (Master_matrix::Option_list::has_vine_update) { - swap_opt::positionToRowIdx_.push_back(i); - } if (!(reducedMatrixR_.is_zero_column(i))) { _reduce_column(i, i); } else { @@ -879,17 +868,13 @@ inline void RU_matrix::_reduce_column_by(index target, index sour } template -inline void RU_matrix::_update_barcode(pos_index birth, pos_index death) +inline void RU_matrix::_update_barcode(id_index birthPivot, pos_index death) { if constexpr (Master_matrix::Option_list::has_column_pairings) { - if constexpr (Master_matrix::hasFixedBarcode || !Master_matrix::Option_list::has_removable_columns) { - _barcode()[_indexToBar()[birth]].death = death; - _indexToBar().push_back(_indexToBar()[birth]); - } else { - auto& barIt = _indexToBar().at(birth); - barIt->death = death; - _indexToBar().try_emplace(death, barIt); // list so iterators are stable - } + if constexpr (Master_matrix::Option_list::has_vine_update) + swap_opt::template RU_pairing::_update_barcode(birthPivot, death); + else + pair_opt::_update_barcode(birthPivot, death); } } @@ -897,22 +882,22 @@ template inline void RU_matrix::_add_bar(dimension_type dim, pos_index birth) { if constexpr (Master_matrix::Option_list::has_column_pairings) { - _barcode().emplace_back(birth, -1, dim); - if constexpr (Master_matrix::hasFixedBarcode || !Master_matrix::Option_list::has_removable_columns) { - _indexToBar().push_back(_barcode().size() - 1); - } else { - _indexToBar().try_emplace(birth, --_barcode().end()); - } + if constexpr (Master_matrix::Option_list::has_vine_update) + swap_opt::template RU_pairing::_add_bar(dim, birth); + else + pair_opt::_add_bar(dim, birth); } } template -inline constexpr typename RU_matrix::barcode_type& RU_matrix::_barcode() +inline void RU_matrix::_remove_last_in_barcode(pos_index eventIndex) { - if constexpr (Master_matrix::Option_list::has_vine_update) - return swap_opt::template RU_pairing::barcode_; - else - return pair_opt::barcode_; + if constexpr (Master_matrix::Option_list::has_column_pairings) { + if constexpr (Master_matrix::Option_list::has_vine_update) + swap_opt::template RU_pairing::_remove_last(eventIndex); + else + pair_opt::_remove_last(eventIndex); + } } template diff --git a/src/Persistence_matrix/include/gudhi/Persistence_matrix/ru_pairing.h b/src/Persistence_matrix/include/gudhi/Persistence_matrix/ru_pairing.h index 6719460cf0..a8d6ac19fb 100644 --- a/src/Persistence_matrix/include/gudhi/Persistence_matrix/ru_pairing.h +++ b/src/Persistence_matrix/include/gudhi/Persistence_matrix/ru_pairing.h @@ -18,7 +18,9 @@ #ifndef PM_RU_PAIRING_H #define PM_RU_PAIRING_H -#include //std::move +#include + +#include "boundary_face_position_to_id_mapper.h" namespace Gudhi { namespace persistence_matrix { @@ -43,81 +45,109 @@ struct Dummy_ru_pairing { * @tparam Master_matrix An instantiation of @ref Matrix from which all types and options are deduced. */ template -class RU_pairing +class RU_pairing : public std::conditional< + Master_matrix::Option_list::has_removable_columns, + Face_position_to_ID_mapper, + Dummy_pos_mapper + >::type { + protected: + using pos_index = typename Master_matrix::pos_index; + using id_index = typename Master_matrix::id_index; + //PIDM = Position to ID Map + using PIDM = typename std::conditional, + Dummy_pos_mapper + >::type; + public: using barcode_type = typename Master_matrix::barcode_type; /**< Barcode type. */ /** * @brief Default constructor. */ - RU_pairing(); - /** - * @brief Copy constructor. - * - * @param matrixToCopy Matrix to copy. - */ - RU_pairing(const RU_pairing& matrixToCopy); - /** - * @brief Move constructor. - * - * @param other Matrix to move. - */ - RU_pairing(RU_pairing&& other) noexcept; + RU_pairing() : PIDM() {} /** * @brief Returns the current barcode which is maintained at any insertion, removal or vine swap. * * @return Const reference to the barcode. */ - const barcode_type& get_current_barcode() const; + const barcode_type& get_current_barcode() const { return barcode_; } - /** - * @brief Assign operator. - */ - RU_pairing& operator=(RU_pairing other); /** * @brief Swap operator. */ friend void swap(RU_pairing& pairing1, RU_pairing& pairing2) { + swap(static_cast(pairing1), static_cast(pairing2)); pairing1.barcode_.swap(pairing2.barcode_); pairing1.indexToBar_.swap(pairing2.indexToBar_); + pairing1.idToPosition_.swap(pairing2.idToPosition_); } protected: + using dimension_type = typename Master_matrix::dimension_type; using dictionary_type = typename Master_matrix::bar_dictionary_type; barcode_type barcode_; /**< Bar container. */ dictionary_type indexToBar_; /**< Map from @ref MatIdx index to bar index. */ -}; - -template -inline RU_pairing::RU_pairing() -{} - -template -inline RU_pairing::RU_pairing(const RU_pairing& matrixToCopy) - : barcode_(matrixToCopy.barcode_), indexToBar_(matrixToCopy.indexToBar_) -{} - -template -inline RU_pairing::RU_pairing(RU_pairing&& other) noexcept - : barcode_(std::move(other.barcode_)), indexToBar_(std::move(other.indexToBar_)) -{} + /** + * @brief Map from face ID to face position. Only stores a pair if ID != position. + */ + std::unordered_map idToPosition_; //TODO: test other map types + + void _update_barcode(id_index birthPivot, pos_index death) { + auto it = idToPosition_.find(birthPivot); + pos_index pivotBirth = it == idToPosition_.end() ? birthPivot : it->second; + if constexpr (Master_matrix::hasFixedBarcode || !Master_matrix::Option_list::has_removable_columns) { + barcode_[indexToBar_[pivotBirth]].death = death; + indexToBar_.push_back(indexToBar_[pivotBirth]); + } else { + auto& barIt = indexToBar_.at(pivotBirth); + barIt->death = death; + indexToBar_.try_emplace(death, barIt); // list so iterators are stable + } + } -template -inline const typename RU_pairing::barcode_type& RU_pairing::get_current_barcode() const -{ - return barcode_; -} + void _add_bar(dimension_type dim, pos_index birth) { + barcode_.emplace_back(birth, -1, dim); + if constexpr (Master_matrix::hasFixedBarcode || !Master_matrix::Option_list::has_removable_columns) { + indexToBar_.push_back(barcode_.size() - 1); + } else { + indexToBar_.try_emplace(birth, --barcode_.end()); + } + } -template -inline RU_pairing& RU_pairing::operator=(RU_pairing other) -{ - barcode_.swap(other.barcode_); - indexToBar_.swap(other.indexToBar_); - return *this; -} + void _remove_last(pos_index eventIndex) { + static_assert(Master_matrix::Option_list::has_removable_columns, "_remove_last not available."); + + if constexpr (Master_matrix::hasFixedBarcode) { + auto& bar = barcode_[indexToBar_[eventIndex]]; + if (bar.death == static_cast(-1)) { // birth + barcode_.pop_back(); // sorted by birth and eventIndex has to be the highest one + } else { // death + bar.death = -1; + }; + indexToBar_.pop_back(); + } else { // birth order eventually shuffled by vine updates. No sort possible to keep the matchings. + auto it = indexToBar_.find(eventIndex); + typename barcode_type::iterator bar = it->second; + + if (bar->death == static_cast(-1)) + barcode_.erase(bar); + else + bar->death = -1; + + indexToBar_.erase(it); + } + + auto it = PIDM::map_.find(eventIndex); + if (it != PIDM::map_.end()){ + idToPosition_.erase(it->second); + PIDM::map_.erase(it); + } + } +}; } // namespace persistence_matrix } // namespace Gudhi diff --git a/src/Persistence_matrix/include/gudhi/Persistence_matrix/ru_vine_swap.h b/src/Persistence_matrix/include/gudhi/Persistence_matrix/ru_vine_swap.h index c439682ce8..62c56b0552 100644 --- a/src/Persistence_matrix/include/gudhi/Persistence_matrix/ru_vine_swap.h +++ b/src/Persistence_matrix/include/gudhi/Persistence_matrix/ru_vine_swap.h @@ -22,10 +22,10 @@ #include //std::move #include //std::conditional #include -#include #include //std::invalid_argument #include "ru_pairing.h" +#include "boundary_face_position_to_id_mapper.h" namespace Gudhi { namespace persistence_matrix { @@ -62,7 +62,13 @@ template class RU_vine_swap : public std::conditional, Dummy_ru_vine_pairing - >::type + >::type, + public std::conditional + >::type { public: using index = typename Master_matrix::index; /**< @ref MatIdx index type. */ @@ -120,20 +126,27 @@ class RU_vine_swap : public std::conditional&>(swap1), static_cast&>(swap2)); } - swap1.positionToRowIdx_.swap(swap2.positionToRowIdx_); + if (!Master_matrix::Option_list::has_column_pairings || !Master_matrix::Option_list::has_removable_columns) { + swap(static_cast&>(swap1), + static_cast&>(swap2)); + } } protected: - // only useful when simplex id does not corresponds to position, so feels kinda useless most of the time... - // TODO: as it takes up some non trivial memory, see if this should not be optional - // or only remember the positions with a difference. but then a map is needed, ie find instead of []. - std::vector positionToRowIdx_; /**< Map from @ref PosIdx index to row index. */ - - private: + //RUP = RU matrix Pairing using RUP = typename std::conditional, Dummy_ru_vine_pairing >::type; + //RUM = RU matrix position to id Map + using RUM = typename std::conditional + >::type; + constexpr auto& _positionToRowIdx(); + + private: using ru_matrix = typename Master_matrix::RU_matrix_type; bool _is_paired(index columnIndex); @@ -154,22 +167,26 @@ class RU_vine_swap : public std::conditional(this); } constexpr const ru_matrix* _matrix() const { return static_cast(this); } }; template -inline RU_vine_swap::RU_vine_swap() : RUP() +inline RU_vine_swap::RU_vine_swap() : RUP(), RUM() {} template inline RU_vine_swap::RU_vine_swap(const RU_vine_swap& matrixToCopy) - : RUP(static_cast(matrixToCopy)), positionToRowIdx_(matrixToCopy.positionToRowIdx_) + : RUP(static_cast(matrixToCopy)), + RUM(static_cast(matrixToCopy)) {} template inline RU_vine_swap::RU_vine_swap(RU_vine_swap&& other) noexcept - : RUP(std::move(static_cast(other))), positionToRowIdx_(std::move(other.positionToRowIdx_)) + : RUP(std::move(static_cast(other))), + RUM(std::move(static_cast(other))) {} template @@ -182,7 +199,7 @@ inline bool RU_vine_swap::vine_swap_with_z_eq_1_case(pos_index in bool iiIsPositive = _matrix()->reducedMatrixR_.is_zero_column(index + 1); if (iIsPositive && iiIsPositive) { - _matrix()->mirrorMatrixU_.zero_cell(index, positionToRowIdx_[index + 1]); + _matrix()->mirrorMatrixU_.zero_cell(index, _get_row_id_from_position(index + 1)); return _positive_vine_swap(index); } else if (!iIsPositive && !iiIsPositive) { return _negative_vine_swap(index); @@ -209,14 +226,14 @@ inline bool RU_vine_swap::vine_swap(pos_index index) _swap_at_index(index); return true; } - if (!_matrix()->mirrorMatrixU_.is_zero_cell(index, positionToRowIdx_[index + 1])) { - _matrix()->mirrorMatrixU_.zero_cell(index, positionToRowIdx_[index + 1]); + if (!_matrix()->mirrorMatrixU_.is_zero_cell(index, _get_row_id_from_position(index + 1))) { + _matrix()->mirrorMatrixU_.zero_cell(index, _get_row_id_from_position(index + 1)); } return _positive_vine_swap(index); } else if (!iIsPositive && !iiIsPositive) { if (_matrix()->reducedMatrixR_.get_column_dimension(index) != _matrix()->reducedMatrixR_.get_column_dimension(index + 1) || - _matrix()->mirrorMatrixU_.is_zero_cell(index, positionToRowIdx_[index + 1])) { + _matrix()->mirrorMatrixU_.is_zero_cell(index, _get_row_id_from_position(index + 1))) { _negative_transpose(index); _swap_at_index(index); return true; @@ -225,7 +242,7 @@ inline bool RU_vine_swap::vine_swap(pos_index index) } else if (iIsPositive && !iiIsPositive) { if (_matrix()->reducedMatrixR_.get_column_dimension(index) != _matrix()->reducedMatrixR_.get_column_dimension(index + 1) || - _matrix()->mirrorMatrixU_.is_zero_cell(index, positionToRowIdx_[index + 1])) { + _matrix()->mirrorMatrixU_.is_zero_cell(index, _get_row_id_from_position(index + 1))) { _positive_negative_transpose(index); _swap_at_index(index); return true; @@ -234,7 +251,7 @@ inline bool RU_vine_swap::vine_swap(pos_index index) } else { if (_matrix()->reducedMatrixR_.get_column_dimension(index) != _matrix()->reducedMatrixR_.get_column_dimension(index + 1) || - _matrix()->mirrorMatrixU_.is_zero_cell(index, positionToRowIdx_[index + 1])) { + _matrix()->mirrorMatrixU_.is_zero_cell(index, _get_row_id_from_position(index + 1))) { _negative_positive_transpose(index); _swap_at_index(index); return true; @@ -247,7 +264,7 @@ template inline RU_vine_swap& RU_vine_swap::operator=(RU_vine_swap other) { RUP::operator=(other); - positionToRowIdx_.swap(other.positionToRowIdx_); + RUM::operator=(other); return *this; } @@ -270,12 +287,14 @@ inline bool RU_vine_swap::_is_paired(index columnIndex) } template -inline void RU_vine_swap::_swap_at_index(index columnIndex) +inline void RU_vine_swap::_swap_at_index(index columnIndex) { _matrix()->reducedMatrixR_.swap_columns(columnIndex, columnIndex + 1); - _matrix()->reducedMatrixR_.swap_rows(positionToRowIdx_[columnIndex], positionToRowIdx_[columnIndex + 1]); + _matrix()->reducedMatrixR_.swap_rows(_get_row_id_from_position(columnIndex), + _get_row_id_from_position(columnIndex + 1)); _matrix()->mirrorMatrixU_.swap_columns(columnIndex, columnIndex + 1); - _matrix()->mirrorMatrixU_.swap_rows(positionToRowIdx_[columnIndex], positionToRowIdx_[columnIndex + 1]); + _matrix()->mirrorMatrixU_.swap_rows(_get_row_id_from_position(columnIndex), + _get_row_id_from_position(columnIndex + 1)); } template @@ -371,7 +390,7 @@ inline bool RU_vine_swap::_positive_vine_swap(index columnIndex) const pos_index iiDeath = _get_death(columnIndex + 1); if (iDeath != static_cast(-1) && iiDeath != static_cast(-1) && - !(_matrix()->reducedMatrixR_.is_zero_cell(iiDeath, positionToRowIdx_[columnIndex]))) { + !(_matrix()->reducedMatrixR_.is_zero_cell(iiDeath, _get_row_id_from_position(columnIndex)))) { if (iDeath < iiDeath) { _swap_at_index(columnIndex); _add_to(iDeath, iiDeath); @@ -387,7 +406,7 @@ inline bool RU_vine_swap::_positive_vine_swap(index columnIndex) _swap_at_index(columnIndex); if (iDeath != static_cast(-1) || iiDeath == static_cast(-1) || - _matrix()->reducedMatrixR_.is_zero_cell(iiDeath, positionToRowIdx_[columnIndex + 1])) { + _matrix()->reducedMatrixR_.is_zero_cell(iiDeath, _get_row_id_from_position(columnIndex + 1))) { _positive_transpose(columnIndex); return true; } @@ -416,7 +435,7 @@ inline bool RU_vine_swap::_negative_vine_swap(index columnIndex) template inline bool RU_vine_swap::_positive_negative_vine_swap(index columnIndex) { - _matrix()->mirrorMatrixU_.zero_cell(columnIndex, positionToRowIdx_[columnIndex + 1]); + _matrix()->mirrorMatrixU_.zero_cell(columnIndex, _get_row_id_from_position(columnIndex + 1)); _swap_at_index(columnIndex); _positive_negative_transpose(columnIndex); @@ -496,6 +515,23 @@ inline typename RU_vine_swap::pos_index RU_vine_swap +inline typename RU_vine_swap::id_index RU_vine_swap::_get_row_id_from_position( + pos_index position) +{ + auto it = _positionToRowIdx().find(position); + return it == _positionToRowIdx().end() ? position : it->second; +} + +template +inline constexpr auto& RU_vine_swap::_positionToRowIdx() +{ + if constexpr (Master_matrix::Option_list::has_column_pairings && Master_matrix::Option_list::has_removable_columns) + return RUP::PIDM::map_; + else + return RUM::map_; +} + } // namespace persistence_matrix } // namespace Gudhi diff --git a/src/Persistence_matrix/include/gudhi/matrix.h b/src/Persistence_matrix/include/gudhi/matrix.h index 1c5e82f477..c87eb8544f 100644 --- a/src/Persistence_matrix/include/gudhi/matrix.h +++ b/src/Persistence_matrix/include/gudhi/matrix.h @@ -573,7 +573,7 @@ class Matrix { * to be consecutive and starting with 0 (an empty boundary is interpreted as a vertex boundary and not as a non * existing simplex). All dimensions up to the maximal dimension of interest have to be present. If only a higher * dimension is of interest and not everything should be stored, then use the @ref insert_boundary method instead - * (after creating the matrix with the @ref Matrix(int numberOfColumns, characteristic_type characteristic) + * (after creating the matrix with the @ref Matrix(unsigned int numberOfColumns, characteristic_type characteristic) * constructor preferably). If the persistence barcode has to be computed from this matrix, the simplices are also * assumed to be ordered by appearance order in the filtration. Also, depending of the options, the matrix is * eventually reduced on the fly or converted into a chain complex base, so the new matrix is not always identical to @@ -593,7 +593,7 @@ class Matrix { * @ref set_characteristic before calling for the first time a method needing it. Ignored if * @ref PersistenceMatrixOptions::is_z2 is true. */ - Matrix(int numberOfColumns, characteristic_type characteristic = static_cast(-1)); + Matrix(unsigned int numberOfColumns, characteristic_type characteristic = static_cast(-1)); /** * @brief Constructs a new empty matrix with the given comparator functions. Only available when those comparators * are necessary. @@ -786,7 +786,7 @@ class Matrix { * @return If it is a @ref chainmatrix "chain matrix", the method returns the @ref MatIdx indices of the unpaired * chains used to reduce the boundary. Otherwise, nothing. */ - template + template insertion_return_type insert_boundary(id_index faceIndex, const Boundary_type& boundary, dimension_type dim = -1); /** @@ -1427,7 +1427,7 @@ inline Matrix::Matrix(const std::vector -inline Matrix::Matrix(int numberOfColumns, characteristic_type characteristic) +inline Matrix::Matrix(unsigned int numberOfColumns, characteristic_type characteristic) : colSettings_(new Column_settings(characteristic)), matrix_(numberOfColumns, colSettings_) { diff --git a/src/Persistence_matrix/test/Persistence_matrix_matrix_tests_z2_boundary.cpp b/src/Persistence_matrix/test/Persistence_matrix_matrix_tests_z2_boundary.cpp index 823b5da237..61f0080ef0 100644 --- a/src/Persistence_matrix/test/Persistence_matrix_matrix_tests_z2_boundary.cpp +++ b/src/Persistence_matrix/test/Persistence_matrix_matrix_tests_z2_boundary.cpp @@ -64,6 +64,9 @@ BOOST_AUTO_TEST_CASE_TEMPLATE(Boundary_matrix_z2_max_dimension, Matrix, max_dim_ BOOST_AUTO_TEST_CASE_TEMPLATE(Boundary_matrix_z2_operation, Matrix, full_matrices) { test_base_operation(); } -BOOST_AUTO_TEST_CASE_TEMPLATE(Boundary_matrix_z2_barcode, Matrix, barcode_matrices) { test_barcode(); } +BOOST_AUTO_TEST_CASE_TEMPLATE(Boundary_matrix_z2_barcode, Matrix, barcode_matrices) { + test_barcode(); + test_shifted_barcode(); +} BOOST_AUTO_TEST_CASE_TEMPLATE(Boundary_matrix_z2_swaps, Matrix, swap_matrices) { test_base_swaps(); } diff --git a/src/Persistence_matrix/test/Persistence_matrix_matrix_tests_z2_chain_barcode.cpp b/src/Persistence_matrix/test/Persistence_matrix_matrix_tests_z2_chain_barcode.cpp index 70d353cf71..6b7d0f5149 100644 --- a/src/Persistence_matrix/test/Persistence_matrix_matrix_tests_z2_chain_barcode.cpp +++ b/src/Persistence_matrix/test/Persistence_matrix_matrix_tests_z2_chain_barcode.cpp @@ -87,4 +87,7 @@ BOOST_AUTO_TEST_CASE_TEMPLATE(Chain_matrix_z2_barcode_operation, Matrix, full_ma test_chain_operation(m); } -BOOST_AUTO_TEST_CASE_TEMPLATE(Chain_matrix_z2_barcode_barcode, Matrix, full_matrices) { test_barcode(); } +BOOST_AUTO_TEST_CASE_TEMPLATE(Chain_matrix_z2_barcode_barcode, Matrix, full_matrices) { + test_barcode(); + test_shifted_barcode(); +} diff --git a/src/Persistence_matrix/test/Persistence_matrix_matrix_tests_z2_chain_rep.cpp b/src/Persistence_matrix/test/Persistence_matrix_matrix_tests_z2_chain_rep.cpp index 99701e0731..156b3b23b8 100644 --- a/src/Persistence_matrix/test/Persistence_matrix_matrix_tests_z2_chain_rep.cpp +++ b/src/Persistence_matrix/test/Persistence_matrix_matrix_tests_z2_chain_rep.cpp @@ -86,7 +86,10 @@ BOOST_AUTO_TEST_CASE_TEMPLATE(Chain_matrix_z2_rep_operation, Matrix, full_matric test_chain_operation(m); } -BOOST_AUTO_TEST_CASE_TEMPLATE(Chain_matrix_z2_rep_barcode, Matrix, barcode_matrices) { test_barcode(); } +BOOST_AUTO_TEST_CASE_TEMPLATE(Chain_matrix_z2_rep_barcode, Matrix, barcode_matrices) { + test_barcode(); + test_shifted_barcode(); +} BOOST_AUTO_TEST_CASE_TEMPLATE(Chain_matrix_z2_rep_representative_cycles, Matrix, full_matrices) { auto columns = build_longer_boundary_matrix(); diff --git a/src/Persistence_matrix/test/Persistence_matrix_matrix_tests_z2_chain_vine.cpp b/src/Persistence_matrix/test/Persistence_matrix_matrix_tests_z2_chain_vine.cpp index 5fb13f1aed..63ce5424ed 100644 --- a/src/Persistence_matrix/test/Persistence_matrix_matrix_tests_z2_chain_vine.cpp +++ b/src/Persistence_matrix/test/Persistence_matrix_matrix_tests_z2_chain_vine.cpp @@ -104,7 +104,10 @@ BOOST_AUTO_TEST_CASE_TEMPLATE(Chain_matrix_z2_vine_operation, Matrix, full_matri test_chain_operation(m); } -BOOST_AUTO_TEST_CASE_TEMPLATE(Chain_matrix_z2_vine_barcode, Matrix, full_matrices) { test_barcode(); } +BOOST_AUTO_TEST_CASE_TEMPLATE(Chain_matrix_z2_vine_barcode, Matrix, full_matrices) { + test_barcode(); + test_shifted_barcode(); +} BOOST_AUTO_TEST_CASE_TEMPLATE(Chain_matrix_z2_vine, Matrix, full_matrices) { auto columns = build_longer_boundary_matrix(); diff --git a/src/Persistence_matrix/test/Persistence_matrix_matrix_tests_z2_ru_rep.cpp b/src/Persistence_matrix/test/Persistence_matrix_matrix_tests_z2_ru_rep.cpp index dcf13e3bc9..7194285d10 100644 --- a/src/Persistence_matrix/test/Persistence_matrix_matrix_tests_z2_ru_rep.cpp +++ b/src/Persistence_matrix/test/Persistence_matrix_matrix_tests_z2_ru_rep.cpp @@ -74,7 +74,10 @@ BOOST_AUTO_TEST_CASE_TEMPLATE(RU_matrix_z2_rep_max_dimension, Matrix, full_matri BOOST_AUTO_TEST_CASE_TEMPLATE(RU_matrix_z2_rep_operation, Matrix, full_matrices) { test_ru_operation(); } #ifdef PM_TEST_BARCODE -BOOST_AUTO_TEST_CASE_TEMPLATE(RU_matrix_z2_rep_barcode, Matrix, full_matrices) { test_barcode(); } +BOOST_AUTO_TEST_CASE_TEMPLATE(RU_matrix_z2_rep_barcode, Matrix, full_matrices) { + test_barcode(); + test_shifted_barcode(); +} #endif BOOST_AUTO_TEST_CASE_TEMPLATE(RU_matrix_z2_rep_representative_cycles, Matrix, full_matrices) { diff --git a/src/Persistence_matrix/test/Persistence_matrix_matrix_tests_z2_ru_vine.cpp b/src/Persistence_matrix/test/Persistence_matrix_matrix_tests_z2_ru_vine.cpp index a0924471e0..4885f323b3 100644 --- a/src/Persistence_matrix/test/Persistence_matrix_matrix_tests_z2_ru_vine.cpp +++ b/src/Persistence_matrix/test/Persistence_matrix_matrix_tests_z2_ru_vine.cpp @@ -75,7 +75,10 @@ BOOST_AUTO_TEST_CASE_TEMPLATE(RU_matrix_z2_vine_max_dimension, Matrix, full_matr BOOST_AUTO_TEST_CASE_TEMPLATE(RU_matrix_z2_vine_operation, Matrix, full_matrices) { test_ru_operation(); } #ifdef PM_TEST_BARCODE -BOOST_AUTO_TEST_CASE_TEMPLATE(RU_matrix_z2_vine_barcode, Matrix, full_matrices) { test_barcode(); } +BOOST_AUTO_TEST_CASE_TEMPLATE(RU_matrix_z2_vine_barcode, Matrix, full_matrices) { + test_barcode(); + test_shifted_barcode(); +} #endif BOOST_AUTO_TEST_CASE_TEMPLATE(RU_matrix_z2_vine_representative_cycles, Matrix, rep_matrices) { diff --git a/src/Persistence_matrix/test/Persistence_matrix_matrix_tests_zp_boundary.cpp b/src/Persistence_matrix/test/Persistence_matrix_matrix_tests_zp_boundary.cpp index 5111b76c6f..384bb62285 100644 --- a/src/Persistence_matrix/test/Persistence_matrix_matrix_tests_zp_boundary.cpp +++ b/src/Persistence_matrix/test/Persistence_matrix_matrix_tests_zp_boundary.cpp @@ -64,6 +64,9 @@ BOOST_AUTO_TEST_CASE_TEMPLATE(Boundary_matrix_zp_max_dimension, Matrix, max_dim_ BOOST_AUTO_TEST_CASE_TEMPLATE(Boundary_matrix_zp_operation, Matrix, full_matrices) { test_base_operation(); } -BOOST_AUTO_TEST_CASE_TEMPLATE(Boundary_matrix_zp_barcode, Matrix, barcode_matrices) { test_barcode(); } +BOOST_AUTO_TEST_CASE_TEMPLATE(Boundary_matrix_zp_barcode, Matrix, barcode_matrices) { + test_barcode(); + test_shifted_barcode(); +} BOOST_AUTO_TEST_CASE_TEMPLATE(Boundary_matrix_zp_swaps, Matrix, swap_matrices) { test_base_swaps(); } diff --git a/src/Persistence_matrix/test/Persistence_matrix_matrix_tests_zp_chain_barcode.cpp b/src/Persistence_matrix/test/Persistence_matrix_matrix_tests_zp_chain_barcode.cpp index 08692b44c2..f3b06fd537 100644 --- a/src/Persistence_matrix/test/Persistence_matrix_matrix_tests_zp_chain_barcode.cpp +++ b/src/Persistence_matrix/test/Persistence_matrix_matrix_tests_zp_chain_barcode.cpp @@ -88,4 +88,7 @@ BOOST_AUTO_TEST_CASE_TEMPLATE(Chain_matrix_zp_barcode_operation, Matrix, full_ma test_chain_operation(m); } -BOOST_AUTO_TEST_CASE_TEMPLATE(Chain_matrix_zp_barcode_barcode, Matrix, full_matrices) { test_barcode(); } +BOOST_AUTO_TEST_CASE_TEMPLATE(Chain_matrix_zp_barcode_barcode, Matrix, full_matrices) { + test_barcode(); + test_shifted_barcode(); +} diff --git a/src/Persistence_matrix/test/Persistence_matrix_matrix_tests_zp_chain_rep.cpp b/src/Persistence_matrix/test/Persistence_matrix_matrix_tests_zp_chain_rep.cpp index d18177b0aa..039c2ad685 100644 --- a/src/Persistence_matrix/test/Persistence_matrix_matrix_tests_zp_chain_rep.cpp +++ b/src/Persistence_matrix/test/Persistence_matrix_matrix_tests_zp_chain_rep.cpp @@ -87,7 +87,10 @@ BOOST_AUTO_TEST_CASE_TEMPLATE(Chain_matrix_zp_rep_operation, Matrix, full_matric test_chain_operation(m); } -BOOST_AUTO_TEST_CASE_TEMPLATE(Chain_matrix_zp_rep_barcode, Matrix, barcode_matrices) { test_barcode(); } +BOOST_AUTO_TEST_CASE_TEMPLATE(Chain_matrix_zp_rep_barcode, Matrix, barcode_matrices) { + test_barcode(); + test_shifted_barcode(); +} BOOST_AUTO_TEST_CASE_TEMPLATE(Chain_matrix_zp_rep_representative_cycles, Matrix, full_matrices) { auto columns = build_longer_boundary_matrix(); diff --git a/src/Persistence_matrix/test/Persistence_matrix_matrix_tests_zp_ru_rep.cpp b/src/Persistence_matrix/test/Persistence_matrix_matrix_tests_zp_ru_rep.cpp index e81bcaa4e7..395698c8a3 100644 --- a/src/Persistence_matrix/test/Persistence_matrix_matrix_tests_zp_ru_rep.cpp +++ b/src/Persistence_matrix/test/Persistence_matrix_matrix_tests_zp_ru_rep.cpp @@ -74,7 +74,10 @@ BOOST_AUTO_TEST_CASE_TEMPLATE(RU_matrix_zp_rep_max_dimension, Matrix, full_matri BOOST_AUTO_TEST_CASE_TEMPLATE(RU_matrix_zp_rep_operation, Matrix, full_matrices) { test_ru_operation(); } #ifdef PM_TEST_BARCODE -BOOST_AUTO_TEST_CASE_TEMPLATE(RU_matrix_zp_rep_barcode, Matrix, full_matrices) { test_barcode(); } +BOOST_AUTO_TEST_CASE_TEMPLATE(RU_matrix_zp_rep_barcode, Matrix, full_matrices) { + test_barcode(); + test_shifted_barcode(); +} #endif BOOST_AUTO_TEST_CASE_TEMPLATE(RU_matrix_zp_rep_representative_cycles, Matrix, full_matrices) { diff --git a/src/Persistence_matrix/test/pm_matrix_tests.h b/src/Persistence_matrix/test/pm_matrix_tests.h index dca9e8ab95..e2a3759dcb 100644 --- a/src/Persistence_matrix/test/pm_matrix_tests.h +++ b/src/Persistence_matrix/test/pm_matrix_tests.h @@ -875,7 +875,7 @@ void test_boundary_maximal_simplex_removal() { test_content_equality(columns, m); BOOST_CHECK_EQUAL(m.get_number_of_columns(), 7); - // pairing always true for boundary for now (only thing differentiating it from base) + // pairing always true for boundary for now (only thing differenciating it from base) BOOST_CHECK_EQUAL(m.get_current_barcode().back().death, 6); m.remove_last(); @@ -1455,6 +1455,140 @@ void test_barcode() { BOOST_CHECK(bars1 == bars3); } +template +void test_shifted_barcode() { + using C = typename Matrix::Column_type; + struct BarComp { + bool operator()(const std::tuple& c1, const std::tuple& c2) const { + if (std::get<0>(c1) == std::get<0>(c2)) return std::get<1>(c1) < std::get<1>(c2); + return std::get<0>(c1) < std::get<0>(c2); + } + }; + + Matrix m(9, 5); + if constexpr (is_z2()) { + m.insert_boundary(2, {}, 0); + m.insert_boundary(3, {}, 0); + m.insert_boundary(5, {}, 0); + m.insert_boundary(7, {2, 3}); + m.insert_boundary(8, {3, 5}); + m.insert_boundary(9, {2, 5}); + m.insert_boundary(10, {7, 8, 9}); + m.insert_boundary(11, {}, 0); + m.insert_boundary(13, {3, 11}); + } else { + m.insert_boundary(2, {}, 0); + m.insert_boundary(3, {}, 0); + m.insert_boundary(5, {}, 0); + m.insert_boundary(7, {{2, 1}, {3, 4}}); + m.insert_boundary(8, {{3, 1}, {5, 4}}); + m.insert_boundary(9, {{2, 1}, {5, 4}}); + m.insert_boundary(10, {{7, 1}, {8, 1}, {9, 4}}); + m.insert_boundary(11, {}, 0); + m.insert_boundary(13, {{3, 1}, {11, 4}}); + } + + const auto& barcode = m.get_current_barcode(); + + std::vector > reducedMatrix; + if constexpr (is_z2()) { + if constexpr (Matrix::Option_list::is_of_boundary_type) { + reducedMatrix.emplace_back(); + reducedMatrix.emplace_back(); + reducedMatrix.emplace_back(); + reducedMatrix.push_back({2, 3}); + reducedMatrix.push_back({3, 5}); + reducedMatrix.emplace_back(); + reducedMatrix.push_back({7, 8, 9}); + reducedMatrix.emplace_back(); + reducedMatrix.push_back({3, 11}); + } else { + reducedMatrix.push_back({2}); + reducedMatrix.push_back({2, 3}); + reducedMatrix.push_back({2, 5}); + reducedMatrix.push_back({7}); + reducedMatrix.push_back({7, 8}); + reducedMatrix.push_back({7, 8, 9}); + reducedMatrix.push_back({10}); + reducedMatrix.push_back({2, 11}); + reducedMatrix.push_back({7, 13}); + } + } else { + if constexpr (Matrix::Option_list::is_of_boundary_type) { + reducedMatrix.emplace_back(); + reducedMatrix.emplace_back(); + reducedMatrix.emplace_back(); + reducedMatrix.push_back({{2, 1}, {3, 4}}); + reducedMatrix.push_back({{3, 1}, {5, 4}}); + reducedMatrix.emplace_back(); + reducedMatrix.push_back({{7, 1}, {8, 1}, {9, 4}}); + reducedMatrix.emplace_back(); + reducedMatrix.push_back({{3, 1}, {11, 4}}); + } else { + reducedMatrix.push_back({{2, 1}}); + reducedMatrix.push_back({{2, 1}, {3, 4}}); + reducedMatrix.push_back({{2, 1}, {5, 4}}); + reducedMatrix.push_back({{7, 1}}); + reducedMatrix.push_back({{7, 1}, {8, 1}}); + reducedMatrix.push_back({{7, 1}, {8, 1}, {9, 4}}); + reducedMatrix.push_back({{10, 1}}); + reducedMatrix.push_back({{2, 1}, {11, 4}}); + reducedMatrix.push_back({{7, 1}, {13, 1}}); + } + } + if constexpr (Matrix::Option_list::column_indexation_type == Column_indexation_types::IDENTIFIER){ + test_column_equality(reducedMatrix[0], get_column_content_via_iterators(m.get_column(2))); + test_column_equality(reducedMatrix[1], get_column_content_via_iterators(m.get_column(3))); + test_column_equality(reducedMatrix[2], get_column_content_via_iterators(m.get_column(5))); + test_column_equality(reducedMatrix[3], get_column_content_via_iterators(m.get_column(7))); + test_column_equality(reducedMatrix[4], get_column_content_via_iterators(m.get_column(8))); + test_column_equality(reducedMatrix[5], get_column_content_via_iterators(m.get_column(9))); + test_column_equality(reducedMatrix[6], get_column_content_via_iterators(m.get_column(10))); + test_column_equality(reducedMatrix[7], get_column_content_via_iterators(m.get_column(11))); + test_column_equality(reducedMatrix[8], get_column_content_via_iterators(m.get_column(13))); + } else { + test_content_equality(reducedMatrix, m); + } + + std::set, BarComp> bars1; + std::set, BarComp> bars2; + std::set, BarComp> bars3; + // bars are not ordered the same for all matrices + for (auto it = barcode.begin(); it != barcode.end(); ++it) { + //three access possibilities + bars1.emplace(it->dim, it->birth, it->death); + bars2.emplace(std::get<2>(*it), std::get<0>(*it), std::get<1>(*it)); + auto [ x, y, z ] = *it; + bars3.emplace(z, x, y); + } + auto it = bars1.begin(); + BOOST_CHECK_EQUAL(std::get<0>(*it), 0); + BOOST_CHECK_EQUAL(std::get<1>(*it), 0); + // TODO: verify why this -1 works...: it->death should be unsigned int, so double conversion + BOOST_CHECK_EQUAL(std::get<2>(*it), -1); + ++it; + BOOST_CHECK_EQUAL(std::get<0>(*it), 0); + BOOST_CHECK_EQUAL(std::get<1>(*it), 1); + BOOST_CHECK_EQUAL(std::get<2>(*it), 3); + ++it; + BOOST_CHECK_EQUAL(std::get<0>(*it), 0); + BOOST_CHECK_EQUAL(std::get<1>(*it), 2); + BOOST_CHECK_EQUAL(std::get<2>(*it), 4); + ++it; + BOOST_CHECK_EQUAL(std::get<0>(*it), 0); + BOOST_CHECK_EQUAL(std::get<1>(*it), 7); + BOOST_CHECK_EQUAL(std::get<2>(*it), 8); + ++it; + BOOST_CHECK_EQUAL(std::get<0>(*it), 1); + BOOST_CHECK_EQUAL(std::get<1>(*it), 5); + BOOST_CHECK_EQUAL(std::get<2>(*it), 6); + ++it; + BOOST_CHECK(it == bars1.end()); + + BOOST_CHECK(bars1 == bars2); + BOOST_CHECK(bars1 == bars3); +} + template void test_base_swaps() { auto columns = build_simple_boundary_matrix(); diff --git a/src/Persistence_matrix/test/pm_test_utilities.h b/src/Persistence_matrix/test/pm_test_utilities.h index f0acb546cb..81c2813efc 100644 --- a/src/Persistence_matrix/test/pm_test_utilities.h +++ b/src/Persistence_matrix/test/pm_test_utilities.h @@ -160,6 +160,7 @@ void test_content_equality(const std::vector(b, get_column_content_via_iterators(col)); } + BOOST_CHECK_EQUAL(m.get_number_of_columns(), i); } #endif // PM_TEST_UTILITIES_H