diff --git a/engine/configProcessor.py b/engine/configProcessor.py index 6ab874b..71f0048 100644 --- a/engine/configProcessor.py +++ b/engine/configProcessor.py @@ -1,5 +1,5 @@ import pandas as pd -from functools import partial, reduce +from functools import reduce def state_identity(k): return lambda step, sL, s, _input: (k, s[k]) @@ -37,9 +37,7 @@ def generate_config(state_dict, mechanisms, exo_proc): sdf_values, bdf_values = sdf.values.tolist(), bdf.values.tolist() else: sdf_values = sdf.values.tolist() - # print(sdf_values) bdf_values = [ [b_identity] * len(sdf_values) for n in range(mechanisms) ] - # print(bdf_values) return sdf_values, bdf_values def only_ep_handler(state_dict): diff --git a/engine/mechanismExecutor.py b/engine/mechanismExecutor.py index 84ebfc5..5ceccf7 100644 --- a/engine/mechanismExecutor.py +++ b/engine/mechanismExecutor.py @@ -1,11 +1,14 @@ from copy import deepcopy -from fn import op, _ +from fn.op import foldr, call +from fn import _ +from ui.config import behavior_ops def getColResults(step, sL, s, funcs): return list(map(lambda f: f(step, sL, s), funcs)) -def getBehaviorInput(step, sL, s, funcs): - return op.foldr(_ + _)(getColResults(step, sL, s, funcs)) +# Data Type reduction +def getBehaviorInput(step, sL, s, funcs, ops = behavior_ops[::-1]): + return foldr(call, getColResults(step, sL, s, funcs))(ops) def apply_env_proc(env_processes, state_dict, step): for state in state_dict.keys(): @@ -21,26 +24,23 @@ def exception_handler(f, m_step, sL, last_mut_obj, _input): def mech_step(m_step, sL, state_funcs, behavior_funcs, env_processes, t_step): - in_copy, mutatable_copy, out_copy = deepcopy(sL), deepcopy(sL), deepcopy(sL) - last_in_obj, last_mut_obj = in_copy[-1], mutatable_copy[-1] + last_in_obj = sL[-1] _input = exception_handler(getBehaviorInput, m_step, sL, last_in_obj, behavior_funcs) + # del last_in_obj - # print(len(state_funcs)) + last_in_copy = dict([ exception_handler(f, m_step, sL, last_in_obj, _input) for f in state_funcs ]) + # print(str(m_step) + ': ' + str(last_in_copy)) - last_mut_obj = dict([ - exception_handler(f, m_step, sL, last_mut_obj, _input) for f in state_funcs - ]) - # print(str(m_step) + ': ' + str(last_mut_obj)) + # mutating last_in_copy + apply_env_proc(env_processes, last_in_copy, last_in_copy['timestamp']) - apply_env_proc(env_processes, last_mut_obj, last_mut_obj['timestamp']) + last_in_copy["mech_step"], last_in_copy["time_step"] = m_step, t_step + sL.append(last_in_copy) - last_mut_obj["mech_step"], last_mut_obj["time_step"] = m_step, t_step - out_copy.append(last_mut_obj) + del last_in_copy - del last_in_obj, last_mut_obj, in_copy, mutatable_copy, - - return out_copy + return sL def block_gen(states_list, configs, env_processes, t_step): @@ -68,12 +68,13 @@ def pipeline(states_list, configs, env_processes, time_seq): simulation_list = [states_list] for time_step in time_seq: pipeline_run = block_gen(simulation_list[-1], configs, env_processes, time_step) - head, *pipeline_run = pipeline_run + _, *pipeline_run = pipeline_run simulation_list.append(pipeline_run) return simulation_list +# Del head def simulation(states_list, configs, env_processes, time_seq, runs): pipeline_run = [] for run in range(runs): @@ -84,7 +85,7 @@ def simulation(states_list, configs, env_processes, time_seq, runs): pipeline_run += simulation_list else: transient_states_list = [pipeline_run[-1][-1]] - head, *tail = pipeline(transient_states_list, configs, env_processes, time_seq) + _, *tail = pipeline(transient_states_list, configs, env_processes, time_seq) pipeline_run += tail return pipeline_run \ No newline at end of file diff --git a/engine/run.py b/engine/run.py index 71a5537..8a019bc 100644 --- a/engine/run.py +++ b/engine/run.py @@ -17,7 +17,7 @@ def main(): # print(states_list) # print(configs) # p = pipeline(states_list, configs, env_processes, range(10)) - T = range(5) + T = sim_config['T'] N = sim_config['N'] # Dimensions: N x r x mechs diff --git a/engine/utils.py b/engine/utils.py index 34d7a68..bde5835 100644 --- a/engine/utils.py +++ b/engine/utils.py @@ -1,6 +1,6 @@ from datetime import datetime, timedelta from decimal import Decimal -from functools import partial +from fn.func import curried flatten = lambda l: [item for sublist in l for item in sublist] @@ -35,13 +35,12 @@ def bound_norm_random(rng, low, high): res = bound_norm_random(rng, low, high) return Decimal(res) -def proc_trigger(trigger_step, update_f): - def step_trigger(trigger_step, update_f, step): - if step == trigger_step: - return update_f - else: - return lambda x: x - return partial(step_trigger, trigger_step, update_f) +@curried +def proc_trigger(trigger_step, update_f, step): + if step == trigger_step: + return update_f + else: + return lambda x: x # accept timedelta instead of timedelta params def time_step(dt_str, dt_format='%Y-%m-%d %H:%M:%S', days=0, minutes=0, seconds=30): @@ -56,6 +55,15 @@ def ep_time_step(s, dt_str, fromat_str='%Y-%m-%d %H:%M:%S', days=0, minutes=0, s else: return dt_str +def exo_update_per_ts(ep): + @curried + def ep_decorator(f, y, step, sL, s, _input): + if s['mech_step'] + 1 == 1: # inside f body to reduce performance costs + return f(step, sL, s, _input) + else: + return (y, s[y]) + return {es: ep_decorator(f, es) for es, f in ep.items()} + # def create_tensor_field(mechanisms, env_poc, keys=['behaviors', 'states']): # dfs = [ create_matrix_field(mechanisms, k) for k in keys ] # df = pd.concat(dfs, axis=1) diff --git a/ui/config.py b/ui/config.py index e5d7df2..a21e126 100644 --- a/ui/config.py +++ b/ui/config.py @@ -1,4 +1,6 @@ -from engine.utils import bound_norm_random, ep_time_step, proc_trigger +from engine.utils import bound_norm_random, ep_time_step, proc_trigger, exo_update_per_ts +from fn.op import foldr +from fn import _ import numpy as np from decimal import Decimal @@ -58,27 +60,23 @@ def s2m3(step, sL, s, _input): # Exogenous States proc_one_coef_A = 0.7 proc_one_coef_B = 1.3 + def es3p1(step, sL, s, _input): y = 's3' - if s['mech_step']+1 == 1: # inside f body to reduce performance costs - x = s['s3'] * bound_norm_random(seed['a'], proc_one_coef_A, proc_one_coef_B) - return (y, x) - else: - return (y, s[y]) + 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' - if s['mech_step']+1 == 1: # inside f body to reduce performance costs - x = s['s4'] * bound_norm_random(seed['b'], proc_one_coef_A, proc_one_coef_B) - return (y, x) - else: - return (y, s[y]) + x = s['s4'] * bound_norm_random(seed['b'], proc_one_coef_A, proc_one_coef_B) + return (y, x) def es5p2(step, sL, s, _input): # accept timedelta instead of timedelta params y = 'timestamp' x = ep_time_step(s, s['timestamp'], seconds=1) return (y, x) + # Environment States def env_a(x): return 10 @@ -96,11 +94,13 @@ state_dict = { 'timestamp': '2018-10-01 15:16:24' } -exogenous_states = { +exogenous_states = exo_update_per_ts( + { "s3": es3p1, "s4": es4p2, "timestamp": es5p2 -} + } +) env_processes = { "s3": proc_trigger('2018-10-01 15:16:25', env_a), @@ -110,6 +110,7 @@ env_processes = { # test return vs. non-return functions as lambdas # test fully defined functions # genesis Sites should always be there +behavior_ops = [foldr(_ + _), lambda x: x + 0] mechanisms = { "m1": { "behaviors": { @@ -144,5 +145,6 @@ mechanisms = { } sim_config = { - "N": 2 + "N": 2, + "T": range(5) } \ No newline at end of file