iaf_cond_alpha_mc#

class brainpy.state.iaf_cond_alpha_mc(in_size, V_th=Quantity(-55., 'mV'), V_reset=Quantity(-60., 'mV'), t_ref=Quantity(2., 'ms'), g_sp=Quantity(2.5, 'nS'), g_pd=Quantity(1., 'nS'), soma=None, proximal=None, distal=None, gsl_error_tol=0.001, V_initializer=None, spk_fun=ReluGrad(alpha=0.3, width=1.0), spk_reset='hard', ref_var=False, name=None)#

NEST-compatible iaf_cond_alpha_mc neuron model.

Short Description

Three-compartment conductance-based leaky integrate-and-fire neuron with alpha-shaped synapses, following NEST models/iaf_cond_alpha_mc.{h,cpp}.

Description

iaf_cond_alpha_mc is the multicompartment extension of iaf_cond_alpha with compartments

  • soma (s),

  • proximal dendrite (p),

  • distal dendrite (d).

Compartments are coupled by passive conductances g_sp and g_pd. Each compartment has one excitatory and one inhibitory alpha synapse. Spike threshold and reset are applied at the soma only.

This implementation mirrors NEST source behavior, including:

  • adaptive RKF45 integration (state-wide, persistent internal step),

  • one-step delayed current buffering per compartment,

  • receptor-specific spike and current routing,

  • NEST update ordering in update().

1. Membrane and Synaptic Dynamics

For compartment \(c \in \{s,p,d\}\):

\[C_{m,c}\frac{dV_c}{dt} = -g_{L,c}(V_c - E_{L,c}) -g_{\mathrm{ex},c}(V_c - E_{\mathrm{ex},c}) -g_{\mathrm{in},c}(V_c - E_{\mathrm{in},c}) -I_{\mathrm{conn},c} + I_{\mathrm{stim},c} + I_{e,c}.\]

Coupling currents are

\[ \begin{align}\begin{aligned}I_{\mathrm{conn},s} = g_{sp}(V_s - V_p),\\I_{\mathrm{conn},p} = g_{sp}(V_p - V_s) + g_{pd}(V_p - V_d),\\I_{\mathrm{conn},d} = g_{pd}(V_d - V_p).\end{aligned}\end{align} \]

Alpha-synapse states per compartment follow

\[\frac{d\,dg_{\mathrm{ex},c}}{dt} = -\frac{dg_{\mathrm{ex},c}}{\tau_{\mathrm{syn,ex},c}}, \qquad \frac{dg_{\mathrm{ex},c}}{dt} = dg_{\mathrm{ex},c} - \frac{g_{\mathrm{ex},c}}{\tau_{\mathrm{syn,ex},c}},\]
\[\frac{d\,dg_{\mathrm{in},c}}{dt} = -\frac{dg_{\mathrm{in},c}}{\tau_{\mathrm{syn,in},c}}, \qquad \frac{dg_{\mathrm{in},c}}{dt} = dg_{\mathrm{in},c} - \frac{g_{\mathrm{in},c}}{\tau_{\mathrm{syn,in},c}}.\]

Incoming spike weight \(w\) on a receptor port adds to dg as

\[dg \leftarrow dg + \frac{e}{\tau_{\mathrm{syn}}} w.\]

2. Spike and Refractory Semantics

  • Spike is emitted if somatic membrane potential satisfies \(V_s \ge V_{th}\) after integration.

  • On spike: somatic voltage is reset to V_reset and refractory counter is set to ceil(t_ref / dt).

  • During refractory period, the ODE uses V_reset as somatic effective voltage and keeps all membrane derivatives at zero, matching NEST C++ implementation.

3. NEST Receptor Types

Spike receptors (must have non-negative weights):

  • soma_exc = 1

  • soma_inh = 2

  • proximal_exc = 3

  • proximal_inh = 4

  • distal_exc = 5

  • distal_inh = 6

Current receptors:

  • soma_curr = 7

  • proximal_curr = 8

  • distal_curr = 9

4. Update Order (NEST Semantics)

Per simulation step:

  1. Integrate ODEs on \((t, t+dt]\) using RKF45 with adaptive substeps.

  2. Apply incoming spike events to dg_ex / dg_in per receptor type.

  3. Apply refractory countdown / threshold test / reset / spike emission.

  4. Store incoming currents into delayed buffer I_stim for next step.

Parameters:
  • in_size (int or tuple of int) – Population shape (required). Defines the dimensionality of the neuron population. Scalar for 1D populations, tuple for multi-dimensional arrays.

  • V_th (ArrayLike, optional) – Somatic spike threshold potential. Must be greater than V_reset. Default: -55.0 * u.mV.

  • V_reset (ArrayLike, optional) – Somatic reset potential after spike emission. Must be less than V_th. Default: -60.0 * u.mV.

  • t_ref (ArrayLike, optional) – Absolute refractory period duration. Must be non-negative. Default: 2.0 * u.ms.

  • g_sp (ArrayLike, optional) – Soma-proximal coupling conductance. Controls current flow between soma and proximal dendrite. Default: 2.5 * u.nS.

  • g_pd (ArrayLike, optional) – Proximal-distal coupling conductance. Controls current flow between proximal and distal dendrites. Default: 1.0 * u.nS.

  • soma (dict or None, optional) – Per-compartment parameters for soma. Overrides default values. Supported keys: g_L, C_m, E_ex, E_in, E_L, tau_syn_ex, tau_syn_in, I_e. Default: None (uses NEST defaults).

  • proximal (dict or None, optional) – Per-compartment parameters for proximal dendrite. Same keys as soma. Default: None (uses NEST defaults).

  • distal (dict or None, optional) – Per-compartment parameters for distal dendrite. Same keys as soma. Default: None (uses NEST defaults).

  • gsl_error_tol (ArrayLike, optional) – Unitless local RKF45 error tolerance, broadcastable and strictly positive. Default: 1e-3.

  • V_initializer (Callable, dict, ArrayLike, or None, optional) –

    Initial membrane potential specification. Can be:

    • None: use each compartment’s E_L

    • dict with keys 'soma', 'proximal', 'distal': per-compartment initialization

    • Callable or ArrayLike: same value for all compartments

    Default: None.

  • spk_fun (Callable, optional) – Surrogate gradient function for differentiable spike generation. Must accept voltage scaled as (V - V_th) / (V_th - V_reset) and return spike probability. Default: braintools.surrogate.ReluGrad().

  • spk_reset (str, optional) –

    Spike reset mode. Options:

    • 'hard': stop gradient at reset (matches NEST behavior)

    • 'soft': allow gradient through reset

    Default: 'hard'.

  • ref_var (bool, optional) – If True, expose boolean refractory state variable indicating refractory status. Default: False.

  • name (str or None, optional) – Optional name for the neuron population. Default: None.

Parameter Mapping

The following table shows default per-compartment parameters matching NEST:

Parameter

Soma

Proximal

Distal

Description

g_L

10.0 nS

5.0 nS

10.0 nS

Leak conductance

C_m

150.0 pF

75.0 pF

150.0 pF

Membrane capacitance

E_ex

0.0 mV

0.0 mV

0.0 mV

Excitatory reversal potential

E_in

-85.0 mV

-85.0 mV

-85.0 mV

Inhibitory reversal potential

E_L

-70.0 mV

-70.0 mV

-70.0 mV

Leak reversal potential

tau_syn_ex

0.5 ms

0.5 ms

0.5 ms

Excitatory synapse time constant

tau_syn_in

2.0 ms

2.0 ms

2.0 ms

Inhibitory synapse time constant

I_e

0.0 pA

0.0 pA

0.0 pA

Constant external current

State Variables

The model maintains the following state variables:

  • VArrayLike, shape [..., 3]

    Compartment membrane potentials in order (soma, proximal, distal). Units: mV.

  • dg_exArrayLike, shape [..., 3]

    Excitatory alpha synapse auxiliary variable (dimensionless).

  • g_exArrayLike, shape [..., 3]

    Excitatory synaptic conductance. Units: nS.

  • dg_inArrayLike, shape [..., 3]

    Inhibitory alpha synapse auxiliary variable (dimensionless).

  • g_inArrayLike, shape [..., 3]

    Inhibitory synaptic conductance. Units: nS.

  • I_stimArrayLike, shape [..., 3]

    One-step delayed current buffer per compartment. Units: pA.

  • refractory_step_countArrayLike, dtype int32

    Somatic refractory countdown (steps remaining).

  • integration_stepArrayLike

    Persistent RKF45 internal step size. Units: ms.

  • last_spike_timeArrayLike

    Last emitted spike time. Units: ms.

  • refractoryArrayLike, dtype bool (optional)

    Boolean refractory indicator (only if ref_var=True).

Notes

Implementation Details:

  • Adaptive Integration: Uses Runge-Kutta-Fehlberg 45 (RKF45) with adaptive step size control to integrate ODEs. The internal step size is persistent across time steps and adjusts based on local error estimates (tolerance 1e-3).

  • Refractory Clamping: During refractory period, somatic voltage is clamped to V_reset and all membrane derivatives are set to zero. This matches NEST’s C++ implementation exactly.

  • Spike Weight Routing: Incoming spike weights are routed to specific compartment-receptor combinations (6 spike receptor types). Weights must be non-negative as per NEST semantics.

  • Current Delay Buffer: External currents applied via x parameter are stored in I_stim and used in the next time step, implementing NEST’s one-step delay semantics.

  • Surrogate Gradients: The spk_fun enables gradient-based learning by providing differentiable spike approximations. The voltage is scaled to [0, 1] range before applying the surrogate function.

Deprecation Notice:

NEST marks iaf_cond_alpha_mc as deprecated in favor of the more general cm_default multi-compartment model. This implementation maintains backward compatibility with legacy NEST code and benchmarks.

Failure Modes

  • Raises ValueError if V_reset >= V_th (reset must be below threshold).

  • Raises ValueError if t_ref < 0 (negative refractory period).

  • Raises ValueError if any capacitance C_m <= 0 (must be strictly positive).

  • Raises ValueError if any time constant tau_syn_ex or tau_syn_in <= 0.

  • Raises ValueError if spike weights are negative (non-negative constraint).

  • Raises TypeError if compartment parameter overrides are not dictionaries.

  • Raises ValueError if unknown keys are provided in compartment parameter dictionaries.

References

Examples

Basic three-compartment neuron with default parameters:

>>> import brainpy.state as bst
>>> import saiunit as u
>>> neuron = bst.iaf_cond_alpha_mc(in_size=10)
>>> neuron.init_state()
>>> spike = neuron.update(x=100. * u.pA)

Custom per-compartment parameters:

>>> soma_params = {'C_m': 200.0 * u.pF, 'g_L': 15.0 * u.nS}
>>> proximal_params = {'C_m': 100.0 * u.pF}
>>> neuron = bst.iaf_cond_alpha_mc(
...     in_size=5,
...     soma=soma_params,
...     proximal=proximal_params,
...     g_sp=3.0 * u.nS
... )

Compartment-specific current injection using dictionary:

>>> currents = {
...     'soma': 50.0 * u.pA,
...     'proximal': 30.0 * u.pA,
...     'distal': 20.0 * u.pA
... }
>>> spike = neuron.update(x=currents)

Receptor-specific spike input:

>>> spike_events = [
...     ('soma_exc', 5.0 * u.nS),      # receptor type 1
...     ('proximal_inh', 3.0 * u.nS),  # receptor type 4
...     ('distal_exc', 2.0 * u.nS)     # receptor type 5
... ]
>>> spike = neuron.update(spike_events=spike_events)

Accessing compartment-specific membrane potentials:

>>> V_soma = neuron.V.value[..., neuron.SOMA]
>>> V_proximal = neuron.V.value[..., neuron.PROX]
>>> V_distal = neuron.V.value[..., neuron.DIST]
get_spike(V=None)[source]#

Compute differentiable spike output using surrogate gradient.

Applies the surrogate gradient function to voltage scaled to the range [0, 1] relative to threshold and reset potentials. This enables gradient-based learning while approximating discrete spike behavior.

Parameters:

V (ArrayLike or None, optional) – Somatic membrane potential. If None, uses current self.V.value[..., SOMA]. Must have units of voltage or be dimensionless (assumed mV). Default: None.

Returns:

spike – Differentiable spike output in range [0, 1]. Shape matches V input. Values near 1 indicate high spike probability; near 0 indicates low probability.

Return type:

ArrayLike

Notes

The voltage scaling formula is:

\[\begin{split}V_{\\text{scaled}} = \\frac{V - V_{th}}{V_{th} - V_{reset}}\end{split}\]

This maps V = V_th to 0 and V = V_reset to -1, allowing the surrogate function to produce smooth gradients around the threshold.

init_state(**kwargs)[source]#

Initialize all state variables.

Sets initial values for membrane potentials (using V_initializer), synaptic conductances (zero), refractory counters (zero), integration step size (to dt), and current buffer (zero).

Parameters:

**kwargs – Additional keyword arguments (ignored, for API compatibility).

Notes

  • Membrane potentials default to each compartment’s E_L unless V_initializer is provided.

  • Refractory counter is initialized to 0 (not refractory).

  • RKF45 integration step size is initialized to environment dt.

  • Last spike time is initialized to -1e7 ms (effectively never spiked).

property receptor_types#

Mapping of receptor labels to numeric receptor type IDs.

Returns:

Dictionary mapping receptor labels (str) to receptor type integers. Includes both spike receptors (1-6) and current receptors (7-9).

Return type:

dict

Examples

>>> neuron = bst.iaf_cond_alpha_mc(in_size=10)
>>> neuron.receptor_types
{'soma_exc': 1, 'soma_inh': 2, 'proximal_exc': 3, ...}
property recordables#

List of recordable state variable names.

Returns:

Names of state variables that can be recorded during simulation. Includes compartment-specific voltages, conductances, and refractory status.

Return type:

list of str

Notes

Recordable names:

  • 'V_m.s', 'V_m.p', 'V_m.d': compartment membrane potentials

  • 'g_ex.s', 'g_ex.p', 'g_ex.d': excitatory conductances

  • 'g_in.s', 'g_in.p', 'g_in.d': inhibitory conductances

  • 't_ref_remaining': remaining refractory time

Examples

>>> neuron = bst.iaf_cond_alpha_mc(in_size=10)
>>> neuron.recordables
['V_m.s', 'g_ex.s', 'g_in.s', 'V_m.p', ...]
update(x=Quantity(0., 'pA'), spike_events=None, current_events=None)[source]#

Advance the neuron state by one time step.

Integrates membrane and synaptic ODEs using adaptive RKF45, applies spike and current inputs, checks threshold, emits spikes, and updates refractory status. Follows NEST update semantics: integrate -> apply spikes -> check threshold -> buffer currents for next step.

Parameters:
  • x (ArrayLike or dict, optional) –

    External current input. Can be:

    • Scalar or array matching in_size: applied to soma only

    • Array with shape [..., 3]: applied to all compartments

    • Dict with keys 'soma', 'proximal', 'distal', or receptor labels ('soma_curr', 'proximal_curr', 'distal_curr'): per-compartment currents

    Units: pA. Default: 0.0 * u.pA.

  • spike_events (list of tuples or dicts, optional) –

    Incoming spike events. Each element can be:

    • Tuple (receptor_type, weight)

    • Dict with keys 'receptor_type' (or 'receptor') and 'weight'

    Receptor types: 'soma_exc' (1), 'soma_inh' (2), 'proximal_exc' (3), 'proximal_inh' (4), 'distal_exc' (5), 'distal_inh' (6). Weights must be non-negative with units of conductance (nS). Default: None (no spike inputs).

  • current_events (list of tuples or dicts, optional) –

    Incoming current events. Each element can be:

    • Tuple (receptor_type, current)

    • Dict with keys 'receptor_type' (or 'receptor') and 'current' (or 'weight')

    Receptor types: 'soma_curr' (7), 'proximal_curr' (8), 'distal_curr' (9), or compartment indices 0-2, or names 'soma', 'proximal', 'distal'. Currents have units of pA. Default: None (no current events).

Returns:

spike – Differentiable spike output for this time step. Shape matches in_size. Values in range [0, 1] represent spike probability via surrogate gradient.

Return type:

ArrayLike

Notes

Update Order:

  1. Integrate ODEs from t to t + dt using RKF45 with adaptive substeps

  2. Apply incoming spike weights to alpha synapse auxiliary variables (dg_ex, dg_in)

  3. Check somatic voltage against threshold; emit spike if V_soma >= V_th

  4. Reset somatic voltage and set refractory counter on spike

  5. Store incoming currents in I_stim buffer for use in next time step

Refractory Behavior:

During refractory period (refractory_step_count > 0):

  • Somatic voltage is clamped to V_reset

  • All membrane derivatives are set to zero

  • Synaptic conductances continue to evolve normally

  • Refractory counter decrements by 1 each step

Adaptive Integration:

RKF45 adjusts internal step size based on local error estimates. The integration step size is persistent across time steps and stored in integration_step state.

Failure Modes

  • Raises ValueError if spike weights are negative (NEST constraint).

  • May fail to converge if integration step size becomes too small.