ode_expeuler_step

ode_expeuler_step#

class braintools.quad.ode_expeuler_step(f, y, t, *args, **kwargs)#

One-step Exponential Euler method for ODEs with linearized drift.

The drift f is linearized around the current state via its diagonal Jacobian A = \partial f / \partial y and the linear part is integrated exactly over one step:

\[y_{n+1} = y_n + \Delta t\, \varphi(\Delta t\, A)\, f(y_n, t_n), \qquad \varphi(z) = \frac{e^{z} - 1}{z}.\]

For a scalar linear ODE dy/dt = A y the method is exact. If the state y has unit [X], the drift f(y, t) must have unit [X]/[T].

Parameters:
  • f (Callable[[PyTree, float | Quantity, ...], PyTree]) – Drift function f(y, t, *args) used in the exponential update.

  • y (Array | ndarray | bool | number | bool | int | float | complex | Quantity) – Current state. Must have a floating dtype (float16/32/64 or bfloat16).

  • t (Array | ndarray | bool | number | bool | int | float | complex | Quantity) – Current time.

  • *args – Additional positional arguments forwarded to f.

Returns:

The updated state y_{n+1}.

Return type:

ArrayLike

Raises:

ValueError – If y does not have a floating dtype.

See also

ode_euler_step

Explicit (forward) Euler step.

sde_expeuler_step

Exponential Euler step for SDEs.

Examples

>>> import brainstate
>>> import brainunit as u
>>> from braintools.quad import ode_expeuler_step
>>> def fun(x, t):
...     return -x
>>> with brainstate.environ.context(dt=0.1):
...     x_next = ode_expeuler_step(fun, 1.0, 0.0)
>>> float(x_next)  # exp(-0.1)
0.904837429523468

>>> with brainstate.environ.context(dt=0.1 * u.ms):
...     v_next = ode_expeuler_step(lambda v, t: -v / (10.0 * u.ms),
...                                -65.0 * u.mV, 0.0 * u.ms)