akreon-linalg
Fixed-size linear algebra and numerical methods in C++26.
Loading...
Searching...
No Matches
householder.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
8#include <algorithm>
9
14
15namespace linalg {
33template <typename T, std::size_t N>
34 requires(Field<T> && N > 0)
41 constexpr HouseholderVector(const Vector<T, N>& x) : beta(real_type_t<T>(0)) {
42 make_householder(x, std::integral_constant<std::size_t, N>{});
43 }
44
47
48private:
56 constexpr void make_householder(const Vector<T, N>& x, auto) {
57 // Scale x before computing its norm and reflector direction.
59 for (const auto& value : x) scale = std::max(scale, constexpr_abs(value));
60 v(0) = T(1);
61 if (scale == real_type_t<T>(0)) return;
62 for (std::size_t i = 0; i < N; ++i) v(i) = x(i) / scale;
63 const auto norm = L2<Vector<T, N>>()(v);
64 if constexpr (Complex<T>) {
65 // Choose the leading phase so x + phase*||x||*e_0 avoids cancellation.
66 // Normalize the phase at unit scale. The constexpr magnitude's
67 // absolute square-root tolerance otherwise distorts tiny leading
68 // entries and leaves a residual that packed QR silently discards.
69 const auto phase_scale =
70 std::max(constexpr_abs(v(0).real()), constexpr_abs(v(0).imag()));
71 const auto leading =
72 phase_scale == real_type_t<T>(0) ? T(1) : v(0) / phase_scale;
73 const auto phase = leading / constexpr_abs(leading);
74 v(0) += phase * norm;
75 // QR and Hessenberg packing reconstruct the leading entry as one.
76 v = (T(1) / v(0)) * v;
77 const auto vv = inner_product(v, v);
78 beta = real_type_t<T>(2) / vv.real();
79 } else {
80 const auto tail = get_elements<1, N>(v);
81 if (inner_product(tail, tail) == T(0)) {
82 beta = x(0) < T(0) ? T(2) : T(0);
83 v(0) = T(1);
84 return;
85 }
86 // Use the opposite-sign reflection and normalize its leading entry to
87 // one.
88 const auto leading = v(0) + (v(0) >= T(0) ? norm : -norm);
89 v = (T(1) / leading) * v;
90 v(0) = T(1);
91 beta = T(2) / inner_product(v, v);
92 }
93 }
94
101 constexpr void make_householder(const Vector<T, N>&,
102 std::integral_constant<std::size_t, 1>) {
103 beta = real_type_t<T>(0);
104 v(0) = T(1);
105 }
106};
107
108} // namespace linalg
Field classified by scalar_traits as complex.
constexpr auto inner_product(const Vec &lhs, const Vec &rhs)
Evaluate the canonical inner product for two field vectors.
typename scalar_traits_t< T >::real_type real_type_t
Associated real component type registered for T.
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.
Compact representation of a real or complex Householder reflector.
Vector< T, N > v
Reflector direction vector.
constexpr HouseholderVector(const Vector< T, N > &x)
Construct a compact Householder reflector for x.
real_type_t< T > beta
Real coefficient in I - beta * v * v^*.
forward declaration for L2 norm
Owning, fixed-size vector container.
Definition vector.hpp:36