consteig
Compile-time eigenvalue and eigenvector computation for C++17
Loading...
Searching...
No Matches
operations.hpp
1#ifndef OPERATIONS_HPP
2#define OPERATIONS_HPP
3
4#include "../math/constmath.hpp"
5#include "matrix.hpp"
6
7namespace consteig
8{
9
12
13// https://pages.mtu.edu/~struther/Courses/OLD/Other/Sp2012/5627/BlockQR/Work/MA5629%20presentation.pdf
14
23template <typename T, Size R, Size C>
24constexpr Matrix<T, R, C> operator+(const Matrix<T, R, C> &lhs,
25 const Matrix<T, R, C> &rhs)
26{
28
29 for (Size row{0}; row < R; ++row)
30 {
31 for (Size col{0}; col < C; ++col)
32 {
33 result(row, col) = lhs(row, col) + rhs(row, col);
34 }
35 }
36
37 return result;
38}
39
48template <typename T, Size R, Size C>
49constexpr Matrix<T, R, C> operator-(const Matrix<T, R, C> &lhs,
50 const Matrix<T, R, C> &rhs)
51{
53
54 for (Size row{0}; row < R; ++row)
55 {
56 for (Size col{0}; col < C; ++col)
57 {
58 result(row, col) = lhs(row, col) - rhs(row, col);
59 }
60 }
61
62 return result;
63}
64
76// Multiply two matrices
77template <typename T, Size R1, Size C1, Size R2, Size C2>
78constexpr Matrix<T, R1, C2> operator*(const Matrix<T, R1, C1> &lhs,
80{
81 static_assert(C1 == R2, "Number of columns must equal number of rows");
83
84 for (Size row{0}; row < R1; row++)
85 {
86 for (Size col{0}; col < C2; col++)
87 {
88 for (Size inner{0}; inner < C1; inner++)
89 {
90 result(row, col) += lhs(row, inner) * rhs(inner, col);
91 }
92 }
93 }
94
95 return result;
96}
97
106// Multiply by a scalar
107// todo(mthompkins): Figure out how to not make it possible to pass the scalar
108// to either side
109template <typename T, Size R, Size C>
110constexpr Matrix<T, R, C> operator*(const T &lhs, const Matrix<T, R, C> &rhs)
111{
113
114 for (Size row{0}; row < R; row++)
115 {
116 for (Size col{0}; col < C; col++)
117 {
118 result(row, col) = lhs * rhs(row, col);
119 }
120 }
121
122 return result;
123}
124
135// Multiply a 1XN by a Nx1 matrix
136template <typename T, Size R, Size C>
137constexpr T dot(const Matrix<T, R, C> &lhs, const Matrix<T, R, C> &rhs)
138{
139 static_assert(R == 1, "Dot Product expects two 1xN matrices");
141 T result{product(0, 0)};
142
143 return result;
144}
145
153template <typename T, Size R, Size C>
155{
157
158 for (Size row{0}; row < R; row++)
159 {
160 for (Size col{0}; col < C; col++)
161 {
162 result(col, row) = mat(row, col);
163 }
164 }
165
166 return result;
167}
168
176template <typename T, Size S> constexpr Matrix<T, S, S> diagonal(const T val)
177{
179
180 for (Size row{0}, col{0}; row < S; row++, col++)
181 {
182 result(row, col) = val;
183 }
184
185 return result;
186}
187
197template <typename T, Size S> constexpr Matrix<T, S, S> eye()
198{
199 return diagonal<T, S>(static_cast<T>(1));
200}
201
209// Euclidean normal of a matrix
210template <typename T, Size R, Size C>
211constexpr T norm(const Matrix<T, R, C> &mat)
212{
213 T result{};
214
215 for (Size row{0}; row < R; row++)
216 {
217 for (Size col{0}; col < C; col++)
218 {
219 result += (mat(row, col) * mat(row, col));
220 }
221 }
222
223 return sqrt(result);
224}
225
233// 1-norm of a matrix (max column sum)
234template <typename T, Size R, Size C>
235constexpr T norm1(const Matrix<T, R, C> &mat)
236{
237 T max_sum{static_cast<T>(0)};
238 for (Size col{0}; col < C; ++col)
239 {
240 T col_sum{static_cast<T>(0)};
241 for (Size row{0}; row < R; ++row)
242 {
243 col_sum += abs(mat(row, col));
244 }
245 if (col_sum > max_sum)
246 {
248 }
249 }
250 return max_sum;
251}
252
260// Infinity-norm of a matrix (max row sum)
261template <typename T, Size R, Size C>
262constexpr T normInf(const Matrix<T, R, C> &mat)
263{
264 T max_sum{static_cast<T>(0)};
265 for (Size row{0}; row < R; ++row)
266 {
267 T row_sum{static_cast<T>(0)};
268 for (Size col{0}; col < C; ++col)
269 {
270 row_sum += abs(mat(row, col));
271 }
272 if (row_sum > max_sum)
273 {
275 }
276 }
277 return max_sum;
278}
279
290template <typename T, Size R, Size C>
292{
294
295 for (Size row{0}; row < R; row++)
296 {
297 for (Size col{0}; col < C; col++)
298 {
299 result(row, col) = sqrt(mat(row, col));
300 }
301 }
302
303 return result;
304}
305
318// Algorithm: Determinant (Laplace Expansion)
319// Currently implemented using Laplace expansion (cofactor expansion).
320// Note: This has factorial time complexity (O(n!)) and is only practical for
321// very small matrices.
322template <typename T, Size R, Size C>
324{
325 static_assert(R == C, "Can only find determinant of a square matrix");
326
327 if constexpr (R == 1)
328 {
329 return mat(0, 0);
330 }
331 else if constexpr (R == 2)
332 {
333 return (mat(0, 0) * mat(1, 1)) - (mat(0, 1) * mat(1, 0));
334 }
335 else
336 {
337 T result{static_cast<T>(0)};
338 for (Size col{0}; col < R; col++)
339 {
340 Matrix<T, R - 1, C - 1> submat{};
341 for (Size row{1}; row < R; row++)
342 {
343 Size subj{0U};
344 for (Size src_col{0}; src_col < R; src_col++)
345 {
346 if (src_col == col)
347 {
348 continue;
349 }
350 submat(row - 1, subj) = mat(row, src_col);
351 subj++;
352 }
353 }
354 T sign = (col % 2 == 0) ? static_cast<T>(1) : static_cast<T>(-1);
355 result += (sign * mat(0, col) * determinant(submat));
356 }
357 return result;
358 }
359}
360
369template <typename T, Size R, Size C>
370constexpr T trace(const Matrix<T, R, C> &mat)
371{
372 static_assert(R == C, "Trace expects a square matrix");
373
374 T result{static_cast<T>(0)};
375 for (Size diag{0}; diag < R; ++diag)
376 {
377 result += mat(diag, diag);
378 }
379 return result;
380}
381
393template <typename T, Size N>
395{
397 coeffs(0u, 0u) = static_cast<T>(1);
398
400
401 for (Size k = 1u; k <= N; ++k)
402 {
403 const Matrix<T, N, N> B = A * M;
404 const T ck = -trace(B) / static_cast<T>(k);
405 coeffs(k, 0u) = ck;
406 M = B + ck * eye<T, N>();
407 }
408
409 return coeffs;
410}
411
426template <typename T, Size R, Size C>
427constexpr bool equalWithinMat(const Matrix<T, R, C> &a,
428 const Matrix<T, R, C> &b, const T thresh)
429{
430 return a.equalWithin(b, thresh);
431}
432
434
435} // namespace consteig
436#endif
Fixed-size matrix with compile-time dimensions.
Definition matrix.hpp:56
constexpr T sqrt(const T x)
Constexpr square root.
Definition sqrt.hpp:67
constexpr T abs(const T x)
Absolute value of a real number.
Definition abs.hpp:17
constexpr T epsilon()
Machine epsilon for type T.
Definition utilities.hpp:82
constexpr Matrix< T, S, S > diagonal(const T val)
Create an S×S matrix with val on the main diagonal and zeros elsewhere.
Definition operations.hpp:176
constexpr T determinant(const Matrix< T, R, C > &mat)
Determinant via Laplace (cofactor) expansion.
Definition operations.hpp:323
constexpr Matrix< T, S, S > eye()
Create an S×S identity matrix.
Definition operations.hpp:197
constexpr T norm1(const Matrix< T, R, C > &mat)
1-norm (maximum absolute column sum).
Definition operations.hpp:235
constexpr T norm(const Matrix< T, R, C > &mat)
Frobenius (Euclidean) norm: sqrt(sum of squared elements).
Definition operations.hpp:211
constexpr bool equalWithinMat(const Matrix< T, R, C > &a, const Matrix< T, R, C > &b, const T thresh)
Element-wise approximate equality within an absolute tolerance.
Definition operations.hpp:427
constexpr Matrix< T, C, R > transpose(const Matrix< T, R, C > &mat)
Matrix transpose.
Definition operations.hpp:154
constexpr Matrix< T, N+1u, 1u > char_poly(const Matrix< T, N, N > &A)
Monic characteristic polynomial via the Faddeev-LeVerrier algorithm.
Definition operations.hpp:394
constexpr T dot(const Matrix< T, R, C > &lhs, const Matrix< T, R, C > &rhs)
Dot product of two 1×N row vectors.
Definition operations.hpp:137
constexpr T trace(const Matrix< T, R, C > &mat)
Trace: sum of diagonal elements.
Definition operations.hpp:370
constexpr T normInf(const Matrix< T, R, C > &mat)
Infinity-norm (maximum absolute row sum).
Definition operations.hpp:262