flowchart LR
Pre["Pre-synaptic<br/>Neuron"]
Dep["Depression<br/>Synapse"]
Fac["Facilitation<br/>Synapse"]
TM["Tsodyks-Markram<br/>Synapse"]
Post["Post-synaptic<br/>Neuron"]
Pre -->|"r_out"| Dep
Pre -->|"r_out"| Fac
Pre -->|"r_out"| TM
Dep -->|"r_eff"| Post
Fac -->|"r_eff"| Post
TM -->|"r_eff"| Post
Heterogeneous Edges
Edgedynamics as Relay-Nodes!
from tvbo import Dynamics
# Tsodyks-Markram sho#rt-term plasticity model
# Combines depression (x) and facilitation (u)
# r_eff is an output (algebraic equation) - PyRates renders this correctly
tsodyks = Dynamics.from_string("""
name: TsodyksMarkram
description: "Short-term synaptic plasticity with depression and facilitation"
parameters:
tau_x:
value: 200.0
description: "Recovery time constant for depression (ms)"
tau_u:
value: 50.0
description: "Recovery time constant for facilitation (ms)"
U0:
value: 0.2
description: "Baseline release probability"
k:
value: 0.5
description: "Depression rate"
k_fac:
value: 0.05
description: "Facilitation rate"
state_variables:
x:
equation:
rhs: "(1 - x)/tau_x - k*x*u*r_in"
initial_value: 1.0
description: "Available synaptic resources (depression variable)"
u:
equation:
rhs: "(U0 - u)/tau_u + k_fac*(1 - u)*r_in"
initial_value: 0.2
description: "Release probability (facilitation variable)"
coupling_inputs:
r_in: {}
derived_variables:
r_eff:
equation:
rhs: "r_in*x*u"
description: "Effective synaptic transmission"
output:
- r_eff
""")
# Pure synaptic depression model
depression = Dynamics.from_string("""
name: Depression
description: "Short-term synaptic depression only"
parameters:
tau_x:
value: 300.0
description: "Recovery time constant (ms)"
k:
value: 0.3
description: "Depression rate"
state_variables:
x:
equation:
rhs: "(1 - x)/tau_x - k*x*r_in"
initial_value: 1.0
description: "Available synaptic resources"
coupling_inputs:
r_in: {}
derived_variables:
r_eff:
equation:
rhs: "r_in*x"
description: "Effective transmission with depression"
output:
- r_eff
""")
# Pure synaptic facilitation model
facilitation = Dynamics.from_string("""
name: Facilitation
description: "Short-term synaptic facilitation only"
parameters:
tau_u:
value: 100.0
description: "Recovery time constant (ms)"
U0:
value: 0.2
description: "Baseline release probability"
k_fac:
value: 0.01
description: "Facilitation rate"
state_variables:
u:
equation:
rhs: "(U0 - u)/tau_u + k_fac*(1 - u)*r_in"
initial_value: 0.2
description: "Release probability"
coupling_inputs:
r_in: {}
derived_variables:
r_eff:
equation:
rhs: "r_in*u"
description: "Effective transmission with facilitation"
output:
- r_eff
""")
# Simple rate neuron (I_ext=0.0, will receive external stimulus)
rate_neuron = Dynamics.from_string("""
name: RateNeuron
description: "Simple rate-based neuron with external input"
parameters:
tau:
value: 10.0
I_ext:
value: 0.0
state_variables:
r:
equation:
rhs: "(-r + I_ext + r_in)/tau"
initial_value: 0.0
coupling_inputs:
r_in: {}
""")
print(f"Created plasticity models: {tsodyks.name}, {depression.name}, {facilitation.name}")Created plasticity models: TsodyksMarkram, Depression, Facilitation
import yaml
from tvbo import SimulationExperiment
from tvbo import Network
# Network: Pre-synaptic neuron → three parallel synaptic pathways → Post-synaptic neuron
# This allows direct comparison of how different plasticity affects the SAME post-synaptic target
network_yaml = """
label: SynapticPlasticityComparison
number_of_nodes: 5
nodes:
- id: 0
label: PreSynaptic
dynamics: RateNeuron
position:
x: 0.0
y: 0.5
z: 0
- id: 1
label: DepressionSynapse
dynamics: Depression
position:
x: 0.5
y: 0.8
z: 0
- id: 2
label: FacilitationSynapse
dynamics: Facilitation
position:
x: 0.5
y: 0.5
z: 0
- id: 3
label: TsodyksSynapse
dynamics: TsodyksMarkram
position:
x: 0.5
y: 0.2
z: 0
- id: 4
label: PostSynaptic
dynamics: RateNeuron
position:
x: 1.0
y: 0.5
z: 0
edges:
# Pre-synaptic drives all three synaptic relays
- source: 0
target: 1
parameters:
weight:
value: 1.0
source_var: r_out
target_var: r_in
- source: 0
target: 2
parameters:
weight:
value: 1.0
source_var: r_out
target_var: r_in
- source: 0
target: 3
parameters:
weight:
value: 1.0
source_var: r_out
target_var: r_in
# All synapses converge onto the post-synaptic neuron
- source: 1
target: 4
parameters:
weight:
value: 0.33
source_var: r_eff
target_var: r_in
- source: 2
target: 4
parameters:
weight:
value: 0.33
source_var: r_eff
target_var: r_in
- source: 3
target: 4
parameters:
weight:
value: 0.33
source_var: r_eff
target_var: r_in
"""
# Parse network and create experiment with all components
network_plasticity = Network.from_string(network_yaml)
network_plasticity.plot_graph(node_size=10, edge_cmap="bwr")
Run Simulation with Pulsed Stimulus
We create a pulsed input pattern that drives the pre-synaptic neuron. This matches Use Case 2 from the PyRates tutorial:
import numpy as np
# Create time array and pulsed input signal
duration = 1000.0
step_size = 0.1
time = np.arange(0, duration, step_size)
# Pulse train with longer recovery periods to show plasticity effects
# Two bursts of rapid pulses separated by a long gap
pulse_times = [
50,
80,
110,
140,
170, # First burst (rapid)
500,
530,
560,
590,
620,
] # Second burst after recovery
input_signal = np.zeros_like(time)
for pt in pulse_times:
mask = (time >= pt) & (time < pt + 15)
input_signal[mask] = 5.0
network_plasticity.dynamics.update(
{
"RateNeuron": rate_neuron,
"Depression": depression,
"Facilitation": facilitation,
"TsodyksMarkram": tsodyks,
}
),
# Create experiment
exp_plasticity = SimulationExperiment(
network=network_plasticity,
)
exp_plasticity.integration.duration = duration
exp_plasticity.integration.step_size = step_size
# Run with pulsed input to PreSynaptic neuron
pyrates_inputs = {"PreSynaptic/RateNeuron_op/I_ext": input_signal}
res = exp_plasticity.run("pyrates", inputs=pyrates_inputs)
print(res)Compilation Progress
--------------------
(1) Translating the circuit template into a networkx graph representation...
...finished.
(2) Preprocessing edge transmission operations...
...finished.
(3) Parsing the model equations into a compute graph...
...finished.
Model compilation was finished.
Simulation Progress
-------------------
(1) Generating the network run function...
(2) Processing output variables...
...finished.
(3) Running the simulation...
...finished after 0.18405149999853165s.
Experiment
└── integration
data: (10000, 4, 5)
Visualize Results
import matplotlib.pyplot as plt
fig, axes = plt.subplots(4, 1, figsize=(10, 10), sharex=True)
t = res.time
# Row 1: Pulsed input stimulus
ax = axes[0]
ax.plot(t, input_signal, 'k', lw=2)
ax.set_ylabel("Input\nStimulus")
ax.set_title("Short-Term Synaptic Plasticity: Pre → Synapses → Post")
ax.set_ylim(-0.5, 6)
# Row 2: Pre-synaptic activity (state variable: r)
ax = axes[1]
pre_r = res.get_region('PreSynaptic').get_state_variable('r')
ax.plot(t, pre_r.data.squeeze(), 'k', lw=2, label="Pre-synaptic Rate")
ax.set_ylabel("Pre-synaptic\nRate")
ax.legend(loc='upper right')
# Row 3: Synaptic variables
ax = axes[2]
dep_x = res.get_region('DepressionSynapse').get_state_variable('x')
fac_u = res.get_region('FacilitationSynapse').get_state_variable('u')
tso_x = res.get_region('TsodyksSynapse').get_state_variable('x')
tso_u = res.get_region('TsodyksSynapse').get_state_variable('u')
ax.plot(t, dep_x.data.squeeze(), 'C0', lw=2, label="Depression (x)")
ax.plot(t, fac_u.data.squeeze(), 'C1', lw=2, label="Facilitation (u)")
ax.plot(t, tso_x.data.squeeze(), 'C2', lw=2, label="Tsodyks x")
ax.plot(t, tso_u.data.squeeze(), 'C3', lw=2, label="Tsodyks u")
ax.set_ylabel("Synaptic\nVariables")
ax.legend(loc='right')
ax.axhline(1.0, color='gray', ls=':', alpha=0.5)
# Row 4: Post-synaptic response (state variable: r)
ax = axes[3]
post_r = res.get_region('PostSynaptic').get_state_variable('r')
ax.plot(t, post_r.data.squeeze(), 'C4', lw=2, label="Post-synaptic Rate")
ax.set_ylabel("Post-synaptic\nRate")
ax.set_xlabel("Time (ms)")
ax.legend(loc='upper right')
plt.tight_layout()
plt.show()