Control Mechanisms

Overview

A ControlMechanism is an AdaptiveMechanism that modifies the parameter(s) of one or more Components, in response to an evaluative signal received from an ObjectiveMechanism. The ObjectiveMechanism monitors a specified set of OutputStates, and from these generates the evaluative signal that is used by the ControlMechanism’s function to calculate an control_allocation: a list of allocation values for each of its ControlSignals. Each ControlSignal uses its allocation to calculate its intensity, which is then transmitted by the ControlSignal’s ControlProjection(s) to the ParameterState(s) to which they project. Each ParameterState uses the value received by a ControlProjection to modify the value of the parameter for which it is responsible (see Modulation for a more detailed description of how modulation operates). A ControlMechanism can regulate only the parameters of Components in the System to which it belongs. The OutputStates used to determine the ControlMechanism’s control_allocation, the ObjectiveMechanism used to evalute these, and the parameters controlled by the ControlMechanism can be listed using its show method.

ControlMechanisms and a System

A ControlMechanism can be assigned to a Process and executed within one or more Systems, just like any other Mechanism. It can also be assigned as the controller of a System, that has a special relation to the System: it is used to control all of the parameters that have been specified for control in that System. A ControlMechanism can be the controller for only one System, and a System can have only one controller. The System’s controller is executed after all of the other Components in the System have been executed, including any other ControlMechanisms that belong to it (see System Execution). A ControlMechanism can be assigned as the controller for a System by specifying it in the controller argument of the System’s constructor, or by specifying the System as the system argument of either the ControlMechanism’s constructor or its assign_as_controller method. A System’s controller and its associated Components can be displayed using the System’s show_graph method with its show_control argument assigned as True.

Creating a ControlMechanism

A ControlMechanism can be created using the standard Python method of calling the constructor for the desired type. A ControlMechanism is also created automatically whenever a System is created, and the ControlMechanism class or one of its subtypes is specified in the controller argument of the System’s constructor (see Creating a System). If the ControlMechanism is created explicitly (using its constructor), it must be included in a Process assigned to the System. The OutputStates monitored by its ObjectiveMechanism are specified in the monitor_for_control argument of its constructor, and the parameters it controls are specified in the control_signals argument; an ObjectiveMechanism is automatically created that monitors and evaluates the specified OutputStates. The ObjectiveMechanism can also be explicitly specified in the objective_mechanism argument of the ControlMechanism’s constructor (see below). If the ControlMechanism is created automatically by a System (as its controller), then the specification of OutputStates to be monitored and parameters to be controlled are made on the System and/or the Components themselves (see Specifying Control). In either case, the Components needed to monitor the specified OutputStates (an ObjectiveMechanism and Projections to it) and to control the specified parameters (ControlSignals and corresponding ControlProjections) are created automatically, as described below.

ObjectiveMechanism

Whenever a ControlMechanism is created, it automatically creates an ObjectiveMechanism that monitors and evaluates the value(s) of a set of OutputState(s); this evaluation is used to determine the ControlMechanism’s control_allocation. The ObjectiveMechanism, the OutputStates that it monitors, and how it evaluates them can be specified in a variety of ways, that depend on the context in which the ControlMechanism is created, as described in the subsections below. In all cases, the ObjectiveMechanism is assigned to the ControlMechanism’s objective_mechanism attribute, and a MappingProjection is created that projects from the ObjectiveMechanism’s OUTCOME OutputState to the ControlMechanism’s OUTCOME InputState (which is its primary InputState. All of the OutputStates monitored by the ObjectiveMechanism are listed in its monitored_output_States attribute, and in the ControlMechanism’s monitor_for_control attribute.

When the ControlMechanism is created explicitly

When a ControlMechanism is created explicitly – either on its own, or in the controller argument of the constructor for a System) – the following arguments of the ControlMechanism’s constructor can be used to specify its ObjectiveMechanism and/or the OutputStates it monitors:

  • objective_mechanism – this can be specified using any of the following:


    • a constructor for an ObjectiveMechanism; its monitored_output_states argument can be used to specify the OutputStates to be monitored, and its function argument can be used to specify how those OutputStates are evaluated (see Examples).

    • a list of OutputState specifications; a default ObjectiveMechanism is created, using the list of OutputState specifications for its monitored_output_states argument.

    Note that if the ObjectiveMechanism is explicitly (using either of the first two methods above), its attributes override any attributes specified by the ControlMechanism for its default objective_mechanism, including those of its function (see note in EVCControlMechanism for an example);

  • monitor_for_control – a list a list of OutputState specifications; a default ObjectiveMechanism is created, using the list of OutputState specifications for its monitored_output_states argument.

If OutputStates to be monitored are specified in both the objective_mechanism argument (on their own, or within the constructor for an ObjectiveMechanism) and the monitor_for_control argument of the ControlMechanism, both sets are used in creating the ObjectiveMechanism.

When the ControlMechanism is created for or assigned as the controller a System

If a ControlMechanism is specified as the controller of a System (see ControlMechanisms and a System), any OutputStates specified to be monitored by the System are assigned as inputs to the ObjectiveMechanism. This includes any specified in the monitor_for_control argument of the System’s constructor, as well as any specified in a MONITOR_FOR_CONTROL entry of a Mechanism parameter specification dictionary (see Additional Constructor Arguments and Specifying Control).

  • Adding OutputStates to be monitored to a ControlMechanism*

OutputStates to be monitored can also be added to an existing ControlMechanism by using the add_monitored_output_states method of the ControlMechanism’s objective_mechanism.

Specifying Parameters to Control

A ControlMechanism is used to control the parameter values of other Components. A ControlSignal is assigned for each parameter controlled by a ControlMechanism, and a ControlProjection is assigned from each ControlSignal to the ParameterState for the corresponding parameter to be controlled.

The parameters to be controlled by a ControlMechanism can be specified where it is created.

If it is created explicitly, the parameters to be controlled can be specified in the control_signals argument of its constructor. The argument must be a specification for one more ControlSignals.

If the ControlMechanism is created as part of a System, the parameters to be controlled by it can be specified in one of two ways:

When a ControlMechanism is created as part of a System, a ControlSignal is created and assigned to the ControlMechanism for every parameter of any Component in the System that has been specified for control using either of the methods above.

Parameters to be controlled can be added to an existing ControlMechanism by using its assign_params method to add a ControlSignal for each additional parameter.

All of the ControlSignals for a ControlMechanism are listed in its control_signals attribute, and all of its ControlProjections are listed in its control_projections attribute.

Structure

Input

A ControlMechanism has a single OUTCOME InputState. Its value (that can be referenced by its outcome attribute) is used as the input to the ControlMechanism’s function, that determines the ControlMechanism’s control_allocation. The OUTCOME InputState receives its input via a MappingProjection from the OUTCOME OutputState of an ObjectiveMechanism. The Objective Mechanism is specified in the objective_mechanism argument of its constructor, and listed in its objective_mechanism attribute. The OutputStates monitored by the ObjectiveMechanism (listed in its monitored_output_states attribute) are also listed in the monitor_for_control of the ControlMechanism (see ObjectiveMechanism for how the ObjectiveMechanism and the OutputStates it monitors are specified). The OutputStates monitored by the ControlMechanism’s objective_mechanism can be displayed using its show method. The ObjectiveMechanism’s function evaluates the specified OutputStates, and the result is conveyed as the input to the ControlMechanism.

Function

A ControlMechanism’s function uses the value of its OUTCOME InputState (outcome to generate an control_allocation. By default, each item of the control_allocation is assigned as the allocation of the corresponding ControlSignal in control_signals; however, subtypes of ControlMechanism may assign values differently (for example, an LCControlMechanism assigns a single value to all of its ControlSignals).

Output

A ControlMechanism has a ControlSignal for each parameter specified in its control_signals attribute, that sends a ControlProjection to the ParameterState for the corresponding parameter. ControlSignals are a type of OutputState, and so they are also listed in the ControlMechanism’s output_states attribute. The parameters modulated by a ControlMechanism’s ControlSignals can be displayed using its show method. By default, each value of each ControlSignal is assigned the value of the corresponding item from the ControlMechanism’s control_allocation; however, subtypes of ControlMechanism may assign values differently. The allocation is used by each ControlSignal to determine its intensity, which is then assigned as the value of the ControlSignal’s ControlProjection. The value of the ControlProjection is used by the ParameterState to which it projects to modify the value of the parameter it controls (see Modulation for description of how a ControlSignal modulates the value of a parameter).

Costs and Net Outcome

When a ControlMechanism executes, each of its control_signals can incur a cost. The costs

Execution

If a ControlMechanism is a System’s controller, it is always the last Mechanism to be executed in a TRIAL for that System (see System Control and Execution). The ControlMechanism’s function takes as its input the value of its OUTCOME input_state (also contained in outcome and uses that to determine its control_allocation which specifies the value assigned to the allocation of each of its ControlSignals. Each ControlSignal uses that value to calculate its intensity, which is used by its ControlProjection(s) to modulate the value of the ParameterState(s) for the parameter(s) it controls, which are then used in the subsequent TRIAL of execution.

Note

A ParameterState that receives a ControlProjection does not update its value until its owner Mechanism executes (see Lazy Evaluation for an explanation of “lazy” updating). This means that even if a ControlMechanism has executed, a parameter that it controls will not assume its new value until the Mechanism to which it belongs has executed.

Examples

The following example creates a ControlMechanism by specifying its objective_mechanism using a constructor that specifies the OutputStates to be monitored by its objective_mechanism and the function used to evaluated these:

>>> import psyneulink as pnl
>>> my_transfer_mech_A = pnl.TransferMechanism(name="Transfer Mech A")
>>> my_DDM = pnl.DDM(name="My DDM")
>>> my_transfer_mech_B = pnl.TransferMechanism(function=pnl.Logistic,
...                                            name="Transfer Mech B")

>>> my_control_mech = pnl.ControlMechanism(
...                          objective_mechanism=pnl.ObjectiveMechanism(monitored_output_states=[(my_transfer_mech_A, 2, 1),
...                                                                                               my_DDM.output_states[pnl.RESPONSE_TIME]],
...                                                                     name="Objective Mechanism"),
...                          function=pnl.LinearCombination(operation=pnl.PRODUCT),
...                          control_signals=[(pnl.THRESHOLD, my_DDM),
...                                           (pnl.GAIN, my_transfer_mech_B)],
...                          name="My Control Mech")

This creates an ObjectiveMechanism for the ControlMechanism that monitors the primary OutputState of my_Transfer_mech_A and the RESPONSE_TIME OutputState of my_DDM; its function first multiplies the former by 2 before, then takes product of their values and passes the result as the input to the ControlMechanism. The ControlMechanism’s function uses this value to determine the allocation for its ControlSignals, that control the value of the threshold parameter of my_DDM and the gain parameter of the Logistic Function for my_transfer_mech_B.

The following example specifies the same set of OutputStates for the ObjectiveMechanism, by assigning them directly to the objective_mechanism argument:

>>> my_control_mech = pnl.ControlMechanism(
...                             objective_mechanism=[(my_transfer_mech_A, 2, 1),
...                                                  my_DDM.output_states[pnl.RESPONSE_TIME]],
...                             control_signals=[(pnl.THRESHOLD, my_DDM),
...                                              (pnl.GAIN, my_transfer_mech_B)])
...

Note that, while this form is more succinct, it precludes specifying the ObjectiveMechanism’s function. Therefore, the values of the monitored OutputStates will be added (the default) rather than multiplied.

The ObjectiveMechanism can also be created on its own, and then referenced in the constructor for the ControlMechanism:

>>> my_obj_mech = pnl.ObjectiveMechanism(monitored_output_states=[(my_transfer_mech_A, 2, 1),
...                                                               my_DDM.output_states[pnl.RESPONSE_TIME]],
...                                      function=pnl.LinearCombination(operation=pnl.PRODUCT))

>>> my_control_mech = pnl.ControlMechanism(
...                        objective_mechanism=my_obj_mech,
...                        control_signals=[(pnl.THRESHOLD, my_DDM),
...                                         (pnl.GAIN, my_transfer_mech_B)])

Here, as in the first example, the constructor for the ObjectiveMechanism can be used to specify its function, as well as the OutputState that it monitors.

See Specifying Control for a System for examples of how a ControlMechanism, the OutputStates its objective_mechanism, and its control_signals can be specified for a System.

Class Reference

class psyneulink.core.components.mechanisms.adaptive.control.controlmechanism.ControlMechanism(system=None monitor_for_control=None, objective_mechanism=None, origin_objective_mechanism=False terminal_objective_mechanism=False function=Linear, control_signals=None, modulation=ModulationParam.MULTIPLICATIVE combine_costs=np.sum, compute_reconfiguration_cost=None, compute_net_outcome=lambda x, y:x-y, params=None, name=None, prefs=None)

Subclass of AdaptiveMechanism that modulates the parameter(s) of one or more Component(s).

Parameters:
  • system (System or bool : default None) – specifies the System to which the ControlMechanism should be assigned as its controller.
  • monitor_for_control (List[OutputState or Mechanism] : default None) – specifies the OutputStates to be monitored by the ObjectiveMechanism specified in the objective_mechanism argument; for any Mechanisms specified, their primary OutputState are used.
  • objective_mechanism (ObjectiveMechanism or List[OutputState specification] : default None) – specifies either an ObjectiveMechanism to use for the ControlMechanism, or a list of the OutputStates it should monitor; if a list of OutputState specifications is used, a default ObjectiveMechanism is created and the list is passed to its monitored_output_states argument.
  • origin_objective_mechanism (Boolean : default False) –

    specifies whether the objective_mechanism may be an ORIGIN node of composition.

    When False, even if the ObjectiveMechanism is an ORIGIN node according to the structure of the Composition’s graph, the ObjectiveMechanism is not marked as ORIGIN. If the ObjectiveMechanism would be the only ORIGIN node, then the user must use required_roles to assign another node as ORIGIN.

    When True, if the ObjectiveMechanism is an ORIGIN node according to the structure of the Composition’s graph, it is treated normally. If the ObjectiveMechanism is not an ORIGIN node according to the structure of the graph, then it takes on ORIGIN as a required role.

  • terminal_objective_mechanism (Boolean : default False) –

    specifies whether the objective_mechanism may be an TERMINAL node of composition.

    When False, even if the ObjectiveMechanism is a TERMINAL node according to the structure of the Composition’s graph, the ObjectiveMechanism is not marked as TERMINAL. If the ObjectiveMechanism was the only TERMINAL node, then the user must use required_roles to assign another node as TERMINAL for the Composition.

    When True, if the ObjectiveMechanism is a TERMINAL node according to the structure of the Composition’s graph, it is treated normally. If the ObjectiveMechanism is not a TERMINAL node according to the structure of the graph, then it takes on TERMINAL as a required role.

  • function (TransferFunction : default Linear(slope=1, intercept=0)) – specifies function used to combine values of monitored OutputStates.
  • control_signals (ControlSignal specification or List[ControlSignal specification, ..]) – specifies the parameters to be controlled by the ControlMechanism; a ControlSignal is created for each (see Specifying ControlSignals for details of specification).
  • modulation (ModulationParam : ModulationParam.MULTIPLICATIVE) – specifies the default form of modulation used by the ControlMechanism’s ControlSignals, unless they are individually specified.
  • combine_costs (Function, function or method : default np.sum) – specifies function used to combine the cost of the ControlMechanism’s control_signals; must take a list or 1d array of scalar values as its argument and return a list or array with a single scalar value.
  • compute_reconfiguration_cost (Function, function or method : default None) – specifies function used to compute the ControlMechanism’s reconfiguration_cost; must take a list or 2d array containing two lists or 1d arrays, both with the same shape as the ControlMechanism’s control_allocation attribute, and return a scalar value.
  • compute_net_outcome (Function, function or method : default lambda outcome, cost: outcome-cost) – function used to combine the values of its outcome and costs attributes; must take two 1d arrays (outcome and cost) with scalar values as its arguments and return an array with a single scalar value.
  • params (Dict[param keyword: param value] : default None) – a parameter dictionary that can be used to specify the parameters for the Mechanism, parameters for its function, and/or a custom function and its parameters. Values specified for parameters in the dictionary override any assigned to those parameters in arguments of the constructor.
  • name (str : default see name) – specifies the name of the ControlMechanism.
  • prefs (PreferenceSet or specification dict : default Mechanism.classPreferences) – specifies the PreferenceSet for the ControlMechanism; see prefs for details.
system

System_Base – The System for which the ControlMechanism is a controller. Note that this is distinct from a Mechanism’s systems attribute, which lists all of the Systems to which a Mechanisms belongs – a ControlMechanism can belong to but not be the controller of a System.

objective_mechanism

ObjectiveMechanismObjectiveMechanism that monitors and evaluates the values specified in the ControlMechanism’s objective_mechanism argument, and transmits the result to the ControlMechanism’s OUTCOME input_state.

origin_objective_mechanism

Boolean – specifies whether the ObjectiveMechanism of a ControlMechanism may be an “origin” node of the Composition.

When False, even if the ObjectiveMechanism is an origin node according to the structure of the graph, the ObjectiveMechanism is not marked as origin. If the ObjectiveMechanism was the only origin node, then the user must use required_roles to assign the origin role to another node.

When True, if the ObjectiveMechanism is an origin node according to the structure of the graph, it is treated normally. If the ObjectiveMechanism is not an origin node according to the structure of the graph, then it takes on origin as a required role.

terminal_objective_mechanism

Boolean – specifies whether the ObjectiveMechanism of a ControlMechanism may be a “terminal” node of the Composition.

When False, even if the ObjectiveMechanism is a terminal node according to the structure of the graph, the ObjectiveMechanism is not marked as terminal. If the ObjectiveMechanism was the only terminal node, then the user must use required_roles to assign the terminal role to another node.

When True, if the ObjectiveMechanism is a terminal node according to the structure of the graph, it is treated normally. If the ObjectiveMechanism is not a terminal node according to the structure of the graph, then it takes on terminal as a required role.

monitor_for_control

List[OutputState] – each item is an OutputState monitored by the ObjectiveMechanism listed in the ControlMechanism’s objective_mechanism attribute; it is the same as that ObjectiveMechanism’s monitored_output_states attribute (see ObjectiveMechanism_Monitored_Output_States for specification). The value of the OutputStates in the list are used by the ObjectiveMechanism to generate the ControlMechanism’s input.

monitored_output_states_weights_and_exponents

List[Tuple(float, float)] – each tuple in the list contains the weight and exponent associated with a corresponding OutputState specified in monitor_for_control; these are the same as those in the monitored_output_states_weights_and_exponents attribute of the objective_mechanism, and are used by the ObjectiveMechanism’s function to parametrize the contribution made to its output by each of the values that it monitors (see ObjectiveMechanism Function).

outcome

1d array – the value of the ControlMechanism’s primary InputState, which receives its Projection from the OUTCOME OutputState of its objective_mechanism.

function

TransferFunction : default Linear(slope=1, intercept=0) – determines how the value s of the OutputStates specified in the monitor_for_control argument of the ControlMechanism’s constructor are used to generate its control_allocation.

control_allocation

2d array – each item is the value assigned as the allocation for the corresponding ControlSignal listed in the control_signals attribute; the control_allocation is the same as the ControlMechanism’s value attribute).

control_signals

ContentAddressableList[ControlSignal] – list of the ControlSignals for the ControlMechanism, including any inherited from a system for which it is a controller (same as ControlMechanism’s output_states attribute); each sends a ControlProjection to the ParameterState for the parameter it controls

compute_reconfiguration_cost

Function, function or method – function used to compute the ControlMechanism’s reconfiguration_cost; result is a scalar value representing the difference — defined by the function — between the values of the ControlMechanism’s current and last control_alloction, that can be accessed by reconfiguration_cost attribute.

reconfiguration_cost

1d array – result of the ControlMechanism’s compute_reconfiguration_cost function.

costs

list – current costs for the ControlMechanism’s control_signals, computed for each using its compute_costs method.

combine_costs

Function, function or method – function used to combine the cost of its control_signals; result is an array with a scalar value that can be accessed by combined_costs.

Note

This function is distinct from the combine_costs_function of a ControlSignal. The latter combines the different costs for an individual ControlSignal to yield its overall cost; the ControlMechanism’s combine_costs function combines those costs for its control_signals.

combined_costs

1d array – result of the ControlMechanism’s combine_costs function.

compute_net_outcome

Function, function or method – function used to combine the values of its outcome and costs attributes; result is an array with a scalar value that can be accessed by the the net_outcome attribute.

net_outcome

1d array – result of the ControlMechanism’s compute_net_outcome function.

control_projections

List[ControlProjection] – list of ControlProjections, one for each ControlSignal in control_signals.

modulation

ModulationParam – the default form of modulation used by the ControlMechanism’s ControlSignals, unless they are individually specified.

name

str – the name of the ControlMechanism; if it is not specified in the name argument of the constructor, a default is assigned by MechanismRegistry (see Naming for conventions used for default and duplicate names).

prefs

PreferenceSet or specification dict – the PreferenceSet for the ControlMechanism; if it is not specified in the prefs argument of the constructor, a default is assigned using classPreferences defined in __init__.py (see PreferenceSet for details).

outputStateType

alias of ControlSignal

show()

Display the OutputStates monitored by ControlMechanism’s objective_mechanism and the parameters modulated by its control_signals.

add_monitored_output_states(monitored_output_states, context=None)

Instantiate OutputStates to be monitored by ControlMechanism’s objective_mechanism.

monitored_output_states can be any of the following:

If any item is a Mechanism, its primary OutputState is used. OutputStates must belong to Mechanisms in the same System as the ControlMechanism.

assign_as_controller(system: psyneulink.core.components.shellclasses.System_Base, context=<ContextFlags.COMMAND_LINE: 512>)

Assign ControlMechanism as controller for a System.

system must be a System for which the ControlMechanism should be assigned as the controller. If the specified System already has a controller, it will be replaced by the current one, and the current one will inherit any ControlSignals previously specified for the old controller or the System itself. If the current one is already the controller for another System, it will be disabled for that System.