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 if (orthogonalize(proj.V, proj.V.cols()) < neigen) {
154 throw std::runtime_error(
155 "DavidsonSolver::solve initial guess has fewer than neigen linearly "
156 "independent columns.");
157 }
158
160 proj.root_converged = ArrayXb::Constant(proj.size_update, false);
161
162 RitzEigenPair rep;
164 << TimeStamp() << " iter\tSearch Space\tNorm" << std::flush;
165
166 for (i_iter_ = 0; i_iter_ < iter_max_; i_iter_++) {
167
168 updateProjection(A, proj);
169
170 rep = getRitzEigenPairs(proj);
171
172 bool converged = checkConvergence(rep, proj, neigen);
173
174 printIterationData(rep, proj, neigen);
175
176 bool last_iter = i_iter_ == (iter_max_ - 1);
177
178 if (converged) {
179 storeConvergedData(rep, neigen);
180 break;
181 } else if (last_iter) {
182 storeNotConvergedData(rep, proj.root_converged, neigen);
183 break;
184 }
185 Index extension_size = extendProjection(rep, proj);
186 bool do_restart = (proj.search_space() > max_search_space_);
187
188 if (do_restart) {
189 restart(rep, proj, extension_size);
190 }
191 }
192
193 printTiming(start);
194 }
195
196 private:
197 using ArrayXb = Eigen::Array<bool, Eigen::Dynamic, 1>;
201 double tol_ = 1E-4;
203 Eigen::VectorXd Adiag_;
205 enum CORR { DPR, OLSEN };
207
208 enum UPDATE { MIN, SAFE, MAX };
210
213
214 Eigen::VectorXd eigenvalues_;
215 Eigen::MatrixXd eigenvectors_;
216 Eigen::ComputationInfo info_ = Eigen::ComputationInfo::NoConvergence;
217
219 Eigen::VectorXd lambda; // eigenvalues
220 Eigen::MatrixXd q; // Ritz (or harmonic Ritz) eigenvectors
221 Eigen::MatrixXd U; // eigenvectors of the small subspace
222 Eigen::MatrixXd res; // residues of the pairs
223 Eigen::ArrayXd res_norm() const {
224 return res.colwise().norm();
225 } // norm of the residues
226 };
227
229 Eigen::MatrixXd V; // basis of vectors
230 Eigen::MatrixXd AV; // A * V
231 Eigen::MatrixXd T; // V.T * A * V
233 return V.cols();
234 }; // size of the projection i.e. number of cols in V
235 Index size_update; // size update ...
236 ArrayXb root_converged; // keep track of which root have onverged
237
238 // These are only used for harmonic ritz in the non-hermitian case
239 Eigen::MatrixXd AAV; // A*A*V
240 Eigen::MatrixXd B; // V.T *A*A*V
241 };
242
243 template <typename MatrixReplacement>
244 void updateProjection(const MatrixReplacement &A,
245 ProjectedSpace &proj) const {
246
247 if (i_iter_ == 0) {
248 proj.AV = A * proj.V;
249 proj.T = proj.V.transpose() * proj.AV;
251 proj.AAV = A * proj.AV;
252 proj.B = proj.V.transpose() * proj.AAV;
253 }
254
255 } else {
256 /* if we use a Gram Schmid(GS) orthogonalisation we do not have to
257 recompute the entire projection as GS doesn't change the original
258 subspace*/
259 Index old_dim = proj.AV.cols();
260 Index new_dim = proj.V.cols();
261 Index nvec = new_dim - old_dim;
262 proj.AV.conservativeResize(Eigen::NoChange, new_dim);
263 proj.AV.rightCols(nvec) = A * proj.V.rightCols(nvec);
264
265 proj.T.conservativeResize(new_dim, new_dim);
266 proj.T.rightCols(nvec) = proj.V.transpose() * proj.AV.rightCols(nvec);
267
269 proj.T.bottomLeftCorner(nvec, old_dim) =
270 proj.T.topRightCorner(old_dim, nvec).transpose();
271
272 } else {
273 proj.T.bottomLeftCorner(nvec, old_dim) =
274 proj.V.rightCols(nvec).transpose() * proj.AV.leftCols(old_dim);
275
276 proj.AAV.conservativeResize(Eigen::NoChange, new_dim);
277 proj.AAV.rightCols(nvec) = A * proj.AV.rightCols(nvec);
278 proj.B.conservativeResize(new_dim, new_dim);
279 proj.B.rightCols(nvec) = proj.V.transpose() * proj.AAV.rightCols(nvec);
280 proj.B.bottomLeftCorner(nvec, old_dim) =
281 proj.V.rightCols(nvec).transpose() * proj.AAV.leftCols(old_dim);
282 }
283 }
284 }
285 RitzEigenPair getRitzEigenPairs(const ProjectedSpace &proj) const;
286
287 Eigen::MatrixXd qr(const Eigen::MatrixXd &A) const;
288 RitzEigenPair getHarmonicRitz(const ProjectedSpace &proj) const;
289
290 RitzEigenPair getRitz(const ProjectedSpace &proj) const;
291
292 Index getSizeUpdate(Index neigen) const;
293
294 void checkOptions(Index operator_size);
295
296 void printOptions(Index operator_size) const;
297
298 void printTiming(
299 const std::chrono::time_point<std::chrono::system_clock> &start) const;
300
301 void printIterationData(const RitzEigenPair &rep, const ProjectedSpace &proj,
302 Index neigen) const;
303
304 ArrayXl argsort(const Eigen::VectorXd &V) const;
305
306 Eigen::MatrixXd setupInitialEigenvectors(Index size_initial_guess) const;
307
308 Eigen::MatrixXd extract_vectors(const Eigen::MatrixXd &V,
309 const ArrayXl &idx) const;
310
311 Index orthogonalize(Eigen::MatrixXd &V, Index nupdate) const;
312 Index gramschmidt(Eigen::MatrixXd &A, Index nstart) const;
313
314 Eigen::VectorXd computeCorrectionVector(const Eigen::VectorXd &qj,
315 double lambdaj,
316 const Eigen::VectorXd &Aqj) const;
317 Eigen::VectorXd dpr(const Eigen::VectorXd &r, double lambda) const;
318 Eigen::VectorXd olsen(const Eigen::VectorXd &r, const Eigen::VectorXd &x,
319 double lambda) const;
320
321 ProjectedSpace initProjectedSpace(Index neigen,
322 Index size_initial_guess) const;
323
324 Index extendProjection(const RitzEigenPair &rep, ProjectedSpace &proj) const;
325
326 bool checkConvergence(const RitzEigenPair &rep, ProjectedSpace &proj,
327 Index neigen) const;
328
329 void restart(const RitzEigenPair &rep, ProjectedSpace &proj,
330 Index newtestvectors) const;
331
332 void storeConvergedData(const RitzEigenPair &rep, Index neigen);
333
334 void storeNotConvergedData(const RitzEigenPair &rep,
335 const ArrayXb &root_converged, Index neigen);
336
337 void storeEigenPairs(const RitzEigenPair &rep, Index neigen);
338};
339
340} // namespace xtp
341} // namespace votca
342
343#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
Index orthogonalize(Eigen::MatrixXd &V, Index nupdate) 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)
Index gramschmidt(Eigen::MatrixXd &A, Index nstart) const
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
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 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:39