# State update¶

In Brian, a state updater transforms a set of equations into an abstract state update code (and therefore is automatically target-independent). In general, any function (or callable object) that takes an `Equations` object and returns abstract code (as a string) can be used as a state updater and passed to the `NeuronGroup` constructor as a `method` argument.

The more common use case is to specify no state updater at all or chose one by name, see Choice of state updaters below.

## Explicit state update¶

Explicit state update schemes can be specified in mathematical notation, using the `ExplicitStateUpdater` class. A state updater scheme contains a series of statements, defining temporary variables and a final line (starting with `x_new =`), giving the updated value for the state variable. The description can make reference to `t` (the current time), `dt` (the size of the time step), `x` (value of the state variable), and `f(x, t)` (the definition of the state variable `x`, assuming `dx/dt = f(x, t)`. In addition, state updaters supporting stochastic equations additionally make use of `dW` (a normal distributed random variable with variance `dt`) and `g(x, t)`, the factor multiplied with the noise variable, assuming `dx/dt = f(x, t) + g(x, t) * xi`.

Using this notation, simple forward Euler integration is specified as:

```x_new = x + dt * f(x, t)
```

A Runge-Kutta 2 (midpoint) method is specified as:

```k = dt * f(x,t)
x_new = x + dt * f(x +  k/2, t + dt/2)
```

When creating a new state updater using `ExplicitStateUpdater`, you can specify the `stochastic` keyword argument, determining whether this state updater does not support any stochastic equations (`None`, the default), stochastic equations with additive noise only (`'additive'`), or arbitrary stochastic equations (`'multiplicative'`). The provided state updaters use the Stratonovich interpretation for stochastic equations (which is the correct interpretation if the white noise source is seen as the limit of a coloured noise source with a short time constant). As a result of this, the simple Euler-Maruyama scheme (`x_new = x + dt*f(x, t) + dW*g(x, t)`) will only be used for additive noise.

An example for a general state updater that handles arbitrary multiplicative noise (under Stratonovich interpretation) is the derivative-free Milstein method:

```x_support = x + dt*f(x, t) + dt**.5 * g(x, t)
g_support = g(x_support, t)
k = 1/(2*dt**.5)*(g_support - g(x, t))*(dW**2)
x_new = x + dt*f(x,t) + g(x, t) * dW + k
```

Note that a single line in these descriptions is only allowed to mention `g(x, t)`, respectively `f(x, t)` only once (and you are not allowed to write, for example, `g(f(x, t), t)`). You can work around these restrictions by using intermediate steps, defining temporary variables, as in the above examples for `milstein` and `rk2`.

## Choice of state updaters¶

As mentioned in the beginning, you can pass arbitrary callables to the method argument of a `NeuronGroup`, as long as this callable converts an `Equations` object into abstract code. The best way to add a new state updater, however, is to register it with brian and provide a method to determine whether it is appropriate for a given set of equations. This way, it can be automatically chosen when no method is specified and it can be referred to with a name (i.e. you can pass a string like `'euler'` to the method argument instead of importing `euler` and passing a reference to the object itself).

If you create a new state updater using the `ExplicitStateUpdater` class, you have to specify what kind of stochastic equations it supports. The keyword argument `stochastic` takes the values `None` (no stochastic equation support, the default), `'additive'` (support for stochastic equations with additive noise), `'multiplicative'` (support for arbitrary stochastic equations).

After creating the state updater, it has to be registered with `StateUpdateMethod`:

```new_state_updater = ExplicitStateUpdater('...', stochastic='additive')
StateUpdateMethod.register('mymethod', new_state_updater)
```

The preferred way to do write new general state updaters (i.e. state updaters that cannot be described using the explicit syntax described above) is to extend the `StateUpdateMethod` class (but this is not strictly necessary, all that is needed is an object that implements a `__call__` method that operates on an `Equations` object and a dictionary of variables). Optionally, the state updater can be registered with `StateUpdateMethod` as shown above.

Note

All of the following is just here for future reference, it’s not implemented yet.

Implicit schemes often use Newton-Raphson or fixed point iterations. These can also be defined by mathematical statements, but the number of iterations is dynamic and therefore not easily vectorised. However, this might not be a big issue in C, GPU or even with Numba.

### Backward Euler¶

Backward Euler is defined as follows:

```x(t+dt)=x(t)+dt*f(x(t+dt),t+dt)
```

This is not a executable statement because the RHS depends on the future. A simple way is to perform fixed point iterations:

```x(t+dt)=x(t)
x(t+dt)=x(t)+dt*dx=f(x(t+dt),t+dt)    until increment<tolerance
```

This includes a loop with a different number of iterations depending on the neuron.