def test_mpi_from_degree_list(): ''' Check that the degrees generated using `from_degree_list` indeed correspond to the provided list ''' num_nodes = 1000 from mpi4py import MPI comm = MPI.COMM_WORLD deg_list = np.random.randint(0, int(0.1 * num_nodes), size=num_nodes) # test for in g = ng.from_degree_list(deg_list, degree_type="in", nodes=num_nodes) deg = g.get_degrees("in") deg = comm.gather(deg, root=0) if nngt.on_master_process(): deg = np.sum(deg, axis=0) assert np.all(deg == deg_list) num_edges = g.edge_nb() num_edges = comm.gather(num_edges, root=0) if nngt.on_master_process(): num_edges = np.sum(num_edges) assert num_edges == np.sum(deg_list) # test for out g = ng.from_degree_list(deg_list, degree_type="out", nodes=num_nodes) deg = g.get_degrees("out") deg = comm.gather(deg, root=0) if nngt.on_master_process(): deg = np.sum(deg, axis=0) assert np.all(deg == deg_list) num_edges = g.edge_nb() num_edges = comm.gather(num_edges, root=0) if nngt.on_master_process(): num_edges = np.sum(num_edges) assert num_edges == np.sum(deg_list)
def test_model_properties(self, graph, instructions, **kwargs): ''' When generating graphs from on of the preconfigured models, check that the expected properties are indeed obtained. ''' if nngt.get_config("backend") != "nngt" and nngt.on_master_process(): graph_type = instructions["graph_type"] ref_result = self.theo_prop[graph_type](instructions) computed_result = self.exp_prop[graph_type](graph, instructions) if graph_type == 'distance_rule': # average degree self.assertTrue( ref_result[0] == computed_result[0], "Avg. deg. for graph {} failed:\nref = {} vs exp {}\ ".format(graph.name, ref_result[0], computed_result[0])) # average error on distance distribution sqd = np.square( np.subtract(ref_result[1:], computed_result[1:])) avg_sqd = sqd / np.square(computed_result[1:]) err = np.sqrt(avg_sqd).mean() tolerance = (self.tolerance if instructions['rule'] == 'lin' else 0.25) self.assertTrue( err <= tolerance, "Distance distribution for graph {} failed:\nerr = {} > {}\ ".format(graph.name, err, tolerance)) elif nngt.get_config("backend") == "nngt": from mpi4py import MPI comm = MPI.COMM_WORLD num_proc = comm.Get_size() graph_type = instructions["graph_type"] ref_result = self.theo_prop[graph_type](instructions) computed_result = self.exp_prop[graph_type](graph, instructions) if graph_type == 'distance_rule': # average degree self.assertTrue( ref_result[0] == computed_result[0] * num_proc, "Avg. deg. for graph {} failed:\nref = {} vs exp {}\ ".format(graph.name, ref_result[0], computed_result[0])) # average error on distance distribution sqd = np.square( np.subtract(ref_result[1:], computed_result[1:])) avg_sqd = sqd / np.square(computed_result[1:]) err = np.sqrt(avg_sqd).mean() tolerance = (self.tolerance if instructions['rule'] == 'lin' else 0.25) self.assertTrue( err <= tolerance, "Distance distribution for graph {} failed:\nerr = {} > {}\ ".format(graph.name, err, tolerance))
def test_group_vs_type(): ''' Gaussian degree with groups and types ''' # first with groups nngt.seed(0) pop = nngt.NeuralPop.exc_and_inhib(1000) igroup = pop["inhibitory"] egroup = pop["excitatory"] net1 = nngt.Network(population=pop) all_groups = list(pop.keys()) # necessary to have same order as types avg_e = 50 std_e = 5 ng.connect_groups(net1, egroup, all_groups, graph_model="gaussian_degree", avg=avg_e, std=std_e, degree_type="out-degree") avg_i = 100 std_i = 5 ng.connect_groups(net1, igroup, all_groups, graph_model="gaussian_degree", avg=avg_i, std=std_i, degree_type="out-degree") # then with types nngt.seed(0) pop = nngt.NeuralPop.exc_and_inhib(1000) igroup = pop["inhibitory"] egroup = pop["excitatory"] net2 = nngt.Network(population=pop) avg_e = 50 std_e = 5 ng.connect_neural_types(net2, 1, [-1, 1], graph_model="gaussian_degree", avg=avg_e, std=std_e, degree_type="out-degree") avg_i = 100 std_i = 5 ng.connect_neural_types(net2, -1, [-1, 1], graph_model="gaussian_degree", avg=avg_i, std=std_i, degree_type="out-degree") # call only on root process (for mpi) unless using distributed backend if nngt.on_master_process() or nngt.get_config("backend") == "nngt": # check that both networks are equals assert np.all(net1.get_degrees() == net2.get_degrees())
def test_random_seeded(): num_seeds = get_num_seeds() # test equality of graph generated with same seeds nngt.seed(msd=0, seeds=[i for i in range(1, num_seeds + 1)]) g1 = ng.gaussian_degree(10, 1, nodes=100) nngt.seed(msd=0, seeds=[i for i in range(1, num_seeds + 1)]) g2 = ng.gaussian_degree(10, 1, nodes=100) assert np.all(g1.edges_array == g2.edges_array) # check that subsequent graphs are different g3 = ng.gaussian_degree(10, 1, nodes=100) # with mpi onnon-distributed backends, test only on master process if nngt.get_config("backend") == "nngt" or nngt.on_master_process(): if g3.edge_nb() == g2.edge_nb(): assert np.any(g2.edges_array != g3.edges_array)
def connect_nodes(network, sources, targets, graph_model, density=None, edges=None, avg_deg=None, unit='um', weighted=True, directed=True, multigraph=False, check_existing=True, ignore_invalid=False, **kwargs): ''' Function to connect nodes with a given graph model. .. versionchanged:: 2.0 Added `check_existing` and `ignore_invalid` arguments. 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"). check_existing : bool, optional (default: True) Check whether some of the edges that will be added already exist in the graph. ignore_invalid : bool, optional (default: False) Ignore invalid edges: they are not added to the graph and are silently dropped. Unless this is set to true, an error is raised if an existing edge is re-generated. **kwargs : keyword arguments Specific model parameters. or edge attributes specifiers such as `weights` or `delays`. Note ---- For graph generation methods which set the properties of a specific degree (e.g. :func:`~nngt.generation.gaussian_degree`), the nodes which have their property sets are the `sources`. ''' 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 graph_model in _one_pop_models: assert np.array_equal(sources, targets), \ "'" + graph_model + "' can only work on a single set of nodes." 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: ww = kwargs['weights'] if isinstance(ww, dict): attr['weight'] = _generate_random(len(elist), ww) elif nonstring_container(ww): attr['weight'] = ww else: attr['weight'] = np.full(len(elist), ww) if 'delays' in kwargs: dd = kwargs['delays'] if isinstance(ww, dict): attr['delay'] = _generate_random(len(elist), dd) elif nonstring_container(dd): attr['weight'] = dd else: attr['weight'] = np.full(len(elist), dd) if network.is_spatial() and distance: attr['distance'] = distance # call only on root process (for mpi) unless using distributed backend if nngt.on_master_process() or nngt.get_config("backend") == "nngt": elist = network.new_edges(elist, attributes=attr, check_duplicates=False, check_self_loops=False, check_existing=check_existing, ignore_invalid=ignore_invalid) if not network._graph_type.endswith('_connect'): network._graph_type += "_nodes_connect" return elist
def test_gaussian(): ''' Gaussian degree with groups ''' pop = nngt.NeuralPop.exc_and_inhib(1000) igroup = pop["inhibitory"] egroup = pop["excitatory"] net = nngt.Network(population=pop) avg_e = 50 std_e = 5 ng.connect_groups(net, egroup, [igroup, egroup], graph_model="gaussian_degree", avg=avg_e, std=std_e, degree_type="out-degree") avg_i = 100 std_i = 5 ng.connect_groups(net, igroup, [igroup, egroup], graph_model="gaussian_degree", avg=avg_i, std=std_i, degree_type="out-degree") edeg = net.get_degrees("out", nodes=egroup.ids) ideg = net.get_degrees("out", nodes=igroup.ids) # call only on root process (for mpi) and not if using distributed backend if nngt.on_master_process() and nngt.get_config("backend") != "nngt": assert avg_e - std_e < np.average(edeg) < avg_e + std_e assert avg_i - std_i < np.average(ideg) < avg_i + std_i elif nngt.get_config("mpi") and nngt.get_config("backend") == "nngt": from mpi4py import MPI comm = MPI.COMM_WORLD rank = comm.Get_rank() num_mpi = comm.Get_size() edeg = comm.gather(edeg[rank::num_mpi], root=0) ideg = comm.gather(ideg[rank::num_mpi], root=0) if nngt.on_master_process(): assert avg_e - std_e < np.average(edeg) < avg_e + std_e assert avg_i - std_i < np.average(ideg) < avg_i + std_i edeg = net.get_degrees("in", nodes=egroup.ids) ideg = net.get_degrees("in", nodes=igroup.ids) avg_deg = (avg_e*egroup.size + avg_i*igroup.size) / pop.size std_deg = np.sqrt(avg_deg) # call only on root process (for mpi) unless using distributed backend if nngt.on_master_process() and nngt.get_config("backend") != "nngt": assert avg_deg - std_deg < np.average(edeg) < avg_deg + std_deg assert avg_deg - std_deg < np.average(ideg) < avg_deg + std_deg elif nngt.get_config("mpi") and nngt.get_config("backend") == "nngt": from mpi4py import MPI comm = MPI.COMM_WORLD rank = comm.Get_rank() num_mpi = comm.Get_size() edeg = comm.gather(edeg, root=0) ideg = comm.gather(ideg, root=0) if nngt.on_master_process(): edeg = np.sum(edeg, axis=0) ideg = np.sum(ideg, axis=0) assert avg_deg - std_deg < np.average(edeg) < avg_deg + std_deg assert avg_deg - std_deg < np.average(ideg) < avg_deg + std_deg
def gen_graph(self, graph_name): di_instructions = self.parser.get_graph_options(graph_name) graph = nngt.generate(di_instructions) if nngt.on_master_process(): graph.set_name(graph_name) return graph, di_instructions