consteig
Compile-time eigenvalue and eigenvector computation for C++17
Loading...
Searching...
No Matches
qr.hpp
1#ifndef QR_DECOMP_HPP
2#define QR_DECOMP_HPP
3
4#include "../../math/constmath.hpp"
5#include "../matrix.hpp"
6#include "../operations.hpp"
7
8namespace consteig
9{
10
14
25template <typename T, Size S> struct QRMatrix
26{
27 Matrix<T, S, S> _q;
28 Matrix<T, S, S> _r;
29};
30
48// Algorithm: QR Decomposition (Hessenberg Optimized)
49// Factors an upper Hessenberg matrix A = QR using a sequence of Givens
50// rotations. Because A is Hessenberg, each column has at most one subdiagonal
51// nonzero, so each rotation only needs to update two adjacent rows of R and
52// two adjacent columns of Q.
53//
54// The rotation angle is chosen (Golub & Van Loan, sec. 5) so that the
55// subdiagonal entry r(i+1, i) is zeroed:
56// c = x / mag, s = y / mag, mag = sqrt(x^2 + y^2)
57// where x = r(i,i) and y = r(i+1,i).
58template <typename T, Size R, Size C>
59constexpr QRMatrix<T, R> qr_hessenberg(const Matrix<T, R, C> a)
60{
61 static_assert(R == C, "QR decomposition must be a square matrix");
62
65
66 for (Size col = 0; col < R - 1; ++col)
67 {
68 // Compute Givens rotation to zero r(col+1, col)
69 T x = r(col, col);
70 T y = r(col + 1, col);
71
72 if (abs(y) > static_cast<T>(1e-15))
73 {
74 T mag = sqrt(x * x + y * y);
75 T c = x / mag;
76 T s = y / mag;
77
78 // R = G * R
79 for (Size k = col; k < R; ++k)
80 {
81 T r_cur = r(col, k);
82 T r_next = r(col + 1, k);
83 r(col, k) = c * r_cur + s * r_next;
84 r(col + 1, k) = -s * r_cur + c * r_next;
85 }
86
87 // Q = Q * G^T
88 for (Size row = 0; row < R; ++row)
89 {
90 T q_cur = q(row, col);
91 T q_next = q(row, col + 1);
92 q(row, col) = c * q_cur + s * q_next;
93 q(row, col + 1) = -s * q_cur + c * q_next;
94 }
95 r(col + 1, col) = 0;
96 }
97 }
98
99 QRMatrix<T, R> res{};
100 res._q = q;
101 res._r = r;
102 return res;
103}
104
132// Algorithm: QR Decomposition (General)
133// Factors a square matrix A = QR using a sequence of Givens rotations, working
134// column by column from bottom to top to zero all subdiagonal entries. Givens
135// rotations are preferred over Gram-Schmidt here because they avoid the loss of
136// orthogonality that Gram-Schmidt can suffer from floating-point cancellation.
137//
138// Reference: Golub & Van Loan, "Matrix Computations" (4th ed.), sec. 5
139template <typename T, Size R, Size C>
140constexpr QRMatrix<T, R> qr(const Matrix<T, R, C> a)
141{
142 static_assert(R == C, "QR decomposition must be a square matrix");
143
146
147 for (Size col = 0; col < C; ++col)
148 {
149 for (Size row = R - 1; row > col; --row)
150 {
151 // Compute Givens rotation to zero r(row, col) using r(row-1, col)
152 T x = r(row - 1, col);
153 T y = r(row, col);
154
155 if (abs(y) > static_cast<T>(1e-15))
156 {
157 T mag = sqrt(x * x + y * y);
158 if (mag > static_cast<T>(1e-18))
159 {
160 T c = x / mag;
161 T s = y / mag;
162
163 // R = G * R
164 // Only need to update columns from col to C-1
165 for (Size k = col; k < C; ++k)
166 {
167 T r_above = r(row - 1, k);
168 T r_cur = r(row, k);
169 r(row - 1, k) = c * r_above + s * r_cur;
170 r(row, k) = -s * r_above + c * r_cur;
171 }
172
173 // Q = Q * G^T
174 for (Size k = 0; k < R; ++k)
175 {
176 T q_above = q(k, row - 1);
177 T q_cur = q(k, row);
178 q(k, row - 1) = c * q_above + s * q_cur;
179 q(k, row) = -s * q_above + c * q_cur;
180 }
181 r(row, col) = 0;
182 }
183 }
184 }
185 }
186
187 QRMatrix<T, R> res{};
188 res._q = q;
189 res._r = r;
190 return res;
191}
192
194
195} // namespace consteig
196#endif
Fixed-size matrix with compile-time dimensions.
Definition matrix.hpp:56
constexpr QRMatrix< T, R > qr_hessenberg(const Matrix< T, R, C > a)
QR decomposition optimized for upper Hessenberg matrices.
Definition qr.hpp:59
constexpr QRMatrix< T, R > qr(const Matrix< T, R, C > a)
General QR decomposition using Givens rotations.
Definition qr.hpp:140
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