Connections¶
Note
Consider using the newer Synapses
class instead of
Connection
, in particular when you are modelling plastic
connections.
Building connections¶
First, one must define which neuron groups are connected and which state variable receives the spikes. The following instruction:
myconnection=Connection(group1,group2,'ge')
defines a connection from group group1
to group2
, acting on variable ge
. When
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:
myconnection[2,5]=3*nS
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 (ge
).
The matrix of synaptic weights can be defined directly with the method Connection.connect()
:
W=rand(len(group1),len(group2))*nS
myconnection.connect(group1,group2,W)
Here a matrix with random elements is used to define the synaptic weights from group1
to group2
. It is possible to build the matrix by block by using subgroups, e.g.:
W=rand(20,30)*nS
myconnection.connect(group1[0:20],group2[10:40],W=W)
There are several handy functions available to set the synaptic weights:
connect_full()
, connect_random()
and
connect_one_to_one()
. The first one
is used to set uniform weights for all pairs of neurons in the (sub)groups:
myconnection.connect_full(group1[0:20],group2[10:40],weight=5*nS)
The second one is used to set uniform weights for random pairs of neurons in the (sub)groups:
myconnection.connect_random(group1[0:20],group2[10:40],sparseness=0.02,weight=5*nS)
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 fixed=True
(probability * number of neurons in group1
).
Finally, the method connect_one_to_one()
connects neuron i from the first
group to neuron i from the second group:
myconnection.connect_one_to_one(group1,group2,weight=3*nS)
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.:
myconnection.connect_full(weight=5*nS)
connects group1
to 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 connect_full()
and connect_random()
.
The function must return the synaptic weight for a given pair of neuron (i,j).
For example:
myconnection.connect_full(group1,group2,weight=lambda i,j:(1+cos(i-j))*2*nS)
where i (j) indexes neurons in group1
(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
The method 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:
myconnection.connect_random(group1,group2,0.1,weight=lambda:rand()*nS)
Here each synaptic weight is random (between 0 and 1 nS). Alternatively, the connection probability can also be a function, e.g.:
myconnection.connect_random(group1,group2,0.1,weight=1*nS,sparseness=lambda i,j:exp(-abs(i-j)*.1))
The weight or the connection probability may both be functions (with 0 or 2 arguments).
Delays¶
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:
myconnection=Connection(group1,group2,'ge',delay=3*ms)
If you have limited heterogeneity, you can use several Connection objects, e.g.:
myconnection_fast=Connection(group1,group2,'ge',delay=1*ms)
myconnection_slow=Connection(group1,group2,'ge',delay=5*ms)
For a highly heterogeneous set of delays, initialise the connection with delay=True
, set
a maximum delay with for example max_delay=5*ms
and
then use the delay
keyword in the connect_random()
and
connect_full()
methods:
myconnection=Connection(group1,group2,'ge',delay=True,max_delay=5*ms)
myconnection.connect_full(group1,group2,weight=3*nS,delay=(0*ms,5*ms))
The code above initialises the delays uniformly randomly between 0ms and 5ms. You can also
set 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
See the reference documentation for Connection
and DelayConnection
for
more details.
Connection structure¶
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:
myconnection=Connection(group1,group2,'ge',structure='dense')
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 structure='dynamic'
keyword. For more details see the reference documentation for Connection
.
Modulation¶
The synaptic weights can be modulated by a state variable of the presynaptic neurons with
the keyword modulation
:
myconnection=Connection(group1,group2,'ge',modulation='u')
When a spike is produced by a presynaptic neuron (group1
), the variable ge of each postsynaptic
neuron (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.
Direct connection¶
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 IdentityConnection
:
myconnection=IdentityConnection(group1,group2,'ge',weight=1*nS)
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 group2
is increased by 1 nS. A typical application is when defining inputs to a network.
Simple connections¶
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
the weight
, sparseness
and 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))
If the 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.