Plasticity rules

Long-term rules (LTPParam, act on W) and short-term rules (STPParam, act on ρ) of SpikingSynapse; they run only under train!. Usage: Plasticity.

Common structure

Rule (parameter type)State typeFamilyTraces
STDPGerstnerSTDPVariablespair STDP, additiveexact decay, event-driven
STDPConfavreux2025STDPVariablespair STDP with rate termsexact decay, event-driven
STDPWeightDependentSTDPVariablespair STDP, soft boundsexact decay, event-driven
STDPTripletSTDPTripletVariablestriplet STDPexact decay, event-driven
STDPMexicanHatSTDPVariablesMexican-hat kernelEuler
STDPSymmetricSTDPStructuredVariablessymmetric difference of exponentialsEuler
STDPAntiSymmetricSTDPStructuredVariablesantisymmetric exponentialsEuler
iSTDPRateiSTDPVariablesinhibitory STDP, target rateEuler
iSTDPPotentialiSTDPVariablesinhibitory STDP, membrane potentialEuler
vSTDPParametervSTDPVariablesvoltage-based STDP, event-driven (lazy weights)Euler
vSTDPDenseParametervSTDPDenseVariablesvoltage-based STDP, clock-drivenEuler
MarkramSTPParameter (= MarkramSTPParameterEvent)MarkramSTPVariablesshort-term plasticityexact, event-driven
MarkramSTPParameterHetMarkramSTPVariablesshort-term plasticity, per-neuron parametersexact, event-driven
MarkramSTPParameterTimestepMarkramSTPVariablesshort-term plasticityEuler
NoLTP, NoSTPNoVariablesno plasticity (defaults)-

Synapse $s$ connects $j$ to $i$ with weight $w_{ij}$ (W[s]); traces jump by 1 at a spike. Read lazily stored traces and weights with trace_values and plasticity_value.

STDPGerstner

Additive pair STDP (Gerstner et al. 1996), traces $x_{pre}$, $x_{post}$; update order: Pair and triplet STDP.

\[\begin{aligned} \text{presynaptic spike of } j:&\quad w_{ij} \mathrel{+}= A_{post}\, x_{post,i} \\ \text{postsynaptic spike of } i:&\quad w_{ij} \mathrel{+}= A_{pre}\, x_{pre,j} \end{aligned}\]

For a single pair with $Δt = t_{post} - t_{pre}$:

\[Δw = \begin{cases} A_{pre}\, e^{-Δt/τ_{pre}} & Δt > 0 \\ A_{post}\, e^{Δt/τ_{post}} & Δt < 0 \end{cases}\]

Amplitudes are signed: A_pre > 0 potentiates, A_post < 0 depresses (default).

FieldDefaultUnitsMeaning
A_post-1e-4weightchange per unit $x_{post}$ at a presynaptic spike (< 0: LTD)
A_pre1e-4weightchange per unit $x_{pre}$ at a postsynaptic spike (> 0: LTP)
τpre20msmspresynaptic trace time constant
τpost20msmspostsynaptic trace time constant
Wmax30pFweightupper bound
Wmin0pFweightlower bound
using SpikingNeuralNetworks
SNN.@load_units
pre = SNN.Poisson(N = 100, param = SNN.PoissonParameter(10Hz))
post = SNN.IF(N = 10)
rule = SNN.STDPGerstner(A_pre = 1e-2, A_post = -1.05e-2, τpre = 16.8ms, τpost = 33.7ms, Wmax = 50)
syn = SNN.SpikingSynapse(pre, post, :ge; conn = (p = 0.1, μ = 10.0), LTPParam = rule)
SNN.train!(model = SNN.compose(; pre, post, syn), duration = 1s)

STDPConfavreux2025

Pair STDP with constant rate terms (Confavreux et al. 2025).

\[\begin{aligned} \text{presynaptic spike of } j:&\quad w_{ij} \mathrel{+}= η\,(κ\, x_{post,i} + α) \\ \text{postsynaptic spike of } i:&\quad w_{ij} \mathrel{+}= η\,(γ\, x_{pre,j} + β) \end{aligned}\]

The signs are carried by κ, γ, α, β.

FieldDefaultUnitsMeaning
η0.01weightlearning rate
α0-constant term at each presynaptic spike
β0-constant term at each postsynaptic spike
κ1-weight of the post-before-pre term (read at a pre spike)
γ1-weight of the pre-before-post term (read at a post spike)
τpre, τpost20msmstrace time constants
Wmin, Wmax0pF, 30pFweightbounds

STDPWeightDependent

Soft-bound pair STDP (Gütig et al. 2003). With $\tilde W = W_{max} - W_{min}$:

\[\begin{aligned} \text{presynaptic spike (LTD)}:&\quad w \mathrel{-}= η\, α\, \tilde W^{1-μ_-}\, (w - W_{min})^{μ_-}\, x_{post} \\ \text{postsynaptic spike (LTP)}:&\quad w \mathrel{+}= η\, \tilde W^{1-μ_+}\, (W_{max} - w)^{μ_+}\, x_{pre} \end{aligned}\]

μ = 0 is additive STDP with hard bounds, μ = 1 multiplicative STDP.

FieldDefaultUnitsMeaning
η1e-3-relative learning rate
α1-LTD/LTP asymmetry
μ_plus1-LTP weight-dependence exponent
μ_minus1-LTD weight-dependence exponent
τpre, τpost20msmstrace time constants
Wmax, Wmin30pF, 0pFweightbounds

STDPTriplet

All-to-all triplet STDP (Pfister and Gerstner 2006), traces $r_1$, $r_2$ (pre), $o_1$, $o_2$ (post):

\[\begin{aligned} \text{presynaptic spike of } j:&\quad w_{ij} \mathrel{-}= o_{1,i}\,(A_2^- + A_3^-\, r_{2,j}) \\ \text{postsynaptic spike of } i:&\quad w_{ij} \mathrel{+}= r_{1,j}\,(A_2^+ + A_3^+\, o_{2,i}) \end{aligned}\]

Defaults: minimal all-to-all model (Table 4 of Pfister and Gerstner 2006).

FieldDefaultUnitsMeaning
A2_plus5.3e-3weightpair LTP amplitude
A3_plus8e-3weighttriplet LTP amplitude
A2_minus3.5e-3weightpair LTD amplitude
A3_minus0weighttriplet LTD amplitude
τ_plus16.8msmspresynaptic trace $r_1$
τ_minus33.7msmspostsynaptic trace $o_1$
τ_x946msmspresynaptic trace $r_2$
τ_y40msmspostsynaptic trace $o_2$
Wmax, Wmin30pF, 0pFweightbounds

STDPMexicanHat

$Δw = A\,(1 - z)\,e^{-z/\sqrt 2}$ with $z = [\ln(x_{pre}/x_{post})]^2 ≈ (Δt/τ)^2$: potentiation for $|Δt| < τ$, depression beyond.

FieldDefaultUnitsMeaning
A0.1weightamplitude
τ20msmstrace time constant
Wmax, Wmin30pF, 0pFweightbounds

STDPSymmetric and STDPAntiSymmetric

Structured rules of Festa, Cusseddu and Gjorgjieva (2024); kernel integral $A_x - A_y$, plus constant terms αpre, αpost per spike.

Symmetric kernel ($Δt = t_{post} - t_{pre}$):

\[Δw(Δt) = \frac{A_x}{2τ_x} e^{-|Δt|/τ_x} - \frac{A_y}{2τ_y} e^{-|Δt|/τ_y}\]

Antisymmetric kernel:

\[Δw(Δt) = \begin{cases} \dfrac{A_x}{τ_x} e^{-Δt/τ_x} & Δt > 0 \\[1ex] -\dfrac{A_y}{τ_y} e^{Δt/τ_y} & Δt < 0 \end{cases}\]

FieldSTDPSymmetricSTDPAntiSymmetricUnitsMeaning
A_x3e-23e-2weight·msnarrow / potentiation amplitude
A_y3e-23e-2weight·mswide / depression amplitude
τ_x50ms50msmstime constant of the $x$ traces
τ_y500ms50msmstime constant of the $y$ traces
αpre, αpost0pF0pFweightconstant change per pre / post spike
Wmax, Wmin30pF, 0pF30pF, 0pFweightbounds
using SpikingNeuralNetworks
SNN.@load_units
pre = SNN.Poisson(N = 100, param = SNN.PoissonParameter(10Hz))
post = SNN.IF(N = 10)
syn = SNN.SpikingSynapse(pre, post, :ge; conn = (p = 0.1, μ = 1.0),
                         LTPParam = SNN.STDPAntiSymmetric(A_x = 1e-2, A_y = 1e-2))
SNN.train!(model = SNN.compose(; pre, post, syn), duration = 500ms)

Inhibitory STDP: iSTDPRate, iSTDPPotential

Vogels et al. (2011), Euler-integrated traces.

iSTDPRate (target rate $r$, $α = 2 r τ_y$):

\[Δw_{ij} = η\,(y_i - α) \ \text{at a presynaptic spike}, \qquad Δw_{ij} = η\, x_j \ \text{at a postsynaptic spike}\]

iSTDPPotential uses $τ_y\, dy_i/dt = V_i - y_i$ and the target potential $v_0$: $Δw_{ij} = η (y_i - v_0)$ at a presynaptic spike, $η x_j$ at a postsynaptic spike.

FieldiSTDPRateiSTDPPotentialUnitsMeaning
η0.01pA0.001pAweightlearning rate
r3Hz-1/mstarget postsynaptic rate
v0--50mVmVreference potential
τy50ms200msmstrace time constant
Wmax243pF243pFweightupper bound
Wmin0.01pF0.01pFweightlower bound

Results of iSTDPRate with SNNModels 1.5.0 to 1.8.1 are wrong; see the V2 changelog.

using SpikingNeuralNetworks
SNN.@load_units
E = SNN.IF(N = 80)
I = SNN.Poisson(N = 20, param = SNN.PoissonParameter(20Hz))
IE = SNN.SpikingSynapse(I, E, :gi; conn = (p = 0.2, μ = 5.0), LTPParam = SNN.iSTDPRate(r = 5Hz))
SNN.train!(model = SNN.compose(; E, I, IE), duration = 500ms)

vSTDPParameter and vSTDPDenseParameter

Clopath et al. (2010). vSTDPParameter is event-driven (read W with plasticity_value(syn, :W)); vSTDPDenseParameter is clock-driven (the vSTDPParameter of SNNModels 1.9). $V_i$ is the postsynaptic potential, $u_i$, $v_i$ its low-pass filters, $[z]_+ = \max(z, 0)$:

\[\begin{aligned} τ_x \frac{dx_j}{dt} &= -x_j + \sum_k δ(t - t_j^k), \qquad τ_u \frac{du_i}{dt} = V_i - u_i, \qquad τ_v \frac{dv_i}{dt} = V_i - v_i \\ Δw_{ij} &= -A_{LTD}\,[u_i - θ_{LTD}]_+ \quad \text{at each presynaptic spike} \\ \frac{dw_{ij}}{dt} &= A_{LTP}\, x_j\,[v_i - θ_{LTD}]_+\,[V_i - θ_{LTP}]_+ \end{aligned}\]

FieldDefaultUnitsMeaning
A_LTD8e-4weight/mVLTD amplitude
A_LTP1.4e-3weight/mV²LTP amplitude
θ_LTD-70mVmVLTD threshold (also applied to $v$ in the LTP term)
θ_LTP-49mVmVLTP threshold on $V$
τu20msmsLTD filter time constant
τv7msmsLTP filter time constant
τx15msmspresynaptic trace time constant
Wmax, Wmin30pF, 0.1pFweightbounds
using SpikingNeuralNetworks
SNN.@load_units
E = SNN.Poisson(N = 50, param = SNN.PoissonParameter(20Hz))
P = SNN.AdEx(N = 10, param = SNN.AdExParameter())
syn = SNN.SpikingSynapse(E, P, :ge; conn = (p = 0.2, μ = 1.0), LTPParam = SNN.vSTDPParameter())
SNN.train!(model = SNN.compose(; E, P, syn), duration = 200ms)
SNN.plasticity_value(syn, :W)   # current weights (syn.W is lazy for the event-driven rule)

Short-term plasticity: Tsodyks-Markram

Presynaptic utilisation $u_j$ and resources $x_j$ set the efficacy $ρ_s = u_j x_j$ (Tsodyks and Markram 1997; Mongillo, Barak and Tsodyks 2008). Between spikes

\[\frac{du}{dt} = \frac{U - u}{τ_F}, \qquad \frac{dx}{dt} = \frac{1 - x}{τ_D}.\]

At a presynaptic spike, $Δ$ after the previous one (MarkramSTPParameter, MarkramSTPParameterHet, exact):

\[\begin{aligned} u^- &= U - (U - u)\,e^{-Δ/τ_F}, & x^- &= 1 - (1 - x)\,e^{-Δ/τ_D}, \\ ρ &= u^- x^-, & & \\ u &\leftarrow u^- + U\,(1 - u^-), & x &\leftarrow x^- - u\,x^- . \end{aligned}\]

MarkramSTPParameterHet takes per-neuron vectors U, τF, τD; MarkramSTPParameterTimestep is clock-driven (Euler).

FieldDefaultUnitsMeaning
τD200msmsrecovery (depression) time constant
τF1500msmsfacilitation time constant
U0.2-baseline utilisation
Wmax, Wmin1pF, 0pFweightnot used by the update
using SpikingNeuralNetworks
SNN.@load_units
E = SNN.Poisson(N = 50, param = SNN.PoissonParameter(20Hz))
P = SNN.IF(N = 10)
syn = SNN.SpikingSynapse(E, P, :ge; conn = (p = 0.2, μ = 1.0),
                         STPParam = SNN.MarkramSTPParameter(τD = 200ms, τF = 1500ms, U = 0.2))
SNN.train!(model = SNN.compose(; E, P, syn), duration = 500ms)
extrema(syn.ρ)

API

Common interface

SNNModels.NoSTDP — Constant
NoSTDP

Non-constant global holding NoLTP(), kept for backward compatibility. Use NoLTP().

source
SNNModels.LTP — Type
LTP()

Empty marker type, subtype of LTPParameter. No plasticityvariables or plasticity! method is defined for it, so it cannot be used as a rule; use a concrete rule or NoLTP().

source
SNNModels.LTPParameter — Type
LTPParameter <: PlasticityParameter

Abstract supertype of the long-term plasticity rules (passed to SpikingSynapse with the keyword LTPParam): the pair/triplet STDP rules (STDPParameter subtypes), the inhibitory rules (iSTDPParameter subtypes), the voltage-based rules vSTDPParameter (event-driven) and vSTDPDenseParameter (clock-driven), and NoLTP (no plasticity, default).

source
SNNModels.NoLTP — Type
NoLTP(; active = [false])

Null long-term plasticity rule, the default LTPParam of SpikingSynapse. Its variables are NoVariables(), whose active flag is false, so train! skips the LTP update. NoSTDP is a (non-constant) global holding an instance NoLTP().

source
SNNModels.NoSTP — Type
NoSTP(; active = [false])

Null short-term plasticity rule, the default STPParam of SpikingSynapse. The efficacy ρ then stays at its initial value 1 for every synapse.

source
SNNModels.NoVariables — Type
NoVariables(; active = [false])

Empty plasticity state returned by plasticityvariables(::NoLTP, ...) and plasticityvariables(::NoSTP, ...). active = [false] disables the rule.

source
SNNModels.STDPParameter — Type
STDPParameter <: LTPParameter

Abstract supertype of the spike-timing-dependent rules: STDPGerstner, STDPConfavreux2025, STDPMexicanHat, STDPWeightDependent, STDPTriplet, the structured rules (STDPSymmetric, STDPAntiSymmetric) and the inhibitory rules (iSTDPParameter). The default state of an STDPParameter is STDPVariables; subtypes with other state define their own plasticityvariables method.

source
SNNModels.STP — Type
STP()

Empty marker type, subtype of STPParameter. No plasticityvariables or plasticity! method is defined for it, so it cannot be used as a rule; use a concrete rule or NoSTP().

source
SNNModels.STPParameter — Type
STPParameter <: PlasticityParameter

Abstract supertype of the short-term plasticity rules (passed to SpikingSynapse with the keyword STPParam): the Markram/Tsodyks rules (MarkramSTPParameter, MarkramSTPParameterTimestep, MarkramSTPParameterHet) and NoSTP (default). STP rules modulate the per-synapse efficacy ρ, so that a presynaptic spike adds W[s] * ρ[s] to the target conductance.

source
SNNModels.change_plasticity! — Method
change_plasticity!(syn; LTP = nothing, STP = nothing)

Replace the long-term rule (LTP, an LTPParameter) and/or the short-term rule (STP, an STPParameter) of the sparse synapse syn by a rule of the same type, re-creating the corresponding state (traces and STP variables are reset). Alias of update_plasticity!: a rule of another type is an ArgumentError, use with_plasticity instead.

source
SNNModels.current_weights — Method
current_weights(c::AbstractSparseSynapse)
current_weights(c, vars::PlasticityVariables)

Implementation of plasticity_value(c, :W) (not exported). A rule listing :W in lazy_variables defines the two-argument method; the default returns c.W and throws for such a rule.

source
SNNModels.lazy_variables — Method
lazy_variables(vars::PlasticityVariables) -> Tuple{Vararg{Symbol}}

Names of the fields of vars stored in a form other than their value, and :W if the rule defers weight updates. Empty by default. Each name needs a current_value(vars, param, key, t) method (for :W: current_weights(c, vars) and sync_weights!(c, vars)); the generic methods throw an ArgumentError for a listed name.

source
SNNModels.needs_transpose — Method
needs_transpose(rule::PlasticityParameter)

Whether the rule reads the transposed index arrays J/index of a SpikingSynapse (the inputs of a postsynaptic neuron). true by default (also for user-defined rules); false for NoLTP, NoSTP, the Markram STP rules and vSTDP.

source
SNNModels.plasticity! — Method
plasticity!(c::AbstractSparseSynapse, param::AbstractSpikingSynapseParameter, dt::AbstractFloat, T::Time)

Apply one step of the plasticity rules of the sparse synapse c: first the short-term rule plasticity!(c, c.STPParam, c.STPVars, dt, T) if any(c.STPVars.active), then the long-term rule plasticity!(c, c.LTPParam, c.LTPVars, dt, T) if any(c.LTPVars.active).

It is called by train! after forward! of the connection, at every step; sim! never calls it. The rule-specific methods plasticity!(c, param::PlasticityParameter, variables::PlasticityVariables, dt, T) update c.W (LTP) or c.ρ (STP) in place; see the docstring of each rule for its equations.

source
SNNModels.plasticity_value — Method
plasticity_value(obj, group::Symbol, key::Symbol, T)
plasticity_value(syn::AbstractSparseSynapse, :W, T = 0)

Value of the plasticity variable key of getfield(obj, group) (group = :LTPVars or :STPVars) at time T (a Time or a number in ms), without changing the state. Lazily stored fields (see lazy_variables) are converted through current_value; any other field is returned as it is. Used by monitor!.

plasticity_value(syn, :W) is the weight vector after the last step: syn.W, or, for a rule that defers weight updates (vSTDPParameter), a scratch vector with the pending updates applied, overwritten by the next call. Read weights through it, or call sync_traces! first, whenever such a rule may be active.

source
SNNModels.plasticityvariables — Method
plasticityvariables(param::PlasticityParameter, Npre, Npost)

Create the state (variables) of the plasticity rule param for a connection with Npre presynaptic and Npost postsynaptic neurons. Called by the SpikingSynapse constructor and by change_plasticity!. Returns NoVariables() for NoLTP/NoSTP, STDPVariables for the pair STDP rules, STDPTripletVariables for STDPTriplet, STDPStructuredVariables for STDPSymmetric/STDPAntiSymmetric, iSTDPVariables for the iSTDP rules, vSTDPVariables for vSTDPParameter, vSTDPDenseVariables for vSTDPDenseParameter and MarkramSTPVariables for the Markram STP rules. The element type of the state is float_type(param).

source
SNNModels.set_LTP! — Method
set_LTP!(c::AbstractConnection, state::Bool)

Activate (true) or deactivate (false) the long-term plasticity rule of a sparse synapse by setting c.LTPVars.active. A no-op for connections that are not AbstractSparseSynapse. Has an effect only under train! (sim! never runs plasticity).

source
SNNModels.set_STP! — Method
set_STP!(c::AbstractConnection, state::Bool)

Activate (true) or deactivate (false) the short-term plasticity rule of a sparse synapse by setting c.STPVars.active. A no-op for connections that are not AbstractSparseSynapse. Deactivation freezes ρ at its current value. Has an effect only under train!.

Example

using SpikingNeuralNetworks
SNN.@load_units
E = SNN.Poisson(N = 10, param = SNN.PoissonParameter(10Hz))
I = SNN.IF(N = 10)
syn = SNN.SpikingSynapse(E, I, :ge; conn = (p = 0.5, μ = 1.0), STPParam = SNN.MarkramSTPParameter())
SNN.set_STP!(syn, false)
source
SNNModels.set_plasticity! — Method
set_plasticity!(c::AbstractSparseSynapse, param::LTPParameter, state::Bool)
set_plasticity!(c::AbstractSparseSynapse, param::STPParameter, state::Bool)

Switch the long-term (if param is an LTPParameter) or short-term (STPParameter) rule of c on (state = true) or off, by setting the active flag of c.LTPVars or c.STPVars. Only the type of param is used to choose the rule. For the variant that acts on any connection see set_plasticity!(synapse::AbstractConnection, bool).

source
SNNModels.sync_weights! — Method
sync_weights!(c::AbstractSparseSynapse)
sync_weights!(c, vars::PlasticityVariables)

Write the deferred weight updates into c.W (a no-op for the other rules); returns c. Not exported; called by sync_traces!(c). A rule listing :W in lazy_variables defines the two-argument method.

source
SNNModels.update_traces! — Method
update_traces!(c::AbstractSparseSynapse, param::AbstractSpikingSynapseParameter, dt::AbstractFloat, T::Time)

Pre-propagation part of the plasticity rules of c, called by train! at every step before forward! (never by sim!): update_traces!(c, c.STPParam, c.STPVars, dt, T) if the STP rule is active, then the same for the LTP rule. The fallback method for a generic rule does nothing; MarkramSTPParameter (event-driven) and MarkramSTPParameterHet use it to compute the efficacy ρ of the synapses of the neurons that spike in this step, so that the spike is transmitted with the updated efficacy.

source

Event-driven kernels (internal)

SNNModels._add_passes! — Method
_add_passes!(c, f_pre, f_post, spikes_pre, spikes_post, Wmin, Wmax)

_pre_spike_add!, _post_spike_add! and _clamp_touched! in this order (the rules that clamp after both passes), threaded like _stdp_passes!.

source
SNNModels._initial_clamp! — Method
_initial_clamp!(W, initialized, Wmin, Wmax)

Clamp all weights once, on the first plasticity step after the variables were created. The clock-driven implementation clamped every weight at every step; the event-driven one clamps only touched weights, so the one-off clamp keeps the two identical for initial weights outside [Wmin, Wmax].

source
SNNModels._post_spike_pass! — Method
_post_spike_pass!(f, W, rowptr, index, J, fireI, Wmin, Wmax)

For each postsynaptic spike i and each incoming synapse s = index[st] (pre j = J[s]): W[s] = clamp(W[s] + f(W[s], i, j), Wmin, Wmax).

source
SNNModels._pre_pass! — Method
_pre_pass!(c, f, spikes_pre, Wmin, Wmax)
_post_pass!(c, f, spikes_post, Wmin, Wmax)

One clamped pass alone (rules with trace updates between the two passes, e.g. iSTDPRate), threaded like _stdp_passes!.

source
SNNModels._pre_spike_pass! — Method
_pre_spike_pass!(f, W, colptr, I, spikes::AbstractVector{Int32}, Wmin, Wmax)

Same, for the index list of the neurons that fired.

source
SNNModels._pre_spike_pass! — Method
_pre_spike_pass!(f, W, colptr, I, fireJ, Wmin, Wmax)

For each presynaptic spike j and each outgoing synapse s (post i = I[s]): W[s] = clamp(W[s] + f(W[s], i, j), Wmin, Wmax).

source
SNNModels._spike_increment! — Function
_spike_increment!(x, last, fire, t, a = 1)

Add a to the trace of every neuron that fired this step and store its spike time.

source
SNNModels._stdp_passes! — Method
_stdp_passes!(c, f_pre, f_post, spikes_pre, spikes_post, Wmin, Wmax)

Clamped pre-spike pass, then clamped post-spike pass, threaded by postsynaptic range when there is enough work.

source

Pair STDP rules

SNNModels.STDPConfavreux2025 — Type
STDPConfavreux2025(; η = 0.01, α = 0, β = 0, κ = 1, γ = 1, τpre = 20ms, τpost = 20ms,
                     Wmin = 0pF, Wmax = 30pF)

Pair-based STDP with rate terms, event-driven (same traces and ordering as STDPGerstner, traces increment by 1 and are read before this step's spikes are added):

  • presynaptic spike of j, each target i: $w_{ij} \mathrel{+}= η (κ\, x_{post,i} + α)$
  • postsynaptic spike of i, each source j: $w_{ij} \mathrel{+}= η (γ\, x_{pre,j} + β)$

then clamping to [Wmin, Wmax]. For one pair with $Δt = t_{post} - t_{pre}$, the trace terms give $Δw = η γ e^{-Δt/τ_{pre}}$ for $Δt > 0$ and $Δw = η κ e^{Δt/τ_{post}}$ for $Δt < 0$; every presynaptic spike adds $η α$ and every postsynaptic spike $η β$.

Fields: η = 0.01 (learning rate), α = 0, β = 0 (rate terms applied at every presynaptic / postsynaptic spike respectively), κ = 1 (weight of the post-before-pre term, read at a presynaptic spike), γ = 1 (weight of the pre-before-post term, read at a postsynaptic spike), τpre = τpost = 20ms, Wmin = 0pF, Wmax = 30pF. Unlike STDPGerstner the sign of the trace terms is carried by κ, γ, α, β, not by a separate amplitude, and η multiplies both. With the defaults both pairings potentiate. Applied only under train!. State: STDPVariables.

Reference: named "Confavreux et al. 2025" in the code; the full reference is not given in the code.

Example

using SpikingNeuralNetworks
SNN.@load_units
pre = SNN.Poisson(N = 100, param = SNN.PoissonParameter(10Hz))
post = SNN.IF(N = 10)
rule = SNN.STDPConfavreux2025(η = 1e-3, κ = -1.0, γ = 1.0, α = -0.1)
syn = SNN.SpikingSynapse(pre, post, :ge; conn = (p = 0.1, μ = 1.0), LTPParam = rule)
SNN.train!(model = SNN.compose(; pre, post, syn), duration = 500ms)
source
SNNModels.STDPGerstner — Type
STDPGerstner(; A_post = -1e-4, A_pre = 1e-4, τpre = 20ms, τpost = 20ms, Wmax = 30pF, Wmin = 0pF)

Additive pair-based STDP with all-to-all spike interaction, event-driven (Gerstner, W., Kempter, R., van Hemmen, J. L., & Wagner, H. (1996). A neuronal learning rule for sub-millisecond temporal coding. Nature, 383(6595), 76–78. https://doi.org/10.1038/383076a0; implementation as Auryn STDPConnection).

Traces $x_{pre}$ (time constant τpre) and $x_{post}$ (τpost) jump by 1 at each spike and decay exponentially. Weight updates, with the traces read before this step's spikes are added:

  • presynaptic spike of j, for each target i: $w_{ij} \mathrel{+}= A_{post}\, x_{post,i}$
  • postsynaptic spike of i, for each source j: $w_{ij} \mathrel{+}= A_{pre}\, x_{pre,j}$

followed by clamping to [Wmin, Wmax]. For a single pair with $Δt = t_{post} - t_{pre}$: $Δw = A_{pre} e^{-Δt/τ_{pre}}$ if $Δt > 0$ and $Δw = A_{post} e^{Δt/τ_{post}}$ if $Δt < 0$ (0 if both spikes fall in the same step).

Sign convention: the amplitudes are signed and used as given. A_pre > 0 gives potentiation for pre-before-post, A_post < 0 gives depression for post-before-pre (classical Hebbian STDP, the default). Any sign combination is allowed (e.g. anti-Hebbian with A_pre < 0 < A_post).

Fields (type FT, Float32 by default; time in ms, weights in the units of W, e.g. pF):

  • A_post = -1e-4: weight change per unit x_post at a presynaptic spike (post-before-pre); < 0 is LTD.
  • A_pre = 1e-4: weight change per unit x_pre at a postsynaptic spike (pre-before-post); > 0 is LTP.
  • τpre = 20ms, τpost = 20ms: trace time constants.
  • Wmax = 30pF, Wmin = 0pF: weight bounds (use Inf/-Inf to disable).

Algorithm: event-driven, Auryn ordering (see STDP_kernels.jl). Per step: (1) pre spikes walk their outgoing synapses, (2) post spikes walk their incoming synapses, (3) the traces of the neurons that fired are incremented by 1, (4) the traces decay by exp(-dt/τ), lazily (see STDPVariables: the stored tpre, tpost are not the trace values). Same-step pre and post spikes do not interact; earlier history does. Only touched weights are clamped (all weights once at the first step).

Plasticity runs only under train!; sim! leaves the weights untouched.

Behaviour change in SNNModels 1.8.2

Up to SNNModels 1.8 the traces were incremented by A_pre/A_post and multiplied by them again, so the effective amplitudes were $A^2$ and the sign was lost (a negative A_post potentiated). Now the amplitude is applied once and the default A_post is -1e-4 (LTD). Parameter sets tuned against the old version must be rescaled: an old A = 5e-2 corresponds to a new amplitude of 2.5e-3.

Example

using SpikingNeuralNetworks
SNN.@load_units
pre = SNN.Poisson(N = 100, param = SNN.PoissonParameter(10Hz))
post = SNN.IF(N = 10)
rule = SNN.STDPGerstner(A_pre = 1e-2, A_post = -1.05e-2, τpre = 16.8ms, τpost = 33.7ms,
                        Wmin = 0, Wmax = 50)
syn = SNN.SpikingSynapse(pre, post, :ge; conn = (p = 0.1, μ = 10.0), LTPParam = rule)
SNN.train!(model = SNN.compose(; pre, post, syn), duration = 1s)   # not sim!
source
SNNModels.STDPMexicanHat — Type
STDPMexicanHat(; A = 0.1, τ = 20ms, Wmax = 30pF, Wmin = 0pF)

STDP with a Mexican-hat kernel: $Δw = A\, (1 - z)\, e^{-z/\sqrt{2}}$ with $z = \left[\ln(x_{pre}/x_{post})\right]^2$, where x_pre and x_post are the pre- and postsynaptic traces (same time constant τ). For a single pair, $\ln(x_{pre}/x_{post}) = -Δt/τ$ up to the Euler discretisation of the traces, so $z = (Δt/τ)^2$ and the kernel is the symmetric "Mexican hat" $(1 - z) e^{-z/\sqrt{2}}$ in $Δt$: potentiation for $|Δt| < τ$, depression beyond. The update is applied at every pre- and every postsynaptic spike of a synapse whose traces are both non-zero (a result NaN is replaced by 0).

Fields: A = 10e-2pA / mV (= 0.1, amplitude), τ = 20ms (trace time constant), Wmax = 30pF, Wmin = 0pF. State: STDPVariables. Reference not given in the code.

Pre spikes walk their outgoing synapses and post spikes their incoming ones (event-driven); only touched weights are clamped. The traces are Euler-integrated (per-step factor 1 - dt/τ) and stored lazily like those of STDPGerstner; the spikes of the step are added before the weight update, so same-step pre and post spikes interact. Applied only under train!.

Example

using SpikingNeuralNetworks
SNN.@load_units
pre = SNN.Poisson(N = 100, param = SNN.PoissonParameter(10Hz))
post = SNN.IF(N = 10)
syn = SNN.SpikingSynapse(pre, post, :ge; conn = (p = 0.1, μ = 1.0),
                         LTPParam = SNN.STDPMexicanHat(A = 1e-3))
SNN.train!(model = SNN.compose(; pre, post, syn), duration = 500ms)
source
SNNModels.STDPVariables — Type
STDPVariables(; Npre, Npost, tpre = zeros(Npre), tpost = zeros(Npost),
              last_pre = zeros(Npre), last_post = zeros(Npost), initialized = [false],
              active = [true], scale = [1.0, 1.0], decay = fill(NaN, 5))

Per-neuron state of the pair-based STDP rules.

The stored traces are not the trace values

The traces decay lazily (see STDP_kernels.jl): the trace of neuron k is tpre[k] * scale[1] (tpost[k] * scale[2]). Read values with trace_values, or call sync_traces! first; monitor!, getvariable and plasticity_value already return values.

  • tpre, tpost: stored presynaptic / postsynaptic traces.
  • last_pre, last_post: time of the last spike (informational, not used in updates).
  • initialized: set after the one-off clamp of all weights on the first step.
  • active: the rule runs only if any(active) (see set_LTP!).
  • scale: factors of the stored tpre, tpost (Float64, in [1e-6, 1]).
  • decay: cache of dt, τpre, τpost and their one-step decay factors.

Created by plasticityvariables(::STDPParameter, Npre, Npost).

source
SNNModels.sync_traces! — Method
sync_traces!(vars)
sync_traces!(c::AbstractSparseSynapse)

Make the lazily stored traces of the long-term rule hold their values (multiply by scale, reset it to 1), so that syn.LTPVars.tpre etc. can be read directly. sync_traces!(syn) also writes deferred weight updates into syn.W (vSTDPParameter). A no-op for variables without lazy traces. Returns its argument.

The simulation does not need it. A sync rounds the traces once, so a run that syncs is not bit-identical to one that does not; trace_values reads without changing the state. The event-driven Markram u, x are not synced: read them with plasticity_value.

Example

using SpikingNeuralNetworks
SNN.@load_units
pre = SNN.Poisson(N = 10, param = SNN.PoissonParameter(20Hz))
post = SNN.IF(N = 5)
syn = SNN.SpikingSynapse(pre, post, :ge; conn = (p = 1.0, μ = 1.0), LTPParam = SNN.STDPGerstner())
SNN.train!(model = SNN.compose(; pre, post, syn), duration = 100ms)
SNN.sync_traces!(syn)
syn.LTPVars.tpre   # presynaptic traces at the end of the run
source
SNNModels.trace_values — Method
trace_values(vars, key::Symbol)
trace_values(c::AbstractSparseSynapse, key::Symbol)   # key = :W: the synaptic weights

Values of the trace key of the long-term rule (key = :W: the weights, as plasticity_value(c, :W)). For a lazily decaying trace a new vector, state unchanged; any other field is returned as it is.

source
SNNModels.STDPWeightDependent — Type
STDPWeightDependent(; η = 1e-3, α = 1, μ_plus = 1, μ_minus = 1, τpre = 20ms, τpost = 20ms,
                      Wmax = 30pF, Wmin = 0pF)

Weight-dependent (soft-bound) pair STDP, all-to-all interaction, event-driven (Gütig, R., Aharonov, R., Rotter, S., & Sompolinsky, H. (2003). Learning input correlations through nonlinear temporally asymmetric Hebbian plasticity. J. Neurosci., 23(9), 3697–3714; Morrison, Diesmann & Gerstner (2008), Biol. Cybern. 98, 459–478; implementation as Auryn STDPwdConnection, Zenke & Gerstner 2014).

Traces $x_{pre}$ (τpre) and $x_{post}$ (τpost) jump by 1 at each spike and decay exponentially; they are read before this step's spikes are added. With $\tilde w = w - W_{min}$ and $\tilde W = W_{max} - W_{min}$:

  • presynaptic spike (LTD): $w \mathrel{-}= η\, α\, \tilde W^{1-μ_-}\, \tilde w^{μ_-}\, x_{post}$
  • postsynaptic spike (LTP): $w \mathrel{+}= η\, \tilde W^{1-μ_+}\, (W_{max} - w)^{μ_+}\, x_{pre}$

followed by clamping to [Wmin, Wmax]. η is a relative learning rate (the factors $\tilde W^{1-μ}$ make the update scale with the weight range): μ = 0 is additive STDP with hard bounds and amplitudes $η \tilde W$ (LTP) and $-η α \tilde W$ (LTD); μ = 1 is multiplicative STDP, LTD $= -η α (w - W_{min}) x_{post}$ and LTP $= η (W_{max} - w) x_{pre}$. With Wmin = 0 this is exactly Auryn's STDPwdConnection (learning_rate = η, param_alpha = α, param_mu_plus, param_mu_minus).

Fields: η = 1e-3 (relative learning rate), α = 1 (LTD/LTP asymmetry), μ_plus = 1, μ_minus = 1 (weight-dependence exponents), τpre = τpost = 20ms, Wmax = 30pF, Wmin = 0pF. State: STDPVariables. Event-driven with the ordering of STDP_kernels.jl, applied only under train!.

Example

using SpikingNeuralNetworks
SNN.@load_units
pre = SNN.Poisson(N = 100, param = SNN.PoissonParameter(10Hz))
post = SNN.IF(N = 10)
rule = SNN.STDPWeightDependent(η = 1e-3, α = 1.05, μ_plus = 0.0, μ_minus = 1.0)
syn = SNN.SpikingSynapse(pre, post, :ge; conn = (p = 0.1, μ = 10.0), LTPParam = rule)
SNN.train!(model = SNN.compose(; pre, post, syn), duration = 500ms)
source

Triplet STDP

SNNModels.STDPTriplet — Type
STDPTriplet(; A2_plus = 5.3e-3, A3_plus = 8e-3, A2_minus = 3.5e-3, A3_minus = 0,
              τ_plus = 16.8ms, τ_minus = 33.7ms, τ_x = 946ms, τ_y = 40ms,
              Wmax = 30pF, Wmin = 0pF)

Triplet STDP, all-to-all interaction, event-driven (Pfister, J.-P., & Gerstner, W. (2006). Triplets of spikes in a model of spike timing-dependent plasticity. J. Neurosci., 26(38), 9673–9682. https://doi.org/10.1523/JNEUROSCI.1425-06.2006; implementation as Auryn MinimalTripletConnection / TripletConnection).

Presynaptic traces $r_1$ (τ_plus), $r_2$ (τ_x); postsynaptic traces $o_1$ (τ_minus), $o_2$ (τ_y). All jump by 1 at a spike and decay exponentially. Weight updates (amplitudes positive, signs explicit), with every trace read before this step's spikes are added (the $t - ε$ of the paper):

  • presynaptic spike of j, for each target i: $w_{ij} \mathrel{-}= o_{1,i} (A_2^- + A_3^- r_{2,j})$
  • postsynaptic spike of i, for each source j: $w_{ij} \mathrel{+}= r_{1,j} (A_2^+ + A_3^+ o_{2,i})$

followed by clamping to [Wmin, Wmax].

Defaults: Table 4 of Pfister & Gerstner (2006), hippocampal culture data set, all-to-all minimal model (A2plus = 5.3e-3, A3plus = 8e-3, A2minus = 3.5e-3, A3minus = 0, τy = 40 ms; τplus = 16.8 ms and τminus = 33.7 ms from Bi & Poo 2001). These equal Auryn's MinimalTripletConnection with eta = 1. With `A3minus = 0,τ_xis unused; its default (946 ms) is the all-to-all full-model value of Table 4. Weights are in the same units asW`; rescale the amplitudes to the weight scale.

Fields: A2_plus, A3_plus, A2_minus, A3_minus (amplitudes, all used with the signs shown above), τ_plus, τ_minus, τ_x, τ_y (trace time constants, ms), Wmax = 30pF, Wmin = 0pF. State: STDPTripletVariables. Event-driven with the ordering of STDP_kernels.jl (same-step pre/post spikes do not interact), applied only under train!.

Example

using SpikingNeuralNetworks
SNN.@load_units
pre = SNN.Poisson(N = 100, param = SNN.PoissonParameter(10Hz))
post = SNN.IF(N = 10)
rule = SNN.STDPTriplet(A2_plus = 5.3e-3 * 10, A3_plus = 8e-3 * 10, A2_minus = 3.5e-3 * 10)
syn = SNN.SpikingSynapse(pre, post, :ge; conn = (p = 0.1, μ = 10.0), LTPParam = rule)
SNN.train!(model = SNN.compose(; pre, post, syn), duration = 500ms)
source
SNNModels.STDPTripletVariables — Type
STDPTripletVariables(; Npre, Npost, r1 = zeros(Npre), r2 = zeros(Npre), o1 = zeros(Npost),
                     o2 = zeros(Npost), last_pre = zeros(Npre), last_post = zeros(Npost),
                     initialized = [false], active = [true], scale = ones(4),
                     decay = fill(NaN, 9))

Traces of STDPTriplet: r1, r2 (presynaptic, length Npre), o1, o2 (postsynaptic, length Npost); last spike times last_pre, last_post (informational); initialized (one-off clamp done); active (the rule runs only if any(active)).

The stored traces are not the trace values

As for STDPVariables: the value of r1, r2, o1, o2 is the stored vector times scale[1:4]. Read values with trace_values or call sync_traces! first.

decay caches dt, the time constants and their decay factors. Created by plasticityvariables(::STDPTriplet, Npre, Npost).

source

Structured STDP

SNNModels.STDPAntiSymmetric — Type
STDPAntiSymmetric(; A_y = 3e-2, A_x = 3e-2, τ_x = 50ms, τ_y = 50ms, αpre = 0pF, αpost = 0pF,
                    Wmax = 30pF, Wmin = 0pF)

Antisymmetric (Hebbian, pair-based) STDP rule with normalised exponential lobes, as used by Festa, Cusseddu and Gjorgjieva (2024).

Equations

For one pair with $Δt = t_{post} - t_{pre}$:

\[Δw(Δt) = \begin{cases} \dfrac{A_x}{τ_x} e^{-Δt/τ_x} & Δt > 0 \\[1ex] -\dfrac{A_y}{τ_y} e^{Δt/τ_y} & Δt < 0 \end{cases}\]

with integral $A_x - A_y$ (zero with the defaults); in addition every presynaptic spike adds αpre and every postsynaptic spike αpost.

Implementation: a presynaptic trace $r_{x,j}$ ($τ_x$) and a postsynaptic trace $o_{y,i}$ ($τ_y$), both jumping by 1 at a spike:

  • presynaptic spike of j, each target i: $w_{ij} \mathrel{+}= α_{pre} - \frac{A_y}{τ_y} o_{y,i}$
  • postsynaptic spike of i, each source j: $w_{ij} \mathrel{+}= α_{post} + \frac{A_x}{τ_x} r_{x,j}$

Integration

As for STDPSymmetric: pre pass, post pass, Euler decay and +1 of the traces, clamp of the touched weights. Only under train!.

Fields

  • A_y::FT = 3e-2: depression amplitude (post-before-pre).
  • A_x::FT = 3e-2: potentiation amplitude (pre-before-post).
  • τ_x::FT = 50ms, τ_y::FT = 50ms: time constants of the pre and post traces.
  • αpre::FT = 0pF, αpost::FT = 0pF: constant change at each pre / post spike.
  • Wmax::FT = 30pF, Wmin::FT = 0pF: weight bounds.

References

Festa, D., Cusseddu, C. & Gjorgjieva, J., "Structured stabilization in recurrent neural circuits through inhibitory synaptic plasticity" (2024), as cited in the code.

source
SNNModels.STDPStructuredVariables — Type
STDPStructuredVariables(; Npre, Npost, to_x = zeros(Npost), to_y = zeros(Npost),
                        tr_x = zeros(Npre), tr_y = zeros(Npre), initialized = [false],
                        active = [true])

Traces of STDPSymmetric / STDPAntiSymmetric: to_x, to_y are postsynaptic traces (length Npost, time constants τ_x, τ_y), tr_x, tr_y presynaptic traces (length Npre). STDPAntiSymmetric uses only tr_x and to_y. initialized marks the one-off clamp of all weights; active enables the rule.

The stored traces are not the trace values

As for STDPVariables: the value of to_x, to_y, tr_x, tr_y is the stored vector times scale[1:4]. Read values with trace_values or call sync_traces! first.

source
SNNModels.STDPSymmetric — Type
STDPSymmetric(; A_x = 3e-2, A_y = 3e-2, τ_x = 50ms, τ_y = 500ms, αpre = 0pF, αpost = 0pF,
                Wmax = 30pF, Wmin = 0pF)

Symmetric STDP rule with a difference-of-exponentials kernel, as used for structured inhibitory plasticity by Festa, Cusseddu and Gjorgjieva (2024).

Equations

For one pair with $Δt = t_{post} - t_{pre}$:

\[Δw(Δt) = \frac{A_x}{2τ_x} e^{-|Δt|/τ_x} - \frac{A_y}{2τ_y} e^{-|Δt|/τ_y},\]

whose integral over $Δt$ is $A_x - A_y$ (zero with the defaults). With $τ_x < τ_y$ the kernel potentiates near-coincident spikes and depresses spikes farther apart. In addition every presynaptic spike adds αpre and every postsynaptic spike αpost.

Implementation: each neuron has two traces (time constants $τ_x$ and $τ_y$) that jump by 1 at a spike:

  • presynaptic spike of j, each target i: $w_{ij} \mathrel{+}= α_{pre} + \frac{A_x}{2τ_x} o_{x,i} - \frac{A_y}{2τ_y} o_{y,i}$
  • postsynaptic spike of i, each source j: $w_{ij} \mathrel{+}= α_{post} + \frac{A_x}{2τ_x} r_{x,j} - \frac{A_y}{2τ_y} r_{y,j}$

Integration

plasticity! (only under train!): (1) pre-spike pass, (2) post-spike pass, both reading the traces before this step's spikes are added; (3) forward-Euler decay of all traces (factor 1 - dt/τ), then +1 for the neurons that fired (stored lazily, see STDPStructuredVariables); (4) clamp to [Wmin, Wmax] of the touched weights (all weights once at the first step).

Fields

  • A_x::FT = 3e-2: amplitude of the narrow (potentiating) kernel.
  • A_y::FT = 3e-2: amplitude of the wide (depressing) kernel.
  • τ_x::FT = 50ms, τ_y::FT = 500ms: kernel time constants.
  • αpre::FT = 0pF, αpost::FT = 0pF: constant change at each pre / post spike.
  • Wmax::FT = 30pF, Wmin::FT = 0pF: weight bounds.

References

Festa, D., Cusseddu, C. & Gjorgjieva, J., "Structured stabilization in recurrent neural circuits through inhibitory synaptic plasticity" (2024), as cited in the code.

Example

using SpikingNeuralNetworks
SNN.@load_units
pre = SNN.Poisson(N = 100, param = SNN.PoissonParameter(10Hz))
post = SNN.IF(N = 10)
syn = SNN.SpikingSynapse(pre, post, :ge; conn = (p = 0.1, μ = 1.0),
                         LTPParam = SNN.STDPSymmetric(A_x = 1e-2, A_y = 1e-2))
SNN.train!(model = SNN.compose(; pre, post, syn), duration = 500ms)
source

Inhibitory STDP

SNNModels.iSTDPParameter — Type
iSTDPParameter <: STDPParameter

Abstract supertype of the inhibitory STDP rules of Vogels et al. (2011): iSTDPRate and iSTDPPotential. All of them use iSTDPVariables and Euler-integrated (not exact-decay) traces. See the notes on iSTDPRate.

source
SNNModels.iSTDPPotential — Type
iSTDPPotential(; η = 0.001pA, v0 = -50mV, τy = 200ms, Wmax = 243pF, Wmin = 0.01pF)

Inhibitory STDP in which the postsynaptic trace follows the membrane potential instead of the spike train (a variant of the Vogels et al. 2011 rule, with tpost low-pass filtering v_post). The rule increases inhibition onto neurons whose filtered potential is above v0 and decreases it otherwise. Reference for the variant: not given in the code.

Equations

\[τ_y \frac{dx_j}{dt} = -x_j + τ_y \sum_k δ(t - t_j^k), \qquad τ_y \frac{dy_i}{dt} = -(y_i - V_i),\]

\[Δw_{ij} = η\,(y_i - v_0) \;\text{at a presynaptic spike of } j, \qquad Δw_{ij} = η\, x_j \;\text{at a postsynaptic spike of } i,\]

with $V_i$ the postsynaptic potential (v_post) and clamping to [Wmin, Wmax]. At the first plasticity! call the trace tpost is set to the postsynaptic potential. (Up to SNNModels 1.8.4 it started at 0 mV, so for the first few τy it was above v0 whatever the potential, which potentiated inhibition at the start of every simulation.)

Fields: η = 0.001pA (learning rate), v0 = -50mV (reference potential), τy = 200ms (trace time constant), Wmax = 243pF, Wmin = 0.01pF.

Algorithm (per step; tpre is an Euler-integrated spike trace, tpost an Euler-integrated trace of v_post):

  • presynaptic spike of j, every outgoing synapse s (post i = I[s]): W[s] += η * (tpost[i] - v0).
  • postsynaptic spike of i, every incoming synapse s (pre j = J[s]): W[s] += η * tpre[j].
  • every weight touched is clamped to [Wmin, Wmax].

Plasticity is applied only under train!. This rule was not affected by the iSTDPRate bug fixed in SNNModels 1.8.2 (its postsynaptic loop never used @turbo); it now uses the same plain @simd loops.

source
SNNModels.iSTDPRate — Type
iSTDPRate(; η = 0.01pA, r = 3Hz, τy = 50ms, Wmax = 243pF, Wmin = 0.01pF)

Inhibitory STDP with a target postsynaptic rate (Vogels, T. P., Sprekeler, H., Zenke, F., Clopath, C., & Gerstner, W. (2011). Inhibitory plasticity balances excitation and inhibition in sensory pathways and memory networks. Science, 334(6062), 1569-1573. https://doi.org/10.1126/science.1211095).

Equations

Traces $x_j$ (presynaptic) and $y_i$ (postsynaptic) jump by 1 at a spike and decay with time constant $τ_y$. With $α = 2 r τ_y$:

\[Δw_{ij} = η\,(y_i - α) \;\text{at a presynaptic spike of } j, \qquad Δw_{ij} = η\, x_j \;\text{at a postsynaptic spike of } i,\]

then $w_{ij}$ is clamped to [Wmin, Wmax]. For uncorrelated pre- and postsynaptic Poisson trains with rates $r_j$ and $r_i$ the mean drift is $2 η τ_y r_j (r_i - r)$: inhibition grows onto neurons that fire above the target rate r and decreases onto the others.

Fields (weights in the units of W, e.g. pF):

  • η = 0.01pA: learning rate.
  • r = 3Hz: target postsynaptic rate.
  • τy = 50ms: time constant of the pre- and postsynaptic traces.
  • Wmax = 243pF, Wmin = 0.01pF: weight bounds.

Algorithm (per step, tpre, tpost are Euler-integrated traces that jump by 1 at a spike; I[s] is the postsynaptic and J[s] the presynaptic index of synapse s):

  • presynaptic spike of j, for every outgoing synapse s (post i = I[s]): W[s] += η * (tpost[i] - 2 r τy). Depression is the constant term -2 η r τy.
  • postsynaptic spike of i, for every incoming synapse s (pre j = J[s]): W[s] += η * tpre[j].
  • every weight touched is clamped to [Wmin, Wmax].

Unlike the event-driven pair rules (STDPGerstner etc.), traces are Euler-integrated (per-step factor 1 - dt/τy) and a spike is added to its trace before the postsynaptic pass of the same step reads tpre, so a pre and a post spike in the same step do interact. The decay is lazy (see iSTDPVariables).

Plasticity is applied only when the network is run with train!; sim! never calls it.

Bug fixed in SNNModels 1.8.2

In SNNModels 1.5.0 - 1.8.1 (and SpikingNeuralNetworks.jl from v1.0.0, commit 680a30c) the potentiation applied at a postsynaptic spike used a @turbo loop that reassigned its loop variable. LoopVectorization ignored the reassignment, so the update hit the synapses stored at CSC positions rowptr[i]:rowptr[i+1]-1 (synapses onto unrelated postsynaptic neurons) instead of the incoming synapses of the spiking neuron i. The depression term was correct. Simulations that used iSTDPRate with those versions must be rerun.

Example

using SpikingNeuralNetworks
SNN.@load_units
E = SNN.IF(N = 80)
I = SNN.Poisson(N = 20, param = SNN.PoissonParameter(20Hz))
IE = SNN.SpikingSynapse(I, E, :gi; conn = (p = 0.2, μ = 5.0), LTPParam = SNN.iSTDPRate(r = 5Hz))
SNN.train!(model = SNN.compose(; E, I, IE), duration = 500ms)   # plasticity needs train!
source
SNNModels.iSTDPVariables — Type
iSTDPVariables

State of the inhibitory STDP rules: tpre (length Npre) and tpost (length Npost) traces, last_spike (unused by the update), the active flag and initialized (used by iSTDPPotential: while false, the first plasticity! call sets tpost to v_post). Record the traces with LTPVars as the variable set, e.g. monitor!(syn, [:tpost], :LTPVars).

iSTDPRate: the stored traces are not the trace values

As for STDPVariables: the value of tpre, tpost is the stored vector times scale[1], scale[2]. Read values with trace_values or call sync_traces! first. iSTDPPotential keeps dense traces (scale stays 1).

source
SNNModels.plasticity! — Method
plasticity!(c::AbstractSparseSynapse, param::iSTDPPotential, variables::iSTDPVariables, dt::AbstractFloat, T::Time)

One step of the membrane-potential variant of the inhibitory STDP of Vogels et al. (2011); modifies c.W in place. Called by train! (never by sim!). See iSTDPPotential for the equations.

Algorithm

  • Presynaptic pass, for every j: Euler decay tpre[j] += -dt * tpre[j] / τy; if j fired, tpre[j] += 1 and every outgoing synapse gets η (tpost[i] - v0) (depression if the filtered potential is below v0), clamped to [Wmin, Wmax].
  • At the first call, tpost .= v_post.
  • Postsynaptic pass, for every i: Euler step tpost[i] += dt * (v_post[i] - tpost[i]) / τy; if i fired, every incoming synapse gets η tpre[j], clamped to [Wmin, Wmax].
  • T is unused.
source
SNNModels.plasticity! — Method
plasticity!(c::AbstractSparseSynapse, param::iSTDPRate, variables::iSTDPVariables, dt::AbstractFloat, T::Time)

One step of the inhibitory STDP of Vogels et al. (2011) with target rate param.r; modifies c.W in place. Called by train! (never by sim!). See iSTDPRate for the update equations.

Arguments

  • c: the synapse; uses rowptr, colptr, index, I, J, W, fireI (post spikes), fireJ (pre spikes).
  • param::iSTDPRate: η, r, τy, Wmin, Wmax.
  • variables::iSTDPVariables: traces tpre, tpost, updated in place.
  • dt::AbstractFloat: time step (ms); T::Time: simulation clock (unused).

Algorithm

  • The traces are decayed by the Euler factor 1 - dt/τy (lazily); a spike adds 1.
  • Presynaptic spike (reads tpost of the previous step): walk the outgoing synapses (colptr) and add η (tpost[i] - 2 r τy).
  • Postsynaptic spike i (reads tpre of this step, spikes included): walk the incoming synapses k = rowptr[i]:rowptr[i+1]-1, map to the CSC position s = index[k] and add η tpre[J[s]]. Weights are clamped to [Wmin, Wmax].
source

Voltage-based STDP

SNNModels.vSTDPDenseParameter — Type
vSTDPDenseParameter(; A_LTD = 8e-4, A_LTP = 1.4e-3, θ_LTD = -70mV, θ_LTP = -49mV,
                      τu = 20ms, τv = 7ms, τx = 15ms, Wmax = 30pF, Wmin = 0.1pF, active = [true])

Clock-driven voltage-based STDP (Clopath et al. 2010): the rule of vSTDPParameter evaluated on every synapse at every step (O(nnz) per step). Same equations, update order, fields (without epoch) and precision, but syn.W always holds the current weights and a negative A_LTP is allowed. State: vSTDPDenseVariables.

Equations

With $V_i$ the postsynaptic potential (v_post), $u_i$, $v_i$ its low-pass filters, $x_j$ the presynaptic trace and $[z]_+ = \max(z, 0)$:

\[\begin{aligned} τ_x \frac{dx_j}{dt} &= -x_j + \sum_k δ(t - t_j^k), \qquad τ_u \frac{du_i}{dt} = -u_i + V_i, \qquad τ_v \frac{dv_i}{dt} = -v_i + V_i,\\ Δw_{ij}^{LTD} &= -A_{LTD}\,[u_i - θ_{LTD}]_+ \quad \text{at each presynaptic spike of } j,\\ \frac{dw_{ij}^{LTP}}{dt} &= A_{LTP}\, x_j\, [v_i - θ_{LTD}]_+\, [V_i - θ_{LTP}]_+ . \end{aligned}\]

A presynaptic spike increases $x_j$ by $1/τ_x$ (units 1/ms) and potentiation is a rate, integrated over dt. The filtered potential $v$ is compared with θ_LTD, the instantaneous one with θ_LTP.

Integration

plasticity! (only under train!), per step: (1) forward Euler for $x$ (all presynaptic neurons, including this step's spikes), (2) forward Euler for $u$ and $v$ (all postsynaptic neurons, driven by the current v_post), (3) for each presynaptic neuron $j$: if $j$ fired, LTD on its outgoing synapses and clamp at Wmin; then, whether or not $j$ fired, the LTP increment dt * A_LTP * x * ... on all its outgoing synapses and clamp at Wmax. At the first call, the voltage traces $u$ and $v$ are set to the current postsynaptic potential.

Fields

  • A_LTD::FT = 8 * 10e-5pA / mV (= 8e-4): LTD amplitude per mV.
  • A_LTP::FT = 14 * 10e-5pA / (mV * mV) (= 1.4e-3): LTP amplitude per mV².
  • θ_LTD::FT = -70mV: LTD threshold (also used for the filtered potential in the LTP term).
  • θ_LTP::FT = -49mV: LTP threshold on the instantaneous potential.
  • τu::FT = 20ms: time constant of $u$ (LTD filter).
  • τv::FT = 7ms: time constant of $v$ (LTP filter).
  • τx::FT = 15ms: time constant of the presynaptic trace $x$.
  • Wmax::FT = 30pF, Wmin::FT = 0.1pF: weight bounds.
  • active::VBT = [true]: present in the parameter type; activation is controlled by the active field of vSTDPDenseVariables (see set_LTP!).

References

Clopath, C., Büsing, L., Vasilaki, E. & Gerstner, W. (2010). Connectivity reflects coding: a model of voltage-based STDP with homeostasis. Nature Neuroscience 13, 344-352. The default parameter values are not referenced in the code.

Example

using SpikingNeuralNetworks
SNN.@load_units
E = SNN.Poisson(N = 50, param = SNN.PoissonParameter(20Hz))
P = SNN.AdEx(N = 10, param = SNN.AdExParameter())
syn = SNN.SpikingSynapse(E, P, :ge; conn = (p = 0.2, μ = 1.0), LTPParam = SNN.vSTDPDenseParameter())
SNN.train!(model = SNN.compose(; E, P, syn), duration = 200ms)
source
SNNModels.vSTDPDenseVariables — Type
vSTDPDenseVariables(; Npre, Npost, u = zeros(Npost), v = zeros(Npost), x = zeros(Npre), active = [true],
                      initialized = [false])

State of vSTDPDenseParameter: u, v (low-pass filters of the postsynaptic potential with time constants τu, τv, length Npost, mV), x (presynaptic spike trace, length Npre, 1/ms), the active flag and initialized: while initialized[1] is false, the first plasticity! call sets u and v to the postsynaptic potential.

source
SNNModels.vSTDPParameter — Type
vSTDPParameter(; A_LTD = 8e-4, A_LTP = 1.4e-3, θ_LTD = -70mV, θ_LTP = -49mV,
                 τu = 20ms, τv = 7ms, τx = 15ms, Wmax = 30pF, Wmin = 0.1pF, epoch = 10)

Voltage-based STDP of Clopath et al. (2010), event-driven. Depression is triggered by a presynaptic spike and depends on a low-pass filtered postsynaptic potential; potentiation depends on a presynaptic trace, on the instantaneous postsynaptic potential and on a second low-pass filter of it. Pass it as LTPParam to a SpikingSynapse whose target has a membrane potential. State: vSTDPVariables. The clock-driven form of the same rule is vSTDPDenseParameter.

`syn.W` is not the current weight vector

The potentiation is applied lazily: read the weights with plasticity_value(syn, :W), or call sync_traces!(syn) first. See "Reading the weights".

Equations

With $V_i$ the postsynaptic potential (v_post), $u_i$, $v_i$ its low-pass filters, $x_j$ the presynaptic trace and $[z]_+ = \max(z, 0)$:

\[\begin{aligned} τ_x \frac{dx_j}{dt} &= -x_j + \sum_k δ(t - t_j^k), \qquad τ_u \frac{du_i}{dt} = -u_i + V_i, \qquad τ_v \frac{dv_i}{dt} = -v_i + V_i,\\ Δw_{ij}^{LTD} &= -A_{LTD}\,[u_i - θ_{LTD}]_+ \quad \text{at each presynaptic spike of } j,\\ \frac{dw_{ij}^{LTP}}{dt} &= A_{LTP}\, x_j\, [v_i - θ_{LTD}]_+\, [V_i - θ_{LTP}]_+ . \end{aligned}\]

A presynaptic spike increases $x_j$ by $1/τ_x$ (units 1/ms) and potentiation is a rate, integrated over dt. The filtered potential $v$ is compared with θ_LTD, the instantaneous one with θ_LTP. Per step (the order of the dense rule): (1) forward Euler for $x$ (this step's spikes included), (2) forward Euler for $u$ and $v$, (3) LTD at the presynaptic spikes of the step, clamped at Wmin, then (4) the LTP increment dt * A_LTP * x * ... on all outgoing synapses, clamped at Wmax. At the first call $u$ and $v$ are set to the current postsynaptic potential.

Event-driven evaluation

The filters $u_i$, $v_i$ and the drive $g_i(n) = [v_i(n) - θ_{LTD}]_+ [V_i(n) - θ_{LTP}]_+$ are computed every step (O(Npost)). Between presynaptic spikes $x_j(n) = a_j q^n$ with $q = 1 - dt/τ_x$, so the LTP since the last presynaptic spike $n_k$ of $j$ is $dt\,A_{LTP}\,a_j (K_i(n) - K_i(n_k - 1))$ with the per-neuron accumulator $K_i(n) = \sum_{m \le n} q^m g_i(m)$; each synapse keeps a snapshot of $K_i$. The weights are materialised

  • at a presynaptic spike of $j$, for its outgoing synapses, in update_traces! (before forward!, so the spike is transmitted with the current weight);
  • for all synapses once per epoch (epoch times τx): the difference of $K$ loses its digits after about 35 τx in Float64, so $K$, the snapshots and $a_j$ are restarted every epoch;
  • on demand (sync_traces!, a change of dt, τx, A_LTP, Wmax or epoch).

K, the snapshots and a_j are Float64 whatever the precision of the synapse; the weights, the filters and the thresholds have the precision of the synapse.

Bounds

LTD acts at presynaptic spikes, before the LTP of the same step, on the materialised weight, and is clamped at Wmin there. The LTP increments are non-negative (A_LTP >= 0 is enforced), so clamping at Wmax once after the accumulation equals clamping at every step ($\min(W_{max}, \min(W_{max}, a) + b) = \min(W_{max}, a + b)$ for $b \ge 0$), including the case where LTD has pushed the weight to Wmin: the clamp at Wmin is applied at the spike, the accumulation afterwards only adds. The one difference: a weight that is initially above Wmax is clamped by the dense rule at the first step and by this rule at the first materialisation (the recorded and forwarded weights are the clamped ones in both).

Reading the weights

syn.W holds the weights as of the last materialisation of each synapse. The current weights are plasticity_value(syn, :W) (a scratch vector, state unchanged; used by monitor!). Call sync_traces!(syn) (materialises all synapses and restarts the epoch) before reading or modifying syn.W directly (save_model does this). The trace x is stored as the amplitude $a_j$; read it with plasticity_value(syn, :LTPVars, :x, t).

Fields

  • A_LTD::FT = 8 * 10e-5pA / mV (= 8e-4): LTD amplitude per mV.
  • A_LTP::FT = 14 * 10e-5pA / (mV * mV) (= 1.4e-3): LTP amplitude per mV²; must be non-negative.
  • θ_LTD::FT = -70mV: LTD threshold (also used for the filtered potential in the LTP term).
  • θ_LTP::FT = -49mV: LTP threshold on the instantaneous potential.
  • τu::FT = 20ms, τv::FT = 7ms, τx::FT = 15ms: time constants of $u$, $v$, $x$ (dt < τx is required).
  • Wmax::FT = 30pF, Wmin::FT = 0.1pF: weight bounds.
  • epoch::FT = 10: restart interval of the accumulator in units of τx (0 < epoch <= 25).
  • active::VBT = [true]: present in the parameter type; activation is controlled by the active field of vSTDPVariables (see set_LTP!).

Precision

FT = Float32 by default; the synapse converts the rule to its own precision (convert_precision). A rule built with Float32 fields keeps the Float32 values: use vSTDPParameter(FT = Float64, A_LTD = 8e-4) for exact Float64 values.

Cost

Per step O(Npost); per presynaptic spike O(fan-out); once per epoch O(nnz). Serial.

References

Clopath, C., Büsing, L., Vasilaki, E. & Gerstner, W. (2010). Connectivity reflects coding: a model of voltage-based STDP with homeostasis. Nature Neuroscience 13, 344-352. The default parameter values are not referenced in the code.

Example

using SpikingNeuralNetworks
SNN.@load_units
E = SNN.Poisson(N = 50, param = SNN.PoissonParameter(20Hz))
P = SNN.AdEx(N = 10, param = SNN.AdExParameter())
syn = SNN.SpikingSynapse(E, P, :ge; conn = (p = 0.2, μ = 1.0), LTPParam = SNN.vSTDPParameter())
SNN.train!(model = SNN.compose(; E, P, syn), duration = 200ms)
SNN.plasticity_value(syn, :W)      # current weights (syn.W is lazy)
source
SNNModels.vSTDPVariables — Type
vSTDPVariables(; Npre, Npost)

State of vSTDPParameter: u, v (filters of the postsynaptic potential), x (stored amplitudes $a_j$, value $a_j q^n$: read it with plasticity_value), K (accumulator per postsynaptic neuron), snap (snapshot of K per synapse), the scratch Wcur of plasticity_value(syn, :W), and step counters and cached constants (steps, tick, matstep, pw, cache). Lists :x and :W in lazy_variables.

source
SNNModels.plasticity! — Method
plasticity!(c::AbstractSparseSynapse, param::vSTDPDenseParameter, variables::vSTDPDenseVariables, dt::AbstractFloat, T::Time)

One step of the dense voltage-based STDP rule vSTDPDenseParameter (see its docstring for the equations and the update order): updates the traces in variables and the weights c.W in place, clamping them to [Wmin, Wmax]. Called by train!, never by sim!.

source
SNNModels.plasticity! — Method
plasticity!(c::AbstractSparseSynapse, param::vSTDPParameter, variables::vSTDPVariables, dt::AbstractFloat, T::Time)

One step of vSTDPParameter (see its docstring): filters and accumulator of the postsynaptic neurons, LTD at the presynaptic spikes, restart of the epoch when due. The weights of the spiking neurons were materialised by update_traces! (done here if update_traces! was not called).

source

Short-term plasticity

SNNModels.AbstractMarkramSTPParameter — Type
AbstractMarkramSTPParameter <: STPParameter

Abstract supertype of the Tsodyks-Markram short-term plasticity rules: MarkramSTPParameterEvent (alias MarkramSTPParameter) and MarkramSTPParameterHet (both event-driven, subtypes of AbstractMarkramSTPParameterEvent) and the clock-driven MarkramSTPParameterTimestep. All use MarkramSTPVariables.

source
SNNModels.MarkramSTPParameterEvent — Type
MarkramSTPParameter(; τD = 200ms, τF = 1500ms, U = 0.2, Wmax = 1pF, Wmin = 0pF)
MarkramSTPParameterEvent(; τD = 200ms, τF = 1500ms, U = 0.2, Wmax = 1pF, Wmin = 0pF)

Tsodyks-Markram short-term plasticity (depression and facilitation), event-driven. MarkramSTPParameter is an alias (a non-constant global) of MarkramSTPParameterEvent. Pass it to SpikingSynapse with STPParam = MarkramSTPParameter().

The model describes the refractoriness of release: a spike uses the fraction $u$ of the available resources $x$, which recover with time constant $τ_D$ (depression); each spike increases $u$, which relaxes to $U$ with time constant $τ_F$ (facilitation). The efficacy of every outgoing synapse $s$ of the presynaptic neuron $j$ is $ρ_s = u_j x_j$ and the spike adds $W_s ρ_s$ to the target conductance.

Equations

Between spikes

\[\frac{du}{dt} = \frac{U - u}{τ_F}, \qquad \frac{dx}{dt} = \frac{1 - x}{τ_D}.\]

At a presynaptic spike at time $t_n$, with $Δ = t_n - t_{n-1}$ the interval from the previous spike of the same neuron:

\[\begin{aligned} u^- &= U - (U - u)\, e^{-Δ/τ_F}, &\qquad x^- &= 1 - (1 - x)\, e^{-Δ/τ_D},\\ u^+ &= u^- + U (1 - u^-), & & \\ ρ &= u^+ x^-, & x &\leftarrow x^- - u^+ x^- ,\qquad u \leftarrow u^+ . \end{aligned}\]

This is the formulation of Mongillo, Barak & Tsodyks (2008): the utilisation jumps first, and the same $u^+$ sets both the transmitted efficacy and the depletion of resources. From rest ($u = U$, $x = 1$) the first spike is transmitted with $ρ = U (2 - U)$.

Changed in SNNModels 1.9.0

Up to 1.8.4 the efficacy used $u^-$ (before the jump) while the depletion used $u^+$, a mix of the Markram et al. (1998) and Mongillo et al. (2008) conventions that depressed more than either. Efficacies are now higher, e.g. $0.51$ instead of $0.30$ for the first spike with $U = 0.3$.

Integration

Exact solution between spikes, evaluated only at presynaptic spikes (no per-step work for silent neurons). The update is done in update_traces!, which train! calls before forward!, so the spike of the current step is transmitted with the new efficacy. plasticity! does nothing for this rule. Under sim! neither is called and ρ keeps its value (1 for a new synapse).

Fields

  • τD::FT = 200ms: recovery (depression) time constant of $x$ (ms).
  • τF::FT = 1500ms: facilitation time constant of $u$ (ms).
  • U::FT = 0.2: baseline utilisation (dimensionless).
  • Wmax::FT = 1pF, Wmin::FT = 0pF: unused by the update (kept for compatibility).

References

Tsodyks, M. V. & Markram, H. (1997). PNAS 94, 719-723; Markram, H., Wang, Y. & Tsodyks, M. (1998). PNAS 95, 5323-5328; Mongillo, G., Barak, O. & Tsodyks, M. (2008). Science 319, 1543-1546 (the formulation named in the code).

Example

using SpikingNeuralNetworks
SNN.@load_units
E = SNN.Poisson(N = 50, param = SNN.PoissonParameter(20Hz))
P = SNN.IF(N = 10)
syn = SNN.SpikingSynapse(E, P, :ge; conn = (p = 0.2, μ = 1.0),
                         STPParam = SNN.MarkramSTPParameter(τD = 200ms, τF = 1500ms, U = 0.2))
SNN.train!(model = SNN.compose(; E, P, syn), duration = 500ms)  # STP needs train!
extrema(syn.ρ)
source
SNNModels.MarkramSTPParameterHet — Type
MarkramSTPParameterHet(; τD::Vector{Float32}, τF::Vector{Float32}, U::Vector{Float32})

Event-driven Tsodyks-Markram short-term plasticity with one parameter set per presynaptic neuron. The equations and the integration are those of MarkramSTPParameterEvent, with $U$, $τ_F$ and $τ_D$ replaced by U[j], τF[j] and τD[j] of the presynaptic neuron $j$.

Fields (no defaults, all required; vectors of length Npre)

  • τD::VFT: recovery (depression) time constants (ms).
  • τF::VFT: facilitation time constants (ms).
  • U::VFT: baseline utilisations.

Unlike the homogeneous rules there are no Wmax/Wmin fields.

Example

using SpikingNeuralNetworks
SNN.@load_units
E = SNN.Poisson(N = 50, param = SNN.PoissonParameter(20Hz))
P = SNN.IF(N = 10)
stp = SNN.MarkramSTPParameterHet(τD = fill(200f0, 50), τF = fill(1500f0, 50), U = rand(Float32, 50))
syn = SNN.SpikingSynapse(E, P, :ge; conn = (p = 0.2, μ = 1.0), STPParam = stp)
source
SNNModels.MarkramSTPParameterTimestep — Type
MarkramSTPParameterTimestep(; τD = 200ms, τF = 1500ms, U = 0.2, Wmax = 1pF, Wmin = 0pF)

Tsodyks-Markram short-term plasticity integrated at every time step (clock-driven variant of MarkramSTPParameterEvent).

Each presynaptic neuron $j$ has a utilisation $u_j$ and a fraction of available resources $x_j$. The efficacy of all its outgoing synapses is $ρ_s = u_j x_j$ and a spike adds $W_s ρ_s$ to the target conductance.

Equations

\[\frac{du}{dt} = \frac{U - u}{τ_F}, \qquad \frac{dx}{dt} = \frac{1 - x}{τ_D}\]

and, at a presynaptic spike (Mongillo, Barak & Tsodyks 2008), $u \leftarrow u + U (1 - u)$, then $ρ_s = u\, x$ for every outgoing synapse, then $x \leftarrow x - u\, x$ (both with the facilitated $u$).

Integration

The spike jumps and the efficacy are computed in update_traces!, which train! calls before forward!, so the spike of step $n$ is transmitted with the efficacy $u^+ x$ of that step. plasticity! (after forward!) relaxes $u$ and $x$ of all neurons by one forward-Euler step. sim! never calls either. Up to SNNModels 1.8.4 the spike was transmitted with the efficacy of the previous step ($u^-$) while the depletion used $u^+$.

Fields

  • τD::FT = 200ms: recovery (depression) time constant of $x$ (ms).
  • τF::FT = 1500ms: facilitation time constant of $u$ (ms).
  • U::FT = 0.2: baseline utilisation (dimensionless).
  • Wmax::FT = 1pF, Wmin::FT = 0pF: unused by the update (kept for compatibility).

References

Tsodyks, M. V. & Markram, H. (1997). PNAS 94, 719-723; Markram, H., Wang, Y. & Tsodyks, M. (1998). PNAS 95, 5323-5328; Mongillo, G., Barak, O. & Tsodyks, M. (2008). Science 319, 1543-1546 (the formulation named in the code).

source
SNNModels.MarkramSTPVariables — Type
MarkramSTPVariables(; Npre, Npost, u = zeros(Npre), x = ones(Npre), _ρ = ones(Npre),
                    last_spike = fill(-Inf, Npre), active = [true])

State of the Markram STP rules, one entry per presynaptic neuron. Created by plasticityvariables(param, Npre, Npost), which sets u .= U, x .= 1 and _ρ .= U (for MarkramSTPParameterHet, U is a vector and is broadcast elementwise).

Fields

  • Npost, Npre: number of postsynaptic and presynaptic neurons.
  • u: utilisation of each presynaptic neuron.
  • x: fraction of available resources of each presynaptic neuron.
  • _ρ: efficacy $u x$ that the last spike of each presynaptic neuron transmitted, copied to the synapse vector c.ρ.
  • last_spike: time of the previous spike (ms), used by the event-driven rules.
Stored `u` and `x` are the values at the last spike

With the event-driven rules (MarkramSTPParameterEvent, MarkramSTPParameterHet) u and x are updated only at a presynaptic spike (to $u^+$ and the depleted $x$). Their value at time t is U - (U - u) exp(-(t - last_spike)/τF) and 1 - (1 - x) exp(-(t - last_spike)/τD); read it with plasticity_value(syn, :STPVars, :u, t). MarkramSTPParameterTimestep stores the values.

  • active: the rule is applied only if any(active); see set_STP!.
source