diff --git a/cadCAD/engine/simulation.py b/cadCAD/engine/simulation.py index a62d1bb..104e8d2 100644 --- a/cadCAD/engine/simulation.py +++ b/cadCAD/engine/simulation.py @@ -5,6 +5,7 @@ from fn.op import foldr, call from cadCAD.engine.utils import engine_exception from cadCAD.utils import flatten +import pprint as pp id_exception: Callable = engine_exception(KeyError, KeyError, None) @@ -72,6 +73,7 @@ class Executor: _input: Dict[str, Any] = self.policy_update_exception(self.get_policy_input(var_dict, sub_step, sL, last_in_obj, policy_funcs)) # ToDo: add env_proc generator to `last_in_copy` iterator as wrapper function + # ToDo: Can be multithreaded ?? last_in_copy: Dict[str, Any] = dict( [ self.state_update_exception(f(var_dict, sub_step, sL, last_in_obj, _input)) for f in state_funcs @@ -86,6 +88,7 @@ class Executor: self.apply_env_proc(env_processes, last_in_copy, last_in_copy['timestep']) + # ToDo: make 'substep' & 'timestep' reserve fields last_in_copy['substep'], last_in_copy['timestep'], last_in_copy['run'] = sub_step, time_step, run sL.append(last_in_copy) @@ -106,7 +109,16 @@ class Executor: sub_step = 0 states_list_copy: List[Dict[str, Any]] = deepcopy(states_list) + # for d1 in states_list: + # for d2 in states_list_copy: + # d2['classX'] = d1['classX'] + # + # print() + # pp.pprint(states_list_copy) + # print() + genesis_states: Dict[str, Any] = states_list_copy[-1] + del states_list_copy genesis_states['substep'], genesis_states['timestep'] = sub_step, time_step states_list: List[Dict[str, Any]] = [genesis_states] @@ -158,6 +170,11 @@ class Executor: def execute_run(var_dict, states_list, configs, env_processes, time_seq, run) -> List[Dict[str, Any]]: run += 1 states_list_copy: List[Dict[str, Any]] = deepcopy(states_list) + + # for d1 in states_list: + # for d2 in states_list_copy: + # d2['classX'] = d1['classX'] + head, *tail = self.run_pipeline(var_dict, states_list_copy, configs, env_processes, time_seq, run) del states_list_copy diff --git a/simulations/az_run.py b/simulations/az_run.py new file mode 100644 index 0000000..8c199ce --- /dev/null +++ b/simulations/az_run.py @@ -0,0 +1,25 @@ +import pandas as pd +from tabulate import tabulate +# The following imports NEED to be in the exact order +from cadCAD.engine import ExecutionMode, ExecutionContext, Executor +from simulations.validation import config_az +from cadCAD import configs + +import pprint as pp + +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.main() +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() \ No newline at end of file diff --git a/simulations/validation/config1.py b/simulations/validation/config1.py index 2c26f91..70d1da3 100644 --- a/simulations/validation/config1.py +++ b/simulations/validation/config1.py @@ -6,7 +6,6 @@ from cadCAD.configuration import append_configs from cadCAD.configuration.utils import proc_trigger, bound_norm_random, ep_time_step from cadCAD.configuration.utils.parameterSweep import config_sim - seeds = { 'z': np.random.RandomState(1), 'a': np.random.RandomState(2), @@ -37,7 +36,7 @@ def p2m3(_g, step, sL, s): # Internal States per Mechanism def s1m1(_g, step, sL, s, _input): y = 's1' - x = _input['param1'] + x = s['s1'] + 1 return (y, x) def s2m1(_g, step, sL, s, _input): y = 's2' @@ -46,7 +45,7 @@ def s2m1(_g, step, sL, s, _input): def s1m2(_g, step, sL, s, _input): y = 's1' - x = _input['param1'] + x = s['s1'] + 1 return (y, x) def s2m2(_g, step, sL, s, _input): y = 's2' @@ -55,7 +54,7 @@ def s2m2(_g, step, sL, s, _input): def s1m3(_g, step, sL, s, _input): y = 's1' - x = _input['param1'] + x = s['s1'] + 1 return (y, x) def s2m3(_g, step, sL, s, _input): y = 's2' diff --git a/simulations/validation/config_az.py b/simulations/validation/config_az.py new file mode 100644 index 0000000..02ff2f3 --- /dev/null +++ b/simulations/validation/config_az.py @@ -0,0 +1,91 @@ +from copy import deepcopy +from datetime import timedelta +from cadCAD.configuration import append_configs +from cadCAD.configuration.utils import ep_time_step +from cadCAD.configuration.utils.parameterSweep import config_sim + + +class MyClass: + def __init__(self): + self.x = 0 + print(f"Instance of MyClass (mem_id {hex(id(self))}) created with value {self.x}") + + def update(self): + # res = deepcopy(self) + self.x += 1 + # print(f"Instance of MyClass (mem_id {hex(id(self))}) has been updated, has now value {self.x}") + return self #res + + def __str__(self): + return f"PRINT MyClass: @ {hex(id(self))}: value {self.x}" + +# genesis state +state_dict = { + 'classX': MyClass(), + 'a': 0, + 'b': 0, + 'timestamp': '2019-01-01 00:00:00' +} + + +timestep_duration = timedelta(minutes=1) # In this example, a timestep has a duration of 1 minute. +ts_format = '%Y-%m-%d %H:%M:%S' +def time_model(_g, step, sL, s, _input): + y = 'timestamp' + x = ep_time_step(s, dt_str=s['timestamp'], fromat_str=ts_format, _timedelta=timestep_duration) + return (y, x) + + +def updateClassX(_g, step, sL, s, _input): + y = 'classX' + x = s['classX'] + return (y, x) + + +def updateA(_g, step, sL, s, _input): + y = 'a' + x = s['a'] + 1 + return (y, x) + + +def updateB(_g, step, sL, s, _input): + s['classX'].update() + y = 'b' + x = s['classX'].x + return (y, x) + + +partial_state_update_blocks = { + 'PSUB1': { + 'behaviors': { + }, + 'states': { + 'timestamp': time_model + } + }, + 'PSUB2': { + 'behaviors': { + }, + 'states': { + 'classX': updateClassX, + 'a': updateA, + 'b': updateB + } + }, + 'PSUB3': { + 'behaviors': { + }, + 'states': { + 'classX': updateClassX, + 'a': updateA, + 'b': updateB + } + } +} + +sim_config = config_sim({ + "N": 2, + "T": range(4) +}) + +append_configs(sim_config, state_dict, {}, {}, {}, partial_state_update_blocks)