Skip to content

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[~_SolverState]) ¤

Arguments:

  • solver: The solver to wrap.