iaf_psc_alpha_multisynapse#
- class brainpy.state.iaf_psc_alpha_multisynapse(in_size, E_L=Quantity(-70., "mV"), C_m=Quantity(250., "pF"), tau_m=Quantity(10., "ms"), t_ref=Quantity(2., "ms"), V_th=Quantity(-55., "mV"), V_reset=Quantity(-70., "mV"), tau_syn=Quantity([2.], "ms"), I_e=Quantity(0., "pA"), V_min=None, V_initializer=Constant(value=-70. mV), spk_fun=ReluGrad(alpha=0.3, width=1.0), spk_reset='hard', ref_var=False, name=None)#
NEST-compatible
iaf_psc_alpha_multisynapseneuron model.Current-based leaky integrate-and-fire neuron with an arbitrary number of receptor-indexed alpha-shaped synaptic current channels.
Description
iaf_psc_alpha_multisynapsemirrors NESTmodels/iaf_psc_alpha_multisynapse.{h,cpp}and generalizesiaf_psc_alphafrom two fixed excitatory/inhibitory channels ton_receptorsindependently parameterized current ports.Each receptor
k(1-based, NEST convention) carries its own alpha time constanttau_syn[k-1]. Synaptic weights are signed currents in pA; positive values are depolarizing and negative values are hyperpolarizing.1. Continuous-Time Dynamics and Receptor States
Membrane dynamics are
\[\frac{dV_m}{dt} = -\frac{V_m - E_L}{\tau_m} + \frac{\sum_k I_k + I_e + I_0}{C_m},\]where \(I_0\) is the one-step delayed continuous current buffer (NEST ring-buffer semantics) and \(I_k\) are the per-receptor alpha currents.
For each receptor \(k\), the alpha current kernel is represented by a two-state linear system (
y1[k],y2[k]):\[\frac{d\,y1_k}{dt} = -\frac{y1_k}{\tau_{\mathrm{syn},k}}, \qquad \frac{d\,y2_k}{dt} = y1_k - \frac{y2_k}{\tau_{\mathrm{syn},k}}.\]The effective synaptic current for receptor \(k\) is \(I_k = y2_k\). An incoming spike with weight \(w_k\) (pA) is injected into
y1[k]with the NEST alpha normalization factor:\[y1_k \leftarrow y1_k + \frac{e}{\tau_{\mathrm{syn},k}} w_k.\]This normalization ensures that a single spike with weight \(w_k\) produces a current kernel that peaks exactly at \(w_k\) when \(t = \tau_{\mathrm{syn},k}\):
\[I_k(t) = w_k \frac{t}{\tau_{\mathrm{syn},k}} \exp\!\left(1 - \frac{t}{\tau_{\mathrm{syn},k}}\right), \quad t \ge 0.\]2. Exact Discrete Propagator, Derivation Constraints, and Stability
With fixed step \(h = dt\), exact matrix propagation of the linear subsystem is used. For each receptor \(k\):
\[y1_{k,n+1} = P_{11,k}\,y1_{k,n} + \frac{e}{\tau_{\mathrm{syn},k}} w_{k,n},\]\[y2_{k,n+1} = P_{21,k}\,y1_{k,n} + P_{22,k}\,y2_{k,n},\]where \(P_{11,k} = P_{22,k} = e^{-h/\tau_{\mathrm{syn},k}}\) and \(P_{21,k} = h\,e^{-h/\tau_{\mathrm{syn},k}}\).
Membrane relative voltage \(y_3 = V_m - E_L\) is updated as
\[y_{3,n+1} = P_{33}\,y_{3,n} + P_{30}(I_{0,n} + I_e) + \sum_k \left(P_{31,k}\,y1_{k,n} + P_{32,k}\,y2_{k,n}\right),\]with \(P_{33} = e^{-h/\tau_m}\) and \(P_{30} = \tau_m(1 - e^{-h/\tau_m})/C_m\). Coefficients \(P_{31,k}\), \(P_{32,k}\) are computed via
iaf_psc_alpha._alpha_propagator_p31_p32(), which applies the stable near-singular limit for \(\tau_m \approx \tau_{\mathrm{syn},k}\):\[P_{32}^{\mathrm{sing}} = \frac{h}{C_m} e^{-h/\tau_m}, \qquad P_{31}^{\mathrm{sing}} = \frac{h^2}{2C_m} e^{-h/\tau_m},\]preventing catastrophic cancellation when \(\tau_m = \tau_{\mathrm{syn},k}\).
3. Update Order per Simulation Step (NEST Semantics)
Per-step execution order:
Integrate membrane with exact propagator for neurons not refractory (\(r = 0\)).
Decrement refractory counters for neurons currently refractory (\(r > 0\)).
Propagate all receptor alpha states
y1,y2forward by one step.Inject receptor-specific spike weights into
y1, including default delta input mapped to receptor 1 whenn_receptors > 0.Apply threshold test, hard reset, refractory assignment, and spike emission.
Store buffered continuous current for the next step.
4. Assumptions, Constraints, and Computational Implications
C_m > 0,tau_m > 0, alltau_syn > 0,t_ref >= 0, andV_reset < V_thare enforced at construction.update(x=...)uses one-step delayed current buffering: current provided at stepncontributes throughi_constat stepn+1, matching NEST ring-buffer event semantics.The update path is fully vectorized over
self.varshapeand scales as \(O(\prod \mathrm{varshape} \times n\_receptors)\) per call.Internal propagator arithmetic is performed in NumPy
float64before writing back to BrainUnit-typed states.When
n_receptors == 0, all spike event inputs are silently ignored.
- Parameters:
in_size (
Size) – Population shape specification. Per-neuron parameters and state variables are broadcast/initialized overself.varshapederived fromin_size.E_L (
ArrayLike, optional) – Resting potential \(E_L\) in mV; scalar or array broadcastable toself.varshape. Default is-70. * u.mV.C_m (
ArrayLike, optional) – Membrane capacitance \(C_m\) in pF; broadcastable toself.varshapeand strictly positive. Default is250. * u.pF.tau_m (
ArrayLike, optional) – Membrane time constant \(\tau_m\) in ms; broadcastable and strictly positive. Default is10. * u.ms.t_ref (
ArrayLike, optional) – Absolute refractory period \(t_\mathrm{ref}\) in ms; broadcastable and nonnegative. Converted to integer grid steps byceil(t_ref / dt). Default is2. * u.ms.V_th (
ArrayLike, optional) – Spike threshold \(V_\mathrm{th}\) in mV; broadcastable toself.varshape. Default is-55. * u.mV.V_reset (
ArrayLike, optional) – Post-spike reset potential \(V_\mathrm{reset}\) in mV; broadcastable and constrained byV_reset < V_thelementwise. Default is-70. * u.mV.tau_syn (
ArrayLike, optional) – Receptor alpha time constants in ms. Values are converted to a 1-Dfloat64array with shape(n_receptors,); every entry must be strictly positive. The number of entries definesn_receptors. Default is(2.0,) * u.ms(one receptor).I_e (
ArrayLike, optional) – Constant injected current \(I_e\) in pA; scalar or array broadcastable toself.varshape. Default is0. * u.pA.V_min (
ArrayLikeorNone, optional) – Optional lower clamp \(V_\mathrm{min}\) in mV applied to the membrane candidate update before thresholding.Nonedisables clamping. Default isNone.V_initializer (
Callable, optional) – Initializer for membrane stateVused byinit_state(). Default isbraintools.init.Constant(-70. * u.mV).spk_fun (
Callable, optional) – Surrogate spike function used byget_spike()and returned byupdate(). Default isbraintools.surrogate.ReluGrad().spk_reset (
str, optional) – Reset policy inherited fromNeuron.'hard'reproduces NEST hard reset behavior. Default is'hard'.ref_var (
bool, optional) – IfTrue, allocates optional boolean stateself.refractoryfor external refractory inspection. Default isFalse.
Parameter Mapping
Table 4 Parameter mapping to model symbols# Parameter
Type / shape / unit
Default
Math symbol
Semantics
in_sizeSize; scalar or tuplerequired
–
Defines population/state shape
self.varshape.E_LArrayLike, broadcastable to
self.varshape(mV)-70. * u.mV\(E_L\)
Leak reversal (resting) potential.
C_mArrayLike, broadcastable (pF),
> 0250. * u.pF\(C_m\)
Membrane capacitance in subthreshold integration.
tau_mArrayLike, broadcastable (ms),
> 010. * u.ms\(\tau_m\)
Membrane leak time constant.
t_refArrayLike, broadcastable (ms),
>= 02. * u.ms\(t_\mathrm{ref}\)
Absolute refractory duration in physical time.
V_thandV_resetArrayLike, broadcastable (mV), with
V_reset < V_th-55. * u.mV,-70. * u.mV\(V_\mathrm{th}\), \(V_\mathrm{reset}\)
Threshold and post-spike reset levels.
tau_synArrayLike, flattened to
(n_receptors,)(ms), each> 0(2.0,) * u.ms\(\tau_{\mathrm{syn},k}\)
Receptor-specific alpha time constants; length defines
n_receptors.I_eArrayLike, broadcastable (pA)
0. * u.pA\(I_e\)
Constant current added each update step.
V_minArrayLike broadcastable (mV) or
NoneNone\(V_\mathrm{min}\)
Optional lower clamp on candidate membrane voltage.
V_initializerCallable
Constant(-70. * u.mV)–
Initializer for membrane state
V.spk_funCallable
ReluGrad()–
Surrogate nonlinearity used for spike output.
spk_resetstr
'hard'–
Reset mode from
Neuron.ref_varbool
False–
If
True, exposes boolean stateself.refractory.namestr | None
None–
Optional node name.
- Raises:
ValueError – Raised at initialization or update time if any of the following holds: -
C_m <= 0,tau_m <= 0, anytau_syn <= 0,t_ref < 0, orV_reset >= V_th. - A spike event receptor index is outside[1, n_receptors].TypeError – If parameters or inputs are not unit-compatible with the expected conversions (mV, ms, pF, pA).
KeyError – If simulation context entries (for example
tordt) are missing whenupdate()is called.AttributeError – If
update()is called beforeinit_state()creates required state holders.
Notes
State variables are
V,y1_syn,y2_syn,i_const,refractory_step_count, andlast_spike_time;refractoryis added only whenref_var=True.Spike weights from
spike_eventsandsum_delta_inputsare signed currents in pA: positive for depolarizing, negative for hyperpolarizing receptors. This differs from conductance-based multisynapse models where weights must be non-negative.update(x=...)storesxintoi_constfor use on the next step, matching NEST current-event buffering semantics.If
n_receptors == 0, all spike event inputs are silently ignored andsum_delta_inputsis discarded.Default delta input from
sum_delta_inputsis routed to receptor 1 whenn_receptors > 0, replicating NEST default port behavior.
Examples
>>> import brainstate >>> import saiunit as u >>> from brainpy_state._nest.iaf_psc_alpha_multisynapse import ( ... iaf_psc_alpha_multisynapse, ... ) >>> with brainstate.environ.context(dt=0.1 * u.ms): ... neu = iaf_psc_alpha_multisynapse( ... in_size=3, ... tau_syn=(1.5, 3.0) * u.ms, ... I_e=180.0 * u.pA, ... ) ... neu.init_state() ... with brainstate.environ.context(t=0.0 * u.ms): ... spk = neu.update( ... spike_events=[{'receptor_type': 2, 'weight': 40.0 * u.pA}] ... ) ... _ = spk.shape
>>> import brainstate >>> import saiunit as u >>> from brainpy_state._nest.iaf_psc_alpha_multisynapse import ( ... iaf_psc_alpha_multisynapse, ... ) >>> with brainstate.environ.context(dt=0.1 * u.ms): ... neu = iaf_psc_alpha_multisynapse(in_size=1, tau_syn=(2.0,) * u.ms) ... neu.init_state() ... with brainstate.environ.context(t=0.0 * u.ms): ... _ = neu.update(x=250.0 * u.pA) ... with brainstate.environ.context(t=0.1 * u.ms): ... spk_next = neu.update() ... _ = spk_next
References
- get_spike(V=None)[source]#
Evaluate surrogate spike output for a voltage tensor.
- Parameters:
V (
ArrayLikeorNone, optional) – Voltage input in mV, broadcast-compatible withself.varshape. IfNone, uses current membrane stateself.V.value.- Returns:
out – Surrogate spike output from
self.spk_funwith the same shape asV(orself.V.valuewhenV is None). The input tospk_funis scaled as(V - V_th) / (V_th - V_reset)so the surrogate activates positively for suprathreshold voltages.- Return type:
- init_state(**kwargs)[source]#
Initialize runtime states for membrane, synaptic, and refractory variables.
- Parameters:
**kwargs – Unused compatibility parameters accepted by the base-state API.
- Raises:
ValueError – If initializers cannot broadcast to
self.varshape.TypeError – If initializer outputs are incompatible with expected unit/array conversions for voltage, current, or integer refractory states.
- update(x=Quantity(0., 'pA'), spike_events=None, w_by_rec=None)[source]#
Advance the neuron by one simulation step.
- Parameters:
x (
ArrayLike, optional) – Continuous current input in pA for this step.xis accumulated throughsum_current_inputs()and stored ini_constfor use on the next call (one-step delayed buffering matching NEST ring-buffer semantics). Default is0. * u.pA.spike_events (
iterableorNone, optional) –Receptor-indexed spike weight events to inject this step. Each entry must be either:
A
(receptor_type, weight)tuple wherereceptor_typeis a 1-based integer in[1, n_receptors]andweightis a scalar or array in pA (broadcastable toself.varshape).A
dictwith keys'receptor_type'(or'receptor') and'weight'.
Multiple events for the same receptor are accumulated additively.
Noneinjects no receptor spike events. Default isNone. Ignored whenw_by_recis provided.w_by_rec (
array-likeorNone, optional) – Pre-computed per-receptor spike weights in pA (dimensionless), shape broadcastable toself.varshape + (n_receptors,). When provided, bypassesspike_eventsparsing andsum_delta_inputs, making the update JIT-compatible for use insidebrainstate.transform.for_loop. Default isNone.
- Returns:
out – Spike output tensor from
get_spike(), shapeself.V.value.shape. On threshold crossings, the voltage presented tospk_funis nudged above threshold by1e-12mV-equivalent to preserve positive surrogate activation.- Return type:
jax.Array- Raises:
ValueError – If any receptor index in
spike_eventsis outside[1, n_receptors].KeyError – If simulation context does not provide
tordt.AttributeError – If required states are missing because
init_state()was not called.TypeError – If
xor stored states are not unit-compatible with expected pA / mV conversions.