izhikevich#

class brainpy.state.izhikevich(in_size, a=0.02, b=0.2, c=Quantity(-65., "mV"), d=Quantity(8., "mV"), I_e=Quantity(0., "pA"), V_th=Quantity(30., "mV"), V_min=None, consistent_integration=True, V_initializer=Constant(value=-65. mV), U_initializer=None, spk_fun=ReluGrad(alpha=0.3, width=1.0), spk_reset='hard', name=None)#

Izhikevich neuron model (NEST-compatible).

This model is a brainpy.state re-implementation of the NEST simulator izhikevich model, using NEST-standard parameterization. It implements the simple spiking neuron model introduced by Izhikevich [1], which reproduces spiking and bursting behavior of known types of cortical neurons through a two-dimensional system of ordinary differential equations.

1. Mathematical Formulation

The model is defined by the following coupled differential equations:

\[\frac{dV_{\text{m}}}{dt} = 0.04\, V_{\text{m}}^2 + 5\, V_{\text{m}} + 140 - U_{\text{m}} + I_{\text{e}}\]
\[\frac{dU_{\text{m}}}{dt} = a\,(b\, V_{\text{m}} - U_{\text{m}})\]

where:

  • \(V_{\text{m}}\) is the membrane potential (mV)

  • \(U_{\text{m}}\) is the recovery variable (mV), representing the combined effects of sodium channel inactivation and potassium channel activation

  • \(I_{\text{e}}\) is the total input current (pA): external constant current plus synaptic current

  • \(a\) is the time scale of the recovery variable (dimensionless)

  • \(b\) describes the sensitivity of \(U_{\text{m}}\) to subthreshold fluctuations of \(V_{\text{m}}\) (dimensionless)

2. Spike Emission and Reset

A spike is emitted when \(V_{\text{m}}\) reaches the threshold \(V_{\text{th}}\). At this point the state variables undergo an instantaneous reset:

\[\begin{split}&\text{if}\; V_m \geq V_{th}:\\ &\quad V_m \leftarrow c\\ &\quad U_m \leftarrow U_m + d\end{split}\]

where:

  • \(c\) is the after-spike reset value for \(V_{\text{m}}\) (mV)

  • \(d\) is the after-spike increment of \(U_{\text{m}}\) (mV)

Each incoming spike adds to \(V_{\text{m}}\) by the synaptic weight associated with the spike (delta-coupling, instantaneous PSC).

3. Integration Scheme

This model offers two forms of Euler integration, selected by the boolean parameter consistent_integration:

  • Standard forward Euler (consistent_integration = True, default): Both \(V_{\text{m}}\) and \(U_{\text{m}}\) are updated based on their values at the beginning of the time step:

    \[\begin{split}V_{n+1} &= V_n + h \cdot f(V_n, U_n, I_n) + \Delta V_{\text{syn}}\\ U_{n+1} &= U_n + h \cdot a \cdot (b \cdot V_n - U_n)\end{split}\]

    where \(h\) is the time step and \(\Delta V_{\text{syn}}\) is the delta synaptic input.

  • Published Izhikevich (2003) numerics (consistent_integration = False): The membrane potential is updated in two half-steps of size \(h/2\), and the recovery variable uses the updated \(V_{\text{m}}\):

    \[\begin{split}V_{\text{mid}} &= V_n + \frac{h}{2} \cdot f(V_n, U_n, I_n)\\ V_{n+1} &= V_{\text{mid}} + \frac{h}{2} \cdot f(V_{\text{mid}}, U_n, I_n)\\ U_{n+1} &= U_n + h \cdot a \cdot (b \cdot V_{n+1} - U_n)\end{split}\]

    This scheme is recommended only for replicating published results and requires \(h = 1.0\,\text{ms}\) for consistency with the original paper. For a detailed analysis of the numerical differences, see [2].

4. Synaptic Input

Synaptic input enters via two channels:

  • Spike (delta) input — delivered through add_delta_input() or the delta keyword; added directly to \(V_{\text{m}}\) at the integration step as an instantaneous voltage jump.

  • Current input — delivered through the x argument of update(). Following NEST ring-buffer semantics, the current applied at simulation step k takes effect at step k + 1 (one-step delay). This is stored in the I state variable.

5. Physical Units and Numerical Assumptions

The original Izhikevich model uses dimensionless equations with implicit units. This implementation follows NEST conventions:

  • Membrane potential \(V_{\text{m}}\) in mV

  • Recovery variable \(U_{\text{m}}\) in mV

  • Input current \(I_{\text{e}}\) in pA (with implicit resistance R=1)

  • Time constants \(a\), \(b\) are dimensionless

  • Time step \(h\) in ms

The coefficients 0.04 and 5 in the voltage equation have implicit units that make the equation dimensionally consistent when \(V_{\text{m}}\) is in mV and time in ms.

6. Computational Considerations

  • The quadratic voltage term can lead to numerical instability if the time step is too large. Use \(h \leq 1.0\,\text{ms}\) for stability.

  • The V_min parameter prevents unphysical negative voltage divergence.

  • The model uses float64 precision internally for all integration steps to match NEST numerical accuracy.

Parameters:
  • in_size (int, tuple of int) – Number of neurons or shape of the neuron population. Determines the shape of all state variables and parameters (varshape).

  • a (float, array_like, optional) – Time scale of the recovery variable \(U_{\text{m}}\). Dimensionless. Default: 0.02. Typical values: 0.02 (regular spiking), 0.1 (fast spiking).

  • b (float, array_like, optional) – Sensitivity of \(U_{\text{m}}\) to subthreshold fluctuations of \(V_{\text{m}}\). Dimensionless. Default: 0.2. Typical values: 0.2 (regular spiking), 0.25 (chattering).

  • c (Quantity (voltage), array_like, optional) – After-spike reset value of \(V_{\text{m}}\). Default: -65 mV. Typical values: -65 mV (regular spiking), -50 mV (chattering).

  • d (Quantity (voltage), array_like, optional) – After-spike increment of \(U_{\text{m}}\). Default: 8 mV. Typical values: 8 mV (regular spiking), 2 mV (fast spiking).

  • I_e (Quantity (current), array_like, optional) – Constant external input current. Default: 0 pA. Positive values provide tonic excitation.

  • V_th (Quantity (voltage), array_like, optional) – Spike threshold voltage. Default: 30 mV. NEST uses 30 mV as the practical threshold for the Izhikevich model.

  • V_min (Quantity (voltage), array_like, optional) – Absolute lower bound for \(V_{\text{m}}\). Default: None (no bound). When set, prevents unphysical negative voltage divergence. Typical value: -100 mV.

  • consistent_integration (bool, optional) – Integration scheme selector. Default: True. - True: standard forward Euler (recommended). - False: published Izhikevich (2003) half-step numerics (requires dt=1ms).

  • V_initializer (callable, optional) – Initialization function for \(V_{\text{m}}\). Default: Constant(-65 mV). Must accept (shape, batch_size) and return voltage values.

  • U_initializer (callable, optional) – Initialization function for \(U_{\text{m}}\). Default: None (uses \(U_0 = b \cdot V_0\), matching NEST). Must accept (shape, batch_size) and return voltage values.

  • spk_fun (callable, optional) – Surrogate gradient function for differentiable spike generation. Default: ReluGrad(). Must map (V - V_th) / scale to [0, 1] with defined gradient.

  • spk_reset (str, optional) – Spike reset mode. Default: ‘hard’. - ‘hard’: stop gradient at reset (matches NEST dynamics). - ‘soft’: allow gradient flow through reset.

  • name (str, optional) – Name of the neuron population. Default: None.

Parameter Mapping

NEST Parameter

brainpy.state

Math Equivalent

Description

a

a

\(a\)

Time scale of recovery variable \(U_{\text{m}}\)

b

b

\(b\)

Sensitivity of \(U_{\text{m}}\) to \(V_{\text{m}}\)

c

c

\(c\)

After-spike reset value of \(V_{\text{m}}\) (mV)

d

d

\(d\)

After-spike increment of \(U_{\text{m}}\) (mV)

I_e

I_e

\(I_{\text{e}}\)

Constant input current (pA)

V_th

V_th

\(V_{\text{th}}\)

Spike threshold (mV)

V_min

V_min

\(V_{\text{min}}\)

Lower bound for \(V_{\text{m}}\) (mV, optional)

consistent_integration

consistent_integration

Forward Euler (True) vs. published numerics (False)

V#

Membrane potential \(V_{\text{m}}\) in mV. Shape: (*varshape,) or (batch_size, *varshape).

Type:

HiddenState

U#

Recovery variable \(U_{\text{m}}\) in mV. Shape: (*varshape,) or (batch_size, *varshape).

Type:

HiddenState

I#

Buffered input current from the previous time step in pA (one-step delayed ring buffer, matching NEST semantics). Shape: (*varshape,) or (batch_size, *varshape).

Type:

ShortTermState

Examples

Example 1: Regular spiking (RS) neuron

>>> import brainpy.state as bp
>>> import brainstate
>>> import saiunit as u
>>>
>>> # Create a regular spiking neuron
>>> neuron = bp.izhikevich(1, a=0.02, b=0.2, c=-65*u.mV, d=8*u.mV)
>>> neuron.init_state()
>>>
>>> # Simulate with constant input
>>> with brainstate.environ.context(dt=1.0*u.ms):
...     spikes = []
...     for _ in range(100):
...         spk = neuron.update(x=10.0*u.pA)
...         spikes.append(spk)

Example 2: Fast spiking (FS) neuron

>>> # Create a fast spiking neuron
>>> neuron = bp.izhikevich(1, a=0.1, b=0.2, c=-65*u.mV, d=2*u.mV)
>>> neuron.init_state()

Example 3: Chattering (CH) neuron

>>> # Create a chattering neuron
>>> neuron = bp.izhikevich(1, a=0.02, b=0.2, c=-50*u.mV, d=2*u.mV)
>>> neuron.init_state()

Example 4: Population with heterogeneous parameters

>>> import jax.numpy as jnp
>>>
>>> # Create 100 neurons with random parameter variation
>>> key = jax.random.PRNGKey(0)
>>> a_vals = jax.random.uniform(key, (100,), minval=0.01, maxval=0.1)
>>> neuron = bp.izhikevich(100, a=a_vals, b=0.2, c=-65*u.mV, d=8*u.mV)
>>> neuron.init_state()

References

See also

iaf_psc_delta

Leaky integrate-and-fire with delta-shaped PSCs

iaf_psc_exp

Leaky integrate-and-fire with exponential PSCs

mat2_psc_exp

Multi-timescale adaptive threshold with exponential PSCs

aeif_psc_exp

Adaptive exponential integrate-and-fire model

get_spike(V=None)[source]#

Compute spike output using the surrogate gradient function.

This method applies the surrogate gradient function (spk_fun) to the scaled voltage difference \((V - V_{\text{th}}) / (V_{\text{th}} - c)\), producing a differentiable spike indicator for gradient-based learning. The scaling factor normalizes the voltage range to approximately [0, 1] for typical surrogate functions.

Parameters:

V (ArrayLike, optional) – Membrane potential to test for spike emission (with units of voltage, typically mV). Shape: (*varshape,) or (batch_size, *varshape). Default: None (uses self.V.value).

Returns:

Surrogate-differentiable spike indicator. Shape matches input V. Values are in [0, 1] for typical surrogate functions, with gradients defined even at the threshold crossing.

Return type:

ArrayLike

Notes

  • The scaling uses the voltage reset range \((V_{\text{th}} - c)\) to normalize the input to the surrogate function.

  • This method is called automatically by update() but can also be used standalone for custom spike detection logic.

  • The returned spike indicator is differentiable for gradient-based training, unlike a hard threshold (V >= V_th).

init_state(batch_size=None, **kwargs)[source]#

Initialize state variables for the Izhikevich neuron.

This method initializes the membrane potential \(V_{\text{m}}\), recovery variable \(U_{\text{m}}\), and buffered input current \(I\). By default, \(V_{\text{m}}\) is initialized to -65 mV and \(U_{\text{m}}\) is initialized to \(b \cdot V_0\) (matching NEST behavior). The buffered current \(I\) is initialized to zero.

Parameters:
  • batch_size (int or None, optional) – If provided, states are created with shape (batch_size, *varshape). None keeps unbatched state. Default is None.

  • **kwargs – Unused compatibility parameters accepted by the base-state API.

Notes

  • If U_initializer is None (default), \(U_{\text{m}}\) is initialized to \(b \cdot V_0\) where \(V_0\) is the initial value of \(V_{\text{m}}\). This matches NEST’s default initialization: u_ = b * v_.

  • The buffered current I is always initialized to zero with units of pA, implementing NEST’s ring buffer semantic (one-step delay).

update(x=Quantity(0., 'pA'))[source]#

Advance the neuron state by one simulation step.

This method implements the NEST izhikevich::update function, integrating the differential equations for one time step and handling spike emission and reset. The update follows NEST semantics exactly, including the one-step delayed ring buffer for current input.

Update Sequence:

  1. Read current state (\(V_{\text{old}}\), \(U_{\text{old}}\)) and buffered current \(I\) from the previous step.

  2. Integrate \(V_{\text{m}}\) and \(U_{\text{m}}\) using forward Euler (or published half-step scheme if consistent_integration=False).

  3. Add delta (spike) input directly to \(V_{\text{m}}\).

  4. Apply the lower bound V_min if specified.

  5. Detect threshold crossing (\(V \geq V_{\text{th}}\)) and apply reset: \(V \leftarrow c\), \(U \leftarrow U + d\).

  6. Buffer the new external current x for the next step (one-step delay, NEST ring-buffer semantic).

  7. Return surrogate-differentiable spike output.

Integration Details:

  • Standard Euler (consistent_integration=True): Both \(V\) and \(U\) are updated using their values at the start of the step.

  • Published Izhikevich numerics (consistent_integration=False): \(V\) is updated in two half-steps, and \(U\) uses the final \(V\) value.

Current Input Timing:

Following NEST conventions, the current x provided at simulation step k is buffered and takes effect at step k + 1. This one-step delay matches NEST’s ring buffer implementation for synaptic and external currents.

Parameters:

x (Quantity (current), array_like, optional) – External current input in pA (or compatible current unit). Shape: scalar, (*varshape,), or (batch_size, *varshape). Default: 0 pA. This current is buffered and applied at the next time step.

Returns:

Surrogate-differentiable spike output for the current time step. Shape: (*varshape,) or (batch_size, *varshape). Values are in [0, 1] for typical surrogate functions, with defined gradients for backpropagation.

Return type:

ArrayLike

Notes

  • The integration is performed in float64 precision to match NEST numerical accuracy.

  • Units are stripped during integration (NEST uses dimensionless arithmetic internally) and restored after integration.

  • Delta (spike) inputs are summed via sum_delta_inputs() and added directly to the membrane potential as an instantaneous voltage jump.

  • The spike detection uses the voltage before reset (V_new) to compute the surrogate gradient, while the state variables are updated to their post-reset values (V_post, U_post).

  • If V_min is set, it is enforced after integration but before spike detection and reset.