def __init__(self, presynaptic_population, postsynaptic_population, label, connector, spinnaker_control, machine_time_step, timescale_factor, source=None, target='excitatory', synapse_dynamics=None, rng=None): """ Instantiates a :py:object:`Projection`. """ self._spinnaker = spinnaker_control self._projection_edge = None self._projection_list_ranges = None self._delay_edge = None self._delay_list_ranges = None self._host_based_synapse_list = None self._has_retrieved_synaptic_list_from_machine = False if isinstance(postsynaptic_population._get_vertex, AbstractPopulationVertex): # Check that the "target" is an acceptable value targets = postsynaptic_population._get_vertex.get_synapse_targets() if target not in targets: raise exceptions.ConfigurationException( "Target {} is not available in the post-synaptic " "pynn_population.py (choices are {})".format( target, targets)) synapse_type = \ postsynaptic_population._get_vertex.get_synapse_id(target) else: raise exceptions.ConfigurationException( "postsynaptic_population is not a supposal reciever of" " synaptic projections") self._weight_scale = postsynaptic_population._get_vertex.weight_scale synapse_list = \ connector.generate_synapse_list( presynaptic_population, postsynaptic_population, 1000.0 / machine_time_step, postsynaptic_population._get_vertex.weight_scale, synapse_type) self._host_based_synapse_list = copy.deepcopy(synapse_list) # If there are some negative weights if synapse_list.get_min_weight() < 0: # If there are mixed negative and positive weights, # raise an exception if synapse_list.get_max_weight() > 0: raise exceptions.ConfigurationException("Weights must be " "positive") # Otherwise, the weights are all negative, so invert them(!) else: synapse_list.flip() # Set any weight scaling for STDP if synapse_dynamics is not None: synapse_dynamics.weight_scale =\ postsynaptic_population._get_vertex.weight_scale # check if all delays requested can fit into the natively supported # delays in the models max_delay = synapse_list.get_max_delay() natively_supported_delay_for_models = \ constants.MAX_SUPPORTED_DELAY_TICS delay_extention_max_supported_delay = \ constants.MAX_DELAY_BLOCKS * \ constants.MAX_TIMER_TICS_SUPPORTED_PER_BLOCK if max_delay > (natively_supported_delay_for_models + delay_extention_max_supported_delay): raise exceptions.ConfigurationException( "the max delay for projection {} is not supported by the " "pacman toolchain".format(max_delay)) if conf.config.has_option("Model", "max_delay"): user_max_delay = conf.config.get("Model", "max_delay") if max_delay > user_max_delay: logger.warn("The end user entered a max delay" " for which the projection breaks") # check that the projection edges label is not none, and give an # autogenerated label if set to None if label is None: label = "projection edge {}".format(Projection._projection_count) Projection._projection_count += 1 if max_delay > natively_supported_delay_for_models: source_sz = presynaptic_population._get_vertex.n_atoms self._add_delay_extension(source_sz, max_delay, natively_supported_delay_for_models, synapse_list, presynaptic_population, postsynaptic_population, machine_time_step, timescale_factor, label, synapse_dynamics) else: # Find out if there is an existing edge between the populations edge_to_merge = self._find_existing_edge( presynaptic_population._get_vertex, postsynaptic_population._get_vertex) if edge_to_merge is not None: # If there is an existing edge, merge the lists self._projection_list_ranges = \ edge_to_merge.synapse_list.merge(synapse_list) self._projection_edge = edge_to_merge else: # If there isn't an existing edge, create a new one self._projection_edge = ProjectionPartitionableEdge( presynaptic_population, postsynaptic_population, machine_time_step, synapse_list=synapse_list, synapse_dynamics=synapse_dynamics, label=label) # add edge to the graph spinnaker_control.add_edge(self._projection_edge) self._projection_list_ranges = synapse_list.ranges()
def __init__(self, presynaptic_population, postsynaptic_population, label, connector, spinnaker_control, machine_time_step, user_max_delay, timescale_factor, source=None, target='excitatory', synapse_dynamics=None, rng=None): self._spinnaker = spinnaker_control self._projection_edge = None self._host_based_synapse_list = None self._has_retrieved_synaptic_list_from_machine = False if not isinstance(postsynaptic_population._get_vertex, AbstractPopulationVertex): raise exceptions.ConfigurationException( "postsynaptic population is not designed to receive" " synaptic projections") synapse_type = postsynaptic_population._get_vertex\ .synapse_type.get_synapse_id_by_target(target) if synapse_type is None: raise exceptions.ConfigurationException( "Synapse target {} not found in {}".format( target, postsynaptic_population.label)) synapse_dynamics_stdp = None if synapse_dynamics is None: synapse_dynamics_stdp = SynapseDynamicsStatic() else: synapse_dynamics_stdp = synapse_dynamics.slow postsynaptic_population._get_vertex.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(presynaptic_population, postsynaptic_population, rng, machine_time_step) 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 delay_extension_max_supported_delay = ( constants.MAX_DELAY_BLOCKS * constants.MAX_TIMER_TICS_SUPPORTED_PER_BLOCK) post_vertex_max_supported_delay_ms = \ postsynaptic_population._get_vertex.maximum_delay_supported_in_ms if max_delay > (post_vertex_max_supported_delay_ms + delay_extension_max_supported_delay): raise exceptions.ConfigurationException( "The maximum delay {} for projection is not supported".format( max_delay)) if max_delay > (user_max_delay / (machine_time_step / 1000.0)): logger.warn("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( presynaptic_population._get_vertex, postsynaptic_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 = ProjectionPartitionableEdge( presynaptic_population._get_vertex, postsynaptic_population._get_vertex, self._synapse_information, label=label) # add edge to the graph spinnaker_control.add_partitionable_edge(self._projection_edge, EDGE_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( presynaptic_population, postsynaptic_population, max_delay, post_vertex_max_supported_delay_ms, machine_time_step, timescale_factor) self._projection_edge.delay_edge = delay_edge 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 = presynaptic_population._get_vertex post_vertex = postsynaptic_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 _add_delay_extension(self, num_src_neurons, max_delay_for_projection, max_delay_per_neuron, original_synapse_list, presynaptic_population, postsynaptic_population, machine_time_step, timescale_factor, label, synapse_dynamics): """ Instantiate new delay extension component, connecting a new edge from the source vertex to it and new edges from it to the target (given by numBlocks). The outgoing edges cover each required block of delays, in groups of MAX_DELAYS_PER_NEURON delay slots (currently 16). """ # If there are any connections with a delay of less than the maximum, # create a direct connection between the two populations only # containing these connections direct_synaptic_sublist = original_synapse_list.create_delay_sublist( 0, max_delay_per_neuron) if direct_synaptic_sublist.get_max_n_connections() != 0: edge_to_merge = self._find_existing_edge( presynaptic_population._get_vertex, postsynaptic_population._get_vertex) if edge_to_merge is not None: self._projection_list_ranges = \ edge_to_merge.synapse_list.merge(direct_synaptic_sublist) self._projection_edge = edge_to_merge else: direct_edge = ProjectionPartitionableEdge( presynaptic_population, postsynaptic_population, self._spinnaker.machine_time_step, synapse_list=direct_synaptic_sublist, label=label) self._spinnaker.add_edge(direct_edge) self._projection_edge = direct_edge self._projection_list_ranges = direct_synaptic_sublist.ranges() # Create a delay extension vertex to do the extra delays delay_vertex = presynaptic_population._internal_delay_vertex if delay_vertex is None: source_name = presynaptic_population._get_vertex.label delay_name = "{}_delayed".format(source_name) delay_vertex = DelayExtensionVertex( n_neurons=num_src_neurons, source_vertex=presynaptic_population._get_vertex, max_delay_per_neuron=max_delay_per_neuron, machine_time_step=machine_time_step, timescale_factor=timescale_factor, label=delay_name) presynaptic_population._internal_delay_vertex = delay_vertex presynaptic_population._get_vertex.add_constraint( PartitionerSameSizeAsVertexConstraint(delay_vertex)) self._spinnaker.add_vertex(delay_vertex) # Create a connection from the source pynn_population.py to the # delay vertex existing_remaining_edge = self._find_existing_edge( presynaptic_population._get_vertex, delay_vertex) if existing_remaining_edge is None: new_label = "{}_to_DE".format(label) remaining_edge = DelayAfferentPartitionableEdge( presynaptic_population._get_vertex, delay_vertex, label=new_label) # add to graph self._spinnaker.add_edge(remaining_edge) # Create a list of the connections with delay larger than that which # can be handled by the neuron itself remaining_sublist = original_synapse_list.create_delay_sublist( max_delay_per_neuron + 1, max_delay_for_projection) # Create a special DelayEdge from the delay vertex to the outgoing # pynn_population.py, with the same set of connections delay_label = "DE to {}".format(label) num_blocks = int( math.floor( float(max_delay_for_projection - 1) / float(max_delay_per_neuron))) if num_blocks > delay_vertex.max_stages: delay_vertex.max_stages = num_blocks # Create the delay edge existing_delay_edge = self._find_existing_edge( delay_vertex, postsynaptic_population._get_vertex) if existing_delay_edge is not None: self._delay_list_ranges = existing_delay_edge.synapse_list.merge( remaining_sublist) self._delay_edge = existing_delay_edge else: self._delay_edge = DelayPartitionableEdge( presynaptic_population, postsynaptic_population, self._spinnaker.machine_time_step, num_blocks, max_delay_per_neuron, synapse_list=remaining_sublist, synapse_dynamics=synapse_dynamics, label=delay_label) self._delay_list_ranges = remaining_sublist.ranges() # add to graph self._spinnaker.add_edge(self._delay_edge)