# Graph generation#

This page gives example on how to generate increasingly complex network structures. The example files can be found at: docs/examples/simple_graphs.py, docs/examples/multi_groups_network.py, docs/examples/basic_nest_network.py, and docs/examples/nest_receptor_ports.py.

**Content:**

## Principle#

In order to keep the code as generic and easy to maintain as possible, the generation of graphs or networks is divided in several steps:

**Structured connectivity:**a simple graph is generated as an assembly of nodes and edges, without any biological properties. This allows us to implement known graph-theoretical algorithms in a straightforward fashion.**Populations:**detailed properties can be implemented, such as inhibitory synapses and separation of the neurons into inhibitory and excitatory populations – these can be done while respecting user-defined constraints.**Synaptic properties:**eventually, synaptic properties such as weight/strength and delays can be added to the network.

## Modularity#

The library as been designed so that these various operations can be realized in any order!

- Juste to get work on a topological graph/network:
Create graph class

Connect

Set connection weights (optional)

Spatialize (optional)

Set types (optional: to use with NEST)

- To work on a really spatially embedded graph/network:
Create spatial graph/network

Connect (can depend on positions)

Set connection weights (optional, can depend on positions)

Set types (optional)

- Or to model a complex neural network in NEST:
Create spatial network (with space and neuron types)

Connect (can depend on types and positions)

Set connection weights and types (optional, can depend on types and positions)

## Setting weights#

The weights can be either user-defined or generated by one of the available distributions (Attributes and distributions). User-defined weights are generated via:

a list of edges

a list of weights

Pre-defined distributions require the following variables:

a distribution name (“constant”, “gaussian”…)

a dictionary containing the distribution properties

an optional attribute for distributions that are correlated to another (e.g. the distances between neurons)

a optional value defining the variance of the Gaussian noise that should be applied on the weights

There are several ways of settings the weights of a graph which depend on the time at which you assign them.

- At graph creation
You can define the weights by entering a

`weights`

argument to the constructor; this should be a dictionary containing at least the name of the weight distribution:`{"distrib": "distribution_name"}`

. If entered, this will be stored as a graph property and used to assign the weights whenever new edges are created unless you specifically assign rules for those new edges’ weights.- At any given time
You can use the

`set_weights()`

function to set the weights of a`graph`

explicitely by using:

```
graph.set_weights(elist=edges_to_weigh, distrib="distrib_of_choice", ...)
```

For more details on weights, other attributes, and available distributions, see Properties of graph components.

## Examples#

```
import nngt
import nngt.generation as ng
```

### Simple generation#

```
num_nodes = 1000
avg_deg_er = 25
avg_deg_sf = 100
# random graphs
g1 = ng.erdos_renyi(nodes=num_nodes, avg_deg=avg_deg_er)
# the same graph but undirected
g2 = ng.erdos_renyi(nodes=num_nodes, avg_deg=avg_deg_er, directed=False)
# 2-step generation of a scale-free with Gaussian weight distribution
w = {
"distribution": "gaussian",
"avg": 60.,
"std": 5.
}
g3 = nngt.Graph(num_nodes, weights=w)
ng.random_scale_free(2.2, 2.9, avg_deg=avg_deg_sf, from_graph=g3)
# same in 1 step
g4 = ng.random_scale_free(
2.2, 2.9, avg_deg=avg_deg_sf, nodes=num_nodes, weights=w)
```

### Networks composed of heterogeneous groups#

```
'''
Make the population
'''
# two groups
g1 = nngt.Group(500) # nodes 0 to 499
g2 = nngt.Group(500) # nodes 500 to 999
# make structure
struct = nngt.Structure.from_groups((g1, g2), ("left", "right"))
# create network from this population
net = nngt.Graph(structure=struct)
'''
Connect the groups
'''
# inter-groups (Erdos-Renyi)
prop_er1 = {"density": 0.005}
ng.connect_groups(net, "left", "right", "erdos_renyi", **prop_er1)
# intra-groups (Newman-Watts)
prop_nw = {
"coord_nb": 20,
"proba_shortcut": 0.1,
"reciprocity_circular": 1.
}
ng.connect_groups(net, "left", "left", "newman_watts", **prop_nw)
ng.connect_groups(net, "right", "right", "newman_watts", **prop_nw)
```

### Use with NEST#

Generating a network with excitatory and inhibitory neurons:

```
'''
Build a network with two populations:
* excitatory (80%)
* inhibitory (20%)
'''
num_nodes = 1000
# 800 excitatory neurons, 200 inhibitory
net = nngt.Network.exc_and_inhib(num_nodes, ei_ratio=0.2)
'''
Connect the populations.
'''
# exc -> inhib (Erdos-Renyi)
ng.connect_neural_types(net, 1, -1, "erdos_renyi", density=0.035)
# exc -> exc (Newmann-Watts)
prop_nw = {
"coord_nb": 10,
"proba_shortcut": 0.1,
"reciprocity_circular": 1.
}
ng.connect_neural_types(net, 1, 1, "newman_watts", **prop_nw)
# inhib -> exc (Random scale-free)
prop_rsf = {
"in_exp": 2.1,
"out_exp": 2.6,
"density": 0.2
}
ng.connect_neural_types(net, -1, 1, "random_scale_free", **prop_rsf)
# inhib -> inhib (Erdos-Renyi)
```

Send the network to NEST:

```
if nngt.get_config('with_nest'):
import nest
import nngt.simulation as ns
'''
Prepare the network and devices.
'''
# send to NEST
gids = net.to_nest()
# excite
ns.set_poisson_input(gids, rate=100000.)
# record
groups = [key for key in net.population]
recorder, record = ns.monitor_groups(groups, net)
'''
Simulate and plot.
'''
simtime = 100.
nest.Simulate(simtime)
if nngt.get_config('with_plot'):
ns.plot_activity(
recorder, record, network=net, show=True, limits=(0,simtime))
```

You can check that connections from neurons that are marked as inhibitory are automatically assigned a negative sign in NEST:

```
# sign of NNGT versus NEST inhibitory connections
igroup = net.population["inhibitory"]
# in NNGT
iedges = net.get_edges(source_node=igroup.ids)
w_nngt = set(net.get_weights(edges=iedges))
# in NEST
try:
# nest 2
iconn = nest.GetConnections(
source=list(net.population["inhibitory"].nest_gids),
```

Returns: `NNGT weights: {1.0} versus NEST weights {-1.0}`

.

## Advanced examples#

### Receptor ports in NEST#

Some models, such as multisynaptic neurons, or advanced models incorporating
various neurotransmitters use an additional information, called `"port"`

to
identify the synapse that will be used by the `nest.Connect`

method.
These models can also be used with NNGT by telling the
`NeuralGroup`

which type of port the neuron should try to bind to.

NB: the port is specified in the **source** neuron and declares which synapse
of the **target** neuron is concerned.

```
'''
Build a network with two populations:
* excitatory (80%)
* inhibitory (20%)
'''
num_neurons = 50 # number of neurons
avg_degree = 20 # average number of neighbours
std_degree = 3 # deviation for the Gaussian graph
# parameters
neuron_model = "ht_neuron" # hill-tononi model
exc_syn = {'receptor_type': 1} # 1 is 'AMPA' in this model
inh_syn = {'receptor_type': 3} # 3 is 'GABA_A' in this model
synapses = {
(1, 1): exc_syn,
(1, -1): exc_syn,
(-1, 1): inh_syn,
(-1, -1): inh_syn,
}
pop = nngt.NeuralPop.exc_and_inhib(
num_neurons, en_model=neuron_model, in_model=neuron_model,
syn_spec=synapses)
# create the network and send it to NEST
w_prop = {"distribution": "gaussian", "avg": 0.2, "std": .05}
net = nngt.generation.gaussian_degree(
avg_degree, std_degree, population=pop, weights=w_prop)
'''
Send to NEST and set excitation and recorders
'''
if nngt.get_config('with_nest'):
import nest
import nngt.simulation as ns
nest.ResetKernel()
gids = net.to_nest()
# add noise to the excitatory neurons
excs = list(pop["excitatory"].nest_gids)
inhs = list(pop["inhibitory"].nest_gids)
ns.set_noise(excs, 10., 2.)
ns.set_noise(inhs, 5., 1.)
# record
groups = [key for key in net.population]
recorder, record = ns.monitor_groups(groups, net)
'''
Simulate and plot.
'''
simtime = 2000.
nest.Simulate(simtime)
if nngt.get_config('with_plot'):
ns.plot_activity(
recorder, record, network=net, show=True, histogram=False,
limits=(0, simtime))
```

**Go to other tutorials:**