/* mmmatrix.hpp * Part of Mathematical library built (ab)using Modern C++ 17 abstractions. * * This library is not intended to be _performant_, it does not contain * hand written SMID / SSE / AVX optimizations. It is instead an example * of highly inefficient (but abstract!) code, where matrices can contain any * data type. * * Naoki Pross * 2018 ~ 2019 */ #pragma once #include namespace mm { template class basic_matrix; template using row_vec = basic_matrix; template using col_vec = basic_matrix; } template class mm::basic_matrix { public: using type = T; static constexpr std::size_t rows = Rows; static constexpr std::size_t cols = Cols; basic_matrix(const basic_matrix& other); basic_matrix(basic_matrix&& other); template basic_matrix(const basic_matrix& other); // access data T& at(std::size_t row, std::size_t col); void swap_rows(std::size_t x, std::size_t y); void swap_cols(std::size_t x, std::size_t y); // mathematical operations basic_matrix transposed(); inline basic_matrix t() { return transposed(); } // bool is_invertible(); // bool invert(); // basic_matrix inverse(); inline constexpr bool is_square() { return (Rows == Cols); } private: T data[Rows][Cols] = {}; }; template mm::basic_matrix::basic_matrix(const mm::basic_matrix& other) { for (int row = 0; row < Rows; row++) for (int col = 0; col < Cols; col++) data[row][col] = other.data[row][col]; } template mm::basic_matrix::basic_matrix(mm::basic_matrix&& other) { data = other.data; } template template mm::basic_matrix::basic_matrix(const mm::basic_matrix& other) { static_assert((ORows <= Rows), "cannot copy a taller matrix into a smaller one" ); static_assert((OCols <= Cols), "cannot copy a larger matrix into a smaller one" ); for (int row = 0; row < Rows; row++) for (int col = 0; col < Cols; col++) data[row][col] = other.data[row][col]; } /* member functions */ template T& mm::basic_matrix::at(std::size_t row, std::size_t col) { static_assert(row < Rows, "out of row bound"); static_assert(col < Cols, "out of column bound"); return data[row][col]; } template void mm::basic_matrix::swap_rows(std::size_t x, std::size_t y) { if (x == y) return; for (int col = 0; col < Cols; col++) std::swap(data[x][col], data[y][col]); } template void mm::basic_matrix::swap_cols(std::size_t x, std::size_t y) { if (x == y) return; for (int row = 0; row < rows; row++) std::swap(data[row][x], data[row][y]); } template mm::basic_matrix mm::basic_matrix::transposed() { mm::basic_matrix result; for (int row = 0; row < M; row++) for (int col = 0; col < N; col++) result.at(row, col) = at(col, row); return result; } /* operator overloading */ template mm::basic_matrix operator+( const mm::basic_matrix& a, const mm::basic_matrix& b ) { mm::basic_matrix result; for (int row = 0; row < Rows; row++) for (int col = 0; col < Cols; col++) result.at(row, col) = a.at(row, col) + a.at(row, col); return result; } template mm::basic_matrix operator*( const mm::basic_matrix& m, const T& scalar ) { mm::basic_matrix result; for (int row = 0; row < Rows; row++) for (int col = 0; col < Cols; col++) result.at(row, col) = m.at(row, col) * scalar; return result; } template mm::basic_matrix operator*( const T& scalar, const mm::basic_matrix& m ) { return m * scalar; } template mm::basic_matrix operator*( const mm::basic_matrix& a, const mm::basic_matrix& b ) { mm::basic_matrix result; // TODO: use a more efficient algorithm for (int row = 0; row < M; row++) for (int col = 0; col < N; col++) for (int k = 0; k < P; k++) result.at(row, col) = a.at(row, k) * b.at(k, col); return result; } template mm::basic_matrix operator-( const mm::basic_matrix& a, const mm::basic_matrix& b ) { return a + static_cast(-1) * b; } template std::ostream& operator<<(std::ostream& os, const mm::basic_matrix& m) { for (int row = 0; row < Rows; row++) { os << "[ "; for (int col = 0; col < (Cols -1); col++) { os << m.at(row, col); } os << m.at(Rows -1, Cols -1) << " ]\n"; } return os; }