Skip to content

Design patterns and principles

jdcpni edited this page Oct 1, 2016 · 1 revision

Functions:

 Everything is a function
 Every call (for both initialization and execution) has five standard arguments
 - variable (value):
     as an arg in __init__, formats and establishes a default for the variable
     as an arg in a function call, serves as the input to the function
 - params (dict):
     as an arg in __init__, instantiates and establishes instance-specific defaults for function parameters;
     as an arg in a function call, used to override instance defaults for that call only
 - name (str): used to the name the function:
     function names have three levels (separated by spaces):  category, class, and instance
     classes index default instance names or if an existing name is provided
 - prefs (dict):
     contains user PreferenceSet (settings and logging)
 - context (str):
     used to license initialization calls to abstract super classes (by legitimate subclasses)
 Every instance has an execute method, that is referenced either by params[FUNCTION] param OR self.execute
     this is the function that is called when executing the class to which the instance belongs:
     Process: executes the list of mechanisms in its configuration
     Mechanism:  executes the States instantiating its inputState, params, and outputState
     MechanismClass: executes each projection for which it is a receiver, and aggregates them if there are several
     Projection: translates the value of its sender and provides it for use as the value of its receiver
 Every subclass of function MUST either:
     - reference a function in paramClassDefauts[FUNCTION] OR
     - implement its own method that then MUST be called "execute" (i.e., <class>.execute);
     FUNCTION takes precedence (i.e., supercedes any subclass implementation of self.execute)
     FUNCTION can be either:
         a reference to an instantiated function, or
         a class of one (in this case, it will be instantiated using FUNCTION_PARAMS if provided)
     if a valid FUNCTION is instantiated, self.execute will be aliased to it
     if FUNCTION is missing or invalid, it will be assigned to self.execute
     if neither exists, an exception is raised
     NOTE:
         * As described above, the execute method of a class is referenced (and can be called) by both
            self.execute and self.paramsCurrent[FUNCTION]:
            - this is done for convenience (self.execute) and flexibility (self.paramsCurrent[FUNCTION])
            - when executing the function, it is generally safer and a best practice to call <instance>.function
 validate_* methods are called (usually in super.__init__) before any instantiate_* methods
     validate_* methods perform a (syntactic) check to:
         - determine if required items are present
         - deterimne if items are of the correct type relative to instance or class default
         - assign defaults where appropriate for invalid entries, with warning if in VERBOSE mode
         - NOT whether items are compatible with other entities (i.e., it is not a "semantic" check)
     instantiate_* methods perform a (semantic) check to:
         - determine if item is compatible with others
             (e.g., variable or output of one is compatible with value of another)

 self.variable is sometimes yoked/aliased to other attributes (for semantic reasons);  for example:
     variable -> value (for States)
              -> input (for Mechanism and Process)
 param values can, in some cases, be specified as numbers, but will be converted to a single-item list
         as the "lingua-franca" for variables
         (which they are, for the receiver's inputState function)

States and Projections:

 - Every mechanism has three types (subclasses) of State associated with it:
     - a single InputState:
          its value serves as the input to the mechanism
          it receives one or more Mapping Projections from other mechanisms
     - one or more ParameterStates:
         their values serve as the parameters of the mechanism's FUNCTION (self.execute),
         each of which receives typically one (but possibly more) ControlSignal projections
     - a single OutputState:
          its value serves as the output to the mechanism,
          and is typically assinged as the sender for other mechanisms' Mapping Projection(s)
 - State:
     every instance of State has a single value attribute (that represents its "state"; = self.variable)
     every instance of State must be explicitly assigned an existing <state>.owner (Mechanism)
     default projections can be implemented for a state (using <state>.defaultProjectionType);
         if their sender is not specified, a default one will be created (see Projection below)
     <state>.receivesFromProjections is consulted when a State's update function is executed,
         and <state>.value is updated based on those
     subclasses must implement defaultProjectionType
 - Projection:
     every projection must be explicitly assigned an existing <projection>.receiver (State)
     default states can be implemented for a projection's sender (using paramsCurrent[kwProjectionSender])
     subclasses must implement paramClassDefaults[kwProjectionSender]

 Mechcanisms and Projections are "receiver-oriented":
 - this the reason for the extra arg in __init__ for State () and Projection (receiver)

Value Compatibility Constraints and Equivalences:

 Constraints
     "x <: y [<module.method>]" indicates x constrains y (y must be (compatiable with) x value or type),
              implemented in module.method

     Main.iscompatible() is used to test for compatiblity

 1) Mechanism <: States
         a) self <: State.owner
             [Mechanism.instantiate_state]
         b) self.inputState.value (InputState value) <: self.variable (function variable)
             [Mechanism. instantiate_attributes_before_function /
             instantiate_input_states; InputState.validate_variable]
         c) self.paramsCurrent[param] <: ParameterState.value
             [Mechanism. instantiate_attributes_before_function  /
              instantiate_parameter_states]
         d) output of self.execute <: self.outputState.value (OutputState value)
             [Mechanism. instantiate_attributes_after_function/instantiate_output_states;
              OutputState.validate_variable]

 2) States value <: execute method
         Note: execute method simply updates value, so variable, output and value should all be compatible
         a) self.value <: self.variable (function variable)
             [InputState.validate_variable]
         b) if number of mechanism.inputStates > 1:
             number of mechanism.inputStates == length of self.variable
             [MechainsmState.instantiate_state_list]
         c) if number of mechanism.outputStates > 1:
             number of mechanism.outstates == length of self.value
             [MechainsmState.instantiate_state_list]

 3) States : Projections:
         Note: any incompatibilities between projection output and receiver value raises an
         exception that must be corrected by the user (since can't force a modification in
         projection's execute method)
         a) State <: projections.receiver;
             [Process.instantiate_configuration, State.instantiate_projection,
              Projection.validate_states, ControlSignal.assign_states, Mapping.assign_states]
        b) self.sender.value : self.variable (function variable)
            [Projection.instantiate_attributes_before_function / instantiate_sender]
        c) self.receiver.value = self.value
            [State.instantiate_projections_to_state, Projection.instantiate_function]

 Equivalences (implied from above constraints):
     == equal values
     ~ compatible values or types (depends on constraint);  values may not be equal
 a) State execute method variable ~ output ~ State value
      note: State execute methods serve as update functions,
            so input, output, and value should all be the same format;
            however, they may not be equivalent in value, depending upon the update states of the mechanism
 b) Mechanism execute method variable == InputState value
 c) InputState value ~ InputState execute method variable
 d) OutputState value == OutputState variable
 e) ParameterState value ~ ParameterState execute method variable

Parameters:

 paramClassDefaults:

     - Dictionary used to provide defaults for params of Function class and all of its subclasses
     - Subclasses should inherit super's paramClassDefaults, and their own
     - Entries added by one subclass should subclass-specific (i.e., not represented in sibling classes)
     - Subclasses should implement their copy of paramClassDefaults as follows:

      class SuperClass:
         paramClassDefaults = {<Parent’s defaults>}

     class SubClass(SuperClass):
         paramClassDefaults = SuperClass.paramClassDefaults.copy()
         paramClassDefaults.update({<SubClass additions>})

 #    - If a class requires a param to be implemented, it should enforce this in validate_params
     - If a class requires a param to be implemented, it should also include

 requiredParamClassDefaultTypes:

     - Dictionary used to specify params that are required for a given class and all subclasses
         and for which there is no default value to assign to paramClassDefaults
     - An exception is generated if a class fails to comply

     class SubClass(SuperClass):
         requiredParamClassDefaultTypes = SuperClass.requiredParamClassDefaultTypes.copy()
         requiredParamClassDefaultTypes.update({<required entries>})

 Parameter specification:
     - All Function objects have three sets of parameter values that determine how their execute method operates:
          + defaults defined for all parameters of the object's class, stored in paramClassDefaults (see above)
          + instance-specific values, stored in paramInstanceDefaults (if specified override paramClassDefaults)
          + current parameter values, stored in paramsCurrent, that are in effect for the current call to the object
     - Parameters are always specified as entries in a dict, with a:
          + key that identifies the parameter set
          + value that itself is a dict, the entries of which have a:
              key that identifies the param
              value that specifies the value to assign to the parmeter
          + example: kwInputStateParams:{<param_name>:value, <param_name>:value...}
     - Parameters can be specified:
         + on instantiation, in a dict passed as the params arg of the instantiation call:
             the value(s) of the param(s) specified will be assigned to paramInstanceDefaults
             they will override the value(s) in paramClassDefaults in all calls/references to the object
         + at runtime, in a dict passed as the params arg of the call to the object's execute method:
             they will override the value(s) in paramInstanceDefaults ONLY FOR THE CURRENT CALL to the object
             the value(s) in paramInstanceDefaults will be preserved, and used in subsequent calls
         + at runtime, in a dict passed as the second item of a (mechanism, params) in a configuration list:
             they will override the value(s) in paramInstanceDefaults ONLY FOR THE CURRENT CALL to the object
             the value(s) in paramInstanceDefaults will be preserved, and used in subsequent calls
             note: this can only be used for State and function params
     - As noted above, all params determine the operation of the object's execute method;
         + these are specified in a set identified by the keyword FUNCTION_PARAMS
         + this can be included as the entry of the dict:
             - in the params arg of a call to instantiate the object
             - in the params arg of a call to execute the object's method
             - in a (mechanism, params) tuple of a configuration list
                 in this case, the FUNCTION_PARAMS entry must be contained in a dict that specifies the type of
                 object for which the params should be used;  this can be one of the following:
                     kwInputStateParams:  will be used for the execute method of the mechanism's inputState(s)
                     kwOutputStateParams:  will be used for the execute method of the mechanism's outputState(s)
                     kwParameterStateParams: will be used for the parameters of the mechanism's execute method
                 FUNCTION_PARAMS can also be specified for projections to any of the states above, by including
                     FUNCTION_PARAMS as an entry in one of the following dicts, that itself must be included in
                     one of the kw<state_type>Params dicts listed above:
                         kwProjectionParams: will apply for all projections to the specified state_type
                         kwMappingParams: will apply only to Mapping projections for the specified state_type
                         kwControlSignalParams: will apply only to ControlSignal projections for the specified state_type
                         kwLearningSignalParams: will apply only to LearningSignal projections for the specified state_type
                         <projection_name>: will apply only to projections with the specified name for the state_type

Instantiation Sequence:

 Note: methods not implemented by subclass are shown in brackets (to see place in sequence)

 A) Function:
     1) Assign name
     2) Assign prefs
     3) Assign log
     4) Enforce implementation of variableClassDefault
     5) Enforce implementation of paramClassDefaults specified in requiredParamClassDefaultTypes
     5) assign_defaults
         a) validate_variable
             - get value from ParamValueProjection tuple
             - resolve function object or reference to current value
             - insure variable is compatible with variableClassDefault (if variableClassDefault_locked == True)
             - assign self.variable = variable
         b) assign missing params (if assign_missing == True)
         c) validate_params
             - checks that each param is listed in paramClassDefaults
             - checks that value is compatible with one in paramClassDefauts
     7) Set self.variable = variableInstanceDefault
     8) Set self.paramsCurrent = paramInstanceDefaults
     9) validate_function
         - checks for valid method reference in paramsCurrent, paramInstanceDefaults, paramClassDefaults, and
             finally self.execute;  if none present or valid, an exception is raised
     10) instantiate_attributes_before_function: stub for subclasses
     11) instantiate_function
         - instantiate params[FUNCTION] if present and assign to self.execute
         - else, instantiate self.execute; if it is not implemented, raise exception
         - call execute method to determine its output and type and assign to self.value
     12) instantiate_attributes_after_function: stub for subclasses

 B) Process:
     1) Assign name
     2) Register category
     3) Assign prefs
     4) Assign log
     5) super.__init__:
         a) instantiate_attributes_after_function
             i) instantiate_configuration:
                 CONFIGURATION:  must be a list of mechanism (object, class, or specification dict)
             ii) super.instantiate_function
     6) Set up log

 C) Mechanism:
     1) Validate that call is from subclass
     2) Assign name
     3) Register category
     4) Assign prefs
     5) Assign log
     6) super.__init__:
         a) validate_variable (for execute method)
             insure that it is a value, consistent with variableClassDefault if variableClassDefault_locked is set
         b) validate_params:
             kwTimeScale: must be TimeScale
             kwInputStates;  must be a list or ordered dict, each item/entry of which is a:
                 InputState or Projection object or class ref, specification dict for one,
                 ParamValueProjection, or numberic value(s)
             FUNCTION_PARAMS; must be a dict, each entry of which must be a:
                 ParameterState or Projection object or class, specification dict for one,
                 ParamProjection tuple, or a value compatible with paramInstanceDefaults
             kwOutputStates; must be a dict, each entry of which must be a:
                 InputState object or class, specification dict for one, or numeric value(s)
         [super: validate_function]
         c) instantiate_attributes_before_function
             i) instantiate_inputStates
                 - inputState.value must be compatible with mechanism's variable
                 - State.instantiate_states_list:
                     - assigns self.inputState (first/only state) and self.inputStates (OrderedDict of states)
                     - if number of inputStates > 1, must equal length of mechanism's variable
                         each state is assigned to an item of the mechanism's variable
                         if there is only one state, it is assigned to the full variable
             ii) instantiate_parameter_states
                 - assigns parameter state for each param in FUNCTION_PARAMS
         [super: instantiate_function]
         d) instantiate_attributes_after_function
             i) instantiate_outputStates - implement using kwOutputStates
                 - outputState.value must be compatible with output of mechanism's execute method
                 - State.instantiate_states_list:
                     - assigns self.outputState (first/only state) and self.outputStates (OrderedDict of states)
                     - if number of outputStates > 1, must equal length of output of mechanism's execute method
                         each state is assigned an item of the output of the mechanism's execute method
                         if there is only one state, full output of mechanism's execute method is assigned to it
     7) Enforce class methods

 D) State:
     1) Validate that call is from subclass
     2) Assign name
     3) Register category
     4) Assign prefs
     5) Assign log
     6) Assign owner
     7) super.__init__:
         a) validate_variable:
             insures that it is a number of list or tuple of numbers
             assigns self.value to self.variable
         b) validate_params:
             STATE_PROJECTIONS:
                 must be a Projection object or class, or specification dict for one
                 specification dict must have the following entries::
                     PROJECTION_TYPE:<Projection class>
                     kwProjectionParams:<dict> - params for PROJECTION_TYPE
         c) instantiate_function:
             insures that output of execute method is compatible with state's value
     8) instantiate_projections_to_state:
         - each must be a Projection class or object or a specification dict for one
         - insures output of projection execute method is compatible with state.value
         - insures receiver for each projection is state
         - if spec is not valid, default is created of type determined by paramsCurrent[PROJECTION_TYPE]
         - adds each to state.receivesFromProjections
     9) Assign observers

 E) Projection:
     1) Validate subclass
     2) Assign name
     3) Register category
     4) Assign prefs
     5) Assign log
     6) Assign self.sender to sender arg
     7) Assign self.receiver to receiver arg
     8) super.__init__:
         [super: validate_variable]
         a) validate_params:
             - kwProjectionSender and/or sender arg:
                 must be Mechanism or State
             - gives precedence to kwProjectionSender, then sender arg, then default
         [super: validate_function]
         b) instantiate_attributes_before_function:
             - calls instantiate_sender and instantiate_receiver (which both must be done before validate_function)
             i) instantiate_sender:
                 insures that projection's variable is compabitible with the output of the sender's execute method
                 if it is not, reassigns self.variable
             ii) instantiate_receiver:
                 assigns (reference to) receiver's inputState to projection's receiver attribute
         c) instantiate_function:
             insures that output of projection's execute method is compatible with receiver's value
             (it if it is a number of len=1, it tries modifying the output of execute method to match receiver)
             checks if FUNCTION is specified, then if self.execute implemented; raises exception if neither
         [super: instantiate_attributes_after_function]
         
      E.1) LearningSignal:  
         1) Assign name
         2) super.__init__:
             a) Assign self.sender to sender arg
             b) Assign self.receiver to receiver arg
             [super: validate_variable]
             c) validate_params:
                 super():
                     - assign self.sender to sender arg or params[kwProjectionSender]
                     - gives precedence to kwProjectionSender, then sender arg, then paramClassDefaults
                     - validate that self.sender is Mechanism or State
                 LearningSignal:
                     - validate that self.sender is OutputState of MonitoringMechanism or ProcessingMechanism
                         or MonitoringMechanism class ref (assigned by paramClassDefaults)

                     ** DOCUMENT ??? GET kwParameterStates OR SET TO None?? 


             [super: validate_function]
             d) instantiate_attributes_before_function:
                 - calls instantiate_receiver and instantiate_sender (which both must be done before validate_function)
                     * instantiate_receiver must be called before instantiate_sender since the latter requires access to
                         self.receiver to determine whether to use a comparator mechanism or <Mapping>.receiverError for error signals
                 i) instantiate_receiver:
                     * doesn't call super() since that assumes self.receiver.owner is a Mechanism and calls add_projection_to_mechanism

    """Instantiate and/or assign the parameterState of the projection to be modified by learning

    If receiver is specified as a Mapping Projection, it is assigned to parameterStates[kwWeightMatrix]
        for the projection;  if that does not exist, it is instantiated and assigned as the receiver
    If specified as a ParameterState, validate that it is parameterStates[kwWeightMatrix]
    Validate that the LearningSignal's error matrix is the same shape as the recevier's weight matrix
    
    Note:
    * This must be called before instantiate_sender since that requires access to self.receiver
        to determine whether to use a comparator mechanism or <Mapping>.receiverError for error signals
    * Doesn't call super().instantiate_receiver since that assumes self.receiver.owner is a Mechanism
                          and calls add_projection_to_mechanism

                 ii) instantiate_sender:

                     insures that projection's variable is compabitible with the output of the sender's execute method
                     if it is not, reassigns self.variable
                     
    """Assign self.variable to MonitoringMechanism output or self.receiver.receiverErrorSignals 
    
    Call this after instantiate_receiver, as the latter may be needed to identify the MonitoringMechanism
    
    If sender arg or kwProjectionSender was specified, it has been assigned to self.sender
        and has been validated as a MonitoringMechanism, so:
        - validate that the length of its outputState.value is the same as the width (# columns) of MATRIX 
        - assign its outputState.value as self.variable
    If sender was not specified (remains MonitoringMechanism_Base as specified in paramClassDefaults):
       if the owner of the Mapping projection projects to a MonitoringMechanism, then
           - validate that the length of its outputState.value is the same as the width (# columns) of MATRIX 
           - assign its outputState.value as self.variable
       otherwise, if self.receiver.owner has an receiverError attribute, as that as self.variable
           (error signal for hidden units by BackPropagation Function)
       [TBI: otherwise, implement default MonitoringMechanism]
       otherwise, raise exception
                     
                     

             e) instantiate_function:
                 insures that output of projection's execute method is compatible with receiver's value
                 (it if it is a number of len=1, it tries modifying the output of execute method to match receiver)
                 checks if FUNCTION is specified, then if self.execute implemented; raises exception if neither
             [super: instantiate_attributes_after_function]

Execution Sequence:

 - Process.execute calls mechanism.update for each mechanism in its configuration in sequence
     - input specified as arg in execution of Process is provided as input to the first mechanism in configuration
     - output of last mechanism in configuration is assigned as Process.ouputState.value
     - DefaultController is executed before execution of each mechanism in the configuration
     - notes:
         * the same mechanism can be listed more than once in a configuration, inducing recurrent processing
         * if it is the first mechanism, it will receive its input from the Process only once (first execution)
 - Mechanism.update_states_and_execute:
     [TBI: calls each of the execute methods in its executionSequence (see Mechanism.execute):
     - calls self.inputState.update() for each entry in self.inputStates, which:
         + executes every self.inputState.receivesFromProjections.[<Projection>.execute()...]
             note:  for the first mechanism in the configuration, this includes a projection with Process input
         + aggregates them using self.inputState.params[FUNCTION]()
         + applies any runtime kwMechansimInputStateParams specified with mechanism in a tuple in the configuration
         + stores result in self.inputState.value
     - calls self.update_parameter_states, which calls every self.params[<ParameterState>].execute(),
         each of which:
         + executes self.params[<ParameterState>].receivesFromProjections.[<Projection>.execute()...]
             (usually this absent, or is a single ControlSignal projection from DefaultController)
             with any runtime kwMechansimParameterStateParams specified with mechanism in tupel in configuration
         + aggregates results using self.params[<ParameterState>].params[FUNCTION]()
         + applies the result to self.params[<ParameterState>].baseValue
             using self.params[<ParameterState>].paramsCurrent[kwParamModulationOperation] or runtime spec
     - calls subclass' self.update, which:
         + uses for each item of its variable the value of the corresponding state in mechanism's self.inputStates
         + uses self.params[<ParameterState>].value for each corresponding param of subclass' execute method
         + calls mechanism.execute method that carries out mechanism-specific computations
         + assigns each item of its output as the value of the corresponding state in mechanisms's self.outputStates
     - [TBI: calls self.outputState.execute() (output gating) to update self.outputState.value]

Preferences:

 DOCUMENT: ADD DETAILS TO PREF DESCRIPTIONS BELOW
     - PreferenceSets:
         Each object has a prefs attribute that is assigned a PreferenceSet object specifying its preferences
         Preference objects have a set of preference attributes, one for each preference
         In addition to objects, every class in the Function hierarchy is assigned a:
         + PreferenceLevel: used to specify preferences for objects at that class level and below
         + PreferenceSet: preference settings for the corresponding level of specification (see PreferenceLevels below)

 - Standard preferences:
     Function objects and Mechanism subclass objects have the following preferences:
     Format:  pref_name (type): [Class]
     * note: "Class" refers to the class (and all subclasses) for which the preference is defined

     + verbose_pref (bool):  [Function]
         determines whether non-execute-related actions (e.g., initialization) and non-fatal warnings are reported

     + paramValidation_pref (bool):  [Function]
         determines whether the parameters of an object's execute method are validated prior to execution

     + reportOutput_pref (bool):  [Function]
         determines whether output of execute-related actions is reported to the console (see Process and Mechanism)

     + log_pref (LogPreferences): [Function]
         determines whether activity of the object is recorded in its log (see Logging)

     + functionRuntimeParams_pref (ModulationOperation): [Mechanism]
         determines whether and, if so, how parameters passed to a mechanism at runtime influence its execution

 - PreferenceEntry:
     Each attribute of a PreferenceSet is a PreferenceEntry(setting, level) tuple:
     + setting (value):
         specifies the value of the preference, which must be of the type noted above
     + level (PreferenceLevel):
         specifies the level that will be used to determine that setting
         specifying a given level causes the value assigned at that level to be returned
         when a request is made for the value of the preference for that PreferenceSet

 - PreferenceLevels:
     There are four PreferenceLevels defined for the Function hierarchy:
     + System:  reserved for the Function class
     + Category: primary function subclasses (e.g., Process, Mechanism, State, Projection, Utility)
     + Type: Category subclasses (e.g., Mapping and ControlSignal subclasses of Projection, Utility subclasses)
     + Instance: an instance of an object of any class

 - Setting preferences:
     + Preferences settings can be assigned individually or in a PreferenceSet
         when instantiating or executing an object using the prefs arg, which can be:
         - a PreferenceSet, or
         - a specification dict with entries for each of the preferences to be set; for each entry the:
             key must be a keyPath for a preference attribute
                 (kpVerbose, kpParamValidation, kpReportOutput, kpLog, kpFunctionRuntimeParams)
             value must be one of the following:
                 a PreferenceEntry(setting, level) tuple
                 a value that is valid for the setting of the corresponding attribute
                 a PreferenceLevel specification
     + a PreferenceSet can also be assigned directly to the preferences attirbute of an object or a class:
         <Object>.prefs = <PreferenceSet>
         <Class>.classPreferences = <PreferenceSet>
            Note:  if an assignment is made to a class, the class must be provided as the owner arg
                   in the call to instantiate the class (e.g.: my_pref_set = PreferenceSet(... owner=class... );
                   otherwise, an error will occur whenever the settings for the PreferenceSet are accessed
                   This is not required for objects; the owner of an object is determined automatically on assignment

     [TBI: + when specifying a configuration, in a (mechanism, params) tuple;  params must have:]

 - Show preferences:
     + Preferences for an object or class can be displayed by using inspect() method of a PreferenceSet:
         <object>.prefs.inspect(type) or <class>.classPreferences.inspect(type);
         both the base and current values of the setting are shown
         Note: these can be different if the PreferenceLevel is set to a value other than:
            INSTANCE for an object
            <class>.classLevel for a class

Defaults:

 - System-wide:
     #Identifier (kwXXX):           # Class:                                 #Object:
     [TBI: SystemDefaultSender                                               ProcessDefaultInput]
     [TBI: SystemDefaultReceiver                                             ProcessDefaultOutput]
     kwDefaultProcessingMechanism       DefaultProcessingMechanism_Base              DefaultProcessingMechanism (in __init__.py)
     kwProcessDefaultMechanism      defaultMechanism (in Mechanism_Base)     Mechanism_Base.defaultMechanism
     kwSystemDefaultController      DefaultControlMechanism            DefaultController(in __init__.py)

 - Process:
     Single Default Mechanism (DDM)

 - Mechanism:
     DDM:
         InputState:
             projections:
                 Mapping
                     sender: SystemDefaultSender
         OutputState:
             [TBI: sender for projection to SystemDefaultReceiver]

 - State:
     ParameterState
         Projection:
             ControlSignal
                 sender:  DefaultController)