#pragma once #include #include #include #include namespace hpr { // forward declarations template requires (Rows >= 0 && Cols >= 0) class Matrix; template using SubMatrix = typename std::conditional<(Rows >= 2 && Cols >= 2), Matrix, Matrix>::type; // type traits template struct is_matrix : public std::false_type {}; template struct is_matrix> : public std::true_type {}; // concepts template concept IsMatrix = is_matrix::value; } namespace hpr { template requires (Rows >= 0 && Cols >= 0) class Matrix : public StaticArray { using base = StaticArray; public: using value_type = Type; using size_type = Size; using pointer = Type*; using reference = Type&; using iterator = Iterator; using const_reference = Type const&; using const_iterator = Iterator; protected: size_type p_rows; size_type p_cols; public: friend constexpr void swap(Matrix& main, Matrix& other) { using std::swap; swap(static_cast(main), static_cast(other)); swap(main.p_rows, other.p_rows); swap(main.p_cols, other.p_cols); } inline Matrix() : base {}, p_rows {Rows}, p_cols {Cols} {} inline Matrix(const Matrix& ms) : base {static_cast(ms)}, p_rows {Rows}, p_cols {Cols} {} inline Matrix(Matrix&& ms) noexcept: base {std::forward(static_cast(ms))}, p_rows {Rows}, p_cols {Cols} {} inline Matrix& operator=(const Matrix& ms) { //base::operator=(ms); swap(*this, ms); return *this; } inline explicit Matrix(const base& vs) : base {vs}, p_rows {Rows}, p_cols {Cols} {} inline explicit Matrix(base&& vs) noexcept: base {std::forward(vs)}, p_rows {Rows}, p_cols {Cols} {} inline Matrix(typename base::iterator start, typename base::iterator end) : base {start, end}, p_rows {Rows}, p_cols {Cols} {} inline Matrix(typename base::const_iterator start, typename base::const_iterator end) : base {start, end}, p_rows {Rows}, p_cols {Cols} {} inline Matrix(std::initializer_list list) : base {list}, p_rows {Rows}, p_cols {Cols} {} template inline Matrix(value_type&& v, Args&& ...args) requires (1 + sizeof...(args) == Rows * Cols): base {v, static_cast(std::forward(args))...}, p_rows {Rows}, p_cols {Cols} {} inline Matrix(const value_type& v) : base {}, p_rows {Rows}, p_cols {Cols} { for (Size n = 0; n < Rows * Cols; ++n) (*this)[n] = v; } inline Matrix& operator=(const value_type& v) { for (Size n = 0; n < Rows * Cols; ++n) (*this)[n] = v; return *this; } inline explicit Matrix(const Quaternion& q) requires (Rows == 3 && Cols == 3 || Rows == 4 && Cols == 4) : base {}, p_rows {Rows}, p_cols {Cols} { const scalar s = pow(norm(q), -2); (*this)(0, 0) = 1 - 2 * s * (q[2] * q[2] + q[3] * q[3]); (*this)(1, 0) = 2 * s * (q[1] * q[2] - q[3] * q[0]); (*this)(2, 0) = 2 * s * (q[1] * q[3] - q[2] * q[0]); (*this)(0, 1) = 2 * s * (q[1] * q[2] + q[3] * q[0]); (*this)(1, 1) = 1 - 2 * s * (q[1] * q[1] + q[3] * q[3]); (*this)(2, 1) = 2 * s * (q[2] * q[3] + q[1] * q[0]); (*this)(0, 2) = 2 * s * (q[1] * q[3] + q[2] * q[0]); (*this)(1, 2) = 2 * s * (q[2] * q[3] + q[1] * q[0]); (*this)(2, 2) = 1 - 2 * s * (q[1] * q[1] + q[2] * q[2]); if constexpr (Rows == 4) (*this)(3, 3) = 1; } // access inline reference operator()(size_type row, size_type col) { if (row >= p_rows || std::numeric_limits::max() - p_rows < row) throw std::out_of_range("Row index is out of range"); if (col >= p_cols || std::numeric_limits::max() - p_cols < col) throw std::out_of_range("Column index is out of range"); return (*this)[col + p_rows * row]; } inline const_reference operator()(size_type row, size_type col) const { if (row >= p_rows || std::numeric_limits::max() - p_rows < row) throw std::out_of_range("Row index is out of range"); if (col >= p_cols || std::numeric_limits::max() - p_cols < col) throw std::out_of_range("Column index is out of range"); return (*this)[col + p_rows * row]; } Vector row(size_type row) const { Vector vs; for (auto n = 0; n < Cols; ++n) vs[n] = (*this)(row, n); return vs; } void row(size_type row, const Vector& vs) { for (auto n = 0; n < Cols; ++n) (*this)(row, n) = vs[n]; } Vector col(size_type col) const { Vector vs; for (auto n = 0; n < Rows; ++n) vs[n] = (*this)(n, col); return vs; } void col(size_type col, const Vector& vs) { for (auto n = 0; n < Rows; ++n) (*this)(n, col) = vs[n]; } [[nodiscard]] constexpr size_type rows() const { return p_rows; } [[nodiscard]] constexpr size_type cols() const { return p_cols; } // member functions [[nodiscard]] constexpr bool is_square() const { return p_rows == p_cols; } inline Matrix& fill(value_type value) { for (auto n = 0; n < this->size(); ++n) (*this)[n] = value; return *this; } // Global functions static inline Matrix identity() { Matrix ms; for (auto n = 0; n < Rows; ++n) //for (auto k = 0; k < Cols; ++k) ms(n, n) = 1; return ms; } }; // global operators template inline Matrix operator+(const Matrix& lhs) { Matrix ms; for (Size n = 0; n < lhs.size(); ++n) ms[n] = lhs[n]; return ms; } template inline Matrix operator-(const Matrix& lhs) { Matrix ms; for (Size n = 0; n < lhs.size(); ++n) ms[n] = -lhs[n]; return ms; } template inline Matrix& operator+=(Matrix& lhs, const Matrix& rhs) { for (Size n = 0; n < lhs.size(); ++n) lhs[n] += rhs[n]; return lhs; } template inline Matrix& operator-=(Matrix& lhs, const Matrix& rhs) { for (Size n = 0; n < lhs.size(); ++n) lhs[n] -= rhs[n]; return lhs; } template inline Matrix& operator*=(Matrix& lhs, const Matrix& rhs) { Matrix temp {lhs}; for (Size n = 0; n < R; ++n) for (Size k = 0; k < C; ++k) lhs(n, k) = sum(temp.col(k) * rhs.row(n)); return lhs; } template inline Matrix operator+(const Matrix& lhs, const Matrix& rhs) { Matrix ms {lhs}; for (Size n = 0; n < lhs.size(); ++n) ms[n] += rhs[n]; return ms; } template inline Matrix operator-(const Matrix& lhs, const Matrix& rhs) { Matrix ms {lhs}; for (Size n = 0; n < lhs.size(); ++n) ms[n] -= rhs[n]; return ms; } template inline Matrix operator*(const Matrix& lhs, const Matrix& rhs) { Matrix ms; for (Size n = 0; n < R; ++n) for (Size k = 0; k < C; ++k) ms(n, k) = sum(lhs.col(k) * rhs.row(n)); return ms; } template inline bool operator==(const Matrix& lhs, const Matrix& rhs) { for (Size n = 0; n < lhs.size(); ++n) if (lhs[n] != rhs[n]) return false; return true; } template inline bool operator!=(const Matrix& lhs, const Matrix& rhs) { for (Size n = 0; n < lhs.size(); ++n) if (lhs[n] == rhs[n]) return false; return true; } template inline Matrix& operator+=(Matrix& lhs, const T& rhs) { for (Size n = 0; n < lhs.size(); ++n) lhs[n] += rhs; return lhs; } template inline Matrix& operator-=(Matrix& lhs, const T& rhs) { for (Size n = 0; n < lhs.size(); ++n) lhs[n] -= rhs; return lhs; } template inline Matrix& operator*=(Matrix& lhs, const T& rhs) { for (Size n = 0; n < lhs.size(); ++n) lhs[n] *= rhs; return lhs; } template inline Matrix& operator/=(Matrix& lhs, const T& rhs) { for (Size n = 0; n < lhs.size(); ++n) lhs[n] /= rhs; return lhs; } template inline Matrix operator+(const Matrix& lhs, const T& rhs) { Matrix ms {lhs}; for (Size n = 0; n < lhs.size(); ++n) ms[n] += rhs; return ms; } template inline Matrix operator-(const Matrix& lhs, const T& rhs) { Matrix ms {lhs}; for (Size n = 0; n < lhs.size(); ++n) ms[n] -= rhs; return ms; } template inline Matrix operator*(const Matrix& lhs, const T& rhs) { Matrix ms {lhs}; for (Size n = 0; n < lhs.size(); ++n) ms[n] *= rhs; return ms; } template inline Matrix operator/(const Matrix& lhs, const T& rhs) { Matrix ms {lhs}; for (Size n = 0; n < lhs.size(); ++n) ms[n] /= rhs; return ms; } template inline Vector operator*(const Matrix& ms, const Vector& vs) { Vector res; for (Size n = 0; n < R; ++n) res[n] = sum(ms.row(n) * vs); return res; } template inline Vector operator*(const Vector& vs, const Matrix& ms) { Vector res; for (Size n = 0; n < C; ++n) res[n] = sum(ms.col(n) * vs); return res; } template inline bool operator==(const Matrix& lhs, const Vector& rhs) { return false; } template inline bool operator!=(const Matrix& lhs, const Vector& rhs) { return true; } // matrix operations //! Transpose matrix template inline Matrix transpose(const Matrix& ms) { Matrix res; for (Size n = 0; n < R; ++n) for (Size k = 0; k < C; ++k) res(k, n) = ms(n, k); return res; } //! Trace of a matrix template inline T trace(const Matrix& ms) requires (R == C) { T res; for (auto n = 0; n < R; ++n) res += ms(n, n); return res; } //! Minor of a matrix template inline SubMatrix minor(const Matrix& ms, Size row, Size col) { if (ms.size() < 4) throw std::runtime_error("Matrix should be greater 2x2"); SubMatrix minor; auto minor_iter = minor.begin(); for (auto n = 0; n < R; ++n) for (auto k = 0; k < C; ++k) if (k != col && n != row) *(minor_iter++) = ms[k + ms.rows() * n]; return minor; } //! Determinant of a matrix template inline scalar det(const Matrix& ms) requires (R == C) { if (ms.size() == 1) return ms[0]; else if (ms.size() == 4) return ms(0, 0) * ms(1, 1) - ms(0, 1) * ms(1, 0); else { scalar res = 0; for (auto n = 0; n < ms.cols(); ++n) res += pow(-1, n) * ms(0, n) * det(minor(ms, 0, n)); return res; } } //! Adjoint matrix template inline Matrix adj(const Matrix& ms) { Matrix res; for (auto n = 0; n < R; ++n) for (auto k = 0; k < C; ++k) res(n, k) = pow(-1, n + k) * det(minor(ms, n, k)); return transpose(res); } //! Inverse matrix template inline Matrix inv(const Matrix& ms) { return adj(ms) / det(ms); } // Aliases template using mat = Matrix; using mat2 = Matrix; using mat3 = Matrix; using mat4 = Matrix; }