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 == 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
import numpy as np import psyneulink.core.llvm as pnlvm import psyneulink.core.components.functions.function as Function import psyneulink.core.components.functions.objectivefunctions as Functions import psyneulink.core.components.functions.transferfunctions import psyneulink.core.globals.keywords as kw import pytest SIZE = 10 # Some metrics (CROSS_ENTROPY) don't like 0s test_var = np.random.rand(SIZE) + Function.EPSILON hollow_matrix = Function.get_matrix(kw.HOLLOW_MATRIX, SIZE, SIZE) v1 = test_var v2 = np.dot(hollow_matrix * hollow_matrix, v1) norm = len(v1) test_data = [ (kw.ENTROPY, False, -np.sum(v1 * np.log(v2))), (kw.ENTROPY, True, -np.sum(v1 * np.log(v2)) / norm), (kw.ENERGY, False, -np.sum(v1 * v2) / 2), (kw.ENERGY, True, (-np.sum(v1 * v2) / 2) / norm**2), ] # use list, naming function produces ugly names names = [ "ENTROPY", "ENTROPY NORMALIZED", "ENERGY", "ENERGY NORMALIZED", ]
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 matrix_spec = self.defaults.matrix if (type(matrix_spec) == str and matrix_spec == AUTO_ASSIGN_MATRIX): if mapping_input_len == receiver_len: matrix_spec = IDENTITY_MATRIX else: 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(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 matrix_spec == IDENTITY_MATRIX or 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, 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.parameters.matrix._set( get_matrix(matrix_spec, mapping_input_len, receiver_len, context=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)