Working with connections¶
Here, we describe how to inspect and modify already created connections. Connectivity concepts describes how to create new connections (for using an external library see Connection generator interface) and Synapse specification how to parameterize synapses as they are created.
Just like a NodeCollection is a container for node IDs, a SynapseCollection is a
container for connections. In NEST 3, when you call GetConnections()
a
SynapseCollection is returned. SynapseCollections support a lot of the same operations
as NodeCollections.
SynapseCollection
supports:
Getting the size
len
Note
We now make consistent use of term synapse_model
throughout NEST 3 in reference to synapse models.
Most importantly, this will change your Connect
call, where instead of passing the synapse
model with the model
key, you should now use the synapse_model
key.
>>> nrns = nest.Create('iaf_psc_alpha', 3)
>>> nest.Connect(nrns, nrns, 'one_to_one', syn_spec={'synapse_model': 'stdp_synapse'})
Similarly, the dictionary GetDefaults
returns an entry called synapsemodel
, which is now called
synapse_model
.
See also
You can find a full SynapseCollection example on our example network page.
- Printing
Printing a SynapseCollection produces a table with source and target node IDs, synapse model, weight and delay. If your SynapseCollection has more than 36 elements, only the first and last 15 connections are displayed. To print all, first set
print_full = True
on your SynapseCollection.>>> nest.Connect(nodes[:2], nodes[:2]) >>> synapses = nest.GetConnections() >>> print(synapses) source target synapse model weight delay -------- -------- --------------- -------- ------- 1 1 static_synapse 1.000 1.000 1 2 static_synapse 1.000 1.000 2 1 static_synapse 1.000 1.000 2 2 static_synapse 1.000 1.000
>>> synapses.print_full = True
- Indexing
Indexing returns a single connection SynapseCollection.
>>> print(synapses[1]) source target synapse model weight delay -------- -------- --------------- -------- ------- 1 2 static_synapse 1.000 1.000
- Iteration
A SynapseCollection can be iterated, yielding a single connection SynapseCollection per iteration.
>>> for conn in synapses: >>> print(conn.source) 1 1 2 2
- Iterator of sources and targets
Calling
SynapseCollection.sources()
orSynapseCollection.targets()
returns an iterator over the source IDs or target IDs, respectively.>>> print([s for s in synapses.sources()]) [1, 1, 2, 2]
- Slicing
A SynapseCollection can be sliced with
start:stop:step
inside brackets>>> print(synapses[0:3:2]) source target synapse model weight delay -------- -------- --------------- -------- ------- 1 1 static_synapse 1.000 1.000 2 1 static_synapse 1.000 1.000
- Getting the size
We can get the number of connections in the SynapseCollection with
>>> len(synapses) 4
- Test of equality
Two SynapseCollections can be tested for equality, i.e. that they contain the same connections.
>>> synapses == synapses True >>> synapses[:2] == synapses[2:] False
- Setting and getting attributes directly
You can also directly get and set parameters of your SynapseCollection
>>> synapses.weight = 5.0 >>> synapses.weight [5.0, 5.0, 5.0, 5.0] >>> synapses.delay = [5.1, 5.2, 5.3, 5.4] >>> synapses.delay [5.1, 5.2, 5.3, 5.4]
If you use a list to set the parameter, the list needs to be the same length as the SynapseCollection.
For spatially distributed sources and targets, you can access the distance between the source-target pairs by calling
distance
on your SynapseCollection.>>> synapses.distance (0.47140452079103173, 0.33333333333333337, 0.4714045207910317, 0.33333333333333337, 3.925231146709438e-17, 0.33333333333333326, 0.4714045207910317, 0.33333333333333326, 0.47140452079103157)
- Getting connection parameters
Just as with NodeCollection, you can get parameters of the connections with
get()
. The same function arguments as for NodeCollections get() apply here. The returned values also follow the same rules.If you call
get()
without any arguments, a dictionary with all parameters is returned. If there is only a single connection in the SynapseCollection, the dictionary contains plain values, whereas if there is more than one connection, the dictionary contains lists of values.>>> synapses.get() {'delay': [1.0, 1.0, 1.0, 1.0], 'port': [0, 1, 2, 3], 'receptor': [0, 0, 0, 0], 'sizeof': [32, 32, 32, 32], 'source': [1, 1, 2, 2], 'synapse_id': [0, 0, 0, 0], 'synapse_model': ['static_synapse','static_synapse','static_synapse','static_synapse'], 'target': [1, 2, 1, 2], 'target_thread': [0, 0, 0, 0], 'weight': [1.0, 1.0, 1.0, 1.0]}
Calling
get(parameter_name)
will return a list of parameter values, whileget([parameter_name_1, ... , parameter_name_n])
returns a dictionary with the values.>>> synapses.get('weight') [1.0, 1.0, 1.0, 1.0]
>>> synapses[2].get(['source', 'target']) {'source': 2, 'target': 1}
It is also possible to select an alternative output format with the
output
keyword. Currently, it is possible to get the output as JSON or as a Pandas dataframe (if Pandas is installed).
- Setting connection parameters
Likewise, you can set the parameters of connections in the SynapseCollection. Again the same rules as with
set()
on NodeCollection applies, see Set node properties for more details.If you want to set several parameters at once, use
set(parameter_dictionary)
. You can use a single value, a list, or anest.Parameter
as values. If a single value is given, the value is set on all connections.>>> synapses.set({'weight': [1.5, 2.0, 2.5, 3.0], 'delay': 2.0})
Updating a single parameter is done by calling
set(parameter_name=parameter_value)
. Again you can use a single value, a list, or anest.Parameter
as value.>>> synapses.set(weight=3.7)
>>> synapses.set(weight=[4.0, 4.5, 5.0, 5.5])
Note that some parameters, like
source
andtarget
, cannot be set. The documentation of a specific model will point out which parameters can be set and which are read-only.
Collocated synapses¶
It is now possible to create connections with several synapses simultaneously. The different synapse dictionaries will
then be applied to each source-target pair. To create these collocated synapses, CollocatedSynapses
must be used
as the syn_spec
argument of Connect()
, instead of the usual syn_spec dictionary argument. The constructor
CollocatedSynapses()
takes dictionaries as arguments.
nodes = nest.Create('iaf_psc_alpha', 3)
syn_spec = nest.CollocatedSynapses({'weight': 4., 'delay': 1.5},
{'synapse_model': 'stdp_synapse'},
{'synapse_model': 'stdp_synapse', 'alpha': 3.})
nest.Connect(nodes, nodes, conn_spec='one_to_one', syn_spec=syn_spec)
conns = nest.GetConnections()
print(conns.alpha)
This will create 9 connections: 3 using static_synapse with a weight
of 4 and delay
of 1.5, and 6 using
the stdp_synapse. Of the 6 using stdp_synapse
, 3 will have the default alpha value, and 3 will have an alpha of
3.0.
>>> print(nest.GetKernelStatus('num_connections'))
9
If you want to connect with different receptor types, you can do the following:
src = nest.Create('iaf_psc_exp_multisynapse', 7)
trgt = nest.Create('iaf_psc_exp_multisynapse', 7, {'tau_syn': [0.1 + i for i in range(7)]})
syn_spec = nest.CollocatedSynapses({'weight': 5.0, 'receptor_type': 2},
{'weight': 1.5, 'receptor_type': 7})
nest.Connect(src, trgt, 'one_to_one', syn_spec=syn_spec)
conns = nest.GetConnections()
print(conns.get())
You can see how many synapse parameters you have by calling len()
on your CollocatedSynapses
object:
>>> len(syn_spec)
2
New functionality for connecting arrays of node IDs¶
While you should aim to use NodeCollections to create connections whenever possible,
there may be cases where you have a predefined set of pairs of pre- and postsynaptic nodes.
In those cases, it may be inefficient to convert the individual IDs in the pair to NodeCollections
to be passed to the Connect()
function, especially if there are thousands or millions of
pairs to connect.
To efficiently create connections in these cases, you can pass NumPy arrays to Connect()
.
This variant of Connect()
will create connections in a one-to-one fashion.
nest.Create('iaf_psc_alpha', 10)
# Node IDs in the arrays must address existing nodes, but may occur multiple times.
sources = np.array([1, 5, 7, 5], dtype=np.uint64)
targets = np.array([2, 2, 4, 4], dtype=np.uint64)
nest.Connect(sources, targets, conn_spec="one_to_one")
You can also specify weights, delays, and receptor type for each connection as arrays.
All arrays have to have lengths equal to those of sources
and targets
.
weights = np.array([0.5, 0.5, 2., 2.])
delays = np.array([1., 1., 2., 2.])
syn_spec = {'weight': weights, 'delay': delays}
nest.Connect(sources, targets, conn_spec='one_to_one', syn_spec=syn_spec)