Merge pull request #53 from BlockScience/staging
Open Sourcing cadCAD!!!!
|
|
@ -14,11 +14,17 @@ results
|
|||
*.txt
|
||||
simulations/.ipynb_checkpoints
|
||||
simulations/validation/config3.py
|
||||
dist/*.gz
|
||||
cadCAD.egg-info
|
||||
|
||||
build
|
||||
cadCAD.egg-info
|
||||
SimCAD.egg-info
|
||||
|
||||
testing/example.py
|
||||
testing/example2.py
|
||||
testing/multi_config_test.py
|
||||
testing/udo.py
|
||||
testing/udo_test.py
|
||||
|
||||
Simulation.md
|
||||
|
||||
monkeytype.sqlite3
|
||||
205
README.md
|
|
@ -1,132 +1,173 @@
|
|||
# cadCAD
|
||||
**Warning**:
|
||||
**Do not** publish this package / software to **any** software repository **except** one permitted by BlockScience.
|
||||
```
|
||||
__________ ____
|
||||
________ __ _____/ ____/ | / __ \
|
||||
/ ___/ __` / __ / / / /| | / / / /
|
||||
/ /__/ /_/ / /_/ / /___/ ___ |/ /_/ /
|
||||
\___/\__,_/\__,_/\____/_/ |_/_____/
|
||||
by BlockScience
|
||||
```
|
||||
|
||||
**Introduction:**
|
||||
|
||||
***cadCAD*** is a Python library that assists in the processes of designing, testing and validating complex systems through
|
||||
simulation. At its core, cadCAD is a differential games engine that supports parameter sweeping and Monte Carlo analyses
|
||||
and can be easily integrated with other scientific computing Python modules and data science workflows.
|
||||
|
||||
**Description:**
|
||||
|
||||
cadCAD is a differential games based simulation software package for research, validation, and Computer \
|
||||
Aided Design of economic systems. An economic system is treated as a state based model and defined through a \
|
||||
set of endogenous and exogenous state variables which are updated through mechanisms and environmental \
|
||||
processes, respectively. Behavioral models, which may be deterministic or stochastic, provide the evolution of \
|
||||
the system within the action space of the mechanisms. Mathematical formulations of these economic games \
|
||||
treat agent utility as derived from state rather than direct from action, creating a rich dynamic modeling framework.
|
||||
|
||||
Simulations may be run with a range of initial conditions and parameters for states, behaviors, mechanisms, \
|
||||
and environmental processes to understand and visualize network behavior under various conditions. Support for \
|
||||
A/B testing policies, monte carlo analysis and other common numerical methods is provided.
|
||||
cadCAD (complex adaptive systems computer-aided design) is a python based, unified modeling framework for stochastic
|
||||
dynamical systems and differential games for research, validation, and Computer Aided Design of economic systems created
|
||||
by BlockScience. It is capable of modeling systems at all levels of abstraction from Agent Based Modeling (ABM) to
|
||||
System Dynamics (SD), and enabling smooth integration of computational social science simulations with empirical data
|
||||
science workflows.
|
||||
|
||||
|
||||
**1. Install Dependencies:**
|
||||
An economic system is treated as a state-based model and defined through a set of endogenous and exogenous state
|
||||
variables which are updated through mechanisms and environmental processes, respectively. Behavioral models, which may
|
||||
be deterministic or stochastic, provide the evolution of the system within the action space of the mechanisms.
|
||||
Mathematical formulations of these economic games treat agent utility as derived from the state rather than direct from
|
||||
an action, creating a rich, dynamic modeling framework. Simulations may be run with a range of initial conditions and
|
||||
parameters for states, behaviors, mechanisms, and environmental processes to understand and visualize network behavior
|
||||
under various conditions. Support for A/B testing policies, Monte Carlo analysis, and other common numerical methods is
|
||||
provided.
|
||||
|
||||
**Option A:** Package Repository Access
|
||||
|
||||
***IMPORTANT NOTE:*** Tokens are issued to and meant to be used by trial users and BlockScience employees **ONLY**. Replace \<TOKEN\> with an issued token in the script below.
|
||||
```bash
|
||||
pip3 install pandas pathos fn funcy tabulate
|
||||
pip3 install cadCAD --extra-index-url https://<TOKEN>@repo.fury.io/blockscience/
|
||||
```
|
||||
In essence, cadCAD tool allows us to represent a company’s or community’s current business model along with a desired
|
||||
future state and helps make informed, rigorously tested decisions on how to get from today’s stage to the future state.
|
||||
It allows us to use code to solidify our conceptualized ideas and see if the outcome meets our expectations. We can
|
||||
iteratively refine our work until we have constructed a model that closely reflects reality at the start of the model,
|
||||
and see how it evolves. We can then use these results to inform business decisions.
|
||||
|
||||
**Option B:** Build From Source
|
||||
#### Documentation:
|
||||
* ##### [Tutorials](tutorials)
|
||||
* ##### [System Model Configuration](documentation/Simulation_Configuration.md)
|
||||
* ##### [System Simulation Execution](documentation/Simulation_Execution.md)
|
||||
* ##### [Policy Aggregation](documentation/Policy_Aggregation.md)
|
||||
* ##### [System Model Parameter Sweep](documentation/System_Model_Parameter_Sweep.md)
|
||||
|
||||
#### 0. Installation:
|
||||
|
||||
**Python 3.6.5** :: Anaconda, Inc.
|
||||
|
||||
**Option A:** Build From Source
|
||||
```bash
|
||||
pip3 install -r requirements.txt
|
||||
python3 setup.py sdist bdist_wheel
|
||||
pip3 install dist/*.whl
|
||||
```
|
||||
|
||||
**2. Configure Simulation:**
|
||||
**Option B:** Proprietary Build Access
|
||||
|
||||
Intructions:
|
||||
`/Simulation.md`
|
||||
|
||||
Examples:
|
||||
`/simulations/validation/*`
|
||||
|
||||
**3. Import cadCAD & Run Simulations:**
|
||||
|
||||
Examples: `/simulations/*.py` or `/simulations/*.ipynb`
|
||||
|
||||
Single Simulation: `/simulations/single_config_run.py`
|
||||
```python
|
||||
from tabulate import tabulate
|
||||
# The following imports NEED to be in the exact order
|
||||
from cadCAD.engine import ExecutionMode, ExecutionContext, Executor
|
||||
from simulations.validation import config1
|
||||
from cadCAD import configs
|
||||
|
||||
exec_mode = ExecutionMode()
|
||||
|
||||
print("Simulation Execution: Single Configuration")
|
||||
print()
|
||||
first_config = configs # only contains config1
|
||||
single_proc_ctx = ExecutionContext(context=exec_mode.single_proc)
|
||||
run1 = Executor(exec_context=single_proc_ctx, configs=first_config)
|
||||
run1_raw_result, tensor_field = run1.main()
|
||||
result = pd.DataFrame(run1_raw_result)
|
||||
print()
|
||||
print("Tensor Field: config1")
|
||||
print(tabulate(tensor_field, headers='keys', tablefmt='psql'))
|
||||
print("Output:")
|
||||
print(tabulate(result, headers='keys', tablefmt='psql'))
|
||||
print()
|
||||
***IMPORTANT NOTE:*** Tokens are issued to those with access to proprietary builds of cadCAD and BlockScience employees **ONLY**.
|
||||
Replace \<TOKEN\> with an issued token in the script below.
|
||||
```bash
|
||||
pip3 install pandas pathos fn funcy tabulate
|
||||
pip3 install cadCAD --extra-index-url https://<TOKEN>@repo.fury.io/blockscience/
|
||||
```
|
||||
|
||||
Parameter Sweep Simulation (Concurrent): `/simulations/param_sweep_run.py`
|
||||
|
||||
#### 1. [Configure System Model](documentation/Simulation_Configuration.md)
|
||||
|
||||
#### 2. [Execute Simulations:](documentation/Simulation_Execution.md)
|
||||
|
||||
##### Single Process Execution:
|
||||
Example System Model Configurations:
|
||||
* [System Model A](documentation/examples/sys_model_A.py):
|
||||
`/documentation/examples/sys_model_A.py`
|
||||
* [System Model B](documentation/examples/sys_model_B.py):
|
||||
`/documentation/examples/sys_model_B.py`
|
||||
|
||||
Example Simulation Executions:
|
||||
* [System Model A](documentation/examples/sys_model_A_exec.py):
|
||||
`/documentation/examples/sys_model_A_exec.py`
|
||||
* [System Model B](documentation/examples/sys_model_B_exec.py):
|
||||
`/documentation/examples/sys_model_B_exec.py`
|
||||
|
||||
```python
|
||||
import pandas as pd
|
||||
from tabulate import tabulate
|
||||
# The following imports NEED to be in the exact order
|
||||
from cadCAD.engine import ExecutionMode, ExecutionContext, Executor
|
||||
from simulations.validation import sweep_config
|
||||
from documentation.examples import sys_model_A
|
||||
from cadCAD import configs
|
||||
|
||||
exec_mode = ExecutionMode()
|
||||
|
||||
print("Simulation Execution: Concurrent Execution")
|
||||
# Single Process Execution using a Single System Model Configuration:
|
||||
# sys_model_A
|
||||
sys_model_A = [configs[0]] # sys_model_A
|
||||
single_proc_ctx = ExecutionContext(context=exec_mode.single_proc)
|
||||
sys_model_A_simulation = Executor(exec_context=single_proc_ctx, configs=sys_model_A)
|
||||
|
||||
sys_model_A_raw_result, sys_model_A_tensor_field = sys_model_A_simulation.execute()
|
||||
sys_model_A_result = pd.DataFrame(sys_model_A_raw_result)
|
||||
print()
|
||||
print("Tensor Field: sys_model_A")
|
||||
print(tabulate(sys_model_A_tensor_field, headers='keys', tablefmt='psql'))
|
||||
print("Result: System Events DataFrame")
|
||||
print(tabulate(sys_model_A_result, headers='keys', tablefmt='psql'))
|
||||
print()
|
||||
```
|
||||
|
||||
##### Multiple Simulations (Concurrent):
|
||||
###### Multiple Simulation Execution (Multi Process Execution)
|
||||
System Model Configurations:
|
||||
* [System Model A](documentation/examples/sys_model_A.py):
|
||||
`/documentation/examples/sys_model_A.py`
|
||||
* [System Model B](documentation/examples/sys_model_B.py):
|
||||
`/documentation/examples/sys_model_B.py`
|
||||
|
||||
[Example Simulation Executions:](documentation/examples/sys_model_AB_exec.py)
|
||||
`/documentation/examples/sys_model_AB_exec.py`
|
||||
|
||||
```python
|
||||
import pandas as pd
|
||||
from tabulate import tabulate
|
||||
from cadCAD.engine import ExecutionMode, ExecutionContext, Executor
|
||||
from documentation.examples import sys_model_A, sys_model_B
|
||||
from cadCAD import configs
|
||||
|
||||
exec_mode = ExecutionMode()
|
||||
|
||||
# # Multiple Processes Execution using Multiple System Model Configurations:
|
||||
# # sys_model_A & sys_model_B
|
||||
multi_proc_ctx = ExecutionContext(context=exec_mode.multi_proc)
|
||||
run2 = Executor(exec_context=multi_proc_ctx, configs=configs)
|
||||
sys_model_AB_simulation = Executor(exec_context=multi_proc_ctx, configs=configs)
|
||||
|
||||
i = 0
|
||||
config_names = ['sweep_config_A', 'sweep_config_B']
|
||||
for raw_result, tensor_field in run2.main():
|
||||
result = pd.DataFrame(raw_result)
|
||||
config_names = ['sys_model_A', 'sys_model_B']
|
||||
for sys_model_AB_raw_result, sys_model_AB_tensor_field in sys_model_AB_simulation.execute():
|
||||
sys_model_AB_result = pd.DataFrame(sys_model_AB_raw_result)
|
||||
print()
|
||||
print("Tensor Field: " + config_names[i])
|
||||
print(tabulate(tensor_field, headers='keys', tablefmt='psql'))
|
||||
print("Output:")
|
||||
print(tabulate(result, headers='keys', tablefmt='psql'))
|
||||
print(f"Tensor Field: {config_names[i]}")
|
||||
print(tabulate(sys_model_AB_tensor_field, headers='keys', tablefmt='psql'))
|
||||
print("Result: System Events DataFrame:")
|
||||
print(tabulate(sys_model_AB_result, headers='keys', tablefmt='psql'))
|
||||
print()
|
||||
i += 1
|
||||
```
|
||||
|
||||
Multiple Simulations (Concurrent): `/simulations/multi_config run.py`
|
||||
##### Parameter Sweep Simulation (Concurrent):
|
||||
[Example:](documentation/examples/param_sweep.py)
|
||||
`/documentation/examples/param_sweep.py`
|
||||
|
||||
```python
|
||||
import pandas as pd
|
||||
from tabulate import tabulate
|
||||
# The following imports NEED to be in the exact order
|
||||
from cadCAD.engine import ExecutionMode, ExecutionContext, Executor
|
||||
from simulations.validation import config1, config2
|
||||
from documentation.examples import param_sweep
|
||||
from cadCAD import configs
|
||||
|
||||
exec_mode = ExecutionMode()
|
||||
|
||||
print("Simulation Execution: Concurrent Execution")
|
||||
multi_proc_ctx = ExecutionContext(context=exec_mode.multi_proc)
|
||||
run2 = Executor(exec_context=multi_proc_ctx, configs=configs)
|
||||
run = Executor(exec_context=multi_proc_ctx, configs=configs)
|
||||
|
||||
i = 0
|
||||
config_names = ['config1', 'config2']
|
||||
for raw_result, tensor_field in run2.main():
|
||||
for raw_result, tensor_field in run.execute():
|
||||
result = pd.DataFrame(raw_result)
|
||||
print()
|
||||
print("Tensor Field: " + config_names[i])
|
||||
print("Tensor Field:")
|
||||
print(tabulate(tensor_field, headers='keys', tablefmt='psql'))
|
||||
print("Output:")
|
||||
print(tabulate(result, headers='keys', tablefmt='psql'))
|
||||
print()
|
||||
i =+ 1
|
||||
```
|
||||
|
||||
The above can be run in Jupyter.
|
||||
```bash
|
||||
jupyter notebook
|
||||
```
|
||||
|
|
|
|||
151
Simulation.md
|
|
@ -1,151 +0,0 @@
|
|||
# cadCAD Documentation
|
||||
|
||||
## Introduction
|
||||
|
||||
A blockchain is a distributed ledger with economic agents transacting in a network. The state of the network evolves with every new transaction, which can be a result of user behaviors, protocol-defined system mechanisms, or external processes.
|
||||
|
||||
It is not uncommon today for blockchain projects to announce a set of rules for their network and make claims about their system level behvaior. However, the validity of those claims is hardly validated. Furthermore, it is difficult to know the potential system-level impact when the network is considering an upgrade to their system rules and prameters.
|
||||
|
||||
To rigorously and reliably analyze, design, and improve cryptoeconomic networks, we are introducing this Computer Aided Design Engine where we define a cryptoeconomic network with its state and exogneous variables, model transactions as a result of agent behaviors, state mechanisms, and environmental processes. We can then run simulations with different initial states, mechanisms, environmental processes to understand and visualize network behavior under different conditions.
|
||||
|
||||
## State Variables and Transitions
|
||||
|
||||
We now define variables and different transition mechanisms that will be inputs to the simulation engine.
|
||||
|
||||
- ***State variables*** are defined to capture the shape and property of the network, such as a vector or a dictionary that captures all user balances.
|
||||
- ***Exogenous variables*** are variables that represent external input and signal. They are only affected by environmental processes and are not affected by system mechanisms. Nonetheless, exgoneous variables can be used as an input to a mechanism that impacts state variables. They can be considered as read-only variables to the system.
|
||||
- ***Behaviors per transition*** model agent behaviors in reaction to state variables and exogenous variables. The resulted user action will become an input to state mechanisms. Note that user behaviors should not directly update value of state variables.
|
||||
- ***State mechanisms per transition*** are system defined mechanisms that take user actions and other states as inputs and produce updates to the value of state variables.
|
||||
- ***Exogenous state updates*** specify how exogenous variables evolve with time which can indirectly impact state variables through behavior and state mechanisms.
|
||||
- ***Environmental processes*** model external changes that directly impact state or exogenous variables at specific timestamps or conditions.
|
||||
|
||||
A state evolves to another state via state transition. Each transition is composed of behavior and state mechanisms as functions of state and exogenous variables. A flow of the state transition is as follows.
|
||||
|
||||
Given some state and exogenous variables of the system at the onset of a state transition, agent behavior takes in these variables as input and return a set of agent actions. This models after agent behavior and reaction to a set of variables. Given these agent actions, state mechanism, as defined by the protocol, takes these actions, state, and exogenous variables as inputs and return a new set of state variables.
|
||||
|
||||
## System Configuration File
|
||||
|
||||
Simulation engine takes in system configuration files, e.g. `config.py`, where all the above variables and mechanisms are defined. The following import statements should be added at the beginning of the configuration files.
|
||||
```python
|
||||
from decimal import Decimal
|
||||
import numpy as np
|
||||
from datetime import timedelta
|
||||
|
||||
from cadCAD import configs
|
||||
from cadCAD.configuration import Configuration
|
||||
from cadCAD.configuration.utils import exo_update_per_ts, proc_trigger, bound_norm_random, \
|
||||
ep_time_step
|
||||
```
|
||||
|
||||
State variables and their initial values can be defined as follows. Note that `timestamp` is a required field for this iteration of cadCAD for `env_proc` to work. Future iterations will strive to make this more generic and timestamp optional.
|
||||
```python
|
||||
genesis_dict = {
|
||||
's1': Decimal(0.0),
|
||||
's2': Decimal(0.0),
|
||||
's3': Decimal(1.0),
|
||||
'timestamp': '2018-10-01 15:16:24'
|
||||
}
|
||||
```
|
||||
|
||||
Each potential transition and its state and behavior mechanisms can be defined in the following dictionary object.
|
||||
```python
|
||||
transitions = {
|
||||
"m1": {
|
||||
"behaviors": {
|
||||
"b1": b1m1,
|
||||
"b2": b2m1
|
||||
},
|
||||
"states": {
|
||||
"s1": s1m1,
|
||||
"s2": s2m1
|
||||
}
|
||||
},
|
||||
"m2": {...}
|
||||
}
|
||||
```
|
||||
Every behavior per transition should return a dictionary as actions taken by the agents. They will then be aggregated through addition in this version of cadCAD. Some examples of behaviors per transition are as follows. More flexible and user-defined aggregation functions will be introduced in future iterations but no example is provided at this point.
|
||||
```python
|
||||
def b1m1(step, sL, s):
|
||||
return {'param1': 1}
|
||||
|
||||
def b1m2(step, sL, s):
|
||||
return {'param1': 'a', 'param2': 2}
|
||||
|
||||
def b1m3(step, sL, s):
|
||||
return {'param1': ['c'], 'param2': np.array([10, 100])}
|
||||
```
|
||||
State mechanism per transition on the other hand takes in the output of behavior mechanisms (`_input`) and returns a tuple of the name of the variable and the new value for the variable. Some examples of a state mechanism per transition are as follows. Note that each state mechanism is supposed to change one state variable at a time. Changes to multiple state variables should be done in separate mechanisms.
|
||||
```python
|
||||
def s1m1(step, sL, s, _input):
|
||||
y = 's1'
|
||||
x = _input['param1'] + 1
|
||||
return (y, x)
|
||||
|
||||
def s1m2(step, sL, s, _input):
|
||||
y = 's1'
|
||||
x = _input['param1']
|
||||
return (y, x)
|
||||
```
|
||||
Exogenous state update functions, for example `es3p1`, `es4p2` and `es5p2` below, update exogenous variables at every timestamp. Note that every timestamp is consist of all behaviors and state mechanisms in the order defined in `transitions` dictionary. If `exo_update_per_ts` is not used, exogenous state updates will be applied at every mechanism step (`m1`, `m2`, etc). Otherwise, exogenous state updates will only be applied once for every timestamp after all the mechanism steps are executed.
|
||||
```python
|
||||
exogenous_states = exo_update_per_ts(
|
||||
{
|
||||
"s3": es3p1,
|
||||
"s4": es4p2,
|
||||
"timestamp": es5p2
|
||||
}
|
||||
)
|
||||
```
|
||||
To model randomness, we should also define pseudorandom seeds in the configuration as follows.
|
||||
```python
|
||||
seed = {
|
||||
'z': np.random.RandomState(1),
|
||||
'a': np.random.RandomState(2),
|
||||
'b': np.random.RandomState(3),
|
||||
'c': np.random.RandomState(3)
|
||||
}
|
||||
```
|
||||
cadCAD currently supports generating random number from a normal distribution through `bound_norm_random` with `min` and `max` values specified. Examples of environmental processes with randomness are as follows. We also define timestamp format with `ts_format` and timestamp changes with `t_delta`. Users can define other distributions to update exogenous variables.
|
||||
```python
|
||||
proc_one_coef_A = 0.7
|
||||
proc_one_coef_B = 1.3
|
||||
|
||||
def es3p1(step, sL, s, _input):
|
||||
y = 's3'
|
||||
x = s['s3'] * bound_norm_random(seed['a'], proc_one_coef_A, proc_one_coef_B)
|
||||
return (y, x)
|
||||
|
||||
def es4p2(step, sL, s, _input):
|
||||
y = 's4'
|
||||
x = s['s4'] * bound_norm_random(seed['b'], proc_one_coef_A, proc_one_coef_B)
|
||||
return (y, x)
|
||||
|
||||
ts_format = '%Y-%m-%d %H:%M:%S'
|
||||
t_delta = timedelta(days=0, minutes=0, seconds=1)
|
||||
def es5p2(step, sL, s, _input):
|
||||
y = 'timestamp'
|
||||
x = ep_time_step(s, s['timestamp'], fromat_str=ts_format, _timedelta=t_delta)
|
||||
return (y, x)
|
||||
```
|
||||
User can also define specific external events such as market shocks at specific timestamps through `env_processes` with `proc_trigger`. An environmental process with no `proc_trigger` will be called at every timestamp. In the example below, it will return the value of `s3` at every timestamp. Logical event triggers, such as a big draw down in exogenous variables, will be supported in a later version of cadCAD.
|
||||
```python
|
||||
def env_a(x):
|
||||
return x
|
||||
def env_b(x):
|
||||
return 10
|
||||
|
||||
env_processes = {
|
||||
"s3": env_a,
|
||||
"s4": proc_trigger('2018-10-01 15:16:25', env_b)
|
||||
}
|
||||
```
|
||||
|
||||
Lastly, we set the overall simulation configuration and initialize the `Configuration` class with the following. `T` denotes the time range and `N` refers to the number of simulation runs. Each run will start from the same initial states and run for `T` time range. Every transition is consist of behaviors, state mechanisms, exogenous updates, and potentially environmental processes. All of these happen within one time step in the simulation.
|
||||
```python
|
||||
sim_config = {
|
||||
"N": 2,
|
||||
"T": range(5)
|
||||
}
|
||||
|
||||
configs.append(Configuration(sim_config, state_dict, seed, exogenous_states, env_processes, mechanisms))
|
||||
```
|
||||
|
|
@ -9,8 +9,6 @@ from cadCAD.configuration.utils import exo_update_per_ts
|
|||
from cadCAD.configuration.utils.policyAggregation import dict_elemwise_sum
|
||||
from cadCAD.configuration.utils.depreciationHandler import sanitize_partial_state_updates, sanitize_config
|
||||
|
||||
# policy_ops=[foldr(dict_elemwise_sum())]
|
||||
# policy_ops=[reduce, lambda a, b: {**a, **b}]
|
||||
|
||||
class Configuration(object):
|
||||
def __init__(self, sim_config={}, initial_state={}, seeds={}, env_processes={},
|
||||
|
|
@ -28,7 +26,7 @@ class Configuration(object):
|
|||
|
||||
sanitize_config(self)
|
||||
|
||||
# ToDo: Remove Seeds
|
||||
|
||||
def append_configs(sim_configs={}, initial_state={}, seeds={}, raw_exogenous_states={}, env_processes={},
|
||||
partial_state_update_blocks={}, policy_ops=[lambda a, b: a + b], _exo_update_per_ts: bool = True) -> None:
|
||||
if _exo_update_per_ts is True:
|
||||
|
|
|
|||
|
|
@ -5,12 +5,10 @@ from fn.func import curried
|
|||
from funcy import curry
|
||||
import pandas as pd
|
||||
|
||||
# Temporary
|
||||
from cadCAD.configuration.utils.depreciationHandler import sanitize_partial_state_updates
|
||||
from cadCAD.utils import dict_filter, contains_type, flatten_tabulated_dict, tabulate_dict
|
||||
|
||||
|
||||
# ToDo: Fix - Returns empty when partial_state_update is missing in Configuration
|
||||
class TensorFieldReport:
|
||||
def __init__(self, config_proc):
|
||||
self.config_proc = config_proc
|
||||
|
|
@ -56,7 +54,6 @@ def time_step(dt_str, dt_format='%Y-%m-%d %H:%M:%S', _timedelta = tstep_delta):
|
|||
return t.strftime(dt_format)
|
||||
|
||||
|
||||
# ToDo: Inject in first elem of last PSUB from Historical state
|
||||
ep_t_delta = timedelta(days=0, minutes=0, seconds=1)
|
||||
def ep_time_step(s_condition, dt_str, fromat_str='%Y-%m-%d %H:%M:%S', _timedelta = ep_t_delta):
|
||||
# print(dt_str)
|
||||
|
|
@ -65,7 +62,7 @@ def ep_time_step(s_condition, dt_str, fromat_str='%Y-%m-%d %H:%M:%S', _timedelta
|
|||
else:
|
||||
return dt_str
|
||||
|
||||
# mech_sweep_filter
|
||||
|
||||
def partial_state_sweep_filter(state_field, partial_state_updates):
|
||||
partial_state_dict = dict([(k, v[state_field]) for k, v in partial_state_updates.items()])
|
||||
return dict([
|
||||
|
|
@ -77,7 +74,7 @@ def partial_state_sweep_filter(state_field, partial_state_updates):
|
|||
def state_sweep_filter(raw_exogenous_states):
|
||||
return dict([(k, v) for k, v in raw_exogenous_states.items() if isinstance(v, list)])
|
||||
|
||||
# sweep_mech_states
|
||||
|
||||
@curried
|
||||
def sweep_partial_states(_type, in_config):
|
||||
configs = []
|
||||
|
|
@ -129,16 +126,19 @@ def exo_update_per_ts(ep):
|
|||
|
||||
return {es: ep_decorator(f, es) for es, f in ep.items()}
|
||||
|
||||
|
||||
def trigger_condition(s, pre_conditions, cond_opp):
|
||||
condition_bools = [s[field] in precondition_values for field, precondition_values in pre_conditions.items()]
|
||||
return reduce(cond_opp, condition_bools)
|
||||
|
||||
|
||||
def apply_state_condition(pre_conditions, cond_opp, y, f, _g, step, sL, s, _input):
|
||||
if trigger_condition(s, pre_conditions, cond_opp):
|
||||
return f(_g, step, sL, s, _input)
|
||||
else:
|
||||
return y, s[y]
|
||||
|
||||
|
||||
def var_trigger(y, f, pre_conditions, cond_op):
|
||||
return lambda _g, step, sL, s, _input: apply_state_condition(pre_conditions, cond_op, y, f, _g, step, sL, s, _input)
|
||||
|
||||
|
|
@ -173,7 +173,6 @@ def env_trigger(end_substep):
|
|||
curry(trigger)(end_substep)(trigger_field)(trigger_vals)(funct_list)
|
||||
|
||||
|
||||
# param sweep enabling middleware
|
||||
def config_sim(d):
|
||||
def process_variables(d):
|
||||
return flatten_tabulated_dict(tabulate_dict(d))
|
||||
|
|
@ -184,15 +183,18 @@ def config_sim(d):
|
|||
d["M"] = [{}]
|
||||
return d
|
||||
|
||||
|
||||
def psub_list(psu_block, psu_steps):
|
||||
return [psu_block[psu] for psu in psu_steps]
|
||||
|
||||
|
||||
def psub(policies, state_updates):
|
||||
return {
|
||||
'policies': policies,
|
||||
'states': state_updates
|
||||
}
|
||||
|
||||
|
||||
def genereate_psubs(policy_grid, states_grid, policies, state_updates):
|
||||
PSUBS = []
|
||||
for policy_ids, state_list in zip(policy_grid, states_grid):
|
||||
|
|
@ -202,19 +204,20 @@ def genereate_psubs(policy_grid, states_grid, policies, state_updates):
|
|||
|
||||
return PSUBS
|
||||
|
||||
def access_block(sH, y, psu_block_offset, exculsion_list=[]):
|
||||
exculsion_list += [y]
|
||||
|
||||
def access_block(state_history, target_field, psu_block_offset, exculsion_list=[]):
|
||||
exculsion_list += [target_field]
|
||||
def filter_history(key_list, sH):
|
||||
filter = lambda key_list: \
|
||||
lambda d: {k: v for k, v in d.items() if k not in key_list}
|
||||
return list(map(filter(key_list), sH))
|
||||
|
||||
if psu_block_offset < -1:
|
||||
if len(sH) >= abs(psu_block_offset):
|
||||
return filter_history(exculsion_list, sH[psu_block_offset])
|
||||
if len(state_history) >= abs(psu_block_offset):
|
||||
return filter_history(exculsion_list, state_history[psu_block_offset])
|
||||
else:
|
||||
return []
|
||||
elif psu_block_offset < 0:
|
||||
return filter_history(exculsion_list, sH[psu_block_offset])
|
||||
elif psu_block_offset == -1:
|
||||
return filter_history(exculsion_list, state_history[psu_block_offset])
|
||||
else:
|
||||
return []
|
||||
|
|
@ -2,8 +2,6 @@ from copy import deepcopy
|
|||
|
||||
|
||||
def sanitize_config(config):
|
||||
# for backwards compatibility, we accept old arguments via **kwargs
|
||||
# TODO: raise specific deprecation warnings for key == 'state_dict', key == 'seed', key == 'mechanisms'
|
||||
for key, value in config.kwargs.items():
|
||||
if key == 'state_dict':
|
||||
config.initial_state = value
|
||||
|
|
@ -18,8 +16,6 @@ def sanitize_config(config):
|
|||
|
||||
def sanitize_partial_state_updates(partial_state_updates):
|
||||
new_partial_state_updates = deepcopy(partial_state_updates)
|
||||
# for backwards compatibility we accept the old keys
|
||||
# ('behaviors' and 'states') and rename them
|
||||
def rename_keys(d):
|
||||
if 'behaviors' in d:
|
||||
d['policies'] = d.pop('behaviors')
|
||||
|
|
@ -28,8 +24,6 @@ def sanitize_partial_state_updates(partial_state_updates):
|
|||
d['variables'] = d.pop('states')
|
||||
|
||||
|
||||
# Also for backwards compatibility, we accept partial state update blocks both as list or dict
|
||||
# No need for a deprecation warning as it's already raised by cadCAD.utils.key_filter
|
||||
if isinstance(new_partial_state_updates, list):
|
||||
for v in new_partial_state_updates:
|
||||
rename_keys(v)
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
from fn.op import foldr
|
||||
from fn.func import curried
|
||||
|
||||
|
||||
def get_base_value(x):
|
||||
if isinstance(x, str):
|
||||
return ''
|
||||
|
|
@ -17,7 +18,7 @@ def policy_to_dict(v):
|
|||
|
||||
|
||||
add = lambda a, b: a + b
|
||||
# df_union = lambda a, b: ...
|
||||
|
||||
|
||||
@curried
|
||||
def foldr_dict_vals(f, d):
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
from collections import namedtuple
|
||||
from copy import deepcopy
|
||||
from inspect import getmembers, ismethod
|
||||
from pandas.core.frame import DataFrame
|
||||
|
||||
|
|
@ -12,13 +11,12 @@ def val_switch(v):
|
|||
else:
|
||||
return v
|
||||
|
||||
|
||||
class udcView(object):
|
||||
def __init__(self, d, masked_members):
|
||||
self.__dict__ = d
|
||||
self.masked_members = masked_members
|
||||
|
||||
# returns dict to dataframe
|
||||
# def __repr__(self):
|
||||
def __repr__(self):
|
||||
members = {}
|
||||
variables = {
|
||||
|
|
@ -26,8 +24,9 @@ class udcView(object):
|
|||
if str(type(v)) != "<class 'method'>" and k not in self.masked_members # and isinstance(v, DataFrame) is not True
|
||||
}
|
||||
members['methods'] = [k for k, v in self.__dict__.items() if str(type(v)) == "<class 'method'>"]
|
||||
|
||||
members.update(variables)
|
||||
return f"{members}" #[1:-1]
|
||||
return f"{members}"
|
||||
|
||||
|
||||
class udcBroker(object):
|
||||
|
|
@ -36,7 +35,8 @@ class udcBroker(object):
|
|||
funcs = dict(getmembers(obj, ismethod))
|
||||
filtered_functions = {k: v for k, v in funcs.items() if k not in function_filter}
|
||||
d['obj'] = obj
|
||||
d.update(deepcopy(vars(obj))) # somehow is enough
|
||||
# d.update(deepcopy(vars(obj))) # somehow is enough
|
||||
d.update(vars(obj)) # somehow is enough
|
||||
d.update(filtered_functions)
|
||||
|
||||
self.members_dict = d
|
||||
|
|
@ -57,4 +57,3 @@ def UDO(udo, masked_members=['obj']):
|
|||
|
||||
def udoPipe(obj_view):
|
||||
return UDO(obj_view.obj, obj_view.masked_members)
|
||||
|
||||
|
|
|
|||
|
|
@ -93,7 +93,6 @@ class Executor:
|
|||
final_result = None
|
||||
|
||||
if self.exec_context == ExecutionMode.single_proc:
|
||||
# ToDO: Deprication Handler - "sanitize" in appropriate place
|
||||
tensor_field = create_tensor_field(partial_state_updates.pop(), eps.pop())
|
||||
result = self.exec_method(simulation_execs, var_dict_list, states_lists, configs_structs, env_processes_list, Ts, Ns)
|
||||
final_result = result, tensor_field
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
from pprint import pprint
|
||||
from typing import Any, Callable, Dict, List, Tuple
|
||||
from pathos.pools import ThreadPool as TPool
|
||||
from copy import deepcopy
|
||||
|
|
@ -62,9 +63,6 @@ class Executor:
|
|||
) for k, val_list in new_dict.items()
|
||||
}
|
||||
|
||||
# [f1] = ops
|
||||
# return {k: reduce(f1, val_list) for k, val_list in new_dict.items()}
|
||||
# return foldr(call, col_results)(ops)
|
||||
|
||||
def apply_env_proc(
|
||||
self,
|
||||
|
|
@ -97,7 +95,6 @@ class Executor:
|
|||
|
||||
return state_dict
|
||||
|
||||
# ToDo: Redifined as a function that applies the tensor field to a set og last conditions
|
||||
# mech_step
|
||||
def partial_state_update(
|
||||
self,
|
||||
|
|
@ -113,10 +110,11 @@ class Executor:
|
|||
) -> List[Dict[str, Any]]:
|
||||
|
||||
last_in_obj: Dict[str, Any] = deepcopy(sL[-1])
|
||||
_input: Dict[str, Any] = self.policy_update_exception(self.get_policy_input(sweep_dict, sub_step, sH, last_in_obj, policy_funcs))
|
||||
_input: Dict[str, Any] = self.policy_update_exception(
|
||||
self.get_policy_input(sweep_dict, sub_step, sH, last_in_obj, policy_funcs)
|
||||
)
|
||||
|
||||
|
||||
# ToDo: add env_proc generator to `last_in_copy` iterator as wrapper function
|
||||
# ToDo: Can be multithreaded ??
|
||||
def generate_record(state_funcs):
|
||||
for f in state_funcs:
|
||||
yield self.state_update_exception(f(sweep_dict, sub_step, sH, last_in_obj, _input))
|
||||
|
|
@ -130,7 +128,6 @@ class Executor:
|
|||
|
||||
last_in_copy: Dict[str, Any] = transfer_missing_fields(last_in_obj, dict(generate_record(state_funcs)))
|
||||
last_in_copy: Dict[str, Any] = self.apply_env_proc(sweep_dict, env_processes, last_in_copy)
|
||||
# ToDo: make 'substep' & 'timestep' reserve fields
|
||||
last_in_copy['substep'], last_in_copy['timestep'], last_in_copy['run'] = sub_step, time_step, run
|
||||
|
||||
sL.append(last_in_copy)
|
||||
|
|
@ -151,7 +148,6 @@ class Executor:
|
|||
|
||||
sub_step = 0
|
||||
states_list_copy: List[Dict[str, Any]] = deepcopy(simulation_list[-1])
|
||||
# ToDo: Causes Substep repeats in sL:
|
||||
genesis_states: Dict[str, Any] = states_list_copy[-1]
|
||||
|
||||
if len(states_list_copy) == 1:
|
||||
|
|
@ -163,7 +159,6 @@ class Executor:
|
|||
del states_list_copy
|
||||
states_list: List[Dict[str, Any]] = [genesis_states]
|
||||
|
||||
# ToDo: Was causing Substep repeats in sL, use for yield
|
||||
sub_step += 1
|
||||
|
||||
for [s_conf, p_conf] in configs: # tensor field
|
||||
|
|
@ -175,6 +170,9 @@ class Executor:
|
|||
|
||||
time_step += 1
|
||||
|
||||
pprint(states_list)
|
||||
print()
|
||||
|
||||
return states_list
|
||||
|
||||
# state_update_pipeline
|
||||
|
|
@ -189,7 +187,6 @@ class Executor:
|
|||
) -> List[List[Dict[str, Any]]]:
|
||||
|
||||
time_seq: List[int] = [x + 1 for x in time_seq]
|
||||
# ToDo: simulation_list should be a Tensor that is generated throughout the Executor
|
||||
simulation_list: List[List[Dict[str, Any]]] = [states_list]
|
||||
|
||||
for time_step in time_seq:
|
||||
|
|
@ -202,8 +199,6 @@ class Executor:
|
|||
|
||||
return simulation_list
|
||||
|
||||
# ToDo: Below can be recieved from a tensor field
|
||||
# configs: List[Tuple[List[Callable], List[Callable]]]
|
||||
def simulation(
|
||||
self,
|
||||
sweep_dict: Dict[str, List[Any]],
|
||||
|
|
@ -224,7 +219,9 @@ class Executor:
|
|||
|
||||
states_list_copy: List[Dict[str, Any]] = list(generate_init_sys_metrics(deepcopy(states_list)))
|
||||
|
||||
first_timestep_per_run: List[Dict[str, Any]] = self.run_pipeline(sweep_dict, states_list_copy, configs, env_processes, time_seq, run)
|
||||
first_timestep_per_run: List[Dict[str, Any]] = self.run_pipeline(
|
||||
sweep_dict, states_list_copy, configs, env_processes, time_seq, run
|
||||
)
|
||||
del states_list_copy
|
||||
|
||||
return first_timestep_per_run
|
||||
|
|
@ -235,5 +232,4 @@ class Executor:
|
|||
list(range(runs))
|
||||
)
|
||||
)
|
||||
|
||||
return pipe_run
|
||||
|
|
|
|||
|
|
@ -24,8 +24,6 @@ def retrieve_state(l, offset):
|
|||
return l[last_index(l) + offset + 1]
|
||||
|
||||
|
||||
# exception_function = f(sub_step, sL, sL[-2], _input)
|
||||
# try_function = f(sub_step, sL, last_mut_obj, _input)
|
||||
@curried
|
||||
def engine_exception(ErrorType, error_message, exception_function, try_function):
|
||||
try:
|
||||
|
|
@ -38,5 +36,3 @@ def engine_exception(ErrorType, error_message, exception_function, try_function)
|
|||
@curried
|
||||
def fit_param(param, x):
|
||||
return x + param
|
||||
|
||||
# fit_param = lambda param: lambda x: x + param
|
||||
|
|
|
|||
|
|
@ -11,18 +11,12 @@ class SilentDF(DataFrame):
|
|||
def __repr__(self):
|
||||
return str(hex(id(DataFrame))) #"pandas.core.frame.DataFrame"
|
||||
|
||||
|
||||
def append_dict(dict, new_dict):
|
||||
dict.update(new_dict)
|
||||
return dict
|
||||
|
||||
|
||||
# def val_switch(v):
|
||||
# if isinstance(v, DataFrame) is True or isinstance(v, SilentDF) is True:
|
||||
# return SilentDF(v)
|
||||
# else:
|
||||
# return v.x
|
||||
|
||||
|
||||
class IndexCounter:
|
||||
def __init__(self):
|
||||
self.i = 0
|
||||
|
|
@ -31,8 +25,6 @@ class IndexCounter:
|
|||
self.i += 1
|
||||
return self.i
|
||||
|
||||
# def compose(*functions):
|
||||
# return reduce(lambda f, g: lambda x: f(g(x)), functions, lambda x: x)
|
||||
|
||||
def compose(*functions):
|
||||
return reduce(lambda f, g: lambda x: f(g(x)), functions, lambda x: x)
|
||||
|
|
@ -110,8 +102,7 @@ def contains_type(_collection, type):
|
|||
def drop_right(l, n):
|
||||
return l[:len(l) - n]
|
||||
|
||||
# backwards compatibility
|
||||
# ToDo: Encapsulate in function
|
||||
|
||||
def key_filter(l, keyname):
|
||||
if (type(l) == list):
|
||||
return [v[keyname] for v in l]
|
||||
|
|
@ -149,23 +140,3 @@ def curry_pot(f, *argv):
|
|||
return f(argv[0], argv[1], argv[2])
|
||||
else:
|
||||
raise TypeError('curry_pot() needs 3 or 4 positional arguments')
|
||||
|
||||
# def curry_pot(f, *argv):
|
||||
# sweep_ind = f.__name__[0:5] == 'sweep'
|
||||
# arg_len = len(argv)
|
||||
# if sweep_ind is True and arg_len == 4:
|
||||
# return f(argv[0])(argv[1])(argv[2])(argv[3])
|
||||
# elif sweep_ind is False and arg_len == 4:
|
||||
# return f(argv[0])(argv[1])(argv[2])(argv[3])
|
||||
# elif sweep_ind is True and arg_len == 3:
|
||||
# return f(argv[0])(argv[1])(argv[2])
|
||||
# elif sweep_ind is False and arg_len == 3:
|
||||
# return f(argv[0])(argv[1])(argv[2])
|
||||
# else:
|
||||
# raise TypeError('curry_pot() needs 3 or 4 positional arguments')
|
||||
|
||||
# def rename(newname):
|
||||
# def decorator(f):
|
||||
# f.__name__ = newname
|
||||
# return f
|
||||
# return decorator
|
||||
|
|
|
|||
|
|
@ -1,37 +1,46 @@
|
|||
from funcy import curry
|
||||
|
||||
from cadCAD.configuration.utils import ep_time_step, time_step
|
||||
|
||||
|
||||
def increment(y, incr_by):
|
||||
return lambda _g, step, sL, s, _input: (y, s[y] + incr_by)
|
||||
|
||||
|
||||
def track(y):
|
||||
return lambda _g, step, sL, s, _input: (y, s[y].x)
|
||||
|
||||
|
||||
def simple_state_update(y, x):
|
||||
return lambda _g, step, sH, s, _input: (y, x)
|
||||
|
||||
|
||||
def simple_policy_update(y):
|
||||
return lambda _g, step, sH, s: y
|
||||
|
||||
|
||||
def update_timestamp(y, timedelta, format):
|
||||
return lambda _g, step, sL, s, _input: (
|
||||
y,
|
||||
ep_time_step(s, dt_str=s[y], fromat_str=format, _timedelta=timedelta)
|
||||
)
|
||||
|
||||
|
||||
def apply(f, y: str, incr_by: int):
|
||||
return lambda _g, step, sL, s, _input: (y, curry(f)(s[y])(incr_by))
|
||||
|
||||
|
||||
def add(y: str, incr_by):
|
||||
return apply(lambda a, b: a + b, y, incr_by)
|
||||
|
||||
|
||||
def increment_state_by_int(y: str, incr_by: int):
|
||||
return lambda _g, step, sL, s, _input: (y, s[y] + incr_by)
|
||||
|
||||
|
||||
def s(y, x):
|
||||
return lambda _g, step, sH, s, _input: (y, x)
|
||||
|
||||
|
||||
def time_model(y, substeps, time_delta, ts_format='%Y-%m-%d %H:%M:%S'):
|
||||
def apply_incriment_condition(s):
|
||||
if s['substep'] == 0 or s['substep'] == substeps:
|
||||
|
|
@ -40,94 +49,3 @@ def time_model(y, substeps, time_delta, ts_format='%Y-%m-%d %H:%M:%S'):
|
|||
return y, s[y]
|
||||
return lambda _g, step, sL, s, _input: apply_incriment_condition(s)
|
||||
|
||||
|
||||
# ToDo: Impliment Matrix reduction
|
||||
#
|
||||
# [
|
||||
# {'conditions': [123], 'opp': lambda a, b: a and b},
|
||||
# {'conditions': [123], 'opp': lambda a, b: a and b}
|
||||
# ]
|
||||
|
||||
# def trigger_condition2(s, conditions, cond_opp):
|
||||
# # print(conditions)
|
||||
# condition_bools = [s[field] in precondition_values for field, precondition_values in conditions.items()]
|
||||
# return reduce(cond_opp, condition_bools)
|
||||
#
|
||||
# def trigger_multi_conditions(s, multi_conditions, multi_cond_opp):
|
||||
# # print([(d['conditions'], d['reduction_opp']) for d in multi_conditions])
|
||||
# condition_bools = [
|
||||
# trigger_condition2(s, conditions, opp) for conditions, opp in [
|
||||
# (d['conditions'], d['reduction_opp']) for d in multi_conditions
|
||||
# ]
|
||||
# ]
|
||||
# return reduce(multi_cond_opp, condition_bools)
|
||||
#
|
||||
# def apply_state_condition2(multi_conditions, multi_cond_opp, y, f, _g, step, sL, s, _input):
|
||||
# if trigger_multi_conditions(s, multi_conditions, multi_cond_opp):
|
||||
# return f(_g, step, sL, s, _input)
|
||||
# else:
|
||||
# return y, s[y]
|
||||
#
|
||||
# def proc_trigger2(y, f, multi_conditions, multi_cond_opp):
|
||||
# return lambda _g, step, sL, s, _input: apply_state_condition2(multi_conditions, multi_cond_opp, y, f, _g, step, sL, s, _input)
|
||||
#
|
||||
# def timestep_trigger2(end_substep, y, f):
|
||||
# multi_conditions = [
|
||||
# {
|
||||
# 'condition': {
|
||||
# 'substep': [0, end_substep]
|
||||
# },
|
||||
# 'reduction_opp': lambda a, b: a and b
|
||||
# }
|
||||
# ]
|
||||
# multi_cond_opp = lambda a, b: a and b
|
||||
# return proc_trigger2(y, f, multi_conditions, multi_cond_opp)
|
||||
|
||||
#
|
||||
# @curried
|
||||
|
||||
|
||||
|
||||
# print(env_trigger(3).__module__)
|
||||
# pp.pprint(dir(env_trigger))
|
||||
|
||||
|
||||
|
||||
# @curried
|
||||
# def env_proc_trigger(trigger_time, update_f, time):
|
||||
# if time == trigger_time:
|
||||
# return update_f
|
||||
# else:
|
||||
# return lambda x: x
|
||||
|
||||
|
||||
|
||||
|
||||
# def p1m1(_g, step, sL, s):
|
||||
# return {'param1': 1}
|
||||
#
|
||||
# def apply_policy_condition(policies, policy_id, f, conditions, _g, step, sL, s):
|
||||
# if trigger_condition(s, conditions):
|
||||
# policies[policy_id] = f(_g, step, sL, s)
|
||||
# return policies
|
||||
# else:
|
||||
# return policies
|
||||
#
|
||||
# def proc_trigger2(policies, conditions, policy_id, f):
|
||||
# return lambda _g, step, sL, s: apply_policy_condition(policies, policy_id, f, conditions,_g, step, sL, s)
|
||||
|
||||
# policies_updates = {"p1": udo_policyA, "p2": udo_policyB}
|
||||
|
||||
|
||||
# @curried
|
||||
# def proc_trigger(trigger_time, update_f, time):
|
||||
# if time == trigger_time:
|
||||
# return update_f
|
||||
# else:
|
||||
# return lambda x: x
|
||||
|
||||
|
||||
# def repr(_g, step, sL, s, _input):
|
||||
# y = 'z'
|
||||
# x = s['state_udo'].__repr__()
|
||||
# return (y, x)
|
||||
|
|
@ -0,0 +1,91 @@
|
|||
Historical State Access
|
||||
==
|
||||
#### Motivation
|
||||
The current state (values of state variables) is accessed through the `s` list. When the user requires previous state variable values, they may be accessed through the state history list, `sH`. Accessing the state history should be implemented without creating unintended feedback loops on the current state.
|
||||
|
||||
The 3rd parameter of state and policy update functions (labeled as `sH` of type `List[List[dict]]`) provides access to past Partial State Update Block (PSUB) given a negative offset number. `access_block` is used to access past PSUBs (`List[dict]`) from `sH`. For example, an offset of `-2` denotes the second to last PSUB.
|
||||
|
||||
#### Exclusion List
|
||||
Create a list of states to exclude from the reported PSU.
|
||||
```python
|
||||
exclusion_list = [
|
||||
'nonexistent', 'last_x', '2nd_to_last_x', '3rd_to_last_x', '4th_to_last_x'
|
||||
]
|
||||
```
|
||||
##### Example Policy Updates
|
||||
###### Last partial state update
|
||||
```python
|
||||
def last_update(_params, substep, sH, s):
|
||||
return {"last_x": access_block(
|
||||
state_history=sH,
|
||||
target_field="last_x", # Add a field to the exclusion list
|
||||
psu_block_offset=-1,
|
||||
exculsion_list=exclusion_list
|
||||
)
|
||||
}
|
||||
```
|
||||
* Note: Although `target_field` adding a field to the exclusion may seem redundant, it is useful in the case of the exclusion list being empty while the `target_field` is assigned to a state or a policy key.
|
||||
##### Define State Updates
|
||||
###### 2nd to last partial state update
|
||||
```python
|
||||
def second2last_update(_params, substep, sH, s):
|
||||
return {"2nd_to_last_x": access_block(sH, "2nd_to_last_x", -2, exclusion_list)}
|
||||
```
|
||||
|
||||
|
||||
###### 3rd to last partial state update
|
||||
```python
|
||||
def third_to_last_x(_params, substep, sH, s, _input):
|
||||
return '3rd_to_last_x', access_block(sH, "3rd_to_last_x", -3, exclusion_list)
|
||||
```
|
||||
###### 4rd to last partial state update
|
||||
```python
|
||||
def fourth_to_last_x(_params, substep, sH, s, _input):
|
||||
return '4th_to_last_x', access_block(sH, "4th_to_last_x", -4, exclusion_list)
|
||||
```
|
||||
###### Non-exsistent partial state update
|
||||
* `psu_block_offset >= 0` doesn't exist
|
||||
```python
|
||||
def nonexistent(_params, substep, sH, s, _input):
|
||||
return 'nonexistent', access_block(sH, "nonexistent", 0, exclusion_list)
|
||||
```
|
||||
|
||||
#### [Example Simulation:](examples/historical_state_access.py)
|
||||
|
||||
|
||||
#### Example Output:
|
||||
###### State History
|
||||
```
|
||||
+----+-------+-----------+------------+-----+
|
||||
| | run | substep | timestep | x |
|
||||
|----+-------+-----------+------------+-----|
|
||||
| 0 | 1 | 0 | 0 | 0 |
|
||||
| 1 | 1 | 1 | 1 | 1 |
|
||||
| 2 | 1 | 2 | 1 | 2 |
|
||||
| 3 | 1 | 3 | 1 | 3 |
|
||||
| 4 | 1 | 1 | 2 | 4 |
|
||||
| 5 | 1 | 2 | 2 | 5 |
|
||||
| 6 | 1 | 3 | 2 | 6 |
|
||||
| 7 | 1 | 1 | 3 | 7 |
|
||||
| 8 | 1 | 2 | 3 | 8 |
|
||||
| 9 | 1 | 3 | 3 | 9 |
|
||||
+----+-------+-----------+------------+-----+
|
||||
```
|
||||
###### Accessed State History:
|
||||
Example: `last_x`
|
||||
```
|
||||
+----+-----------------------------------------------------------------------------------------------------------------------------------------------------+
|
||||
| | last_x |
|
||||
|----+-----------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| 0 | [] |
|
||||
| 1 | [{'x': 0, 'run': 1, 'substep': 0, 'timestep': 0}] |
|
||||
| 2 | [{'x': 0, 'run': 1, 'substep': 0, 'timestep': 0}] |
|
||||
| 3 | [{'x': 0, 'run': 1, 'substep': 0, 'timestep': 0}] |
|
||||
| 4 | [{'x': 1, 'run': 1, 'substep': 1, 'timestep': 1}, {'x': 2, 'run': 1, 'substep': 2, 'timestep': 1}, {'x': 3, 'run': 1, 'substep': 3, 'timestep': 1}] |
|
||||
| 5 | [{'x': 1, 'run': 1, 'substep': 1, 'timestep': 1}, {'x': 2, 'run': 1, 'substep': 2, 'timestep': 1}, {'x': 3, 'run': 1, 'substep': 3, 'timestep': 1}] |
|
||||
| 6 | [{'x': 1, 'run': 1, 'substep': 1, 'timestep': 1}, {'x': 2, 'run': 1, 'substep': 2, 'timestep': 1}, {'x': 3, 'run': 1, 'substep': 3, 'timestep': 1}] |
|
||||
| 7 | [{'x': 4, 'run': 1, 'substep': 1, 'timestep': 2}, {'x': 5, 'run': 1, 'substep': 2, 'timestep': 2}, {'x': 6, 'run': 1, 'substep': 3, 'timestep': 2}] |
|
||||
| 8 | [{'x': 4, 'run': 1, 'substep': 1, 'timestep': 2}, {'x': 5, 'run': 1, 'substep': 2, 'timestep': 2}, {'x': 6, 'run': 1, 'substep': 3, 'timestep': 2}] |
|
||||
| 9 | [{'x': 4, 'run': 1, 'substep': 1, 'timestep': 2}, {'x': 5, 'run': 1, 'substep': 2, 'timestep': 2}, {'x': 6, 'run': 1, 'substep': 3, 'timestep': 2}] |
|
||||
+----+-----------------------------------------------------------------------------------------------------------------------------------------------------+
|
||||
```
|
||||
|
|
@ -0,0 +1,77 @@
|
|||
Policy Aggregation
|
||||
==
|
||||
|
||||
For each Partial State Update, multiple policy dictionaries are aggregated into a single dictionary to be imputted into
|
||||
all state functions using an initial reduction function and optional subsequent map functions.
|
||||
|
||||
#### Aggregate Function Composition:
|
||||
```python
|
||||
# Reduce Function
|
||||
add = lambda a, b: a + b # Used to add policy values of the same key
|
||||
# Map Function
|
||||
mult_by_2 = lambda y: y * 2 # Used to multiply all policy values by 2
|
||||
policy_ops=[add, mult_by_2]
|
||||
```
|
||||
|
||||
##### Example Policy Updates per Partial State Update (PSU)
|
||||
```python
|
||||
def p1_psu1(_params, step, sH, s):
|
||||
return {'policy1': 1}
|
||||
def p2_psu1(_params, step, sH, s):
|
||||
return {'policy2': 2}
|
||||
```
|
||||
* `add` not applicable due to lack of redundant policies
|
||||
* `mult_by_2` applied to all policies
|
||||
* Result: `{'policy1': 2, 'policy2': 4}`
|
||||
|
||||
```python
|
||||
def p1_psu2(_params, step, sH, s):
|
||||
return {'policy1': 2, 'policy2': 2}
|
||||
def p2_psu2(_params, step, sH, s):
|
||||
return {'policy1': 2, 'policy2': 2}
|
||||
```
|
||||
* `add` applicable due to redundant policies
|
||||
* `mult_by_2` applied to all policies
|
||||
* Result: `{'policy1': 8, 'policy2': 8}`
|
||||
|
||||
```python
|
||||
def p1_psu3(_params, step, sH, s):
|
||||
return {'policy1': 1, 'policy2': 2, 'policy3': 3}
|
||||
def p2_psu3(_params, step, sH, s):
|
||||
return {'policy1': 1, 'policy2': 2, 'policy3': 3}
|
||||
```
|
||||
* `add` applicable due to redundant policies
|
||||
* `mult_by_2` applied to all policies
|
||||
* Result: `{'policy1': 4, 'policy2': 8, 'policy3': 12}`
|
||||
|
||||
#### Aggregate Policies using functions
|
||||
```python
|
||||
from cadCAD.configuration import append_configs
|
||||
|
||||
append_configs(
|
||||
sim_configs=???,
|
||||
initial_state=???,
|
||||
partial_state_update_blocks=???,
|
||||
policy_ops=[add, mult_by_2] # Default: [lambda a, b: a + b]
|
||||
)
|
||||
```
|
||||
|
||||
#### Example
|
||||
##### * [System Model Configuration](examples/policy_aggregation.py)
|
||||
##### * Simulation Results:
|
||||
```
|
||||
+----+---------------------------------------------+-------+------+-----------+------------+
|
||||
| | policies | run | s1 | substep | timestep |
|
||||
|----+---------------------------------------------+-------+------+-----------+------------|
|
||||
| 0 | {} | 1 | 0 | 0 | 0 |
|
||||
| 1 | {'policy1': 2, 'policy2': 4} | 1 | 1 | 1 | 1 |
|
||||
| 2 | {'policy1': 8, 'policy2': 8} | 1 | 2 | 2 | 1 |
|
||||
| 3 | {'policy3': 12, 'policy1': 4, 'policy2': 8} | 1 | 3 | 3 | 1 |
|
||||
| 4 | {'policy1': 2, 'policy2': 4} | 1 | 4 | 1 | 2 |
|
||||
| 5 | {'policy1': 8, 'policy2': 8} | 1 | 5 | 2 | 2 |
|
||||
| 6 | {'policy3': 12, 'policy1': 4, 'policy2': 8} | 1 | 6 | 3 | 2 |
|
||||
| 7 | {'policy1': 2, 'policy2': 4} | 1 | 7 | 1 | 3 |
|
||||
| 8 | {'policy1': 8, 'policy2': 8} | 1 | 8 | 2 | 3 |
|
||||
| 9 | {'policy3': 12, 'policy1': 4, 'policy2': 8} | 1 | 9 | 3 | 3 |
|
||||
+----+---------------------------------------------+-------+------+-----------+------------+
|
||||
```
|
||||
|
|
@ -0,0 +1,241 @@
|
|||
Simulation Configuration
|
||||
==
|
||||
|
||||
## Introduction
|
||||
|
||||
Given a **Simulation Configuration**, cadCAD produces datasets that represent the evolution of the state of a system
|
||||
over [discrete time](https://en.wikipedia.org/wiki/Discrete_time_and_continuous_time#Discrete_time). The state of the
|
||||
system is described by a set of [State Variables](#State-Variables). The dynamic of the system is described by
|
||||
[Policy Functions](#Policy-Functions) and [State Update Functions](#State-Update-Functions), which are evaluated by
|
||||
cadCAD according to the definitions set by the user in [Partial State Update Blocks](#Partial-State-Update-Blocks).
|
||||
|
||||
A Simulation Configuration is comprised of a [System Model](#System-Model) and a set of
|
||||
[Simulation Properties](#Simulation-Properties)
|
||||
|
||||
`append_configs`, stores a **Simulation Configuration** to be [Executed](/JS4Q9oayQASihxHBJzz4Ug) by cadCAD
|
||||
|
||||
```python
|
||||
from cadCAD.configuration import append_configs
|
||||
|
||||
append_configs(
|
||||
initial_state = ..., # System Model
|
||||
partial_state_update_blocks = .., # System Model
|
||||
policy_ops = ..., # System Model
|
||||
sim_configs = ... # Simulation Properties
|
||||
)
|
||||
```
|
||||
Parameters:
|
||||
* **initial_state** : _dict_ - [State Variables](#State-Variables) and their initial values
|
||||
* **partial_state_update_blocks** : List[dict[dict]] - List of [Partial State Update Blocks](#Partial-State-Update-Blocks)
|
||||
* **policy_ops** : List[functions] - See [Policy Aggregation](/63k2ncjITuqOPCUHzK7Viw)
|
||||
* **sim_configs** - See [System Model Parameter Sweep](/4oJ_GT6zRWW8AO3yMhFKrg)
|
||||
|
||||
## Simulation Properties
|
||||
|
||||
Simulation properties are passed to `append_configs` in the `sim_configs` parameter. To construct this parameter, we
|
||||
use the `config_sim` function in `cadCAD.configuration.utils`
|
||||
|
||||
```python
|
||||
from cadCAD.configuration.utils import config_sim
|
||||
|
||||
c = config_sim({
|
||||
"N": ...,
|
||||
"T": range(...),
|
||||
"M": ...
|
||||
})
|
||||
|
||||
append_configs(
|
||||
...
|
||||
sim_configs = c # Simulation Properties
|
||||
)
|
||||
```
|
||||
|
||||
### T - Simulation Length
|
||||
Computer simulations run in discrete time:
|
||||
|
||||
>Discrete time views values of variables as occurring at distinct, separate "points in time", or equivalently as being
|
||||
unchanged throughout each non-zero region of time ("time period")—that is, time is viewed as a discrete variable. (...)
|
||||
This view of time corresponds to a digital clock that gives a fixed reading of 10:37 for a while, and then jumps to a
|
||||
new fixed reading of 10:38, etc.
|
||||
([source: Wikipedia](https://en.wikipedia.org/wiki/Discrete_time_and_continuous_time#Discrete_time))
|
||||
|
||||
As is common in many simulation tools, in cadCAD too we refer to each discrete unit of time as a **timestep**. cadCAD
|
||||
increments a "time counter", and at each step it updates the state variables according to the equations that describe
|
||||
the system.
|
||||
|
||||
The main simulation property that the user must set when creating a Simulation Configuration is the number of timesteps
|
||||
in the simulation. In other words, for how long do they want to simulate the system that has been modeled.
|
||||
|
||||
### N - Number of Runs
|
||||
|
||||
cadCAD facilitates running multiple simulations of the same system sequentially, reporting the results of all those
|
||||
runs in a single dataset. This is especially helpful for running
|
||||
[Monte Carlo Simulations](../tutorials/robot-marbles-part-4/robot-marbles-part-4.ipynb).
|
||||
|
||||
### M - Parameters of the System
|
||||
|
||||
Parameters of the system, passed to the state update functions and the policy functions in the `params` parameter are
|
||||
defined here. See [System Model Parameter Sweep](/4oJ_GT6zRWW8AO3yMhFKrg) for more information.
|
||||
|
||||
## System Model
|
||||
The System Model describes the system that will be simulated in cadCAD. It is comprised of a set of
|
||||
[State Variables](###Sate-Variables) and the [State Update Functions](#State-Update-Functions) that determine the
|
||||
evolution of the state of the system over time. [Policy Functions](#Policy-Functions) (representations of user policies
|
||||
or internal system control policies) may also be part of a System Model.
|
||||
|
||||
### State Variables
|
||||
>A state variable is one of the set of variables that are used to describe the mathematical "state" of a dynamical
|
||||
system. Intuitively, the state of a system describes enough about the system to determine its future behaviour in the
|
||||
absence of any external forces affecting the system. ([source: Wikipedia](https://en.wikipedia.org/wiki/State_variable))
|
||||
|
||||
cadCAD can handle state variables of any Python data type, including custom classes. It is up to the user of cadCAD to
|
||||
determine the state variables needed to **sufficiently and accurately** describe the system they are interested in.
|
||||
|
||||
State Variables are passed to `append_configs` along with its initial values, as a Python `dict` where the `dict_keys`
|
||||
are the names of the variables and the `dict_values` are their initial values.
|
||||
|
||||
```python
|
||||
from cadCAD.configuration import append_configs
|
||||
|
||||
genesis_states = {
|
||||
'state_variable_1': 0,
|
||||
'state_variable_2': 0,
|
||||
'state_variable_3': 1.5,
|
||||
'timestamp': '2019-01-01 00:00:00'
|
||||
}
|
||||
|
||||
append_configs(
|
||||
initial_state = genesis_states,
|
||||
...
|
||||
)
|
||||
```
|
||||
### State Update Functions
|
||||
State Update Functions represent equations according to which the state variables change over time. Each state update
|
||||
function must return a tuple containing a string with the name of the state variable being updated and its new value.
|
||||
Each state update function can only modify a single state variable. The general structure of a state update function is:
|
||||
```python
|
||||
def state_update_function_A(_params, substep, sH, s, _input):
|
||||
...
|
||||
return 'state_variable_name', new_value
|
||||
```
|
||||
Parameters:
|
||||
* **_params** : _dict_ - [System parameters](/4oJ_GT6zRWW8AO3yMhFKrg)
|
||||
* **substep** : _int_ - Current [substep](#Substep)
|
||||
* **sH** : _list[list[dict_]] - Historical values of all state variables for the simulation. See
|
||||
[Historical State Access](/smiyQTnATtC9xPwvF8KbBQ) for details
|
||||
* **s** : _dict_ - Current state of the system, where the `dict_keys` are the names of the state variables and the
|
||||
`dict_values` are their current values.
|
||||
* **_input** : _dict_ - Aggregation of the signals of all policy functions in the current
|
||||
[Partial State Update Block](#Partial-State-Update-Block)
|
||||
|
||||
Return:
|
||||
* _tuple_ containing a string with the name of the state variable being updated and its new value.
|
||||
|
||||
State update functions should not modify any of the parameters passed to it, as those are mutable Python objects that
|
||||
cadCAD relies on in order to run the simulation according to the specifications.
|
||||
|
||||
### Policy Functions
|
||||
A Policy Function computes one or more signals to be passed to [State Update Functions](#State-Update-Functions)
|
||||
(via the _\_input_ parameter). Read
|
||||
[this article](../tutorials/robot-marbles-part-2/robot-marbles-part-2.ipynb)
|
||||
for details on why and when to use policy functions.
|
||||
|
||||
<!-- We would then expand the tutorials with these kind of concepts
|
||||
#### Policies
|
||||
Policies consist of the potential action made available through mechanisms. The action taken is expected to be the
|
||||
result of a conditional determination of the past state.
|
||||
|
||||
While executed the same, the modeller can approach policies dependent on the availability of a mechanism to a population.
|
||||
|
||||
- ***Control Policy***
|
||||
When the controlling or deploying entity has the ability to act in order to affect some aspect of the system, this is a
|
||||
control policy.
|
||||
- ***User Policy*** 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.
|
||||
The action taken, as well as the potential to act, through a mechanism is a behavior. -->
|
||||
|
||||
The general structure of a policy function is:
|
||||
```python
|
||||
def policy_function_1(_params, substep, sH, s):
|
||||
...
|
||||
return {'signal_1': value_1, ..., 'signal_N': value_N}
|
||||
```
|
||||
Parameters:
|
||||
* **_params** : _dict_ - [System parameters](/4oJ_GT6zRWW8AO3yMhFKrg)
|
||||
* **substep** : _int_ - Current [substep](#Substep)
|
||||
* **sH** : _list[list[dict_]] - Historical values of all state variables for the simulation. See
|
||||
[Historical State Access](/smiyQTnATtC9xPwvF8KbBQ) for details
|
||||
* **s** : _dict_ - Current state of the system, where the `dict_keys` are the names of the state variables and the
|
||||
`dict_values` are their current values.
|
||||
|
||||
Return:
|
||||
* _dict_ of signals to be passed to the state update functions in the same
|
||||
[Partial State Update Block](#Partial-State-Update-Blocks)
|
||||
|
||||
Policy functions should not modify any of the parameters passed to it, as those are mutable Python objects that cadCAD
|
||||
relies on in order to run the simulation according to the specifications.
|
||||
|
||||
At each [Partial State Update Block](#Partial-State-Update-Blocks) (PSUB), the `dicts` returned by all policy functions
|
||||
within that PSUB dictionaries are aggregated into a single `dict` using an initial reduction function
|
||||
(a key-wise operation, default: `dic1['keyA'] + dic2['keyA']`) and optional subsequent map functions. The resulting
|
||||
aggregated `dict` is then passed as the `_input` parameter to the state update functions in that PSUB. For more
|
||||
information on how to modify the aggregation method, see [Policy Aggregation](/63k2ncjITuqOPCUHzK7Viw).
|
||||
|
||||
### Partial State Update Blocks
|
||||
|
||||
A **Partial State Update Block** (PSUB) is a set of State Update Functions and Policy Functions such that State Update
|
||||
Functions in the set are independent from each other and Policies in the set are independent from each other and from
|
||||
the State Update Functions in the set. In other words, if a state variable is updated in a PSUB, its new value cannot
|
||||
impact the State Update Functions and Policy Functions in that PSUB - only those in the next PSUB.
|
||||
|
||||

|
||||
|
||||
Partial State Update Blocks are passed to `append_configs` as a List of Python `dicts` where the `dict_keys` are named
|
||||
`"policies"` and `"variables"` and the values are also Python `dicts` where the keys are the names of the policy and
|
||||
state update functions and the values are the functions.
|
||||
|
||||
```python
|
||||
PSUBs = [
|
||||
{
|
||||
"policies": {
|
||||
"b_1": policy_function_1,
|
||||
...
|
||||
"b_J": policy_function_J
|
||||
},
|
||||
"variables": {
|
||||
"s_1": state_update_function_1,
|
||||
...
|
||||
"s_K": state_update_function_K
|
||||
}
|
||||
}, #PSUB_1,
|
||||
{...}, #PSUB_2,
|
||||
...
|
||||
{...} #PSUB_M
|
||||
]
|
||||
|
||||
append_configs(
|
||||
...
|
||||
partial_state_update_blocks = PSUBs,
|
||||
...
|
||||
)
|
||||
|
||||
```
|
||||
|
||||
#### Substep
|
||||
At each timestep, cadCAD iterates over the `partial_state_update_blocks` list. For each Partial State Update Block,
|
||||
cadCAD returns a record containing the state of the system at the end of that PSUB. We refer to that subdivision of a
|
||||
timestep as a `substep`.
|
||||
|
||||
## Result Dataset
|
||||
|
||||
cadCAD returns a dataset containing the evolution of the state variables defined by the user over time, with three `int`
|
||||
indexes:
|
||||
* `run` - id of the [run](#N-Number-of-Runs)
|
||||
* `timestep` - discrete unit of time (the total number of timesteps is defined by the user in the
|
||||
[T Simulation Parameter](#T-Simulation-Length))
|
||||
* `substep` - subdivision of timestep (the number of [substeps](#Substeps) is the same as the number of Partial State
|
||||
Update Blocks)
|
||||
|
||||
Therefore, the total number of records in the resulting dataset is `N` x `T` x `len(partial_state_update_blocks)`
|
||||
|
||||
#### [System Simulation Execution](Simulation_Execution.md)
|
||||
|
|
@ -0,0 +1,160 @@
|
|||
Simulation Execution
|
||||
==
|
||||
System Simulations are executed with the execution engine executor (`cadCAD.engine.Executor`) given System Model
|
||||
Configurations. There are multiple simulation Execution Modes and Execution Contexts.
|
||||
|
||||
### Steps:
|
||||
1. #### *Choose Execution Mode*:
|
||||
* ##### Simulation Execution Modes:
|
||||
`cadCAD` executes a process per System Model Configuration and a thread per System Simulation.
|
||||
##### Class: `cadCAD.engine.ExecutionMode`
|
||||
##### Attributes:
|
||||
* **Single Process:** A single process Execution Mode for a single System Model Configuration (Example:
|
||||
`cadCAD.engine.ExecutionMode().single_proc`).
|
||||
* **Multi-Process:** Multiple process Execution Mode for System Model Simulations which executes on a thread per
|
||||
given System Model Configuration (Example: `cadCAD.engine.ExecutionMode().multi_proc`).
|
||||
2. #### *Create Execution Context using Execution Mode:*
|
||||
```python
|
||||
from cadCAD.engine import ExecutionMode, ExecutionContext
|
||||
exec_mode = ExecutionMode()
|
||||
single_proc_ctx = ExecutionContext(context=exec_mode.single_proc)
|
||||
```
|
||||
3. #### *Create Simulation Executor*
|
||||
```python
|
||||
from cadCAD.engine import Executor
|
||||
from cadCAD import configs
|
||||
simulation = Executor(exec_context=single_proc_ctx, configs=configs)
|
||||
```
|
||||
4. #### *Execute Simulation: Produce System Event Dataset*
|
||||
A Simulation execution produces a System Event Dataset and the Tensor Field applied to initial states used to create it.
|
||||
```python
|
||||
import pandas as pd
|
||||
raw_system_events, tensor_field = simulation.execute()
|
||||
|
||||
# Simulation Result Types:
|
||||
# raw_system_events: List[dict]
|
||||
# tensor_field: pd.DataFrame
|
||||
|
||||
# Result System Events DataFrame
|
||||
simulation_result = pd.DataFrame(raw_system_events)
|
||||
```
|
||||
|
||||
##### Example Tensor Field
|
||||
```
|
||||
+----+-----+--------------------------------+--------------------------------+
|
||||
| | m | b1 | s1 |
|
||||
|----+-----+--------------------------------+--------------------------------|
|
||||
| 0 | 1 | <function p1m1 at 0x10c458ea0> | <function s1m1 at 0x10c464510> |
|
||||
| 1 | 2 | <function p1m2 at 0x10c464048> | <function s1m2 at 0x10c464620> |
|
||||
| 2 | 3 | <function p1m3 at 0x10c464400> | <function s1m3 at 0x10c464730> |
|
||||
+----+-----+--------------------------------+--------------------------------+
|
||||
```
|
||||
|
||||
##### Example Result: System Events DataFrame
|
||||
```
|
||||
+----+-------+------------+-----------+------+-----------+
|
||||
| | run | timestep | substep | s1 | s2 |
|
||||
|----+-------+------------+-----------+------+-----------|
|
||||
| 0 | 1 | 0 | 0 | 0 | 0.0 |
|
||||
| 1 | 1 | 1 | 1 | 1 | 4 |
|
||||
| 2 | 1 | 1 | 2 | 2 | 6 |
|
||||
| 3 | 1 | 1 | 3 | 3 | [ 30 300] |
|
||||
| 4 | 2 | 0 | 0 | 0 | 0.0 |
|
||||
| 5 | 2 | 1 | 1 | 1 | 4 |
|
||||
| 6 | 2 | 1 | 2 | 2 | 6 |
|
||||
| 7 | 2 | 1 | 3 | 3 | [ 30 300] |
|
||||
+----+-------+------------+-----------+------+-----------+
|
||||
```
|
||||
|
||||
### Execution Examples:
|
||||
##### Single Simulation Execution (Single Process Execution)
|
||||
Example System Model Configurations:
|
||||
* [System Model A](examples/sys_model_A.py): `/documentation/examples/sys_model_A.py`
|
||||
* [System Model B](examples/sys_model_B.py): `/documentation/examples/sys_model_B.py`
|
||||
Example Simulation Executions:
|
||||
* [System Model A](examples/sys_model_A_exec.py): `/documentation/examples/sys_model_A_exec.py`
|
||||
* [System Model B](examples/sys_model_B_exec.py): `/documentation/examples/sys_model_B_exec.py`
|
||||
```python
|
||||
import pandas as pd
|
||||
from tabulate import tabulate
|
||||
from cadCAD.engine import ExecutionMode, ExecutionContext, Executor
|
||||
from documentation.examples import sys_model_A
|
||||
from cadCAD import configs
|
||||
|
||||
exec_mode = ExecutionMode()
|
||||
|
||||
# Single Process Execution using a Single System Model Configuration:
|
||||
# sys_model_A
|
||||
sys_model_A = [configs[0]] # sys_model_A
|
||||
single_proc_ctx = ExecutionContext(context=exec_mode.single_proc)
|
||||
sys_model_A_simulation = Executor(exec_context=single_proc_ctx, configs=sys_model_A)
|
||||
|
||||
sys_model_A_raw_result, sys_model_A_tensor_field = sys_model_A_simulation.execute()
|
||||
sys_model_A_result = pd.DataFrame(sys_model_A_raw_result)
|
||||
print()
|
||||
print("Tensor Field: sys_model_A")
|
||||
print(tabulate(sys_model_A_tensor_field, headers='keys', tablefmt='psql'))
|
||||
print("Result: System Events DataFrame")
|
||||
print(tabulate(sys_model_A_result, headers='keys', tablefmt='psql'))
|
||||
print()
|
||||
```
|
||||
|
||||
##### Multiple Simulation Execution
|
||||
|
||||
* ##### *Multi Process Execution*
|
||||
Documentation: Simulation Execution
|
||||
[Example Simulation Executions::](examples/sys_model_AB_exec.py) `/documentation/examples/sys_model_AB_exec.py`
|
||||
Example System Model Configurations:
|
||||
* [System Model A](examples/sys_model_A.py): `/documentation/examples/sys_model_A.py`
|
||||
* [System Model B](examples/sys_model_B.py): `/documentation/examples/sys_model_B.py`
|
||||
```python
|
||||
import pandas as pd
|
||||
from tabulate import tabulate
|
||||
from cadCAD.engine import ExecutionMode, ExecutionContext, Executor
|
||||
from documentation.examples import sys_model_A, sys_model_B
|
||||
from cadCAD import configs
|
||||
|
||||
exec_mode = ExecutionMode()
|
||||
|
||||
# # Multiple Processes Execution using Multiple System Model Configurations:
|
||||
# # sys_model_A & sys_model_B
|
||||
multi_proc_ctx = ExecutionContext(context=exec_mode.multi_proc)
|
||||
sys_model_AB_simulation = Executor(exec_context=multi_proc_ctx, configs=configs)
|
||||
|
||||
i = 0
|
||||
config_names = ['sys_model_A', 'sys_model_B']
|
||||
for sys_model_AB_raw_result, sys_model_AB_tensor_field in sys_model_AB_simulation.execute():
|
||||
sys_model_AB_result = pd.DataFrame(sys_model_AB_raw_result)
|
||||
print()
|
||||
print(f"Tensor Field: {config_names[i]}")
|
||||
print(tabulate(sys_model_AB_tensor_field, headers='keys', tablefmt='psql'))
|
||||
print("Result: System Events DataFrame:")
|
||||
print(tabulate(sys_model_AB_result, headers='keys', tablefmt='psql'))
|
||||
print()
|
||||
i += 1
|
||||
```
|
||||
|
||||
* ##### [*System Model Parameter Sweep*](System_Model_Parameter_Sweep.md)
|
||||
|
||||
[Example:](examples/param_sweep.py) `/documentation/examples/param_sweep.py`
|
||||
```python
|
||||
import pandas as pd
|
||||
from tabulate import tabulate
|
||||
# The following imports NEED to be in the exact order
|
||||
from cadCAD.engine import ExecutionMode, ExecutionContext, Executor
|
||||
from documentation.examples import param_sweep
|
||||
from cadCAD import configs
|
||||
|
||||
exec_mode = ExecutionMode()
|
||||
multi_proc_ctx = ExecutionContext(context=exec_mode.multi_proc)
|
||||
run = Executor(exec_context=multi_proc_ctx, configs=configs)
|
||||
|
||||
for raw_result, tensor_field in run.execute():
|
||||
result = pd.DataFrame(raw_result)
|
||||
print()
|
||||
print("Tensor Field:")
|
||||
print(tabulate(tensor_field, headers='keys', tablefmt='psql'))
|
||||
print("Output:")
|
||||
print(tabulate(result, headers='keys', tablefmt='psql'))
|
||||
print()
|
||||
```
|
||||
|
|
@ -0,0 +1,72 @@
|
|||
System Model Parameter Sweep
|
||||
==
|
||||
Parametrization of a System Model configuration that produces multiple configurations.
|
||||
|
||||
##### Set Parameters
|
||||
```python
|
||||
params = {
|
||||
'alpha': [1],
|
||||
'beta': [2, 5],
|
||||
'gamma': [3, 4],
|
||||
'omega': [7]
|
||||
}
|
||||
```
|
||||
The parameters above produce 2 simulations.
|
||||
* Simulation 1:
|
||||
* `alpha = 1`
|
||||
* `beta = 2`
|
||||
* `gamma = 3`
|
||||
* `omega = 7`
|
||||
* Simulation 2:
|
||||
* `alpha = 1`
|
||||
* `beta = 5`
|
||||
* `gamma = 4`
|
||||
* `omega = 7`
|
||||
|
||||
All parameters can also be set to include a single parameter each, which will result in a single simulation.
|
||||
|
||||
##### Example State Updates
|
||||
|
||||
Previous State:
|
||||
`y = 0`
|
||||
|
||||
```python
|
||||
def state_update(_params, step, sH, s, _input):
|
||||
y = 'state'
|
||||
x = s['state'] + _params['alpha'] + _params['gamma']
|
||||
return y, x
|
||||
```
|
||||
* Updated State:
|
||||
* Simulation 1: `y = 4 = 0 + 1 + 3`
|
||||
* Simulation 2: `y = 5 = 0 + 1 + 4`
|
||||
|
||||
##### Example Policy Updates
|
||||
```python
|
||||
# Internal States per Mechanism
|
||||
def policies(_params, step, sH, s):
|
||||
return {'beta': _params['beta'], 'gamma': _params['gamma']}
|
||||
```
|
||||
* Simulation 1: `{'beta': 2, 'gamma': 3]}`
|
||||
* Simulation 2: `{'beta': 5, 'gamma': 4}`
|
||||
|
||||
##### Configure Simulation
|
||||
```python
|
||||
from cadCAD.configuration.utils import config_sim
|
||||
|
||||
g = {
|
||||
'alpha': [1],
|
||||
'beta': [2, 5],
|
||||
'gamma': [3, 4],
|
||||
'omega': [7]
|
||||
}
|
||||
|
||||
sim_config = config_sim(
|
||||
{
|
||||
"N": 2,
|
||||
"T": range(5),
|
||||
"M": g,
|
||||
}
|
||||
)
|
||||
```
|
||||
#### Example
|
||||
##### * [System Model Configuration](examples/param_sweep.py)
|
||||
|
|
@ -0,0 +1,45 @@
|
|||
from pprint import pprint
|
||||
|
||||
import pandas as pd
|
||||
from tabulate import tabulate
|
||||
from cadCAD.engine import ExecutionMode, ExecutionContext, Executor
|
||||
from documentation.examples import sys_model_A, sys_model_B
|
||||
from cadCAD import configs
|
||||
|
||||
exec_mode = ExecutionMode()
|
||||
|
||||
# Single Process Execution using a Single System Model Configuration:
|
||||
# sys_model_A
|
||||
sys_model_A = [configs[0]]
|
||||
single_proc_ctx = ExecutionContext(context=exec_mode.single_proc)
|
||||
sys_model_A_simulation = Executor(exec_context=single_proc_ctx, configs=sys_model_A)
|
||||
|
||||
sys_model_A_raw_result, sys_model_A_tensor_field = sys_model_A_simulation.execute()
|
||||
sys_model_A_result = pd.DataFrame(sys_model_A_raw_result)
|
||||
print()
|
||||
print("Tensor Field: sys_model_A")
|
||||
print(tabulate(sys_model_A_tensor_field, headers='keys', tablefmt='psql'))
|
||||
print("Result: System Events DataFrame")
|
||||
print(tabulate(sys_model_A_result, headers='keys', tablefmt='psql'))
|
||||
print()
|
||||
|
||||
# # Multiple Processes Execution using Multiple System Model Configurations:
|
||||
# # sys_model_A & sys_model_B
|
||||
multi_proc_ctx = ExecutionContext(context=exec_mode.multi_proc)
|
||||
sys_model_AB_simulation = Executor(exec_context=multi_proc_ctx, configs=configs)
|
||||
|
||||
|
||||
|
||||
i = 0
|
||||
config_names = ['sys_model_A', 'sys_model_B']
|
||||
for sys_model_AB_raw_result, sys_model_AB_tensor_field in sys_model_AB_simulation.execute():
|
||||
print()
|
||||
pprint(sys_model_AB_raw_result)
|
||||
# sys_model_AB_result = pd.DataFrame(sys_model_AB_raw_result)
|
||||
print()
|
||||
print(f"Tensor Field: {config_names[i]}")
|
||||
print(tabulate(sys_model_AB_tensor_field, headers='keys', tablefmt='psql'))
|
||||
# print("Result: System Events DataFrame:")
|
||||
# print(tabulate(sys_model_AB_result, headers='keys', tablefmt='psql'))
|
||||
# print()
|
||||
i += 1
|
||||
|
|
@ -0,0 +1,110 @@
|
|||
import pandas as pd
|
||||
from tabulate import tabulate
|
||||
from cadCAD.configuration import append_configs
|
||||
from cadCAD.configuration.utils import config_sim, access_block
|
||||
from cadCAD.engine import ExecutionMode, ExecutionContext, Executor
|
||||
from cadCAD import configs
|
||||
|
||||
|
||||
policies, variables = {}, {}
|
||||
exclusion_list = ['nonexsistant', 'last_x', '2nd_to_last_x', '3rd_to_last_x', '4th_to_last_x']
|
||||
|
||||
# Policies per Mechanism
|
||||
|
||||
# state_history, target_field, psu_block_offset, exculsion_list
|
||||
def last_update(_g, substep, sH, s):
|
||||
return {"last_x": access_block(
|
||||
state_history=sH,
|
||||
target_field="last_x",
|
||||
psu_block_offset=-1,
|
||||
exculsion_list=exclusion_list
|
||||
)
|
||||
}
|
||||
policies["last_x"] = last_update
|
||||
|
||||
def second2last_update(_g, substep, sH, s):
|
||||
return {"2nd_to_last_x": access_block(sH, "2nd_to_last_x", -2, exclusion_list)}
|
||||
policies["2nd_to_last_x"] = second2last_update
|
||||
|
||||
|
||||
# Internal States per Mechanism
|
||||
|
||||
# WARNING: DO NOT delete elements from sH
|
||||
def add(y, x):
|
||||
return lambda _g, substep, sH, s, _input: (y, s[y] + x)
|
||||
variables['x'] = add('x', 1)
|
||||
|
||||
# last_partial_state_update_block
|
||||
def nonexsistant(_g, substep, sH, s, _input):
|
||||
return 'nonexsistant', access_block(sH, "nonexsistant", 0, exclusion_list)
|
||||
variables['nonexsistant'] = nonexsistant
|
||||
|
||||
# last_partial_state_update_block
|
||||
def last_x(_g, substep, sH, s, _input):
|
||||
return 'last_x', _input["last_x"]
|
||||
variables['last_x'] = last_x
|
||||
|
||||
# 2nd to last partial state update block
|
||||
def second_to_last_x(_g, substep, sH, s, _input):
|
||||
return '2nd_to_last_x', _input["2nd_to_last_x"]
|
||||
variables['2nd_to_last_x'] = second_to_last_x
|
||||
|
||||
# 3rd to last partial state update block
|
||||
def third_to_last_x(_g, substep, sH, s, _input):
|
||||
return '3rd_to_last_x', access_block(sH, "3rd_to_last_x", -3, exclusion_list)
|
||||
variables['3rd_to_last_x'] = third_to_last_x
|
||||
|
||||
# 4th to last partial state update block
|
||||
def fourth_to_last_x(_g, substep, sH, s, _input):
|
||||
return '4th_to_last_x', access_block(sH, "4th_to_last_x", -4, exclusion_list)
|
||||
variables['4th_to_last_x'] = fourth_to_last_x
|
||||
|
||||
|
||||
genesis_states = {
|
||||
'x': 0,
|
||||
'nonexsistant': [],
|
||||
'last_x': [],
|
||||
'2nd_to_last_x': [],
|
||||
'3rd_to_last_x': [],
|
||||
'4th_to_last_x': []
|
||||
}
|
||||
|
||||
PSUB = {
|
||||
"policies": policies,
|
||||
"variables": variables
|
||||
}
|
||||
|
||||
psubs = {
|
||||
"PSUB1": PSUB,
|
||||
"PSUB2": PSUB,
|
||||
"PSUB3": PSUB
|
||||
}
|
||||
|
||||
sim_config = config_sim(
|
||||
{
|
||||
"N": 1,
|
||||
"T": range(3),
|
||||
}
|
||||
)
|
||||
|
||||
append_configs(
|
||||
sim_configs=sim_config,
|
||||
initial_state=genesis_states,
|
||||
partial_state_update_blocks=psubs
|
||||
)
|
||||
|
||||
exec_mode = ExecutionMode()
|
||||
single_proc_ctx = ExecutionContext(context=exec_mode.single_proc)
|
||||
run = Executor(exec_context=single_proc_ctx, configs=configs)
|
||||
|
||||
raw_result, tensor_field = run.execute()
|
||||
result = pd.DataFrame(raw_result)
|
||||
cols = ['run','substep','timestep','x','nonexsistant','last_x','2nd_to_last_x','3rd_to_last_x','4th_to_last_x']
|
||||
result = result[cols]
|
||||
|
||||
print()
|
||||
print("Tensor Field:")
|
||||
print(tabulate(tensor_field, headers='keys', tablefmt='psql'))
|
||||
print("Output:")
|
||||
print(tabulate(result, headers='keys', tablefmt='psql'))
|
||||
print()
|
||||
|
|
@ -0,0 +1,116 @@
|
|||
import pprint
|
||||
from typing import Dict, List
|
||||
|
||||
import pandas as pd
|
||||
from tabulate import tabulate
|
||||
|
||||
from cadCAD.configuration import append_configs
|
||||
from cadCAD.configuration.utils import env_trigger, var_substep_trigger, config_sim, psub_list
|
||||
from cadCAD.engine import ExecutionMode, ExecutionContext, Executor
|
||||
from cadCAD import configs
|
||||
|
||||
pp = pprint.PrettyPrinter(indent=4)
|
||||
|
||||
|
||||
def some_function(x):
|
||||
return x
|
||||
|
||||
|
||||
g: Dict[str, List[int]] = {
|
||||
'alpha': [1],
|
||||
'beta': [2, 5],
|
||||
'gamma': [3, 4],
|
||||
'omega': [some_function]
|
||||
}
|
||||
|
||||
psu_steps = ['1', '2', '3']
|
||||
system_substeps = len(psu_steps)
|
||||
var_timestep_trigger = var_substep_trigger([0, system_substeps])
|
||||
env_timestep_trigger = env_trigger(system_substeps)
|
||||
env_process = {}
|
||||
|
||||
|
||||
# Policies
|
||||
def gamma(_params, step, sH, s):
|
||||
return {'gamma': _params['gamma']}
|
||||
|
||||
|
||||
def omega(_params, step, sH, s):
|
||||
return {'omega': _params['omega'](7)}
|
||||
|
||||
|
||||
# Internal States
|
||||
def alpha(_params, step, sH, s, _input):
|
||||
return 'alpha', _params['alpha']
|
||||
|
||||
def alpha_plus_gamma(_params, step, sH, s, _input):
|
||||
return 'alpha_plus_gamma', _params['alpha'] + _params['gamma']
|
||||
|
||||
|
||||
def beta(_params, step, sH, s, _input):
|
||||
return 'beta', _params['beta']
|
||||
|
||||
|
||||
def policies(_params, step, sH, s, _input):
|
||||
return 'policies', _input
|
||||
|
||||
|
||||
def sweeped(_params, step, sH, s, _input):
|
||||
return 'sweeped', {'beta': _params['beta'], 'gamma': _params['gamma']}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
genesis_states = {
|
||||
'alpha_plus_gamma': 0,
|
||||
'alpha': 0,
|
||||
'beta': 0,
|
||||
'policies': {},
|
||||
'sweeped': {}
|
||||
}
|
||||
|
||||
env_process['sweeped'] = env_timestep_trigger(trigger_field='timestep', trigger_vals=[5], funct_list=[lambda _g, x: _g['beta']])
|
||||
|
||||
sim_config = config_sim(
|
||||
{
|
||||
"N": 2,
|
||||
"T": range(5),
|
||||
"M": g,
|
||||
}
|
||||
)
|
||||
|
||||
psu_block = {k: {"policies": {}, "variables": {}} for k in psu_steps}
|
||||
for m in psu_steps:
|
||||
psu_block[m]['policies']['gamma'] = gamma
|
||||
psu_block[m]['policies']['omega'] = omega
|
||||
psu_block[m]["variables"]['alpha'] = alpha_plus_gamma
|
||||
psu_block[m]["variables"]['alpha_plus_gamma'] = alpha
|
||||
psu_block[m]["variables"]['beta'] = beta
|
||||
psu_block[m]['variables']['policies'] = policies
|
||||
psu_block[m]["variables"]['sweeped'] = var_timestep_trigger(y='sweeped', f=sweeped)
|
||||
|
||||
psubs = psub_list(psu_block, psu_steps)
|
||||
print()
|
||||
pp.pprint(psu_block)
|
||||
print()
|
||||
|
||||
append_configs(
|
||||
sim_configs=sim_config,
|
||||
initial_state=genesis_states,
|
||||
env_processes=env_process,
|
||||
partial_state_update_blocks=psubs
|
||||
)
|
||||
|
||||
exec_mode = ExecutionMode()
|
||||
multi_proc_ctx = ExecutionContext(context=exec_mode.multi_proc)
|
||||
run = Executor(exec_context=multi_proc_ctx, configs=configs)
|
||||
|
||||
for raw_result, tensor_field in run.execute():
|
||||
result = pd.DataFrame(raw_result)
|
||||
print()
|
||||
print("Tensor Field:")
|
||||
print(tabulate(tensor_field, headers='keys', tablefmt='psql'))
|
||||
print("Output:")
|
||||
print(tabulate(result, headers='keys', tablefmt='psql'))
|
||||
print()
|
||||
|
|
@ -0,0 +1,98 @@
|
|||
import pandas as pd
|
||||
from tabulate import tabulate
|
||||
|
||||
from cadCAD.configuration import append_configs
|
||||
from cadCAD.configuration.utils import config_sim
|
||||
from cadCAD.engine import ExecutionMode, ExecutionContext, Executor
|
||||
from cadCAD import configs
|
||||
|
||||
# Policies per Mechanism
|
||||
def p1m1(_g, step, sH, s):
|
||||
return {'policy1': 1}
|
||||
def p2m1(_g, step, sH, s):
|
||||
return {'policy2': 2}
|
||||
|
||||
def p1m2(_g, step, sH, s):
|
||||
return {'policy1': 2, 'policy2': 2}
|
||||
def p2m2(_g, step, sH, s):
|
||||
return {'policy1': 2, 'policy2': 2}
|
||||
|
||||
def p1m3(_g, step, sH, s):
|
||||
return {'policy1': 1, 'policy2': 2, 'policy3': 3}
|
||||
def p2m3(_g, step, sH, s):
|
||||
return {'policy1': 1, 'policy2': 2, 'policy3': 3}
|
||||
|
||||
|
||||
# Internal States per Mechanism
|
||||
def add(y, x):
|
||||
return lambda _g, step, sH, s, _input: (y, s[y] + x)
|
||||
|
||||
def policies(_g, step, sH, s, _input):
|
||||
y = 'policies'
|
||||
x = _input
|
||||
return (y, x)
|
||||
|
||||
|
||||
# Genesis States
|
||||
genesis_states = {
|
||||
'policies': {},
|
||||
's1': 0
|
||||
}
|
||||
|
||||
variables = {
|
||||
's1': add('s1', 1),
|
||||
"policies": policies
|
||||
}
|
||||
|
||||
psubs = {
|
||||
"m1": {
|
||||
"policies": {
|
||||
"p1": p1m1,
|
||||
"p2": p2m1
|
||||
},
|
||||
"variables": variables
|
||||
},
|
||||
"m2": {
|
||||
"policies": {
|
||||
"p1": p1m2,
|
||||
"p2": p2m2
|
||||
},
|
||||
"variables": variables
|
||||
},
|
||||
"m3": {
|
||||
"policies": {
|
||||
"p1": p1m3,
|
||||
"p2": p2m3
|
||||
},
|
||||
"variables": variables
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
sim_config = config_sim(
|
||||
{
|
||||
"N": 1,
|
||||
"T": range(3),
|
||||
}
|
||||
)
|
||||
|
||||
append_configs(
|
||||
sim_configs=sim_config,
|
||||
initial_state=genesis_states,
|
||||
partial_state_update_blocks=psubs,
|
||||
policy_ops=[lambda a, b: a + b, lambda y: y * 2] # Default: lambda a, b: a + b
|
||||
)
|
||||
|
||||
exec_mode = ExecutionMode()
|
||||
single_proc_ctx = ExecutionContext(context=exec_mode.single_proc)
|
||||
run = Executor(exec_context=single_proc_ctx, configs=configs)
|
||||
|
||||
raw_result, tensor_field = run.execute()
|
||||
result = pd.DataFrame(raw_result)
|
||||
|
||||
print()
|
||||
print("Tensor Field:")
|
||||
print(tabulate(tensor_field, headers='keys', tablefmt='psql'))
|
||||
print("Output:")
|
||||
print(tabulate(result, headers='keys', tablefmt='psql'))
|
||||
print()
|
||||
|
|
@ -0,0 +1,159 @@
|
|||
import numpy as np
|
||||
from datetime import timedelta
|
||||
|
||||
|
||||
from cadCAD.configuration import append_configs
|
||||
from cadCAD.configuration.utils import bound_norm_random, config_sim, time_step, env_trigger
|
||||
|
||||
seeds = {
|
||||
'z': np.random.RandomState(1),
|
||||
'a': np.random.RandomState(2),
|
||||
'b': np.random.RandomState(3),
|
||||
'c': np.random.RandomState(4)
|
||||
}
|
||||
|
||||
|
||||
# Policies per Mechanism
|
||||
def p1m1(_g, step, sH, s):
|
||||
return {'param1': 1}
|
||||
def p2m1(_g, step, sH, s):
|
||||
return {'param1': 1, 'param2': 4}
|
||||
|
||||
def p1m2(_g, step, sH, s):
|
||||
return {'param1': 'a', 'param2': 2}
|
||||
def p2m2(_g, step, sH, s):
|
||||
return {'param1': 'b', 'param2': 4}
|
||||
|
||||
def p1m3(_g, step, sH, s):
|
||||
return {'param1': ['c'], 'param2': np.array([10, 100])}
|
||||
def p2m3(_g, step, sH, s):
|
||||
return {'param1': ['d'], 'param2': np.array([20, 200])}
|
||||
|
||||
|
||||
# Internal States per Mechanism
|
||||
def s1m1(_g, step, sH, s, _input):
|
||||
y = 's1'
|
||||
x = s['s1'] + 1
|
||||
return (y, x)
|
||||
def s2m1(_g, step, sH, s, _input):
|
||||
y = 's2'
|
||||
x = _input['param2']
|
||||
return (y, x)
|
||||
|
||||
def s1m2(_g, step, sH, s, _input):
|
||||
y = 's1'
|
||||
x = s['s1'] + 1
|
||||
return (y, x)
|
||||
def s2m2(_g, step, sH, s, _input):
|
||||
y = 's2'
|
||||
x = _input['param2']
|
||||
return (y, x)
|
||||
|
||||
def s1m3(_g, step, sH, s, _input):
|
||||
y = 's1'
|
||||
x = s['s1'] + 1
|
||||
return (y, x)
|
||||
def s2m3(_g, step, sH, s, _input):
|
||||
y = 's2'
|
||||
x = _input['param2']
|
||||
return (y, x)
|
||||
|
||||
def policies(_g, step, sH, s, _input):
|
||||
y = 'policies'
|
||||
x = _input
|
||||
return (y, x)
|
||||
|
||||
|
||||
# Exogenous States
|
||||
proc_one_coef_A = 0.7
|
||||
proc_one_coef_B = 1.3
|
||||
|
||||
def es3(_g, step, sH, s, _input):
|
||||
y = 's3'
|
||||
x = s['s3'] * bound_norm_random(seeds['a'], proc_one_coef_A, proc_one_coef_B)
|
||||
return (y, x)
|
||||
|
||||
def es4(_g, step, sH, s, _input):
|
||||
y = 's4'
|
||||
x = s['s4'] * bound_norm_random(seeds['b'], proc_one_coef_A, proc_one_coef_B)
|
||||
return (y, x)
|
||||
|
||||
def update_timestamp(_g, step, sH, s, _input):
|
||||
y = 'timestamp'
|
||||
return y, time_step(dt_str=s[y], dt_format='%Y-%m-%d %H:%M:%S', _timedelta=timedelta(days=0, minutes=0, seconds=1))
|
||||
|
||||
|
||||
# Genesis States
|
||||
genesis_states = {
|
||||
's1': 0.0,
|
||||
's2': 0.0,
|
||||
's3': 1.0,
|
||||
's4': 1.0,
|
||||
'timestamp': '2018-10-01 15:16:24'
|
||||
}
|
||||
|
||||
|
||||
# Environment Process
|
||||
# ToDo: Depreciation Waring for env_proc_trigger convention
|
||||
trigger_timestamps = ['2018-10-01 15:16:25', '2018-10-01 15:16:27', '2018-10-01 15:16:29']
|
||||
env_processes = {
|
||||
"s3": [lambda _g, x: 5],
|
||||
"s4": env_trigger(3)(trigger_field='timestamp', trigger_vals=trigger_timestamps, funct_list=[lambda _g, x: 10])
|
||||
}
|
||||
|
||||
|
||||
psubs = [
|
||||
{
|
||||
"policies": {
|
||||
"b1": p1m1,
|
||||
"b2": p2m1
|
||||
},
|
||||
"variables": {
|
||||
"s1": s1m1,
|
||||
"s2": s2m1,
|
||||
"s3": es3,
|
||||
"s4": es4,
|
||||
"timestamp": update_timestamp
|
||||
}
|
||||
},
|
||||
{
|
||||
"policies": {
|
||||
"b1": p1m2,
|
||||
"b2": p2m2
|
||||
},
|
||||
"variables": {
|
||||
"s1": s1m2,
|
||||
"s2": s2m2,
|
||||
# "s3": es3p1,
|
||||
# "s4": es4p2,
|
||||
}
|
||||
},
|
||||
{
|
||||
"policies": {
|
||||
"b1": p1m3,
|
||||
"b2": p2m3
|
||||
},
|
||||
"variables": {
|
||||
"s1": s1m3,
|
||||
"s2": s2m3,
|
||||
# "s3": es3p1,
|
||||
# "s4": es4p2,
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
|
||||
sim_config = config_sim(
|
||||
{
|
||||
"N": 2,
|
||||
"T": range(1),
|
||||
}
|
||||
)
|
||||
|
||||
append_configs(
|
||||
sim_configs=sim_config,
|
||||
initial_state=genesis_states,
|
||||
env_processes=env_processes,
|
||||
partial_state_update_blocks=psubs,
|
||||
policy_ops=[lambda a, b: a + b]
|
||||
)
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
import pandas as pd
|
||||
from tabulate import tabulate
|
||||
from cadCAD.engine import ExecutionMode, ExecutionContext, Executor
|
||||
from documentation.examples import sys_model_A, sys_model_B
|
||||
from cadCAD import configs
|
||||
|
||||
exec_mode = ExecutionMode()
|
||||
|
||||
# # Multiple Processes Execution using Multiple System Model Configurations:
|
||||
# # sys_model_A & sys_model_B
|
||||
multi_proc_ctx = ExecutionContext(context=exec_mode.multi_proc)
|
||||
sys_model_AB_simulation = Executor(exec_context=multi_proc_ctx, configs=configs)
|
||||
|
||||
i = 0
|
||||
config_names = ['sys_model_A', 'sys_model_B']
|
||||
for sys_model_AB_raw_result, sys_model_AB_tensor_field in sys_model_AB_simulation.execute():
|
||||
sys_model_AB_result = pd.DataFrame(sys_model_AB_raw_result)
|
||||
print()
|
||||
print(f"Tensor Field: {config_names[i]}")
|
||||
print(tabulate(sys_model_AB_tensor_field, headers='keys', tablefmt='psql'))
|
||||
print("Result: System Events DataFrame:")
|
||||
print(tabulate(sys_model_AB_result, headers='keys', tablefmt='psql'))
|
||||
print()
|
||||
i += 1
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
import pandas as pd
|
||||
from tabulate import tabulate
|
||||
from cadCAD.engine import ExecutionMode, ExecutionContext, Executor
|
||||
from documentation.examples import sys_model_A
|
||||
from cadCAD import configs
|
||||
|
||||
exec_mode = ExecutionMode()
|
||||
|
||||
# Single Process Execution using a Single System Model Configuration:
|
||||
# sys_model_A
|
||||
sys_model_A = [configs[0]] # sys_model_A
|
||||
single_proc_ctx = ExecutionContext(context=exec_mode.single_proc)
|
||||
sys_model_A_simulation = Executor(exec_context=single_proc_ctx, configs=sys_model_A)
|
||||
|
||||
sys_model_A_raw_result, sys_model_A_tensor_field = sys_model_A_simulation.execute()
|
||||
sys_model_A_result = pd.DataFrame(sys_model_A_raw_result)
|
||||
print()
|
||||
print("Tensor Field: sys_model_A")
|
||||
print(tabulate(sys_model_A_tensor_field, headers='keys', tablefmt='psql'))
|
||||
print("Result: System Events DataFrame")
|
||||
print(tabulate(sys_model_A_result, headers='keys', tablefmt='psql'))
|
||||
print()
|
||||
|
|
@ -0,0 +1,147 @@
|
|||
import numpy as np
|
||||
from datetime import timedelta
|
||||
|
||||
from cadCAD.configuration import append_configs
|
||||
from cadCAD.configuration.utils import bound_norm_random, config_sim, env_trigger, time_step
|
||||
|
||||
seeds = {
|
||||
'z': np.random.RandomState(1),
|
||||
'a': np.random.RandomState(2),
|
||||
'b': np.random.RandomState(3),
|
||||
'c': np.random.RandomState(3)
|
||||
}
|
||||
|
||||
|
||||
# Policies per Mechanism
|
||||
def p1m1(_g, step, sH, s):
|
||||
return {'param1': 1}
|
||||
def p2m1(_g, step, sH, s):
|
||||
return {'param2': 4}
|
||||
|
||||
def p1m2(_g, step, sH, s):
|
||||
return {'param1': 'a', 'param2': 2}
|
||||
def p2m2(_g, step, sH, s):
|
||||
return {'param1': 'b', 'param2': 4}
|
||||
|
||||
def p1m3(_g, step, sH, s):
|
||||
return {'param1': ['c'], 'param2': np.array([10, 100])}
|
||||
def p2m3(_g, step, sH, s):
|
||||
return {'param1': ['d'], 'param2': np.array([20, 200])}
|
||||
|
||||
|
||||
# Internal States per Mechanism
|
||||
def s1m1(_g, step, sH, s, _input):
|
||||
y = 's1'
|
||||
x = _input['param1']
|
||||
return (y, x)
|
||||
def s2m1(_g, step, sH, s, _input):
|
||||
y = 's2'
|
||||
x = _input['param2']
|
||||
return (y, x)
|
||||
|
||||
def s1m2(_g, step, sH, s, _input):
|
||||
y = 's1'
|
||||
x = _input['param1']
|
||||
return (y, x)
|
||||
def s2m2(_g, step, sH, s, _input):
|
||||
y = 's2'
|
||||
x = _input['param2']
|
||||
return (y, x)
|
||||
|
||||
def s1m3(_g, step, sH, s, _input):
|
||||
y = 's1'
|
||||
x = _input['param1']
|
||||
return (y, x)
|
||||
def s2m3(_g, step, sH, s, _input):
|
||||
y = 's2'
|
||||
x = _input['param2']
|
||||
return (y, x)
|
||||
|
||||
|
||||
# Exogenous States
|
||||
proc_one_coef_A = 0.7
|
||||
proc_one_coef_B = 1.3
|
||||
|
||||
def es3(_g, step, sH, s, _input):
|
||||
y = 's3'
|
||||
x = s['s3'] * bound_norm_random(seeds['a'], proc_one_coef_A, proc_one_coef_B)
|
||||
return (y, x)
|
||||
|
||||
def es4(_g, step, sH, s, _input):
|
||||
y = 's4'
|
||||
x = s['s4'] * bound_norm_random(seeds['b'], proc_one_coef_A, proc_one_coef_B)
|
||||
return (y, x)
|
||||
|
||||
def update_timestamp(_g, step, sH, s, _input):
|
||||
y = 'timestamp'
|
||||
return y, time_step(dt_str=s[y], dt_format='%Y-%m-%d %H:%M:%S', _timedelta=timedelta(days=0, minutes=0, seconds=1))
|
||||
|
||||
|
||||
# Genesis States
|
||||
genesis_states = {
|
||||
's1': 0,
|
||||
's2': 0,
|
||||
's3': 1,
|
||||
's4': 1,
|
||||
'timestamp': '2018-10-01 15:16:24'
|
||||
}
|
||||
|
||||
|
||||
# Environment Process
|
||||
# ToDo: Depreciation Waring for env_proc_trigger convention
|
||||
trigger_timestamps = ['2018-10-01 15:16:25', '2018-10-01 15:16:27', '2018-10-01 15:16:29']
|
||||
env_processes = {
|
||||
"s3": [lambda _g, x: 5],
|
||||
"s4": env_trigger(3)(trigger_field='timestamp', trigger_vals=trigger_timestamps, funct_list=[lambda _g, x: 10])
|
||||
}
|
||||
|
||||
psubs = [
|
||||
{
|
||||
"policies": {
|
||||
"b1": p1m1,
|
||||
# "b2": p2m1
|
||||
},
|
||||
"states": {
|
||||
"s1": s1m1,
|
||||
# "s2": s2m1
|
||||
"s3": es3,
|
||||
"s4": es4,
|
||||
"timestep": update_timestamp
|
||||
}
|
||||
},
|
||||
{
|
||||
"policies": {
|
||||
"b1": p1m2,
|
||||
# "b2": p2m2
|
||||
},
|
||||
"states": {
|
||||
"s1": s1m2,
|
||||
# "s2": s2m2
|
||||
}
|
||||
},
|
||||
{
|
||||
"policies": {
|
||||
"b1": p1m3,
|
||||
"b2": p2m3
|
||||
},
|
||||
"states": {
|
||||
"s1": s1m3,
|
||||
"s2": s2m3
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
|
||||
sim_config = config_sim(
|
||||
{
|
||||
"N": 2,
|
||||
"T": range(5),
|
||||
}
|
||||
)
|
||||
|
||||
append_configs(
|
||||
sim_configs=sim_config,
|
||||
initial_state=genesis_states,
|
||||
env_processes=env_processes,
|
||||
partial_state_update_blocks=psubs
|
||||
)
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
import pandas as pd
|
||||
from tabulate import tabulate
|
||||
# The following imports NEED to be in the exact order
|
||||
from cadCAD.engine import ExecutionMode, ExecutionContext, Executor
|
||||
from documentation.examples import sys_model_B
|
||||
from cadCAD import configs
|
||||
|
||||
exec_mode = ExecutionMode()
|
||||
|
||||
print("Simulation Execution: Single Configuration")
|
||||
print()
|
||||
first_config = configs # only contains sys_model_B
|
||||
single_proc_ctx = ExecutionContext(context=exec_mode.single_proc)
|
||||
run = Executor(exec_context=single_proc_ctx, configs=first_config)
|
||||
|
||||
raw_result, tensor_field = run.execute()
|
||||
result = pd.DataFrame(raw_result)
|
||||
print()
|
||||
print("Tensor Field: sys_model_B")
|
||||
print(tabulate(tensor_field, headers='keys', tablefmt='psql'))
|
||||
print("Output:")
|
||||
print(tabulate(result, headers='keys', tablefmt='psql'))
|
||||
print()
|
||||
|
|
@ -1,150 +0,0 @@
|
|||
SOFTWARE LICENSE AGREEMENT
|
||||
|
||||
This Software License Agreement (the “Agreement”) is entered into as of December __ 2018, (the “Effective Date”) between
|
||||
Dapper Labs, Inc., a Canadian corporation having its principal place of business at 980-350 Howe Street,
|
||||
Vancouver, BC V6Z 1N9 (“DLI”) and BlockScience, Inc., a California corporation with an address at 471 McAuley Street,
|
||||
Oakland, CA 94609 (“BlockScience”). This Agreement includes the attached Exhibit A.
|
||||
|
||||
WHEREAS, DLI and BlockScience are parties to that certain Professional Services Agreement dated March 23, 2018 (the
|
||||
“PSA”), pursuant to which BlockScience performed and is currently performing professional services and other development
|
||||
work for DLI;
|
||||
|
||||
WHEREAS, as part of BlockScience’s performance under the PSA, BlockScience developed certain “behaviour archetypes” and
|
||||
“configuration of the Null Model”, which the parties agree are “Work Product” under the PSA;
|
||||
|
||||
WHEREAS, the parties agree that BlockScience’s proprietary SimCAD software tool is considered “Contractor Technology”
|
||||
under the PSA; and
|
||||
|
||||
WHEREAS, the parties wish to enter into this Agreement to clarify DLI’s rights to use the SimCAD software tool on a
|
||||
going-forward basis.
|
||||
|
||||
NOW, THEREFORE, for good and valuable consideration, the receipt and sufficiency of which is hereby acknowledged, DLI
|
||||
and BlockScience agree as follows:
|
||||
|
||||
1. DEFINITIONS
|
||||
|
||||
(a) “Affiliate” means any entity that, directly or indirectly through one or more intermediaries, controls, is
|
||||
controlled by, or is under common control with, DLI.
|
||||
|
||||
(b) “Documentation” means any manuals, documentation and other supporting materials related to the Software.
|
||||
Documentation is considered part of the related Software.
|
||||
|
||||
(c) “Intellectual Property Rights” means patent rights (including patent applications and disclosures), copyrights,
|
||||
trade marks, trade secrets, know-how and any other intellectual property rights recognized in any country or
|
||||
jurisdiction in the world.
|
||||
|
||||
(d) “Software” means the object and source code versions of BlockScience’s proprietary SimCAD software product more
|
||||
fully described in Exhibit A. Software includes the applicable Documentation, as well as any Updates.
|
||||
|
||||
(e) “Update” means any bug fix, error correction, patch, modification, enhancement, update, upgrade, replacement,
|
||||
successor product, new version, new release, or derivative work of or to the Software.
|
||||
|
||||
(f) “Zeus” means the decentralized synchronous computational network developed by DLI, as such name or reference may be
|
||||
changed from time to time at DLI’s sole discretion.
|
||||
|
||||
2. SOFTWARE LICENSE
|
||||
|
||||
(a) License Grant. BlockScience hereby grants to DLI and its Affiliates a worldwide, non-exclusive, royalty-free,
|
||||
irrevocable, perpetual license to (i) download, install, use, execute, access, copy, perform, and modify, the Software
|
||||
in connection with the Zeus project; (ii) distribute and display the Software internally amongst DLI and its Affiliates,
|
||||
its and their employees, contractors, and agents, subject to the use of reasonable efforts to maintain the confidential
|
||||
status of the non-public aspects of the Software display; and (iii) create derivative works of the Software in
|
||||
connection with the Zeus project, provided that any such derivative works may only be used in connection with the Zeus
|
||||
project. For the sake of clarity, nothing in this Agreement (including, without limitation, this Section 2) will create
|
||||
any liability to DLI for or restrict DLI’s ability to externally distribute python scripts containing the “input”
|
||||
configuration files specific to the Zeus project, as well as the notebooks with the resulting “output” data from the
|
||||
Software, all of which may be distributed, displayed, and shared publicly at DLI’s discretion.
|
||||
|
||||
(b) Ownership; Limited Rights. As between the parties, BlockScience owns and retains all right, title and interest in
|
||||
and to the Software, and all Intellectual Property Rights therein. DLI’s rights in the Software are limited to those
|
||||
expressly granted in Section 2(a) and in the PSA. BlockScience reserves all rights and licenses in the Software not
|
||||
expressly granted to DLI herein and in the PSA.
|
||||
|
||||
(c) Delivery. BlockScience will deliver a copy of the Software and Documentation to DLI on the Effective Date. The
|
||||
delivery may be made in electronic form, or via hardcopy medium (e.g., a CD).
|
||||
|
||||
(d) Updates. BlockScience will deliver Updates to DLI as and when such Updates become available. The obligation to
|
||||
deliver Updates will continue for as long as the PSA remains in force; upon termination or expiration of the PSA,
|
||||
BlockScience’s obligation to provide Updates will automatically terminate.
|
||||
|
||||
(e) Support. BlockScience will provide reasonable technical support for the Software, to help DLI manage any support
|
||||
issues that arise. The obligation to provide support will continue for as long as the PSA remains in force; upon
|
||||
termination or expiration of the PSA, BlockScience’s obligation to provide support will automatically terminate.
|
||||
|
||||
3. NO FEES.
|
||||
|
||||
There are no fees owed by DLI for the license granted or the Updates or support provided by BlockScience
|
||||
pursuant to this Agreement. Each party will bear its own costs and expenses arising out of or relating to its
|
||||
obligations, efforts and performance under this Agreement.
|
||||
|
||||
4. LIMITED WARRANTY; DISCLAIMER
|
||||
|
||||
(a) Limited Warranty. BlockScience represents and warrants as follows: (i) that it has the right to enter into this
|
||||
Agreement, and to perform its obligations hereunder, without violating the terms of any other agreement; (ii) that the
|
||||
Software, and any Updates, do not and will not infringe, violate, or misappropriate the Intellectual Property Rights of
|
||||
any third party; (iii) that the Software and any Updates do not and will not contain any virus, malware, spyware, trojan
|
||||
horse, or other malicious code; and (iv) that the Software and each Update will substantially conform to its
|
||||
Documentation.
|
||||
|
||||
(b) Disclaimer. EXCEPT AS OTHERWISE SET FORTH IN THIS AGREEMENT, BLOCKSCIENCE DISCLAIMS ALL OTHER WARRANTIES, EXPRESS OR
|
||||
IMPLIED, RELATED TO THE SOFTWARE, INCLUDING ANY IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR
|
||||
PURPOSE.
|
||||
|
||||
5. TERM & TERMINATION
|
||||
|
||||
(a) Term. This Agreement begins on the Effective Date, and will continue in effect until one of us terminates it in
|
||||
accordance with Section 5(b).
|
||||
|
||||
(b) Termination for Breach. Either party may terminate this Agreement if the other party breaches any material term or
|
||||
condition of this Agreement, and the breaching party fails to cure the breach within thirty (30) days of receiving
|
||||
written notice of it.
|
||||
|
||||
(c) Survival. Sections 2 through 7 will survive termination or expiration of this Agreement.
|
||||
|
||||
6. INDEMNIFICATION.
|
||||
|
||||
BlockScience will defend, indemnify, and hold DLI harmless from and against any claim, damage, loss,
|
||||
liability, expense and cost (including, without limitation, reasonable attorneys’ fees) incurred by or brought against
|
||||
DLI arising out of or related to: (i) any claim that the Software infringes or misappropriates the Intellectual Property
|
||||
Rights of that third party; or (ii) BlockScience’s breach of its limited warranties in Section 4(a).
|
||||
|
||||
7. GENERAL TERMS
|
||||
|
||||
(a) Entire Agreement; Waiver. This Agreement is the entire understanding of the parties, and supersedes any and all
|
||||
prior agreements or understandings between the parties as to its subject matter. It may be amended or modified, or
|
||||
provisions waived, only in a writing signed by both parties. The waiver of a breach of any provision of this Agreement
|
||||
will not operate or be interpreted as a waiver of any other or subsequent breach.
|
||||
|
||||
(b) Acknowledgement. BlockScience acknowledges and agrees that the “behaviour archetypes” and “configuration of the Null
|
||||
Model” referenced in the PSA are considered “Work Product” under the PSA.
|
||||
|
||||
(c) Governing Law. This Agreement will be construed, interpreted and applies in accordance with the internal laws of
|
||||
British Columbia, Canada (excluding its body of law controlling conflicts of law). Any legal action or proceeding
|
||||
arising under or related to this Agreement will be brought exclusively in the federal or provincial courts located in
|
||||
Vancouver, British Columbia, and the parties irrevocably consent to personal jurisdiction and venue there.
|
||||
|
||||
(d) Severability. If any provision of this Agreement is held to be invalid or unenforceable for any reason, that
|
||||
provision will be enforced to the maximum extent permitted by law, and the remaining provisions will continue in full
|
||||
force and effect.
|
||||
|
||||
(e) Miscellaneous. This Agreement may be executed in one or more counterparts, with the same effect as if the parties
|
||||
had signed the same document. Each counterpart so executed will be deemed to be an original, and all such counterparts
|
||||
will be construed together and will constitute one Agreement. The prevailing party in any action or legal proceeding
|
||||
arising out of this Agreement will be entitled to recover from the other party all reasonable costs and expenses
|
||||
incurred in connection with such action or proceeding, including reasonable attorneys’ fees and court costs. In the
|
||||
event of a direct conflict between the terms of this Agreement and the PSA with respect to the DLI’s rights in and to
|
||||
the Software, the terms of this Agreement will control.
|
||||
|
||||
EXHIBIT A
|
||||
|
||||
SOFTWARE
|
||||
|
||||
Software Name: SimCAD tool
|
||||
|
||||
Software Description: SimCAD is a Monte-Carlo based simulation software package for research, validation, and
|
||||
Computer Aided Design of economic systems. An economic system is treated as a state based model and defined
|
||||
through a set of endogenous and exogenous state variables which are updated through mechanisms and
|
||||
environmental processes, respectively. Behavioral models, which may be deterministic or stochastic, provide the
|
||||
evolution of the system within the action space of the mechanisms. Simulations can be run with a range of initial
|
||||
conditions and parameters for states, behaviors, mechanisms, and environmental processes to understand and
|
||||
visualize network behavior under various conditions.
|
||||
119
licenses/LICENSE
|
|
@ -1,119 +0,0 @@
|
|||
TRIAL LICENSE AGREEMENT
|
||||
|
||||
BACKGROUND
|
||||
|
||||
Company has developed and intends to market and license a certain software product and service called ”SimCAD” which,
|
||||
among other things, is a scientific engineering simulation tool (“Software”). Company wishes to provide access, on a
|
||||
trial basis, to users of a “beta” version of the Software to test and provide feedback to Company. Licensee wishes to
|
||||
participate in Company’s beta trial of the Software and to provide feedback to Company with respect to Licensee’s use
|
||||
thereof.
|
||||
|
||||
Accordingly, the parties hereby agree as follows:
|
||||
|
||||
1. BETA PRODUCT.
|
||||
|
||||
This Agreement applies to any prerelease version of the Software and any updates and changes thereto during the Term
|
||||
(collectively, “Beta Product”). As an essential condition of this Agreement, Licensee understands and acknowledges that:
|
||||
(a) Licensee is participating in a beta test of the Beta Product; (b) the Beta Product has not been field tested or
|
||||
trialed; and (c) the Beta Product may not operate properly or be error free and may not perform all functions for
|
||||
which it is intended or represented.
|
||||
|
||||
2. FEEDBACK.
|
||||
|
||||
As a condition of this Agreement, during the Term of this Agreement, Licensee agrees to provide Company with comments,
|
||||
feedback, criticisms, and suggestions for changes to the Beta Product (“Feedback”), and to help Company identify errors
|
||||
or malfunctions, and performance issues, in the operation of the Beta Product, as Company may reasonably request. All
|
||||
rights to any Feedback or other intellectual property derived from Licensee’s use of or relating to the Beta Product,
|
||||
as well any data collected from the use of the Beta Product, belong solely to Company and Licensee hereby irrevocably
|
||||
assigns all such rights to Company. Company reserves the right to use all Feedback and data collected as a result of the
|
||||
use of the Beta Product to advertise and promote the Company and the Software.
|
||||
|
||||
3. LICENSE AND RESERVATION OF RIGHTS.
|
||||
|
||||
3.1 Subject to the terms and conditions set forth in this Agreement, Company hereby grants Licensee, and Licensee
|
||||
accepts, during the Term, a nonexclusive, royaltyfree, revocable, nontransferable, limited license to access and use
|
||||
the Beta Product for its internal, noncommercial use for evaluation purposes only, and to give permission to employees
|
||||
of Licensee and employees of Licensee’s subsidiaries (“Permitted Users”) to use the Beta Product in accordance with the
|
||||
foregoing.
|
||||
|
||||
3.2 The Beta Product and the Software comprise the intellectual property of Company. All right, title and interest in
|
||||
and to the Beta Product (and, more generally, in and to the Software), and to all Feedback and data arising from its
|
||||
use, in whole or in part, and all patent, copyright, trademarks, trade secret and all other intellectual and industrial
|
||||
property rights therein and the structure, sequence and organization of same, and the media on which such material is
|
||||
contained belong exclusively to Company. Licensee and its Permitted Users will not, directly or indirectly: reverse
|
||||
engineer, decompile, disassemble or otherwise attempt to discover the source code, object code or underlying structure,
|
||||
ideas, knowhow or algorithms relevant to the Beta Product; modify, adapt, alter, edit, correct, translate, publish,
|
||||
sell, transfer, assign, convey, rent, lease, loan, pledge, sublicense, distribute, export, enhance or create derivative
|
||||
works based on the Beta Product; or remove, alter, cover or otherwise obscure any proprietary notices or labels
|
||||
displayed on or within the Beta Product any documentation relating thereto.
|
||||
|
||||
4. DISCLAIMER.
|
||||
|
||||
4.1 COMPANY MAKES NO WARRANTIES, WHETHER EXPRESS, IMPLIED, STATUTORY OR OTHERWISE, WITH RESPECT TO THE BETA PRODUCT,
|
||||
INCLUDING, BUT NOT LIMITED TO, THE AVAILABILITY, QUALITY OR PERFORMANCE OF THE BETA PRODUCT. COMPANY SPECIFICALLY
|
||||
DISCLAIMS ALL EXPRESS, STATUTORY AND IMPLIED WARRANTIES AND CONDITIONS, INCLUDING, WITHOUT LIMITATION (A) THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT, (B) ANY WARRANTIES AGAINST HIDDEN
|
||||
OR LATENT DEFECTS, (C) AND ANY WARRANTIES AND CONDITIONS ARISING OUT OF COURSE OF DEALING OR USAGE OF TRADE AND (D) ANY
|
||||
WARRANTY OR REPRESENTATION THAT THE BETA PRODUCT IS ERRORFREE, VIRUSFREE, SECURE, UNINTERRUPTED, OR FREE FROM
|
||||
UNAUTHORIZED ACCESS (INCLUDING, BUT NOT LIMITED TO, THIRD PARTY HACKERS OR DENIAL OF SERVICE ATTACKS). THE BETA PRODUCT
|
||||
IS SUPPLIED ON AN “AS IS”, “AS AVAILABLE” BASIS WITHOUT WARRANTY.
|
||||
|
||||
4.2 NEITHER PARTY SHALL BE LIABLE FOR SPECIAL, INCIDENTAL, PUNITIVE, CONSEQUENTIAL OR INDIRECT DAMAGES OR LOSS
|
||||
(INCLUDING DEATH AND PERSONAL INJURY), IRRESPECTIVE OF THEIR CAUSE, NOTWITHSTANDING THAT A PARTY HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH LOSS OR DAMAGE, NOR FOR ANY CLAIMS FOR SUCH LOSS OR DAMAGE INSTITUTED AGAINST A PARTY OR ITS
|
||||
CUSTOMERS BY ANY THIRD PARTY.
|
||||
|
||||
5. CONFIDENTIALITY
|
||||
|
||||
5.1 All Confidential Information disclosed by either party shall be kept by the receiving party in strict confidence and
|
||||
shall not be disclosed to any third party without the disclosing party’s express written consent. For purposes of this
|
||||
Agreement, “Confidential Information” means all information regarding either party’s business which has been marked or
|
||||
is otherwise communicated as being “proprietary” or “confidential” or which reasonably should be known by the receiving
|
||||
party to be proprietary or confidential information. Without limiting the generality of the foregoing, Confidential
|
||||
Information of Company includes nonpublic information regarding features, functionality and performance of the Beta
|
||||
Product, including all Feedback and related data. Notwithstanding the foregoing, each party’s confidentiality
|
||||
obligations hereunder shall not apply to information that: (a) is already known to the receiving party without a
|
||||
preexisting restriction as to disclosure; (b) is or becomes publicly available without fault of the receiving party;
|
||||
(c) is rightfully obtained by the receiving party from a third party without restriction as to disclosure, or is
|
||||
approved for release by written authorization of the disclosing party; (d) is developed independently by the receiving
|
||||
party without use of the disclosing party’s Confidential Information; or (e) is required to be disclosed by law or
|
||||
regulation, including, but not limited to, supplying such information or making such statements or disclosures relating
|
||||
to this Agreement before any competent court, governmental agency or authority in response to a lawful requirement or
|
||||
request from a court of governmental agency or authority, provided that the disclosing party shall give the other party
|
||||
prompt notice of such request, to the extent practicable, so that the other party may seek (at its sole cost and
|
||||
expense) an appropriate protective order or similar relief.
|
||||
|
||||
5.2 In the event of a breach of Sections 2, 3 or this Section 5, the nonbreaching party shall be entitled to seek
|
||||
equitable relief to protect its interests, including, but not limited to, injunctive relief. In the event of expiration
|
||||
or earlier termination of this Agreement, each party shall immediately return to the other party such other party’s
|
||||
Confidential Information, or at such other party’s option, destroy any remaining Confidential Information and certify
|
||||
that such destruction has taken place.
|
||||
|
||||
6. FEES; EXPENSES.
|
||||
|
||||
Neither party shall be entitled to any compensation in connection with this Agreement or its use or provision of the
|
||||
Beta Product. Each party shall bear its own costs and expenses arising from this Agreement and its use or provision of
|
||||
the Beta Product, as the case may be.
|
||||
|
||||
7. TERM OF AGREEMENT.
|
||||
|
||||
This Agreement shall begin on the Effective Date and shall continue until it has been terminated (such period, the
|
||||
“Term”). Either party shall have the right to terminate this Agreement at any time on one (1) month written notice to
|
||||
the other party, or in the case of a breach of this Agreement by Licensee or its Permitted Users, Company may terminate
|
||||
this Agreement immediately on written notice to Licensee. Upon termination of this Agreement, all rights granted to
|
||||
Licensee (and any Permitted User) under this Agreement will immediately terminate and Licensee (and all Permitted Users)
|
||||
must immediately cease all use of the Beta Product at such time. Notwithstanding any termination of this Agreement,
|
||||
Sections 2, 3.2, 4, 5, 6, this Section 7 and Section 8 shall survive and remain binding on the parties.
|
||||
|
||||
8. MISCELLANEOUS.
|
||||
|
||||
This Agreement shall be governed by and construed in accordance with the laws of the State of New York. All disputes
|
||||
relating to this Agreement shall be resolved in the federal and state courts of New York County, New York and the
|
||||
parties submit to the jurisdiction of such courts. This Agreement does not create any agency, partnership, or joint
|
||||
venture relationship between Licensee and Company. This Agreement is the entire understanding of the parties with
|
||||
respect to the subject matter hereof and supersedes any previous or contemporaneous communications, representations,
|
||||
warranties, discussions, arrangements or commitments, whether oral or written with respect to such subject matter. This
|
||||
Agreement cannot be amended except by a written amendment that expressly refers to this Agreement and is signed by an
|
||||
authorized representative of each party. This Agreement may be executed in one or more counterparts, including via
|
||||
facsimile or email (or any other electronic means such as “.pdf” or “.tiff” files), each of which shall be deemed an
|
||||
original, and all of which shall constitute one and the same Agreement.
|
||||
8
setup.py
|
|
@ -11,13 +11,13 @@ long_description = "cadCAD is a differential games based simulation software pac
|
|||
monte carlo analysis and other common numerical methods is provided."
|
||||
|
||||
setup(name='cadCAD',
|
||||
version='0.2.4',
|
||||
version='0.3.0',
|
||||
description="cadCAD: a differential games based simulation software package for research, validation, and \
|
||||
Computer Aided Design of economic systems",
|
||||
long_description=long_description,
|
||||
url='https://github.com/BlockScience/DiffyQ-SimCAD',
|
||||
url='https://github.com/BlockScience/cadCAD',
|
||||
author='Joshua E. Jodesty',
|
||||
author_email='joshua@block.science',
|
||||
# license='LICENSE',
|
||||
author_email='joshua@block.science, joshua.jodesty@gmail.com',
|
||||
license='LICENSE.txt',
|
||||
packages=find_packages()
|
||||
)
|
||||
|
|
@ -9,7 +9,7 @@ seeds = {
|
|||
'z': np.random.RandomState(1),
|
||||
'a': np.random.RandomState(2),
|
||||
'b': np.random.RandomState(3),
|
||||
'c': np.random.RandomState(3)
|
||||
'c': np.random.RandomState(4)
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -95,14 +95,15 @@ genesis_states = {
|
|||
|
||||
# Environment Process
|
||||
# ToDo: Depreciation Waring for env_proc_trigger convention
|
||||
trigger_timestamps = ['2018-10-01 15:16:25', '2018-10-01 15:16:27', '2018-10-01 15:16:29']
|
||||
env_processes = {
|
||||
"s3": [lambda _g, x: 5],
|
||||
"s4": env_trigger(3)(trigger_field='timestep', trigger_vals=[1], funct_list=[lambda _g, x: 10])
|
||||
"s4": env_trigger(3)(trigger_field='timestamp', trigger_vals=trigger_timestamps, funct_list=[lambda _g, x: 10])
|
||||
}
|
||||
|
||||
|
||||
partial_state_update_blocks = {
|
||||
"m1": {
|
||||
partial_state_update_block = [
|
||||
{
|
||||
"policies": {
|
||||
"b1": p1m1,
|
||||
"b2": p2m1
|
||||
|
|
@ -115,7 +116,7 @@ partial_state_update_blocks = {
|
|||
"timestamp": update_timestamp
|
||||
}
|
||||
},
|
||||
"m2": {
|
||||
{
|
||||
"policies": {
|
||||
"b1": p1m2,
|
||||
"b2": p2m2
|
||||
|
|
@ -127,7 +128,7 @@ partial_state_update_blocks = {
|
|||
# "s4": es4p2,
|
||||
}
|
||||
},
|
||||
"m3": {
|
||||
{
|
||||
"policies": {
|
||||
"b1": p1m3,
|
||||
"b2": p2m3
|
||||
|
|
@ -139,12 +140,13 @@ partial_state_update_blocks = {
|
|||
# "s4": es4p2,
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
|
||||
sim_config = config_sim(
|
||||
{
|
||||
"N": 2,
|
||||
"N": 1,
|
||||
# "N": 5,
|
||||
"T": range(5),
|
||||
}
|
||||
)
|
||||
|
|
@ -153,6 +155,6 @@ append_configs(
|
|||
sim_configs=sim_config,
|
||||
initial_state=genesis_states,
|
||||
env_processes=env_processes,
|
||||
partial_state_update_blocks=partial_state_update_blocks,
|
||||
partial_state_update_blocks=partial_state_update_block,
|
||||
policy_ops=[lambda a, b: a + b]
|
||||
)
|
||||
|
|
@ -8,7 +8,7 @@ seeds = {
|
|||
'z': np.random.RandomState(1),
|
||||
'a': np.random.RandomState(2),
|
||||
'b': np.random.RandomState(3),
|
||||
'c': np.random.RandomState(4)
|
||||
'c': np.random.RandomState(3)
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -89,9 +89,10 @@ genesis_states = {
|
|||
|
||||
# Environment Process
|
||||
# ToDo: Depreciation Waring for env_proc_trigger convention
|
||||
trigger_timestamps = ['2018-10-01 15:16:25', '2018-10-01 15:16:27', '2018-10-01 15:16:29']
|
||||
env_processes = {
|
||||
"s3": [lambda _g, x: 5],
|
||||
"s4": env_trigger(3)(trigger_field='timestep', trigger_vals=[2], funct_list=[lambda _g, x: 10])
|
||||
"s4": env_trigger(3)(trigger_field='timestamp', trigger_vals=trigger_timestamps, funct_list=[lambda _g, x: 10])
|
||||
}
|
||||
|
||||
partial_state_update_block = {
|
||||
|
|
|
|||
|
|
@ -7,9 +7,15 @@ exclusion_list = ['nonexsistant', 'last_x', '2nd_to_last_x', '3rd_to_last_x', '4
|
|||
# Policies per Mechanism
|
||||
|
||||
# WARNING: DO NOT delete elements from sH
|
||||
|
||||
# state_history, target_field, psu_block_offset, exculsion_list
|
||||
def last_update(_g, substep, sH, s):
|
||||
return {"last_x": access_block(sH, "last_x", -1, exclusion_list)}
|
||||
return {"last_x": access_block(
|
||||
state_history=sH,
|
||||
target_field="last_x",
|
||||
psu_block_offset=-1,
|
||||
exculsion_list=exclusion_list
|
||||
)
|
||||
}
|
||||
policies["last_x"] = last_update
|
||||
|
||||
def second2last_update(_g, substep, sH, s):
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
import numpy as np
|
||||
from cadCAD.configuration import append_configs
|
||||
from cadCAD.configuration.utils import config_sim
|
||||
|
||||
|
|
@ -73,14 +72,12 @@ sim_config = config_sim(
|
|||
}
|
||||
)
|
||||
|
||||
|
||||
|
||||
# Aggregation == Reduce Map / Reduce Map Aggregation
|
||||
# ToDo: subsequent functions should accept the entire datastructure
|
||||
# using env functions (include in reg test using / for env proc)
|
||||
append_configs(
|
||||
sim_configs=sim_config,
|
||||
initial_state=genesis_states,
|
||||
partial_state_update_blocks=partial_state_update_block,
|
||||
# ToDo: subsequent functions should include policy dict for access to each policy (i.e shouldnt be a map)
|
||||
policy_ops=[lambda a, b: a + b, lambda y: y * 2] # Default: lambda a, b: a + b ToDO: reduction function requires high lvl explanation
|
||||
)
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
import unittest
|
||||
|
||||
import pandas as pd
|
||||
# from tabulate import tabulate
|
||||
from cadCAD.engine import ExecutionMode, ExecutionContext, Executor
|
||||
from simulations.regression_tests import policy_aggregation
|
||||
from cadCAD import configs
|
||||
|
||||
exec_mode = ExecutionMode()
|
||||
first_config = configs # only contains config1
|
||||
single_proc_ctx = ExecutionContext(context=exec_mode.single_proc)
|
||||
run = Executor(exec_context=single_proc_ctx, configs=first_config)
|
||||
raw_result, tensor_field = run.execute()
|
||||
result = pd.DataFrame(raw_result)
|
||||
|
||||
class TestStringMethods(unittest.TestCase):
|
||||
def __init__(self, result: pd.DataFrame, tensor_field: pd.DataFrame) -> None:
|
||||
self.result = result
|
||||
self.tensor_field = tensor_field
|
||||
|
||||
def test_upper(self):
|
||||
self.assertEqual('foo'.upper(), 'FOO')
|
||||
|
||||
def test_isupper(self):
|
||||
self.assertTrue('FOO'.isupper())
|
||||
self.assertFalse('Foo'.isupper())
|
||||
|
||||
def test_split(self):
|
||||
s = 'hello world'
|
||||
self.assertEqual(s.split(), ['hello', 'world'])
|
||||
# check that s.split fails when the separator is not a string
|
||||
with self.assertRaises(TypeError):
|
||||
s.split(2)
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
|
|
@ -1,3 +1,5 @@
|
|||
from copy import deepcopy
|
||||
|
||||
import pandas as pd
|
||||
from fn.func import curried
|
||||
from datetime import timedelta
|
||||
|
|
@ -26,6 +28,11 @@ class udoExample(object):
|
|||
self.x += 1
|
||||
return self
|
||||
|
||||
def updateDS(self):
|
||||
self.ds.iloc[0,0] -= 10
|
||||
# pp.pprint(self.ds)
|
||||
return self
|
||||
|
||||
def perceive(self, s):
|
||||
self.perception = self.ds[
|
||||
(self.ds['run'] == s['run']) & (self.ds['substep'] == s['substep']) & (self.ds['timestep'] == s['timestep'])
|
||||
|
|
@ -106,7 +113,7 @@ def perceive(s, self):
|
|||
def state_udo_update(_g, step, sL, s, _input):
|
||||
y = 'state_udo'
|
||||
# s['hydra_state'].updateX().anon(perceive(s))
|
||||
s['state_udo'].updateX().perceive(s)
|
||||
s['state_udo'].updateX().perceive(s).updateDS()
|
||||
x = udoPipe(s['state_udo'])
|
||||
return y, x
|
||||
for m in psu_steps:
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
import pandas as pd
|
||||
from typing import List
|
||||
from tabulate import tabulate
|
||||
# The following imports NEED to be in the exact order
|
||||
from cadCAD.engine import ExecutionMode, ExecutionContext, Executor
|
||||
|
|
@ -17,7 +18,8 @@ raw_result, tensor_field = run.execute()
|
|||
result = pd.DataFrame(raw_result)
|
||||
print()
|
||||
print("Tensor Field: config1")
|
||||
print(tabulate(tensor_field, headers='keys', tablefmt='psql'))
|
||||
# print(raw_result)
|
||||
print(tabulate(tensor_field[['m', 'b1', 's1', 's2']], headers='keys', tablefmt='psql'))
|
||||
print("Output:")
|
||||
print(tabulate(result, headers='keys', tablefmt='psql'))
|
||||
print()
|
||||
|
|
|
|||
|
|
@ -15,10 +15,10 @@ run = Executor(exec_context=single_proc_ctx, configs=first_config)
|
|||
|
||||
raw_result, tensor_field = run.execute()
|
||||
result = pd.DataFrame(raw_result)
|
||||
cols = ['run','substep','timestep','x','nonexsistant','last_x','2nd_to_last_x','3rd_to_last_x','4th_to_last_x']
|
||||
# cols = ['run','substep','timestep','x','nonexsistant','last_x','2nd_to_last_x','3rd_to_last_x','4th_to_last_x']
|
||||
cols = ['last_x']
|
||||
result = result[cols]
|
||||
|
||||
|
||||
print()
|
||||
print("Tensor Field: config1")
|
||||
print(tabulate(tensor_field, headers='keys', tablefmt='psql'))
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
from pprint import pprint
|
||||
|
||||
import pandas as pd
|
||||
from tabulate import tabulate
|
||||
# The following imports NEED to be in the exact order
|
||||
from cadCAD.engine import ExecutionMode, ExecutionContext, Executor
|
||||
from simulations.regression_tests import policy_aggregation
|
||||
from cadCAD import configs
|
||||
|
|
@ -15,6 +16,7 @@ run = Executor(exec_context=single_proc_ctx, configs=first_config)
|
|||
|
||||
raw_result, tensor_field = run.execute()
|
||||
result = pd.DataFrame(raw_result)
|
||||
|
||||
print()
|
||||
print("Tensor Field: config1")
|
||||
print(tabulate(tensor_field, headers='keys', tablefmt='psql'))
|
||||
|
|
|
|||
|
|
@ -11,9 +11,9 @@ print("Simulation Execution: Single Configuration")
|
|||
print()
|
||||
|
||||
|
||||
first_config = configs # only contains config1
|
||||
|
||||
single_proc_ctx = ExecutionContext(context=exec_mode.single_proc)
|
||||
run = Executor(exec_context=single_proc_ctx, configs=first_config)
|
||||
run = Executor(exec_context=single_proc_ctx, configs=configs)
|
||||
# cols = configs[0].initial_state.keys()
|
||||
cols = [
|
||||
'increment',
|
||||
|
|
@ -29,6 +29,10 @@ result = pd.DataFrame(raw_result)[['run', 'substep', 'timestep'] + cols]
|
|||
|
||||
# print(tabulate(result['c'].apply(pd.Series), headers='keys', tablefmt='psql'))
|
||||
|
||||
# print(result.iloc[8,:]['state_udo'].ds)
|
||||
|
||||
# ctypes.cast(id(v['state_udo']['mem_id']), ctypes.py_object).value
|
||||
|
||||
print()
|
||||
print("Tensor Field: config1")
|
||||
print(tabulate(tensor_field, headers='keys', tablefmt='psql'))
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@
|
|||
"\n",
|
||||
"cadCAD is a Python library that assists in the processes of designing, testing and validating complex systems through simulation. At its core, cadCAD is a differential games engine that supports parameter sweeping and Monte Carlo analyses and can be easily integrated with other scientific computing Python modules and data science workflows.\n",
|
||||
"\n",
|
||||
"To learn more about cadCAD, follow our [tutorial series](https://github.com/BlockScience/cadCAD-Tutorials/tree/master/01%20Tutorials)\n",
|
||||
"To learn more about cadCAD, follow our [tutorial series](../../tutorials)\n",
|
||||
"\n",
|
||||
"**Installing cadCAD:**\n",
|
||||
"\n",
|
||||
|
|
|
|||
|
|
@ -0,0 +1,763 @@
|
|||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### Exogenous Example\n",
|
||||
"## Authored by BlockScience, MV Barlin\n",
|
||||
"### Updated July-10-2019 \n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Key assumptions and space:\n",
|
||||
"1. Implementation of System Model in cell 2\n",
|
||||
"2. Timestep = day\n",
|
||||
"3. Launch simulation, without intervention from changing governance policies"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"#### Library Imports"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 1,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from IPython.display import Image\n",
|
||||
"import pandas as pd\n",
|
||||
"import numpy as np\n",
|
||||
"import matplotlib as mpl\n",
|
||||
"import matplotlib.pyplot as plt\n",
|
||||
"import seaborn as sns\n",
|
||||
"import math\n",
|
||||
"#from tabulate import tabulate\n",
|
||||
"from scipy import stats\n",
|
||||
"sns.set_style('whitegrid')\n",
|
||||
"from decimal import Decimal\n",
|
||||
"from datetime import timedelta\n",
|
||||
"\n",
|
||||
"%matplotlib inline"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## cadCAD Setup\n",
|
||||
"#### ----------------cadCAD LIBRARY IMPORTS------------------------"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 2,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from cadCAD.engine import ExecutionMode, ExecutionContext, Executor\n",
|
||||
"#from simulations.validation import sweep_config\n",
|
||||
"from cadCAD import configs\n",
|
||||
"from cadCAD.configuration import append_configs\n",
|
||||
"from cadCAD.configuration.utils import proc_trigger, ep_time_step, config_sim"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 3,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"#from cadCAD.configuration.utils.parameterSweep import config_sim"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 4,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from typing import Dict, List"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"#### ----------------Random State Seed-----------------------------"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 5,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"seed = {\n",
|
||||
"# 'z': np.random.RandomState(1)\n",
|
||||
"}"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"#### Timestamp"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 6,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"ts_format = '%Y-%m-%d %H:%M:%S'\n",
|
||||
"t_delta = timedelta(days=0, minutes=0, seconds=1)\n",
|
||||
"def set_time(_g, step, sL, s, _input):\n",
|
||||
" y = 'timestamp'\n",
|
||||
" x = ep_time_step(s, dt_str=s['timestamp'], fromat_str=ts_format, _timedelta=t_delta)\n",
|
||||
" return (y, x)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# ASSUMED PARAMETERS"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### PRICE LIST"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 7,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# dai_xns_conversion = 1.0 # Assumed for static conversion 'PUBLISHED PRICE LIST' DEPRECATED"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"#### Initial Condition State Variables"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 8,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"del_stake_pct = 2\n",
|
||||
"\n",
|
||||
"starting_xns = float(10**10) # initial supply of xns tokens\n",
|
||||
"starting_broker_xns = float(1 * 10**8) # inital holding of xns token by broker app\n",
|
||||
"starting_broker_fiat = float(1 * 10**5) # inital holding of xns token by broker app\n",
|
||||
"starting_broker_stable = float(1 * 10**6) # inital holding of stable token by broker app\n",
|
||||
"starting_deposit_acct = float(100) # inital deposit locked for first month of resources TBD: make function of resource*price\n",
|
||||
"starting_entrance = float(1 * 10**4) # TBD: make function of entrance fee % * cost * # of initial apps\n",
|
||||
"starting_app_usage = float(10) # initial fees from app usage \n",
|
||||
"starting_platform = float(100) # initial platform fees \n",
|
||||
"starting_resource_fees = float(10) # initial resource fees usage paid by apps \n",
|
||||
"starting_app_subsidy = float(0.25* 10**9) # initial application subsidy pool\n",
|
||||
"starting_stake = float(4 * 10**7)\n",
|
||||
"starting_stake_pool = starting_stake + ((3*10**7)*(del_stake_pct)) # initial staked pool + ((3*10**7)*(del_stake_pct))\n",
|
||||
"\n",
|
||||
"#starting_block_reward = float(0) # initial block reward MOVED ABOVE TO POLICY\n",
|
||||
"starting_capacity_subsidy = float(7.5 * 10**7) # initial capacity subsidy pool\n",
|
||||
"starting_delegate_holdings = 0.15 * starting_xns\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"#### Initial Condition Composite State Variables"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 9,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# subsidy limit is 30% of the 10B supply\n",
|
||||
"starting_treasury = float(5.5 * 10**9) \n",
|
||||
"starting_app_income = float(0) # initial income to application\n",
|
||||
"starting_resource_income = float(0) # initial income to application\n",
|
||||
"starting_delegate_income = float(0) # initial income to delegate"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"#### Initial Condition Exogoneous State Variables "
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 10,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"starting_xns_fiat = float(0.01) # initial xns per fiat signal\n",
|
||||
"starting_fiat_ext = float(1) # initial xns per fiat signal\n",
|
||||
"starting_stable_ext = float(1) # initial stable signal"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### Exogenous Price Updates"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 11,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"def delta_price(mean,sd):\n",
|
||||
" '''Returns normal random variable generated by first two central moments of price change of input ticker'''\n",
|
||||
" rv = np.random.normal(mean, sd)\n",
|
||||
" return rv"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 12,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"\n",
|
||||
"def xns_ext_update(_g, step, sL, s, _input):\n",
|
||||
" key = 'XNS_fiat_external'\n",
|
||||
" \n",
|
||||
" value = s['XNS_fiat_external'] * (1 + delta_price(0.000000, 0.005))\n",
|
||||
" \n",
|
||||
" return key, value"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"From Currency Analysis of DAI-USD pair \n",
|
||||
"May-09-2018 through June-10-2019 \n",
|
||||
"Datasource: BitFinex \n",
|
||||
"Analysis of daily return percentage performed by BlockScience"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 13,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"DAI_mean = 0.0000719\n",
|
||||
"DAI_sd = 0.006716"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"The daily return is computed as: \n",
|
||||
"$$ r = \\frac{Price_n - Price_{n-1}}{Price_{n-1}} $$ \n",
|
||||
"Thus, the modelled current price can be as: \n",
|
||||
"$$ Price_n = Price_{n-1} * r + Price_{n-1} $$"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 14,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"\n",
|
||||
"def stable_update(_g, step, sL, s, _input):\n",
|
||||
" key = 'stable_external'\n",
|
||||
" \n",
|
||||
" value = s['stable_external'] * (1 + delta_price(DAI_mean, DAI_sd))\n",
|
||||
" return key, value\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"#### Assumed Parameters"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 15,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"apps_deployed = 1 # Make part of test- application deployment model\n",
|
||||
"\n",
|
||||
"starting_deposit_acct = float(100) # inital deposit locked for first month of resources TBD: make function of resource*price\n",
|
||||
"\n",
|
||||
"app_resource_fee_constant = 10**1 # in STABLE, assumed per day per total nodes \n",
|
||||
"platform_fee_constant = 10 # in XNS\n",
|
||||
"# ^^^^^^^^^^^^ MAKE A PERCENTAGE OR FLAT FEE as PART of TESTING"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 16,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"1000"
|
||||
]
|
||||
},
|
||||
"execution_count": 16,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"\n",
|
||||
"alpha = 100 # Fee Rate\n",
|
||||
"beta = 0.10 # FIXED Too high because multiplied by constant and resource fees\n",
|
||||
"app_platform = alpha * platform_fee_constant\n",
|
||||
"app_platform"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 17,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"10.0"
|
||||
]
|
||||
},
|
||||
"execution_count": 17,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"beta_out =beta*100\n",
|
||||
"beta_out"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 18,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"0.15"
|
||||
]
|
||||
},
|
||||
"execution_count": 18,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"starting_capacity_subsidy / (5 * 10**7) / 10"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 19,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"\n",
|
||||
"weight = 0.95 # 0.95 internal weight 5% friction from external markets\n",
|
||||
"\n",
|
||||
"def xns_int_update(_g, step, sL, s, _input):\n",
|
||||
" key = 'XNS_fiat_internal'\n",
|
||||
"\n",
|
||||
" internal = s['XNS_fiat_internal'] * weight\n",
|
||||
" external = s['XNS_fiat_external'] * (1 - weight)\n",
|
||||
" value = internal + external\n",
|
||||
" \n",
|
||||
" return key, value"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"#### CONFIGURATION DICTIONARY"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 20,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"time_step_count = 3652 # days = 10 years\n",
|
||||
"run_count = 1"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": []
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"#### Genesis States"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 21,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"#----------STATE VARIABLE Genesis DICTIONARY---------------------------\n",
|
||||
"genesis_states = {\n",
|
||||
" 'XNS_fiat_external' : starting_xns_fiat,\n",
|
||||
" 'XNS_fiat_internal' : starting_xns_fiat,\n",
|
||||
" # 'fiat_external' : starting_fiat_ext,\n",
|
||||
" 'stable_external' : starting_stable_ext,\n",
|
||||
" 'timestamp': '2018-10-01 15:16:24', #es5\n",
|
||||
"}"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 22,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"#--------------EXOGENOUS STATE MECHANISM DICTIONARY--------------------\n",
|
||||
"exogenous_states = {\n",
|
||||
" 'XNS_fiat_external' : xns_ext_update,\n",
|
||||
"# 'fiat_external' : starting_fiat_ext,\n",
|
||||
" 'stable_external' : stable_update,\n",
|
||||
" \"timestamp\": set_time,\n",
|
||||
" }\n",
|
||||
"\n",
|
||||
"#--------------ENVIRONMENTAL PROCESS DICTIONARY------------------------\n",
|
||||
"env_processes = {\n",
|
||||
"# \"Poisson\": env_proc_id\n",
|
||||
"}\n",
|
||||
"#----------------------SIMULATION RUN SETUP----------------------------\n",
|
||||
"sim_config = config_sim(\n",
|
||||
" {\n",
|
||||
" \"N\": run_count,\n",
|
||||
" \"T\": range(time_step_count)\n",
|
||||
"# \"M\": g # for parameter sweep\n",
|
||||
"}\n",
|
||||
")\n",
|
||||
"#----------------------MECHANISM AND BEHAVIOR DICTIONARY---------------\n",
|
||||
"partial_state_update_block = {\n",
|
||||
" \"price\": { \n",
|
||||
" \"policies\": { \n",
|
||||
" },\n",
|
||||
" \"variables\": {\n",
|
||||
" 'XNS_fiat_internal' : xns_int_update\n",
|
||||
"# 'app_income' : app_earn,\n",
|
||||
" }\n",
|
||||
" },\n",
|
||||
"}\n",
|
||||
"\n",
|
||||
"append_configs(\n",
|
||||
" sim_configs=sim_config,\n",
|
||||
" initial_state=genesis_states,\n",
|
||||
" seeds=seed,\n",
|
||||
" raw_exogenous_states= exogenous_states,\n",
|
||||
" env_processes=env_processes,\n",
|
||||
" partial_state_update_blocks=partial_state_update_block\n",
|
||||
")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"#### Running cadCAD"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 23,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Simulation Execution: Single Configuration\n",
|
||||
"\n",
|
||||
"single_proc: [<cadCAD.configuration.Configuration object at 0x0000024B3B37AF60>]\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "stderr",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"C:\\Users\\mbarl\\AppData\\Local\\Continuum\\anaconda3\\lib\\site-packages\\cadCAD\\utils\\__init__.py:89: FutureWarning: The use of a dictionary to describe Partial State Update Blocks will be deprecated. Use a list instead.\n",
|
||||
" FutureWarning)\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"exec_mode = ExecutionMode()\n",
|
||||
"\n",
|
||||
"print(\"Simulation Execution: Single Configuration\")\n",
|
||||
"print()\n",
|
||||
"first_config = configs # only contains config1\n",
|
||||
"single_proc_ctx = ExecutionContext(context=exec_mode.single_proc)\n",
|
||||
"run1 = Executor(exec_context=single_proc_ctx, configs=first_config)\n",
|
||||
"run1_raw_result, tensor_field = run1.main()\n",
|
||||
"result = pd.DataFrame(run1_raw_result)\n",
|
||||
"# print()\n",
|
||||
"# print(\"Tensor Field: config1\")\n",
|
||||
"# print(tabulate(tensor_field, headers='keys', tablefmt='psql'))\n",
|
||||
"# print(\"Output:\")\n",
|
||||
"# print(tabulate(result, headers='keys', tablefmt='psql'))\n",
|
||||
"# print()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 24,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"df = result"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 25,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/html": [
|
||||
"<div>\n",
|
||||
"<style scoped>\n",
|
||||
" .dataframe tbody tr th:only-of-type {\n",
|
||||
" vertical-align: middle;\n",
|
||||
" }\n",
|
||||
"\n",
|
||||
" .dataframe tbody tr th {\n",
|
||||
" vertical-align: top;\n",
|
||||
" }\n",
|
||||
"\n",
|
||||
" .dataframe thead th {\n",
|
||||
" text-align: right;\n",
|
||||
" }\n",
|
||||
"</style>\n",
|
||||
"<table border=\"1\" class=\"dataframe\">\n",
|
||||
" <thead>\n",
|
||||
" <tr style=\"text-align: right;\">\n",
|
||||
" <th></th>\n",
|
||||
" <th>XNS_fiat_external</th>\n",
|
||||
" <th>XNS_fiat_internal</th>\n",
|
||||
" <th>run</th>\n",
|
||||
" <th>stable_external</th>\n",
|
||||
" <th>substep</th>\n",
|
||||
" <th>timestamp</th>\n",
|
||||
" <th>timestep</th>\n",
|
||||
" </tr>\n",
|
||||
" </thead>\n",
|
||||
" <tbody>\n",
|
||||
" <tr>\n",
|
||||
" <th>0</th>\n",
|
||||
" <td>0.010000</td>\n",
|
||||
" <td>0.010000</td>\n",
|
||||
" <td>1</td>\n",
|
||||
" <td>1.000000</td>\n",
|
||||
" <td>0</td>\n",
|
||||
" <td>2018-10-01 15:16:24</td>\n",
|
||||
" <td>0</td>\n",
|
||||
" </tr>\n",
|
||||
" <tr>\n",
|
||||
" <th>1</th>\n",
|
||||
" <td>0.009944</td>\n",
|
||||
" <td>0.010000</td>\n",
|
||||
" <td>1</td>\n",
|
||||
" <td>1.000172</td>\n",
|
||||
" <td>1</td>\n",
|
||||
" <td>2018-10-01 15:16:25</td>\n",
|
||||
" <td>1</td>\n",
|
||||
" </tr>\n",
|
||||
" <tr>\n",
|
||||
" <th>2</th>\n",
|
||||
" <td>0.009889</td>\n",
|
||||
" <td>0.009997</td>\n",
|
||||
" <td>1</td>\n",
|
||||
" <td>1.003516</td>\n",
|
||||
" <td>1</td>\n",
|
||||
" <td>2018-10-01 15:16:26</td>\n",
|
||||
" <td>2</td>\n",
|
||||
" </tr>\n",
|
||||
" <tr>\n",
|
||||
" <th>3</th>\n",
|
||||
" <td>0.009848</td>\n",
|
||||
" <td>0.009992</td>\n",
|
||||
" <td>1</td>\n",
|
||||
" <td>0.990655</td>\n",
|
||||
" <td>1</td>\n",
|
||||
" <td>2018-10-01 15:16:27</td>\n",
|
||||
" <td>3</td>\n",
|
||||
" </tr>\n",
|
||||
" <tr>\n",
|
||||
" <th>4</th>\n",
|
||||
" <td>0.009814</td>\n",
|
||||
" <td>0.009985</td>\n",
|
||||
" <td>1</td>\n",
|
||||
" <td>1.001346</td>\n",
|
||||
" <td>1</td>\n",
|
||||
" <td>2018-10-01 15:16:28</td>\n",
|
||||
" <td>4</td>\n",
|
||||
" </tr>\n",
|
||||
" <tr>\n",
|
||||
" <th>5</th>\n",
|
||||
" <td>0.009798</td>\n",
|
||||
" <td>0.009976</td>\n",
|
||||
" <td>1</td>\n",
|
||||
" <td>1.002495</td>\n",
|
||||
" <td>1</td>\n",
|
||||
" <td>2018-10-01 15:16:29</td>\n",
|
||||
" <td>5</td>\n",
|
||||
" </tr>\n",
|
||||
" <tr>\n",
|
||||
" <th>6</th>\n",
|
||||
" <td>0.009706</td>\n",
|
||||
" <td>0.009967</td>\n",
|
||||
" <td>1</td>\n",
|
||||
" <td>0.994911</td>\n",
|
||||
" <td>1</td>\n",
|
||||
" <td>2018-10-01 15:16:30</td>\n",
|
||||
" <td>6</td>\n",
|
||||
" </tr>\n",
|
||||
" <tr>\n",
|
||||
" <th>7</th>\n",
|
||||
" <td>0.009625</td>\n",
|
||||
" <td>0.009954</td>\n",
|
||||
" <td>1</td>\n",
|
||||
" <td>0.998919</td>\n",
|
||||
" <td>1</td>\n",
|
||||
" <td>2018-10-01 15:16:31</td>\n",
|
||||
" <td>7</td>\n",
|
||||
" </tr>\n",
|
||||
" <tr>\n",
|
||||
" <th>8</th>\n",
|
||||
" <td>0.009632</td>\n",
|
||||
" <td>0.009938</td>\n",
|
||||
" <td>1</td>\n",
|
||||
" <td>0.995047</td>\n",
|
||||
" <td>1</td>\n",
|
||||
" <td>2018-10-01 15:16:32</td>\n",
|
||||
" <td>8</td>\n",
|
||||
" </tr>\n",
|
||||
" <tr>\n",
|
||||
" <th>9</th>\n",
|
||||
" <td>0.009648</td>\n",
|
||||
" <td>0.009922</td>\n",
|
||||
" <td>1</td>\n",
|
||||
" <td>0.980786</td>\n",
|
||||
" <td>1</td>\n",
|
||||
" <td>2018-10-01 15:16:33</td>\n",
|
||||
" <td>9</td>\n",
|
||||
" </tr>\n",
|
||||
" </tbody>\n",
|
||||
"</table>\n",
|
||||
"</div>"
|
||||
],
|
||||
"text/plain": [
|
||||
" XNS_fiat_external XNS_fiat_internal run stable_external substep \\\n",
|
||||
"0 0.010000 0.010000 1 1.000000 0 \n",
|
||||
"1 0.009944 0.010000 1 1.000172 1 \n",
|
||||
"2 0.009889 0.009997 1 1.003516 1 \n",
|
||||
"3 0.009848 0.009992 1 0.990655 1 \n",
|
||||
"4 0.009814 0.009985 1 1.001346 1 \n",
|
||||
"5 0.009798 0.009976 1 1.002495 1 \n",
|
||||
"6 0.009706 0.009967 1 0.994911 1 \n",
|
||||
"7 0.009625 0.009954 1 0.998919 1 \n",
|
||||
"8 0.009632 0.009938 1 0.995047 1 \n",
|
||||
"9 0.009648 0.009922 1 0.980786 1 \n",
|
||||
"\n",
|
||||
" timestamp timestep \n",
|
||||
"0 2018-10-01 15:16:24 0 \n",
|
||||
"1 2018-10-01 15:16:25 1 \n",
|
||||
"2 2018-10-01 15:16:26 2 \n",
|
||||
"3 2018-10-01 15:16:27 3 \n",
|
||||
"4 2018-10-01 15:16:28 4 \n",
|
||||
"5 2018-10-01 15:16:29 5 \n",
|
||||
"6 2018-10-01 15:16:30 6 \n",
|
||||
"7 2018-10-01 15:16:31 7 \n",
|
||||
"8 2018-10-01 15:16:32 8 \n",
|
||||
"9 2018-10-01 15:16:33 9 "
|
||||
]
|
||||
},
|
||||
"execution_count": 25,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"df.head(10)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": []
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.6.5"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 2
|
||||
}
|
||||
|
|
@ -0,0 +1,57 @@
|
|||
import unittest
|
||||
from parameterized import parameterized
|
||||
from functools import reduce
|
||||
|
||||
|
||||
def generate_assertions_df(df, expected_results, target_cols, evaluations):
|
||||
test_names = []
|
||||
for eval_f in evaluations:
|
||||
def wrapped_eval(a, b):
|
||||
try:
|
||||
return eval_f(a, b)
|
||||
except KeyError:
|
||||
return True
|
||||
|
||||
test_name = f"{eval_f.__name__}_test"
|
||||
test_names.append(test_name)
|
||||
df[test_name] = df.apply(
|
||||
lambda x: wrapped_eval(
|
||||
x.filter(items=target_cols).to_dict(),
|
||||
expected_results[(x['run'], x['timestep'], x['substep'])]
|
||||
),
|
||||
axis=1
|
||||
)
|
||||
|
||||
return df, test_names
|
||||
|
||||
|
||||
def make_generic_test(params):
|
||||
class TestSequence(unittest.TestCase):
|
||||
|
||||
def generic_test(self, tested_df, expected_reults, test_name):
|
||||
erroneous = tested_df[(tested_df[test_name] == False)]
|
||||
# print(tabulate(tested_df, headers='keys', tablefmt='psql'))
|
||||
|
||||
if erroneous.empty is False: # Or Entire df IS NOT erroneous
|
||||
for index, row in erroneous.iterrows():
|
||||
expected = expected_reults[(row['run'], row['timestep'], row['substep'])]
|
||||
unexpected = {f"invalid_{k}": expected[k] for k in expected if k in row and expected[k] != row[k]}
|
||||
|
||||
for key in unexpected.keys():
|
||||
erroneous[key] = None
|
||||
erroneous.at[index, key] = unexpected[key]
|
||||
# etc.
|
||||
|
||||
# ToDo: Condition that will change false to true
|
||||
self.assertTrue(reduce(lambda a, b: a and b, tested_df[test_name]))
|
||||
|
||||
|
||||
@parameterized.expand(params)
|
||||
def test_validation(self, name, result_df, expected_reults, target_cols, evaluations):
|
||||
# alt for (*) Exec Debug mode
|
||||
tested_df, test_names = generate_assertions_df(result_df, expected_reults, target_cols, evaluations)
|
||||
|
||||
for test_name in test_names:
|
||||
self.generic_test(tested_df, expected_reults, test_name)
|
||||
|
||||
return TestSequence
|
||||
|
|
@ -0,0 +1,66 @@
|
|||
from cadCAD.configuration import append_configs
|
||||
from cadCAD.configuration.utils import config_sim
|
||||
import pandas as pd
|
||||
from cadCAD.utils import SilentDF
|
||||
|
||||
df = SilentDF(pd.read_csv('/DiffyQ-SimCAD/simulations/external_data/output.csv'))
|
||||
|
||||
|
||||
def query(s, df):
|
||||
return df[
|
||||
(df['run'] == s['run']) & (df['substep'] == s['substep']) & (df['timestep'] == s['timestep'])
|
||||
].drop(columns=['run', 'substep', "timestep"])
|
||||
|
||||
def p1(_g, substep, sL, s):
|
||||
result_dict = query(s, df).to_dict()
|
||||
del result_dict["ds3"]
|
||||
return {k: list(v.values()).pop() for k, v in result_dict.items()}
|
||||
|
||||
def p2(_g, substep, sL, s):
|
||||
result_dict = query(s, df).to_dict()
|
||||
del result_dict["ds1"], result_dict["ds2"]
|
||||
return {k: list(v.values()).pop() for k, v in result_dict.items()}
|
||||
|
||||
# integrate_ext_dataset
|
||||
def integrate_ext_dataset(_g, step, sL, s, _input):
|
||||
result_dict = query(s, df).to_dict()
|
||||
return 'external_data', {k: list(v.values()).pop() for k, v in result_dict.items()}
|
||||
|
||||
def increment(y, incr_by):
|
||||
return lambda _g, step, sL, s, _input: (y, s[y] + incr_by)
|
||||
increment = increment('increment', 1)
|
||||
|
||||
def view_policies(_g, step, sL, s, _input):
|
||||
return 'policies', _input
|
||||
|
||||
|
||||
external_data = {'ds1': None, 'ds2': None, 'ds3': None}
|
||||
state_dict = {
|
||||
'increment': 0,
|
||||
'external_data': external_data,
|
||||
'policies': external_data
|
||||
}
|
||||
|
||||
|
||||
policies = {"p1": p1, "p2": p2}
|
||||
states = {'increment': increment, 'external_data': integrate_ext_dataset, 'policies': view_policies}
|
||||
PSUB = {'policies': policies, 'states': states}
|
||||
|
||||
# needs M1&2 need behaviors
|
||||
partial_state_update_blocks = {
|
||||
'PSUB1': PSUB,
|
||||
'PSUB2': PSUB,
|
||||
'PSUB3': PSUB
|
||||
}
|
||||
|
||||
sim_config = config_sim({
|
||||
"N": 2,
|
||||
"T": range(4)
|
||||
})
|
||||
|
||||
append_configs(
|
||||
sim_configs=sim_config,
|
||||
initial_state=state_dict,
|
||||
partial_state_update_blocks=partial_state_update_blocks,
|
||||
policy_ops=[lambda a, b: {**a, **b}]
|
||||
)
|
||||
|
|
@ -0,0 +1,93 @@
|
|||
from cadCAD.configuration import append_configs
|
||||
from cadCAD.configuration.utils import config_sim, access_block
|
||||
|
||||
|
||||
policies, variables = {}, {}
|
||||
exclusion_list = ['nonexsistant', 'last_x', '2nd_to_last_x', '3rd_to_last_x', '4th_to_last_x']
|
||||
|
||||
# Policies per Mechanism
|
||||
|
||||
# WARNING: DO NOT delete elements from sH
|
||||
# state_history, target_field, psu_block_offset, exculsion_list
|
||||
def last_update(_g, substep, sH, s):
|
||||
return {"last_x": access_block(
|
||||
state_history=sH,
|
||||
target_field="last_x",
|
||||
psu_block_offset=-1,
|
||||
exculsion_list=exclusion_list
|
||||
)
|
||||
}
|
||||
policies["last_x"] = last_update
|
||||
|
||||
def second2last_update(_g, substep, sH, s):
|
||||
return {"2nd_to_last_x": access_block(sH, "2nd_to_last_x", -2, exclusion_list)}
|
||||
policies["2nd_to_last_x"] = second2last_update
|
||||
|
||||
|
||||
# Internal States per Mechanism
|
||||
|
||||
# WARNING: DO NOT delete elements from sH
|
||||
def add(y, x):
|
||||
return lambda _g, substep, sH, s, _input: (y, s[y] + x)
|
||||
variables['x'] = add('x', 1)
|
||||
|
||||
# last_partial_state_update_block
|
||||
def nonexsistant(_g, substep, sH, s, _input):
|
||||
return 'nonexsistant', access_block(sH, "nonexsistant", 0, exclusion_list)
|
||||
variables['nonexsistant'] = nonexsistant
|
||||
|
||||
# last_partial_state_update_block
|
||||
def last_x(_g, substep, sH, s, _input):
|
||||
return 'last_x', _input["last_x"]
|
||||
variables['last_x'] = last_x
|
||||
|
||||
# 2nd to last partial state update block
|
||||
def second_to_last_x(_g, substep, sH, s, _input):
|
||||
return '2nd_to_last_x', _input["2nd_to_last_x"]
|
||||
variables['2nd_to_last_x'] = second_to_last_x
|
||||
|
||||
# 3rd to last partial state update block
|
||||
def third_to_last_x(_g, substep, sH, s, _input):
|
||||
return '3rd_to_last_x', access_block(sH, "3rd_to_last_x", -3, exclusion_list)
|
||||
variables['3rd_to_last_x'] = third_to_last_x
|
||||
|
||||
# 4th to last partial state update block
|
||||
def fourth_to_last_x(_g, substep, sH, s, _input):
|
||||
return '4th_to_last_x', access_block(sH, "4th_to_last_x", -4, exclusion_list)
|
||||
variables['4th_to_last_x'] = fourth_to_last_x
|
||||
|
||||
|
||||
genesis_states = {
|
||||
'x': 0,
|
||||
'nonexsistant': [],
|
||||
'last_x': [],
|
||||
'2nd_to_last_x': [],
|
||||
'3rd_to_last_x': [],
|
||||
'4th_to_last_x': []
|
||||
}
|
||||
|
||||
PSUB = {
|
||||
"policies": policies,
|
||||
"variables": variables
|
||||
}
|
||||
|
||||
partial_state_update_block = {
|
||||
"PSUB1": PSUB,
|
||||
"PSUB2": PSUB,
|
||||
"PSUB3": PSUB
|
||||
}
|
||||
|
||||
sim_config = config_sim(
|
||||
{
|
||||
"N": 1,
|
||||
"T": range(3),
|
||||
}
|
||||
)
|
||||
|
||||
append_configs(
|
||||
sim_configs=sim_config,
|
||||
initial_state=genesis_states,
|
||||
partial_state_update_blocks=partial_state_update_block
|
||||
)
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,98 @@
|
|||
import pprint
|
||||
from typing import Dict, List
|
||||
|
||||
from cadCAD.configuration import append_configs
|
||||
from cadCAD.configuration.utils import env_trigger, var_substep_trigger, config_sim, psub_list
|
||||
|
||||
pp = pprint.PrettyPrinter(indent=4)
|
||||
|
||||
def some_function(x):
|
||||
return x
|
||||
|
||||
# Optional
|
||||
# dict must contain lists opf 2 distinct lengths
|
||||
g: Dict[str, List[int]] = {
|
||||
'alpha': [1],
|
||||
'beta': [2, some_function],
|
||||
'gamma': [3, 4],
|
||||
'omega': [7]
|
||||
}
|
||||
|
||||
psu_steps = ['m1', 'm2', 'm3']
|
||||
system_substeps = len(psu_steps)
|
||||
var_timestep_trigger = var_substep_trigger([0, system_substeps])
|
||||
env_timestep_trigger = env_trigger(system_substeps)
|
||||
env_process = {}
|
||||
|
||||
|
||||
# ['s1', 's2', 's3', 's4']
|
||||
# Policies per Mechanism
|
||||
def gamma(_g, step, sL, s):
|
||||
return {'gamma': _g['gamma']}
|
||||
|
||||
|
||||
def omega(_g, step, sL, s):
|
||||
return {'omega': _g['omega']}
|
||||
|
||||
|
||||
# Internal States per Mechanism
|
||||
def alpha(_g, step, sL, s, _input):
|
||||
return 'alpha', _g['alpha']
|
||||
|
||||
|
||||
def beta(_g, step, sL, s, _input):
|
||||
return 'beta', _g['beta']
|
||||
|
||||
|
||||
def policies(_g, step, sL, s, _input):
|
||||
return 'policies', _input
|
||||
|
||||
|
||||
def sweeped(_g, step, sL, s, _input):
|
||||
return 'sweeped', {'beta': _g['beta'], 'gamma': _g['gamma']}
|
||||
|
||||
psu_block = {k: {"policies": {}, "variables": {}} for k in psu_steps}
|
||||
for m in psu_steps:
|
||||
psu_block[m]['policies']['gamma'] = gamma
|
||||
psu_block[m]['policies']['omega'] = omega
|
||||
psu_block[m]["variables"]['alpha'] = alpha
|
||||
psu_block[m]["variables"]['beta'] = beta
|
||||
psu_block[m]['variables']['policies'] = policies
|
||||
psu_block[m]["variables"]['sweeped'] = var_timestep_trigger(y='sweeped', f=sweeped)
|
||||
|
||||
|
||||
# Genesis States
|
||||
genesis_states = {
|
||||
'alpha': 0,
|
||||
'beta': 0,
|
||||
'policies': {},
|
||||
'sweeped': {}
|
||||
}
|
||||
|
||||
# Environment Process
|
||||
env_process['sweeped'] = env_timestep_trigger(trigger_field='timestep', trigger_vals=[5], funct_list=[lambda _g, x: _g['beta']])
|
||||
|
||||
|
||||
sim_config = config_sim(
|
||||
{
|
||||
"N": 2,
|
||||
"T": range(5),
|
||||
"M": g, # Optional
|
||||
}
|
||||
)
|
||||
|
||||
# New Convention
|
||||
partial_state_update_blocks = psub_list(psu_block, psu_steps)
|
||||
append_configs(
|
||||
sim_configs=sim_config,
|
||||
initial_state=genesis_states,
|
||||
env_processes=env_process,
|
||||
partial_state_update_blocks=partial_state_update_blocks
|
||||
)
|
||||
|
||||
|
||||
print()
|
||||
print("Policie State Update Block:")
|
||||
pp.pprint(partial_state_update_blocks)
|
||||
print()
|
||||
print()
|
||||
|
|
@ -0,0 +1,83 @@
|
|||
from cadCAD.configuration import append_configs
|
||||
from cadCAD.configuration.utils import config_sim
|
||||
|
||||
|
||||
# Policies per Mechanism
|
||||
def p1m1(_g, step, sL, s):
|
||||
return {'policy1': 1}
|
||||
def p2m1(_g, step, sL, s):
|
||||
return {'policy2': 2}
|
||||
|
||||
def p1m2(_g, step, sL, s):
|
||||
return {'policy1': 2, 'policy2': 2}
|
||||
def p2m2(_g, step, sL, s):
|
||||
return {'policy1': 2, 'policy2': 2}
|
||||
|
||||
def p1m3(_g, step, sL, s):
|
||||
return {'policy1': 1, 'policy2': 2, 'policy3': 3}
|
||||
def p2m3(_g, step, sL, s):
|
||||
return {'policy1': 1, 'policy2': 2, 'policy3': 3}
|
||||
|
||||
|
||||
# Internal States per Mechanism
|
||||
def add(y, x):
|
||||
return lambda _g, step, sH, s, _input: (y, s[y] + x)
|
||||
|
||||
def policies(_g, step, sH, s, _input):
|
||||
y = 'policies'
|
||||
x = _input
|
||||
return (y, x)
|
||||
|
||||
|
||||
# Genesis States
|
||||
genesis_states = {
|
||||
'policies': {},
|
||||
's1': 0
|
||||
}
|
||||
|
||||
variables = {
|
||||
's1': add('s1', 1),
|
||||
"policies": policies
|
||||
}
|
||||
|
||||
partial_state_update_block = {
|
||||
"m1": {
|
||||
"policies": {
|
||||
"p1": p1m1,
|
||||
"p2": p2m1
|
||||
},
|
||||
"variables": variables
|
||||
},
|
||||
"m2": {
|
||||
"policies": {
|
||||
"p1": p1m2,
|
||||
"p2": p2m2
|
||||
},
|
||||
"variables": variables
|
||||
},
|
||||
"m3": {
|
||||
"policies": {
|
||||
"p1": p1m3,
|
||||
"p2": p2m3
|
||||
},
|
||||
"variables": variables
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
sim_config = config_sim(
|
||||
{
|
||||
"N": 1,
|
||||
"T": range(3),
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
append_configs(
|
||||
sim_configs=sim_config,
|
||||
initial_state=genesis_states,
|
||||
partial_state_update_blocks=partial_state_update_block,
|
||||
policy_ops=[lambda a, b: a + b, lambda y: y * 2] # Default: lambda a, b: a + b
|
||||
)
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,110 @@
|
|||
import unittest
|
||||
|
||||
import pandas as pd
|
||||
from cadCAD.engine import ExecutionMode, ExecutionContext, Executor
|
||||
from simulations.regression_tests import external_dataset
|
||||
from cadCAD import configs
|
||||
from testing.generic_test import make_generic_test
|
||||
|
||||
exec_mode = ExecutionMode()
|
||||
|
||||
print("Simulation Execution: Single Configuration")
|
||||
print()
|
||||
first_config = configs
|
||||
single_proc_ctx = ExecutionContext(context=exec_mode.single_proc)
|
||||
run = Executor(exec_context=single_proc_ctx, configs=first_config)
|
||||
|
||||
raw_result, tensor_field = run.execute()
|
||||
result = pd.DataFrame(raw_result)
|
||||
|
||||
|
||||
def get_expected_results(run):
|
||||
return {
|
||||
(run, 0, 0): {
|
||||
'external_data': {'ds1': None, 'ds2': None, 'ds3': None},
|
||||
'increment': 0,
|
||||
'policies': {'ds1': None, 'ds2': None, 'ds3': None}
|
||||
},
|
||||
(run, 1, 1): {
|
||||
'external_data': {'ds1': 0, 'ds2': 0, 'ds3': 1},
|
||||
'increment': 1,
|
||||
'policies': {'ds1': 0, 'ds2': 0, 'ds3': 1}
|
||||
},
|
||||
(run, 1, 2): {
|
||||
'external_data': {'ds1': 1, 'ds2': 40, 'ds3': 5},
|
||||
'increment': 2,
|
||||
'policies': {'ds1': 1, 'ds2': 40, 'ds3': 5}
|
||||
},
|
||||
(run, 1, 3): {
|
||||
'external_data': {'ds1': 2, 'ds2': 40, 'ds3': 5},
|
||||
'increment': 3,
|
||||
'policies': {'ds1': 2, 'ds2': 40, 'ds3': 5}
|
||||
},
|
||||
(run, 2, 1): {
|
||||
'external_data': {'ds1': 3, 'ds2': 40, 'ds3': 5},
|
||||
'increment': 4,
|
||||
'policies': {'ds1': 3, 'ds2': 40, 'ds3': 5}
|
||||
},
|
||||
(run, 2, 2): {
|
||||
'external_data': {'ds1': 4, 'ds2': 40, 'ds3': 5},
|
||||
'increment': 5,
|
||||
'policies': {'ds1': 4, 'ds2': 40, 'ds3': 5}
|
||||
},
|
||||
(run, 2, 3): {
|
||||
'external_data': {'ds1': 5, 'ds2': 40, 'ds3': 5},
|
||||
'increment': 6,
|
||||
'policies': {'ds1': 5, 'ds2': 40, 'ds3': 5}
|
||||
},
|
||||
(run, 3, 1): {
|
||||
'external_data': {'ds1': 6, 'ds2': 40, 'ds3': 5},
|
||||
'increment': 7,
|
||||
'policies': {'ds1': 6, 'ds2': 40, 'ds3': 5}
|
||||
},
|
||||
(run, 3, 2): {
|
||||
'external_data': {'ds1': 7, 'ds2': 40, 'ds3': 5},
|
||||
'increment': 8,
|
||||
'policies': {'ds1': 7, 'ds2': 40, 'ds3': 5}
|
||||
},
|
||||
(run, 3, 3): {
|
||||
'external_data': {'ds1': 8, 'ds2': 40, 'ds3': 5},
|
||||
'increment': 9,
|
||||
'policies': {'ds1': 8, 'ds2': 40, 'ds3': 5}
|
||||
},
|
||||
(run, 4, 1): {
|
||||
'external_data': {'ds1': 9, 'ds2': 40, 'ds3': 5},
|
||||
'increment': 10,
|
||||
'policies': {'ds1': 9, 'ds2': 40, 'ds3': 5}
|
||||
},
|
||||
(run, 4, 2): {
|
||||
'external_data': {'ds1': 10, 'ds2': 40, 'ds3': 5},
|
||||
'increment': 11,
|
||||
'policies': {'ds1': 10, 'ds2': 40, 'ds3': 5}
|
||||
},
|
||||
(run, 4, 3): {
|
||||
'external_data': {'ds1': 11, 'ds2': 40, 'ds3': 5},
|
||||
'increment': 12,
|
||||
'policies': {'ds1': 11, 'ds2': 40, 'ds3': 5}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
expected_results = {}
|
||||
expected_results_1 = get_expected_results(1)
|
||||
expected_results_2 = get_expected_results(2)
|
||||
expected_results.update(expected_results_1)
|
||||
expected_results.update(expected_results_2)
|
||||
|
||||
|
||||
def row(a, b):
|
||||
return a == b
|
||||
|
||||
|
||||
params = [["external_dataset", result, expected_results, ['increment', 'external_data', 'policies'], [row]]]
|
||||
|
||||
|
||||
class GenericTest(make_generic_test(params)):
|
||||
pass
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
|
|
@ -0,0 +1,124 @@
|
|||
import unittest
|
||||
import pandas as pd
|
||||
|
||||
from cadCAD.engine import ExecutionMode, ExecutionContext, Executor
|
||||
from testing.generic_test import make_generic_test
|
||||
from testing.system_models import historical_state_access
|
||||
from cadCAD import configs
|
||||
|
||||
|
||||
exec_mode = ExecutionMode()
|
||||
single_proc_ctx = ExecutionContext(context=exec_mode.single_proc)
|
||||
run = Executor(exec_context=single_proc_ctx, configs=configs)
|
||||
|
||||
raw_result, tensor_field = run.execute()
|
||||
result = pd.DataFrame(raw_result)
|
||||
expected_results = {
|
||||
(1, 0, 0): {'x': 0, 'nonexsistant': [], 'last_x': [], '2nd_to_last_x': [], '3rd_to_last_x': [], '4th_to_last_x': []},
|
||||
(1, 1, 1): {'x': 1,
|
||||
'nonexsistant': [],
|
||||
'last_x': [{'x': 0, 'run': 1, 'substep': 0, 'timestep': 0}],
|
||||
'2nd_to_last_x': [],
|
||||
'3rd_to_last_x': [],
|
||||
'4th_to_last_x': []},
|
||||
(1, 1, 2): {'x': 2,
|
||||
'nonexsistant': [],
|
||||
'last_x': [{'x': 0, 'run': 1, 'substep': 0, 'timestep': 0}],
|
||||
'2nd_to_last_x': [],
|
||||
'3rd_to_last_x': [],
|
||||
'4th_to_last_x': []},
|
||||
(1, 1, 3): {'x': 3,
|
||||
'nonexsistant': [],
|
||||
'last_x': [{'x': 0, 'run': 1, 'substep': 0, 'timestep': 0}],
|
||||
'2nd_to_last_x': [],
|
||||
'3rd_to_last_x': [],
|
||||
'4th_to_last_x': []},
|
||||
(1, 2, 1): {'x': 4,
|
||||
'nonexsistant': [],
|
||||
'last_x': [
|
||||
{'x': 4, 'run': 1, 'substep': 1, 'timestep': 1}, # x: 1
|
||||
{'x': 2, 'run': 1, 'substep': 2, 'timestep': 1},
|
||||
{'x': 3, 'run': 1, 'substep': 3, 'timestep': 1}
|
||||
],
|
||||
'2nd_to_last_x': [{'x': -1, 'run': 1, 'substep': 0, 'timestep': 0}], # x: 0
|
||||
'3rd_to_last_x': [],
|
||||
'4th_to_last_x': []},
|
||||
(1, 2, 2): {'x': 5,
|
||||
'nonexsistant': [],
|
||||
'last_x': [
|
||||
{'x': 1, 'run': 1, 'substep': 1, 'timestep': 1},
|
||||
{'x': 2, 'run': 1, 'substep': 2, 'timestep': 1},
|
||||
{'x': 3, 'run': 1, 'substep': 3, 'timestep': 1}
|
||||
],
|
||||
'2nd_to_last_x': [{'x': 0, 'run': 1, 'substep': 0, 'timestep': 0}],
|
||||
'3rd_to_last_x': [],
|
||||
'4th_to_last_x': []},
|
||||
(1, 2, 3): {'x': 6,
|
||||
'nonexsistant': [],
|
||||
'last_x': [
|
||||
{'x': 1, 'run': 1, 'substep': 1, 'timestep': 1},
|
||||
{'x': 2, 'run': 1, 'substep': 2, 'timestep': 1},
|
||||
{'x': 3, 'run': 1, 'substep': 3, 'timestep': 1}
|
||||
],
|
||||
'2nd_to_last_x': [{'x': 0, 'run': 1, 'substep': 0, 'timestep': 0}],
|
||||
'3rd_to_last_x': [],
|
||||
'4th_to_last_x': []},
|
||||
(1, 3, 1): {'x': 7,
|
||||
'nonexsistant': [],
|
||||
'last_x': [
|
||||
{'x': 4, 'run': 1, 'substep': 1, 'timestep': 2},
|
||||
{'x': 5, 'run': 1, 'substep': 2, 'timestep': 2},
|
||||
{'x': 6, 'run': 1, 'substep': 3, 'timestep': 2}
|
||||
],
|
||||
'2nd_to_last_x': [
|
||||
{'x': 1, 'run': 1, 'substep': 1, 'timestep': 1},
|
||||
{'x': 2, 'run': 1, 'substep': 2, 'timestep': 1},
|
||||
{'x': 3, 'run': 1, 'substep': 3, 'timestep': 1}
|
||||
],
|
||||
'3rd_to_last_x': [{'x': 0, 'run': 1, 'substep': 0, 'timestep': 0}],
|
||||
'4th_to_last_x': []},
|
||||
(1, 3, 2): {'x': 8,
|
||||
'nonexsistant': [],
|
||||
'last_x': [
|
||||
{'x': 4, 'run': 1, 'substep': 1, 'timestep': 2},
|
||||
{'x': 5, 'run': 1, 'substep': 2, 'timestep': 2},
|
||||
{'x': 6, 'run': 1, 'substep': 3, 'timestep': 2}
|
||||
],
|
||||
'2nd_to_last_x': [
|
||||
{'x': 1, 'run': 1, 'substep': 1, 'timestep': 1},
|
||||
{'x': 2, 'run': 1, 'substep': 2, 'timestep': 1},
|
||||
{'x': 3, 'run': 1, 'substep': 3, 'timestep': 1}
|
||||
],
|
||||
'3rd_to_last_x': [{'x': 0, 'run': 1, 'substep': 0, 'timestep': 0}],
|
||||
'4th_to_last_x': []},
|
||||
(1, 3, 3): {'x': 9,
|
||||
'nonexsistant': [],
|
||||
'last_x': [
|
||||
{'x': 4, 'run': 1, 'substep': 1, 'timestep': 2},
|
||||
{'x': 5, 'run': 1, 'substep': 2, 'timestep': 2},
|
||||
{'x': 6, 'run': 1, 'substep': 3, 'timestep': 2}
|
||||
],
|
||||
'2nd_to_last_x': [
|
||||
{'x': 1, 'run': 1, 'substep': 1, 'timestep': 1},
|
||||
{'x': 2, 'run': 1, 'substep': 2, 'timestep': 1},
|
||||
{'x': 3, 'run': 1, 'substep': 3, 'timestep': 1}
|
||||
],
|
||||
'3rd_to_last_x': [{'x': 0, 'run': 1, 'substep': 0, 'timestep': 0}],
|
||||
'4th_to_last_x': []}
|
||||
}
|
||||
|
||||
|
||||
def row(a, b):
|
||||
return a == b
|
||||
params = [
|
||||
["historical_state_access", result, expected_results,
|
||||
['x', 'nonexsistant', 'last_x', '2nd_to_last_x', '3rd_to_last_x', '4th_to_last_x'], [row]]
|
||||
]
|
||||
|
||||
|
||||
class GenericTest(make_generic_test(params)):
|
||||
pass
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
|
|
@ -0,0 +1,73 @@
|
|||
import unittest
|
||||
import pandas as pd
|
||||
|
||||
|
||||
from cadCAD.engine import ExecutionMode, ExecutionContext, Executor
|
||||
from testing.system_models import param_sweep
|
||||
from cadCAD import configs
|
||||
|
||||
from testing.generic_test import make_generic_test
|
||||
from testing.system_models.param_sweep import some_function
|
||||
|
||||
|
||||
exec_mode = ExecutionMode()
|
||||
multi_proc_ctx = ExecutionContext(context=exec_mode.multi_proc)
|
||||
run = Executor(exec_context=multi_proc_ctx, configs=configs)
|
||||
|
||||
|
||||
def get_expected_results(run, beta, gamma):
|
||||
return {
|
||||
(run, 0, 0): {'policies': {}, 'sweeped': {}, 'alpha': 0, 'beta': 0},
|
||||
(run, 1, 1): {'policies': {'gamma': gamma, 'omega': 7}, 'sweeped': {'beta': beta, 'gamma': gamma}, 'alpha': 1, 'beta': beta},
|
||||
(run, 1, 2): {'policies': {'gamma': gamma, 'omega': 7}, 'sweeped': {'beta': beta, 'gamma': gamma}, 'alpha': 1, 'beta': beta},
|
||||
(run, 1, 3): {'policies': {'gamma': gamma, 'omega': 7}, 'sweeped': {'beta': beta, 'gamma': gamma}, 'alpha': 1, 'beta': beta},
|
||||
(run, 2, 1): {'policies': {'gamma': gamma, 'omega': 7}, 'sweeped': {'beta': beta, 'gamma': gamma}, 'alpha': 1, 'beta': beta},
|
||||
(run, 2, 2): {'policies': {'gamma': gamma, 'omega': 7}, 'sweeped': {'beta': beta, 'gamma': gamma}, 'alpha': 1, 'beta': beta},
|
||||
(run, 2, 3): {'policies': {'gamma': gamma, 'omega': 7}, 'sweeped': {'beta': beta, 'gamma': gamma}, 'alpha': 1, 'beta': beta},
|
||||
(run, 3, 1): {'policies': {'gamma': gamma, 'omega': 7}, 'sweeped': {'beta': beta, 'gamma': gamma}, 'alpha': 1, 'beta': beta},
|
||||
(run, 3, 2): {'policies': {'gamma': gamma, 'omega': 7}, 'sweeped': {'beta': beta, 'gamma': gamma}, 'alpha': 1, 'beta': beta},
|
||||
(run, 3, 3): {'policies': {'gamma': gamma, 'omega': 7}, 'sweeped': {'beta': beta, 'gamma': gamma}, 'alpha': 1, 'beta': beta},
|
||||
(run, 4, 1): {'policies': {'gamma': gamma, 'omega': 7}, 'sweeped': {'beta': beta, 'gamma': gamma}, 'alpha': 1, 'beta': beta},
|
||||
(run, 4, 2): {'policies': {'gamma': gamma, 'omega': 7}, 'sweeped': {'beta': beta, 'gamma': gamma}, 'alpha': 1, 'beta': beta},
|
||||
(run, 4, 3): {'policies': {'gamma': gamma, 'omega': 7}, 'sweeped': {'beta': beta, 'gamma': gamma}, 'alpha': 1, 'beta': beta},
|
||||
(run, 5, 1): {'policies': {'gamma': gamma, 'omega': 7}, 'sweeped': beta, 'alpha': 1, 'beta': beta},
|
||||
(run, 5, 2): {'policies': {'gamma': gamma, 'omega': 7}, 'sweeped': beta, 'alpha': 1, 'beta': beta},
|
||||
(run, 5, 3): {'policies': {'gamma': gamma, 'omega': 7}, 'sweeped': beta, 'alpha': 1, 'beta': beta}
|
||||
}
|
||||
|
||||
|
||||
expected_results_1 = {}
|
||||
expected_results_1a = get_expected_results(1, 2, 3)
|
||||
expected_results_1b = get_expected_results(2, 2, 3)
|
||||
expected_results_1.update(expected_results_1a)
|
||||
expected_results_1.update(expected_results_1b)
|
||||
|
||||
expected_results_2 = {}
|
||||
expected_results_2a = get_expected_results(1, some_function, 4)
|
||||
expected_results_2b = get_expected_results(2, some_function, 4)
|
||||
expected_results_2.update(expected_results_2a)
|
||||
expected_results_2.update(expected_results_2b)
|
||||
|
||||
|
||||
i = 0
|
||||
expected_results = [expected_results_1, expected_results_2]
|
||||
config_names = ['sweep_config_A', 'sweep_config_B']
|
||||
|
||||
def row(a, b):
|
||||
return a == b
|
||||
def create_test_params(feature, fields):
|
||||
i = 0
|
||||
for raw_result, _ in run.execute():
|
||||
yield [feature, pd.DataFrame(raw_result), expected_results[i], fields, [row]]
|
||||
i += 1
|
||||
|
||||
|
||||
params = list(create_test_params("param_sweep", ['alpha', 'beta', 'policies', 'sweeped']))
|
||||
|
||||
|
||||
class GenericTest(make_generic_test(params)):
|
||||
pass
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
import unittest
|
||||
import pandas as pd
|
||||
|
||||
from cadCAD.engine import ExecutionMode, ExecutionContext, Executor
|
||||
from testing.generic_test import make_generic_test
|
||||
from testing.system_models import policy_aggregation
|
||||
from cadCAD import configs
|
||||
|
||||
exec_mode = ExecutionMode()
|
||||
single_proc_ctx = ExecutionContext(context=exec_mode.single_proc)
|
||||
run = Executor(exec_context=single_proc_ctx, configs=configs)
|
||||
|
||||
raw_result, tensor_field = run.execute()
|
||||
result = pd.DataFrame(raw_result)
|
||||
|
||||
expected_results = {
|
||||
(1, 0, 0): {'policies': {}, 's1': 0},
|
||||
(1, 1, 1): {'policies': {'policy1': 1, 'policy2': 4}, 's1': 1}, # 'policy1': 2
|
||||
(1, 1, 2): {'policies': {'policy1': 8, 'policy2': 8}, 's1': 2},
|
||||
(1, 1, 3): {'policies': {'policy1': 4, 'policy2': 8, 'policy3': 12}, 's1': 3},
|
||||
(1, 2, 1): {'policies': {'policy1': 2, 'policy2': 4}, 's1': 4},
|
||||
(1, 2, 2): {'policies': {'policy1': 8, 'policy2': 8}, 's1': 5},
|
||||
(1, 2, 3): {'policies': {'policy1': 4, 'policy2': 8, 'policy3': 12}, 's1': 6},
|
||||
(1, 3, 1): {'policies': {'policy1': 2, 'policy2': 4}, 's1': 7},
|
||||
(1, 3, 2): {'policies': {'policy1': 8, 'policy2': 8}, 's1': 8},
|
||||
(1, 3, 3): {'policies': {'policy1': 4, 'policy2': 8, 'policy3': 12}, 's1': 9}
|
||||
}
|
||||
|
||||
|
||||
def row(a, b):
|
||||
return a == b
|
||||
|
||||
|
||||
params = [["policy_aggregation", result, expected_results, ['policies', 's1'], [row]]]
|
||||
|
||||
|
||||
class GenericTest(make_generic_test(params)):
|
||||
pass
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
#
|
||||
# def record_generator(row, cols):
|
||||
# return {col: row[col] for col in cols}
|
||||
|
||||
def gen_metric_row(row, cols):
|
||||
return ((row['run'], row['timestep'], row['substep']), {col: row[col] for col in cols})
|
||||
|
||||
# def gen_metric_row(row):
|
||||
# return ((row['run'], row['timestep'], row['substep']), {'s1': row['s1'], 'policies': row['policies']})
|
||||
|
||||
# def gen_metric_row(row):
|
||||
# return {
|
||||
# 'run': row['run'],
|
||||
# 'timestep': row['timestep'],
|
||||
# 'substep': row['substep'],
|
||||
# 's1': row['s1'],
|
||||
# 'policies': row['policies']
|
||||
# }
|
||||
|
||||
def gen_metric_dict(df, cols):
|
||||
return dict([gen_metric_row(row, cols) for index, row in df.iterrows()])
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
**Robot and Marbles Tutorial Series**
|
||||
|
||||
In this series, we introduce basic concepts of cadCAD and system modelling in general using a simple toy model.
|
||||
[Part 1](robot-marbles-part-1/robot-marbles-part-1.ipynb) - States and State Update Functions
|
||||
[Part 2](robot-marbles-part-2/robot-marbles-part-2.ipynb) - Actions and State Dependent Policies
|
||||
[Part 3](robot-marbles-part-3/robot-marbles-part-3.ipynb) - From Synchronous to Asynchronous Time
|
||||
[Part 4](robot-marbles-part-4/robot-marbles-part-4.ipynb) - Uncertainty and Stochastic Processes
|
||||
[Part 5](robot-marbles-part-5/robot-marbles-part-5.ipynb) - Using class objects as state variables
|
||||
|
||||
Check out the [videos](videos) folder for detailed walkthroughs of each one of the tutorials.
|
||||
|
After Width: | Height: | Size: 59 KiB |
|
After Width: | Height: | Size: 47 KiB |
|
After Width: | Height: | Size: 39 KiB |
|
|
@ -0,0 +1 @@
|
|||
(https://youtu.be/uJEiYHRWA9g)
|
||||
|
|
@ -0,0 +1,85 @@
|
|||
# import libraries
|
||||
from decimal import Decimal
|
||||
import numpy as np
|
||||
from datetime import timedelta
|
||||
from cadCAD.configuration import append_configs
|
||||
from cadCAD.configuration.utils import bound_norm_random, ep_time_step, config_sim
|
||||
|
||||
seeds = {
|
||||
# 'z': np.random.RandomState(1),
|
||||
# 'a': np.random.RandomState(2)
|
||||
}
|
||||
|
||||
sim_config = config_sim({
|
||||
'T': range(10), #number of discrete iterations in each experiement
|
||||
'N': 1, #number of times the simulation will be run (Monte Carlo runs)
|
||||
#'M': g #parameter sweep dictionary
|
||||
})
|
||||
|
||||
|
||||
# define the time deltas for the discrete increments in the model
|
||||
# ts_format = '%Y-%m-%d %H:%M:%S'
|
||||
# t_delta = timedelta(days=0, minutes=1, seconds=0)
|
||||
# def time_model(_g, step, sL, s, _input):
|
||||
# y = 'time'
|
||||
# x = ep_time_step(s, dt_str=s['time'], fromat_str=ts_format, _timedelta=t_delta)
|
||||
# return (y, x)
|
||||
|
||||
# Behaviors
|
||||
|
||||
# Mechanisms
|
||||
def update_A(_g, step, sL, s, _input):
|
||||
y = 'box_A'
|
||||
add_to_A = 0
|
||||
if (s['box_A'] > s['box_B']):
|
||||
add_to_A = -1
|
||||
elif (s['box_A'] < s['box_B']):
|
||||
add_to_A = 1
|
||||
x = s['box_A'] + add_to_A
|
||||
return (y, x)
|
||||
|
||||
def update_B(_g, step, sL, s, _input):
|
||||
y = 'box_B'
|
||||
add_to_B = 0
|
||||
if (s['box_B'] > s['box_A']):
|
||||
add_to_B = -1
|
||||
elif (s['box_B'] < s['box_A']):
|
||||
add_to_B = 1
|
||||
x = s['box_B'] + add_to_B
|
||||
return (y, x)
|
||||
|
||||
# Initial States
|
||||
genesis_states = {
|
||||
'box_A': 10, # as per the description of the example, box_A starts out with 10 marbles in it
|
||||
'box_B': 0 # as per the description of the example, box_B starts out empty
|
||||
}
|
||||
|
||||
exogenous_states = {
|
||||
#'time': time_model
|
||||
}
|
||||
|
||||
env_processes = {
|
||||
}
|
||||
|
||||
#build mechanism dictionary to "wire up the circuit"
|
||||
mechanisms = [
|
||||
{
|
||||
'policies': {
|
||||
},
|
||||
'variables': { # The following state variables will be updated simultaneously
|
||||
'box_A': update_A,
|
||||
'box_B': update_B
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
|
||||
|
||||
append_configs(
|
||||
sim_configs=sim_config,
|
||||
initial_state=genesis_states,
|
||||
seeds=seeds,
|
||||
raw_exogenous_states=exogenous_states,
|
||||
env_processes=env_processes,
|
||||
partial_state_update_blocks=mechanisms
|
||||
)
|
||||
|
|
@ -0,0 +1,85 @@
|
|||
# import libraries
|
||||
from decimal import Decimal
|
||||
import numpy as np
|
||||
from datetime import timedelta
|
||||
from cadCAD.configuration import append_configs
|
||||
from cadCAD.configuration.utils import bound_norm_random, ep_time_step, config_sim
|
||||
|
||||
seeds = {
|
||||
# 'z': np.random.RandomState(1),
|
||||
# 'a': np.random.RandomState(2)
|
||||
}
|
||||
|
||||
sim_config = config_sim({
|
||||
'T': range(10), #number of discrete iterations in each experiement
|
||||
'N': 1, #number of times the simulation will be run (Monte Carlo runs)
|
||||
#'M': g #parameter sweep dictionary
|
||||
})
|
||||
|
||||
|
||||
# define the time deltas for the discrete increments in the model
|
||||
# ts_format = '%Y-%m-%d %H:%M:%S'
|
||||
# t_delta = timedelta(days=0, minutes=1, seconds=0)
|
||||
# def time_model(_g, step, sL, s, _input):
|
||||
# y = 'time'
|
||||
# x = ep_time_step(s, dt_str=s['time'], fromat_str=ts_format, _timedelta=t_delta)
|
||||
# return (y, x)
|
||||
|
||||
# Behaviors
|
||||
|
||||
# Mechanisms
|
||||
def update_A(_g, step, sL, s, _input):
|
||||
y = 'box_A'
|
||||
add_to_A = 0
|
||||
if (s['box_A'] > s['box_B']):
|
||||
add_to_A = -1
|
||||
elif (s['box_A'] < s['box_B']):
|
||||
add_to_A = 1
|
||||
x = s['box_A'] + add_to_A
|
||||
return (y, x)
|
||||
|
||||
def update_B(_g, step, sL, s, _input):
|
||||
y = 'box_B'
|
||||
add_to_B = 0
|
||||
if (s['box_B'] > s['box_A']):
|
||||
add_to_B = -1
|
||||
elif (s['box_B'] < s['box_A']):
|
||||
add_to_B = 1
|
||||
x = s['box_B'] + add_to_B
|
||||
return (y, x)
|
||||
|
||||
# Initial States
|
||||
genesis_states = {
|
||||
'box_A': 11, # as per the description of the example, box_A starts out with 10 marbles in it
|
||||
'box_B': 0 # as per the description of the example, box_B starts out empty
|
||||
}
|
||||
|
||||
exogenous_states = {
|
||||
#'time': time_model
|
||||
}
|
||||
|
||||
env_processes = {
|
||||
}
|
||||
|
||||
#build mechanism dictionary to "wire up the circuit"
|
||||
mechanisms = [
|
||||
{
|
||||
'policies': {
|
||||
},
|
||||
'variables': { # The following state variables will be updated simultaneously
|
||||
'box_A': update_A,
|
||||
'box_B': update_B
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
|
||||
|
||||
append_configs(
|
||||
sim_configs=sim_config,
|
||||
initial_state=genesis_states,
|
||||
seeds=seeds,
|
||||
raw_exogenous_states=exogenous_states,
|
||||
env_processes=env_processes,
|
||||
partial_state_update_blocks=mechanisms
|
||||
)
|
||||
|
After Width: | Height: | Size: 42 KiB |
|
After Width: | Height: | Size: 39 KiB |
|
After Width: | Height: | Size: 87 KiB |
|
|
@ -0,0 +1 @@
|
|||
(https://youtu.be/Y5MzhVRQyzY)
|
||||
|
|
@ -0,0 +1,85 @@
|
|||
# import libraries
|
||||
from decimal import Decimal
|
||||
import numpy as np
|
||||
from datetime import timedelta
|
||||
from cadCAD.configuration import append_configs
|
||||
from cadCAD.configuration.utils import bound_norm_random, ep_time_step, config_sim
|
||||
|
||||
seeds = {
|
||||
# 'z': np.random.RandomState(1),
|
||||
# 'a': np.random.RandomState(2)
|
||||
}
|
||||
|
||||
sim_config = config_sim({
|
||||
'T': range(10), #number of discrete iterations in each experiement
|
||||
'N': 1, #number of times the simulation will be run (Monte Carlo runs)
|
||||
#'M': g #parameter sweep dictionary
|
||||
})
|
||||
|
||||
|
||||
# define the time deltas for the discrete increments in the model
|
||||
# ts_format = '%Y-%m-%d %H:%M:%S'
|
||||
# t_delta = timedelta(days=0, minutes=1, seconds=0)
|
||||
# def time_model(_g, step, sL, s, _input):
|
||||
# y = 'time'
|
||||
# x = ep_time_step(s, dt_str=s['time'], fromat_str=ts_format, _timedelta=t_delta)
|
||||
# return (y, x)
|
||||
|
||||
# Behaviors
|
||||
def robot_arm(_g, step, sL, s):
|
||||
add_to_A = 0
|
||||
if (s['box_A'] > s['box_B']):
|
||||
add_to_A = -1
|
||||
elif (s['box_A'] < s['box_B']):
|
||||
add_to_A = 1
|
||||
return({'add_to_A': add_to_A, 'add_to_B': -add_to_A})
|
||||
|
||||
|
||||
|
||||
# Mechanisms
|
||||
def increment_A(_g, step, sL, s, _input):
|
||||
y = 'box_A'
|
||||
x = s['box_A'] + _input['add_to_A']
|
||||
return (y, x)
|
||||
|
||||
def increment_B(_g, step, sL, s, _input):
|
||||
y = 'box_B'
|
||||
x = s['box_B'] + _input['add_to_B']
|
||||
return (y, x)
|
||||
|
||||
# Initial States
|
||||
genesis_states = {
|
||||
'box_A': 10, # as per the description of the example, box_A starts out with 10 marbles in it
|
||||
'box_B': 0 # as per the description of the example, box_B starts out empty
|
||||
}
|
||||
|
||||
exogenous_states = {
|
||||
#'time': time_model
|
||||
}
|
||||
|
||||
env_processes = {
|
||||
}
|
||||
|
||||
#build mechanism dictionary to "wire up the circuit"
|
||||
mechanisms = [
|
||||
{
|
||||
'policies': { # The following policy functions will be evaluated and their returns will be passed to the state update functions
|
||||
'robot_arm': robot_arm
|
||||
},
|
||||
'states': { # The following state variables will be updated simultaneously
|
||||
'box_A': increment_A,
|
||||
'box_B': increment_B
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
|
||||
|
||||
append_configs(
|
||||
sim_configs=sim_config,
|
||||
initial_state=genesis_states,
|
||||
seeds=seeds,
|
||||
raw_exogenous_states=exogenous_states,
|
||||
env_processes=env_processes,
|
||||
partial_state_update_blocks=mechanisms
|
||||
)
|
||||
|
|
@ -0,0 +1,87 @@
|
|||
# import libraries
|
||||
from decimal import Decimal
|
||||
import numpy as np
|
||||
from datetime import timedelta
|
||||
from cadCAD.configuration import append_configs
|
||||
from cadCAD.configuration.utils import bound_norm_random, ep_time_step, config_sim
|
||||
|
||||
seeds = {
|
||||
# 'z': np.random.RandomState(1),
|
||||
# 'a': np.random.RandomState(2)
|
||||
}
|
||||
|
||||
sim_config = config_sim({
|
||||
'T': range(10), #number of discrete iterations in each experiement
|
||||
'N': 1, #number of times the simulation will be run (Monte Carlo runs)
|
||||
#'M': g #parameter sweep dictionary
|
||||
})
|
||||
|
||||
|
||||
# define the time deltas for the discrete increments in the model
|
||||
# ts_format = '%Y-%m-%d %H:%M:%S'
|
||||
# t_delta = timedelta(days=0, minutes=1, seconds=0)
|
||||
# def time_model(_g, step, sL, s, _input):
|
||||
# y = 'time'
|
||||
# x = ep_time_step(s, dt_str=s['time'], fromat_str=ts_format, _timedelta=t_delta)
|
||||
# return (y, x)
|
||||
|
||||
# Behaviors
|
||||
def robot_arm(_g, step, sL, s):
|
||||
add_to_A = 0
|
||||
if (s['box_A'] > s['box_B']):
|
||||
add_to_A = -1
|
||||
elif (s['box_A'] < s['box_B']):
|
||||
add_to_A = 1
|
||||
return({'add_to_A': add_to_A, 'add_to_B': -add_to_A})
|
||||
|
||||
|
||||
|
||||
# Mechanisms
|
||||
def increment_A(_g, step, sL, s, _input):
|
||||
y = 'box_A'
|
||||
x = s['box_A'] + _input['add_to_A']
|
||||
return (y, x)
|
||||
|
||||
def increment_B(_g, step, sL, s, _input):
|
||||
y = 'box_B'
|
||||
x = s['box_B'] + _input['add_to_B']
|
||||
return (y, x)
|
||||
|
||||
# Initial States
|
||||
genesis_states = {
|
||||
'box_A': 10, # as per the description of the example, box_A starts out with 10 marbles in it
|
||||
'box_B': 0 # as per the description of the example, box_B starts out empty
|
||||
}
|
||||
|
||||
exogenous_states = {
|
||||
#'time': time_model
|
||||
}
|
||||
|
||||
env_processes = {
|
||||
}
|
||||
|
||||
#build mechanism dictionary to "wire up the circuit"
|
||||
mechanisms = [
|
||||
{
|
||||
'policies': { # The following policy functions will be evaluated and their returns will be passed to the state update functions
|
||||
'robot_arm_1': robot_arm,
|
||||
'robot_arm_2': robot_arm
|
||||
},
|
||||
|
||||
'states': { # The following state variables will be updated simultaneously
|
||||
'box_A': increment_A,
|
||||
'box_B': increment_B
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
|
||||
|
||||
append_configs(
|
||||
sim_configs=sim_config,
|
||||
initial_state=genesis_states,
|
||||
seeds=seeds,
|
||||
raw_exogenous_states=exogenous_states,
|
||||
env_processes=env_processes,
|
||||
partial_state_update_blocks=mechanisms
|
||||
)
|
||||
|
|
@ -0,0 +1,71 @@
|
|||
# import libraries
|
||||
from decimal import Decimal
|
||||
import numpy as np
|
||||
from datetime import timedelta
|
||||
from cadCAD.configuration import append_configs
|
||||
from cadCAD.configuration.utils import bound_norm_random, ep_time_step, config_sim
|
||||
|
||||
seeds = {
|
||||
}
|
||||
|
||||
sim_config = config_sim({
|
||||
'T': range(10),
|
||||
'N': 1
|
||||
})
|
||||
|
||||
# Behaviors
|
||||
def robot_arm(_g, step, sL, s):
|
||||
add_to_A = 0
|
||||
if (s['box_A'] > s['box_B']):
|
||||
add_to_A = -1
|
||||
elif (s['box_A'] < s['box_B']):
|
||||
add_to_A = 1
|
||||
return({'add_to_A': add_to_A, 'add_to_B': -add_to_A})
|
||||
|
||||
|
||||
# Mechanisms
|
||||
def increment_A(_g, step, sL, s, _input):
|
||||
y = 'box_A'
|
||||
x = s['box_A'] + _input['add_to_A']
|
||||
return (y, x)
|
||||
|
||||
def increment_B(_g, step, sL, s, _input):
|
||||
y = 'box_B'
|
||||
x = s['box_B'] + _input['add_to_B']
|
||||
return (y, x)
|
||||
|
||||
# Initial States
|
||||
genesis_states = {
|
||||
'box_A': 10,
|
||||
'box_B': 0
|
||||
}
|
||||
|
||||
exogenous_states = {
|
||||
}
|
||||
|
||||
|
||||
env_processes = {
|
||||
}
|
||||
|
||||
|
||||
mechanisms = [
|
||||
{
|
||||
'policies': {
|
||||
'robot_arm': robot_arm
|
||||
},
|
||||
'states': {
|
||||
'box_A': increment_A,
|
||||
'box_B': increment_B
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
|
||||
append_configs(
|
||||
sim_configs=sim_config,
|
||||
initial_state=genesis_states,
|
||||
seeds=seeds,
|
||||
raw_exogenous_states=exogenous_states,
|
||||
env_processes=env_processes,
|
||||
partial_state_update_blocks=mechanisms
|
||||
)
|
||||
|
After Width: | Height: | Size: 50 KiB |
|
After Width: | Height: | Size: 53 KiB |
|
After Width: | Height: | Size: 39 KiB |
|
|
@ -0,0 +1 @@
|
|||
(https://youtu.be/wF539-K0qXs)
|
||||
|
|
@ -0,0 +1,108 @@
|
|||
# import libraries
|
||||
from decimal import Decimal
|
||||
import numpy as np
|
||||
from datetime import timedelta
|
||||
from cadCAD.configuration import append_configs
|
||||
from cadCAD.configuration.utils import bound_norm_random, ep_time_step, config_sim
|
||||
|
||||
seeds = {
|
||||
# 'z': np.random.RandomState(1),
|
||||
# 'a': np.random.RandomState(2)
|
||||
}
|
||||
|
||||
sim_config = config_sim({
|
||||
'T': range(10), #number of discrete iterations in each experiement
|
||||
'N': 1, #number of times the simulation will be run (Monte Carlo runs)
|
||||
#'M': g #parameter sweep dictionary
|
||||
})
|
||||
|
||||
|
||||
# define the time deltas for the discrete increments in the model
|
||||
# ts_format = '%Y-%m-%d %H:%M:%S'
|
||||
# t_delta = timedelta(days=0, minutes=1, seconds=0)
|
||||
# def time_model(_g, step, sL, s, _input):
|
||||
# y = 'time'
|
||||
# x = ep_time_step(s, dt_str=s['time'], fromat_str=ts_format, _timedelta=t_delta)
|
||||
# return (y, x)
|
||||
|
||||
# Behaviors
|
||||
def robot_arm(_g, step, sL, s):
|
||||
add_to_A = 0
|
||||
if (s['box_A'] > s['box_B']):
|
||||
add_to_A = -1
|
||||
elif (s['box_A'] < s['box_B']):
|
||||
add_to_A = 1
|
||||
return({'add_to_A': add_to_A, 'add_to_B': -add_to_A})
|
||||
|
||||
robots_periods = [2,3] # Robot 1 acts once every 2 timesteps; Robot 2 acts once every 3 timesteps
|
||||
|
||||
def get_current_timestep(cur_substep, s):
|
||||
if cur_substep == 1:
|
||||
return s['timestep']+1
|
||||
return s['timestep']
|
||||
|
||||
def robot_arm_1(_g, step, sL, s):
|
||||
_robotId = 1
|
||||
if get_current_timestep(step, s)%robots_periods[_robotId-1]==0: # on timesteps that are multiple of 2, Robot 1 acts
|
||||
return robot_arm(_g, step, sL, s)
|
||||
else:
|
||||
return({'add_to_A': 0, 'add_to_B': 0}) # for all other timesteps, Robot 1 doesn't interfere with the system
|
||||
|
||||
def robot_arm_2(_g, step, sL, s):
|
||||
_robotId = 2
|
||||
if get_current_timestep(step, s)%robots_periods[_robotId-1]==0: # on timesteps that are multiple of 3, Robot 2 acts
|
||||
return robot_arm(_g, step, sL, s)
|
||||
else:
|
||||
return({'add_to_A': 0, 'add_to_B': 0}) # for all other timesteps, Robot 2 doesn't interfere with the system
|
||||
|
||||
|
||||
|
||||
# Mechanisms
|
||||
def increment_A(_g, step, sL, s, _input):
|
||||
y = 'box_A'
|
||||
x = s['box_A'] + _input['add_to_A']
|
||||
return (y, x)
|
||||
|
||||
def increment_B(_g, step, sL, s, _input):
|
||||
y = 'box_B'
|
||||
x = s['box_B'] + _input['add_to_B']
|
||||
return (y, x)
|
||||
|
||||
# Initial States
|
||||
genesis_states = {
|
||||
'box_A': 10, # as per the description of the example, box_A starts out with 10 marbles in it
|
||||
'box_B': 0 # as per the description of the example, box_B starts out empty
|
||||
}
|
||||
|
||||
exogenous_states = {
|
||||
#'time': time_model
|
||||
}
|
||||
|
||||
env_processes = {
|
||||
}
|
||||
|
||||
#build mechanism dictionary to "wire up the circuit"
|
||||
mechanisms = [
|
||||
{
|
||||
'policies': { # The following policy functions will be evaluated and their returns will be passed to the state update functions
|
||||
'robot_arm_1': robot_arm_1,
|
||||
'robot_arm_2': robot_arm_2
|
||||
},
|
||||
|
||||
'states': { # The following state variables will be updated simultaneously
|
||||
'box_A': increment_A,
|
||||
'box_B': increment_B
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
|
||||
|
||||
append_configs(
|
||||
sim_configs=sim_config,
|
||||
initial_state=genesis_states,
|
||||
seeds=seeds,
|
||||
raw_exogenous_states=exogenous_states,
|
||||
env_processes=env_processes,
|
||||
partial_state_update_blocks=mechanisms
|
||||
)
|
||||
|
After Width: | Height: | Size: 53 KiB |
|
After Width: | Height: | Size: 39 KiB |
|
|
@ -0,0 +1 @@
|
|||
(https://youtu.be/MLNTqqX47Ew)
|
||||
|
|
@ -0,0 +1,103 @@
|
|||
# import libraries
|
||||
from decimal import Decimal
|
||||
import numpy as np
|
||||
from datetime import timedelta
|
||||
from cadCAD.configuration import append_configs
|
||||
from cadCAD.configuration.utils import bound_norm_random, ep_time_step, config_sim
|
||||
|
||||
seeds = {
|
||||
# 'z': np.random.RandomState(1),
|
||||
# 'a': np.random.RandomState(2)
|
||||
}
|
||||
|
||||
sim_config = config_sim({
|
||||
'T': range(10), #number of discrete iterations in each experiement
|
||||
'N': 1, #number of times the simulation will be run (Monte Carlo runs)
|
||||
#'M': g #parameter sweep dictionary
|
||||
})
|
||||
|
||||
|
||||
# define the time deltas for the discrete increments in the model
|
||||
# ts_format = '%Y-%m-%d %H:%M:%S'
|
||||
# t_delta = timedelta(days=0, minutes=1, seconds=0)
|
||||
# def time_model(_g, step, sL, s, _input):
|
||||
# y = 'time'
|
||||
# x = ep_time_step(s, dt_str=s['time'], fromat_str=ts_format, _timedelta=t_delta)
|
||||
# return (y, x)
|
||||
|
||||
# Behaviors
|
||||
def robot_arm(_g, step, sL, s):
|
||||
add_to_A = 0
|
||||
if (s['box_A'] > s['box_B']):
|
||||
add_to_A = -1
|
||||
elif (s['box_A'] < s['box_B']):
|
||||
add_to_A = 1
|
||||
return({'add_to_A': add_to_A, 'add_to_B': -add_to_A})
|
||||
|
||||
robots_probabilities = [0.5,1/3] # Robot 1 acts with a 50% probability; Robot 2, 33.33%
|
||||
|
||||
def robot_arm_1(_g, step, sL, s):
|
||||
_robotId = 1
|
||||
if np.random.rand()<robots_probabilities[_robotId-1]: # draw a random number between 0 and 1; if it's smaller than the robot's parameter, it acts
|
||||
return robot_arm(_g, step, sL, s)
|
||||
else:
|
||||
return({'add_to_A': 0, 'add_to_B': 0}) # otherwise, the robot doesn't interfere with the system
|
||||
|
||||
def robot_arm_2(_g, step, sL, s):
|
||||
_robotId = 2
|
||||
if np.random.rand()<robots_probabilities[_robotId-1]: # draw a random number between 0 and 1; if it's smaller than the robot's parameter, it acts
|
||||
return robot_arm(_g, step, sL, s)
|
||||
else:
|
||||
return({'add_to_A': 0, 'add_to_B': 0}) # otherwise, the robot doesn't interfere with the system
|
||||
|
||||
|
||||
|
||||
# Mechanisms
|
||||
def increment_A(_g, step, sL, s, _input):
|
||||
y = 'box_A'
|
||||
x = s['box_A'] + _input['add_to_A']
|
||||
return (y, x)
|
||||
|
||||
def increment_B(_g, step, sL, s, _input):
|
||||
y = 'box_B'
|
||||
x = s['box_B'] + _input['add_to_B']
|
||||
return (y, x)
|
||||
|
||||
# Initial States
|
||||
genesis_states = {
|
||||
'box_A': 10, # as per the description of the example, box_A starts out with 10 marbles in it
|
||||
'box_B': 0 # as per the description of the example, box_B starts out empty
|
||||
}
|
||||
|
||||
exogenous_states = {
|
||||
#'time': time_model
|
||||
}
|
||||
|
||||
env_processes = {
|
||||
}
|
||||
|
||||
#build mechanism dictionary to "wire up the circuit"
|
||||
mechanisms = [
|
||||
{
|
||||
'policies': { # The following policy functions will be evaluated and their returns will be passed to the state update functions
|
||||
'robot_arm_1': robot_arm_1,
|
||||
'robot_arm_2': robot_arm_2
|
||||
},
|
||||
|
||||
'states': { # The following state variables will be updated simultaneously
|
||||
'box_A': increment_A,
|
||||
'box_B': increment_B
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
|
||||
|
||||
append_configs(
|
||||
sim_configs=sim_config,
|
||||
initial_state=genesis_states,
|
||||
seeds=seeds,
|
||||
raw_exogenous_states=exogenous_states,
|
||||
env_processes=env_processes,
|
||||
partial_state_update_blocks=mechanisms
|
||||
)
|
||||
|
|
@ -0,0 +1,103 @@
|
|||
# import libraries
|
||||
from decimal import Decimal
|
||||
import numpy as np
|
||||
from datetime import timedelta
|
||||
from cadCAD.configuration import append_configs
|
||||
from cadCAD.configuration.utils import bound_norm_random, ep_time_step, config_sim
|
||||
|
||||
seeds = {
|
||||
# 'z': np.random.RandomState(1),
|
||||
# 'a': np.random.RandomState(2)
|
||||
}
|
||||
|
||||
sim_config = config_sim({
|
||||
'T': range(10), #number of discrete iterations in each experiement
|
||||
'N': 50, #number of times the simulation will be run (Monte Carlo runs)
|
||||
#'M': g #parameter sweep dictionary
|
||||
})
|
||||
|
||||
|
||||
# define the time deltas for the discrete increments in the model
|
||||
# ts_format = '%Y-%m-%d %H:%M:%S'
|
||||
# t_delta = timedelta(days=0, minutes=1, seconds=0)
|
||||
# def time_model(_g, step, sL, s, _input):
|
||||
# y = 'time'
|
||||
# x = ep_time_step(s, dt_str=s['time'], fromat_str=ts_format, _timedelta=t_delta)
|
||||
# return (y, x)
|
||||
|
||||
# Behaviors
|
||||
def robot_arm(_g, step, sL, s):
|
||||
add_to_A = 0
|
||||
if (s['box_A'] > s['box_B']):
|
||||
add_to_A = -1
|
||||
elif (s['box_A'] < s['box_B']):
|
||||
add_to_A = 1
|
||||
return({'add_to_A': add_to_A, 'add_to_B': -add_to_A})
|
||||
|
||||
robots_probabilities = [0.5,1/3] # Robot 1 acts with a 50% probability; Robot 2, 33.33%
|
||||
|
||||
def robot_arm_1(_g, step, sL, s):
|
||||
_robotId = 1
|
||||
if np.random.rand()<robots_probabilities[_robotId-1]: # draw a random number between 0 and 1; if it's smaller than the robot's parameter, it acts
|
||||
return robot_arm(_g, step, sL, s)
|
||||
else:
|
||||
return({'add_to_A': 0, 'add_to_B': 0}) # otherwise, the robot doesn't interfere with the system
|
||||
|
||||
def robot_arm_2(_g, step, sL, s):
|
||||
_robotId = 2
|
||||
if np.random.rand()<robots_probabilities[_robotId-1]: # draw a random number between 0 and 1; if it's smaller than the robot's parameter, it acts
|
||||
return robot_arm(_g, step, sL, s)
|
||||
else:
|
||||
return({'add_to_A': 0, 'add_to_B': 0}) # otherwise, the robot doesn't interfere with the system
|
||||
|
||||
|
||||
|
||||
# Mechanisms
|
||||
def increment_A(_g, step, sL, s, _input):
|
||||
y = 'box_A'
|
||||
x = s['box_A'] + _input['add_to_A']
|
||||
return (y, x)
|
||||
|
||||
def increment_B(_g, step, sL, s, _input):
|
||||
y = 'box_B'
|
||||
x = s['box_B'] + _input['add_to_B']
|
||||
return (y, x)
|
||||
|
||||
# Initial States
|
||||
genesis_states = {
|
||||
'box_A': 10, # as per the description of the example, box_A starts out with 10 marbles in it
|
||||
'box_B': 0 # as per the description of the example, box_B starts out empty
|
||||
}
|
||||
|
||||
exogenous_states = {
|
||||
#'time': time_model
|
||||
}
|
||||
|
||||
env_processes = {
|
||||
}
|
||||
|
||||
#build mechanism dictionary to "wire up the circuit"
|
||||
mechanisms = [
|
||||
{
|
||||
'policies': { # The following policy functions will be evaluated and their returns will be passed to the state update functions
|
||||
'robot_arm_1': robot_arm_1,
|
||||
'robot_arm_2': robot_arm_2
|
||||
},
|
||||
|
||||
'states': { # The following state variables will be updated simultaneously
|
||||
'box_A': increment_A,
|
||||
'box_B': increment_B
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
|
||||
|
||||
append_configs(
|
||||
sim_configs=sim_config,
|
||||
initial_state=genesis_states,
|
||||
seeds=seeds,
|
||||
raw_exogenous_states=exogenous_states,
|
||||
env_processes=env_processes,
|
||||
partial_state_update_blocks=mechanisms
|
||||
)
|
||||
|
After Width: | Height: | Size: 53 KiB |
|
After Width: | Height: | Size: 39 KiB |
|
|
@ -0,0 +1 @@
|
|||
https://www.youtube.com/watch?v=I0mSQppibLs&feature=youtu.be
|
||||
|
After Width: | Height: | Size: 22 KiB |
|
After Width: | Height: | Size: 21 KiB |