def test_csa_one_to_one_connector(): unittest_setup() connector = CSAConnector(csa.oneToOne) weight = 1.0 delay = 2.0 synapse_info = SynapseInformation(connector=None, pre_population=MockPopulation(10, "Pre"), post_population=MockPopulation( 10, "Post"), prepop_is_view=False, postpop_is_view=False, rng=None, synapse_dynamics=None, synapse_type=None, receptor_type=None, is_virtual_machine=False, synapse_type_from_dynamics=False, weights=weight, delays=delay) connector.set_projection_information(synapse_info) pre_vertex_slice = Slice(0, 10) post_vertex_slice = Slice(0, 10) block = connector.create_synaptic_block([pre_vertex_slice], [post_vertex_slice], pre_vertex_slice, post_vertex_slice, 0, synapse_info) assert (len(block) > 0) assert (all(item["source"] == item["target"] for item in block)) assert (all(item["weight"] == 1.0 for item in block)) assert (all(item["delay"] == 2.0 for item in block))
def test_csa_from_list_connector(): unittest_setup() conn_list = [(i, i + 1 % 10) for i in range(10)] connector = CSAConnector(conn_list) weight = 1.0 delay = 2.0 mock_synapse_info = SynapseInformation( connector=None, pre_population=MockPopulation(10, "Pre"), post_population=MockPopulation(10, "Post"), prepop_is_view=False, postpop_is_view=False, rng=None, synapse_dynamics=None, synapse_type=None, is_virtual_machine=False, weights=weight, delays=delay) connector.set_projection_information(mock_synapse_info) pre_vertex_slice = Slice(0, 10) post_vertex_slice = Slice(0, 10) block = connector.create_synaptic_block([pre_vertex_slice], [post_vertex_slice], pre_vertex_slice, post_vertex_slice, 0, mock_synapse_info) assert (len(block) > 0) assert (all(item["source"] == conn[0] for item, conn in zip(block, conn_list))) assert (all(item["target"] == conn[1] for item, conn in zip(block, conn_list))) assert (all(item["weight"] == 1.0 for item in block)) assert (all(item["delay"] == 2.0 for item in block))
def test_csa_random_connector(): unittest_setup() connector = CSAConnector(csa.random(0.05)) weight = 1.0 delay = 2.0 mock_synapse_info = SynapseInformation( connector=None, pre_population=MockPopulation(10, "Pre"), post_population=MockPopulation(10, "Post"), prepop_is_view=False, postpop_is_view=False, rng=None, synapse_dynamics=None, synapse_type=None, is_virtual_machine=False, weights=weight, delays=delay) connector.set_projection_information(mock_synapse_info) pre_vertex_slice = Slice(0, 10) post_vertex_slice = Slice(0, 10) block = connector.create_synaptic_block([pre_vertex_slice], [post_vertex_slice], pre_vertex_slice, post_vertex_slice, 0, mock_synapse_info) assert (len(block) >= 0) assert (all(item["weight"] == 1.0 for item in block)) assert (all(item["delay"] == 2.0 for item in block))
def test_connector_split(): unittest_setup() n_sources = 1000 n_targets = 1000 n_connections = 10000 pre_neurons_per_core = 57 post_neurons_per_core = 59 sources = numpy.random.randint(0, n_sources, n_connections) targets = numpy.random.randint(0, n_targets, n_connections) pre_slices = [ Slice(i, i + pre_neurons_per_core - 1) for i in range(0, n_sources, pre_neurons_per_core) ] post_slices = [ Slice(i, i + post_neurons_per_core - 1) for i in range(0, n_targets, post_neurons_per_core) ] connection_list = numpy.dstack((sources, targets))[0] connector = MockFromListConnector(connection_list) weight = 1.0 delay = 1.0 synapse_info = SynapseInformation( connector=None, pre_population=MockPopulation(n_sources, "Pre"), post_population=MockPopulation(n_targets, "Post"), prepop_is_view=False, postpop_is_view=False, rng=None, synapse_dynamics=None, synapse_type=None, is_virtual_machine=False, weights=weight, delays=delay) has_block = set() try: # Check each connection is in the right place for pre_slice in pre_slices: for post_slice in post_slices: block = connector.create_synaptic_block( pre_slices, post_slices, pre_slice, post_slice, 1, synapse_info) for source in block["source"]: assert (pre_slice.lo_atom <= source <= pre_slice.hi_atom) for target in block["target"]: assert (post_slice.lo_atom <= target <= post_slice.hi_atom) for item in block: has_block.add((item["source"], item["target"])) # Check each connection has a place for source, target in zip(sources, targets): assert (source, target) in has_block # Check the split only happens once assert connector._split_count == 1 except AssertionError as e: print(connection_list) raise e
def test_connector(clist, column_names, weights, delays, expected_clist, expected_weights, expected_delays, expected_extra_parameters, expected_extra_parameter_names): spynnaker8.setup() temp = tempfile.NamedTemporaryFile(delete=False) with temp as f: header = '' if column_names is not None: columns = ["i", "j"] columns.extend(column_names) header = 'columns = {}'.format(columns) if clist is not None and len(clist): numpy.savetxt(f, clist, header=header) elif len(header): f.write("# {}\n".format(header)) connector = FromFileConnector(temp.name) if expected_clist is not None: assert (numpy.array_equal(connector.conn_list, expected_clist)) else: assert (numpy.array_equal(connector.conn_list, clist)) # Check extra parameters are as expected extra_params = connector.get_extra_parameters() extra_param_names = connector.get_extra_parameter_names() assert (numpy.array_equal(extra_params, expected_extra_parameters)) assert (numpy.array_equal(extra_param_names, expected_extra_parameter_names)) if extra_params is not None: assert (len(extra_params.shape) == 2) assert (extra_params.shape[1] == len(extra_param_names)) for i in range(len(extra_param_names)): assert (extra_params[:, i].shape == (len(clist), )) # Check weights and delays are used or ignored as expected pre_slice = Slice(0, 10) post_slice = Slice(0, 10) synapse_info = SynapseInformation(connector=None, pre_population=MockPopulation(10, "Pre"), post_population=MockPopulation( 10, "Post"), prepop_is_view=False, postpop_is_view=False, rng=None, synapse_dynamics=None, synapse_type=None, receptor_type=None, is_virtual_machine=False, synapse_type_from_dynamics=False, weights=weights, delays=delays) block = connector.create_synaptic_block([pre_slice], [post_slice], pre_slice, post_slice, 1, synapse_info) assert (numpy.array_equal(block["weight"], numpy.array(expected_weights))) assert (numpy.array_equal(block["delay"], numpy.array(expected_delays)))
def test_get_max_row_length(dynamics, size, exception, max_size): io = SynapseIORowBased() population_table = MasterPopTableAsBinarySearch() synapse_information = SynapseInformation(None, dynamics, 0) in_edge = ProjectionApplicationEdge(None, None, synapse_information) if exception is not None: with pytest.raises(exception) as exc_info: io._get_max_row_length(size, dynamics, population_table, in_edge, size) assert exc_info.value.max_size == max_size else: actual_size = io._get_max_row_length(size, dynamics, population_table, in_edge, size) assert actual_size == max_size
def test_get_allowed_row_length(dynamics_class, timing, weight, size, exception, max_size): spynnaker8.setup() if timing is not None and weight is not None: dynamics = dynamics_class(timing(), weight()) else: dynamics = dynamics_class() synapse_information = SynapseInformation(None, None, None, False, False, None, None, dynamics, 0, True) in_edge = ProjectionApplicationEdge(None, None, synapse_information) if exception is not None: with pytest.raises(exception) as exc_info: _get_allowed_row_length(size, dynamics, in_edge, size) assert exc_info.value.max_size == max_size else: actual_size = _get_allowed_row_length(size, dynamics, in_edge, size) assert actual_size == max_size
def test_connector(clist, column_names, weights, delays, expected_clist, expected_weights, expected_delays, expected_extra_parameters, expected_extra_parameter_names): unittest_setup() connector = FromListConnector(clist, column_names=column_names) if expected_clist is not None: assert (numpy.array_equal(connector.conn_list, expected_clist)) else: assert (numpy.array_equal(connector.conn_list, clist)) # Check extra parameters are as expected extra_params = connector.get_extra_parameters() extra_param_names = connector.get_extra_parameter_names() assert (numpy.array_equal(extra_params, expected_extra_parameters)) assert (numpy.array_equal(extra_param_names, expected_extra_parameter_names)) if extra_params is not None: assert (len(extra_params.shape) == 2) assert (extra_params.shape[1] == len(extra_param_names)) for i in range(len(extra_param_names)): assert (extra_params[:, i].shape == (len(clist), )) # Check weights and delays are used or ignored as expected pre_slice = Slice(0, 10) post_slice = Slice(0, 10) synapse_info = SynapseInformation(connector=None, pre_population=MockPopulation(10, "Pre"), post_population=MockPopulation( 10, "Post"), prepop_is_view=False, postpop_is_view=False, rng=None, synapse_dynamics=None, synapse_type=None, is_virtual_machine=False, weights=weights, delays=delays) block = connector.create_synaptic_block([pre_slice], [post_slice], pre_slice, post_slice, 1, synapse_info) assert (numpy.array_equal(block["weight"], numpy.array(expected_weights))) assert (numpy.array_equal(block["delay"], numpy.array(expected_delays)))
def test_slices(): unittest_setup() s_info = SynapseInformation(None, None, None, False, False, None, None, None, None, False, False, None, None) app_edge = ProjectionApplicationEdge(None, None, s_info) mv0_2 = SimpleMachineVertex(None, None, None, None, Slice(0, 1)) mv2_4 = SimpleMachineVertex(None, None, None, None, Slice(2, 3)) mv4_6 = SimpleMachineVertex(None, None, None, None, Slice(4, 5)) app_edge.remember_associated_machine_edge(MachineEdge(mv0_2, mv2_4)) app_edge.remember_associated_machine_edge(MachineEdge(mv4_6, mv0_2)) app_edge.remember_associated_machine_edge(MachineEdge(mv0_2, mv2_4)) assert app_edge.pre_slices == [Slice(0, 1), Slice(4, 5)] post1 = app_edge.post_slices assert post1 == [Slice(0, 1), Slice(2, 3)] app_edge.remember_associated_machine_edge(MachineEdge(mv0_2, mv0_2)) app_edge.remember_associated_machine_edge(MachineEdge(mv2_4, mv2_4)) assert app_edge.pre_slices == [Slice(0, 1), Slice(2, 3), Slice(4, 5)] post2 = app_edge.post_slices assert post1 == post2 assert id(post1) != id(post2)
def test_csa_block_connector(): unittest_setup() try: # This creates a block of size (2, 5) with a probability of 0.5; then # within the block an individual connection has a probability of 0.3 connector = CSAConnector( csa.block(2, 5) * csa.random(0.5) * csa.random(0.3)) weight = 1.0 delay = 2.0 mock_synapse_info = SynapseInformation( connector=None, pre_population=MockPopulation(10, "Pre"), post_population=MockPopulation(10, "Post"), prepop_is_view=False, postpop_is_view=False, rng=None, synapse_dynamics=None, synapse_type=None, receptor_type=None, is_virtual_machine=False, synapse_type_from_dynamics=False, weights=weight, delays=delay) connector.set_projection_information(mock_synapse_info) pre_vertex_slice = Slice(0, 10) post_vertex_slice = Slice(0, 10) block = connector.create_synaptic_block([pre_vertex_slice], 0, [post_vertex_slice], 0, pre_vertex_slice, post_vertex_slice, 0, mock_synapse_info) assert (len(block) >= 0) assert (all(item["weight"] == 1.0 for item in block)) assert (all(item["delay"] == 2.0 for item in block)) except TypeError as e: raise SkipTest("https://github.com/INCF/csa/issues/17") from e except RuntimeError as e: if sys.version_info >= (3, 7): raise SkipTest("https://github.com/INCF/csa/issues/16") from e raise e
def test_get_max_row_length(dynamics_class, timing, weight, size, exception, max_size): MockSimulator.setup() if timing is not None and weight is not None: dynamics = dynamics_class(timing(), weight()) else: dynamics = dynamics_class() io = SynapseIORowBased() population_table = MasterPopTableAsBinarySearch() synapse_information = SynapseInformation(None, None, None, None, None, None, dynamics, 0) in_edge = ProjectionApplicationEdge(None, None, synapse_information) if exception is not None: with pytest.raises(exception) as exc_info: io._get_max_row_length(size, dynamics, population_table, in_edge, size) assert exc_info.value.max_size == max_size else: actual_size = io._get_max_row_length(size, dynamics, population_table, in_edge, size) assert actual_size == max_size
def test_write_synaptic_matrix_and_master_population_table(self): MockSimulator.setup() default_config_paths = os.path.join( os.path.dirname(abstract_spinnaker_common.__file__), AbstractSpiNNakerCommon.CONFIG_FILE_NAME) config = conf_loader.load_config( AbstractSpiNNakerCommon.CONFIG_FILE_NAME, default_config_paths) config.set("Simulation", "one_to_one_connection_dtcm_max_bytes", 40) machine_time_step = 1000.0 pre_app_vertex = SimpleApplicationVertex(10) pre_vertex = SimpleMachineVertex(resources=None) pre_vertex_slice = Slice(0, 9) post_app_vertex = SimpleApplicationVertex(10) post_vertex = SimpleMachineVertex(resources=None) post_vertex_slice = Slice(0, 9) post_slice_index = 0 one_to_one_connector_1 = OneToOneConnector(None) one_to_one_connector_1.set_projection_information( pre_app_vertex, post_app_vertex, None, machine_time_step) one_to_one_connector_1.set_weights_and_delays(1.5, 1.0) one_to_one_connector_2 = OneToOneConnector(None) one_to_one_connector_2.set_projection_information( pre_app_vertex, post_app_vertex, None, machine_time_step) one_to_one_connector_2.set_weights_and_delays(2.5, 2.0) all_to_all_connector = AllToAllConnector(None) all_to_all_connector.set_projection_information( pre_app_vertex, post_app_vertex, None, machine_time_step) all_to_all_connector.set_weights_and_delays(4.5, 4.0) direct_synapse_information_1 = SynapseInformation( one_to_one_connector_1, SynapseDynamicsStatic(), 0) direct_synapse_information_2 = SynapseInformation( one_to_one_connector_2, SynapseDynamicsStatic(), 1) all_to_all_synapse_information = SynapseInformation( all_to_all_connector, SynapseDynamicsStatic(), 0) app_edge = ProjectionApplicationEdge(pre_app_vertex, post_app_vertex, direct_synapse_information_1) app_edge.add_synapse_information(direct_synapse_information_2) app_edge.add_synapse_information(all_to_all_synapse_information) machine_edge = ProjectionMachineEdge(app_edge.synapse_information, pre_vertex, post_vertex) partition_name = "TestPartition" graph = MachineGraph("Test") graph.add_vertex(pre_vertex) graph.add_vertex(post_vertex) graph.add_edge(machine_edge, partition_name) graph_mapper = GraphMapper() graph_mapper.add_vertex_mapping(pre_vertex, pre_vertex_slice, pre_app_vertex) graph_mapper.add_vertex_mapping(post_vertex, post_vertex_slice, post_app_vertex) graph_mapper.add_edge_mapping(machine_edge, app_edge) weight_scales = [4096.0, 4096.0] key = 0 routing_info = RoutingInfo() routing_info.add_partition_info( PartitionRoutingInfo( [BaseKeyAndMask(key, 0xFFFFFFF0)], graph.get_outgoing_edge_partition_starting_at_vertex( pre_vertex, partition_name))) temp_spec = tempfile.mktemp() spec_writer = FileDataWriter(temp_spec) spec = DataSpecificationGenerator(spec_writer, None) master_pop_sz = 1000 master_pop_region = 0 all_syn_block_sz = 2000 synapse_region = 1 spec.reserve_memory_region(master_pop_region, master_pop_sz) spec.reserve_memory_region(synapse_region, all_syn_block_sz) synapse_type = MockSynapseType() synaptic_manager = SynapticManager(synapse_type=synapse_type, ring_buffer_sigma=5.0, spikes_per_second=100.0, config=config) synaptic_manager._write_synaptic_matrix_and_master_population_table( spec, [post_vertex_slice], post_slice_index, post_vertex, post_vertex_slice, all_syn_block_sz, weight_scales, master_pop_region, synapse_region, routing_info, graph_mapper, graph, machine_time_step) spec.end_specification() spec_writer.close() spec_reader = FileDataReader(temp_spec) executor = DataSpecificationExecutor(spec_reader, master_pop_sz + all_syn_block_sz) executor.execute() master_pop_table = executor.get_region(0) synaptic_matrix = executor.get_region(1) all_data = bytearray() all_data.extend( master_pop_table.region_data[:master_pop_table.max_write_pointer]) all_data.extend( synaptic_matrix.region_data[:synaptic_matrix.max_write_pointer]) master_pop_table_address = 0 synaptic_matrix_address = master_pop_table.max_write_pointer direct_synapses_address = struct.unpack_from( "<I", synaptic_matrix.region_data)[0] direct_synapses_address += synaptic_matrix_address + 8 indirect_synapses_address = synaptic_matrix_address + 4 placement = Placement(None, 0, 0, 1) transceiver = MockTransceiverRawData(all_data) # Get the master population table details items = synaptic_manager._poptable_type\ .extract_synaptic_matrix_data_location( key, master_pop_table_address, transceiver, placement.x, placement.y) # The first entry should be direct, but the rest should be indirect; # the second is potentially direct, but has been restricted by the # restriction on the size of the direct matrix assert len(items) == 3 # TODO: This has been changed because direct matrices are disabled! assert not items[0][2] assert not items[1][2] assert not items[2][2] data_1, row_len_1 = synaptic_manager._retrieve_synaptic_block( transceiver=transceiver, placement=placement, master_pop_table_address=master_pop_table_address, indirect_synapses_address=indirect_synapses_address, direct_synapses_address=direct_synapses_address, key=key, n_rows=pre_vertex_slice.n_atoms, index=0, using_extra_monitor_cores=False) connections_1 = synaptic_manager._synapse_io.read_synapses( direct_synapse_information_1, pre_vertex_slice, post_vertex_slice, row_len_1, 0, 2, weight_scales, data_1, None, app_edge.n_delay_stages, machine_time_step) # The first matrix is a 1-1 matrix, so row length is 1 assert row_len_1 == 1 # Check that all the connections have the right weight and delay assert len(connections_1) == post_vertex_slice.n_atoms assert all([conn["weight"] == 1.5 for conn in connections_1]) assert all([conn["delay"] == 1.0 for conn in connections_1]) data_2, row_len_2 = synaptic_manager._retrieve_synaptic_block( transceiver=transceiver, placement=placement, master_pop_table_address=master_pop_table_address, indirect_synapses_address=indirect_synapses_address, direct_synapses_address=direct_synapses_address, key=key, n_rows=pre_vertex_slice.n_atoms, index=1, using_extra_monitor_cores=False) connections_2 = synaptic_manager._synapse_io.read_synapses( direct_synapse_information_2, pre_vertex_slice, post_vertex_slice, row_len_2, 0, 2, weight_scales, data_2, None, app_edge.n_delay_stages, machine_time_step) # The second matrix is a 1-1 matrix, so row length is 1 assert row_len_2 == 1 # Check that all the connections have the right weight and delay assert len(connections_2) == post_vertex_slice.n_atoms assert all([conn["weight"] == 2.5 for conn in connections_2]) assert all([conn["delay"] == 2.0 for conn in connections_2]) data_3, row_len_3 = synaptic_manager._retrieve_synaptic_block( transceiver=transceiver, placement=placement, master_pop_table_address=master_pop_table_address, indirect_synapses_address=indirect_synapses_address, direct_synapses_address=direct_synapses_address, key=key, n_rows=pre_vertex_slice.n_atoms, index=2, using_extra_monitor_cores=False) connections_3 = synaptic_manager._synapse_io.read_synapses( all_to_all_synapse_information, pre_vertex_slice, post_vertex_slice, row_len_3, 0, 2, weight_scales, data_3, None, app_edge.n_delay_stages, machine_time_step) # The third matrix is an all-to-all matrix, so length is n_atoms assert row_len_3 == post_vertex_slice.n_atoms # Check that all the connections have the right weight and delay assert len(connections_3) == \ post_vertex_slice.n_atoms * pre_vertex_slice.n_atoms assert all([conn["weight"] == 4.5 for conn in connections_3]) assert all([conn["delay"] == 4.0 for conn in connections_3])
def test_connectors(n_pre, n_post, n_in_slice, create_connector, weight, delay): unittest_setup() max_target = 0 max_source = 0 max_row_length = None max_col_length = None for seed in range(10): numpy.random.seed(random.randint(0, 1000)) connector = create_connector() synapse_info = SynapseInformation( connector=None, pre_population=MockPopulation(n_pre, "Pre"), post_population=MockPopulation(n_post, "Post"), prepop_is_view=False, postpop_is_view=False, rng=None, synapse_dynamics=None, synapse_type=None, receptor_type=None, is_virtual_machine=False, synapse_type_from_dynamics=False, weights=weight, delays=delay) connector.set_projection_information(synapse_info=synapse_info) pre_slices = [ Slice(i, i + n_in_slice - 1) for i in range(0, n_pre, n_in_slice) ] post_slices = [ Slice(i, i + n_in_slice - 1) for i in range(0, n_post, n_in_slice) ] pre_slice_index = 0 post_slice_index = 0 pre_vertex_slice = pre_slices[pre_slice_index] post_vertex_slice = post_slices[post_slice_index] synapse_type = 0 pre_slice = pre_slices[pre_slice_index] post_slice = post_slices[post_slice_index] pre_range = numpy.arange(pre_slice.lo_atom, pre_slice.hi_atom + 2) post_range = numpy.arange(post_slice.lo_atom, post_slice.hi_atom + 2) max_delay = connector.get_delay_maximum(synapse_info) max_weight = connector.get_weight_maximum(synapse_info) if max_row_length is None: max_row_length = connector.\ get_n_connections_from_pre_vertex_maximum( post_vertex_slice, synapse_info) else: assert (max_row_length == connector.get_n_connections_from_pre_vertex_maximum( post_vertex_slice, synapse_info)) if max_col_length is None: max_col_length = connector.\ get_n_connections_to_post_vertex_maximum(synapse_info) else: assert (max_col_length == connector. get_n_connections_to_post_vertex_maximum(synapse_info)) synaptic_block = connector.create_synaptic_block( pre_slices, post_slices, pre_vertex_slice, post_vertex_slice, synapse_type, synapse_info) source_histogram = numpy.histogram(synaptic_block["source"], pre_range)[0] target_histogram = numpy.histogram(synaptic_block["target"], post_range)[0] matrix_max_weight = (max(synaptic_block["weight"]) if len(synaptic_block) > 0 else 0) matrix_max_delay = (max(synaptic_block["delay"]) if len(synaptic_block) > 0 else 0) max_source = max((max(source_histogram), max_source)) max_target = max((max(target_histogram), max_target)) if len(post_slices) > post_slice_index + 1: test_post_slice = post_slices[post_slice_index + 1] test_synaptic_block = connector.create_synaptic_block( pre_slices, post_slices, pre_vertex_slice, test_post_slice, synapse_type, synapse_info) if len(test_synaptic_block) > 0: assert not numpy.array_equal(test_synaptic_block, synaptic_block) if len(pre_slices) > pre_slice_index + 1: test_pre_slice = pre_slices[pre_slice_index + 1] test_synaptic_block = connector.create_synaptic_block( pre_slices, post_slices, test_pre_slice, post_vertex_slice, synapse_type, synapse_info) if len(test_synaptic_block) > 0: assert not numpy.array_equal(test_synaptic_block, synaptic_block) try: assert max(source_histogram) <= max_row_length assert max(target_histogram) <= max_col_length assert matrix_max_weight <= max_weight assert matrix_max_delay <= max_delay except Exception: print(connector, n_pre, n_post, n_in_slice) print(max_row_length, max(source_histogram), source_histogram) print(max_col_length, max(target_histogram), target_histogram) print(max_weight, matrix_max_weight, synaptic_block["weight"]) print(max_delay, matrix_max_delay, synaptic_block["delay"]) print(connector, n_pre, n_post, n_in_slice, max_row_length, max_source, max_col_length, max_target)
def test_write_synaptic_matrix_and_master_population_table(self): MockSimulator.setup() # Add an sdram so max SDRAM is high enough SDRAM(10000) # UGLY but the mock transceiver NEED generate_on_machine to be False AbstractGenerateConnectorOnMachine.generate_on_machine = self.say_false default_config_paths = os.path.join( os.path.dirname(abstract_spinnaker_common.__file__), AbstractSpiNNakerCommon.CONFIG_FILE_NAME) config = conf_loader.load_config( AbstractSpiNNakerCommon.CONFIG_FILE_NAME, default_config_paths) config.set("Simulation", "one_to_one_connection_dtcm_max_bytes", 40) machine_time_step = 1000.0 pre_app_vertex = SimpleApplicationVertex(10) pre_vertex_slice = Slice(0, 9) pre_vertex = pre_app_vertex.create_machine_vertex( pre_vertex_slice, None) post_app_vertex = SimpleApplicationVertex(10) post_vertex_slice = Slice(0, 9) post_vertex = post_app_vertex.create_machine_vertex( post_vertex_slice, None) post_slice_index = 0 one_to_one_connector_1 = OneToOneConnector(None) direct_synapse_information_1 = SynapseInformation( one_to_one_connector_1, pre_app_vertex, post_app_vertex, False, False, None, SynapseDynamicsStatic(), 0, 1.5, 1.0) one_to_one_connector_1.set_projection_information( machine_time_step, direct_synapse_information_1) one_to_one_connector_2 = OneToOneConnector(None) direct_synapse_information_2 = SynapseInformation( one_to_one_connector_2, pre_app_vertex, post_app_vertex, False, False, None, SynapseDynamicsStatic(), 1, 2.5, 2.0) one_to_one_connector_2.set_projection_information( machine_time_step, direct_synapse_information_2) all_to_all_connector = AllToAllConnector(None) all_to_all_synapse_information = SynapseInformation( all_to_all_connector, pre_app_vertex, post_app_vertex, False, False, None, SynapseDynamicsStatic(), 0, 4.5, 4.0) all_to_all_connector.set_projection_information( machine_time_step, all_to_all_synapse_information) app_edge = ProjectionApplicationEdge(pre_app_vertex, post_app_vertex, direct_synapse_information_1) app_edge.add_synapse_information(direct_synapse_information_2) app_edge.add_synapse_information(all_to_all_synapse_information) machine_edge = app_edge.create_machine_edge(pre_vertex, post_vertex, label=None) partition_name = "TestPartition" graph = MachineGraph("Test") graph.add_vertex(pre_vertex) graph.add_vertex(post_vertex) graph.add_edge(machine_edge, partition_name) weight_scales = [4096.0, 4096.0] key = 0 routing_info = RoutingInfo() routing_info.add_partition_info( PartitionRoutingInfo( [BaseKeyAndMask(key, 0xFFFFFFF0)], graph.get_outgoing_edge_partition_starting_at_vertex( pre_vertex, partition_name))) temp_spec = tempfile.mktemp() spec_writer = FileDataWriter(temp_spec) spec = DataSpecificationGenerator(spec_writer, None) master_pop_sz = 1000 all_syn_block_sz = 2000 master_pop_region = 0 synapse_region = 1 direct_region = 2 spec.reserve_memory_region(master_pop_region, master_pop_sz) spec.reserve_memory_region(synapse_region, all_syn_block_sz) synaptic_manager = SynapticManager(n_synapse_types=2, ring_buffer_sigma=5.0, spikes_per_second=100.0, config=config) # Poke in our testing region IDs synaptic_manager._pop_table_region = master_pop_region synaptic_manager._synaptic_matrix_region = synapse_region synaptic_manager._direct_matrix_region = direct_region synaptic_manager._write_synaptic_matrix_and_master_population_table( spec, [post_vertex_slice], post_slice_index, post_vertex, post_vertex_slice, all_syn_block_sz, weight_scales, routing_info, graph, machine_time_step) spec.end_specification() spec_writer.close() spec_reader = FileDataReader(temp_spec) executor = DataSpecificationExecutor(spec_reader, master_pop_sz + all_syn_block_sz) executor.execute() master_pop_table = executor.get_region(0) synaptic_matrix = executor.get_region(1) direct_matrix = executor.get_region(2) all_data = bytearray() all_data.extend( master_pop_table.region_data[:master_pop_table.max_write_pointer]) all_data.extend( synaptic_matrix.region_data[:synaptic_matrix.max_write_pointer]) all_data.extend( direct_matrix.region_data[:direct_matrix.max_write_pointer]) master_pop_table_address = 0 synaptic_matrix_address = master_pop_table.max_write_pointer direct_synapses_address = (synaptic_matrix_address + synaptic_matrix.max_write_pointer) direct_synapses_address += 4 indirect_synapses_address = synaptic_matrix_address placement = Placement(None, 0, 0, 1) transceiver = MockTransceiverRawData(all_data) # Get the master population table details items = synaptic_manager._extract_synaptic_matrix_data_location( key, master_pop_table_address, transceiver, placement) # The first entry should be direct, but the rest should be indirect; # the second is potentially direct, but has been restricted by the # restriction on the size of the direct matrix assert len(items) == 3 assert items[0][2] assert not items[1][2] assert not items[2][2] data_1, row_len_1 = synaptic_manager._retrieve_synaptic_block( txrx=transceiver, placement=placement, master_pop_table_address=master_pop_table_address, indirect_synapses_address=indirect_synapses_address, direct_synapses_address=direct_synapses_address, key=key, n_rows=pre_vertex_slice.n_atoms, index=0, using_monitors=False) connections_1 = synaptic_manager._read_synapses( direct_synapse_information_1, pre_vertex_slice, post_vertex_slice, row_len_1, 0, weight_scales, data_1, None, machine_time_step) # The first matrix is a 1-1 matrix, so row length is 1 assert row_len_1 == 1 # Check that all the connections have the right weight and delay assert len(connections_1) == post_vertex_slice.n_atoms assert all([conn["weight"] == 1.5 for conn in connections_1]) assert all([conn["delay"] == 1.0 for conn in connections_1]) data_2, row_len_2 = synaptic_manager._retrieve_synaptic_block( txrx=transceiver, placement=placement, master_pop_table_address=master_pop_table_address, indirect_synapses_address=indirect_synapses_address, direct_synapses_address=direct_synapses_address, key=key, n_rows=pre_vertex_slice.n_atoms, index=1, using_monitors=False) connections_2 = synaptic_manager._read_synapses( direct_synapse_information_2, pre_vertex_slice, post_vertex_slice, row_len_2, 0, weight_scales, data_2, None, machine_time_step) # The second matrix is a 1-1 matrix, so row length is 1 assert row_len_2 == 1 # Check that all the connections have the right weight and delay assert len(connections_2) == post_vertex_slice.n_atoms assert all([conn["weight"] == 2.5 for conn in connections_2]) assert all([conn["delay"] == 2.0 for conn in connections_2]) data_3, row_len_3 = synaptic_manager._retrieve_synaptic_block( txrx=transceiver, placement=placement, master_pop_table_address=master_pop_table_address, indirect_synapses_address=indirect_synapses_address, direct_synapses_address=direct_synapses_address, key=key, n_rows=pre_vertex_slice.n_atoms, index=2, using_monitors=False) connections_3 = synaptic_manager._read_synapses( all_to_all_synapse_information, pre_vertex_slice, post_vertex_slice, row_len_3, 0, weight_scales, data_3, None, machine_time_step) # The third matrix is an all-to-all matrix, so length is n_atoms assert row_len_3 == post_vertex_slice.n_atoms # Check that all the connections have the right weight and delay assert len(connections_3) == \ post_vertex_slice.n_atoms * pre_vertex_slice.n_atoms assert all([conn["weight"] == 4.5 for conn in connections_3]) assert all([conn["delay"] == 4.0 for conn in connections_3])
class Projection(object): """ A container for all the connections of a given type (same synapse type and plasticity mechanisms) between two populations, together with methods to set parameters of those connections, including of plasticity mechanisms. """ # pylint: disable=redefined-builtin __slots__ = [ "__has_retrieved_synaptic_list_from_machine", "__host_based_synapse_list", "__projection_edge", "__requires_mapping", "__synapse_information", "__virtual_connection_list", "__label" ] def __init__(self, pre_synaptic_population, post_synaptic_population, connector, synapse_type=None, source=None, receptor_type=None, space=None, label=None): """ :param ~spynnaker.pyNN.models.populations.PopulationBase \ pre_synaptic_population: :param ~spynnaker.pyNN.models.populations.PopulationBase \ post_synaptic_population: :param AbstractConnector connector: :param AbstractSynapseDynamics synapse_type: :param None source: Unsupported; must be None :param str receptor_type: :param ~pyNN.space.Space space: :param str label: """ # pylint: disable=too-many-arguments, too-many-locals if source is not None: raise NotImplementedError( "sPyNNaker {} does not yet support multi-compartmental " "cells.".format(__version__)) sim = get_simulator() self.__projection_edge = None self.__host_based_synapse_list = None self.__has_retrieved_synaptic_list_from_machine = False self.__requires_mapping = True self.__label = label pre_is_view = self.__check_population(pre_synaptic_population, connector) post_is_view = self.__check_population(post_synaptic_population, connector) # set default label if label is None: # set the projection's label to a default (maybe non-unique!) self.__label = ("from pre {} to post {} with connector {}".format( pre_synaptic_population.label, post_synaptic_population.label, connector)) # give an auto generated label for the underlying edge label = "projection edge {}".format(sim.none_labelled_edge_count) sim.increment_none_labelled_edge_count() # Handle default synapse type if synapse_type is None: synapse_dynamics = SynapseDynamicsStatic() else: synapse_dynamics = synapse_type # set the space function as required if space is None: space = PyNNSpace() connector.set_space(space) pre_vertex = pre_synaptic_population._vertex post_vertex = post_synaptic_population._vertex if not isinstance(post_vertex, AbstractAcceptsIncomingSynapses): raise ConfigurationException( "postsynaptic population is not designed to receive" " synaptic projections") # sort out synapse type synaptic_type = post_vertex.get_synapse_id_by_target(receptor_type) synapse_type_from_dynamics = False if synaptic_type is None: synaptic_type = synapse_dynamics.get_synapse_id_by_target( receptor_type) synapse_type_from_dynamics = True if synaptic_type is None: raise ConfigurationException( "Synapse target {} not found in {}".format( receptor_type, post_synaptic_population.label)) # as a from-list connector can have plastic parameters, grab those ( # if any) and add them to the synapse dynamics object if isinstance(connector, FromListConnector): connector._apply_parameters_to_synapse_type(synaptic_type) # round the delays to multiples of full timesteps # (otherwise SDRAM estimation calculations can go wrong) if ((not isinstance(synapse_dynamics.delay, RandomDistribution)) and (not isinstance(synapse_dynamics.delay, str))): synapse_dynamics.set_delay( numpy.rint( numpy.array(synapse_dynamics.delay) * machine_time_step_per_ms()) * machine_time_step_ms()) # set the plasticity dynamics for the post pop (allows plastic stuff # when needed) post_vertex.set_synapse_dynamics(synapse_dynamics) # get rng if needed rng = connector.rng if hasattr(connector, "rng") else None # Set and store synapse information for future processing self.__synapse_information = SynapseInformation( connector, pre_synaptic_population, post_synaptic_population, pre_is_view, post_is_view, rng, synapse_dynamics, synaptic_type, receptor_type, sim.use_virtual_board, synapse_type_from_dynamics, synapse_dynamics.weight, synapse_dynamics.delay) # Set projection information in connector connector.set_projection_information(self.__synapse_information) # Find out if there is an existing edge between the populations edge_to_merge = self._find_existing_edge(pre_vertex, post_vertex) if edge_to_merge is not None: # If there is an existing edge, add the connector edge_to_merge.add_synapse_information(self.__synapse_information) self.__projection_edge = edge_to_merge else: # If there isn't an existing edge, create a new one and add it self.__projection_edge = ProjectionApplicationEdge( pre_vertex, post_vertex, self.__synapse_information, label=label) sim.add_application_edge(self.__projection_edge, SPIKE_PARTITION_ID) # add projection to the SpiNNaker control system sim.add_projection(self) # If there is a virtual board, we need to hold the data in case the # user asks for it self.__virtual_connection_list = None if sim.use_virtual_board: self.__virtual_connection_list = list() connection_holder = ConnectionHolder( None, False, pre_vertex.n_atoms, post_vertex.n_atoms, self.__virtual_connection_list) self.__synapse_information.add_pre_run_connection_holder( connection_holder) # If the target is a population, add to the list of incoming # projections if isinstance(post_vertex, AbstractPopulationVertex): post_vertex.add_incoming_projection(self) # If the source is a poisson, add to the list of outgoing projections if isinstance(pre_vertex, SpikeSourcePoissonVertex): pre_vertex.add_outgoing_projection(self) @staticmethod def __check_population(param, connector): """ :param ~spynnaker.pyNN.models.populations.PopulationBase param: :param AbstractConnector connector: :return: Whether the parameter is a view :rtype: bool """ if isinstance(param, Population): # Projections definitely work from Populations return False if not isinstance(param, PopulationView): raise ConfigurationException( "Unexpected parameter type {}. Expected Population".format( type(param))) if not isinstance(connector, AbstractConnectorSupportsViewsOnMachine): raise NotImplementedError( "Projections over views not currently supported with the {}". format(connector)) # Check whether the array is contiguous or not inds = param._indexes if inds != tuple(range(inds[0], inds[-1] + 1)): raise NotImplementedError( "Projections over views only work on contiguous arrays, " "e.g. view = pop[n:m], not view = pop[n,m]") # Projection is compatible with PopulationView return True def get( self, attribute_names, format, # @ReservedAssignment gather=True, with_address=True, multiple_synapses='last'): """ Get a parameter/attribute of the projection. .. note:: SpiNNaker always gathers. :param attribute_names: list of attributes to gather :type attribute_names: str or iterable(str) :param str format: ``"list"`` or ``"array"`` :param bool gather: gather over all nodes :param bool with_address: True if the source and target are to be included :param str multiple_synapses: What to do with the data if format="array" and if the multiple source-target pairs with the same values exist. Currently only "last" is supported :return: values selected """ # pylint: disable=too-many-arguments if not gather: logger.warning("sPyNNaker always gathers from every core.") if multiple_synapses != 'last': raise ConfigurationException( "sPyNNaker only recognises multiple_synapses == last") return self.__get_data(attribute_names, format, with_address, notify=None) def save( self, attribute_names, file, format='list', # @ReservedAssignment gather=True, with_address=True): """ Print synaptic attributes (weights, delays, etc.) to file. In the\ array format, zeros are printed for non-existent connections.\ Values will be expressed in the standard PyNN units (i.e., \ millivolts, nanoamps, milliseconds, microsiemens, nanofarads, \ event per second). .. note:: SpiNNaker always gathers. :param attribute_names: :type attribute_names: str or list(str) :param file: filename or open handle (which will be closed) :type file: str or pyNN.recording.files.BaseFile :param str format: :param bool gather: Ignored :param bool with_address: """ # pylint: disable=too-many-arguments if not gather: warn_once( logger, "sPyNNaker only supports gather=True. We will run " "as if gather was set to True.") if isinstance(attribute_names, str): attribute_names = [attribute_names] if attribute_names in (['all'], ['connections']): attribute_names = \ self._projection_edge.post_vertex.synapse_dynamics.\ get_parameter_names() metadata = {"columns": attribute_names} if with_address: metadata["columns"] = ["i", "j"] + list(metadata["columns"]) self.__get_data(attribute_names, format, with_address, notify=functools.partial(self.__save_callback, file, metadata)) def __get_data( self, attribute_names, format, # @ReservedAssignment with_address, notify): """ Internal data getter to add notify option :param attribute_names: list of attributes to gather :type attribute_names: str or iterable(str) :param str format: ``"list"`` or ``"array"`` :param bool with_address: :param callable(ConnectionHolder,None) notify: :return: values selected """ # fix issue with 1 versus many if isinstance(attribute_names, str): attribute_names = [attribute_names] data_items = list() if format != "list": with_address = False if with_address: data_items.append("source") data_items.append("target") if "source" in attribute_names: logger.warning( "Ignoring request to get source as with_address=True. ") attribute_names.remove("source") if "target" in attribute_names: logger.warning( "Ignoring request to get target as with_address=True. ") attribute_names.remove("target") # Split out attributes in to standard versus synapse dynamics data fixed_values = list() for attribute in attribute_names: data_items.append(attribute) if attribute not in {"source", "target", "weight", "delay"}: value = self._synapse_information.synapse_dynamics.get_value( attribute) fixed_values.append((attribute, value)) # Return the connection data return self._get_synaptic_data(format == "list", data_items, fixed_values, notify=notify) @staticmethod def __save_callback(save_file, metadata, data): """ :param save_file: :type save_file: str or pyNN.recording.files.BaseFile :param dict(str,object) metadata: :param data: :type data: ConnectionHolder or numpy.ndarray """ # Convert structured array to normal numpy array if hasattr(data, "dtype") and hasattr(data.dtype, "names"): dtype = [(name, "<f8") for name in data.dtype.names] data = data.astype(dtype) data = numpy.nan_to_num(data) if isinstance(save_file, str): data_file = StandardTextFile(save_file, mode='wb') else: data_file = save_file try: data_file.write(data, metadata) finally: data_file.close() @property def pre(self): """ The pre-population or population view. :rtype: ~spynnaker.pyNN.models.populations.PopulationBase """ return self._synapse_information.pre_population @property def post(self): """ The post-population or population view. :rtype: ~spynnaker.pyNN.models.populations.PopulationBase """ return self._synapse_information.post_population @property def label(self): """ :rtype: str """ return self.__label def __repr__(self): return "projection {}".format(self.__label) # ----------------------------------------------------------------- @property def requires_mapping(self): """ Whether this projection requires mapping. :rtype: bool """ return self.__requires_mapping def mark_no_changes(self): """ Mark this projection as not having changes to be mapped. """ self.__requires_mapping = False @property def _synapse_information(self): """ :rtype: SynapseInformation """ return self.__synapse_information @property def _projection_edge(self): """ :rtype: ProjectionApplicationEdge """ return self.__projection_edge def _find_existing_edge(self, pre_synaptic_vertex, post_synaptic_vertex): """ Searches though the graph's edges to locate any\ edge which has the same post and pre vertex :param pre_synaptic_vertex: the source vertex of the multapse :type pre_synaptic_vertex: ~pacman.model.graphs.application.ApplicationVertex :param post_synaptic_vertex: The destination vertex of the multapse :type post_synaptic_vertex: ~pacman.model.graphs.application.ApplicationVertex :return: None or the edge going to these vertices. :rtype: ~.ApplicationEdge """ # Find edges ending at the postsynaptic vertex graph_edges = get_simulator().original_application_graph.\ get_edges_ending_at_vertex(post_synaptic_vertex) # Search the edges for any that start at the presynaptic vertex for edge in graph_edges: if edge.pre_vertex == pre_synaptic_vertex: return edge return None def _get_synaptic_data(self, as_list, data_to_get, fixed_values=None, notify=None): """ :param bool as_list: :param list(int) data_to_get: :param list(tuple(str,int)) fixed_values: :param callable(ConnectionHolder,None) notify: :rtype: ConnectionHolder """ # pylint: disable=too-many-arguments post_vertex = self.__projection_edge.post_vertex pre_vertex = self.__projection_edge.pre_vertex # If in virtual board mode, the connection data should be set if self.__virtual_connection_list is not None: connection_holder = ConnectionHolder( data_to_get, as_list, pre_vertex.n_atoms, post_vertex.n_atoms, self.__virtual_connection_list, fixed_values=fixed_values, notify=notify) connection_holder.finish() return connection_holder # if not virtual board, make connection holder to be filled in at # possible later date connection_holder = ConnectionHolder(data_to_get, as_list, pre_vertex.n_atoms, post_vertex.n_atoms, fixed_values=fixed_values, notify=notify) # If we haven't run, add the holder to get connections, and return it # and set up a callback for after run to fill in this connection holder if not get_simulator().has_ran: self.__synapse_information.add_pre_run_connection_holder( connection_holder) return connection_holder # Otherwise, get the connections now, as we have ran and therefore can # get them connections = post_vertex.get_connections_from_machine( get_simulator().transceiver, get_simulator().placements, self.__projection_edge, self.__synapse_information) if connections is not None: connection_holder.add_connections(connections) connection_holder.finish() return connection_holder def _clear_cache(self): post_vertex = self.__projection_edge.post_vertex if isinstance(post_vertex, AbstractAcceptsIncomingSynapses): post_vertex.clear_connection_cache() # ----------------------------------------------------------------- def set(self, **attributes): # @UnusedVariable # pylint: disable=unused-argument """ .. warning:: Not implemented. """ _we_dont_do_this_now() def getWeights( self, format='list', # @ReservedAssignment gather=True): """ .. deprecated:: 5.0 Use ``get('weight')`` instead. """ logger.warning("getWeights is deprecated. Use get('weight') instead") return self.get('weight', format, gather, with_address=False) def getDelays( self, format='list', # @ReservedAssignment gather=True): """ .. deprecated:: 5.0 Use ``get('delay')`` instead. """ logger.warning("getDelays is deprecated. Use get('delay') instead") return self.get('delay', format, gather, with_address=False) def getSynapseDynamics( self, parameter_name, format='list', # @ReservedAssignment gather=True): """ .. deprecated:: 5.0 Use ``get(parameter_name)`` instead. """ logger.warning( "getSynapseDynamics is deprecated. Use get(parameter_name)" " instead") return self.get(parameter_name, format, gather, with_address=False) def saveConnections( self, file, # @ReservedAssignment gather=True, compatible_output=True): """ .. deprecated:: 5.0 Use ``save('all')`` instead. """ if not compatible_output: logger.warning("SpiNNaker only supports compatible_output=True.") logger.warning( "saveConnections is deprecated. Use save('all') instead") self.save('all', file, format='list', gather=gather) def printWeights( self, file, format='list', # @ReservedAssignment gather=True): """ .. deprecated:: 5.0 Use ``save('weight')`` instead. """ logger.warning( "printWeights is deprecated. Use save('weight') instead") self.save('weight', file, format, gather) def printDelays( self, file, format='list', # @ReservedAssignment gather=True): """ .. deprecated:: 5.0 Use ``save('delay')`` instead. Print synaptic weights to file. In the array format, zeros are printed for non-existent connections. """ logger.warning("printDelays is deprecated. Use save('delay') instead") self.save('delay', file, format, gather) def weightHistogram( self, min=None, max=None, # @ReservedAssignment nbins=10): """ .. deprecated:: 5.0 Use ``numpy.histogram`` on the weights instead. Return a histogram of synaptic weights. If ``min`` and ``max`` are not given, the minimum and maximum weights are calculated automatically. """ logger.warning( "weightHistogram is deprecated. Use numpy.histogram function" " instead") pynn_common.Projection.weightHistogram(self, min=min, max=max, nbins=nbins) def size(self, gather=True): # @UnusedVariable # pylint: disable=unused-argument """ Return the total number of connections. .. note:: SpiNNaker always gathers. .. warning:: Not implemented. :param bool gather: If False, only get the number of connections locally. """ # TODO _we_dont_do_this_now()
def __init__(self, spinnaker_control, connector, synapse_dynamics_stdp, target, pre_synaptic_population, post_synaptic_population, rng, machine_time_step, user_max_delay, label, time_scale_factor): # pylint: disable=too-many-arguments, too-many-locals self._spinnaker_control = spinnaker_control self._projection_edge = None self._host_based_synapse_list = None self._has_retrieved_synaptic_list_from_machine = False self._requires_mapping = True self._label = None if not isinstance(post_synaptic_population._get_vertex, AbstractAcceptsIncomingSynapses): raise ConfigurationException( "postsynaptic population is not designed to receive" " synaptic projections") # sort out synapse type synapse_type = post_synaptic_population._get_vertex\ .get_synapse_id_by_target(target) if synapse_type is None: raise ConfigurationException( "Synapse target {} not found in {}".format( target, post_synaptic_population.label)) # set the plasticity dynamics for the post pop (allows plastic stuff # when needed) post_synaptic_population._get_vertex.set_synapse_dynamics( synapse_dynamics_stdp) # Set and store information for future processing self._synapse_information = SynapseInformation(connector, synapse_dynamics_stdp, synapse_type) connector.set_projection_information(pre_synaptic_population, post_synaptic_population, rng, machine_time_step) # handle max delay max_delay = synapse_dynamics_stdp.get_delay_maximum(connector) if max_delay is None: max_delay = user_max_delay # check if all delays requested can fit into the natively supported # delays in the models post_vertex_max_supported_delay_ms = \ post_synaptic_population._get_vertex \ .get_maximum_delay_supported_in_ms(machine_time_step) if max_delay > (post_vertex_max_supported_delay_ms + _delay_extension_max_supported_delay): raise ConfigurationException( "The maximum delay {} for projection is not supported".format( max_delay)) if max_delay > user_max_delay / (machine_time_step / 1000.0): logger.warning("The end user entered a max delay" " for which the projection breaks") # check that the projection edges label is not none, and give an # auto generated label if set to None if label is None: label = "projection edge {}".format( spinnaker_control.none_labelled_edge_count) spinnaker_control.increment_none_labelled_edge_count() # Find out if there is an existing edge between the populations edge_to_merge = self._find_existing_edge( pre_synaptic_population._get_vertex, post_synaptic_population._get_vertex) if edge_to_merge is not None: # If there is an existing edge, add the connector edge_to_merge.add_synapse_information(self._synapse_information) self._projection_edge = edge_to_merge else: # If there isn't an existing edge, create a new one self._projection_edge = ProjectionApplicationEdge( pre_synaptic_population._get_vertex, post_synaptic_population._get_vertex, self._synapse_information, label=label) # add edge to the graph spinnaker_control.add_application_edge( self._projection_edge, constants.SPIKE_PARTITION_ID) # If the delay exceeds the post vertex delay, add a delay extension if max_delay > post_vertex_max_supported_delay_ms: delay_edge = self._add_delay_extension( pre_synaptic_population, post_synaptic_population, max_delay, post_vertex_max_supported_delay_ms, machine_time_step, time_scale_factor) self._projection_edge.delay_edge = delay_edge # add projection to the SpiNNaker control system spinnaker_control.add_projection(self) # If there is a virtual board, we need to hold the data in case the # user asks for it self._virtual_connection_list = None if spinnaker_control.use_virtual_board: self._virtual_connection_list = list() pre_vertex = pre_synaptic_population._get_vertex post_vertex = post_synaptic_population._get_vertex connection_holder = ConnectionHolder(None, False, pre_vertex.n_atoms, post_vertex.n_atoms, self._virtual_connection_list) post_vertex.add_pre_run_connection_holder( connection_holder, self._projection_edge, self._synapse_information)
def __init__(self, pre_synaptic_population, post_synaptic_population, connector, synapse_type=None, source=None, receptor_type=None, space=None, label=None): """ :param ~spynnaker.pyNN.models.populations.PopulationBase \ pre_synaptic_population: :param ~spynnaker.pyNN.models.populations.PopulationBase \ post_synaptic_population: :param AbstractConnector connector: :param AbstractSynapseDynamics synapse_type: :param None source: Unsupported; must be None :param str receptor_type: :param ~pyNN.space.Space space: :param str label: """ # pylint: disable=too-many-arguments, too-many-locals if source is not None: raise NotImplementedError( "sPyNNaker {} does not yet support multi-compartmental " "cells.".format(__version__)) sim = get_simulator() self.__projection_edge = None self.__host_based_synapse_list = None self.__has_retrieved_synaptic_list_from_machine = False self.__requires_mapping = True self.__label = label pre_is_view = self.__check_population(pre_synaptic_population, connector) post_is_view = self.__check_population(post_synaptic_population, connector) # set default label if label is None: # set the projection's label to a default (maybe non-unique!) self.__label = ("from pre {} to post {} with connector {}".format( pre_synaptic_population.label, post_synaptic_population.label, connector)) # give an auto generated label for the underlying edge label = "projection edge {}".format(sim.none_labelled_edge_count) sim.increment_none_labelled_edge_count() # Handle default synapse type if synapse_type is None: synapse_dynamics = SynapseDynamicsStatic() else: synapse_dynamics = synapse_type # set the space function as required if space is None: space = PyNNSpace() connector.set_space(space) pre_vertex = pre_synaptic_population._vertex post_vertex = post_synaptic_population._vertex if not isinstance(post_vertex, AbstractAcceptsIncomingSynapses): raise ConfigurationException( "postsynaptic population is not designed to receive" " synaptic projections") # sort out synapse type synaptic_type = post_vertex.get_synapse_id_by_target(receptor_type) synapse_type_from_dynamics = False if synaptic_type is None: synaptic_type = synapse_dynamics.get_synapse_id_by_target( receptor_type) synapse_type_from_dynamics = True if synaptic_type is None: raise ConfigurationException( "Synapse target {} not found in {}".format( receptor_type, post_synaptic_population.label)) # as a from-list connector can have plastic parameters, grab those ( # if any) and add them to the synapse dynamics object if isinstance(connector, FromListConnector): connector._apply_parameters_to_synapse_type(synaptic_type) # round the delays to multiples of full timesteps # (otherwise SDRAM estimation calculations can go wrong) if ((not isinstance(synapse_dynamics.delay, RandomDistribution)) and (not isinstance(synapse_dynamics.delay, str))): synapse_dynamics.set_delay( numpy.rint( numpy.array(synapse_dynamics.delay) * machine_time_step_per_ms()) * machine_time_step_ms()) # set the plasticity dynamics for the post pop (allows plastic stuff # when needed) post_vertex.set_synapse_dynamics(synapse_dynamics) # get rng if needed rng = connector.rng if hasattr(connector, "rng") else None # Set and store synapse information for future processing self.__synapse_information = SynapseInformation( connector, pre_synaptic_population, post_synaptic_population, pre_is_view, post_is_view, rng, synapse_dynamics, synaptic_type, receptor_type, sim.use_virtual_board, synapse_type_from_dynamics, synapse_dynamics.weight, synapse_dynamics.delay) # Set projection information in connector connector.set_projection_information(self.__synapse_information) # Find out if there is an existing edge between the populations edge_to_merge = self._find_existing_edge(pre_vertex, post_vertex) if edge_to_merge is not None: # If there is an existing edge, add the connector edge_to_merge.add_synapse_information(self.__synapse_information) self.__projection_edge = edge_to_merge else: # If there isn't an existing edge, create a new one and add it self.__projection_edge = ProjectionApplicationEdge( pre_vertex, post_vertex, self.__synapse_information, label=label) sim.add_application_edge(self.__projection_edge, SPIKE_PARTITION_ID) # add projection to the SpiNNaker control system sim.add_projection(self) # If there is a virtual board, we need to hold the data in case the # user asks for it self.__virtual_connection_list = None if sim.use_virtual_board: self.__virtual_connection_list = list() connection_holder = ConnectionHolder( None, False, pre_vertex.n_atoms, post_vertex.n_atoms, self.__virtual_connection_list) self.__synapse_information.add_pre_run_connection_holder( connection_holder) # If the target is a population, add to the list of incoming # projections if isinstance(post_vertex, AbstractPopulationVertex): post_vertex.add_incoming_projection(self) # If the source is a poisson, add to the list of outgoing projections if isinstance(pre_vertex, SpikeSourcePoissonVertex): pre_vertex.add_outgoing_projection(self)