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.

Implicit state updates
----------------------

.. 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.

