1#ifndef LAMBDA_LANCZOS_TRIDIAGONAL_IMPL_H_
2#define LAMBDA_LANCZOS_TRIDIAGONAL_IMPL_H_
26 size_t m = alpha.size();
32 for (
size_t i = 1; i < m; ++i) {
33 q_i = alpha[i] - c - beta[i - 1] * beta[i - 1] / q_i;
38 q_i = std::numeric_limits<T>::epsilon();
64inline T
find_mth_eigenvalue(
const std::vector<T>& alpha,
const std::vector<T>& beta,
const size_t m) {
66 T pmid = std::numeric_limits<T>::max();
71 while (upper - lower > std::min(std::abs(lower), std::abs(upper)) * std::numeric_limits<T>::epsilon()) {
72 mid = (lower + upper) * T(0.5);
95 const std::vector<T>& beta,
100 const auto m = alpha.size();
101 std::vector<T> cv(m);
106 cv[m - 2] = (ev - alpha[m - 1]) * cv[m - 1] / beta[m - 2];
107 for (
size_t k = m - 2; k-- > 0;) {
108 cv[k] = ((ev - alpha[k + 1]) * cv[k + 1] - beta[k + 1] * cv[k + 2]) / beta[k];
122 const std::vector<T>& beta,
123 std::vector<T>& eigenvalues,
124 std::vector<std::vector<T>>& eigenvectors) {
125 const size_t n = alpha.size();
126 eigenvalues.resize(n);
127 eigenvectors.resize(n);
129 for (
size_t j = 0; j < n; ++j) {
132 alpha, beta, j, eigenvalues[j]);
154 return std::make_pair(1.0, 0.0);
158 return std::make_pair(0.0, 1.0);
161 T x = std::sqrt(a * a + b * b);
165 return std::make_pair(c, s);
183 std::vector<T>& beta,
184 std::vector<std::vector<T>>& q,
187 bool rotate_matrix) {
196 T d = (alpha[offset + nsub - 2] - alpha[offset + nsub - 1]) / (2 * beta[offset + nsub - 2]);
197 T mu = alpha[offset + nsub - 1] - beta[offset + nsub - 2] / (d + sgn(d) * sqrt(d * d + T(1)));
198 T x = alpha[offset + 0] - mu;
204 for (
size_t k = 0; k < nsub - 1; ++k) {
205 T z = s * beta[offset + k];
206 T beta_prev = c * beta[offset + k];
213 beta[offset + k - 1] = sqrt(x * x + z * z);
215 T u = ((alpha[offset + k + 1] - alpha[offset + k] + p) * s + T(2) * c * beta_prev);
216 alpha[offset + k] = alpha[offset + k] - p + s * u;
218 x = c * u - beta_prev;
224 for (
size_t j = 0; j < alpha.size(); ++j) {
225 auto v0 = q[offset + k][j];
226 auto v1 = q[offset + k + 1][j];
228 q[offset + k][j] = c * v0 + s * v1;
229 q[offset + k + 1][j] = -s * v0 + c * v1;
234 alpha[offset + nsub - 1] = alpha[offset + nsub - 1] - p;
235 beta[offset + nsub - 2] = x;
254 std::vector<T>& beta,
255 size_t& submatrix_first,
256 size_t& submatrix_last) {
257 const T eps = std::numeric_limits<T>::epsilon() * 0.5;
258 const T safe_min = std::numeric_limits<T>::min();
259 const size_t n = alpha.size();
262 for (
size_t i = 0; i < n - 1; ++i) {
263 if (std::abs(beta[i]) < std::sqrt(std::abs(alpha[i]) * std::abs(alpha[i + 1])) * eps + safe_min) {
269 while (submatrix_last > 0 && beta[submatrix_last - 1] == 0) {
272 submatrix_first = submatrix_last;
273 while (submatrix_first > 0 && beta[submatrix_first - 1] != 0) {
292 const std::vector<T>& beta,
293 std::vector<T>& eigenvalues,
294 std::vector<std::vector<T>>& eigenvectors,
295 bool compute_eigenvector =
true) {
296 const size_t n = alpha.size();
298 auto alpha_work = alpha;
299 auto beta_work = beta;
302 if (compute_eigenvector) {
306 size_t unconverged_count = 0;
307 size_t submatrix_last_prev = n - 1;
309 size_t loop_count = 1;
311 size_t submatrix_last = submatrix_last_prev;
312 size_t submatrix_first;
313 find_subspace(alpha_work, beta_work, submatrix_first, submatrix_last);
315 const size_t nsub = submatrix_last - submatrix_first + 1;
316 const size_t max_loop_count = nsub * 50;
318 if (submatrix_last > 0) {
319 isqr_step(alpha_work, beta_work, eigenvectors, submatrix_first, nsub, compute_eigenvector);
324 if (submatrix_last == submatrix_last_prev) {
325 if (loop_count > max_loop_count) {
326 submatrix_last_prev = submatrix_first;
334 submatrix_last_prev = submatrix_last;
338 eigenvalues = alpha_work;
342 return unconverged_count;
357 const std::vector<T>& beta,
358 std::vector<T>& eigenvalues) {
359 std::vector<std::vector<T>> dummy_eigenvectors;
Definition lambda_lanczos_tridiagonal_impl.hpp:14
size_t num_of_eigs_smaller_than(T c, const std::vector< T > &alpha, const std::vector< T > &beta)
Finds the number of eigenvalues of given tridiagonal matrix smaller than c.
Definition lambda_lanczos_tridiagonal_impl.hpp:23
size_t tridiagonal_eigenvalues(const std::vector< T > &alpha, const std::vector< T > &beta, std::vector< T > &eigenvalues)
Computes all eigenvalues for given tri-diagonal matrix using the Implicitly Shifted QR algorithm.
Definition lambda_lanczos_tridiagonal_impl.hpp:356
T find_mth_eigenvalue(const std::vector< T > &alpha, const std::vector< T > &beta, const size_t m)
Finds the mth smaller eigenvalue of given tridiagonal matrix.
Definition lambda_lanczos_tridiagonal_impl.hpp:64
void find_subspace(const std::vector< T > &alpha, std::vector< T > &beta, size_t &submatrix_first, size_t &submatrix_last)
Find sub-tridiagonal matrix that remains non-diagonal.
Definition lambda_lanczos_tridiagonal_impl.hpp:253
void tridiagonal_eigenpairs_bisection(const std::vector< T > &alpha, const std::vector< T > &beta, std::vector< T > &eigenvalues, std::vector< std::vector< T > > &eigenvectors)
Computes all eigenpairs (eigenvalues and eigenvectors) for given tri-diagonal matrix.
Definition lambda_lanczos_tridiagonal_impl.hpp:121
std::vector< T > compute_tridiagonal_eigenvector_from_eigenvalue(const std::vector< T > &alpha, const std::vector< T > &beta, const size_t index, const T ev)
Computes an eigenvector corresponding to given eigenvalue for given tri-diagonal matrix.
Definition lambda_lanczos_tridiagonal_impl.hpp:94
T tridiagonal_eigen_limit(const std::vector< T > &alpha, const std::vector< T > &beta)
Computes the upper bound of the absolute value of eigenvalues by Gerschgorin theorem.
Definition lambda_lanczos_tridiagonal_impl.hpp:53
void isqr_step(std::vector< T > &alpha, std::vector< T > &beta, std::vector< std::vector< T > > &q, size_t offset, size_t nsub, bool rotate_matrix)
Performs an implicit shift QR step A = Z^T A Z on given sub tridiagonal matrix A.
Definition lambda_lanczos_tridiagonal_impl.hpp:182
size_t tridiagonal_eigenpairs(const std::vector< T > &alpha, const std::vector< T > &beta, std::vector< T > &eigenvalues, std::vector< std::vector< T > > &eigenvectors, bool compute_eigenvector=true)
Computes all eigenpairs (eigenvalues and eigenvectors) for given tri-diagonal matrix using the Implic...
Definition lambda_lanczos_tridiagonal_impl.hpp:291
std::pair< T, T > calc_givens_cs(T a, T b)
Calculates the cosine and sine of Givens rotation that eliminates a specific element (see detail).
Definition lambda_lanczos_tridiagonal_impl.hpp:152
void normalize(std::vector< T > &vec)
Normalizes given vector.
Definition linear_algebra.hpp:78
void sort_eigenpairs(std::vector< real_t< T > > &eigenvalues, std::vector< std::vector< T > > &eigenvectors, bool sort_eigenvector, const std::function< bool(real_t< T >, real_t< T >)> predicate=std::less< real_t< T > >())
Sorts eigenvalues and eigenvectors with respect to given predicate.
Definition common.hpp:142
T sgn(T val)
Return the sign of given value.
Definition common.hpp:195
real_t< T > m_norm(const std::vector< T > &vec)
Returns Manhattan-like norm of given vector.
Definition linear_algebra.hpp:123
void initAsIdentity(std::vector< std::vector< T > > &a, size_t n)
Initializes the given matrix a to an n by n identity matrix.
Definition linear_algebra.hpp:150
Definition eigenpair_manager.hpp:9