35 const std::chrono::time_point<std::chrono::system_clock> &start)
const {
37 <<
TimeStamp() <<
"-----------------------------------" << std::flush;
38 std::chrono::time_point<std::chrono::system_clock> end =
39 std::chrono::system_clock::now();
40 std::chrono::duration<double> elapsed_time = end - start;
42 << elapsed_time.count() <<
"secs." << std::flush;
44 <<
TimeStamp() <<
"-----------------------------------" << std::flush;
51 <<
TimeStamp() <<
" == Warning : Max search space ("
57 <<
TimeStamp() <<
" == Warning : Max search space set to "
58 << operator_size << std::flush;
62 <<
" == Warning : If problems appear, try asking for less than "
63 <<
Index(operator_size / 10) <<
" eigenvalues" << std::flush;
71 <<
" threads." << std::flush;
78 <<
TimeStamp() <<
" DPR Correction" << std::flush;
82 <<
TimeStamp() <<
" Olsen Correction" << std::flush;
87 <<
'x' << operator_size << std::flush;
95 double percent_converged = 100 * double(converged_roots) / double(neigen);
98 << format(
" %1$4d %2$12d \t %3$4.2e \t %4$5.2f%% converged") %
i_iter_ %
107 }
else if (mt ==
"SYMM") {
110 throw std::runtime_error(mt +
" is not a valid Davidson matrix type");
115 if (method ==
"DPR") {
117 }
else if (method ==
"OLSEN") {
120 throw std::runtime_error(method +
121 " is not a valid Davidson correction method");
126 if (tol ==
"loose") {
128 }
else if (tol ==
"normal") {
130 }
else if (tol ==
"strict") {
132 }
else if (tol ==
"lapack") {
135 throw std::runtime_error(tol +
" is not a valid Davidson tolerance");
141 if (update_size ==
"min") {
143 }
else if (update_size ==
"safe") {
145 }
else if (update_size ==
"max") {
148 throw std::runtime_error(update_size +
" is not a valid Davidson update");
156 size_update = neigen;
160 size_update =
static_cast<Index>(1.5 * double(neigen));
162 size_update = neigen + 10;
166 size_update = 2 * neigen;
169 size_update = 2 * neigen;
177 ArrayXl idx = ArrayXl::LinSpaced(
V.rows(), 0,
V.rows() - 1);
178 std::sort(idx.data(), idx.data() + idx.size(),
179 [&](
Index i1,
Index i2) { return V[i1] < V[i2]; });
184 Index size_initial_guess)
const {
186 Eigen::MatrixXd guess =
187 Eigen::MatrixXd::Zero(
Adiag_.size(), size_initial_guess);
194 for (
Index j = 0; j < size_initial_guess; j++) {
195 guess(idx(j), j) = 1.0;
203 for (
Index j = 0; j < size_initial_guess; j++) {
204 guess(idx(ind0 + j), j) = 1.0;
228 Eigen::SelfAdjointEigenSolver<Eigen::MatrixXd> es(proj.
T);
229 if (es.info() != Eigen::ComputationInfo::Success) {
230 std::cerr <<
"A\n" << proj.
T << std::endl;
231 throw std::runtime_error(
"Small hermitian eigenvalue problem failed.");
236 rep.
lambda = es.eigenvalues().head(needed_pairs);
237 rep.
U = es.eigenvectors().leftCols(needed_pairs);
239 rep.
q = proj.
V * rep.
U;
255 bool return_eigenvectors =
true;
256 Eigen::GeneralizedEigenSolver<Eigen::MatrixXd> ges(proj.
T, proj.
B,
257 return_eigenvectors);
258 if (ges.info() != Eigen::ComputationInfo::Success) {
259 std::cerr <<
"A\n" << proj.
T << std::endl;
260 std::cerr <<
"B\n" << proj.
B << std::endl;
261 throw std::runtime_error(
"Small generalized eigenvalue problem failed.");
264 std::vector<std::pair<Index, Index>> complex_pairs;
265 for (
Index i = 0; i < ges.eigenvalues().size(); i++) {
266 if (ges.eigenvalues()(i).imag() != 0) {
267 bool found_partner =
false;
268 for (
auto &pair : complex_pairs) {
269 if (pair.second > -1) {
272 bool are_pair = (std::abs(ges.eigenvalues()(pair.first).real() -
273 ges.eigenvalues()(i).real()) < 1
e-9) &&
274 (std::abs(ges.eigenvalues()(pair.first).imag() +
275 ges.eigenvalues()(i).imag()) < 1
e-9);
278 found_partner =
true;
283 if (!found_partner) {
284 complex_pairs.emplace_back(i, -1);
289 for (
const auto &pair : complex_pairs) {
290 if (pair.second < 0) {
291 throw std::runtime_error(
"Eigenvalue:" + std::to_string(pair.first) +
292 " is complex but has no partner.");
295 if (!complex_pairs.empty()) {
297 <<
TimeStamp() <<
" Found " << complex_pairs.size()
298 <<
" complex pairs in eigenvalue problem" << std::flush;
301 Eigen::VectorXd::Zero(ges.eigenvalues().size() - complex_pairs.size());
303 Eigen::MatrixXd::Zero(ges.eigenvectors().rows(),
304 ges.eigenvectors().cols() - complex_pairs.size());
307 for (
Index i = 0; i < ges.eigenvalues().size(); i++) {
308 bool is_second_in_complex_pair =
309 std::find_if(complex_pairs.begin(), complex_pairs.end(),
310 [&](
const std::pair<Index, Index> &pair) {
311 return pair.second == i;
312 }) != complex_pairs.end();
313 if (is_second_in_complex_pair) {
331 rep.
lambda = (rep.
U.transpose() * proj.
T * rep.
U).diagonal();
332 rep.
q = proj.
V * rep.
U;
338 Index neigen,
Index size_initial_guess)
const {
352 Index neigen)
const {
362 Index oldsize = proj.
V.cols();
363 proj.
V.conservativeResize(Eigen::NoChange, oldsize + nupdate);
376 proj.
V.col(oldsize + k) = w.normalized();
385 Eigen::MatrixXd W = Eigen::MatrixXd::Zero(
V.rows(), idx.size());
386 for (
Index i = 0; i < idx.size(); i++) {
387 W.col(i) =
V.col(idx(i));
393 const Eigen::VectorXd &qj,
double lambdaj,
394 const Eigen::VectorXd &Aqj)
const {
403 Eigen::VectorXd correction;
406 correction =
dpr(Aqj, lambdaj);
410 correction =
olsen(Aqj, qj, lambdaj);
415 return correction.unaryExpr(
416 [](
double v) {
return std::isfinite(v) ? v : 0.0; });
420 double lambda)
const {
424 return (-r.array() / (
Adiag_.array() - lambda));
428 const Eigen::VectorXd &x,
429 double lambda)
const {
434 double num = -x.transpose() * delta;
435 double denom = -x.transpose() *
dpr(x, lambda);
436 double eps = num / denom;
446 Index nupdate = Q.cols() - nstart;
447 Eigen::VectorXd norms = Q.rightCols(nupdate).colwise().norm();
450 Q.rightCols(nupdate) -=
452 (Q.leftCols(nstart).transpose() * Q.rightCols(nupdate));
453 Q.rightCols(nupdate).colwise().normalize();
456 for (
Index j = nstart + 1; j < Q.cols(); ++j) {
457 Index range = j - nstart;
458 Q.col(j) -= Q.middleCols(nstart, range) *
459 (Q.middleCols(nstart, range).transpose() * Q.col(j));
460 Q.col(j).normalize();
465 Q.rightCols(nupdate) -=
467 (Q.leftCols(nstart).transpose() * Q.rightCols(nupdate));
468 Q.rightCols(nupdate).colwise().normalize();
471 for (
Index j = nstart + 1; j < Q.cols(); ++j) {
472 Index range = j - nstart;
473 Q.col(j) -= Q.middleCols(nstart, range) *
474 (Q.middleCols(nstart, range).transpose() * Q.col(j));
475 if (Q.col(j).norm() <= 1E-12 * norms(range)) {
477 throw std::runtime_error(
"Linear dependencies in Gram-Schmidt.");
479 Q.col(j).normalize();
485 Index nrows = A.rows();
486 Index ncols = A.cols();
487 ncols = std::min(nrows, ncols);
488 Eigen::MatrixXd
I = Eigen::MatrixXd::Identity(nrows, ncols);
489 Eigen::HouseholderQR<Eigen::MatrixXd>
qr(A);
490 return qr.householderQ() *
I;
495 Index newvectors)
const {
496 Eigen::MatrixXd newV =
498 newV.rightCols(newvectors) = proj.
V.rightCols(newvectors);
505 Eigen::MatrixXd orthonormal =
508 proj.
V.leftCols(proj.
V.cols() - newvectors) * orthonormal;
509 proj.
AV *= orthonormal;
511 proj.
AAV *= orthonormal;
523 <<
i_iter_ <<
" iterations." << std::flush;
524 info_ = Eigen::ComputationInfo::Success;
533 double percent_converged = 0;
535 for (
Index i = 0; i < neigen; i++) {
536 if (!root_converged[i]) {
540 percent_converged += 1.;
543 percent_converged /= double(neigen);
544 percent_converged *= 100.;
546 <<
TimeStamp() <<
"- Warning : Davidson "
547 << format(
"%1$5.2f%%") % percent_converged <<
" converged after "
548 <<
i_iter_ <<
" iterations." << std::flush;
549 info_ = Eigen::ComputationInfo::NoConvergence;
Index getSizeUpdate(Index neigen) const
RitzEigenPair getRitzEigenPairs(const ProjectedSpace &proj) const
bool checkConvergence(const RitzEigenPair &rep, ProjectedSpace &proj, Index neigen) const
void restart(const RitzEigenPair &rep, ProjectedSpace &proj, Index newtestvectors) const
ProjectedSpace initProjectedSpace(Index neigen, Index size_initial_guess) const
void printOptions(Index operator_size) const
Eigen::MatrixXd eigenvectors_
ArrayXl argsort(const Eigen::VectorXd &V) const
DavidsonSolver(Logger &log)
Index extendProjection(const RitzEigenPair &rep, ProjectedSpace &proj) const
Eigen::VectorXd eigenvalues() const
void checkOptions(Index operator_size)
void set_matrix_type(std::string mt)
Eigen::MatrixXd setupInitialEigenvectors(Index size_initial_guess) const
void set_correction(std::string method)
void set_size_update(std::string update_size)
RitzEigenPair getHarmonicRitz(const ProjectedSpace &proj) const
void set_tolerance(std::string tol)
Eigen::MatrixXd eigenvectors() const
Eigen::VectorXd dpr(const Eigen::VectorXd &r, double lambda) const
void gramschmidt(Eigen::MatrixXd &A, Index nstart) const
Eigen::VectorXd computeCorrectionVector(const Eigen::VectorXd &qj, double lambdaj, const Eigen::VectorXd &Aqj) const
Eigen::MatrixXd extract_vectors(const Eigen::MatrixXd &V, const ArrayXl &idx) const
void printTiming(const std::chrono::time_point< std::chrono::system_clock > &start) const
void storeEigenPairs(const RitzEigenPair &rep, Index neigen)
Eigen::Array< bool, Eigen::Dynamic, 1 > ArrayXb
RitzEigenPair getRitz(const ProjectedSpace &proj) const
void storeConvergedData(const RitzEigenPair &rep, Index neigen)
void orthogonalize(Eigen::MatrixXd &V, Index nupdate) const
Eigen::ComputationInfo info_
void printIterationData(const RitzEigenPair &rep, const ProjectedSpace &proj, Index neigen) const
Eigen::VectorXd olsen(const Eigen::VectorXd &r, const Eigen::VectorXd &x, double lambda) const
Eigen::VectorXd eigenvalues_
CORR davidson_correction_
Eigen::MatrixXd qr(const Eigen::MatrixXd &A) const
void storeNotConvergedData(const RitzEigenPair &rep, const ArrayXb &root_converged, Index neigen)
Logger is used for thread-safe output of messages.
Timestamp returns the current time as a string Example: cout << TimeStamp()
#define XTP_LOG(level, log)
base class for all analysis tools
Index search_space() const
Eigen::ArrayXd res_norm() const
Eigen::Array< votca::Index, Eigen::Dynamic, 1 > ArrayXl