iterative-solver 0.0
 
Loading...
Searching...
No Matches
propose_rspace.h
1#ifndef LINEARALGEBRA_SRC_MOLPRO_LINALG_ITSOLV_PROPOSE_RSPACE_H
2#define LINEARALGEBRA_SRC_MOLPRO_LINALG_ITSOLV_PROPOSE_RSPACE_H
3#include <Eigen/Dense>
4#include <molpro/linalg/itsolv/IterativeSolver.h>
5#include <molpro/linalg/itsolv/helper.h>
6#include <molpro/linalg/itsolv/qspace_options.h>
7#include <molpro/linalg/itsolv/rspace_options.h>
8#include <molpro/linalg/itsolv/subspace/Dimensions.h>
9#include <molpro/linalg/itsolv/subspace/ISubspaceSolver.h>
10#include <molpro/linalg/itsolv/subspace/IXSpace.h>
11#include <molpro/linalg/itsolv/subspace/QSpace.h>
12#include <molpro/linalg/itsolv/subspace/gram_schmidt.h>
13#include <molpro/linalg/itsolv/subspace/util.h>
14#include <molpro/linalg/itsolv/util.h>
15#include <molpro/linalg/itsolv/wrap_util.h>
16#include <molpro/profiler/Profiler.h>
17
18#include <algorithm>
19#include <cassert>
20#include <cmath>
21#include <cstddef>
22#include <format>
23#include <functional>
24#include <limits>
25#include <ranges>
26#include <utility>
27#include <vector>
28
30
31// Normalises each parameter to unit length, leaving alone only vectors whose length is zero or too small to invert.
32// The threshold must not depend on the scale of the problem: a preconditioned residual can legitimately be very short
33// (for example with a large diagonal), and whether it is redundant is decided afterwards from the overlap of
34// normalised vectors.
35template <class R>
36void normalise(VecRef<R>& params, array::ArrayHandler<R, R>& handler, Logger& logger,
38 1 / std::numeric_limits<typename array::ArrayHandler<R, R>::value_type_abs>::max()) {
39 for (auto& p : params) {
40 const auto dot = util::norm(handler, p);
41 if (dot > thresh and std::isfinite(dot)) {
42 handler.scal(1. / dot, p);
43 } else {
44 logger.warn("parameter's length is too small for normalisation, dot = " + std::format("{:.2e}", double(dot)));
45 }
46 }
47}
48
50template <class R, class Q, class P, typename Index>
51void erase_qspace(subspace::IXSpace<R, Q, P>& xspace, std::vector<Index> indices) {
52 std::sort(begin(indices), end(indices), std::greater<Index>());
53 for (auto i : indices)
54 xspace.eraseq(i);
55}
56
57namespace dspace {
58
65inline std::vector<std::size_t> projected_solutions_basis(const subspace::Dimensions& dims,
66 const std::vector<std::size_t>& remove_qspace) {
67 auto basis = std::vector<std::size_t>{};
68 for (auto iq : remove_qspace)
69 basis.push_back(dims.oQ() + iq);
70 for (size_t k = 0; k < dims.nD; ++k)
71 basis.push_back(dims.oD() + k);
72 return basis;
73}
74
83template <typename value_type>
85 const std::vector<std::size_t>& remove_qspace, Logger& logger) {
86 logger.trace("construct_projected_solution()");
87 const auto nQd = remove_qspace.size();
88 const auto nSol = solutions.rows();
91 for (size_t i = 0; i < nSol; ++i)
92 for (size_t j = 0; j < basis.size(); ++j)
93 solutions_proj(i, j) = solutions(i, basis[j]);
94 logger.debug("nSol, nQd, nD", nSol, nQd, dims.nD);
95 return solutions_proj;
96}
97
110template <typename value_type>
112 const subspace::Matrix<value_type>& overlap, const std::vector<std::size_t>& basis,
113 const std::vector<std::size_t>& indices) {
114 assert(solutions_proj.cols() == basis.size());
115 const auto nSol = solutions_proj.rows();
116 auto ov = subspace::Matrix<value_type>({nSol, indices.size()});
117 for (size_t i = 0; i < nSol; ++i)
118 for (size_t m = 0; m < indices.size(); ++m)
119 for (size_t k = 0; k < basis.size(); ++k)
120 ov(i, m) += conjugate(solutions_proj(i, k)) * overlap(basis[k], indices[m]);
121 return ov;
122}
123
135template <typename value_type>
137 const subspace::Matrix<value_type>& overlap, const std::vector<std::size_t>& basis) {
138 const auto nSol = solutions_proj.rows();
141 for (size_t i = 0; i < nSol; ++i) {
142 for (size_t j = 0; j <= i; ++j) {
143 for (size_t l = 0; l < basis.size(); ++l)
144 ov(i, j) += xu(i, l) * solutions_proj(j, l);
145 ov(j, i) = conjugate(ov(i, j));
146 }
147 }
148 return ov;
149}
150
160template <typename value_type>
162 const subspace::Matrix<value_type>& overlap,
164 const std::vector<std::size_t>& remove_qspace, Logger& logger) {
165 logger.trace("construct_projected_solution_overlap()");
167}
168
176template <typename value_type, typename value_type_abs>
178 const value_type_abs norm_thresh, Logger& logger) {
179 logger.trace("remove_null_norm_and_normalise()");
180 const auto nSol = parameters.rows();
181 auto norm_proj = std::vector<value_type_abs>(nSol, 0.);
182 for (size_t i = 0; i < nSol; ++i)
183 norm_proj[i] = std::sqrt(std::abs(overlap(i, i)));
184 for (size_t i = 0, j = 0; i < nSol; ++i) {
185 if (norm_proj[i] > norm_thresh) {
186 parameters.row(j).scal(1. / norm_proj[i]);
187 overlap.col(j).scal(1. / norm_proj[i]);
188 overlap.row(j).scal(1. / norm_proj[i]);
189 ++j;
190 } else {
191 parameters.remove_row(j);
192 overlap.remove_row_col(j, j);
193 std::stringstream ss;
194 ss << std::setprecision(3) << "remove projected solution parameter i = " << i << ", norm = " << norm_proj[i];
195 logger.info(ss.str());
196 }
197 }
198 logger.data_dump("norm = ", norm_proj);
199 logger.data_dump("parameters after normalisation = ", parameters);
200 logger.data_dump("overlap of parameters = ", overlap);
201}
202
215template <typename value_type, typename value_type_abs>
217 const subspace::Matrix<value_type>& overlap_proj, const value_type_abs svd_thresh,
218 Logger& logger) {
219 logger.trace("remove_null_projected_solutions()");
220 logger.debug("nS on entry = ", solutions_proj.rows());
221 value_type* m = const_cast<std::vector<value_type>&>(overlap_proj.data()).data();
222 auto svd_vecs = svd_system(overlap_proj.rows(), overlap_proj.cols(), array::Span(m, overlap_proj.size()),
223 std::numeric_limits<value_type_abs>::max(), true);
224 svd_vecs.remove_if([&svd_thresh](const auto& el) { return real_part(el.value) < svd_thresh; });
225 svd_vecs.sort([](const auto& lt, const auto& rt) { return real_part(lt.value) < real_part(rt.value); });
226 const auto nD = svd_vecs.size();
227 const auto nX = solutions_proj.cols();
229 auto svd = svd_vecs.begin();
230 for (size_t i = 0; i < nD; ++i, ++svd)
231 for (size_t j = 0; j < overlap_proj.cols(); ++j)
232 for (size_t k = 0; k < nX; ++k)
233 solutions_stable(i, k) += svd->v[j] * solutions_proj(j, k);
234 logger.debug("nS without null space = ", solutions_stable.rows());
235 return solutions_stable;
236}
237
250template <typename value_type, typename value_type_abs>
253 const std::vector<std::size_t>& remove_qspace, const value_type_abs norm_thresh,
254 const value_type_abs svd_thresh, Logger& logger) {
261 return solutions_proj;
262}
263
273template <typename value_type>
275 const subspace::Dimensions& dims, const std::vector<std::size_t>& remove_qspace,
276 const subspace::Matrix<value_type>& overlap, const size_t nR) {
277 const auto nDnew = solutions_proj.rows();
278 const auto nQd = remove_qspace.size();
279 const auto nQ = dims.nQ - nQd;
280 auto ov = overlap;
281 for (size_t i = 0; i < dims.nD; ++i) {
282 ov.remove_row_col(dims.oD(), dims.oD());
283 }
284 auto is_Qdelete = [&remove_qspace](size_t i) {
285 return std::find(begin(remove_qspace), end(remove_qspace), i) != end(remove_qspace);
286 };
287 for (size_t i = 0, j = 0; i < dims.nQ; ++i) {
288 if (is_Qdelete(i))
289 ov.remove_row_col(dims.oQ() + j, dims.oQ() + j);
290 else
291 ++j;
292 }
293 const auto oDnew = dims.nP + nQ + nR;
294 ov.resize({oDnew + nDnew, oDnew + nDnew});
295 // subspace indices of the remaining P+Q+R vectors, in their order in ov
296 auto remaining = std::vector<std::size_t>{};
297 for (size_t j = 0; j < dims.nP; ++j)
298 remaining.push_back(dims.oP() + j);
299 for (size_t j = 0; j < dims.nQ; ++j)
300 if (!is_Qdelete(j))
301 remaining.push_back(dims.oQ() + j);
302 for (size_t j = 0; j < nR; ++j)
303 remaining.push_back(dims.nX() + j);
304 assert(remaining.size() == oDnew);
308 for (size_t i = 0; i < nDnew; ++i) {
309 for (size_t j = 0; j < oDnew; ++j) {
310 ov(oDnew + i, j) = ov_xv(i, j);
311 ov(j, oDnew + i) = conjugate(ov_xv(i, j));
312 }
313 for (size_t j = 0; j < nDnew; ++j)
314 ov(oDnew + i, oDnew + j) = ov_xx(i, j);
315 }
316 return ov;
317}
318} // namespace dspace
319
332template <class R, class Q, class P, typename value_type>
334 const CVecRef<P>& pparams, const CVecRef<Q>& qparams, const CVecRef<Q>& dparams,
336 logger.trace("append_overlap_with_r()");
337 const auto nP = pparams.size(), nQ = qparams.size(), nD = dparams.size(), nN = params.size();
338 const auto nX = nP + nQ + nD + nN;
339 const auto oP = 0;
340 const auto oQ = oP + nP;
341 const auto oD = oQ + nQ;
342 const auto oN = oD + nD;
343 auto ov = overlap;
344 ov.resize({nX, nX}); // solutions are last
345 ov.slice({oN, oN}, {oN + nN, oN + nN}) = subspace::util::overlap(params, handlers.rr());
346 ov.slice({oN, oP}, {oN + nN, oP + nP}) = subspace::util::overlap(params, pparams, handlers.rp());
347 ov.slice({oN, oQ}, {oN + nN, oQ + nQ}) = subspace::util::overlap(params, qparams, handlers.rq());
348 ov.slice({oN, oD}, {oN + nN, oD + nD}) = subspace::util::overlap(params, dparams, handlers.rq());
349 auto copy_upper_to_lower = [&ov, oN, nN](size_t oX, size_t nX) {
350 for (size_t i = 0; i < nX; ++i)
351 for (size_t j = 0; j < nN; ++j)
352 ov(oX + i, oN + j) = ov(oN + j, oX + i);
353 };
354 copy_upper_to_lower(oP, nP);
355 copy_upper_to_lower(oQ, nQ);
356 copy_upper_to_lower(oD, nD);
357 logger.data_dump("full overlap P+Q+D+R = ", ov);
358 return ov;
359}
360
366template <class R, class Q, class P, typename value_type>
373
382template <typename value_type>
383std::vector<std::size_t> limit_qspace_size(const subspace::Dimensions& dims, const QSpaceOptions& opts,
384 const subspace::Matrix<value_type>& solutions, Logger& logger) {
385 using value_type_abs = decltype(std::abs(solutions(0, 0)));
386 using contrib_pair = std::pair<std::size_t, value_type_abs>;
387 using std::begin;
388 using std::end;
389
390 logger.trace("limit_qspace_size()");
391
392 assert(opts.max_size >= opts.min_size);
393
394 const bool must_trim_size = dims.nQ > opts.max_size;
395 const bool may_trim_size = dims.nQ > opts.min_size && opts.contrib_thresh > 0;
396
397 if (!must_trim_size && !may_trim_size) {
398 return {};
399 }
400
401 const std::size_t min_deletions = must_trim_size ? dims.nQ - opts.max_size : 0;
402 const std::size_t max_deletions = dims.nQ - opts.min_size;
403
404 std::vector<std::size_t> q_delete;
405 q_delete.reserve(min_deletions);
406
407 const std::size_t nSol = solutions.rows();
408
409 std::vector<contrib_pair> max_contrib_to_solution;
411
412 for (std::size_t idx : std::ranges::views::iota(std::size_t(0), dims.nQ)) {
413 max_contrib_to_solution.emplace_back(std::make_pair(idx, value_type_abs(0)));
414
415 for (size_t j = 0; j < nSol; ++j) {
416 const value_type_abs current = std::abs(solutions(j, dims.oQ() + idx));
417 max_contrib_to_solution.back().second = std::max(max_contrib_to_solution.back().second, current);
418 }
419 }
420
421 std::ranges::sort(max_contrib_to_solution, std::less<>{}, &contrib_pair::second);
422
423 logger.trace("contribution to solutions =",
424 max_contrib_to_solution | std::ranges::views::transform([](const contrib_pair& p) { return p.second; }));
425
426 for (auto [idx, contrib] : max_contrib_to_solution) {
427 if (q_delete.size() == max_deletions || (q_delete.size() >= min_deletions && contrib >= opts.contrib_thresh)) {
428 break;
429 }
430
431 if (opts.contrib_thresh != 0 && contrib >= opts.contrib_thresh) {
432 logger.warn("deleted Q vector with max. contribution = ", contrib);
433 } else {
434 logger.debug("deleted Q vector with max. contribution = ", contrib);
435 }
436
437 q_delete.emplace_back(idx);
438 }
439
440 return q_delete;
441}
442
456template <class R, class Q, class P, typename value_type, typename value_type_abs>
458 const std::vector<std::size_t>& q_delete, const value_type_abs norm_thresh,
459 const value_type_abs svd_thresh, array::ArrayHandler<Q, Q>& handler, Logger& logger) {
460 const auto dims = xspace.dimensions();
461 const auto overlap = xspace.data.at(subspace::EqnData::S);
462 auto solutions_proj =
463 dspace::stable_projected_solutions(solutions, overlap, dims, q_delete, norm_thresh, svd_thresh, logger);
464#ifndef NDEBUG
465 // a decomposition of the whole subspace overlap, wanted only by this check
468 array::Span(&overlap_full_subspace(0, 0), overlap_full_subspace.size()), svd_thresh, true);
469 assert(svd_vecs.empty() && "P+Q+D subspace should be stable by construction");
470#endif
471 const auto nD = solutions_proj.rows();
472 const auto nQd = q_delete.size();
473 assert(nQd + dims.nD == solutions_proj.cols());
474 const auto& qparams = xspace.cparamsq();
475 const auto& qactions = xspace.cactionsq();
476 const auto& dparams = xspace.cparamsd();
477 const auto& dactions = xspace.cactionsd();
478 const bool metric = xspace.stores_metric_actions();
479 const auto& qmetric_actions = xspace.cmetric_actionsq();
480 const auto& dmetric_actions = xspace.cmetric_actionsd();
481 // The new D vectors are normalised by scaling their coefficients, with norms from the overlap of the vectors they are
482 // combinations of, so that no pass over the new vectors is needed for it.
483 {
484 auto basis = std::vector<size_t>{};
485 for (auto iq : q_delete)
486 basis.push_back(dims.oQ() + iq);
487 for (size_t k = 0; k < dims.nD; ++k)
488 basis.push_back(dims.oD() + k);
489 auto overlap_basis = subspace::Matrix<value_type>({basis.size(), basis.size()});
490 for (size_t j = 0; j < basis.size(); ++j)
491 for (size_t k = 0; k < basis.size(); ++k)
492 overlap_basis(j, k) = overlap(basis[j], basis[k]);
494 for (size_t i = 0; i < nD; ++i) {
495 if (norms[i] < norm_thresh) {
496 logger.warn(std::format("construct_dspace: skipping normalisation of D vector {} with near-zero norm = {:.2e}",
497 i, double(norms[i])));
498 continue;
499 }
500 for (size_t j = 0; j < solutions_proj.cols(); ++j)
501 solutions_proj(i, j) /= value_type(norms[i]);
502 }
503 }
505 if (nD > 0) {
506 const Q& q = !qparams.empty() ? qparams.front().get() : dparams.front().get();
507 for (size_t i = 0; i < nD; ++i) {
508 dparams_new.emplace_back(util::construct_zeroed_copy(q, handler));
509 dactions_new.emplace_back(util::construct_zeroed_copy(q, handler));
510 if (metric)
511 dmetric_actions_new.emplace_back(util::construct_zeroed_copy(q, handler));
512 }
513 // coefficient matrix with Q_{delete} and D vectors in rows and new D vectors in columns, as required by gemm_outer
514 auto coeff = subspace::Matrix<value_type>({nQd + dims.nD, nD});
515 for (size_t i = 0; i < nD; ++i)
516 for (size_t j = 0; j < nQd + dims.nD; ++j)
517 coeff(j, i) = solutions_proj(i, j);
518 // Q_{delete} followed by D, as the columns of solutions_proj, so that one call per output passes over each new
519 // vector only once
521 for (auto iq : q_delete) {
522 qd_params.emplace_back(qparams.at(iq));
523 qd_actions.emplace_back(qactions.at(iq));
524 if (metric)
525 qd_metric_actions.emplace_back(qmetric_actions.at(iq));
526 }
527 qd_params.insert(qd_params.end(), dparams.begin(), dparams.end());
528 qd_actions.insert(qd_actions.end(), dactions.begin(), dactions.end());
530 const auto wdparams_new = wrap(dparams_new);
531 const auto wdactions_new = wrap(dactions_new);
534 if (metric) {
537 }
538 }
539 return std::make_tuple(std::move(dparams_new), std::move(dactions_new), std::move(dmetric_actions_new),
540 std::move(solutions_proj));
541}
542
563template <class R, class Q, class P, typename value_type, typename value_type_abs>
566 const CVecRef<P>& pparams, const CVecRef<Q>& qparams, const CVecRef<Q>& dparams,
567 const value_type_abs norm_thresh, ArrayHandlers<R, Q, P>& handlers,
568 Logger& logger) {
569 logger.trace("project_out_and_orthonormalise()");
570 const auto nR = rparams.size(), nP = pparams.size(), nQ = qparams.size(), nD = dparams.size();
571 assert(nP == dims.nP && nQ == dims.nQ && nD == dims.nD);
572 assert(rx_overlap.rows() == nR && rx_overlap.cols() == dims.nX());
573 // Project the new parameters out of the span of P+Q+D. The existing vectors need not be orthogonal to each other
574 // (for example user-supplied initial guesses), so subtract V S^{-1} V^dagger r rather than projecting on each vector
575 // separately.
576 auto prof = molpro::Profiler::single();
577 prof->start("orthoganalise");
578 const auto nX = nP + nQ + nD;
579 if (nR > 0 and nX > 0) {
580 using EMatrix = Eigen::Matrix<value_type, Eigen::Dynamic, Eigen::Dynamic>;
581 EMatrix S(nX, nX);
582 for (size_t i = 0; i < nX; ++i)
583 for (size_t j = 0; j < nX; ++j)
584 S(i, j) = overlap(i, j);
585 // equilibrate, so that vectors of very different lengths do not make S needlessly ill-conditioned
586 Eigen::Vector<value_type, Eigen::Dynamic> scale(nX);
587 for (size_t i = 0; i < nX; ++i)
588 scale(i) = std::abs(S(i, i)) > 0 ? 1 / std::sqrt(std::abs(S(i, i))) : 0;
589 const auto Sinv = (scale.asDiagonal() * S * scale.asDiagonal()).eval().completeOrthogonalDecomposition();
590 // the projection needs <x_i|r_j>, the conjugate of the overlaps already calculated
591 EMatrix dots(nX, nR);
592 for (size_t i = 0; i < nX; ++i)
593 for (size_t j = 0; j < nR; ++j)
595 const EMatrix y = scale.asDiagonal() * Sinv.solve(scale.asDiagonal() * dots);
596 auto subtract = [&y, &rparams, nR](const auto& xparams, auto& handler, size_t o, size_t n) {
597 if (n == 0)
598 return;
600 for (size_t i = 0; i < n; ++i)
601 for (size_t j = 0; j < nR; ++j)
602 coeff(i, j) = -y(o + i, j);
603 handler.gemm_outer(coeff, xparams, rparams);
604 };
605 subtract(pparams, handlers.rp(), dims.oP(), nP);
606 subtract(qparams, handlers.rq(), dims.oQ(), nQ);
607 subtract(dparams, handlers.rq(), dims.oD(), nD);
608 }
609 prof->stop();
610 prof->start("get null_params");
611 auto null_params = std::vector<int>{};
612 for (size_t i = 0; i < nR; ++i) {
613 auto norm = util::norm(handlers.rr(), rparams[i]);
614 if (norm > norm_thresh) {
615 handlers.rr().scal(1. / norm, rparams[i]);
616 for (size_t j = i + 1; j < nR; ++j) {
617 auto ov = handlers.rr().dot(rparams[i], rparams[j]);
618 handlers.rr().axpy(-ov, rparams[i], rparams[j]);
619 }
620 } else {
621 null_params.push_back(i);
622 }
623 }
624 prof->stop();
625 return null_params;
626}
627
629template <class R>
630auto get_new_working_set(const std::vector<int>& working_set, const CVecRef<R>& params, const CVecRef<R>& wparams) {
631 auto new_indices = find_ref(wparams, params);
632 auto new_working_set = std::vector<int>{};
633 for (auto i : new_indices) {
634 new_working_set.emplace_back(working_set.at(i));
635 }
636 return new_working_set;
637}
638
670template <class R, class Q, class P>
676 logger.trace("itsolv::detail::propose_rspace");
677 logger.trace("dimensions {nP, nQ, nD, nW} = ", xspace.dimensions().nP, xspace.dimensions().nQ, xspace.dimensions().nD,
678 solver.working_set().size());
679 profiler.start("itsolv::ISubspaceSolver::solutions");
680 auto solutions = subspace_solver.retained_solutions();
681 profiler.stop();
682 // the solutions scaled to unit length, so that thresholds on contributions and norms do not depend on their
683 // normalisation
684 const auto unit_solutions = contribution_solutions(solutions, xspace);
685 auto q_delete = limit_qspace_size(xspace.dimensions(), q_opts, unit_solutions, logger);
686 logger.debug("delete Q parameter indices = ", q_delete);
687 if (!q_delete.empty()) {
688 auto prof = profiler.push("construct_dspace");
690 unit_solutions, xspace, q_delete, r_opts.norm_thresh, r_opts.svd_thresh, handlers.qq(), logger);
691 auto wdparams = wrap(dparams);
692 auto wdactions = wrap(dactions);
694 auto eigenvalues_ref = subspace_solver.eigenvalues();
695 subspace_solver.solve(xspace, subspace_solver.size());
696 const auto& eigenvalues_new = subspace_solver.eigenvalues();
697 const auto n_compare = std::min(eigenvalues_ref.size(), eigenvalues_new.size());
698 auto eigval_error = std::vector<double>{};
699 std::transform(std::begin(eigenvalues_ref), std::begin(eigenvalues_ref) + n_compare, std::begin(eigenvalues_new),
700 std::back_inserter(eigval_error), [](auto& e_ref, auto& e_new) { return std::abs(e_ref - e_new); });
701 logger.debug("eigenvalue error due to new D space = ", eigval_error);
702 // FIXME Optionally, solve the subspace problem again and get an estimate of the error due to new D
703 }
704 // Orthonormalise the residuals against P+Q+D and among themselves, removing redundant and null parameters.
705 auto wresidual = wrap(residuals.begin(), residuals.begin() + solver.working_set().size());
706 profiler.start("normalise");
707 normalise(wresidual, handlers.rr(), logger);
708 profiler.stop();
709 profiler.start("append_overlap_with_r");
710 const auto full_overlap =
712 xspace.cparamsq(), xspace.cparamsd(), handlers, logger);
713 profiler.stop();
714 profiler.start("redundant_indices");
715 auto redundant_indices =
716 redundant_parameters(full_overlap, xspace.dimensions().nX(), wresidual.size(), r_opts.svd_thresh, logger);
717 profiler.stop();
718 logger.debug("redundant indices = ", redundant_indices);
719 // overlaps of the remaining R parameters with P+Q+D, to save project_out_and_orthonormalise() from
720 // recalculating them
721 const auto nX = xspace.dimensions().nX();
722 auto kept = std::vector<size_t>{};
723 for (size_t j = 0; j < wresidual.size(); ++j)
724 if (std::find(redundant_indices.begin(), redundant_indices.end(), int(j)) == redundant_indices.end())
725 kept.push_back(j);
727 for (size_t j = 0; j < kept.size(); ++j)
728 for (size_t i = 0; i < nX; ++i)
729 rx_overlap(j, i) = full_overlap(nX + kept[j], i);
731 profiler.start("project_out_and_orthonormalise");
733 xspace.dimensions(), xspace.cparamsp(), xspace.cparamsq(),
734 xspace.cparamsd(), r_opts.norm_thresh, handlers, logger);
735 profiler.stop();
736 // Now that there is SVD null_param_indices should always be empty
737 logger.debug("null parameters = ", null_param_indices);
739 normalise(wresidual, handlers.rr(), logger);
740 for (size_t i = 0; i < wresidual.size(); ++i)
741 handlers.rr().copy(parameters.at(i), wresidual.at(i));
742 profiler.start("get_new_working_set");
744 profiler.stop();
745 return new_working_set;
746}
747} // namespace molpro::linalg::itsolv::detail
748
749#endif // LINEARALGEBRA_SRC_MOLPRO_LINALG_ITSOLV_PROPOSE_RSPACE_H
Enhances various operations between pairs of arrays and allows dynamic code injection with uniform in...
Definition ArrayHandler.h:163
virtual void scal(value_type alpha, AL &x)=0
virtual void gemm_outer(const Matrix< value_type > alphas, const CVecRef< AR > &xx, const VecRef< AL > &yy)=0
decltype(check_abs< value_type >()) value_type_abs
Definition ArrayHandler.h:183
Non-owning container taking a pointer to the data buffer and its size and exposing routines for itera...
Definition Span.h:31
Class, containing a collection of array handlers used in IterativeSolver Provides a Builder sub-class...
Definition ArrayHandlers.h:25
Base class defining the interface common to all iterative solvers.
Definition IterativeSolver.h:361
virtual const std::vector< int > & working_set() const =0
Working set of roots that are not yet converged.
Logger class implementation. Provides (customizable) logging functionalities.
Definition Logger.h:370
void info(std::string_view message, const Ts &...args) const
Definition Logger.h:473
void warn(std::string_view message, const Ts &...args) const
Definition Logger.h:478
void trace(std::string_view message, const Ts &...args) const
Definition Logger.h:463
void debug(std::string_view message, const Ts &...args) const
Definition Logger.h:468
void data_dump(std::string_view what, const T &data) const
Dumps data (context log::DataDump<T>, verbosity Trace). Nothing is copied.
Definition Logger.h:496
Full subspace.
Definition IXSpace.h:21
SubspaceData< value_type > data
Equation data in the subspace.
Definition IXSpace.h:30
virtual CVecRef< Q > cparamsq() const =0
virtual CVecRef< P > cparamsp() const =0
virtual MetricKind metric_kind() const =0
The kind of metric declared with set_metric()
size_t size() const
Number of vectors forming the subspace.
Definition IXSpace.h:33
virtual CVecRef< Q > cactionsd() const =0
virtual void eraseq(size_t i)=0
Removes parameter i from Q subspace.
virtual void update_dspace(VecRef< Q > &params, VecRef< Q > &actions, const VecRef< Q > &metric_actions={}, const std::vector< size_t > &q_delete={}, const Matrix< value_type > &coefficients={})=0
Replaces the old D space and the Q vectors q_delete by new D vectors, which are linear combinations o...
virtual CVecRef< Q > cactionsq() const =0
virtual CVecRef< Q > cparamsd() const =0
virtual CVecRef< Q > cmetric_actionsd() const =0
Actions of the metric on the D space parameters, empty unless there is a metric.
bool stores_metric_actions() const
Whether the actions of the metric on the Q and D vectors are kept.
Definition IXSpace.h:65
virtual const Dimensions & dimensions() const =0
virtual CVecRef< Q > cmetric_actionsq() const =0
Actions of the metric on the Q space parameters, empty unless there is a metric.
Slice & scal(T a)
Scale all elements of the slice.
Definition Matrix.h:230
Matrix container that allows simple data access, slicing, copying and resizing without loosing data.
Definition Matrix.h:32
Slice row(size_t i)
Access row slice.
Definition Matrix.h:122
void remove_row(index_type row)
removes a row from the matrix
Definition Matrix.h:146
index_type rows() const
Definition Matrix.h:169
Profiler & start(const std::string &name)
Profiler & stop(const std::string &name="")
Proxy push(const std::string &name)
static std::shared_ptr< Profiler > single()
auto projected_solutions_overlap(const subspace::Matrix< value_type > &solutions_proj, const subspace::Matrix< value_type > &overlap, const std::vector< std::size_t > &basis, const std::vector< std::size_t > &indices)
Constructs overlaps of projected solutions with subspace vectors.
Definition propose_rspace.h:111
auto stable_projected_solutions(const subspace::Matrix< value_type > &solutions, const subspace::Matrix< value_type > &overlap, const subspace::Dimensions &dims, const std::vector< std::size_t > &remove_qspace, const value_type_abs norm_thresh, const value_type_abs svd_thresh, Logger &logger)
Projects solutions onto Q_{delete} and the current D space, and transforms them to a normalised set w...
Definition propose_rspace.h:251
auto construct_projected_solution(const subspace::Matrix< value_type > &solutions, const subspace::Dimensions &dims, const std::vector< std::size_t > &remove_qspace, Logger &logger)
Projects solution from the full subspace on to Q_{delete} and current D space.
Definition propose_rspace.h:84
auto construct_projected_solutions_overlap(const subspace::Matrix< value_type > &solutions_proj, const subspace::Matrix< value_type > &overlap, const subspace::Dimensions &dims, const std::vector< std::size_t > &remove_qspace, Logger &logger)
Constructs overlap matrix for projected solutions.
Definition propose_rspace.h:161
auto remove_null_projected_solutions(const subspace::Matrix< value_type > &solutions_proj, const subspace::Matrix< value_type > &overlap_proj, const value_type_abs svd_thresh, Logger &logger)
Transforms to a stable subspace of projected solutions via SVD.
Definition propose_rspace.h:216
void remove_null_norm_and_normalise(subspace::Matrix< value_type > &parameters, subspace::Matrix< value_type > &overlap, const value_type_abs norm_thresh, Logger &logger)
Removes parameters with norm less than threshold and normalises the rest.
Definition propose_rspace.h:177
auto construct_full_subspace_overlap(const subspace::Matrix< value_type > &solutions_proj, const subspace::Dimensions &dims, const std::vector< std::size_t > &remove_qspace, const subspace::Matrix< value_type > &overlap, const size_t nR)
Constructs overlap matrix of P+Q+R+(projected solutions) subspaces, where Q is without removed parame...
Definition propose_rspace.h:274
std::vector< std::size_t > projected_solutions_basis(const subspace::Dimensions &dims, const std::vector< std::size_t > &remove_qspace)
Returns subspace indices of the vectors u_k that the columns of a projected solutions matrix refer to...
Definition propose_rspace.h:65
Definition helper-dispatch.h:224
void erase_qspace(subspace::IXSpace< R, Q, P > &xspace, subspace::Matrix< value_type > &solutions, std::vector< Index > indices)
Erases Q parameters with the given indices together with the corresponding columns of a solutions mat...
Definition DSpaceResetter.h:36
void normalise(VecRef< R > &params, array::ArrayHandler< R, R > &handler, Logger &logger, typename array::ArrayHandler< R, R >::value_type_abs thresh=1/std::numeric_limits< typename array::ArrayHandler< R, R >::value_type_abs >::max())
Definition propose_rspace.h:36
subspace::Matrix< value_type > contribution_solutions(const subspace::Matrix< value_type > &solutions, const subspace::IXSpace< R, Q, P > &xspace)
The solutions scaled to unit length, as needed wherever thresholds apply to their coefficients or to ...
Definition propose_rspace.h:367
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:671
auto construct_dspace(const subspace::Matrix< value_type > &solutions, const subspace::IXSpace< R, Q, P > &xspace, const std::vector< std::size_t > &q_delete, const value_type_abs norm_thresh, const value_type_abs svd_thresh, array::ArrayHandler< Q, Q > &handler, Logger &logger)
Constructs the new D space by projecting the solutions onto Qd+D subspace and ensuring they are well ...
Definition propose_rspace.h:457
auto project_out_and_orthonormalise(const VecRef< R > &rparams, const subspace::Matrix< value_type > &overlap, const subspace::Matrix< value_type > &rx_overlap, const subspace::Dimensions &dims, const CVecRef< P > &pparams, const CVecRef< Q > &qparams, const CVecRef< Q > &dparams, const value_type_abs norm_thresh, ArrayHandlers< R, Q, P > &handlers, Logger &logger)
Projects R parameters out of the P+Q+D subspace and orthonormalises them among themselves.
Definition propose_rspace.h:564
auto get_new_working_set(const std::vector< int > &working_set, const CVecRef< R > &params, const CVecRef< R > &wparams)
Returns new working set based on parameters included in wparams.
Definition propose_rspace.h:630
auto append_overlap_with_r(const subspace::Matrix< value_type > &overlap, const CVecRef< R > &params, const CVecRef< P > &pparams, const CVecRef< Q > &qparams, const CVecRef< Q > &dparams, ArrayHandlers< R, Q, P > &handlers, Logger &logger)
Constructs overlap of the full subspace by appending overlap with new parameters to the overlap of pr...
Definition propose_rspace.h:333
std::vector< std::size_t > limit_qspace_size(const subspace::Dimensions &dims, const QSpaceOptions &opts, const subspace::Matrix< value_type > &solutions, Logger &logger)
Ensures that size Q space is within limit by proposing Q parameters for deletion.
Definition propose_rspace.h:383
auto redundant_parameters(const subspace::Matrix< value_type > &overlap, const size_t oR, const size_t nR, const value_type_abs svd_thresh, Logger &logger)
Deduces a set of parameters that are redundant due to linear dependencies.
Definition helper-implementation.h:960
Matrix< T > unit_length_solutions(const Matrix< T > &solutions, const Matrix< T > &overlap)
The subspace coefficients of the solutions scaled to unit Euclidean length, so that their sizes can b...
Definition util.h:106
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
Q construct_zeroed_copy(const R &param, array::ArrayHandler< Q, R > &handler)
Copy R parameter to Q and zero it. This ensures same size and distribution of the copy.
Definition util.h:60
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
void delete_parameters(std::vector< int > indices, Container &params)
Removes parameters.
Definition util.h:128
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
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
std::list< SVD< value_type > > svd_system(size_t nrows, size_t ncols, const array::Span< value_type > &m, real_type_t< value_type > threshold, bool hermitian=false, bool reduce_to_rank=false)
Performs singular value decomposition and returns SVD objects for singular values less than threshold...
Definition helper-implementation.h:268
std::vector< std::reference_wrapper< A > > VecRef
Definition wrap.h:11
@ Identity
M = 1, i.e. no metric.
std::vector< size_t > find_ref(const VecRef< R > &wparams, ForwardIt begin, ForwardIt end)
Given wrapped references in wparams and a range of original parameters [begin, end),...
Definition wrap_util.h:17
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
size_t nD
Definition Dimensions.h:14
size_t nQ
Definition Dimensions.h:13
size_t nP
Definition Dimensions.h:12
size_t nX() const
total size of the X space
Definition Dimensions.h:16
Manages solution of the subspace problem and storage of those solutions.
Definition ISubspaceSolver.h:21