# Log¶

## Overview¶

A Log object is used to record the value of PsyNeuLink Components during their “life cycle” (i.e., when they are created, validated, and/or executed). Every Component has a Log object, assigned to its log attribute when the Component is created, that can be used to record its value and/or that of other Components that belong to it. These are stored in entries of the Log, that contain a sequential list of the recorded values, along with the time and context of the recording. The conditions under which values are recorded is specified by the logPref property of a Component. While these can be set directly, they are most easily specified using the Log’s set_log_conditions method, together with its loggable_items and logged_items attributes that identify and track the items to be logged, respectively. Entries can also be made by the user programmatically, using the log_values method. Logging can be useful not only for observing the behavior of a Component in a model, but also in debugging the model during construction. The entries of a Log can be displayed in a “human readable” table using its print_entries method, and returned in CSV and numpy array formats using its and nparray, nparray_dictionary and csv methods.

## Creating Logs and Entries¶

A log object is automatically created for and assigned to a Component’s log attribute when the Component is created. An entry is automatically created and added to the Log’s entries attribute when its value or that of a Component that belongs to it is recorded in the Log.

## Structure¶

A Log is composed of entries, each of which is a dictionary that maintains a record of the logged values of a Component. The key for each entry is a string that is the name of the Component, and its value is a list of LogEntry tuples recording its values. Each LogEntry tuple has three items:

The time is recorded only if the Component is executed within a System; otherwise, the time field is None.

A Log has several attributes and methods that make it easy to manage how and when it values are recorded, and to access its entries:

• set_log_conditions – used to assign the condition for logging one or more Components. Components can be specified by their names, a reference to the Component object, in a tuple that specifies the condition(s) for logging that Component, or in a list with a condition to be assigned to multiple items at once.

### Loggable Items¶

Although every Component is assigned its own Log, that records the value of that Component, the Logs for Mechanisms and MappingProjections also provide access to and control the Logs of their States. Specifically the Logs of these Components contain the following information:

### Logging Conditions¶

Configuring a Component to be logged is done using a condition, that specifies a LogCondition under which its value should be entered in its Log. These can be specified in the set_log_conditions method of a Log, or directly by specifying a LogCondition for the value a Component’s logPref item of its prefs attribute. The former is easier, and allows multiple Components to be specied at once, while the latter affords more control over the specification (see Preferences). LogConditions are treated as binary “flags”, and can be combined to permit logging under more than one condition using bitwise operators on the LogConditions. For convenience, they can also be referred to by their names, and combined by specifying a list. For example, all of the following specify that the value of my_mech be logged both during execution and learning:

>>> import psyneulink as pnl
>>> my_mech = pnl.TransferMechanism()
>>> my_mech.set_log_conditions('value', pnl.LogCondition.EXECUTION | pnl.LogCondition.LEARNING)
>>> my_mech.set_log_conditions('value', pnl.LogCondition.EXECUTION + pnl.LogCondition.LEARNING)
>>> my_mech.set_log_conditions('value', [pnl.EXECUTION, LEARNING])


Note

Currently, the VALIDATION LogCondition is not implemented.

Note

Using LogCondition.INITIALIZATION to log the value of a Component during its initialization requires that it be assigned in the prefs argument of the Component’s constructor. For example:

>>> my_mech = pnl.TransferMechanism(
...        prefs={pnl.LOG_PREF: pnl.PreferenceEntry(pnl.LogCondition.INITIALIZATION, pnl.PreferenceLevel.INSTANCE)})


Hint

LogCondition.TRIAL logs the value of a Component at the end of a TRIAL. To log its value at the start of a TRIAL, use its log_values method in the call_before_trial argument of the System’s run method.

## Execution¶

The value of a Component is recorded to a Log when the condition assigned to its logPref is met. This is specified as a LogCondition or a boolean combination of them (see Logging Conditions). The default LogCondition is OFF.

Examples

The following example creates a Process with two TransferMechanisms, one that projects to another, and logs the noise and RESULTS OutputState of the first and the MappingProjection from the first to the second:

# Create a Process with two TransferMechanisms, and get a reference for the Projection created between them:
>>> my_mech_A = pnl.TransferMechanism(name='mech_A', size=2)
>>> my_mech_B = pnl.TransferMechanism(name='mech_B', size=3)
>>> my_process = pnl.Process(pathway=[my_mech_A, my_mech_B])
>>> my_system = pnl.System(processes=[my_process])
>>> proj_A_to_B = my_mech_B.path_afferents[0]

# Show the loggable items (and current condition assignments) for each Mechanism and the Projection between them:
>> my_mech_A.loggable_items
{'InputState-0': 'OFF', 'slope': 'OFF', 'RESULTS': 'OFF', 'integration_rate': 'OFF', 'intercept': 'OFF', 'noise': 'OFF'}
>> my_mech_B.loggable_items
{'InputState-0': 'OFF', 'slope': 'OFF', 'RESULTS': 'OFF', 'intercept': 'OFF', 'noise': 'OFF', 'integration_rate': 'OFF'}
>> proj_A_to_B.loggable_items
{'value': 'OFF', 'matrix': 'OFF'}

# Assign the noise parameter and RESULTS OutputState of my_mech_A, and the matrix of the Projection, to be logged
>>> my_mech_A.set_log_conditions([pnl.NOISE, pnl.RESULTS])
>>> proj_A_to_B.set_log_conditions(pnl.MATRIX)


Note that since no condition was specified, the default (LogCondition.EXECUTION) is used. Executing the Process generates entries in the Logs, that can then be displayed in several ways:

# Execute the System twice (to generate some values in the logs):
>> my_system.execute()
[array([ 0.,  0.,  0.])]
>> my_system.execute()
[array([ 0.,  0.,  0.])]

# List the items of each Mechanism and the Projection that were actually logged:
>> my_mech_A.logged_items
{'RESULTS': 'EXECUTION', 'noise': 'EXECUTION'}
>> my_mech_B.logged_items
{}
>> proj_A_to_B.logged_items
{'matrix': 'EXECUTION'}


Notice that entries dictionary of the Log for my_mech_B is empty, since no items were specified to be logged for it. The results of the two other logs can be printed to the console using the print_entries method of a Log:

# Print the Log for my_mech_A:
>> my_mech_A.log.print_entries()

Log for mech_A:

Logged Item:   Time       Context                                                                   Value

'RESULTS'      0:0:0     " EXECUTING  System System-0| Mechanism: mech_A [in processes: ['Pro..."   [ 0.  0.]
'RESULTS'      0:1:0     " EXECUTING  System System-0| Mechanism: mech_A [in processes: ['Pro..."   [ 0.  0.]

'noise'        0:0:0     " EXECUTING  System System-0| Mechanism: mech_A [in processes: ['Pro..."   [ 0.]
'noise'        0:1:0     " EXECUTING  System System-0| Mechanism: mech_A [in processes: ['Pro..."   [ 0.]


They can also be exported in numpy array and CSV formats. The following shows the CSV-formatted output of the Logs for my_mech_A and proj_A_to_B, using different formatting options:

>> print(my_mech_A.log.csv(entries=[pnl.NOISE, pnl.RESULTS], owner_name=False, quotes=None))
'Run', 'Trial', 'Time_step', 'noise', 'RESULTS'
0, 0, 0, 0.0, 0.0 0.0
0, 1, 0, 0.0, 0.0 0.0

# Display the csv formatted entry of Log for proj_A_to_B
#    with quotes around values and the Projection's name included in the header:
>> print(proj_A_to_B.log.csv(entries=pnl.MATRIX, owner_name=False, quotes=True))
'Run', 'Trial', 'Time_step', 'matrix'
'0', '0', '1', '1.0 1.0 1.0' '1.0 1.0 1.0'
'0', '1', '1', '1.0 1.0 1.0' '1.0 1.0 1.0'


Note that since the name attribute of the Projection was not assigned, its default name is reported.

The following shows the Log of proj_A_to_B in numpy array format, with and without header information:

>> proj_A_to_B.log.nparray(entries=[pnl.MATRIX], owner_name=False, header=True)
[[['Run'] [0] [0]]
[['Trial'] [0] [1]]
[['Time_step'] [1] [1]]
['matrix' [[1.0, 1.0, 1.0], [1.0, 1.0, 1.0]] [[1.0, 1.0, 1.0], [1.0, 1.0, 1.0]]]]

[[[0] [0]]
[[0] [1]]
[[1] [1]]
[[[1.0, 1.0, 1.0], [1.0, 1.0, 1.0]] [[1.0, 1.0, 1.0], [1.0, 1.0, 1.0]]]]


## Class Reference¶

class psyneulink.globals.log.LogCondition

Used to specify the context in which a value of the Component or its attribute is logged.

Note

The values of LogCondition are subset of (and directly reference) the ContextFlags bitwise enum, with the exception of TRIAL and RUN, which are bit-shifted to follow the ContextFlags.SIMULATION value.

INITIALIZATION = 16

Set during execution of the Component’s constructor.

VALIDATION = 8

Set during validation of the value of a Component or its attribute.

EXECUTION = 480

Set during all phases of execution of the Component.

PROCESSING = 32

Set during the processing phase of execution of a Composition.

LEARNING = 64

Set during the learning phase of execution of a Composition.

CONTROL = 128

Set during the control phase System_Execution_Control> of execution of a Composition.

TRIAL = 512

Set at the end of a TRIAL.

RUN = 1024

Set at the end of a RUN.

ALL_ASSIGNMENTS = 504

Specifies all contexts.

class psyneulink.globals.log.Log(owner, entries=None)

Maintain a Log for an object, which contains a dictionary of logged value(s).

owner

Component – the Component to which the Log belongs (and assigned as its log attribute).

loggable_components

ContentAddressableList – each item is a Component that is loggable for the Log’s owner

loggable_items

Dict[Component.name: List[LogEntry]] – identifies Components that can be logged by the owner; the key of each entry is the name of a Component, and the value is its currently assigned LogCondition.

entries

Dict[Component.name: List[LogEntry]] – contains the logged information for loggable_components; the key of each entry is the name of a Component, and its value is a list of LogEntry items for that Component. Only Components for which information has been logged appear in the entries dict.

logged_items

Dict[Component.name: List[LogEntry]] – identifies Components that currently have entries in the Log; the key for each entry is the name of a Component, and the value is its currently assigned LogCondition.

set_log_conditions(items, log_condition=<LogCondition.EXECUTION: 480>)

Specifies items to be logged under the specified LogCondition(s).

Parameters: items (str, Component, tuple or List of these) – specifies items to be logged; these must be be loggable_items of the Log. Each item must be a: * string that is the name of a loggable_item  of the Log’s owner; * a reference to a Component; * tuple, the first item of which is one of the above, and the second a ContextFlags to use for the item. log_condition (LogCondition : default LogCondition.EXECUTION) – specifies LogCondition to use as the default for items not specified in tuples (see above). For convenience, the name of a LogCondition can be used in place of its full specification (e.g., EXECUTION instead of LogCondition.EXECUTION). params_set (list : default None) – list of parameters to include as loggable items; these must be attributes of the owner (for example, Mechanism
log_values(entries)

Log the value of one or more Components programmatically.

This can be used to “manually” enter the value of any of a Component’s loggable_items (including its own value) in its log. The context item of its LogEntry is assigned COMMAND_LINE. If the call to log_values is made while a System to which the Component belongs is being run (e.g., in a call_before.. or call_after… argument of its run method), then the time of the LogEntry is assigned the value of the Clock of the System’s scheduler_processing or scheduler_learning, whichever is currently executing (see Scheduler).

Parameters: entries (string, Component or list containing either : default ALL) – specifies the Components, the current values of which should be added to the Log. they must be loggable_items of the owner’s Log. If entries is ALL or is not specified, then the values of all loggable_items are logged.
clear_entries(entries='all', delete_entry=True, confirm=False)

Clear one or more entries either by deleting the entry or just removing its data.

Parameters: entries (string, Component or list containing either : default ALL) – specifies the entries of the Log to be cleared; they must be loggable_items of the Log that have been logged (i.e., are also logged_items). If entries is ALL or is not specified, then all logged_items are cleared. delete_entry (bool : default True) – specifies whether to delete the entry (if True) from the log to which it belongs, or just delete the data, but leave the entry itself (if False). Note This option is included for generality and potential future features, but is not advised; the Log interface (e.g., the logged_items interface generally assumes that the only entries in a log are ones with data. confirm (bool : default False) – specifies whether user confirmation is required before clearing the entries. Note If confirm is True, only a single confirmation will occur for a list or ALL
print_entries(entries=ALL, width=120, display=None)

Print summary of the Log’s entries in a (human-readable) table format.

Parameters: entries (string, Component or list containing either : default ALL) – specifies the entries of the Log to printed; they must be loggable_items of the Log that have been logged (i.e., are also logged_items). If entries is ALL or is not specified, then all logged_items are printed. width (int : default 120) – specifies the width of the display. The widths of each column are adjusted accordingly, and based on which items are displayed (see display below); information that does not fit within its column’s width is truncated and suffixes with an ellipsis. display (TIME, CONTEXT, VALUE, a list containing any of these, or ALL : default ALL) – specifies the information items to display. The name of the entry is always displayed, followed by the specified items; the widths of the columns for the items is dynamically adjusted, based on how many are specified, allowing more information about one to be shown by omitting others (this is useful if the context strings are long and/or the values are arrays).
nparray(entries=None, header:bool=True, owner_name=False):)

Return a 2d numpy array with headers (optional) and values for the specified entries.

Each row (axis 0) is a time series, with each item in each row the data for the corresponding time point. Rows are ordered in the same order as Components are specified in the entries argument.

If all of the data for every entry has a time value (i.e., the time field of its LogEntry is not None), then the first four rows are time indices for the run, trial, pass, and time_step of each data item, respectively. Each subsequent row is the times series of data for a given entry. If there is no data for a given entry at a given time point, it is entered as None.

If any of the data for any entry does not have a time value (e.g., if that Component was not run within a System), then all of the entries must have the same number of data (LogEntry) items, and the first row is a sequential index (starting with 0) that simply designates the data item number.

Note

For data without time stamps, the nth items in each entry correspond (i.e., ones in the same column) are not guaranteed to have been logged at the same time point.

If header is True, the first item of each row is a header field: for time indices it is either “Run”, “Trial”, and “Time_step”, or “Index” if any data are missing time stamps. For subsequent rows it is the name of the Component logged in that entry (see owner_name argument below for formatting).

Parameters: entries (string, Component or list containing either : default ALL) – specifies the entries of the Log to be included in the output; they must be loggable_items of the Log that have been logged (i.e., are also logged_items). If entries is ALL or is not specified, then all logged_items are included. header (bool : default True) – specifies whether or not to include a header in each row with the name of the Component for that entry. owner_name (bool : default False) – specifies whether or not to include the Log’s owner in the header of each field; if it is True, the format of the header for each field is “[]”; otherwise, it is “”. Returns – 2d np.array
nparray_dictionary(entries=None)

Returns an OrderedDict

Keys:

Keys of the OrderedDict are strings.

Keys are the names of logged Components specified in the entries argument, plus either Run, Trial, Pass, and Time_step, or Index.

If all of the data for every entry has a time value (i.e., the time field of its LogEntry is not None), then the first four keys are Run, Trial, Pass, and Time_step, respectively.

If any of the data for any entry does not have a time value (e.g., if that Component was not run within a System), then all of the entries must have the same number of data (LogEntry) items, and the first key is Index.

Then, the logged components follow in the same order as they were specified.

Values:

Values of the OrderedDict are numpy arrays.

The numpy array value for a given component key consists of that logged Component’s data over many time points or executions.

The numpy array values for Run, Trial, Pass, and Time_step are counters for each of those time scales. The ith elements of the Run, Trial, Pass, Time_step and component data arrays can be taken together to represent the value of that component during a particular time step of a particular trial of a particular run.

For example, if log_dict is a log dictionary in which log_dict[‘slope’][5] = 2.0, log_dict[‘Time_step’][5] = 1, log_dict[‘Pass’][5] = 0, log_dict[‘Trial’][5] = 2, and log_dict[‘Run’][5] = 0, then the value of slope was 2.0 during time step 1 of pass 0 of trial 2 of run 0. If there is no data for a given entry at a given time point, it is entered as None.

The numpy array value for Index is a sequential index starting at zero.

Note

For data without time stamps, the nth item in each dictionary key (i.e., data in the same “column”) is not guaranteed to have been logged at the same time point across all keys (Components).

Parameters: entries (string, Component or list containing either : default ALL) – specifies the entries of the Log to be included in the output; they must be loggable_items of the Log that have been logged (i.e., are also logged_items). If entries is ALL or is not specified, then all logged_items are included. Returns – 2d np.array
csv(entries=None, owner_name=False, quotes="'")

Returns a CSV-formatted string with headers and values for the specified entries.

Each row (axis 0) is a time point, beginning with the time stamp and followed by the data for each Component at that time point, in the order they are specified in the entries argument. If all of the data for every Component have time values, then the first four items of each row are the time indices for the run, trial, pass, and time_step of that time point, respectively, followed by the data for each Component at that time point; if a Component has no data for a time point, None is entered.

If any of the data for any Component does not have a time value (i.e., it has None in the time field of its LogEntry) then all of the entries must have the same number of data (LogEntry) items, and the first item of each row is a sequential index (starting with 0) that designates the data item number.

Note

For data without time stamps, items in the same row are not guaranteed to refer to the same time point.

The owner_name argument can be used to prepend the header for each Component with its owner. The quotes argument can be used to suppress or specifiy quotes to use around numeric values.

Parameters: entries (string, Component or list containing either : default ALL) – specifies the entries of the Log to be included in the output; they must be loggable_items of the Log that have been logged (i.e., are also logged_items). If entries is ALL or is not specified, then all logged_items are included. owner_name (bool : default False) – specifies whether or not to include the Component’s owner in the header of each field; if it is True, the format of the header for each field is “[]”; otherwise, it is “”. quotes (bool, str : default ') – specifies whether or not to enclose numeric values in quotes (may be useful for arrays); if not specified or True, single quotes are used for all items; if specified with a string, that is used in place of single quotes to enclose all items; if False or None, single quotes are used for headers (the items in the first row), but no others. Returns – CSV-formatted string
loggable_items

Return dict of loggable items.

Keys are names of the Components, values their ContextStates

loggable_components

Return a list of owner’s Components that are loggable

The loggable items of a Component are the Components (typically States) specified in the _logagble_items property of its class, and its own value attribute.

logged_items

Dict of items that have logged entries, indicating their specified ContextFlags`.