def __init__(self, presynaptic_population, postsynaptic_population,
              machine_time_step, num_delay_stages, max_delay_per_neuron,
              connector=None, synapse_list=None, synapse_dynamics=None,
              label=None):
     ProjectionPartitionableEdge.__init__(self,
                                          presynaptic_population,
                                          postsynaptic_population,
                                          machine_time_step,
                                          connector=connector,
                                          synapse_list=synapse_list,
                                          synapse_dynamics=synapse_dynamics,
                                          label=label)
     self._pre_vertex = presynaptic_population._internal_delay_vertex
     self._stored_synaptic_data_from_machine = None
예제 #2
0
 def __init__(self,
              presynaptic_population,
              postsynaptic_population,
              machine_time_step,
              num_delay_stages,
              max_delay_per_neuron,
              connector=None,
              synapse_list=None,
              synapse_dynamics=None,
              label=None):
     ProjectionPartitionableEdge.__init__(self,
                                          presynaptic_population,
                                          postsynaptic_population,
                                          machine_time_step,
                                          connector=connector,
                                          synapse_list=synapse_list,
                                          synapse_dynamics=synapse_dynamics,
                                          label=label)
     self._pre_vertex = presynaptic_population._internal_delay_vertex
     self._stored_synaptic_data_from_machine = None
예제 #3
0
    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._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 not isinstance(postsynaptic_population._get_vertex,
                          AbstractPopulationVertex):

            raise exceptions.ConfigurationException(
                "postsynaptic population is not designed to receive"
                " synaptic projections")

        # Check that the "target" is an acceptable value
        synapse_type = postsynaptic_population._get_vertex.synapse_type
        targets = synapse_type.get_synapse_targets()
        if target not in targets:
            raise exceptions.ConfigurationException(
                "Target {} is not available in the post-synaptic population"
                " (choices are {})".format(target, targets))
        synapse_id = synapse_type.get_synapse_id_by_target(target)

        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_id)
        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 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(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, EDGE_PARTITION_ID)
                self._projection_list_ranges = synapse_list.ranges()
예제 #4
0
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.

    :param `pacman103.front.pynn.Population` presynaptic_population:
        presynaptic Population for the Projection
    :param `pacman103.front.pynn.Population` postsynaptic_population:
        postsynaptic Population for the Projection
    :param `pacman103.front.pynn.connectors` method:
        an instance of the connection method and parameters for the Projection
    """
    _projection_count = 0

    # noinspection PyUnusedLocal
    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._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 not isinstance(postsynaptic_population._get_vertex,
                          AbstractPopulationVertex):

            raise exceptions.ConfigurationException(
                "postsynaptic population is not designed to receive"
                " synaptic projections")

        # Check that the "target" is an acceptable value
        synapse_type = postsynaptic_population._get_vertex.synapse_type
        targets = synapse_type.get_synapse_targets()
        if target not in targets:
            raise exceptions.ConfigurationException(
                "Target {} is not available in the post-synaptic population"
                " (choices are {})".format(target, targets))
        synapse_id = synapse_type.get_synapse_id_by_target(target)

        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_id)
        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 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(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, EDGE_PARTITION_ID)
                self._projection_list_ranges = synapse_list.ranges()

    def _find_existing_edge(self, presynaptic_vertex, postsynaptic_vertex):
        """ searches though the partitionable graph's edges to locate any
        edge which has the same post and pre vertex

        :param presynaptic_vertex: the source partitionable vertex of the\
                multapse
        :type presynaptic_vertex: instance of\
                pacman.model.partitionable_graph.abstract_partitionable_vertex
        :param postsynaptic_vertex: The destination partitionable vertex of\
                the multapse
        :type postsynaptic_vertex: instance of\
                pacman.model.partitionable_graph.abstract_partitionable_vertex
        :return: None or the edge going to these vertices.
        """
        graph_edges = self._spinnaker.partitionable_graph.edges
        for edge in graph_edges:
            if ((edge.pre_vertex == presynaptic_vertex) and
                    (edge.post_vertex == postsynaptic_vertex)):
                return edge
        return None

    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, EDGE_PARTITION_ID)
                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, EDGE_PARTITION_ID)

        # 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, EDGE_PARTITION_ID)

    def describe(self, template='projection_default.txt', engine='default'):
        """
        Returns a human-readable description of the projection.

        The output may be customised by specifying a different template
        together with an associated template engine (see ``pyNN.descriptions``)

        If template is None, then a dictionary containing the template context
        will be returned.
        """
        # TODO
        raise NotImplementedError

    def __getitem__(self, i):
        """Return the `i`th connection within the Projection."""
        # TODO: Need to work out what is being returned
        raise NotImplementedError

    # noinspection PyPep8Naming
    def getDelays(self, format='list', gather=True):  # @ReservedAssignment
        """
        Get synaptic delays for all connections in this Projection.

        Possible formats are: a list of length equal to the number of
        connections in the projection, a 2D delay array (with NaN for
        non-existent connections).
        """
        if not gather:
            exceptions.ConfigurationException(
                "the gather param has no meaning for spinnaker when set to "
                "false")

        if (self._spinnaker.has_ran and not
                self._has_retrieved_synaptic_list_from_machine):
            self._retrieve_synaptic_data_from_machine()

        if format == 'list':
            delays = list()
            for row in self._host_based_synapse_list.get_rows():
                delays.extend(
                    numpy.asarray(
                        row.delays * (
                            float(self._spinnaker.machine_time_step) / 1000.0),
                        dtype=float))
            return delays

        delays = numpy.zeros((self._projection_edge.pre_vertex.n_atoms,
                              self._projection_edge.post_vertex.n_atoms))
        rows = self._host_based_synapse_list.get_rows()
        for pre_atom in range(len(rows)):
            row = rows[pre_atom]
            for i in xrange(len(row.target_indices)):
                post_atom = row.target_indices[i]
                delay = (float(row.delays[i]) *
                         (float(self._spinnaker.machine_time_step) / 1000.0))
                delays[pre_atom][post_atom] = delay
        return delays

    # noinspection PyPep8Naming
    def getSynapseDynamics(self, parameter_name, list_format='list',
                           gather=True):
        """
        Get parameters of the dynamic synapses for all connections in this
        Projection.
        :param parameter_name:
        :param list_format:
        :param gather:
        """
        # TODO: Need to work out what is to be returned
        raise NotImplementedError

    # noinspection PyPep8Naming
    def getWeights(self, format='list', gather=True):  # @ReservedAssignment
        """
        Get synaptic weights for all connections in this Projection.
        (pyNN gather parameter not supported from the signature
        getWeights(self, format='list', gather=True):)

        Possible formats are: a list of length equal to the number of
        connections in the projection, a 2D weight array (with NaN for
        non-existent connections). Note that for the array format, if there is
        more than connection between two cells, the summed weight will be
        given.
        :param format: the type of format to be returned (only support "list")
        :param gather: gather the weights from stuff. currently has no meaning\
                in spinnaker when set to false. Therefore is always true
        """
        if not gather:
            exceptions.ConfigurationException(
                "the gather param has no meaning for spinnaker when set to "
                "false")

        if (self._spinnaker.has_ran and not
                self._has_retrieved_synaptic_list_from_machine):
            self._retrieve_synaptic_data_from_machine()

        if format == 'list':
            weights = list()
            for row in self._host_based_synapse_list.get_rows():
                weights.extend(row.weights / self._weight_scale)
            return weights

        weights = None
        if self._projection_edge is not None:
            weights = numpy.empty((self._projection_edge.pre_vertex.n_atoms,
                                   self._projection_edge.post_vertex.n_atoms))
        else:
            weights = numpy.empty((self._delay_edge.pre_vertex.n_atoms,
                                   self._delay_edge.post_vertex.n_atoms))
        weights.fill(numpy.nan)
        rows = self._host_based_synapse_list.get_rows()
        for pre_atom in range(len(rows)):
            row = rows[pre_atom]
            for i in xrange(len(row.target_indices)):
                post_atom = row.target_indices[i]
                weight = row.weights[i]
                weights[pre_atom][post_atom] = weight / self._weight_scale
        return weights

    def __len__(self):
        """ Return the total number of local connections.
        """

        # TODO: Need to work out what this means
        raise NotImplementedError

    # noinspection PyPep8Naming
    def printDelays(self, file_name, list_format='list', gather=True):
        """
        Print synaptic weights to file. In the array format, zeros are printed
        for non-existent connections.
        """
        # TODO:
        raise NotImplementedError

    # noinspection PyPep8Naming
    def printWeights(self, file_name, list_format='list', gather=True):
        """
        Print synaptic weights to file. In the array format, zeros are printed
        for non-existent connections.
        """
        # TODO:
        raise NotImplementedError

    # noinspection PyPep8Naming
    def randomizeWeights(self, rand_distr):
        """
        Set weights to random values taken from rand_distr.
        """
        # TODO: Requires that the synapse list is not created proactively
        raise NotImplementedError

    # noinspection PyPep8Naming
    def randomizeDelays(self, rand_distr):
        """
        Set delays to random values taken from rand_distr.
        """
        # TODO: Requires that the synapse list is not created proactively
        raise NotImplementedError

    # noinspection PyPep8Naming
    def randomizeSynapseDynamics(self, param, rand_distr):
        """
        Set parameters of the synapse dynamics to values taken from rand_distr
        """
        # TODO: Look at what this is randomising
        raise NotImplementedError

    def __repr__(self):
        """
        returns a string representation of the projection
        """
        return "projection {}".format(self._projection_edge.label)

    def _retrieve_synaptic_data_from_machine(self):
        synapse_list = None
        delay_synapse_list = None
        if self._projection_edge is not None:
            synapse_list = \
                self._projection_edge.get_synaptic_list_from_machine(
                    graph_mapper=self._spinnaker.graph_mapper,
                    partitioned_graph=self._spinnaker.partitioned_graph,
                    placements=self._spinnaker.placements,
                    transceiver=self._spinnaker.transceiver,
                    routing_infos=self._spinnaker.routing_infos)
        if self._delay_edge is not None:
            delay_synapse_list = \
                self._delay_edge.get_synaptic_list_from_machine(
                    graph_mapper=self._spinnaker.graph_mapper,
                    placements=self._spinnaker.placements,
                    transceiver=self._spinnaker.transceiver,
                    partitioned_graph=self._spinnaker.partitioned_graph,
                    routing_infos=self._spinnaker.routing_infos)

        # If there is both a delay and a non-delay list, merge them
        if synapse_list is not None and delay_synapse_list is not None:
            rows = synapse_list.get_rows()
            delay_rows = delay_synapse_list.get_rows()
            combined_rows = list()
            for i in range(len(rows)):
                combined_row = rows[i][self._projection_list_ranges[i]]
                combined_row.append(delay_rows[i][self._delay_list_ranges[i]])
                combined_rows.append(combined_row)
            self._host_based_synapse_list = SynapticList(combined_rows)

        # If there is only a synapse list, return that
        elif synapse_list is not None:
            rows = synapse_list.get_rows()
            new_rows = list()
            for i in range(len(rows)):
                new_rows.append(rows[i][self._projection_list_ranges[i]])
            self._host_based_synapse_list = SynapticList(new_rows)

        # Otherwise return the delay list (there should be at least one!)
        else:
            rows = delay_synapse_list.get_rows()
            new_rows = list()
            for i in range(len(rows)):
                new_rows.append(rows[i][self._delay_list_ranges[i]])
            self._host_based_synapse_list = SynapticList(new_rows)

        self._has_retrieved_synaptic_list_from_machine = True

    # noinspection PyPep8Naming
    def saveConnections(self, file_name, gather=True, compatible_output=True):
        """
        Save connections to file in a format suitable for reading in with a
        FromFileConnector.
        """
        # TODO
        raise NotImplementedError

    def size(self, gather=True):
        """
        Return the total number of connections.
         - only local connections, if gather is False,
         - all connections, if gather is True (default)
        """
        # TODO
        raise NotImplementedError

    # noinspection PyPep8Naming
    def setDelays(self, d):
        """
        d can be a single number, in which case all delays are set to this
        value, or a list/1D array of length equal to the number of connections
        in the projection, or a 2D array with the same dimensions as the
        connectivity matrix (as returned by `getDelays(format='array')`).
        """
        # TODO: Requires that the synapse list is not created proactively
        raise NotImplementedError

    # noinspection PyPep8Naming
    def setSynapseDynamics(self, param, value):
        """
        Set parameters of the dynamic synapses for all connections in this
        projection.
        """
        # TODO: Need to set this in the edge
        raise NotImplementedError

    # noinspection PyPep8Naming
    def setWeights(self, w):
        """
        w can be a single number, in which case all weights are set to this
        value, or a list/1D array of length equal to the number of connections
        in the projection, or a 2D array with the same dimensions as the
        connectivity matrix (as returned by `getWeights(format='array')`).
        Weights should be in nA for current-based and uS for conductance-based
        synapses.
        """

        # TODO: Requires that the synapse list is not created proactively
        raise NotImplementedError

    # noinspection PyPep8Naming
    def weightHistogram(self, min_weight=None, max_weight=None, nbins=10):
        """
        Return a histogram of synaptic weights.
        If min and max are not given, the minimum and maximum weights are
        calculated automatically.
        """
        # TODO
        raise NotImplementedError
예제 #5
0
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.
    """

    # noinspection PyUnusedLocal
    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)

    @property
    def requires_mapping(self):
        if (isinstance(self._projection_edge, AbstractChangableAfterRun)
                and self._projection_edge.requires_mapping):
            return True
        return False

    def mark_no_changes(self):
        if isinstance(self._projection_edge, AbstractChangableAfterRun):
            self._projection_edge.mark_no_changes()

    def _find_existing_edge(self, presynaptic_vertex, postsynaptic_vertex):
        """ Searches though the partitionable graph's edges to locate any\
            edge which has the same post and pre vertex

        :param presynaptic_vertex: the source partitionable vertex of the\
                multapse
        :type presynaptic_vertex: instance of\
                pacman.model.partitionable_graph.abstract_partitionable_vertex
        :param postsynaptic_vertex: The destination partitionable vertex of\
                the multapse
        :type postsynaptic_vertex: instance of\
                pacman.model.partitionable_graph.abstract_partitionable_vertex
        :return: None or the edge going to these vertices.
        """
        graph_edges = self._spinnaker.partitionable_graph.edges
        for edge in graph_edges:
            if ((edge.pre_vertex == presynaptic_vertex)
                    and (edge.post_vertex == postsynaptic_vertex)):
                return edge
        return None

    def _add_delay_extension(self, presynaptic_population,
                             postsynaptic_population, max_delay_for_projection,
                             max_delay_per_neuron, machine_time_step,
                             timescale_factor):
        """ Instantiate delay extension component
        """

        # Create a delay extension vertex to do the extra delays
        delay_vertex = presynaptic_population._internal_delay_vertex
        pre_vertex = presynaptic_population._get_vertex
        if delay_vertex is None:
            delay_name = "{}_delayed".format(pre_vertex.label)
            delay_vertex = DelayExtensionVertex(pre_vertex.n_atoms,
                                                max_delay_per_neuron,
                                                pre_vertex,
                                                machine_time_step,
                                                timescale_factor,
                                                label=delay_name)
            presynaptic_population._internal_delay_vertex = delay_vertex
            pre_vertex.add_constraint(
                PartitionerSameSizeAsVertexConstraint(delay_vertex))
            self._spinnaker.add_partitionable_vertex(delay_vertex)

            # Add the edge
            delay_afferent_edge = DelayAfferentPartitionableEdge(
                pre_vertex,
                delay_vertex,
                label="{}_to_DelayExtension".format(pre_vertex.label))
            self._spinnaker.add_partitionable_edge(delay_afferent_edge,
                                                   EDGE_PARTITION_ID)

        # Ensure that the delay extension knows how many states it will support
        n_stages = int(
            math.ceil(
                float(max_delay_for_projection - max_delay_per_neuron) /
                float(max_delay_per_neuron)))
        if n_stages > delay_vertex.n_delay_stages:
            delay_vertex.n_delay_stages = n_stages

        # Create the delay edge if there isn't one already
        post_vertex = postsynaptic_population._get_vertex
        delay_edge = self._find_existing_edge(delay_vertex, post_vertex)
        if delay_edge is None:
            delay_edge = MultiCastPartitionableEdge(
                delay_vertex,
                post_vertex,
                label="{}_delayed_to_{}".format(pre_vertex.label,
                                                post_vertex.label))
            self._spinnaker.add_partitionable_edge(delay_edge,
                                                   EDGE_PARTITION_ID)
        return delay_edge

    def describe(self, template='projection_default.txt', engine='default'):
        """ Return a human-readable description of the projection.

        The output may be customised by specifying a different template
        together with an associated template engine (see ``pyNN.descriptions``)

        If template is None, then a dictionary containing the template context
        will be returned.
        """
        # TODO
        raise NotImplementedError

    def __getitem__(self, i):
        """Return the `i`th connection within the Projection."""
        # TODO: Need to work out what is being returned
        raise NotImplementedError

    # noinspection PyPep8Naming
    def getSynapseDynamics(self,
                           parameter_name,
                           list_format='list',
                           gather=True):
        """ Get parameters of the dynamic synapses for all connections in this\
            Projection.
        :param parameter_name:
        :param list_format:
        :param gather:
        """
        # TODO: Need to work out what is to be returned
        raise NotImplementedError

    def _get_synaptic_data(self, as_list, data_to_get):

        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:
            post_vertex = self._projection_edge.post_vertex
            pre_vertex = self._projection_edge.pre_vertex
            return ConnectionHolder(data_to_get, as_list, pre_vertex.n_atoms,
                                    post_vertex.n_atoms,
                                    self._virtual_connection_list)

        connection_holder = ConnectionHolder(data_to_get, as_list,
                                             pre_vertex.n_atoms,
                                             post_vertex.n_atoms)

        # If we haven't run, add the holder to get connections, and return it
        if not self._spinnaker.has_ran:

            post_vertex.add_pre_run_connection_holder(
                connection_holder, self._projection_edge,
                self._synapse_information)
            return connection_holder

        # Otherwise, get the connections now
        graph_mapper = self._spinnaker.graph_mapper
        placements = self._spinnaker.placements
        transceiver = self._spinnaker.transceiver
        routing_infos = self._spinnaker.routing_infos
        partitioned_graph = self._spinnaker.partitioned_graph
        subedges = graph_mapper.get_partitioned_edges_from_partitionable_edge(
            self._projection_edge)
        progress = ProgressBar(
            len(subedges),
            "Getting {}s for projection between {} and {}".format(
                data_to_get, pre_vertex.label, post_vertex.label))
        for subedge in subedges:
            placement = placements.get_placement_of_subvertex(
                subedge.post_subvertex)
            connections = post_vertex.get_connections_from_machine(
                transceiver, placement, subedge, graph_mapper, routing_infos,
                self._synapse_information, partitioned_graph)
            if connections is not None:
                connection_holder.add_connections(connections)
            progress.update()
        progress.end()
        connection_holder.finish()
        return connection_holder

    # noinspection PyPep8Naming
    def getWeights(self, format='list', gather=True):  # @ReservedAssignment
        """
        Get synaptic weights for all connections in this Projection.

        Possible formats are: a list of length equal to the number of
        connections in the projection, a 2D weight array (with NaN for
        non-existent connections). Note that for the array format, if there is
        more than connection between two cells, the summed weight will be
        given.
        :param format: the type of format to be returned (only support "list")
        :param gather: gather the weights from stuff. currently has no meaning\
                in spinnaker when set to false. Therefore is always true
        """
        if not gather:
            exceptions.ConfigurationException(
                "the gather param has no meaning for spinnaker when set to "
                "false")

        return self._get_synaptic_data(format == 'list', "weight")

    # noinspection PyPep8Naming
    def getDelays(self, format='list', gather=True):  # @ReservedAssignment
        """
        Get synaptic delays for all connections in this Projection.

        Possible formats are: a list of length equal to the number of
        connections in the projection, a 2D delay array (with NaN for
        non-existent connections).
        """
        if not gather:
            exceptions.ConfigurationException(
                "the gather param has no meaning for spinnaker when set to "
                "false")

        return self._get_synaptic_data(format == 'list', "delay")

    def __len__(self):
        """ Return the total number of local connections.
        """

        # TODO: Need to work out what this means
        raise NotImplementedError

    # noinspection PyPep8Naming
    def printDelays(self, file_name, list_format='list', gather=True):
        """ Print synaptic weights to file. In the array format, zeros are\
            printed for non-existent connections.
        """
        # TODO:
        raise NotImplementedError

    # noinspection PyPep8Naming
    def printWeights(self, file_name, list_format='list', gather=True):
        """ Print synaptic weights to file. In the array format, zeros are\
            printed for non-existent connections.
        """
        # TODO:
        raise NotImplementedError

    # noinspection PyPep8Naming
    def randomizeWeights(self, rand_distr):
        """ Set weights to random values taken from rand_distr.
        """
        # TODO: Requires that the synapse list is not created proactively
        raise NotImplementedError

    # noinspection PyPep8Naming
    def randomizeDelays(self, rand_distr):
        """ Set delays to random values taken from rand_distr.
        """
        # TODO: Requires that the synapse list is not created proactively
        raise NotImplementedError

    # noinspection PyPep8Naming
    def randomizeSynapseDynamics(self, param, rand_distr):
        """ Set parameters of the synapse dynamics to values taken from\
            rand_distr
        """
        # TODO: Look at what this is randomising
        raise NotImplementedError

    def __repr__(self):
        return "projection {}".format(self._projection_edge.label)

    # noinspection PyPep8Naming
    def saveConnections(self, file_name, gather=True, compatible_output=True):
        """ Save connections to file in a format suitable for reading in with\
            a FromFileConnector.
        """
        # TODO
        raise NotImplementedError

    def size(self, gather=True):
        """ Return the total number of connections.
         - only local connections, if gather is False,
         - all connections, if gather is True (default)
        """
        # TODO
        raise NotImplementedError

    # noinspection PyPep8Naming
    def setDelays(self, d):
        """ Set the delays

        d can be a single number, in which case all delays are set to this\
        value, or a list/1D array of length equal to the number of connections\
        in the projection, or a 2D array with the same dimensions as the\
        connectivity matrix (as returned by `getDelays(format='array')`).
        """
        # TODO: Requires that the synapse list is not created proactively
        raise NotImplementedError

    # noinspection PyPep8Naming
    def setSynapseDynamics(self, param, value):
        """ Set parameters of the dynamic synapses for all connections in this\
            projection.
        """
        # TODO: Need to set this in the edge
        raise NotImplementedError

    # noinspection PyPep8Naming
    def setWeights(self, w):
        """ Set the weights

        w can be a single number, in which case all weights are set to this\
        value, or a list/1D array of length equal to the number of connections\
        in the projection, or a 2D array with the same dimensions as the\
        connectivity matrix (as returned by `getWeights(format='array')`).\
        Weights should be in nA for current-based and uS for conductance-based\
        synapses.
        """

        # TODO: Requires that the synapse list is not created proactively
        raise NotImplementedError

    # noinspection PyPep8Naming
    def weightHistogram(self, min_weight=None, max_weight=None, nbins=10):
        """ Return a histogram of synaptic weights.

        If min and max are not given, the minimum and maximum weights are\
        calculated automatically.
        """
        # TODO
        raise NotImplementedError
예제 #6
0
    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)
예제 #7
0
    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)
예제 #8
0
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.
    """

    # noinspection PyUnusedLocal
    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)

    @property
    def requires_mapping(self):
        if (isinstance(self._projection_edge, AbstractChangableAfterRun) and
                self._projection_edge.requires_mapping):
            return True
        return False

    def mark_no_changes(self):
        if isinstance(self._projection_edge, AbstractChangableAfterRun):
            self._projection_edge.mark_no_changes()

    def _find_existing_edge(self, presynaptic_vertex, postsynaptic_vertex):
        """ Searches though the partitionable graph's edges to locate any\
            edge which has the same post and pre vertex

        :param presynaptic_vertex: the source partitionable vertex of the\
                multapse
        :type presynaptic_vertex: instance of\
                pacman.model.partitionable_graph.abstract_partitionable_vertex
        :param postsynaptic_vertex: The destination partitionable vertex of\
                the multapse
        :type postsynaptic_vertex: instance of\
                pacman.model.partitionable_graph.abstract_partitionable_vertex
        :return: None or the edge going to these vertices.
        """
        graph_edges = self._spinnaker.partitionable_graph.edges
        for edge in graph_edges:
            if ((edge.pre_vertex == presynaptic_vertex) and
                    (edge.post_vertex == postsynaptic_vertex)):
                return edge
        return None

    def _add_delay_extension(
            self, presynaptic_population, postsynaptic_population,
            max_delay_for_projection, max_delay_per_neuron, machine_time_step,
            timescale_factor):
        """ Instantiate delay extension component
        """

        # Create a delay extension vertex to do the extra delays
        delay_vertex = presynaptic_population._internal_delay_vertex
        pre_vertex = presynaptic_population._get_vertex
        if delay_vertex is None:
            delay_name = "{}_delayed".format(pre_vertex.label)
            delay_vertex = DelayExtensionVertex(
                pre_vertex.n_atoms, max_delay_per_neuron, pre_vertex,
                machine_time_step, timescale_factor, label=delay_name)
            presynaptic_population._internal_delay_vertex = delay_vertex
            pre_vertex.add_constraint(
                PartitionerSameSizeAsVertexConstraint(delay_vertex))
            self._spinnaker.add_partitionable_vertex(delay_vertex)

            # Add the edge
            delay_afferent_edge = DelayAfferentPartitionableEdge(
                pre_vertex, delay_vertex, label="{}_to_DelayExtension".format(
                    pre_vertex.label))
            self._spinnaker.add_partitionable_edge(
                delay_afferent_edge, EDGE_PARTITION_ID)

        # Ensure that the delay extension knows how many states it will support
        n_stages = int(math.ceil(
            float(max_delay_for_projection - max_delay_per_neuron) /
            float(max_delay_per_neuron)))
        if n_stages > delay_vertex.n_delay_stages:
            delay_vertex.n_delay_stages = n_stages

        # Create the delay edge if there isn't one already
        post_vertex = postsynaptic_population._get_vertex
        delay_edge = self._find_existing_edge(delay_vertex, post_vertex)
        if delay_edge is None:
            delay_edge = DelayedPartitionableEdge(
                delay_vertex, post_vertex, self._synapse_information,
                label="{}_delayed_to_{}".format(
                    pre_vertex.label, post_vertex.label))
            self._spinnaker.add_partitionable_edge(
                delay_edge, EDGE_PARTITION_ID)
        else:
            delay_edge.add_synapse_information(self._synapse_information)
        return delay_edge

    def describe(self, template='projection_default.txt', engine='default'):
        """ Return a human-readable description of the projection.

        The output may be customised by specifying a different template
        together with an associated template engine (see ``pyNN.descriptions``)

        If template is None, then a dictionary containing the template context
        will be returned.
        """
        # TODO
        raise NotImplementedError

    def __getitem__(self, i):
        """Return the `i`th connection within the Projection."""
        # TODO: Need to work out what is being returned
        raise NotImplementedError

    # noinspection PyPep8Naming
    def getSynapseDynamics(self, parameter_name, list_format='list',
                           gather=True):
        """ Get parameters of the dynamic synapses for all connections in this\
            Projection.
        :param parameter_name:
        :param list_format:
        :param gather:
        """
        # TODO: Need to work out what is to be returned
        raise NotImplementedError

    def _get_synaptic_data(self, as_list, data_to_get):

        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:
            post_vertex = self._projection_edge.post_vertex
            pre_vertex = self._projection_edge.pre_vertex
            return ConnectionHolder(
                data_to_get, as_list, pre_vertex.n_atoms, post_vertex.n_atoms,
                self._virtual_connection_list)

        connection_holder = ConnectionHolder(
            data_to_get, as_list, pre_vertex.n_atoms, post_vertex.n_atoms)

        # If we haven't run, add the holder to get connections, and return it
        if not self._spinnaker.has_ran:

            post_vertex.add_pre_run_connection_holder(
                connection_holder, self._projection_edge,
                self._synapse_information)
            return connection_holder

        # Otherwise, get the connections now
        graph_mapper = self._spinnaker.graph_mapper
        placements = self._spinnaker.placements
        transceiver = self._spinnaker.transceiver
        routing_infos = self._spinnaker.routing_infos
        partitioned_graph = self._spinnaker.partitioned_graph
        subedges = graph_mapper.get_partitioned_edges_from_partitionable_edge(
            self._projection_edge)
        progress = ProgressBar(
            len(subedges),
            "Getting {}s for projection between {} and {}".format(
                data_to_get, pre_vertex.label, post_vertex.label))
        for subedge in subedges:
            placement = placements.get_placement_of_subvertex(
                subedge.post_subvertex)
            connections = post_vertex.get_connections_from_machine(
                transceiver, placement, subedge, graph_mapper, routing_infos,
                self._synapse_information, partitioned_graph)
            if connections is not None:
                connection_holder.add_connections(connections)
            progress.update()
        progress.end()
        connection_holder.finish()
        return connection_holder

    # noinspection PyPep8Naming
    def getWeights(self, format='list', gather=True):  # @ReservedAssignment
        """
        Get synaptic weights for all connections in this Projection.

        Possible formats are: a list of length equal to the number of
        connections in the projection, a 2D weight array (with NaN for
        non-existent connections). Note that for the array format, if there is
        more than connection between two cells, the summed weight will be
        given.
        :param format: the type of format to be returned (only support "list")
        :param gather: gather the weights from stuff. currently has no meaning\
                in spinnaker when set to false. Therefore is always true
        """
        if not gather:
            exceptions.ConfigurationException(
                "the gather param has no meaning for spinnaker when set to "
                "false")

        return self._get_synaptic_data(format == 'list', "weight")

    # noinspection PyPep8Naming
    def getDelays(self, format='list', gather=True):  # @ReservedAssignment
        """
        Get synaptic delays for all connections in this Projection.

        Possible formats are: a list of length equal to the number of
        connections in the projection, a 2D delay array (with NaN for
        non-existent connections).
        """
        if not gather:
            exceptions.ConfigurationException(
                "the gather param has no meaning for spinnaker when set to "
                "false")

        return self._get_synaptic_data(format == 'list', "delay")

    def __len__(self):
        """ Return the total number of local connections.
        """

        # TODO: Need to work out what this means
        raise NotImplementedError

    # noinspection PyPep8Naming
    def printDelays(self, file_name, list_format='list', gather=True):
        """ Print synaptic weights to file. In the array format, zeros are\
            printed for non-existent connections.
        """
        # TODO:
        raise NotImplementedError

    # noinspection PyPep8Naming
    def printWeights(self, file_name, list_format='list', gather=True):
        """ Print synaptic weights to file. In the array format, zeros are\
            printed for non-existent connections.
        """
        # TODO:
        raise NotImplementedError

    # noinspection PyPep8Naming
    def randomizeWeights(self, rand_distr):
        """ Set weights to random values taken from rand_distr.
        """
        # TODO: Requires that the synapse list is not created proactively
        raise NotImplementedError

    # noinspection PyPep8Naming
    def randomizeDelays(self, rand_distr):
        """ Set delays to random values taken from rand_distr.
        """
        # TODO: Requires that the synapse list is not created proactively
        raise NotImplementedError

    # noinspection PyPep8Naming
    def randomizeSynapseDynamics(self, param, rand_distr):
        """ Set parameters of the synapse dynamics to values taken from\
            rand_distr
        """
        # TODO: Look at what this is randomising
        raise NotImplementedError

    def __repr__(self):
        return "projection {}".format(self._projection_edge.label)

    # noinspection PyPep8Naming
    def saveConnections(self, file_name, gather=True, compatible_output=True):
        """ Save connections to file in a format suitable for reading in with\
            a FromFileConnector.
        """
        # TODO
        raise NotImplementedError

    def size(self, gather=True):
        """ Return the total number of connections.
         - only local connections, if gather is False,
         - all connections, if gather is True (default)
        """
        # TODO
        raise NotImplementedError

    # noinspection PyPep8Naming
    def setDelays(self, d):
        """ Set the delays

        d can be a single number, in which case all delays are set to this\
        value, or a list/1D array of length equal to the number of connections\
        in the projection, or a 2D array with the same dimensions as the\
        connectivity matrix (as returned by `getDelays(format='array')`).
        """
        # TODO: Requires that the synapse list is not created proactively
        raise NotImplementedError

    # noinspection PyPep8Naming
    def setSynapseDynamics(self, param, value):
        """ Set parameters of the dynamic synapses for all connections in this\
            projection.
        """
        # TODO: Need to set this in the edge
        raise NotImplementedError

    # noinspection PyPep8Naming
    def setWeights(self, w):
        """ Set the weights

        w can be a single number, in which case all weights are set to this\
        value, or a list/1D array of length equal to the number of connections\
        in the projection, or a 2D array with the same dimensions as the\
        connectivity matrix (as returned by `getWeights(format='array')`).\
        Weights should be in nA for current-based and uS for conductance-based\
        synapses.
        """

        # TODO: Requires that the synapse list is not created proactively
        raise NotImplementedError

    # noinspection PyPep8Naming
    def weightHistogram(self, min_weight=None, max_weight=None, nbins=10):
        """ Return a histogram of synaptic weights.

        If min and max are not given, the minimum and maximum weights are\
        calculated automatically.
        """
        # TODO
        raise NotImplementedError
예제 #9
0
    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()
예제 #10
0
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.

    :param `pacman103.front.pynn.Population` presynaptic_population:
        presynaptic Population for the Projection
    :param `pacman103.front.pynn.Population` postsynaptic_population:
        postsynaptic Population for the Projection
    :param `pacman103.front.pynn.connectors` method:
        an instance of the connection method and parameters for the Projection
    """
    _projection_count = 0

    # noinspection PyUnusedLocal
    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 _find_existing_edge(self, presynaptic_vertex, postsynaptic_vertex):
        """ searches though the partitionable graph's edges to locate any
        edge which has the same post and pre vertex

        :param presynaptic_vertex: the source partitionable vertex of the
        multapse
        :type presynaptic_vertex: instance of
        pacman.model.partitionable_graph.abstract_partitionable_vertex
        :param postsynaptic_vertex: The destination partitionable vertex of
        the multapse
        :type postsynaptic_vertex: instance of
        pacman.model.partitionable_graph.abstract_partitionable_vertex
        :return: None or the edge going to these vertices.
        """
        graph_edges = self._spinnaker.partitionable_graph.edges
        for edge in graph_edges:
            if ((edge.pre_vertex == presynaptic_vertex)
                    and (edge.post_vertex == postsynaptic_vertex)):
                return edge
        return None

    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)

    def describe(self, template='projection_default.txt', engine='default'):
        """
        Returns a human-readable description of the projection.

        The output may be customized by specifying a different template
        togther with an associated template engine (see ``pyNN.descriptions``).

        If template is None, then a dictionary containing the template context
        will be returned.
        """
        raise NotImplementedError

    def __getitem__(self, i):
        """Return the `i`th connection within the Projection."""
        raise NotImplementedError

    # noinspection PyPep8Naming
    def getDelays(self, format='list', gather=True):
        """
        Get synaptic delays for all connections in this Projection.

        Possible formats are: a list of length equal to the number of
        connections in the projection, a 2D delay array (with NaN for
        non-existent connections).
        """
        if not gather:
            exceptions.ConfigurationException(
                "the gather param has no meaning for spinnaker when set to "
                "false")

        if (self._spinnaker.has_ran
                and not self._has_retrieved_synaptic_list_from_machine):
            self._retrieve_synaptic_data_from_machine()

        if format == 'list':
            delays = list()
            for row in self._host_based_synapse_list.get_rows():
                delays.extend(
                    numpy.asarray(
                        row.delays *
                        (float(self._spinnaker.machine_time_step) / 1000.0),
                        dtype=float))
            return delays

        delays = numpy.zeros((self._projection_edge.pre_vertex.n_atoms,
                              self._projection_edge.post_vertex.n_atoms))
        rows = self._host_based_synapse_list.get_rows()
        for pre_atom in range(len(rows)):
            row = rows[pre_atom]
            for i in xrange(len(row.target_indices)):
                post_atom = row.target_indices[i]
                delay = (float(row.delays[i]) *
                         (float(self._spinnaker.machine_time_step) / 1000.0))
                delays[pre_atom][post_atom] = delay
        return delays

    # noinspection PyPep8Naming
    def getSynapseDynamics(self,
                           parameter_name,
                           list_format='list',
                           gather=True):
        """
        Get parameters of the dynamic synapses for all connections in this
        Projection.
        """
        raise NotImplementedError

    # noinspection PyPep8Naming
    def getWeights(self, format='list', gather=True):
        """
        Get synaptic weights for all connections in this Projection.
        (pyNN gather parameter not supported from the signiture
        getWeights(self, format='list', gather=True):)

        Possible formats are: a list of length equal to the number of
        connections in the projection, a 2D weight array (with NaN for
        non-existent connections). Note that for the array format, if there is
        more than connection between two cells, the summed weight will be
        given.
        """
        if not gather:
            exceptions.ConfigurationException(
                "the gather param has no meaning for spinnaker when set to "
                "false")

        if (self._spinnaker.has_ran
                and not self._has_retrieved_synaptic_list_from_machine):
            self._retrieve_synaptic_data_from_machine()

        if format == 'list':
            weights = list()
            for row in self._host_based_synapse_list.get_rows():
                weights.extend(row.weights / self._weight_scale)
            return weights

        weights = numpy.empty((self._projection_edge.pre_vertex.n_atoms,
                               self._projection_edge.post_vertex.n_atoms))
        weights.fill(numpy.nan)
        rows = self._host_based_synapse_list.get_rows()
        for pre_atom in range(len(rows)):
            row = rows[pre_atom]
            for i in xrange(len(row.target_indices)):
                post_atom = row.target_indices[i]
                weight = row.weights[i]
                weights[pre_atom][post_atom] = weight / self._weight_scale
        return weights

    def __len__(self):
        """Return the total number of local connections."""
        raise NotImplementedError

    # noinspection PyPep8Naming
    def printDelays(self, file_name, list_format='list', gather=True):
        """
        Print synaptic weights to file. In the array format, zeros are printed
        for non-existent connections.
        """
        raise NotImplementedError

    # noinspection PyPep8Naming
    def printWeights(self, file_name, list_format='list', gather=True):
        """
        Print synaptic weights to file. In the array format, zeros are printed
        for non-existent connections.
        """
        raise NotImplementedError

    # noinspection PyPep8Naming
    def randomizeWeights(self, rand_distr):
        """
        Set weights to random values taken from rand_distr.
        """
        raise NotImplementedError

    # noinspection PyPep8Naming
    def randomizeDelays(self, rand_distr):
        """
        Set delays to random values taken from rand_distr.
        """
        raise NotImplementedError

    # noinspection PyPep8Naming
    def randomizeSynapseDynamics(self, param, rand_distr):
        """
        Set parameters of the synapse dynamics to values taken from rand_distr
        """
        raise NotImplementedError

    def __repr__(self):
        """
        returns a string rep of the projection
        """
        return "projection {}".format(self._projection_edge.label)

    def _retrieve_synaptic_data_from_machine(self):
        synapse_list = None
        delay_synapse_list = None
        if self._projection_edge is not None:
            synapse_list = \
                self._projection_edge.get_synaptic_list_from_machine(
                    graph_mapper=self._spinnaker.graph_mapper,
                    partitioned_graph=self._spinnaker.partitioned_graph,
                    placements=self._spinnaker.placements,
                    transceiver=self._spinnaker.transceiver,
                    routing_infos=self._spinnaker.routing_infos)
        if self._delay_edge is not None:
            delay_synapse_list = \
                self._delay_edge.get_synaptic_list_from_machine(
                    graph_mapper=self._spinnaker.graph_mapper,
                    placements=self._spinnaker.placements,
                    transceiver=self._spinnaker.transceiver,
                    partitioned_graph=self._spinnaker.partitioned_graph,
                    routing_infos=self._spinnaker.routing_infos)

        # If there is both a delay and a non-delay list, merge them
        if synapse_list is not None and delay_synapse_list is not None:
            rows = synapse_list.get_rows()
            delay_rows = delay_synapse_list.get_rows()
            combined_rows = list()
            for i in range(len(rows)):
                combined_row = rows[i][self._projection_list_ranges[i]]
                combined_row.append(delay_rows[i][self._delay_list_ranges[i]])
                combined_rows.append(combined_row)
            self._host_based_synapse_list = SynapticList(combined_rows)

        # If there is only a synapse list, return that
        elif synapse_list is not None:
            rows = synapse_list.get_rows()
            new_rows = list()
            for i in range(len(rows)):
                new_rows.append(rows[i][self._projection_list_ranges[i]])
            self._host_based_synapse_list = SynapticList(new_rows)

        # Otherwise return the delay list (there should be at least one!)
        else:
            rows = delay_synapse_list.get_rows()
            new_rows = list()
            for i in range(len(rows)):
                new_rows.append(rows[i][self._delay_list_ranges[i]])
            self._host_based_synapse_list = SynapticList(new_rows)

        self._has_retrieved_synaptic_list_from_machine = True

    # noinspection PyPep8Naming
    def saveConnections(self, file_name, gather=True, compatible_output=True):
        """
        Save connections to file in a format suitable for reading in with a
        FromFileConnector.
        """
        raise NotImplementedError

    def size(self, gather=True):
        """
        Return the total number of connections.
         - only local connections, if gather is False,
         - all connections, if gather is True (default)
        """
        raise NotImplementedError

    # noinspection PyPep8Naming
    def setDelays(self, d):
        """
        d can be a single number, in which case all delays are set to this
        value, or a list/1D array of length equal to the number of connections
        in the projection, or a 2D array with the same dimensions as the
        connectivity matrix (as returned by `getDelays(format='array')`).
        """
        raise NotImplementedError

    # noinspection PyPep8Naming
    def setSynapseDynamics(self, param, value):
        """
        Set parameters of the dynamic synapses for all connections in this
        projection.
        """
        raise NotImplementedError

    # noinspection PyPep8Naming
    def setWeights(self, w):
        """
        w can be a single number, in which case all weights are set to this
        value, or a list/1D array of length equal to the number of connections
        in the projection, or a 2D array with the same dimensions as the
        connectivity matrix (as returned by `getWeights(format='array')`).
        Weights should be in nA for current-based and uS for conductance-based
        synapses.
        """
        raise NotImplementedError

    # noinspection PyPep8Naming
    def weightHistogram(self, min_weight=None, max_weight=None, nbins=10):
        """
        Return a histogram of synaptic weights.
        If min and max are not given, the minimum and maximum weights are
        calculated automatically.
        """
        raise NotImplementedError
예제 #11
0
    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)