SDE solvers¤
See also How to choose a solver.
Term structure
The type of solver chosen determines how the terms
argument of diffeqsolve
should be laid out. Most of them operate in the same way whether they are solving an ODE or an SDE, and as such expected that it should be a single AbstractTerm
. For SDEs that typically means a diffrax.MultiTerm
wrapping together a drift (diffrax.ODETerm
) and diffusion (diffrax.ControlTerm
). (Although you could also include any other term, e.g. an exogenous forcing term, if you wished.) For example:
drift = lambda t, y, args: -y
diffusion = lambda t, y, args: y[..., None]
bm = UnsafeBrownianPath(shape=(1,), key=...)
terms = MultiTerm(ODETerm(drift), ControlTerm(diffusion, bm))
diffeqsolve(terms, solver=Euler(), ...)
Some solvers are SDE-specific. For these, such as for example diffrax.StratonovichMilstein
, then terms
must specifically be of the form MultiTerm(ODETerm(...), SomeOtherTerm(...))
(Typically SomeOTherTerm
will be a ControlTerm
or WeaklyDiagonalControlTerm
) representing the drift and diffusion specifically.
For those SDE-specific solvers then this is documented below, and the term structure is available programmatically under <solver>.term_structure
.
Explicit Runge--Kutta (ERK) methods¤
diffrax.Euler (AbstractItoSolver)
¤
Euler's method.
1st order explicit Runge--Kutta method. Does not support adaptive step sizing. Uses 1 stage. Uses 1st order local linear interpolation for dense/ts output.
When used to solve SDEs, converges to the Itô solution.
diffrax.Heun (AbstractERK, AbstractStratonovichSolver)
¤
Heun's method.
2nd order explicit Runge--Kutta method. Has an embedded Euler method for adaptive step sizing. Uses 2 stages. Uses 2nd-order Hermite interpolation for dense/ts output.
Also sometimes known as either the "improved Euler method", "modified Euler method" or "explicit trapezoidal rule".
Should not be confused with Heun's third order method, which is a different (higher order) method occasionally also just referred to as "Heun's method".
When used to solve SDEs, converges to the Stratonovich solution.
diffrax.Midpoint (AbstractERK, AbstractStratonovichSolver)
¤
Midpoint method.
2nd order explicit Runge--Kutta method. Has an embedded Euler method for adaptive step sizing. Uses 2 stages. Uses 2nd order Hermite interpolation for dense/ts output.
Also sometimes known as the "modified Euler method".
When used to solve SDEs, converges to the Stratonovich solution.
diffrax.Ralston (AbstractERK, AbstractStratonovichSolver)
¤
Ralston's method.
2nd order explicit Runge--Kutta method. Has an embedded Euler method for adaptive step sizing. Uses 2 stages. Uses 2nd order Hermite interpolation for dense output.
When used to solve SDEs, converges to the Stratonovich solution.
Info
In addition to the solvers above, then most higher-order ODE solvers can actually also be used as SDE solvers. They will typically converge to the Stratonovich solution. In practice this is computationally wasteful as they will not obtain more accurate solutions when applied to SDEs.
Reversible methods¤
These are reversible in the same way as when applied to ODEs. See here.
diffrax.ReversibleHeun (AbstractAdaptiveSolver, AbstractStratonovichSolver)
¤
Reversible Heun method.
Algebraically reversible 2nd order method. Has an embedded 1st order method for adaptive step sizing. Uses 1st order local linear interpolation for dense/ts output.
When used to solve SDEs, converges to the Stratonovich solution.
Reference
@article{kidger2021efficient,
author={Kidger, Patrick and Foster, James and Li, Xuechen and Lyons, Terry},
title={{E}fficient and {A}ccurate {G}radients for {N}eural {SDE}s},
year={2021},
journal={Advances in Neural Information Processing Systems}
}
SDE-only solvers¤
Term structure
These solvers are SDE-specific. For these, terms
must specifically be of the form MultiTerm(ODETerm(...), SomeOtherTerm(...))
(Typically SomeOTherTerm
will be a ControlTerm
or WeaklyDiagonalControlTerm
) representing the drift and diffusion specifically.
diffrax.EulerHeun (AbstractStratonovichSolver)
¤
Euler-Heun method.
Uses a 1st order local linear interpolation scheme for dense/ts output.
This should be called with terms=MultiTerm(drift_term, diffusion_term)
, where the
drift is an ODETerm
.
Used to solve SDEs, and converges to the Stratonovich solution.
diffrax.ItoMilstein (AbstractItoSolver)
¤
Milstein's method; Itô version.
Used to solve SDEs, and converges to the Itô solution. Uses local linear interpolation for dense/ts output.
This should be called with terms=MultiTerm(drift_term, diffusion_term)
, where the
drift is an ODETerm
.
Warning
Requires commutative noise. Note that this commutativity condition is not checked.
diffrax.StratonovichMilstein (AbstractStratonovichSolver)
¤
Milstein's method; Stratonovich version.
Used to solve SDEs, and converges to the Stratonovich solution. Uses local linear interpolation for dense/ts output.
This should be called with terms=MultiTerm(drift_term, diffusion_term)
, where the
drift is an ODETerm
.
Warning
Requires commutative noise. Note that this commutativity condition is not checked.
Wrapper solvers¤
diffrax.HalfSolver (AbstractAdaptiveSolver, AbstractWrappedSolver)
¤
Wraps another solver, trading cost in order to provide error estimates. (That is, it means the solver can be used with an adaptive step size controller, regardless of whether the underlying solver supports adaptive step sizing.)
For every step of the wrapped solver, it does this by also making two half-steps, and comparing the results between the full step and the two half steps. Hence the name "HalfSolver".
As such each step costs 3 times the computational cost of the wrapped solver, whilst producing results that are roughly twice as accurate, in addition to producing error estimates.
Tip
Many solvers already provide error estimates, making HalfSolver
primarily
useful when using a solver that doesn't provide error estimates -- e.g.
diffrax.Euler
. Such solvers are most common when solving SDEs.
__init__(self, solver: AbstractSolver)
¤
Arguments:
solver
: The solver to wrap.