docs pending review
This commit is contained in:
parent
964e3f7bc1
commit
c55e433920
38
README.md
38
README.md
|
|
@ -4,25 +4,41 @@
|
|||
|
||||
**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.
|
||||
|
||||
|
||||
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.
|
||||
|
||||
|
||||
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.
|
||||
|
||||
#### Simulation Instructional:
|
||||
* ##### [System Model Configuration](link)
|
||||
* ##### [System Simulation Execution](link)
|
||||
|
||||
#### Installation:
|
||||
**1. Install Dependencies:**
|
||||
|
||||
**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 tabulate
|
||||
pip3 install pandas pathos fn funcy tabulate
|
||||
pip3 install cadCAD --extra-index-url https://<TOKEN>@repo.fury.io/blockscience/
|
||||
```
|
||||
|
||||
|
|
|
|||
|
|
@ -5,7 +5,6 @@ from pandas.core.frame import DataFrame
|
|||
|
||||
from cadCAD.utils import SilentDF
|
||||
|
||||
|
||||
def val_switch(v):
|
||||
if isinstance(v, DataFrame) is True:
|
||||
return SilentDF(v)
|
||||
|
|
@ -18,7 +17,7 @@ class udcView(object):
|
|||
self.masked_members = masked_members
|
||||
|
||||
# returns dict to dataframe
|
||||
# def __repr__(self):
|
||||
|
||||
def __repr__(self):
|
||||
members = {}
|
||||
variables = {
|
||||
|
|
@ -26,9 +25,20 @@ 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]
|
||||
|
||||
# def __repr__(self):
|
||||
# members = {}
|
||||
# variables = {
|
||||
# k: val_switch(v) for k, v in self.__dict__.items()
|
||||
# if str(type(v)) != "<class 'method'>" and k not in self.masked_members and k == 'x' # and isinstance(v, DataFrame) is not True
|
||||
# }
|
||||
#
|
||||
# members.update(variables)
|
||||
# return f"{members}" #[1:-1]
|
||||
|
||||
|
||||
class udcBroker(object):
|
||||
def __init__(self, obj, function_filter=['__init__']):
|
||||
|
|
@ -36,7 +46,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 +68,3 @@ def UDO(udo, masked_members=['obj']):
|
|||
|
||||
def udoPipe(obj_view):
|
||||
return UDO(obj_view.obj, obj_view.masked_members)
|
||||
|
||||
|
|
|
|||
|
|
@ -115,12 +115,48 @@ class Executor:
|
|||
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))
|
||||
|
||||
|
||||
# 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))
|
||||
|
||||
# def generate_record(state_funcs):
|
||||
# for f in state_funcs:
|
||||
# tmp_last_in_copy = deepcopy(last_in_obj)
|
||||
# new_kv = self.state_update_exception(f(sweep_dict, sub_step, sH, tmp_last_in_copy, _input))
|
||||
# del tmp_last_in_copy
|
||||
# yield new_kv
|
||||
#
|
||||
# # get `state` from last_in_obj.keys()
|
||||
# # vals = last_in_obj.values()
|
||||
# def generate_record(state_funcs):
|
||||
# for state, v, f in zip(states, vals, state_funcs):
|
||||
# v_copy = deepcopy(v)
|
||||
# last_in_obj[state] = v_copy
|
||||
# new_kv = self.state_update_exception(f(sweep_dict, sub_step, sH, last_in_copy, _input))
|
||||
# del v
|
||||
# yield new_kv
|
||||
|
||||
# {k: v for k, v in l}
|
||||
|
||||
# r() - r(a') -> r(a',b') -> r(a',b',c')
|
||||
|
||||
# r(f(a),b,c) -> r(a'f(b),c) -> r(a',b',f(c)) => r(a',b',c')
|
||||
# r(a',b.update(),c)
|
||||
# r1(f(a1),b1,c1) -> r2(a2,f(b1),c1) -> r3(a3,b1,f(c1)) => r(a',b',c')
|
||||
|
||||
# r1(f(a1),b,c) -> r2(a,f(b1),c) -> r3(a,b,f(c1)) => r(a',b',c')
|
||||
|
||||
# r1(f(a1),b1,c1) -> r(a2',b2.update(),c2) -> r3(a3,b1,f(c1)) => r(a',b',c')
|
||||
|
||||
|
||||
# r1(f(a1),b1,c1) -> r2(a2,f(b1),c1) -> r3(a3,b1,f(c1)) => r(a',b',c')
|
||||
|
||||
|
||||
# reduce(lambda r: F(r), [r2(f(a),b,c), r2(a,f(b),c), r3(a,b,f(c))]) => R(a',b',c')
|
||||
|
||||
def transfer_missing_fields(source, destination):
|
||||
for k in source:
|
||||
if k not in destination:
|
||||
|
|
|
|||
|
|
@ -15,14 +15,12 @@ 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
|
||||
|
|
|
|||
|
|
@ -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,111 @@
|
|||
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
|
||||
|
||||
# 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
|
||||
)
|
||||
|
||||
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, sL, s):
|
||||
return {'gamma': _params['gamma']}
|
||||
|
||||
|
||||
def omega(_params, step, sL, s):
|
||||
return {'omega': _params['omega'](7)}
|
||||
|
||||
|
||||
# Internal States
|
||||
def alpha(_params, step, sL, s, _input):
|
||||
return 'alpha', _params['alpha']
|
||||
|
||||
def alpha_plus_gamma(_params, step, sL, s, _input):
|
||||
return 'alpha_plus_gamma', _params['alpha'] + _params['gamma']
|
||||
|
||||
|
||||
def beta(_params, step, sL, s, _input):
|
||||
return 'beta', _params['beta']
|
||||
|
||||
|
||||
def policies(_params, step, sL, s, _input):
|
||||
return 'policies', _input
|
||||
|
||||
|
||||
def sweeped(_params, step, sL, 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)
|
||||
|
||||
partial_state_update_blocks = 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=partial_state_update_blocks
|
||||
)
|
||||
|
||||
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, 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
|
||||
)
|
||||
|
||||
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, sL, s):
|
||||
return {'param1': 1}
|
||||
def p2m1(_g, step, sL, s):
|
||||
return {'param1': 1, 'param2': 4}
|
||||
|
||||
def p1m2(_g, step, sL, s):
|
||||
return {'param1': 'a', 'param2': 2}
|
||||
def p2m2(_g, step, sL, s):
|
||||
return {'param1': 'b', 'param2': 4}
|
||||
|
||||
def p1m3(_g, step, sL, s):
|
||||
return {'param1': ['c'], 'param2': np.array([10, 100])}
|
||||
def p2m3(_g, step, sL, s):
|
||||
return {'param1': ['d'], 'param2': np.array([20, 200])}
|
||||
|
||||
|
||||
# Internal States per Mechanism
|
||||
def s1m1(_g, step, sL, s, _input):
|
||||
y = 's1'
|
||||
x = s['s1'] + 1
|
||||
return (y, x)
|
||||
def s2m1(_g, step, sL, s, _input):
|
||||
y = 's2'
|
||||
x = _input['param2']
|
||||
return (y, x)
|
||||
|
||||
def s1m2(_g, step, sL, s, _input):
|
||||
y = 's1'
|
||||
x = s['s1'] + 1
|
||||
return (y, x)
|
||||
def s2m2(_g, step, sL, s, _input):
|
||||
y = 's2'
|
||||
x = _input['param2']
|
||||
return (y, x)
|
||||
|
||||
def s1m3(_g, step, sL, s, _input):
|
||||
y = 's1'
|
||||
x = s['s1'] + 1
|
||||
return (y, x)
|
||||
def s2m3(_g, step, sL, s, _input):
|
||||
y = 's2'
|
||||
x = _input['param2']
|
||||
return (y, x)
|
||||
|
||||
def policies(_g, step, sL, 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, sL, 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, sL, 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, 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))
|
||||
|
||||
|
||||
# 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])
|
||||
}
|
||||
|
||||
|
||||
partial_state_update_block = [
|
||||
{
|
||||
"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=partial_state_update_block,
|
||||
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: config1")
|
||||
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, sL, s):
|
||||
return {'param1': 1}
|
||||
def p2m1(_g, step, sL, s):
|
||||
return {'param2': 4}
|
||||
|
||||
def p1m2(_g, step, sL, s):
|
||||
return {'param1': 'a', 'param2': 2}
|
||||
def p2m2(_g, step, sL, s):
|
||||
return {'param1': 'b', 'param2': 4}
|
||||
|
||||
def p1m3(_g, step, sL, s):
|
||||
return {'param1': ['c'], 'param2': np.array([10, 100])}
|
||||
def p2m3(_g, step, sL, s):
|
||||
return {'param1': ['d'], 'param2': np.array([20, 200])}
|
||||
|
||||
|
||||
# Internal States per Mechanism
|
||||
def s1m1(_g, step, sL, s, _input):
|
||||
y = 's1'
|
||||
x = _input['param1']
|
||||
return (y, x)
|
||||
def s2m1(_g, step, sL, s, _input):
|
||||
y = 's2'
|
||||
x = _input['param2']
|
||||
return (y, x)
|
||||
|
||||
def s1m2(_g, step, sL, s, _input):
|
||||
y = 's1'
|
||||
x = _input['param1']
|
||||
return (y, x)
|
||||
def s2m2(_g, step, sL, s, _input):
|
||||
y = 's2'
|
||||
x = _input['param2']
|
||||
return (y, x)
|
||||
|
||||
def s1m3(_g, step, sL, s, _input):
|
||||
y = 's1'
|
||||
x = _input['param1']
|
||||
return (y, x)
|
||||
def s2m3(_g, step, sL, 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, sL, 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, sL, 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, 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))
|
||||
|
||||
|
||||
# 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])
|
||||
}
|
||||
|
||||
partial_state_update_block = [
|
||||
{
|
||||
"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=partial_state_update_block
|
||||
)
|
||||
|
|
@ -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 config2
|
||||
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: config1")
|
||||
print(tabulate(tensor_field, headers='keys', tablefmt='psql'))
|
||||
print("Output:")
|
||||
print(tabulate(result, headers='keys', tablefmt='psql'))
|
||||
print()
|
||||
|
|
@ -0,0 +1,71 @@
|
|||
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
|
||||
```python
|
||||
+----+-------+------------+-----------+------+-----------+
|
||||
| | 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] |
|
||||
+----+-------+------------+-----------+------+-----------+
|
||||
```
|
||||
|
||||
##### [Single Process Example Execution](link)
|
||||
|
||||
##### [Multiple Process Example Execution](link)
|
||||
|
|
@ -0,0 +1,97 @@
|
|||
Historical State Access
|
||||
==
|
||||
The 3rd parameter of state and policy update functions (labels as `sH` of type `List[List[dict]]`) provides access to
|
||||
past Partial State Updates (PSU) given a negative offset number. `access_block` is used to access past PSUs
|
||||
(`List[dict]`) from `sH`.
|
||||
|
||||
Example: `-2` denotes to second to last PSU
|
||||
|
||||
##### Exclusion List
|
||||
Create a list of states to exclude from the reported PSU.
|
||||
```python
|
||||
exclusion_list = [
|
||||
'nonexsistant', 'last_x', '2nd_to_last_x', '3rd_to_last_x', '4th_to_last_x'
|
||||
]
|
||||
```
|
||||
##### Example Policy Updates
|
||||
###### Last partial state update
|
||||
```python
|
||||
from cadCAD.configuration.utils import config_sim, access_block
|
||||
|
||||
def last_update(_g, 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.
|
||||
###### 2nd to last partial state update
|
||||
```python
|
||||
def second2last_update(_g, substep, sH, s):
|
||||
return {"2nd_to_last_x": access_block(sH, "2nd_to_last_x", -2, exclusion_list)}
|
||||
```
|
||||
|
||||
##### Define State Updates
|
||||
###### 3rd to last partial state update
|
||||
```python
|
||||
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)
|
||||
```
|
||||
###### 4rd to last partial state update
|
||||
```python
|
||||
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)
|
||||
```
|
||||
###### Non-exsistant partial state update
|
||||
* `psu_block_offset >= 0` doesn't exsist
|
||||
```python
|
||||
def nonexsistant(_g, substep, sH, s, _input):
|
||||
return 'nonexsistant', access_block(sH, "nonexsistant", 0, exclusion_list)
|
||||
```
|
||||
|
||||
#### Example Simulation
|
||||
link
|
||||
|
||||
#### 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}] |
|
||||
+----+-----------------------------------------------------------------------------------------------------------------------------------------------------+
|
||||
```
|
||||
|
||||
#### [Example Configuration](link)
|
||||
#### [Example Results](link)
|
||||
|
|
@ -0,0 +1,68 @@
|
|||
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, sL, 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(_g, step, sL, s):
|
||||
return {'beta': _g['beta'], 'gamma': _g['gamma']}
|
||||
```
|
||||
* Simulation 1: `{'beta': 2, 'gamma': 3]}`
|
||||
* Simulation 2: `{'beta': 5, 'gamma': 4}`
|
||||
|
||||
##### Configure Simulation
|
||||
```python
|
||||
from cadCAD.configuration.utils import config_sim
|
||||
|
||||
sim_config = config_sim(
|
||||
{
|
||||
"N": 2,
|
||||
"T": range(5),
|
||||
"M": g,
|
||||
}
|
||||
)
|
||||
```
|
||||
|
||||
#### [Example Configuration](link)
|
||||
#### [Example Results](link)
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,60 @@
|
|||
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(_g, step, sL, s):
|
||||
return {'policy1': 1}
|
||||
def p2_psu1(_g, step, sL, 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(_g, step, sL, s):
|
||||
return {'policy1': 2, 'policy2': 2}
|
||||
def p2_psu2(_g, step, sL, 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(_g, step, sL, s):
|
||||
return {'policy1': 1, 'policy2': 2, 'policy3': 3}
|
||||
def p2_psu3(_g, step, sL, 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 Configuration](link)
|
||||
#### [Example Results](link)
|
||||
|
|
@ -0,0 +1,220 @@
|
|||
System Model Configuration
|
||||
==
|
||||
|
||||
#### Introduction
|
||||
|
||||
Given System Model Configurations, cadCAD produces system event datasets that conform to specified system metrics. Each
|
||||
event / record is of [Enogenous State variables](link) produced by user defined [Partial State Updates](link) (PSU /
|
||||
functions that update state); A sequence of event / record subsets that comprises the resulting system event dataset is
|
||||
produced by a [Partial State Update Block](link) (PSUB / a Tensor Field for which State, Policy, and Time are dimensions
|
||||
and PSU functions are values).
|
||||
|
||||
A **System Model Configuration** is comprised of a simulation configuration, initial endogenous states, Partial State
|
||||
Update Blocks, environmental process, and a user defined policy aggregation function.
|
||||
|
||||
Execution:
|
||||
|
||||
#### Simulation Properties
|
||||
|
||||
###### System Metrics
|
||||
The following system metrics determine the size of resulting system event datasets:
|
||||
* `run` - the number of simulations in the resulting dataset
|
||||
* `timestep` - the number of timestamps in the resulting dataset
|
||||
* `substep` - the number of PSUs per `timestep` / within PSUBS
|
||||
* Number of events / records: `run` x `timestep` x `substep`
|
||||
|
||||
###### Simulation Configuration
|
||||
For the following dictionary, `T` is assigned a `timestep` range, `N` is assigned the number of simulation runs, and
|
||||
`params` is assigned the [**Parameter Sweep**](link) dictionary.
|
||||
|
||||
```python
|
||||
from cadCAD.configuration.utils import config_sim
|
||||
|
||||
sim_config = config_sim({
|
||||
"N": 2,
|
||||
"T": range(5),
|
||||
"M": params, # Optional
|
||||
})
|
||||
```
|
||||
|
||||
#### Initial Endogenous States
|
||||
**Enogenous State variables** are read-only variables defined to capture the shape and property of the network and
|
||||
represent internal input and signal.
|
||||
|
||||
The PSUB tensor field is applied to the following states to produce a resulting system event
|
||||
dataset.
|
||||
```python
|
||||
genesis_states = {
|
||||
's1': 0.0,
|
||||
's2': 0.0,
|
||||
's3': 1.0,
|
||||
'timestamp': '2018-10-01 15:16:24'
|
||||
}
|
||||
```
|
||||
|
||||
#### Partial State Update Block:
|
||||
- ***Partial State Update Block(PSUB)*** ***(Define ?)*** Tensor Field for which State, Policy, Time are dimensions
|
||||
and Partial State Update functions are values.
|
||||
- ***Partial State Update (PSU)*** are user defined functions that encodes state updates and are executed in
|
||||
a specified order PSUBs. PSUs update states given the most recent set of states and PSU policies.
|
||||
- ***Mechanism*** ***(Define)***
|
||||
|
||||
|
||||
The PSUBs is a list of PSU dictionaries of the structure within the code block below. PSUB elements (PSU dictionaries)
|
||||
are listed / defined in order of `substeps` and **identity functions** (returning a previous state's value) are assigned
|
||||
to unreferenced states within PSUs. The number of records produced produced per `timestep` is the number of `substeps`.
|
||||
|
||||
```python
|
||||
partial_state_update_block = [
|
||||
{
|
||||
"policies": {
|
||||
"b1": p1_psu1,
|
||||
"b2": p2_psu1
|
||||
},
|
||||
"variables": {
|
||||
"s1": s1_psu1,
|
||||
"s2": s2_psu1
|
||||
}
|
||||
},
|
||||
{
|
||||
"policies": {
|
||||
"b1": p1_psu2,
|
||||
},
|
||||
"variables": {
|
||||
"s2": s2_psu2
|
||||
}
|
||||
},
|
||||
{...}
|
||||
]
|
||||
```
|
||||
*Notes:*
|
||||
1. An identity function (returning the previous state value) is assigned to `s1` in the second PSU.
|
||||
2. Currently the only names that need not correspond to the convention below are `'b1'` and `'b2'`.
|
||||
|
||||
#### Policies
|
||||
- ***Policies*** ***(Define)*** When are policies behavior ?
|
||||
- ***Behaviors*** model agent behaviors in reaction to state variables and exogenous variables. The
|
||||
resulted user action will become an input to PSUs. Note that user behaviors should not directly update value
|
||||
of state variables.
|
||||
|
||||
Policies accept parameter sweep variables [see link] `_g` (`dict`), the most recent
|
||||
`substep` integer, the state history[see link] (`sH`), the most recent state record `s` (`dict) as inputs and returns a
|
||||
set of actions (`dict`).
|
||||
|
||||
Policy functions return dictionaries as actions. Policy functions provide access to parameter sweep variables [see link]
|
||||
via dictionary `_g`.
|
||||
```python
|
||||
def p1_psu1(_g, substep, sH, s):
|
||||
return {'policy1': 1}
|
||||
def p2_psu1(_g, substep, sH, s):
|
||||
return {'policy1': 1, 'policy2': 4}
|
||||
```
|
||||
For each PSU, multiple policy dictionaries are aggregated into a single dictionary to be imputted into
|
||||
all state functions using an initial reduction function (default: `lambda a, b: a + b`) and optional subsequent map
|
||||
functions.
|
||||
Example Result: `{'policy1': 2, 'policy2': 4}`
|
||||
|
||||
#### State Updates
|
||||
State update functions provide access to parameter sweep variables [see link] `_g` (`dict`), the most recent `substep`
|
||||
integer, the state history[see link] (`sH`), the most recent state record as a dictionary (`s`), the policies of a
|
||||
PSU (`_input`), and returns a tuple of the state variable's name and the resulting new value of the variable.
|
||||
|
||||
```python
|
||||
def state_update(_g, substep, sH, s, _input):
|
||||
...
|
||||
return state, update
|
||||
```
|
||||
**Note:** Each state update function updates one state variable at a time. Changes to multiple state variables requires
|
||||
separate state update functions. A generic example of a PSU is as follows.
|
||||
|
||||
* ##### Endogenous State Updates
|
||||
They are only updated by PSUs and can be used as inputs to a PSUs.
|
||||
```python
|
||||
def s1_update(_g, substep, sH, s, _input):
|
||||
x = _input['policy1'] + 1
|
||||
return 's1', x
|
||||
|
||||
def s2_update(_g, substep, sH, s, _input):
|
||||
x = _input['policy2']
|
||||
return 's2', x
|
||||
```
|
||||
|
||||
* ##### Exogenous State Updates
|
||||
***Exogenous State variables*** ***(Review)*** are read-only variables that represent external input and signal. They
|
||||
update endogenous states and are only updated by environmental processes. Exgoneous variables can be used
|
||||
as an input to a PSU that impacts state variables. ***(Expand upon Exogenous state updates)***
|
||||
|
||||
```python
|
||||
from datetime import timedelta
|
||||
from cadCAD.configuration.utils import time_step
|
||||
def es3_update(_g, substep, sH, s, _input):
|
||||
x = ...
|
||||
return 's3'
|
||||
def es4_update(_g, substep, sH, s, _input):
|
||||
x = ...
|
||||
return 's4', x
|
||||
def update_timestamp(_g, substep, sH, s, _input):
|
||||
x = time_step(dt_str=s[y], dt_format='%Y-%m-%d %H:%M:%S', _timedelta=timedelta(days=0, minutes=0, seconds=1))
|
||||
return 'timestamp', x
|
||||
```
|
||||
Exogenous state update functions (`es3_update`, `es4_update` and `es5_update`) update once per timestamp and should be
|
||||
included as a part of the first PSU in the PSUB.
|
||||
```python
|
||||
partial_state_update_block['psu1']['variables']['s3'] = es3_update
|
||||
partial_state_update_block['psu1']['variables']['s4'] = es4_update
|
||||
partial_state_update_block['psu1']['variables']['timestamp'] = update_timestamp
|
||||
```
|
||||
|
||||
* #### Environmental Process
|
||||
- ***Environmental processes*** model external changes that directly impact exogenous states at given specific
|
||||
conditions such as market shocks at specific timestamps.
|
||||
|
||||
Create a dictionary like `env_processes` below for which the keys are exogenous states and the values are lists of user
|
||||
defined **Environment Update** functions to be composed (e.g. `[f(params, x), g(params, x)]` becomes
|
||||
`f(params, g(params, x))`).
|
||||
|
||||
Environment Updates accept the [**Parameter Sweep**](link) dictionary `params` and a state as a result of a PSU.
|
||||
```python
|
||||
def env_update(params, state):
|
||||
. . .
|
||||
return updated_state
|
||||
|
||||
# OR
|
||||
|
||||
env_update = lambda params, state: state + 5
|
||||
```
|
||||
|
||||
The `env_trigger` function is used to apply composed environment update functions to a list of specific exogenous state
|
||||
update results. `env_trigger` accepts the total number of `substeps` for the simulation / `end_substep` and returns a
|
||||
function accepting `trigger_field`, `trigger_vals`, and `funct_list`.
|
||||
|
||||
In the following example functions are used to add `5` to every `s3` update and assign `10` to `s4` at
|
||||
`timestamp`s `'2018-10-01 15:16:25'`, `'2018-10-01 15:16:27'`, and `'2018-10-01 15:16:29'`.
|
||||
```python
|
||||
from cadCAD.configuration.utils import env_trigger
|
||||
trigger_timestamps = ['2018-10-01 15:16:25', '2018-10-01 15:16:27', '2018-10-01 15:16:29']
|
||||
env_processes = {
|
||||
"s3": [lambda params, x: x + 5],
|
||||
"s4": env_trigger(end_substep=3)(
|
||||
trigger_field='timestamp', trigger_vals=trigger_timestamps, funct_list=[lambda params, x: 10]
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
#### System Model Configuration
|
||||
`append_configs`, stores a **System Model Configuration** to be (Executed)[url] as
|
||||
simulations producing system event dataset(s)
|
||||
|
||||
```python
|
||||
from cadCAD.configuration import append_configs
|
||||
|
||||
append_configs(
|
||||
sim_configs=sim_config,
|
||||
initial_state=genesis_states,
|
||||
env_processes=env_processes,
|
||||
partial_state_update_blocks=partial_state_update_block,
|
||||
policy_ops=[lambda a, b: a + b]
|
||||
)
|
||||
```
|
||||
|
||||
#### [System Simulation Execution](link)
|
||||
|
|
@ -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,7 +140,7 @@ partial_state_update_blocks = {
|
|||
# "s4": es4p2,
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
|
||||
sim_config = config_sim(
|
||||
|
|
@ -153,6 +154,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 = {
|
||||
|
|
|
|||
|
|
@ -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'))
|
||||
|
|
|
|||
|
|
@ -2,11 +2,9 @@ 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
|
||||
from testing.utils import generate_assertions
|
||||
|
||||
exec_mode = ExecutionMode()
|
||||
|
||||
|
|
|
|||
|
|
@ -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'))
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@ import unittest
|
|||
from parameterized import parameterized
|
||||
from functools import reduce
|
||||
from tabulate import tabulate
|
||||
from testing.utils import generate_assertions_df
|
||||
|
||||
# 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)
|
||||
|
|
@ -14,26 +13,61 @@ from testing.utils import generate_assertions_df
|
|||
# ToDo: Use self.assertRaises(AssertionError)
|
||||
|
||||
|
||||
def generate_assertions_df(df, expected_results, target_cols, evaluations):
|
||||
# cols = ['run', 'timestep', 'substep'] + target_cols
|
||||
# print(cols)
|
||||
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):
|
||||
@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)]
|
||||
if erroneous.empty is False:
|
||||
|
||||
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 = {k: expected[k] for k in expected if k in row and expected[k] != row[k]}
|
||||
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[f"invalid_{key}"] = unexpected[key]
|
||||
erroneous[key] = None
|
||||
erroneous.at[index, key] = unexpected[key]
|
||||
# etc.
|
||||
|
||||
print()
|
||||
print(tabulate(erroneous, headers='keys', tablefmt='psql'))
|
||||
# print()
|
||||
# print(f"TEST: {test_name}")
|
||||
# print(tabulate(erroneous, headers='keys', tablefmt='psql'))
|
||||
|
||||
self.assertTrue(reduce(lambda a, b: a and b, tested_df['test']))
|
||||
# ToDo: Condition that will change false to true
|
||||
self.assertTrue(reduce(lambda a, b: a and b, tested_df[test_name]))
|
||||
|
||||
# def etc.
|
||||
|
||||
@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,67 @@
|
|||
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('/Users/jjodesty/Projects/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()}
|
||||
|
||||
# ToDo: SilentDF(df) wont work
|
||||
#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}]
|
||||
)
|
||||
|
|
@ -92,6 +92,4 @@ append_configs(
|
|||
partial_state_update_blocks=partial_state_update_block
|
||||
)
|
||||
|
||||
exec_mode = ExecutionMode()
|
||||
single_proc_ctx = ExecutionContext(context=exec_mode.single_proc)
|
||||
run = Executor(exec_context=single_proc_ctx, configs=configs)
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,110 @@
|
|||
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)
|
||||
|
||||
|
||||
# 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 = {
|
||||
'alpha': 0,
|
||||
'beta': 0,
|
||||
'policies': {},
|
||||
'sweeped': {}
|
||||
}
|
||||
|
||||
# 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']])
|
||||
|
||||
|
||||
# config_sim Necessary
|
||||
sim_config = config_sim(
|
||||
{
|
||||
"N": 2,
|
||||
"T": range(5),
|
||||
"M": g, # Optional
|
||||
}
|
||||
)
|
||||
# print()
|
||||
# pp.pprint(g)
|
||||
# print()
|
||||
# pp.pprint(sim_config)
|
||||
|
||||
|
||||
# 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()
|
||||
|
|
@ -1,7 +1,5 @@
|
|||
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
|
||||
|
|
@ -85,6 +83,4 @@ append_configs(
|
|||
policy_ops=[lambda a, b: a + b, lambda y: y * 2] # Default: lambda a, b: a + b ToDO: reduction function requires high lvl explanation
|
||||
)
|
||||
|
||||
exec_mode = ExecutionMode()
|
||||
single_proc_ctx = ExecutionContext(context=exec_mode.single_proc)
|
||||
run = Executor(exec_context=single_proc_ctx, configs=configs)
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,185 @@
|
|||
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)
|
||||
|
|
@ -0,0 +1,127 @@
|
|||
import unittest
|
||||
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 external_dataset
|
||||
from cadCAD import configs
|
||||
from testing.generic_test import make_generic_test
|
||||
from testing.utils import gen_metric_dict
|
||||
|
||||
exec_mode = ExecutionMode()
|
||||
|
||||
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)
|
||||
|
||||
raw_result, tensor_field = run.execute()
|
||||
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):
|
||||
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()
|
||||
|
||||
# print()
|
||||
# print("Tensor Field: config1")
|
||||
# print(tabulate(tensor_field, headers='keys', tablefmt='psql'))
|
||||
# print("Output:")
|
||||
# print(tabulate(result, headers='keys', tablefmt='psql'))
|
||||
# print()
|
||||
|
|
@ -1,14 +1,20 @@
|
|||
import unittest
|
||||
import pandas as pd
|
||||
from tabulate import tabulate
|
||||
|
||||
|
||||
from cadCAD.engine import ExecutionMode, ExecutionContext, Executor
|
||||
from testing.generic_test import make_generic_test
|
||||
from testing.system_models.historical_state_access import run
|
||||
from testing.utils import generate_assertions_df
|
||||
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)
|
||||
|
||||
# ToDo: Discrepance not reported fot collection values. Needs custom test for collection values
|
||||
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,
|
||||
|
|
@ -31,49 +37,85 @@ expected_results = {
|
|||
'4th_to_last_x': []},
|
||||
(1, 2, 1): {'x': 4,
|
||||
'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}],
|
||||
'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}],
|
||||
'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}],
|
||||
'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}],
|
||||
'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}],
|
||||
'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}],
|
||||
'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': []}
|
||||
}
|
||||
|
||||
params = [["historical_state_access", result, expected_results,
|
||||
['x', 'nonexsistant', 'last_x', '2nd_to_last_x', '3rd_to_last_x', '4th_to_last_x']]
|
||||
]
|
||||
# df = generate_assertions_df(result, expected_results,
|
||||
# ['x', 'nonexsistant', 'last_x', '2nd_to_last_x', '3rd_to_last_x', '4th_to_last_x']
|
||||
# )
|
||||
# print(tabulate(df, headers='keys', tablefmt='psql'))
|
||||
|
||||
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)):
|
||||
|
|
|
|||
|
|
@ -0,0 +1,56 @@
|
|||
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
|
||||
|
|
@ -0,0 +1,85 @@
|
|||
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()
|
||||
|
||||
# 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
|
||||
|
|
@ -1,14 +1,21 @@
|
|||
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.policy_aggregation import run
|
||||
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': 2, 'policy2': 4}, 's1': 500},
|
||||
(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},
|
||||
|
|
@ -19,14 +26,14 @@ expected_results = {
|
|||
(1, 3, 3): {'policies': {'policy1': 4, 'policy2': 8, 'policy3': 12}, 's1': 9}
|
||||
}
|
||||
|
||||
params = [["policy_aggregation", result, expected_results, ['policies', 's1']]]
|
||||
# df = generate_assertions_df(result, expected_results, ['policies', 's1'])
|
||||
# print(tabulate(df, headers='keys', tablefmt='psql'))
|
||||
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,39 @@
|
|||
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'))
|
||||
#
|
||||
|
|
@ -1,28 +1,21 @@
|
|||
def gen_metric_row(row):
|
||||
return ((row['run'], row['timestep'], row['substep']), {'s1': row['s1'], 'policies': row['policies']})
|
||||
#
|
||||
# def record_generator(row, cols):
|
||||
# return {col: row[col] for col in cols}
|
||||
|
||||
def gen_metric_row(row):
|
||||
return {
|
||||
'run': row['run'],
|
||||
'timestep': row['timestep'],
|
||||
'substep': row['substep'],
|
||||
's1': row['s1'],
|
||||
'policies': row['policies']
|
||||
}
|
||||
def gen_metric_row(row, cols):
|
||||
return ((row['run'], row['timestep'], row['substep']), {col: row[col] for col in cols})
|
||||
|
||||
def gen_metric_dict(df):
|
||||
return [gen_metric_row(row) for index, row in df.iterrows()]
|
||||
# def gen_metric_row(row):
|
||||
# return ((row['run'], row['timestep'], row['substep']), {'s1': row['s1'], 'policies': row['policies']})
|
||||
|
||||
def generate_assertions_df(df, expected_results, target_cols):
|
||||
def df_filter(run, timestep, substep):
|
||||
return df[
|
||||
(df['run'] == run) & (df['timestep'] == timestep) & (df['substep'] == substep)
|
||||
][target_cols].to_dict(orient='records')[0]
|
||||
# def gen_metric_row(row):
|
||||
# return {
|
||||
# 'run': row['run'],
|
||||
# 'timestep': row['timestep'],
|
||||
# 'substep': row['substep'],
|
||||
# 's1': row['s1'],
|
||||
# 'policies': row['policies']
|
||||
# }
|
||||
|
||||
df['test'] = df.apply(
|
||||
lambda x: \
|
||||
df_filter(x['run'], x['timestep'], x['substep']) == expected_results[(x['run'], x['timestep'], x['substep'])]
|
||||
, axis=1
|
||||
)
|
||||
|
||||
return df
|
||||
def gen_metric_dict(df, cols):
|
||||
return dict([gen_metric_row(row, cols) for index, row in df.iterrows()])
|
||||
|
|
|
|||
Loading…
Reference in New Issue