diff options
author | Nao Pross <naopross@thearcway.org> | 2019-10-10 01:18:49 +0200 |
---|---|---|
committer | Nao Pross <naopross@thearcway.org> | 2019-10-10 01:19:17 +0200 |
commit | 241149ba6e85ad225d9c355e2033f0595e29a10d (patch) | |
tree | 6884a1c042e1434e403fd5efc3dad3e82048ba42 | |
parent | New matrix data model (breaks everything) (diff) | |
download | libmm-241149ba6e85ad225d9c355e2033f0595e29a10d.tar.gz libmm-241149ba6e85ad225d9c355e2033f0595e29a10d.zip |
Update access model for operator|
The operator | can access the matrix either by directly changing
the values (by reference, mm::mutate(M)) or by creating first a
a copy of the matrix (mm::clone(M)).
ToDo:
The order of destruction of the mutate object is not yet well defined,
and therefore it is not yet deterministic enough to work with
expressions like (pseudocode)
matrix m = a * b * (a | mm::alg::invert)
because operator| (defaults to mutate), should not but could, change
the value of a before the product a * b gets evaluated.
-rw-r--r-- | include/mm/mmmatrix.hpp | 120 | ||||
-rw-r--r-- | include/mm/view.hpp | 134 | ||||
-rw-r--r-- | test/matrix_example.cpp | 72 |
3 files changed, 233 insertions, 93 deletions
diff --git a/include/mm/mmmatrix.hpp b/include/mm/mmmatrix.hpp index d653d72..0f8833e 100644 --- a/include/mm/mmmatrix.hpp +++ b/include/mm/mmmatrix.hpp @@ -11,13 +11,19 @@ */ #pragma once +#include "mm/debug.hpp" + #include <iostream> +#include <iomanip> #include <cassert> #include <initializer_list> #include <array> #include <memory> +/* + * Forward declarations + */ namespace mm { using index = std::size_t; @@ -29,46 +35,96 @@ namespace mm { class matrix; template<typename T, std::size_t N> + class vector; + + template<typename T, std::size_t N> class square_matrix; template<typename T, std::size_t N> class diagonal_matrix; + } /* - * Matrix class, no access methods + * Matrix Classes */ namespace mm { template<typename T, std::size_t Rows, std::size_t Cols> - class basic_matrix + struct basic_matrix { public: using type = T; + static constexpr std::size_t rows = Rows; + static constexpr std::size_t cols = Cols; + + template<typename U, std::size_t ORows, std::size_t OCols> - friend class mm::matrix; + friend class mm::basic_matrix; + + virtual ~basic_matrix() {}; // copy from another matrix - template<std::size_t ORows, std::size_t OCols> - matrix(const basic_matrix<T, ORows, OCols>& other); + // template<std::std::size_t ORows, std::size_t OCols> + // basic_matrix(const basic_matrix<T, ORows, OCols>& other) { + // static_assert(ORows <= Rows); + // static_assert(OCols <= Cols); + + // for (index row = 0; row < Rows; row++) + // for (index col = 0; col < Cols; col++) + // at(row, col) = other.at(row, col); + // } virtual T& at(index row, index col) = 0; - virtual const T& at(index row, index col) const = 0; + virtual const T& at(index row, index col) const = 0; + + // constexpr std::size_t rows() { return Rows; } + // constexpr std::size_t cols() { return Cols; } + + protected: + basic_matrix() { + npdebug("default construtor"); + } + + basic_matrix(const basic_matrix<T, Rows, Cols>& other) { + npdebug("copy constructor"); + } + + basic_matrix(basic_matrix<T, Rows, Cols>&& other) { + npdebug("move constructor"); + } }; + /* Specializations */ template<typename T, std::size_t Rows, std::size_t Cols> - struct matrix : public basic_matrix<T, N> + struct matrix : public basic_matrix<T, Rows, Cols> { public: + // aggregate initialization + template<typename ...E, + typename std::enable_if< + std::is_convertible<E, T>::value + >::type... + > + matrix(E ...e) : m_data({{std::forward<E>(e)...}}) {} + + matrix(const matrix<T, Rows, Cols>& o) + : basic_matrix<T, Rows, Cols>(o), m_data(o.m_data) {} + + matrix(matrix<T, Rows, Cols>&& o) + : basic_matrix<T, Rows, Cols>(std::move(o)), m_data(std::move(o.m_data)) {} + + virtual ~matrix() = default; + virtual T& at(index row, index col) override { return m_data[row * Cols + col]; } virtual const T& at(index row, index col) const override { - return at(row, col); + return m_data[row * Cols + col]; } private: @@ -80,20 +136,8 @@ namespace mm { struct vector : public matrix<T, 1, N> {}; template<typename T, std::size_t N> - struct square_matrix : public basic_matrix<T, N> - { - public: - virtual T& at(index row, index col) override { - return m_data[row * N + col]; - } - - virtual const T& at(index row, index col) const override { - return at(row, col); - } - - private: - std::array<T, N*N> m_data; - }; + struct square_matrix : public matrix<T, N, N> + {}; template<typename T, std::size_t N> struct identity_matrix : public basic_matrix<T, N, N> @@ -104,17 +148,17 @@ namespace mm { } private: - T m_useless; - T& at(index row, index col) { return m_useless; } - } + // not allowed + T& at(index row, index col) { return static_cast<T>(0); } + }; template<typename T, std::size_t N> struct diagonal_matrix : public basic_matrix<T, N, N> { public: T& at(index row, index col) override { - n_null_element = static_cast<T>(0); - return (row != col) ? m_data[row] : n_null_element; + m_null_element = static_cast<T>(0); + return (row != col) ? m_data[row] : m_null_element; } const T& at(index row, index col) const override { @@ -124,5 +168,27 @@ namespace mm { private: T m_null_element; std::array<T, N> m_data; + }; +} + +/* + * Matrix Opertors + */ + +namespace mm { +} + + +template<typename T, std::size_t Rows, std::size_t Cols, unsigned NumW = 3> +std::ostream& operator<<(std::ostream& os, const mm::basic_matrix<T, Rows, Cols>& m) { + for (mm::index row = 0; row < Rows; row++) { + os << "[ "; + for (mm::index col = 0; col < (Cols -1); col++) { + os << std::setw(NumW) << m.at(row, col) << ", "; + } + os << std::setw(NumW) << m.at(row, (Cols -1)) << " ]\n"; } + + return os; } +
\ No newline at end of file diff --git a/include/mm/view.hpp b/include/mm/view.hpp index 910c16a..e701a78 100644 --- a/include/mm/view.hpp +++ b/include/mm/view.hpp @@ -1,66 +1,112 @@ #pragma once -#include <mmmatrix.hpp> +#include "mm/mmmatrix.hpp" +#include <variant> +#include <tuple> +#include <type_traits> +#include <functional> -namespace mm::alg { - template < - template<typename, std::size_t, std::size_t> typename Matrix, - typename T, std::size_t Rows, std::size_t Cols - > - struct visitor - { - using type = T; +namespace mm { + + namespace algorithm { + // does nothing + struct visit + { + visit() = default; - // copy constructible - visitor(const visitor& other) = default; + template<typename Matrix> + void operator()(Matrix& m) {} + }; - T& operator()(const Matrix<T, Rows, Cols>& m, index row, index col) { - return m.at(row, col); - } + struct transpose : public visit + { + /// does not work with non-square matrices + template<typename Matrix> + void operator()(Matrix& m) { + static_assert(Matrix::rows == Matrix::cols); + // naiive impl + for (index r = 0; r < m.rows / 2; r++) + for (index c = 0; c < m.cols; c++) + if (c != r) + std::swap(m.at(r, c), m.at(c, r)); + } + }; - const T& operator()(const Matrix<T, Rows, Cols>& m, index row, index col) { - return operator()(m, row, col); - } - }; + /// algorithm aliases + using tr = transpose; + } + + /// namespace alias + namespace alg = algorithm; - template < - template<typename, std::size_t, std::size_t> typename Matrix, - typename T, std::size_t Rows, std::size_t Cols - > - struct transpose : public visitor<Matrix, T, Rows, Cols> + template<typename Matrix> + struct clone { - T& operator()(const Matrix<T, Rows, Cols> m, index row, index col) { - // assert(col < Rows) - // assert(row < Cols) - return m.at(col, row); + Matrix matrix; + + explicit clone(Matrix&& m) : matrix(m) {} + explicit clone(const Matrix& m) : matrix(m) {} + + operator Matrix() { + return std::move(matrix); } }; -} -namespace mm { - template < - template<typename, std::size_t, std::size_t> typename Matrix, - typename T, std::size_t Rows, std::size_t Cols - > - struct view + template<typename Matrix, typename ...Algs> + struct mutate { - Matrix<T, Rows, Cols>& m; - // std::stack<std::unique_ptr<alg::visitor>> visitors; - std::unique_ptr<alg::visitor> visitor; + Matrix& matrix; + std::tuple<Algs...> visitors; + + explicit mutate(Matrix& m) : matrix(m) {} + + template<typename ...OAlgs, typename Alg> + explicit mutate(Matrix& m, std::tuple<OAlgs...>&& t, Alg&& v) + : matrix(m) + { + /// append the new operator + visitors = std::tuple_cat(t, std::make_tuple(v)); + } + + ~mutate() { + visit(); + } - T& at(index row, index col) { - return visitor(m, row, col); + void visit() { + std::apply([this](auto&&... v) { + (v(matrix),...); + }, visitors); } - view& operator|=(const alg::visitor& other) { - // visitors.push(std::move(std::make_unique<alg::visitor>(other))); - visitor = std::make_unique<alg::visistor>(other); + operator Matrix() { + return std::move(matrix); } }; - view operator|(const view& left, const alg::visitor& right) { - return left |= right; + template<typename Matrix, typename Alg> + clone<Matrix> operator|(clone<Matrix>&& cl, Alg&& v) { + static_assert(std::is_convertible<Alg, alg::visit>::value); + /// apply alg operator + v(cl.matrix); + /// forward to next alg + return clone<Matrix>(std::move(cl)); + } + + template<typename Matrix, typename ...Algs, typename Alg> + mutate<Matrix, Algs..., Alg> operator|(mutate<Matrix, Algs...>&& mut, Alg&& v) { + static_assert(std::is_convertible<Alg, alg::visit>::value); + /// append alg to the visitors tuple + return mutate<Matrix, Algs..., Alg>( + mut.matrix, + std::move(mut.visitors), + v + ); + } + + template<typename Matrix, typename Alg> + mutate<Matrix, Alg> operator|(Matrix& m, Alg&& v) { + return mutate(m) | std::move(v); } } diff --git a/test/matrix_example.cpp b/test/matrix_example.cpp index 96ba67d..af95a00 100644 --- a/test/matrix_example.cpp +++ b/test/matrix_example.cpp @@ -1,36 +1,64 @@ #include "mm/mmmatrix.hpp" +#include "mm/view.hpp" #include <iostream> #include <complex> -int main(int argc, char *argv[]) { - std::cout << "MxN dimensional (int) matrices" << std::endl; - mm::matrix<int, 3, 2> a {{1, 2}, {3, 4}, {5, 6}}; - mm::matrix<int, 3, 2> b {{4, 3}, {9, 1}, {2, 5}}; - mm::matrix<int, 2, 4> c {{1, 2, 3, 4}, {5, 6, 7, 8}}; - auto ct = c.t(); +// int main(int argc, char *argv[]) { +int main() { + // std::cout << "MxN dimensional (int) matrices" << std::endl; - std::cout << "a = \n" << a; - std::cout << "b = \n" << b; - std::cout << "c = \n" << c; - std::cout << "c^t = \n" << ct; - std::cout << std::endl; + mm::matrix<int, 2, 2> a { 1, 2, 3, 4 }; + + // mm::matrix<int, 3, 2> a {{1, 2}, {3, 4}, {5, 6}}; + // mm::matrix<int, 3, 2> a {1, 2, 3, 4, 5, 6}; + + // mm::matrix<int, 3, 2> b {4, 3, 9, 1, 2, 5}; + // mm::matrix<int, 2, 4> c {1, 2, 3, 4, 5, 6, 7, 8}; + + // std::cout << "a = \n" << a; + // std::cout << "b = \n" << b; + // std::cout << "c = \n" << c; + // std::cout << std::endl; // access elements - std::cout << "Access elements" << std::endl; - std::cout << "a.at(2,0) = " << a.at(2, 0) << std::endl; - std::cout << "a[2][0] = " << a[2][0] << std::endl;; - std::cout << std::endl; + // std::cout << "Access elements" << std::endl; + // std::cout << "a.at(2,0) = " << a.at(2, 0) << std::endl; + // std::cout << "a[2][0] = " << a[2][0] << std::endl;; + // std::cout << std::endl; // basic operations - std::cout << "Basic operations" << std::endl; - std::cout << "a + b = \n" << a + b; - std::cout << "a - b = \n" << a - b; - std::cout << "a * c = \n" << a * c; - std::cout << "a * 2 = \n" << a * 2; - std::cout << "2 * a = \n" << 2 * a; - std::cout << "a.td() = \n" << a.t(); // or a.trasposed(); + // std::cout << "Basic operations" << std::endl; + // std::cout << "a + b = \n" << a + b; + // std::cout << "a - b = \n" << a - b; + // std::cout << "a * c = \n" << a * c; + // std::cout << "a * 2 = \n" << a * 2; + // std::cout << "2 * a = \n" << 2 * a; + // std::cout << "a.td() = \n" << a.t(); // or a.trasposed(); + // std::cout << std::endl; + + std::cout << "a = \n" << a; + + std::cout << "Cloning a" << std::endl; + decltype(a) e = mm::clone(a) | mm::alg::transpose(); + std::cout << "e = \n" << e; std::cout << std::endl; + std::cout << "Mutating a" << std::endl; + mm::mutate(a) | mm::alg::transpose(); + std::cout << "a = \n" << a; + std::cout << std::endl; + + a | mm::alg::tr(); + std::cout << "a = \n" << a; + + // std::cout << "Converting clone object" << std::endl; + // mm::matrix<int, 2, 2> g = e; + // std::cout << std::endl; + + // std::cout << "Converting mutate object" << std::endl; + // mm::matrix<int, 2, 2> h = f; + // std::cout << std::endl; + return 0; } |