System Model Configuration == #### Introduction Given System Model Configurations, cadCAD produces system event datasets that conform to specified system metrics. Each event / record is of [Enogenous State variables](link) produced by user defined [Partial State Updates](link) (PSU / functions that update state); A sequence of event / record subsets that comprises the resulting system event dataset is produced by a [Partial State Update Block](link) (PSUB / a Tensor Field for which State, Policy, and Time are dimensions and PSU functions are values). A **System Model Configuration** is comprised of a simulation configuration, initial endogenous states, Partial State Update Blocks, environmental process, and a user defined policy aggregation function. Execution: #### Simulation Properties ###### System Metrics The following system metrics determine the size of resulting system event datasets: * `run` - the number of simulations in the resulting dataset * `timestep` - the number of timestamps in the resulting dataset * `substep` - the number of PSUs per `timestep` / within PSUBS * Number of events / records: `run` x `timestep` x `substep` ###### Simulation Configuration For the following dictionary, `T` is assigned a `timestep` range, `N` is assigned the number of simulation runs, and `params` is assigned the [**Parameter Sweep**](link) dictionary. ```python from cadCAD.configuration.utils import config_sim sim_config = config_sim({ "N": 2, "T": range(5), "M": params, # Optional }) ``` #### Initial Endogenous States **Enogenous State variables** are read-only variables defined to capture the shape and property of the network and represent internal input and signal. The PSUB tensor field is applied to the following states to produce a resulting system event dataset. ```python genesis_states = { 's1': 0.0, 's2': 0.0, 's3': 1.0, 'timestamp': '2018-10-01 15:16:24' } ``` #### Partial State Update Block: - ***Partial State Update Block(PSUB)*** ***(Define ?)*** Tensor Field for which State, Policy, Time are dimensions and Partial State Update functions are values. - ***Partial State Update (PSU)*** are user defined functions that encodes state updates and are executed in a specified order PSUBs. PSUs update states given the most recent set of states and PSU policies. - ***Mechanism*** ***(Define)*** The PSUBs is a list of PSU dictionaries of the structure within the code block below. PSUB elements (PSU dictionaries) are listed / defined in order of `substeps` and **identity functions** (returning a previous state's value) are assigned to unreferenced states within PSUs. The number of records produced produced per `timestep` is the number of `substeps`. ```python partial_state_update_block = [ { "policies": { "b1": p1_psu1, "b2": p2_psu1 }, "variables": { "s1": s1_psu1, "s2": s2_psu1 } }, { "policies": { "b1": p1_psu2, }, "variables": { "s2": s2_psu2 } }, {...} ] ``` *Notes:* 1. An identity function (returning the previous state value) is assigned to `s1` in the second PSU. 2. Currently the only names that need not correspond to the convention below are `'b1'` and `'b2'`. #### Policies - ***Policies*** ***(Define)*** When are policies behavior ? - ***Behaviors*** model agent behaviors in reaction to state variables and exogenous variables. The resulted user action will become an input to PSUs. Note that user behaviors should not directly update value of state variables. Policies accept parameter sweep variables [see link] `_g` (`dict`), the most recent `substep` integer, the state history[see link] (`sH`), the most recent state record `s` (`dict) as inputs and returns a set of actions (`dict`). Policy functions return dictionaries as actions. Policy functions provide access to parameter sweep variables [see link] via dictionary `_g`. ```python def p1_psu1(_g, substep, sH, s): return {'policy1': 1} def p2_psu1(_g, substep, sH, s): return {'policy1': 1, 'policy2': 4} ``` For each PSU, multiple policy dictionaries are aggregated into a single dictionary to be imputted into all state functions using an initial reduction function (default: `lambda a, b: a + b`) and optional subsequent map functions. Example Result: `{'policy1': 2, 'policy2': 4}` #### State Updates State update functions provide access to parameter sweep variables [see link] `_g` (`dict`), the most recent `substep` integer, the state history[see link] (`sH`), the most recent state record as a dictionary (`s`), the policies of a PSU (`_input`), and returns a tuple of the state variable's name and the resulting new value of the variable. ```python def state_update(_g, substep, sH, s, _input): ... return state, update ``` **Note:** Each state update function updates one state variable at a time. Changes to multiple state variables requires separate state update functions. A generic example of a PSU is as follows. * ##### Endogenous State Updates They are only updated by PSUs and can be used as inputs to a PSUs. ```python def s1_update(_g, substep, sH, s, _input): x = _input['policy1'] + 1 return 's1', x def s2_update(_g, substep, sH, s, _input): x = _input['policy2'] return 's2', x ``` * ##### Exogenous State Updates ***Exogenous State variables*** ***(Review)*** are read-only variables that represent external input and signal. They update endogenous states and are only updated by environmental processes. Exgoneous variables can be used as an input to a PSU that impacts state variables. ***(Expand upon Exogenous state updates)*** ```python from datetime import timedelta from cadCAD.configuration.utils import time_step def es3_update(_g, substep, sH, s, _input): x = ... return 's3' def es4_update(_g, substep, sH, s, _input): x = ... return 's4', x def update_timestamp(_g, substep, sH, s, _input): x = time_step(dt_str=s[y], dt_format='%Y-%m-%d %H:%M:%S', _timedelta=timedelta(days=0, minutes=0, seconds=1)) return 'timestamp', x ``` Exogenous state update functions (`es3_update`, `es4_update` and `es5_update`) update once per timestamp and should be included as a part of the first PSU in the PSUB. ```python partial_state_update_block['psu1']['variables']['s3'] = es3_update partial_state_update_block['psu1']['variables']['s4'] = es4_update partial_state_update_block['psu1']['variables']['timestamp'] = update_timestamp ``` * #### Environmental Process - ***Environmental processes*** model external changes that directly impact exogenous states at given specific conditions such as market shocks at specific timestamps. Create a dictionary like `env_processes` below for which the keys are exogenous states and the values are lists of user defined **Environment Update** functions to be composed (e.g. `[f(params, x), g(params, x)]` becomes `f(params, g(params, x))`). Environment Updates accept the [**Parameter Sweep**](link) dictionary `params` and a state as a result of a PSU. ```python def env_update(params, state): . . . return updated_state # OR env_update = lambda params, state: state + 5 ``` The `env_trigger` function is used to apply composed environment update functions to a list of specific exogenous state update results. `env_trigger` accepts the total number of `substeps` for the simulation / `end_substep` and returns a function accepting `trigger_field`, `trigger_vals`, and `funct_list`. In the following example functions are used to add `5` to every `s3` update and assign `10` to `s4` at `timestamp`s `'2018-10-01 15:16:25'`, `'2018-10-01 15:16:27'`, and `'2018-10-01 15:16:29'`. ```python from cadCAD.configuration.utils import env_trigger trigger_timestamps = ['2018-10-01 15:16:25', '2018-10-01 15:16:27', '2018-10-01 15:16:29'] env_processes = { "s3": [lambda params, x: x + 5], "s4": env_trigger(end_substep=3)( trigger_field='timestamp', trigger_vals=trigger_timestamps, funct_list=[lambda params, x: 10] ) } ``` #### System Model Configuration `append_configs`, stores a **System Model Configuration** to be (Executed)[url] as simulations producing system event dataset(s) ```python from cadCAD.configuration import append_configs append_configs( sim_configs=sim_config, initial_state=genesis_states, env_processes=env_processes, partial_state_update_blocks=partial_state_update_block, policy_ops=[lambda a, b: a + b] ) ``` #### [System Simulation Execution](link)