numerics 0.1.0
Loading...
Searching...
No Matches
jacobi_eig.cpp
Go to the documentation of this file.
1/// @file linalg/eigen/backends/seq/jacobi_eig.cpp
2/// @brief Sequential cyclic Jacobi eigensolver.
3///
4/// Uses \f$t=\operatorname{sign}(\tau)/(|\tau|+\sqrt{1+\tau^2})\f$ with
5/// \f$\tau=(a_{qq}-a_{pp})/(2a_{pq})\f$.
6#include "impl.hpp"
7#include <algorithm>
8#include <cmath>
9#include <stdexcept>
10
11namespace num::backends::seq {
12
13EigenResult eig_sym(const Matrix& A_in, real tol, idx max_sweeps) {
14 if (A_in.rows() != A_in.cols())
15 throw std::invalid_argument("eig_sym: matrix must be square");
16
17 constexpr real rotation_tol = 1e-15;
18 idx n = A_in.rows();
19 Matrix A = A_in;
20 Matrix V(n, n, 0.0);
21 for (idx i = 0; i < n; ++i)
22 V(i, i) = 1.0;
23
24 idx sweeps = 0;
25 bool converged = false;
26
27 for (idx sweep = 0; sweep < max_sweeps; ++sweep) {
28 real off = 0;
29 for (idx p = 0; p < n; ++p)
30 for (idx q = p + 1; q < n; ++q)
31 off += A(p, q) * A(p, q);
32
33 if (std::sqrt(2.0 * off) < tol) {
34 converged = true;
35 break;
36 }
37
38 for (idx p = 0; p < n - 1; ++p) {
39 for (idx q = p + 1; q < n; ++q) {
40 real apq = A(p, q);
41 if (std::abs(apq) < rotation_tol)
42 continue;
43
44 real app = A(p, p), aqq = A(q, q);
45 real tau = (aqq - app) / (2.0 * apq);
46 real t = std::copysign(1.0, tau)
47 / (std::abs(tau) + std::sqrt(1.0 + tau * tau));
48 real c = 1.0 / std::sqrt(1.0 + t * t);
49 real s = c * t;
50
51 A(p, p) = c * c * app - 2.0 * c * s * apq + s * s * aqq;
52 A(q, q) = s * s * app + 2.0 * c * s * apq + c * c * aqq;
53 A(p, q) = A(q, p) = 0.0;
54
55 for (idx r = 0; r < n; ++r) {
56 if (r == p || r == q)
57 continue;
58 real arp = A(r, p), arq = A(r, q);
59 A(r, p) = A(p, r) = c * arp - s * arq;
60 A(r, q) = A(q, r) = s * arp + c * arq;
61 }
62
63 for (idx r = 0; r < n; ++r) {
64 real vrp = V(r, p), vrq = V(r, q);
65 V(r, p) = c * vrp - s * vrq;
66 V(r, q) = s * vrp + c * vrq;
67 }
68 }
69 }
70 ++sweeps;
71 }
72
73 Vector values(n);
74 for (idx i = 0; i < n; ++i)
75 values[i] = A(i, i);
76
77 for (idx i = 0; i < n - 1; ++i) {
78 idx min_j = i;
79 for (idx j = i + 1; j < n; ++j)
80 if (values[j] < values[min_j])
81 min_j = j;
82 if (min_j != i) {
83 std::swap(values[i], values[min_j]);
84 for (idx r = 0; r < n; ++r)
85 std::swap(V(r, i), V(r, min_j));
86 }
87 }
88
89 return {values, V, sweeps, converged};
90}
91
92} // namespace num::backends::seq
constexpr idx rows() const noexcept
Definition matrix.hpp:87
constexpr idx cols() const noexcept
Definition matrix.hpp:88
EigenResult eig_sym(const Matrix &A, real tol, idx max_sweeps)
double real
Definition types.hpp:10
std::size_t idx
Definition types.hpp:11
constexpr real e
Definition math.hpp:44
std::experimental::simd butterfly for FFT.
Symmetric eigendecomposition .