diff --git a/cadCAD/configuration/__init__.py b/cadCAD/configuration/__init__.py index 56aae05..cbfea98 100644 --- a/cadCAD/configuration/__init__.py +++ b/cadCAD/configuration/__init__.py @@ -9,8 +9,6 @@ from cadCAD.configuration.utils import exo_update_per_ts from cadCAD.configuration.utils.policyAggregation import dict_elemwise_sum from cadCAD.configuration.utils.depreciationHandler import sanitize_partial_state_updates, sanitize_config -# policy_ops=[foldr(dict_elemwise_sum())] -# policy_ops=[reduce, lambda a, b: {**a, **b}] class Configuration(object): def __init__(self, sim_config={}, initial_state={}, seeds={}, env_processes={}, @@ -28,7 +26,7 @@ class Configuration(object): sanitize_config(self) -# ToDo: Remove Seeds + def append_configs(sim_configs={}, initial_state={}, seeds={}, raw_exogenous_states={}, env_processes={}, partial_state_update_blocks={}, policy_ops=[lambda a, b: a + b], _exo_update_per_ts: bool = True) -> None: if _exo_update_per_ts is True: diff --git a/cadCAD/configuration/utils/__init__.py b/cadCAD/configuration/utils/__init__.py index 8c16b8c..ea5f068 100644 --- a/cadCAD/configuration/utils/__init__.py +++ b/cadCAD/configuration/utils/__init__.py @@ -5,12 +5,10 @@ from fn.func import curried from funcy import curry import pandas as pd -# Temporary from cadCAD.configuration.utils.depreciationHandler import sanitize_partial_state_updates from cadCAD.utils import dict_filter, contains_type, flatten_tabulated_dict, tabulate_dict -# ToDo: Fix - Returns empty when partial_state_update is missing in Configuration class TensorFieldReport: def __init__(self, config_proc): self.config_proc = config_proc @@ -56,7 +54,6 @@ def time_step(dt_str, dt_format='%Y-%m-%d %H:%M:%S', _timedelta = tstep_delta): return t.strftime(dt_format) -# ToDo: Inject in first elem of last PSUB from Historical state ep_t_delta = timedelta(days=0, minutes=0, seconds=1) def ep_time_step(s_condition, dt_str, fromat_str='%Y-%m-%d %H:%M:%S', _timedelta = ep_t_delta): # print(dt_str) @@ -65,7 +62,7 @@ def ep_time_step(s_condition, dt_str, fromat_str='%Y-%m-%d %H:%M:%S', _timedelta else: return dt_str -# mech_sweep_filter + def partial_state_sweep_filter(state_field, partial_state_updates): partial_state_dict = dict([(k, v[state_field]) for k, v in partial_state_updates.items()]) return dict([ @@ -77,7 +74,7 @@ def partial_state_sweep_filter(state_field, partial_state_updates): def state_sweep_filter(raw_exogenous_states): return dict([(k, v) for k, v in raw_exogenous_states.items() if isinstance(v, list)]) -# sweep_mech_states + @curried def sweep_partial_states(_type, in_config): configs = [] @@ -129,16 +126,19 @@ def exo_update_per_ts(ep): return {es: ep_decorator(f, es) for es, f in ep.items()} + def trigger_condition(s, pre_conditions, cond_opp): condition_bools = [s[field] in precondition_values for field, precondition_values in pre_conditions.items()] return reduce(cond_opp, condition_bools) + def apply_state_condition(pre_conditions, cond_opp, y, f, _g, step, sL, s, _input): if trigger_condition(s, pre_conditions, cond_opp): return f(_g, step, sL, s, _input) else: return y, s[y] + def var_trigger(y, f, pre_conditions, cond_op): return lambda _g, step, sL, s, _input: apply_state_condition(pre_conditions, cond_op, y, f, _g, step, sL, s, _input) @@ -173,7 +173,6 @@ def env_trigger(end_substep): curry(trigger)(end_substep)(trigger_field)(trigger_vals)(funct_list) -# param sweep enabling middleware def config_sim(d): def process_variables(d): return flatten_tabulated_dict(tabulate_dict(d)) @@ -184,15 +183,18 @@ def config_sim(d): d["M"] = [{}] return d + def psub_list(psu_block, psu_steps): return [psu_block[psu] for psu in psu_steps] + def psub(policies, state_updates): return { 'policies': policies, 'states': state_updates } + def genereate_psubs(policy_grid, states_grid, policies, state_updates): PSUBS = [] for policy_ids, state_list in zip(policy_grid, states_grid): @@ -202,7 +204,7 @@ def genereate_psubs(policy_grid, states_grid, policies, state_updates): return PSUBS -# ToDo: DO NOT filter sH for every state/policy update. Requires a consumable sH (new sH) + def access_block(state_history, target_field, psu_block_offset, exculsion_list=[]): exculsion_list += [target_field] def filter_history(key_list, sH): diff --git a/cadCAD/configuration/utils/depreciationHandler.py b/cadCAD/configuration/utils/depreciationHandler.py index 330823b..ab57082 100644 --- a/cadCAD/configuration/utils/depreciationHandler.py +++ b/cadCAD/configuration/utils/depreciationHandler.py @@ -2,8 +2,6 @@ from copy import deepcopy def sanitize_config(config): - # for backwards compatibility, we accept old arguments via **kwargs - # TODO: raise specific deprecation warnings for key == 'state_dict', key == 'seed', key == 'mechanisms' for key, value in config.kwargs.items(): if key == 'state_dict': config.initial_state = value @@ -18,8 +16,6 @@ def sanitize_config(config): def sanitize_partial_state_updates(partial_state_updates): new_partial_state_updates = deepcopy(partial_state_updates) - # for backwards compatibility we accept the old keys - # ('behaviors' and 'states') and rename them def rename_keys(d): if 'behaviors' in d: d['policies'] = d.pop('behaviors') @@ -28,8 +24,6 @@ def sanitize_partial_state_updates(partial_state_updates): d['variables'] = d.pop('states') - # Also for backwards compatibility, we accept partial state update blocks both as list or dict - # No need for a deprecation warning as it's already raised by cadCAD.utils.key_filter if isinstance(new_partial_state_updates, list): for v in new_partial_state_updates: rename_keys(v) diff --git a/cadCAD/configuration/utils/policyAggregation.py b/cadCAD/configuration/utils/policyAggregation.py index 96077dc..9309d01 100644 --- a/cadCAD/configuration/utils/policyAggregation.py +++ b/cadCAD/configuration/utils/policyAggregation.py @@ -1,6 +1,7 @@ from fn.op import foldr from fn.func import curried + def get_base_value(x): if isinstance(x, str): return '' @@ -17,7 +18,7 @@ def policy_to_dict(v): add = lambda a, b: a + b -# df_union = lambda a, b: ... + @curried def foldr_dict_vals(f, d): diff --git a/cadCAD/configuration/utils/userDefinedObject.py b/cadCAD/configuration/utils/userDefinedObject.py index 4ced71f..f37b3f2 100644 --- a/cadCAD/configuration/utils/userDefinedObject.py +++ b/cadCAD/configuration/utils/userDefinedObject.py @@ -1,23 +1,22 @@ from collections import namedtuple -from copy import deepcopy from inspect import getmembers, ismethod from pandas.core.frame import DataFrame from cadCAD.utils import SilentDF + def val_switch(v): if isinstance(v, DataFrame) is True: return SilentDF(v) else: return v + class udcView(object): def __init__(self, d, masked_members): self.__dict__ = d self.masked_members = masked_members - # returns dict to dataframe - def __repr__(self): members = {} variables = { @@ -27,17 +26,7 @@ class udcView(object): members['methods'] = [k for k, v in self.__dict__.items() if str(type(v)) == ""] 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)) != "" 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] + return f"{members}" class udcBroker(object): diff --git a/cadCAD/engine/__init__.py b/cadCAD/engine/__init__.py index a8002b9..8147f5f 100644 --- a/cadCAD/engine/__init__.py +++ b/cadCAD/engine/__init__.py @@ -93,7 +93,6 @@ class Executor: final_result = None if self.exec_context == ExecutionMode.single_proc: - # ToDO: Deprication Handler - "sanitize" in appropriate place tensor_field = create_tensor_field(partial_state_updates.pop(), eps.pop()) result = self.exec_method(simulation_execs, var_dict_list, states_lists, configs_structs, env_processes_list, Ts, Ns) final_result = result, tensor_field diff --git a/cadCAD/engine/simulation.py b/cadCAD/engine/simulation.py index dd2d45d..c5818a4 100644 --- a/cadCAD/engine/simulation.py +++ b/cadCAD/engine/simulation.py @@ -63,9 +63,6 @@ class Executor: ) for k, val_list in new_dict.items() } - # [f1] = ops - # return {k: reduce(f1, val_list) for k, val_list in new_dict.items()} - # return foldr(call, col_results)(ops) def apply_env_proc( self, @@ -98,7 +95,6 @@ class Executor: return state_dict - # ToDo: Redifined as a function that applies the tensor field to a set og last conditions # mech_step def partial_state_update( self, @@ -119,8 +115,6 @@ class Executor: ) - # 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)) @@ -134,7 +128,6 @@ class Executor: last_in_copy: Dict[str, Any] = transfer_missing_fields(last_in_obj, dict(generate_record(state_funcs))) last_in_copy: Dict[str, Any] = self.apply_env_proc(sweep_dict, env_processes, last_in_copy) - # ToDo: make 'substep' & 'timestep' reserve fields last_in_copy['substep'], last_in_copy['timestep'], last_in_copy['run'] = sub_step, time_step, run sL.append(last_in_copy) @@ -155,7 +148,6 @@ class Executor: sub_step = 0 states_list_copy: List[Dict[str, Any]] = deepcopy(simulation_list[-1]) - # ToDo: Causes Substep repeats in sL: genesis_states: Dict[str, Any] = states_list_copy[-1] if len(states_list_copy) == 1: @@ -167,7 +159,6 @@ class Executor: del states_list_copy states_list: List[Dict[str, Any]] = [genesis_states] - # ToDo: Was causing Substep repeats in sL, use for yield sub_step += 1 for [s_conf, p_conf] in configs: # tensor field @@ -196,7 +187,6 @@ class Executor: ) -> List[List[Dict[str, Any]]]: time_seq: List[int] = [x + 1 for x in time_seq] - # ToDo: simulation_list should be a Tensor that is generated throughout the Executor simulation_list: List[List[Dict[str, Any]]] = [states_list] for time_step in time_seq: @@ -209,8 +199,6 @@ class Executor: return simulation_list - # ToDo: Below can be recieved from a tensor field - # configs: List[Tuple[List[Callable], List[Callable]]] def simulation( self, sweep_dict: Dict[str, List[Any]], diff --git a/cadCAD/engine/utils.py b/cadCAD/engine/utils.py index c0f3a76..4fa5b47 100644 --- a/cadCAD/engine/utils.py +++ b/cadCAD/engine/utils.py @@ -24,8 +24,6 @@ def retrieve_state(l, offset): return l[last_index(l) + offset + 1] -# exception_function = f(sub_step, sL, sL[-2], _input) -# try_function = f(sub_step, sL, last_mut_obj, _input) @curried def engine_exception(ErrorType, error_message, exception_function, try_function): try: @@ -38,5 +36,3 @@ def engine_exception(ErrorType, error_message, exception_function, try_function) @curried def fit_param(param, x): return x + param - -# fit_param = lambda param: lambda x: x + param diff --git a/cadCAD/utils/__init__.py b/cadCAD/utils/__init__.py index ccb5f9d..0243464 100644 --- a/cadCAD/utils/__init__.py +++ b/cadCAD/utils/__init__.py @@ -11,15 +11,11 @@ class SilentDF(DataFrame): def __repr__(self): return str(hex(id(DataFrame))) #"pandas.core.frame.DataFrame" + def append_dict(dict, new_dict): dict.update(new_dict) return dict -# def val_switch(v): -# if isinstance(v, DataFrame) is True or isinstance(v, SilentDF) is True: -# return SilentDF(v) -# else: -# return v.x class IndexCounter: def __init__(self): @@ -29,8 +25,6 @@ class IndexCounter: self.i += 1 return self.i -# def compose(*functions): -# return reduce(lambda f, g: lambda x: f(g(x)), functions, lambda x: x) def compose(*functions): return reduce(lambda f, g: lambda x: f(g(x)), functions, lambda x: x) @@ -108,8 +102,7 @@ def contains_type(_collection, type): def drop_right(l, n): return l[:len(l) - n] -# backwards compatibility -# ToDo: Encapsulate in function + def key_filter(l, keyname): if (type(l) == list): return [v[keyname] for v in l] @@ -147,23 +140,3 @@ def curry_pot(f, *argv): return f(argv[0], argv[1], argv[2]) else: raise TypeError('curry_pot() needs 3 or 4 positional arguments') - -# def curry_pot(f, *argv): -# sweep_ind = f.__name__[0:5] == 'sweep' -# arg_len = len(argv) -# if sweep_ind is True and arg_len == 4: -# return f(argv[0])(argv[1])(argv[2])(argv[3]) -# elif sweep_ind is False and arg_len == 4: -# return f(argv[0])(argv[1])(argv[2])(argv[3]) -# elif sweep_ind is True and arg_len == 3: -# return f(argv[0])(argv[1])(argv[2]) -# elif sweep_ind is False and arg_len == 3: -# return f(argv[0])(argv[1])(argv[2]) -# else: -# raise TypeError('curry_pot() needs 3 or 4 positional arguments') - -# def rename(newname): -# def decorator(f): -# f.__name__ = newname -# return f -# return decorator diff --git a/cadCAD/utils/sys_config.py b/cadCAD/utils/sys_config.py index 3da1efe..4d1c285 100644 --- a/cadCAD/utils/sys_config.py +++ b/cadCAD/utils/sys_config.py @@ -1,37 +1,46 @@ from funcy import curry - from cadCAD.configuration.utils import ep_time_step, time_step + def increment(y, incr_by): return lambda _g, step, sL, s, _input: (y, s[y] + incr_by) + def track(y): return lambda _g, step, sL, s, _input: (y, s[y].x) + def simple_state_update(y, x): return lambda _g, step, sH, s, _input: (y, x) + def simple_policy_update(y): return lambda _g, step, sH, s: y + def update_timestamp(y, timedelta, format): return lambda _g, step, sL, s, _input: ( y, ep_time_step(s, dt_str=s[y], fromat_str=format, _timedelta=timedelta) ) + def apply(f, y: str, incr_by: int): return lambda _g, step, sL, s, _input: (y, curry(f)(s[y])(incr_by)) + def add(y: str, incr_by): return apply(lambda a, b: a + b, y, incr_by) + def increment_state_by_int(y: str, incr_by: int): return lambda _g, step, sL, s, _input: (y, s[y] + incr_by) + def s(y, x): return lambda _g, step, sH, s, _input: (y, x) + def time_model(y, substeps, time_delta, ts_format='%Y-%m-%d %H:%M:%S'): def apply_incriment_condition(s): if s['substep'] == 0 or s['substep'] == substeps: @@ -40,94 +49,3 @@ def time_model(y, substeps, time_delta, ts_format='%Y-%m-%d %H:%M:%S'): return y, s[y] return lambda _g, step, sL, s, _input: apply_incriment_condition(s) - -# ToDo: Impliment Matrix reduction -# -# [ -# {'conditions': [123], 'opp': lambda a, b: a and b}, -# {'conditions': [123], 'opp': lambda a, b: a and b} -# ] - -# def trigger_condition2(s, conditions, cond_opp): -# # print(conditions) -# condition_bools = [s[field] in precondition_values for field, precondition_values in conditions.items()] -# return reduce(cond_opp, condition_bools) -# -# def trigger_multi_conditions(s, multi_conditions, multi_cond_opp): -# # print([(d['conditions'], d['reduction_opp']) for d in multi_conditions]) -# condition_bools = [ -# trigger_condition2(s, conditions, opp) for conditions, opp in [ -# (d['conditions'], d['reduction_opp']) for d in multi_conditions -# ] -# ] -# return reduce(multi_cond_opp, condition_bools) -# -# def apply_state_condition2(multi_conditions, multi_cond_opp, y, f, _g, step, sL, s, _input): -# if trigger_multi_conditions(s, multi_conditions, multi_cond_opp): -# return f(_g, step, sL, s, _input) -# else: -# return y, s[y] -# -# def proc_trigger2(y, f, multi_conditions, multi_cond_opp): -# return lambda _g, step, sL, s, _input: apply_state_condition2(multi_conditions, multi_cond_opp, y, f, _g, step, sL, s, _input) -# -# def timestep_trigger2(end_substep, y, f): -# multi_conditions = [ -# { -# 'condition': { -# 'substep': [0, end_substep] -# }, -# 'reduction_opp': lambda a, b: a and b -# } -# ] -# multi_cond_opp = lambda a, b: a and b -# return proc_trigger2(y, f, multi_conditions, multi_cond_opp) - -# -# @curried - - - -# print(env_trigger(3).__module__) -# pp.pprint(dir(env_trigger)) - - - -# @curried -# def env_proc_trigger(trigger_time, update_f, time): -# if time == trigger_time: -# return update_f -# else: -# return lambda x: x - - - - -# def p1m1(_g, step, sL, s): -# return {'param1': 1} -# -# def apply_policy_condition(policies, policy_id, f, conditions, _g, step, sL, s): -# if trigger_condition(s, conditions): -# policies[policy_id] = f(_g, step, sL, s) -# return policies -# else: -# return policies -# -# def proc_trigger2(policies, conditions, policy_id, f): -# return lambda _g, step, sL, s: apply_policy_condition(policies, policy_id, f, conditions,_g, step, sL, s) - -# policies_updates = {"p1": udo_policyA, "p2": udo_policyB} - - -# @curried -# def proc_trigger(trigger_time, update_f, time): -# if time == trigger_time: -# return update_f -# else: -# return lambda x: x - - -# def repr(_g, step, sL, s, _input): -# y = 'z' -# x = s['state_udo'].__repr__() -# return (y, x) \ No newline at end of file