rate_neuron_ipn#

class brainpy.state.rate_neuron_ipn(in_size, tau=Quantity(10., 'ms'), lambda_=1.0, sigma=1.0, mu=0.0, g=1.0, mult_coupling=False, g_ex=1.0, g_in=1.0, theta_ex=0.0, theta_in=0.0, linear_summation=True, rectify_rate=0.0, rectify_output=False, input_nonlinearity=None, mult_coupling_ex_fn=None, mult_coupling_in_fn=None, rate_initializer=Constant(value=0.0), noise_initializer=Constant(value=0.0), name=None)#

NEST-compatible input-noise rate-neuron template with stochastic dynamics.

Implements the NEST rate_neuron_ipn<TNonlinearities> template model, a continuous-time rate neuron with additive Gaussian input noise. With default settings, this is equivalent to NEST’s lin_rate_ipn. The model supports custom input nonlinearities, multiplicative coupling (rate-dependent synaptic efficacy), and flexible input summation modes.

Mathematical Description

1. Continuous-Time Stochastic Dynamics

The rate state \(X(t)\) evolves according to the Langevin equation:

\[\tau\,dX(t) = [-\lambda X(t) + \mu + I_\mathrm{net}(t)]\,dt + \sqrt{\tau}\,\sigma\,dW(t),\]

where:

  • \(\tau > 0\) is the time constant (ms).

  • \(\lambda \ge 0\) is the passive decay rate (dimensionless). Controls exponential relaxation; \(\lambda=0\) yields driftless diffusion.

  • \(\mu\) is the mean drive (dimensionless, external constant input).

  • \(\sigma \ge 0\) is the input-noise strength (dimensionless).

  • \(W(t)\) is a standard Wiener process.

  • \(I_\mathrm{net}(t)\) is the network input (see below).

The stationary distribution variance (without external input) is \(\sigma^2/(2\lambda)\) for \(\lambda > 0\); for \(\lambda=0\), the model is non-stationary.

2. Network Input Structure

The network input \(I_\mathrm{net}(t)\) decomposes into excitatory and inhibitory branches:

\[I_\mathrm{net}(t) = H_\mathrm{ex}(X) \cdot g(I_\mathrm{ex}(t)) + H_\mathrm{in}(X) \cdot g(I_\mathrm{in}(t)),\]

where:

  • \(I_\mathrm{ex}(t)\), \(I_\mathrm{in}(t)\) are synaptic input branches (sign-separated by event weight).

  • \(g(\cdot)\) is the input nonlinearity. Default: \(g(h)=g\,h\) (linear gain).

  • \(H_\mathrm{ex}(X)\), \(H_\mathrm{in}(X)\) are optional multiplicative coupling factors (rate-dependent synaptic efficacy). Default: \(H_\mathrm{ex}(X)=g_\mathrm{ex}(\theta_\mathrm{ex}-X)\), \(H_\mathrm{in}(X)=g_\mathrm{in}(\theta_\mathrm{in}+X)\). Only active if mult_coupling=True.

The linear_summation switch controls nonlinearity application:

  • linear_summation=True: \(I_\mathrm{net}(t) = H\cdot g(I_\mathrm{ex}+I_\mathrm{in})\).

  • linear_summation=False: \(I_\mathrm{net}(t) = H_\mathrm{ex}\cdot g(I_\mathrm{ex}) + H_\mathrm{in}\cdot g(I_\mathrm{in})\).

3. Discrete-Time Integration (Stochastic Exponential Euler)

For time step \(h=dt\) (in ms), the model uses an exact Ornstein-Uhlenbeck integration scheme for the linear part, with Euler-Maruyama for the forcing:

\[X_{n+1} = P_1 X_n + P_2 (\mu + I_\mathrm{net,n}) + N\,\xi_n,\]

where \(\xi_n\sim\mathcal{N}(0,1)\) is standard Gaussian noise.

For \(\lambda > 0\):

\[P_1 = \exp\left(-\frac{\lambda h}{\tau}\right), \quad P_2 = \frac{1-P_1}{\lambda}, \quad N = \sigma\sqrt{\frac{1-P_1^2}{2\lambda}}.\]

For \(\lambda = 0\) (Euler-Maruyama):

\[P_1=1, \quad P_2=\frac{h}{\tau}, \quad N=\sigma\sqrt{\frac{h}{\tau}}.\]

The noise factor \(N\) is derived from exact OU process integration over \([0, h]\), ensuring correct fluctuation amplitude as \(h\to 0\).

4. Update Ordering (Matching NEST ``rate_neuron_ipn_impl.h``)

Per simulation step:

  1. Store outgoing delayed value: current rate is recorded as delayed_rate.

  2. Draw noise: sample \(\xi_n\sim\mathcal{N}(0,1)\), compute \(\mathrm{noise}_n=\sigma\,\xi_n\).

  3. Propagate intrinsic dynamics: apply stochastic exponential Euler to \(X_n\) with external drive and noise.

  4. Read event buffers: drain delayed events arriving at current step; accumulate instantaneous events.

  5. Apply network input: according to linear_summation and mult_coupling settings.

    • linear_summation=True: nonlinearity applied to summed branch input during update.

    • linear_summation=False: nonlinearity applied per event during buffering (matching NEST event handlers).

  6. Rectification (optional): if rectify_output=True, clamp \(X_{n+1}\gets\max(X_{n+1},\,\mathrm{rectify\_rate})\).

  7. Update state variables: rate, noise, delayed_rate, instant_rate, _step_count.

5. Numerical Stability and Computational Complexity

  • Construction enforces \(\tau>0\), \(\lambda\ge 0\), \(\sigma\ge 0\), \(\mathrm{rectify\_rate}\ge 0\).

  • The exponential Euler scheme is numerically stable for all \(h>0\).

  • Stochastic dynamics may violate deterministic stability bounds; use rectify_output=True to enforce rate constraints.

  • Per-call cost is \(O(\prod\mathrm{varshape})\) with vectorized NumPy operations in float64 for coefficient evaluation and state updates.

Parameters:
  • in_size (Size) – Population shape (tuple or int). All per-neuron parameters are broadcast to self.varshape.

  • tau (ArrayLike, optional) – Time constant \(\tau\) (ms). Scalar or array broadcastable to self.varshape. Must be \(>0\). Default: 10.0 * u.ms.

  • lambda (ArrayLike, optional) – Passive decay rate \(\lambda\) (dimensionless). Scalar or array broadcastable to self.varshape. Must be \(\ge 0\). Controls exponential relaxation (\(\lambda=0\) yields driftless diffusion). Default: 1.0.

  • sigma (ArrayLike, optional) – Input-noise scale \(\sigma\) (dimensionless). Scalar or array broadcastable to self.varshape. Must be \(\ge 0\). Default: 1.0.

  • mu (ArrayLike, optional) – Mean drive \(\mu\) (dimensionless). Scalar or array broadcastable to self.varshape. External constant input to the rate dynamics. Default: 0.0.

  • g (ArrayLike, optional) – Linear gain parameter \(g\) (dimensionless) used by the default input nonlinearity \(g(h)=g\,h\). Scalar or array broadcastable to self.varshape. Default: 1.0.

  • mult_coupling (bool, optional) – Enable multiplicative coupling (rate-dependent synaptic efficacy). If True, applies \(H_\mathrm{ex}(X)\) and \(H_\mathrm{in}(X)\) to synaptic inputs. Default: False.

  • g_ex (ArrayLike, optional) – Excitatory multiplicative coupling gain \(g_\mathrm{ex}\) (dimensionless). Scalar or array broadcastable to self.varshape. Only used if mult_coupling=True. Default: 1.0.

  • g_in (ArrayLike, optional) – Inhibitory multiplicative coupling gain \(g_\mathrm{in}\) (dimensionless). Scalar or array broadcastable to self.varshape. Only used if mult_coupling=True. Default: 1.0.

  • theta_ex (ArrayLike, optional) – Excitatory coupling reference rate \(\theta_\mathrm{ex}\) (dimensionless). Scalar or array broadcastable to self.varshape. Only used if mult_coupling=True. Default: 0.0.

  • theta_in (ArrayLike, optional) – Inhibitory coupling reference rate \(\theta_\mathrm{in}\) (dimensionless). Scalar or array broadcastable to self.varshape. Only used if mult_coupling=True. Default: 0.0.

  • linear_summation (bool, optional) – Controls where the input nonlinearity is applied. If True, the nonlinearity is applied to the sum of excitatory and inhibitory inputs. If False, the nonlinearity is applied separately to each input branch (matching NEST event semantics). Default: True.

  • rectify_rate (ArrayLike, optional) – Lower bound \(X_\mathrm{min}\) for the rate when rectify_output=True (dimensionless). Scalar or array broadcastable to self.varshape. Must be \(\ge 0\). Default: 0.0.

  • rectify_output (bool, optional) – If True, clamp the rate output to \(X\ge\mathrm{rectify\_rate}\) after each update step. Default: False.

  • input_nonlinearity (Callable or None, optional) – Custom input nonlinearity \(g(\cdot)\) replacing the default \(g(h)=g\,h\). Callable signature: f(h) (receives NumPy array) or f(model, h) (receives model instance and array). Must return array of same shape as input. If None, uses default linear gain. Default: None.

  • mult_coupling_ex_fn (Callable or None, optional) – Custom excitatory multiplicative coupling function \(H_\mathrm{ex}(X)\). Callable signature: f(rate) or f(model, rate). Must return array of same shape as input. If None, uses default \(g_\mathrm{ex}(\theta_\mathrm{ex}-X)\). Default: None.

  • mult_coupling_in_fn (Callable or None, optional) – Custom inhibitory multiplicative coupling function \(H_\mathrm{in}(X)\). Callable signature: f(rate) or f(model, rate). Must return array of same shape as input. If None, uses default \(g_\mathrm{in}(\theta_\mathrm{in}+X)\). Default: None.

  • rate_initializer (Callable, optional) – Initializer for the rate state variable \(X_0\). Callable compatible with braintools.init API. Default: braintools.init.Constant(0.0).

  • noise_initializer (Callable, optional) – Initializer for the noise state variable (records last noise sample \(\sigma\,\xi_{n-1}\)). Callable compatible with braintools.init API. Default: braintools.init.Constant(0.0).

  • name (str or None, optional) – Module name for identification in hierarchies. If None, an auto-generated name is used. Default: None.

Parameter Mapping

The following table maps NEST rate_neuron_ipn / lin_rate_ipn parameters to brainpy.state equivalents:

NEST Parameter

brainpy.state

Default

tau

tau

10 ms

lambda

lambda_

1.0

sigma

sigma

1.0

mu

mu

0.0

g (nonlinearity gain)

g

1.0

mult_coupling

mult_coupling

False

g_ex, g_in

g_ex, g_in

1.0

theta_ex, theta_in

theta_ex, theta_in

0.0

linear_summation

linear_summation

True

rectify_rate

rectify_rate

0.0

rectify_output

rectify_output

False

rate#

Current rate state \(X_n\) (float64 array of shape self.varshape or (batch_size,) + self.varshape).

Type:

brainstate.ShortTermState

noise#

Last noise sample \(\sigma\,\xi_{n-1}\) (float64 array, same shape as rate).

Type:

brainstate.ShortTermState

instant_rate#

Rate value after instantaneous event application (float64 array, same shape as rate).

Type:

brainstate.ShortTermState

delayed_rate#

Rate value before current update, used for delayed projections (float64 array, same shape as rate).

Type:

brainstate.ShortTermState

_step_count#

Internal step counter for delayed event scheduling (int64 scalar).

Type:

brainstate.ShortTermState

_delayed_ex_queue#

Internal queue mapping step_idx to accumulated excitatory delayed events.

Type:

dict

_delayed_in_queue#

Internal queue mapping step_idx to accumulated inhibitory delayed events.

Type:

dict

Raises:
  • ValueError – If tau <= 0, lambda_ < 0, sigma < 0, or rectify_rate < 0.

  • ValueError – If instant_rate_events contain non-zero delay_steps.

  • ValueError – If delayed_rate_events contain negative delay_steps.

  • ValueError – If event tuples have length other than 2, 3, or 4.

Notes

Runtime Event Semantics

  • instant_rate_events: Applied in the current step without delay. Each event can be:

    • A scalar (treated as rate value with weight=1.0).

    • A tuple (rate, weight) or (rate, weight, delay_steps) or (rate, weight, delay_steps, multiplicity).

    • A dict with keys 'rate'/'coeff'/'value', 'weight', 'delay_steps'/'delay', 'multiplicity'.

  • delayed_rate_events: Scheduled with integer delay_steps (units of simulation time step). Same format as instant_rate_events.

  • Sign convention: events with weight >= 0 contribute to the excitatory branch; events with weight < 0 contribute to the inhibitory branch.

  • For linear_summation=False, event values are transformed by the input nonlinearity during buffering (matching NEST event handlers).

Comparison to Output-Noise Variant

The rate_neuron_opn model uses output noise (applied after nonlinearity), while rate_neuron_ipn uses input noise (applied before dynamics propagation). This leads to different stationary distributions and noise scaling behavior. Input noise typically results in stronger fluctuations at high rates.

Failure Modes

  • No automatic failure handling. Negative time constants, decay rates, or noise parameters are caught at construction by _validate_parameters.

  • Invalid event formats raise ValueError during update.

  • Numerical instability is unlikely due to exact OU integration, but extreme parameter combinations (very large \(\sigma\), very small \(\tau\)) may lead to rate explosions without rectify_output=True.

Examples

Example 1: Minimal stochastic rate neuron with external drive.

>>> import brainpy.state as bst
>>> import saiunit as u
>>> model = bst.rate_neuron_ipn(in_size=10, tau=20*u.ms, sigma=0.5)
>>> model.init_all_states(batch_size=1)
>>> rate = model(x=0.1)  # external drive
>>> print(rate.shape)
(1, 10)

Example 2: Multiplicative coupling with custom nonlinearity.

>>> import numpy as np
>>> def tanh_nonlin(h):
...     return np.tanh(h)
>>> model = bst.rate_neuron_ipn(
...     in_size=5,
...     tau=10*u.ms,
...     lambda_=2.0,
...     mult_coupling=True,
...     g_ex=1.5, theta_ex=1.0,
...     input_nonlinearity=tanh_nonlin
... )
>>> model.init_all_states()

Example 3: Update with instantaneous and delayed events.

>>> model = bst.rate_neuron_ipn(in_size=3, tau=10*u.ms, sigma=0.1)
>>> model.init_all_states()
>>> instant_event = {'rate': 1.0, 'weight': 0.1}
>>> delayed_event = {'rate': 0.5, 'weight': -0.05, 'delay_steps': 3}
>>> rate = model.update(
...     x=0.2,
...     instant_rate_events=instant_event,
...     delayed_rate_events=delayed_event
... )

References

See also

rate_neuron_opn

Output-noise variant of the rate neuron template.

lin_rate

Deterministic linear rate neuron (sigma=0).

init_state(**kwargs)[source]#

Initialize all state variables for simulation.

Parameters:

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

Notes

This method initializes:

  • rate: Current rate state \(X_n\).

  • noise: Last noise sample \(\sigma\,\xi_{n-1}\).

  • instant_rate: Rate after instantaneous event application.

  • delayed_rate: Rate before current update (for delayed projections).

  • _step_count: Internal step counter for delay scheduling.

  • _delayed_ex_queue, _delayed_in_queue: Delay queues.

All state arrays are initialized as float64 NumPy arrays using the provided initializers.

property receptor_types#

Receptor type dictionary for projection compatibility.

Returns:

{'RATE': 0}. Rate neurons have a single unified receptor port for all rate-based inputs. Excitatory vs. inhibitory separation is handled internally via event weight signs.

Return type:

dict[str, int]

Notes

This property is used by projection objects to validate connection targets. Unlike spiking neurons with separate AMPA/GABA receptor ports, rate neurons use sign-based branch routing (weight >= 0 → excitatory branch, weight < 0 → inhibitory branch).

property recordables#

List of state variable names that can be recorded during simulation.

Returns:

['rate', 'noise']. The rate variable records the current rate state \(X_n\), and noise records the last noise sample \(\sigma\,\xi_{n-1}\).

Return type:

list of str

Notes

These variables can be accessed via recording tools in BrainPy for post-simulation analysis of rate dynamics and noise contributions.

update(x=0.0, instant_rate_events=None, delayed_rate_events=None, noise=None)[source]#

Perform one simulation step of stochastic rate dynamics.

Parameters:
  • x (ArrayLike, optional) – External drive (scalar or array broadcastable to self.varshape). Added to mu as constant forcing. Default is 0.0.

  • instant_rate_events (None, dict, tuple, list, or iterable, optional) – Instantaneous rate events applied in the current step without delay. See class docstring for event format. Default is None.

  • delayed_rate_events (None, dict, tuple, list, or iterable, optional) – Delayed rate events scheduled with integer delay_steps (units of simulation time step). See class docstring for event format. Default is None.

  • noise (ArrayLike, optional) – Externally supplied noise sample \(\xi_n\) (scalar or array broadcastable to state shape). If None (default), draws \(\xi_n\sim\mathcal{N}(0,1)\) internally.

Returns:

rate_new – Updated rate state \(X_{n+1}\) (float64 array of shape self.rate.value.shape).

Return type:

np.ndarray

Notes

Update algorithm:

  1. Collect input contributions:

    • Delayed events arriving at current step (from internal queues).

    • Newly scheduled delayed events with delay_steps=0.

    • Instantaneous events.

    • Delta inputs (sign-separated into excitatory/inhibitory).

    • Current inputs via sum_current_inputs(x, rate).

  2. Compute propagator coefficients:

    For \(\lambda>0\):

    \[P_1 = \exp(-\lambda h/\tau), \quad P_2 = (1-P_1)/\lambda, \quad N = \sigma\sqrt{(1-P_1^2)/(2\lambda)}.\]

    For \(\lambda=0\): \(P_1=1\), \(P_2=h/\tau\), \(N=\sigma\sqrt{h/\tau}\).

  3. Propagate intrinsic dynamics:

    \[X' = P_1 X_n + P_2(\mu + \mu_\mathrm{ext}) + N\,\xi_n.\]
  4. Apply network input with optional multiplicative coupling and input nonlinearity according to linear_summation mode.

  5. Apply optional output rectification: \(X_{n+1}\gets\max(X',\,\mathrm{rectify\_rate})\).

  6. Update state variables: rate, noise, delayed_rate, instant_rate, _step_count.

Numerical stability: The implementation uses np.expm1 for numerically stable evaluation of \(1-e^{-x}\) and handles the \(\lambda=0\) limit explicitly. The noise factor \(N\) is derived from exact Ornstein-Uhlenbeck integration.

Failure modes: No automatic failure handling. Negative time constants, decay rates, or noise parameters are caught at construction by _validate_parameters. Invalid event formats raise ValueError.