.. _program_listing_file_include_ripple_math_mat.hpp: Program Listing for File mat.hpp ================================ |exhale_lsh| :ref:`Return to documentation for file ` (``include/ripple/math/mat.hpp``) .. |exhale_lsh| unicode:: U+021B0 .. UPWARDS ARROW WITH TIP LEFTWARDS .. code-block:: cpp #ifndef RIPPLE_MATH_MAT_HPP #define RIPPLE_MATH_MAT_HPP #include #include #include #include #include #include #include namespace ripple { template struct MatImpl; template < typename T, size_t Rows, size_t Cols, typename Layout = ContiguousOwned> using Mat = MatImpl, Num, Layout>; template struct MatImpl : public PolymorphicLayout> { private: static constexpr auto elements = size_t{Rows::value * Cols::value}; // clang-format off using Descriptor = StorageDescriptor>; using Storage = typename Descriptor::Storage; using Value = std::decay_t; // clang-format on template friend struct MatImpl; template friend struct LayoutTraits; public: Storage storage_; /*==--- [construction] ---------------------------------------------------==*/ ripple_all constexpr MatImpl() noexcept {} ripple_all constexpr MatImpl(T val) noexcept { unrolled_for( [&](auto i) { storage_.template get<0, i>() = val; }); } template = 0> ripple_all constexpr MatImpl(Values&&... values) noexcept { const auto v = Tuple{values...}; unrolled_for( [&](auto i) { storage_.template get<0, i>() = get(v); }); } ripple_all constexpr MatImpl(Storage storage) noexcept : storage_{storage} {} ripple_all constexpr MatImpl(const MatImpl& other) noexcept : storage_{other.storage_} {} ripple_all constexpr MatImpl(MatImpl&& other) noexcept : storage_{ripple_move(other.storage_)} {} template ripple_all constexpr MatImpl( const MatImpl& other) noexcept : storage_{other.storage_} {} template ripple_all constexpr MatImpl( MatImpl&& other) : storage_{ripple_move(other.storage_)} {} /*==--- [operator overloads] ---------------------------------------------==*/ ripple_all auto operator=(const MatImpl& other) noexcept -> MatImpl& { storage_ = other.storage_; return *this; } ripple_all auto operator=(MatImpl&& other) noexcept -> MatImpl& { storage_ = ripple_move(other.storage_); return *this; } template ripple_all auto operator=(const MatImpl& other) noexcept -> MatImpl& { unrolled_for([&](auto i) { storage_.template get<0, i>() = other.storage_.template get<0, i>(); }); return *this; } template ripple_all auto operator=(MatImpl&& other) noexcept -> MatImpl& { storage_ = ripple_move(other.storage_); return *this; } ripple_all auto operator()(size_t row, size_t col) noexcept -> Value& { return storage_.template get<0>(to_index(row, col)); } ripple_all auto operator()(size_t row, size_t col) const noexcept -> const Value& { return storage_.template get<0>(to_index(row, col)); } /*==--- [interface] ------------------------------------------------------==*/ ripple_all constexpr auto columns() const noexcept -> size_t { return Cols::value; } ripple_all constexpr auto rows() const noexcept -> size_t { return Rows::value; } template ripple_all constexpr auto at() const noexcept -> const Value& { static_assert((Row < rows()), "Compile time row index out of range!"); static_assert((Col < columns()), "Compile time col index out of range!"); constexpr size_t i = to_index(Row, Col); return storage_.template get<0, i>(); } template ripple_all constexpr auto at() const noexcept -> Value& { static_assert((Row < rows()), "Compile time row index out of range!"); static_assert((Col < columns()), "Compile time col index out of range!"); constexpr size_t i = to_index(Row, Col); return storage_.template get<0, i>(); } ripple_all constexpr auto size() const noexcept -> size_t { return elements; } private: ripple_all constexpr auto to_index(size_t r, size_t c) const noexcept -> size_t { return r * columns() + c; } }; template using mat_vec_result_t = typename array_traits_t::template ImplType; template ripple_all auto operator*(const MatImpl& m, const Array& v) noexcept -> mat_vec_result_t { constexpr size_t rows = R::value; constexpr size_t cols = C::value; using Value = typename array_traits_t::Value; using Result = mat_vec_result_t; static_assert( cols == array_traits_t::size, "Invalid configuration for matrix vector multiplication!"); static_assert( std::is_convertible_v::Value>, "Matrix and vector types must be convertible!"); Result result; unrolled_for([&](auto r) { result[r] = 0; unrolled_for([&](auto c) { result[r] += m(r, c) * v[c]; }); }); return result; } template < typename T1, typename T2, typename R1, typename C1R2, typename C2, typename L1, typename L2> ripple_all auto operator*( const MatImpl& a, const MatImpl& b) noexcept -> MatImpl { constexpr size_t rows = R1::value; constexpr size_t cols = C2::value; constexpr size_t inner = C1R2::value; static_assert( std::is_convertible_v, "Matrix multiplication requires data types which are convertible!"); using Result = MatImpl; Result res{0}; for (size_t r = 0; r < rows; ++r) { for (size_t c = 0; c < cols; ++c) { unrolled_for([&](auto i) { res(r, c) += a(r, i) * b(i, c); }); } } return res; } } // namespace ripple #endif // namespace RIPPLE_MATH_MAT_HPP