================
Graph generation
================

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:
    1) Create graph class
    2) Connect
    3) Set connection weights (optional)
    4) Spatialize (optional)
    5) Set types (optional: to use with NEST)

To work on a really spatially embedded graph/network:
    1) Create spatial graph/network
    2) Connect (can depend on positions)
    3) Set connection weights (optional, can depend on positions)
    4) Set types (optional)

Or to model a complex neural network in NEST:
    1) Create spatial network (with space and neuron types)
    2) Connect (can depend on types and positions)
    3) 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 (MAKE A REF).
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 ``weight_prop`` 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 :class:`~nngt.Connections` class to set the weights of a ``graph`` explicitely by using:

    >>> nngt.Connections.weights(graph, elist=edges_to_weigh, distrib="distrib_of_choice", ...)


Examples
========

.. code-block:: python

	import nngt
	import nngt.generation as ng


Simple generation
-----------------

.. literalinclude:: ../examples/simple_graphs.py
   :lines: 31-49


Networks composed of heterogeneous groups
-----------------------------------------

.. literalinclude:: ../examples/multi_groups_network.py
   :lines: 30-64


Use with NEST
-------------

Generating a network with excitatory and inhibitory neurons:

.. literalinclude:: ../examples/basic_nest_network.py
   :lines: 37-64

Send the network to NEST:

.. literalinclude:: ../examples/basic_nest_network.py
   :lines: 71-


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 :class:`~nngt.core.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.


.. literalinclude:: ../examples/nest_receptor_ports.py
   :lines: 27-
