Phyth v0.1.0
A dimensional safe C++ header-only mechanics and electromagnetics simulation library.
Loading...
Searching...
No Matches
Matrix.hpp
Go to the documentation of this file.
1#ifndef PHYTH_MATRIX_HPP
2#define PHYTH_MATRIX_HPP
3
5#include "Vector3.hpp"
6#include <array>
7#include <cstddef>
8#include <ostream>
9#include <stdexcept>
10#include <type_traits>
11#include <utility>
12
13namespace Phyth {
14 template<std::size_t Row, std::size_t Col, typename T>
15 struct Matrix {
16 static_assert(is_quantity_v<T>, "Matrix only supports Quantity types");
17 static_assert(Row > 0 && Col > 0, "Matrix dimensions must be positive");
18
19 std::array<Vector<Row, T>, Col> datas;
20
21 constexpr Matrix()
23
24 template<typename... Args,
25 std::enable_if_t<
26 sizeof...(Args) == Col &&
27 std::conjunction_v<std::is_convertible<Args, Vector<Row, T> >...>,
28 int> = 0>
29 constexpr Matrix(Args... basics) : datas{basics...} {}
30
31 template<typename... Args,
32 std::enable_if_t<
33 sizeof...(Args) == Row * Col &&
34 std::conjunction_v<std::is_convertible<Args, T>...>,
35 int> = 0>
36 constexpr Matrix(Args... elems)
37 : Matrix(std::array<T, Row * Col>{static_cast<T>(elems)...},
38 std::make_index_sequence<Col>{}) {}
39
40 static constexpr Matrix Identity() {
41 static_assert(Row == Col, "Identity matrix requires a square matrix");
42 return IdentityImpl(std::make_index_sequence<Col>{});
43 }
44
45 [[nodiscard]] constexpr auto Transpose() const {
46 return TransposeImpl(std::make_index_sequence<Row>{},
47 std::make_index_sequence<Col>{});
48 }
49
50 [[nodiscard]] constexpr T Trace() const {
51 static_assert(Row == Col, "Trace requires a square matrix");
52 return TraceImpl(std::make_index_sequence<Row>{});
53 }
54
55 [[nodiscard]] constexpr auto Symmetric() const {
56 return (*this + this->Transpose()) * T(0.5);
57 }
58
59 [[nodiscard]] constexpr auto Antisymmetric() const {
60 return (*this - this->Transpose()) * T(0.5);
61 }
62
63 [[nodiscard]] const T &At(const std::size_t i, const std::size_t j) const {
64 if (i >= Row || j >= Col) {
65 throw std::out_of_range("Matrix::At: index out of range");
66 }
67 return datas[j][i];
68 }
69
70 T &At(const std::size_t i, const std::size_t j) {
71 if (i >= Row || j >= Col) {
72 throw std::out_of_range("Matrix::At: index out of range");
73 }
74 return datas[j][i];
75 }
76
77 [[nodiscard]] constexpr const T &operator()(const std::size_t i, const std::size_t j) const {
78 return datas[j][i];
79 }
80
81 constexpr T &operator()(const std::size_t i, const std::size_t j) {
82 return datas[j][i];
83 }
84
85 template<typename U>
86 constexpr auto operator+(const Matrix<Row, Col, U> &other) const {
87 return AddImpl(other, std::make_index_sequence<Col>{});
88 }
89
90 template<typename U>
91 constexpr auto operator-(const Matrix<Row, Col, U> &other) const {
92 return SubImpl(other, std::make_index_sequence<Col>{});
93 }
94
95 constexpr auto operator-() const {
96 return NegImpl(std::make_index_sequence<Col>{});
97 }
98
99 template<typename U>
100 constexpr auto operator*(U scalar) const {
101 return ScaleImpl(scalar, std::make_index_sequence<Col>{});
102 }
103
104 template<typename U>
105 constexpr auto operator*(const Vector<Row, U> &v) const {
106 using ResultVec = decltype(datas[0] * v[0]);
107 ResultVec result = datas[0] * v[0];
108 for (std::size_t c = 1; c < Col; ++c) {
109 result = result + datas[c] * v[c];
110 }
111 return result;
112 }
113
114 template<typename U, std::size_t OtherCol>
115 constexpr auto operator*(const Matrix<Col, OtherCol, U> &other) const {
116 using ResultMat = Matrix<Row, OtherCol, decltype(*this * other.datas[0])>;
118 for (std::size_t c = 0; c < OtherCol; ++c) {
119 result.datas[c] = *this * other.datas[c];
120 }
121 return result;
122 }
123
124 template<typename U>
126 for (std::size_t c = 0; c < Col; ++c) {
127 datas[c] += other.datas[c];
128 }
129 return *this;
130 }
131
132 template<typename U>
134 for (std::size_t c = 0; c < Col; ++c) {
135 datas[c] -= other.datas[c];
136 }
137 return *this;
138 }
139
140 template<typename U>
141 constexpr Matrix &operator*=(U scalar) {
142 for (std::size_t c = 0; c < Col; ++c) {
143 datas[c] *= scalar;
144 }
145 return *this;
146 }
147
148 template<typename U>
149 constexpr bool operator==(const Matrix<Row, Col, U> &other) const {
150 for (std::size_t c = 0; c < Col; ++c) {
151 if (!(datas[c] == other.datas[c])) return false;
152 }
153 return true;
154 }
155
156 template<typename U>
157 constexpr bool operator!=(const Matrix<Row, Col, U> &other) const {
158 return !(*this == other);
159 }
160
161 template<typename UnitT>
163 return AsImpl<UnitT>(std::make_index_sequence<Col>{});
164 }
165
166 friend std::ostream &operator<<(std::ostream &os, const Matrix &m) {
167 os << "[";
168 for (std::size_t r = 0; r < Row; ++r) {
169 os << (r == 0 ? "" : "\n ");
170 for (std::size_t c = 0; c < Col; ++c) {
171 if (c != 0) os << " ";
172 os << m.datas[c][r];
173 }
174 }
175 os << "]";
176 return os;
177 }
178
179 private:
180 template<std::size_t... Cs>
181 static constexpr Matrix MakeZero(std::index_sequence<Cs...>) {
182 return Matrix((static_cast<void>(Cs), MakeZeroCol(std::make_index_sequence<Row>{}))...);
183 }
184
185 template<std::size_t... Rs>
186 static constexpr Vector<Row, T> MakeZeroCol(std::index_sequence<Rs...>) {
187 return Vector<Row, T>((static_cast<void>(Rs), T(0))...);
188 }
189
190 template<std::size_t... Cs>
191 static constexpr Matrix IdentityImpl(std::index_sequence<Cs...>) {
192 return Matrix(MakeIdentityCol<Cs>(std::make_index_sequence<Row>{})...);
193 }
194
195 template<std::size_t C, std::size_t... Rs>
196 static constexpr Vector<Row, T> MakeIdentityCol(std::index_sequence<Rs...>) {
197 return Vector<Row, T>((Rs == C ? T(1) : T(0))...);
198 }
199
200 template<std::size_t... Cs>
201 constexpr Matrix(const std::array<T, Row * Col> &flat,
202 std::index_sequence<Cs...>)
203 : datas{MakeCol<Cs>(flat, std::make_index_sequence<Row>{})...} {}
204
205 template<std::size_t C, std::size_t... Rs>
206 static constexpr Vector<Row, T>
207 MakeCol(const std::array<T, Row * Col> &flat, std::index_sequence<Rs...>) {
208 return Vector<Row, T>(flat[Rs * Col + C]...);
209 }
210
211 template<std::size_t... Rs, std::size_t... Cs>
212 constexpr auto TransposeImpl(std::index_sequence<Rs...>,
213 std::index_sequence<Cs...>) const {
214 return Matrix<Col, Row, T>(
215 MakeTransposeCol<Rs>(std::make_index_sequence<Col>{})...);
216 }
217
218 template<std::size_t R, std::size_t... Cs>
219 constexpr Vector<Col, T> MakeTransposeCol(std::index_sequence<Cs...>) const {
220 return Vector<Col, T>(datas[Cs][R]...);
221 }
222
223 template<std::size_t... Rs>
224 constexpr T TraceImpl(std::index_sequence<Rs...>) const {
225 return (datas[Rs][Rs] + ...);
226 }
227
228 template<typename U, std::size_t... Cs>
229 constexpr auto AddImpl(const Matrix<Row, Col, U> &other,
230 std::index_sequence<Cs...>) const {
231 return Matrix<Row, Col, decltype(datas[0] + other.datas[0])>(
232 (datas[Cs] + other.datas[Cs])...);
233 }
234
235 template<typename U, std::size_t... Cs>
236 constexpr auto SubImpl(const Matrix<Row, Col, U> &other,
237 std::index_sequence<Cs...>) const {
238 return Matrix<Row, Col, decltype(datas[0] - other.datas[0])>(
239 (datas[Cs] - other.datas[Cs])...);
240 }
241
242 template<std::size_t... Cs>
243 constexpr auto NegImpl(std::index_sequence<Cs...>) const {
244 return Matrix<Row, Col, decltype(-datas[0])>((-datas[Cs])...);
245 }
246
247 template<typename U, std::size_t... Cs>
248 constexpr auto ScaleImpl(U scalar, std::index_sequence<Cs...>) const {
250 (datas[Cs] * scalar)...);
251 }
252
253 template<typename UnitT, std::size_t... Cs>
255 AsImpl(std::index_sequence<Cs...>) const {
257 (datas[Cs].template As<UnitT>())...);
258 }
259 };
260
261 template<typename T, typename U, std::size_t Row, std::size_t Col>
262 constexpr auto operator*(T scalar, const Matrix<Row, Col, U> &m) {
263 return m * scalar;
264 }
265}
266
267#endif // PHYTH_MATRIX_HPP
constexpr auto operator*(Quantity< U1 > a, Quantity< U2 > b)
Multiply two quantities.
Definition Quantity.hpp:524
constexpr bool is_unit_v
Definition Unit.hpp:79
constexpr Matrix(const std::array< T, Row *Col > &flat, std::index_sequence< Cs... >)
Definition Matrix.hpp:201
constexpr auto operator*(U scalar) const
Definition Matrix.hpp:100
constexpr T TraceImpl(std::index_sequence< Rs... >) const
Definition Matrix.hpp:224
constexpr auto AddImpl(const Matrix< Row, Col, U > &other, std::index_sequence< Cs... >) const
Definition Matrix.hpp:229
constexpr auto operator-() const
Definition Matrix.hpp:95
constexpr auto Antisymmetric() const
Definition Matrix.hpp:59
T & At(const std::size_t i, const std::size_t j)
Definition Matrix.hpp:70
constexpr Vector< Col, T > MakeTransposeCol(std::index_sequence< Cs... >) const
Definition Matrix.hpp:219
constexpr auto SubImpl(const Matrix< Row, Col, U > &other, std::index_sequence< Cs... >) const
Definition Matrix.hpp:236
constexpr auto operator+(const Matrix< Row, Col, U > &other) const
Definition Matrix.hpp:86
constexpr auto TransposeImpl(std::index_sequence< Rs... >, std::index_sequence< Cs... >) const
Definition Matrix.hpp:212
std::array< Vector< Row, T >, Col > datas
Definition Matrix.hpp:19
constexpr Matrix(Args... elems)
Definition Matrix.hpp:36
constexpr Matrix(Args... basics)
Definition Matrix.hpp:29
static constexpr Matrix IdentityImpl(std::index_sequence< Cs... >)
Definition Matrix.hpp:191
constexpr Matrix< Row, Col, Quantity< UnitT > > AsImpl(std::index_sequence< Cs... >) const
Definition Matrix.hpp:255
static constexpr Vector< Row, T > MakeZeroCol(std::index_sequence< Rs... >)
Definition Matrix.hpp:186
static constexpr Vector< Row, T > MakeIdentityCol(std::index_sequence< Rs... >)
Definition Matrix.hpp:196
friend std::ostream & operator<<(std::ostream &os, const Matrix &m)
Definition Matrix.hpp:166
static constexpr Matrix MakeZero(std::index_sequence< Cs... >)
Definition Matrix.hpp:181
constexpr T & operator()(const std::size_t i, const std::size_t j)
Definition Matrix.hpp:81
constexpr const T & operator()(const std::size_t i, const std::size_t j) const
Definition Matrix.hpp:77
constexpr auto operator*(const Vector< Row, U > &v) const
Definition Matrix.hpp:105
constexpr auto Symmetric() const
Definition Matrix.hpp:55
static constexpr Matrix Identity()
Definition Matrix.hpp:40
constexpr auto ScaleImpl(U scalar, std::index_sequence< Cs... >) const
Definition Matrix.hpp:248
constexpr T Trace() const
Definition Matrix.hpp:50
constexpr auto operator-(const Matrix< Row, Col, U > &other) const
Definition Matrix.hpp:91
Matrix< Row, Col, Quantity< UnitT > > As() const
Definition Matrix.hpp:162
constexpr bool operator!=(const Matrix< Row, Col, U > &other) const
Definition Matrix.hpp:157
constexpr Matrix()
Definition Matrix.hpp:21
constexpr auto NegImpl(std::index_sequence< Cs... >) const
Definition Matrix.hpp:243
constexpr Matrix & operator-=(const Matrix< Row, Col, U > &other)
Definition Matrix.hpp:133
constexpr bool operator==(const Matrix< Row, Col, U > &other) const
Definition Matrix.hpp:149
static constexpr Vector< Row, T > MakeCol(const std::array< T, Row *Col > &flat, std::index_sequence< Rs... >)
Definition Matrix.hpp:207
constexpr auto Transpose() const
Definition Matrix.hpp:45
constexpr Matrix & operator+=(const Matrix< Row, Col, U > &other)
Definition Matrix.hpp:125
constexpr auto operator*(const Matrix< Col, OtherCol, U > &other) const
Definition Matrix.hpp:115
constexpr Matrix & operator*=(U scalar)
Definition Matrix.hpp:141
const T & At(const std::size_t i, const std::size_t j) const
Definition Matrix.hpp:63