diff --git a/Scripts/Scratch Pad.py b/Scripts/Scratch Pad.py index 45e79e77c11..c60d3e0e58d 100644 --- a/Scripts/Scratch Pad.py +++ b/Scripts/Scratch Pad.py @@ -948,15 +948,25 @@ def __init__(self, error_value): #region TEST Naming -D = pnl.DDM() -T = pnl.TransferMechanism(input_states=['x']) - -T = pnl.TransferMechanism(input_states=['a','b','c']) -print(T.variable) -print(T.execute([[1],[2],[3]])) +# D = pnl.DDM() +# T = pnl.TransferMechanism(input_states=['x'], +# output_states=pnl.MECHANISM_VALUE) +# +T = pnl.TransferMechanism(input_states=[[[0],[0]],'b','c'], +# T = pnl.TransferMechanism(input_states=[[[[0],[0]],[[0],[0]]],'b','c'], + output_states=pnl.MECHANISM_VALUE + ) +# print(T.variable) +# assert T.output_states[MECHANISM_VALUE].value == WHAT IT DOES +# GET NAME RIGHT FOR ALL AS WELL +print(T.execute([[[1],[4]],[2],[3]])) +# print(T.execute([[[[1],[4]],[[[5],[6]]]],[2],[3]])) print(T.output_states) -print(T.output_values) -print(T.value) +for i, o in enumerate(T.output_states): + print("Output {}: {}".format(o.name, o.value)) +# print(T.output_states[0].value) +# print(T.output_values) +# print(T.value) # endregion diff --git a/psyneulink/components/mechanisms/processing/objectivemechanism.py b/psyneulink/components/mechanisms/processing/objectivemechanism.py index e672a818446..0b9f5dc83fc 100644 --- a/psyneulink/components/mechanisms/processing/objectivemechanism.py +++ b/psyneulink/components/mechanisms/processing/objectivemechanism.py @@ -363,7 +363,7 @@ class ObjectiveMechanism(ProcessingMechanism_Base): default_variable, \ size, \ function=LinearCombination, \ - output_states=[OUTCOME], \ + output_states=OUTCOME, \ params=None, \ name=None, \ prefs=None) diff --git a/psyneulink/components/mechanisms/processing/transfermechanism.py b/psyneulink/components/mechanisms/processing/transfermechanism.py index a96fc44a8f2..f588ce60a18 100644 --- a/psyneulink/components/mechanisms/processing/transfermechanism.py +++ b/psyneulink/components/mechanisms/processing/transfermechanism.py @@ -26,26 +26,26 @@ Overview -------- -A TransferMechanism transforms its input using a simple mathematical function. The input can be a single scalar value -or an an array of scalars (list or 1d np.array). The function used to carry out the transformation can be selected -from a standard set of `Functions ` (`Linear`, `Exponential` or `Logistic`) or specified using a -user-defined custom function. The transformation can be carried out instantaneously or in a time-averaged manner, -as described in `Transfer_Execution`. +A TransferMechanism transforms its input using a simple mathematical function, that maintains the form (dimensionality) +of its input. The input can be a single scalar value, a multidimensional array (list or numpy array), or several +independent ones. The function used to carry out the transformation can be selected from a standard set of `Functions +` (such as `Linear`, `Exponential`, `Logistic`, and `Softmax`) or specified using a user-defined custom +function. The transformation can be carried out instantaneously or in "time averaged" (integrated) manner, as described +in `Transfer_Execution`. .. _Transfer_Creation: Creating a TransferMechanism ----------------------------- -A TransferMechanism can be created directly by calling its constructor, or using the `mechanism` command and specifying -*TRANSFER_MECHANISM* as its **mech_spec** argument. Its `function ` is specified in the -**function** argument, which can be the name of a `Function ` class (first example below), or a call to its -constructor which can include arguments specifying the function's parameters (second example):: +A TransferMechanism is created by calling its constructor. Its `function ` is specified in +the **function** argument, which can be the name of a `Function ` class (first example below), or a call to +a Function constructor that can include arguments specifying the Function's parameters (second example):: my_linear_transfer_mechanism = TransferMechanism(function=Linear) my_logistic_transfer_mechanism = TransferMechanism(function=Logistic(gain=1.0, bias=-4) -In addition to function-specific parameters, `noise ` and `time_constant +In addition to Function-specific parameters, `noise ` and `time_constant ` parameters can be specified for the Mechanism (see `Transfer_Execution`). @@ -54,15 +54,54 @@ Structure --------- -A TransferMechanism has a single `InputState`, the `value ` of which is -used as the `variable ` for its `function `. The -`function ` can be selected from one of three standard PsyNeuLink `Functions `: -`Linear`, `Logistic` or `Exponential`; or a custom function can be specified, so long as it returns a numeric value or -list or np.ndarray of numeric values. The result of the `function ` is assigned as the -only item of the TransferMechanism's `value ` and as the `value ` of its -`primary OutputState ` (see `below `). Additional OutputStates can be -assigned using the TransferMechanism's `Standard OutputStates ` -(see `OutputState_Standard`) or by creating `custom OutputStates `. +.. _TransferMechanism_InputStates: + +InputStates +~~~~~~~~~~~ + +By default, a TransferMechanism has a single `InputState`; however, more than one can be specified +using the **default_variable** or **size** arguments of its constructor (see `Mechanism`). The `value +` of each InputState is used as a separate item of the Mechanism's `variable +`, and transformed independently by its `function `. +Like any InputStates, the `value ` of any or all of the TransferMechanism's InputStates can be +modulated by one or more `GatingSignals ` prior to transformation by its `function +`. + +.. _TransferMechanism_Function: + +Function +~~~~~~~~ + +*Function*. The `function ` can be selected from one of four standard PsyNeuLink +`Functions `: `Linear`, `Logistic`, `Exponential` or `SoftMax`; or a custom function can be specified, +so long as it returns a numeric value or a list or numpy array of numeric values. The result of the `function +` applied to the `value ` of each InputState is to an item of an +array as the TransferMechanism's `value `, and as the `value ` of each +of its `OutputStates ` (one corresponding to each InputState). + +.. _TransferMechanism_OutputStates: + +OutputStates +~~~~~~~~~~~~ + +By default, a TransferMechanism generates one `OutputState` for each of its `InputStates`. The first (and `primary +`) OutputState is named `RESULT`; subsequent ones use that as the base name, suffixed with an +incrementing integer starting at '-1' for each additional OutputState (e.g., 'RESULT-1', 'RESULT-2', etc.; see +`Naming`). The `value ` of each OutputState is assigned the result of the Mechanism's `function +` applied to the `value ` of the corresponding InputState. Additional +OutputStates can be assigned using the TransferMechanism's `Standard OutputStates +` (see `OutputState_Standard`) or by creating `custom OutputStates +` (but see note below). Like any OutputStates, the `value ` of any or +all of these can be modulated by one or more `GatingSignals `. + + .. _TransferMechanism_OutputStates_Note: + + .. note:: + If any OutputStates are specified in the **output_states** argument of the TransferMechanism's constructor, + then, `as with any Mechanism `, its default OutputStates are not + automatically generated. Therefore, an OutputState with the appropriate `index ` must be + explicitly specified for each and every item of the Mechanism's `value ` (corresponding + to each InputState) for which an OutputState is needed. .. _Transfer_Execution: @@ -95,14 +134,10 @@ integration (a higher value specifies a faster rate); if `integrator_mode ` is False, `time_constant ` is ignored and time-averaging does not occur. - - -.. _Transfer_OutputState: - -After each execution of the Mechanism the result of `function ` is assigned as the -only item of the Mechanism's `value `, the `value ` of its -`primary OutputState `, (same as the output_states[RESULT] OutputState if it has been assigned), -and to the 1st item of the Mechanism's `output_values ` attribute; +After each execution of the Mechanism the result of `function ` applied to each +`InputState` is assigned as an item of the Mechanism's `value `, and the `value +` of each of its `OutputStates `, and to the 1st item of the Mechanism's +`output_values ` attribute. .. _Transfer_Class_Reference: @@ -178,12 +213,24 @@ class TRANSFER_OUTPUT(): *VARIANCE* : float variance of `output_state.value`. + COMMENT: + *ALL* : list + a list of all of the items of the TransferMechanism's `value ` (that is, of the result + of its `function ` applied to the `value ` of each of its InputStates). + + *COMBINE* : scalar or numpy array + linear combination of the `value ` of all items of the TransferMechanism's `value + ` (requires that they all have the same dimensionality). + COMMENT + """ + RESULT=RESULT MEAN=MEAN MEDIAN=MEDIAN STANDARD_DEVIATION=STANDARD_DEVIATION VARIANCE=VARIANCE + # THE FOLLOWING WOULD HAVE BEEN NICE, BUT IDE DOESN'T EXECUTE IT, SO NAMES DON'T SHOW UP # for item in [item[NAME] for item in DDM_standard_output_states]: # setattr(DDM_OUTPUT.__class__, item, item) @@ -201,12 +248,14 @@ class TransferMechanism(ProcessingMechanism_Base): TransferMechanism( \ default_variable=None, \ size=None, \ + input_states=None, \ function=Linear, \ initial_value=None, \ noise=0.0, \ time_constant=1.0, \ integrator_mode=False, \ clip=(float:min, float:max), \ + output_states=RESULT \ params=None, \ name=None, \ prefs=None) @@ -254,6 +303,13 @@ class TransferMechanism(ProcessingMechanism_Base): T1 = TransferMechanism(size = [3, 2]) T2 = TransferMechanism(default_variable = [[0, 0, 0], [0, 0]]) + input_states : str, list or np.ndarray + specifies the InputStates for the TransferMechanism; by default, a single InputState is created using the + value of default_variable as its `variable `; if more than one is specified, the number + and, if specified, their values must be compatible with any specifications in **default_variable** or + **size** (see `Mechanism_InputStates`); see `input_states ` for additional + details. + function : TransferFunction : default Linear specifies the function used to transform the input; can be `Linear`, `Logistic`, `Exponential`, or a custom function. @@ -282,6 +338,11 @@ class TransferMechanism(ProcessingMechanism_Base): any element of the result that exceeds the specified minimum or maximum value is set to the value of `clip ` that it exceeds. + output_states : str, list or np.ndarray : default RESULT + specifies the OutputStates for the TransferMechanism; by default, one is created for each InputState + specified in **input_states**; see `note `, and `output_states + ` for additional details). + params : Dict[param keyword, param value] : default None a `parameter dictionary ` that can be used to specify the parameters for the Mechanism, its `function `, and/or a custom function and its parameters. Values @@ -305,13 +366,17 @@ class TransferMechanism(ProcessingMechanism_Base): Attributes ---------- - variable : value: default Transfer_DEFAULT_BIAS + variable : value the input to Mechanism's `function `. COMMENT: :py:data:`Transfer_DEFAULT_BIAS SHOULD RESOLVE TO VALUE>` COMMENT - function : Function : default Linear + input_states : *ContentAddressableList[InputState]* + list of Mechanism's `OutputStates `. By default there is one OutputState for each InputState, + with the base name `RESULT` (see `TransferMechanism_InputStates` for additional details). + + function : Function the Function used to transform the input. COMMENT: @@ -324,18 +389,18 @@ class TransferMechanism(ProcessingMechanism_Base): Transfer_DEFAULT_BIAS SHOULD RESOLVE TO A VALUE COMMENT - noise : float or function : default 0.0 + noise : float or function a stochastically-sampled value added to the output of the `function `: if it is a float, it must be in the interval [0,1] and is used to scale the variance of a zero-mean Gaussian; if it is a function, it must return a scalar value. - time_constant : float : default 1.0 + time_constant : float the time constant for exponential time averaging of input when the Mechanism is executed with `integrator_mode` set to True:: result = (time_constant * current input) + ( (1-time_constant) * result on previous time_step) - integrator_mode : boolean : default False + integrator_mode : booleane when set to True, the Mechanism time averages its input according to an exponentially weighted moving average (see `time_constant `). @@ -355,12 +420,9 @@ class TransferMechanism(ProcessingMechanism_Base): the change in `value ` from the previous execution of the Mechanism (i.e., `value ` - `previous_value `). - output_states : *ContentAddressableList[OutputState]* : default [`RESULT `] - list of Mechanism's `OutputStates `. By default there is a single OutputState, - `RESULT `, that contains the result of a call to the Mechanism's - `function `; additional `standard ` - and/or custom OutputStates may be included, based on the specifications made in the **output_states** argument - of the Mechanism's constructor. + output_states : *ContentAddressableList[OutputState]* + list of Mechanism's `OutputStates `; by default there is one OutputState for each InputState, + with the base name `RESULT` (see `TransferMechanism_OutputStates` for additional details). output_values : List[array(float64)] each item is the `value ` of the corresponding OutputState in `output_states @@ -442,7 +504,8 @@ def __init__(self, if not isinstance(self.standard_output_states, StandardOutputStates): self.standard_output_states = StandardOutputStates(self, self.standard_output_states, - indices=PRIMARY) + indices=PRIMARY + ) super(TransferMechanism, self).__init__( variable=default_variable, diff --git a/psyneulink/components/states/outputstate.py b/psyneulink/components/states/outputstate.py index 1cd3b18b0ce..60e57c4ea1b 100644 --- a/psyneulink/components/states/outputstate.py +++ b/psyneulink/components/states/outputstate.py @@ -339,13 +339,13 @@ import typecheck as tc from psyneulink.components.component import Component, InitStatus -from psyneulink.components.functions.function import Linear, LinearCombination, is_function_type +from psyneulink.components.functions.function import Linear, is_function_type from psyneulink.components.shellclasses import Mechanism, Projection from psyneulink.components.states.state import State_Base, _instantiate_state_list, state_type_keywords, ADD_STATES from psyneulink.globals.keywords import \ PROJECTION, PROJECTIONS, PROJECTION_TYPE, MAPPING_PROJECTION, INPUT_STATE, INPUT_STATES, RECEIVER, GATING_SIGNAL, \ - COMMAND_LINE, STATE, OUTPUT_STATE, OUTPUT_STATE_PARAMS, RESULT, INDEX, PARAMS, DEFERRED_INITIALIZATION, \ - CALCULATE, MEAN, MEDIAN, NAME, STANDARD_DEVIATION, STANDARD_OUTPUT_STATES, SUM, VARIANCE, REFERENCE_VALUE + COMMAND_LINE, STATE, OUTPUT_STATE, OUTPUT_STATE_PARAMS, RESULT, INDEX, PARAMS, \ + CALCULATE, MEAN, MEDIAN, NAME, STANDARD_DEVIATION, STANDARD_OUTPUT_STATES, VARIANCE, ALL, MECHANISM_VALUE from psyneulink.globals.preferences.componentpreferenceset import is_pref_set from psyneulink.globals.preferences.preferenceset import PreferenceLevel from psyneulink.globals.utilities import UtilitiesError, iscompatible, type_match @@ -385,7 +385,10 @@ class OUTPUTS(): {NAME:STANDARD_DEVIATION, CALCULATE:lambda x: np.std(x)}, {NAME:VARIANCE, - CALCULATE:lambda x: np.var(x)}] + CALCULATE:lambda x: np.var(x)}, + {NAME: MECHANISM_VALUE, + INDEX: ALL} + ] class OutputStateError(Exception): def __init__(self, error_value): @@ -397,18 +400,18 @@ def __str__(self): class OutputState(State_Base): """ - OutputState( \ - owner, \ - reference_value, \ - variable=None, \ - size=None, \ - function=LinearCombination(operation=SUM), \ - index=PRIMARY, \ - calculate=Linear, \ - projections=None, \ - params=None, \ - name=None, \ - prefs=None, \ + OutputState( \ + owner, \ + reference_value, \ + variable=None, \ + size=None, \ + function=Linear(), \ + index=PRIMARY, \ + calculate=Linear, \ + projections=None, \ + params=None, \ + name=None, \ + prefs=None, \ context=None) Subclass of `State ` that calculates and represents an output of a `Mechanism `. @@ -425,11 +428,11 @@ class OutputState(State_Base): Class attributes: + componentType (str) = OUTPUT_STATES + paramClassDefaults (dict) - + FUNCTION (LinearCombination) + + FUNCTION (Linear) + FUNCTION_PARAMS (Operation.PRODUCT) Class methods: - function (executes function specified in params[FUNCTION]; default: LinearCombination with Operation.SUM) + function (executes function specified in params[FUNCTION]; default: Linear) StateRegistry ------------- @@ -463,7 +466,7 @@ class OutputState(State_Base): T1 = TransferMechanism(size = [3, 2]) T2 = TransferMechanism(default_variable = [[0, 0, 0], [0, 0]]) - function : Function, function, or method : default LinearCombination(operation=SUM) + function : Function, function, or method : default Linear specifies the function used to transform the item of the owner Mechanism's `value ` designated by the OutputState's `index ` attribute, under the possible influence of `GatingProjections ` received by the OutputState. @@ -593,7 +596,7 @@ def __init__(self, reference_value=None, variable=None, size=None, - function=LinearCombination(operation=SUM), + function=Linear(), index=PRIMARY, calculate:is_function_type=Linear, projections=None, @@ -691,7 +694,7 @@ def _validate_params(self, request_set, target_set=None, context=None): # - can't yet determine relationship to default_value # - can't yet evaluate calculate function (below) # so just return - if target_set[INDEX] is SEQUENTIAL: + if target_set[INDEX] in {ALL, SEQUENTIAL}: return else: try: @@ -786,13 +789,24 @@ def _execute(self, function_params, context): """Call self.function with owner's value as variable """ - # IMPLEMENTATION NOTE: OutputStates don't current receive TransmissiveProjections, + # Most common case is OutputState has index, so assume that for efficiency + try: + # Get indexed item of owner's value + owner_val = self.owner.value[self.index] + except IndexError: + # Index is ALL, so use owner's entire value + if self.index is ALL: + owner_val = self.owner.value + else: + raise IndexError + + # IMPLEMENTATION NOTE: OutputStates don't currently receive PathwayProjections, # so there is no need to use their value (as do InputStates) - value = self.function(variable=self.owner.value[self.index], + value = self.function(variable=owner_val, params=function_params, context=context) - return type_match(self.calculate(self.owner.value[self.index]), type(value)) + return type_match(self.calculate(owner_val), type(value)) def _get_primary_state(self, mechanism): return mechanism.output_state @@ -1064,22 +1078,23 @@ class StandardOutputStates(): the Component to which this OutputState belongs output_state_dicts : list of dicts - list of dictionaries specifying OutputStates for the Component specified - by `owner` + list of dictionaries specifying OutputStates for the Component specified by `owner` - indices : PRIMARY_OUTPUT_STATES, SEQUENTIAL, list of ints - specifies how to assign the INDEX entry for each dict listed in - `output_state_dicts` + indices : PRIMARY, SEQUENTIAL, list of ints + specifies how to assign the INDEX entry for each dict listed in `output_state_dicts`; The effects of each value of indices are as follows: - * PRIMARY_OUTPUT_STATES -- assigns the INDEX for the owner's primary OutputState to all indices + * *PRIMARY* -- assigns the INDEX for the owner's primary OutputState to all output_states + for which an INDEX entry is not already specified; - * SEQUENTIAL -- assigns sequentially incremented int to each INDEX entry + * *SEQUENTIAL* -- assigns sequentially incremented int to each INDEX entry, + ignoring any INDEX entries previously specified for individual OutputStates; - * list of ints -- assigns each int to the corresponding entry in `output_state_dicts` + * list of ints -- assigns each int to the corresponding entry in `output_state_dicts`; + ignoring any INDEX entries previously specified for individual OutputStates; - * None -- assigns `None` to each INDEX entry + * None -- assigns `None` to INDEX entries for all OutputStates for which it is not already specified. Attributes ---------- @@ -1140,14 +1155,19 @@ def __init__(self, for index, state_dict in enumerate(self.data): state_dict[INDEX] = index - # Assign PRIMARY as INDEX for all OutputStates in output_state_dicts + # Assign PRIMARY as INDEX for all OutputStates in output_state_dicts that don't already have an index specified elif indices is PRIMARY: for state_dict in self.data: + if INDEX in state_dict: + continue state_dict[INDEX] = PRIMARY # No indices specification, so assign None to INDEX for all OutputStates in output_state_dicts + # that don't already have an index specified else: for state_dict in self.data: + if INDEX in state_dict: + continue state_dict[INDEX] = None diff --git a/psyneulink/globals/keywords.py b/psyneulink/globals/keywords.py index 82847a2dc35..7f1f544fc47 100644 --- a/psyneulink/globals/keywords.py +++ b/psyneulink/globals/keywords.py @@ -65,16 +65,17 @@ 'LINEAR_FUNCTION', 'LINEAR_MATRIX_FUNCTION', 'LOGISTIC_FUNCTION', 'LOW', 'MAKE_DEFAULT_GATING_MECHANISM', 'MAPPING_PROJECTION', 'MAPPING_PROJECTION_PARAMS', 'MATRIX', 'MATRIX_KEYWORD_NAMES', 'MATRIX_KEYWORD_SET', 'MATRIX_KEYWORD_VALUES', 'MATRIX_KEYWORDS', 'MatrixKeywords', 'MAX_INDICATOR', 'MAX_VAL', 'MEAN', 'MECHANISM', - 'MECHANISM_TIME_SCALE', 'MechanismRoles', 'MEDIAN', 'MODULATION', 'MODULATORY_PROJECTION', 'MODULATORY_SIGNAL', - 'MONITOR_FOR_CONTROL', 'MONITOR_FOR_LEARNING', 'MUTUAL_ENTROPY', 'NAME', 'NO_CONTEXT', 'NOISE', 'NORMAL_DIST_FUNCTION', - 'OBJECTIVE_FUNCTION_TYPE', 'OBJECTIVE_MECHANISM', 'OBJECTIVE_MECHANISM_OBJECT', 'OFF', 'OFFSET', 'ON', 'OPERATION', - 'ORIGIN', 'ORNSTEIN_UHLENBECK_INTEGRATOR_FUNCTION', 'OUTCOME_FUNCTION', 'OUTPUT_STATE', 'OUTPUT_STATE_PARAMS', - 'OUTPUT_STATES', 'OUTPUT_TYPE', 'OWNER', 'PARAM_CLASS_DEFAULTS', 'PARAM_INSTANCE_DEFAULTS', 'PARAMETER_STATE', - 'PARAMETER_STATE_PARAMS', 'PARAMETER_STATES', 'PARAMS', 'PARAMS_CURRENT', 'PATHWAY', 'PATHWAY_PROJECTION', 'PEARSON', - 'PREDICTION_MECHANISM', 'PREDICTION_MECHANISM_OUTPUT', 'PREDICTION_MECHANISM_PARAMS', 'PREDICTION_MECHANISM_TYPE', - 'PREFS_ARG', 'PRIMARY', 'PROB', 'PROCESS', 'PROCESS_INIT', 'PROCESSES', 'PROCESSES_DIM', 'PROCESSING_MECHANISM', - 'PRODUCT', 'PROJECTION', 'PROJECTION_PARAMS', 'PROJECTION_SENDER', 'PROJECTION_SENDER_VALUE', 'PROJECTION_TYPE', - 'PROJECTIONS', 'QUOTIENT', 'RANDOM_CONNECTIVITY_MATRIX', 'RATE', 'RATIO', 'RECEIVER', 'RECURRENT_TRANSFER_MECHANISM', + 'MECHANISM_TIME_SCALE', 'MechanismRoles', 'MECHANISM_VALUE', 'MEDIAN', 'MODULATION', 'MODULATORY_PROJECTION', + 'MODULATORY_SIGNAL', 'MONITOR_FOR_CONTROL', 'MONITOR_FOR_LEARNING', 'MUTUAL_ENTROPY', 'NAME', 'NO_CONTEXT', + 'NOISE', 'NORMAL_DIST_FUNCTION', 'OBJECTIVE_FUNCTION_TYPE', 'OBJECTIVE_MECHANISM', 'OBJECTIVE_MECHANISM_OBJECT', + 'OFF', 'OFFSET', 'ON', 'OPERATION', 'ORIGIN', 'ORNSTEIN_UHLENBECK_INTEGRATOR_FUNCTION', 'OUTCOME_FUNCTION', + 'OUTPUT_STATE', 'OUTPUT_STATE_PARAMS', 'OUTPUT_STATES', 'OUTPUT_TYPE', 'OWNER', 'PARAM_CLASS_DEFAULTS', + 'PARAM_INSTANCE_DEFAULTS', 'PARAMETER_STATE', 'PARAMETER_STATE_PARAMS', 'PARAMETER_STATES', 'PARAMS', + 'PARAMS_CURRENT', 'PATHWAY', 'PATHWAY_PROJECTION', 'PEARSON', 'PREDICTION_MECHANISM', 'PREDICTION_MECHANISM_OUTPUT', + 'PREDICTION_MECHANISM_PARAMS', 'PREDICTION_MECHANISM_TYPE', 'PREFS_ARG', 'PRIMARY', 'PROB', 'PROCESS', + 'PROCESS_INIT', 'PROCESSES', 'PROCESSES_DIM', 'PROCESSING_MECHANISM', 'PRODUCT', 'PROJECTION', + 'PROJECTION_PARAMS', 'PROJECTION_SENDER', 'PROJECTION_SENDER_VALUE', 'PROJECTION_TYPE', 'PROJECTIONS', + 'QUOTIENT', 'RANDOM_CONNECTIVITY_MATRIX', 'RATE', 'RATIO', 'RECEIVER', 'RECURRENT_TRANSFER_MECHANISM', 'REDUCE_FUNCTION', 'REFERENCE_VALUE', 'RESULT', 'RL_FUNCTION', 'RUN', 'SAMPLE', 'SAVE_ALL_VALUES_AND_POLICIES', 'SCALAR', 'SCALE', 'SCHEDULER', 'SENDER', 'SEPARATOR_BAR', 'SET_ATTRIBUTE', 'SIMPLE', 'SIMPLE_INTEGRATOR_FUNCTION', 'SINGLETON', 'SIZE', 'SLOPE', 'SOFT_CLAMP', 'SOFTMAX_FUNCTION', 'STABILITY_FUNCTION', 'STANDARD_ARGS', @@ -607,6 +608,7 @@ def _is_metric(metric): MEAN = 'MEAN' MEDIAN = 'MEDIAN' VARIANCE = 'VARIANCE' +MECHANISM_VALUE = 'MECHANISM_VALUE' SIZE = 'size' K_VALUE = 'k_value' THRESHOLD = 'threshold' diff --git a/psyneulink/library/mechanisms/processing/objective/comparatormechanism.py b/psyneulink/library/mechanisms/processing/objective/comparatormechanism.py index 62c28894a8c..fb7b76f6eaf 100644 --- a/psyneulink/library/mechanisms/processing/objective/comparatormechanism.py +++ b/psyneulink/library/mechanisms/processing/objective/comparatormechanism.py @@ -184,7 +184,7 @@ class ComparatorMechanism(ObjectiveMechanism): target, \ input_states=[SAMPLE,TARGET] \ function=LinearCombination(weights=[[-1],[1]], \ - output_states=[OUTCOME] \ + output_states=OUTCOME \ params=None, \ name=None, \ prefs=None) diff --git a/psyneulink/library/mechanisms/processing/transfer/recurrenttransfermechanism.py b/psyneulink/library/mechanisms/processing/transfer/recurrenttransfermechanism.py index 7613213bbc2..a8bbdcdab60 100644 --- a/psyneulink/library/mechanisms/processing/transfer/recurrenttransfermechanism.py +++ b/psyneulink/library/mechanisms/processing/transfer/recurrenttransfermechanism.py @@ -476,6 +476,8 @@ class RecurrentTransferMechanism(TransferMechanism): standard_output_states = TransferMechanism.standard_output_states.copy() standard_output_states.extend([{NAME:ENERGY}, {NAME:ENTROPY}]) + # FIX: 11/19/17 ??SHOULD THE ABOVE BE: + # standard_output_states.extend([{NAME:ENERGY, INDEX:PRIMARY}, {NAME:ENTROPY, INDEX:PRIMARY}]) @tc.typecheck def __init__(self, diff --git a/tests/mechanisms/test_transfer_mechanism.py b/tests/mechanisms/test_transfer_mechanism.py index 83cda055de5..af8622a9ab3 100644 --- a/tests/mechanisms/test_transfer_mechanism.py +++ b/tests/mechanisms/test_transfer_mechanism.py @@ -735,10 +735,20 @@ def test_transfer_mech_2d_variable_noise(self): ) val = T.execute([[1.0, 2.0], [3.0, 4.0]]) - def test_multiple_output_states_for_multiple_input_states(selfs): + def test_multiple_output_states_for_multiple_input_states(self): T = TransferMechanism(input_states=['a','b','c']) val = T.execute([[1],[2],[3]]) assert len(T.variable)==3 assert all(a==b for a,b in zip(val, [[ 1.],[ 2.],[ 3.]])) assert len(T.output_states)==3 - assert all(a==b for a,b in zip(T.output_values,val)) \ No newline at end of file + assert all(a==b for a,b in zip(T.output_values,val)) + + def test_MECHANISM_VALUE_standard_output_state(self): + from psyneulink.globals.keywords import MECHANISM_VALUE + T = TransferMechanism(input_states=[[[0],[0]],'b','c'], + output_states=MECHANISM_VALUE) + val = T.execute([[[1],[4]],[2],[3]]) + expected_val = [[[1],[4]],[2],[3]] + assert len(T.output_states)==1 + assert len(T.output_states[MECHANISM_VALUE].value)==3 + assert all(all(a==b for a,b in zip(x,y)) for x,y in zip(val, expected_val))