Uni20
Asynchronous tensor and runtime library.
Loading...
Searching...
No Matches
gmres_diagnostics.hpp
Go to the documentation of this file.
1#pragma once
2
8#include <uni20/core/math.hpp>
10
11#include <algorithm>
12#include <cstdint>
13#include <optional>
14#include <stdexcept>
15
16namespace uni20::krylov
17{
20{
23};
24
31
37template <Real R> struct GmresOperatorEstimates
38{
39 std::optional<GmresOperatorEstimate<R>> norm = {};
40 std::optional<GmresOperatorEstimate<R>> inverse_norm = {};
41 std::optional<GmresOperatorEstimate<R>> condition_number = {};
42};
43
45template <Real R> struct GmresResidual
46{
50};
51
57template <Real R> struct GmresErrorEstimates
58{
61 std::optional<R> normwise_backward_error = {};
63 std::optional<R> absolute_solution_error = {};
67 std::optional<R> relative_solution_error = {};
68};
69
70namespace gmres_detail
71{
72template <Real R>
74{
75 auto convert = [&](auto const& entry, int minimum, bool strict) -> std::optional<GmresOperatorEstimate<R>> {
76 if (!entry) return {};
77 if (!uni20::isfinite(entry->value) || (strict ? entry->value <= minimum : entry->value < minimum))
78 throw std::invalid_argument("GMRES requires finite norms >= 0, inverse norms > 0, and condition numbers >= 1");
79 R value = scalar_at_precision<R>(entry->value, p);
80 if (entry->kind == GmresEstimateKind::upper_bound && value < entry->value) value = math::next_up(value);
81 if (!uni20::isfinite(value) || (strict ? value <= minimum : value < minimum) || (entry->value > 0 && value == 0))
82 throw std::invalid_argument("GMRES operator estimate is not representable at diagnostic precision");
83 return GmresOperatorEstimate<R>{value, entry->kind};
84 };
85 return {convert(input.norm, 0, false), convert(input.inverse_norm, 0, true),
86 convert(input.condition_number, 1, false)};
87}
88
89// Keep products and denominators scaled until the final diagnostic is formed.
90// For example, kappa*r/b can be representable even when r/b underflows.
91// Wide exponents also accommodate sums of MPFR exponents without signed overflow.
92template <Real R> struct DiagnosticMagnitude
93{
95 __int128_t exponent;
96};
97
98template <Real R> DiagnosticMagnitude<R> magnitude(R const& value)
99{
100 auto parts = math::frexp(value);
101 return {parts.fraction, parts.exponent};
102}
103
104template <Real R> R diagnostic_scale(R const& fraction, __int128_t exponent)
105{
106 auto shift =
107 std::clamp<__int128_t>(exponent, numeric_limits<std::int64_t>::min(), numeric_limits<std::int64_t>::max());
108 return math::ldexp(fraction, static_cast<std::int64_t>(shift));
109}
110
112{
113 return {a.fraction * b.fraction, a.exponent + b.exponent};
114}
115
117{
118 if (a.fraction == 0) return b;
119 if (b.fraction == 0) return a;
120 auto exponent = std::max(a.exponent, b.exponent);
121 return {diagnostic_scale(a.fraction, a.exponent - exponent) + diagnostic_scale(b.fraction, b.exponent - exponent),
122 exponent};
123}
124
125template <Real R> R ratio(DiagnosticMagnitude<R> const& a, DiagnosticMagnitude<R> const& b)
126{
127 if (a.fraction == 0) return a.fraction; // Define the zero-over-zero diagnostic as zero.
128 return diagnostic_scale(R(a.fraction / b.fraction), a.exponent - b.exponent);
129}
130
131template <Real R>
132std::optional<GmresErrorEstimates<R>> error_estimates(GmresResidual<R> const& residual,
133 GmresOperatorEstimates<R> const& properties)
134{
135 if (!properties.norm && !properties.inverse_norm && !properties.condition_number) return {};
136 GmresErrorEstimates<R> result{.operator_estimates = properties};
137 auto r = magnitude(residual.norm), b = magnitude(residual.rhs_norm);
138 if (properties.norm)
139 result.normwise_backward_error =
140 ratio(r, add(multiply(magnitude(properties.norm->value), magnitude(residual.solution_norm)), b));
141 if (properties.inverse_norm)
142 {
143 auto error = multiply(magnitude(properties.inverse_norm->value), r);
144 result.absolute_solution_error = diagnostic_scale(error.fraction, error.exponent);
145 }
146 if (residual.rhs_norm > 0)
147 {
148 if (properties.condition_number)
149 result.relative_solution_error = ratio(multiply(magnitude(properties.condition_number->value), r), b);
150 else if (properties.norm && properties.inverse_norm)
151 result.relative_solution_error =
152 ratio(multiply(multiply(magnitude(properties.norm->value), magnitude(properties.inverse_norm->value)), r), b);
153 }
154 return result;
155}
156} // namespace gmres_detail
157} // namespace uni20::krylov
Exact arithmetic or an explicit binary working precision.
Definition core/precision.hpp:13
locale_t value
Definition data_table.cpp:49
constexpr bool isfinite(I const &x) noexcept
Returns whether an integer scalar is finite.
Definition math.hpp:121
Scalar math helper utilities.
std::optional< GmresErrorEstimates< R > > error_estimates(GmresResidual< R > const &residual, GmresOperatorEstimates< R > const &properties)
Definition gmres_diagnostics.hpp:132
DiagnosticMagnitude< R > add(DiagnosticMagnitude< R > const &a, DiagnosticMagnitude< R > const &b)
Definition gmres_diagnostics.hpp:116
R diagnostic_scale(R const &fraction, __int128_t exponent)
Definition gmres_diagnostics.hpp:104
DiagnosticMagnitude< R > multiply(DiagnosticMagnitude< R > const &a, DiagnosticMagnitude< R > const &b)
Definition gmres_diagnostics.hpp:111
GmresOperatorEstimates< R > operator_estimates_at_precision(GmresOperatorEstimates< R > const &input, Precision p)
Definition gmres_diagnostics.hpp:73
DiagnosticMagnitude< R > magnitude(R const &value)
Definition gmres_diagnostics.hpp:98
R ratio(DiagnosticMagnitude< R > const &a, DiagnosticMagnitude< R > const &b)
Definition gmres_diagnostics.hpp:125
Definition block_tensor_vector.hpp:23
GmresEstimateKind
Provenance of a supplied operator quantity, not of a computed error.
Definition gmres_diagnostics.hpp:20
constexpr detail::scalar_math::ldexp_fn ldexp
Multiply by a power of two using the scalar's exponent interface.
Definition math.hpp:511
constexpr detail::scalar_math::next_up_fn next_up
Adjacent value toward positive infinity.
Definition math.hpp:551
constexpr detail::scalar_math::frexp_fn frexp
Binary fraction and exponent as an owning result.
Definition math.hpp:535
Definition data_table.cpp:8
Error estimates evaluated from the residual and supplied operator data.
Definition gmres_diagnostics.hpp:58
std::optional< R > relative_solution_error
kappa(A) ||r|| / ||b||, relative to the exact solution norm.
Definition gmres_diagnostics.hpp:67
std::optional< R > absolute_solution_error
||A^{-1}|| ||r||, requiring an inverse norm.
Definition gmres_diagnostics.hpp:63
std::optional< R > normwise_backward_error
||r|| / (||A|| ||x_hat|| + ||b||), requiring an operator norm.
Definition gmres_diagnostics.hpp:61
GmresOperatorEstimates< R > operator_estimates
Definition gmres_diagnostics.hpp:59
An application-supplied estimate or known upper bound.
Definition gmres_diagnostics.hpp:27
GmresEstimateKind kind
Definition gmres_diagnostics.hpp:29
R value
Definition gmres_diagnostics.hpp:28
Optional properties of the original operator in the vector space's 2-norm.
Definition gmres_diagnostics.hpp:38
std::optional< GmresOperatorEstimate< R > > condition_number
Definition gmres_diagnostics.hpp:41
std::optional< GmresOperatorEstimate< R > > norm
Definition gmres_diagnostics.hpp:39
std::optional< GmresOperatorEstimate< R > > inverse_norm
Definition gmres_diagnostics.hpp:40
Recomputed Euclidean norms for the published iterate.
Definition gmres_diagnostics.hpp:46
R solution_norm
Definition gmres_diagnostics.hpp:49
R norm
Definition gmres_diagnostics.hpp:47
R rhs_norm
Definition gmres_diagnostics.hpp:48
Definition gmres_diagnostics.hpp:93
__int128_t exponent
Definition gmres_diagnostics.hpp:95
R fraction
Definition gmres_diagnostics.hpp:94
Project-level numeric limits customization point.
Definition numeric_limits.hpp:16