Unable to create proper synapses connections using a loop

Description of problem

I was trying to create some synapses and store them in a list. I was able to create each synapses one by one. However, when creating them using a for loop, the results were different.

My network is simple:
Layer G has two neurons 0 and 1; neuron #1 is not connected to any other neurons.
Layer H has three neurons 0, 1, 2.
Synapses #1: G_0 is connected to H_0 and H_1 with a weight of 0 and 0.2 respectively.
Synapses #2: G_0 is connected to H_2 with a weight of 0.01

G_0 fires periodically. If everything works as expected, H_0 never fires, H_1’s voltage increases faster than H_2’s voltage.

Minimal code to reproduce problem

from brian2 import *

eqs = ‘’’
dv/dt = (I-v)/tau : 1
I : 1
tau : second
‘’’

G = NeuronGroup(2, eqs, threshold=‘v>1’, reset=‘v = 0’, method=‘exact’)
G.I = [2, 2]
G.tau = [10, 10]*ms

H = NeuronGroup(3, eqs, threshold=‘v>1’, reset=‘v = 0’, method=‘exact’)
H.I = [0, 0, 0]
H.tau = [10, 100, 100]*ms

J = [[0,1],[2]] # connection list
W = [[0,0.2],[0.01]] # weight list
S = [0]*2 # list to store synapses

#The for loop below was supposed to create the synapses, but it never worked out properly
#for syn in range(2):
#S[syn] = Synapses(G, H, model=‘w : 1’, on_pre=‘v_post += w’)
#S[syn].connect(i=0, j=J[syn])
#S[syn].w = W[syn]

#creating the synapses one by one worked.
S1 = Synapses(G, H, model=‘w : 1’, on_pre=‘v_post += w’)
S1.connect(i=0, j=J[0])
S1.w = W[0]
S2 = Synapses(G,H, ‘w : 1’, on_pre=‘v_post += w’)
S2.connect(i=0,j=J[1])
S2.w = W[1]

M = StateMonitor(H, ‘v’, record=True)

run(50*ms)
plot(M.t/ms, M.v[0], label=‘Neuron 0’)
plot(M.t/ms, M.v[1], label=‘Neuron 1’)
plot(M.t/ms, M.v[2], label=‘Neuron 2’)

xlabel(‘Time (ms)’)
ylabel(‘v’)
legend()
show()

What you have already tried

If I don’t use the indexing method to store the synapses, I was able to create a synapses (that functions properly) in the last iteration only.

S =
for syn in range(2):
S_tmp = Synapses(G, H, model=‘w : 1’, on_pre=‘v_post += w’)
S_tmp.connect(i=0, j=J[syn])
S_tmp.w = W[syn]
S.append(S_tmp)

Expected output (if relevant)

expected

Actual output (if relevant)

None of the neuron in layer H fired. All three neurons’ voltage were flat at 0V all the time.

Full traceback of error (if relevant)

Hi @RRHHAAWW. This is quite a common issue, and I wonder what we could do to handle this better. When you call run, Brian looks for Brian objects in the current scope and adds them to a Network object internally (we call this the “magic” :star2: system). To avoid digging deeply into all container objects that are present (with the risk of going into infinite recursions, if two containers refer to each other, etc.), Brian will only look at objects that are directly visible. In your above code, it will find S1 and S2 which are “Brian objects”, but when it looks at S it will see a list and skip it. We mention this in the documentation here: Running a simulation — Brian 2 2.4.2 documentation
The way around this is to create a Network object manually. If the synapses list is the only container you use, you can still use the automatic system for most of the objects (NeuronGroup, etc.), and only add the container manually:

net = Network(collect())  # automatically add everything that run(...) would discover by itself
net.add(S)  # add the list of synapses manually
net.run(50*ms)

That said, in your example you could also use a single Synapses object which would be more efficient to simulate. You could use something like this to convert your data structures into “flat” arrays of values:

J_flat, W_flat = [], []
for syn in range(2):
    J_flat.extend(J[syn])
    W_flat.extend(W[syn])

And then you can use these new arrays to set up everything:

S = Synapses(G, H, model=‘w : 1’, on_pre=‘v_post += w’)
S.connect(i=0, j=J_flat)
S.w = W_flat

Hope that makes things clearer, best
Marcel

The Network() object method works. Thanks.

One more question regarding your “flat” array solution: this method works too, but is it only because the synapses only connects neuron 0 in layer G to layer H? If neuron 1 of G also connects to some neurons in layer H, then I have to use the Network() object method to do so, is that right?

You can still use the “single Synapses object method” if there are other neurons in group G connecting to H. In that case you also have to give a list of indices for i. E.g. to connect neuron 0→[0, 1, 2] and neuron 1→[0, 2], you’d use:

syn.connect(i=[0, 0, 0, 1, 1],
            j=[0, 1, 2, 0, 2])

Accordingly, you’d need to set 5 weights. For example, if the weight for the connections from neuron 0 are supposed to be 0.1, and those for connections from neuron 1 are supposed to be 0.2, you’d set

syn.w = [0.1, 0.1, 0.1, 0.2, 0.2]