akreon-linalg
Fixed-size linear algebra and numerical methods in C++26.
Loading...
Searching...
No Matches
qr.hpp
Go to the documentation of this file.
1/*
2 * Copyright © 2025-2026 Akreon LLC
3 * SPDX-License-Identifier: Apache-2.0
4 */
5
6#pragma once
7
12
13namespace linalg {
23template <MatrixContainer Mat>
24struct QR {
25 // @brief alias for underlying type
28
29 // @brief get rows and cols from matrix type
30 static constexpr std::size_t Rows = mat_rows_v<Mat>;
31 static constexpr std::size_t Cols = mat_cols_v<Mat>;
32
33 static_assert(Rows >= Cols && Rows > 0,
34 "QR Factorization requires [square | overdetermined] system");
35
41 constexpr QR(const Mat& A) { solve_householder(A); }
42
49 constexpr QR(const Mat& A, const config::FactorConfig<ScalarT>& config_in)
50 : config(config_in) {
51 solve_householder(A);
52 }
53
59 constexpr auto Q() const { return get_unitary_matrix(); }
60
66 constexpr auto R() const { return get_upper_right_triangular_matrix(H); }
67
74 constexpr auto rank(ScalarT tol = 1e-6) const {
75 const auto LT = R();
76 const std::size_t mn = std::min(Rows, Cols);
77 std::size_t rank = 0;
78 for (std::size_t i = 0; i < mn; ++i)
79 if (L2<Vector<T, 1>>()(Vector<T, 1>{LT(i, i)}) > tol) rank += 1;
80 return rank;
81 }
82
91 constexpr auto solve(const Vector<T, Rows>& b) const {
93
94 const auto U = Q();
95 const auto LT = R();
96
97 if constexpr (Complex<T>) c = conjugate_transpose(U) * b;
98 else c = transpose(U) * b;
99
100 return back_solve(LT, c);
101 }
102
103private:
109 constexpr void solve_householder(Mat A) {
110 H = A;
111 constexpr_for<0, Cols>([&]<std::size_t j>(
112 std::integral_constant<std::size_t, j>) {
113 const auto& Q_jm = get_n_rows<j, Rows>(H);
114 const auto& Q_jm_j = get_col(Q_jm, j);
115
116 // Construct P_j to eliminate rows j+1,... in column j.
117 const auto& q = HouseholderVector(Q_jm_j);
118 beta(j) = q.beta;
119 const auto& v = as_col_vector(q.v);
120
121 // Apply P_j = I - beta*v*v^* to the trailing block from the left.
123 if constexpr (Complex<T>)
124 Q_jm_jn = Q_jm_jn - (beta(j) * v) * (conjugate_transpose(v) * Q_jm_jn);
125 else Q_jm_jn = Q_jm_jn - (beta(j) * v) * (transpose(v) * Q_jm_jn);
126
127 for (std::size_t k = j, a = 0; k < Rows; ++k, ++a)
128 for (std::size_t l = j, b = 0; l < Cols; ++l, ++b)
129 H(k, l) = Q_jm_jn(a, b);
130
131 // Store the reflector tail in the eliminated entries; v(0) is implicit.
132 for (std::size_t k = j + 1, a = 1; k < Rows; ++k, ++a) H(k, j) = v(a, 0);
133 });
134 }
135
141 constexpr auto get_unitary_matrix() const {
142 auto U = make_identity<T, Rows>();
143 constexpr_for<0, Cols>([&]<std::size_t jj>(
144 std::integral_constant<std::size_t, jj>) {
145 const std::size_t j = Cols - jj - 1;
146 Vector<T, Rows - j> v;
147 v(0) = T(1);
148 for (std::size_t i = j + 1, a = 1; i < Rows; ++i, ++a) v(a) = H(i, j);
149
150 const auto& v_col = as_col_vector(v);
151
153 if constexpr (Complex<T>)
154 Q_block = Q_block -
155 (beta(j) * v_col) * (conjugate_transpose(v_col) * Q_block);
156 else Q_block = Q_block - (beta(j) * v_col) * (transpose(v_col) * Q_block);
157
158 for (std::size_t r = j, a = 0; r < Rows; ++r, ++a)
159 for (std::size_t c = 0; c < Rows; ++c) U(r, c) = Q_block(a, c);
160 });
161 return U;
162 }
163
171 constexpr auto back_solve(const Matrix<T, Rows, Cols>& R,
172 const Vector<T, Rows>& rhs) const {
174 constexpr auto mn = std::min(Rows, Cols);
176 for (int i = static_cast<int>(mn) - 1; i >= 0; --i) {
177 T sum = 0;
178 for (std::size_t j = i + 1; j < Cols; ++j) sum += (R(i, j) * x(j));
179
180 AK_ASSERT(R(i, i) != T(0) &&
181 "QR back_solve requires non-zero diagonal in R");
182 // Floor a small pivot while preserving its sign or complex phase.
183 T d = R(i, i);
185 if (mag <= config.floor_eps) {
186 d = (mag > ScalarT(0)) ? d * config.floor_eps / mag
187 : T(config.floor_eps);
189 }
190 x(i) = (rhs(i) - sum) / d;
191 }
192 return std::tuple{x, event};
193 }
194
196 Mat H;
197 Vector<T, Rows> beta;
199};
200
201} // namespace linalg
#define AK_ASSERT(x)
Definition assert.hpp:13
Field classified by scalar_traits as complex.
typename scalar_traits_t< T >::real_type real_type_t
Associated real component type registered for T.
constexpr auto conjugate_transpose(const Mat &A)
conjugate transpose of a matrix
Vector(T, Ts...) -> Vector< std::common_type_t< T, Ts... >, 1+sizeof...(Ts)>
Deduce coordinate type and dimension from constructor arguments.
constexpr auto transpose(const Vec &x)
tranpose of a vector
constexpr T constexpr_abs(T x)
Compute real absolute value or complex magnitude.
constexpr std::size_t mat_rows_v
Registered compile-time row count after cv/ref normalization.
constexpr auto get_col(const Mat &A, std::size_t idx)
get the column of matrix A based on given index
NumericalEvent
NumericalEvent.
typename mat_traits< remove_cvref_t< Mat > >::value_type matrix_scalar_t
Registered matrix scalar type after cv/ref normalization.
constexpr auto as_col_vector(const Vec &X)
express the vector X as a column vector (N x 1)
constexpr auto get_upper_right_triangular_matrix(const Mat &A)
get upper right triangular matrix from A
Configuration for generic numerical factorizations.
Compact representation of a real or complex Householder reflector.
forward declaration for L2 norm
Factors A = Q R using Householder reflections.
Definition qr.hpp:24
constexpr auto R() const
Extract the upper-trapezoidal factor.
Definition qr.hpp:66
constexpr auto Q() const
Reconstruct the full orthogonal or unitary factor.
Definition qr.hpp:59
real_type_t< T > ScalarT
Definition qr.hpp:27
constexpr QR(const Mat &A, const config::FactorConfig< ScalarT > &config_in)
Factor A with an explicit solve configuration.
Definition qr.hpp:49
constexpr QR(const Mat &A)
Factor A using Householder reflections.
Definition qr.hpp:41
static constexpr std::size_t Rows
Definition qr.hpp:30
constexpr auto solve(const Vector< T, Rows > &b) const
Solve A x = b in the least-squares sense.
Definition qr.hpp:91
static constexpr std::size_t Cols
Definition qr.hpp:31
constexpr auto rank(ScalarT tol=1e-6) const
Estimate rank from the diagonal of R.
Definition qr.hpp:74
matrix_scalar_t< Mat > T
Definition qr.hpp:26
Owning, fixed-size vector container.
Definition vector.hpp:36