diff --git a/SimCAD/__init__.py b/SimCAD/__init__.py index afb7760..3b57d59 100644 --- a/SimCAD/__init__.py +++ b/SimCAD/__init__.py @@ -1,5 +1,5 @@ from fn.op import foldr -from SimCAD.utils.configuration import dict_elemwise_sum +from SimCAD.configuration.utils.behaviorAggregation import dict_elemwise_sum configs = [] diff --git a/SimCAD/configuration/__init__.py b/SimCAD/configuration/__init__.py new file mode 100644 index 0000000..ad438bf --- /dev/null +++ b/SimCAD/configuration/__init__.py @@ -0,0 +1,87 @@ +from functools import reduce +import pandas as pd +from SimCAD.utils import key_filter + +class Identity: + def __init__(self, behavior_id={'indentity': 0}): + self.beh_id_return_val = behavior_id + + def b_identity(self, step, sL, s): + return self.beh_id_return_val + + def behavior_identity(self, k): + return self.b_identity + + def no_state_identity(self, step, sL, s, _input): + return None + + def state_identity(self, k): + return lambda step, sL, s, _input: (k, s[k]) + + def apply_identity_funcs(self, identity, df, cols): + def fillna_with_id_func(identity, df, col): + return df[[col]].fillna(value=identity(col)) + + return list(map(lambda col: fillna_with_id_func(identity, df, col), cols)) + + +class Processor: + + def __init__(self, id=Identity()): + self.id = id + self.b_identity = id.b_identity + self.behavior_identity = id.behavior_identity + self.no_state_identity = id.no_state_identity + self.state_identity = id.state_identity + self.apply_identity_funcs = id.apply_identity_funcs + + # Make returntype chosen by user. Must Classify Configs + def create_matrix_field(self, mechanisms, key): + if key == 'states': + identity = self.state_identity + else: + identity = self.behavior_identity + df = pd.DataFrame(key_filter(mechanisms, key)) + col_list = self.apply_identity_funcs(identity, df, list(df.columns)) + if len(col_list) != 0: + return reduce((lambda x, y: pd.concat([x, y], axis=1)), col_list) + else: + return pd.DataFrame({'empty': []}) + + # Maybe Refactor to only use dictionary BUT I used dfs to fill NAs. Perhaps fill + def generate_config(self, state_dict, mechanisms, exo_proc): + + # include False / False case + def no_update_handler(bdf, sdf): + if (bdf.empty == False) and (sdf.empty == True): + bdf_values = bdf.values.tolist() + sdf_values = [[self.no_state_identity] * len(bdf_values) for m in range(len(mechanisms))] + return sdf_values, bdf_values + elif (bdf.empty == True) and (sdf.empty == False): + sdf_values = sdf.values.tolist() + bdf_values = [[self.b_identity] * len(sdf_values) for m in range(len(mechanisms))] + return sdf_values, bdf_values + else: + sdf_values = sdf.values.tolist() + bdf_values = bdf.values.tolist() + return sdf_values, bdf_values + + def only_ep_handler(state_dict): + sdf_functions = [ + lambda step, sL, s, _input: (k, v) for k, v in zip(state_dict.keys(), state_dict.values()) + ] + sdf_values = [sdf_functions] + bdf_values = [[self.b_identity] * len(sdf_values)] + return sdf_values, bdf_values + + # zipped_list = [] + if len(mechanisms) != 0: + bdf = self.create_matrix_field(mechanisms, 'behaviors') + sdf = self.create_matrix_field(mechanisms, 'states') + sdf_values, bdf_values = no_update_handler(bdf, sdf) + zipped_list = list(zip(sdf_values, bdf_values)) + else: + sdf_values, bdf_values = only_ep_handler(state_dict) + zipped_list = list(zip(sdf_values, bdf_values)) + + return list(map(lambda x: (x[0] + exo_proc, x[1]), zipped_list)) \ No newline at end of file diff --git a/SimCAD/utils/configuration.py b/SimCAD/configuration/utils/__init__.py similarity index 54% rename from SimCAD/utils/configuration.py rename to SimCAD/configuration/utils/__init__.py index 1b657a6..ca15942 100644 --- a/SimCAD/utils/configuration.py +++ b/SimCAD/configuration/utils/__init__.py @@ -1,7 +1,20 @@ from datetime import datetime, timedelta from decimal import Decimal from fn.func import curried -from fn.op import foldr +import pandas as pd + +class TensorFieldReport: + def __init__(self, config_proc): + self.config_proc = config_proc + + # dont for-loop to apply exo_procs, use exo_proc struct + def create_tensor_field(self, mechanisms, exo_proc, keys=['behaviors', 'states']): + dfs = [self.config_proc.create_matrix_field(mechanisms, k) for k in keys] + df = pd.concat(dfs, axis=1) + for es, i in zip(exo_proc, range(len(exo_proc))): + df['es' + str(i + 1)] = es + df['m'] = df.index + 1 + return df def bound_norm_random(rng, low, high): @@ -44,53 +57,4 @@ def exo_update_per_ts(ep): return f(step, sL, s, _input) else: return (y, s[y]) - return {es: ep_decorator(f, es) for es, f in ep.items()} - - -def print_fwd(x): - print(x) - return x - - -def get_base_value(datatype): - if datatype is str: - return '' - elif datatype is int: - return 0 - elif datatype is list: - return [] - return 0 - - -def behavior_to_dict(v): - return dict(list(zip(map(lambda n: 'b' + str(n + 1), list(range(len(v)))), v))) - - -add = lambda a, b: a + b - - -@curried -def foldr_dict_vals(f, d): - return foldr(f)(list(d.values())) - - -def sum_dict_values(): - return foldr_dict_vals(add) - -# AttributeError: 'int' object has no attribute 'keys' -# config7c -@curried -def dict_op(f, d1, d2): - def set_base_value(target_dict, source_dict, key): - if key not in target_dict: - return get_base_value(type(source_dict[key])) - else: - return target_dict[key] - - key_set = set(list(d1.keys()) + list(d2.keys())) - - return {k: f(set_base_value(d1, d2, k), set_base_value(d2, d1, k)) for k in key_set} - - -def dict_elemwise_sum(): - return dict_op(add) \ No newline at end of file + return {es: ep_decorator(f, es) for es, f in ep.items()} \ No newline at end of file diff --git a/SimCAD/configuration/utils/behaviorAggregation/__init__.py b/SimCAD/configuration/utils/behaviorAggregation/__init__.py new file mode 100644 index 0000000..abde5d6 --- /dev/null +++ b/SimCAD/configuration/utils/behaviorAggregation/__init__.py @@ -0,0 +1,49 @@ +from fn.op import foldr +from fn.func import curried + + +def get_base_value(datatype): + if datatype is str: + return '' + elif datatype is int: + return 0 + elif datatype is list: + return [] + return 0 + + +def behavior_to_dict(v): + return dict(list(zip(map(lambda n: 'b' + str(n + 1), list(range(len(v)))), v))) + + +add = lambda a, b: a + b + + +@curried +def foldr_dict_vals(f, d): + return foldr(f)(list(d.values())) + + +def sum_dict_values(): + return foldr_dict_vals(add) + +# AttributeError: 'int' object has no attribute 'keys' +# config7c +@curried +def dict_op(f, d1, d2): + def set_base_value(target_dict, source_dict, key): + if key not in target_dict: + return get_base_value(type(source_dict[key])) + else: + return target_dict[key] + + key_set = set(list(d1.keys()) + list(d2.keys())) + + return {k: f(set_base_value(d1, d2, k), set_base_value(d2, d1, k)) for k in key_set} + + +def dict_elemwise_sum(): + return dict_op(add) + + +# class BehaviorAggregation: \ No newline at end of file diff --git a/SimCAD/engine/__init__.py b/SimCAD/engine/__init__.py index 78dc6f1..11b2031 100644 --- a/SimCAD/engine/__init__.py +++ b/SimCAD/engine/__init__.py @@ -2,8 +2,8 @@ from pathos.multiprocessing import ProcessingPool as Pool from tabulate import tabulate from SimCAD.utils import flatten -from SimCAD.utils.ui import create_tensor_field -from SimCAD.utils.configProcessor import generate_config +from SimCAD.configuration import Processor +from SimCAD.configuration.utils import TensorFieldReport from SimCAD.engine.simulation import Executor as SimExecutor @@ -50,6 +50,9 @@ class Executor: def execute(self): + config_proc = Processor() + create_tensor_field = TensorFieldReport(config_proc).create_tensor_field + print(self.exec_context+": "+str(self.configs)) states_lists, Ts, Ns, eps, configs_structs, env_processes_list, mechanisms, simulation_execs = \ [], [], [], [], [], [], [], [] @@ -59,7 +62,7 @@ class Executor: Ts.append(x.sim_config['T']) Ns.append(x.sim_config['N']) eps.append(list(x.exogenous_states.values())) - configs_structs.append(generate_config(x.state_dict, x.mechanisms, eps[config_idx])) + configs_structs.append(config_proc.generate_config(x.state_dict, x.mechanisms, eps[config_idx])) env_processes_list.append(x.env_processes) mechanisms.append(x.mechanisms) simulation_execs.append(SimExecutor(x.behavior_ops).simulation) diff --git a/SimCAD/engine/simulation.py b/SimCAD/engine/simulation.py index 0249dc9..1c22286 100644 --- a/SimCAD/engine/simulation.py +++ b/SimCAD/engine/simulation.py @@ -3,11 +3,11 @@ from fn.op import foldr, call import pprint pp = pprint.PrettyPrinter(indent=4) + class Executor: def __init__(self, behavior_ops): self.behavior_ops = behavior_ops - # Data Type reduction def getBehaviorInput(self, step, sL, s, funcs): @@ -17,13 +17,11 @@ class Executor: return foldr(call, getColResults(step, sL, s, funcs))(ops) - def apply_env_proc(self, env_processes, state_dict, step): for state in state_dict.keys(): if state in list(env_processes.keys()): state_dict[state] = env_processes[state](step)(state_dict[state]) - # remove / modify def exception_handler(self, f, m_step, sL, last_mut_obj, _input): try: @@ -32,7 +30,6 @@ class Executor: print("Exception") return f(m_step, sL, sL[-2], _input) - def mech_step(self, m_step, sL, state_funcs, behavior_funcs, env_processes, t_step, run): last_in_obj = sL[-1] @@ -58,7 +55,6 @@ class Executor: return sL - def mech_pipeline(self, states_list, configs, env_processes, t_step, run): m_step = 0 states_list_copy = deepcopy(states_list) diff --git a/SimCAD/utils/engine.py b/SimCAD/engine/utils.py similarity index 100% rename from SimCAD/utils/engine.py rename to SimCAD/engine/utils.py diff --git a/SimCAD/utils/__init__.py b/SimCAD/utils/__init__.py index 60a491b..4ec31e1 100644 --- a/SimCAD/utils/__init__.py +++ b/SimCAD/utils/__init__.py @@ -1,5 +1,14 @@ +def print_fwd(x): + print(x) + return x + + flatten = lambda l: [item for sublist in l for item in sublist] def flatmap(f, items): - return list(map(f, items)) \ No newline at end of file + return list(map(f, items)) + + +def key_filter(l, keyname): + return [v[keyname] for k, v in l.items()] \ No newline at end of file diff --git a/SimCAD/utils/configProcessor.py b/SimCAD/utils/configProcessor.py deleted file mode 100644 index c2d0bbe..0000000 --- a/SimCAD/utils/configProcessor.py +++ /dev/null @@ -1,83 +0,0 @@ -import pandas as pd -from functools import reduce - - -def no_state_identity(step, sL, s, _input): - return None - - -def state_identity(k): - return lambda step, sL, s, _input: (k, s[k]) - - -# Make returntype chosen by user. Must Classify Configs -def b_identity(step, sL, s): - return {'indentity': 0} - - -def behavior_identity(k): - return b_identity - - -def key_filter(mechanisms, keyname): - return [v[keyname] for k, v in mechanisms.items()] - - -def fillna_with_id_func(identity, df, col): - return df[[col]].fillna(value=identity(col)) - - -def apply_identity_funcs(identity, df, cols): - return list(map(lambda col: fillna_with_id_func(identity, df, col), cols)) - - -def create_matrix_field(mechanisms, key): - if key == 'states': - identity = state_identity - else: - identity = behavior_identity - df = pd.DataFrame(key_filter(mechanisms, key)) - col_list = apply_identity_funcs(identity, df, list(df.columns)) - if len(col_list) != 0: - return reduce((lambda x, y: pd.concat([x, y], axis=1)), col_list) - else: - return pd.DataFrame({'empty' : []}) - - -# Maybe Refactor to only use dictionary BUT I used dfs to fill NAs. Perhaps fill -def generate_config(state_dict, mechanisms, exo_proc): - - # include False / False case - def no_update_handler(bdf, sdf): - if (bdf.empty == False) and (sdf.empty == True): - bdf_values = bdf.values.tolist() - sdf_values = [[no_state_identity] * len(bdf_values) for m in range(len(mechanisms))] - return sdf_values, bdf_values - elif (bdf.empty == True) and (sdf.empty == False): - sdf_values = sdf.values.tolist() - bdf_values = [[b_identity] * len(sdf_values) for m in range(len(mechanisms))] - return sdf_values, bdf_values - else: - sdf_values = sdf.values.tolist() - bdf_values = bdf.values.tolist() - return sdf_values, bdf_values - - def only_ep_handler(state_dict): - sdf_functions = [ - lambda step, sL, s, _input: (k, v) for k, v in zip(state_dict.keys(), state_dict.values()) - ] - sdf_values = [sdf_functions] - bdf_values = [[b_identity] * len(sdf_values)] - return sdf_values, bdf_values - - # zipped_list = [] - if len(mechanisms) != 0: - bdf = create_matrix_field(mechanisms, 'behaviors') - sdf = create_matrix_field(mechanisms, 'states') - sdf_values, bdf_values = no_update_handler(bdf, sdf) - zipped_list = list(zip(sdf_values, bdf_values)) - else: - sdf_values, bdf_values = only_ep_handler(state_dict) - zipped_list = list(zip(sdf_values, bdf_values)) - - return list(map(lambda x: (x[0] + exo_proc, x[1]), zipped_list)) \ No newline at end of file diff --git a/SimCAD/utils/ui.py b/SimCAD/utils/ui.py deleted file mode 100644 index bed280d..0000000 --- a/SimCAD/utils/ui.py +++ /dev/null @@ -1,12 +0,0 @@ -import pandas as pd -from SimCAD.utils.configProcessor import create_matrix_field - - -# dont for-loop to apply exo_procs, use exo_proc struct -def create_tensor_field(mechanisms, exo_proc, keys=['behaviors', 'states']): - dfs = [create_matrix_field(mechanisms, k) for k in keys] - df = pd.concat(dfs, axis=1) - for es, i in zip(exo_proc, range(len(exo_proc))): - df['es'+str(i+1)] = es - df['m'] = df.index + 1 - return df \ No newline at end of file diff --git a/sandbox/barlin/config3.py b/sandbox/barlin/config3.py index 242913d..14f45fd 100644 --- a/sandbox/barlin/config3.py +++ b/sandbox/barlin/config3.py @@ -2,7 +2,7 @@ from decimal import Decimal import numpy as np from SimCAD import Configuration, configs -from SimCAD.utils.configuration import exo_update_per_ts, proc_trigger, bound_norm_random, \ +from SimCAD.configuration import exo_update_per_ts, bound_norm_random, \ ep_time_step seed = { diff --git a/sandbox/barlin/config4.py b/sandbox/barlin/config4.py index c9243dd..eb62774 100644 --- a/sandbox/barlin/config4.py +++ b/sandbox/barlin/config4.py @@ -2,7 +2,7 @@ from decimal import Decimal import numpy as np from SimCAD import Configuration, configs -from SimCAD.utils.configuration import exo_update_per_ts, proc_trigger, bound_norm_random, \ +from SimCAD.configuration import exo_update_per_ts, bound_norm_random, \ ep_time_step seed = { diff --git a/sandbox/validation/config1.py b/sandbox/validation/config1.py index 2e464cf..7017dfe 100644 --- a/sandbox/validation/config1.py +++ b/sandbox/validation/config1.py @@ -3,7 +3,7 @@ import numpy as np from datetime import timedelta from SimCAD import Configuration, configs -from SimCAD.utils.configuration import exo_update_per_ts, proc_trigger, bound_norm_random, \ +from SimCAD.configuration.utils import exo_update_per_ts, proc_trigger, bound_norm_random, \ ep_time_step seed = { diff --git a/sandbox/validation/config2.py b/sandbox/validation/config2.py index c762eba..4d03faf 100644 --- a/sandbox/validation/config2.py +++ b/sandbox/validation/config2.py @@ -3,7 +3,7 @@ import numpy as np from datetime import timedelta from SimCAD import Configuration, configs -from SimCAD.utils.configuration import exo_update_per_ts, proc_trigger, bound_norm_random, \ +from SimCAD.configuration.utils import exo_update_per_ts, proc_trigger, bound_norm_random, \ ep_time_step diff --git a/sandbox/zx/config_zx.py b/sandbox/zx/config_zx.py index cd91f75..d17b523 100644 --- a/sandbox/zx/config_zx.py +++ b/sandbox/zx/config_zx.py @@ -5,7 +5,7 @@ from decimal import Decimal import numpy as np from SimCAD import Configuration, configs -from SimCAD.utils.configuration import exo_update_per_ts, proc_trigger, bound_norm_random, \ +from SimCAD.configuration import exo_update_per_ts, proc_trigger, bound_norm_random, \ ep_time_step seed = {