added docs from tutorial
This commit is contained in:
parent
747ec36e50
commit
7d0a14efbf
|
|
@ -19,6 +19,13 @@ cadCAD.egg-info
|
||||||
|
|
||||||
build
|
build
|
||||||
cadCAD.egg-info
|
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
|
monkeytype.sqlite3
|
||||||
28
README.md
28
README.md
|
|
@ -1,6 +1,17 @@
|
||||||
# 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:**
|
**Description:**
|
||||||
|
|
||||||
|
|
@ -35,9 +46,9 @@ and see how it evolves. We can then use these results to inform business decisio
|
||||||
|
|
||||||
#### 0. Installation:
|
#### 0. Installation:
|
||||||
|
|
||||||
**Option A:** Package Repository Access
|
**Option A:** Proprietary Build Access
|
||||||
|
|
||||||
***IMPORTANT NOTE:*** Tokens are issued to and meant to be used by trial users and BlockScience employees **ONLY**.
|
***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.
|
Replace \<TOKEN\> with an issued token in the script below.
|
||||||
```bash
|
```bash
|
||||||
pip3 install pandas pathos fn funcy tabulate
|
pip3 install pandas pathos fn funcy tabulate
|
||||||
|
|
@ -147,3 +158,10 @@ for raw_result, tensor_field in run.execute():
|
||||||
print()
|
print()
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Tests:
|
||||||
|
```python
|
||||||
|
python -m unittest testing/tests/param_sweep.py
|
||||||
|
python -m unittest testing/tests/policy_aggregation.py
|
||||||
|
python -m unittest testing/tests/historical_state_access.py
|
||||||
|
python -m unittest testing/tests/external_dataset.py
|
||||||
|
```
|
||||||
|
|
|
||||||
151
Simulation.md
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))
|
|
||||||
```
|
|
||||||
|
|
@ -56,5 +56,22 @@ append_configs(
|
||||||
)
|
)
|
||||||
```
|
```
|
||||||
|
|
||||||
#### [Example Configuration](link)
|
#### Example
|
||||||
#### [Example Results](link)
|
##### * [System Model Configuration](https://github.com/BlockScience/cadCAD-Tutorials/blob/master/Documentation/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 |
|
||||||
|
+----+---------------------------------------------+-------+------+-----------+------------+
|
||||||
|
```
|
||||||
|
|
|
||||||
|
|
@ -3,12 +3,16 @@ Simulation Configuration
|
||||||
|
|
||||||
## Introduction
|
## 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).
|
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)
|
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
|
`append_configs`, stores a **Simulation Configuration** to be [Executed](/JS4Q9oayQASihxHBJzz4Ug) by cadCAD
|
||||||
[Executed](https://github.com/BlockScience/cadCAD-Tutorials/blob/master/Documentation/Simulation_Execution.md) by cadCAD
|
|
||||||
|
|
||||||
```python
|
```python
|
||||||
from cadCAD.configuration import append_configs
|
from cadCAD.configuration import append_configs
|
||||||
|
|
@ -21,25 +25,15 @@ append_configs(
|
||||||
)
|
)
|
||||||
```
|
```
|
||||||
Parameters:
|
Parameters:
|
||||||
* **initial_state** : _dict_
|
* **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)
|
||||||
[State Variables](#State-Variables) and their initial values
|
* **policy_ops** : List[functions] - See [Policy Aggregation](/63k2ncjITuqOPCUHzK7Viw)
|
||||||
|
* **sim_configs** - See [System Model Parameter Sweep](/4oJ_GT6zRWW8AO3yMhFKrg)
|
||||||
* **partial_state_update_blocks** : List[dict[dict]]
|
|
||||||
|
|
||||||
List of [Partial State Update Blocks](#Partial-State-Update-Blocks)
|
|
||||||
|
|
||||||
* **policy_ops** : List[functions]
|
|
||||||
|
|
||||||
See [Policy Aggregation](https://github.com/BlockScience/cadCAD-Tutorials/blob/master/Documentation/Policy_Aggregation.md)
|
|
||||||
|
|
||||||
* **sim_configs** :
|
|
||||||
|
|
||||||
See
|
|
||||||
|
|
||||||
## Simulation Properties
|
## Simulation Properties
|
||||||
|
|
||||||
Simulation properties are passed to `append_configs` in the `sim_configs` parameter. To construct this paramenter, we use the `config_sim` function in `cadCAD.configuration.utils`
|
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
|
```python
|
||||||
from cadCAD.configuration.utils import config_sim
|
from cadCAD.configuration.utils import config_sim
|
||||||
|
|
@ -59,29 +53,46 @@ append_configs(
|
||||||
### T - Simulation Length
|
### T - Simulation Length
|
||||||
Computer simulations run in discrete time:
|
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))
|
>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.
|
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.
|
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
|
### 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](https://github.com/BlockScience/cadCAD-Tutorials/blob/master/01%20Tutorials/robot-marbles-part-4/robot-marbles-part-4.ipynb).
|
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](https://github.com/BlockScience/cadCAD-Tutorials/blob/master/01%20Tutorials/robot-marbles-part-4/robot-marbles-part-4.ipynb).
|
||||||
|
|
||||||
### M - Parameters of the System
|
### 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.
|
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
|
## 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.
|
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
|
### 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))
|
>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.
|
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.
|
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
|
```python
|
||||||
from cadCAD.configuration import append_configs
|
from cadCAD.configuration import append_configs
|
||||||
|
|
@ -99,41 +110,48 @@ append_configs(
|
||||||
)
|
)
|
||||||
```
|
```
|
||||||
### State Update Functions
|
### 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:
|
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
|
```python
|
||||||
def state_update_function_A(_params, substep, sH, s, _input):
|
def state_update_function_A(_params, substep, sH, s, _input):
|
||||||
...
|
...
|
||||||
return 'state_variable_name', new_value
|
return 'state_variable_name', new_value
|
||||||
```
|
```
|
||||||
Parameters:
|
Parameters:
|
||||||
* **_params** : _dict_
|
* **_params** : _dict_ - [System parameters](/4oJ_GT6zRWW8AO3yMhFKrg)
|
||||||
[System parameters](/4oJ_GT6zRWW8AO3yMhFKrg)
|
* **substep** : _int_ - Current [substep](#Substep)
|
||||||
* **substep** : _int_
|
* **sH** : _list[list[dict_]] - Historical values of all state variables for the simulation. See
|
||||||
Current [substep](#Substep)
|
[Historical State Access](/smiyQTnATtC9xPwvF8KbBQ) for details
|
||||||
* **sH** : _list[list[dict_]]
|
* **s** : _dict_ - Current state of the system, where the `dict_keys` are the names of the state variables and the
|
||||||
Historical values of all state variables for the simulation. See [Historical State Access](/smiyQTnATtC9xPwvF8KbBQ) for details
|
`dict_values` are their current values.
|
||||||
* **s** : _dict_
|
* **_input** : _dict_ - Aggregation of the signals of all policy functions in the current
|
||||||
Current state of the system, where the `dict_keys` are the names of the state variables and the `dict_values` are their current values.
|
[Partial State Update Block](#Partial-State-Update-Block)
|
||||||
* **_input** : _dict_
|
|
||||||
Aggregation of the signals of all policy functions in the current [Partial State Update Block](#Partial-State-Update-Block)
|
|
||||||
|
|
||||||
Return:
|
Return:
|
||||||
* _tuple_ containing a string with the name of the state variable being updated and its new value.
|
* _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.
|
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
|
### 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](https://github.com/BlockScience/cadCAD-Tutorials/blob/master/01%20Tutorials/robot-marbles-part-2/robot-marbles-part-2.ipynb) for details on why and when to use 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](https://github.com/BlockScience/cadCAD-Tutorials/blob/master/01%20Tutorials/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
|
<!-- We would then expand the tutorials with these kind of concepts
|
||||||
#### Policies
|
#### 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.
|
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.
|
While executed the same, the modeller can approach policies dependent on the availability of a mechanism to a population.
|
||||||
|
|
||||||
- ***Control Policy***
|
- ***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.
|
When the controlling or deploying entity has the ability to act in order to affect some aspect of the system, this is a
|
||||||
- ***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.
|
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 action taken, as well as the potential to act, through a mechanism is a behavior. -->
|
||||||
|
|
||||||
The general structure of a policy function is:
|
The general structure of a policy function is:
|
||||||
|
|
@ -143,29 +161,38 @@ def policy_function_1(_params, substep, sH, s):
|
||||||
return {'signal_1': value_1, ..., 'signal_N': value_N}
|
return {'signal_1': value_1, ..., 'signal_N': value_N}
|
||||||
```
|
```
|
||||||
Parameters:
|
Parameters:
|
||||||
* **_params** : _dict_
|
* **_params** : _dict_ - [System parameters](/4oJ_GT6zRWW8AO3yMhFKrg)
|
||||||
[System parameters](/4oJ_GT6zRWW8AO3yMhFKrg)
|
* **substep** : _int_ - Current [substep](#Substep)
|
||||||
* **substep** : _int_
|
* **sH** : _list[list[dict_]] - Historical values of all state variables for the simulation. See
|
||||||
Current [substep](#Substep)
|
[Historical State Access](/smiyQTnATtC9xPwvF8KbBQ) for details
|
||||||
* **sH** : _list[list[dict_]]
|
* **s** : _dict_ - Current state of the system, where the `dict_keys` are the names of the state variables and the
|
||||||
Historical values of all state variables for the simulation. See [Historical State Access](/smiyQTnATtC9xPwvF8KbBQ) for details
|
`dict_values` are their current values.
|
||||||
* **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:
|
Return:
|
||||||
* _dict_ of signals to be passed to the state update functions in the same [Partial State Update Block](#Partial-State-Update-Blocks)
|
* _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.
|
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).
|
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
|
### 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 cannnot impact the State Update Functions and Policy Functions in that PSUB - only those in the next PSUB.
|
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.
|
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
|
```python
|
||||||
PSUBs = [
|
PSUBs = [
|
||||||
|
|
@ -191,19 +218,23 @@ append_configs(
|
||||||
partial_state_update_blocks = PSUBs,
|
partial_state_update_blocks = PSUBs,
|
||||||
...
|
...
|
||||||
)
|
)
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Substep
|
#### 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`.
|
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
|
## Result Dataset
|
||||||
|
|
||||||
cadCAD returns a dataset containing the evolution of the state variables defined by the user over time, with three `int` indexes:
|
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)
|
* `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))
|
* `timestep` - discrete unit of time (the total number of timesteps is defined by the user in the
|
||||||
* `substep` - subdivision of timestep (the number of [substeps](#Substeps) is the same as the number of Partial State Update Blocks)
|
[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)`
|
Therefore, the total number of records in the resulting dataset is `N` x `T` x `len(partial_state_update_blocks)`
|
||||||
|
|
||||||
#### [System Simulation Execution](link)
|
#### [System Simulation Execution](https://github.com/BlockScience/cadCAD-Tutorials/blob/master/documentation/Simulation_Execution.md)
|
||||||
|
|
|
||||||
|
|
@ -51,7 +51,7 @@ simulation_result = pd.DataFrame(raw_system_events)
|
||||||
```
|
```
|
||||||
|
|
||||||
##### Example Result: System Events DataFrame
|
##### Example Result: System Events DataFrame
|
||||||
```python
|
```
|
||||||
+----+-------+------------+-----------+------+-----------+
|
+----+-------+------------+-----------+------+-----------+
|
||||||
| | run | timestep | substep | s1 | s2 |
|
| | run | timestep | substep | s1 | s2 |
|
||||||
|----+-------+------------+-----------+------+-----------|
|
|----+-------+------------+-----------+------+-----------|
|
||||||
|
|
@ -68,6 +68,6 @@ sim_config = config_sim(
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
```
|
```
|
||||||
|
#### Example
|
||||||
#### [Example](link)
|
##### * [System Model Configuration](https://github.com/BlockScience/cadCAD-Tutorials/blob/master/Documentation/examples/param_sweep.py)
|
||||||
|
##### * Simulation Results:
|
||||||
|
|
|
||||||
|
|
@ -80,7 +80,7 @@ append_configs(
|
||||||
sim_configs=sim_config,
|
sim_configs=sim_config,
|
||||||
initial_state=genesis_states,
|
initial_state=genesis_states,
|
||||||
partial_state_update_blocks=psubs,
|
partial_state_update_blocks=psubs,
|
||||||
policy_ops=[lambda a, b: a + b] # Default: lambda a, b: a + b , lambda y: y * 2
|
policy_ops=[lambda a, b: a + b, lambda y: y * 2] # Default: lambda a, b: a + b
|
||||||
)
|
)
|
||||||
|
|
||||||
exec_mode = ExecutionMode()
|
exec_mode = ExecutionMode()
|
||||||
|
|
|
||||||
|
|
@ -35,9 +35,6 @@ def s1m1(_g, step, sH, s, _input):
|
||||||
y = 's1'
|
y = 's1'
|
||||||
x = s['s1'] + 1
|
x = s['s1'] + 1
|
||||||
return (y, x)
|
return (y, x)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def s2m1(_g, step, sH, s, _input):
|
def s2m1(_g, step, sH, s, _input):
|
||||||
y = 's2'
|
y = 's2'
|
||||||
x = _input['param2']
|
x = _input['param2']
|
||||||
|
|
|
||||||
2
setup.py
2
setup.py
|
|
@ -11,7 +11,7 @@ long_description = "cadCAD is a differential games based simulation software pac
|
||||||
monte carlo analysis and other common numerical methods is provided."
|
monte carlo analysis and other common numerical methods is provided."
|
||||||
|
|
||||||
setup(name='cadCAD',
|
setup(name='cadCAD',
|
||||||
version='0.2.4',
|
version='0.3.0',
|
||||||
description="cadCAD: a differential games based simulation software package for research, validation, and \
|
description="cadCAD: a differential games based simulation software package for research, validation, and \
|
||||||
Computer Aided Design of economic systems",
|
Computer Aided Design of economic systems",
|
||||||
long_description=long_description,
|
long_description=long_description,
|
||||||
|
|
|
||||||
|
|
@ -1,20 +0,0 @@
|
||||||
import unittest
|
|
||||||
|
|
||||||
class TestStringMethods(unittest.TestCase):
|
|
||||||
|
|
||||||
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,71 +0,0 @@
|
||||||
from functools import reduce
|
|
||||||
|
|
||||||
import pandas as pd
|
|
||||||
import unittest
|
|
||||||
from parameterized import parameterized
|
|
||||||
from tabulate import tabulate
|
|
||||||
|
|
||||||
from testing.system_models.policy_aggregation import run
|
|
||||||
from testing.generic_test import make_generic_test
|
|
||||||
from testing.utils import generate_assertions_df
|
|
||||||
|
|
||||||
raw_result, tensor_field = run.execute()
|
|
||||||
result = pd.DataFrame(raw_result)
|
|
||||||
|
|
||||||
expected_results = {
|
|
||||||
(1, 0, 0): {'policies': {}, 's1': 0},
|
|
||||||
(1, 1, 1): {'policies': {'policy1': 2, 'policy2': 4}, 's1': 500},
|
|
||||||
(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}
|
|
||||||
}
|
|
||||||
|
|
||||||
params = [["policy_aggregation", result, expected_results, ['policies', 's1']]]
|
|
||||||
|
|
||||||
|
|
||||||
class TestSequence(unittest.TestCase):
|
|
||||||
@parameterized.expand(params)
|
|
||||||
def test_validate_results(self, name, result_df, expected_reults, target_cols):
|
|
||||||
# alt for (*) Exec Debug mode
|
|
||||||
tested_df = generate_assertions_df(result_df, expected_reults, target_cols)
|
|
||||||
|
|
||||||
erroneous = tested_df[(tested_df['test'] == False)]
|
|
||||||
for index, row in erroneous.iterrows():
|
|
||||||
expected = expected_reults[(row['run'], row['timestep'], row['substep'])]
|
|
||||||
unexpected = {k: expected[k] for k in expected if k in row and expected[k] != row[k]}
|
|
||||||
for key in unexpected.keys():
|
|
||||||
erroneous[f"invalid_{key}"] = unexpected[key]
|
|
||||||
# etc.
|
|
||||||
|
|
||||||
# def etc.
|
|
||||||
|
|
||||||
print()
|
|
||||||
print(tabulate(erroneous, headers='keys', tablefmt='psql'))
|
|
||||||
|
|
||||||
self.assertEqual(reduce(lambda a, b: a and b, tested_df['test']), True)
|
|
||||||
|
|
||||||
s = 'hello world'
|
|
||||||
# self.assertEqual(s.split(), 1)
|
|
||||||
# # check that s.split fails when the separator is not a string
|
|
||||||
# with self.assertRaises(AssertionError):
|
|
||||||
# tested_df[(tested_df['test'] == False)]
|
|
||||||
# erroneous = tested_df[(tested_df['test'] == False)]
|
|
||||||
# for index, row in erroneous.iterrows():
|
|
||||||
# expected = expected_reults[(row['run'], row['timestep'], row['substep'])]
|
|
||||||
# unexpected = {k: expected[k] for k in expected if k in row and expected[k] != row[k]}
|
|
||||||
# for key in unexpected.keys():
|
|
||||||
# erroneous[f"invalid_{key}"] = unexpected[key]
|
|
||||||
# # etc.
|
|
||||||
#
|
|
||||||
# # def etc.
|
|
||||||
#
|
|
||||||
# print()
|
|
||||||
# print(tabulate(erroneous, headers='keys', tablefmt='psql'))
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
unittest.main()
|
|
||||||
|
|
@ -1,21 +1,9 @@
|
||||||
import unittest
|
import unittest
|
||||||
from parameterized import parameterized
|
from parameterized import parameterized
|
||||||
from functools import reduce
|
from functools import reduce
|
||||||
from tabulate import tabulate
|
|
||||||
|
|
||||||
# ToDo: Exec Debug mode (*) for which state and policy updates are validated during runtime using `expected_results`
|
|
||||||
# EXAMPLE: ('state_test' T/F, 'policy_test' T/F)
|
|
||||||
# ToDo: (Sys Model Config) give `expected_results to` `Configuration` for Exec Debug mode (*)
|
|
||||||
# ToDo: (expected_results) Function to generate sys metrics keys using system model config
|
|
||||||
# ToDo: (expected_results) Function to generate target_vals given user input (apply fancy validation lib later on)
|
|
||||||
|
|
||||||
|
|
||||||
# ToDo: Use self.assertRaises(AssertionError)
|
|
||||||
|
|
||||||
|
|
||||||
def generate_assertions_df(df, expected_results, target_cols, evaluations):
|
def generate_assertions_df(df, expected_results, target_cols, evaluations):
|
||||||
# cols = ['run', 'timestep', 'substep'] + target_cols
|
|
||||||
# print(cols)
|
|
||||||
test_names = []
|
test_names = []
|
||||||
for eval_f in evaluations:
|
for eval_f in evaluations:
|
||||||
def wrapped_eval(a, b):
|
def wrapped_eval(a, b):
|
||||||
|
|
@ -54,10 +42,6 @@ def make_generic_test(params):
|
||||||
erroneous.at[index, key] = unexpected[key]
|
erroneous.at[index, key] = unexpected[key]
|
||||||
# etc.
|
# etc.
|
||||||
|
|
||||||
# print()
|
|
||||||
# print(f"TEST: {test_name}")
|
|
||||||
# print(tabulate(erroneous, headers='keys', tablefmt='psql'))
|
|
||||||
|
|
||||||
# ToDo: Condition that will change false to true
|
# ToDo: Condition that will change false to true
|
||||||
self.assertTrue(reduce(lambda a, b: a and b, tested_df[test_name]))
|
self.assertTrue(reduce(lambda a, b: a and b, tested_df[test_name]))
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ from cadCAD.configuration.utils import config_sim
|
||||||
import pandas as pd
|
import pandas as pd
|
||||||
from cadCAD.utils import SilentDF
|
from cadCAD.utils import SilentDF
|
||||||
|
|
||||||
df = SilentDF(pd.read_csv('/Users/jjodesty/Projects/DiffyQ-SimCAD/simulations/external_data/output.csv'))
|
df = SilentDF(pd.read_csv('/DiffyQ-SimCAD/simulations/external_data/output.csv'))
|
||||||
|
|
||||||
|
|
||||||
def query(s, df):
|
def query(s, df):
|
||||||
|
|
@ -21,8 +21,7 @@ def p2(_g, substep, sL, s):
|
||||||
del result_dict["ds1"], result_dict["ds2"]
|
del result_dict["ds1"], result_dict["ds2"]
|
||||||
return {k: list(v.values()).pop() for k, v in result_dict.items()}
|
return {k: list(v.values()).pop() for k, v in result_dict.items()}
|
||||||
|
|
||||||
# ToDo: SilentDF(df) wont work
|
# integrate_ext_dataset
|
||||||
#integrate_ext_dataset
|
|
||||||
def integrate_ext_dataset(_g, step, sL, s, _input):
|
def integrate_ext_dataset(_g, step, sL, s, _input):
|
||||||
result_dict = query(s, df).to_dict()
|
result_dict = query(s, df).to_dict()
|
||||||
return 'external_data', {k: list(v.values()).pop() for k, v in result_dict.items()}
|
return 'external_data', {k: list(v.values()).pop() for k, v in result_dict.items()}
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,5 @@
|
||||||
from cadCAD.configuration import append_configs
|
from cadCAD.configuration import append_configs
|
||||||
from cadCAD.configuration.utils import config_sim, access_block
|
from cadCAD.configuration.utils import config_sim, access_block
|
||||||
from cadCAD.engine import ExecutionMode, ExecutionContext, Executor
|
|
||||||
from cadCAD import configs
|
|
||||||
|
|
||||||
|
|
||||||
policies, variables = {}, {}
|
policies, variables = {}, {}
|
||||||
|
|
|
||||||
|
|
@ -61,11 +61,6 @@ for m in psu_steps:
|
||||||
psu_block[m]["variables"]['sweeped'] = var_timestep_trigger(y='sweeped', f=sweeped)
|
psu_block[m]["variables"]['sweeped'] = var_timestep_trigger(y='sweeped', f=sweeped)
|
||||||
|
|
||||||
|
|
||||||
# ToDo: The number of values entered in sweep should be the # of config objs created,
|
|
||||||
# not dependent on the # of times the sweep is applied
|
|
||||||
# sweep exo_state func and point to exo-state in every other funtion
|
|
||||||
# param sweep on genesis states
|
|
||||||
|
|
||||||
# Genesis States
|
# Genesis States
|
||||||
genesis_states = {
|
genesis_states = {
|
||||||
'alpha': 0,
|
'alpha': 0,
|
||||||
|
|
@ -75,11 +70,9 @@ genesis_states = {
|
||||||
}
|
}
|
||||||
|
|
||||||
# Environment Process
|
# Environment Process
|
||||||
# ToDo: Validate - make env proc trigger field agnostic
|
|
||||||
env_process['sweeped'] = env_timestep_trigger(trigger_field='timestep', trigger_vals=[5], funct_list=[lambda _g, x: _g['beta']])
|
env_process['sweeped'] = env_timestep_trigger(trigger_field='timestep', trigger_vals=[5], funct_list=[lambda _g, x: _g['beta']])
|
||||||
|
|
||||||
|
|
||||||
# config_sim Necessary
|
|
||||||
sim_config = config_sim(
|
sim_config = config_sim(
|
||||||
{
|
{
|
||||||
"N": 2,
|
"N": 2,
|
||||||
|
|
@ -87,11 +80,6 @@ sim_config = config_sim(
|
||||||
"M": g, # Optional
|
"M": g, # Optional
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
# print()
|
|
||||||
# pp.pprint(g)
|
|
||||||
# print()
|
|
||||||
# pp.pprint(sim_config)
|
|
||||||
|
|
||||||
|
|
||||||
# New Convention
|
# New Convention
|
||||||
partial_state_update_blocks = psub_list(psu_block, psu_steps)
|
partial_state_update_blocks = psub_list(psu_block, psu_steps)
|
||||||
|
|
|
||||||
|
|
@ -73,14 +73,11 @@ 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(
|
append_configs(
|
||||||
sim_configs=sim_config,
|
sim_configs=sim_config,
|
||||||
initial_state=genesis_states,
|
initial_state=genesis_states,
|
||||||
partial_state_update_blocks=partial_state_update_block,
|
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 ToDO: reduction function requires high lvl explanation
|
policy_ops=[lambda a, b: a + b, lambda y: y * 2] # Default: lambda a, b: a + b
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,185 +0,0 @@
|
||||||
import pandas as pd
|
|
||||||
from fn.func import curried
|
|
||||||
from datetime import timedelta
|
|
||||||
import pprint as pp
|
|
||||||
|
|
||||||
from cadCAD.utils import SilentDF #, val_switch
|
|
||||||
from cadCAD.configuration import append_configs
|
|
||||||
from cadCAD.configuration.utils import time_step, config_sim, var_trigger, var_substep_trigger, env_trigger, psub_list
|
|
||||||
from cadCAD.configuration.utils.userDefinedObject import udoPipe, UDO
|
|
||||||
|
|
||||||
from cadCAD.engine import ExecutionMode, ExecutionContext, Executor
|
|
||||||
from cadCAD import configs
|
|
||||||
|
|
||||||
|
|
||||||
DF = SilentDF(pd.read_csv('/Users/jjodesty/Projects/DiffyQ-SimCAD/simulations/external_data/output.csv'))
|
|
||||||
|
|
||||||
|
|
||||||
class udoExample(object):
|
|
||||||
def __init__(self, x, dataset=None):
|
|
||||||
self.x = x
|
|
||||||
self.mem_id = str(hex(id(self)))
|
|
||||||
self.ds = dataset # for setting ds initially or querying
|
|
||||||
self.perception = {}
|
|
||||||
|
|
||||||
def anon(self, f):
|
|
||||||
return f(self)
|
|
||||||
|
|
||||||
def updateX(self):
|
|
||||||
self.x += 1
|
|
||||||
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'])
|
|
||||||
].drop(columns=['run', 'substep']).to_dict()
|
|
||||||
return self
|
|
||||||
|
|
||||||
def read(self, ds_uri):
|
|
||||||
self.ds = SilentDF(pd.read_csv(ds_uri))
|
|
||||||
return self
|
|
||||||
|
|
||||||
def write(self, ds_uri):
|
|
||||||
pd.to_csv(ds_uri)
|
|
||||||
|
|
||||||
# ToDo: Generic update function
|
|
||||||
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
state_udo = UDO(udo=udoExample(0, DF), masked_members=['obj', 'perception'])
|
|
||||||
policy_udoA = UDO(udo=udoExample(0, DF), masked_members=['obj', 'perception'])
|
|
||||||
policy_udoB = UDO(udo=udoExample(0, DF), masked_members=['obj', 'perception'])
|
|
||||||
|
|
||||||
|
|
||||||
sim_config = config_sim({
|
|
||||||
"N": 2,
|
|
||||||
"T": range(4)
|
|
||||||
})
|
|
||||||
|
|
||||||
# ToDo: DataFrame Column order
|
|
||||||
state_dict = {
|
|
||||||
'increment': 0,
|
|
||||||
'state_udo': state_udo, 'state_udo_tracker': 0,
|
|
||||||
'state_udo_perception_tracker': {"ds1": None, "ds2": None, "ds3": None, "timestep": None},
|
|
||||||
'udo_policies': {'udo_A': policy_udoA, 'udo_B': policy_udoB},
|
|
||||||
'udo_policy_tracker': (0, 0),
|
|
||||||
'timestamp': '2019-01-01 00:00:00'
|
|
||||||
}
|
|
||||||
|
|
||||||
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)
|
|
||||||
psu_block = {k: {"policies": {}, "variables": {}} for k in psu_steps}
|
|
||||||
|
|
||||||
def udo_policyA(_g, step, sL, s):
|
|
||||||
s['udo_policies']['udo_A'].updateX()
|
|
||||||
return {'udo_A': udoPipe(s['udo_policies']['udo_A'])}
|
|
||||||
# policies['a'] = udo_policyA
|
|
||||||
for m in psu_steps:
|
|
||||||
psu_block[m]['policies']['a'] = udo_policyA
|
|
||||||
|
|
||||||
def udo_policyB(_g, step, sL, s):
|
|
||||||
s['udo_policies']['udo_B'].updateX()
|
|
||||||
return {'udo_B': udoPipe(s['udo_policies']['udo_B'])}
|
|
||||||
# policies['b'] = udo_policyB
|
|
||||||
for m in psu_steps:
|
|
||||||
psu_block[m]['policies']['b'] = udo_policyB
|
|
||||||
|
|
||||||
|
|
||||||
# policies = {"p1": udo_policyA, "p2": udo_policyB}
|
|
||||||
# policies = {"A": udo_policyA, "B": udo_policyB}
|
|
||||||
|
|
||||||
def add(y: str, added_val):
|
|
||||||
return lambda _g, step, sL, s, _input: (y, s[y] + added_val)
|
|
||||||
# state_updates['increment'] = add('increment', 1)
|
|
||||||
for m in psu_steps:
|
|
||||||
psu_block[m]["variables"]['increment'] = add('increment', 1)
|
|
||||||
|
|
||||||
|
|
||||||
@curried
|
|
||||||
def perceive(s, self):
|
|
||||||
self.perception = self.ds[
|
|
||||||
(self.ds['run'] == s['run']) & (self.ds['substep'] == s['substep']) & (self.ds['timestep'] == s['timestep'])
|
|
||||||
].drop(columns=['run', 'substep']).to_dict()
|
|
||||||
return 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)
|
|
||||||
x = udoPipe(s['state_udo'])
|
|
||||||
return y, x
|
|
||||||
for m in psu_steps:
|
|
||||||
psu_block[m]["variables"]['state_udo'] = state_udo_update
|
|
||||||
|
|
||||||
|
|
||||||
def track(destination, source):
|
|
||||||
return lambda _g, step, sL, s, _input: (destination, s[source].x)
|
|
||||||
state_udo_tracker = track('state_udo_tracker', 'state_udo')
|
|
||||||
for m in psu_steps:
|
|
||||||
psu_block[m]["variables"]['state_udo_tracker'] = state_udo_tracker
|
|
||||||
|
|
||||||
|
|
||||||
def track_state_udo_perception(destination, source):
|
|
||||||
def id(past_perception):
|
|
||||||
if len(past_perception) == 0:
|
|
||||||
return state_dict['state_udo_perception_tracker']
|
|
||||||
else:
|
|
||||||
return past_perception
|
|
||||||
return lambda _g, step, sL, s, _input: (destination, id(s[source].perception))
|
|
||||||
state_udo_perception_tracker = track_state_udo_perception('state_udo_perception_tracker', 'state_udo')
|
|
||||||
for m in psu_steps:
|
|
||||||
psu_block[m]["variables"]['state_udo_perception_tracker'] = state_udo_perception_tracker
|
|
||||||
|
|
||||||
|
|
||||||
def view_udo_policy(_g, step, sL, s, _input):
|
|
||||||
return 'udo_policies', _input
|
|
||||||
for m in psu_steps:
|
|
||||||
psu_block[m]["variables"]['udo_policies'] = view_udo_policy
|
|
||||||
|
|
||||||
|
|
||||||
def track_udo_policy(destination, source):
|
|
||||||
def val_switch(v):
|
|
||||||
if isinstance(v, pd.DataFrame) is True or isinstance(v, SilentDF) is True:
|
|
||||||
return SilentDF(v)
|
|
||||||
else:
|
|
||||||
return v.x
|
|
||||||
return lambda _g, step, sL, s, _input: (destination, tuple(val_switch(v) for _, v in s[source].items()))
|
|
||||||
udo_policy_tracker = track_udo_policy('udo_policy_tracker', 'udo_policies')
|
|
||||||
for m in psu_steps:
|
|
||||||
psu_block[m]["variables"]['udo_policy_tracker'] = udo_policy_tracker
|
|
||||||
|
|
||||||
|
|
||||||
def update_timestamp(_g, step, sL, 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))
|
|
||||||
for m in psu_steps:
|
|
||||||
psu_block[m]["variables"]['timestamp'] = var_timestep_trigger(y='timestamp', f=update_timestamp)
|
|
||||||
# psu_block[m]["variables"]['timestamp'] = var_trigger(
|
|
||||||
# y='timestamp', f=update_timestamp,
|
|
||||||
# pre_conditions={'substep': [0, system_substeps]}, cond_op=lambda a, b: a and b
|
|
||||||
# )
|
|
||||||
# psu_block[m]["variables"]['timestamp'] = update_timestamp
|
|
||||||
|
|
||||||
# ToDo: Bug without specifying parameters
|
|
||||||
# New Convention
|
|
||||||
partial_state_update_blocks = psub_list(psu_block, psu_steps)
|
|
||||||
append_configs(
|
|
||||||
sim_configs=sim_config,
|
|
||||||
initial_state=state_dict,
|
|
||||||
partial_state_update_blocks=partial_state_update_blocks
|
|
||||||
)
|
|
||||||
|
|
||||||
print()
|
|
||||||
print("State Updates:")
|
|
||||||
pp.pprint(partial_state_update_blocks)
|
|
||||||
print()
|
|
||||||
|
|
||||||
|
|
||||||
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)
|
|
||||||
|
|
@ -1,34 +1,22 @@
|
||||||
import unittest
|
import unittest
|
||||||
from pprint import pprint
|
|
||||||
|
|
||||||
import pandas as pd
|
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 cadCAD.engine import ExecutionMode, ExecutionContext, Executor
|
||||||
from simulations.regression_tests import external_dataset
|
from simulations.regression_tests import external_dataset
|
||||||
from cadCAD import configs
|
from cadCAD import configs
|
||||||
from testing.generic_test import make_generic_test
|
from testing.generic_test import make_generic_test
|
||||||
from testing.utils import gen_metric_dict
|
|
||||||
|
|
||||||
exec_mode = ExecutionMode()
|
exec_mode = ExecutionMode()
|
||||||
|
|
||||||
print("Simulation Execution: Single Configuration")
|
print("Simulation Execution: Single Configuration")
|
||||||
print()
|
print()
|
||||||
first_config = configs # only contains config1
|
first_config = configs
|
||||||
single_proc_ctx = ExecutionContext(context=exec_mode.single_proc)
|
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=first_config)
|
||||||
|
|
||||||
raw_result, tensor_field = run.execute()
|
raw_result, tensor_field = run.execute()
|
||||||
result = pd.DataFrame(raw_result)
|
result = pd.DataFrame(raw_result)
|
||||||
|
|
||||||
# print(tabulate(result, headers='keys', tablefmt='psql'))
|
|
||||||
|
|
||||||
# cols = ['run', 'substep', 'timestep', 'increment', 'external_data', 'policies']
|
|
||||||
# result = result[cols]
|
|
||||||
#
|
|
||||||
# metrics = gen_metric_dict(result, ['increment', 'external_data', 'policies'])
|
|
||||||
# #
|
|
||||||
# pprint(metrics)
|
|
||||||
|
|
||||||
def get_expected_results(run):
|
def get_expected_results(run):
|
||||||
return {
|
return {
|
||||||
|
|
@ -109,6 +97,8 @@ expected_results.update(expected_results_2)
|
||||||
|
|
||||||
def row(a, b):
|
def row(a, b):
|
||||||
return a == b
|
return a == b
|
||||||
|
|
||||||
|
|
||||||
params = [["external_dataset", result, expected_results, ['increment', 'external_data', 'policies'], [row]]]
|
params = [["external_dataset", result, expected_results, ['increment', 'external_data', 'policies'], [row]]]
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -118,10 +108,3 @@ class GenericTest(make_generic_test(params)):
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
unittest.main()
|
unittest.main()
|
||||||
|
|
||||||
# print()
|
|
||||||
# print("Tensor Field: config1")
|
|
||||||
# print(tabulate(tensor_field, headers='keys', tablefmt='psql'))
|
|
||||||
# print("Output:")
|
|
||||||
# print(tabulate(result, headers='keys', tablefmt='psql'))
|
|
||||||
# print()
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
import unittest
|
import unittest
|
||||||
import pandas as pd
|
import pandas as pd
|
||||||
|
|
||||||
|
|
||||||
from cadCAD.engine import ExecutionMode, ExecutionContext, Executor
|
from cadCAD.engine import ExecutionMode, ExecutionContext, Executor
|
||||||
from testing.generic_test import make_generic_test
|
from testing.generic_test import make_generic_test
|
||||||
from testing.system_models import historical_state_access
|
from testing.system_models import historical_state_access
|
||||||
|
|
@ -14,7 +13,6 @@ run = Executor(exec_context=single_proc_ctx, configs=configs)
|
||||||
|
|
||||||
raw_result, tensor_field = run.execute()
|
raw_result, tensor_field = run.execute()
|
||||||
result = pd.DataFrame(raw_result)
|
result = pd.DataFrame(raw_result)
|
||||||
# ToDo: Discrepance not reported fot collection values. Needs custom test for collection values
|
|
||||||
expected_results = {
|
expected_results = {
|
||||||
(1, 0, 0): {'x': 0, 'nonexsistant': [], 'last_x': [], '2nd_to_last_x': [], '3rd_to_last_x': [], '4th_to_last_x': []},
|
(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,
|
(1, 1, 1): {'x': 1,
|
||||||
|
|
|
||||||
|
|
@ -1,56 +0,0 @@
|
||||||
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 config1, config2
|
|
||||||
from cadCAD import configs
|
|
||||||
from testing.utils import gen_metric_dict
|
|
||||||
|
|
||||||
exec_mode = ExecutionMode()
|
|
||||||
|
|
||||||
print("Simulation Execution: Concurrent Execution")
|
|
||||||
multi_proc_ctx = ExecutionContext(context=exec_mode.multi_proc)
|
|
||||||
run = Executor(exec_context=multi_proc_ctx, configs=configs)
|
|
||||||
|
|
||||||
|
|
||||||
def get_expected_results_1(run):
|
|
||||||
return {
|
|
||||||
(run, 0, 0): {'s1': 0, 's2': 0.0, 's3': 5},
|
|
||||||
(run, 1, 1): {'s1': 1, 's2': 4, 's3': 5},
|
|
||||||
(run, 1, 2): {'s1': 2, 's2': 6, 's3': 5},
|
|
||||||
(run, 1, 3): {'s1': 3, 's2': [30, 300], 's3': 5},
|
|
||||||
(run, 2, 1): {'s1': 4, 's2': 4, 's3': 5},
|
|
||||||
(run, 2, 2): {'s1': 5, 's2': 6, 's3': 5},
|
|
||||||
(run, 2, 3): {'s1': 6, 's2': [30, 300], 's3': 5},
|
|
||||||
(run, 3, 1): {'s1': 7, 's2': 4, 's3': 5},
|
|
||||||
(run, 3, 2): {'s1': 8, 's2': 6, 's3': 5},
|
|
||||||
(run, 3, 3): {'s1': 9, 's2': [30, 300], 's3': 5},
|
|
||||||
(run, 4, 1): {'s1': 10, 's2': 4, 's3': 5},
|
|
||||||
(run, 4, 2): {'s1': 11, 's2': 6, 's3': 5},
|
|
||||||
(run, 4, 3): {'s1': 12, 's2': [30, 300], 's3': 5},
|
|
||||||
(run, 5, 1): {'s1': 13, 's2': 4, 's3': 5},
|
|
||||||
(run, 5, 2): {'s1': 14, 's2': 6, 's3': 5},
|
|
||||||
(run, 5, 3): {'s1': 15, 's2': [30, 300], 's3': 5},
|
|
||||||
}
|
|
||||||
|
|
||||||
expected_results_1 = {}
|
|
||||||
expected_results_A = get_expected_results_1(1)
|
|
||||||
expected_results_B = get_expected_results_1(2)
|
|
||||||
expected_results_1.update(expected_results_A)
|
|
||||||
expected_results_1.update(expected_results_B)
|
|
||||||
|
|
||||||
expected_results_2 = {}
|
|
||||||
|
|
||||||
# print(configs)
|
|
||||||
i = 0
|
|
||||||
config_names = ['config1', 'config2']
|
|
||||||
for raw_result, tensor_field in run.execute():
|
|
||||||
result = pd.DataFrame(raw_result)
|
|
||||||
print()
|
|
||||||
print(f"Tensor Field: {config_names[i]}")
|
|
||||||
print(tabulate(tensor_field, headers='keys', tablefmt='psql'))
|
|
||||||
print("Output:")
|
|
||||||
print(tabulate(result, headers='keys', tablefmt='psql'))
|
|
||||||
print()
|
|
||||||
print(gen_metric_dict)
|
|
||||||
i += 1
|
|
||||||
|
|
@ -71,15 +71,3 @@ class GenericTest(make_generic_test(params)):
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
unittest.main()
|
unittest.main()
|
||||||
|
|
||||||
# i = 0
|
|
||||||
# # config_names = ['sweep_config_A', 'sweep_config_B']
|
|
||||||
# for raw_result, tensor_field in run.execute():
|
|
||||||
# result = pd.DataFrame(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()
|
|
||||||
# i += 1
|
|
||||||
|
|
@ -26,14 +26,18 @@ expected_results = {
|
||||||
(1, 3, 3): {'policies': {'policy1': 4, 'policy2': 8, 'policy3': 12}, 's1': 9}
|
(1, 3, 3): {'policies': {'policy1': 4, 'policy2': 8, 'policy3': 12}, 's1': 9}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
def row(a, b):
|
def row(a, b):
|
||||||
return a == b
|
return a == b
|
||||||
|
|
||||||
|
|
||||||
params = [["policy_aggregation", result, expected_results, ['policies', 's1'], [row]]]
|
params = [["policy_aggregation", result, expected_results, ['policies', 's1'], [row]]]
|
||||||
|
|
||||||
|
|
||||||
class GenericTest(make_generic_test(params)):
|
class GenericTest(make_generic_test(params)):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
unittest.main()
|
unittest.main()
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,39 +0,0 @@
|
||||||
import unittest
|
|
||||||
import ctypes
|
|
||||||
from copy import deepcopy
|
|
||||||
from pprint import pprint
|
|
||||||
|
|
||||||
import pandas as pd
|
|
||||||
from tabulate import tabulate
|
|
||||||
|
|
||||||
from testing.generic_test import make_generic_test
|
|
||||||
from testing.system_models.udo import run
|
|
||||||
from testing.utils import generate_assertions_df, gen_metric_dict
|
|
||||||
|
|
||||||
raw_result, tensor_field = run.execute()
|
|
||||||
result = pd.DataFrame(raw_result)
|
|
||||||
|
|
||||||
cols = ['increment', 'state_udo', 'state_udo_perception_tracker',
|
|
||||||
'state_udo_tracker', 'timestamp', 'udo_policies', 'udo_policy_tracker']
|
|
||||||
|
|
||||||
|
|
||||||
# print(list(result.columns)
|
|
||||||
# ctypes.cast(id(a), ctypes.py_object).value
|
|
||||||
# pprint(gen_metric_dict(result, cols))
|
|
||||||
d = gen_metric_dict(result, cols)
|
|
||||||
pprint(d)
|
|
||||||
|
|
||||||
# for k1, v1 in d:
|
|
||||||
# print(v1)
|
|
||||||
# d_copy = deepcopy(d)
|
|
||||||
# for k, v in d_copy.items():
|
|
||||||
# # print(d[k]['state_udo']) # =
|
|
||||||
# print(ctypes.cast(id(v['state_udo']['mem_id']), ctypes.py_object).value)
|
|
||||||
|
|
||||||
|
|
||||||
# pprint(d_copy)
|
|
||||||
|
|
||||||
# df = generate_assertions_df(result, d, cols)
|
|
||||||
#
|
|
||||||
# print(tabulate(df, headers='keys', tablefmt='psql'))
|
|
||||||
#
|
|
||||||
Loading…
Reference in New Issue