diff --git a/.gitignore b/.gitignore index a9e45ba..b70d197 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,9 @@ .idea .ipynb_checkpoints .DS_Store +.idea +notebooks +SimCAD.egg-info __pycache__ Pipfile Pipfile.lock diff --git a/README.md b/README.md index 289fd4b..825c846 100644 --- a/README.md +++ b/README.md @@ -19,9 +19,9 @@ SimCAD is written in Python 3. **1. Install Dependencies:** ```bash -pip install -r requirements.txt +pip3 install -r requirements.txt python3 setup.py sdist bdist_wheel -pip install dist/SimCAD-0.1-py3-none-any.whl +pip3 install dist/SimCAD-0.1-py3-none-any.whl ``` **2. Configure Simulation:** diff --git a/SimCAD/__init__.py b/SimCAD/__init__.py index 0b7fa28..b4234cb 100644 --- a/SimCAD/__init__.py +++ b/SimCAD/__init__.py @@ -1,2 +1,2 @@ name = "SimCAD" -configs = [] +configs = [] \ No newline at end of file diff --git a/SimCAD/configuration/__init__.py b/SimCAD/configuration/__init__.py index 223de64..018a4d7 100644 --- a/SimCAD/configuration/__init__.py +++ b/SimCAD/configuration/__init__.py @@ -2,36 +2,70 @@ from functools import reduce from fn.op import foldr import pandas as pd +from SimCAD import configs from SimCAD.utils import key_filter from SimCAD.configuration.utils.behaviorAggregation import dict_elemwise_sum +from SimCAD.configuration.utils import exo_update_per_ts -class Configuration: - def __init__(self, sim_config, state_dict, seed, exogenous_states, env_processes, mechanisms, behavior_ops=[foldr(dict_elemwise_sum())]): +class Configuration(object): + def __init__(self, sim_config=None, state_dict=None, seed=None, env_processes=None, + exogenous_states=None, mechanisms=None, behavior_ops=[foldr(dict_elemwise_sum())]): self.sim_config = sim_config self.state_dict = state_dict self.seed = seed - self.exogenous_states = exogenous_states self.env_processes = env_processes - self.behavior_ops = behavior_ops + self.exogenous_states = exogenous_states self.mechanisms = mechanisms + self.behavior_ops = behavior_ops + + +def append_configs(sim_configs, state_dict, seed, raw_exogenous_states, env_processes, mechanisms, _exo_update_per_ts=True): + if _exo_update_per_ts is True: + exogenous_states = exo_update_per_ts(raw_exogenous_states) + else: + exogenous_states = raw_exogenous_states + + if isinstance(sim_configs, list): + for sim_config in sim_configs: + configs.append( + Configuration( + sim_config=sim_config, + state_dict=state_dict, + seed=seed, + exogenous_states=exogenous_states, + env_processes=env_processes, + mechanisms=mechanisms + ) + ) + elif isinstance(sim_configs, dict): + configs.append( + Configuration( + sim_config=sim_configs, + state_dict=state_dict, + seed=seed, + exogenous_states=exogenous_states, + env_processes=env_processes, + mechanisms=mechanisms + ) + ) class Identity: def __init__(self, behavior_id={'identity': 0}): self.beh_id_return_val = behavior_id - def b_identity(self, step, sL, s): + def b_identity(self, var_dict, 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): + def no_state_identity(self, var_dict, step, sL, s, _input): return None def state_identity(self, k): - return lambda step, sL, s, _input: (k, s[k]) + return lambda var_dict, step, sL, s, _input: (k, s[k]) def apply_identity_funcs(self, identity, df, cols): def fillna_with_id_func(identity, df, col): diff --git a/SimCAD/configuration/utils/__init__.py b/SimCAD/configuration/utils/__init__.py index 53dad43..f5334d5 100644 --- a/SimCAD/configuration/utils/__init__.py +++ b/SimCAD/configuration/utils/__init__.py @@ -1,8 +1,11 @@ from datetime import datetime, timedelta from decimal import Decimal +from copy import deepcopy from fn.func import curried import pandas as pd +from SimCAD.utils import dict_filter, contains_type + class TensorFieldReport: def __init__(self, config_proc): @@ -17,9 +20,17 @@ class TensorFieldReport: return df +# def s_update(y, x): +# return lambda step, sL, s, _input: (y, x) +# +# +def state_update(y, x): + return lambda step, sL, s, _input: (y, x) + + def bound_norm_random(rng, low, high): - res = rng.normal((high+low)/2,(high-low)/6) - if (reshigh): + res = rng.normal((high+low)/2, (high-low)/6) + if res < low or res > high: res = bound_norm_random(rng, low, high) return Decimal(res) @@ -32,26 +43,78 @@ def proc_trigger(trigger_step, update_f, step): return lambda x: x -t_delta = timedelta(days=0, minutes=0, seconds=30) -def time_step(dt_str, dt_format='%Y-%m-%d %H:%M:%S', _timedelta = t_delta): +step_t_delta = timedelta(days=0, minutes=0, seconds=30) +def time_step(dt_str, dt_format='%Y-%m-%d %H:%M:%S', _timedelta = step_t_delta): dt = datetime.strptime(dt_str, dt_format) t = dt + _timedelta return t.strftime(dt_format) -t_delta = timedelta(days=0, minutes=0, seconds=1) -def ep_time_step(s, dt_str, fromat_str='%Y-%m-%d %H:%M:%S', _timedelta = t_delta): +ep_t_delta = timedelta(days=0, minutes=0, seconds=1) +def ep_time_step(s, dt_str, fromat_str='%Y-%m-%d %H:%M:%S', _timedelta = ep_t_delta): if s['mech_step'] == 0: return time_step(dt_str, fromat_str, _timedelta) else: return dt_str +def mech_sweep_filter(mech_field, mechanisms): + mech_dict = dict([(k, v[mech_field]) for k, v in mechanisms.items()]) + return dict([ + (k, dict_filter(v, lambda v: isinstance(v, list))) for k, v in mech_dict.items() + if contains_type(list(v.values()), list) + ]) + + +def state_sweep_filter(raw_exogenous_states): + return dict([(k, v) for k, v in raw_exogenous_states.items() if isinstance(v, list)]) + +@curried +def sweep_mechs(_type, in_config): + configs = [] + filtered_mech_states = mech_sweep_filter(_type, in_config.mechanisms) + if len(filtered_mech_states) > 0: + for mech, state_dict in filtered_mech_states.items(): + for state, state_funcs in state_dict.items(): + for f in state_funcs: + config = deepcopy(in_config) + config.mechanisms[mech][_type][state] = f + configs.append(config) + del config + else: + configs = [in_config] + + return configs + + +@curried +def sweep_states(state_type, states, in_config): + configs = [] + filtered_states = state_sweep_filter(states) + if len(filtered_states) > 0: + for state, state_funcs in filtered_states.items(): + for f in state_funcs: + config = deepcopy(in_config) + exploded_states = deepcopy(states) + exploded_states[state] = f + if state_type == 'exogenous': + config.exogenous_states = exploded_states + elif state_type == 'environmental': + config.env_processes = exploded_states + configs.append(config) + del config, exploded_states + else: + configs = [in_config] + + return configs + + def exo_update_per_ts(ep): @curried - def ep_decorator(f, y, step, sL, s, _input): + def ep_decorator(f, y, var_dict, step, sL, s, _input): if s['mech_step'] + 1 == 1: - return f(step, sL, s, _input) + return f(var_dict, step, sL, s, _input) # curry_pot else: - return (y, s[y]) + return y, s[y] + return {es: ep_decorator(f, es) for es, f in ep.items()} diff --git a/SimCAD/configuration/utils/behaviorAggregation.py b/SimCAD/configuration/utils/behaviorAggregation.py index 5f8b5f6..a16f5e1 100644 --- a/SimCAD/configuration/utils/behaviorAggregation.py +++ b/SimCAD/configuration/utils/behaviorAggregation.py @@ -2,14 +2,15 @@ from fn.op import foldr from fn.func import curried -def get_base_value(datatype): - if datatype is str: +def get_base_value(x): + if isinstance(x, str): return '' - elif datatype is int: + elif isinstance(x, int): return 0 - elif datatype is list: + elif isinstance(x, list): return [] - return 0 + else: + return 0 def behavior_to_dict(v): @@ -32,7 +33,7 @@ def sum_dict_values(): 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])) + return get_base_value(source_dict[key]) else: return target_dict[key] diff --git a/SimCAD/configuration/utils/parameterSweep.py b/SimCAD/configuration/utils/parameterSweep.py new file mode 100644 index 0000000..1260da0 --- /dev/null +++ b/SimCAD/configuration/utils/parameterSweep.py @@ -0,0 +1,19 @@ +from SimCAD.utils import flatten_tabulated_dict, tabulate_dict + + +def process_variables(d): + return flatten_tabulated_dict(tabulate_dict(d)) + + +def config_sim(d): + if "M" in d: + return [ + { + "N": d["N"], + "T": d["T"], + "M": M + } + for M in process_variables(d["M"]) + ] + else: + return d diff --git a/SimCAD/engine/__init__.py b/SimCAD/engine/__init__.py index 66a0773..5c05c1b 100644 --- a/SimCAD/engine/__init__.py +++ b/SimCAD/engine/__init__.py @@ -16,16 +16,16 @@ class ExecutionContext: self.name = context self.method = None - def single_proc_exec(simulation_execs, states_lists, configs_structs, env_processes_list, Ts, Ns): + def single_proc_exec(simulation_execs, var_dict, states_lists, configs_structs, env_processes_list, Ts, Ns): l = [simulation_execs, states_lists, configs_structs, env_processes_list, Ts, Ns] simulation, states_list, config, env_processes, T, N = list(map(lambda x: x.pop(), l)) - result = simulation(states_list, config, env_processes, T, N) + result = simulation(var_dict, states_list, config, env_processes, T, N) return flatten(result) - def parallelize_simulations(fs, states_list, configs, env_processes, Ts, Ns): - l = list(zip(fs, states_list, configs, env_processes, Ts, Ns)) + def parallelize_simulations(fs, var_dict_list, states_list, configs, env_processes, Ts, Ns): + l = list(zip(fs, var_dict_list, states_list, configs, env_processes, Ts, Ns)) with Pool(len(configs)) as p: - results = p.map(lambda t: t[0](t[1], t[2], t[3], t[4], t[5]), l) + results = p.map(lambda t: t[0](t[1], t[2], t[3], t[4], t[5], t[6]), l) return results if context == 'single_proc': @@ -47,13 +47,16 @@ class Executor: 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 = \ - [], [], [], [], [], [], [], [] + var_dict_list, states_lists, Ts, Ns, eps, configs_structs, env_processes_list, mechanisms, simulation_execs = \ + [], [], [], [], [], [], [], [], [] config_idx = 0 for x in self.configs: - states_lists.append([x.state_dict]) + Ts.append(x.sim_config['T']) Ns.append(x.sim_config['N']) + var_dict_list.append(x.sim_config['M']) + + states_lists.append([x.state_dict]) eps.append(list(x.exogenous_states.values())) configs_structs.append(config_proc.generate_config(x.state_dict, x.mechanisms, eps[config_idx])) env_processes_list.append(x.env_processes) @@ -64,11 +67,11 @@ class Executor: if self.exec_context == ExecutionMode.single_proc: tensor_field = create_tensor_field(mechanisms.pop(), eps.pop()) - result = self.exec_method(simulation_execs, states_lists, configs_structs, env_processes_list, Ts, Ns) + result = self.exec_method(simulation_execs, var_dict_list, states_lists, configs_structs, env_processes_list, Ts, Ns) return result, tensor_field elif self.exec_context == ExecutionMode.multi_proc: if len(self.configs) > 1: - simulations = self.exec_method(simulation_execs, states_lists, configs_structs, env_processes_list, Ts, Ns) + simulations = self.exec_method(simulation_execs, var_dict_list, states_lists, configs_structs, env_processes_list, Ts, Ns) results = [] for result, mechanism, ep in list(zip(simulations, mechanisms, eps)): results.append((flatten(result), create_tensor_field(mechanism, ep))) diff --git a/SimCAD/engine/simulation.py b/SimCAD/engine/simulation.py index 66f065f..759e7ce 100644 --- a/SimCAD/engine/simulation.py +++ b/SimCAD/engine/simulation.py @@ -1,5 +1,6 @@ from copy import deepcopy from fn.op import foldr, call + from SimCAD.engine.utils import engine_exception id_exception = engine_exception(KeyError, KeyError, None) @@ -11,13 +12,15 @@ class Executor: self.state_update_exception = state_update_exception self.behavior_update_exception = behavior_update_exception - def get_behavior_input(self, step, sL, s, funcs): + def get_behavior_input(self, var_dict, step, sL, s, funcs): ops = self.behavior_ops[::-1] - def get_col_results(step, sL, s, funcs): - return list(map(lambda f: f(step, sL, s), funcs)) + def get_col_results(var_dict, step, sL, s, funcs): + # return list(map(lambda f: curry_pot(f, step, sL, s), funcs)) + return list(map(lambda f: f(var_dict, step, sL, s), funcs)) - return foldr(call, get_col_results(step, sL, s, funcs))(ops) + # print(get_col_results(step, sL, s, funcs)) + return foldr(call, get_col_results(var_dict, step, sL, s, funcs))(ops) def apply_env_proc(self, env_processes, state_dict, step): for state in state_dict.keys(): @@ -28,12 +31,19 @@ class Executor: else: state_dict[state] = env_state(state_dict[state]) - def mech_step(self, m_step, sL, state_funcs, behavior_funcs, env_processes, t_step, run): + def mech_step(self, var_dict, m_step, sL, state_funcs, behavior_funcs, env_processes, t_step, run): last_in_obj = sL[-1] - _input = self.state_update_exception(self.get_behavior_input(m_step, sL, last_in_obj, behavior_funcs)) + _input = self.behavior_update_exception(self.get_behavior_input(var_dict, m_step, sL, last_in_obj, behavior_funcs)) + # print(_input) - last_in_copy = dict([self.behavior_update_exception(f(m_step, sL, last_in_obj, _input)) for f in state_funcs]) + # ToDo: add env_proc generator to `last_in_copy` iterator as wrapper function + last_in_copy = dict( + [ + # self.state_update_exception(curry_pot(f, m_step, sL, last_in_obj, _input)) for f in state_funcs + self.state_update_exception(f(var_dict, m_step, sL, last_in_obj, _input)) for f in state_funcs + ] + ) for k in last_in_obj: if k not in last_in_copy: @@ -49,7 +59,7 @@ class Executor: return sL - def mech_pipeline(self, states_list, configs, env_processes, t_step, run): + def mech_pipeline(self, var_dict, states_list, configs, env_processes, t_step, run): m_step = 0 states_list_copy = deepcopy(states_list) genesis_states = states_list_copy[-1] @@ -59,33 +69,36 @@ class Executor: m_step += 1 for config in configs: s_conf, b_conf = config[0], config[1] - states_list = self.mech_step(m_step, states_list, s_conf, b_conf, env_processes, t_step, run) + states_list = self.mech_step(var_dict, m_step, states_list, s_conf, b_conf, env_processes, t_step, run) m_step += 1 t_step += 1 return states_list - def block_pipeline(self, states_list, configs, env_processes, time_seq, run): + # ToDo: Rename Run Pipeline + def block_pipeline(self, var_dict, states_list, configs, env_processes, time_seq, run): time_seq = [x + 1 for x in time_seq] simulation_list = [states_list] for time_step in time_seq: - pipe_run = self.mech_pipeline(simulation_list[-1], configs, env_processes, time_step, run) + pipe_run = self.mech_pipeline(var_dict, simulation_list[-1], configs, env_processes, time_step, run) _, *pipe_run = pipe_run simulation_list.append(pipe_run) return simulation_list - def simulation(self, states_list, configs, env_processes, time_seq, runs): + + # ToDo: Muiltithreaded Runs + def simulation(self, var_dict, states_list, configs, env_processes, time_seq, runs): pipe_run = [] for run in range(runs): run += 1 states_list_copy = deepcopy(states_list) - head, *tail = self.block_pipeline(states_list_copy, configs, env_processes, time_seq, run) + head, *tail = self.block_pipeline(var_dict, states_list_copy, configs, env_processes, time_seq, run) genesis = head.pop() genesis['mech_step'], genesis['time_step'], genesis['run'] = 0, 0, run first_timestep_per_run = [genesis] + tail.pop(0) pipe_run += [first_timestep_per_run] + tail del states_list_copy - return pipe_run \ No newline at end of file + return pipe_run diff --git a/SimCAD/engine/utils.py b/SimCAD/engine/utils.py index bcf1507..2e569b8 100644 --- a/SimCAD/engine/utils.py +++ b/SimCAD/engine/utils.py @@ -24,6 +24,8 @@ def retrieve_state(l, offset): return l[last_index(l) + offset + 1] +# exception_function = f(m_step, sL, sL[-2], _input) +# try_function = f(m_step, sL, last_mut_obj, _input) @curried def engine_exception(ErrorType, error_message, exception_function, try_function): try: @@ -31,3 +33,10 @@ def engine_exception(ErrorType, error_message, exception_function, try_function) except ErrorType: print(error_message) return exception_function + + +@curried +def fit_param(param, x): + return x + param + +# fit_param = lambda param: lambda x: x + param diff --git a/SimCAD/utils/__init__.py b/SimCAD/utils/__init__.py index 720ab6a..495d09e 100644 --- a/SimCAD/utils/__init__.py +++ b/SimCAD/utils/__init__.py @@ -1,3 +1,7 @@ +from collections import defaultdict +from itertools import product + + def pipe(x): return x @@ -7,14 +11,118 @@ def print_pipe(x): return x +def flattenDict(l): + def tupalize(k, vs): + l = [] + if isinstance(vs, list): + for v in vs: + l.append((k, v)) + else: + l.append((k, vs)) + return l + + flat_list = [tupalize(k, vs) for k, vs in l.items()] + flat_dict = [dict(items) for items in product(*flat_list)] + return flat_dict + + def flatten(l): - return [item for sublist in l for item in sublist] + if isinstance(l, list): + return [item for sublist in l for item in sublist] + elif isinstance(l, dict): + return flattenDict(l) + + +def flatMap(f, collection): + return flatten(list(map(f, collection))) + + +def dict_filter(dictionary, condition): + return dict([(k, v) for k, v in dictionary.items() if condition(v)]) + + +def get_max_dict_val_len(g): + return len(max(g.values(), key=len)) + + +def tabulate_dict(d): + max_len = get_max_dict_val_len(d) + _d = {} + for k, vl in d.items(): + if len(vl) != max_len: + _d[k] = vl + list([vl[-1]] * (max_len-1)) + else: + _d[k] = vl + + return _d + + +def flatten_tabulated_dict(d): + max_len = get_max_dict_val_len(d) + dl = [{} for i in range(max_len)] + + for k, vl in d.items(): + for v, i in zip(vl, list(range(len(vl)))): + dl[i][k] = v + + return dl + + +def contains_type(_collection, type): + return any(isinstance(x, type) for x in _collection) + + +def drop_right(l, n): + return l[:len(l) - n] def key_filter(l, keyname): return [v[keyname] for k, v in l.items()] +def groupByKey(l): + d = defaultdict(list) + for key, value in l: + d[key].append(value) + return list(dict(d).items()).pop() + + +# @curried def rename(new_name, f): f.__name__ = new_name return f + + +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 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/Simulation.md b/Simulation.md index 4e04f54..a6e1347 100644 --- a/Simulation.md +++ b/Simulation.md @@ -1,4 +1,4 @@ -# SimmCAD Documentation +# SimCAD Documentation ## Introduction diff --git a/notebooks/jjodesty/multithreading.ipynb b/notebooks/jjodesty/multithreading.ipynb new file mode 100644 index 0000000..c3a41ad --- /dev/null +++ b/notebooks/jjodesty/multithreading.ipynb @@ -0,0 +1,576 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "import _thread\n", + "import time\n", + "from fn.func import curried" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Define a function for the thread\n", + "def f(threadName, delay):\n", + " count = 0\n", + " print(count)\n", + " # while count < 5:\n", + " # time.sleep(delay)\n", + " # count += 1\n", + " # print(count)\n", + " \n", + "def pipe(x):\n", + " print(x)\n", + " return x" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "00\n", + "\n" + ] + } + ], + "source": [ + "# Create two threads as follows\n", + "try:\n", + " _thread.start_new_thread( f, (\"Thread-1\", 2, ) )\n", + " _thread.start_new_thread( f, (\"Thread-2\", 4, ) )\n", + "except:\n", + " print (\"Error: unable to start thread\")\n", + "\n", + "while 1:\n", + " pass\n" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[1, 2]\n", + "('s2', . at 0x1099efae8>)\n", + "('s2', . at 0x1099ef9d8>)\n" + ] + } + ], + "source": [ + "from SimCAD.engine.utils import sweep\n", + "from SimCAD.utils import rename\n", + "from SimCAD.configuration.utils import s_update\n", + "\n", + "# @curried\n", + "def fit_param(param):\n", + " return lambda x: x + param\n", + "\n", + "# xf = lambda param: lambda x: x + param\n", + "\n", + "def sweep(params, y, xf):\n", + " op = [rename('sweep', s_update(y, xf(param))) for param in params]\n", + " print(params)\n", + " # print()\n", + " return op\n", + "\n", + "for f in sweep([1,2], 's2', fit_param):\n", + " print(f(1,2,3,4))\n", + "# sweep([1,2], 's2', xf)" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[1, 64, 2187, 65536]\n" + ] + } + ], + "source": [ + "# instantiate and configure the worker pool\n", + "from pathos.threading import ThreadPool\n", + "pool = ThreadPool(nodes=4)\n", + "\n", + "# do a blocking map on the chosen function\n", + "print(pool.map(pow, [1,2,3,4], [5,6,7,8]))" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "ename": "SyntaxError", + "evalue": "invalid syntax (, line 3)", + "traceback": [ + "\u001b[0;36m File \u001b[0;32m\"\"\u001b[0;36m, line \u001b[0;32m3\u001b[0m\n\u001b[0;31m [for f in fs]\u001b[0m\n\u001b[0m ^\u001b[0m\n\u001b[0;31mSyntaxError\u001b[0m\u001b[0;31m:\u001b[0m invalid syntax\n" + ], + "output_type": "error" + } + ], + "source": [ + "with Pool(len(configs)) as p:\n", + " results = p.map(lambda t: t[0](t[1], t[2], t[3], t[4], t[5]), l)\n", + " \n", + "\n", + "def state_multithreading(self, fs, m_step, sL, last_in_obj, _input):\n", + " if type(fs) == 'list':\n", + " pool.map(f(m_step, sL, last_in_obj, _input), fs)\n", + " else:\n", + " f(m_step, sL, last_in_obj, _input)" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[('s2', [11, 23])]" + ] + }, + "execution_count": 12, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "from itertools import groupby\n", + "l = [('s2', 11), ('s2', 23)]\n", + "l.sort(key = lambda i : i[0])\n", + "[(key, [i[1] for i in values]) for key, values in groupby(l, lambda i: i[0])]" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "metadata": {}, + "outputs": [], + "source": [ + "def groupByKV(l):\n", + " l.sort(key = lambda i : i[0])\n", + " return [(key, [i[1] for i in values]) for key, values in groupby(l, lambda i: i[0])]" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[('s2', [11, 23])]" + ] + }, + "execution_count": 18, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "groupByKV(l)" + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "metadata": {}, + "outputs": [ + { + "ename": "SyntaxError", + "evalue": "invalid syntax (, line 2)", + "traceback": [ + "\u001b[0;36m File \u001b[0;32m\"\"\u001b[0;36m, line \u001b[0;32m2\u001b[0m\n\u001b[0;31m collect = lambda tuplist: reduce(lambda acc, (k,v): acc[k].append(v) or acc,tuplist, defaultdict(list))\u001b[0m\n\u001b[0m ^\u001b[0m\n\u001b[0;31mSyntaxError\u001b[0m\u001b[0;31m:\u001b[0m invalid syntax\n" + ], + "output_type": "error" + } + ], + "source": [ + "from collections import defaultdict \n", + "collect = lambda tuplist: reduce(lambda acc, (k,v): acc[k].append(v) or acc,tuplist, defaultdict(list))" + ] + }, + { + "cell_type": "code", + "execution_count": 23, + "metadata": {}, + "outputs": [], + "source": [ + "from collections import defaultdict\n", + "d = defaultdict(list)\n", + "for key, value in [('s2', 11), ('s2', 23)]:\n", + " d[key].append(value)" + ] + }, + { + "cell_type": "code", + "execution_count": 25, + "metadata": { + "collapsed": true + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Help on defaultdict object:\n", + "\n", + "class defaultdict(builtins.dict)\n", + " | defaultdict(default_factory[, ...]) --> dict with default factory\n", + " | \n", + " | The default factory is called without arguments to produce\n", + " | a new value when a key is not present, in __getitem__ only.\n", + " | A defaultdict compares equal to a dict with the same items.\n", + " | All remaining arguments are treated the same as if they were\n", + " | passed to the dict constructor, including keyword arguments.\n", + " | \n", + " | Method resolution order:\n", + " | defaultdict\n", + " | builtins.dict\n", + " | builtins.object\n", + " | \n", + " | Methods defined here:\n", + " | \n", + " | __copy__(...)\n", + " | D.copy() -> a shallow copy of D.\n", + " | \n", + " | __getattribute__(self, name, /)\n", + " | Return getattr(self, name).\n", + " | \n", + " | __init__(self, /, *args, **kwargs)\n", + " | Initialize self. See help(type(self)) for accurate signature.\n", + " | \n", + " | __missing__(...)\n", + " | __missing__(key) # Called by __getitem__ for missing key; pseudo-code:\n", + " | if self.default_factory is None: raise KeyError((key,))\n", + " | self[key] = value = self.default_factory()\n", + " | return value\n", + " | \n", + " | __reduce__(...)\n", + " | Return state information for pickling.\n", + " | \n", + " | __repr__(self, /)\n", + " | Return repr(self).\n", + " | \n", + " | copy(...)\n", + " | D.copy() -> a shallow copy of D.\n", + " | \n", + " | ----------------------------------------------------------------------\n", + " | Data descriptors defined here:\n", + " | \n", + " | default_factory\n", + " | Factory for default value called by __missing__().\n", + " | \n", + " | ----------------------------------------------------------------------\n", + " | Methods inherited from builtins.dict:\n", + " | \n", + " | __contains__(self, key, /)\n", + " | True if D has a key k, else False.\n", + " | \n", + " | __delitem__(self, key, /)\n", + " | Delete self[key].\n", + " | \n", + " | __eq__(self, value, /)\n", + " | Return self==value.\n", + " | \n", + " | __ge__(self, value, /)\n", + " | Return self>=value.\n", + " | \n", + " | __getitem__(...)\n", + " | x.__getitem__(y) <==> x[y]\n", + " | \n", + " | __gt__(self, value, /)\n", + " | Return self>value.\n", + " | \n", + " | __iter__(self, /)\n", + " | Implement iter(self).\n", + " | \n", + " | __le__(self, value, /)\n", + " | Return self<=value.\n", + " | \n", + " | __len__(self, /)\n", + " | Return len(self).\n", + " | \n", + " | __lt__(self, value, /)\n", + " | Return self size of D in memory, in bytes\n", + " | \n", + " | clear(...)\n", + " | D.clear() -> None. Remove all items from D.\n", + " | \n", + " | fromkeys(iterable, value=None, /) from builtins.type\n", + " | Returns a new dict with keys from iterable and values equal to value.\n", + " | \n", + " | get(...)\n", + " | D.get(k[,d]) -> D[k] if k in D, else d. d defaults to None.\n", + " | \n", + " | items(...)\n", + " | D.items() -> a set-like object providing a view on D's items\n", + " | \n", + " | keys(...)\n", + " | D.keys() -> a set-like object providing a view on D's keys\n", + " | \n", + " | pop(...)\n", + " | D.pop(k[,d]) -> v, remove specified key and return the corresponding value.\n", + " | If key is not found, d is returned if given, otherwise KeyError is raised\n", + " | \n", + " | popitem(...)\n", + " | D.popitem() -> (k, v), remove and return some (key, value) pair as a\n", + " | 2-tuple; but raise KeyError if D is empty.\n", + " | \n", + " | setdefault(...)\n", + " | D.setdefault(k[,d]) -> D.get(k,d), also set D[k]=d if k not in D\n", + " | \n", + " | update(...)\n", + " | D.update([E, ]**F) -> None. Update D from dict/iterable E and F.\n", + " | If E is present and has a .keys() method, then does: for k in E: D[k] = E[k]\n", + " | If E is present and lacks a .keys() method, then does: for k, v in E: D[k] = v\n", + " | In either case, this is followed by: for k in F: D[k] = F[k]\n", + " | \n", + " | values(...)\n", + " | D.values() -> an object providing a view on D's values\n", + " | \n", + " | ----------------------------------------------------------------------\n", + " | Data and other attributes inherited from builtins.dict:\n", + " | \n", + " | __hash__ = None\n", + "\n" + ] + } + ], + "source": [ + "help(d)" + ] + }, + { + "cell_type": "code", + "execution_count": 27, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{'s2': [11, 23]}" + ] + }, + "execution_count": 27, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "dict(d)" + ] + }, + { + "cell_type": "code", + "execution_count": 55, + "metadata": {}, + "outputs": [], + "source": [ + "def groupByKey(l):\n", + " d = defaultdict(list)\n", + " for key, value in l:\n", + " d[key].append(value)\n", + " return list(dict(d).items()).pop()" + ] + }, + { + "cell_type": "code", + "execution_count": 56, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "('s2', [11, 23])" + ] + }, + "execution_count": 56, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "r = groupByKey([('s2', 11), ('s2', 23)])\n", + "r" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# xf = lambda param: 1.0 + param\n", + "# def xf(y, param, s):\n", + "# return s[y] + param\n", + "\n", + "# def fit_param(param):\n", + "# y = 's2'\n", + "# x = 1 + param\n", + "# return lambda step, sL, s, _input: (y, x)\n", + "#\n", + "# def fit_param(param):\n", + "# return lambda step, sL, s, _input: (\n", + "# 's2',\n", + "# s['s2'] + param\n", + "# )\n", + "#\n", + "# s2m1 = sweep(\n", + "# params = [Decimal(11.0), Decimal(22.0)],\n", + "# sweep_f = fit_param\n", + "# )" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": {}, + "outputs": [], + "source": [ + "from decimal import Decimal\n", + "from itertools import product\n", + "\n", + "# def \n", + "\n", + "l = {\n", + " 's1': 1, \n", + " 's2': [Decimal('11'), Decimal('22')], \n", + " 's3': [Decimal('12'), Decimal('23')], \n", + " 's4': 10, \n", + " 'timestamp': '2018-10-01 15:16:25', \n", + " 'mech_step': 0, \n", + " 'time_step': 1\n", + "}\n", + "\n", + "def flattenDict(l):\n", + " def tupalize(k, vs):\n", + " l = []\n", + " if isinstance(vs, list):\n", + " for v in vs:\n", + " l.append((k, v))\n", + " else:\n", + " l.append((k, vs))\n", + " return l\n", + "\n", + " flat_list = [tupalize(k, vs) for k, vs in l.items()]\n", + " flat_dict = [dict(items) for items in product(*flat_list)]\n", + " return flat_dict" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[{'s1': 1,\n", + " 's2': Decimal('11'),\n", + " 's3': Decimal('12'),\n", + " 's4': 10,\n", + " 'timestamp': '2018-10-01 15:16:25',\n", + " 'mech_step': 0,\n", + " 'time_step': 1},\n", + " {'s1': 1,\n", + " 's2': Decimal('11'),\n", + " 's3': Decimal('23'),\n", + " 's4': 10,\n", + " 'timestamp': '2018-10-01 15:16:25',\n", + " 'mech_step': 0,\n", + " 'time_step': 1},\n", + " {'s1': 1,\n", + " 's2': Decimal('22'),\n", + " 's3': Decimal('12'),\n", + " 's4': 10,\n", + " 'timestamp': '2018-10-01 15:16:25',\n", + " 'mech_step': 0,\n", + " 'time_step': 1},\n", + " {'s1': 1,\n", + " 's2': Decimal('22'),\n", + " 's3': Decimal('23'),\n", + " 's4': 10,\n", + " 'timestamp': '2018-10-01 15:16:25',\n", + " 'mech_step': 0,\n", + " 'time_step': 1}]" + ] + }, + "execution_count": 15, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "flattenDict(l)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.5" + } + }, + "nbformat": 4, + "nbformat_minor": 1 +} diff --git a/requirements.txt b/requirements.txt index 47937eb..0418284 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,5 @@ wheel +pandas pathos fn tabulate \ No newline at end of file diff --git a/simulations/example_run.py b/simulations/example_run.py index e50cddd..cf2bba9 100644 --- a/simulations/example_run.py +++ b/simulations/example_run.py @@ -1,29 +1,27 @@ import pandas as pd from tabulate import tabulate - # The following imports NEED to be in the exact order from SimCAD.engine import ExecutionMode, ExecutionContext, Executor -from simulations.validation import config1, config2 +from simulations.validation import sweep_config 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") -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(): diff --git a/simulations/validation/base_config1.py b/simulations/validation/base_config1.py deleted file mode 100644 index 3bf83ba..0000000 --- a/simulations/validation/base_config1.py +++ /dev/null @@ -1,171 +0,0 @@ -from decimal import Decimal -import numpy as np -from datetime import timedelta - -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 - -seed = { - 'z': np.random.RandomState(1), - 'a': np.random.RandomState(2), - 'b': np.random.RandomState(3), - 'c': np.random.RandomState(3) -} - -# Behaviors per Mechanism -# Different return types per mechanism ?? *** No *** -def b1m1(step, sL, s): - return {'param1': 1} -def b2m1(step, sL, s): - return {'param1': 1} - -def b1m2(step, sL, s): - return {'param1': 1, 'param2': 2} -def b2m2(step, sL, s): - return {'param1': 1, 'param2': 4} - -def b1m3(step, sL, s): - return {'param1': 1, 'param2': np.array([10, 100])} -def b2m3(step, sL, s): - return {'param1': 1, 'param2': np.array([20, 200])} - -# deff not more than 2 -# Internal States per Mechanism -def s1m1(step, sL, s, _input): - y = 's1' - x = s['s1'] + _input['param1'] - return (y, x) -def s2m1(step, sL, s, _input): - y = 's2' - x = s['s2'] + _input['param1'] - return (y, x) - -def s1m2(step, sL, s, _input): - y = 's1' - x = s['s1'] + _input['param1'] - return (y, x) -def s2m2(step, sL, s, _input): - y = 's2' - x = s['s2'] + _input['param1'] - return (y, x) - -def s1m3(step, sL, s, _input): - y = 's1' - x = s['s1'] + _input['param1'] - return (y, x) -def s2m3(step, sL, s, _input): - y = 's2' - x = s['s2'] + _input['param1'] - return (y, x) - -# Exogenous States -proc_one_coef_A = 0.7 -proc_one_coef_B = 1.3 - -def es3p1(step, sL, s, _input): - y = 's3' - x = s['s3'] * bound_norm_random(seed['a'], proc_one_coef_A, proc_one_coef_B) - return (y, x) - -def es4p2(step, sL, s, _input): - y = 's4' - x = s['s4'] * bound_norm_random(seed['b'], proc_one_coef_A, proc_one_coef_B) - return (y, x) - -ts_format = '%Y-%m-%d %H:%M:%S' -t_delta = timedelta(days=0, minutes=0, seconds=1) -def es5p2(step, sL, s, _input): - y = 'timestamp' - x = ep_time_step(s, dt_str=s['timestamp'], fromat_str=ts_format, _timedelta=t_delta) - return (y, x) - - -# Environment States -def env_a(x): - return 10 -def env_b(x): - return 10 -# def what_ever(x): -# return x + 1 - -# Genesis States -genesis_states = { - 's1': Decimal(0.0), - 's2': Decimal(0.0), - 's3': Decimal(1.0), - 's4': Decimal(1.0), - 'timestamp': '2018-10-01 15:16:24' -} - -# remove `exo_update_per_ts` to update every ts -exogenous_states = exo_update_per_ts( - { - "s3": es3p1, - "s4": es4p2, - "timestamp": es5p2 - } -) - -# make env proc trigger field agnostic - -# ToDo: Bug - Can't use environments without proc_trigger. TypeError: 'int' object is not callable -# "/Users/jjodesty/Projects/DiffyQ-SimCAD/SimCAD/engine/simulation.py" -env_processes = { - # "s3": env_a, - # "s4": env_b - "s3": proc_trigger('2018-10-01 15:16:25', env_a), - "s4": proc_trigger('2018-10-01 15:16:25', env_b) -} - -# need at least 1 behaviour and 1 state function for the 1st mech with behaviors -# mechanisms = {} -mechanisms = { - "m1": { - "behaviors": { - "b1": b1m1, # lambda step, sL, s: s['s1'] + 1, - "b2": b2m1 - }, - "states": { # exclude only. TypeError: reduce() of empty sequence with no initial value - "s1": s1m1, - "s2": s2m1 - } - }, - "m2": { - "behaviors": { - "b1": b1m2, - "b2": b2m2 - }, - "states": { - "s1": s1m2, - "s2": s2m2 - } - }, - "m3": { - "behaviors": { - "b1": b1m3, - "b2": b2m3 - }, - "states": { - "s1": s1m3, - "s2": s2m3 - } - } -} - -sim_config = { - "N": 2, - "T": range(5) -} - -configs.append( - Configuration( - sim_config=sim_config, - state_dict=genesis_states, - seed=seed, - exogenous_states=exogenous_states, - env_processes=env_processes, - mechanisms=mechanisms - ) -) \ No newline at end of file diff --git a/simulations/validation/base_config2.py b/simulations/validation/base_config2.py deleted file mode 100644 index 6b9469e..0000000 --- a/simulations/validation/base_config2.py +++ /dev/null @@ -1,180 +0,0 @@ -from decimal import Decimal -import numpy as np -from datetime import timedelta - -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 - - -seed = { - 'z': np.random.RandomState(1), - 'a': np.random.RandomState(2), - 'b': np.random.RandomState(3), - 'c': np.random.RandomState(3) -} - -# Behaviors per Mechanism -# Different return types per mechanism ?? *** No *** -def b1m1(step, sL, s): - return {'param1': 1} -def b2m1(step, sL, s): - return {'param2': 4} - -def b1m2(step, sL, s): - return {'param1': 'a', 'param2': 2} -def b2m2(step, sL, s): - return {'param1': 'b', 'param2': 4} - - -def b1m3(step, sL, s): - return {'param1': ['c'], 'param2': np.array([10, 100])} -def b2m3(step, sL, s): - return {'param1': ['d'], 'param2': np.array([20, 200])} - - -# Internal States per Mechanism -def s1m1(step, sL, s, _input): - y = 's1' - x = _input['param1'] - return (y, x) -def s2m1(step, sL, s, _input): - y = 's2' - x = _input['param2'] - return (y, x) - -def s1m2(step, sL, s, _input): - y = 's1' - x = _input['param1'] - return (y, x) -def s2m2(step, sL, s, _input): - y = 's2' - x = _input['param2'] - return (y, x) - -def s1m3(step, sL, s, _input): - y = 's1' - x = _input['param1'] - return (y, x) -def s2m3(step, sL, s, _input): - y = 's2' - x = _input['param2'] - return (y, x) - -# Exogenous States -proc_one_coef_A = 0.7 -proc_one_coef_B = 1.3 - -def es3p1(step, sL, s, _input): - y = 's3' - x = s['s3'] * bound_norm_random(seed['a'], proc_one_coef_A, proc_one_coef_B) - return (y, x) - -def es4p2(step, sL, s, _input): - y = 's4' - x = s['s4'] * bound_norm_random(seed['b'], proc_one_coef_A, proc_one_coef_B) - return (y, x) - -ts_format = '%Y-%m-%d %H:%M:%S' -t_delta = timedelta(days=0, minutes=0, seconds=1) -def es5p2(step, sL, s, _input): - y = 'timestamp' - x = ep_time_step(s, dt_str=s['timestamp'], fromat_str=ts_format, _timedelta=t_delta) - return (y, x) - - -# Environment States -def env_a(x): - return 10 -def env_b(x): - return 10 -# def what_ever(x): -# return x + 1 - -# Genesis States -genesis_states = { - 's1': Decimal(0.0), - 's2': Decimal(0.0), - 's3': Decimal(1.0), - 's4': Decimal(1.0), - 'timestamp': '2018-10-01 15:16:24' -} - -# remove `exo_update_per_ts` to update every ts -# why `exo_update_per_ts` here instead of `env_processes` -exogenous_states = exo_update_per_ts( - { - "s3": es3p1, - "s4": es4p2, - "timestamp": es5p2 - } -) - -# make env proc trigger field agnostic -env_processes = { - "s3": proc_trigger('2018-10-01 15:16:25', env_a), - "s4": proc_trigger('2018-10-01 15:16:25', env_b) -} - -# lambdas -# genesis Sites should always be there -# [1, 2] -# behavior_ops = [ foldr(_ + _), lambda x: x + 0 ] - - -# [1, 2] = {'b1': ['a'], 'b2', [1]} = -# behavior_ops = [behavior_to_dict, print_fwd, sum_dict_values] -# behavior_ops = [foldr(dict_elemwise_sum())] -# behavior_ops = [] - -# need at least 1 behaviour and 1 state function for the 1st mech with behaviors -# mechanisms = {} -mechanisms = { - "m1": { - "behaviors": { - "b1": b1m1, # lambda step, sL, s: s['s1'] + 1, - # "b2": b2m1 - }, - "states": { # exclude only. TypeError: reduce() of empty sequence with no initial value - "s1": s1m1, - # "s2": s2m1 - } - }, - "m2": { - "behaviors": { - "b1": b1m2, - # "b2": b2m2 - }, - "states": { - "s1": s1m2, - # "s2": s2m2 - } - }, - "m3": { - "behaviors": { - "b1": b1m3, - "b2": b2m3 - }, - "states": { - "s1": s1m3, - "s2": s2m3 - } - } -} - -sim_config = { - "N": 2, - "T": range(5) -} - -configs.append( - Configuration( - sim_config=sim_config, - state_dict=genesis_states, - seed=seed, - exogenous_states=exogenous_states, - env_processes=env_processes, - mechanisms=mechanisms - ) -) \ No newline at end of file diff --git a/simulations/validation/config_1.py b/simulations/validation/config_1.py deleted file mode 100644 index 7bdd5ac..0000000 --- a/simulations/validation/config_1.py +++ /dev/null @@ -1,178 +0,0 @@ -from decimal import Decimal -import numpy as np -from datetime import timedelta - -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 - -seed = { - 'z': np.random.RandomState(1), - 'a': np.random.RandomState(2), - 'b': np.random.RandomState(3), - 'c': np.random.RandomState(3) -} - -# Behaviors per Mechanism -# Different return types per mechanism ?? *** No *** -def b1m1(step, sL, s): - return {'param1': 1} -def b2m1(step, sL, s): - return {'param2': 4} - -def b1m2(step, sL, s): - return {'param1': 'a', 'param2': 2} -def b2m2(step, sL, s): - return {'param1': 'b', 'param2': 4} - -def b1m3(step, sL, s): - return {'param1': ['c'], 'param2': np.array([10, 100])} -def b2m3(step, sL, s): - return {'param1': ['d'], 'param2': np.array([20, 200])} - -# deff not more than 2 -# Internal States per Mechanism -def s1m1(step, sL, s, _input): - y = 's1' - x = _input['param1'] #+ [Coef1 x 5] - return (y, x) -def s2m1(step, sL, s, _input): - y = 's2' - x = _input['param2'] #+ [Coef2 x 5] - return (y, x) - -def s1m2(step, sL, s, _input): - y = 's1' - x = _input['param1'] - return (y, x) -def s2m2(step, sL, s, _input): - y = 's2' - x = _input['param2'] - return (y, x) - -def s1m3(step, sL, s, _input): - y = 's1' - x = _input['param1'] - return (y, x) -def s2m3(step, sL, s, _input): - y = 's2' - x = _input['param2'] - return (y, x) - -# Exogenous States -proc_one_coef_A = 0.7 -proc_one_coef_B = 1.3 - -def es3p1(step, sL, s, _input): - y = 's3' - x = s['s3'] * bound_norm_random(seed['a'], proc_one_coef_A, proc_one_coef_B) - return (y, x) - -def es4p2(step, sL, s, _input): - y = 's4' - x = s['s4'] * bound_norm_random(seed['b'], proc_one_coef_A, proc_one_coef_B) - return (y, x) - -ts_format = '%Y-%m-%d %H:%M:%S' -t_delta = timedelta(days=0, minutes=0, seconds=1) -def es5p2(step, sL, s, _input): - y = 'timestamp' - x = ep_time_step(s, dt_str=s['timestamp'], fromat_str=ts_format, _timedelta=t_delta) - return (y, x) - - -# Environment States -def env_a(x): - return 5 -def env_b(x): - return 10 -# def what_ever(x): -# return x + 1 - -# Genesis States -genesis_states = { - 's1': Decimal(0.0), - 's2': Decimal(0.0), - 's3': Decimal(1.0), - 's4': Decimal(1.0), - 'timestamp': '2018-10-01 15:16:24' -} - -# remove `exo_update_per_ts` to update every ts -exogenous_states = exo_update_per_ts( - { - "s3": es3p1, - "s4": es4p2, - "timestamp": es5p2 - } -) - -# ToDo: make env proc trigger field agnostic -# ToDo: input json into function renaming __name__ -env_processes = { - "s3": env_a, - "s4": proc_trigger('2018-10-01 15:16:25', env_b) -} - -# lambdas -# genesis Sites should always be there -# [1, 2] -# behavior_ops = [ foldr(_ + _), lambda x: x + 0 ] - -# [1, 2] = {'b1': ['a'], 'b2', [1]} = -# behavior_ops = [ behavior_to_dict, print_fwd, sum_dict_values ] -# behavior_ops = [foldr(dict_elemwise_sum())] -# behavior_ops = [foldr(lambda a, b: a + b)] - -# need at least 1 behaviour and 1 state function for the 1st mech with behaviors -# mechanisms = {} - -mechanisms = { - "m1": { - "behaviors": { - "b1": b1m1, # lambda step, sL, s: s['s1'] + 1, - "b2": b2m1 - }, - "states": { # exclude only. TypeError: reduce() of empty sequence with no initial value - "s1": s1m1, - "s2": s2m1 - } - }, - "m2": { - "behaviors": { - "b1": b1m2, - "b2": b2m2 - }, - "states": { - "s1": s1m2, - "s2": s2m2 - } - }, - "m3": { - "behaviors": { - "b1": b1m3, - "b2": b2m3 - }, - "states": { - "s1": s1m3, - "s2": s2m3 - } - } -} - -sim_config = { - "N": 2, - "T": range(5) -} - -configs.append( - Configuration( - sim_config=sim_config, - state_dict=genesis_states, - seed=seed, - exogenous_states=exogenous_states, - env_processes=env_processes, - mechanisms=mechanisms - ) -) \ No newline at end of file diff --git a/simulations/validation/config_2.py b/simulations/validation/config_2.py deleted file mode 100644 index 6b9469e..0000000 --- a/simulations/validation/config_2.py +++ /dev/null @@ -1,180 +0,0 @@ -from decimal import Decimal -import numpy as np -from datetime import timedelta - -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 - - -seed = { - 'z': np.random.RandomState(1), - 'a': np.random.RandomState(2), - 'b': np.random.RandomState(3), - 'c': np.random.RandomState(3) -} - -# Behaviors per Mechanism -# Different return types per mechanism ?? *** No *** -def b1m1(step, sL, s): - return {'param1': 1} -def b2m1(step, sL, s): - return {'param2': 4} - -def b1m2(step, sL, s): - return {'param1': 'a', 'param2': 2} -def b2m2(step, sL, s): - return {'param1': 'b', 'param2': 4} - - -def b1m3(step, sL, s): - return {'param1': ['c'], 'param2': np.array([10, 100])} -def b2m3(step, sL, s): - return {'param1': ['d'], 'param2': np.array([20, 200])} - - -# Internal States per Mechanism -def s1m1(step, sL, s, _input): - y = 's1' - x = _input['param1'] - return (y, x) -def s2m1(step, sL, s, _input): - y = 's2' - x = _input['param2'] - return (y, x) - -def s1m2(step, sL, s, _input): - y = 's1' - x = _input['param1'] - return (y, x) -def s2m2(step, sL, s, _input): - y = 's2' - x = _input['param2'] - return (y, x) - -def s1m3(step, sL, s, _input): - y = 's1' - x = _input['param1'] - return (y, x) -def s2m3(step, sL, s, _input): - y = 's2' - x = _input['param2'] - return (y, x) - -# Exogenous States -proc_one_coef_A = 0.7 -proc_one_coef_B = 1.3 - -def es3p1(step, sL, s, _input): - y = 's3' - x = s['s3'] * bound_norm_random(seed['a'], proc_one_coef_A, proc_one_coef_B) - return (y, x) - -def es4p2(step, sL, s, _input): - y = 's4' - x = s['s4'] * bound_norm_random(seed['b'], proc_one_coef_A, proc_one_coef_B) - return (y, x) - -ts_format = '%Y-%m-%d %H:%M:%S' -t_delta = timedelta(days=0, minutes=0, seconds=1) -def es5p2(step, sL, s, _input): - y = 'timestamp' - x = ep_time_step(s, dt_str=s['timestamp'], fromat_str=ts_format, _timedelta=t_delta) - return (y, x) - - -# Environment States -def env_a(x): - return 10 -def env_b(x): - return 10 -# def what_ever(x): -# return x + 1 - -# Genesis States -genesis_states = { - 's1': Decimal(0.0), - 's2': Decimal(0.0), - 's3': Decimal(1.0), - 's4': Decimal(1.0), - 'timestamp': '2018-10-01 15:16:24' -} - -# remove `exo_update_per_ts` to update every ts -# why `exo_update_per_ts` here instead of `env_processes` -exogenous_states = exo_update_per_ts( - { - "s3": es3p1, - "s4": es4p2, - "timestamp": es5p2 - } -) - -# make env proc trigger field agnostic -env_processes = { - "s3": proc_trigger('2018-10-01 15:16:25', env_a), - "s4": proc_trigger('2018-10-01 15:16:25', env_b) -} - -# lambdas -# genesis Sites should always be there -# [1, 2] -# behavior_ops = [ foldr(_ + _), lambda x: x + 0 ] - - -# [1, 2] = {'b1': ['a'], 'b2', [1]} = -# behavior_ops = [behavior_to_dict, print_fwd, sum_dict_values] -# behavior_ops = [foldr(dict_elemwise_sum())] -# behavior_ops = [] - -# need at least 1 behaviour and 1 state function for the 1st mech with behaviors -# mechanisms = {} -mechanisms = { - "m1": { - "behaviors": { - "b1": b1m1, # lambda step, sL, s: s['s1'] + 1, - # "b2": b2m1 - }, - "states": { # exclude only. TypeError: reduce() of empty sequence with no initial value - "s1": s1m1, - # "s2": s2m1 - } - }, - "m2": { - "behaviors": { - "b1": b1m2, - # "b2": b2m2 - }, - "states": { - "s1": s1m2, - # "s2": s2m2 - } - }, - "m3": { - "behaviors": { - "b1": b1m3, - "b2": b2m3 - }, - "states": { - "s1": s1m3, - "s2": s2m3 - } - } -} - -sim_config = { - "N": 2, - "T": range(5) -} - -configs.append( - Configuration( - sim_config=sim_config, - state_dict=genesis_states, - seed=seed, - exogenous_states=exogenous_states, - env_processes=env_processes, - mechanisms=mechanisms - ) -) \ No newline at end of file diff --git a/simulations/validation/sweep_config.py b/simulations/validation/sweep_config.py new file mode 100644 index 0000000..e2d1880 --- /dev/null +++ b/simulations/validation/sweep_config.py @@ -0,0 +1,196 @@ +from decimal import Decimal +import numpy as np +from datetime import timedelta +import pprint + +from SimCAD.configuration import append_configs +from SimCAD.configuration.utils import proc_trigger, ep_time_step +from SimCAD.configuration.utils.parameterSweep import config_sim + +pp = pprint.PrettyPrinter(indent=4) + +seed = { + 'z': np.random.RandomState(1), + 'a': np.random.RandomState(2), + 'b': np.random.RandomState(3), + 'c': np.random.RandomState(3) +} + + +g = { + 'alpha': [1], + 'beta': [2, 5], + 'gamma': [3, 4], + 'omega': [7] +} + +# Behaviors per Mechanism +def b1m1(_g, step, sL, s): + return {'param1': 1} + +def b2m1(_g, step, sL, s): + return {'param2': 4} + +def b1m2(_g, step, sL, s): + return {'param1': 'a', 'param2': _g['beta']} + +def b2m2(_g, step, sL, s): + return {'param1': 'b', 'param2': 0} + +def b1m3(_g, step, sL, s): + return {'param1': np.array([10, 100])} + +def b2m3(_g, step, sL, s): + return {'param1': np.array([20, 200])} + +# Internal States per Mechanism +def s1m1(_g, step, sL, s, _input): + y = 's1' + x = 0 + return (y, x) + +def s2m1(_g, step, sL, s, _input): + y = 's2' + x = _g['beta'] + return (y, x) + +def s1m2(_g, step, sL, s, _input): + y = 's1' + x = _input['param2'] + return (y, x) + +def s2m2(_g, step, sL, s, _input): + y = 's2' + x = _input['param2'] + return (y, x) + +def s1m3(_g, step, sL, s, _input): + y = 's1' + x = 0 + return (y, x) + +def s2m3(_g, step, sL, s, _input): + y = 's2' + x = 0 + return (y, x) + + +# Exogenous States +proc_one_coef_A = 0.7 +proc_one_coef_B = 1.3 + + +def es3p1(_g, step, sL, s, _input): + y = 's3' + x = _g['gamma'] + return (y, x) +# @curried +def es4p2(_g, step, sL, s, _input): + y = 's4' + x = _g['gamma'] + return (y, x) + +ts_format = '%Y-%m-%d %H:%M:%S' +t_delta = timedelta(days=0, minutes=0, seconds=1) +def es5p2(_g, step, sL, s, _input): + y = 'timestamp' + x = ep_time_step(s, dt_str=s['timestamp'], fromat_str=ts_format, _timedelta=t_delta) + return (y, x) + + +# Environment States +# @curried +# def env_a(param, x): +# return x + param +def env_a(x): + return x +def env_b(x): + return 10 + + +# Genesis States +genesis_states = { + 's1': Decimal(0.0), + 's2': Decimal(0.0), + 's3': Decimal(1.0), + 's4': Decimal(1.0), + 'timestamp': '2018-10-01 15:16:24' +} + + +# remove `exo_update_per_ts` to update every ts +raw_exogenous_states = { + "s3": es3p1, + "s4": es4p2, + "timestamp": es5p2 +} + + +# ToDo: make env proc trigger field agnostic +# ToDo: input json into function renaming __name__ +triggered_env_b = proc_trigger('2018-10-01 15:16:25', env_b) +env_processes = { + "s3": env_a, #sweep(beta, env_a), + "s4": triggered_env_b #rename('parameterized', triggered_env_b) #sweep(beta, triggered_env_b) +} +# parameterized_env_processes = parameterize_states(env_processes) +# +# pp.pprint(parameterized_env_processes) +# exit() + +# 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 + +mechanisms = { + "m1": { + "behaviors": { + "b1": b1m1, + "b2": b2m1 + }, + "states": { + "s1": s1m1, + "s2": s2m1 + } + }, + "m2": { + "behaviors": { + "b1": b1m2, + "b2": b2m2, + }, + "states": { + "s1": s1m2, + "s2": s2m2 + } + }, + "m3": { + "behaviors": { + "b1": b1m3, + "b2": b2m3 + }, + "states": { + "s1": s1m3, + "s2": s2m3 + } + } +} + + +sim_config = config_sim( + { + "N": 2, + "T": range(5), + "M": g + } +) + + +append_configs( + sim_configs=sim_config, + state_dict=genesis_states, + seed=seed, + raw_exogenous_states=raw_exogenous_states, + env_processes=env_processes, + mechanisms=mechanisms +) \ No newline at end of file