numerics
Loading...
Searching...
No Matches
small_matrix.hpp
Go to the documentation of this file.
1/// @file small_matrix.hpp
2/// @brief Constexpr fixed-size stack-allocated matrix and Givens rotation.
3///
4/// These types complement the heap-allocated Matrix / Vector for small inner
5/// kernels where heap traffic is undesirable:
6///
7/// SmallVec<N> -- constexpr dense vector backed by std::array<real,N>
8/// SmallMatrix<M,N> -- constexpr row-major matrix backed by std::array<real,M*N>
9/// GivensRotation -- constexpr (c,s) pair; apply() / apply_t() are branchless
10///
11/// Because these are literal types every operation can be evaluated at
12/// compile time (C++17: arithmetic only; C++20+: also sqrt/hypot via
13/// constexpr `<cmath>`). At runtime the compiler places them entirely in
14/// registers for small M, N.
15///
16/// Typical uses:
17/// - GMRES: Hessenberg column updates via GivensRotation::from + apply
18/// - Jacobi SVD / eig: 2x2 eigensystem kernel as SmallMatrix<2,2>
19/// - Register-tile accumulation: SmallMatrix<4,4> replaces 16 named doubles
20/// - Unit tests: known-answer matmuls computed at compile time
21#pragma once
22
23#include "core/types.hpp"
24#include <array>
25#include <cmath>
26#include <algorithm>
27
28namespace num {
29
30// SmallVec<N>
31
32/// @brief Constexpr fixed-size dense vector (stack-allocated).
33template<idx N>
34struct SmallVec {
35 std::array<real, N> data{};
36
37 constexpr real& operator[](idx i) noexcept { return data[i]; }
38 constexpr const real& operator[](idx i) const noexcept { return data[i]; }
39 static constexpr idx size() noexcept { return N; }
40
41 constexpr SmallVec& operator+=(const SmallVec& o) noexcept {
42 for (idx i = 0; i < N; ++i) data[i] += o.data[i];
43 return *this;
44 }
45 constexpr SmallVec& operator-=(const SmallVec& o) noexcept {
46 for (idx i = 0; i < N; ++i) data[i] -= o.data[i];
47 return *this;
48 }
49 constexpr SmallVec& operator*=(real s) noexcept {
50 for (idx i = 0; i < N; ++i) data[i] *= s;
51 return *this;
52 }
53
54 constexpr real dot(const SmallVec& o) const noexcept {
55 real s = 0;
56 for (idx i = 0; i < N; ++i) s += data[i] * o.data[i];
57 return s;
58 }
59 /// @brief Sum of squares (avoid sqrt to stay constexpr in C++17).
60 constexpr real norm_sq() const noexcept { return dot(*this); }
61};
62
63template<idx N>
64constexpr SmallVec<N> operator+(SmallVec<N> a, const SmallVec<N>& b) noexcept {
65 return a += b;
66}
67template<idx N>
68constexpr SmallVec<N> operator*(real s, SmallVec<N> v) noexcept {
69 return v *= s;
70}
71
72// SmallMatrix<M, N>
73
74/// @brief Constexpr fixed-size row-major matrix (stack-allocated).
75template<idx M, idx N>
77 std::array<real, M * N> data{};
78
79 constexpr real& operator()(idx i, idx j) noexcept { return data[i * N + j]; }
80 constexpr const real& operator()(idx i, idx j) const noexcept { return data[i * N + j]; }
81
82 static constexpr idx rows() noexcept { return M; }
83 static constexpr idx cols() noexcept { return N; }
84
85 constexpr void fill(real v) noexcept { data.fill(v); }
86
87 static constexpr SmallMatrix zeros() noexcept { return SmallMatrix{}; }
88
89 static constexpr SmallMatrix identity() noexcept {
90 static_assert(M == N, "identity() requires a square matrix");
91 SmallMatrix m{};
92 for (idx i = 0; i < M; ++i) m(i, i) = real(1);
93 return m;
94 }
95
98 for (idx i = 0; i < M; ++i)
99 for (idx j = 0; j < N; ++j)
100 t(j, i) = (*this)(i, j);
101 return t;
102 }
103
104 /// @brief Matrix multiplication: (M x N) * (N x K) -> (M x K).
105 template<idx K>
106 constexpr SmallMatrix<M, K> operator*(const SmallMatrix<N, K>& B) const noexcept {
108 for (idx i = 0; i < M; ++i)
109 for (idx k = 0; k < N; ++k)
110 for (idx j = 0; j < K; ++j)
111 C(i, j) += (*this)(i, k) * B(k, j);
112 return C;
113 }
114
115 /// @brief Matrix-vector product: (MxN) * (N) -> (M).
116 constexpr SmallVec<M> operator*(const SmallVec<N>& x) const noexcept {
117 SmallVec<M> y{};
118 for (idx i = 0; i < M; ++i)
119 for (idx j = 0; j < N; ++j)
120 y[i] += (*this)(i, j) * x[j];
121 return y;
122 }
123
124 constexpr SmallMatrix& operator+=(const SmallMatrix& o) noexcept {
125 for (idx k = 0; k < M * N; ++k) data[k] += o.data[k];
126 return *this;
127 }
128 constexpr SmallMatrix& operator*=(real s) noexcept {
129 for (idx k = 0; k < M * N; ++k) data[k] *= s;
130 return *this;
131 }
132};
133
134// GivensRotation
135
136/// @brief Givens plane rotation: G = [c, s; -s, c].
137///
138/// Constructed so that G * [a; b]^T = [r; 0] with r = hypot(a, b).
139///
140/// @code
141/// auto g = GivensRotation::from(h_jj, h_jj1); // zero H[j,j+1] in GMRES
142/// g.apply(g_j, g_j1); // rotate RHS vector too
143/// @endcode
146
147 /// Compute (c,s) such that G*[a;b] = [r;0], r = hypot(a,b).
148 /// Stable for any (a,b) including b==0.
149 static constexpr GivensRotation from(real a, real b) noexcept {
150 if (b == real(0)) return {real(1), real(0)};
151 // Use the standard stable form. std::hypot is constexpr in GCC/Clang
152 // as a built-in extension even in C++17; becomes standard in C++23.
153 real r = std::sqrt(a * a + b * b);
154 return {a / r, b / r};
155 }
156
157 /// Apply G from the left: [x; y] <- G * [x; y].
158 constexpr void apply(real& x, real& y) const noexcept {
159 real tmp = c * x + s * y;
160 y = -s * x + c * y;
161 x = tmp;
162 }
163
164 /// Apply G^T (inverse rotation): [x; y] <- G^T * [x; y].
165 constexpr void apply_t(real& x, real& y) const noexcept {
166 real tmp = c * x - s * y;
167 y = s * x + c * y;
168 x = tmp;
169 }
170
171 /// Return the 2x2 rotation matrix.
173 return SmallMatrix<2, 2>{{ c, s, -s, c }};
174 }
175};
176
177} // namespace num
Core type definitions.
double real
Definition types.hpp:10
constexpr SmallVec< N > operator*(real s, SmallVec< N > v) noexcept
constexpr SmallVec< N > operator+(SmallVec< N > a, const SmallVec< N > &b) noexcept
constexpr T ipow(T x) noexcept
Compute x^N at compile time via repeated squaring.
std::size_t idx
Definition types.hpp:11
Givens plane rotation: G = [c, s; -s, c].
constexpr void apply(real &x, real &y) const noexcept
Apply G from the left: [x; y] <- G * [x; y].
constexpr void apply_t(real &x, real &y) const noexcept
Apply G^T (inverse rotation): [x; y] <- G^T * [x; y].
constexpr SmallMatrix< 2, 2 > as_matrix() const noexcept
Return the 2x2 rotation matrix.
static constexpr GivensRotation from(real a, real b) noexcept
Constexpr fixed-size row-major matrix (stack-allocated).
static constexpr SmallMatrix identity() noexcept
static constexpr idx cols() noexcept
constexpr SmallMatrix & operator+=(const SmallMatrix &o) noexcept
constexpr SmallMatrix< N, M > transposed() const noexcept
static constexpr SmallMatrix zeros() noexcept
constexpr real & operator()(idx i, idx j) noexcept
constexpr SmallVec< M > operator*(const SmallVec< N > &x) const noexcept
Matrix-vector product: (MxN) * (N) -> (M).
constexpr void fill(real v) noexcept
static constexpr idx rows() noexcept
constexpr SmallMatrix & operator*=(real s) noexcept
std::array< real, M *N > data
constexpr const real & operator()(idx i, idx j) const noexcept
constexpr SmallMatrix< M, K > operator*(const SmallMatrix< N, K > &B) const noexcept
Matrix multiplication: (M x N) * (N x K) -> (M x K).
Constexpr fixed-size dense vector (stack-allocated).
static constexpr idx size() noexcept
constexpr real norm_sq() const noexcept
Sum of squares (avoid sqrt to stay constexpr in C++17).
constexpr SmallVec & operator+=(const SmallVec &o) noexcept
constexpr real dot(const SmallVec &o) const noexcept
constexpr SmallVec & operator-=(const SmallVec &o) noexcept
constexpr const real & operator[](idx i) const noexcept
constexpr real & operator[](idx i) noexcept
std::array< real, N > data
constexpr SmallVec & operator*=(real s) noexcept