tsodyks_synapse#
- class brainpy.state.tsodyks_synapse(weight=1.0, delay=Quantity(1., 'ms'), receptor_type=0, tau_psc=Quantity(3., 'ms'), tau_fac=Quantity(0., 'ms'), tau_rec=Quantity(800., 'ms'), U=0.5, x=1.0, y=0.0, u=0.0, post=None, name=None)#
NEST-compatible
tsodyks_synapseconnection model.tsodyks_synapseimplements the short-term plasticity (STP) model of Tsodyks, Uziel, and Markram (2000), exhibiting both synaptic depression and facilitation. This synapse tracks three dynamic state variables—recovered resourcesx, active resourcesy, and utilizationu—that evolve between presynaptic spikes and are updated upon spike arrival.The model replicates NEST
models/tsodyks_synapse.hexactly, including propagator computation, update ordering, and event timing semantics. Delay scheduling and receiver delivery inherit fromstatic_synapse.1. Mathematical Model
State Variables
x: Fraction of resources in the recovered (available) statey: Fraction of resources in the active (released) stateu: Utilization (instantaneous release probability)z = 1 - x - y: Fraction of resources in the inactive (unavailable) state
Constraint: \(x + y + z = 1\) at all times;
x, y, zare non-negative.Continuous-time dynamics (between spikes):
\[ \begin{align}\begin{aligned}\frac{du}{dt} = -\frac{u}{\tau_{\mathrm{fac}}}\\\frac{dy}{dt} = -\frac{y}{\tau_{\mathrm{psc}}}\\\frac{dz}{dt} = -\frac{z}{\tau_{\mathrm{rec}}}\\x = 1 - y - z\end{aligned}\end{align} \]where:
\(\tau_{\mathrm{fac}}\) – Facilitation time constant (ms). If \(\tau_{\mathrm{fac}} = 0\), facilitation is disabled and \(u\) decays instantly to zero.
\(\tau_{\mathrm{psc}}\) – Time constant of synaptic current decay (ms).
\(\tau_{\mathrm{rec}}\) – Recovery time constant for inactive resources (ms).
Upon presynaptic spike at time \(t_s\):
Let \(h = t_s - t_{\mathrm{last}}\) be the inter-spike interval since the last presynaptic spike.
Step 1: Propagate state from \(t_{\mathrm{last}}\) to \(t_s\):
\[ \begin{align}\begin{aligned}u \leftarrow u \cdot P_{uu}\\x \leftarrow x + P_{xy} \, y - P_{zz} \, z\\y \leftarrow y \cdot P_{yy}\end{aligned}\end{align} \]where the exact propagators are:
\[ \begin{align}\begin{aligned}\begin{split}P_{uu} = \begin{cases} 0, & \tau_{\mathrm{fac}} = 0 \\ e^{-h/\tau_{\mathrm{fac}}}, & \tau_{\mathrm{fac}} > 0 \end{cases}\end{split}\\P_{yy} = e^{-h/\tau_{\mathrm{psc}}}\\P_{zz} = e^{-h/\tau_{\mathrm{rec}}} - 1\\P_{xy} = \frac{P_{zz} \, \tau_{\mathrm{rec}} - (P_{yy} - 1) \, \tau_{\mathrm{psc}}} {\tau_{\mathrm{psc}} - \tau_{\mathrm{rec}}}\end{aligned}\end{align} \]Step 2: Spike-triggered facilitation:
\[u \leftarrow u + U (1 - u)\]where \(U\) is the baseline utilization increment parameter.
Step 3: Resource release:
\[\Delta y = u \cdot x\]Step 4: Update resource fractions:
\[ \begin{align}\begin{aligned}x \leftarrow x - \Delta y\\y \leftarrow y + \Delta y\end{aligned}\end{align} \]Step 5: Effective weight delivered to postsynaptic neuron:
\[w_{\mathrm{eff}} = \Delta y \cdot w\]where \(w\) is the baseline synaptic weight.
2. Update Ordering and NEST Compatibility
This implementation preserves the exact update sequence from NEST
models/tsodyks_synapse.h::send():Compute propagators \(P_{uu}, P_{yy}, P_{zz}, P_{xy}\) from inter-spike interval \(h\)
Propagate utilization:
u *= P_uuPropagate recovered resources:
x += P_xy * y - P_zz * zPropagate active resources:
y *= P_yyFacilitation jump:
u += U * (1 - u)Compute release:
delta_y = u * xUpdate resources:
x -= delta_y,y += delta_ySchedule weighted event:
w_eff = delta_y * weight
3. Event Timing Semantics
NEST evaluates this model using spike time stamps (on-grid times) and ignores precise sub-step offsets. This implementation follows the same convention:
Presynaptic spike detected at simulation step
nSpike time stamp: \(t_{\mathrm{spike}} = t_n + dt\)
Inter-spike interval: \(h = t_{\mathrm{spike}} - t_{\mathrm{lastspike}}\)
Delivery time: \(t_{\mathrm{delivery}} = t_{\mathrm{spike}} + \mathrm{delay}\)
4. Stability Constraints and Computational Implications
Parameter Constraints:
\(\tau_{\mathrm{psc}} > 0\) (strictly positive)
\(\tau_{\mathrm{fac}} \geq 0\) (zero disables facilitation)
\(\tau_{\mathrm{rec}} > 0\) (strictly positive)
\(U \in [0, 1]\)
\(x, y, u \in [0, 1]\)
\(x + y \leq 1\) (ensures \(z \geq 0\))
Numerical Considerations
Propagators \(P_{uu}, P_{yy}, P_{zz}\) are computed using
math.exp()andmath.expm1()for numerical stability.The cross-propagator \(P_{xy}\) involves division by \(\tau_{\mathrm{psc}} - \tau_{\mathrm{rec}}\). If these time constants are nearly equal, numerical precision may degrade. NEST does not provide a singular fallback; users should avoid \(\tau_{\mathrm{psc}} \approx \tau_{\mathrm{rec}}\).
All state variables are stored as Python floats (
float64precision).Per-call cost is \(O(1)\) (scalar operations only).
Behavioral Regimes:
Depression-dominated (\(\tau_{\mathrm{fac}} = 0\), \(U > 0\)): Repeated spikes deplete
x, reducingdelta_yover time.Facilitation-dominated (\(\tau_{\mathrm{fac}} > 0\), large \(U\)): Utilization
ugrows with repeated spikes, increasing release.Mixed dynamics: Both effects coexist, yielding complex short-term plasticity.
- Parameters:
weight (
ArrayLike, optional) – Baseline synaptic weight \(w\) (dimensionless or with receiver-specific units). Scalar float or array-like. Default:1.0.delay (
ArrayLike, optional) – Synaptic transmission delay \(d\) in milliseconds. Must be> 0. Quantized to integer time steps perstatic_synapseconventions. Scalar withsaiunittime dimension or dimensionless value interpreted as milliseconds. Default:1.0 * u.ms.receptor_type (
int, optional) – Postsynaptic receptor port identifier (non-negative integer). Routes events to labeled input channels on the receiver neuron. Default:0.tau_psc (
ArrayLike, optional) – Time constant of synaptic current decay \(\tau_{\mathrm{psc}}\) in milliseconds. Must be> 0. Scalar withsaiunittime dimension or dimensionless value interpreted as milliseconds. Default:3.0 * u.ms.tau_fac (
ArrayLike, optional) – Facilitation time constant \(\tau_{\mathrm{fac}}\) in milliseconds. Must be>= 0. Set to0.0 * u.msto disable facilitation. Scalar withsaiunittime dimension or dimensionless value interpreted as milliseconds. Default:0.0 * u.ms.tau_rec (
ArrayLike, optional) – Recovery (depression) time constant \(\tau_{\mathrm{rec}}\) in milliseconds. Must be> 0. Scalar withsaiunittime dimension or dimensionless value interpreted as milliseconds. Default:800.0 * u.ms.U (
ArrayLike, optional) – Baseline utilization increment parameter \(U\) (dimensionless). Must be in[0, 1]. Determines the magnitude of facilitation per spike. Scalar float. Default:0.5.x (
ArrayLike, optional) – Initial fraction of recovered resources (dimensionless). Must be in[0, 1]. Together withy, must satisfyx + y <= 1. Scalar float. Default:1.0.y (
ArrayLike, optional) – Initial fraction of active resources (dimensionless). Must be in[0, 1]. Together withx, must satisfyx + y <= 1. Scalar float. Default:0.0.u (
ArrayLike, optional) – Initial utilization value (dimensionless). Must be in[0, 1]. Scalar float. Default:0.0.post (
object, optional) – Default postsynaptic receiver neuron. If provided, this neuron will be the target for allsend()calls unless overridden by thepostargument insend()orupdate(). Default:None.name (
str, optional) – Unique identifier for this synapse instance. Used for debugging and logging. Default:None(auto-generated).
Parameter Mapping
NEST Parameter
brainpy.state
Description
weightweightBaseline synaptic weight
delaydelaySynaptic delay (ms)
receptor_typereceptor_typePostsynaptic receptor port
tau_psctau_pscSynaptic current time constant (ms)
tau_factau_facFacilitation time constant (ms)
tau_rectau_recRecovery time constant (ms)
UUUtilization increment parameter
xxRecovered resources state variable
yyActive resources state variable
uuUtilization state variable
- t_lastspike#
Time stamp of the last presynaptic spike (ms). Used to compute inter-spike intervals for propagator calculations.
- Type:
Notes
Event Type: This model transmits
'spike'events only. Other event types ('rate','current','conductance') are not supported.State Variables:
x,y, anduare mutable per-connection states. They can be inspected viaget()and modified viaset().Initialization: Calling
init_state()resets the internal event queue and restoresx,y,uto their initial values (self._x0,self._y0,self._u0). It also resetst_lastspiketo0.0.Scalar-Only: All parameters and state variables are scalar floats. This model does not support vectorized per-connection parameters.
No Precise Timing: Unlike some NEST models with
_psvariants, this implementation uses on-grid spike stamps and does not track sub-step offsets.
See also
tsodyks_synapse_homHomogeneous variant with shared state across all connections.
tsodyks2_synapseAlternative Tsodyks model with different parameterization.
static_synapseBase class for non-plastic synaptic connections.
References
Examples
1. Depression-dominated synapse (excitatory with depletion):
>>> import brainpy.state as bp >>> import saiunit as u >>> syn = bp.nest.tsodyks_synapse( ... weight=1.0, ... delay=1.5 * u.ms, ... tau_psc=5.0 * u.ms, ... tau_fac=0.0 * u.ms, # no facilitation ... tau_rec=800.0 * u.ms, ... U=0.5, ... x=1.0, ... y=0.0, ... u=0.0 ... )
2. Facilitation-dominated synapse (inhibitory with strengthening):
>>> syn = bp.nest.tsodyks_synapse( ... weight=-2.0, # inhibitory ... delay=1.0 * u.ms, ... tau_psc=3.0 * u.ms, ... tau_fac=200.0 * u.ms, # strong facilitation ... tau_rec=800.0 * u.ms, ... U=0.15, ... x=1.0, ... y=0.0, ... u=0.0 ... )
3. Simulating short-term plasticity:
>>> import brainstate as bst >>> with bst.environ.context(dt=0.1 * u.ms): ... syn.init_all_states() ... # Simulate spike train at 50 Hz ... spike_times = [0.0, 20.0, 40.0, 60.0, 80.0] # ms ... for t_spike in spike_times: ... # Advance simulation to spike time ... # ... (step simulation forward) ... syn.send(multiplicity=1.0) ... print(f"t={t_spike:.1f} ms: u={syn.u:.3f}, x={syn.x:.3f}, y={syn.y:.3f}")
4. Inspecting and modifying state:
>>> params = syn.get() >>> print(params['x'], params['y'], params['u']) 1.0 0.0 0.0 >>> syn.set(x=0.8, y=0.1, u=0.3) >>> print(syn.x, syn.y, syn.u) 0.8 0.1 0.3
5. Multi-receptor connection:
>>> syn_ex = bp.nest.tsodyks_synapse( ... weight=1.0, delay=1.0 * u.ms, receptor_type=0, U=0.5 ... ) >>> syn_in = bp.nest.tsodyks_synapse( ... weight=-1.0, delay=1.0 * u.ms, receptor_type=1, U=0.25 ... ) >>> # Excitatory and inhibitory inputs routed to different receptor ports
- get()[source]#
Return current public parameters and mutable state variables.
Retrieves all NEST-visible synapse parameters, including the baseline weight, delay, receptor type (from
super().get()), time constants, utilization parameter, and current state variablesx,y,u.- Returns:
Dictionary with the following keys:
'weight'(float): Baseline synaptic weight'delay'(float): Synaptic delay in ms'receptor_type'(int): Postsynaptic receptor port'tau_psc'(float): Synaptic current time constant in ms'tau_fac'(float): Facilitation time constant in ms'tau_rec'(float): Recovery time constant in ms'U'(float): Utilization increment parameter'x'(float): Current recovered resources'y'(float): Current active resources'u'(float): Current utilization value'synapse_model'(str): Model identifier ('tsodyks_synapse')
- Return type:
Notes
The returned dictionary reflects the current state at the time of the call. State variables
x,y,uevolve during simulation.This method is compatible with NEST’s
GetStatus()semantics.
Examples
>>> syn = bp.nest.tsodyks_synapse(U=0.5, tau_rec=800.0 * u.ms) >>> params = syn.get() >>> print(params['U'], params['tau_rec'], params['x']) 0.5 800.0 1.0
- init_state(batch_size=None, **kwargs)[source]#
Initialize or reset all state variables to their configured initial values.
Resets the internal event delivery queue (via
super().init_state()) and restores the short-term plasticity state variablesx,y,uto their initial values (self._x0,self._y0,self._u0). Also resets the last spike time stamp to0.0.- Parameters:
batch_size (
int, optional) – Ignored. This scalar synapse model does not support batching.**kwargs – Additional keyword arguments. Ignored.
Notes
This method is typically called once at the start of a simulation or when resetting the network state.
After calling this method, the synapse behaves as if no presynaptic spikes have occurred yet (
t_lastspike = 0.0).
- send(multiplicity=1.0, *, post=None, receptor_type=None)[source]#
Schedule one outgoing event with NEST
tsodyks_synapseshort-term plasticity dynamics.Processes a presynaptic spike event by:
Propagating state variables
u,x,yfrom the last spike time to the current spike time.Applying spike-triggered facilitation to
u.Computing the released resource fraction
delta_y = u * x.Updating resource fractions
xandy.Scheduling a weighted event (
delta_y * weight * multiplicity) for delivery to the postsynaptic neuron.
The update ordering exactly matches NEST
models/tsodyks_synapse.h::send().- Parameters:
multiplicity (
ArrayLike, optional) – Presynaptic spike count (typically1.0for a single spike or0.0for no spike). Can be a float representing spike rate or an integer spike count. Default:1.0.post (
object, optional) – Postsynaptic receiver neuron. IfNone, uses the default receiver specified at construction (self.post). Default:None.receptor_type (
ArrayLike, optional) – Receptor port to target on the postsynaptic neuron. IfNone, usesself.receptor_type. Default:None.
- Returns:
Trueif an event was scheduled (i.e.,multiplicityis non-zero),Falseotherwise.- Return type:
Notes
Event Timing: The spike time stamp is computed as
current_time + dt(on-grid time). Inter-spike intervalhis the difference between the current spike stamp andself.t_lastspike.State Update: State variables
u,x,yare updated in place and persist across calls.t_lastspikeis updated to the current spike stamp.Zero Multiplicity: If
multiplicityis zero or negligible, no event is scheduled and state variables are not updated. ReturnsFalse.Effective Weight: The delivered payload is
delta_y * weight * multiplicity, wheredelta_yis the released resource fraction computed from current state.
Warnings
If
tau_pscandtau_recare numerically close, the propagatorP_xymay suffer from floating-point cancellation. Users should avoid configurations whereabs(tau_psc - tau_rec) < 1e-6.
Examples
>>> import brainstate as bst >>> with bst.environ.context(dt=0.1 * u.ms): ... syn = bp.nest.tsodyks_synapse(weight=1.0, U=0.5, tau_rec=800.0 * u.ms) ... syn.init_all_states() ... # First spike ... success = syn.send(multiplicity=1.0) ... print(f"Scheduled: {success}, u={syn.u:.3f}, x={syn.x:.3f}") Scheduled: True, u=0.500, x=0.500 ... # Second spike 20 ms later (simulate time advancement) ... success = syn.send(multiplicity=1.0) ... print(f"Scheduled: {success}, u={syn.u:.3f}, x={syn.x:.3f}") Scheduled: True, u=0.750, x=0.125
- set(*, weight=<object object>, delay=<object object>, receptor_type=<object object>, tau_psc=<object object>, tau_fac=<object object>, tau_rec=<object object>, U=<object object>, x=<object object>, y=<object object>, u=<object object>, post=<object object>)[source]#
Set NEST-style public parameters and state variables.
Updates synapse parameters and/or state variables. Only parameters explicitly provided (not
_UNSET) are modified. All changes are validated before application. Ifxoryare updated, their sum is checked to ensurex + y <= 1.Updating state variables
x,y, orualso updates their initial values (self._x0,self._y0,self._u0), so subsequent calls toinit_state()will restore to the newly set values.- Parameters:
weight (
ArrayLike, optional) – New baseline synaptic weight. If not provided, weight is unchanged.delay (
ArrayLike, optional) – New synaptic delay in ms. Must be> 0. If not provided, delay is unchanged.receptor_type (
int, optional) – New postsynaptic receptor port. Must be a non-negative integer. If not provided, receptor type is unchanged.tau_psc (
ArrayLike, optional) – New synaptic current time constant in ms. Must be> 0. If not provided,tau_pscis unchanged.tau_fac (
ArrayLike, optional) – New facilitation time constant in ms. Must be>= 0. If not provided,tau_facis unchanged.tau_rec (
ArrayLike, optional) – New recovery time constant in ms. Must be> 0. If not provided,tau_recis unchanged.U (
ArrayLike, optional) – New utilization increment parameter. Must be in[0, 1]. If not provided,Uis unchanged.x (
ArrayLike, optional) – New recovered resources value. Must be in[0, 1]. Together withy, must satisfyx + y <= 1. If not provided,xis unchanged.y (
ArrayLike, optional) – New active resources value. Must be in[0, 1]. Together withx, must satisfyx + y <= 1. If not provided,yis unchanged.u (
ArrayLike, optional) – New utilization value. Must be in[0, 1]. If not provided,uis unchanged.post (
object, optional) – New default postsynaptic receiver neuron. If not provided, receiver is unchanged.
- Raises:
ValueError – If any parameter violates its constraint (e.g.,
tau_psc <= 0,Uout of range,x + y > 1).
Notes
This method is compatible with NEST’s
SetStatus()semantics.Parameter validation occurs before any state is modified. If validation fails, no changes are applied.
Updating state variables mid-simulation can produce non-physical dynamics. Use with caution outside of initialization or testing contexts.
Examples
>>> syn = bp.nest.tsodyks_synapse(U=0.5) >>> syn.set(U=0.8, tau_rec=600.0 * u.ms) >>> print(syn.U, syn.tau_rec) 0.8 600.0 >>> syn.set(x=0.7, y=0.2) >>> print(syn.x, syn.y) 0.7 0.2 >>> syn.set(x=0.8, y=0.3) ValueError: x + y must be <= 1.0.
- update(pre_spike=0.0, *, post=None, receptor_type=None)[source]#
Deliver due events and process current-step presynaptic input.
This method performs two tasks per simulation time step:
Deliver pending events: Dequeue and dispatch all events scheduled for delivery at the current simulation time step (via
_deliver_due_events()).Process presynaptic input: Collect current-step and delta inputs (via
sum_current_inputs()andsum_delta_inputs()), then schedule a new event if total input is non-zero (viasend()).
This is the main per-step entry point for synapse dynamics when integrated into a simulation loop.
- Parameters:
pre_spike (
ArrayLike, optional) – Presynaptic spike count or rate for the current simulation step. Typically0.0(no spike) or1.0(spike). This value is accumulated with any other inputs registered viaadd_current_input()oradd_delta_input(). Default:0.0.post (
object, optional) – Postsynaptic receiver neuron. IfNone, uses the default receiver specified at construction. Default:None.receptor_type (
ArrayLike, optional) – Receptor port to target. IfNone, usesself.receptor_type. Default:None.
- Returns:
Number of events delivered during this step (from the delivery queue).
- Return type:
Notes
Execution Order: Delivery precedes scheduling. Events scheduled at step
nare delivered at stepn + delay_steps.Input Accumulation:
pre_spikeis summed with any inputs registered via thecurrent_inputsanddelta_inputsdictionaries (inherited fromDynamics). The total determines whether a new event is scheduled.Typical Usage: Call this method once per simulation time step in a network update loop, after presynaptic neuron spike detection.
Examples
>>> import brainstate as bst >>> with bst.environ.context(dt=0.1 * u.ms): ... syn = bp.nest.tsodyks_synapse(weight=1.0, delay=1.0 * u.ms, U=0.5) ... syn.init_all_states() ... # Simulate one step with a presynaptic spike ... delivered_count = syn.update(pre_spike=1.0) ... print(f"Delivered: {delivered_count}, State: u={syn.u:.3f}, x={syn.x:.3f}") Delivered: 0, State: u=0.500, x=0.500 ... # Advance simulation by delay steps (typically via outer loop) ... # ... (advance time by 1.0 ms) ... delivered_count = syn.update(pre_spike=0.0) ... print(f"Delivered: {delivered_count}") Delivered: 1