From 964e3f7bc11a1479987c7bd791ab580f0cb15d8c Mon Sep 17 00:00:00 2001 From: "Joshua E. Jodesty" Date: Fri, 7 Jun 2019 10:40:45 -0400 Subject: [PATCH 01/21] test partially done --- cadCAD/configuration/utils/__init__.py | 13 +-- .../historical_state_access.py | 10 +- .../regression_tests/policy_aggregation.py | 5 +- simulations/regression_tests/tests.py | 36 +++++++ .../test_executions/policy_agg_test.py | 4 + testing/__init__.py | 0 testing/example.py | 20 ++++ testing/example2.py | 71 ++++++++++++++ testing/generic_test.py | 39 ++++++++ .../system_models/historical_state_access.py | 97 +++++++++++++++++++ testing/system_models/policy_aggregation.py | 90 +++++++++++++++++ testing/tests/__init__.py | 0 testing/tests/historical_state_access.py | 84 ++++++++++++++++ testing/tests/policy_aggregation.py | 32 ++++++ testing/utils.py | 28 ++++++ 15 files changed, 517 insertions(+), 12 deletions(-) create mode 100644 simulations/regression_tests/tests.py create mode 100644 testing/__init__.py create mode 100644 testing/example.py create mode 100644 testing/example2.py create mode 100644 testing/generic_test.py create mode 100644 testing/system_models/historical_state_access.py create mode 100644 testing/system_models/policy_aggregation.py create mode 100644 testing/tests/__init__.py create mode 100644 testing/tests/historical_state_access.py create mode 100644 testing/tests/policy_aggregation.py create mode 100644 testing/utils.py diff --git a/cadCAD/configuration/utils/__init__.py b/cadCAD/configuration/utils/__init__.py index 3efdcc3..8c16b8c 100644 --- a/cadCAD/configuration/utils/__init__.py +++ b/cadCAD/configuration/utils/__init__.py @@ -202,19 +202,20 @@ def genereate_psubs(policy_grid, states_grid, policies, state_updates): return PSUBS -def access_block(sH, y, psu_block_offset, exculsion_list=[]): - exculsion_list += [y] +# ToDo: DO NOT filter sH for every state/policy update. Requires a consumable sH (new sH) +def access_block(state_history, target_field, psu_block_offset, exculsion_list=[]): + exculsion_list += [target_field] def filter_history(key_list, sH): filter = lambda key_list: \ lambda d: {k: v for k, v in d.items() if k not in key_list} return list(map(filter(key_list), sH)) if psu_block_offset < -1: - if len(sH) >= abs(psu_block_offset): - return filter_history(exculsion_list, sH[psu_block_offset]) + if len(state_history) >= abs(psu_block_offset): + return filter_history(exculsion_list, state_history[psu_block_offset]) else: return [] - elif psu_block_offset < 0: - return filter_history(exculsion_list, sH[psu_block_offset]) + elif psu_block_offset == -1: + return filter_history(exculsion_list, state_history[psu_block_offset]) else: return [] \ No newline at end of file diff --git a/simulations/regression_tests/historical_state_access.py b/simulations/regression_tests/historical_state_access.py index 67dce76..08382ee 100644 --- a/simulations/regression_tests/historical_state_access.py +++ b/simulations/regression_tests/historical_state_access.py @@ -7,9 +7,15 @@ exclusion_list = ['nonexsistant', 'last_x', '2nd_to_last_x', '3rd_to_last_x', '4 # Policies per Mechanism # WARNING: DO NOT delete elements from sH - +# state_history, target_field, psu_block_offset, exculsion_list def last_update(_g, substep, sH, s): - return {"last_x": access_block(sH, "last_x", -1, exclusion_list)} + return {"last_x": access_block( + state_history=sH, + target_field="last_x", + psu_block_offset=-1, + exculsion_list=exclusion_list + ) + } policies["last_x"] = last_update def second2last_update(_g, substep, sH, s): diff --git a/simulations/regression_tests/policy_aggregation.py b/simulations/regression_tests/policy_aggregation.py index f5e3916..a81ac07 100644 --- a/simulations/regression_tests/policy_aggregation.py +++ b/simulations/regression_tests/policy_aggregation.py @@ -1,4 +1,3 @@ -import numpy as np from cadCAD.configuration import append_configs from cadCAD.configuration.utils import config_sim @@ -73,14 +72,12 @@ sim_config = config_sim( } ) - - # Aggregation == Reduce Map / Reduce Map Aggregation -# ToDo: subsequent functions should accept the entire datastructure # using env functions (include in reg test using / for env proc) append_configs( sim_configs=sim_config, initial_state=genesis_states, partial_state_update_blocks=partial_state_update_block, + # ToDo: subsequent functions should include policy dict for access to each policy (i.e shouldnt be a map) policy_ops=[lambda a, b: a + b, lambda y: y * 2] # Default: lambda a, b: a + b ToDO: reduction function requires high lvl explanation ) \ No newline at end of file diff --git a/simulations/regression_tests/tests.py b/simulations/regression_tests/tests.py new file mode 100644 index 0000000..3226c62 --- /dev/null +++ b/simulations/regression_tests/tests.py @@ -0,0 +1,36 @@ +import unittest + +import pandas as pd +# from tabulate import tabulate +from cadCAD.engine import ExecutionMode, ExecutionContext, Executor +from simulations.regression_tests import policy_aggregation +from cadCAD import configs + +exec_mode = ExecutionMode() +first_config = configs # only contains config1 +single_proc_ctx = ExecutionContext(context=exec_mode.single_proc) +run = Executor(exec_context=single_proc_ctx, configs=first_config) +raw_result, tensor_field = run.execute() +result = pd.DataFrame(raw_result) + +class TestStringMethods(unittest.TestCase): + def __init__(self, result: pd.DataFrame, tensor_field: pd.DataFrame) -> None: + self.result = result + self.tensor_field = tensor_field + + def test_upper(self): + self.assertEqual('foo'.upper(), 'FOO') + + def test_isupper(self): + self.assertTrue('FOO'.isupper()) + self.assertFalse('Foo'.isupper()) + + def test_split(self): + s = 'hello world' + self.assertEqual(s.split(), ['hello', 'world']) + # check that s.split fails when the separator is not a string + with self.assertRaises(TypeError): + s.split(2) + +if __name__ == '__main__': + unittest.main() \ No newline at end of file diff --git a/simulations/test_executions/policy_agg_test.py b/simulations/test_executions/policy_agg_test.py index ec6d564..f1da13f 100644 --- a/simulations/test_executions/policy_agg_test.py +++ b/simulations/test_executions/policy_agg_test.py @@ -1,9 +1,12 @@ +from pprint import pprint + 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.regression_tests import policy_aggregation from cadCAD import configs +from testing.utils import generate_assertions exec_mode = ExecutionMode() @@ -15,6 +18,7 @@ run = Executor(exec_context=single_proc_ctx, configs=first_config) raw_result, tensor_field = run.execute() result = pd.DataFrame(raw_result) + print() print("Tensor Field: config1") print(tabulate(tensor_field, headers='keys', tablefmt='psql')) diff --git a/testing/__init__.py b/testing/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/testing/example.py b/testing/example.py new file mode 100644 index 0000000..09ee3aa --- /dev/null +++ b/testing/example.py @@ -0,0 +1,20 @@ +import unittest + +class TestStringMethods(unittest.TestCase): + + def test_upper(self): + self.assertEqual('foo'.upper(), 'FOO') + + def test_isupper(self): + self.assertTrue('FOO'.isupper()) + self.assertFalse('Foo'.isupper()) + + def test_split(self): + s = 'hello world' + self.assertEqual(s.split(), ['hello', 'world']) + # check that s.split fails when the separator is not a string + with self.assertRaises(TypeError): + s.split(2) + +if __name__ == '__main__': + unittest.main() \ No newline at end of file diff --git a/testing/example2.py b/testing/example2.py new file mode 100644 index 0000000..081ec32 --- /dev/null +++ b/testing/example2.py @@ -0,0 +1,71 @@ +from functools import reduce + +import pandas as pd +import unittest +from parameterized import parameterized +from tabulate import tabulate + +from testing.system_models.policy_aggregation import run +from testing.generic_test import make_generic_test +from testing.utils import generate_assertions_df + +raw_result, tensor_field = run.execute() +result = pd.DataFrame(raw_result) + +expected_results = { + (1, 0, 0): {'policies': {}, 's1': 0}, + (1, 1, 1): {'policies': {'policy1': 2, 'policy2': 4}, 's1': 500}, + (1, 1, 2): {'policies': {'policy1': 8, 'policy2': 8}, 's1': 2}, + (1, 1, 3): {'policies': {'policy1': 4, 'policy2': 8, 'policy3': 12}, 's1': 3}, + (1, 2, 1): {'policies': {'policy1': 2, 'policy2': 4}, 's1': 4}, + (1, 2, 2): {'policies': {'policy1': 8, 'policy2': 8}, 's1': 5}, + (1, 2, 3): {'policies': {'policy1': 4, 'policy2': 8, 'policy3': 12}, 's1': 6}, + (1, 3, 1): {'policies': {'policy1': 2, 'policy2': 4}, 's1': 7}, + (1, 3, 2): {'policies': {'policy1': 8, 'policy2': 8}, 's1': 8}, + (1, 3, 3): {'policies': {'policy1': 4, 'policy2': 8, 'policy3': 12}, 's1': 9} +} + +params = [["policy_aggregation", result, expected_results, ['policies', 's1']]] + + +class TestSequence(unittest.TestCase): + @parameterized.expand(params) + def test_validate_results(self, name, result_df, expected_reults, target_cols): + # alt for (*) Exec Debug mode + tested_df = generate_assertions_df(result_df, expected_reults, target_cols) + + erroneous = tested_df[(tested_df['test'] == False)] + for index, row in erroneous.iterrows(): + expected = expected_reults[(row['run'], row['timestep'], row['substep'])] + unexpected = {k: expected[k] for k in expected if k in row and expected[k] != row[k]} + for key in unexpected.keys(): + erroneous[f"invalid_{key}"] = unexpected[key] + # etc. + + # def etc. + + print() + print(tabulate(erroneous, headers='keys', tablefmt='psql')) + + self.assertEqual(reduce(lambda a, b: a and b, tested_df['test']), True) + + s = 'hello world' + # self.assertEqual(s.split(), 1) + # # check that s.split fails when the separator is not a string + # with self.assertRaises(AssertionError): + # tested_df[(tested_df['test'] == False)] + # erroneous = tested_df[(tested_df['test'] == False)] + # for index, row in erroneous.iterrows(): + # expected = expected_reults[(row['run'], row['timestep'], row['substep'])] + # unexpected = {k: expected[k] for k in expected if k in row and expected[k] != row[k]} + # for key in unexpected.keys(): + # erroneous[f"invalid_{key}"] = unexpected[key] + # # etc. + # + # # def etc. + # + # print() + # print(tabulate(erroneous, headers='keys', tablefmt='psql')) + +if __name__ == '__main__': + unittest.main() \ No newline at end of file diff --git a/testing/generic_test.py b/testing/generic_test.py new file mode 100644 index 0000000..19b562c --- /dev/null +++ b/testing/generic_test.py @@ -0,0 +1,39 @@ +import unittest +from parameterized import parameterized +from functools import reduce +from tabulate import tabulate +from testing.utils import generate_assertions_df + +# ToDo: Exec Debug mode (*) for which state and policy updates are validated during runtime using `expected_results` +# EXAMPLE: ('state_test' T/F, 'policy_test' T/F) +# ToDo: (Sys Model Config) give `expected_results to` `Configuration` for Exec Debug mode (*) +# ToDo: (expected_results) Function to generate sys metrics keys using system model config +# ToDo: (expected_results) Function to generate target_vals given user input (apply fancy validation lib later on) + + +# ToDo: Use self.assertRaises(AssertionError) + + +def make_generic_test(params): + class TestSequence(unittest.TestCase): + @parameterized.expand(params) + def test_validate_results(self, name, result_df, expected_reults, target_cols): + # alt for (*) Exec Debug mode + tested_df = generate_assertions_df(result_df, expected_reults, target_cols) + erroneous = tested_df[(tested_df['test'] == False)] + if erroneous.empty is False: + for index, row in erroneous.iterrows(): + expected = expected_reults[(row['run'], row['timestep'], row['substep'])] + unexpected = {k: expected[k] for k in expected if k in row and expected[k] != row[k]} + for key in unexpected.keys(): + erroneous[f"invalid_{key}"] = unexpected[key] + # etc. + + print() + print(tabulate(erroneous, headers='keys', tablefmt='psql')) + + self.assertTrue(reduce(lambda a, b: a and b, tested_df['test'])) + + # def etc. + + return TestSequence diff --git a/testing/system_models/historical_state_access.py b/testing/system_models/historical_state_access.py new file mode 100644 index 0000000..839a826 --- /dev/null +++ b/testing/system_models/historical_state_access.py @@ -0,0 +1,97 @@ +from cadCAD.configuration import append_configs +from cadCAD.configuration.utils import config_sim, access_block +from cadCAD.engine import ExecutionMode, ExecutionContext, Executor +from cadCAD import configs + + +policies, variables = {}, {} +exclusion_list = ['nonexsistant', 'last_x', '2nd_to_last_x', '3rd_to_last_x', '4th_to_last_x'] + +# Policies per Mechanism + +# WARNING: DO NOT delete elements from sH +# state_history, target_field, psu_block_offset, exculsion_list +def last_update(_g, substep, sH, s): + return {"last_x": access_block( + state_history=sH, + target_field="last_x", + psu_block_offset=-1, + exculsion_list=exclusion_list + ) + } +policies["last_x"] = last_update + +def second2last_update(_g, substep, sH, s): + return {"2nd_to_last_x": access_block(sH, "2nd_to_last_x", -2, exclusion_list)} +policies["2nd_to_last_x"] = second2last_update + + +# Internal States per Mechanism + +# WARNING: DO NOT delete elements from sH +def add(y, x): + return lambda _g, substep, sH, s, _input: (y, s[y] + x) +variables['x'] = add('x', 1) + +# last_partial_state_update_block +def nonexsistant(_g, substep, sH, s, _input): + return 'nonexsistant', access_block(sH, "nonexsistant", 0, exclusion_list) +variables['nonexsistant'] = nonexsistant + +# last_partial_state_update_block +def last_x(_g, substep, sH, s, _input): + return 'last_x', _input["last_x"] +variables['last_x'] = last_x + +# 2nd to last partial state update block +def second_to_last_x(_g, substep, sH, s, _input): + return '2nd_to_last_x', _input["2nd_to_last_x"] +variables['2nd_to_last_x'] = second_to_last_x + +# 3rd to last partial state update block +def third_to_last_x(_g, substep, sH, s, _input): + return '3rd_to_last_x', access_block(sH, "3rd_to_last_x", -3, exclusion_list) +variables['3rd_to_last_x'] = third_to_last_x + +# 4th to last partial state update block +def fourth_to_last_x(_g, substep, sH, s, _input): + return '4th_to_last_x', access_block(sH, "4th_to_last_x", -4, exclusion_list) +variables['4th_to_last_x'] = fourth_to_last_x + + +genesis_states = { + 'x': 0, + 'nonexsistant': [], + 'last_x': [], + '2nd_to_last_x': [], + '3rd_to_last_x': [], + '4th_to_last_x': [] +} + +PSUB = { + "policies": policies, + "variables": variables +} + +partial_state_update_block = { + "PSUB1": PSUB, + "PSUB2": PSUB, + "PSUB3": PSUB +} + +sim_config = config_sim( + { + "N": 1, + "T": range(3), + } +) + +append_configs( + sim_configs=sim_config, + initial_state=genesis_states, + partial_state_update_blocks=partial_state_update_block +) + +exec_mode = ExecutionMode() +single_proc_ctx = ExecutionContext(context=exec_mode.single_proc) +run = Executor(exec_context=single_proc_ctx, configs=configs) diff --git a/testing/system_models/policy_aggregation.py b/testing/system_models/policy_aggregation.py new file mode 100644 index 0000000..aae9234 --- /dev/null +++ b/testing/system_models/policy_aggregation.py @@ -0,0 +1,90 @@ +from cadCAD.configuration import append_configs +from cadCAD.configuration.utils import config_sim +from cadCAD.engine import ExecutionMode, ExecutionContext, Executor +from cadCAD import configs + + +# Policies per Mechanism +def p1m1(_g, step, sL, s): + return {'policy1': 1} +def p2m1(_g, step, sL, s): + return {'policy2': 2} + +def p1m2(_g, step, sL, s): + return {'policy1': 2, 'policy2': 2} +def p2m2(_g, step, sL, s): + return {'policy1': 2, 'policy2': 2} + +def p1m3(_g, step, sL, s): + return {'policy1': 1, 'policy2': 2, 'policy3': 3} +def p2m3(_g, step, sL, s): + return {'policy1': 1, 'policy2': 2, 'policy3': 3} + + +# Internal States per Mechanism +def add(y, x): + return lambda _g, step, sH, s, _input: (y, s[y] + x) + +def policies(_g, step, sH, s, _input): + y = 'policies' + x = _input + return (y, x) + + +# Genesis States +genesis_states = { + 'policies': {}, + 's1': 0 +} + +variables = { + 's1': add('s1', 1), + "policies": policies +} + +partial_state_update_block = { + "m1": { + "policies": { + "p1": p1m1, + "p2": p2m1 + }, + "variables": variables + }, + "m2": { + "policies": { + "p1": p1m2, + "p2": p2m2 + }, + "variables": variables + }, + "m3": { + "policies": { + "p1": p1m3, + "p2": p2m3 + }, + "variables": variables + } +} + + +sim_config = config_sim( + { + "N": 1, + "T": range(3), + } +) + + +# Aggregation == Reduce Map / Reduce Map Aggregation +# ToDo: subsequent functions should accept the entire datastructure +# using env functions (include in reg test using / for env proc) +append_configs( + sim_configs=sim_config, + initial_state=genesis_states, + partial_state_update_blocks=partial_state_update_block, + policy_ops=[lambda a, b: a + b, lambda y: y * 2] # Default: lambda a, b: a + b ToDO: reduction function requires high lvl explanation +) + +exec_mode = ExecutionMode() +single_proc_ctx = ExecutionContext(context=exec_mode.single_proc) +run = Executor(exec_context=single_proc_ctx, configs=configs) diff --git a/testing/tests/__init__.py b/testing/tests/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/testing/tests/historical_state_access.py b/testing/tests/historical_state_access.py new file mode 100644 index 0000000..4ab145f --- /dev/null +++ b/testing/tests/historical_state_access.py @@ -0,0 +1,84 @@ +import unittest +import pandas as pd +from tabulate import tabulate + +from testing.generic_test import make_generic_test +from testing.system_models.historical_state_access import run +from testing.utils import generate_assertions_df + +raw_result, tensor_field = run.execute() +result = pd.DataFrame(raw_result) + +expected_results = { + (1, 0, 0): {'x': 0, 'nonexsistant': [], 'last_x': [], '2nd_to_last_x': [], '3rd_to_last_x': [], '4th_to_last_x': []}, + (1, 1, 1): {'x': 1, + 'nonexsistant': [], + 'last_x': [{'x': 0, 'run': 1, 'substep': 0, 'timestep': 0}], + '2nd_to_last_x': [], + '3rd_to_last_x': [], + '4th_to_last_x': []}, + (1, 1, 2): {'x': 2, + 'nonexsistant': [], + 'last_x': [{'x': 0, 'run': 1, 'substep': 0, 'timestep': 0}], + '2nd_to_last_x': [], + '3rd_to_last_x': [], + '4th_to_last_x': []}, + (1, 1, 3): {'x': 3, + 'nonexsistant': [], + 'last_x': [{'x': 0, 'run': 1, 'substep': 0, 'timestep': 0}], + '2nd_to_last_x': [], + '3rd_to_last_x': [], + '4th_to_last_x': []}, + (1, 2, 1): {'x': 4, + 'nonexsistant': [], + 'last_x': [{'x': 1, 'run': 1, 'substep': 1, 'timestep': 1}, {'x': 2, 'run': 1, 'substep': 2, 'timestep': 1}, {'x': 3, 'run': 1, 'substep': 3, 'timestep': 1}], + '2nd_to_last_x': [{'x': 0, 'run': 1, 'substep': 0, 'timestep': 0}], + '3rd_to_last_x': [], + '4th_to_last_x': []}, + (1, 2, 2): {'x': 5, + 'nonexsistant': [], + 'last_x': [{'x': 1, 'run': 1, 'substep': 1, 'timestep': 1}, {'x': 2, 'run': 1, 'substep': 2, 'timestep': 1}, {'x': 3, 'run': 1, 'substep': 3, 'timestep': 1}], + '2nd_to_last_x': [{'x': 0, 'run': 1, 'substep': 0, 'timestep': 0}], + '3rd_to_last_x': [], + '4th_to_last_x': []}, + (1, 2, 3): {'x': 6, + 'nonexsistant': [], + 'last_x': [{'x': 1, 'run': 1, 'substep': 1, 'timestep': 1}, {'x': 2, 'run': 1, 'substep': 2, 'timestep': 1}, {'x': 3, 'run': 1, 'substep': 3, 'timestep': 1}], + '2nd_to_last_x': [{'x': 0, 'run': 1, 'substep': 0, 'timestep': 0}], + '3rd_to_last_x': [], + '4th_to_last_x': []}, + (1, 3, 1): {'x': 7, + 'nonexsistant': [], + 'last_x': [{'x': 4, 'run': 1, 'substep': 1, 'timestep': 2}, {'x': 5, 'run': 1, 'substep': 2, 'timestep': 2}, {'x': 6, 'run': 1, 'substep': 3, 'timestep': 2}], + '2nd_to_last_x': [{'x': 1, 'run': 1, 'substep': 1, 'timestep': 1}, {'x': 2, 'run': 1, 'substep': 2, 'timestep': 1}, {'x': 3, 'run': 1, 'substep': 3, 'timestep': 1}], + '3rd_to_last_x': [{'x': 0, 'run': 1, 'substep': 0, 'timestep': 0}], + '4th_to_last_x': []}, + (1, 3, 2): {'x': 8, + 'nonexsistant': [], + 'last_x': [{'x': 4, 'run': 1, 'substep': 1, 'timestep': 2}, {'x': 5, 'run': 1, 'substep': 2, 'timestep': 2}, {'x': 6, 'run': 1, 'substep': 3, 'timestep': 2}], + '2nd_to_last_x': [{'x': 1, 'run': 1, 'substep': 1, 'timestep': 1}, {'x': 2, 'run': 1, 'substep': 2, 'timestep': 1}, {'x': 3, 'run': 1, 'substep': 3, 'timestep': 1}], + '3rd_to_last_x': [{'x': 0, 'run': 1, 'substep': 0, 'timestep': 0}], + '4th_to_last_x': []}, + (1, 3, 3): {'x': 9, + 'nonexsistant': [], + 'last_x': [{'x': 4, 'run': 1, 'substep': 1, 'timestep': 2}, {'x': 5, 'run': 1, 'substep': 2, 'timestep': 2}, {'x': 6, 'run': 1, 'substep': 3, 'timestep': 2}], + '2nd_to_last_x': [{'x': 1, 'run': 1, 'substep': 1, 'timestep': 1}, {'x': 2, 'run': 1, 'substep': 2, 'timestep': 1}, {'x': 3, 'run': 1, 'substep': 3, 'timestep': 1}], + '3rd_to_last_x': [{'x': 0, 'run': 1, 'substep': 0, 'timestep': 0}], + '4th_to_last_x': []} +} + +params = [["historical_state_access", result, expected_results, + ['x', 'nonexsistant', 'last_x', '2nd_to_last_x', '3rd_to_last_x', '4th_to_last_x']] + ] +# df = generate_assertions_df(result, expected_results, +# ['x', 'nonexsistant', 'last_x', '2nd_to_last_x', '3rd_to_last_x', '4th_to_last_x'] +# ) +# print(tabulate(df, headers='keys', tablefmt='psql')) + + +class GenericTest(make_generic_test(params)): + pass + + +if __name__ == '__main__': + unittest.main() diff --git a/testing/tests/policy_aggregation.py b/testing/tests/policy_aggregation.py new file mode 100644 index 0000000..4be0da4 --- /dev/null +++ b/testing/tests/policy_aggregation.py @@ -0,0 +1,32 @@ +import unittest +import pandas as pd +from testing.generic_test import make_generic_test +from testing.system_models.policy_aggregation import run + +raw_result, tensor_field = run.execute() +result = pd.DataFrame(raw_result) + +expected_results = { + (1, 0, 0): {'policies': {}, 's1': 0}, + (1, 1, 1): {'policies': {'policy1': 2, 'policy2': 4}, 's1': 500}, + (1, 1, 2): {'policies': {'policy1': 8, 'policy2': 8}, 's1': 2}, + (1, 1, 3): {'policies': {'policy1': 4, 'policy2': 8, 'policy3': 12}, 's1': 3}, + (1, 2, 1): {'policies': {'policy1': 2, 'policy2': 4}, 's1': 4}, + (1, 2, 2): {'policies': {'policy1': 8, 'policy2': 8}, 's1': 5}, + (1, 2, 3): {'policies': {'policy1': 4, 'policy2': 8, 'policy3': 12}, 's1': 6}, + (1, 3, 1): {'policies': {'policy1': 2, 'policy2': 4}, 's1': 7}, + (1, 3, 2): {'policies': {'policy1': 8, 'policy2': 8}, 's1': 8}, + (1, 3, 3): {'policies': {'policy1': 4, 'policy2': 8, 'policy3': 12}, 's1': 9} +} + +params = [["policy_aggregation", result, expected_results, ['policies', 's1']]] +# df = generate_assertions_df(result, expected_results, ['policies', 's1']) +# print(tabulate(df, headers='keys', tablefmt='psql')) + + +class GenericTest(make_generic_test(params)): + pass + + +if __name__ == '__main__': + unittest.main() diff --git a/testing/utils.py b/testing/utils.py new file mode 100644 index 0000000..62dc439 --- /dev/null +++ b/testing/utils.py @@ -0,0 +1,28 @@ +def gen_metric_row(row): + return ((row['run'], row['timestep'], row['substep']), {'s1': row['s1'], 'policies': row['policies']}) + +def gen_metric_row(row): + return { + 'run': row['run'], + 'timestep': row['timestep'], + 'substep': row['substep'], + 's1': row['s1'], + 'policies': row['policies'] + } + +def gen_metric_dict(df): + return [gen_metric_row(row) for index, row in df.iterrows()] + +def generate_assertions_df(df, expected_results, target_cols): + def df_filter(run, timestep, substep): + return df[ + (df['run'] == run) & (df['timestep'] == timestep) & (df['substep'] == substep) + ][target_cols].to_dict(orient='records')[0] + + df['test'] = df.apply( + lambda x: \ + df_filter(x['run'], x['timestep'], x['substep']) == expected_results[(x['run'], x['timestep'], x['substep'])] + , axis=1 + ) + + return df \ No newline at end of file From c55e43392026ff99919f54953879c30e8c73e3e0 Mon Sep 17 00:00:00 2001 From: "Joshua E. Jodesty" Date: Fri, 19 Jul 2019 10:59:05 -0400 Subject: [PATCH 02/21] docs pending review --- README.md | 38 ++- .../configuration/utils/userDefinedObject.py | 18 +- cadCAD/engine/simulation.py | 36 +++ cadCAD/utils/__init__.py | 2 - documentation/examples/__init__.py | 0 documentation/examples/example_1.py | 45 ++++ .../examples/historical_state_access.py | 111 +++++++++ documentation/examples/param_sweep.py | 116 +++++++++ documentation/examples/policy_aggregation.py | 98 ++++++++ documentation/examples/sys_model_A.py | 159 +++++++++++++ documentation/examples/sys_model_AB_exec.py | 24 ++ documentation/examples/sys_model_A_exec.py | 22 ++ documentation/examples/sys_model_B.py | 147 ++++++++++++ documentation/examples/sys_model_B_exec.py | 23 ++ documentation/execution.md | 71 ++++++ documentation/historical_state_access.md | 97 ++++++++ documentation/param_sweep.md | 68 ++++++ documentation/policy_agg.md | 60 +++++ documentation/sys_model_config.md | 220 ++++++++++++++++++ simulations/regression_tests/config1.py | 17 +- simulations/regression_tests/config2.py | 5 +- simulations/regression_tests/udo.py | 9 +- simulations/test_executions/config1_test.py | 4 +- .../historical_state_access_test.py | 4 +- .../test_executions/policy_agg_test.py | 2 - simulations/test_executions/udo_test.py | 8 +- testing/generic_test.py | 60 +++-- testing/system_models/__init__.py | 0 testing/system_models/external_dataset.py | 67 ++++++ .../system_models/historical_state_access.py | 4 +- testing/system_models/param_sweep.py | 110 +++++++++ testing/system_models/policy_aggregation.py | 6 +- testing/system_models/udo.py | 185 +++++++++++++++ testing/tests/external_test.py | 127 ++++++++++ testing/tests/historical_state_access.py | 84 +++++-- testing/tests/multi_config_test.py | 56 +++++ testing/tests/param_sweep.py | 85 +++++++ testing/tests/policy_aggregation.py | 19 +- testing/tests/udo.py | 39 ++++ testing/utils.py | 41 ++-- 40 files changed, 2180 insertions(+), 107 deletions(-) create mode 100644 documentation/examples/__init__.py create mode 100644 documentation/examples/example_1.py create mode 100644 documentation/examples/historical_state_access.py create mode 100644 documentation/examples/param_sweep.py create mode 100644 documentation/examples/policy_aggregation.py create mode 100644 documentation/examples/sys_model_A.py create mode 100644 documentation/examples/sys_model_AB_exec.py create mode 100644 documentation/examples/sys_model_A_exec.py create mode 100644 documentation/examples/sys_model_B.py create mode 100644 documentation/examples/sys_model_B_exec.py create mode 100644 documentation/execution.md create mode 100644 documentation/historical_state_access.md create mode 100644 documentation/param_sweep.md create mode 100644 documentation/policy_agg.md create mode 100644 documentation/sys_model_config.md create mode 100644 testing/system_models/__init__.py create mode 100644 testing/system_models/external_dataset.py create mode 100644 testing/system_models/param_sweep.py create mode 100644 testing/system_models/udo.py create mode 100644 testing/tests/external_test.py create mode 100644 testing/tests/multi_config_test.py create mode 100644 testing/tests/param_sweep.py create mode 100644 testing/tests/udo.py diff --git a/README.md b/README.md index 0719875..f919ca9 100644 --- a/README.md +++ b/README.md @@ -4,25 +4,41 @@ **Description:** -cadCAD is a differential games based simulation software package for research, validation, and Computer \ -Aided Design of economic systems. An economic system is treated as a state based model and defined through a \ -set of endogenous and exogenous state variables which are updated through mechanisms and environmental \ -processes, respectively. Behavioral models, which may be deterministic or stochastic, provide the evolution of \ -the system within the action space of the mechanisms. Mathematical formulations of these economic games \ -treat agent utility as derived from state rather than direct from action, creating a rich dynamic modeling framework. - -Simulations may be run with a range of initial conditions and parameters for states, behaviors, mechanisms, \ -and environmental processes to understand and visualize network behavior under various conditions. Support for \ -A/B testing policies, monte carlo analysis and other common numerical methods is provided. +cadCAD (complex adaptive systems computer-aided design) is a python based, unified modeling framework for stochastic +dynamical systems and differential games for research, validation, and Computer Aided Design of economic systems created +by BlockScience. It is capable of modeling systems at all levels of abstraction from Agent Based Modeling (ABM) to +System Dynamics (SD), and enabling smooth integration of computational social science simulations with empirical data +science workflows. +An economic system is treated as a state-based model and defined through a set of endogenous and exogenous state +variables which are updated through mechanisms and environmental processes, respectively. Behavioral models, which may +be deterministic or stochastic, provide the evolution of the system within the action space of the mechanisms. +Mathematical formulations of these economic games treat agent utility as derived from the state rather than direct from +an action, creating a rich, dynamic modeling framework. Simulations may be run with a range of initial conditions and +parameters for states, behaviors, mechanisms, and environmental processes to understand and visualize network behavior +under various conditions. Support for A/B testing policies, Monte Carlo analysis, and other common numerical methods is +provided. + + +In essence, cadCAD tool allows us to represent a company’s or community’s current business model along with a desired +future state and helps make informed, rigorously tested decisions on how to get from today’s stage to the future state. +It allows us to use code to solidify our conceptualized ideas and see if the outcome meets our expectations. We can +iteratively refine our work until we have constructed a model that closely reflects reality at the start of the model, +and see how it evolves. We can then use these results to inform business decisions. + +#### Simulation Instructional: +* ##### [System Model Configuration](link) +* ##### [System Simulation Execution](link) + +#### Installation: **1. Install Dependencies:** **Option A:** Package Repository Access ***IMPORTANT NOTE:*** Tokens are issued to and meant to be used by trial users and BlockScience employees **ONLY**. Replace \ with an issued token in the script below. ```bash -pip3 install pandas pathos fn tabulate +pip3 install pandas pathos fn funcy tabulate pip3 install cadCAD --extra-index-url https://@repo.fury.io/blockscience/ ``` diff --git a/cadCAD/configuration/utils/userDefinedObject.py b/cadCAD/configuration/utils/userDefinedObject.py index c1f532c..4ced71f 100644 --- a/cadCAD/configuration/utils/userDefinedObject.py +++ b/cadCAD/configuration/utils/userDefinedObject.py @@ -5,7 +5,6 @@ from pandas.core.frame import DataFrame from cadCAD.utils import SilentDF - def val_switch(v): if isinstance(v, DataFrame) is True: return SilentDF(v) @@ -18,7 +17,7 @@ class udcView(object): self.masked_members = masked_members # returns dict to dataframe - # def __repr__(self): + def __repr__(self): members = {} variables = { @@ -26,9 +25,20 @@ class udcView(object): if str(type(v)) != "" and k not in self.masked_members # and isinstance(v, DataFrame) is not True } members['methods'] = [k for k, v in self.__dict__.items() if str(type(v)) == ""] + members.update(variables) return f"{members}" #[1:-1] + # def __repr__(self): + # members = {} + # variables = { + # k: val_switch(v) for k, v in self.__dict__.items() + # if str(type(v)) != "" and k not in self.masked_members and k == 'x' # and isinstance(v, DataFrame) is not True + # } + # + # members.update(variables) + # return f"{members}" #[1:-1] + class udcBroker(object): def __init__(self, obj, function_filter=['__init__']): @@ -36,7 +46,8 @@ class udcBroker(object): funcs = dict(getmembers(obj, ismethod)) filtered_functions = {k: v for k, v in funcs.items() if k not in function_filter} d['obj'] = obj - d.update(deepcopy(vars(obj))) # somehow is enough + # d.update(deepcopy(vars(obj))) # somehow is enough + d.update(vars(obj)) # somehow is enough d.update(filtered_functions) self.members_dict = d @@ -57,4 +68,3 @@ def UDO(udo, masked_members=['obj']): def udoPipe(obj_view): return UDO(obj_view.obj, obj_view.masked_members) - diff --git a/cadCAD/engine/simulation.py b/cadCAD/engine/simulation.py index 8a5c5df..1823a34 100644 --- a/cadCAD/engine/simulation.py +++ b/cadCAD/engine/simulation.py @@ -115,12 +115,48 @@ class Executor: last_in_obj: Dict[str, Any] = deepcopy(sL[-1]) _input: Dict[str, Any] = self.policy_update_exception(self.get_policy_input(sweep_dict, sub_step, sH, last_in_obj, policy_funcs)) + # ToDo: add env_proc generator to `last_in_copy` iterator as wrapper function # ToDo: Can be multithreaded ?? def generate_record(state_funcs): for f in state_funcs: yield self.state_update_exception(f(sweep_dict, sub_step, sH, last_in_obj, _input)) + # def generate_record(state_funcs): + # for f in state_funcs: + # tmp_last_in_copy = deepcopy(last_in_obj) + # new_kv = self.state_update_exception(f(sweep_dict, sub_step, sH, tmp_last_in_copy, _input)) + # del tmp_last_in_copy + # yield new_kv + # + # # get `state` from last_in_obj.keys() + # # vals = last_in_obj.values() + # def generate_record(state_funcs): + # for state, v, f in zip(states, vals, state_funcs): + # v_copy = deepcopy(v) + # last_in_obj[state] = v_copy + # new_kv = self.state_update_exception(f(sweep_dict, sub_step, sH, last_in_copy, _input)) + # del v + # yield new_kv + + # {k: v for k, v in l} + + # r() - r(a') -> r(a',b') -> r(a',b',c') + + # r(f(a),b,c) -> r(a'f(b),c) -> r(a',b',f(c)) => r(a',b',c') + # r(a',b.update(),c) + # r1(f(a1),b1,c1) -> r2(a2,f(b1),c1) -> r3(a3,b1,f(c1)) => r(a',b',c') + + # r1(f(a1),b,c) -> r2(a,f(b1),c) -> r3(a,b,f(c1)) => r(a',b',c') + + # r1(f(a1),b1,c1) -> r(a2',b2.update(),c2) -> r3(a3,b1,f(c1)) => r(a',b',c') + + + # r1(f(a1),b1,c1) -> r2(a2,f(b1),c1) -> r3(a3,b1,f(c1)) => r(a',b',c') + + + # reduce(lambda r: F(r), [r2(f(a),b,c), r2(a,f(b),c), r3(a,b,f(c))]) => R(a',b',c') + def transfer_missing_fields(source, destination): for k in source: if k not in destination: diff --git a/cadCAD/utils/__init__.py b/cadCAD/utils/__init__.py index 44717b5..ccb5f9d 100644 --- a/cadCAD/utils/__init__.py +++ b/cadCAD/utils/__init__.py @@ -15,14 +15,12 @@ def append_dict(dict, new_dict): dict.update(new_dict) return dict - # def val_switch(v): # if isinstance(v, DataFrame) is True or isinstance(v, SilentDF) is True: # return SilentDF(v) # else: # return v.x - class IndexCounter: def __init__(self): self.i = 0 diff --git a/documentation/examples/__init__.py b/documentation/examples/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/documentation/examples/example_1.py b/documentation/examples/example_1.py new file mode 100644 index 0000000..ed1edfc --- /dev/null +++ b/documentation/examples/example_1.py @@ -0,0 +1,45 @@ +from pprint import pprint + +import pandas as pd +from tabulate import tabulate +from cadCAD.engine import ExecutionMode, ExecutionContext, Executor +from documentation.examples import sys_model_A, sys_model_B +from cadCAD import configs + +exec_mode = ExecutionMode() + +# Single Process Execution using a Single System Model Configuration: +# sys_model_A +sys_model_A = [configs[0]] +single_proc_ctx = ExecutionContext(context=exec_mode.single_proc) +sys_model_A_simulation = Executor(exec_context=single_proc_ctx, configs=sys_model_A) + +sys_model_A_raw_result, sys_model_A_tensor_field = sys_model_A_simulation.execute() +sys_model_A_result = pd.DataFrame(sys_model_A_raw_result) +print() +print("Tensor Field: sys_model_A") +print(tabulate(sys_model_A_tensor_field, headers='keys', tablefmt='psql')) +print("Result: System Events DataFrame") +print(tabulate(sys_model_A_result, headers='keys', tablefmt='psql')) +print() + +# # Multiple Processes Execution using Multiple System Model Configurations: +# # sys_model_A & sys_model_B +multi_proc_ctx = ExecutionContext(context=exec_mode.multi_proc) +sys_model_AB_simulation = Executor(exec_context=multi_proc_ctx, configs=configs) + + + +i = 0 +config_names = ['sys_model_A', 'sys_model_B'] +for sys_model_AB_raw_result, sys_model_AB_tensor_field in sys_model_AB_simulation.execute(): + print() + pprint(sys_model_AB_raw_result) + # sys_model_AB_result = pd.DataFrame(sys_model_AB_raw_result) + print() + print(f"Tensor Field: {config_names[i]}") + print(tabulate(sys_model_AB_tensor_field, headers='keys', tablefmt='psql')) + # print("Result: System Events DataFrame:") + # print(tabulate(sys_model_AB_result, headers='keys', tablefmt='psql')) + # print() + i += 1 \ No newline at end of file diff --git a/documentation/examples/historical_state_access.py b/documentation/examples/historical_state_access.py new file mode 100644 index 0000000..5079988 --- /dev/null +++ b/documentation/examples/historical_state_access.py @@ -0,0 +1,111 @@ +import pandas as pd +from tabulate import tabulate +from cadCAD.configuration import append_configs +from cadCAD.configuration.utils import config_sim, access_block +from cadCAD.engine import ExecutionMode, ExecutionContext, Executor +from cadCAD import configs + + +policies, variables = {}, {} +exclusion_list = ['nonexsistant', 'last_x', '2nd_to_last_x', '3rd_to_last_x', '4th_to_last_x'] + +# Policies per Mechanism + +# WARNING: DO NOT delete elements from sH +# state_history, target_field, psu_block_offset, exculsion_list +def last_update(_g, substep, sH, s): + return {"last_x": access_block( + state_history=sH, + target_field="last_x", + psu_block_offset=-1, + exculsion_list=exclusion_list + ) + } +policies["last_x"] = last_update + +def second2last_update(_g, substep, sH, s): + return {"2nd_to_last_x": access_block(sH, "2nd_to_last_x", -2, exclusion_list)} +policies["2nd_to_last_x"] = second2last_update + + +# Internal States per Mechanism + +# WARNING: DO NOT delete elements from sH +def add(y, x): + return lambda _g, substep, sH, s, _input: (y, s[y] + x) +variables['x'] = add('x', 1) + +# last_partial_state_update_block +def nonexsistant(_g, substep, sH, s, _input): + return 'nonexsistant', access_block(sH, "nonexsistant", 0, exclusion_list) +variables['nonexsistant'] = nonexsistant + +# last_partial_state_update_block +def last_x(_g, substep, sH, s, _input): + return 'last_x', _input["last_x"] +variables['last_x'] = last_x + +# 2nd to last partial state update block +def second_to_last_x(_g, substep, sH, s, _input): + return '2nd_to_last_x', _input["2nd_to_last_x"] +variables['2nd_to_last_x'] = second_to_last_x + +# 3rd to last partial state update block +def third_to_last_x(_g, substep, sH, s, _input): + return '3rd_to_last_x', access_block(sH, "3rd_to_last_x", -3, exclusion_list) +variables['3rd_to_last_x'] = third_to_last_x + +# 4th to last partial state update block +def fourth_to_last_x(_g, substep, sH, s, _input): + return '4th_to_last_x', access_block(sH, "4th_to_last_x", -4, exclusion_list) +variables['4th_to_last_x'] = fourth_to_last_x + + +genesis_states = { + 'x': 0, + 'nonexsistant': [], + 'last_x': [], + '2nd_to_last_x': [], + '3rd_to_last_x': [], + '4th_to_last_x': [] +} + +PSUB = { + "policies": policies, + "variables": variables +} + +partial_state_update_block = { + "PSUB1": PSUB, + "PSUB2": PSUB, + "PSUB3": PSUB +} + +sim_config = config_sim( + { + "N": 1, + "T": range(3), + } +) + +append_configs( + sim_configs=sim_config, + initial_state=genesis_states, + partial_state_update_blocks=partial_state_update_block +) + +exec_mode = ExecutionMode() +single_proc_ctx = ExecutionContext(context=exec_mode.single_proc) +run = Executor(exec_context=single_proc_ctx, configs=configs) + +raw_result, tensor_field = run.execute() +result = pd.DataFrame(raw_result) +cols = ['run','substep','timestep','x','nonexsistant','last_x','2nd_to_last_x','3rd_to_last_x','4th_to_last_x'] +result = result[cols] + +print() +print("Tensor Field:") +print(tabulate(tensor_field, headers='keys', tablefmt='psql')) +print("Output:") +print(tabulate(result, headers='keys', tablefmt='psql')) +print() \ No newline at end of file diff --git a/documentation/examples/param_sweep.py b/documentation/examples/param_sweep.py new file mode 100644 index 0000000..a118966 --- /dev/null +++ b/documentation/examples/param_sweep.py @@ -0,0 +1,116 @@ +import pprint +from typing import Dict, List + +import pandas as pd +from tabulate import tabulate + +from cadCAD.configuration import append_configs +from cadCAD.configuration.utils import env_trigger, var_substep_trigger, config_sim, psub_list +from cadCAD.engine import ExecutionMode, ExecutionContext, Executor +from cadCAD import configs + +pp = pprint.PrettyPrinter(indent=4) + + +def some_function(x): + return x + + +g: Dict[str, List[int]] = { + 'alpha': [1], + 'beta': [2, 5], + 'gamma': [3, 4], + 'omega': [some_function] +} + +psu_steps = ['1', '2', '3'] +system_substeps = len(psu_steps) +var_timestep_trigger = var_substep_trigger([0, system_substeps]) +env_timestep_trigger = env_trigger(system_substeps) +env_process = {} + + +# Policies +def gamma(_params, step, sL, s): + return {'gamma': _params['gamma']} + + +def omega(_params, step, sL, s): + return {'omega': _params['omega'](7)} + + +# Internal States +def alpha(_params, step, sL, s, _input): + return 'alpha', _params['alpha'] + +def alpha_plus_gamma(_params, step, sL, s, _input): + return 'alpha_plus_gamma', _params['alpha'] + _params['gamma'] + + +def beta(_params, step, sL, s, _input): + return 'beta', _params['beta'] + + +def policies(_params, step, sL, s, _input): + return 'policies', _input + + +def sweeped(_params, step, sL, s, _input): + return 'sweeped', {'beta': _params['beta'], 'gamma': _params['gamma']} + + + + + +genesis_states = { + 'alpha_plus_gamma': 0, + 'alpha': 0, + 'beta': 0, + 'policies': {}, + 'sweeped': {} +} + +env_process['sweeped'] = env_timestep_trigger(trigger_field='timestep', trigger_vals=[5], funct_list=[lambda _g, x: _g['beta']]) + +sim_config = config_sim( + { + "N": 2, + "T": range(5), + "M": g, + } +) + +psu_block = {k: {"policies": {}, "variables": {}} for k in psu_steps} +for m in psu_steps: + psu_block[m]['policies']['gamma'] = gamma + psu_block[m]['policies']['omega'] = omega + psu_block[m]["variables"]['alpha'] = alpha_plus_gamma + psu_block[m]["variables"]['alpha_plus_gamma'] = alpha + psu_block[m]["variables"]['beta'] = beta + psu_block[m]['variables']['policies'] = policies + psu_block[m]["variables"]['sweeped'] = var_timestep_trigger(y='sweeped', f=sweeped) + +partial_state_update_blocks = psub_list(psu_block, psu_steps) +print() +pp.pprint(psu_block) +print() + +append_configs( + sim_configs=sim_config, + initial_state=genesis_states, + env_processes=env_process, + partial_state_update_blocks=partial_state_update_blocks +) + +exec_mode = ExecutionMode() +multi_proc_ctx = ExecutionContext(context=exec_mode.multi_proc) +run = Executor(exec_context=multi_proc_ctx, configs=configs) + +for raw_result, tensor_field in run.execute(): + result = pd.DataFrame(raw_result) + print() + print("Tensor Field:") + print(tabulate(tensor_field, headers='keys', tablefmt='psql')) + print("Output:") + print(tabulate(result, headers='keys', tablefmt='psql')) + print() \ No newline at end of file diff --git a/documentation/examples/policy_aggregation.py b/documentation/examples/policy_aggregation.py new file mode 100644 index 0000000..86313e7 --- /dev/null +++ b/documentation/examples/policy_aggregation.py @@ -0,0 +1,98 @@ +import pandas as pd +from tabulate import tabulate + +from cadCAD.configuration import append_configs +from cadCAD.configuration.utils import config_sim +from cadCAD.engine import ExecutionMode, ExecutionContext, Executor +from cadCAD import configs + +# Policies per Mechanism +def p1m1(_g, step, sL, s): + return {'policy1': 1} +def p2m1(_g, step, sL, s): + return {'policy2': 2} + +def p1m2(_g, step, sL, s): + return {'policy1': 2, 'policy2': 2} +def p2m2(_g, step, sL, s): + return {'policy1': 2, 'policy2': 2} + +def p1m3(_g, step, sL, s): + return {'policy1': 1, 'policy2': 2, 'policy3': 3} +def p2m3(_g, step, sL, s): + return {'policy1': 1, 'policy2': 2, 'policy3': 3} + + +# Internal States per Mechanism +def add(y, x): + return lambda _g, step, sH, s, _input: (y, s[y] + x) + +def policies(_g, step, sH, s, _input): + y = 'policies' + x = _input + return (y, x) + + +# Genesis States +genesis_states = { + 'policies': {}, + 's1': 0 +} + +variables = { + 's1': add('s1', 1), + "policies": policies +} + +partial_state_update_block = { + "m1": { + "policies": { + "p1": p1m1, + "p2": p2m1 + }, + "variables": variables + }, + "m2": { + "policies": { + "p1": p1m2, + "p2": p2m2 + }, + "variables": variables + }, + "m3": { + "policies": { + "p1": p1m3, + "p2": p2m3 + }, + "variables": variables + } +} + + +sim_config = config_sim( + { + "N": 1, + "T": range(3), + } +) + +append_configs( + sim_configs=sim_config, + initial_state=genesis_states, + partial_state_update_blocks=partial_state_update_block, + policy_ops=[lambda a, b: a + b, lambda y: y * 2] # Default: lambda a, b: a + b +) + +exec_mode = ExecutionMode() +single_proc_ctx = ExecutionContext(context=exec_mode.single_proc) +run = Executor(exec_context=single_proc_ctx, configs=configs) + +raw_result, tensor_field = run.execute() +result = pd.DataFrame(raw_result) + +print() +print("Tensor Field:") +print(tabulate(tensor_field, headers='keys', tablefmt='psql')) +print("Output:") +print(tabulate(result, headers='keys', tablefmt='psql')) +print() \ No newline at end of file diff --git a/documentation/examples/sys_model_A.py b/documentation/examples/sys_model_A.py new file mode 100644 index 0000000..92a7fe3 --- /dev/null +++ b/documentation/examples/sys_model_A.py @@ -0,0 +1,159 @@ +import numpy as np +from datetime import timedelta + + +from cadCAD.configuration import append_configs +from cadCAD.configuration.utils import bound_norm_random, config_sim, time_step, env_trigger + +seeds = { + 'z': np.random.RandomState(1), + 'a': np.random.RandomState(2), + 'b': np.random.RandomState(3), + 'c': np.random.RandomState(4) +} + + +# Policies per Mechanism +def p1m1(_g, step, sL, s): + return {'param1': 1} +def p2m1(_g, step, sL, s): + return {'param1': 1, '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 = s['s1'] + 1 + 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 = s['s1'] + 1 + 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 = s['s1'] + 1 + return (y, x) +def s2m3(_g, step, sL, s, _input): + y = 's2' + x = _input['param2'] + return (y, x) + +def policies(_g, step, sL, s, _input): + y = 'policies' + x = _input + return (y, x) + + +# Exogenous States +proc_one_coef_A = 0.7 +proc_one_coef_B = 1.3 + +def es3(_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 es4(_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) + +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)) + + +# Genesis States +genesis_states = { + 's1': 0.0, + 's2': 0.0, + 's3': 1.0, + 's4': 1.0, + 'timestamp': '2018-10-01 15:16:24' +} + + +# Environment Process +# ToDo: Depreciation Waring for env_proc_trigger convention +trigger_timestamps = ['2018-10-01 15:16:25', '2018-10-01 15:16:27', '2018-10-01 15:16:29'] +env_processes = { + "s3": [lambda _g, x: 5], + "s4": env_trigger(3)(trigger_field='timestamp', trigger_vals=trigger_timestamps, funct_list=[lambda _g, x: 10]) +} + + +partial_state_update_block = [ + { + "policies": { + "b1": p1m1, + "b2": p2m1 + }, + "variables": { + "s1": s1m1, + "s2": s2m1, + "s3": es3, + "s4": es4, + "timestamp": update_timestamp + } + }, + { + "policies": { + "b1": p1m2, + "b2": p2m2 + }, + "variables": { + "s1": s1m2, + "s2": s2m2, + # "s3": es3p1, + # "s4": es4p2, + } + }, + { + "policies": { + "b1": p1m3, + "b2": p2m3 + }, + "variables": { + "s1": s1m3, + "s2": s2m3, + # "s3": es3p1, + # "s4": es4p2, + } + } +] + + +sim_config = config_sim( + { + "N": 2, + "T": range(1), + } +) + +append_configs( + sim_configs=sim_config, + initial_state=genesis_states, + env_processes=env_processes, + partial_state_update_blocks=partial_state_update_block, + policy_ops=[lambda a, b: a + b] +) \ No newline at end of file diff --git a/documentation/examples/sys_model_AB_exec.py b/documentation/examples/sys_model_AB_exec.py new file mode 100644 index 0000000..95067b3 --- /dev/null +++ b/documentation/examples/sys_model_AB_exec.py @@ -0,0 +1,24 @@ +import pandas as pd +from tabulate import tabulate +from cadCAD.engine import ExecutionMode, ExecutionContext, Executor +from documentation.examples import sys_model_A, sys_model_B +from cadCAD import configs + +exec_mode = ExecutionMode() + +# # Multiple Processes Execution using Multiple System Model Configurations: +# # sys_model_A & sys_model_B +multi_proc_ctx = ExecutionContext(context=exec_mode.multi_proc) +sys_model_AB_simulation = Executor(exec_context=multi_proc_ctx, configs=configs) + +i = 0 +config_names = ['sys_model_A', 'sys_model_B'] +for sys_model_AB_raw_result, sys_model_AB_tensor_field in sys_model_AB_simulation.execute(): + sys_model_AB_result = pd.DataFrame(sys_model_AB_raw_result) + print() + print(f"Tensor Field: {config_names[i]}") + print(tabulate(sys_model_AB_tensor_field, headers='keys', tablefmt='psql')) + print("Result: System Events DataFrame:") + print(tabulate(sys_model_AB_result, headers='keys', tablefmt='psql')) + print() + i += 1 \ No newline at end of file diff --git a/documentation/examples/sys_model_A_exec.py b/documentation/examples/sys_model_A_exec.py new file mode 100644 index 0000000..8a630d9 --- /dev/null +++ b/documentation/examples/sys_model_A_exec.py @@ -0,0 +1,22 @@ +import pandas as pd +from tabulate import tabulate +from cadCAD.engine import ExecutionMode, ExecutionContext, Executor +from documentation.examples import sys_model_A +from cadCAD import configs + +exec_mode = ExecutionMode() + +# Single Process Execution using a Single System Model Configuration: +# sys_model_A +sys_model_A = [configs[0]] # sys_model_A +single_proc_ctx = ExecutionContext(context=exec_mode.single_proc) +sys_model_A_simulation = Executor(exec_context=single_proc_ctx, configs=sys_model_A) + +sys_model_A_raw_result, sys_model_A_tensor_field = sys_model_A_simulation.execute() +sys_model_A_result = pd.DataFrame(sys_model_A_raw_result) +print() +print("Tensor Field: config1") +print(tabulate(sys_model_A_tensor_field, headers='keys', tablefmt='psql')) +print("Result: System Events DataFrame") +print(tabulate(sys_model_A_result, headers='keys', tablefmt='psql')) +print() \ No newline at end of file diff --git a/documentation/examples/sys_model_B.py b/documentation/examples/sys_model_B.py new file mode 100644 index 0000000..7298d0b --- /dev/null +++ b/documentation/examples/sys_model_B.py @@ -0,0 +1,147 @@ +import numpy as np +from datetime import timedelta + +from cadCAD.configuration import append_configs +from cadCAD.configuration.utils import bound_norm_random, config_sim, env_trigger, time_step + +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) + + +# Exogenous States +proc_one_coef_A = 0.7 +proc_one_coef_B = 1.3 + +def es3(_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 es4(_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) + +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)) + + +# Genesis States +genesis_states = { + 's1': 0, + 's2': 0, + 's3': 1, + 's4': 1, + 'timestamp': '2018-10-01 15:16:24' +} + + +# Environment Process +# ToDo: Depreciation Waring for env_proc_trigger convention +trigger_timestamps = ['2018-10-01 15:16:25', '2018-10-01 15:16:27', '2018-10-01 15:16:29'] +env_processes = { + "s3": [lambda _g, x: 5], + "s4": env_trigger(3)(trigger_field='timestamp', trigger_vals=trigger_timestamps, funct_list=[lambda _g, x: 10]) +} + +partial_state_update_block = [ + { + "policies": { + "b1": p1m1, + # "b2": p2m1 + }, + "states": { + "s1": s1m1, + # "s2": s2m1 + "s3": es3, + "s4": es4, + "timestep": update_timestamp + } + }, + { + "policies": { + "b1": p1m2, + # "b2": p2m2 + }, + "states": { + "s1": s1m2, + # "s2": s2m2 + } + }, + { + "policies": { + "b1": p1m3, + "b2": p2m3 + }, + "states": { + "s1": s1m3, + "s2": s2m3 + } + } +] + + +sim_config = config_sim( + { + "N": 2, + "T": range(5), + } +) + +append_configs( + sim_configs=sim_config, + initial_state=genesis_states, + env_processes=env_processes, + partial_state_update_blocks=partial_state_update_block +) \ No newline at end of file diff --git a/documentation/examples/sys_model_B_exec.py b/documentation/examples/sys_model_B_exec.py new file mode 100644 index 0000000..53eef37 --- /dev/null +++ b/documentation/examples/sys_model_B_exec.py @@ -0,0 +1,23 @@ +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 documentation.examples import sys_model_B +from cadCAD import configs + +exec_mode = ExecutionMode() + +print("Simulation Execution: Single Configuration") +print() +first_config = configs # only contains config2 +single_proc_ctx = ExecutionContext(context=exec_mode.single_proc) +run = Executor(exec_context=single_proc_ctx, configs=first_config) + +raw_result, tensor_field = run.execute() +result = pd.DataFrame(raw_result) +print() +print("Tensor Field: config1") +print(tabulate(tensor_field, headers='keys', tablefmt='psql')) +print("Output:") +print(tabulate(result, headers='keys', tablefmt='psql')) +print() diff --git a/documentation/execution.md b/documentation/execution.md new file mode 100644 index 0000000..f34064b --- /dev/null +++ b/documentation/execution.md @@ -0,0 +1,71 @@ +Simulation Execution +== +System Simulations are executed with the execution engine executor (`cadCAD.engine.Executor`) given System Model +Configurations. There are multiple simulation Execution Modes and Execution Contexts. + +### Steps: +1. #### *Choose Execution Mode*: + * ##### Simulation Execution Modes: + `cadCAD` executes a process per System Model Configuration and a thread per System Simulation. + ##### Class: `cadCAD.engine.ExecutionMode` + ##### Attributes: + * **Single Process:** A single process Execution Mode for a single System Model Configuration (Example: + `cadCAD.engine.ExecutionMode().single_proc`). + * **Multi-Process:** Multiple process Execution Mode for System Model Simulations which executes on a thread per + given System Model Configuration (Example: `cadCAD.engine.ExecutionMode().multi_proc`). +2. #### *Create Execution Context using Execution Mode:* +```python +from cadCAD.engine import ExecutionMode, ExecutionContext +exec_mode = ExecutionMode() +single_proc_ctx = ExecutionContext(context=exec_mode.single_proc) +``` +3. #### *Create Simulation Executor* +```python +from cadCAD.engine import Executor +from cadCAD import configs +simulation = Executor(exec_context=single_proc_ctx, configs=configs) +``` +4. #### *Execute Simulation: Produce System Event Dataset* +A Simulation execution produces a System Event Dataset and the Tensor Field applied to initial states used to create it. +```python +import pandas as pd +raw_system_events, tensor_field = simulation.execute() + +# Simulation Result Types: +# raw_system_events: List[dict] +# tensor_field: pd.DataFrame + +# Result System Events DataFrame +simulation_result = pd.DataFrame(raw_system_events) +``` + +##### Example Tensor Field +``` ++----+-----+--------------------------------+--------------------------------+ +| | m | b1 | s1 | +|----+-----+--------------------------------+--------------------------------| +| 0 | 1 | | | +| 1 | 2 | | | +| 2 | 3 | | | ++----+-----+--------------------------------+--------------------------------+ +``` + +##### Example Result: System Events DataFrame +```python ++----+-------+------------+-----------+------+-----------+ +| | run | timestep | substep | s1 | s2 | +|----+-------+------------+-----------+------+-----------| +| 0 | 1 | 0 | 0 | 0 | 0.0 | +| 1 | 1 | 1 | 1 | 1 | 4 | +| 2 | 1 | 1 | 2 | 2 | 6 | +| 3 | 1 | 1 | 3 | 3 | [ 30 300] | +| 4 | 2 | 0 | 0 | 0 | 0.0 | +| 5 | 2 | 1 | 1 | 1 | 4 | +| 6 | 2 | 1 | 2 | 2 | 6 | +| 7 | 2 | 1 | 3 | 3 | [ 30 300] | ++----+-------+------------+-----------+------+-----------+ +``` + +##### [Single Process Example Execution](link) + +##### [Multiple Process Example Execution](link) diff --git a/documentation/historical_state_access.md b/documentation/historical_state_access.md new file mode 100644 index 0000000..944fc8a --- /dev/null +++ b/documentation/historical_state_access.md @@ -0,0 +1,97 @@ +Historical State Access +== +The 3rd parameter of state and policy update functions (labels as `sH` of type `List[List[dict]]`) provides access to +past Partial State Updates (PSU) given a negative offset number. `access_block` is used to access past PSUs +(`List[dict]`) from `sH`. + +Example: `-2` denotes to second to last PSU + +##### Exclusion List +Create a list of states to exclude from the reported PSU. +```python +exclusion_list = [ + 'nonexsistant', 'last_x', '2nd_to_last_x', '3rd_to_last_x', '4th_to_last_x' +] +``` +##### Example Policy Updates +###### Last partial state update +```python +from cadCAD.configuration.utils import config_sim, access_block + +def last_update(_g, substep, sH, s): + return {"last_x": access_block( + state_history=sH, + target_field="last_x", # Add a field to the exclusion list + psu_block_offset=-1, + exculsion_list=exclusion_list + ) + } +``` +* Note: Although `target_field` adding a field to the exclusion may seem redundant, it is useful in the case of +the exclusion list being empty while the `target_field` is assigned to a state or a policy key. +###### 2nd to last partial state update +```python +def second2last_update(_g, substep, sH, s): + return {"2nd_to_last_x": access_block(sH, "2nd_to_last_x", -2, exclusion_list)} +``` + +##### Define State Updates +###### 3rd to last partial state update +```python +def third_to_last_x(_g, substep, sH, s, _input): + return '3rd_to_last_x', access_block(sH, "3rd_to_last_x", -3, exclusion_list) +``` +###### 4rd to last partial state update +```python +def fourth_to_last_x(_g, substep, sH, s, _input): + return '4th_to_last_x', access_block(sH, "4th_to_last_x", -4, exclusion_list) +``` +###### Non-exsistant partial state update +* `psu_block_offset >= 0` doesn't exsist +```python +def nonexsistant(_g, substep, sH, s, _input): + return 'nonexsistant', access_block(sH, "nonexsistant", 0, exclusion_list) +``` + +#### Example Simulation +link + +#### Example Output +###### State History +``` ++----+-------+-----------+------------+-----+ +| | run | substep | timestep | x | +|----+-------+-----------+------------+-----| +| 0 | 1 | 0 | 0 | 0 | +| 1 | 1 | 1 | 1 | 1 | +| 2 | 1 | 2 | 1 | 2 | +| 3 | 1 | 3 | 1 | 3 | +| 4 | 1 | 1 | 2 | 4 | +| 5 | 1 | 2 | 2 | 5 | +| 6 | 1 | 3 | 2 | 6 | +| 7 | 1 | 1 | 3 | 7 | +| 8 | 1 | 2 | 3 | 8 | +| 9 | 1 | 3 | 3 | 9 | ++----+-------+-----------+------------+-----+ +``` +###### Accessed State History: +Example: `last_x` +``` ++----+-----------------------------------------------------------------------------------------------------------------------------------------------------+ +| | last_x | +|----+-----------------------------------------------------------------------------------------------------------------------------------------------------| +| 0 | [] | +| 1 | [{'x': 0, 'run': 1, 'substep': 0, 'timestep': 0}] | +| 2 | [{'x': 0, 'run': 1, 'substep': 0, 'timestep': 0}] | +| 3 | [{'x': 0, 'run': 1, 'substep': 0, 'timestep': 0}] | +| 4 | [{'x': 1, 'run': 1, 'substep': 1, 'timestep': 1}, {'x': 2, 'run': 1, 'substep': 2, 'timestep': 1}, {'x': 3, 'run': 1, 'substep': 3, 'timestep': 1}] | +| 5 | [{'x': 1, 'run': 1, 'substep': 1, 'timestep': 1}, {'x': 2, 'run': 1, 'substep': 2, 'timestep': 1}, {'x': 3, 'run': 1, 'substep': 3, 'timestep': 1}] | +| 6 | [{'x': 1, 'run': 1, 'substep': 1, 'timestep': 1}, {'x': 2, 'run': 1, 'substep': 2, 'timestep': 1}, {'x': 3, 'run': 1, 'substep': 3, 'timestep': 1}] | +| 7 | [{'x': 4, 'run': 1, 'substep': 1, 'timestep': 2}, {'x': 5, 'run': 1, 'substep': 2, 'timestep': 2}, {'x': 6, 'run': 1, 'substep': 3, 'timestep': 2}] | +| 8 | [{'x': 4, 'run': 1, 'substep': 1, 'timestep': 2}, {'x': 5, 'run': 1, 'substep': 2, 'timestep': 2}, {'x': 6, 'run': 1, 'substep': 3, 'timestep': 2}] | +| 9 | [{'x': 4, 'run': 1, 'substep': 1, 'timestep': 2}, {'x': 5, 'run': 1, 'substep': 2, 'timestep': 2}, {'x': 6, 'run': 1, 'substep': 3, 'timestep': 2}] | ++----+-----------------------------------------------------------------------------------------------------------------------------------------------------+ +``` + +#### [Example Configuration](link) +#### [Example Results](link) \ No newline at end of file diff --git a/documentation/param_sweep.md b/documentation/param_sweep.md new file mode 100644 index 0000000..3822369 --- /dev/null +++ b/documentation/param_sweep.md @@ -0,0 +1,68 @@ +System Model Parameter Sweep +== +Parametrization of a System Model configuration that produces multiple configurations. + +##### Set Parameters +```python +params = { + 'alpha': [1], + 'beta': [2, 5], + 'gamma': [3, 4], + 'omega': [7] +} +``` +The parameters above produce 2 simulations. +* Simulation 1: + * `alpha = 1` + * `beta = 2` + * `gamma = 3` + * `omega = 7` +* Simulation 2: + * `alpha = 1` + * `beta = 5` + * `gamma = 4` + * `omega = 7` + +All parameters can also be set to include a single parameter each, which will result in a single simulation. + +##### Example State Updates + +Previous State: +`y = 0` + +```python +def state_update(_params, step, sL, s, _input): + y = 'state' + x = s['state'] + _params['alpha'] + _params['gamma'] + return y, x +``` +* Updated State: + * Simulation 1: `y = 4 = 0 + 1 + 3` + * Simulation 2: `y = 5 = 0 + 1 + 4` + +##### Example Policy Updates +```python +# Internal States per Mechanism +def policies(_g, step, sL, s): + return {'beta': _g['beta'], 'gamma': _g['gamma']} +``` +* Simulation 1: `{'beta': 2, 'gamma': 3]}` +* Simulation 2: `{'beta': 5, 'gamma': 4}` + +##### Configure Simulation +```python +from cadCAD.configuration.utils import config_sim + +sim_config = config_sim( + { + "N": 2, + "T": range(5), + "M": g, + } +) +``` + +#### [Example Configuration](link) +#### [Example Results](link) + + diff --git a/documentation/policy_agg.md b/documentation/policy_agg.md new file mode 100644 index 0000000..7ddaa50 --- /dev/null +++ b/documentation/policy_agg.md @@ -0,0 +1,60 @@ +Policy Aggregation +== + +For each Partial State Update, multiple policy dictionaries are aggregated into a single dictionary to be imputted into +all state functions using an initial reduction function and optional subsequent map functions. + +#### Aggregate Function Composition: +```python +# Reduce Function +add = lambda a, b: a + b # Used to add policy values of the same key +# Map Function +mult_by_2 = lambda y: y * 2 # Used to multiply all policy values by 2 +policy_ops=[add, mult_by_2] +``` + +##### Example Policy Updates per Partial State Update (PSU) +```python +def p1_psu1(_g, step, sL, s): + return {'policy1': 1} +def p2_psu1(_g, step, sL, s): + return {'policy2': 2} +``` +* `add` not applicable due to lack of redundant policies +* `mult_by_2` applied to all policies +* Result: `{'policy1': 2, 'policy2': 4}` + +```python +def p1_psu2(_g, step, sL, s): + return {'policy1': 2, 'policy2': 2} +def p2_psu2(_g, step, sL, s): + return {'policy1': 2, 'policy2': 2} +``` +* `add` applicable due to redundant policies +* `mult_by_2` applied to all policies +* Result: `{'policy1': 8, 'policy2': 8}` + +```python +def p1_psu3(_g, step, sL, s): + return {'policy1': 1, 'policy2': 2, 'policy3': 3} +def p2_psu3(_g, step, sL, s): + return {'policy1': 1, 'policy2': 2, 'policy3': 3} +``` +* `add` applicable due to redundant policies +* `mult_by_2` applied to all policies +* Result: `{'policy1': 4, 'policy2': 8, 'policy3': 12}` + +#### Aggregate Policies using functions +```python +from cadCAD.configuration import append_configs + +append_configs( + sim_configs=???, + initial_state=???, + partial_state_update_blocks=???, + policy_ops=[add, mult_by_2] # Default: [lambda a, b: a + b] +) +``` + +#### [Example Configuration](link) +#### [Example Results](link) \ No newline at end of file diff --git a/documentation/sys_model_config.md b/documentation/sys_model_config.md new file mode 100644 index 0000000..edece69 --- /dev/null +++ b/documentation/sys_model_config.md @@ -0,0 +1,220 @@ +System Model Configuration +== + +#### Introduction + +Given System Model Configurations, cadCAD produces system event datasets that conform to specified system metrics. Each +event / record is of [Enogenous State variables](link) produced by user defined [Partial State Updates](link) (PSU / +functions that update state); A sequence of event / record subsets that comprises the resulting system event dataset is +produced by a [Partial State Update Block](link) (PSUB / a Tensor Field for which State, Policy, and Time are dimensions +and PSU functions are values). + +A **System Model Configuration** is comprised of a simulation configuration, initial endogenous states, Partial State +Update Blocks, environmental process, and a user defined policy aggregation function. + +Execution: + +#### Simulation Properties + +###### System Metrics +The following system metrics determine the size of resulting system event datasets: +* `run` - the number of simulations in the resulting dataset +* `timestep` - the number of timestamps in the resulting dataset +* `substep` - the number of PSUs per `timestep` / within PSUBS +* Number of events / records: `run` x `timestep` x `substep` + +###### Simulation Configuration +For the following dictionary, `T` is assigned a `timestep` range, `N` is assigned the number of simulation runs, and +`params` is assigned the [**Parameter Sweep**](link) dictionary. + +```python +from cadCAD.configuration.utils import config_sim + +sim_config = config_sim({ + "N": 2, + "T": range(5), + "M": params, # Optional +}) +``` + +#### Initial Endogenous States +**Enogenous State variables** are read-only variables defined to capture the shape and property of the network and +represent internal input and signal. + +The PSUB tensor field is applied to the following states to produce a resulting system event +dataset. +```python +genesis_states = { + 's1': 0.0, + 's2': 0.0, + 's3': 1.0, + 'timestamp': '2018-10-01 15:16:24' +} +``` + +#### Partial State Update Block: +- ***Partial State Update Block(PSUB)*** ***(Define ?)*** Tensor Field for which State, Policy, Time are dimensions +and Partial State Update functions are values. +- ***Partial State Update (PSU)*** are user defined functions that encodes state updates and are executed in +a specified order PSUBs. PSUs update states given the most recent set of states and PSU policies. +- ***Mechanism*** ***(Define)*** + + +The PSUBs is a list of PSU dictionaries of the structure within the code block below. PSUB elements (PSU dictionaries) +are listed / defined in order of `substeps` and **identity functions** (returning a previous state's value) are assigned +to unreferenced states within PSUs. The number of records produced produced per `timestep` is the number of `substeps`. + +```python +partial_state_update_block = [ + { + "policies": { + "b1": p1_psu1, + "b2": p2_psu1 + }, + "variables": { + "s1": s1_psu1, + "s2": s2_psu1 + } + }, + { + "policies": { + "b1": p1_psu2, + }, + "variables": { + "s2": s2_psu2 + } + }, + {...} +] +``` +*Notes:* +1. An identity function (returning the previous state value) is assigned to `s1` in the second PSU. +2. Currently the only names that need not correspond to the convention below are `'b1'` and `'b2'`. + +#### Policies +- ***Policies*** ***(Define)*** When are policies behavior ? +- ***Behaviors*** model agent behaviors in reaction to state variables and exogenous variables. The +resulted user action will become an input to PSUs. Note that user behaviors should not directly update value +of state variables. + +Policies accept parameter sweep variables [see link] `_g` (`dict`), the most recent +`substep` integer, the state history[see link] (`sH`), the most recent state record `s` (`dict) as inputs and returns a +set of actions (`dict`). + +Policy functions return dictionaries as actions. Policy functions provide access to parameter sweep variables [see link] +via dictionary `_g`. +```python +def p1_psu1(_g, substep, sH, s): + return {'policy1': 1} +def p2_psu1(_g, substep, sH, s): + return {'policy1': 1, 'policy2': 4} +``` +For each PSU, multiple policy dictionaries are aggregated into a single dictionary to be imputted into +all state functions using an initial reduction function (default: `lambda a, b: a + b`) and optional subsequent map +functions. +Example Result: `{'policy1': 2, 'policy2': 4}` + +#### State Updates +State update functions provide access to parameter sweep variables [see link] `_g` (`dict`), the most recent `substep` +integer, the state history[see link] (`sH`), the most recent state record as a dictionary (`s`), the policies of a +PSU (`_input`), and returns a tuple of the state variable's name and the resulting new value of the variable. + +```python +def state_update(_g, substep, sH, s, _input): + ... + return state, update +``` +**Note:** Each state update function updates one state variable at a time. Changes to multiple state variables requires +separate state update functions. A generic example of a PSU is as follows. + +* ##### Endogenous State Updates +They are only updated by PSUs and can be used as inputs to a PSUs. +```python +def s1_update(_g, substep, sH, s, _input): + x = _input['policy1'] + 1 + return 's1', x + +def s2_update(_g, substep, sH, s, _input): + x = _input['policy2'] + return 's2', x +``` + +* ##### Exogenous State Updates +***Exogenous State variables*** ***(Review)*** are read-only variables that represent external input and signal. They +update endogenous states and are only updated by environmental processes. Exgoneous variables can be used +as an input to a PSU that impacts state variables. ***(Expand upon Exogenous state updates)*** + +```python +from datetime import timedelta +from cadCAD.configuration.utils import time_step +def es3_update(_g, substep, sH, s, _input): + x = ... + return 's3' +def es4_update(_g, substep, sH, s, _input): + x = ... + return 's4', x +def update_timestamp(_g, substep, sH, s, _input): + x = time_step(dt_str=s[y], dt_format='%Y-%m-%d %H:%M:%S', _timedelta=timedelta(days=0, minutes=0, seconds=1)) + return 'timestamp', x +``` +Exogenous state update functions (`es3_update`, `es4_update` and `es5_update`) update once per timestamp and should be +included as a part of the first PSU in the PSUB. +```python +partial_state_update_block['psu1']['variables']['s3'] = es3_update +partial_state_update_block['psu1']['variables']['s4'] = es4_update +partial_state_update_block['psu1']['variables']['timestamp'] = update_timestamp +``` + +* #### Environmental Process +- ***Environmental processes*** model external changes that directly impact exogenous states at given specific +conditions such as market shocks at specific timestamps. + +Create a dictionary like `env_processes` below for which the keys are exogenous states and the values are lists of user +defined **Environment Update** functions to be composed (e.g. `[f(params, x), g(params, x)]` becomes +`f(params, g(params, x))`). + +Environment Updates accept the [**Parameter Sweep**](link) dictionary `params` and a state as a result of a PSU. +```python +def env_update(params, state): + . . . + return updated_state + +# OR + +env_update = lambda params, state: state + 5 +``` + +The `env_trigger` function is used to apply composed environment update functions to a list of specific exogenous state +update results. `env_trigger` accepts the total number of `substeps` for the simulation / `end_substep` and returns a +function accepting `trigger_field`, `trigger_vals`, and `funct_list`. + +In the following example functions are used to add `5` to every `s3` update and assign `10` to `s4` at +`timestamp`s `'2018-10-01 15:16:25'`, `'2018-10-01 15:16:27'`, and `'2018-10-01 15:16:29'`. +```python +from cadCAD.configuration.utils import env_trigger +trigger_timestamps = ['2018-10-01 15:16:25', '2018-10-01 15:16:27', '2018-10-01 15:16:29'] +env_processes = { + "s3": [lambda params, x: x + 5], + "s4": env_trigger(end_substep=3)( + trigger_field='timestamp', trigger_vals=trigger_timestamps, funct_list=[lambda params, x: 10] + ) +} +``` + +#### System Model Configuration +`append_configs`, stores a **System Model Configuration** to be (Executed)[url] as +simulations producing system event dataset(s) + +```python +from cadCAD.configuration import append_configs + +append_configs( + sim_configs=sim_config, + initial_state=genesis_states, + env_processes=env_processes, + partial_state_update_blocks=partial_state_update_block, + policy_ops=[lambda a, b: a + b] +) +``` + +#### [System Simulation Execution](link) diff --git a/simulations/regression_tests/config1.py b/simulations/regression_tests/config1.py index 9ee1979..a677f5e 100644 --- a/simulations/regression_tests/config1.py +++ b/simulations/regression_tests/config1.py @@ -9,7 +9,7 @@ seeds = { 'z': np.random.RandomState(1), 'a': np.random.RandomState(2), 'b': np.random.RandomState(3), - 'c': np.random.RandomState(3) + 'c': np.random.RandomState(4) } @@ -95,14 +95,15 @@ genesis_states = { # Environment Process # ToDo: Depreciation Waring for env_proc_trigger convention +trigger_timestamps = ['2018-10-01 15:16:25', '2018-10-01 15:16:27', '2018-10-01 15:16:29'] env_processes = { "s3": [lambda _g, x: 5], - "s4": env_trigger(3)(trigger_field='timestep', trigger_vals=[1], funct_list=[lambda _g, x: 10]) + "s4": env_trigger(3)(trigger_field='timestamp', trigger_vals=trigger_timestamps, funct_list=[lambda _g, x: 10]) } -partial_state_update_blocks = { - "m1": { +partial_state_update_block = [ + { "policies": { "b1": p1m1, "b2": p2m1 @@ -115,7 +116,7 @@ partial_state_update_blocks = { "timestamp": update_timestamp } }, - "m2": { + { "policies": { "b1": p1m2, "b2": p2m2 @@ -127,7 +128,7 @@ partial_state_update_blocks = { # "s4": es4p2, } }, - "m3": { + { "policies": { "b1": p1m3, "b2": p2m3 @@ -139,7 +140,7 @@ partial_state_update_blocks = { # "s4": es4p2, } } -} +] sim_config = config_sim( @@ -153,6 +154,6 @@ append_configs( sim_configs=sim_config, initial_state=genesis_states, env_processes=env_processes, - partial_state_update_blocks=partial_state_update_blocks, + partial_state_update_blocks=partial_state_update_block, policy_ops=[lambda a, b: a + b] ) \ No newline at end of file diff --git a/simulations/regression_tests/config2.py b/simulations/regression_tests/config2.py index e120285..f8c4981 100644 --- a/simulations/regression_tests/config2.py +++ b/simulations/regression_tests/config2.py @@ -8,7 +8,7 @@ seeds = { 'z': np.random.RandomState(1), 'a': np.random.RandomState(2), 'b': np.random.RandomState(3), - 'c': np.random.RandomState(4) + 'c': np.random.RandomState(3) } @@ -89,9 +89,10 @@ genesis_states = { # Environment Process # ToDo: Depreciation Waring for env_proc_trigger convention +trigger_timestamps = ['2018-10-01 15:16:25', '2018-10-01 15:16:27', '2018-10-01 15:16:29'] env_processes = { "s3": [lambda _g, x: 5], - "s4": env_trigger(3)(trigger_field='timestep', trigger_vals=[2], funct_list=[lambda _g, x: 10]) + "s4": env_trigger(3)(trigger_field='timestamp', trigger_vals=trigger_timestamps, funct_list=[lambda _g, x: 10]) } partial_state_update_block = { diff --git a/simulations/regression_tests/udo.py b/simulations/regression_tests/udo.py index 02647e7..618b86c 100644 --- a/simulations/regression_tests/udo.py +++ b/simulations/regression_tests/udo.py @@ -1,3 +1,5 @@ +from copy import deepcopy + import pandas as pd from fn.func import curried from datetime import timedelta @@ -26,6 +28,11 @@ class udoExample(object): self.x += 1 return self + def updateDS(self): + self.ds.iloc[0,0] -= 10 + # pp.pprint(self.ds) + return self + def perceive(self, s): self.perception = self.ds[ (self.ds['run'] == s['run']) & (self.ds['substep'] == s['substep']) & (self.ds['timestep'] == s['timestep']) @@ -106,7 +113,7 @@ def perceive(s, self): def state_udo_update(_g, step, sL, s, _input): y = 'state_udo' # s['hydra_state'].updateX().anon(perceive(s)) - s['state_udo'].updateX().perceive(s) + s['state_udo'].updateX().perceive(s).updateDS() x = udoPipe(s['state_udo']) return y, x for m in psu_steps: diff --git a/simulations/test_executions/config1_test.py b/simulations/test_executions/config1_test.py index 052c602..8807c02 100644 --- a/simulations/test_executions/config1_test.py +++ b/simulations/test_executions/config1_test.py @@ -1,4 +1,5 @@ import pandas as pd +from typing import List from tabulate import tabulate # The following imports NEED to be in the exact order from cadCAD.engine import ExecutionMode, ExecutionContext, Executor @@ -17,7 +18,8 @@ raw_result, tensor_field = run.execute() result = pd.DataFrame(raw_result) print() print("Tensor Field: config1") -print(tabulate(tensor_field, headers='keys', tablefmt='psql')) +# print(raw_result) +print(tabulate(tensor_field[['m', 'b1', 's1', 's2']], headers='keys', tablefmt='psql')) print("Output:") print(tabulate(result, headers='keys', tablefmt='psql')) print() diff --git a/simulations/test_executions/historical_state_access_test.py b/simulations/test_executions/historical_state_access_test.py index 2b3b477..f0229bc 100644 --- a/simulations/test_executions/historical_state_access_test.py +++ b/simulations/test_executions/historical_state_access_test.py @@ -15,10 +15,10 @@ run = Executor(exec_context=single_proc_ctx, configs=first_config) raw_result, tensor_field = run.execute() result = pd.DataFrame(raw_result) -cols = ['run','substep','timestep','x','nonexsistant','last_x','2nd_to_last_x','3rd_to_last_x','4th_to_last_x'] +# cols = ['run','substep','timestep','x','nonexsistant','last_x','2nd_to_last_x','3rd_to_last_x','4th_to_last_x'] +cols = ['last_x'] result = result[cols] - print() print("Tensor Field: config1") print(tabulate(tensor_field, headers='keys', tablefmt='psql')) diff --git a/simulations/test_executions/policy_agg_test.py b/simulations/test_executions/policy_agg_test.py index f1da13f..2d86f09 100644 --- a/simulations/test_executions/policy_agg_test.py +++ b/simulations/test_executions/policy_agg_test.py @@ -2,11 +2,9 @@ from pprint import pprint 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.regression_tests import policy_aggregation from cadCAD import configs -from testing.utils import generate_assertions exec_mode = ExecutionMode() diff --git a/simulations/test_executions/udo_test.py b/simulations/test_executions/udo_test.py index f4cf6d9..45c9d55 100644 --- a/simulations/test_executions/udo_test.py +++ b/simulations/test_executions/udo_test.py @@ -11,9 +11,9 @@ print("Simulation Execution: Single Configuration") print() -first_config = configs # only contains config1 + single_proc_ctx = ExecutionContext(context=exec_mode.single_proc) -run = Executor(exec_context=single_proc_ctx, configs=first_config) +run = Executor(exec_context=single_proc_ctx, configs=configs) # cols = configs[0].initial_state.keys() cols = [ 'increment', @@ -29,6 +29,10 @@ result = pd.DataFrame(raw_result)[['run', 'substep', 'timestep'] + cols] # print(tabulate(result['c'].apply(pd.Series), headers='keys', tablefmt='psql')) +# print(result.iloc[8,:]['state_udo'].ds) + +# ctypes.cast(id(v['state_udo']['mem_id']), ctypes.py_object).value + print() print("Tensor Field: config1") print(tabulate(tensor_field, headers='keys', tablefmt='psql')) diff --git a/testing/generic_test.py b/testing/generic_test.py index 19b562c..796770b 100644 --- a/testing/generic_test.py +++ b/testing/generic_test.py @@ -2,7 +2,6 @@ import unittest from parameterized import parameterized from functools import reduce from tabulate import tabulate -from testing.utils import generate_assertions_df # ToDo: Exec Debug mode (*) for which state and policy updates are validated during runtime using `expected_results` # EXAMPLE: ('state_test' T/F, 'policy_test' T/F) @@ -14,26 +13,61 @@ from testing.utils import generate_assertions_df # ToDo: Use self.assertRaises(AssertionError) +def generate_assertions_df(df, expected_results, target_cols, evaluations): + # cols = ['run', 'timestep', 'substep'] + target_cols + # print(cols) + test_names = [] + for eval_f in evaluations: + def wrapped_eval(a, b): + try: + return eval_f(a, b) + except KeyError: + return True + + test_name = f"{eval_f.__name__}_test" + test_names.append(test_name) + df[test_name] = df.apply( + lambda x: wrapped_eval( + x.filter(items=target_cols).to_dict(), + expected_results[(x['run'], x['timestep'], x['substep'])] + ), + axis=1 + ) + + return df, test_names + + def make_generic_test(params): class TestSequence(unittest.TestCase): - @parameterized.expand(params) - def test_validate_results(self, name, result_df, expected_reults, target_cols): - # alt for (*) Exec Debug mode - tested_df = generate_assertions_df(result_df, expected_reults, target_cols) - erroneous = tested_df[(tested_df['test'] == False)] - if erroneous.empty is False: + + def generic_test(self, tested_df, expected_reults, test_name): + erroneous = tested_df[(tested_df[test_name] == False)] + # print(tabulate(tested_df, headers='keys', tablefmt='psql')) + + if erroneous.empty is False: # Or Entire df IS NOT erroneous for index, row in erroneous.iterrows(): expected = expected_reults[(row['run'], row['timestep'], row['substep'])] - unexpected = {k: expected[k] for k in expected if k in row and expected[k] != row[k]} + unexpected = {f"invalid_{k}": expected[k] for k in expected if k in row and expected[k] != row[k]} + for key in unexpected.keys(): - erroneous[f"invalid_{key}"] = unexpected[key] + erroneous[key] = None + erroneous.at[index, key] = unexpected[key] # etc. - print() - print(tabulate(erroneous, headers='keys', tablefmt='psql')) + # print() + # print(f"TEST: {test_name}") + # print(tabulate(erroneous, headers='keys', tablefmt='psql')) - self.assertTrue(reduce(lambda a, b: a and b, tested_df['test'])) + # ToDo: Condition that will change false to true + self.assertTrue(reduce(lambda a, b: a and b, tested_df[test_name])) - # def etc. + + @parameterized.expand(params) + def test_validation(self, name, result_df, expected_reults, target_cols, evaluations): + # alt for (*) Exec Debug mode + tested_df, test_names = generate_assertions_df(result_df, expected_reults, target_cols, evaluations) + + for test_name in test_names: + self.generic_test(tested_df, expected_reults, test_name) return TestSequence diff --git a/testing/system_models/__init__.py b/testing/system_models/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/testing/system_models/external_dataset.py b/testing/system_models/external_dataset.py new file mode 100644 index 0000000..0265288 --- /dev/null +++ b/testing/system_models/external_dataset.py @@ -0,0 +1,67 @@ +from cadCAD.configuration import append_configs +from cadCAD.configuration.utils import config_sim +import pandas as pd +from cadCAD.utils import SilentDF + +df = SilentDF(pd.read_csv('/Users/jjodesty/Projects/DiffyQ-SimCAD/simulations/external_data/output.csv')) + + +def query(s, df): + return df[ + (df['run'] == s['run']) & (df['substep'] == s['substep']) & (df['timestep'] == s['timestep']) + ].drop(columns=['run', 'substep', "timestep"]) + +def p1(_g, substep, sL, s): + result_dict = query(s, df).to_dict() + del result_dict["ds3"] + return {k: list(v.values()).pop() for k, v in result_dict.items()} + +def p2(_g, substep, sL, s): + result_dict = query(s, df).to_dict() + del result_dict["ds1"], result_dict["ds2"] + return {k: list(v.values()).pop() for k, v in result_dict.items()} + +# ToDo: SilentDF(df) wont work +#integrate_ext_dataset +def integrate_ext_dataset(_g, step, sL, s, _input): + result_dict = query(s, df).to_dict() + return 'external_data', {k: list(v.values()).pop() for k, v in result_dict.items()} + +def increment(y, incr_by): + return lambda _g, step, sL, s, _input: (y, s[y] + incr_by) +increment = increment('increment', 1) + +def view_policies(_g, step, sL, s, _input): + return 'policies', _input + + +external_data = {'ds1': None, 'ds2': None, 'ds3': None} +state_dict = { + 'increment': 0, + 'external_data': external_data, + 'policies': external_data +} + + +policies = {"p1": p1, "p2": p2} +states = {'increment': increment, 'external_data': integrate_ext_dataset, 'policies': view_policies} +PSUB = {'policies': policies, 'states': states} + +# needs M1&2 need behaviors +partial_state_update_blocks = { + 'PSUB1': PSUB, + 'PSUB2': PSUB, + 'PSUB3': PSUB +} + +sim_config = config_sim({ + "N": 2, + "T": range(4) +}) + +append_configs( + sim_configs=sim_config, + initial_state=state_dict, + partial_state_update_blocks=partial_state_update_blocks, + policy_ops=[lambda a, b: {**a, **b}] +) diff --git a/testing/system_models/historical_state_access.py b/testing/system_models/historical_state_access.py index 839a826..8f88e85 100644 --- a/testing/system_models/historical_state_access.py +++ b/testing/system_models/historical_state_access.py @@ -92,6 +92,4 @@ append_configs( partial_state_update_blocks=partial_state_update_block ) -exec_mode = ExecutionMode() -single_proc_ctx = ExecutionContext(context=exec_mode.single_proc) -run = Executor(exec_context=single_proc_ctx, configs=configs) + diff --git a/testing/system_models/param_sweep.py b/testing/system_models/param_sweep.py new file mode 100644 index 0000000..fabb450 --- /dev/null +++ b/testing/system_models/param_sweep.py @@ -0,0 +1,110 @@ +import pprint +from typing import Dict, List + +from cadCAD.configuration import append_configs +from cadCAD.configuration.utils import env_trigger, var_substep_trigger, config_sim, psub_list + +pp = pprint.PrettyPrinter(indent=4) + +def some_function(x): + return x + +# Optional +# dict must contain lists opf 2 distinct lengths +g: Dict[str, List[int]] = { + 'alpha': [1], + 'beta': [2, some_function], + 'gamma': [3, 4], + 'omega': [7] +} + +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) +env_process = {} + + +# ['s1', 's2', 's3', 's4'] +# Policies per Mechanism +def gamma(_g, step, sL, s): + return {'gamma': _g['gamma']} + + +def omega(_g, step, sL, s): + return {'omega': _g['omega']} + + +# Internal States per Mechanism +def alpha(_g, step, sL, s, _input): + return 'alpha', _g['alpha'] + + +def beta(_g, step, sL, s, _input): + return 'beta', _g['beta'] + + +def policies(_g, step, sL, s, _input): + return 'policies', _input + + +def sweeped(_g, step, sL, s, _input): + return 'sweeped', {'beta': _g['beta'], 'gamma': _g['gamma']} + +psu_block = {k: {"policies": {}, "variables": {}} for k in psu_steps} +for m in psu_steps: + psu_block[m]['policies']['gamma'] = gamma + psu_block[m]['policies']['omega'] = omega + psu_block[m]["variables"]['alpha'] = alpha + psu_block[m]["variables"]['beta'] = beta + psu_block[m]['variables']['policies'] = policies + psu_block[m]["variables"]['sweeped'] = var_timestep_trigger(y='sweeped', f=sweeped) + + +# 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 = { + 'alpha': 0, + 'beta': 0, + 'policies': {}, + 'sweeped': {} +} + +# Environment Process +# ToDo: Validate - make env proc trigger field agnostic +env_process['sweeped'] = env_timestep_trigger(trigger_field='timestep', trigger_vals=[5], funct_list=[lambda _g, x: _g['beta']]) + + +# config_sim Necessary +sim_config = config_sim( + { + "N": 2, + "T": range(5), + "M": g, # Optional + } +) +# print() +# pp.pprint(g) +# print() +# pp.pprint(sim_config) + + +# New Convention +partial_state_update_blocks = psub_list(psu_block, psu_steps) +append_configs( + sim_configs=sim_config, + initial_state=genesis_states, + 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() diff --git a/testing/system_models/policy_aggregation.py b/testing/system_models/policy_aggregation.py index aae9234..e2be18b 100644 --- a/testing/system_models/policy_aggregation.py +++ b/testing/system_models/policy_aggregation.py @@ -1,7 +1,5 @@ from cadCAD.configuration import append_configs from cadCAD.configuration.utils import config_sim -from cadCAD.engine import ExecutionMode, ExecutionContext, Executor -from cadCAD import configs # Policies per Mechanism @@ -85,6 +83,4 @@ append_configs( policy_ops=[lambda a, b: a + b, lambda y: y * 2] # Default: lambda a, b: a + b ToDO: reduction function requires high lvl explanation ) -exec_mode = ExecutionMode() -single_proc_ctx = ExecutionContext(context=exec_mode.single_proc) -run = Executor(exec_context=single_proc_ctx, configs=configs) + diff --git a/testing/system_models/udo.py b/testing/system_models/udo.py new file mode 100644 index 0000000..1415908 --- /dev/null +++ b/testing/system_models/udo.py @@ -0,0 +1,185 @@ +import pandas as pd +from fn.func import curried +from datetime import timedelta +import pprint as pp + +from cadCAD.utils import SilentDF #, val_switch +from cadCAD.configuration import append_configs +from cadCAD.configuration.utils import time_step, config_sim, var_trigger, var_substep_trigger, env_trigger, psub_list +from cadCAD.configuration.utils.userDefinedObject import udoPipe, UDO + +from cadCAD.engine import ExecutionMode, ExecutionContext, Executor +from cadCAD import configs + + +DF = SilentDF(pd.read_csv('/Users/jjodesty/Projects/DiffyQ-SimCAD/simulations/external_data/output.csv')) + + +class udoExample(object): + def __init__(self, x, dataset=None): + self.x = x + self.mem_id = str(hex(id(self))) + self.ds = dataset # for setting ds initially or querying + self.perception = {} + + def anon(self, f): + return f(self) + + def updateX(self): + self.x += 1 + return self + + def perceive(self, s): + self.perception = self.ds[ + (self.ds['run'] == s['run']) & (self.ds['substep'] == s['substep']) & (self.ds['timestep'] == s['timestep']) + ].drop(columns=['run', 'substep']).to_dict() + return self + + def read(self, ds_uri): + self.ds = SilentDF(pd.read_csv(ds_uri)) + return self + + def write(self, ds_uri): + pd.to_csv(ds_uri) + + # ToDo: Generic update function + + pass + + +state_udo = UDO(udo=udoExample(0, DF), masked_members=['obj', 'perception']) +policy_udoA = UDO(udo=udoExample(0, DF), masked_members=['obj', 'perception']) +policy_udoB = UDO(udo=udoExample(0, DF), masked_members=['obj', 'perception']) + + +sim_config = config_sim({ + "N": 2, + "T": range(4) +}) + +# ToDo: DataFrame Column order +state_dict = { + 'increment': 0, + 'state_udo': state_udo, 'state_udo_tracker': 0, + 'state_udo_perception_tracker': {"ds1": None, "ds2": None, "ds3": None, "timestep": None}, + 'udo_policies': {'udo_A': policy_udoA, 'udo_B': policy_udoB}, + 'udo_policy_tracker': (0, 0), + 'timestamp': '2019-01-01 00:00:00' +} + +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 +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 +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 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): + self.perception = self.ds[ + (self.ds['run'] == s['run']) & (self.ds['substep'] == s['substep']) & (self.ds['timestep'] == s['timestep']) + ].drop(columns=['run', 'substep']).to_dict() + return self + + +def state_udo_update(_g, step, sL, s, _input): + y = 'state_udo' + # s['hydra_state'].updateX().anon(perceive(s)) + s['state_udo'].updateX().perceive(s) + x = udoPipe(s['state_udo']) + return y, x +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_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 id(past_perception): + if len(past_perception) == 0: + return state_dict['state_udo_perception_tracker'] + else: + return past_perception + return lambda _g, step, sL, s, _input: (destination, id(s[source].perception)) +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 +for m in psu_steps: + psu_block[m]["variables"]['udo_policies'] = view_udo_policy + + +def track_udo_policy(destination, source): + def val_switch(v): + if isinstance(v, pd.DataFrame) is True or isinstance(v, SilentDF) is True: + return SilentDF(v) + else: + return v.x + return lambda _g, step, sL, s, _input: (destination, tuple(val_switch(v) for _, v in s[source].items())) +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 + +# 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, + partial_state_update_blocks=partial_state_update_blocks +) + +print() +print("State Updates:") +pp.pprint(partial_state_update_blocks) +print() + + +exec_mode = ExecutionMode() +first_config = configs # only contains config1 +single_proc_ctx = ExecutionContext(context=exec_mode.single_proc) +run = Executor(exec_context=single_proc_ctx, configs=first_config) diff --git a/testing/tests/external_test.py b/testing/tests/external_test.py new file mode 100644 index 0000000..1d86a3e --- /dev/null +++ b/testing/tests/external_test.py @@ -0,0 +1,127 @@ +import unittest +from pprint import pprint + +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.regression_tests import external_dataset +from cadCAD import configs +from testing.generic_test import make_generic_test +from testing.utils import gen_metric_dict + +exec_mode = ExecutionMode() + +print("Simulation Execution: Single Configuration") +print() +first_config = configs # only contains config1 +single_proc_ctx = ExecutionContext(context=exec_mode.single_proc) +run = Executor(exec_context=single_proc_ctx, configs=first_config) + +raw_result, tensor_field = run.execute() +result = pd.DataFrame(raw_result) + +# print(tabulate(result, headers='keys', tablefmt='psql')) + +# cols = ['run', 'substep', 'timestep', 'increment', 'external_data', 'policies'] +# result = result[cols] +# +# metrics = gen_metric_dict(result, ['increment', 'external_data', 'policies']) +# # +# pprint(metrics) + +def get_expected_results(run): + return { + (run, 0, 0): { + 'external_data': {'ds1': None, 'ds2': None, 'ds3': None}, + 'increment': 0, + 'policies': {'ds1': None, 'ds2': None, 'ds3': None} + }, + (run, 1, 1): { + 'external_data': {'ds1': 0, 'ds2': 0, 'ds3': 1}, + 'increment': 1, + 'policies': {'ds1': 0, 'ds2': 0, 'ds3': 1} + }, + (run, 1, 2): { + 'external_data': {'ds1': 1, 'ds2': 40, 'ds3': 5}, + 'increment': 2, + 'policies': {'ds1': 1, 'ds2': 40, 'ds3': 5} + }, + (run, 1, 3): { + 'external_data': {'ds1': 2, 'ds2': 40, 'ds3': 5}, + 'increment': 3, + 'policies': {'ds1': 2, 'ds2': 40, 'ds3': 5} + }, + (run, 2, 1): { + 'external_data': {'ds1': 3, 'ds2': 40, 'ds3': 5}, + 'increment': 4, + 'policies': {'ds1': 3, 'ds2': 40, 'ds3': 5} + }, + (run, 2, 2): { + 'external_data': {'ds1': 4, 'ds2': 40, 'ds3': 5}, + 'increment': 5, + 'policies': {'ds1': 4, 'ds2': 40, 'ds3': 5} + }, + (run, 2, 3): { + 'external_data': {'ds1': 5, 'ds2': 40, 'ds3': 5}, + 'increment': 6, + 'policies': {'ds1': 5, 'ds2': 40, 'ds3': 5} + }, + (run, 3, 1): { + 'external_data': {'ds1': 6, 'ds2': 40, 'ds3': 5}, + 'increment': 7, + 'policies': {'ds1': 6, 'ds2': 40, 'ds3': 5} + }, + (run, 3, 2): { + 'external_data': {'ds1': 7, 'ds2': 40, 'ds3': 5}, + 'increment': 8, + 'policies': {'ds1': 7, 'ds2': 40, 'ds3': 5} + }, + (run, 3, 3): { + 'external_data': {'ds1': 8, 'ds2': 40, 'ds3': 5}, + 'increment': 9, + 'policies': {'ds1': 8, 'ds2': 40, 'ds3': 5} + }, + (run, 4, 1): { + 'external_data': {'ds1': 9, 'ds2': 40, 'ds3': 5}, + 'increment': 10, + 'policies': {'ds1': 9, 'ds2': 40, 'ds3': 5} + }, + (run, 4, 2): { + 'external_data': {'ds1': 10, 'ds2': 40, 'ds3': 5}, + 'increment': 11, + 'policies': {'ds1': 10, 'ds2': 40, 'ds3': 5} + }, + (run, 4, 3): { + 'external_data': {'ds1': 11, 'ds2': 40, 'ds3': 5}, + 'increment': 12, + 'policies': {'ds1': 11, 'ds2': 40, 'ds3': 5} + } + } + + +expected_results = {} +expected_results_1 = get_expected_results(1) +expected_results_2 = get_expected_results(2) +expected_results.update(expected_results_1) +expected_results.update(expected_results_2) + + +def row(a, b): + return a == b +params = [["external_dataset", result, expected_results, ['increment', 'external_data', 'policies'], [row]]] + + +class GenericTest(make_generic_test(params)): + pass + + +if __name__ == '__main__': + unittest.main() + +# print() +# print("Tensor Field: config1") +# print(tabulate(tensor_field, headers='keys', tablefmt='psql')) +# print("Output:") +# print(tabulate(result, headers='keys', tablefmt='psql')) +# print() diff --git a/testing/tests/historical_state_access.py b/testing/tests/historical_state_access.py index 4ab145f..ffc2d95 100644 --- a/testing/tests/historical_state_access.py +++ b/testing/tests/historical_state_access.py @@ -1,14 +1,20 @@ import unittest import pandas as pd -from tabulate import tabulate + +from cadCAD.engine import ExecutionMode, ExecutionContext, Executor from testing.generic_test import make_generic_test -from testing.system_models.historical_state_access import run -from testing.utils import generate_assertions_df +from testing.system_models import historical_state_access +from cadCAD import configs + + +exec_mode = ExecutionMode() +single_proc_ctx = ExecutionContext(context=exec_mode.single_proc) +run = Executor(exec_context=single_proc_ctx, configs=configs) raw_result, tensor_field = run.execute() result = pd.DataFrame(raw_result) - +# ToDo: Discrepance not reported fot collection values. Needs custom test for collection values expected_results = { (1, 0, 0): {'x': 0, 'nonexsistant': [], 'last_x': [], '2nd_to_last_x': [], '3rd_to_last_x': [], '4th_to_last_x': []}, (1, 1, 1): {'x': 1, @@ -31,49 +37,85 @@ expected_results = { '4th_to_last_x': []}, (1, 2, 1): {'x': 4, 'nonexsistant': [], - 'last_x': [{'x': 1, 'run': 1, 'substep': 1, 'timestep': 1}, {'x': 2, 'run': 1, 'substep': 2, 'timestep': 1}, {'x': 3, 'run': 1, 'substep': 3, 'timestep': 1}], - '2nd_to_last_x': [{'x': 0, 'run': 1, 'substep': 0, 'timestep': 0}], + 'last_x': [ + {'x': 4, 'run': 1, 'substep': 1, 'timestep': 1}, # x: 1 + {'x': 2, 'run': 1, 'substep': 2, 'timestep': 1}, + {'x': 3, 'run': 1, 'substep': 3, 'timestep': 1} + ], + '2nd_to_last_x': [{'x': -1, 'run': 1, 'substep': 0, 'timestep': 0}], # x: 0 '3rd_to_last_x': [], '4th_to_last_x': []}, (1, 2, 2): {'x': 5, 'nonexsistant': [], - 'last_x': [{'x': 1, 'run': 1, 'substep': 1, 'timestep': 1}, {'x': 2, 'run': 1, 'substep': 2, 'timestep': 1}, {'x': 3, 'run': 1, 'substep': 3, 'timestep': 1}], + 'last_x': [ + {'x': 1, 'run': 1, 'substep': 1, 'timestep': 1}, + {'x': 2, 'run': 1, 'substep': 2, 'timestep': 1}, + {'x': 3, 'run': 1, 'substep': 3, 'timestep': 1} + ], '2nd_to_last_x': [{'x': 0, 'run': 1, 'substep': 0, 'timestep': 0}], '3rd_to_last_x': [], '4th_to_last_x': []}, (1, 2, 3): {'x': 6, 'nonexsistant': [], - 'last_x': [{'x': 1, 'run': 1, 'substep': 1, 'timestep': 1}, {'x': 2, 'run': 1, 'substep': 2, 'timestep': 1}, {'x': 3, 'run': 1, 'substep': 3, 'timestep': 1}], + 'last_x': [ + {'x': 1, 'run': 1, 'substep': 1, 'timestep': 1}, + {'x': 2, 'run': 1, 'substep': 2, 'timestep': 1}, + {'x': 3, 'run': 1, 'substep': 3, 'timestep': 1} + ], '2nd_to_last_x': [{'x': 0, 'run': 1, 'substep': 0, 'timestep': 0}], '3rd_to_last_x': [], '4th_to_last_x': []}, (1, 3, 1): {'x': 7, 'nonexsistant': [], - 'last_x': [{'x': 4, 'run': 1, 'substep': 1, 'timestep': 2}, {'x': 5, 'run': 1, 'substep': 2, 'timestep': 2}, {'x': 6, 'run': 1, 'substep': 3, 'timestep': 2}], - '2nd_to_last_x': [{'x': 1, 'run': 1, 'substep': 1, 'timestep': 1}, {'x': 2, 'run': 1, 'substep': 2, 'timestep': 1}, {'x': 3, 'run': 1, 'substep': 3, 'timestep': 1}], + 'last_x': [ + {'x': 4, 'run': 1, 'substep': 1, 'timestep': 2}, + {'x': 5, 'run': 1, 'substep': 2, 'timestep': 2}, + {'x': 6, 'run': 1, 'substep': 3, 'timestep': 2} + ], + '2nd_to_last_x': [ + {'x': 1, 'run': 1, 'substep': 1, 'timestep': 1}, + {'x': 2, 'run': 1, 'substep': 2, 'timestep': 1}, + {'x': 3, 'run': 1, 'substep': 3, 'timestep': 1} + ], '3rd_to_last_x': [{'x': 0, 'run': 1, 'substep': 0, 'timestep': 0}], '4th_to_last_x': []}, (1, 3, 2): {'x': 8, 'nonexsistant': [], - 'last_x': [{'x': 4, 'run': 1, 'substep': 1, 'timestep': 2}, {'x': 5, 'run': 1, 'substep': 2, 'timestep': 2}, {'x': 6, 'run': 1, 'substep': 3, 'timestep': 2}], - '2nd_to_last_x': [{'x': 1, 'run': 1, 'substep': 1, 'timestep': 1}, {'x': 2, 'run': 1, 'substep': 2, 'timestep': 1}, {'x': 3, 'run': 1, 'substep': 3, 'timestep': 1}], + 'last_x': [ + {'x': 4, 'run': 1, 'substep': 1, 'timestep': 2}, + {'x': 5, 'run': 1, 'substep': 2, 'timestep': 2}, + {'x': 6, 'run': 1, 'substep': 3, 'timestep': 2} + ], + '2nd_to_last_x': [ + {'x': 1, 'run': 1, 'substep': 1, 'timestep': 1}, + {'x': 2, 'run': 1, 'substep': 2, 'timestep': 1}, + {'x': 3, 'run': 1, 'substep': 3, 'timestep': 1} + ], '3rd_to_last_x': [{'x': 0, 'run': 1, 'substep': 0, 'timestep': 0}], '4th_to_last_x': []}, (1, 3, 3): {'x': 9, 'nonexsistant': [], - 'last_x': [{'x': 4, 'run': 1, 'substep': 1, 'timestep': 2}, {'x': 5, 'run': 1, 'substep': 2, 'timestep': 2}, {'x': 6, 'run': 1, 'substep': 3, 'timestep': 2}], - '2nd_to_last_x': [{'x': 1, 'run': 1, 'substep': 1, 'timestep': 1}, {'x': 2, 'run': 1, 'substep': 2, 'timestep': 1}, {'x': 3, 'run': 1, 'substep': 3, 'timestep': 1}], + 'last_x': [ + {'x': 4, 'run': 1, 'substep': 1, 'timestep': 2}, + {'x': 5, 'run': 1, 'substep': 2, 'timestep': 2}, + {'x': 6, 'run': 1, 'substep': 3, 'timestep': 2} + ], + '2nd_to_last_x': [ + {'x': 1, 'run': 1, 'substep': 1, 'timestep': 1}, + {'x': 2, 'run': 1, 'substep': 2, 'timestep': 1}, + {'x': 3, 'run': 1, 'substep': 3, 'timestep': 1} + ], '3rd_to_last_x': [{'x': 0, 'run': 1, 'substep': 0, 'timestep': 0}], '4th_to_last_x': []} } -params = [["historical_state_access", result, expected_results, - ['x', 'nonexsistant', 'last_x', '2nd_to_last_x', '3rd_to_last_x', '4th_to_last_x']] - ] -# df = generate_assertions_df(result, expected_results, -# ['x', 'nonexsistant', 'last_x', '2nd_to_last_x', '3rd_to_last_x', '4th_to_last_x'] -# ) -# print(tabulate(df, headers='keys', tablefmt='psql')) + +def row(a, b): + return a == b +params = [ + ["historical_state_access", result, expected_results, + ['x', 'nonexsistant', 'last_x', '2nd_to_last_x', '3rd_to_last_x', '4th_to_last_x'], [row]] + ] class GenericTest(make_generic_test(params)): diff --git a/testing/tests/multi_config_test.py b/testing/tests/multi_config_test.py new file mode 100644 index 0000000..c668773 --- /dev/null +++ b/testing/tests/multi_config_test.py @@ -0,0 +1,56 @@ +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.regression_tests import config1, config2 +from cadCAD import configs +from testing.utils import gen_metric_dict + +exec_mode = ExecutionMode() + +print("Simulation Execution: Concurrent Execution") +multi_proc_ctx = ExecutionContext(context=exec_mode.multi_proc) +run = Executor(exec_context=multi_proc_ctx, configs=configs) + + +def get_expected_results_1(run): + return { + (run, 0, 0): {'s1': 0, 's2': 0.0, 's3': 5}, + (run, 1, 1): {'s1': 1, 's2': 4, 's3': 5}, + (run, 1, 2): {'s1': 2, 's2': 6, 's3': 5}, + (run, 1, 3): {'s1': 3, 's2': [30, 300], 's3': 5}, + (run, 2, 1): {'s1': 4, 's2': 4, 's3': 5}, + (run, 2, 2): {'s1': 5, 's2': 6, 's3': 5}, + (run, 2, 3): {'s1': 6, 's2': [30, 300], 's3': 5}, + (run, 3, 1): {'s1': 7, 's2': 4, 's3': 5}, + (run, 3, 2): {'s1': 8, 's2': 6, 's3': 5}, + (run, 3, 3): {'s1': 9, 's2': [30, 300], 's3': 5}, + (run, 4, 1): {'s1': 10, 's2': 4, 's3': 5}, + (run, 4, 2): {'s1': 11, 's2': 6, 's3': 5}, + (run, 4, 3): {'s1': 12, 's2': [30, 300], 's3': 5}, + (run, 5, 1): {'s1': 13, 's2': 4, 's3': 5}, + (run, 5, 2): {'s1': 14, 's2': 6, 's3': 5}, + (run, 5, 3): {'s1': 15, 's2': [30, 300], 's3': 5}, + } + +expected_results_1 = {} +expected_results_A = get_expected_results_1(1) +expected_results_B = get_expected_results_1(2) +expected_results_1.update(expected_results_A) +expected_results_1.update(expected_results_B) + +expected_results_2 = {} + +# print(configs) +i = 0 +config_names = ['config1', 'config2'] +for raw_result, tensor_field in run.execute(): + result = pd.DataFrame(raw_result) + print() + print(f"Tensor Field: {config_names[i]}") + print(tabulate(tensor_field, headers='keys', tablefmt='psql')) + print("Output:") + print(tabulate(result, headers='keys', tablefmt='psql')) + print() + print(gen_metric_dict) + i += 1 diff --git a/testing/tests/param_sweep.py b/testing/tests/param_sweep.py new file mode 100644 index 0000000..a87dab3 --- /dev/null +++ b/testing/tests/param_sweep.py @@ -0,0 +1,85 @@ +import unittest +import pandas as pd + + +from cadCAD.engine import ExecutionMode, ExecutionContext, Executor +from testing.system_models import param_sweep +from cadCAD import configs + +from testing.generic_test import make_generic_test +from testing.system_models.param_sweep import some_function + + +exec_mode = ExecutionMode() +multi_proc_ctx = ExecutionContext(context=exec_mode.multi_proc) +run = Executor(exec_context=multi_proc_ctx, configs=configs) + + +def get_expected_results(run, beta, gamma): + return { + (run, 0, 0): {'policies': {}, 'sweeped': {}, 'alpha': 0, 'beta': 0}, + (run, 1, 1): {'policies': {'gamma': gamma, 'omega': 7}, 'sweeped': {'beta': beta, 'gamma': gamma}, 'alpha': 1, 'beta': beta}, + (run, 1, 2): {'policies': {'gamma': gamma, 'omega': 7}, 'sweeped': {'beta': beta, 'gamma': gamma}, 'alpha': 1, 'beta': beta}, + (run, 1, 3): {'policies': {'gamma': gamma, 'omega': 7}, 'sweeped': {'beta': beta, 'gamma': gamma}, 'alpha': 1, 'beta': beta}, + (run, 2, 1): {'policies': {'gamma': gamma, 'omega': 7}, 'sweeped': {'beta': beta, 'gamma': gamma}, 'alpha': 1, 'beta': beta}, + (run, 2, 2): {'policies': {'gamma': gamma, 'omega': 7}, 'sweeped': {'beta': beta, 'gamma': gamma}, 'alpha': 1, 'beta': beta}, + (run, 2, 3): {'policies': {'gamma': gamma, 'omega': 7}, 'sweeped': {'beta': beta, 'gamma': gamma}, 'alpha': 1, 'beta': beta}, + (run, 3, 1): {'policies': {'gamma': gamma, 'omega': 7}, 'sweeped': {'beta': beta, 'gamma': gamma}, 'alpha': 1, 'beta': beta}, + (run, 3, 2): {'policies': {'gamma': gamma, 'omega': 7}, 'sweeped': {'beta': beta, 'gamma': gamma}, 'alpha': 1, 'beta': beta}, + (run, 3, 3): {'policies': {'gamma': gamma, 'omega': 7}, 'sweeped': {'beta': beta, 'gamma': gamma}, 'alpha': 1, 'beta': beta}, + (run, 4, 1): {'policies': {'gamma': gamma, 'omega': 7}, 'sweeped': {'beta': beta, 'gamma': gamma}, 'alpha': 1, 'beta': beta}, + (run, 4, 2): {'policies': {'gamma': gamma, 'omega': 7}, 'sweeped': {'beta': beta, 'gamma': gamma}, 'alpha': 1, 'beta': beta}, + (run, 4, 3): {'policies': {'gamma': gamma, 'omega': 7}, 'sweeped': {'beta': beta, 'gamma': gamma}, 'alpha': 1, 'beta': beta}, + (run, 5, 1): {'policies': {'gamma': gamma, 'omega': 7}, 'sweeped': beta, 'alpha': 1, 'beta': beta}, + (run, 5, 2): {'policies': {'gamma': gamma, 'omega': 7}, 'sweeped': beta, 'alpha': 1, 'beta': beta}, + (run, 5, 3): {'policies': {'gamma': gamma, 'omega': 7}, 'sweeped': beta, 'alpha': 1, 'beta': beta} + } + + +expected_results_1 = {} +expected_results_1a = get_expected_results(1, 2, 3) +expected_results_1b = get_expected_results(2, 2, 3) +expected_results_1.update(expected_results_1a) +expected_results_1.update(expected_results_1b) + +expected_results_2 = {} +expected_results_2a = get_expected_results(1, some_function, 4) +expected_results_2b = get_expected_results(2, some_function, 4) +expected_results_2.update(expected_results_2a) +expected_results_2.update(expected_results_2b) + + +i = 0 +expected_results = [expected_results_1, expected_results_2] +config_names = ['sweep_config_A', 'sweep_config_B'] + +def row(a, b): + return a == b +def create_test_params(feature, fields): + i = 0 + for raw_result, _ in run.execute(): + yield [feature, pd.DataFrame(raw_result), expected_results[i], fields, [row]] + i += 1 + + +params = list(create_test_params("param_sweep", ['alpha', 'beta', 'policies', 'sweeped'])) + + +class GenericTest(make_generic_test(params)): + pass + + +if __name__ == '__main__': + unittest.main() + +# i = 0 +# # config_names = ['sweep_config_A', 'sweep_config_B'] +# for raw_result, tensor_field in run.execute(): +# result = pd.DataFrame(raw_result) +# print() +# # print("Tensor Field: " + config_names[i]) +# print(tabulate(tensor_field, headers='keys', tablefmt='psql')) +# print("Output:") +# print(tabulate(result, headers='keys', tablefmt='psql')) +# print() +# i += 1 \ No newline at end of file diff --git a/testing/tests/policy_aggregation.py b/testing/tests/policy_aggregation.py index 4be0da4..657b6e6 100644 --- a/testing/tests/policy_aggregation.py +++ b/testing/tests/policy_aggregation.py @@ -1,14 +1,21 @@ import unittest import pandas as pd + +from cadCAD.engine import ExecutionMode, ExecutionContext, Executor from testing.generic_test import make_generic_test -from testing.system_models.policy_aggregation import run +from testing.system_models import policy_aggregation +from cadCAD import configs + +exec_mode = ExecutionMode() +single_proc_ctx = ExecutionContext(context=exec_mode.single_proc) +run = Executor(exec_context=single_proc_ctx, configs=configs) raw_result, tensor_field = run.execute() result = pd.DataFrame(raw_result) expected_results = { (1, 0, 0): {'policies': {}, 's1': 0}, - (1, 1, 1): {'policies': {'policy1': 2, 'policy2': 4}, 's1': 500}, + (1, 1, 1): {'policies': {'policy1': 1, 'policy2': 4}, 's1': 1}, # 'policy1': 2 (1, 1, 2): {'policies': {'policy1': 8, 'policy2': 8}, 's1': 2}, (1, 1, 3): {'policies': {'policy1': 4, 'policy2': 8, 'policy3': 12}, 's1': 3}, (1, 2, 1): {'policies': {'policy1': 2, 'policy2': 4}, 's1': 4}, @@ -19,14 +26,14 @@ expected_results = { (1, 3, 3): {'policies': {'policy1': 4, 'policy2': 8, 'policy3': 12}, 's1': 9} } -params = [["policy_aggregation", result, expected_results, ['policies', 's1']]] -# df = generate_assertions_df(result, expected_results, ['policies', 's1']) -# print(tabulate(df, headers='keys', tablefmt='psql')) +def row(a, b): + return a == b +params = [["policy_aggregation", result, expected_results, ['policies', 's1'], [row]]] class GenericTest(make_generic_test(params)): pass - if __name__ == '__main__': unittest.main() + diff --git a/testing/tests/udo.py b/testing/tests/udo.py new file mode 100644 index 0000000..ea4b42a --- /dev/null +++ b/testing/tests/udo.py @@ -0,0 +1,39 @@ +import unittest +import ctypes +from copy import deepcopy +from pprint import pprint + +import pandas as pd +from tabulate import tabulate + +from testing.generic_test import make_generic_test +from testing.system_models.udo import run +from testing.utils import generate_assertions_df, gen_metric_dict + +raw_result, tensor_field = run.execute() +result = pd.DataFrame(raw_result) + +cols = ['increment', 'state_udo', 'state_udo_perception_tracker', + 'state_udo_tracker', 'timestamp', 'udo_policies', 'udo_policy_tracker'] + + +# print(list(result.columns) +# ctypes.cast(id(a), ctypes.py_object).value +# pprint(gen_metric_dict(result, cols)) +d = gen_metric_dict(result, cols) +pprint(d) + +# for k1, v1 in d: +# print(v1) +# d_copy = deepcopy(d) +# for k, v in d_copy.items(): +# # print(d[k]['state_udo']) # = +# print(ctypes.cast(id(v['state_udo']['mem_id']), ctypes.py_object).value) + + +# pprint(d_copy) + +# df = generate_assertions_df(result, d, cols) +# +# print(tabulate(df, headers='keys', tablefmt='psql')) +# \ No newline at end of file diff --git a/testing/utils.py b/testing/utils.py index 62dc439..0fff73d 100644 --- a/testing/utils.py +++ b/testing/utils.py @@ -1,28 +1,21 @@ -def gen_metric_row(row): - return ((row['run'], row['timestep'], row['substep']), {'s1': row['s1'], 'policies': row['policies']}) +# +# def record_generator(row, cols): +# return {col: row[col] for col in cols} -def gen_metric_row(row): - return { - 'run': row['run'], - 'timestep': row['timestep'], - 'substep': row['substep'], - 's1': row['s1'], - 'policies': row['policies'] - } +def gen_metric_row(row, cols): + return ((row['run'], row['timestep'], row['substep']), {col: row[col] for col in cols}) -def gen_metric_dict(df): - return [gen_metric_row(row) for index, row in df.iterrows()] +# def gen_metric_row(row): +# return ((row['run'], row['timestep'], row['substep']), {'s1': row['s1'], 'policies': row['policies']}) -def generate_assertions_df(df, expected_results, target_cols): - def df_filter(run, timestep, substep): - return df[ - (df['run'] == run) & (df['timestep'] == timestep) & (df['substep'] == substep) - ][target_cols].to_dict(orient='records')[0] +# def gen_metric_row(row): +# return { +# 'run': row['run'], +# 'timestep': row['timestep'], +# 'substep': row['substep'], +# 's1': row['s1'], +# 'policies': row['policies'] +# } - df['test'] = df.apply( - lambda x: \ - df_filter(x['run'], x['timestep'], x['substep']) == expected_results[(x['run'], x['timestep'], x['substep'])] - , axis=1 - ) - - return df \ No newline at end of file +def gen_metric_dict(df, cols): + return dict([gen_metric_row(row, cols) for index, row in df.iterrows()]) From 715e6f9a745f8eea4a71c2e46a63cb461d332d09 Mon Sep 17 00:00:00 2001 From: "Joshua E. Jodesty" Date: Tue, 30 Jul 2019 11:17:49 -0400 Subject: [PATCH 03/21] pre refactor upload --- cadCAD/engine/simulation.py | 13 +- simulations/regression_tests/config1.py | 3 +- simulations/validation/exo_example.ipynb | 763 +++++++++++++++++++++++ 3 files changed, 775 insertions(+), 4 deletions(-) create mode 100644 simulations/validation/exo_example.ipynb diff --git a/cadCAD/engine/simulation.py b/cadCAD/engine/simulation.py index 1823a34..a288658 100644 --- a/cadCAD/engine/simulation.py +++ b/cadCAD/engine/simulation.py @@ -1,3 +1,4 @@ +from pprint import pprint from typing import Any, Callable, Dict, List, Tuple from pathos.pools import ThreadPool as TPool from copy import deepcopy @@ -113,7 +114,9 @@ class Executor: ) -> List[Dict[str, Any]]: last_in_obj: Dict[str, Any] = deepcopy(sL[-1]) - _input: Dict[str, Any] = self.policy_update_exception(self.get_policy_input(sweep_dict, sub_step, sH, last_in_obj, policy_funcs)) + _input: Dict[str, Any] = self.policy_update_exception( + self.get_policy_input(sweep_dict, sub_step, sH, last_in_obj, policy_funcs) + ) # ToDo: add env_proc generator to `last_in_copy` iterator as wrapper function @@ -211,6 +214,9 @@ class Executor: time_step += 1 + pprint(states_list) + print() + return states_list # state_update_pipeline @@ -260,7 +266,9 @@ class Executor: states_list_copy: List[Dict[str, Any]] = list(generate_init_sys_metrics(deepcopy(states_list))) - first_timestep_per_run: List[Dict[str, Any]] = self.run_pipeline(sweep_dict, states_list_copy, configs, env_processes, time_seq, run) + first_timestep_per_run: List[Dict[str, Any]] = self.run_pipeline( + sweep_dict, states_list_copy, configs, env_processes, time_seq, run + ) del states_list_copy return first_timestep_per_run @@ -271,5 +279,4 @@ class Executor: list(range(runs)) ) ) - return pipe_run diff --git a/simulations/regression_tests/config1.py b/simulations/regression_tests/config1.py index a677f5e..a0eb078 100644 --- a/simulations/regression_tests/config1.py +++ b/simulations/regression_tests/config1.py @@ -145,7 +145,8 @@ partial_state_update_block = [ sim_config = config_sim( { - "N": 2, + "N": 1, + # "N": 5, "T": range(5), } ) diff --git a/simulations/validation/exo_example.ipynb b/simulations/validation/exo_example.ipynb new file mode 100644 index 0000000..f1588c7 --- /dev/null +++ b/simulations/validation/exo_example.ipynb @@ -0,0 +1,763 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Exogenous Example\n", + "## Authored by BlockScience, MV Barlin\n", + "### Updated July-10-2019 \n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Key assumptions and space:\n", + "1. Implementation of System Model in cell 2\n", + "2. Timestep = day\n", + "3. Launch simulation, without intervention from changing governance policies" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Library Imports" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "from IPython.display import Image\n", + "import pandas as pd\n", + "import numpy as np\n", + "import matplotlib as mpl\n", + "import matplotlib.pyplot as plt\n", + "import seaborn as sns\n", + "import math\n", + "#from tabulate import tabulate\n", + "from scipy import stats\n", + "sns.set_style('whitegrid')\n", + "from decimal import Decimal\n", + "from datetime import timedelta\n", + "\n", + "%matplotlib inline" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## cadCAD Setup\n", + "#### ----------------cadCAD LIBRARY IMPORTS------------------------" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [], + "source": [ + "from cadCAD.engine import ExecutionMode, ExecutionContext, Executor\n", + "#from simulations.validation import sweep_config\n", + "from cadCAD import configs\n", + "from cadCAD.configuration import append_configs\n", + "from cadCAD.configuration.utils import proc_trigger, ep_time_step, config_sim" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [], + "source": [ + "#from cadCAD.configuration.utils.parameterSweep import config_sim" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [], + "source": [ + "from typing import Dict, List" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### ----------------Random State Seed-----------------------------" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [], + "source": [ + "seed = {\n", + "# 'z': np.random.RandomState(1)\n", + "}" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Timestamp" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [], + "source": [ + "ts_format = '%Y-%m-%d %H:%M:%S'\n", + "t_delta = timedelta(days=0, minutes=0, seconds=1)\n", + "def set_time(_g, step, sL, s, _input):\n", + " y = 'timestamp'\n", + " x = ep_time_step(s, dt_str=s['timestamp'], fromat_str=ts_format, _timedelta=t_delta)\n", + " return (y, x)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# ASSUMED PARAMETERS" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### PRICE LIST" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [], + "source": [ + "# dai_xns_conversion = 1.0 # Assumed for static conversion 'PUBLISHED PRICE LIST' DEPRECATED" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Initial Condition State Variables" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [], + "source": [ + "del_stake_pct = 2\n", + "\n", + "starting_xns = float(10**10) # initial supply of xns tokens\n", + "starting_broker_xns = float(1 * 10**8) # inital holding of xns token by broker app\n", + "starting_broker_fiat = float(1 * 10**5) # inital holding of xns token by broker app\n", + "starting_broker_stable = float(1 * 10**6) # inital holding of stable token by broker app\n", + "starting_deposit_acct = float(100) # inital deposit locked for first month of resources TBD: make function of resource*price\n", + "starting_entrance = float(1 * 10**4) # TBD: make function of entrance fee % * cost * # of initial apps\n", + "starting_app_usage = float(10) # initial fees from app usage \n", + "starting_platform = float(100) # initial platform fees \n", + "starting_resource_fees = float(10) # initial resource fees usage paid by apps \n", + "starting_app_subsidy = float(0.25* 10**9) # initial application subsidy pool\n", + "starting_stake = float(4 * 10**7)\n", + "starting_stake_pool = starting_stake + ((3*10**7)*(del_stake_pct)) # initial staked pool + ((3*10**7)*(del_stake_pct))\n", + "\n", + "#starting_block_reward = float(0) # initial block reward MOVED ABOVE TO POLICY\n", + "starting_capacity_subsidy = float(7.5 * 10**7) # initial capacity subsidy pool\n", + "starting_delegate_holdings = 0.15 * starting_xns\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Initial Condition Composite State Variables" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [], + "source": [ + "# subsidy limit is 30% of the 10B supply\n", + "starting_treasury = float(5.5 * 10**9) \n", + "starting_app_income = float(0) # initial income to application\n", + "starting_resource_income = float(0) # initial income to application\n", + "starting_delegate_income = float(0) # initial income to delegate" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Initial Condition Exogoneous State Variables " + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": {}, + "outputs": [], + "source": [ + "starting_xns_fiat = float(0.01) # initial xns per fiat signal\n", + "starting_fiat_ext = float(1) # initial xns per fiat signal\n", + "starting_stable_ext = float(1) # initial stable signal" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Exogenous Price Updates" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": {}, + "outputs": [], + "source": [ + "def delta_price(mean,sd):\n", + " '''Returns normal random variable generated by first two central moments of price change of input ticker'''\n", + " rv = np.random.normal(mean, sd)\n", + " return rv" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": {}, + "outputs": [], + "source": [ + "\n", + "def xns_ext_update(_g, step, sL, s, _input):\n", + " key = 'XNS_fiat_external'\n", + " \n", + " value = s['XNS_fiat_external'] * (1 + delta_price(0.000000, 0.005))\n", + " \n", + " return key, value" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "From Currency Analysis of DAI-USD pair \n", + "May-09-2018 through June-10-2019 \n", + "Datasource: BitFinex \n", + "Analysis of daily return percentage performed by BlockScience" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": {}, + "outputs": [], + "source": [ + "DAI_mean = 0.0000719\n", + "DAI_sd = 0.006716" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The daily return is computed as: \n", + "$$ r = \\frac{Price_n - Price_{n-1}}{Price_{n-1}} $$ \n", + "Thus, the modelled current price can be as: \n", + "$$ Price_n = Price_{n-1} * r + Price_{n-1} $$" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": {}, + "outputs": [], + "source": [ + "\n", + "def stable_update(_g, step, sL, s, _input):\n", + " key = 'stable_external'\n", + " \n", + " value = s['stable_external'] * (1 + delta_price(DAI_mean, DAI_sd))\n", + " return key, value\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Assumed Parameters" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": {}, + "outputs": [], + "source": [ + "apps_deployed = 1 # Make part of test- application deployment model\n", + "\n", + "starting_deposit_acct = float(100) # inital deposit locked for first month of resources TBD: make function of resource*price\n", + "\n", + "app_resource_fee_constant = 10**1 # in STABLE, assumed per day per total nodes \n", + "platform_fee_constant = 10 # in XNS\n", + "# ^^^^^^^^^^^^ MAKE A PERCENTAGE OR FLAT FEE as PART of TESTING" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "1000" + ] + }, + "execution_count": 16, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "\n", + "alpha = 100 # Fee Rate\n", + "beta = 0.10 # FIXED Too high because multiplied by constant and resource fees\n", + "app_platform = alpha * platform_fee_constant\n", + "app_platform" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "10.0" + ] + }, + "execution_count": 17, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "beta_out =beta*100\n", + "beta_out" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "0.15" + ] + }, + "execution_count": 18, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "starting_capacity_subsidy / (5 * 10**7) / 10" + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "metadata": {}, + "outputs": [], + "source": [ + "\n", + "weight = 0.95 # 0.95 internal weight 5% friction from external markets\n", + "\n", + "def xns_int_update(_g, step, sL, s, _input):\n", + " key = 'XNS_fiat_internal'\n", + "\n", + " internal = s['XNS_fiat_internal'] * weight\n", + " external = s['XNS_fiat_external'] * (1 - weight)\n", + " value = internal + external\n", + " \n", + " return key, value" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### CONFIGURATION DICTIONARY" + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "metadata": {}, + "outputs": [], + "source": [ + "time_step_count = 3652 # days = 10 years\n", + "run_count = 1" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Genesis States" + ] + }, + { + "cell_type": "code", + "execution_count": 21, + "metadata": {}, + "outputs": [], + "source": [ + "#----------STATE VARIABLE Genesis DICTIONARY---------------------------\n", + "genesis_states = {\n", + " 'XNS_fiat_external' : starting_xns_fiat,\n", + " 'XNS_fiat_internal' : starting_xns_fiat,\n", + " # 'fiat_external' : starting_fiat_ext,\n", + " 'stable_external' : starting_stable_ext,\n", + " 'timestamp': '2018-10-01 15:16:24', #es5\n", + "}" + ] + }, + { + "cell_type": "code", + "execution_count": 22, + "metadata": {}, + "outputs": [], + "source": [ + "#--------------EXOGENOUS STATE MECHANISM DICTIONARY--------------------\n", + "exogenous_states = {\n", + " 'XNS_fiat_external' : xns_ext_update,\n", + "# 'fiat_external' : starting_fiat_ext,\n", + " 'stable_external' : stable_update,\n", + " \"timestamp\": set_time,\n", + " }\n", + "\n", + "#--------------ENVIRONMENTAL PROCESS DICTIONARY------------------------\n", + "env_processes = {\n", + "# \"Poisson\": env_proc_id\n", + "}\n", + "#----------------------SIMULATION RUN SETUP----------------------------\n", + "sim_config = config_sim(\n", + " {\n", + " \"N\": run_count,\n", + " \"T\": range(time_step_count)\n", + "# \"M\": g # for parameter sweep\n", + "}\n", + ")\n", + "#----------------------MECHANISM AND BEHAVIOR DICTIONARY---------------\n", + "partial_state_update_block = {\n", + " \"price\": { \n", + " \"policies\": { \n", + " },\n", + " \"variables\": {\n", + " 'XNS_fiat_internal' : xns_int_update\n", + "# 'app_income' : app_earn,\n", + " }\n", + " },\n", + "}\n", + "\n", + "append_configs(\n", + " sim_configs=sim_config,\n", + " initial_state=genesis_states,\n", + " seeds=seed,\n", + " raw_exogenous_states= exogenous_states,\n", + " env_processes=env_processes,\n", + " partial_state_update_blocks=partial_state_update_block\n", + ")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Running cadCAD" + ] + }, + { + "cell_type": "code", + "execution_count": 23, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Simulation Execution: Single Configuration\n", + "\n", + "single_proc: []\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "C:\\Users\\mbarl\\AppData\\Local\\Continuum\\anaconda3\\lib\\site-packages\\cadCAD\\utils\\__init__.py:89: FutureWarning: The use of a dictionary to describe Partial State Update Blocks will be deprecated. Use a list instead.\n", + " FutureWarning)\n" + ] + } + ], + "source": [ + "exec_mode = ExecutionMode()\n", + "\n", + "print(\"Simulation Execution: Single Configuration\")\n", + "print()\n", + "first_config = configs # only contains config1\n", + "single_proc_ctx = ExecutionContext(context=exec_mode.single_proc)\n", + "run1 = Executor(exec_context=single_proc_ctx, configs=first_config)\n", + "run1_raw_result, tensor_field = run1.main()\n", + "result = pd.DataFrame(run1_raw_result)\n", + "# print()\n", + "# print(\"Tensor Field: config1\")\n", + "# print(tabulate(tensor_field, headers='keys', tablefmt='psql'))\n", + "# print(\"Output:\")\n", + "# print(tabulate(result, headers='keys', tablefmt='psql'))\n", + "# print()" + ] + }, + { + "cell_type": "code", + "execution_count": 24, + "metadata": {}, + "outputs": [], + "source": [ + "df = result" + ] + }, + { + "cell_type": "code", + "execution_count": 25, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
XNS_fiat_externalXNS_fiat_internalrunstable_externalsubsteptimestamptimestep
00.0100000.01000011.00000002018-10-01 15:16:240
10.0099440.01000011.00017212018-10-01 15:16:251
20.0098890.00999711.00351612018-10-01 15:16:262
30.0098480.00999210.99065512018-10-01 15:16:273
40.0098140.00998511.00134612018-10-01 15:16:284
50.0097980.00997611.00249512018-10-01 15:16:295
60.0097060.00996710.99491112018-10-01 15:16:306
70.0096250.00995410.99891912018-10-01 15:16:317
80.0096320.00993810.99504712018-10-01 15:16:328
90.0096480.00992210.98078612018-10-01 15:16:339
\n", + "
" + ], + "text/plain": [ + " XNS_fiat_external XNS_fiat_internal run stable_external substep \\\n", + "0 0.010000 0.010000 1 1.000000 0 \n", + "1 0.009944 0.010000 1 1.000172 1 \n", + "2 0.009889 0.009997 1 1.003516 1 \n", + "3 0.009848 0.009992 1 0.990655 1 \n", + "4 0.009814 0.009985 1 1.001346 1 \n", + "5 0.009798 0.009976 1 1.002495 1 \n", + "6 0.009706 0.009967 1 0.994911 1 \n", + "7 0.009625 0.009954 1 0.998919 1 \n", + "8 0.009632 0.009938 1 0.995047 1 \n", + "9 0.009648 0.009922 1 0.980786 1 \n", + "\n", + " timestamp timestep \n", + "0 2018-10-01 15:16:24 0 \n", + "1 2018-10-01 15:16:25 1 \n", + "2 2018-10-01 15:16:26 2 \n", + "3 2018-10-01 15:16:27 3 \n", + "4 2018-10-01 15:16:28 4 \n", + "5 2018-10-01 15:16:29 5 \n", + "6 2018-10-01 15:16:30 6 \n", + "7 2018-10-01 15:16:31 7 \n", + "8 2018-10-01 15:16:32 8 \n", + "9 2018-10-01 15:16:33 9 " + ] + }, + "execution_count": 25, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df.head(10)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.5" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} From 176593ae0f9565de2f5c32e5740c3c0c1eb67384 Mon Sep 17 00:00:00 2001 From: "Joshua E. Jodesty" Date: Tue, 30 Jul 2019 12:41:13 -0400 Subject: [PATCH 04/21] included execution in readme --- README.md | 109 ++++----- cadCAD/engine/simulation.py | 35 --- documentation/Execution.md | 160 +++++++++++++ ...access.md => Historically_State_Access.md} | 40 ++-- .../{policy_agg.md => Policy_Aggregation.md} | 12 +- documentation/Simulation_Configuration.md | 201 ++++++++++++++++ ...eep.md => System_Model_Parameter_Sweep.md} | 15 +- .../examples/historical_state_access.py | 4 +- documentation/examples/param_sweep.py | 18 +- documentation/examples/policy_aggregation.py | 16 +- documentation/examples/sys_model_A.py | 36 +-- documentation/examples/sys_model_A_exec.py | 2 +- documentation/examples/sys_model_B.py | 34 +-- documentation/examples/sys_model_B_exec.py | 4 +- documentation/execution.md | 71 ------ documentation/sys_model_config.md | 220 ------------------ 16 files changed, 508 insertions(+), 469 deletions(-) create mode 100644 documentation/Execution.md rename documentation/{historical_state_access.md => Historically_State_Access.md} (75%) rename documentation/{policy_agg.md => Policy_Aggregation.md} (86%) create mode 100644 documentation/Simulation_Configuration.md rename documentation/{param_sweep.md => System_Model_Parameter_Sweep.md} (84%) delete mode 100644 documentation/execution.md delete mode 100644 documentation/sys_model_config.md diff --git a/README.md b/README.md index f919ca9..129a577 100644 --- a/README.md +++ b/README.md @@ -59,90 +59,95 @@ Examples: **3. Import cadCAD & Run Simulations:** -Examples: `/simulations/*.py` or `/simulations/*.ipynb` -Single Simulation: `/simulations/single_config_run.py` -```python -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 config1 -from cadCAD import configs - -exec_mode = ExecutionMode() - -print("Simulation Execution: Single Configuration") -print() -first_config = configs # only contains config1 -single_proc_ctx = ExecutionContext(context=exec_mode.single_proc) -run1 = Executor(exec_context=single_proc_ctx, configs=first_config) -run1_raw_result, tensor_field = run1.main() -result = pd.DataFrame(run1_raw_result) -print() -print("Tensor Field: config1") -print(tabulate(tensor_field, headers='keys', tablefmt='psql')) -print("Output:") -print(tabulate(result, headers='keys', tablefmt='psql')) -print() -``` - -Parameter Sweep Simulation (Concurrent): `/simulations/param_sweep_run.py` +##### Single Process Execution: +Example [System Model Configurations](link): +* [System Model A](link): `/documentation/examples/sys_model_A.py` +* [System Model B](link): `/documentation/examples/sys_model_B.py` +Execution Examples: +* [System Model A](link): `/documentation/examples/sys_model_A_exec.py` +* [System Model B](link): `/documentation/examples/sys_model_B_exec.py` ```python 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 sweep_config +from documentation.examples import sys_model_A from cadCAD import configs exec_mode = ExecutionMode() -print("Simulation Execution: Concurrent Execution") +# Single Process Execution using a Single System Model Configuration: +# sys_model_A +sys_model_A = [configs[0]] # sys_model_A +single_proc_ctx = ExecutionContext(context=exec_mode.single_proc) +sys_model_A_simulation = Executor(exec_context=single_proc_ctx, configs=sys_model_A) + +sys_model_A_raw_result, sys_model_A_tensor_field = sys_model_A_simulation.execute() +sys_model_A_result = pd.DataFrame(sys_model_A_raw_result) +print() +print("Tensor Field: sys_model_A") +print(tabulate(sys_model_A_tensor_field, headers='keys', tablefmt='psql')) +print("Result: System Events DataFrame") +print(tabulate(sys_model_A_result, headers='keys', tablefmt='psql')) +print() +``` + +### Multiple Simulations (Concurrent): +##### Multiple Simulation Execution (Multi Process Execution) +Documentation: [Simulation Execution](link) +Example [System Model Configurations](link): +* [System Model A](link): `/documentation/examples/sys_model_A.py` +* [System Model B](link): `/documentation/examples/sys_model_B.py` +[Execution Example:](link) `/documentation/examples/sys_model_AB_exec.py` +```python +import pandas as pd +from tabulate import tabulate +from cadCAD.engine import ExecutionMode, ExecutionContext, Executor +from documentation.examples import sys_model_A, sys_model_B +from cadCAD import configs + +exec_mode = ExecutionMode() + +# # Multiple Processes Execution using Multiple System Model Configurations: +# # sys_model_A & sys_model_B multi_proc_ctx = ExecutionContext(context=exec_mode.multi_proc) -run2 = Executor(exec_context=multi_proc_ctx, configs=configs) +sys_model_AB_simulation = Executor(exec_context=multi_proc_ctx, configs=configs) i = 0 -config_names = ['sweep_config_A', 'sweep_config_B'] -for raw_result, tensor_field in run2.main(): - result = pd.DataFrame(raw_result) +config_names = ['sys_model_A', 'sys_model_B'] +for sys_model_AB_raw_result, sys_model_AB_tensor_field in sys_model_AB_simulation.execute(): + sys_model_AB_result = pd.DataFrame(sys_model_AB_raw_result) print() - print("Tensor Field: " + config_names[i]) - print(tabulate(tensor_field, headers='keys', tablefmt='psql')) - print("Output:") - print(tabulate(result, headers='keys', tablefmt='psql')) + print(f"Tensor Field: {config_names[i]}") + print(tabulate(sys_model_AB_tensor_field, headers='keys', tablefmt='psql')) + print("Result: System Events DataFrame:") + print(tabulate(sys_model_AB_result, headers='keys', tablefmt='psql')) print() i += 1 ``` -Multiple Simulations (Concurrent): `/simulations/multi_config run.py` +### Parameter Sweep Simulation (Concurrent): +Documentation: [System Model Parameter Sweep](link) +[Example:](link) `/documentation/examples/param_sweep.py` ```python 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 config1, config2 +from documentation.examples import param_sweep from cadCAD import configs exec_mode = ExecutionMode() - -print("Simulation Execution: Concurrent Execution") multi_proc_ctx = ExecutionContext(context=exec_mode.multi_proc) -run2 = Executor(exec_context=multi_proc_ctx, configs=configs) +run = Executor(exec_context=multi_proc_ctx, configs=configs) -i = 0 -config_names = ['config1', 'config2'] -for raw_result, tensor_field in run2.main(): +for raw_result, tensor_field in run.execute(): result = pd.DataFrame(raw_result) print() - print("Tensor Field: " + config_names[i]) + print("Tensor Field:") print(tabulate(tensor_field, headers='keys', tablefmt='psql')) print("Output:") print(tabulate(result, headers='keys', tablefmt='psql')) print() - i =+ 1 ``` -The above can be run in Jupyter. -```bash -jupyter notebook -``` diff --git a/cadCAD/engine/simulation.py b/cadCAD/engine/simulation.py index a288658..dd2d45d 100644 --- a/cadCAD/engine/simulation.py +++ b/cadCAD/engine/simulation.py @@ -125,41 +125,6 @@ class Executor: for f in state_funcs: yield self.state_update_exception(f(sweep_dict, sub_step, sH, last_in_obj, _input)) - # def generate_record(state_funcs): - # for f in state_funcs: - # tmp_last_in_copy = deepcopy(last_in_obj) - # new_kv = self.state_update_exception(f(sweep_dict, sub_step, sH, tmp_last_in_copy, _input)) - # del tmp_last_in_copy - # yield new_kv - # - # # get `state` from last_in_obj.keys() - # # vals = last_in_obj.values() - # def generate_record(state_funcs): - # for state, v, f in zip(states, vals, state_funcs): - # v_copy = deepcopy(v) - # last_in_obj[state] = v_copy - # new_kv = self.state_update_exception(f(sweep_dict, sub_step, sH, last_in_copy, _input)) - # del v - # yield new_kv - - # {k: v for k, v in l} - - # r() - r(a') -> r(a',b') -> r(a',b',c') - - # r(f(a),b,c) -> r(a'f(b),c) -> r(a',b',f(c)) => r(a',b',c') - # r(a',b.update(),c) - # r1(f(a1),b1,c1) -> r2(a2,f(b1),c1) -> r3(a3,b1,f(c1)) => r(a',b',c') - - # r1(f(a1),b,c) -> r2(a,f(b1),c) -> r3(a,b,f(c1)) => r(a',b',c') - - # r1(f(a1),b1,c1) -> r(a2',b2.update(),c2) -> r3(a3,b1,f(c1)) => r(a',b',c') - - - # r1(f(a1),b1,c1) -> r2(a2,f(b1),c1) -> r3(a3,b1,f(c1)) => r(a',b',c') - - - # reduce(lambda r: F(r), [r2(f(a),b,c), r2(a,f(b),c), r3(a,b,f(c))]) => R(a',b',c') - def transfer_missing_fields(source, destination): for k in source: if k not in destination: diff --git a/documentation/Execution.md b/documentation/Execution.md new file mode 100644 index 0000000..613c8a6 --- /dev/null +++ b/documentation/Execution.md @@ -0,0 +1,160 @@ +Simulation Execution +== +System Simulations are executed with the execution engine executor (`cadCAD.engine.Executor`) given System Model +Configurations. There are multiple simulation Execution Modes and Execution Contexts. + +### Steps: +1. #### *Choose Execution Mode*: + * ##### Simulation Execution Modes: + `cadCAD` executes a process per System Model Configuration and a thread per System Simulation. + ##### Class: `cadCAD.engine.ExecutionMode` + ##### Attributes: + * **Single Process:** A single process Execution Mode for a single System Model Configuration (Example: + `cadCAD.engine.ExecutionMode().single_proc`). + * **Multi-Process:** Multiple process Execution Mode for System Model Simulations which executes on a thread per + given System Model Configuration (Example: `cadCAD.engine.ExecutionMode().multi_proc`). +2. #### *Create Execution Context using Execution Mode:* +```python +from cadCAD.engine import ExecutionMode, ExecutionContext +exec_mode = ExecutionMode() +single_proc_ctx = ExecutionContext(context=exec_mode.single_proc) +``` +3. #### *Create Simulation Executor* +```python +from cadCAD.engine import Executor +from cadCAD import configs +simulation = Executor(exec_context=single_proc_ctx, configs=configs) +``` +4. #### *Execute Simulation: Produce System Event Dataset* +A Simulation execution produces a System Event Dataset and the Tensor Field applied to initial states used to create it. +```python +import pandas as pd +raw_system_events, tensor_field = simulation.execute() + +# Simulation Result Types: +# raw_system_events: List[dict] +# tensor_field: pd.DataFrame + +# Result System Events DataFrame +simulation_result = pd.DataFrame(raw_system_events) +``` + +##### Example Tensor Field +``` ++----+-----+--------------------------------+--------------------------------+ +| | m | b1 | s1 | +|----+-----+--------------------------------+--------------------------------| +| 0 | 1 | | | +| 1 | 2 | | | +| 2 | 3 | | | ++----+-----+--------------------------------+--------------------------------+ +``` + +##### Example Result: System Events DataFrame +```python ++----+-------+------------+-----------+------+-----------+ +| | run | timestep | substep | s1 | s2 | +|----+-------+------------+-----------+------+-----------| +| 0 | 1 | 0 | 0 | 0 | 0.0 | +| 1 | 1 | 1 | 1 | 1 | 4 | +| 2 | 1 | 1 | 2 | 2 | 6 | +| 3 | 1 | 1 | 3 | 3 | [ 30 300] | +| 4 | 2 | 0 | 0 | 0 | 0.0 | +| 5 | 2 | 1 | 1 | 1 | 4 | +| 6 | 2 | 1 | 2 | 2 | 6 | +| 7 | 2 | 1 | 3 | 3 | [ 30 300] | ++----+-------+------------+-----------+------+-----------+ +``` + +### Execution Examples: +##### Single Simulation Execution (Single Process Execution) +Example [System Model Configurations](link): +* [System Model A](link): `/documentation/examples/sys_model_A.py` +* [System Model B](link): `/documentation/examples/sys_model_B.py` +Execution Examples: +* [System Model A](link): `/documentation/examples/sys_model_A_exec.py` +* [System Model B](link): `/documentation/examples/sys_model_B_exec.py` +```python +import pandas as pd +from tabulate import tabulate +from cadCAD.engine import ExecutionMode, ExecutionContext, Executor +from documentation.examples import sys_model_A +from cadCAD import configs + +exec_mode = ExecutionMode() + +# Single Process Execution using a Single System Model Configuration: +# sys_model_A +sys_model_A = [configs[0]] # sys_model_A +single_proc_ctx = ExecutionContext(context=exec_mode.single_proc) +sys_model_A_simulation = Executor(exec_context=single_proc_ctx, configs=sys_model_A) + +sys_model_A_raw_result, sys_model_A_tensor_field = sys_model_A_simulation.execute() +sys_model_A_result = pd.DataFrame(sys_model_A_raw_result) +print() +print("Tensor Field: sys_model_A") +print(tabulate(sys_model_A_tensor_field, headers='keys', tablefmt='psql')) +print("Result: System Events DataFrame") +print(tabulate(sys_model_A_result, headers='keys', tablefmt='psql')) +print() +``` + +##### Multiple Simulation Execution + +* ##### *Multi Process Execution* +Documentation: [Simulation Execution](link) +[Execution Example:](link) `/documentation/examples/sys_model_AB_exec.py` +Example [System Model Configurations](link): +* [System Model A](link): `/documentation/examples/sys_model_A.py` +* [System Model B](link): `/documentation/examples/sys_model_B.py` +```python +import pandas as pd +from tabulate import tabulate +from cadCAD.engine import ExecutionMode, ExecutionContext, Executor +from documentation.examples import sys_model_A, sys_model_B +from cadCAD import configs + +exec_mode = ExecutionMode() + +# # Multiple Processes Execution using Multiple System Model Configurations: +# # sys_model_A & sys_model_B +multi_proc_ctx = ExecutionContext(context=exec_mode.multi_proc) +sys_model_AB_simulation = Executor(exec_context=multi_proc_ctx, configs=configs) + +i = 0 +config_names = ['sys_model_A', 'sys_model_B'] +for sys_model_AB_raw_result, sys_model_AB_tensor_field in sys_model_AB_simulation.execute(): + sys_model_AB_result = pd.DataFrame(sys_model_AB_raw_result) + print() + print(f"Tensor Field: {config_names[i]}") + print(tabulate(sys_model_AB_tensor_field, headers='keys', tablefmt='psql')) + print("Result: System Events DataFrame:") + print(tabulate(sys_model_AB_result, headers='keys', tablefmt='psql')) + print() + i += 1 +``` + +* ##### *Parameter Sweep* +Documentation: [System Model Parameter Sweep](link) +[Example:](link) `/documentation/examples/param_sweep.py` +```python +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 documentation.examples import param_sweep +from cadCAD import configs + +exec_mode = ExecutionMode() +multi_proc_ctx = ExecutionContext(context=exec_mode.multi_proc) +run = Executor(exec_context=multi_proc_ctx, configs=configs) + +for raw_result, tensor_field in run.execute(): + result = pd.DataFrame(raw_result) + print() + print("Tensor Field:") + print(tabulate(tensor_field, headers='keys', tablefmt='psql')) + print("Output:") + print(tabulate(result, headers='keys', tablefmt='psql')) + print() +``` diff --git a/documentation/historical_state_access.md b/documentation/Historically_State_Access.md similarity index 75% rename from documentation/historical_state_access.md rename to documentation/Historically_State_Access.md index 944fc8a..7d684bf 100644 --- a/documentation/historical_state_access.md +++ b/documentation/Historically_State_Access.md @@ -1,24 +1,21 @@ Historical State Access == -The 3rd parameter of state and policy update functions (labels as `sH` of type `List[List[dict]]`) provides access to -past Partial State Updates (PSU) given a negative offset number. `access_block` is used to access past PSUs -(`List[dict]`) from `sH`. +#### Motivation +The current state (values of state variables) is accessed through the `s` list. When the user requires previous state variable values, they may be accessed through the state history list, `sH`. Accessing the state history should be implemented without creating unintended feedback loops on the current state. -Example: `-2` denotes to second to last PSU +The 3rd parameter of state and policy update functions (labeled as `sH` of type `List[List[dict]]`) provides access to past Partial State Update Block (PSUB) given a negative offset number. `access_block` is used to access past PSUBs (`List[dict]`) from `sH`. For example, an offset of `-2` denotes the second to last PSUB. -##### Exclusion List +#### Exclusion List Create a list of states to exclude from the reported PSU. ```python exclusion_list = [ - 'nonexsistant', 'last_x', '2nd_to_last_x', '3rd_to_last_x', '4th_to_last_x' + 'nonexistent', 'last_x', '2nd_to_last_x', '3rd_to_last_x', '4th_to_last_x' ] ``` ##### Example Policy Updates ###### Last partial state update ```python -from cadCAD.configuration.utils import config_sim, access_block - -def last_update(_g, substep, sH, s): +def last_update(_params, substep, sH, s): return {"last_x": access_block( state_history=sH, target_field="last_x", # Add a field to the exclusion list @@ -27,30 +24,30 @@ def last_update(_g, substep, sH, s): ) } ``` -* Note: Although `target_field` adding a field to the exclusion may seem redundant, it is useful in the case of -the exclusion list being empty while the `target_field` is assigned to a state or a policy key. +* Note: Although `target_field` adding a field to the exclusion may seem redundant, it is useful in the case of the exclusion list being empty while the `target_field` is assigned to a state or a policy key. +##### Define State Updates ###### 2nd to last partial state update ```python -def second2last_update(_g, substep, sH, s): +def second2last_update(_params, substep, sH, s): return {"2nd_to_last_x": access_block(sH, "2nd_to_last_x", -2, exclusion_list)} ``` -##### Define State Updates + ###### 3rd to last partial state update ```python -def third_to_last_x(_g, substep, sH, s, _input): +def third_to_last_x(_params, substep, sH, s, _input): return '3rd_to_last_x', access_block(sH, "3rd_to_last_x", -3, exclusion_list) ``` ###### 4rd to last partial state update ```python -def fourth_to_last_x(_g, substep, sH, s, _input): +def fourth_to_last_x(_params, substep, sH, s, _input): return '4th_to_last_x', access_block(sH, "4th_to_last_x", -4, exclusion_list) ``` -###### Non-exsistant partial state update -* `psu_block_offset >= 0` doesn't exsist +###### Non-exsistent partial state update +* `psu_block_offset >= 0` doesn't exist ```python -def nonexsistant(_g, substep, sH, s, _input): - return 'nonexsistant', access_block(sH, "nonexsistant", 0, exclusion_list) +def nonexistent(_params, substep, sH, s, _input): + return 'nonexistent', access_block(sH, "nonexistent", 0, exclusion_list) ``` #### Example Simulation @@ -91,7 +88,4 @@ Example: `last_x` | 8 | [{'x': 4, 'run': 1, 'substep': 1, 'timestep': 2}, {'x': 5, 'run': 1, 'substep': 2, 'timestep': 2}, {'x': 6, 'run': 1, 'substep': 3, 'timestep': 2}] | | 9 | [{'x': 4, 'run': 1, 'substep': 1, 'timestep': 2}, {'x': 5, 'run': 1, 'substep': 2, 'timestep': 2}, {'x': 6, 'run': 1, 'substep': 3, 'timestep': 2}] | +----+-----------------------------------------------------------------------------------------------------------------------------------------------------+ -``` - -#### [Example Configuration](link) -#### [Example Results](link) \ No newline at end of file +``` \ No newline at end of file diff --git a/documentation/policy_agg.md b/documentation/Policy_Aggregation.md similarity index 86% rename from documentation/policy_agg.md rename to documentation/Policy_Aggregation.md index 7ddaa50..64b4b1e 100644 --- a/documentation/policy_agg.md +++ b/documentation/Policy_Aggregation.md @@ -15,9 +15,9 @@ policy_ops=[add, mult_by_2] ##### Example Policy Updates per Partial State Update (PSU) ```python -def p1_psu1(_g, step, sL, s): +def p1_psu1(_params, step, sH, s): return {'policy1': 1} -def p2_psu1(_g, step, sL, s): +def p2_psu1(_params, step, sH, s): return {'policy2': 2} ``` * `add` not applicable due to lack of redundant policies @@ -25,9 +25,9 @@ def p2_psu1(_g, step, sL, s): * Result: `{'policy1': 2, 'policy2': 4}` ```python -def p1_psu2(_g, step, sL, s): +def p1_psu2(_params, step, sH, s): return {'policy1': 2, 'policy2': 2} -def p2_psu2(_g, step, sL, s): +def p2_psu2(_params, step, sH, s): return {'policy1': 2, 'policy2': 2} ``` * `add` applicable due to redundant policies @@ -35,9 +35,9 @@ def p2_psu2(_g, step, sL, s): * Result: `{'policy1': 8, 'policy2': 8}` ```python -def p1_psu3(_g, step, sL, s): +def p1_psu3(_params, step, sH, s): return {'policy1': 1, 'policy2': 2, 'policy3': 3} -def p2_psu3(_g, step, sL, s): +def p2_psu3(_params, step, sH, s): return {'policy1': 1, 'policy2': 2, 'policy3': 3} ``` * `add` applicable due to redundant policies diff --git a/documentation/Simulation_Configuration.md b/documentation/Simulation_Configuration.md new file mode 100644 index 0000000..a49e364 --- /dev/null +++ b/documentation/Simulation_Configuration.md @@ -0,0 +1,201 @@ +Simulation Configuration +== + +## Introduction + +Given a **Simulation Configuration**, cadCAD produces datasets that represent the evolution of the state of a system over [discrete time](https://en.wikipedia.org/wiki/Discrete_time_and_continuous_time#Discrete_time). The state of the system is described by a set of [State Variables](#State-Variables). The dynamic of the system is described by [Policy Functions](#Policy-Functions) and [State Update Functions](#State-Update-Functions), which are evaluated by cadCAD according to the definitions set by the user in [Partial State Update Blocks](#Partial-State-Update-Blocks). + +A Simulation Configuration is comprised of a [System Model](#System-Model) and a set of [Simulation Properties](#Simulation-Properties) + +`append_configs`, stores a **Simulation Configuration** to be [Executed](/JS4Q9oayQASihxHBJzz4Ug) by cadCAD + +```python +from cadCAD.configuration import append_configs + +append_configs( + initial_state = ..., # System Model + partial_state_update_blocks = .., # System Model + policy_ops = ..., # System Model + sim_configs = ... # Simulation Properties +) +``` +Parameters: +* **initial_state** : _dict_ + [State Variables](#State-Variables) and their initial values +* **partial_state_update_blocks** : List[dict[dict]] + List of [Partial State Update Blocks](#Partial-State-Update-Blocks) +* **policy_ops** : List[functions] + See [Policy Aggregation](/63k2ncjITuqOPCUHzK7Viw) +* **sim_configs** : _???_ + See [System Model Parameter Sweep](/4oJ_GT6zRWW8AO3yMhFKrg) + +## Simulation Properties + +Simulation properties are passed to `append_configs` in the `sim_configs` parameter. To construct this paramenter, we use the `config_sim` function in `cadCAD.configuration.utils` + +```python +from cadCAD.configuration.utils import config_sim + +c = config_sim({ + "N": ..., + "T": range(...), + "M": ... +}) + +append_configs( + ... + sim_configs = c # Simulation Properties +) +``` + +### T - Simulation Length +Computer simulations run in discrete time: + +>Discrete time views values of variables as occurring at distinct, separate "points in time", or equivalently as being unchanged throughout each non-zero region of time ("time period")—that is, time is viewed as a discrete variable. (...) This view of time corresponds to a digital clock that gives a fixed reading of 10:37 for a while, and then jumps to a new fixed reading of 10:38, etc. ([source: Wikipedia](https://en.wikipedia.org/wiki/Discrete_time_and_continuous_time#Discrete_time)) + +As is common in many simulation tools, in cadCAD too we refer to each discrete unit of time as a **timestep**. cadCAD increments a "time counter", and at each step it updates the state variables according to the equations that describe the system. + +The main simulation property that the user must set when creating a Simulation Configuration is the number of timesteps in the simulation. In other words, for how long do they want to simulate the system that has been modeled. + +### N - Number of Runs + +cadCAD facilitates running multiple simulations of the same system sequentially, reporting the results of all those runs in a single dataset. This is especially helpful for running [Monte Carlo Simulations](https://github.com/BlockScience/cadCAD-Tutorials/blob/master/01%20Tutorials/robot-marbles-part-4/robot-marbles-part-4.ipynb). + +### M - Parameters of the System + +Parameters of the system, passed to the state update functions and the policy functions in the `params` parameter are defined here. See [System Model Parameter Sweep](/4oJ_GT6zRWW8AO3yMhFKrg) for more information. + +## System Model +The System Model describes the system that will be simulated in cadCAD. It is comprised of a set of [State Variables](#Sate-Variables) and the [State Update Functions](#State-Update-Functions) that determine the evolution of the state of the system over time. [Policy Functions](#Policy-Functions) (representations of user policies or internal system control policies) may also be part of a System Model. + +### State Variables +>A state variable is one of the set of variables that are used to describe the mathematical "state" of a dynamical system. Intuitively, the state of a system describes enough about the system to determine its future behaviour in the absence of any external forces affecting the system. ([source: Wikipedia](https://en.wikipedia.org/wiki/State_variable)) + +cadCAD can handle state variables of any Python data type, including custom classes. It is up to the user of cadCAD to determine the state variables needed to **sufficiently and accurately** describe the system they are interested in. + +State Variables are passed to `append_configs` along with its initial values, as a Python `dict` where the `dict_keys` are the names of the variables and the `dict_values` are their initial values. + +```python +from cadCAD.configuration import append_configs + +genesis_states = { + 'state_variable_1': 0, + 'state_variable_2': 0, + 'state_variable_3': 1.5, + 'timestamp': '2019-01-01 00:00:00' +} + +append_configs( + initial_state = genesis_states, + ... +) +``` +### State Update Functions +State Update Functions represent equations according to which the state variables change over time. Each state update function must return a tuple containing a string with the name of the state variable being updated and its new value. Each state update function can only modify a single state variable. The general structure of a state update function is: +```python +def state_update_function_A(_params, substep, sH, s, _input): + ... + return 'state_variable_name', new_value +``` +Parameters: +* **_params** : _dict_ + [System parameters](/4oJ_GT6zRWW8AO3yMhFKrg) +* **substep** : _int_ + Current [substep](#Substep) +* **sH** : _list[list[dict_]] + Historical values of all state variables for the simulation. See [Historical State Access](/smiyQTnATtC9xPwvF8KbBQ) for details +* **s** : _dict_ + Current state of the system, where the `dict_keys` are the names of the state variables and the `dict_values` are their current values. +* **_input** : _dict_ + Aggregation of the signals of all policy functions in the current [Partial State Update Block](#Partial-State-Update-Block) + +Return: +* _tuple_ containing a string with the name of the state variable being updated and its new value. + +State update functions should not modify any of the parameters passed to it, as those are mutable Python objects that cadCAD relies on in order to run the simulation according to the specifications. + +### Policy Functions +A Policy Function computes one or more signals to be passed to [State Update Functions](#State-Update-Functions) (via the _\_input_ parameter). Read [this article](https://github.com/BlockScience/cadCAD-Tutorials/blob/master/01%20Tutorials/robot-marbles-part-2/robot-marbles-part-2.ipynb) for details on why and when to use policy functions. + + + +The general structure of a policy function is: +```python +def policy_function_1(_params, substep, sH, s): + ... + return {'signal_1': value_1, ..., 'signal_N': value_N} +``` +Parameters: +* **_params** : _dict_ + [System parameters](/4oJ_GT6zRWW8AO3yMhFKrg) +* **substep** : _int_ + Current [substep](#Substep) +* **sH** : _list[list[dict_]] + Historical values of all state variables for the simulation. See [Historical State Access](/smiyQTnATtC9xPwvF8KbBQ) for details +* **s** : _dict_ + Current state of the system, where the `dict_keys` are the names of the state variables and the `dict_values` are their current values. + +Return: +* _dict_ of signals to be passed to the state update functions in the same [Partial State Update Block](#Partial-State-Update-Blocks) + +Policy functions should not modify any of the parameters passed to it, as those are mutable Python objects that cadCAD relies on in order to run the simulation according to the specifications. + +At each [Partial State Update Block](#Partial-State-Update-Blocks) (PSUB), the `dicts` returned by all policy functions within that PSUB dictionaries are aggregated into a single `dict` using an initial reduction function (a key-wise operation, default: `dic1['keyA'] + dic2['keyA']`) and optional subsequent map functions. The resulting aggregated `dict` is then passed as the `_input` parameter to the state update functions in that PSUB. For more information on how to modify the aggregation method, see [Policy Aggregation](/63k2ncjITuqOPCUHzK7Viw). + +### Partial State Update Blocks + +A **Partial State Update Block** (PSUB) is a set of State Update Functions and Policy Functions such that State Update Functions in the set are independent from each other and Policies in the set are independent from each other and from the State Update Functions in the set. In other words, if a state variable is updated in a PSUB, its new value cannnot impact the State Update Functions and Policy Functions in that PSUB - only those in the next PSUB. + +![](https://i.imgur.com/9rlX9TG.png) + +Partial State Update Blocks are passed to `append_configs` as a List of Python `dicts` where the `dict_keys` are named `"policies"` and `"variables"` and the values are also Python `dicts` where the keys are the names of the policy and state update functions and the values are the functions. + +```python +PSUBs = [ + { + "policies": { + "b_1": policy_function_1, + ... + "b_J": policy_function_J + }, + "variables": { + "s_1": state_update_function_1, + ... + "s_K": state_update_function_K + } + }, #PSUB_1, + {...}, #PSUB_2, + ... + {...} #PSUB_M +] + +append_configs( + ... + partial_state_update_blocks = PSUBs, + ... +) + +``` + +#### Substep +At each timestep, cadCAD iterates over the `partial_state_update_blocks` list. For each Partial State Update Block, cadCAD returns a record containing the state of the system at the end of that PSUB. We refer to that subdivision of a timestep as a `substep`. + +## Result Dataset + +cadCAD returns a dataset containing the evolution of the state variables defined by the user over time, with three `int` indexes: +* `run` - id of the [run](#N-Number-of-Runs) +* `timestep` - discrete unit of time (the total number of timesteps is defined by the user in the [T Simulation Parameter](#T-Simulation-Length)) +* `substep` - subdivision of timestep (the number of [substeps](#Substeps) is the same as the number of Partial State Update Blocks) + +Therefore, the total number of records in the resulting dataset is `N` x `T` x `len(partial_state_update_blocks)` + +#### [System Simulation Execution](link) diff --git a/documentation/param_sweep.md b/documentation/System_Model_Parameter_Sweep.md similarity index 84% rename from documentation/param_sweep.md rename to documentation/System_Model_Parameter_Sweep.md index 3822369..aa47e7b 100644 --- a/documentation/param_sweep.md +++ b/documentation/System_Model_Parameter_Sweep.md @@ -31,7 +31,7 @@ Previous State: `y = 0` ```python -def state_update(_params, step, sL, s, _input): +def state_update(_params, step, sH, s, _input): y = 'state' x = s['state'] + _params['alpha'] + _params['gamma'] return y, x @@ -43,8 +43,8 @@ def state_update(_params, step, sL, s, _input): ##### Example Policy Updates ```python # Internal States per Mechanism -def policies(_g, step, sL, s): - return {'beta': _g['beta'], 'gamma': _g['gamma']} +def policies(_params, step, sH, s): + return {'beta': _params['beta'], 'gamma': _params['gamma']} ``` * Simulation 1: `{'beta': 2, 'gamma': 3]}` * Simulation 2: `{'beta': 5, 'gamma': 4}` @@ -53,6 +53,13 @@ def policies(_g, step, sL, s): ```python from cadCAD.configuration.utils import config_sim +g = { + 'alpha': [1], + 'beta': [2, 5], + 'gamma': [3, 4], + 'omega': [7] +} + sim_config = config_sim( { "N": 2, @@ -64,5 +71,3 @@ sim_config = config_sim( #### [Example Configuration](link) #### [Example Results](link) - - diff --git a/documentation/examples/historical_state_access.py b/documentation/examples/historical_state_access.py index 5079988..fa038e7 100644 --- a/documentation/examples/historical_state_access.py +++ b/documentation/examples/historical_state_access.py @@ -75,7 +75,7 @@ PSUB = { "variables": variables } -partial_state_update_block = { +psubs = { "PSUB1": PSUB, "PSUB2": PSUB, "PSUB3": PSUB @@ -91,7 +91,7 @@ sim_config = config_sim( append_configs( sim_configs=sim_config, initial_state=genesis_states, - partial_state_update_blocks=partial_state_update_block + partial_state_update_blocks=psubs ) exec_mode = ExecutionMode() diff --git a/documentation/examples/param_sweep.py b/documentation/examples/param_sweep.py index a118966..1157db2 100644 --- a/documentation/examples/param_sweep.py +++ b/documentation/examples/param_sweep.py @@ -31,31 +31,31 @@ env_process = {} # Policies -def gamma(_params, step, sL, s): +def gamma(_params, step, sH, s): return {'gamma': _params['gamma']} -def omega(_params, step, sL, s): +def omega(_params, step, sH, s): return {'omega': _params['omega'](7)} # Internal States -def alpha(_params, step, sL, s, _input): +def alpha(_params, step, sH, s, _input): return 'alpha', _params['alpha'] -def alpha_plus_gamma(_params, step, sL, s, _input): +def alpha_plus_gamma(_params, step, sH, s, _input): return 'alpha_plus_gamma', _params['alpha'] + _params['gamma'] -def beta(_params, step, sL, s, _input): +def beta(_params, step, sH, s, _input): return 'beta', _params['beta'] -def policies(_params, step, sL, s, _input): +def policies(_params, step, sH, s, _input): return 'policies', _input -def sweeped(_params, step, sL, s, _input): +def sweeped(_params, step, sH, s, _input): return 'sweeped', {'beta': _params['beta'], 'gamma': _params['gamma']} @@ -90,7 +90,7 @@ for m in psu_steps: psu_block[m]['variables']['policies'] = policies psu_block[m]["variables"]['sweeped'] = var_timestep_trigger(y='sweeped', f=sweeped) -partial_state_update_blocks = psub_list(psu_block, psu_steps) +psubs = psub_list(psu_block, psu_steps) print() pp.pprint(psu_block) print() @@ -99,7 +99,7 @@ append_configs( sim_configs=sim_config, initial_state=genesis_states, env_processes=env_process, - partial_state_update_blocks=partial_state_update_blocks + partial_state_update_blocks=psubs ) exec_mode = ExecutionMode() diff --git a/documentation/examples/policy_aggregation.py b/documentation/examples/policy_aggregation.py index 86313e7..38865ad 100644 --- a/documentation/examples/policy_aggregation.py +++ b/documentation/examples/policy_aggregation.py @@ -7,19 +7,19 @@ from cadCAD.engine import ExecutionMode, ExecutionContext, Executor from cadCAD import configs # Policies per Mechanism -def p1m1(_g, step, sL, s): +def p1m1(_g, step, sH, s): return {'policy1': 1} -def p2m1(_g, step, sL, s): +def p2m1(_g, step, sH, s): return {'policy2': 2} -def p1m2(_g, step, sL, s): +def p1m2(_g, step, sH, s): return {'policy1': 2, 'policy2': 2} -def p2m2(_g, step, sL, s): +def p2m2(_g, step, sH, s): return {'policy1': 2, 'policy2': 2} -def p1m3(_g, step, sL, s): +def p1m3(_g, step, sH, s): return {'policy1': 1, 'policy2': 2, 'policy3': 3} -def p2m3(_g, step, sL, s): +def p2m3(_g, step, sH, s): return {'policy1': 1, 'policy2': 2, 'policy3': 3} @@ -44,7 +44,7 @@ variables = { "policies": policies } -partial_state_update_block = { +psubs = { "m1": { "policies": { "p1": p1m1, @@ -79,7 +79,7 @@ sim_config = config_sim( append_configs( sim_configs=sim_config, initial_state=genesis_states, - partial_state_update_blocks=partial_state_update_block, + partial_state_update_blocks=psubs, policy_ops=[lambda a, b: a + b, lambda y: y * 2] # Default: lambda a, b: a + b ) diff --git a/documentation/examples/sys_model_A.py b/documentation/examples/sys_model_A.py index 92a7fe3..5c54dbe 100644 --- a/documentation/examples/sys_model_A.py +++ b/documentation/examples/sys_model_A.py @@ -14,51 +14,51 @@ seeds = { # Policies per Mechanism -def p1m1(_g, step, sL, s): +def p1m1(_g, step, sH, s): return {'param1': 1} -def p2m1(_g, step, sL, s): +def p2m1(_g, step, sH, s): return {'param1': 1, 'param2': 4} -def p1m2(_g, step, sL, s): +def p1m2(_g, step, sH, s): return {'param1': 'a', 'param2': 2} -def p2m2(_g, step, sL, s): +def p2m2(_g, step, sH, s): return {'param1': 'b', 'param2': 4} -def p1m3(_g, step, sL, s): +def p1m3(_g, step, sH, s): return {'param1': ['c'], 'param2': np.array([10, 100])} -def p2m3(_g, step, sL, s): +def p2m3(_g, step, sH, s): return {'param1': ['d'], 'param2': np.array([20, 200])} # Internal States per Mechanism -def s1m1(_g, step, sL, s, _input): +def s1m1(_g, step, sH, s, _input): y = 's1' x = s['s1'] + 1 return (y, x) -def s2m1(_g, step, sL, s, _input): +def s2m1(_g, step, sH, s, _input): y = 's2' x = _input['param2'] return (y, x) -def s1m2(_g, step, sL, s, _input): +def s1m2(_g, step, sH, s, _input): y = 's1' x = s['s1'] + 1 return (y, x) -def s2m2(_g, step, sL, s, _input): +def s2m2(_g, step, sH, s, _input): y = 's2' x = _input['param2'] return (y, x) -def s1m3(_g, step, sL, s, _input): +def s1m3(_g, step, sH, s, _input): y = 's1' x = s['s1'] + 1 return (y, x) -def s2m3(_g, step, sL, s, _input): +def s2m3(_g, step, sH, s, _input): y = 's2' x = _input['param2'] return (y, x) -def policies(_g, step, sL, s, _input): +def policies(_g, step, sH, s, _input): y = 'policies' x = _input return (y, x) @@ -68,17 +68,17 @@ def policies(_g, step, sL, s, _input): proc_one_coef_A = 0.7 proc_one_coef_B = 1.3 -def es3(_g, step, sL, s, _input): +def es3(_g, step, sH, s, _input): y = 's3' x = s['s3'] * bound_norm_random(seeds['a'], proc_one_coef_A, proc_one_coef_B) return (y, x) -def es4(_g, step, sL, s, _input): +def es4(_g, step, sH, s, _input): y = 's4' x = s['s4'] * bound_norm_random(seeds['b'], proc_one_coef_A, proc_one_coef_B) return (y, x) -def update_timestamp(_g, step, sL, s, _input): +def update_timestamp(_g, step, sH, 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)) @@ -102,7 +102,7 @@ env_processes = { } -partial_state_update_block = [ +psubs = [ { "policies": { "b1": p1m1, @@ -154,6 +154,6 @@ append_configs( sim_configs=sim_config, initial_state=genesis_states, env_processes=env_processes, - partial_state_update_blocks=partial_state_update_block, + partial_state_update_blocks=psubs, policy_ops=[lambda a, b: a + b] ) \ No newline at end of file diff --git a/documentation/examples/sys_model_A_exec.py b/documentation/examples/sys_model_A_exec.py index 8a630d9..e568482 100644 --- a/documentation/examples/sys_model_A_exec.py +++ b/documentation/examples/sys_model_A_exec.py @@ -15,7 +15,7 @@ sys_model_A_simulation = Executor(exec_context=single_proc_ctx, configs=sys_mode sys_model_A_raw_result, sys_model_A_tensor_field = sys_model_A_simulation.execute() sys_model_A_result = pd.DataFrame(sys_model_A_raw_result) print() -print("Tensor Field: config1") +print("Tensor Field: sys_model_A") print(tabulate(sys_model_A_tensor_field, headers='keys', tablefmt='psql')) print("Result: System Events DataFrame") print(tabulate(sys_model_A_result, headers='keys', tablefmt='psql')) diff --git a/documentation/examples/sys_model_B.py b/documentation/examples/sys_model_B.py index 7298d0b..2c6ad9e 100644 --- a/documentation/examples/sys_model_B.py +++ b/documentation/examples/sys_model_B.py @@ -13,46 +13,46 @@ seeds = { # Policies per Mechanism -def p1m1(_g, step, sL, s): +def p1m1(_g, step, sH, s): return {'param1': 1} -def p2m1(_g, step, sL, s): +def p2m1(_g, step, sH, s): return {'param2': 4} -def p1m2(_g, step, sL, s): +def p1m2(_g, step, sH, s): return {'param1': 'a', 'param2': 2} -def p2m2(_g, step, sL, s): +def p2m2(_g, step, sH, s): return {'param1': 'b', 'param2': 4} -def p1m3(_g, step, sL, s): +def p1m3(_g, step, sH, s): return {'param1': ['c'], 'param2': np.array([10, 100])} -def p2m3(_g, step, sL, s): +def p2m3(_g, step, sH, s): return {'param1': ['d'], 'param2': np.array([20, 200])} # Internal States per Mechanism -def s1m1(_g, step, sL, s, _input): +def s1m1(_g, step, sH, s, _input): y = 's1' x = _input['param1'] return (y, x) -def s2m1(_g, step, sL, s, _input): +def s2m1(_g, step, sH, s, _input): y = 's2' x = _input['param2'] return (y, x) -def s1m2(_g, step, sL, s, _input): +def s1m2(_g, step, sH, s, _input): y = 's1' x = _input['param1'] return (y, x) -def s2m2(_g, step, sL, s, _input): +def s2m2(_g, step, sH, s, _input): y = 's2' x = _input['param2'] return (y, x) -def s1m3(_g, step, sL, s, _input): +def s1m3(_g, step, sH, s, _input): y = 's1' x = _input['param1'] return (y, x) -def s2m3(_g, step, sL, s, _input): +def s2m3(_g, step, sH, s, _input): y = 's2' x = _input['param2'] return (y, x) @@ -62,17 +62,17 @@ def s2m3(_g, step, sL, s, _input): proc_one_coef_A = 0.7 proc_one_coef_B = 1.3 -def es3(_g, step, sL, s, _input): +def es3(_g, step, sH, s, _input): y = 's3' x = s['s3'] * bound_norm_random(seeds['a'], proc_one_coef_A, proc_one_coef_B) return (y, x) -def es4(_g, step, sL, s, _input): +def es4(_g, step, sH, s, _input): y = 's4' x = s['s4'] * bound_norm_random(seeds['b'], proc_one_coef_A, proc_one_coef_B) return (y, x) -def update_timestamp(_g, step, sL, s, _input): +def update_timestamp(_g, step, sH, 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)) @@ -95,7 +95,7 @@ env_processes = { "s4": env_trigger(3)(trigger_field='timestamp', trigger_vals=trigger_timestamps, funct_list=[lambda _g, x: 10]) } -partial_state_update_block = [ +psubs = [ { "policies": { "b1": p1m1, @@ -143,5 +143,5 @@ append_configs( sim_configs=sim_config, initial_state=genesis_states, env_processes=env_processes, - partial_state_update_blocks=partial_state_update_block + partial_state_update_blocks=psubs ) \ No newline at end of file diff --git a/documentation/examples/sys_model_B_exec.py b/documentation/examples/sys_model_B_exec.py index 53eef37..75a339a 100644 --- a/documentation/examples/sys_model_B_exec.py +++ b/documentation/examples/sys_model_B_exec.py @@ -9,14 +9,14 @@ exec_mode = ExecutionMode() print("Simulation Execution: Single Configuration") print() -first_config = configs # only contains config2 +first_config = configs # only contains sys_model_B single_proc_ctx = ExecutionContext(context=exec_mode.single_proc) run = Executor(exec_context=single_proc_ctx, configs=first_config) raw_result, tensor_field = run.execute() result = pd.DataFrame(raw_result) print() -print("Tensor Field: config1") +print("Tensor Field: sys_model_B") print(tabulate(tensor_field, headers='keys', tablefmt='psql')) print("Output:") print(tabulate(result, headers='keys', tablefmt='psql')) diff --git a/documentation/execution.md b/documentation/execution.md deleted file mode 100644 index f34064b..0000000 --- a/documentation/execution.md +++ /dev/null @@ -1,71 +0,0 @@ -Simulation Execution -== -System Simulations are executed with the execution engine executor (`cadCAD.engine.Executor`) given System Model -Configurations. There are multiple simulation Execution Modes and Execution Contexts. - -### Steps: -1. #### *Choose Execution Mode*: - * ##### Simulation Execution Modes: - `cadCAD` executes a process per System Model Configuration and a thread per System Simulation. - ##### Class: `cadCAD.engine.ExecutionMode` - ##### Attributes: - * **Single Process:** A single process Execution Mode for a single System Model Configuration (Example: - `cadCAD.engine.ExecutionMode().single_proc`). - * **Multi-Process:** Multiple process Execution Mode for System Model Simulations which executes on a thread per - given System Model Configuration (Example: `cadCAD.engine.ExecutionMode().multi_proc`). -2. #### *Create Execution Context using Execution Mode:* -```python -from cadCAD.engine import ExecutionMode, ExecutionContext -exec_mode = ExecutionMode() -single_proc_ctx = ExecutionContext(context=exec_mode.single_proc) -``` -3. #### *Create Simulation Executor* -```python -from cadCAD.engine import Executor -from cadCAD import configs -simulation = Executor(exec_context=single_proc_ctx, configs=configs) -``` -4. #### *Execute Simulation: Produce System Event Dataset* -A Simulation execution produces a System Event Dataset and the Tensor Field applied to initial states used to create it. -```python -import pandas as pd -raw_system_events, tensor_field = simulation.execute() - -# Simulation Result Types: -# raw_system_events: List[dict] -# tensor_field: pd.DataFrame - -# Result System Events DataFrame -simulation_result = pd.DataFrame(raw_system_events) -``` - -##### Example Tensor Field -``` -+----+-----+--------------------------------+--------------------------------+ -| | m | b1 | s1 | -|----+-----+--------------------------------+--------------------------------| -| 0 | 1 | | | -| 1 | 2 | | | -| 2 | 3 | | | -+----+-----+--------------------------------+--------------------------------+ -``` - -##### Example Result: System Events DataFrame -```python -+----+-------+------------+-----------+------+-----------+ -| | run | timestep | substep | s1 | s2 | -|----+-------+------------+-----------+------+-----------| -| 0 | 1 | 0 | 0 | 0 | 0.0 | -| 1 | 1 | 1 | 1 | 1 | 4 | -| 2 | 1 | 1 | 2 | 2 | 6 | -| 3 | 1 | 1 | 3 | 3 | [ 30 300] | -| 4 | 2 | 0 | 0 | 0 | 0.0 | -| 5 | 2 | 1 | 1 | 1 | 4 | -| 6 | 2 | 1 | 2 | 2 | 6 | -| 7 | 2 | 1 | 3 | 3 | [ 30 300] | -+----+-------+------------+-----------+------+-----------+ -``` - -##### [Single Process Example Execution](link) - -##### [Multiple Process Example Execution](link) diff --git a/documentation/sys_model_config.md b/documentation/sys_model_config.md deleted file mode 100644 index edece69..0000000 --- a/documentation/sys_model_config.md +++ /dev/null @@ -1,220 +0,0 @@ -System Model Configuration -== - -#### Introduction - -Given System Model Configurations, cadCAD produces system event datasets that conform to specified system metrics. Each -event / record is of [Enogenous State variables](link) produced by user defined [Partial State Updates](link) (PSU / -functions that update state); A sequence of event / record subsets that comprises the resulting system event dataset is -produced by a [Partial State Update Block](link) (PSUB / a Tensor Field for which State, Policy, and Time are dimensions -and PSU functions are values). - -A **System Model Configuration** is comprised of a simulation configuration, initial endogenous states, Partial State -Update Blocks, environmental process, and a user defined policy aggregation function. - -Execution: - -#### Simulation Properties - -###### System Metrics -The following system metrics determine the size of resulting system event datasets: -* `run` - the number of simulations in the resulting dataset -* `timestep` - the number of timestamps in the resulting dataset -* `substep` - the number of PSUs per `timestep` / within PSUBS -* Number of events / records: `run` x `timestep` x `substep` - -###### Simulation Configuration -For the following dictionary, `T` is assigned a `timestep` range, `N` is assigned the number of simulation runs, and -`params` is assigned the [**Parameter Sweep**](link) dictionary. - -```python -from cadCAD.configuration.utils import config_sim - -sim_config = config_sim({ - "N": 2, - "T": range(5), - "M": params, # Optional -}) -``` - -#### Initial Endogenous States -**Enogenous State variables** are read-only variables defined to capture the shape and property of the network and -represent internal input and signal. - -The PSUB tensor field is applied to the following states to produce a resulting system event -dataset. -```python -genesis_states = { - 's1': 0.0, - 's2': 0.0, - 's3': 1.0, - 'timestamp': '2018-10-01 15:16:24' -} -``` - -#### Partial State Update Block: -- ***Partial State Update Block(PSUB)*** ***(Define ?)*** Tensor Field for which State, Policy, Time are dimensions -and Partial State Update functions are values. -- ***Partial State Update (PSU)*** are user defined functions that encodes state updates and are executed in -a specified order PSUBs. PSUs update states given the most recent set of states and PSU policies. -- ***Mechanism*** ***(Define)*** - - -The PSUBs is a list of PSU dictionaries of the structure within the code block below. PSUB elements (PSU dictionaries) -are listed / defined in order of `substeps` and **identity functions** (returning a previous state's value) are assigned -to unreferenced states within PSUs. The number of records produced produced per `timestep` is the number of `substeps`. - -```python -partial_state_update_block = [ - { - "policies": { - "b1": p1_psu1, - "b2": p2_psu1 - }, - "variables": { - "s1": s1_psu1, - "s2": s2_psu1 - } - }, - { - "policies": { - "b1": p1_psu2, - }, - "variables": { - "s2": s2_psu2 - } - }, - {...} -] -``` -*Notes:* -1. An identity function (returning the previous state value) is assigned to `s1` in the second PSU. -2. Currently the only names that need not correspond to the convention below are `'b1'` and `'b2'`. - -#### Policies -- ***Policies*** ***(Define)*** When are policies behavior ? -- ***Behaviors*** model agent behaviors in reaction to state variables and exogenous variables. The -resulted user action will become an input to PSUs. Note that user behaviors should not directly update value -of state variables. - -Policies accept parameter sweep variables [see link] `_g` (`dict`), the most recent -`substep` integer, the state history[see link] (`sH`), the most recent state record `s` (`dict) as inputs and returns a -set of actions (`dict`). - -Policy functions return dictionaries as actions. Policy functions provide access to parameter sweep variables [see link] -via dictionary `_g`. -```python -def p1_psu1(_g, substep, sH, s): - return {'policy1': 1} -def p2_psu1(_g, substep, sH, s): - return {'policy1': 1, 'policy2': 4} -``` -For each PSU, multiple policy dictionaries are aggregated into a single dictionary to be imputted into -all state functions using an initial reduction function (default: `lambda a, b: a + b`) and optional subsequent map -functions. -Example Result: `{'policy1': 2, 'policy2': 4}` - -#### State Updates -State update functions provide access to parameter sweep variables [see link] `_g` (`dict`), the most recent `substep` -integer, the state history[see link] (`sH`), the most recent state record as a dictionary (`s`), the policies of a -PSU (`_input`), and returns a tuple of the state variable's name and the resulting new value of the variable. - -```python -def state_update(_g, substep, sH, s, _input): - ... - return state, update -``` -**Note:** Each state update function updates one state variable at a time. Changes to multiple state variables requires -separate state update functions. A generic example of a PSU is as follows. - -* ##### Endogenous State Updates -They are only updated by PSUs and can be used as inputs to a PSUs. -```python -def s1_update(_g, substep, sH, s, _input): - x = _input['policy1'] + 1 - return 's1', x - -def s2_update(_g, substep, sH, s, _input): - x = _input['policy2'] - return 's2', x -``` - -* ##### Exogenous State Updates -***Exogenous State variables*** ***(Review)*** are read-only variables that represent external input and signal. They -update endogenous states and are only updated by environmental processes. Exgoneous variables can be used -as an input to a PSU that impacts state variables. ***(Expand upon Exogenous state updates)*** - -```python -from datetime import timedelta -from cadCAD.configuration.utils import time_step -def es3_update(_g, substep, sH, s, _input): - x = ... - return 's3' -def es4_update(_g, substep, sH, s, _input): - x = ... - return 's4', x -def update_timestamp(_g, substep, sH, s, _input): - x = time_step(dt_str=s[y], dt_format='%Y-%m-%d %H:%M:%S', _timedelta=timedelta(days=0, minutes=0, seconds=1)) - return 'timestamp', x -``` -Exogenous state update functions (`es3_update`, `es4_update` and `es5_update`) update once per timestamp and should be -included as a part of the first PSU in the PSUB. -```python -partial_state_update_block['psu1']['variables']['s3'] = es3_update -partial_state_update_block['psu1']['variables']['s4'] = es4_update -partial_state_update_block['psu1']['variables']['timestamp'] = update_timestamp -``` - -* #### Environmental Process -- ***Environmental processes*** model external changes that directly impact exogenous states at given specific -conditions such as market shocks at specific timestamps. - -Create a dictionary like `env_processes` below for which the keys are exogenous states and the values are lists of user -defined **Environment Update** functions to be composed (e.g. `[f(params, x), g(params, x)]` becomes -`f(params, g(params, x))`). - -Environment Updates accept the [**Parameter Sweep**](link) dictionary `params` and a state as a result of a PSU. -```python -def env_update(params, state): - . . . - return updated_state - -# OR - -env_update = lambda params, state: state + 5 -``` - -The `env_trigger` function is used to apply composed environment update functions to a list of specific exogenous state -update results. `env_trigger` accepts the total number of `substeps` for the simulation / `end_substep` and returns a -function accepting `trigger_field`, `trigger_vals`, and `funct_list`. - -In the following example functions are used to add `5` to every `s3` update and assign `10` to `s4` at -`timestamp`s `'2018-10-01 15:16:25'`, `'2018-10-01 15:16:27'`, and `'2018-10-01 15:16:29'`. -```python -from cadCAD.configuration.utils import env_trigger -trigger_timestamps = ['2018-10-01 15:16:25', '2018-10-01 15:16:27', '2018-10-01 15:16:29'] -env_processes = { - "s3": [lambda params, x: x + 5], - "s4": env_trigger(end_substep=3)( - trigger_field='timestamp', trigger_vals=trigger_timestamps, funct_list=[lambda params, x: 10] - ) -} -``` - -#### System Model Configuration -`append_configs`, stores a **System Model Configuration** to be (Executed)[url] as -simulations producing system event dataset(s) - -```python -from cadCAD.configuration import append_configs - -append_configs( - sim_configs=sim_config, - initial_state=genesis_states, - env_processes=env_processes, - partial_state_update_blocks=partial_state_update_block, - policy_ops=[lambda a, b: a + b] -) -``` - -#### [System Simulation Execution](link) From 9399c6b72827ede3fd2fdb18eb4ffc3d8b9abdcf Mon Sep 17 00:00:00 2001 From: "Joshua E. Jodesty" Date: Tue, 30 Jul 2019 12:53:25 -0400 Subject: [PATCH 05/21] improved readme --- README.md | 20 ++++++++------------ documentation/Execution.md | 4 ++-- 2 files changed, 10 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index 129a577..679a8bf 100644 --- a/README.md +++ b/README.md @@ -27,12 +27,13 @@ It allows us to use code to solidify our conceptualized ideas and see if the out iteratively refine our work until we have constructed a model that closely reflects reality at the start of the model, and see how it evolves. We can then use these results to inform business decisions. -#### Simulation Instructional: +#### Documentation: * ##### [System Model Configuration](link) * ##### [System Simulation Execution](link) +* ##### [Tutorials](link) -#### Installation: -**1. Install Dependencies:** + +#### 0. Installation: Install Dependencies **Option A:** Package Repository Access @@ -49,22 +50,17 @@ python3 setup.py sdist bdist_wheel pip3 install dist/*.whl ``` -**2. Configure Simulation:** -Intructions: -`/Simulation.md` +#### 1. [Configure System Model](link) -Examples: -`/simulations/validation/*` - -**3. Import cadCAD & Run Simulations:** +#### 2. [Execute Simulations:](link) ##### Single Process Execution: Example [System Model Configurations](link): * [System Model A](link): `/documentation/examples/sys_model_A.py` * [System Model B](link): `/documentation/examples/sys_model_B.py` -Execution Examples: +Example Simulation Executions: * [System Model A](link): `/documentation/examples/sys_model_A_exec.py` * [System Model B](link): `/documentation/examples/sys_model_B_exec.py` ```python @@ -98,7 +94,7 @@ Documentation: [Simulation Execution](link) Example [System Model Configurations](link): * [System Model A](link): `/documentation/examples/sys_model_A.py` * [System Model B](link): `/documentation/examples/sys_model_B.py` -[Execution Example:](link) `/documentation/examples/sys_model_AB_exec.py` +[Example Simulation Executions::](link) `/documentation/examples/sys_model_AB_exec.py` ```python import pandas as pd from tabulate import tabulate diff --git a/documentation/Execution.md b/documentation/Execution.md index 613c8a6..d8dc83b 100644 --- a/documentation/Execution.md +++ b/documentation/Execution.md @@ -71,7 +71,7 @@ simulation_result = pd.DataFrame(raw_system_events) Example [System Model Configurations](link): * [System Model A](link): `/documentation/examples/sys_model_A.py` * [System Model B](link): `/documentation/examples/sys_model_B.py` -Execution Examples: +Example Simulation Executions: * [System Model A](link): `/documentation/examples/sys_model_A_exec.py` * [System Model B](link): `/documentation/examples/sys_model_B_exec.py` ```python @@ -103,7 +103,7 @@ print() * ##### *Multi Process Execution* Documentation: [Simulation Execution](link) -[Execution Example:](link) `/documentation/examples/sys_model_AB_exec.py` +[Example Simulation Executions::](link) `/documentation/examples/sys_model_AB_exec.py` Example [System Model Configurations](link): * [System Model A](link): `/documentation/examples/sys_model_A.py` * [System Model B](link): `/documentation/examples/sys_model_B.py` From 67c46cfe094c7bbb86becd375ccc71a2b1ca4c22 Mon Sep 17 00:00:00 2001 From: "Joshua E. Jodesty" Date: Wed, 21 Aug 2019 14:16:31 -0400 Subject: [PATCH 06/21] diverged docs --- README.md | 6 +++--- documentation/Simulation_Configuration.md | 16 ++++++++++++---- documentation/System_Model_Parameter_Sweep.md | 4 ++-- .../examples/historical_state_access.py | 1 - documentation/examples/policy_aggregation.py | 2 +- documentation/examples/sys_model_A.py | 3 +++ 6 files changed, 21 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 679a8bf..ee67bb9 100644 --- a/README.md +++ b/README.md @@ -33,11 +33,12 @@ and see how it evolves. We can then use these results to inform business decisio * ##### [Tutorials](link) -#### 0. Installation: Install Dependencies +#### 0. Installation: **Option A:** Package Repository Access -***IMPORTANT NOTE:*** Tokens are issued to and meant to be used by trial users and BlockScience employees **ONLY**. Replace \ with an issued token in the script below. +***IMPORTANT NOTE:*** Tokens are issued to and meant to be used by trial users and BlockScience employees **ONLY**. +Replace \ with an issued token in the script below. ```bash pip3 install pandas pathos fn funcy tabulate pip3 install cadCAD --extra-index-url https://@repo.fury.io/blockscience/ @@ -55,7 +56,6 @@ pip3 install dist/*.whl #### 2. [Execute Simulations:](link) - ##### Single Process Execution: Example [System Model Configurations](link): * [System Model A](link): `/documentation/examples/sys_model_A.py` diff --git a/documentation/Simulation_Configuration.md b/documentation/Simulation_Configuration.md index a49e364..304a01d 100644 --- a/documentation/Simulation_Configuration.md +++ b/documentation/Simulation_Configuration.md @@ -7,7 +7,8 @@ Given a **Simulation Configuration**, cadCAD produces datasets that represent th A Simulation Configuration is comprised of a [System Model](#System-Model) and a set of [Simulation Properties](#Simulation-Properties) -`append_configs`, stores a **Simulation Configuration** to be [Executed](/JS4Q9oayQASihxHBJzz4Ug) by cadCAD +`append_configs`, stores a **Simulation Configuration** to be +[Executed](https://github.com/BlockScience/cadCAD-Tutorials/blob/master/Documentation/Simulation_Execution.md) by cadCAD ```python from cadCAD.configuration import append_configs @@ -21,13 +22,20 @@ append_configs( ``` Parameters: * **initial_state** : _dict_ + [State Variables](#State-Variables) and their initial values + * **partial_state_update_blocks** : List[dict[dict]] + List of [Partial State Update Blocks](#Partial-State-Update-Blocks) + * **policy_ops** : List[functions] - See [Policy Aggregation](/63k2ncjITuqOPCUHzK7Viw) -* **sim_configs** : _???_ - See [System Model Parameter Sweep](/4oJ_GT6zRWW8AO3yMhFKrg) + + See [Policy Aggregation](https://github.com/BlockScience/cadCAD-Tutorials/blob/master/Documentation/Policy_Aggregation.md) + +* **sim_configs** : + + See ## Simulation Properties diff --git a/documentation/System_Model_Parameter_Sweep.md b/documentation/System_Model_Parameter_Sweep.md index aa47e7b..63b7306 100644 --- a/documentation/System_Model_Parameter_Sweep.md +++ b/documentation/System_Model_Parameter_Sweep.md @@ -69,5 +69,5 @@ sim_config = config_sim( ) ``` -#### [Example Configuration](link) -#### [Example Results](link) +#### [Example](link) + diff --git a/documentation/examples/historical_state_access.py b/documentation/examples/historical_state_access.py index fa038e7..327460a 100644 --- a/documentation/examples/historical_state_access.py +++ b/documentation/examples/historical_state_access.py @@ -11,7 +11,6 @@ exclusion_list = ['nonexsistant', 'last_x', '2nd_to_last_x', '3rd_to_last_x', '4 # Policies per Mechanism -# WARNING: DO NOT delete elements from sH # state_history, target_field, psu_block_offset, exculsion_list def last_update(_g, substep, sH, s): return {"last_x": access_block( diff --git a/documentation/examples/policy_aggregation.py b/documentation/examples/policy_aggregation.py index 38865ad..2807a74 100644 --- a/documentation/examples/policy_aggregation.py +++ b/documentation/examples/policy_aggregation.py @@ -80,7 +80,7 @@ append_configs( sim_configs=sim_config, initial_state=genesis_states, partial_state_update_blocks=psubs, - policy_ops=[lambda a, b: a + b, lambda y: y * 2] # Default: lambda a, b: a + b + policy_ops=[lambda a, b: a + b] # Default: lambda a, b: a + b , lambda y: y * 2 ) exec_mode = ExecutionMode() diff --git a/documentation/examples/sys_model_A.py b/documentation/examples/sys_model_A.py index 5c54dbe..3614291 100644 --- a/documentation/examples/sys_model_A.py +++ b/documentation/examples/sys_model_A.py @@ -35,6 +35,9 @@ def s1m1(_g, step, sH, s, _input): y = 's1' x = s['s1'] + 1 return (y, x) + + + def s2m1(_g, step, sH, s, _input): y = 's2' x = _input['param2'] From 747ec36e5096e959cbdf3f79cbba25f484d8e18d Mon Sep 17 00:00:00 2001 From: "Joshua E. Jodesty" Date: Wed, 21 Aug 2019 14:27:31 -0400 Subject: [PATCH 07/21] os refactor pt 1 --- cadCAD/configuration/__init__.py | 4 +- cadCAD/configuration/utils/__init__.py | 16 +-- .../utils/depreciationHandler.py | 6 -- .../configuration/utils/policyAggregation.py | 3 +- .../configuration/utils/userDefinedObject.py | 17 +-- cadCAD/engine/__init__.py | 1 - cadCAD/engine/simulation.py | 12 --- cadCAD/engine/utils.py | 4 - cadCAD/utils/__init__.py | 31 +----- cadCAD/utils/sys_config.py | 102 ++---------------- 10 files changed, 27 insertions(+), 169 deletions(-) diff --git a/cadCAD/configuration/__init__.py b/cadCAD/configuration/__init__.py index 56aae05..cbfea98 100644 --- a/cadCAD/configuration/__init__.py +++ b/cadCAD/configuration/__init__.py @@ -9,8 +9,6 @@ from cadCAD.configuration.utils import exo_update_per_ts from cadCAD.configuration.utils.policyAggregation import dict_elemwise_sum from cadCAD.configuration.utils.depreciationHandler import sanitize_partial_state_updates, sanitize_config -# policy_ops=[foldr(dict_elemwise_sum())] -# policy_ops=[reduce, lambda a, b: {**a, **b}] class Configuration(object): def __init__(self, sim_config={}, initial_state={}, seeds={}, env_processes={}, @@ -28,7 +26,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: diff --git a/cadCAD/configuration/utils/__init__.py b/cadCAD/configuration/utils/__init__.py index 8c16b8c..ea5f068 100644 --- a/cadCAD/configuration/utils/__init__.py +++ b/cadCAD/configuration/utils/__init__.py @@ -5,12 +5,10 @@ from fn.func import curried from funcy import curry import pandas as pd -# Temporary from cadCAD.configuration.utils.depreciationHandler import sanitize_partial_state_updates from cadCAD.utils import dict_filter, contains_type, flatten_tabulated_dict, tabulate_dict -# ToDo: Fix - Returns empty when partial_state_update is missing in Configuration class TensorFieldReport: def __init__(self, config_proc): self.config_proc = config_proc @@ -56,7 +54,6 @@ def time_step(dt_str, dt_format='%Y-%m-%d %H:%M:%S', _timedelta = tstep_delta): return t.strftime(dt_format) -# ToDo: Inject in first elem of last PSUB from Historical state ep_t_delta = timedelta(days=0, minutes=0, seconds=1) def ep_time_step(s_condition, dt_str, fromat_str='%Y-%m-%d %H:%M:%S', _timedelta = ep_t_delta): # print(dt_str) @@ -65,7 +62,7 @@ def ep_time_step(s_condition, dt_str, fromat_str='%Y-%m-%d %H:%M:%S', _timedelta else: return dt_str -# mech_sweep_filter + def partial_state_sweep_filter(state_field, partial_state_updates): partial_state_dict = dict([(k, v[state_field]) for k, v in partial_state_updates.items()]) return dict([ @@ -77,7 +74,7 @@ def partial_state_sweep_filter(state_field, partial_state_updates): def state_sweep_filter(raw_exogenous_states): return dict([(k, v) for k, v in raw_exogenous_states.items() if isinstance(v, list)]) -# sweep_mech_states + @curried def sweep_partial_states(_type, in_config): configs = [] @@ -129,16 +126,19 @@ def exo_update_per_ts(ep): return {es: ep_decorator(f, es) for es, f in ep.items()} + def trigger_condition(s, pre_conditions, cond_opp): condition_bools = [s[field] in precondition_values for field, precondition_values in pre_conditions.items()] return reduce(cond_opp, condition_bools) + 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 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) @@ -173,7 +173,6 @@ def env_trigger(end_substep): curry(trigger)(end_substep)(trigger_field)(trigger_vals)(funct_list) -# param sweep enabling middleware def config_sim(d): def process_variables(d): return flatten_tabulated_dict(tabulate_dict(d)) @@ -184,15 +183,18 @@ def config_sim(d): 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 { 'policies': policies, 'states': state_updates } + def genereate_psubs(policy_grid, states_grid, policies, state_updates): PSUBS = [] for policy_ids, state_list in zip(policy_grid, states_grid): @@ -202,7 +204,7 @@ def genereate_psubs(policy_grid, states_grid, policies, state_updates): return PSUBS -# ToDo: DO NOT filter sH for every state/policy update. Requires a consumable sH (new sH) + def access_block(state_history, target_field, psu_block_offset, exculsion_list=[]): exculsion_list += [target_field] def filter_history(key_list, sH): diff --git a/cadCAD/configuration/utils/depreciationHandler.py b/cadCAD/configuration/utils/depreciationHandler.py index 330823b..ab57082 100644 --- a/cadCAD/configuration/utils/depreciationHandler.py +++ b/cadCAD/configuration/utils/depreciationHandler.py @@ -2,8 +2,6 @@ from copy import deepcopy def sanitize_config(config): - # for backwards compatibility, we accept old arguments via **kwargs - # TODO: raise specific deprecation warnings for key == 'state_dict', key == 'seed', key == 'mechanisms' for key, value in config.kwargs.items(): if key == 'state_dict': config.initial_state = value @@ -18,8 +16,6 @@ def sanitize_config(config): def sanitize_partial_state_updates(partial_state_updates): new_partial_state_updates = deepcopy(partial_state_updates) - # for backwards compatibility we accept the old keys - # ('behaviors' and 'states') and rename them def rename_keys(d): if 'behaviors' in d: d['policies'] = d.pop('behaviors') @@ -28,8 +24,6 @@ def sanitize_partial_state_updates(partial_state_updates): d['variables'] = d.pop('states') - # 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 if isinstance(new_partial_state_updates, list): for v in new_partial_state_updates: rename_keys(v) diff --git a/cadCAD/configuration/utils/policyAggregation.py b/cadCAD/configuration/utils/policyAggregation.py index 96077dc..9309d01 100644 --- a/cadCAD/configuration/utils/policyAggregation.py +++ b/cadCAD/configuration/utils/policyAggregation.py @@ -1,6 +1,7 @@ from fn.op import foldr from fn.func import curried + def get_base_value(x): if isinstance(x, str): return '' @@ -17,7 +18,7 @@ def policy_to_dict(v): add = lambda a, b: a + b -# df_union = lambda a, b: ... + @curried def foldr_dict_vals(f, d): diff --git a/cadCAD/configuration/utils/userDefinedObject.py b/cadCAD/configuration/utils/userDefinedObject.py index 4ced71f..f37b3f2 100644 --- a/cadCAD/configuration/utils/userDefinedObject.py +++ b/cadCAD/configuration/utils/userDefinedObject.py @@ -1,23 +1,22 @@ from collections import namedtuple -from copy import deepcopy from inspect import getmembers, ismethod from pandas.core.frame import DataFrame from cadCAD.utils import SilentDF + def val_switch(v): if isinstance(v, DataFrame) is True: return SilentDF(v) else: return v + class udcView(object): def __init__(self, d, masked_members): self.__dict__ = d self.masked_members = masked_members - # returns dict to dataframe - def __repr__(self): members = {} variables = { @@ -27,17 +26,7 @@ class udcView(object): members['methods'] = [k for k, v in self.__dict__.items() if str(type(v)) == ""] members.update(variables) - return f"{members}" #[1:-1] - - # def __repr__(self): - # members = {} - # variables = { - # k: val_switch(v) for k, v in self.__dict__.items() - # if str(type(v)) != "" and k not in self.masked_members and k == 'x' # and isinstance(v, DataFrame) is not True - # } - # - # members.update(variables) - # return f"{members}" #[1:-1] + return f"{members}" class udcBroker(object): diff --git a/cadCAD/engine/__init__.py b/cadCAD/engine/__init__.py index a8002b9..8147f5f 100644 --- a/cadCAD/engine/__init__.py +++ b/cadCAD/engine/__init__.py @@ -93,7 +93,6 @@ class Executor: final_result = None if self.exec_context == ExecutionMode.single_proc: - # ToDO: Deprication Handler - "sanitize" in appropriate place tensor_field = create_tensor_field(partial_state_updates.pop(), eps.pop()) result = self.exec_method(simulation_execs, var_dict_list, states_lists, configs_structs, env_processes_list, Ts, Ns) final_result = result, tensor_field diff --git a/cadCAD/engine/simulation.py b/cadCAD/engine/simulation.py index dd2d45d..c5818a4 100644 --- a/cadCAD/engine/simulation.py +++ b/cadCAD/engine/simulation.py @@ -63,9 +63,6 @@ class Executor: ) for k, val_list in new_dict.items() } - # [f1] = ops - # 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, @@ -98,7 +95,6 @@ class Executor: return state_dict - # ToDo: Redifined as a function that applies the tensor field to a set og last conditions # mech_step def partial_state_update( self, @@ -119,8 +115,6 @@ class Executor: ) - # ToDo: add env_proc generator to `last_in_copy` iterator as wrapper function - # ToDo: Can be multithreaded ?? def generate_record(state_funcs): for f in state_funcs: yield self.state_update_exception(f(sweep_dict, sub_step, sH, last_in_obj, _input)) @@ -134,7 +128,6 @@ 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] = self.apply_env_proc(sweep_dict, 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 sL.append(last_in_copy) @@ -155,7 +148,6 @@ class Executor: sub_step = 0 states_list_copy: List[Dict[str, Any]] = deepcopy(simulation_list[-1]) - # ToDo: Causes Substep repeats in sL: genesis_states: Dict[str, Any] = states_list_copy[-1] if len(states_list_copy) == 1: @@ -167,7 +159,6 @@ class Executor: del states_list_copy states_list: List[Dict[str, Any]] = [genesis_states] - # ToDo: Was causing Substep repeats in sL, use for yield sub_step += 1 for [s_conf, p_conf] in configs: # tensor field @@ -196,7 +187,6 @@ class Executor: ) -> List[List[Dict[str, Any]]]: time_seq: List[int] = [x + 1 for x in time_seq] - # ToDo: simulation_list should be a Tensor that is generated throughout the Executor simulation_list: List[List[Dict[str, Any]]] = [states_list] for time_step in time_seq: @@ -209,8 +199,6 @@ class Executor: return simulation_list - # ToDo: Below can be recieved from a tensor field - # configs: List[Tuple[List[Callable], List[Callable]]] def simulation( self, sweep_dict: Dict[str, List[Any]], diff --git a/cadCAD/engine/utils.py b/cadCAD/engine/utils.py index c0f3a76..4fa5b47 100644 --- a/cadCAD/engine/utils.py +++ b/cadCAD/engine/utils.py @@ -24,8 +24,6 @@ def retrieve_state(l, offset): return l[last_index(l) + offset + 1] -# exception_function = f(sub_step, sL, sL[-2], _input) -# try_function = f(sub_step, sL, last_mut_obj, _input) @curried def engine_exception(ErrorType, error_message, exception_function, try_function): try: @@ -38,5 +36,3 @@ def engine_exception(ErrorType, error_message, exception_function, try_function) @curried def fit_param(param, x): return x + param - -# fit_param = lambda param: lambda x: x + param diff --git a/cadCAD/utils/__init__.py b/cadCAD/utils/__init__.py index ccb5f9d..0243464 100644 --- a/cadCAD/utils/__init__.py +++ b/cadCAD/utils/__init__.py @@ -11,15 +11,11 @@ class SilentDF(DataFrame): def __repr__(self): return str(hex(id(DataFrame))) #"pandas.core.frame.DataFrame" + def append_dict(dict, new_dict): dict.update(new_dict) return dict -# def val_switch(v): -# if isinstance(v, DataFrame) is True or isinstance(v, SilentDF) is True: -# return SilentDF(v) -# else: -# return v.x class IndexCounter: def __init__(self): @@ -29,8 +25,6 @@ class IndexCounter: self.i += 1 return self.i -# def compose(*functions): -# return reduce(lambda f, g: lambda x: f(g(x)), functions, lambda x: x) def compose(*functions): return reduce(lambda f, g: lambda x: f(g(x)), functions, lambda x: x) @@ -108,8 +102,7 @@ def contains_type(_collection, type): def drop_right(l, n): return l[:len(l) - n] -# backwards compatibility -# ToDo: Encapsulate in function + def key_filter(l, keyname): if (type(l) == list): return [v[keyname] for v in l] @@ -147,23 +140,3 @@ def curry_pot(f, *argv): return f(argv[0], argv[1], argv[2]) else: raise TypeError('curry_pot() needs 3 or 4 positional arguments') - -# def curry_pot(f, *argv): -# sweep_ind = f.__name__[0:5] == 'sweep' -# arg_len = len(argv) -# if sweep_ind is True and arg_len == 4: -# return f(argv[0])(argv[1])(argv[2])(argv[3]) -# elif sweep_ind is False and arg_len == 4: -# return f(argv[0])(argv[1])(argv[2])(argv[3]) -# elif sweep_ind is True and arg_len == 3: -# return f(argv[0])(argv[1])(argv[2]) -# elif sweep_ind is False and arg_len == 3: -# return f(argv[0])(argv[1])(argv[2]) -# else: -# raise TypeError('curry_pot() needs 3 or 4 positional arguments') - -# def rename(newname): -# def decorator(f): -# f.__name__ = newname -# return f -# return decorator diff --git a/cadCAD/utils/sys_config.py b/cadCAD/utils/sys_config.py index 3da1efe..4d1c285 100644 --- a/cadCAD/utils/sys_config.py +++ b/cadCAD/utils/sys_config.py @@ -1,37 +1,46 @@ from funcy import curry - from cadCAD.configuration.utils import ep_time_step, time_step + def increment(y, incr_by): return lambda _g, step, sL, s, _input: (y, s[y] + incr_by) + def track(y): return lambda _g, step, sL, s, _input: (y, s[y].x) + def simple_state_update(y, x): return lambda _g, step, sH, s, _input: (y, x) + def simple_policy_update(y): return lambda _g, step, sH, s: y + def update_timestamp(y, timedelta, format): return lambda _g, step, sL, s, _input: ( y, ep_time_step(s, dt_str=s[y], fromat_str=format, _timedelta=timedelta) ) + 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): return apply(lambda a, b: a + b, y, incr_by) + def increment_state_by_int(y: str, incr_by: int): return lambda _g, step, sL, s, _input: (y, s[y] + incr_by) + def s(y, x): return lambda _g, step, sH, s, _input: (y, x) + def time_model(y, substeps, time_delta, ts_format='%Y-%m-%d %H:%M:%S'): def apply_incriment_condition(s): if s['substep'] == 0 or s['substep'] == substeps: @@ -40,94 +49,3 @@ def time_model(y, substeps, time_delta, ts_format='%Y-%m-%d %H:%M:%S'): return y, s[y] return lambda _g, step, sL, s, _input: apply_incriment_condition(s) - -# ToDo: Impliment Matrix reduction -# -# [ -# {'conditions': [123], 'opp': lambda a, b: a and b}, -# {'conditions': [123], 'opp': lambda a, b: a and b} -# ] - -# def trigger_condition2(s, conditions, cond_opp): -# # print(conditions) -# condition_bools = [s[field] in precondition_values for field, precondition_values in conditions.items()] -# return reduce(cond_opp, condition_bools) -# -# def trigger_multi_conditions(s, multi_conditions, multi_cond_opp): -# # print([(d['conditions'], d['reduction_opp']) for d in multi_conditions]) -# condition_bools = [ -# trigger_condition2(s, conditions, opp) for conditions, opp in [ -# (d['conditions'], d['reduction_opp']) for d in multi_conditions -# ] -# ] -# return reduce(multi_cond_opp, condition_bools) -# -# def apply_state_condition2(multi_conditions, multi_cond_opp, y, f, _g, step, sL, s, _input): -# if trigger_multi_conditions(s, multi_conditions, multi_cond_opp): -# return f(_g, step, sL, s, _input) -# else: -# return y, s[y] -# -# def proc_trigger2(y, f, multi_conditions, multi_cond_opp): -# return lambda _g, step, sL, s, _input: apply_state_condition2(multi_conditions, multi_cond_opp, y, f, _g, step, sL, s, _input) -# -# def timestep_trigger2(end_substep, y, f): -# multi_conditions = [ -# { -# 'condition': { -# 'substep': [0, end_substep] -# }, -# 'reduction_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) - -# -# @curried - - - -# 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 - - - - -# def p1m1(_g, step, sL, s): -# return {'param1': 1} -# -# def apply_policy_condition(policies, policy_id, f, conditions, _g, step, sL, s): -# if trigger_condition(s, conditions): -# policies[policy_id] = f(_g, step, sL, s) -# return policies -# else: -# return policies -# -# def proc_trigger2(policies, conditions, policy_id, f): -# return lambda _g, step, sL, s: apply_policy_condition(policies, policy_id, f, conditions,_g, step, sL, s) - -# policies_updates = {"p1": udo_policyA, "p2": udo_policyB} - - -# @curried -# def proc_trigger(trigger_time, update_f, time): -# if time == trigger_time: -# return update_f -# else: -# return lambda x: x - - -# def repr(_g, step, sL, s, _input): -# y = 'z' -# x = s['state_udo'].__repr__() -# return (y, x) \ No newline at end of file From 9ac9e238bbc42247ed197fc85fc306bfc9c2863e Mon Sep 17 00:00:00 2001 From: Markus Date: Wed, 21 Aug 2019 21:08:23 -0300 Subject: [PATCH 08/21] tutorials from cadCAD-Tutorials repo + fixed links --- .../validation/conviction_cadCAD.ipynb | 2 +- tutorials/README.md | 10 + .../partial-state-update-blocks.png | Bin 0 -> 60228 bytes .../robot-marbles-part-1.ipynb | 639 ++++++++++++++++ tutorials/robot-marbles-part-2/policies.png | Bin 0 -> 47993 bytes tutorials/robot-marbles-part-2/policy.png | Bin 0 -> 39729 bytes .../robot-marbles-part-2.ipynb | 355 +++++++++ .../robot-marbles-part-3.ipynb | 298 ++++++++ .../robot-marbles-part-4.ipynb | 715 ++++++++++++++++++ .../robot-marbles-part-5.ipynb | 356 +++++++++ .../videos/robot-marbles-part-1/README.md | 1 + .../videos/robot-marbles-part-1/config.py | 85 +++ .../videos/robot-marbles-part-1/config2.py | 85 +++ .../robot-marbles-part-1/images/Mech.jpeg | Bin 0 -> 42961 bytes .../robot-marbles-part-1/images/Overview.jpeg | Bin 0 -> 40229 bytes .../robot-marbles-part-1/images/equations.png | Bin 0 -> 89457 bytes .../robot-marbles-part-1.ipynb | 409 ++++++++++ .../videos/robot-marbles-part-2/README.md | 1 + .../videos/robot-marbles-part-2/config.py | 85 +++ .../videos/robot-marbles-part-2/config2.py | 87 +++ .../robot-marbles-part-2/configBlank.py | 71 ++ .../robot-marbles-part-2/images/Mech.jpeg | Bin 0 -> 50681 bytes .../robot-marbles-part-2/images/Mech2.jpeg | Bin 0 -> 53898 bytes .../robot-marbles-part-2/images/Overview.jpeg | Bin 0 -> 40229 bytes .../robot-marbles-part-2.ipynb | 239 ++++++ .../videos/robot-marbles-part-3/README.md | 1 + .../videos/robot-marbles-part-3/config.py | 108 +++ .../robot-marbles-part-3/images/Mech1.jpeg | Bin 0 -> 53898 bytes .../robot-marbles-part-3/images/Overview.jpeg | Bin 0 -> 40229 bytes .../robot-marbles-part-3.ipynb | 257 +++++++ .../videos/robot-marbles-part-4/README.md | 1 + .../videos/robot-marbles-part-4/config.py | 103 +++ .../videos/robot-marbles-part-4/config2.py | 103 +++ .../robot-marbles-part-4/images/Mech1.jpeg | Bin 0 -> 53898 bytes .../robot-marbles-part-4/images/Overview.jpeg | Bin 0 -> 40229 bytes .../robot-marbles-part-4.ipynb | 642 ++++++++++++++++ .../videos/robot-marbles-part-5/README.md | 1 + .../robot-marbles-part-5/images/Mech1.png | Bin 0 -> 22894 bytes .../robot-marbles-part-5/images/Overview.png | Bin 0 -> 21586 bytes .../robot-marbles-part-5.ipynb | 317 ++++++++ 40 files changed, 4970 insertions(+), 1 deletion(-) create mode 100644 tutorials/README.md create mode 100644 tutorials/robot-marbles-part-1/partial-state-update-blocks.png create mode 100644 tutorials/robot-marbles-part-1/robot-marbles-part-1.ipynb create mode 100644 tutorials/robot-marbles-part-2/policies.png create mode 100644 tutorials/robot-marbles-part-2/policy.png create mode 100644 tutorials/robot-marbles-part-2/robot-marbles-part-2.ipynb create mode 100644 tutorials/robot-marbles-part-3/robot-marbles-part-3.ipynb create mode 100644 tutorials/robot-marbles-part-4/robot-marbles-part-4.ipynb create mode 100644 tutorials/robot-marbles-part-5/robot-marbles-part-5.ipynb create mode 100644 tutorials/videos/robot-marbles-part-1/README.md create mode 100644 tutorials/videos/robot-marbles-part-1/config.py create mode 100644 tutorials/videos/robot-marbles-part-1/config2.py create mode 100644 tutorials/videos/robot-marbles-part-1/images/Mech.jpeg create mode 100644 tutorials/videos/robot-marbles-part-1/images/Overview.jpeg create mode 100644 tutorials/videos/robot-marbles-part-1/images/equations.png create mode 100644 tutorials/videos/robot-marbles-part-1/robot-marbles-part-1.ipynb create mode 100644 tutorials/videos/robot-marbles-part-2/README.md create mode 100644 tutorials/videos/robot-marbles-part-2/config.py create mode 100644 tutorials/videos/robot-marbles-part-2/config2.py create mode 100644 tutorials/videos/robot-marbles-part-2/configBlank.py create mode 100644 tutorials/videos/robot-marbles-part-2/images/Mech.jpeg create mode 100644 tutorials/videos/robot-marbles-part-2/images/Mech2.jpeg create mode 100644 tutorials/videos/robot-marbles-part-2/images/Overview.jpeg create mode 100644 tutorials/videos/robot-marbles-part-2/robot-marbles-part-2.ipynb create mode 100644 tutorials/videos/robot-marbles-part-3/README.md create mode 100644 tutorials/videos/robot-marbles-part-3/config.py create mode 100644 tutorials/videos/robot-marbles-part-3/images/Mech1.jpeg create mode 100644 tutorials/videos/robot-marbles-part-3/images/Overview.jpeg create mode 100644 tutorials/videos/robot-marbles-part-3/robot-marbles-part-3.ipynb create mode 100644 tutorials/videos/robot-marbles-part-4/README.md create mode 100644 tutorials/videos/robot-marbles-part-4/config.py create mode 100644 tutorials/videos/robot-marbles-part-4/config2.py create mode 100644 tutorials/videos/robot-marbles-part-4/images/Mech1.jpeg create mode 100644 tutorials/videos/robot-marbles-part-4/images/Overview.jpeg create mode 100644 tutorials/videos/robot-marbles-part-4/robot-marbles-part-4.ipynb create mode 100644 tutorials/videos/robot-marbles-part-5/README.md create mode 100644 tutorials/videos/robot-marbles-part-5/images/Mech1.png create mode 100644 tutorials/videos/robot-marbles-part-5/images/Overview.png create mode 100644 tutorials/videos/robot-marbles-part-5/robot-marbles-part-5.ipynb diff --git a/simulations/validation/conviction_cadCAD.ipynb b/simulations/validation/conviction_cadCAD.ipynb index c7b219f..494e28b 100644 --- a/simulations/validation/conviction_cadCAD.ipynb +++ b/simulations/validation/conviction_cadCAD.ipynb @@ -34,7 +34,7 @@ "\n", "cadCAD is a Python library that assists in the processes of designing, testing and validating complex systems through simulation. At its core, cadCAD is a differential games engine that supports parameter sweeping and Monte Carlo analyses and can be easily integrated with other scientific computing Python modules and data science workflows.\n", "\n", - "To learn more about cadCAD, follow our [tutorial series](https://github.com/BlockScience/cadCAD-Tutorials/tree/master/01%20Tutorials)\n", + "To learn more about cadCAD, follow our [tutorial series](../../tutorials)\n", "\n", "**Installing cadCAD:**\n", "\n", diff --git a/tutorials/README.md b/tutorials/README.md new file mode 100644 index 0000000..2d7ecef --- /dev/null +++ b/tutorials/README.md @@ -0,0 +1,10 @@ +**Robot and Marbles Tutorial Series** + +In this series, we introduce basic concepts of cadCAD and system modelling in general using a simple toy model. +[Part 1](robot-marbles-part-1/robot-marbles-part-1.ipynb) - States and State Update Functions +[Part 2](robot-marbles-part-2/robot-marbles-part-2.ipynb) - Actions and State Dependent Policies +[Part 3](robot-marbles-part-3/robot-marbles-part-3.ipynb) - From Synchronous to Asynchronous Time +[Part 4](robot-marbles-part-4/robot-marbles-part-4.ipynb) - Uncertainty and Stochastic Processes +[Part 5](robot-marbles-part-5/robot-marbles-part-5.ipynb) - Using class objects as state variables + +Check out the [videos](videos) folder for detailed walkthroughs of each one of the tutorials. \ No newline at end of file diff --git a/tutorials/robot-marbles-part-1/partial-state-update-blocks.png b/tutorials/robot-marbles-part-1/partial-state-update-blocks.png new file mode 100644 index 0000000000000000000000000000000000000000..746a748f713a336a9c2dc25c79d4feabd3852b1b GIT binary patch literal 60228 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 z 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 state variable is one of the set of variables that are used to describe the mathematical \"state\" of a dynamical system. Intuitively, the state of a system describes enough about the system to determine its future behaviour in the absence of any external forces affecting the system. [_(source: Wikipedia)_](https://en.wikipedia.org/wiki/State_variable)\n", + "\n", + "cadCAD can handle state variables of any Python data type, including custom classes. It is up to the user of cadCAD to determine the state variables needed to sufficiently accurately describe the system they are interested in.\n", + "\n", + "We could describe the simple system in our example with only two state variables: the number of marbles in `box_A` and in `box_B`. These are not the only two variables that describe the system, of course. Things like the position of the robot arm in space or its temperature also qualify as \"variables that describe the state of the system\". But if we assume those variables have no impact on the behavior of the system (as implied by the description) we can safely disregard them.\n", + "\n", + "cadCAD expects state variables to be passed to it as a Python `dict` where the `dict_keys` are the __names of the \n", + "variables__ and the `dict_values` are their __initial values__." + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # \n", + "# List of all the state variables in the system and their initial values\n", + "initial_conditions = {\n", + " 'box_A': 10, # as per the description of the example, box_A starts out with 10 marbles in it\n", + " 'box_B': 0 # as per the description of the example, box_B starts out empty\n", + "}\n", + "# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Timestep\n", + "Computer simulations run in discrete time:\n", + ">Discrete time views values of variables as occurring at distinct, separate \"points in time\", or equivalently as being unchanged throughout each non-zero region of time (\"time period\")—that is, time is viewed as a discrete variable. Thus a non-time variable jumps from one value to another as time moves from one time period to the next. This view of time corresponds to a digital clock that gives a fixed reading of 10:37 for a while, and then jumps to a new fixed reading of 10:38, etc. [_(source: Wikipedia)_](https://en.wikipedia.org/wiki/Discrete_time_and_continuous_time)\n", + "\n", + "The concept of Timestep in cadCAD refers to a discrete unit of time. cadCAD increments a \"time counter\", and at each step it updates the state variables according to the equations that describe the system. If time itself is a state variable that the user is interested in keeping track of, they may specify a state update function that models the passing of time. We'll cover that scenario in an upcoming article. For the moment, it suffices to define that the robot acts once per timestep.\n", + "# State Update Functions\n", + "State Update Functions are Python functions that represent the equations according to which the state variables change over time. Each state update function must return a tuple containing the name of the state variable being updated and its new value. The general structure of a state update function is:\n", + "```python\n", + "def function(params, step, sL, s, _input):\n", + " ...\n", + " y = ...\n", + " x = ...\n", + " return (y, x)\n", + "```\n", + "State update functions can read the current state of the system from argument `s`. We'll ignore the other arguments for now. `s` is a Python `dict` where the `dict_keys` are the __names of the variables__ and the `dict_values` are their __current values__. With this, we can define the state update functions for variables `box_A` and `box_B`." + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [], + "source": [ + "def update_A(params, step, sL, s, _input):\n", + " y = 'box_A'\n", + " add_to_A = 0\n", + " if (s['box_A'] > s['box_B']):\n", + " add_to_A = -1\n", + " elif (s['box_A'] < s['box_B']):\n", + " add_to_A = 1\n", + " x = s['box_A'] + add_to_A\n", + " return (y, x)\n", + "\n", + "def update_B(params, step, sL, s, _input):\n", + " y = 'box_B'\n", + " add_to_B = 0\n", + " if (s['box_B'] > s['box_A']):\n", + " add_to_B = -1\n", + " elif (s['box_B'] < s['box_A']):\n", + " add_to_B = 1\n", + " x = s['box_B'] + add_to_B\n", + " return (y, x)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Partial State Update Blocks\n", + "Within a timestep, state update functions can be run in any combination of serial or parallel executions. Take the following diagram for example:\n", + "![partial state update blocks](partial-state-update-blocks.png \"Partial State Update Blocks\")
Figure 1: Visual representation of Partial State Update Blocks
\n", + "\n", + "State update functions (SUF) 1 and 2 are run in parallel. This means that if SUF2 reads the value of variable A, it will not get the value updated by SUF1. On the other hand, SUF3 and SUF4 are executed after SUF1 and SUF2 have completed, thus having access to the updated values of variables A and C.\n", + "\n", + "We refer to the groups of state update functions that are executed in parallel within a timestep as Partial State Update Blocks. cadCAD expects partial state update blocks to be specified as a list of `dict`s with the following structure:\n", + "```python\n", + "partial_state_update_blocks = [\n", + " { \n", + " 'policies': {\n", + " 'policy1': policy_function_1,\n", + " 'policy2': policy_function_2,\n", + " ...\n", + " },\n", + " 'variables': {\n", + " 'variable1': state_update_function_1,\n", + " 'variable2': state_update_function_2,\n", + " ...\n", + " }\n", + " },\n", + " ...\n", + "]\n", + "```\n", + "\n", + "We'll ignore the `policies` key for now. The `dict` that represents the structure of Figure 1 would be:\n", + "```python\n", + "partial_state_update_blocks = [\n", + " { \n", + " 'policies': {\n", + " },\n", + " 'variables': {\n", + " 'variableA': state_update_function_1,\n", + " 'variableC': state_update_function_2,\n", + " }\n", + " },\n", + " { \n", + " 'policies': {\n", + " },\n", + " 'variables': {\n", + " 'variableA': state_update_function_3,\n", + " 'variableB': state_update_function_4,\n", + " }\n", + " }\n", + "]\n", + "```\n", + "\n", + "In the case of our robot and marbles example system, we can model the system so that all state update functions are executed in parallel. In other words, we consider the marbles move from one box to the other simultaneously (ie, `box_A + box_B` is constant)" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [], + "source": [ + "# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # \n", + "# In the Partial State Update Blocks, the user specifies if state update functions will be run in series or in parallel\n", + "partial_state_update_blocks = [\n", + " { \n", + " 'policies': { # We'll ignore policies for now\n", + " },\n", + " 'variables': { # The following state variables will be updated simultaneously\n", + " 'box_A': update_A,\n", + " 'box_B': update_B\n", + " }\n", + " }\n", + "]\n", + "# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Simulation Configuration Parameters\n", + "Lastly, we define the number of timesteps and the number of Monte Carlo runs of the simulation. These parameters must be passed in a dictionary, in `dict_keys` `T` and `N`, respectively. In our example, we'll run the simulation for 10 timesteps. And because we are dealing with a deterministic system, it makes no sense to have multiple Monte Carlo runs, so we set `N=1`. We'll ignore the `M` key for now and set it to an empty `dict`" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [], + "source": [ + "# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # \n", + "# Settings of general simulation parameters, unrelated to the system itself\n", + "# `T` is a range with the number of discrete units of time the simulation will run for;\n", + "# `N` is the number of times the simulation will be run (Monte Carlo runs)\n", + "# In this example, we'll run the simulation once (N=1) and its duration will be of 10 timesteps\n", + "# We'll cover the `M` key in a future article. For now, let's leave it empty\n", + "simulation_parameters = {\n", + " 'T': range(10),\n", + " 'N': 1,\n", + " 'M': {}\n", + "}\n", + "# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Putting it all together\n", + "We have defined the state variables of our system and their initial conditions, as well as the state update functions, which have been grouped in a single state update block. We have also specified the parameters of the simulation (number of timesteps and runs). We are now ready to put all those pieces together in a `Configuration` object." + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [], + "source": [ + "from cadCAD.configuration import Configuration\n", + "\n", + "# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # \n", + "# The configurations above are then packaged into a `Configuration` object\n", + "config = Configuration(initial_state=initial_conditions, #dict containing variable names and initial values\n", + " partial_state_update_blocks=partial_state_update_blocks, #dict containing state update functions\n", + " sim_config=simulation_parameters #dict containing simulation parameters\n", + " )" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Running the engine\n", + "We are now ready to run the engine with the configuration defined above. Instantiate an ExecutionMode, an ExecutionContext and an Executor objects, passing the Configuration object to the latter. Then run the `execute()` method of the Executor object, which returns the results of the experiment in the first element of a tuple." + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [], + "source": [ + "%%capture\n", + "from cadCAD.engine import ExecutionMode, ExecutionContext, Executor\n", + "exec_mode = ExecutionMode()\n", + "exec_context = ExecutionContext(exec_mode.single_proc)\n", + "executor = Executor(exec_context, [config]) # Pass the configuration object inside an array\n", + "raw_result, tensor = executor.execute() # The `execute()` method returns a tuple; its first elements contains the raw results" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Analyzing the results\n", + "We can now convert the raw results into a DataFrame for analysis" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
box_Abox_B
runtimestepsubstep
100100
1191
2182
3173
4164
5155
6155
7155
8155
9155
10155
\n", + "
" + ], + "text/plain": [ + " box_A box_B\n", + "run timestep substep \n", + "1 0 0 10 0\n", + " 1 1 9 1\n", + " 2 1 8 2\n", + " 3 1 7 3\n", + " 4 1 6 4\n", + " 5 1 5 5\n", + " 6 1 5 5\n", + " 7 1 5 5\n", + " 8 1 5 5\n", + " 9 1 5 5\n", + " 10 1 5 5" + ] + }, + "execution_count": 7, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "%matplotlib inline\n", + "import pandas as pd\n", + "df = pd.DataFrame(raw_result)\n", + "df.set_index(['run', 'timestep', 'substep'])" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "df.plot('timestep', ['box_A', 'box_B'], grid=True, \n", + " colormap = 'RdYlGn',\n", + " xticks=list(df['timestep'].drop_duplicates()), \n", + " yticks=list(range(1+(df['box_A']+df['box_B']).max())));" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Because the number of marbles in the system is even, it converges to an equilibrium with 5 marbles in each box. Simulating a scenario with an odd number of marbles is as easy as modifying the `initial_condition` of the system, recreating the configuration object and rerunning the simulation:" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [], + "source": [ + "%%capture\n", + "initial_conditions = {\n", + " 'box_A': 11,\n", + " 'box_B': 0\n", + "}\n", + "config = Configuration(initial_state=initial_conditions, #dict containing variable names and initial values\n", + " partial_state_update_blocks=partial_state_update_blocks, #dict containing state update functions\n", + " sim_config=simulation_parameters #dict containing simulation parameters\n", + " )\n", + "executor = Executor(exec_context, [config])\n", + "raw_result, tensor = executor.execute()" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
box_Abox_B
runtimestepsubstep
100110
11101
2192
3183
4174
5165
6156
7165
8156
9165
10156
\n", + "
" + ], + "text/plain": [ + " box_A box_B\n", + "run timestep substep \n", + "1 0 0 11 0\n", + " 1 1 10 1\n", + " 2 1 9 2\n", + " 3 1 8 3\n", + " 4 1 7 4\n", + " 5 1 6 5\n", + " 6 1 5 6\n", + " 7 1 6 5\n", + " 8 1 5 6\n", + " 9 1 6 5\n", + " 10 1 5 6" + ] + }, + "execution_count": 10, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df = pd.DataFrame(raw_result)\n", + "df.set_index(['run', 'timestep', 'substep'])" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "df.plot('timestep', ['box_A', 'box_B'], grid=True, \n", + " colormap = 'RdYlGn',\n", + " xticks=list(df['timestep'].drop_duplicates()), \n", + " yticks=list(range(1+(df['box_A']+df['box_B']).max())));" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "As was to be expected, the system oscilates between 5 and 6 marbles in each box.\n", + "\n", + "In the next article of this series we'll cover another base concept in cadCAD: **policies**.\n", + "\n", + "---\n", + "\n", + "_About BlockScience_ \n", + "[BlockScience](http://bit.ly/github_articles_M_1) is a research and engineering firm specialized in complex adaptive systems and applying practical methodologies from engineering design, development and testing to projects in emerging technologies such as blockchain. Follow us on [Medium](http://bit.ly/bsci-medium) or [Twitter](http://bit.ly/bsci-twitter) to stay in touch." + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.5" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/tutorials/robot-marbles-part-2/policies.png b/tutorials/robot-marbles-part-2/policies.png new file mode 100644 index 0000000000000000000000000000000000000000..c50e55a02923372fbdf3370cfbcdf9d6e9fb9b85 GIT binary patch literal 47993 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 Q`<4kc70qio%J&2R4;J64f&c&j literal 0 HcmV?d00001 diff --git a/tutorials/robot-marbles-part-2/policy.png b/tutorials/robot-marbles-part-2/policy.png new file mode 100644 index 0000000000000000000000000000000000000000..cede32f780df348bbc73b9b038657420cb565703 GIT binary patch literal 39729 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 iMUQW+M$wR)pOTqYiCY8nz65blaC^G?xvX s['box_B']):\n", + " add_to_A = -1\n", + " elif (s['box_A'] < s['box_B']):\n", + " add_to_A = 1\n", + " x = s['box_A'] + add_to_A\n", + " return (y, x)\n", + "\n", + "def update_B(params, step, sL, s, _input):\n", + " y = 'box_B'\n", + " add_to_B = 0\n", + " if (s['box_B'] > s['box_A']):\n", + " add_to_B = -1\n", + " elif (s['box_B'] < s['box_A']):\n", + " add_to_B = 1\n", + " x = s['box_B'] + add_to_B\n", + " return (y, x)\n", + "\n", + "# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # \n", + "# In the Partial State Update Blocks, the user specifies if state update functions will be run in series or in parallel\n", + "partial_state_update_blocks = [\n", + " { \n", + " 'policies': { # We'll ignore policies for now\n", + " },\n", + " 'variables': { # The following state variables will be updated simultaneously\n", + " 'box_A': update_A,\n", + " 'box_B': update_B\n", + " }\n", + " }\n", + "]\n", + "# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # \n", + "\n", + "# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # \n", + "# Settings of general simulation parameters, unrelated to the system itself\n", + "# `T` is a range with the number of discrete units of time the simulation will run for;\n", + "# `N` is the number of times the simulation will be run (Monte Carlo runs)\n", + "# In this example, we'll run the simulation once (N=1) and its duration will be of 10 timesteps\n", + "# We'll cover the `M` key in a future article. For now, let's leave it empty\n", + "simulation_parameters = {\n", + " 'T': range(10),\n", + " 'N': 1,\n", + " 'M': {}\n", + "}\n", + "# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # \n", + "\n", + "from cadCAD.configuration import Configuration\n", + "\n", + "# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # \n", + "# The configurations above are then packaged into a `Configuration` object\n", + "config = Configuration(initial_state=initial_conditions, #dict containing variable names and initial values\n", + " partial_state_update_blocks=partial_state_update_blocks, #dict containing state update functions\n", + " sim_config=simulation_parameters #dict containing simulation parameters\n", + " )\n", + "\n", + "from cadCAD.engine import ExecutionMode, ExecutionContext, Executor\n", + "exec_mode = ExecutionMode()\n", + "exec_context = ExecutionContext(exec_mode.single_proc)\n", + "executor = Executor(exec_context, [config]) # Pass the configuration object inside an array\n", + "raw_result, tensor = executor.execute() # The `execute()` method returns a tuple; its first elements contains the raw results\n", + "\n", + "%matplotlib inline\n", + "import pandas as pd\n", + "df = pd.DataFrame(raw_result)" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAXQAAAEKCAYAAAACS67iAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADl0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uIDIuMi4yLCBodHRwOi8vbWF0cGxvdGxpYi5vcmcvhp/UCwAAIABJREFUeJzt3Xd4FOXXxvHvkxAIvYMgSADpAUKRIoIUkRKkCAgKCtJ7UVRAf9gootJERBFQ6SV0Ero0ld5DqEoLXQydAEnO+8cuvohIyZbJ7p7PdeXKbtjMfYbAyWQy8xwjIiillPJ8flYXoJRSyjm0oSullJfQhq6UUl5CG7pSSnkJbehKKeUltKErpZSX0IaulFJeQhu6Ukp5CW3oSinlJZK5MyxLliwSFBSUqM+9du0aqVOndm5BSTjXymzdZ9/I1n32nNxt27b9KSJZH/pCEXHbW5kyZSSxVq9enejPdYRVuVZm6z77Rrbus+fkAlvlEXqsnnJRSikvoQ1dKaW8hDZ0pZTyEm79pahSSv2X27dvEx0dTWxsrMsy0qdPz759+1y2fUdzAwMDyZUrFwEBAYnK0YaulEoSoqOjSZs2LUFBQRhjXJJx5coV0qZN65JtO5orIly4cIHo6Gjy5s2bqJyHnnIxxkw0xpwzxkTe9bFMxpgVxphD9vcZE5WulFJ2sbGxZM6c2WXNPKkzxpA5c2aHfkJ5lHPoPwK17/lYX2CViBQAVtmfK6WUQ3y1md/h6P4/tKGLyDrgr3s+3AD4yf74J6ChQ1U8xLFZEVxfsQnRcXlKKfWfzKM0SWNMELBYRILtzy+KSAb7YwPE3Hl+n8/tAHQAyJ49e5kZM2Y8dpEX+o7m5qZIUlQoTober+GfLdNjbyOxrl69Spo0adyWlxSydZ99Izup7XP69Ol5+umnXZobHx+Pv7+/SzMczT18+DCXLl36x8eqVau2TUTKPvSTH+XuIyAIiLzr+cV7/jzmUbaT2DtF4+PiZFHX92VGqpIyM20pOTh2miTExydqW49L76bzjWzdZ+uzo6KiXJ57+fLlB/75kSNHpFixYi7L3bFjhwCyZMmS/3zt/f4ecPGdomeNMTkA7O/PJXI7j8TP3580TV4gdM8iMpcrwZbOH7GqeisuHzrqylillHKq6dOn89xzzzF9+nSXbD+xly0uBFoBn9nfL3BaRQ+QJl9uqq/4gT9+mMP2tz5jSYn6FP+kB4V7t8YvmV6BqZS32NZrEDE79zt1mxlDClPw0x4PfV1cXBwtWrRg+/btFCtWjEmTJrFhwwb69OlDXFwczzzzDGPHjiU2NpZy5cqxcOFCChUqxKuvvkr16tVp3779fbcrIsyePZsVK1ZQuXJlYmNjCQwMdOo+Pspli9OBDUAhY0y0MaYttkZe0xhzCHjB/twtjDHkb9OE0KhwctR6jp3vfsHyCq8Qs8u5X3yllG86cOAAXbp0Yd++faRLl47hw4fTunVrZs6cyZ49e4iLi2Ps2LGkT5+er7/+mtatWzNjxgxiYmL+s5kD/Pbbb+TNm5f8+fNTtWpVwsPDnV77Qw9rReTV//ijGk6u5bGkypmdyvPGcCJsKVu7fcrSso0p2rc9wR90wT9FcitLU0o5qMzI912y3StXrjz0Nblz56ZSpUoAtGzZkk8//ZS8efNSsGBBAFq1asWYMWPo1asXNWvWZPbs2XTt2pVdu3Y9cLvTp0+nefPmADRv3pxJkybRuHFjB/fonzx6LRdjDE81rUNoVDh5Xg1l78CxLCnVkPMbdlhdmlLKQ917LXiGDPe9gA+AhIQE9u3bR6pUqYiJifnP18XHxzNnzhw++eQTgoKC6N69O0uXLn2kbzCPw6Mb+h0pMmfk2UmfUzViHHFXr7Oi0qts6zWIuGvXrS5NKeVhjh8/zoYNGwCYNm0aZcuW5ejRoxw+fBiAyZMn8/zzzwMwYsQIihQpwrRp03jzzTe5ffv2fbe5Zs0aSpQowYkTJzh69CjHjh2jcePGzJs3z6m1e0VDvyNnnecJ3buYAl1e48CoSYQH1+PMyt+sLksp5UEKFSrEmDFjKFKkCDExMfTu3ZsffviBpk2bUrx4cfz8/OjUqRMHDhxg/PjxDBs2jMqVK1OlShUGDhx4322GhYXRqFGjf3yscePGTr/axesuDQlIm4Znvh5AnmZ12dT2fX6u+Sb52jSm9LC+JM+QzurylFJJWFBQEPv3//sCixo1arBjxz9P5RYqVOgfKygOHz78P7c7duzYfy3OVb9+ferXr+9gxf/kVUfod8tWuSx1di2gaN8OHPlpPuFF63Ji/kqry1JKKZfx2oYOkCxlICFD3qbWplmkyJaZ9Y268ssrPblx9k+rS1NKeany5csTEhLyj7e9e/e6JdvrTrncT6YywdTeEsa+Lyaw5+OvObNyA6VH9ifv6w18fnU3pZRzbdq06V8fc/bVLP/Fq4/Q7+YXEECx/p2os2sB6YrkY2Or91hTtz3Xjp+yujSllHIKn2nod6QvnJ+a66dR5qsPOL9+G+HFQjk4ZiqSkGB1aUop5RCfa+gAxs+PQt1fp27kIrJULMXWbp+w8vmWXD7wh9WlKaVUojnU0I0xPY0xkcaYvcaYXs4qyl3SBOWi2rIJVPhhCBcjDxFRsgF7PxtHQlyc1aUppdRjS3RDN8YEA+2BckBJoJ4xxrWr07uAMYZ8rV+m3r4InqxXjV39hrGs/CvE7HT/ZHCllLWOHj1KcHCwS7YdFBRE8eLFCQkJoXjx4ixY4PxFah05Qi8CbBKR6yISB6wFXnZOWe6X8omsVA77iufCvuLGybMsLduYXe+PQG7d/1ZepZR6XKtXr2bnzp2EhYXRo8fDl/J9XI5cthgJDDLGZAZuAHWBrU6pykJPNa5F9mrl2fH2UPYO/pZkU57g/LRMZK1UxurSlPIZvWaNYGf0QaduMyRXQT6t0+6hr3PVeuh3u3z5MhkzZnTGbv3DI80U/c9Ptq2N3gW4BuwFbopIr3te4/BMUbBm/mHslihivpyEnL9I6oZVSdu+IX4pnbsg/YPorEnvz7UyO6nt890zRd9b+A17Tv3u1MziOfMzOLTjA2d7Hjt2jOLFi7N8+XIqVKhAly5dCAoK4ocffmDhwoUUKFCADh06ULJkSbp27crPP//MoEGD6Ny5M1OnTv3Pxbbi4+MpWbIkadKkQUQ4evQoP/74I3Xq1PnXa10+U/RR3oDBQJcHvSaxM0VFrJt/uCpiiWzp/qlMNYVkfp5qcmrZerdl66xJ78+1Mjup7XNSmSmaO3fuv5+vWrVKqlatKpUrV/77YytXrpRGjRr9/bx9+/aSKVMmOXHixANz8+TJI+fPnxcRkcOHD0uePHnkypUr/3qtFTNFATDGZLO/fwrb+fNpjmwvKfJLGUjZrz6g5vqp+KdMwepabdn4Zj9u/nXR6tKUUi7givXQ75U/f36yZ89OVFRUouu8H0evQ59jjIkCFgFdRcRru1zWSmWos2M+xd7vxJHJCwgvGsrxOcusLksp5WSuWA/9XufOnePIkSPkyZPHqbU71NBFpLKIFBWRkiKyyllFJVX+gSkoObA3tbfOIWXObPzSpAfrG3fnxulzVpemlHISV6yHfke1atUICQmhWrVqfPbZZ2TPnt2ptfvE4lzOljGkCLU2z2b/sIns/nA0Z37eSJkR/cjbqpEu9qWUB3PVeuhgu8bd1Xzy1n9n8EuWjKLvdaDurgVkCC7Axjf7sbpWW64ejba6NKWUj9KG7qB0hfLxwtoplB0zgD837CAi+CUOjJ5MQny81aUppSyg66F7OOPnR8EuLXiyXjU2dxzAth4DOTYjnPLjB5G+SH6ry1PKY4iIx5+2dGQ9dHHgviDQI3SnSv1UTqpGfE/FSUO5vP8IS0IaEDloLAmP+JtvpXxZYGAgFy5ccLipeSoR4cKFCwQGJv7mRT1CdzJjDHlfb8gTLz7Hth4D2f3BSI7PXkqFiYPJVLqY1eUplWTlypWL6Ohozp8/77KM2NhYhxqmq3MDAwPJlStXonO0obtIyuxZeG7mSE68Wo+tXT5iWbmmFOnThuAPu5HMjcsHKOUpAgICyJs3r0sz1qxZQ6lSpVyaYWWunnJxsdwNXyA0KoJ8rRsRNfR7loQ04Nx6j1/DTCmVBGlDd4PkGdJRfvwgqq/8kYTbcays0oItXT/m9uWrVpemlPIi2tDd6IkaFQnds4hCvVpxaOx0woPrcWrJWqvLUkp5CW3obpYsdSrKjOjPi7/NICBtatbU7cBvb7zLzQuPvrCPUkrdj6OrLfa2zxONNMZMN8bob/seUZYKIdTePo/gAV05Nj2cxUXqcmxWhM9esqWUcpwjM0WfBHoAZUUkGPAHmjurMF/gnyI5JT7uQe1tc0idJye/NuvN+kZduX7qrNWlKaU8kKOnXJIBKY0xyYBUwCnHS/I9GUsU5sUNMyn1xbucXvYL4UVD+X3CbD1aV0o9lkQ3dBE5CXwJHAdOA5dEZLmzCvM1fsmSUaRPW+ruWUTGkCJsavcBF94ewdU/TlhdmlLKQyR6pqgxJiMwB2gGXARmA2EiMuWe13nsTFGrciUhgeuLf+HSt2EYEdK2bUDqRtUx/u75HXZSmzXpzblWZus+e06uy2eKAk2BCXc9fwP45kGf44kzRa2cu7hy1lxZHdpBplJQlpZvKjGRB92Sm9RmTXpzrpXZus+ek4sbZooeByoYY1IZ2/JoNYB9D/kc9Rj8s2bk+UXf8uy0YVz9/ThLSzVizydfE3/rltWlKaWSIEfOoW8CwoDtwB77tsY5qS5lZ4wh6NV6hEZFkLtJLfZ8OJplZRtzYctuq0tTSiUxjs4U/VBECotIsIi8LiI3nVWY+qfArJmoNG0YVRaO5eZfl1heoRk73hlK3PUbVpemlEoi9E5RD5PrpeqE7g0nf7um7PtyIhElG3B2zb8X1FdK+R5t6B4oefq0lPvuE2r8/BOIsKraG2zuNIBblx5tKopSyjtpQ/dg2atVoO7uhRR+uw2/fz+b8GKhnAxfY3VZSimLaEP3cMlSpaT0l+9Rc8NMkmdMz9p6Hfm1xdvEnv/L6tKUUm6mDd1LZClXgtrb5lD84+6cmL2M8KJ1OTp9sS4foJQP0YbuRfyTJ6f4gG7U3j6XNPly89trb7O2fmeuR5+xujSllBtoQ/dCGYILUvO3GZQe3o+zqzYQXiyUw+NmIgkJVpemlHIhbeheys/fn8K9W1N3zyIylSnG5o4DWFWjFVcOH7O6NKWUi2hD93Jp8z9F9VU/Ue77gcRsjyKiRH32DZtIQny81aUppZxMG7oPMMbwdLumhEZF8ETNZ9nRZyjLKzbjYuRBq0tTSjmRNnQfkurJ7FSZ/w2VZozg2tGTLC39Mrs/Gq2LfSnlJRwZQVfIGLPzrrfLxphezixOOZ8xhjzN6hIaFc5TzeoQ+fHXLC39Mn9u2mV1aUopBzmy2uIBEQkRkRCgDHAdmOe0ypRLBWbJxLOTv+D5xd9x+9IVlldsxra3hhB37brVpSmlEslZp1xqAL+LiF5C4WGeDK1K6N5wCnRqzoERPxJRoj43t++3uiylVCI4q6E3B6Y7aVvKzQLSpeGZbz6ixprJ4OfHhbdHsKn9B9y6eNnq0pRSjyHRM0X/3oAxyYFTQDEROXufP9eZoh6ULTdvceH7udyatwa/TOnJ0Os1AiuVdFu+fp29P9fKbE/NdflM0TtvQANg+aO8VmeKekb26tWr5c8tuyW8xEsylYKyvlkvuXH2T7dlW8FXv85W8bV99oSZone8ip5u8TqZyxan9tY5lPi0J9HzVhBetC5Hpi7Uxb6USsIcaujGmNRATWCuc8pRSYlfQADBH3Shzo75pCkQxIaW77C2XkeunThtdWlKqftwdKboNRHJLCKXnFWQSnrSF32amr9Mo/TI/pxds5nwYqEcGjtNF/tSKonRO0XVI/Hz96dwz1aERi4iS/mSbOnyMauqvcHlQ0etLk0pZacNXT2WNHlzU235RMpPGETMrv0sKVGfqM+/JyEuzurSlPJ52tDVYzPGkL9NE0KjwslRuzI73/uS5RVeIWaX3pCklJW0oatES5UzO5Xnfs1zs0dx/cQZlpZtzK7/jST+pi72pZQVtKErhxhjeKpJbUKjwgl6rR57B45lSamGnN+ww+rSlPI52tCVU6TInJGKPw2l6pLvibt2gxWVXmVbr0HcvnrN6tKU8hna0JVT5axdhdDIRRTo8hoHRk0iovhLnF7xq9VlKeUTtKErpwtIm4Znvh7AC+um4pc8gNUvtmFj2/7citHbFZRyJW3oymWyVS5L3V0LKdqvI0d+ms/ioqGcmLfC6rKU8lra0JVL+QemIGTwW9TaPJuUT2Rh/cvd+OWVntw4+6fVpSnldbShK7fIVLoYtTbPpuTgt4he+DPhReryx6T5utiXUk7k6OJcGYwxYcaY/caYfcaYis4qTHkfv4AAivXrSJ2d80lXJB8bW73HmjrtuHbspNWlKeUVHD1CHwUsFZHCQElgn+MlKW+XvnB+aq6fRpnR/+P8L9sJD67HwTFTdbEvpRyU6IZujEkPVAEmAIjILRG56KzClHczfn4U6taSupGLyPJsabZ2+4SVz7ck7vgZq0tTymMlegSdMSYEGAdEYTs63wb0FJFr97xOR9B5WLa7c0WEG8s2cumbWUjsLdK2fok0r9TEJPN3Ww36dfaNbE/NdfkIOqAsEAeUtz8fBXz6oM/REXSekW1V7vXT52TO881lKgUlolRDubB9r9uy9evsG9memosbRtBFA9Eissn+PAwo7cD2lI9L+URWMn3UkcpzRnPj1DmWPdOEnf2HEx970+rSlPIIiW7oInIGOGGMKWT/UA1sp1+Uckjul1+k3r4I8r7RgKgh37EkpAHnf91mdVlKJXmOXuXSHZhqjNkNhACDHS9JKUieMT0VJg6h2rIJxMfeYkXlFmzt/im3r1y1ujSlkixHZ4ruFJGyIlJCRBqKSIyzClMKIMeLz1E3chEFu7fk4JiphAe/xKll660uS6kkSe8UVUleQJrUlB31ATXXTyVZqkDW1G7HhtZ9ufmXXiWr1N20oSuPkbVSGersmE+x9ztxdOoiwovU5XjYUqvLUirJ0IauPIp/YApKDuxN7S1hpMz1BL807cn6xt25cfqc1aUpZTlt6MojZQwpQq1Nswj57G1Ohq9hcdFQfv9hji72pXyaNnTlsfySJaPoex2ou3shGYoXZFOb/qyu1ZarR6OtLk0pS2hDVx4vXcG8vLBmMmXHDODPDTuICH6JA19NIiE+3urSlHIrbejKKxg/Pwp2aUHo3nCyVi7Dtp6DWFm5BZf2/W51aUq5jTZ05VVSP5WTqhHfU3HSUC4fOMKSkAZEDhpLwu3bVpemlMtpQ1dexxhD3tcbEhoVTq6GL7D7g5EsLduYv7ZFWl2aUi6lDV15rZTZs/DczJFUnjeGm+f/Yln5V9jx3hfE3Yi1ujSlXMLREXRHjTF7jDE7jTFbnVWUUs6Uu+ELhEZFkK91I/Z9Pp4lJRtwbt0Wq8tSyumccYReTURC5FEWX1fKIskzpKP8+EFUX/kjCXFxrHy+JVu6fMTty7rYl/IeespF+ZQnalQkdM8iCvVqxaFvZxAeXI+TEWutLkspp0jm4OcLsNwYI8B3IjLOCTUp5VLJUqeizIj+5GlWl41t+/NZj65sLZ2ZFJNSWVLPzZs3STFpqM/kWpltZe7k7Nl4ukhRl+YkeqYogDHmSRE5aYzJBqwAuovIunteozNFPSzbV/b5/PVLDN8yl41nDpD5BqSMM27JVb5pcLU25M5fIFGf6/KZove+AR8BfR70Gp0p6hnZ3r7P8fHx8u26uZK2VzVJ2b2KDF85TVauWuXy3P+iX2fNfRhcPVPUGJPaGJP2zmPgRUAv9FVJ2uFzJ6gxqhudpg3lmTxFifzfNHrXeBV/P/11kvJ8jpxDzw7MM8bc2c40EdHFqVWSFBcfx8ifZ/K/ReNIkSyA8S370+bZl7D/+1XKKyS6oYvIH0BJJ9ailEvsOXmYtpMHs+VYFA1KVuGb5u+QM0NWq8tSyukcvcpFqSTr5u1bDF76E4OX/kjGVOmY2W4gTUvX0KNy5bW0oSuvtOlIJG0nD2bv6T9oWa42I5v2JnOa9FaXpZRLaUNXXuXazRv8b9F3jPx5Jk9myEp41+HUDX7W6rKUcgtt6MprrNq/hfZThnDkwik6V3mZzxp2JV3K1FaXpZTbaENXHu/i9Su8M3c0439dSIFsuVn71liqFChldVlKuZ02dOXRFuxaR+fpn3PuSgzvvfg6H4a2JWXyQKvLUsoS2tCVRzp3+S96zBrOzG0rKZmrAIs6f0mZPIWtLkspS2lDVx5FRJi6eSk9Z4/g6s0bDKzfkXdffJ0Af/2nrJT+L1Ae48RfZ+k0fSgRkb9RMV9xJrTsT5Ecea0uS6kkQxu6SvISEhL4bv083p03hgRJYFTT3nSt2gR/P3+rS1MqSdGGrpK0g2eP027KYNYf3skLhZ9hXIt+5M2S0+qylEqSHG7oxhh/YCtwUkTqOV6SUrbFtIavms6Hi8cTmCw5E1//gNYVQ/W2faUewBlH6D2BfUA6J2xLKXZFH6LNpIFsP3GARiHPM6b5O+RIn8XqspRK8hxq6MaYXEAoMAh4yykVKZ918/YtJu5ZzvTZa8mUOh2z2w+mcalqelSu1CNy9Ah9JPAukNYJtSgf9tvvu2k3ZTD7zhylVYW6DG/Sk0ypdTEtpR5HomeKGmPqAXVFpIsxpiq28XP/OoeuM0U9L9uduTdu32T8nmXMO7SBbKnS07lYHZ7P5/5l9vXr7BvZnprr8pmiwBAgGjgKnAGuA1Me9Dk6U9Qzst2VuzxqowS931DoVF66zfhCLt+46vX7nJSydZ89J5dHnCnqyMSifkA/gLuO0FsmdnvKd8Rcu8zbc77ihw2LKZQ9D+vf/pbnng6xuiylPJ5eh67cat7ONXSZ/gXnr16kX61WDAhtQ2BACqvLUsorOKWhi8gaYI0ztqW805lLF+g+axhh238mJFdBwrsOo/RTupiWUs6kR+jKpUSESRsj6B02iuu3YhncoDN9arbQxbSUcgH9X6Vc5tiF03ScNpRlURuplL8E41v2p/ATQVaXpZTX0oaunC4hIYFv1s2h7/xvABjd7G26VGmMn5+fxZUp5d20oSunOnDmGG2nDOLX33dTq2gFvnvtPfJkzmF1WUr5BG3oyilux8fx5YqpfBw+gVTJA/nxjf/xRoW6etu+Um6kDV05bMeJA7SdPIgdJw7SpHR1Rr/yNk+kz2x1WUr5HG3oKtFib9/kk/CJfL5iClnTZGBOhyG8XKqa1WUp5bO0oatE+eXwTtpOHszBc8d5s2I9hjXuQcbUuoKyUlbShq4ey5XYa/SbP5Yxa8MIypyD5T1GUbNIeavLUkqhDV09hmVRG+kw9TNOxJylR7VXGFS/E2kCU1ldllLKThu6eqi/rl2i9+xRTNoUQeEn8vDL29/xbP4SVpellLpHohu6MSYQWAeksG8nTEQ+dFZhKmkI2/4zXWd8wV/XLvNBnTd5v05rXUxLqSTKkSP0m0B1EblqjAkAfjHGLBGRjU6qTVno9KU/6TbjS+buXEOZpwqzvMdXlMxVwOqylFIP4Mh66AJctT8NsL8lbvyRSjJEhCV/bKXRwkHExt1iaKOuvFXjVZLpYlpKJXmODon2B7YBTwNjRGSTU6pSljjy5yk6TB3Cyv1bqPx0CONb9qdg9qesLksp9YgSPVP0HxsxJgMwD+guIpH3/JnOFE3i2fEJCcw/vIHxu5dijKFVoeo0LVYFP+P+xbT06+z9uVZme2quy2eK3vsGDMA2hk5ninpQdtSpP6Ti5+2ETuWlzuhecuzCaa/f56SUa2W27rPn5OLqmaLGmKzAbRG5aIxJCdQEhiZ2e8q9bsfH8fnyyXwSMZG0KVIxufWHtChXG2MMf7Df6vKUUongyDn0HMBP9vPofsAsEVnsnLKUK207tp82kwey++RhmpV5ga9eeYts6TJZXZZSykGOXOWyGyjlxFqUi924FctH4eMZtnI62dJmZH6nz2lQsorVZSmlnESvRfMR6w7toN2UwRw6d4J2lerzxcvdyZAqrdVlKaWcSBu6l7t84xp9549h7Lq55M2ck5U9R1Oj8DNWl6WUcgFt6F4sIvI3Ok0bSvTFc/Su0ZxPX+pI6hQprS5LKeUi2tC90J9XL9J79kimbF5K0Rx5+a3P91TIF2x1WUopF9OG7kVEhNnbV9FtxjBirl/mw9C29KvVihQBya0uTSnlBtrQvcSpi+fpMuMLFuxaR9k8RVjVazTFn3za6rKUUm6kDd3DiQgTfl1In7mjuRl3my8bd6dntWa6mJZSPkj/13uwP86fpP3UIfx8YCvPFyjF+Jb9eTpbbqvLUkpZRBu6B4pPiOer1bN4f8G3JPP357vX+tKuUn38/Ny/mJZSKunQhu5h9p76g7aTB7Hp6F7qFa/E2FffI1fGbFaXpZRKArShe4hbcbf5bNkkBi75gfQp0zCtzSc0L1sTY4zVpSmlkghHVlvMDUwCsmObVDROREY5qzD1/7YcjaLtlEHsOfk7rz3zIiOb9iZr2oxWl6WUSmIcOUKPA94Wke3GmLTANmPMChGJclJtPi827hbvzBnN8FXTyZE+Mws7f8FLJSpbXZZSKolyZLXF08Bp++Mrxph9wJOANnQnWHNwG+2WjeLk1Qt0rNyIoY26kj6lNdNllFKewVkj6IKAdUCwiFy+5890BN3j5N2K5btdESz+YzM5UmXknXJNKJU9v9vyQUeT+Uq27rPn5LptBB2QBtug6Jcf9lodQfdgC3etkyf71hO/zhWlT9hXsmTFMrdl301Hk/lGtu6z5+Ti6hF0AMaYAGAOMFVE5jqyLV92/koMPWeNYPrW5RR/Mj/zOg7lmaCirFmzxurSlFIexJGrXAwwAdgnIsOdV5LvEBGmb1lOj1nDuRx7jY/rtadvrTdInizA6tKUUh7IkSP0SsDrwB5jzE77x/qLSITjZXm/6JhzdJ4+lMV7fqV8UDEmvP4+xXLms7ospZQHc+Qql18AvavlMSUkJPD9rwt4Z+5o4uLjGd6k7cnMAAAMW0lEQVSkJz2qvYK/n7/VpSmlPJzeKepGh8+doP3UIaw5uJ3qhcryfYt+5Mv6pNVlKaW8hDZ0N4iLj2PkzzP536JxpEgWwPiW/Wnz7Et6275Syqm0obvY7uhDtJ0ymK3H9tGgZBW+af4OOTNktbospZQX0obuIjdv32Lw0p8YvPRHMqZKx8x2A2lauoYelSulXEYbugts/COStlMGEXX6CC3L1WZk095kTpPe6rKUUl5OG7oTXbt5g/8t+o6RP8/kyQxZCe86nLrBz1pdllLKR2hDd5JV+7fQfsoQjlw4RecqL/NZw66kS5na6rKUUj5EG7qDLl6/Qp85XzHht0UUyJabtW+NpUqBUlaXpZTyQdrQHbBg1zo6T/+cc1dieO/F1/kwtC0pkwdaXZZSykdpQ0+Es5cv0GPWcGZtW0XJXAVY1PlLyuQpbHVZSikf5+hqixOBesA5EQl2TklJl4gwdfNSes4ewdWbNxhYvyPvvvg6Af76fVEpZT1HO9GPwNfYZot6teN/naHTtKEs2buBivmKM6Flf4rkyGt1WUop9TeHGrqIrLNPK/JaCZLAN2vDeG/eNyRIAqOa9qZr1Sa6mJZSKsnRcwUPcPDscXqvHsfu80epWaQc41r0JShzTqvLUkqp+3J4pqj9CH3xf51D98SZovEJ8cw6sJ4fIleS3C8Z3UrXo1ZQGbfftu+p8w89MVv32TeyPTXXnTNFg4DIR3mtJ8wU3XnioJQe9IbQqbw0+vZdCYtY4Jbc+/HU+YeemK377BvZnprLI84U9Uv0twwvE3v7Jh8s+JayQ1pz8tJ5wtoPZm7HoWROmc7q0pRS6pE4etnidKAqkMUYEw18KCITnFGYO/32+27aThnE/jPHaFWhLsOb9CRTal1MSynlWRy9yuVVZxVihaux1+m/YCxfrw0jd8bsLO0+klpFK1hdllJKJYrPXuWyPGoTHaYO4XjMWbo+35jBDTqTNlAX01JKeS6fa+gx1y7z1pxR/LghnELZ87DurbE893SI1WUppZTDfKqhz92xmq4zvuT81Yv0q9WKAaFtCAxIYXVZSinlFD7R0M9cukC3mV8yZ8dqQnIVJKLbcErlLmR1WUop5VRe3dBFhJ82hvNW2FdcvxXL4Aad6VOzhS6mpZTySl7b2Y5eOEXHqUNZvm8TlfKXYHzL/hR+IsjqspRSymW8rqEnJCQwZm0Y/RaMxWD4ulkfOld5GT8/vYdKKeXdvKqh7z9zlHZTBvPr77upVbQC3732Hnky57C6LKWUcguvaOi34+P4YvkUPo6YQOrkKfmp1QBeL1/H7YtpKaWUlTy+oW8/vp+2kwezM/ogTUpX5+tmb5M9XWary1JKKbfz2IZ+41Ysn0RM5IsVU8maJgNzOgzh5VLVrC5LKaUs4+jiXLWBUYA/MF5EPnNKVQ/xy+GdtJ08mIPnjvNmxXoMa9yDjKl1VUSllG9LdEM3xvgDY4CaQDSwxRizUESinFXcva7EXqPf/LGMWRtGUOYcLO8xippFyrsqTimlPIojR+jlgMMi8geAMWYG0ABwSUPffPoArT4dyYmYs/Ss1oyB9TuSJjCVK6KUUsojOdLQnwRO3PU8GnDJ4XLHqZ8x7pf5FHkiiF/7jKNivuKuiFFKKY+W6JmixpgmQG0RaWd//jpQXkS63fM6h2eKzti/lovXrtAmpDbJ3Xzbvs5d9I1s3WffyPbUXJfPFAUqAsvuet4P6Pegz/GEmaJJJdfKbN1n38jWffacXNwwU3QLUMAYk9cYkxxoDix0YHtKKaUckOjzFyISZ4zpBizDdtniRBHZ67TKlFJKPRZHZ4pGABFOqkUppZQDdAlCpZTyEtrQlVLKS2hDV0opL6ENXSmlvIQ2dKWU8hKJvlM0UWHGnAeOJfLTswB/OrGcpJ5rZbbus29k6z57Tm4eEcn6sBe5taE7whizVR7l1lcvybUyW/fZN7J1n70vV0+5KKWUl9CGrpRSXsKTGvo4H8u1Mlv32TeydZ+9LNdjzqErpZR6ME86QldKKfUAHtHQjTG1jTEHjDGHjTF93ZQ50RhzzhgT6Y68u3JzG2NWG2OijDF7jTE93ZgdaIzZbIzZZc/+2F3Z9nx/Y8wOY8xiN+ceNcbsMcbsNMZsdWNuBmNMmDFmvzFmnzGmoptyC9n39c7bZWNMLzdl97b/24o0xkw3xgS6KbenPXOvq/f1fr3DGJPJGLPCGHPI/j6jS8IfZdF0K9+wLc37O5APSA7sAoq6IbcKUBqIdPP+5gBK2x+nBQ66Y3/teQZIY38cAGwCKrhx398CpgGL3fx3fhTI4s5Me+5PQDv74+RABgtq8AfOYLvO2dVZTwJHgJT257OA1m7IDQYigVTYVphdCTztwrx/9Q7gc6Cv/XFfYKgrsj3hCP3vYdQicgu4M4zapURkHfCXq3Puk3taRLbbH18B9mH7j+CObBGRq/anAfY3t/ySxRiTCwgFxrsjz2rGmPTY/uNPABCRWyJy0YJSagC/i0hib/h7XMmAlMaYZNga7Ck3ZBYBNonIdRGJA9YCL7sq7D96RwNs38Cxv2/oimxPaOj3G0btlgZnNWNMEFAK25GyuzL9jTE7gXPAChFxV/ZI4F0gwU15dxNguTFmm30GrjvkBc4DP9hPM403xqR2U/bdmgPT3REkIieBL4HjwGngkogsd0N0JFDZGJPZGJMKqAvkdkPu3bKLyGn74zNAdleEeEJD90nGmDTAHKCXiFx2V66IxItICJALKGeMCXZ1pjGmHnBORLa5Ous/PCcipYE6QFdjTBU3ZCbD9mP5WBEpBVzD9qO429hHR9YHZrspLyO2I9W8QE4gtTGmpatzRWQfMBRYDiwFdgLxrs59QD2Ci37y9YSGfpJ/fjfNZf+Y1zLGBGBr5lNFZK4VNdh//F8N1HZDXCWgvjHmKLZTatWNMVPckAv8feSIiJwD5mE7zedq0UD0XT8BhWFr8O5UB9guImfdlPcCcEREzovIbWAu8Kw7gkVkgoiUEZEqQAy2302501ljTA4A+/tzrgjxhIbuU8OojTEG23nVfSIy3M3ZWY0xGeyPUwI1gf2uzhWRfiKSS0SCsH19fxYRlx+5ARhjUhtj0t55DLyI7Ud0lxKRM8AJY0wh+4dqAFGuzr3Hq7jpdIvdcaCCMSaV/d95DWy/I3I5Y0w2+/unsJ0/n+aO3LssBFrZH7cCFrgixKGZou4gFg2jNsZMB6oCWYwx0cCHIjLB1bnYjlZfB/bYz2UD9Bfb/FZXywH8ZIzxx/bNfpaIuPUSQgtkB+bZ+gvJgGkistRN2d2BqfYDlT+AN92Ue+ebV02go7syRWSTMSYM2A7EATtw352bc4wxmYHbQFdX/gL6fr0D+AyYZYxpi23F2Vdckm2/jEYppZSH84RTLkoppR6BNnSllPIS2tCVUspLaENXSikvoQ1dKaW8hDZ05VHsKxR2sT/Oab8MzlVZIcaYuq7avlLOpg1deZoMQBcAETklIk1cmBWCbd0PpTyCXoeuPIox5s5qmweAQ0AREQk2xrTGtoJdaqAAtkWgkmO7SesmUFdE/jLG5AfGAFmB60B7EdlvjGmK7QaQeOASttvUDwMpsS01MQRYDIzGthxrAPCRiCywZzcC0mNbOG6KiLh1LXmlwAPuFFXqHn2BYBEJsa9GefedrMHYVqcMxNaM3xORUsaYEcAb2FZ0HAd0EpFDxpjywDdAdWAAUEtEThpjMojILWPMAKCsiHQDMMYMxrYsQRv7EgmbjTEr7dnl7PnXgS3GmHARcduwDKVAG7ryLqvta8hfMcZcAhbZP74HKGFfwfJZYLb9Vn+AFPb3vwI/GmNmYVs06n5exLaIWB/780DgKfvjFSJyAcAYMxd4DtCGrtxKG7ryJjfvepxw1/MEbP/W/YCL9uWB/0FEOtmP2EOBbcaYMvfZvgEai8iBf3zQ9nn3nrvUc5nK7fSXosrTXME2mu+x2deVP2I/X46xKWl/nF9ENonIAGyDJ3LfJ2sZ0N2+UiDGmFJ3/VlN+9zIlNjO5f+amBqVcoQ2dOVR7Kc1frUP4P0iEZtoAbQ1xuwC9vL/4wy/MLZB0ZHAb9hm164GitoHKTcDPsX2y9Ddxpi99ud3bMa2hv1uYI6eP1dW0KtclHKQ/SqXv395qpRV9AhdKaW8hB6hK6WUl9AjdKWU8hLa0JVSyktoQ1dKKS+hDV0ppbyENnSllPIS2tCVUspL/B9zEYV421CkzQAAAABJRU5ErkJggg==\n", + "text/plain": [ + "

" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "df.plot('timestep', ['box_A', 'box_B'], grid=True, \n", + " colormap = 'RdYlGn',\n", + " xticks=list(df['timestep'].drop_duplicates()), \n", + " yticks=list(range(1+(df['box_A']+df['box_B']).max())));" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Policies\n", + "In part 1, we ignored the `_input` argument of state update functions. That argument is a signal passed to the state update function by another set of functions: Policy Functions.\n", + "\n", + "Policy Functions are most commonly used as representations of the behavior of agents that interact with the components of the system we're simulating in cadCAD. But more generally, they describe the logic of some component or mechanism of the system. It is possible to encode the functionality of a policy function in the state update functions themselves (as we did in part 1, where we had the robot's algorithm reside in the `update_A` and `update_B` functions), but as systems grow more complex this approach makes the code harder to read and maintain, and in some cases more inefficient because of unnecessary repetition of computational steps.\n", + "\n", + "The general structure of a policy function is:\n", + "```python\n", + "def policy_function(params, step, sL, s):\n", + " ...\n", + " return {'value1': value1, 'value2': value2, ...}\n", + "```\n", + "Just like State Update Functions, policies can read the current state of the system from argument `s`, a Python `dict` where the `dict_keys` are the __names of the variables__ and the `dict_values` are their __current values__. The Policy Function must return a dictionary, which will be passed as an argument (`_input`) to the state update functions.\n", + "![Policy](policy.png \"Policy\")\n", + "\n", + "Let's update our simulation so that the robot arm's logic is encoded in a Policy instead of in the State Update Functions." + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [], + "source": [ + "%%capture\n", + "# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # \n", + "# We specify the robot arm's logic in a Policy Function\n", + "def robot_arm(params, step, sL, s):\n", + " add_to_A = 0\n", + " if (s['box_A'] > s['box_B']):\n", + " add_to_A = -1\n", + " elif (s['box_A'] < s['box_B']):\n", + " add_to_A = 1\n", + " return({'add_to_A': add_to_A, 'add_to_B': -add_to_A})\n", + " \n", + "\n", + "# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # \n", + "# We make the state update functions less \"intelligent\",\n", + "# ie. they simply add the number of marbles specified in _input \n", + "# (which, per the policy function definition, may be negative)\n", + "def increment_A(params, step, sL, s, _input):\n", + " y = 'box_A'\n", + " x = s['box_A'] + _input['add_to_A']\n", + " return (y, x)\n", + "\n", + "def increment_B(params, step, sL, s, _input):\n", + " y = 'box_B'\n", + " x = s['box_B'] + _input['add_to_B']\n", + " return (y, x)\n", + "# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # \n", + "\n", + "\n", + "# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # \n", + "# In the Partial State Update Blocks, \n", + "# the user specifies if state update functions will be run in series or in parallel\n", + "# and the policy functions that will be evaluated in that block\n", + "partial_state_update_blocks = [\n", + " { \n", + " 'policies': { # The following policy functions will be evaluated and their returns will be passed to the state update functions\n", + " 'robot_arm': robot_arm\n", + " },\n", + " 'states': { # The following state variables will be updated simultaneously\n", + " 'box_A': increment_A,\n", + " 'box_B': increment_B\n", + " }\n", + " }\n", + "]\n", + "# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # \n", + "\n", + "# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # \n", + "# The configurations above are then packaged into a `Configuration` object\n", + "config = Configuration(initial_state=initial_conditions, #dict containing variable names and initial values\n", + " partial_state_update_blocks=partial_state_update_blocks, #dict containing state update functions\n", + " sim_config=simulation_parameters #dict containing simulation parameters\n", + " )\n", + "\n", + "exec_mode = ExecutionMode()\n", + "exec_context = ExecutionContext(exec_mode.single_proc)\n", + "executor = Executor(exec_context, [config]) # Pass the configuration object inside an array\n", + "raw_result, tensor = executor.execute() # The `execute()` method returns a tuple; its first elements contains the raw results" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "df.plot('timestep', ['box_A', 'box_B'], grid=True, \n", + " xticks=list(df['timestep'].drop_duplicates()), \n", + " colormap = 'RdYlGn',\n", + " yticks=list(range(1+(df['box_A']+df['box_B']).max())));" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "As expected, the results are the same as when the robot arm logic was encoded within the state update functions. \n", + "\n", + "Several policies may be evaluated within a Partial State Update Block. When that's the case, cadCAD's engine aggregates the outputs of the policies and passes them as a single signal to the state update functions. \n", + "![Policies](policies.png \"Policies\")\n", + "\n", + "Aggregation of policies is defined in cadCAD as __key-wise sum (+) of the elements of the outputted `dict`s__.\n", + "```python\n", + ">policy_1_output = {'int': 1, 'str': 'abc', 'list': [1, 2], '1-only': 'Specific to policy 1'}\n", + ">policy_2_output = {'int': 2, 'str': 'def', 'list': [3, 4], '2-only': 'Specific to policy 2'}\n", + ">print(aggregate([policy_1_output, policy_2_output]))\n", + "```\n", + "```\n", + "{'int': 3, 'str': 'abcdef', 'list': [1, 2, 3, 4], '1-only': 'Specific to policy 1', '2-only': 'Specific to policy 2'}\n", + "```\n", + "\n", + "To illustrate, let's add to another system another robot arm identical to the first one, that acts in tandem with it. All it takes is to add a policy to the `dict` that describes the partial state update block." + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [], + "source": [ + "%%capture\n", + "# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # \n", + "# In the Partial State Update Blocks, \n", + "# the user specifies if state update functions will be run in series or in parallel\n", + "# and the policy functions that will be evaluated in that block\n", + "partial_state_update_blocks = [\n", + " { \n", + " 'policies': { # The following policy functions will be evaluated and their returns will be passed to the state update functions\n", + " 'robot_arm_1': robot_arm,\n", + " 'robot_arm_2': robot_arm\n", + " },\n", + " 'variables': { # The following state variables will be updated simultaneously\n", + " 'box_A': increment_A,\n", + " 'box_B': increment_B\n", + " }\n", + " }\n", + "]\n", + "# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # \n", + "\n", + "# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # \n", + "# The configurations above are then packaged into a `Configuration` object\n", + "config = Configuration(initial_state=initial_conditions, #dict containing variable names and initial values\n", + " partial_state_update_blocks=partial_state_update_blocks, #dict containing state update functions\n", + " sim_config=simulation_parameters #dict containing simulation parameters\n", + " )\n", + "\n", + "exec_mode = ExecutionMode()\n", + "exec_context = ExecutionContext(exec_mode.single_proc)\n", + "executor = Executor(exec_context, [config]) # Pass the configuration object inside an array\n", + "raw_result, tensor = executor.execute() # The `execute()` method returns a tuple; its first elements contains the raw results" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "%matplotlib inline\n", + "df = pd.DataFrame(raw_result)\n", + "df.plot('timestep', ['box_A', 'box_B'], grid=True, \n", + " xticks=list(df['timestep'].drop_duplicates()), \n", + " colormap = 'RdYlGn',\n", + " yticks=list(range(1+(df['box_A']+df['box_B']).max())));" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Because we have made it so that both robots read and update the state of the system at the same time, the equilibrium we had before (with 5 marbles in each box) is never reached. Instead, the system oscillates around that point.\n", + "\n", + "---\n", + "\n", + "_About BlockScience_ \n", + "[BlockScience](http://bit.ly/github_articles_M_02) is a research and engineering firm specialized in complex adaptive systems and applying practical methodologies from engineering design, development and testing to projects in emerging technologies such as blockchain. Follow us on [Medium](http://bit.ly/bsci-medium) or [Twitter](http://bit.ly/bsci-twitter) to stay in touch." + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.5" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/tutorials/robot-marbles-part-3/robot-marbles-part-3.ipynb b/tutorials/robot-marbles-part-3/robot-marbles-part-3.ipynb new file mode 100644 index 0000000..c3d5ba5 --- /dev/null +++ b/tutorials/robot-marbles-part-3/robot-marbles-part-3.ipynb @@ -0,0 +1,298 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# cadCAD Tutorials: The Robot and the Marbles, part 3\n", + "In parts [1](../robot-marbles-part-1/robot-marbles-part-1.ipynb) and [2](../robot-marbles-part-2/robot-marbles-part-2.ipynb) we introduced the 'language' in which a system must be described in order for it to be interpretable by cadCAD and some of the basic concepts of the library:\n", + "* State Variables\n", + "* Timestep\n", + "* State Update Functions\n", + "* Partial State Update Blocks\n", + "* Simulation Configuration Parameters\n", + "* Policies\n", + "\n", + "In this notebook we'll look at how subsystems within a system can operate in different frequencies. But first let's copy the base configuration with which we ended Part 2. Here's the description of that system:\n", + "\n", + "__The robot and the marbles__ \n", + "* Picture a box (`box_A`) with ten marbles in it; an empty box (`box_B`) next to the first one; and __two__ robot arms capable of taking a marble from any one of the boxes and dropping it into the other one. \n", + "* The robots are programmed to take one marble at a time from the box containing the largest number of marbles and drop it in the other box. They repeat that process until the boxes contain an equal number of marbles.\n", + "* The robots act simultaneously; in other words, they assess the state of the system at the exact same time, and decide what their action will be based on that information." + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "%%capture\n", + "\n", + "\n", + "# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # \n", + "# List of all the state variables in the system and their initial values\n", + "initial_conditions = {\n", + " 'box_A': 10, # as per the description of the example, box_A starts out with 10 marbles in it\n", + " 'box_B': 0 # as per the description of the example, box_B starts out empty\n", + "}\n", + "# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # \n", + "\n", + "\n", + "\n", + "# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # \n", + "# Settings of general simulation parameters, unrelated to the system itself\n", + "# `T` is a range with the number of discrete units of time the simulation will run for;\n", + "# `N` is the number of times the simulation will be run (Monte Carlo runs)\n", + "# In this example, we'll run the simulation once (N=1) and its duration will be of 10 timesteps\n", + "# We'll cover the `M` key in a future article. For now, let's leave it empty\n", + "simulation_parameters = {\n", + " 'T': range(10),\n", + " 'N': 1,\n", + " 'M': {}\n", + "}\n", + "# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # \n", + "\n", + "# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # \n", + "# We specify the robot arm's logic in a Policy Function\n", + "def robot_arm(params, step, sL, s):\n", + " add_to_A = 0\n", + " if (s['box_A'] > s['box_B']):\n", + " add_to_A = -1\n", + " elif (s['box_A'] < s['box_B']):\n", + " add_to_A = 1\n", + " return({'add_to_A': add_to_A, 'add_to_B': -add_to_A})\n", + " \n", + "\n", + "# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # \n", + "# We make the state update functions less \"intelligent\",\n", + "# ie. they simply add the number of marbles specified in _input \n", + "# (which, per the policy function definition, may be negative)\n", + "def increment_A(params, step, sL, s, _input):\n", + " y = 'box_A'\n", + " x = s['box_A'] + _input['add_to_A']\n", + " return (y, x)\n", + "\n", + "def increment_B(params, step, sL, s, _input):\n", + " y = 'box_B'\n", + " x = s['box_B'] + _input['add_to_B']\n", + " return (y, x)\n", + "# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # \n", + "\n", + "\n", + "\n", + "# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # \n", + "# In the Partial State Update Blocks, \n", + "# the user specifies if state update functions will be run in series or in parallel\n", + "# and the policy functions that will be evaluated in that block\n", + "partial_state_update_blocks = [\n", + " { \n", + " 'policies': { # The following policy functions will be evaluated and their returns will be passed to the state update functions\n", + " 'robot_arm_1': robot_arm,\n", + " 'robot_arm_2': robot_arm\n", + " },\n", + " 'variables': { # The following state variables will be updated simultaneously\n", + " 'box_A': increment_A,\n", + " 'box_B': increment_B\n", + " }\n", + " }\n", + "]\n", + "# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # \n", + "\n", + "\n", + "\n", + "\n", + "\n", + "from cadCAD.configuration import Configuration\n", + "# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # \n", + "# The configurations above are then packaged into a `Configuration` object\n", + "config = Configuration(initial_state=initial_conditions, #dict containing variable names and initial values\n", + " partial_state_update_blocks=partial_state_update_blocks, #dict containing state update functions\n", + " sim_config=simulation_parameters #dict containing simulation parameters\n", + " )\n", + "\n", + "from cadCAD.engine import ExecutionMode, ExecutionContext, Executor\n", + "exec_mode = ExecutionMode()\n", + "exec_context = ExecutionContext(exec_mode.single_proc)\n", + "executor = Executor(exec_context, [config]) # Pass the configuration object inside an array\n", + "raw_result, tensor = executor.execute() # The `execute()` method returns a tuple; its first elements contains the raw results\n", + "\n", + "%matplotlib inline\n", + "import pandas as pd\n", + "df = pd.DataFrame(raw_result)" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "df.plot('timestep', ['box_A', 'box_B'], grid=True, \n", + " xticks=list(df['timestep'].drop_duplicates()), \n", + " colormap = 'RdYlGn',\n", + " yticks=list(range(1+(df['box_A']+df['box_B']).max())));" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Asynchronous Subsystems\n", + "We have defined that the robots operate simultaneously on the boxes of marbles. But it is often the case that agents within a system operate asynchronously, each having their own operation frequencies or conditions.\n", + "\n", + "Suppose that instead of acting simultaneously, the robots in our examples operated in the following manner:\n", + "* Robot 1: acts once every 2 timesteps\n", + "* Robot 2: acts once every 3 timesteps\n", + "\n", + "One way to simulate the system with this change is to introduce a check of the current timestep before the robots act, with the definition of separate policy functions for each robot arm." + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [], + "source": [ + "%%capture\n", + "\n", + "# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # \n", + "# We specify each of the robots logic in a Policy Function\n", + "robots_periods = [2,3] # Robot 1 acts once every 2 timesteps; Robot 2 acts once every 3 timesteps\n", + "\n", + "def get_current_timestep(cur_substep, s):\n", + " if cur_substep == 1:\n", + " return s['timestep']+1\n", + " return s['timestep']\n", + "\n", + "def robot_arm_1(params, step, sL, s):\n", + " _robotId = 1\n", + " if get_current_timestep(step, s)%robots_periods[_robotId-1]==0: # on timesteps that are multiple of 2, Robot 1 acts\n", + " return robot_arm(params, step, sL, s)\n", + " else:\n", + " return({'add_to_A': 0, 'add_to_B': 0}) # for all other timesteps, Robot 1 doesn't interfere with the system\n", + "\n", + "def robot_arm_2(params, step, sL, s):\n", + " _robotId = 2\n", + " if get_current_timestep(step, s)%robots_periods[_robotId-1]==0: # on timesteps that are multiple of 3, Robot 2 acts\n", + " return robot_arm(params, step, sL, s)\n", + " else:\n", + " return({'add_to_A': 0, 'add_to_B': 0}) # for all other timesteps, Robot 2 doesn't interfere with the system\n", + "\n", + "\n", + "# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # \n", + "# In the Partial State Update Blocks, \n", + "# the user specifies if state update functions will be run in series or in parallel\n", + "# and the policy functions that will be evaluated in that block\n", + "partial_state_update_blocks = [\n", + " { \n", + " 'policies': { # The following policy functions will be evaluated and their returns will be passed to the state update functions\n", + " 'robot_arm_1': robot_arm_1,\n", + " 'robot_arm_2': robot_arm_2\n", + " },\n", + " 'variables': { # The following state variables will be updated simultaneously\n", + " 'box_A': increment_A,\n", + " 'box_B': increment_B\n", + " }\n", + " }\n", + "]\n", + "# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # \n", + "\n", + "\n", + "# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # \n", + "# The configurations above are then packaged into a `Configuration` object\n", + "config = Configuration(initial_state=initial_conditions, #dict containing variable names and initial values\n", + " partial_state_update_blocks=partial_state_update_blocks, #dict containing state update functions\n", + " sim_config=simulation_parameters #dict containing simulation parameters\n", + " )\n", + "\n", + "exec_mode = ExecutionMode()\n", + "exec_context = ExecutionContext(exec_mode.single_proc)\n", + "executor = Executor(exec_context, [config]) # Pass the configuration object inside an array\n", + "raw_result, tensor = executor.execute() # The `execute()` method returns a tuple; its first elements contains the raw results\n", + "\n", + "df = pd.DataFrame(raw_result)" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "df.plot('timestep', ['box_A', 'box_B'], \n", + " grid=True, \n", + " xticks=list(df['timestep'].drop_duplicates()), \n", + " yticks=list(range(1+max(df['box_A'].max(),df['box_B'].max()))),\n", + " colormap = 'RdYlGn'\n", + " )" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Let's take a step-by-step look at what the simulation tells us:\n", + "* Timestep 1: the number of marbles in the boxes does not change, as none of the robots act\n", + "* Timestep 2: Robot 1 acts, Robot 2 doesn't; resulting in one marble being moved from box A to box B\n", + "* Timestep 3: Robot 2 acts, Robot 1 doesn't; resulting in one marble being moved from box A to box B\n", + "* Timestep 4: Robot 1 acts, Robot 2 doesn't; resulting in one marble being moved from box A to box B\n", + "* Timestep 5: the number of marbles in the boxes does not change, as none of the robots act\n", + "* Timestep 6: Robots 1 __and__ 2 act, as 6 is a multiple of 2 __and__ 3; resulting in two marbles being moved from box A to box B and an equilibrium being reached." + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.5" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/tutorials/robot-marbles-part-4/robot-marbles-part-4.ipynb b/tutorials/robot-marbles-part-4/robot-marbles-part-4.ipynb new file mode 100644 index 0000000..1fac437 --- /dev/null +++ b/tutorials/robot-marbles-part-4/robot-marbles-part-4.ipynb @@ -0,0 +1,715 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# cadCAD Tutorials: The Robot and the Marbles, part 4\n", + "In parts [1](../robot-marbles-part-1/robot-marbles-part-1.ipynb) and [2](../robot-marbles-part-2/robot-marbles-part-2.ipynb) we introduced the 'language' in which a system must be described in order for it to be interpretable by cadCAD and some of the basic concepts of the library:\n", + "* State Variables\n", + "* Timestep\n", + "* State Update Functions\n", + "* Partial State Update Blocks\n", + "* Simulation Configuration Parameters\n", + "* Policies\n", + "\n", + "In [part 3](../robot-marbles-part-3/robot-marbles-part-3.ipynb) we covered how to describe the presence of asynchronous subsystems within the system being modeled in cadCAD.\n", + "\n", + "So far, all the examples referred to deterministic systems: no matter how many times you ran one of those simulations, the results would be the same. However, systems are more commonly non-deterministic, and modelling them as deterministic might be an oversimplification sometimes. \n", + "\n", + "In this notebook, we'll cover cadCAD's support for modelling non-deterministic systems and Monte Carlo simulations. But first let's copy the base configuration with which we ended Part 3. Here's the description of that system:\n", + "\n", + "__The robot and the marbles__ \n", + "* Picture a box (`box_A`) with ten marbles in it; an empty box (`box_B`) next to the first one; and __two__ robot arms capable of taking a marble from any one of the boxes and dropping it into the other one. \n", + "* The robots are programmed to take one marble at a time from the box containing the largest number of marbles and drop it in the other box. They repeat that process until the boxes contain an equal number of marbles.\n", + "* The robots act __asynchronously__; robot 1 acts once every two timesteps, and robot 2 acts once every three timesteps." + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "%%capture\n", + "\n", + "\n", + "# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # \n", + "# List of all the state variables in the system and their initial values\n", + "initial_conditions = {\n", + " 'box_A': 10, # as per the description of the example, box_A starts out with 10 marbles in it\n", + " 'box_B': 0 # as per the description of the example, box_B starts out empty\n", + "}\n", + "# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # \n", + "\n", + "\n", + "\n", + "# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # \n", + "# Settings of general simulation parameters, unrelated to the system itself\n", + "# `T` is a range with the number of discrete units of time the simulation will run for;\n", + "# `N` is the number of times the simulation will be run (Monte Carlo runs)\n", + "# In this example, we'll run the simulation once (N=1) and its duration will be of 10 timesteps\n", + "# We'll cover the `M` key in a future article. For now, let's leave it empty\n", + "simulation_parameters = {\n", + " 'T': range(10),\n", + " 'N': 1,\n", + " 'M': {}\n", + "}\n", + "# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # \n", + "\n", + "# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # \n", + "# We specify the robot arm's logic in a Policy Function\n", + "def robot_arm(params, step, sL, s):\n", + " add_to_A = 0\n", + " if (s['box_A'] > s['box_B']):\n", + " add_to_A = -1\n", + " elif (s['box_A'] < s['box_B']):\n", + " add_to_A = 1\n", + " return({'add_to_A': add_to_A, 'add_to_B': -add_to_A})\n", + " \n", + "robots_periods = [2,3] # Robot 1 acts once every 2 timesteps; Robot 2 acts once every 3 timesteps\n", + "\n", + "def robot_arm_1(params, step, sL, s):\n", + " _robotId = 1\n", + " if s['timestep']%robots_periods[_robotId-1]==0: # on timesteps that are multiple of 2, Robot 1 acts\n", + " return robot_arm(params, step, sL, s)\n", + " else:\n", + " return({'add_to_A': 0, 'add_to_B': 0}) # for all other timesteps, Robot 1 doesn't interfere with the system\n", + "\n", + "def robot_arm_2(params, step, sL, s):\n", + " _robotId = 2\n", + " if s['timestep']%robots_periods[_robotId-1]==0: # on timesteps that are multiple of 3, Robot 2 acts\n", + " return robot_arm(params, step, sL, s)\n", + " else:\n", + " return({'add_to_A': 0, 'add_to_B': 0}) # for all other timesteps, Robot 2 doesn't interfere with the system\n", + "\n", + " \n", + "# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # \n", + "# We make the state update functions less \"intelligent\",\n", + "# ie. they simply add the number of marbles specified in _input \n", + "# (which, per the policy function definition, may be negative)\n", + "def increment_A(params, step, sL, s, _input):\n", + " y = 'box_A'\n", + " x = s['box_A'] + _input['add_to_A']\n", + " return (y, x)\n", + "\n", + "def increment_B(params, step, sL, s, _input):\n", + " y = 'box_B'\n", + " x = s['box_B'] + _input['add_to_B']\n", + " return (y, x)\n", + "# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # \n", + "\n", + "\n", + "\n", + "# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # \n", + "# In the Partial State Update Blocks, \n", + "# the user specifies if state update functions will be run in series or in parallel\n", + "# and the policy functions that will be evaluated in that block\n", + "partial_state_update_blocks = [\n", + " { \n", + " 'policies': { # The following policy functions will be evaluated and their returns will be passed to the state update functions\n", + " 'robot_arm_1': robot_arm_1,\n", + " 'robot_arm_2': robot_arm_2\n", + " },\n", + " 'variables': { # The following state variables will be updated simultaneously\n", + " 'box_A': increment_A,\n", + " 'box_B': increment_B\n", + " }\n", + " }\n", + "]\n", + "# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # \n", + "\n", + "\n", + "\n", + "from cadCAD.configuration import Configuration\n", + "# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # \n", + "# The configurations above are then packaged into a `Configuration` object\n", + "config = Configuration(initial_state=initial_conditions, #dict containing variable names and initial values\n", + " partial_state_update_blocks=partial_state_update_blocks, #dict containing state update functions\n", + " sim_config=simulation_parameters #dict containing simulation parameters\n", + " )\n", + "\n", + "from cadCAD.engine import ExecutionMode, ExecutionContext, Executor\n", + "exec_mode = ExecutionMode()\n", + "exec_context = ExecutionContext(exec_mode.single_proc)\n", + "executor = Executor(exec_context, [config]) # Pass the configuration object inside an array\n", + "raw_result, tensor = executor.execute() # The `execute()` method returns a tuple; its first elements contains the raw results\n", + "\n", + "%matplotlib inline\n", + "import pandas as pd\n", + "df = pd.DataFrame(raw_result)" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "df.plot('timestep', ['box_A', 'box_B'], grid=True, \n", + " xticks=list(df['timestep'].drop_duplicates()), \n", + " colormap = 'RdYlGn',\n", + " yticks=list(range(1+(df['box_A']+df['box_B']).max())));" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Non-determinism\n", + "Non-deterministic systems exhibit different behaviors on different runs for the same input. The order of heads and tails in a series of 3 coin tosses, for example, is non deterministic. \n", + "\n", + "Our robots and marbles system is currently modelled as a deterministic system. Meaning that every time we run the simulation: none of the robots act on timestep 1; robot 1 acts on timestep 2; robot 2 acts on timestep 3; an so on. \n", + "\n", + "If however we were to define that at every timestep each robot would act with a probability P, then we would have a non-deterministic (probabilistic) system. Let's make the following changes to our system.\n", + "* Robot 1: instead of acting once every two timesteps, there's a 50% chance it will act in any given timestep\n", + "* Robot 2: instead of acting once every three timesteps, there's a 33.33% chance it will act in any given timestep" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [], + "source": [ + "%%capture\n", + "from numpy.random import rand\n", + "\n", + "# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # \n", + "# We specify each of the robots logic in a Policy Function\n", + "robots_probabilities = [0.5,1/3] # Robot 1 acts with a 50% probability; Robot 2, 33.33%\n", + "\n", + "def robot_arm_1(params, step, sL, s):\n", + " _robotId = 1\n", + " if rand()" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "df.plot('timestep', ['box_A', 'box_B'], grid=True, \n", + " xticks=list(df['timestep'].drop_duplicates()), \n", + " colormap = 'RdYlGn',\n", + " yticks=list(range(1+(df['box_A']+df['box_B']).max())));" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "And if we run it again, it returns yet another result" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [], + "source": [ + "%%capture\n", + "# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # \n", + "# The configurations above are then packaged into a `Configuration` object\n", + "config = Configuration(initial_state=initial_conditions, #dict containing variable names and initial values\n", + " partial_state_update_blocks=partial_state_update_blocks, #dict containing state update functions\n", + " sim_config=simulation_parameters #dict containing simulation parameters\n", + " )\n", + "\n", + "exec_mode = ExecutionMode()\n", + "exec_context = ExecutionContext(exec_mode.single_proc)\n", + "executor = Executor(exec_context, [config]) # Pass the configuration object inside an array\n", + "raw_result, tensor = executor.execute() # The `execute()` method returns a tuple; its first elements contains the raw results\n", + "\n", + "df = pd.DataFrame(raw_result)" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "df.plot('timestep', ['box_A', 'box_B'], grid=True, \n", + " xticks=list(df['timestep'].drop_duplicates()), \n", + " colormap = 'RdYlGn',\n", + " yticks=list(range(1+(df['box_A']+df['box_B']).max())));" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "In order to take advantage of cadCAD's Monte Carlo simulation features, we should modify the configuration file so as to define the number of times we want the same simulation to be run. This is done in the `N` key of the `simulation_parameters` dict." + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [], + "source": [ + "%%capture\n", + "# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # \n", + "# Settings of general simulation parameters, unrelated to the system itself\n", + "# `T` is a range with the number of discrete units of time the simulation will run for;\n", + "# `N` is the number of times the simulation will be run (Monte Carlo runs)\n", + "# In this example, we'll run the simulation once (N=1) and its duration will be of 10 timesteps\n", + "# We'll cover the `M` key in a future article. For now, let's leave it empty\n", + "simulation_parameters = {\n", + " 'T': range(10),\n", + " 'N': 50, # We'll run the same simulation 50 times; the random events in each simulation are independent\n", + " 'M': {}\n", + "}\n", + "# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # \n", + "\n", + "# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # \n", + "# The configurations above are then packaged into a `Configuration` object\n", + "config = Configuration(initial_state=initial_conditions, #dict containing variable names and initial values\n", + " partial_state_update_blocks=partial_state_update_blocks, #dict containing state update functions\n", + " sim_config=simulation_parameters #dict containing simulation parameters\n", + " )\n", + "\n", + "exec_mode = ExecutionMode()\n", + "exec_context = ExecutionContext(exec_mode.single_proc)\n", + "executor = Executor(exec_context, [config]) # Pass the configuration object inside an array\n", + "raw_result, tensor = executor.execute() # The `execute()` method returns a tuple; its first elements contains the raw results\n", + "\n", + "df = pd.DataFrame(raw_result)" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
box_Abox_B
runtimestepsubstep
100100
1191
2182
3182
4164
...............
506155
7155
8155
9155
10155
\n", + "

550 rows × 2 columns

\n", + "
" + ], + "text/plain": [ + " box_A box_B\n", + "run timestep substep \n", + "1 0 0 10 0\n", + " 1 1 9 1\n", + " 2 1 8 2\n", + " 3 1 8 2\n", + " 4 1 6 4\n", + "... ... ...\n", + "50 6 1 5 5\n", + " 7 1 5 5\n", + " 8 1 5 5\n", + " 9 1 5 5\n", + " 10 1 5 5\n", + "\n", + "[550 rows x 2 columns]" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "from IPython.display import display\n", + "tmp_rows = pd.options.display.max_rows\n", + "pd.options.display.max_rows = 10\n", + "display(df.set_index(['run', 'timestep', 'substep']))\n", + "pd.options.display.max_rows = tmp_rows" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Plotting two of those runs allows us to see the different behaviors over time." + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAXQAAAEKCAYAAAACS67iAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADl0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uIDIuMi4yLCBodHRwOi8vbWF0cGxvdGxpYi5vcmcvhp/UCwAAIABJREFUeJzt3XmcjfX7x/HXNcMY+zIkRUaSMBjxRVkiKSElLVQiki1bKVRfbSgt0uKrREq2LJV9y1JEZN9F2SaFZGcwM9fvj3PqJ1nGWe57zjnX8/GYx5wzzrnf191Ml9s99/25RFUxxhgT+qLcLsAYY0xgWEM3xpgwYQ3dGGPChDV0Y4wJE9bQjTEmTFhDN8aYMGEN3RhjwoQ1dGOMCRPW0I0xJkxkcjIsf/78Gh8f79N7jx8/Tvbs2QNbUAbOdTPb9jkysm2fQyd3xYoVf6hqgUu+UFUd+6hYsaL6av78+T6/1x9u5bqZbfscGdm2z6GTCyzXdPRYO+VijDFhwhq6McaECWvoxhgTJhz9pagxxlzImTNnSEpKIjk5OWgZuXPnZtOmTUHbvr+5sbGxFC5cmMyZM/uUYw3dGJMhJCUlkTNnTuLj4xGRoGQcPXqUnDlzBmXb/uaqKgcOHCApKYlixYr5lHPJUy4i8omI7BOR9Wd9LZ+IzBGRrd7PeX1KN8YYr+TkZOLi4oLWzDM6ESEuLs6vf6Gk5xz6p0C9c77WE5irqiWAud7nxhjjl0ht5n/xd/8v2dBV9Tvgz3O+fDfwmffxZ8A9flVxCTvHTefEnKWojcszxpgLkvQ0SRGJB6aqaoL3+SFVzeN9LMDBv56f571PAE8AFCxYsOLYsWMvu8gDPd/n1NL1ZKlaljzdHiL6inyXvQ1fHTt2jBw5cjiWlxGybZ8jIzuj7XPu3Lm57rrrgpqbmppKdHR0UDP8zd22bRuHDx/+x9dq1669QlUrXfLN6bn7CIgH1p/1/NA5f34wPdvx9U7R1JQUndLxeR2brbx+kbOC/jR4tKalpvq0rctld9NFRrbts/vZGzduDHrukSNHLvrn27dv1zJlygQtd9WqVQrojBkzLvja8/13IMh3iu4VkUIA3s/7fNxOukRFR5PjvttosG4KcZXL8WP7l5h7awuObN0RzFhjjAmoMWPGUL16dcaMGROU7ft62eJkoAXwuvfzpIBVdBE5ri3CrXOG88vwiax86nVmlGtE2Vc6c0O3lkRlsiswjQkXK7r25eDqzQHdZt7EG7j+1c6XfF1KSgoPP/wwK1eupEyZMowYMYIlS5bQvXt3UlJS+M9//sPgwYNJTk6mcuXKTJ48mZIlS9KsWTNuvfVW2rRpc97tqirjx49nzpw51KhRg+TkZGJjYwO6j+m5bHEMsAQoKSJJItIaTyOvKyJbgdu8zx0hIhRvdR8NNk6j0B3VWf3sm8yu+gAH1wT2m2+MiUxbtmyhQ4cObNq0iVy5cjFgwABatmzJF198wbp160hJSWHw4MHkzp2bDz74gJYtWzJ27FgOHjx4wWYOsHjxYooVK0bx4sWpVasW06ZNC3jtlzysVdVmF/ijOgGu5bJku6ogNb4axO4JM1n+5KvMrNSE0j3bkPBCB6KzxLhZmjHGTxUHPh+U7R49evSSrylSpAjVqlUD4JFHHuHVV1+lWLFiXH/99QC0aNGCQYMG0bVrV+rWrcv48ePp2LEja9asueh2x4wZQ9OmTQFo2rQpI0aMoEmTJn7u0T+F9FouIsI1999Jg43TKNqsARv6DGZGhXvYv2SV26UZY0LUudeC58lz3gv4AEhLS2PTpk1ky5aNgwcPXvB1qampTJw4kVdeeYX4+Hg6derEzJkz0/UXzOUI6Yb+lyxxebl5xBvUmj6ElGMnmFOtGSu69iXl+Am3SzPGhJhdu3axZMkSAEaPHk2lSpXYsWMH27ZtA+Dzzz/nlltuAeCdd96hVKlSjB49mscee4wzZ86cd5sLFiygXLly7N69mx07drBz506aNGnCV199FdDaw6Kh/+WqO2+hwYaplOjwEFveHcG0hIb8/s1it8syxoSQkiVLMmjQIEqVKsXBgwfp1q0bw4cP5/7776ds2bJERUXRrl07tmzZwtChQ3n77bepUaMGNWvWpE+fPufd5oQJE2jcuPE/vtakSZOAX+0SdpeGZM6Zg/980JuiD9ZnaevnmVf3Ma5t1YQb3+5JTJ5cbpdnjMnA4uPj2bz53xdY1KlTh1Wr/nkqt2TJkv9YQXHAgAEX3O7gwYP/tThXo0aNaNSokZ8V/1NYHaGf7YoalbhzzSRK93yC7Z99zbTS9dn99Tdul2WMMUETtg0dIFPWWBJfe5o7lo4jyxVxLGzckUUPdOHk3j/cLs0YE6aqVKlCYmLiPz42bNjgSHbYnXI5n3wVE6j34wQ2vTmMdS9/wO/fLOHGgc9RrPndEb+6mzEmsJYuXfqvrwX6apYLCesj9LNFZc5MmefaceeaSeQqdS0/tOjBgvptOL5rj9ulGWNMQERMQ/9L7huKU3fhaCq+9wL7F65gWpkG/DRoFJqW5nZpxhjjl4hr6AASFUXJTs2pv34K+W+qwPInX+GbWx7hyJZf3C7NGGN85ldDF5EuIrJeRDaISNdAFeWUHPGFqT1rGFWHv8ah9VuZXv5uNrw+hLSUFLdLM8aYy+ZzQxeRBKANUBkoDzQUkeCuTh8EIsK1Le+l4abpXN2wNmt6vc2sKg9wcLXzk8GNMe7asWMHCQkJQdl2fHw8ZcuWJTExkbJlyzJpUuAXqfXnCL0UsFRVT6hqCvAtcG9gynJe1isLUGPCe1Sf8B4nf93LzEpNWPP8O+jp89/Ka4wxl2v+/PmsXr2aCRMm0LnzpZfyvVz+XLa4HugrInHASaA+sDwgVbnomiZ3ULB2FVY93Z8N/T4k08gr2T86HwWqVXS7NGMiRtdx77A66aeAbjOx8PW8eufjl3xdsNZDP9uRI0fImzdvIHbrH9I1U/SCb/asjd4BOA5sAE6patdzXuP3TFFwZ/5h8o8bOfjWCHT/IbLfU4ucbe4hKmtgF6S/GJs1Gf65bmZntH0+e6Zoj8n/Y92enwOaWfaq4vRr0Paisz137txJ2bJlmT17NlWrVqVDhw7Ex8czfPhwJk+eTIkSJXjiiScoX748HTt2ZN68efTt25f27dszatSoCy62lZqaSvny5cmRIweqyo4dO/j000+58847//XaoM8UTc8H0A/ocLHX+DpTVNW9+Ydzp8/QHzu9qqOkpH5dtLbumbXQsWybNRn+uW5mZ7R9zigzRYsUKfL387lz52qtWrW0Ro0af3/tm2++0caNG//9vE2bNpovXz7dvXv3RXOLFi2q+/fvV1XVbdu2adGiRfXo0aP/eq0bM0UBEJErvJ+vwXP+fLQ/28uIorLGUum9F6i7cBTRWbMw/47W/PBYL079ecjt0owxQRCM9dDPVbx4cQoWLMjGjRt9rvN8/L0OfaKIbASmAB1VNWy7XIFqFblz1deUeb4d2z+fxLTSDdg1cZbbZRljAiwY66Gfa9++fWzfvp2iRYsGtHa/Grqq1lDV0qpaXlXnBqqojCo6Ngvl+3Sj3vKJZL3qChbd15mFTTpx8rd9bpdmjAmQYKyH/pfatWuTmJhI7dq1ef311ylYsGBAa4+IxbkCLW9iKe5YNp7Nb3/C2hff5/d5P1DxnV4Ua9HYFvsyJoQFaz108FzjHmwReet/IERlykTpHk9Qf80k8iSU4IfHejH/jtYc25HkdmnGmAhlDd1PuUpey23fjqTSoN78sWQV0xPuYsv7n9tiX8ZEKFsPPcRJVBTXd3iYqxvWZlnb3qzo3IedY6dRZWhfcpcq7nZ5xoQMVQ3505b+rIeuftwXBHaEHlDZr7mKWtM/5qYR/TmyeTszEu9mfd/BpKXzN9/GRLLY2FgOHDjgd1MLVarKgQMHiI31/eZFO0IPMBGhWPN7uPL26qzo3Ie1Lwxk1/iZVP2kH/luLON2ecZkWIULFyYpKYn9+/cHLSM5Odmvhhns3NjYWAoXLuxzjjX0IMlaMD/VvxjI7mYNWd7hJWZVvp9S3VuR8OKTZHJw+QBjQkXmzJkpVqxYUDMWLFhAhQoVgprhZq6dcgmyIvfcRoON07m2ZWM29v+YGYl3s29hyK9hZozJgKyhOyAmTy6qDO3Lrd98StqZFL6p+TA/dnyZM0eOuV2aMSaMWEN30JV1bqLBuimU7NqCrYPHMC2hIXtmfOt2WcaYMGEN3WGZsmej4jvPcfvisWTOmZ0F9Z9g8aPPcupA+hf2McaY8/F3tcVu3nmi60VkjIjYb/vSKX/VROqt/IqE3h3ZOWYaU0vVZ+e46RF7yZYxxn/+zBS9GugMVFLVBCAaaBqowiJBdJYYyr3cmXorJpK96FV8/2A3FjbuyIk9e90uzRgTgvw95ZIJyCoimYBswB7/S4o8ecvdwO1LvqDCm8/y26xFTCvdgJ+HjbejdWPMZfH5OnRV/VVE3gJ24ZkpOltVZwessggTlSkTpbq3pvA9t7H08RdY+vgLkCmasVHO/5pD8uXiyHejyVUi3vFsY4zvfJ4pKiJ5gYnAg8AhYDwwQVVHnvO6kJ0p6laupqVxcu4yTvy0k5iYGEezUeX41IVEF8hH/kE9iIp1Nj+Svs9uZ9s+h05u0GeKAvcDw856/ijwv4u9JxRnima0uYtOmNH/Ax0lJXVxix6alpbmaLZ9n8M/183sUM3FgZmiu4CqIpJNPMuj1QE2XeI9JgTEVi5DQu+ObP/sK34eOt7tcowx6eRzQ1fVpcAEYCWwzrutIQGqy7gs4b8duPL26izv9Cp/rnRmLWdjjH/8nSn6oqreoKoJqtpcVU8FqjDjrqjoaG4e9SaxV8SxsEknTh887HZJxphLsDtFzQXF5s9H9fHvcvLXfSx+tIdNYTImg7OGbi4qf5XyVBjQkz1T57Ox/8dul2OMuQhr6OaSru/4MEWbNmDtCwPZO/8Ht8sxxlyANXRzSSJC5Y9fJWfJYnzf9ClO/GpLExiTEVlDN+mSOUd2akx8n5TjJ/n+wa42J9WYDMgaukm33KWKU3loH/Z/v5LVPd92uxxjzDmsoZvLEt+0Add3as7mAcPZNXGW2+UYY85iDd1ctgpvPUtc1UR+eKwXR37a7nY5xhgva+jmskXHxFB93ECis8SwsElnUo6fcLskYwzW0I2PshcpxM2j3+bwhq0sa/+Srd1uTAZgDd34rFDdapR96Ul2fD6JbUO+cLscYyKePyPoSorI6rM+johI10AWZzK+hBc6UKheDVZ07sOB5evcLseYiObPaotbVDVRVROBisAJ4KuAVWZCgkRFcfPIN4m9sgCL7uvCqT8PuV2SMRErUKdc6gA/q+rOAG3PhJAscXk9i3jt2ceS5s/aIl7GuCRQDb0pMCZA2zIhKH/lctw4sBd7pn/Lhtc+crscYyKSzzNF/96ASAywByijqv9a5MNmioZetq+5qsqhvp9wcv6PxL3RhSwVSzmW7S/7PkdGdqjmBn2m6F8fwN3A7PS81maKhka2P7lnjh3XqaXr64QCVfV40u+OZvvDvs+RkR2quTgwU/QvzbDTLcYrU/ZsVJ/4Hqknk1n0QBdbxMsYB/nV0EUkO1AX+DIw5ZhwkPuG4lQZ1pc/Fq9i1bNvul2OMREjkz9vVtXjQFyAajFhpOgD9flj8Sq2DPyMAjdX4Jr773S7JGPCnt0paoIm8Y1nyH9TBX5o9RyHN//sdjnGhD1r6CZo/l7EKzYLi+7rYot4GRNk1tBNUGUrfCXVxgzg8MZtLGvb2xbxMiaIrKGboLvytpsp90pndoyawrYP7YIoY4LFGrpxRJnn2nFV/VtY0bUfB35c63Y5xoQla+jGERIVxU2fv0HWQlew8L4unDpw0O2SjAk71tCNY7Lky0P1Ce+S/Pt+FtsiXsYEnDV046i4SmWp+O7z/DbjO9b3Hex2OcaEFWvoxnHXtW1K/CONWPfi+/w253u3yzEmbFhDN44TESp/+DK5y5Rg8UNPc3z3b26XZExYsIZuXJEpezZqTHyP1FOnWfRAV1JPn3a7JGNCnr+Lc+URkQkisllENonITYEqzIS/XNcXo+on/Tjww2pWPfOG2+UYE/L8WpwLeBeYqar3eQddZAtATSaCXHNfPUp2a8mWdz4l/00V4MrsbpdkTMjyuaGLSG6gJtASQFVPA/bvZnPZKvTvzp/L1rLs8RfI9kg9Nq/e4XgNx7ZtcyVXMmUi9Up3pgaZ8OPzCDoRSQSGABuB8sAKoIt3Sd2zX2cj6EIs243c1P0H+aPTG6Tu/dPR3Awheyy5299PtvrVEBHHYu1nO3Ry0zuCzp+GXgn4AaimqktF5F3giKr+90LvqVSpki5fvtynvAULFlCrVi2f3usPt3LdzHYrN+3MGRbMmkP16tUdz160aJEruSd+3cs3Dz/F6TU/UfDWqlT5uA85ri3iSLb9bIdOroikq6H7cw49CUhS1aXe5xOAnn5sz0S4qMyZicqRjZg8uZzPdik3Jk8u4gZ0o/DWfax65g2mJTSkfN9uXN+5OVHR0Y7XY0Kbz1e5qOrvwG4RKen9Uh08p1+MMZdBoqIo0bYpDTdOp+CtVVn51GvMqdaMQxu2ul2aCTH+XofeCRglImuBRKCf/yUZE5myFb6SW6Z8yM2j3uLYtp3MrNCYda98YNfom3Tzq6Gr6mpVraSq5VT1HlW1JfSM8YOIEP/QXTTYNIMi993BuhffZ1alJrbksEkXu1PUmAwotkA+qo1+m5qTB3Pqz8PMrvogq57pT8qJk26XZjIwa+jGZGCF77qVBhumUfzx+9n01idML9eIvQuWXvqNJiJZQzcmg4vJnZPKH71CnXmfATC39qMsa9ub04ePulyZyWisoRsTIgrWrkr9tZO54elW/Dx0PNPKNODXqfPdLstkINbQjQkhmbJl5ca3elB3yRfE5M3Nt3e14/uHniZ5fwTeYWv+xRq6MSEof+Vy1FsxkbIvdWL3hFlMK12fHWOm4uud3yY8WEM3JkRFx8RQ9sUnqbfyS3JcW4TFDz3Nt43acyLpd7dLMy6xhm5MiMuTcD11F4+lwts92Tt3CVNL12frR2NtCHcEsoZuTBiIio6m1FOPUX/dFOIqJfBjuxeZW6cFR7ftdLs04yBr6MaEkZzFr+HWuZ9R+eM+HFy5kell72LTW8NIS0lxuzTjAH9H0O0QkXUislpEfFsX1xgTUCLCdY/fT4ON07my7s2seuYNZt/0IAfXbna7NBNkgThCr62qielZq9cY45xsVxek5qTBVBv7Dsd37mFmxSasfdEzmNuEJzvlYkwYExGKPlifBhunUfTBO1n/yiBm3tiYP35Y7XZpJgj8HRKtwGwRUeAjVR0SgJqMMQEWmz8fN498i6LNGvJDu9488/ijbE7IR5YRWV2p59SpU2QZ0T+icj8veAXXlSod1ByfR9ABiMjVqvqriFwBzAE6qep357zGZoqGWLbtc/hm7zi8lzeXjmfjwSSuOA4xac7NMI10/Wq3okjxEj69N70zRVHVgHwALwHdL/aaihUrqq/mz5/v83v94Vaum9m2z+GXfTrljL46bZjGPFld8z1dVz//YbrOmzcv6LkXEmnfZ39zgeWajj7s8zl0EckuIjn/egzcDqz3dXvGmOBYsXMzlV5ryX+nDOGe8jXZ1Hssj1S5ExE7Og83/pxDLwh85f2hyASMVtWZAanKGOO3k6eTeWnaUN6aM5qCufLxVdv+3JN4i9tlmSDyuaGr6i9A+QDWYowJkO+2ruLxkf3Yum83j1drxJv3diJPtpxul2WCzN+rXIwxGciRk8fp+fUgBn/3JcXiruKbLu9T54b/uF2WcYg1dGPCxPT1i2k3uj9Jh/bRrU5TXr2rLdmzuHNZonGHNXRjQtwfxw7RbfxARi6bSelCxVjc/WOqXpvgdlnGBdbQjQlRqsq4Fd/Q6YsBHDxxhN71W/NcvRZkyRzjdmnGJdbQjQlBew7tp/2YN5i8diGVipbimy7vUa6wbzetmPBhDd2YEKKqDPt+Mt2/fJ9TKWd4895OdL31QTJF2//Kxhq6MSHjl/2/0mbUa8zbspxbSlRg6CPPcd0VRdwuy2Qg1tCNyeBS01J5b/44np/0IZmio/nooZ48Xq0RUVG2WKr5J2voxmRgG/b8QuvP+7J0xwYaJFTjw4d6UDjvFW6XZTIoa+jGZECnU87w+qwR9JkxnNxZczC61Ss0rVTX1l8xF2UN3ZgM5scdG2n1eV/W7/mZZpVu590HulEgZ163yzIhwO+GLiLRwHLgV1Vt6H9JxkSmE6eT6T1lCO/MHUuh3HFMbv8md5Wr4XZZJoQE4gi9C7AJyBWAbRkTkRb8tILHR77Gz/uTeKL6Pbxx75PkzurOwA0Tuvxq6CJSGGgA9AWeCkhFxkSQwyeP8faPXzL1l2UUL1CYeV0HUbtkRbfLMiHK3yP0gcCzgK3LafxyNPk4jT/swaqdW4iZ8abj+adPn3Yl9+ipE5w8nUz32x7m5bvakC0m1vEaTPjweaaoiDQE6qtqBxGphWf83L/OodtM0dDLdjpXVXl5yWgWJm2gztVlyRKTxbHsv5xJOUPmTJkdz42OiqJmwVLcWLik49n2sx06uUGfKQq8BiQBO4DfgRPAyIu9x2aKhka207kD545V2lXR/rNGRMw+Z4Rs2+fQySXYM0VVtZeqFlbVeKApME9VH/F1eyYyLf55Ld0nvsfd5WvyTF378THGH3bvsHHNviN/8sDQ5ykaV4hPH/2v3TRjjJ8CcmORqi4AFgRiWyYypKal8tAnvTlw/AhLnvnY5l0aEwB2hG5c8dLUoczdspxBTbuTWOR6t8sxJixYQzeOm75+MX1mDKfVzXfR6ua73C7HmLBhDd04aseBPTwy/CUSC1/PBw8+7XY5xoQVa+jGMafOnOb+j58nTdOY8EQ/stpNNMYElK22aBzTdfw7LN+5ia/bvUHxAoXdLseYsGNH6MYRny+dwYcLv6LH7c25u3xNt8sxJixZQzdBt+7XbbQd9Tq1rr+RPo3aul2OMWHLGroJqiMnj9NkSC/yZMvJmFav2nR6Y4LI/u8yQaOqtPq8D7/8sYf5XQdxZe44t0syJqzZEboJmoHzxjJx1Xxev6cDNUokul2OMWHPGroJiu9/XsOzX35A48RbePq2h9wux5iI4HNDF5FYEVkmImtEZIOIvBzIwkzo2nfkTx74+AXi4wox3BbdMsYx/pxDPwXcqqrHRCQzsEhEZqjqDwGqzYSg1LRUmn3Smz9PHGH6k0NtLqYxDvJnPXRV1WPep5m9H76NPzJho/eUIczbspzBzZ6hfOESbpdjTETx6xy6iESLyGpgHzBHVZcGpiwTiqauW0S/mZ/xeLVGtLzpX9MIjTFB5vNM0X9sRCQP8BXQSVXXn/NnNlM0xLJ9yf3t2J88Mfs9CmXPxwe3tScm2rf5nKG0z6GebfscOrlBnyl67gfQG8+gaJspGuLZl5t78nSy3tj3Uc3T7Tb9eV+So9mBYt/nyMgO1VyCPVNURAp4j8wRkaxAXWCzr9szoavLuHdYuXsLnz/2ItcWuNrtcoyJWP5c5VII+ExEovGcix+nqlMDU5YJFZ8tmcaQRV/T644WNCxb3e1yjIloPjd0VV0LVAhgLSbErE3aSrsxb1D7+oq8clcbt8sxJuLZnaLGJ4dPHqPJkF7kzZaTMa1fsUW3jMkA7P9Cc9lUlVYj+rD9wG8s6DaIgrls0S1jMgI7QjeXbcDc0Xy5egFvNO5I9ets0S1jMgpr6OayLNy6mh5f/Y8mFWrTrU4zt8sxxpzFGrpJt98PH+DBYS9wbf6r+KT5C7boljEZjJ1DN+mSkppCs0/+y6ETR5nVaSC5smZ3uyRjzDnsCN2ky3+nDGHBTyv58KEelL36OrfLMcachzV0c0mT13zH67NG8ET1e3i0an23yzHGXIA1dHNRv+z/lUc/e4WK19zAuw90c7scY8xFWEM3F3TydDL3fdyLKIliwhP9iM2cxe2SjDEXYb8UNRfU6Yu3WbX7J6Z2eJv4uKvcLscYcwn+rLZYRETmi8hG70zRLoEszLhr+OKpDFs8hefrtaRB2Wpul2OMSQd/jtBTgKdVdaWI5ARWiMgcVd0YoNqMS7Yd3EOn+R9Rp2QlXrZFt4wJGf6stvgb8Jv38VER2QRcDVhDD4Afd2xk1vYV7Io94WiuqvLi4lHEZc/F6FavEB0V7Wi+McZ3gRpBFw98BySo6pFz/sxG0F1O3ulkPloznam/LHMs81wxUZl4u3YbEvIXdTw7Ur7PGSHb9jl0ctM7gs7vhi4iOYBvgb6q+uXFXlupUiVdvny5TzkLFiygVq1aPr3XH07mTlm7kPZj3uC3wwd4qk4zEmMKcVPVmxzJPtuGVWu463Z3rjePhO9zRsm2fQ6dXBFJV0P36yoXEckMTARGXaqZmwvbf/QgXca9w5jlsyl7dXG+atuf/8SXZsGCBa6MdNsVs9XxTGOM/3xu6OJZmWkYsElVBwSupMihqoz5cTadxw3gSPJxXm7Yhp53PEpMpsxul2aMCUH+HKFXA5oD60Rktfdrz6nqdP/LCn9JB/fRfkx/pq77nirxZRjW/HnKXHWt22UZY0KYP1e5LAJs/dTLlJaWxsffT+KZL98nJTWVAfd1oXPtB+xqEmOM3+xOUQdt27ebNqNeY8FPK7m1ZCU+friXK+fIjTHhyRq6A1JSUxg47wv+O2UIWTJlZugjz9Hq5rtsQIQxJqCsoQfZ2qSttB7Zj+U7N3F3+Zr8r+kzXJWngNtlGWPCkDX0IDl15jT9Zn5Gv5mfkjdbLr54vA/331jHjsqNMUFjDT0IfvhlPa1H9mXjb9t5pHI9Bt7fjbgcud0uyxgT5qyhB9DxUyf575SPGDjvC67OU4BpHQdQP+Fmt8syxkQIa+gBMnfzj7QZ+RrbD+yhQ80mvHZPBxukbIxxlDV0Px06cZTuE99j2OIplLiiCN8+NZiaJSq4XZYxJgJZQ/fDpDXf0X7MG+w7epAetzfnxQatyRoT63ZZxpgIZQ3dB3uPHKDzuAGMWzGX8oVLMKX9W1QseoPbZRljIpy/qy1+AjQE9qmJfGwMAAALAklEQVRqQmBKyrhUlVHLZtJl/DscO3WSPo3a8uztzckcbX8vGmPc528n+hT4ABjhfykZ264/f6fd6P7M2LCEm64ty7BHnqNUoWJul2WMMX/zq6Gr6nfeaUVhK03T+N+3E+jx1f9QlPceeIoOtzSxxbSMMRmOnSu4iJ/27qLb/CGs3b+DuqUqM+ThnsTHXeV2WcYYc16BGEEXD0y90Dn0UJwpmpqWyrgtCxm+/htiojLRsUJD6hWr6Pht+6E6/zAUs22fIyM7VHPTO1MUVfXrA4gH1qfntRUrVlRfzZ8/3+f3Xo7Vu3/SG/s+qrSroo0/fFYnTJ/kSO75OLXPGSXXzWzb58jIDtVcYLmmo8dG+fxXRphJPnOKFyZ9SKXXWvLr4f1MaNOPL9v2Jy5rLrdLM8aYdPH3ssUxQC0gv4gkAS+q6rBAFOakxT+vpfXIvmz+fSctqtZnwH1dyJfdFtMyxoQWf69yaRaoQtxwLPkEz00azAffTqBI3oLM7DSQO0pXdbssY4zxScRe5TJ741KeGPUauw7upeMtTeh3d3tyxtpiWsaY0BVxDf3g8SM8NfFdPl0yjZIFi/LdU4Opfl2i22UZY4zfIqqhf7lqPh3HvsX+Y4fodUcLejdoRWzmLG6XZYwxARERDf33wwd48ou3mLhqPomFr2f6kwOoUKSk22UZY0xAhXVDV1U++2EaT014jxOnk+l3d3u6133YFtMyxoSlsO1sOw7soe2o/szetJRqxcsx9JHnuOHKeLfLMsaYoAm7hp6WlsagbyfQa9JgBOGDB7vTvua9REXZPVTGmPAWVg198+87eHxkP77/eS13lK7KRw/1oGhcIbfLMsYYR4RFQz+TmsKbs0fy8vRhZI/JymctetO8yp2OL6ZljDFuCvmGvnLXZlp/3o/VST9x34238sGDT1MwV5zbZRljjONCtqGfPJ3MK9M/4c05oyiQIw8Tn3iNeyvUdrssY4xxjb+Lc9UD3gWigaGq+npAqrqERdtW0/rzfvy0bxeP3dSQt5t0Jm92WxXRGBPZfG7oIhINDALqAknAjyIyWVU3Bqq4cx1NPk6vrwcz6NsJxMcVYnbnd6lbqkqw4owxJqT4c4ReGdimqr8AiMhY4G4gKA192W9baPHqQHYf3EuX2g/Sp1FbcsRmC0aUMcaEJH8a+tXA7rOeJwFBOVxuO+p1hiz6mlJXxvN99yHcdG3ZYMQYY0xI83mmqIjcB9RT1ce9z5sDVVT1yXNe5/dM0bGbv+XQ8aO0SqxHjMO37dvcxcjItn2OjOxQzQ36TFHgJmDWWc97Ab0u9p5QmCmaUXLdzLZ9joxs2+fQycWBmaI/AiVEpJiIxABNgcl+bM8YY4wffD5/oaopIvIkMAvPZYufqOqGgFVmjDHmsvg7U3Q6MD1AtRhjjPGDLUFojDFhwhq6McaECWvoxhgTJqyhG2NMmLCGbowxYcLnO0V9ChPZD+z08e35gT8CWE5Gz3Uz2/Y5MrJtn0Mnt6iqFrjUixxt6P4QkeWanltfwyTXzWzb58jItn0Ov1w75WKMMWHCGroxxoSJUGroQyIs181s2+fIyLZ9DrPckDmHbowx5uJC6QjdGGPMRYREQxeReiKyRUS2iUhPhzI/EZF9IrLeibyzcouIyHwR2SgiG0Ski4PZsSKyTETWeLNfdirbmx8tIqtEZKrDuTtEZJ2IrBaR5Q7m5hGRCSKyWUQ2ichNDuWW9O7rXx9HRKSrQ9ndvD9b60VkjIjEOpTbxZu5Idj7er7eISL5RGSOiGz1fs4blPD0LJru5geepXl/Bq4FYoA1QGkHcmsCNwLrHd7fQsCN3sc5gZ+c2F9vngA5vI8zA0uBqg7u+1PAaGCqw//NdwD5ncz05n4GPO59HAPkcaGGaOB3PNc5BzvramA7kNX7fBzQ0oHcBGA9kA3PCrPfANcFMe9fvQN4A+jpfdwT6B+M7FA4Qv97GLWqngb+GkYdVKr6HfBnsHPOk/ubqq70Pj4KbMLzP4IT2aqqx7xPM3s/HPkli4gUBhoAQ53Ic5uI5MbzP/4wAFU9raqHXCilDvCzqvp6w9/lygRkFZFMeBrsHgcySwFLVfWEqqYA3wL3BivsAr3jbjx/geP9fE8wskOhoZ9vGLUjDc5tIhIPVMBzpOxUZrSIrAb2AXNU1ansgcCzQJpDeWdTYLaIrPDOwHVCMWA/MNx7mmmoiGR3KPtsTYExTgSp6q/AW8Au4DfgsKrOdiB6PVBDROJEJBtQHyjiQO7ZCqrqb97HvwMFgxESCg09IolIDmAi0FVVjziVq6qpqpoIFAYqi0hCsDNFpCGwT1VXBDvrAqqr6o3AnUBHEanpQGYmPP8sH6yqFYDjeP4p7hjv6MhGwHiH8vLiOVItBlwFZBeRR4Kdq6qbgP7AbGAmsBpIDXbuRepRgvQv31Bo6L/yz79NC3u/FrZEJDOeZj5KVb90owbvP//nA/UciKsGNBKRHXhOqd0qIiMdyAX+PnJEVfcBX+E5zRdsSUDSWf8CmoCnwTvpTmClqu51KO82YLuq7lfVM8CXwM1OBKvqMFWtqKo1gYN4fjflpL0iUgjA+3lfMEJCoaFH1DBqERE851U3qeoAh7MLiEge7+OsQF1gc7BzVbWXqhZW1Xg83995qhr0IzcAEckuIjn/egzcjuef6EGlqr8Du0WkpPdLdYCNwc49RzMcOt3itQuoKiLZvD/ndfD8jijoROQK7+dr8Jw/H+1E7lkmAy28j1sAk4IR4tdMUSeoS8OoRWQMUAvILyJJwIuqOizYuXiOVpsD67znsgGeU8/81mArBHwmItF4/rIfp6qOXkLogoLAV57+QiZgtKrOdCi7EzDKe6DyC/CYQ7l//eVVF2jrVKaqLhWRCcBKIAVYhXN3bk4UkTjgDNAxmL+APl/vAF4HxolIazwrzj4QlGzvZTTGGGNCXCiccjHGGJMO1tCNMSZMWEM3xpgwYQ3dGGPChDV0Y4wJE9bQTUjxrlDYwfv4Ku9lcMHKShSR+sHavjGBZg3dhJo8QAcAVd2jqvcFMSsRz7ofxoQEuw7dhBQR+Wu1zS3AVqCUqiaISEs8K9hlB0rgWQQqBs9NWqeA+qr6p4gUBwYBBYATQBtV3Swi9+O5ASQVOIznNvVtQFY8S028BkwF3sezHGtm4CVVneTNbgzkxrNw3EhVdXQteWMgBO4UNeYcPYEEVU30rkZ59p2sCXhWp4zF04x7qGoFEXkHeBTPio5DgHaqulVEqgD/A24FegN3qOqvIpJHVU+LSG+gkqo+CSAi/fAsS9DKu0TCMhH5xptd2Zt/AvhRRKapqmPDMowBa+gmvMz3riF/VEQOA1O8X18HlPOuYHkzMN57qz9AFu/n74FPRWQcnkWjzud2PIuIdfc+jwWu8T6eo6oHAETkS6A6YA3dOMoaugknp856nHbW8zQ8P+tRwCHv8sD/oKrtvEfsDYAVIlLxPNsXoImqbvnHFz3vO/fcpZ3LNI6zX4qaUHMUz2i+y+ZdV36793w54lHe+7i4qi5V1d54Bk8UOU/WLKCTd6VARKTCWX9W1zs3Miuec/nf+1KjMf6whm5Cive0xvfeAbxv+rCJh4HWIrIG2MD/jzN8UzyDotcDi/HMrp0PlPYOUn4QeBXPL0PXisgG7/O/LMOzhv1aYKKdPzdusKtcjPGT9yqXv395aoxb7AjdGGPChB2hG2NMmLAjdGOMCRPW0I0xJkxYQzfGmDBhDd0YY8KENXRjjAkT1tCNMSZM/B8GFQzHDlXKIgAAAABJRU5ErkJggg==\n", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "df[df['run']==1].plot('timestep', ['box_A', 'box_B'], grid=True,\n", + " xticks=list(df['timestep'].drop_duplicates()), \n", + " yticks=list(range(11)),\n", + " colormap = 'RdYlGn');\n", + "df[df['run']==9].plot('timestep', ['box_A', 'box_B'], grid=True,\n", + " xticks=list(df['timestep'].drop_duplicates()), \n", + " yticks=list(range(11)),\n", + " colormap = 'RdYlGn');" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "If we plot all those runs onto a single chart, we can see every possible trajectory for the number of marbles in each box." + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "ax = None\n", + "for i in range(simulation_parameters['N']):\n", + " ax = df[df['run']==i+1].plot('timestep', ['box_A', 'box_B'],\n", + " grid=True,\n", + " xticks=list(df['timestep'].drop_duplicates()), \n", + " yticks=list(range(1+max(df['box_A'].max(),df['box_B'].max()))),\n", + " legend = (ax == None),\n", + " colormap = 'RdYlGn',\n", + " ax = ax\n", + " )" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "For some analyses, it might make sense to look at the data in aggregate. Take the median for example:" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 12, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "dfmc_median = df.groupby(['timestep', 'substep']).median().reset_index()\n", + "dfmc_median.plot('timestep', ['box_A', 'box_B'], \n", + " grid=True,\n", + " xticks=list(dfmc_median['timestep'].drop_duplicates()), \n", + " yticks=list(range(int(1+max(dfmc_median['box_A'].max(),dfmc_median['box_B'].max())))),\n", + " colormap = 'RdYlGn'\n", + " )" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Or look at edge cases" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAXQAAAEKCAYAAAACS67iAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADl0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uIDIuMi4yLCBodHRwOi8vbWF0cGxvdGxpYi5vcmcvhp/UCwAAIABJREFUeJzt3XmcjXX/x/HXZ8YwtqwlRUZCRIgsWSKlUFpQpEWKLAn33aZ9I9WNSnKnTdlKKEWEIpG4rdlDBpNkyb7PzPf3xzn1k6xnu+ac834+Hucx58ycc70/3zE+c811ruv7NeccIiIS/RK8LkBEREJDDV1EJEaooYuIxAg1dBGRGKGGLiISI9TQRURihBq6iEiMUEMXEYkRaugiIjEiWyTDChcu7FJSUgJ67b59+8idO3doC8rCuV5ma8zxka0xR0/u/Pnztznnzj7lE51zEbtVrVrVBWratGkBvzYYXuV6ma0xx0e2xhw9ucA8dxo9VodcRERihBq6iEiMUEMXEYkREX1TVETkRI4cOUJaWhoHDx4MW0a+fPlYsWJF2LYfbG5ycjLFihUjKSkpoBw1dBHJEtLS0sibNy8pKSmYWVgy9uzZQ968ecOy7WBznXNs376dtLQ0SpYsGVDOKQ+5mNn7ZrbFzJYe9bmCZjbFzFb7PxYIKF1ExO/gwYMUKlQobM08qzMzChUqFNRfKKdzDH0IcN0xn3sM+MY5Vxr4xv9YRCQo8drM/xTs+E95yMU5N8PMUo759I1Aff/9D4HpwKNBVXIS64aNY/fk7/jp28Xhijih3anrPcn1MtuzMSckkF763MjnisQIc6expqi/oY93zlXwP97pnMvvv2/Ajj8fH+e1HYAOAEWKFKn68ccfn3GR23u+yaE5S0/9RIluzmHnFKTIu0+SkDeyV/Pt3buXPHnyRDTT6+ysNuZ8+fJx0UUXhTU3IyODxMTEsGYEm7tmzRp27dr1t881aNBgvnOu2ilffDpXHwEpwNKjHu885us7Tmc7ulI0OrK9yt06e6Ebnq2cm3b9/S4zIyOi2fp39j57+fLlYc/dvXv3Sb++bt06d8kll4Qtd+HChQ5wEydOPOFzj/d9IMxXiv5uZkUB/B+3BLgdkb8UrlmZszq1YNP4aSx/+R2vyxEJuZEjR1KnTh1GjhwZlu0HetriF8DdQB//x3Ehq0jiWu6bG1Bg615+evI1CtesRJEGNb0uSTwwv3svdixaGdJtFqh8MWVeePCUz0tPT6dNmzYsWLCASy65hI8++ojZs2fz0EMPkZ6ezuWXX86gQYM4ePAg1atX54svvqBs2bK0bt2aq666ivbt2x93u845Pv30U6ZMmULdunU5ePAgycnJIR3j6Zy2OBKYDZQ1szQzuxdfI7/GzFYDV/sfiwTNzKj+zgvkLZPCrFb/Yv+vv3tdksSZVatW0blzZ1asWMFZZ51Fv379aNu2LZ988glLliwhPT2dQYMGkS9fPt58803atm3Lxx9/zI4dO07YzAF++OEHSpYsSalSpahfvz4TJkwIee2nc5ZL6xN8qWGIaxEBIClPbuqOGcDX1Vsy67buNJz2EQkBXjkn0anqa0+EZbt79uw55XOKFy9O7dq1Abjjjjt44YUXKFmyJGXKlAHg7rvvZuDAgXTv3p1rrrmGTz/9lC5durB48cnPDBs5ciStWrUCoFWrVnz00Uc0b948yBH9neZykSwpX/mLqP7OC2ydtYBFj/X1uhyJI8eeC54//3FP4AMgMzOTFStWkCtXLnbs2HHC52VkZDBmzBief/55UlJS6Nq1K5MmTTqtXzBnQg1dsqyU1tdT5oE7WNnvAzaMnuR1ORInNmzYwOzZswEYMWIE1apVIzU1lTVr1gAwdOhQrrzySgD69+9PuXLlGDFiBPfccw9Hjhw57janT5/OpZdeysaNG0lNTWX9+vU0b96czz77LKS1q6FLllal76MUqlGJH9s9zu6f13ldjsSBsmXLMnDgQMqVK8eOHTvo0aMHH3zwAS1btqRixYokJCTQsWNHVq1axbvvvkvfvn2pW7cu9erV48UXXzzuNkePHs3NN9/8t881b9485Ge7aHIuydISs2enzqjXmHTZzXzf/EGu/fETsuXO5XVZEqNSUlJYufKfZ9c0bNiQhQsX/u1zZcuW/dsMiv369TvhdgcNGvSPybmaNWtGs2bNgqz477SHLlle7gvO44oRfdm1bDVzOz3758VsInIMNXSJCkUb1aHiMw+QOnQcawZ/4nU5IidUo0YNKleu/LfbsmXLIpKtQy4SNSo81Zltsxcy/8EXKVj1EgpVq+h1SSL/MGfOnH98LtRns5yI9tAlalhCArWGvUpykcLMbNGNQ3/s9LokkSxFDV2iSnLhgtQZ/QYHNm1h9p2P4DIzvS5JJMtQQ5eoU7j6pVzWvyebvvqOZS+97XU5IllGUA3dzLqZ2VIzW2Zm3UNVlMiplO58OyVaX8+Sp99g8zezvS5HJEsIuKGbWQWgPVAdqARcb2bhnZ1exM/MqD74efKWLcms1prES0IjNTWVChUqhGXbKSkpVKxYkcqVK1OxYkXGjQv9JLXB7KGXA+Y45/Y759KB74BbQlOWyKkl5clN3bEDyDhwkJm3diPzBJddi2QV06ZNY9GiRYwePZoHHzz1VL5nKpjTFpcCvcysEHAAaALMC0lVIqcp38WlqPFeL2bd1oOFj7xK1f6Pe12ShED3Uf1ZlPZzSLdZuVgZXmh83ymfF6750I+2e/duChQoEIph/c1prSl6whf75kbvDOwDlgGHnHPdj3lO0GuKgtZdjIfcYLJ3DfiEfWO/pcDT7cnZ4NRLL4YqNxT07+xz9Jqij37xFks2rQ1pZsXzStG76f0nXdtz/fr1VKxYkcmTJ1OzZk06d+5MSkoKH3zwAV988QWlS5emQ4cOVKpUiS5duvDtt9/Sq1cvOnXqxPDhw0842VZGRgaVKlUiT548OOdITU1lyJAhNG7c+B/PDfuaoqdzA3oDnU/2HK0pGh3Z0Tjm9EOH3Ne1bnOf5Knsdq5YE7HcUNC/s09WWVO0ePHifz3+5ptvXP369V3dunX/+tzUqVPdzTff/Nfj9u3bu4IFC7qNGzeeNLdEiRJu69atzjnn1qxZ40qUKOH27Nnzj+d6saYoAGZ2jv/jBfiOn48IZnsigfpzEq/E5BzMbNGN9H37vS5JolQ45kM/VqlSpShSpAjLly8PuM7jCfY89DFmthz4EujinNOle+KZXMXO9U3itXwNc+9/WpN4SUDCMR/6sbZs2cK6desoUaJESGsPai4X51zdUBUiEgpFr6lNxee6suTpNzi79mWU7nS71yVJlPlzPvR27dpRvnx53njjDWrWrEnLli3/elP06PnQ586dS968ef+aD/2555474bYbNGhAYmIiR44coU+fPhQpUiSktWtyLok5FZ7oxLbZi5jfvTcFq1Wg0OWXel2SRIlwzYcOvnPcw02X/kvMsYQErhj6Csnnns33LbpxaPvpH9sUiWZq6BKTchQqQN3Rr3Nw81Z+0CReEkGaD10kDApdfilVX3uc/3V+jqW9BlHxqS5elySn4Jz7x1km0SaY+dCDfSNfe+gS0y7q2JqUNjew5JkB/DZlltflyEkkJyezffv2uD07yTnH9u3bSU5ODngb2kOXmGZmVH/7eXYsWskPt/+b6xZ8Ru7iRb0uS46jWLFipKWlsXXr1rBlHDx4MKiGGe7c5ORkihUrFnCOGrrEvGy5c1F3zBtMurwFM2/tztXfDSUxe3avy5JjJCUlUbJkybBmTJ8+nSpVqoQ1w8tcHXKRuHBW2Qup+X5vtv+4iIUPveJ1OSJhoYYuceOCFtdRtvvd/DxgKKkfT/C6HJGQU0OXuFLllYcpfEUV5t73JLtWhHY2PxGvqaFLXElISqLOqNdJzJXM9827cmTvPq9LEgmZYGdb7OFfT3SpmY00s8i/fSxyhnKdX4TaI/uxZ9U65nbQJF4SO4JZU/R84EGgmnOuApAItApVYSLhdG7DWlR8/kHWjxzP6rc067PEhmAPuWQDcppZNiAXsCn4kkQi45Ke93Ne0/os6PESh5ev87ockaAFfB66c+5XM/sPsAHfmqKTnXOTQ1aZSJhZQgK1PnqZSVVvYdsDL/Nxj76e1JHpHB97cLl7QvEibBuWn8I1K0c8W8Ij4DVFzawAMAa4DdgJfAqMds4NO+Z5WlM0yrLjbczpab+z88sZZM/mzXV2hw8fJnukL3TKzGTf1Lm47bvI3fwq8ra7kYScOSIWH28/28Hmhn1NUaAl8N5Rj+8C3jrZa7SmaHRka8zxkf3N+K/c3M7PuuGUcZ+XvMr9NvWHiGXH279zsLlEYE3RDUBNM8tlvunRGgIrTvEaEckiEnLn5PKBz3D1d8NIyJaNb69uy5z7nuDwzt1elyYBCrihO+fmAKOBBcAS/7YGh6guEYmQc+pdTuPF4yj/aHt+GfIZE8o3IW3cVK/LkgAEdZaLc+4Z59zFzrkKzrk7nXOHQlWYiEROtpzJVO7zENfOGUWOcwox46YuzLytOwd+3+Z1aXIGdKWoiPylYNUKXPe/0Vz6YnfSPp/KhPJNWTf0c118FSXU0EXkbxKSkqjwRCcaLxrHWWVLMvuuR5netAP7Nugyk6xODV1EjitfuVJc/f1wqr7xJFtnzGPCJU35+a3hWp81C1NDF5ETSkhMpGzXO2my9EsK16rCvC7PM7X+nez+WVfWZkVq6CJySnlSitHg6/eo+cFL7FzyM19d2ozlLw8mMz3d69LkKGroInJazIwL297C9csncF6TK1n0WF++rnErOxav9Lo08VNDF5EzkrPoOdQb+yZ1Rr/BgV9/Z1K15ix+sj8ZB3XWstfU0EUkIBc0v5amyyeQ0uYGlvX6LxOr3MTWHxZ4XVZcU0MXkYDlKJifWkP6UH/Su6TvP8iUOrczr9uLWgnKI2roIhK0866tS9OlX1KmSxt+HjCMryrewG9TZnldVtxRQxeRkEjKm4dqA57i6hnDSMyRnWmN2vFju54c3rHL69LiRjBL0JU1s0VH3XabWfdQFici0eecOtVovGgc5Xvez7qPxjG+fFM2jtXaN5EQzGyLq5xzlZ1zlYGqwH7gs5BVJiJRKzE5B5V7/4tr/zeanOcW5vvmXfm+xYMc2LzV69JiWqgOuTQE1jrn1odoeyISAwpWKc+1cz+lUu9/8ev4aUwo35RfPvxMk32FSagaeitgZIi2JSIxJCEpiUt63k/jRZ+Tr3wpfmz7GH88+gb71v/qdWkxJ+A1Rf/agFl2YBNwiXPu9+N8XWuKRlm2xhwf2V7kusxM9o/7jl2Dx2IYZ3W4mVw3XoklROb8jGj9Xod9TdE/b8CNwOTTea7WFI2ObI05PrK9HPOUkaPdt9e2c8Mp4ybXbuV2rVwbkdxo/V4TgTVF/9QaHW4RkTOQ7dxC1J/4LjU/fJldy9fyVaUbWfbS22QeOeJ1aVEtqIZuZrmBa4CxoSlHROKFmXHhXTfRdMVXnH9DAxY/3o+vq7fkj4XLvS4tagW7pug+51wh55yuHBCRgOQsUpi6n75B3TEDOLB5G19f3oJFPftqsq8A6EpREckSit/SiOuXT6Dk3TexvM9gvqrUjC0z53ldVlRRQxeRLCN7gXzUfK83V035gMzDR5hatw3/e+B5juzZ63VpUUENXUSynHOvvoImS76kbLe7WP3WCCZUuIFNk2Z4XVaWp4YuIllSUp7cVH3tCa6ZNZJsuXMyvXF7Zt/9KIe27/C6tCxLDV1EsrSza1Wh8cLPueTJTqSOGM+E8k3ZMHqSpg84DjV0EcnyEnNkp9IL3blu3hhyFT+XmS278X3zrhz4bYvXpWUpaugiEjUKVLqYRj+OovIrD/PbxBmML9+Ute+P1t66nxq6iESVhGzZKP/wfTRePI4Cl5Zlzr1PMK1RO/au2+h1aZ5TQxeRqHRWmZI0nPYRlw96lm1zFjOhwg2sfP1DMjMyvC7NM2roIhK1LCGB0h1b03TZBIrUr86C7r2ZWrcNu5av8bo0T6ihi0jUy128KFeOf5taw15lz8/rmFjlJpa++FbcTfYV7ORc+c1stJmtNLMVZlYrVIWJiJwJM6Nkm2Y0Xf4VxW9pxE9Pvc6kas3ZPm+J16VFTLB76K8Dk5xzFwOVgBXBlyQiErjkcwpRe2Q/6o17i0PbdjC5xq0sfOQV0g8c9Lq0sMsW6AvNLB9QD2gL4Jw7DBwOTVkiIsEp1qwh59S7nIWPvMqKV99j42dTSbi6GisXpUa8lr1r1nDo0srkKJg/rDkBL0FnZpWBwcByfHvn84Fuzrl9xzxPS9BFWbbGHB/Z8TTmQwtWsrPvMDI2bY1Y5rHO/vA5ki44N6DXnu4SdME09GrAj0Bt59wcM3sd2O2ce+pEr6lWrZqbNy+w6TCnT59O/fr1A3ptMLzK9TJbY46P7Hgbc2ZGBtMnfk2dOnUimgswc+ZM6je+loTExIBeb2an1dADPuQCpAFpzrk5/sejgceC2J6ISNgkJCaSkCcX2fOfFfnsPLkCbuZnlBPoC51zm4GNZlbW/6mG+A6/iIiIB4LZQwfoCgw3s+zAL8A9wZckIiKBCKqhO+cWAac8riMiIuGnK0VFRGKEGrqISIxQQxcRiRFq6CIiMUINXUQkRqihi4jECDV0EZEYoYYuIhIj1NBFRGKEGrqISIwI6tJ/M0sF9gAZQPrpTO8oIiLhEezkXAANnHPbQrAdEREJgg65iIjEiGAbugMmm9l8/1JzIiLikYCXoAMws/Odc7+a2TnAFKCrc27GMc/RmqJRlq0xx0e2xhw9uae7pijOuZDcgGeBh072nKpVq7pATZs2LeDXBsOrXC+zNeb4yNaYoycXmOdOow8HfMjFzHKbWd4/7wONgKWBbk9ERIITzFkuRYDPzOzP7Yxwzk0KSVUiInLGAm7ozrlfgEohrEVERIKg0xZFRGKEGrqISIxQQxcRiRFq6CIiMUINXUQkRqihi4jECDV0EZEYoYYuIhIj1NBFRGKEGrqISIxQQxcRiRFBN3QzSzSzhWY2PhQFiYhIYEKxh94NWBGC7YiISBCCauhmVgxoCrwbmnJERCRQwcyHDvAa8AiQNwS1iIiExdqtaXT9pC9z1i4l+8RXI55/+PBhfix/IaXPuSCsOQGvKWpm1wNNnHOdzaw+vuXnrj/O87SmaJRla8zxkR0PY87IzGTM6lm8v2Qy2RISuOLccuRIyh723GMdST9Ch8pNKJgzsH3fsK8pCrwEpAGpwGZgPzDsZK/RmqLRka0xx0d2rI95SdoaV73PPY6ONdwNA//t0nb8HrXfa05zTdFgVizqCfQEOGoP/Y5AtyciEgqH04/w0qQP6TVpCPly5mFkuxe4rdrVmBmrWe51eWEV7DF0EZEsY27qMu4d2pulm9bSpvq1vNayB4Xz5Pe6rIgJSUN3zk0HpodiWyIiZ2r/4YM89cXbvPbtJ5yXvzDjO/elacXaXpcVcdpDF5GoNm3VfO4b1ptftv1Kx7o38/LND3BWztxel+UJNXQRiUq7Duzl4bEDeGfmOC46uxjTe7zFlWUu87osT6mhi0jU+fKn7+k44hU2797Ow9e04dnr25Mre7LXZXlODV1EosbWPTt4cFQ/Pp43hYrnl2Jcp1eoVqKc12VlGWroIpLlOecY8b+v6TaqP3sO7eeFGzrwSKM7yZ4tyevSshQ1dBHJ0jb+8TudRr7ChKWzqFmyAu/d+QTli5b0uqwsSQ1dRLKkzMxMBs/8nEc+e5OMzExea9mDB+q3IDEh0evSsiw1dBHJclZv2UD7YS/x3eqFXH3x5Qxu05OShc/zuqwsTw1dRLKM9Ix0+n/zMU+Pf4cc2ZJ4784nuKfW9ZiZ16VFBTV0EckSFqet5t6hvZi/YSU3VbqSga0e4rz8Z3tdVlRRQxcRTx06cpgXJ35An68/omDusxh1Xy9aXHaV9soDEHBDN7NkYAaQw7+d0c65Z0JVmIjEvtm/LOHeob1YsTmVu2o0oV+LbhTKk8/rsqJWMHvoh4CrnHN7zSwJmGlmE51zP4aoNhGJUQfSD9N9VH/emD6K4gWKMPGB/lx3SS2vy4p6wcyH7oC9/odJ/ltgyx+JSNyYumIu7Sb1Z/O+HXS5sgUv3dSJvMnxOZlWqAV1DN3MEoH5wEXAQOfcnJBUJSIxZ8e+3Tw0dgDv//AlxfMWZsa//kvd0pW9LiumBLym6N82YpYf+Azo6pxbeszXtKZolGVrzPGRHcnc79OW8tr8cew8tI/bytaleUpNCuUrEJHso0Xr9zrsa4oeewOexrcMndYUjfJsjTk+siORu3nXNtdy8OOOjjVc5RfvdPPXr4hY9vFEay7hXlPUzM4GjjjndppZTuAa4OVAtyciscM5x9A5E+n+6WvsO3yAXs068nCjO0hK1JnS4RTMd7co8KH/OHoCMMo5Nz40ZYlItNrwx2buH96HSct/5IoLK/LenU9w8bkpXpcVF4I5y+UnoEoIaxGRKJaZmcmgGWN57PO3cDgG3PZvOtdrTkJCgtelxQ39/SMiQVu1eT33DevNzLWLaVSuBm+3eZSUQppMK9LU0EUkYEcy0uk7dQTPjn+XXNmTGXLXU9xVs4ku2/eIGrqIBGThxlXcO7QXCzf+TPMqDXjztoc4N18hr8uKa2roInJGDh45xAtfvc/Lk4dROE8+RrfvTfPLrvK6LEENXUTOwKy1i7l3aG9W/b6etrWa0rf5gxTMrcm0sgo1dBE5pb0H9/P4uEG8+d1oLihQhK+7vk6j8jW8LkuOoYYuIic1efkcOgx/iQ07fueBK1vQ+8ZO5EnO5XVZchxq6CJyXH/s28W/x7zBkNkTKFukBN//+7/ULlXJ67LkJNTQReQfxiz4li6f/Idte3fx+HV381STdiQn5fC6LDkFNXQR+ctvu7bxwMf/Yeyi6VQpXoZJD7xG5eJlvC5LTpMauojgnOPDHyfQ49PXOXDkEH1u6sy/rr5dk2lFmWBmWywOfAQUwbdS0WDn3OuhKkxEIiN1+yY6DO/DlBVzqVOqEu/e8Thlzy3hdVkSgGB+/aYD/3bOLTCzvMB8M5vinFseotpEJIwyXSYDpo2i57hBGMbAVg/Rse4tmkwrigUz2+JvwG/++3vMbAVwPqCGLlFlx77dTEldyIYf93uSv2LdCjYkRzY702Xyn2+Gsmz7eq4rX5P/3v4oJQoVjWgNEnqhWoIuBZgBVHDO7T7ma1qCLsqy42nMhzPSefCb/7JqR1rEMrOKvEk5eeCyG7imRJWIT6YVbz/bkVqCLuh3PMwsDzAG6H5sMwdwzg0GBgNUq1bN1a9fP6Cc6dOnE+hrg+FVrpfZ8TTmziNfYdWONHrWuJX7mt4Wsdyj/TjnR2rWqBnx3FWLl9H46kYRz4X4+9mOVG5QDd3MkvA18+HOubGhKUkkMobPncSgGWN56Oo2NCpUkQvPPt+TOjbkKeRJ9oZsqyOeKeEV8Lsf5vsb7T1ghXOuX+hKEgm/ZZt+ocPwPtQrXYWXburkdTkiIRHM29m1gTuBq8xskf/WJER1iYTN7gP7uOXtx8ibnIuP732BbDrXWmJEMGe5zAS0LIlEFecc9w7rxdptv/JNtwEUzVfY65JEQkYnnEpcef3bTxi94Ft639iRK8tc5nU5IiGlhi5xY9baxTw8dgA3VqrHw9fc4XU5IiGnhi5xYcvuP7j1nScpUagoQ+56SosYS0zSu0ES8zIyM7j9/af5Y/9uZnd5h/y58npdkkhYaA9dYt4zX77DN6vmMbDVQ5oKVmKaGrrEtAlLZtFr0hDaXXED7a64wetyRMJKDV1iVur2Tdw55DkqFyvDm7f92+tyRMJODV1i0sEjh2gx+HEyXSajO/QmZ/Zkr0sSCTu9KSoxqfunrzF/w0o+7/gKpc4u5nU5IhGhPXSJOUPnTOTt7z/j0UZ3cmOlel6XIxIxQTV0M3vfzLaY2dJQFSQSjCW/ruH+4X2oX+YyXmx2v9fliERUsHvoQ4DrQlCHSNB2HdhL88E9yZ8rLyPbadItiT9B/cQ752b4VysS8ZRzjnYfvcgv2zYxrftAzs1XyOuSRCJOx9AlJvT/ZiRjF02nz02dqVu6stfliHgi6DVF/Xvo451zFU7wda0pGmXZ0TbmJVtT6T5tMLXPK8dzte8IaJ6WaBtzNOd6mR2tuae7pijOuaBuQAqw9HSeW7VqVReoadOmBfzaYHiV62V2NI15865truijTd1FTzV3O/fviVhuKOnfWbmnAsxzp9Fj9a6RRK30jHRav/c0O/bvYeID/cmX05u9TZGsItjTFkcCs4GyZpZmZveGpiyRU3v6y3eY9vN8BrV+mErFSntdjojngj3LpXWoChE5E1/+9D0vff0h99VuRtta13tdjkiWoLNcJOr8svVX7hryPFWKl2GAJt0S+YsaukSVg0cO0fKdxwEY3f4lkpNyeFyRSNahN0Ulqjw4qh8LNq7iy87/4cKzz/e6HJEsRXvoEjWGzB7POzPH0fPau7m+Yh2vyxHJctTQJSosTltNp5Gv0qBMVZ6/ob3X5YhkSWrokuXtOrCXFoN7UiBXXkbe+7wm3RI5Af3PkCzNOUfbD19g3fbfmN5jIEXO0qRbIieiPXTJ0vpOHcHni7/jlZu7UOciTbolcjJq6JJlzVi9kMc+f4vmVRrQo6GuYRM5FTV0yZI279rObe8+yYWFz+P9O58MaAZFkXijY+iS5aRnpNPqvSfZdWAvkx98nbNy5va6JJGoEOzkXNeZ2SozW2Nmj4WqKIlvT37xNt+tXsh/b3+Uiudf5HU5IlEj4IZuZonAQKAxUB5obWblQ1WYxKdZvy7n5clD6VDnJu6q2cTrckSiSjB76NWBNc65X5xzh4GPgRtDU5bEo7Vb03hpziiqXnAxr9/aw+tyRKJOMMfQzwc2HvU4DagRXDnH12nEy0xcPIvcM94Ox+ZPat++fZ7kepntVe7vu/8gwYzRHXpr0i2RAIT9TdFj1hRl+vTpZ7yN9J37KZarkCdXCBbIlezZlYleZXuVe07BvFxXrDKpS34mlZ8jmr13796AfjajOVtjjsHc01mn7ng3oBbw9VGPewI9T/YarSkHID1zAAAHJ0lEQVQaHdkac3xka8zRk8tprikazDH0/wGlzaykmWUHWgFfBPn7RUREAhTw39XOuXQzewD4GkgE3nfOLQtZZSIickaCXVP0K+CrENUiIiJB0KX/IiIxQg1dRCRGqKGLiMQINXQRkRihhi4iEiPMd856hMLMtgLrA3x5YWBbCMvJ6rleZmvM8ZGtMUdPbgnn3NmnelJEG3owzGyec65avOR6ma0xx0e2xhx7uTrkIiISI9TQRURiRDQ19MFxlutltsYcH9kac4zlRs0xdBEROblo2kMXEZGTiIqG7sVi1Gb2vpltMbOlkcg7Kre4mU0zs+VmtszMukUwO9nM5prZYn/2c5HK9ucnmtlCMxsf4dxUM1tiZovMbF4Ec/Ob2WgzW2lmK8ysVoRyy/rH+udtt5l1j1B2D//P1lIzG2lmyRHK7ebPXBbusR6vd5hZQTObYmar/R8LhCX8dCZN9/KGb2retcCFQHZgMVA+Arn1gMuApREeb1HgMv/9vMDPkRivP8+APP77ScAcoGYEx/4vYAQwPsLf81SgcCQz/bkfAvf572cH8ntQQyKwGd95zuHOOh9YB+T0Px4FtI1AbgVgKZAL3wyzU4GLwpj3j94BvAI85r//GPByOLKjYQ/dk8WonXMzgD/CnXOc3N+ccwv89/cAK/D9R4hEtnPO7fU/TPLfIvImi5kVA5oC70Yiz2tmlg/ff/z3AJxzh51zOz0opSGw1jkX6AV/ZyobkNPMsuFrsJsikFkOmOOc2++cSwe+A24JV9gJeseN+H6B4/94Uziyo6GhH28x6og0OK+ZWQpQBd+ecqQyE81sEbAFmOKci1T2a8AjQGaE8o7mgMlmNt+/Bm4klAS2Ah/4DzO9a2a5I5R9tFbAyEgEOed+Bf4DbAB+A3Y55yZHIHopUNfMCplZLqAJUDwCuUcr4pz7zX9/M1AkHCHR0NDjkpnlAcYA3Z1zuyOV65zLcM5VBooB1c2sQrgzzex6YItzbn64s06gjnPuMqAx0MXM6kUgMxu+P8sHOeeqAPvw/SkeMf6lI5sBn0YorwC+PdWSwHlAbjO7I9y5zrkVwMvAZGASsAjICHfuSepxhOkv32ho6L/y99+mxfyfi1lmloSvmQ93zo31ogb/n//TgOsiEFcbaGZmqfgOqV1lZsMikAv8teeIc24L8Bm+w3zhlgakHfUX0Gh8DT6SGgMLnHO/RyjvamCdc26rc+4IMBa4IhLBzrn3nHNVnXP1gB343puKpN/NrCiA/+OWcIREQ0OPq8WozczwHVdd4ZzrF+Hss80sv/9+TuAaYGW4c51zPZ1zxZxzKfj+fb91zoV9zw3AzHKbWd4/7wON8P2JHlbOuc3ARjMr6/9UQ2B5uHOP0ZoIHW7x2wDUNLNc/p/zhvjeIwo7MzvH//ECfMfPR0Qi9yhfAHf7798NjAtHSFBrikaC82gxajMbCdQHCptZGvCMc+69cOfi21u9E1jiP5YN8Ljzrd8abkWBD80sEd8v+1HOuYieQuiBIsBnvv5CNmCEc25ShLK7AsP9Oyq/APdEKPfPX17XAPdHKtM5N8fMRgMLgHRgIZG7cnOMmRUCjgBdwvkG9PF6B9AHGGVm9+KbcfbWsGT7T6MREZEoFw2HXERE5DSooYuIxAg1dBGRGKGGLiISI9TQRURihBq6RBX/DIWd/ffP858GF66symbWJFzbFwk1NXSJNvmBzgDOuU3OuRZhzKqMb94Pkaig89AlqpjZn7NtrgJWA+WccxXMrC2+GexyA6XxTQKVHd9FWoeAJs65P8ysFDAQOBvYD7R3zq00s5b4LgDJAHbhu0x9DZAT31QTLwHjgQH4pmNNAp51zo3zZ98M5MM3cdww51xE55IXgSi4UlTkGI8BFZxzlf2zUR59JWsFfLNTJuNrxo8656qYWX/gLnwzOg4GOjrnVptZDeAt4CrgaeBa59yvZpbfOXfYzJ4GqjnnHgAws974piVo558iYa6ZTfVnV/fn7wf+Z2YTnHMRWyxDBNTQJbZM888hv8fMdgFf+j+/BLjUP4PlFcCn/kv9AXL4P84ChpjZKHyTRh1PI3yTiD3kf5wMXOC/P8U5tx3AzMYCdQA1dIkoNXSJJYeOup951ONMfD/rCcBO//TAf+Oc6+jfY28KzDezqsfZvgHNnXOr/vZJ3+uOPXapY5kScXpTVKLNHnxL850x/7zy6/zHyzGfSv77pZxzc5xzT+NbeKL4cbK+Brr6ZwrEzKoc9bVr/OtG5sR3LH9WIDWKBEMNXaKK/7DGLP8CvK8GsIk2wL1mthhYxv8vZ/iq+RaKXgr8gG/t2mlAef9CyrcBL+B7M/QnM1vmf/ynufjmsP8JGKPj5+IFneUiEiT/WS5/vXkq4hXtoYuIxAjtoYuIxAjtoYuIxAg1dBGRGKGGLiISI9TQRURihBq6iEiMUEMXEYkR/wfov5gBKaADCQAAAABJRU5ErkJggg==\n", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "max_final_A = df[df['timestep']==df['timestep'].max()]['box_A'].max()\n", + "# max_final_A\n", + "slow_runs = df[(df['timestep']==df['timestep'].max()) & \n", + " (df['box_A']==max_final_A)]['run']\n", + "slow_runs = list(slow_runs)\n", + "slow_runs\n", + "\n", + "ax = None\n", + "for i in slow_runs:\n", + " ax = df[df['run']==i].plot('timestep', ['box_A', 'box_B'],\n", + " grid=True,\n", + " xticks=list(df['timestep'].drop_duplicates()), \n", + " yticks=list(range(1+max(df['box_A'].max(),df['box_B'].max()))),\n", + " legend = (ax == None),\n", + " colormap = 'RdYlGn',\n", + " ax = ax\n", + " )" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We invite the reader to fork this code and come up with answers for their other questions that might be interesting to look at. For example:\n", + "* How often does box B momentarily contain more marbles than box A?\n", + "* What's the frequency distribution of the time to reach equilibrium?\n", + "* What's the probability distribution of the waiting times of each one of the robots?" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.5" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/tutorials/robot-marbles-part-5/robot-marbles-part-5.ipynb b/tutorials/robot-marbles-part-5/robot-marbles-part-5.ipynb new file mode 100644 index 0000000..84ceb4d --- /dev/null +++ b/tutorials/robot-marbles-part-5/robot-marbles-part-5.ipynb @@ -0,0 +1,356 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# cadCAD Tutorials: The Robot and the Marbles Part 5 - Networks\n", + "\n", + "To expand upon our previous examples, we will introduce the concept of using a graph network object that is updated during each state update. The ability to essential embed a graph 'database' into a state is a game changer for scalability, allowing increased complexity with multiple agents or components is represented, easily updated. Below, building upon our previous examples, we will represent the Robots and Marbles example with n boxes, and a variable number of marbles. \n", + "\n", + "## Behavior and Mechanisms:\n", + "* A network of robotic arms is capable of taking a marble from their one of their boxes and dropping it into the other one. \n", + "* Each robotic arm in the network only controls two boxes and they act by moving a marble from one box to the other.\n", + "* Each robotic arm is programmed to take one marble at a time from the box containing the most significant number of marbles and drop it in the other box. It repeats that process until the boxes contain an equal number of marbles.\n", + "* For our analysis of this system, suppose we are only interested in monitoring the number of marbles in only their two boxes." + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": {}, + "outputs": [], + "source": [ + "from cadCAD.engine import ExecutionMode, ExecutionContext, Executor\n", + "from cadCAD.configuration import Configuration\n", + "import networkx as nx\n", + "import matplotlib.pyplot as plt\n", + "import numpy as np\n", + "import pandas as pd\n", + "#from copy import deepcopy\n", + "\n", + "%matplotlib inline\n", + "\n", + "# define global variables\n", + "T = 25 #iterations in our simulation\n", + "boxes=5 #number of boxes in our network\n", + "m= 2 #for barabasi graph type number of edges is (n-2)*m" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We create a [Barabási–Albert](https://en.wikipedia.org/wiki/Barab%C3%A1si%E2%80%93Albert_model) graph and then fill the 5 boxes with between 1 and 10 balls. You can create as many different nodes or types of nodes as needed" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [], + "source": [ + "# create graph object with the number of boxes as nodes\n", + "network = nx.barabasi_albert_graph(boxes, m)\n", + "\n", + "# add balls to box nodes\n", + "for node in network.nodes:\n", + " network.nodes[node]['balls'] = np.random.randint(1,10)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now we will plot the network of boxes and with their labels showing how many balls are in each box." + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/home/aclarkdata/anaconda3/lib/python3.6/site-packages/networkx/drawing/nx_pylab.py:611: MatplotlibDeprecationWarning: isinstance(..., numbers.Number)\n", + " if cb.is_numlike(alpha):\n" + ] + }, + { + "data": { + "image/png": "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K6+8omHDhql169Z64YUXSEFRgP/GgHNIujihnj176r333tOUKVP0f//3f9q5c6d1SXCI9Uoc8DK2l3HSLrroImVmZqp+/fpq3LixVq5caV0SHELSBZxhvail6UaY0047TWPGjFFaWpq6du2qRx55RPn5+dZloQxZr8QBryPposTatWunQCCgzMxMpaam6uuvv7YuCWXEeiUOeJn1+KLpRrDzzjtPGRkZ6tixoxITEzVnzhzrklBGSLqAc0i6KLVy5cppyJAheuuttzR48GD169dPubm51mXhFFivxAEvsz59Q9P1iKZNmyoQCGj37t1KSkrSxx9/bF0STgFJF3CG9aKWpushsbGxeu211zRw4EClpqZqwoQJTN4RyHolDngdSRdlxufz6bbbbtPq1as1fvx4de7cWbt27bIuCyVgvRIHvMx6fNF0PepPf/qT1q1bp1q1asnv92vt2rXWJaEESLqAc0i6cESlSpX03HPP6fnnn9eNN96okSNHqqCgwLosnID1ShzwMuvTNzTdKNCxY0dlZ2dryZIlat26tb799lvrknACJF3AGdaLWppulKhdu7aWLl2qVq1aKSEhQW+99ZZ1SSiG9Uoc8DqSLlxRvnx5PfTQQ5o9e7buu+8+DRgwQAcOHLAuC0exXokDXmY9vmi6USglJUXvv/++vvnmGzVr1kybN2+2LglHIekCziHpwnXVqlXTm2++qbvvvlstWrTQ5MmTmejDhPVKHPAy69M3NN0o5vP51LdvXy1fvlxPP/20unfvrj179liXBZF0AadYL2pputBll12mrKwsxcbGKj4+Xhs2bLAuKapZr8QBryPpwlxMTIzGjx+v0aNHq2PHjho9erQKCwuty4pK1itxwMusxxdNF79z4403KisrSwsWLFDbtm31ww8/WJcUlUi6gHNIuggr559/vlasWKHk5GT5/X6988471iVFFbaXAedYjy+aLopUoUIFjRgxQjNmzNCdd96pwYMHKy8vz7qsqGC9/QV4mfX4ouniuFJTUxUIBLRlyxY1b95cW7dutS4pKpB0AeeQdBHWzjnnHM2fP1+9e/dWs2bNNH36dOuSPM16JQ54mfX4ounipPh8PvXv319LlizRyJEj1bt3b+3du9e6LM8i6QLOIekiYjRq1EjZ2dmqUKGCEhISlJ2dbV2S51hf6AF4mfX4oumixKpUqaKX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\n", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "# plot of boxes and balls\n", + "nx.draw_kamada_kawai(network,labels=nx.get_node_attributes(network,'balls'))" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [], + "source": [ + "# we initialize the cadCAD state as a network object\n", + "initial_conditions = {'network':network}" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [], + "source": [ + "#Behavior: node by edge dimensional operator\n", + "#input the states of the boxes output the deltas along the edges\n", + "\n", + "# We specify the robotic networks logic in a Policy/Behavior Function\n", + "# unlike previous examples our policy controls a vector valued action, defined over the edges of our network\n", + "def robotic_network(params, step, sL, s):\n", + " network = s['network']\n", + " delta_balls = {}\n", + " for e in network.edges:\n", + " src = e[0]\n", + " dst = e[1]\n", + " #transfer one ball across the edge in the direction of more balls to less\n", + " delta_balls[e] = np.sign(network.nodes[src]['balls']-network.nodes[dst]['balls'])\n", + " return({'delta': delta_balls})" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [], + "source": [ + "#mechanism: edge by node dimensional operator\n", + "#input the deltas along the edges and update the boxes\n", + "\n", + "# We make the state update functions less \"intelligent\",\n", + "# ie. they simply add the number of marbles specified in _input \n", + "# (which, per the policy function definition, may be negative)\n", + "\n", + "def update_network(params, step, sL, s, _input):\n", + " network = s['network'] #deepcopy(s['network']) \n", + " delta_balls = _input['delta']\n", + " for e in network.edges:\n", + " move_ball = delta_balls[e]\n", + " src = e[0]\n", + " dst = e[1]\n", + " if (network.nodes[src]['balls'] >= move_ball) and (network.nodes[dst]['balls'] >= -move_ball):\n", + " network.nodes[src]['balls'] = network.nodes[src]['balls']-move_ball\n", + " network.nodes[dst]['balls'] = network.nodes[dst]['balls']+move_ball\n", + " \n", + " return ('network', network)" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [], + "source": [ + "# wire up the mechanisms and states\n", + "partial_state_update_blocks = [\n", + " { \n", + " 'policies': { # The following policy functions will be evaluated and their returns will be passed to the state update functions\n", + " 'action': robotic_network\n", + " },\n", + " 'variables': { # The following state variables will be updated simultaneously\n", + " 'network': update_network\n", + " \n", + " }\n", + " }\n", + "]" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [], + "source": [ + "# Settings of general simulation parameters, unrelated to the system itself\n", + "# `T` is a range with the number of discrete units of time the simulation will run for;\n", + "# `N` is the number of times the simulation will be run (Monte Carlo runs)\n", + "simulation_parameters = {\n", + " 'T': range(T),\n", + " 'N': 1,\n", + " 'M': {}\n", + "}" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [], + "source": [ + "# The configurations above are then packaged into a `Configuration` object\n", + "config = Configuration(initial_state=initial_conditions, #dict containing variable names and initial values\n", + " partial_state_update_blocks=partial_state_update_blocks, #dict containing state update functions\n", + " sim_config=simulation_parameters #dict containing simulation parameters\n", + " )" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "single_proc: []\n", + "[]\n" + ] + } + ], + "source": [ + "# Run the simulations\n", + "exec_mode = ExecutionMode()\n", + "exec_context = ExecutionContext(exec_mode.single_proc)\n", + "executor = Executor(exec_context, [config]) # Pass the configuration object inside an array\n", + "raw_result, tensor = executor.execute() # The `execute()` method returns a tuple; its first elements contains the raw results\n", + "df = pd.DataFrame(raw_result)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We create some helper functions to extract the networkx graph object from the Pandas dataframe and plot it." + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": {}, + "outputs": [], + "source": [ + "#NetworkX helper functions\n", + "def get_nodes(g):\n", + " return [node for node in g.nodes if g.nodes[node]]\n", + "\n", + "\n", + "def pad(vec, length,fill=True):\n", + "\n", + " if fill:\n", + " padded = np.zeros(length,)\n", + " else:\n", + " padded = np.empty(length,)\n", + " padded[:] = np.nan\n", + " \n", + " for i in range(len(vec)):\n", + " padded[i]= vec[i]\n", + " \n", + " return padded\n", + "\n", + "def make2D(key, data, fill=False):\n", + " maxL = data[key].apply(len).max()\n", + " newkey = 'padded_'+key\n", + " data[newkey] = data[key].apply(lambda x: pad(x,maxL,fill))\n", + " reshaped = np.array([a for a in data[newkey].values])\n", + " \n", + " return reshaped" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Using our helper function get_nodes() we pull out the boxes ball quantity and save it to a new dataframe column." + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": {}, + "outputs": [], + "source": [ + "df['Balls'] = df.network.apply(lambda g: np.array([g.nodes[j]['balls'] for j in get_nodes(g)]))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Next we will plot the number of balls in each box over the simulation time period. We can see an oscillation occurs never reaching an equilibrium due to the uneven nature of the boxes and balls." + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 13, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "plt.plot(df.timestep,make2D('Balls', df))\n", + "plt.title('Number of balls in boxes over simulation period')\n", + "plt.ylabel('Qty')\n", + "plt.xlabel('Iteration')\n", + "plt.legend(['Box #'+str(node) for node in range(boxes)], ncol = 2)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "In summary, we created a graph network of boxes and robotic arms to transfer balls between the boxes, striving for an unachievable equilibrium state. The ability to embed a graph, virtually a graph database, into a cadCAD state allows for tremendous scalability and flexibility as a modeling tool. " + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.7" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/tutorials/videos/robot-marbles-part-1/README.md b/tutorials/videos/robot-marbles-part-1/README.md new file mode 100644 index 0000000..8639784 --- /dev/null +++ b/tutorials/videos/robot-marbles-part-1/README.md @@ -0,0 +1 @@ +(https://youtu.be/uJEiYHRWA9g) diff --git a/tutorials/videos/robot-marbles-part-1/config.py b/tutorials/videos/robot-marbles-part-1/config.py new file mode 100644 index 0000000..da40790 --- /dev/null +++ b/tutorials/videos/robot-marbles-part-1/config.py @@ -0,0 +1,85 @@ +# import libraries +from decimal import Decimal +import numpy as np +from datetime import timedelta +from cadCAD.configuration import append_configs +from cadCAD.configuration.utils import bound_norm_random, ep_time_step, config_sim + +seeds = { + # 'z': np.random.RandomState(1), + # 'a': np.random.RandomState(2) +} + +sim_config = config_sim({ + 'T': range(10), #number of discrete iterations in each experiement + 'N': 1, #number of times the simulation will be run (Monte Carlo runs) + #'M': g #parameter sweep dictionary +}) + + +# define the time deltas for the discrete increments in the model +# ts_format = '%Y-%m-%d %H:%M:%S' +# t_delta = timedelta(days=0, minutes=1, seconds=0) +# def time_model(_g, step, sL, s, _input): +# y = 'time' +# x = ep_time_step(s, dt_str=s['time'], fromat_str=ts_format, _timedelta=t_delta) +# return (y, x) + +# Behaviors + +# Mechanisms +def update_A(_g, step, sL, s, _input): + y = 'box_A' + add_to_A = 0 + if (s['box_A'] > s['box_B']): + add_to_A = -1 + elif (s['box_A'] < s['box_B']): + add_to_A = 1 + x = s['box_A'] + add_to_A + return (y, x) + +def update_B(_g, step, sL, s, _input): + y = 'box_B' + add_to_B = 0 + if (s['box_B'] > s['box_A']): + add_to_B = -1 + elif (s['box_B'] < s['box_A']): + add_to_B = 1 + x = s['box_B'] + add_to_B + return (y, x) + +# Initial States +genesis_states = { + 'box_A': 10, # as per the description of the example, box_A starts out with 10 marbles in it + 'box_B': 0 # as per the description of the example, box_B starts out empty +} + +exogenous_states = { + #'time': time_model +} + +env_processes = { +} + +#build mechanism dictionary to "wire up the circuit" +mechanisms = [ + { + 'policies': { + }, + 'variables': { # The following state variables will be updated simultaneously + 'box_A': update_A, + 'box_B': update_B + } + } +] + + + +append_configs( + sim_configs=sim_config, + initial_state=genesis_states, + seeds=seeds, + raw_exogenous_states=exogenous_states, + env_processes=env_processes, + partial_state_update_blocks=mechanisms +) diff --git a/tutorials/videos/robot-marbles-part-1/config2.py b/tutorials/videos/robot-marbles-part-1/config2.py new file mode 100644 index 0000000..c87f05d --- /dev/null +++ b/tutorials/videos/robot-marbles-part-1/config2.py @@ -0,0 +1,85 @@ +# import libraries +from decimal import Decimal +import numpy as np +from datetime import timedelta +from cadCAD.configuration import append_configs +from cadCAD.configuration.utils import bound_norm_random, ep_time_step, config_sim + +seeds = { + # 'z': np.random.RandomState(1), + # 'a': np.random.RandomState(2) +} + +sim_config = config_sim({ + 'T': range(10), #number of discrete iterations in each experiement + 'N': 1, #number of times the simulation will be run (Monte Carlo runs) + #'M': g #parameter sweep dictionary +}) + + +# define the time deltas for the discrete increments in the model +# ts_format = '%Y-%m-%d %H:%M:%S' +# t_delta = timedelta(days=0, minutes=1, seconds=0) +# def time_model(_g, step, sL, s, _input): +# y = 'time' +# x = ep_time_step(s, dt_str=s['time'], fromat_str=ts_format, _timedelta=t_delta) +# return (y, x) + +# Behaviors + +# Mechanisms +def update_A(_g, step, sL, s, _input): + y = 'box_A' + add_to_A = 0 + if (s['box_A'] > s['box_B']): + add_to_A = -1 + elif (s['box_A'] < s['box_B']): + add_to_A = 1 + x = s['box_A'] + add_to_A + return (y, x) + +def update_B(_g, step, sL, s, _input): + y = 'box_B' + add_to_B = 0 + if (s['box_B'] > s['box_A']): + add_to_B = -1 + elif (s['box_B'] < s['box_A']): + add_to_B = 1 + x = s['box_B'] + add_to_B + return (y, x) + +# Initial States +genesis_states = { + 'box_A': 11, # as per the description of the example, box_A starts out with 10 marbles in it + 'box_B': 0 # as per the description of the example, box_B starts out empty +} + +exogenous_states = { + #'time': time_model +} + +env_processes = { +} + +#build mechanism dictionary to "wire up the circuit" +mechanisms = [ + { + 'policies': { + }, + 'variables': { # The following state variables will be updated simultaneously + 'box_A': update_A, + 'box_B': update_B + } + } +] + + + +append_configs( + sim_configs=sim_config, + initial_state=genesis_states, + seeds=seeds, + raw_exogenous_states=exogenous_states, + env_processes=env_processes, + partial_state_update_blocks=mechanisms +) diff --git a/tutorials/videos/robot-marbles-part-1/images/Mech.jpeg b/tutorials/videos/robot-marbles-part-1/images/Mech.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..26606d5cceb740fc82ec1aba29515202c7d42087 GIT binary patch literal 42961 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 literal 0 HcmV?d00001 diff --git a/tutorials/videos/robot-marbles-part-1/images/equations.png b/tutorials/videos/robot-marbles-part-1/images/equations.png new file mode 100644 index 0000000000000000000000000000000000000000..5421cb0cf621dfd21610c5adadea5334a28fdd64 GIT binary patch literal 89457 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]\n", + "[]\n" + ] + }, + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
box_Abox_B
runtimestepsubstep
100100
1191
2182
3173
4164
5155
6155
7155
8155
9155
10155
\n", + "
" + ], + "text/plain": [ + " box_A box_B\n", + "run timestep substep \n", + "1 0 0 10 0\n", + " 1 1 9 1\n", + " 2 1 8 2\n", + " 3 1 7 3\n", + " 4 1 6 4\n", + " 5 1 5 5\n", + " 6 1 5 5\n", + " 7 1 5 5\n", + " 8 1 5 5\n", + " 9 1 5 5\n", + " 10 1 5 5" + ] + }, + "execution_count": 2, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# Run Cad^2\n", + "\n", + "first_config = configs # only contains config1\n", + "single_proc_ctx = ExecutionContext(context=exec_mode.single_proc)\n", + "run = Executor(exec_context=single_proc_ctx, configs=first_config)\n", + "\n", + "raw_result, tensor_field = run.execute()\n", + "df = pd.DataFrame(raw_result)\n", + "df.set_index(['run', 'timestep', 'substep'])" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "df.plot('timestep', ['box_A', 'box_B'], grid=True, \n", + " colormap = 'RdYlGn',\n", + " xticks=list(df['timestep'].drop_duplicates()), \n", + " yticks=list(range(1+(df['box_A']+df['box_B']).max())));" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "single_proc: [, ]\n", + "[, ]\n" + ] + }, + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
box_Abox_B
runtimestepsubstep
100110
11101
2192
3183
4174
5165
6156
7165
8156
9165
10156
\n", + "
" + ], + "text/plain": [ + " box_A box_B\n", + "run timestep substep \n", + "1 0 0 11 0\n", + " 1 1 10 1\n", + " 2 1 9 2\n", + " 3 1 8 3\n", + " 4 1 7 4\n", + " 5 1 6 5\n", + " 6 1 5 6\n", + " 7 1 6 5\n", + " 8 1 5 6\n", + " 9 1 6 5\n", + " 10 1 5 6" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "import config2\n", + "first_config = configs # only contains config1\n", + "single_proc_ctx = ExecutionContext(context=exec_mode.single_proc)\n", + "run = Executor(exec_context=single_proc_ctx, configs=first_config)\n", + "\n", + "raw_result, tensor_field = run.execute()\n", + "df2 = pd.DataFrame(raw_result)\n", + "df2.set_index(['run', 'timestep', 'substep'])" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "df2.plot('timestep', ['box_A', 'box_B'], grid=True, \n", + " colormap = 'RdYlGn',\n", + " xticks=list(df['timestep'].drop_duplicates()), \n", + " yticks=list(range(1+(df['box_A']+df['box_B']).max())));" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.7.0" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/tutorials/videos/robot-marbles-part-2/README.md b/tutorials/videos/robot-marbles-part-2/README.md new file mode 100644 index 0000000..4e0cd6e --- /dev/null +++ b/tutorials/videos/robot-marbles-part-2/README.md @@ -0,0 +1 @@ +(https://youtu.be/Y5MzhVRQyzY) diff --git a/tutorials/videos/robot-marbles-part-2/config.py b/tutorials/videos/robot-marbles-part-2/config.py new file mode 100644 index 0000000..c8ff8be --- /dev/null +++ b/tutorials/videos/robot-marbles-part-2/config.py @@ -0,0 +1,85 @@ +# import libraries +from decimal import Decimal +import numpy as np +from datetime import timedelta +from cadCAD.configuration import append_configs +from cadCAD.configuration.utils import bound_norm_random, ep_time_step, config_sim + +seeds = { + # 'z': np.random.RandomState(1), + # 'a': np.random.RandomState(2) +} + +sim_config = config_sim({ + 'T': range(10), #number of discrete iterations in each experiement + 'N': 1, #number of times the simulation will be run (Monte Carlo runs) + #'M': g #parameter sweep dictionary +}) + + +# define the time deltas for the discrete increments in the model +# ts_format = '%Y-%m-%d %H:%M:%S' +# t_delta = timedelta(days=0, minutes=1, seconds=0) +# def time_model(_g, step, sL, s, _input): +# y = 'time' +# x = ep_time_step(s, dt_str=s['time'], fromat_str=ts_format, _timedelta=t_delta) +# return (y, x) + +# Behaviors +def robot_arm(_g, step, sL, s): + add_to_A = 0 + if (s['box_A'] > s['box_B']): + add_to_A = -1 + elif (s['box_A'] < s['box_B']): + add_to_A = 1 + return({'add_to_A': add_to_A, 'add_to_B': -add_to_A}) + + + +# Mechanisms +def increment_A(_g, step, sL, s, _input): + y = 'box_A' + x = s['box_A'] + _input['add_to_A'] + return (y, x) + +def increment_B(_g, step, sL, s, _input): + y = 'box_B' + x = s['box_B'] + _input['add_to_B'] + return (y, x) + +# Initial States +genesis_states = { + 'box_A': 10, # as per the description of the example, box_A starts out with 10 marbles in it + 'box_B': 0 # as per the description of the example, box_B starts out empty +} + +exogenous_states = { + #'time': time_model +} + +env_processes = { +} + +#build mechanism dictionary to "wire up the circuit" +mechanisms = [ + { + 'policies': { # The following policy functions will be evaluated and their returns will be passed to the state update functions + 'robot_arm': robot_arm + }, + 'states': { # The following state variables will be updated simultaneously + 'box_A': increment_A, + 'box_B': increment_B + } + } +] + + + +append_configs( + sim_configs=sim_config, + initial_state=genesis_states, + seeds=seeds, + raw_exogenous_states=exogenous_states, + env_processes=env_processes, + partial_state_update_blocks=mechanisms +) diff --git a/tutorials/videos/robot-marbles-part-2/config2.py b/tutorials/videos/robot-marbles-part-2/config2.py new file mode 100644 index 0000000..fb471f4 --- /dev/null +++ b/tutorials/videos/robot-marbles-part-2/config2.py @@ -0,0 +1,87 @@ +# import libraries +from decimal import Decimal +import numpy as np +from datetime import timedelta +from cadCAD.configuration import append_configs +from cadCAD.configuration.utils import bound_norm_random, ep_time_step, config_sim + +seeds = { + # 'z': np.random.RandomState(1), + # 'a': np.random.RandomState(2) +} + +sim_config = config_sim({ + 'T': range(10), #number of discrete iterations in each experiement + 'N': 1, #number of times the simulation will be run (Monte Carlo runs) + #'M': g #parameter sweep dictionary +}) + + +# define the time deltas for the discrete increments in the model +# ts_format = '%Y-%m-%d %H:%M:%S' +# t_delta = timedelta(days=0, minutes=1, seconds=0) +# def time_model(_g, step, sL, s, _input): +# y = 'time' +# x = ep_time_step(s, dt_str=s['time'], fromat_str=ts_format, _timedelta=t_delta) +# return (y, x) + +# Behaviors +def robot_arm(_g, step, sL, s): + add_to_A = 0 + if (s['box_A'] > s['box_B']): + add_to_A = -1 + elif (s['box_A'] < s['box_B']): + add_to_A = 1 + return({'add_to_A': add_to_A, 'add_to_B': -add_to_A}) + + + +# Mechanisms +def increment_A(_g, step, sL, s, _input): + y = 'box_A' + x = s['box_A'] + _input['add_to_A'] + return (y, x) + +def increment_B(_g, step, sL, s, _input): + y = 'box_B' + x = s['box_B'] + _input['add_to_B'] + return (y, x) + +# Initial States +genesis_states = { + 'box_A': 10, # as per the description of the example, box_A starts out with 10 marbles in it + 'box_B': 0 # as per the description of the example, box_B starts out empty +} + +exogenous_states = { + #'time': time_model +} + +env_processes = { +} + +#build mechanism dictionary to "wire up the circuit" +mechanisms = [ + { + 'policies': { # The following policy functions will be evaluated and their returns will be passed to the state update functions + 'robot_arm_1': robot_arm, + 'robot_arm_2': robot_arm + }, + + 'states': { # The following state variables will be updated simultaneously + 'box_A': increment_A, + 'box_B': increment_B + } + } +] + + + +append_configs( + sim_configs=sim_config, + initial_state=genesis_states, + seeds=seeds, + raw_exogenous_states=exogenous_states, + env_processes=env_processes, + partial_state_update_blocks=mechanisms +) diff --git a/tutorials/videos/robot-marbles-part-2/configBlank.py b/tutorials/videos/robot-marbles-part-2/configBlank.py new file mode 100644 index 0000000..913497e --- /dev/null +++ b/tutorials/videos/robot-marbles-part-2/configBlank.py @@ -0,0 +1,71 @@ +# import libraries +from decimal import Decimal +import numpy as np +from datetime import timedelta +from cadCAD.configuration import append_configs +from cadCAD.configuration.utils import bound_norm_random, ep_time_step, config_sim + +seeds = { +} + +sim_config = config_sim({ + 'T': range(10), + 'N': 1 +}) + +# Behaviors +def robot_arm(_g, step, sL, s): + add_to_A = 0 + if (s['box_A'] > s['box_B']): + add_to_A = -1 + elif (s['box_A'] < s['box_B']): + add_to_A = 1 + return({'add_to_A': add_to_A, 'add_to_B': -add_to_A}) + + +# Mechanisms +def increment_A(_g, step, sL, s, _input): + y = 'box_A' + x = s['box_A'] + _input['add_to_A'] + return (y, x) + +def increment_B(_g, step, sL, s, _input): + y = 'box_B' + x = s['box_B'] + _input['add_to_B'] + return (y, x) + +# Initial States +genesis_states = { + 'box_A': 10, + 'box_B': 0 +} + +exogenous_states = { +} + + +env_processes = { +} + + +mechanisms = [ + { + 'policies': { + 'robot_arm': robot_arm + }, + 'states': { + 'box_A': increment_A, + 'box_B': increment_B + } + } +] + + +append_configs( + sim_configs=sim_config, + initial_state=genesis_states, + seeds=seeds, + raw_exogenous_states=exogenous_states, + env_processes=env_processes, + partial_state_update_blocks=mechanisms +) \ No newline at end of file diff --git a/tutorials/videos/robot-marbles-part-2/images/Mech.jpeg b/tutorials/videos/robot-marbles-part-2/images/Mech.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..1a1d5d21018bbb3a002e65c92b0fa9d72310ee3c GIT binary patch literal 50681 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 literal 0 HcmV?d00001 diff --git a/tutorials/videos/robot-marbles-part-2/images/Mech2.jpeg b/tutorials/videos/robot-marbles-part-2/images/Mech2.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..e4bb29555c7c5baf1e45ebdb7cebd2ea97eef97d GIT binary patch literal 53898 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 literal 0 HcmV?d00001 diff --git a/tutorials/videos/robot-marbles-part-2/robot-marbles-part-2.ipynb b/tutorials/videos/robot-marbles-part-2/robot-marbles-part-2.ipynb new file mode 100644 index 0000000..6f3b6a0 --- /dev/null +++ b/tutorials/videos/robot-marbles-part-2/robot-marbles-part-2.ipynb @@ -0,0 +1,239 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# cadCAD Template: Robot and the Marbles - Part 2\n", + "\n", + "![](images/Overview.jpeg)\n", + "![](images/Mech.jpeg)" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "# import libraries\n", + "import pandas as pd\n", + "import numpy as np\n", + "import matplotlib \n", + "from cadCAD.engine import ExecutionMode, ExecutionContext, Executor\n", + "import configBlank\n", + "from cadCAD import configs\n", + "import matplotlib.pyplot as plt\n", + "\n", + "%matplotlib inline\n", + "\n", + "exec_mode = ExecutionMode()" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "single_proc: []\n", + "[]\n" + ] + }, + { + "data": { + "text/html": [ + "

\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
box_Abox_B
runtimestepsubstep
100100
1191
2182
3173
4164
5155
6155
7155
8155
9155
10155
\n", + "
" + ], + "text/plain": [ + " box_A box_B\n", + "run timestep substep \n", + "1 0 0 10 0\n", + " 1 1 9 1\n", + " 2 1 8 2\n", + " 3 1 7 3\n", + " 4 1 6 4\n", + " 5 1 5 5\n", + " 6 1 5 5\n", + " 7 1 5 5\n", + " 8 1 5 5\n", + " 9 1 5 5\n", + " 10 1 5 5" + ] + }, + "execution_count": 2, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# Run Cad^2\n", + "\n", + "first_config = configs # only contains config1\n", + "single_proc_ctx = ExecutionContext(context=exec_mode.single_proc)\n", + "run = Executor(exec_context=single_proc_ctx, configs=first_config)\n", + "\n", + "raw_result, tensor_field = run.execute()\n", + "df = pd.DataFrame(raw_result)\n", + "df.set_index(['run', 'timestep', 'substep'])" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "df.plot('timestep', ['box_A', 'box_B'], grid=True, \n", + " colormap = 'RdYlGn',\n", + " xticks=list(df['timestep'].drop_duplicates()), \n", + " yticks=list(range(1+(df['box_A']+df['box_B']).max())));" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Because we have made it so that both robots read and update the state of the system at the same time, the equilibrium we had before (with 5 marbles in each box) is never reached. Instead, the system oscillates around that point." + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.7.0" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/tutorials/videos/robot-marbles-part-3/README.md b/tutorials/videos/robot-marbles-part-3/README.md new file mode 100644 index 0000000..1d73674 --- /dev/null +++ b/tutorials/videos/robot-marbles-part-3/README.md @@ -0,0 +1 @@ +(https://youtu.be/wF539-K0qXs) diff --git a/tutorials/videos/robot-marbles-part-3/config.py b/tutorials/videos/robot-marbles-part-3/config.py new file mode 100644 index 0000000..fdbe1a9 --- /dev/null +++ b/tutorials/videos/robot-marbles-part-3/config.py @@ -0,0 +1,108 @@ +# import libraries +from decimal import Decimal +import numpy as np +from datetime import timedelta +from cadCAD.configuration import append_configs +from cadCAD.configuration.utils import bound_norm_random, ep_time_step, config_sim + +seeds = { + # 'z': np.random.RandomState(1), + # 'a': np.random.RandomState(2) +} + +sim_config = config_sim({ + 'T': range(10), #number of discrete iterations in each experiement + 'N': 1, #number of times the simulation will be run (Monte Carlo runs) + #'M': g #parameter sweep dictionary +}) + + +# define the time deltas for the discrete increments in the model +# ts_format = '%Y-%m-%d %H:%M:%S' +# t_delta = timedelta(days=0, minutes=1, seconds=0) +# def time_model(_g, step, sL, s, _input): +# y = 'time' +# x = ep_time_step(s, dt_str=s['time'], fromat_str=ts_format, _timedelta=t_delta) +# return (y, x) + +# Behaviors +def robot_arm(_g, step, sL, s): + add_to_A = 0 + if (s['box_A'] > s['box_B']): + add_to_A = -1 + elif (s['box_A'] < s['box_B']): + add_to_A = 1 + return({'add_to_A': add_to_A, 'add_to_B': -add_to_A}) + +robots_periods = [2,3] # Robot 1 acts once every 2 timesteps; Robot 2 acts once every 3 timesteps + +def get_current_timestep(cur_substep, s): + if cur_substep == 1: + return s['timestep']+1 + return s['timestep'] + +def robot_arm_1(_g, step, sL, s): + _robotId = 1 + if get_current_timestep(step, s)%robots_periods[_robotId-1]==0: # on timesteps that are multiple of 2, Robot 1 acts + return robot_arm(_g, step, sL, s) + else: + return({'add_to_A': 0, 'add_to_B': 0}) # for all other timesteps, Robot 1 doesn't interfere with the system + +def robot_arm_2(_g, step, sL, s): + _robotId = 2 + if get_current_timestep(step, s)%robots_periods[_robotId-1]==0: # on timesteps that are multiple of 3, Robot 2 acts + return robot_arm(_g, step, sL, s) + else: + return({'add_to_A': 0, 'add_to_B': 0}) # for all other timesteps, Robot 2 doesn't interfere with the system + + + +# Mechanisms +def increment_A(_g, step, sL, s, _input): + y = 'box_A' + x = s['box_A'] + _input['add_to_A'] + return (y, x) + +def increment_B(_g, step, sL, s, _input): + y = 'box_B' + x = s['box_B'] + _input['add_to_B'] + return (y, x) + +# Initial States +genesis_states = { + 'box_A': 10, # as per the description of the example, box_A starts out with 10 marbles in it + 'box_B': 0 # as per the description of the example, box_B starts out empty +} + +exogenous_states = { + #'time': time_model +} + +env_processes = { +} + +#build mechanism dictionary to "wire up the circuit" +mechanisms = [ + { + 'policies': { # The following policy functions will be evaluated and their returns will be passed to the state update functions + 'robot_arm_1': robot_arm_1, + 'robot_arm_2': robot_arm_2 + }, + + 'states': { # The following state variables will be updated simultaneously + 'box_A': increment_A, + 'box_B': increment_B + } + } +] + + + +append_configs( + sim_configs=sim_config, + initial_state=genesis_states, + seeds=seeds, + raw_exogenous_states=exogenous_states, + env_processes=env_processes, + partial_state_update_blocks=mechanisms +) diff --git a/tutorials/videos/robot-marbles-part-3/images/Mech1.jpeg b/tutorials/videos/robot-marbles-part-3/images/Mech1.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..e4bb29555c7c5baf1e45ebdb7cebd2ea97eef97d GIT binary patch literal 53898 zcmeFa2UwF!(=Z$qkgjwoqJ$=)Nw0#^O8_aM1`wnpEun*`NDD|OKqw-ihbC15C@Q^o zQ9$WcMT#g@{&>zIp7Olk^}PT8mhXA~6EDf$!|d$r?A)`vGqcO_o8uY4IZag!RR942 z0pKz2AK-WrpadWxCO$(Jl9E!8Q=F%yJTJn|$}aMs{v5vmP?HdT zCS*TN00f+(COAz^aNG)D1rPvE15V@E#eay1&zw3 z(|})o{9usa6!mEuT0J^;;p_S$grc4sz)BA5&Ep9G#c3Qa^=WE=0$}2(uV2n6B=!Za+e&cdii+{d4puC^B0@wwR4U6K@(n& zm_GfJ*tva$Y7}1+ru%Y+F&7B|}j{MT+Y&ixbbzqxVAvSGJvoTCV2#ZaaEm zA||dhw%nD7&@8%>OWvgBE;zQ*#yHCEtBUWYf6dD5qhZ;Tj?Lox%JKB1W4ZXg%1wBA z3^-jlVRZw~J@q7>RXq1>t};>%HL-YB-A}lW{Dfx}&wZRk7OUul8lF|j6Yg7m@T}sw zSIf|e{aes~3;N$rqfaaq%l>bMW?nk_w)tu!NP~+iEirIy}37wNWU zVLDmDpi$U!x~2!S&)%j|uvS75*;MXpif#{h1jHrXWO8)kuIhxzQjc7j)smN|+|X6U z)E1S5>pxAqk^Xwc3^IgJ0g zdYlV{xw#e&pD}PU+}q=Omf92`r>Z_$0KC3SqXcVDbQvnU{i+%@&9=k7q@H2Zi({$U3<$v*bA{sv$AA`*2E+0wZ9%ab zk|A_koX7w<8C~g_j=-GlX0FJR#772b$`9A#G&3+FcS^YUM5-#HUSm5~(!@P%fS^X! zycR;JW-U-Z*Tr~cTb$Wzs+Z>m*XlqFAL&pEosTrcWWk-*m~Kxq%_h^)$c`6jhHSi% zhD^>1sY=as>fEq{l(4aiIg9t4T^8?muAs4rDynCQA@hkD9FjWm3;@w(L zN2R7CgU*+QMwX;JgaI-3mK+QDpOqe^Cp)A^>YC03>pZUR2Z@n!#@y$hQW(=)^6w&sM&hcyN=3)p$P|6#YMdfJ?}}F0=Uzu5 zXy~f;fLF_mYVSHPEx$;Juqt2wIZ zfnM!V?xlH6KT_k?2(dR^Tb_Y%aRb&1Q3WJv*}PSvb+u#HvWvU>+QOdId)3FK+}quw zrHmZ6ZDeO8G;E{xtEO%P-+eyPVAPpfOGB48`l{n$SxS*iTB+?B>?XJQK7})|B=sxX znni$OHG?xno_aAG#4KS(?cT01`y#gh#AS$)NEynA@DPpi7Qg5|ZuCs4RM9r@k=&@H zrV=EMH`=W1;Z!C>kCCq1Sz2m$u*Q@YX^QBsk=hm=sfpAgpP_|s^_&t@F)B9$@tKt? zL*?~rrFT1@$JlV+jMmXdYCVrrD>*a}r;!xJ|Bh+UMgrK# zW!4Jmf`J@f!qN0gdTU*mYRB?=cO|CQOC*#y&QG5)vbD4IT>PG*yUoY!l{Rqjofc)W z;0~hul6lyz!%y6KcbZ9*au9uOi!W_KMcMN9+hc%JH_BJvd55_3?NRw6277N4HKHAp9y{wrE$2#Ec+QboL$( zD5t9HE$P#Z-hI#mZcUErq(*ykm{Xf4)?+~2L2J?X;_lqA%k2~4_fLMndvRu)R)d%R zrXnJiY+PA&p@6I?3RBO0*}$nHPOI49l38y>cOCx+eOUBW&c)P}&_yefrBEIGcpnl_^425Tdb?*Jn9@y2p|`_mI+&R0#Q=nZ76xdp&0CHG&Iu+vMX#B*7Nmd=X| z#g89w`<*EWl6Srp;!TfgxTE7Xi5bpcSUb1O`Jp@uZvCpuWROAT*#**daD*(8it^Ue z=xCa17sYMeMkjC5$gMsNtbf{-6qy$pNCeS(Xmq%_UMEW9;4DAopulR>Eetq4DpA0T zTgG|=`o?i3I)q!lfIQ^zBjdt0a?LA~ISa-)34CYZX~&r>!5Z+e(fYbdpof>3E^&wS z+a$ylFjY}9;t`4K9${g-dRffnO1nd{MV_xk6~>Yj23f`zOIb=A49cS{bcz`=2)55H z<-FQ>OT9RKMv&n$%C%d$t-kzx&SK*8%kXX3#?7|$4Y)7^T}{s-P=e66K!GcPz8-Xl zTpkF&txM@cbX};6w2R5O)x--`SKB?d5ljuiyv9yxMCDvdk1;ROb4;pSTz6UvlMkj_ zRHV>QAfloX-7`exZdwNH(Uj#a zbl|-)zfFESo#Fdz7ho%K43=V-;k2I+q&C9lDbs{gt8r{WZBK-(?g1Enr#gQqUVje_ zuNS}F-_`mKkvr)E(fpXMX!(1P`wx(oU~@13CBV!{)zfWPub#@#L1kw~&n)I!%ZNEf zjzLqz>7n)9pn9MX0}R#Tw)~9!JK3#w_aC2Dn0*R=AAbxW5?=41Y<%=3VwX40hxnfH z=VxqF4Hy^Oxn?|e{J7t!wFpRc~U4{1BGsKMEB#hsI6G zxoTg~XzDdGvl)s*uFzSYFZ~tHDr{nL&O$Qe8{J9^mF@T}q*dIJxMdbJ<8tA6ydrFbvNJJ9mJ$}Ap2 zANJ+jM#8}ZTwC00U!R?dZaIO3^O3K9p5^#Vj@> zM#;n%G9f(Vq!&E@F+q}FIV`2m@S(I3YwFh3Ro8x@CR{BdtQTh_8&j^LqQ*nB4DL=V zI8&aWfkf-is%!eGgi%5ly^KrVf0OQBmhOkHVKA7I9i+}L?LCN_VikU)@Qc*U=d(UO*e8>Tn7 zkvns-{?}omQt&{HjAf@K{|94OffKC3e|n@sH~zz+pJkQFMoAji{v&0Q@>US}5BT`M zNtY%=U1fL#UWrs0yyEbLGO{%TQ(gBa zj<|C74+S?rIw`jSxtz_eWDs&6ehN+;Itpg=bMGHt6}UJ)>l<6gv>{R{3gkJ;Y#6MZ`|NhPo^RxBkM7k zZALy?wYt|B6SO4BuuK-jh(pODR8cn$WX^g$0q`B1;0`ruDWQ|)`yagH z2atWoqqv{c(gK`n#-p&D)Ea&P_?z&r!u~fBg^25#d8Txb)g}?&jQQloF@SiN?nm^2 zHYqhJoXNz#gTkZNQWD|lr62KjFfi}TLm~9@*Ny<=rzfCXzmy1-%XhNQG?-kY|1@WI zfiCB(7u(8vuACvwiw@VZs@D`qUtIez3UuYy=JKLvC!Wx{jftq1)vm>?Y5NlXvLO%Gbp)19Kko6Vpyka$?j0 z{~xWomPz{6x?02XuKdu7pG7?Nf4V?%3}|N@vT_kSt*{yP#dxCcpRW0j5r1}z|2J3n z-%|MD@c&y1e@o%-H{!=4_TNkjqO!4v#fBJ9fk_5driOl|awoaC~*Ss)a-v!<*g4p~y}e;kmj7A8QnIp1n~ z`Nl+f;QIyDTG|+hF@mBz-*fD#dOAX@4&7EbdD{oPXhCgGbBkzzib_sn(f1gjvlsU*?$TrXF9mC(U0w$JV5rJ}>_2?7R>E_vQTBJXqYk(n8hUwRQbYAfY2`M?a( z8hL+OS4)0z9(`l=>y9A3Ooreak&V418SK2cv4hf-Qd=Z1|4=j9kR;g2vr=vaSLRHmbE#HByT827LZ z2ER;7MF_L;;d(n3q@KVUx}4N`qaW?eTiPnmLo98< zYxY$4jo#^ta+jRT9TAXF09j@wmqp7&VzcQD5KSwHZ*XaiGW(H8A48Wh*AaW*h$Ho_ zkurO%b>A4Zh>Z@=-bhhp&Uv{l;1~dLqjMIJnJ!Q&99}dP5;%(}n};kzEXA$LbfHa6 zOd5W$tql|zg+#6?6^mY(GY<`rhvq`4gn4T&iVqc zd9Z)O6X>!^$sHX{!&$R$c@mnC@rCYwoV34m5E@m`T!q^&TLCfbPQY?<9~68TZGcH! zWgxGv^~UZ82ItFM(*^`V8M+e3s2br#d)=Er7pEy1Za_AdEHv%>5>oJv{y`A56 zzcoMdb}OXf;81dzea6-SlrDFki;8Y7%Buo{b-1PgKNpL?NZz>OH;?zMjpNseG5tpF z=+A0T1u^MwrA}6Wk4>)O2MLcp$KAbfp|OOkPMhn5!cWjCF90Cqng1D2=dP?I#4y>; z!iBaHZXcafW+yK{KUV<0cnMGapDs9jzw$il!1OWGG2pjN-|wpO`sVKmxyn-ts#@&u zg}95A$&<}Be{QuJvbhuFCnN%Ttp3i|TX3L&^WF7z_=;l%<4x!6 z{S49sy5Yw17JFs392!Q?cwT?CcO|k}`WW!^^O51sWL;1Ts2nTkpH~c})}yX4{NAnC zTujsMwZcgBy4 z9BC~W&KW{injFIP=&$I9$+|;sHzYeBAxVMPBC+r1^R(NsFKAPYdfcd)ZDKuKoaIXJ%;sfj&t@pe_IgGG~%70T% zi^9?j$8Wc#-4!*a0~>TlR*oYNh~ImGAQBeNzO2L60vx2l?gyTXU(7Q7H#*k9 z5caZ3c`@dsa=sM1T9$B;yO~zou(Bg{ZA+oaaJgVe>oZ=7)Yxp-F~NyazNl}vgu^kb zWTM9B^~<)JcOKO{bnJ7u-#qu$tnJnyfE)mj+pf~DWx8Aif5P68@^C6GevVrJMrT4x zf2aEvsO7eEe%i9liZfPk^-a0A`v;|gw!`{&ITu++;gE7=Bh1aBrdh3F0a9i=ebrjs z)a=4O5gQ{}SWavBN4>6NfQm|QaeFjM*FV1R#@g!(isEkl5wok6jIVTWY#O>WRXo@) zZ$Zf~K>NhVZC3LwzJ%)z7szq=p<7_qH00QcuiHYqLd-Uyl@rybt%WZLZv0M?L;)xH z;0(V_P>#>P1j5#e%aX!QJYqzl_zFMKfw#-APc~GU+YXzZP{4x*d9DFS_{QUX8A@@! zz^qFZme;4usvK-*xJrN98x6lQ{#nFR|ECMYcjw7hDr(aSvUgwY^L?_vcT)4r3lI1t zWo+P7jEe!z!ADKoZHEl3D!HQzzVWduLUTAr+IqlPPgDpQFISSi%=1Y_`K4hR0@cbX zn6c%?r72M1Ae@98$Y68odPqvR3?C;_fx#u^gXN4DDrC(DlIv#M(}En6#+)jUk~iWW zaYB}rI}pvrmOKs9Pn}ZQc$4>`XU~v|K3nhKEnkMGW*Hv?O3$URSLkYTOdZ|>tevn~ zFy#~4JvzKlTfm}I&tBMrGw4!NZ>sqGQdy;r0rqn0#R~S*ux}#m1^u{qzEyIcq;6C* zufn9w_asIMuemm9B)x6-*oZ^-loPQVokORQU9e%kBC%t9DvI%J=5)yi=#@65@Pd>( z9X-m#zRuIt8W6h*zw5R!-lErHrv`bFP`#F%uavDM?(at}mq%j?8PT7IlN(ROg{7Nkv$qzUu_hi=r{M z31c`(2M?&BO-IND)It}-6rjp`?~Sf)m0!&NhDP5kv3dGw!md)wPCivIJ_k7WP0+X1 zS2nZh!!cmko~j|hz#YD^Y4$ZJtCmX4J94kPbhxBoje5K7;bK2_FC$LUlI!6q<~bn8 zIl!r3nLU+iS>s>_>c^Im^d^)`$~jW?o${}rD~o&tIdT`05$e`@Og2&J*xJP4y~E*M zCzhw~mQdEclu@YGN5i}cdb*R*mL*pldp^fqG`e8mfhB@CpX17!w~v8bnIe?~uyCb$ zCu2tl8H9;`=QzD-50af|cwCj`(W09WHB07QKNA=F9CBne89{^A;`*{wMhIYi0XX^4 zfB5qhg+6&r@Gly}xf5)_Pjo~T_Ke$Fmur%S%LxTM=vo#b<+1`>hEso^RtJLr>#jtD zoJ4LGQEcSvXS*PwK4)z3T+CI=j3Um(HgG*Rii2JJRJP{54zyB{%AP!}0KIUqKGrNM z(-gEYciI^LTF!alC&GIvm12Re&N#=t7O5q^_^0_8&-MSIfS>hFUe(`lFP&ik zRLd>`x1=ENO%){o1xZG6c7Bgq6tkq%0=F>CP>tV@v9xAa0uRnUl~eCua$)Ijp2>7B zLiO%jB21bw=UgO1xl-~K?}jGi%x@WV?oO9}luqsGO+%;rSU-8BWt6&=T_i4T6YOz$ z?%o@x-_o=H;g}i$g#==>ZRy5S67RIn25xJdNYVXBWK~)mmz1L5?vbu1KFg3imBnyV*rho9=BbJ zr5IV54q?U|_87qRWEvSgr03C>bU+|_uIfRDZixYAFpD8eflrz;whNv=R|f>{(d+3Z z?xaJf7Br-tALcm~SuI~`i5@)d^Q?Mi@2WFu758)XX*y% z>pW;P{Vk{SRc`CH$n1r68_ZSK#TF4hW0~0u=@r+PDgibVO%IX;O53Xb^im zI+zd*di$}+0$Eev+!Mh)GICx6!7yqU$(z3|-xV-etXu_GZ^6F6VD znyMnOMK4849sP(^bt#AkE*;(5Jkz8VMZd2y4XNUp8LTkr5!R0Se1^-yl50yuA;IH_ z>tGWMO@;T}DC~xCa%kvkwWJ|`ov1Gt>W=j>K%p$yU5ZZg*@0e|Y2$2Z ztsrd^XAC(?E-r4rzXcW4)DO@ioU7W-1Y-jCqrHS@~km6raoD=<%@ zqLY|;owGt{*J89A{yrPCd-m*xIv?XpyM@KszF6`IJ<5ycl8EGeKGgGyxZEh3h}nHk z%fRVZg=A<8l0e&(#4m|n#A?y?*`s(k$b8&#_=NcAnM8IPO zSZHJnv*A>e}Z zqdj#URpr>XDSYQkTBAOCs1RFUrn)lM5<{9`eYGO|i<>sf(5{1x!d`r8I6}uweuJ2mKn%xw6S6k*je&%3>WDxZAZpOF5fCv1@mw^T}W++(O+;8TN&MdSk29Ki(6~2zzsDmEYs`Rnm&qh6N3Nw%nvkC5U=%d)ROvPZ(+jH%w8b)Q zu;+dFMre4it8ZZGW+@M_r86@%(7K!~syGT=U}wqML8Py<8z(JbH^!mblR;x8Js|G|B=h>cqFP?_((6J(JYclywnXw>6S9do= z`K9pDJ(q?5d0&qoM%ezbfxV4-Po2F}{M3`14cv;#0o?W_*h)+I1fZqVoxmFk_YN$u z-dsmX#X1{sv+qi%3o}YSu-V)WD!*;OdJN$8rV-hyv|D$$UaSF@&+yQ6Ko(usP0s#! zRY4;N$Mjt%q{FOX@&9_z@*@iah_ z7j^h^c|YfJ@DAO2_ME6(J*|<;SVY>a>}60|a(78_mzz>#Y51hKJGTs(El-GPP=sBH z0m3xa@;o=I{lp%xdSWqX&rvYN8OX__q+$c~zI&=@YR7(}JT;(UB94k*gWkFN6{s)-T(H#rl94KiDgr#YS;U}BcJ}23 z!!TLC1TrhGTZ&+XI+IA$(3K88R$=IxbJbSWR{U$$8j>3(m~x{Q8*yPv@t3E$9xKMt z$Vr`h%Ph#`$=s?YOT}*-bG=fp%H~=aq#-YJ_jbna62JQ?Oe8LzyyCIp!|KnsDEHI= zL*LVnRLj4Pe3+c9nK@#QmX6=ruA_yekAtKcdEZ!P6AB5WhIFn!d~;=3bXx`}E|S&O z-sIAnrPi)>ErN~T&%?S(3@XQoTk8zGyaG0k@zCK{^x1E@5;cJoygIFdxt@G~b5X`7 z7{X;EJ(vhmGExCUUt_SrTH}(*+lIU%=bp+>eYHsR(5HB(lerq6OG|>;b?fflnoq8u zUljKnP8>OVYrf}I)K`uK+<#=z!pk?e+M?{OcsGaj%fpCi^Bv@SR|)+}z8 z*`4{ulkm0y=jAV*85kqv7R|b0q1Mb;_*8asg__`bPYjS-9(?2T6q;||%}&KjjW07M zY82;6i~6E`kU&iya4qD`dTe}JLguIon!|usPb$GU?({-a6RA4oeF0+D^8y{*tP;6q zY2|z&+-_IW%DI#pK8!m0zQe?osEgY!+3P!i><}};Aw?*E+%D$rUe8C84g1GRX{k}2 zgEr!UT()cMOve+xevJtctpOlj_E5<&XJv5_CrDpGLfr$jvV`pFL_`EuDnC;J= z-A>$do)9aMPk9T1QXqY(;;tNS-fG-=v>qHZr4egmT3bQ8#&8MX@E2Qw-6N%5L8X^3 zwfXnDwW~8~cS#yIa9gphB}FdfOUNk@za<79W)ru~FYQ6!6i9#9U+2OZ3a)bFUkn9q zCpy4)BQ%>=;Y~nr5~IA`T$?{qPfLHuv^Vdi&Qo{NREW_;16N{}$1B~$>|KMHBfnqm z#d8(q`uKO|D!Es1)}rQ)#V^*vREPTJtF(|^y__meo&u^{6H((l33`4nh0|Ij8jHnI zGW?|hF)cTWZd6T7x!KTQhucP0hlZ|bk^LS;sHnIB@zXI;sh zR>3@T-{N8Mh{T~YWx}Zk8)^`Co$dw2R9v2S(%DZbKyELvaCZlVu}n%Jkdp*rj?owh z@2V+niT+SsE@JX$ckX#YcG7=^U~H=_4auu zroAj`W|Yp{yruY@&f^+mS|szDw<0z`zvxSmNM&L&!T@!9R854<(&v?%f!U%Oa8Z^* zbS6~JXtWs4c!!~wSl?>C+pF~uquC0d$rp8Ux!p3hPvZu(6`q~W=!vtL& z@V%O9n@RUT(x6brx~TOP=s8Q(R#W|=pwylgYZx1f)?0JD&@e5HXnKs7va=m- z%?H|?AwlP0<&4{>+8?gO8cVa#7h#&Z=y6_mAdro0tVgRJH1hhe&n8%&!Qa!V!S(I5Z%HS;fghv<| z>v?b(X-ouVWQ@!CG!C2%qn3)b_Lya$liIK%<71&=nJ5cnOUq608#2hE(t(?dUtPzA zZhm;T&OPoZgFL-fq>^hUY{jP@x)>n~?SeA)P@O?ef8zPnn+8g*ovZwG;d)xyQ%NmN zA|&+=$k3Q?&FdRzmpNcA4VxgH8n>`#K=C15=l%7`lxLuke8qxcyJ0$p<-kH-05BM@0s|BRkqG&l-a4y$y1RRS5G z^)g?N5g7-`h-eM7*RDNMD=^X*WHS`1bt>+Xv32~iN0go6#ztidtYb67po5m}m6f5! zUzz%h9!}(aBzrbsh#tx&mK9;qw2^VLh^2JNt>}id8H<`918#_m;DZ4?>Ub|Esmn<& z%M;`WeDU5%5C7?Jyvy<=KJZ&jzNe5}t;W^n(?zdfSEEyfgehS*Ju#KVt@R9- zh*dZ|Af*k-AfgY{Kiudv^fh3d8(q}qd&$Pu(OR>#dr?tw6x+lzpz1TN7@gwoDtmpI zo4fAdY5hVOkSDsp%Rnfy*0me06ehpBqb1$1`YN-lJ4Uz7L$$SKSyY~+_?tBf<2dqq zzgp=GxOBAXOR03R`r!PFs8KJeU*fzHlKU1IR*RbmaHj42 zl}X$_HrJ#b&0&T>QBzCBr&wr1_ahP$G~#ncxK_WsRfknQVM*-t7$MXx^B*&gfxt1# z`s%+P#wdSh6eIY#Ac!W1vU5og+SDtKi-F;MwH%L3Ix!$nh3KBg-{l7;$cT)0uBz>C~y+w{vO5M6MY zV&`*-n=vzM?e!6Q+3WqP*B`Zj#6mzbF^C8jsRYInRQ^{ZXTp!AyeO02m{WXu8*@rN z0zaG~@o%--awY)eKb7lDdT@X~ih~*EW5Y`7DA0|d0nS8bf8UFvZ}A*)jWS=OSN~4M zY=4U-Yty3lHP4TC){osH&kSO|u~IP|ViN^_o@ad6 zR5k2rx#Y8j$L9aeIG!Y3<9tR~AT>F8N`Tw7;W3R|FaJO`O-j#hfzo zHCnt3Oig`7Sqa7OQ!@d-1i18@5))YdC3qn8=h)qS>)()Zm;B(-BQyBoeb!4;a7n-? z6n=uJ8t05)J_FgQiDArQYP)jvH!PB9_&EcOIGCS9Y@}(wqJoYXvNX$EBeZMmC-o81 zypn2&4F`Vi7Nb`i4-xG#T}G`PbP(r8x~+8AMX095DR0g-SR#_4l65Sa8U?o3x05cl z$}F17S8kC(vs9-8r@UlJ-R(uQ%UxV3vHz9i5R92t4w>}k}sbKja$PrzCbU5!foBIqkMxsKlBR*Yb zTZ0q3p4@AqVfvH<0S&Bu5CoF%($og0UJ#;n z`N)5WUV1}CLssTh#I-bp38pv52?j0@UPf~}`W5zuW}`>vmLU5{A{Je@Mn^O5MhpVr zCyM7ke=S0kXoCZ{-_&EqO|GLxSjHH7#u!{Ggd4@)l=P4Dh!n;rfQ&E1T~#e<#g=;A zW?IPx`J|L2o${6*qeWEoV|SZvFpGg@E_I5lNr8_!7MJbDfo`fYwr#0*X>t?bvr&R~ z7wXYUmXGqx$0vdS7q0!n@F}d9#a7DXrJgDZjkTKbuH?cO12mv*&}{2;MG0-2rzP!` zwV1k32wPmJ*ML!&@qkzLdy}yz53~KzBSV#pYJQDCr%mUik+a26TK^>sbrStC0LB~~ zO}jS#QaXW}iaEXUj-t%#Ck5Gtc0>Luwx2wM4V$XrFXDCVE2WTKi(7lfi-J)E{MFLm zgdU%W5ciFr)c;G@0CPsD&I^LU-&?)9KKFALd9+M%(+@bpTSSli{J{E086lZN}6ozSFDDfe%< z0>_E7-gYQ zgS^}O5V7x(`X#|{W8fRw#wpBxqnh_A^6C?N)vs>+T9N3PPgoB9u!()w z3dvVY@G@NS_A}~RYrppBZdYQlBtBiq-xwhbwl2{%me2PCobfn~vA3tltkFQE^*%U7 z3mF0`!^F#Qxk8Y+YqFa3igOr?9jTO^#4oBXP}Kf#!Ik`^EL<4N^gCF7-B&WF5|@;v zg5U#t1=u|v=i?ZdO=9+^6{%ttqQ$MGJ})~J4XxDd6A4mEr1DW28Ij$5b6e*wsDc@@ zjavtq)`~yJ#MXS=hh&4j%4BFWccW8<#i?QFUWJ{^^(Nd|+dac70Mm;<=;6;Gwm9kq^Y2K=}a_i5Pv<=^tn6cbDeA(C9`V<02Lqr7EwTLOaiK!ZnGkJ=jRH&Jc~mT#Vz z)0wVvX5><(>X?t5tr{sJK-e!eO-E(A5c5hjAI!7e}7YBJ2XrmOU*LxC4%n_C5;?qlx=9LzrvN7X> z*(gSh!l92;R77NIVvJ!DYS{(iJF?d;qVwidzQ0!Khtjh5w70>~@bbHYpu#&>p#fE& z%*qVP_J73@@>duB!_>eeGe5OUhg1v(feksv6Ge za@;-eeLh)

N3KOW#%ZEHK~7E7pb<(Kt4(>+mR)(SGPlDtK&cVC1?cf8oj{MdW=d zLK1KoF^gVl1ZC0dT3Qhx(3AZ=0QP4Y;S<{aee&Oa>7w3KtB6@&z6#(~lVU2CP4|mk zQEe@sTTV^uM&fRstfZ%=-$+|jUTQmsajQi)J~#%jD=a%X<=;I5Y8?ZB7Y~chJo&Sz zetmwtKKQL=Dy8nLbRW!*f_3br!GWLM?!Z&mAxikhf!|H5OLyPR-mTB>{3P@Er1V!x zKQn&u$5{U56NGWSJeAwvC7}S9MX-(YPG>x=1|9#s}hL2_$luaF5Ez8xZ&DQ*!fqn;UEOrZj)%{<=L+r zeS|sdJp|hY+!cHF*A{@9$vK2#>fD2*pJlixpl|^ zXYt?L))YsL??7;V!)tE_BO5GBpERA9}~RIdV?duAW$kdfF(X3-@S zaWpZT8HU_{J5hfGwGaPOZQSF}tV?|E*ol_}KLY!zwG|JPeq=>uu5-!BVq*9j(OwKuEt(JuQP< zAb&jAKSZNJN*XH=;#>WdZ<7~wOX!qTM2nMmD|}HTJ?Zo|F*Ftm6Var5&dmoNVmD40 z`uY9ev$vH20Px4tTYv5-2?S2^+EZwr;fv>fa`VrY@Y_fH;l{tzB=*JXc6zUp`n`qs z3t6gt5mUPQgz?3D-;V`S3!}5`106?sask!$rxpKF^H%^tmRn-6Zasg%guQ9ND^2OC zK3ks>XvsIRAx*ZAGzr|kq8OD_-7SPlm^kS)rZjR4qI)E*(ya(%J(4i;p_!+$AqQ3l z7Xm?duUx(Mmp1;5#qNymS?>sb1-qFr+o|I48bPXOTxK{#v2Jjf;oJR?4ou^ApGu~J z0rciAD|8S0{ju0zrSq$}sK>fpTkcYj(4qWU z{@jV;kf$%DO(L5uwahGfm*H^-67$c>mTj_$Foz;6{uxx(SZ(F~B%Z_ICt^2$CH%Xe z|2;dsECAqtCFk^K$4<)?J)N0s(wkq_4I8?pHQy1d3~rJy7gZ81sg*z5u(Z6nn{W&` z8@f2B(oS|W3U?bL&nR)!&-#BXIp{$~@4UZs)tH+I7Qf<{cDTD?f&5PK-Py6gyTLig z!k~Jcduf-*A|BYhbF&?sirL{YVZQuF8n~zbo;)d?|KL`P|GD$i1drU}KZi_7@P7qG zO-yoa;*JI`o0ZKS#8C8qGXqDdG|R?PCRTKHz-BWDjk&#-bdymphW;X*-vDH8YhE>_ zZVr|yDu!^b6zh8KAZw6v%jd3^&w^@T$16*AbJu=Es!ENnmh?xZfe0?Tj>*f`Ie9C$ zFk#g_Gaso*7h$qtbD@=w)~~X0+_s9kg|!e>%}Oh5xB8m41H1D^ns#06(x03E_cciV zjr!7!DWgm0>y=ZZh3KOf3?H`Ql3@EN3fJ?6Hp+ShN&L4p`E~e%opYO4h-zciD$8|v zfFRb+Mjt1hvUI~q2t7yF%gCrqE8fWF9j-qM4*%TmO2I3Ou}r?*7a{fpl=x|D@hM69 zG2nfXV>{f#TH_u1busW}cV1?jgeW$N=Roz&+G5KwAXgPn;J3p6>pcJy(KBpqkHYQY z!b@(^M#&G@bSO+<8^hdSZfqnj-Z050EJ*eSu#V7!MF#8fR zzN}b1#yHLV00#X$b$&DON!!KOuyPYhB8TF!c50Xt~pL{TA2$yB>JHp zn4Xr3Ykp3`2EVX973R8b;Wa7{0A6^$>Wz@1rSY(7NeNGY-K_0ZQRSvixS|Y|N{U91 zT9UXO17yYfi=H1gpSaudLn$7Fur&Ag!7)P3tmoc+_i@S6yR%nuPlW0xwuh4M-rI6- zm2XSW0i9CpjfWq{WzYwkFDa*&?XkEHr0<@-G!y=LyBdn?KnJ1Z-K_LwL#tqynZIfO z+si~jcEj6qBX?7XMBFO;P-~<4;S@eShZcomHOsjcHL{)cF*jz7KJFk?P;dFZKD zNxxDAAN_htR050xC~nODrrq$R$4j`-MVbu6QdUTki0Cvt%5C|UN7LXg0Fo^eb58Xo0DfT$od4XI|ghyU#Qd8aA6Rqy3?(0O7qf*LiC61N)3c1^S8Ag|Nx-*&n#v|+w~cT|V@e=K zqDd4N+d}4BZyTLlFktoWsj~P$%ct2Cyx;O)^ZFf%ZO`_+XK^&wMLCg*&K9(+delJB z(sGM}bPnqMLRTpH%O=fK<#l&%d*(}jUM`$Gv$D0f-omAQmV@c#iX09QB}uUE+h^ty zE~%u2FIB8yR0C$ebB8-*B!EOFG2OtW)_?PM z_7I%}f&T@)F#rIuH`eNCZub}v#iNj+P1pZTSmlA<^GmYJ`5mH+YcKae;gKg|{mXa% zHvwG&@qljZ6%$|1QRSmp)!FYPj^V!cjW67a8|c!5rpdW3G}jJ7jKAM=y!WT-qMs(c zl%R+5@0o6%q!Vg>|J1-<9(>WA;>pSC=U?rN|8Jdin9PKQ?2pGC1CW%21Gj}fR>^-pre2R!UTPTb3U2X!mq*xfr#A}>!IP5=3Ptp9aSEkLwv z!u4~UuT&O-QaDb>Fe~DKISMD>nR2U%NXNn-+rdk?KN5gDmBd^cXpGP^AiAbNWuEMp zO4OyDr_^>q@=7OY;fMjV>^qfKF%>-jfS9$3#KRgFvt-eG=z{zHRRr=iT_PP8kpyj9OG5+>jnCs`L|4UtCa~g5Mq-?}d z>T#4uX^&DQw?`oGC_JAMVkdKPts0r z#(1nZrm#FGM6HU|XD`hvEk%9ZlwO}-TY5>8+N3XfxfabKk{rC^EAZmu?E}|`N%O9X zPZq;F5#M_y%6}wq&L8NVjY)f_$?g3RIv9~3{y?&jU9?Der{c8jktZZ07r^Qm+iANd6qX#>G%XpC!Vk6ua$QrqXEr|l*vQCkvUA$%w^Gr25&&~I!xM|I{y5VlH*ylX# zU-G4^WpEZ#ugg;9R!(*-iRx^JErl-!qnBGQPWCQZFq=&t>2~itzoTUZxbW_$hO+si zB1K?B+}yw_3KDJO=bUP|KSfyJ4T1DVI*7^^>b$-sZ`qZjTwKdq=B?^#L{S1^{NmY< z3p}L>eFE|<<+_zw#1H_lrdY@bD&}5HtUcdnDQ9pDpp$g&Isj^mVIcB?-Yo18Uy$|*l{wOj+2Ojh4>>&IIro?+}2^Ml<-e2@S zoBwGVf;dvc3;xGQc)?7KHV%sJ2)XT->aO{JKieSGu5kWPeqz_^{stS%OoB)go3yFa zd|NE+|7q{L`Kb@64Ka=6#-L=D*NxUmDWo z{-8u$#eGedZLW*16r!A%J&wDq+&4bqA40-X2m6fX6x1s>b>F3k+l9mxvYSSW^1F2 zhx7I6MYk5ALT#d6X^6}610&vZ=5kp?k31bpM5Iuvk0It_U<+%#QAm+umFLOeBo9Lq zqKQ&Aq)UF#QGQZJkzoDbFiRAz**5v;zIdm=z%Z4ofRd}fwK3(pA70TJo=%fzM!!U)I)V_J^NTs&8SifMqD>n16eP|_SAA0Y>l{VC4z;`J9U5A;3LNf`2-UHusWHI2dcEbX5H$=B8c3e-?!kc2;W>PAcw2mJF z?h%`Gs@oKk`d33T^zGZs2DQ{IAd*TT=1T+b7}nM6w%%cj$1_nM8+8HHNzZ<(+h5W5 zPWa^ulnA&kKf#TFicLX@VRL0#2mX~omDAN+k2U?8uy3P+hqGcJ2>kn1(HMnQ2U-8! z-Xs#wZE@U~nRA=ta&m34uw-gg5P~sR?|r8EA>bTm3(|9*b6_K_d$MGZEhrN{v(!f} zWui%AzY%x2VMiKjGK{&^Nire786#TEWM1IvQ)#S*am_Y^_-u`XhhH0M4`HEIJU9v(qL zV@PYzewuDTyhDKq+prVMKo`BMiV8LgXiYaC@v%A9K$0ayCBsVsGICz{ULG#p zZz(=?L-u{3P)uNabU?UubX@24_{6n0`UV7Ab7k>37K=NEW-=P!MMB1;QHAKNn~}OQ zC6Ul!iL~jM4pKr>Z@n|eG(66OFa-oHDT%=u8G=*;l}non;YO-S2|>q~s^miM6`K^$ zIkC#Jx;a04!aOReWUdez34@3P66%U6l`|xgsI!FxG)cEZ7#174wvA51W%Mz&D!U z>inr7LCjFQw7vm0B`o9~%WVY8=4h>)KS2r+DltBUpvwAT*?LJI#PzAXNT&KS7n@`A zeJ7w$s-n9$bH+=4HgZObD#PLF=#erBn}`dc=L_svNTzOopq_%2Irk;ul&(mE<>SB= zjl6|UiiS(t?n4k|7So5bUi3PtG8p~A|hS>F=)$J}X2a*a3_-_CG~$fn$NTWnGyQObP+s*a4E zN7@S27MMu#VN7G11LD~&x^obq7VHyt_3e*ZGl7~CDH^eX7v8u#LTiqJGYi}Ff$^I> z?T|(x%0+9(svLz{EH5x$4n9B>cto|e5`E2vf{xiK$1tKi_gt%!ZKtTV1G;}oIyS*; zIsy|&l8sbyCY{Q`_5_5~z11e6p=;ezBaBV(#fV=Do^7=m*st z|ATa{;}Wp`yY1Z3t!#aQwfp@mIxB5Hot@Q~EIJ?Ghs@$GEW^+R)w`ZHuA`)F z$W;udQB^R+XaTw~NjFWr>)8aj5ck_q1|Ul4@@yzbeDP@Rpl>^_9aBhqR-LKN$-TM6 zEEdGU9+xf*O6#9Va5~lU5W~*%!eQiqG&5^mzm+gw;apOOiqEoT6Jl93J3k;|Vz`Vl z0`ZAON?mN-I59ZoB6~D4umhbWGR%;1tF7xA0<%JK9*G0Qd!jShO(iDi$=EzP!2@g% z%bTXxGJ0^-PZ5)sh8$UHTL(4l&Q~FIO5&JY*JfHqZq`_)s;FE`AKwIuy4_1?t1Oxo zEV#kW5K}bzFz*Hf1gI_?zL8O*HZ>C`qYd7%t;x`2;2Su$=AgT1Iiug2B@#&iBuvxN zWeiTAAWXOSx$dsx>%V5zj-#h}Qx8iFQuR=n?b^m=m}k^p9$rfbfj6LAduN-q6zdZL z$vKUVPZ^8ffz=j(RlB-2T!tKG>Qw}Wwl72u#IWgdr1dkRpPsXNEzm3t<82>#N^^yR zE$88S73QgwY@%FpT#W@3E_%im>Ui=@aOWuQ7v;uK{5Qr32n3JjJ(>gQicZ&BM!zsq0mqNQMx=K_*>%p=Ljfu991i70-VJ#t$ z+=mNx=S@R7uwHYKlgBrs+aWroR=vyW#YpZC{w)@lW<*ENr@2ftIk6V#$8;g+S(MS8 z@-N_<%Y@X7CURHfe8aN?gMiP`!blR}C5{cv3=8rF4Fo67gzkA0BE^)`WXDWRb9Z*) z=B6ZZ0ppGI!R-;TsF?Et31TXI33FzRGfL&e>Lse}&#fQMWQT$s+Q4uc;kC9v%oW1B zLY!km>63zZA7vlY>-o2Nh(_=ia3H4rP6h>@61D`(4M8{0a$#g{;}jFY*MfxJm2IrT znAOB-hOqH7Igyq7I_vUn3Pf`mEiwsarRkK`P)8k?H?iOV+ki#h=e)ToEay}av=I=! z?n2TDWC)A0ZJB~vDzP$@dV$29Dt9y~H?m3zCQ2Pj;K%+1`$}gWtK8b=5FQ_YNI>X$mY-}mc=`7E>^2wWerq_;Zu$yOjs(=FdOj?qF_S|LfLsqs8fL5 zy39h%yuPg&cG-sjZ=E+eAXCzm%RGXoUHkM%$b?5WqN}4rhH)8{T~gGlkaf^CQ!135 z5#dBDeBj^?Vz1E%KpXY@s>07(VZ1hzJ2=&sqYgZ|Hq+#PoWz}m++6$>CLja~$6(O+ z=T6J+MP&{fT-$TL3>+TSC^zHc~favE;3>r{_nU#t!5Jx*wrn?}@djqtNPVGE$ z{7H>b+F*}{aCBs>FAsMoj9$t_FdqxS%~d9#x$l#vkflBCFn~Kep_${w zoQ-Zg1~V1lL$7|%LtwJxWsIGOn)N1Gp$2aK#?vftFM5cm2Ue+^+pYDMHAEkg-cvtU z5_Jf8Gc_})v0=_Fk`0Sz{{zE&OXF za{WeW{wOjaVzzg=*i^<17nyhP>Myd-U~>KLLYS}d^3xG?V3pI=SyuwaY<)@-P1rg5 zk1-e1qe8nT||!@Erm+5h=RDUb+LYHh+Em{rbV}_@r_C9lk!vw&`FBcRIJ<%Ow{FsfuEJi>DcZh;rN+jbi49qfO@wd6-3T=yEHA zvjtGSHi*pN%@WabJE;#-7VSeEkqm#$(VMf1JK1wLA(~;vB*Z^A>K3pgV2Sfi-$ZJE-p& z=_+rfHIzd|C0=n_ki^r_INvZsL;c+Hm;}nAr0C%ZkKqcr9K-USSHf>>91$_EZ4WY> z^wLe#pLxA3%kO8`%745Y@=yL2J8=cCXH4WX}&H5%_=|#u}PT`M5h@%;UsTL@; zyqs6d_MQ!6Afy?g6q_aAAP4JTOC+Se5`xQUGGb3&J8k#u_s#)00yIif&=+89mwpZD zAGi}sUDQbafhK+vJ(aVKCVfN{*^#T%+7f0t@**U!e}I{KqAGLB!$-DI!j^Y&W3lBF za==Z8bj0=~$tW+WLLuY4d-N7h5`jA+C4Feab9WZ3*idN0VQ!C+*3qn(%g|K~BG<&x z56@+CLAnx&JkohzEpx*?e-`5Pt#BEowkqU)bOiSu2-J?(l9xV=GE|~ zEHAuo4f3Up)P(fXNRy8d@8{b^sMX$18MGf8UIu<@3fT_F|6Vg!@p_D@^=`bpGcY8% z=MV|n76yX)KO|S8#dKTHV2FMlljUsjt@Z{Z_S_;Zc2h(J-v?eU0}j1qUY)q|jVe>M zjH!NWq8*t=H6uJG?oOa?ZVSotb-}6;U>Cxb1j03JP>m?TCNB#xB4n#eck!^GgP|_5YJ?S{_!I>TRlE_OM2YlkXTzgyf&gcyNQyzkDBu zKi!m#L0E1^mL>?AGpaeQ2N5b=taiF0mXJp&6Oa==ve?s%$VSOkE^?39ZiB?Ba_A+6 z1vw)-y{H(i&KfRCK>~sZy6P#|R99r`d1rd!(-epD<4XfdD@QKKLQT@Hv>~E96*M#) z+nEWb`uHxHYB2@&JTyUl@V@oS20Z}af&+aC2QcFNh#;IpKOP<4w=!-B1!3dMm)6ld z)H8Aou)-JlEdQF&Qk0%hMlGG=$5(2CN8?B}^=1wMM~-jY911UaRAmr81g1tT>Wd6M z`6~Y|wb-pMy+bzyOcfA-YW*JDW;y=DUS!Pv4;#T(iynNn zL*W}27K}mEaM)(W8ft6 zLeg{RJ3PBO%bs6mr+HGs2fDA#3+H*m#B*YR(ni_cf$_sKllE=LTnR@ljF`Cq|#BEEb}Zv!kuW<-o`?jF&a9Cl{Qb=q`W@&pf2eOoHt+ zXqIuWhOU#;-8-5EZ@;8yOM9Ao3+Bn}0RB1_0py_;v6nIvD6*U8<`QBL1N_eQl;M?AV`Kp>A1yJ@dKn zv!bJ;w3~T`(Fr~$Zd&ufqcePxX&D|p70|ZFKHu}J#VkxmH6fmuovxwHP{UMP#C{}U zKRLg)Oe`xvS)R3QF4%noy=f`c;xxHU1(Z52mLipa3Zx>H*1>uMH`W{=V2b+UZrC0Q zb_d*!Y|kB6Db$#^F($k_x!hUbH`t)^77eQmhY0|oMrY$iyR((_gem9${&tj!F!)y%FljC4f|O$ zr(;XFneDIRx%u4^-@W+0^RgeT^yP~$?>^i#=eJ~auSZ|bd^!Gg)8KIVUt?|tlN9eQ z>YE>Y=Vf1N{=@OhjK24akKtYY!!>`!jIu9P{P&q&{WATWFQ&pJ1AmJezW1_k7yP00 zM+&Rce>e~LX=@(6r8E114ub-MIs~`=K{)Tju>UXwz4ExNq>m8HwqMvH9?F=;Mg@GPz3i zUMy6c@-Bg7%pAH{h{-Ia`f=&TK$o2dBP(C^v5cKw%#SEZjih%guEuFcdGWH~bBbD7 zQ!t;>Z_@Y;cqG#pC{h_7^A&mZY^46rkXLv{e~!F5?fz%Tt2M#3KSOo>eeW-rxNk_e zznD#qdVbc!-mE*JMMo$}y5HHb>P+9CVwit{U;K;ytn!5c>l-k`l={&s9CkBL zH$>UfkuXD3^UTAJ$j}Hr(7cSPI*mycKYLnboY?(^o_}X#&fg))xB1H-CN6)_YX0rI z?B`7-?&=7vP7hp{YV_~cS!QdSl?KLzA9M$si@`OAqmb{ zUzuk9Uj6+fKl&HK|Ng!D`)M%1{rz!?=!bRfPuG0g_WZxT`b&I@ic~yUJNSll3q7zc zsA#sa{lqVkj`_{FzyHgz^S!IAGn}U|nC>Ima|9R?Ld-CPyIk&bwUeutTZ?0BPu$c#r)w4-xdz54(qv2pKMu{IW) z??l;0k;IGF|J@`1q4;@z;*i?~mRDWOOrK(G>O6TSkdUx|fTRnG5vH|;T#^*HGbviv zwY4XY*RZFv?p(hoHa9)(&a5fouzBmmt6NufhL9bIfvjPc3`#aC7@e;i7*<7vg|z8w zwNFsIWqI}wPXzp|<^3~p>3N-RGQ@c}xIe^IQN|q!)vV?ez=@9NX6Gbnhf41bqLurY zZSJtxog5T>4wSE|a)ok=gdYM*BfQTrsWC)Qd=$WfL{&Y~7o|4cm6YXmhA0DB-^L-D z%ZzBLVM+MpdTI<~$(oPZ)ZbCAP&Jh%Nu;q{s|JC4geo{o7bIL6q!VqB$7x2`F_>b= zTkM^BphO;yl=au-U;l1%8rpZ)O=?$dbWzax`m;U>Pu>Kw1`%7#q}RJS6mJ&wO}IFi z29PxwxJ41xUQNlk(M1fyo5DCB119HhnIlA_Vc#MI8> z%V*ZqX;;ql)WnaIVD9C#s#{D|k;-09QxYbExf9Ml+*jDL(R!Cs6fE?zR#+HqG;*P7 zZ1Yl%i{#NjCOUG9W}XAOWl<7El=x_cBx1|djyWwZX`^^73EBy$dzisfeLITZ-@9r# zCv3O%>6rst0#}Y$e|0BP!D`3;4;Phqar`hIrAM{@(XT#z!b4yLfe=*^(Lv&?eyHl( zuizz?xr1$%EKALae%MzKP^Pd-iFsYO{@`|x|2u~(EPIt+c9PT@E7`f#6ZaJG$f=~W zcUWCTH!fDeB3?QQ%6ts#Q<+SGFNkZu_QhmZa)ZVOpoU=O_eQ}m8VSU zrW_3m^T+DNZAuR9g$uR0x~P@(W=vg|yJO6IzF9ahU%H+|V)jYTXpQn>H%yTG92RaF z9U3^C$9T~$%?xZ|-f5a+7yn(=f7;UX@{`O0QK-7+WRx#2rO9s59|r ziU4y)b(s&56Dg#WoBPx1iK8D8ZL{K`)sHmoGY$-+%6Ax z=WFP&_i1gE(3I80mywh&TXLq+l<&6~E?FLxuNGhp33%6a4ab#}PzB9FwgDjq578Kh z>4*5czcO2dO&GFH8>Q`S-5gqZyZ_4y3HsP zkt?SJTIVE)mHfan_~^dZ)igyxHNz+d0*YfA{@l&$4i5Bhp67&5HRL{G7{F87)5GGHa-U@xw!?PU$}kG!<9&7BwT3ZdS!h7@;Y^yfv?eot9P&Hibu<6T2nTj>rCSAq3 zgSlZMK$!`@FqULroq|4^6u}bp)z+5RHpMOPOzt+tObR_$ImLA|qB?yvsh63av9z03 zRu>$MZdHf>wibK4x37e@`VNK*xyo|E#egQ{N7$w;>uK5ijhdCD!z$zjqT2!6QN zCTReZYTfN8G@0MUt=?SK<+@y=@HSJzPVJnlOD}_%Aym^G$$Lx2o?1WU;9y=xx|q^% z4ySJ;)9BXLg_BpZjw*^3=tzt#HeBF9t%yFZf>S;Et~UaX7P}admPZGlkkB=Ox!JKi zjEal}o7@QWCv_#^H>p~~^7D{b@)-=}Y;Ip(#l~dxed1*hALwc3HzlPFk@ z&vrghY&sUiR+BLiB3DM(8B@%@x6DC*oS~)O74@F`ghZ4wP3?XUyI?NrVY!7eNYk*sl3ERll;Cy?;WXE=+LfrNzE z@aUP{Y|oE3-vAuNbn(XW9Z%Xp7c?|M=w!A;r$CVjBt~39%-D~_TzjsuEs5ZI5Gq7Q ziyg!w=B1f1@uC9-E#WFwg!1enof-_wZ>5W^3fd~p>Za7Roz|;w%Tbn zbwHi+RhNX81l@QSZ%UWK%E4<*aq-rcktx}Lw+U^U5)x`3cum+%-+R%NFDykLYeyU0 z;kZeSWzqHW#_>>h*|)=R@HS+ry+&oGMGl0}(M`$e#&KjsaQ55C+=t?!DySEnhX7p% zG&=8cg;b@@ZEdHFC^bYu=V)~aV;(tfDiM$yH1JAB=3>6vZCFZ8)a0GPROLa7CGL2) zXBJ=)*5Zhq)5)4>{;*?^776!P)EB>c&QBY~Hw=4UN0E~Dm$Ij)qb966WgCNnOk~^c z8D_UI3yrL*qV$!$=<`|-i&SFh z(K!&<#j@o_8CC8^VmMaXkWm^d`fNn*mraZCJ+BRzkMB3Ad|<<+_nc6Qvwu$@IhXn1 z*lj6qxm;!-m45Kz`#>igg*ozEVfU)KsS0|>2C7uKzC)BPxxr3x5&zz^vM7S~Wov>Q zh@m8&I3=$NvoqVaFhiQ)C4cQo<6;RLN_CIZDxmwa4*@-u4C(hpVeiro0jcZ4^p7Nu zA+tv^by46DH8(U*oDgN#$s@_kGfq@hMpO~xmq!*QI9JReM(k5t%uLP#C1wLBHL<)e zKlGCF>^+YyI+36(t0qM#6&>rvb6Qf0NWkPS{W5Md8#}+cME7#a7MF&)VraPPwSR!$ z`j62X<&6ax`3)YXx zc=oLZiev6?(33@Aw{D#||65YHIL zt#t1C3jpPW%2t5)A>hSfaF?TY4&&AazCw8q2N?o(s0#Q1R_3DbRbZf z+nZor2d93r6u#c-RtD4yqdnCX*!e5jv%mLj%dHDS26YpRhk(cg0N`ZvuvwD9ePD46 z^z3}Ub#DoUfFP`lg67h!Ojqbd`3JZm=_uc0y-dBWMU|l}`gVn~)}esCJMD&yT}c|@ zHVN<25dTA*LrBCN8P%`L)`37Hx4N#kyE z3|Q~fd)wZ7&so)%Wi7Z6ZcDcL%l zw}mKkJyV4He5N}=IKDI4KIkG2Id;&W8DQxk*$+Ci$Mc3AKj7;x{Ap>|zjP7)KO5)( z9qe0`+ezc5awWN!ReVbEr4h^LbBH;mtD8FPiHwE8n3 z;o0RnC0#*G7wG4TX$odE3q)plPwUA9M>b*F6Nz^MGbi z(7d))AYk~WzU~9&{Q7OZgrI7z-M4et`a&Ilkq^E? zi6j$JD~vdOB@aA)ZuI2V7%KQl=lQ`vXT@jUOp!t4glJE*Ip=OWRs^z7Rh`DAdw;We zX&!zE*t-7K3;cv#;8pD*fbDwDRa8QTT80s?D50)0XS>)Hi(LA$rRFLw+$yx^ z;YauYc#_4g_o`34-=Su>%KwofuI7=ar&q~8X0zje8~mx*k__GSCKmU1{jd+L9s&51 z2F%lxAhye{u8VC=K@d%M5EWWHplAY-j|KAKx}-2wDw$6H&`Lm@IGd6^RO1QN6T5kr+7;UhM&hTF;#3jP~@o=J>=Oe=aaGJ19C3aVr;b zD<_F8g#Q95xeT{5P@Z{4d5B?fD(}fe=ay|{1pTd?a2!xyuu{|m%3=t()+Loa2DxWv z{QiP+8gb5*QPJo8+@{apOHdCLnlPx>qeXL&mCSU8?8TlmkoRxucZZXvJb-J3!I6A> z49|?GB~FFyc6ut(xYN3yatsMlicE}Cxu6oNp{XT|v)l%bmTZsmKZQF(k?&%(usZAH7&i{we_fwWc9iQ#LV z4~vY5&w)VwAI_ znRo3;E%f=RT=mj)HU!)fU)k{AOv$c3^I%6~uLE66KZD4JTG*&UNZ=q#&Id%_SSOXv zcF%aGOVjNbjcJ@d`*q~|izfLI9e8JURDASF*-*dAze}9R{c@GmvrXx1wLc{Q{txC% z55C^$S588be(63O^@>$Z-3Q$0|Rkey@vVABKcvBeA_Q9sVMeY<02Y*6L2;Pp6vI-0^$?72rq z4UNKc5C;=iE4{_+7T_DKxiU{zMP>HM!OgavLLV;KMDWw;*smg)>z=zqT z2xzVJLgR@Y0zNbnTx#w>Btv!-Jg*nCyw_|4TgCPlN|31ndatFpn^u=|90H8>JSxua zEKd%DZnbLU>XH^NH^m1pWKG1gQk~^5ZI14l!-NkIt)?Ni_hF2vVlRcM&B!MaaPo9Dz>N4d3nYc&;cgFKwI?wl2EK z3n6>00e*F-ZPG)?{C?sQk&=Wcb{w3Zn-w2H^k(?QGCy+mrJ9DpI zF4m|xizR;H5;?G3zn+qUdt8HF6sb8mi;p%^WWheF17X~hzJCU8BlRL6!i-g|jWRbn zA`RW_#uG!c4S^nXp85_B_R|2EV!vLL>K~l%pMLmhkhuQ~SfPJf`|mFJOT&P^tLHy0 z{;Vy)Ur%)XPpkg@1%GAi&iD2FXXSrA{62Pk{wU{A$Q{Lw26wAI>j5HvLMjf_drlS* z2xJL?ba|!djpTJPk7f**jtU2*DahA*kr?+wbPG&LFgZaHcd%Fdo&h>`WP*D2#!D!k zh^QZ6uovN}7=#H5`GPu9A5CVlQ{f+$G`3P zY1H^vyvN9qx*WDrjL{H11zPhL6r3udqm9gNYD2UXu!llspqmZ}N{L4~^F!=AI;Gst i_vZAk1QLQc^jjF2(P;Fdj7*o8#6KJL|35r`IQk#-CSI;*Mq@h7GRAM0M!)6~3RV|ejXkfo)ij)5)slDUJag{Ao~ zjU0Oa{r5jS{^98pCr+FHR`a*!|Hse4bAZZw?_N5hefW?r;2o7ihgA+8Gy^mNhX98G zhn2(q^*M6%*x`5IJM@n7Thwn30S+BL40!k56DQw)@4ch%90nYE=kU8nj;b8{=(ix? zXRf#2Q&rcsagT_>eV5JdQ8O^NzIqd#`}j%av#J-DK1W4H|L%`JbZh8+Vue8FP)}P} zI=Myt{Ps%V?~BC>=)K!7-zfVytL$6Z|DO%uzxq&qXQ*-r@Xn#b@4j_$HrX^x-Xoi@rWx`Ji9iN5cDdm&5XrX(hrq7`6fOs z^nw;qvcP@`7t^>M)CeA!AP|Uc1VZW){PEE(pMooGJyym!Q5LXtd>)fYW(_eZw#z~b z&8SIoVxr*tx|8QNuvDKmmA(Lih z%)7{kijHSxJf8JcpHtyg5$VeZr(ijrCx*uOcZ|CIj~2hwi>iR;-t`h z_RMYvVJ_ME+t92&97(*cGH7FND#qq-%20%Z|by$p+%Liz_#@5qy!U3FR@hu zA`0I7%}OwFyRt$YsW(Bpt@Sp>JVx^(ghPwE=rt$qD|$cDaNMEc$Jej=Eg#vhdA3VF zE%T=nt9e{igjV- zGZ`4E1IOyerH2SPf}Ly;CYekvAt)a?;oIbI0f2XLPgx<}R&`hmo}zuiD(S)G7;VgF zWF8hdGrj~bFTfXE8qWEGhbtW?Ul4MvU|YqM+rZZVyBJKIs>HItAQSHD0D}*qP{|%B z>5!QZZK`gTMOb8zWCjz*KE5ZA?u6cW^(ayL@@e20VLVJK;J{rMn?;}g@nvUoZ$xn0 zi*|M{s;QEPp7enGPx5cys{)*~uZDTCN|w^mfs^Q_W$oFe+@wFc!10UrWsvn5Vd6d(3eswuCQG(W z+x%HBE# z_F*6&1XA@-IIAB3s!e8oQ$UY=BR6TtEf4C()h8xbcxSi*{SZi3n3I#hIdRL2v!}Pt z* zXh^$lz6^3HfAhNqc~;}9e2YFQo2?ymH<^&WMP7wkHVYKMK?!L=?ma+%%#$NL_X~AO zuZIGh=e+y!iic=2dg-k&h|5J5-)Nm$y$F2JSKzEsQdu8{@y4&ypU~6SN*XjW9r!zyTDo0pAdl%-sW473& zEDvwV0L_5u5FrJDCXUq~%bJ~~KRIi!_l<~8K&8M>(o(JsPa`U=&11D;KFp@)2q>wD zn2!1kEbc76U(^F`|7M=bsH_Ydc*P(Nyv??P@gbh+rG$-33WJ6d0~6A$Jp|6X)rk*8cNZFdu8-W+&ZbLW6<0{OIRWL>*aX{o5AY*}gJKx+MIICHIOsX7 z5#}Sl+pqBqi?oS+rb}@+A2qq+Do8x6~aN+eQcF&f&`!gNS^47N&Gjc#sFl7qqLPj0xZk@4Doc#KR zNAIvYbAcSOIN7aXMA+QSibS7BWRUmUMl{02{_eSqaY-*%6)9mjB)VwjBEUHlgsh9; z=I7v#?7$^-XkSS>YC#ysF(3{VFO+V9Q`(P@LH%^M>$;*)-z71!&i)z1>n zrmXcfK`*Z)OZvj(axrag!vu+YV6VW1i5=j+ad|#G$0yhvZ0Go^mkfD*I+~~E-vF=E zr6d?~oJ1g(95!KzM2WvyL&?3$;Z-G>PQr%T1=W~o;O>_UyRn?ST9aX_ur6$vdV!js z9zx3>*VU`jJ@lp_{IbM)l0ywy+0bAlqEQNTg47zhM`rU?p{?8fLbJ?dBGN z^hhz*?!VvC`opU8Y>n~o*{e)Y%g&jcOxRWkE1gl)frWV8 zF8m1Xaj%DXKavtuk$hL+Of;r3Qr4!&kCkyw@=|N6G=+hXQu;Y{VzqCq#6h9Tr=U@K z(s*F}>V4Ld?{J>QGKO#beS-#(f7)U_|&eA(2W zg^D9&M5w4h{D&Xy!t$u)+I`#}{|rJl6zNHod(0DUvsR*o5kMKalx843mf$=Sh@ZDh zvhAzd@$6$#O}!s5d%KaZD2s;j{C&;`qoq$ncl3N{t#|4R&2Cn!M5fE7NB0z9@7nd;8F%=$Ac5_HrJ3R??lW(o5jc zgFKMHisA2{4vWGyT?(tTc(rxV{>9;DmdyXQxW6eU7mvO`T*NTqi!7a@ zOk%sWif@m;>|QHypQ|{hjrDADOZf;hCj>%5#!IFUA_jo{IxNJiUZ6J02%Xe0Kb5ao5S^=PxUCduIo$5t^HtK5H>Dhi*UB=AB2&-wrnX zcJV}NsTj)SVBh$#f}3cQNH5J=o$F~ua((h=ri>(;0Ai6B(} z8_;qX0xwBPg1Z8N%h#(Ws8aQEF|-bqZb;N62d1S(0)%#7&%U$Y-c>dr-mYX|wD5QP zm8_#u>?DdQCFevz;D-8ddL)^m>UCPBi^Qbuern`{&_sNoe&Z9LVoCx=rmII%+-p1Q zPpSwP3a^@iJ*rP!*X#F))t!`pV6hUvm{=$0{cNrJ&r@)#P;Lz_XU)Y9WFBG2Fy#85 zZ)d*s-GIAV@_*@RL||3!7#nTRw#pd9LpyM6bpN-kvg@&n2uoNCLd9Y}s79~GfmpLR zTO1TxaNV;fVh@a5D7#)$4v*VKSP3m8l>N?8hs)H}FMIrpe+=F9wth-V(1W(IE+Vi~ ze&N?8Zp{d!!+MLuIxLD0wBUcbcI7$90w{3#XhXuF@hp+x6&UPZvrmt{&FC8fQQyje z5_kZRm*QSXcT)WahP0c9`kt|-x-oLEYENQ067eRK96XPU2~I~-g7T;Hi3#H&1xtgc zB6sF8wSW26&;h`i#|(XQ70oX8ZEYn} zi;int;KE=VPC_*oopVLSdn<*{tafbOm;4ItrXtS7ReD%Ti|c}ji&e4B8=E|ue|^6t z@9Zd{@ag0Mpm%DJCG?Hud+Xa~ImGfQ+8-TjoM9FGfbatXe_4F(OL>pB@6H<77gV6O7hknUs`FB*J3rHqbucPAHFWB+t}186J0m&=AQOPd91ah_Zl$ zED(d9CD?2Dnm8t{8kY`9B0)4+cBI^TIiwnI%*GqEK8 z*U7Z@x}#u1pN%+XVB_b$UB)%~mPDnk`Swx~3NHmn2A{ro-N0cWZO)PJQVO zA7U^HY>}N>qYe>Keag^d(wCc*mN?!MxO#a-k9K(~T3=FU?f`M<9+Xg<0$kh^M-&S1 z75g4Rw8vZ%*><~dmRKeV`hHH)yFXTbjJ)mFpIi~0%aGEzjMnqXIn}`NjHKKM8F_m} z!NnuG_TYEI3iU(gMk*hB6;vJo1Pu8c^8i3Djo!BCHXf0FGJ9zwo+Y)_Cck1-_z5lX zTk|P)D8v0{l9_a7d5^wk(qbOgaVIb60PvMx!-+8rnZG)-cgYbsXZ<}E$=6g3fM9oum4fqc0ist@5(R-W9hK7B-X%-vWC(jQ>lnde#(`9KKXNPr( zAVTZMWk?<^l(!Puoss1yzjCup&RB#FGEn)%AtsA8qg;a?y&9DIiT-Z&>A`Jh32f}z z?OS4yMraEcnS7k`icDn$vMGA`(~W2Qit6gL2Fbz^p{|_g#m3zA@Hf%;FF7Ex6or9? zwOBO^vqk9n1Q)NKyPYu}kv}aCv8^T)uzpL?&4eAja(x7SElDt(YNM zwd8XmS)8W~2Fj2@Nhl>Or7eu3<7C>UaYyx0@q}^z?P@n6*@&`5(@(w}mzT8j+r@yS z$VS|gn#c7~YbWk;YH&w97}aP~WDYis#8_*u@UV0p98-abLE2s`pBwyIfz~~P8@|*# zOWGmJ!FS1vo#!bj1ShC6(lAZR&zjr%*>5Hx7z+kINz`m`aS}E23p9#fNGshCKuesH zNGoS};v2kP(jTf00QmAw|!Cv-3!276qNZM5gDbZNw|io8!;T9$mD;e}6U4W~tvz5=rRb_{}QT=>52rMZs21 za%%b6&g4}=Zv_GxfKbF&12qL6z6v#GE)1!2PWqOV$Cw}Pycuh{Uyv1WCmJS3 z0=060+xiA0c@=e+MpYVcI7n$^KHW5(*6OFqzhe_JLCUghZt=&)DI7M$l-wZLtd0Iu zI*J@s=F`r|PfJUulQCOp0%=9SO8&lnNLJo*4~c|pdNx2IMnU~8h(%HP)*;F2wF5wT z%>iH^y43enV*;T0Tq z%%jo7lO~NEcgpr0X`CD=vHbtsFGl&gldE%Hizu;1 zQ%w#_asgg(@JgQ?!R2<;0SjwdpzKw3u!1r3utTJsbkK(cA%s^?=eL^Hwf)%Pt z+$5@^n<%4vVtXBXZ2ZUz{$-z@^}HLm#q?nw5**yjO-3zo*TJ4e^G0><94_8&Bu}>` z_NS?JxCelD`VRoPS<$7usxUbhwC1Oy zVXX5YxH?6wihv^}YA(Qe43pB9HZ26KY4?o8@ha}#3cXaR+MS#g5MC}AX4xCjf`lM& zr%SDCGNua(FR<26RAVL7ctp(PcLl=r! zt-bQK$Y+s1(VBcL?@Yk>;SYo7owaAou^HP)32wcTK*Pjy%&UAeei&ky8z5zQvWt1=f*`Hc z#S@62YwhFG4)=+^0iMeEGSpRbrxN0sTB2f~>hyAid=i^oN-;<4*P!R{Lf9X21&JKyJ=OeNJ+F9>z)D6AVM zZAxzlskJK6Rz_^HVrE8vZ?nWOIXtJHv{*x@b*n&;E@AUpy&_7;0xg9JW}AO_0O&rG z8QHfbUe+hQ^@yGep;f3#;2n?nEozA6CjV4eok=*{S-mu^U=xVclCt5^>k0KRQHzNg zEi)?xCl8JHjw$7qhEyYQ(mE8H`A`N=Gc1ikD=Thk8j531}s#k#``T= zUdi-)D3LK<0)`z>ht+&4C>5AMt zhbT594oAn?m9Ok>F$}WiD#O+qqLh|i1wuf*I7rPpl9>ftQI{)YU?O5ENv715U!=X8 zcO_18dzJZE+$?bQ>&O9(r&aszQy}hxGrwE6JOIp>C#V0x@6bYGrp?*)+1|TIjLfg3 z`aU$G#s7mKGIKl;8R4QGOj^vpw*A{BWN2|2MprMRE|+0MT8^{N#U(~R{}fAn7Ti3m zft9jQhO2uFbll=RQuP2Zx6XcX_Ucg_o#ELm4(pGy=91V@?szF9pWF~$#AbJnM(a4; zC<_0Q6B;0nVu(0S2)~hQ!DLgUPHR57bZ%vm_?f{>#w%)O27N;4s$q&zN~=v7Ic#Kl zS?FjCoO#wFAm*&EsZWrLO^u5p^U3sOCm#5d=zF<6C#%t`0}sL+KO)i9TM$6EnA&-y z+olYizvAQ+FT+Aog{27=-;9lLNyo_zDQXK8($4fZb3%4`@;*|_+u~^|CI9|?B~u9dkk)H)&johEVedGtLVvwy3aBB zpgx9vevv`Aw%47#PolH)dX7E~Wd`+-v1X9GN(&*vf^UU{*i!6yREX^#SPKjIXB=88 ziiq#GI$`nrq);=&KwJ#&osj3{kw31kx160l+izJy5- zhff6tg`B0`$y8sfrA|McO;0>AP^1;1*^C5gMu8PZbmu~wvElrUpExGA+fUQy3u=~8 zOTTYYhNLY;{(g?NE{Z$L@Bly}54`Hd zEmpj_C`mc~)k~h`ie|T8-7H1lU=;@bEotWWL+%mt73XviZ4JY{oYx^#{kR1gn)Pa$ zuVNv~E36K?ViB|WpzHu}T^LU$!X)qvkd=#f=>jc(sYvxQ_+DkKnok8fge-}MYDAg{ z{AiRJ7MYe_yX2plXO?B_)b{{9@oyE}%hWU@B_jP3WPi z#==;CEWN=j7?d0=t{Q!Uz>pilV$u1G&?1MJy2{D%1a4lb_7}74FWba*H+sWI*vLy; zRl`lFCbfuO8oBXWDdWD#89rX(9uQC`Y9cnixUB|mLm$_gZ_63|=xte_9hEhzX=%@)uT0{M1&T27TR4x>tBV!T7Mz zlnuTwG>s)ux^*DfI#N`w;A_V9?699`1w1XQ_bcT@&n*N7aMgS>a-I4km1Zp~@EO@~ ziLyVi@$u=7F?Yv>^(Kh4S)y(`8xdq-e@H*!z zyurIw)xV8ar+Yz0qLFE2E(L{QTv|CS;Qi|6f=#+^cY{@DE1e=hxLuFwqT?R>j~v8} zdw@k850Al)@k?Y>c(N}~1>wa4uUsG0{gTcNHdf)ia;v)`EyvVnZ@ zRZt>w|LR0=OWWH6fE&88!h_v2600$nHfuWDjwC2;6Lq3y0IEl z{KmuCeGiue!s}n6G>8H~kT^nm3gcyi3gp#5TOzPR{a?ey)NoS#AjFN7}| za=*)sEXc9`vjZlGNsL%G%pC49W%jhX>-P?mV>(U`+USPT|^sJ0W zuxj?@Wn!l+<79>mRM7Z5zkM~drNG#;4_8y{J|hOv_8~<`^=A{CY-lISkjYm8dyQA9 zDrAHqGrZpF>F4CK;Gs;f2LFy2VJ)X`KM`rcU;FH{)yrt_SF^@H`!Mv&?w)gJIl06j ztUQ``k^J^b{MmA(`{UYhT+D@P6k!7$n!o22=)K4$)y9+weZFEDx3zQoS*S~C3Z;Fa ztE=nKwRY-r-p%#FLDf+q$C@2;j*`!Xx+##V5iP2s7NI|uqy2Hv{$KY5dl22m`!&A+ zP#R6%KLkAP7(D*f24lK&=m@>rAQg%C|E^%Z?qT>S+hUx+BBLSL6l0y41Hk2O%BPweD6N&VV;bN8z z$O<9KDDQX`H+Ysf(jRsk0TuXNd1u!{b)-1Ge1sN1&Il4|Rero0w5M5+lO}jUU1v3x2jl?sBE?@SB$yy+dpi(L?%HyFvV;to$;-ZbaQ@b4? zJ=;3jR5DAZpbIj<-WSJxctT6DODsrg1rrEF+7Nr{p_#Dk?wahM!qFo=&sLW3kz_;e z4P-P@MM4@6WI`R2jMdqXXUY2ou`ZHt%I}Pi$O~fi>JlqK!@y~xB(~V+9Ho#RY7iqE zYbv=d`aMlJWJqHwap?@0LS>%b7%wNH>@NlGeX0!egk#GdgfsD(g?jpl`f43O^+2U7 z;Ow17AkpH9gVRL)grCuU4JWK0g&Z%H;?Z@1h zM@eR|N}FdDk`~Z7%^?N}xj@{?<5&ug4TIo)Bv?b>k$qCLuh3$9Vy{MJ`ExeN2{%HI3_Rl@rml1>RoWqaeE{;C&RZNYQq{P z>&NBG(>TD1<*F{gA*ay>^_g??U-3J8=LMD7=#inf`MKS&5jq8BG>`Cbz$y4zD>CSe z*89QdLVa5#RZk?#SHZy&euz%YL;i!4t8Q^Y1>kxA~vqE9LOLx54p}LRKF|7y-Bwlvm29Yem*gp<0#gcdG$p|wRic@1rK+h>P%n6AvP$l?rQDF}D!P46hR@&7Wkxs(8Tx@E zgfz_SPv;@uON~sMM@P<74=cpb^bpdfENIn?=TWRx!Cpe-&~Hg%?efPh%$aZV^hOqG zl(zh}O0A3^0RZFS;^5$dmp2}OLr#?AKoGC^ z@gB2oW!h1{W%pv83@slyJ6rq$CUTGfVa=imrvGA2Jw2?=iBN;s5@ksc093iK38%q^#LwxH1)`gy^^+E4Zc7D6~*fLS283tpeZ>a$ zQCaxvVP*&1br`sv81npdx#$XUv|x9*FXr0ay(#~bm@Rzew8C`9z8KDVhAF7Sfjdam z2no|nw}dsV{l&PhVOFGGk&bcxheW0QHXky1+po#LxV$CSm@G4F3MHcB4*<7&qQTm& zV_k1oA6(B10>^ewG3e zP^$rhS&%~)770}*S!KQw%X;B8`St=571E~E%WLQm62*{8n(pIgrX1R2q+?wzkt#?l zXCQFmdw6))3VT+WJu@}80`pLdGpZP#6GVyJQ-mx0jHV)c-$To~x|i-Bi(7?14$nl5 zmNL*7_lj;*fyxc5c0)Q7=+>-2s<}Yw5<@pXptTK<(J#fz-&EB<=%`sX-SnO|s>9?{ zbnWe`#DfEJZ02KX_zAmD*UBz6z#TS?E9bFZq$RS^5^-i>Q3);N{{E;*RM#7hg9H3* zD^oo&T4F7$kjJ1L^*$T2KlRz5XYNoB2=kwt5BJ|T->`D?mDa7jFKVkyIb}L2kn-;N zS;l=ynkG|2@<}TS!OD}&IK zpC7|2%0kc7(XQeup}Qj)Bn?9jz89h9;U)p8Sj&C^k$GWY=6!b6aXh3jR$m6Ln`0Th zVvw1#Qdt5@*HJg|(B)AuFxY3plf%G}$hpi_Pg*k~GcrA7u2}+dKtd5BR?*r0ce1LK zraBI1P0z@%wXNMQv~Ok9tGHY%{NbIS077fg=LrZb+BMIQxlMs`(@P!=l`_%|I#ivUT-LY~%{|Xm3zxbn znN5)qW^*L3bxbprap8f_4+x+d47SootdY0GD^)F6zg59QksSG?D zX$5OWKrKX;&ROkE-x{5(C{C)b#}o|FK5Px}V4m?@i?gqfP&jCyIk^Nf!*=gN)?X3{k;R9%J(tD`c^Eimb_5q`87=7azOHJcTJ zcyGWvHts!^d$BIu?-;kdI$F8w?u%kU)Oh}~3&sA{Cx^8q;8W)UP3smzw(7orR|0;x z-7BRQMg77Ey0b>taItIbqlVb8c;QQ7KGcz2cHiEK`XiyC3tzEjSZv+}4YA-g@+*=lo~| zWyxpPb4AqBo=RdaB@J5P15K^_3OsPuT7HS-;w=xyj6HvcoDYW9D$M)UKO_ZRyIOAJ zE3G>^M8))3CHh{gorl)V%cfjqR9i;!1w_Sa+jlu`;vZ+uwpQr0G(fYCpeyE)!#bMA z+gMSzC1cm5-Y9%hu*P`Rb^x%CEL~m!ix6GyBJv+(j{l>_Ih?<8* zse8tbFIM)_vi4r4N@Bk}0BnZQ_a0?ES!%>t901@_(5Ao;}rc{2DE4{d+l5$ zYX7l+UhYI?sdoX;h3B?Cu-_xctd$j5O4*Sa59f)>BrYl{umkuZ$LtvJEB0%4#NEl^ zo#C4ClHC$xA0Itvle@dP&wMpO3=XMOg9{RJc9}7_#AGv7s|tkI^y);%rXY8(CkC6< zsE?pU(@DkB>iZ3=125AVbKQ(v&HY(Qzs?BKp0&5`WVzs5mbl>Kb%`UN43yH0I58-8q->#9=SiZjtcJxVRL{qWM?5 z#gq>%x0EchDjZ{TmWqpcu@Ll*#4JqSl;f9qSi6){GN-;{pj)9;5H&&XfH+1GISGf4 zX~14or`|_pTv{(q52iVqQ4-k`QBy+pnr4G`*5gM_(#@+g1);~B$jV&CHW5$gu@Y%e zfs-S~EZjDtCb#03;J;t54GXE7H^cu>t``>g1>nl%U)T{bS{hU(aOlFdd1#)Gt~G(gSmH3neEEzs_?A0 zdO5v5S~x+IJco(+mzc4vV3Gy2vD(U{NES{20GZx-p0Q7G_- z@w$pKNL1-;`S(LE$1k7IeErKb{zcCz(Z!}G<-%MN>FTSlr5KCInfWV zJNu|^Zizsd(`!?0R`4@8EiW%}tv%%Z-K%>GWEYioj~ik|bRnekr;br@b)f&GsRq zf6;mn_3^-+&=f+!syM2!knr7bYcf4E z6SUE7VHGjCZ;%Pxh6j3e1F5(6;9Wm`S}SK~LDdo}RRp{ByvgUww3xzx0HUt33gA6o zz@e6$$h+gCJeZRN3UrH-3O=vAUxF1B>i5xKulhV>4bpbKvfhUxfGQ4A79b$MrCm}c zz_f4avY(V^Q7o+?Q{uUTZ%FL^NDwf_%GJ{NSB%}1m^rBC2b@;`Z>cEg7%+L*G zqUS{<)By?GZX?eU(o2i^>jZZhcdqY{LLZ^CjFW8 zq#OQG}f?|HQ{1tqcvJTHvIHinl(%`+6)tmcK0n^ zj^B)~x&(+ftEd3H^BgcQYwkP>b4q#3*!!rsb+91?^+wv#-ir-*5b6=ytW3@~@mF3A zDvya@AP`ZPCYrmB%*R)JXnyNKPFZQ*vxp>6O?AiV{*a!^g;5R&&Ly?XBYpvOEL60- zXhC(q8QQa{2J7L1CIUxSDFIJrE0OMVv~VTh+AL8OMDg!BE2C_(kl!itTt*+r#n?>c zT?n})0vqJjAFEF|8^%=3nw^*>&s8F|^U}-LP=t9WoIo)sn^Hlx(Qo1NijV8f37lL{ zD^QJ_JkjsxBlsShQfyp^u6@%Nlp?>BMCNImz*9+>hmmN8ve8N;VNT>eeUrRB;u0M( z?Zp?_JuJM_Xm>YL=Q6ScpnX0nDusnhdGVo3pXUVk5YuN>wmg{c5M_nQ&f$}LW4O!f zDLbL5otjC}v%eG8AA7R(?XTSbCl?NVHERzq^eGNYP}fD5v=pp1#|nn?xhgsXJ|i9` zu6U{YB0|m87jA`6rt*&g+ALvX3~%+L;b4wphE;(>*=FVa@ViR(LjMynL(XGEG`!ki%F7EVpFhGCEjdQ+6zT|n`Vf11y`?gVrUgcRK#STmYS_iHC9pdJQ4 zD;5E*N zx3T}j!0(?%^$(N+_dXuS7tS7rkNm**IEJKJ?zSlqIQuXU$bz%xCYAI>T));J2ejcn z+}Zssh&Td#Qkt98dSMUSEm0QbK=c5e9BVI5jV>)MhQep9h@;`4QV!lgJ@D~w%c`!@<@ zV4TIB$X|}oT;GZdwGVQttXc0XDjpaQZf3)|3_W6l-x^XOv2Z+RHE>!DE1gJ)@uwv} znN3OzGuO8_l~OwL0y{Ku&OB|qJ3oOnEr$cf%t-U>jmYHM)S085pZ+?6e|jO=E9Fc3 zK!a1}nexYj^RjW*-d<4g{z{hC%I;hsXC!TBfY9sUQj$-|Jdg1X39gFzFz-fhM9kge zwga)Ksf^yWQig-SXVEA8=$F+W5v05T3lt`A`E4EPiRi znVf8@swvbkpc zdRDtM;CGw?_=9{(x#yOnjD>*QFlbEbL`WAy%J_5sh34*x@}RHYwF3M`vu=dQ5AC%nagN1}J4?>F7}~cOTi#gP7^0d$8<%(r)EI99+wv z-fF;0GOR`$A~SF$#A;-}8`P4ojJ@YB+!Y2TO!d>ljP(0XsI8gDFslSUoT-cm$2%VT zJG!VR`=o9(wh}jr-RNzwQ5AV-8lOZzz#D8K){zH*rJ7rG)cC;9E!7zrs8I-*fhxe2 zyQ+$voYQsfb+zK&IwdbCwu@dVZ!~l|_I|wnuv2V}C0!ays$(|c@LRUAK?Pj3Eevyl zqE}~IbWt!EV4Dgds_q=&Q6A#H-kU4$bcz8Ibv(nByqfk5i5mw+QrOQ&T{ruK9 z1*OarjQp-&f&YBCNeS4=M!0LvkiMdz=bItpQ=NFW2S^h!A4DPs38Zc(e`p-vSNnQ@ zyRgpXW!&6~^X}7Q;dfTE@aRXG9@s#{MxTk43yB{uNyC|}B3V;N9VDmkj{9`u=t+~) zE80`Oq8SV-P%AJETKA|=)a7m5cjnXe5WS#p?ji$j zn%*9zNi5u&1x`x9L8M~ACx7;_@jh!kwWi^eBD3fTo;RdDwCdPuo&1N3?=;OV1t)|m zajVnH+ZfD-$MT9RyMaNo?>zrMudy6{!~4VFJ-yqvhl`nkN{<}r;C$NyQd7Hu?-e3; zr=K+V$xnshbtcX^eo2XbJa;9&bChgjO>i5ZQx#`}N`{Ca<#m>_eVgTwBRp#PJJw6i zb~jAipf*cGtCIargNmsB2uK_)gucyW@Xk#KiB(kUsxGB1q-B0C>Ph}n<6o#B3RsJ+ z0$0zZJh;23CmHQp?|-}xVy}Mpwb}u|BjL)hf9htds0aM(aQ@L6N$mQX#v9Q3#H6+- zehs)ampJFToP&FwetTY{L7xsI!``3C#x!AX^4YwkqT3x9Ug}1r7TiL zwxz)3b~8Wdgj&%meM9YS#j%Z_zg~O43d{&j$tc?c_Ud=7mpzH4FLF6@~waStNeN0^%ny;^y|V69d?{`Su}p*e`@L8 z<-ef$r@kCb=_wlVcu}u27OYI{f9hCUaX-$n@x)*DdFB9cEhQr0gSRP3KmM0w|7WmL zwet_L+7+B{EVD`;z6}-j#$2~cf>3B&j?3@UH%W6a7_J$&z8*C&n-qHhIHW`*j()4e z6<7y=*N)Rc{V8vCR(=XT?6|$Oe|R7FZ<4>{%bzXo|7HzxBbM33uy>R=mX3X~{p7`5 z68!Bx@I{n|=H`vg3axNQhr_>U>?@1#tLxd-)nP8$1yKp7POd}iuueh?q^k0+sS3y; zO4}1=yfd!faIbcTs?T8bEK?2BWavaSzi*koBfN<(hZJ0^i}2$XM+;P^{3;2^VH;Gh z80Y{;AT2;52V7Kh8E2z)v_%4{>KJ-}P=@``!mJ~{l7RcurJxqDG)J&mpJ-fX;G9ny z4!=?C(Pt&SqAs&apMTyi7;lClfU3&0IG7ORfP;ymKlwCzJ9sw5UGUabFtgd~!|k15 z0wWu%L5{t&;o=mTJNd0s;kw} zkJc?heMhJ!{qR~AML&qxMjRyen>5&b-Z8Y@_%tUrdI}YUQO6>S{H?4jyt&RQH{c9I z8Yw;SnLdjSE|k9Rim*Ww^0G+y(P*FI4@Ugj9%RG}GK9+1bfjCq3P{swv)+a5zR+D= zPmcI0a-Ok=qphh|1S(VJ-N#XO-AZT&B;enTcXNQ>C=bwx{CdvD+y*jM{0`~CZlYaS z0Ex^#$@^wi=;+l{8;y^^!sE}x67)$Py zDv1aP)WWurjy_WE)nCP|{7^x3)2yg;$73$#+tm$*ujBRYz@lSsE^#IEYYF&zg-EOZ z@Rv%t_8(${J>Rr>YHPsqP|@ChNfrq20PyVrpzz-1|C?!4JF__26}3NEr7&@CgN5Si z>qANY*|b`Y$Gvph{CR<3U9i56ix}X3`HT1VD|5f^jv-e~bR_|NXCy@b9=if0h2}CUXJFOwzuat?X1?n7Ytyt3$rC>})nZhI%;A|DG`YN~Nr%z^wTEUmLDMcBDDDt)< zTwiDtl1|mvMHvx@aU^2m@_T>7C;6+^_vOFp*kt`R3*PC}Uv+i<-RwEXFaDpHaNam& z5q`|GiCwwc5Okxn>BjU6F0$U2VJcB=mH^#aER@-yDk6$Tz@HeO#Af3ft)cY~k~mMi z8!)vj>2RF2GDVIWPavc#f8~>Z(>Ju(&w$92)uxjtltB^oq@i8o&b`)e|J!E&2VeiX zoJ;!gAFTd&$PPQsuowH^_{T0<9!=>El2*K^UmE#4GVJd(^%n~HPoB=-t?`e2`Tr&> zPn})8ceXLL(F$y|SWHqbzvzFp_vLX-UfbGOkG9n#7D22sSvUomMJ5>nwgs^oND)G0 zt{_7gg3Lo0Y&|N2Kq)c=BvH@+34<6yATgj72%`}~!Vm&VWC{diNFYGs_uAg0R_(p_ z`{Um4{(j$uKiGR^zdL&`-o4(v*ZZtz?a8o@-_MkDvLbUFdxT&o=a|iE_N|-t-wl9z zVQ0HKIw%zvpiqE(1J{({oG`SArhD#}*jo2}N?d#qJfd8A%|E!QMDi2VXdT#bvDc@x zaMrldC|y0)m0R!)d(_l*%LJV^k8l>R)rL+nWH0>;{?E<&uUj2F0Eu(UQ*e@XV?;*O z;U2XNw8-m2ZR{yGZNN*Q2T-}z6mvJ8MtERDtn}!BQO1_-!F(+ut8f}`sFa7SvxKzn z)s2E2!V>!RP-!P`7du$Kc!F?tOs)WUKBKY0S;z!{nbHunMU7bjAjez;r;Ta4v$DV+ zA6wV>5UbG!0|npMtYelu3f06&`CX^walczY7U_!073$g97JoG@tDgnpM&Y@Y*Q+P7%n7WYjP6l&f zL5DI8Rg~mfp;GyBwE z%PUhm?_BR0Tum}pk0gdDo&!MDdvk0R6A9B-ks#U7twOGIH_O;{=?Nk!8vIHs;2Ki4 zY){@5+RyBvyl@G-I#w|CjahELOIIs4sHthSs}W#RNY+cPJ(5vkG_MuJb7$eH-j=o| zFBic*A~jaHrjBPd>0bFw&)wiUSpL}8MV^}-6U3cxKjEx3yEob+E8N^{KpTao z?=3+L24D)&8a*N&_s%ZKnjg-SeY)YlMJ437*ph0 zH)cur5dgo)6K>T&mhaq7|8N%t+$y5Rej$RK z9LvLL*pDfcORLR?_Ep$B+X?(FlFfEvk8MOL|8g`yygTKjtqdpF)Sd*h;)jC*7I`hF z6B1Waz-%(HaXLLb%%d)%Hmk*b-yS3Xx_$)lCs{#QnHWJ+23g?@HP@%m$73&UoF8_D ziFH$)Yqx8V@vcLHk)ovGLLRMa_sk4@qq!JATuesXPAf)OXJ;l9=PWahEna$m)&51@ z{Lobb7A{}9aJOROyd#KtVH`V}(tEVRf3@v?cv#$S^SkjPrM}=@ZL$8f5kBUG<)1e; zdhoMnoO@C?GVTfRTk9)xW&5o4-3z>?CT1Wd1x{59TTT$F27Jnr>LI)#6JmNm;Iw0UeS=CxT!Pl0=Q7Nkgj8*v_h-^Zp&s_cCF zuJ+%Vx?_wVoF6K$PT*6bM8P;!Yb{v~B;Vuv!j4h0ExFW;_awBL)JfM7j@weKGSK^` z@}Qf!hK8Q=8F^qjW-wgyjD<$<5LPv_1xrUi2-3pj`?$=zy3(DSVZePO9oN)Y1+`p~ z_;b2j@L;kN!-3wUG80Su`|xz?^$>;J9+8C)Xb{m}d^tnW_qp##w!{+$7k@EdElDA! z^sQb)7apBMT~E48(Wj;3jAkZ$yOn|aRRlW1i;Y{Yc{~`5;=huzHgcU`pF$>f=73U# z*{hH{dpuRc4oxL~YG-Oruxh{;5pe$DL4G z#EZ34o(r#a=C0*aicHd~}ua9|R@)To~;5%!U4F&LMBo0@_8AA7a~NdXtoFXv@(V9+Il^$92wY^Owu+P}>k@-7{-H zl={wZ?ewEi(TI-8%~w*|k--Fw3kx`nmf~}c5y#gOo}y%ivf%(n>4r@oL;W&11q*k- z{ArsNiowgWyeaTUjQcbDr^ctU zx&9M_{*~+1OVYg-n+eb8hq7p8>Kto7his7c#kVICf}QE@ zkLzS;JF59#&O@3-TR$ySb01bf8xM80)$|$m(l$4|Z7{bC=1x9j!8po5xtF)%w9lJa&=!r9lC!dX&2oz+5t_ey21Dhoa zCtz4BejEACtZ5KpcRkm2fGcYrfIl8Tu)ezvHns%2Krcew_)Wu|eMp^K_l%fisG@az zLc0d7jkV78NZ=)F?s#}%m2cly-$)@Ck1Rg#q@l9;8wIPl9~so>w_I}SueWnV6x7N6{2s+lw2dL=bl zSAKsGJ()CMH@PsKivA|vi73g9!H!d0Kw^iRRYPbs*hSsc^2Il^1S)0LXx=Zun?%4Xyf<@3tVwPhVIswgkQtp#B`trZ(; z6d*dGMRhcOAEm_)$|(D&`c|`2DdN@5h~_XwLYOzS1L-8^Kh5h z_Vh$f93KZ7a&PaudapgwEzbER*>t2a)?bj|XBNxj*DUyT)!I8v7UJTjCtSlX)?Ex~ zs{#if7jnrNE)(g#6W5MEa8bJ&2}hrhcmBA3q$Qo-@+`hX@Tl_0a0MWa|BzD_zq;~cUozvYFCD=w(EAC1R+ZK}B_q3<3m zsDhJO`q=uO`H*hKrRN3qwt#O}oxDivam4@CAev%zkYoCx} zL(RP%BjzD5aBJ(5fz__N7NtpH2hIT$0S+V|vZcxX#`YG3g?f7B z0&2}SZJKWN{f-GBg7MM^<9JW-H}&Zeve!IAW3MA&u5v2mh2wBUo0nE4zHMTD0dpv1 zM{rs7qskY|3Vum)?dMf9Oh?;z#g&65L0N%Kueaj|Km<$gp(g`_b<5ry6jlvmzC8O#2HT?Nv0^^^Qfemh-ye+BHUn8jaOA$*ycoUJ@XGetrxmyo zb;=C}9$uex#Tg9HKWQ$cmj<+n)bf@fv!<~2{sz4=`;CfXRLrz;Z_^?UM*(7%vjQdp zepL-NucyH?PG&|hNA%rF`9KVyHWuIrTPQ@&M&OI3$u+A!>VvW5?d#L zQfXp|o)cyhObM_Z9YPl{S2xX!S`)f>S=wbHqFqShS^UX<4m&7*WHX!57_|l;p&EMF z#A{NN$pE9Mvg^)EM^q-&wCw~GN=T3!1eSV}BDWEsz$uztShMi+?>F@yADk%c7bJp< zrpz*;MpK(;=(LH7^=Gn&KbY@Z!9+(#U78Pm*tB|>2nmJ0c4&fze~C!~Q6q^p^x0w$XB@S}wS!ZO(#YX0qLeJh;oV8VV}D_N<4K94xQ%s{B62lP58{zwig zYAz`~4@Ff@4Y$(Dn<>OL1H%{DI-)Y-w=Fdb(mCcs?*1IU_BXXfVRNQ4MZr`^R9lh7 zX7Z-M|2PU{T4sOjdY7@%qrBWk<0Jf+O)I_R0Fk_;U9H#hB?aJH0Df%%R(6?*ov{t| zU|kBsN*#qAc^M~+0cZ^^na&&j@i>6kn;t?G`eke#4&6G48S%qjdOPQjl(s93jhM(& z83zXDHPY=kO6GK*Sm^8iEAeUP3C=B%cB8;!+RIedssd3p%1L30ikgr3P5SQEyl zfaw<&DDz9c&t4?=ouwJ)fr>XNpmVstBr<|D)s$=VX(GS z*Lv;xp$GdHEC~qTG>oyq5|LxjbBrz9TB~~Zr~Z?pUDVl-s$#OgM^awq$$?=UCMJL- zfnwWjZ{m%{XcPn=M}gOH9HE8_U|rdLKyZNGiG39x(Z;`tt}#gtmv6UuI}<(JfsIXX zQ5QuenVe{lBRyE+C56hlNdYR>wMB!L+nZ37fL5^}k9W7rA-!eL1&^baWxF{wB zj}^4xTehE01CoNgz%}s;muX=|P|j>_6N$P|xA6<=4P$xbo;s_iCTmod_1SGdN`0PM zH~}s3E#sHh*h2#X;|LLzbM|bbb*-sH0#p&a6?}BpUXkU%>Jv^A)%g0CS#xHQ4xTvQ zPJ82U+GNs8s`{*lV5wd=f(aViMXp0+&o83hwi{g&Q3#Z2XzrLOkIczjW+E42|%zL(= zE9-3=@6*w2qspZ|&Bf zi2jvc1CT2hV|2D|HSbcXu&1Rd0%s4NklQxPcJ_mG!#*9z`t=@nt9`mp@Ok!@|KCTZ zC12|QoOUqjh>virUpN+GmvKnUjEQj9mIec!U`B z6OJ3>9|C#|rd`-@W15QTb?CvagtKkfnqwvny!I6iBOoiWBoF+v@JMdIaDXUd1~Xg& z_*1R+ckt-H#-;I-%CWlF40`4wAw}W(Nm5={zRkMPV4oP?Xh4mPH5ydGS}0{NXAr1$ zv#+Faa$#of8@i65RbO}v_XRGXpktT$-;q|7<)`3V3MvSi_oUo~lcN^}+>|GwjOkS(bJdkI!}7pAww)jXOF&3XCd>3bk-!`CFJhdRSAD9b4Th z`8L*SV*m^97ec>`f(*R~imz|AqaZMz%cn&$GKx0gUwm@KBIS;fi)yqk`x@2}l;_%C zXFf_RnoNZ56LVJ~q#)|aleMvqtYtVqgPiXPJHB3)%I&qRJz-vyoL4^UV!0D@IWsMI z(SYw{lYA=Xq0}~To8$`<$=~VxV+_}P{g*$HUizoN^NT((41W^*9q%QKuX`C`9awq6 zMX(r9tn#UvFg@SSOXYxa%Hf?oo*sO|?M}pJ#J}q#;!}_b12C05mzKV)D+hvF?vB#? z7MbIb+qH0J>*a;qUPV10^*YOH`NHSlZ(M7xe_~a>aNYjoXi{eNnFILN__?wo?5RV`ZjN(+uU(+duQquQ+^n^U$SJ<2 zoaj7Q@cc+NujdfE->8=O^eh(<<`F-wf@~X6MIPy3RMP{{6=-ku@$b(8Rwo7FXA`&J zlmI+d=1r3{!bW(SkyVTH$=$`UPxa~96;5_@XgulbifL`1X-64Q^L9PX0zLik_-Dh~ zx9-wU!E|H1M-c|ph!&e4-<(@zY}ohBv#s*CeafSUAb(_7Qyl@L0jlF)21^8X z>*Z0%lf$bwzeuhU(i-*{ZZcIS5(sSNAtU;tb4nT+1jO=P{N~9jTSjr?*6-KqslbYz z#Nx|9X!D*vzC}QPs}?aTmr#*5?O8X6TrX_`@;=Q$`y0Ab=UM8tk@9O#Px3Z_fldMQ z${J}>Le<;$4G(26%%}rGJI$Ex&b5=z)p7;}KNi`9+ zz-cmAVho7{+IRkrOQ9p|4RWuBeVwM;j|G;XNd2w#Ucu z^x|caw{>Uo6{Oe?VC73{S?d|WiM_1XK4*<(YV&=2M$Ppwh6jrpq(R=uNY(U!7pQM8 ztd`Wzd%iRw?z+FYUOh2X^8z@o=ke zs@w>6W9(AR?2eT0CCTDRdfE~cB{$J$Fqw{<`bQD@g%%3dE?-gzKN6r`D1|)4NFL)>1Zw|U+(zVKyy&Z=pIEW3+&PD@4nF;eE#u9IT29mr$`8xMd>5}%59 z{t|rn^SASm`Yd!@m{*JBje^W)s3;&2r5&vuKQnS z$PoUKA>(w%%GjUO{kvY?IryGc@JYHAx`?bwzM~#HUbis0hS#3LeHQ|$-$PxD&K|gQ z?u{n@varMO!1@XHx}kM_x4r+lmfv=cKSGJIZvO#l;8-GUprxq(3^cZXVdnKTJ7G9Z0ldP`yc*O>klhmky1unsEaXny#uK45Wt(+YUJ2_ zc5$Wr^PtGxrT~F1@(%*t3oaXPm7_-g$Q%3ryA#ldBY96E*W>+sd)Tuc2}9Qy^^R(8 zz1Qx&Y8Ua%uF5v-?Pe?b`BM1wvQ$Xxd(Gdk{>@}@^YkEfp+iK@J@R(tsE+D7ocDj% z4yTX5qnr4}6YqB0We!^*Uc2!UQTH$L3TjrS5%r`TG*!T>j<+(o^?FGaoTp?_TNW_QqbQ zlHQsT^Ox(5DhD_5WA82;-QNbLF&S5>O7TZr~? z#6=ZKoqlKBQvW0D_?^{q)5_ri2UDlV?a4aqIdQi8Zw#6h0(L>2$BrSnWSIMH6*mfb zRK)x!k><`~%C<&wKqb#E;h`*H4aIl23)A-;t@}|YkZq-{v^UCwU~g=1U?hz8S4U3x zYh(>a9bv6mNwXNFt1-3NG40TE%op(0=WQnZVan?SA;mb2+QHOXw7hXm~$L=gbX{y7JM| z@gzf8d*jjc1ZJPC(hXt!6mr|sL6SPPbZ#wX@UwbwLQP&huF1Y*e(DIf z2&o=4oi=qoxeh@&C#)W&LU}W#nmE3r3^Y=P?c8c(16~u_d|QXA3pYN(T$rBpq?S~` z>|O4cniD6SY*vDbJ)22*SdGNFXPLi&eZ(j|x)MB4J9#d(l+R8$31)aYDiLk^5ODqq z_~CK$6Qfqx1_UCMQqS&clF80AhSEe`o2n^zMdpH&7W&bE(H_}Y7|F=qNyTux=}yjE zWKgru&EhD5UQB#2R<(uKHGF(Xf#k}F);Aje@VU*2FCGPB|) zEG9WDA-}|HsyI1=kda$H*_Ri@C##{jg}5|{y`$m2&u_hZ6G}<_H*8`8-2CO6P~=#T z*&?cW65jO&Q*Og6qgj6Xa{2ulQnZ20#6(hTim$EnLdZPM*xtzkGJ5bFGzbRAtETJp zc|`lD9xty}WWbcdJf|1t&-T@1^hYrjE;kWF=`Pof(ZL#!k2_27Fe5d4ddbP-G@nyV963 zcd>cfbx*xa4GT3$CqsuBpe!)zi>$Wyh%P1jAIGE0(N8Rpn4$(KZguOXdr>~Li?FOo ztr)LS)w=-1@|uXSs+y%f$0yV%g-iIm1+3cQGalU>(__&^diK?-J~|T_GzlXdT%Jt)$K06fPa3{$@aj-x}{(W6;dt>XwY%?X4L`AykvL>$qi~wkCpS?2)1%EI>R9@JsWvs#avCQlmroO7460 zO&;v&OOaL3*IIzO9C=KDx!`zHK3X_+ry}*t%v-ZDFAaj4Jmr|sXb%d^jgkj7G=w@0 z_w;lTt6FQ3How{Iynf=Hd+dLNoqK0IZ;Jm7PmVX=^|tWtWB31&Pvz}k{#5$k{p!2w z_}~5NyW05wdcXRvBK}p@EPUe)3O@GsJep@>PF|!yWT}V_DMdK*3Y8U`t*!GWLymF zulB-%{MfnP|Ex`05(EJ6Lzf;qeyo?bvYpVHO~BD+`n#jeVghHRd}CE9R?Gjo;=I;s z*CIHf8`>5bkrmL!LUBo*h7)jo zdoA0)a0*Wx6+CcKw(3N=Fz%cl$mShLe)l+;!6sjrp@f}bsMpj#pKz-)j`uI}QBP5I zeE5;0<<3}ggI8sMdu{amrm%{~bd;Mq?>SE>0mnwJ5toK#MZOIIHrs9ndLD)sVFL!J z4$R&I9;H6Tg$JAOS7Kg3Ep5ZC^cB}$HZ%us!fZI_lJi+nb7s!8A((Txr%G>)1$_PP z=~|x!J`ogJ-lS$Ijj3Zq7Zy#Zb=r?4Ma7rhx4ggm-tEDD`Iu{lCl^P^=v=uaR(Bl) z8%`arK`%x&xB!%iq2grCOnq2uXN_+m$-X1wX8a6VD?4l3v5)HS523Wq^^7m`wSb%u zoMLAo)3d9z$d`lq^awU!^>%|ngqrMbbzyBWYzTOJjTJ+Yxj=LPY|lZE+Cp3^qyD-l z@rt*2+7bWTi||S8fSnw@sABz52-7&p!sa);p;Ip*EgO;)8=USF&~yp6_L5l8+2C#C-joW$2CtyX3E9m;y%**WTVGiE(R1SA{V%JBA;nL@{T z!?8u0>F`v5fK%1-#Pz2}ihGEqzHsx<3Swq9L~aGZCav{CAzA)NzyHWRm^QeoxTm}H z!mN2-1tl{FvOgRk6J2X_rUPiC^ZBFQqe@EQ8I7S{Ort|_*e7*9X*i0}nvGXk3t_PZ zOqZ#*-tS}|)oW}628SD18ROwqbGt_B0{fjq-@=e4&;1#Oq=a9ElwI&+R?L_kR6shS z$9MlU98@WR*47oS*eTxDckEXlNvDGDa2G7itryLcymq~kQg*8bC(N!msVI~-O~gmK z|Bbf$N8I_SOj6hj2ldd+5f?w}fJ}g#d%x2{&&H6*1$j_DqKbi3=2IGQd@Lo})|uXP zl%*^CSo1X&>95eRuWyF$cx?PPPbX?|ZZ*2;vswP5qiMC9GQCdAs{U#>TEQ<1<=F0Y zr$PTCBS?40feQS5vR3xjFf9Q? z`P@We|C3?7qA>sn)^D$)zPxAXdxoLIVG4?-;ANlg9_;-Cla#HJWwHMJE24?s?Z|V) zrnM_<*F!`ZN!qob__`~yFE)8w;^uiF*xhJPb!ljb_nAO)=*=_HNhQv$z0o3bCd3#z z4q6$y8R`9x;XZKq4?7Nh^v<^e+tBvmf|C?N_oP(2BwtQ54MG!PAx_VNQOmu~;f71g z4N|>9Gn5|~Niid1BTxPoS2Zb!;5#V;InuJMwX^U_nsCdN%v*CT_(BFutG&gW!V>(# zxa3D@F}^O{8+Lwfox!b@=9tCIX6rB^iq>&dosb8`=v`Fzeo|TU7&Ie)3KQdhe5)EX z(9L*B-0c)>DyyPCDzraP?c@PzJGx6KJ<(@u#@&AIVHf7>n?>4%>!oK;-IQcBoGgPJ zXkhJ-v0hJ5Z+#^toVo#CH6?}E9dbz~-HBKG^oQTkMAeg+8}g5SKxeK=>srE-RDU#+#G863`6hy#g5;}I8 z`ROSWYrc}w`l&R2O?$0>eD-TZ(ZUJ6(i|@lD?EiyRar3i*GO9>7KLqMd_lE2{Xm2k zS0f0~69(ew#Z7k(J9p@Rk^wtY?9yvs7R~!Ihc0XS5@F|(nA-}0L%{CRz9`ld#t6s| zE=ApSMM*QHXq|h}H(_A`USkc8u~3;j5PuwSI>YQGo~+*>^BRhwlN) z`_L-h0Slv@Q2o*J8zElc5}v)cpRxYbQYozsgEn)uaIIzQuM?^L7wRf9&) zImuckbYW}z_VGBg!M?+V>4MEj`q(*&H;-|cyh}smGi(fH5^Uue z#jVP~HM5)c+TJ}}@zr9F6>B7$7O4M8ro{0+0@`lU##vKGs@0Z9`(i8w*snHA*px-u zaZjb7{jKx>Y^3fG+R6$Uzx2txW>gSJ-7m&{m>eUwLNjwKF;(LTvg>E5Iv0cW|{Ei+c?uEq%MNQqayL255*i`ME6p9H68r1HkzTfQ0Ds{|4OEWSttE*)W$_&Zi>qDGwMuxfA|GZuQkHG3*qQzG zNqb#{9;aWsi^^@v&5LQm#F&plI_hROtwU#_ZE@y1QP~mbx%{QT^cEuRa9K)TsDhrq zk-eb@3&;fhkTHi-tGtfQ?sYt%LfxPt$f3o zuFV|05vu%)AaL4w>`OO4*+4)y@t_`Lna{w_yF9oFPq!S`Sv%f$RC%Kon5G^DJmT zK=CXi2nMt2;b{8m{I1#TjI6WgkaI!P3|U{VM}VJ9kCPE;y+85H4~1!I0CO_(Y0*_W zJE1z#EBPnv1rPLQfk9vqpmObYWFq0_{`K#MI|w;;UTt%+ff%l%GgKv~W9CAXab2xv zF{?g(DGa=_pX=vY3SU#JZcWU(vubCX72q(YP<*I%qAflrCRI|!P~5_|r(CRBmE1Kt z9Pne9M?zEEIFOk|UYuiL)t-l`P`eKr;EcEHr7;_{O7)s;l732Hg+j@m-*xK>y0A$1;&Vl=_)Zj z$$k1*Pp_GRN{pkyu;IxPV>>JObXwvosUstPjoJ3IZVMXL{8b(|ZFB4iGUXAdYts%P zDUdk>B!SqpDk2v||BfrdX}3{i!6I>R{@`haW2-$*HI9l&;^KNq(RqtGzJl&-*#6?A zuR^u!dlL#G+6C#&mM#$UvX?-v{FD%L?=_rtD@VDPFnj!Pc>+H!E9r+>%ou<& zIItJbDVMyGdI+TT+c_f)CEdLa)tc1^=#zcYlnr2uu>XcFYJQC^^8W){w6O_6j1_zX zF1sV9q>%O*|Gfg;mAG?%7a2%1OMXfZ3wte%54C2_?Z}$LY+$ z+80Z+pewbn(M6#QU(R$jD4S!ReF`?E%6gdLXicNy-6kwolwL{gv#1x6f+YF3-Bz!i zb_F%OG-1g>GE~JQQ{iuECqoQMgKA-VqM=S%I%pI+r|CTfr2e0St;r!@R>_l@tqj&;2dwr2fowuPCv`&HMlx;JK?>j?Q!^VOHli$^{86n^yuX6Tj_a(0iH; zO{Fu+=?9CNU!#p;|3Djg&sqezQJ?AXjHkRYb;JxGN-nHOT`f%nQ&hfg;!t7-QwfC& zXh4#7_m?ZnqjNe#jd4RRTgoP&V!0$fKHMhpm#S$@s@GB2l&dY3UBh!~&!{u*-V(OC z)-%#Gz+uVZa1erHX`+%JQ)k*=iO*8 zTVsV|4MLd8-(%77qVqm|3Fadf$#A^G({N1+SWrog!R(IE=-v_i#nZVQYhbg9}~z z2vF)H6a1J6z(p0})PW3-7&-FV#c=)b=iwoPv{<)Mi1gFXx+y8PEzU6HsfSI@c1l4@ z6(}zEnw#(`+YIErmt>Sd^#agBCOq!w)QxAm)++38^PRri@(h?k-!{2MwBNfFjVZl% zsW#!th%(d2x{cMG#*+<1Is+t|2V6I_Kijnx;(1%PC)86~V{Fsgc0^!!E2VLDd?Ejp w)FYkkcOCM|-BZ(#8o<+$jRbJGNT~?OGX)@j;20e{=@TED%m42(l~=?62PjkxqyPW_ literal 0 HcmV?d00001 diff --git a/tutorials/videos/robot-marbles-part-3/robot-marbles-part-3.ipynb b/tutorials/videos/robot-marbles-part-3/robot-marbles-part-3.ipynb new file mode 100644 index 0000000..21bfa41 --- /dev/null +++ b/tutorials/videos/robot-marbles-part-3/robot-marbles-part-3.ipynb @@ -0,0 +1,257 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# cadCAD Template: Robot and the Marbles - Part 3\n", + "\n", + "![](images/Overview.jpeg)\n", + "![](images/Mech1.jpeg)\n", + "\n", + "\n", + "### Asynchronous Subsystems\n", + "We have defined that the robots operate simultaneously on the boxes of marbles. But it is often the case that agents within a system operate asynchronously, each having their own operation frequencies or conditions.\n", + "\n", + "Suppose that instead of acting simultaneously, the robots in our examples operated in the following manner:\n", + "\n", + "* Robot 1: acts once every 2 timesteps\n", + "* Robot 2: acts once every 3 timesteps\n", + "\n", + "One way to simulate the system with this change is to introduce a check of the current timestep before the robots act, with the definition of separate policy functions for each robot arm." + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "# import libraries\n", + "import pandas as pd\n", + "import numpy as np\n", + "import matplotlib \n", + "from cadCAD.engine import ExecutionMode, ExecutionContext, Executor\n", + "import config\n", + "from cadCAD import configs\n", + "import matplotlib.pyplot as plt\n", + "\n", + "%matplotlib inline\n", + "\n", + "exec_mode = ExecutionMode()" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "single_proc: []\n", + "[]\n" + ] + }, + { + "data": { + "text/html": [ + "

\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
box_Abox_B
runtimestepsubstep
100100
11100
2191
3182
4173
5173
6155
7155
8155
9155
10155
\n", + "
" + ], + "text/plain": [ + " box_A box_B\n", + "run timestep substep \n", + "1 0 0 10 0\n", + " 1 1 10 0\n", + " 2 1 9 1\n", + " 3 1 8 2\n", + " 4 1 7 3\n", + " 5 1 7 3\n", + " 6 1 5 5\n", + " 7 1 5 5\n", + " 8 1 5 5\n", + " 9 1 5 5\n", + " 10 1 5 5" + ] + }, + "execution_count": 2, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# Run Cad^2\n", + "\n", + "first_config = configs # only contains config1\n", + "single_proc_ctx = ExecutionContext(context=exec_mode.single_proc)\n", + "run = Executor(exec_context=single_proc_ctx, configs=first_config)\n", + "\n", + "raw_result, tensor_field = run.execute()\n", + "df = pd.DataFrame(raw_result)\n", + "df.set_index(['run', 'timestep', 'substep'])" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAXcAAAEGCAYAAACevtWaAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADh0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uMy4xLjEsIGh0dHA6Ly9tYXRwbG90bGliLm9yZy8QZhcZAAAgAElEQVR4nO3deZzN9RfH8deZMYxlsidbRmKSbWxRQhJZI8ryk5J+ypIQvzaVSgu/smStlFZkD0PWLC1S2deRMpiIrIMMZub8/rhXP8ky5t653+/cOc/HYx5z7517v9/3XOPMnc/9fs8RVcUYY0xwCXE6gDHGGP+z4m6MMUHIirsxxgQhK+7GGBOErLgbY0wQyhLIneXJk0dvvPHGQO7yH06ePEnOnDkdzeCWHG7I4JYcbsjglhxuyOCWHG7IALB69eqDqlrwqh6kqgH7KFOmjDpt6dKlTkdQVXfkcEMGVXfkcEMGVXfkcEMGVXfkcEMGVVXgJ73KemvLMsYYE4SsuBtjTBCy4m6MMUEooG+oGmPMpZw9e5b4+HgSExMByJ07N1u3bnU0U6AzhIeHU6xYMcLCwnzelhV3Y4wrxMfHExERQWRkJCLC8ePHiYiIcDRTIDOoKocOHSI+Pp6SJUv6vL0rLsuIyHgROSAim867LZ+ILBKRn72f8/qcxBiTqSUmJpI/f35ExOkojhAR8ufP/9dfLr5KzZr7R0CjC257BliiqqWBJd7rxhjjk8xa2M/x5/d/xWUZVV0hIpEX3NwCuMN7+WNgGfD0lbaVfPAoG158+6oC+tuJI4dIqn4LWXLmcDSHMcakJ9FU9HP3FvcYVS3vvX5UVfN4Lwtw5Nz1izz2UeBRgJJkq/qqRPojd9qpEnptXq7peh/hd1R17JXCiRMnyJUrlyP7dlMGt+RwQwa35HAqQ+7cuTn/DPbk5GRCQ0MDnuN8TmTYsWMHx44d+9tt9erVW62q1a5qQ6k50wmIBDadd/3oBV8/kprtuOEM1fkjxum86BY6gTK6uF5HPbIx1pEcbjjzzQ0ZVN2Rww0ZVN2Rw6kMW7Zs+dv1hISEgGfYuXOnlitXLt0yrF27VgH98ssvL3mfC58H1cCeobpfRAoDeD8fSON2Ai5bhRu5+6fpVB8zgCPrY/kyuiWre7/GmaMJTkczxgS5SZMmcfvttzNp0qR031daD4WcDTwEDPJ+nuW3RAEQEhpK6W7/4vo2jVn//HBiR3xK3MQYogf15YZOrZAQO7fLGCet7v0aB1dvIjTUf0dr542+iarD+1/xfklJSXTo0IE1a9YQFRXFxIkTWblyJf369SMpKYnq1aszduxYEhMTueWWW5g9ezZRUVG0b9+eO++8ky5dulx0u6rK1KlTWbRoEbVr1yYxMZHw8HC/fX8XSs2hkJOAlUCUiMSLyCN4inoDEfkZuMt7PcPJlj8vt4x9mUY/TSeidAlWPdKfhbe25eAPG5yOZoxxSGxsLN27d2fr1q1EREQwdOhQOnXqxOTJk9m4cSNJSUmMHTuW3LlzM2rUKDp16sTnn3/OkSNHLlnYAb777jtKlixJqVKluOOOO5g7d266fh+pOVqm/SW+VN/PWRyTr0o5GnwzibjPZrH2qbdYWON+bujcmug3+hJ+bX6n4xmT6VQd3t+xk5iKFy9OrVq1AGjbti1DhgyhZMmSlClTBoCHHnqI0aNH07t3bxo0aMDUqVPp0aMH69evv+x2J02aRLt27QBo164dn3zyCa1bt06378PWH7xEhJIdW9I8dj5l+3Vm5yezmFPmbmJHfEJKUpLT8YwxAXLhEXR58lz0QEAAUlJS2Lp1Kzly5ODIkSOXvF9ycjLTp0/nlVdeITIykp49ezJ//nyOHz/ut9wXsuJ+gbBrclH5zadpsnE2+WtUYnWv1/iy8r3sX7bK6WjGmADYvXs3K1euBGDq1KlUq1aNuLg4duzYAcCnn35K3bp1ARg2bBhly5Zl4sSJPPzww5w9e/ai21yyZAkVK1Zkz549xMXFsWvXLlq3bs3MmTPT7fuw4n4JuW8qRb3571N75miSTpxkSb0H+aZtb07u2ed0NGNMOoqKimL06NGULVuWo0eP0qdPHz788EPuv/9+KlSoQEhICF27diU2Npb333+fIUOGULt2berUqcOrr7560W1OmjSJe++992+3tW7dOl2PmrHGYZchIhRveReF776drf99ny2D3uO3mGWUe+4xyvbtTGh4NqcjGmP8KDIykm3btv11/fjx4+TIkYP69euzdu3av903Kirqbx0jhw4desntfvjhh/+47Z577uGee+7xQ+qLs1fuqZAlezgVBjxO063zKNKoNhueH87c8s34LWap09GMMeairLhfhVyRxag9fST1Fo4nJCwLy5t3ZVnTR0n4Oc7paMYYl6hRowbR0dF/+9i4cWPAc9iyTBoUblCLxutnsX3kZ2x8eRTzyjfjpicfplz/roTlcn5SujHGOatWuePgC3vlnkahWbNStm9nmsfOp0S7pmwZ9B4xNzUmblLMuX47xhjjGCvuPspe+Fpu/XgwDb6dRHihAnz3r74suaMjRzZsu/KDjTEmnVhx95OCt1Xh7h+mUv2dlzm2+WfmV76Xn3oO5MyRY1d+sDHG+JkVdz8KCQ2l9GPtaLZ9ATd2bcfPYyYyp8zd7Bg3hZTkZKfjGWMyEZ+Ku4j0EpFNIrJZRHr7K1RGly1fHqqPHkCj1TO45qYb+OHRF1hY434Ofr/O6WjGmMuIi4ujfPny6bLtyMhIKlSoQHR0NBUqVGDWrPRtppvm4i4i5YEuwC1AJaCZiNx4+UdlLnmjy3LXigncNuEtTu09wMJb27Ky0zOc+v0Pp6MZYxywdOlS1q1bx7Rp03jiiSfSdV++HApZFlilqn8CiMhyoBXwX38ECxYiQuS/mlO0eT02vTqW2GEfEz9zEdk7NCKlVi1CwsKcjmiM6/SeMozVu7b6dcRddLEyDG/T54r3S69+7udLSEggb968/vi2LilVM1Qv+kCRsniGdNwKnAKW4BkF1fOC+/01Q7VgwYJVp0yZ4lNgXzk9ozJp9+8cGz2F0z9sJkuJwuTu2ZZsVcs6ksXp58JNOdyQwS053DBD9enZY9jw2w6/zjiuUKQUg+/pftn77Nq1iwoVKrBw4UJq1qxJt27dKFmyJB9++CGzZ8+mdOnSPProo1SqVIkePXrw1Vdf8dprr9GtWzcmTJhw2UZg5cuXJ1euXKgqcXFxfPTRRzRu3Pgf9wvoDNVLfQCPAKuBFcBYYPjl7u+GGapumFGZkpKiX746XL8oeadOoIyuaN1TT8TFBzyHG54LVXfkcEMGVXfkyOwzVIsXL/7X9Tlz5ugdd9yhtWvX/uu2xYsX67333vvX9S5dumi+fPl0z549l912iRIl9I8//lBV1R07dmiJEiX0+PHj/7if0zNUz/1i+EBVq6pqHeAIsN2X7WUWIkJ4rUo02zKPigN7sXfecmLKNmHjK6NIOpXodDxjMrX06Od+oVKlSlGoUCG2bNmS5pxX4uvRMtd6P1+PZ719oj9CZRah4dko/3x3mm37kiJN67JxwEjmlmtK/KzFdparMQ5Jj37uFzpw4AA7d+6kRIkS6fNN4Ptx7tNFZAswB+ihqkf9kCnTyXl9EWpPHcGdiz8iS/ZwVrTswbLG/yYh9lenoxmT6aRHP/dz6tWrR3R0NPXq1WPQoEEUKlQo3b4PnxqHqWptfwUxcF39W2m87gu2j57AxgEjmVfhHqL6PET557sRFuH8m33GBLv06ucOnmPoA8nOUHWZkLAwburdiWbbFxDZoTlb//s+MVGN2Dlhti3VGGNSzYq7S2UvVICaH75Bw5WTyV60ECsf+A+L63TgyLqtV36wMcYx1s/dpEqBmtHcvWoqv4yfzvpnhzC/aitufKwtFV/tTbZ8l34X35iMSFX9emy7E3zp5+7Pv87tlXsGICEh3Pjv+2m+fQGle3Rgx7uTiSlzNz+/+7k1JDNBIzw8nEOHDmXa5UdV5dChQ4SHh/tle/bKPQPJmjc31UY8T6l/38fqnq/yY9cB7HhvCtVGPk/B26o4Hc8YnxQrVoz4+Hj++MPTeykxMdFvhS6tAp0hPDycYsWK+WVbVtwzoLwVb6L+sk/ZNXkea/sNZlGt9kR2bEHlwf3IXvhap+MZkyZhYWGULFnyr+vLli2jcuXKDiZyR4a0smWZDEpEiGzXlGbbvuTmZx9j9+R5zIlqxNYh40k+c8bpeMYYh1lxz+DCcuUk+vUnabIphmvrVGdtv8F8WakF+xZ963Q0Y4yDrLgHiWtKR3JHzLvUnfMOKWeTWNqwMytaPc6JuHinoxljHGDFPcgUbVaPpptiqPRaH/Yt+Ia5ZZuw8WVrSGZMZmPFPQiFhmej3HNdabbtS4q2qM/Gl0Yy9+Ym7Jm5KNMeZmZMZuNrV8g+3vmpm0Rkkog4e9yS+ZucxQtz++fDqP/Vx2TJlZOvWz3O0rsf4di2X5yOZoxJZ77MUC0KPAFUU9XyQCjQzl/BjP8UqleTxmtnUvXt/hz6YQPzKtzDmn6DSTl5yuloxph04uuyTBYgu4hkAXIAe32PZNJDSJYsRD3xIM23L+CGh1qybeiHHHjwRXZ++oUt1RgThNI8QxVARHoBr+GZobpQVTtc5D42Q9WFOc5s3cnh4RNJ2b6bsHKlyP1EO7KWud6RLE4/F27J4JYcbsjglhxuyAABnqEK5AW+AgoCYcAXwAOXe4zNUP0/N+T4askS3fHBVJ1WsKZOkChd9dgLmnjwcMBzuOG5cEMGVXfkcEMGVXfkcEMG1cDPUL0L2Kmqf6jqWWAGcJsP2zMBJiEhlOp8H823LyDqiY788v405pS+m5/HTrSGZMZkcL4U991ATRHJIZ4enfUBazaeAWXNcw1Vh/en8bovyBt9Ez92f5kF1Vpz4JufnI5mjEmjNBd3VV0FTAPWABu923rPT7mMA/KUL8OdSz6m1uRhnD54hMW1O/DdA/34c+9+p6MZY66ST0fLqOoAVb1JVcurakdVPe2vYMYZIkKJNk1otu1LyvXvyu6p84mJasSW/46zhmTGZCB2hqq5qCw5c1Dp1T403TKPQvVqsO7pt5hXoTl7569wOpoxJhWsuJvLiih1PXVnv8Md894DhWWNu7CiZXdO/LrH6WjGmMuw4m5SpUjjujTZOIfoQX35ffFKYm5uwoYX3ybpTzvL1Rg3suJuUi00W1ZufvpRmsXOp3jrhmwaOIaYsk3YPW2+neVqjMtYcTdXLUfRQtSaMIS7ln9G1jwRfHN/L75q8DDHtuxwOpoxxsuKu0mza+tUp9HqGVQb9SKHV29mXqUWrH7yDc4cO+50NGMyPSvuxichWbJQpkcHmv+8gFKdWxM7/GNiohrx60cz0JQUp+MZk2lZcTd+EV4gH7e8+wqNfpxGrhuK8/3Dz7KwVnsO/bTR6WjGZEpW3I1f5atangbfTKTmx4M5uTOeBbfcz6ouz5P4x2GnoxmTqVhxN34nISHc8GBLmsXO56Y+nfj1o5nMKXM3saM+IyUpyel4xmQKvkxiihKRded9JIhIb3+GMxlb1twRVBnyDE02zCZ/tfKs7jmQ+VXu5cCKH52OZkzQ86VxWKyqRqtqNFAV+BOY6bdkJmjkLluKegvHU3v6SM4mnGRx3Qf4tv2T/Bn/u9PRjAlaWfy0nfrAL6q6y0/bM0FGRCjeqiGFG9Vmy+BxbBk8jt/mLKVc/66cyZeNQ7mcfeM1+fAxR/dvjL/5q7i3Ayb5aVsmiGXJkZ2KLz/BDZ3uZc2Tg1j/3FAAFjicS7KFcejrkuSvXtHhJMb4h08zVAFEJCuewdjlVPUfjb9thqp7c7ghw5nYOE7+doDs2cMdy6DJKRwdNRk5m0SBMc+SpVA+x7K44d/EDRncksMNGSDAM1TPfQAt8AzHvuJ9bYbq/7khhxsyqLojx8IPJ+iUa6ro3IrN9UzCccdyuOG5cEMGVXfkcEMG1cDPUD2nPbYkYzK4sMgi1JoynGObd/Dtv/rZDFmT4flU3EUkJ9AAz3BsYzK0InfXpuqI/uyNWcra//zX6TjG+MSnN1RV9SSQ309ZjHFcme4dSIjdSeywj7gmqiSlH2vndCRj0sRfR8sYEzSqDH2WEzt281OPV8h1Q3EKN6jldCRjrpq1HzDmAiGhodT6fCi5by7FN/f34tjWX5yOZMxVs+JuzEWEReSi7px3CA3PxvJmj5F40BqfmYzFirsxl5CzRFHqzBrDqb0H+Prex0k+fcbpSMakmhV3Yy6jQI1K1Px4EH98s5pV/+5vs2JNhmFvqBpzBSXaNOH49jg2vPA210SVpPzz3Z2OZMwVWXE3JhXK9e9GgrfAR5SJpESbJk5HMuaybFnGmFQQEWqMe5WCtarw/UPPcHDVeqcjGXNZVtyNSaXQbFmpPXM02Ytcy4oW3Tm56zenIxlzSVbcjbkK4QXzUTfmXZITT7O8eVfOJpxwOpIxF2XF3ZirlLtsKWpPG8GxLb/wbfsnbS6scSVfG4flEZFpIrJNRLaKyK3+CmaMm113121UG/UCe+ctZ22/wU7HMeYffD1a5m1gvqre5x3akcMPmYzJEEp3be9pMjb8Y0+TsW7/cjqSMX9Jc3EXkdxAHaATgKqeAewUPpOpVH7raY7v2M1PPV8l5w3FKXJ3bacjGQP4MGZPRKKB94AtQCVgNdDL2wb4/PvZmD2X5nBDBrfk8CVDyp+JHOz5Jsn7D1Jg5NOElSziSA5/cUMGt+RwQwYI8Jg9oBqQBNTwXn8bGHi5x9iYvf9zQw43ZFB1Rw5fM5zYvVenX1dLv4isp6f2H3Qshz+4IYOqO3K4IYNq4MfsxQPxqrrKe30aUMWH7RmTYeUsXpi6s8eQ+PtBVtzbg+TE005HMplcmou7qv4O7BGRKO9N9fEs0RiTKeWvXpFbP/0vB79by/ePPGdNxoyjfD3OvScwQUQ2ANHA675HMibjuv6+RlR6rQ+7JsawaeBop+OYTMzXGarr8Ky9G2O8bn72MRK2x7FxwEgiypQksl1TpyOZTMjOUDXGz0SEW959hYK1q/F9p2f4Y+VapyOZTMiKuzHpIDRbVmrPGEmOYtexokV3TsTFOx3JZDJW3I1JJ+EF8lE35h1SziaxvJk1GTOBZcXdmHSU+yZPk7GE2J1807a3NRkzAWPF3Zh0dl39W6k+ZgD75n/Nmj5vOB3HZBI2Zs+YALixSxsSYneybch4IqJKEvX4A05HMkHOirsxARI9uB/Hf45jTa/XiChVnCKN6zodyQQxW5YxJkBCQkO5bcJb5KkYxTdt+3B003anI5kgZsXdmAAKy5WTunPeISxXDpY368qp/QedjmSClBV3YwIsR7HrqDvnHRIPHGJFyx4knUp0OpIJQlbcjXFAvqrlue2zNzn0/TpWdbYmY8b/fJ2hGiciG0VknYj85K9QxmQGxVs1pNIbfdn1+Vw2vjTS6TgmyPjjaJl6qmoLh8akwc1Pd+H49p1semU0EWUioeg1TkcyQcIOhTTGQSJC9Xde5vDO3Tz+zkscLp6HbJ8MdjTT6dOnHc/glhxuyJBWaZ6hCiAiO4EjgALvqup7F7mPzVB1aQ43ZHBLDiczqCqvfzOBxXs3UfS4II6kMG4WP+H7wM1Q9f5SKOr9fC2wHqhzufvbDNX/c0MON2RQdUcOJzMMnPuB0rWGvjpvfKZ/Ls7nhhxuyKAa+BmqqOpv3s8HgJnALb5sz5jMZsrqxbww5z061mjMc406OR3HBJE0F3cRySkiEecuAw2BTf4KZkywW7VzEw99PJDbS1ViXIdnEbEFGeM/vryhWgiY6f2BzAJMVNX5fkllTJDbdWgf94z9D0VyF2Bm18FkC8vqdCQTZNJc3FX1V6CSH7MYkykknDpJ87H9OJ10luVPDqFArjxORzJByA6FNCaAkpKTaD/+Bbbsi2P+48O46bpIpyOZIGXtB4wJoL7TRzBv03eMbtePu8ra8Qcm/VhxNyZAxiyfxoilU+hTvx2P1b7X6TgmyFlxNyYAFmz5niemDKN5hdt5s1VPp+OYTMCKuzHpbPPeX2kzrj/li9zAxM6vEBoS6nQkkwlYcTcmHR1IOEyzMX3JkTWcOd3eIld4DqcjmUzCjpYxJp0knj1Ny3efZn/CYZY/OZbi+Qo5HclkIlbcjUkHqkrnT15j5a8bmdrldapH3ux0JJPJ2LKMMelg4LzxTPppIa+36MZ9Ve50Oo7JhKy4G+Nnn/+4iAEx43ioZhOeuftBp+OYTMqKuzF+tPLXjXT6ZCB1SlfmPWsGZhzkc3EXkVARWSsiMf4IZExGFXdoLy3GPkWxvNcy/dE3yJolzOlIJhPzxyv3XsBWP2zHmAwr4dRJmo3ux9nkJOZ2t2Zgxnk+FXcRKQY0Bd73TxxjMp6k5CTavt+f2P27mP7oG0RdV8LpSMb4PEN1GvAGEAH0U9VmF7mPzVB1aQ43ZHBLDl8yjFg9i5k7VtKvWiualvKtGVhGfy6CLYcbMgDUq1cvcDNUgWbAGO/lO4CYKz3GZqj+nxtyuCGDqjtypDXDyKVTlK41tO+0tx3N4U9uyKDqjhxuyKAa+BmqtYB7RCQO+By4U0Q+82F7xmQoX276jl5ThnFPxdoMvreH03GM+Zs0F3dVfVZVi6lqJNAO+EpVH/BbMmNcbNNvv9D2g+epWPRGJjz8sjUDM65jx7kbc5X2Jxyi2Zi+RGTLyZzu1gzMuJNfesuo6jJgmT+2ZYybnTqTSMt3nubA8SN83fddiuW91ulIxlyUNQ4zJpVUlc6fvsb3Ozcx/dE3qFriJqcjGXNJtixjTCq9FPM+n/+0iEEtu9Oqcj2n4xhzWVbcjUmFCT/M55V5H9D5tuY81bCj03GMuSIr7sZcwXe/bKDzp69Rt3RlxrZ/ypqBmQzBirsxl7Hz4F5avvM0JfJdx/RHB1kzMJNhWHE35hKOnTpBszF9SUpJJqb7EPLnyu10JGNSzY6WMeYikpKTaDOuP9v372bhEyMoU+h6pyMZc1XslbsxF1BVek0ZxsKtq3i3wzPUi6rqdCRjrpoVd2MuMHLpFMasmM5TDR+g823NnY5jTJpYcTfmPHM3fkufaW/TslJd3mjR3ek4xqRZmou7iISLyA8isl5ENovIy/4MZkygbYj/mXYfvEB0sdJ89vBLhITYax+Tcfny03sauFNVKwHRQCMRqemfWMYE1uFTx2k+9j9cE56T2d3fJGe27E5HMsYnaT5axttA/oT3apj3I+1jnUymdPjkMX47cYhf/oh3LENySgrPf/MJB08c5eu+71A0jzUDMxmfT4dCikgosBq4ERitqqv8ksoEvROJf/La/I8YumQSZ5LOwlxn8wjCjMcGUeV6awZmgoNPM1T/2ohIHmAm0FNVN13wNZuh6tIcTmRQVZbu2cDYdXM5eCqBhpFVKJe7GOHh4QHNcaF8oTmoVtz5wp5Zfy7cmsMNGSDAM1Qv/ABexDMk22aopoIbcgQ6w/o927XukK5K1xpa5bUH9btfNjiS42LckEHVHTnckEHVHTnckEE1bTNU07wsIyIFgbOqelREsgMNgMFp3Z4JXkdOJvBizHuMWT6DvDkiePdfz/BIreY2ms6YdOTLmnth4GPvunsIMEVVY/wTywSD5JRkxn83h+dmvcPhkwl0q9OKV5p3IV9O69FiTHrz5WiZDUBlP2YxQeT7Xzfx+OS3WL17G7VvjGZk275UKlba6VjGZBrWOMz41f6EQzzzxRg+WjmXIrkLMuHhl2lfvaH1QDcmwKy4G784m5zEqGVTeSnmfU6dPc3TDTvSv3EnIsJzOh3NmEzJirvx2ZJtP/LElKFs2beTxuVuZfj9faxFrjEOs+Ju0mzXoX30nT6C6WuXckOBoszu9ibNKtxuSzDGuIAVd3PVEs+e5s1FE3hj/scADGz+KP0adCA8LJvDyYwx51hxN6mmqsze8DV9pg5n56G93F+lPm+17sn1+a5zOpox5gJW3E2qxP6+i15Th7Fgy/eUK3wDS3qN4s6bru5saGNM4FhxN5d1PPEkA+eNZ/hXk8kelo3h9/ehe93WhIXaj44xbmb/Q81FqSoTfpjPUzNHs+/YQR6+tRlvtOxGoWvyOx3NGJMKVtzNP6zbs53HJ7/Ft79soHqJm5n52CBqlCzvdCxjzFWw4m7+cujEMV6Y8y7vfv0F+XJew/sPPMfDtzazcXPGZEC+dIUsDnwCFMIzgek9VX3bX8FM4CSnJDPum1n0n/0Ox06dpEfd1rzcrAt5c17jdDRjTBr58so9CeirqmtEJAJYLSKLVHWLn7KZAPj2l/X0nDyEtXu2U7d0ZUa27UuFojc6HcsY4yNfukLuA/Z5Lx8Xka1AUcCKewaw79hBXv9+Mosmr6VY3mv5/JGBtKl6l51dakyQ8NeYvUhgBVBeVRMu+JqN2XNRjrPJScz4+Ts+3ryYsynJtI2qQ4eb65E9S9aAZznHDf8mbsjglhxuyOCWHG7IAA6N2QNy4RmS3epK97Uxe//nRI4Fm7/XqAFtlK41tOmoJ/Wz2VMDnuFi3PBv4oYMqu7I4YYMqu7I4YYMqgEeswcgImHAdGCCqs7wZVsm/ew8uJcnp73NF+uXc2PBYsR0H0LTCrVYtmyZ09GMMenEl6NlBPgA2KqqQ/0XyfjLqTOJDF74KYMXfkaICK+36MaT9duTLcy5JRhjTGD48sq9FtAR2Cgi67y3Paeq83yPZXyhqsxct4wnp73NrsO/07bqXbzZqifF8xVyOpoxJkB8OVrmG8AOrXCZrft28sSUoSze9iPli5RiaZ/R3FGmqtOxjDEBZmeoBomEUyd5Zd4HvP3VZHJly8GINk/SrU4rsliDL2MyJfufn8GlpKTw2Q/zeXrmaPYfP8wjtzXn9RbdKBiR1+loxhgHWXHPwNbs3sbjk4ew8teN3BJ5M7O7vUn1yJudjmWMcQEr7hnQwRNH6T/rHcZ9O4uCufIwvuPzPFSziTX4Msb8xYp7BpKUnMS7X3/BC3PeIyHxJL3qtWVA00fIkyPC6WjGGJex4p5BfP3zOnpOGcL6+J+pV6YqI9v2pVyRG5yOZYxxKSvuLvfb0QM8NWMUE39cSPG8hZjy79e4r24tRfcAAAvwSURBVMqd1uDLGHNZVtxd6kzSWYZ/9TmvzBtPUnIyzzd+mGfufpCc2bI7Hc0YkwFYcXeh+ZtX0mvKMLYf2E3zCrcz7P7elCpYzOlYxpgMxIq7i/z6x2/0mTac2Ru+pvS1xZnXYyiNy9/mdCxjTAZkxd0F/jyTyBvzP+bNRRPIEhrKoJbd6X1nO2vwZYxJM19b/o4HmgEHVLW8fyJlHqrK9LVLeXLa2+w5sp9/VW/If1s9TtE81zodzRiTwfn6yv0jYBSeQdnmKuw8tp+Bb/fkq9ifqFj0Rj57+CXqlK7sdCxjTJDwqbir6grviD2TSsdOneClmPcZsXQK14TnZFTbfjxWu6U1+DLG+JXPM1S9xT3mUssyNkPVI0VTWLBzDeM2zOfo6ZM0LB5N1ypNyRPu3HxGt8yHdEMON2RwSw43ZHBLDjdkAOdmqEYCm1Jz38w6Q/WHnZu1xqDOStcaWnPwI/pT3FZXzGZ0QwZVd+RwQwZVd+RwQwZVd+RwQwZVB2aomsv74/gRnps1lg++m8O1EXn56MEX6FijMSEhISzb+bvT8YwxQcyKezpISk5i7IoZvDhnHCdO/0mfO9vxYtNHyJ3d+T/vjDGZg6+HQk4C7gAKiEg8MEBVP/BHsIxq+fY19JwyhI2//UL9qGqMaNuXmwuXdDqWMSaT8fVomfb+CpLRxR85wH9mjOTznxZxfb7rmNbldVpVrmcNvowxjrBlGR+dPnuGoUsm8eqXH5KcksKLTR7h6bs7kiNruNPRjDGZmBV3H8zd+C29pw5jxx/xtKxUl6H39aJkgSJOxzLGGCvuabHjwB76TBtOzMZviSpUggU936bhzTWcjmWMMX+x4n4VTp4+xevzP+KtxRPJGhrGm6168kS9NmTNEuZ0NGOM+Rsr7qmgqkxZvZh+M0YSf+QAD9zSiMH39qBInoJORzPGmIuy4n4FG3/bwRNThrJs+xqii5Xh80cGUqtUJadjGWPMZVlxv4Sjfx5nQMw4Ri+fTu7sORnb/im63N6C0JBQp6MZY8wVWXG/QEpKCh+ujOHZL8Zy6OQxHqvdkoHNHyN/rtxORzPGmFSz4n6eH+I28/jnQ/hx1xZqlarIyLbDqVw8yulYxhhz1ay4AwcSDvPsrLGM/24OhXMX4NNOA+hwSyM7u9QYk2Fl6uJ+NjmJMcunMyBmHH+eSeQ/DTrwQpPORITndDqaMcb4xNfGYY2At4FQ4H1VHeSXVAGwNHY1PScPYfO+X2lYtgYj2jxJ1HUlnI5ljDF+kebiLiKhwGigARAP/Cgis1V1i7/CpYf9J4/SZlx/pq5ZQmT+wsx8bDAtKtWxJRhjTFDx5ZX7LcAOVf0VQEQ+B1oAlyzuccf2U+4VZxtJ/nIgHgkJ4eVmXfhPgw5ktwZfxpgglOYZqiJyH9BIVf/tvd4RqKGqj19wv79mqGYreE3Vmr3a+JbYRzlCsvJgxbu4LmdeR3O4YTajGzK4JYcbMrglhxsyuCWHGzJAgGeoAvfhWWc/d70jMOpyj8msM1Qvxg053JBB1R053JBB1R053JBB1R053JBBNW0zVEN8+GXyG1D8vOvFvLcZY4xxmC/F/UegtIiUFJGsQDtgtn9iGWOM8UWa31BV1SQReRxYgOdQyPGqutlvyYwxxqSZrzNU5wHz/JTFGGOMn/iyLGOMMcalrLgbY0wQsuJujDFByIq7McYEoTSfoZqmnYkcB2IDtsOLKwAcdDgDuCOHGzKAO3K4IQO4I4cbMoA7crghA0CUqkZczQMC3fI3Vq/2FFo/E5GfnM7glhxuyOCWHG7I4JYcbsjglhxuyHAux9U+xpZljDEmCFlxN8aYIBTo4v5egPd3MW7IAO7I4YYM4I4cbsgA7sjhhgzgjhxuyABpyBHQN1SNMcYEhi3LGGNMELLibowxQSggxV1EGolIrIjsEJFnArHPi2QYLyIHRGSTE/v3ZiguIktFZIuIbBaRXg7lCBeRH0RkvTfHy07k8GYJFZG1IhLjYIY4EdkoIuvScsiZnzLkEZFpIrJNRLaKyK0OZIjyPgfnPhJEpLcDOfp4fy43icgkEXFkFqaI9PJm2Byo5+FidUpE8onIIhH52fs5dWPkrna6x9V+4GkH/AtwA5AVWA/cnN77vUiOOkAVYFOg931ehsJAFe/lCGC7Q8+FALm8l8OAVUBNh56TJ4GJQIyD/y5xQAGn9u/N8DHwb+/lrEAeh/OEAr8DJQK836LATiC79/oUoJMD3395YBOQA8/5QIuBGwOw33/UKeC/wDPey88Ag1OzrUC8cv9rkLaqngHODdIOKFVdARwO9H4vyLBPVdd4Lx8HtuL5YQ50DlXVE96rYd6PgL+zLiLFgKbA+4Het5uISG48/6k/AFDVM6p61NlU1Ad+UdVdDuw7C5BdRLLgKa57HchQFlilqn+qahKwHGiV3ju9RJ1qgeeXP97PLVOzrUAU96LAnvOux+NAQXMbEYkEKuN51ezE/kNFZB1wAFikqk7kGA48BaQ4sO/zKbBQRFZ7B7oHWkngD+BD7xLV+yKS04Ec52sHTAr0TlX1N+AtYDewDzimqgsDnQPPq/baIpJfRHIATfj7WNFAKqSq+7yXfwcKpeZB9oaqA0QkFzAd6K2qCU5kUNVkVY3GM/v2FhEpH8j9i0gz4ICqrg7kfi/hdlWtAjQGeohInQDvPwueP8XHqmpl4CSeP78d4R2beQ8w1YF958XzSrUkUATIKSIPBDqHqm4FBgMLgfnAOiA50DkupJ61mVT9lR2I4m6DtM8jImF4CvsEVZ3hdB7vn/9LgUYB3nUt4B4RicOzVHeniHwW4AzAX68WUdUDwEw8S4mBFA/En/fX0zQ8xd4pjYE1qrrfgX3fBexU1T9U9SwwA7jNgRyo6geqWlVV6wBH8LxH5oT9IlIYwPv5QGoeFIjiboO0vURE8KyrblXVoQ7mKCgiebyXswMNgG2BzKCqz6pqMVWNxPMz8ZWqBvwVmojkFJGIc5eBhnj+JA8YVf0d2CMiUd6b6gNbApnhAu1xYEnGazdQU0RyeP+/1Mfz3lTAici13s/X41lvn+hEDjz18iHv5YeAWal5ULp3hVSXDNIWkUnAHUABEYkHBqjqBwGOUQvoCGz0rncDPKeeWbSBVBj4WERC8fyCn6Kqjh2K6LBCwExPHSELMFFV5zuQoycwwfsC6FfgYQcynPsF1wB4zIn9q+oqEZkGrAGSgLU41wJguojkB84CPQLxJvfF6hQwCJgiIo8Au4A2qdqW9/AaY4wxQcTeUDXGmCBkxd0YY4KQFXdjjAlCVtyNMSYIWXE3xpggZMXdZCje7ondvZeLeA+bS699RYtIk/TavjHpyYq7yWjyAN0BVHWvqt6XjvuKxtNTxJgMx45zNxmKiJzrKhoL/AyUVdXyItIJT7e8nEBpPM2nsuI5aew00ERVD4tIKWA0UBD4E+iiqttE5H48J4wkA8fwnAa/A8iOp13GG0AMMBJPO9gw4CVVneXd971AbjxN8T5TVcd65BsDAThD1Rg/ewYor6rR3s6a559ZWx5Pp81wPIX5aVWtLCLDgAfxdKF8D+iqqj+LSA1gDHAn8CJwt6r+JiJ5VPWMiLwIVFPVxwFE5HU8bRI6e9s3/CAii737vsW7/z+BH0Vkrqo6MvjDGLDiboLLUm+f/OMicgyY4719I1DR243zNmCqt90AQDbv52+Bj0RkCp5mVRfTEE+zs37e6+HA9d7Li1T1EICIzABuB6y4G8dYcTfB5PR5l1POu56C52c9BDjqbXX8N6ra1ftKvimwWkSqXmT7ArRW1di/3eh53IXrm7beaRxlb6iajOY4nhGFV83bO3+nd30d8ajkvVxKVVep6ot4BmcUv8i+FgA9vd0KEZHK532tgXfWZXY8a//fpiWjMf5ixd1kKN6lj2+9A4TfTMMmOgCPiMh6YDP/H/n4pniGZG8CvsMz63cpcLN3WHRbYCCeN1I3iMhm7/VzfsDTp38DMN3W243T7GgZY3zkPVrmrzdejXEDe+VujDFByF65G2NMELJX7sYYE4SsuBtjTBCy4m6MMUHIirsxxgQhK+7GGBOE/gcznBH/udI3nwAAAABJRU5ErkJggg==\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "df.plot('timestep', ['box_A', 'box_B'], grid=True, \n", + " colormap = 'RdYlGn',\n", + " xticks=list(df['timestep'].drop_duplicates()), \n", + " yticks=list(range(1+(df['box_A']+df['box_B']).max())));" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Let's take a step-by-step look at what the simulation tells us:\n", + "\n", + "* Timestep 1: the number of marbles in the boxes does not change, as none of the robots act\n", + "* Timestep 2: Robot 1 acts, Robot 2 doesn't; resulting in one marble being moved from box A to box B\n", + "* Timestep 3: Robot 2 acts, Robot 1 doesn't; resulting in one marble being moved from box A to box B\n", + "* Timestep 4: Robot 1 acts, Robot 2 doesn't; resulting in one marble being moved from box A to box B\n", + "* Timestep 5: the number of marbles in the boxes does not change, as none of the robots act\n", + "* Timestep 6: Robots 1 and 2 act, as 6 is a multiple of 2 and 3; resulting in two marbles being moved from box A to box B and an equilibrium being reached." + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.7.0" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/tutorials/videos/robot-marbles-part-4/README.md b/tutorials/videos/robot-marbles-part-4/README.md new file mode 100644 index 0000000..5ae38d9 --- /dev/null +++ b/tutorials/videos/robot-marbles-part-4/README.md @@ -0,0 +1 @@ +(https://youtu.be/MLNTqqX47Ew) diff --git a/tutorials/videos/robot-marbles-part-4/config.py b/tutorials/videos/robot-marbles-part-4/config.py new file mode 100644 index 0000000..d4b2c99 --- /dev/null +++ b/tutorials/videos/robot-marbles-part-4/config.py @@ -0,0 +1,103 @@ +# import libraries +from decimal import Decimal +import numpy as np +from datetime import timedelta +from cadCAD.configuration import append_configs +from cadCAD.configuration.utils import bound_norm_random, ep_time_step, config_sim + +seeds = { + # 'z': np.random.RandomState(1), + # 'a': np.random.RandomState(2) +} + +sim_config = config_sim({ + 'T': range(10), #number of discrete iterations in each experiement + 'N': 1, #number of times the simulation will be run (Monte Carlo runs) + #'M': g #parameter sweep dictionary +}) + + +# define the time deltas for the discrete increments in the model +# ts_format = '%Y-%m-%d %H:%M:%S' +# t_delta = timedelta(days=0, minutes=1, seconds=0) +# def time_model(_g, step, sL, s, _input): +# y = 'time' +# x = ep_time_step(s, dt_str=s['time'], fromat_str=ts_format, _timedelta=t_delta) +# return (y, x) + +# Behaviors +def robot_arm(_g, step, sL, s): + add_to_A = 0 + if (s['box_A'] > s['box_B']): + add_to_A = -1 + elif (s['box_A'] < s['box_B']): + add_to_A = 1 + return({'add_to_A': add_to_A, 'add_to_B': -add_to_A}) + +robots_probabilities = [0.5,1/3] # Robot 1 acts with a 50% probability; Robot 2, 33.33% + +def robot_arm_1(_g, step, sL, s): + _robotId = 1 + if np.random.rand() s['box_B']): + add_to_A = -1 + elif (s['box_A'] < s['box_B']): + add_to_A = 1 + return({'add_to_A': add_to_A, 'add_to_B': -add_to_A}) + +robots_probabilities = [0.5,1/3] # Robot 1 acts with a 50% probability; Robot 2, 33.33% + +def robot_arm_1(_g, step, sL, s): + _robotId = 1 + if np.random.rand()zIp7Olk^}PT8mhXA~6EDf$!|d$r?A)`vGqcO_o8uY4IZag!RR942 z0pKz2AK-WrpadWxCO$(Jl9E!8Q=F%yJTJn|$}aMs{v5vmP?HdT zCS*TN00f+(COAz^aNG)D1rPvE15V@E#eay1&zw3 z(|})o{9usa6!mEuT0J^;;p_S$grc4sz)BA5&Ep9G#c3Qa^=WE=0$}2(uV2n6B=!Za+e&cdii+{d4puC^B0@wwR4U6K@(n& zm_GfJ*tva$Y7}1+ru%Y+F&7B|}j{MT+Y&ixbbzqxVAvSGJvoTCV2#ZaaEm zA||dhw%nD7&@8%>OWvgBE;zQ*#yHCEtBUWYf6dD5qhZ;Tj?Lox%JKB1W4ZXg%1wBA z3^-jlVRZw~J@q7>RXq1>t};>%HL-YB-A}lW{Dfx}&wZRk7OUul8lF|j6Yg7m@T}sw zSIf|e{aes~3;N$rqfaaq%l>bMW?nk_w)tu!NP~+iEirIy}37wNWU zVLDmDpi$U!x~2!S&)%j|uvS75*;MXpif#{h1jHrXWO8)kuIhxzQjc7j)smN|+|X6U z)E1S5>pxAqk^Xwc3^IgJ0g zdYlV{xw#e&pD}PU+}q=Omf92`r>Z_$0KC3SqXcVDbQvnU{i+%@&9=k7q@H2Zi({$U3<$v*bA{sv$AA`*2E+0wZ9%ab zk|A_koX7w<8C~g_j=-GlX0FJR#772b$`9A#G&3+FcS^YUM5-#HUSm5~(!@P%fS^X! zycR;JW-U-Z*Tr~cTb$Wzs+Z>m*XlqFAL&pEosTrcWWk-*m~Kxq%_h^)$c`6jhHSi% zhD^>1sY=as>fEq{l(4aiIg9t4T^8?muAs4rDynCQA@hkD9FjWm3;@w(L zN2R7CgU*+QMwX;JgaI-3mK+QDpOqe^Cp)A^>YC03>pZUR2Z@n!#@y$hQW(=)^6w&sM&hcyN=3)p$P|6#YMdfJ?}}F0=Uzu5 zXy~f;fLF_mYVSHPEx$;Juqt2wIZ zfnM!V?xlH6KT_k?2(dR^Tb_Y%aRb&1Q3WJv*}PSvb+u#HvWvU>+QOdId)3FK+}quw zrHmZ6ZDeO8G;E{xtEO%P-+eyPVAPpfOGB48`l{n$SxS*iTB+?B>?XJQK7})|B=sxX znni$OHG?xno_aAG#4KS(?cT01`y#gh#AS$)NEynA@DPpi7Qg5|ZuCs4RM9r@k=&@H zrV=EMH`=W1;Z!C>kCCq1Sz2m$u*Q@YX^QBsk=hm=sfpAgpP_|s^_&t@F)B9$@tKt? zL*?~rrFT1@$JlV+jMmXdYCVrrD>*a}r;!xJ|Bh+UMgrK# zW!4Jmf`J@f!qN0gdTU*mYRB?=cO|CQOC*#y&QG5)vbD4IT>PG*yUoY!l{Rqjofc)W z;0~hul6lyz!%y6KcbZ9*au9uOi!W_KMcMN9+hc%JH_BJvd55_3?NRw6277N4HKHAp9y{wrE$2#Ec+QboL$( zD5t9HE$P#Z-hI#mZcUErq(*ykm{Xf4)?+~2L2J?X;_lqA%k2~4_fLMndvRu)R)d%R zrXnJiY+PA&p@6I?3RBO0*}$nHPOI49l38y>cOCx+eOUBW&c)P}&_yefrBEIGcpnl_^425Tdb?*Jn9@y2p|`_mI+&R0#Q=nZ76xdp&0CHG&Iu+vMX#B*7Nmd=X| z#g89w`<*EWl6Srp;!TfgxTE7Xi5bpcSUb1O`Jp@uZvCpuWROAT*#**daD*(8it^Ue z=xCa17sYMeMkjC5$gMsNtbf{-6qy$pNCeS(Xmq%_UMEW9;4DAopulR>Eetq4DpA0T zTgG|=`o?i3I)q!lfIQ^zBjdt0a?LA~ISa-)34CYZX~&r>!5Z+e(fYbdpof>3E^&wS z+a$ylFjY}9;t`4K9${g-dRffnO1nd{MV_xk6~>Yj23f`zOIb=A49cS{bcz`=2)55H z<-FQ>OT9RKMv&n$%C%d$t-kzx&SK*8%kXX3#?7|$4Y)7^T}{s-P=e66K!GcPz8-Xl zTpkF&txM@cbX};6w2R5O)x--`SKB?d5ljuiyv9yxMCDvdk1;ROb4;pSTz6UvlMkj_ zRHV>QAfloX-7`exZdwNH(Uj#a zbl|-)zfFESo#Fdz7ho%K43=V-;k2I+q&C9lDbs{gt8r{WZBK-(?g1Enr#gQqUVje_ zuNS}F-_`mKkvr)E(fpXMX!(1P`wx(oU~@13CBV!{)zfWPub#@#L1kw~&n)I!%ZNEf zjzLqz>7n)9pn9MX0}R#Tw)~9!JK3#w_aC2Dn0*R=AAbxW5?=41Y<%=3VwX40hxnfH z=VxqF4Hy^Oxn?|e{J7t!wFpRc~U4{1BGsKMEB#hsI6G zxoTg~XzDdGvl)s*uFzSYFZ~tHDr{nL&O$Qe8{J9^mF@T}q*dIJxMdbJ<8tA6ydrFbvNJJ9mJ$}Ap2 zANJ+jM#8}ZTwC00U!R?dZaIO3^O3K9p5^#Vj@> zM#;n%G9f(Vq!&E@F+q}FIV`2m@S(I3YwFh3Ro8x@CR{BdtQTh_8&j^LqQ*nB4DL=V zI8&aWfkf-is%!eGgi%5ly^KrVf0OQBmhOkHVKA7I9i+}L?LCN_VikU)@Qc*U=d(UO*e8>Tn7 zkvns-{?}omQt&{HjAf@K{|94OffKC3e|n@sH~zz+pJkQFMoAji{v&0Q@>US}5BT`M zNtY%=U1fL#UWrs0yyEbLGO{%TQ(gBa zj<|C74+S?rIw`jSxtz_eWDs&6ehN+;Itpg=bMGHt6}UJ)>l<6gv>{R{3gkJ;Y#6MZ`|NhPo^RxBkM7k zZALy?wYt|B6SO4BuuK-jh(pODR8cn$WX^g$0q`B1;0`ruDWQ|)`yagH z2atWoqqv{c(gK`n#-p&D)Ea&P_?z&r!u~fBg^25#d8Txb)g}?&jQQloF@SiN?nm^2 zHYqhJoXNz#gTkZNQWD|lr62KjFfi}TLm~9@*Ny<=rzfCXzmy1-%XhNQG?-kY|1@WI zfiCB(7u(8vuACvwiw@VZs@D`qUtIez3UuYy=JKLvC!Wx{jftq1)vm>?Y5NlXvLO%Gbp)19Kko6Vpyka$?j0 z{~xWomPz{6x?02XuKdu7pG7?Nf4V?%3}|N@vT_kSt*{yP#dxCcpRW0j5r1}z|2J3n z-%|MD@c&y1e@o%-H{!=4_TNkjqO!4v#fBJ9fk_5driOl|awoaC~*Ss)a-v!<*g4p~y}e;kmj7A8QnIp1n~ z`Nl+f;QIyDTG|+hF@mBz-*fD#dOAX@4&7EbdD{oPXhCgGbBkzzib_sn(f1gjvlsU*?$TrXF9mC(U0w$JV5rJ}>_2?7R>E_vQTBJXqYk(n8hUwRQbYAfY2`M?a( z8hL+OS4)0z9(`l=>y9A3Ooreak&V418SK2cv4hf-Qd=Z1|4=j9kR;g2vr=vaSLRHmbE#HByT827LZ z2ER;7MF_L;;d(n3q@KVUx}4N`qaW?eTiPnmLo98< zYxY$4jo#^ta+jRT9TAXF09j@wmqp7&VzcQD5KSwHZ*XaiGW(H8A48Wh*AaW*h$Ho_ zkurO%b>A4Zh>Z@=-bhhp&Uv{l;1~dLqjMIJnJ!Q&99}dP5;%(}n};kzEXA$LbfHa6 zOd5W$tql|zg+#6?6^mY(GY<`rhvq`4gn4T&iVqc zd9Z)O6X>!^$sHX{!&$R$c@mnC@rCYwoV34m5E@m`T!q^&TLCfbPQY?<9~68TZGcH! zWgxGv^~UZ82ItFM(*^`V8M+e3s2br#d)=Er7pEy1Za_AdEHv%>5>oJv{y`A56 zzcoMdb}OXf;81dzea6-SlrDFki;8Y7%Buo{b-1PgKNpL?NZz>OH;?zMjpNseG5tpF z=+A0T1u^MwrA}6Wk4>)O2MLcp$KAbfp|OOkPMhn5!cWjCF90Cqng1D2=dP?I#4y>; z!iBaHZXcafW+yK{KUV<0cnMGapDs9jzw$il!1OWGG2pjN-|wpO`sVKmxyn-ts#@&u zg}95A$&<}Be{QuJvbhuFCnN%Ttp3i|TX3L&^WF7z_=;l%<4x!6 z{S49sy5Yw17JFs392!Q?cwT?CcO|k}`WW!^^O51sWL;1Ts2nTkpH~c})}yX4{NAnC zTujsMwZcgBy4 z9BC~W&KW{injFIP=&$I9$+|;sHzYeBAxVMPBC+r1^R(NsFKAPYdfcd)ZDKuKoaIXJ%;sfj&t@pe_IgGG~%70T% zi^9?j$8Wc#-4!*a0~>TlR*oYNh~ImGAQBeNzO2L60vx2l?gyTXU(7Q7H#*k9 z5caZ3c`@dsa=sM1T9$B;yO~zou(Bg{ZA+oaaJgVe>oZ=7)Yxp-F~NyazNl}vgu^kb zWTM9B^~<)JcOKO{bnJ7u-#qu$tnJnyfE)mj+pf~DWx8Aif5P68@^C6GevVrJMrT4x zf2aEvsO7eEe%i9liZfPk^-a0A`v;|gw!`{&ITu++;gE7=Bh1aBrdh3F0a9i=ebrjs z)a=4O5gQ{}SWavBN4>6NfQm|QaeFjM*FV1R#@g!(isEkl5wok6jIVTWY#O>WRXo@) zZ$Zf~K>NhVZC3LwzJ%)z7szq=p<7_qH00QcuiHYqLd-Uyl@rybt%WZLZv0M?L;)xH z;0(V_P>#>P1j5#e%aX!QJYqzl_zFMKfw#-APc~GU+YXzZP{4x*d9DFS_{QUX8A@@! zz^qFZme;4usvK-*xJrN98x6lQ{#nFR|ECMYcjw7hDr(aSvUgwY^L?_vcT)4r3lI1t zWo+P7jEe!z!ADKoZHEl3D!HQzzVWduLUTAr+IqlPPgDpQFISSi%=1Y_`K4hR0@cbX zn6c%?r72M1Ae@98$Y68odPqvR3?C;_fx#u^gXN4DDrC(DlIv#M(}En6#+)jUk~iWW zaYB}rI}pvrmOKs9Pn}ZQc$4>`XU~v|K3nhKEnkMGW*Hv?O3$URSLkYTOdZ|>tevn~ zFy#~4JvzKlTfm}I&tBMrGw4!NZ>sqGQdy;r0rqn0#R~S*ux}#m1^u{qzEyIcq;6C* zufn9w_asIMuemm9B)x6-*oZ^-loPQVokORQU9e%kBC%t9DvI%J=5)yi=#@65@Pd>( z9X-m#zRuIt8W6h*zw5R!-lErHrv`bFP`#F%uavDM?(at}mq%j?8PT7IlN(ROg{7Nkv$qzUu_hi=r{M z31c`(2M?&BO-IND)It}-6rjp`?~Sf)m0!&NhDP5kv3dGw!md)wPCivIJ_k7WP0+X1 zS2nZh!!cmko~j|hz#YD^Y4$ZJtCmX4J94kPbhxBoje5K7;bK2_FC$LUlI!6q<~bn8 zIl!r3nLU+iS>s>_>c^Im^d^)`$~jW?o${}rD~o&tIdT`05$e`@Og2&J*xJP4y~E*M zCzhw~mQdEclu@YGN5i}cdb*R*mL*pldp^fqG`e8mfhB@CpX17!w~v8bnIe?~uyCb$ zCu2tl8H9;`=QzD-50af|cwCj`(W09WHB07QKNA=F9CBne89{^A;`*{wMhIYi0XX^4 zfB5qhg+6&r@Gly}xf5)_Pjo~T_Ke$Fmur%S%LxTM=vo#b<+1`>hEso^RtJLr>#jtD zoJ4LGQEcSvXS*PwK4)z3T+CI=j3Um(HgG*Rii2JJRJP{54zyB{%AP!}0KIUqKGrNM z(-gEYciI^LTF!alC&GIvm12Re&N#=t7O5q^_^0_8&-MSIfS>hFUe(`lFP&ik zRLd>`x1=ENO%){o1xZG6c7Bgq6tkq%0=F>CP>tV@v9xAa0uRnUl~eCua$)Ijp2>7B zLiO%jB21bw=UgO1xl-~K?}jGi%x@WV?oO9}luqsGO+%;rSU-8BWt6&=T_i4T6YOz$ z?%o@x-_o=H;g}i$g#==>ZRy5S67RIn25xJdNYVXBWK~)mmz1L5?vbu1KFg3imBnyV*rho9=BbJ zr5IV54q?U|_87qRWEvSgr03C>bU+|_uIfRDZixYAFpD8eflrz;whNv=R|f>{(d+3Z z?xaJf7Br-tALcm~SuI~`i5@)d^Q?Mi@2WFu758)XX*y% z>pW;P{Vk{SRc`CH$n1r68_ZSK#TF4hW0~0u=@r+PDgibVO%IX;O53Xb^im zI+zd*di$}+0$Eev+!Mh)GICx6!7yqU$(z3|-xV-etXu_GZ^6F6VD znyMnOMK4849sP(^bt#AkE*;(5Jkz8VMZd2y4XNUp8LTkr5!R0Se1^-yl50yuA;IH_ z>tGWMO@;T}DC~xCa%kvkwWJ|`ov1Gt>W=j>K%p$yU5ZZg*@0e|Y2$2Z ztsrd^XAC(?E-r4rzXcW4)DO@ioU7W-1Y-jCqrHS@~km6raoD=<%@ zqLY|;owGt{*J89A{yrPCd-m*xIv?XpyM@KszF6`IJ<5ycl8EGeKGgGyxZEh3h}nHk z%fRVZg=A<8l0e&(#4m|n#A?y?*`s(k$b8&#_=NcAnM8IPO zSZHJnv*A>e}Z zqdj#URpr>XDSYQkTBAOCs1RFUrn)lM5<{9`eYGO|i<>sf(5{1x!d`r8I6}uweuJ2mKn%xw6S6k*je&%3>WDxZAZpOF5fCv1@mw^T}W++(O+;8TN&MdSk29Ki(6~2zzsDmEYs`Rnm&qh6N3Nw%nvkC5U=%d)ROvPZ(+jH%w8b)Q zu;+dFMre4it8ZZGW+@M_r86@%(7K!~syGT=U}wqML8Py<8z(JbH^!mblR;x8Js|G|B=h>cqFP?_((6J(JYclywnXw>6S9do= z`K9pDJ(q?5d0&qoM%ezbfxV4-Po2F}{M3`14cv;#0o?W_*h)+I1fZqVoxmFk_YN$u z-dsmX#X1{sv+qi%3o}YSu-V)WD!*;OdJN$8rV-hyv|D$$UaSF@&+yQ6Ko(usP0s#! zRY4;N$Mjt%q{FOX@&9_z@*@iah_ z7j^h^c|YfJ@DAO2_ME6(J*|<;SVY>a>}60|a(78_mzz>#Y51hKJGTs(El-GPP=sBH z0m3xa@;o=I{lp%xdSWqX&rvYN8OX__q+$c~zI&=@YR7(}JT;(UB94k*gWkFN6{s)-T(H#rl94KiDgr#YS;U}BcJ}23 z!!TLC1TrhGTZ&+XI+IA$(3K88R$=IxbJbSWR{U$$8j>3(m~x{Q8*yPv@t3E$9xKMt z$Vr`h%Ph#`$=s?YOT}*-bG=fp%H~=aq#-YJ_jbna62JQ?Oe8LzyyCIp!|KnsDEHI= zL*LVnRLj4Pe3+c9nK@#QmX6=ruA_yekAtKcdEZ!P6AB5WhIFn!d~;=3bXx`}E|S&O z-sIAnrPi)>ErN~T&%?S(3@XQoTk8zGyaG0k@zCK{^x1E@5;cJoygIFdxt@G~b5X`7 z7{X;EJ(vhmGExCUUt_SrTH}(*+lIU%=bp+>eYHsR(5HB(lerq6OG|>;b?fflnoq8u zUljKnP8>OVYrf}I)K`uK+<#=z!pk?e+M?{OcsGaj%fpCi^Bv@SR|)+}z8 z*`4{ulkm0y=jAV*85kqv7R|b0q1Mb;_*8asg__`bPYjS-9(?2T6q;||%}&KjjW07M zY82;6i~6E`kU&iya4qD`dTe}JLguIon!|usPb$GU?({-a6RA4oeF0+D^8y{*tP;6q zY2|z&+-_IW%DI#pK8!m0zQe?osEgY!+3P!i><}};Aw?*E+%D$rUe8C84g1GRX{k}2 zgEr!UT()cMOve+xevJtctpOlj_E5<&XJv5_CrDpGLfr$jvV`pFL_`EuDnC;J= z-A>$do)9aMPk9T1QXqY(;;tNS-fG-=v>qHZr4egmT3bQ8#&8MX@E2Qw-6N%5L8X^3 zwfXnDwW~8~cS#yIa9gphB}FdfOUNk@za<79W)ru~FYQ6!6i9#9U+2OZ3a)bFUkn9q zCpy4)BQ%>=;Y~nr5~IA`T$?{qPfLHuv^Vdi&Qo{NREW_;16N{}$1B~$>|KMHBfnqm z#d8(q`uKO|D!Es1)}rQ)#V^*vREPTJtF(|^y__meo&u^{6H((l33`4nh0|Ij8jHnI zGW?|hF)cTWZd6T7x!KTQhucP0hlZ|bk^LS;sHnIB@zXI;sh zR>3@T-{N8Mh{T~YWx}Zk8)^`Co$dw2R9v2S(%DZbKyELvaCZlVu}n%Jkdp*rj?owh z@2V+niT+SsE@JX$ckX#YcG7=^U~H=_4auu zroAj`W|Yp{yruY@&f^+mS|szDw<0z`zvxSmNM&L&!T@!9R854<(&v?%f!U%Oa8Z^* zbS6~JXtWs4c!!~wSl?>C+pF~uquC0d$rp8Ux!p3hPvZu(6`q~W=!vtL& z@V%O9n@RUT(x6brx~TOP=s8Q(R#W|=pwylgYZx1f)?0JD&@e5HXnKs7va=m- z%?H|?AwlP0<&4{>+8?gO8cVa#7h#&Z=y6_mAdro0tVgRJH1hhe&n8%&!Qa!V!S(I5Z%HS;fghv<| z>v?b(X-ouVWQ@!CG!C2%qn3)b_Lya$liIK%<71&=nJ5cnOUq608#2hE(t(?dUtPzA zZhm;T&OPoZgFL-fq>^hUY{jP@x)>n~?SeA)P@O?ef8zPnn+8g*ovZwG;d)xyQ%NmN zA|&+=$k3Q?&FdRzmpNcA4VxgH8n>`#K=C15=l%7`lxLuke8qxcyJ0$p<-kH-05BM@0s|BRkqG&l-a4y$y1RRS5G z^)g?N5g7-`h-eM7*RDNMD=^X*WHS`1bt>+Xv32~iN0go6#ztidtYb67po5m}m6f5! zUzz%h9!}(aBzrbsh#tx&mK9;qw2^VLh^2JNt>}id8H<`918#_m;DZ4?>Ub|Esmn<& z%M;`WeDU5%5C7?Jyvy<=KJZ&jzNe5}t;W^n(?zdfSEEyfgehS*Ju#KVt@R9- zh*dZ|Af*k-AfgY{Kiudv^fh3d8(q}qd&$Pu(OR>#dr?tw6x+lzpz1TN7@gwoDtmpI zo4fAdY5hVOkSDsp%Rnfy*0me06ehpBqb1$1`YN-lJ4Uz7L$$SKSyY~+_?tBf<2dqq zzgp=GxOBAXOR03R`r!PFs8KJeU*fzHlKU1IR*RbmaHj42 zl}X$_HrJ#b&0&T>QBzCBr&wr1_ahP$G~#ncxK_WsRfknQVM*-t7$MXx^B*&gfxt1# z`s%+P#wdSh6eIY#Ac!W1vU5og+SDtKi-F;MwH%L3Ix!$nh3KBg-{l7;$cT)0uBz>C~y+w{vO5M6MY zV&`*-n=vzM?e!6Q+3WqP*B`Zj#6mzbF^C8jsRYInRQ^{ZXTp!AyeO02m{WXu8*@rN z0zaG~@o%--awY)eKb7lDdT@X~ih~*EW5Y`7DA0|d0nS8bf8UFvZ}A*)jWS=OSN~4M zY=4U-Yty3lHP4TC){osH&kSO|u~IP|ViN^_o@ad6 zR5k2rx#Y8j$L9aeIG!Y3<9tR~AT>F8N`Tw7;W3R|FaJO`O-j#hfzo zHCnt3Oig`7Sqa7OQ!@d-1i18@5))YdC3qn8=h)qS>)()Zm;B(-BQyBoeb!4;a7n-? z6n=uJ8t05)J_FgQiDArQYP)jvH!PB9_&EcOIGCS9Y@}(wqJoYXvNX$EBeZMmC-o81 zypn2&4F`Vi7Nb`i4-xG#T}G`PbP(r8x~+8AMX095DR0g-SR#_4l65Sa8U?o3x05cl z$}F17S8kC(vs9-8r@UlJ-R(uQ%UxV3vHz9i5R92t4w>}k}sbKja$PrzCbU5!foBIqkMxsKlBR*Yb zTZ0q3p4@AqVfvH<0S&Bu5CoF%($og0UJ#;n z`N)5WUV1}CLssTh#I-bp38pv52?j0@UPf~}`W5zuW}`>vmLU5{A{Je@Mn^O5MhpVr zCyM7ke=S0kXoCZ{-_&EqO|GLxSjHH7#u!{Ggd4@)l=P4Dh!n;rfQ&E1T~#e<#g=;A zW?IPx`J|L2o${6*qeWEoV|SZvFpGg@E_I5lNr8_!7MJbDfo`fYwr#0*X>t?bvr&R~ z7wXYUmXGqx$0vdS7q0!n@F}d9#a7DXrJgDZjkTKbuH?cO12mv*&}{2;MG0-2rzP!` zwV1k32wPmJ*ML!&@qkzLdy}yz53~KzBSV#pYJQDCr%mUik+a26TK^>sbrStC0LB~~ zO}jS#QaXW}iaEXUj-t%#Ck5Gtc0>Luwx2wM4V$XrFXDCVE2WTKi(7lfi-J)E{MFLm zgdU%W5ciFr)c;G@0CPsD&I^LU-&?)9KKFALd9+M%(+@bpTSSli{J{E086lZN}6ozSFDDfe%< z0>_E7-gYQ zgS^}O5V7x(`X#|{W8fRw#wpBxqnh_A^6C?N)vs>+T9N3PPgoB9u!()w z3dvVY@G@NS_A}~RYrppBZdYQlBtBiq-xwhbwl2{%me2PCobfn~vA3tltkFQE^*%U7 z3mF0`!^F#Qxk8Y+YqFa3igOr?9jTO^#4oBXP}Kf#!Ik`^EL<4N^gCF7-B&WF5|@;v zg5U#t1=u|v=i?ZdO=9+^6{%ttqQ$MGJ})~J4XxDd6A4mEr1DW28Ij$5b6e*wsDc@@ zjavtq)`~yJ#MXS=hh&4j%4BFWccW8<#i?QFUWJ{^^(Nd|+dac70Mm;<=;6;Gwm9kq^Y2K=}a_i5Pv<=^tn6cbDeA(C9`V<02Lqr7EwTLOaiK!ZnGkJ=jRH&Jc~mT#Vz z)0wVvX5><(>X?t5tr{sJK-e!eO-E(A5c5hjAI!7e}7YBJ2XrmOU*LxC4%n_C5;?qlx=9LzrvN7X> z*(gSh!l92;R77NIVvJ!DYS{(iJF?d;qVwidzQ0!Khtjh5w70>~@bbHYpu#&>p#fE& z%*qVP_J73@@>duB!_>eeGe5OUhg1v(feksv6Ge za@;-eeLh)

N3KOW#%ZEHK~7E7pb<(Kt4(>+mR)(SGPlDtK&cVC1?cf8oj{MdW=d zLK1KoF^gVl1ZC0dT3Qhx(3AZ=0QP4Y;S<{aee&Oa>7w3KtB6@&z6#(~lVU2CP4|mk zQEe@sTTV^uM&fRstfZ%=-$+|jUTQmsajQi)J~#%jD=a%X<=;I5Y8?ZB7Y~chJo&Sz zetmwtKKQL=Dy8nLbRW!*f_3br!GWLM?!Z&mAxikhf!|H5OLyPR-mTB>{3P@Er1V!x zKQn&u$5{U56NGWSJeAwvC7}S9MX-(YPG>x=1|9#s}hL2_$luaF5Ez8xZ&DQ*!fqn;UEOrZj)%{<=L+r zeS|sdJp|hY+!cHF*A{@9$vK2#>fD2*pJlixpl|^ zXYt?L))YsL??7;V!)tE_BO5GBpERA9}~RIdV?duAW$kdfF(X3-@S zaWpZT8HU_{J5hfGwGaPOZQSF}tV?|E*ol_}KLY!zwG|JPeq=>uu5-!BVq*9j(OwKuEt(JuQP< zAb&jAKSZNJN*XH=;#>WdZ<7~wOX!qTM2nMmD|}HTJ?Zo|F*Ftm6Var5&dmoNVmD40 z`uY9ev$vH20Px4tTYv5-2?S2^+EZwr;fv>fa`VrY@Y_fH;l{tzB=*JXc6zUp`n`qs z3t6gt5mUPQgz?3D-;V`S3!}5`106?sask!$rxpKF^H%^tmRn-6Zasg%guQ9ND^2OC zK3ks>XvsIRAx*ZAGzr|kq8OD_-7SPlm^kS)rZjR4qI)E*(ya(%J(4i;p_!+$AqQ3l z7Xm?duUx(Mmp1;5#qNymS?>sb1-qFr+o|I48bPXOTxK{#v2Jjf;oJR?4ou^ApGu~J z0rciAD|8S0{ju0zrSq$}sK>fpTkcYj(4qWU z{@jV;kf$%DO(L5uwahGfm*H^-67$c>mTj_$Foz;6{uxx(SZ(F~B%Z_ICt^2$CH%Xe z|2;dsECAqtCFk^K$4<)?J)N0s(wkq_4I8?pHQy1d3~rJy7gZ81sg*z5u(Z6nn{W&` z8@f2B(oS|W3U?bL&nR)!&-#BXIp{$~@4UZs)tH+I7Qf<{cDTD?f&5PK-Py6gyTLig z!k~Jcduf-*A|BYhbF&?sirL{YVZQuF8n~zbo;)d?|KL`P|GD$i1drU}KZi_7@P7qG zO-yoa;*JI`o0ZKS#8C8qGXqDdG|R?PCRTKHz-BWDjk&#-bdymphW;X*-vDH8YhE>_ zZVr|yDu!^b6zh8KAZw6v%jd3^&w^@T$16*AbJu=Es!ENnmh?xZfe0?Tj>*f`Ie9C$ zFk#g_Gaso*7h$qtbD@=w)~~X0+_s9kg|!e>%}Oh5xB8m41H1D^ns#06(x03E_cciV zjr!7!DWgm0>y=ZZh3KOf3?H`Ql3@EN3fJ?6Hp+ShN&L4p`E~e%opYO4h-zciD$8|v zfFRb+Mjt1hvUI~q2t7yF%gCrqE8fWF9j-qM4*%TmO2I3Ou}r?*7a{fpl=x|D@hM69 zG2nfXV>{f#TH_u1busW}cV1?jgeW$N=Roz&+G5KwAXgPn;J3p6>pcJy(KBpqkHYQY z!b@(^M#&G@bSO+<8^hdSZfqnj-Z050EJ*eSu#V7!MF#8fR zzN}b1#yHLV00#X$b$&DON!!KOuyPYhB8TF!c50Xt~pL{TA2$yB>JHp zn4Xr3Ykp3`2EVX973R8b;Wa7{0A6^$>Wz@1rSY(7NeNGY-K_0ZQRSvixS|Y|N{U91 zT9UXO17yYfi=H1gpSaudLn$7Fur&Ag!7)P3tmoc+_i@S6yR%nuPlW0xwuh4M-rI6- zm2XSW0i9CpjfWq{WzYwkFDa*&?XkEHr0<@-G!y=LyBdn?KnJ1Z-K_LwL#tqynZIfO z+si~jcEj6qBX?7XMBFO;P-~<4;S@eShZcomHOsjcHL{)cF*jz7KJFk?P;dFZKD zNxxDAAN_htR050xC~nODrrq$R$4j`-MVbu6QdUTki0Cvt%5C|UN7LXg0Fo^eb58Xo0DfT$od4XI|ghyU#Qd8aA6Rqy3?(0O7qf*LiC61N)3c1^S8Ag|Nx-*&n#v|+w~cT|V@e=K zqDd4N+d}4BZyTLlFktoWsj~P$%ct2Cyx;O)^ZFf%ZO`_+XK^&wMLCg*&K9(+delJB z(sGM}bPnqMLRTpH%O=fK<#l&%d*(}jUM`$Gv$D0f-omAQmV@c#iX09QB}uUE+h^ty zE~%u2FIB8yR0C$ebB8-*B!EOFG2OtW)_?PM z_7I%}f&T@)F#rIuH`eNCZub}v#iNj+P1pZTSmlA<^GmYJ`5mH+YcKae;gKg|{mXa% zHvwG&@qljZ6%$|1QRSmp)!FYPj^V!cjW67a8|c!5rpdW3G}jJ7jKAM=y!WT-qMs(c zl%R+5@0o6%q!Vg>|J1-<9(>WA;>pSC=U?rN|8Jdin9PKQ?2pGC1CW%21Gj}fR>^-pre2R!UTPTb3U2X!mq*xfr#A}>!IP5=3Ptp9aSEkLwv z!u4~UuT&O-QaDb>Fe~DKISMD>nR2U%NXNn-+rdk?KN5gDmBd^cXpGP^AiAbNWuEMp zO4OyDr_^>q@=7OY;fMjV>^qfKF%>-jfS9$3#KRgFvt-eG=z{zHRRr=iT_PP8kpyj9OG5+>jnCs`L|4UtCa~g5Mq-?}d z>T#4uX^&DQw?`oGC_JAMVkdKPts0r z#(1nZrm#FGM6HU|XD`hvEk%9ZlwO}-TY5>8+N3XfxfabKk{rC^EAZmu?E}|`N%O9X zPZq;F5#M_y%6}wq&L8NVjY)f_$?g3RIv9~3{y?&jU9?Der{c8jktZZ07r^Qm+iANd6qX#>G%XpC!Vk6ua$QrqXEr|l*vQCkvUA$%w^Gr25&&~I!xM|I{y5VlH*ylX# zU-G4^WpEZ#ugg;9R!(*-iRx^JErl-!qnBGQPWCQZFq=&t>2~itzoTUZxbW_$hO+si zB1K?B+}yw_3KDJO=bUP|KSfyJ4T1DVI*7^^>b$-sZ`qZjTwKdq=B?^#L{S1^{NmY< z3p}L>eFE|<<+_zw#1H_lrdY@bD&}5HtUcdnDQ9pDpp$g&Isj^mVIcB?-Yo18Uy$|*l{wOj+2Ojh4>>&IIro?+}2^Ml<-e2@S zoBwGVf;dvc3;xGQc)?7KHV%sJ2)XT->aO{JKieSGu5kWPeqz_^{stS%OoB)go3yFa zd|NE+|7q{L`Kb@64Ka=6#-L=D*NxUmDWo z{-8u$#eGedZLW*16r!A%J&wDq+&4bqA40-X2m6fX6x1s>b>F3k+l9mxvYSSW^1F2 zhx7I6MYk5ALT#d6X^6}610&vZ=5kp?k31bpM5Iuvk0It_U<+%#QAm+umFLOeBo9Lq zqKQ&Aq)UF#QGQZJkzoDbFiRAz**5v;zIdm=z%Z4ofRd}fwK3(pA70TJo=%fzM!!U)I)V_J^NTs&8SifMqD>n16eP|_SAA0Y>l{VC4z;`J9U5A;3LNf`2-UHusWHI2dcEbX5H$=B8c3e-?!kc2;W>PAcw2mJF z?h%`Gs@oKk`d33T^zGZs2DQ{IAd*TT=1T+b7}nM6w%%cj$1_nM8+8HHNzZ<(+h5W5 zPWa^ulnA&kKf#TFicLX@VRL0#2mX~omDAN+k2U?8uy3P+hqGcJ2>kn1(HMnQ2U-8! z-Xs#wZE@U~nRA=ta&m34uw-gg5P~sR?|r8EA>bTm3(|9*b6_K_d$MGZEhrN{v(!f} zWui%AzY%x2VMiKjGK{&^Nire786#TEWM1IvQ)#S*am_Y^_-u`XhhH0M4`HEIJU9v(qL zV@PYzewuDTyhDKq+prVMKo`BMiV8LgXiYaC@v%A9K$0ayCBsVsGICz{ULG#p zZz(=?L-u{3P)uNabU?UubX@24_{6n0`UV7Ab7k>37K=NEW-=P!MMB1;QHAKNn~}OQ zC6Ul!iL~jM4pKr>Z@n|eG(66OFa-oHDT%=u8G=*;l}non;YO-S2|>q~s^miM6`K^$ zIkC#Jx;a04!aOReWUdez34@3P66%U6l`|xgsI!FxG)cEZ7#174wvA51W%Mz&D!U z>inr7LCjFQw7vm0B`o9~%WVY8=4h>)KS2r+DltBUpvwAT*?LJI#PzAXNT&KS7n@`A zeJ7w$s-n9$bH+=4HgZObD#PLF=#erBn}`dc=L_svNTzOopq_%2Irk;ul&(mE<>SB= zjl6|UiiS(t?n4k|7So5bUi3PtG8p~A|hS>F=)$J}X2a*a3_-_CG~$fn$NTWnGyQObP+s*a4E zN7@S27MMu#VN7G11LD~&x^obq7VHyt_3e*ZGl7~CDH^eX7v8u#LTiqJGYi}Ff$^I> z?T|(x%0+9(svLz{EH5x$4n9B>cto|e5`E2vf{xiK$1tKi_gt%!ZKtTV1G;}oIyS*; zIsy|&l8sbyCY{Q`_5_5~z11e6p=;ezBaBV(#fV=Do^7=m*st z|ATa{;}Wp`yY1Z3t!#aQwfp@mIxB5Hot@Q~EIJ?Ghs@$GEW^+R)w`ZHuA`)F z$W;udQB^R+XaTw~NjFWr>)8aj5ck_q1|Ul4@@yzbeDP@Rpl>^_9aBhqR-LKN$-TM6 zEEdGU9+xf*O6#9Va5~lU5W~*%!eQiqG&5^mzm+gw;apOOiqEoT6Jl93J3k;|Vz`Vl z0`ZAON?mN-I59ZoB6~D4umhbWGR%;1tF7xA0<%JK9*G0Qd!jShO(iDi$=EzP!2@g% z%bTXxGJ0^-PZ5)sh8$UHTL(4l&Q~FIO5&JY*JfHqZq`_)s;FE`AKwIuy4_1?t1Oxo zEV#kW5K}bzFz*Hf1gI_?zL8O*HZ>C`qYd7%t;x`2;2Su$=AgT1Iiug2B@#&iBuvxN zWeiTAAWXOSx$dsx>%V5zj-#h}Qx8iFQuR=n?b^m=m}k^p9$rfbfj6LAduN-q6zdZL z$vKUVPZ^8ffz=j(RlB-2T!tKG>Qw}Wwl72u#IWgdr1dkRpPsXNEzm3t<82>#N^^yR zE$88S73QgwY@%FpT#W@3E_%im>Ui=@aOWuQ7v;uK{5Qr32n3JjJ(>gQicZ&BM!zsq0mqNQMx=K_*>%p=Ljfu991i70-VJ#t$ z+=mNx=S@R7uwHYKlgBrs+aWroR=vyW#YpZC{w)@lW<*ENr@2ftIk6V#$8;g+S(MS8 z@-N_<%Y@X7CURHfe8aN?gMiP`!blR}C5{cv3=8rF4Fo67gzkA0BE^)`WXDWRb9Z*) z=B6ZZ0ppGI!R-;TsF?Et31TXI33FzRGfL&e>Lse}&#fQMWQT$s+Q4uc;kC9v%oW1B zLY!km>63zZA7vlY>-o2Nh(_=ia3H4rP6h>@61D`(4M8{0a$#g{;}jFY*MfxJm2IrT znAOB-hOqH7Igyq7I_vUn3Pf`mEiwsarRkK`P)8k?H?iOV+ki#h=e)ToEay}av=I=! z?n2TDWC)A0ZJB~vDzP$@dV$29Dt9y~H?m3zCQ2Pj;K%+1`$}gWtK8b=5FQ_YNI>X$mY-}mc=`7E>^2wWerq_;Zu$yOjs(=FdOj?qF_S|LfLsqs8fL5 zy39h%yuPg&cG-sjZ=E+eAXCzm%RGXoUHkM%$b?5WqN}4rhH)8{T~gGlkaf^CQ!135 z5#dBDeBj^?Vz1E%KpXY@s>07(VZ1hzJ2=&sqYgZ|Hq+#PoWz}m++6$>CLja~$6(O+ z=T6J+MP&{fT-$TL3>+TSC^zHc~favE;3>r{_nU#t!5Jx*wrn?}@djqtNPVGE$ z{7H>b+F*}{aCBs>FAsMoj9$t_FdqxS%~d9#x$l#vkflBCFn~Kep_${w zoQ-Zg1~V1lL$7|%LtwJxWsIGOn)N1Gp$2aK#?vftFM5cm2Ue+^+pYDMHAEkg-cvtU z5_Jf8Gc_})v0=_Fk`0Sz{{zE&OXF za{WeW{wOjaVzzg=*i^<17nyhP>Myd-U~>KLLYS}d^3xG?V3pI=SyuwaY<)@-P1rg5 zk1-e1qe8nT||!@Erm+5h=RDUb+LYHh+Em{rbV}_@r_C9lk!vw&`FBcRIJ<%Ow{FsfuEJi>DcZh;rN+jbi49qfO@wd6-3T=yEHA zvjtGSHi*pN%@WabJE;#-7VSeEkqm#$(VMf1JK1wLA(~;vB*Z^A>K3pgV2Sfi-$ZJE-p& z=_+rfHIzd|C0=n_ki^r_INvZsL;c+Hm;}nAr0C%ZkKqcr9K-USSHf>>91$_EZ4WY> z^wLe#pLxA3%kO8`%745Y@=yL2J8=cCXH4WX}&H5%_=|#u}PT`M5h@%;UsTL@; zyqs6d_MQ!6Afy?g6q_aAAP4JTOC+Se5`xQUGGb3&J8k#u_s#)00yIif&=+89mwpZD zAGi}sUDQbafhK+vJ(aVKCVfN{*^#T%+7f0t@**U!e}I{KqAGLB!$-DI!j^Y&W3lBF za==Z8bj0=~$tW+WLLuY4d-N7h5`jA+C4Feab9WZ3*idN0VQ!C+*3qn(%g|K~BG<&x z56@+CLAnx&JkohzEpx*?e-`5Pt#BEowkqU)bOiSu2-J?(l9xV=GE|~ zEHAuo4f3Up)P(fXNRy8d@8{b^sMX$18MGf8UIu<@3fT_F|6Vg!@p_D@^=`bpGcY8% z=MV|n76yX)KO|S8#dKTHV2FMlljUsjt@Z{Z_S_;Zc2h(J-v?eU0}j1qUY)q|jVe>M zjH!NWq8*t=H6uJG?oOa?ZVSotb-}6;U>Cxb1j03JP>m?TCNB#xB4n#eck!^GgP|_5YJ?S{_!I>TRlE_OM2YlkXTzgyf&gcyNQyzkDBu zKi!m#L0E1^mL>?AGpaeQ2N5b=taiF0mXJp&6Oa==ve?s%$VSOkE^?39ZiB?Ba_A+6 z1vw)-y{H(i&KfRCK>~sZy6P#|R99r`d1rd!(-epD<4XfdD@QKKLQT@Hv>~E96*M#) z+nEWb`uHxHYB2@&JTyUl@V@oS20Z}af&+aC2QcFNh#;IpKOP<4w=!-B1!3dMm)6ld z)H8Aou)-JlEdQF&Qk0%hMlGG=$5(2CN8?B}^=1wMM~-jY911UaRAmr81g1tT>Wd6M z`6~Y|wb-pMy+bzyOcfA-YW*JDW;y=DUS!Pv4;#T(iynNn zL*W}27K}mEaM)(W8ft6 zLeg{RJ3PBO%bs6mr+HGs2fDA#3+H*m#B*YR(ni_cf$_sKllE=LTnR@ljF`Cq|#BEEb}Zv!kuW<-o`?jF&a9Cl{Qb=q`W@&pf2eOoHt+ zXqIuWhOU#;-8-5EZ@;8yOM9Ao3+Bn}0RB1_0py_;v6nIvD6*U8<`QBL1N_eQl;M?AV`Kp>A1yJ@dKn zv!bJ;w3~T`(Fr~$Zd&ufqcePxX&D|p70|ZFKHu}J#VkxmH6fmuovxwHP{UMP#C{}U zKRLg)Oe`xvS)R3QF4%noy=f`c;xxHU1(Z52mLipa3Zx>H*1>uMH`W{=V2b+UZrC0Q zb_d*!Y|kB6Db$#^F($k_x!hUbH`t)^77eQmhY0|oMrY$iyR((_gem9${&tj!F!)y%FljC4f|O$ zr(;XFneDIRx%u4^-@W+0^RgeT^yP~$?>^i#=eJ~auSZ|bd^!Gg)8KIVUt?|tlN9eQ z>YE>Y=Vf1N{=@OhjK24akKtYY!!>`!jIu9P{P&q&{WATWFQ&pJ1AmJezW1_k7yP00 zM+&Rce>e~LX=@(6r8E114ub-MIs~`=K{)Tju>UXwz4ExNq>m8HwqMvH9?F=;Mg@GPz3i zUMy6c@-Bg7%pAH{h{-Ia`f=&TK$o2dBP(C^v5cKw%#SEZjih%guEuFcdGWH~bBbD7 zQ!t;>Z_@Y;cqG#pC{h_7^A&mZY^46rkXLv{e~!F5?fz%Tt2M#3KSOo>eeW-rxNk_e zznD#qdVbc!-mE*JMMo$}y5HHb>P+9CVwit{U;K;ytn!5c>l-k`l={&s9CkBL zH$>UfkuXD3^UTAJ$j}Hr(7cSPI*mycKYLnboY?(^o_}X#&fg))xB1H-CN6)_YX0rI z?B`7-?&=7vP7hp{YV_~cS!QdSl?KLzA9M$si@`OAqmb{ zUzuk9Uj6+fKl&HK|Ng!D`)M%1{rz!?=!bRfPuG0g_WZxT`b&I@ic~yUJNSll3q7zc zsA#sa{lqVkj`_{FzyHgz^S!IAGn}U|nC>Ima|9R?Ld-CPyIk&bwUeutTZ?0BPu$c#r)w4-xdz54(qv2pKMu{IW) z??l;0k;IGF|J@`1q4;@z;*i?~mRDWOOrK(G>O6TSkdUx|fTRnG5vH|;T#^*HGbviv zwY4XY*RZFv?p(hoHa9)(&a5fouzBmmt6NufhL9bIfvjPc3`#aC7@e;i7*<7vg|z8w zwNFsIWqI}wPXzp|<^3~p>3N-RGQ@c}xIe^IQN|q!)vV?ez=@9NX6Gbnhf41bqLurY zZSJtxog5T>4wSE|a)ok=gdYM*BfQTrsWC)Qd=$WfL{&Y~7o|4cm6YXmhA0DB-^L-D z%ZzBLVM+MpdTI<~$(oPZ)ZbCAP&Jh%Nu;q{s|JC4geo{o7bIL6q!VqB$7x2`F_>b= zTkM^BphO;yl=au-U;l1%8rpZ)O=?$dbWzax`m;U>Pu>Kw1`%7#q}RJS6mJ&wO}IFi z29PxwxJ41xUQNlk(M1fyo5DCB119HhnIlA_Vc#MI8> z%V*ZqX;;ql)WnaIVD9C#s#{D|k;-09QxYbExf9Ml+*jDL(R!Cs6fE?zR#+HqG;*P7 zZ1Yl%i{#NjCOUG9W}XAOWl<7El=x_cBx1|djyWwZX`^^73EBy$dzisfeLITZ-@9r# zCv3O%>6rst0#}Y$e|0BP!D`3;4;Phqar`hIrAM{@(XT#z!b4yLfe=*^(Lv&?eyHl( zuizz?xr1$%EKALae%MzKP^Pd-iFsYO{@`|x|2u~(EPIt+c9PT@E7`f#6ZaJG$f=~W zcUWCTH!fDeB3?QQ%6ts#Q<+SGFNkZu_QhmZa)ZVOpoU=O_eQ}m8VSU zrW_3m^T+DNZAuR9g$uR0x~P@(W=vg|yJO6IzF9ahU%H+|V)jYTXpQn>H%yTG92RaF z9U3^C$9T~$%?xZ|-f5a+7yn(=f7;UX@{`O0QK-7+WRx#2rO9s59|r ziU4y)b(s&56Dg#WoBPx1iK8D8ZL{K`)sHmoGY$-+%6Ax z=WFP&_i1gE(3I80mywh&TXLq+l<&6~E?FLxuNGhp33%6a4ab#}PzB9FwgDjq578Kh z>4*5czcO2dO&GFH8>Q`S-5gqZyZ_4y3HsP zkt?SJTIVE)mHfan_~^dZ)igyxHNz+d0*YfA{@l&$4i5Bhp67&5HRL{G7{F87)5GGHa-U@xw!?PU$}kG!<9&7BwT3ZdS!h7@;Y^yfv?eot9P&Hibu<6T2nTj>rCSAq3 zgSlZMK$!`@FqULroq|4^6u}bp)z+5RHpMOPOzt+tObR_$ImLA|qB?yvsh63av9z03 zRu>$MZdHf>wibK4x37e@`VNK*xyo|E#egQ{N7$w;>uK5ijhdCD!z$zjqT2!6QN zCTReZYTfN8G@0MUt=?SK<+@y=@HSJzPVJnlOD}_%Aym^G$$Lx2o?1WU;9y=xx|q^% z4ySJ;)9BXLg_BpZjw*^3=tzt#HeBF9t%yFZf>S;Et~UaX7P}admPZGlkkB=Ox!JKi zjEal}o7@QWCv_#^H>p~~^7D{b@)-=}Y;Ip(#l~dxed1*hALwc3HzlPFk@ z&vrghY&sUiR+BLiB3DM(8B@%@x6DC*oS~)O74@F`ghZ4wP3?XUyI?NrVY!7eNYk*sl3ERll;Cy?;WXE=+LfrNzE z@aUP{Y|oE3-vAuNbn(XW9Z%Xp7c?|M=w!A;r$CVjBt~39%-D~_TzjsuEs5ZI5Gq7Q ziyg!w=B1f1@uC9-E#WFwg!1enof-_wZ>5W^3fd~p>Za7Roz|;w%Tbn zbwHi+RhNX81l@QSZ%UWK%E4<*aq-rcktx}Lw+U^U5)x`3cum+%-+R%NFDykLYeyU0 z;kZeSWzqHW#_>>h*|)=R@HS+ry+&oGMGl0}(M`$e#&KjsaQ55C+=t?!DySEnhX7p% zG&=8cg;b@@ZEdHFC^bYu=V)~aV;(tfDiM$yH1JAB=3>6vZCFZ8)a0GPROLa7CGL2) zXBJ=)*5Zhq)5)4>{;*?^776!P)EB>c&QBY~Hw=4UN0E~Dm$Ij)qb966WgCNnOk~^c z8D_UI3yrL*qV$!$=<`|-i&SFh z(K!&<#j@o_8CC8^VmMaXkWm^d`fNn*mraZCJ+BRzkMB3Ad|<<+_nc6Qvwu$@IhXn1 z*lj6qxm;!-m45Kz`#>igg*ozEVfU)KsS0|>2C7uKzC)BPxxr3x5&zz^vM7S~Wov>Q zh@m8&I3=$NvoqVaFhiQ)C4cQo<6;RLN_CIZDxmwa4*@-u4C(hpVeiro0jcZ4^p7Nu zA+tv^by46DH8(U*oDgN#$s@_kGfq@hMpO~xmq!*QI9JReM(k5t%uLP#C1wLBHL<)e zKlGCF>^+YyI+36(t0qM#6&>rvb6Qf0NWkPS{W5Md8#}+cME7#a7MF&)VraPPwSR!$ z`j62X<&6ax`3)YXx zc=oLZiev6?(33@Aw{D#||65YHIL zt#t1C3jpPW%2t5)A>hSfaF?TY4&&AazCw8q2N?o(s0#Q1R_3DbRbZf z+nZor2d93r6u#c-RtD4yqdnCX*!e5jv%mLj%dHDS26YpRhk(cg0N`ZvuvwD9ePD46 z^z3}Ub#DoUfFP`lg67h!Ojqbd`3JZm=_uc0y-dBWMU|l}`gVn~)}esCJMD&yT}c|@ zHVN<25dTA*LrBCN8P%`L)`37Hx4N#kyE z3|Q~fd)wZ7&so)%Wi7Z6ZcDcL%l zw}mKkJyV4He5N}=IKDI4KIkG2Id;&W8DQxk*$+Ci$Mc3AKj7;x{Ap>|zjP7)KO5)( z9qe0`+ezc5awWN!ReVbEr4h^LbBH;mtD8FPiHwE8n3 z;o0RnC0#*G7wG4TX$odE3q)plPwUA9M>b*F6Nz^MGbi z(7d))AYk~WzU~9&{Q7OZgrI7z-M4et`a&Ilkq^E? zi6j$JD~vdOB@aA)ZuI2V7%KQl=lQ`vXT@jUOp!t4glJE*Ip=OWRs^z7Rh`DAdw;We zX&!zE*t-7K3;cv#;8pD*fbDwDRa8QTT80s?D50)0XS>)Hi(LA$rRFLw+$yx^ z;YauYc#_4g_o`34-=Su>%KwofuI7=ar&q~8X0zje8~mx*k__GSCKmU1{jd+L9s&51 z2F%lxAhye{u8VC=K@d%M5EWWHplAY-j|KAKx}-2wDw$6H&`Lm@IGd6^RO1QN6T5kr+7;UhM&hTF;#3jP~@o=J>=Oe=aaGJ19C3aVr;b zD<_F8g#Q95xeT{5P@Z{4d5B?fD(}fe=ay|{1pTd?a2!xyuu{|m%3=t()+Loa2DxWv z{QiP+8gb5*QPJo8+@{apOHdCLnlPx>qeXL&mCSU8?8TlmkoRxucZZXvJb-J3!I6A> z49|?GB~FFyc6ut(xYN3yatsMlicE}Cxu6oNp{XT|v)l%bmTZsmKZQF(k?&%(usZAH7&i{we_fwWc9iQ#LV z4~vY5&w)VwAI_ znRo3;E%f=RT=mj)HU!)fU)k{AOv$c3^I%6~uLE66KZD4JTG*&UNZ=q#&Id%_SSOXv zcF%aGOVjNbjcJ@d`*q~|izfLI9e8JURDASF*-*dAze}9R{c@GmvrXx1wLc{Q{txC% z55C^$S588be(63O^@>$Z-3Q$0|Rkey@vVABKcvBeA_Q9sVMeY<02Y*6L2;Pp6vI-0^$?72rq z4UNKc5C;=iE4{_+7T_DKxiU{zMP>HM!OgavLLV;KMDWw;*smg)>z=zqT z2xzVJLgR@Y0zNbnTx#w>Btv!-Jg*nCyw_|4TgCPlN|31ndatFpn^u=|90H8>JSxua zEKd%DZnbLU>XH^NH^m1pWKG1gQk~^5ZI14l!-NkIt)?Ni_hF2vVlRcM&B!MaaPo9Dz>N4d3nYc&;cgFKwI?wl2EK z3n6>00e*F-ZPG)?{C?sQk&=Wcb{w3Zn-w2H^k(?QGCy+mrJ9DpI zF4m|xizR;H5;?G3zn+qUdt8HF6sb8mi;p%^WWheF17X~hzJCU8BlRL6!i-g|jWRbn zA`RW_#uG!c4S^nXp85_B_R|2EV!vLL>K~l%pMLmhkhuQ~SfPJf`|mFJOT&P^tLHy0 z{;Vy)Ur%)XPpkg@1%GAi&iD2FXXSrA{62Pk{wU{A$Q{Lw26wAI>j5HvLMjf_drlS* z2xJL?ba|!djpTJPk7f**jtU2*DahA*kr?+wbPG&LFgZaHcd%Fdo&h>`WP*D2#!D!k zh^QZ6uovN}7=#H5`GPu9A5CVlQ{f+$G`3P zY1H^vyvN9qx*WDrjL{H11zPhL6r3udqm9gNYD2UXu!llspqmZ}N{L4~^F!=AI;Gst i_vZAk1QLQc^jjF2(P;Fdj7*o8#6KJL|35r`IQk#-CSI;*Mq@h7GRAM0M!)6~3RV|ejXkfo)ij)5)slDUJag{Ao~ zjU0Oa{r5jS{^98pCr+FHR`a*!|Hse4bAZZw?_N5hefW?r;2o7ihgA+8Gy^mNhX98G zhn2(q^*M6%*x`5IJM@n7Thwn30S+BL40!k56DQw)@4ch%90nYE=kU8nj;b8{=(ix? zXRf#2Q&rcsagT_>eV5JdQ8O^NzIqd#`}j%av#J-DK1W4H|L%`JbZh8+Vue8FP)}P} zI=Myt{Ps%V?~BC>=)K!7-zfVytL$6Z|DO%uzxq&qXQ*-r@Xn#b@4j_$HrX^x-Xoi@rWx`Ji9iN5cDdm&5XrX(hrq7`6fOs z^nw;qvcP@`7t^>M)CeA!AP|Uc1VZW){PEE(pMooGJyym!Q5LXtd>)fYW(_eZw#z~b z&8SIoVxr*tx|8QNuvDKmmA(Lih z%)7{kijHSxJf8JcpHtyg5$VeZr(ijrCx*uOcZ|CIj~2hwi>iR;-t`h z_RMYvVJ_ME+t92&97(*cGH7FND#qq-%20%Z|by$p+%Liz_#@5qy!U3FR@hu zA`0I7%}OwFyRt$YsW(Bpt@Sp>JVx^(ghPwE=rt$qD|$cDaNMEc$Jej=Eg#vhdA3VF zE%T=nt9e{igjV- zGZ`4E1IOyerH2SPf}Ly;CYekvAt)a?;oIbI0f2XLPgx<}R&`hmo}zuiD(S)G7;VgF zWF8hdGrj~bFTfXE8qWEGhbtW?Ul4MvU|YqM+rZZVyBJKIs>HItAQSHD0D}*qP{|%B z>5!QZZK`gTMOb8zWCjz*KE5ZA?u6cW^(ayL@@e20VLVJK;J{rMn?;}g@nvUoZ$xn0 zi*|M{s;QEPp7enGPx5cys{)*~uZDTCN|w^mfs^Q_W$oFe+@wFc!10UrWsvn5Vd6d(3eswuCQG(W z+x%HBE# z_F*6&1XA@-IIAB3s!e8oQ$UY=BR6TtEf4C()h8xbcxSi*{SZi3n3I#hIdRL2v!}Pt z* zXh^$lz6^3HfAhNqc~;}9e2YFQo2?ymH<^&WMP7wkHVYKMK?!L=?ma+%%#$NL_X~AO zuZIGh=e+y!iic=2dg-k&h|5J5-)Nm$y$F2JSKzEsQdu8{@y4&ypU~6SN*XjW9r!zyTDo0pAdl%-sW473& zEDvwV0L_5u5FrJDCXUq~%bJ~~KRIi!_l<~8K&8M>(o(JsPa`U=&11D;KFp@)2q>wD zn2!1kEbc76U(^F`|7M=bsH_Ydc*P(Nyv??P@gbh+rG$-33WJ6d0~6A$Jp|6X)rk*8cNZFdu8-W+&ZbLW6<0{OIRWL>*aX{o5AY*}gJKx+MIICHIOsX7 z5#}Sl+pqBqi?oS+rb}@+A2qq+Do8x6~aN+eQcF&f&`!gNS^47N&Gjc#sFl7qqLPj0xZk@4Doc#KR zNAIvYbAcSOIN7aXMA+QSibS7BWRUmUMl{02{_eSqaY-*%6)9mjB)VwjBEUHlgsh9; z=I7v#?7$^-XkSS>YC#ysF(3{VFO+V9Q`(P@LH%^M>$;*)-z71!&i)z1>n zrmXcfK`*Z)OZvj(axrag!vu+YV6VW1i5=j+ad|#G$0yhvZ0Go^mkfD*I+~~E-vF=E zr6d?~oJ1g(95!KzM2WvyL&?3$;Z-G>PQr%T1=W~o;O>_UyRn?ST9aX_ur6$vdV!js z9zx3>*VU`jJ@lp_{IbM)l0ywy+0bAlqEQNTg47zhM`rU?p{?8fLbJ?dBGN z^hhz*?!VvC`opU8Y>n~o*{e)Y%g&jcOxRWkE1gl)frWV8 zF8m1Xaj%DXKavtuk$hL+Of;r3Qr4!&kCkyw@=|N6G=+hXQu;Y{VzqCq#6h9Tr=U@K z(s*F}>V4Ld?{J>QGKO#beS-#(f7)U_|&eA(2W zg^D9&M5w4h{D&Xy!t$u)+I`#}{|rJl6zNHod(0DUvsR*o5kMKalx843mf$=Sh@ZDh zvhAzd@$6$#O}!s5d%KaZD2s;j{C&;`qoq$ncl3N{t#|4R&2Cn!M5fE7NB0z9@7nd;8F%=$Ac5_HrJ3R??lW(o5jc zgFKMHisA2{4vWGyT?(tTc(rxV{>9;DmdyXQxW6eU7mvO`T*NTqi!7a@ zOk%sWif@m;>|QHypQ|{hjrDADOZf;hCj>%5#!IFUA_jo{IxNJiUZ6J02%Xe0Kb5ao5S^=PxUCduIo$5t^HtK5H>Dhi*UB=AB2&-wrnX zcJV}NsTj)SVBh$#f}3cQNH5J=o$F~ua((h=ri>(;0Ai6B(} z8_;qX0xwBPg1Z8N%h#(Ws8aQEF|-bqZb;N62d1S(0)%#7&%U$Y-c>dr-mYX|wD5QP zm8_#u>?DdQCFevz;D-8ddL)^m>UCPBi^Qbuern`{&_sNoe&Z9LVoCx=rmII%+-p1Q zPpSwP3a^@iJ*rP!*X#F))t!`pV6hUvm{=$0{cNrJ&r@)#P;Lz_XU)Y9WFBG2Fy#85 zZ)d*s-GIAV@_*@RL||3!7#nTRw#pd9LpyM6bpN-kvg@&n2uoNCLd9Y}s79~GfmpLR zTO1TxaNV;fVh@a5D7#)$4v*VKSP3m8l>N?8hs)H}FMIrpe+=F9wth-V(1W(IE+Vi~ ze&N?8Zp{d!!+MLuIxLD0wBUcbcI7$90w{3#XhXuF@hp+x6&UPZvrmt{&FC8fQQyje z5_kZRm*QSXcT)WahP0c9`kt|-x-oLEYENQ067eRK96XPU2~I~-g7T;Hi3#H&1xtgc zB6sF8wSW26&;h`i#|(XQ70oX8ZEYn} zi;int;KE=VPC_*oopVLSdn<*{tafbOm;4ItrXtS7ReD%Ti|c}ji&e4B8=E|ue|^6t z@9Zd{@ag0Mpm%DJCG?Hud+Xa~ImGfQ+8-TjoM9FGfbatXe_4F(OL>pB@6H<77gV6O7hknUs`FB*J3rHqbucPAHFWB+t}186J0m&=AQOPd91ah_Zl$ zED(d9CD?2Dnm8t{8kY`9B0)4+cBI^TIiwnI%*GqEK8 z*U7Z@x}#u1pN%+XVB_b$UB)%~mPDnk`Swx~3NHmn2A{ro-N0cWZO)PJQVO zA7U^HY>}N>qYe>Keag^d(wCc*mN?!MxO#a-k9K(~T3=FU?f`M<9+Xg<0$kh^M-&S1 z75g4Rw8vZ%*><~dmRKeV`hHH)yFXTbjJ)mFpIi~0%aGEzjMnqXIn}`NjHKKM8F_m} z!NnuG_TYEI3iU(gMk*hB6;vJo1Pu8c^8i3Djo!BCHXf0FGJ9zwo+Y)_Cck1-_z5lX zTk|P)D8v0{l9_a7d5^wk(qbOgaVIb60PvMx!-+8rnZG)-cgYbsXZ<}E$=6g3fM9oum4fqc0ist@5(R-W9hK7B-X%-vWC(jQ>lnde#(`9KKXNPr( zAVTZMWk?<^l(!Puoss1yzjCup&RB#FGEn)%AtsA8qg;a?y&9DIiT-Z&>A`Jh32f}z z?OS4yMraEcnS7k`icDn$vMGA`(~W2Qit6gL2Fbz^p{|_g#m3zA@Hf%;FF7Ex6or9? zwOBO^vqk9n1Q)NKyPYu}kv}aCv8^T)uzpL?&4eAja(x7SElDt(YNM zwd8XmS)8W~2Fj2@Nhl>Or7eu3<7C>UaYyx0@q}^z?P@n6*@&`5(@(w}mzT8j+r@yS z$VS|gn#c7~YbWk;YH&w97}aP~WDYis#8_*u@UV0p98-abLE2s`pBwyIfz~~P8@|*# zOWGmJ!FS1vo#!bj1ShC6(lAZR&zjr%*>5Hx7z+kINz`m`aS}E23p9#fNGshCKuesH zNGoS};v2kP(jTf00QmAw|!Cv-3!276qNZM5gDbZNw|io8!;T9$mD;e}6U4W~tvz5=rRb_{}QT=>52rMZs21 za%%b6&g4}=Zv_GxfKbF&12qL6z6v#GE)1!2PWqOV$Cw}Pycuh{Uyv1WCmJS3 z0=060+xiA0c@=e+MpYVcI7n$^KHW5(*6OFqzhe_JLCUghZt=&)DI7M$l-wZLtd0Iu zI*J@s=F`r|PfJUulQCOp0%=9SO8&lnNLJo*4~c|pdNx2IMnU~8h(%HP)*;F2wF5wT z%>iH^y43enV*;T0Tq z%%jo7lO~NEcgpr0X`CD=vHbtsFGl&gldE%Hizu;1 zQ%w#_asgg(@JgQ?!R2<;0SjwdpzKw3u!1r3utTJsbkK(cA%s^?=eL^Hwf)%Pt z+$5@^n<%4vVtXBXZ2ZUz{$-z@^}HLm#q?nw5**yjO-3zo*TJ4e^G0><94_8&Bu}>` z_NS?JxCelD`VRoPS<$7usxUbhwC1Oy zVXX5YxH?6wihv^}YA(Qe43pB9HZ26KY4?o8@ha}#3cXaR+MS#g5MC}AX4xCjf`lM& zr%SDCGNua(FR<26RAVL7ctp(PcLl=r! zt-bQK$Y+s1(VBcL?@Yk>;SYo7owaAou^HP)32wcTK*Pjy%&UAeei&ky8z5zQvWt1=f*`Hc z#S@62YwhFG4)=+^0iMeEGSpRbrxN0sTB2f~>hyAid=i^oN-;<4*P!R{Lf9X21&JKyJ=OeNJ+F9>z)D6AVM zZAxzlskJK6Rz_^HVrE8vZ?nWOIXtJHv{*x@b*n&;E@AUpy&_7;0xg9JW}AO_0O&rG z8QHfbUe+hQ^@yGep;f3#;2n?nEozA6CjV4eok=*{S-mu^U=xVclCt5^>k0KRQHzNg zEi)?xCl8JHjw$7qhEyYQ(mE8H`A`N=Gc1ikD=Thk8j531}s#k#``T= zUdi-)D3LK<0)`z>ht+&4C>5AMt zhbT594oAn?m9Ok>F$}WiD#O+qqLh|i1wuf*I7rPpl9>ftQI{)YU?O5ENv715U!=X8 zcO_18dzJZE+$?bQ>&O9(r&aszQy}hxGrwE6JOIp>C#V0x@6bYGrp?*)+1|TIjLfg3 z`aU$G#s7mKGIKl;8R4QGOj^vpw*A{BWN2|2MprMRE|+0MT8^{N#U(~R{}fAn7Ti3m zft9jQhO2uFbll=RQuP2Zx6XcX_Ucg_o#ELm4(pGy=91V@?szF9pWF~$#AbJnM(a4; zC<_0Q6B;0nVu(0S2)~hQ!DLgUPHR57bZ%vm_?f{>#w%)O27N;4s$q&zN~=v7Ic#Kl zS?FjCoO#wFAm*&EsZWrLO^u5p^U3sOCm#5d=zF<6C#%t`0}sL+KO)i9TM$6EnA&-y z+olYizvAQ+FT+Aog{27=-;9lLNyo_zDQXK8($4fZb3%4`@;*|_+u~^|CI9|?B~u9dkk)H)&johEVedGtLVvwy3aBB zpgx9vevv`Aw%47#PolH)dX7E~Wd`+-v1X9GN(&*vf^UU{*i!6yREX^#SPKjIXB=88 ziiq#GI$`nrq);=&KwJ#&osj3{kw31kx160l+izJy5- zhff6tg`B0`$y8sfrA|McO;0>AP^1;1*^C5gMu8PZbmu~wvElrUpExGA+fUQy3u=~8 zOTTYYhNLY;{(g?NE{Z$L@Bly}54`Hd zEmpj_C`mc~)k~h`ie|T8-7H1lU=;@bEotWWL+%mt73XviZ4JY{oYx^#{kR1gn)Pa$ zuVNv~E36K?ViB|WpzHu}T^LU$!X)qvkd=#f=>jc(sYvxQ_+DkKnok8fge-}MYDAg{ z{AiRJ7MYe_yX2plXO?B_)b{{9@oyE}%hWU@B_jP3WPi z#==;CEWN=j7?d0=t{Q!Uz>pilV$u1G&?1MJy2{D%1a4lb_7}74FWba*H+sWI*vLy; zRl`lFCbfuO8oBXWDdWD#89rX(9uQC`Y9cnixUB|mLm$_gZ_63|=xte_9hEhzX=%@)uT0{M1&T27TR4x>tBV!T7Mz zlnuTwG>s)ux^*DfI#N`w;A_V9?699`1w1XQ_bcT@&n*N7aMgS>a-I4km1Zp~@EO@~ ziLyVi@$u=7F?Yv>^(Kh4S)y(`8xdq-e@H*!z zyurIw)xV8ar+Yz0qLFE2E(L{QTv|CS;Qi|6f=#+^cY{@DE1e=hxLuFwqT?R>j~v8} zdw@k850Al)@k?Y>c(N}~1>wa4uUsG0{gTcNHdf)ia;v)`EyvVnZ@ zRZt>w|LR0=OWWH6fE&88!h_v2600$nHfuWDjwC2;6Lq3y0IEl z{KmuCeGiue!s}n6G>8H~kT^nm3gcyi3gp#5TOzPR{a?ey)NoS#AjFN7}| za=*)sEXc9`vjZlGNsL%G%pC49W%jhX>-P?mV>(U`+USPT|^sJ0W zuxj?@Wn!l+<79>mRM7Z5zkM~drNG#;4_8y{J|hOv_8~<`^=A{CY-lISkjYm8dyQA9 zDrAHqGrZpF>F4CK;Gs;f2LFy2VJ)X`KM`rcU;FH{)yrt_SF^@H`!Mv&?w)gJIl06j ztUQ``k^J^b{MmA(`{UYhT+D@P6k!7$n!o22=)K4$)y9+weZFEDx3zQoS*S~C3Z;Fa ztE=nKwRY-r-p%#FLDf+q$C@2;j*`!Xx+##V5iP2s7NI|uqy2Hv{$KY5dl22m`!&A+ zP#R6%KLkAP7(D*f24lK&=m@>rAQg%C|E^%Z?qT>S+hUx+BBLSL6l0y41Hk2O%BPweD6N&VV;bN8z z$O<9KDDQX`H+Ysf(jRsk0TuXNd1u!{b)-1Ge1sN1&Il4|Rero0w5M5+lO}jUU1v3x2jl?sBE?@SB$yy+dpi(L?%HyFvV;to$;-ZbaQ@b4? zJ=;3jR5DAZpbIj<-WSJxctT6DODsrg1rrEF+7Nr{p_#Dk?wahM!qFo=&sLW3kz_;e z4P-P@MM4@6WI`R2jMdqXXUY2ou`ZHt%I}Pi$O~fi>JlqK!@y~xB(~V+9Ho#RY7iqE zYbv=d`aMlJWJqHwap?@0LS>%b7%wNH>@NlGeX0!egk#GdgfsD(g?jpl`f43O^+2U7 z;Ow17AkpH9gVRL)grCuU4JWK0g&Z%H;?Z@1h zM@eR|N}FdDk`~Z7%^?N}xj@{?<5&ug4TIo)Bv?b>k$qCLuh3$9Vy{MJ`ExeN2{%HI3_Rl@rml1>RoWqaeE{;C&RZNYQq{P z>&NBG(>TD1<*F{gA*ay>^_g??U-3J8=LMD7=#inf`MKS&5jq8BG>`Cbz$y4zD>CSe z*89QdLVa5#RZk?#SHZy&euz%YL;i!4t8Q^Y1>kxA~vqE9LOLx54p}LRKF|7y-Bwlvm29Yem*gp<0#gcdG$p|wRic@1rK+h>P%n6AvP$l?rQDF}D!P46hR@&7Wkxs(8Tx@E zgfz_SPv;@uON~sMM@P<74=cpb^bpdfENIn?=TWRx!Cpe-&~Hg%?efPh%$aZV^hOqG zl(zh}O0A3^0RZFS;^5$dmp2}OLr#?AKoGC^ z@gB2oW!h1{W%pv83@slyJ6rq$CUTGfVa=imrvGA2Jw2?=iBN;s5@ksc093iK38%q^#LwxH1)`gy^^+E4Zc7D6~*fLS283tpeZ>a$ zQCaxvVP*&1br`sv81npdx#$XUv|x9*FXr0ay(#~bm@Rzew8C`9z8KDVhAF7Sfjdam z2no|nw}dsV{l&PhVOFGGk&bcxheW0QHXky1+po#LxV$CSm@G4F3MHcB4*<7&qQTm& zV_k1oA6(B10>^ewG3e zP^$rhS&%~)770}*S!KQw%X;B8`St=571E~E%WLQm62*{8n(pIgrX1R2q+?wzkt#?l zXCQFmdw6))3VT+WJu@}80`pLdGpZP#6GVyJQ-mx0jHV)c-$To~x|i-Bi(7?14$nl5 zmNL*7_lj;*fyxc5c0)Q7=+>-2s<}Yw5<@pXptTK<(J#fz-&EB<=%`sX-SnO|s>9?{ zbnWe`#DfEJZ02KX_zAmD*UBz6z#TS?E9bFZq$RS^5^-i>Q3);N{{E;*RM#7hg9H3* zD^oo&T4F7$kjJ1L^*$T2KlRz5XYNoB2=kwt5BJ|T->`D?mDa7jFKVkyIb}L2kn-;N zS;l=ynkG|2@<}TS!OD}&IK zpC7|2%0kc7(XQeup}Qj)Bn?9jz89h9;U)p8Sj&C^k$GWY=6!b6aXh3jR$m6Ln`0Th zVvw1#Qdt5@*HJg|(B)AuFxY3plf%G}$hpi_Pg*k~GcrA7u2}+dKtd5BR?*r0ce1LK zraBI1P0z@%wXNMQv~Ok9tGHY%{NbIS077fg=LrZb+BMIQxlMs`(@P!=l`_%|I#ivUT-LY~%{|Xm3zxbn znN5)qW^*L3bxbprap8f_4+x+d47SootdY0GD^)F6zg59QksSG?D zX$5OWKrKX;&ROkE-x{5(C{C)b#}o|FK5Px}V4m?@i?gqfP&jCyIk^Nf!*=gN)?X3{k;R9%J(tD`c^Eimb_5q`87=7azOHJcTJ zcyGWvHts!^d$BIu?-;kdI$F8w?u%kU)Oh}~3&sA{Cx^8q;8W)UP3smzw(7orR|0;x z-7BRQMg77Ey0b>taItIbqlVb8c;QQ7KGcz2cHiEK`XiyC3tzEjSZv+}4YA-g@+*=lo~| zWyxpPb4AqBo=RdaB@J5P15K^_3OsPuT7HS-;w=xyj6HvcoDYW9D$M)UKO_ZRyIOAJ zE3G>^M8))3CHh{gorl)V%cfjqR9i;!1w_Sa+jlu`;vZ+uwpQr0G(fYCpeyE)!#bMA z+gMSzC1cm5-Y9%hu*P`Rb^x%CEL~m!ix6GyBJv+(j{l>_Ih?<8* zse8tbFIM)_vi4r4N@Bk}0BnZQ_a0?ES!%>t901@_(5Ao;}rc{2DE4{d+l5$ zYX7l+UhYI?sdoX;h3B?Cu-_xctd$j5O4*Sa59f)>BrYl{umkuZ$LtvJEB0%4#NEl^ zo#C4ClHC$xA0Itvle@dP&wMpO3=XMOg9{RJc9}7_#AGv7s|tkI^y);%rXY8(CkC6< zsE?pU(@DkB>iZ3=125AVbKQ(v&HY(Qzs?BKp0&5`WVzs5mbl>Kb%`UN43yH0I58-8q->#9=SiZjtcJxVRL{qWM?5 z#gq>%x0EchDjZ{TmWqpcu@Ll*#4JqSl;f9qSi6){GN-;{pj)9;5H&&XfH+1GISGf4 zX~14or`|_pTv{(q52iVqQ4-k`QBy+pnr4G`*5gM_(#@+g1);~B$jV&CHW5$gu@Y%e zfs-S~EZjDtCb#03;J;t54GXE7H^cu>t``>g1>nl%U)T{bS{hU(aOlFdd1#)Gt~G(gSmH3neEEzs_?A0 zdO5v5S~x+IJco(+mzc4vV3Gy2vD(U{NES{20GZx-p0Q7G_- z@w$pKNL1-;`S(LE$1k7IeErKb{zcCz(Z!}G<-%MN>FTSlr5KCInfWV zJNu|^Zizsd(`!?0R`4@8EiW%}tv%%Z-K%>GWEYioj~ik|bRnekr;br@b)f&GsRq zf6;mn_3^-+&=f+!syM2!knr7bYcf4E z6SUE7VHGjCZ;%Pxh6j3e1F5(6;9Wm`S}SK~LDdo}RRp{ByvgUww3xzx0HUt33gA6o zz@e6$$h+gCJeZRN3UrH-3O=vAUxF1B>i5xKulhV>4bpbKvfhUxfGQ4A79b$MrCm}c zz_f4avY(V^Q7o+?Q{uUTZ%FL^NDwf_%GJ{NSB%}1m^rBC2b@;`Z>cEg7%+L*G zqUS{<)By?GZX?eU(o2i^>jZZhcdqY{LLZ^CjFW8 zq#OQG}f?|HQ{1tqcvJTHvIHinl(%`+6)tmcK0n^ zj^B)~x&(+ftEd3H^BgcQYwkP>b4q#3*!!rsb+91?^+wv#-ir-*5b6=ytW3@~@mF3A zDvya@AP`ZPCYrmB%*R)JXnyNKPFZQ*vxp>6O?AiV{*a!^g;5R&&Ly?XBYpvOEL60- zXhC(q8QQa{2J7L1CIUxSDFIJrE0OMVv~VTh+AL8OMDg!BE2C_(kl!itTt*+r#n?>c zT?n})0vqJjAFEF|8^%=3nw^*>&s8F|^U}-LP=t9WoIo)sn^Hlx(Qo1NijV8f37lL{ zD^QJ_JkjsxBlsShQfyp^u6@%Nlp?>BMCNImz*9+>hmmN8ve8N;VNT>eeUrRB;u0M( z?Zp?_JuJM_Xm>YL=Q6ScpnX0nDusnhdGVo3pXUVk5YuN>wmg{c5M_nQ&f$}LW4O!f zDLbL5otjC}v%eG8AA7R(?XTSbCl?NVHERzq^eGNYP}fD5v=pp1#|nn?xhgsXJ|i9` zu6U{YB0|m87jA`6rt*&g+ALvX3~%+L;b4wphE;(>*=FVa@ViR(LjMynL(XGEG`!ki%F7EVpFhGCEjdQ+6zT|n`Vf11y`?gVrUgcRK#STmYS_iHC9pdJQ4 zD;5E*N zx3T}j!0(?%^$(N+_dXuS7tS7rkNm**IEJKJ?zSlqIQuXU$bz%xCYAI>T));J2ejcn z+}Zssh&Td#Qkt98dSMUSEm0QbK=c5e9BVI5jV>)MhQep9h@;`4QV!lgJ@D~w%c`!@<@ zV4TIB$X|}oT;GZdwGVQttXc0XDjpaQZf3)|3_W6l-x^XOv2Z+RHE>!DE1gJ)@uwv} znN3OzGuO8_l~OwL0y{Ku&OB|qJ3oOnEr$cf%t-U>jmYHM)S085pZ+?6e|jO=E9Fc3 zK!a1}nexYj^RjW*-d<4g{z{hC%I;hsXC!TBfY9sUQj$-|Jdg1X39gFzFz-fhM9kge zwga)Ksf^yWQig-SXVEA8=$F+W5v05T3lt`A`E4EPiRi znVf8@swvbkpc zdRDtM;CGw?_=9{(x#yOnjD>*QFlbEbL`WAy%J_5sh34*x@}RHYwF3M`vu=dQ5AC%nagN1}J4?>F7}~cOTi#gP7^0d$8<%(r)EI99+wv z-fF;0GOR`$A~SF$#A;-}8`P4ojJ@YB+!Y2TO!d>ljP(0XsI8gDFslSUoT-cm$2%VT zJG!VR`=o9(wh}jr-RNzwQ5AV-8lOZzz#D8K){zH*rJ7rG)cC;9E!7zrs8I-*fhxe2 zyQ+$voYQsfb+zK&IwdbCwu@dVZ!~l|_I|wnuv2V}C0!ays$(|c@LRUAK?Pj3Eevyl zqE}~IbWt!EV4Dgds_q=&Q6A#H-kU4$bcz8Ibv(nByqfk5i5mw+QrOQ&T{ruK9 z1*OarjQp-&f&YBCNeS4=M!0LvkiMdz=bItpQ=NFW2S^h!A4DPs38Zc(e`p-vSNnQ@ zyRgpXW!&6~^X}7Q;dfTE@aRXG9@s#{MxTk43yB{uNyC|}B3V;N9VDmkj{9`u=t+~) zE80`Oq8SV-P%AJETKA|=)a7m5cjnXe5WS#p?ji$j zn%*9zNi5u&1x`x9L8M~ACx7;_@jh!kwWi^eBD3fTo;RdDwCdPuo&1N3?=;OV1t)|m zajVnH+ZfD-$MT9RyMaNo?>zrMudy6{!~4VFJ-yqvhl`nkN{<}r;C$NyQd7Hu?-e3; zr=K+V$xnshbtcX^eo2XbJa;9&bChgjO>i5ZQx#`}N`{Ca<#m>_eVgTwBRp#PJJw6i zb~jAipf*cGtCIargNmsB2uK_)gucyW@Xk#KiB(kUsxGB1q-B0C>Ph}n<6o#B3RsJ+ z0$0zZJh;23CmHQp?|-}xVy}Mpwb}u|BjL)hf9htds0aM(aQ@L6N$mQX#v9Q3#H6+- zehs)ampJFToP&FwetTY{L7xsI!``3C#x!AX^4YwkqT3x9Ug}1r7TiL zwxz)3b~8Wdgj&%meM9YS#j%Z_zg~O43d{&j$tc?c_Ud=7mpzH4FLF6@~waStNeN0^%ny;^y|V69d?{`Su}p*e`@L8 z<-ef$r@kCb=_wlVcu}u27OYI{f9hCUaX-$n@x)*DdFB9cEhQr0gSRP3KmM0w|7WmL zwet_L+7+B{EVD`;z6}-j#$2~cf>3B&j?3@UH%W6a7_J$&z8*C&n-qHhIHW`*j()4e z6<7y=*N)Rc{V8vCR(=XT?6|$Oe|R7FZ<4>{%bzXo|7HzxBbM33uy>R=mX3X~{p7`5 z68!Bx@I{n|=H`vg3axNQhr_>U>?@1#tLxd-)nP8$1yKp7POd}iuueh?q^k0+sS3y; zO4}1=yfd!faIbcTs?T8bEK?2BWavaSzi*koBfN<(hZJ0^i}2$XM+;P^{3;2^VH;Gh z80Y{;AT2;52V7Kh8E2z)v_%4{>KJ-}P=@``!mJ~{l7RcurJxqDG)J&mpJ-fX;G9ny z4!=?C(Pt&SqAs&apMTyi7;lClfU3&0IG7ORfP;ymKlwCzJ9sw5UGUabFtgd~!|k15 z0wWu%L5{t&;o=mTJNd0s;kw} zkJc?heMhJ!{qR~AML&qxMjRyen>5&b-Z8Y@_%tUrdI}YUQO6>S{H?4jyt&RQH{c9I z8Yw;SnLdjSE|k9Rim*Ww^0G+y(P*FI4@Ugj9%RG}GK9+1bfjCq3P{swv)+a5zR+D= zPmcI0a-Ok=qphh|1S(VJ-N#XO-AZT&B;enTcXNQ>C=bwx{CdvD+y*jM{0`~CZlYaS z0Ex^#$@^wi=;+l{8;y^^!sE}x67)$Py zDv1aP)WWurjy_WE)nCP|{7^x3)2yg;$73$#+tm$*ujBRYz@lSsE^#IEYYF&zg-EOZ z@Rv%t_8(${J>Rr>YHPsqP|@ChNfrq20PyVrpzz-1|C?!4JF__26}3NEr7&@CgN5Si z>qANY*|b`Y$Gvph{CR<3U9i56ix}X3`HT1VD|5f^jv-e~bR_|NXCy@b9=if0h2}CUXJFOwzuat?X1?n7Ytyt3$rC>})nZhI%;A|DG`YN~Nr%z^wTEUmLDMcBDDDt)< zTwiDtl1|mvMHvx@aU^2m@_T>7C;6+^_vOFp*kt`R3*PC}Uv+i<-RwEXFaDpHaNam& z5q`|GiCwwc5Okxn>BjU6F0$U2VJcB=mH^#aER@-yDk6$Tz@HeO#Af3ft)cY~k~mMi z8!)vj>2RF2GDVIWPavc#f8~>Z(>Ju(&w$92)uxjtltB^oq@i8o&b`)e|J!E&2VeiX zoJ;!gAFTd&$PPQsuowH^_{T0<9!=>El2*K^UmE#4GVJd(^%n~HPoB=-t?`e2`Tr&> zPn})8ceXLL(F$y|SWHqbzvzFp_vLX-UfbGOkG9n#7D22sSvUomMJ5>nwgs^oND)G0 zt{_7gg3Lo0Y&|N2Kq)c=BvH@+34<6yATgj72%`}~!Vm&VWC{diNFYGs_uAg0R_(p_ z`{Um4{(j$uKiGR^zdL&`-o4(v*ZZtz?a8o@-_MkDvLbUFdxT&o=a|iE_N|-t-wl9z zVQ0HKIw%zvpiqE(1J{({oG`SArhD#}*jo2}N?d#qJfd8A%|E!QMDi2VXdT#bvDc@x zaMrldC|y0)m0R!)d(_l*%LJV^k8l>R)rL+nWH0>;{?E<&uUj2F0Eu(UQ*e@XV?;*O z;U2XNw8-m2ZR{yGZNN*Q2T-}z6mvJ8MtERDtn}!BQO1_-!F(+ut8f}`sFa7SvxKzn z)s2E2!V>!RP-!P`7du$Kc!F?tOs)WUKBKY0S;z!{nbHunMU7bjAjez;r;Ta4v$DV+ zA6wV>5UbG!0|npMtYelu3f06&`CX^walczY7U_!073$g97JoG@tDgnpM&Y@Y*Q+P7%n7WYjP6l&f zL5DI8Rg~mfp;GyBwE z%PUhm?_BR0Tum}pk0gdDo&!MDdvk0R6A9B-ks#U7twOGIH_O;{=?Nk!8vIHs;2Ki4 zY){@5+RyBvyl@G-I#w|CjahELOIIs4sHthSs}W#RNY+cPJ(5vkG_MuJb7$eH-j=o| zFBic*A~jaHrjBPd>0bFw&)wiUSpL}8MV^}-6U3cxKjEx3yEob+E8N^{KpTao z?=3+L24D)&8a*N&_s%ZKnjg-SeY)YlMJ437*ph0 zH)cur5dgo)6K>T&mhaq7|8N%t+$y5Rej$RK z9LvLL*pDfcORLR?_Ep$B+X?(FlFfEvk8MOL|8g`yygTKjtqdpF)Sd*h;)jC*7I`hF z6B1Waz-%(HaXLLb%%d)%Hmk*b-yS3Xx_$)lCs{#QnHWJ+23g?@HP@%m$73&UoF8_D ziFH$)Yqx8V@vcLHk)ovGLLRMa_sk4@qq!JATuesXPAf)OXJ;l9=PWahEna$m)&51@ z{Lobb7A{}9aJOROyd#KtVH`V}(tEVRf3@v?cv#$S^SkjPrM}=@ZL$8f5kBUG<)1e; zdhoMnoO@C?GVTfRTk9)xW&5o4-3z>?CT1Wd1x{59TTT$F27Jnr>LI)#6JmNm;Iw0UeS=CxT!Pl0=Q7Nkgj8*v_h-^Zp&s_cCF zuJ+%Vx?_wVoF6K$PT*6bM8P;!Yb{v~B;Vuv!j4h0ExFW;_awBL)JfM7j@weKGSK^` z@}Qf!hK8Q=8F^qjW-wgyjD<$<5LPv_1xrUi2-3pj`?$=zy3(DSVZePO9oN)Y1+`p~ z_;b2j@L;kN!-3wUG80Su`|xz?^$>;J9+8C)Xb{m}d^tnW_qp##w!{+$7k@EdElDA! z^sQb)7apBMT~E48(Wj;3jAkZ$yOn|aRRlW1i;Y{Yc{~`5;=huzHgcU`pF$>f=73U# z*{hH{dpuRc4oxL~YG-Oruxh{;5pe$DL4G z#EZ34o(r#a=C0*aicHd~}ua9|R@)To~;5%!U4F&LMBo0@_8AA7a~NdXtoFXv@(V9+Il^$92wY^Owu+P}>k@-7{-H zl={wZ?ewEi(TI-8%~w*|k--Fw3kx`nmf~}c5y#gOo}y%ivf%(n>4r@oL;W&11q*k- z{ArsNiowgWyeaTUjQcbDr^ctU zx&9M_{*~+1OVYg-n+eb8hq7p8>Kto7his7c#kVICf}QE@ zkLzS;JF59#&O@3-TR$ySb01bf8xM80)$|$m(l$4|Z7{bC=1x9j!8po5xtF)%w9lJa&=!r9lC!dX&2oz+5t_ey21Dhoa zCtz4BejEACtZ5KpcRkm2fGcYrfIl8Tu)ezvHns%2Krcew_)Wu|eMp^K_l%fisG@az zLc0d7jkV78NZ=)F?s#}%m2cly-$)@Ck1Rg#q@l9;8wIPl9~so>w_I}SueWnV6x7N6{2s+lw2dL=bl zSAKsGJ()CMH@PsKivA|vi73g9!H!d0Kw^iRRYPbs*hSsc^2Il^1S)0LXx=Zun?%4Xyf<@3tVwPhVIswgkQtp#B`trZ(; z6d*dGMRhcOAEm_)$|(D&`c|`2DdN@5h~_XwLYOzS1L-8^Kh5h z_Vh$f93KZ7a&PaudapgwEzbER*>t2a)?bj|XBNxj*DUyT)!I8v7UJTjCtSlX)?Ex~ zs{#if7jnrNE)(g#6W5MEa8bJ&2}hrhcmBA3q$Qo-@+`hX@Tl_0a0MWa|BzD_zq;~cUozvYFCD=w(EAC1R+ZK}B_q3<3m zsDhJO`q=uO`H*hKrRN3qwt#O}oxDivam4@CAev%zkYoCx} zL(RP%BjzD5aBJ(5fz__N7NtpH2hIT$0S+V|vZcxX#`YG3g?f7B z0&2}SZJKWN{f-GBg7MM^<9JW-H}&Zeve!IAW3MA&u5v2mh2wBUo0nE4zHMTD0dpv1 zM{rs7qskY|3Vum)?dMf9Oh?;z#g&65L0N%Kueaj|Km<$gp(g`_b<5ry6jlvmzC8O#2HT?Nv0^^^Qfemh-ye+BHUn8jaOA$*ycoUJ@XGetrxmyo zb;=C}9$uex#Tg9HKWQ$cmj<+n)bf@fv!<~2{sz4=`;CfXRLrz;Z_^?UM*(7%vjQdp zepL-NucyH?PG&|hNA%rF`9KVyHWuIrTPQ@&M&OI3$u+A!>VvW5?d#L zQfXp|o)cyhObM_Z9YPl{S2xX!S`)f>S=wbHqFqShS^UX<4m&7*WHX!57_|l;p&EMF z#A{NN$pE9Mvg^)EM^q-&wCw~GN=T3!1eSV}BDWEsz$uztShMi+?>F@yADk%c7bJp< zrpz*;MpK(;=(LH7^=Gn&KbY@Z!9+(#U78Pm*tB|>2nmJ0c4&fze~C!~Q6q^p^x0w$XB@S}wS!ZO(#YX0qLeJh;oV8VV}D_N<4K94xQ%s{B62lP58{zwig zYAz`~4@Ff@4Y$(Dn<>OL1H%{DI-)Y-w=Fdb(mCcs?*1IU_BXXfVRNQ4MZr`^R9lh7 zX7Z-M|2PU{T4sOjdY7@%qrBWk<0Jf+O)I_R0Fk_;U9H#hB?aJH0Df%%R(6?*ov{t| zU|kBsN*#qAc^M~+0cZ^^na&&j@i>6kn;t?G`eke#4&6G48S%qjdOPQjl(s93jhM(& z83zXDHPY=kO6GK*Sm^8iEAeUP3C=B%cB8;!+RIedssd3p%1L30ikgr3P5SQEyl zfaw<&DDz9c&t4?=ouwJ)fr>XNpmVstBr<|D)s$=VX(GS z*Lv;xp$GdHEC~qTG>oyq5|LxjbBrz9TB~~Zr~Z?pUDVl-s$#OgM^awq$$?=UCMJL- zfnwWjZ{m%{XcPn=M}gOH9HE8_U|rdLKyZNGiG39x(Z;`tt}#gtmv6UuI}<(JfsIXX zQ5QuenVe{lBRyE+C56hlNdYR>wMB!L+nZ37fL5^}k9W7rA-!eL1&^baWxF{wB zj}^4xTehE01CoNgz%}s;muX=|P|j>_6N$P|xA6<=4P$xbo;s_iCTmod_1SGdN`0PM zH~}s3E#sHh*h2#X;|LLzbM|bbb*-sH0#p&a6?}BpUXkU%>Jv^A)%g0CS#xHQ4xTvQ zPJ82U+GNs8s`{*lV5wd=f(aViMXp0+&o83hwi{g&Q3#Z2XzrLOkIczjW+E42|%zL(= zE9-3=@6*w2qspZ|&Bf zi2jvc1CT2hV|2D|HSbcXu&1Rd0%s4NklQxPcJ_mG!#*9z`t=@nt9`mp@Ok!@|KCTZ zC12|QoOUqjh>virUpN+GmvKnUjEQj9mIec!U`B z6OJ3>9|C#|rd`-@W15QTb?CvagtKkfnqwvny!I6iBOoiWBoF+v@JMdIaDXUd1~Xg& z_*1R+ckt-H#-;I-%CWlF40`4wAw}W(Nm5={zRkMPV4oP?Xh4mPH5ydGS}0{NXAr1$ zv#+Faa$#of8@i65RbO}v_XRGXpktT$-;q|7<)`3V3MvSi_oUo~lcN^}+>|GwjOkS(bJdkI!}7pAww)jXOF&3XCd>3bk-!`CFJhdRSAD9b4Th z`8L*SV*m^97ec>`f(*R~imz|AqaZMz%cn&$GKx0gUwm@KBIS;fi)yqk`x@2}l;_%C zXFf_RnoNZ56LVJ~q#)|aleMvqtYtVqgPiXPJHB3)%I&qRJz-vyoL4^UV!0D@IWsMI z(SYw{lYA=Xq0}~To8$`<$=~VxV+_}P{g*$HUizoN^NT((41W^*9q%QKuX`C`9awq6 zMX(r9tn#UvFg@SSOXYxa%Hf?oo*sO|?M}pJ#J}q#;!}_b12C05mzKV)D+hvF?vB#? z7MbIb+qH0J>*a;qUPV10^*YOH`NHSlZ(M7xe_~a>aNYjoXi{eNnFILN__?wo?5RV`ZjN(+uU(+duQquQ+^n^U$SJ<2 zoaj7Q@cc+NujdfE->8=O^eh(<<`F-wf@~X6MIPy3RMP{{6=-ku@$b(8Rwo7FXA`&J zlmI+d=1r3{!bW(SkyVTH$=$`UPxa~96;5_@XgulbifL`1X-64Q^L9PX0zLik_-Dh~ zx9-wU!E|H1M-c|ph!&e4-<(@zY}ohBv#s*CeafSUAb(_7Qyl@L0jlF)21^8X z>*Z0%lf$bwzeuhU(i-*{ZZcIS5(sSNAtU;tb4nT+1jO=P{N~9jTSjr?*6-KqslbYz z#Nx|9X!D*vzC}QPs}?aTmr#*5?O8X6TrX_`@;=Q$`y0Ab=UM8tk@9O#Px3Z_fldMQ z${J}>Le<;$4G(26%%}rGJI$Ex&b5=z)p7;}KNi`9+ zz-cmAVho7{+IRkrOQ9p|4RWuBeVwM;j|G;XNd2w#Ucu z^x|caw{>Uo6{Oe?VC73{S?d|WiM_1XK4*<(YV&=2M$Ppwh6jrpq(R=uNY(U!7pQM8 ztd`Wzd%iRw?z+FYUOh2X^8z@o=ke zs@w>6W9(AR?2eT0CCTDRdfE~cB{$J$Fqw{<`bQD@g%%3dE?-gzKN6r`D1|)4NFL)>1Zw|U+(zVKyy&Z=pIEW3+&PD@4nF;eE#u9IT29mr$`8xMd>5}%59 z{t|rn^SASm`Yd!@m{*JBje^W)s3;&2r5&vuKQnS z$PoUKA>(w%%GjUO{kvY?IryGc@JYHAx`?bwzM~#HUbis0hS#3LeHQ|$-$PxD&K|gQ z?u{n@varMO!1@XHx}kM_x4r+lmfv=cKSGJIZvO#l;8-GUprxq(3^cZXVdnKTJ7G9Z0ldP`yc*O>klhmky1unsEaXny#uK45Wt(+YUJ2_ zc5$Wr^PtGxrT~F1@(%*t3oaXPm7_-g$Q%3ryA#ldBY96E*W>+sd)Tuc2}9Qy^^R(8 zz1Qx&Y8Ua%uF5v-?Pe?b`BM1wvQ$Xxd(Gdk{>@}@^YkEfp+iK@J@R(tsE+D7ocDj% z4yTX5qnr4}6YqB0We!^*Uc2!UQTH$L3TjrS5%r`TG*!T>j<+(o^?FGaoTp?_TNW_QqbQ zlHQsT^Ox(5DhD_5WA82;-QNbLF&S5>O7TZr~? z#6=ZKoqlKBQvW0D_?^{q)5_ri2UDlV?a4aqIdQi8Zw#6h0(L>2$BrSnWSIMH6*mfb zRK)x!k><`~%C<&wKqb#E;h`*H4aIl23)A-;t@}|YkZq-{v^UCwU~g=1U?hz8S4U3x zYh(>a9bv6mNwXNFt1-3NG40TE%op(0=WQnZVan?SA;mb2+QHOXw7hXm~$L=gbX{y7JM| z@gzf8d*jjc1ZJPC(hXt!6mr|sL6SPPbZ#wX@UwbwLQP&huF1Y*e(DIf z2&o=4oi=qoxeh@&C#)W&LU}W#nmE3r3^Y=P?c8c(16~u_d|QXA3pYN(T$rBpq?S~` z>|O4cniD6SY*vDbJ)22*SdGNFXPLi&eZ(j|x)MB4J9#d(l+R8$31)aYDiLk^5ODqq z_~CK$6Qfqx1_UCMQqS&clF80AhSEe`o2n^zMdpH&7W&bE(H_}Y7|F=qNyTux=}yjE zWKgru&EhD5UQB#2R<(uKHGF(Xf#k}F);Aje@VU*2FCGPB|) zEG9WDA-}|HsyI1=kda$H*_Ri@C##{jg}5|{y`$m2&u_hZ6G}<_H*8`8-2CO6P~=#T z*&?cW65jO&Q*Og6qgj6Xa{2ulQnZ20#6(hTim$EnLdZPM*xtzkGJ5bFGzbRAtETJp zc|`lD9xty}WWbcdJf|1t&-T@1^hYrjE;kWF=`Pof(ZL#!k2_27Fe5d4ddbP-G@nyV963 zcd>cfbx*xa4GT3$CqsuBpe!)zi>$Wyh%P1jAIGE0(N8Rpn4$(KZguOXdr>~Li?FOo ztr)LS)w=-1@|uXSs+y%f$0yV%g-iIm1+3cQGalU>(__&^diK?-J~|T_GzlXdT%Jt)$K06fPa3{$@aj-x}{(W6;dt>XwY%?X4L`AykvL>$qi~wkCpS?2)1%EI>R9@JsWvs#avCQlmroO7460 zO&;v&OOaL3*IIzO9C=KDx!`zHK3X_+ry}*t%v-ZDFAaj4Jmr|sXb%d^jgkj7G=w@0 z_w;lTt6FQ3How{Iynf=Hd+dLNoqK0IZ;Jm7PmVX=^|tWtWB31&Pvz}k{#5$k{p!2w z_}~5NyW05wdcXRvBK}p@EPUe)3O@GsJep@>PF|!yWT}V_DMdK*3Y8U`t*!GWLymF zulB-%{MfnP|Ex`05(EJ6Lzf;qeyo?bvYpVHO~BD+`n#jeVghHRd}CE9R?Gjo;=I;s z*CIHf8`>5bkrmL!LUBo*h7)jo zdoA0)a0*Wx6+CcKw(3N=Fz%cl$mShLe)l+;!6sjrp@f}bsMpj#pKz-)j`uI}QBP5I zeE5;0<<3}ggI8sMdu{amrm%{~bd;Mq?>SE>0mnwJ5toK#MZOIIHrs9ndLD)sVFL!J z4$R&I9;H6Tg$JAOS7Kg3Ep5ZC^cB}$HZ%us!fZI_lJi+nb7s!8A((Txr%G>)1$_PP z=~|x!J`ogJ-lS$Ijj3Zq7Zy#Zb=r?4Ma7rhx4ggm-tEDD`Iu{lCl^P^=v=uaR(Bl) z8%`arK`%x&xB!%iq2grCOnq2uXN_+m$-X1wX8a6VD?4l3v5)HS523Wq^^7m`wSb%u zoMLAo)3d9z$d`lq^awU!^>%|ngqrMbbzyBWYzTOJjTJ+Yxj=LPY|lZE+Cp3^qyD-l z@rt*2+7bWTi||S8fSnw@sABz52-7&p!sa);p;Ip*EgO;)8=USF&~yp6_L5l8+2C#C-joW$2CtyX3E9m;y%**WTVGiE(R1SA{V%JBA;nL@{T z!?8u0>F`v5fK%1-#Pz2}ihGEqzHsx<3Swq9L~aGZCav{CAzA)NzyHWRm^QeoxTm}H z!mN2-1tl{FvOgRk6J2X_rUPiC^ZBFQqe@EQ8I7S{Ort|_*e7*9X*i0}nvGXk3t_PZ zOqZ#*-tS}|)oW}628SD18ROwqbGt_B0{fjq-@=e4&;1#Oq=a9ElwI&+R?L_kR6shS z$9MlU98@WR*47oS*eTxDckEXlNvDGDa2G7itryLcymq~kQg*8bC(N!msVI~-O~gmK z|Bbf$N8I_SOj6hj2ldd+5f?w}fJ}g#d%x2{&&H6*1$j_DqKbi3=2IGQd@Lo})|uXP zl%*^CSo1X&>95eRuWyF$cx?PPPbX?|ZZ*2;vswP5qiMC9GQCdAs{U#>TEQ<1<=F0Y zr$PTCBS?40feQS5vR3xjFf9Q? z`P@We|C3?7qA>sn)^D$)zPxAXdxoLIVG4?-;ANlg9_;-Cla#HJWwHMJE24?s?Z|V) zrnM_<*F!`ZN!qob__`~yFE)8w;^uiF*xhJPb!ljb_nAO)=*=_HNhQv$z0o3bCd3#z z4q6$y8R`9x;XZKq4?7Nh^v<^e+tBvmf|C?N_oP(2BwtQ54MG!PAx_VNQOmu~;f71g z4N|>9Gn5|~Niid1BTxPoS2Zb!;5#V;InuJMwX^U_nsCdN%v*CT_(BFutG&gW!V>(# zxa3D@F}^O{8+Lwfox!b@=9tCIX6rB^iq>&dosb8`=v`Fzeo|TU7&Ie)3KQdhe5)EX z(9L*B-0c)>DyyPCDzraP?c@PzJGx6KJ<(@u#@&AIVHf7>n?>4%>!oK;-IQcBoGgPJ zXkhJ-v0hJ5Z+#^toVo#CH6?}E9dbz~-HBKG^oQTkMAeg+8}g5SKxeK=>srE-RDU#+#G863`6hy#g5;}I8 z`ROSWYrc}w`l&R2O?$0>eD-TZ(ZUJ6(i|@lD?EiyRar3i*GO9>7KLqMd_lE2{Xm2k zS0f0~69(ew#Z7k(J9p@Rk^wtY?9yvs7R~!Ihc0XS5@F|(nA-}0L%{CRz9`ld#t6s| zE=ApSMM*QHXq|h}H(_A`USkc8u~3;j5PuwSI>YQGo~+*>^BRhwlN) z`_L-h0Slv@Q2o*J8zElc5}v)cpRxYbQYozsgEn)uaIIzQuM?^L7wRf9&) zImuckbYW}z_VGBg!M?+V>4MEj`q(*&H;-|cyh}smGi(fH5^Uue z#jVP~HM5)c+TJ}}@zr9F6>B7$7O4M8ro{0+0@`lU##vKGs@0Z9`(i8w*snHA*px-u zaZjb7{jKx>Y^3fG+R6$Uzx2txW>gSJ-7m&{m>eUwLNjwKF;(LTvg>E5Iv0cW|{Ei+c?uEq%MNQqayL255*i`ME6p9H68r1HkzTfQ0Ds{|4OEWSttE*)W$_&Zi>qDGwMuxfA|GZuQkHG3*qQzG zNqb#{9;aWsi^^@v&5LQm#F&plI_hROtwU#_ZE@y1QP~mbx%{QT^cEuRa9K)TsDhrq zk-eb@3&;fhkTHi-tGtfQ?sYt%LfxPt$f3o zuFV|05vu%)AaL4w>`OO4*+4)y@t_`Lna{w_yF9oFPq!S`Sv%f$RC%Kon5G^DJmT zK=CXi2nMt2;b{8m{I1#TjI6WgkaI!P3|U{VM}VJ9kCPE;y+85H4~1!I0CO_(Y0*_W zJE1z#EBPnv1rPLQfk9vqpmObYWFq0_{`K#MI|w;;UTt%+ff%l%GgKv~W9CAXab2xv zF{?g(DGa=_pX=vY3SU#JZcWU(vubCX72q(YP<*I%qAflrCRI|!P~5_|r(CRBmE1Kt z9Pne9M?zEEIFOk|UYuiL)t-l`P`eKr;EcEHr7;_{O7)s;l732Hg+j@m-*xK>y0A$1;&Vl=_)Zj z$$k1*Pp_GRN{pkyu;IxPV>>JObXwvosUstPjoJ3IZVMXL{8b(|ZFB4iGUXAdYts%P zDUdk>B!SqpDk2v||BfrdX}3{i!6I>R{@`haW2-$*HI9l&;^KNq(RqtGzJl&-*#6?A zuR^u!dlL#G+6C#&mM#$UvX?-v{FD%L?=_rtD@VDPFnj!Pc>+H!E9r+>%ou<& zIItJbDVMyGdI+TT+c_f)CEdLa)tc1^=#zcYlnr2uu>XcFYJQC^^8W){w6O_6j1_zX zF1sV9q>%O*|Gfg;mAG?%7a2%1OMXfZ3wte%54C2_?Z}$LY+$ z+80Z+pewbn(M6#QU(R$jD4S!ReF`?E%6gdLXicNy-6kwolwL{gv#1x6f+YF3-Bz!i zb_F%OG-1g>GE~JQQ{iuECqoQMgKA-VqM=S%I%pI+r|CTfr2e0St;r!@R>_l@tqj&;2dwr2fowuPCv`&HMlx;JK?>j?Q!^VOHli$^{86n^yuX6Tj_a(0iH; zO{Fu+=?9CNU!#p;|3Djg&sqezQJ?AXjHkRYb;JxGN-nHOT`f%nQ&hfg;!t7-QwfC& zXh4#7_m?ZnqjNe#jd4RRTgoP&V!0$fKHMhpm#S$@s@GB2l&dY3UBh!~&!{u*-V(OC z)-%#Gz+uVZa1erHX`+%JQ)k*=iO*8 zTVsV|4MLd8-(%77qVqm|3Fadf$#A^G({N1+SWrog!R(IE=-v_i#nZVQYhbg9}~z z2vF)H6a1J6z(p0})PW3-7&-FV#c=)b=iwoPv{<)Mi1gFXx+y8PEzU6HsfSI@c1l4@ z6(}zEnw#(`+YIErmt>Sd^#agBCOq!w)QxAm)++38^PRri@(h?k-!{2MwBNfFjVZl% zsW#!th%(d2x{cMG#*+<1Is+t|2V6I_Kijnx;(1%PC)86~V{Fsgc0^!!E2VLDd?Ejp w)FYkkcOCM|-BZ(#8o<+$jRbJGNT~?OGX)@j;20e{=@TED%m42(l~=?62PjkxqyPW_ literal 0 HcmV?d00001 diff --git a/tutorials/videos/robot-marbles-part-4/robot-marbles-part-4.ipynb b/tutorials/videos/robot-marbles-part-4/robot-marbles-part-4.ipynb new file mode 100644 index 0000000..0ed3822 --- /dev/null +++ b/tutorials/videos/robot-marbles-part-4/robot-marbles-part-4.ipynb @@ -0,0 +1,642 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# cadCAD Template: Robot and the Marbles - Part 4\n", + "\n", + "![](images/Overview.jpeg)\n", + "![](images/Mech1.jpeg)\n", + "\n", + "\n", + "## Non-determinism\n", + "Non-deterministic systems exhibit different behaviors on different runs for the same input. The order of heads and tails in a series of 3 coin tosses, for example, is non deterministic. \n", + "\n", + "Our robots and marbles system is currently modelled as a deterministic system. Meaning that every time we run the simulation: none of the robots act on timestep 1; robot 1 acts on timestep 2; robot 2 acts on timestep 3; an so on. \n", + "\n", + "If however we were to define that at every timestep each robot would act with a probability P, then we would have a non-deterministic (probabilistic) system. Let's make the following changes to our system.\n", + "* Robot 1: instead of acting once every two timesteps, there's a 50% chance it will act in any given timestep\n", + "* Robot 2: instead of acting once every three timesteps, there's a 33.33% chance it will act in any given timestep" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "# import libraries\n", + "import pandas as pd\n", + "import numpy as np\n", + "import matplotlib \n", + "from cadCAD.engine import ExecutionMode, ExecutionContext, Executor\n", + "import config\n", + "from cadCAD import configs\n", + "import matplotlib.pyplot as plt\n", + "\n", + "%matplotlib inline\n", + "\n", + "exec_mode = ExecutionMode()" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "single_proc: []\n", + "[]\n" + ] + }, + { + "data": { + "text/html": [ + "

\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
box_Abox_B
runtimestepsubstep
100100
11100
2191
3191
4182
5164
6155
7155
8155
9155
10155
\n", + "
" + ], + "text/plain": [ + " box_A box_B\n", + "run timestep substep \n", + "1 0 0 10 0\n", + " 1 1 10 0\n", + " 2 1 9 1\n", + " 3 1 9 1\n", + " 4 1 8 2\n", + " 5 1 6 4\n", + " 6 1 5 5\n", + " 7 1 5 5\n", + " 8 1 5 5\n", + " 9 1 5 5\n", + " 10 1 5 5" + ] + }, + "execution_count": 2, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# Run Cad^2\n", + "\n", + "first_config = configs # only contains config1\n", + "single_proc_ctx = ExecutionContext(context=exec_mode.single_proc)\n", + "run = Executor(exec_context=single_proc_ctx, configs=first_config)\n", + "\n", + "raw_result, tensor_field = run.execute()\n", + "df = pd.DataFrame(raw_result)\n", + "df.set_index(['run', 'timestep', 'substep'])" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "df.plot('timestep', ['box_A', 'box_B'], grid=True, \n", + " colormap = 'RdYlGn',\n", + " xticks=list(df['timestep'].drop_duplicates()), \n", + " yticks=list(range(1+(df['box_A']+df['box_B']).max())));" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Since it is random, lets run it again:" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "single_proc: []\n", + "[]\n" + ] + }, + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAXcAAAEGCAYAAACevtWaAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADh0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uMy4xLjEsIGh0dHA6Ly9tYXRwbG90bGliLm9yZy8QZhcZAAAgAElEQVR4nO3dd3gU5dfG8e9JCL0joAKSgCT0LqAYqvSiiCD8sKBYKNIUxYqiWFBpShNRbHQQgSC9CgoK0gkgSFcB6Z2QnPePXXwRKSG72Zlszue69tqdze7MnU1yMvvszHNEVTHGGBNcQpwOYIwxxv+suBtjTBCy4m6MMUHIirsxxgQhK+7GGBOE0gRyY9mzZ9fbb789kJv8j1OnTpEpUyZHM7glhxsyuCWHGzK4JYcbMrglhxsyAKxatepvVc19Q09S1YBdIiMj1WkLFy50OoKquiOHGzKouiOHGzKouiOHGzKouiOHGzKoqgIr9QbrrQ3LGGNMELLibowxQciKuzHGBKGAfqBqjDFXExcXx969ezl79iwA2bJlIzY21tFMgc6QPn168ufPT1hYmM/rsuJujHGFvXv3kiVLFsLDwxERTpw4QZYsWRzNFMgMqsqhQ4fYu3cvERERPq/vusMyIvK5iBwQkQ2X3JdTROaKyG/e6xw+JzHGpGpnz54lV65ciIjTURwhIuTKleufdy6+SsyY+xdA/cvuexGYr6pFgPneZWOM8UlqLewX+fP7v+6wjKouEZHwy+6+F6jhvf0lsAjoeb11xf99lHW9Bt1QQH87dfo4Wq0aEmKfJRtjgpdoIuZz9xb3GFUt6V0+qqrZvbcFOHJx+QrPfQp4CiCCdBX6SLg/cieN93vN/HAjsj7e1LkcwMmTJ8mcOXOqz+CWHG7I4JYcTmXIli0bl57BHh8fT2hoaMBzXMqJDNu2bePYsWP/uq9mzZqrVLXiDa0oMWc6AeHAhkuWj1729SOJWY/TZ6gmJCTolAaP6Wgi9fevv3M0ixvOfHNDBlV35HBDBlV35HAqw6ZNm/61fPz48YBn2LFjh5YoUSLZMqxevVoBnTlz5lUfc/nroBrYM1T3i8gtAN7rA0lcT0CJCNm6/488NSqxot0rHFy2yulIxphUZOzYsdx9992MHTs22beV1EMhpwGPAu95r6f6LVEyk7A0RE/+mDlVHmTJfZ2ot2IimQsVcDqWMeYSq7q9zd+rNhAa6r+jtXOULUqFga9c93EXLlygTZs2/Prrr0RFRTFmzBh++uknevTowYULF7jjjjsYNmwYZ8+epVKlSkybNo2oqChat25NrVq1ePLJJ6+4XlVl4sSJzJ07l+joaM6ePUv69On99v1dLjGHQo4FfgKiRGSviLTDU9TriMhvwD3e5RQjXc7sVI8ZjsYnsKjx05w/etzpSMYYl9iyZQsdO3YkNjaWLFmy0L9/f9q2bcv48eNZv349Fy5cYNiwYWTLlo3BgwfTtm1bxo0bx5EjR65a2AF+/PFHIiIiKFy4MDVq1GDGjBnJ+n0k5miZ1lf5Um0/ZwmorJERRE/+iAV127G0ZTdqzPiEED+cFWaM8V2Fga84dhJTgQIFqFq1KgAPPvgg/fr1IyIigsjISAAeffRRhgwZQrdu3ahTpw4TJ06kU6dOrF279prrHTt2LK1atQKgVatWfPXVVzRv3jzZvo9UfTxg3ppVqPRJb/6au4yVXfpc/HDYGJOKXX6sefbsVzwQEICEhARiY2PJmDEjR44cuerj4uPjmTx5Mm+++Sbh4eF07tyZWbNmceLECb/lvlyqLu4AhR9/gGIvPMG24ePY8tFXTscxxjhs9+7d/PTTTwBMnDiRihUrsnPnTrZt2wbA119/TfXq1QEYMGAAxYoVY8yYMTz22GPExcVdcZ3z58+ndOnS7Nmzh507d7Jr1y6aN2/OlClTku37SPXFHaDsu8+R/757WP3se+ybscjpOMYYB0VFRTFkyBCKFSvG0aNH6d69O6NGjaJFixaUKlWKkJAQ2rdvz5YtWxg5ciT9+vUjOjqaatWq0adPnyuuc+zYsTRr1uxf9zVv3jxZj5qxicMACQnhrm8+YG61h1jWqjt1lo0lR+miTscyxgRYeHg4mzdv/mf5xIkTZMyYkdq1a7N69ep/PTYqKupfM0b279//qusdNWrUf+5r2rQpTZsm38mUtufulSZTRqpPG0ZY1swsbtyeM3+miEP3jTHmiqy4XyJjvrxUnz6cc4eOsvjejlw445/Z2YwxqUflypUpW7bsvy7r168PeA4blrlMzvIlqDrmQ5Y0e4blj/ak6rgBNsmYMSbRVqxY4XQEwPbcryj/vfdQ7v3n2T1xluOzWBpjTFLYnvtVFH3ucY5v/p2Nbw8nS2QEhR65z+lIxhiTaLbnfhUiQsWhr5O3ZmV+fuJVDvyw0ulIxhiTaFbcryE0bVqiJ39Mpoh8/NCsEye273Y6kjHGJIpPxV1EuorIBhHZKCLd/BXKTdLmyEaNGSNQhcU2yZgxQW3nzp2ULFkyWdYdHh5OqVKlKFu2LKVKlWLq1OSdTDfJxV1ESgJPApWAMkBjEbn92s9KmbLcXpDobz/m5PY9/PBAFxKucoqxMcZcy8KFC1mzZg2TJk2iS5cuybotXz5QLQasUNXTACKyGLgfeN8fwdwmb/VKVBrxJssfe4mVz7zFHcN7p/pmvsYkl24TBrBqV6xfW9yVzR/JwJbdr/u45JrP/VLHjx8nR44c/vi2ripRPVSv+ESRYniadNwJnAHm42kF1fmyx/3TQzV37twVJkyY4FNgX/naH/L4p1M4OWYWWTu2IHOLexzL4Q9uyOCWHG7I4JYcbuih2nPaUNbt2+bXHahStxamb9OO13zMrl27KFWqFHPmzKFKlSp06NCBiIgIRo0axbRp0yhSpAhPPfUUZcqUoVOnTixYsIC3336bDh06MHr06GtOBFayZEkyZ86MqrJz506++OILGjRo8J/HBbSH6tUuQDtgFbAEGAYMvNbjne6hqup7f8iE+Hhd0ryzjpYo3TNtvmM5/MENGVTdkcMNGVTdkSO191AtUKDAP8vTp0/XGjVqaHR09D/3zZs3T5s1a/bP8pNPPqk5c+bUPXv2XHPdBQsW1IMHD6qq6rZt27RgwYJ64sSJ/zzO6R6qF/8xfKaqFVS1GnAE2OrL+lICCQnhzq/6krN8cX5s/RxH1sRe/0nGmBQjOeZzv1zhwoXJmzcvmzZtSnLO6/H1aJk83uvb8Iy3j/FHKLdLkzED1aYNI22OrCxuYpOMGRNMkmM+98sdOHCAHTt2ULBgweT5JvD9OPfJIrIJmA50UtWjfsiUImS81TPJ2Pkjx1nctAMXTp9xOpIxxg+SYz73i2rWrEnZsmWpWbMm7733Hnnz5k2278On6QdUNdpfQVKiHGWLcdfYfiy5tyM/PdKTuycMtEnGjEnBkms+d/AcQx9IVol8lL9JLcp92JM9k2ez9tWBTscxxhjAJg7zi6Ld23Jiyw42vfsJWSPDKdT2fqcjGWMcUrlyZc6dO/ev+77++mtKlSoV0BxW3P1ARKg4+DVObN/Nz0/1IlNEfvJWr+R0LGNSHFVN8ScH+jKfuybxvKMrsWEZPwkJCyN64iAyF8rPD/d35vhvO52OZEyKkj59eg4dOuTXApeSqCqHDh0iffr0flmf7bn7Udoc2ag+YwRzKrdgceOnqbd8AmlzZHM6ljEpQv78+dm7dy8HDx4E4OzZs34rdEkV6Azp06cnf/78flmXFXc/y1L4NqKnDGFB7bb88EAXas4aSUhYmNOxjHG9sLAwIiIi/lletGgR5cqVczCROzIklQ3LJIM80RWpNLIP+xcs55eOvVPt20xjjHNszz2ZFHrkPk5s2cHGd4aTNSqCYj3aOR3JGJOKWHFPRqXf6srxrTtY/cIHZClSkPz3Jn0WSWOMuRE2LJOMJCSEO7/sS86KJVn2vx4cXp18kwQZY8ylrLgnszQZM1B92jDS5crO4ibtOb1vv9ORjDGpgK+zQnb39k/dICJjRcTZ45ZcKsPNuak+fThxx054Jhk7ddrpSMaYIOdLD9V8QBegoqqWBEKBVv4KFmxylClK1bH9Obomlh8feh5NSHA6kjEmiPn6gWoaIIOIxAEZgT98jxS88jWuSbl+Pfm1+7sQs5BxDs8gKTmy8Pv7PYl4qKnNZmlMkElyD1UAEekKvI2nh+ocVW1zhccEVQ9VX6kqZ2Yv5/T23aRNm9axHACnV24iYetuwkoUJluXVqSNvM2RHE7/TNySwS053JDBLTnckAEC3EMVyAEsAHIDYcB3wEPXek4w9FD1FzfkWDB/vm77fJJOznOnjpYoXfH0a3r278MBz+GG18INGVTdkcMNGVTdkcMNGVQD30P1HmCHqh5U1TjgW+AuH9ZnAkxCQij8WHMab5lFVNdH2D5yEtOL1OO3YWNIiI93Op4xxge+FPfdQBURySieOTprA9YtOgVKmz0rFQa8TIO1U8lRtii/dOzN7IrNObB0pdPRjDFJlOTirqorgEnAr8B677pG+CmXcUD2EkWoNf9L7p4wkHOHjjIvug0/PtSD03/YsfnGpDQ+HSKhqq+ralFVLamqD6vques/y7iZiHBbiwY0jv2eEq92YPek2cRE1WfT+58Sf/680/GMMYlkx7+ZK0qTKSNl3upGo40zyFuzMmt6fsj3pZrwx6wlTkczxiSCFXdzTVkK30b1acOp8f0IUFjU4EkW39uBk7/vcTqaMeYarLibRLm1QXUarp9O2feeY//85cQUb8i6XoO4cPqM09GMMVdgxd0kWmi6tBTv+RSNt8yiQPO6bHhrKDHFGrJ70ixrSGKMy1hxNzcsY768VB3dj3uWjCZt9iwsbdGVBfe05dimbU5HM8Z4WXE3SZYnuiL1V31LxcG9OLI6lu9LN2VV93c4f+yE09GMSfWsuBufhKRJQ2SnNjTeOovC7R5gy6CviImsx/ZRk23mS2McZMXd+EX6m3JS6ZM3qf/LJDIXvo0Vj7/MnLtacWjleqejGZMqWXE3fpWzQknqLB1DlS/7cmrnPmZXasGKJ1/l7MHDTkczJlWx4m78TkJCKPTIfTTZOpui3dvy+xdTmB5Zjy0ff03ChQtOxzMmVfClE1OUiKy55HJcRLr5M5xJ2cKyZqZ8vxdpuG4auSqWZFWXPswq34z9i392OpoxQc+XicO2qGpZVS0LVABOA1P8lswEjWzFClNzzudET/6YuOOnmF/jYZa1fpbTe/9yOpoxQctfwzK1ge2qustP6zNBRkQocH9dGm2aQclendgzZS7To+qz8d1P0PNxTsczJuj4q7i3Asb6aV0miKXJmIHSvbvQOPZ7bqlblbUv9+fA42+yb8Yip6MZE1R86qEKICJp8TTGLqGq/5n423qoujeHGzKc/WUTRweNIWHfQdJVKUW2Z1qSJl+egOdww2vhlhxuyOCWHG7IAAHuoXrxAtyLpzn2dR9rPVT/nxtyuCGDquqCOXN10wcjdXzmsjo2bQld83J/jTt5KqAZ3PJauCGHGzKouiOHGzKoBr6H6kWtsSEZ4wMJS0OxHu1osnU2tz3YkI3vDCemaAN2jf/eJiQzJol8Ku4ikgmog6c5tjE+yXBLHu766n3qLB1DuptysKxVd+bXeoSj67c4Hc2YFMfXNnunVDWXqh7zVyBjcletQL2Vk7lj2BscXbeVmeWasbJLH84fPe50NGNSDDtD1bhSSGgoRdq3psnWWdz+VEt+GzKa6ZH12P7ZRJuQzJhEsOJuXC1drhzcMfQN6q2cTNbIcFY88Sqzq7Tk75/XOR3NGFez4m5ShJzlinPPD2O485sPOLP3L+ZUbsHydi9z9sAhp6MZ40pW3E2KISJEtGlK4y2zKPZ8O3Z+PY3pkfXYPOhLEuLsLFdjLmXF3aQ4YVkyU+79F2i4fho3VSnDr93eYWa5ZuxfuNzpaMa4hhV3k2JljSpEjZkjqfbdEC6cPsP8Wo+ytGVXTu3+w+loxjjOirtJ0USE/PfeQ6ONMyjVuzP7pi8kpmgDNvQZSvzZc07HM8YxVtxNUEiTIT2lej1D480zubVhdda9NogZJRqxd/oCO8vVpEpW3E1QyVQwH9GTPqLWvC8ISZeWJU07sKjRUxzfusPpaMYElBV3E5Rurn0nDddOpXz/l/h72a98X7IJa178kLiTp5yOZkxAWHE3QSskLIyi3dvSeMsswts0YVPfT4kp2oCdY2NsqMYEPV8nDssuIpNEZLOIxIrInf4KZoy/ZLg5N1VGvUvdn8aT4eab+PF/zzG/xsMcWbfZ6WjGJBtf99wHAbNUtShQBoj1PZIxyeOmKmWpu2IilUa8xbFN25hVrhm/PPMm5w4fdTqaMX6X5OIuItmAasBnAKp6XlXtr8S4WkhoKLc/2ZImW2dTpOP/2DZsLDGR9Tg1fQkJ8fFOxzPGb5LcZk9EygIjgE149tpXAV1V9dRlj7M2ey7N4YYMTueI276XYx+N4/y63wiLvI1sXVuTtnghR7KAO34mbsjglhxuyAABbrMHVAQuAJW9y4OAt671HGuz9//ckMMNGVSdz5GQkKDfv/a+fpsvWkcTqT8+2lNP/3nAkSxOvxZuyaDqjhxuyKAa+DZ7e4G9qrrCuzwJKO/D+oxxhIiQodYdNN48k+IvPsWuMTFMj6xHbP9RNiGZSbGSXNxV9S9gj4hEee+qjWeIxpgUKSxzJsq++xwNN8aQJ7oiq597j+/L3Mtf8350OpoxN8zXo2U6A6NFZB1QFnjH90jGOCtrkXBqzBhB9enDSTgfx4I6j/FD886c2rXP6WjGJJqvPVTXqGpFVS2tqvep6hF/BTPGafka16TRhhhK9+nGH7N+IKZoA9b3HsyFM2edjmbMddkZqsZcQ2j6dJR8pQONN88kX9NarH/jY2YUb8ie7+bZWa7G1ay4G5MImQrcwt3jB1J7wZekyZyJH5p1YmH9Jzi2ebvT0Yy5IivuxtyAvDWr0GD1FCoMeoVDK9byfammrH6+L3HHTzodzZh/seJuzA0KSZOGqC6P0GTrbCIeuZfYDz9nelR9dnwz1YZqjGtYcTcmidLnyUWVz96h7oqJZCxwMz89/ALzov/H4dV2RLBxnhV3Y3x0U6XS1Fs+gcqfvc3xrTuZVeF+fu7wOucO2cFjxjlW3I3xAwkJofDjD9Bk62wiOz/E9k8nMj2yPr8NG2MTkhlHWHE3xo/SZs9KxUGv0mDNd2QvHckvHXszu2JzDixd6XQ0k8pYcTcmGWQvGUntBV9RdfwAzv19hHnRbfjxoR6c/mO/09FMKmHF3ZhkIiIUbNmQxptnUuKV9uyeOIuYqPps+mAk8efPOx3PBDkr7sYkszSZMlKmT3cabZxBnhqVWfPCB8ws3ZQ/Zv/gdDQTxHztobpTRNaLyBoRsUFFY64hy+0FqTF9ONVnjCAhPoFF9Z9gyX0dOfn7HqejmSDkjz33mqpaVm+0S4gxqVS+htVptCGGMu8+x1/zfiKmeEPW9RrEhdNnnI5mgkgapwMYkxqFpktLiRefIuKhpqx+4QMWDhjOCysncCxHOtJ91dfRbOfOnXM8g1tyuCFDUiW5hyqAiOwAjgAKfKKqI67wGOuh6tIcbsjglhxOZTh3IY5xmxczZtNCuBBPntMS8AzG/faOXh64Hqrefwr5vNd5gLVAtWs93nqo/j835HBDBlV35Ah0hoSEBJ2yepGGv3Kf0r6ytvz0Zd196K9U+VpcjRtyuCGDatJ6qPo0LKOq+7zXB0RkClAJWOLLOo0Jdpv/2knXCQOYE7uCkrcWZkG3IdSMqgDAdmIdTmeCRZKLu4hkAkJU9YT3dl3gTb8lMybInDh7ijdnfM7ABePIlC4Dg1p0p2P15qQJtY++jP/58luVF5giIhfXM0ZVZ/kllTFBRFUZ/fMsXpgyhD+P/U27u5rwzr0dyJM1p9PRTBBLcnFX1d+BMn7MYkzQWb1nC53H92PZ9nXcUbA437XvS6XwEk7HMqmAvR80JhkcOnmMV6cNZ8TSqeTKlI3PHn6FtlUaERJiJ4WbwLDibowfxSfE8+nSqbwybTjHzpyic40WvNH4CbJnzOJ0NJPKWHE3xk+WbV9L5/H9WL1nKzUiy/Nxy+coma+w07FMKmXF3Rgf/Xnsb174djDf/DyL/DnyMP6JPrQoXxvvwQbGOMKKuzFJdP5CHIMWjOfN7z/nfHwcr9Rvy0v1HyVTugxORzPGirsxSTF703K6ThjAlv27aFLqbga06Ebh3PmdjmXMP6y4G3MDdvz9B89OGsR3axdze+78zOjUn4Yl73I6ljH/YcXdmEQ4ff4sfWd/zftzvyE0JIR37+tI91qtSBeW1uloxlyRFXdjrkFVmbJmEd0nDWL34b9oXbEuHzR/hnzZ8zgdzZhrsuJuzFXE/rmDLhP6M2/zL5TOdztfPzuMakXKOR3LmESx4m7MZY6fOUXvGSP5aOEEMqfLyOAHe/B09H02wZdJUXz+bRWRUGAlsE9VG/seyRhnJCQk8PWKmfT8bggHThzhiapNebtpe3JnyeF0NGNumD92RboCsUBWP6zLGEdsPbyPl/s9zU+/r6dKREliOvajYsFiTscyJsl8Ku4ikh9oBLwNPOuXRMYE0N8nj/LK1OF8unQqebLm4ItHXuPhyg1sgi+T4vnaQ3US8C6QBehxpWEZ66Hq3hxuyOBUjviEeKZt/5lRG+ZwOu4cjcPv4ImyDcicNn1Ac1zODT8TN2RwSw43ZACoWbNm4HqoAo2Bod7bNYCY6z3Heqj+PzfkcEMG1cDnWLJ1tZZ+q43SvrLWHtBJN/7xe6p9LdyaQdUdOdyQQTXwPVSrAk1FpCGQHsgqIt+o6kM+rNOYZLPv6AGenzyYsSvncFvOm5n05DvcX64mIsKBLbucjmeMX/nSiekl4CUAEamBZ1jGCrtxnXNx5xmwYBx9Zo7iQnw8vRq2o2e9h8no8BCMMcnJDtw1QW3mhh/pOnEAvx3Yw71lqtG/eVcK5c7ndCxjkp1firuqLgIW+WNdxvjD9oN76T5xINPXLyUyz23M6jyQesWrOB3LmICxPXcTVE6fP8u7s77kg7mjCQtNw/vNnqFrrQdJmybM6WjGBJQVdxMUVJVJvy7guckfsefIftpUqsf7zZ7h1uy5nY5mjCOsuJsUb+Mfv9N5fD8Wbl1F2fyRjHm8N3ffXtbpWMY4yoq7SbGOnj7BGzEjGbx4EtkyZGJoq+d5Kvo+QkNCnY5mjOOsuJsUJyEhgS+Wz+Cl74Zy8ORRnr77Pvo0bU+uzNmcjmaMa1hxNynKzzs30nl8P37euYm7CpVi5jMDKH9bUadjGeM6VtxNinDg+GFenjqMz36czs1Zc/FV29d5qFJ9RMTpaMa4khV342oX4i8wdPFkesV8yqlzZ+hxTxtea/g4WTNkcjqaMa5mxd241qKtq+g8vj8b/thOnWKV+KjlsxS9OdzpWMakCFbcjevsObyfHt9+xIRV8wnPdQvfPv0e95WpbkMwxtyAJBd3EUkPLAHSedczSVVf91cwk/qcjTtHv3ljeGfWlySo8kajJ3ih7kNksAm+jLlhvuy5nwNqqepJEQkDlorITFVd7qdsJhWJWb+UbhMHsv3gXu4vW4N+D3QhPNetTscyJsXyZcpfBU56F8O8l6S3dTKp0m8HdvPiklGs+HMLRW8uyJwug6hTrLLTsYxJ8XztoRoKrAJuB4ao6gq/pDJB7+TZ07w96wv6zx9LGkL4sHlnOtdoaRN8GeMnPvVQ/WclItmBKUBnVd1w2desh6pLcziRQVVZuGcdw9bM4O8zx6kbXp42haO57aZbAprjcm74ebglhxsyuCWHGzJAgHuoXn4BeuHpxmQ9VBPBDTkCnWHtnq1avV97pX1lLf/2I7ps21pHclyJGzKouiOHGzKouiOHGzKoBriHqojkBuJU9aiIZADqAH2Tuj4TvI6cOk6vmBEMXfwtOTJmYfj/evJE1aY2wZcxyciXMfdbgC+94+4hwARVjfFPLBMM4hPi+fzH6bw8dTiHTx2nfXQz3mr6FDkz2QRfxiQ3X46WWQeU82MWE0SW/76BZ8Z/yKrdm7m7cBkGt+pBmfxFnI5lTKphZ6gav9p//BAvfjeUL36awa3ZcjP6sd60vqOunV1qTIBZcTd+ERd/gcGLJvJGzEjOxJ2jZ92HeaVBW7Kktwm+jHGCFXfjs/mbf6HLhP5s+nMH9YtXYWCL7kTdXNDpWMakalbcTZLtPvwXz03+iEm/LqDQTfmY2v59mpSOtiEYY1zAiru5YWfjzvHB3NG8O+tLAN5q8hQ96rQhfVg6h5MZYy6y4m4STVWZtu4Huk8cyI5Df9CifG0+bN6Z23Le7HQ0Y8xlrLibRNny1y66ThzA7E3LKXFLIeZ3HUytojd2NrQxJnCsuJtrOnH2FH1mjmLA/HFkCEvHgAe60anGA4SF2q+OMW5mf6HmilSVMb/M5vlvB/Pnsb957M7GvHtfB/JmzeV0NGNMIlhxN/+xZs9WOo/vx9Lta6lYsBhTnn6PyhElnY5ljLkBVtzNPw6fOsar0z7hkx++I2emrHza5iUev6sJISEhTkczxtwgX2aFLAB8BeTF04FphKoO8lcwEzjxCfF8unQqr0wbzrEzp+hUvTm9Gz9JjkxZnY5mjEkiX/bcLwDPqeqvIpIFWCUic1V1k5+ymQD4cfs6nhn/Iav3bKV6kXJ8/OBzlMp3u9OxjDE+8mVWyD+BP723T4hILJAPsOJ+Hct/38DsHavYnf60ozm+WT6dueNXkz9HHsa1e4uWFe6xs0uNCRL+arMXDiwBSqrq8cu+Zm32LrF070Z6LfsGdUEv8TQhoTwYVY02xWuSIU1ax3I4/TNxSwa35HBDBrfkcEMGSFqbPZ+Lu4hkBhYDb6vqt9d6bFRUlG7ZssWn7flq0aJF1KhRw5Ft/7p7M9H92lPilkJ0KdGQu6rc6UiOizauXkuTug0dzQDO/kzclMEtOdyQwS053JABQERuuLj7dLSMiIQBk4HR1yvsqd2+owdoMvR5cmXKxrQOH7B59XoK5c7naKbdaX9zdPvGmOST5GPcxDM4+xkQq6r9/Rcp+Jw6d4YmQ3tw/OwpYuD07RsAAAwsSURBVDp+yM3Z7EQgY0zy8uUA5qrAw0AtEVnjvTj/Ht9lEhISeGjUG6zdu41x7d6itLWaM8YEgC9HyywF7NCK63hp6lC+W7uYgS2606hUVafjGGNSCTv1MBl9tmwa78/5hg7V7qdLzZZOxzHGpCJW3JPJwi2raD+mL3WKVWJQy2ft+HFjTEBZcU8GW/fvpvmIlyiSpwATnnjbpsc1xgScFXc/O3TyGI2GPEtoSAgxHfuRPWMWpyMZY1Ih26X0o/MX4mg+4kV2H9nPgm6DHT+O3RiTetmeu5+oKu3H9GXxb6v5/OFXqFq4jNORjDGpmBV3P3l/zteM+imG1xo+TptK9Z2OY4xJ5ay4+8G3qxfy4ndDebDCPfRu/KTTcYwxxoq7r1bt2sxDo96gSkRJRj3yqh3yaIxxBSvuPth75ABNhvUgd5YcfNe+LxnSpnc6kjHGAHa0TJKdPHuaJkN7cPLcaZb1GEHerDYZmDHGPXzacxeRz0XkgIhs8FeglCA+IZ42o15n3b5tjG/Xx9rSGWNcx9dhmS+AVHdoyItThjJt3Q8MbNGNBiXvcjqOMcb8h0/FXVWXAIf9lCVFGLl0Kh/OG02n6g/Q2SYDM8a4lD/a7IUDMapa8ipfD5oeqqv2b6Pn4s8pn/d23o1+lNCQUEdy+IsbMrglhxsyuCWHGzK4JYcbMkDSeqiiqj5dgHBgQ2IeGxkZqU5buHBhkp4X++cOzd79Hi3eu5UePX3CsRz+5IYMqu7I4YYMqu7I4YYMqu7I4YYMqqrASr3B2myHQibC3yeP0nhoD8JC0xDTsR/ZMjj/n9wYY67FDoW8jnNx57n/kxfZe+QAC7sPIeKmW52OZIwx1+XroZBjgZ+AKBHZKyLt/BPLHVSVp8e8xw/b1jDqkVe5s1AppyMZY0yi+LTnrqqt/RXEjd6b/RVfLv+eNxo9Qes76jodxxhjEs3G3K9i0q8LeHnqMFpXrEuvRkH1hsQYkwpYcb+CX3Zu4pEvenNnoVJ8/sgrNhmYMSbFseJ+mT2H99N02PPkzZqT757uS/qwdE5HMsaYG2ZHy1zi5NnTNBnWg1PnzzCv68fkyZrT6UjGGJMkVty94hPiaf35a6zft50ZnfpR4tZCTkcyxpgks2EZr+e//ZiY9cv4qOWz1C9xp9NxjDHGJ1bcgU9+mMKA+ePoXKMFnWo84HQcY4zxWaov7vNif6bTuA9pUOJO+j/Q1ek4xhjjF6m6uMf+uYMHPn2ZYjeHM65dH9KE2kcQxpjgkGqL+8XJwNKlCSOm44dkzZDJ6UjGGOM3qXJX9VzceZoN78m+owdZ1H0oBXPd4nQkY4zxK18nDqsvIltEZJuIvOivUMlJVXly9Lss3b6WLx99jSqFrthjxBhjUrQkF3cRCQWGAA2A4kBrESnur2DJZXTsQr5eMZM3mzzFgxXrOB3HGGOShS/DMpWAbar6O4CIjAPuBTZd7Qk7j+2nxJvOTSSpqsT+tZM2lerxaoPHHMthjDHJLck9VEXkAaC+qj7hXX4YqKyqz1z2uH96qKbLnbVCla7ONpXOHpaRjhUakzY0zNEcbujN6IYMbsnhhgxuyeGGDG7J4YYMEOAeqsADwMhLlh8GBl/rOSm5h6q/uSGHGzKouiOHGzKouiOHGzKouiOHGzKoBr6H6j6gwCXL+b33GWOMcZgvxf0XoIiIRIhIWqAVMM0/sYwxxvgiyR+oquoFEXkGmA2EAp+r6ka/JTPGGJNkvvZQ/R743k9ZjDHG+EmqnX7AGGOCmRV3Y4wJQlbcjTEmCFlxN8aYIJTkM1STtDGRE8CWgG3wym4C/nY4A7gjhxsygDtyuCEDuCOHGzKAO3K4IQNAlKpmuZEnBHrK3y16o6fQ+pmIrHQ6g1tyuCGDW3K4IYNbcrghg1tyuCHDxRw3+hwbljHGmCBkxd0YY4JQoIv7iABv70rckAHckcMNGcAdOdyQAdyRww0ZwB053JABkpAjoB+oGmOMCQwbljHGmCBkxd0YY4JQQIq7Gxppi8jnInJARDY4sX1vhgIislBENonIRhHp6lCO9CLys4is9ebo7UQOb5ZQEVktIjEOZtgpIutFZE1SDjnzU4bsIjJJRDaLSKyI3OlAhijva3DxclxEujmQo7v393KDiIwVkfSBzuDN0dWbYWOgXocr1SkRySkic0XkN+91jkSt7Ea7e9zoBc90wNuBQkBaYC1QPLm3e4Uc1YDywIZAb/uSDLcA5b23swBbHXotBMjsvR0GrACqOPSaPAuMAWIc/LnsBG5yavveDF8CT3hvpwWyO5wnFPgLKBjg7eYDdgAZvMsTgLYOfP8lgQ1ARjznA80Dbg/Adv9Tp4D3gRe9t18E+iZmXYHYc/+nkbaqngcuNtIOKFVdAhwO9HYvy/Cnqv7qvX0CiMXzyxzoHKqqJ72LYd5LwD9ZF5H8QCNgZKC37SYikg3PH/VnAKp6XlWPOpuK2sB2Vd3lwLbTABlEJA2e4vqHAxmKAStU9bSqXgAWA/cn90avUqfuxfPPH+/1fYlZVyCKez5gzyXLe3GgoLmNiIQD5fDsNTux/VARWQMcAOaqqhM5BgIvAAkObPtSCswRkVXehu6BFgEcBEZ5h6hGikgmB3JcqhUwNtAbVdV9wIfAbuBP4Jiqzgl0Djx77dEikktEMgIN+Xdb0UDKq6p/em//BeRNzJPsA1UHiEhmYDLQTVWPO5FBVeNVtSye3reVRKRkILcvIo2BA6q6KpDbvYq7VbU80ADoJCLVArz9NHjeig9T1XLAKTxvvx3hbZvZFJjowLZz4NlTjQBuBTKJyEOBzqGqsUBfYA4wC1gDxAc6x+XUMzaTqHfZgSju1kj7EiIShqewj1bVb53O4337vxCoH+BNVwWaishOPEN1tUTkmwBnAP7ZW0RVDwBT8AwlBtJeYO8l754m4Sn2TmkA/Kqq+x3Y9j3ADlU9qKpxwLfAXQ7kQFU/U9UKqloNOILnMzIn7BeRWwC81wcS86RAFHdrpO0lIoJnXDVWVfs7mCO3iGT33s4A1AE2BzKDqr6kqvlVNRzP78QCVQ34HpqIZBKRLBdvA3XxvCUPGFX9C9gjIlHeu2oDmwKZ4TKtcWBIxms3UEVEMnr/Xmrj+Wwq4EQkj/f6Njzj7WOcyIGnXj7qvf0oMDUxT0r2WSHVJY20RWQsUAO4SUT2Aq+r6mcBjlEVeBhY7x3vBnhZPb1oA+kW4EsRCcXzD36Cqjp2KKLD8gJTPHWENMAYVZ3lQI7OwGjvDtDvwGMOZLj4D64O8LQT21fVFSIyCfgVuACsxrkpACaLSC4gDugUiA+5r1SngPeACSLSDtgFtEzUuryH1xhjjAki9oGqMcYEISvuxhgThKy4G2NMELLibowxQciKuzHGBCEr7iZF8c6e2NF7+1bvYXPJta2yItIwudZvTHKy4m5SmuxARwBV/UNVH0jGbZXFM6eIMSmOHeduUhQRuTir6BbgN6CYqpYUkbZ4ZsvLBBTBM/lUWjwnjZ0DGqrqYREpDAwBcgOngSdVdbOItMBzwkg8cAzPafDbgAx4pst4F4gBPsYzHWwY8IaqTvVuuxmQDc+keN+oqmNz5BsDAThD1Rg/exEoqaplvTNrXnpmbUk8M22mx1OYe6pqOREZADyCZxbKEUB7Vf1NRCoDQ4FaQC+gnqruE5HsqnpeRHoBFVX1GQAReQfPNAmPe6dv+FlE5nm3Xcm7/dPALyIyQ1UdafxhDFhxN8FloXee/BMicgyY7r1/PVDaOxvnXcBE73QDAOm818uAL0RkAp7Jqq6kLp7Jznp4l9MDt3lvz1XVQwAi8i1wN2DF3TjGirsJJucuuZ1wyXICnt/1EOCod6rjf1HV9t49+UbAKhGpcIX1C9BcVbf8607P8y4f37TxTuMo+0DVpDQn8LQovGHeufN3eMfXEY8y3tuFVXWFqvbC0zijwBW2NRvo7J2tEBEpd8nX6nh7XWbAM/a/LCkZjfEXK+4mRfEOfSzzNhD+IAmraAO0E5G1wEb+v+XjB+Jpkr0B+BFPr9+FQHFvs+gHgbfwfJC6TkQ2epcv+hnPPP3rgMk23m6cZkfLGOMj79Ey/3zwaowb2J67McYEIdtzN8aYIGR77sYYE4SsuBtjTBCy4m6MMUHIirsxxgQhK+7GGBOE/g8p4r+mGESM3gAAAABJRU5ErkJggg==\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "# Run Cad^2\n", + "\n", + "first_config = configs # only contains config1\n", + "single_proc_ctx = ExecutionContext(context=exec_mode.single_proc)\n", + "run = Executor(exec_context=single_proc_ctx, configs=first_config)\n", + "\n", + "raw_result, tensor_field = run.execute()\n", + "df = pd.DataFrame(raw_result)\n", + "df.plot('timestep', ['box_A', 'box_B'], grid=True, \n", + " colormap = 'RdYlGn',\n", + " xticks=list(df['timestep'].drop_duplicates()), \n", + " yticks=list(range(1+(df['box_A']+df['box_B']).max())));" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Run 50 Monte Carlo Runs\n", + "In order to take advantage of cadCAD's Monte Carlo simulation features, we should modify the configuration file so as to define the number of times we want the same simulation to be run. This is done in the N key of the sim_config dictionary." + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "single_proc: [, ]\n", + "[, ]\n" + ] + } + ], + "source": [ + "import config2\n", + "first_config = configs # only contains config1\n", + "single_proc_ctx = ExecutionContext(context=exec_mode.single_proc)\n", + "run = Executor(exec_context=single_proc_ctx, configs=first_config)\n", + "\n", + "raw_result, tensor_field = run.execute()\n", + "df2 = pd.DataFrame(raw_result)" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
box_Abox_B
runtimestepsubstep
100100
1182
2164
3155
4155
...............
506155
7155
8155
9155
10155
\n", + "

550 rows × 2 columns

\n", + "
" + ], + "text/plain": [ + " box_A box_B\n", + "run timestep substep \n", + "1 0 0 10 0\n", + " 1 1 8 2\n", + " 2 1 6 4\n", + " 3 1 5 5\n", + " 4 1 5 5\n", + "... ... ...\n", + "50 6 1 5 5\n", + " 7 1 5 5\n", + " 8 1 5 5\n", + " 9 1 5 5\n", + " 10 1 5 5\n", + "\n", + "[550 rows x 2 columns]" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "from IPython.display import display\n", + "tmp_rows = pd.options.display.max_rows\n", + "pd.options.display.max_rows = 10\n", + "display(df2.set_index(['run', 'timestep', 'substep']))\n", + "pd.options.display.max_rows = tmp_rows" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Plotting two of those runs allows us to see the different behaviors over time." + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "df2[df2['run']==1].plot('timestep', ['box_A', 'box_B'], grid=True,\n", + " xticks=list(df['timestep'].drop_duplicates()), \n", + " yticks=list(range(11)),\n", + " colormap = 'RdYlGn');\n", + "df2[df2['run']==9].plot('timestep', ['box_A', 'box_B'], grid=True,\n", + " xticks=list(df['timestep'].drop_duplicates()), \n", + " yticks=list(range(11)),\n", + " colormap = 'RdYlGn');" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "If we plot all those runs onto a single chart, we can see every possible trajectory for the number of marbles in each box." + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "ax = None\n", + "for i in range(50):\n", + " ax = df2[df2['run']==i+1].plot('timestep', ['box_A', 'box_B'],\n", + " grid=True,\n", + " xticks=list(df['timestep'].drop_duplicates()), \n", + " yticks=list(range(1+max(df2['box_A'].max(),df2['box_B'].max()))),\n", + " legend = (ax == None),\n", + " colormap = 'RdYlGn',\n", + " ax = ax\n", + " )" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "For some analyses, it might make sense to look at the data in aggregate. Take the median for example:" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 9, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "dfmc_median = df2.groupby(['timestep', 'substep']).median().reset_index()\n", + "dfmc_median.plot('timestep', ['box_A', 'box_B'], \n", + " grid=True,\n", + " xticks=list(dfmc_median['timestep'].drop_duplicates()), \n", + " yticks=list(range(int(1+max(dfmc_median['box_A'].max(),dfmc_median['box_B'].max())))),\n", + " colormap = 'RdYlGn'\n", + " )" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Or look at edge cases" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "max_final_A = df2[df2['timestep']==df2['timestep'].max()]['box_A'].max()\n", + "# max_final_A\n", + "slow_runs = df2[(df2['timestep']==df2['timestep'].max()) & \n", + " (df2['box_A']==max_final_A)]['run']\n", + "slow_runs = list(slow_runs)\n", + "slow_runs\n", + "\n", + "ax = None\n", + "for i in slow_runs:\n", + " ax = df2[df2['run']==i].plot('timestep', ['box_A', 'box_B'],\n", + " grid=True,\n", + " xticks=list(df2['timestep'].drop_duplicates()), \n", + " yticks=list(range(1+max(df2['box_A'].max(),df2['box_B'].max()))),\n", + " legend = (ax == None),\n", + " colormap = 'RdYlGn',\n", + " ax = ax\n", + " )" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.7.0" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/tutorials/videos/robot-marbles-part-5/README.md b/tutorials/videos/robot-marbles-part-5/README.md new file mode 100644 index 0000000..af35b9f --- /dev/null +++ b/tutorials/videos/robot-marbles-part-5/README.md @@ -0,0 +1 @@ +https://www.youtube.com/watch?v=I0mSQppibLs&feature=youtu.be diff --git a/tutorials/videos/robot-marbles-part-5/images/Mech1.png b/tutorials/videos/robot-marbles-part-5/images/Mech1.png new file mode 100644 index 0000000000000000000000000000000000000000..b9d7a918b5e42f5368b5322d7386154ee4597dce GIT binary patch literal 22894 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%0Duj*;97C6$u07*80C3#?Sc;HBuO|?@!N&T! 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 literal 0 HcmV?d00001 diff --git a/tutorials/videos/robot-marbles-part-5/images/Overview.png b/tutorials/videos/robot-marbles-part-5/images/Overview.png new file mode 100644 index 0000000000000000000000000000000000000000..139b06723647ef96e3e8ddcadf5ca22d1c571a74 GIT binary patch literal 21586 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

@?h(BM@csu@ExUtv{@J=2IsSPIwWl~t%KP@A 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 MsXi>YZ~E$g0g!yQ=l}o! literal 0 HcmV?d00001 diff --git a/tutorials/videos/robot-marbles-part-5/robot-marbles-part-5.ipynb b/tutorials/videos/robot-marbles-part-5/robot-marbles-part-5.ipynb new file mode 100644 index 0000000..761bd34 --- /dev/null +++ b/tutorials/videos/robot-marbles-part-5/robot-marbles-part-5.ipynb @@ -0,0 +1,317 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# cadCAD Template: Robot and the Marbles - Part 5\n", + "\n", + "![](images/Overview.png)\n", + "![](images/Mech1.png)\n", + "\n", + "To expand upon our previous examples, we will introduce the concept of using a graph network object that is updated during each state update. The ability to essential embed a graph 'database' into a state is a game changer for scalability, allowing increased complexity with multiple agents or components is represented, easily updated. Below, building upon our previous examples, we will represent the Robots and Marbles example with n boxes, and a variable number of marbles.\n", + "\n", + "## Behavior and Mechanisms:\n", + "* A network of robotic arms is capable of taking a marble from their one of their boxes and dropping it into the other one.\n", + "* Each robotic arm in the network only controls two boxes and they act by moving a marble from one box to the other.\n", + "* Each robotic arm is programmed to take one marble at a time from the box containing the most significant number of marbles and drop it in the other box. It repeats that process until the boxes contain an equal number of marbles.\n", + "* For our analysis of this system, suppose we are only interested in monitoring the number of marbles in only their two boxes." + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "from cadCAD.engine import ExecutionMode, ExecutionContext, Executor\n", + "from cadCAD.configuration import Configuration\n", + "import networkx as nx\n", + "import matplotlib.pyplot as plt\n", + "import numpy as np\n", + "import pandas as pd\n", + "#from copy import deepcopy\n", + "\n", + "%matplotlib inline" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [], + "source": [ + "# define global variables\n", + "T = 25 #iterations in our simulation\n", + "boxes=5 #number of boxes in our network\n", + "m= 2 #for barabasi graph type number of edges is (n-2)*m\n", + "\n", + "# Settings of general simulation parameters, unrelated to the system itself\n", + "# `T` is a range with the number of discrete units of time the simulation will run for;\n", + "# `N` is the number of times the simulation will be run (Monte Carlo runs)\n", + "simulation_parameters = {\n", + " 'T': range(T),\n", + " 'N': 1,\n", + " 'M': {}\n", + "}\n", + "\n", + "# We create a Barabási–Albert graph and then fill the 5 boxes with between 1 and 10 balls.\n", + "# create graph object with the number of boxes as nodes\n", + "network = nx.barabasi_albert_graph(boxes, m)\n", + "\n", + "# add balls to box nodes\n", + "for node in network.nodes:\n", + " network.nodes[node]['balls'] = np.random.randint(1,10)\n", + " \n", + " \n", + "\n", + "#Behavior: node by edge dimensional operator\n", + "#input the states of the boxes output the deltas along the edges\n", + "\n", + "# We specify the robotic networks logic in a Policy/Behavior Function\n", + "# unlike previous examples our policy controls a vector valued action, defined over the edges of our network\n", + "def robotic_network(params, step, sL, s):\n", + " network = s['network']\n", + " delta_balls = {}\n", + " for e in network.edges:\n", + " src = e[0]\n", + " dst = e[1]\n", + " #transfer one ball across the edge in the direction of more balls to less\n", + " delta_balls[e] = np.sign(network.nodes[src]['balls']-network.nodes[dst]['balls'])\n", + " return({'delta': delta_balls}) \n", + " \n", + "\n", + "#mechanism: edge by node dimensional operator\n", + "#input the deltas along the edges and update the boxes\n", + "\n", + "# We make the state update functions less \"intelligent\",\n", + "# ie. they simply add the number of marbles specified in _input \n", + "# (which, per the policy function definition, may be negative)\n", + "\n", + "def update_network(params, step, sL, s, _input):\n", + " network = s['network'] #deepcopy(s['network']) \n", + " delta_balls = _input['delta']\n", + " for e in network.edges:\n", + " move_ball = delta_balls[e]\n", + " src = e[0]\n", + " dst = e[1]\n", + " if (network.nodes[src]['balls'] >= move_ball) and (network.nodes[dst]['balls'] >= -move_ball):\n", + " network.nodes[src]['balls'] = network.nodes[src]['balls']-move_ball\n", + " network.nodes[dst]['balls'] = network.nodes[dst]['balls']+move_ball\n", + " \n", + " return ('network', network)\n", + "\n", + " \n", + "# we initialize the cadCAD state as a network object\n", + "initial_conditions = {'network':network}\n", + "\n", + "\n", + "# wire up the mechanisms and states\n", + "partial_state_update_blocks = [\n", + " { \n", + " 'policies': { # The following policy functions will be evaluated and their returns will be passed to the state update functions\n", + " 'action': robotic_network\n", + " },\n", + " 'variables': { # The following state variables will be updated simultaneously\n", + " 'network': update_network\n", + " \n", + " }\n", + " }\n", + "]\n", + "\n", + "\n", + "# The configurations above are then packaged into a `Configuration` object\n", + "config = Configuration(initial_state=initial_conditions, #dict containing variable names and initial values\n", + " partial_state_update_blocks=partial_state_update_blocks, #dict containing state update functions\n", + " sim_config=simulation_parameters #dict containing simulation parameters\n", + " )" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now we will plot the network of boxes and with their labels showing how many balls are in each box." + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/usr/local/lib/python3.7/site-packages/networkx/drawing/nx_pylab.py:579: MatplotlibDeprecationWarning: \n", + "The iterable function was deprecated in Matplotlib 3.1 and will be removed in 3.3. Use np.iterable instead.\n", + " if not cb.iterable(width):\n" + ] + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "

" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "# plot of boxes and balls\n", + "nx.draw_kamada_kawai(network,labels=nx.get_node_attributes(network,'balls'))" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "single_proc: []\n", + "[]\n" + ] + } + ], + "source": [ + "# Run the simulations\n", + "exec_mode = ExecutionMode()\n", + "exec_context = ExecutionContext(exec_mode.single_proc)\n", + "executor = Executor(exec_context, [config]) # Pass the configuration object inside an array\n", + "raw_result, tensor = executor.execute() # The `execute()` method returns a tuple; its first elements contains the raw results\n", + "df = pd.DataFrame(raw_result)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We create some helper functions to extract the networkx graph object from the Pandas dataframe and plot it." + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [], + "source": [ + "#NetworkX helper functions\n", + "def get_nodes(g):\n", + " return [node for node in g.nodes if g.nodes[node]]\n", + "\n", + "\n", + "def pad(vec, length,fill=True):\n", + " if fill:\n", + " padded = np.zeros(length,)\n", + " else:\n", + " padded = np.empty(length,)\n", + " padded[:] = np.nan\n", + " \n", + " for i in range(len(vec)):\n", + " padded[i]= vec[i]\n", + " \n", + " return padded\n", + "\n", + "def make2D(key, data, fill=False):\n", + " maxL = data[key].apply(len).max()\n", + " newkey = 'padded_'+key\n", + " data[newkey] = data[key].apply(lambda x: pad(x,maxL,fill))\n", + " reshaped = np.array([a for a in data[newkey].values])\n", + " \n", + " return reshaped" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Using our helper function get_nodes() we pull out the boxes ball quantity and save it to a new dataframe column." + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [], + "source": [ + "df['Balls'] = df.network.apply(lambda g: np.array([g.nodes[j]['balls'] for j in get_nodes(g)]))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Next we will plot the number of balls in each box over the simulation time period. We can see an oscillation occurs never reaching an equilibrium due to the uneven nature of the boxes and balls." + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 7, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "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yUht6yZKadoTgYni6caNG9m7dy8LFiwAYGhoiAULFuQyTHp4i0BK+Zb59453vEOeCHr+8KDcvniJTO7efUJ0piq2b98+2V2Q1dXVub937NghI5GITKfT8p577pEf+MAHZDqdlsePH5dz586VR48elalUSp511lny2WeflTfeeKO85ZZbLOmm02n5rne9S0op5fve9z7Z29tred28efNkZ2en8wObREw2T/P7kI+3wrybygBelTYydYpp8KN54SsXLpzk3niwwmSlC/7pT3/KzTffTEdHB6tWreLSSy/NvSx8u2OyeOrhrY8pkS5YR+rYcfZeeCEzvvV/abruOgd7NjXgpW31MBnw5p27mPLpgnUEpkURwSBp70WrBw8ePEwtAS98PgKzZzHiuUp68ODBw9QS8KDK93mukh48ePAwBQV8YPZsLx+NBw8ePDAFBXxFczOZWIxsMjnZXfHgwYOHScWUE/C5tMHtRye5Jx48ePAwuXBVwAshGoQQdwshdgohdgghznOzPfAKf7zVMVmpba+//noWL17MihUruOGGG0ilUo6268HDWxFua/A/ATZIKZcALcAOl9vzCn+8xTFZqW2vv/56du7cyZYtW0gkElMmyMmDh2JwTcALIeqBC4BfAUgpR6SUPY43NDIET34X9jwKQGD6dAgEJlWDjyVi3LP7HtfoSym5c9edxBNx19oYTA0ymBp0jX46m6Y91u5qatsPXfohfv6LnwNw6aWXIoRACME555zD4cOHT3gMQ6khBkaczR5pRCabIZ6I42YwYs9wDyOZEdfoJ9IJkmn33ocl00n+a9t/kc6mXWtjw4EN7O/d7xr9hw88zK0bb3WFtpupCk4FOoHbhBAtwGvAl6SUJqkhhPhL4C8B5s6dO/ZWApWw8XfQvhEW/hkiECA4c+akavD3772fH7/+Yy485UKi4ajj9DsGO/jOi98hkU7wyeWfHBeN77/8fXZ27bT9PZlOIpGEA+GyaS5pWsLXzvla0Wv0sPrBxCAdRzt45LFHAOdT2375y1/mpp/dxLSqaabrUqkUv/3tb/nJT35S9rjs0JnoZCQzwsIKd9Ji9I/00zHYQVWwakzPoVxkZZYj/UeIhCPMrC7kqROIJWL0Dve6Qhvg2SPPcsurt7A8upx3zHiH4/SllPyfZ/8PVy28im+e+03H6QM8c/gZXul4hc+f8XnH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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "plt.plot(df.timestep,make2D('Balls', df))\n", + "plt.title('Number of balls in boxes over simulation period')\n", + "plt.ylabel('Qty')\n", + "plt.xlabel('Iteration')\n", + "plt.legend(['Box #'+str(node) for node in range(boxes)], ncol = 2)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "In summary, we created a graph network of boxes and robotic arms to transfer balls between the boxes, striving for an unachievable equilibrium state. The ability to embed a graph, virtually a graph database, into a cadCAD state allows for tremendous scalability and flexibility as a modeling tool." + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.7.0" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} From 7d0a14efbf707463b5052cf4ceb1d92debc68cdb Mon Sep 17 00:00:00 2001 From: "Joshua E. Jodesty" Date: Thu, 22 Aug 2019 12:52:32 -0400 Subject: [PATCH 09/21] added docs from tutorial --- .gitignore | 9 +- README.md | 28 ++- Simulation.md | 151 -------------- documentation/Policy_Aggregation.md | 21 +- documentation/Simulation_Configuration.md | 159 +++++++++------ .../{Execution.md => Simulation_Execution.md} | 2 +- documentation/System_Model_Parameter_Sweep.md | 6 +- documentation/examples/policy_aggregation.py | 2 +- documentation/examples/sys_model_A.py | 3 - setup.py | 2 +- testing/example.py | 20 -- testing/example2.py | 71 ------- testing/generic_test.py | 16 -- testing/system_models/external_dataset.py | 5 +- .../system_models/historical_state_access.py | 2 - testing/system_models/param_sweep.py | 12 -- testing/system_models/policy_aggregation.py | 5 +- testing/system_models/udo.py | 185 ------------------ .../{external_test.py => external_dataset.py} | 23 +-- testing/tests/historical_state_access.py | 2 - testing/tests/multi_config_test.py | 56 ------ testing/tests/param_sweep.py | 12 -- testing/tests/policy_aggregation.py | 4 + testing/tests/udo.py | 39 ---- 24 files changed, 161 insertions(+), 674 deletions(-) delete mode 100644 Simulation.md rename documentation/{Execution.md => Simulation_Execution.md} (99%) delete mode 100644 testing/example.py delete mode 100644 testing/example2.py delete mode 100644 testing/system_models/udo.py rename testing/tests/{external_test.py => external_dataset.py} (83%) delete mode 100644 testing/tests/multi_config_test.py delete mode 100644 testing/tests/udo.py diff --git a/.gitignore b/.gitignore index 2990b51..8b72b88 100644 --- a/.gitignore +++ b/.gitignore @@ -19,6 +19,13 @@ cadCAD.egg-info build cadCAD.egg-info -SimCAD.egg-info + +testing/example.py +testing/example2.py +testing/multi_config_test.py +testing/udo.py +testing/udo_test.py + +Simulation.md monkeytype.sqlite3 \ No newline at end of file diff --git a/README.md b/README.md index ee67bb9..da92cd3 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,17 @@ -# cadCAD -**Warning**: -**Do not** publish this package / software to **any** software repository **except** one permitted by BlockScience. +``` + __________ ____ + ________ __ _____/ ____/ | / __ \ + / ___/ __` / __ / / / /| | / / / / +/ /__/ /_/ / /_/ / /___/ ___ |/ /_/ / +\___/\__,_/\__,_/\____/_/ |_/_____/ +by BlockScience +``` + +**Introduction:** + +***cadCAD*** is a Python library that assists in the processes of designing, testing and validating complex systems through +simulation. At its core, cadCAD is a differential games engine that supports parameter sweeping and Monte Carlo analyses +and can be easily integrated with other scientific computing Python modules and data science workflows. **Description:** @@ -35,9 +46,9 @@ and see how it evolves. We can then use these results to inform business decisio #### 0. Installation: -**Option A:** Package Repository Access +**Option A:** Proprietary Build Access -***IMPORTANT NOTE:*** Tokens are issued to and meant to be used by trial users and BlockScience employees **ONLY**. +***IMPORTANT NOTE:*** Tokens are issued to those with access to proprietary builds of cadCAD and BlockScience employees **ONLY**. Replace \ with an issued token in the script below. ```bash pip3 install pandas pathos fn funcy tabulate @@ -147,3 +158,10 @@ for raw_result, tensor_field in run.execute(): print() ``` +### Tests: +```python +python -m unittest testing/tests/param_sweep.py +python -m unittest testing/tests/policy_aggregation.py +python -m unittest testing/tests/historical_state_access.py +python -m unittest testing/tests/external_dataset.py +``` diff --git a/Simulation.md b/Simulation.md deleted file mode 100644 index 8c1d3cf..0000000 --- a/Simulation.md +++ /dev/null @@ -1,151 +0,0 @@ -# cadCAD Documentation - -## Introduction - -A blockchain is a distributed ledger with economic agents transacting in a network. The state of the network evolves with every new transaction, which can be a result of user behaviors, protocol-defined system mechanisms, or external processes. - -It is not uncommon today for blockchain projects to announce a set of rules for their network and make claims about their system level behvaior. However, the validity of those claims is hardly validated. Furthermore, it is difficult to know the potential system-level impact when the network is considering an upgrade to their system rules and prameters. - -To rigorously and reliably analyze, design, and improve cryptoeconomic networks, we are introducing this Computer Aided Design Engine where we define a cryptoeconomic network with its state and exogneous variables, model transactions as a result of agent behaviors, state mechanisms, and environmental processes. We can then run simulations with different initial states, mechanisms, environmental processes to understand and visualize network behavior under different conditions. - -## State Variables and Transitions - -We now define variables and different transition mechanisms that will be inputs to the simulation engine. - -- ***State variables*** are defined to capture the shape and property of the network, such as a vector or a dictionary that captures all user balances. -- ***Exogenous variables*** are variables that represent external input and signal. They are only affected by environmental processes and are not affected by system mechanisms. Nonetheless, exgoneous variables can be used as an input to a mechanism that impacts state variables. They can be considered as read-only variables to the system. -- ***Behaviors per transition*** model agent behaviors in reaction to state variables and exogenous variables. The resulted user action will become an input to state mechanisms. Note that user behaviors should not directly update value of state variables. -- ***State mechanisms per transition*** are system defined mechanisms that take user actions and other states as inputs and produce updates to the value of state variables. -- ***Exogenous state updates*** specify how exogenous variables evolve with time which can indirectly impact state variables through behavior and state mechanisms. -- ***Environmental processes*** model external changes that directly impact state or exogenous variables at specific timestamps or conditions. - -A state evolves to another state via state transition. Each transition is composed of behavior and state mechanisms as functions of state and exogenous variables. A flow of the state transition is as follows. - -Given some state and exogenous variables of the system at the onset of a state transition, agent behavior takes in these variables as input and return a set of agent actions. This models after agent behavior and reaction to a set of variables. Given these agent actions, state mechanism, as defined by the protocol, takes these actions, state, and exogenous variables as inputs and return a new set of state variables. - -## System Configuration File - -Simulation engine takes in system configuration files, e.g. `config.py`, where all the above variables and mechanisms are defined. The following import statements should be added at the beginning of the configuration files. -```python -from decimal import Decimal -import numpy as np -from datetime import timedelta - -from cadCAD import configs -from cadCAD.configuration import Configuration -from cadCAD.configuration.utils import exo_update_per_ts, proc_trigger, bound_norm_random, \ - ep_time_step -``` - -State variables and their initial values can be defined as follows. Note that `timestamp` is a required field for this iteration of cadCAD for `env_proc` to work. Future iterations will strive to make this more generic and timestamp optional. -```python -genesis_dict = { - 's1': Decimal(0.0), - 's2': Decimal(0.0), - 's3': Decimal(1.0), - 'timestamp': '2018-10-01 15:16:24' -} -``` - -Each potential transition and its state and behavior mechanisms can be defined in the following dictionary object. -```python -transitions = { - "m1": { - "behaviors": { - "b1": b1m1, - "b2": b2m1 - }, - "states": { - "s1": s1m1, - "s2": s2m1 - } - }, - "m2": {...} -} -``` -Every behavior per transition should return a dictionary as actions taken by the agents. They will then be aggregated through addition in this version of cadCAD. Some examples of behaviors per transition are as follows. More flexible and user-defined aggregation functions will be introduced in future iterations but no example is provided at this point. -```python -def b1m1(step, sL, s): - return {'param1': 1} - -def b1m2(step, sL, s): - return {'param1': 'a', 'param2': 2} - -def b1m3(step, sL, s): - return {'param1': ['c'], 'param2': np.array([10, 100])} -``` -State mechanism per transition on the other hand takes in the output of behavior mechanisms (`_input`) and returns a tuple of the name of the variable and the new value for the variable. Some examples of a state mechanism per transition are as follows. Note that each state mechanism is supposed to change one state variable at a time. Changes to multiple state variables should be done in separate mechanisms. -```python -def s1m1(step, sL, s, _input): - y = 's1' - x = _input['param1'] + 1 - return (y, x) - -def s1m2(step, sL, s, _input): - y = 's1' - x = _input['param1'] - return (y, x) -``` -Exogenous state update functions, for example `es3p1`, `es4p2` and `es5p2` below, update exogenous variables at every timestamp. Note that every timestamp is consist of all behaviors and state mechanisms in the order defined in `transitions` dictionary. If `exo_update_per_ts` is not used, exogenous state updates will be applied at every mechanism step (`m1`, `m2`, etc). Otherwise, exogenous state updates will only be applied once for every timestamp after all the mechanism steps are executed. -```python -exogenous_states = exo_update_per_ts( - { - "s3": es3p1, - "s4": es4p2, - "timestamp": es5p2 - } -) -``` -To model randomness, we should also define pseudorandom seeds in the configuration as follows. -```python -seed = { - 'z': np.random.RandomState(1), - 'a': np.random.RandomState(2), - 'b': np.random.RandomState(3), - 'c': np.random.RandomState(3) -} -``` -cadCAD currently supports generating random number from a normal distribution through `bound_norm_random` with `min` and `max` values specified. Examples of environmental processes with randomness are as follows. We also define timestamp format with `ts_format` and timestamp changes with `t_delta`. Users can define other distributions to update exogenous variables. -```python -proc_one_coef_A = 0.7 -proc_one_coef_B = 1.3 - -def es3p1(step, sL, s, _input): - y = 's3' - 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' - x = s['s4'] * bound_norm_random(seed['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(step, sL, s, _input): - y = 'timestamp' - x = ep_time_step(s, s['timestamp'], fromat_str=ts_format, _timedelta=t_delta) - return (y, x) -``` -User can also define specific external events such as market shocks at specific timestamps through `env_processes` with `proc_trigger`. An environmental process with no `proc_trigger` will be called at every timestamp. In the example below, it will return the value of `s3` at every timestamp. Logical event triggers, such as a big draw down in exogenous variables, will be supported in a later version of cadCAD. -```python -def env_a(x): - return x -def env_b(x): - return 10 - -env_processes = { - "s3": env_a, - "s4": proc_trigger('2018-10-01 15:16:25', env_b) -} -``` - -Lastly, we set the overall simulation configuration and initialize the `Configuration` class with the following. `T` denotes the time range and `N` refers to the number of simulation runs. Each run will start from the same initial states and run for `T` time range. Every transition is consist of behaviors, state mechanisms, exogenous updates, and potentially environmental processes. All of these happen within one time step in the simulation. -```python -sim_config = { - "N": 2, - "T": range(5) -} - -configs.append(Configuration(sim_config, state_dict, seed, exogenous_states, env_processes, mechanisms)) -``` \ No newline at end of file diff --git a/documentation/Policy_Aggregation.md b/documentation/Policy_Aggregation.md index 64b4b1e..b80db6b 100644 --- a/documentation/Policy_Aggregation.md +++ b/documentation/Policy_Aggregation.md @@ -56,5 +56,22 @@ append_configs( ) ``` -#### [Example Configuration](link) -#### [Example Results](link) \ No newline at end of file +#### Example +##### * [System Model Configuration](https://github.com/BlockScience/cadCAD-Tutorials/blob/master/Documentation/examples/policy_aggregation.py) +##### * Simulation Results: +``` ++----+---------------------------------------------+-------+------+-----------+------------+ +| | policies | run | s1 | substep | timestep | +|----+---------------------------------------------+-------+------+-----------+------------| +| 0 | {} | 1 | 0 | 0 | 0 | +| 1 | {'policy1': 2, 'policy2': 4} | 1 | 1 | 1 | 1 | +| 2 | {'policy1': 8, 'policy2': 8} | 1 | 2 | 2 | 1 | +| 3 | {'policy3': 12, 'policy1': 4, 'policy2': 8} | 1 | 3 | 3 | 1 | +| 4 | {'policy1': 2, 'policy2': 4} | 1 | 4 | 1 | 2 | +| 5 | {'policy1': 8, 'policy2': 8} | 1 | 5 | 2 | 2 | +| 6 | {'policy3': 12, 'policy1': 4, 'policy2': 8} | 1 | 6 | 3 | 2 | +| 7 | {'policy1': 2, 'policy2': 4} | 1 | 7 | 1 | 3 | +| 8 | {'policy1': 8, 'policy2': 8} | 1 | 8 | 2 | 3 | +| 9 | {'policy3': 12, 'policy1': 4, 'policy2': 8} | 1 | 9 | 3 | 3 | ++----+---------------------------------------------+-------+------+-----------+------------+ +``` diff --git a/documentation/Simulation_Configuration.md b/documentation/Simulation_Configuration.md index 304a01d..0656244 100644 --- a/documentation/Simulation_Configuration.md +++ b/documentation/Simulation_Configuration.md @@ -3,12 +3,16 @@ Simulation Configuration ## Introduction -Given a **Simulation Configuration**, cadCAD produces datasets that represent the evolution of the state of a system over [discrete time](https://en.wikipedia.org/wiki/Discrete_time_and_continuous_time#Discrete_time). The state of the system is described by a set of [State Variables](#State-Variables). The dynamic of the system is described by [Policy Functions](#Policy-Functions) and [State Update Functions](#State-Update-Functions), which are evaluated by cadCAD according to the definitions set by the user in [Partial State Update Blocks](#Partial-State-Update-Blocks). +Given a **Simulation Configuration**, cadCAD produces datasets that represent the evolution of the state of a system +over [discrete time](https://en.wikipedia.org/wiki/Discrete_time_and_continuous_time#Discrete_time). The state of the +system is described by a set of [State Variables](#State-Variables). The dynamic of the system is described by +[Policy Functions](#Policy-Functions) and [State Update Functions](#State-Update-Functions), which are evaluated by +cadCAD according to the definitions set by the user in [Partial State Update Blocks](#Partial-State-Update-Blocks). -A Simulation Configuration is comprised of a [System Model](#System-Model) and a set of [Simulation Properties](#Simulation-Properties) +A Simulation Configuration is comprised of a [System Model](#System-Model) and a set of +[Simulation Properties](#Simulation-Properties) -`append_configs`, stores a **Simulation Configuration** to be -[Executed](https://github.com/BlockScience/cadCAD-Tutorials/blob/master/Documentation/Simulation_Execution.md) by cadCAD +`append_configs`, stores a **Simulation Configuration** to be [Executed](/JS4Q9oayQASihxHBJzz4Ug) by cadCAD ```python from cadCAD.configuration import append_configs @@ -21,25 +25,15 @@ append_configs( ) ``` Parameters: -* **initial_state** : _dict_ - - [State Variables](#State-Variables) and their initial values - -* **partial_state_update_blocks** : List[dict[dict]] - - List of [Partial State Update Blocks](#Partial-State-Update-Blocks) - -* **policy_ops** : List[functions] - - See [Policy Aggregation](https://github.com/BlockScience/cadCAD-Tutorials/blob/master/Documentation/Policy_Aggregation.md) - -* **sim_configs** : - - See +* **initial_state** : _dict_ - [State Variables](#State-Variables) and their initial values +* **partial_state_update_blocks** : List[dict[dict]] - List of [Partial State Update Blocks](#Partial-State-Update-Blocks) +* **policy_ops** : List[functions] - See [Policy Aggregation](/63k2ncjITuqOPCUHzK7Viw) +* **sim_configs** - See [System Model Parameter Sweep](/4oJ_GT6zRWW8AO3yMhFKrg) ## Simulation Properties -Simulation properties are passed to `append_configs` in the `sim_configs` parameter. To construct this paramenter, we use the `config_sim` function in `cadCAD.configuration.utils` +Simulation properties are passed to `append_configs` in the `sim_configs` parameter. To construct this parameter, we +use the `config_sim` function in `cadCAD.configuration.utils` ```python from cadCAD.configuration.utils import config_sim @@ -59,29 +53,46 @@ append_configs( ### T - Simulation Length Computer simulations run in discrete time: ->Discrete time views values of variables as occurring at distinct, separate "points in time", or equivalently as being unchanged throughout each non-zero region of time ("time period")—that is, time is viewed as a discrete variable. (...) This view of time corresponds to a digital clock that gives a fixed reading of 10:37 for a while, and then jumps to a new fixed reading of 10:38, etc. ([source: Wikipedia](https://en.wikipedia.org/wiki/Discrete_time_and_continuous_time#Discrete_time)) +>Discrete time views values of variables as occurring at distinct, separate "points in time", or equivalently as being +unchanged throughout each non-zero region of time ("time period")—that is, time is viewed as a discrete variable. (...) +This view of time corresponds to a digital clock that gives a fixed reading of 10:37 for a while, and then jumps to a +new fixed reading of 10:38, etc. +([source: Wikipedia](https://en.wikipedia.org/wiki/Discrete_time_and_continuous_time#Discrete_time)) -As is common in many simulation tools, in cadCAD too we refer to each discrete unit of time as a **timestep**. cadCAD increments a "time counter", and at each step it updates the state variables according to the equations that describe the system. +As is common in many simulation tools, in cadCAD too we refer to each discrete unit of time as a **timestep**. cadCAD +increments a "time counter", and at each step it updates the state variables according to the equations that describe +the system. -The main simulation property that the user must set when creating a Simulation Configuration is the number of timesteps in the simulation. In other words, for how long do they want to simulate the system that has been modeled. +The main simulation property that the user must set when creating a Simulation Configuration is the number of timesteps +in the simulation. In other words, for how long do they want to simulate the system that has been modeled. ### N - Number of Runs -cadCAD facilitates running multiple simulations of the same system sequentially, reporting the results of all those runs in a single dataset. This is especially helpful for running [Monte Carlo Simulations](https://github.com/BlockScience/cadCAD-Tutorials/blob/master/01%20Tutorials/robot-marbles-part-4/robot-marbles-part-4.ipynb). +cadCAD facilitates running multiple simulations of the same system sequentially, reporting the results of all those +runs in a single dataset. This is especially helpful for running +[Monte Carlo Simulations](https://github.com/BlockScience/cadCAD-Tutorials/blob/master/01%20Tutorials/robot-marbles-part-4/robot-marbles-part-4.ipynb). ### M - Parameters of the System -Parameters of the system, passed to the state update functions and the policy functions in the `params` parameter are defined here. See [System Model Parameter Sweep](/4oJ_GT6zRWW8AO3yMhFKrg) for more information. +Parameters of the system, passed to the state update functions and the policy functions in the `params` parameter are +defined here. See [System Model Parameter Sweep](/4oJ_GT6zRWW8AO3yMhFKrg) for more information. ## System Model -The System Model describes the system that will be simulated in cadCAD. It is comprised of a set of [State Variables](#Sate-Variables) and the [State Update Functions](#State-Update-Functions) that determine the evolution of the state of the system over time. [Policy Functions](#Policy-Functions) (representations of user policies or internal system control policies) may also be part of a System Model. +The System Model describes the system that will be simulated in cadCAD. It is comprised of a set of +[State Variables](###Sate-Variables) and the [State Update Functions](#State-Update-Functions) that determine the +evolution of the state of the system over time. [Policy Functions](#Policy-Functions) (representations of user policies +or internal system control policies) may also be part of a System Model. ### State Variables ->A state variable is one of the set of variables that are used to describe the mathematical "state" of a dynamical system. Intuitively, the state of a system describes enough about the system to determine its future behaviour in the absence of any external forces affecting the system. ([source: Wikipedia](https://en.wikipedia.org/wiki/State_variable)) +>A state variable is one of the set of variables that are used to describe the mathematical "state" of a dynamical +system. Intuitively, the state of a system describes enough about the system to determine its future behaviour in the +absence of any external forces affecting the system. ([source: Wikipedia](https://en.wikipedia.org/wiki/State_variable)) -cadCAD can handle state variables of any Python data type, including custom classes. It is up to the user of cadCAD to determine the state variables needed to **sufficiently and accurately** describe the system they are interested in. +cadCAD can handle state variables of any Python data type, including custom classes. It is up to the user of cadCAD to +determine the state variables needed to **sufficiently and accurately** describe the system they are interested in. -State Variables are passed to `append_configs` along with its initial values, as a Python `dict` where the `dict_keys` are the names of the variables and the `dict_values` are their initial values. +State Variables are passed to `append_configs` along with its initial values, as a Python `dict` where the `dict_keys` +are the names of the variables and the `dict_values` are their initial values. ```python from cadCAD.configuration import append_configs @@ -99,41 +110,48 @@ append_configs( ) ``` ### State Update Functions -State Update Functions represent equations according to which the state variables change over time. Each state update function must return a tuple containing a string with the name of the state variable being updated and its new value. Each state update function can only modify a single state variable. The general structure of a state update function is: +State Update Functions represent equations according to which the state variables change over time. Each state update +function must return a tuple containing a string with the name of the state variable being updated and its new value. +Each state update function can only modify a single state variable. The general structure of a state update function is: ```python def state_update_function_A(_params, substep, sH, s, _input): ... return 'state_variable_name', new_value ``` Parameters: -* **_params** : _dict_ - [System parameters](/4oJ_GT6zRWW8AO3yMhFKrg) -* **substep** : _int_ - Current [substep](#Substep) -* **sH** : _list[list[dict_]] - Historical values of all state variables for the simulation. See [Historical State Access](/smiyQTnATtC9xPwvF8KbBQ) for details -* **s** : _dict_ - Current state of the system, where the `dict_keys` are the names of the state variables and the `dict_values` are their current values. -* **_input** : _dict_ - Aggregation of the signals of all policy functions in the current [Partial State Update Block](#Partial-State-Update-Block) +* **_params** : _dict_ - [System parameters](/4oJ_GT6zRWW8AO3yMhFKrg) +* **substep** : _int_ - Current [substep](#Substep) +* **sH** : _list[list[dict_]] - Historical values of all state variables for the simulation. See +[Historical State Access](/smiyQTnATtC9xPwvF8KbBQ) for details +* **s** : _dict_ - Current state of the system, where the `dict_keys` are the names of the state variables and the +`dict_values` are their current values. +* **_input** : _dict_ - Aggregation of the signals of all policy functions in the current +[Partial State Update Block](#Partial-State-Update-Block) Return: * _tuple_ containing a string with the name of the state variable being updated and its new value. -State update functions should not modify any of the parameters passed to it, as those are mutable Python objects that cadCAD relies on in order to run the simulation according to the specifications. +State update functions should not modify any of the parameters passed to it, as those are mutable Python objects that +cadCAD relies on in order to run the simulation according to the specifications. ### Policy Functions -A Policy Function computes one or more signals to be passed to [State Update Functions](#State-Update-Functions) (via the _\_input_ parameter). Read [this article](https://github.com/BlockScience/cadCAD-Tutorials/blob/master/01%20Tutorials/robot-marbles-part-2/robot-marbles-part-2.ipynb) for details on why and when to use policy functions. +A Policy Function computes one or more signals to be passed to [State Update Functions](#State-Update-Functions) +(via the _\_input_ parameter). Read +[this article](https://github.com/BlockScience/cadCAD-Tutorials/blob/master/01%20Tutorials/robot-marbles-part-2/robot-marbles-part-2.ipynb) +for details on why and when to use policy functions. The general structure of a policy function is: @@ -143,29 +161,38 @@ def policy_function_1(_params, substep, sH, s): return {'signal_1': value_1, ..., 'signal_N': value_N} ``` Parameters: -* **_params** : _dict_ - [System parameters](/4oJ_GT6zRWW8AO3yMhFKrg) -* **substep** : _int_ - Current [substep](#Substep) -* **sH** : _list[list[dict_]] - Historical values of all state variables for the simulation. See [Historical State Access](/smiyQTnATtC9xPwvF8KbBQ) for details -* **s** : _dict_ - Current state of the system, where the `dict_keys` are the names of the state variables and the `dict_values` are their current values. +* **_params** : _dict_ - [System parameters](/4oJ_GT6zRWW8AO3yMhFKrg) +* **substep** : _int_ - Current [substep](#Substep) +* **sH** : _list[list[dict_]] - Historical values of all state variables for the simulation. See +[Historical State Access](/smiyQTnATtC9xPwvF8KbBQ) for details +* **s** : _dict_ - Current state of the system, where the `dict_keys` are the names of the state variables and the +`dict_values` are their current values. Return: -* _dict_ of signals to be passed to the state update functions in the same [Partial State Update Block](#Partial-State-Update-Blocks) +* _dict_ of signals to be passed to the state update functions in the same +[Partial State Update Block](#Partial-State-Update-Blocks) -Policy functions should not modify any of the parameters passed to it, as those are mutable Python objects that cadCAD relies on in order to run the simulation according to the specifications. +Policy functions should not modify any of the parameters passed to it, as those are mutable Python objects that cadCAD +relies on in order to run the simulation according to the specifications. -At each [Partial State Update Block](#Partial-State-Update-Blocks) (PSUB), the `dicts` returned by all policy functions within that PSUB dictionaries are aggregated into a single `dict` using an initial reduction function (a key-wise operation, default: `dic1['keyA'] + dic2['keyA']`) and optional subsequent map functions. The resulting aggregated `dict` is then passed as the `_input` parameter to the state update functions in that PSUB. For more information on how to modify the aggregation method, see [Policy Aggregation](/63k2ncjITuqOPCUHzK7Viw). +At each [Partial State Update Block](#Partial-State-Update-Blocks) (PSUB), the `dicts` returned by all policy functions +within that PSUB dictionaries are aggregated into a single `dict` using an initial reduction function +(a key-wise operation, default: `dic1['keyA'] + dic2['keyA']`) and optional subsequent map functions. The resulting +aggregated `dict` is then passed as the `_input` parameter to the state update functions in that PSUB. For more +information on how to modify the aggregation method, see [Policy Aggregation](/63k2ncjITuqOPCUHzK7Viw). ### Partial State Update Blocks -A **Partial State Update Block** (PSUB) is a set of State Update Functions and Policy Functions such that State Update Functions in the set are independent from each other and Policies in the set are independent from each other and from the State Update Functions in the set. In other words, if a state variable is updated in a PSUB, its new value cannnot impact the State Update Functions and Policy Functions in that PSUB - only those in the next PSUB. +A **Partial State Update Block** (PSUB) is a set of State Update Functions and Policy Functions such that State Update +Functions in the set are independent from each other and Policies in the set are independent from each other and from +the State Update Functions in the set. In other words, if a state variable is updated in a PSUB, its new value cannot +impact the State Update Functions and Policy Functions in that PSUB - only those in the next PSUB. ![](https://i.imgur.com/9rlX9TG.png) -Partial State Update Blocks are passed to `append_configs` as a List of Python `dicts` where the `dict_keys` are named `"policies"` and `"variables"` and the values are also Python `dicts` where the keys are the names of the policy and state update functions and the values are the functions. +Partial State Update Blocks are passed to `append_configs` as a List of Python `dicts` where the `dict_keys` are named +`"policies"` and `"variables"` and the values are also Python `dicts` where the keys are the names of the policy and +state update functions and the values are the functions. ```python PSUBs = [ @@ -191,19 +218,23 @@ append_configs( partial_state_update_blocks = PSUBs, ... ) - ``` #### Substep -At each timestep, cadCAD iterates over the `partial_state_update_blocks` list. For each Partial State Update Block, cadCAD returns a record containing the state of the system at the end of that PSUB. We refer to that subdivision of a timestep as a `substep`. +At each timestep, cadCAD iterates over the `partial_state_update_blocks` list. For each Partial State Update Block, +cadCAD returns a record containing the state of the system at the end of that PSUB. We refer to that subdivision of a +timestep as a `substep`. ## Result Dataset -cadCAD returns a dataset containing the evolution of the state variables defined by the user over time, with three `int` indexes: +cadCAD returns a dataset containing the evolution of the state variables defined by the user over time, with three `int` +indexes: * `run` - id of the [run](#N-Number-of-Runs) -* `timestep` - discrete unit of time (the total number of timesteps is defined by the user in the [T Simulation Parameter](#T-Simulation-Length)) -* `substep` - subdivision of timestep (the number of [substeps](#Substeps) is the same as the number of Partial State Update Blocks) +* `timestep` - discrete unit of time (the total number of timesteps is defined by the user in the +[T Simulation Parameter](#T-Simulation-Length)) +* `substep` - subdivision of timestep (the number of [substeps](#Substeps) is the same as the number of Partial State +Update Blocks) Therefore, the total number of records in the resulting dataset is `N` x `T` x `len(partial_state_update_blocks)` -#### [System Simulation Execution](link) +#### [System Simulation Execution](https://github.com/BlockScience/cadCAD-Tutorials/blob/master/documentation/Simulation_Execution.md) diff --git a/documentation/Execution.md b/documentation/Simulation_Execution.md similarity index 99% rename from documentation/Execution.md rename to documentation/Simulation_Execution.md index d8dc83b..786cb5f 100644 --- a/documentation/Execution.md +++ b/documentation/Simulation_Execution.md @@ -51,7 +51,7 @@ simulation_result = pd.DataFrame(raw_system_events) ``` ##### Example Result: System Events DataFrame -```python +``` +----+-------+------------+-----------+------+-----------+ | | run | timestep | substep | s1 | s2 | |----+-------+------------+-----------+------+-----------| diff --git a/documentation/System_Model_Parameter_Sweep.md b/documentation/System_Model_Parameter_Sweep.md index 63b7306..57df42a 100644 --- a/documentation/System_Model_Parameter_Sweep.md +++ b/documentation/System_Model_Parameter_Sweep.md @@ -68,6 +68,6 @@ sim_config = config_sim( } ) ``` - -#### [Example](link) - +#### Example +##### * [System Model Configuration](https://github.com/BlockScience/cadCAD-Tutorials/blob/master/Documentation/examples/param_sweep.py) +##### * Simulation Results: diff --git a/documentation/examples/policy_aggregation.py b/documentation/examples/policy_aggregation.py index 2807a74..38865ad 100644 --- a/documentation/examples/policy_aggregation.py +++ b/documentation/examples/policy_aggregation.py @@ -80,7 +80,7 @@ append_configs( sim_configs=sim_config, initial_state=genesis_states, partial_state_update_blocks=psubs, - policy_ops=[lambda a, b: a + b] # Default: lambda a, b: a + b , lambda y: y * 2 + policy_ops=[lambda a, b: a + b, lambda y: y * 2] # Default: lambda a, b: a + b ) exec_mode = ExecutionMode() diff --git a/documentation/examples/sys_model_A.py b/documentation/examples/sys_model_A.py index 3614291..5c54dbe 100644 --- a/documentation/examples/sys_model_A.py +++ b/documentation/examples/sys_model_A.py @@ -35,9 +35,6 @@ def s1m1(_g, step, sH, s, _input): y = 's1' x = s['s1'] + 1 return (y, x) - - - def s2m1(_g, step, sH, s, _input): y = 's2' x = _input['param2'] diff --git a/setup.py b/setup.py index 966cce7..1dfe6f9 100644 --- a/setup.py +++ b/setup.py @@ -11,7 +11,7 @@ long_description = "cadCAD is a differential games based simulation software pac monte carlo analysis and other common numerical methods is provided." setup(name='cadCAD', - version='0.2.4', + version='0.3.0', description="cadCAD: a differential games based simulation software package for research, validation, and \ Computer Aided Design of economic systems", long_description=long_description, diff --git a/testing/example.py b/testing/example.py deleted file mode 100644 index 09ee3aa..0000000 --- a/testing/example.py +++ /dev/null @@ -1,20 +0,0 @@ -import unittest - -class TestStringMethods(unittest.TestCase): - - def test_upper(self): - self.assertEqual('foo'.upper(), 'FOO') - - def test_isupper(self): - self.assertTrue('FOO'.isupper()) - self.assertFalse('Foo'.isupper()) - - def test_split(self): - s = 'hello world' - self.assertEqual(s.split(), ['hello', 'world']) - # check that s.split fails when the separator is not a string - with self.assertRaises(TypeError): - s.split(2) - -if __name__ == '__main__': - unittest.main() \ No newline at end of file diff --git a/testing/example2.py b/testing/example2.py deleted file mode 100644 index 081ec32..0000000 --- a/testing/example2.py +++ /dev/null @@ -1,71 +0,0 @@ -from functools import reduce - -import pandas as pd -import unittest -from parameterized import parameterized -from tabulate import tabulate - -from testing.system_models.policy_aggregation import run -from testing.generic_test import make_generic_test -from testing.utils import generate_assertions_df - -raw_result, tensor_field = run.execute() -result = pd.DataFrame(raw_result) - -expected_results = { - (1, 0, 0): {'policies': {}, 's1': 0}, - (1, 1, 1): {'policies': {'policy1': 2, 'policy2': 4}, 's1': 500}, - (1, 1, 2): {'policies': {'policy1': 8, 'policy2': 8}, 's1': 2}, - (1, 1, 3): {'policies': {'policy1': 4, 'policy2': 8, 'policy3': 12}, 's1': 3}, - (1, 2, 1): {'policies': {'policy1': 2, 'policy2': 4}, 's1': 4}, - (1, 2, 2): {'policies': {'policy1': 8, 'policy2': 8}, 's1': 5}, - (1, 2, 3): {'policies': {'policy1': 4, 'policy2': 8, 'policy3': 12}, 's1': 6}, - (1, 3, 1): {'policies': {'policy1': 2, 'policy2': 4}, 's1': 7}, - (1, 3, 2): {'policies': {'policy1': 8, 'policy2': 8}, 's1': 8}, - (1, 3, 3): {'policies': {'policy1': 4, 'policy2': 8, 'policy3': 12}, 's1': 9} -} - -params = [["policy_aggregation", result, expected_results, ['policies', 's1']]] - - -class TestSequence(unittest.TestCase): - @parameterized.expand(params) - def test_validate_results(self, name, result_df, expected_reults, target_cols): - # alt for (*) Exec Debug mode - tested_df = generate_assertions_df(result_df, expected_reults, target_cols) - - erroneous = tested_df[(tested_df['test'] == False)] - for index, row in erroneous.iterrows(): - expected = expected_reults[(row['run'], row['timestep'], row['substep'])] - unexpected = {k: expected[k] for k in expected if k in row and expected[k] != row[k]} - for key in unexpected.keys(): - erroneous[f"invalid_{key}"] = unexpected[key] - # etc. - - # def etc. - - print() - print(tabulate(erroneous, headers='keys', tablefmt='psql')) - - self.assertEqual(reduce(lambda a, b: a and b, tested_df['test']), True) - - s = 'hello world' - # self.assertEqual(s.split(), 1) - # # check that s.split fails when the separator is not a string - # with self.assertRaises(AssertionError): - # tested_df[(tested_df['test'] == False)] - # erroneous = tested_df[(tested_df['test'] == False)] - # for index, row in erroneous.iterrows(): - # expected = expected_reults[(row['run'], row['timestep'], row['substep'])] - # unexpected = {k: expected[k] for k in expected if k in row and expected[k] != row[k]} - # for key in unexpected.keys(): - # erroneous[f"invalid_{key}"] = unexpected[key] - # # etc. - # - # # def etc. - # - # print() - # print(tabulate(erroneous, headers='keys', tablefmt='psql')) - -if __name__ == '__main__': - unittest.main() \ No newline at end of file diff --git a/testing/generic_test.py b/testing/generic_test.py index 796770b..810eb47 100644 --- a/testing/generic_test.py +++ b/testing/generic_test.py @@ -1,21 +1,9 @@ import unittest from parameterized import parameterized from functools import reduce -from tabulate import tabulate - -# ToDo: Exec Debug mode (*) for which state and policy updates are validated during runtime using `expected_results` -# EXAMPLE: ('state_test' T/F, 'policy_test' T/F) -# ToDo: (Sys Model Config) give `expected_results to` `Configuration` for Exec Debug mode (*) -# ToDo: (expected_results) Function to generate sys metrics keys using system model config -# ToDo: (expected_results) Function to generate target_vals given user input (apply fancy validation lib later on) - - -# ToDo: Use self.assertRaises(AssertionError) def generate_assertions_df(df, expected_results, target_cols, evaluations): - # cols = ['run', 'timestep', 'substep'] + target_cols - # print(cols) test_names = [] for eval_f in evaluations: def wrapped_eval(a, b): @@ -54,10 +42,6 @@ def make_generic_test(params): erroneous.at[index, key] = unexpected[key] # etc. - # print() - # print(f"TEST: {test_name}") - # print(tabulate(erroneous, headers='keys', tablefmt='psql')) - # ToDo: Condition that will change false to true self.assertTrue(reduce(lambda a, b: a and b, tested_df[test_name])) diff --git a/testing/system_models/external_dataset.py b/testing/system_models/external_dataset.py index 0265288..3e0087b 100644 --- a/testing/system_models/external_dataset.py +++ b/testing/system_models/external_dataset.py @@ -3,7 +3,7 @@ from cadCAD.configuration.utils import config_sim import pandas as pd from cadCAD.utils import SilentDF -df = SilentDF(pd.read_csv('/Users/jjodesty/Projects/DiffyQ-SimCAD/simulations/external_data/output.csv')) +df = SilentDF(pd.read_csv('/DiffyQ-SimCAD/simulations/external_data/output.csv')) def query(s, df): @@ -21,8 +21,7 @@ def p2(_g, substep, sL, s): del result_dict["ds1"], result_dict["ds2"] return {k: list(v.values()).pop() for k, v in result_dict.items()} -# ToDo: SilentDF(df) wont work -#integrate_ext_dataset +# integrate_ext_dataset def integrate_ext_dataset(_g, step, sL, s, _input): result_dict = query(s, df).to_dict() return 'external_data', {k: list(v.values()).pop() for k, v in result_dict.items()} diff --git a/testing/system_models/historical_state_access.py b/testing/system_models/historical_state_access.py index 8f88e85..1f5db26 100644 --- a/testing/system_models/historical_state_access.py +++ b/testing/system_models/historical_state_access.py @@ -1,7 +1,5 @@ from cadCAD.configuration import append_configs from cadCAD.configuration.utils import config_sim, access_block -from cadCAD.engine import ExecutionMode, ExecutionContext, Executor -from cadCAD import configs policies, variables = {}, {} diff --git a/testing/system_models/param_sweep.py b/testing/system_models/param_sweep.py index fabb450..1f7f4ad 100644 --- a/testing/system_models/param_sweep.py +++ b/testing/system_models/param_sweep.py @@ -61,11 +61,6 @@ for m in psu_steps: psu_block[m]["variables"]['sweeped'] = var_timestep_trigger(y='sweeped', f=sweeped) -# 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 = { 'alpha': 0, @@ -75,11 +70,9 @@ genesis_states = { } # Environment Process -# ToDo: Validate - make env proc trigger field agnostic env_process['sweeped'] = env_timestep_trigger(trigger_field='timestep', trigger_vals=[5], funct_list=[lambda _g, x: _g['beta']]) -# config_sim Necessary sim_config = config_sim( { "N": 2, @@ -87,11 +80,6 @@ sim_config = config_sim( "M": g, # Optional } ) -# print() -# pp.pprint(g) -# print() -# pp.pprint(sim_config) - # New Convention partial_state_update_blocks = psub_list(psu_block, psu_steps) diff --git a/testing/system_models/policy_aggregation.py b/testing/system_models/policy_aggregation.py index e2be18b..4849ede 100644 --- a/testing/system_models/policy_aggregation.py +++ b/testing/system_models/policy_aggregation.py @@ -73,14 +73,11 @@ sim_config = config_sim( ) -# Aggregation == Reduce Map / Reduce Map Aggregation -# ToDo: subsequent functions should accept the entire datastructure -# using env functions (include in reg test using / for env proc) append_configs( sim_configs=sim_config, initial_state=genesis_states, partial_state_update_blocks=partial_state_update_block, - policy_ops=[lambda a, b: a + b, lambda y: y * 2] # Default: lambda a, b: a + b ToDO: reduction function requires high lvl explanation + policy_ops=[lambda a, b: a + b, lambda y: y * 2] # Default: lambda a, b: a + b ) diff --git a/testing/system_models/udo.py b/testing/system_models/udo.py deleted file mode 100644 index 1415908..0000000 --- a/testing/system_models/udo.py +++ /dev/null @@ -1,185 +0,0 @@ -import pandas as pd -from fn.func import curried -from datetime import timedelta -import pprint as pp - -from cadCAD.utils import SilentDF #, val_switch -from cadCAD.configuration import append_configs -from cadCAD.configuration.utils import time_step, config_sim, var_trigger, var_substep_trigger, env_trigger, psub_list -from cadCAD.configuration.utils.userDefinedObject import udoPipe, UDO - -from cadCAD.engine import ExecutionMode, ExecutionContext, Executor -from cadCAD import configs - - -DF = SilentDF(pd.read_csv('/Users/jjodesty/Projects/DiffyQ-SimCAD/simulations/external_data/output.csv')) - - -class udoExample(object): - def __init__(self, x, dataset=None): - self.x = x - self.mem_id = str(hex(id(self))) - self.ds = dataset # for setting ds initially or querying - self.perception = {} - - def anon(self, f): - return f(self) - - def updateX(self): - self.x += 1 - return self - - def perceive(self, s): - self.perception = self.ds[ - (self.ds['run'] == s['run']) & (self.ds['substep'] == s['substep']) & (self.ds['timestep'] == s['timestep']) - ].drop(columns=['run', 'substep']).to_dict() - return self - - def read(self, ds_uri): - self.ds = SilentDF(pd.read_csv(ds_uri)) - return self - - def write(self, ds_uri): - pd.to_csv(ds_uri) - - # ToDo: Generic update function - - pass - - -state_udo = UDO(udo=udoExample(0, DF), masked_members=['obj', 'perception']) -policy_udoA = UDO(udo=udoExample(0, DF), masked_members=['obj', 'perception']) -policy_udoB = UDO(udo=udoExample(0, DF), masked_members=['obj', 'perception']) - - -sim_config = config_sim({ - "N": 2, - "T": range(4) -}) - -# ToDo: DataFrame Column order -state_dict = { - 'increment': 0, - 'state_udo': state_udo, 'state_udo_tracker': 0, - 'state_udo_perception_tracker': {"ds1": None, "ds2": None, "ds3": None, "timestep": None}, - 'udo_policies': {'udo_A': policy_udoA, 'udo_B': policy_udoB}, - 'udo_policy_tracker': (0, 0), - 'timestamp': '2019-01-01 00:00:00' -} - -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 -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 -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 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): - self.perception = self.ds[ - (self.ds['run'] == s['run']) & (self.ds['substep'] == s['substep']) & (self.ds['timestep'] == s['timestep']) - ].drop(columns=['run', 'substep']).to_dict() - return self - - -def state_udo_update(_g, step, sL, s, _input): - y = 'state_udo' - # s['hydra_state'].updateX().anon(perceive(s)) - s['state_udo'].updateX().perceive(s) - x = udoPipe(s['state_udo']) - return y, x -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_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 id(past_perception): - if len(past_perception) == 0: - return state_dict['state_udo_perception_tracker'] - else: - return past_perception - return lambda _g, step, sL, s, _input: (destination, id(s[source].perception)) -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 -for m in psu_steps: - psu_block[m]["variables"]['udo_policies'] = view_udo_policy - - -def track_udo_policy(destination, source): - def val_switch(v): - if isinstance(v, pd.DataFrame) is True or isinstance(v, SilentDF) is True: - return SilentDF(v) - else: - return v.x - return lambda _g, step, sL, s, _input: (destination, tuple(val_switch(v) for _, v in s[source].items())) -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 - -# 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, - partial_state_update_blocks=partial_state_update_blocks -) - -print() -print("State Updates:") -pp.pprint(partial_state_update_blocks) -print() - - -exec_mode = ExecutionMode() -first_config = configs # only contains config1 -single_proc_ctx = ExecutionContext(context=exec_mode.single_proc) -run = Executor(exec_context=single_proc_ctx, configs=first_config) diff --git a/testing/tests/external_test.py b/testing/tests/external_dataset.py similarity index 83% rename from testing/tests/external_test.py rename to testing/tests/external_dataset.py index 1d86a3e..563d577 100644 --- a/testing/tests/external_test.py +++ b/testing/tests/external_dataset.py @@ -1,34 +1,22 @@ import unittest -from pprint import pprint 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.regression_tests import external_dataset from cadCAD import configs from testing.generic_test import make_generic_test -from testing.utils import gen_metric_dict exec_mode = ExecutionMode() print("Simulation Execution: Single Configuration") print() -first_config = configs # only contains config1 +first_config = configs single_proc_ctx = ExecutionContext(context=exec_mode.single_proc) run = Executor(exec_context=single_proc_ctx, configs=first_config) raw_result, tensor_field = run.execute() result = pd.DataFrame(raw_result) -# print(tabulate(result, headers='keys', tablefmt='psql')) - -# cols = ['run', 'substep', 'timestep', 'increment', 'external_data', 'policies'] -# result = result[cols] -# -# metrics = gen_metric_dict(result, ['increment', 'external_data', 'policies']) -# # -# pprint(metrics) def get_expected_results(run): return { @@ -109,6 +97,8 @@ expected_results.update(expected_results_2) def row(a, b): return a == b + + params = [["external_dataset", result, expected_results, ['increment', 'external_data', 'policies'], [row]]] @@ -118,10 +108,3 @@ class GenericTest(make_generic_test(params)): if __name__ == '__main__': unittest.main() - -# print() -# print("Tensor Field: config1") -# print(tabulate(tensor_field, headers='keys', tablefmt='psql')) -# print("Output:") -# print(tabulate(result, headers='keys', tablefmt='psql')) -# print() diff --git a/testing/tests/historical_state_access.py b/testing/tests/historical_state_access.py index ffc2d95..13ae394 100644 --- a/testing/tests/historical_state_access.py +++ b/testing/tests/historical_state_access.py @@ -1,7 +1,6 @@ import unittest import pandas as pd - from cadCAD.engine import ExecutionMode, ExecutionContext, Executor from testing.generic_test import make_generic_test from testing.system_models import historical_state_access @@ -14,7 +13,6 @@ run = Executor(exec_context=single_proc_ctx, configs=configs) raw_result, tensor_field = run.execute() result = pd.DataFrame(raw_result) -# ToDo: Discrepance not reported fot collection values. Needs custom test for collection values expected_results = { (1, 0, 0): {'x': 0, 'nonexsistant': [], 'last_x': [], '2nd_to_last_x': [], '3rd_to_last_x': [], '4th_to_last_x': []}, (1, 1, 1): {'x': 1, diff --git a/testing/tests/multi_config_test.py b/testing/tests/multi_config_test.py deleted file mode 100644 index c668773..0000000 --- a/testing/tests/multi_config_test.py +++ /dev/null @@ -1,56 +0,0 @@ -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.regression_tests import config1, config2 -from cadCAD import configs -from testing.utils import gen_metric_dict - -exec_mode = ExecutionMode() - -print("Simulation Execution: Concurrent Execution") -multi_proc_ctx = ExecutionContext(context=exec_mode.multi_proc) -run = Executor(exec_context=multi_proc_ctx, configs=configs) - - -def get_expected_results_1(run): - return { - (run, 0, 0): {'s1': 0, 's2': 0.0, 's3': 5}, - (run, 1, 1): {'s1': 1, 's2': 4, 's3': 5}, - (run, 1, 2): {'s1': 2, 's2': 6, 's3': 5}, - (run, 1, 3): {'s1': 3, 's2': [30, 300], 's3': 5}, - (run, 2, 1): {'s1': 4, 's2': 4, 's3': 5}, - (run, 2, 2): {'s1': 5, 's2': 6, 's3': 5}, - (run, 2, 3): {'s1': 6, 's2': [30, 300], 's3': 5}, - (run, 3, 1): {'s1': 7, 's2': 4, 's3': 5}, - (run, 3, 2): {'s1': 8, 's2': 6, 's3': 5}, - (run, 3, 3): {'s1': 9, 's2': [30, 300], 's3': 5}, - (run, 4, 1): {'s1': 10, 's2': 4, 's3': 5}, - (run, 4, 2): {'s1': 11, 's2': 6, 's3': 5}, - (run, 4, 3): {'s1': 12, 's2': [30, 300], 's3': 5}, - (run, 5, 1): {'s1': 13, 's2': 4, 's3': 5}, - (run, 5, 2): {'s1': 14, 's2': 6, 's3': 5}, - (run, 5, 3): {'s1': 15, 's2': [30, 300], 's3': 5}, - } - -expected_results_1 = {} -expected_results_A = get_expected_results_1(1) -expected_results_B = get_expected_results_1(2) -expected_results_1.update(expected_results_A) -expected_results_1.update(expected_results_B) - -expected_results_2 = {} - -# print(configs) -i = 0 -config_names = ['config1', 'config2'] -for raw_result, tensor_field in run.execute(): - result = pd.DataFrame(raw_result) - print() - print(f"Tensor Field: {config_names[i]}") - print(tabulate(tensor_field, headers='keys', tablefmt='psql')) - print("Output:") - print(tabulate(result, headers='keys', tablefmt='psql')) - print() - print(gen_metric_dict) - i += 1 diff --git a/testing/tests/param_sweep.py b/testing/tests/param_sweep.py index a87dab3..4fca5e1 100644 --- a/testing/tests/param_sweep.py +++ b/testing/tests/param_sweep.py @@ -71,15 +71,3 @@ class GenericTest(make_generic_test(params)): if __name__ == '__main__': unittest.main() - -# i = 0 -# # config_names = ['sweep_config_A', 'sweep_config_B'] -# for raw_result, tensor_field in run.execute(): -# result = pd.DataFrame(raw_result) -# print() -# # print("Tensor Field: " + config_names[i]) -# print(tabulate(tensor_field, headers='keys', tablefmt='psql')) -# print("Output:") -# print(tabulate(result, headers='keys', tablefmt='psql')) -# print() -# i += 1 \ No newline at end of file diff --git a/testing/tests/policy_aggregation.py b/testing/tests/policy_aggregation.py index 657b6e6..a864f93 100644 --- a/testing/tests/policy_aggregation.py +++ b/testing/tests/policy_aggregation.py @@ -26,14 +26,18 @@ expected_results = { (1, 3, 3): {'policies': {'policy1': 4, 'policy2': 8, 'policy3': 12}, 's1': 9} } + def row(a, b): return a == b + + params = [["policy_aggregation", result, expected_results, ['policies', 's1'], [row]]] class GenericTest(make_generic_test(params)): pass + if __name__ == '__main__': unittest.main() diff --git a/testing/tests/udo.py b/testing/tests/udo.py deleted file mode 100644 index ea4b42a..0000000 --- a/testing/tests/udo.py +++ /dev/null @@ -1,39 +0,0 @@ -import unittest -import ctypes -from copy import deepcopy -from pprint import pprint - -import pandas as pd -from tabulate import tabulate - -from testing.generic_test import make_generic_test -from testing.system_models.udo import run -from testing.utils import generate_assertions_df, gen_metric_dict - -raw_result, tensor_field = run.execute() -result = pd.DataFrame(raw_result) - -cols = ['increment', 'state_udo', 'state_udo_perception_tracker', - 'state_udo_tracker', 'timestamp', 'udo_policies', 'udo_policy_tracker'] - - -# print(list(result.columns) -# ctypes.cast(id(a), ctypes.py_object).value -# pprint(gen_metric_dict(result, cols)) -d = gen_metric_dict(result, cols) -pprint(d) - -# for k1, v1 in d: -# print(v1) -# d_copy = deepcopy(d) -# for k, v in d_copy.items(): -# # print(d[k]['state_udo']) # = -# print(ctypes.cast(id(v['state_udo']['mem_id']), ctypes.py_object).value) - - -# pprint(d_copy) - -# df = generate_assertions_df(result, d, cols) -# -# print(tabulate(df, headers='keys', tablefmt='psql')) -# \ No newline at end of file From 7b428ddb8138937bef8a651b169043965e4722e4 Mon Sep 17 00:00:00 2001 From: Markus Buhatem Koch <34865315+markusbkoch@users.noreply.github.com> Date: Thu, 22 Aug 2019 15:06:17 -0300 Subject: [PATCH 10/21] relative link --- documentation/Policy_Aggregation.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/documentation/Policy_Aggregation.md b/documentation/Policy_Aggregation.md index b80db6b..f9b24bf 100644 --- a/documentation/Policy_Aggregation.md +++ b/documentation/Policy_Aggregation.md @@ -57,7 +57,7 @@ append_configs( ``` #### Example -##### * [System Model Configuration](https://github.com/BlockScience/cadCAD-Tutorials/blob/master/Documentation/examples/policy_aggregation.py) +##### * [System Model Configuration](examples/policy_aggregation.py) ##### * Simulation Results: ``` +----+---------------------------------------------+-------+------+-----------+------------+ From 2a37eb5c02533c1d9d81cac14711c49ab47d3516 Mon Sep 17 00:00:00 2001 From: "Joshua E. Jodesty" Date: Thu, 22 Aug 2019 14:26:03 -0400 Subject: [PATCH 11/21] fixing likns --- README.md | 75 ++++++++++--------- documentation/Historically_State_Access.md | 6 +- documentation/Policy_Aggregation.md | 2 +- documentation/Simulation_Configuration.md | 7 +- documentation/Simulation_Execution.md | 24 +++--- documentation/System_Model_Parameter_Sweep.md | 3 +- 6 files changed, 60 insertions(+), 57 deletions(-) diff --git a/README.md b/README.md index da92cd3..c539ded 100644 --- a/README.md +++ b/README.md @@ -39,14 +39,21 @@ iteratively refine our work until we have constructed a model that closely refle and see how it evolves. We can then use these results to inform business decisions. #### Documentation: -* ##### [System Model Configuration](link) -* ##### [System Simulation Execution](link) -* ##### [Tutorials](link) +* ##### [Tutorials](tutorials) +* ##### [System Model Configuration](documentation/Simulation_Configuration.md) +* ##### [System Simulation Execution](documentation/Simulation_Execution.md) #### 0. Installation: -**Option A:** Proprietary Build Access +**Option A:** Build From Source +```bash +pip3 install -r requirements.txt +python3 setup.py sdist bdist_wheel +pip3 install dist/*.whl +``` + +**Option B:** Proprietary Build Access ***IMPORTANT NOTE:*** Tokens are issued to those with access to proprietary builds of cadCAD and BlockScience employees **ONLY**. Replace \ with an issued token in the script below. @@ -55,25 +62,24 @@ pip3 install pandas pathos fn funcy tabulate pip3 install cadCAD --extra-index-url https://@repo.fury.io/blockscience/ ``` -**Option B:** Build From Source -```bash -pip3 install -r requirements.txt -python3 setup.py sdist bdist_wheel -pip3 install dist/*.whl -``` +#### 1. [Configure System Model](documentation/Simulation_Configuration.md) -#### 1. [Configure System Model](link) - -#### 2. [Execute Simulations:](link) +#### 2. [Execute Simulations:](documentation/Simulation_Execution.md) ##### Single Process Execution: -Example [System Model Configurations](link): -* [System Model A](link): `/documentation/examples/sys_model_A.py` -* [System Model B](link): `/documentation/examples/sys_model_B.py` +Example System Model Configurations: +* [System Model A](documentation/examples/sys_model_A.py): +`/documentation/examples/sys_model_A.py` +* [System Model B](documentation/examples/sys_model_B.py): +`/documentation/examples/sys_model_B.py` + Example Simulation Executions: -* [System Model A](link): `/documentation/examples/sys_model_A_exec.py` -* [System Model B](link): `/documentation/examples/sys_model_B_exec.py` +* [System Model A](documentation/examples/sys_model_A_exec.py): +`/documentation/examples/sys_model_A_exec.py` +* [System Model B](documentation/examples/sys_model_B_exec.py): +`/documentation/examples/sys_model_B_exec.py` + ```python import pandas as pd from tabulate import tabulate @@ -99,13 +105,17 @@ print(tabulate(sys_model_A_result, headers='keys', tablefmt='psql')) print() ``` -### Multiple Simulations (Concurrent): -##### Multiple Simulation Execution (Multi Process Execution) -Documentation: [Simulation Execution](link) -Example [System Model Configurations](link): -* [System Model A](link): `/documentation/examples/sys_model_A.py` -* [System Model B](link): `/documentation/examples/sys_model_B.py` -[Example Simulation Executions::](link) `/documentation/examples/sys_model_AB_exec.py` +##### Multiple Simulations (Concurrent): +###### Multiple Simulation Execution (Multi Process Execution) +System Model Configurations: +* [System Model A](documentation/examples/sys_model_A.py): +`/documentation/examples/sys_model_A.py` +* [System Model B](documentation/examples/sys_model_B.py): +`/documentation/examples/sys_model_B.py` + +[Example Simulation Executions:](documentation/examples/sys_model_AB_exec.py) +`/documentation/examples/sys_model_AB_exec.py` + ```python import pandas as pd from tabulate import tabulate @@ -133,9 +143,10 @@ for sys_model_AB_raw_result, sys_model_AB_tensor_field in sys_model_AB_simulatio i += 1 ``` -### Parameter Sweep Simulation (Concurrent): -Documentation: [System Model Parameter Sweep](link) -[Example:](link) `/documentation/examples/param_sweep.py` +##### Parameter Sweep Simulation (Concurrent): +[Example:](documentation/examples/param_sweep.py) +`/documentation/examples/param_sweep.py` + ```python import pandas as pd from tabulate import tabulate @@ -157,11 +168,3 @@ for raw_result, tensor_field in run.execute(): print(tabulate(result, headers='keys', tablefmt='psql')) print() ``` - -### Tests: -```python -python -m unittest testing/tests/param_sweep.py -python -m unittest testing/tests/policy_aggregation.py -python -m unittest testing/tests/historical_state_access.py -python -m unittest testing/tests/external_dataset.py -``` diff --git a/documentation/Historically_State_Access.md b/documentation/Historically_State_Access.md index 7d684bf..e5961f7 100644 --- a/documentation/Historically_State_Access.md +++ b/documentation/Historically_State_Access.md @@ -50,10 +50,10 @@ def nonexistent(_params, substep, sH, s, _input): return 'nonexistent', access_block(sH, "nonexistent", 0, exclusion_list) ``` -#### Example Simulation -link +#### [Example Simulation:](examples/historical_state_access.py) -#### Example Output + +#### Example Output: ###### State History ``` +----+-------+-----------+------------+-----+ diff --git a/documentation/Policy_Aggregation.md b/documentation/Policy_Aggregation.md index b80db6b..f9b24bf 100644 --- a/documentation/Policy_Aggregation.md +++ b/documentation/Policy_Aggregation.md @@ -57,7 +57,7 @@ append_configs( ``` #### Example -##### * [System Model Configuration](https://github.com/BlockScience/cadCAD-Tutorials/blob/master/Documentation/examples/policy_aggregation.py) +##### * [System Model Configuration](examples/policy_aggregation.py) ##### * Simulation Results: ``` +----+---------------------------------------------+-------+------+-----------+------------+ diff --git a/documentation/Simulation_Configuration.md b/documentation/Simulation_Configuration.md index 0656244..9ceb57c 100644 --- a/documentation/Simulation_Configuration.md +++ b/documentation/Simulation_Configuration.md @@ -70,7 +70,7 @@ in the simulation. In other words, for how long do they want to simulate the sys cadCAD facilitates running multiple simulations of the same system sequentially, reporting the results of all those runs in a single dataset. This is especially helpful for running -[Monte Carlo Simulations](https://github.com/BlockScience/cadCAD-Tutorials/blob/master/01%20Tutorials/robot-marbles-part-4/robot-marbles-part-4.ipynb). +[Monte Carlo Simulations](../tutorials/robot-marbles-part-4/robot-marbles-part-4.ipynb). ### M - Parameters of the System @@ -137,7 +137,7 @@ cadCAD relies on in order to run the simulation according to the specifications. ### Policy Functions A Policy Function computes one or more signals to be passed to [State Update Functions](#State-Update-Functions) (via the _\_input_ parameter). Read -[this article](https://github.com/BlockScience/cadCAD-Tutorials/blob/master/01%20Tutorials/robot-marbles-part-2/robot-marbles-part-2.ipynb) +[this article](../tutorials/robot-marbles-part-2/robot-marbles-part-2.ipynb) for details on why and when to use policy functions.