Encoding a triadic synapse model

Hi, I am still a beginner for Brian, and I am wondering if it is possible to encode a synapse model containing a triadic synapse structure.
More specifically, with two input neurons targeting the same single synapse in the downstream neuron, and affecting the downstream synapse temporally.
Thank you!

Hi @BetaFish. Could you give a bit more detail of what such a model would look like or e.g. link to a paper that uses such a model?
Brian’s synapse mechanism is very flexible, so there’s a big chance that what you want to do is possible. See for example our paper on neuron-glia interactions, which demonstrates how to use advanced techniques like synapses targeting other synapses: https://www.biorxiv.org/content/10.1101/198366v1 The code from this paper is here: Examples — Brian 2 2.5.1 documentation

@mstimberg Thanks for your reply and the paper! I will read the paper to find some inspiration!

Here are more details about what I am trying to do:

Having input1 and 2 as the input neuron connecting to the interneuron, the first part of my model will be the two input neurons affecting a single synapse of the interneuron, which constructs a triadic synapse. In this case, when a new input comes in (the second part in the figure) to other synapses in the interneuron, it will be easier for the target interneuron to fire and pass the signal to the downstream output neuron. Each synapse in the two input neurons should connect to a specific synapse in the interneuron.
My main problem is that not knowing how to target a single synapse specifically in a multi-synapse neuron.
I’ve tried to set the synapse equation for each synapse independently like:

ds_ach/dt = -s_ach/tau_ach : 1 (clock-driven)
Isyn1_post = -s_ach*(v-E_ach)*a1:1 (summed)
Isyn2_post= -s_ach*(v-E_ach)*a2:1 (summed)
Isyn3_post= -s_ach*(v-E_ach)*a3:1 (summed)
w: 1

And changes the variable aX to modify the status of different synapses, the issue will be the time cost when I build a larger network.

Hi @BetaFish. I am afraid I still do not understand what your triadic synapse is supposed to look like. In your drawing, you have three synapses coming together at (1), and three synapses coming together at (2) – one coming from an “output”, shouldn’t this rather go somewhere else? From the drawing, it seems that the synapses are not connecting to anything, but I guess this is not the idea. Could you break things down to the simplest possible model, like: there are four neurons, two input neurons N1 and N2, an interneuron I, and output neuron O. The synapse S connects I→O, and N1 → S modulates this synapse. Or something along these lines that actually describes your model :wink:

Do you mean how to target individual post-synaptic conductances, or the synapse itself?

Hi, @mstimberg thanks a lot for your reply!
The simpler way to describe the model is similar to what you’ve mentioned. Two input neurons N1 and N2, interneuron I, and output neuron O. Synapse S connects I->O, N1 & N2 → modulates the synapse.

Yes, that’s my question!

Ok, so let’s make this concrete so that we can more easily discuss the details. Here’s a model of a synapse that has a weight, but the weight can be temporarily modulated away from the default:

S = Synapses(I, O, '''dw/dt = (w_default - w) / tau_w : 1 (clock-driven)
                      w_default : 1 (constant)''',
             on_pre='v_post += w')

To modulate it, we can target this synapse with another synapse (in Brian’s terminology):

# The neurons in N modulate the S synapse by different amounts
modulation = Synapses(N, S, 'w_modulation : 1 (constant)',
                      on_pre='w_post += w_modulation')

Here’s a full example putting everything together, with two neurons in N firing randomly, and one neuron in I firing regularly. You can see how the synaptic weight is temporarily increased after N1 or N2 spikes (with N2 having a stronger effect; spikes from N2 are plotted on the first row, spikes from N1 in the second row). This in turn affects the post-synaptic effect on the O neuron, if this modulation happens sufficiently close in time to a spike coming in from I (see bottom row).

Code example
from brian2 import *

N = PoissonGroup(2, rates=10*Hz)  # randomly firing with 10 Hz each
I = SpikeGeneratorGroup(1, [0], [10]*ms, period=50*ms)  # firing every 50ms
O = NeuronGroup(1, 'dv/dt = -v / (10*ms) : 1')

# One possible model, with a "default" weight that gets temporarily modulated
tau_w = 20*ms
S = Synapses(I, O, '''dw/dt = (w_default - w) / tau_w : 1 (clock-driven)
                      w_default : 1 (constant)''',
             on_pre='v_post += w')
S.w_default = 1
S.w = 'w_default'

# The neurons in N modulate the S synapse by different amounts
modulation = Synapses(N, S, 'w_modulation : 1 (constant)',
                      on_pre='w_post += w_modulation')
modulation.w_modulation = [0.2, 0.8]

spikes_N = SpikeMonitor(N)
spikes_I = SpikeMonitor(I)
weight_mon = StateMonitor(S, 'w', record=0)
v_mon = StateMonitor(O, 'v', record=0)

fig, axs = plt.subplots(4, 1, sharex=True, gridspec_kw={'height_ratios': [1, 1, 2, 2]})
axs[0].plot(spikes_N.t/ms, spikes_N.i, '|', color='darkblue'); axs[0].axis('off')
axs[1].plot(spikes_I.t/ms, spikes_I.i, '|', color='darkred'); axs[1].axis('off')
axs[2].plot(weight_mon.t/ms, weight_mon.w[0]); axs[2].set(ylabel='w')
axs[3].plot(v_mon.t/ms, v_mon.v[0]); axs[3].set(ylabel='v', xlabel='t (ms)')


Of course the neuron and synapse models above are very simplified and will probably be more complex in your case, but I hope it conveys the basic idea.

@mstimberg Thanks a lot for your suggestion! I will try if this method is usable in my model!!