def _update_default_variable(self, new_default_variable, context):
        from psyneulink.core.components.projections.pathway.mappingprojection import MappingProjection
        from psyneulink.core.components.ports.parameterport import ParameterPort

        # this mirrors the transformation in _function
        # it is a hack, and a general solution should be found
        squeezed = np.array(new_default_variable)
        if squeezed.ndim > 1:
            squeezed = np.squeeze(squeezed)

        size = safe_len(squeezed)
        matrix = self.parameters.matrix._get(context)

        if isinstance(matrix, MappingProjection):
            matrix = matrix._parameter_ports[MATRIX]
        elif isinstance(matrix, ParameterPort):
            pass
        else:
            matrix = get_matrix(self.defaults.matrix, size, size)

        self.parameters.matrix._set(matrix, context)

        self._hollow_matrix = get_matrix(HOLLOW_MATRIX, size, size)

        super()._update_default_variable(new_default_variable, context)
    def _instantiate_attributes_before_function(self,
                                                function=None,
                                                context=None):
        """Instantiate matrix

        Specified matrix is convolved with HOLLOW_MATRIX
            to eliminate the diagonal (self-connections) from the calculation.
        The `Distance` Function is used for all calculations except ENERGY (which is not really a distance metric).
        If ENTROPY is specified as the metric, convert to CROSS_ENTROPY for use with the Distance Function.
        :param function:

        """
        from psyneulink.core.components.projections.pathway.mappingprojection import MappingProjection
        from psyneulink.core.components.ports.parameterport import ParameterPort

        # this mirrors the transformation in _function
        # it is a hack, and a general solution should be found
        squeezed = np.array(self.defaults.variable)
        if squeezed.ndim > 1:
            squeezed = np.squeeze(squeezed)

        size = safe_len(squeezed)

        matrix = self.parameters.matrix._get(context)

        if isinstance(matrix, MappingProjection):
            matrix = matrix._parameter_ports[MATRIX]
        elif isinstance(matrix, ParameterPort):
            pass
        else:
            matrix = get_matrix(matrix, size, size)

        self.parameters.matrix._set(matrix, context)

        self._hollow_matrix = get_matrix(HOLLOW_MATRIX, size, size)

        default_variable = [self.defaults.variable, self.defaults.variable]

        if self.metric is ENTROPY:
            self.metric_fct = Distance(default_variable=default_variable,
                                       metric=CROSS_ENTROPY,
                                       normalize=self.normalize)
        elif self.metric in DISTANCE_METRICS._set():
            self.metric_fct = Distance(default_variable=default_variable,
                                       metric=self.metric,
                                       normalize=self.normalize)
        else:
            assert False, "Unknown metric"
        #FIXME: This is a hack to make sure metric-fct param is set
        self.parameters.metric_fct.set(self.metric_fct)
def get_hetero_matrix(raw_hetero, size):
    if isinstance(raw_hetero, numbers.Number):
        return get_matrix(HOLLOW_MATRIX, size, size) * raw_hetero
    elif ((isinstance(raw_hetero, np.ndarray) and raw_hetero.ndim == 1) or
              (isinstance(raw_hetero, list) and np.array(raw_hetero).ndim == 1)):
        if len(raw_hetero) != 1:
            return None
        return get_matrix(HOLLOW_MATRIX, size, size) * raw_hetero[0]
    elif (isinstance(raw_hetero, np.matrix) or
              (isinstance(raw_hetero, np.ndarray) and raw_hetero.ndim == 2) or
              (isinstance(raw_hetero, list) and np.array(raw_hetero).ndim == 2)):
        np.fill_diagonal(raw_hetero, 0)
        return np.array(raw_hetero)
    else:
        return None
示例#4
0
    def _instantiate_attributes_before_function(self,
                                                function=None,
                                                context=None):
        """Instantiate matrix

        Specified matrix is convolved with HOLLOW_MATRIX
            to eliminate the diagonal (self-connections) from the calculation.
        The `Distance` Function is used for all calculations except ENERGY (which is not really a distance metric).
        If ENTROPY is specified as the metric, convert to CROSS_ENTROPY for use with the Distance Function.
        :param function:

        """

        size = len(self.defaults.variable)

        from psyneulink.core.components.projections.pathway.mappingprojection import MappingProjection
        from psyneulink.core.components.states.parameterstate import ParameterState

        matrix = self.parameters.matrix.get()

        if isinstance(matrix, MappingProjection):
            matrix = matrix._parameter_states[MATRIX]
        elif isinstance(matrix, ParameterState):
            pass
        else:
            matrix = get_matrix(matrix, size, size)

        self.parameters.matrix.set(matrix)

        self._hollow_matrix = get_matrix(HOLLOW_MATRIX, size, size)

        default_variable = [self.defaults.variable, self.defaults.variable]

        if self.metric is ENTROPY:
            self._metric_fct = Distance(default_variable=default_variable,
                                        metric=CROSS_ENTROPY,
                                        normalize=self.normalize)
        elif self.metric in DISTANCE_METRICS._set():
            self._metric_fct = Distance(default_variable=default_variable,
                                        metric=self.metric,
                                        normalize=self.normalize)
示例#5
0
    def test_recurrent_mech_matrix_keyword_spec(self, matrix):

        if matrix == RANDOM_CONNECTIVITY_MATRIX:
            pytest.skip("Random test")
        R = RecurrentTransferMechanism(
            name='R',
            size=4,
            matrix=matrix
        )
        val = R.execute([10, 10, 10, 10])
        np.testing.assert_allclose(val, [[10., 10., 10., 10.]])
        np.testing.assert_allclose(R.recurrent_projection.matrix, get_matrix(matrix, R.size[0], R.size[0]))
示例#6
0
    def _instantiate_parameter_states(self, function=None, context=None):

        super()._instantiate_parameter_states(function=function,
                                              context=context)

        # FIX: UPDATE FOR LEARNING
        # FIX: UPDATE WITH MODULATION_MODS
        # FIX: MOVE THIS TO MappingProjection.__init__;
        # FIX: AS IT IS, OVER-WRITES USER ASSIGNMENT OF FUNCTION IN params dict FOR MappingProjection
        matrix = get_matrix(self._parameter_states[MATRIX].value)
        initial_rate = matrix * 0.0

        self._parameter_states[MATRIX].function = AccumulatorIntegrator(
            owner=self._parameter_states[MATRIX],
            default_variable=matrix,
            initializer=matrix,
            # rate=initial_rate
        )
    def _validate_params(self, request_set, target_set=None, context=None):
        """Validate **mask** argument"""

        super()._validate_params(request_set=request_set,
                                 target_set=target_set,
                                 context=context)

        if MASK in target_set and target_set[MASK]:
            mask = target_set[MASK]
            if isinstance(mask, (int, float)):
                return
            mask_shape = np.array(mask).shape
            matrix = get_matrix(self.user_params[FUNCTION_PARAMS][MATRIX],
                                len(self.sender.defaults.value), len(self.receiver.defaults.value))
            matrix_shape = matrix.shape
            if mask_shape != matrix_shape:
                raise MaskedMappingProjectionError("Shape of the {} for {} ({}) "
                                                   "must be the same as its {} ({})".
                                                   format(repr(MASK), self.name, mask_shape,
                                                          repr(MATRIX), matrix_shape))
    def _instantiate_parameter_ports(self, function=None, context=None):

        super()._instantiate_parameter_ports(function=function,
                                             context=context)

        # FIX: UPDATE FOR LEARNING
        # FIX: UPDATE WITH MODULATION_MODS
        # FIX: MOVE THIS TO MappingProjection.__init__;
        # FIX: AS IT IS, OVER-WRITES USER ASSIGNMENT OF FUNCTION IN params dict FOR MappingProjection
        matrix = get_matrix(self._parameter_ports[MATRIX].value)
        initial_rate = matrix * 0.0

        # KDM 7/11/19: instead of simply setting the function, we need to reinstantiate to ensure
        # new defaults get set properly
        self._parameter_ports[MATRIX]._instantiate_function(
            function=AccumulatorIntegrator(
                owner=self._parameter_ports[MATRIX],
                default_variable=matrix,
                initializer=matrix,
                # rate=initial_rate
            ),
            context=context)
        self._parameter_ports[MATRIX]._instantiate_value(context)
        self._parameter_ports[MATRIX]._update_parameter_components(context)
    def _instantiate_receiver(self, context=None):
        """Determine matrix needed to map from sender to receiver

        Assign specification to self.matrix_spec attribute
        Assign matrix to self.matrix attribute

        """
        self.reshapedWeightMatrix = False

        # Get sender and receiver lengths
        # Note: if either is a scalar, manually set length to 1 to avoid TypeError in call to len()
        try:
            mapping_input_len = len(self.defaults.variable)
        except TypeError:
            mapping_input_len = 1
        try:
            receiver_len = self.receiver.socket_width
        except TypeError:
            receiver_len = 1

        # Compare length of MappingProjection output and receiver's variable to be sure matrix has proper dimensions
        try:
            mapping_output_len = len(self.defaults.value)
        except TypeError:
            mapping_output_len = 1

        # FIX: CONVERT ALL REFS TO matrix_spec TO self._matrix_spec
        # FIX: CREATE @PROPERTY FOR self._learning_spec AND ASSIGN IN INIT??
        # FIX: HOW DOES mapping_output_len RELATE TO receiver_len?/

        if self._matrix_spec is AUTO_ASSIGN_MATRIX:
            if mapping_input_len == receiver_len:
                self._matrix_spec = IDENTITY_MATRIX
            else:
                self._matrix_spec = FULL_CONNECTIVITY_MATRIX

        # Length of the output of the Projection doesn't match the length of the receiving InputPort
        #    so consider reshaping the matrix
        if mapping_output_len != receiver_len:

            if 'projection' in self.name or 'Projection' in self.name:
                projection_string = ''
            else:
                projection_string = 'projection'

            if all(string in self.name for string in {'from', 'to'}):
                states_string = ''
            else:
                states_string = "from \'{}\' OuputState of \'{}\' to \'{}\'".format(
                    self.sender.name, self.sender.owner.name,
                    self.receiver.owner.name)
            if not isinstance(self._matrix_spec, str):
                # if all(string in self.name for string in {'from', 'to'}):

                raise ProjectionError(
                    "Width ({}) of the {} of \'{}{}\'{} "
                    "does not match the length of its \'{}\' InputPort ({})".
                    format(mapping_output_len, VALUE, self.name,
                           projection_string, states_string,
                           self.receiver.name, receiver_len))

            elif self._matrix_spec == IDENTITY_MATRIX or self._matrix_spec == HOLLOW_MATRIX:
                # Identity matrix is not reshapable
                raise ProjectionError(
                    "Output length ({}) of \'{}{}\' from {} to Mechanism \'{}\'"
                    " must equal length of it InputPort ({}) to use {}".format(
                        mapping_output_len, self.name, projection_string,
                        self.sender.name, self.receiver.owner.name,
                        receiver_len, self._matrix_spec))
            else:
                # Flag that matrix is being reshaped
                self.reshapedWeightMatrix = True
                if self.prefs.verbosePref:
                    print(
                        "Length ({}) of the output of {}{} does not match the length ({}) "
                        "of the InputPort for the receiver {}; the width of the matrix (number of columns); "
                        "the width of the matrix (number of columns) will be adjusted to accomodate the receiver"
                        .format(mapping_output_len, self.name,
                                projection_string, receiver_len,
                                self.receiver.owner.name))

                self.matrix = get_matrix(self._matrix_spec,
                                         mapping_input_len,
                                         receiver_len,
                                         context=context)

                # Since matrix shape has changed, output of self.function may have changed, so update value
                self._instantiate_value(context=context)

        super()._instantiate_receiver(context=context)
    def _validate_params(self,
                         variable,
                         request_set,
                         target_set=None,
                         context=None):
        """Validate matrix param

        `matrix <Stability.matrix>` argument must be one of the following
            - 2d list, np.ndarray or np.matrix
            - ParameterPort for one of the above
            - MappingProjection with a parameterPorts[MATRIX] for one of the above

        Parse matrix specification to insure it resolves to a square matrix
        (but leave in the form in which it was specified so that, if it is a ParameterPort or MappingProjection,
         its current value can be accessed at runtime (i.e., it can be used as a "pointer")
        """

        # Validate matrix specification
        if MATRIX in target_set:

            from psyneulink.core.components.projections.pathway.mappingprojection import MappingProjection
            from psyneulink.core.components.ports.parameterport import ParameterPort

            matrix = target_set[MATRIX]

            if isinstance(matrix, str):
                matrix = get_matrix(matrix)

            if isinstance(matrix, MappingProjection):
                try:
                    matrix = matrix._parameter_ports[MATRIX].value
                    param_type_string = "MappingProjection's ParameterPort"
                except KeyError:
                    raise FunctionError(
                        "The MappingProjection specified for the {} arg of {} ({}) must have a {} "
                        "ParameterPort that has been assigned a 2d array or matrix"
                        .format(MATRIX, self.name, matrix.shape, MATRIX))

            elif isinstance(matrix, ParameterPort):
                try:
                    matrix = matrix.value
                    param_type_string = "ParameterPort"
                except KeyError:
                    raise FunctionError(
                        "The value of the {} parameterPort specified for the {} arg of {} ({}) "
                        "must be a 2d array or matrix".format(
                            MATRIX, MATRIX, self.name, matrix.shape))

            else:
                param_type_string = "array or matrix"

            matrix = np.array(matrix)
            if matrix.ndim != 2:
                raise FunctionError(
                    "The value of the {} specified for the {} arg of {} ({}) "
                    "must be a 2d array or matrix".format(
                        param_type_string, MATRIX, self.name, matrix))
            rows = matrix.shape[0]
            cols = matrix.shape[1]
            size = len(self.defaults.variable)

            if rows != size:
                raise FunctionError(
                    "The value of the {} specified for the {} arg of {} is the wrong size;"
                    "it is {}x{}, but must be square matrix of size {}".format(
                        param_type_string, MATRIX, self.name, rows, cols,
                        size))

            if rows != cols:
                raise FunctionError(
                    "The value of the {} specified for the {} arg of {} ({}) "
                    "must be a square matrix".format(param_type_string, MATRIX,
                                                     self.name, matrix))

        super()._validate_params(request_set=request_set,
                                 target_set=target_set,
                                 context=context)