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 // the length of a vector is a magnitude, real even when the elements are complex
41 const typename array::ArrayHandler<R, R>::value_type_abs dot = std::sqrt(std::abs(handler.dot(p, p)));
42 if (dot > thresh and std::isfinite(dot)) {
43 handler.scal(1. / dot, p);
44 } else {
45 logger.warn("parameter's length is too small for normalisation, dot = " + std::format("{:.2e}", double(dot)));
46 }
47 }
48}
49namespace dspace {
50
59template <typename value_type>
61 const std::vector<std::size_t>& remove_qspace, Logger& logger) {
62 logger.trace("construct_projected_solution()");
63 const auto nQd = remove_qspace.size();
64 const auto nSol = solutions.rows();
66 for (size_t i = 0; i < nSol; ++i) {
67 for (size_t j = 0; j < nQd; ++j) {
68 solutions_proj(i, j) = solutions(i, dims.oQ() + remove_qspace[j]);
69 }
70 for (size_t j = 0; j < dims.nD; ++j) {
71 solutions_proj(i, nQd + j) = solutions(i, dims.oD() + j);
72 }
73 }
74 logger.debug("nSol, nQd, nD", nSol, nQd, dims.nD);
75 return solutions_proj;
76}
77
92template <typename value_type>
94 const subspace::Matrix<value_type>& overlap,
96 const std::vector<std::size_t>& remove_qspace, Logger& logger) {
97 logger.trace("construct_projected_solution_overlap()");
98 const auto nSol = solutions_proj.rows();
99 const auto nQd = remove_qspace.size();
101 for (size_t i = 0; i < nSol; ++i) {
102 for (size_t ii = 0; ii <= i; ++ii) {
103 for (size_t j = 0; j < nQd; ++j) {
104 for (size_t k = 0; k < nQd; ++k) {
106 overlap(dims.oQ() + remove_qspace[j], dims.oQ() + remove_qspace[k]);
107 }
108 for (size_t k = 0; k < dims.nD; ++k) {
109 overlap_proj(i, ii) +=
110 solutions_proj(i, j) * solutions_proj(ii, nQd + k) * overlap(dims.oQ() + remove_qspace[j], dims.oD() + k);
111 }
112 }
113 for (size_t j = 0; j < dims.nD; ++j) {
114 for (size_t k = 0; k < dims.nD; ++k) {
115 overlap_proj(i, ii) +=
116 solutions_proj(i, nQd + j) * solutions_proj(ii, nQd + k) * overlap(dims.oD() + j, dims.oD() + k);
117 }
118 for (size_t k = 0; k < nQd; ++k) {
119 overlap_proj(i, ii) +=
120 solutions_proj(i, nQd + j) * solutions_proj(ii, k) * overlap(dims.oD() + j, dims.oQ() + remove_qspace[k]);
121 }
122 }
124 }
125 }
126 return overlap_proj;
127}
128
136template <typename value_type, typename value_type_abs>
138 const value_type_abs norm_thresh, Logger& logger) {
139 logger.trace("remove_null_norm_and_normalise()");
140 const auto nSol = parameters.rows();
141 auto norm_proj = std::vector<value_type_abs>(nSol, 0.);
142 for (size_t i = 0; i < nSol; ++i)
143 norm_proj[i] = std::sqrt(std::abs(overlap(i, i)));
144 for (size_t i = 0, j = 0; i < nSol; ++i) {
145 if (norm_proj[i] > norm_thresh) {
146 parameters.row(j).scal(1. / norm_proj[i]);
147 overlap.col(j).scal(1. / norm_proj[i]);
148 overlap.row(j).scal(1. / norm_proj[i]);
149 ++j;
150 } else {
151 parameters.remove_row(j);
152 overlap.remove_row_col(j, j);
153 std::stringstream ss;
154 ss << std::setprecision(3) << "remove projected solution parameter i = " << i << ", norm = " << norm_proj[i];
155 logger.info(ss.str());
156 }
157 }
158 logger.data_dump("norm = ", norm_proj);
159 logger.data_dump("parameters after normalisation = ", parameters);
160 logger.data_dump("overlap of parameters = ", overlap);
161}
162
175template <typename value_type, typename value_type_abs>
177 const subspace::Matrix<value_type>& overlap_proj, const value_type_abs svd_thresh,
178 Logger& logger) {
179 logger.trace("remove_null_projected_solutions()");
180 logger.debug("nS on entry = ", solutions_proj.rows());
181 value_type* m = const_cast<std::vector<value_type>&>(overlap_proj.data()).data();
182 auto svd_vecs = svd_system(overlap_proj.rows(), overlap_proj.cols(), array::Span(m, overlap_proj.size()),
183 std::numeric_limits<value_type_abs>::max(), true);
184 svd_vecs.remove_if([&svd_thresh](const auto& el) { return real_part(el.value) < svd_thresh; });
185 svd_vecs.sort([](const auto& lt, const auto& rt) { return real_part(lt.value) < real_part(rt.value); });
186 const auto nD = svd_vecs.size();
187 const auto nX = solutions_proj.cols();
189 auto svd = svd_vecs.begin();
190 for (size_t i = 0; i < nD; ++i, ++svd)
191 for (size_t j = 0; j < overlap_proj.cols(); ++j)
192 for (size_t k = 0; k < nX; ++k)
193 solutions_stable(i, k) += svd->v[j] * solutions_proj(j, k);
194 logger.debug("nS without null space = ", solutions_stable.rows());
195 return solutions_stable;
196}
197
207template <typename value_type>
209 const subspace::Dimensions& dims, const std::vector<std::size_t>& remove_qspace,
210 const subspace::Matrix<value_type>& overlap, const size_t nR) {
211 const auto nDnew = solutions_proj.rows();
212 const auto nQd = remove_qspace.size();
213 const auto nQ = dims.nQ - nQd;
214 auto ov = overlap;
215 for (size_t i = 0; i < dims.nD; ++i) {
216 ov.remove_row_col(dims.oD(), dims.oD());
217 }
218 auto is_Qdelete = [&remove_qspace](size_t i) {
219 return std::find(begin(remove_qspace), end(remove_qspace), i) != end(remove_qspace);
220 };
221 for (size_t i = 0, j = 0; i < dims.nQ; ++i) {
222 if (is_Qdelete(i))
223 ov.remove_row_col(dims.oQ() + j, dims.oQ() + j);
224 else
225 ++j;
226 }
227 const auto oDnew = dims.nP + nQ + nR;
228 ov.resize({oDnew + nDnew, oDnew + nDnew});
229 /*
230 * append overlap with solutions_proj
231 * x_i = \sum_j c_ij v_j
232 * <x_i, v_j> = \sum_k c_ik <v_k, v_j>
233 * <x_i, x_j> = \sum_kl c_ik c_jl <v_k, v_l>
234 */
235 auto accumulate_ov_offdiag = [&](size_t i, size_t j, size_t jj) {
236 for (size_t k = 0; k < nQd; ++k)
237 ov(oDnew + i, j) += solutions_proj(i, k) * overlap(jj, dims.oQ() + remove_qspace[k]);
238 for (size_t k = 0; k < dims.nD; ++k)
239 ov(oDnew + i, j) += solutions_proj(i, nQd + k) * overlap(jj, dims.oD() + k);
240 ov(j, oDnew + i) = ov(oDnew + i, j);
241 };
242 for (size_t i = 0; i < nDnew; ++i) {
243 for (size_t j = 0; j < dims.nP; ++j)
244 accumulate_ov_offdiag(i, j, dims.oP() + j);
245 for (size_t j = 0, jj = 0; j < dims.nQ; ++j)
246 if (!is_Qdelete(j))
247 accumulate_ov_offdiag(i, dims.nP + jj++, dims.oQ() + j);
248 for (size_t j = 0; j < nR; ++j)
249 accumulate_ov_offdiag(i, dims.nP + nQ + j, dims.nX() + j);
250 }
251 for (size_t i = 0; i < nDnew; ++i) {
252 for (size_t j = 0; j <= i; ++j) {
253 for (size_t k = 0; k < nQd; ++k) {
254 for (size_t l = 0; l < nQd; ++l)
255 ov(oDnew + i, oDnew + j) += solutions_proj(i, k) * solutions_proj(j, l) *
256 overlap(dims.oQ() + remove_qspace[k], dims.oQ() + remove_qspace[l]);
257 for (size_t l = 0; l < dims.nD; ++l)
258 ov(oDnew + i, oDnew + j) +=
259 solutions_proj(i, k) * solutions_proj(j, nQd + l) * overlap(dims.oQ() + remove_qspace[k], dims.oD() + l);
260 }
261 for (size_t k = 0; k < dims.nD; ++k) {
262 for (size_t l = 0; l < nQd; ++l)
263 ov(oDnew + i, oDnew + j) +=
264 solutions_proj(i, nQd + k) * solutions_proj(j, l) * overlap(dims.oD() + k, dims.oQ() + remove_qspace[l]);
265 for (size_t l = 0; l < dims.nD; ++l)
266 ov(oDnew + i, oDnew + j) +=
267 solutions_proj(i, nQd + k) * solutions_proj(j, nQd + l) * overlap(dims.oD() + k, dims.oD() + l);
268 }
269 ov(oDnew + j, oDnew + i) = ov(oDnew + i, oDnew + j);
270 }
271 }
272 return ov;
273}
274} // namespace dspace
275
288template <class R, class Q, class P, typename value_type>
290 const CVecRef<P>& pparams, const CVecRef<Q>& qparams, const CVecRef<Q>& dparams,
292 logger.trace("append_overlap_with_r()");
293 const auto nP = pparams.size(), nQ = qparams.size(), nD = dparams.size(), nN = params.size();
294 const auto nX = nP + nQ + nD + nN;
295 const auto oP = 0;
296 const auto oQ = oP + nP;
297 const auto oD = oQ + nQ;
298 const auto oN = oD + nD;
299 auto ov = overlap;
300 ov.resize({nX, nX}); // solutions are last
301 ov.slice({oN, oN}, {oN + nN, oN + nN}) = subspace::util::overlap(params, handlers.rr());
302 ov.slice({oN, oP}, {oN + nN, oP + nP}) = subspace::util::overlap(params, pparams, handlers.rp());
303 ov.slice({oN, oQ}, {oN + nN, oQ + nQ}) = subspace::util::overlap(params, qparams, handlers.rq());
304 ov.slice({oN, oD}, {oN + nN, oD + nD}) = subspace::util::overlap(params, dparams, handlers.rq());
305 auto copy_upper_to_lower = [&ov, oN, nN](size_t oX, size_t nX) {
306 for (size_t i = 0; i < nX; ++i)
307 for (size_t j = 0; j < nN; ++j)
308 ov(oX + i, oN + j) = ov(oN + j, oX + i);
309 };
310 copy_upper_to_lower(oP, nP);
311 copy_upper_to_lower(oQ, nQ);
312 copy_upper_to_lower(oD, nD);
313 logger.data_dump("full overlap P+Q+D+R = ", ov);
314 return ov;
315}
316
325template <typename value_type>
326std::vector<std::size_t> limit_qspace_size(const subspace::Dimensions& dims, const QSpaceOptions& opts,
327 const subspace::Matrix<value_type>& solutions, Logger& logger) {
328 using value_type_abs = decltype(std::abs(solutions(0, 0)));
329 using contrib_pair = std::pair<std::size_t, value_type_abs>;
330 using std::begin;
331 using std::end;
332
333 logger.trace("limit_qspace_size()");
334
335 assert(opts.max_size >= opts.min_size);
336
337 const bool must_trim_size = dims.nQ > opts.max_size;
338 const bool may_trim_size = dims.nQ > opts.min_size && opts.contrib_thresh > 0;
339
340 if (!must_trim_size && !may_trim_size) {
341 return {};
342 }
343
344 const std::size_t min_deletions = must_trim_size ? dims.nQ - opts.max_size : 0;
345 const std::size_t max_deletions = dims.nQ - opts.min_size;
346
347 std::vector<std::size_t> q_delete;
348 q_delete.reserve(min_deletions);
349
350 const std::size_t nSol = solutions.rows();
351
352 std::vector<contrib_pair> max_contrib_to_solution;
354
355 for (std::size_t idx : std::ranges::views::iota(std::size_t(0), dims.nQ)) {
356 max_contrib_to_solution.emplace_back(std::make_pair(idx, value_type_abs(0)));
357
358 for (size_t j = 0; j < nSol; ++j) {
359 const value_type_abs current = std::abs(solutions(j, dims.oQ() + idx));
360 max_contrib_to_solution.back().second = std::max(max_contrib_to_solution.back().second, current);
361 }
362 }
363
364 std::ranges::sort(max_contrib_to_solution, std::less<>{}, &contrib_pair::second);
365
366 logger.trace("contribution to solutions =",
367 max_contrib_to_solution | std::ranges::views::transform([](const contrib_pair& p) { return p.second; }));
368
369 for (auto [idx, contrib] : max_contrib_to_solution) {
370 if (q_delete.size() == max_deletions || (q_delete.size() >= min_deletions && contrib >= opts.contrib_thresh)) {
371 break;
372 }
373
374 if (opts.contrib_thresh != 0 && contrib >= opts.contrib_thresh) {
375 logger.warn("deleted Q vector with max. contribution = ", contrib);
376 } else {
377 logger.debug("deleted Q vector with max. contribution = ", contrib);
378 }
379
380 q_delete.emplace_back(idx);
381 }
382
383 return q_delete;
384}
385
397template <class R, class Q, class P, typename value_type, typename value_type_abs>
399 const std::vector<std::size_t>& q_delete, const value_type_abs norm_thresh,
400 const value_type_abs svd_thresh, array::ArrayHandler<Q, Q>& handler, Logger& logger) {
401 const auto dims = xspace.dimensions();
402 const auto overlap = xspace.data.at(subspace::EqnData::S);
411 array::Span(&overlap_full_subspace(0, 0), overlap_full_subspace.size()), svd_thresh, true);
412 assert(svd_vecs.empty() && "P+Q+D subspace should be stable by construction");
413 const auto nD = solutions_proj.rows();
414 const auto nQd = q_delete.size();
415 assert(nQd + dims.nD == solutions_proj.cols());
416 const auto &qparams = xspace.cparamsq(), qactions = xspace.cactionsq();
417 const auto &dparams = xspace.cparamsd(), dactions = xspace.cactionsd();
418 std::vector<Q> dparams_new, dactions_new;
419 {
420 // FIXME need a simpler mechanism for constructing null parameters
421 Q const* q = nullptr;
422 if (!qparams.empty())
423 q = &qparams.front().get();
424 else if (!dparams.empty())
425 q = &dparams.front().get();
426 if (q) {
427 for (size_t i = 0; i < nD; ++i) {
428 dparams_new.emplace_back(handler.copy(*q));
429 dactions_new.emplace_back(handler.copy(*q));
430 handler.fill(0, dparams_new.back());
431 handler.fill(0, dactions_new.back());
432 }
433 }
434 }
435 for (size_t i = 0; i < nD; ++i) {
436 for (size_t j = 0; j < q_delete.size(); ++j) {
437 handler.axpy(solutions_proj(i, j), qparams.at(q_delete[j]), dparams_new.at(i));
438 handler.axpy(solutions_proj(i, j), qactions.at(q_delete[j]), dactions_new.at(i));
439 }
440 for (size_t j = 0; j < dims.nD; ++j) {
441 handler.axpy(solutions_proj(i, nQd + j), dparams.at(j), dparams_new.at(i));
442 handler.axpy(solutions_proj(i, nQd + j), dactions.at(j), dactions_new.at(i));
443 }
444 }
445 for (size_t i = 0; i < nD; ++i) {
446 auto norm = std::sqrt(std::abs(handler.dot(dparams_new.at(i), dparams_new.at(i))));
447 if (norm < norm_thresh) {
448 logger.warn(
449 std::format("construct_dspace: skipping normalisation of D vector {} with near-zero norm = {:.2e}", i, norm));
450 continue;
451 }
452 handler.scal(1. / norm, dparams_new[i]);
453 handler.scal(1. / norm, dactions_new[i]);
454 }
455 return std::make_tuple(std::move(dparams_new), std::move(dactions_new));
456}
457
476template <class R, class Q, class P, typename value_type, typename value_type_abs>
479 const CVecRef<P>& pparams, const CVecRef<Q>& qparams, const CVecRef<Q>& dparams,
480 const value_type_abs norm_thresh,
482 logger.trace("modified_gram_schmidt()");
483 const auto nR = rparams.size(), nP = pparams.size(), nQ = qparams.size(), nD = dparams.size();
484 // std::cout << "modified_gram_schmidt() nR="<<nR<<" nQ="<<nQ<<" nD="<<nD<<std::endl;
485 assert(nP == dims.nP && nQ == dims.nQ && nD == dims.nD);
486 assert(rx_overlap.rows() == nR && rx_overlap.cols() == dims.nX());
487 // Project the new parameters out of the span of P+Q+D. The existing vectors need not be orthogonal to each other
488 // (for example user-supplied initial guesses), so subtract V S^{-1} V^dagger r rather than projecting on each vector
489 // separately.
490 auto prof = molpro::Profiler::single();
491 prof->start("orthoganalise");
492 const auto nX = nP + nQ + nD;
493 if (nR > 0 and nX > 0) {
494 using EMatrix = Eigen::Matrix<value_type, Eigen::Dynamic, Eigen::Dynamic>;
495 EMatrix S(nX, nX);
496 for (size_t i = 0; i < nX; ++i)
497 for (size_t j = 0; j < nX; ++j)
498 S(i, j) = overlap(i, j);
499 // equilibrate, so that vectors of very different lengths do not make S needlessly ill-conditioned
500 Eigen::Vector<value_type, Eigen::Dynamic> scale(nX);
501 for (size_t i = 0; i < nX; ++i)
502 scale(i) = std::abs(S(i, i)) > 0 ? 1 / std::sqrt(std::abs(S(i, i))) : 0;
503 const auto Sinv = (scale.asDiagonal() * S * scale.asDiagonal()).eval().completeOrthogonalDecomposition();
504 // the projection needs <x_i|r_j>, the conjugate of the overlaps already calculated
505 EMatrix dots(nX, nR);
506 for (size_t i = 0; i < nX; ++i)
507 for (size_t j = 0; j < nR; ++j)
509 const EMatrix y = scale.asDiagonal() * Sinv.solve(scale.asDiagonal() * dots);
510 auto subtract = [&y, &rparams, nR](const auto& xparams, auto& handler, size_t o, size_t n) {
511 if (n == 0)
512 return;
514 for (size_t i = 0; i < n; ++i)
515 for (size_t j = 0; j < nR; ++j)
516 coeff(i, j) = -y(o + i, j);
517 handler.gemm_outer(coeff, xparams, rparams);
518 };
519 subtract(pparams, handlers.rp(), dims.oP(), nP);
520 subtract(qparams, handlers.rq(), dims.oQ(), nQ);
521 subtract(dparams, handlers.rq(), dims.oD(), nD);
522 }
523 prof->stop();
524 prof->start("get null_params");
525 auto null_params = std::vector<int>{};
526 for (size_t i = 0; i < nR; ++i) {
527 auto norm = std::sqrt(std::abs(handlers.rr().dot(rparams[i], rparams[i])));
528 if (norm > norm_thresh) {
529 handlers.rr().scal(1. / norm, rparams[i]);
530 for (size_t j = i + 1; j < nR; ++j) {
531 auto ov = handlers.rr().dot(rparams[i], rparams[j]);
532 handlers.rr().axpy(-ov, rparams[i], rparams[j]);
533 }
534 } else {
535 null_params.push_back(i);
536 }
537 }
538 prof->stop();
539 return null_params;
540}
541
543template <class R>
544auto get_new_working_set(const std::vector<int>& working_set, const CVecRef<R>& params, const CVecRef<R>& wparams) {
545 auto new_indices = find_ref(wparams, params);
546 auto new_working_set = std::vector<int>{};
547 for (auto i : new_indices) {
548 new_working_set.emplace_back(working_set.at(i));
549 }
550 return new_working_set;
551}
552
581template <class R, class Q, class P>
587 // auto prof = profiler.push("itsolv::propose_rspace"); // FIXME two separate profilers
588 auto prof = molpro::Profiler::single();
589 logger.trace("itsolv::detail::propose_rspace");
590 logger.trace("dimensions {nP, nQ, nD, nW} = ", xspace.dimensions().nP, xspace.dimensions().nQ, xspace.dimensions().nD,
591 solver.working_set().size());
592 profiler.start("itsolv::ISubspaceSolver::solutions");
593 auto solutions = subspace_solver.solutions();
594 profiler.stop();
595 auto q_delete = limit_qspace_size(xspace.dimensions(), q_opts, solutions, logger);
596 logger.debug("delete Q parameter indices = ", q_delete);
597 if (!q_delete.empty()) {
598 auto prof = profiler.push("construct_dspace");
599 auto [dparams, dactions] =
600 construct_dspace(solutions, xspace, q_delete, r_opts.norm_thresh, r_opts.svd_thresh, handlers.qq(), logger);
601 std::sort(begin(q_delete), end(q_delete), std::greater<int>());
602 for (auto iq : q_delete)
603 xspace.eraseq(iq);
604 auto wdparams = wrap(dparams);
605 auto wdactions = wrap(dactions);
607 auto eigenvalues_ref = subspace_solver.eigenvalues();
608 subspace_solver.solve(xspace, solutions.rows());
609 auto eigval_error = std::vector<double>{};
610 std::transform(std::begin(eigenvalues_ref), std::end(eigenvalues_ref), std::begin(subspace_solver.eigenvalues()),
611 std::back_inserter(eigval_error), [](auto& e_ref, auto& e_new) { return std::abs(e_ref - e_new); });
612 logger.debug("eigenvalue error due to new D space = ", eigval_error);
613 // FIXME Optionally, solve the subspace problem again and get an estimate of the error due to new D
614 }
615 // Use modified GS to orthonormalise z against P+Q+D, removing any null parameters.
616 auto wresidual = wrap(residuals.begin(), residuals.begin() + solver.working_set().size());
617 profiler.start("normalise");
618 normalise(wresidual, handlers.rr(), logger);
619 profiler.stop();
620 profiler.start("append_overlap_with_r");
621 prof->start("append_overlap_with_r");
622 const auto full_overlap =
624 xspace.cparamsq(), xspace.cparamsd(), handlers, logger);
625 profiler.stop();
626 prof->stop();
627 prof->start("redundant_indices");
628 auto redundant_indices =
629 redundant_parameters(full_overlap, xspace.dimensions().nX(), wresidual.size(), r_opts.svd_thresh, logger);
630 prof->stop();
631 logger.debug("redundant indices = ", redundant_indices);
632 // overlaps of the remaining R parameters with P+Q+D, to save modified_gram_schmidt() from recalculating them
633 const auto nX = xspace.dimensions().nX();
634 auto kept = std::vector<size_t>{};
635 for (size_t j = 0; j < wresidual.size(); ++j)
636 if (std::find(redundant_indices.begin(), redundant_indices.end(), int(j)) == redundant_indices.end())
637 kept.push_back(j);
639 for (size_t j = 0; j < kept.size(); ++j)
640 for (size_t i = 0; i < nX; ++i)
641 rx_overlap(j, i) = full_overlap(nX + kept[j], i);
643 profiler.start("modified_gram_schmidt");
644 prof->start("modified_gram_schmidt");
645 auto null_param_indices =
647 xspace.cparamsp(), xspace.cparamsq(), xspace.cparamsd(), r_opts.norm_thresh, handlers,
648 logger);
649 profiler.stop();
650 prof->stop();
651 // Now that there is SVD null_param_indices should always be empty
652 logger.debug("null parameters = ", null_param_indices);
654 normalise(wresidual, handlers.rr(), logger);
655 for (size_t i = 0; i < wresidual.size(); ++i)
656 handlers.rr().copy(parameters.at(i), wresidual.at(i));
657 profiler.start("get_new_working_set");
659 profiler.stop();
660 return new_working_set;
661}
662} // namespace molpro::linalg::itsolv::detail
663
664#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 value_type dot(const AL &x, const AR &y)=0
The hermitian inner product <x|y>: conjugate-linear in x, linear in y.
virtual void scal(value_type alpha, AL &x)=0
virtual AL copy(const AR &source)=0
virtual void axpy(value_type alpha, const AR &x, AL &y)=0
virtual void fill(value_type alpha, AL &x)=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:209
virtual const std::vector< int > & working_set() const =0
Working set of roots that are not yet converged.
Definition Logger.h:442
void info(std::string_view message, Ts &&...args) const
Definition Logger.h:505
void warn(std::string_view message, Ts &&...args) const
Definition Logger.h:510
void debug(std::string_view message, Ts &&...args) const
Definition Logger.h:500
void data_dump(std::string_view what, Ts...data) const
Definition Logger.h:526
void trace(std::string_view message, Ts &&...args) const
Definition Logger.h:495
Full subspace.
Definition IXSpace.h:19
SubspaceData< value_type > data
Equation data in the subspace.
Definition IXSpace.h:28
virtual CVecRef< Q > cparamsq() const =0
virtual CVecRef< P > cparamsp() const =0
virtual CVecRef< Q > cactionsd() const =0
virtual void eraseq(size_t i)=0
Removes parameter i from Q subspace.
virtual CVecRef< Q > cactionsq() const =0
virtual CVecRef< Q > cparamsd() const =0
virtual const Dimensions & dimensions() const =0
virtual void update_dspace(VecRef< Q > &params, VecRef< Q > &actions)=0
Updates D space with the new parameters.
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 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:60
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:93
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:176
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:137
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:208
Definition helper-dispatch.h:140
void normalise(const size_t n_roots, const VecRef< R > &params, const VecRef< R > &actions, array::ArrayHandler< R, R > &handler, Logger &logger)
Definition IterativeSolverTemplate.h:84
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:582
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:398
auto modified_gram_schmidt(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)
Orthogonalises R parameters against P+Q+D subspace (and themselves)
Definition propose_rspace.h:477
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:544
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:289
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:326
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:856
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:52
void delete_parameters(std::vector< int > indices, Container &params)
Removes parameters.
Definition util.h:98
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:262
std::vector< std::reference_wrapper< A > > VecRef
Definition wrap.h:11
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