68 std::optional<TaylorExponentialDiagnostics<uni20::make_real_t<Scalar>>>
diagnostics;
74template <uni20::Real Scalar>
Scalar default_taylor_exponential_tolerance()
79template <uni20::Real Scalar>
80Scalar effective_taylor_exponential_tolerance(TaylorExponentialParams<Scalar>
const& params)
82 return params.tolerance >
Scalar{} ? params.tolerance : default_taylor_exponential_tolerance<Scalar>();
85template <uni20::Real Scalar>
86void validate_taylor_exponential_params(Scalar operator_norm_bound, TaylorExponentialParams<Scalar>
const& params)
88 if (!
uni20::isfinite(operator_norm_bound) || operator_norm_bound < Scalar{})
90 throw std::invalid_argument(
"Taylor exponential requires a finite non-negative operator norm bound");
94 throw std::invalid_argument(
"Taylor exponential requires a finite non-negative tolerance");
96 if (params.step_norm_limit <= Scalar{} || !
uni20::isfinite(params.step_norm_limit))
98 throw std::invalid_argument(
"Taylor exponential requires a positive finite step norm limit");
100 if (params.max_taylor_degree <= 0)
102 throw std::invalid_argument(
"Taylor exponential requires a positive maximum Taylor degree");
104 if (params.max_scaling_steps <= 0)
106 throw std::invalid_argument(
"Taylor exponential requires a positive maximum scaling step count");
110template <uni20::Real Scalar>
111int taylor_scaling_steps(Scalar scaled_operator_norm, TaylorExponentialParams<Scalar>
const& params)
113 if (scaled_operator_norm == Scalar{})
120 Scalar
const ratio = scaled_operator_norm / params.step_norm_limit;
121 Scalar
const steps =
ceil(std::max(Scalar{1},
ratio));
122 if (steps >
static_cast<Scalar
>(params.max_scaling_steps))
124 throw std::runtime_error(
"Taylor exponential requires more scaling steps than allowed");
128 throw std::overflow_error(
"Taylor exponential scaling step count exceeds int range");
130 return static_cast<int>(steps);
133template <uni20::Real Scalar> Scalar taylor_tail_bound(Scalar term_norm, Scalar step_norm_bound,
int degree)
135 if (term_norm == Scalar{} || step_norm_bound == Scalar{})
140 Scalar
const ratio = step_norm_bound /
static_cast<Scalar
>(
degree + 1);
141 if (ratio >= Scalar{1})
145 return term_norm *
ratio / (Scalar{1} -
ratio);
148template <uni20::Real Scalar>
149Scalar amplified_tail_bound(Scalar local_tail_bound, Scalar step_norm_bound,
int remaining_steps)
151 if (local_tail_bound == Scalar{} || remaining_steps <= 0)
153 return local_tail_bound;
159 Scalar
const exponent =
static_cast<Scalar
>(remaining_steps) * step_norm_bound;
161 if (exponent >=
log(max_value) -
log(local_tail_bound))
165 return local_tail_bound *
exp(exponent);
168template <uni20::RealOrComplex Scalar,
typename Vector>
169void attach_taylor_exponential_diagnostics(TaylorExponentialResult<Scalar, Vector>& result,
177 result.diagnostics = diagnostics;
204 KrylovMatrixFreeOperator<Vector, Scalar> Ops>
205 requires(std::constructible_from<uni20::make_real_t<Scalar>, TimeScalar> ||
207TaylorExponentialResult<Scalar, Vector>
214 detail::validate_taylor_exponential_params(operator_norm_bound, params);
221 throw std::invalid_argument(
"Taylor exponential requires a finite time coefficient");
224 Real const tolerance = detail::effective_taylor_exponential_tolerance(params);
225 Real const scaled_operator_norm = time_abs * operator_norm_bound;
228 throw std::overflow_error(
"Taylor exponential scaled operator norm overflowed");
230 int const scaling_steps = detail::taylor_scaling_steps(scaled_operator_norm, params);
231 Real const step_norm_bound = scaled_operator_norm /
static_cast<Real>(scaling_steps);
232 Real const step_tolerance = tolerance /
static_cast<Real>(scaling_steps);
233 Scalar
const step_time = time_scalar / Scalar{
static_cast<Real>(scaling_steps)};
235 Vector state = ops.allocate_like(initial);
236 ops.copy(state, initial);
238 TaylorExponentialDiagnostics<Real> diagnostics;
239 diagnostics.scaling_steps = scaling_steps;
240 diagnostics.tolerance = tolerance;
241 diagnostics.operator_norm_bound = operator_norm_bound;
242 diagnostics.step_norm_bound = step_norm_bound;
244 if (time_abs ==
Real{} || operator_norm_bound ==
Real{} || norm_or_inner_product<Scalar>(ops, state) ==
Real{})
246 TaylorExponentialResult<Scalar, Vector> result{.action = std::move(state),
247 .estimated_error =
Real{},
249 .scaling_steps = scaling_steps,
250 .max_degree_used = 0,
252 .diagnostics = std::nullopt};
253 detail::attach_taylor_exponential_diagnostics(result, diagnostics, params.diagnostics);
257 Vector step_result = ops.allocate_like(initial);
258 Vector term = ops.allocate_like(initial);
259 Vector scratch = ops.allocate_like(initial);
261 bool all_steps_converged =
true;
263 int matvec_count = 0;
264 int max_degree_used = 0;
266 for (
int step = 0; step < scaling_steps; ++step)
268 ops.copy(step_result, state);
269 ops.copy(term, state);
271 bool step_converged =
false;
278 ops.matvec(scratch, term);
280 ops.scal(scratch, step_time /
static_cast<Real>(
degree));
281 ops.copy(term, scratch);
282 ops.axpy(step_result, Scalar{1}, term);
284 final_term_norm = norm_or_inner_product<Scalar>(ops, term);
285 final_tail_bound = detail::taylor_tail_bound(final_term_norm, step_norm_bound,
degree);
287 if (final_tail_bound <= step_tolerance)
289 step_converged =
true;
294 max_degree_used = std::max(max_degree_used, degree_used);
295 diagnostics.final_step_degree = degree_used;
296 diagnostics.final_tail_bound = final_tail_bound;
297 diagnostics.final_term_norm = final_term_norm;
298 estimated_error += detail::amplified_tail_bound(final_tail_bound, step_norm_bound, scaling_steps - step - 1);
300 ops.copy(state, step_result);
303 all_steps_converged =
false;
304 if (params.throw_on_nonconvergence)
306 throw std::runtime_error(
"Taylor exponential did not satisfy the requested tolerance");
313 diagnostics.matvec_count = matvec_count;
314 diagnostics.max_degree_used = max_degree_used;
315 diagnostics.estimated_error = estimated_error;
316 diagnostics.converged = all_steps_converged;
318 TaylorExponentialResult<Scalar, Vector> result{.action = std::move(state),
319 .estimated_error = estimated_error,
320 .matvec_count = matvec_count,
321 .scaling_steps = scaling_steps,
322 .max_degree_used = max_degree_used,
323 .converged = all_steps_converged,
324 .diagnostics = std::nullopt};
325 detail::attach_taylor_exponential_diagnostics(result, diagnostics, params.diagnostics);
Concept for complex scalar types.
Definition scalar_concepts.hpp:75
Concept for types that are either real or complex.
Definition scalar_concepts.hpp:87
Concept for real scalar types (float, double, etc.).
Definition scalar_concepts.hpp:69
Concept for numeric scalar types (integer, real, or complex).
Definition scalar_concepts.hpp:81
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
R ratio(DiagnosticMagnitude< R > const &a, DiagnosticMagnitude< R > const &b)
Definition gmres_diagnostics.hpp:125
Definition block_tensor_vector.hpp:23
TaylorExponentialResult< Scalar, Vector > taylor_exponential_action(Ops &ops, Vector const &initial, TimeScalar time, uni20::make_real_t< Scalar > operator_norm_bound, TaylorExponentialParams< uni20::make_real_t< Scalar > > const ¶ms={})
Compute exp(t A) v using conservative scaled Taylor series.
Definition taylor_exponential.hpp:208
KrylovDiagnosticsLevel
Amount of solver-internal diagnostic state to retain.
Definition matrix_free.hpp:37
std::size_t validate_matrix_free_dimensions(Ops const &ops, Vector const &vector, char const *context)
Validate that an initial/prototype vector matches the matrix-free problem dimension.
Definition matrix_free.hpp:549
constexpr detail::scalar_math::abs_fn abs
Absolute value or complex magnitude, preserving the selected scalar implementation.
Definition math.hpp:459
Definition async/async.hpp:26
mpcomplex log(mpcomplex const &z)
Principal logarithm, with the sign of imaginary zero selecting the cut side.
Definition mpcomplex.hpp:505
auto degree(QNum const &q) -> int
Return the integral degree of a quantum number.
Definition qnum.hpp:270
mpreal ceil(mpreal const &x)
Round toward positive infinity; exact inputs produce exact integers.
Definition mpreal_functions.hpp:72
mpcomplex exp(mpcomplex const &z)
Definition mpcomplex.hpp:503
Diagnostic state for Taylor exponential actions.
Definition taylor_exponential.hpp:43
int final_step_degree
Definition taylor_exponential.hpp:47
Scalar operator_norm_bound
Definition taylor_exponential.hpp:49
int max_degree_used
Definition taylor_exponential.hpp:46
int scaling_steps
Definition taylor_exponential.hpp:45
Scalar tolerance
Definition taylor_exponential.hpp:48
int matvec_count
Definition taylor_exponential.hpp:44
Scalar final_tail_bound
Definition taylor_exponential.hpp:52
Scalar final_term_norm
Definition taylor_exponential.hpp:53
bool converged
Definition taylor_exponential.hpp:54
Scalar estimated_error
Definition taylor_exponential.hpp:51
Scalar step_norm_bound
Definition taylor_exponential.hpp:50
Parameters for conservative Taylor scaling exponential actions.
Definition taylor_exponential.hpp:25
KrylovDiagnosticsLevel diagnostics
Optional diagnostic retention level.
Definition taylor_exponential.hpp:37
Scalar step_norm_limit
Target upper bound for ||h A|| in one scaled Taylor step.
Definition taylor_exponential.hpp:29
int max_scaling_steps
Maximum number of scaled Taylor steps allowed.
Definition taylor_exponential.hpp:33
Scalar tolerance
Absolute action tolerance; zero selects 100 * epsilon.
Definition taylor_exponential.hpp:27
int max_taylor_degree
Maximum Taylor degree allowed within one scaled step.
Definition taylor_exponential.hpp:31
bool throw_on_nonconvergence
Throw if any scaled step fails to satisfy the tail bound.
Definition taylor_exponential.hpp:35
Result for validation-oriented Taylor exponential actions.
Definition taylor_exponential.hpp:61
std::optional< TaylorExponentialDiagnostics< uni20::make_real_t< Scalar > > > diagnostics
Definition taylor_exponential.hpp:68
uni20::make_real_t< Scalar > estimated_error
Definition taylor_exponential.hpp:63
int max_degree_used
Definition taylor_exponential.hpp:66
int scaling_steps
Definition taylor_exponential.hpp:65
int matvec_count
Definition taylor_exponential.hpp:64
bool converged
Definition taylor_exponential.hpp:67
Vector action
Definition taylor_exponential.hpp:62
Project-level numeric limits customization point.
Definition numeric_limits.hpp:16