Exemplo n.º 1
0
    def create_row_info_from_elements(p_p_entries, f_f_entries,
                                      f_p_entries, bits_reserved_for_type,
                                      weight_scales):
        """
        takes a collection of entries for both fixed fixed, plastic plasitic
        and fixed plastic and returns a synaptic row object for them

        p_p_entries and f_p_entries are ignored due to this model dealing with
        fixed synapses
        """
        if len(p_p_entries) > 0 or len(f_p_entries) > 0:
            raise exceptions.SynapticBlockGenerationException(
                "fixed synaptic row ios cannot be built from plastic entries"
            )

        synaptic_type_mask = (1 << bits_reserved_for_type) - 1
        delay_mask = (1 << (8 - bits_reserved_for_type)) - 1

        # Extract indices, delays and synapse types from fixed-plastic region
        target_indices = f_f_entries & 0xFF
        delays_in_ticks = ((f_f_entries >> 8 + bits_reserved_for_type) &
                           delay_mask)
        synapse_types = (f_f_entries >> 8) & synaptic_type_mask

        # Convert per-synapse type weight scales to numpy and
        # Index this to obtain per-synapse weight scales.
        weight_scales_numpy = numpy.array(weight_scales, dtype="float")
        synapse_weight_scales = weight_scales_numpy[synapse_types]

        # Finally, shift out the weights from the fixed words and scale
        weights = (f_f_entries >> 16).astype("float") / synapse_weight_scales

        return SynapseRowInfo(target_indices, weights, delays_in_ticks,
                              synapse_types)
    def update_master_population_table(
            self, spec, block_start_addr, row_length, keys_and_masks,
            master_pop_table_region):
        """
        Writes an entry in the Master Population Table for the newly
        created synaptic block.
        An entry in the table is a 16-bit value, with the following structure:
        Bits [2:0]  Row length information. This value (from 0->7)
                    indicates the maximum number of synapses in this
                    block. It is translated in the row length translation
                    table by the executing code each time the table is
                    accessed, to calculate offsets.
        Bits [15:3] Address within the synaptic matrix region of the
                    start of the block. This is 1K bytes aligned, so
                    the true value is found by shifting left by 7 bits
                    then adding the start address of the memory region.
        :param spec:
        :param block_start_addr:
        :param row_length:
        :param keys_and_masks:
        :param mask:
        :param master_pop_table_region:
        :return:
        """
        # Which core has this projection arrived from?
        key = keys_and_masks[0].key
        x = get_x_from_key(key)
        y = get_y_from_key(key)
        p = get_p_from_key(key)

        # Calculate the index into the master pynn_population.py table for
        # a projection from the given core:
        table_slot_addr = self._get_table_address_from_coords(x, y, p)
        row_index = self._get_row_length_table_index(row_length)

        # What is the write address in the table for this index?
        spec.comment("\nUpdate entry in master pynn_population.py table for "
                     "incoming connection from {}, {}, {}:\n".format(x, y, p))

        # Process start address (align to 1K boundary then shift right by 10
        # and left by 3 (i.e. 7) to make it the top 13-bits of the field):
        if (block_start_addr & 0x3FF) != 0:
            raise exceptions.SynapticBlockGenerationException(
                "Synaptic Block start address is not aligned to a 1K boundary")
        assert(block_start_addr < math.pow(2, 32))

        # moves by 7 to tack on at the end the row_length information
        # which resides in the last 3 bits
        entry_addr_field = block_start_addr >> 7

        # Assembly entry:
        new_entry = entry_addr_field | row_index

        # Write entry:
        spec.switch_write_focus(region=master_pop_table_region)
        spec.set_write_pointer(address=table_slot_addr)
        spec.write_value(data=new_entry, data_type=DataType.INT16)
Exemplo n.º 3
0
    def get_allowed_row_length(self, row_length):
        """

        :param row_length:
        :return:
        """

        # Can even the largest valid entry accommodate the given synaptic row?
        if row_length > ROW_LEN_TABLE_ENTRIES[-1]:
            raise exceptions.SynapticBlockGenerationException(
                "Max row length too long -"
                " wanted length %d, but max length permitted is %d." %
                (row_length, ROW_LEN_TABLE_ENTRIES[-1]))

        # Search up the list until we find one entry big enough:
        for i in range(len(ROW_LEN_TABLE_ENTRIES)):
            if row_length <= ROW_LEN_TABLE_ENTRIES[i]:

                # This row length is big enough. Choose it and exit:
                return ROW_LEN_TABLE_ENTRIES[i]
        raise Exception("Should not get here!")
Exemplo n.º 4
0
    def create_row_info_from_elements(self, p_p_entries, f_f_entries,
                                      f_p_entries, bits_reserved_for_type,
                                      weight_scales):
        """
        takes a collection of entries for both fixed fixed, plastic plastic
        and fixed plastic and returns a synaptic row object for them

        f_f_entries are ignored due to this model dealing with plastic synapses
        """

        if len(f_f_entries) > 0:
            raise exceptions.SynapticBlockGenerationException(
                "plastic synapses cannot create row ios from fixed entries.")

        # Calculate masks and convert per-synapse type weight scales to numpy
        synaptic_type_mask = (1 << bits_reserved_for_type) - 1
        delay_mask = (1 << (8 - bits_reserved_for_type)) - 1
        weight_scales_numpy = numpy.array(weight_scales, dtype="float")

        # Extract indices, delays and synapse types from fixed-plastic region
        target_indices = f_p_entries & 0xFF
        delays_in_ticks = (((f_p_entries >> 8) + bits_reserved_for_type)
                           & delay_mask)
        synapse_types = (f_p_entries >> 8) & synaptic_type_mask

        # Index out per-synapse weight scales
        synapse_weight_scales = weight_scales_numpy[synapse_types]

        # Get half word view of plastic region with correct signedness
        half_word_datatype = "int16" if self._signed else "uint16"
        half_words = p_p_entries[self._num_header_words:].view(
            dtype=half_word_datatype)

        # Slice out weight half words,
        # Convert to float  and divide by weight scale
        weights = half_words[0::2].astype("float") / synapse_weight_scales

        return SynapseRowInfo(target_indices, weights, delays_in_ticks,
                              synapse_types)
Exemplo n.º 5
0
def write_exp_synapse_param(tau, machine_time_step, vertex_slice, spec):

    # Calculate decay and initialisation values
    decay = numpy.exp(numpy.divide(-float(machine_time_step),
                                   numpy.multiply(1000.0, tau)))
    init = numpy.multiply(numpy.multiply(tau, numpy.subtract(1.0, decay)),
                          (1000.0 / float(machine_time_step)))

    # Scale to fixed-point
    scale = float(pow(2, 32))
    rescaled_decay = numpy.multiply(decay, scale).astype("uint32")
    rescaled_init = numpy.multiply(init, scale).astype("uint32")

    # If we only generated a single param
    if rescaled_decay.size == 1 and rescaled_init.size == 1:

        # Copy for all atoms
        # **YUCK** this is inefficient in terms of DSG
        for _ in range(vertex_slice.n_atoms):
            spec.write_value(data=rescaled_decay[0])
            spec.write_value(data=rescaled_init[0])

    # Otherwise, if we have generated decays and inits for each atom
    elif (rescaled_decay.size > vertex_slice.hi_atom and
            rescaled_init.size > vertex_slice.hi_atom):

        # Interleave into one array
        interleaved_params = numpy.empty(vertex_slice.n_atoms * 2)
        interleaved_params[0::2] = \
            rescaled_decay[vertex_slice.lo_atom:vertex_slice.hi_atom + 1]
        interleaved_params[1::2] = \
            rescaled_init[vertex_slice.lo_atom:vertex_slice.hi_atom + 1]

        spec.write_array(interleaved_params)
    else:
        raise exceptions.SynapticBlockGenerationException(
            "Cannot generate synapse parameters from %u values"
            % rescaled_decay.size)