From 93a1404d9a85b4a6d580239bdb1c8911aca7624e Mon Sep 17 00:00:00 2001 From: Joel Falcou Date: Tue, 2 Sep 2025 19:52:22 +0200 Subject: [PATCH] - Refurbish block implementation to support nested block - Add missing extractors --- include/rotgen/common/ref.hpp | 34 ++- include/rotgen/concepts.hpp | 4 +- include/rotgen/dynamic/block.hpp | 124 +++++--- include/rotgen/dynamic/map.hpp | 14 +- include/rotgen/dynamic/matrix.hpp | 21 +- include/rotgen/extract.hpp | 309 +++++++++---------- include/rotgen/fixed/block.hpp | 93 ++++-- include/rotgen/fixed/matrix.hpp | 1 + include/rotgen/impl/block.hpp | 68 ++--- include/rotgen/impl/block_indirect.hpp | 43 +++ include/rotgen/impl/block_model.hpp | 53 ++-- include/rotgen/impl/map.hpp | 77 +---- include/rotgen/impl/map_indirect.hpp | 35 +++ src/block.cpp | 55 +--- src/block_indirect.cpp | 51 ++++ src/block_model.cpp | 400 +++++++++++++++++++++---- src/map.cpp | 96 +----- src/map_indirect.cpp | 43 +++ src/map_model.cpp | 1 - src/matrix_model.cpp | 6 +- test/CMakeLists.txt | 5 + test/integration/extract.cpp | 51 ++++ test/unit/block/basic_api.cpp | 14 +- test/unit/block/extract.cpp | 237 ++++++++++++--- 24 files changed, 1205 insertions(+), 630 deletions(-) create mode 100644 include/rotgen/impl/block_indirect.hpp create mode 100644 include/rotgen/impl/map_indirect.hpp create mode 100644 src/block_indirect.cpp create mode 100644 src/map_indirect.cpp create mode 100644 test/integration/extract.cpp diff --git a/include/rotgen/common/ref.hpp b/include/rotgen/common/ref.hpp index 656acf3..de58989 100644 --- a/include/rotgen/common/ref.hpp +++ b/include/rotgen/common/ref.hpp @@ -25,6 +25,8 @@ namespace rotgen using value_type = typename T::value_type; using rotgen_tag = void; + static constexpr int storage_order = T::storage_order; + using parent::operator(); using parent::rows; using parent::cols; @@ -59,19 +61,19 @@ namespace rotgen ref(matrix& m) : parent(m.data(), m.rows(), m.cols(), strides(m)) { - static_assert((O & 1) == Options, "ref: Incompatible storage layout"); + static_assert((O & 1) == storage_order, "ref: Incompatible storage layout"); } - template - ref(block& b) : parent(b.data(), b.rows(), b.cols(), stride_type{b.outerStride(),b.innerStride()}) + template + ref(block& b) : parent(b.data(), b.rows(), b.cols(), stride_type{b.outerStride(),b.innerStride()}) { - static_assert((Ref::Options & 1) == Options, "ref: Incompatible storage layout"); + static_assert((Ref::storage_order & 1) == storage_order, "ref: Incompatible storage layout"); } template ref(map& b) : parent(b.data(), b.rows(), b.cols(), stride_type{b.outerStride(),b.innerStride()}) { - static_assert((Ref::Options & 1) == Options, "ref: Incompatible storage layout"); + static_assert((Ref::storage_order & 1) == storage_order, "ref: Incompatible storage layout"); } ref(parent& m) : parent(m.data(), m.rows(), m.cols()) {} @@ -89,7 +91,9 @@ namespace rotgen public: using parent = map; using value_type = typename T::value_type; - using rotgen_tag = void; + using rotgen_tag = void; + + static constexpr int storage_order = T::storage_order; using parent::operator(); using parent::rows; @@ -125,19 +129,19 @@ namespace rotgen ref(matrix const& m) : parent(m.data(), m.rows(), m.cols(), strides(m)) { - static_assert((O & 1) == Options, "ref: Incompatible storage layout"); + static_assert((O & 1) == storage_order, "ref: Incompatible storage layout"); } - template - ref(block const& b) : parent(b.data(), b.rows(), b.cols(), stride_type{b.outerStride(),b.innerStride()}) + template + ref(block const& b) : parent(b.data(), b.rows(), b.cols(), stride_type{b.outerStride(),b.innerStride()}) { - static_assert((Ref::Options & 1) == Options, "ref: Incompatible storage layout"); + static_assert((Ref::storage_order & 1) == storage_order, "ref: Incompatible storage layout"); } template ref(map const& b) : parent(b.data(), b.rows(), b.cols(), stride_type{b.outerStride(),b.innerStride()}) { - static_assert((Ref::Options & 1) == Options, "ref: Incompatible storage layout"); + static_assert((Ref::storage_order & 1) == storage_order, "ref: Incompatible storage layout"); } ref(parent const& m) : parent(m.data(), m.rows(), m.cols()) {} @@ -151,14 +155,14 @@ namespace rotgen template ref(matrix&) -> ref>; - template - ref(block& b) -> ref; + template + ref(block& b) -> ref; template ref(matrix const&) -> ref const>; - template - ref(block const& b) -> ref; + template + ref(block const& b) -> ref; template bool operator==(ref lhs, ref rhs) diff --git a/include/rotgen/concepts.hpp b/include/rotgen/concepts.hpp index ab2071c..3c26e53 100644 --- a/include/rotgen/concepts.hpp +++ b/include/rotgen/concepts.hpp @@ -15,8 +15,8 @@ namespace rotgen::concepts template concept entity = requires(T const&) { - typename T::rotgen_tag; - typename T::parent; + typename std::remove_cvref_t::rotgen_tag; + typename std::remove_cvref_t::parent; }; //================================================================================================ diff --git a/include/rotgen/dynamic/block.hpp b/include/rotgen/dynamic/block.hpp index abeb6ee..977f4a7 100644 --- a/include/rotgen/dynamic/block.hpp +++ b/include/rotgen/dynamic/block.hpp @@ -15,7 +15,7 @@ namespace rotgen { - template + template class block : public find_block { public: @@ -25,20 +25,24 @@ namespace rotgen using parent = find_block; using rotgen_tag = void; - using value_type = typename Ref::value_type; - static constexpr int storage_order = (ForceStorageOrder == -1) ? Ref::storage_order : ForceStorageOrder; + using rotgen_block_tag = void; + using value_type = typename std::remove_const_t::value_type; + + static constexpr int storage_order = Ref::storage_order; + static constexpr bool is_immutable = std::is_const_v; using concrete_type = matrix; using concrete_dynamic_type = matrix; - static constexpr int RowsAtCompileTime = Rows; - static constexpr int ColsAtCompileTime = Cols; - static constexpr int Options = Ref::Options; + static constexpr int RowsAtCompileTime = Rows; + static constexpr int ColsAtCompileTime = Cols; + static constexpr int Options = Ref::Options; + static constexpr bool IsRowMajor = (storage_order & RowMajor) == RowMajor; - static constexpr bool is_defined_static = false; - static constexpr bool has_static_storage = false; + static constexpr bool is_defined_static = false; + static constexpr bool has_static_storage = false; using parent::operator=; - block& operator=(concepts::entity auto const& other) + block& operator=(concepts::entity auto const& other) requires(!is_immutable) { assert(parent::rows() == other.rows() && parent::cols() == other.cols()); for (rotgen::Index r = 0; r < parent::rows(); ++r) @@ -48,26 +52,58 @@ namespace rotgen return *this; } - block(Ref& r, std::size_t i0, std::size_t j0, std::size_t ni, std::size_t nj) : parent(r,i0,j0,ni,nj) + block(Ref const& r, std::size_t i0, std::size_t j0, std::size_t ni, std::size_t nj) + requires( !requires{typename Ref::rotgen_block_tag; } && is_immutable) + : parent(r,i0,j0,ni,nj) {} - block(Ref& r, std::size_t i0, std::size_t j0) requires(Rows != -1 && Cols != -1) + block(Ref const& r, std::size_t i0, std::size_t j0, std::size_t ni, std::size_t nj) + requires( requires{typename Ref::rotgen_block_tag; } && is_immutable) + : parent(*r.storage(),i0,j0,ni,nj) + {} + + block(Ref const& r, std::size_t i0, std::size_t j0) + requires(!requires{typename Ref::rotgen_block_tag; } && Rows != -1 && Cols != -1 && is_immutable) : parent(r,i0,j0,Rows,Cols) {} + block(Ref const& r, std::size_t i0, std::size_t j0) + requires(requires{typename Ref::rotgen_block_tag; } && Rows != -1 && Cols != -1 && is_immutable) + : parent(*r.storage(),i0,j0,Rows,Cols) + {} + + block(Ref& r, std::size_t i0, std::size_t j0, std::size_t ni, std::size_t nj) + requires( !requires{typename Ref::rotgen_block_tag; } && !is_immutable) + : parent(r,i0,j0,ni,nj) + {} + + block(Ref& r, std::size_t i0, std::size_t j0, std::size_t ni, std::size_t nj) + requires( requires{typename Ref::rotgen_block_tag; } && !is_immutable) + : parent(*r.storage(),i0,j0,ni,nj) + {} + + block(Ref& r, std::size_t i0, std::size_t j0) + requires(!requires{typename Ref::rotgen_block_tag; } && Rows != -1 && Cols != -1 && !is_immutable) + : parent(r,i0,j0,Rows,Cols) + {} + + block(Ref& r, std::size_t i0, std::size_t j0) + requires(requires{typename Ref::rotgen_block_tag; } && Rows != -1 && Cols != -1 && !is_immutable) + : parent(*r.storage(),i0,j0,Rows,Cols) + {} + block(parent const& base) : parent(base) {} bool is_contiguous_linear() const { if(parent::innerStride() != 1) return false; - // outer‐stride must equal the “inner‐dimension length” if constexpr(storage_order) return parent::outerStride() == parent::cols(); else return parent::outerStride() == parent::rows(); } - value_type& operator()(Index i, Index j) { return parent::operator()(i,j); } + value_type& operator()(Index i, Index j) requires(!is_immutable) { return parent::operator()(i,j); } - value_type& operator()(Index i) + value_type& operator()(Index i) requires(!is_immutable) { assert(is_contiguous_linear()); return parent::operator()(i); @@ -96,22 +132,22 @@ namespace rotgen return concrete_type(static_cast(*this).adjoint()); } - void transposeInPlace() { parent::transposeInPlace(); } + void transposeInPlace() requires(!is_immutable) { parent::transposeInPlace(); } - void adjointInPlace() { parent::adjointInPlace(); } + void adjointInPlace() requires(!is_immutable) { parent::adjointInPlace(); } friend bool operator==(block const& lhs, block const& rhs) { return static_cast(lhs) == static_cast(rhs); } - block& operator+=(block const& rhs) + block& operator+=(block const& rhs) requires(!is_immutable) { base() += static_cast(rhs); return *this; } - block& operator-=(block const& rhs) + block& operator-=(block const& rhs) requires(!is_immutable) { base() -= static_cast(rhs); return *this; @@ -122,19 +158,19 @@ namespace rotgen return concrete_type(static_cast(*this).operator-()); } - block& operator*=(block const& rhs) + block& operator*=(block const& rhs) requires(!is_immutable) { base() *= static_cast(rhs); return *this; } - block& operator*=(value_type rhs) + block& operator*=(value_type rhs) requires(!is_immutable) { base() *= rhs; return *this; } - block& operator/=(value_type rhs) + block& operator/=(value_type rhs) requires(!is_immutable) { base() /= rhs; return *this; @@ -205,31 +241,31 @@ namespace rotgen return parent::Identity(rows, cols); } - block& setOnes() + block& setOnes() requires(!is_immutable) { parent::assign(parent::Ones(parent::rows(), parent::cols())); return *this; } - block& setZero() + block& setZero() requires(!is_immutable) { parent::assign(parent::Zero(parent::rows(), parent::cols())); return *this; } - block& setConstant(value_type value) + block& setConstant(value_type value) requires(!is_immutable) { parent::assign(parent::Constant(parent::rows(), parent::cols(), value)); return *this; } - block& setRandom() + block& setRandom() requires(!is_immutable) { parent::assign(parent::Random(parent::rows(), parent::cols())); return *this; } - block& setIdentity() + block& setIdentity() requires(!is_immutable) { parent::assign(parent::Identity(parent::rows(), parent::cols())); return *this; @@ -246,45 +282,45 @@ namespace rotgen parent const& base() const { return static_cast(*this); } }; - template - auto operator+(block const& lhs, block const& rhs) + template + auto operator+(block const& lhs, block const& rhs) { - using concrete_type = typename block::concrete_type; + using concrete_type = typename block::concrete_type; return concrete_type(lhs.base().add(rhs)); } - template - auto operator-(block const& lhs, block const& rhs) + template + auto operator-(block const& lhs, block const& rhs) { - using concrete_type = typename block::concrete_type; + using concrete_type = typename block::concrete_type; return concrete_type(lhs.base().sub(rhs)); } - template - auto operator*(block const& lhs, block const& rhs) + template + auto operator*(block const& lhs, block const& rhs) { - using concrete_type = typename block::concrete_type; + using concrete_type = typename block::concrete_type; return concrete_type(lhs.base().mul(rhs)); } - template - auto operator*(block const& lhs, double rhs) + template + auto operator*(block const& lhs, double rhs) { - using concrete_type = typename block::concrete_type; + using concrete_type = typename block::concrete_type; return concrete_type(lhs.base().mul(rhs)); } - template - auto operator*(double lhs, block const& rhs) + template + auto operator*(double lhs, block const& rhs) { - using concrete_type = typename block::concrete_type; + using concrete_type = typename block::concrete_type; return concrete_type(rhs.base().mul(lhs)); } - template - auto operator/(block const& lhs, double rhs) + template + auto operator/(block const& lhs, double rhs) { - using concrete_type = typename block::concrete_type; + using concrete_type = typename block::concrete_type; return concrete_type(lhs.base().div(rhs)); } } \ No newline at end of file diff --git a/include/rotgen/dynamic/map.hpp b/include/rotgen/dynamic/map.hpp index 153fbb6..1a9b02e 100644 --- a/include/rotgen/dynamic/map.hpp +++ b/include/rotgen/dynamic/map.hpp @@ -22,12 +22,14 @@ namespace rotgen , "[ROTGEN][CRITICAL] - Map of non-rotgen type instanciated" ); - using parent = find_map; - using rotgen_tag = void; - using value_type = typename std::remove_const_t::value_type; - using concrete_type = typename std::remove_const_t::concrete_type; - static constexpr int storage_order = Ref::storage_order; - static constexpr bool has_static_storage = false; + using parent = find_map; + using rotgen_tag = void; + using value_type = typename std::remove_const_t::value_type; + using concrete_type = typename std::remove_const_t::concrete_type; + + static constexpr bool IsRowMajor = Ref::IsRowMajor; + static constexpr int storage_order = Ref::storage_order; + static constexpr bool has_static_storage = false; static constexpr bool is_immutable = std::is_const_v; static constexpr bool is_defined_static = false; diff --git a/include/rotgen/dynamic/matrix.hpp b/include/rotgen/dynamic/matrix.hpp index b1aae1c..02afd79 100644 --- a/include/rotgen/dynamic/matrix.hpp +++ b/include/rotgen/dynamic/matrix.hpp @@ -21,17 +21,18 @@ namespace rotgen class matrix : public find_matrix { public: - using parent = find_matrix; - using rotgen_tag = void; - using concrete_type = matrix; - using value_type = Scalar; - static constexpr auto storage_order = Opts & 1; + using parent = find_matrix; + using rotgen_tag = void; + using concrete_type = matrix; + using value_type = Scalar; - static constexpr int RowsAtCompileTime = Rows; - static constexpr int ColsAtCompileTime = Cols; - static constexpr int Options = Opts; - static constexpr bool is_defined_static = false; - static constexpr bool has_static_storage = false; + static constexpr auto storage_order = Opts & 1; + static constexpr int RowsAtCompileTime = Rows; + static constexpr int ColsAtCompileTime = Cols; + static constexpr int Options = Opts; + static constexpr bool IsRowMajor = (Opts & RowMajor) == RowMajor; + static constexpr bool is_defined_static = false; + static constexpr bool has_static_storage = false; matrix() : parent(Rows==-1?0:Rows,Cols==-1?0:Cols) {} diff --git a/include/rotgen/extract.hpp b/include/rotgen/extract.hpp index 8cf77b5..77c3535 100644 --- a/include/rotgen/extract.hpp +++ b/include/rotgen/extract.hpp @@ -9,224 +9,233 @@ namespace rotgen { - template< typename S, int R , int C - , int Opts , int MaxR, int MaxC - > - auto extract(matrix& m, int i0, int j0,int ni, int nj) + namespace detail { - using base = matrix; - return block(m, i0,j0,ni,nj); + template + void validate_extract ( [[maybe_unused]] Entity& e + , [[maybe_unused]] Index i0, [[maybe_unused]] Index j0 + , [[maybe_unused]] Index ni, [[maybe_unused]] Index nj + ) + { + assert(i0 >= 0 && "block extraction uses negative row index."); + assert(j0 >= 0 && "block extraction uses negative col index."); + assert(i0 + ni <= e.rows() && "block extraction rows is out of range."); + assert(j0 + nj <= e.cols() && "block extraction cols is out of range."); + } + } + //======================== EXTRACT ======================== + template + auto extract(Entity& e, Index i0, Index j0, Index ni, Index nj) + { + detail::validate_extract(e,i0,j0,ni,nj); + return block(e, i0, j0, ni, nj); } - template< int NI, int NJ - , typename S, int R , int C - , int Opts , int MaxR, int MaxC - > - auto extract(matrix& m, int i0, int j0) + template + requires(NI!=-1 && NJ!=-1) + auto extract(Entity& e, Index i0, Index j0) { - using base = matrix; - return block(m,i0,j0); + detail::validate_extract(e,i0,j0,NI,NJ); + return block(e, i0, j0); } - template< typename S, int R , int C - , int Opts , int MaxR, int MaxC - > - auto topLeftCorner(matrix& m, int ni, int nj) + template + requires((NI!=-1) != (NJ!=-1)) + auto extract(Entity& e, Index i0, Index j0, Index ni, Index nj) { - using base = matrix; - return block(m,0,0,ni,nj); + detail::validate_extract(e,i0,j0,ni,nj); + return block(e, i0, j0, ni, nj); } - template< typename S, int R , int C - , int Opts , int MaxR, int MaxC - > - auto topRightCorner(matrix& m, int ni, int nj) + //======================== TOP LEFT CORNER ======================== + template + auto topLeftCorner(Entity& e, Index ni, Index nj) { - using base = matrix; - return block(m,0,m.cols()-nj,ni,nj); + return extract(e, 0, 0, ni, nj); } - template< typename S, int R , int C - , int Opts , int MaxR, int MaxC - > - auto bottomLeftCorner(matrix& m, int ni, int nj) + template + auto topLeftCorner(Entity& e) { - using base = matrix; - return block(m,m.rows()-ni,0,ni,nj); + return extract(e, 0, 0); } - template< typename S, int R , int C - , int Opts , int MaxR, int MaxC - > - auto bottomRightCorner(matrix& m, int ni, int nj) + //======================== TOP RIGHT CORNER ======================== + template + auto topRightCorner(Entity& e, Index ni, Index nj) { - using base = matrix; - return block(m,m.rows()-ni,m.cols()-nj,ni,nj); + return extract(e, 0, e.cols() - nj, ni, nj); } - template< typename S, int R , int C - , int Opts , int MaxR, int MaxC - > - auto topRows(matrix& m, int ni) + template + auto topRightCorner(Entity& e) { - using base = matrix; - return block(m,0,0,ni,m.cols()); + return extract(e, 0, e.cols()-NJ); } - template< typename S, int R , int C, - int Opts , int MaxR, int MaxC - > - auto middleRows(matrix& m, int i0, int ni) + //======================== BOTTOM LEFT CORNER ======================== + template + auto bottomLeftCorner(Entity& e, Index ni, Index nj) { - using base = matrix; - return block(m,i0,0,ni,m.cols()); + return extract(e, e.rows() - ni, 0, ni, nj); } - template< typename S, int R , int C - , int Opts , int MaxR, int MaxC - > - auto bottomRows(matrix& m, int ni) + template + auto bottomLeftCorner(Entity& e) { - using base = matrix; - return block(m,m.rows()-ni,0,ni,m.cols()); + return extract(e, e.rows()-NI, 0); } - template< typename S, int R , int C - , int Opts , int MaxR, int MaxC - > - auto leftCols(matrix& m, int nj) + //======================== BOTTOM RIGHT CORNER ======================== + template + auto bottomRightCorner(Entity& e, Index ni, Index nj) { - using base = matrix; - return block(m,0,0,m.rows(),nj); + return extract(e, e.rows() - ni, e.cols() - nj, ni, nj); } - template< typename S, int R , int C, - int Opts , int MaxR, int MaxC - > - auto middleCols(matrix& m, int j0, int nj) + template + auto bottomRightCorner(Entity& e) { - using base = matrix; - return block(m,0,j0,m.rows(),nj); + return extract(e, e.rows()-NI, e.cols()-NJ); } - template< typename S, int R , int C - , int Opts , int MaxR, int MaxC - > - auto rightCols(matrix& m, int nj) + //======================== TOP ROWS ======================== + template + auto topRows(Entity& e, Index ni) { - using base = matrix; - return block(m,0,m.cols()-nj,m.rows(),nj); + return extract(e, 0, 0, ni, e.cols()); } - template< typename S, int R, int C - , int Opts , int MaxR, int MaxC - > - auto row(matrix& m, int i0) + template + auto topRows(Entity& e) { - using base = matrix; - return block(m,i0,0, 1, m.cols()); + return extract(e, 0, 0, NI,e.cols()); } - template< typename S, int R, int C - , int Opts , int MaxR, int MaxC - > - auto col(matrix& m, int j0) + //======================== MIDDLE ROWS ======================== + template + auto middleRows(Entity& e, Index i0, Index ni) { - using base = matrix; - return block(m,0,j0, m.rows(), 1); + return extract(e, i0, 0, ni, e.cols()); } - template< int NI, typename S, int R, int C, - int Opts, int MaxR, int MaxC - > - auto topRows(matrix& m) + template + auto middleRows(Entity& e, Index i0) { - using base = matrix; - return block(m,0,0, NI, m.cols()); + return extract(e, i0, 0,NI,e.cols()); } - template< int NI, typename S, int R, int C, - int Opts, int MaxR, int MaxC - > - auto bottomRows(matrix& m) + //======================== BOTTOM ROWS ======================== + template + auto bottomRows(Entity& e, Index ni) { - using base = matrix; - return block(m,m.rows()-NI,0, NI, m.cols()); + return extract(e, e.rows() - ni, 0, ni, e.cols()); } - template< int NI, typename S, int R, int C, - int Opts , int MaxR, int MaxC - > - auto middleRows(matrix& m, int i0) + template + auto bottomRows(Entity& e) { - using base = matrix; - return block(m,i0,0, NI, m.cols()); + return extract(e, e.rows()-NI, 0,NI,e.cols()); } - template< int NJ, typename S, int R, int C, - int Opts, int MaxR, int MaxC - > - auto leftCols(matrix& m) + //======================== LEFT COLS ======================== + template + auto leftCols(Entity& e, Index nj) { - using base = matrix; - return block(m,0,0, m.rows(), NJ); + return extract(e, 0, 0, e.rows(), nj); } - template< int NJ, typename S, int R, int C, - int Opts, int MaxR, int MaxC - > - auto rightCols(matrix& m) + template + auto leftCols(Entity& e) { - using base = matrix; - return block(m,0,m.cols()-NJ, m.rows(), NJ); + return extract<-1,NJ>(e, 0, 0,e.rows(),NJ); } - template< int NJ, typename S, int R, int C, - int Opts , int MaxR, int MaxC - > - auto middleCols(matrix& m, int j0) + //======================== MIDDLE COLS ======================== + template + auto middleCols(Entity& e, Index j0, Index nj) { - using base = matrix; - return block(m,0,j0, m.rows(), NJ); + return extract(e, 0, j0, e.rows(), nj); } - template< int NI, int NJ - , typename S, int R , int C - , int Opts , int MaxR, int MaxC - > - auto topLeftCorner(matrix& m) + template + auto middleCols(Entity& e, Index j0) { - using base = matrix; - return block(m,0,0); + return extract<-1,NJ>(e, 0, j0,e.rows(),NJ); } - template< int NI, int NJ - , typename S, int R , int C - , int Opts , int MaxR, int MaxC - > - auto topRightCorner(matrix& m) + //======================== RIGHT COLS ======================== + template + auto rightCols(Entity& e, Index nj) { - using base = matrix; - return block(m,0,m.cols()-NJ); + return extract(e, 0, e.cols() - nj, e.rows(), nj); } - template< int NI, int NJ - , typename S, int R , int C - , int Opts , int MaxR, int MaxC - > - auto bottomLeftCorner(matrix& m) + template + auto rightCols(Entity& e) { - using base = matrix; - return block(m,m.rows()-NI,0); + return extract<-1,NJ>(e, 0, e.cols()-NJ,e.rows(),NJ); } - template< int NI, int NJ - , typename S, int R , int C - , int Opts , int MaxR, int MaxC - > - auto bottomRightCorner(matrix& m) + //======================== ROW ======================== + template + auto row(Entity& e, Index i0) { - using base = matrix; - return block(m,m.rows()-NI,m.cols()-NJ); + return extract<1,-1>(e, i0, 0, 1, e.cols()); } -} \ No newline at end of file + + //======================== COL ======================== + template + auto col(Entity& e, Index j0) + { + return extract<-1,1>(e, 0, j0, e.rows(), 1); + } + + //======================== VECTOR HEAD ======================== + template + auto head(Entity& e, Index n) + requires(Entity::RowsAtCompileTime==1 || Entity::ColsAtCompileTime==1) + { + if constexpr(Entity::RowsAtCompileTime==1) return extract<1,Dynamic>(e,0,0,1,n); + else if constexpr(Entity::ColsAtCompileTime==1) return extract(e,0,0,n,1); + } + + template + auto head(Entity& e) requires(Entity::RowsAtCompileTime==1 || Entity::ColsAtCompileTime==1) + { + if constexpr(Entity::RowsAtCompileTime==1) return extract<1,N>(e,0,0); + else if constexpr(Entity::ColsAtCompileTime==1) return extract(e,0,0); + } + + //======================== VECTOR TAIL ======================== + template + auto tail(Entity& e, Index n) + requires(Entity::RowsAtCompileTime==1 || Entity::ColsAtCompileTime==1) + { + if constexpr(Entity::RowsAtCompileTime==1) return extract<1,Dynamic>(e,0,e.cols()-n,1,n); + else if constexpr(Entity::ColsAtCompileTime==1) return extract(e,e.rows()-n,0,n,1); + } + + template + auto tail(Entity& e) requires(Entity::RowsAtCompileTime==1 || Entity::ColsAtCompileTime==1) + { + if constexpr(Entity::RowsAtCompileTime==1) return extract<1,N>(e,0,e.cols()-N); + else if constexpr(Entity::ColsAtCompileTime==1) return extract(e,e.rows()-N,0); + } + + //======================== VECTOR SEGMENT ======================== + template + auto segment(Entity& e, Index s, Index n) + requires(Entity::RowsAtCompileTime==1 || Entity::ColsAtCompileTime==1) + { + if constexpr(Entity::RowsAtCompileTime==1) return extract<1,Dynamic>(e,0,s,1,n); + else if constexpr(Entity::ColsAtCompileTime==1) return extract(e,s,0,n,1); + } + + template + auto segment(Entity& e, Index s) requires(Entity::RowsAtCompileTime==1 || Entity::ColsAtCompileTime==1) + { + if constexpr(Entity::RowsAtCompileTime==1) return extract<1,N>(e,0,s); + else if constexpr(Entity::ColsAtCompileTime==1) return extract(e,s,0); + } +} diff --git a/include/rotgen/fixed/block.hpp b/include/rotgen/fixed/block.hpp index d86b75d..1a99ee1 100644 --- a/include/rotgen/fixed/block.hpp +++ b/include/rotgen/fixed/block.hpp @@ -14,30 +14,43 @@ namespace rotgen { namespace detail { - template - using block_type = std::conditional_t < storage_status - , Eigen::Block - , Eigen::Block - >; + template + struct compute_block_type + { + using ref_t = std::conditional_t; + + using type = std::conditional_t < storage_status + , Eigen::Block + , Eigen::Block + >; + }; + + template + using block_type = typename compute_block_type::type; } template< typename Ref , int Rows = Dynamic, int Cols = Dynamic , bool Inner = false , int ForceStorageOrder = -1 > - class block : private detail::block_type + class block : private detail::block_type, Rows, Cols, Inner,std::is_const_v > { static_assert ( concepts::entity , "[ROTGEN][CRITICAL] - Block of non-rotgen type instanciated" ); public: - using rotgen_tag = void; - using parent = detail::block_type; - using value_type = typename parent::value_type; - using Index = typename parent::Index; + using rotgen_tag = void; + using rotgen_block_tag = void; + using parent = detail::block_type, Rows, Cols, Inner,std::is_const_v>; + using value_type = typename parent::value_type; + using Index = typename parent::Index; + + static constexpr int storage_order = (ForceStorageOrder == -1) ? Ref::storage_order : ForceStorageOrder; + static constexpr bool is_immutable = std::is_const_v; + + static constexpr bool IsRowMajor = parent::IsRowMajor; - static constexpr int storage_order = (ForceStorageOrder == -1) ? Ref::storage_order : ForceStorageOrder; using concrete_type = matrix; using concrete_dynamic_type = matrix; @@ -58,10 +71,23 @@ namespace rotgen block& operator=(const block&) = default; block& operator=(block&&) = default; - block(Ref& r, std::size_t i0, std::size_t j0, std::size_t ni, std::size_t nj) : parent(r.base(),i0,j0,ni,nj) + block(Ref const& r, std::size_t i0, std::size_t j0, std::size_t ni, std::size_t nj) + requires(is_immutable) + : parent(r.base(),i0,j0,ni,nj) {} - block(Ref& r, std::size_t i0, std::size_t j0) requires(Rows != -1 && Cols != -1) + block(Ref const& r, std::size_t i0, std::size_t j0) + requires(Rows != -1 && Cols != -1 && is_immutable) + : parent(r.base(),i0,j0,Rows,Cols) + {} + + block(Ref& r, std::size_t i0, std::size_t j0, std::size_t ni, std::size_t nj) + requires(!is_immutable) + : parent(r.base(),i0,j0,ni,nj) + {} + + block(Ref& r, std::size_t i0, std::size_t j0) + requires(Rows != -1 && Cols != -1 && !is_immutable) : parent(r.base(),i0,j0,Rows,Cols) {} @@ -111,8 +137,8 @@ namespace rotgen return as_concrete_type(res); } - void transposeInPlace() { parent::transposeInPlace(); } - void adjointInPlace() { parent::adjointInPlace(); } + void transposeInPlace() requires(!is_immutable) { parent::transposeInPlace(); } + void adjointInPlace() requires(!is_immutable) { parent::adjointInPlace(); } static concrete_type Constant(value_type value) requires (Rows != -1 && Cols != -1) { @@ -174,61 +200,61 @@ namespace rotgen return parent::Random(rows, cols); } - block& setOnes() + block& setOnes() requires(!is_immutable) { *this = parent::Ones(rows(), cols()); return *this; } - block& setOnes(int r, int c) + block& setOnes(int r, int c) requires(!is_immutable) { *this = parent::Ones(r, c); return *this; } - block& setZero() + block& setZero() requires(!is_immutable) { *this = parent::Zero(rows(), cols()); return *this; } - block& setZero(int r, int c) + block& setZero(int r, int c) requires(!is_immutable) { *this = parent::Zero(r,c); return *this; } - block& setConstant(value_type value) + block& setConstant(value_type value) requires(!is_immutable) { *this = parent::Constant(rows(), cols(), value); return *this; } - block& setConstant(int r, int c, value_type value) + block& setConstant(int r, int c, value_type value) requires(!is_immutable) { *this = parent::Constant(r,c, value); return *this; } - block& setRandom() + block& setRandom() requires(!is_immutable) { *this = parent::Random(rows(),cols()); return *this; } - block& setRandom(int r, int c) + block& setRandom(int r, int c) requires(!is_immutable) { *this = parent::Random(r,c); return *this; } - block& setIdentity() + block& setIdentity() requires(!is_immutable) { *this = parent::Identity(rows(),cols()); return *this; } - block& setIdentity(int r, int c) + block& setIdentity(int r, int c) requires(!is_immutable) { *this = parent::Identity(r,c); return *this; @@ -249,10 +275,10 @@ namespace rotgen else return parent::outerStride() == parent::rows(); } - value_type& operator()(Index i, Index j) { return base()(i,j); } + value_type& operator()(Index i, Index j) requires(!is_immutable) { return base()(i,j); } value_type operator()(Index i, Index j) const { return base()(i,j); } - value_type& operator()(Index i) + value_type& operator()(Index i) requires(!is_immutable) { assert(is_contiguous_linear()); return base().data()[i]; @@ -279,13 +305,16 @@ namespace rotgen using parent::sum; using parent::data; - block& operator+=(block const& rhs) + Index startRow() const { return base().startRow(); } + Index startCol() const { return base().startCol(); } + + block& operator+=(block const& rhs) requires(!is_immutable) { static_cast(*this) += static_cast(rhs); return *this; } - block& operator-=(block const& rhs) + block& operator-=(block const& rhs) requires(!is_immutable) { static_cast(*this) -= static_cast(rhs); return *this; @@ -296,19 +325,19 @@ namespace rotgen return concrete_type(static_cast(*this).operator-()); } - block& operator*=(block const& rhs) + block& operator*=(block const& rhs) requires(!is_immutable) { static_cast(*this) *= static_cast(rhs); return *this; } - block& operator*=(value_type rhs) + block& operator*=(value_type rhs) requires(!is_immutable) { static_cast(*this) *= rhs; return *this; } - block& operator/=(value_type rhs) + block& operator/=(value_type rhs) requires(!is_immutable) { static_cast(*this) /= rhs; return *this; diff --git a/include/rotgen/fixed/matrix.hpp b/include/rotgen/fixed/matrix.hpp index c02063c..de8b989 100644 --- a/include/rotgen/fixed/matrix.hpp +++ b/include/rotgen/fixed/matrix.hpp @@ -42,6 +42,7 @@ namespace rotgen static constexpr int RowsAtCompileTime = Rows; static constexpr int ColsAtCompileTime = Cols; static constexpr int Options = parent::Options; + static constexpr bool IsRowMajor = parent::IsRowMajor; template using as_concrete_type = as_concrete_t; diff --git a/include/rotgen/impl/block.hpp b/include/rotgen/impl/block.hpp index bb5a75d..1834c3b 100644 --- a/include/rotgen/impl/block.hpp +++ b/include/rotgen/impl/block.hpp @@ -9,55 +9,47 @@ #include #include +#include #include #include #include namespace rotgen { - #define SIZE 64 - #define TYPE double + class matrix_impl64_row; + class matrix_impl64_col; + class matrix_impl32_row; + class matrix_impl32_col; - #define CLASSNAME ROTGEN_MATRIX_NAME(block_impl,SIZE,_col) - #define SOURCENAME ROTGEN_MATRIX_NAME(matrix_impl,SIZE,_col) - #include - #undef CLASSNAME - #undef SOURCENAME - #define CLASSNAME ROTGEN_MATRIX_NAME(block_impl,SIZE,_row) - #define SOURCENAME ROTGEN_MATRIX_NAME(matrix_impl,SIZE,_row) - #include - #undef CLASSNAME - #undef SOURCENAME + #define USE_CONST + #define CONST const + #define BASENAME block_const_impl + #include + #undef BASENAME + #undef CONST + #undef USE_CONST - #undef SIZE - #undef TYPE + #define CONST + #define BASENAME block_impl + #include + #undef BASENAME + #undef CONST - #define SIZE 32 - #define TYPE float + template struct find_block_impl; - #define CLASSNAME ROTGEN_MATRIX_NAME(block_impl,SIZE,_col) - #define SOURCENAME ROTGEN_MATRIX_NAME(matrix_impl,SIZE,_col) - #include - #undef CLASSNAME - #undef SOURCENAME - - #define CLASSNAME ROTGEN_MATRIX_NAME(block_impl,SIZE,_row) - #define SOURCENAME ROTGEN_MATRIX_NAME(matrix_impl,SIZE,_row) - #include - #undef CLASSNAME - #undef SOURCENAME - - #undef SIZE - #undef TYPE - - template struct find_block_impl; - - template<> struct find_block_impl { using type = block_impl32_col; }; - template<> struct find_block_impl { using type = block_impl32_row; }; - template<> struct find_block_impl { using type = block_impl64_col; }; - template<> struct find_block_impl { using type = block_impl64_row; }; + template<> struct find_block_impl { using type = block_const_impl32_col; }; + template<> struct find_block_impl { using type = block_const_impl32_row; }; + template<> struct find_block_impl { using type = block_const_impl64_col; }; + template<> struct find_block_impl { using type = block_const_impl64_row; }; + template<> struct find_block_impl { using type = block_impl32_col; }; + template<> struct find_block_impl { using type = block_impl32_row; }; + template<> struct find_block_impl { using type = block_impl64_col; }; + template<> struct find_block_impl { using type = block_impl64_row; }; template - using find_block = typename find_block_impl::type; + using find_block = typename find_block_impl < typename std::remove_const_t::value_type + , Ref::storage_order + , std::is_const_v + >::type; } diff --git a/include/rotgen/impl/block_indirect.hpp b/include/rotgen/impl/block_indirect.hpp new file mode 100644 index 0000000..997ecad --- /dev/null +++ b/include/rotgen/impl/block_indirect.hpp @@ -0,0 +1,43 @@ + #define SIZE 64 + #define TYPE double + + #define CLASSNAME ROTGEN_MATRIX_NAME(BASENAME,SIZE,_col) + #define SOURCENAME ROTGEN_MATRIX_NAME(matrix_impl,SIZE,_col) + #define MAPNAME ROTGEN_MATRIX_NAME(map_impl,SIZE,_col) + #include + #undef CLASSNAME + #undef SOURCENAME + #undef MAPNAME + + #define CLASSNAME ROTGEN_MATRIX_NAME(BASENAME,SIZE,_row) + #define SOURCENAME ROTGEN_MATRIX_NAME(matrix_impl,SIZE,_row) + #define MAPNAME ROTGEN_MATRIX_NAME(map_impl,SIZE,_row) + #include + #undef CLASSNAME + #undef SOURCENAME + #undef MAPNAME + + #undef SIZE + #undef TYPE + + #define SIZE 32 + #define TYPE float + + #define CLASSNAME ROTGEN_MATRIX_NAME(BASENAME,SIZE,_col) + #define SOURCENAME ROTGEN_MATRIX_NAME(matrix_impl,SIZE,_col) + #define MAPNAME ROTGEN_MATRIX_NAME(map_impl,SIZE,_col) + #include + #undef CLASSNAME + #undef SOURCENAME + #undef MAPNAME + + #define CLASSNAME ROTGEN_MATRIX_NAME(BASENAME,SIZE,_row) + #define SOURCENAME ROTGEN_MATRIX_NAME(matrix_impl,SIZE,_row) + #define MAPNAME ROTGEN_MATRIX_NAME(map_impl,SIZE,_row) + #include + #undef CLASSNAME + #undef SOURCENAME + #undef MAPNAME + + #undef SIZE + #undef TYPE \ No newline at end of file diff --git a/include/rotgen/impl/block_model.hpp b/include/rotgen/impl/block_model.hpp index 0c8935d..a446ead 100644 --- a/include/rotgen/impl/block_model.hpp +++ b/include/rotgen/impl/block_model.hpp @@ -13,18 +13,28 @@ //================================================================================================== class ROTGEN_EXPORT CLASSNAME { + private: + struct payload; + std::unique_ptr storage_; + public: - CLASSNAME(SOURCENAME& r, std::size_t i0, std::size_t j0, std::size_t ni, std::size_t nj); + CLASSNAME(SOURCENAME CONST& r , Index i0, Index j0, Index ni, Index nj); + CLASSNAME(MAPNAME CONST& r, Index i0, Index j0, Index ni, Index nj); + CLASSNAME(payload const& r, Index i0, Index j0, Index ni, Index nj); CLASSNAME(CLASSNAME const& other); CLASSNAME(CLASSNAME&&) noexcept; + #if !defined(USE_CONST) CLASSNAME& operator=(CLASSNAME const& other); CLASSNAME& operator=(CLASSNAME&&) noexcept; + #endif ~CLASSNAME(); + #if !defined(USE_CONST) void assign(SOURCENAME const&); + #endif Index rows() const; Index cols() const; @@ -33,12 +43,17 @@ class ROTGEN_EXPORT CLASSNAME Index innerStride() const; Index outerStride() const; + Index startRow() const; + Index startCol() const; + SOURCENAME transpose() const; SOURCENAME conjugate() const; SOURCENAME adjoint() const; + #if !defined(USE_CONST) void transposeInPlace(); void adjointInPlace(); + #endif TYPE sum() const; TYPE prod() const; @@ -53,18 +68,19 @@ class ROTGEN_EXPORT CLASSNAME TYPE norm() const; TYPE lpNorm(int p) const; - TYPE& operator()(std::size_t i, std::size_t j); - TYPE const& operator()(std::size_t i, std::size_t j) const; - - TYPE& operator()(std::size_t index); - TYPE const& operator()(std::size_t index) const; - + #if !defined(USE_CONST) + TYPE& operator()(Index i, Index j); + TYPE& operator()(Index index); CLASSNAME& operator+=(CLASSNAME const& rhs); CLASSNAME& operator-=(CLASSNAME const& rhs); - SOURCENAME operator-() const; CLASSNAME& operator*=(CLASSNAME const& rhs); CLASSNAME& operator*=(TYPE d); CLASSNAME& operator/=(TYPE d); + #endif + + TYPE operator()(Index i, Index j) const; + TYPE operator()(Index index) const; + SOURCENAME operator-() const; SOURCENAME add(CLASSNAME const& rhs) const; SOURCENAME sub(CLASSNAME const& rhs) const; @@ -76,20 +92,21 @@ class ROTGEN_EXPORT CLASSNAME friend ROTGEN_EXPORT bool operator==(CLASSNAME const& lhs, CLASSNAME const& rhs); friend ROTGEN_EXPORT bool operator!=(CLASSNAME const& lhs, CLASSNAME const& rhs); - const TYPE* data() const; + #if !defined(USE_CONST) TYPE* data(); + #endif + const TYPE* data() const; - static SOURCENAME Zero(std::size_t r, std::size_t c) { return SOURCENAME::Zero(r,c); } - static SOURCENAME Ones(std::size_t r, std::size_t c) { return SOURCENAME::Ones(r,c); } - static SOURCENAME Constant(std::size_t r, std::size_t c, TYPE v) { return SOURCENAME::Constant(r,c,v); } - static SOURCENAME Random(std::size_t r, std::size_t c) { return SOURCENAME::Random(r,c); } - static SOURCENAME Identity(std::size_t r, std::size_t c) { return SOURCENAME::Identity(r,c); } - - private: - struct payload; - std::unique_ptr storage_; + static SOURCENAME Zero(Index r, Index c) { return SOURCENAME::Zero(r,c); } + static SOURCENAME Ones(Index r, Index c) { return SOURCENAME::Ones(r,c); } + static SOURCENAME Constant(Index r, Index c, TYPE v) { return SOURCENAME::Constant(r,c,v); } + static SOURCENAME Random(Index r, Index c) { return SOURCENAME::Random(r,c); } + static SOURCENAME Identity(Index r, Index c) { return SOURCENAME::Identity(r,c); } public: + #if !defined(USE_CONST) std::unique_ptr& storage() { return storage_; } + #endif + std::unique_ptr const& storage() const { return storage_; } }; \ No newline at end of file diff --git a/include/rotgen/impl/map.hpp b/include/rotgen/impl/map.hpp index 5c696bf..9f7aaf4 100644 --- a/include/rotgen/impl/map.hpp +++ b/include/rotgen/impl/map.hpp @@ -18,82 +18,19 @@ namespace rotgen { #define USE_CONST #define CONST const - #define SIZE 64 - #define TYPE double - - #define CLASSNAME ROTGEN_MATRIX_NAME(map_const_impl,SIZE,_col) - #define SOURCENAME ROTGEN_MATRIX_NAME(matrix_impl,SIZE,_col) - #include - #undef CLASSNAME - #undef SOURCENAME - - #define CLASSNAME ROTGEN_MATRIX_NAME(map_const_impl,SIZE,_row) - #define SOURCENAME ROTGEN_MATRIX_NAME(matrix_impl,SIZE,_row) - #include - #undef CLASSNAME - #undef SOURCENAME - - #undef SIZE - #undef TYPE - - #define SIZE 32 - #define TYPE float - - #define CLASSNAME ROTGEN_MATRIX_NAME(map_const_impl,SIZE,_col) - #define SOURCENAME ROTGEN_MATRIX_NAME(matrix_impl,SIZE,_col) - #include - #undef CLASSNAME - #undef SOURCENAME - - #define CLASSNAME ROTGEN_MATRIX_NAME(map_const_impl,SIZE,_row) - #define SOURCENAME ROTGEN_MATRIX_NAME(matrix_impl,SIZE,_row) - #include - #undef CLASSNAME - #undef SOURCENAME - - #undef SIZE - #undef TYPE + #define BASENAME map_const_impl + #include + #undef BASENAME #undef CONST #undef USE_CONST - #define SIZE 64 - #define TYPE double #define CONST - - #define CLASSNAME ROTGEN_MATRIX_NAME(map_impl,SIZE,_col) - #define SOURCENAME ROTGEN_MATRIX_NAME(matrix_impl,SIZE,_col) - #include - #undef CLASSNAME - #undef SOURCENAME - - #define CLASSNAME ROTGEN_MATRIX_NAME(map_impl,SIZE,_row) - #define SOURCENAME ROTGEN_MATRIX_NAME(matrix_impl,SIZE,_row) - #include - #undef CLASSNAME - #undef SOURCENAME - - #undef SIZE - #undef TYPE - - #define SIZE 32 - #define TYPE float - - #define CLASSNAME ROTGEN_MATRIX_NAME(map_impl,SIZE,_col) - #define SOURCENAME ROTGEN_MATRIX_NAME(matrix_impl,SIZE,_col) - #include - #undef CLASSNAME - #undef SOURCENAME - - #define CLASSNAME ROTGEN_MATRIX_NAME(map_impl,SIZE,_row) - #define SOURCENAME ROTGEN_MATRIX_NAME(matrix_impl,SIZE,_row) - #include - #undef CLASSNAME - #undef SOURCENAME - - #undef SIZE - #undef TYPE + #define BASENAME map_impl + #include + #undef BASENAME #undef CONST + template struct find_map_impl; template<> struct find_map_impl { using type = map_const_impl32_col; }; diff --git a/include/rotgen/impl/map_indirect.hpp b/include/rotgen/impl/map_indirect.hpp new file mode 100644 index 0000000..a11c1fe --- /dev/null +++ b/include/rotgen/impl/map_indirect.hpp @@ -0,0 +1,35 @@ + #define SIZE 64 + #define TYPE double + + #define CLASSNAME ROTGEN_MATRIX_NAME(BASENAME,SIZE,_col) + #define SOURCENAME ROTGEN_MATRIX_NAME(matrix_impl,SIZE,_col) + #include + #undef CLASSNAME + #undef SOURCENAME + + #define CLASSNAME ROTGEN_MATRIX_NAME(BASENAME,SIZE,_row) + #define SOURCENAME ROTGEN_MATRIX_NAME(matrix_impl,SIZE,_row) + #include + #undef CLASSNAME + #undef SOURCENAME + + #undef SIZE + #undef TYPE + + #define SIZE 32 + #define TYPE float + + #define CLASSNAME ROTGEN_MATRIX_NAME(BASENAME,SIZE,_col) + #define SOURCENAME ROTGEN_MATRIX_NAME(matrix_impl,SIZE,_col) + #include + #undef CLASSNAME + #undef SOURCENAME + + #define CLASSNAME ROTGEN_MATRIX_NAME(BASENAME,SIZE,_row) + #define SOURCENAME ROTGEN_MATRIX_NAME(matrix_impl,SIZE,_row) + #include + #undef CLASSNAME + #undef SOURCENAME + + #undef SIZE + #undef TYPE diff --git a/src/block.cpp b/src/block.cpp index df11c60..cc183bf 100644 --- a/src/block.cpp +++ b/src/block.cpp @@ -9,50 +9,21 @@ #include #include #include +#include namespace rotgen { - #define SIZE 64 - #define TYPE double - #define STORAGE_ORDER Eigen::ColMajor + #define USE_CONST + #define CONST const + #define BASENAME block_const_impl + #include "block_indirect.cpp" + #undef BASENAME + #undef USE_CONST + #undef CONST - #define CLASSNAME ROTGEN_MATRIX_NAME(block_impl,SIZE,_col) - #define SOURCENAME ROTGEN_MATRIX_NAME(matrix_impl,SIZE,_col) - #include "block_model.cpp" - #undef CLASSNAME - #undef SOURCENAME - #undef STORAGE_ORDER - - #define STORAGE_ORDER Eigen::RowMajor - #define CLASSNAME ROTGEN_MATRIX_NAME(block_impl,SIZE,_row) - #define SOURCENAME ROTGEN_MATRIX_NAME(matrix_impl,SIZE,_row) - #include "block_model.cpp" - #undef CLASSNAME - #undef SOURCENAME - #undef STORAGE_ORDER - - #undef SIZE - #undef TYPE - - #define SIZE 32 - #define TYPE float - #define STORAGE_ORDER Eigen::ColMajor - - #define CLASSNAME ROTGEN_MATRIX_NAME(block_impl,SIZE,_col) - #define SOURCENAME ROTGEN_MATRIX_NAME(matrix_impl,SIZE,_col) - #include "block_model.cpp" - #undef CLASSNAME - #undef SOURCENAME - #undef STORAGE_ORDER - - #define STORAGE_ORDER Eigen::RowMajor - #define CLASSNAME ROTGEN_MATRIX_NAME(block_impl,SIZE,_row) - #define SOURCENAME ROTGEN_MATRIX_NAME(matrix_impl,SIZE,_row) - #include "block_model.cpp" - #undef CLASSNAME - #undef SOURCENAME - #undef STORAGE_ORDER - - #undef SIZE - #undef TYPE + #define CONST + #define BASENAME block_impl + #include "block_indirect.cpp" + #undef BASENAME + #undef CONST } diff --git a/src/block_indirect.cpp b/src/block_indirect.cpp new file mode 100644 index 0000000..43fab3e --- /dev/null +++ b/src/block_indirect.cpp @@ -0,0 +1,51 @@ + #define SIZE 64 + #define TYPE double + #define STORAGE_ORDER Eigen::ColMajor + + #define CLASSNAME ROTGEN_MATRIX_NAME(BASENAME,SIZE,_col) + #define SOURCENAME ROTGEN_MATRIX_NAME(matrix_impl,SIZE,_col) + #define MAPNAME ROTGEN_MATRIX_NAME(map_impl,SIZE,_col) + #include "block_model.cpp" + #undef CLASSNAME + #undef SOURCENAME + #undef MAPNAME + #undef STORAGE_ORDER + + #define STORAGE_ORDER Eigen::RowMajor + #define CLASSNAME ROTGEN_MATRIX_NAME(BASENAME,SIZE,_row) + #define SOURCENAME ROTGEN_MATRIX_NAME(matrix_impl,SIZE,_row) + #define MAPNAME ROTGEN_MATRIX_NAME(map_impl,SIZE,_row) + #include "block_model.cpp" + #undef CLASSNAME + #undef SOURCENAME + #undef MAPNAME + #undef STORAGE_ORDER + + #undef SIZE + #undef TYPE + + #define SIZE 32 + #define TYPE float + #define STORAGE_ORDER Eigen::ColMajor + + #define CLASSNAME ROTGEN_MATRIX_NAME(BASENAME,SIZE,_col) + #define SOURCENAME ROTGEN_MATRIX_NAME(matrix_impl,SIZE,_col) + #define MAPNAME ROTGEN_MATRIX_NAME(map_impl,SIZE,_col) + #include "block_model.cpp" + #undef CLASSNAME + #undef SOURCENAME + #undef MAPNAME + #undef STORAGE_ORDER + + #define STORAGE_ORDER Eigen::RowMajor + #define CLASSNAME ROTGEN_MATRIX_NAME(BASENAME,SIZE,_row) + #define SOURCENAME ROTGEN_MATRIX_NAME(matrix_impl,SIZE,_row) + #define MAPNAME ROTGEN_MATRIX_NAME(map_impl,SIZE,_row) + #include "block_model.cpp" + #undef CLASSNAME + #undef SOURCENAME + #undef MAPNAME + #undef STORAGE_ORDER + + #undef SIZE + #undef TYPE \ No newline at end of file diff --git a/src/block_model.cpp b/src/block_model.cpp index ea47ebc..df4c0af 100644 --- a/src/block_model.cpp +++ b/src/block_model.cpp @@ -11,204 +11,476 @@ This file is a X-File to generate various block_impl_* definitions variant */ //================================================================================================== +#define STR(text) STR_I(text) +#define STR_I(...) #__VA_ARGS__ //================================================================================================== // Internal payload //================================================================================================== struct CLASSNAME::payload { - using base_type = Eigen::Matrix; - using data_type = Eigen::Block; + using stride_type = Eigen::Stride; + using matrix_type = Eigen::Matrix; + using matrix_block_type = Eigen::Block; + using matrix_storage_t = std::pair; + using map_type = Eigen::Map; + using map_block_type = Eigen::Block; + using map_storage_t = std::pair; + using data_type = std::variant; - data_type data; + data_type data; + rotgen::Index abs_i0 = 0; // absolute start row in original matrix + rotgen::Index abs_j0 = 0; // absolute start col in original matrix + rotgen::Index rel_i0 = 0; // relative start row in original matrix + rotgen::Index rel_j0 = 0; // relative start col in original matrix + + template + void apply(Func f) { std::visit([&](auto& blk) { return f(blk.first); }, data); } + + template + void apply(Func f) const { std::visit([&](auto const& blk) { return f(blk.first); }, data); } payload (data_type const& o) : data(o) {} - payload (base_type& r, std::size_t i0, std::size_t j0, std::size_t ni, std::size_t nj) - : data(r,i0,j0,ni,nj) + payload (SOURCENAME CONST& o, rotgen::Index i0, rotgen::Index j0, rotgen::Index ni, rotgen::Index nj) + : data(matrix_storage_t{matrix_block_type{o.storage()->data,i0,j0,ni,nj},&o.storage()->data}) + , abs_i0(i0), abs_j0(j0), rel_i0(i0), rel_j0(j0) + {} + + payload (MAPNAME CONST& o, rotgen::Index i0, rotgen::Index j0, rotgen::Index ni, rotgen::Index nj) + : data(map_storage_t{map_block_type{o.storage()->data,i0,j0,ni,nj},&o.storage()->data}) + , abs_i0(i0), abs_j0(j0), rel_i0(i0), rel_j0(j0) {} }; //================================================================================================== // Constructors & Special Members //================================================================================================== - CLASSNAME::CLASSNAME(SOURCENAME& r, std::size_t i0, std::size_t j0, std::size_t ni, std::size_t nj) - : storage_(std::make_unique(r.storage()->data,i0,j0,ni,nj)) + CLASSNAME::CLASSNAME(SOURCENAME CONST& r, Index i0, Index j0, Index ni, Index nj) + : storage_(std::make_unique(r, i0,j0,ni,nj)) {} - CLASSNAME::CLASSNAME(CLASSNAME const& o) : storage_(std::make_unique(o.storage_->data)) + CLASSNAME::CLASSNAME(MAPNAME CONST& r, Index i0, Index j0, Index ni, Index nj) + : storage_(std::make_unique(r, i0,j0,ni,nj)) {} + // We're building a block from a block - So we have to dig around the internals + CLASSNAME::CLASSNAME(payload const& o, Index i0, Index j0, Index ni, Index nj) + { + // Compute absolute indices from the parent stored block + Index abs_i0 = 0; + Index abs_j0 = 0; + std::visit( [&](auto const& blk) + { + abs_i0 = blk.first.startRow() + i0; + abs_j0 = blk.first.startCol() + j0; + } + , o.data + ); + + // Build a payload::data_type that holds the child block using absolute indices + payload::data_type new_data = + std::visit([&](T const& blk) -> payload::data_type + { + auto& [parent_block, ref] = blk; + using block_type = typename T::first_type; + return T{ block_type{ *ref, abs_i0, abs_j0, ni, nj }, ref }; + }, o.data); + + storage_ = std::make_unique(new_data); + storage_->abs_i0 = abs_i0; + storage_->abs_j0 = abs_j0; + storage_->rel_i0 = i0; + storage_->rel_j0 = j0; + } + + CLASSNAME::CLASSNAME(CLASSNAME const& o) + : storage_(std::make_unique(o.storage_->data)) + {} + + CLASSNAME::CLASSNAME(CLASSNAME&&) noexcept = default; + + #if !defined(USE_CONST) CLASSNAME& CLASSNAME::operator=(CLASSNAME const& o) { - if (this != &o) storage_->data = o.storage_->data; + if (this != &o) { storage_->data = o.storage_->data; } return *this; } - CLASSNAME::CLASSNAME(CLASSNAME&&) noexcept = default; CLASSNAME& CLASSNAME::operator=(CLASSNAME&&) noexcept = default; + #endif + CLASSNAME::~CLASSNAME() = default; + #if !defined(USE_CONST) void CLASSNAME::assign(SOURCENAME const& m) { - storage_->data = m.storage()->data; + storage_->apply([&](auto& blk) + { + blk = m.storage()->data; + }); } + #endif //================================================================================================== // Matrix API //================================================================================================== - rotgen::Index CLASSNAME::rows() const { return storage_->data.rows(); } - rotgen::Index CLASSNAME::cols() const { return storage_->data.cols(); } - rotgen::Index CLASSNAME::size() const { return storage_->data.size(); } - rotgen::Index CLASSNAME::innerStride() const { return storage_->data.innerStride(); } - rotgen::Index CLASSNAME::outerStride() const { return storage_->data.outerStride(); } + rotgen::Index CLASSNAME::rows() const + { + rotgen::Index that; + storage_->apply([&](const auto& blk) { that = blk.rows(); }); + return that; + } - TYPE& CLASSNAME::operator()(std::size_t i, std::size_t j) { return storage_->data(i,j); } - TYPE const& CLASSNAME::operator()(std::size_t i, std::size_t j) const { return storage_->data(i,j); } + rotgen::Index CLASSNAME::cols() const + { + rotgen::Index that; + storage_->apply([&](const auto& blk) { that = blk.cols(); }); + return that; + } - TYPE& CLASSNAME::operator()(std::size_t index) { return storage_->data.data()[index]; } - TYPE const& CLASSNAME::operator()(std::size_t index) const { return storage_->data.data()[index]; } + rotgen::Index CLASSNAME::size() const + { + rotgen::Index that; + storage_->apply([&](const auto& blk) { that = blk.size(); }); + return that; + } - TYPE* CLASSNAME::data() { return storage_->data.data(); } - const TYPE* CLASSNAME::data() const { return storage_->data.data(); } + rotgen::Index CLASSNAME::innerStride() const + { + rotgen::Index that; + storage_->apply([&](const auto& blk) { that = blk.innerStride(); }); + return that; + } + rotgen::Index CLASSNAME::outerStride() const + { + rotgen::Index that; + storage_->apply([&](const auto& blk) { that = blk.outerStride(); }); + return that; + } + + rotgen::Index CLASSNAME::startRow() const + { + return storage_->rel_i0; + } + + rotgen::Index CLASSNAME::startCol() const + { + return storage_->rel_j0; + } + + // Element access by (i,j) + #if !defined(USE_CONST) + TYPE& CLASSNAME::operator()(Index i, Index j) + { + TYPE* ptr = nullptr; + storage_->apply([&](auto& blk) { ptr = &blk(i,j); }); + return *ptr; + } + #endif + + TYPE CLASSNAME::operator()(Index i, Index j) const + { + TYPE ptr; + storage_->apply([&](auto const& blk) { ptr = blk(i,j); }); + return ptr; + } + + // Element access by linear index + #if !defined(USE_CONST) + TYPE& CLASSNAME::operator()(Index index) + { + TYPE* ptr = nullptr; + storage_->apply([&](auto& blk) { ptr = blk.data() + index; }); + return *ptr; + } + #endif + + TYPE CLASSNAME::operator()(Index index) const + { + TYPE ptr; + storage_->apply([&](auto const& blk) { ptr = *(blk.data() + index); }); + return ptr; + } + + // Raw pointer access + #if !defined(USE_CONST) + TYPE* CLASSNAME::data() + { + TYPE* ptr = nullptr; + storage_->apply([&](auto& blk) { ptr = blk.data(); }); + return ptr; + } + #endif + + TYPE const* CLASSNAME::data() const + { + TYPE const* ptr = nullptr; + storage_->apply([&](auto const& blk) { ptr = blk.data(); }); + return ptr; + } + + //================================================================================================== + // Matrix operations + //================================================================================================== SOURCENAME CLASSNAME::transpose() const { SOURCENAME result; - result.storage()->assign(storage_->data.transpose().eval()); + storage_->apply([&](const auto& blk) { result.storage()->assign(blk.transpose().eval()); }); return result; } - SOURCENAME CLASSNAME::conjugate() const { + SOURCENAME CLASSNAME::conjugate() const + { SOURCENAME result; - result.storage()->assign(storage_->data.conjugate().eval()); + storage_->apply([&](const auto& blk) { result.storage()->assign(blk.conjugate().eval()); }); return result; } - SOURCENAME CLASSNAME::adjoint() const { + SOURCENAME CLASSNAME::adjoint() const + { SOURCENAME result; - result.storage()->assign(storage_->data.adjoint().eval()); + storage_->apply([&](const auto& blk) { result.storage()->assign(blk.adjoint().eval()); }); return result; } + #if !defined(USE_CONST) void CLASSNAME::transposeInPlace() { - storage_->data.transposeInPlace(); + storage_->apply([](auto& blk) { blk.transposeInPlace(); }); } void CLASSNAME::adjointInPlace() { - storage_->data.adjointInPlace(); + storage_->apply([](auto& blk) { blk.adjointInPlace(); }); + } + #endif + + //================================================================================================== + // Reductions + //================================================================================================== + TYPE CLASSNAME::sum() const + { + TYPE val{}; + storage_->apply([&](const auto& blk) { val = blk.sum(); }); + return val; } - TYPE CLASSNAME::sum() const { return storage_->data.sum(); } - TYPE CLASSNAME::prod() const { return storage_->data.prod(); } - TYPE CLASSNAME::mean() const { return storage_->data.mean(); } - TYPE CLASSNAME::trace() const { return storage_->data.trace(); } + TYPE CLASSNAME::prod() const + { + TYPE val{}; + storage_->apply([&](const auto& blk) { val = blk.prod(); }); + return val; + } - TYPE CLASSNAME::minCoeff() const { return storage_->data.minCoeff(); } - TYPE CLASSNAME::maxCoeff() const { return storage_->data.maxCoeff(); } + TYPE CLASSNAME::mean() const + { + TYPE val{}; + storage_->apply([&](const auto& blk) { val = blk.mean(); }); + return val; + } - TYPE CLASSNAME::minCoeff(std::ptrdiff_t* row, std::ptrdiff_t* col) const { return storage_->data.minCoeff(row, col); } - TYPE CLASSNAME::maxCoeff(std::ptrdiff_t* row, std::ptrdiff_t* col) const { return storage_->data.maxCoeff(row, col); } + TYPE CLASSNAME::trace() const + { + TYPE val{}; + storage_->apply([&](const auto& blk) { val = blk.trace(); }); + return val; + } - TYPE CLASSNAME::squaredNorm() const { return storage_->data.squaredNorm(); } - TYPE CLASSNAME::norm() const { return storage_->data.norm(); } + TYPE CLASSNAME::minCoeff() const + { + TYPE val{}; + storage_->apply([&](const auto& blk) { val = blk.minCoeff(); }); + return val; + } + + TYPE CLASSNAME::maxCoeff() const + { + TYPE val{}; + storage_->apply([&](const auto& blk) { val = blk.maxCoeff(); }); + return val; + } + + TYPE CLASSNAME::minCoeff(std::ptrdiff_t* row, std::ptrdiff_t* col) const + { + TYPE val{}; + storage_->apply([&](const auto& blk) { val = blk.minCoeff(row, col); }); + return val; + } + + TYPE CLASSNAME::maxCoeff(std::ptrdiff_t* row, std::ptrdiff_t* col) const + { + TYPE val{}; + storage_->apply([&](const auto& blk) { val = blk.maxCoeff(row, col); }); + return val; + } + + TYPE CLASSNAME::squaredNorm() const + { + TYPE val{}; + storage_->apply([&](const auto& blk) { val = blk.squaredNorm(); }); + return val; + } + + TYPE CLASSNAME::norm() const + { + TYPE val{}; + storage_->apply([&](const auto& blk) { val = blk.norm(); }); + return val; + } TYPE CLASSNAME::lpNorm(int p) const { - if (p == 1) return storage_->data.lpNorm<1>(); - else if (p == 2) return storage_->data.lpNorm<2>(); - else return storage_->data.lpNorm(); + TYPE val{}; + storage_->apply([&](const auto& blk) + { + if (p == 1) val = blk.template lpNorm<1>(); + else if (p == 2) val = blk.template lpNorm<2>(); + else val = blk.template lpNorm(); + }); + return val; } //================================================================================================== // Operators //================================================================================================== - ROTGEN_EXPORT std::ostream& operator<<(std::ostream& os,CLASSNAME const& m) + ROTGEN_EXPORT std::ostream& operator<<(std::ostream& os, CLASSNAME const& m) { - return os << m.storage_->data; + m.storage_->apply([&](const auto& blk) { os << blk; }); + return os; } ROTGEN_EXPORT bool operator==(CLASSNAME const& lhs, CLASSNAME const& rhs) { - return lhs.storage_->data == rhs.storage_->data; + return std::visit ( [](auto const& lhs_blk, auto const& rhs_blk) { return lhs_blk.first == rhs_blk.first; } + , lhs.storage_->data + , rhs.storage_->data + ); } ROTGEN_EXPORT bool operator!=(CLASSNAME const& lhs, CLASSNAME const& rhs) { - return lhs.storage_->data != rhs.storage_->data; + return std::visit ( [](auto const& lhs_blk, auto const& rhs_blk) { return lhs_blk.first != rhs_blk.first; } + , lhs.storage_->data + , rhs.storage_->data + ); } + + SOURCENAME CLASSNAME::operator-() const + { + SOURCENAME result; + storage_->apply([&](const auto& blk) { result.storage()->assign(blk); }); + return -result; + } + + #if !defined(USE_CONST) CLASSNAME& CLASSNAME::operator+=(CLASSNAME const& rhs) { - storage_->data += rhs.storage_->data; + std::visit( [](auto& lhs_blk, auto const& rhs_blk) { lhs_blk.first += rhs_blk.first; } + , storage_->data + , rhs.storage_->data + ); return *this; } CLASSNAME& CLASSNAME::operator-=(CLASSNAME const& rhs) { - storage_->data -= rhs.storage_->data; + std::visit( [](auto& lhs_blk, auto const& rhs_blk) { lhs_blk.first -= rhs_blk.first; } + , storage_->data + , rhs.storage_->data + ); return *this; } - SOURCENAME CLASSNAME::operator-() const - { - SOURCENAME result; - result.storage()->assign(storage_->data); - return -result; - } - CLASSNAME& CLASSNAME::operator*=(CLASSNAME const& rhs) { - storage_->data *= rhs.storage_->data; + std::visit( [](auto& lhs_blk, auto const& rhs_blk) { lhs_blk.first *= rhs_blk.first; } + , storage_->data + , rhs.storage_->data + ); return *this; } CLASSNAME& CLASSNAME::operator*=(TYPE s) { - storage_->data *= s; + storage_->apply([&](auto& blk) { blk *= s; }); return *this; } CLASSNAME& CLASSNAME::operator/=(TYPE s) { - storage_->data /= s; + storage_->apply([&](auto& blk) { blk /= s; }); return *this; } + #endif SOURCENAME CLASSNAME::add(CLASSNAME const& rhs) const { SOURCENAME result; - result.storage()->assign(storage_->data + rhs.storage_->data); + result.storage()->assign( std::visit( [](auto const& lhs_blk, auto const& rhs_blk) + { + return (lhs_blk.first + rhs_blk.first).eval(); + } + , storage_->data + , rhs.storage_->data + ) + ); return result; } SOURCENAME CLASSNAME::sub(CLASSNAME const& rhs) const { SOURCENAME result; - result.storage()->assign(storage_->data - rhs.storage_->data); + result.storage()->assign( std::visit( [](auto const& lhs_blk, auto const& rhs_blk) + { + return (lhs_blk.first - rhs_blk.first).eval(); + } + , storage_->data + , rhs.storage_->data + ) + ); return result; } SOURCENAME CLASSNAME::mul(CLASSNAME const& rhs) const { SOURCENAME result; - result.storage()->assign(storage_->data * rhs.storage_->data); + result.storage()->assign( std::visit( [](auto const& lhs_blk, auto const& rhs_blk) + { + return (lhs_blk.first * rhs_blk.first).eval(); + } + , storage_->data + , rhs.storage_->data + ) + ); return result; } SOURCENAME CLASSNAME::mul(TYPE s) const { SOURCENAME result; - result.storage()->assign(storage_->data * s); + result.storage()->assign( std::visit( [s](auto const& lhs_blk) + { + return (lhs_blk.first * s).eval(); + } + , storage_->data + ) + ); return result; } SOURCENAME CLASSNAME::div(TYPE s) const { SOURCENAME result; - result.storage()->assign(storage_->data / s); + result.storage()->assign( std::visit( [s](auto const& lhs_blk) + { + return (lhs_blk.first / s).eval(); + } + , storage_->data + ) + ); return result; - } \ No newline at end of file + } diff --git a/src/map.cpp b/src/map.cpp index 2871ebc..f129684 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -14,97 +14,15 @@ namespace rotgen { #define USE_CONST #define CONST const - - #define SIZE 64 - #define TYPE double - #define STORAGE_ORDER Eigen::ColMajor - - #define CLASSNAME ROTGEN_MATRIX_NAME(map_const_impl,SIZE,_col) - #define SOURCENAME ROTGEN_MATRIX_NAME(matrix_impl,SIZE,_col) - #include "map_model.cpp" - #undef CLASSNAME - #undef SOURCENAME - #undef STORAGE_ORDER - - #define STORAGE_ORDER Eigen::RowMajor - #define CLASSNAME ROTGEN_MATRIX_NAME(map_const_impl,SIZE,_row) - #define SOURCENAME ROTGEN_MATRIX_NAME(matrix_impl,SIZE,_row) - #include "map_model.cpp" - #undef CLASSNAME - #undef SOURCENAME - #undef STORAGE_ORDER - - #undef SIZE - #undef TYPE - - #define SIZE 32 - #define TYPE float - #define STORAGE_ORDER Eigen::ColMajor - - #define CLASSNAME ROTGEN_MATRIX_NAME(map_const_impl,SIZE,_col) - #define SOURCENAME ROTGEN_MATRIX_NAME(matrix_impl,SIZE,_col) - #include "map_model.cpp" - #undef CLASSNAME - #undef SOURCENAME - #undef STORAGE_ORDER - - #define STORAGE_ORDER Eigen::RowMajor - #define CLASSNAME ROTGEN_MATRIX_NAME(map_const_impl,SIZE,_row) - #define SOURCENAME ROTGEN_MATRIX_NAME(matrix_impl,SIZE,_row) - #include "map_model.cpp" - #undef CLASSNAME - #undef SOURCENAME - #undef STORAGE_ORDER - - #undef SIZE - #undef TYPE - + #define BASENAME map_const_impl + #include "map_indirect.cpp" + #undef BASENAME #undef USE_CONST #undef CONST + #define CONST - - #define SIZE 64 - #define TYPE double - #define STORAGE_ORDER Eigen::ColMajor - - #define CLASSNAME ROTGEN_MATRIX_NAME(map_impl,SIZE,_col) - #define SOURCENAME ROTGEN_MATRIX_NAME(matrix_impl,SIZE,_col) - #include "map_model.cpp" - #undef CLASSNAME - #undef SOURCENAME - #undef STORAGE_ORDER - - #define STORAGE_ORDER Eigen::RowMajor - #define CLASSNAME ROTGEN_MATRIX_NAME(map_impl,SIZE,_row) - #define SOURCENAME ROTGEN_MATRIX_NAME(matrix_impl,SIZE,_row) - #include "map_model.cpp" - #undef CLASSNAME - #undef SOURCENAME - #undef STORAGE_ORDER - - #undef SIZE - #undef TYPE - - #define SIZE 32 - #define TYPE float - #define STORAGE_ORDER Eigen::ColMajor - - #define CLASSNAME ROTGEN_MATRIX_NAME(map_impl,SIZE,_col) - #define SOURCENAME ROTGEN_MATRIX_NAME(matrix_impl,SIZE,_col) - #include "map_model.cpp" - #undef CLASSNAME - #undef SOURCENAME - #undef STORAGE_ORDER - - #define STORAGE_ORDER Eigen::RowMajor - #define CLASSNAME ROTGEN_MATRIX_NAME(map_impl,SIZE,_row) - #define SOURCENAME ROTGEN_MATRIX_NAME(matrix_impl,SIZE,_row) - #include "map_model.cpp" - #undef CLASSNAME - #undef SOURCENAME - #undef STORAGE_ORDER - - #undef SIZE - #undef TYPE + #define BASENAME map_impl + #include "map_indirect.cpp" + #undef BASENAME #undef CONST } diff --git a/src/map_indirect.cpp b/src/map_indirect.cpp new file mode 100644 index 0000000..d271163 --- /dev/null +++ b/src/map_indirect.cpp @@ -0,0 +1,43 @@ + #define SIZE 64 + #define TYPE double + #define STORAGE_ORDER Eigen::ColMajor + + #define CLASSNAME ROTGEN_MATRIX_NAME(BASENAME,SIZE,_col) + #define SOURCENAME ROTGEN_MATRIX_NAME(matrix_impl,SIZE,_col) + #include "map_model.cpp" + #undef CLASSNAME + #undef SOURCENAME + #undef STORAGE_ORDER + + #define STORAGE_ORDER Eigen::RowMajor + #define CLASSNAME ROTGEN_MATRIX_NAME(BASENAME,SIZE,_row) + #define SOURCENAME ROTGEN_MATRIX_NAME(matrix_impl,SIZE,_row) + #include "map_model.cpp" + #undef CLASSNAME + #undef SOURCENAME + #undef STORAGE_ORDER + + #undef SIZE + #undef TYPE + + #define SIZE 32 + #define TYPE float + #define STORAGE_ORDER Eigen::ColMajor + + #define CLASSNAME ROTGEN_MATRIX_NAME(BASENAME,SIZE,_col) + #define SOURCENAME ROTGEN_MATRIX_NAME(matrix_impl,SIZE,_col) + #include "map_model.cpp" + #undef CLASSNAME + #undef SOURCENAME + #undef STORAGE_ORDER + + #define STORAGE_ORDER Eigen::RowMajor + #define CLASSNAME ROTGEN_MATRIX_NAME(BASENAME,SIZE,_row) + #define SOURCENAME ROTGEN_MATRIX_NAME(matrix_impl,SIZE,_row) + #include "map_model.cpp" + #undef CLASSNAME + #undef SOURCENAME + #undef STORAGE_ORDER + + #undef SIZE + #undef TYPE diff --git a/src/map_model.cpp b/src/map_model.cpp index 2f4d834..9c03508 100644 --- a/src/map_model.cpp +++ b/src/map_model.cpp @@ -48,7 +48,6 @@ rotgen::Index CLASSNAME::rows() const { return storage_->data.rows(); } rotgen::Index CLASSNAME::cols() const { return storage_->data.cols(); } rotgen::Index CLASSNAME::size() const { return storage_->data.size(); } - rotgen::Index CLASSNAME::innerStride() const { return storage_->data.innerStride(); } rotgen::Index CLASSNAME::outerStride() const { return storage_->data.outerStride(); } diff --git a/src/matrix_model.cpp b/src/matrix_model.cpp index fa8fb9e..0e48c94 100644 --- a/src/matrix_model.cpp +++ b/src/matrix_model.cpp @@ -51,9 +51,9 @@ CLASSNAME::~CLASSNAME() = default; //================================================================================================== // Matrix API //================================================================================================== -rotgen::Index CLASSNAME::rows() const { return storage_->data.rows(); } -rotgen::Index CLASSNAME::cols() const { return storage_->data.cols(); } -rotgen::Index CLASSNAME::size() const { return storage_->data.size(); } +rotgen::Index CLASSNAME::rows() const { return storage_->data.rows(); } +rotgen::Index CLASSNAME::cols() const { return storage_->data.cols(); } +rotgen::Index CLASSNAME::size() const { return storage_->data.size(); } void CLASSNAME::resize(std::size_t new_rows, std::size_t new_cols) { diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index ffbb907..8a095aa 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -21,3 +21,8 @@ rotgen_glob_unit(QUIET PATTERN "unit/*.cpp" INTERFACE rotgen_test) rotgen_glob_unit(QUIET PATTERN "unit/matrix/*.cpp" INTERFACE rotgen_test) rotgen_glob_unit(QUIET PATTERN "unit/block/*.cpp" INTERFACE rotgen_test) rotgen_glob_unit(QUIET PATTERN "unit/map/*.cpp" INTERFACE rotgen_test) + +##====================================================================================================================== +## Integrations Tests registration +##====================================================================================================================== +rotgen_glob_unit(QUIET PATTERN "integration/*.cpp" INTERFACE rotgen_test) diff --git a/test/integration/extract.cpp b/test/integration/extract.cpp new file mode 100644 index 0000000..93da720 --- /dev/null +++ b/test/integration/extract.cpp @@ -0,0 +1,51 @@ +//================================================================================================== +/* + ROTGEN - Runtime Overlay for Eigen + Copyright : CODE RECKONS + SPDX-License-Identifier: BSL-1.0 +*/ +//================================================================================================== +#include "unit/tests.hpp" +#include + +TTS_CASE_TPL("Chains of extraction", rotgen::tests::types) +( tts::type< tts::types> ) +{ + constexpr int N = 8; + auto a = rotgen::matrix::Random(); + + auto b = topLeftCorner(a,5,5); + TTS_EQUAL(b.startRow(), 0); + TTS_EQUAL(b.startCol(), 0); + b.setConstant(-7); + + for(rotgen::Index r=0;r<5;r++) + for(rotgen::Index c=0;c<5;c++) + TTS_EQUAL(a(r,c), -7); + + auto bb = bottomRightCorner(b,3,3); + TTS_EQUAL(bb.startRow(), 2); + TTS_EQUAL(bb.startCol(), 2); + bb.setConstant(42); + + for(rotgen::Index r=2;r<5;r++) + for(rotgen::Index c=2;c<5;c++) + TTS_EQUAL(a(r,c), 42); + + auto bbb = row(bb,1); + TTS_EQUAL(bbb.startRow(), 1); + TTS_EQUAL(bbb.startCol(), 0); + bbb.setConstant(99.5); + + for(rotgen::Index c=3;c<5;c++) + TTS_EQUAL(a(3,c), 99.5); + + auto bbbb = col(bbb,1); + TTS_EQUAL(bbbb.startRow(), 0); + TTS_EQUAL(bbbb.startCol(), 1); + bbbb.setConstant(0.125); + + TTS_EQUAL(a(3,3), 0.125); + + std::cout << "a: \n" << a << std::endl; +}; \ No newline at end of file diff --git a/test/unit/block/basic_api.cpp b/test/unit/block/basic_api.cpp index 5ab9774..05320a2 100644 --- a/test/unit/block/basic_api.cpp +++ b/test/unit/block/basic_api.cpp @@ -21,19 +21,19 @@ TTS_CASE_TPL("Function size", rotgen::tests::types) // 1x12 dynamic block at (0,0) rotgen::matrix dm(1,12); fill(dm,1,12); - auto b1 = rotgen::block(dm, 0,0,1,12); + auto b1 = rotgen::block(dm, 0,0,1,12); TTS_EQUAL(b1.rows(), rotgen::Index{1}); TTS_EQUAL(b1.cols(), rotgen::Index{12}); // 1x5 dynamic block at (0,2) - auto b2 = rotgen::block(dm, 0,2,1,5); + auto b2 = rotgen::block(dm, 0,2,1,5); TTS_EQUAL(b2.rows(), rotgen::Index{1}); TTS_EQUAL(b2.cols(), rotgen::Index{5}); // 3x2 dynamic block at (1,4) in 4x6 rotgen::matrix dm2(4,6); fill(dm2,4,6); - auto b3 = rotgen::block(dm2, 1,4,3,2); + auto b3 = rotgen::block(dm2, 1,4,3,2); TTS_EQUAL(b3.rows(), rotgen::Index{3}); TTS_EQUAL(b3.cols(), rotgen::Index{2}); TTS_EQUAL(b3.size(), rotgen::Index{6}); @@ -41,7 +41,7 @@ TTS_CASE_TPL("Function size", rotgen::tests::types) // 3x4 static block rotgen::matrix sm; fill(sm,3,4); - auto b4 = rotgen::block(sm, 0,0); + auto b4 = rotgen::block(sm, 0,0); TTS_EQUAL(b4.rows(), rotgen::Index{3}); TTS_EQUAL(b4.cols(), rotgen::Index{4}); TTS_EQUAL(b4.size(), rotgen::Index{12}); @@ -49,7 +49,7 @@ TTS_CASE_TPL("Function size", rotgen::tests::types) // 6x2 static block rotgen::matrix sm2; fill(sm2,6,2); - auto b5 = rotgen::block(sm2, 0,0); + auto b5 = rotgen::block(sm2, 0,0); TTS_EQUAL(b5.rows(), rotgen::Index{6}); TTS_EQUAL(b5.cols(), rotgen::Index{2}); TTS_EQUAL(b5.size(), rotgen::Index{12}); @@ -64,7 +64,7 @@ TTS_CASE_TPL("Test coefficient accessors", rotgen::tests::types) base mat(4,3); for(int k=0;k<12;++k) mat.data()[k] = data[k]; - auto b = rotgen::block(mat, 0, 0, 4, 3); + auto b = rotgen::block(mat, 0, 0, 4, 3); for(rotgen::Index i=0;i<4;i++) { for(rotgen::Index j=0;j<3;j++) @@ -91,7 +91,7 @@ TTS_CASE_TPL("Test one index coefficient accessors", rotgen::tests::types) base mat(4,3); for(int k=0;k<12;++k) mat.data()[k] = data[k]; - auto b = rotgen::block(mat, 0, 0, 4, 3); + auto b = rotgen::block(mat, 0, 0, 4, 3); for(rotgen::Index i=0;i +template void validate_block_behavior(MatrixType& matrix, BlockType& block, rotgen::Index i0, rotgen::Index j0, rotgen::Index ni, rotgen::Index nj) { + using T = typename MatrixType::value_type; TTS_EQUAL(block.rows(), ni); TTS_EQUAL(block.cols(), nj); TTS_EQUAL(block.size(), ni * nj); @@ -53,24 +54,27 @@ void validate_block_behavior(MatrixType& matrix, BlockType& block, TTS_EQUAL(val, matrix(i0 + i, j0 + j)); }); - // test aliasing - T value = 1; - for_each_element(block, [&](auto i, auto j, auto&) { - block(i, j) = value++; - }); + // test aliasing if non immutable + if constexpr(!BlockType::is_immutable) + { + T value = 1; + for_each_element(block, [&](auto i, auto j, auto&) { + block(i, j) = value++; + }); - value = 1; - for_each_element(block, [&](auto i, auto j, auto&) { - TTS_EQUAL(matrix(i0 + i, j0 + j), value++); - }); + value = 1; + for_each_element(block, [&](auto i, auto j, auto&) { + TTS_EQUAL(matrix(i0 + i, j0 + j), value++); + }); - for_each_element(block, [&](auto i, auto j, auto&) { - matrix(i0 + i, j0 + j) = T(42); - }); + for_each_element(block, [&](auto i, auto j, auto&) { + matrix(i0 + i, j0 + j) = T(42); + }); - for_each_element(block, [&](auto&, auto&, auto val) { - TTS_EQUAL(val, T(42)); - }); + for_each_element(block, [&](auto&, auto&, auto val) { + TTS_EQUAL(val, T(42)); + }); + } } template @@ -78,6 +82,23 @@ void test_dynamic_block_extraction(rotgen::tests::matrix_block_test_case(matrix_construct); + MatrixType const c_matrix = matrix; + + auto c_block_main = rotgen::extract(c_matrix, matrix_construct.i0, matrix_construct.j0, + matrix_construct.ni, matrix_construct.nj); + auto c_block_top_left_corner = rotgen::topLeftCorner(c_matrix, matrix_construct.ni, matrix_construct.nj); + auto c_block_top_right_corner = rotgen::topRightCorner(c_matrix, matrix_construct.ni, matrix_construct.nj); + auto c_block_bottom_left_corner = rotgen::bottomLeftCorner(c_matrix, matrix_construct.ni, matrix_construct.nj); + auto c_block_bottom_right_corner = rotgen::bottomRightCorner(c_matrix, matrix_construct.ni, matrix_construct.nj); + + auto c_block_top_rows = rotgen::topRows(c_matrix, matrix_construct.ni); + auto c_block_middle_rows = rotgen::middleRows(c_matrix, matrix_construct.i0, matrix_construct.ni); + auto c_block_bottom_rows = rotgen::bottomRows(c_matrix, matrix_construct.ni); + + auto c_block_left_cols = rotgen::leftCols(c_matrix, matrix_construct.nj); + auto c_block_middle_cols = rotgen::middleCols(c_matrix, matrix_construct.j0, matrix_construct.nj); + auto c_block_right_cols = rotgen::rightCols(c_matrix, matrix_construct.nj); + auto block_main = rotgen::extract(matrix, matrix_construct.i0, matrix_construct.j0, matrix_construct.ni, matrix_construct.nj); auto block_top_left_corner = rotgen::topLeftCorner(matrix, matrix_construct.ni, matrix_construct.nj); @@ -94,6 +115,22 @@ void test_dynamic_block_extraction(rotgen::tests::matrix_block_test_case(matrix, block, i_offset, j_offset, ni, nj); + validate_block_behavior(matrix, block, i_offset, j_offset, ni, nj); })(), ...); }, blocks); @@ -139,68 +176,109 @@ void test_static_block_extraction(rotgen::tests::static_matrix_block_test_case(fn(i, j)); + MatrixType const c_matrix = matrix; + + auto c_block_main = rotgen::extract(c_matrix, i0, j0); + auto c_block_top_left_corner = rotgen::topLeftCorner(c_matrix); + auto c_block_top_right_corner = rotgen::topRightCorner(c_matrix); + auto c_block_bottom_left_corner = rotgen::bottomLeftCorner(c_matrix); + auto c_block_bottom_right_corner = rotgen::bottomRightCorner(c_matrix); + auto c_block_top_rows = rotgen::topRows(c_matrix); + auto c_block_middle_rows = rotgen::middleRows(c_matrix, i0); + auto c_block_bottom_rows = rotgen::bottomRows(c_matrix); + auto c_block_left_cols = rotgen::leftCols(c_matrix); + auto c_block_middle_cols = rotgen::middleCols(c_matrix, j0); + auto c_block_right_cols = rotgen::rightCols(c_matrix); + auto c_block_row = rotgen::row(c_matrix, i0); + auto c_block_col = rotgen::col(c_matrix, j0); + auto block_main = rotgen::extract(matrix, i0, j0); auto block_top_left_corner = rotgen::topLeftCorner(matrix); auto block_top_right_corner = rotgen::topRightCorner(matrix); auto block_bottom_left_corner = rotgen::bottomLeftCorner(matrix); auto block_bottom_right_corner = rotgen::bottomRightCorner(matrix); - auto block_top_rows = rotgen::topRows(matrix); auto block_middle_rows = rotgen::middleRows(matrix, i0); auto block_bottom_rows = rotgen::bottomRows(matrix); - auto block_left_cols = rotgen::leftCols(matrix); auto block_middle_cols = rotgen::middleCols(matrix, j0); auto block_right_cols = rotgen::rightCols(matrix); - auto block_row = rotgen::row(matrix, i0); auto block_col = rotgen::col(matrix, j0); auto blocks = std::make_tuple( + + // ----- TEST ON BLOCK FROM CONST MATRIX + std::make_tuple(c_block_main, i0, j0, + matrix_construct.ni, matrix_construct.nj, int(NI), int(NJ)), + std::make_tuple(c_block_top_left_corner, 0, 0, + matrix_construct.ni, matrix_construct.nj, int(NI), int(NJ)), + std::make_tuple(c_block_top_right_corner, 0, matrix.cols() - matrix_construct.nj, + matrix_construct.ni, matrix_construct.nj, int(NI), int(NJ)), + std::make_tuple(c_block_bottom_left_corner, matrix.rows() - matrix_construct.ni, 0, + matrix_construct.ni, matrix_construct.nj, int(NI), int(NJ)), + std::make_tuple(c_block_bottom_right_corner, matrix.rows() - matrix_construct.ni, + matrix.cols() - matrix_construct.nj, matrix_construct.ni, + matrix_construct.nj, int(NI), int(NJ)), + + std::make_tuple(c_block_top_rows, 0, 0, matrix_construct.ni, matrix.cols(), int(NI), rotgen::Dynamic), + std::make_tuple(c_block_middle_rows, i0, 0, matrix_construct.ni, + matrix.cols(), int(NI), rotgen::Dynamic), + std::make_tuple(c_block_bottom_rows, matrix.rows() - matrix_construct.ni, + 0, matrix_construct.ni, matrix.cols(), int(NI), rotgen::Dynamic), + + std::make_tuple(c_block_left_cols, 0, 0, matrix.rows(), matrix_construct.nj, rotgen::Dynamic, int(NJ)), + std::make_tuple(c_block_middle_cols, 0, j0, + matrix.rows(), matrix_construct.nj, rotgen::Dynamic, int(NJ)), + std::make_tuple(c_block_right_cols, 0, matrix.cols() - matrix_construct.nj, + matrix.rows(), matrix_construct.nj, rotgen::Dynamic, int(NJ)), + + std::make_tuple(c_block_row, i0, 0, + 1, matrix.cols(), 1, rotgen::Dynamic), + std::make_tuple(c_block_col, 0, j0, + matrix.rows(), 1, rotgen::Dynamic, 1), + // -- Block to NON CONST std::make_tuple(block_main, i0, j0, - matrix_construct.ni, matrix_construct.nj, int(NI), int(NJ), -1), + matrix_construct.ni, matrix_construct.nj, int(NI), int(NJ)), std::make_tuple(block_top_left_corner, 0, 0, - matrix_construct.ni, matrix_construct.nj, int(NI), int(NJ), -1), + matrix_construct.ni, matrix_construct.nj, int(NI), int(NJ)), std::make_tuple(block_top_right_corner, 0, matrix.cols() - matrix_construct.nj, - matrix_construct.ni, matrix_construct.nj, int(NI), int(NJ), -1), + matrix_construct.ni, matrix_construct.nj, int(NI), int(NJ)), std::make_tuple(block_bottom_left_corner, matrix.rows() - matrix_construct.ni, 0, - matrix_construct.ni, matrix_construct.nj, int(NI), int(NJ), -1), + matrix_construct.ni, matrix_construct.nj, int(NI), int(NJ)), std::make_tuple(block_bottom_right_corner, matrix.rows() - matrix_construct.ni, matrix.cols() - matrix_construct.nj, matrix_construct.ni, - matrix_construct.nj, int(NI), int(NJ), -1), + matrix_construct.nj, int(NI), int(NJ)), - std::make_tuple(block_top_rows, 0, 0, matrix_construct.ni, matrix.cols(), int(NI), rotgen::Dynamic, -1), + std::make_tuple(block_top_rows, 0, 0, matrix_construct.ni, matrix.cols(), int(NI), rotgen::Dynamic), std::make_tuple(block_middle_rows, i0, 0, matrix_construct.ni, - matrix.cols(), int(NI), rotgen::Dynamic, -1), + matrix.cols(), int(NI), rotgen::Dynamic), std::make_tuple(block_bottom_rows, matrix.rows() - matrix_construct.ni, - 0, matrix_construct.ni, matrix.cols(), int(NI), rotgen::Dynamic, -1), + 0, matrix_construct.ni, matrix.cols(), int(NI), rotgen::Dynamic), - std::make_tuple(block_left_cols, 0, 0, matrix.rows(), matrix_construct.nj, rotgen::Dynamic, int(NJ), -1), + std::make_tuple(block_left_cols, 0, 0, matrix.rows(), matrix_construct.nj, rotgen::Dynamic, int(NJ)), std::make_tuple(block_middle_cols, 0, j0, - matrix.rows(), matrix_construct.nj, rotgen::Dynamic, int(NJ), -1), + matrix.rows(), matrix_construct.nj, rotgen::Dynamic, int(NJ)), std::make_tuple(block_right_cols, 0, matrix.cols() - matrix_construct.nj, - matrix.rows(), matrix_construct.nj, rotgen::Dynamic, int(NJ), -1), + matrix.rows(), matrix_construct.nj, rotgen::Dynamic, int(NJ)), std::make_tuple(block_row, i0, 0, - 1, matrix.cols(), 1, rotgen::Dynamic, 1), + 1, matrix.cols(), 1, rotgen::Dynamic), std::make_tuple(block_col, 0, j0, - matrix.rows(), 1, rotgen::Dynamic, 1, 0) + matrix.rows(), 1, rotgen::Dynamic, 1) ); std::apply([&](auto&&... block_entries) { (([&] { - auto&& [block, i_offset, j_offset, ni, nj, rows_ct, cols_ct, storage_order] = block_entries; + auto&& [block, i_offset, j_offset, ni, nj, rows_ct, cols_ct] = block_entries; using block_t = std::remove_reference_t; TTS_EQUAL(block_t::RowsAtCompileTime, rows_ct); TTS_EQUAL(block_t::ColsAtCompileTime, cols_ct); - auto expected_storage_order = (storage_order == -1) ? MatrixType::storage_order : storage_order; - TTS_EQUAL(block_t::storage_order, expected_storage_order); - - validate_block_behavior(matrix, block, i_offset, j_offset, ni, nj); + validate_block_behavior(matrix, block, i_offset, j_offset, ni, nj); })(), ...); }, blocks); } @@ -242,7 +320,7 @@ TTS_CASE_TPL("Check all dynamic block extractions on a static column-major matri TTS_CASE_TPL("Check all static block extractions", rotgen::tests::types) ( tts::type< tts::types> ) { - using mat_t = rotgen::matrix; + using mat_t = rotgen::matrix; test_static_block_extraction( rotgen::tests::static_matrix_block_test_case{ @@ -264,4 +342,85 @@ TTS_CASE_TPL("Check all static block extractions", rotgen::tests::types) 0, 0 } ); +}; + +TTS_CASE_TPL("Check vector-only extractions", rotgen::tests::types) +( tts::type< tts::types> ) +{ + auto refs = []() + { + if constexpr(O::value == rotgen::RowMajor) + { + using mat_t = rotgen::matrix; + mat_t m(1,11); + + for(rotgen::Index i=0;i<11;++i) m(i) = 1 + i; + + return std::make_tuple( m, + std::make_tuple + ( + std::make_tuple(head(m, 1), 0, 0, 1, 1, 1, rotgen::Dynamic) + , std::make_tuple(head(m, 5), 0, 0, 1, 5, 1, rotgen::Dynamic) + , std::make_tuple(head(m,11), 0, 0, 1,11, 1, rotgen::Dynamic) + , std::make_tuple(head<1>(m), 0, 0, 1, 1, 1, 1) + , std::make_tuple(head<4>(m), 0, 0, 1, 4, 1, 4) + , std::make_tuple(head<9>(m), 0, 0, 1, 9, 1, 9) + , std::make_tuple(tail(m, 1), 0,10, 1, 1, 1, rotgen::Dynamic) + , std::make_tuple(tail(m, 5), 0, 6, 1, 5, 1, rotgen::Dynamic) + , std::make_tuple(tail(m,11), 0, 0, 1,11, 1, rotgen::Dynamic) + , std::make_tuple(tail<1>(m), 0,10, 1, 1, 1, 1) + , std::make_tuple(tail<4>(m), 0, 7, 1, 4, 1, 4) + , std::make_tuple(tail<9>(m), 0, 2, 1, 9, 1, 9) + , std::make_tuple(segment(m,0,11), 0, 0, 1, 11, 1, rotgen::Dynamic) + , std::make_tuple(segment(m,0, 7), 0, 0, 1, 7, 1, rotgen::Dynamic) + , std::make_tuple(segment(m,5, 6), 0, 5, 1, 6, 1, rotgen::Dynamic) + , std::make_tuple(segment<11>(m,0), 0, 0, 1, 11, 1, 11) + , std::make_tuple(segment< 7>(m,0), 0, 0, 1, 7, 1, 7) + , std::make_tuple(segment< 6>(m,5), 0, 5, 1, 6, 1, 6) + ) + ); + } + else + { + using mat_t = rotgen::matrix; + mat_t m(11,1); + + for(rotgen::Index i=0;i<11;++i) m(i) = 1 + i; + + return std::make_tuple( m, + std::make_tuple + ( + std::make_tuple(head(m, 1), 0, 0, 1, 1, rotgen::Dynamic, 1) + , std::make_tuple(head(m, 5), 0, 0, 5, 1, rotgen::Dynamic, 1) + , std::make_tuple(head(m,11), 0, 0,11, 1, rotgen::Dynamic, 1) + , std::make_tuple(head<1>(m), 0, 0, 1, 1, 1, 1) + , std::make_tuple(head<4>(m), 0, 0, 4, 1, 4, 1) + , std::make_tuple(head<9>(m), 0, 0, 9, 1, 9, 1) + , std::make_tuple(tail(m, 1),10, 0, 1, 1, rotgen::Dynamic, 1) + , std::make_tuple(tail(m, 5), 6, 0, 5, 1, rotgen::Dynamic, 1) + , std::make_tuple(tail(m,11), 0, 0,11, 1, rotgen::Dynamic, 1) + , std::make_tuple(tail<1>(m),10, 0, 1, 1, 1, 1) + , std::make_tuple(tail<4>(m), 7, 0, 4, 1, 4, 1) + , std::make_tuple(tail<9>(m), 2, 0, 9, 1, 9, 1) + ) + ); + } + }(); + + auto matrix = std::get<0>(refs); + auto blocks = std::get<1>(refs); + + std::apply([&](auto&&... block_entries) + { + (([&] + { + auto&& [block, i_offset, j_offset, ni, nj, rows_ct, cols_ct] = block_entries; + using block_t = std::remove_reference_t; + + TTS_EQUAL(block_t::RowsAtCompileTime, rows_ct); + TTS_EQUAL(block_t::ColsAtCompileTime, cols_ct); + + validate_block_behavior(matrix, block, i_offset, j_offset, ni, nj); + })(), ...); + }, blocks); }; \ No newline at end of file