Source code for nngt.generation.graph_connectivity

#!/usr/bin/env python
#-*- coding:utf-8 -*-
#
# graph_connectivity.py
#
# This file is part of the NNGT project to generate and analyze
# neuronal networks and their activity.
# Copyright (C) 2015-2017  Tanguy Fardet
# 
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
# 
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
# 
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.

""" Connectivity generators for nngt.Graph """

from copy import deepcopy
import logging

import numpy as np

import nngt
from nngt.geometry.geom_utils import conversion_magnitude
from nngt.lib.connect_tools import _set_options
from nngt.lib.logger import _log_message
from nngt.lib.test_functions import mpi_checker, mpi_random

# do default import

from .connect_algorithms import *

# try to import multithreaded or mpi algorithms

using_mt_algorithms = False

if nngt.get_config("multithreading"):
    logger = logging.getLogger(__name__)
    try:
        from .cconnect import *
        from .connect_algorithms import price_network
        using_mt_algorithms = True
        _log_message(logger, "DEBUG",
                     "Using multithreaded algorithms compiled on install.")
        nngt.set_config('multithreading', True, silent=True)
    except Exception as e:
        try:
            import cython
            import pyximport; pyximport.install()
            from .cconnect import *
            from .connect_algorithms import price_network
            using_mt_algorithms = True
            _log_message(logger, "DEBUG", str(e) + "\n\tCompiled "
                         "multithreaded algorithms on-the-run.")
            nngt.set_config('multithreading', True, silent=True)
        except Exception as e2:
            _log_message(
                logger, "WARNING", str(e) + "\n\t" + str(e2) + "\n\t"
                "Cython import failed, using non-multithreaded algorithms.")
            nngt._config['multithreading'] = False
if nngt.get_config("mpi"):
    try:
        from .mpi_connect import *
        nngt._config['mpi'] = True
    except ImportError as e:
        nngt._config['mpi'] = False
        raise e



__all__ = [
    'all_to_all',
    'connect_neural_groups',
    'connect_neural_types',
    'connect_nodes',
	'distance_rule',
	'erdos_renyi',
    'fixed_degree',
    'gaussian_degree',
	'newman_watts',
	'random_scale_free',
	'price_scale_free',
]


# ----------------------------- #
# Specific degree distributions #
# ----------------------------- #

def all_to_all(nodes=0, weighted=True, directed=True, multigraph=False,
               name="AlltoAll", shape=None, positions=None, population=None,
               **kwargs):
    """
    Generate a graph where all nodes are connected.

    .. versionadded:: 1.0

    Parameters
    ----------
    nodes : int, optional (default: None)
        The number of nodes in the graph.
    reciprocity : double, optional (default: -1 to let it free)
        Fraction of edges that are bidirectional  (only for directed graphs
        -- undirected graphs have a reciprocity of  1 by definition)
    weighted : bool, optional (default: True)
        Whether the graph edges have weights.
    directed : bool, optional (default: True)
        Whether the graph is directed or not.
    multigraph : bool, optional (default: False)
        Whether the graph can contain multiple edges between two
        nodes.
    name : string, optional (default: "ER")
        Name of the created graph.
    shape : :class:`~nngt.geometry.Shape`, optional (default: None)
        Shape of the neurons' environment.
    positions : :class:`numpy.ndarray`, optional (default: None)
        A 2D or 3D array containing the positions of the neurons in space.
    population : :class:`~nngt.NeuralPop`, optional (default: None)
        Population of neurons defining their biological properties (to create a
        :class:`~nngt.Network`).

    Note
    ----
	`nodes` is required unless `population` is provided.

    Returns
    -------
    graph_all : :class:`~nngt.Graph`, or subclass
        A new generated graph.
    """
    nodes = nodes if population is None else population.size
    matrix = np.ones((nodes, nodes))
    graph_all = nngt.Graph(name=name, nodes=nodes, directed=directed, **kwargs)
    _set_options(graph_all, population, shape, positions)
    # add edges
    if nodes > 1:
        ids = np.arange(nodes, dtype=np.uint)
        edges = _all_to_all(ids, ids, directed, multigraph)
        graph_all.new_edges(ia_edges, check_edges=False)
    graph_all._graph_type = "all_to_all"
    return graph_all


[docs]def fixed_degree(degree, degree_type='in', nodes=0, reciprocity=-1., weighted=True, directed=True, multigraph=False, name="FD", shape=None, positions=None, population=None, from_graph=None, **kwargs): """ Generate a random graph with constant in- or out-degree. Parameters ---------- degree : int The value of the constant degree. degree_type : str, optional (default: 'in') The type of the fixed degree, among ``'in'``, ``'out'`` or ``'total'``. @todo `'total'` not implemented yet. nodes : int, optional (default: None) The number of nodes in the graph. reciprocity : double, optional (default: -1 to let it free) @todo: not implemented yet. Fraction of edges that are bidirectional (only for directed graphs -- undirected graphs have a reciprocity of 1 by definition) weighted : bool, optional (default: True) Whether the graph edges have weights. directed : bool, optional (default: True) @todo: only for directed graphs for now. Whether the graph is directed or not. multigraph : bool, optional (default: False) Whether the graph can contain multiple edges between two nodes. name : string, optional (default: "ER") Name of the created graph. shape : :class:`~nngt.geometry.Shape`, optional (default: None) Shape of the neurons' environment. positions : :class:`numpy.ndarray`, optional (default: None) A 2D or 3D array containing the positions of the neurons in space. population : :class:`~nngt.NeuralPop`, optional (default: None) Population of neurons defining their biological properties (to create a :class:`~nngt.Network`). from_graph : :class:`Graph` or subclass, optional (default: None) Initial graph whose nodes are to be connected. Note ---- `nodes` is required unless `from_graph` or `population` is provided. If an `from_graph` is provided, all preexistant edges in the object will be deleted before the new connectivity is implemented. Returns ------- graph_fd : :class:`~nngt.Graph`, or subclass A new generated graph or the modified `from_graph`. """ # set node number and library graph graph_fd = from_graph if graph_fd is not None: nodes = graph_fd.node_nb() graph_fd.clear_all_edges() else: nodes = population.size if population is not None else nodes graph_fd = nngt.Graph( name=name, nodes=nodes, directed=directed, **kwargs) _set_options(graph_fd, population, shape, positions) # add edges ia_edges = None if nodes > 1: ids = np.arange(nodes, dtype=np.uint) ia_edges = _fixed_degree(ids, ids, degree, degree_type, reciprocity, directed, multigraph) graph_fd.new_edges(ia_edges, check_edges=False) graph_fd._graph_type = "fixed_{}_degree".format(degree_type) return graph_fd
[docs]def gaussian_degree(avg, std, degree_type='in', nodes=0, reciprocity=-1., weighted=True, directed=True, multigraph=False, name="GD", shape=None, positions=None, population=None, from_graph=None, **kwargs): """ Generate a random graph with constant in- or out-degree. @todo: adapt it for undirected graphs! Parameters ---------- avg : float The value of the average degree. std : float The standard deviation of the Gaussian distribution. degree_type : str, optional (default: 'in') The type of the fixed degree, among 'in', 'out' or 'total' @todo: Implement 'total' degree nodes : int, optional (default: None) The number of nodes in the graph. reciprocity : double, optional (default: -1 to let it free) @todo: not implemented yet. Fraction of edges that are bidirectional (only for directed graphs -- undirected graphs have a reciprocity of 1 by definition) weighted : bool, optional (default: True) Whether the graph edges have weights. directed : bool, optional (default: True) @todo: only for directed graphs for now. Whether the graph is directed or not. multigraph : bool, optional (default: False) Whether the graph can contain multiple edges between two nodes. name : string, optional (default: "ER") Name of the created graph. shape : :class:`~nngt.geometry.Shape`, optional (default: None) Shape of the neurons' environment. positions : :class:`numpy.ndarray`, optional (default: None) A 2D or 3D array containing the positions of the neurons in space. population : :class:`~nngt.NeuralPop`, optional (default: None) Population of neurons defining their biological properties (to create a :class:`~nngt.Network`). from_graph : :class:`Graph` or subclass, optional (default: None) Initial graph whose nodes are to be connected. Returns ------- graph_gd : :class:`~nngt.Graph`, or subclass A new generated graph or the modified `from_graph`. Note ---- `nodes` is required unless `from_graph` or `population` is provided. If an `from_graph` is provided, all preexistant edges in the object will be deleted before the new connectivity is implemented. """ # set node number and library graph graph_gd = from_graph if graph_gd is not None: nodes = graph_gd.node_nb() graph_gd.clear_all_edges() else: nodes = population.size if population is not None else nodes graph_gd = nngt.Graph( name=name, nodes=nodes, directed=directed, **kwargs) _set_options(graph_gd, population, shape, positions) # add edges ia_edges = None if nodes > 1: ids = np.arange(nodes, dtype=np.uint) ia_edges = _gaussian_degree(ids, ids, avg, std, degree_type, reciprocity, directed, multigraph) # check for None if MPI if ia_edges is not None: graph_gd.new_edges(ia_edges, check_edges=False) graph_gd._graph_type = "gaussian_{}_degree".format(degree_type) return graph_gd
#-----------------------------------------------------------------------------# # Erdos-Renyi #------------------------ #
[docs]def erdos_renyi(density=-1., nodes=0, edges=-1, avg_deg=-1., reciprocity=-1., weighted=True, directed=True, multigraph=False, name="ER", shape=None, positions=None, population=None, from_graph=None, **kwargs): """ Generate a random graph as defined by Erdos and Renyi but with a reciprocity that can be chosen. Parameters ---------- density : double, optional (default: -1.) Structural density given by `edges / nodes`:math:`^2`. It is also the probability for each possible edge in the graph to exist. nodes : int, optional (default: None) The number of nodes in the graph. edges : int (optional) The number of edges between the nodes avg_deg : double, optional Average degree of the neurons given by `edges / nodes`. reciprocity : double, optional (default: -1 to let it free) Fraction of edges that are bidirectional (only for directed graphs -- undirected graphs have a reciprocity of 1 by definition) weighted : bool, optional (default: True) Whether the graph edges have weights. directed : bool, optional (default: True) Whether the graph is directed or not. multigraph : bool, optional (default: False) Whether the graph can contain multiple edges between two nodes. name : string, optional (default: "ER") Name of the created graph. shape : :class:`~nngt.geometry.Shape`, optional (default: None) Shape of the neurons' environment. positions : :class:`numpy.ndarray`, optional (default: None) A 2D or 3D array containing the positions of the neurons in space. population : :class:`~nngt.NeuralPop`, optional (default: None) Population of neurons defining their biological properties (to create a :class:`~nngt.Network`). from_graph : :class:`Graph` or subclass, optional (default: None) Initial graph whose nodes are to be connected. Returns ------- graph_er : :class:`~nngt.Graph`, or subclass A new generated graph or the modified `from_graph`. Note ---- `nodes` is required unless `from_graph` or `population` is provided. If an `from_graph` is provided, all preexistant edges in the object will be deleted before the new connectivity is implemented. """ # set node number and library graph graph_er = from_graph if graph_er is not None: nodes = graph_er.node_nb() graph_er.clear_all_edges() else: nodes = population.size if population is not None else nodes graph_er = nngt.Graph( name=name, nodes=nodes, directed=directed, **kwargs) _set_options(graph_er, population, shape, positions) # add edges ia_edges = None if nodes > 1: ids = range(nodes) ia_edges = _erdos_renyi(ids, ids, density, edges, avg_deg, reciprocity, directed, multigraph) graph_er.new_edges(ia_edges, check_edges=False) graph_er._graph_type = "erdos_renyi" return graph_er
# #--- # Scale-free models #------------------------
[docs]def random_scale_free(in_exp, out_exp, nodes=0, density=-1, edges=-1, avg_deg=-1, reciprocity=0., weighted=True, directed=True, multigraph=False, name="RandomSF", shape=None, positions=None, population=None, from_graph=None, **kwargs): """ Generate a free-scale graph of given reciprocity and otherwise devoid of correlations. Parameters ---------- in_exp : float Absolute value of the in-degree exponent :math:`\gamma_i`, such that :math:`p(k_i) \propto k_i^{-\gamma_i}` out_exp : float Absolute value of the out-degree exponent :math:`\gamma_o`, such that :math:`p(k_o) \propto k_o^{-\gamma_o}` nodes : int, optional (default: None) The number of nodes in the graph. density: double, optional (default: 0.1) Structural density given by `edges / (nodes*nodes)`. edges : int (optional) The number of edges between the nodes avg_deg : double, optional Average degree of the neurons given by `edges / nodes`. weighted : bool, optional (default: True) @todo Whether the graph edges have weights. directed : bool, optional (default: True) Whether the graph is directed or not. multigraph : bool, optional (default: False) Whether the graph can contain multiple edges between two nodes. can contain multiple edges between two name : string, optional (default: "ER") Name of the created graph. shape : :class:`~nngt.geometry.Shape`, optional (default: None) Shape of the neurons' environment. positions : :class:`numpy.ndarray`, optional (default: None) A 2D or 3D array containing the positions of the neurons in space. population : :class:`~nngt.NeuralPop`, optional (default: None) Population of neurons defining their biological properties (to create a :class:`~nngt.Network`) from_graph : :class:`Graph` or subclass, optional (default: None) Initial graph whose nodes are to be connected. Returns ------- graph_fs : :class:`~nngt.Graph` Note ---- As reciprocity increases, requested values of `in_exp` and `out_exp` will be less and less respected as the distribution will converge to a common exponent :math:`\gamma = (\gamma_i + \gamma_o) / 2`. Parameter `nodes` is required unless `from_graph` or `population` is provided. """ # set node number and library graph graph_rsf = from_graph if graph_rsf is not None: nodes = graph_rsf.node_nb() graph_rsf.clear_all_edges() else: nodes = population.size if population is not None else nodes graph_rsf = nngt.Graph( name=name,nodes=nodes,directed=directed,**kwargs) _set_options(graph_rsf, population, shape, positions) # add edges ia_edges = None if nodes > 1: ids = range(nodes) ia_edges = _random_scale_free(ids, ids, in_exp, out_exp, density, edges, avg_deg, reciprocity, directed, multigraph) graph_rsf.new_edges(ia_edges, check_edges=False) graph_rsf._graph_type = "random_scale_free" return graph_rsf
[docs]def price_scale_free(m, c=None, gamma=1, nodes=0, weighted=True, directed=True, seed_graph=None, multigraph=False, name="PriceSF", shape=None, positions=None, population=None, from_graph=None, **kwargs): """ @todo make the algorithm. Generate a Price graph model (Barabasi-Albert if undirected). Parameters ---------- m : int The number of edges each new node will make. c : double Constant added to the probability of a vertex receiving an edge. gamma : double Preferential attachment power. nodes : int, optional (default: None) The number of nodes in the graph. weighted : bool, optional (default: True) @todo Whether the graph edges have weights. directed : bool, optional (default: True) Whether the graph is directed or not. multigraph : bool, optional (default: False) Whether the graph can contain multiple edges between two nodes. name : string, optional (default: "ER") Name of the created graph. shape : :class:`~nngt.geometry.Shape`, optional (default: None) Shape of the neurons' environment positions : :class:`numpy.ndarray`, optional (default: None) A 2D or 3D array containing the positions of the neurons in space. population : :class:`~nngt.NeuralPop`, optional (default: None) Population of neurons defining their biological properties (to create a :class:`~nngt.Network`). from_graph : :class:`~nngt.Graph` or subclass, optional (default: None) Initial graph whose nodes are to be connected. Returns ------- graph_price : :class:`~nngt.Graph` or subclass. Note ---- `nodes` is required unless `from_graph` or `population` is provided. """ nodes = ( ( population.size if population is not None else nodes ) if from_graph is None else from_graph.node_nb() ) #~ c = c if c is not None else 0 if directed else 1 g = price_network(nodes, m, c, gamma, directed, seed_graph) graph_obj_price = nngt.Graph.from_library(g) graph_price = nngt.Graph.from_library(g) _set_options(graph_price, population, shape, positions) graph_price._graph_type = "price_scale_free" return graph_price
# #--- # Small-world models #------------------------
[docs]def newman_watts(coord_nb, proba_shortcut, nodes=0, weighted=True, directed=True,multigraph=False, name="NW", shape=None, positions=None, population=None, from_graph=None, **kwargs): """ Generate a small-world graph using the Newman-Watts algorithm. @todo generate the edges of a circular graph to not replace the graph of the `from_graph` and implement chosen reciprocity. Parameters ---------- coord_nb : int The number of neighbours for each node on the initial topological lattice. proba_shortcut : double Probability of adding a new random (shortcut) edge for each existing edge on the initial lattice. nodes : int, optional (default: None) The number of nodes in the graph. density: double, optional (default: 0.1) Structural density given by `edges` / (`nodes`*`nodes`). edges : int (optional) The number of edges between the nodes avg_deg : double, optional Average degree of the neurons given by `edges` / `nodes`. weighted : bool, optional (default: True) @todo Whether the graph edges have weights. directed : bool, optional (default: True) Whether the graph is directed or not. multigraph : bool, optional (default: False) Whether the graph can contain multiple edges between two nodes. name : string, optional (default: "ER") Name of the created graph. shape : :class:`~nngt.geometry.Shape`, optional (default: None) Shape of the neurons' environment positions : :class:`numpy.ndarray`, optional (default: None) A 2D or 3D array containing the positions of the neurons in space. population : :class:`~nngt.NeuralPop`, optional (default: None) Population of neurons defining their biological properties (to create a :class:`~nngt.Network`). from_graph : :class:`Graph` or subclass, optional (default: None) Initial graph whose nodes are to be connected. Returns ------- graph_nw : :class:`~nngt.Graph` or subclass Note ---- `nodes` is required unless `from_graph` or `population` is provided. """ # set node number and library graph graph_nw = from_graph if graph_nw is not None: nodes = graph_nw.node_nb() graph_nw.clear_all_edges() else: nodes = population.size if population is not None else nodes graph_nw = nngt.Graph(name=name,nodes=nodes,directed=directed,**kwargs) _set_options(graph_nw, population, shape, positions) # add edges ia_edges = None if nodes > 1: ids = range(nodes) ia_edges = _newman_watts(ids, ids, coord_nb, proba_shortcut, directed, multigraph) graph_nw.new_edges(ia_edges, check_edges=False) graph_nw._graph_type = "newman_watts" return graph_nw
# --------------------- # # Distance-based models # # --------------------- #
[docs]@mpi_random def distance_rule(scale, rule="exp", shape=None, neuron_density=1000., max_proba=-1., nodes=0, density=-1., edges=-1, avg_deg=-1., unit='um', weighted=True, directed=True, multigraph=False, name="DR", positions=None, population=None, from_graph=None, **kwargs): """ Create a graph using a 2D distance rule to create the connection between neurons. Available rules are linear and exponential. Parameters ---------- scale : float Characteristic scale for the distance rule. E.g for linear distance- rule, :math:`P(i,j) \propto (1-d_{ij}/scale))`, whereas for the exponential distance-rule, :math:`P(i,j) \propto e^{-d_{ij}/scale}`. rule : string, optional (default: 'exp') Rule that will be apply to draw the connections between neurons. Choose among "exp" (exponential), "gaussian" (Gaussian), or "lin" (linear). shape : :class:`~nngt.geometry.Shape`, optional (default: None) Shape of the neurons' environment. If not specified, a square will be created with the appropriate dimensions for the number of neurons and the neuron spatial density. neuron_density : float, optional (default: 1000.) Density of neurons in space (:math:`neurons \cdot mm^{-2}`). nodes : int, optional (default: None) The number of nodes in the graph. p : float, optional Normalization factor for the distance rule; it is equal to the probability of connection when testing a node at zero distance. density: double, optional Structural density given by `edges` / (`nodes` * `nodes`). edges : int, optional The number of edges between the nodes avg_deg : double, optional Average degree of the neurons given by `edges` / `nodes`. unit : string (default: 'um') Unit for the length `scale` among 'um' (:math:`\mu m`), 'mm', 'cm', 'dm', 'm'. weighted : bool, optional (default: True) @todo Whether the graph edges have weights. directed : bool, optional (default: True) Whether the graph is directed or not. multigraph : bool, optional (default: False) Whether the graph can contain multiple edges between two nodes. name : string, optional (default: "DR") Name of the created graph. positions : :class:`numpy.ndarray`, optional (default: None) A 2D (N, 2) or 3D (N, 3) shaped array containing the positions of the neurons in space. population : :class:`~nngt.NeuralPop`, optional (default: None) Population of neurons defining their biological properties (to create a :class:`~nngt.Network`). from_graph : :class:`Graph` or subclass, optional (default: None) Initial graph whose nodes are to be connected. """ distance = [] # convert neuronal density in (mu m)^2 neuron_density *= conversion_magnitude(unit, 'mm')**2 # set node number and library graph graph_dr = from_graph if graph_dr is not None: nodes = graph_dr.node_nb() graph_dr.clear_all_edges() else: nodes = population.size if population is not None else nodes # check shape if shape is None: h = w = np.sqrt(float(nodes) / neuron_density) shape = nngt.geometry.Shape.rectangle(h, w) if graph_dr is None: graph_dr = nngt.SpatialGraph( name=name, nodes=nodes, directed=directed, shape=shape, positions=positions, **kwargs) else: Graph.make_spatial(graph_dr, shape, positions=positions) positions = np.array(graph_dr.get_positions().T, dtype=np.float32) # set options (graph has already been made spatial) _set_options(graph_dr, population, None, None) # add edges ia_edges = None conversion_factor = conversion_magnitude(shape.unit, unit) if unit != shape.unit: positions = np.multiply(conversion_factor, positions, dtype=np.float32) if nodes > 1: ids = np.arange(0, nodes, dtype=np.uint) ia_edges = _distance_rule( ids, ids, density, edges, avg_deg, scale, rule, max_proba, shape, positions, directed, multigraph, distance=distance, **kwargs) attr = {'distance': distance} # check for None if MPI if ia_edges is not None: graph_dr.new_edges(ia_edges, attributes=attr, check_edges=False) graph_dr._graph_type = "{}_distance_rule".format(rule) return graph_dr
# -------------------- # # Polyvalent generator # # -------------------- # _di_generator = { "all_to_all": all_to_all, "distance_rule": distance_rule, "erdos_renyi": erdos_renyi, "fixed_degree": fixed_degree, "gaussian_degree": gaussian_degree, "newman_watts": newman_watts, "price_scale_free": price_scale_free, "random_scale_free": random_scale_free }
[docs]def generate(di_instructions, **kwargs): ''' Generate a :class:`~nngt.Graph` or one of its subclasses from a ``dict`` containing all the relevant informations. Parameters ---------- di_instructions : ``dict`` Dictionary containing the instructions to generate the graph. It must have at least ``"graph_type"`` in its keys, with a value among ``"distance_rule", "erdos_renyi", "fixed_degree", "newman_watts", "price_scale_free", "random_scale_free"``. Depending on the type, `di_instructions` should also contain at least all non-optional arguments of the generator function. See also -------- :mod:`~nngt.generation` ''' graph_type = di_instructions["graph_type"] instructions = deepcopy(di_instructions) instructions.update(kwargs) return _di_generator[graph_type](**instructions)
#-----------------------------------------------------------------------------# # Connecting groups #------------------------ # _di_gen_edges = { "all_to_all": _all_to_all, "distance_rule": _distance_rule, "erdos_renyi": _erdos_renyi, "fixed_degree": _fixed_degree, "gaussian_degree": _gaussian_degree, "newman_watts": _newman_watts, "price_scale_free": _price_scale_free, "random_scale_free": _random_scale_free } _one_pop_models = ("newman_watts",) def connect_nodes(network, sources, targets, graph_model, density=-1., edges=-1, avg_deg=-1., unit='um', weighted=True, directed=True, multigraph=False, **kwargs): ''' Function to connect nodes with a given graph model. .. versionadded:: 1.0 Parameters ---------- network : :class:`Network` or :class:`SpatialNetwork` The network to connect. sources : list Ids of the source nodes. targets : list Ids of the target nodes. graph_model : string The name of the connectivity model (among "erdos_renyi", "random_scale_free", "price_scale_free", and "newman_watts"). kwargs : keyword arguments Specific model parameters. or edge attributes specifiers such as `weights` or `delays`. ''' if network.is_spatial() and 'positions' not in kwargs: kwargs['positions'] = network.get_positions().astype(np.float32).T if network.is_spatial() and 'shape' not in kwargs: kwargs['shape'] = network.shape sources = np.array(sources, dtype=np.uint) targets = np.array(targets, dtype=np.uint) distance = [] elist = _di_gen_edges[graph_model]( sources, targets, density=density, edges=edges, avg_deg=avg_deg, weighted=weighted, directed=directed, multigraph=multigraph, distance=distance, **kwargs) # Attributes are not set by subfunctions attr = {} if 'weights' in kwargs: attr['weight'] = kwargs['weights'] if 'delays' in kwargs: attr['delay'] = kwargs['delays'] if network.is_spatial(): attr['distance'] = distance network.new_edges(elist, attributes=attr, check_edges=False) if not network._graph_type.endswith('_connect'): network._graph_type += "_nodes_connect" return elist
[docs]def connect_neural_types(network, source_type, target_type, graph_model, density=-1., edges=-1, avg_deg=-1., unit='um', weighted=True, directed=True, multigraph=False, **kwargs): ''' Function to connect excitatory and inhibitory population with a given graph model. .. versionchanged:: 0.8 Model-specific arguments are now provided as keywords and not through a dict. It is now possible to provide different weights and delays at each call. @todo make the modifications for only a set of edges Parameters ---------- network : :class:`Network` or :class:`SpatialNetwork` The network to connect. source_type : int The type of source neurons (``1`` for excitatory, ``-1`` for inhibitory neurons). target_type : int The type of target neurons. graph_model : string The name of the connectivity model (among "erdos_renyi", "random_scale_free", "price_scale_free", and "newman_watts"). kwargs : keyword arguments Specific model parameters. or edge attributes specifiers such as `weights` or `delays`. ''' elist, source_ids, target_ids = None, [], [] if network.is_spatial() and 'positions' not in kwargs: kwargs['positions'] = network.get_positions().astype(np.float32).T if network.is_spatial() and 'shape' not in kwargs: kwargs['shape'] = network.shape for group in iter(network._population.values()): if group.neuron_type == source_type: source_ids.extend(group.ids) if group.neuron_type == target_type: target_ids.extend(group.ids) source_ids = np.array(source_ids, dtype=np.uint) target_ids = np.array(target_ids, dtype=np.uint) elist = connect_nodes( network, source_ids, target_ids, graph_model, density=density, edges=edges, avg_deg=avg_deg, unit=unit, weighted=weighted, directed=directed, multigraph=multigraph, **kwargs) if not network._graph_type.endswith('_neural_type_connect'): network._graph_type += "_neural_type_connect" return elist
[docs]def connect_neural_groups(network, source_groups, target_groups, graph_model, density=-1., edges=-1, avg_deg=-1., unit='um', weighted=True, directed=True, multigraph=False, **kwargs): ''' Function to connect excitatory and inhibitory population with a given graph model. .. versionchanged:: 0.8 Model-specific arguments are now provided as keywords and not through a dict. It is now possible to provide different weights and delays at each call. @todo make the modifications for only a set of edges Parameters ---------- network : :class:`Network` or :class:`SpatialNetwork` The network to connect. source_groups : str or tuple Names of the source groups (which contain the pre-synaptic neurons) target_groups : str or tuple Names of the target groups (which contain the post-synaptic neurons) graph_model : string The name of the connectivity model (among "erdos_renyi", "random_scale_free", "price_scale_free", and "newman_watts"). kwargs : keyword arguments Specific model parameters. or edge attributes specifiers such as `weights` or `delays`. ''' elist, source_ids, target_ids = None, [], [] if network.is_spatial() and 'positions' not in kwargs: kwargs['positions'] = network.get_positions().astype(np.float32).T if network.is_spatial() and 'shape' not in kwargs: kwargs['shape'] = network.shape if isinstance(source_groups, str): source_groups = [source_groups] if isinstance(target_groups, str): target_groups = [target_groups] for name, group in network.population.items(): if name in source_groups: source_ids.extend(group.ids) if name in target_groups: target_ids.extend(group.ids) source_ids = np.array(source_ids, dtype=np.uint) target_ids = np.array(target_ids, dtype=np.uint) elist = connect_nodes( network, source_ids, target_ids, graph_model, density=density, edges=edges, avg_deg=avg_deg, unit=unit, weighted=weighted, directed=directed, multigraph=multigraph, **kwargs) if not network._graph_type.endswith('_neural_group_connect'): network._graph_type += "_neural_group_connect" return elist