tesseract++ 0.0.1
N-dimensional tensor library for embedded systems
Loading...
Searching...
No Matches
qr.h
Go to the documentation of this file.
1#ifndef FUSED_ALGORITHMS_QR_H
2#define FUSED_ALGORITHMS_QR_H
3
4#include "config.h"
7#include "math/math_utils.h" // math::sqrt, math::abs
8
51namespace matrix_algorithms
52{
53
54 // ========================================================================
55 // QR Result
56 // ========================================================================
57
68 template <typename T, my_size_t M, my_size_t N>
69 struct QRResult
70 {
73
82 {
83 FusedMatrix<T, M, M> result(T(0));
84 result.setIdentity();
85
86 for (my_size_t jj = N; jj-- > 0;)
87 {
88 T tj = tau(jj);
89
90 if (tj == T(0))
91 continue;
92
93 // Apply Hⱼ to result from the left: result = Hⱼ · result
94 // v = [0..0, 1, QR(jj+1,jj), ..., QR(M-1,jj)]
95 for (my_size_t k = 0; k < M; ++k)
96 {
97 // dot = vᵀ · result(:, k)
98 T dot = result(jj, k); // v(jj) = 1 (implicit)
99
100 for (my_size_t i = jj + 1; i < M; ++i)
101 {
102 dot += QR(i, jj) * result(i, k);
103 }
104
105 // result(:, k) -= τ · v · dot
106 result(jj, k) -= tj * dot;
107
108 for (my_size_t i = jj + 1; i < M; ++i)
109 {
110 result(i, k) -= tj * QR(i, jj) * dot;
111 }
112 }
113 }
114
115 return result;
116 }
117
124 {
125 FusedMatrix<T, M, N> result(T(0));
126
127 for (my_size_t i = 0; i < M; ++i)
128 {
129 for (my_size_t j = i; j < N; ++j)
130 {
131 result(i, j) = QR(i, j);
132 }
133 }
134
135 return result;
136 }
137
148 {
149 FusedVector<T, M> result = b;
150
151 for (my_size_t j = 0; j < N; ++j)
152 {
153 T tj = tau(j);
154
155 if (tj == T(0))
156 continue;
157
158 // dot = vᵀ · result
159 T dot = result(j); // v(j) = 1 (implicit)
160
161 for (my_size_t i = j + 1; i < M; ++i)
162 {
163 dot += QR(i, j) * result(i);
164 }
165
166 // result -= τ · v · dot
167 result(j) -= tj * dot;
168
169 for (my_size_t i = j + 1; i < M; ++i)
170 {
171 result(i) -= tj * QR(i, j) * dot;
172 }
173 }
174
175 return result;
176 }
177 };
178
179 // ========================================================================
180 // Householder QR Decomposition
181 // ========================================================================
182
206 template <typename T, my_size_t M, my_size_t N>
208 {
209 static_assert(is_floating_point_v<T>,
210 "qr_householder requires a floating-point scalar type");
211 static_assert(M >= N, "qr_householder requires M >= N");
212
213 QRResult<T, M, N> result;
214 result.QR = A;
215 result.tau = FusedVector<T, N>(T(0));
216
217 for (my_size_t j = 0; j < N; ++j)
218 {
219 // 1. Compute norm of sub-column QR(j:M-1, j)
220 T norm_sq = T(0);
221
222 for (my_size_t i = j; i < M; ++i)
223 {
224 norm_sq += result.QR(i, j) * result.QR(i, j);
225 }
226
227 T norm = math::sqrt(norm_sq);
228
229 if (norm <= T(PRECISION_TOLERANCE))
230 {
231 result.tau(j) = T(0);
232 continue;
233 }
234
235 // 2. Choose α = -sign(QR(j,j)) · norm
236 T alpha = (result.QR(j, j) >= T(0)) ? -norm : norm;
237
238 // 3. Form Householder vector v
239 // v(j) = QR(j,j) - α, v(i) = QR(i,j) for i > j
240 T v0 = result.QR(j, j) - alpha;
241
242 // 4. Compute τ and normalize v
243 // vᵀv = v0² + Σ QR(i,j)² for i > j
244 T vtv = v0 * v0;
245
246 for (my_size_t i = j + 1; i < M; ++i)
247 {
248 vtv += result.QR(i, j) * result.QR(i, j);
249 }
250
251 T tj = T(2) * v0 * v0 / vtv;
252 result.tau(j) = tj;
253
254 // Normalize: store v(i)/v(0) below diagonal
255 for (my_size_t i = j + 1; i < M; ++i)
256 {
257 result.QR(i, j) /= v0;
258 }
259
260 // 5. Apply reflection to remaining columns k = j+1..N-1
261 // col_k -= τ · v_norm · (v_normᵀ · col_k)
262 // v_norm(j) = 1, v_norm(i) = QR(i,j) for i > j
263 for (my_size_t k = j + 1; k < N; ++k)
264 {
265 T dot = result.QR(j, k); // v_norm(j) = 1
266
267 for (my_size_t i = j + 1; i < M; ++i)
268 {
269 dot += result.QR(i, j) * result.QR(i, k);
270 }
271
272 result.QR(j, k) -= tj * dot;
273
274 for (my_size_t i = j + 1; i < M; ++i)
275 {
276 result.QR(i, k) -= tj * result.QR(i, j) * dot;
277 }
278 }
279
280 // 6. Store R(j,j) = α
281 result.QR(j, j) = alpha;
282 }
283
284 return result;
285 }
286
287} // namespace matrix_algorithms
288
289#endif // FUSED_ALGORITHMS_QR_H
Definition fused_matrix.h:12
FusedMatrix & setIdentity(void)
Definition fused_matrix.h:234
Definition fused_vector.h:9
Global configuration for the tesseract tensor library.
#define my_size_t
Size/index type used throughout the library.
Definition config.h:126
#define PRECISION_TOLERANCE
Tolerance for floating-point comparisons (e.g. symmetry checks, Cholesky).
Definition config.h:117
constexpr T sqrt(T x) noexcept
Compute the square root of a floating-point value.
Definition math_utils.h:29
Definition cholesky.h:52
QRResult< T, M, N > qr_householder(const FusedMatrix< T, M, N > &A)
Compute the Householder QR decomposition of a rectangular matrix.
Definition qr.h:207
Result of Householder QR decomposition.
Definition qr.h:70
FusedVector< T, N > tau
Householder scaling factors.
Definition qr.h:72
FusedMatrix< T, M, M > Q() const
Extract the full orthogonal factor Q (M×M).
Definition qr.h:81
FusedVector< T, M > apply_Qt(const FusedVector< T, M > &b) const
Apply Qᵀ to a vector b without forming Q explicitly.
Definition qr.h:147
FusedMatrix< T, M, N > QR
Compact Householder + R storage.
Definition qr.h:71
FusedMatrix< T, M, N > R() const
Extract the upper-triangular factor R (M×N).
Definition qr.h:123