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
.DS_Store
.idea

View File

@ -28,7 +28,7 @@ class Configuration(object):
sanitize_config(self)
# ToDo: Remove Seeds
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:
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()]
return reduce(cond_opp, condition_bools)
def apply_state_condition(conditions, cond_opp, y, f, _g, step, sL, s, _input):
if trigger_condition(s, conditions, cond_opp):
def apply_state_condition(pre_conditions, cond_opp, y, f, _g, step, sL, s, _input):
if trigger_condition(s, pre_conditions, cond_opp):
return f(_g, step, sL, s, _input)
else:
return y, s[y]
def proc_trigger(y, f, conditions, cond_op):
return lambda _g, step, sL, s, _input: apply_state_condition(conditions, cond_op, y, f, _g, step, sL, s, _input)
def var_trigger(y, f, pre_conditions, cond_op):
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):
conditions = {'substep': [0, end_substep]}
cond_opp = lambda a, b: a and b
return proc_trigger(y, f, conditions, cond_opp)
def var_substep_trigger(substeps):
def trigger(end_substep, y, f):
pre_conditions = {'substep': substeps}
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)
# print(timestep_trigger)
@ -157,19 +180,15 @@ def timestep_trigger(end_substep, y, f):
def config_sim(d):
def process_variables(d):
return flatten_tabulated_dict(tabulate_dict(d))
if "M" in d:
return [
{
"N": d["N"],
"T": d["T"],
"M": M
}
for M in process_variables(d["M"])
]
return [{"N": d["N"], "T": d["T"], "M": M} for M in process_variables(d["M"])]
else:
d["M"] = [{}]
return d
def psub_list(psu_block, psu_steps):
return [psu_block[psu] for psu in psu_steps]
def psub(policies, state_updates):
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.update(variables)
return f"{members}"
return f"{members}" #[1:-1]
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 copy import deepcopy
from functools import reduce
from funcy import compose
from cadCAD.engine.utils import engine_exception
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 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(
self,
env_processes: Dict[str, Callable],
state_dict: Dict[str, Any],
sub_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])
def env_composition(target_field, state_dict, target_value):
function_type = type(lambda x: x)
env_update = env_processes[target_field]
if isinstance(env_update, list):
target_value = compose(*env_update[::-1])(target_value)
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
@ -137,7 +167,10 @@ class Executor:
last_in_copy: Dict[str, Any] = transfer_missing_fields(last_in_obj, dict(generate_record(state_funcs)))
# 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
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 funcy import curry
import pprint as pp
# from fn import _
from functools import reduce
@ -25,7 +30,7 @@ def update_timestamp(y, timedelta, format):
def apply(f, y: str, incr_by: int):
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)
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
# return proc_trigger2(y, f, multi_conditions, multi_cond_opp)
#
# @curried
def env_trigger(trigger_field, trigger_val, input, funct_list):
y, x = input
if trigger_field == trigger_val:
i = 0
for g in funct_list:
x = g(x)
return y, x
# print(env_trigger(3).__module__)
# pp.pprint(dir(env_trigger))
# @curried
# def env_proc_trigger(trigger_time, update_f, time):
# if time == trigger_time:
# return update_f
# else:
# return lambda x: x

View File

@ -2,4 +2,5 @@ pandas
wheel
pathos
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()
result = pd.DataFrame(raw_result)
def delSH(d):
print(d)
if 'sh' in d.keys():
del d['sh']
return d

View File

@ -2,7 +2,8 @@ import pandas as pd
from tabulate import tabulate
# The following imports NEED to be in the exact order
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
exec_mode = ExecutionMode()

View File

@ -1,10 +1,12 @@
from decimal import Decimal
import numpy as np
from datetime import timedelta
from funcy import compose
import pprint
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
@ -25,74 +27,95 @@ g: Dict[str, List[int]] = {
'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
def p1m1(_g, step, sL, s):
return {'param1': 1}
psu_block['m1']['policies']['p1'] = p1m1
def p2m1(_g, step, sL, s):
return {'param2': 4}
psu_block['m1']['policies']['p2'] = p2m1
def p1m2(_g, step, sL, s):
return {'param1': 'a', 'param2': _g['beta']}
psu_block['m2']['policies']['p1'] = p1m2
def p2m2(_g, step, sL, s):
return {'param1': 'b', 'param2': 0}
psu_block['m2']['policies']['p2'] = p2m2
def p1m3(_g, step, sL, s):
return {'param1': np.array([10, 100])}
psu_block['m3']['policies']['p1'] = p1m3
def p2m3(_g, step, sL, s):
return {'param1': np.array([20, 200])}
psu_block['m3']['policies']['p2'] = p2m3
# Internal States per Mechanism
def s1m1(_g, step, sL, s, _input):
return 's1', 0
psu_block['m1']["variables"]['s1'] = s1m1
def s2m1(_g, step, sL, s, _input):
return 's2', _g['beta']
psu_block['m1']["variables"]['s2'] = s2m1
def s1m2(_g, step, sL, s, _input):
return 's1', _input['param2']
psu_block['m2']["variables"]['s1'] = s1m2
def s2m2(_g, step, sL, s, _input):
return 's2', _input['param2']
psu_block['m2']["variables"]['s2'] = s2m2
def s1m3(_g, step, sL, s, _input):
return 's1', 0
psu_block['m3']["variables"]['s1'] = s1m3
def s2m3(_g, step, sL, s, _input):
return 's2', 0
psu_block['m3']["variables"]['s2'] = s2m3
# 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_B = 1.3
def es3p1(_g, step, sL, s, _input):
return 's3', _g['gamma']
# @curried
return 's3', s['s3']
# 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):
return 's4', _g['gamma']
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 = 'timestep'
x = ep_time_step(s, dt_str=s['timestep'], fromat_str=ts_format, _timedelta=t_delta)
return (y, x)
return 's4', s['s4'] #+ 4 #g['gamma'] + proc_one_coef_B
for m in ['m1','m2','m3']:
psu_block[m]["variables"]['s4'] = var_timestep_trigger(y='s4', f=es4p2)
# Environment States
# @curried
# def env_a(param, x):
# return x + param
def env_a(x):
return x
def env_b(x):
return 10
# 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
# Genesis States
genesis_states = {
@ -100,83 +123,37 @@ genesis_states = {
's2': Decimal(0.0),
's3': 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
sim_config = config_sim(
{
"N": 2,
"T": range(5),
"M": g # Optional
"M": g, # Optional
}
)
# New Convention
partial_state_update_blocks = psub_list(psu_block, psu_steps)
append_configs(
sim_configs=sim_config,
initial_state=genesis_states,
seeds=seeds,
raw_exogenous_states=raw_exogenous_states,
env_processes=env_processes,
partial_state_update_blocks=partial_state_update_block
)
env_processes=env_process,
partial_state_update_blocks=partial_state_update_blocks
)
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.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
import pandas as pd
@ -69,32 +70,36 @@ state_dict = {
'timestamp': '2019-01-01 00:00:00'
}
policies, state_updates = {}, {}
#
# def assign_udo_policy(udo):
# def policy(_g, step, sL, s):
# s['udo_policies'][udo].updateX()
# 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'])}
psu_steps = ['m1', 'm2', 'm3']
system_substeps = len(psu_steps)
var_timestep_trigger = var_substep_trigger([0, system_substeps])
env_timestep_trigger = env_trigger(system_substeps)
psu_block = {k: {"policies": {}, "variables": {}} for k in psu_steps}
def udo_policyA(_g, step, sL, s):
s['udo_policies']['udo_A'].updateX()
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):
s['udo_policies']['udo_B'].updateX()
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 = {"A": udo_policyA, "B": udo_policyB}
# def increment_state_by_int(y: str, incr_by: int):
# return lambda _g, step, sL, s, _input: (y, s[y] + incr_by)
state_updates['increment'] = add('increment', 1)
def add(y: str, added_val):
return lambda _g, step, sL, s, _input: (y, s[y] + added_val)
# state_updates['increment'] = add('increment', 1)
for m in psu_steps:
psu_block[m]["variables"]['increment'] = add('increment', 1)
@curried
def perceive(s, self):
@ -110,12 +115,15 @@ def state_udo_update(_g, step, sL, s, _input):
s['state_udo'].updateX().perceive(s)
x = udoPipe(s['state_udo'])
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):
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):
@ -125,12 +133,15 @@ def track_state_udo_perception(destination, source):
else:
return past_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):
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):
@ -140,56 +151,32 @@ def track_udo_policy(destination, source):
else:
return v.x
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):
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 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
# New Convention
partial_state_update_blocks = psub_list(psu_block, psu_steps)
append_configs(
sim_configs=sim_config,
initial_state=state_dict,
seeds={},
raw_exogenous_states={},
env_processes={},
partial_state_update_blocks=PSUBS,
# policy_ops=[lambda a, b: {**a, **b}]
partial_state_update_blocks=partial_state_update_blocks
)
# pp.pprint(partial_state_update_blocks)
# PSUB = {
# 'policies': policies,
# 'states': state_updates
# }
# partial_state_update_blocks = [PSUB] * substeps
print()
print("State Updates:")
pp.pprint(partial_state_update_blocks)
print()

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.userDefinedObject import udoPipe, UDO
import pandas as pd
import pprint as pp
from fn.func import curried
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,
# 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.utils.userDefinedObject import udoPipe, UDO
import networkx as nx
import matplotlib.pyplot as plt
import numpy as np
@ -21,11 +22,98 @@ for node in G.nodes:
scale=100
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):
delta_balls = _input['delta']
delta_balls = _input['robot'].internal_policy['delta']
new_balls = s['balls']
for e in G.edges:
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):
new_nodes = _input['nodes']
new_edges = _input['edges']
new_balls = _input['quantity']
new_nodes = _input['robot'].internal_policy['nodes']
new_edges = _input['robot'].internal_policy['edges']
new_balls = _input['robot'].internal_policy['quantity']
graph = s['network']
for node in new_nodes:
graph.add_node(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:
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'
value = graph
@ -63,8 +151,8 @@ def update_network(params, step, sL, s, _input):
def update_network_balls(params, step, sL, s, _input):
new_nodes = _input['nodes']
new_balls = _input['quantity']
new_nodes = _input['robot'].internal_policy['nodes']
new_balls = _input['robot'].internal_policy['quantity']
balls = np.zeros(len(s['balls']) + len(new_nodes))
for node in s['network'].nodes:
@ -79,91 +167,17 @@ def update_network_balls(params, step, sL, s, _input):
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):
graph = s['network']
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)
s['robot'].robotic_network(s['network'], s['balls'])
return {'robot': udoPipe(s['robot'])}
def agent_arrival(params, step, sL, s):
node = len(s['network'].nodes)
edge_list = s['network'].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}
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)
s['robot'].agent_arrival(s['network'], s['balls'])
return {'robot': udoPipe(s['robot'])}
def get_robot(params, step, sL, s, _input):
return 'robot', _input['robot']
partial_state_update_blocks = [
{
@ -172,7 +186,8 @@ partial_state_update_blocks = [
'p1': robotic_network
},
'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
'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
# The following imports NEED to be in the exact order
from cadCAD.engine import ExecutionMode, ExecutionContext, Executor
from simulations.validation import marbles2
from cadCAD import configs
exec_mode = ExecutionMode()
@ -20,6 +19,7 @@ print("Tensor Field: config1")
print(tabulate(tensor_field, headers='keys', tablefmt='psql'))
print("Output:")
print(tabulate(result, headers='keys', tablefmt='psql'))
print(result[['network']])
print()
print(result[['network', 'substep']])

View File

@ -2,10 +2,9 @@ import pandas as pd
from tabulate import tabulate
# The following imports NEED to be in the exact order
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
exec_mode = ExecutionMode()
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 cadCAD import configs
exec_mode = ExecutionMode()
print("Simulation Execution: Single Configuration")

View File

@ -1,25 +1,25 @@
from cadCAD.configuration import append_configs
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
def last_update_block(_g, substep, sH, s, _input):
return 'sh', sH[-1]
# Policies per Mechanism
def p(_g, substep, sH, s):
return {'last_update_block': sH[-1]}
def add(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 = {
's': 0,
'sh': [{}], # {[], {}}
@ -34,7 +34,7 @@ variables = {
PSUB = {
"policies": policies,
"policies": {}, #policies,
"variables": variables
}
@ -58,6 +58,5 @@ append_configs(
seeds={},
raw_exogenous_states={},
env_processes={},
partial_state_update_blocks=partial_state_update_block,
policy_ops=[lambda a, b: a + b]
partial_state_update_blocks=partial_state_update_block
)