32 const std::chrono::time_point<std::chrono::system_clock> &start)
const {
34 <<
TimeStamp() <<
"-----------------------------------" << std::flush;
35 std::chrono::time_point<std::chrono::system_clock> end =
36 std::chrono::system_clock::now();
37 std::chrono::duration<double> elapsed_time = end - start;
39 << elapsed_time.count() <<
"secs." << std::flush;
41 <<
TimeStamp() <<
"-----------------------------------" << std::flush;
48 <<
TimeStamp() <<
" == Warning : Max search space ("
54 <<
TimeStamp() <<
" == Warning : Max search space set to "
55 << operator_size << std::flush;
59 <<
" == Warning : If problems appear, try asking for less than "
60 <<
Index(operator_size / 10) <<
" eigenvalues" << std::flush;
68 <<
" threads." << std::flush;
75 <<
TimeStamp() <<
" DPR Correction" << std::flush;
79 <<
TimeStamp() <<
" Olsen Correction" << std::flush;
84 <<
'x' << operator_size << std::flush;
92 double percent_converged = 100 * double(converged_roots) / double(neigen);
95 << boost::format(
" %1$4d %2$12d \t %3$4.2e \t %4$5.2f%% converged") %
i_iter_ %
104 }
else if (mt ==
"SYMM") {
107 throw std::runtime_error(mt +
" is not a valid Davidson matrix type");
112 if (method ==
"DPR") {
114 }
else if (method ==
"OLSEN") {
117 throw std::runtime_error(method +
118 " is not a valid Davidson correction method");
123 if (tol ==
"loose") {
125 }
else if (tol ==
"normal") {
127 }
else if (tol ==
"strict") {
129 }
else if (tol ==
"lapack") {
132 throw std::runtime_error(tol +
" is not a valid Davidson tolerance");
138 if (update_size ==
"min") {
140 }
else if (update_size ==
"safe") {
142 }
else if (update_size ==
"max") {
145 throw std::runtime_error(update_size +
" is not a valid Davidson update");
153 size_update = neigen;
157 size_update =
static_cast<Index>(1.5 * double(neigen));
159 size_update = neigen + 10;
163 size_update = 2 * neigen;
166 size_update = 2 * neigen;
174 ArrayXl idx = ArrayXl::LinSpaced(
V.rows(), 0,
V.rows() - 1);
175 std::sort(idx.data(), idx.data() + idx.size(),
176 [&](
Index i1,
Index i2) { return V[i1] < V[i2]; });
181 Index size_initial_guess)
const {
183 Eigen::MatrixXd guess =
184 Eigen::MatrixXd::Zero(
Adiag_.size(), size_initial_guess);
191 for (
Index j = 0; j < size_initial_guess; j++) {
192 guess(idx(j), j) = 1.0;
200 for (
Index j = 0; j < size_initial_guess; j++) {
201 guess(idx(ind0 + j), j) = 1.0;
225 Eigen::SelfAdjointEigenSolver<Eigen::MatrixXd> es(proj.
T);
226 if (es.info() != Eigen::ComputationInfo::Success) {
227 std::cerr <<
"A\n" << proj.
T << std::endl;
228 throw std::runtime_error(
"Small hermitian eigenvalue problem failed.");
233 rep.
lambda = es.eigenvalues().head(needed_pairs);
234 rep.
U = es.eigenvectors().leftCols(needed_pairs);
236 rep.
q = proj.
V * rep.
U;
252 bool return_eigenvectors =
true;
253 Eigen::GeneralizedEigenSolver<Eigen::MatrixXd> ges(proj.
T, proj.
B,
254 return_eigenvectors);
255 if (ges.info() != Eigen::ComputationInfo::Success) {
256 std::cerr <<
"A\n" << proj.
T << std::endl;
257 std::cerr <<
"B\n" << proj.
B << std::endl;
258 throw std::runtime_error(
"Small generalized eigenvalue problem failed.");
261 std::vector<std::pair<Index, Index>> complex_pairs;
262 for (
Index i = 0; i < ges.eigenvalues().size(); i++) {
263 if (ges.eigenvalues()(i).imag() != 0) {
264 bool found_partner =
false;
265 for (
auto &pair : complex_pairs) {
266 if (pair.second > -1) {
269 bool are_pair = (std::abs(ges.eigenvalues()(pair.first).real() -
270 ges.eigenvalues()(i).real()) < 1
e-9) &&
271 (std::abs(ges.eigenvalues()(pair.first).imag() +
272 ges.eigenvalues()(i).imag()) < 1
e-9);
275 found_partner =
true;
280 if (!found_partner) {
281 complex_pairs.emplace_back(i, -1);
286 for (
const auto &pair : complex_pairs) {
287 if (pair.second < 0) {
288 throw std::runtime_error(
"Eigenvalue:" + std::to_string(pair.first) +
289 " is complex but has no partner.");
292 if (!complex_pairs.empty()) {
294 <<
TimeStamp() <<
" Found " << complex_pairs.size()
295 <<
" complex pairs in eigenvalue problem" << std::flush;
298 Eigen::VectorXd::Zero(ges.eigenvalues().size() - complex_pairs.size());
300 Eigen::MatrixXd::Zero(ges.eigenvectors().rows(),
301 ges.eigenvectors().cols() - complex_pairs.size());
304 for (
Index i = 0; i < ges.eigenvalues().size(); i++) {
305 bool is_second_in_complex_pair =
306 std::find_if(complex_pairs.begin(), complex_pairs.end(),
307 [&](
const std::pair<Index, Index> &pair) {
308 return pair.second == i;
309 }) != complex_pairs.end();
310 if (is_second_in_complex_pair) {
328 rep.
lambda = (rep.
U.transpose() * proj.
T * rep.
U).diagonal();
329 rep.
q = proj.
V * rep.
U;
335 Index neigen,
Index size_initial_guess)
const {
349 Index neigen)
const {
359 Index oldsize = proj.
V.cols();
360 proj.
V.conservativeResize(Eigen::NoChange, oldsize + nupdate);
373 proj.
V.col(oldsize + k) = w.normalized();
382 Eigen::MatrixXd W = Eigen::MatrixXd::Zero(
V.rows(), idx.size());
383 for (
Index i = 0; i < idx.size(); i++) {
384 W.col(i) =
V.col(idx(i));
390 const Eigen::VectorXd &qj,
double lambdaj,
391 const Eigen::VectorXd &Aqj)
const {
400 Eigen::VectorXd correction;
403 correction =
dpr(Aqj, lambdaj);
407 correction =
olsen(Aqj, qj, lambdaj);
412 return correction.unaryExpr(
413 [](
double v) {
return std::isfinite(v) ? v : 0.0; });
417 double lambda)
const {
421 return (-r.array() / (
Adiag_.array() - lambda));
425 const Eigen::VectorXd &x,
426 double lambda)
const {
431 double num = -x.transpose() * delta;
432 double denom = -x.transpose() *
dpr(x, lambda);
433 double eps = num / denom;
443 Index nupdate = Q.cols() - nstart;
444 Eigen::VectorXd norms = Q.rightCols(nupdate).colwise().norm();
447 Q.rightCols(nupdate) -=
449 (Q.leftCols(nstart).transpose() * Q.rightCols(nupdate));
450 Q.rightCols(nupdate).colwise().normalize();
453 for (
Index j = nstart + 1; j < Q.cols(); ++j) {
454 Index range = j - nstart;
455 Q.col(j) -= Q.middleCols(nstart, range) *
456 (Q.middleCols(nstart, range).transpose() * Q.col(j));
457 Q.col(j).normalize();
462 Q.rightCols(nupdate) -=
464 (Q.leftCols(nstart).transpose() * Q.rightCols(nupdate));
465 Q.rightCols(nupdate).colwise().normalize();
468 for (
Index j = nstart + 1; j < Q.cols(); ++j) {
469 Index range = j - nstart;
470 Q.col(j) -= Q.middleCols(nstart, range) *
471 (Q.middleCols(nstart, range).transpose() * Q.col(j));
472 if (Q.col(j).norm() <= 1E-12 * norms(range)) {
474 throw std::runtime_error(
"Linear dependencies in Gram-Schmidt.");
476 Q.col(j).normalize();
482 Index nrows = A.rows();
483 Index ncols = A.cols();
484 ncols = std::min(nrows, ncols);
485 Eigen::MatrixXd
I = Eigen::MatrixXd::Identity(nrows, ncols);
486 Eigen::HouseholderQR<Eigen::MatrixXd>
qr(A);
487 return qr.householderQ() *
I;
492 Index newvectors)
const {
493 Eigen::MatrixXd newV =
495 newV.rightCols(newvectors) = proj.
V.rightCols(newvectors);
502 Eigen::MatrixXd orthonormal =
505 proj.
V.leftCols(proj.
V.cols() - newvectors) * orthonormal;
506 proj.
AV *= orthonormal;
508 proj.
AAV *= orthonormal;
520 <<
i_iter_ <<
" iterations." << std::flush;
521 info_ = Eigen::ComputationInfo::Success;
530 double percent_converged = 0;
532 for (
Index i = 0; i < neigen; i++) {
533 if (!root_converged[i]) {
537 percent_converged += 1.;
540 percent_converged /= double(neigen);
541 percent_converged *= 100.;
543 <<
TimeStamp() <<
"- Warning : Davidson "
544 << boost::format(
"%1$5.2f%%") % percent_converged <<
" converged after "
545 <<
i_iter_ <<
" iterations." << std::flush;
546 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)
Charge transport classes.
Provides a means for comparing floating point numbers.
Index search_space() const
Eigen::ArrayXd res_norm() const
Eigen::Array< votca::Index, Eigen::Dynamic, 1 > ArrayXl