Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor/controlmech and ocm #2186

Merged
merged 53 commits into from
Nov 7, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
53 commits
Select commit Hold shift + click to select a range
064d63f
• component.py
jdcpni Apr 30, 2021
614a53a
Merge branch 'devel' of https://github.com/PrincetonUniversity/PsyNeu…
jdcpni Apr 30, 2021
a32f213
Merge branch 'devel' of https://github.com/PrincetonUniversity/PsyNeu…
jdcpni Apr 30, 2021
75cf069
Merge branch 'devel' of https://github.com/PrincetonUniversity/PsyNeu…
jdcpni May 5, 2021
dff1a37
Merge branch 'devel' of https://github.com/PrincetonUniversity/PsyNeu…
jdcpni Jul 8, 2021
cd5e38e
Merge branch 'devel' of https://github.com/PrincetonUniversity/PsyNeu…
jdcpni Oct 23, 2021
9361857
Merge branch 'devel' of https://github.com/PrincetonUniversity/PsyNeu…
jdcpni Oct 30, 2021
0129ff7
Merge branch 'devel' of https://github.com/PrincetonUniversity/PsyNeu…
jdcpni Nov 4, 2021
bbd20f5
Merge branch 'devel' of https://github.com/PrincetonUniversity/PsyNeu…
jdcpni Nov 4, 2021
0f2b360
• controlmechanism.py: add support for monitor_for_control in _instan…
jdcpni Nov 4, 2021
ac16124
-
jdcpni Nov 5, 2021
8c63766
• controlmechanism.py: refactoring to use outcome_input_ports_option
jdcpni Nov 5, 2021
8497a2c
• controlmechanism.py: refactored to use outcome_input_ports
jdcpni Nov 5, 2021
d27f0de
-
jdcpni Nov 5, 2021
ae8dd04
-
jdcpni Nov 5, 2021
815f3bf
-
Nov 5, 2021
53529af
-
Nov 5, 2021
136cf8c
-
Nov 5, 2021
4738dc1
Tests passing
Nov 6, 2021
7e26c83
• controlMechanism.py:
jdcpni Nov 6, 2021
ae14a7c
-
jdcpni Nov 6, 2021
c7154b4
• port.py:
jdcpni Nov 6, 2021
9560d05
• port.py:
jdcpni Nov 6, 2021
a1fefa9
• controlmechanism.py: fixed bugs in use of COMBINE and CONCATENATE
jdcpni Nov 6, 2021
96e3c09
• controlmechanism.py: fixed more bugs in use of COMBINE and CONCATENATE
jdcpni Nov 6, 2021
fa28f3f
• optimizationcontrolmechanism.py: renamed evaluation_function -> eva…
jdcpni Nov 6, 2021
f844101
• optimizationfunctions.py:
jdcpni Nov 6, 2021
011f0fb
• optimizationfunctions.py:
jdcpni Nov 6, 2021
7266eee
-
jdcpni Nov 6, 2021
7f85b91
• optimizationfunctions.py:
jdcpni Nov 6, 2021
afba56e
-
jdcpni Nov 6, 2021
47a8e23
-
jdcpni Nov 6, 2021
39979ea
-
jdcpni Nov 6, 2021
6b06ff1
• tests/composition: add test_parameterestimationcomposition.py
jdcpni Nov 6, 2021
a1de1e4
• tests/composition: add test_parameterestimationcomposition.py (basi…
jdcpni Nov 6, 2021
b133d7b
-
jdcpni Nov 6, 2021
37e470d
-
Nov 6, 2021
1d86b2a
-
Nov 7, 2021
2ea427c
-
Nov 7, 2021
ddaa3f5
• optimizationcontrolmechanism.py:
Nov 7, 2021
d311cc9
-
Nov 7, 2021
2a9a0dd
-
jdcpni Nov 7, 2021
3176354
Merge branch 'refactor/controlmech_and_ocm' of https://github.com/Pri…
jdcpni Nov 7, 2021
8b97f0f
Merge branch 'devel' of https://github.com/PrincetonUniversity/PsyNeu…
jdcpni Nov 7, 2021
edd2890
Merge branch 'devel' of https://github.com/PrincetonUniversity/PsyNeu…
Nov 7, 2021
f66aaac
Merge branch 'refactor/controlmech_and_ocm' of https://github.com/Pri…
jdcpni Nov 7, 2021
2a75511
• optimizationcontrolmechanism.py:
jdcpni Nov 7, 2021
492d2c6
• optimizationcontrolmechanism.py: docstring updates to reflect prece…
jdcpni Nov 7, 2021
711d60c
• optimizationcontrolmechanism.py: more docstring edits
jdcpni Nov 7, 2021
e2f5fa1
-
jdcpni Nov 7, 2021
adf34b2
-
jdcpni Nov 7, 2021
a8eb851
-
Nov 7, 2021
bc6f4a9
-
jdcpni Nov 7, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,7 @@ def print_weights():
print('ControlSignal variables: ', [sig.parameters.variable.get(i) for sig in lvoc.control_signals])
print('ControlSignal values: ', [sig.parameters.value.get(i) for sig in lvoc.control_signals])
# print('state_features: ', lvoc.get_feature_values(context=c))
print('lvoc: ', lvoc.evaluation_function([sig.parameters.variable.get(i) for sig in lvoc.control_signals], context=i))
print('lvoc: ', lvoc.evaluate_agent_rep([sig.parameters.variable.get(i) for sig in lvoc.control_signals], context=i))
# print('time: ', duration)
print('--------------------')

Expand Down Expand Up @@ -222,6 +222,6 @@ def print_weights():
# print('ControlSignal variables: ', [sig.parameters.variable.get(c) for sig in lvoc.control_signals])
# print('ControlSignal values: ', [sig.parameters.value.get(c) for sig in lvoc.control_signals])
# # print('state_features: ', lvoc.get_feature_values(context=c))
# print('lvoc: ', lvoc.evaluation_function([sig.parameters.variable.get(c) for sig in lvoc.control_signals], context=c))
# print('lvoc: ', lvoc.evaluate_agent_rep([sig.parameters.variable.get(c) for sig in lvoc.control_signals], context=c))
# print('time: ', duration)
# print('--------------------')
Original file line number Diff line number Diff line change
Expand Up @@ -232,7 +232,7 @@ def print_weights():
print('ControlSignal variables: ', [sig.parameters.variable.get(i) for sig in lvoc.control_signals])
print('ControlSignal values: ', [sig.parameters.value.get(i) for sig in lvoc.control_signals])
# print('state_features: ', lvoc.state_feature_values)
# print('lvoc: ', lvoc.evaluation_function([sig.parameters.variable.get(i) for sig in lvoc.control_signals], context=i))
# print('lvoc: ', lvoc.evaluate_agent_rep([sig.parameters.variable.get(i) for sig in lvoc.control_signals], context=i))
# print('time: ', duration)
print('--------------------')

Expand Down
8 changes: 0 additions & 8 deletions psyneulink/core/components/component.py
Original file line number Diff line number Diff line change
Expand Up @@ -1697,16 +1697,8 @@ def _deferred_init(self, **kwargs):
self._init_args.update(kwargs)

# Complete initialization
# MODIFIED 10/27/18 OLD:
super(self.__class__,self).__init__(**self._init_args)

# MODIFIED 10/27/18 NEW: FOLLOWING IS NEEDED TO HANDLE FUNCTION DEFERRED INIT (JDC)
# try:
# super(self.__class__,self).__init__(**self._init_args)
# except:
# self.__init__(**self._init_args)
# MODIFIED 10/27/18 END

# If name was assigned, "[DEFERRED INITIALIZATION]" was appended to it, so remove it
if DEFERRED_INITIALIZATION in self.name:
self.name = self.name.replace("[" + DEFERRED_INITIALIZATION + "]", "")
Expand Down

Large diffs are not rendered by default.

6 changes: 3 additions & 3 deletions psyneulink/core/components/mechanisms/mechanism.py
Original file line number Diff line number Diff line change
Expand Up @@ -1380,20 +1380,20 @@ class Mechanism_Base(Mechanism):

projections : ContentAddressableList
a list of all of the Mechanism's `Projections <Projection>`, composed from the
`path_afferents <InputPorts.path_afferents>` of all of its `input_ports <Mechanism_Base.input_ports>`,
`path_afferents <Port.path_afferents>` of all of its `input_ports <Mechanism_Base.input_ports>`,
the `mod_afferents` of all of its `input_ports <Mechanism_Base.input_ports>`,
`parameter_ports <Mechanism)Base.parameter_ports>`, and `output_ports <Mechanism_Base.output_ports>`,
and the `efferents <Port.efferents>` of all of its `output_ports <Mechanism_Base.output_ports>`.

afferents : ContentAddressableList
a list of all of the Mechanism's afferent `Projections <Projection>`, composed from the
`path_afferents <InputPorts.path_afferents>` of all of its `input_ports <Mechanism_Base.input_ports>`,
`path_afferents <Port.path_afferents>` of all of its `input_ports <Mechanism_Base.input_ports>`,
and the `mod_afferents` of all of its `input_ports <Mechanism_Base.input_ports>`,
`parameter_ports <Mechanism)Base.parameter_ports>`, and `output_ports <Mechanism_Base.output_ports>`.,

path_afferents : ContentAddressableList
a list of all of the Mechanism's afferent `PathwayProjections <PathwayProjection>`, composed from the
`path_afferents <InputPorts.path_afferents>` attributes of all of its `input_ports
`path_afferents <Port.path_afferents>` attributes of all of its `input_ports
<Mechanism_Base.input_ports>`.

mod_afferents : ContentAddressableList
Expand Down

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -833,6 +833,8 @@ def monitored_output_ports_weights_and_exponents(self):
def monitored_output_ports_weights_and_exponents(self, weights_and_exponents_tuples):
self.monitor_weights_and_exponents = weights_and_exponents_tuples

# FIX: 11/3/21 -- MOVE THIS TO ControlMechanism, AND INTEGRATE WITH ControlMechanism.validate_monitored_port_spec()
# OR MOVE THAT METHOD TO HERE??
def _parse_monitor_specs(monitor_specs):
spec_tuple = namedtuple('SpecTuple', 'index spec')
parsed_specs = []
Expand Down
13 changes: 10 additions & 3 deletions psyneulink/core/components/ports/port.py
Original file line number Diff line number Diff line change
Expand Up @@ -1766,7 +1766,12 @@ def _get_receiver_port(spec):
context=context)
# Match the projection's value with the value of the function parameter
# should be defaults.value?
mod_proj_spec_value = type_match(projection.value, type(mod_param_value))
try:
mod_proj_spec_value = type_match(projection.value, type(mod_param_value))
except TypeError as error:
raise PortError(f"The value for {self.name} of {self.owner.name} ({projection.value}) does "
f"not match the format ({mod_param_value}) of the Parameter it modulates "
f"({receiver.owner.name}[{mod_param_name}]).")
if (mod_param_value is not None
and not iscompatible(mod_param_value, mod_proj_spec_value)):
raise PortError(f"Output of {projection.name} ({mod_proj_spec_value}) is not compatible "
Expand Down Expand Up @@ -3260,8 +3265,10 @@ def _parse_port_spec(port_type=None,
# port_dict[OWNER].name, spec_function_value, spec_function))

if port_dict[REFERENCE_VALUE] is not None and not iscompatible(port_dict[VALUE], port_dict[REFERENCE_VALUE]):
raise PortError("Port value ({}) does not match reference_value ({}) for {} of {})".
format(port_dict[VALUE], port_dict[REFERENCE_VALUE], port_type.__name__, owner.name))
port_name = f"the {port_dict[NAME]}" if (NAME in port_dict and port_dict[NAME]) else f"an"
raise PortError(f"The value ({port_dict[VALUE]}) for {port_name} {port_type.__name__} of "
f"{owner.name} does not match the reference_value ({port_dict[REFERENCE_VALUE]}) "
f"used for it at construction.")

return port_dict

Expand Down
23 changes: 15 additions & 8 deletions psyneulink/core/compositions/composition.py
Original file line number Diff line number Diff line change
Expand Up @@ -402,10 +402,10 @@
- `Composition_Controller_Execution`


A Composition can be assigned a `controller <Composition.controller>`. This is a `ControlMechanism`, or a subclass of
one, that modulates the parameters of Components within the Composition (including Components of nested Compositions).
It typically does this based on the output of an `ObjectiveMechanism` that evaluates the value of other Mechanisms in
the Composition, and provides the result to the `controller <Composition.controller>`.
A Composition can be assigned a `controller <Composition.controller>`. This must be an `OptimizationControlMechanism`,
or a subclass of one, that modulates the parameters of Components within the Composition (including Components of
nested Compositions). It typically does this based on the output of an `ObjectiveMechanism` that evaluates the value
of other Mechanisms in the Composition, and provides the result to the `controller <Composition.controller>`.

.. _Composition_Controller_Assignment:

Expand Down Expand Up @@ -2370,8 +2370,9 @@ def input_function(env, result):

from psyneulink.core import llvm as pnlvm
from psyneulink.core.components.component import Component, ComponentsMeta
from psyneulink.core.components.functions.nonstateful.combinationfunctions import LinearCombination, PredictionErrorDeltaFunction
from psyneulink.core.components.functions.function import is_function_type
from psyneulink.core.components.functions.nonstateful.combinationfunctions import LinearCombination, \
PredictionErrorDeltaFunction
from psyneulink.core.components.functions.nonstateful.learningfunctions import \
LearningFunction, Reinforcement, BackPropagation, TDLearning
from psyneulink.core.components.functions.nonstateful.transferfunctions import Identity
Expand Down Expand Up @@ -7140,6 +7141,7 @@ def add_controller(self, controller:ControlMechanism, context=None):
if invalid_aux_components:
self._controller_initialization_status = ContextFlags.DEFERRED_INIT

# FIX: 11/3/21: ISN'T THIS HANDLED IN HANDLING OF aux_components?
if self.controller.objective_mechanism and self.controller.objective_mechanism not in invalid_aux_components:
self.add_node(self.controller.objective_mechanism, required_roles=NodeRole.CONTROLLER_OBJECTIVE)

Expand All @@ -7159,6 +7161,8 @@ def add_controller(self, controller:ControlMechanism, context=None):
input_cims= [self.input_CIM] + nested_cims
# For the rest of the controller's input_ports if they are marked as receiving SHADOW_INPUTS,
# instantiate the shadowing Projection to them from the sender to the shadowed InputPort
# FIX: 11/3/21: BELOW NEEDS TO BE CORRECTED IF OUTCOME InputPort GETS MOVED
# ALSO, IF Non-OCM IS USED AS CONTROLLER, MAY HAVE MORE THAN ONE Inport FOR MONITORING
for input_port in controller.input_ports[1:]:
if hasattr(input_port, SHADOW_INPUTS) and input_port.shadow_inputs is not None:
for proj in input_port.shadow_inputs.path_afferents:
Expand Down Expand Up @@ -7189,7 +7193,7 @@ def add_controller(self, controller:ControlMechanism, context=None):
if proj.sender.owner not in nested_cims:
proj._activate_for_compositions(self)

# Check whether controller has input, and if not then disable
# Confirm that controller has input, and if not then disable it
if not (isinstance(self.controller.input_ports, ContentAddressableList)
and self.controller.input_ports):
# If controller was enabled, warn that it has been disabled
Expand Down Expand Up @@ -7260,14 +7264,17 @@ def _build_predicted_inputs_dict(self, predicted_input):
# If this is not a good assumption, we need another way to look up the feature InputPorts
# of the OCM and know which InputPort maps to which predicted_input value

if predicted_input is None:
no_predicted_input = (predicted_input is None or not len(predicted_input))
if no_predicted_input:
warnings.warn(f"{self.name}.evaluate() called without any inputs specified; default values will be used")


nested_nodes = dict(self._get_nested_nodes())
# FIX: 11/3/21 NEED TO MODIFY WHEN OUTCOME InputPort IS MOVED
shadow_inputs_start_index = self.controller.num_outcome_input_ports
for j in range(len(self.controller.input_ports) - shadow_inputs_start_index):
input_port = self.controller.input_ports[j + shadow_inputs_start_index]
if predicted_input is None:
if no_predicted_input:
shadowed_input = input_port.defaults.value
else:
shadowed_input = predicted_input[j]
Expand Down
Loading