votca 2026-dev
Loading...
Searching...
No Matches
davidsonsolver.h
Go to the documentation of this file.
1/*
2 * Copyright 2009-2020 The VOTCA Development Team (http://www.votca.org)
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 *
16 */
17
18#pragma once
19#ifndef VOTCA_XTP_DAVIDSONSOLVER_H
20#define VOTCA_XTP_DAVIDSONSOLVER_H
21
22// Standard includes
23#include <chrono>
24#include <iostream>
25#include <stdexcept>
26
27// Third party includes
28#include <boost/format.hpp>
29
30// Local VOTCA includes
31#include "eigen.h"
32#include "logger.h"
33
34namespace votca {
35namespace xtp {
36
46
48
49 public:
51
52 void set_iter_max(Index N) { this->iter_max_ = N; }
54 void set_tolerance(std::string tol);
55 void set_correction(std::string method);
56 void set_size_update(std::string update_size);
57 void set_matrix_type(std::string mt);
58
59 Eigen::ComputationInfo info() const { return info_; }
60 Eigen::VectorXd eigenvalues() const { return this->eigenvalues_; }
61 Eigen::MatrixXd eigenvectors() const { return this->eigenvectors_; }
62 Index num_iterations() const { return this->i_iter_; }
63
64 template <typename MatrixReplacement>
65 void solve(const MatrixReplacement &A, Index neigen,
66 Index size_initial_guess = 0) {
67
68 if (max_search_space_ < neigen) {
69 max_search_space_ = neigen * 5;
70 }
71 std::chrono::time_point<std::chrono::system_clock> start =
72 std::chrono::system_clock::now();
73 Index op_size = A.rows();
74
75 checkOptions(op_size);
76 printOptions(op_size);
77
78 // initial guess size
79 if (size_initial_guess == 0) {
80 size_initial_guess = 2 * neigen;
81 }
82
83 restart_size_ = size_initial_guess;
84
85 // get the diagonal of the operator
86 this->Adiag_ = A.diagonal();
87
88 // target the lowest diagonal element
89 ProjectedSpace proj = initProjectedSpace(neigen, size_initial_guess);
90 RitzEigenPair rep;
92 << TimeStamp() << " iter\tSearch Space\tNorm" << std::flush;
93
94 for (i_iter_ = 0; i_iter_ < iter_max_; i_iter_++) {
95
96 updateProjection(A, proj);
97
98 rep = getRitzEigenPairs(proj);
99
100 bool converged = checkConvergence(rep, proj, neigen);
101
102 printIterationData(rep, proj, neigen);
103
104 bool last_iter = i_iter_ == (iter_max_ - 1);
105
106 if (converged) {
107 storeConvergedData(rep, neigen);
108 break;
109 } else if (last_iter) {
110 storeNotConvergedData(rep, proj.root_converged, neigen);
111 break;
112 }
113 Index extension_size = extendProjection(rep, proj);
114 bool do_restart = (proj.search_space() > max_search_space_);
115
116 if (do_restart) {
117 restart(rep, proj, extension_size);
118 }
119 }
120
121 printTiming(start);
122 }
123
124 template <typename MatrixReplacement>
125 void solve(const MatrixReplacement &A, Index neigen,
126 const Eigen::MatrixXd &initial_guess) {
127
128 if (max_search_space_ < neigen) {
129 max_search_space_ = neigen * 5;
130 }
131 std::chrono::time_point<std::chrono::system_clock> start =
132 std::chrono::system_clock::now();
133 Index op_size = A.rows();
134
135 checkOptions(op_size);
136 printOptions(op_size);
137
138 if (initial_guess.rows() != op_size) {
139 throw std::runtime_error(
140 "DavidsonSolver::solve initial_guess has wrong number of rows.");
141 }
142 if (initial_guess.cols() < neigen) {
143 throw std::runtime_error(
144 "DavidsonSolver::solve initial_guess has fewer columns than neigen.");
145 }
146
147 restart_size_ = std::min<Index>(initial_guess.cols(), max_search_space_);
148 // get the diagonal of the operator
149 this->Adiag_ = A.diagonal();
150
151 ProjectedSpace proj;
152 proj.V = initial_guess;
153 orthogonalize(proj.V, proj.V.cols());
154
156 proj.root_converged = ArrayXb::Constant(proj.size_update, false);
157
158 RitzEigenPair rep;
160 << TimeStamp() << " iter\tSearch Space\tNorm" << std::flush;
161
162 for (i_iter_ = 0; i_iter_ < iter_max_; i_iter_++) {
163
164 updateProjection(A, proj);
165
166 rep = getRitzEigenPairs(proj);
167
168 bool converged = checkConvergence(rep, proj, neigen);
169
170 printIterationData(rep, proj, neigen);
171
172 bool last_iter = i_iter_ == (iter_max_ - 1);
173
174 if (converged) {
175 storeConvergedData(rep, neigen);
176 break;
177 } else if (last_iter) {
178 storeNotConvergedData(rep, proj.root_converged, neigen);
179 break;
180 }
181 Index extension_size = extendProjection(rep, proj);
182 bool do_restart = (proj.search_space() > max_search_space_);
183
184 if (do_restart) {
185 restart(rep, proj, extension_size);
186 }
187 }
188
189 printTiming(start);
190 }
191
192 private:
193 using ArrayXb = Eigen::Array<bool, Eigen::Dynamic, 1>;
197 double tol_ = 1E-4;
199 Eigen::VectorXd Adiag_;
201 enum CORR { DPR, OLSEN };
203
204 enum UPDATE { MIN, SAFE, MAX };
206
209
210 Eigen::VectorXd eigenvalues_;
211 Eigen::MatrixXd eigenvectors_;
212 Eigen::ComputationInfo info_ = Eigen::ComputationInfo::NoConvergence;
213
215 Eigen::VectorXd lambda; // eigenvalues
216 Eigen::MatrixXd q; // Ritz (or harmonic Ritz) eigenvectors
217 Eigen::MatrixXd U; // eigenvectors of the small subspace
218 Eigen::MatrixXd res; // residues of the pairs
219 Eigen::ArrayXd res_norm() const {
220 return res.colwise().norm();
221 } // norm of the residues
222 };
223
225 Eigen::MatrixXd V; // basis of vectors
226 Eigen::MatrixXd AV; // A * V
227 Eigen::MatrixXd T; // V.T * A * V
229 return V.cols();
230 }; // size of the projection i.e. number of cols in V
231 Index size_update; // size update ...
232 ArrayXb root_converged; // keep track of which root have onverged
233
234 // These are only used for harmonic ritz in the non-hermitian case
235 Eigen::MatrixXd AAV; // A*A*V
236 Eigen::MatrixXd B; // V.T *A*A*V
237 };
238
239 template <typename MatrixReplacement>
240 void updateProjection(const MatrixReplacement &A,
241 ProjectedSpace &proj) const {
242
243 if (i_iter_ == 0) {
244 proj.AV = A * proj.V;
245 proj.T = proj.V.transpose() * proj.AV;
247 proj.AAV = A * proj.AV;
248 proj.B = proj.V.transpose() * proj.AAV;
249 }
250
251 } else {
252 /* if we use a Gram Schmid(GS) orthogonalisation we do not have to
253 recompute the entire projection as GS doesn't change the original
254 subspace*/
255 Index old_dim = proj.AV.cols();
256 Index new_dim = proj.V.cols();
257 Index nvec = new_dim - old_dim;
258 proj.AV.conservativeResize(Eigen::NoChange, new_dim);
259 proj.AV.rightCols(nvec) = A * proj.V.rightCols(nvec);
260
261 proj.T.conservativeResize(new_dim, new_dim);
262 proj.T.rightCols(nvec) = proj.V.transpose() * proj.AV.rightCols(nvec);
263
265 proj.T.bottomLeftCorner(nvec, old_dim) =
266 proj.T.topRightCorner(old_dim, nvec).transpose();
267
268 } else {
269 proj.T.bottomLeftCorner(nvec, old_dim) =
270 proj.V.rightCols(nvec).transpose() * proj.AV.leftCols(old_dim);
271
272 proj.AAV.conservativeResize(Eigen::NoChange, new_dim);
273 proj.AAV.rightCols(nvec) = A * proj.AV.rightCols(nvec);
274 proj.B.conservativeResize(new_dim, new_dim);
275 proj.B.rightCols(nvec) = proj.V.transpose() * proj.AAV.rightCols(nvec);
276 proj.B.bottomLeftCorner(nvec, old_dim) =
277 proj.V.rightCols(nvec).transpose() * proj.AAV.leftCols(old_dim);
278 }
279 }
280 }
281 RitzEigenPair getRitzEigenPairs(const ProjectedSpace &proj) const;
282
283 Eigen::MatrixXd qr(const Eigen::MatrixXd &A) const;
284 RitzEigenPair getHarmonicRitz(const ProjectedSpace &proj) const;
285
286 RitzEigenPair getRitz(const ProjectedSpace &proj) const;
287
288 Index getSizeUpdate(Index neigen) const;
289
290 void checkOptions(Index operator_size);
291
292 void printOptions(Index operator_size) const;
293
294 void printTiming(
295 const std::chrono::time_point<std::chrono::system_clock> &start) const;
296
297 void printIterationData(const RitzEigenPair &rep, const ProjectedSpace &proj,
298 Index neigen) const;
299
300 ArrayXl argsort(const Eigen::VectorXd &V) const;
301
302 Eigen::MatrixXd setupInitialEigenvectors(Index size_initial_guess) const;
303
304 Eigen::MatrixXd extract_vectors(const Eigen::MatrixXd &V,
305 const ArrayXl &idx) const;
306
307 void orthogonalize(Eigen::MatrixXd &V, Index nupdate) const;
308 void gramschmidt(Eigen::MatrixXd &A, Index nstart) const;
309
310 Eigen::VectorXd computeCorrectionVector(const Eigen::VectorXd &qj,
311 double lambdaj,
312 const Eigen::VectorXd &Aqj) const;
313 Eigen::VectorXd dpr(const Eigen::VectorXd &r, double lambda) const;
314 Eigen::VectorXd olsen(const Eigen::VectorXd &r, const Eigen::VectorXd &x,
315 double lambda) const;
316
317 ProjectedSpace initProjectedSpace(Index neigen,
318 Index size_initial_guess) const;
319
320 Index extendProjection(const RitzEigenPair &rep, ProjectedSpace &proj) const;
321
322 bool checkConvergence(const RitzEigenPair &rep, ProjectedSpace &proj,
323 Index neigen) const;
324
325 void restart(const RitzEigenPair &rep, ProjectedSpace &proj,
326 Index newtestvectors) const;
327
328 void storeConvergedData(const RitzEigenPair &rep, Index neigen);
329
330 void storeNotConvergedData(const RitzEigenPair &rep,
331 const ArrayXb &root_converged, Index neigen);
332
333 void storeEigenPairs(const RitzEigenPair &rep, Index neigen);
334};
335
336} // namespace xtp
337} // namespace votca
338
339#endif // VOTCA_XTP_DAVIDSONSOLVER_H
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
ArrayXl argsort(const Eigen::VectorXd &V) const
Index extendProjection(const RitzEigenPair &rep, ProjectedSpace &proj) const
void set_max_search_space(Index N)
Eigen::VectorXd eigenvalues() const
void solve(const MatrixReplacement &A, Index neigen, Index size_initial_guess=0)
void solve(const MatrixReplacement &A, Index neigen, const Eigen::MatrixXd &initial_guess)
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)
Eigen::ComputationInfo info() const
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
void updateProjection(const MatrixReplacement &A, ProjectedSpace &proj) 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::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.
Definition logger.h:164
Timestamp returns the current time as a string Example: cout << TimeStamp()
Definition logger.h:224
#define XTP_LOG(level, log)
Definition logger.h:40
Provides a means for comparing floating point numbers.
Definition basebead.h:33
Eigen::Index Index
Definition types.h:26
Eigen::Array< votca::Index, Eigen::Dynamic, 1 > ArrayXl
Definition eigen.h:36