Skip to content

Commit

Permalink
Refactor/projection/connection specs (#507)
Browse files Browse the repository at this point in the history
* • Projection
  _parse_connection_specs: moved connection info to states

* -

* -

* • Projection
  _parse_connection_spec:  moved connection attributes to State subclasses

• Registry:
  -register_category: added test for connection attributes on State subclasses
  • Loading branch information
jdcpni authored Nov 2, 2017
1 parent 9237616 commit 069e8a7
Show file tree
Hide file tree
Showing 9 changed files with 99 additions and 119 deletions.
126 changes: 18 additions & 108 deletions psyneulink/components/projections/projection.py
Original file line number Diff line number Diff line change
Expand Up @@ -321,7 +321,8 @@
INPUT_STATE, LEARNING, LEARNING_PROJECTION, MAPPING_PROJECTION, MATRIX, MATRIX_KEYWORD_SET, \
MECHANISM, NAME, OUTPUT_STATE, PARAMETER_STATES, PARAMETER_STATE_PARAMS, PARAMS, PATHWAY, \
PROJECTION, PROJECTION_PARAMS, PROJECTION_SENDER, PROJECTION_TYPE, RECEIVER, SENDER, \
STANDARD_ARGS, STATE, STATES, WEIGHT, kwAddInputState, kwAddOutputState, kwProjectionComponentCategory
STANDARD_ARGS, STATE, STATES, WEIGHT, CONTROLLED_PARAMS, LEARNED_PARAM, GATED_STATES, \
kwAddInputState, kwAddOutputState, kwProjectionComponentCategory
from psyneulink.globals.preferences.preferenceset import PreferenceLevel
from psyneulink.globals.registry import register_category
from psyneulink.globals.utilities import ContentAddressableList, iscompatible, type_match, is_matrix
Expand Down Expand Up @@ -1082,6 +1083,16 @@ def _parse_connection_specs(connectee_state_type,
usually it is a Mechanism or State to/from which the connectee_state_type should send/receive the Projection,
so calling the method "_parse_projections" would be misleading.
CONNECTION CHARACTERISTICS DECLARED BY EACH TYPE (SUBCLASS) OF State:
ConnectsWith : State
- specifies the type (subclass) of State to which the connectee_state_type should be assigned projection(s)
connect_with_attr : str
- specifies the name of the attribute of the Mechanism that holds the states of the ConnectsWith's type
PROJECTION_SOCKET : [SENDER or RECEIVER]
- specifies for this method whether to use a Projection's sender or receiver for the connection
Modulator : ModulatorySignal
- class of ModulatorySignal that can send ModulatoryProjection to the connectee_state_type
This method deals with CONNECTION specifications that are made in one of the following places/ways:
- *PROJECTIONS* entry of a State specification dict [SYNONYM: *PROJECTIONS* - for backward compatiability];
- last item of a State specification tuple.
Expand Down Expand Up @@ -1151,122 +1162,21 @@ def _parse_connection_specs(connectee_state_type,
"""

# FIX: vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
# FIX: MOVE HANDLING OF ALL THIS TO REGISTRY

from psyneulink.components.system import SystemInputState
from psyneulink.components.process import ProcessInputState
from psyneulink.components.mechanisms.processing.processingmechanism import ProcessingMechanism_Base
from psyneulink.components.mechanisms.adaptive.learning.learningmechanism import LearningMechanism
from psyneulink.components.mechanisms.adaptive.control.controlmechanism import ControlMechanism
from psyneulink.components.mechanisms.adaptive.gating.gatingmechanism import GatingMechanism
from psyneulink.components.projections.pathway.mappingprojection import MappingProjection
from psyneulink.components.states.state import _get_state_for_socket
from psyneulink.components.states.inputstate import InputState
from psyneulink.components.states.outputstate import OutputState
from psyneulink.components.states.parameterstate import ParameterState
from psyneulink.components.states.modulatorysignals.learningsignal import LearningSignal
from psyneulink.components.states.modulatorysignals.controlsignal import ControlSignal
from psyneulink.components.states.modulatorysignals.gatingsignal import GatingSignal
from psyneulink.globals.keywords import SENDER, RECEIVER, INPUT_STATES, OUTPUT_STATES, \
LEARNING_SIGNALS, CONTROL_SIGNALS, GATING_SIGNALS

# BaseSpec = connectee_state_type

# CONNECTION CHARACTERISTICS THAT MUST BE DECLARED BY EACH TYPE (SUBCLASS) OF State
# ConnectsWith : State
# - specifies the type (subclass) of State to which the connectee_state_type should be assigned projection(s)
# - [TBI] subclass' attribute: connect_with [??CURRENTLY: PROJECTION_TYPE]
# connect_with_attr : str
# - specifies the name of the attribute of the Mechanism that holds the states of the ConnectsWith's type
# - [TBI] subclass' attribute: connect_with_attr
# CONNECTIONS_KEYWORD : str
# - specifies the keyword used in State specification dictionary for entry specifying States to connect to
# - [TBI] subclass' attribute: connect_with_keyword
# PROJECTION_SOCKET : [SENDER or RECEIVER]
# - specifies for this method whether to use a Projection's sender or receiver for the connection
# - [TBI] subclass' attribute: projection_socket
# Modulator : ModulatorySignal
# - class of ModulatorySignal that can send ModulatoryProjection to the connectee_state_type
# - [TBI] subclass' attribute: modulator
# MOD_KEYWORD : str
# - specifies the keyword used in State specification dictionary for entry specifying ModulatorySignal
# - [TBI] subclass' attribute: mod_keyword
from psyneulink.components.states.state import StateRegistry

if not inspect.isclass(connectee_state_type):
raise ProjectionError("Called for {} with \'connectee_state_type\' arg ({}) that is not a class".
format(owner.name, connectee_state_type))
else:
BaseSpec = connectee_state_type

# Request for afferent Projections (projection socket is SENDER)
if issubclass(connectee_state_type, InputState):
ConnectsWith = [OutputState, # types of States to which the connectee can connect
ProcessInputState,
SystemInputState,
LearningSignal,
GatingSignal]
connect_with_attr = OUTPUT_STATES # attribute that holds the ConnectsWith States
CONNECTIONS_KEYWORD = OUTPUT_STATES # keyword used in a State specification dictionary for connection specs
PROJECTION_SOCKET = SENDER # socket of the Projection that connects to the ConnectsWith State
Modulators = [GatingSignal] # type of ModulatorySignals the connectee can receive
# MOD_KEYWORD = GATING_SIGNALS # keyword used in a State specification dictionary for Modulatory specs
elif isinstance(owner, Mechanism) and issubclass(connectee_state_type, ParameterState):
ConnectsWith = [ControlSignal]
connect_with_attr = CONTROL_SIGNALS
CONNECTIONS_KEYWORD = CONTROL_SIGNALS
PROJECTION_SOCKET = SENDER
Modulators = [ControlSignal]
# MOD_KEYWORD = CONTROL_SIGNALS
elif isinstance(owner, MappingProjection) and issubclass(connectee_state_type, ParameterState):
ConnectsWith = [LearningSignal, ControlSignal]
connect_with_attr = LEARNING_SIGNALS
CONNECTIONS_KEYWORD = LEARNING_SIGNALS
PROJECTION_SOCKET = SENDER
Modulators = [LearningSignal]
MOD_KEYWORD = LEARNING_SIGNALS

# Request for efferent Projections (projection socket is RECEIVER)
elif isinstance(owner, ProcessingMechanism_Base) and issubclass(connectee_state_type, OutputState):
ConnectsWith = [InputState]
connect_with_attr = INPUT_STATES
CONNECTIONS_KEYWORD = INPUT_STATES
PROJECTION_SOCKET = RECEIVER
Modulators = [GatingSignal]
MOD_KEYWORD = GATING_SIGNALS
elif isinstance(owner, ControlMechanism) and issubclass(connectee_state_type, ControlSignal):
ConnectsWith = [ParameterState]
connect_with_attr = PARAMETER_STATES
# CONNECTIONS_KEYWORD = CONTROLLED_PARAMS
PROJECTION_SOCKET = RECEIVER
Modulators = []
MOD_KEYWORD = None
elif isinstance(owner, LearningMechanism) and issubclass(connectee_state_type, LearningSignal):
ConnectsWith = [ParameterState]
connect_with_attr = PARAMETER_STATES
# CONNECTIONS_KEYWORD = LEARNED_PROJECTIONS
PROJECTION_SOCKET = RECEIVER
Modulators = []
MOD_KEYWORD = None
elif isinstance(owner, GatingMechanism) and issubclass(connectee_state_type, GatingSignal):
ConnectsWith = [InputState, OutputState]
connect_with_attr = [INPUT_STATES, OUTPUT_STATES]
# CONNECTIONS_KEYWORD = GATED_STATES
PROJECTION_SOCKET = RECEIVER
Modulators = []
MOD_KEYWORD = None

else:
raise ProjectionError("Called for {} with unsupported owner type ({}), connectee_state_type ({}), "
"or combination of them".
format(owner.name, owner.__class__.__name__, connectee_state_type.__name__))

# FIX: ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

# Get connection attributes
ConnectsWith = [StateRegistry[name].subclass for name in connectee_state_type.ConnectsWith]
connect_with_attr = connectee_state_type.ConnectsWithAttribute
PROJECTION_SOCKET = connectee_state_type.ProjectionSocket
Modulators = [StateRegistry[name].subclass for name in connectee_state_type.Modulators]

DEFAULT_WEIGHT = None
DEFAULT_EXPONENT = None
# DEFAULT_PROJECTION = PROJECTION_TYPE
DEFAULT_PROJECTION = None

# Convert to list for subsequent processing
Expand Down
12 changes: 11 additions & 1 deletion psyneulink/components/states/inputstate.py
Original file line number Diff line number Diff line change
Expand Up @@ -429,7 +429,8 @@
from psyneulink.components.states.state import StateError, State_Base, _instantiate_state_list, state_type_keywords
from psyneulink.components.states.outputstate import OutputState
from psyneulink.globals.keywords import EXPONENT, FUNCTION, INPUT_STATE, INPUT_STATE_PARAMS, MAPPING_PROJECTION, \
MECHANISM, OUTPUT_STATES, MATRIX, PROJECTIONS, PROJECTION_TYPE, SUM, VARIABLE, WEIGHT, REFERENCE_VALUE
MECHANISM, OUTPUT_STATES, MATRIX, PROJECTIONS, PROJECTION_TYPE, SUM, VARIABLE, WEIGHT, REFERENCE_VALUE, \
OUTPUT_STATE, PROCESS_INPUT_STATE, SYSTEM_INPUT_STATE, LEARNING_SIGNAL, GATING_SIGNAL, SENDER
from psyneulink.globals.preferences.componentpreferenceset import is_pref_set
from psyneulink.globals.preferences.preferenceset import PreferenceLevel
from psyneulink.globals.utilities import append_type_to_name, iscompatible
Expand Down Expand Up @@ -625,6 +626,15 @@ class InputState(State_Base):
componentType = INPUT_STATE
paramsType = INPUT_STATE_PARAMS

ConnectsWith = [OUTPUT_STATE,
PROCESS_INPUT_STATE,
SYSTEM_INPUT_STATE,
LEARNING_SIGNAL,
GATING_SIGNAL]
ConnectsWithAttribute = OUTPUT_STATES
ProjectionSocket = SENDER
Modulators = [GATING_SIGNAL]

classPreferenceLevel = PreferenceLevel.TYPE
# Any preferences specified below will override those specified in TypeDefaultPreferences
# Note: only need to specify setting; level will be assigned to TYPE automatically
Expand Down
11 changes: 10 additions & 1 deletion psyneulink/components/states/modulatorysignals/controlsignal.py
Original file line number Diff line number Diff line change
Expand Up @@ -294,7 +294,11 @@
from psyneulink.components.states.parameterstate import _get_parameter_state
from psyneulink.components.states.state import State_Base
from psyneulink.globals.defaults import defaultControlAllocation
from psyneulink.globals.keywords import ALLOCATION_SAMPLES, AUTO, CONTROLLED_PARAMS, CONTROL_PROJECTION, CONTROL_SIGNAL, EXECUTING, FUNCTION, FUNCTION_PARAMS, INTERCEPT, MECHANISM, MODULATION, NAME, OFF, ON, OUTPUT_STATE_PARAMS, PROJECTION_TYPE, SEPARATOR_BAR, SLOPE, SUM, kwAssign
from psyneulink.globals.keywords import \
ALLOCATION_SAMPLES, AUTO, CONTROLLED_PARAMS, CONTROL_PROJECTION, CONTROL_SIGNAL, EXECUTING, \
FUNCTION, FUNCTION_PARAMS, INTERCEPT, MECHANISM, MODULATION, NAME, OFF, ON, \
PARAMETER_STATE, PARAMETER_STATES, OUTPUT_STATE_PARAMS, \
PROJECTION_TYPE, RECEIVER, SEPARATOR_BAR, SLOPE, SUM, kwAssign
from psyneulink.globals.log import LogEntry, LogLevel
from psyneulink.globals.preferences.componentpreferenceset import is_pref_set
from psyneulink.globals.preferences.preferenceset import PreferenceLevel
Expand Down Expand Up @@ -610,6 +614,11 @@ class ControlSignal(ModulatorySignal):
componentType = CONTROL_SIGNAL
paramsType = OUTPUT_STATE_PARAMS

ConnectsWith = [PARAMETER_STATE]
ConnectsWithAttribute = [PARAMETER_STATES]
ProjectionSocket = RECEIVER
Modulators = []

classPreferenceLevel = PreferenceLevel.TYPE
# Any preferences specified below will override those specified in TypeDefaultPreferences
# Note: only need to specify setting; level will be assigned to TYPE automatically
Expand Down
10 changes: 8 additions & 2 deletions psyneulink/components/states/modulatorysignals/gatingsignal.py
Original file line number Diff line number Diff line change
Expand Up @@ -234,8 +234,9 @@
from psyneulink.components.states.modulatorysignals.modulatorysignal import ModulatorySignal, modulatory_signal_keywords
from psyneulink.components.states.outputstate import OutputState, PRIMARY_OUTPUT_STATE
from psyneulink.components.states.state import State_Base
from psyneulink.globals.keywords import GATING_PROJECTION, GATING_SIGNAL, GATING_SIGNALS, INPUT_STATE, MECHANISM, NAME, \
OUTPUT_STATE, OUTPUT_STATES, OUTPUT_STATE_PARAMS, PARAMS, PROJECTION_TYPE, STATES, SUM, GATE
from psyneulink.globals.keywords import \
GATING_PROJECTION, GATING_SIGNAL, GATE, RECEIVER, SUM, PROJECTION_TYPE, \
INPUT_STATE, INPUT_STATES, OUTPUT_STATE, OUTPUT_STATES, OUTPUT_STATE_PARAMS
from psyneulink.globals.preferences.componentpreferenceset import is_pref_set
from psyneulink.globals.preferences.preferenceset import PreferenceLevel

Expand Down Expand Up @@ -393,6 +394,11 @@ class GatingSignal(ModulatorySignal):
componentName = 'GatingSignal'
paramsType = OUTPUT_STATE_PARAMS

ConnectsWith = [INPUT_STATE, OUTPUT_STATE]
ConnectsWithAttribute = [INPUT_STATES, OUTPUT_STATES]
ProjectionSocket = RECEIVER
Modulators = []

classPreferenceLevel = PreferenceLevel.TYPE
# Any preferences specified below will override those specified in TypeDefaultPreferences
# Note: only need to specify setting; level will be assigned to TYPE automatically
Expand Down
10 changes: 8 additions & 2 deletions psyneulink/components/states/modulatorysignals/learningsignal.py
Original file line number Diff line number Diff line change
Expand Up @@ -174,8 +174,9 @@
from psyneulink.components.states.modulatorysignals.modulatorysignal import ModulatorySignal
from psyneulink.components.states.outputstate import PRIMARY_OUTPUT_STATE
from psyneulink.components.states.state import State_Base
from psyneulink.globals.keywords \
import LEARNED_PARAM, LEARNING_SIGNAL, LEARNING_PROJECTION, OUTPUT_STATE_PARAMS, PROJECTION_TYPE, SUM
from psyneulink.globals.keywords import \
LEARNED_PARAM, LEARNING_SIGNAL, LEARNING_PROJECTION, \
PROJECTION_TYPE, RECEIVER, OUTPUT_STATE_PARAMS, PARAMETER_STATE, PARAMETER_STATES, SUM
from psyneulink.globals.preferences.componentpreferenceset import is_pref_set
from psyneulink.globals.preferences.preferenceset import PreferenceLevel
from psyneulink.globals.utilities import parameter_spec
Expand Down Expand Up @@ -335,6 +336,11 @@ class LearningSignal(ModulatorySignal):
componentType = LEARNING_SIGNAL
paramsType = OUTPUT_STATE_PARAMS

ConnectsWith = [PARAMETER_STATE]
ConnectsWithAttribute = [PARAMETER_STATES]
ProjectionSocket = RECEIVER
Modulators = []

classPreferenceLevel = PreferenceLevel.TYPE
# Any preferences specified below will override those specified in TypeDefaultPreferences
# Note: only need to specify setting; level will be assigned to TYPE automatically
Expand Down
7 changes: 6 additions & 1 deletion psyneulink/components/states/outputstate.py
Original file line number Diff line number Diff line change
Expand Up @@ -339,7 +339,7 @@
from psyneulink.components.shellclasses import Mechanism, Projection
from psyneulink.components.states.state import State_Base, _instantiate_state_list, state_type_keywords
from psyneulink.globals.keywords import \
PROJECTION, PROJECTIONS, PROJECTION_TYPE, MAPPING_PROJECTION, \
PROJECTION, PROJECTIONS, PROJECTION_TYPE, MAPPING_PROJECTION, INPUT_STATE, INPUT_STATES, RECEIVER, GATING_SIGNAL, \
STATE, OUTPUT_STATE, OUTPUT_STATES, OUTPUT_STATE_PARAMS, RESULT, INDEX, \
CALCULATE, MEAN, MEDIAN, NAME, STANDARD_DEVIATION, STANDARD_OUTPUT_STATES, SUM, VARIANCE
from psyneulink.globals.preferences.componentpreferenceset import is_pref_set
Expand Down Expand Up @@ -573,6 +573,11 @@ class OutputState(State_Base):
componentType = OUTPUT_STATE
paramsType = OUTPUT_STATE_PARAMS

ConnectsWith = [INPUT_STATE]
ConnectsWithAttribute = INPUT_STATES
ProjectionSocket = RECEIVER
Modulators = [GATING_SIGNAL]

class ClassDefaults(State_Base.ClassDefaults):
variable = None

Expand Down
10 changes: 9 additions & 1 deletion psyneulink/components/states/parameterstate.py
Original file line number Diff line number Diff line change
Expand Up @@ -287,7 +287,9 @@
from psyneulink.components.functions.function import Linear, get_param_value_for_keyword
from psyneulink.components.shellclasses import Mechanism, Projection
from psyneulink.components.states.state import StateError, State_Base, _instantiate_state, state_type_keywords
from psyneulink.globals.keywords import CONTROL_PROJECTION, FUNCTION, FUNCTION_PARAMS, MECHANISM, PARAMETER_STATE, PARAMETER_STATES, PARAMETER_STATE_PARAMS, PATHWAY_PROJECTION, PROJECTION, PROJECTIONS, PROJECTION_TYPE, VALUE
from psyneulink.globals.keywords import CONTROL_PROJECTION, FUNCTION, FUNCTION_PARAMS, MECHANISM, PARAMETER_STATE, \
PARAMETER_STATES, PARAMETER_STATE_PARAMS, PATHWAY_PROJECTION, PROJECTION, PROJECTIONS, PROJECTION_TYPE, VALUE, \
CONTROL_SIGNAL, CONTROL_SIGNALS, LEARNING_SIGNAL, LEARNING_SIGNALS, SENDER
from psyneulink.globals.preferences.componentpreferenceset import is_pref_set
from psyneulink.globals.preferences.preferenceset import PreferenceLevel
from psyneulink.globals.utilities import ContentAddressableList, ReadOnlyOrderedDict, is_numeric, is_value_spec, iscompatible
Expand Down Expand Up @@ -450,6 +452,12 @@ class ParameterState(State_Base):
componentType = PARAMETER_STATE
paramsType = PARAMETER_STATE_PARAMS

ConnectsWith = [CONTROL_SIGNAL, LEARNING_SIGNAL]
ConnectsWithAttribute = [CONTROL_SIGNALS, LEARNING_SIGNALS]
ProjectionSocket = SENDER
Modulators = [CONTROL_SIGNAL, LEARNING_SIGNAL]


classPreferenceLevel = PreferenceLevel.TYPE
# Any preferences specified below will override those specified in TypeDefaultPreferences
# Note: only need to specify setting; level will be assigned to TYPE automatically
Expand Down
10 changes: 7 additions & 3 deletions psyneulink/globals/keywords.py
Original file line number Diff line number Diff line change
Expand Up @@ -569,16 +569,18 @@ def _names(self):

MODULATION = 'modulation'

# LearningMechanism:
LEARNING_SIGNALS = 'learning_signals'
LEARNING_SIGNAL_SPECS = 'LEARNING_SIGNAL_SPECS'
LEARNED_PARAM = 'learned_param'

# ControlMechanism / EVCControlMechanism
OBJECTIVE_MECHANISM = "objective_mechanism"
MONITOR_FOR_CONTROL = "monitor_for_control"
PREDICTION_MECHANISM = "Prediction Mechanism"
PREDICTION_MECHANISM_TYPE = "prediction_mechanism_type"
PREDICTION_MECHANISM_PARAMS = "prediction_mechanism_params"
PREDICTION_MECHANISM_OUTPUT = "PredictionMechanismOutput"
LEARNING_SIGNALS = 'learning_signals'
LEARNING_SIGNAL_SPECS = 'LEARNING_SIGNAL_SPECS'
LEARNED_PARAM = 'learned_param'
CONTROL_SIGNALS = 'control_signals'
CONTROL_SIGNAL_SPECS = 'CONTROL_SIGNAL_SPECS'
CONTROLLED_PARAMS = 'CONTROLLED_PARAMS'
Expand All @@ -592,11 +594,13 @@ def _names(self):
EVC_SIMULATION = 'SIMULATING'
ALLOCATION_SAMPLES = "allocation_samples"


# GatingMechanism
MAKE_DEFAULT_GATING_MECHANISM = "make_default_gating_mechanism"
GATING_SIGNALS = 'gating_signals'
GATING_SIGNAL_SPECS = 'GATING_SIGNAL_SPECS'
GATE = 'GATE'
GATED_STATES = 'GATED_STATES'
GATING_PROJECTIONS = 'GatingProjections'
GATING_POLICY = 'gating_policy'

Expand Down
22 changes: 22 additions & 0 deletions psyneulink/globals/registry.py
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,28 @@ def register_category(entry,
:return:
"""

# IMPLEMENTATION NOTE: Move to State when that is implemented as ABC
import inspect
from psyneulink.components.states.state import State, State_Base
if inspect.isclass(entry) and issubclass(entry, State) and not entry == State_Base:
try:
entry.ConnectsWith
except AttributeError:
raise RegistryError("{} does not have ConnectsWith attribute".format(entry.__name__))
try:
entry.ConnectsWithAttribute
except AttributeError:
raise RegistryError("{} does not have ConnectsWithAttribute attribute".format(entry.__name__))
try:
entry.ProjectionSocket
except AttributeError:
raise RegistryError("{} does not have ProjectionSocket attribute".format(entry.__name__))
try:
entry.Modulators
except AttributeError:
raise RegistryError("{} does not have Modulators attribute".format(entry.__name__))


from psyneulink.components.component import Component
from psyneulink.globals.preferences.preferenceset import PreferenceSet
if not issubclass(base_class, (Component, PreferenceSet)):
Expand Down

0 comments on commit 069e8a7

Please sign in to comment.