From 6e39d531ed36d043e6f6fee6befca2be00fd3f57 Mon Sep 17 00:00:00 2001 From: ancarola Date: Sun, 30 Jun 2019 22:21:54 +0200 Subject: Optimized matrix section - Vector iterators: allow to iterate on rows, columns or diagonals - Transposition doesn't affect allocated space, O(1) --- include/mm/mmmatrix.hpp | 716 ++++++++++++++++++------------------------------ 1 file changed, 262 insertions(+), 454 deletions(-) (limited to 'include/mm/mmmatrix.hpp') diff --git a/include/mm/mmmatrix.hpp b/include/mm/mmmatrix.hpp index 9910273..f88e90c 100644 --- a/include/mm/mmmatrix.hpp +++ b/include/mm/mmmatrix.hpp @@ -17,39 +17,20 @@ #include #include #include +#include + +#include "mm/mmiterator.hpp" namespace mm { template class basic_matrix; - /* specialization of basic_matrix for Rows == Cols */ - template - class square_interface; - - /* - * Most general type of matrix iterator - * IterType = Row, Column, Diagonal - * Grid = constness of mm::basic_matrix - */ - template - class vector_iterator; - - /* - * Access methods interface - */ - - template - class access; - /* specialisations */ template class matrix; // simple matrix format - template - class t_matrix; // transposed matrix format - /* specialization of basic_matrx for Cols = 1 */ template class row_vec; @@ -61,155 +42,20 @@ namespace mm { template class square_matrix; - template - class t_square_matrix; - /* specialisation of a square_matrix for a sub-diagonal composed matrix */ template class diag_matrix; - - template - class t_diag_matrix; } -// TODO, short term solution -#define MM_ROW_ITER 0 -#define MM_COL_ITER 1 -#define MM_DIAG_ITER 2 - -template -class mm::vector_iterator -{ - std::size_t index; // variable index - - Grid& M; - - const int position; // fixed index, negative too for diagonal iterator - -public: - template - friend class vector_iterator; - - vector_iterator(Grid& M, int position, std::size_t index = 0); - - mm::vector_iterator operator++() - { - vector_iterator it = *this; - ++index; - return it; - } - - mm::vector_iterator operator--() - { - vector_iterator it = *this; - --index; - return it; - } - - mm::vector_iterator& operator++(int) - { - ++index; - return *this; - } - - mm::vector_iterator& operator--(int) - { - --index; - return *this; - } - - bool operator==(const mm::vector_iterator& other) const - { - return index == other.index; - } - - bool operator!=(const mm::vector_iterator& other) const - { - return index != other.index; - } - - bool ok() const - { - if constexpr(IterType == MM_ROW_ITER) - return index < Cols; - else - return index < Rows; - } - T& operator*() const; - T& operator[](std::size_t); -}; - -/* Row Iterators */ - -namespace mm { - - template - using row_iterator = vector_iterator>; - - template - using col_iterator = vector_iterator>; - - template - using const_row_iterator = vector_iterator>>; - - template - using const_col_iterator = vector_iterator>>; +/*namespace mm { template using diag_iterator = vector_iterator>; template - using const_diag_iterator = vector_iterator>>; -} - -/* - * Accessors - */ -template -class mm::access -{ -public: - - //access(mm::basic_matrix& ref) : M(ref) {} - - T& at(std::size_t row, std::size_t col); - const T& at(std::size_t row, std::size_t col) const; - - auto operator[](std::size_t index); - auto operator[](std::size_t index) const; - -//private: -// mm::basic_matrix& M; -protected: - std::array data; -}; - -/* - * Square interface - */ - -template -class mm::square_interface { -public: - - //square_interface(mm:basic_matrix& _M) : M(_M) {} - - T trace(); - inline T tr() { return trace(); } - - // TODO, determinant - - /// in place inverse - // TODO, det != 0 - // TODO, use gauss jordan for invertible ones - //void invert();, TODO, section algorithm - -//private: -// mm:basic_matrix& M; // one information more than mm::matrix ! -protected: - std::array data; -}; + using const_diag_iterator = vector_iterator::type, N, N, MM_DIAG_ITER, typename std::add_const>::type>; +}*/ /* @@ -217,15 +63,25 @@ protected: */ template -class mm::basic_matrix { +class mm::basic_matrix +{ public: using type = T; template friend class mm::basic_matrix; - static constexpr std::size_t rows = Rows; - static constexpr std::size_t cols = Cols; + template + friend class mm::matrix; + + template + friend class mm::iter::basic_iterator; + + //template + //friend class mm::iter::basic_iterator>; + + //template + //friend class mm::iter::basic_iterator::type, Rows, Cols, typename std::add_const>::type>; basic_matrix(); @@ -233,20 +89,13 @@ public: basic_matrix(std::initializer_list> l); // copyable and movable - basic_matrix(const basic_matrix& other); - basic_matrix(basic_matrix&& other); + basic_matrix(const basic_matrix& other) = default; + basic_matrix(basic_matrix&& other) = default; // copy from another matrix template basic_matrix(const basic_matrix& other); - // access data, basic definition - //virtual T& at(std::size_t row, std::size_t col); - //virtual const T& at(std::size_t row, std::size_t col) const; - - // allows to access a matrix M at row j col k with M[j][k] - //auto operator[](std::size_t index); - void swap_rows(std::size_t x, std::size_t y); void swap_cols(std::size_t x, std::size_t y); @@ -254,35 +103,15 @@ public: //virtual basic_matrix transposed() const; //inline basic_matrix td() const { return transposed(); } - /// downcast to square matrix - static inline constexpr bool is_square() { return (Rows == Cols); } - inline constexpr square_matrix to_square() const { - static_assert(is_square()); - return static_cast>(*this); - } - - /// downcast to row_vector - static inline constexpr bool is_row_vec() { return (Cols == 1); } - inline constexpr row_vec to_row_vec() const { - static_assert(is_row_vec()); - return static_cast>(*this); - } - - /// downcast to col_vector - static inline constexpr bool is_col_vec() { return (Rows == 1); } - inline constexpr col_vec to_col_vec() const { - static_assert(is_col_vec()); - return static_cast>(*this); - } - protected: template basic_matrix(ConstIterator begin, ConstIterator end); -//private: +private: std::array data; }; + template mm::basic_matrix::basic_matrix() { std::fill(data.begin(), data.end(), 0); @@ -300,16 +129,6 @@ mm::basic_matrix::basic_matrix( } } -template -mm::basic_matrix::basic_matrix( - const mm::basic_matrix& other -) : data(other.data) {} - -template -mm::basic_matrix::basic_matrix( - mm::basic_matrix&& other -) : data(std::forward(other.data)) {} - template template mm::basic_matrix::basic_matrix( @@ -339,40 +158,6 @@ mm::basic_matrix::basic_matrix( std::copy(begin, end, data.begin()); } - -/* member functions */ - -/*template -T& mm::basic_matrix::at(std::size_t row, std::size_t col) { - assert(row < Rows); // "out of row bound" - assert(col < Cols); // "out of column bound" - - return data[row * Cols + col]; -} - -template -const T& mm::basic_matrix::at(std::size_t row, std::size_t col) const { - assert(row < Rows); // "out of row bound" - assert(col < Cols); // "out of column bound" - - return data[row * Cols + col]; -} - -template -auto mm::basic_matrix::operator[](std::size_t index) { - if constexpr (is_row_vec() || is_col_vec()) { - return data.at(index); - } else { - return mm::row_iterator(*this, static_cast(index)); - - //return row_vec( - // data.cbegin() + (index * Cols), - // data.cbegin() + ((index + 1) * Cols) + 1 - ); - } -}*/ - - template void mm::basic_matrix::swap_rows(std::size_t x, std::size_t y) { if (x == y) @@ -387,274 +172,297 @@ void mm::basic_matrix::swap_cols(std::size_t x, std::size_t y) { if (x == y) return; - for (unsigned row = 0; row < rows; row++) + for (unsigned row = 0; row < Rows; row++) std::swap(this->at(row, x), this->at(row, y)); } -/*template -mm::basic_matrix mm::basic_matrix::transposed() const { - mm::basic_matrix result; +/* + * Matrix object + */ - for (unsigned row = 0; row < M; row++) - for (unsigned col = 0; col < N; col++) - result.at(col, row) = this->at(row, col); +template +class mm::matrix +{ +protected: - return result; -}*/ + // shallow construction + matrix(std::shared_ptr> grid = nullptr, bool tr = false) : M(grid), transposed(tr) {} +public: -/* TODO, operator overloading */ -/*template -mm::basic_matrix operator+( - const mm::basic_matrix& a, - const mm::basic_matrix& b -) { - mm::basic_matrix result; + //template + using vec_iterator = mm::iter::basic_iterator>; - for (unsigned row = 0; row < Rows; row++) - for (unsigned col = 0; col < Cols; col++) - result.at(row, col) = a.at(row, col) + b.at(row, col); + //template + using const_vec_iterator = mm::iter::basic_iterator::type, Rows, Cols, typename std::add_const>::type>; - return result; -} + // default zeros constructor + matrix() : M(std::make_shared>()), transposed(false) {} + + // from initializer_list + matrix(std::initializer_list> l) + : M(std::make_shared>(l)), transposed(false) {} -template -mm::basic_matrix operator*( - const mm::basic_matrix& m, - const T& scalar -) { - mm::basic_matrix result; - for (unsigned row = 0; row < Rows; row++) - for (unsigned col = 0; col < Cols; col++) - result.at(row, col) = m.at(row, col) * scalar; + // copyable and movable + matrix(const matrix& other) // deep copy + : M(std::make_shared>(*other.M)), transposed(other.transposed) {} - return result; -} + matrix(basic_matrix&& other) // move ptr + : M(other.M), transposed(other.transposed) + { + other.M = nullptr; + } -template -mm::basic_matrix operator*( - const T& scalar, - const mm::basic_matrix& m -) { - return m * scalar; -} + // copy from another matrix + /*template + matrix(const matrix& other) + : M(std::make_shared(*other.M)), transposed(other.transposed) {} */ + + matrix operator=(const basic_matrix& other) // deep copy + { + *M = *other.M; + transposed = other.transposed; + } -template -mm::basic_matrix operator*( - const mm::basic_matrix& a, - const mm::basic_matrix& b -) { - static_assert(P1 == P2, "invalid matrix multiplication"); - mm::basic_matrix result; + /* + * Transposition + */ - // TODO: use a more efficient algorithm - for (unsigned row = 0; row < M; row++) - for (unsigned col = 0; col < N; col++) - for (unsigned k = 0; k < P1; k++) - result.at(row, col) = a.at(row, k) * b.at(k, col); + matrix& transpose() + { + transposed = !transposed; + return *this; + } - return result; -} + matrix transpose() const + { + auto m = shallow_cpy(); + m.transposed = !transposed; + return m; + } -template -mm::basic_matrix operator-( - const mm::basic_matrix& a, - const mm::basic_matrix& b -) { - return a + (static_cast(-1) * b); -} + inline matrix& t() + { + return transpose(); + } -template -std::ostream& operator<<(std::ostream& os, const mm::basic_matrix& m) { - for (unsigned row = 0; row < Rows; row++) { - os << "[ "; - for (unsigned col = 0; col < (Cols -1); col++) { - os << std::setw(NumW) << m.at(row, col) << ", "; - } - os << std::setw(NumW) << m.at(row, (Cols -1)) << " ]\n"; + inline matrix t() const + { + return transpose(); } - return os; -}*/ + // strongly transpose + matrix transpose_cpy() const + { + matrix out(); // copy + // TODO + } -/* - * derivated classes - */ + /* + * Pointer status + */ -// simple format matrix -template -class mm::matrix : public mm::basic_matrix, virtual public mm::access -{ -public: - using mm::basic_matrix::basic_matrix; -}; + bool expired() const + { + return M == nullptr; + } -// transposed matrix -template -class mm::t_matrix : public mm::basic_matrix, virtual public mm::access -{ -public: - using mm::basic_matrix::basic_matrix; -}; + /* + * Downcasting conditions + */ -/* row vector specialization */ -template -class mm::row_vec : public mm::matrix { -public: - using mm::matrix::matrix; + /// downcast to square matrix + static inline constexpr bool is_square() { return (Rows == Cols); } + inline constexpr square_matrix to_square() const { + static_assert(is_square()); + return static_cast>(*this); + } - // TODO, begin, end -}; + /// downcast to row_vector + static inline constexpr bool is_row_vec() { return (Cols == 1); } + inline constexpr row_vec to_row_vec() const { + static_assert(is_row_vec()); + return static_cast>(*this); + } -/* column vector specialization */ -template -class mm::col_vec : public mm::t_matrix { -public: - using mm::t_matrix::t_matrix; + /// downcast to col_vector + static inline constexpr bool is_col_vec() { return (Rows == 1); } + inline constexpr col_vec to_col_vec() const { + static_assert(is_col_vec()); + return static_cast>(*this); + } - // TODO, begin, end -}; + /* Accessors */ -/* square matrix specialization */ -template -class mm::square_matrix : public mm::matrix , virtual public mm::square_interface { -public: - using mm::matrix::matrix; + T& at(std::size_t row, std::size_t col) + { + return (transposed) ? M->data[col * Cols + row] : M->data[row * Cols + col]; + } - // get the identity of size N - static inline constexpr square_matrix identity() { - mm::square_matrix i; - for (unsigned row = 0; row < N; row++) - for (unsigned col = 0; col < N; col++) - i.at(row, col) = (row == col) ? 1 : 0; + const T& at(std::size_t row, std::size_t col) const + { + return (transposed) ? M->data[col * Cols + row] : M->data[row * Cols + col]; + } - return i; + std::size_t rows() const { + return (transposed) ? Cols : Rows; } -}; -template -class mm::t_square_matrix : virtual public mm::t_matrix, virtual public mm::square_interface { -public: - using mm::t_matrix::t_matrix; -}; + std::size_t cols() const { + return (transposed) ? Rows : Cols; + } -/* - * K-diagonal square matrix format - * K is bounded between ]-N, N[ - */ + mm::matrix::vec_iterator operator[](std::size_t index) + { + return mm::matrix::vec_iterator(*M, index, !transposed); + } -/*template -class mm::diagonal_matrix : public mm::square_matrix -{ -public: - using mm::square_matrix::square_matrix; + mm::matrix::const_vec_iterator operator[](std::size_t index) const + { + return mm::matrix::const_vec_iterator(*M, index, !transposed); + } + + /* + * Basic matematical operations (dimension indipendent) + */ - // TODO, redefine at, operator[] - // TODO, matrix multiplication -};*/ + mm::matrix& operator+=(const mm::matrix& m) { -/*template -void mm::square_matrix::transpose() { - for (unsigned row = 0; row < N; row++) - for (unsigned col = 0; col < row; col++) - std::swap(this->at(row, col), this->at(col, row)); -}*/ + for (unsigned row = 0; row < std::min(rows(), m.rows()); ++row) + for (unsigned col = 0; col < std::min(cols(), m.cols()); ++col) + at(row, col) += m.at(row, col); + + return *this; + } -/* Iterators implementation */ + mm::matrix& operator-=(const mm::matrix& m) { -template -mm::vector_iterator::vector_iterator(Grid& _M, int pos, std::size_t i) - : index(i), M(_M), position(pos) -{ - if constexpr (IterType == MM_ROW_ITER) { - assert(pos < Cols); - } else if constexpr (IterType == MM_COL_ITER) { - assert(pos < Rows); - } else if constexpr (IterType == MM_DIAG_ITER) { - assert(abs(pos) < Rows); + for (unsigned row = 0; row < std::min(rows(), m.rows()); ++row) + for (unsigned col = 0; col < std::min(cols(), m.cols()); ++col) + at(row, col) -= m.at(row, col); + + return *this; } -} -template -T& mm::vector_iterator::operator*() const -{ - if constexpr (IterType == MM_ROW_ITER) - return M.data[position * Cols + index]; - else if constexpr (IterType == MM_COL_ITER) - return M.data[index * Cols + position]; - else if constexpr (IterType == MM_DIAG_ITER) - return (position > 0) ? - M.data[(index + position) * Cols + index] : - M.data[index * Cols + (index - position)]; -} + mm::matrix operator*=(const T& k) { -template -T& mm::vector_iterator::operator[](std::size_t i) -{ - if constexpr (IterType == MM_ROW_ITER) - return M.data[position * Cols + i]; - else if constexpr (IterType == MM_COL_ITER) - return M.data[i * Cols + position]; - else if constexpr (IterType == MM_DIAG_ITER) - return (position > 0) ? - M.data[(i + position) * Cols + i] : - M.data[i * Cols + (i - position)]; -} + for (unsigned row = 0; row < rows(); ++row) + for (auto& x : (*this)[row]) + x *= k; + + return *this; + } -/* - * Accessors implementation - */ +protected: -template -T& mm::access::at(std::size_t row, std::size_t col) -{ - if constexpr (Regular) - return data[row * Cols + col]; - else - return data[col * Cols + row]; // transpose + std::shared_ptr> M; + + matrix shallow_cpy() + { + return matrix(M, transposed); + } + +private: + + bool transposed; +}; + +/* Basic operator overloading (dimension indipendent) */ + +template +mm::matrix operator+( + mm::matrix a, + const mm::matrix& b +) { + return a += b; } -template -const T& mm::access::at(std::size_t row, std::size_t col) const -{ - if constexpr (Regular) - return data[row * Cols + col]; - else - return data[col * Cols + row]; // transpose +template +mm::matrix operator-( + mm::matrix a, + const mm::matrix& b +) { + return a -= b; } -template -auto mm::access::operator[](std::size_t index) -{ - if constexpr (this->is_row_vec() || this->is_col_vec()) - return data.at(index); - else if (Regular) - return mm::row_iterator(*this, static_cast(index)); - else - return mm::col_iterator(*this, static_cast(index)); +template +mm::matrix operator*( + mm::matrix a, + const T& k +) { + return a *= k; } -template -auto mm::access::operator[](std::size_t index) const -{ - if constexpr (this->is_row_vec() || this->is_col_vec()) - return data.at(index); - else if (Regular) - return mm::const_row_iterator(*this, static_cast(index)); - else - return mm::const_col_iterator(*this, static_cast(index)); +template +mm::matrix operator*( + const T& k, + mm::matrix a +) { + return a *= k; } -/* Square interface implementation */ +// simple multiplication +template +mm::matrix operator*( + const mm::matrix& a, + const mm::matrix& b +) { + static_assert(P1 == P2, "invalid matrix multiplication"); + assert(a.cols() == b.rows()); -template -T mm::square_interface::trace() -{ - T sum = 0; - for (mm::diag_iterator it(*this, 0); it.ok(); ++it) - sum += *it; + mm::matrix result; + mm::matrix bt = b.t(); // weak transposition - return sum; + for (unsigned row = 0; row < M; row++) + for (unsigned col = 0; col < N; col++) + result.at(row, col) = a[row] * bt[col]; // scalar product + + return result; } +// transposed multiplication +/*template +mm::matrix operator*( + const mm::matrix& a, + const mm::matrix& b +) { + static_assert(P1 == P2, "invalid matrix multiplication"); + assert(a.cols() == b.rows()); + + mm::matrix result; + mm::matrix bt = b.t(); // weak transposition + + for (unsigned row = 0; row < M; row++) + for (unsigned col = 0; col < N; col++) + result.at(row, col) = a[row] * bt[col]; // scalar product + + return result; +}*/ + + +/*template +void mm::square_matrix::transpose() { + for (unsigned row = 0; row < N; row++) + for (unsigned col = 0; col < row; col++) + std::swap(this->at(row, col), this->at(col, row)); +}*/ + + +/* + * Matrix operator << + */ + +template +std::ostream& operator<<(std::ostream& os, const mm::matrix& m) { + + for (unsigned index = 0; index < m.rows(); index++) { + os << "[ "; + for (unsigned col = 0; col < m.cols()-1; ++col) { + os << std::setw(NumW) << m.at(index, col) << ", "; + } + os << std::setw(NumW) << m.at(index, m.cols()-1) << " ]\n"; + } + + return os; +} -- cgit v1.2.1