19 throw std::invalid_argument(
"eig_sym: matrix must be square");
21 constexpr real rotation_tol = 1
e-15;
25 for (
idx i = 0; i < n; ++i)
29 bool converged =
false;
31 for (
idx sweep = 0; sweep < max_sweeps; ++sweep) {
33 for (
idx p = 0; p < n; ++p)
34 for (
idx q = p + 1; q < n; ++q)
35 off += A(p, q) * A(p, q);
37 if (std::sqrt(2.0 * off) < tol) {
42 for (
idx p = 0; p < n - 1; ++p) {
43 for (
idx q = p + 1; q < n; ++q) {
45 if (std::abs(apq) < rotation_tol)
48 real app = A(p, p), aqq = A(q, q);
49 real tau = (aqq - app) / (2.0 * apq);
50 real t = std::copysign(1.0, tau)
51 / (std::abs(tau) + std::sqrt(1.0 + tau * tau));
52 real c = 1.0 / std::sqrt(1.0 + t * t);
55 A(p, p) = c * c * app - 2.0 * c * s * apq + s * s * aqq;
56 A(q, q) = s * s * app + 2.0 * c * s * apq + c * c * aqq;
57 A(p, q) = A(q, p) = 0.0;
59#ifdef NUMERICS_HAS_OMP
60 #pragma omp parallel for schedule(static) if (n >= 128)
62 for (
idx r = 0; r < n; ++r) {
65 real arp = A(r, p), arq = A(r, q);
66 A(r, p) = A(p, r) = c * arp - s * arq;
67 A(r, q) = A(q, r) = s * arp + c * arq;
70#ifdef NUMERICS_HAS_OMP
72 #pragma omp parallel for schedule(static) if (n >= 128)
74 for (
idx r = 0; r < n; ++r) {
75 real vrp = V(r, p), vrq = V(r, q);
76 V(r, p) = c * vrp - s * vrq;
77 V(r, q) = s * vrp + c * vrq;
85 for (
idx i = 0; i < n; ++i)
88 for (
idx i = 0; i < n - 1; ++i) {
90 for (
idx j = i + 1; j < n; ++j)
91 if (values[j] < values[min_j])
94 std::swap(values[i], values[min_j]);
95 for (
idx r = 0; r < n; ++r)
96 std::swap(V(r, i), V(r, min_j));
100 return {values, V, sweeps, converged};