From cc5ab775bcae8d64f2987faf4818c0c3cfd7849b Mon Sep 17 00:00:00 2001 From: Joel Falcou Date: Tue, 9 Sep 2025 15:21:35 +0200 Subject: [PATCH] Implements noalias/evaluate See merge request oss/rotgen!18 --- include/rotgen/common/ref.hpp | 4 +++ include/rotgen/dynamic/block.hpp | 4 +++ include/rotgen/dynamic/map.hpp | 14 +++++++++ include/rotgen/dynamic/matrix.hpp | 17 +++++++++++ include/rotgen/fixed/block.hpp | 26 +++++++++++++++++ include/rotgen/fixed/map.hpp | 27 ++++++++++++++++++ include/rotgen/fixed/matrix.hpp | 26 +++++++++++++++-- include/rotgen/functions.hpp | 18 ++++++++++++ test/integration/aliasing.cpp | 47 +++++++++++++++++++++++++++++++ 9 files changed, 181 insertions(+), 2 deletions(-) create mode 100644 test/integration/aliasing.cpp diff --git a/include/rotgen/common/ref.hpp b/include/rotgen/common/ref.hpp index 62720d6..4d27f5d 100644 --- a/include/rotgen/common/ref.hpp +++ b/include/rotgen/common/ref.hpp @@ -27,6 +27,8 @@ namespace rotgen static constexpr int storage_order = T::storage_order; + using parent::evaluate; + using parent::noalias; using parent::operator(); using parent::rows; using parent::cols; @@ -99,6 +101,8 @@ namespace rotgen static constexpr int storage_order = T::storage_order; + using parent::evaluate; + using parent::noalias; using parent::operator(); using parent::rows; using parent::cols; diff --git a/include/rotgen/dynamic/block.hpp b/include/rotgen/dynamic/block.hpp index e67c612..9ffd4b8 100644 --- a/include/rotgen/dynamic/block.hpp +++ b/include/rotgen/dynamic/block.hpp @@ -117,6 +117,10 @@ namespace rotgen return parent::operator()(i); } + auto evaluate() const { return *this; } + decltype(auto) noalias() const { return *this; } + decltype(auto) noalias() { return *this; } + concrete_type transpose() const { return concrete_type(static_cast(*this).transpose()); diff --git a/include/rotgen/dynamic/map.hpp b/include/rotgen/dynamic/map.hpp index c8d5d8d..ffd58a7 100644 --- a/include/rotgen/dynamic/map.hpp +++ b/include/rotgen/dynamic/map.hpp @@ -72,6 +72,16 @@ namespace rotgen return *this; } + map& 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) + for (rotgen::Index c = 0; c < parent::cols(); ++c) + (*this)(r, c) = other(r, c); + + return *this; + } + value_type& operator()(Index i, Index j) requires(!is_immutable) { return parent::operator()(i,j); } value_type& operator()(Index i) requires(!is_immutable) { @@ -90,6 +100,10 @@ namespace rotgen return parent::operator()(i); } + auto evaluate() const { return *this; } + decltype(auto) noalias() const { return *this; } + decltype(auto) noalias() { return *this; } + concrete_type transpose() const { return concrete_type(static_cast(*this).transpose()); diff --git a/include/rotgen/dynamic/matrix.hpp b/include/rotgen/dynamic/matrix.hpp index ed80384..c7e65b0 100644 --- a/include/rotgen/dynamic/matrix.hpp +++ b/include/rotgen/dynamic/matrix.hpp @@ -70,6 +70,23 @@ namespace rotgen (*this)(r, c) = e(r, c); } + matrix& operator=(concepts::entity auto const& e) + { + if constexpr(Rows != -1) assert(e.rows() == Rows && "Mismatched between dynamic and static row size"); + if constexpr(Cols != -1) assert(e.cols() == Cols && "Mismatched between dynamic and static col size"); + resize(e.rows(), e.cols()); + + for (rotgen::Index r = 0; r < e.rows(); ++r) + for (rotgen::Index c = 0; c < e.cols(); ++c) + (*this)(r, c) = e(r, c); + + return *this; + } + + auto evaluate() const { return *this; } + decltype(auto) noalias() const { return *this; } + decltype(auto) noalias() { return *this; } + void resize(int new_rows, int new_cols) requires(Rows == -1 && Cols == -1) { parent::resize(new_rows, new_cols); diff --git a/include/rotgen/fixed/block.hpp b/include/rotgen/fixed/block.hpp index 4a7c0f3..18d199c 100644 --- a/include/rotgen/fixed/block.hpp +++ b/include/rotgen/fixed/block.hpp @@ -101,6 +101,15 @@ namespace rotgen template block(const Eigen::EigenBase& other) : parent(other) {} + block(concepts::entity auto const& other) : parent(other.base()) + {} + + block& operator=(concepts::entity auto const& other) + { + parent::operator=(other.base()); + return *this; + } + template block& operator=(const Eigen::MatrixBase& other) { @@ -118,6 +127,23 @@ namespace rotgen parent& base() { return static_cast(*this); } parent const& base() const { return static_cast(*this); } + auto evaluate() const + { + auto res = static_cast(*this).eval(); + return as_concrete_type(res); + } + + decltype(auto) noalias() const + { + if constexpr(use_expression_templates) return base().noalias(); + else return *this; + } + + decltype(auto) noalias() + { + if constexpr(use_expression_templates) return base().noalias(); + else return *this; + } auto transpose() const { diff --git a/include/rotgen/fixed/map.hpp b/include/rotgen/fixed/map.hpp index 329e411..ec0076b 100644 --- a/include/rotgen/fixed/map.hpp +++ b/include/rotgen/fixed/map.hpp @@ -73,9 +73,36 @@ namespace rotgen : map( ptr, RowsAtCompileTime, ColsAtCompileTime ) {} + map(concepts::entity auto const& other) : parent(other.base()) + {} + + map& operator=(concepts::entity auto const& other) + { + parent::operator=(other.base()); + return *this; + } + parent& base() { return static_cast(*this); } parent const& base() const { return static_cast(*this); } + auto evaluate() const + { + auto res = static_cast(*this).eval(); + return as_concrete_type(res); + } + + decltype(auto) noalias() const + { + if constexpr(use_expression_templates) return base().noalias(); + else return *this; + } + + decltype(auto) noalias() + { + if constexpr(use_expression_templates) return base().noalias(); + else return *this; + } + value_type& operator()(Index i, Index j) { return base()(i, j); } value_type operator()(Index i, Index j) const { return base()(i, j); } diff --git a/include/rotgen/fixed/matrix.hpp b/include/rotgen/fixed/matrix.hpp index 3d53ef6..57afd5a 100644 --- a/include/rotgen/fixed/matrix.hpp +++ b/include/rotgen/fixed/matrix.hpp @@ -118,10 +118,32 @@ namespace rotgen parent& base() { return static_cast(*this); } parent const& base() const { return static_cast(*this); } + auto evaluate() const + { + auto res = static_cast(*this).eval(); + return as_concrete_type(res); + } + + decltype(auto) noalias() const + { + if constexpr(use_expression_templates) return base().noalias(); + else return *this; + } + + decltype(auto) noalias() + { + if constexpr(use_expression_templates) return base().noalias(); + else return *this; + } + auto transpose() const { - auto res = static_cast(*this).transpose(); - return as_concrete_type(res); + if constexpr(use_expression_templates) return base().transpose(); + else + { + auto res = static_cast(*this).transpose(); + return as_concrete_type(res); + } } auto conjugate() const diff --git a/include/rotgen/functions.hpp b/include/rotgen/functions.hpp index 84949da..5a093f8 100644 --- a/include/rotgen/functions.hpp +++ b/include/rotgen/functions.hpp @@ -69,4 +69,22 @@ namespace rotgen static_assert(P == 1 || P == 2 || P == Infinity); return arg.template lpNorm

(); } + + template + decltype(auto) noalias(T&& t) requires( requires{std::forward(t).noalias();} ) + { + return std::forward(t).noalias(); + } + + template + auto evaluate(T&& t) requires( requires{std::forward(t).evaluate();} ) + { + return std::forward(t).evaluate(); + } + + template + auto evaluate(T&& t) requires( requires{std::forward(t).eval();} ) + { + return std::forward(t).eval(); + } } diff --git a/test/integration/aliasing.cpp b/test/integration/aliasing.cpp new file mode 100644 index 0000000..51cf9d6 --- /dev/null +++ b/test/integration/aliasing.cpp @@ -0,0 +1,47 @@ +//================================================================================================== +/* + ROTGEN - Runtime Overlay for Eigen + Copyright : CODE RECKONS + SPDX-License-Identifier: BSL-1.0 +*/ +//================================================================================================== +#include "unit/tests.hpp" +#include + +TTS_CASE_TPL("noalias behavior - dynamicallly sized", rotgen::tests::types) +( tts::type< tts::types> ) +{ + rotgen::matrix a{{1,2},{3,4}}; + rotgen::matrix ref{{7,10},{15,22}}; + rotgen::matrix b(2,2),c(2,2),d(2,2); + + rotgen::noalias(b) = a * a; + TTS_EQUAL(b, ref); + + auto e = rotgen::extract(c,0,0,2,2); + rotgen::noalias(e) = a * a; + TTS_EQUAL(c, ref); + + rotgen::map> m(d.data(),2,2); + rotgen::noalias(m) = a * a; + TTS_EQUAL(m, ref); +}; + +TTS_CASE_TPL("noalias behavior - statically sized", rotgen::tests::types) +( tts::type< tts::types> ) +{ + rotgen::matrix a{{1,2},{3,4}}; + rotgen::matrix ref{{7,10},{15,22}}; + rotgen::matrix b,c,d; + + rotgen::noalias(b) = a * a; + TTS_EQUAL(b, ref); + + auto e = rotgen::extract(c,0,0,2,2); + rotgen::noalias(e) = a * a; + TTS_EQUAL(c, ref); + + rotgen::map> m(d.data()); + rotgen::noalias(m) = a * a; + TTS_EQUAL(m, ref); +}; \ No newline at end of file