braincell.quad.backward_euler_step

braincell.quad.backward_euler_step#

braincell.quad.backward_euler_step(target, *args, excluded_paths=())[source]#

Advance one step with the linearised backward (implicit) Euler method.

Backward Euler discretises an ODE \(dy/dt = f(t, y)\) as

\[y_{n+1} = y_n + \Delta t \, f(t_{n+1}, y_{n+1}),\]

which is implicit in \(y_{n+1}\). Rather than running a Newton solver to convergence (see implicit_euler_step() for that variant), this routine takes a single Newton step from a local Jacobian:

\[J = \frac{\partial f}{\partial y}\bigg|_{y_n}, \qquad (I - \Delta t \, J)\, \Delta y = \Delta t \, f(t_n, y_n), \qquad y_{n+1} = y_n + \Delta y.\]

The result is the so-called Rosenbrock / linearly implicit Euler update — first-order accurate, \(L\)-stable, and considerably cheaper than full Newton because the Jacobian is built once per step and the linear system is solved by a batched jax.scipy.linalg.solve(). It is the recommended choice for

medium-stiff Hodgkin-Huxley models when matrix-exponential schemes such as exp_euler_step() are too expensive.

Parameters:
  • target (DiffEqModule) – The module whose differential states are to be advanced. Must be an HHTypedNeuron (single compartment or multi-compartment).

  • *args – Extra positional arguments forwarded to target’s pre_integral(), compute_derivative(), and post_integral() hooks.

Returns:

target’s differential states are updated in place.

Return type:

None

Raises:

AssertionError – Raised inside apply_standard_solver_step() if target is not a DiffEqModule.

See also

implicit_euler_step

Full Newton iteration on the same residual.

exp_euler_step

Matrix-exponential exponential Euler step.

Notes

The current time and step size are read from the active brainstate.environ context. State leaves are stacked along the

last axis (merging='stack') before the linear solve.

Examples

>>> import brainstate
>>> import brainunit as u
>>> from braincell.quad import backward_euler_step
>>> with brainstate.environ.context(t=0. * u.ms, dt=0.025 * u.ms):
...     backward_euler_step(my_neuron, input_current)