17#ifndef NUMERICAL_EIGEN_HPP
18#define NUMERICAL_EIGEN_HPP
38 inline constexpr double schur_ulp {std::numeric_limits<double>::epsilon()};
61 return std::abs(x.real()) + std::abs(x.imag());
76 [[
nodiscard]]
inline std::complex<double>
times(
const std::complex<double>& a,
77 const std::complex<double>& b)
79 return {(a.real() * b.real()) - (a.imag() * b.imag()), (a.real() * b.imag()) + (a.imag() * b.real())};
91 return std::max(std::abs(x.real()), std::abs(x.imag()));
100 std::vector<std::pair<std::size_t, std::size_t>>
swaps;
105 template <
typename T>
111 for (std::size_t c {0}; c < n; ++c) {
112 std::swap(a[(i * n) + c], a[(j * n) + c]);
114 for (std::size_t r {0}; r < n; ++r) {
115 std::swap(a[(r * n) + i], a[(r * n) + j]);
125 template <
typename T>
134 for (std::size_t i {
out.high}; i-- >
out.low;) {
136 for (std::size_t j {
out.low}; j <
out.high &&
alone; ++j) {
137 alone = j == i || a[(i * n) + j] ==
T {};
141 out.swaps.emplace_back(i,
out.high - 1);
150 for (std::size_t j {
out.low}; j <
out.high; ++j) {
152 for (std::size_t i {
out.low}; i <
out.high &&
alone; ++i) {
153 alone = i == j || a[(i * n) + j] ==
T {};
157 out.swaps.emplace_back(j,
out.low);
167 for (std::size_t i {
out.low}; i <
out.high; ++i) {
168 for (std::size_t k {
out.low}; k <
out.high; ++k) {
191 for (std::size_t k {
out.low}; k < n; ++k) {
194 for (std::size_t k {0}; k <
out.high; ++k) {
214 template <
typename T>
221 std::vector<buffer<T>> reflectors(n);
222 for (std::size_t k {low}; k + 2 < high; ++k) {
224 for (std::size_t i {k + 1}; i < high; ++i) {
225 v[i - k - 1] = a[(i * n) + k];
227 if (
scaled_norm(v.data() + 1, v.size() - 1) == 0.0) {
238 for (std::size_t i {0}; i < v.size(); ++i) {
240 const T*
row {a.data() + ((k + 1 + i) * n) + k};
241 for (std::size_t c {0}; c <
w.size(); ++c) {
245 for (std::size_t i {0}; i < v.size(); ++i) {
246 const T twice {
static_cast<T>(2) * v[i]};
247 T*
row {a.data() + ((k + 1 + i) * n) + k};
248 for (std::size_t c {0}; c <
w.size(); ++c) {
252 for (std::size_t r {0}; r < high; ++r) {
253 T*
row {a.data() + (r * n) + k + 1};
255 for (std::size_t j {0}; j < v.size(); ++j) {
258 s *=
static_cast<T>(2);
259 for (std::size_t j {0}; j < v.size(); ++j) {
263 for (std::size_t i {k + 2}; i < high; ++i) {
264 a[(i * n) + k] =
T {};
266 reflectors[k] = std::move(v);
272 for (std::size_t i {0}; i < n; ++i) {
273 q[(i * n) + i] =
T {1};
275 for (std::size_t k {n}; k-- > 0;) {
281 for (std::size_t i {0}; i < v.size(); ++i) {
283 const T*
row {q.data() + ((k + 1 + i) * n) + k + 1};
284 for (std::size_t c {0}; c <
w.size(); ++c) {
288 for (std::size_t i {0}; i < v.size(); ++i) {
289 const T twice {
static_cast<T>(2) * v[i]};
290 T*
row {q.data() + ((k + 1 + i) * n) + k + 1};
291 for (std::size_t c {0}; c <
w.size(); ++c) {
297 for (std::size_t i {0}; i < n; ++i) {
298 for (std::size_t j {0}; j < n; ++j) {
299 qt[(j * n) + i] = q[(i * n) + j];
322 return rest == 0.0 &&
alpha.imag() == 0.0;
330 template <
typename T>
342 for (std::size_t i {0}; i < count; ++i) {
372 const auto*
const parts {
reinterpret_cast<const double*
>(
row)};
383 for (std::size_t
l {0};
l < count; ++
l) {
395 for (std::size_t
l {0};
l < count; ++
l) {
396 const std::complex<double> x {v[
l *
stride]};
398 out.real_side[(2 *
l) + 1] = -x.imag();
399 out.imaginary_side[2 *
l] = x.imag();
400 out.imaginary_side[(2 *
l) + 1] = x.real();
406 template <
typename T>
421 template <
typename T>
428 std::vector<hessenberg_panel<T>>
panels;
429 for (std::size_t k {low}; k + 2 < high;) {
431 const std::size_t m {high - k - 1};
437 for (std::size_t i {0}; i < b; ++i) {
438 const std::size_t j {k + i};
439 for (std::size_t r {0}; r < m; ++r) {
440 column[r] = a[((k + 1 + r) * n) + j];
443 for (std::size_t r {0}; r < m; ++r) {
445 for (std::size_t p {0}; p < i; ++p) {
450 for (std::size_t p {0}; p < i; ++p) {
452 for (std::size_t r {p}; r < m; ++r) {
457 for (std::size_t p {i}; p-- > 0;) {
459 for (std::size_t q {0}; q <= p; ++q) {
464 for (std::size_t r {0}; r < m; ++r) {
466 for (std::size_t p {0}; p < std::min(i, r + 1); ++p) {
474 v[(i * b) + i] =
T {1};
475 for (std::size_t r {i + 1}; r < m; ++r) {
476 v[(r * b) + i] =
column[r];
478 for (std::size_t r {0}; r < m; ++r) {
479 a[((k + 1 + r) * n) + j] = r < i ?
column[r] : (r == i ?
alpha :
T {});
484 y[((k + 1 + r) * b) + i] =
against_v.dot(a.data() + ((k + 1 + r) * n) + j + 1);
486 for (std::size_t p {0}; p < i; ++p) {
488 for (std::size_t r {i}; r < m; ++r) {
493 for (std::size_t r {0}; r < m; ++r) {
495 for (std::size_t p {0}; p < i; ++p) {
498 y[((k + 1 + r) * b) + i] =
tau * (
y[((k + 1 + r) * b) + i] -
sum);
500 for (std::size_t p {0}; p < i; ++p) {
502 for (std::size_t q {p}; q < i; ++q) {
505 t[(p * b) + i] = -
tau *
sum;
507 t[(i * b) + i] =
tau;
510 gemm(k + 1, b, m, a.data() + k + 1, n, v.data(), b,
top.data(), b);
511 for (std::size_t r {0}; r <= k; ++r) {
512 for (std::size_t p {b}; p-- > 0;) {
514 for (std::size_t q {0}; q <= p; ++q) {
517 y[(r * b) + p] =
sum;
520 for (std::size_t r {0}; r <= k; ++r) {
521 for (std::size_t i {1}; i < b; ++i) {
523 for (std::size_t p {0}; p < i; ++p) {
526 a[(r * n) + k + i] -=
sum;
529 const std::size_t
rest {high - k - b};
531 for (std::size_t e {0}; e < high * b; ++e) {
535 for (std::size_t r {0}; r < m; ++r) {
536 for (std::size_t p {0}; p < b; ++p) {
541 const std::size_t columns {n - k - b};
543 gemm(b, columns, m,
v_adjoint.data(), m, a.data() + ((k + 1) * n) + k + b, n,
product.data(), columns);
545 for (std::size_t p {0}; p < b; ++p) {
546 for (std::size_t q {0}; q <= p; ++q) {
547 const T factor {-
conj_of(t[(q * b) + p])};
548 for (std::size_t c {0}; c < columns; ++c) {
549 scaled[(p * columns) + c] +=
times(factor,
product[(q * columns) + c]);
553 gemm(m, columns, b, v.data(), b, scaled.data(), columns, a.data() + ((k + 1) * n) + k + b, n);
555 panels.push_back({k, b, std::move(v), std::move(t)});
563 for (std::size_t i {0}; i < n; ++i) {
564 q[(i * n) + i] =
T {1};
566 for (std::size_t s {
panels.size()}; s-- > 0;) {
569 const std::size_t b {
panel.width};
572 for (std::size_t r {0}; r < m; ++r) {
573 for (std::size_t p {0}; p < b; ++p) {
580 for (std::size_t p {0}; p < b; ++p) {
581 for (std::size_t r {p}; r < b; ++r) {
582 const T factor {-
panel.t[(p * b) + r]};
583 for (std::size_t c {0}; c < m; ++c) {
584 scaled[(p * m) + c] +=
times(factor,
product[(r * m) + c]);
591 for (std::size_t i {0}; i < n; ++i) {
592 for (std::size_t j {0}; j < n; ++j) {
593 qt[(j * n) + i] = q[(i * n) + j];
600 template <
typename T>
621 const double rest {count == 3 ? std::hypot(v[1], v[2]) : std::abs(v[1])};
625 const double beta {-std::copysign(std::hypot(v[0],
rest), v[0])};
626 const double tau {(beta - v[0]) / beta};
627 const double scale {1.0 / (v[0] - beta)};
628 for (std::size_t i {1}; i < count; ++i) {
645 const double beta {-std::copysign(std::hypot(std::abs(v[0]), std::abs(v[1])), v[0].real())};
646 const std::complex<double>
tau {(beta - v[0].real()) / beta, -v[0].
imag() / beta};
647 v[1] = v[1] / (v[0] - beta);
674 if (b == 0.0 && c != 0.0) {
681 else if (c != 0.0 && (a - d != 0.0 || std::signbit(b) == std::signbit(c))) {
682 const double temp {a - d};
683 double p {0.5 *
temp};
684 const double bcmax {std::max(std::abs(b), std::abs(c))};
685 const double bcmis {std::min(std::abs(b), std::abs(c)) * std::copysign(1.0, b) * std::copysign(1.0, c)};
686 const double scale {std::max(std::abs(p),
bcmax)};
687 double z {((p / scale) * p) + ((
bcmax / scale) *
bcmis)};
689 z = p + std::copysign(std::sqrt(scale) * std::sqrt(
z), p);
692 const double tau {std::hypot(c,
z)};
699 const double sigma {b + c};
700 const double tau {std::hypot(sigma,
temp)};
701 out.cs = std::sqrt(0.5 * (1.0 + (std::abs(sigma) /
tau)));
702 out.sn = -(0.5 * (
temp /
tau) /
out.cs) * std::copysign(1.0, sigma);
703 const double aa {(a *
out.cs) + (b *
out.sn)};
704 const double bb {(-a *
out.sn) + (b *
out.cs)};
705 const double cc {(c *
out.cs) + (d *
out.sn)};
706 const double dd {(-c *
out.sn) + (d *
out.cs)};
714 if (c != 0.0 && b != 0.0 && std::signbit(b) == std::signbit(c)) {
715 const double sab {std::sqrt(std::abs(b))};
716 const double sac {std::sqrt(std::abs(c))};
717 const double root {std::copysign(
sab *
sac, c)};
718 const double inverse {1.0 / std::sqrt(std::abs(b + c))};
729 else if (c != 0.0 && b == 0.0) {
732 const double cs {
out.cs};
741 out.im1 = std::sqrt(std::abs(b)) * std::sqrt(std::abs(c));
748 template <
typename T>
756 for (std::size_t i {0}; i < count; ++i) {
769 template <
typename T>
785 for (std::size_t j {
from}; j <
to; ++j) {
795 template <
typename T>
807 for (std::size_t j {
from}; j <
to; ++j) {
819 template <
typename T>
829 for (std::size_t r {0}; r < rows; ++r) {
830 T*
const x {first + (r * ld)};
839 template <
typename T>
847 for (std::size_t r {0}; r < rows; ++r) {
848 T*
const x {first + (r * ld)};
856 template <
typename T>
884 const std::size_t n {t.
n};
885 const auto at {[&h, n](std::size_t i, std::size_t j) ->
double& {
return h[(i * n) + j]; }};
888 for (std::size_t end {t.
high}; end > t.
low;) {
889 const std::size_t i {end - 1};
890 std::size_t
l {t.
low};
895 const double sub {std::abs(at(k, k - 1))};
899 double test {std::abs(at(k - 1, k - 1)) + std::abs(at(k, k))};
901 if (k >= t.
low + 2) {
902 test += std::abs(at(k - 1, k - 2));
904 if (k + 1 < t.
high) {
905 test += std::abs(at(k + 1, k));
909 const double ab {std::max(
sub, std::abs(at(k - 1, k)))};
910 const double ba {std::min(
sub, std::abs(at(k - 1, k)))};
911 const double aa {std::max(std::abs(at(k, k)), std::abs(at(k - 1, k - 1) - at(k, k)))};
912 const double bb {std::min(std::abs(at(k, k)), std::abs(at(k - 1, k - 1) - at(k, k)))};
913 const double s {
aa +
ab};
928 const std::size_t first {t.
full ? 0 :
l};
929 const std::size_t
last {t.
full ? n : i + 1};
935 const double s {std::abs(at(i, i - 1)) + std::abs(at(i - 1, i - 2))};
936 h11 = (0.75 * s) + at(i, i);
942 const double s {std::abs(at(
l + 1,
l)) + std::abs(at(
l + 2,
l + 1))};
943 h11 = (0.75 * s) + at(
l,
l);
949 h11 = at(i - 1, i - 1);
954 const double s {std::abs(
h11) + std::abs(
h12) + std::abs(
h21) + std::abs(
h22)};
961 const double root {std::sqrt(std::abs(
det))};
974 std::size_t m {i - 2};
977 const double h21s {at(m + 1, m) / (std::abs(at(m, m) -
rt2r) + std::abs(
rt2i) + std::abs(at(m + 1, m)))};
978 const double scale {std::abs(at(m, m) -
rt2r) + std::abs(
rt2i) + std::abs(at(m + 1, m))};
979 v[0] = (
h21s * at(m, m + 1)) + ((at(m, m) -
rt1r) * ((at(m, m) -
rt2r) / scale)) - (
rt1i * (
rt2i / scale));
980 v[1] =
h21s * (at(m, m) + at(m + 1, m + 1) -
rt1r -
rt2r);
981 v[2] =
h21s * at(m + 2, m + 1);
982 const double sum {std::abs(v[0]) + std::abs(v[1]) + std::abs(v[2])};
989 const double above {std::abs(at(m, m - 1)) * (std::abs(v[1]) + std::abs(v[2]))};
990 const double here {std::abs(v[0]) * (std::abs(at(m - 1, m - 1)) + std::abs(at(m, m)) + std::abs(at(m + 1, m + 1)))};
995 for (std::size_t
k2 {m};
k2 < i; ++
k2) {
996 const std::size_t count {std::min<std::size_t>(3, i -
k2 + 1)};
998 v[0] = at(
k2,
k2 - 1);
999 v[1] = at(
k2 + 1,
k2 - 1);
1000 v[2] = count == 3 ? at(
k2 + 2,
k2 - 1) : 0.0;
1004 at(
k2,
k2 - 1) = v[0];
1005 at(
k2 + 1,
k2 - 1) = 0.0;
1007 at(
k2 + 2,
k2 - 1) = 0.0;
1011 at(
k2,
k2 - 1) *= 1.0 -
t1;
1013 const double v2 {v[1]};
1014 const double v3 {count == 3 ? v[2] : 0.0};
1015 const double t2 {
t1 *
v2};
1016 const double t3 {
t1 *
v3};
1017 const std::size_t
third {count == 3 ? std::size_t {2} : std::size_t {1}};
1018 double*
a1 {&at(
k2, 0)};
1019 double*
a2 {
a1 + n};
1021 for (std::size_t j {
k2}; j <
last; ++j) {
1027 for (std::size_t j {first}; j <= std::min(
k2 + 3, i); ++j) {
1028 double*
row {&at(j,
k2)};
1034 if (t.
zt !=
nullptr) {
1036 double*
r1 {zt.data() + (
k2 * n)};
1037 double*
r2 {
r1 + n};
1039 for (std::size_t j {t.
low}; j < t.
high; ++j) {
1049 throw convergence_error(
"eigendecomposition: the QR iterations did not converge");
1058 im[i - 1] =
block.im1;
1062 rotate(&at(i - 1, i + 1 < n ? i + 1 : i), &at(i, i + 1 < n ? i + 1 : i), n - i - 1, 1,
block.cs,
block.sn);
1065 if (t.
zt !=
nullptr) {
1085 buffer<std::complex<double>>& values,
1088 using C = std::complex<double>;
1090 const std::size_t n {t.n};
1091 const auto at {[&h, n](std::size_t i, std::size_t j) ->
C& {
return h[(i * n) + j]; }};
1092 const double smallest {std::numeric_limits<double>::min() * (
static_cast<double>(t.high - t.low) /
schur_ulp)};
1094 for (std::size_t end {t.high}; end > t.low;) {
1095 const std::size_t i {end - 1};
1096 std::size_t
l {t.low};
1100 for (; k >
l; --k) {
1107 if (k >= t.low + 2) {
1110 if (k + 1 < t.high) {
1119 const double s {
aa +
ab};
1127 at(
l,
l - 1) =
C {};
1134 const std::size_t first {t.full ? 0 :
l};
1135 const std::size_t
last {t.full ? n : i + 1};
1145 const C u {std::sqrt(at(i - 1, i)) * std::sqrt(at(i, i - 1))};
1147 const C x {0.5 * (at(i - 1, i - 1) -
shift)};
1150 C y {s * std::sqrt(((x / s) * (x / s)) + ((u / s) * (u / s)))};
1151 if (
sx > 0.0 && ((x /
sx).real() *
y.real()) + ((x /
sx).imag() *
y.imag()) < 0.0) {
1154 shift -= u * (u / (x +
y));
1157 std::size_t m {i - 1};
1160 const C h11 {at(m, m)};
1161 const C h22 {at(m + 1, m + 1)};
1162 const C h21 {at(m + 1, m)};
1173 for (std::size_t
k2 {m};
k2 < i; ++
k2) {
1175 v[0] = at(
k2,
k2 - 1);
1176 v[1] = at(
k2 + 1,
k2 - 1);
1180 at(
k2,
k2 - 1) = v[0];
1181 at(
k2 + 1,
k2 - 1) =
C {};
1184 at(
k2,
k2 - 1) *= 1.0 - std::conj(
t1);
1189 if (t.zt !=
nullptr) {
1190 C*
const r1 {t.zt->data() + (
k2 * n)};
1196 throw convergence_error(
"eigendecomposition: the QR iterations did not converge");
1198 values[i] = at(i, i);
1209 template <
typename T>
1225 return data[((i - 1) *
ld) + (j - 1)];
1232 return static_cast<std::size_t
>(count);
1264 template <
typename T>
1277 return {1.0, 0.0,
f};
1280 return {0.0, std::copysign(1.0,
g), std::abs(
g)};
1282 const double r {std::copysign(std::hypot(
f,
g),
f)};
1283 return {std::abs(
f) / std::abs(r),
g / r, r};
1288 const std::complex<double>&
g)
1290 using C = std::complex<double>;
1292 return {1.0,
C {},
f};
1295 return {0.0, std::conj(
g) / std::abs(
g),
C {std::abs(
g)}};
1297 const double size {std::abs(
f)};
1298 const double d {std::hypot(size, std::abs(
g))};
1300 return {size / d,
phase * std::conj(
g) / d,
phase * d};
1304 template <
typename T>
1312 for (std::size_t i {0}; i < count; ++i) {
1325 template <
typename T>
1331 const T t11 {t(k, k)};
1332 const T t22 {t(k + 1, k + 1)};
1339 t(k + 1, k + 1) =
t11;
1350 for (std::size_t c {0}; c < count; ++c) {
1351 const double sum {(u[0] * t[c]) + (u[1] * t[ld + c]) + (u[2] * t[(2 * ld) + c])};
1352 t[c] -=
tau *
sum * u[0];
1353 t[ld + c] -=
tau *
sum * u[1];
1354 t[(2 * ld) + c] -=
tau *
sum * u[2];
1365 for (std::size_t r {0}; r < count; ++r) {
1366 double*
const row {t + (r * ld)};
1367 const double sum {(
row[0] * u[0]) + (
row[1] * u[1]) + (
row[2] * u[2])};
1402 for (std::size_t r {0}; r < size; ++r) {
1403 for (std::size_t c {0}; c < size; ++c) {
1409 for (std::size_t s {0}; s < size; ++s) {
1412 for (std::size_t r {s}; r < size; ++r) {
1413 for (std::size_t c {s}; c < size; ++c) {
1414 if (std::abs(k[r][c]) > std::abs(k[
pr][
pc])) {
1420 std::swap(k[s], k[
pr]);
1422 for (std::size_t r {0}; r < size; ++r) {
1423 std::swap(k[r][s], k[r][
pc]);
1426 if (std::abs(k[s][s]) <
floor) {
1429 for (std::size_t r {s + 1}; r < size; ++r) {
1430 const double factor {k[r][s] / k[s][s]};
1431 for (std::size_t c {s}; c < size; ++c) {
1432 k[r][c] -= factor * k[s][c];
1434 rhs[r] -= factor *
rhs[s];
1438 for (std::size_t s {size}; s-- > 0;) {
1440 for (std::size_t c {s + 1}; c < size; ++c) {
1441 sum -= k[s][c] *
y[c];
1443 y[s] =
sum / k[s][s];
1445 for (std::size_t s {0}; s < size; ++s) {
1477 if (n1 == 1 &&
n2 == 1) {
1485 std::array<double, 16> d {};
1490 dd(i, j) = t(
j1 + i - 1,
j1 + j - 1);
1499 std::array<double, 3>
u1 {};
1500 std::array<double, 3>
u2 {};
1515 residue = std::max({std::abs(
dd(3, 1)), std::abs(
dd(3, 2)), std::abs(
dd(3, 3) -
t11)});
1526 residue = std::max({std::abs(
dd(2, 1)), std::abs(
dd(3, 1)), std::abs(
dd(1, 1) -
t33)});
1535 const double temp {-
tau1 * (at(1, 2) + (
u1[1] * at(2, 2)))};
1536 u2[0] = (-
temp *
u1[1]) - at(2, 2);
1546 residue = std::max({std::abs(
dd(3, 1)), std::abs(
dd(3, 2)), std::abs(
dd(4, 1)), std::abs(
dd(4, 2))});
1594 return j < n && t(j + 1, j) != 0.0 ? 2 : 1;
1619 struct refused : std::exception
1629 if (
nbf == 2 &&
nbl == 1) {
1632 if (
nbf == 1 &&
nbl == 2) {
1647 if (next == 2 && t(
here + 2,
here + 1) == 0.0) {
1672 if (next == 2 && t(
here,
here - 1) == 0.0) {
1716 const std::complex<double>&
s1,
1717 const std::complex<double>&
s2,
1720 const double sr1 {
s1.real()};
1721 const double si1 {
s1.imag()};
1722 const double sr2 {
s2.real()};
1723 const double si2 {
s2.imag()};
1725 const double s {std::abs(h(1, 1) -
sr2) + std::abs(
si2) + std::abs(h(2, 1))};
1731 const double h21s {h(2, 1) / s};
1732 v[0] = (
h21s * h(1, 2)) + ((h(1, 1) -
sr1) * ((h(1, 1) -
sr2) / s)) - (
si1 * (
si2 / s));
1733 v[1] =
h21s * (h(1, 1) + h(2, 2) -
sr1 -
sr2);
1736 const double s {std::abs(h(1, 1) -
sr2) + std::abs(
si2) + std::abs(h(2, 1)) + std::abs(h(3, 1))};
1743 const double h21s {h(2, 1) / s};
1744 const double h31s {h(3, 1) / s};
1745 v[0] = ((h(1, 1) -
sr1) * ((h(1, 1) -
sr2) / s)) - (
si1 * (
si2 / s)) + (h(1, 2) *
h21s) + (h(1, 3) *
h31s);
1746 v[1] = (
h21s * (h(1, 1) + h(2, 2) -
sr1 -
sr2)) + (h(2, 3) *
h31s);
1747 v[2] = (
h31s * (h(1, 1) + h(3, 3) -
sr1 -
sr2)) + (
h21s * h(3, 2));
1753 const std::complex<double>&
s1,
1754 const std::complex<double>&
s2,
1755 std::complex<double>* v)
1757 using C = std::complex<double>;
1765 const C h21s {h(2, 1) / s};
1766 v[0] = (
h21s * h(1, 2)) + ((h(1, 1) -
s1) * ((h(1, 1) -
s2) / s));
1767 v[1] =
h21s * (h(1, 1) + h(2, 2) -
s1 -
s2);
1777 const C h21s {h(2, 1) / s};
1778 const C h31s {h(3, 1) / s};
1779 v[0] = ((h(1, 1) -
s1) * ((h(1, 1) -
s2) / s)) + (
h21s * h(1, 2)) + (
h31s * h(1, 3));
1780 v[1] = (
h21s * (h(1, 1) + h(2, 2) -
s1 -
s2)) + (
h31s * h(2, 3));
1781 v[2] = (
h31s * (h(1, 1) + h(3, 3) -
s1 -
s2)) + (
h21s * h(3, 2));
1791 if (s[i].
imag() != -s[i + 1].
imag()) {
1792 const std::complex<double> first {s[i]};
1794 s[i + 1] = s[i + 2];
1803 const std::complex<double>& )
1816 const std::complex<double>& )
1823 template <
typename T>
1830 if (h(k + 1, k) ==
T {}) {
1836 if (k >=
ktop + d) {
1839 if (k <=
kbot - d - 1) {
1851 const double scale {
h11 +
h12};
1860 template <
typename T>
1881 template <
typename T>
1885 std::complex<double>* s,
1893 const double smallest {std::numeric_limits<double>::min() * (
static_cast<double>(n) /
schur_ulp)};
1915 reflect_three_rows(&zt(k + 1, 1), &zt(k + 2, 1), &zt(k + 3, 1),
count_of(low - 1),
count_of(high), v(1, m), v(2, m), v(3, m),
false);
1918 reflect_two_rows(&zt(k + 1, 1), &zt(k + 2, 1),
count_of(low - 1),
count_of(high), v(1, m), v(2, m),
false);
1932 if (k ==
ktop - 1) {
1933 std::array<T, 2>
column {};
1940 T beta {h(k + 1, k)};
1941 v(2,
m22) = h(k + 2, k);
1947 reflect_two_rows(&h(k + 1, 1), &h(k + 2, 1),
count_of(k),
count_of(
jbot), v(1,
m22), v(2,
m22),
true);
1954 reflect_two_rows(&
ut(
kms + 1, 1), &
ut(
kms + 2, 1),
from,
count_of(
kdu), v(1,
m22), v(2,
m22),
false);
1960 if (k ==
ktop - 1) {
1961 std::array<T, 3>
column {};
1970 const T sum {v(1, m) * v(3, m) * h(k + 3, k + 2)};
1974 T beta {h(k + 1, k)};
1975 v(2, m) = h(k + 2, k);
1976 v(3, m) = h(k + 3, k);
1981 double fill {std::numeric_limits<double>::infinity()};
1982 std::array<T, 3>
fresh {};
1985 if (h(k + 3, k) ==
T {} && h(k + 3, k + 2) !=
T {}) {
2005 reflect_three_columns(&h(
jtop, k + 1),
count_of(std::min(
kbot, k + 3) -
jtop + 1),
count_of(n), v(1, m), v(2, m), v(3, m));
2013 reflect_three_rows(&h(k + 1, 1), &h(k + 2, 1), &h(k + 3, 1),
count_of(std::max(
ktop,
krcol + (2 * m)) - 1),
count_of(
jbot), v(1, m),
2014 v(2, m), v(3, m),
true);
2022 reflect_three_rows(&
ut(
kms + 1, 1), &
ut(
kms + 2, 1), &
ut(
kms + 3, 1),
count_of(
i2 - 1),
count_of(
i4), v(1, m), v(2, m), v(3, m),
false);
2057 for (std::size_t r {0}; r < rows; ++r) {
2061 if (
target.zt !=
nullptr) {
2069 const std::size_t width {
count_of(high - low + 1)};
2079 template <
typename T>
2081 std::complex<double>*
w,
2087 std::complex<double>*
w)
2092 for (std::size_t i {t.
low}; i < t.
high; ++i) {
2093 w[i] = std::complex<double> {re[i], im[i]};
2099 std::complex<double>*
w)
2103 std::copy(values.begin() +
static_cast<std::ptrdiff_t
>(t.low), values.begin() +
static_cast<std::ptrdiff_t
>(t.high),
w + t.low);
2117 std::complex<double>*
w)
2120 return k == i + 1 ? std::abs(t(i, i)) : std::abs(t(i, i)) + (std::sqrt(std::abs(t(i + 1, i))) * std::sqrt(std::abs(t(i, i + 1))));
2126 double foo {order == 1 ? std::abs(t(
ns,
ns)) : size(
ns - 1,
ns + 1)};
2130 const double spike {order == 1 ? std::abs(s *
vt(
ns, 1)) : std::max(std::abs(s *
vt(
ns, 1)), std::abs(s *
vt(
ns - 1, 1)))};
2149 const double evi {size(i, k)};
2150 const double evk {k ==
kend ? std::abs(t(k, k)) : size(k, next(k,
kend))};
2164 if (i == 1 || t(i, i - 1) == 0.0) {
2165 w[i - 1] = std::complex<double> {t(i, i), 0.0};
2169 double a {t(i - 1, i - 1)};
2170 double b {t(i - 1, i)};
2171 double c {t(i, i - 1)};
2175 w[i - 1] = std::complex<double> {
block.re2,
block.im2};
2186 const std::complex<double>& s,
2188 std::complex<double>*
w)
2236 template <
typename T>
2241 std::complex<double>*
w,
2246 const double smallest {std::numeric_limits<double>::min() * (
static_cast<double>(n) /
schur_ulp)};
2260 for (
lapack_index j {std::max<lapack_index>(1, i - 1)}; j <=
jw; ++j) {
2278 t(
jw,
jw - 2) =
T {};
2330 std::copy(rows.begin(), rows.end(),
vt_store.begin());
2336 for (
lapack_index j {std::max<lapack_index>(1, i - 1)}; j <=
jw; ++j) {
2353 for (std::size_t r {0}; r < rows; ++r) {
2361 for (std::size_t r {0}; r < width; ++r) {
2365 if (
target.zt !=
nullptr) {
2371 for (std::size_t r {0}; r < width; ++r) {
2385 else if (
nh >= 3000) {
2388 else if (
nh >= 590) {
2391 else if (
nh >= 150) {
2392 ns = std::max<lapack_index>(10,
nh /
static_cast<lapack_index>(std::lround(std::log2(
static_cast<double>(
nh)))));
2394 else if (
nh >= 60) {
2397 else if (
nh >= 30) {
2400 return std::max<lapack_index>(2,
ns - (
ns % 2));
2407 return nh <= 500 ?
ns : 3 *
ns / 2;
2413 std::complex<double>*
w,
2419 const double ss {std::abs(h(i, i - 1)) + std::abs(h(i - 1, i - 2))};
2420 double a {(0.75 *
ss) + h(i, i)};
2422 double c {-0.4375 *
ss};
2426 w[i - 1] = std::complex<double> {
block.re2,
block.im2};
2434 std::complex<double>*
w,
2440 w[i - 1] = h(i, i) + (0.75 *
modulus_1(h(i, i - 1)));
2441 w[i - 2] =
w[i - 1];
2454 const std::complex<double>
last {
w[i - 1]};
2455 w[i - 1] =
w[i - 2];
2456 w[i - 2] =
w[i - 3];
2466 const std::complex<double>& )
2476 return kbot -
ks + 1 == 2 &&
w[
kbot - 1].imag() == 0.0;
2483 const std::complex<double>& )
2485 return kbot -
ks + 1 == 2;
2501 template <
typename T>
2503 std::complex<double>*
w,
2516 nsr = std::max<lapack_index>(2,
nsr - (
nsr % 2));
2569 for (
lapack_index j {std::max<lapack_index>(1, i - 1)}; j <=
ns; ++j) {
2570 lower(i, j) = h(
ks + i - 1,
ks + j - 1);
2582 std::swap(
w[i - 1],
w[i]);
2607 throw convergence_error(
"eigendecomposition: the QR iterations did not converge");
2623 for (std::size_t i {t.
low}; i < t.
high; ++i) {
2624 re[i] =
w[i].real();
2625 im[i] =
w[i].imag();
2631 buffer<std::complex<double>>& values,
2646 template <
typename S>
2652 for (std::size_t q {1}; q < 4; ++q) {
2655 const std::size_t
pr {p / 2};
2656 const std::size_t
pc {p % 2};
2659 const S u12 {m[(
pr * 2) + 1 -
pc]};
2666 double factor {1.0};
2681 template <
typename S>
2690 template <
typename S,
typename P>
2697 double factor {1.0};
2715 std::size_t
to)
const
2732 for (std::size_t
l {
from};
l <=
to; ++
l) {
2750 std::size_t
to)
const
2757 const std::complex<double>& value)
2759 re[j] = value.real();
2760 im[j] = value.imag();
2768 for (std::size_t
l {
from};
l <=
to; ++
l) {
2788 std::size_t
to)
const
2790 const auto*
const parts {
reinterpret_cast<const double*
>(
row)};
2791 const std::size_t count {2 * (
to -
from + 1)};
2798 const std::complex<double>& value)
2817 for (std::size_t
l {2 *
from};
l <= (2 *
to) + 1; ++
l) {
2832 for (std::size_t r {0}; r < n; ++r) {
2840 for (std::size_t r {0}; r < n; ++r) {
2852 template <
typename T,
typename X>
2857 typename X::scalar
lambda,
2861 using S =
typename X::scalar;
2862 for (std::size_t j {k}; j > 0;) {
2863 if constexpr (std::is_floating_point_v<T>) {
2864 if (j >= 2 && t[((j - 1) * n) + j - 2] != 0.0) {
2865 const S m[4] {
S {t[((j - 2) * n) + j - 2]} -
lambda,
S {t[((j - 2) * n) + j - 1]},
S {t[((j - 1) * n) + j - 2]},
2866 S {t[((j - 1) * n) + j - 1]} -
lambda};
2867 S r[2] {-x.dot(t.data() + ((j - 2) * n), j,
top), -x.dot(t.data() + ((j - 1) * n), j,
top)};
2869 if (factor != 1.0) {
2870 x.scale(j,
top, factor);
2878 const auto [value, factor] {
divided(-x.dot(t.data() + ((j - 1) * n), j,
top),
S {t[((j - 1) * n) + j - 1]} -
lambda,
floor)};
2879 if (factor != 1.0) {
2880 x.scale(j,
top, factor);
2882 x.set(j - 1, value);
2894 using C = std::complex<double>;
2895 const double smallest {std::numeric_limits<double>::min() * (
static_cast<double>(n) /
schur_ulp)};
2898 for (std::size_t k {0}; k < n; ++k) {
2899 const C lambda {t[(k * n) + k]};
2902 for (std::size_t
l {0};
l <= k; ++
l) {
2903 xt[(k * n) +
l] = x.get(
l);
2926 using C = std::complex<double>;
2927 const double smallest {std::numeric_limits<double>::min() * (
static_cast<double>(n) /
schur_ulp)};
2931 for (std::size_t k {0}; k < n; ++k) {
2934 double*
row_im {
out.im.data() + (k * n)};
2938 std::copy(x.x.begin(), x.x.begin() +
static_cast<std::ptrdiff_t
>(k + 1),
row_re);
2940 else if (im[k] > 0.0) {
2941 const double b {t[(k * n) + k + 1]};
2942 const double c {t[((k + 1) * n) + k]};
2943 y.set(k, std::abs(b) >= std::abs(c) ?
C {1.0} :
C {-im[k] / c});
2944 y.set(k + 1, std::abs(b) >= std::abs(c) ?
C {0.0, im[k] / b} :
C {0.0, 1.0});
2946 for (std::size_t
l {0};
l <= k + 1; ++
l) {
2958 template <
typename T>
2965 gemm(n, n, n,
xt.data(), n, zt.data(), n,
vt.data(), n);
2978 template <
typename T>
3000 for (std::size_t i {0}; i <
n_; ++i) {
3001 for (std::size_t j {0}; j <
n_; ++j) {
3007 const double scale {
largest == 0.0 ? 1.0 : std::ldexp(1.0, std::ilogb(
largest))};
3009 for (std::size_t i {0}; i <
n_; ++i) {
3010 for (std::size_t j {0}; j <
n_; ++j) {
3024 if constexpr (std::is_floating_point_v<T>) {
3027 for (std::size_t i {0}; i <
n_; ++i) {
3028 re[i] = a[(i *
n_) + i];
3031 for (std::size_t i {0}; i <
n_; ++i) {
3032 values[i] = std::complex<double> {re[i] * scale, im[i] * scale};
3040 for (std::size_t e {0}; e <
n_ *
n_; ++e) {
3041 vt[e] = std::complex<double> {
vre[e],
vim[e]};
3046 for (std::size_t i {0}; i <
n_; ++i) {
3050 for (std::size_t i {0}; i <
n_; ++i) {
3062 for (std::size_t c {0}; c <
n_; ++c) {
3063 std::complex<double>*
row {
vt.data() + (c *
n_)};
3067 for (std::size_t s {
balanced.swaps.size()}; s-- > 0;) {
3073 constexpr std::size_t tile {32};
3074 for (std::size_t
r0 {0};
r0 <
n_;
r0 += tile) {
3075 for (std::size_t
c0 {0};
c0 <
n_;
c0 += tile) {
3076 for (std::size_t r {
r0}; r < std::min(
r0 + tile,
n_); ++r) {
3077 for (std::size_t c {
c0}; c < std::min(
c0 + tile,
n_); ++c) {
3078 v[(r *
n_) + c] =
vt[(c *
n_) + r];
3117 const std::complex<double>& value,
3120 if (value.imag() == 0.0) {
3122 for (std::size_t r {0}; r <
n_; ++r) {
3123 row[r] = std::complex<double> {
row[r].real() /
norm, 0.0};
3126 else if (value.imag() < 0.0) {
3127 const std::complex<double>* first {
row -
n_};
3128 for (std::size_t r {0}; r <
n_; ++r) {
3129 row[r] = std::conj(first[r]);
3140 const std::complex<double>& ,
3141 const std::complex<double>& )
const
3158 template <
typename T>
Thrown when an iterative algorithm has not converged within its bound of sweeps.
Thrown when an operation's operands have incompatible shapes.
The eigenvalues, and optionally the right eigenvectors, of a general square matrix,...
void finish(std::complex< double > *row, const std::complex< double > &value, double) const
Normalises the eigenvector row (a row of Vᵀ) of a real matrix's eigenvalue value, as dgeev: a real on...
matrix< std::complex< double > > vectors_
The eigenvectors as columns.
bool real_
Whether all eigenvalues are real.
const vector< std::complex< double > > & values() const noexcept
The eigenvalues, in the order of the Schur form.
const matrix< std::complex< double > > & vectors() const &noexcept
The eigenvectors as columns, ordered to match values (empty where they were not computed).
void finish(std::complex< double > *row, const std::complex< double > &, const std::complex< double > &) const
Normalises the eigenvector row of a complex matrix, as zgeev: to unit norm, its largest component rea...
bool real() const noexcept
Whether every eigenvalue is real (a real matrix's whose Schur form has no 2 × 2 block): its vectors a...
std::size_t n_
The matrix order.
vector< std::complex< double > > values_
The eigenvalues.
matrix< std::complex< double > > vectors() &&
The eigenvectors, moved out of an expiring decomposition.
eigen_decomposition(const matrix< T > &input, bool vectors=true)
Decomposes input.
A dense, row-major matrix of T with value semantics.
A dense vector of T with value semantics.
Matrix factorisations and the algorithms built on them.
buffer< T > hessenberg_unblocked(buffer< T > &a, std::size_t n, std::size_t low, std::size_t high, bool form)
Reduces the active block low … high − 1 of the balanced row-major n × n a to upper Hessenberg form by...
double rescale_tiny(buffer< T > &x)
Scales x by rescue_factor of its largest magnitude, exactly, so that a Householder vector built from ...
T reflector_tau(T &alpha, T *x, std::size_t count)
The Householder reflection H = I − τ v vᴴ, v = (1, v₁…), with Hᴴ (α, x) = (β, 0) and β real,...
void reflect_columns_3(const std::array< double, 3 > &u, double tau, double *t, std::size_t ld, std::size_t count)
The same from the right, to the count × 3 columns at t.
constexpr double back_substitution_limit
The modulus an eigenvector's components are kept under during the back-substitution: the sums stay fi...
void reflect_three_rows(T *r1, T *r2, T *r3, std::size_t from, std::size_t to, const T &tau, const T &v2, const T &v3, bool adjoint)
A reflection I − τ v vᴴ, v = (1, v₂, v₃), on the entries from … to − 1 of three rows: its adjoint fro...
void bulge_column(one_based< double > h, lapack_index count, const std::complex< double > &s1, const std::complex< double > &s2, double *v)
A multiple of the first column of (H − s₁ I)(H − s₂ I) for the leading 2 × 2 or 3 × 3 (count) of the ...
void multishift_schur(const schur_target< T > &target, std::complex< double > *w, bool recursive, lapack_index steps=0)
The Schur form of target's active block by the multishift QR algorithm with aggressive early deflatio...
void normalize_vector(std::complex< double > *v, std::size_t n, bool signed_real)
Scales v to unit Euclidean norm and turns it so that its first component of largest modulus is real: ...
void reflect_two_rows(T *r1, T *r2, std::size_t from, std::size_t to, const T &tau, const T &v2, bool adjoint)
reflect_three_rows for a reflection of two entries, v = (1, v₂), on two rows: its own loop,...
buffer< T > hessenberg_blocked(buffer< T > &a, std::size_t n, std::size_t low, std::size_t high, bool form)
hessenberg_unblocked by panels of hessenberg_block columns, as LAPACK's dgehrd and dlahr2: a panel's ...
buffer< T > hessenberg(buffer< T > &a, std::size_t n, std::size_t low, std::size_t high, bool form)
hessenberg_blocked from an active order of hessenberg_crossover, else hessenberg_unblocked.
void exchange(buffer< T > &a, std::size_t n, std::size_t i, std::size_t j)
Exchanges rows i and j, then columns i and j, of the row-major n × n a: a similarity.
void reflect_three_columns(T *first, std::size_t rows, std::size_t ld, const T &tau, const T &v2, const T &v3)
A reflection I − τ v vᴴ, v = (1, v₂, v₃), from the right on rows rows (ld apart) of the three columns...
constexpr std::size_t hessenberg_crossover
The active order from which hessenberg reduces by panels.
std::size_t count_of(lapack_index count)
A count as an unsigned size (never negative where it is taken).
void reflect_two_columns(T *first, std::size_t rows, std::size_t ld, const T &tau, const T &v2)
The same for a reflection of two entries, v = (1, v₂), on two columns.
void vigilant_deflation(one_based< T > h, lapack_index k, lapack_index ktop, lapack_index kbot, double smallest)
H(k + 1, k) set to zero where the deflation criterion of Ahues and Tisseur holds, as the sweep of dla...
void chase_bulges(const schur_target< T > &target, lapack_index ktop, lapack_index kbot, std::complex< double > *s, lapack_index count, bool accumulate)
One small-bulge multishift QR sweep over the active block ktop … kbot of target's Hessenberg matrix w...
double solve_block(const S(&m)[4], S(&r)[2], double floor)
Solves [a b; c d] x = r in place of r by Gaussian elimination with complete pivoting,...
constexpr std::size_t hessenberg_block
The columns of a panel of hessenberg_blocked.
constexpr double schur_ulp
The relative spacing LAPACK's ‘dlamch('P’)` names: the roundoff a QR sweep judges a subdiagonal by.
void pair_for_sweep(std::complex< double > *w, lapack_index ks, lapack_index kbot, double)
A real matrix's shifts brought into pairs, each a conjugate pair or two reals, as dlaqr0 does before ...
void require_finite(const matrix< T > &a, const char *what)
The one non-finite policy, checked where every decomposition starts.
void exchange_diagonal(one_based< T > t, one_based< T > qt, lapack_index n, lapack_index k)
Exchanges the diagonal entries k and k + 1 of the upper triangular (or quasi-triangular,...
void reflect_from_left(T *x, std::size_t stride, const T &tau, const T &v2, const T &v3)
The adjoint I − τ̄ v vᴴ of a reflection of three entries from the left on one column (x three entries...
T conj_of(const T &x)
The conjugate of a real (or general) scalar — the value itself.
real_operand operand_of(const double *v, std::size_t stride, std::size_t count)
The count entries stride apart at v as a real_operand.
bool two_real_shifts(const std::complex< double > *w, lapack_index ks, lapack_index kbot, double)
Whether a real matrix's sweep is down to two shifts, both real: then the one nearer the corner serves...
void small_sylvester(const one_based< double > &tl, const one_based< double > &tr, const one_based< double > &b, lapack_index n1, lapack_index n2, double(&x)[4])
The solution X (n1 × n2, row-major in x) of TL X − X TR = B, n1 and n2 at most 2, by Gaussian elimina...
auto times(const A &a, const B &b)
a · b.
lapack_index block_order(one_based< double > t, lapack_index n, lapack_index j)
The order of the diagonal block of the quasi-triangular t that starts at j: 2 where a subdiagonal ent...
bool exchange_blocks(one_based< double > t, one_based< double > qt, lapack_index n, lapack_index j1, lapack_index n1, lapack_index n2)
Exchanges the adjacent diagonal blocks of the real quasi-triangular t at j1, of orders n1 then n2,...
std::ptrdiff_t lapack_index
A signed index from 1, as LAPACK's: the multishift sweep starts its bulges in phantom columns above t...
buffer< T > back_transformed(const buffer< T > &xt, const buffer< T > &zt, std::size_t n)
Vᵀ = Xᵀ Zᵀ, row-major n × n, through the matrix product kernel.
bool reorder(one_based< double > t, one_based< double > qt, lapack_index n, lapack_index ifst, lapack_index &ilst)
Moves the diagonal block of the real quasi-triangular t at ifst to ilst by exchanges of adjacent bloc...
constexpr lapack_index multishift_crossover
LAPACK's nmin: the active order below which dlaqr0's iterations skip a sweep after enough deflation.
void gemm(std::size_t m, std::size_t n, std::size_t k, const T *a, std::size_t lda, const T *b, std::size_t ldb, T *c, std::size_t ldc)
C += A·B, every element of C summed in ascending order of the depth.
real_eigenvectors real_vectors(const buffer< double > &t, const buffer< double > &re, const buffer< double > &im, std::size_t n)
The eigenvectors of the real quasi-triangular t (row-major n × n, its 2 × 2 blocks standard) as the r...
void parallel_for(std::size_t count, std::size_t work_per_index, const Body &body)
Runs body(i) for every i in [0, count).
bool already_reduced(double, double rest)
Whether (α, x), of tail norm rest, is already (β, 0) with β real: for a real one, its tail zero.
deflation_count early_deflation(const schur_target< T > &target, lapack_index ktop, lapack_index kbot, lapack_index nw, std::complex< double > *w, bool recursive)
Aggressive early deflation, as LAPACK's dlaqr3 and zlaqr3: the trailing nw × nw window of the active ...
standard_block standardize_block(double &a, double &b, double &c, double &d)
The Schur factorisation of the real 2 × 2 block [a b; c d], as LAPACK's dlanv2: [a b; c d] ← [cs −sn;...
double real_part(const T &x)
The real part of a real (or general) scalar as a double.
plane_rotation< double > givens(double f, double g)
The rotation that takes (f, g) to (r, 0), as LAPACK's dlartg: r of f's sign.
double as_scalar(const std::complex< double > &s, double)
The shift s as the matrix's scalar: a real matrix's are real where they are used one by one.
double small_reflector(double(&v)[3], std::size_t count)
The Householder reflection I − τ v vᵀ, v = (1, x…), that takes (α, x…) to (β, 0…),...
constexpr lapack_index exceptional_after
The iterations without deflation after which the shifts are exceptional (kexsh).
void plain_schur(const schur_target< double > &t, std::complex< double > *w)
The Schur form of t's active block by real_schur, its eigenvalues to w (one per row of t).
void standardize_at(one_based< double > t, one_based< double > qt, lapack_index n, lapack_index j)
The standard form of the 2 × 2 block at j of the quasi-triangular t, its rotation carried to the rest...
void complex_schur(const schur_target< std::complex< double > > &t, buffer< std::complex< double > > &values, std::size_t steps)
The complex Schur form of the upper Hessenberg t's active block, as LAPACK's zlahqr: the shifted QR a...
lapack_index recommended_window(lapack_index nh, lapack_index ns)
The deflation window LAPACK's iparmq recommends for an active block of order nh and ns shifts.
double modulus_1(double x)
|x| of a real x: what modulus_1 of a complex one stands for.
double dot_product(const double *x, const double *y, std::size_t count)
Σ x[i] · y[i] for double, as subtract_product chooses its units (in another order of summation there,...
double largest_part(double x)
|x| of a real x.
lapack_index undeflated(one_based< double > t, one_based< double > vt, lapack_index jw, double s, double smallest, std::complex< double > *w)
The eigenvalues of the real Schur form t (jw × jw) of a deflation window that do not deflate,...
T phase_of(const T &x)
The unit-modulus factor of x: x / |x| (its sign, for a real scalar), and 1 at 0. A subnormal x is sca...
void pair_shifts(std::complex< double > *s, lapack_index count, double)
Arranges a real matrix's shifts so that each pair is a conjugate pair or two reals,...
void real_schur(const schur_target< double > &t, buffer< double > &re, buffer< double > &im, std::size_t steps)
The real Schur form of the upper Hessenberg t's active block, as LAPACK's dlahqr: Francis's implicit ...
scaled_quotient< S > divided(S r, P pivot, double floor)
r / pivot, a pivot below floor taken as floor, r scaled first where the quotient would pass back_subs...
matrix< T > adjoint(const matrix< T > &a)
The conjugate transpose of a.
void rotate_pair(T *x, T *y, std::size_t count, std::size_t stride, double c, const T &s)
(x, y) ← (c x + s y, c y − s̄ x) over count pairs stride apart.
void solve_upward(const buffer< T > &t, std::size_t n, std::size_t k, std::size_t top, typename X::scalar lambda, double floor, X &x)
Solves (T − λ I) x = 0 upward from the component k, rows k − 1 … 0 of the row-major quasi-triangular ...
void rotate(T *x, T *y, std::size_t count, std::size_t stride, double cs, double sn)
(x, y) ← (cs x + sn y, cs y − sn x) over count pairs stride apart: a plane rotation.
std::complex< double > complex_reflector(std::complex< double >(&v)[2])
The Householder reflection I − τ v vᴴ, v = (1, x), whose adjoint takes (α, x) to (β,...
constexpr double balance_limit
The largest power of two a balancing scales a row or a column by, either way: the matrix enters at a ...
buffer< std::complex< double > > complex_vectors(const buffer< std::complex< double > > &t, std::size_t n)
The eigenvectors of the complex upper triangular t (row-major n × n) as the rows of Xᵀ: row k is x wi...
void exceptional_shifts(one_based< double > h, std::complex< double > *w, lapack_index ks, lapack_index kbot, lapack_index ktop)
Exceptional shifts for a real matrix, as dlaqr0's after kexsh iterations without deflation: from the ...
constexpr lapack_index nibble
The share of the window, in percent, whose deflation makes the sweep unnecessary (nibble).
void schur_form(const schur_target< double > &t, buffer< double > &re, buffer< double > &im, std::size_t steps)
The real Schur form of t's active block: real_schur below multishift_from, else multishift_schur,...
constexpr std::size_t schur_steps_per_order
The iterations one eigenvalue (or pair) may take per unit of the active order, as dlahqr's 30.
constexpr lapack_index multishift_from(double)
The order from which a real Schur form is taken by multishift_schur, below which real_schur is faster...
balancing balance(buffer< T > &a, std::size_t n)
Balances the row-major n × n a in place, as LAPACK's ‘dgebal('B’)`: rows with no off-diagonal entry i...
lapack_index recommended_shifts(lapack_index nh)
The shifts LAPACK's iparmq recommends for an active block of order nh.
void reflect_rows_3(const std::array< double, 3 > &u, double tau, double *t, std::size_t ld, std::size_t count)
H = I − τ u uᵀ of three entries applied from the left to the 3 × count rows at t (row stride ld).
constexpr lapack_index window_growth
The iterations without deflation after which the window grows (kexnw).
double scaled_norm(const T *x, std::size_t count)
The Euclidean norm of the count elements at x, by norm_at_scale for this type.
The NumericAL public API.
std::vector< T, detail::default_init_allocator< T > > buffer
The storage of vector, matrix and tensor, namely a std::vector whose buffer<T>(n) and resize(n) leave...
T sum(const tensor< T > &t)
The sum of every element, by pairwise halving (0 for an empty tensor).
vector< std::complex< double > > eigenvalues(const matrix< T > &a)
The eigenvalues alone of the square a, as numpy.linalg.eigvals.
@ amx
The Apple AMX coprocessor, fused multiply-adds; the products it does not suit on the NEON path's tile...
matrix< T > inverse(matrix< T > a)
The inverse of a square matrix.
How a matrix was balanced: swaps, in the order they were applied, then the scaling of the active bloc...
std::vector< std::pair< std::size_t, std::size_t > > swaps
Rows and columns exchanged, in order.
std::size_t high
One past its last.
buffer< double > scale
The diagonal D of D⁻¹ A D (1 outside).
std::size_t low
The active block's first row and column.
A complex vector that rows are summed against, kept as (re, −im) and (im, re) pairs: a complex row,...
std::complex< double > dot(const std::complex< double > *row) const
Σ row[l] v[l].
buffer< double > real_side
(re, −im) per entry.
buffer< double > imaginary_side
(im, re) per entry.
What early_deflation found: the eigenvalues left as shifts, and those deflated.
lapack_index shifts
Undeflated: the shifts, at the bottom of the active block.
lapack_index deflated
Deflated below them.
One panel of hessenberg_blocked, Q_panel = I − V T Vᴴ.
buffer< T > t
T, row-major width × width, upper triangular.
std::size_t width
Its columns.
buffer< T > v
V, row-major (high − first − 1) × width, unit lower trapezoidal.
std::size_t first
The panel's first column; its reflectors act on rows first + 1 … high − 1.
A complex matrix's eigenvector during its back-substitution, kept as (re, −im) and (im,...
void set(std::size_t j, const std::complex< double > &value)
Sets component j to value.
buffer< double > real_side
(re, −im) per component: a row against it gives the product's real part.
void scale(std::size_t from, std::size_t to, double factor)
Scales the components from … to by factor.
std::complex< double > scalar
Its components.
std::complex< double > dot(const std::complex< double > *row, std::size_t from, std::size_t to) const
Σ_{l = from…to} row[l] x[l].
std::complex< double > get(std::size_t j) const
Component j.
buffer< double > imaginary_side
(im, re) per component: its imaginary part.
A row-major matrix read through indices from 1, (1, 1) its first entry.
lapack_index ld
The distance between rows.
T & operator()(lapack_index i, lapack_index j) const
The entry of row i and column j (from 1).
one_based(T *first, lapack_index distance)
The matrix whose first entry is at first, its rows distance apart.
A plane rotation [c s; −s̄ c] and what it leaves of its first argument.
A real eigenvector during its back-substitution, the sums of rows against it by dot_product.
double scalar
Its components.
void set(std::size_t j, double value)
Sets component j to value.
double dot(const double *row, std::size_t from, std::size_t to) const
Σ_{l = from…to} row[l] x[l].
void scale(std::size_t from, std::size_t to, double factor)
Scales the components from … to by factor.
buffer< double > x
The components.
A real matrix's eigenvectors before their back-transformation: Xᵀ's real and imaginary parts.
buffer< double > im
Im Xᵀ, zero where every eigenvalue is real.
buffer< double > re
Re Xᵀ, row-major n × n.
A real vector that rows are summed against by dot_product.
double dot(const double *row) const
Σ row[l] v[l].
buffer< double > v
The vector.
A quotient of divided and the factor its dividend was scaled by: a type of its own,...
double factor
The dividend's scaling, 1 where none was needed.
Where a QR sweep applies its reflections: the rows and columns it updates, and Z.
std::size_t low
The active block's first row.
bool full
Whether the whole Schur form is wanted (else the active block alone).
buffer< T > * h
The Hessenberg matrix, row-major.
std::size_t high
One past its last.
buffer< T > * zt
The Schur vectors to accumulate, transposed (row-major Zᵀ), or none.
A real matrix's complex eigenvector during its back-substitution, its real and imaginary parts apart:...
void scale(std::size_t from, std::size_t to, double factor)
Scales the components from … to by factor.
buffer< double > im
The imaginary parts.
void set(std::size_t j, const std::complex< double > &value)
Sets component j to value.
std::complex< double > dot(const double *row, std::size_t from, std::size_t to) const
Σ_{l = from…to} row[l] x[l].
buffer< double > re
The real parts.
std::complex< double > scalar
Its components.
The rotation standardize_block found, and the eigenvalues of the block it standardised.
double re2
The second's real part.
double re1
The first eigenvalue's real part.
double im1
Its imaginary part (positive for a complex pair).
double im2
Its imaginary part (−im1).