hyporo-cpp/source/hpr/math/matrix/matrix_space.hpp

364 lines
12 KiB
C++
Raw Normal View History

2022-10-27 22:27:50 +05:00
#pragma once
2023-01-11 14:46:49 +05:00
#include "../integer.hpp"
#include "../scalar.hpp"
#include "../../containers/array/static_array.hpp"
2022-12-06 23:52:49 +05:00
2022-10-27 22:27:50 +05:00
namespace hpr
{
2023-01-11 14:46:49 +05:00
// forward declarations
template <IsReal Type, Size Rows, Size Cols> requires (Rows >= 0 && Cols >= 0)
class Matrix;
template <IsReal Type, Size Rows, Size Cols>
using SubMatrix = typename std::conditional<(Rows >= 2 && Cols >= 2), Matrix<Type, Rows - 1, Cols - 1>, Matrix<Type, 1, 1>>::type;
// type traits
template <typename T>
struct is_matrix : public std::false_type {};
template <typename T, Size Rows, Size Cols>
struct is_matrix<Matrix<T, Rows, Cols>> : public std::true_type {};
// concepts
template <typename T>
concept IsMatrix = is_matrix<T>::value;
}
namespace hpr
2022-10-27 22:27:50 +05:00
{
2023-01-11 14:46:49 +05:00
template <IsReal Type, Size Rows, Size Cols> requires (Rows >= 0 && Cols >= 0)
class Matrix : public StaticArray<Type, Rows * Cols>
{
using base = StaticArray<Type, Rows * Cols>;
2022-10-27 22:27:50 +05:00
public:
using value_type = Type;
2023-01-11 14:46:49 +05:00
using size_type = Size;
2022-10-27 22:27:50 +05:00
using pointer = Type*;
using reference = Type&;
using iterator = Iterator<Type>;
2022-12-06 23:52:49 +05:00
using const_reference = Type const&;
2022-10-27 22:27:50 +05:00
using const_iterator = Iterator<const Type>;
protected:
size_type p_rows;
size_type p_cols;
public:
inline
2023-01-11 14:46:49 +05:00
Matrix() :
2022-10-27 22:27:50 +05:00
base {},
p_rows {Rows},
p_cols {Cols}
{}
inline
2023-01-11 14:46:49 +05:00
Matrix(const Matrix& ms) :
2022-10-27 22:27:50 +05:00
base {static_cast<base>(ms)},
p_rows {Rows},
p_cols {Cols}
{}
inline
2023-01-11 14:46:49 +05:00
Matrix(Matrix&& ms) noexcept:
base {std::forward<base>(static_cast<base>(ms))},
2022-10-27 22:27:50 +05:00
p_rows {Rows},
p_cols {Cols}
{}
2022-12-06 23:52:49 +05:00
inline
2023-01-11 14:46:49 +05:00
Matrix& operator=(const Matrix& ms)
2022-12-06 23:52:49 +05:00
{
base::operator=(ms);
return *this;
}
2023-01-11 14:46:49 +05:00
inline explicit
Matrix(const base& vs) :
base {vs},
p_rows {Rows},
p_cols {Cols}
{}
inline explicit
Matrix(base&& vs) noexcept:
base {std::forward<base>(vs)},
p_rows {Rows},
p_cols {Cols}
{}
2022-10-27 22:27:50 +05:00
inline
2023-01-11 14:46:49 +05:00
Matrix(typename base::iterator start, typename base::iterator end) :
2022-10-27 22:27:50 +05:00
base {start, end},
p_rows {Rows},
p_cols {Cols}
{}
inline
2023-01-11 14:46:49 +05:00
Matrix(typename base::const_iterator start, typename base::const_iterator end) :
2022-10-27 22:27:50 +05:00
base {start, end},
p_rows {Rows},
p_cols {Cols}
{}
inline
2023-01-11 14:46:49 +05:00
Matrix(std::initializer_list<value_type> list) :
2022-10-27 22:27:50 +05:00
base {list},
p_rows {Rows},
p_cols {Cols}
{}
2023-01-11 14:46:49 +05:00
template <IsReal... Args>
2022-10-27 22:27:50 +05:00
inline
2023-01-11 14:46:49 +05:00
Matrix(value_type&& v, Args&& ...args) requires (1 + sizeof...(args) == Rows * Cols):
2022-10-27 22:27:50 +05:00
base {v, static_cast<value_type>(std::forward<Args>(args))...},
p_rows {Rows},
p_cols {Cols}
2023-01-11 14:46:49 +05:00
{}
inline
Matrix(const value_type& v) :
base {},
p_rows {Rows},
p_cols {Cols}
2022-10-27 22:27:50 +05:00
{
2023-01-11 14:46:49 +05:00
for (Size n = 0; n < Rows * Cols; ++n)
(*this)[n] = v;
2022-10-27 22:27:50 +05:00
}
2023-01-11 14:46:49 +05:00
inline
Matrix& operator=(const value_type& v)
{
for (Size n = 0; n < Rows * Cols; ++n)
(*this)[n] = v;
return *this;
}
// access
2022-10-27 22:27:50 +05:00
inline
reference operator()(size_type row, size_type col)
{
if (row >= p_rows || std::numeric_limits<size_type>::max() - p_rows < row)
throw std::out_of_range("Row index is out of range");
if (col >= p_cols || std::numeric_limits<size_type>::max() - p_cols < col)
throw std::out_of_range("Column index is out of range");
return (*this)[col + p_rows * row];
}
2022-12-06 23:52:49 +05:00
inline
const_reference operator()(size_type row, size_type col) const
{
if (row >= p_rows || std::numeric_limits<size_type>::max() - p_rows < row)
throw std::out_of_range("Row index is out of range");
if (col >= p_cols || std::numeric_limits<size_type>::max() - p_cols < col)
throw std::out_of_range("Column index is out of range");
return (*this)[col + p_rows * row];
}
2023-01-11 14:46:49 +05:00
Vector<value_type, Cols> row(size_type row)
2022-10-27 22:27:50 +05:00
{
2023-01-11 14:46:49 +05:00
Vector<value_type, Cols> vs;
2022-10-27 22:27:50 +05:00
for (auto n = 0; n < Cols; ++n)
vs[n] = (*this)(row, n);
return vs;
}
2023-01-11 14:46:49 +05:00
Vector<value_type, Cols> row(size_type row) const
2022-12-06 23:52:49 +05:00
{
2023-01-11 14:46:49 +05:00
Vector<value_type, Cols> vs;
2022-12-06 23:52:49 +05:00
for (auto n = 0; n < Cols; ++n)
vs[n] = (*this)(row, n);
return vs;
}
2023-01-11 14:46:49 +05:00
void row(size_type row, const Vector<value_type, Cols>& vs)
2022-10-27 22:27:50 +05:00
{
for (auto n = 0; n < Cols; ++n)
(*this)(n, row) = vs[n];
}
2023-01-11 14:46:49 +05:00
Vector<value_type, Rows> col(size_type col)
2022-10-27 22:27:50 +05:00
{
2023-01-11 14:46:49 +05:00
Vector<value_type, Rows> vs;
2022-10-27 22:27:50 +05:00
for (auto n = 0; n < Rows; ++n)
vs[n] = (*this)(n, col);
return vs;
}
2023-01-11 14:46:49 +05:00
void col(size_type col, const Vector<value_type, Rows>& vs)
2022-10-27 22:27:50 +05:00
{
for (auto n = 0; n < Rows; ++n)
(*this)(n, col) = vs[n];
}
2023-01-11 14:46:49 +05:00
[[nodiscard]] constexpr size_type rows() const { return p_rows; }
[[nodiscard]] constexpr size_type cols() const { return p_cols; }
// member functions
2022-10-27 22:27:50 +05:00
[[nodiscard]]
2023-01-11 14:46:49 +05:00
constexpr
2022-10-27 22:27:50 +05:00
bool is_square() const
{
return p_rows == p_cols;
}
inline
2023-01-11 14:46:49 +05:00
Matrix& fill(value_type value)
2022-10-27 22:27:50 +05:00
{
2023-01-11 14:46:49 +05:00
for (auto n = 0; n < this->size(); ++n)
(*this)[n] = value;
return *this;
2022-10-27 22:27:50 +05:00
}
2023-01-11 14:46:49 +05:00
// Global functions
2022-10-27 22:27:50 +05:00
2023-01-11 14:46:49 +05:00
static inline
Matrix identity()
2022-10-27 22:27:50 +05:00
{
2023-01-11 14:46:49 +05:00
Matrix ms;
2022-10-27 22:27:50 +05:00
for (auto n = 0; n < Rows; ++n)
for (auto k = 0; k < Cols; ++k)
2023-01-11 14:46:49 +05:00
ms(n, k) = 1;
2022-10-27 22:27:50 +05:00
return ms;
}
2023-01-11 14:46:49 +05:00
};
2022-10-27 22:27:50 +05:00
2023-01-11 14:46:49 +05:00
// global operators
2022-10-27 22:27:50 +05:00
2023-01-11 14:46:49 +05:00
template <IsReal T, Size R, Size C> inline Matrix<T, R, C> operator+(const Matrix<T, R, C>& lhs) { Matrix<T, R, C> ms; for (Size n = 0; n < lhs.size(); ++n) ms[n] = lhs[n]; return ms; }
template <IsReal T, Size R, Size C> inline Matrix<T, R, C> operator-(const Matrix<T, R, C>& lhs) { Matrix<T, R, C> ms; for (Size n = 0; n < lhs.size(); ++n) ms[n] = -lhs[n]; return ms; }
2022-10-27 22:27:50 +05:00
2023-01-11 14:46:49 +05:00
template <IsReal T, Size R, Size C> inline Matrix<T, R, C>& operator+=(Matrix<T, R, C>& lhs, const Matrix<T, R, C>& rhs) { for (Size n = 0; n < lhs.size(); ++n) lhs[n] += rhs[n]; return lhs; }
template <IsReal T, Size R, Size C> inline Matrix<T, R, C>& operator-=(Matrix<T, R, C>& lhs, const Matrix<T, R, C>& rhs) { for (Size n = 0; n < lhs.size(); ++n) lhs[n] -= rhs[n]; return lhs; }
template <IsReal T, Size R, Size C, Size R2, Size C2> requires (R == C2 && R2 == C) inline Matrix<T, R, C>& operator*=(Matrix<T, R, C>& lhs, const Matrix<T, R, C>& rhs) { Matrix<T, R, C> 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; }
2022-10-27 22:27:50 +05:00
2023-01-11 14:46:49 +05:00
template <IsReal T, Size R, Size C> inline Matrix<T, R, C> operator+(const Matrix<T, R, C>& lhs, const Matrix<T, R, C>& rhs) { Matrix<T, R, C> ms {lhs}; for (Size n = 0; n < lhs.size(); ++n) ms[n] += rhs[n]; return ms; }
template <IsReal T, Size R, Size C> inline Matrix<T, R, C> operator-(const Matrix<T, R, C>& lhs, const Matrix<T, R, C>& rhs) { Matrix<T, R, C> ms {lhs}; for (Size n = 0; n < lhs.size(); ++n) ms[n] -= rhs[n]; return ms; }
template <IsReal T, Size R, Size C, Size R2, Size C2> requires (R == C2 && R2 == C) inline Matrix<T, R, C> operator*(const Matrix<T, R, C>& lhs, const Matrix<T, R, C>& rhs) { Matrix<T, R, C> 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; }
2022-10-27 22:27:50 +05:00
2023-01-11 14:46:49 +05:00
template <IsReal T, Size R, Size C> inline bool operator==(const Matrix<T, R, C>& lhs, const Matrix<T, R, C>& rhs) { for (Size n = 0; n < lhs.size(); ++n) if (lhs[n] != rhs[n]) return false; return true; }
template <IsReal T, Size R, Size C> inline bool operator!=(const Matrix<T, R, C>& lhs, const Matrix<T, R, C>& rhs) { for (Size n = 0; n < lhs.size(); ++n) if (lhs[n] == rhs[n]) return false; return true; }
2022-10-27 22:27:50 +05:00
2023-01-11 14:46:49 +05:00
template <IsReal T, Size R, Size C> inline Matrix<T, R, C>& operator+=(Matrix<T, R, C>& lhs, const T& rhs) { for (Size n = 0; n < lhs.size(); ++n) lhs[n] += rhs; return lhs; }
template <IsReal T, Size R, Size C> inline Matrix<T, R, C>& operator-=(Matrix<T, R, C>& lhs, const T& rhs) { for (Size n = 0; n < lhs.size(); ++n) lhs[n] -= rhs; return lhs; }
template <IsReal T, Size R, Size C> inline Matrix<T, R, C>& operator*=(Matrix<T, R, C>& lhs, const T& rhs) { for (Size n = 0; n < lhs.size(); ++n) lhs[n] *= rhs; return lhs; }
template <IsReal T, Size R, Size C> inline Matrix<T, R, C>& operator/=(Matrix<T, R, C>& lhs, const T& rhs) { for (Size n = 0; n < lhs.size(); ++n) lhs[n] /= rhs; return lhs; }
2022-12-06 23:52:49 +05:00
2023-01-11 14:46:49 +05:00
template <IsReal T, Size R, Size C> inline Matrix<T, R, C> operator+(const Matrix<T, R, C>& lhs, const T& rhs) { Matrix<T, R, C> ms {lhs}; for (Size n = 0; n < lhs.size(); ++n) ms[n] += rhs; return ms; }
template <IsReal T, Size R, Size C> inline Matrix<T, R, C> operator-(const Matrix<T, R, C>& lhs, const T& rhs) { Matrix<T, R, C> ms {lhs}; for (Size n = 0; n < lhs.size(); ++n) ms[n] -= rhs; return ms; }
template <IsReal T, Size R, Size C> inline Matrix<T, R, C> operator*(const Matrix<T, R, C>& lhs, const T& rhs) { Matrix<T, R, C> ms {lhs}; for (Size n = 0; n < lhs.size(); ++n) ms[n] *= rhs; return ms; }
template <IsReal T, Size R, Size C> inline Matrix<T, R, C> operator/(const Matrix<T, R, C>& lhs, const T& rhs) { Matrix<T, R, C> ms {lhs}; for (Size n = 0; n < lhs.size(); ++n) ms[n] /= rhs; return ms; }
2022-12-06 23:52:49 +05:00
2022-10-27 22:27:50 +05:00
2023-01-11 14:46:49 +05:00
template <IsReal T, Size R, Size C> inline Vector<T, R> operator*(const Matrix<T, R, C>& ms, const Vector<T, R>& vs) { Vector<T, R> res; for (Size n = 0; n < R; ++n) res[0] = sum(ms.row(n) * vs); return res; }
template <IsReal T, Size R, Size C> inline Vector<T, C> operator*(const Vector<T, R>& vs, const Matrix<T, R, C>& ms) { Vector<T, C> res; for (Size n = 0; n < C; ++n) res[0] = sum(ms.col(n) * vs); return res; }
2022-10-27 22:27:50 +05:00
2023-01-11 14:46:49 +05:00
template <IsReal T, Size R, Size C> inline bool operator==(const Matrix<T, R, C>& lhs, const Vector<T, R * C>& rhs) { return false; }
template <IsReal T, Size R, Size C> inline bool operator!=(const Matrix<T, R, C>& lhs, const Vector<T, R * C>& rhs) { return true; }
// matrix operations
//! Transpose matrix
template <IsReal T, Size R, Size C>
inline
Matrix<T, R, C> transpose(const Matrix<T, R, C>& ms)
{
Matrix<T, R, C> 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 <IsReal T, Size R, Size C>
inline
T trace(const Matrix<T, R, C>& ms) requires (R == C)
{
T res;
for (auto n = 0; n < R; ++n)
res += ms(n, n);
return res;
}
//! Minor of a matrix
template <IsReal T, Size R, Size C>
inline
SubMatrix<T, R, C> minor(const Matrix<T, R, C>& ms, Size row, Size col)
{
if (ms.size() < 4)
throw std::runtime_error("Matrix should be greater 2x2");
SubMatrix<T, R, C> 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 <IsReal T, Size R, Size C>
inline
scalar det(const Matrix<T, R, C>& 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;
2022-10-27 22:27:50 +05:00
}
2023-01-11 14:46:49 +05:00
}
//! Adjoint matrix
template <IsReal T, Size R, Size C>
inline
Matrix<T, R, C> adj(const Matrix<T, R, C>& ms)
{
Matrix<T, R, C> 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 <IsReal T, Size R, Size C>
inline
Matrix<T, R, C> inv(const Matrix<T, R, C>& ms)
{
return adj(ms) / det(ms);
}
2022-10-27 22:27:50 +05:00
2022-12-06 23:52:49 +05:00
// Aliases
template <typename Type, size_t Row, size_t Col>
2023-01-11 14:46:49 +05:00
using mat = Matrix<Type, Row, Col>;
2022-12-06 23:52:49 +05:00
2023-01-11 14:46:49 +05:00
using mat2 = Matrix<scalar, 2, 2>;
using mat3 = Matrix<scalar, 3, 3>;
using mat4 = Matrix<scalar, 4, 4>;
2022-10-27 22:27:50 +05:00
}