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>
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) {
48 t.v.emplace_back(
svd.matrixV()(
j,
i));
56template <
typename value_type>
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) {
69 t.v.emplace_back(
svd.matrixV()(
j,
i));
84template <
typename value_type>
90 std::vector<value_type>
a(mat.
begin(), mat.
end());
91 std::vector<real_type_t<value_type>>
sv(
sdim);
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) {
104 for (
size_t j = 0;
j <
ncols; ++
j) {
114template <
typename value_type>
120 std::vector<value_type>
a(mat.begin(), mat.end());
121 std::vector<real_type_t<value_type>>
sv(
sdim);
123 std::vector<real_type_t<value_type>>
superb(
sdim > 0 ?
sdim - 1 : 0);
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) {
135 for (
size_t j = 0;
j <
ncols; ++
j) {
154 std::span<double> eigenvalues,
const size_t dimension) {
170template <
typename value_type>
172 if (eigenvalues.size() == 0) {
175 value_type
max = *
max_element(eigenvalues.begin(), eigenvalues.end());
178 std::count_if(eigenvalues.begin(), eigenvalues.end(), [&](
auto const&
val) { return val >= threshold_scaled; });
189template <
typename value_type>
193 typename std::list<SVD<value_type>>::iterator
it;
221template <
typename value_type>
224 std::list<SVD<value_type>>
svds;
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);
258 for (
int i =
ncols;
i > rank;
i--) {
267template <
typename value_type,
typename std::enable_if_t<!is_complex<value_type>{}, std::
nullptr_t>>
273template <
typename value_type,
typename std::enable_if_t<is_complex<value_type>{},
int>>
279template <
typename value_type>
280void printMatrix(
const std::vector<value_type>&
m,
size_t rows,
size_t cols, std::string
title, std::ostream&
s) {
282 << Eigen::Map<const Eigen::Matrix<value_type, Eigen::Dynamic, Eigen::Dynamic>>(
m.data(), rows, cols) << std::endl;
293template <
typename real_type>
295 bool operator()(
const std::complex<real_type>&
lhs,
const std::complex<real_type>& rhs)
const {
297 if (
lhs.real() != rhs.real()) {
298 return lhs.real() < rhs.real();
300 if (
abs(
lhs.imag()) !=
abs(rhs.imag())) {
302 return abs(
lhs.imag()) <
abs(rhs.imag());
305 return lhs.imag() < rhs.imag();
310template <
typename value_type>
312 using matrix_type = Eigen::Matrix<value_type, Eigen::Dynamic, Eigen::Dynamic, Eigen::ColMajor>;
330template <
typename value_type>
332 const std::vector<value_type>&
metric,
size_t dimension,
338 using row_major_type = Eigen::Matrix<value_type, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor>;
343 const matrix_type H = Eigen::Map<const row_major_type>(matrix.data(), dimension, dimension);
344 result.S = Eigen::Map<const row_major_type>(
metric.data(), dimension, dimension);
349 Eigen::Vector<real_t, Eigen::Dynamic>
metricEvals(dimension);
352 std::span<const value_type>{
result.S.data(),
size_t(
result.S.size())},
355 throw std::runtime_error(
"Eigensolver did not converge");
358 const int rank =
result.rank;
360 if (verbosity > 1 && rank <
int(dimension))
361 molpro::cout <<
"SVD rank " << rank <<
" in subspace of dimension " << dimension << std::endl;
362 if (verbosity > 2 && rank <
int(dimension))
363 molpro::cout <<
"singular values " <<
metricEvals.transpose() << std::endl;
368 Eigen::Vector<value_type, Eigen::Dynamic>
svmh(rank);
369 for (
int k = 0;
k < rank;
k++) {
398template <
typename value_type,
typename matrix_type,
typename vector_type>
403 using colmajor_type = Eigen::Matrix<value_type, Eigen::Dynamic, Eigen::Dynamic, Eigen::ColMajor>;
404 using row_major_type = Eigen::Matrix<value_type, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor>;
407 const auto Hr = Eigen::Map<const row_major_type>(matrix.data(), dimension, dimension);
408 const auto Sr = Eigen::Map<const row_major_type>(
metric.data(), dimension, dimension);
413 Eigen::Vector<real_t, Eigen::Dynamic>
evals(
nroots);
415 std::span<const value_type>{H.data(),
size_t(H.size())}, std::span<const value_type>{S.data(),
size_t(S.size())},
416 std::span<value_type>{
evecs.data(),
size_t(
evecs.size())},
426template <
typename value_type,
typename std::enable_if_t<is_complex<value_type>{},
int>>
428 const std::vector<value_type>& matrix,
const std::vector<value_type>&
metric,
size_t dimension,
434 using matrix_type = Eigen::Matrix<value_type, Eigen::Dynamic, Eigen::Dynamic, Eigen::ColMajor>;
435 using vector_type = Eigen::Vector<value_type, Eigen::Dynamic>;
443 prof->start(
"itsolv::eigenproblem");
455 const auto subspace = detail::orthogonalise_subspace<value_type>(matrix,
metric, dimension,
svdThreshold, verbosity);
456 const int rank = subspace.rank;
468 const auto wanted = std::min<size_t>(
nroots,
size_t(rank));
469 const matrix_type
Hsym = (subspace.Hbar + subspace.Hbar.adjoint()) / value_type(2);
470 Eigen::Vector<real_t, Eigen::Dynamic>
evals(
wanted);
475 throw std::runtime_error(
"Eigensolver of the subspace matrix did not converge");
481 Eigen::ComplexEigenSolver<matrix_type>
s(subspace.Hbar);
482 if (
s.info() != Eigen::Success) {
483 throw std::runtime_error(
"Eigensolver of the subspace matrix did not converge");
515 Eigen::Index
pivot = 0;
532template <
typename value_type,
typename std::enable_if_t<!is_complex<value_type>{}, std::
nullptr_t>>
534 const std::vector<value_type>& matrix,
const std::vector<value_type>&
metric,
size_t dimension,
543 using MatrixT = Eigen::Matrix<value_type, Eigen::Dynamic, Eigen::Dynamic, Eigen::ColMajor>;
544 using ComplexMatrixT = Eigen::Matrix<std::complex<value_type>, Eigen::Dynamic, Eigen::Dynamic, Eigen::ColMajor>;
545 using VectorT = Eigen::Vector<value_type, Eigen::Dynamic>;
546 using ComplexVectorT = Eigen::Vector<std::complex<value_type>, Eigen::Dynamic>;
549 prof->start(
"itsolv::eigenproblem");
561 const auto subspace = detail::orthogonalise_subspace<value_type>(matrix,
metric, dimension,
svdThreshold, verbosity);
562 const int rank = subspace.rank;
563 const auto& Hbar = subspace.Hbar;
580 const auto wanted = std::min<size_t>(
nroots,
size_t(rank));
581 const MatrixT Hsym = (Hbar + Hbar.transpose()) / value_type(2);
587 throw std::runtime_error(
"Eigensolver of the subspace matrix did not converge");
592 Eigen::EigenSolver<MatrixT>
s(Hbar);
594 if (
s.eigenvalues().imag().norm() <
zero_tol) {
623 #ifdef __INTEL_COMPILER
624 molpro::cout <<
"Hbar\n" << Hbar << std::endl;
625 molpro::cout <<
"Eigenvalues\n" <<
s.eigenvalues() << std::endl;
626 molpro::cout <<
"Eigenvectors\n" <<
s.eigenvectors() << std::endl;
627 throw std::runtime_error(
"Intel compiler does not support working with complex eigen3 entities properly");
672 auto it = std::ranges::max_element(col, std::less<>{}, [](
auto val) {
return abs(
val); });
673 auto idx = std::distance(col.begin(),
it);
715 throw std::runtime_error(
"unexpected complex solution found");
737template <
typename value_type>
739 const std::vector<value_type>& matrix,
const std::vector<value_type>&
metric,
740 const std::vector<value_type>& rhs,
const size_t dimension,
size_t nroot,
743 const Eigen::Index nX = dimension;
744 solution.resize(nX *
nroot);
746 if (augmented_hessian > 0) {
747 Eigen::Matrix<value_type, Eigen::Dynamic, Eigen::Dynamic>
subspaceMatrix;
748 Eigen::Matrix<value_type, Eigen::Dynamic, Eigen::Dynamic>
subspaceOverlap;
753 using row_major_type = Eigen::Matrix<value_type, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor>;
754 subspaceMatrix.block(0, 0, nX, nX) = Eigen::Map<const row_major_type>(matrix.data(), nX, nX);
756 eigenvalues.resize(
nroot);
757 for (
size_t root = 0; root <
nroot; root++) {
758 for (Eigen::Index
i = 0;
i < nX;
i++) {
773 using matrix_type = Eigen::Matrix<value_type, Eigen::Dynamic, Eigen::Dynamic, Eigen::ColMajor>;
776 Eigen::Map<Eigen::Matrix<value_type, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor>>(
778 Eigen::Map<Eigen::Matrix<value_type, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor>>(
783 throw std::runtime_error(
"augmented Hessian: the augmented overlap matrix has no non-singular direction");
784 Eigen::ComplexEigenSolver<matrix_type>
s(
augmented.Hbar);
785 if (
s.info() != Eigen::Success)
786 throw std::runtime_error(
"augmented Hessian: eigensolver did not converge");
787 auto eval =
s.eigenvalues();
788 Eigen::Index
imax = 0;
789 for (Eigen::Index
i = 0;
i < eval.size();
i++)
792 eigenvalues[root] = eval(
imax);
793 const Eigen::Vector<value_type, Eigen::Dynamic>
evec =
augmented.transformation *
s.eigenvectors().col(
imax);
794 const value_type
scale = value_type(augmented_hessian) *
evec(nX);
795 for (Eigen::Index
k = 0;
k < nX;
k++)
798 Eigen::GeneralizedEigenSolver<Eigen::Matrix<value_type, Eigen::Dynamic, Eigen::Dynamic>>
s(
subspaceMatrix,
800 auto eval =
s.eigenvalues();
801 auto evec =
s.eigenvectors();
802 Eigen::Index
imax = 0;
803 for (Eigen::Index
i = 0;
i < nX + 1;
i++)
806 eigenvalues[root] = eval(
imax).real();
808 for (
auto k = 0;
k < nX;
k++)
814 Eigen::Map<const Eigen::Matrix<value_type, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor>>
subspaceMatrixR(
815 matrix.data(), nX, nX);
816 Eigen::Map<const Eigen::Matrix<value_type, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor>>
RHS_R(rhs.data(), nX,
819 Eigen::Matrix<value_type, Eigen::Dynamic, Eigen::Dynamic> RHS =
RHS_R;
820 Eigen::Matrix<value_type, Eigen::Dynamic, Eigen::Dynamic>
Solution;
831 for (
size_t root = 0; root <
nroot; root++)
832 for (
auto k = 0;
k < nX;
k++)
839template <
typename value_type,
typename std::enable_if_t<is_complex<value_type>{},
int>>
841 const std::vector<value_type>& matrix,
const std::vector<value_type>&
metric,
842 const std::vector<value_type>& rhs,
const size_t dimension,
size_t nroot,
845 detail::solve_LinearEquations_impl<value_type>(solution, eigenvalues, matrix,
metric, rhs, dimension,
nroot,
849template <
typename value_type,
typename std::enable_if_t<!is_complex<value_type>{}, std::
nullptr_t>>
851 const std::vector<value_type>& matrix,
const std::vector<value_type>&
metric,
852 const std::vector<value_type>& rhs,
const size_t dimension,
size_t nroot,
855 detail::solve_LinearEquations_impl<value_type>(solution, eigenvalues, matrix,
metric, rhs, dimension,
nroot,
867template <
typename value_type>
868void solve_DIIS_impl(std::vector<value_type>& solution,
const std::vector<value_type>& matrix,
const size_t dimension,
873 using VectorT = Eigen::Vector<value_type, Eigen::Dynamic>;
874 using MatrixT = Eigen::Matrix<value_type, Eigen::Dynamic, Eigen::Dynamic>;
875 auto nAug = dimension + 1;
877 solution.resize(dimension);
884 Eigen::Map<const Eigen::Matrix<value_type, Eigen::Dynamic, Eigen::Dynamic>>
subspaceMatrix(matrix.data(), dimension,
887 for (
size_t i = 0;
i < dimension; ++
i) {
891 BAug(dimension, dimension) = 0;
898 Eigen::JacobiSVD<MatrixT>
svd(
BAug, Eigen::ComputeThinU | Eigen::ComputeThinV);
911 molpro::cout <<
"Combination of iteration vectors: " <<
Coeffs.transpose() << std::endl;
914 molpro::cout <<
"B:" << std::endl <<
BAug << std::endl;
915 molpro::cout <<
"Rhs:" << std::endl <<
Rhs << std::endl;
916 molpro::cout <<
"Combination of iteration vectors: " <<
Coeffs.transpose() << std::endl;
917 throw std::overflow_error(
"NaN detected in DIIS submatrix solution");
925template <
typename value_type,
typename std::enable_if_t<is_complex<value_type>{},
int>>
926void solve_DIIS(std::vector<value_type>& solution,
const std::vector<value_type>& matrix,
const size_t dimension,
928 detail::solve_DIIS_impl<value_type>(solution, matrix, dimension,
svdThreshold, verbosity);
931template <
typename value_type,
typename std::enable_if_t<!is_complex<value_type>{}, std::
nullptr_t>>
932void solve_DIIS(std::vector<value_type>& solution,
const std::vector<value_type>& matrix,
const size_t dimension,
934 detail::solve_DIIS_impl<value_type>(solution, matrix, dimension,
svdThreshold, verbosity);
955template <
typename value_type,
typename value_type_abs>
957 const value_type_abs svd_thresh,
Logger& logger) {
959 prof->start(
"itsolv::svd_system");
960 logger.
trace(
"redundant_parameters()");
965 array::Span(
const_cast<value_type*
>(overlap.data().data()), overlap.size()), svd_thresh,
true);
967 prof->start(
"find redundant parameters");
977 std::stringstream
ss;
978 ss << std::setprecision(3) <<
"redundant parameter found, i = " <<
redundant_params.back()
Non-owning container taking a pointer to the data buffer and its size and exposing routines for itera...
Definition Span.h:31
iterator begin()
Definition Span.h:72
iterator end()
Definition Span.h:76
void info(std::string_view message, Ts &&...args) const
Definition Logger.h:507
void trace(std::string_view message, Ts &&...args) const
Definition Logger.h:497
Matrix container that allows simple data access, slicing, copying and resizing without loosing data.
Definition Matrix.h:32
static std::shared_ptr< Profiler > single()
Definition helper-dispatch.h:223
bool hermitian_lowest_by_cholesky(const std::vector< value_type > &matrix, const std::vector< value_type > &metric, size_t dimension, size_t nroots, real_type_t< value_type > svdThreshold, matrix_type &eigenvectors, vector_type &eigenvalues)
The lowest nroots eigenpairs of a hermitian H C = S C E by Cholesky reduction, where that is safe.
Definition helper-implementation.h:399
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:868
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:738
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:331
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:956
4-parameter interpolation of a 1-dimensional function given two points for which function values and ...
Definition helper.h:14
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
std::unique_ptr< LinearEigensystem< R, Q, P > > create_LinearEigensystem(const LinearEigensystemOptions &options, const std::shared_ptr< ArrayHandlers< R, Q, P > > &handlers=std::make_shared< molpro::linalg::itsolv::ArrayHandlers< R, Q, P > >())
Definition SolverFactory.h:111
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:840
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:926
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:268
size_t get_rank(std::span< const value_type > eigenvalues, value_type threshold)
Definition helper-implementation.h:171
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, size_t nroots=std::numeric_limits< size_t >::max())
Definition helper-implementation.h:427
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:280
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:294
bool operator()(const std::complex< real_type > &lhs, const std::complex< real_type > &rhs) const
Definition helper-implementation.h:295
A generalised eigenproblem reduced to a standard one by symmetric orthogonalisation of the metric.
Definition helper-implementation.h:311
Eigen::Matrix< value_type, Eigen::Dynamic, Eigen::Dynamic, Eigen::ColMajor > matrix_type
Definition helper-implementation.h:312
matrix_type S
the metric, column-major
Definition helper-implementation.h:313
int rank
the number of directions of the metric that were kept
Definition helper-implementation.h:316
matrix_type transformation
X, of dimension x rank, with X^dagger S X = I.
Definition helper-implementation.h:314
matrix_type Hbar
X^dagger H X, of rank x rank.
Definition helper-implementation.h:315