First, one must define which neuron groups are connected and which state variable receives the spikes. The following instruction:
defines a connection from group
group2, acting on variable
neurons from group
group1 spike, the variable
ge of the target neurons in group
group2 are incremented. When the connection object is initialised, the list of connections
is empty. It can be created in several ways. First, explicitly:
This instruction connects neuron 2 from
group1 to neuron 5 from
group2 with synaptic weight
3 nS. Units should match the units of the variable defined at initialisation time (
The matrix of synaptic weights can be defined directly with the method
Here a matrix with random elements is used to define the synaptic weights from
group2. It is possible to build the matrix by block by using subgroups, e.g.:
There are several handy functions available to set the synaptic weights:
connect_one_to_one(). The first one
is used to set uniform weights for all pairs of neurons in the (sub)groups:
The second one is used to set uniform weights for random pairs of neurons in the (sub)groups:
Here the third argument (0.02) is the probability that a synaptic connection exists between two neurons.
The number of presynaptic neurons can be made constant by setting the keyword
(probability * number of neurons in
Finally, the method
connect_one_to_one() connects neuron i from the first
group to neuron i from the second group:
Both groups must have the same number of neurons.
If you are connecting the whole groups, you can omit the first two arguments, e.g.:
group2 with weights 5 nS.
Building connections with connectivity functions¶
There is a simple and efficient way to build heterogeneous connections, by passing functions
instead of constants to the methods
The function must return the synaptic weight for a given pair of neuron (i,j).
where i (j) indexes neurons in
group2). This is the same as doing by hand:
for i in range(len(group1)): for j in range(len(group2)): myconnection[i,j]=(1+cos(i-j))*2*nS
but it is much faster because the construction is vectorised, i.e., the function is called for every i with j being the entire row of target indexes. Thus, the implementation is closer to:
for i in range(len(group1)): myconnection[i,j]=(1+cos(i-arange(len(group2)))*2*nS
connect_random() also accepts functional arguments for the
weights and connection probability. For that method, it is possible to pass a function
with no argument, as in the following example:
Here each synaptic weight is random (between 0 and 1 nS). Alternatively, the connection probability can also be a function, e.g.:
The weight or the connection probability may both be functions (with 0 or 2 arguments).
Transmission delays can be introduced with the keyword
delay, passed at initialisation time.
There are two types of delays, homogeneous (all synapses have the same delay) and heterogeneous
(all synapses can have different delays). The former is more computationally efficient than the
latter. An example of homogeneous delays:
If you have limited heterogeneity, you can use several Connection objects, e.g.:
For a highly heterogeneous set of delays, initialise the connection with
a maximum delay with for example
then use the
delay keyword in the
The code above initialises the delays uniformly randomly between 0ms and 5ms. You can also
delay to be a function of no variables, where it will be called once for each synapse,
or of two variables
i, j where it will be called once for each row, as in the case of the
weights in the section above.
Alternatively, you can set the delays as follows:
myconnection.delay[i,j] = 3*ms
The underlying data structure used to store the synaptic connections is by default a sparse matrix. If the connections are dense, it is more efficient to use a dense matrix, which can be set at initialisation time:
The sparse matrix structure is fixed during a run, new synapses cannot be added or deleted,
but there is a dynamic sparse matrix structure. It is less computationally efficient, but
allows runtime adding and deleting of synaptic connections. Use the
keyword. For more details see the reference documentation for
The synaptic weights can be modulated by a state variable of the presynaptic neurons with
When a spike is produced by a presynaptic neuron (
group1), the variable ge of each postsynaptic
group2) is incremented by the synaptic weight multiplied by the value of the variable u
of the presynaptic neuron. This is useful to implement short-term plasticity.
In some cases, it is useful to connect a group directly to another one, in a one-to-one fashion.
The most efficient way to implement it is with the class
With this structure, the synaptic weights are homogeneous (it is not possible to define them
independently). When neuron i from
group1 spikes, the variable ge of neuron i from
is increased by 1 nS. A typical application is when defining inputs to a network.
If your connection just connects one group to another in a simple way, you can initialise
the weights and delays at the time you initialise the
Connection object by using
delay keywords. For example:
myconnection = Connection(group1, group2, 'ge', weight=1*nS, sparseness=0.1, delay=(0*ms, 5*ms), max_delay=5*ms)
This would be equivalent to:
myconnection = Connection(group1, group2, 'ge', delay=True, max_delay=5*ms) myconnection.connect_random(group1, group2, weight=1*nS, delay=(0*ms, 5*ms))
sparseness value is omitted or set to value 1, full connectivity is assumed,
otherwise random connectivity.
NOTE: in this case the
delay keyword used without the
weight keyword has no effect.