This commit is contained in:
Joshua E. Jodesty 2019-02-18 13:10:23 -05:00
commit 0c234e2f00
17 changed files with 428 additions and 1908 deletions

3
.gitignore vendored
View File

@ -3,7 +3,7 @@
.DS_Store .DS_Store
.idea .idea
notebooks notebooks
SimCAD.egg-info *.egg-info
__pycache__ __pycache__
Pipfile Pipfile
Pipfile.lock Pipfile.lock
@ -12,6 +12,7 @@ results
*.csv *.csv
*.txt *.txt
simulations/.ipynb_checkpoints simulations/.ipynb_checkpoints
simulations/validation/config3.py
dist/*.gz dist/*.gz
cadCAD.egg-info cadCAD.egg-info

View File

@ -21,7 +21,7 @@ SimCAD is written in Python 3.
```bash ```bash
pip3 install -r requirements.txt pip3 install -r requirements.txt
python3 setup.py sdist bdist_wheel python3 setup.py sdist bdist_wheel
pip3 install dist/cadCAD-0.2-py3-none-any.whl pip3 install dist/*.whl
``` ```
**2. Configure Simulation:** **2. Configure Simulation:**

View File

@ -1,7 +1,7 @@
from functools import reduce from functools import reduce
from fn.op import foldr from fn.op import foldr
import pandas as pd import pandas as pd
from copy import deepcopy
from cadCAD import configs from cadCAD import configs
from cadCAD.utils import key_filter from cadCAD.utils import key_filter
@ -21,16 +21,16 @@ class Configuration(object):
self.policy_ops = policy_ops self.policy_ops = policy_ops
# for backwards compatibility, we accept old arguments via **kwargs # for backwards compatibility, we accept old arguments via **kwargs
# TODO: raise deprecation warnings # TODO: raise specific deprecation warnings for key == 'state_dict', key == 'seed', key == 'mechanisms'
for key, value in kwargs.items(): for key, value in kwargs.items():
if (key=='state_dict'): if key == 'state_dict':
self.initial_state = value self.initial_state = value
elif (key=='seed'): elif key == 'seed':
self.seeds = value self.seeds = value
elif (key=='mechanisms'): elif key == 'mechanisms':
self.partial_state_updates = value self.partial_state_updates = value
if (self.initial_state == {}): if self.initial_state == {}:
raise Exception('The initial conditions of the system have not been set') raise Exception('The initial conditions of the system have not been set')
@ -49,7 +49,7 @@ def append_configs(sim_configs, initial_state, seeds, raw_exogenous_states, env_
seeds=seeds, seeds=seeds,
exogenous_states=exogenous_states, exogenous_states=exogenous_states,
env_processes=env_processes, env_processes=env_processes,
partial_state_updates=partial_state_update_blocks partial_state_update_blocks=partial_state_update_blocks
) )
) )
elif isinstance(sim_configs, dict): elif isinstance(sim_configs, dict):
@ -60,7 +60,7 @@ def append_configs(sim_configs, initial_state, seeds, raw_exogenous_states, env_
seeds=seeds, seeds=seeds,
exogenous_states=exogenous_states, exogenous_states=exogenous_states,
env_processes=env_processes, env_processes=env_processes,
partial_state_updates=partial_state_update_blocks partial_state_update_blocks=partial_state_update_blocks
) )
) )
@ -98,10 +98,11 @@ class Processor:
self.apply_identity_funcs = id.apply_identity_funcs self.apply_identity_funcs = id.apply_identity_funcs
def create_matrix_field(self, partial_state_updates, key): def create_matrix_field(self, partial_state_updates, key):
if key == 'state_update_functions': if key == 'variables':
identity = self.state_identity identity = self.state_identity
elif key == 'policies': elif key == 'policies':
identity = self.policy_identity identity = self.policy_identity
df = pd.DataFrame(key_filter(partial_state_updates, key)) df = pd.DataFrame(key_filter(partial_state_updates, key))
col_list = self.apply_identity_funcs(identity, df, list(df.columns)) col_list = self.apply_identity_funcs(identity, df, list(df.columns))
if len(col_list) != 0: if len(col_list) != 0:
@ -127,13 +128,15 @@ class Processor:
def only_ep_handler(state_dict): def only_ep_handler(state_dict):
sdf_functions = [ sdf_functions = [
lambda sub_step, sL, s, _input: (k, v) for k, v in zip(state_dict.keys(), state_dict.values()) lambda var_dict, sub_step, sL, s, _input: (k, v) for k, v in zip(state_dict.keys(), state_dict.values())
] ]
sdf_values = [sdf_functions] sdf_values = [sdf_functions]
bdf_values = [[self.p_identity] * len(sdf_values)] bdf_values = [[self.p_identity] * len(sdf_values)]
return sdf_values, bdf_values return sdf_values, bdf_values
def sanitize_partial_state_updates(m): # backwards compatibility
def sanitize_partial_state_updates(partial_state_updates):
new_partial_state_updates = deepcopy(partial_state_updates)
# for backwards compatibility we accept the old keys # for backwards compatibility we accept the old keys
# ('behaviors' and 'states') and rename them # ('behaviors' and 'states') and rename them
def rename_keys(d): def rename_keys(d):
@ -142,24 +145,26 @@ class Processor:
except KeyError: except KeyError:
pass pass
try: try:
d['state_update_functions'] = d.pop('states') d['variables'] = d.pop('states')
except KeyError: except KeyError:
pass pass
# Also for backwards compatibility, we accept partial state update blocks both as list or dict # Also for backwards compatibility, we accept partial state update blocks both as list or dict
# No need for a deprecation warning as it's already raised by cadCAD.utils.key_filter # No need for a deprecation warning as it's already raised by cadCAD.utils.key_filter
if (type(m)==list): if (type(new_partial_state_updates)==list):
for v in m: for v in new_partial_state_updates:
rename_keys(v) rename_keys(v)
elif (type(m)==dict): elif (type(new_partial_state_updates)==dict):
for k, v in mechanisms.items(): for k, v in new_partial_state_updates.items():
rename_keys(v) rename_keys(v)
return
del partial_state_updates
return new_partial_state_updates
if len(partial_state_updates) != 0: if len(partial_state_updates) != 0:
sanitize_partial_state_updates(partial_state_updates) partial_state_updates = sanitize_partial_state_updates(partial_state_updates)
bdf = self.create_matrix_field(partial_state_updates, 'policies') bdf = self.create_matrix_field(partial_state_updates, 'policies')
sdf = self.create_matrix_field(partial_state_updates, 'state_update_functions') sdf = self.create_matrix_field(partial_state_updates, 'variables')
sdf_values, bdf_values = no_update_handler(bdf, sdf) sdf_values, bdf_values = no_update_handler(bdf, sdf)
zipped_list = list(zip(sdf_values, bdf_values)) zipped_list = list(zip(sdf_values, bdf_values))
else: else:

View File

@ -7,11 +7,12 @@ import pandas as pd
from cadCAD.utils import dict_filter, contains_type from cadCAD.utils import dict_filter, contains_type
# ToDo: Fix - Returns empty when partial_state_update is missing in Configuration
class TensorFieldReport: class TensorFieldReport:
def __init__(self, config_proc): def __init__(self, config_proc):
self.config_proc = config_proc self.config_proc = config_proc
def create_tensor_field(self, partial_state_updates, exo_proc, keys=['policies', 'state_update_functions']): def create_tensor_field(self, partial_state_updates, exo_proc, keys=['policies', 'variables']):
dfs = [self.config_proc.create_matrix_field(partial_state_updates, k) for k in keys] dfs = [self.config_proc.create_matrix_field(partial_state_updates, k) for k in keys]
df = pd.concat(dfs, axis=1) df = pd.concat(dfs, axis=1)
for es, i in zip(exo_proc, range(len(exo_proc))): for es, i in zip(exo_proc, range(len(exo_proc))):
@ -25,7 +26,7 @@ class TensorFieldReport:
# #
# #
def state_update(y, x): def state_update(y, x):
return lambda sub_step, sL, s, _input: (y, x) return lambda var_dict, sub_step, sL, s, _input: (y, x)
def bound_norm_random(rng, low, high): def bound_norm_random(rng, low, high):
@ -52,7 +53,7 @@ def time_step(dt_str, dt_format='%Y-%m-%d %H:%M:%S', _timedelta = tstep_delta):
ep_t_delta = timedelta(days=0, minutes=0, seconds=1) 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): def ep_time_step(s, dt_str, fromat_str='%Y-%m-%d %H:%M:%S', _timedelta = ep_t_delta):
if s['sub_step'] == 0: if s['substep'] == 0:
return time_step(dt_str, fromat_str, _timedelta) return time_step(dt_str, fromat_str, _timedelta)
else: else:
return dt_str return dt_str
@ -114,7 +115,7 @@ def sweep_states(state_type, states, in_config):
def exo_update_per_ts(ep): def exo_update_per_ts(ep):
@curried @curried
def ep_decorator(f, y, var_dict, sub_step, sL, s, _input): def ep_decorator(f, y, var_dict, sub_step, sL, s, _input):
if s['sub_step'] + 1 == 1: if s['substep'] + 1 == 1:
return f(var_dict, sub_step, sL, s, _input) return f(var_dict, sub_step, sL, s, _input)
else: else:
return y, s[y] return y, s[y]

View File

@ -1,45 +0,0 @@
from fn.op import foldr
from fn.func import curried
def get_base_value(datatype):
if datatype is str:
return ''
elif datatype is int:
return 0
elif datatype is list:
return []
return 0
def behavior_to_dict(v):
return dict(list(zip(map(lambda n: 'b' + str(n + 1), list(range(len(v)))), v)))
add = lambda a, b: a + b
@curried
def foldr_dict_vals(f, d):
return foldr(f)(list(d.values()))
def sum_dict_values():
return foldr_dict_vals(add)
@curried
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]))
else:
return target_dict[key]
key_set = set(list(d1.keys()) + list(d2.keys()))
return {k: f(set_base_value(d1, d2, k), set_base_value(d2, d1, k)) for k in key_set}
def dict_elemwise_sum():
return dict_op(add)

View File

@ -52,7 +52,7 @@ class Executor:
self.apply_env_proc(env_processes, last_in_copy, last_in_copy['timestep']) self.apply_env_proc(env_processes, last_in_copy, last_in_copy['timestep'])
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
sL.append(last_in_copy) sL.append(last_in_copy)
del last_in_copy del last_in_copy

View File

@ -75,7 +75,7 @@ def contains_type(_collection, type):
def drop_right(l, n): def drop_right(l, n):
return l[:len(l) - n] return l[:len(l) - n]
# backwards compatibility
def key_filter(l, keyname): def key_filter(l, keyname):
if (type(l) == list): if (type(l) == list):
return [v[keyname] for v in l] return [v[keyname] for v in l]

Binary file not shown.

Binary file not shown.

BIN
dist/cadCAD-0.2.tar.gz vendored

Binary file not shown.

View File

@ -14,8 +14,8 @@ setup(name='cadCAD',
version='0.2', version='0.2',
description="cadCAD: a differential games based simulation software package for research, validation, and \ description="cadCAD: a differential games based simulation software package for research, validation, and \
Computer Aided Design of economic systems", Computer Aided Design of economic systems",
long_description = long_description, long_description=long_description,
url='https://github.com/BlockScience/DiffyQ-cadCAD', url='https://github.com/BlockScience/DiffyQ-SimCAD',
author='Joshua E. Jodesty', author='Joshua E. Jodesty',
author_email='joshua@block.science', author_email='joshua@block.science',
# license='LICENSE', # license='LICENSE',

File diff suppressed because one or more lines are too long

View File

@ -2,7 +2,7 @@ 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 sweep_config, config1, config2 from simulations.validation import sweep_config, config1, config2, config4
from cadCAD import configs from cadCAD import configs
exec_mode = ExecutionMode() exec_mode = ExecutionMode()

View File

@ -98,20 +98,20 @@ 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' # 'timestep': '2018-10-01 15:16:24'
} }
raw_exogenous_states = { raw_exogenous_states = {
"s3": es3p1, "s3": es3p1,
"s4": es4p2, "s4": es4p2,
"timestep": es5p2 # "timestep": es5p2
} }
env_processes = { env_processes = {
"s3": env_a, "s3": env_a,
"s4": proc_trigger('2018-10-01 15:16:25', env_b) "s4": proc_trigger(1, env_b)
} }
@ -121,7 +121,7 @@ partial_state_update_block = {
"b1": p1m1, "b1": p1m1,
"b2": p2m1 "b2": p2m1
}, },
"states": { "variables": {
"s1": s1m1, "s1": s1m1,
"s2": s2m1 "s2": s2m1
} }
@ -131,7 +131,7 @@ partial_state_update_block = {
"b1": p1m2, "b1": p1m2,
"b2": p2m2 "b2": p2m2
}, },
"states": { "variables": {
"s1": s1m2, "s1": s1m2,
"s2": s2m2 "s2": s2m2
} }
@ -141,7 +141,7 @@ partial_state_update_block = {
"b1": p1m3, "b1": p1m3,
"b2": p2m3 "b2": p2m3
}, },
"states": { "variables": {
"s1": s1m3, "s1": s1m3,
"s2": s2m3 "s2": s2m3
} }
@ -163,5 +163,5 @@ append_configs(
seeds=seeds, seeds=seeds,
raw_exogenous_states=raw_exogenous_states, raw_exogenous_states=raw_exogenous_states,
env_processes=env_processes, env_processes=env_processes,
partial_state_updates=partial_state_update_block partial_state_update_blocks=partial_state_update_block
) )

View File

@ -97,20 +97,20 @@ 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' # 'timestep': '2018-10-01 15:16:24'
} }
raw_exogenous_states = { raw_exogenous_states = {
"s3": es3p1, "s3": es3p1,
"s4": es4p2, "s4": es4p2,
"timestep": es5p2 # "timestep": es5p2
} }
env_processes = { env_processes = {
"s3": proc_trigger('2018-10-01 15:16:25', env_a), "s3": proc_trigger(1, env_a),
"s4": proc_trigger('2018-10-01 15:16:25', env_b) "s4": proc_trigger(1, env_b)
} }
@ -120,7 +120,7 @@ partial_state_update_block = {
"b1": p1m1, "b1": p1m1,
# "b2": p2m1 # "b2": p2m1
}, },
"states": { "variables": {
"s1": s1m1, "s1": s1m1,
# "s2": s2m1 # "s2": s2m1
} }
@ -130,7 +130,7 @@ partial_state_update_block = {
"b1": p1m2, "b1": p1m2,
# "b2": p2m2 # "b2": p2m2
}, },
"states": { "variables": {
"s1": s1m2, "s1": s1m2,
# "s2": s2m2 # "s2": s2m2
} }
@ -140,7 +140,7 @@ partial_state_update_block = {
"b1": p1m3, "b1": p1m3,
"b2": p2m3 "b2": p2m3
}, },
"states": { "variables": {
"s1": s1m3, "s1": s1m3,
"s2": s2m3 "s2": s2m3
} }
@ -162,5 +162,5 @@ append_configs(
seeds=seeds, seeds=seeds,
raw_exogenous_states=raw_exogenous_states, raw_exogenous_states=raw_exogenous_states,
env_processes=env_processes, env_processes=env_processes,
partial_state_updates=partial_state_update_block partial_state_update_blocks=partial_state_update_block
) )

View File

@ -0,0 +1,142 @@
from decimal import Decimal
import numpy as np
from datetime import timedelta
from cadCAD.configuration import append_configs
from cadCAD.configuration.utils import proc_trigger, bound_norm_random, ep_time_step
from cadCAD.configuration.utils.parameterSweep import config_sim
seeds = {
'z': np.random.RandomState(1),
'a': np.random.RandomState(2),
'b': np.random.RandomState(3),
'c': np.random.RandomState(3)
}
# Policies per Mechanism
def p1m1(_g, step, sL, s):
return {'param1': 1}
def p2m1(_g, step, sL, s):
return {'param2': 4}
def p1m2(_g, step, sL, s):
return {'param1': 'a', 'param2': 2}
def p2m2(_g, step, sL, s):
return {'param1': 'b', 'param2': 4}
def p1m3(_g, step, sL, s):
return {'param1': ['c'], 'param2': np.array([10, 100])}
def p2m3(_g, step, sL, s):
return {'param1': ['d'], 'param2': np.array([20, 200])}
# Internal States per Mechanism
def s1m1(_g, step, sL, s, _input):
y = 's1'
x = _input['param1']
return (y, x)
def s2m1(_g, step, sL, s, _input):
y = 's2'
x = _input['param2']
return (y, x)
def s1m2(_g, step, sL, s, _input):
y = 's1'
x = _input['param1']
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 = _input['param1']
return (y, x)
def s2m3(_g, step, sL, s, _input):
y = 's2'
x = _input['param2']
return (y, x)
def s1m4(_g, step, sL, s, _input):
y = 's1'
x = [1]
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 = s['s3'] * bound_norm_random(seeds['a'], proc_one_coef_A, proc_one_coef_B)
return (y, x)
def es4p2(_g, step, sL, s, _input):
y = 's4'
x = s['s4'] * bound_norm_random(seeds['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(_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
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'
}
raw_exogenous_states = {
"s3": es3p1,
"s4": es4p2,
"timestamp": es5p2
}
env_processes = {
"s3": env_a,
"s4": proc_trigger('2018-10-01 15:16:25', env_b)
}
partial_state_update_block = [
]
sim_config = config_sim(
{
"N": 2,
"T": range(5),
}
)
append_configs(
sim_configs=sim_config,
initial_state=genesis_states,
seeds={},
raw_exogenous_states={},
env_processes={},
partial_state_update_blocks=partial_state_update_block
)

View File

@ -114,7 +114,7 @@ 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' # 'timestep': '2018-10-01 15:16:24'
} }
@ -122,13 +122,13 @@ genesis_states = {
raw_exogenous_states = { raw_exogenous_states = {
"s3": es3p1, "s3": es3p1,
"s4": es4p2, "s4": es4p2,
"timestep": es5p2 # "timestep": es5p2
} }
# ToDo: make env proc trigger field agnostic # ToDo: make env proc trigger field agnostic
# ToDo: input json into function renaming __name__ # ToDo: input json into function renaming __name__
triggered_env_b = proc_trigger('2018-10-01 15:16:25', env_b) triggered_env_b = proc_trigger(1, env_b)
env_processes = { env_processes = {
"s3": env_a, #sweep(beta, env_a), "s3": env_a, #sweep(beta, env_a),
"s4": triggered_env_b #rename('parameterized', triggered_env_b) #sweep(beta, triggered_env_b) "s4": triggered_env_b #rename('parameterized', triggered_env_b) #sweep(beta, triggered_env_b)
@ -149,7 +149,7 @@ partial_state_update_block = {
"b1": p1m1, "b1": p1m1,
"b2": p2m1 "b2": p2m1
}, },
"states": { "variables": {
"s1": s1m1, "s1": s1m1,
"s2": s2m1 "s2": s2m1
} }
@ -159,7 +159,7 @@ partial_state_update_block = {
"b1": p1m2, "b1": p1m2,
"b2": p2m2, "b2": p2m2,
}, },
"states": { "variables": {
"s1": s1m2, "s1": s1m2,
"s2": s2m2 "s2": s2m2
} }
@ -169,7 +169,7 @@ partial_state_update_block = {
"b1": p1m3, "b1": p1m3,
"b2": p2m3 "b2": p2m3
}, },
"states": { "variables": {
"s1": s1m3, "s1": s1m3,
"s2": s2m3 "s2": s2m3
} }
@ -192,5 +192,5 @@ append_configs(
seeds=seeds, seeds=seeds,
raw_exogenous_states=raw_exogenous_states, raw_exogenous_states=raw_exogenous_states,
env_processes=env_processes, env_processes=env_processes,
partial_state_updates=partial_state_update_block partial_state_update_blocks=partial_state_update_block
) )