# ExplicitStateUpdater class

(Shortest import: `from brian2 import ExplicitStateUpdater)`

class brian2.stateupdaters.explicit.ExplicitStateUpdater(description, stochastic=None, custom_check=None)

  Bases: `StateUpdateMethod`

  An object that can be used for defining state updaters via a simple description (see below). Resulting instances can be passed to the `method` argument of the `NeuronGroup` constructor. As other state updater functions the `ExplicitStateUpdater` objects are callable, returning abstract code when called with an `Equations` object.

  A description of an explicit state updater consists of a (multi-line) string, containing assignments to variables and a final “x_new = …”, stating the integration result for a single timestep. The assignments can be used to define an arbitrary number of intermediate results and can refer to `f(x, t)` (the function being integrated, as a function of `x`, the previous value of the state variable and `t`, the time) and `dt`, the size of the timestep.

  For example, to define a Runge-Kutta 4 integrator (already provided as `rk4`), use:

      k1 = dt*f(x,t)
      k2 = dt*f(x+k1/2,t+dt/2)
      k3 = dt*f(x+k2/2,t+dt/2)
      k4 = dt*f(x+k3,t+dt)
      x_new = x+(k1+2*k2+2*k3+k4)/6

  Note that for stochastic equations, the function `f` only corresponds to the non-stochastic part of the equation. The additional function `g` corresponds to the stochastic part that has to be multiplied with the stochastic variable xi (a standard normal random variable – if the algorithm needs a random variable with a different variance/mean you have to multiply/add it accordingly). Equations with more than one stochastic variable do not have to be treated differently, the part referring to `g` is repeated for all stochastic variables automatically.

  Stochastic integrators can also make reference to `dW` (a normal distributed random number with variance `dt`) and `g(x, t)`, the stochastic part of an equation. A stochastic state updater could therefore use a description like:

      x_new = x + dt*f(x,t) + g(x, t) * dW

  For simplicity, the same syntax is used for state updaters that only support additive noise, even though `g(x, t)` does not depend on `x` or `t` in that case.

  There a some restrictions on the complexity of the expressions (but most can be worked around by using intermediate results as in the above Runge- Kutta example): Every statement can only contain the functions `f` and `g` once; The expressions have to be linear in the functions, e.g. you can use `dt*f(x, t)` but not `f(x, t)**2`.

  Parameters:

    description : str

    > A state updater description (see above).

    stochastic : {None, ‘additive’, ‘multiplicative’}

    > What kind of stochastic equations this state updater supports: `None` means no support of stochastic equations, `'additive'` means only equations with additive noise and `'multiplicative'` means supporting arbitrary stochastic equations.

  Raises

  `ValueError`

    If the parsing of the description failed.

  See also

  `euler`, `rk2`, `rk4`, `milstein`

  Notes

  Since clocks are updated after the state update, the time `t` used in the state update step is still at its previous value. Enumerating the states and discrete times, `x_new = x + dt*f(x, t)` is therefore understood as \(x_{i+1} = x_i + dt f(x_i, t_i)\), yielding the correct forward Euler integration. If the integrator has to refer to the time at the end of the timestep, simply use `t + dt` instead of `t`.

  Attributes

  `DESCRIPTION` | A complete state updater description
  `EXPRESSION` | A single expression
  `OUTPUT` | The last line of a state updater description
  `STATEMENT` | An assignment statement
  `TEMP_VAR` | Legal names for temporary variables

  Methods

  `DESCRIPTION` | A complete state updater description
  `EXPRESSION` | A single expression
  `OUTPUT` | The last line of a state updater description
  `STATEMENT` | An assignment statement
  `TEMP_VAR` | Legal names for temporary variables
  `__call__`(eqs[, variables, method_options]) | Apply a state updater description to model equations.
  `replace_func`(x, t, expr, temp_vars, eq_symbols) | Used to replace a single occurance of `f(x, t)` or `g(x, t)`: `expr` is the non-stochastic (in the case of `f`) or stochastic part (`g`) of the expression defining the right-hand-side of the differential equation describing `var`.

  Details

  DESCRIPTION = {[Group:({~{'x_new'} W:(A-Z_a-z, 0-9A-Z_a-z) Suppress:('=') rest of line})]... Group:({Suppress:('x_new') Suppress:('=') rest of line})}

    A complete state updater description

  EXPRESSION = rest of line

    A single expression

  OUTPUT = Group:({Suppress:('x_new') Suppress:('=') rest of line})

    The last line of a state updater description

  STATEMENT = Group:({~{'x_new'} W:(A-Z_a-z, 0-9A-Z_a-z) Suppress:('=') rest of line})

    An assignment statement

  TEMP_VAR = {~{'x_new'} W:(A-Z_a-z, 0-9A-Z_a-z)}

    Legal names for temporary variables

  DESCRIPTION() → ParserElement

    Requires all given `ParserElement` s to be found in the given order. Expressions may be separated by whitespace. May be constructed using the `'+'` operator. May also be constructed using the `'-'` operator, which will suppress backtracking.

    Example:

        integer = Word(nums)
        name_expr = Word(alphas)[1, ...]

        expr = And([integer("id"), name_expr("name"), integer("age")])
        # more easily written as:
        expr = integer("id") + name_expr("name") + integer("age")

  EXPRESSION() → ParserElement

    Token for matching strings that match a given regular expression. Defined with string specifying the regular expression in a form recognized by the stdlib Python re module. If the given regex contains named groups (defined using `(?P<name>...)`), these will be preserved as named `ParseResults`.

    If instead of the Python stdlib `re` module you wish to use a different RE module (such as the `regex` module), you can do so by building your `Regex` object with a compiled RE that was compiled using `regex`.

    The parameters `pattern` and `flags` are passed to the `re.compile()` function as-is. See the Python re module module for an explanation of the acceptable patterns and flags.

    Example:

        realnum = Regex(r"[+-]?\d+\.\d*")
        # ref: https://stackoverflow.com/questions/267399/how-do-you-match-only-valid-roman-numerals-with-a-regular-expression
        roman = Regex(r"M{0,4}(CM|CD|D?{0,3})(XC|XL|L?X{0,3})(IX|IV|V?I{0,3})")

        # named fields in a regex will be returned as named results
        date = Regex(r'(?P<year>\d{4})-(?P<month>\d\d?)-(?P<day>\d\d?)')

        # the Regex class will accept regular expressions compiled using the
        # re module
        import re
        parser = pp.Regex(re.compile(r'[0-9]'))

  OUTPUT() → ParserElement

    Converter to return the matched tokens as a list - useful for returning tokens of `ZeroOrMore` and `OneOrMore` expressions.

    The optional `aslist` argument when set to True will return the parsed tokens as a Python list instead of a pyparsing ParseResults.

    Example:

        >>> ident = Word(alphas)
        >>> num = Word(nums)
        >>> term = ident | num
        >>> func = ident + Opt(DelimitedList(term))
        >>> print(func.parse_string("fn a, b, 100"))
        ['fn', 'a', 'b', '100']

        >>> func = ident + Group(Opt(DelimitedList(term)))
        >>> print(func.parse_string("fn a, b, 100"))
        ['fn', ['a', 'b', '100']]

  STATEMENT() → ParserElement

    Converter to return the matched tokens as a list - useful for returning tokens of `ZeroOrMore` and `OneOrMore` expressions.

    The optional `aslist` argument when set to True will return the parsed tokens as a Python list instead of a pyparsing ParseResults.

    Example:

        >>> ident = Word(alphas)
        >>> num = Word(nums)
        >>> term = ident | num
        >>> func = ident + Opt(DelimitedList(term))
        >>> print(func.parse_string("fn a, b, 100"))
        ['fn', 'a', 'b', '100']

        >>> func = ident + Group(Opt(DelimitedList(term)))
        >>> print(func.parse_string("fn a, b, 100"))
        ['fn', ['a', 'b', '100']]

  TEMP_VAR() → ParserElement

    Requires all given `ParserElement` s to be found in the given order. Expressions may be separated by whitespace. May be constructed using the `'+'` operator. May also be constructed using the `'-'` operator, which will suppress backtracking.

    Example:

        integer = Word(nums)
        name_expr = Word(alphas)[1, ...]

        expr = And([integer("id"), name_expr("name"), integer("age")])
        # more easily written as:
        expr = integer("id") + name_expr("name") + integer("age")

  __call__(eqs, variables=None, method_options=None)

    Apply a state updater description to model equations.

    Parameters:

      eqs : `Equations`

      > The equations describing the model

      variables: dict-like, optional :

      > The `Variable` objects for the model. Ignored by the explicit state updater.

      method_options : dict, optional

      > Additional options to the state updater (not used at the moment for the explicit state updaters).

    Examples

        >>> from brian2 import *
        >>> eqs = Equations('dv/dt = -v / tau : volt')
        >>> print(euler(eqs))
        _v = -dt*v/tau + v
        v = _v
        >>> print(rk4(eqs))
        __k_1_v = -dt*v/tau
        __k_2_v = -dt*(__k_1_v/2 + v)/tau
        __k_3_v = -dt*(__k_2_v/2 + v)/tau
        __k_4_v = -dt*(__k_3_v + v)/tau
        _v = __k_1_v/6 + __k_2_v/3 + __k_3_v/3 + __k_4_v/6 + v
        v = _v

  replace_func(x, t, expr, temp_vars, eq_symbols, stochastic_variable=None)

    Used to replace a single occurance of `f(x, t)` or `g(x, t)`: `expr` is the non-stochastic (in the case of `f`) or stochastic part (`g`) of the expression defining the right-hand-side of the differential equation describing `var`. It replaces the variable `var` with the value given as `x` and `t` by the value given for `t`. Intermediate variables will be replaced with the appropriate replacements as well.

    For example, in the `rk2` integrator, the second step involves the calculation of `f(k/2 + x, dt/2 + t)`. If `var` is `v` and `expr` is `-v / tau`, this will result in `-(_k_v/2 + v)/tau`.

    Note that this deals with only one state variable `var`, given as an argument to the surrounding `_generate_RHS` function.