diff --git a/SimCAD/configuration/__init__.py b/SimCAD/configuration/__init__.py index 0af1af7..2e9bc99 100644 --- a/SimCAD/configuration/__init__.py +++ b/SimCAD/configuration/__init__.py @@ -1,21 +1,23 @@ from functools import reduce from fn.op import foldr import pandas as pd +from fn.func import curried from SimCAD.utils import key_filter from SimCAD.configuration.utils.behaviorAggregation import dict_elemwise_sum +# class ParameterSeep: class Configuration: - def __init__(self, sim_config, state_dict, seed, exogenous_states, env_processes, mechanisms, behavior_ops=[foldr(dict_elemwise_sum())]): + 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 class Identity: def __init__(self, behavior_id={'identity': 0}): diff --git a/SimCAD/engine/utils.py b/SimCAD/engine/utils.py index 90c8fd9..8bb4218 100644 --- a/SimCAD/engine/utils.py +++ b/SimCAD/engine/utils.py @@ -43,5 +43,5 @@ def fit_param(param, x): # fit_param = lambda param: lambda x: x + param -def sweep(params, sweep_f): - return [rename('sweep', sweep_f(param)) for param in params] +def sweep(params, sweep_f, f_name='sweep'): + return [rename(f_name+"_"+str(i), sweep_f(param)) for param, i in zip(params, range(len(params)))] diff --git a/SimCAD/utils/__init__.py b/SimCAD/utils/__init__.py index 05363a1..d96cb23 100644 --- a/SimCAD/utils/__init__.py +++ b/SimCAD/utils/__init__.py @@ -2,6 +2,7 @@ from collections import defaultdict from itertools import product # from fn.func import curried + def pipe(x): return x @@ -33,9 +34,33 @@ def flatten(l): 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 contains_type(_collection, type): + return any(isinstance(x, type) for x in _collection) + + def drop_right(l, n): return l[:len(l)-n] + +def mech_sweep_filter(mechanisms): + mech_states_dict = dict([(k, v['states']) for k, v in mechanisms.items()]) + return dict([ + (k, dict_filter(v, lambda v: isinstance(v, list))) for k, v in mech_states_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)]) + # def flatmap(f, items): # return list(map(f, items)) @@ -55,7 +80,7 @@ def groupByKey(l): def rename(new_name, f): f.__name__ = new_name return f -# + # def rename(newname): # def decorator(f): # f.__name__ = newname diff --git a/simulations/validation/config1.py b/simulations/validation/config1.py index f1bb962..aae710d 100644 --- a/simulations/validation/config1.py +++ b/simulations/validation/config1.py @@ -2,13 +2,17 @@ from decimal import Decimal import numpy as np from datetime import timedelta from fn.func import curried - +import pprint +from copy import deepcopy from SimCAD import configs +from SimCAD.utils import flatMap, mech_sweep_filter, state_sweep_filter from SimCAD.configuration import Configuration from SimCAD.configuration.utils import state_update, exo_update_per_ts, proc_trigger, bound_norm_random, \ ep_time_step from SimCAD.engine.utils import sweep +pp = pprint.PrettyPrinter(indent=4) + seed = { 'z': np.random.RandomState(1), 'a': np.random.RandomState(2), @@ -41,14 +45,12 @@ def s1m1(step, sL, s, _input): return (y, x) - -# curry to give sweep_f s2m1 and returning a s2m1 sweep_f(s2m1)(param) # decorator -param = Decimal(11.0) -def s2m1(step, sL, s, _input): - y = 's2' - x = _input['param2'] + param - return (y, x) +# param = Decimal(11.0) +# def s2m1(step, sL, s, _input): +# y = 's2' +# x = _input['param2'] + param +# return (y, x) s2m1_params =[Decimal(11.0), Decimal(22.0)] @curried @@ -57,15 +59,6 @@ def s2m1(param, step, sL, s, _input): x = _input['param2'] + param return (y, x) - -# s2m1_sweep = s2m1(param=s2m1_params) - -# -# s2m1_sweep = sweep( -# params = s2m1_params, -# sweep_f = s2m1_sweep -# ) - def s1m2(step, sL, s, _input): y = 's1' x = _input['param1'] @@ -94,13 +87,20 @@ proc_one_coef_B = 1.3 # return (y, x) -es3p1 = sweep( - params = [Decimal(11.0), Decimal(22.0)], - sweep_f = lambda param: lambda step, sL, s, _input: ( - 's3', - s['s3'] + param - ) -) +# es3p1 = sweep( +# params = [Decimal(11.0), Decimal(22.0)], +# sweep_f = lambda param: lambda step, sL, s, _input: ( +# 's3', +# s['s3'] + param +# ) +# ) + +es3p1_params =[Decimal(11.0), Decimal(22.0)] +@curried +def es3p1(param, step, sL, s, _input): + y = 's3' + x = s['s3'] + param + return (y, x) def es4p2(step, sL, s, _input): y = 's4' @@ -116,8 +116,10 @@ def es5p2(step, sL, s, _input): # Environment States -def env_a(x): - return 5 +env_a_params = [Decimal(1), Decimal(2)] +@curried +def env_a(param, x): + return x + param def env_b(x): return 10 # def what_ever(x): @@ -133,18 +135,17 @@ genesis_states = { } # remove `exo_update_per_ts` to update every ts -exogenous_states = exo_update_per_ts( - { - "s3": es3p1, +raw_exogenous_states = { + "s3": sweep(es3p1_params, es3p1), "s4": es4p2, "timestamp": es5p2 - } -) +} +exogenous_states = exo_update_per_ts(raw_exogenous_states) # ToDo: make env proc trigger field agnostic # ToDo: input json into function renaming __name__ env_processes = { - # "s3": env_a, + "s3": sweep(env_a_params, env_a, 'env_a'), "s4": proc_trigger('2018-10-01 15:16:25', env_b) } @@ -198,13 +199,90 @@ sim_config = { "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 +# configs.append( +# Configuration( +# sim_config=sim_config, +# state_dict=genesis_states, +# seed=seed, +# env_processes=env_processes, +# exogenous_states=exogenous_states, +# mechanisms=mechanisms +# ) +# ) + + +# filtered_exo_states = raw_exo_sweep_filter(raw_exogenous_states) +# pp.pprint(filtered_exo_states) +# print() + + +@curried +def sweep_mechs(in_config): + configs = [] + filtered_mech_states = mech_sweep_filter(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: Configuration = deepcopy(in_config) + exploded_mechs = deepcopy(mechanisms) + exploded_mechs[mech]['states'][state] = f + config.mechanisms = exploded_mechs + configs.append(config) + del config, exploded_mechs + 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: Configuration = 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 + + +c = Configuration( + sim_config=sim_config, + state_dict=genesis_states, + seed=seed, + env_processes=env_processes, + exogenous_states=exogenous_states, + mechanisms=mechanisms +) + + +l = flatMap( + sweep_states('environmental', env_processes), + flatMap( + sweep_states('exogenous', raw_exogenous_states), + sweep_mechs(c) + ) +) + +for g in l: + print() + print('Configuration') + print() + pp.pprint(g.env_processes) + print() + pp.pprint(g.exogenous_states) + print() + pp.pprint(g.mechanisms) + print() \ No newline at end of file