From c58f2d65a6f3e5ab8873f6784bdc14060773528a Mon Sep 17 00:00:00 2001 From: "Joshua E. Jodesty" Date: Tue, 5 Feb 2019 20:00:39 -0500 Subject: [PATCH] middle ground pt. 3 --- SimCAD/configuration/utils/__init__.py | 104 +------------ SimCAD/configuration/utils/parameterSweep.py | 148 +++++++++++++++++++ simulations/example_run.py | 48 +++--- simulations/validation/config1.py | 123 +++++++-------- 4 files changed, 224 insertions(+), 199 deletions(-) create mode 100644 SimCAD/configuration/utils/parameterSweep.py diff --git a/SimCAD/configuration/utils/__init__.py b/SimCAD/configuration/utils/__init__.py index 9c9e238..3ad5b97 100644 --- a/SimCAD/configuration/utils/__init__.py +++ b/SimCAD/configuration/utils/__init__.py @@ -3,11 +3,12 @@ from decimal import Decimal from copy import deepcopy from fn.func import curried import pandas as pd +import inspect + from SimCAD.utils import rename from SimCAD.utils import dict_filter, contains_type, curry_pot - from funcy import curry import pprint @@ -125,104 +126,3 @@ def exo_update_per_ts(ep): return (y, s[y]) return {es: ep_decorator(f, es) for es, f in ep.items()} - - -def sweep(params, sweep_f): - return [rename("sweep_"+sweep_f.__name__+"_"+str(i), curry(sweep_f)(param)) for param, i in zip(params, range(len(params)))] - - -def zip_sweep_functions(sweep_lists): - zipped_sweep_lists = [] - it = iter(sweep_lists) - the_len = len(next(it)) - same_len_ind = all(len(l) == the_len for l in it) - count_ind = len(sweep_lists) >= 2 - if same_len_ind == True and count_ind == True: - return list(map(lambda x: list(x), list(zip(*sweep_lists)))) - elif same_len_ind == False or count_ind == False: - return sweep_lists - else: - raise ValueError('lists have different lengths!') - - -# ToDo: Not producing multiple dicts. -def create_sweep_config_list(zipped_sweep_lists, states_dict, state_type_ind='mechs'): - configs = [] - for f_lists in zipped_sweep_lists: - new_states_dict = deepcopy(states_dict) - for f_dict in f_lists: - if state_type_ind == 'mechs': - updates = list(f_dict.values()).pop() - functs = list(updates.values()).pop() - - mech = list(f_dict.keys()).pop() - update_type = list(updates.keys()).pop() - sk = list(functs.keys()).pop() - vf = list(functs.values()).pop() - - new_states_dict[mech][update_type][sk] = vf - elif state_type_ind == 'exo_proc': - sk = list(f_dict.keys()).pop() - vf = list(f_dict.values()).pop() - - new_states_dict[sk] = vf - else: - raise ValueError("Incorrect \'state_type_ind\'") - - configs.append(new_states_dict) - del new_states_dict - - return configs - - -def parameterize_states(exo_states): - # pp.pprint(exo_states) - # print() - sweep_lists = [] - for sk, vfs in exo_states.items(): - id_sweep_lists = [] - if isinstance(vfs, list): - for vf in vfs: - id_sweep_lists.append({sk: vf}) - if len(id_sweep_lists) != 0: - sweep_lists.append(id_sweep_lists) - - if len(sweep_lists) == 0: - return [exo_states] - - # pp.pprint(sweep_lists) - # print() - - zipped_sweep_lists = zip_sweep_functions(sweep_lists) - states_configs = create_sweep_config_list(zipped_sweep_lists, exo_states, "exo_proc") - - return states_configs - - -def parameterize_mechanism(mechanisms): - sweep_lists = [] - for mech, update_types in mechanisms.items(): - for update_type, fkv in update_types.items(): - for sk, vfs in fkv.items(): - id_sweep_lists = [] - if isinstance(vfs, list): - for vf in vfs: - id_sweep_lists.append({mech: {update_type: {sk: vf}}}) - if len(id_sweep_lists) != 0: - sweep_lists.append(id_sweep_lists) - - if len(sweep_lists) == 0: - return [mechanisms] - - zipped_sweep_lists = zip_sweep_functions(sweep_lists) - mechanisms_configs = create_sweep_config_list(zipped_sweep_lists, mechanisms, "mechs") - - return mechanisms_configs - - -# def ep_decorator(f, y, step, sL, s, _input): -# if s['mech_step'] + 1 == 1: -# return f(step, sL, s, _input) -# else: -# return (y, s[y]) -# return {es: ep_decorator(f, es) for es, f in ep.items()} diff --git a/SimCAD/configuration/utils/parameterSweep.py b/SimCAD/configuration/utils/parameterSweep.py new file mode 100644 index 0000000..e0467b2 --- /dev/null +++ b/SimCAD/configuration/utils/parameterSweep.py @@ -0,0 +1,148 @@ +import inspect +from copy import deepcopy +from funcy import curry + +from SimCAD.utils import rename +from SimCAD.configuration.utils import exo_update_per_ts + + +class ParamSweep: + def __init__(self, sweep_list, mechs=None, raw_exogenous_states=None): + self.sweep_list = sweep_list + self.mechs = mechs + self.raw_exogenous_states = raw_exogenous_states + + def mechanisms(self): + swept_mechanisms = mech_sweep_identifier(self.sweep_list, self.mechs) + return parameterize_mechanism(swept_mechanisms) + + def exogenous_states(self): + swept_raw_exogenous_states = exo_sweep_identifier(self.sweep_list, self.raw_exogenous_states) + return parameterize_states(swept_raw_exogenous_states) + + +def sweep(params, sweep_f): + return [ + rename("sweep_"+sweep_f.__name__+"_"+str(i), curry(sweep_f)(param)) + for param, i in zip(params, range(len(params))) + ] + + +def mech_sweep_identifier(sweep_list, mechanisms): + new_mechanisms = deepcopy(mechanisms) + for mech, update_types in new_mechanisms.items(): + for update_type, fkv in update_types.items(): + for sk, current_f in fkv.items(): + current_f_arg_len = len(inspect.getfullargspec(current_f).args) + if update_type == 'behaviors' and current_f_arg_len == 4: + new_mechanisms[mech][update_type][sk] = sweep(sweep_list, current_f) + elif update_type == 'states' and current_f_arg_len == 5: + new_mechanisms[mech][update_type][sk] = sweep(sweep_list, current_f) + + del mechanisms + return new_mechanisms + + +def exo_sweep_identifier(sweep_list, exo_states): + new_exo_states = deepcopy(exo_states) + for sk, current_f in exo_states.items(): + current_f_arg_len = len(inspect.getfullargspec(current_f).args) + if current_f_arg_len == 5: + new_exo_states[sk] = sweep(sweep_list, current_f) + + del exo_states + return new_exo_states + + +def zip_sweep_functions(sweep_lists): + zipped_sweep_lists = [] + it = iter(sweep_lists) + the_len = len(next(it)) + same_len_ind = all(len(l) == the_len for l in it) + count_ind = len(sweep_lists) >= 2 + if same_len_ind is True and count_ind is True: + return list(map(lambda x: list(x), list(zip(*sweep_lists)))) + elif same_len_ind is False or count_ind is False: + return sweep_lists + else: + raise ValueError('lists have different lengths!') + + +# ToDo: Not producing multiple dicts. +def create_sweep_config_list(zipped_sweep_lists, states_dict, state_type_ind='mechs'): + configs = [] + for f_lists in zipped_sweep_lists: + new_states_dict = deepcopy(states_dict) + for f_dict in f_lists: + if state_type_ind == 'mechs': + updates = list(f_dict.values()).pop() + functs = list(updates.values()).pop() + + mech = list(f_dict.keys()).pop() + update_type = list(updates.keys()).pop() + sk = list(functs.keys()).pop() + vf = list(functs.values()).pop() + + new_states_dict[mech][update_type][sk] = vf + elif state_type_ind == 'exo_proc': + sk = list(f_dict.keys()).pop() + vf = list(f_dict.values()).pop() + + new_states_dict[sk] = vf + else: + raise ValueError("Incorrect \'state_type_ind\'") + + configs.append(new_states_dict) + del new_states_dict + + return configs + + +def parameterize_states(exo_states, exo_update=exo_update_per_ts): + # pp.pprint(exo_states) + # print() + sweep_lists = [] + for sk, vfs in exo_states.items(): + id_sweep_lists = [] + if isinstance(vfs, list): + for vf in vfs: + id_sweep_lists.append({sk: vf}) + if len(id_sweep_lists) != 0: + sweep_lists.append(id_sweep_lists) + + sweep_lists_len = len(sweep_lists) + if sweep_lists_len != 0: + zipped_sweep_lists = zip_sweep_functions(sweep_lists) + states_configs = create_sweep_config_list(zipped_sweep_lists, exo_states, "exo_proc") + # pp.pprint(sweep_lists) + # print() + if exo_update == exo_update_per_ts: + return list(map(exo_update_per_ts, states_configs)) + elif exo_update != exo_update_per_ts: + return states_configs + + elif sweep_lists_len == 0 and exo_update == exo_update_per_ts: + return list(map(exo_update_per_ts, [exo_states])) + elif sweep_lists_len == 0 and exo_update != exo_update_per_ts: + return [exo_states] + + +def parameterize_mechanism(mechanisms): + sweep_lists = [] + for mech, update_types in mechanisms.items(): + for update_type, fkv in update_types.items(): + for sk, vfs in fkv.items(): + id_sweep_lists = [] + if isinstance(vfs, list): + for vf in vfs: + id_sweep_lists.append({mech: {update_type: {sk: vf}}}) + if len(id_sweep_lists) != 0: + sweep_lists.append(id_sweep_lists) + + if len(sweep_lists) == 0: + return [mechanisms] + + zipped_sweep_lists = zip_sweep_functions(sweep_lists) + mechanisms_configs = create_sweep_config_list(zipped_sweep_lists, mechanisms, "mechs") + + return mechanisms_configs diff --git a/simulations/example_run.py b/simulations/example_run.py index d41d8da..1109322 100644 --- a/simulations/example_run.py +++ b/simulations/example_run.py @@ -8,28 +8,28 @@ from SimCAD import configs exec_mode = ExecutionMode() -print("Simulation Execution 1") -print() -first_config = [configs[0]] # from config1 -single_proc_ctx = ExecutionContext(context=exec_mode.single_proc) -run1 = Executor(exec_context=single_proc_ctx, configs=first_config) -run1_raw_result, tensor_field = run1.main() -result = pd.DataFrame(run1_raw_result) -print() -print("Tensor Field:") -print(tabulate(tensor_field, headers='keys', tablefmt='psql')) -print("Output:") -print(tabulate(result, headers='keys', tablefmt='psql')) -print() +# print("Simulation Execution 1") +# print() +# first_config = [configs[0]] # from config1 +# single_proc_ctx = ExecutionContext(context=exec_mode.single_proc) +# run1 = Executor(exec_context=single_proc_ctx, configs=first_config) +# run1_raw_result, tensor_field = run1.main() +# result = pd.DataFrame(run1_raw_result) +# print() +# print("Tensor Field:") +# print(tabulate(tensor_field, headers='keys', tablefmt='psql')) +# print("Output:") +# print(tabulate(result, headers='keys', tablefmt='psql')) +# print() -# print("Simulation Execution 2: Pairwise Execution") -# multi_proc_ctx = ExecutionContext(context=exec_mode.multi_proc) -# run2 = Executor(exec_context=multi_proc_ctx, configs=configs) -# for raw_result, tensor_field in run2.main(): -# 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() +print("Simulation Execution 2: Concurrent Execution") +multi_proc_ctx = ExecutionContext(context=exec_mode.multi_proc) +run2 = Executor(exec_context=multi_proc_ctx, configs=configs) +for raw_result, tensor_field in run2.main(): + 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() diff --git a/simulations/validation/config1.py b/simulations/validation/config1.py index 14084fb..abb1211 100644 --- a/simulations/validation/config1.py +++ b/simulations/validation/config1.py @@ -5,11 +5,10 @@ import pprint from SimCAD import configs from SimCAD.configuration import Configuration -from SimCAD.configuration.utils import exo_update_per_ts, proc_trigger, bound_norm_random, \ - ep_time_step, parameterize_mechanism, parameterize_states, sweep -from SimCAD.utils import rename +from SimCAD.configuration.utils import proc_trigger, bound_norm_random, \ + ep_time_step +from SimCAD.configuration.utils.parameterSweep import ParamSweep -from fn.func import curried pp = pprint.PrettyPrinter(indent=4) @@ -33,8 +32,8 @@ def b2m1(step, sL, s): return {'param2': 4} # @curried -def b1m2(param, step, sL, s): - return {'param1': 'a', 'param2': param} +def b1m2(_beta, step, sL, s): + return {'param1': 'a', 'param2': _beta} # @curried def b2m2(step, sL, s): return {'param1': 'b', 'param2': 0} @@ -54,10 +53,16 @@ def s1m1(step, sL, s, _input): return (y, x) # @curried -def s2m1(param, step, sL, s, _input): +def s2m1(sweep_param, step, sL, s, _input): y = 's2' - x = param + x = sweep_param return (y, x) +# +# def s2m1(step, sL, s, _input): +# y = 's2' +# x = 0 +# return (y, x) + # @curried def s1m2(step, sL, s, _input): y = 's1' @@ -126,11 +131,10 @@ genesis_states = { # remove `exo_update_per_ts` to update every ts raw_exogenous_states = { - "s3": sweep(beta, es3p1), #es3p1, #sweep(beta, es3p1), - "s4": sweep(beta, es4p2), + "s3": es3p1, #es3p1, #sweep(beta, es3p1), + "s4": es4p2, "timestamp": es5p2 } -exogenous_states_list = list(map(exo_update_per_ts, parameterize_states(raw_exogenous_states))) # ToDo: make env proc trigger field agnostic @@ -147,7 +151,7 @@ env_processes = { # pp.pprint(parameterized_env_processes) # exit() -# ToDo: The number of values enteren in sweep should be the # of config objs created, +# 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 @@ -155,98 +159,71 @@ env_processes = { # need at least 1 behaviour and 1 state function for the 1st mech with behaviors # mechanisms = {} -#middleware(beta, [(m1, states, s2, s2m1), (m2, behaviors, b1, b1m2)], mechanisms) - -mechanisms_test = { +mechanisms = { "m1": { "behaviors": { - "b1": b1m1,#(0), - "b2": b2m1#(0) + "b1": b1m1, + "b2": b2m1 }, "states": { - "s1": s1m1,#(0), - "s2": "sweep" + "s1": s1m1, + "s2": s2m1 } }, "m2": { "behaviors": { - "b1": "sweep", - "b2": b2m2,#(0) + "b1": b1m2, + "b2": b2m2, }, "states": { - "s1": s1m2,#(0), - "s2": s2m2#(0) + "s1": s1m2, + "s2": s2m2 } }, "m3": { "behaviors": { - "b1": b1m3,#(0), - "b2": b2m3,#(0) + "b1": b1m3, + "b2": b2m3, }, "states": { - "s1": s1m3,#(0), - "s2": s2m3#(0) + "s1": s1m3, + "s2": s2m3 } } } -from copy import deepcopy -from funcy import curry -from inspect import getfullargspec - - -def sweep_identifier(sweep_list, sweep_id_list, mechanisms): - new_mechanisms = deepcopy(mechanisms) - for x in sweep_id_list: - current_f = new_mechanisms[x[0]][x[1]][x[2]] - if current_f is 'sweep': - new_mechanisms[x[0]][x[1]][x[2]] = sweep(sweep_list, x[3]) - - # for mech, update_types in new_mechanisms.items(): - # for update_type, fkv in update_types.items(): - # for sk, current_f in fkv.items(): - # if current_f != 'sweep' and isinstance(current_f, list) is False: - # # new_mechanisms[mech][update_type][sk] = rename("unsweeped", current_f(0)) - # curried_f = curry(current_f) - # - # def uncurried_beh_func(a, b, c): - # return curried_f(0)(a)(b)(c) - # - # def uncurried_state_func(a, b, c, d): - # return curried_f(0)(a)(b)(c)(d) - # - # if update_type == 'behaviors': - # new_mechanisms[mech][update_type][sk] = uncurried_beh_func - # elif update_type == 'states': - # new_mechanisms[mech][update_type][sk] = uncurried_state_func - - del mechanisms - return new_mechanisms - - -sweep_id_list = [('m1', 'states', 's2', s2m1), ('m2', 'behaviors', 'b1', b1m2)] -# pp.pprint(sweep_identifier(beta, sweep_id_list, mechanisms_test)) -# exit() - -mechanisms = sweep_identifier(beta, sweep_id_list, mechanisms_test) - -parameterized_mechanism = parameterize_mechanism(mechanisms) -pp.pprint(parameterized_mechanism) -# exit() +# ToDo: inspect **** +# ToDo: code block regenerator abstracted from user: input config module with params as convention, output it not as convention, +# ToDo: make ParamSweep a part of sim_config sim_config = { "N": 2, "T": range(5) + # beta } -for mechanisms, exogenous_states in zip(parameterized_mechanism, exogenous_states_list): +# beta = [1,2] +# Test +# def(beta, a, b, c): +# return a + b + beta + beta + +# ToDo: and/or, or not working +# ToDo: Abstract ParamSweep away from user +param_sweep = ParamSweep( + sweep_list=beta, + mechs=mechanisms, + raw_exogenous_states=raw_exogenous_states +) + +# ToDo: Make loop standard by returning single elems from ParamSweep if sweep not specified +for mechanisms, exogenous_states in zip(param_sweep.mechanisms(), param_sweep.exogenous_states()): configs.append( Configuration( sim_config=sim_config, state_dict=genesis_states, seed=seed, - exogenous_states=exogenous_states, #parameterize_states(raw_exogenous_states)[1], + exogenous_states=exogenous_states, env_processes=env_processes, - mechanisms=mechanisms #parameterize_mechanism(mechanisms)[1] + mechanisms=mechanisms ) )