From 6c2b260229203a5b195769e732d54393b036094b Mon Sep 17 00:00:00 2001 From: Joel Falcou Date: Wed, 13 Aug 2025 17:43:57 +0200 Subject: [PATCH] Implements map and ref for both static & dynamic mode See merge request oss/rotgen!12 --- CMakeLists.txt | 5 +- CMakePresets.json | 10 +- cmake/options.cmake | 50 ++- include/rotgen/alias.hpp | 40 +++ include/rotgen/common/ref.hpp | 284 +++++++++++++++ include/rotgen/common/strides.hpp | 37 ++ include/rotgen/common/traits.hpp | 28 ++ include/rotgen/concepts.hpp | 19 + include/rotgen/config.hpp | 50 ++- include/rotgen/dynamic/block.hpp | 165 ++++++--- include/rotgen/dynamic/map.hpp | 280 +++++++++++++++ include/rotgen/dynamic/matrix.hpp | 124 ++++++- include/rotgen/fixed/block.hpp | 164 +++++++-- include/rotgen/fixed/common.hpp | 86 ----- include/rotgen/fixed/map.hpp | 328 ++++++++++++++++++ include/rotgen/fixed/matrix.hpp | 136 ++++++-- include/rotgen/functions.hpp | 154 ++------ include/rotgen/impl/block.hpp | 3 +- include/rotgen/impl/block_model.hpp | 22 +- include/rotgen/impl/map.hpp | 115 ++++++ include/rotgen/impl/map_model.hpp | 106 ++++++ include/rotgen/impl/map_operators.hpp | 39 +++ include/rotgen/impl/matrix_model.hpp | 3 + include/rotgen/impl/payload.hpp | 111 +++++- include/rotgen/operators.hpp | 71 ++++ include/rotgen/rotgen.hpp | 7 + src/block_model.cpp | 29 +- src/info.cpp | 20 +- src/map.cpp | 110 ++++++ src/map_model.cpp | 236 +++++++++++++ src/matrix_model.cpp | 15 +- src/operators.cpp | 40 +++ test/CMakeLists.txt | 7 +- test/unit/block/arithmetic_functions.cpp | 181 ++++------ test/unit/block/basic_api.cpp | 104 ++++++ test/unit/block/extract.cpp | 66 ++-- test/unit/block/generators.cpp | 268 ++++++++++++++ test/unit/block/norms.cpp | 62 ++-- test/unit/block/operators.cpp | 271 ++++++++------- test/unit/block/static_functions.cpp | 117 ------- test/unit/common/arithmetic.hpp | 126 +++++++ test/unit/common/norms.hpp | 35 ++ test/unit/common/references.hpp | 192 ++++++++++ .../free_functions/arithmetic_functions.cpp | 124 ------- test/unit/free_functions/norms.cpp | 60 ---- test/unit/io.cpp | 47 +++ test/unit/map/arithmetic_functions.cpp | 73 ++++ test/unit/map/basic_api.cpp | 83 +++++ test/unit/map/constructors.cpp | 89 +++++ test/unit/map/norms.cpp | 41 +++ test/unit/map/operators.cpp | 202 +++++++++++ test/unit/matrix/arithmetic_functions.cpp | 134 +++---- .../matrix/{functions.cpp => basic_api.cpp} | 2 +- test/unit/matrix/constructors.cpp | 3 +- .../{static_functions.cpp => generators.cpp} | 52 +++ test/unit/matrix/io.cpp | 20 -- test/unit/matrix/norms.cpp | 52 ++- test/unit/tests.hpp | 28 +- 58 files changed, 4121 insertions(+), 1205 deletions(-) create mode 100644 include/rotgen/alias.hpp create mode 100644 include/rotgen/common/ref.hpp create mode 100644 include/rotgen/common/strides.hpp create mode 100644 include/rotgen/common/traits.hpp create mode 100644 include/rotgen/dynamic/map.hpp delete mode 100644 include/rotgen/fixed/common.hpp create mode 100644 include/rotgen/fixed/map.hpp create mode 100644 include/rotgen/impl/map.hpp create mode 100644 include/rotgen/impl/map_model.hpp create mode 100644 include/rotgen/impl/map_operators.hpp create mode 100644 include/rotgen/operators.hpp create mode 100644 src/map.cpp create mode 100644 src/map_model.cpp create mode 100644 src/operators.cpp create mode 100644 test/unit/block/basic_api.cpp create mode 100644 test/unit/block/generators.cpp delete mode 100644 test/unit/block/static_functions.cpp create mode 100644 test/unit/common/arithmetic.hpp create mode 100644 test/unit/common/norms.hpp create mode 100644 test/unit/common/references.hpp delete mode 100644 test/unit/free_functions/arithmetic_functions.cpp delete mode 100644 test/unit/free_functions/norms.cpp create mode 100644 test/unit/io.cpp create mode 100644 test/unit/map/arithmetic_functions.cpp create mode 100644 test/unit/map/basic_api.cpp create mode 100644 test/unit/map/constructors.cpp create mode 100644 test/unit/map/norms.cpp create mode 100644 test/unit/map/operators.cpp rename test/unit/matrix/{functions.cpp => basic_api.cpp} (99%) rename test/unit/matrix/{static_functions.cpp => generators.cpp} (51%) delete mode 100644 test/unit/matrix/io.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index ad9bac1..06430fe 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -29,20 +29,23 @@ endif() ## Handle options ##====================================================================================================================== option(ROTGEN_FORCE_DYNAMIC "Force dynamic configuration for rotgen" OFF) -option(ROTGEN_DISABLE_EXPRESSION_TEMPLATES "Disable expression templates" OFF) +option(ROTGEN_ENABLE_EXPRESSION_TEMPLATES "Enable expression templates" OFF) set(ROTGEN_MAX_SIZE "" CACHE STRING "Max matrix number of elements for rotgen (integer)") include(${ROTGEN_SOURCE_DIR}/cmake/options.cmake) handle_option(ROTGEN_COMPILE_DEFS) +message(STATUS "[ROGEN] - Compiling with ${ROTGEN_COMPILE_DEFS}") ##====================================================================================================================== ## Sources & Public Headers lists ##====================================================================================================================== if(ROTGEN_FORCE_DYNAMIC) set ( SOURCES + src/map.cpp src/matrix.cpp src/block.cpp src/info.cpp + src/operators.cpp ) else() set ( SOURCES diff --git a/CMakePresets.json b/CMakePresets.json index 4759685..49a1a51 100644 --- a/CMakePresets.json +++ b/CMakePresets.json @@ -48,7 +48,7 @@ "generator": "Ninja", "binaryDir": "${sourceDir}/build/release-static", "cacheVariables": { - "ROTGEN_MAX_SIZE": "4" + "ROTGEN_MAX_SIZE": "16" } }, { @@ -58,7 +58,7 @@ "generator": "Ninja", "binaryDir": "${sourceDir}/build/debug-static", "cacheVariables": { - "ROTGEN_MAX_SIZE": "4" + "ROTGEN_MAX_SIZE": "16" } }, { @@ -68,7 +68,8 @@ "generator": "Ninja", "binaryDir": "${sourceDir}/build/release-et", "cacheVariables": { - "ROTGEN_DISABLE_EXPRESSION_TEMPLATES": "ON" + "ROTGEN_ENABLE_EXPRESSION_TEMPLATES": "ON", + "ROTGEN_MAX_SIZE": "16" } }, { @@ -78,7 +79,8 @@ "generator": "Ninja", "binaryDir": "${sourceDir}/build/debug-et", "cacheVariables": { - "ROTGEN_DISABLE_EXPRESSION_TEMPLATES": "ON" + "ROTGEN_ENABLE_EXPRESSION_TEMPLATES": "ON", + "ROTGEN_MAX_SIZE": "16" } } ], diff --git a/cmake/options.cmake b/cmake/options.cmake index 202586d..f1b1153 100644 --- a/cmake/options.cmake +++ b/cmake/options.cmake @@ -20,21 +20,24 @@ function(check_force_dynamic_and_sizes FORCE_DYNAMIC_VAR MAX_SIZE_VAR) endif() endfunction() -function(infer_force_dynamic FORCE_DYNAMIC_VAR MAX_SIZE_VAR OUT_FORCE_DYNAMIC_INFERRED) +function(infer_force_dynamic FORCE_DYNAMIC_VAR MAX_SIZE_VAR ET_VAR OUT_FORCE_DYNAMIC_INFERRED) set(${OUT_FORCE_DYNAMIC_INFERRED} OFF PARENT_SCOPE) if(${FORCE_DYNAMIC_VAR}) if(NOT ${MAX_SIZE_VAR} STREQUAL "") - message(FATAL_ERROR "ROTGEN_FORCE_DYNAMIC cannot be used together with MAX_SIZE.") + message(FATAL_ERROR "ROTGEN_FORCE_DYNAMIC cannot be used together with ROTGEN_MAX_SIZE.") endif() - elseif(${MAX_SIZE_VAR} STREQUAL "") + if(NOT ${ET_VAR} STREQUAL "") + message(FATAL_ERROR "ROTGEN_FORCE_DYNAMIC cannot be used together with ROTGEN_ENABLE_EXPRESSION_TEMPLATES.") + endif() + elseif(NOT ${MAX_SIZE_VAR} AND NOT ${ET_VAR}) # None set, enable force_dynamic set(${OUT_FORCE_DYNAMIC_INFERRED} ON PARENT_SCOPE) set(${FORCE_DYNAMIC_VAR} ON PARENT_SCOPE) # update caller variable! endif() endfunction() -function(build_compile_definitions FORCE_DYNAMIC_VAR MAX_SIZE_VAR OUT_DEFS) +function(build_compile_definitions FORCE_DYNAMIC_VAR MAX_SIZE_VAR ENABLE_ET OUT_DEFS) set(defs "") if(${FORCE_DYNAMIC_VAR}) list(APPEND defs "ROTGEN_FORCE_DYNAMIC") @@ -42,6 +45,9 @@ function(build_compile_definitions FORCE_DYNAMIC_VAR MAX_SIZE_VAR OUT_DEFS) if(NOT ${MAX_SIZE_VAR} STREQUAL "") list(APPEND defs "ROTGEN_MAX_SIZE=${${MAX_SIZE_VAR}}") endif() + if(${ENABLE_ET}) + list(APPEND defs "ROTGEN_ENABLE_EXPRESSION_TEMPLATES") + endif() endif() set(${OUT_DEFS} "${defs}" PARENT_SCOPE) endfunction() @@ -49,15 +55,14 @@ endfunction() function(print_configuration_summary FORCE_DYNAMIC_VAR FORCE_CONFIG_REASON MAX_SIZE_VAR COMPILE_DEFS) message(STATUS "==================== Rotgen Configuration Summary ====================") - if(DEFINED ROTGEN_DISABLE_EXPRESSION_TEMPLATES AND ROTGEN_DISABLE_EXPRESSION_TEMPLATES) - message(STATUS " Configuration mode: DISABLE_EXPRESSION_TEMPLATES (overrides other settings)") - elseif(${FORCE_DYNAMIC_VAR}) - message(STATUS " Configuration mode: DYNAMIC") - if(${FORCE_CONFIG_REASON}) - message(STATUS " Reason : No static size options were provided") - endif() + if(${FORCE_DYNAMIC_VAR}) + message(STATUS " Configuration mode: DYNAMIC") + if(${FORCE_CONFIG_REASON}) + message(STATUS " Reason : No static size options were provided") + endif() else() - message(STATUS " Configuration mode: STATIC") + message(STATUS " Configuration mode: STATIC") + message(STATUS " Expression Templates: ${ROTGEN_ENABLE_EXPRESSION_TEMPLATES}") endif() set(PREPROCESSOR_FLAGS "") @@ -70,20 +75,9 @@ endfunction() function(handle_option OUT_DEFS) # Early-out if disabling expression templates - if(NOT DEFINED ROTGEN_DISABLE_EXPRESSION_TEMPLATES) + if(NOT DEFINED ROTGEN_ENABLE_EXPRESSION_TEMPLATES) set(ROTGEN_DISABLE_EXPRESSION_TEMPLATES OFF) endif() - if(ROTGEN_DISABLE_EXPRESSION_TEMPLATES) - # Pass only the disable flag - set(${OUT_DEFS} "ROTGEN_DISABLE_EXPRESSION_TEMPLATES" PARENT_SCOPE) - message(STATUS "==================== Rotgen Configuration Summary ====================") - message(STATUS " Configuration mode: DISABLE_EXPRESSION_TEMPLATES (overrides other settings)") - message(STATUS " Preprocessor flags: -DROTGEN_DISABLE_EXPRESSION_TEMPLATES") - message(STATUS "======================================================================") - # Propagate to parent - set(ROTGEN_DISABLE_EXPRESSION_TEMPLATES ${ROTGEN_DISABLE_EXPRESSION_TEMPLATES} PARENT_SCOPE) - return() - endif() # Defaults for other options if(NOT DEFINED ROTGEN_FORCE_DYNAMIC) @@ -95,12 +89,16 @@ function(handle_option OUT_DEFS) assert_integer("ROTGEN_MAX_SIZE") check_force_dynamic_and_sizes("ROTGEN_FORCE_DYNAMIC" "ROTGEN_MAX_SIZE") - infer_force_dynamic("ROTGEN_FORCE_DYNAMIC" "ROTGEN_MAX_SIZE" _force_dynamic_inferred) + infer_force_dynamic ( "ROTGEN_FORCE_DYNAMIC" "ROTGEN_MAX_SIZE" + "ROTGEN_ENABLE_EXPRESSION_TEMPLATES" _force_dynamic_inferred + ) - build_compile_definitions("ROTGEN_FORCE_DYNAMIC" "ROTGEN_MAX_SIZE" defs) + build_compile_definitions("ROTGEN_FORCE_DYNAMIC" "ROTGEN_MAX_SIZE" "ROTGEN_ENABLE_EXPRESSION_TEMPLATES" defs) print_configuration_summary("ROTGEN_FORCE_DYNAMIC" "_force_dynamic_inferred" "ROTGEN_MAX_SIZE" "${defs}") set(${OUT_DEFS} "${defs}" PARENT_SCOPE) set(ROTGEN_FORCE_DYNAMIC ${ROTGEN_FORCE_DYNAMIC} PARENT_SCOPE) set(ROTGEN_MAX_SIZE ${ROTGEN_MAX_SIZE} PARENT_SCOPE) + set(ROTGEN_ENABLE_EXPRESSION_TEMPLATES ${ROTGEN_ENABLE_EXPRESSION_TEMPLATES} PARENT_SCOPE) + endfunction() diff --git a/include/rotgen/alias.hpp b/include/rotgen/alias.hpp new file mode 100644 index 0000000..33b2182 --- /dev/null +++ b/include/rotgen/alias.hpp @@ -0,0 +1,40 @@ +//================================================================================================== +/* + ROTGEN - Runtime Overlay for Eigen + Copyright : CODE RECKONS + SPDX-License-Identifier: BSL-1.0 +*/ +//================================================================================================== +namespace rotgen +{ + // matrix aliases (float and double, fixed and dynamic) + using matrix2f = rotgen::matrix; + using matrix3f = rotgen::matrix; + using matrix4f = rotgen::matrix; + using matrix2d = rotgen::matrix; + using matrix3d = rotgen::matrix; + using matrix4d = rotgen::matrix; + using matrixXf = rotgen::matrix; + using matrixXd = rotgen::matrix; + using matrixXi = rotgen::matrix; + + // Column vector aliases + using vector2f = rotgen::matrix; + using vector3f = rotgen::matrix; + using vector4f = rotgen::matrix; + using vector2d = rotgen::matrix; + using vector3d = rotgen::matrix; + using vector4d = rotgen::matrix; + using vectorXf = rotgen::matrix; + using vectorXd = rotgen::matrix; + + // Row vector aliases + using row_vector2f = rotgen::matrix; + using row_vector3f = rotgen::matrix; + using row_vector4f = rotgen::matrix; + using row_vector2d = rotgen::matrix; + using row_vector3d = rotgen::matrix; + using row_vector4d = rotgen::matrix; + using row_vectorXf = rotgen::matrix; + using row_vectorXd = rotgen::matrix; +} \ No newline at end of file diff --git a/include/rotgen/common/ref.hpp b/include/rotgen/common/ref.hpp new file mode 100644 index 0000000..34ea890 --- /dev/null +++ b/include/rotgen/common/ref.hpp @@ -0,0 +1,284 @@ +//================================================================================================== +/* + ROTGEN - Runtime Overlay for Eigen + Copyright : CODE RECKONS + SPDX-License-Identifier: BSL-1.0 +*/ +//================================================================================================== +#pragma once + +#include +#include + +#if !defined(ROTGEN_FORCE_DYNAMIC) +#include +#endif + +namespace rotgen +{ + // Primary template: mutable ref + template + class ref : private map + { + public: + using parent = map; + using value_type = typename T::value_type; + using rotgen_tag = void; + + using parent::operator(); + using parent::rows; + using parent::cols; + using parent::size; + using parent::data; + using parent::sum; + using parent::prod; + using parent::mean; + using parent::trace; + using parent::maxCoeff; + using parent::minCoeff; + using parent::norm; + using parent::squaredNorm; + using parent::lpNorm; + using parent::operator+=; + using parent::operator-=; + using parent::operator*=; + using parent::operator/=; + using parent::Zero; + using parent::Constant; + using parent::Random; + using parent::Identity; + + using parent::operator=; + + using stride_type = typename parent::stride_type; + + parent const& base() const { return static_cast(*this); } + parent& base() { return static_cast(*this); } + + template S, int R, int C, int O, int MR, int MC> + ref(matrix& m) + : parent(m.data(), m.rows(), m.cols(), strides(m)) + { + static_assert((O & 1) == Options, "ref: Incompatible storage layout"); + } + + 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"); + } + + 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"); + } + +// #if !defined(ROTGEN_FORCE_DYNAMIC) +// template +// ref(const Eigen::MatrixBase& b) +// : parent(b.data(), b.rows(), b.cols()/*, stride_type{b.outerStride(),b.innerStride()}*/) +// { +// using Str = typename parent::stride_type; +// std::cerr << "Stride compile-time: Outer=" << Str::OuterStrideAtCompileTime +// << " Inner=" << Str::InnerStrideAtCompileTime < + class ref : private map + { + public: + using parent = map; + using value_type = typename T::value_type; + using rotgen_tag = void; + + using parent::operator(); + using parent::rows; + using parent::cols; + using parent::size; + using parent::data; + using parent::sum; + using parent::prod; + using parent::mean; + using parent::trace; + using parent::maxCoeff; + using parent::minCoeff; + using parent::norm; + using parent::squaredNorm; + using parent::lpNorm; + using parent::operator+=; + using parent::operator-=; + using parent::operator*=; + using parent::operator/=; + using parent::Zero; + using parent::Constant; + using parent::Random; + using parent::Identity; + + using parent::operator=; + + using stride_type = typename parent::stride_type; + static constexpr bool has_static_storage = parent::has_static_storage; + + parent const& base() const { return static_cast(*this); } + + template S, int R, int C, int O, int MR, int MC> + ref(matrix const& m) + : parent(m.data(), m.rows(), m.cols(), strides(m)) + { + static_assert((O & 1) == Options, "ref: Incompatible storage layout"); + } + + 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"); + } + + 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"); + } + +// #if !defined(ROTGEN_FORCE_DYNAMIC) +// template +// ref(const Eigen::MatrixBase& b) +// : parent(b.data(), b.rows(), b.cols())//, stride_type{b.outerStride(),b.innerStride()}) +// { +// using Str = typename parent::stride_type; +// std::cerr << "Stride compile-time: Outer=" << Str::OuterStrideAtCompileTime +// << " Inner=" << Str::InnerStrideAtCompileTime < + ref(matrix&) -> ref>; + + template + ref(block& b) -> ref; + + template + ref(matrix const&) -> ref const>; + + template + ref(block const& b) -> ref; + + template + bool operator==(ref lhs, ref rhs) + { + return lhs.base() == rhs.base(); + } + + template + bool operator!=(ref lhs, ref rhs) + { + return lhs.base() != rhs.base(); + } + + template + auto operator+(ref lhs, ref rhs) -> decltype(lhs.base() + rhs.base()) + { + return lhs.base() + rhs.base(); + } + + template + auto operator-(ref lhs, ref rhs) + { + return lhs.base() - rhs.base(); + } + + template + auto operator*(ref lhs, ref rhs) + { + return lhs.base() * rhs.base(); + } + + template + auto operator*(ref lhs, std::convertible_to auto s) + { + return lhs.base() * s; + } + + template + auto operator*(std::convertible_to auto s, ref rhs) + { + return s * rhs.base(); + } + + template + auto operator/(ref lhs, std::convertible_to auto s) + { + return lhs.base() / s; + } + + template struct generalize; + + template + requires(std::is_arithmetic_v>) + struct generalize + { + using type = std::remove_cvref_t; + }; + + template + using generalize_t = typename generalize::type; + + template struct generalize + { + static constexpr bool is_const = std::is_const_v; + using base = matrix; + using type = std::conditional_t, ref>; + }; + + template + typename T::parent const& base_of(T const& a) + { + return a.base(); + } + + template + T base_of(T a) requires(std::is_arithmetic_v) + { + return a; + } + +#if !defined(ROTGEN_FORCE_DYNAMIC) + template struct generalize + { + static constexpr bool is_const = std::is_const_v; + using concrete_type = decltype(std::declval().eval()); + using base = matrix; + using type = std::conditional_t, ref>; + }; + + template + T const& base_of(T const& a) + { + return a; + } +#endif +} diff --git a/include/rotgen/common/strides.hpp b/include/rotgen/common/strides.hpp new file mode 100644 index 0000000..9a24878 --- /dev/null +++ b/include/rotgen/common/strides.hpp @@ -0,0 +1,37 @@ +//================================================================================================== +/* + ROTGEN - Runtime Overlay for Eigen + Copyright : CODE RECKONS + SPDX-License-Identifier: BSL-1.0 +*/ +//================================================================================================== +#pragma once + +#include +#include + +#if !defined(ROTGEN_FORCE_DYNAMIC) +#include +#endif + +namespace rotgen +{ +#if !defined(ROTGEN_FORCE_DYNAMIC) + using stride = Eigen::Stride<-1,-1>; +#else + struct stride { Index outer, inner; }; +#endif + + template + stride strides(Index r, Index c) + { + if constexpr (Order == RowMajor) return {c,1}; + else return {r,1}; + } + + template + auto strides(const E& e) + { + return strides(e.rows(), e.cols()); + } +} diff --git a/include/rotgen/common/traits.hpp b/include/rotgen/common/traits.hpp new file mode 100644 index 0000000..8d8df6a --- /dev/null +++ b/include/rotgen/common/traits.hpp @@ -0,0 +1,28 @@ +//================================================================================================== +/* + ROTGEN - Runtime Overlay for Eigen + Copyright : CODE RECKONS + SPDX-License-Identifier: BSL-1.0 +*/ +//================================================================================================== +#pragma once + +namespace rotgen +{ + template< typename EigenType + , template typename Wrapper + > + struct as_concrete + { + using type = Wrapper< typename EigenType::value_type + , EigenType::RowsAtCompileTime, EigenType::ColsAtCompileTime + , EigenType::Flags & 1 + , EigenType::MaxRowsAtCompileTime, EigenType::MaxColsAtCompileTime + >; + }; + + template typename Wrapper + > + using as_concrete_t = typename as_concrete,Wrapper>::type; +} \ No newline at end of file diff --git a/include/rotgen/concepts.hpp b/include/rotgen/concepts.hpp index 98539a7..ab2071c 100644 --- a/include/rotgen/concepts.hpp +++ b/include/rotgen/concepts.hpp @@ -9,10 +9,29 @@ namespace rotgen::concepts { + //================================================================================================ + //! @brief Check if a type is a ROTGEN type. + //================================================================================================ template concept entity = requires(T const&) { typename T::rotgen_tag; typename T::parent; }; + + //================================================================================================ + //! @brief Check if a type is an EIGEN type. + //================================================================================================ + template + concept eigen_compatible = requires(T const& a) + { + typename T::Scalar; + + { T::RowsAtCompileTime } -> std::convertible_to; + { T::ColsAtCompileTime } -> std::convertible_to; + { T::MaxRowsAtCompileTime } -> std::convertible_to; + { T::MaxColsAtCompileTime } -> std::convertible_to; + + { a.eval() }; + }; } \ No newline at end of file diff --git a/include/rotgen/config.hpp b/include/rotgen/config.hpp index de708f0..363b4d8 100644 --- a/include/rotgen/config.hpp +++ b/include/rotgen/config.hpp @@ -8,15 +8,15 @@ #pragma once #include -#include +#include namespace rotgen { using Index = std::ptrdiff_t; } -#if defined(ROTGEN_DISABLE_EXPRESSION_TEMPLATES) - #define ROTGEN_MAX_SIZE 0 +#if !defined(ROTGEN_MAX_SIZE) && defined(ROTGEN_ENABLE_EXPRESSION_TEMPLATES) +#define ROTGEN_MAX_SIZE 0 #endif #if !defined(ROTGEN_FORCE_DYNAMIC) @@ -33,10 +33,19 @@ namespace rotgen namespace rotgen { +#if defined(ROTGEN_ENABLE_EXPRESSION_TEMPLATES) + inline constexpr bool use_expression_templates = true; +#else + inline constexpr bool use_expression_templates = false; +#endif + inline constexpr bool has_static_limit = ROTGEN_HAS_STATIC_LIMIT; inline constexpr bool is_forcing_dynamic_status = !has_static_limit; - std::ostream& setup_summary(std::ostream& os); + namespace detail + { + std::ostream& dynamic_info(std::ostream& os); + } } #if defined(ROTGEN_FORCE_DYNAMIC) @@ -51,12 +60,37 @@ namespace rotgen namespace rotgen { inline constexpr Index max_static_size = ROTGEN_MAX_SIZE; - template - inline constexpr bool storage_status = (Rows > 0 && Cols > 0) && ((Rows*Cols) <= max_static_size); + + template + inline constexpr bool storage_status = + []() + { + // Actual static size + if(Rows > 0 && Cols > 0) return (Rows*Cols) <= max_static_size; + // Dynamic size but static Max Size + else if(MaxRows > 0 && MaxCols > 0) return (MaxRows*MaxCols) <= max_static_size; + // Everything dynamic already + else return false; + }(); } #endif namespace rotgen { - inline constexpr bool use_expression_templates = max_static_size > 0; -} \ No newline at end of file + inline std::ostream& setup_summary(std::ostream& os) + { + detail::dynamic_info(os); + if(!is_forcing_dynamic_status) + { + if constexpr(use_expression_templates) + os << "[ROTGEN] - Expression templates : Enabled." << std::endl; + else + os << "[ROTGEN] - Expression templates : Disabled." << std::endl; + + if constexpr(rotgen::max_static_size) + os << "[ROTGEN] - Static/Dynamic mode with maximum size: " << rotgen::max_static_size << std::endl; + } + + return os; + } +} diff --git a/include/rotgen/dynamic/block.hpp b/include/rotgen/dynamic/block.hpp index 009eba3..abeb6ee 100644 --- a/include/rotgen/dynamic/block.hpp +++ b/include/rotgen/dynamic/block.hpp @@ -23,14 +23,30 @@ namespace rotgen , "[ROTGEN][CRITICAL] - Block of non-rotgen type instanciated" ); - using parent = find_block; + using parent = find_block; using rotgen_tag = void; - using scalar_type = typename Ref::scalar_type; + using value_type = typename Ref::value_type; static constexpr int storage_order = (ForceStorageOrder == -1) ? Ref::storage_order : ForceStorageOrder; - using concrete_type = matrix; + 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 bool is_defined_static = false; + static constexpr bool has_static_storage = false; + + using parent::operator=; + block& operator=(concepts::entity auto const& other) + { + 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; + } 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) {} @@ -41,6 +57,30 @@ namespace rotgen 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) + { + assert(is_contiguous_linear()); + return parent::operator()(i); + } + + value_type operator()(Index i, Index j) const { return parent::operator()(i,j); } + + value_type operator()(Index i) const + { + assert(is_contiguous_linear()); + return parent::operator()(i); + } + concrete_type transpose() const { return concrete_type(static_cast(*this).transpose()); @@ -67,13 +107,13 @@ namespace rotgen block& operator+=(block const& rhs) { - static_cast(*this) += static_cast(rhs); + base() += static_cast(rhs); return *this; } block& operator-=(block const& rhs) { - static_cast(*this) -= static_cast(rhs); + base() -= static_cast(rhs); return *this; } @@ -82,46 +122,21 @@ namespace rotgen return concrete_type(static_cast(*this).operator-()); } - concrete_type matrix_addition(block const& rhs) const - { - return concrete_type(static_cast(*this).matrix_addition(rhs)); - } - - concrete_type matrix_subtraction(block const& rhs) const - { - return concrete_type(static_cast(*this).matrix_subtraction(rhs)); - } - - concrete_type matrix_multiplication(block const& rhs) const - { - return concrete_type(static_cast(*this).matrix_multiplication(rhs)); - } - - concrete_type matrix_multiplication(scalar_type rhs) const - { - return concrete_type(static_cast(*this).matrix_multiplication(rhs)); - } - - concrete_type matrix_division(scalar_type rhs) const - { - return concrete_type(static_cast(*this).matrix_division(rhs)); - } - block& operator*=(block const& rhs) { - static_cast(*this) *= static_cast(rhs); + base() *= static_cast(rhs); return *this; } - block& operator*=(scalar_type rhs) + block& operator*=(value_type rhs) { - static_cast(*this) *= rhs; + base() *= rhs; return *this; } - block& operator/=(scalar_type rhs) + block& operator/=(value_type rhs) { - static_cast(*this) /= rhs; + base() /= rhs; return *this; } @@ -138,13 +153,26 @@ namespace rotgen return parent::Zero(rows, cols); } - static concrete_type Constant(scalar_type value) + static concrete_type Ones() + requires (Rows != -1 && Cols != -1) + { + return parent::Ones(Rows, Cols); + } + + static concrete_type Ones(int rows, int cols) + { + if constexpr(Rows != -1) assert(rows == Rows && "Mismatched between dynamic and static row size"); + if constexpr(Cols != -1) assert(cols == Cols && "Mismatched between dynamic and static column size"); + return parent::Ones(rows, cols); + } + + static concrete_type Constant(value_type value) requires (Rows != -1 && Cols != -1) { return parent::Constant(Rows, Cols, static_cast(value)); } - static concrete_type Constant(int rows, int cols, scalar_type value) + static concrete_type Constant(int rows, int cols, value_type value) { if constexpr(Rows != -1) assert(rows == Rows && "Mismatched between dynamic and static row size"); if constexpr(Cols != -1) assert(cols == Cols && "Mismatched between dynamic and static column size"); @@ -177,47 +205,86 @@ namespace rotgen return parent::Identity(rows, cols); } + block& setOnes() + { + parent::assign(parent::Ones(parent::rows(), parent::cols())); + return *this; + } + + block& setZero() + { + parent::assign(parent::Zero(parent::rows(), parent::cols())); + return *this; + } + + block& setConstant(value_type value) + { + parent::assign(parent::Constant(parent::rows(), parent::cols(), value)); + return *this; + } + + block& setRandom() + { + parent::assign(parent::Random(parent::rows(), parent::cols())); + return *this; + } + + block& setIdentity() + { + parent::assign(parent::Identity(parent::rows(), parent::cols())); + return *this; + } + template double lpNorm() const { assert(P == 1 || P == 2 || P == Infinity); return parent::lpNorm(P); } + + parent& base() { return static_cast(*this); } + parent const& base() const { return static_cast(*this); } }; template - typename block::concrete_type operator+(block const& lhs, block const& rhs) + auto operator+(block const& lhs, block const& rhs) { - return lhs.matrix_addition(rhs); + using concrete_type = typename block::concrete_type; + return concrete_type(lhs.base().add(rhs)); } template - typename block::concrete_type operator-(block const& lhs, block const& rhs) + auto operator-(block const& lhs, block const& rhs) { - return lhs.matrix_subtraction(rhs); + using concrete_type = typename block::concrete_type; + return concrete_type(lhs.base().sub(rhs)); } template - typename block::concrete_type operator*(block const& lhs, block const& rhs) + auto operator*(block const& lhs, block const& rhs) { - return lhs.matrix_multiplication(rhs); + using concrete_type = typename block::concrete_type; + return concrete_type(lhs.base().mul(rhs)); } template - typename block::concrete_type operator*(block const& lhs, double rhs) + auto operator*(block const& lhs, double rhs) { - return lhs.matrix_multiplication(rhs); + using concrete_type = typename block::concrete_type; + return concrete_type(lhs.base().mul(rhs)); } template - typename block::concrete_type operator*(double lhs, block const& rhs) + auto operator*(double lhs, block const& rhs) { - return rhs.matrix_multiplication(lhs); + using concrete_type = typename block::concrete_type; + return concrete_type(rhs.base().mul(lhs)); } template - typename block::concrete_type operator/(block const& lhs, double rhs) + auto operator/(block const& lhs, double rhs) { - return lhs.matrix_division(rhs); + 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 new file mode 100644 index 0000000..3968db2 --- /dev/null +++ b/include/rotgen/dynamic/map.hpp @@ -0,0 +1,280 @@ +//================================================================================================== +/* + ROTGEN - Runtime Overlay for Eigen + Copyright : CODE RECKONS + SPDX-License-Identifier: BSL-1.0 +*/ +//================================================================================================== +#pragma once + +#include +#include +#include + +namespace rotgen +{ + template + class map : public find_map + { + public: + + static_assert ( concepts::entity + , "[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; + + static constexpr bool is_immutable = std::is_const_v; + static constexpr bool is_defined_static = false; + + using ptr_type = std::conditional_t; + using stride_type = stride; + + static constexpr Index RowsAtCompileTime = Ref::RowsAtCompileTime; + static constexpr Index ColsAtCompileTime = Ref::ColsAtCompileTime; + + map(ptr_type ptr, Index r, Index c, stride_type s) : parent(ptr, r, c,s) {} + map(ptr_type ptr, Index r, Index c) : map(ptr, r, c, strides(r,c)) {} + + map(ptr_type ptr, stride_type s) requires(RowsAtCompileTime!=-1 && ColsAtCompileTime!=-1) + : parent(ptr,RowsAtCompileTime,ColsAtCompileTime, s) + {} + + map(ptr_type ptr, Index size) requires(RowsAtCompileTime==1 || ColsAtCompileTime==1) + : map( ptr, RowsAtCompileTime==1?1:size, ColsAtCompileTime==1?1:size) + {} + + map(ptr_type ptr) requires(RowsAtCompileTime!=-1 && ColsAtCompileTime!=-1) + : map( ptr, RowsAtCompileTime, ColsAtCompileTime ) + {} + + template + map(map const& other) : map ( other.data(), other.rows(), other.cols() + , stride{other.outerStride(),other.innerStride()} + ) + {} + + map(parent const& base) : parent(base) {} + + map(map const& other) : parent(other) + {} + + map& operator=(map const& other) requires(!is_immutable) + { + base() = static_cast(*other); + 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) + { + assert( parent::innerStride() == 1 + && parent::outerStride() ==(storage_order == RowMajor ? parent::cols() : parent::rows()) + ); + return parent::operator()(i); + } + + value_type operator()(Index i, Index j) const { return parent::operator()(i,j); } + value_type operator()(Index i) const + { + assert( parent::innerStride() == 1 + && parent::outerStride() ==(storage_order == RowMajor ? parent::cols() : parent::rows()) + ); + return parent::operator()(i); + } + + concrete_type transpose() const + { + return concrete_type(static_cast(*this).transpose()); + } + + concrete_type conjugate() const + { + return concrete_type(static_cast(*this).conjugate()); + } + + concrete_type adjoint() const + { + return concrete_type(static_cast(*this).adjoint()); + } + + void transposeInPlace() requires(!is_immutable) { parent::transposeInPlace(); } + void adjointInPlace() requires(!is_immutable) { parent::adjointInPlace(); } + + map& operator+=(map const& rhs) requires(!is_immutable) + { + base() += static_cast(rhs); + return *this; + } + + map& operator-=(map const& rhs) requires(!is_immutable) + { + base() -= static_cast(rhs); + return *this; + } + + concrete_type operator-() const + { + return concrete_type(base().operator-()); + } + + map& operator*=(map const& rhs) requires(!is_immutable) + { + base() *= static_cast(rhs); + return *this; + } + + map& operator*=(value_type rhs) requires(!is_immutable) + { + base() *= rhs; + return *this; + } + + map& operator/=(value_type rhs) requires(!is_immutable) + { + base() /= rhs; + return *this; + } + + static auto Zero() requires( requires {Ref::Zero();} ) + { + return Ref::Zero(); + } + + static auto Zero(int rows, int cols) + { + return Ref::Zero(rows,cols); + } + + static auto Constant(value_type value) requires( requires {Ref::Constant(value);} ) + { + return Ref::Constant(value); + } + + static auto Constant(int rows, int cols, value_type value) + { + return Ref::Constant(rows, cols, value); + } + + static auto Random() requires( requires {Ref::Random();} ) + { + return Ref::Random(); + } + + static auto Random(int rows, int cols) + { + return Ref::Random(rows, cols); + } + + static auto Identity() requires( requires {Ref::Identity();} ) + { + return Ref::Identity(); + } + + static auto Identity(int rows, int cols) + { + return Ref::Identity(rows, cols); + } + + map& setZero() requires(!is_immutable) + { + parent::setZero(); + return *this; + } + + map& setOnes() requires(!is_immutable) + { + parent::setOnes(); + return *this; + } + + map& setIdentity() requires(!is_immutable) + { + parent::setIdentity(); + return *this; + } + + map& setRandom() requires(!is_immutable) + { + parent::setRandom(); + return *this; + } + + map& setConstant(value_type s) requires(!is_immutable) + { + parent::setConstant(s); + return *this; + } + + template + double lpNorm() const + { + assert(P == 1 || P == 2 || P == Infinity); + return parent::lpNorm(P); + } + + parent& base() { return static_cast(*this); } + parent const& base() const { return static_cast(*this); } + }; + + template + typename map::concrete_type operator+(map const& lhs, map const& rhs) + { + using concrete_type = typename map::concrete_type; + return concrete_type(lhs.base().add(map(rhs))); + } + + template + typename map::concrete_type operator-(map const& lhs, map const& rhs) + { + using concrete_type = typename map::concrete_type; + return concrete_type(lhs.base().sub(map(rhs))); + } + + template + typename map::concrete_type operator*(map const& lhs, map const& rhs) + { + using concrete_type = typename map::concrete_type; + return concrete_type(lhs.base().mul(map(rhs))); + } + + template + typename map::concrete_type + operator*(map const& lhs, std::convertible_to auto s) + { + using concrete_type = typename map::concrete_type; + return concrete_type(lhs.base().mul(s)); + } + + template + typename map::concrete_type + operator*(std::convertible_to auto s, map const& rhs) + { + using concrete_type = typename map::concrete_type; + return concrete_type(rhs.base().mul(s)); + } + + template + typename map::concrete_type + operator/(map const& lhs, std::convertible_to auto s) + { + using concrete_type = typename map::concrete_type; + return concrete_type(lhs.base().div(s)); + } + + template + bool operator==(map const& lhs, map const& rhs) + { + return lhs.base() == rhs.base(); + } + template + bool operator!=(map const& lhs, map const& rhs) + { + return lhs.base() != rhs.base(); + } +} \ No newline at end of file diff --git a/include/rotgen/dynamic/matrix.hpp b/include/rotgen/dynamic/matrix.hpp index 65669c9..b1aae1c 100644 --- a/include/rotgen/dynamic/matrix.hpp +++ b/include/rotgen/dynamic/matrix.hpp @@ -15,20 +15,23 @@ namespace rotgen { template< typename Scalar , int Rows = Dynamic , int Cols = Dynamic - , int Options = ColMajor + , int Opts = ColMajor , int MaxRows = Rows , int MaxCols = Cols > - class matrix : public find_matrix + class matrix : public find_matrix { public: - using parent = find_matrix; + using parent = find_matrix; using rotgen_tag = void; using concrete_type = matrix; - using scalar_type = Scalar; - static constexpr auto storage_order = Options & 1; + using value_type = Scalar; + static constexpr auto storage_order = Opts & 1; - static constexpr int RowsAtCompileTime = Rows; - static constexpr int ColsAtCompileTime = Cols; + 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; matrix() : parent(Rows==-1?0:Rows,Cols==-1?0:Cols) {} @@ -57,6 +60,15 @@ namespace rotgen : parent(Rows, Cols, {s0,static_cast(init)...}) {} + matrix(concepts::entity auto const& e) : parent(e.rows(),e.cols()) + { + 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"); + for (rotgen::Index r = 0; r < e.rows(); ++r) + for (rotgen::Index c = 0; c < e.cols(); ++c) + (*this)(r, c) = e(r, c); + } + void resize(int new_rows, int new_cols) requires(Rows == -1 && Cols == -1) { parent::resize(new_rows, new_cols); @@ -69,17 +81,17 @@ namespace rotgen matrix transpose() const { - return matrix(static_cast(*this).transpose()); + return matrix(base().transpose()); } matrix conjugate() const { - return matrix(static_cast(*this).conjugate()); + return matrix(base().conjugate()); } matrix adjoint() const { - return matrix(static_cast(*this).adjoint()); + return matrix(base().adjoint()); } void transposeInPlace() { parent::transposeInPlace(); } @@ -92,39 +104,51 @@ namespace rotgen matrix& operator+=(matrix const& rhs) { - static_cast(*this) += static_cast(rhs); + base() += static_cast(rhs); return *this; } matrix& operator-=(matrix const& rhs) { - static_cast(*this) -= static_cast(rhs); + base() -= static_cast(rhs); return *this; } matrix operator-() const { - return matrix(static_cast(*this).operator-()); + return matrix(base().operator-()); } matrix& operator*=(matrix const& rhs) { - static_cast(*this) *= static_cast(rhs); + base() *= static_cast(rhs); return *this; } matrix& operator*=(Scalar rhs) { - static_cast(*this) *= rhs; + base() *= rhs; return *this; } matrix& operator/=(Scalar rhs) { - static_cast(*this) /= rhs; + base() /= rhs; return *this; } + static matrix Ones() requires (Rows != -1 && Cols != -1) + { + return parent::Ones(Rows, Cols); + } + + static matrix Ones(int rows, int cols) + { + if constexpr(Rows != -1) assert(rows == Rows && "Mismatched between dynamic and static row size"); + if constexpr(Cols != -1) assert(cols == Cols && "Mismatched between dynamic and static column size"); + return parent::Ones(rows, cols); + } + static matrix Zero() requires (Rows != -1 && Cols != -1) { return parent::Zero(Rows, Cols); @@ -173,6 +197,66 @@ namespace rotgen return parent::Identity(rows, cols); } + matrix& setOnes() + { + *this = parent::Ones(Rows, Cols); + return *this; + } + + matrix& setOnes(int rows, int cols) + { + *this = parent::Ones(rows, cols); + return *this; + } + + matrix& setZero() + { + *this = parent::Zero(Rows, Cols); + return *this; + } + + matrix& setZero(int rows, int cols) + { + *this = parent::Zero(rows, cols); + return *this; + } + + matrix& setConstant(Scalar value) + { + *this = parent::Constant(Rows, Cols, static_cast(value)); + return *this; + } + + matrix& setConstant(int rows, int cols, Scalar value) + { + *this = parent::Constant(rows, cols, static_cast(value)); + return *this; + } + + matrix& setRandom() + { + *this = parent::Random(Rows, Cols); + return *this; + } + + matrix& setRandom(int rows, int cols) + { + *this = parent::Random(rows, cols); + return *this; + } + + matrix& setIdentity() + { + *this = parent::Identity(Rows, Cols); + return *this; + } + + matrix& setIdentity(int rows, int cols) + { + *this = parent::Identity(rows, cols); + return *this; + } + template Scalar lpNorm() const { @@ -180,6 +264,8 @@ namespace rotgen return parent::lp_norm(P); } + parent& base() { return static_cast(*this); } + parent const& base() const { return static_cast(*this);; } }; template @@ -204,20 +290,20 @@ namespace rotgen } template - matrix operator*(matrix const& lhs, S rhs) + matrix operator*(matrix const& lhs, double rhs) { matrix that(lhs); return that *= rhs; } template - matrix operator*(S lhs, matrix const& rhs) + matrix operator*(double lhs, matrix const& rhs) { return rhs * lhs; } template - matrix operator/(matrix const& lhs, S rhs) + matrix operator/(matrix const& lhs, double rhs) { matrix that(lhs); return that /= rhs; diff --git a/include/rotgen/fixed/block.hpp b/include/rotgen/fixed/block.hpp index b8ea489..6dbaad5 100644 --- a/include/rotgen/fixed/block.hpp +++ b/include/rotgen/fixed/block.hpp @@ -8,7 +8,6 @@ #pragma once #include -#include #include #include @@ -17,15 +16,15 @@ namespace rotgen namespace detail { template - using block_type = std::conditional_t < storage_status + using block_type = std::conditional_t < storage_status , Eigen::Block , Eigen::Block >; } template< typename Ref - , int Rows = Dynamic, int Cols = Dynamic - , bool Inner = false, int ForceStorageOrder = -1 + , int Rows = Dynamic, int Cols = Dynamic + , bool Inner = false , int ForceStorageOrder = -1 > class block : private detail::block_type { @@ -37,21 +36,21 @@ namespace rotgen using rotgen_tag = void; using parent = detail::block_type; using value_type = typename parent::value_type; - using scalar_type = typename parent::value_type; using Index = typename parent::Index; static constexpr int storage_order = (ForceStorageOrder == -1) ? Ref::storage_order : ForceStorageOrder; - using concrete_type = matrix; - using concrete_dynamic_type = matrix; + using concrete_type = matrix; + using concrete_dynamic_type = matrix; template using as_concrete_type = as_concrete_t; - static constexpr int RowsAtCompileTime = Rows; - static constexpr int ColsAtCompileTime = Cols; - - private: - static constexpr bool has_static_storage = storage_status; + static constexpr auto Flags = Ref::Flags; + static constexpr int Options = Ref::Options; + static constexpr int RowsAtCompileTime = Rows; + static constexpr int ColsAtCompileTime = Cols; + static constexpr bool is_defined_static = Rows!=-1 && Cols!=-1; + static constexpr bool has_static_storage = storage_status; public: @@ -67,6 +66,10 @@ namespace rotgen : parent(r.base(),i0,j0,Rows,Cols) {} + template + block(block const& other) : parent(other.base()) + {} + template block(const Eigen::MatrixBase& other) : parent(other) {} @@ -90,34 +93,38 @@ namespace rotgen parent& base() { return static_cast(*this); } parent const& base() const { return static_cast(*this); } - concrete_type transpose() const + + auto transpose() const { - return concrete_type(static_cast(*this).transpose()); + auto res = static_cast(*this).transpose(); + return as_concrete_type(res); } - concrete_type conjugate() const + auto conjugate() const { - return concrete_type(static_cast(*this).conjugate()); + auto res = static_cast(*this).conjugate(); + return as_concrete_type(res); } - concrete_type adjoint() const + auto adjoint() const { - return concrete_type(static_cast(*this).adjoint()); + auto res = static_cast(*this).adjoint(); + return as_concrete_type(res); } void transposeInPlace() { parent::transposeInPlace(); } void adjointInPlace() { parent::adjointInPlace(); } - static concrete_type Constant(scalar_type value) requires (Rows != -1 && Cols != -1) + static concrete_type Constant(value_type value) requires (Rows != -1 && Cols != -1) { - return parent::Constant(Rows, Cols, static_cast(value)); + return parent::Constant(Rows, Cols, static_cast(value)); } - static concrete_type Constant(int rows, int cols, scalar_type value) + static concrete_type Constant(int rows, int cols, value_type value) { if constexpr(Rows != -1) assert(rows == Rows && "Mismatched between dynamic and static row size"); if constexpr(Cols != -1) assert(cols == Cols && "Mismatched between dynamic and static column size"); - return parent::Constant(rows, cols, static_cast(value)); + return parent::Constant(rows, cols, static_cast(value)); } static concrete_type Identity() requires (Rows != -1 && Cols != -1) @@ -144,6 +151,18 @@ namespace rotgen return parent::Zero(rows, cols); } + static concrete_type Ones() requires (Rows != -1 && Cols != -1) + { + return parent::Ones(Rows, Cols); + } + + static concrete_type Ones(int rows, int cols) + { + if constexpr(Rows != -1) assert(rows == Rows && "Mismatched between dynamic and static row size"); + if constexpr(Cols != -1) assert(cols == Cols && "Mismatched between dynamic and static column size"); + return parent::Ones(rows, cols); + } + static concrete_type Random() requires (Rows != -1 && Cols != -1) { return parent::Random(Rows, Cols); @@ -156,14 +175,98 @@ namespace rotgen return parent::Random(rows, cols); } + block& setOnes() + { + *this = parent::Ones(rows(), cols()); + return *this; + } + + block& setOnes(int r, int c) + { + *this = parent::Ones(r, c); + return *this; + } + + block& setZero() + { + *this = parent::Zero(rows(), cols()); + return *this; + } + + block& setZero(int r, int c) + { + *this = parent::Zero(r,c); + return *this; + } + + block& setConstant(value_type value) + { + *this = parent::Constant(rows(), cols(), value); + return *this; + } + + block& setConstant(int r, int c, value_type value) + { + *this = parent::Constant(r,c, value); + return *this; + } + + block& setRandom() + { + *this = parent::Random(rows(),cols()); + return *this; + } + + block& setRandom(int r, int c) + { + *this = parent::Random(r,c); + return *this; + } + + block& setIdentity() + { + *this = parent::Identity(rows(),cols()); + return *this; + } + + block& setIdentity(int r, int c) + { + *this = parent::Identity(r,c); + return *this; + } + template - scalar_type lpNorm() const + value_type lpNorm() const { static_assert(P == 1 || P == 2 || P == Infinity); return parent::template lpNorm

(); } - using parent::operator(); + 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 base()(i,j); } + value_type operator()(Index i, Index j) const { return base()(i,j); } + + value_type& operator()(Index i) + { + assert(is_contiguous_linear()); + return base().data()[i]; + } + + value_type operator()(Index i) const + { + assert(is_contiguous_linear()); + return base().data()[i]; + } + + using parent::innerStride; + using parent::outerStride; using parent::rows; using parent::cols; using parent::size; @@ -200,25 +303,16 @@ namespace rotgen return *this; } - block& operator*=(scalar_type rhs) + block& operator*=(value_type rhs) { static_cast(*this) *= rhs; return *this; } - block& operator/=(scalar_type rhs) + block& operator/=(value_type rhs) { static_cast(*this) /= rhs; return *this; } - - static void print_storage_info() - { - std::cout << "Block " << Rows << "x" << Cols - << " - Storage: " << (has_static_storage ? "Static" : "Dynamic") - << " (from: "; - Ref::print_storage_info(); - std::cout << ")" << std::endl; - } }; } \ No newline at end of file diff --git a/include/rotgen/fixed/common.hpp b/include/rotgen/fixed/common.hpp deleted file mode 100644 index 7c741f0..0000000 --- a/include/rotgen/fixed/common.hpp +++ /dev/null @@ -1,86 +0,0 @@ -//================================================================================================== -/* - ROTGEN - Runtime Overlay for Eigen - Copyright : CODE RECKONS - SPDX-License-Identifier: BSL-1.0 -*/ -//================================================================================================== -#pragma once - -#include -#include -#include - -namespace rotgen -{ - template typename Wrapper - > - struct as_concrete - { - using type = Wrapper< typename EigenType::value_type - , EigenType::RowsAtCompileTime, EigenType::ColsAtCompileTime - , EigenType::Flags - , EigenType::MaxRowsAtCompileTime, EigenType::MaxColsAtCompileTime - >; - }; - - template typename Wrapper - > - using as_concrete_t = typename as_concrete::type; - - template - bool operator==(E1 const& lhs, E2 const& rhs) - { - return lhs.base() == rhs.base(); - } - - template - std::ostream& operator<<(std::ostream& os, E const& arg) - { - return os << arg.base(); - } - - template - auto operator+(E1 const& lhs, E2 const& rhs) - { - using type = E1::template as_concrete_type; - return type(lhs.base() + rhs.base()); - } - - template - auto operator-(E1 const& lhs, E2 const& rhs) - { - using type = E1::template as_concrete_type; - return type(lhs.base() - rhs.base()); - } - - template - auto operator*(E1 const& lhs, E2 const& rhs) - { - using type = typename E1::concrete_dynamic_type; - return type(lhs.base() * rhs.base()); - } - - template S> - auto operator*(E const& lhs, S rhs) - { - using type = E::template as_concrete_type; - return type(lhs.base() * rhs); - } - - template S> - auto operator*(S lhs, E const& rhs ) - { - using type = E::template as_concrete_type; - return type(lhs * rhs.base()); - } - - template S> - auto operator/(E const& lhs, S rhs) - { - using type = E::template as_concrete_type; - return type(lhs.base() / rhs); - } -} \ No newline at end of file diff --git a/include/rotgen/fixed/map.hpp b/include/rotgen/fixed/map.hpp new file mode 100644 index 0000000..87b1d63 --- /dev/null +++ b/include/rotgen/fixed/map.hpp @@ -0,0 +1,328 @@ +//================================================================================================== +/* + ROTGEN - Runtime Overlay for Eigen + Copyright : CODE RECKONS + SPDX-License-Identifier: BSL-1.0 +*/ +//================================================================================================== +#pragma once + +#include +#include +#include + +namespace rotgen +{ + namespace detail + { + template + struct compute_map_type + { + using base = Eigen::Matrix< typename Ref::value_type + , Ref::RowsAtCompileTime, Ref::ColsAtCompileTime + , Ref::storage_order + >; + + using ref_t = std::conditional_t; + using type = Eigen::Map>; + }; + + template + using map_type = typename compute_map_type::type; + + template struct map_stride; + + template + struct map_stride> + { + using type = Stride; + }; + } + + template + class map : private detail::map_type, Options, std::is_const_v> + { + public: + using rotgen_tag = void; + using parent = detail::map_type, Options, std::is_const_v>; + using value_type = typename std::remove_const_t::value_type; + using concrete_type = typename std::remove_const_t::concrete_type; + + static constexpr auto Flags = Ref::Flags; + static constexpr Index RowsAtCompileTime = Ref::RowsAtCompileTime; + static constexpr Index ColsAtCompileTime = Ref::ColsAtCompileTime; + static constexpr bool has_static_storage = Ref::has_static_storage; + static constexpr int storage_order = Ref::storage_order; + static constexpr bool is_immutable = std::is_const_v; + static constexpr bool is_defined_static = Ref::is_defined_static; + + template + using as_concrete_type = as_concrete_t; + + using ptr_type = std::conditional_t; + using stride_type = typename detail::map_stride::type; + + map(const map&) = default; + map(map&&) = default; + map& operator=(const map&) = default; + map& operator=(map&&) = default; + + map(ptr_type ptr, Index r, Index c, stride_type s) : parent(ptr, r, c, s) {} + map(ptr_type ptr, Index r, Index c) : map(ptr, r, c, strides(r,c)) {} + + map(ptr_type ptr, stride_type s) requires(RowsAtCompileTime!=-1 && ColsAtCompileTime!=-1) + : parent(ptr, s) + {} + + map(ptr_type ptr, Index sz) requires(RowsAtCompileTime==1 || ColsAtCompileTime==1) + : map(ptr, RowsAtCompileTime==1?1:sz, ColsAtCompileTime==1?1:sz) + {} + + map(ptr_type ptr) requires(RowsAtCompileTime!=-1 && ColsAtCompileTime!=-1) + : map( ptr, RowsAtCompileTime, ColsAtCompileTime ) + {} + + parent& base() { return static_cast(*this); } + parent const& base() const { return static_cast(*this); } + + value_type& operator()(Index i, Index j) { return base()(i, j); } + value_type operator()(Index i, Index j) const { return base()(i, j); } + + value_type& operator()(Index i) requires(!is_immutable) + { + assert(is_contiguous_linear()); + return base().data()[i]; + } + + value_type operator()(Index i) const + { + assert(is_contiguous_linear()); + return base().data()[i]; + } + + map& operator+=(map const& rhs) + { + base() += rhs.base(); + return *this; + } + + map& operator-=(map const& rhs) + { + base() -= rhs.base(); + return *this; + } + + map& operator*=(map const& rhs) + { + base() *= rhs; + return *this; + } + + map& operator*=(value_type rhs) + { + base() *= rhs; + return *this; + } + + map& operator/=(value_type rhs) + { + base() /= rhs; + return *this; + } + + auto transpose() const + { + if constexpr(use_expression_templates) return base().transpose(); + else return as_concrete_type(base().transpose()); + } + + auto adjoint() const + { + if constexpr(use_expression_templates) return base().adjoint(); + else return as_concrete_type(base().adjoint()); + } + + auto conjugate() const + { + if constexpr(use_expression_templates) return base().conjugate(); + else return as_concrete_type(base().conjugate()); + } + + void transposeInPlace() { base().transposeInPlace(); } + void adjointInPlace() { base().adjointInPlace(); } + + static auto Zero() requires( requires {Ref::Zero();} ) { return Ref::Zero(); } + static auto Zero(int rows, int cols) { return Ref::Zero(rows,cols); } + + static auto Ones() requires( requires {Ref::Ones();} ) { return Ref::Ones(); } + static auto Ones(int rows, int cols) { return Ref::Ones(rows,cols); } + + static auto Constant(value_type value) requires( requires {Ref::Constant(value);} ) + { return Ref::Constant(value); } + + static auto Constant(int rows, int cols, value_type value) { return Ref::Constant(rows, cols, value); } + + static auto Random() requires( requires {Ref::Random();} ) { return Ref::Random(); } + static auto Random(int rows, int cols) { return Ref::Random(rows, cols); } + + static auto Identity() requires( requires {Ref::Identity();} ) { return Ref::Identity(); } + static auto Identity(int rows, int cols) { return Ref::Identity(rows, cols); } + + map& setOnes() + { + base() = parent::Ones(base().rows(), base().cols()); + return *this; + } + + map& setZero() + { + base() = parent::Zero(base().rows(), base().cols()); + return *this; + } + + map& setConstant(value_type value) + { + base() = parent::Constant(base().rows(), base().cols(), value); + return *this; + } + + map& setRandom() + { + base() = parent::Random(base().rows(), base().cols()); + return *this; + } + + map& setIdentity() + { + base() = parent::Identity(base().rows(), base().cols()); + return *this; + } + + bool is_contiguous_linear() const + { + if(base().innerStride() != 1) return false; + if constexpr(storage_order == rotgen::RowMajor) return base().outerStride() == base().cols(); + else return base().outerStride() == base().rows(); + } + + using parent::innerStride; + using parent::outerStride; + using parent::rows; + using parent::cols; + using parent::size; + using parent::data; + using parent::sum; + using parent::mean; + using parent::prod; + using parent::trace; + using parent::maxCoeff; + using parent::minCoeff; + using parent::norm; + using parent::squaredNorm; + + template value_type lpNorm() const + { + static_assert(P == 1 || P == 2 || P == Infinity); + return parent::template lpNorm

(); + } + }; + + template + bool operator==(map const& lhs, map const& rhs) + { + return lhs.base() == rhs.base(); + } + + template + bool operator!=(map const& lhs, map const& rhs) + { + return lhs.base() != rhs.base(); + } + +#if defined(ROTGEN_ENABLE_EXPRESSION_TEMPLATES) + template + auto operator+(map const& lhs, map const& rhs) + { + return lhs.base() + rhs.base(); + } + + template + auto operator-(map const& lhs, map const& rhs) + { + return lhs.base() - rhs.base(); + } + + template + auto operator*(map const& lhs, map const& rhs) + { + return lhs.base() * rhs.base(); + } + + template + auto operator*( map const& lhs, std::convertible_to auto s) + { + return lhs.base() * s; + } + + template + auto operator*(std::convertible_to auto s, map const& rhs) + { + return s * rhs.base(); + } + + template + auto operator/(map const& lhs, std::convertible_to auto s) + { + return lhs.base() / s; + } +#else + template + typename map::concrete_type operator+(map const& lhs, map const& rhs) + { + using concrete_type = typename map::concrete_type; + return concrete_type(lhs.base() + rhs.base()); + } + + template + typename map::concrete_type operator-(map const& lhs, map const& rhs) + { + using concrete_type = typename map::concrete_type; + return concrete_type(lhs.base() - rhs.base()); + } + + template + typename map::concrete_type operator*(map const& lhs, map const& rhs) + { + using concrete_type = typename map::concrete_type; + return concrete_type(lhs.base() * rhs.base()); + } + + template + typename map::concrete_type operator*( map const& lhs + , std::convertible_to auto s + ) + { + using concrete_type = typename map::concrete_type; + return concrete_type(lhs.base() * s); + } + + template + typename map::concrete_type operator*( std::convertible_to auto s + , map const& rhs + ) + { + using concrete_type = typename map::concrete_type; + return concrete_type(rhs.base() * s); + } + + template + typename map::concrete_type operator/( map const& lhs + , std::convertible_to auto s + ) + { + using concrete_type = typename map::concrete_type; + return concrete_type(lhs.base() / s); + } +#endif + +} diff --git a/include/rotgen/fixed/matrix.hpp b/include/rotgen/fixed/matrix.hpp index f130842..63fefda 100644 --- a/include/rotgen/fixed/matrix.hpp +++ b/include/rotgen/fixed/matrix.hpp @@ -8,7 +8,6 @@ #pragma once #include -#include #include #include @@ -17,7 +16,7 @@ namespace rotgen namespace detail { template - using storage_type = std::conditional_t < storage_status + using storage_type = std::conditional_t < storage_status , Eigen::Matrix , Eigen::Matrix >; @@ -25,27 +24,31 @@ namespace rotgen template< typename Scalar , int Rows = Dynamic , int Cols = Dynamic - , int Options = ColMajor + , int Opts = ColMajor , int MaxRows = Rows , int MaxCols = Cols > - class matrix : private detail::storage_type + class matrix : private detail::storage_type { public: - using rotgen_tag = void; - using parent = detail::storage_type; + using rotgen_tag = void; + using parent = detail::storage_type; using value_type = Scalar; - using scalar_type = Scalar; using Index = typename parent::Index; - static constexpr auto storage_order = Options & 1; + static constexpr auto storage_order = Opts & 1; using concrete_type = matrix; - using concrete_dynamic_type = matrix; + using concrete_dynamic_type = matrix; + + static constexpr auto Flags = parent::Flags; + static constexpr int RowsAtCompileTime = Rows; + static constexpr int ColsAtCompileTime = Cols; + static constexpr int Options = parent::Options; template using as_concrete_type = as_concrete_t; - private: - static constexpr bool has_static_storage = storage_status; + static constexpr bool is_defined_static = Rows!=-1 && Cols!=-1; + static constexpr bool has_static_storage = storage_status; public: @@ -58,7 +61,6 @@ namespace rotgen matrix& operator=(const matrix&) = default; matrix& operator=(matrix&&) = default; - matrix(std::initializer_list> init) : parent(init) {} @@ -82,10 +84,17 @@ namespace rotgen } } + matrix(concepts::entity auto const& other) : parent(other.base()) + {} + template matrix(const Eigen::MatrixBase& other) : parent(other) {} + template + matrix(const Eigen::EigenBase& other) : parent(other) + {} + template matrix& operator=(const Eigen::MatrixBase& other) { @@ -100,22 +109,31 @@ namespace rotgen return *this; } + matrix& 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); } - concrete_type transpose() const + auto transpose() const { - return concrete_type(static_cast(*this).transpose()); + auto res = static_cast(*this).transpose(); + return as_concrete_type(res); } - concrete_type conjugate() const + auto conjugate() const { - return concrete_type(static_cast(*this).conjugate()); + auto res = static_cast(*this).conjugate(); + return as_concrete_type(res); } - concrete_type adjoint() const + auto adjoint() const { - return concrete_type(static_cast(*this).adjoint()); + auto res = static_cast(*this).adjoint(); + return as_concrete_type(res); } void transposeInPlace() { parent::transposeInPlace(); } @@ -155,6 +173,18 @@ namespace rotgen return parent::Identity(rows, cols); } + static matrix Ones() requires (Rows != -1 && Cols != -1) + { + return parent::Ones(Rows, Cols); + } + + static matrix Ones(int rows, int cols) + { + if constexpr(Rows != -1) assert(rows == Rows && "Mismatched between dynamic and static row size"); + if constexpr(Cols != -1) assert(cols == Cols && "Mismatched between dynamic and static column size"); + return parent::Ones(rows, cols); + } + static matrix Zero() requires (Rows != -1 && Cols != -1) { return parent::Zero(Rows, Cols); @@ -180,7 +210,7 @@ namespace rotgen } template - scalar_type lpNorm() const + value_type lpNorm() const { static_assert(P == 1 || P == 2 || P == Infinity); return parent::template lpNorm

(); @@ -200,6 +230,66 @@ namespace rotgen using parent::sum; using parent::data; + matrix& setOnes() + { + *this = parent::Ones(rows(),cols()); + return *this; + } + + matrix& setOnes(int r, int c) + { + *this = parent::Ones(r, c); + return *this; + } + + matrix& setZero() + { + *this = parent::Zero(rows(),cols()); + return *this; + } + + matrix& setZero(int r, int c) + { + *this = parent::Zero(r, c); + return *this; + } + + matrix& setConstant(Scalar value) + { + *this = parent::Constant(rows(),cols(), static_cast(value)); + return *this; + } + + matrix& setConstant(int r, int c, Scalar value) + { + *this = parent::Constant(r, c, static_cast(value)); + return *this; + } + + matrix& setRandom() + { + *this = parent::Random(rows(),cols()); + return *this; + } + + matrix& setRandom(int r, int c) + { + *this = parent::Random(r, c); + return *this; + } + + matrix& setIdentity() + { + *this = parent::Identity(rows(),cols()); + return *this; + } + + matrix& setIdentity(int r, int c) + { + *this = parent::Identity(r, c); + return *this; + } + matrix& operator+=(matrix const& rhs) { static_cast(*this) += static_cast(rhs); @@ -234,13 +324,5 @@ namespace rotgen static_cast(*this) /= rhs; return *this; } - - static void print_storage_info() - { - std::cout << "Matrix " << Rows << "x" << Cols - << " - Storage: " << (has_static_storage ? "Static" : "Dynamic") - << " (Max. size=" << max_static_size << ")" - << std::endl; - } }; } \ No newline at end of file diff --git a/include/rotgen/functions.hpp b/include/rotgen/functions.hpp index 565cbdf..2864645 100644 --- a/include/rotgen/functions.hpp +++ b/include/rotgen/functions.hpp @@ -9,134 +9,52 @@ namespace rotgen { - template< typename Scalar, int Rows = -1, int Cols = 1, int Options = 0, int MaxRows = Rows, int MaxCols = Cols > - std::size_t rows(const rotgen::matrix &matrix) + std::size_t rows(concepts::entity auto const& arg) { return arg.rows(); } + std::size_t cols(concepts::entity auto const& arg) { return arg.cols(); } + std::size_t size(concepts::entity auto const& arg) { return arg.size(); } + + template + void resize(E& arg, int new_rows, int new_cols) + requires(E::RowsAtCompileTime == -1 && E::ColsAtCompileTime == -1) { - return matrix.rows(); + arg.resize(new_rows, new_cols); } - template< typename Scalar, int Rows = -1, int Cols = 1, int Options = 0, int MaxRows = Rows, int MaxCols = Cols > - std::size_t cols(const rotgen::matrix &matrix) + template + void conservativeResize(E& arg, int new_rows, int new_cols) + requires(E::RowsAtCompileTime == -1 && E::ColsAtCompileTime == -1) { - return matrix.cols(); + arg.conservativeResize(new_rows, new_cols); } - template< typename Scalar, int Rows = -1, int Cols = 1, int Options = 0, int MaxRows = Rows, int MaxCols = Cols > - std::size_t size(const rotgen::matrix &matrix) + decltype(auto) transpose(concepts::entity auto const& arg) { return arg.transpose(); } + decltype(auto) conjugate(concepts::entity auto const& arg) { return arg.conjugate(); } + decltype(auto) adjoint (concepts::entity auto const& arg) { return arg.adjoint(); } + + void transposeInPlace(concepts::entity auto& arg) { arg.transposeInPlace(); } + void adjointInPlace(concepts::entity auto& arg) { arg.adjointInPlace(); } + + auto trace(concepts::entity auto const& arg) { return arg.trace(); } + auto squaredNorm(concepts::entity auto const& arg) { return arg.squaredNorm(); } + auto norm(concepts::entity auto const& arg) { return arg.norm(); } + 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 minCoeff(concepts::entity auto const& arg) { return arg.minCoeff(); } + auto maxCoeff(concepts::entity auto const& arg, Index* row, Index* col) { - return matrix.size(); + return arg.maxCoeff(row, col); + } + auto minCoeff(concepts::entity auto const& arg, Index* row, Index* col) + { + return arg.minCoeff(row, col); } - template< typename Scalar, int Rows = -1, int Cols = 1, int Options = 0, int MaxRows = Rows, int MaxCols = Cols > - void resize(rotgen::matrix &matrix, int new_rows, int new_cols) - requires(Rows == -1 && Cols == -1) - { - matrix.resize(new_rows, new_cols); - } - - template< typename Scalar, int Rows = -1, int Cols = 1, int Options = 0, int MaxRows = Rows, int MaxCols = Cols > - void conservativeResize(rotgen::matrix &matrix, int new_rows, int new_cols) - requires(Rows == -1 && Cols == -1) - { - matrix.conservativeResize(new_rows, new_cols); - } - - template< typename Scalar, int Rows = -1, int Cols = 1, int Options = 0, int MaxRows = Rows, int MaxCols = Cols > - rotgen::matrix transpose(const rotgen::matrix &matrix) - { - return matrix.transpose(); - } - - template< typename Scalar, int Rows = -1, int Cols = 1, int Options = 0, int MaxRows = Rows, int MaxCols = Cols > - rotgen::matrix conjugate(const rotgen::matrix &matrix) - { - return matrix.conjugate(); - } - - template< typename Scalar, int Rows = -1, int Cols = 1, int Options = 0, int MaxRows = Rows, int MaxCols = Cols > - rotgen::matrix adjoint(const rotgen::matrix &matrix) - { - return matrix.adjoint(); - } - - template< typename Scalar, int Rows = -1, int Cols = 1, int Options = 0, int MaxRows = Rows, int MaxCols = Cols > - void transposeInPlace(rotgen::matrix &matrix) - { - matrix.transposeInPlace(); - } - - template< typename Scalar, int Rows = -1, int Cols = 1, int Options = 0, int MaxRows = Rows, int MaxCols = Cols > - void adjointInPlace(rotgen::matrix &matrix) - { - matrix.adjointInPlace(); - } - - template< typename Scalar, int Rows = -1, int Cols = 1, int Options = 0, int MaxRows = Rows, int MaxCols = Cols > - double squaredNorm(const rotgen::matrix &matrix) - { - return matrix.squaredNorm(); - } - - template< typename Scalar, int Rows = -1, int Cols = 1, int Options = 0, int MaxRows = Rows, int MaxCols = Cols > - double norm(const rotgen::matrix &matrix) - { - return matrix.norm(); - } - - template< int P, typename Scalar, int Rows = -1, int Cols = 1, int Options = 0, int MaxRows = Rows, int MaxCols = Cols > - double lpNorm(const rotgen::matrix &matrix) + template + auto lpNorm(concepts::entity auto const& arg) { static_assert(P == 1 || P == 2 || P == Infinity); - - return matrix.template lpNorm

(); + return arg.template lpNorm

(); } - - template< typename Scalar, int Rows = -1, int Cols = 1, int Options = 0, int MaxRows = Rows, int MaxCols = Cols > - double sum(const rotgen::matrix &matrix) - { - return matrix.sum(); - } - - template< typename Scalar, int Rows = -1, int Cols = 1, int Options = 0, int MaxRows = Rows, int MaxCols = Cols > - double prod(const rotgen::matrix &matrix) - { - return matrix.prod(); - } - - template< typename Scalar, int Rows = -1, int Cols = 1, int Options = 0, int MaxRows = Rows, int MaxCols = Cols > - double mean(const rotgen::matrix &matrix) - { - return matrix.mean(); - } - - template< typename Scalar, int Rows = -1, int Cols = 1, int Options = 0, int MaxRows = Rows, int MaxCols = Cols > - double maxCoeff(const rotgen::matrix &matrix) - { - return matrix.maxCoeff(); - } - - template< typename Scalar, int Rows = -1, int Cols = 1, int Options = 0, int MaxRows = Rows, int MaxCols = Cols > - double maxCoeff(const rotgen::matrix &matrix, std::ptrdiff_t* row, std::ptrdiff_t* col) - { - return matrix.maxCoeff(row, col); - } - - template< typename Scalar, int Rows = -1, int Cols = 1, int Options = 0, int MaxRows = Rows, int MaxCols = Cols > - double minCoeff(const rotgen::matrix &matrix) - { - return matrix.minCoeff(); - } - - template< typename Scalar, int Rows = -1, int Cols = 1, int Options = 0, int MaxRows = Rows, int MaxCols = Cols > - double minCoeff(const rotgen::matrix &matrix, std::ptrdiff_t* row, std::ptrdiff_t* col) - { - return matrix.minCoeff(row, col); - } - - template< typename Scalar, int Rows = -1, int Cols = 1, int Options = 0, int MaxRows = Rows, int MaxCols = Cols > - double trace(const rotgen::matrix &matrix) - { - return matrix.trace(); - } - } diff --git a/include/rotgen/impl/block.hpp b/include/rotgen/impl/block.hpp index a5db371..bb5a75d 100644 --- a/include/rotgen/impl/block.hpp +++ b/include/rotgen/impl/block.hpp @@ -8,7 +8,6 @@ #pragma once #include -#include #include #include #include @@ -60,5 +59,5 @@ namespace rotgen 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::type; } diff --git a/include/rotgen/impl/block_model.hpp b/include/rotgen/impl/block_model.hpp index 1dcbf5f..b08c6f5 100644 --- a/include/rotgen/impl/block_model.hpp +++ b/include/rotgen/impl/block_model.hpp @@ -24,10 +24,15 @@ class CLASSNAME ~CLASSNAME(); + void assign(SOURCENAME const&); + Index rows() const; Index cols() const; Index size() const; + Index innerStride() const; + Index outerStride() const; + SOURCENAME transpose() const; SOURCENAME conjugate() const; SOURCENAME adjoint() const; @@ -51,8 +56,8 @@ class CLASSNAME 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; + TYPE& operator()(std::size_t index); + TYPE const& operator()(std::size_t index) const; CLASSNAME& operator+=(CLASSNAME const& rhs); CLASSNAME& operator-=(CLASSNAME const& rhs); @@ -61,18 +66,21 @@ class CLASSNAME CLASSNAME& operator*=(TYPE d); CLASSNAME& operator/=(TYPE d); - SOURCENAME matrix_addition(CLASSNAME const& rhs) const; - SOURCENAME matrix_subtraction(CLASSNAME const& rhs) const; - SOURCENAME matrix_multiplication(CLASSNAME const& rhs) const; - SOURCENAME matrix_multiplication(TYPE s) const; - SOURCENAME matrix_division(TYPE s) const; + SOURCENAME add(CLASSNAME const& rhs) const; + SOURCENAME sub(CLASSNAME const& rhs) const; + SOURCENAME mul(CLASSNAME const& rhs) const; + SOURCENAME mul(TYPE s) const; + SOURCENAME div(TYPE s) const; friend std::ostream& operator<<(std::ostream&,CLASSNAME const&); friend bool operator==(CLASSNAME const& lhs, CLASSNAME const& rhs); + friend bool operator!=(CLASSNAME const& lhs, CLASSNAME const& rhs); const TYPE* data() const; + TYPE* data(); 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); } diff --git a/include/rotgen/impl/map.hpp b/include/rotgen/impl/map.hpp new file mode 100644 index 0000000..5c696bf --- /dev/null +++ b/include/rotgen/impl/map.hpp @@ -0,0 +1,115 @@ +//================================================================================================== +/* + ROTGEN - Runtime Overlay for Eigen + Copyright : CODE RECKONS + SPDX-License-Identifier: BSL-1.0 +*/ +//================================================================================================== +#pragma once + +#include +#include +#include +#include +#include +#include + +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 + #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 + #undef CONST + + template struct find_map_impl; + + template<> struct find_map_impl { using type = map_const_impl32_col; }; + template<> struct find_map_impl { using type = map_const_impl32_row; }; + template<> struct find_map_impl { using type = map_const_impl64_col; }; + template<> struct find_map_impl { using type = map_const_impl64_row; }; + template<> struct find_map_impl { using type = map_impl32_col; }; + template<> struct find_map_impl { using type = map_impl32_row; }; + template<> struct find_map_impl { using type = map_impl64_col; }; + template<> struct find_map_impl { using type = map_impl64_row; }; + + template + using find_map = typename find_map_impl < typename std::remove_const_t::value_type + , Ref::storage_order + , std::is_const_v + >::type; +} + +#include diff --git a/include/rotgen/impl/map_model.hpp b/include/rotgen/impl/map_model.hpp new file mode 100644 index 0000000..80cc75b --- /dev/null +++ b/include/rotgen/impl/map_model.hpp @@ -0,0 +1,106 @@ +//================================================================================================== +/* + ROTGEN - Runtime Overlay for Eigen + Copyright : CODE RECKONS + SPDX-License-Identifier: BSL-1.0 +*/ +//================================================================================================== + +//================================================================================================== +/* + This file is a X-File to generate various map_impl_* declarations variant +*/ +//================================================================================================== +class CLASSNAME +{ + public: + CLASSNAME(TYPE CONST* ptr, Index r, Index c); + CLASSNAME(TYPE CONST* ptr, Index r, Index c, stride s); + + CLASSNAME(CLASSNAME const& other); + + #if !defined(USE_CONST) + CLASSNAME& operator=(CLASSNAME const& other); + #endif + + CLASSNAME(CLASSNAME&&) noexcept; + + CLASSNAME& operator=(CLASSNAME&&) noexcept; + + ~CLASSNAME(); + + Index rows() const; + Index cols() const; + Index size() const; + + Index innerStride() const; + Index outerStride() 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; + TYPE mean() const; + TYPE trace() const; + TYPE maxCoeff() const; + TYPE minCoeff() const; + TYPE maxCoeff(Index* row, Index* col) const; + TYPE minCoeff(Index* row, Index* col) const; + + TYPE squaredNorm() const; + TYPE norm() const; + TYPE lpNorm(int p) const; + + #if !defined(USE_CONST) + TYPE& operator()(Index i, Index j); + TYPE& operator()(Index i); + #endif + + TYPE operator()(Index i, Index j) const; + TYPE operator()(Index i) const; + + + #if !defined(USE_CONST) + CLASSNAME& operator+=(CLASSNAME const& rhs); + CLASSNAME& operator-=(CLASSNAME const& rhs); + CLASSNAME& operator*=(CLASSNAME const& rhs); + CLASSNAME& operator*=(TYPE d); + CLASSNAME& operator/=(TYPE d); + #endif + + SOURCENAME operator-() const; + SOURCENAME add(CLASSNAME const& rhs) const; + SOURCENAME sub(CLASSNAME const& rhs) const; + SOURCENAME mul(CLASSNAME const& rhs) const; + SOURCENAME mul(TYPE s) const; + SOURCENAME div(TYPE s) const; + + friend std::ostream& operator<<(std::ostream&,CLASSNAME const&); + const TYPE* data() const; + + #if !defined(USE_CONST) + void setZero(); + void setOnes(); + void setRandom(); + void setIdentity(); + void setConstant(TYPE); + #endif + + friend bool operator==(CLASSNAME const& lhs, CLASSNAME const& rhs); + friend bool operator!=(CLASSNAME const& lhs, CLASSNAME const& rhs); + + private: + struct payload; + std::unique_ptr storage_; + + public: + std::unique_ptr& storage() { return storage_; } + std::unique_ptr const& storage() const { return storage_; } +}; \ No newline at end of file diff --git a/include/rotgen/impl/map_operators.hpp b/include/rotgen/impl/map_operators.hpp new file mode 100644 index 0000000..c6a6d78 --- /dev/null +++ b/include/rotgen/impl/map_operators.hpp @@ -0,0 +1,39 @@ +//================================================================================================== +/* + ROTGEN - Runtime Overlay for Eigen + Copyright : CODE RECKONS + SPDX-License-Identifier: BSL-1.0 +*/ +//================================================================================================== +#pragma once + +#define ROTGEN_DEF_RELOP_PAIR(OP, T1, T2) \ +bool operator OP (T1 const&, T2 const&); \ +inline bool operator OP (T2 const& a, T1 const& b) { return b OP a; } \ +/**/ + +#define ROTGEN_DEF_RELOP(OP) \ +ROTGEN_DEF_RELOP_PAIR(OP, map_const_impl32_col, map_impl32_col) \ +ROTGEN_DEF_RELOP_PAIR(OP, map_const_impl32_col, map_impl32_row) \ +ROTGEN_DEF_RELOP_PAIR(OP, map_const_impl32_col, map_const_impl32_row) \ +ROTGEN_DEF_RELOP_PAIR(OP, map_const_impl32_row, map_impl32_row) \ +ROTGEN_DEF_RELOP_PAIR(OP, map_const_impl32_row, map_impl32_col) \ +ROTGEN_DEF_RELOP_PAIR(OP, map_impl32_col, map_impl32_row) \ +ROTGEN_DEF_RELOP_PAIR(OP, map_const_impl64_col, map_impl64_col) \ +ROTGEN_DEF_RELOP_PAIR(OP, map_const_impl64_col, map_impl64_row) \ +ROTGEN_DEF_RELOP_PAIR(OP, map_const_impl64_col, map_const_impl64_row) \ +ROTGEN_DEF_RELOP_PAIR(OP, map_const_impl64_row, map_impl64_row) \ +ROTGEN_DEF_RELOP_PAIR(OP, map_const_impl64_row, map_impl64_col) \ +ROTGEN_DEF_RELOP_PAIR(OP, map_impl64_col, map_impl64_row) \ +/**/ + +namespace rotgen +{ + ROTGEN_DEF_RELOP(==) + ROTGEN_DEF_RELOP(!=) + // ROTGEN_DEF_RELOP(+) + // ROTGEN_DEF_RELOP(-) +} + +#undef ROTGEN_DEF_RELOP_PAIR +#undef ROTGEN_DEF_RELOP \ No newline at end of file diff --git a/include/rotgen/impl/matrix_model.hpp b/include/rotgen/impl/matrix_model.hpp index 94d2004..a842390 100644 --- a/include/rotgen/impl/matrix_model.hpp +++ b/include/rotgen/impl/matrix_model.hpp @@ -69,10 +69,13 @@ class CLASSNAME friend std::ostream& operator<<(std::ostream&,CLASSNAME const&); friend bool operator==(CLASSNAME const& lhs, CLASSNAME const& rhs); + friend bool operator!=(CLASSNAME const& lhs, CLASSNAME const& rhs); const TYPE* data() const; + TYPE* data(); static CLASSNAME Zero(std::size_t rows, std::size_t cols); + static CLASSNAME Ones(std::size_t rows, std::size_t cols); static CLASSNAME Constant(std::size_t rows, std::size_t cols, TYPE value); static CLASSNAME Random(std::size_t rows, std::size_t cols); static CLASSNAME Identity(std::size_t rows, std::size_t cols); diff --git a/include/rotgen/impl/payload.hpp b/include/rotgen/impl/payload.hpp index b1af8c1..6a6cd32 100644 --- a/include/rotgen/impl/payload.hpp +++ b/include/rotgen/impl/payload.hpp @@ -10,12 +10,13 @@ #include #include #include +#include #include namespace rotgen { //================================================================================================== - // Internal payload - Requried for cross-referencing from block_impl* + // Internal payload - Required for cross-referencing from block_impl* //================================================================================================== struct matrix_impl64_col::payload { @@ -72,4 +73,112 @@ namespace rotgen void assign(data_type const& mat) { data = mat; } void assign(data_type&& mat) { data = std::move(mat); } }; + + //================================================================================================== + // Internal payload - Required for cross-referencing from mixed order on map operators + //================================================================================================== + struct map_const_impl32_col::payload + { + using stride_type = Eigen::Stride; + using base_type = Eigen::Matrix; + using data_type = Eigen::Map; + + data_type data; + + payload (data_type const& o) : data(o) {} + payload (float const* ptr, Index r, Index c) : data(ptr,r,c) {} + payload (float const* ptr, Index r, Index c, stride_type s) : data(ptr,r,c,s) {} + }; + + struct map_const_impl32_row::payload + { + using stride_type = Eigen::Stride; + using base_type = Eigen::Matrix; + using data_type = Eigen::Map; + + data_type data; + + payload (data_type const& o) : data(o) {} + payload (float const* ptr, Index r, Index c) : data(ptr,r,c) {} + payload (float const* ptr, Index r, Index c, stride_type s) : data(ptr,r,c,s) {} + }; + + struct map_impl32_col::payload + { + using stride_type = Eigen::Stride; + using base_type = Eigen::Matrix; + using data_type = Eigen::Map; + + data_type data; + + payload (data_type const& o) : data(o) {} + payload (float* ptr, Index r, Index c) : data(ptr,r,c) {} + payload (float* ptr, Index r, Index c, stride_type s) : data(ptr,r,c,s) {} + }; + + struct map_impl32_row::payload + { + using stride_type = Eigen::Stride; + using base_type = Eigen::Matrix; + using data_type = Eigen::Map; + + data_type data; + + payload (data_type const& o) : data(o) {} + payload (float* ptr, Index r, Index c) : data(ptr,r,c) {} + payload (float* ptr, Index r, Index c, stride_type s) : data(ptr,r,c,s) {} + }; + + + struct map_const_impl64_col::payload + { + using stride_type = Eigen::Stride; + using base_type = Eigen::Matrix; + using data_type = Eigen::Map; + + data_type data; + + payload (data_type const& o) : data(o) {} + payload (double const* ptr, Index r, Index c) : data(ptr,r,c) {} + payload (double const* ptr, Index r, Index c, stride_type s) : data(ptr,r,c,s) {} + }; + + struct map_const_impl64_row::payload + { + using stride_type = Eigen::Stride; + using base_type = Eigen::Matrix; + using data_type = Eigen::Map; + + data_type data; + + payload (data_type const& o) : data(o) {} + payload (double const* ptr, Index r, Index c) : data(ptr,r,c) {} + payload (double const* ptr, Index r, Index c, stride_type s) : data(ptr,r,c,s) {} + }; + + struct map_impl64_col::payload + { + using stride_type = Eigen::Stride; + using base_type = Eigen::Matrix; + using data_type = Eigen::Map; + + data_type data; + + payload (data_type const& o) : data(o) {} + payload (double* ptr, Index r, Index c) : data(ptr,r,c) {} + payload (double* ptr, Index r, Index c, stride_type s) : data(ptr,r,c,s) {} + }; + + struct map_impl64_row::payload + { + using stride_type = Eigen::Stride; + using base_type = Eigen::Matrix; + using data_type = Eigen::Map; + + data_type data; + + payload (data_type const& o) : data(o) {} + payload (double* ptr, Index r, Index c) : data(ptr,r,c) {} + payload (double* ptr, Index r, Index c, stride_type s) : data(ptr,r,c,s) {} + }; } diff --git a/include/rotgen/operators.hpp b/include/rotgen/operators.hpp new file mode 100644 index 0000000..cc8f5d8 --- /dev/null +++ b/include/rotgen/operators.hpp @@ -0,0 +1,71 @@ +//================================================================================================== +/* + ROTGEN - Runtime Overlay for Eigen + Copyright : CODE RECKONS + SPDX-License-Identifier: BSL-1.0 +*/ +//================================================================================================== +#pragma once + +#include +#include +#include + +namespace rotgen +{ + template + std::ostream& operator<<(std::ostream& os, E const& arg) + { + return os << arg.base(); + } + + template + constexpr bool operator==(A const& a, B const& b) noexcept + requires(concepts::entity || concepts::entity) + { + static_assert ( std::same_as + , "[ROTGEN] Incompatible type in operator==" + ); + if constexpr(!use_expression_templates) return generalize_t(a) == generalize_t(b); + else return base_of(a) == base_of(b); + } + + template + constexpr bool operator!=(A const& a, B const& b) noexcept + requires(concepts::entity || concepts::entity) + { + static_assert ( std::same_as + , "[ROTGEN] Incompatible type in operator!=" + ); + if constexpr(!use_expression_templates) return generalize_t(a) != generalize_t(b); + else return base_of(a) != base_of(b); + } + + template + auto operator+(A const& a, B const& b) requires(concepts::entity || concepts::entity) + { + if constexpr(!use_expression_templates) return generalize_t(a) + generalize_t(b); + else return base_of(a) + base_of(b); + } + + template + auto operator-(A const& a, B const& b) requires(concepts::entity || concepts::entity) + { + if constexpr(!use_expression_templates) return generalize_t(a) - generalize_t(b); + else return base_of(a) - base_of(b); + } + + template + auto operator*(A const& a, B const& b) requires(concepts::entity || concepts::entity) + { + if constexpr(!use_expression_templates) return generalize_t(a) * generalize_t(b); + else return base_of(a) * base_of(b); + } + + template + auto operator/(A const& a, B const& b) requires(concepts::entity && std::is_arithmetic_v) + { + if constexpr(!use_expression_templates) return generalize_t(a) / b; + else return base_of(a) / b; + } +} \ No newline at end of file diff --git a/include/rotgen/rotgen.hpp b/include/rotgen/rotgen.hpp index f489060..95ad9e1 100644 --- a/include/rotgen/rotgen.hpp +++ b/include/rotgen/rotgen.hpp @@ -9,14 +9,21 @@ #include #include +#include +#include #if defined(ROTGEN_FORCE_DYNAMIC) #include #include +#include #else #include #include +#include #endif +#include #include #include +#include +#include diff --git a/src/block_model.cpp b/src/block_model.cpp index 91a8bc7..d31f344 100644 --- a/src/block_model.cpp +++ b/src/block_model.cpp @@ -50,21 +50,27 @@ struct CLASSNAME::payload CLASSNAME::~CLASSNAME() = default; + void CLASSNAME::assign(SOURCENAME const& m) + { + storage_->data = m.storage()->data; + } + //================================================================================================== // 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(); } 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); } - /* - TYPE& CLASSNAME::operator()(std::size_t index) { return storage_->data(index); } - TYPE const& CLASSNAME::operator()(std::size_t index) const { return storage_->data(index); } - */ + 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]; } + TYPE* CLASSNAME::data() { return storage_->data.data(); } const TYPE* CLASSNAME::data() const { return storage_->data.data(); } SOURCENAME CLASSNAME::transpose() const @@ -130,6 +136,11 @@ struct CLASSNAME::payload return lhs.storage_->data == rhs.storage_->data; } + bool operator!=(CLASSNAME const& lhs, CLASSNAME const& rhs) + { + return lhs.storage_->data != rhs.storage_->data; + } + CLASSNAME& CLASSNAME::operator+=(CLASSNAME const& rhs) { storage_->data += rhs.storage_->data; @@ -167,35 +178,35 @@ struct CLASSNAME::payload return *this; } - SOURCENAME CLASSNAME::matrix_addition(CLASSNAME const& rhs) const + SOURCENAME CLASSNAME::add(CLASSNAME const& rhs) const { SOURCENAME result; result.storage()->assign(storage_->data + rhs.storage_->data); return result; } - SOURCENAME CLASSNAME::matrix_subtraction(CLASSNAME const& rhs) const + SOURCENAME CLASSNAME::sub(CLASSNAME const& rhs) const { SOURCENAME result; result.storage()->assign(storage_->data - rhs.storage_->data); return result; } - SOURCENAME CLASSNAME::matrix_multiplication(CLASSNAME const& rhs) const + SOURCENAME CLASSNAME::mul(CLASSNAME const& rhs) const { SOURCENAME result; result.storage()->assign(storage_->data * rhs.storage_->data); return result; } - SOURCENAME CLASSNAME::matrix_multiplication(TYPE s) const + SOURCENAME CLASSNAME::mul(TYPE s) const { SOURCENAME result; result.storage()->assign(storage_->data * s); return result; } - SOURCENAME CLASSNAME::matrix_division(TYPE s) const + SOURCENAME CLASSNAME::div(TYPE s) const { SOURCENAME result; result.storage()->assign(storage_->data / s); diff --git a/src/info.cpp b/src/info.cpp index 0291e93..e6e13ff 100644 --- a/src/info.cpp +++ b/src/info.cpp @@ -7,24 +7,12 @@ */ //================================================================================================== #include -#include -namespace rotgen +namespace rotgen::detail { - std::ostream& setup_summary(std::ostream& os) + std::ostream& dynamic_info(std::ostream& os) { - if constexpr(rotgen::is_forcing_dynamic_status) - { - os << "[ROTGEN] - Fully Dynamic mode" << std::endl; - } - else - { - if constexpr(use_expression_templates) - os << "[ROTGEN] - Expression templates : Disabled." << std::endl; - else - os << "[ROTGEN] - Static/Dynamic mode with maximum size: " << rotgen::max_static_size << std::endl; - } - - return os; + if constexpr(rotgen::is_forcing_dynamic_status) return os << "[ROTGEN] - Fully Dynamic mode" << std::endl; + else return os << "[ROTGEN] - Flexible mode with" << std::endl; } } \ No newline at end of file diff --git a/src/map.cpp b/src/map.cpp new file mode 100644 index 0000000..2871ebc --- /dev/null +++ b/src/map.cpp @@ -0,0 +1,110 @@ +//================================================================================================== +/* + ROTGEN - Runtime Overlay for Eigen + Copyright : CODE RECKONS + SPDX-License-Identifier: BSL-1.0 +*/ +//================================================================================================== +#include +#include +#include +#include + +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 + + #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 + #undef CONST +} diff --git a/src/map_model.cpp b/src/map_model.cpp new file mode 100644 index 0000000..2c6f030 --- /dev/null +++ b/src/map_model.cpp @@ -0,0 +1,236 @@ +//================================================================================================== +/* + ROTGEN - Runtime Overlay for Eigen + Copyright : CODE RECKONS + SPDX-License-Identifier: BSL-1.0 +*/ +//================================================================================================== + +//================================================================================================== +/* + This file is a X-File to generate various map_impl_* definitions variant +*/ +//================================================================================================== + +//================================================================================================== +// Internal payload +//================================================================================================== + + //================================================================================================== + // Constructors & Special Members + //================================================================================================== + CLASSNAME::CLASSNAME(TYPE CONST* ptr, Index r, Index c) : storage_(std::make_unique(ptr,r,c)) + {} + + CLASSNAME::CLASSNAME(TYPE CONST* ptr, Index r, Index c, stride s) + : storage_(std::make_unique(ptr,r,c,payload::stride_type{s.outer,s.inner})) + {} + + CLASSNAME::CLASSNAME(CLASSNAME const& o) : storage_(std::make_unique(o.storage_->data)) + {} + + #if !defined(USE_CONST) + CLASSNAME& CLASSNAME::operator=(CLASSNAME const& o) + { + if (this != &o) storage_->data = o.storage_->data; + return *this; + } + #endif + + CLASSNAME::CLASSNAME(CLASSNAME&&) noexcept = default; + CLASSNAME& CLASSNAME::operator=(CLASSNAME&&) noexcept = default; + + 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::innerStride() const { return storage_->data.innerStride(); } + rotgen::Index CLASSNAME::outerStride() const { return storage_->data.outerStride(); } + + #if !defined(USE_CONST) + TYPE& CLASSNAME::operator()(Index i, Index j) { return storage_->data(i,j); } + TYPE& CLASSNAME::operator()(Index i) { return storage_->data.data()[i]; } + #endif + + TYPE CLASSNAME::operator()(Index i, Index j) const { return storage_->data(i,j); } + TYPE CLASSNAME::operator()(Index i) const { return storage_->data.data()[i]; } + + const TYPE* CLASSNAME::data() const { return storage_->data.data(); } + + SOURCENAME CLASSNAME::transpose() const + { + SOURCENAME result; + result.storage()->assign(storage_->data.transpose().eval()); + return result; + } + + SOURCENAME CLASSNAME::conjugate() const + { + SOURCENAME result; + result.storage()->assign(storage_->data.conjugate().eval()); + return result; + } + + SOURCENAME CLASSNAME::adjoint() const + { + SOURCENAME result; + result.storage()->assign(storage_->data.adjoint().eval()); + return result; + } + +#if !defined(USE_CONST) + void CLASSNAME::transposeInPlace() + { + storage_->data.transposeInPlace(); + } + + void CLASSNAME::adjointInPlace() + { + storage_->data.adjointInPlace(); + } +#endif + + 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::minCoeff() const { return storage_->data.minCoeff(); } + TYPE CLASSNAME::maxCoeff() const { return storage_->data.maxCoeff(); } + + TYPE CLASSNAME::minCoeff(Index* row, Index* col) const { return storage_->data.minCoeff(row, col); } + TYPE CLASSNAME::maxCoeff(Index* row, Index* col) const { return storage_->data.maxCoeff(row, col); } + + TYPE CLASSNAME::squaredNorm() const { return storage_->data.squaredNorm(); } + TYPE CLASSNAME::norm() const { return storage_->data.norm(); } + + 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(); + } + + #if !defined(USE_CONST) + void CLASSNAME::setZero() + { + storage_->data.setZero(); + } + + void CLASSNAME::setOnes() + { + storage_->data.setOnes(); + } + + void CLASSNAME::setIdentity() + { + storage_->data.setIdentity(); + } + + void CLASSNAME::setRandom() + { + storage_->data.setRandom(); + } + + void CLASSNAME::setConstant(TYPE s) + { + storage_->data.setConstant(s); + } + #endif + + //================================================================================================== + // Operators + //================================================================================================== + std::ostream& operator<<(std::ostream& os,CLASSNAME const& m) + { + return os << m.storage_->data; + } + + bool operator==(CLASSNAME const& lhs, CLASSNAME const& rhs) + { + return lhs.storage_->data == rhs.storage_->data; + } + + bool operator!=(CLASSNAME const& lhs, CLASSNAME const& rhs) + { + return lhs.storage_->data != rhs.storage_->data; + } + + SOURCENAME CLASSNAME::operator-() const + { + SOURCENAME result; + result.storage()->assign(storage_->data); + return -result; + } + + #if !defined(USE_CONST) + CLASSNAME& CLASSNAME::operator+=(CLASSNAME const& rhs) + { + storage_->data += rhs.storage_->data; + return *this; + } + + CLASSNAME& CLASSNAME::operator-=(CLASSNAME const& rhs) + { + storage_->data -= rhs.storage_->data; + return *this; + } + + CLASSNAME& CLASSNAME::operator*=(CLASSNAME const& rhs) + { + storage_->data *= rhs.storage_->data; + return *this; + } + + CLASSNAME& CLASSNAME::operator*=(TYPE s) + { + storage_->data *= s; + return *this; + } + + CLASSNAME& CLASSNAME::operator/=(TYPE s) + { + storage_->data /= s; + return *this; + } + #endif + + SOURCENAME CLASSNAME::add(CLASSNAME const& rhs) const + { + SOURCENAME result; + result.storage()->assign(storage_->data + rhs.storage_->data); + return result; + } + + SOURCENAME CLASSNAME::sub(CLASSNAME const& rhs) const + { + SOURCENAME result; + result.storage()->assign(storage_->data - rhs.storage_->data); + return result; + } + + SOURCENAME CLASSNAME::mul(CLASSNAME const& rhs) const + { + SOURCENAME result; + result.storage()->assign(storage_->data * rhs.storage_->data); + return result; + } + + SOURCENAME CLASSNAME::mul(TYPE s) const + { + SOURCENAME result; + result.storage()->assign(storage_->data * s); + return result; + } + + SOURCENAME CLASSNAME::div(TYPE s) const + { + SOURCENAME result; + result.storage()->assign(storage_->data / s); + return result; + } \ No newline at end of file diff --git a/src/matrix_model.cpp b/src/matrix_model.cpp index 419eded..24ed5ca 100644 --- a/src/matrix_model.cpp +++ b/src/matrix_model.cpp @@ -46,7 +46,7 @@ CLASSNAME& CLASSNAME::operator=(CLASSNAME const& o) CLASSNAME& CLASSNAME::operator=(CLASSNAME&&) noexcept = default; -CLASSNAME::~CLASSNAME() = default; +CLASSNAME::~CLASSNAME() = default; //================================================================================================== // Matrix API @@ -72,6 +72,7 @@ TYPE& CLASSNAME::operator()(std::size_t index) { return storage_->da TYPE const& CLASSNAME::operator()(std::size_t index) const { return storage_->data(index); } const TYPE* CLASSNAME::data() const { return storage_->data.data(); } +TYPE* CLASSNAME::data() { return storage_->data.data(); } CLASSNAME CLASSNAME::transpose() const { @@ -139,6 +140,11 @@ bool operator==(CLASSNAME const& lhs, CLASSNAME const& rhs) return lhs.storage_->data == rhs.storage_->data; } +bool operator!=(CLASSNAME const& lhs, CLASSNAME const& rhs) +{ + return lhs.storage_->data != rhs.storage_->data; +} + CLASSNAME& CLASSNAME::operator+=(CLASSNAME const& rhs) { storage_->data += rhs.storage_->data; @@ -180,6 +186,13 @@ CLASSNAME& CLASSNAME::operator/=(TYPE s) // Static functions //================================================================================================== +CLASSNAME CLASSNAME::Ones(std::size_t rows, std::size_t cols) +{ + CLASSNAME m; + m.storage_ = std::make_unique(payload::data_type::Ones(rows, cols)); + return m; +} + CLASSNAME CLASSNAME::Zero(std::size_t rows, std::size_t cols) { CLASSNAME m; diff --git a/src/operators.cpp b/src/operators.cpp new file mode 100644 index 0000000..9679c46 --- /dev/null +++ b/src/operators.cpp @@ -0,0 +1,40 @@ +//================================================================================================== +/* + ROTGEN - Runtime Overlay for Eigen + Copyright : CODE RECKONS + SPDX-License-Identifier: BSL-1.0 +*/ +//================================================================================================== + +#include +#include +#include + +#define ROTGEN_IMPL_OP(OP,FN,RET) \ +RET operator OP(map_const_impl32_col const& a, map_impl32_col const& b ) { return FN(a, b); } \ +RET operator OP(map_const_impl32_col const& a, map_impl32_row const& b ) { return FN(a, b); } \ +RET operator OP(map_const_impl32_col const& a, map_const_impl32_row const& b ) { return FN(a, b); } \ +RET operator OP(map_const_impl32_row const& a, map_impl32_row const& b ) { return FN(a, b); } \ +RET operator OP(map_const_impl32_row const& a, map_impl32_col const& b ) { return FN(a, b); } \ +RET operator OP(map_impl32_col const& a, map_impl32_row const& b ) { return FN(a, b); } \ +RET operator OP(map_const_impl64_col const& a, map_impl64_col const& b ) { return FN(a, b); } \ +RET operator OP(map_const_impl64_col const& a, map_impl64_row const& b ) { return FN(a, b); } \ +RET operator OP(map_const_impl64_col const& a, map_const_impl64_row const& b ) { return FN(a, b); } \ +RET operator OP(map_const_impl64_row const& a, map_impl64_row const& b ) { return FN(a, b); } \ +RET operator OP(map_const_impl64_row const& a, map_impl64_col const& b ) { return FN(a, b); } \ +RET operator OP(map_impl64_col const& a, map_impl64_row const& b ) { return FN(a, b); } \ +/**/ + +namespace rotgen +{ + namespace + { + auto add(auto const& a, auto const& b) { return a.storage()->data + b.storage()->data; } + auto sub(auto const& a, auto const& b) { return a.storage()->data - b.storage()->data; } + bool equal(auto const& a, auto const& b) { return a.storage()->data == b.storage()->data; } + bool not_equal(auto const& a, auto const& b) { return a.storage()->data != b.storage()->data; } + } + + ROTGEN_IMPL_OP(==, equal , bool); + ROTGEN_IMPL_OP(!=, not_equal, bool); +} \ No newline at end of file diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 18eab67..e395a6d 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -17,6 +17,7 @@ target_link_libraries(rotgen_test INTERFACE rotgen Eigen3::Eigen) ##====================================================================================================================== ## Unit Tests registration ##====================================================================================================================== -rotgen_glob_unit(PATTERN "unit/free_functions/*.cpp" INTERFACE rotgen_test) -rotgen_glob_unit(PATTERN "unit/matrix/*.cpp" INTERFACE rotgen_test) -rotgen_glob_unit(PATTERN "unit/block/*.cpp" INTERFACE rotgen_test) +rotgen_glob_unit(PATTERN "unit/*.cpp" INTERFACE rotgen_test) +rotgen_glob_unit(PATTERN "unit/matrix/*.cpp" INTERFACE rotgen_test) +rotgen_glob_unit(PATTERN "unit/block/*.cpp" INTERFACE rotgen_test) +rotgen_glob_unit(PATTERN "unit/map/*.cpp" INTERFACE rotgen_test) diff --git a/test/unit/block/arithmetic_functions.cpp b/test/unit/block/arithmetic_functions.cpp index 618305f..61a0860 100644 --- a/test/unit/block/arithmetic_functions.cpp +++ b/test/unit/block/arithmetic_functions.cpp @@ -6,128 +6,69 @@ */ //================================================================================================== #include "unit/tests.hpp" +#include "unit/common/arithmetic.hpp" #include -#include -template -void test_comparison(const Type1& t1, const Type2& t2) -{ - TTS_EQUAL(static_cast(t1.rows()), static_cast(t2.rows())); - TTS_EQUAL(static_cast(t1.cols()), static_cast(t2.cols())); - for (rotgen::Index r = 0; r < static_cast(t1.rows()); ++r) - for (rotgen::Index c = 0; c < static_cast(t1.cols()); ++c) - TTS_EQUAL(t1(r, c), t2(r, c)); -} - -template -void test_block_unary_ops(const Matrix1& original_matrix, const Matrix2& ref_matrix, - Block1 original_block, Block2 ref_block) -{ - TTS_EXPECT(verify_rotgen_reentrance(original_block.transpose())); - TTS_EXPECT(verify_rotgen_reentrance(original_block.conjugate())); - TTS_EXPECT(verify_rotgen_reentrance(original_block.adjoint())); - - test_comparison(original_block.transpose(), ref_block.transpose()); - test_comparison(original_block.conjugate(), ref_block.conjugate()); - test_comparison(original_block.adjoint(), ref_block.adjoint()); - - if (original_block.rows() == original_block.cols()) { - original_block.transposeInPlace(); - ref_block.transposeInPlace(); - test_comparison(original_block, ref_block); - test_comparison(original_matrix, ref_matrix); - - original_block.adjointInPlace(); - ref_block.adjointInPlace(); - test_comparison(original_block, ref_block); - test_comparison(original_matrix, ref_matrix); - } -} - -template -void compare_reductions(const Block1& block, const Block2& ref) -{ - constexpr double epsilon = 0.0001; - TTS_RELATIVE_EQUAL(block.sum(), ref.sum(), epsilon); - TTS_RELATIVE_EQUAL(block.prod(), ref.prod(), epsilon); - TTS_RELATIVE_EQUAL(block.mean(), ref.mean(), epsilon); - TTS_EQUAL(block.trace(), ref.trace()); - TTS_EQUAL(block.minCoeff(), ref.minCoeff()); - TTS_EQUAL(block.maxCoeff(), ref.maxCoeff()); - - std::ptrdiff_t row, col, ref_row, ref_col; - - TTS_EQUAL(block.minCoeff(&row, &col), ref.minCoeff(&ref_row, &ref_col)); - TTS_EQUAL(row, ref_row); - TTS_EQUAL(col, ref_col); - - TTS_EQUAL(block.maxCoeff(&row, &col), ref.maxCoeff(&ref_row, &ref_col)); - TTS_EQUAL(row, ref_row); - TTS_EQUAL(col, ref_col); -} - -template -void test_dynamic_block_reductions(rotgen::tests::matrix_block_test_case const& matrix_construct) -{ - using EigenMatrix = Eigen::Matrix; - - MatrixType original(matrix_construct.rows, matrix_construct.cols); - EigenMatrix ref(matrix_construct.rows, matrix_construct.cols); - - for (rotgen::Index r = 0; r < matrix_construct.rows; ++r) - for (rotgen::Index c = 0; c < matrix_construct.cols; ++c) - ref(r, c) = original(r,c) = static_cast(matrix_construct.init_fn(r, c)); - - std::vector, Eigen::Block>> test_cases { - { rotgen::extract(original, matrix_construct.i0, matrix_construct.j0, - matrix_construct.ni, matrix_construct.nj), - ref.block(matrix_construct.i0, matrix_construct.j0, - matrix_construct.ni, matrix_construct.nj) }, - - { rotgen::topLeftCorner(original, matrix_construct.ni, matrix_construct.nj), - ref.topLeftCorner(matrix_construct.ni, matrix_construct.nj) }, - { rotgen::topRightCorner(original, matrix_construct.ni, matrix_construct.nj), - ref.topRightCorner(matrix_construct.ni, matrix_construct.nj) }, - { rotgen::bottomLeftCorner(original, matrix_construct.ni, matrix_construct.nj), - ref.bottomLeftCorner(matrix_construct.ni, matrix_construct.nj) }, - { rotgen::bottomRightCorner(original, matrix_construct.ni, matrix_construct.nj), - ref.bottomRightCorner(matrix_construct.ni, matrix_construct.nj) }, - - { rotgen::topRows(original, matrix_construct.ni), - ref.topRows(matrix_construct.ni) }, - { rotgen::middleRows(original, matrix_construct.i0, matrix_construct.ni), - ref.middleRows(matrix_construct.i0, matrix_construct.ni) }, - { rotgen::bottomRows(original, matrix_construct.ni), - ref.bottomRows(matrix_construct.ni) }, - }; - - for (const auto& [original_block, ref_block] : test_cases) { - compare_reductions(original_block, ref_block); - test_block_unary_ops(original, ref, original_block, ref_block); - } - -} - -TTS_CASE_TPL("Test dynamic block reductions", rotgen::tests::types) +TTS_CASE_TPL("Test dynamic block transposition-like operations", rotgen::tests::types) ( tts::type< tts::types> ) { - using mat_t = rotgen::matrix; - - std::vector> test_cases = - { - {6, 5, [](rotgen::Index r, rotgen::Index c) { return T(r + c); }, 1, 2, 3, 2}, - {9, 11, [](rotgen::Index r, rotgen::Index c) {return T(r + c); }, 0, 1, 4, 9}, - {3, 3, [](rotgen::Index , rotgen::Index ) {return T(0.0); }, 1, 1, 1, 1}, - {1, 4, [](rotgen::Index r, rotgen::Index c) {return T(-r -c*c - 1234); }, 0, 0, 1, 1}, - {9, 9, [](rotgen::Index r, rotgen::Index c) {return T(-r + 2*c); }, 0, 1, 3, 3}, - {11, 13, [](rotgen::Index r, rotgen::Index c) {return T(std::tan(r+c)); }, 1, 1, 2, 2}, - {4, 1, [](rotgen::Index , rotgen::Index ) {return T(7.0); }, 2, 0, 2, 1}, - {1, 1, [](rotgen::Index , rotgen::Index ) {return T(42.0); }, 0, 0, 1, 1}, - {12, 13, [](rotgen::Index r, rotgen::Index c) {return T(std::sin(r + c)); }, 2, 3, 4, 5 }, - {4, 9, [](rotgen::Index r, rotgen::Index c) {return T(-1.5 * r + 2.56 * c); }, 0, 1, 2, 3 }, - {2, 5, [](rotgen::Index r, rotgen::Index c) {return T(r == c ? 1.0 : 0.0); }, 1, 1, 1, 1}, - }; - - for (const auto& test_case : test_cases) - test_dynamic_block_reductions(test_case); + auto const cases = rotgen::tests::generate_block_references(); + for (const auto& [matrix_desc, i0, j0, ni, nj] : cases) + { + auto[rows,cols,fn] = matrix_desc; + rotgen::matrix m(rows, cols); + rotgen::tests::prepare(rows,cols,fn,m); + auto input = rotgen::extract(m, i0, j0, ni, nj); + rotgen::tests::check_shape_functions(input); + } +}; + +TTS_CASE_TPL("Test static block transposition-like operations", rotgen::tests::types) +( tts::type< tts::types> ) +{ + auto const cases = rotgen::tests::generate_static_block_references(); + + auto process = [](D const& d) + { + auto[desc,i0,j0] = d; + auto[rows,cols,fn] = desc; + rotgen::matrix m(rows, cols); + rotgen::tests::prepare(rows,cols,fn,m); + auto input = rotgen::extract(m, i0, j0); + rotgen::tests::check_shape_functions(input); + }; + + std::apply([&](auto const&... d) { (process(d),...);}, cases); +}; + +TTS_CASE_TPL("Test dynamic block reduction-like operations", rotgen::tests::types) +( tts::type< tts::types> ) +{ + auto const cases = rotgen::tests::generate_block_references(); + for (const auto& [matrix_desc, i0, j0, ni, nj] : cases) + { + auto[rows,cols,fn] = matrix_desc; + rotgen::matrix m(rows, cols); + rotgen::tests::prepare(rows,cols,fn,m); + auto input = rotgen::extract(m, i0, j0, ni, nj); + rotgen::tests::check_reduction_functions(input); + } +}; + +TTS_CASE_TPL("Test static block reduction-like operations", rotgen::tests::types) +( tts::type< tts::types> ) +{ + auto const cases = rotgen::tests::generate_static_block_references(); + + auto process = [](D const& d) + { + auto[desc,i0,j0] = d; + auto[rows,cols,fn] = desc; + rotgen::matrix m(rows, cols); + rotgen::tests::prepare(rows,cols,fn,m); + auto input = rotgen::extract(m, i0, j0); + rotgen::tests::check_reduction_functions(input); + }; + + std::apply([&](auto const&... d) { (process(d),...);}, cases); }; diff --git a/test/unit/block/basic_api.cpp b/test/unit/block/basic_api.cpp new file mode 100644 index 0000000..5ab9774 --- /dev/null +++ b/test/unit/block/basic_api.cpp @@ -0,0 +1,104 @@ +//================================================================================================== +/* + ROTGEN - Runtime Overlay for Eigen + Copyright : CODE RECKONS + SPDX-License-Identifier: BSL-1.0 +*/ +//================================================================================================== +#include "unit/tests.hpp" +#include + +TTS_CASE_TPL("Function size", rotgen::tests::types) +(tts::type>) +{ + T data[] = {1,2,3,4,5,6,7,8,9,10,11,12}; + + // Helper: fill matrix from raw data + auto fill = [&](auto& m, int r, int c) { + for(int k = 0; k < r * c; ++k) m.data()[k] = data[k]; + }; + + // 1x12 dynamic block at (0,0) + rotgen::matrix dm(1,12); + fill(dm,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); + 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); + TTS_EQUAL(b3.rows(), rotgen::Index{3}); + TTS_EQUAL(b3.cols(), rotgen::Index{2}); + TTS_EQUAL(b3.size(), rotgen::Index{6}); + + // 3x4 static block + rotgen::matrix sm; + fill(sm,3,4); + 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}); + + // 6x2 static block + rotgen::matrix sm2; + fill(sm2,6,2); + 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}); +}; + +TTS_CASE_TPL("Test coefficient accessors", rotgen::tests::types) +( tts::type< tts::types> ) +{ + using base = rotgen::matrix; + + T data[] = {1,2,3,4,5,6,7,8,9,10,11,12}; + 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); + for(rotgen::Index i=0;i<4;i++) + { + for(rotgen::Index j=0;j<3;j++) + { + if constexpr(O::value) TTS_EQUAL(b(i,j), data[j+3*i]); + else TTS_EQUAL(b(i,j), data[i+4*j]); + } + } + + b(1, 1) = 42; + TTS_EQUAL(b(1,1), 42); + + T& ref = b(2, 2); + ref = 17; + TTS_EQUAL(b(2, 2), 17); +}; + +TTS_CASE_TPL("Test one index coefficient accessors", rotgen::tests::types) +( tts::type< tts::types> ) +{ + using base = rotgen::matrix; + + T data[] = {1,2,3,4,5,6,7,8,9,10,11,12}; + 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); + for(rotgen::Index i=0;i MatrixType make_initialized_matrix(rotgen::tests::matrix_block_test_case const& matrix_construct) { - MatrixType matrix(matrix_construct.rows, matrix_construct.cols); + auto[d,i0,j0,ni,nj] = matrix_construct; + auto[r,c,fn] = d; - for(rotgen::Index i = 0; i < matrix_construct.rows; ++i) - for(rotgen::Index j = 0; j < matrix_construct.cols; ++j) - matrix(i, j) = static_cast(matrix_construct.init_fn(i, j)); + MatrixType matrix(r, c); + + for(rotgen::Index i = 0; i < r; ++i) + for(rotgen::Index j = 0; j < c; ++j) + matrix(i, j) = static_cast(fn(i, j)); return matrix; } @@ -127,31 +130,34 @@ void test_dynamic_block_extraction(rotgen::tests::matrix_block_test_case void test_static_block_extraction(rotgen::tests::static_matrix_block_test_case const& matrix_construct) { - MatrixType matrix(matrix_construct.rows, matrix_construct.cols); + auto[d,i0,j0] = matrix_construct; + auto[r,c,fn] = d; - for (rotgen::Index i = 0; i < matrix_construct.rows; ++i) - for (rotgen::Index j = 0; j < matrix_construct.cols; ++j) - matrix(i, j) = static_cast(matrix_construct.init_fn(i, j)); + MatrixType matrix(r,c); - auto block_main = rotgen::extract(matrix, matrix_construct.i0, matrix_construct.j0); + for (rotgen::Index i = 0; i < r; ++i) + for (rotgen::Index j = 0; j < c; ++j) + matrix(i, j) = static_cast(fn(i, j)); + + 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, matrix_construct.i0); + 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, matrix_construct.j0); + auto block_middle_cols = rotgen::middleCols(matrix, j0); auto block_right_cols = rotgen::rightCols(matrix); - auto block_row = rotgen::row(matrix, matrix_construct.i0); - auto block_col = rotgen::col(matrix, matrix_construct.j0); + auto block_row = rotgen::row(matrix, i0); + auto block_col = rotgen::col(matrix, j0); auto blocks = std::make_tuple( - std::make_tuple(block_main, matrix_construct.i0, matrix_construct.j0, + std::make_tuple(block_main, i0, j0, matrix_construct.ni, matrix_construct.nj, int(NI), int(NJ), -1), std::make_tuple(block_top_left_corner, 0, 0, matrix_construct.ni, matrix_construct.nj, int(NI), int(NJ), -1), @@ -164,20 +170,20 @@ void test_static_block_extraction(rotgen::tests::static_matrix_block_test_case; std::vector> cases = { - { 6, 11, [](rotgen::Index i, rotgen::Index j) { return T(i * 10 + j); }, 1, 2, 3, 2 }, - { 7, 10, [](rotgen::Index i, rotgen::Index j) { return T(std::sin(i + j)); }, 4, 4, 3, 3 }, - { 5, 5, [](rotgen::Index i, rotgen::Index j) { return T((i + j) % 7); }, 0, 0, 5, 5 }, - { 9, 14, [](rotgen::Index i, rotgen::Index j) { return T(i+j + 3*j); }, 3, 7, 1, 1 } + { {6, 11, [](rotgen::Index i, rotgen::Index j) { return T(i * 10 + j); }}, 1, 2, 3, 2 }, + { {7, 10, [](rotgen::Index i, rotgen::Index j) { return T(std::sin(i + j)); }}, 4, 4, 3, 3 }, + { {5, 5, [](rotgen::Index i, rotgen::Index j) { return T((i + j) % 7); }}, 0, 0, 5, 5 }, + { {9, 14, [](rotgen::Index i, rotgen::Index j) { return T(i+j + 3*j); }}, 3, 7, 1, 1 } }; for (auto const& matrix_case : cases) { test_dynamic_block_extraction(matrix_case); } - }; TTS_CASE_TPL("Check all dynamic block extractions on a static column-major matrix", rotgen::tests::types) @@ -223,9 +228,9 @@ TTS_CASE_TPL("Check all dynamic block extractions on a static column-major matri using mat_t = rotgen::matrix; std::vector> cases = { - { 4, 5, [](auto i, auto j) { return T(2*i + j*j*j - 42); }, 1, 2, 3, 2 }, - { 4, 5, [](auto i, auto j) { return T(std::tan(i*i*j)); }, 0, 1, 2, 1 }, - { 4, 5, [](auto i, auto j) { return T((i*i + j*j) / 6); }, 2, 0, 0, 0 } + { {4, 5, [](auto i, auto j) { return T(2*i + j*j*j - 42); } }, 1, 2, 3, 2 }, + { {4, 5, [](auto i, auto j) { return T(std::tan(i*i*j)); } }, 0, 1, 2, 1 }, + { {4, 5, [](auto i, auto j) { return T((i*i + j*j) / 6); } }, 2, 0, 0, 0 } }; for (auto const& matrix_case : cases) { @@ -241,24 +246,21 @@ TTS_CASE_TPL("Check all static block extractions", rotgen::tests::types) test_static_block_extraction( rotgen::tests::static_matrix_block_test_case{ - 11, 11, - [](rotgen::Index i, rotgen::Index j) { return T(i*i*i + 3*j - 127); }, + {11, 11, [](rotgen::Index i, rotgen::Index j) { return T(i*i*i + 3*j - 127); } }, 3, 2 } ); test_static_block_extraction( rotgen::tests::static_matrix_block_test_case{ - 14, 15, - [](rotgen::Index i, rotgen::Index j) { return T(std::cos(i * j * 2)); }, + {14, 15,[](rotgen::Index i, rotgen::Index j) { return T(std::cos(i * j * 2)); }}, 5, 1 } ); test_static_block_extraction( rotgen::tests::static_matrix_block_test_case{ - 5, 5, - [](rotgen::Index i, rotgen::Index j) { return T((i + j) % 9); }, + {5, 5,[](rotgen::Index i, rotgen::Index j) { return T((i + j) % 9); }}, 0, 0 } ); diff --git a/test/unit/block/generators.cpp b/test/unit/block/generators.cpp new file mode 100644 index 0000000..ac0d071 --- /dev/null +++ b/test/unit/block/generators.cpp @@ -0,0 +1,268 @@ +//================================================================================================== +/* + ROTGEN - Runtime Overlay for Eigen + Copyright : CODE RECKONS + SPDX-License-Identifier: BSL-1.0 +*/ +//================================================================================================== +#include "unit/tests.hpp" +#include + +void test_value ( const auto& matrix, auto value + , rotgen::Index i0, rotgen::Index j0 + , rotgen::Index rows, rotgen::Index cols + ) +{ + for(rotgen::Index r=0;r( tts::type< tts::types>) +{ + auto const cases = rotgen::tests::generate_block_references(); + for (const auto& [matrix_desc, i0, j0, ni, nj] : cases) + { + auto[rows,cols,fn] = matrix_desc; + rotgen::matrix m(rows, cols); + rotgen::tests::prepare(rows,cols,fn,m); + auto input = rotgen::extract(m, i0, j0, ni, nj); + + input.setZero(); + test_value(m,T{0},i0,j0,ni,nj); + + using input_type = decltype(rotgen::extract(m, i0, j0, ni, nj)); + auto values = input_type::Zero(ni,nj); + test_value(values,T{0},0,0,ni,nj); + } +}; + +TTS_CASE_TPL("Test static block:setZero", rotgen::tests::types) +( tts::type< tts::types> ) +{ + auto const cases = rotgen::tests::generate_static_block_references(); + + auto process = [](D const& d) + { + auto[desc,i0,j0] = d; + auto[rows,cols,fn] = desc; + + rotgen::matrix m(rows, cols); + rotgen::tests::prepare(rows,cols,fn,m); + auto input = rotgen::extract(m, i0, j0); + + input.setZero(); + test_value(m,T{0},i0,j0,D::ni,D::nj); + + using input_type = decltype(rotgen::extract(m, i0, j0)); + auto values = input_type::Zero(); + test_value(values,T{0},0,0,D::ni,D::nj); + }; + + std::apply([&](auto const&... d) { (process(d),...);}, cases); +}; + +TTS_CASE_TPL("Test dynamic block::setOnes", rotgen::tests::types) +( tts::type< tts::types>) +{ + auto const cases = rotgen::tests::generate_block_references(); + for (const auto& [matrix_desc, i0, j0, ni, nj] : cases) + { + auto[rows,cols,fn] = matrix_desc; + rotgen::matrix m(rows, cols); + rotgen::tests::prepare(rows,cols,fn,m); + auto input = rotgen::extract(m, i0, j0, ni, nj); + + input.setOnes(); + test_value(m,T{1},i0,j0,ni,nj); + + using input_type = decltype(rotgen::extract(m, i0, j0, ni, nj)); + auto values = input_type::Ones(ni,nj); + test_value(values,T{1},0,0,ni,nj); + } +}; + +TTS_CASE_TPL("Test static block:setOnes", rotgen::tests::types) +( tts::type< tts::types> ) +{ + auto const cases = rotgen::tests::generate_static_block_references(); + + auto process = [](D const& d) + { + auto[desc,i0,j0] = d; + auto[rows,cols,fn] = desc; + + rotgen::matrix m(rows, cols); + rotgen::tests::prepare(rows,cols,fn,m); + auto input = rotgen::extract(m, i0, j0); + + input.setOnes(); + test_value(m,T{1},i0,j0,D::ni,D::nj); + + using input_type = decltype(rotgen::extract(m, i0, j0)); + auto values = input_type::Ones(); + test_value(values,T{1},0,0,D::ni,D::nj); + }; + + std::apply([&](auto const&... d) { (process(d),...);}, cases); +}; + +TTS_CASE_TPL("Test dynamic block::setConstant", rotgen::tests::types) +( tts::type< tts::types>) +{ + auto const cases = rotgen::tests::generate_block_references(); + for (const auto& [matrix_desc, i0, j0, ni, nj] : cases) + { + auto[rows,cols,fn] = matrix_desc; + rotgen::matrix m(rows, cols); + rotgen::tests::prepare(rows,cols,fn,m); + auto input = rotgen::extract(m, i0, j0, ni, nj); + + input.setConstant(T{13.37f}); + test_value(m,T{13.37f},i0,j0,ni,nj); + + using input_type = decltype(rotgen::extract(m, i0, j0, ni, nj)); + auto values = input_type::Constant(ni,nj,T{13.37f}); + test_value(values,T{13.37f},0,0,ni,nj); + } +}; + +TTS_CASE_TPL("Test static block:setConstant", rotgen::tests::types) +( tts::type< tts::types> ) +{ + auto const cases = rotgen::tests::generate_static_block_references(); + + auto process = [](D const& d) + { + auto[desc,i0,j0] = d; + auto[rows,cols,fn] = desc; + + rotgen::matrix m(rows, cols); + rotgen::tests::prepare(rows,cols,fn,m); + auto input = rotgen::extract(m, i0, j0); + + input.setConstant(T{13.37f}); + test_value(m,T{13.37f},i0,j0,D::ni,D::nj); + + using input_type = decltype(rotgen::extract(m, i0, j0)); + auto values = input_type::Constant(T{13.37f}); + test_value(values,T{13.37f},0,0,D::ni,D::nj); + }; + + std::apply([&](auto const&... d) { (process(d),...);}, cases); +}; + +TTS_CASE_TPL("Test dynamic block::setIdentity", rotgen::tests::types) +( tts::type< tts::types>) +{ + auto const cases = rotgen::tests::generate_block_references(); + for (const auto& [matrix_desc, i0, j0, ni, nj] : cases) + { + auto[rows,cols,fn] = matrix_desc; + rotgen::matrix m(rows, cols); + rotgen::tests::prepare(rows,cols,fn,m); + auto input = rotgen::extract(m, i0, j0, ni, nj); + + input.setIdentity(); + test_identity(m,i0,j0,ni,nj); + + using input_type = decltype(rotgen::extract(m, i0, j0, ni, nj)); + auto values = input_type::Identity(ni,nj); + test_identity(values,0,0,ni,nj); + } +}; + +TTS_CASE_TPL("Test static block:setIdentity", rotgen::tests::types) +( tts::type< tts::types> ) +{ + auto const cases = rotgen::tests::generate_static_block_references(); + + auto process = [](D const& d) + { + auto[desc,i0,j0] = d; + auto[rows,cols,fn] = desc; + + rotgen::matrix m(rows, cols); + rotgen::tests::prepare(rows,cols,fn,m); + auto input = rotgen::extract(m, i0, j0); + + input.setIdentity(); + test_identity(m,i0,j0,D::ni,D::nj); + + using input_type = decltype(rotgen::extract(m, i0, j0)); + auto values = input_type::Identity(); + test_identity(values,0,0,D::ni,D::nj); + }; + + std::apply([&](auto const&... d) { (process(d),...);}, cases); +}; + +TTS_CASE_TPL("Test dynamic block::setRandom", rotgen::tests::types) +( tts::type< tts::types>) +{ + auto const cases = rotgen::tests::generate_block_references(); + for (const auto& [matrix_desc, i0, j0, ni, nj] : cases) + { + auto[rows,cols,fn] = matrix_desc; + rotgen::matrix m(rows, cols); + rotgen::tests::prepare(rows,cols,fn,m); + auto input = rotgen::extract(m, i0, j0, ni, nj); + + input.setRandom(); + test_random(m,i0,j0,ni,nj); + + using input_type = decltype(rotgen::extract(m, i0, j0, ni, nj)); + auto values = input_type::Random(ni,nj); + test_random(values,0,0,ni,nj); + } +}; + + +TTS_CASE_TPL("Test static block:setRandom", rotgen::tests::types) +( tts::type< tts::types> ) +{ + auto const cases = rotgen::tests::generate_static_block_references(); + + auto process = [](D const& d) + { + auto[desc,i0,j0] = d; + auto[rows,cols,fn] = desc; + + rotgen::matrix m(rows, cols); + rotgen::tests::prepare(rows,cols,fn,m); + auto input = rotgen::extract(m, i0, j0); + + input.setRandom(); + test_random(m,i0,j0,D::ni,D::nj); + + using input_type = decltype(rotgen::extract(m, i0, j0)); + auto values = input_type::Random(); + test_random(values,0,0,D::ni,D::nj); + }; + + std::apply([&](auto const&... d) { (process(d),...);}, cases); +}; \ No newline at end of file diff --git a/test/unit/block/norms.cpp b/test/unit/block/norms.cpp index f0e466b..0752910 100644 --- a/test/unit/block/norms.cpp +++ b/test/unit/block/norms.cpp @@ -6,43 +6,37 @@ */ //================================================================================================== #include "unit/tests.hpp" +#include "unit/common/norms.hpp" #include -#include -TTS_CASE_TPL("Matrix norm-related operations", rotgen::tests::types) +TTS_CASE_TPL("Test dynamic block norm operations", rotgen::tests::types) ( tts::type< tts::types> ) { - using mat_t = rotgen::matrix; - - std::vector> test_cases = - { - {6, 5, [](rotgen::Index r, rotgen::Index c) {return r + c; }, 1, 2, 3, 2}, - {9, 11, [](rotgen::Index r, rotgen::Index c) {return r + c; }, 0, 1, 4, 9}, - {3, 3, [](rotgen::Index , rotgen::Index ) {return 0.0; }, 1, 1, 1, 1}, - {1, 4, [](rotgen::Index r, rotgen::Index c) {return -r -c*c - 1234; }, 0, 0, 1, 1}, - {4, 1, [](rotgen::Index , rotgen::Index ) {return 7.0; }, 2, 0, 2, 1}, - {1, 1, [](rotgen::Index , rotgen::Index ) {return 42.0; }, 0, 0, 1, 1}, - {12, 13, [](rotgen::Index r, rotgen::Index c) {return std::sin(r + c); }, 2, 3, 4, 5 }, - {4, 9, [](rotgen::Index r, rotgen::Index c) {return -1.5 * r + 2.56 * c; }, 0, 1, 2, 3 }, - {2, 5, [](rotgen::Index r, rotgen::Index c) {return (r == c ? 1.0 : 0.0); }, 1, 1, 1, 1}, - }; - - for (const auto& [rows, cols, fn, i0, j0, ni, nj] : test_cases) + auto const cases = rotgen::tests::generate_block_references(); + for (const auto& [matrix_desc, i0, j0, ni, nj] : cases) { - rotgen::matrix original_matrix(rows, cols); - Eigen::Matrix ref_matrix(rows, cols); - - for (rotgen::Index r = 0; r < rows; ++r) - for (rotgen::Index c = 0; c < cols; ++c) - ref_matrix(r, c) = original_matrix(r, c) = fn(r,c); - - auto original_block = rotgen::extract(original_matrix, i0, j0, ni, nj); - auto ref_block = ref_matrix.block(i0, j0, ni, nj); - - TTS_EQUAL(original_block.norm(), ref_block.norm()); - TTS_EQUAL(original_block.squaredNorm(), ref_block.squaredNorm()); - TTS_EQUAL(original_block.template lpNorm<1>() , ref_block.template lpNorm<1>()); - TTS_EQUAL(original_block.template lpNorm<2>() , ref_block.template lpNorm<2>()); - TTS_EQUAL(original_block.template lpNorm(), ref_block.template lpNorm()); + auto[rows,cols,fn] = matrix_desc; + rotgen::matrix m(rows, cols); + rotgen::tests::prepare(rows,cols,fn,m); + auto input = rotgen::extract(m, i0, j0, ni, nj); + rotgen::tests::check_norms_functions(input); } -}; \ No newline at end of file +}; + +TTS_CASE_TPL("Test static block norm operations", rotgen::tests::types) +( tts::type< tts::types> ) +{ + auto const cases = rotgen::tests::generate_static_block_references(); + + auto process = [](D const& d) + { + auto[desc,i0,j0] = d; + auto[rows,cols,fn] = desc; + rotgen::matrix m(rows, cols); + rotgen::tests::prepare(rows,cols,fn,m); + auto input = rotgen::extract(m, i0, j0); + rotgen::tests::check_norms_functions(input); + }; + + std::apply([&](auto const&... d) { (process(d),...);}, cases); +}; diff --git a/test/unit/block/operators.cpp b/test/unit/block/operators.cpp index f135e59..cac0fe4 100644 --- a/test/unit/block/operators.cpp +++ b/test/unit/block/operators.cpp @@ -15,51 +15,50 @@ void test_block_matrix_operations(rotgen::tests::matrix_block_test_case; - MatrixType a(matrix_construct.rows, matrix_construct.cols); - MatrixType b(matrix_construct.rows, matrix_construct.cols); - EigenMatrix ref_a(matrix_construct.rows, matrix_construct.cols); - EigenMatrix ref_b(matrix_construct.rows, matrix_construct.cols); + auto[d,i0,j0,ni,nj] = matrix_construct; + auto[r,c,fn] = d; + + MatrixType a(r, c); + MatrixType b(r, c); + EigenMatrix ref_a(r, c); + EigenMatrix ref_b(r, c); TTS_EXPECT(verify_rotgen_reentrance(ops(a,b))); - for (rotgen::Index r = 0; r < matrix_construct.rows; ++r) + for (rotgen::Index rr = 0; rr < r; ++rr) { - for (rotgen::Index c = 0; c < matrix_construct.cols; ++c) + for (rotgen::Index cc = 0; cc < c; ++cc) { - ref_a(r,c) = a(r,c) = static_cast(matrix_construct.init_fn(r, c)); - ref_b(r,c) = b(r,c) = static_cast(b_init_fn(r, c)); + ref_a(rr,cc) = a(rr,cc) = static_cast(fn(rr,cc)); + ref_b(rr,cc) = b(rr,cc) = static_cast(b_init_fn(rr,cc)); } } - auto a_block = rotgen::extract(a, matrix_construct.i0, matrix_construct.j0, - matrix_construct.ni, matrix_construct.nj); - auto b_block = rotgen::extract(b, matrix_construct.i0, matrix_construct.j0, - matrix_construct.ni, matrix_construct.nj); - auto ref_a_block = ref_a.block(matrix_construct.i0, matrix_construct.j0, - matrix_construct.ni, matrix_construct.nj); - auto ref_b_block = ref_b.block(matrix_construct.i0, matrix_construct.j0, - matrix_construct.ni, matrix_construct.nj); + auto a_block = rotgen::extract(a, i0, j0,ni, nj); + auto b_block = rotgen::extract(b, i0, j0,ni, nj); + auto ref_a_block = ref_a.block(i0, j0,ni, nj); + auto ref_b_block = ref_b.block(i0, j0,ni, nj); auto result_block = ops(a_block, b_block); auto ref_result_block = ops(ref_a_block, ref_b_block); - for (rotgen::Index r = 0; r < matrix_construct.ni; ++r) - for (rotgen::Index c = 0; c < matrix_construct.nj; ++c) - TTS_EQUAL(result_block(r, c), ref_result_block(r, c)); + for (rotgen::Index rr = 0; rr < ni; ++rr) + for (rotgen::Index cc = 0; cc < nj; ++cc) + TTS_EQUAL(result_block(rr, cc), ref_result_block(rr, cc)); self_ops(a_block,b_block); self_ops(ref_a_block, ref_b_block); - for (rotgen::Index r = 0; r < matrix_construct.ni; ++r) - for (rotgen::Index c = 0; c < matrix_construct.nj; ++c) - TTS_EQUAL(a_block(r, c), ref_a_block(r, c)); + for (rotgen::Index rr = 0; rr < ni; ++rr) + for (rotgen::Index cc = 0; cc < nj; ++cc) + TTS_EQUAL(a_block(rr, cc), ref_a_block(rr, cc)); - for (rotgen::Index r = 0; r < matrix_construct.rows; ++r) + for (rotgen::Index rr = 0; rr < ni; ++rr) { - for (rotgen::Index c = 0; c < matrix_construct.cols; ++c) + for (rotgen::Index cc = 0; cc < nj; ++cc) { - TTS_EQUAL(a(r, c), ref_a(r, c)); - TTS_EQUAL(b(r, c), ref_b(r, c)); + TTS_EQUAL(a(rr, cc), ref_a(rr, cc)); + TTS_EQUAL(b(rr, cc), ref_b(rr, cc)); } } } @@ -70,36 +69,37 @@ void test_block_scalar_operations(rotgen::tests::matrix_block_test_case; - MatrixType a(matrix_construct.rows, matrix_construct.cols); - EigenMatrix ref_a(matrix_construct.rows, matrix_construct.cols); + auto[d,i0,j0,ni,nj] = matrix_construct; + auto[rows,cols,fn] = d; + + MatrixType a(rows, cols); + EigenMatrix ref_a(rows, cols); TTS_EXPECT(verify_rotgen_reentrance(ops(a,scalar))); - for (rotgen::Index r = 0; r < matrix_construct.rows; ++r) - for (rotgen::Index c = 0; c < matrix_construct.cols; ++c) - ref_a(r,c) = a(r,c) = static_cast(matrix_construct.init_fn(r, c)); + for (rotgen::Index r = 0; r < rows; ++r) + for (rotgen::Index c = 0; c < cols; ++c) + ref_a(r,c) = a(r,c) = static_cast(fn(r, c)); - auto a_block = rotgen::extract(a, matrix_construct.i0, matrix_construct.j0, - matrix_construct.ni, matrix_construct.nj); - auto ref_a_block = ref_a.block(matrix_construct.i0, matrix_construct.j0, - matrix_construct.ni, matrix_construct.nj); + auto a_block = rotgen::extract(a, i0, j0,ni, nj); + auto ref_a_block = ref_a.block(i0, j0,ni, nj); auto result = ops(a_block, scalar); auto ref_result = ops(ref_a_block, scalar); - for (rotgen::Index r = 0; r < matrix_construct.ni; ++r) - for (rotgen::Index c = 0; c < matrix_construct.nj; ++c) + for (rotgen::Index r = 0; r < ni; ++r) + for (rotgen::Index c = 0; c < nj; ++c) TTS_EQUAL(result(r, c), ref_result(r, c)); self_ops(a_block,scalar); self_ops(ref_a_block, scalar); - for (rotgen::Index r = 0; r < matrix_construct.ni; ++r) - for (rotgen::Index c = 0; c < matrix_construct.nj; ++c) + for (rotgen::Index r = 0; r < ni; ++r) + for (rotgen::Index c = 0; c < nj; ++c) TTS_EQUAL(a_block(r, c), ref_a_block(r, c)); - for (rotgen::Index r = 0; r < matrix_construct.rows; ++r) - for (rotgen::Index c = 0; c < matrix_construct.cols; ++c) + for (rotgen::Index r = 0; r < rows; ++r) + for (rotgen::Index c = 0; c < cols; ++c) TTS_EQUAL(a(r, c), ref_a(r, c)); } @@ -109,29 +109,32 @@ void test_scalar_block_multiplications(rotgen::tests::matrix_block_test_case; - MatrixType a(matrix_construct.rows, matrix_construct.cols); - EigenMatrix ref_a(matrix_construct.rows, matrix_construct.cols); + auto[d,i0,j0,ni,nj] = matrix_construct; + auto[rows,cols,fn] = d; + + MatrixType a(rows, cols); + EigenMatrix ref_a(rows, cols); TTS_EXPECT(verify_rotgen_reentrance(a * scalar)); TTS_EXPECT(verify_rotgen_reentrance(scalar * a)); - for (rotgen::Index r = 0; r < matrix_construct.rows; ++r) - for (rotgen::Index c = 0; c < matrix_construct.cols; ++c) - ref_a(r,c) = a(r,c) = static_cast(matrix_construct.init_fn(r, c)); + for (rotgen::Index r = 0; r < rows; ++r) + for (rotgen::Index c = 0; c < cols; ++c) + ref_a(r,c) = a(r,c) = static_cast(fn(r, c)); - auto a_block = rotgen::extract(a, matrix_construct.i0, matrix_construct.j0, - matrix_construct.ni, matrix_construct.nj); - auto ref_a_block = ref_a.block(matrix_construct.i0, matrix_construct.j0, - matrix_construct.ni, matrix_construct.nj); + auto a_block = rotgen::extract(a, i0, j0, + ni, nj); + auto ref_a_block = ref_a.block(i0, j0, + ni, nj); auto a_scalar_multiplication = a_block * scalar; auto scalar_a_multiplication = scalar * a_block; auto a_scalar_multiplication_ref = ref_a_block * scalar; auto scalar_a_multiplication_ref = scalar * ref_a_block; - for (rotgen::Index r = 0; r < matrix_construct.ni; ++r) + for (rotgen::Index r = 0; r < ni; ++r) { - for (rotgen::Index c = 0; c < matrix_construct.nj; ++c) + for (rotgen::Index c = 0; c < nj; ++c) { TTS_EQUAL(a_scalar_multiplication (r, c), a_scalar_multiplication_ref(r, c)); TTS_EQUAL(scalar_a_multiplication(r, c), scalar_a_multiplication_ref(r, c)); @@ -141,12 +144,12 @@ void test_scalar_block_multiplications(rotgen::tests::matrix_block_test_case { using EigenMatrix = Eigen::Matrix; - MatrixType a(a_matrix_construct.rows, a_matrix_construct.cols); - MatrixType b(b_matrix_construct.rows, b_matrix_construct.cols); - EigenMatrix ref_a(a_matrix_construct.rows, a_matrix_construct.cols); - EigenMatrix ref_b(b_matrix_construct.rows, b_matrix_construct.cols); + auto[a_d,a_i0,a_j0,a_ni,a_nj] = a_matrix_construct; + auto[a_rows,a_cols,a_fn] = a_d; - for (rotgen::Index r = 0; r < a_matrix_construct.rows; ++r) - for (rotgen::Index c = 0; c < a_matrix_construct.cols; ++c) - ref_a(r,c) = a(r,c) = static_cast(a_matrix_construct.init_fn(r, c)); - - for (rotgen::Index r = 0; r < b_matrix_construct.rows; ++r) - for (rotgen::Index c = 0; c < b_matrix_construct.cols; ++c) - ref_b(r,c) = b(r,c) = static_cast(b_matrix_construct.init_fn(r, c)); + auto[b_d,b_i0,b_j0,b_ni,b_nj] = b_matrix_construct; + auto[b_rows,b_cols,b_fn] = b_d; - auto a_block = rotgen::extract(a, a_matrix_construct.i0, a_matrix_construct.j0, - a_matrix_construct.ni, a_matrix_construct.nj); - auto b_block = rotgen::extract(b, b_matrix_construct.i0, b_matrix_construct.j0, - b_matrix_construct.ni, b_matrix_construct.nj); - auto ref_a_block = ref_a.block(a_matrix_construct.i0, a_matrix_construct.j0, - a_matrix_construct.ni, a_matrix_construct.nj); - auto ref_b_block = ref_b.block(b_matrix_construct.i0, b_matrix_construct.j0, - b_matrix_construct.ni, b_matrix_construct.nj); + MatrixType a(a_rows, a_cols); + MatrixType b(b_rows, b_cols); + EigenMatrix ref_a(a_rows, a_cols); + EigenMatrix ref_b(b_rows, b_cols); + + for (rotgen::Index r = 0; r < a_rows; ++r) + for (rotgen::Index c = 0; c < a_cols; ++c) + ref_a(r,c) = a(r,c) = static_cast(a_fn(r, c)); + + for (rotgen::Index r = 0; r < b_rows; ++r) + for (rotgen::Index c = 0; c < b_cols; ++c) + ref_b(r,c) = b(r,c) = static_cast(b_fn(r, c)); + + + auto a_block = rotgen::extract(a, a_i0, a_j0,a_ni, a_nj); + auto b_block = rotgen::extract(b, b_i0, b_j0,b_ni, b_nj); + auto ref_a_block = ref_a.block(a_i0, a_j0,a_ni, a_nj); + auto ref_b_block = ref_b.block(b_i0, b_j0,b_ni, b_nj); TTS_EXPECT(verify_rotgen_reentrance(a_block * b_block)); auto a_b_product_original = a_block * b_block; auto a_b_product_ref = ref_a_block * ref_b_block; - for (rotgen::Index r = 0; r < a_matrix_construct.ni; ++r) - for (rotgen::Index c = 0; c < a_matrix_construct.nj; ++c) + for (rotgen::Index r = 0; r < a_ni; ++r) + for (rotgen::Index c = 0; c < a_nj; ++c) TTS_EQUAL(a_b_product_original (r, c), a_b_product_ref(r, c)); a_block *= b_block; ref_a_block *= ref_b_block; - for (rotgen::Index r = 0; r < a_matrix_construct.ni; ++r) - for (rotgen::Index c = 0; c < a_matrix_construct.nj; ++c) + for (rotgen::Index r = 0; r < a_ni; ++r) + for (rotgen::Index c = 0; c < a_nj; ++c) TTS_EQUAL(a_block(r, c), ref_a_block(r, c)); - for (rotgen::Index r = 0; r < a_matrix_construct.rows; ++r) - for (rotgen::Index c = 0; c < a_matrix_construct.cols; ++c) + for (rotgen::Index r = 0; r < a_rows; ++r) + for (rotgen::Index c = 0; c < a_cols; ++c) TTS_EQUAL(a(r, c), ref_a(r, c)); - for (rotgen::Index r = 0; r < b_matrix_construct.rows; ++r) - for (rotgen::Index c = 0; c < b_matrix_construct.cols; ++c) + for (rotgen::Index r = 0; r < b_rows; ++r) + for (rotgen::Index c = 0; c < b_cols; ++c) TTS_EQUAL(b(r, c), ref_b(r, c)); } @@ -216,18 +222,17 @@ TTS_CASE_TPL("Check block addition", rotgen::tests::types) auto op = [](auto a, auto b) { return a + b; }; auto s_op = [](auto& a, auto b) { return a += b; }; - test_block_matrix_operations({1 , 1, init_a, 0, 0, 1, 1}, init_b, op, s_op); - test_block_matrix_operations({13 , 15, init_a, 1, 2, 3, 4}, init_b, op, s_op); - test_block_matrix_operations({5 , 9, init_a, 2, 2, 2, 2}, init_b, op, s_op); - test_block_matrix_operations({15 , 15, init_a, 3, 4, 5, 5}, init_b, op, s_op); - test_block_matrix_operations({5 , 5, init_b, 1, 0, 3, 2}, init_a, op, s_op); - test_block_matrix_operations({10, 1, init_a, 0, 0, 5, 1}, init_b, op, s_op); - test_block_matrix_operations({1 , 10, init_a, 0, 0, 1, 5}, init_b, op, s_op); - test_block_matrix_operations({21 , 5, init_0, 4, 4, 10, 1}, init_b, op, s_op); - test_block_matrix_operations({11 , 7, init_a, 2, 0, 7, 5}, init_0, op, s_op); + test_block_matrix_operations({{ 1, 1, init_a}, 0, 0, 1, 1}, init_b, op, s_op); + test_block_matrix_operations({{13, 15, init_a}, 1, 2, 3, 4}, init_b, op, s_op); + test_block_matrix_operations({{ 5, 9, init_a}, 2, 2, 2, 2}, init_b, op, s_op); + test_block_matrix_operations({{15, 15, init_a}, 3, 4, 5, 5}, init_b, op, s_op); + test_block_matrix_operations({{ 5, 5, init_b}, 1, 0, 3, 2}, init_a, op, s_op); + test_block_matrix_operations({{10, 1, init_a}, 0, 0, 5, 1}, init_b, op, s_op); + test_block_matrix_operations({{ 1, 10, init_a}, 0, 0, 1, 5}, init_b, op, s_op); + test_block_matrix_operations({{21, 5, init_0}, 4, 4, 10, 1}, init_b, op, s_op); + test_block_matrix_operations({{11, 7, init_a}, 2, 0, 7, 5}, init_0, op, s_op); }; - TTS_CASE_TPL("Check block subtraction", rotgen::tests::types) ( tts::type< tts::types> ) { @@ -235,36 +240,35 @@ TTS_CASE_TPL("Check block subtraction", rotgen::tests::types) auto op = [](auto a, auto b) { return a - b; }; auto s_op = [](auto& a, auto b) { return a -= b; }; - test_block_matrix_operations({1 , 1, init_a, 0, 0, 1, 1}, init_b, op, s_op); - test_block_matrix_operations({1 , 1, init_a, 0, 0, 1, 1}, init_b, op, s_op); - test_block_matrix_operations({13 , 15, init_a, 1, 2, 3, 4}, init_b, op, s_op); - test_block_matrix_operations({5 , 9, init_a, 2, 2, 2, 2}, init_b, op, s_op); - test_block_matrix_operations({15 , 15, init_a, 3, 4, 5, 5}, init_b, op, s_op); - test_block_matrix_operations({5 , 5, init_b, 1, 0, 3, 2}, init_a, op, s_op); - test_block_matrix_operations({10, 1, init_a, 0, 0, 5, 1}, init_b, op, s_op); - test_block_matrix_operations({1 , 10, init_a, 0, 0, 1, 5}, init_b,op, s_op); - test_block_matrix_operations({21 , 5, init_0, 4, 4, 10, 1}, init_b, op, s_op); - test_block_matrix_operations({11 , 7, init_a, 2, 0, 7, 5}, init_0, op, s_op); + test_block_matrix_operations({{ 1, 1, init_a}, 0, 0, 1, 1}, init_b, op, s_op); + test_block_matrix_operations({{ 1, 1, init_a}, 0, 0, 1, 1}, init_b, op, s_op); + test_block_matrix_operations({{13, 15, init_a}, 1, 2, 3, 4}, init_b, op, s_op); + test_block_matrix_operations({{ 5, 9, init_a}, 2, 2, 2, 2}, init_b, op, s_op); + test_block_matrix_operations({{15, 15, init_a}, 3, 4, 5, 5}, init_b, op, s_op); + test_block_matrix_operations({{ 5, 5, init_b}, 1, 0, 3, 2}, init_a, op, s_op); + test_block_matrix_operations({{10, 1, init_a}, 0, 0, 5, 1}, init_b, op, s_op); + test_block_matrix_operations({{ 1, 10, init_a}, 0, 0, 1, 5}, init_b,op, s_op); + test_block_matrix_operations({{21 , 5, init_0}, 4, 4, 10, 1}, init_b, op, s_op); + test_block_matrix_operations({{11 , 7, init_a}, 2, 0, 7, 5}, init_0, op, s_op); }; - TTS_CASE_TPL("Check block multiplications", rotgen::tests::types) ( tts::type< tts::types> ) { using mat_t = rotgen::matrix; auto init_id = [](rotgen::Index r, rotgen::Index c) { return r == c ? 1 : 0; }; - test_block_multiplication({1 , 1, init_a, 0, 0, 1, 1}, {1 , 1, init_b, 0, 0, 1, 1}); - test_block_multiplication({13 , 15, init_b, 1, 2, 4, 4}, {13 , 15, init_b, 0, 1, 4, 4}); - test_block_multiplication({6 , 9, init_a, 2, 2, 2, 2}, {5 , 9, init_b, 2, 2, 2, 2}); - test_block_multiplication({15 , 15, init_a, 3, 4, 5, 5}, {15 , 15, init_b, 0, 0, 5, 5}); - test_block_multiplication({5 , 5, init_b, 1, 0, 3, 3}, {5 , 5, init_a, 0, 0, 3, 3}); - test_block_multiplication({11 , 3, init_id, 2, 0, 2, 2}, {18 , 7, init_a, 2, 0, 2, 2}); - test_block_multiplication({10, 1, init_a, 0, 0, 1, 1}, {10, 1, init_a, 0, 0, 1, 1}); - test_block_multiplication({1 , 10, init_a, 0, 0, 1, 1}, {1 , 10, init_id, 0, 0, 1, 1}); - test_block_multiplication({21 , 5, init_0, 1, 1, 3, 3}, {12 , 7, init_0, 4, 4, 3, 3}); - test_block_multiplication({11 , 7, init_a, 2, 0, 7, 7}, {11 , 11, init_a, 2, 1, 7, 7}); - test_block_multiplication({11 , 7, init_a, 2, 0, 5, 5}, {11 , 12, init_id, 0, 0, 5, 5}); + test_block_multiplication({{ 1, 1, init_a }, 0, 0, 1, 1}, {{ 1, 1, init_b }, 0, 0, 1, 1}); + test_block_multiplication({{13, 15, init_b }, 1, 2, 4, 4}, {{13, 15, init_b }, 0, 1, 4, 4}); + test_block_multiplication({{ 6, 9, init_a }, 2, 2, 2, 2}, {{ 5, 9, init_b }, 2, 2, 2, 2}); + test_block_multiplication({{15, 15, init_a }, 3, 4, 5, 5}, {{15, 15, init_b }, 0, 0, 5, 5}); + test_block_multiplication({{ 5, 5, init_b }, 1, 0, 3, 3}, {{ 5, 5, init_a }, 0, 0, 3, 3}); + test_block_multiplication({{11, 3, init_id}, 2, 0, 2, 2}, {{18, 7, init_a }, 2, 0, 2, 2}); + test_block_multiplication({{10, 1, init_a }, 0, 0, 1, 1}, {{10, 1, init_a }, 0, 0, 1, 1}); + test_block_multiplication({{ 1, 10, init_a }, 0, 0, 1, 1}, {{ 1, 10, init_id}, 0, 0, 1, 1}); + test_block_multiplication({{21, 5, init_0 }, 1, 1, 3, 3}, {{12, 7, init_0 }, 4, 4, 3, 3}); + test_block_multiplication({{11, 7, init_a }, 2, 0, 7, 7}, {{11, 11, init_a }, 2, 1, 7, 7}); + test_block_multiplication({{11, 7, init_a }, 2, 0, 5, 5}, {{11, 12, init_id}, 0, 0, 5, 5}); }; TTS_CASE_TPL("Check block multiplication with scalar", rotgen::tests::types) @@ -272,15 +276,15 @@ TTS_CASE_TPL("Check block multiplication with scalar", rotgen::tests::types) { using mat_t = rotgen::matrix; - test_scalar_block_multiplications({1 , 1, init_a, 0, 0, 1, 1}, T{ 3.5}); - test_scalar_block_multiplications({13 , 15, init_a, 1, 2, 3, 4}, T{ 0.}); - test_scalar_block_multiplications({5 , 9, init_a, 2, 2, 2, 2}, T{-2.5}); - test_scalar_block_multiplications({15 , 15, init_a, 3, 4, 5, 5}, T{ 42. }); - test_scalar_block_multiplications({5 , 5, init_b, 1, 0, 3, 2}, T{-5. }); - test_scalar_block_multiplications({10, 1, init_a, 0, 0, 5, 1}, T{ 1. }); - test_scalar_block_multiplications({1 , 10, init_a, 0, 0, 1, 5}, T{ 6. }); - test_scalar_block_multiplications({21 , 5, init_0, 4, 4, 10, 1}, T{ 10.1}); - test_scalar_block_multiplications({11 , 7, init_a, 2, 0, 7, 5}, T{-0.5}); + test_scalar_block_multiplications({{ 1, 1, init_a}, 0, 0, 1, 1}, T{ 3.5}); + test_scalar_block_multiplications({{13, 15, init_a}, 1, 2, 3, 4}, T{ 0.}); + test_scalar_block_multiplications({{ 5 , 9, init_a}, 2, 2, 2, 2}, T{-2.5}); + test_scalar_block_multiplications({{15, 15, init_a}, 3, 4, 5, 5}, T{ 42. }); + test_scalar_block_multiplications({{ 5, 5, init_b}, 1, 0, 3, 2}, T{-5. }); + test_scalar_block_multiplications({{10, 1, init_a}, 0, 0, 5, 1}, T{ 1. }); + test_scalar_block_multiplications({{ 1, 10, init_a}, 0, 0, 1, 5}, T{ 6. }); + test_scalar_block_multiplications({{21, 5, init_0}, 4, 4, 10, 1}, T{ 10.1}); + test_scalar_block_multiplications({{11, 7, init_a}, 2, 0, 7, 5}, T{-0.5}); }; TTS_CASE_TPL("Check block division with scalar", rotgen::tests::types) @@ -290,13 +294,14 @@ TTS_CASE_TPL("Check block division with scalar", rotgen::tests::types) auto op = [](auto a, auto b) { return a / b; }; auto s_op = [](auto& a, auto b) { return a /= b; }; - test_block_scalar_operations({1 , 1, init_a, 0, 0, 1, 1}, T{ 3.5}, op, s_op); - test_block_scalar_operations({13 , 15, init_a, 1, 2, 3, 4}, T{-2.5}, op, s_op); - test_block_scalar_operations({5 , 9, init_a, 2, 2, 2, 2}, T{ 42. }, op, s_op); - test_block_scalar_operations({15 , 15, init_a, 3, 4, 5, 5}, T{-5. }, op, s_op); - test_block_scalar_operations({5 , 5, init_b, 1, 0, 3, 2}, T{ 1. }, op, s_op); - test_block_scalar_operations({10, 1, init_a, 0, 0, 5, 1}, T{ 0. }, op, s_op); - test_block_scalar_operations({1 , 10, init_a, 0, 0, 1, 5}, T{ 6. }, op, s_op); - test_block_scalar_operations({21 , 5, init_0, 4, 4, 10, 1}, T{ 10.}, op, s_op); - test_block_scalar_operations({11 , 7, init_a, 2, 0, 7, 5}, T{-0.5}, op, s_op); + test_block_scalar_operations({{ 1, 1, init_a}, 0, 0, 1, 1}, T{ 3.5}, op, s_op); + test_block_scalar_operations({{13, 15, init_a}, 1, 2, 3, 4}, T{-2.5}, op, s_op); + test_block_scalar_operations({{ 5, 9, init_a}, 2, 2, 2, 2}, T{ 42. }, op, s_op); + test_block_scalar_operations({{15, 15, init_a}, 3, 4, 5, 5}, T{-5. }, op, s_op); + test_block_scalar_operations({{ 5, 5, init_b}, 1, 0, 3, 2}, T{ 1. }, op, s_op); + test_block_scalar_operations({{10, 1, init_a}, 0, 0, 5, 1}, T{ 0. }, op, s_op); + test_block_scalar_operations({{ 1, 10, init_a}, 0, 0, 1, 5}, T{ 6. }, op, s_op); + test_block_scalar_operations({{21, 5, init_0}, 4, 4, 10, 1}, T{ 10.}, op, s_op); + test_block_scalar_operations({{11, 7, init_a}, 2, 0, 7, 5}, T{-0.5}, op, s_op); }; + diff --git a/test/unit/block/static_functions.cpp b/test/unit/block/static_functions.cpp deleted file mode 100644 index 44e6efa..0000000 --- a/test/unit/block/static_functions.cpp +++ /dev/null @@ -1,117 +0,0 @@ -//================================================================================================== -/* - ROTGEN - Runtime Overlay for Eigen - Copyright : CODE RECKONS - SPDX-License-Identifier: BSL-1.0 -*/ -//================================================================================================== -#include "unit/tests.hpp" -#include - -void test_size(const auto& matrix, rotgen::Index rows, rotgen::Index cols) -{ - TTS_EQUAL(matrix.rows(), rows); - TTS_EQUAL(matrix.cols(), cols); - TTS_EQUAL(matrix.size(), rows*cols); -} - -void test_value(const auto& matrix, rotgen::Index rows, rotgen::Index cols, auto constant) -{ - TTS_EXPECT(verify_rotgen_reentrance(matrix)); - test_size(matrix, rows, cols); - for(rotgen::Index r=0;r( tts::type< tts::types>) -{ - test_value(rotgen::block, 3, 4>::Zero(), 3, 4, 0); - test_value(rotgen::block, 1, 1>::Zero(), 1, 1, 0); - test_value(rotgen::block, 10, 10>::Zero(), 10, 10, 0); - test_value(rotgen::block, 3, 4>::Zero(3, 4), 3, 4, 0); - test_value(rotgen::block, 3, 3>::Zero(3, 3), 3, 3, 0); - test_value(rotgen::block, 2, 2>::Zero(2, 2), 2, 2, 0); - test_value(rotgen::block, rotgen::Dynamic, rotgen::Dynamic>::Zero(2, 3), 2, 3, 0); - test_value(rotgen::block, 0, 0>::Zero(0, 0), 0, 0, 0); - test_value(rotgen::block::Identity(2, 7)), - rotgen::Dynamic, 7>::Zero(3, 7), 3, 7, 0); - test_value(rotgen::block::Random(14, 3)), - 4, rotgen::Dynamic>::Zero(4, 3), 4, 3, 0); -}; - - -TTS_CASE_TPL("Test constant", rotgen::tests::types) -( tts::type< tts::types> ) -{ - test_value(rotgen::block, 3, 4>::Constant(5.12), 3, 4, T(5.12)); - test_value(rotgen::block, 1, 1>::Constant(2.2), 1, 1, T(2.2)); - test_value(rotgen::block, 10, 10>::Constant(13), 10, 10, T(13)); - test_value(rotgen::block, rotgen::Dynamic, rotgen::Dynamic>::Constant(2, 7, 5.6), 2, 7, T(5.6)); - test_value(rotgen::block, 2, 2>::Constant(2, 2, 2.0), 2, 2, T(2.0)); - test_value(rotgen::block, rotgen::Dynamic, 9>::Constant(9, 9, 1.1), 9, 9, T(1.1)); - test_value(rotgen::block, 5, rotgen::Dynamic>::Constant(5, 9, 42), 5, 9, T(42)); - test_value(rotgen::block, 4, 3>::Constant(4, 3, 0), 4, 3, 0); - test_value(rotgen::block::Identity(3, 7)), - rotgen::Dynamic, 7>::Constant(3, 7, 88), 3, 7, T(88)); - test_value(rotgen::block::Random(14, 3)), - 4, rotgen::Dynamic>::Constant(4, 3, 3.99), 4, 3, T(3.99)); -}; - - -TTS_CASE_TPL("Test random", rotgen::tests::types) -( tts::type< tts::types> ) -{ - test_random(rotgen::block, 3, 3>::Random(), 3, 3); - test_random(rotgen::block, 1, 1>::Random(), 1, 1); - test_random(rotgen::block, 3, 4>::Random(), 3, 4); - test_random(rotgen::block, rotgen::Dynamic, rotgen::Dynamic>::Random(1, 5), 1, 5); - test_random(rotgen::block, 2, 1>::Random(2, 1), 2, 1); - test_random(rotgen::block, rotgen::Dynamic, 9>::Random(3, 9), 3, 9); - test_random(rotgen::block, 5, rotgen::Dynamic>::Random(5, 2), 5, 2); - test_random(rotgen::block, 4, 3>::Random(4, 3), 4, 3); - test_random(rotgen::block::Identity(3, 7)), - rotgen::Dynamic, 7>::Random(3, 7), 3, 7); - test_random(rotgen::block::Random(14, 15)), - 4, rotgen::Dynamic>::Random(4, 11), 4, 11); -}; - - -TTS_CASE_TPL("Test identity", rotgen::tests::types) -( tts::type< tts::types> ) -{ - test_identity(rotgen::block, 3, 3>::Identity(), 3, 3); - test_identity(rotgen::block, 1, 1>::Identity(), 1, 1); - test_identity(rotgen::block, 3, 4>::Identity(), 3, 4); - test_identity(rotgen::block, rotgen::Dynamic, rotgen::Dynamic>::Identity(1, 5), 1, 5); - test_identity(rotgen::block, 2, 1>::Identity(2, 1), 2, 1); - test_identity(rotgen::block, rotgen::Dynamic, 9>::Identity(3, 9), 3, 9); - test_identity(rotgen::block, 5, rotgen::Dynamic>::Identity(5, 2), 5, 2); - test_identity(rotgen::block, 4, 3>::Identity(4, 3), 4, 3); - test_identity(rotgen::block::Identity(3, 7)), - rotgen::Dynamic, 7>::Identity(3, 7), 3, 7); - test_identity(rotgen::block::Random(14, 15)), - 4, rotgen::Dynamic>::Identity(4, 11), 4, 11); -}; \ No newline at end of file diff --git a/test/unit/common/arithmetic.hpp b/test/unit/common/arithmetic.hpp new file mode 100644 index 0000000..292104a --- /dev/null +++ b/test/unit/common/arithmetic.hpp @@ -0,0 +1,126 @@ +//================================================================================================== +/* + ROTGEN - Runtime Overlay for Eigen + Copyright : CODE RECKONS + SPDX-License-Identifier: BSL-1.0 +*/ +//================================================================================================== +#include +#include +#include +#include + +namespace rotgen::tests +{ + template + void check_shape_functions(T original) + { + using mat_t = matrix; + + mat_t result(original.cols(), original.rows()); + prepare([&](auto r, auto c) { return original(c,r); },result); + + TTS_EQUAL(original.transpose(), result ); + TTS_EQUAL(original.conjugate(), original); + TTS_EQUAL(original.adjoint() , result ); + + TTS_EQUAL(transpose(original) , result ); + TTS_EQUAL(conjugate(original) , original); + TTS_EQUAL(adjoint(original) , result ); + + if constexpr(T::is_defined_static) + { + if constexpr(T::RowsAtCompileTime == T::ColsAtCompileTime) + { + mat_t ref = original; + original.transposeInPlace(); + TTS_EQUAL(original, result); + + original.adjointInPlace(); + TTS_EQUAL(original, ref); + + transposeInPlace(original); + TTS_EQUAL(original, result); + + adjointInPlace(original); + TTS_EQUAL(original, ref); + } + } + else + { + if (original.rows() == original.cols()) + { + mat_t ref = original; + original.transposeInPlace(); + TTS_EQUAL(original, result); + + original.adjointInPlace(); + TTS_EQUAL(original, ref); + + transposeInPlace(original); + TTS_EQUAL(original, result); + + adjointInPlace(original); + TTS_EQUAL(original, ref); + } + } + + if constexpr(!rotgen::use_expression_templates) + { + TTS_EXPECT(verify_rotgen_reentrance( original.transpose()) ); + TTS_EXPECT(verify_rotgen_reentrance( original.conjugate()) ); + TTS_EXPECT(verify_rotgen_reentrance( original.adjoint()) ); + } + } + + template + void check_reduction_functions(const T& input) + { + using EigenMatrix = Eigen::Matrix; + + EigenMatrix ref(input.rows(), input.cols()); + prepare([&](auto r, auto c) { return input(r,c); }, ref); + + TTS_ULP_EQUAL(input.sum(), ref.sum() , 2); + TTS_ULP_EQUAL(sum(input) , ref.sum() , 2); + + TTS_ULP_EQUAL(input.prod(), ref.prod(), 2); + TTS_ULP_EQUAL(prod(input) , ref.prod(), 2); + + TTS_ULP_EQUAL(input.mean(), ref.mean(), 2); + TTS_ULP_EQUAL(mean(input) , ref.mean(), 2); + + TTS_EQUAL(input.trace(), ref.trace()); + TTS_EQUAL(trace(input) , ref.trace()); + + TTS_EQUAL(input.minCoeff(), ref.minCoeff()); + TTS_EQUAL(minCoeff(input) , ref.minCoeff()); + + TTS_EQUAL(input.maxCoeff(), ref.maxCoeff()); + TTS_EQUAL(maxCoeff(input) , ref.maxCoeff()); + + { + rotgen::Index row, col, ref_row, ref_col; + + TTS_EQUAL(input.minCoeff(&row, &col), ref.minCoeff(&ref_row, &ref_col)); + TTS_EQUAL(row, ref_row); + TTS_EQUAL(col, ref_col); + + TTS_EQUAL(input.maxCoeff(&row, &col), ref.maxCoeff(&ref_row, &ref_col)); + TTS_EQUAL(row, ref_row); + TTS_EQUAL(col, ref_col); + } + + { + rotgen::Index row, col, ref_row, ref_col; + + TTS_EQUAL(minCoeff(input,&row, &col), ref.minCoeff(&ref_row, &ref_col)); + TTS_EQUAL(row, ref_row); + TTS_EQUAL(col, ref_col); + + TTS_EQUAL(maxCoeff(input,&row, &col), ref.maxCoeff(&ref_row, &ref_col)); + TTS_EQUAL(row, ref_row); + TTS_EQUAL(col, ref_col); + } + } +} diff --git a/test/unit/common/norms.hpp b/test/unit/common/norms.hpp new file mode 100644 index 0000000..c476ada --- /dev/null +++ b/test/unit/common/norms.hpp @@ -0,0 +1,35 @@ +//================================================================================================== +/* + ROTGEN - Runtime Overlay for Eigen + Copyright : CODE RECKONS + SPDX-License-Identifier: BSL-1.0 +*/ +//================================================================================================== +#include +#include +#include +#include + +namespace rotgen::tests +{ + template + void check_norms_functions(const T& input) + { + using EigenMatrix = Eigen::Matrix; + + EigenMatrix ref(input.rows(), input.cols()); + prepare([&](auto r, auto c) { return input(r,c); }, ref); + + TTS_EQUAL(input.norm() , ref.norm()); + TTS_EQUAL(input.squaredNorm() , ref.squaredNorm()); + TTS_EQUAL(input.template lpNorm<1>() , ref.template lpNorm<1>()); + TTS_EQUAL(input.template lpNorm<2>() , ref.template lpNorm<2>()); + TTS_EQUAL(input.template lpNorm() , ref.template lpNorm()); + + TTS_EQUAL(norm(input) , ref.norm()); + TTS_EQUAL(squaredNorm(input) , ref.squaredNorm()); + TTS_EQUAL(lpNorm<1>(input) , ref.template lpNorm<1>()); + TTS_EQUAL(lpNorm<2>(input) , ref.template lpNorm<2>()); + TTS_EQUAL(lpNorm(input) , ref.template lpNorm()); + } +} diff --git a/test/unit/common/references.hpp b/test/unit/common/references.hpp new file mode 100644 index 0000000..15bd14b --- /dev/null +++ b/test/unit/common/references.hpp @@ -0,0 +1,192 @@ +//================================================================================================== +/* + ROTGEN - Runtime Overlay for Eigen + Copyright : CODE RECKONS + SPDX-License-Identifier: BSL-1.0 +*/ +//================================================================================================== + +#include +#include +#include +#include + +namespace rotgen::tests +{ + struct matrix_descriptor + { + rotgen::Index rows, cols; + std::function init_fn; + }; + + template + struct static_matrix_descriptor + { + static constexpr rotgen::Index rows = Rows; + static constexpr rotgen::Index cols = Cols; + std::function init_fn; + }; + + template + struct matrix_block_test_case + { + matrix_descriptor matrix_desc; + rotgen::Index i0, j0, ni, nj; + }; + + template + struct static_matrix_block_test_case + { + matrix_descriptor matrix_desc; + static constexpr rotgen::Index ni = NI; + static constexpr rotgen::Index nj = NJ; + rotgen::Index i0, j0; + }; + + void prepare(rotgen::Index rows, rotgen::Index cols, auto const &init_fn, auto& output) + { + for (rotgen::Index r = 0; r < rows; ++r) + for (rotgen::Index c = 0; c < cols; ++c) + output(r,c) = init_fn(r, c); + } + + void prepare(auto fn, auto& output) + { + for (rotgen::Index r = 0; r < output.rows(); ++r) + for (rotgen::Index c = 0; c < output.cols(); ++c) + output(r,c) = fn(r, c); + } + + auto generate_matrix_references() + { + auto fn = [](auto r, auto c) { return r + 3 * c - 2.5; }; + std::vector cases = + { + // Singular matrix + {1, 1, fn}, + // Square matrix below MAX_SIZE + {3, 3, fn}, + // Square matrix at MAX_SIZE + {4, 4, fn}, + // Square matrix above MAX_SIZE + {7, 7, fn}, + // Tall matrix below MAX_SIZE + {5, 2, fn}, + // Tall matrix at MAX_SIZE + {8, 2, fn}, + // Tall matrix above MAX_SIZE + {10, 3, fn}, + // Thick matrix below MAX_SIZE + {2, 5, fn}, + // Thick matrix at MAX_SIZE + {2, 8, fn}, + // Thick matrix above MAX_SIZE + {3, 10, fn} + }; + + return cases; + } + + auto generate_static_matrix_references() + { + auto fn = [](auto r, auto c) { return r + 3 * c - 2.5; }; + std::tuple cases = + { + // Singular matrix + static_matrix_descriptor< 1, 1>{fn}, + // Square matrix below MAX_SIZE + static_matrix_descriptor< 3, 3>{fn}, + // Square matrix at MAX_SIZE + static_matrix_descriptor< 4, 4>{fn}, + // Square matrix above MAX_SIZE + static_matrix_descriptor< 7, 7>{fn}, + // Tall matrix below MAX_SIZE + static_matrix_descriptor< 5, 2>{fn}, + // Tall matrix at MAX_SIZE + static_matrix_descriptor< 8, 2>{fn}, + // Tall matrix above MAX_SIZE + static_matrix_descriptor<10, 3>{fn}, + // Thick matrix below MAX_SIZE + static_matrix_descriptor< 2, 5>{fn}, + // Thick matrix at MAX_SIZE + static_matrix_descriptor< 2, 8>{fn}, + // Thick matrix above MAX_SIZE + static_matrix_descriptor< 3,10>{fn} + }; + + return cases; + } + + template + auto generate_block_references() + { + rotgen::tests::matrix_descriptor base{16,16,[](auto r, auto c) { return r + 3 * c - 2.5; }}; + + using mat_t = rotgen::matrix; + + std::vector> cases = + { + // Singular blocks + {base, 0, 0, 1, 1}, + {base, 3, 2, 1, 1}, + {base, 4,11, 1, 1}, + {base,15,15, 1, 1}, + // Square block below MAX_SIZE + {base,7,9, 3, 3}, + // Square block at MAX_SIZE + {base,6,3, 4, 4}, + // Square block above MAX_SIZE + {base,6,3, 6, 6}, + // Tall block below MAX_SIZE + {base,6,3, 5, 2}, + // Tall block at MAX_SIZE + {base,6,3, 8, 2}, + // Tall block above MAX_SIZE + {base,6,3, 7, 3}, + // Thick block below MAX_SIZE + {base,6,3, 2, 5}, + // Thick block at MAX_SIZE + {base,6,3, 2, 8}, + // Thick block above MAX_SIZE + {base,6,3, 3, 7} + }; + + return cases; + } + template + auto generate_static_block_references() + { + rotgen::tests::matrix_descriptor base{16,16,[](auto r, auto c) { return r + 3 * c - 2.5; }}; + + using mat_t = rotgen::matrix; + + std::tuple cases = + { + // Singular blocks + static_matrix_block_test_case{base, 0, 0}, + static_matrix_block_test_case{base, 3, 2}, + static_matrix_block_test_case{base, 4,11}, + static_matrix_block_test_case{base,15,15}, + // Square block below MAX_SIZE + static_matrix_block_test_case{base,7,9}, + // Square block at MAX_SIZE + static_matrix_block_test_case{base,6,3}, + // Square block above MAX_SIZE + static_matrix_block_test_case{base,6,3}, + // Tall block below MAX_SIZE + static_matrix_block_test_case{base,6,3}, + // Tall block at MAX_SIZE + static_matrix_block_test_case{base,6,3}, + // Tall block above MAX_SIZE + static_matrix_block_test_case{base,6,3}, + // Thick block below MAX_SIZE + static_matrix_block_test_case{base,6,3}, + // Thick block at MAX_SIZE + static_matrix_block_test_case{base,6,3}, + // Thick block above MAX_SIZE + static_matrix_block_test_case{base,6,3} + }; + + return cases; + } +} diff --git a/test/unit/free_functions/arithmetic_functions.cpp b/test/unit/free_functions/arithmetic_functions.cpp deleted file mode 100644 index 58849c0..0000000 --- a/test/unit/free_functions/arithmetic_functions.cpp +++ /dev/null @@ -1,124 +0,0 @@ -//================================================================================================== -/* - ROTGEN - Runtime Overlay for Eigen - Copyright : CODE RECKONS - SPDX-License-Identifier: BSL-1.0 -*/ -//================================================================================================== -#include "unit/tests.hpp" -#include -#include - -template -struct MatrixDescriptor -{ - std::size_t rows, cols; - std::function init_fn; -}; - -template -void test_matrix_unary_ops(std::size_t rows, std::size_t cols, - const std::function &init_fn) -{ - - MatrixType original(rows, cols); - MatrixType transposed_matrix(cols, rows); - - for (std::size_t r = 0; r < rows; ++r) - for (std::size_t c = 0; c < cols; ++c) - init_fn(original, r, c); - - for (std::size_t r = 0; r < rows; ++r) - for (std::size_t c = 0; c < cols; ++c) - transposed_matrix(c, r) = original(r, c); - - TTS_EQUAL(rotgen::transpose(original), transposed_matrix); - TTS_EQUAL(rotgen::conjugate(original), original); - TTS_EQUAL(rotgen::adjoint(original), transposed_matrix); - - TTS_EXPECT(verify_rotgen_reentrance(rotgen::transpose(original))); - TTS_EXPECT(verify_rotgen_reentrance(rotgen::conjugate(original))); - TTS_EXPECT(verify_rotgen_reentrance(rotgen::adjoint(original))); - - rotgen::transposeInPlace(original); - TTS_EQUAL(original, transposed_matrix); - - rotgen::transposeInPlace(original); - rotgen::adjointInPlace(original); - TTS_EQUAL(original, transposed_matrix); -} - -template -void test_matrix_scalar_reductions(std::size_t rows, std::size_t cols, - const std::function& init_fn) -{ - using EigenMatrix = Eigen::Matrix; - - MatrixType original(rows, cols); - EigenMatrix ref(rows, cols); - - for (std::size_t r = 0; r < rows; ++r) - for (std::size_t c = 0; c < cols; ++c) - { - init_fn(original, r, c); - ref(r, c) = original(r, c); - } - - TTS_EQUAL(rotgen::sum(original), ref.sum()); - TTS_EQUAL(rotgen::prod(original), ref.prod()); - TTS_EQUAL(rotgen::mean(original), ref.mean()); - TTS_EQUAL(rotgen::maxCoeff(original), ref.maxCoeff()); - TTS_EQUAL(rotgen::minCoeff(original), ref.minCoeff()); - TTS_EQUAL(rotgen::trace(original), ref.trace()); - - std::ptrdiff_t row, col, ref_row, ref_col; - - double cmin = rotgen::minCoeff(original, &row, &col); - double rmin = ref.minCoeff(&ref_row, &ref_col); - - TTS_EQUAL(cmin, rmin); - TTS_EQUAL(row, ref_row); - TTS_EQUAL(col, ref_col); - - double cmax = rotgen::maxCoeff(original, &row, &col); - double rmax = ref.maxCoeff(&ref_row, &ref_col); - - TTS_EQUAL(cmax, rmax); - TTS_EQUAL(row, ref_row); - TTS_EQUAL(col, ref_col); -} - -TTS_CASE("Matrix unary operations: transpose, adjoint, conjugate") -{ - std::vector>> test_matrices = { - {3, 3, [](auto& m, std::size_t r, std::size_t c) { m(r, c) = r + 3 * c - 2.5; }}, - {4, 9, [](auto& m, std::size_t r, std::size_t c) { m(r, c) = r*r + 3.12 * c + 6.87; }}, - {2, 7, [](auto& m, std::size_t r, std::size_t c) { m(r, c) = 1.1 * (r - c); }}, - {1, 5, [](auto &m, std::size_t r, std::size_t c) { m(r, c) = 9.99; }}, - {4, 2, [](auto& m, std::size_t r, std::size_t c) { m(r, c) = 0.0; }}, - {3, 3, [](auto& m, std::size_t r, std::size_t c) { m(r, c) = (r == c) ? 1.0 : 0.0; }}, - {2, 2, [](auto& m, std::size_t r, std::size_t c) { m(r, c) = (r + c) * 1e-10; }}, - {2, 2, [](auto& m, std::size_t r, std::size_t c) { m(r, c) = (r + 1) * 1e+10; }}, - }; - - for (auto const &desc : test_matrices) - test_matrix_unary_ops>(desc.rows, desc.cols, desc.init_fn); -}; - -TTS_CASE("Basic arithmetic reduction operations") -{ - std::vector>> test_matrices = { - {3, 3, [](auto& m, std::size_t r, std::size_t c) { m(r, c) = r + c; }}, - {3, 3, [](auto& m, std::size_t r, std::size_t c) { m(r, c) = 0.0; }}, - {2, 4, [](auto& m, std::size_t r, std::size_t c) { m(r, c) = -r -c*c - 1234; }}, - {4, 4, [](auto& m, std::size_t r, std::size_t c) { m(r, c) = 7.0; }}, - {1, 1, [](auto& m, std::size_t r, std::size_t c) { m(r, c) = 42.0; }}, - {4, 2, [](auto& m, std::size_t r, std::size_t c) { m(r, c) = std::sin(r + c); }}, - {1, 5, [](auto& m, std::size_t r, std::size_t c) { m(r, c) = -1.5 * r + 2.56 * c; }}, - {5, 7, [](auto& m, std::size_t r, std::size_t c) { m(r, c) = (r == c ? 1.0 : 0.0); }}, - }; - - for (const auto& [rows, cols, init_fn] : test_matrices) - test_matrix_scalar_reductions>(rows, cols, init_fn); -}; - diff --git a/test/unit/free_functions/norms.cpp b/test/unit/free_functions/norms.cpp deleted file mode 100644 index 832952e..0000000 --- a/test/unit/free_functions/norms.cpp +++ /dev/null @@ -1,60 +0,0 @@ -//================================================================================================== -/* - ROTGEN - Runtime Overlay for Eigen - Copyright : CODE RECKONS - SPDX-License-Identifier: BSL-1.0 -*/ -//================================================================================================== -#include "unit/tests.hpp" -#include -#include - -template -struct MatrixDescriptor -{ - std::size_t rows, cols; - std::function init_fn; -}; - -template -void test_matrix_norms(std::size_t rows, std::size_t cols, - const std::function &init_fn) -{ - MatrixType matrix(rows, cols); - Eigen::Matrix ref(rows, cols); - - for (std::size_t r = 0; r < rows; ++r) - for (std::size_t c = 0; c < cols; ++c) - { - init_fn(matrix, r, c); - ref(r, c) = matrix(r, c); - } - - constexpr double epsilon = 1e-10; - - TTS_RELATIVE_EQUAL(rotgen::norm(matrix), ref.norm(), epsilon); - TTS_RELATIVE_EQUAL(rotgen::squaredNorm(matrix), ref.squaredNorm(), epsilon); - - TTS_RELATIVE_EQUAL(rotgen::lpNorm<1>(matrix), ref.lpNorm<1>(), epsilon); - TTS_RELATIVE_EQUAL(rotgen::lpNorm<2>(matrix), ref.lpNorm<2>(), epsilon); - TTS_RELATIVE_EQUAL(rotgen::lpNorm<-1>(matrix), ref.lpNorm(), epsilon); -} - -TTS_CASE("Matrix norm-related operations") -{ - std::vector>> test_matrices = { - {3, 3, [](auto& m, std::size_t r, std::size_t c) { m(r, c) = r + c; }}, - {2, 3, [](auto& m, std::size_t r, std::size_t c) { m(r, c) = 0.0; }}, - {2, 7, [](auto& m, std::size_t r, std::size_t c) { m(r, c) = -r*r*r - c*c - 1.23; }}, - {17, 3, [](auto& m, std::size_t r, std::size_t c) { m(r, c) = r*c + 0.98; }}, - {1, 1, [](auto& m, std::size_t r, std::size_t c) { m(r, c) = 42.0; }}, - {10, 11, [](auto& m, std::size_t r, std::size_t c) { m(r, c) = std::tan(r + c); }}, - {1, 5, [](auto& m, std::size_t r, std::size_t c) { m(r, c) = -1.5*r + 2.56*c + 3.33; }}, - {7, 1, [](auto& m, std::size_t r, std::size_t c) { m(r, c) = (r == c ? 1.0 : 0.0); }}, - {0, 0, [](auto& m, std::size_t r, std::size_t c) { m(r, c) = (r == c ? 1.0 : 0.0); }}, - }; - - for (const auto& [rows, cols, init_fn] : test_matrices) - test_matrix_norms>(rows, cols, init_fn); - -}; \ No newline at end of file diff --git a/test/unit/io.cpp b/test/unit/io.cpp new file mode 100644 index 0000000..698063c --- /dev/null +++ b/test/unit/io.cpp @@ -0,0 +1,47 @@ +//================================================================================================== +/* + ROTGEN - Runtime Overlay for Eigen + Copyright : CODE RECKONS + SPDX-License-Identifier: BSL-1.0 +*/ +//================================================================================================== +#include "unit/tests.hpp" +#include +#include + +TTS_CASE_TPL("I/O for matrix", rotgen::tests::types) +( tts::type< tts::types> ) +{ + rotgen::matrix x({ {1,2} , {3,4} }); + std::ostringstream os; + os << x; + + TTS_EQUAL(os.str(), std::string{"1 2\n3 4"}); +}; + +TTS_CASE_TPL("I/O for block", rotgen::tests::types) +( tts::type< tts::types> ) +{ + rotgen::matrix base({ {1,2} , {3,4} }); + + auto x = rotgen::extract(base,0,0,2,2); + std::ostringstream os; + os << x; + + TTS_EQUAL(os.str(), std::string{"1 2\n3 4"}); +}; + +TTS_CASE_TPL("I/O for map test", rotgen::tests::types) +( tts::type< tts::types> ) +{ + using base = rotgen::matrix; + + T data[] = {1,2,3,4}; + + rotgen::map x(data,2,2); + std::ostringstream os; + os << x; + + if constexpr(O::value) TTS_EQUAL(os.str(), std::string{"1 2\n3 4"}); + else TTS_EQUAL(os.str(), std::string{"1 3\n2 4"}); +}; diff --git a/test/unit/map/arithmetic_functions.cpp b/test/unit/map/arithmetic_functions.cpp new file mode 100644 index 0000000..1837bef --- /dev/null +++ b/test/unit/map/arithmetic_functions.cpp @@ -0,0 +1,73 @@ +//================================================================================================== +/* + ROTGEN - Runtime Overlay for Eigen + Copyright : CODE RECKONS + SPDX-License-Identifier: BSL-1.0 +*/ +//================================================================================================== +#include "unit/tests.hpp" +#include "unit/common/arithmetic.hpp" +#include + +TTS_CASE_TPL("Test dynamic map transposition-like operations", rotgen::tests::types) +( tts::type< tts::types> ) +{ + auto const cases = rotgen::tests::generate_matrix_references(); + for (const auto& [rows, cols, fn] : cases) + { + using mat_t = rotgen::matrix; + mat_t base(rows, cols); + rotgen::tests::prepare(rows,cols,fn,base); + + rotgen::map input(base.data(),rows,cols); + rotgen::tests::check_shape_functions(input); + } +}; + +TTS_CASE_TPL("Test static map transposition-like operations", rotgen::tests::types) +( tts::type< tts::types> ) +{ + auto const cases = rotgen::tests::generate_static_matrix_references(); + + auto process = [](D const& desc) + { + rotgen::matrix base(D::rows,D::cols); + rotgen::tests::prepare(base.rows(),base.cols(),desc.init_fn,base); + + rotgen::map> input(base.data()); + rotgen::tests::check_shape_functions(input); + }; + + std::apply([&](auto const&... d) { (process(d),...);}, cases); +}; + +TTS_CASE_TPL("Test dynamic map reduction-like operations", rotgen::tests::types) +( tts::type< tts::types> ) +{ + auto const cases = rotgen::tests::generate_matrix_references(); + for (const auto& [rows, cols, fn] : cases) + { + rotgen::matrix base(rows, cols); + rotgen::tests::prepare(rows,cols,fn,base); + + rotgen::map> input(base.data(),rows,cols); + rotgen::tests::check_reduction_functions(input); + } +}; + +TTS_CASE_TPL("Test static map reduction-like operations", rotgen::tests::types) +( tts::type< tts::types> ) +{ + auto const cases = rotgen::tests::generate_static_matrix_references(); + + auto process = [](D const& desc) + { + rotgen::matrix base(D::rows,D::cols); + rotgen::tests::prepare(base.rows(),base.cols(),desc.init_fn,base); + + rotgen::map> input(base.data()); + rotgen::tests::check_reduction_functions(input); + }; + + std::apply([&](auto const&... d) { (process(d),...);}, cases); +}; \ No newline at end of file diff --git a/test/unit/map/basic_api.cpp b/test/unit/map/basic_api.cpp new file mode 100644 index 0000000..0d8abe2 --- /dev/null +++ b/test/unit/map/basic_api.cpp @@ -0,0 +1,83 @@ +//================================================================================================== +/* + ROTGEN - Runtime Overlay for Eigen + Copyright : CODE RECKONS + SPDX-License-Identifier: BSL-1.0 +*/ +//================================================================================================== +#include "unit/tests.hpp" +#include + +TTS_CASE_TPL("Function size", rotgen::tests::types) +( tts::type< tts::types> ) +{ + T data[] = {1,2,3,4,5,6,7,8,9,10,11,12}; + + rotgen::map> dyn_map(data,1,12); + TTS_EQUAL(dyn_map.rows(), rotgen::Index{1}); + TTS_EQUAL(dyn_map.cols(), rotgen::Index{12}); + + rotgen::map> s112_map(data); + TTS_EQUAL(s112_map.rows(), rotgen::Index{1}); + TTS_EQUAL(s112_map.cols(), rotgen::Index{12}); + TTS_EQUAL(s112_map.size(), rotgen::Index{12}); + + rotgen::map> s121_map(data); + TTS_EQUAL(s121_map.rows(), rotgen::Index{12}); + TTS_EQUAL(s121_map.cols(), rotgen::Index{1}); + TTS_EQUAL(s121_map.size(), rotgen::Index{12}); + + rotgen::map> s34_map(data); + TTS_EQUAL(s34_map.rows(), rotgen::Index{3}); + TTS_EQUAL(s34_map.cols(), rotgen::Index{4}); + TTS_EQUAL(s34_map.size(), rotgen::Index{12}); + + rotgen::map> s62_map(data); + TTS_EQUAL(s62_map.rows(), rotgen::Index{6}); + TTS_EQUAL(s62_map.cols(), rotgen::Index{2}); + TTS_EQUAL(s62_map.size(), rotgen::Index{12}); +}; + +TTS_CASE_TPL("Test coefficient accessors", rotgen::tests::types) +( tts::type< tts::types> ) +{ + using base = rotgen::matrix; + + T data[] = {1,2,3,4,5,6,7,8,9,10,11,12}; + + rotgen::map a(data,4,3); + for(rotgen::Index i=0;i<4;i++) + { + for(rotgen::Index j=0;j<3;j++) + { + if constexpr(O::value) TTS_EQUAL(a(i,j), data[j+3*i]); + else TTS_EQUAL(a(i,j), data[i+4*j]); + } + } + + a(1, 1) = 42; + TTS_EQUAL(a(1,1), 42); + + T& ref = a(2, 2); + ref = 17; + TTS_EQUAL(a(2, 2), 17); +}; + +TTS_CASE_TPL("Test one index coefficient accessors", rotgen::tests::types) +( tts::type< tts::types> ) +{ + using base = rotgen::matrix; + + T data[] = {1,2,3,4,5,6,7,8,9,10,11,12}; + + rotgen::map a(data,4,3); + for(rotgen::Index i=0;i + +TTS_CASE_TPL("map constructor from pointer and single static size", rotgen::tests::types) +( tts::type< tts::types> ) +{ + T data[] = {1,2,3,4,5,6,7,8,9,10,11,12}; + + rotgen::map> row_map(data); + for(rotgen::Index i=0;i<12;i++) + TTS_EQUAL(row_map(i), data[i]); + + rotgen::map const> const_row_map(data); + for(rotgen::Index i=0;i<12;i++) + TTS_EQUAL(const_row_map(i), data[i]); + + rotgen::map> col_map(data); + for(rotgen::Index i=0;i<12;i++) + TTS_EQUAL(col_map(i), data[i]); + + rotgen::map const> const_col_map(data); + for(rotgen::Index i=0;i<12;i++) + TTS_EQUAL(const_col_map(i), data[i]); +}; + +TTS_CASE_TPL("map constructor from pointer and static size", rotgen::tests::types) +( tts::type< tts::types> ) +{ + using base = rotgen::matrix; + + T data[] = {1,2,3,4,5,6,7,8,9,10,11,12}; + + rotgen::map dyn_map(data); + for(rotgen::Index i=0;i<4;i++) + { + for(rotgen::Index j=0;j<3;j++) + { + if constexpr(O::value) TTS_EQUAL(dyn_map(i,j), data[j+3*i]); + else TTS_EQUAL(dyn_map(i,j), data[i+4*j]); + } + } +}; + +TTS_CASE_TPL("map constructor from pointer and single dynamic size", rotgen::tests::types) +( tts::type< tts::types> ) +{ + T data[] = {1,2,3,4,5,6,7,8,9,10,11,12}; + + rotgen::map> row_map(data,12); + for(rotgen::Index i=0;i<12;i++) + TTS_EQUAL(row_map(i), data[i]); + + rotgen::map const> const_row_map(data,12); + for(rotgen::Index i=0;i<12;i++) + TTS_EQUAL(const_row_map(i), data[i]); + + rotgen::map> col_map(data,12); + for(rotgen::Index i=0;i<12;i++) + TTS_EQUAL(col_map(i), data[i]); + + rotgen::map const> const_col_map(data,12); + for(rotgen::Index i=0;i<12;i++) + TTS_EQUAL(const_col_map(i), data[i]); +}; + +TTS_CASE_TPL("map constructor from pointer and dynamic size", rotgen::tests::types) +( tts::type< tts::types> ) +{ + using base = rotgen::matrix; + + T data[] = {1,2,3,4,5,6,7,8,9,10,11,12}; + + rotgen::map dyn_map(data,4,3); + for(rotgen::Index i=0;i<4;i++) + { + for(rotgen::Index j=0;j<3;j++) + { + if constexpr(O::value) TTS_EQUAL(dyn_map(i,j), data[j+3*i]); + else TTS_EQUAL(dyn_map(i,j), data[i+4*j]); + } + } +}; diff --git a/test/unit/map/norms.cpp b/test/unit/map/norms.cpp new file mode 100644 index 0000000..610eeeb --- /dev/null +++ b/test/unit/map/norms.cpp @@ -0,0 +1,41 @@ +//================================================================================================== +/* + ROTGEN - Runtime Overlay for Eigen + Copyright : CODE RECKONS + SPDX-License-Identifier: BSL-1.0 +*/ +//================================================================================================== +#include "unit/tests.hpp" +#include "unit/common/norms.hpp" +#include + +TTS_CASE_TPL("Test dynamic map norm operations", rotgen::tests::types) +( tts::type< tts::types> ) +{ + auto const cases = rotgen::tests::generate_matrix_references(); + for (const auto& [rows, cols, fn] : cases) + { + rotgen::matrix base(rows, cols); + rotgen::tests::prepare(rows,cols,fn,base); + + rotgen::map> input(base.data(),rows,cols); + rotgen::tests::check_norms_functions(input); + } +}; + +TTS_CASE_TPL("Test static map norm operations", rotgen::tests::types) +( tts::type< tts::types> ) +{ + auto const cases = rotgen::tests::generate_static_matrix_references(); + + auto process = [](D const& desc) + { + rotgen::matrix base(D::rows,D::cols); + rotgen::tests::prepare(base.rows(),base.cols(),desc.init_fn,base); + + rotgen::map> input(base.data()); + rotgen::tests::check_norms_functions(input); + }; + + std::apply([&](auto const&... d) { (process(d),...);}, cases); +}; \ No newline at end of file diff --git a/test/unit/map/operators.cpp b/test/unit/map/operators.cpp new file mode 100644 index 0000000..508c14f --- /dev/null +++ b/test/unit/map/operators.cpp @@ -0,0 +1,202 @@ +//================================================================================================== +/* + ROTGEN - Runtime Overlay for Eigen + Copyright : CODE RECKONS + SPDX-License-Identifier: BSL-1.0 +*/ +//================================================================================================== +#include "unit/tests.hpp" +#include +#include + +template +void test_map_operations(rotgen::Index rows, rotgen::Index cols, auto a_init_fn, auto b_init_fn, auto ops, auto self_ops) +{ + MatrixType a_data(rows, cols); + MatrixType b_data(rows, cols); + MatrixType ref_data; + + for (rotgen::Index r = 0; r < rows; ++r) + for (rotgen::Index c = 0; c < cols; ++c) + { + a_data(r,c) = a_init_fn(r, c); + b_data(r,c) = b_init_fn(r, c); + } + + ref_data = ops(a_data, b_data); + rotgen::map a_map(a_data.data(), rows, cols); + rotgen::map b_map(b_data.data(), rows, cols); + + TTS_EQUAL(ops(a_map, b_map), ref_data); + self_ops(a_map, b_map); + TTS_EQUAL(a_map, ref_data); + + TTS_EXPECT(verify_rotgen_reentrance(ops(a_map, b_map))); + TTS_EXPECT(verify_rotgen_reentrance(self_ops(a_map, b_map))); +} + +template +void test_map_scalar_operations(rotgen::Index rows, rotgen::Index cols, auto fn, auto s, auto ops, auto self_ops) +{ + MatrixType a_data(rows, cols); + MatrixType ref_data; + + for (rotgen::Index r = 0; r < rows; ++r) + for (rotgen::Index c = 0; c < cols; ++c) + a_data(r,c) = fn(r, c); + + ref_data = ops(a_data, s); + rotgen::map a_map(a_data.data(), rows, cols); + + TTS_EQUAL(ops(a_map, s), ref_data); + self_ops(a_map, s); + TTS_EQUAL(a_map, ref_data); + + TTS_EXPECT(verify_rotgen_reentrance(ops(a_map, s))); + TTS_EXPECT(verify_rotgen_reentrance(self_ops(a_map, s))); +} + +template +void test_map_scalar_multiplications(rotgen::Index rows, rotgen::Index cols, auto fn, auto s) +{ + MatrixType a_data(rows, cols); + MatrixType ref_data; + + for (rotgen::Index r = 0; r < rows; ++r) + for (rotgen::Index c = 0; c < cols; ++c) + a_data(r,c) = fn(r, c); + + ref_data = a_data * s; + rotgen::map a_map(a_data.data(), rows, cols); + + TTS_EQUAL(a_map * s, ref_data); + TTS_EQUAL(s * a_map, ref_data); + a_map *= s; + TTS_EQUAL(a_map, ref_data); + + TTS_EXPECT(verify_rotgen_reentrance(a_map * s)); + TTS_EXPECT(verify_rotgen_reentrance(s * a_map)); + TTS_EXPECT(verify_rotgen_reentrance(a_map *= s)); +} + +template +void test_map_multiplication(rotgen::Index rows, rotgen::Index cols, auto a_init_fn, auto b_init_fn) +{ + MatrixType a_data(rows, cols); + MatrixType b_data(cols, rows); + MatrixType ref_data; + + for (rotgen::Index r = 0; r < rows; ++r) + for (rotgen::Index c = 0; c < cols; ++c) + { + a_data(r,c) = a_init_fn(r,c); + b_data(c,r) = b_init_fn(c,r); + } + + ref_data = a_data * b_data; + rotgen::map a_map(a_data.data(), rows, cols); + rotgen::map b_map(b_data.data(), cols, rows); + + TTS_EQUAL(a_map * b_map, ref_data); + TTS_EXPECT(verify_rotgen_reentrance(a_map * b_map)); + + if(rows == cols) + { + a_map *= b_map; + TTS_EQUAL(a_map, ref_data); + TTS_EXPECT(verify_rotgen_reentrance(a_map *= b_map)); + } + +} + +inline constexpr auto init_a = [](auto r, auto c) { return 9.9*r*r*r - 6*c - 12; }; +inline constexpr auto init_b = [](auto r, auto c) { return 3.1*r + 4.2*c - 12.3; }; +inline constexpr auto init_0 = [](auto , auto ) { return 0; }; + +TTS_CASE_TPL("Check map addition", rotgen::tests::types) +( tts::type< tts::types> ) +{ + using mat_t = rotgen::matrix; + auto op = [](auto a, auto b) { return a + b; }; + auto s_op = [](auto& a, auto b) { return a += b; }; + + test_map_operations(1 , 1, init_a, init_b, op, s_op); + test_map_operations(3 , 5, init_a, init_b, op, s_op); + test_map_operations(5 , 3, init_a, init_b, op, s_op); + test_map_operations(5 , 5, init_a, init_b, op, s_op); + test_map_operations(5 , 5, init_b, init_a, op, s_op); + test_map_operations(10, 1, init_a, init_b, op, s_op); + test_map_operations(1 ,10, init_a, init_b, op, s_op); + test_map_operations(5 , 5, init_0, init_b, op, s_op); + test_map_operations(5 , 5, init_a, init_0, op, s_op); +}; + +TTS_CASE_TPL("Check map subtraction", rotgen::tests::types) +( tts::type< tts::types> ) +{ + using mat_t = rotgen::matrix; + auto op = [](auto a, auto b) { return a - b; }; + auto s_op = [](auto& a, auto b) { return a -= b; }; + + test_map_operations(1 , 1, init_a, init_b, op, s_op); + test_map_operations(3 , 5, init_a, init_b, op, s_op); + test_map_operations(5 , 3, init_a, init_b, op, s_op); + test_map_operations(5 , 5, init_a, init_b, op, s_op); + test_map_operations(5 , 5, init_b, init_a, op, s_op); + test_map_operations(10, 1, init_a, init_b, op, s_op); + test_map_operations(1 ,10, init_a, init_b, op, s_op); + test_map_operations(5 , 5, init_0, init_b, op, s_op); + test_map_operations(5 , 5, init_a, init_0, op, s_op); +}; + +TTS_CASE_TPL("Check map multiplications", rotgen::tests::types) +( tts::type< tts::types> ) +{ + using mat_t = rotgen::matrix; + auto init_id = [](auto r, auto c) { return r == c ? 1 : 0; }; + + test_map_multiplication(1 , 1, init_a , init_b ); + test_map_multiplication(3 , 5, init_a , init_b ); + test_map_multiplication(5 , 3, init_a , init_b ); + test_map_multiplication(5 , 5, init_a , init_b ); + test_map_multiplication(5 , 5, init_b , init_a ); + test_map_multiplication(5 , 5, init_a , init_a ); + test_map_multiplication(5 , 5, init_a , init_id); + test_map_multiplication(5 , 5, init_id, init_a ); + test_map_multiplication(10, 1, init_a , init_b ); + test_map_multiplication(1 ,10, init_a , init_b ); + test_map_multiplication(5 , 5, init_0 , init_b ); + test_map_multiplication(5 , 5, init_a , init_0 ); +}; + +TTS_CASE_TPL("Check map multiplication with scalar", rotgen::tests::types) +( tts::type< tts::types> ) +{ + using mat_t = rotgen::matrix; + + test_map_scalar_multiplications(1 , 1, init_a, T{ 3.5}); + test_map_scalar_multiplications(3 , 5, init_a, T{-2.5}); + test_map_scalar_multiplications(5 , 3, init_a, T{ 4. }); + test_map_scalar_multiplications(5 , 5, init_a, T{-5. }); + test_map_scalar_multiplications(5 , 5, init_a, T{ 1. }); + test_map_scalar_multiplications(5 , 5, init_a, T{ 6. }); + test_map_scalar_multiplications(10, 1, init_a, T{ 10.}); + test_map_scalar_multiplications(1 ,10, init_a, T{-0.5}); +}; + +TTS_CASE_TPL("Check map division with scalar", rotgen::tests::types) +( tts::type< tts::types> ) +{ + using mat_t = rotgen::matrix; + auto op = [](auto a, auto b) { return a / b; }; + auto s_op = [](auto& a, auto b) { return a /= b; }; + + test_map_scalar_operations(1 , 1, init_a, T{ 3.5}, op, s_op); + test_map_scalar_operations(3 , 5, init_a, T{-2.5}, op, s_op); + test_map_scalar_operations(5 , 3, init_a, T{ 4. }, op, s_op); + test_map_scalar_operations(5 , 5, init_a, T{-5. }, op, s_op); + test_map_scalar_operations(5 , 5, init_a, T{ 1. }, op, s_op); + test_map_scalar_operations(5 , 5, init_a, T{ 6. }, op, s_op); + test_map_scalar_operations(10, 1, init_a, T{ 10.}, op, s_op); + test_map_scalar_operations(1 ,10, init_a, T{-0.5}, op, s_op); +}; diff --git a/test/unit/matrix/arithmetic_functions.cpp b/test/unit/matrix/arithmetic_functions.cpp index c2ad1a9..05eb229 100644 --- a/test/unit/matrix/arithmetic_functions.cpp +++ b/test/unit/matrix/arithmetic_functions.cpp @@ -6,113 +6,59 @@ */ //================================================================================================== #include "unit/tests.hpp" +#include "unit/common/arithmetic.hpp" #include -#include -template -void test_matrix_unary_ops(std::size_t rows, std::size_t cols, auto const &init_fn) -{ - MatrixType original(rows, cols); - MatrixType transposed_matrix(cols, rows); - - for (std::size_t r = 0; r < rows; ++r) - for (std::size_t c = 0; c < cols; ++c) - original(r,c) = init_fn(r, c); - - for (std::size_t r = 0; r < rows; ++r) - for (std::size_t c = 0; c < cols; ++c) - transposed_matrix(c, r) = original(r, c); - - TTS_EQUAL(original.transpose(), transposed_matrix); - TTS_EQUAL(original.conjugate(), original); - TTS_EQUAL(original.adjoint(), transposed_matrix); - - TTS_EXPECT(verify_rotgen_reentrance(original.transpose())); - TTS_EXPECT(verify_rotgen_reentrance(original.conjugate())); - TTS_EXPECT(verify_rotgen_reentrance(original.adjoint())); - - original.transposeInPlace(); - TTS_EQUAL(original, transposed_matrix); - - original.transposeInPlace(); - original.adjointInPlace(); - TTS_EQUAL(original, transposed_matrix); -} - -TTS_CASE_TPL("Test transpotion related operations", rotgen::tests::types) +TTS_CASE_TPL("Test dynamic matrix transposition-like operations", rotgen::tests::types) ( tts::type< tts::types> ) { - std::vector test_matrices = + auto const cases = rotgen::tests::generate_matrix_references(); + for (const auto& [rows, cols, fn] : cases) { - {3, 3, [](auto r, auto c) { return r + 3 * c - 2.5; }}, - {4, 9, [](auto r, auto c) { return r*r + 3.12 * c + 6.87; }}, - {2, 7, [](auto r, auto c) { return 1.1 * (r - c); }}, - {1, 5, [](auto , auto ) { return 9.99; }}, - {4, 2, [](auto , auto ) { return 0.0; }}, - {3, 3, [](auto r, auto c) { return (r == c) ? 1.0 : 0.0; }}, - {2, 2, [](auto r, auto c) { return (r + c) * 1e-10; }}, - {2, 2, [](auto r, auto ) { return (r + 1) * 1e+10; }} - }; - - for (const auto& [rows, cols, fn] : test_matrices) - { - test_matrix_unary_ops>(rows, cols, fn); + rotgen::matrix input(rows, cols); + rotgen::tests::prepare(rows,cols,fn,input); + rotgen::tests::check_shape_functions(input); } }; -template -void test_matrix_reductions(std::size_t rows, std::size_t cols, auto const& init_fn) -{ - using EigenMatrix = Eigen::Matrix; - - MatrixType original(rows, cols); - EigenMatrix ref(rows, cols); - - for (std::size_t r = 0; r < rows; ++r) - for (std::size_t c = 0; c < cols; ++c) - ref(r, c) = original(r,c) = init_fn(r, c); - - TTS_EQUAL(original.sum(), ref.sum()); - TTS_EQUAL(original.prod(), ref.prod()); - TTS_EQUAL(original.mean(), ref.mean()); - TTS_EQUAL(original.maxCoeff(), ref.maxCoeff()); - TTS_EQUAL(original.minCoeff(), ref.minCoeff()); - TTS_EQUAL(original.trace(), ref.trace()); - - std::ptrdiff_t row, col, ref_row, ref_col; - - double cmin = original.minCoeff(&row, &col); - double rmin = ref.minCoeff(&ref_row, &ref_col); - - TTS_EQUAL(cmin, rmin); - TTS_EQUAL(row, ref_row); - TTS_EQUAL(col, ref_col); - - double cmax = original.maxCoeff(&row, &col); - double rmax = ref.maxCoeff(&ref_row, &ref_col); - - TTS_EQUAL(cmax, rmax); - TTS_EQUAL(row, ref_row); - TTS_EQUAL(col, ref_col); -} - -TTS_CASE_TPL("Test reductions", rotgen::tests::types) +TTS_CASE_TPL("Test static matrix transposition-like operations", rotgen::tests::types) ( tts::type< tts::types> ) { - std::vector test_matrices = + auto const cases = rotgen::tests::generate_static_matrix_references(); + + auto process = [](D const& desc) { - {3, 3, [](auto r, auto c) {return r + c; }}, - {3, 3, [](auto , auto ) {return 0.0; }}, - {2, 4, [](auto r, auto c) {return -r -c*c - 1234; }}, - {4, 4, [](auto , auto ) {return 7.0; }}, - {1, 1, [](auto , auto ) {return 42.0; }}, - {4, 2, [](auto r, auto c) {return std::sin(r + c); }}, - {1, 5, [](auto r, auto c) {return -1.5 * r + 2.56 * c; }}, - {5, 7, [](auto r, auto c) {return (r == c ? 1.0 : 0.0); }} + rotgen::matrix input; + rotgen::tests::prepare(input.rows(),input.cols(),desc.init_fn,input); + rotgen::tests::check_shape_functions(input); }; - for (const auto& [rows, cols, fn] : test_matrices) + std::apply([&](auto const&... d) { (process(d),...);}, cases); +}; + +TTS_CASE_TPL("Test dynamic matrix reduction-like operations", rotgen::tests::types) +( tts::type< tts::types> ) +{ + auto const cases = rotgen::tests::generate_matrix_references(); + for (const auto& [rows, cols, fn] : cases) { - test_matrix_reductions>(rows, cols, fn); + rotgen::matrix input(rows, cols); + rotgen::tests::prepare(rows,cols,fn,input); + rotgen::tests::check_reduction_functions(input); } }; + +TTS_CASE_TPL("Test static matrix reduction-like operations", rotgen::tests::types) +( tts::type< tts::types> ) +{ + auto const cases = rotgen::tests::generate_static_matrix_references(); + + auto process = [](D const& desc) + { + rotgen::matrix input; + rotgen::tests::prepare(input.rows(),input.cols(),desc.init_fn,input); + rotgen::tests::check_reduction_functions(input); + }; + + std::apply([&](auto const&... d) { (process(d),...);}, cases); +}; \ No newline at end of file diff --git a/test/unit/matrix/functions.cpp b/test/unit/matrix/basic_api.cpp similarity index 99% rename from test/unit/matrix/functions.cpp rename to test/unit/matrix/basic_api.cpp index 82c26e0..39e9040 100644 --- a/test/unit/matrix/functions.cpp +++ b/test/unit/matrix/basic_api.cpp @@ -132,7 +132,7 @@ TTS_CASE_TPL("Test coefficient accessors", rotgen::tests::types) T& ref = a(2, 2); ref = 17; - assert(a(2, 2) == 17); + TTS_EQUAL(a(2, 2), 17); }; TTS_CASE_TPL("Test one index coefficient accessors", rotgen::tests::types) diff --git a/test/unit/matrix/constructors.cpp b/test/unit/matrix/constructors.cpp index 993ccea..418b8bd 100644 --- a/test/unit/matrix/constructors.cpp +++ b/test/unit/matrix/constructors.cpp @@ -97,7 +97,6 @@ TTS_CASE_TPL("Copy constructor on static matrix", rotgen::tests::types) TTS_EQUAL(b.cols(), rotgen::Index{5}); }; -/* TTS_CASE_TPL("Copy constructor on static/dynamic matrix", rotgen::tests::types) ( tts::type< tts::types> ) { @@ -114,7 +113,7 @@ TTS_CASE_TPL("Copy constructor on dynamic/static matrix", rotgen::tests::types) rotgen::matrix b = a; TTS_EQUAL(b.rows(), 5); TTS_EQUAL(b.cols(), 7); -};*/ +}; TTS_CASE_TPL("Move constructor transfers contents", rotgen::tests::types) ( tts::type< tts::types> ) diff --git a/test/unit/matrix/static_functions.cpp b/test/unit/matrix/generators.cpp similarity index 51% rename from test/unit/matrix/static_functions.cpp rename to test/unit/matrix/generators.cpp index 48d98ef..06f4827 100644 --- a/test/unit/matrix/static_functions.cpp +++ b/test/unit/matrix/generators.cpp @@ -38,6 +38,14 @@ void test_identity(const auto& matrix, std::size_t rows, std::size_t cols) TTS_CASE_TPL("Test zero", rotgen::tests::types) ( tts::type< tts::types> ) { + test_value(rotgen::matrix{}.setZero(), 3, 4, 0); + test_value(rotgen::matrix{}.setZero(), 1, 1, 0); + test_value(rotgen::matrix{}.setZero(), 10, 10, 0); + test_value(rotgen::matrix(1,1).setZero(3,4), 3, 4, 0); + test_value(rotgen::matrix().setZero(7, 5), 7, 5, 0); + test_value(rotgen::matrix(9,1).setZero(9, 3), 9, 3, 0); + test_value(rotgen::matrix(1,3).setZero(2, 3), 2, 3, 0); + test_value(rotgen::matrix::Zero(), 3, 4, 0); test_value(rotgen::matrix::Zero(), 1, 1, 0); test_value(rotgen::matrix::Zero(), 10, 10, 0); @@ -47,9 +55,37 @@ TTS_CASE_TPL("Test zero", rotgen::tests::types) test_value(rotgen::matrix::Zero(2, 3), 2, 3, 0); }; +TTS_CASE_TPL("Test ones", rotgen::tests::types) +( tts::type< tts::types> ) +{ + test_value(rotgen::matrix{}.setOnes(), 3, 4, 1); + test_value(rotgen::matrix{}.setOnes(), 1, 1, 1); + test_value(rotgen::matrix{}.setOnes(), 10, 10, 1); + test_value(rotgen::matrix(1,1).setOnes(3, 4), 3, 4, 1); + test_value(rotgen::matrix{}.setOnes(7, 5), 7, 5, 1); + test_value(rotgen::matrix(9,1).setOnes(9, 3), 9, 3, 1); + test_value(rotgen::matrix(1,3).setOnes(2, 3), 2, 3, 1); + + test_value(rotgen::matrix::Ones(), 3, 4, 1); + test_value(rotgen::matrix::Ones(), 1, 1, 1); + test_value(rotgen::matrix::Ones(), 10, 10, 1); + test_value(rotgen::matrix::Ones(3, 4), 3, 4, 1); + test_value(rotgen::matrix::Ones(7, 5), 7, 5, 1); + test_value(rotgen::matrix::Ones(9, 3), 9, 3, 1); + test_value(rotgen::matrix::Ones(2, 3), 2, 3, 1); +}; + TTS_CASE_TPL("Test constant", rotgen::tests::types) ( tts::type< tts::types> ) { + test_value(rotgen::matrix{}.setConstant(5.12), 3, 8, T(5.12)); + test_value(rotgen::matrix{}.setConstant(2.2), 1, 1, T(2.2)); + test_value(rotgen::matrix{}.setConstant(13), 11, 12, T(13)); + test_value(rotgen::matrix(1,1).setConstant(2, 7, 5.6), 2, 7, T(5.6)); + test_value(rotgen::matrix{}.setConstant(2, 2, 2.0), 2, 2, T(2.0)); + test_value(rotgen::matrix(9,1).setConstant(9, 3, 1.1), 9, 3, T(1.1)); + test_value(rotgen::matrix(1,9).setConstant(5, 9, 42), 5, 9,T(42)); + test_value(rotgen::matrix::Constant(5.12), 3, 8, T(5.12)); test_value(rotgen::matrix::Constant(2.2), 1, 1, T(2.2)); test_value(rotgen::matrix::Constant(13), 11, 12, T(13)); @@ -62,6 +98,14 @@ TTS_CASE_TPL("Test constant", rotgen::tests::types) TTS_CASE_TPL("Test random", rotgen::tests::types) ( tts::type< tts::types> ) { + test_random(rotgen::matrix{}.setRandom(), 2, 3); + test_random(rotgen::matrix{}.setRandom(), 1, 1); + test_random(rotgen::matrix{}.setRandom(), 11, 17); + test_random(rotgen::matrix{1,1}.setRandom(7, 3), 7, 3); + test_random(rotgen::matrix{}.setRandom(2, 2), 2, 2); + test_random(rotgen::matrix{4,1}.setRandom(4, 3), 4, 3); + test_random(rotgen::matrix{1,5}.setRandom(5, 5), 5, 5); + test_random(rotgen::matrix::Random(), 2, 3); test_random(rotgen::matrix::Random(), 1, 1); test_random(rotgen::matrix::Random(), 11, 17); @@ -74,6 +118,14 @@ TTS_CASE_TPL("Test random", rotgen::tests::types) TTS_CASE_TPL("Test identity", rotgen::tests::types) ( tts::type< tts::types> ) { + test_identity(rotgen::matrix{}.setIdentity(), 4, 5); + test_identity(rotgen::matrix{}.setIdentity(), 1, 1); + test_identity(rotgen::matrix{}.setIdentity(), 21, 3); + test_identity(rotgen::matrix{1,1}.setIdentity(2, 7), 2, 7); + test_identity(rotgen::matrix{}.setIdentity(2, 2), 2, 2); + test_identity(rotgen::matrix{3,1}.setIdentity(3, 3), 3, 3); + test_identity(rotgen::matrix{1,11}.setIdentity(5, 11), 5, 11); + test_identity(rotgen::matrix::Identity(), 4, 5); test_identity(rotgen::matrix::Identity(), 1, 1); test_identity(rotgen::matrix::Identity(), 21, 3); diff --git a/test/unit/matrix/io.cpp b/test/unit/matrix/io.cpp deleted file mode 100644 index 6742e1d..0000000 --- a/test/unit/matrix/io.cpp +++ /dev/null @@ -1,20 +0,0 @@ -//================================================================================================== -/* - ROTGEN - Runtime Overlay for Eigen - Copyright : CODE RECKONS - SPDX-License-Identifier: BSL-1.0 -*/ -//================================================================================================== -#include "unit/tests.hpp" -#include -#include - -TTS_CASE_TPL("Sample test", rotgen::tests::types) -( tts::type< tts::types> ) -{ - rotgen::matrix x({ {1,2} , {3,4} }); - std::ostringstream os; - os << x; - - TTS_EQUAL(os.str(), std::string{"1 2\n3 4"}); -}; diff --git a/test/unit/matrix/norms.cpp b/test/unit/matrix/norms.cpp index 8b4819b..4b05866 100644 --- a/test/unit/matrix/norms.cpp +++ b/test/unit/matrix/norms.cpp @@ -6,42 +6,32 @@ */ //================================================================================================== #include "unit/tests.hpp" +#include "unit/common/norms.hpp" #include -#include -TTS_CASE_TPL("Matrix norm-related operations", rotgen::tests::types) +TTS_CASE_TPL("Test dynamic matrix norm operations", rotgen::tests::types) ( tts::type< tts::types> ) { - std::vector test_matrices = + auto const cases = rotgen::tests::generate_matrix_references(); + for (const auto& [rows, cols, fn] : cases) { - { 3, 3, [](int r, int c) { return r + c; }}, - { 2, 3, [](int , int ) { return T{0}; }}, - { 2, 7, [](int r, int c) { return -r*r*r - c*c - T(1.23); }}, - {17, 3, [](int r, int c) { return r*c + T(0.98); }}, - { 1, 1, [](int , int ) { return 42; }}, - {10, 11, [](int r, int c) { return std::tan(T(r + c)); }}, - { 1, 5, [](int r, int c) { return T(-1.5)*r + T(2.56)*c + T(3.33); }}, - { 7, 1, [](int r, int c) { return r == c ? T(1) : T(0); }}, - { 0, 0, [](int r, int c) { return r == c ? T(1) : T(0); }}, + rotgen::matrix input(rows, cols); + rotgen::tests::prepare(rows,cols,fn,input); + rotgen::tests::check_norms_functions(input); + } +}; + +TTS_CASE_TPL("Test static matrix norm operations", rotgen::tests::types) +( tts::type< tts::types> ) +{ + auto const cases = rotgen::tests::generate_static_matrix_references(); + + auto process = [](D const& desc) + { + rotgen::matrix input; + rotgen::tests::prepare(input.rows(),input.cols(),desc.init_fn,input); + rotgen::tests::check_norms_functions(input); }; - for (const auto& [rows, cols, fn] : test_matrices) - { - rotgen::matrix matrix(rows, cols); - Eigen::Matrix ref(rows, cols); - - for (rotgen::Index r = 0; r < rows; ++r) - { - for (rotgen::Index c = 0; c < cols; ++c) - { - ref(r, c) = matrix(r, c) = fn(r,c); - } - } - - TTS_EQUAL(matrix.norm(), ref.norm()); - TTS_EQUAL(matrix.squaredNorm(), ref.squaredNorm()); - TTS_EQUAL(matrix.template lpNorm<1>() , ref.template lpNorm<1>()); - TTS_EQUAL(matrix.template lpNorm<2>() , ref.template lpNorm<2>()); - TTS_EQUAL(matrix.template lpNorm(), ref.template lpNorm()); - } + std::apply([&](auto const&... d) { (process(d),...);}, cases); }; \ No newline at end of file diff --git a/test/unit/tests.hpp b/test/unit/tests.hpp index 0bd2ca1..a14da60 100644 --- a/test/unit/tests.hpp +++ b/test/unit/tests.hpp @@ -8,6 +8,7 @@ #define TTS_MAIN #define TTS_CUSTOM_DRIVER_FUNCTION rotgen_main #include "tts.hpp" +#include "unit/common/references.hpp" #include #include #include @@ -25,30 +26,6 @@ namespace rotgen::tests , tts::types> , tts::types> >; - - struct matrix_descriptor - { - rotgen::Index rows, cols; - std::function init_fn; - }; - - template - struct matrix_block_test_case - { - rotgen::Index rows, cols; - std::function init_fn; - rotgen::Index i0, j0, ni, nj; - }; - - template - struct static_matrix_block_test_case - { - rotgen::Index rows, cols; - std::function init_fn; - static constexpr rotgen::Index ni = NI; - static constexpr rotgen::Index nj = NJ; - rotgen::Index i0, j0; - }; } #include @@ -56,7 +33,8 @@ namespace rotgen::tests template constexpr bool verify_rotgen_reentrance(T const&) { - return rotgen::concepts::entity; + if constexpr(rotgen::use_expression_templates) return true; + else return rotgen::concepts::entity; } int main(int argc, char const **argv)