From bb47b074221d20430b61cf3d943af19976c21976 Mon Sep 17 00:00:00 2001 From: Joel Falcou Date: Tue, 9 Sep 2025 16:27:22 +0200 Subject: [PATCH] Implement a QR solver wrapper --- include/rotgen/dynamic/map.hpp | 5 +++ include/rotgen/fixed/map.hpp | 5 +++ include/rotgen/functions.hpp | 8 ++++- include/rotgen/impl/map_model.hpp | 2 ++ include/rotgen/rotgen.hpp | 1 + include/rotgen/solver.hpp | 20 +++++++++++ src/map_model.cpp | 10 ++++++ test/CMakeLists.txt | 11 +++--- test/unit/functions/qr.cpp | 34 +++++++++++++++++++ .../size_related.cpp | 0 10 files changed, 90 insertions(+), 6 deletions(-) create mode 100644 include/rotgen/solver.hpp create mode 100644 test/unit/functions/qr.cpp rename test/unit/{free_functions => functions}/size_related.cpp (100%) diff --git a/include/rotgen/dynamic/map.hpp b/include/rotgen/dynamic/map.hpp index ffd58a7..67c4b23 100644 --- a/include/rotgen/dynamic/map.hpp +++ b/include/rotgen/dynamic/map.hpp @@ -241,6 +241,11 @@ namespace rotgen parent& base() { return static_cast(*this); } parent const& base() const { return static_cast(*this); } + + concrete_type qr_solve(map const& rhs) const + { + return concrete_type(base().qr_solve(rhs.base())); + }; }; template diff --git a/include/rotgen/fixed/map.hpp b/include/rotgen/fixed/map.hpp index ec0076b..40772bd 100644 --- a/include/rotgen/fixed/map.hpp +++ b/include/rotgen/fixed/map.hpp @@ -193,6 +193,11 @@ namespace rotgen void transposeInPlace() { base().transposeInPlace(); } void adjointInPlace() { base().adjointInPlace(); } + auto qr_solve(map const& rhs) const + { + return concrete_type(base().colPivHouseholderQr().solve(rhs.base())); + }; + static auto Zero() requires( requires {Ref::Zero();} ) { return Ref::Zero(); } static auto Zero(int rows, int cols) { return Ref::Zero(rows,cols); } diff --git a/include/rotgen/functions.hpp b/include/rotgen/functions.hpp index 5a093f8..5126cfd 100644 --- a/include/rotgen/functions.hpp +++ b/include/rotgen/functions.hpp @@ -52,7 +52,13 @@ namespace rotgen auto sum(concepts::entity auto const& arg) { return arg.sum(); } auto prod(concepts::entity auto const& arg) { return arg.prod(); } auto mean(concepts::entity auto const& arg) { return arg.mean(); } - auto maxCoeff(concepts::entity auto const& arg) { return arg.maxCoeff(); } + + auto maxCoeff(auto const& arg) + requires( requires{ arg.maxCoeff(); } ) + { + return arg.maxCoeff(); + } + auto minCoeff(concepts::entity auto const& arg) { return arg.minCoeff(); } auto maxCoeff(concepts::entity auto const& arg, Index* row, Index* col) { diff --git a/include/rotgen/impl/map_model.hpp b/include/rotgen/impl/map_model.hpp index e52788e..0820799 100644 --- a/include/rotgen/impl/map_model.hpp +++ b/include/rotgen/impl/map_model.hpp @@ -63,6 +63,8 @@ class ROTGEN_EXPORT CLASSNAME TYPE norm() const; TYPE lpNorm(int p) const; + SOURCENAME qr_solve(CLASSNAME const& rhs) const; + #if !defined(USE_CONST) TYPE& operator()(Index i, Index j); TYPE& operator()(Index i); diff --git a/include/rotgen/rotgen.hpp b/include/rotgen/rotgen.hpp index 95ad9e1..bebb7e9 100644 --- a/include/rotgen/rotgen.hpp +++ b/include/rotgen/rotgen.hpp @@ -26,4 +26,5 @@ #include #include #include +#include #include diff --git a/include/rotgen/solver.hpp b/include/rotgen/solver.hpp new file mode 100644 index 0000000..0c9579f --- /dev/null +++ b/include/rotgen/solver.hpp @@ -0,0 +1,20 @@ +//================================================================================================== +/* + ROTGEN - Runtime Overlay for Eigen + Copyright : CODE RECKONS + SPDX-License-Identifier: BSL-1.0 +*/ +//================================================================================================== +#pragma once + +namespace rotgen::solver +{ + template + void qr(X& x, M const& m, RHS const& rhs ) + { + auto r_x = generalize_t(x); + auto r_m = generalize_t(m); + auto r_rhs = generalize_t(rhs); + r_x = r_m.base().qr_solve(r_rhs.base()); + } +} \ No newline at end of file diff --git a/src/map_model.cpp b/src/map_model.cpp index cee0edf..668f78b 100644 --- a/src/map_model.cpp +++ b/src/map_model.cpp @@ -170,6 +170,16 @@ } #endif + //================================================================================================== + // Solvers + //================================================================================================== + SOURCENAME CLASSNAME::qr_solve(CLASSNAME const& rhs) const + { + SOURCENAME result; + result.storage()->assign(storage_->data.colPivHouseholderQr().solve(rhs.storage_->data).eval()); + return result; + } + //================================================================================================== // Operators //================================================================================================== diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 8a095aa..2a245c7 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -17,12 +17,13 @@ target_link_libraries(rotgen_test INTERFACE rotgen Eigen3::Eigen) ##====================================================================================================================== ## Unit Tests registration ##====================================================================================================================== -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) +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) +rotgen_glob_unit(QUIET PATTERN "unit/functions/*.cpp" INTERFACE rotgen_test) ##====================================================================================================================== ## Integrations Tests registration ##====================================================================================================================== -rotgen_glob_unit(QUIET PATTERN "integration/*.cpp" INTERFACE rotgen_test) +rotgen_glob_unit(QUIET PATTERN "integration/*.cpp" INTERFACE rotgen_test) diff --git a/test/unit/functions/qr.cpp b/test/unit/functions/qr.cpp new file mode 100644 index 0000000..d5bd7ec --- /dev/null +++ b/test/unit/functions/qr.cpp @@ -0,0 +1,34 @@ +//================================================================================================== +/* + ROTGEN - Runtime Overlay for Eigen + Copyright : CODE RECKONS + SPDX-License-Identifier: BSL-1.0 +*/ +//================================================================================================== +#include "unit/tests.hpp" +#include + +TTS_CASE_TPL("System solver using QR", rotgen::tests::types) +( tts::type< tts::types> ) +{ + rotgen::matrix + a { { 2.3, -1, 0.1} + , {-1.6, 2.6, -1} + , { 0.3, -1, 2} + }; + + rotgen::matrix b(3,1); + b(0) = b(2) = 1; b(1) = 0; + + rotgen::matrix r(3,1), error; + + auto x = rotgen::extract(r,0,0,3,1); + rotgen::solver::qr(x, a, b); + + error = a * r - b; + auto eps = std::numeric_limits::epsilon(); + + TTS_LESS(rotgen::maxCoeff(rotgen::abs(error)) / eps, 5) + << "Result:\n" << r << "\n" + << "Residuals:\n" << error << "\n"; +}; \ No newline at end of file diff --git a/test/unit/free_functions/size_related.cpp b/test/unit/functions/size_related.cpp similarity index 100% rename from test/unit/free_functions/size_related.cpp rename to test/unit/functions/size_related.cpp