From 875f370c5e6ba6bfa1ada41e6193424b0e361e2f Mon Sep 17 00:00:00 2001 From: "Joshua E. Jodesty" Date: Wed, 3 Apr 2019 15:33:38 -0400 Subject: [PATCH] json udc working - meets spec --- cadCAD/engine/simulation.py | 27 +--- cadCAD/utils/__init__.py | 36 +++-- simulations/az_run_udc.py | 2 +- simulations/validation/config_udc_json2.py | 4 +- simulations/validation/config_udc_json3.py | 157 +++++++++++++++++++++ 5 files changed, 186 insertions(+), 40 deletions(-) create mode 100644 simulations/validation/config_udc_json3.py diff --git a/cadCAD/engine/simulation.py b/cadCAD/engine/simulation.py index 73fc690..aa8e10c 100644 --- a/cadCAD/engine/simulation.py +++ b/cadCAD/engine/simulation.py @@ -1,11 +1,10 @@ -from collections import namedtuple from typing import Any, Callable, Dict, List, Tuple from pathos.pools import ThreadPool as TPool from copy import deepcopy from fn.op import foldr, call from cadCAD.engine.utils import engine_exception -from cadCAD.utils import flatten, UDC_Wrapper, objectview +from cadCAD.utils import flatten id_exception: Callable = engine_exception(KeyError, KeyError, None) @@ -69,34 +68,16 @@ class Executor: ) -> List[Dict[str, Any]]: last_in_obj: Dict[str, Any] = deepcopy(sL[-1]) - udc = var_dict[0]['udc'] _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 ?? - - def generate_record(state_funcs, alt_udc_dict): - for k, v in last_in_obj.items(): - if isinstance(v, dict) and hasattr(v, 'class_id'): - del last_in_obj[k] - - new_last_in_obj = dict(list(last_in_obj.items()) + list(alt_udc_dict.items())) + def generate_record(state_funcs): for f in state_funcs: - # ToDo: Create Named Tuple Here - yield self.state_update_exception(f(var_dict, sub_step, sL, new_last_in_obj, _input)) + yield self.state_update_exception(f(var_dict, sub_step, sL, last_in_obj, _input)) - - udc_dict = { - k: UDC_Wrapper( - v['current'], - udc(**v['current'].__dict__), - current_functions=['update'] - ).get_hybrid_members() - for k, v in last_in_obj.items() if isinstance(v, dict) and 'current' in v.keys() - } - last_in_copy: Dict[str, Any] = dict(generate_record(state_funcs, udc_dict)) - del udc_dict + last_in_copy: Dict[str, Any] = dict(generate_record(state_funcs)) for k in last_in_obj: if k not in last_in_copy: diff --git a/cadCAD/utils/__init__.py b/cadCAD/utils/__init__.py index 5379e88..c9fe37b 100644 --- a/cadCAD/utils/__init__.py +++ b/cadCAD/utils/__init__.py @@ -2,8 +2,6 @@ from typing import Dict, List from collections import defaultdict from itertools import product import warnings -from inspect import getmembers, ismethod -from copy import deepcopy, copy from collections import namedtuple @@ -11,25 +9,35 @@ class objectview(object): def __init__(self, d): self.__dict__ = d + def __str__(self): + filtered_members = {k: v for k, v in self.__dict__.items() if k != 'obj'} + return f"{filtered_members}" -class UDC_Wrapper(object): - def __init__(self, current, past, current_functions, past_functions=[]): - current_funcs = dict(getmembers(current, ismethod)) - filtered_current_funcs = {k: v for k, v in current_funcs.items() if k in current_functions} +class UDC(object): + def __init__(self, obj): + d = vars(obj) # somehow is enough + d['obj'] = obj - filtered_current_funcs.update(vars(past)) - filtered_current_funcs['hydra_type'] = Dict - filtered_current_funcs['current'] = current - filtered_current_funcs['past'] = past + self.members_dict = d - self.hybrid_members = filtered_current_funcs + def get_members(self): + return self.members_dict - def get_hybrid_members(self): - return self.hybrid_members + def get_object(self): + return objectview(self.members_dict) def get_namedtuple(self): - return namedtuple("Hydra", self.hybrid_members.keys())(*self.hybrid_members.values()) + return namedtuple("Hydra", self.members_dict.keys())(*self.members_dict.values()) + + +# class UDC_Wrapper2(object): +# def __init__(self, obj, functions): +# +# self.obj = obj +# +# def get_object(self): +# return objectview(self.obj.__dict__) def pipe(x): diff --git a/simulations/az_run_udc.py b/simulations/az_run_udc.py index de7abb5..88d04d1 100644 --- a/simulations/az_run_udc.py +++ b/simulations/az_run_udc.py @@ -2,7 +2,7 @@ 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_udc_json2 +from simulations.validation import config_udc_json3 from cadCAD import configs diff --git a/simulations/validation/config_udc_json2.py b/simulations/validation/config_udc_json2.py index 1f34b4b..4f9221e 100644 --- a/simulations/validation/config_udc_json2.py +++ b/simulations/validation/config_udc_json2.py @@ -19,7 +19,7 @@ class MyClassA(object): # self.past = copy(self) self.x += 1 print(f"Instance of MyClass (mem_id {hex(id(self))}) has been updated, has now value {self.x}") - return self.x #self #old_self #self.x + return self #.x #self #old_self #self.x def getMemID(self): return str(hex(id(self))) @@ -75,7 +75,7 @@ g: Dict[str, List[MyClassA]] = {'udc': [MyClassA]} # genesis state udc = MyClassA(0) # namedtuple("Hydra", self.hybrid_members.keys())(*self.hybrid_members.values()) -# udc_json = {'current': udc, 'past': udc} +udc_json = {'current': udc, 'past': udc} hydra = UDC_Wrapper(udc, udc, current_functions=['update']) hydra_members = hydra.get_hybrid_members() # hydra_obj = namedtuple("Hydra", hydra_members.keys())(*hydra_members.values()) diff --git a/simulations/validation/config_udc_json3.py b/simulations/validation/config_udc_json3.py new file mode 100644 index 0000000..8b1e0d8 --- /dev/null +++ b/simulations/validation/config_udc_json3.py @@ -0,0 +1,157 @@ +from datetime import timedelta +from cadCAD.utils import UDC +from cadCAD.configuration import append_configs +from cadCAD.configuration.utils import ep_time_step, config_sim +from typing import Dict, List + + +# ToDo: Create member for past value +class MyClassA(object): + def __init__(self, x): + self.x = x + print(f"Instance of MyClass (mem_id {hex(id(self))}) created with value {self.x}") + + def update(self): + self.x += 1 + print(f"Instance of MyClass (mem_id {hex(id(self))}) has been updated, has now value {self.x}") + # return self.x + return self + + def getMemID(self): + return str(hex(id(self))) + + # can be accessed after an update within the same substep and timestep + # ToDo: id sensitive to lineage, rerepresent + def __str__(self): + # return f"{self.__class__.__name__} - {hex(id(self))} - {self.__dict__}" + return f"{self.__dict__}" + + +# a is Correct, and classX's value is Incorrect +# Expected: a == classX's value +# b should be tracking classX's value and a: +# b should be the same value as the previous classX value and the previous a value +# https://pymotw.com/2/multiprocessing/communication.html +# ccc = MyClassA +# udc = ccc(0) +# print(MyClassA(**udc.__dict__).__dict__) + +g: Dict[str, List[MyClassA]] = {'udc': [MyClassA]} + +# udcB = MyClassB() + +# z = MyClass() +# pointer(z) +# separate thread/process for UCD with async calls to this thread/process + +# genesis state +# udc_obj = MyClassA(0) +# hydra = UDC_Wrapper(udc, udc, current_functions=['update']) +# hydra = UDC_Wrapper(udc_obj, functions=['update']) +hydra = UDC(MyClassA(0)) +hydra_members = hydra.get_object() + +state_dict = { + 'a': 0, + 'b': 0, + 'j': 0, + "hydra_members": hydra_members, + '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 HydraMembers(_g, step, sL, s, _input): + y = 'hydra_members' + obj = s['hydra_members'].obj + obj.update() + x = UDC(obj).get_object() + return (y, x) + + +def A(_g, step, sL, s, _input): + y = 'a' + x = s['a'] + 1 + return (y, x) + +def B(_g, step, sL, s, _input): + y = 'b' + # x = s['hydra_members']['x'] + x = s['hydra_members'].x + # x = s['hydra_obj'].x + return (y, x) + + +def J(_g, step, sL, s, _input): + y = 'j' + # x = s['hydra_members']['x'] + x = s['hydra_members'].x + # x = s['hydra_obj'].x + # x = s['hydra_view'].x + return (y, x) + + +partial_state_update_blocks = { + 'PSUB1': { + 'behaviors': { + }, + 'states': { + # 'ca': CA, + 'a': A, + 'b': B, + # 'hydra': Hydra, + 'hydra_members': HydraMembers, + # 'hydra_obj': HydraObj, + # 'hydra_view': HydraView, + # 'i': I, + 'j': J, + # 'k': K, + 'timestamp': time_model, + } + }, + 'PSUB2': { + 'behaviors': { + }, + 'states': { + # 'ca': CA, + 'a': A, + 'b': B, + # 'hydra': Hydra, + 'hydra_members': HydraMembers, + # 'hydra_obj': HydraObj, + # 'hydra_view': HydraView, + # 'i': I, + 'j': J, + # 'k': K, + } + }, + 'PSUB3': { + 'behaviors': { + }, + 'states': { + 'a': A, + 'b': B, + # 'hydra': Hydra, + 'hydra_members': HydraMembers, + # 'hydra_obj': HydraObj, + # 'hydra_view': HydraView, + # 'i': I, + 'j': J, + # 'k': K, + } + } +} + +sim_config = config_sim({ + "N": 2, + "T": range(4), + "M": g +}) + +append_configs(sim_config, state_dict, {}, {}, {}, partial_state_update_blocks)