26template <SquareMatrix Mat>
33 using Complex = std::conditional_t<linalg::Complex<T>,
T, std::complex<Real>>;
36 static_assert(
N > 0,
"Eigen decomposition requires a nonempty matrix");
45 .tol =
Real(8) * std::numeric_limits<Real>::epsilon(),
46 .floor_eps = std::numeric_limits<Real>::min()};
78 for (std::size_t
i = 0;
i <
N; ++
i) {
102 Real(4) * std::numeric_limits<Real>::epsilon() *
111 constexpr void solve_qr(
const Mat&
A) {
115 for (std::size_t
r = 0;
r <
N; ++
r)
116 for (std::size_t c = 0; c <
N; ++c)
120 for (std::size_t
r = 0;
r <
N; ++
r)
121 for (std::size_t c = 0; c <
N; ++c)
126 for (std::size_t
r = 0;
r <
N; ++
r)
130 if constexpr (
N > 2) {
143 Vector<Complex, N>
eigs;
148 for (std::size_t
r = 1;
r <
N; ++
r)
151 for (std::size_t
r = 1;
r <
N; ++
r) {
152 if (H(
r,
r - 1) ==
T(0))
continue;
159 (
r > 1 && H(
r - 1,
r - 2) !=
T(0)) ||
160 (
r + 1 <
N && H(
r + 1,
r) !=
T(0)))
172 while (end > 1 && H(end - 1, end - 2) ==
T(0)) --end;
174 while (!
hermitian && end > 2 && H(end - 2, end - 3) ==
T(0)) {
175 const Real d = (H(end - 2, end - 2) - H(end - 1, end - 1)) / 2;
176 if (
d *
d + H(end - 2, end - 1) * H(end - 1, end - 2) >= 0)
break;
178 while (end > 1 && H(end - 1, end - 2) ==
T(0)) --end;
182 T shift = H(end - 1, end - 1);
185 const Real a = H(end - 2, end - 2),
d = H(end - 1, end - 1);
188 delta *
delta + H(end - 2, end - 1) * H(end - 1, end - 2);
198 (H(end - 2, end - 2) + H(end - 1, end - 1)) /
Real(2);
200 (H(end - 2, end - 2) - H(end - 1, end - 1)) /
Real(2);
202 delta *
delta + H(end - 2, end - 1) * H(end - 1, end - 2);
222 const T a = H(end - 2, end - 2),
d = H(end - 1, end - 1);
223 const T b = H(end - 2, end - 1), c = H(end - 1, end - 2);
236 const auto Q =
qr.Q();
240 for (std::size_t
j = 0;
j <
N; ++
j) H(
j,
j) +=
shift;
243 for (std::size_t
r = 2;
r <
N; ++
r)
244 for (std::size_t c = 0; c + 1 <
r; ++c) H(
r, c) =
T(0);
251 for (std::size_t
j = 0;
j <
N; ++
j) {
254 if (
j + 1 <
N && H(
j + 1,
j) !=
T(0)) {
272 for (std::size_t
r = 0;
r <
N; ++
r)
273 for (std::size_t c = 0; c <
N; ++c)
276 for (std::size_t
j = 0;
j <
N; ++
j) {
278 for (std::size_t
k =
j + 1;
k <
N; ++
k)
289 std::array<bool, N>
used{
false};
293 std::array<int, N>
idx;
295 for (
int j = 0;
j <
int(
N); ++
j)
301 for (
int j = 0;
j <
int(
N); ++
j) {
311 for (
int i =
static_cast<int>(
N) - 1;
i >= 0; --
i) {
312 if (
used[
i])
continue;
316 std::for_each(
eigs.begin(),
eigs.end(), [&](
const auto&
val) {
317 AM += constexpr_abs(eigs(i) - val) < config.tol;
327 Vector<Complex, N> x;
332 seed_complex_block(H,
i, x);
333 back_sub_1x1_block(H,
i, x);
336 auto v = map_to_A(U, x);
337 for (std::size_t
j = 0;
j <
N; ++
j)
V(
j,
i) = v(
j);
342 for (std::size_t
j = 0;
j <
N; ++
j)
V(
j,
i) = v(
j);
349 seed_real_block(
i, x);
350 back_sub_1x1_block(H,
i, x);
353 auto v = map_to_A(U, x);
354 for (std::size_t
j = 0;
j <
N; ++
j)
V(
j,
i) = v(
j);
368 seed_complex_block(H,
i,
chain(0));
369 back_sub_1x1_block(H,
i,
chain(0));
382 auto v = map_to_A(U,
chain(
k));
408 seed_real_block(
i,
chain(0));
409 back_sub_1x1_block(H,
i,
chain(0));
422 auto v = map_to_A(U,
chain(
k));
443 constexpr void back_sub_1x1_block(
const Mat& H,
int idx,
444 Vector<Complex, N>& x) {
453 if (
r > 0 && H(
r,
r - 1) !=
T(0)) {
456 for (
int c =
r + 1; c <=
idx; ++c)
484 constexpr void back_sub_shifted_rhs(
const Mat& H,
const Complex&
eig,
485 const Vector<Complex, N>&
rhs,
486 Vector<Complex, N>& x) {
488 for (
int r =
int(
N) - 1;
r >= 0; --
r) {
490 for (
int c =
r + 1; c <
int(
N); ++c)
sum += H(
r, c) * x(c);
504 constexpr void seed_complex_block(
const Mat& H,
int idx,
505 Vector<Complex, N>& x) {
506 const auto&
a = H(
idx - 1,
idx - 1);
507 const auto&
b = H(
idx - 1,
idx);
508 const auto& c = H(
idx,
idx - 1);
540 constexpr void seed_real_block(
int idx, Vector<Complex, N>& x) {
553 constexpr auto map_to_A(
const Mat& U,
const Vector<Complex, N>& x) {
554 Vector<Complex, N> v;
556 for (std::size_t
j = 0;
j <
N; ++
j) {
563 const auto norm = std::max(L2<Vector<Complex, N>>()(v),
config.floor_eps);
564 return T(1) /
norm * v;
Field classified by scalar_traits as complex.
Field classified by scalar_traits as real.
typename scalar_traits_t< T >::real_type real_type_t
Associated real component type registered for T.
constexpr auto as_complex_matrix(const Mat &A)
express matrix as complex one
constexpr auto conjugate_transpose(const Mat &A)
conjugate transpose of a matrix
constexpr auto transpose(const Vec &x)
tranpose of a vector
constexpr T constexpr_abs(T x)
Compute real absolute value or complex magnitude.
constexpr T constexpr_sqrt_safe(T x, T floor=T(0), T g=1e-10, T tol=1e-10)
Return a scalar square root with a sanitized fallback radicand.
constexpr bool is_same(const T &a, const T &b, real_type_t< T > tol=1e-10)
Compare complex scalars by magnitude of their difference.
constexpr std::size_t mat_rows_v
Registered compile-time row count after cv/ref normalization.
constexpr auto max(const Vec &x)
max element
constexpr auto conjugate(const Vec &x)
conjugate a vector
constexpr bool all_equal(const Vec &X, const Vec &Y, real_type_t< vector_element_t< Vec > > tol=1e-10)
checks if two vectors are equivalent to a given tolerance (different than == operator on vector which...
constexpr auto trace(const Mat &A)
trace of a matrix
typename mat_traits< remove_cvref_t< Mat > >::value_type matrix_scalar_t
Registered matrix scalar type after cv/ref normalization.
Configuration for generic numerical factorizations.
std::size_t steps
total number of iter
Computes eigenvalues and eigenvectors satisfying A V = V diag(lambda).
Matrix< Complex, N, N > V
eigenvectors
static constexpr config::FactorConfig< Real > default_config()
Construct the nominal shifted-QR configuration.
bool converged
eigenvalue convergence flag
Vector< Complex, N > lambda
eigendecomposition member variables
constexpr EigenDecomposition(const Mat &A, const config::FactorConfig< Real > &config_in)
Compute eigenvalues and eigenvectors with explicit settings.
constexpr auto spectral_radius() const
Select the eigenvalue whose magnitude is the spectral radius.
static constexpr std::size_t N
constexpr EigenDecomposition(const Mat &A)
Compute eigenvalues and eigenvectors using the nominal configuration.
std::conditional_t< linalg::Complex< T >, T, std::complex< Real > > Complex
Owning, fixed-size, row-major matrix container over a scalar field.
Owning, fixed-size vector container.