stdp_dopamine_synapse#
- class brainpy.state.stdp_dopamine_synapse(weight=1.0, delay=Quantity(1., 'ms'), receptor_type=0, volume_transmitter=None, A_plus=1.0, A_minus=1.5, tau_plus=Quantity(20., 'ms'), tau_minus=Quantity(20., 'ms'), tau_c=Quantity(1000., 'ms'), tau_n=Quantity(200., 'ms'), b=0.0, Wmin=0.0, Wmax=200.0, Kplus=0.0, c=0.0, n=0.0, post=None, name=None)#
NEST-compatible
stdp_dopamine_synapseconnection model.Synapse type for dopamine-modulated spike-timing dependent plasticity following the NEST
models/stdp_dopamine_synapseimplementation. This model combines classical STDP with reward modulation through an eligibility trace mechanism, enabling reinforcement learning in spiking neural networks.1. Model Overview
stdp_dopamine_synapseimplements dopamine-modulated STDP with per-connection state variables:weight– synaptic efficacy (modulated by dopamine)Kplus– presynaptic facilitation tracec– eligibility trace (records recent spike timing correlations)n– dopamine trace (reward signal)t_last_update– timestamp of last propagated state updatet_lastspike– timestamp of previous presynaptic spike
In NEST, the postsynaptic depression trace
Kminusis read from the postsynaptic archiving neuron. For standalone compatibility, this implementation maintains an internal post-spike history buffer parameterized bytau_minus(not a synapse parameter in NEST but a neuron property).Dopaminergic spikes are provided by a NEST
volume_transmitterdevice. In this implementation, dopamine spikes can be fed throughupdate(..., dopa_spike=...)orrecord_dopa_spike(), while still requiring a non-Nonevolume_transmitterhandle to preserve NEST connection semantics.2. Mathematical Formulation
Between spike events, the model integrates three coupled differential equations:
\[\begin{split}\frac{dw}{dt} &= c(t) \cdot (n(t) - b) \\ \frac{dc}{dt} &= -\frac{c}{\tau_c} \\ \frac{dn}{dt} &= -\frac{n}{\tau_n}\end{split}\]where:
\(w\) – synaptic weight
\(c\) – eligibility trace
\(n\) – dopamine concentration
\(b\) – dopamine baseline
\(\tau_c\) – eligibility trace decay time constant
\(\tau_n\) – dopamine trace decay time constant
Weight updates are computed analytically using
expm1over each time interval:\[w \leftarrow w - c_0 \left( \frac{n_0}{\tau_s} \cdot \mathrm{expm1}(\tau_s \Delta t) - b \tau_c \cdot \mathrm{expm1}\left(\frac{\Delta t}{\tau_c}\right) \right)\]where \(\tau_s = \frac{\tau_c + \tau_n}{\tau_c \tau_n}\) and \(\Delta t = t_0 - t_1 \le 0\). The weight is then clipped to \([W_{\min}, W_{\max}]\).
3. Eligibility Trace Updates
At spike events, the eligibility trace is modified by:
Facilitation (pre-before-post): \(c \leftarrow c + A_+ K_+(t)\)
Depression (post-before-pre): \(c \leftarrow c - A_- K_-(t)\)
where \(K_+\) and \(K_-\) are exponentially decaying spike traces:
\[\begin{split}K_+(t) &= \sum_{t_i^{\mathrm{pre}} < t} \exp\left(-\frac{t - t_i^{\mathrm{pre}}}{\tau_+}\right) \\ K_-(t) &= \sum_{t_j^{\mathrm{post}} < t} \exp\left(-\frac{t - t_j^{\mathrm{post}}}{\tau_-}\right)\end{split}\]4. Update Order for Presynaptic Spikes
For a presynaptic spike at time \(t_{\mathrm{pre}}\) with dendritic delay \(d\), NEST
stdp_dopamine_synapse::sendperforms:Read postsynaptic history in \((t_{\mathrm{last\_update}} - d,\; t_{\mathrm{pre}} - d]\)
For each postsynaptic spike \(t_{\mathrm{post}}\) in that range:
Propagate dopamine/eligibility/weight to \(t_{\mathrm{post}} + d\)
If \(t_{\mathrm{pre}} - t_{\mathrm{post}} > \epsilon\), facilitate: \(c \leftarrow c + A_+ K_+ \exp((t_{\mathrm{last\_update}} - (t_{\mathrm{post}} + d)) / \tau_+)\)
Propagate dopamine/eligibility/weight to \(t_{\mathrm{pre}}\)
Depress eligibility: \(c \leftarrow c - A_- K_-(t_{\mathrm{pre}} - d)\)
Send event with updated
weightUpdate presynaptic trace: \(K_+ \leftarrow K_+ \exp((t_{\mathrm{last\_update}} - t_{\mathrm{pre}}) / \tau_+) + 1\)
Set \(t_{\mathrm{last\_update}} = t_{\mathrm{lastspike}} = t_{\mathrm{pre}}\)
This implementation preserves the exact NEST update ordering.
5. Event Timing Semantics
As in NEST, this model uses on-grid spike timestamps and ignores precise sub-step offsets for plasticity updates. All spike times are rounded to simulation time steps.
- Parameters:
weight (
floatorarray-like, optional) – Initial synaptic weight (unitless). Default:1.0.delay (
Quantityorarray-like, optional) – Synaptic delay. Must have time units. Default:1.0 * u.ms.receptor_type (
int, optional) – Receiver port/receptor identifier on the postsynaptic neuron. Default:0.volume_transmitter (
objectorNone, optional) – Handle to a dopamine volume transmitter (NEST compatibility placeholder). Must be set to a non-Nonevalue before simulation starts. Default:None.A_plus (
floatorarray-like, optional) – Facilitation amplitude for pre-before-post spike pairs (unitless). Default:1.0.A_minus (
floatorarray-like, optional) – Depression amplitude for post-before-pre spike pairs (unitless). Default:1.5.tau_plus (
Quantityorarray-like, optional) – Presynaptic trace decay time constant. Must have time units. Default:20.0 * u.ms.tau_minus (
Quantityorarray-like, optional) – Postsynaptic trace decay time constant. Must have time units. In NEST, this is a neuron property; here it is stored on the synapse for standalone operation. Default:20.0 * u.ms.tau_c (
Quantityorarray-like, optional) – Eligibility trace decay time constant. Must have time units. Default:1000.0 * u.ms.tau_n (
Quantityorarray-like, optional) – Dopamine trace decay time constant. Must have time units. Default:200.0 * u.ms.b (
floatorarray-like, optional) – Dopamine baseline concentration (unitless). Weight changes occur proportionally to \((n - b)\). Default:0.0.Wmin (
floatorarray-like, optional) – Minimum allowed weight (hard lower bound). Default:0.0.Wmax (
floatorarray-like, optional) – Maximum allowed weight (hard upper bound). Default:200.0.Kplus (
floatorarray-like, optional) – Initial presynaptic trace value. Must be non-negative. Default:0.0.c (
floatorarray-like, optional) – Initial eligibility trace value. Default:0.0.n (
floatorarray-like, optional) – Initial dopamine trace value. Default:0.0.post (
DynamicsorNone, optional) – Default postsynaptic receiver object. Can be overridden insend(). Default:None.name (
strorNone, optional) – Object name for identification. Default:None.
Parameter Mapping
NEST-to-BrainPy parameter correspondence:
NEST Parameter
BrainPy Parameter
Units
Description
weightweightunitless
Synaptic efficacy
delaydelayms
Synaptic delay
receptor_typereceptor_typeinteger
Postsynaptic receptor port
vtvolume_transmitterhandle
Dopamine volume transmitter
A_plusA_plusunitless
Facilitation amplitude
A_minusA_minusunitless
Depression amplitude
tau_plustau_plusms
Pre-trace time constant
(neuron property)
tau_minusms
Post-trace time constant
tau_ctau_cms
Eligibility decay constant
tau_ntau_nms
Dopamine decay constant
bbunitless
Dopamine baseline
WminWminunitless
Minimum weight bound
WmaxWmaxunitless
Maximum weight bound
KplusKplusunitless
Presynaptic trace state
ccunitless
Eligibility trace state
nnunitless
Dopamine trace state
- Raises:
If any time constant (
tau_plus,tau_minus,tau_c,tau_n) is non-positive. - IfKplusis negative. - Ifvolume_transmitterisNonewhensendorupdateis called. - If dopamine spikes are recorded out of temporal order. - Iftrigger_update_weightis called with a time earlier thant_last_update. - If any scalar parameter has non-scalar shape or non-finite value.
Notes
This model transmits spike-like events only (no continuous current injection).
update(pre_spike=..., post_spike=..., dopa_spike=...)supports explicit per-step dopamine multiplicity for standalone simulations without a separate volume transmitter object.One
trigger_update_weightpropagation is performed per simulation step inupdate(), corresponding to NEST’s defaultvolume_transmitterdelivery interval.Common properties (
A_plus,A_minus,tau_plus,tau_c,tau_n,Wmin,Wmax,b,volume_transmitter) cannot be specified in connect-time synapse specs; set them on the model template (viaCopyModel/SetDefaultsin NEST parlance).For large-scale simulations, consider memory overhead: each synapse maintains internal postsynaptic and dopamine spike histories.
Examples
Basic usage with explicit dopamine signaling:
>>> import brainpy.state as bp >>> import saiunit as u >>> # Create synapse with volume transmitter placeholder >>> syn = bp.stdp_dopamine_synapse( ... weight=1.0, ... delay=1.0 * u.ms, ... A_plus=1.0, ... A_minus=1.5, ... tau_plus=20.0 * u.ms, ... tau_minus=20.0 * u.ms, ... tau_c=1000.0 * u.ms, ... tau_n=200.0 * u.ms, ... b=0.0, ... Wmin=0.0, ... Wmax=10.0, ... volume_transmitter=object() # dummy handle ... ) >>> syn.init_state() >>> # Simulate pre spike followed by post spike (causal pairing) >>> syn.update(pre_spike=1.0, post_spike=0.0) # pre spike at t=dt >>> syn.update(pre_spike=0.0, post_spike=1.0) # post spike at t=2*dt >>> # Deliver reward signal >>> syn.update(pre_spike=0.0, post_spike=0.0, dopa_spike=1.0) # dopamine at t=3*dt >>> print(f"Weight after reward: {syn.weight:.3f}") Weight after reward: ...
Recording dopamine spikes explicitly:
>>> syn = bp.stdp_dopamine_synapse( ... weight=5.0, ... volume_transmitter=object(), ... tau_c=1000.0 * u.ms, ... tau_n=200.0 * u.ms ... ) >>> syn.init_state() >>> # Record multiple dopamine spikes >>> syn.record_dopa_spike(1.0, t_spike_ms=10.0) 1.0 >>> syn.record_dopa_spike(0.5, t_spike_ms=15.0) 0.5 >>> # Trigger weight update to specified time >>> syn.trigger_update_weight(t_trig_ms=20.0) >>> print(f"Weight: {syn.weight:.3f}") Weight: ...
See also
static_synapseBase class for static synaptic connections
stdp_synapseClassical spike-timing dependent plasticity without dopamine modulation
tsodyks_synapseShort-term synaptic plasticity (depression and facilitation)
References
- check_synapse_params(syn_spec)[source]#
Validate connect-time synapse specification for disallowed common properties.
Enforces NEST convention that certain parameters (STDP learning rules, dopamine modulation parameters) must be set on the synapse model template rather than per-connection at connect time.
- Parameters:
syn_spec (
dictorNone) – Synapse specification dictionary to validate. IfNone, no validation is performed.- Raises:
ValueError – If
syn_speccontains any of the following disallowed keys:'vt','volume_transmitter','A_plus','A_minus','tau_plus','tau_c','tau_n','Wmin','Wmax','b'.
Notes
In NEST, dopamine synapse common properties are set globally on the synapse model (via
CopyModelorSetDefaults), not per-connection. This method enforces that convention to prevent user confusion and maintain NEST compatibility.Allowed per-connection parameters:
weight,delay,receptor_type.Examples
>>> syn = bp.stdp_dopamine_synapse(volume_transmitter=object()) >>> # Valid: per-connection weight/delay >>> syn.check_synapse_params({'weight': 2.0, 'delay': 1.5}) >>> # Invalid: common property at connect time >>> syn.check_synapse_params({'A_plus': 1.0}) Traceback (most recent call last): ... ValueError: A_plus cannot be specified in connect-time synapse parameters ...
- clear_dopamine_history()[source]#
Reset internal dopamine spike history.
Clears the dopamine spike buffer and reinitializes it with a single pseudo-spike at the current
t_last_updatetime with zero multiplicity. This effectively resets the dopamine delivery history while preserving temporal continuity.Notes
Does not modify the current dopamine trace value (
n). To resetnas well, useset()withn=0.0or callinit_state().
- clear_post_history()[source]#
Clear internal postsynaptic STDP history state.
Resets the postsynaptic spike history buffer and depression trace to initial conditions. This is useful when reinitializing the synapse or starting a new trial in an experiment.
Notes
Does not affect presynaptic traces (
Kplus), eligibility trace (c), dopamine trace (n), or weight. To fully reset the synapse, useinit_state()instead.
- get()[source]#
Return current public parameters and mutable state.
Retrieves all NEST-style synapse parameters and state variables as a dictionary, suitable for inspection, serialization, or comparison with NEST
GetStatusoutput.- Returns:
Dictionary containing:
All parent class parameters (
weight,delay,receptor_type, etc.)volume_transmitter: dopamine volume transmitter handleA_plus: facilitation amplitudeA_minus: depression amplitudetau_plus: presynaptic trace time constant (ms)tau_minus: postsynaptic trace time constant (ms)tau_c: eligibility trace time constant (ms)tau_n: dopamine trace time constant (ms)b: dopamine baselineWmin: minimum weight boundWmax: maximum weight boundKplus: current presynaptic trace valuec: current eligibility trace valuen: current dopamine trace valuesynapse_model: model identifier ('stdp_dopamine_synapse')
- Return type:
Notes
Time constants are returned in milliseconds (internal representation), not as
saiunit.Quantityobjects.Examples
>>> syn = bp.stdp_dopamine_synapse( ... weight=5.0, ... A_plus=1.0, ... volume_transmitter=object() ... ) >>> syn.init_state() >>> params = syn.get() >>> print(params['weight']) 5.0 >>> print(params['A_plus']) 1.0 >>> print(params['synapse_model']) stdp_dopamine_synapse
- init_state(batch_size=None, **kwargs)[source]#
Initialize or reset all synapse state variables to their default values.
Resets all dynamic state (traces, timestamps, spike histories) to initial conditions as specified during construction or via
set(). This is typically called at the start of a simulation.- Parameters:
Notes
Resets the following state variables:
Kplus: presynaptic tracec: eligibility tracen: dopamine tracet_last_update: last update timestampt_lastspike: last presynaptic spike timestampPostsynaptic spike history (cleared)
Dopamine spike history (initialized with zero-multiplicity pseudo-spike)
Event delivery queue (inherited from parent)
Does not reset parameters (
A_plus,tau_c, etc.) or initial weight.
- record_dopa_spike(multiplicity=1.0, *, t_spike_ms=None)[source]#
Record dopamine spikes into internal volume-transmitter history.
Adds dopamine delivery events to the internal dopamine spike buffer. These events are processed during subsequent
trigger_update_weight()calls to update the dopamine trace (n) and modulate synaptic weight changes.- Parameters:
multiplicity (
floatorarray-like, optional) – Dopamine spike magnitude (must be non-negative float). Unlike postsynaptic spikes, dopamine “spikes” can have arbitrary positive real values representing dopamine concentration increments. Default:1.0.t_spike_ms (
float,array-like, orNone, optional) – Explicit timestamp in milliseconds for dopamine delivery. IfNone, uses current simulation time plus one timestep (t + dt). Default:None.
- Returns:
Dopamine multiplicity actually recorded.
- Return type:
- Raises:
ValueError – If
multiplicityis negative.ValueError – If
t_spike_msis earlier than the last recorded dopamine spike time (dopamine spikes must be recorded in non-decreasing temporal order).ValueError – If
multiplicityort_spike_msis not scalar or not finite.
Notes
Multiple dopamine deliveries at the same timestamp (within tolerance \(\epsilon = 10^{-6}\) ms) are accumulated additively.
Dopamine spikes are not processed immediately; they are stored in a queue and integrated during the next
trigger_update_weight()call.To simulate volume transmission delays, record dopamine spikes at future timestamps relative to the triggering event.
Examples
>>> syn = bp.stdp_dopamine_synapse( ... volume_transmitter=object(), ... tau_n=200.0 * u.ms ... ) >>> syn.init_state() >>> # Record reward signal at t=100 ms >>> mult = syn.record_dopa_spike(1.5, t_spike_ms=100.0) >>> print(f"Recorded dopamine: {mult}") Recorded dopamine: 1.5 >>> # Accumulate additional dopamine at same time >>> mult = syn.record_dopa_spike(0.5, t_spike_ms=100.0) >>> print(f"Total at t=100: {syn._dopa_spikes[-1][1]}") Total at t=100: 2.0 >>> # Trigger update to integrate dopamine >>> syn.trigger_update_weight(t_trig_ms=150.0)
- record_post_spike(multiplicity=1.0, *, t_spike_ms=None)[source]#
Record postsynaptic spikes into internal STDP history.
Adds postsynaptic spike events to the internal history buffer and updates the postsynaptic depression trace (
Kminus). These spikes are used during subsequent presynaptic spike processing to compute eligibility trace updates.- Parameters:
multiplicity (
floatorarray-like, optional) – Number of spikes to record (must be non-negative integer or convertible to integer). Fractional values will be rounded. Default:1.0.t_spike_ms (
float,array-like, orNone, optional) – Explicit spike timestamp in milliseconds. IfNone, uses the current simulation time plus one timestep (t + dt). Default:None.
- Returns:
Number of spikes actually recorded (rounded
multiplicity).- Return type:
- Raises:
ValueError – If
multiplicityis not a non-negative integer (after rounding).ValueError – If
t_spike_msis not a scalar or not finite.
Notes
Multiple spikes at the same timestamp accumulate exponentially in the
Kminustrace: \(K_- \leftarrow (K_- + 1)^{\text{multiplicity}}\).This method does not trigger plasticity updates; it only records spike times for future processing during
send()ortrigger_update_weight().
Examples
>>> syn = bp.stdp_dopamine_synapse(volume_transmitter=object()) >>> syn.init_state() >>> # Record single spike at current time >>> n = syn.record_post_spike(1.0) >>> print(n) 1 >>> # Record multiple spikes at explicit time >>> n = syn.record_post_spike(3.0, t_spike_ms=25.0) >>> print(n) 3
- send(multiplicity=1.0, *, post=None, receptor_type=None)[source]#
Schedule one outgoing spike event with dopamine-modulated STDP updates.
Implements the NEST
stdp_dopamine_synapse::sendmethod: processes postsynaptic spike history, updates eligibility trace, propagates dopamine and weight dynamics, then schedules a delayed synaptic event to the postsynaptic target.- Parameters:
multiplicity (
floatorarray-like, optional) – Presynaptic spike multiplicity (typically1.0for single spikes, or higher for burst events). If zero, no event is sent. Default:1.0.post (
DynamicsorNone, optional) – Postsynaptic receiver object. IfNone, uses the synapse’s defaultpostattribute. Default:None.receptor_type (
int,array-like, orNone, optional) – Target receptor port on postsynaptic neuron. IfNone, uses the synapse’s defaultreceptor_type. Default:None.
- Returns:
Trueif an event was scheduled,Falseifmultiplicitywas zero.- Return type:
- Raises:
ValueError – If
volume_transmitterisNone(must be assigned before sending events).
Notes
Update sequence (following NEST ``stdp_dopamine_synapse::send``):
Retrieve postsynaptic spike history in the window \((t_{\mathrm{last\_update}} - d,\; t_{\mathrm{pre}} - d]\) where \(d\) is dendritic delay.
For each postsynaptic spike \(t_{\mathrm{post}}\) in that window:
Propagate dopamine/eligibility/weight to \(t_{\mathrm{post}} + d\)
If \(t_{\mathrm{pre}} - t_{\mathrm{post}} > \epsilon\), facilitate eligibility trace: \(c \leftarrow c + A_+ K_+(t)\)
Propagate dopamine/eligibility/weight to \(t_{\mathrm{pre}}\)
Depress eligibility trace: \(c \leftarrow c - A_- K_-(t_{\mathrm{pre}} - d)\)
Schedule spike event with updated
weightfor delivery at \(t_{\mathrm{pre}} + \mathrm{delay}\)Update presynaptic trace: \(K_+ \leftarrow K_+ \exp((t_{\mathrm{last\_update}} - t_{\mathrm{pre}}) / \tau_+) + 1\)
Set \(t_{\mathrm{last\_update}} = t_{\mathrm{lastspike}} = t_{\mathrm{pre}}\)
The event payload is
multiplicity * weight, modulated by dopamine-driven weight changes up to the current spike time.Timing: Uses current simulation time plus one timestep (
t + dt) as the spike timestamp (on-grid timing).Examples
>>> import brainpy.state as bp >>> import saiunit as u >>> # Create postsynaptic neuron and synapse >>> post_neuron = bp.LIF(1) >>> syn = bp.stdp_dopamine_synapse( ... weight=5.0, ... delay=1.0 * u.ms, ... post=post_neuron, ... volume_transmitter=object() ... ) >>> syn.init_state() >>> # Send presynaptic spike >>> sent = syn.send(1.0) >>> print(sent) True >>> # Check updated trace >>> print(f"Kplus after spike: {syn.Kplus:.3f}") Kplus after spike: 1.000
See also
trigger_update_weightPropagate state without sending spike event
updateHigh-level method combining spike delivery, recording, and sending
- set(*, weight=<object object>, delay=<object object>, receptor_type=<object object>, volume_transmitter=<object object>, A_plus=<object object>, A_minus=<object object>, tau_plus=<object object>, tau_minus=<object object>, tau_c=<object object>, tau_n=<object object>, b=<object object>, Wmin=<object object>, Wmax=<object object>, Kplus=<object object>, c=<object object>, n=<object object>, post=<object object>)[source]#
Set NEST-style public parameters and mutable state.
Updates synapse parameters and/or state variables. Validates all new values before applying changes. Only parameters explicitly provided are modified.
- Parameters:
weight (
float,array-like, orsentinel, optional) – New synaptic weight. If_UNSET, weight is not changed.delay (
Quantity,array-like, orsentinel, optional) – New synaptic delay. If_UNSET, delay is not changed.receptor_type (
intorsentinel, optional) – New receptor port identifier. If_UNSET, receptor type is not changed.volume_transmitter (
objectorsentinel, optional) – New volume transmitter handle. If_UNSET, handle is not changed.A_plus (
float,array-like, orsentinel, optional) – New facilitation amplitude. If_UNSET, not changed.A_minus (
float,array-like, orsentinel, optional) – New depression amplitude. If_UNSET, not changed.tau_plus (
Quantity,array-like, orsentinel, optional) – New presynaptic trace time constant. If_UNSET, not changed.tau_minus (
Quantity,array-like, orsentinel, optional) – New postsynaptic trace time constant. If_UNSET, not changed.tau_c (
Quantity,array-like, orsentinel, optional) – New eligibility trace time constant. If_UNSET, not changed.tau_n (
Quantity,array-like, orsentinel, optional) – New dopamine trace time constant. If_UNSET, not changed.b (
float,array-like, orsentinel, optional) – New dopamine baseline. If_UNSET, not changed.Wmin (
float,array-like, orsentinel, optional) – New minimum weight bound. If_UNSET, not changed.Wmax (
float,array-like, orsentinel, optional) – New maximum weight bound. If_UNSET, not changed.Kplus (
float,array-like, orsentinel, optional) – New presynaptic trace value. Must be non-negative. If_UNSET, not changed.c (
float,array-like, orsentinel, optional) – New eligibility trace value. If_UNSET, not changed.n (
float,array-like, orsentinel, optional) – New dopamine trace value. If_UNSET, not changed.post (
objectorsentinel, optional) – New default postsynaptic receiver. If_UNSET, not changed.
- Raises:
If any time constant is non-positive. - If
Kplusis negative. - If any parameter has non-scalar shape or non-finite value.
Notes
Changing parameters during a simulation may produce non-physical discontinuities. For clean state resets, use
init_state()instead.Updating initial state values (
Kplus,c,n) also updates the stored initial conditions used byinit_state().
Examples
>>> syn = bp.stdp_dopamine_synapse( ... weight=1.0, ... A_plus=1.0, ... volume_transmitter=object() ... ) >>> syn.init_state() >>> # Modify learning rate mid-simulation >>> syn.set(A_plus=2.0, A_minus=3.0) >>> print(syn.A_plus) 2.0 >>> # Reset dopamine trace >>> syn.set(n=0.5) >>> print(syn.n) 0.5
- trigger_update_weight(*, t_trig_ms=None)[source]#
Propagate dopamine, eligibility, and weight to specified trigger time.
Implements NEST
stdp_dopamine_synapse::trigger_update_weight: processes postsynaptic spikes, integrates dopamine spike history, updates weight via eligibility trace modulation, and advances all state traces to the trigger time. This is typically called once per simulation timestep to integrate volume transmitter dopamine deliveries.- Parameters:
t_trig_ms (
float,array-like, orNone, optional) – Target timestamp in milliseconds to which state should be propagated. IfNone, uses current simulation time plus one timestep (t + dt). Default:None.- Raises:
ValueError – If
volume_transmitterisNone.ValueError – If
t_trig_msis earlier thant_last_update(backward time propagation is not allowed).ValueError – If
t_trig_msis not scalar or not finite.
Notes
Update sequence:
Retrieve postsynaptic spike history in the window \((t_{\mathrm{last\_update}} - d,\; t_{\mathrm{trig}} - d]\) where \(d\) is dendritic delay.
For each postsynaptic spike \(t_{\mathrm{post}}\) in that window:
Propagate dopamine/eligibility/weight to \(t_{\mathrm{post}} + d\)
Facilitate eligibility trace: \(c \leftarrow c + A_+ K_+(t) \exp((t_{\mathrm{last\_update}} - (t_{\mathrm{post}} + d)) / \tau_+)\)
Propagate dopamine/eligibility/weight to \(t_{\mathrm{trig}}\)
Advance dopamine trace: \(n \leftarrow n \exp((t_{\mathrm{last\_dopa}} - t_{\mathrm{trig}}) / \tau_n)\)
Advance presynaptic trace: \(K_+ \leftarrow K_+ \exp((t_{\mathrm{last\_update}} - t_{\mathrm{trig}}) / \tau_+)\)
Set \(t_{\mathrm{last\_update}} = t_{\mathrm{trig}}\)
Reset dopamine spike buffer to \([(t_{\mathrm{trig}}, 0)]\)
Weight integration uses the analytical solution:
\[w \leftarrow w - c(t_0) \left( \frac{n(t_0)}{\tau_s} \mathrm{expm1}(\tau_s \Delta t) - b \tau_c \mathrm{expm1}(\Delta t / \tau_c) \right)\]where \(\tau_s = (\tau_c + \tau_n) / (\tau_c \tau_n)\) and clipped to \([W_{\min}, W_{\max}]\).
Typical usage: Called once per timestep in
update()withtrigger_dopa_update=True(default) to synchronize with volume transmitter delivery intervals.Examples
>>> syn = bp.stdp_dopamine_synapse( ... weight=5.0, ... tau_c=1000.0 * u.ms, ... tau_n=200.0 * u.ms, ... b=0.1, ... volume_transmitter=object() ... ) >>> syn.init_state() >>> # Record some eligibility via spike pairing (not shown) >>> syn.c = 0.5 # artificial eligibility >>> # Record dopamine spike >>> syn.record_dopa_spike(2.0, t_spike_ms=10.0) >>> # Trigger update to integrate dopamine effect >>> syn.trigger_update_weight(t_trig_ms=50.0) >>> print(f"Weight after dopamine: {syn.weight:.3f}") Weight after dopamine: ...
See also
sendSend presynaptic spike with plasticity updates
record_dopa_spikeRecord dopamine delivery event
updateHigh-level simulation step including trigger_update_weight
- update(pre_spike=0.0, *, post_spike=0.0, dopa_spike=0.0, post=None, receptor_type=None, trigger_dopa_update=True)[source]#
Execute one simulation timestep with spike delivery, plasticity, and dopamine updates.
This is the primary high-level interface for advancing synapse dynamics. It integrates spike event delivery, postsynaptic/dopamine spike recording, presynaptic spike processing with STDP updates, and dopamine-modulated weight integration.
- Parameters:
pre_spike (
floatorarray-like, optional) – Presynaptic spike multiplicity for the current timestep (typically0.0or1.0). Aggregated with any registered input sources viasum_current_inputs()andsum_delta_inputs(). Default:0.0.post_spike (
floatorarray-like, optional) – Postsynaptic spike multiplicity (integer count, will be rounded). Recorded into internal postsynaptic history for STDP processing. Default:0.0.dopa_spike (
floatorarray-like, optional) – Dopamine delivery multiplicity (arbitrary non-negative float representing concentration increment). Recorded into internal dopamine history. Default:0.0.post (
DynamicsorNone, optional) – Postsynaptic receiver for spike events. IfNone, uses synapse’s defaultpostattribute. Default:None.receptor_type (
int,array-like, orNone, optional) – Target receptor port on postsynaptic neuron. IfNone, uses synapse’s defaultreceptor_type. Default:None.trigger_dopa_update (
bool, optional) – IfTrue, callstrigger_update_weight()at the end of the timestep to integrate dopamine effects (standard NEST behavior). IfFalse, skips weight propagation (useful for debugging or custom control). Default:True.
- Returns:
Number of delayed synaptic events delivered to postsynaptic targets during this timestep.
- Return type:
- Raises:
ValueError – If
volume_transmitterisNone.ValueError – If
post_spikeordopa_spikecannot be converted to valid non-negative scalar counts/multiplicities.
Notes
Update sequence:
Deliver delayed events: Process all events in the delivery queue scheduled for the current simulation step (
t). Events are sent to their target neurons.Record postsynaptic spikes: If
post_spike > 0, record spike(s) at timestampt + dtinto internal postsynaptic history. UpdatesKminustrace.Record dopamine spikes: If
dopa_spike > 0, record dopamine delivery at timestampt + dtinto internal dopamine history.Process presynaptic spikes: If
pre_spike > 0(after aggregating input sources), callsend()to:Process postsynaptic history for STDP eligibility updates
Integrate dopamine/weight dynamics
Schedule delayed synaptic event
Update presynaptic trace
Kplus
Trigger dopamine update (if
trigger_dopa_update=True): Calltrigger_update_weight()to propagate all traces and weight tot + dt, integrating queued dopamine spikes.
Timing convention: All spikes (pre, post, dopamine) are timestamped at
t + dt(on-grid, next simulation step).Typical usage: Called once per simulation timestep in a training loop.
Examples
Basic simulation loop with pre/post spike pairing:
>>> import brainpy.state as bp >>> import saiunit as u >>> import brainstate as bs >>> # Setup >>> post_neuron = bp.LIF(1) >>> syn = bp.stdp_dopamine_synapse( ... weight=5.0, ... delay=1.0 * u.ms, ... post=post_neuron, ... volume_transmitter=object(), ... A_plus=0.01, ... A_minus=0.012 ... ) >>> syn.init_state() >>> post_neuron.init_all_states() >>> # Simulate causal spike pairing >>> with bs.environ.context(dt=0.1 * u.ms): ... delivered = syn.update(pre_spike=1.0, post_spike=0.0) # pre at t=0.1ms ... delivered = syn.update(pre_spike=0.0, post_spike=1.0) # post at t=0.2ms ... # Deliver reward ... delivered = syn.update(pre_spike=0.0, post_spike=0.0, dopa_spike=1.0) >>> print(f"Final weight: {syn.weight:.4f}") Final weight: ...
Disabling dopamine updates for testing:
>>> syn = bp.stdp_dopamine_synapse( ... weight=1.0, ... volume_transmitter=object() ... ) >>> syn.init_state() >>> # Update without weight propagation >>> delivered = syn.update( ... pre_spike=1.0, ... trigger_dopa_update=False ... ) >>> # Weight remains unchanged (no dopamine integration) >>> print(syn.weight) 1.0
See also
sendProcess presynaptic spike with STDP updates
trigger_update_weightPropagate state with dopamine integration
record_post_spikeManually record postsynaptic spike
record_dopa_spikeManually record dopamine delivery