# Connection concepts in NEST

In the previous post, we learned about the basic concepts of the NEST simulator and how to create a simple single neuron model. This time, we will take a closer look at the connection concepts in NEST, which are crucial for building more complex neural networks.

## Introduction

Connectionsꜛ in NEST are created via the

```
nest.Conncetion(pre, post, conn_spec, syn_spec)
```

commandꜛ, where `pre`

and `post`

are the pre- and post-synaptic nodes (e.g., single neurons or neuron populations), respectively. The `conn_spec`

and `syn_spec`

arguments define the connection rule and the synapse model, respectively. If the latter two are omitted, the default `all_to_all`

connection and the default `static_synapse`

ꜛ are used. The static synapse is a synapse, where the synaptic strength (or weight) does not evolve over time and remains at a defined constant value.

`conn_spec`

expects a connection rule alongside additional rule-specific parameters (if any). The following connection rules are available:

`all_to_all`

(default)`one_to_one`

`pairwise_bernoulli`

(parameter:`p`

)`symmetric_pairwise_bernoulli`

(parameter:`p`

)`pairwise_poisson`

(parameter:`pairwise_avg_num_conns`

)`fixed_indegree`

(parameter:`indegree`

)`fixed_outdegree`

(parameter:`outdegree`

)`fixed_total_number`

(parameter:`N`

)

For instance, connection using the `pairwise_bernoulli`

rule would look like this:

```
n = 5
m = 5
p = 0.5
S = nest.Create('iaf_psc_alpha', n)
T = nest.Create('iaf_psc_alpha', m)
conn_spec = {'rule': 'pairwise_bernoulli', 'p': p}
nest.Connect(S, T, conn_spec)
```

The chosen synapse model (`syn_spec`

) along with its parameters such as the synaptic weight, delay, and model-specific parameters controls the strength of the connection between the pre- and post-synaptic neurons. The synaptic weight determines how strongly a spike from a presynaptic neuron affects the postsynaptic neuron. Thus, it quantifies the efficacy of the synapse in transmitting the signal. An exemplary `syn_spec`

definition looks like this:

```
n = 10
neuron_dict = {'tau_syn': [0.3, 1.5]}
A = nest.Create('iaf_psc_exp_multisynapse', n, neuron_dict)
B = nest.Create('iaf_psc_exp_multisynapse', n, neuron_dict)
syn_spec_dict ={'synapse_model': 'static_synapse',
'weight': 2.5,
'delay': 0.5,
'receptor_type': 1}
nest.Connect(A, B, syn_spec=syn_spec_dict)
```

Further details on synapse specification can be found in the NEST documentationꜛ.

In the following, we will discuss the different connection concepts in more detail. For consistency, we will call a single neuron a “node” and a collection of nodes a “node collection” (or just collection). Pre- and postsynaptic node collections are further referred to as $S$ and $T$ for the source and target node collections, respectively. A single connection between two nodes is called an *edge*, while a group of edges that connect groups of nodes with similar properties (i.e, populations) is called a *projection*. In these terms, the `nest.Conncetion()`

function establishes a projection between the source and target node collection.

## Connection rules

### Autapses and multapses

The `conn_spec`

argument can receive two additional parameters, `autapses`

and `multapses`

. Autapases are self-conncetions of a node and multapses are multiple connections between the same pair of nodes:

`autapses`

and `multapses`

are both set to `True`

by default.

### All to all

The `all_to_all`

connection rule connects all pre-synaptic nodes (source) to all post-synaptic nodes (target). This is the default connection rule in NEST. The `all_to_all`

rule does not require any additional parameters.

Example:

```
n = 5
m = 5
S = nest.Create('iaf_psc_alpha', n)
T = nest.Create('iaf_psc_alpha', m)
nest.Connect(S, T, 'all_to_all')
nest.Connect(S, T) # this is equivalent
```

To explicitly connect source and target nodes, the respective node IDs from the node collections must be extracted and then be connected using the one-to-one connection rule. For instance, in the following example we connect the 3rd, 4th, and 1st source nodes to the 8th, 6th, and 9th target nodes, respectively:

```
n = 5
m = 5
S = nest.Create('iaf_psc_alpha', n) # node ids: 1..5
T = nest.Create('iaf_psc_alpha', m) # node ids: 6..10
# source-target pairs: (3,8), (4,1), (1,9)
nest.Connect([3,4,1], [8,6,9], 'one_to_one')
```

### One to one

The `one_to_one`

connection rule connects each pre-synaptic node to exactly one post-synaptic node, i.e., the $i$-th source node in the source node collection $S$ is connected to the $i$-th target node in the target node collection $T$. The number of pre- and post-synaptic nodes must be equal. The `one_to_one`

rule does not require any additional parameters.

Example:

```
n = 5
S = nest.Create('iaf_psc_alpha', n)
T = nest.Create('spike_recorder', n)
nest.Connect(S, T, 'one_to_one')
```

**Deterministic connection rules**: Both `all_to_all`

and `one_to_one`

are deterministic connection rules, i.e., precisely defined sets of connections are established between the source and target nodes without any randomness or variability across network realizations.

**Probabilistic connection rules**: In contrast, probabilistic connection rules such as `pairwise_bernoulli`

or `pairwise_poisson`

establish connections between the source and target nodes based on a probabilistic rule. This leads to variability in the network structure across different network realizations. However, such connectivity leads to specific expectation values of network characteristics, such as degree distributions or correlation structure.

### Pairwise Bernoulli

The `pairwise_bernoulli`

connection rule establishes connections between the source and target nodes based on a Bernoulli process. The probability `p`

of establishing a connection between any pair of nodes is given as an additional parameter. The `pairwise_bernoulli`

rule requires the parameter `p`

to be set. Multapses cannot be established with this rule as each possible edge is visited only once, independent of setting `allow_multapses`

to `True`

.

Example:

```
n = 5
m = 5
p = 0.5
S = nest.Create('iaf_psc_alpha', n)
T = nest.Create('iaf_psc_alpha', m)
conn_spec = {'rule': 'pairwise_bernoulli', 'p': p}
nest.Connect(S, T, conn_spec)+
```

### Symmetric pairwise Bernoulli

The `symmetric_pairwise_bernoulli`

connection rule is similar to the `pairwise_bernoulli`

rule, but it ensures that the connection matrix is symmetric. This means that if node $i$ is connected to node $j$, then node $j$ is also connected to node $i$ (two connections in total). To use this rule, `allow_autapses`

must be `False`

the and `make_symmetric`

argument must be set to `True`

.

Example:

```
n = 10
m = 12
p = 0.2
S = nest.Create('iaf_psc_alpha', n)
T = nest.Create('iaf_psc_alpha', m)
conn_spec = {'rule': 'symmetric_pairwise_bernoulli', 'p': p,
'allow_autapses': False, 'make_symmetric': True}
nest.Connect(S, T, conn_spec)
```

### Pairwise Poisson

The `pairwise_poisson`

connection rule establishes connections between the source and target nodes based on a Poisson distribution. The average number of connections `pairwise_avg_num_conns`

is given as an additional parameter. Multiple connections between the same pair of nodes are possible, even for a small average number of connections. Thus, multapses can be established and `allow_multapses`

can not be `False`

.

Example:

```
n = 10
m = 12
p_avg_num_conns = 0.2 # can be greater than 1
S = nest.Create('iaf_psc_alpha', n)
T = nest.Create('iaf_psc_alpha', m)
conn_spec = {'rule': 'pairwise_poisson',
'pairwise_avg_num_conns': p_avg_num_conns}
nest.Connect(S, T, conn_spec)
```

### Random, fixed total number

The `fixed_total_number`

connection rule randomly establishes a fixed number of total connections between the source and target nodes. The number of connections `N`

is given as an additional parameter and must be specified. While multapses can be established with this rule, you can also disable them by setting `allow_multapses`

to `False`

.

Example:

```
n = 5
m = 5
N = 10
S = nest.Create('iaf_psc_alpha', n)
T = nest.Create('iaf_psc_alpha', m)
conn_spec = {'rule': 'fixed_total_number', 'N': N}
nest.Connect(S, T, conn_spec)
```

### Random, fixed in-degree

The `fixed_indegree`

connection rule randomly establishes a fixed number of incoming connections to each target node. The number of incoming connections `indegree`

is given as an additional parameter and must be specified. While multapses can be established with this rule, you can also disable them by setting `allow_multapses`

to `False`

.

Example:

```
n = 5
m = 5
N = 2
S = nest.Create('iaf_psc_alpha', n)
T = nest.Create('iaf_psc_alpha', m)
conn_spec = {'rule': 'fixed_indegree', 'indegree': N}
nest.Connect(S, T, conn_spec)
```

### Random, fixed out-degree

The `fixed_outdegree`

connection rule randomly establishes a fixed number of outgoing connections from each source node. The number of outgoing connections `outdegree`

is given as an additional parameter and must be specified. While multapses can be established with this rule, you can also disable them by setting `allow_multapses`

to `False`

.

Example:

```
n = 5
m = 5
N = 2
S = nest.Create('iaf_psc_alpha', n)
T = nest.Create('iaf_psc_alpha', m)
conn_spec = {'rule': 'fixed_outdegree', 'indegree': N}
nest.Connect(S, T, conn_spec)
```

### Tripartite Bernoulli with pool

For each possible pair of nodes from a source node collection $S$ and a target node collection $T$, a primary connection is created with probability `p_primary`

. For each primary connection, a third-party connection pair involving a node from a third node collection, e.g., an astrocyte population $A$, is created with the conditional probability `p_third_if_primary`

. This connection pair includes a connection from the $S$ node to the $A$ node, and a connection from the $A$ node to the $T$ node. The $A$ node to connect to is chosen at random from a pool, a subset of the nodes in $A$. By default, this pool is all of $A$.

The `pool_type`

parameter controlls the pool formation and can be `random`

(default) or `block`

. The `pool_size`

parameter must be between 1 and the size of $A$ (default). For random pools, for each node from $T$, `pool_size`

nodes from $A$ are chosen randomly without replacement.

For block pools, two variants exist. Let `N_T`

and `N_A`

be the number of nodes in $T$ and $A$, respectively. If `pool_size == 1`

, the first `N_T/N_A`

nodes in $T$ are assigned the first node in $A$ as their pool, the second `N_T/N_A`

nodes in $T$ the second node in $A$ and so forth. In this case, `N_T`

must be a multiple of `N_A`

. If `pool_size > 1`

, the first `pool_size`

elements of $A$ are the pool for the first node in $T$, the second `pool_size`

elements of $A$ are the pool for the second node in $T$ and so forth. In this case, `N_T * pool_size == N_A`

is required.

The corresponding code snippet for each of the presented cases above is:

```
# left plot: random pool
N_S = 6
N_T = 6
N_A = 3
p_primary = 0.2
p_third_if_primary = 1.0
pool_type = 'random'
pool_size = 2
S = nest.Create('aeif_cond_alpha_astro', N_S)
T = nest.Create('aeif_cond_alpha_astro', N_T)
A = nest.Create('astrocyte_lr_1994', N_A)
conn_spec = {'rule': 'tripartite_bernoulli_with_pool',
'p_primary': p_primary,
'p_third_if_primary': p_third_if_primary,
'pool_type': pool_type,
'pool_size': pool_size}
syn_specs = {'third_out': 'sic_connection'}
nest.TripartiteConnect(S, T, A, conn_spec, syn_specs)
```

```
# middle plot: block pool, pool_size = 1
N_S = 6
N_T = 6
N_A = 3
p_primary = 0.2
p_third_if_primary = 1.0
pool_type = 'block'
pool_size = 1
S = nest.Create('aeif_cond_alpha_astro', N_S)
T = nest.Create('aeif_cond_alpha_astro', N_T)
A = nest.Create('astrocyte_lr_1994', N_A)
conn_spec = {'rule': 'tripartite_bernoulli_with_pool',
'p_primary': p_primary,
'p_third_if_primary': p_third_if_primary,
'pool_type': pool_type,
'pool_size': pool_size}
syn_specs = {'third_out': 'sic_connection'}
nest.TripartiteConnect(S, T, A, conn_spec, syn_specs)
```

```
# right plot: block pool, pool_size > 1
N_S = 6
N_T = 3
N_A = 6
p_primary = 0.2
p_third_if_primary = 1.0
pool_type = 'block'
pool_size = 2
S = nest.Create('aeif_cond_alpha_astro', N_S)
T = nest.Create('aeif_cond_alpha_astro', N_T)
A = nest.Create('astrocyte_lr_1994', N_A)
conn_spec = {'rule': 'tripartite_bernoulli_with_pool',
'p_primary': p_primary,
'p_third_if_primary': p_third_if_primary,
'pool_type': pool_type,
'pool_size': pool_size}
syn_specs = {'third_out': 'sic_connection'}
nest.TripartiteConnect(S, T, A, conn_spec, syn_specs)
```

`sic_connection`

ꜛ is a synapse model that is used to connect third-party nodes such as astrocytes to the source and target nodes.

## Conclusion

NEST allows for the creation of complex neural networks by providing a variety of connection rules. These rules can be used to establish connections between different types of nodes, such as neurons and astrocytes. The connection rules can be deterministic or probabilistic, and they can be used to create different types of network structures. By using the appropriate connection rules, you can create networks that mimic the connectivity patterns found in the brain and study the dynamics of these networks.

In the next post, we will create a simple neural network using the connection concepts discussed here and explore the dynamics of the network using the NEST simulator.

## References and useful links

- Gewaltig, M.-O., & Diesmann, M.,
*NEST (NEural Simulation Tool)*, 2007 Scholarpedia, 2(4), 1430, doi: 10.4249/scholarpedia.1430ꜛ - Documentation of the NEST simulatorꜛ
- PyNEST API listingꜛ
- List of all supported neuron and synapse models in NESTꜛ
- Connection concepts in NESTꜛ
- Synapse specification in NESTꜛ
- Senk, Kriener, Djurfeldt, Voges, Jiang, Schüttler, Gramelsberger, Diesmann, Plesser, van Albada,
*Connectivity concepts in neuronal network modeling*, 2022, PLOS Computational Biology, Vol. 18, Issue 9, pages e1010086, doi: 10.1371/journal.pcbi.1010086ꜛ - Djurfeldt,
*The Connection-set Algebra—A Novel Formalism for the Representation of Connectivity Structure in Neuronal Network Models*, 2012, Neuroinformatics, Vol. 10, Issue 3, pages 287-304, doi: 10.1007/s12021-012-9146-1 - Daniel Hjertholm,
*Statistical tests for connection algorithms for structured neural networks*, 2013, Master’s thesis, Norwegian University of Life Sciences ,Ås, Norway. PDFꜛ

## Comments

Comment on this post by publicly replying to this Mastodon post using a Mastodon or other ActivityPub/Fediverse account.

Comments on this website are based on a Mastodon-powered comment system. Learn more about it here.

There are no known comments, yet. Be the first to write a reply.