Solvers: adaptive steps¤
RejectionLoop(solver: solver_protocols.Solver, clip_dt: bool, error: Any, control: controllers.Control, while_loop: Callable, stop_gradient_through_dt: bool = True)
¤
An implementation of a rejection loop.
clip_dt = clip_dt
instance-attribute
¤
control = control
instance-attribute
¤
error = error
instance-attribute
¤
init(state_solver, dt) -> TimeStepState
¤
Initialise the adaptive solver state.
interp_at_t1(args)
¤
If we stepped exactly to t1, still interpolate.
interp_beyond_t1(args)
¤
If we stepped cleanly over t1, interpolate.
interp_skip(args)
¤
If step_from.t < t1, don't interpolate.
loop(state0: TimeStepState, *, t1, atol, rtol, eps, damp) -> tuple[Any, TimeStepState]
¤
Repeatedly attempt a step until the controller is happy.
Notably: - This function may never attempt a step if the current timestep is beyond t1. - If we step beyond t1, this function interpolates to t1.
solver = solver
instance-attribute
¤
step(s_and_t1_and_tols_and_damp)
¤
Do a rejection-loop step.
Keep attempting steps until one is accepted.
step_attempt(state: _RejectionLoopState, *, t1, atol, rtol, damp) -> _RejectionLoopState
¤
Attempt a step.
Perform a step with an IVP solver and propose a future time-step based on tolerances and error estimates.
step_extract_timestep_state(state: _RejectionLoopState) -> TimeStepState
¤
Extract a time-step-state after a successful rejection loop.
step_init_loopstate(s0: TimeStepState) -> _RejectionLoopState
¤
Initialise the rejection state.
stop_gradient_through_dt = stop_gradient_through_dt
instance-attribute
¤
while_loop = while_loop
instance-attribute
¤
S = TypeVar('S')
module-attribute
¤
T = TypeVar('T')
module-attribute
¤
TimeStepState
¤
A state variable type for adaptive time-stepping.
control: Any
instance-attribute
¤
The controller state.
dt: float
instance-attribute
¤
The time-step-size proposal for the next step.
error_step_from: Any
instance-attribute
¤
The error-estimate corresponding to 'step_from'.
interp_from: T
instance-attribute
¤
Where to continue interpolation from.
This is the left-hand side of the current subinterval.
step_from: T
instance-attribute
¤
Where to continue time-stepping from.
This is the right-hand side boundary of the current subinterval.
__all__ = ['RejectionLoop', 'TimeStepState', 'solve_adaptive_save_at', 'solve_adaptive_terminal_values']
module-attribute
¤
solve_adaptive_save_at(*, solver: solver_protocols.Solver, error, control: controllers.Control | None = None, clip_dt: bool = False, while_loop: Callable = flow.while_loop, warn=True) -> Callable[..., solver_protocols.Solution]
¤
Solve an initial value problem and return the solution at a pre-determined grid.
This algorithm implements the method by Krämer (2025). Please consider citing it if you use it for your research. A PDF is available here and Krämer's (2025) experiments are available here.
BibTex for Krämer (2025)
@InProceedings{kramer2024adaptive,
title = {Adaptive Probabilistic ODE Solvers Without Adaptive Memory
Requirements},
author = {Kr{\"a}mer, Nicholas},
booktitle = {Proceedings of the First International Conference on
Probabilistic Numerics},
pages = {12--24},
year = {2025},
editor = {Kanagawa, Motonobu and Cockayne, Jon and Gessner, Alexandra
and Hennig, Philipp},
volume = {271},
series = {Proceedings of Machine Learning Research},
publisher = {PMLR},
url = {https://proceedings.mlr.press/v271/kramer25a.html}
}
solve_adaptive_terminal_values(solver: solver_protocols.Solver, error, control: controllers.Control | None = None, clip_dt: bool = True, while_loop: Callable = flow.while_loop) -> Callable[..., solver_protocols.Solution]
¤
Simulate the terminal values of an initial value problem.