fefactored env_process

This commit is contained in:
Joshua E. Jodesty 2019-05-16 12:51:56 -04:00
parent 1c89d28ab5
commit 2de989db0a
20 changed files with 344 additions and 297 deletions

2
.gitignore vendored
View File

@ -1,4 +1,4 @@
.idea jupyter notebook.idea
.ipynb_checkpoints .ipynb_checkpoints
.DS_Store .DS_Store
.idea .idea

View File

@ -28,7 +28,7 @@ class Configuration(object):
sanitize_config(self) sanitize_config(self)
# ToDo: Remove Seeds
def append_configs(sim_configs={}, initial_state={}, seeds={}, raw_exogenous_states={}, env_processes={}, def append_configs(sim_configs={}, initial_state={}, seeds={}, raw_exogenous_states={}, env_processes={},
partial_state_update_blocks={}, policy_ops=[lambda a, b: a + b], _exo_update_per_ts: bool = True) -> None: partial_state_update_blocks={}, policy_ops=[lambda a, b: a + b], _exo_update_per_ts: bool = True) -> None:
if _exo_update_per_ts is True: if _exo_update_per_ts is True:

View File

@ -134,20 +134,43 @@ def trigger_condition(s, conditions, cond_opp):
condition_bools = [s[field] in precondition_values for field, precondition_values in conditions.items()] condition_bools = [s[field] in precondition_values for field, precondition_values in conditions.items()]
return reduce(cond_opp, condition_bools) return reduce(cond_opp, condition_bools)
def apply_state_condition(conditions, cond_opp, y, f, _g, step, sL, s, _input): def apply_state_condition(pre_conditions, cond_opp, y, f, _g, step, sL, s, _input):
if trigger_condition(s, conditions, cond_opp): if trigger_condition(s, pre_conditions, cond_opp):
return f(_g, step, sL, s, _input) return f(_g, step, sL, s, _input)
else: else:
return y, s[y] return y, s[y]
def proc_trigger(y, f, conditions, cond_op): def var_trigger(y, f, pre_conditions, cond_op):
return lambda _g, step, sL, s, _input: apply_state_condition(conditions, cond_op, y, f, _g, step, sL, s, _input) return lambda _g, step, sL, s, _input: apply_state_condition(pre_conditions, cond_op, y, f, _g, step, sL, s, _input)
def timestep_trigger(end_substep, y, f): def var_substep_trigger(substeps):
conditions = {'substep': [0, end_substep]} def trigger(end_substep, y, f):
cond_opp = lambda a, b: a and b pre_conditions = {'substep': substeps}
return proc_trigger(y, f, conditions, cond_opp) cond_opp = lambda a, b: a and b
return var_trigger(y, f, pre_conditions, cond_opp)
return lambda y, f: curry(trigger)(substeps)(y)(f)
def env_trigger(end_substep):
def trigger(end_substep, trigger_field, trigger_vals, funct_list):
def env_update(state_dict, target_value):
state_dict_copy = deepcopy(state_dict)
# Use supstep to simulate current sysMetrics
if state_dict_copy['substep'] == end_substep:
state_dict_copy['timestep'] = state_dict_copy['timestep'] + 1
if state_dict_copy[trigger_field] in trigger_vals:
for g in funct_list:
target_value = g(target_value)
del state_dict_copy
return target_value
return env_update
return lambda trigger_field, trigger_vals, funct_list: \
curry(trigger)(end_substep)(trigger_field)(trigger_vals)(funct_list)
# trigger = curry(_trigger) # trigger = curry(_trigger)
# print(timestep_trigger) # print(timestep_trigger)
@ -157,19 +180,15 @@ def timestep_trigger(end_substep, y, f):
def config_sim(d): def config_sim(d):
def process_variables(d): def process_variables(d):
return flatten_tabulated_dict(tabulate_dict(d)) return flatten_tabulated_dict(tabulate_dict(d))
if "M" in d: if "M" in d:
return [ return [{"N": d["N"], "T": d["T"], "M": M} for M in process_variables(d["M"])]
{
"N": d["N"],
"T": d["T"],
"M": M
}
for M in process_variables(d["M"])
]
else: else:
d["M"] = [{}] d["M"] = [{}]
return d return d
def psub_list(psu_block, psu_steps):
return [psu_block[psu] for psu in psu_steps]
def psub(policies, state_updates): def psub(policies, state_updates):
return { return {

View File

@ -27,7 +27,7 @@ class udcView(object):
} }
members['methods'] = [k for k, v in self.__dict__.items() if str(type(v)) == "<class 'method'>"] members['methods'] = [k for k, v in self.__dict__.items() if str(type(v)) == "<class 'method'>"]
members.update(variables) members.update(variables)
return f"{members}" return f"{members}" #[1:-1]
class udcBroker(object): class udcBroker(object):

View File

@ -3,6 +3,7 @@ from typing import Any, Callable, Dict, List, Tuple
from pathos.pools import ThreadPool as TPool from pathos.pools import ThreadPool as TPool
from copy import deepcopy from copy import deepcopy
from functools import reduce from functools import reduce
from funcy import compose
from cadCAD.engine.utils import engine_exception from cadCAD.engine.utils import engine_exception
from cadCAD.utils import flatten from cadCAD.utils import flatten
@ -72,19 +73,48 @@ class Executor:
# return {k: reduce(f1, val_list) for k, val_list in new_dict.items()} # return {k: reduce(f1, val_list) for k, val_list in new_dict.items()}
# return foldr(call, col_results)(ops) # return foldr(call, col_results)(ops)
# def apply_env_proc(
# self,
# env_processes: Dict[str, Callable],
# state_dict: Dict[str, Any],
# time_step: int
# ) -> Dict[str, Any]:
# for state in state_dict.keys():
# if state in list(env_processes.keys()):
# env_state: Callable = env_processes[state]
# if (env_state.__name__ == '_curried') or (env_state.__name__ == 'proc_trigger'):
# state_dict[state] = env_state(sub_step)(state_dict[state])
# else:
# state_dict[state] = env_state(state_dict[state])
#
# return state_dict
def apply_env_proc( def apply_env_proc(
self, self,
env_processes: Dict[str, Callable], env_processes: Dict[str, Callable],
state_dict: Dict[str, Any], state_dict: Dict[str, Any],
sub_step: int
) -> Dict[str, Any]: ) -> Dict[str, Any]:
for state in state_dict.keys():
if state in list(env_processes.keys()): def env_composition(target_field, state_dict, target_value):
env_state: Callable = env_processes[state] function_type = type(lambda x: x)
if (env_state.__name__ == '_curried') or (env_state.__name__ == 'proc_trigger'): env_update = env_processes[target_field]
state_dict[state] = env_state(sub_step)(state_dict[state]) if isinstance(env_update, list):
else: target_value = compose(*env_update[::-1])(target_value)
state_dict[state] = env_state(state_dict[state]) elif isinstance(env_update, function_type):
target_value = env_update(state_dict, target_value)
else:
target_value = env_update
return target_value
filtered_state_dict = {k: v for k, v in state_dict.items() if k in env_processes.keys()}
env_proc_dict = {
target_field: env_composition(target_field, state_dict, target_value)
for target_field, target_value in filtered_state_dict.items()
}
for k, v in env_proc_dict.items():
state_dict[k] = v
return state_dict return state_dict
@ -137,7 +167,10 @@ class Executor:
last_in_copy: Dict[str, Any] = transfer_missing_fields(last_in_obj, dict(generate_record(state_funcs))) last_in_copy: Dict[str, Any] = transfer_missing_fields(last_in_obj, dict(generate_record(state_funcs)))
# ToDo: Remove # ToDo: Remove
last_in_copy: Dict[str, Any] = self.apply_env_proc(env_processes, last_in_copy, last_in_copy['timestep']) # last_in_copy: Dict[str, Any] = self.apply_env_proc(env_processes, last_in_copy, last_in_copy['timestep'])
last_in_copy: Dict[str, Any] = self.apply_env_proc(env_processes, last_in_copy)
# ToDo: make 'substep' & 'timestep' reserve fields # ToDo: make 'substep' & 'timestep' reserve fields
last_in_copy['substep'], last_in_copy['timestep'], last_in_copy['run'] = sub_step, time_step, run last_in_copy['substep'], last_in_copy['timestep'], last_in_copy['run'] = sub_step, time_step, run

View File

@ -1,5 +1,10 @@
from copy import deepcopy
from fn.func import curried
from cadCAD.configuration.utils import ep_time_step, time_step from cadCAD.configuration.utils import ep_time_step, time_step
from funcy import curry from funcy import curry
import pprint as pp
# from fn import _ # from fn import _
from functools import reduce from functools import reduce
@ -25,7 +30,7 @@ def update_timestamp(y, timedelta, format):
def apply(f, y: str, incr_by: int): def apply(f, y: str, incr_by: int):
return lambda _g, step, sL, s, _input: (y, curry(f)(s[y])(incr_by)) return lambda _g, step, sL, s, _input: (y, curry(f)(s[y])(incr_by))
def add(y: str, incr_by: int): def add(y: str, incr_by):
return apply(lambda a, b: a + b, y, incr_by) return apply(lambda a, b: a + b, y, incr_by)
def increment_state_by_int(y: str, incr_by: int): def increment_state_by_int(y: str, incr_by: int):
@ -85,15 +90,22 @@ def time_model(y, substeps, time_delta, ts_format='%Y-%m-%d %H:%M:%S'):
# multi_cond_opp = lambda a, b: a and b # multi_cond_opp = lambda a, b: a and b
# return proc_trigger2(y, f, multi_conditions, multi_cond_opp) # return proc_trigger2(y, f, multi_conditions, multi_cond_opp)
#
# @curried
def env_trigger(trigger_field, trigger_val, input, funct_list):
y, x = input # print(env_trigger(3).__module__)
if trigger_field == trigger_val: # pp.pprint(dir(env_trigger))
i = 0
for g in funct_list:
x = g(x)
return y, x # @curried
# def env_proc_trigger(trigger_time, update_f, time):
# if time == trigger_time:
# return update_f
# else:
# return lambda x: x

View File

@ -3,3 +3,4 @@ wheel
pathos pathos
fn fn
tabulate tabulate
funcy

View File

@ -16,7 +16,6 @@ run = Executor(exec_context=single_proc_ctx, configs=first_config)
raw_result, tensor_field = run.main() raw_result, tensor_field = run.main()
result = pd.DataFrame(raw_result) result = pd.DataFrame(raw_result)
def delSH(d): def delSH(d):
print(d)
if 'sh' in d.keys(): if 'sh' in d.keys():
del d['sh'] del d['sh']
return d return d

View File

@ -2,7 +2,8 @@ import pandas as pd
from tabulate import tabulate from tabulate import tabulate
# The following imports NEED to be in the exact order # The following imports NEED to be in the exact order
from cadCAD.engine import ExecutionMode, ExecutionContext, Executor from cadCAD.engine import ExecutionMode, ExecutionContext, Executor
from simulations.validation import new_sweep_config # from simulations.validation import new_sweep_config
from simulations.regression_tests import sweep_config
from cadCAD import configs from cadCAD import configs
exec_mode = ExecutionMode() exec_mode = ExecutionMode()

View File

@ -1,10 +1,12 @@
from decimal import Decimal from decimal import Decimal
import numpy as np import numpy as np
from datetime import timedelta from datetime import timedelta
from funcy import compose
import pprint import pprint
from cadCAD.configuration import append_configs from cadCAD.configuration import append_configs
from cadCAD.configuration.utils import proc_trigger, ep_time_step, config_sim from cadCAD.configuration.utils import proc_trigger, env_trigger, var_substep_trigger, config_sim, env_proc_trigger, \
time_step, psub_list
from typing import Dict, List from typing import Dict, List
@ -25,74 +27,95 @@ g: Dict[str, List[int]] = {
'omega': [7] 'omega': [7]
} }
psu_steps = ['m1', 'm2', 'm3']
system_substeps = len(psu_steps)
var_timestep_trigger = var_substep_trigger(system_substeps)
env_timestep_trigger = env_trigger(system_substeps)
env_process = {}
psu_block = {k: {"policies": {}, "variables": {}} for k in psu_steps}
# ['s1', 's2', 's3', 's4']
# Policies per Mechanism # Policies per Mechanism
def p1m1(_g, step, sL, s): def p1m1(_g, step, sL, s):
return {'param1': 1} return {'param1': 1}
psu_block['m1']['policies']['p1'] = p1m1
def p2m1(_g, step, sL, s): def p2m1(_g, step, sL, s):
return {'param2': 4} return {'param2': 4}
psu_block['m1']['policies']['p2'] = p2m1
def p1m2(_g, step, sL, s): def p1m2(_g, step, sL, s):
return {'param1': 'a', 'param2': _g['beta']} return {'param1': 'a', 'param2': _g['beta']}
psu_block['m2']['policies']['p1'] = p1m2
def p2m2(_g, step, sL, s): def p2m2(_g, step, sL, s):
return {'param1': 'b', 'param2': 0} return {'param1': 'b', 'param2': 0}
psu_block['m2']['policies']['p2'] = p2m2
def p1m3(_g, step, sL, s): def p1m3(_g, step, sL, s):
return {'param1': np.array([10, 100])} return {'param1': np.array([10, 100])}
psu_block['m3']['policies']['p1'] = p1m3
def p2m3(_g, step, sL, s): def p2m3(_g, step, sL, s):
return {'param1': np.array([20, 200])} return {'param1': np.array([20, 200])}
psu_block['m3']['policies']['p2'] = p2m3
# Internal States per Mechanism # Internal States per Mechanism
def s1m1(_g, step, sL, s, _input): def s1m1(_g, step, sL, s, _input):
return 's1', 0 return 's1', 0
psu_block['m1']["variables"]['s1'] = s1m1
def s2m1(_g, step, sL, s, _input): def s2m1(_g, step, sL, s, _input):
return 's2', _g['beta'] return 's2', _g['beta']
psu_block['m1']["variables"]['s2'] = s2m1
def s1m2(_g, step, sL, s, _input): def s1m2(_g, step, sL, s, _input):
return 's1', _input['param2'] return 's1', _input['param2']
psu_block['m2']["variables"]['s1'] = s1m2
def s2m2(_g, step, sL, s, _input): def s2m2(_g, step, sL, s, _input):
return 's2', _input['param2'] return 's2', _input['param2']
psu_block['m2']["variables"]['s2'] = s2m2
def s1m3(_g, step, sL, s, _input): def s1m3(_g, step, sL, s, _input):
return 's1', 0 return 's1', 0
psu_block['m3']["variables"]['s1'] = s1m3
def s2m3(_g, step, sL, s, _input): def s2m3(_g, step, sL, s, _input):
return 's2', 0 return 's2', 0
psu_block['m3']["variables"]['s2'] = s2m3
# Exogenous States # Exogenous States
def update_timestamp(_g, step, sL, s, _input):
y = 'timestamp'
return y, time_step(dt_str=s[y], dt_format='%Y-%m-%d %H:%M:%S', _timedelta=timedelta(days=0, minutes=0, seconds=1))
for m in ['m1','m2','m3']:
# psu_block[m]["variables"]['timestamp'] = update_timestamp
psu_block[m]["variables"]['timestamp'] = var_timestep_trigger(y='timestamp', f=update_timestamp)
# psu_block[m]["variables"]['timestamp'] = proc_trigger(
# y='timestamp', f=update_timestamp, pre_conditions={'substep': [0, system_substeps]}, cond_op=lambda a, b: a and b
# )
proc_one_coef_A = 0.7 proc_one_coef_A = 0.7
proc_one_coef_B = 1.3
def es3p1(_g, step, sL, s, _input): def es3p1(_g, step, sL, s, _input):
return 's3', _g['gamma'] return 's3', s['s3']
# @curried # use `timestep_trigger` to update every ts
for m in ['m1','m2','m3']:
psu_block[m]["variables"]['s3'] = var_timestep_trigger(y='s3', f=es3p1)
proc_one_coef_B = 1.3
def es4p2(_g, step, sL, s, _input): def es4p2(_g, step, sL, s, _input):
return 's4', _g['gamma'] return 's4', s['s4'] #+ 4 #g['gamma'] + proc_one_coef_B
for m in ['m1','m2','m3']:
ts_format = '%Y-%m-%d %H:%M:%S' psu_block[m]["variables"]['s4'] = var_timestep_trigger(y='s4', f=es4p2)
t_delta = timedelta(days=0, minutes=0, seconds=1)
def es5p2(_g, step, sL, s, _input):
y = 'timestep'
x = ep_time_step(s, dt_str=s['timestep'], fromat_str=ts_format, _timedelta=t_delta)
return (y, x)
# Environment States # ToDo: The number of values entered in sweep should be the # of config objs created,
# @curried # not dependent on the # of times the sweep is applied
# def env_a(param, x): # sweep exo_state func and point to exo-state in every other funtion
# return x + param # param sweep on genesis states
def env_a(x):
return x
def env_b(x):
return 10
# Genesis States # Genesis States
genesis_states = { genesis_states = {
@ -100,83 +123,37 @@ genesis_states = {
's2': Decimal(0.0), 's2': Decimal(0.0),
's3': Decimal(1.0), 's3': Decimal(1.0),
's4': Decimal(1.0), 's4': Decimal(1.0),
# 'timestep': '2018-10-01 15:16:24' 'timestamp': '2018-10-01 15:16:24'
} }
# Environment Process
# ToDo: Validate - make env proc trigger field agnostic
env_process["s3"] = [lambda x: x + 1, lambda x: x + 1]
env_process["s4"] = env_timestep_trigger(trigger_field='timestep', trigger_vals=[5], funct_list=[lambda x: 1, lambda x: x + 2])
# remove `exo_update_per_ts` to update every ts
raw_exogenous_states = {
"s3": es3p1,
"s4": es4p2,
# "timestep": es5p2
}
# ToDo: make env proc trigger field agnostic
# ToDo: input json into function renaming __name__
triggered_env_b = proc_trigger(1, 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
partial_state_update_block = {
"m1": {
"policies": {
"b1": p1m1,
"b2": p2m1
},
"variables": {
"s1": s1m1,
"s2": s2m1
}
},
"m2": {
"policies": {
"b1": p1m2,
"b2": p2m2,
},
"variables": {
"s1": s1m2,
"s2": s2m2
}
},
"m3": {
"policies": {
"b1": p1m3,
"b2": p2m3
},
"variables": {
"s1": s1m3,
"s2": s2m3
}
}
}
# config_sim Necessary # config_sim Necessary
sim_config = config_sim( sim_config = config_sim(
{ {
"N": 2, "N": 2,
"T": range(5), "T": range(5),
"M": g # Optional "M": g, # Optional
} }
) )
# New Convention # New Convention
partial_state_update_blocks = psub_list(psu_block, psu_steps)
append_configs( append_configs(
sim_configs=sim_config, sim_configs=sim_config,
initial_state=genesis_states, initial_state=genesis_states,
seeds=seeds, seeds=seeds,
raw_exogenous_states=raw_exogenous_states, env_processes=env_process,
env_processes=env_processes, partial_state_update_blocks=partial_state_update_blocks
partial_state_update_blocks=partial_state_update_block
) )
print()
print("Policie State Update Block:")
pp.pprint(partial_state_update_blocks)
print()
print()

View File

@ -4,7 +4,8 @@ from functools import reduce
from cadCAD.utils import SilentDF #, val_switch from cadCAD.utils import SilentDF #, val_switch
from cadCAD.configuration import append_configs from cadCAD.configuration import append_configs
from cadCAD.configuration.utils import time_step, config_sim, proc_trigger, timestep_trigger, genereate_psubs from cadCAD.configuration.utils import time_step, config_sim, var_trigger, var_substep_trigger, genereate_psubs, \
env_trigger, psub_list
from cadCAD.configuration.utils.userDefinedObject import udoPipe, UDO from cadCAD.configuration.utils.userDefinedObject import udoPipe, UDO
import pandas as pd import pandas as pd
@ -69,32 +70,36 @@ state_dict = {
'timestamp': '2019-01-01 00:00:00' 'timestamp': '2019-01-01 00:00:00'
} }
policies, state_updates = {}, {} psu_steps = ['m1', 'm2', 'm3']
# system_substeps = len(psu_steps)
# def assign_udo_policy(udo): var_timestep_trigger = var_substep_trigger([0, system_substeps])
# def policy(_g, step, sL, s): env_timestep_trigger = env_trigger(system_substeps)
# s['udo_policies'][udo].updateX() psu_block = {k: {"policies": {}, "variables": {}} for k in psu_steps}
# return {udo: udoPipe(s['udo_policies'][udo])}
# return policy
# policies_updates = {p: assign_udo_policy(udo) for p, udo in zip(['p1', 'p2'], ['udo_A', 'udo_B'])}
def udo_policyA(_g, step, sL, s): def udo_policyA(_g, step, sL, s):
s['udo_policies']['udo_A'].updateX() s['udo_policies']['udo_A'].updateX()
return {'udo_A': udoPipe(s['udo_policies']['udo_A'])} return {'udo_A': udoPipe(s['udo_policies']['udo_A'])}
policies['a'] = udo_policyA # policies['a'] = udo_policyA
for m in psu_steps:
psu_block[m]['policies']['a'] = udo_policyA
def udo_policyB(_g, step, sL, s): def udo_policyB(_g, step, sL, s):
s['udo_policies']['udo_B'].updateX() s['udo_policies']['udo_B'].updateX()
return {'udo_B': udoPipe(s['udo_policies']['udo_B'])} return {'udo_B': udoPipe(s['udo_policies']['udo_B'])}
policies['b'] = udo_policyB # policies['b'] = udo_policyB
for m in psu_steps:
psu_block[m]['policies']['b'] = udo_policyB
# policies = {"p1": udo_policyA, "p2": udo_policyB} # policies = {"p1": udo_policyA, "p2": udo_policyB}
# policies = {"A": udo_policyA, "B": udo_policyB} # policies = {"A": udo_policyA, "B": udo_policyB}
# def increment_state_by_int(y: str, incr_by: int): def add(y: str, added_val):
# return lambda _g, step, sL, s, _input: (y, s[y] + incr_by) return lambda _g, step, sL, s, _input: (y, s[y] + added_val)
state_updates['increment'] = add('increment', 1) # state_updates['increment'] = add('increment', 1)
for m in psu_steps:
psu_block[m]["variables"]['increment'] = add('increment', 1)
@curried @curried
def perceive(s, self): def perceive(s, self):
@ -110,12 +115,15 @@ def state_udo_update(_g, step, sL, s, _input):
s['state_udo'].updateX().perceive(s) s['state_udo'].updateX().perceive(s)
x = udoPipe(s['state_udo']) x = udoPipe(s['state_udo'])
return y, x return y, x
state_updates['state_udo'] = state_udo_update for m in psu_steps:
psu_block[m]["variables"]['state_udo'] = state_udo_update
def track(destination, source): def track(destination, source):
return lambda _g, step, sL, s, _input: (destination, s[source].x) return lambda _g, step, sL, s, _input: (destination, s[source].x)
state_updates['state_udo_tracker'] = track('state_udo_tracker', 'state_udo') state_udo_tracker = track('state_udo_tracker', 'state_udo')
for m in psu_steps:
psu_block[m]["variables"]['state_udo_tracker'] = state_udo_tracker
def track_state_udo_perception(destination, source): def track_state_udo_perception(destination, source):
@ -125,12 +133,15 @@ def track_state_udo_perception(destination, source):
else: else:
return past_perception return past_perception
return lambda _g, step, sL, s, _input: (destination, id(s[source].perception)) return lambda _g, step, sL, s, _input: (destination, id(s[source].perception))
state_updates['state_udo_perception_tracker'] = track_state_udo_perception('state_udo_perception_tracker', 'state_udo') state_udo_perception_tracker = track_state_udo_perception('state_udo_perception_tracker', 'state_udo')
for m in psu_steps:
psu_block[m]["variables"]['state_udo_perception_tracker'] = state_udo_perception_tracker
def view_udo_policy(_g, step, sL, s, _input): def view_udo_policy(_g, step, sL, s, _input):
return 'udo_policies', _input return 'udo_policies', _input
state_updates['udo_policies'] = view_udo_policy for m in psu_steps:
psu_block[m]["variables"]['udo_policies'] = view_udo_policy
def track_udo_policy(destination, source): def track_udo_policy(destination, source):
@ -140,56 +151,32 @@ def track_udo_policy(destination, source):
else: else:
return v.x return v.x
return lambda _g, step, sL, s, _input: (destination, tuple(val_switch(v) for _, v in s[source].items())) return lambda _g, step, sL, s, _input: (destination, tuple(val_switch(v) for _, v in s[source].items()))
state_updates['udo_policy_tracker'] = track_udo_policy('udo_policy_tracker', 'udo_policies') udo_policy_tracker = track_udo_policy('udo_policy_tracker', 'udo_policies')
for m in psu_steps:
psu_block[m]["variables"]['udo_policy_tracker'] = udo_policy_tracker
def update_timestamp(_g, step, sL, s, _input): def update_timestamp(_g, step, sL, s, _input):
y = 'timestamp' y = 'timestamp'
return y, time_step(dt_str=s[y], dt_format='%Y-%m-%d %H:%M:%S', _timedelta=timedelta(days=0, minutes=0, seconds=1)) return y, time_step(dt_str=s[y], dt_format='%Y-%m-%d %H:%M:%S', _timedelta=timedelta(days=0, minutes=0, seconds=1))
for m in psu_steps:
psu_block[m]["variables"]['timestamp'] = var_timestep_trigger(y='timestamp', f=update_timestamp)
# psu_block[m]["variables"]['timestamp'] = var_trigger(
# y='timestamp', f=update_timestamp,
# pre_conditions={'substep': [0, system_substeps]}, cond_op=lambda a, b: a and b
# )
# psu_block[m]["variables"]['timestamp'] = update_timestamp
system_substeps = 3
# state_updates['timestamp'] = update_timestamp
state_updates['timestamp'] = timestep_trigger(end_substep=system_substeps, y='timestamp', f=update_timestamp)
# state_updates['timestamp'] = proc_trigger(y='timestamp', f=update_timestamp, conditions={'substep': [0, substeps]}, cond_op=lambda a, b: a and b)
print()
print("State Updates:")
pp.pprint(state_updates)
print()
print("Policies:")
pp.pprint(policies)
print()
filter_out = lambda remove_list, state_list: list(filter(lambda state: state not in remove_list, state_list))
states = list(state_updates.keys())
# states_noTS = filter_out(['timestamp'], states)
# states_grid = [states,states_noTS,states_noTS]
# states_grid = [states] * system_substeps #
states_grid = [states,states,states]
policy_grid = [['a', 'b'], ['a', 'b'], ['a', 'b']]
PSUBS = genereate_psubs(policy_grid, states_grid, policies, state_updates)
pp.pprint(PSUBS)
# ToDo: Bug without specifying parameters # ToDo: Bug without specifying parameters
# New Convention
partial_state_update_blocks = psub_list(psu_block, psu_steps)
append_configs( append_configs(
sim_configs=sim_config, sim_configs=sim_config,
initial_state=state_dict, initial_state=state_dict,
seeds={}, partial_state_update_blocks=partial_state_update_blocks
raw_exogenous_states={},
env_processes={},
partial_state_update_blocks=PSUBS,
# policy_ops=[lambda a, b: {**a, **b}]
) )
# pp.pprint(partial_state_update_blocks) print()
print("State Updates:")
# PSUB = { pp.pprint(partial_state_update_blocks)
# 'policies': policies, print()
# 'states': state_updates
# }
# partial_state_update_blocks = [PSUB] * substeps

View File

@ -5,7 +5,7 @@ from cadCAD.configuration import append_configs
from cadCAD.configuration.utils import time_step, ep_time_step, config_sim from cadCAD.configuration.utils import time_step, ep_time_step, config_sim
from cadCAD.configuration.utils.userDefinedObject import udoPipe, UDO from cadCAD.configuration.utils.userDefinedObject import udoPipe, UDO
import pandas as pd import pandas as pd
import pprint as pp
from fn.func import curried from fn.func import curried
DF = SilentDF(pd.read_csv('/Users/jjodesty/Projects/DiffyQ-SimCAD/simulations/external_data/output.csv')) DF = SilentDF(pd.read_csv('/Users/jjodesty/Projects/DiffyQ-SimCAD/simulations/external_data/output.csv'))
@ -161,3 +161,8 @@ append_configs(
partial_state_update_blocks=partial_state_update_blocks, partial_state_update_blocks=partial_state_update_blocks,
# policy_ops=[lambda a, b: {**a, **b}] # policy_ops=[lambda a, b: {**a, **b}]
) )
print()
print("State Updates:")
pp.pprint(partial_state_update_blocks)
print()

View File

@ -1,4 +1,5 @@
from cadCAD.configuration import append_configs from cadCAD.configuration import append_configs
from cadCAD.configuration.utils.userDefinedObject import udoPipe, UDO
import networkx as nx import networkx as nx
import matplotlib.pyplot as plt import matplotlib.pyplot as plt
import numpy as np import numpy as np
@ -21,11 +22,98 @@ for node in G.nodes:
scale=100 scale=100
nx.draw_kamada_kawai(G, node_size=balls*scale,labels=nx.get_node_attributes(G,'initial_balls')) nx.draw_kamada_kawai(G, node_size=balls*scale,labels=nx.get_node_attributes(G,'initial_balls'))
initial_conditions = {'balls': balls, 'network': G} def greedy_robot(src_balls, dst_balls):
# robot wishes to accumlate balls at its source
# takes half of its neighbors balls
if src_balls < dst_balls:
return -np.floor(dst_balls / 2)
else:
return 0
def fair_robot(src_balls, dst_balls):
# robot follows the simple balancing rule
return np.sign(src_balls - dst_balls)
def giving_robot(src_balls, dst_balls):
# robot wishes to gice away balls one at a time
if src_balls > 0:
return 1
else:
return 0
robot_strategies = [greedy_robot,fair_robot, giving_robot]
for node in G.nodes:
nstrats = len(robot_strategies)
rv = np.random.randint(0,nstrats)
G.nodes[node]['strat'] = robot_strategies[rv]
for e in G.edges:
owner_node = e[0]
G.edges[e]['strat'] = G.nodes[owner_node]['strat']
default_policy = {'nodes': [], 'edges': {}, 'quantity': {}, 'node_strats': {}, 'edge_strats': {}, 'delta': {}}
class robot(object):
def __init__(self, graph, balls, internal_policy=default_policy):
self.mem_id = str(hex(id(self)))
self.internal_policy = internal_policy
self.graph = graph
self.balls = balls
def robotic_network(self, graph, balls): # move balls
self.graph, self.balls = graph, balls
delta_balls = {}
for e in self.graph.edges:
src = e[0]
src_balls = self.balls[src]
dst = e[1]
dst_balls = self.balls[dst]
# transfer balls according to specific robot strat
strat = self.graph.edges[e]['strat']
delta_balls[e] = strat(src_balls, dst_balls)
self.internal_policy = {'nodes': [], 'edges': {}, 'quantity': {}, 'node_strats': {}, 'edge_strats': {}, 'delta': delta_balls}
return self
def agent_arrival(self, graph, balls): # add node
self.graph, self.balls = graph, balls
node = len(self.graph.nodes)
edge_list = self.graph.edges
# choose a m random edges without replacement
# new = np.random.choose(edgelist,m)
new = [0, 1] # tester
nodes = [node]
edges = [(node, new_node) for new_node in new]
initial_balls = {node: np.random.randint(1, 25)}
rv = np.random.randint(0, nstrats)
node_strat = {node: robot_strategies[rv]}
edge_strats = {e: robot_strategies[rv] for e in edges}
self.internal_policy = {'nodes': nodes,
'edges': edges,
'quantity': initial_balls,
'node_strats': node_strat,
'edge_strats': edge_strats,
'delta': np.zeros(node + 1)
}
return self
robot_udo = UDO(udo=robot(G, balls), masked_members=['obj'])
initial_conditions = {'balls': balls, 'network': G, 'robot': robot_udo}
def update_balls(params, step, sL, s, _input): def update_balls(params, step, sL, s, _input):
delta_balls = _input['delta'] delta_balls = _input['robot'].internal_policy['delta']
new_balls = s['balls'] new_balls = s['balls']
for e in G.edges: for e in G.edges:
move_ball = delta_balls[e] move_ball = delta_balls[e]
@ -42,20 +130,20 @@ def update_balls(params, step, sL, s, _input):
def update_network(params, step, sL, s, _input): def update_network(params, step, sL, s, _input):
new_nodes = _input['nodes'] new_nodes = _input['robot'].internal_policy['nodes']
new_edges = _input['edges'] new_edges = _input['robot'].internal_policy['edges']
new_balls = _input['quantity'] new_balls = _input['robot'].internal_policy['quantity']
graph = s['network'] graph = s['network']
for node in new_nodes: for node in new_nodes:
graph.add_node(node) graph.add_node(node)
graph.nodes[node]['initial_balls'] = new_balls[node] graph.nodes[node]['initial_balls'] = new_balls[node]
graph.nodes[node]['strat'] = _input['node_strats'][node] graph.nodes[node]['strat'] = _input['robot'].internal_policy['node_strats'][node]
for edge in new_edges: for edge in new_edges:
graph.add_edge(edge[0], edge[1]) graph.add_edge(edge[0], edge[1])
graph.edges[edge]['strat'] = _input['edge_strats'][edge] graph.edges[edge]['strat'] = _input['robot'].internal_policy['edge_strats'][edge]
key = 'network' key = 'network'
value = graph value = graph
@ -63,8 +151,8 @@ def update_network(params, step, sL, s, _input):
def update_network_balls(params, step, sL, s, _input): def update_network_balls(params, step, sL, s, _input):
new_nodes = _input['nodes'] new_nodes = _input['robot'].internal_policy['nodes']
new_balls = _input['quantity'] new_balls = _input['robot'].internal_policy['quantity']
balls = np.zeros(len(s['balls']) + len(new_nodes)) balls = np.zeros(len(s['balls']) + len(new_nodes))
for node in s['network'].nodes: for node in s['network'].nodes:
@ -79,91 +167,17 @@ def update_network_balls(params, step, sL, s, _input):
return (key, value) return (key, value)
def greedy_robot(src_balls, dst_balls):
# robot wishes to accumlate balls at its source
# takes half of its neighbors balls
if src_balls < dst_balls:
delta = -np.floor(dst_balls / 2)
else:
delta = 0
return delta
def fair_robot(src_balls, dst_balls):
# robot follows the simple balancing rule
delta = np.sign(src_balls - dst_balls)
return delta
def giving_robot(src_balls, dst_balls):
# robot wishes to gice away balls one at a time
if src_balls > 0:
delta = 1
else:
delta = 0
return delta
robot_strategies = [greedy_robot,fair_robot, giving_robot]
for node in G.nodes:
nstrats = len(robot_strategies)
rv = np.random.randint(0,nstrats)
G.nodes[node]['strat'] = robot_strategies[rv]
for e in G.edges:
owner_node = e[0]
G.edges[e]['strat'] = G.nodes[owner_node]['strat']
def robotic_network(params, step, sL, s): def robotic_network(params, step, sL, s):
graph = s['network'] s['robot'].robotic_network(s['network'], s['balls'])
return {'robot': udoPipe(s['robot'])}
delta_balls = {}
for e in graph.edges:
src = e[0]
src_balls = s['balls'][src]
dst = e[1]
dst_balls = s['balls'][dst]
# transfer balls according to specific robot strat
strat = graph.edges[e]['strat']
delta_balls[e] = strat(src_balls, dst_balls)
return_dict = {'nodes': [], 'edges': {}, 'quantity': {}, 'node_strats': {}, 'edge_strats': {}, 'delta': delta_balls}
return (return_dict)
def agent_arrival(params, step, sL, s): def agent_arrival(params, step, sL, s):
node = len(s['network'].nodes) s['robot'].agent_arrival(s['network'], s['balls'])
edge_list = s['network'].edges return {'robot': udoPipe(s['robot'])}
# choose a m random edges without replacement
# new = np.random.choose(edgelist,m)
new = [0, 1] # tester
nodes = [node]
edges = [(node, new_node) for new_node in new]
initial_balls = {node: np.random.randint(1, 25)}
rv = np.random.randint(0, nstrats)
node_strat = {node: robot_strategies[rv]}
edge_strats = {e: robot_strategies[rv] for e in edges}
return_dict = {'nodes': nodes,
'edges': edges,
'quantity': initial_balls,
'node_strats': node_strat,
'edge_strats': edge_strats,
'delta': np.zeros(node + 1)
}
return (return_dict)
def get_robot(params, step, sL, s, _input):
return 'robot', _input['robot']
partial_state_update_blocks = [ partial_state_update_blocks = [
{ {
@ -172,7 +186,8 @@ partial_state_update_blocks = [
'p1': robotic_network 'p1': robotic_network
}, },
'variables': { # The following state variables will be updated simultaneously 'variables': { # The following state variables will be updated simultaneously
'balls': update_balls 'balls': update_balls,
'robot': get_robot
} }
}, },
@ -183,7 +198,8 @@ partial_state_update_blocks = [
}, },
'variables': { # The following state variables will be updated simultaneously 'variables': { # The following state variables will be updated simultaneously
'network': update_network, 'network': update_network,
'balls': update_network_balls 'balls': update_network_balls,
'robot': get_robot
} }
} }
] ]

View File

@ -2,7 +2,6 @@ import pandas as pd
from tabulate import tabulate from tabulate import tabulate
# The following imports NEED to be in the exact order # The following imports NEED to be in the exact order
from cadCAD.engine import ExecutionMode, ExecutionContext, Executor from cadCAD.engine import ExecutionMode, ExecutionContext, Executor
from simulations.validation import marbles2
from cadCAD import configs from cadCAD import configs
exec_mode = ExecutionMode() exec_mode = ExecutionMode()
@ -20,6 +19,7 @@ print("Tensor Field: config1")
print(tabulate(tensor_field, headers='keys', tablefmt='psql')) print(tabulate(tensor_field, headers='keys', tablefmt='psql'))
print("Output:") print("Output:")
print(tabulate(result, headers='keys', tablefmt='psql')) print(tabulate(result, headers='keys', tablefmt='psql'))
print(result[['network']])
print() print()
print(result[['network', 'substep']]) print(result[['network', 'substep']])

View File

@ -2,10 +2,9 @@ import pandas as pd
from tabulate import tabulate from tabulate import tabulate
# The following imports NEED to be in the exact order # The following imports NEED to be in the exact order
from cadCAD.engine import ExecutionMode, ExecutionContext, Executor from cadCAD.engine import ExecutionMode, ExecutionContext, Executor
from simulations.validation import udo from simulations.regression_tests import udo_inter_substep_update
from cadCAD import configs from cadCAD import configs
exec_mode = ExecutionMode() exec_mode = ExecutionMode()
print("Simulation Execution: Single Configuration") print("Simulation Execution: Single Configuration")

View File

@ -5,7 +5,6 @@ from cadCAD.engine import ExecutionMode, ExecutionContext, Executor
from simulations.regression_tests import udo from simulations.regression_tests import udo
from cadCAD import configs from cadCAD import configs
exec_mode = ExecutionMode() exec_mode = ExecutionMode()
print("Simulation Execution: Single Configuration") print("Simulation Execution: Single Configuration")

View File

@ -1,25 +1,25 @@
from cadCAD.configuration import append_configs from cadCAD.configuration import append_configs
from cadCAD.configuration.utils import config_sim from cadCAD.configuration.utils import config_sim
# Policies per Mechanism
# def p(_g, substep, sH, s):
# return {'last_update_block': sH[-1]}
# def policies(_g, substep, sH, s, _input):
# y = 'policies'
# x = _input
# return (y, x)
# policies = {"p1": p, "p2": p}
# last_partial_state_update_block # last_partial_state_update_block
def last_update_block(_g, substep, sH, s, _input): def last_update_block(_g, substep, sH, s, _input):
return 'sh', sH[-1] return 'sh', sH[-1]
# Policies per Mechanism
def p(_g, substep, sH, s):
return {'last_update_block': sH[-1]}
def add(y, x): def add(y, x):
return lambda _g, substep, sH, s, _input: (y, s[y] + x) return lambda _g, substep, sH, s, _input: (y, s[y] + x)
def policies(_g, substep, sH, s, _input):
y = 'policies'
x = _input
return (y, x)
policies = {"p1": p, "p2": p}
genesis_states = { genesis_states = {
's': 0, 's': 0,
'sh': [{}], # {[], {}} 'sh': [{}], # {[], {}}
@ -34,7 +34,7 @@ variables = {
PSUB = { PSUB = {
"policies": policies, "policies": {}, #policies,
"variables": variables "variables": variables
} }
@ -58,6 +58,5 @@ append_configs(
seeds={}, seeds={},
raw_exogenous_states={}, raw_exogenous_states={},
env_processes={}, env_processes={},
partial_state_update_blocks=partial_state_update_block, partial_state_update_blocks=partial_state_update_block
policy_ops=[lambda a, b: a + b]
) )