iterative-solver 0.0
 
Loading...
Searching...
No Matches
IterativeSolverTemplate.h
1#ifndef LINEARALGEBRA_SRC_MOLPRO_LINALG_ITSOLV_ITERATIVESOLVERTEMPLATE_H
2#define LINEARALGEBRA_SRC_MOLPRO_LINALG_ITSOLV_ITERATIVESOLVERTEMPLATE_H
3#include <molpro/Profiler.h>
4#include <molpro/iostream.h>
5#include <molpro/linalg/itsolv/IterativeSolver.h>
6#include <molpro/linalg/itsolv/Logger.h>
7#include <molpro/linalg/itsolv/MetricChecker.h>
8#include <molpro/linalg/itsolv/subspace/ISubspaceSolver.h>
9#include <molpro/linalg/itsolv/subspace/IXSpace.h>
10#include <molpro/linalg/itsolv/subspace/Matrix.h>
11#include <molpro/linalg/itsolv/subspace/util.h>
12#include <molpro/linalg/itsolv/util.h>
13#include <molpro/linalg/itsolv/wrap.h>
14#include <molpro/profiler/Profiler.h>
15
16#include <cassert>
17#include <cmath>
18#include <format>
19#include <iostream>
20#include <optional>
21#include <sstream>
22
23namespace molpro::linalg::itsolv {
24namespace detail {
25
26inline std::vector<std::pair<size_t, size_t>> parameter_batches(const size_t nsol, const size_t nparam) {
27 auto batches = std::vector<std::pair<size_t, size_t>>{};
28 if (nparam && nsol) {
29 auto n_batch = nsol / nparam + (nsol % nparam ? 1 : 0);
30 for (size_t ib = 0, start_sol = 0, end_sol = 0; ib < n_batch; ++ib, start_sol = end_sol) {
31 end_sol = std::min(start_sol + nparam, nsol);
32 batches.emplace_back(start_sol, end_sol);
33 }
34 }
35 return batches;
36}
37
39template <class R, class Q>
43 bool empty() const { return r.empty() && q.empty(); }
44};
45
46template <typename T>
47std::vector<std::vector<T>> construct_vectorP(const std::vector<int>& roots, const subspace::Matrix<T>& solutions,
48 const size_t oP, const size_t nP) {
49 auto vectorP = std::vector<std::vector<T>>{};
50 for (auto root : roots) {
51 vectorP.emplace_back();
52 for (size_t j = 0; j < nP; ++j)
53 vectorP.back().push_back(solutions(root, oP + j));
54 }
55 return vectorP;
56}
57
58template <class R, typename T>
59void update_errors(std::vector<T>& errors, const CVecRef<R>& residual, array::ArrayHandler<R, R>& handler) {
60 assert(residual.size() >= errors.size());
61 for (size_t i = 0; i < errors.size(); ++i)
62 errors[i] = util::norm(handler, residual[i]);
63}
64
65template <typename T>
66std::vector<int> select_working_set(const size_t nw, const std::vector<T>& errors, const T threshold,
67 const std::vector<T>& value_errors, const T value_threshold) {
68 auto ordered_errors = std::multimap<T, size_t, std::greater<T>>{};
69 for (size_t i = 0; i < errors.size(); ++i) {
70 if (errors[i] > threshold or (i < value_errors.size() and value_errors[i] > value_threshold))
71 ordered_errors.emplace(errors[i], i);
72 }
73 auto working_set = std::vector<int>{};
74 auto end = (ordered_errors.size() < nw ? ordered_errors.end() : next(begin(ordered_errors), nw));
75 std::transform(begin(ordered_errors), end, std::back_inserter(working_set), [](const auto& el) { return el.second; });
76 std::sort(working_set.begin(), working_set.end());
77 return working_set;
78}
79
80} // namespace detail
81
82namespace log {
83
84/*
85 * Events emitted by IterativeSolverTemplate::solve() describing the progress of the solver. They are templated on
86 * the solver's scalar type (IterativeSolver::scalar_type), so subscribe to e.g. log::IterationCompleted<double>.
87 * Solvers driven by explicit add_vector()/end_iteration() calls instead of solve() do not emit them.
88 */
89
93template <typename Scalar>
95 static constexpr std::string_view name = "SolveStarted";
103 static std::string format(const Payload& p) {
104 return std::format("n_roots = {}, max_iter = {}, convergence threshold = {}, P-space dimension = {}, initial "
105 "guess generated = {}",
106 p.n_roots, p.max_iter, stringify(p.convergence_threshold), p.pspace_size,
107 p.initial_guess_generated);
108 }
109};
110
114template <typename Scalar>
116 static constexpr std::string_view name = "NewIteration";
117 struct Payload {
118 int iter;
119 std::vector<int> roots;
121 };
122 static std::string format(const Payload& p) { return std::format("{}, roots {}", p.iter, stringify(p.roots)); }
123};
124
128template <typename Scalar>
130 static constexpr std::string_view name = "IterationCompleted";
131 struct Payload {
132 int iter;
133 std::vector<int> roots;
134 std::vector<real_t<Scalar>> errors;
135 std::vector<Scalar> values;
137 std::size_t n_next;
138 };
139 static std::string format(const Payload& p) {
140 return std::format("{}, roots {}, errors {}, values {}, next {}", p.iter, stringify(p.roots), stringify(p.errors),
141 stringify(p.values), p.n_next);
142 }
143};
144
148template <typename Scalar>
150 static constexpr std::string_view name = "SolveFinished";
151 struct Payload {
154 std::vector<real_t<Scalar>> errors;
155 std::vector<Scalar> values;
156 };
157 static std::string format(const Payload& p) {
158 return std::format("iterations = {}, converged = {}, errors {}, values {}", p.iterations, p.converged,
159 stringify(p.errors), stringify(p.values));
160 }
161};
162
167 static constexpr std::string_view name = "IterationReport";
168 struct Payload {};
169};
170
175 static constexpr std::string_view name = "SummaryReport";
176 struct Payload {};
177};
178
179} // namespace log
180
186template <template <class, class, class> class Solver, class R, class Q, class P>
187class IterativeSolverTemplate : public Solver<R, Q, P> {
188public:
189 using typename Solver<R, Q, P>::fapply_on_p_type;
190 using typename Solver<R, Q, P>::fapply_metric_type;
191 using typename Solver<R, Q, P>::PSpaceMetric;
192 using typename Solver<R, Q, P>::scalar_type;
193 using typename Solver<R, Q, P>::value_type;
194 using typename Solver<R, Q, P>::value_type_abs;
195 using typename Solver<R, Q, P>::VectorP;
196
200 IterativeSolverTemplate<Solver, R, Q, P>& operator=(const IterativeSolverTemplate<Solver, R, Q, P>&) = delete;
202
203 void set_logger(std::shared_ptr<Logger> logger) override {
204 assert(logger);
205 m_logger = std::move(logger);
206 m_xspace->set_logger(m_logger);
207 m_subspace_solver->set_logger(m_logger);
208 }
209
210 Logger &logger() override { return *m_logger; }
211
212 using Solver<R, Q, P>::add_vector;
213 using Solver<R, Q, P>::solve;
214
215 int add_vector(const VecRef<R>& parameters, const VecRef<R>& actions) override {
217 throw std::logic_error("The actions of the metric declared with set_metric() have to be given to add_vector()");
218 return add_vector_impl(parameters, actions, {});
219 }
220
221 int add_vector(const VecRef<R>& parameters, const VecRef<R>& actions, const VecRef<R>& metric_actions) override {
223 throw std::logic_error("Actions of a metric given to add_vector(), but no metric was declared with set_metric()");
224 const auto nW = n_added_vectors(parameters);
225 if (metric_actions.size() < nW)
226 throw std::invalid_argument("IterativeSolver::add_vector(): fewer actions of the metric than parameters");
227 return add_vector_impl(parameters, actions, metric_actions);
228 }
229
230 bool supports_metric(MetricKind kind) const override { return kind == MetricKind::Identity; }
231
233 fapply_metric_type apply_metric = {}) override {
237 if (bool(apply_metric) != (kind != MetricKind::Identity && storage == MetricStorage::OnTheFly))
238 throw std::invalid_argument("A function applying the metric has to be given exactly for MetricStorage::OnTheFly");
239 if (m_xspace->dimensions().nX() == 0)
240 m_metric_checker.reset();
243 m_apply_metric = std::move(apply_metric);
244 m_xspace->set_metric(kind, storage);
245 }
246
247 MetricKind metric_kind() const override { return m_metric_kind; }
248 void set_check_metric(bool check) override { m_check_metric = check; }
249 bool get_check_metric() const override { return m_check_metric; }
250 MetricStorage metric_storage() const override { return m_metric_storage; }
251
252 int add_vector(std::vector<R>& parameters, std::vector<R>& actions) override {
253 return add_vector(wrap(parameters), wrap(actions));
254 }
255 int add_vector(R& parameters, R& actions, value_type value = 0) override {
256 return add_vector(wrap_arg(parameters), wrap_arg(actions));
257 }
258
259 size_t add_p(const CVecRef<P>& pparams, const array::Span<value_type>& pp_action_matrix, const VecRef<R>& parameters,
260 const VecRef<R>& actions, fapply_on_p_type apply_p) override {
261 if (m_metric_kind != MetricKind::Identity && !pparams.empty())
262 throw std::logic_error(
263 "With a metric, the P space has to be added with the overload of add_p() taking the metric "
264 "matrix");
265 return add_p_impl(pparams, pp_action_matrix, {}, parameters, actions, std::move(apply_p));
266 }
267
268 size_t add_p(const CVecRef<P>& pparams, const array::Span<value_type>& pp_action_matrix, const VecRef<R>& parameters,
269 const VecRef<R>& actions, fapply_on_p_type apply_p, const PSpaceMetric& metric) override {
271 throw std::logic_error("A metric in the P space was given, but no metric was declared with set_metric()");
272 if (!pparams.empty() && m_xspace->stores_metric_actions() && !metric.apply)
273 throw std::invalid_argument("A function applying the metric in the P space is needed unless the metric is "
274 "applied on the fly");
276 if (metric.apply)
277 m_apply_metric_p = metric.apply;
278 return add_p_impl(pparams, pp_action_matrix, metric.pp_matrix, parameters, actions, std::move(apply_p));
279 }
280
281 void clearP() override {}
282
283 void solution(const std::vector<int>& roots, const VecRef<R>& parameters, const VecRef<R>& residual) override {
284 solution_impl(roots, parameters, residual, {});
285 }
286
287 void solution(const std::vector<int>& roots, std::vector<R>& parameters, std::vector<R>& residual) override {
288 return solution(roots, wrap(parameters), wrap(residual));
289 }
290 void solution(R& parameters, R& residual) override {
291 return solution(std::vector<int>(1, 0), wrap_arg(parameters), wrap_arg(residual));
292 }
293
294 void solution_params(const std::vector<int>& roots, std::vector<R>& parameters) override {
295 return solution_params(roots, wrap(parameters));
296 }
297
298 void solution_params(const std::vector<int>& roots, const VecRef<R>& parameters) override {
299 check_consistent_number_of_roots_and_solutions(roots, parameters.size());
300 const auto& dims = m_xspace->dimensions();
301 util::construct_solutions(parameters, roots, m_subspace_solver->solutions(), m_xspace->cparamsp(),
302 m_xspace->cparamsq(), m_xspace->cparamsd(), dims.oP(), dims.oQ(), dims.oD(),
303 m_handlers->rr(), m_handlers->rp(), m_handlers->rq());
304 };
305
306 void solution_params(R& parameters) override { return solution_params(std::vector<int>(1, 0), wrap_arg(parameters)); }
307
308 // TODO Implement this
309 std::vector<size_t> suggest_p(const CVecRef<R>& solution, const CVecRef<R>& residual, size_t max_number,
310 value_type_abs threshold) override {
311 return {};
312 }
313
314 const std::vector<int>& working_set() const override { return m_working_set; }
315
316 size_t n_roots() const override { return m_nroots; }
317
318 void set_n_roots(size_t roots) override {
319 m_nroots = roots;
320 m_working_set.resize(roots);
321 std::iota(begin(m_working_set), end(m_working_set), (int)0);
322 }
323
324 void set_options(const Options& options) override {
325 if (options.n_roots)
326 set_n_roots(options.n_roots.value());
327 if (options.convergence_threshold)
328 set_convergence_threshold(options.convergence_threshold.value());
329 if (options.verbosity)
330 set_verbosity(options.verbosity.value());
331 if (options.max_iter)
332 set_max_iter(options.max_iter.value());
333 if (options.max_p)
334 set_max_p(options.max_p.value());
335 if (options.p_threshold)
336 set_p_threshold(options.p_threshold.value());
337 if (options.check_metric)
338 set_check_metric(options.check_metric.value());
339 }
340
341 std::shared_ptr<Options> get_options() const override {
342 auto options = std::make_shared<Options>();
343 options->n_roots = n_roots();
344 options->convergence_threshold = convergence_threshold();
345 options->verbosity = get_verbosity();
346 options->max_iter = get_max_iter();
347 options->max_p = get_max_p();
348 options->p_threshold = get_p_threshold();
349 options->check_metric = get_check_metric();
350 return options;
351 }
352
353 const std::vector<value_type_abs>& errors() const override { return m_errors; }
354
355 const Statistics& statistics() const override { return *m_stats; }
356
357 void report(std::ostream& cout, bool endl = true) const override {
359 cout << "iteration " << m_stats->iterations;
360 if (not m_errors.empty()) {
361 auto it_max_error = std::max_element(m_errors.cbegin(), m_errors.cend());
362 if (n_roots() > 1)
363 cout << ", |residual[" << std::distance(m_errors.cbegin(), it_max_error) << "]| = ";
364 else
365 cout << ", |residual| = ";
366 cout << std::scientific << *it_max_error;
367 }
368 if (endl)
369 cout << std::endl;
370 }
371
372 void iteration_report() const {
373 std::stringstream sstream;
374 report(sstream, false);
376 }
377
378 void summary_report() const {
379 std::stringstream sstream;
380 report(sstream, false);
382 }
383
384 void report() const override {
385 // We don't know what kind of report this is supposed to be -> default to summary
387 }
388
390 value_type_abs convergence_threshold() const override { return m_convergence_threshold; }
392 value_type_abs convergence_threshold_value() const override { return m_convergence_threshold_value; }
393 void set_verbosity(Verbosity v) override { m_verbosity = v; }
394 void set_verbosity(int v) override {
395 if (v == 0) {
396 m_logger->set_verbosity(log::Verbosity::None);
397 m_logger->set_min_severity(log::Severity::Error);
398 } else if (v == 1) {
399 m_logger->set_verbosity(log::Verbosity::None);
400 m_logger->set_min_severity(log::Severity::Warning);
401 } else if (v == 2) {
402 m_logger->set_verbosity(log::Verbosity::Info);
403 m_logger->set_min_severity(log::Severity::Normal);
404 } else if (v == 3) {
405 m_logger->set_verbosity(log::Verbosity::Debug);
406 m_logger->set_min_severity(log::Severity::Normal);
407 } else {
408 m_logger->set_verbosity(log::Verbosity::Trace);
409 m_logger->set_min_severity(log::Severity::Normal);
410 }
411 }
412 Verbosity get_verbosity() const override { return m_verbosity.value_or(Verbosity::None); }
413 void set_max_iter(int n) override { m_max_iter = n; }
414 int get_max_iter() const override { return m_max_iter; }
415 void set_max_p(int n) override { m_max_p = n; }
416 int get_max_p() const override { return m_max_p; }
417 void set_p_threshold(value_type_abs threshold) override { m_p_threshold = threshold; }
418 value_type_abs get_p_threshold() const override { return m_p_threshold; }
420 const subspace::Dimensions& dimensions() const override { return m_xspace->dimensions(); }
421 scalar_type value() const override {
422 return m_xspace->data.count(subspace::EqnData::value) > 0 ? m_xspace->data[subspace::EqnData::value](0, 0)
423 : nan("molpro::linalg::itsolv::IterativeSolver::value");
424 }
426 // non-owning: the profiler belongs to the caller and must not be deleted by the solver
427 m_profiler = std::shared_ptr<molpro::profiler::Profiler>(std::shared_ptr<molpro::profiler::Profiler>{}, &profiler);
428 }
429 void set_profiler(std::shared_ptr<molpro::profiler::Profiler> profiler) override {
430 if (!profiler)
431 throw std::invalid_argument("IterativeSolver::set_profiler: null profiler");
432 m_profiler = std::move(profiler);
433 }
434 const std::shared_ptr<molpro::profiler::Profiler>& profiler() const override { return m_profiler; }
435
437 std::vector<scalar_type> current_values() const {
438 if constexpr (std::derived_from<Solver<R, Q, P>, LinearEigensystem<R, Q, P>>)
439 return this->eigenvalues();
440 else if (m_xspace->data.count(subspace::EqnData::value) > 0)
441 return {value()};
442 else
443 return {};
444 }
445
446 bool solve(const VecRef<R>& parameters, const VecRef<R>& actions, const Problem<R>& problem,
447 bool generate_initial_guess = false) override {
448 if (problem.metric_kind() != MetricKind::Identity)
449 throw std::invalid_argument("A problem with a metric has to be solved with the overload of "
450 "IterativeSolver::solve() taking buffers for the actions of the metric");
451 return solve_impl(parameters, actions, {}, problem, generate_initial_guess);
452 }
453
454 bool solve(const VecRef<R>& parameters, const VecRef<R>& actions, const VecRef<R>& metric_actions,
455 const Problem<R>& problem, bool generate_initial_guess = false) override {
456 if (parameters.size() != metric_actions.size())
457 throw std::invalid_argument("IterativeSolver::solve(): metric_actions has to hold as many vectors as parameters");
458 return solve_impl(parameters, actions, metric_actions, problem, generate_initial_guess);
459 }
460
461 bool solve(R& parameters, R& actions, const Problem<R>& problem, bool generate_initial_guess = false) override {
462 return solve(wrap_arg(parameters), wrap_arg(actions), problem, generate_initial_guess);
463 }
464 bool solve(std::vector<R>& parameters, std::vector<R>& actions, const Problem<R>& problem,
465 bool generate_initial_guess = false) override {
466 return solve(wrap(parameters), wrap(actions), problem, generate_initial_guess);
467 }
468
469 bool test_problem(const Problem<R>& problem, R& v0, R& v1, int verbosity, value_type_abs threshold) const override {
470 bool success = true;
471 value_type_abs step = 1e-4;
472 if (this->nonlinear()) {
473 if (!problem.test_parameters(0, v0))
474 return true;
475 auto value0 = problem.residual(v0, v1);
476 if (verbosity > 1) {
477 std::cout << "value0 " << value0 << std::endl;
478 // std::cout << "parameters0 " << v0[0] << "," << v0[1] << ",..." << std::endl;
479 // std::cout << "residual0 " << v1[0] << "," << v1[1] << ",..." << std::endl;
480 }
481 Q parameters0 = m_handlers->qr().copy(v0);
482 Q residual0 = m_handlers->qr().copy(v1);
483 for (int instance = 1; problem.test_parameters(instance, v0); ++instance) {
484 m_handlers->rq().axpy(-1.0, parameters0, v0);
485 m_handlers->rr().scal(1 / util::norm(m_handlers->rr(), v0), v0);
486 Q step1 = m_handlers->qr().copy(v0);
487 auto residual_analytic = m_handlers->rq().dot(v0, residual0);
488 m_handlers->rq().copy(v0, parameters0);
489 m_handlers->rq().axpy(-2*step, step1, v0);
490 auto valuem2 = problem.residual(v0, v1);
491 m_handlers->rq().copy(v0, parameters0);
492 m_handlers->rq().axpy(-1*step, step1, v0);
493 auto valuem1 = problem.residual(v0, v1);
494 m_handlers->rq().copy(v0, parameters0);
495 m_handlers->rq().axpy(+1*step, step1, v0);
496 auto valuep1 = problem.residual(v0, v1);
497 m_handlers->rq().copy(v0, parameters0);
498 m_handlers->rq().axpy(+2*step, step1, v0);
499 auto valuep2 = problem.residual(v0, v1);
500 auto residual_numerical = (valuem2 - value_type(8) * valuem1 + value_type(8) * valuep1 - valuep2) /
501 value_type(12 * step);
502 if (verbosity > 1)
503 std::cout << "testing problem class, instance: " << instance << ", numerical: " << residual_numerical <<", analytical: "<<residual_analytic <<", difference: "<<residual_numerical-residual_analytic << std::endl;
505 }
506 } else {
507 // checks that the operator applied by apply(x, y) scales linearly; name describes its result
508 auto check_scaling = [&](const auto& apply, const std::string& name) {
509 apply(v0, v1);
510 Q residual = m_handlers->qr().copy(v1);
511 auto norm2_residual = util::norm(m_handlers->rr(), v1);
512 const value_type_abs scale_factor{10.0};
513 m_handlers->rr().scal(scale_factor, v0);
514 apply(v0, v1);
515 m_handlers->rq().axpy(-scale_factor, residual, v1);
516 auto norm2 = util::norm(m_handlers->rr(), v1);
517 success = success && std::abs(norm2 / norm2_residual) < threshold;
518 if (verbosity > 0 or (verbosity > -1 and not success))
519 std::cout << "Length of " << name << ": " << norm2_residual << ", scaling defect: " << norm2 << std::endl;
520 };
521 for (int instance = 0; problem.test_parameters(instance, v0); ++instance) {
522 check_scaling([&problem](R& x, R& y) { problem.action({x}, {y}); }, "residual");
523 if (problem.metric_kind() != MetricKind::Identity)
524 check_scaling([&problem](R& x, R& y) { problem.metric_action({x}, {y}); }, "action of the metric");
525 }
526 if (problem.metric_kind() != MetricKind::Identity)
527 success = test_metric(problem, v0, v1, verbosity, threshold) && success;
528 }
529 return success;
530 }
531
532protected:
539 virtual void prepare_solve(const Problem<R>& problem, const VecRef<R>& actions) {}
540
542 bool solve_impl(const VecRef<R>& parameters, const VecRef<R>& actions, const VecRef<R>& metric_actions,
543 const Problem<R>& problem, bool generate_initial_guess) {
544 if (parameters.empty())
545 throw std::runtime_error("Empty container passed to IterativeSolver::solve()");
546 if (parameters.size() != actions.size())
547 throw std::runtime_error("Inconsistent container sizes in IterativeSolver::solve()");
548 // applies the verbosity of the solver to its logger, which repeating does not change
549 if (this->m_verbosity == Verbosity::None) {
550 // Backwards compatibility
551 this->m_logger->set_verbosity(log::Verbosity::None);
552 }
553 if (this->m_verbosity == Verbosity::Detailed) {
554 this->m_logger->set_verbosity(log::Verbosity::Trace);
555 this->m_logger->enable_data_dumps(true);
556 }
557 const auto kind = problem.metric_kind();
558 const bool metric = kind != MetricKind::Identity;
561 // the problem is checked before the solver changes, using the buffers as scratch space
562 bool use_diagonals = problem.diagonals(actions.at(0));
564 throw std::runtime_error("Default initial guess requested, but diagonal elements are not available");
565 std::unique_ptr<Q> diagonals;
566 if (use_diagonals)
567 diagonals.reset(new Q{m_handlers->qr().copy(actions.at(0))});
568 std::unique_ptr<Q> metric_diagonals;
570 if (not problem.metric_diagonals(actions.at(0)))
571 throw std::invalid_argument("The problem provides diagonals() but not metric_diagonals(), without which the "
572 "default preconditioner would ignore the metric");
573 metric_diagonals.reset(new Q{m_handlers->qr().copy(actions.at(0))});
574 }
575 // the initial guess and the P space are selected from the lowest of these values
576 const Q* selection = diagonals.get();
577 std::unique_ptr<Q> ratios;
578 if (metric_diagonals and (generate_initial_guess or m_max_p > 0)) {
579 // the lowest eigenvalues of a generalised eigenproblem are expected at the lowest ratios of the diagonals, which
580 // are exact, as a regulariser would make them depend on the scale of the metric
581 m_handlers->rq().copy(parameters.at(0), *diagonals);
582 detail::precondition_default(wrap_arg(parameters.at(0).get()), std::vector<value_type>{0}, actions.at(0).get(),
583 static_cast<const R*>(nullptr), false);
584 ratios.reset(new Q{m_handlers->qr().copy(parameters.at(0))});
585 selection = ratios.get();
586 }
587 std::vector<P> pspace;
588 if (use_diagonals and m_max_p > 0)
589 pspace = select_pspace(*selection);
591 prepare_solve(problem, actions);
594 [&problem](const CVecRef<R>& parameters, const VecRef<R>& metric_actions) {
595 problem.metric_action(parameters, metric_actions);
596 });
597 else
599 int nwork = parameters.size();
600 // a P space replaces any initial guess; without one, max_p > 0 still means the contents of parameters are not used
601 const bool initial_guess =
602 pspace.empty() and (generate_initial_guess or (use_diagonals and m_max_p > 0));
603 if (initial_guess)
605 // the ratios of the diagonal elements are not needed any more
606 selection = nullptr;
607 ratios.reset();
608 if (!pspace.empty())
609 nwork = initialise_pspace(pspace, problem, pspace_matrices, parameters, actions);
611 [&] {
614 pspace.size(), initial_guess};
615 });
616 // the roots worked on in the current iteration, only recorded if the iteration events are wanted
617 std::vector<int> roots;
618 const bool record_roots =
621 int iter = 0;
622 // an iteration that resets the D space is followed by one that takes up its vectors, even beyond max_iter, as
623 // there are no solutions to return in between
624 for (; (iter < this->m_max_iter || m_solutions_outdated) && nwork > 0; iter++) {
625 // the vectors worked on in this iteration: add_vector() takes up no more vectors than there are in the working
626 // set, and in the first iteration after initialising a P space the actions are already known
627 std::size_t naction = 0;
628 if (this->nonlinear())
629 naction = std::min(std::size_t(1), m_working_set.size());
630 else if (iter > 0 or pspace.empty())
631 naction = std::min(size_t(nwork), m_working_set.size());
632 // add_vector() replaces the working set, so it is recorded beforehand
633 if (record_roots)
634 roots.assign(m_working_set.begin(), m_working_set.begin() + naction);
637 [&] { return typename log::NewIteration<scalar_type>::Payload{iter, roots}; });
638 value_type value;
639 if (this->nonlinear()) {
640 value = problem.residual(*parameters.begin(), *actions.begin());
641 nwork = this->add_vector(*parameters.begin(), *actions.begin(), value);
642 } else if (iter > 0 or pspace.empty()) {
643 const auto wparameters = cwrap(parameters.begin(), parameters.begin() + naction);
644 const auto wactions = wrap(actions.begin(), actions.begin() + naction);
645 if (naction > 0 and metric)
647 wrap(metric_actions.begin(), metric_actions.begin() + naction));
648 else if (naction > 0)
649 problem.action(wparameters, wactions);
650 nwork = metric ? this->add_vector(parameters, actions, metric_actions) : this->add_vector(parameters, actions);
651 }
652 while (this->end_iteration_needed()) {
653 if (nwork > 0) {
654 if (metric_diagonals) {
655 // parameters[0] and metric_actions[0] are overwritten to hand the diagonals to the preconditioner
656 m_handlers->rq().copy(parameters.at(0), *diagonals);
657 m_handlers->rq().copy(metric_actions.at(0), *metric_diagonals);
658 problem.precondition_with_metric(wrap(actions.begin(), actions.begin() + nwork),
659 this->working_set_eigenvalues(), parameters.at(0), metric_actions.at(0));
660 } else if (use_diagonals) {
661 // parameters[0] is overwritten to hand the diagonals to the preconditioner
662 m_handlers->rq().copy(parameters.at(0), *diagonals);
663 problem.precondition(wrap(actions.begin(), actions.begin() + nwork), this->working_set_eigenvalues(),
664 parameters.at(0));
665 } else
666 problem.precondition(wrap(actions.begin(), actions.begin() + nwork), this->working_set_eigenvalues());
667 }
668 nwork = this->end_iteration(parameters, actions);
669 }
671 log::Severity::Normal, log::Verbosity::Info, "Iteration completed ", [&] {
672 return typename log::IterationCompleted<scalar_type>::Payload{iter, roots, {m_errors.begin(), m_errors.end()}, current_values(),
673 std::size_t(std::max(nwork, 0))};
674 });
677 }
678 }
679
680 this->finalize();
681
684 }
685 // without any errors (e.g. no iteration was done) nothing is known to have converged, and roots without a solution
686 // in the subspace have no error; the non-linear solvers look for a single solution, whatever n_roots() is
687 const bool all_roots = m_errors.size() >= (this->nonlinear() ? 1 : n_roots());
688 const bool errors_converged = all_roots && !m_errors.empty() &&
689 *std::max_element(m_errors.begin(), m_errors.end()) <= m_convergence_threshold;
690 // roots also remain in the working set while their values change by more than the value threshold
691 const bool converged = nwork == 0 and errors_converged;
693 if (!all_roots && !m_errors.empty()) {
694 this->m_logger->warn("Subspace holds solutions for only ", m_errors.size(), " of ", n_roots(), " roots");
695 } else if (!errors_converged) {
696 this->m_logger->warn("Solver has not converged to threshold ", m_convergence_threshold);
697 } else if (!converged) {
698 this->m_logger->warn("Solver has not converged to value threshold ", m_convergence_threshold_value);
699 } else {
700 this->m_logger->info("Solver converged");
701 }
702 }
704 log::Severity::Normal, log::Verbosity::Debug, "Solve finished ", [&] {
706 {m_errors.begin(), m_errors.end()},
708 });
709 return converged;
710 }
711
717 void solution_impl(const std::vector<int>& roots, const VecRef<R>& parameters, const VecRef<R>& residual,
718 const VecRef<R>& scratch) {
719 solution_impl(roots, parameters, residual, scratch, [this](const auto&... args) { construct_residual(args...); });
720 }
721
726 template <typename ConstructResidual>
727 void solution_impl(const std::vector<int>& roots, const VecRef<R>& parameters, const VecRef<R>& residual,
729 // auto prof = profiler()->push("itsolv::solution"); // FIXME two profilers
730 auto prof = molpro::Profiler::single();
731 check_consistent_number_of_roots_and_solutions(roots, parameters.size());
732 construct_solutions(roots, m_subspace_solver->solutions(), parameters);
734 auto metric_solutions_q = std::vector<Q>{};
736 prof->start("apply metric");
737 const auto solutions = cwrap(parameters.begin(), parameters.begin() + roots.size());
738 const bool use_scratch = scratch.size() >= roots.size();
739 // without scratch vectors, the residuals hold the actions of the metric until they are copied
740 const auto metric_actions = use_scratch ? wrap(scratch.begin(), scratch.begin() + roots.size())
741 : wrap(residual.begin(), residual.begin() + roots.size());
742 m_apply_metric(solutions, metric_actions);
743 if (use_scratch) {
745 } else {
746 for (const auto& m : metric_actions)
747 metric_solutions_q.emplace_back(m_handlers->qr().copy(m));
748 m_stats->q_creations += metric_solutions_q.size();
750 }
751 prof->stop();
752 }
753 construct_actions(roots, m_subspace_solver->solutions(), residual);
754 prof->start("apply");
755 construct_residual_with(roots, cwrap(parameters), residual, metric_solutions);
757 prof->stop();
758 }
759
766 void construct_solutions(const std::vector<int>& rows, const subspace::Matrix<value_type>& solutions,
767 const VecRef<R>& parameters) {
768 auto prof = molpro::Profiler::single();
769 const auto& dims = m_xspace->dimensions();
770 prof->start("construct_solution (parameters)");
771 util::construct_solutions(parameters, rows, solutions, m_xspace->cparamsp(), m_xspace->cparamsq(),
772 m_xspace->cparamsd(), dims.oP(), dims.oQ(), dims.oD(), m_handlers->rr(),
773 m_handlers->rp(), m_handlers->rq());
774 prof->stop();
775 }
776
783 void construct_actions(const std::vector<int>& rows, const subspace::Matrix<value_type>& solutions,
784 const VecRef<R>& actions) {
785 auto prof = molpro::Profiler::single();
786 const auto& dims = m_xspace->dimensions();
787 prof->start("construct_solution (residual)");
788 util::construct_solutions(actions, rows, solutions, {}, m_xspace->cactionsq(), m_xspace->cactionsd(), dims.oP(),
789 dims.oQ(), dims.oD(), m_handlers->rr(), m_handlers->rp(), m_handlers->rq());
790 prof->stop();
791 prof->start("apply_p");
792 if (m_apply_p)
793 m_apply_p(detail::construct_vectorP(rows, solutions, dims.oP(), dims.nP), m_xspace->cparamsp(), actions);
794 prof->stop();
795 }
796
798 std::shared_ptr<subspace::ISubspaceSolver<R, Q, P>> solver,
799 std::shared_ptr<ArrayHandlers<R, Q, P>> handlers, std::shared_ptr<Statistics> stats,
800 std::shared_ptr<Logger> logger)
801 : m_handlers(std::move(handlers)), m_xspace(std::move(xspace)), m_subspace_solver(std::move(solver)),
802 m_stats(std::move(stats)), m_logger(std::move(logger)), m_profiler(molpro::Profiler::single()),
803 m_profiler_saved_depth(m_profiler->get_max_depth()) {
804 set_n_roots(1);
805 m_profiler->set_max_depth(options()->parameter("PROFILER_DEPTH", 0));
806 }
807
808 // The destructor is implicitly noexcept, so any exception from writing the profiler output would terminate the
809 // program. Report such failures and carry on.
811 try {
812 if (molpro::mpi::rank_global() == 0) {
813 auto file = options()->parameter("PROFILER_OUTPUT", "");
814 if (profiler()->get_max_depth() > 0 and
815 std::find_if(file.begin(), file.end(), [](unsigned char ch) { return !std::isspace(ch); }) != file.end())
816 std::ofstream(file) << *profiler() << std::endl;
817 }
818 if (molpro::mpi::rank_global() == 0) {
819 auto file = options()->parameter("PROFILER_DOTGRAPH", "");
820 if (profiler()->get_max_depth() > 0 and
821 std::find_if(file.begin(), file.end(), [](unsigned char ch) { return !std::isspace(ch); }) != file.end())
822 profiler()->dotgraph(file, options()->parameter("PROFILER_THRESHOLD", .01));
823 }
824 } catch (const std::exception& e) {
825 std::cerr << "~IterativeSolverTemplate: failed to write profiler output: " << e.what() << std::endl;
826 } catch (...) {
827 std::cerr << "~IterativeSolverTemplate: failed to write profiler output" << std::endl;
828 }
829 molpro::Profiler::single()->set_max_depth(m_profiler_saved_depth);
830 }
831
837 bool test_metric(const Problem<R>& problem, R& v0, R& v1, int verbosity, value_type_abs threshold) const {
838 bool success = true;
841 std::optional<std::pair<Q, Q>> u; // the first test parameter and its action of the metric
842 for (int instance = 0; instance < 2 && problem.test_parameters(instance, v0); ++instance) {
843 problem.metric_action({v0}, {v1});
844 const auto norm = util::norm(m_handlers->rr(), v0);
845 const auto norm_metric_action = util::norm(m_handlers->rr(), v1);
846 const auto vmv = m_handlers->rr().dot(v0, v1);
847 if (std::abs(vmv - conjugate(vmv)) / 2 > threshold * norm * norm_metric_action or
849 success = false;
850 if (verbosity > -1)
851 std::cout << "<v|M v> = " << vmv << " is not real" << (positive ? " and non-negative" : "") << std::endl;
852 }
853 if (u) {
854 const auto umv = conjugate(m_handlers->rq().dot(v1, u->first));
855 const auto muv = m_handlers->rq().dot(v0, u->second);
856 const auto scale = std::sqrt(std::abs(m_handlers->qq().dot(u->first, u->first)) *
857 std::abs(m_handlers->qq().dot(u->second, u->second))) *
858 norm * norm_metric_action;
859 const auto defect = std::abs(umv - conjugate(muv));
860 if (defect > threshold * std::sqrt(scale)) {
861 success = false;
862 if (verbosity > -1)
863 std::cout << "The metric is not Hermitian: <u|M v> = " << umv << ", <M u|v> = " << conjugate(muv)
864 << std::endl;
865 } else if (verbosity > 0)
866 std::cout << "Hermiticity defect of the metric: " << defect << std::endl;
867 } else
868 u.emplace(m_handlers->qr().copy(v0), m_handlers->qr().copy(v1));
869 }
870 return success;
871 }
872
874 virtual void combine_errors() {}
876 virtual void set_value_errors() {}
881 virtual void construct_residual(const std::vector<int>& roots, const CVecRef<R>& params, const VecRef<R>& actions,
888 virtual void compute_errors(const std::vector<int>& roots, const CVecRef<R>& params, const CVecRef<R>& residuals,
889 const std::vector<value_type_abs>& solution_norms, std::vector<value_type_abs>& errors) {
891 if (!solution_norms.empty())
892 for (size_t i = 0; i < roots.size(); ++i)
893 errors[i] /= solution_norms[roots[i]];
894 }
899 virtual void solution_with_errors(const std::vector<int>& roots, const VecRef<R>& parameters,
900 const VecRef<R>& residual, const VecRef<R>& scratch,
901 const std::vector<value_type_abs>& solution_norms,
902 std::vector<value_type_abs>& errors) {
903 solution_impl(roots, parameters, residual, scratch);
904 compute_errors(roots, cwrap(parameters), cwrap(residual), solution_norms, errors);
905 }
906 virtual bool linearEigensystem() const { return false; }
907
908 // FIXME Currently only works if called on an empty subspace. Either enforce it or generalise.
910 size_t add_p_impl(const CVecRef<P>& pparams, const array::Span<value_type>& pp_action_matrix,
911 const array::Span<value_type>& pp_metric_matrix, const VecRef<R>& parameters,
912 const VecRef<R>& actions, fapply_on_p_type apply_p) {
913 auto prof = profiler()->push("itsolv::add_p");
914 if (not pparams.empty() and pparams.size() < n_roots())
915 throw std::runtime_error("P space must be empty or at least as large as number of roots sought");
916 if (apply_p)
917 m_apply_p = std::move(apply_p);
918 m_xspace->update_pspace(pparams, pp_action_matrix, pp_metric_matrix);
919 m_metric_checker.reset_pspace();
920 auto working_set = solve_and_generate_working_set(parameters, actions);
922 return working_set;
923 }
924
930 const array::Span<value_type>& pp_metric_matrix) const {
931 const auto n = pparams.size();
932 if (kind == MetricKind::Identity || n == 0)
933 return;
934 if (pp_metric_matrix.size() != n * n)
935 throw std::invalid_argument("The metric matrix in the P space must have as many rows and columns as there are "
936 "P-space vectors");
938 return;
943 std::vector<value_type>(pp_metric_matrix.data(), pp_metric_matrix.data() + n * n), {n, n}),
945 }
946
949 if (!supports_metric(kind))
950 throw std::invalid_argument("This solver does not support the requested kind of metric");
953 if (m_xspace->dimensions().nX() != 0 && (kind != m_metric_kind || storage != m_metric_storage))
954 throw std::logic_error("The metric, or how its actions are obtained, cannot be changed once the subspace is not "
955 "empty");
956 }
957
965
967 size_t n_added_vectors(const VecRef<R>& parameters) const {
968 return std::min(m_working_set.size(), parameters.size());
969 }
970
976 int add_vector_impl(const VecRef<R>& parameters, const VecRef<R>& actions, const VecRef<R>& metric_actions) {
977 auto outer = profiler()->push("itsolv::add_vector");
978 auto prof = molpro::Profiler::single();
979 m_logger->trace("IterativeSolverTemplate::add_vector iteration = ", m_stats->iterations);
980 m_logger->debug("IterativeSolverTemplate::add_vector size of {params, actions, working_set} = ", parameters.size(),
981 actions.size(), m_working_set.size());
982 if (m_xspace->dimensions().nP != 0 && !m_apply_p)
983 throw std::runtime_error(
984 "Solver contains P space but no valid apply_p function. Make sure add_p was called correctly.");
985 if (m_xspace->dimensions().nP != 0 && m_xspace->stores_metric_actions() && !m_apply_metric_p)
986 throw std::runtime_error("Solver contains P space but no valid function applying the metric to it. Make sure "
987 "add_p was called correctly.");
988 auto nW = n_added_vectors(parameters);
989 auto cwparams = cwrap(begin(parameters), begin(parameters) + nW);
990 auto cwactions = cwrap(begin(actions), begin(actions) + nW);
991 m_stats->r_creations += nW;
992 // the actions of the metric beyond those of the added parameters are only scratch space
993 const auto cwmetric_actions =
994 metric_actions.empty() ? CVecRef<R>{} : cwrap(begin(metric_actions), begin(metric_actions) + nW);
997 prof->start("update_qspace");
999 m_stats->q_creations += (m_xspace->stores_metric_actions() ? 3 : 2) * nW;
1000 prof->stop();
1004 prof->start("solve_and_generate_working_set");
1005 // the actions of the metric are not needed any more and serve as scratch space
1006 auto working_set = solve_and_generate_working_set(parameters, actions, metric_actions);
1007 prof->stop();
1009 this->m_end_iteration_needed = true;
1010 return working_set;
1011 }
1020 size_t solve_and_generate_working_set(const VecRef<R>& parameters, const VecRef<R>& action,
1021 const VecRef<R>& scratch = {}) {
1022 auto prof = profiler();
1023 auto p = prof->push("itsolv::solve_and_generate_working_set");
1024 prof->start("itsolv::solve");
1026 m_solutions_outdated = false;
1027 prof->stop();
1028 prof->start("itsolv::temp_solutions");
1029 auto nsol = m_subspace_solver->size();
1030 std::vector<std::pair<Q, Q>> temp_solutions{};
1031 const auto batches = detail::parameter_batches(nsol, parameters.size());
1032 // The solutions of a problem with a metric are normalised in the metric, so their Euclidean length, and with it
1033 // the length of the residual, would depend on the scale of the metric. The error is that of the solution of unit
1034 // length instead, which is the same as without a metric.
1035 const auto solution_norms =
1036 m_xspace->metric_kind() != MetricKind::Identity
1038 : std::vector<value_type_abs>{};
1039 for (const auto& batch : batches) {
1040 auto [start_sol, end_sol] = batch;
1041 auto roots = std::vector<int>(end_sol - start_sol);
1042 std::iota(begin(roots), end(roots), start_sol);
1043 auto errors = std::vector<value_type_abs>(roots.size(), 0);
1044 solution_with_errors(roots, parameters, action, scratch, solution_norms, errors);
1045 if (batches.size() > 1) {
1046 for (size_t i = 0; i < roots.size(); ++i)
1047 temp_solutions.emplace_back(m_handlers->qr().copy(parameters[i]), m_handlers->qr().copy(action[i]));
1048 m_stats->q_creations += 2 * roots.size();
1049 }
1050 m_subspace_solver->set_error(roots, errors);
1051 }
1052 prof->stop();
1053 combine_errors();
1054 set_value_errors();
1055 m_errors = m_subspace_solver->errors();
1056 m_working_set = detail::select_working_set(parameters.size(), m_errors, m_convergence_threshold, m_value_errors,
1057 m_convergence_threshold_value);
1058 for (size_t i = 0; i < m_working_set.size(); ++i) {
1059 size_t root = m_working_set[i];
1060 if (batches.size() > 1) {
1061 m_handlers->rq().copy(parameters[i], temp_solutions.at(root).first);
1062 m_handlers->rq().copy(action[i], temp_solutions.at(root).second);
1063 } else {
1064 if (root < i)
1065 throw std::logic_error("incorrect ordering of roots");
1066 if (root > i && root < parameters.size()) {
1067 m_handlers->rr().copy(parameters[i], parameters[root]);
1068 m_handlers->rr().copy(action[i], action[root]);
1069 }
1070 }
1071 }
1072 m_logger->trace("add_vector::errors = ", m_errors);
1073 return m_working_set.size();
1074 }
1075
1076 template <typename TTT>
1077 void check_consistent_number_of_roots_and_solutions(const std::vector<TTT>& roots, const size_t nparams) {
1078 if (m_solutions_outdated)
1079 throw std::logic_error("solutions are not available after an end_iteration() that reset the D space; they are "
1080 "returned in its parameters and available again after the next add_vector()");
1081 if (roots.size() > nparams)
1082 throw std::runtime_error("asking for more roots than parameters");
1083 // there is a row of the solutions matrix for each solution
1084 if (!roots.empty() &&
1085 size_t(*std::max_element(roots.begin(), roots.end())) >= m_subspace_solver->solutions().rows())
1086 throw std::runtime_error("asking for more roots than there are solutions");
1087 }
1088
1089 bool end_iteration_needed() override { return m_end_iteration_needed; }
1090
1091 void finalize() override {}
1092
1094 bool verbosity_at_least(Verbosity v) const { return !m_verbosity.has_value() || m_verbosity >= v; }
1095
1102 void generate_initial_guess_from_diagonals(const VecRef<R>& parameters, const Q& diagonals) {
1103 // add_vector() takes up no more vectors than there are in the working set
1104 const auto nguess = std::min(parameters.size(), m_working_set.size());
1105 if (nguess == 0) {
1106 if (verbosity_at_least(Verbosity::Summary))
1107 this->m_logger->info("No initial guess generated, as no roots remain in the working set");
1108 return;
1109 }
1110 auto guess = m_handlers->qq().select(nguess, diagonals);
1111 size_t root = 0;
1112 if (verbosity_at_least(Verbosity::Summary))
1113 this->m_logger->info("Initial guess generated from diagonal elements for ", guess.size(), " vectors");
1114 for (const auto& g : guess) {
1115 m_handlers->rp().copy(parameters[root], P{{g.first, 1}});
1116 if (verbosity_at_least(Verbosity::Detailed)) {
1117 m_logger->debug("-> initial guess with index ", g.first);
1118 }
1119 root++;
1120 }
1121 }
1122
1128 std::vector<P> select_pspace(const Q& diagonals) {
1129 auto selectp = m_handlers->qq().select(m_max_p, diagonals);
1130 if (!selectp.empty()) {
1131 // selectp is keyed by index, not value; find the smallest selected
1132 // diagonal explicitly before applying the threshold.
1133 // the diagonal of a hermitian operator is real, so it is orderable
1134 auto min_val = real_part(std::min_element(selectp.begin(), selectp.end(),
1135 [](const auto& a, const auto& b) {
1136 return real_part(a.second) < real_part(b.second);
1137 })
1138 ->second);
1139 for (auto s = selectp.begin(); s != selectp.end();) {
1140 if (real_part(s->second) > min_val + m_p_threshold)
1141 s = selectp.erase(s);
1142 else
1143 ++s;
1144 }
1145 }
1146 if (!selectp.empty() && selectp.size() < n_roots()) {
1147 this->m_logger->warn("P space smaller than number of roots is not used, starting from the diagonal elements "
1148 "instead; dimension and number of roots",
1149 selectp.size(), n_roots());
1150 selectp.clear();
1151 }
1152 if (!selectp.empty() && verbosity_at_least(Verbosity::Summary)) {
1153 this->m_logger->info("P-space dimension, threshold and limit", selectp.size(), m_p_threshold, m_max_p);
1154 }
1155 if (verbosity_at_least(Verbosity::Detailed)) {
1156 for (const auto& s : selectp) {
1157 this->m_logger->debug(std::format("P space element {}: {:.6e}", s.first, double(real_part(s.second))));
1158 }
1159 }
1160 std::vector<P> pspace;
1161 for (const auto& s : selectp)
1162 pspace.emplace_back((P){{s.first, 1}});
1163 return pspace;
1164 }
1165
1167
1173 std::pair<std::vector<value_type>, std::vector<value_type>>
1174 pspace_problem_matrices(const std::vector<P>& pspace, const Problem<R>& problem, const bool metric,
1175 const bool store_metric_actions) const {
1176 if (pspace.empty())
1177 return {};
1178 auto matrices = std::make_pair(problem.pp_action_matrix(pspace), std::vector<value_type>{});
1179 if (metric) {
1180 matrices.second = problem.pp_metric_matrix(pspace);
1181 check_pspace_metric(problem.metric_kind(), cwrap(pspace),
1182 array::Span<value_type>(matrices.second.data(), matrices.second.size()));
1183 }
1185 problem.p_metric_action({}, cwrap(pspace), {});
1186 return matrices;
1187 }
1188
1190 size_t initialise_pspace(const std::vector<P>& pspace, const Problem<R>& problem,
1191 std::pair<std::vector<value_type>, std::vector<value_type>>& matrices,
1192 const VecRef<R>& parameters, const VecRef<R>& actions) {
1193 fapply_on_p_type apply_on_p = [&problem](const std::vector<std::vector<value_type>>& pcoeff,
1194 const CVecRef<P>& pparams, const VecRef<R>& actions) {
1195 problem.p_action(pcoeff, pparams, actions);
1196 };
1199 if (m_metric_kind == MetricKind::Identity)
1200 return add_p(cwrap(pspace), action_span, parameters, actions, apply_on_p);
1201 fapply_on_p_type apply_metric_on_p = [&problem](const std::vector<std::vector<value_type>>& pcoeff,
1202 const CVecRef<P>& pparams, const VecRef<R>& metric_actions) {
1204 };
1205 return add_p(cwrap(pspace), action_span, parameters, actions, apply_on_p,
1207 }
1208
1209 std::shared_ptr<ArrayHandlers<R, Q, P>> m_handlers;
1210 std::shared_ptr<subspace::IXSpace<R, Q, P>> m_xspace;
1211 std::shared_ptr<subspace::ISubspaceSolver<R, Q, P>> m_subspace_solver;
1212 std::vector<value_type_abs> m_errors;
1213 std::vector<value_type_abs> m_value_errors;
1214 std::vector<int> m_working_set;
1215 size_t m_nroots{0};
1216 value_type_abs m_convergence_threshold{1.0e-8};
1217 value_type_abs m_convergence_threshold_value{
1218 std::numeric_limits<value_type_abs>::max()};
1219 std::shared_ptr<Statistics> m_stats;
1220 std::shared_ptr<Logger> m_logger;
1221 fapply_on_p_type m_apply_p = {};
1222 std::optional<Verbosity> m_verbosity = {};
1223 int m_max_iter = 100;
1224 size_t m_max_p = 0;
1227 fapply_metric_type m_apply_metric = {};
1228 bool m_check_metric = true;
1230 fapply_on_p_type m_apply_metric_p = {};
1231 value_type_abs m_p_threshold = std::numeric_limits<value_type_abs>::max();
1232private:
1233 mutable std::shared_ptr<molpro::profiler::Profiler> m_profiler;
1234 int m_profiler_saved_depth;
1235protected:
1236 bool m_end_iteration_needed = true;
1237 bool m_solutions_outdated = false;
1238};
1239
1240} // namespace molpro::linalg::itsolv
1241
1242#endif // LINEARALGEBRA_SRC_MOLPRO_LINALG_ITSOLV_ITERATIVESOLVERTEMPLATE_H
Enhances various operations between pairs of arrays and allows dynamic code injection with uniform in...
Definition ArrayHandler.h:163
Non-owning container taking a pointer to the data buffer and its size and exposing routines for itera...
Definition Span.h:31
size_type size() const
Definition Span.h:80
iterator data()
Definition Span.h:69
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:187
std::vector< value_type_abs > m_value_errors
value errors from the most recent solution
Definition IterativeSolverTemplate.h:1213
void check_metric_positive()
For a positive (semi)definite metric, throws if the metric matrix shows that it is not,...
Definition IterativeSolverTemplate.h:959
void set_convergence_threshold(value_type_abs thresh) override
Definition IterativeSolverTemplate.h:389
void iteration_report() const
Definition IterativeSolverTemplate.h:372
MetricKind metric_kind() const override
Definition IterativeSolverTemplate.h:247
void set_profiler(std::shared_ptr< molpro::profiler::Profiler > profiler) override
Definition IterativeSolverTemplate.h:429
void set_profiler(molpro::profiler::Profiler &profiler) override
Definition IterativeSolverTemplate.h:425
std::optional< Verbosity > m_verbosity
how much output to print in solve()
Definition IterativeSolverTemplate.h:1222
value_type_abs m_p_threshold
threshold for selecting P space
Definition IterativeSolverTemplate.h:1231
size_t add_p(const CVecRef< P > &pparams, const array::Span< value_type > &pp_action_matrix, const VecRef< R > &parameters, const VecRef< R > &actions, fapply_on_p_type apply_p) override
Definition IterativeSolverTemplate.h:259
fapply_on_p_type m_apply_metric_p
adds the action of the metric on the P space, if its actions are stored
Definition IterativeSolverTemplate.h:1230
value_type_abs convergence_threshold_value() const override
Definition IterativeSolverTemplate.h:392
int get_max_iter() const override
Definition IterativeSolverTemplate.h:414
void solution_params(const std::vector< int > &roots, std::vector< R > &parameters) override
Definition IterativeSolverTemplate.h:294
void report(std::ostream &cout, bool endl=true) const override
Definition IterativeSolverTemplate.h:357
std::vector< int > m_working_set
indices of roots in the working set
Definition IterativeSolverTemplate.h:1214
value_type_abs convergence_threshold() const override
Definition IterativeSolverTemplate.h:390
void generate_initial_guess_from_diagonals(const VecRef< R > &parameters, const Q &diagonals)
Fills parameters with unit vectors at the positions of the lowest diagonal elements.
Definition IterativeSolverTemplate.h:1102
void summary_report() const
Definition IterativeSolverTemplate.h:378
scalar_type value() const override
Definition IterativeSolverTemplate.h:421
std::shared_ptr< subspace::IXSpace< R, Q, P > > m_xspace
manages the subspace and associated data
Definition IterativeSolverTemplate.h:1210
size_t initialise_pspace(const std::vector< P > &pspace, const Problem< R > &problem, std::pair< std::vector< value_type >, std::vector< value_type > > &matrices, const VecRef< R > &parameters, const VecRef< R > &actions)
Adds the P space to the subspace with the matrices of pspace_problem_matrices(); returns the working-...
Definition IterativeSolverTemplate.h:1190
void set_n_roots(size_t roots) override
Definition IterativeSolverTemplate.h:318
std::vector< scalar_type > current_values() const
The values reported in the iteration events: eigenvalues of eigensystems, the function value otherwis...
Definition IterativeSolverTemplate.h:437
bool solve_impl(const VecRef< R > &parameters, const VecRef< R > &actions, const VecRef< R > &metric_actions, const Problem< R > &problem, bool generate_initial_guess)
Implements both overloads of solve(), with empty metric_actions for a problem without a metric.
Definition IterativeSolverTemplate.h:542
std::shared_ptr< ArrayHandlers< R, Q, P > > m_handlers
Array handlers.
Definition IterativeSolverTemplate.h:1209
fapply_on_p_type m_apply_p
function that evaluates effect of action on the P space projection
Definition IterativeSolverTemplate.h:1221
virtual void compute_errors(const std::vector< int > &roots, const CVecRef< R > &params, const CVecRef< R > &residuals, const std::vector< value_type_abs > &solution_norms, std::vector< value_type_abs > &errors)
Computes the errors of roots, given their parameters and residuals; by default the norms of the resid...
Definition IterativeSolverTemplate.h:888
int add_vector_impl(const VecRef< R > &parameters, const VecRef< R > &actions, const VecRef< R > &metric_actions)
Implements add_vector()
Definition IterativeSolverTemplate.h:976
void solution(const std::vector< int > &roots, std::vector< R > &parameters, std::vector< R > &residual) override
Definition IterativeSolverTemplate.h:287
void set_max_iter(int n) override
Definition IterativeSolverTemplate.h:413
MetricKind m_metric_kind
the metric declared with set_metric()
Definition IterativeSolverTemplate.h:1225
void check_consistent_number_of_roots_and_solutions(const std::vector< TTT > &roots, const size_t nparams)
Definition IterativeSolverTemplate.h:1077
virtual void solution_with_errors(const std::vector< int > &roots, const VecRef< R > &parameters, const VecRef< R > &residual, const VecRef< R > &scratch, const std::vector< value_type_abs > &solution_norms, std::vector< value_type_abs > &errors)
Constructs the parameters and residuals of roots, as solution_impl() does, and computes their errors,...
Definition IterativeSolverTemplate.h:899
detail::MetricChecker< R, Q, P > m_metric_checker
checks the properties of the metric
Definition IterativeSolverTemplate.h:1229
virtual void prepare_solve(const Problem< R > &problem, const VecRef< R > &actions)
Prepares solving problem in solve(), after the problem has been checked and before the solver changes...
Definition IterativeSolverTemplate.h:539
void set_max_p(int n) override
Definition IterativeSolverTemplate.h:415
void construct_actions(const std::vector< int > &rows, const subspace::Matrix< value_type > &solutions, const VecRef< R > &actions)
Constructs the actions on the subspace vectors with the coefficients in the given rows of solutions.
Definition IterativeSolverTemplate.h:783
std::shared_ptr< subspace::ISubspaceSolver< R, Q, P > > m_subspace_solver
solves the subspace problem
Definition IterativeSolverTemplate.h:1211
void set_p_threshold(value_type_abs threshold) override
Definition IterativeSolverTemplate.h:417
std::vector< size_t > suggest_p(const CVecRef< R > &solution, const CVecRef< R > &residual, size_t max_number, value_type_abs threshold) override
Definition IterativeSolverTemplate.h:309
bool get_check_metric() const override
Definition IterativeSolverTemplate.h:249
int get_max_p() const override
Definition IterativeSolverTemplate.h:416
void solution_impl(const std::vector< int > &roots, const VecRef< R > &parameters, const VecRef< R > &residual, const VecRef< R > &scratch, ConstructResidual &&construct_residual_with)
Implements solution(), with the residuals constructed by the given function in place of construct_res...
Definition IterativeSolverTemplate.h:727
size_t n_roots() const override
Definition IterativeSolverTemplate.h:316
std::vector< value_type_abs > m_errors
errors from the most recent solution
Definition IterativeSolverTemplate.h:1212
std::shared_ptr< Options > get_options() const override
Definition IterativeSolverTemplate.h:341
bool m_solutions_outdated
whether the subspace was changed since the solutions of its problem were found
Definition IterativeSolverTemplate.h:1237
void solution_impl(const std::vector< int > &roots, const VecRef< R > &parameters, const VecRef< R > &residual, const VecRef< R > &scratch)
Implements solution()
Definition IterativeSolverTemplate.h:717
bool m_check_metric
whether the properties of the metric are checked
Definition IterativeSolverTemplate.h:1228
void construct_solutions(const std::vector< int > &rows, const subspace::Matrix< value_type > &solutions, const VecRef< R > &parameters)
Constructs the subspace vectors with the coefficients in the given rows of solutions.
Definition IterativeSolverTemplate.h:766
size_t m_max_p
maximum size of P space
Definition IterativeSolverTemplate.h:1224
const subspace::Dimensions & dimensions() const override
Access dimensions of the subspace.
Definition IterativeSolverTemplate.h:420
const std::shared_ptr< molpro::profiler::Profiler > & profiler() const override
Definition IterativeSolverTemplate.h:434
bool verbosity_at_least(Verbosity v) const
Whether output of verbosity v is printed in solve(); everything is printed if no verbosity was set.
Definition IterativeSolverTemplate.h:1094
bool test_metric(const Problem< R > &problem, R &v0, R &v1, int verbosity, value_type_abs threshold) const
Tests that the metric of a problem is Hermitian, <u|M v> = <M u|v>, and, if its kind says so,...
Definition IterativeSolverTemplate.h:837
bool supports_metric(MetricKind kind) const override
Definition IterativeSolverTemplate.h:230
IterativeSolverTemplate(std::shared_ptr< subspace::IXSpace< R, Q, P > > xspace, std::shared_ptr< subspace::ISubspaceSolver< R, Q, P > > solver, std::shared_ptr< ArrayHandlers< R, Q, P > > handlers, std::shared_ptr< Statistics > stats, std::shared_ptr< Logger > logger)
Definition IterativeSolverTemplate.h:797
std::vector< P > select_pspace(const Q &diagonals)
Selects the P space from the lowest diagonal elements, subject to max_p and p_threshold.
Definition IterativeSolverTemplate.h:1128
virtual ~IterativeSolverTemplate()
Definition IterativeSolverTemplate.h:810
int add_vector(std::vector< R > &parameters, std::vector< R > &actions) override
Definition IterativeSolverTemplate.h:252
bool test_problem(const Problem< R > &problem, R &v0, R &v1, int verbosity, value_type_abs threshold) const override
Definition IterativeSolverTemplate.h:469
void solution_params(R &parameters) override
Definition IterativeSolverTemplate.h:306
virtual bool linearEigensystem() const
Definition IterativeSolverTemplate.h:906
const Statistics & statistics() const override
Definition IterativeSolverTemplate.h:355
const std::vector< value_type_abs > & errors() const override
Definition IterativeSolverTemplate.h:353
void solution(R &parameters, R &residual) override
Definition IterativeSolverTemplate.h:290
size_t m_nroots
number of roots the solver is searching for
Definition IterativeSolverTemplate.h:1215
bool m_end_iteration_needed
whether end_iteration should be called after any preconditioner
Definition IterativeSolverTemplate.h:1236
void solution_params(const std::vector< int > &roots, const VecRef< R > &parameters) override
Definition IterativeSolverTemplate.h:298
std::pair< std::vector< value_type >, std::vector< value_type > > pspace_problem_matrices(const std::vector< P > &pspace, const Problem< R > &problem, const bool metric, const bool store_metric_actions) const
Adds the P space to the subspace using the P-space kernel provided by problem; returns the working-se...
Definition IterativeSolverTemplate.h:1174
void check_pspace_metric(MetricKind kind, const CVecRef< P > &pparams, const array::Span< value_type > &pp_metric_matrix) const
Throws if the metric matrix in the P space is not given for a metric of this kind,...
Definition IterativeSolverTemplate.h:929
int add_vector(const VecRef< R > &parameters, const VecRef< R > &actions) override
Definition IterativeSolverTemplate.h:215
void clearP() override
Definition IterativeSolverTemplate.h:281
bool solve(R &parameters, R &actions, const Problem< R > &problem, bool generate_initial_guess=false) override
Definition IterativeSolverTemplate.h:461
bool end_iteration_needed() override
Definition IterativeSolverTemplate.h:1089
MetricStorage metric_storage() const override
Definition IterativeSolverTemplate.h:250
IterativeSolverTemplate(const IterativeSolverTemplate< Solver, R, Q, P > &)=delete
size_t n_added_vectors(const VecRef< R > &parameters) const
The number of the given parameters that add_vector() takes up: no more than there are in the working ...
Definition IterativeSolverTemplate.h:967
MetricStorage m_metric_storage
how the actions of the metric are obtained
Definition IterativeSolverTemplate.h:1226
void report() const override
Definition IterativeSolverTemplate.h:384
const std::vector< int > & working_set() const override
Definition IterativeSolverTemplate.h:314
std::shared_ptr< Logger > m_logger
logger
Definition IterativeSolverTemplate.h:1220
void set_convergence_threshold_value(value_type_abs thresh) override
Definition IterativeSolverTemplate.h:391
virtual void set_value_errors()
Implementation class should overload this to set errors in the current values (e.g....
Definition IterativeSolverTemplate.h:876
bool solve(std::vector< R > &parameters, std::vector< R > &actions, const Problem< R > &problem, bool generate_initial_guess=false) override
Definition IterativeSolverTemplate.h:464
void set_logger(std::shared_ptr< Logger > logger) override
Definition IterativeSolverTemplate.h:203
void set_options(const Options &options) override
Definition IterativeSolverTemplate.h:324
size_t add_p(const CVecRef< P > &pparams, const array::Span< value_type > &pp_action_matrix, const VecRef< R > &parameters, const VecRef< R > &actions, fapply_on_p_type apply_p, const PSpaceMetric &metric) override
Definition IterativeSolverTemplate.h:268
int add_vector(const VecRef< R > &parameters, const VecRef< R > &actions, const VecRef< R > &metric_actions) override
Definition IterativeSolverTemplate.h:221
int add_vector(R &parameters, R &actions, value_type value=0) override
Definition IterativeSolverTemplate.h:255
value_type_abs m_convergence_threshold_value
value changes less than this mark a converged solution
Definition IterativeSolverTemplate.h:1217
virtual void combine_errors()
Implementation class can overload this to combine the errors of solutions, once those of all are know...
Definition IterativeSolverTemplate.h:874
size_t add_p_impl(const CVecRef< P > &pparams, const array::Span< value_type > &pp_action_matrix, const array::Span< value_type > &pp_metric_matrix, const VecRef< R > &parameters, const VecRef< R > &actions, fapply_on_p_type apply_p)
Implements add_p(), with an empty pp_metric_matrix for a problem without a metric.
Definition IterativeSolverTemplate.h:910
virtual void construct_residual(const std::vector< int > &roots, const CVecRef< R > &params, const VecRef< R > &actions, const detail::MetricSolutions< R, Q > &metric_solutions)=0
Constructs residual for given roots provided their parameters and actions.
void finalize() override
Definition IterativeSolverTemplate.h:1091
void set_verbosity(Verbosity v) override
Definition IterativeSolverTemplate.h:393
bool solve(const VecRef< R > &parameters, const VecRef< R > &actions, const Problem< R > &problem, bool generate_initial_guess=false) override
Definition IterativeSolverTemplate.h:446
bool solve(const VecRef< R > &parameters, const VecRef< R > &actions, const VecRef< R > &metric_actions, const Problem< R > &problem, bool generate_initial_guess=false) override
Definition IterativeSolverTemplate.h:454
void check_metric_change(MetricKind kind, MetricStorage storage) const
Throws if set_metric() with these arguments is not possible, apart from the function applying the met...
Definition IterativeSolverTemplate.h:948
void set_check_metric(bool check) override
Definition IterativeSolverTemplate.h:248
int m_max_iter
maximum number of iterations in solve()
Definition IterativeSolverTemplate.h:1223
std::shared_ptr< Statistics > m_stats
accumulates statistics of operations performed by the solver
Definition IterativeSolverTemplate.h:1219
size_t solve_and_generate_working_set(const VecRef< R > &parameters, const VecRef< R > &action, const VecRef< R > &scratch={})
Solves the subspace problems and selects the working set of roots, returning their parameters and res...
Definition IterativeSolverTemplate.h:1020
value_type_abs get_p_threshold() const override
Definition IterativeSolverTemplate.h:418
Logger & logger() override
Definition IterativeSolverTemplate.h:210
fapply_metric_type m_apply_metric
applies the metric on the fly, if its actions are not stored
Definition IterativeSolverTemplate.h:1227
value_type_abs m_convergence_threshold
residual norms less than this mark a converged solution
Definition IterativeSolverTemplate.h:1216
void set_verbosity(int v) override
Definition IterativeSolverTemplate.h:394
Verbosity get_verbosity() const override
Definition IterativeSolverTemplate.h:412
void solution(const std::vector< int > &roots, const VecRef< R > &parameters, const VecRef< R > &residual) override
Definition IterativeSolverTemplate.h:283
void set_metric(MetricKind kind, MetricStorage storage=MetricStorage::Stored, fapply_metric_type apply_metric={}) override
Definition IterativeSolverTemplate.h:232
IterativeSolverTemplate(IterativeSolverTemplate< Solver, R, Q, P > &&) noexcept=default
Interface for a specific iterative solver, it can add special member functions or variables.
Definition IterativeSolver.h:770
Logger class implementation. Provides (customizable) logging functionalities.
Definition Logger.h:370
Abstract class defining the problem-specific interface for the simplified solver interface to Iterati...
Definition IterativeSolver.h:125
virtual MetricKind metric_kind() const
The kind of metric M of the problem. Anything other than MetricKind::Identity turns the eigenproblem ...
Definition IterativeSolver.h:211
virtual void action(const CVecRef< R > &parameters, const VecRef< R > &action) const
Calculate the action of the kernel matrix on a set of parameters. Used by linear solvers,...
Definition IterativeSolver.h:149
virtual MetricStorage metric_storage() const
How IterativeSolver::solve() obtains the actions of the metric on its subspace vectors,...
Definition IterativeSolver.h:221
virtual void precondition(const VecRef< R > &residual, const std::vector< value_t > &shift) const
Apply preconditioning to a residual vector in order to predict a step towards the solution.
Definition IterativeSolver.h:175
virtual bool metric_diagonals(R &d) const
Provide the diagonal elements of the metric. For a problem with a metric that provides diagonals(),...
Definition IterativeSolver.h:256
virtual void p_metric_action(const std::vector< std::vector< value_t > > &p_coefficients, const CVecRef< P > &pparams, const VecRef< container_t > &metric_actions) const
Calculate the action of the metric on a set of vectors in the P space, for a problem with a metric (m...
Definition IterativeSolver.h:311
virtual bool diagonals(container_t &d) const
Optionally provide the diagonal elements of the underlying kernel. If implemented and returning true,...
Definition IterativeSolver.h:161
virtual void precondition_with_metric(const VecRef< R > &residual, const std::vector< value_t > &shift, const R &diagonals, const R &metric_diagonals) const
Apply preconditioning to a residual vector of a generalised eigenproblem. Used instead of preconditio...
Definition IterativeSolver.h:200
virtual void p_action(const std::vector< std::vector< value_t > > &p_coefficients, const CVecRef< P > &pparams, const VecRef< container_t > &actions) const
Calculate the action of the kernel matrix on a set of vectors in the P space.
Definition IterativeSolver.h:284
virtual std::vector< value_t > pp_action_matrix(const std::vector< P > &pparams) const
Calculate the kernel matrix in the P space.
Definition IterativeSolver.h:272
virtual void action_with_metric(const CVecRef< R > &parameters, const VecRef< R > &actions, const VecRef< R > &metric_actions) const
Calculate the actions of the kernel and of the metric on a set of parameters together....
Definition IterativeSolver.h:241
virtual void metric_action(const CVecRef< R > &parameters, const VecRef< R > &metric_actions) const
Calculate the action of the metric on a set of parameters. Called only if metric_kind() is not Metric...
Definition IterativeSolver.h:229
virtual value_t residual(const R &parameters, R &residual) const
Calculate the residual vector. Used by non-linear solvers (NonLinearEquations, Optimize) only.
Definition IterativeSolver.h:141
virtual bool test_parameters(unsigned int instance, R &parameters) const
Provide values of R vectors for testing the problem class. For use in a non-linear solver,...
Definition IterativeSolver.h:326
virtual std::vector< value_t > pp_metric_matrix(const std::vector< P > &pparams) const
Calculate the metric matrix in the P space, for a problem with a metric (metric_kind())
Definition IterativeSolver.h:295
Checks that the metric of a generalised problem has the properties that its kind declares,...
Definition MetricChecker.h:28
static void check_positive(const subspace::Matrix< value_type > &metric, const subspace::Matrix< value_type > &overlap)
Definition MetricChecker.h:177
void check_hermitian(const CVecRef< R > &params, const CVecRef< R > &metric_actions, const subspace::IXSpace< R, Q, P > &xspace, ArrayHandlers< R, Q, P > &handlers) const
Checks that the metric is Hermitian on new parameters before they are added to the subspace.
Definition MetricChecker.h:66
Full subspace.
Definition IXSpace.h:21
Matrix container that allows simple data access, slicing, copying and resizing without loosing data.
Definition Matrix.h:32
Restores the format flags and precision of a stream when it goes out of scope.
Definition util.h:156
static std::shared_ptr< Profiler > single()
std::vector< std::vector< T > > construct_vectorP(const std::vector< int > &roots, const subspace::Matrix< T > &solutions, const size_t oP, const size_t nP)
Definition IterativeSolverTemplate.h:47
std::vector< std::pair< size_t, size_t > > parameter_batches(const size_t nsol, const size_t nparam)
Definition IterativeSolverTemplate.h:26
std::vector< int > select_working_set(const size_t nw, const std::vector< T > &errors, const T threshold, const std::vector< T > &value_errors, const T value_threshold)
Definition IterativeSolverTemplate.h:66
void update_errors(std::vector< T > &errors, const CVecRef< R > &residual, array::ArrayHandler< R, R > &handler)
Definition IterativeSolverTemplate.h:59
void precondition_default(const VecRef< T > &action, const std::vector< S > &shift, const T &diagonals, const T *metric_diagonals, const bool regularise)
Definition IterativeSolver.h:44
decltype(std::abs(std::declval< Scalar >())) real_t
Definition Logger.h:89
std::string stringify(const T &t, std::size_t precision=default_precision)
Converts the given object into a string.
Definition Logger.h:178
auto overlap(const CVecRef< R > &left, const CVecRef< Q > &right, array::ArrayHandler< Z, W > &handler) -> std::enable_if_t< detail::Z_and_W_are_one_of_R_and_Q< R, Q, Z, W >, Matrix< typename array::ArrayHandler< Z, W >::value_type > >
Calculates overlap matrix between left and right vectors.
Definition util.h:57
std::vector< real_type_t< T > > solution_norms(const Matrix< T > &solutions, const Matrix< T > &overlap)
The Euclidean norms of the solutions x_i = sum_j c_ij b_j, from their subspace coefficients c (one ro...
Definition util.h:82
void construct_solutions(const VecRef< R > &params, const std::vector< int > &roots, const subspace::Matrix< value_type > &solutions, const CVecRef< P > &pparams, const CVecRef< Q > &qparams, const CVecRef< Q > &dparams, size_t oP, size_t oQ, size_t oD, array::ArrayHandler< R, R > &handler_rr, array::ArrayHandler< R, P > &handler_rp, array::ArrayHandler< R, Q > &handler_rq)
Construct solutions.
Definition util.h:82
auto norm(array::ArrayHandler< R, R > &handler, const std::type_identity_t< R > &x) -> typename array::ArrayHandler< R, R >::value_type_abs
The length of x, sqrt(|<x|x>|), which is real also for complex values.
Definition util.h:21
4-parameter interpolation of a 1-dimensional function given two points for which function values and ...
Definition helper.h:14
auto cwrap(ForwardIt begin, ForwardIt end)
Takes a begin and end iterators and returns a vector of references to each element.
Definition wrap.h:52
auto wrap_arg(T &&arg, S &&... args) -> std::enable_if_t< std::conjunction_v< std::is_same< decay_t< T >, decay_t< S > >... >, VecRef< decay_t< T > > >
Constructs a vector of reference wrappers with provided arguments.
Definition wrap.h:135
std::unique_ptr< LinearEigensystem< R, Q, P > > create_LinearEigensystem(const LinearEigensystemOptions &options, const std::shared_ptr< ArrayHandlers< R, Q, P > > &handlers=std::make_shared< molpro::linalg::itsolv::ArrayHandlers< R, Q, P > >())
Definition SolverFactory.h:111
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
MetricStorage
How a solver obtains the actions of a metric on its subspace vectors, see IterativeSolver::set_metric...
Definition Metric.h:21
@ Stored
the actions of the metric on all subspace vectors are kept
@ OnTheFly
the metric is applied to the solutions whenever residuals are constructed
std::vector< std::reference_wrapper< A > > VecRef
Definition wrap.h:11
Verbosity
Specifies how much detail IterativeSolver::solve should write to output.
Definition Options.h:12
@ Summary
only summary at the start and end of solve
@ Detailed
Iteration plus more detail such as operation count.
@ Iteration
Summary plus minimal results at each iteration.
MetricKind
The kind of metric M of a generalised problem, such as the eigenproblem A v = lambda M v.
Definition Metric.h:13
@ HermitianPositiveSemidefinite
Hermitian and positive semidefinite, i.e. possibly singular.
@ HermitianPositiveDefinite
Hermitian and positive definite, e.g. the overlap matrix of a non-orthogonal basis.
@ Identity
M = 1, i.e. no metric.
void read_handler_counts(std::shared_ptr< Statistics > stats, std::shared_ptr< ArrayHandlers< R, Q, P > > handlers)
Definition Statistics.h:30
real_type_t< T > real_part(const T &x)
The real part of a scalar; the value itself for a real type.
Definition scalar_traits.h:58
T conjugate(const T &x)
Complex conjugate, staying within the scalar type; the identity for a real type.
Definition scalar_traits.h:47
const std::shared_ptr< const molpro::Options > options()
Get the Options object associated with iterative-solver.
Definition linalg_options.cpp:4
Access point for different options in iterative solvers.
Definition Options.h:20
The metric of a problem in the P space, for IterativeSolver::add_p()
Definition IterativeSolver.h:335
Information about performance of IterativeSolver instance.
Definition Statistics.h:10
The actions of a metric applied on the fly on solutions, in R vectors or, if there are not enough of ...
Definition IterativeSolverTemplate.h:40
CVecRef< R > r
Definition IterativeSolverTemplate.h:41
CVecRef< Q > q
Definition IterativeSolverTemplate.h:42
bool empty() const
Definition IterativeSolverTemplate.h:43
Definition IterativeSolverTemplate.h:131
std::vector< real_t< Scalar > > errors
current errors of all roots
Definition IterativeSolverTemplate.h:134
std::vector< int > roots
roots whose vectors were worked on in this iteration
Definition IterativeSolverTemplate.h:133
int iter
0-based iteration number
Definition IterativeSolverTemplate.h:132
std::vector< Scalar > values
Definition IterativeSolverTemplate.h:135
std::size_t n_next
number of vectors to work on in the next iteration (0 if done)
Definition IterativeSolverTemplate.h:137
Definition IterativeSolverTemplate.h:129
static std::string format(const Payload &p)
Definition IterativeSolverTemplate.h:139
static constexpr std::string_view name
Definition IterativeSolverTemplate.h:130
Definition IterativeSolverTemplate.h:168
Definition IterativeSolverTemplate.h:166
static constexpr std::string_view name
Definition IterativeSolverTemplate.h:167
Definition IterativeSolverTemplate.h:117
std::vector< int > roots
Definition IterativeSolverTemplate.h:119
int iter
0-based iteration number
Definition IterativeSolverTemplate.h:118
Definition IterativeSolverTemplate.h:115
static std::string format(const Payload &p)
Definition IterativeSolverTemplate.h:122
static constexpr std::string_view name
Definition IterativeSolverTemplate.h:116
Definition IterativeSolverTemplate.h:151
std::vector< Scalar > values
see IterationCompleted::Payload::values
Definition IterativeSolverTemplate.h:155
bool converged
same as the return value of solve()
Definition IterativeSolverTemplate.h:153
std::vector< real_t< Scalar > > errors
final errors of all roots
Definition IterativeSolverTemplate.h:154
int iterations
number of iterations performed
Definition IterativeSolverTemplate.h:152
Definition IterativeSolverTemplate.h:149
static std::string format(const Payload &p)
Definition IterativeSolverTemplate.h:157
static constexpr std::string_view name
Definition IterativeSolverTemplate.h:150
Definition IterativeSolverTemplate.h:96
real_t< Scalar > convergence_threshold
threshold on the errors
Definition IterativeSolverTemplate.h:99
int max_iter
maximum number of iterations
Definition IterativeSolverTemplate.h:98
std::size_t n_roots
number of roots sought
Definition IterativeSolverTemplate.h:97
std::size_t pspace_size
dimension of the P space (0 if none is used)
Definition IterativeSolverTemplate.h:100
bool initial_guess_generated
whether an initial guess was generated from the diagonal elements
Definition IterativeSolverTemplate.h:101
Definition IterativeSolverTemplate.h:94
static constexpr std::string_view name
Definition IterativeSolverTemplate.h:95
static std::string format(const Payload &p)
Definition IterativeSolverTemplate.h:103
Definition IterativeSolverTemplate.h:176
Definition IterativeSolverTemplate.h:174
static constexpr std::string_view name
Definition IterativeSolverTemplate.h:175
Manages solution of the subspace problem and storage of those solutions.
Definition ISubspaceSolver.h:21