iterative-solver 0.0
LinearEigensystemDavidson.h
1#ifndef LINEARALGEBRA_SRC_MOLPRO_LINALG_ITSOLV_LINEAREIGENSYSTEMDAVIDSON_H
2#define LINEARALGEBRA_SRC_MOLPRO_LINALG_ITSOLV_LINEAREIGENSYSTEMDAVIDSON_H
3#include <molpro/Profiler.h>
4#include <molpro/linalg/itsolv/CastOptions.h>
5#include <molpro/linalg/itsolv/DSpaceResetter.h>
6#include <molpro/linalg/itsolv/IterativeSolverTemplate.h>
7#include <molpro/linalg/itsolv/Logger.h>
8#include <molpro/linalg/itsolv/helper.h>
9#include <molpro/linalg/itsolv/propose_rspace.h>
10#include <molpro/linalg/itsolv/qspace_options.h>
11#include <molpro/linalg/itsolv/rspace_options.h>
12#include <molpro/linalg/itsolv/subspace/SubspaceSolverLinEig.h>
13#include <molpro/linalg/itsolv/subspace/XSpace.h>
14
15#include <algorithm>
16#include <cassert>
17#include <iterator>
18#include <map>
19
20namespace molpro::linalg::itsolv {
21
22namespace log {
23
24template< typename value_type >
25struct ComplexRootsDavidson : ContextBase<ComplexRootsDavidson<value_type>, true, std::vector<std::pair<std::size_t, value_type>>> {
26 static const char *name;
27};
28template<typename value_type>
29const char *ComplexRootsDavidson<value_type>::name = "ComplexRootsDavidson";
31
32}
33
45template <class R, class Q = R, class P = std::map<size_t, typename R::value_type>>
46class LinearEigensystemDavidson : public IterativeSolverTemplate<LinearEigensystem, R, Q, P> {
47public:
49 using typename SolverTemplate::scalar_type;
50 using typename SolverTemplate::value_type_abs;
52
53 explicit LinearEigensystemDavidson(const std::shared_ptr<ArrayHandlers<R, Q, P>>& handlers =
55 const std::shared_ptr<Logger>& logger_ = std::make_shared<Logger>())
56 : SolverTemplate(std::make_shared<subspace::XSpace<R, Q, P>>(handlers, logger_),
57 std::static_pointer_cast<subspace::ISubspaceSolver<R, Q, P>>(
58 std::make_shared<subspace::SubspaceSolverLinEig<R, Q, P>>(logger_)),
59 handlers, std::make_shared<Statistics>(), logger_) {
61 this->m_normalise_solution = false;
62 }
63
64 bool nonlinear() const override { return false; }
65
82 size_t end_iteration(const VecRef<R>& parameters, const VecRef<R>& action) override {
83 auto prof = this->profiler();
84 auto m_prof = prof->push("itsolv::end_iteration");
85 if (m_dspace_resetter.do_reset(this->m_stats->iterations, this->m_xspace->dimensions())) {
87 this->m_working_set =
88 m_dspace_resetter.run(parameters, *this->m_xspace, this->m_subspace_solver->solutions(),
89 rspace_opts.norm_thresh, rspace_opts.svd_thresh, *this->m_handlers, *this->m_logger);
90 } else {
92 prof->start("end_iteration (propose_rspace)");
93 this->m_working_set =
94 detail::propose_rspace(*this, parameters, action, *this->m_xspace, *this->m_subspace_solver,
95 *this->m_handlers, *this->m_logger, rspace_opts, qspace_opts, *this->profiler().get());
96 prof->stop();
97 }
98 this->m_stats->iterations++;
100 this->m_end_iteration_needed = false;
101 return this->working_set().size();
102 }
103 size_t end_iteration(std::vector<R>& parameters, std::vector<R>& action) override {
104 return end_iteration(wrap(parameters), wrap(action));
105 }
106 size_t end_iteration(R& parameters, R& actions) override {
107 auto wparams = std::vector<std::reference_wrapper<R>>{std::ref(parameters)};
108 auto wactions = std::vector<std::reference_wrapper<R>>{std::ref(actions)};
109 return end_iteration(wparams, wactions);
110 }
111
112 void finalize() override {
114 return;
115 }
116
117 auto subspace_solver = std::dynamic_pointer_cast<subspace::SubspaceSolverLinEig<R, Q, P>>(this->m_subspace_solver);
118 assert(subspace_solver);
119 auto imag_eigval_components = subspace_solver->imag_eigval_components();
120 if (imag_eigval_components.empty()) {
121 return;
122 }
123
124 // Convert to 1-based indexing for printout
125 for (auto& pair : imag_eigval_components) {
126 pair.first += 1;
127 }
128
129 this->m_logger->template warn<log::ComplexRootsDavidson<typename R::value_type>>(
130 "The following roots are complex-valued. Associated eigenvectors are the real and imaginary part "
131 "of the pairs and the imaginary parts of the eigenvalues are ",
132 imag_eigval_components);
133 }
134
136 void precondition(std::vector<R>& parameters, std::vector<R>& action) const {}
137
138 std::vector<scalar_type> eigenvalues() const override { return this->m_subspace_solver->eigenvalues(); }
139
140 virtual std::vector<scalar_type> working_set_eigenvalues() const override {
141 auto eval = std::vector<scalar_type>{};
142 for (auto i : this->working_set()) {
143 eval.push_back(i < this->m_subspace_solver->eigenvalues().size() ? this->m_subspace_solver->eigenvalues().at(i)
144 : 0);
145 }
146 return eval;
147 }
148
149 void set_value_errors() override {
150 auto current_values = this->m_subspace_solver->eigenvalues();
151 this->m_value_errors.assign(current_values.size(), std::numeric_limits<value_type_abs>::max());
152 for (size_t i = 0; i < std::min(m_last_values.size(), current_values.size()); i++)
153 this->m_value_errors[i] = std::abs(current_values[i] - m_last_values[i]);
155 m_last_values = current_values;
156 }
157
158 void report(std::ostream& cout, bool endl = true) const override {
160 cout << "errors " << std::scientific;
161 auto& err = this->m_errors;
162 std::copy(begin(err), end(err), std::ostream_iterator<scalar_type>(cout, ", "));
163 cout << std::endl;
164 cout << "eigenvalues ";
165 auto ev = eigenvalues();
166 cout << std::fixed << std::setprecision(14);
167 std::copy(begin(ev), end(ev), std::ostream_iterator<scalar_type>(cout, ", "));
168 cout << std::defaultfloat;
169 if (endl)
170 cout << std::endl;
171 }
172
174 void set_reset_D(size_t n) { m_dspace_resetter.set_nreset(n); }
175 size_t get_reset_D() const { return m_dspace_resetter.get_nreset(); }
177 void set_reset_D_maxQ_size(size_t n) { m_dspace_resetter.set_max_Qsize(n); }
178 int get_reset_D_maxQ_size() const { return m_dspace_resetter.get_max_Qsize(); }
179 std::size_t get_max_size_qspace() const { return qspace_opts.max_size; }
180 void set_max_size_qspace(std::size_t n) {
181 qspace_opts.max_size = n;
182 if (m_dspace_resetter.get_max_Qsize() > qspace_opts.max_size)
183 m_dspace_resetter.set_max_Qsize(qspace_opts.max_size);
184 }
185 std::size_t get_min_size_qspace() const { return qspace_opts.min_size; }
186 void set_min_size_qspace(std::size_t n) { qspace_opts.min_size = n; }
187 void set_hermiticity(bool hermitian) override {
188 m_hermiticity = hermitian;
189 auto xspace = std::dynamic_pointer_cast<subspace::XSpace<R, Q, P>>(this->m_xspace);
190 xspace->set_hermiticity(hermitian);
191 auto subspace_solver = std::dynamic_pointer_cast<subspace::SubspaceSolverLinEig<R, Q, P>>(this->m_subspace_solver);
192 subspace_solver->set_hermiticity(hermitian);
193 }
194 bool get_hermiticity() const override { return m_hermiticity; }
195
196 void set_options(const Options& options) override {
199 if (opt.reset_D)
200 set_reset_D(opt.reset_D.value());
201 if (opt.reset_D_max_Q_size)
202 set_reset_D_maxQ_size(opt.reset_D_max_Q_size.value());
203 if (opt.max_size_qspace)
204 set_max_size_qspace(opt.max_size_qspace.value());
205 if (opt.min_size_qspace)
206 set_min_size_qspace(opt.min_size_qspace.value());
207 if (opt.contrib_thresh)
208 qspace_opts.contrib_thresh = opt.contrib_thresh.value();
209 if (opt.norm_thresh)
210 rspace_opts.norm_thresh = opt.norm_thresh.value();
211 if (opt.svd_thresh)
212 rspace_opts.svd_thresh = opt.svd_thresh.value();
213 if (opt.hermiticity)
214 set_hermiticity(opt.hermiticity.value());
215 }
216
217 std::shared_ptr<Options> get_options() const override {
218 auto opt = std::make_shared<LinearEigensystemDavidsonOptions>();
219 opt->copy(*SolverTemplate::get_options());
220 opt->reset_D = get_reset_D();
221 opt->reset_D_max_Q_size = get_reset_D_maxQ_size();
222 opt->max_size_qspace = get_max_size_qspace();
223 opt->min_size_qspace = get_min_size_qspace();
224 opt->contrib_thresh = qspace_opts.contrib_thresh;
225 opt->norm_thresh = rspace_opts.norm_thresh;
226 opt->svd_thresh = rspace_opts.svd_thresh;
227 opt->hermiticity = get_hermiticity();
228 return opt;
229 }
230
231protected:
232 void construct_residual(const std::vector<int>& roots, const CVecRef<R>& params, const VecRef<R>& actions) override {
233 auto prof = this->profiler()->push("itsolv::construct_residual");
234 assert(params.size() >= roots.size());
235 const auto& eigvals = eigenvalues();
236
237 auto subspace_solver = std::dynamic_pointer_cast<subspace::SubspaceSolverLinEig<R, Q, P>>(this->m_subspace_solver);
238 assert(subspace_solver);
239 const auto& imag_eigval_components = subspace_solver->imag_eigval_components();
240
241 for (size_t i = 0; i < roots.size(); ++i) {
242 this->m_handlers->rr().axpy(-eigvals.at(roots[i]), params.at(i), actions.at(i));
243
244 auto it = std::ranges::find(imag_eigval_components, roots[i], [](const auto& pair) { return pair.first; });
245
246 if (it != imag_eigval_components.end()) {
247 // Ref.: https://doi.org/10.1063/1.2755681 (Appendix)
248 // The idea is the following: We make use of the fact that the real and imaginary parts of the
249 // eigenvectors belonging to the complex root pair are spanned by the same basis. This allows
250 // us to split the associated residual vectors into a part corresponding to the real and a part
251 // corresponding to the imaginary part as well. The actual (complex-valued) residual can then
252 // always be reconstructed from this and therefore we don't lose any information. The formulas are
253 // |(R_real)_i> = sum_j [ (|A_j> - (e_real)_i |b_j>) (c_real)_{ji} + (e_imag) |b_j> (c_imag)_{ji} ]
254 // |(R_imag)_i> = sum_j [ (|A_j> - (e_real)_i |b_j>) (c_imag)_{ji} - (e_imag) |b_j> (c_real)_{ji} ]
255 // where |A_j> is the j-th action and |b_j> the j-th trial vector. e are the complex conjugate
256 // eigenvalues and c the associated eigenvectors.
257 // Note: At this point, params and actions already contain the vectors transformed into the
258 // eigenbasis (aka.: multiplied with c). Due to the way we process these complex-valued vectors,
259 // the first vector in a pair is the one that has been transformed with the real and the second
260 // with the imaginary part of c.
261 // The above code has already dealt with the bulk of the necessary expression and we only need
262 // to add the part with the imaginary components of the eigenvalue pair. We use the knowledge
263 // about the ordering of vectors (which has been transformed with what eigenvector component)
264 // to compute the right thing without explicit access to the eigenvectors.
265 const auto distance = std::ranges::distance(imag_eigval_components.begin(), it);
266 const int offset = (distance % 2) == 0 ? 1 : -1;
267
268 auto root_it = std::ranges::find(roots, roots[i] + offset);
269 if (root_it == roots.end()) {
270 // We can only do this, if we have both components of a complex eigenvalue/eigenvector pair
271 // available here.
272 this->m_logger->warn(
273 "Complex conjugate eigenvalue pair incomplete in construct_residual (this can lead to poor convergence)");
274 continue;
275 }
276
277 const std::size_t param_idx = std::ranges::distance(roots.begin(), root_it);
278
279 // Note: The minus sign in above expression is implicitly taken into account as the
280 // imaginary parts of the complex conjugate eigenvalue pair has flipped signs
281 this->m_handlers->rr().axpy(it->second, params.at(param_idx), actions.at(i));
282 }
283 }
284 }
285
287 bool m_hermiticity = false;
288 std::vector<scalar_type> m_last_values;
290 RSpaceOptions<value_type_abs> rspace_opts;
291 QSpaceOptions qspace_opts;
292};
293
294} // namespace molpro::linalg::itsolv
295
296#endif // LINEARALGEBRA_SRC_MOLPRO_LINALG_ITSOLV_LINEAREIGENSYSTEMDAVIDSON_H
Class, containing a collection of array handlers used in IterativeSolver Provides a Builder sub-class...
Definition: ArrayHandlers.h:25
Implements IterativeSolver interface that is common to all solvers.
Definition: IterativeSolverTemplate.h:163
std::vector< value_type_abs > m_value_errors
value errors from the most recent solution
Definition: IterativeSolverTemplate.h:685
std::vector< int > m_working_set
indices of roots in the working set
Definition: IterativeSolverTemplate.h:686
std::shared_ptr< subspace::IXSpace< R, R, std::map< size_t, typename R::value_type > > > m_xspace
manages the subspace and associated data
Definition: IterativeSolverTemplate.h:682
std::shared_ptr< ArrayHandlers< R, R, std::map< size_t, typename R::value_type > > > m_handlers
Array handlers.
Definition: IterativeSolverTemplate.h:681
std::shared_ptr< subspace::ISubspaceSolver< R, R, std::map< size_t, typename R::value_type > > > m_subspace_solver
solves the subspace problem
Definition: IterativeSolverTemplate.h:683
std::vector< value_type_abs > m_errors
errors from the most recent solution
Definition: IterativeSolverTemplate.h:684
std::shared_ptr< Options > get_options() const override
Definition: IterativeSolverTemplate.h:311
const std::shared_ptr< molpro::profiler::Profiler > & profiler() const override
Definition: IterativeSolverTemplate.h:397
bool m_end_iteration_needed
whether end_iteration should be called after any preconditioner
Definition: IterativeSolverTemplate.h:703
void report() const override
Writes a report to std::cout.
Definition: IterativeSolverTemplate.h:352
bool m_normalise_solution
whether to normalise the solutions
Definition: IterativeSolverTemplate.h:693
const std::vector< int > & working_set() const override
Working set of roots that are not yet converged.
Definition: IterativeSolverTemplate.h:286
void set_options(const Options &options) override
Definition: IterativeSolverTemplate.h:296
std::shared_ptr< Statistics > m_stats
accumulates statistics of operations performed by the solver
Definition: IterativeSolverTemplate.h:691
One specific implementation of LinearEigensystem using Davidson's algorithm with modifications to man...
Definition: LinearEigensystemDavidson.h:46
void finalize() override
Definition: LinearEigensystemDavidson.h:112
int get_reset_D_maxQ_size() const
Definition: LinearEigensystemDavidson.h:178
void set_min_size_qspace(std::size_t n)
Definition: LinearEigensystemDavidson.h:186
size_t end_iteration(const VecRef< R > &parameters, const VecRef< R > &action) override
Proposes new parameters for the subspace from the preconditioned residuals.
Definition: LinearEigensystemDavidson.h:82
void set_reset_D_maxQ_size(size_t n)
Set the maximum size of Q space after resetting the D space.
Definition: LinearEigensystemDavidson.h:177
bool nonlinear() const override
Report whether the class is a non-linear solver.
Definition: LinearEigensystemDavidson.h:64
QSpaceOptions qspace_opts
Options concerning Q-space handling.
Definition: LinearEigensystemDavidson.h:291
void set_hermiticity(bool hermitian) override
Sets hermiticity of kernel.
Definition: LinearEigensystemDavidson.h:187
bool get_hermiticity() const override
Gets hermiticity of kernel, if true than it is hermitian, otherwise it is not.
Definition: LinearEigensystemDavidson.h:194
bool m_resetting_in_progress
whether D space resetting is in progress
Definition: LinearEigensystemDavidson.h:289
detail::DSpaceResetter< Q > m_dspace_resetter
resets D space
Definition: LinearEigensystemDavidson.h:286
std::vector< scalar_type > eigenvalues() const override
The calculated eigenvalues of the subspace matrix.
Definition: LinearEigensystemDavidson.h:138
std::size_t get_max_size_qspace() const
Definition: LinearEigensystemDavidson.h:179
size_t end_iteration(std::vector< R > &parameters, std::vector< R > &action) override
Definition: LinearEigensystemDavidson.h:103
void precondition(std::vector< R > &parameters, std::vector< R > &action) const
Applies the Davidson preconditioner.
Definition: LinearEigensystemDavidson.h:136
void set_value_errors() override
Implementation class should overload this to set errors in the current values (e.g....
Definition: LinearEigensystemDavidson.h:149
void set_max_size_qspace(std::size_t n)
Definition: LinearEigensystemDavidson.h:180
size_t get_reset_D() const
Definition: LinearEigensystemDavidson.h:175
std::size_t get_min_size_qspace() const
Definition: LinearEigensystemDavidson.h:185
bool m_hermiticity
whether the problem is hermitian or not
Definition: LinearEigensystemDavidson.h:287
void set_options(const Options &options) override
Definition: LinearEigensystemDavidson.h:196
RSpaceOptions< value_type_abs > rspace_opts
Options concerning R-space handling.
Definition: LinearEigensystemDavidson.h:290
void set_reset_D(size_t n)
Set the period in iterations for resetting the D space.
Definition: LinearEigensystemDavidson.h:174
std::vector< scalar_type > m_last_values
The values from the previous iteration.
Definition: LinearEigensystemDavidson.h:288
void report(std::ostream &cout, bool endl=true) const override
Writes a report to cout output stream.
Definition: LinearEigensystemDavidson.h:158
void construct_residual(const std::vector< int > &roots, const CVecRef< R > &params, const VecRef< R > &actions) override
Constructs residual for given roots provided their parameters and actions.
Definition: LinearEigensystemDavidson.h:232
virtual std::vector< scalar_type > working_set_eigenvalues() const override
Definition: LinearEigensystemDavidson.h:140
LinearEigensystemDavidson(const std::shared_ptr< ArrayHandlers< R, Q, P > > &handlers=std::make_shared< molpro::linalg::itsolv::ArrayHandlers< R, Q, P > >(), const std::shared_ptr< Logger > &logger_=std::make_shared< Logger >())
Definition: LinearEigensystemDavidson.h:53
std::shared_ptr< Options > get_options() const override
Definition: LinearEigensystemDavidson.h:217
size_t end_iteration(R &parameters, R &actions) override
Definition: LinearEigensystemDavidson.h:106
Interface for a specific iterative solver, it can add special member functions or variables.
Definition: IterativeSolver.h:425
Resets D space constructing full solutions as the new working set, removing instabilities from Q spac...
Definition: DSpaceResetter.h:74
Definition: Logger.h:123
auto propose_rspace(IterativeSolver< R, Q, P > &solver, const VecRef< R > &parameters, const VecRef< R > &residuals, subspace::IXSpace< R, Q, P > &xspace, subspace::ISubspaceSolver< R, Q, P > &subspace_solver, ArrayHandlers< R, Q, P > &handlers, Logger &logger, const RSpaceOptions< typename array::ArrayHandler< R, R >::value_type_abs > &r_opts, const QSpaceOptions &q_opts, molpro::profiler::Profiler &profiler)
Proposes new parameters for the subspace from the preconditioned residuals.
Definition: propose_rspace.h:554
4-parameter interpolation of a 1-dimensional function given two points for which function values and ...
Definition: helper.h:14
auto wrap(ForwardIt begin, ForwardIt end)
Takes a begin and end iterators and returns a vector of references to each element.
Definition: wrap.h:32
std::vector< std::reference_wrapper< const A > > CVecRef
Definition: wrap.h:14
std::vector< std::reference_wrapper< A > > VecRef
Definition: wrap.h:11
void read_handler_counts(std::shared_ptr< Statistics > stats, std::shared_ptr< ArrayHandlers< R, Q, P > > handlers)
Definition: Statistics.h:30
const std::shared_ptr< const molpro::Options > options()
Get the Options object associated with iterative-solver.
Definition: linalg_options.cpp:4
Definition: scalar_traits.h:19
static std::shared_ptr< LinearEigensystemDavidsonOptions > LinearEigensystem(const std::shared_ptr< Options > &options)
Definition: CastOptions.h:39
Access point for different options in iterative solvers.
Definition: Options.h:20
Information about performance of IterativeSolver instance.
Definition: Statistics.h:10
Definition: LinearEigensystemDavidson.h:25
static const char * name
Definition: LinearEigensystemDavidson.h:26