Uni20
Asynchronous tensor and runtime library.
Loading...
Searching...
No Matches
gmres_refinement.hpp
Go to the documentation of this file.
1#pragma once
2
10
11namespace uni20::krylov
12{
26template <class WorkingSpace, class InnerSpace, class ResidualSpace, class InnerOp, class ResidualOp,
27 class Preconditioner, class Transfer>
29{
30 WorkingSpace working;
31 InnerSpace inner;
32 ResidualSpace residual;
34 ResidualOp& residual_operator;
35 Preconditioner& preconditioner;
36 Transfer& transfer;
37};
38
40template <Real InnerReal, Real ResidualReal> struct GmresRefinementOptions
41{
43 std::optional<ResidualReal> relative_tolerance = {};
44 ResidualReal absolute_tolerance = ResidualReal{};
45 std::size_t max_corrections = 10;
48};
49
60
62template <Real I, Real R> struct GmresRefinementInfo
63{
65 std::size_t corrections = 0;
66 std::size_t inner_iterations = 0;
68 std::optional<GmresResidual<R>> residual = {};
69 std::optional<GmresErrorEstimates<R>> errors = {};
70 std::optional<GmresInfo<I>> last_inner = {};
71 bool succeeded() const noexcept { return this->status == GmresRefinementStatus::converged; }
72};
73
86template <class WSpace, class ISpace, class RSpace, class IOp, class ROp, class P, class Transfer>
88 GmresRefinementContext<WSpace, ISpace, RSpace, IOp, ROp, P, Transfer>& context, typename WSpace::vector_type& x,
89 typename RSpace::vector_type const& b,
91{
92 using W = typename WSpace::scalar_type;
93 using I = typename ISpace::scalar_type;
94 using R = typename RSpace::scalar_type;
95 using WR = make_real_t<W>;
96 using IR = make_real_t<I>;
97 using RR = make_real_t<R>;
98 static_assert(Complex<W> == Complex<I> && Complex<I> == Complex<R>,
99 "GMRES refinement spaces must be all real or all complex");
100 auto& ws = context.working;
101 auto& is = context.inner;
102 auto& rs = context.residual;
103 ws.validate();
104 is.validate();
105 rs.validate();
106 (void)gmres_detail::tolerances(options.inner, is.precision);
107 (void)gmres_detail::operator_estimates_at_precision(options.inner.operator_estimates, is.precision);
108 auto estimates = gmres_detail::operator_estimates_at_precision(options.operator_estimates, rs.precision);
109 auto n = ws.ops.problem_dimension();
110 if (is.ops.problem_dimension() != n || rs.ops.problem_dimension() != n || ws.ops.vector_dimension(x) != n ||
111 rs.ops.vector_dimension(b) != n)
112 throw std::invalid_argument("GMRES refinement spaces have incompatible dimensions");
113 if ((options.relative_tolerance &&
114 (!uni20::isfinite(*options.relative_tolerance) || *options.relative_tolerance < 0)) ||
115 !uni20::isfinite(options.absolute_tolerance) || options.absolute_tolerance < 0)
116 throw std::invalid_argument("GMRES refinement requires finite nonnegative tolerances");
117 RR relative = options.relative_tolerance
118 ? scalar_at_precision<RR>(*options.relative_tolerance, rs.precision)
119 : gmres_detail::convert_scalar<RR>(numeric_limits<WR>::epsilon(ws.precision), rs.precision);
120 RR absolute = scalar_at_precision<RR>(options.absolute_tolerance, rs.precision);
121 if (!uni20::isfinite(relative) || !uni20::isfinite(absolute))
122 throw std::invalid_argument("GMRES refinement tolerance is not representable at residual precision");
123 auto rone = scalar_at_precision<R>(1, rs.precision);
124 auto wone = scalar_at_precision<W>(1, ws.precision);
125 GmresRefinementInfo<IR, RR> info;
126 auto fail = [&](GmresRefinementStatus status) {
127 info.status = status;
128 return info;
129 };
130 auto rnorm = [&](auto const& v) { return gmres_detail::norm<R>(rs.ops, v, rs.precision); };
131 auto wnorm = [&](auto const& v) { return gmres_detail::norm<W>(ws.ops, v, ws.precision); };
132 if (!wnorm(x) || !rnorm(b)) return fail(GmresRefinementStatus::nonfinite_input);
133
134 auto rhs = rs.ops.allocate_like(rs.prototype);
135 context.transfer(rhs, b, rs.precision);
136 auto bnorm = rnorm(rhs);
137 if (!bnorm) return fail(GmresRefinementStatus::nonfinite_result);
138 auto residual = rs.ops.allocate_like(rs.prototype);
139 auto rx = rs.ops.allocate_like(rs.prototype);
140 auto applied = rs.ops.allocate_like(rs.prototype);
141 std::optional<RR> candidate_norm;
142 auto evaluate = [&](auto const& candidate) {
143 context.transfer(rx, candidate, rs.precision);
144 candidate_norm = rnorm(rx);
145 if (!candidate_norm) return std::optional<RR>{};
146 ++info.residual_operator_applications;
147 context.residual_operator.matvec(applied, rx);
148 rs.ops.copy(residual, rhs);
149 rs.ops.axpy(residual, -rone, applied);
150 return rnorm(residual);
151 };
152 auto beta = evaluate(x);
154 auto diagnose = [&](RR const& residual_norm) {
155 info.residual = GmresResidual<RR>{residual_norm, *bnorm, *candidate_norm};
156 info.errors = gmres_detail::error_estimates(*info.residual, estimates);
157 };
158 diagnose(*beta);
159 auto reached = [&](RR const& value) { return gmres_detail::reached(value, *bnorm, relative, absolute); };
161 if (options.max_corrections == 0) return info;
162
163 auto ib = is.ops.allocate_like(is.prototype);
164 auto correction = is.ops.allocate_like(is.prototype);
165 auto update = ws.ops.allocate_like(ws.prototype);
166 auto candidate = ws.ops.allocate_like(ws.prototype);
167 auto difference = ws.ops.allocate_like(ws.prototype);
168 while (info.corrections < options.max_corrections)
169 {
170 // Normalization happens before narrowing: a small residual can still
171 // generate an ordinary-size inner RHS even outside the inner exponent range.
172 gmres_detail::normalize<R>(rs.ops, residual, *beta, rs.precision);
173 context.transfer(ib, residual, is.precision);
174 if (!gmres_detail::norm<I>(is.ops, ib, is.precision)) return fail(GmresRefinementStatus::nonfinite_result);
175 is.ops.set_zero(correction);
176 ++info.corrections;
177 info.last_inner = gmres_with_info<I>(is.ops, context.inner_operator, context.preconditioner, correction, ib,
178 options.inner, is.precision);
179 info.inner_iterations += info.last_inner->iterations;
180 if (!info.last_inner->succeeded()) return fail(GmresRefinementStatus::inner_failed);
181 context.transfer(rx, correction, rs.precision);
182 rs.ops.scal(rx, scalar_at_precision<R>(*beta, rs.precision));
183 if (!rnorm(rx)) return fail(GmresRefinementStatus::nonfinite_result);
184 context.transfer(update, rx, ws.precision);
185 if (!wnorm(update)) return fail(GmresRefinementStatus::nonfinite_result);
186 ws.ops.copy(candidate, x);
187 ws.ops.axpy(candidate, wone, update);
188 if (!wnorm(candidate)) return fail(GmresRefinementStatus::nonfinite_result);
189 ws.ops.copy(difference, candidate);
190 ws.ops.axpy(difference, -wone, x);
191 auto change = wnorm(difference);
192 if (!change) return fail(GmresRefinementStatus::nonfinite_result);
193 beta = evaluate(candidate);
195 ws.ops.copy(x, candidate);
196 diagnose(*beta);
198 if (*change == 0) return fail(GmresRefinementStatus::stagnated);
199 }
200 return info;
201}
202} // namespace uni20::krylov
Precision precision() const
Return exact state or the working precision stored by MPFR.
Definition mpreal.hpp:178
Concept for complex scalar types.
Definition scalar_concepts.hpp:75
locale_t value
Definition data_table.cpp:49
Restarted right-preconditioned GMRES over opaque vector operations.
typename make_real< T >::type make_real_t
Alias for the underlying real-valued type of T.
Definition scalar_traits.hpp:168
constexpr bool isfinite(I const &x) noexcept
Returns whether an integer scalar is finite.
Definition math.hpp:121
void info(checked_format_string< Args... > format, Args &&... args)
Emit an informational display message.
Definition display.hpp:393
bool reached(R const &residual, R const &rhs, R const &relative, R const &absolute)
Definition gmres.hpp:156
std::optional< GmresErrorEstimates< R > > error_estimates(GmresResidual< R > const &residual, GmresOperatorEstimates< R > const &properties)
Definition gmres_diagnostics.hpp:132
Tolerances< R > tolerances(GmresOptions< R > const &options, Precision precision)
Definition gmres.hpp:77
GmresOperatorEstimates< R > operator_estimates_at_precision(GmresOperatorEstimates< R > const &input, Precision p)
Definition gmres_diagnostics.hpp:73
Definition block_tensor_vector.hpp:23
GmresRefinementStatus
Outer termination, distinct from convergence of an inner correction.
Definition gmres_refinement.hpp:52
auto gmres_refine_with_info(GmresRefinementContext< WSpace, ISpace, RSpace, IOp, ROp, P, Transfer > &context, typename WSpace::vector_type &x, typename RSpace::vector_type const &b, GmresRefinementOptions< typename ISpace::real_type, typename RSpace::real_type > const &options={})
Refine a supplied iterate using matrix-free GMRES correction solves.
Definition gmres_refinement.hpp:87
std::optional< DenseMatrix< W > > correction(Backend &backend, LuFactorization< F > const &factor, DenseMatrix< R > const &rhs, LuRefinementPrecision< F, W, R > p, std::vector< bool > const &active, std::int64_t target_exponent, SolveInfo &info)
Definition lu_refine.hpp:93
mpreal epsilon(Precision precision)
Spacing above one for a specified binary working precision.
Definition mpreal.hpp:805
mpreal beta(mpreal const &a, mpreal const &x)
Real Beta function; positive rational/integer pairs retain exact values.
Definition mpreal_special.hpp:164
Optional properties of the original operator in the vector space's 2-norm.
Definition gmres_diagnostics.hpp:38
Residual stopping policy and storage/iteration limits.
Definition gmres.hpp:27
Bind precision roles and application operations for GMRES refinement.
Definition gmres_refinement.hpp:29
InnerOp & inner_operator
Definition gmres_refinement.hpp:33
InnerSpace inner
Definition gmres_refinement.hpp:31
ResidualSpace residual
Definition gmres_refinement.hpp:32
ResidualOp & residual_operator
Definition gmres_refinement.hpp:34
Transfer & transfer
Definition gmres_refinement.hpp:36
WorkingSpace working
Definition gmres_refinement.hpp:30
Preconditioner & preconditioner
Definition gmres_refinement.hpp:35
Refinement diagnostics for the last finite published working iterate.
Definition gmres_refinement.hpp:63
std::size_t inner_iterations
Definition gmres_refinement.hpp:66
std::size_t corrections
Definition gmres_refinement.hpp:65
bool succeeded() const noexcept
Definition gmres_refinement.hpp:71
std::size_t residual_operator_applications
Definition gmres_refinement.hpp:67
GmresRefinementStatus status
Definition gmres_refinement.hpp:64
std::optional< GmresResidual< R > > residual
Definition gmres_refinement.hpp:68
std::optional< GmresErrorEstimates< R > > errors
Definition gmres_refinement.hpp:69
std::optional< GmresInfo< I > > last_inner
Definition gmres_refinement.hpp:70
Outer residual targets and independently configured inner solves.
Definition gmres_refinement.hpp:41
std::size_t max_corrections
Definition gmres_refinement.hpp:45
GmresOptions< InnerReal > inner
Definition gmres_refinement.hpp:46
std::optional< ResidualReal > relative_tolerance
Absent means working-precision epsilon, converted to residual precision.
Definition gmres_refinement.hpp:43
ResidualReal absolute_tolerance
Definition gmres_refinement.hpp:44
GmresOperatorEstimates< ResidualReal > operator_estimates
Definition gmres_refinement.hpp:47
Project-level numeric limits customization point.
Definition numeric_limits.hpp:16