1#ifndef LINEARALGEBRA_SRC_MOLPRO_LINALG_ITERATIVESOLVER_HELPER_IMPLEMENTATION_H_
2#define LINEARALGEBRA_SRC_MOLPRO_LINALG_ITERATIVESOLVER_HELPER_IMPLEMENTATION_H_
5#include <molpro/Profiler.h>
6#include <molpro/lapacke.h>
7#include <molpro/linalg/itsolv/helper-dispatch.h>
8#include <molpro/linalg/itsolv/helper.h>
11#include "subspace/Matrix.h"
26template <
typename value_type>
28 real_type_t<value_type> threshold) {
29 auto mat = Eigen::Map<const Eigen::Matrix<value_type, Eigen::Dynamic, Eigen::Dynamic>>(m.
data(), nrows, ncols);
30#if EIGEN_VERSION_AT_LEAST(3, 4, 90)
33 auto svd = Eigen::JacobiSVD<Eigen::Matrix<value_type, Eigen::Dynamic, Eigen::Dynamic>>(
34 mat,
static_cast<unsigned int>(Eigen::ComputeThinV) |
35 static_cast<unsigned int>(Eigen::NoQRPreconditioner));
37 auto svd = Eigen::JacobiSVD<Eigen::Matrix<value_type, Eigen::Dynamic, Eigen::Dynamic>, Eigen::NoQRPreconditioner>(
38 mat, Eigen::ComputeThinV);
40 auto svd_system = std::list<SVD<value_type>>{};
41 auto sv = svd.singularValues();
42 for (
int i =
int(ncols) - 1; i >= 0; --i) {
43 if (std::abs(sv(i)) < threshold) {
47 for (
size_t j = 0; j < ncols; ++j) {
48 t.v.emplace_back(svd.matrixV()(j, i));
56template <
typename value_type>
58 real_type_t<value_type> threshold) {
59 auto mat = Eigen::Map<const Eigen::Matrix<value_type, Eigen::Dynamic, Eigen::Dynamic>>(m.
data(), nrows, ncols);
60 auto svd = Eigen::BDCSVD<Eigen::Matrix<value_type, Eigen::Dynamic, Eigen::Dynamic>>(mat, Eigen::ComputeThinV);
61 auto svd_system = std::list<SVD<value_type>>{};
62 auto sv = svd.singularValues();
63 for (
int i =
int(ncols) - 1; i >= 0; --i) {
64 if (std::abs(sv(i)) < threshold) {
68 for (
size_t j = 0; j < ncols; ++j) {
69 t.v.emplace_back(svd.matrixV()(j, i));
84template <
typename value_type>
87 static_assert(has_lapack_kernel_v<value_type>,
"LAPACK has no ?gesdd kernel for this scalar type");
88 const size_t sdim = std::min(nrows, ncols);
90 std::vector<value_type> a(mat.
begin(), mat.
end());
91 std::vector<real_type_t<value_type>> sv(sdim);
92 std::vector<value_type> u(nrows * nrows), v(ncols * ncols);
94 lapack::gesdd(LAPACK_ROW_MAJOR,
'A', lapack_int(nrows), lapack_int(ncols), a.data(), lapack_int(ncols), sv.data(),
95 u.data(), lapack_int(nrows), v.data(), lapack_int(ncols));
97 throw std::runtime_error(
"?gesdd (singular value decomposition) failed with info = " + std::to_string(info));
98 auto svd_system = std::list<SVD<value_type>>{};
99 for (
int i =
int(ncols) - 1; i >= 0; --i) {
100 if (std::abs(sv[i]) < threshold) {
101 auto t = SVD<value_type>{};
104 for (
size_t j = 0; j < ncols; ++j) {
105 t.v.emplace_back(v[i * ncols + j]);
114template <
typename value_type>
115std::list<SVD<value_type>> svd_lapacke_gesvd(
size_t nrows,
size_t ncols,
const array::Span<value_type>& mat,
116 real_type_t<value_type> threshold) {
117 static_assert(has_lapack_kernel_v<value_type>,
"LAPACK has no ?gesvd kernel for this scalar type");
118 const size_t sdim = std::min(nrows, ncols);
120 std::vector<value_type> a(mat.begin(), mat.end());
121 std::vector<real_type_t<value_type>> sv(sdim);
122 std::vector<value_type> u(nrows * nrows), v(ncols * ncols);
123 std::vector<real_type_t<value_type>> superb(sdim > 0 ? sdim - 1 : 0);
124 const auto info = lapack::gesvd(LAPACK_ROW_MAJOR,
'N',
'A', lapack_int(nrows), lapack_int(ncols), a.data(),
125 lapack_int(ncols), sv.data(), u.data(), lapack_int(nrows), v.data(),
126 lapack_int(ncols), superb.data());
128 throw std::runtime_error(
"?gesvd (singular value decomposition) failed with info = " + std::to_string(info));
129 auto svd_system = std::list<SVD<value_type>>{};
130 for (
int i =
int(ncols) - 1; i >= 0; --i) {
131 if (std::abs(sv[i]) < threshold) {
132 auto t = SVD<value_type>{};
135 for (
size_t j = 0; j < ncols; ++j) {
136 t.v.emplace_back(v[i * ncols + j]);
154 std::span<double> eigenvalues,
const size_t dimension) {
155 return eigensolver_hermitian<double>(matrix, eigenvectors, eigenvalues, dimension);
160 return eigensolver_hermitian<double>(dimension, matrix);
170template <
typename value_type>
171size_t get_rank(std::span<const value_type> eigenvalues, value_type threshold) {
172 if (eigenvalues.size() == 0) {
175 value_type max = *max_element(eigenvalues.begin(), eigenvalues.end());
176 value_type threshold_scaled = threshold * max;
178 std::count_if(eigenvalues.begin(), eigenvalues.end(), [&](
auto const& val) { return val >= threshold_scaled; });
189template <
typename value_type>
192 real_type_t<value_type> max_value = 0;
193 typename std::list<SVD<value_type>>::iterator it;
200 const real_type_t<value_type> threshold_scaled = threshold * max_value;
205 if (
real_part(it->value) > threshold_scaled) {
221template <
typename value_type>
223 real_type_t<value_type> threshold,
bool hermitian,
bool reduce_to_rank) {
224 std::list<SVD<value_type>> svds;
225 assert(m.
size() == nrows * ncols);
229 assert(nrows == ncols);
232 using matrix_type = Eigen::Matrix<value_type, Eigen::Dynamic, Eigen::Dynamic, Eigen::ColMajor>;
233 using row_major_type = Eigen::Matrix<value_type, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor>;
234 const matrix_type a = Eigen::Map<const row_major_type>(m.
data(), nrows, ncols);
235 svds = eigensolver_hermitian<value_type>(nrows, std::span<const value_type>{a.data(),
size_t(a.size())});
236 for (
auto s = svds.begin(); s != svds.end();)
245 svds = svd_eigen_jacobi<value_type>(nrows, ncols, m, threshold);
250 if (reduce_to_rank) {
251 int rank =
get_rank(svds, threshold);
252 for (
int i = ncols; i > rank; i--) {
261template <
typename value_type,
typename std::enable_if_t<!is_complex<value_type>{}, std::
nullptr_t>>
263 real_type_t<value_type> threshold,
bool hermitian,
bool reduce_to_rank) {
264 return detail::svd_system_impl<value_type>(nrows, ncols, m, threshold, hermitian, reduce_to_rank);
267template <
typename value_type,
typename std::enable_if_t<is_complex<value_type>{},
int>>
270 return detail::svd_system_impl<value_type>(nrows, ncols, m, threshold, hermitian, reduce_to_rank);
273template <
typename value_type>
274void printMatrix(
const std::vector<value_type>& m,
size_t rows,
size_t cols, std::string title, std::ostream& s) {
276 << Eigen::Map<const Eigen::Matrix<value_type, Eigen::Dynamic, Eigen::Dynamic>>(m.data(), rows, cols) << std::endl;
287template <
typename real_type>
289 bool operator()(
const std::complex<real_type>& lhs,
const std::complex<real_type>& rhs)
const {
291 if (lhs.real() != rhs.real()) {
292 return lhs.real() < rhs.real();
294 if (abs(lhs.imag()) != abs(rhs.imag())) {
296 return abs(lhs.imag()) < abs(rhs.imag());
299 return lhs.imag() < rhs.imag();
304template <
typename value_type>
306 using matrix_type = Eigen::Matrix<value_type, Eigen::Dynamic, Eigen::Dynamic, Eigen::ColMajor>;
324template <
typename value_type>
326 const std::vector<value_type>& metric,
size_t dimension,
327 real_type_t<value_type> svdThreshold,
int verbosity) {
330 using real_t = real_type_t<value_type>;
332 using row_major_type = Eigen::Matrix<value_type, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor>;
334 const real_t null_metric_eigenvalue_tol = precision_scaled<value_type>(1e-14);
337 const matrix_type H = Eigen::Map<const row_major_type>(matrix.data(), dimension, dimension);
338 result.
S = Eigen::Map<const row_major_type>(metric.data(), dimension, dimension);
343 Eigen::Vector<real_t, Eigen::Dynamic> metricEvals(dimension);
344 matrix_type metricEvecs(dimension, dimension);
345 const int success = eigensolver_hermitian<value_type>(
346 std::span<const value_type>{result.
S.data(),
size_t(result.
S.size())},
347 {metricEvecs.data(), dimension * dimension}, {metricEvals.data(), dimension}, dimension);
349 throw std::runtime_error(
"Eigensolver did not converge");
351 result.
rank = int(get_rank<real_t>(std::span<const real_t>{metricEvals.data(), dimension}, svdThreshold));
352 const int rank = result.
rank;
354 if (verbosity > 1 && rank <
int(dimension))
355 molpro::cout <<
"SVD rank " << rank <<
" in subspace of dimension " << dimension << std::endl;
356 if (verbosity > 2 && rank <
int(dimension))
357 molpro::cout <<
"singular values " << metricEvals.transpose() << std::endl;
362 Eigen::Vector<value_type, Eigen::Dynamic> svmh(rank);
363 for (
int k = 0; k < rank; k++) {
364 const real_t lambda = metricEvals(dimension - rank + k);
365 assert(abs(lambda) <= svdThreshold || lambda >= 0);
366 svmh(k) = lambda > null_metric_eigenvalue_tol ? value_type(1 / sqrt(lambda)) : value_type(0);
368 const auto retained = metricEvecs.rightCols(rank);
369 result.
Hbar = svmh.asDiagonal() * retained.adjoint() * H * retained * svmh.asDiagonal();
376template <
typename value_type,
typename std::enable_if_t<is_complex<value_type>{},
int>>
377void eigenproblem(std::vector<value_type>& eigenvectors, std::vector<value_type>& eigenvalues,
378 const std::vector<value_type>& matrix,
const std::vector<value_type>& metric,
size_t dimension,
379 bool hermitian, real_type_t<value_type> svdThreshold,
int verbosity,
380 std::vector<std::pair<std::size_t, value_type>>* imag_eval_parts) {
383 using real_t = real_type_t<value_type>;
384 using matrix_type = Eigen::Matrix<value_type, Eigen::Dynamic, Eigen::Dynamic, Eigen::ColMajor>;
385 using vector_type = Eigen::Vector<value_type, Eigen::Dynamic>;
389 imag_eval_parts->clear();
390 const real_t null_eigenvalue_tol = precision_scaled<value_type>(1e-12);
393 prof->start(
"itsolv::eigenproblem");
394 const auto subspace = detail::orthogonalise_subspace<value_type>(matrix, metric, dimension, svdThreshold, verbosity);
395 const int rank = subspace.rank;
396 eigenvectors.resize(dimension * rank);
397 eigenvalues.resize(rank);
405 Eigen::ComplexEigenSolver<matrix_type> s(subspace.Hbar);
406 if (s.info() != Eigen::Success) {
407 throw std::runtime_error(
"Eigensolver of the subspace matrix did not converge");
409 vector_type subspaceEigenvalues = s.eigenvalues();
411 matrix_type subspaceEigenvectors = subspace.transformation * s.eigenvectors();
415 Eigen::PermutationMatrix<Eigen::Dynamic, Eigen::Dynamic> perm(subspaceEigenvalues.size());
418 [&subspaceEigenvalues](
auto idx) { return subspaceEigenvalues[idx]; });
419 subspaceEigenvectors = subspaceEigenvectors * perm;
420 subspaceEigenvalues = perm.transpose() * subspaceEigenvalues;
425 for (Eigen::Index k = 0; k < subspaceEigenvectors.cols(); k++) {
426 const auto ovl = subspaceEigenvectors.col(k).dot(subspace.S * subspaceEigenvectors.col(k));
428 assert(abs(ovl.imag()) < precision_scaled<value_type>(1e-10));
429 if (ovl.real() > null_eigenvalue_tol)
430 subspaceEigenvectors.col(k) /= value_type(sqrt(ovl.real()));
435 for (Eigen::Index i = 0; i < subspaceEigenvectors.cols(); ++i) {
436 Eigen::Index pivot = 0;
437 for (Eigen::Index j = 1; j < subspaceEigenvectors.rows(); ++j)
438 if (abs(subspaceEigenvectors(j, i)) > abs(subspaceEigenvectors(pivot, i)))
440 const real_t magnitude = abs(subspaceEigenvectors(pivot, i));
442 subspaceEigenvectors.col(i) *=
conjugate(subspaceEigenvectors(pivot, i)) / value_type(magnitude);
445 Eigen::Map<matrix_type>(eigenvectors.data(), dimension, rank) = subspaceEigenvectors;
446 Eigen::Map<vector_type>(eigenvalues.data(), rank) = subspaceEigenvalues;
450template <
typename value_type,
typename std::enable_if_t<!is_complex<value_type>{}, std::
nullptr_t>>
451void eigenproblem(std::vector<value_type>& eigenvectors, std::vector<value_type>& eigenvalues,
452 const std::vector<value_type>& matrix,
const std::vector<value_type>& metric,
size_t dimension,
454 std::vector<std::pair<std::size_t, value_type>>* imag_eval_parts) {
459 const value_type zero_tol = precision_scaled<value_type>(1e-10);
460 const value_type null_eigenvalue_tol = precision_scaled<value_type>(1e-12);
461 using MatrixT = Eigen::Matrix<value_type, Eigen::Dynamic, Eigen::Dynamic, Eigen::ColMajor>;
462 using ComplexMatrixT = Eigen::Matrix<std::complex<value_type>, Eigen::Dynamic, Eigen::Dynamic, Eigen::ColMajor>;
463 using VectorT = Eigen::Vector<value_type, Eigen::Dynamic>;
464 using ComplexVectorT = Eigen::Vector<std::complex<value_type>, Eigen::Dynamic>;
467 prof->start(
"itsolv::eigenproblem");
468 const auto subspace = detail::orthogonalise_subspace<value_type>(matrix, metric, dimension, svdThreshold, verbosity);
469 const int rank = subspace.rank;
470 const auto& S = subspace.S;
471 const auto& Hbar = subspace.Hbar;
472 ComplexMatrixT subspaceEigenvectors;
473 ComplexVectorT subspaceEigenvalues;
475 eigenvectors.clear();
482 Eigen::EigenSolver<MatrixT> s(Hbar);
483 subspaceEigenvalues = s.eigenvalues();
484 if (s.eigenvalues().imag().norm() < zero_tol) {
486 subspaceEigenvalues = subspaceEigenvalues.real();
487 subspaceEigenvectors = s.eigenvectors();
490 for (
int i = 0; i < subspaceEigenvectors.cols() - 1; i++) {
491 if (subspaceEigenvectors.col(i).imag().norm() <= zero_tol) {
496 if (abs(subspaceEigenvalues(i) - subspaceEigenvalues(j)) >= zero_tol or
497 subspaceEigenvectors.col(j).imag().norm() <= zero_tol) {
505 subspaceEigenvectors.col(j) = subspaceEigenvectors.col(i).imag() / subspaceEigenvectors.col(i).imag().norm();
506 subspaceEigenvectors.col(i) = subspaceEigenvectors.col(i).real() / subspaceEigenvectors.col(i).real().norm();
510 subspaceEigenvectors = subspace.transformation * subspaceEigenvectors;
513#ifdef __INTEL_COMPILER
514 molpro::cout <<
"Hbar\n" << Hbar << std::endl;
515 molpro::cout <<
"Eigenvalues\n" << s.eigenvalues() << std::endl;
516 molpro::cout <<
"Eigenvectors\n" << s.eigenvectors() << std::endl;
517 throw std::runtime_error(
"Intel compiler does not support working with complex eigen3 entities properly");
521 subspaceEigenvectors = subspace.transformation * s.eigenvectors();
526 Eigen::PermutationMatrix<Eigen::Dynamic, Eigen::Dynamic> perm(subspaceEigenvalues.size());
528 std::ranges::sort(perm.indices(), detail::eigenvalue_order<real_type_t<value_type>>{},
529 [&subspaceEigenvalues](
auto idx) { return subspaceEigenvalues[idx]; });
532 subspaceEigenvectors = subspaceEigenvectors * perm;
533 subspaceEigenvalues = perm.transpose() * subspaceEigenvalues;
540 for (
auto repeat = 0; repeat < 1; ++repeat)
541 for (Eigen::Index k = 0; k < subspaceEigenvectors.cols(); k++) {
542 if (abs(subspaceEigenvalues(k)) < null_eigenvalue_tol) {
544 subspaceEigenvectors.col(k).real() += value_type(0.3256897) * subspaceEigenvectors.col(k).imag();
545 subspaceEigenvectors.col(k).imag().setZero();
548 auto ovl = subspaceEigenvectors.col(k).dot(S * subspaceEigenvectors.col(k));
550 assert(abs(ovl.imag()) < zero_tol);
551 assert(ovl.real() > 0);
552 subspaceEigenvectors.col(k) /= sqrt(ovl.real());
557 for (std::size_t i = 0; i < subspaceEigenvectors.cols(); ++i) {
558 const auto &col = subspaceEigenvectors.col(i);
559 auto it = std::ranges::max_element(col, std::less<>{}, [](
auto val) {
return abs(val); });
560 auto idx = std::distance(col.begin(), it);
561 if (subspaceEigenvectors.col(i)[idx].real() < 0) {
562 subspaceEigenvectors.col(i) *= -1;
566 if (imag_eval_parts) {
569 imag_eval_parts->clear();
571 for (Eigen::Index root = 0; root < Hbar.cols(); ++root) {
572 if (subspaceEigenvalues(root).imag() == 0) {
577 assert(root + 1 < subspaceEigenvalues.size());
578 assert(abs(std::conj(subspaceEigenvalues(root)) - subspaceEigenvalues(root + 1)) < zero_tol);
580 imag_eval_parts->emplace_back(root, subspaceEigenvalues(root).imag());
581 imag_eval_parts->emplace_back(root + 1, -subspaceEigenvalues(root).imag());
584 subspaceEigenvalues(root) = subspaceEigenvalues(root + 1) = subspaceEigenvalues(root).real();
592 subspaceEigenvectors.col(root + 1) = subspaceEigenvectors.col(root).imag();
593 subspaceEigenvectors.col(root) = subspaceEigenvectors.col(root).real();
600 if ((subspaceEigenvectors - subspaceEigenvectors.real()).norm() > zero_tol or
601 (subspaceEigenvalues - subspaceEigenvalues.real()).norm() > zero_tol) {
602 throw std::runtime_error(
"unexpected complex solution found");
605 eigenvectors.resize(dimension * Hbar.cols());
606 eigenvalues.resize(Hbar.cols());
608 Eigen::Map<MatrixT>(eigenvectors.data(), dimension, Hbar.cols()) =
609 subspaceEigenvectors.real();
610 Eigen::Map<VectorT> ev(eigenvalues.data(), Hbar.cols());
611 ev = subspaceEigenvalues.real();
624template <
typename value_type>
626 const std::vector<value_type>& matrix,
const std::vector<value_type>& metric,
627 const std::vector<value_type>& rhs,
const size_t dimension,
size_t nroot,
628 real_type_t<value_type> augmented_hessian, real_type_t<value_type> svdThreshold,
630 const Eigen::Index nX = dimension;
631 solution.resize(nX * nroot);
633 if (augmented_hessian > 0) {
634 Eigen::Matrix<value_type, Eigen::Dynamic, Eigen::Dynamic> subspaceMatrix;
635 Eigen::Matrix<value_type, Eigen::Dynamic, Eigen::Dynamic> subspaceOverlap;
636 subspaceMatrix.conservativeResize(nX + 1, nX + 1);
637 subspaceOverlap.conservativeResize(nX + 1, nX + 1);
640 using row_major_type = Eigen::Matrix<value_type, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor>;
641 subspaceMatrix.block(0, 0, nX, nX) = Eigen::Map<const row_major_type>(matrix.data(), nX, nX);
642 subspaceOverlap.block(0, 0, nX, nX) = Eigen::Map<const row_major_type>(metric.data(), nX, nX);
643 eigenvalues.resize(nroot);
644 for (
size_t root = 0; root < nroot; root++) {
645 for (Eigen::Index i = 0; i < nX; i++) {
647 subspaceMatrix(i, nX) = -augmented_hessian * rhs[i * nroot + root];
649 subspaceMatrix(nX, i) =
conjugate(subspaceMatrix(i, nX));
650 subspaceOverlap(i, nX) = subspaceOverlap(nX, i) = 0;
652 subspaceMatrix(nX, nX) = 0;
653 subspaceOverlap(nX, nX) = 1;
660 using matrix_type = Eigen::Matrix<value_type, Eigen::Dynamic, Eigen::Dynamic, Eigen::ColMajor>;
661 std::vector<value_type> augmented_matrix(subspaceMatrix.size()), augmented_overlap(subspaceOverlap.size());
663 Eigen::Map<Eigen::Matrix<value_type, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor>>(
664 augmented_matrix.data(), nX + 1, nX + 1) = subspaceMatrix;
665 Eigen::Map<Eigen::Matrix<value_type, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor>>(
666 augmented_overlap.data(), nX + 1, nX + 1) = subspaceOverlap;
667 const auto augmented = detail::orthogonalise_subspace<value_type>(augmented_matrix, augmented_overlap,
668 nX + 1, svdThreshold, verbosity);
669 if (augmented.rank == 0)
670 throw std::runtime_error(
"augmented Hessian: the augmented overlap matrix has no non-singular direction");
671 Eigen::ComplexEigenSolver<matrix_type> s(augmented.Hbar);
672 if (s.info() != Eigen::Success)
673 throw std::runtime_error(
"augmented Hessian: eigensolver did not converge");
674 auto eval = s.eigenvalues();
675 Eigen::Index imax = 0;
676 for (Eigen::Index i = 0; i < eval.size(); i++)
677 if (eval(i).real() < eval(imax).real())
679 eigenvalues[root] = eval(imax);
680 const Eigen::Vector<value_type, Eigen::Dynamic> evec = augmented.transformation * s.eigenvectors().col(imax);
681 const value_type scale = value_type(augmented_hessian) * evec(nX);
682 for (Eigen::Index k = 0; k < nX; k++)
683 solution[k + nX * root] = evec(k) / scale;
685 Eigen::GeneralizedEigenSolver<Eigen::Matrix<value_type, Eigen::Dynamic, Eigen::Dynamic>> s(subspaceMatrix,
687 auto eval = s.eigenvalues();
688 auto evec = s.eigenvectors();
689 Eigen::Index imax = 0;
690 for (Eigen::Index i = 0; i < nX + 1; i++)
691 if (eval(i).real() < eval(imax).real())
693 eigenvalues[root] = eval(imax).real();
694 auto Solution = evec.col(imax).real().head(nX) / (augmented_hessian * evec.real()(nX, imax));
695 for (
auto k = 0; k < nX; k++)
696 solution[k + nX * root] = Solution(k);
701 Eigen::Map<const Eigen::Matrix<value_type, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor>> subspaceMatrixR(
702 matrix.data(), nX, nX);
703 Eigen::Map<const Eigen::Matrix<value_type, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor>> RHS_R(rhs.data(), nX,
705 Eigen::Matrix<value_type, Eigen::Dynamic, Eigen::Dynamic> subspaceMatrix = subspaceMatrixR;
706 Eigen::Matrix<value_type, Eigen::Dynamic, Eigen::Dynamic> RHS = RHS_R;
707 Eigen::Matrix<value_type, Eigen::Dynamic, Eigen::Dynamic> Solution;
716 Solution = subspaceMatrix.householderQr().solve(RHS);
718 for (
size_t root = 0; root < nroot; root++)
719 for (
auto k = 0; k < nX; k++)
720 solution[k + nX * root] = Solution(k, root);
726template <
typename value_type,
typename std::enable_if_t<is_complex<value_type>{},
int>>
728 const std::vector<value_type>& matrix,
const std::vector<value_type>& metric,
729 const std::vector<value_type>& rhs,
const size_t dimension,
size_t nroot,
730 real_type_t<value_type> augmented_hessian, real_type_t<value_type> svdThreshold,
732 detail::solve_LinearEquations_impl<value_type>(solution, eigenvalues, matrix, metric, rhs, dimension, nroot,
733 augmented_hessian, svdThreshold, verbosity);
736template <
typename value_type,
typename std::enable_if_t<!is_complex<value_type>{}, std::
nullptr_t>>
738 const std::vector<value_type>& matrix,
const std::vector<value_type>& metric,
739 const std::vector<value_type>& rhs,
const size_t dimension,
size_t nroot,
742 detail::solve_LinearEquations_impl<value_type>(solution, eigenvalues, matrix, metric, rhs, dimension, nroot,
743 augmented_hessian, svdThreshold, verbosity);
754template <
typename value_type>
755void solve_DIIS_impl(std::vector<value_type>& solution,
const std::vector<value_type>& matrix,
const size_t dimension,
756 real_type_t<value_type> svdThreshold,
int verbosity) {
760 using VectorT = Eigen::Vector<value_type, Eigen::Dynamic>;
761 using MatrixT = Eigen::Matrix<value_type, Eigen::Dynamic, Eigen::Dynamic>;
762 auto nAug = dimension + 1;
764 solution.resize(dimension);
766 VectorT Rhs(nAug), Coeffs(nAug);
767 MatrixT BAug(nAug, nAug);
771 Eigen::Map<const Eigen::Matrix<value_type, Eigen::Dynamic, Eigen::Dynamic>> subspaceMatrix(matrix.data(), dimension,
773 BAug.block(0, 0, dimension, dimension) = subspaceMatrix;
774 for (
size_t i = 0; i < dimension; ++i) {
775 BAug(dimension, i) = BAug(i, dimension) = -1;
778 BAug(dimension, dimension) = 0;
785 Eigen::JacobiSVD<MatrixT> svd(BAug, Eigen::ComputeThinU | Eigen::ComputeThinV);
789 svd.setThreshold(svdThreshold * svd.singularValues().maxCoeff() * 0);
794 Coeffs = svd.solve(Rhs).head(dimension);
798 molpro::cout <<
"Combination of iteration vectors: " << Coeffs.transpose() << std::endl;
799 for (
size_t k = 0; k < (size_t)Coeffs.rows(); k++) {
800 if (isnan(abs(Coeffs(k)))) {
801 molpro::cout <<
"B:" << std::endl << BAug << std::endl;
802 molpro::cout <<
"Rhs:" << std::endl << Rhs << std::endl;
803 molpro::cout <<
"Combination of iteration vectors: " << Coeffs.transpose() << std::endl;
804 throw std::overflow_error(
"NaN detected in DIIS submatrix solution");
806 solution[k] = Coeffs(k);
812template <
typename value_type,
typename std::enable_if_t<is_complex<value_type>{},
int>>
813void solve_DIIS(std::vector<value_type>& solution,
const std::vector<value_type>& matrix,
const size_t dimension,
814 real_type_t<value_type> svdThreshold,
int verbosity) {
815 detail::solve_DIIS_impl<value_type>(solution, matrix, dimension, svdThreshold, verbosity);
818template <
typename value_type,
typename std::enable_if_t<!is_complex<value_type>{}, std::
nullptr_t>>
819void solve_DIIS(std::vector<value_type>& solution,
const std::vector<value_type>& matrix,
const size_t dimension,
821 detail::solve_DIIS_impl<value_type>(solution, matrix, dimension, svdThreshold, verbosity);
842template <
typename value_type,
typename value_type_abs>
844 const value_type_abs svd_thresh,
Logger& logger) {
846 prof->start(
"itsolv::svd_system");
847 logger.
trace(
"redundant_parameters()");
848 auto redundant_params = std::vector<int>{};
849 auto rspace_indices = std::vector<int>(nR);
850 std::iota(std::begin(rspace_indices), std::end(rspace_indices), 0);
851 auto svd =
svd_system(overlap.rows(), overlap.cols(),
852 array::Span(
const_cast<value_type*
>(overlap.data().data()), overlap.size()), svd_thresh,
true);
854 prof->start(
"find redundant parameters");
855 for (
const auto& singular_system : svd) {
856 if (!rspace_indices.empty()) {
857 auto rspace_contribution = std::vector<value_type_abs>{};
858 for (
auto i : rspace_indices)
859 rspace_contribution.push_back(std::abs(singular_system.v.at(oR + i)));
860 auto it_min = std::max_element(std::begin(rspace_contribution), std::end(rspace_contribution));
861 auto imin = std::distance(std::begin(rspace_contribution), it_min);
862 redundant_params.push_back(rspace_indices[imin]);
863 rspace_indices.erase(std::begin(rspace_indices) + imin);
864 std::stringstream ss;
865 ss << std::setprecision(3) <<
"redundant parameter found, i = " << redundant_params.back()
866 <<
", svd.value = " << singular_system.value
867 <<
", svd.v[i] = " << singular_system.v[oR + redundant_params.back()];
868 logger.
info(ss.str());
872 return redundant_params;
Non-owning container taking a pointer to the data buffer and its size and exposing routines for itera...
Definition: Span.h:31
bool empty() const
Definition: Span.h:79
iterator begin()
Definition: Span.h:69
size_type size() const
Definition: Span.h:77
iterator end()
Definition: Span.h:73
iterator data()
Definition: Span.h:66
void info(std::string_view message, Ts &&...args) const
Definition: Logger.h:505
void trace(std::string_view message, Ts &&...args) const
Definition: Logger.h:495
static std::shared_ptr< Profiler > single()
Definition: helper-dispatch.h:140
void solve_DIIS_impl(std::vector< value_type > &solution, const std::vector< value_type > &matrix, const size_t dimension, real_type_t< value_type > svdThreshold, int verbosity)
Implementation of solve_DIIS(), shared by its real and complex overloads.
Definition: helper-implementation.h:755
std::list< SVD< value_type > > svd_system_impl(size_t nrows, size_t ncols, const array::Span< value_type > &m, real_type_t< value_type > threshold, bool hermitian, bool reduce_to_rank)
Implementation of svd_system(), shared by its real and complex overloads.
Definition: helper-implementation.h:222
void solve_LinearEquations_impl(std::vector< value_type > &solution, std::vector< value_type > &eigenvalues, const std::vector< value_type > &matrix, const std::vector< value_type > &metric, const std::vector< value_type > &rhs, const size_t dimension, size_t nroot, real_type_t< value_type > augmented_hessian, real_type_t< value_type > svdThreshold, int verbosity)
Implementation of solve_LinearEquations(), shared by its real and complex overloads.
Definition: helper-implementation.h:625
orthogonalised_subspace< value_type > orthogonalise_subspace(const std::vector< value_type > &matrix, const std::vector< value_type > &metric, size_t dimension, real_type_t< value_type > svdThreshold, int verbosity)
Reduce H C = S C E to the standard eigenproblem Hbar U = U E, whose solution is C = X U.
Definition: helper-implementation.h:325
auto redundant_parameters(const subspace::Matrix< value_type > &overlap, const size_t oR, const size_t nR, const value_type_abs svd_thresh, Logger &logger)
Deduces a set of parameters that are redundant due to linear dependencies.
Definition: helper-implementation.h:843
4-parameter interpolation of a 1-dimensional function given two points for which function values and ...
Definition: helper.h:14
void eigenproblem(std::vector< value_type > &eigenvectors, std::vector< value_type > &eigenvalues, const std::vector< value_type > &matrix, const std::vector< value_type > &metric, size_t dimension, bool hermitian, real_type_t< value_type > svdThreshold, int verbosity, std::vector< std::pair< std::size_t, value_type > > *imag_eval_parts=nullptr)
Definition: helper-implementation.h:377
std::list< SVD< value_type > > svd_eigen_bdcsvd(size_t nrows, size_t ncols, const array::Span< value_type > &m, real_type_t< value_type > threshold)
Definition: helper-implementation.h:57
void solve_LinearEquations(std::vector< value_type > &solution, std::vector< value_type > &eigenvalues, const std::vector< value_type > &matrix, const std::vector< value_type > &metric, const std::vector< value_type > &rhs, size_t dimension, size_t nroot, real_type_t< value_type > augmented_hessian, real_type_t< value_type > svdThreshold, int verbosity)
Definition: helper-implementation.h:727
int eigensolver_lapacke_dsyev(std::span< const double > matrix, std::span< double > eigenvectors, std::span< double > eigenvalues, const size_t dimension)
Eigen-decomposition of a real symmetric matrix in double precision.
Definition: helper-implementation.h:153
void solve_DIIS(std::vector< value_type > &solution, const std::vector< value_type > &matrix, size_t dimension, real_type_t< value_type > svdThreshold, int verbosity=0)
Definition: helper-implementation.h:813
std::list< SVD< value_type > > svd_eigen_jacobi(size_t nrows, size_t ncols, const array::Span< value_type > &m, real_type_t< value_type > threshold)
Definition: helper-implementation.h:27
std::list< SVD< value_type > > svd_system(size_t nrows, size_t ncols, const array::Span< value_type > &m, real_type_t< value_type > threshold, bool hermitian=false, bool reduce_to_rank=false)
Performs singular value decomposition and returns SVD objects for singular values less than threshold...
Definition: helper-implementation.h:262
size_t get_rank(std::span< const value_type > eigenvalues, value_type threshold)
Definition: helper-implementation.h:171
void printMatrix(const std::vector< value_type > &, size_t rows, size_t cols, std::string title="", std::ostream &s=molpro::cout)
Definition: helper-implementation.h:274
real_type_t< T > real_part(const T &x)
The real part of a scalar; the value itself for a real type.
Definition: scalar_traits.h:58
T conjugate(const T &x)
Complex conjugate, staying within the scalar type; the identity for a real type.
Definition: scalar_traits.h:47
typename real_type< T >::type real_type_t
The real type underlying T, i.e. T itself for a real type and U for std::complex<U>.
Definition: scalar_traits.h:43
Definition: scalar_traits.h:19
Stores a singular value and corresponding left and right singular vectors.
Definition: helper.h:27
value_type value
Definition: helper.h:29
Orders eigenvalues by non-descending real part, then by imaginary part.
Definition: helper-implementation.h:288
bool operator()(const std::complex< real_type > &lhs, const std::complex< real_type > &rhs) const
Definition: helper-implementation.h:289
A generalised eigenproblem reduced to a standard one by symmetric orthogonalisation of the metric.
Definition: helper-implementation.h:305
Eigen::Matrix< value_type, Eigen::Dynamic, Eigen::Dynamic, Eigen::ColMajor > matrix_type
Definition: helper-implementation.h:306
matrix_type S
the metric, column-major
Definition: helper-implementation.h:307
int rank
the number of directions of the metric that were kept
Definition: helper-implementation.h:310
matrix_type transformation
X, of dimension x rank, with X^dagger S X = I.
Definition: helper-implementation.h:308
matrix_type Hbar
X^dagger H X, of rank x rank.
Definition: helper-implementation.h:309