├── .gitignore ├── 00-Reference-Mechanisms ├── 01-augmented-bonding-curve │ ├── hatch_sim.ipynb │ └── slippage.jpeg └── README.md ├── 01 Tutorials ├── README.md ├── robot-marbles-part-1 │ ├── partial-state-update-blocks.png │ └── robot-marbles-part-1.ipynb ├── robot-marbles-part-2 │ ├── policies.png │ ├── policy.png │ └── robot-marbles-part-2.ipynb ├── robot-marbles-part-3 │ └── robot-marbles-part-3.ipynb ├── robot-marbles-part-4 │ └── robot-marbles-part-4.ipynb ├── robot-marbles-part-5 │ └── robot-marbles-part-5.ipynb └── videos │ ├── README.md │ ├── robot-marbles-part-1 │ ├── README.md │ ├── cadCAD Template Robot and the Marbles.ipynb │ ├── config.py │ ├── config2.py │ └── images │ │ ├── Mech.jpeg │ │ ├── Overview.jpeg │ │ └── equations.png │ ├── robot-marbles-part-2 │ ├── README.md │ ├── cadCAD Template Robot and the Marbles - part 2.ipynb │ ├── config.py │ ├── config2.py │ ├── configBlank.py │ └── images │ │ ├── Mech.jpeg │ │ ├── Mech2.jpeg │ │ └── Overview.jpeg │ ├── robot-marbles-part-3 │ ├── README.md │ ├── cadCAD Template Robot and the Marbles - part 3.ipynb │ ├── config.py │ └── images │ │ ├── Mech1.jpeg │ │ └── Overview.jpeg │ ├── robot-marbles-part-4 │ ├── README.md │ ├── cadCAD Template Robot and the Marbles - part 4.ipynb │ ├── config.py │ ├── config2.py │ └── images │ │ ├── Mech1.jpeg │ │ └── Overview.jpeg │ └── robot-marbles-part-5 │ ├── README.md │ ├── cadCAD Template Robot and the Marbles - part 5.ipynb │ └── images │ ├── Mech1.png │ └── Overview.png ├── 02 Reference Models ├── ThreeSided │ ├── 3SM-mechsteps.jpeg │ ├── Three Sided Market Model.ipynb │ ├── ThreeSidedMarket.ipynb │ ├── model │ │ ├── config.py │ │ ├── partial_state_update_block.py │ │ ├── parts │ │ │ ├── consumers.py │ │ │ ├── exogenous.py │ │ │ ├── governance.py │ │ │ ├── investors.py │ │ │ ├── producers.py │ │ │ ├── providers.py │ │ │ ├── sys_params.py │ │ │ ├── system.py │ │ │ └── utils.py │ │ ├── run.py │ │ └── state_variables.py │ └── threesidedmarket.jpeg ├── ThreeSidedBasic │ ├── Basic Three Sided Market Model.ipynb │ ├── Basic Three-Sided Market Model.pdf │ ├── depreciated │ │ ├── 3 sided model.ipynb │ │ ├── Latex │ │ │ ├── Basic Three-Sided Market Model.pdf │ │ │ ├── images │ │ │ │ ├── 3SidedMarketBasicDemo.png │ │ │ │ ├── Results-eps-converted-to.pdf │ │ │ │ ├── Results.eps │ │ │ │ ├── components-eps-converted-to.pdf │ │ │ │ ├── components.eps │ │ │ │ └── productCost.png │ │ │ ├── main.aux │ │ │ ├── main.log │ │ │ ├── main.synctex.gz │ │ │ └── main.tex │ │ └── cadCadFunctions.py │ ├── images │ │ ├── 3SidedMarketBasicDemo.png │ │ ├── Results.eps │ │ ├── components.eps │ │ └── productCost.png │ └── model │ │ ├── config.py │ │ ├── partial_state_update_block.py │ │ ├── parts │ │ ├── exogenous.py │ │ ├── flows.py │ │ ├── investors.py │ │ ├── kpis.py │ │ ├── sys_params.py │ │ └── utils.py │ │ ├── run.py │ │ └── state_variables.py ├── Verifiers-Dilemma │ ├── Dilemma.jpeg │ ├── feedback.jpeg │ └── verifiers_dilemma.ipynb ├── Viral-Marketing-SIR │ ├── SIR.jpeg │ ├── SIR0.jpeg │ ├── cadcad-susceptible_infected_recovered.ipynb │ └── susceptible_infected_recovered.ipynb └── sourcecred │ ├── dynamicCred.ipynb │ ├── graph_generators.py │ ├── import_graph.py │ ├── inspect_subgraph.py │ ├── pageRankerChecker.ipynb │ ├── page_ranker.py │ └── robots_scratchwork.ipynb ├── 03 Methodology ├── EmergentV.jpg ├── System Simulation Architecture - U-E-O.pdf └── workflow.jpeg ├── LICENSE ├── README.md ├── documentation ├── Historically_State_Access.md ├── Policy_Aggregation.md ├── Simulation_Configuration.md ├── Simulation_Execution.md ├── System_Model_Parameter_Sweep.md └── examples │ ├── __init__.py │ ├── example_1.py │ ├── historical_state_access.py │ ├── param_sweep.py │ ├── policy_aggregation.py │ ├── sys_model_A.py │ ├── sys_model_AB_exec.py │ ├── sys_model_A_exec.py │ ├── sys_model_B.py │ └── sys_model_B_exec.py └── requirements.txt /.gitignore: -------------------------------------------------------------------------------- 1 | .ipynb_checkpoints 2 | .DS_Store 3 | .idea 4 | notebooks/.ipynb_checkpoints 5 | notebooks/multithreading.ipynb 6 | tutorials/results 7 | SimCAD.egg-info 8 | __pycache__ 9 | Pipfile 10 | Pipfile.lock 11 | results 12 | .mypy_cache -------------------------------------------------------------------------------- /00-Reference-Mechanisms/01-augmented-bonding-curve/slippage.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlockScience/cadCAD-Tutorials/5ac9e99bfb66299316de4c9929fcc77fd16a23f9/00-Reference-Mechanisms/01-augmented-bonding-curve/slippage.jpeg -------------------------------------------------------------------------------- /00-Reference-Mechanisms/README.md: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /01 Tutorials/README.md: -------------------------------------------------------------------------------- 1 | cadCAD is now open source! The tutorials have been moved to the [main repo](https://github.com/BlockScience/cadCAD) -------------------------------------------------------------------------------- /01 Tutorials/robot-marbles-part-1/partial-state-update-blocks.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlockScience/cadCAD-Tutorials/5ac9e99bfb66299316de4c9929fcc77fd16a23f9/01 Tutorials/robot-marbles-part-1/partial-state-update-blocks.png -------------------------------------------------------------------------------- /01 Tutorials/robot-marbles-part-1/robot-marbles-part-1.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "cadCAD is now open source! The tutorials have been moved to the [main repo](https://github.com/BlockScience/cadCAD)" 8 | ] 9 | } 10 | ], 11 | "metadata": { 12 | "kernelspec": { 13 | "display_name": "Python 3", 14 | "language": "python", 15 | "name": "python3" 16 | }, 17 | "language_info": { 18 | "codemirror_mode": { 19 | "name": "ipython", 20 | "version": 3 21 | }, 22 | "file_extension": ".py", 23 | "mimetype": "text/x-python", 24 | "name": "python", 25 | "nbconvert_exporter": "python", 26 | "pygments_lexer": "ipython3", 27 | "version": "3.6.5" 28 | } 29 | }, 30 | "nbformat": 4, 31 | "nbformat_minor": 2 32 | } 33 | -------------------------------------------------------------------------------- /01 Tutorials/robot-marbles-part-2/policies.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlockScience/cadCAD-Tutorials/5ac9e99bfb66299316de4c9929fcc77fd16a23f9/01 Tutorials/robot-marbles-part-2/policies.png -------------------------------------------------------------------------------- /01 Tutorials/robot-marbles-part-2/policy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlockScience/cadCAD-Tutorials/5ac9e99bfb66299316de4c9929fcc77fd16a23f9/01 Tutorials/robot-marbles-part-2/policy.png -------------------------------------------------------------------------------- /01 Tutorials/robot-marbles-part-2/robot-marbles-part-2.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "cadCAD is now open source! The tutorials have been moved to the [main repo](https://github.com/BlockScience/cadCAD)" 8 | ] 9 | } 10 | ], 11 | "metadata": { 12 | "kernelspec": { 13 | "display_name": "Python 3", 14 | "language": "python", 15 | "name": "python3" 16 | }, 17 | "language_info": { 18 | "codemirror_mode": { 19 | "name": "ipython", 20 | "version": 3 21 | }, 22 | "file_extension": ".py", 23 | "mimetype": "text/x-python", 24 | "name": "python", 25 | "nbconvert_exporter": "python", 26 | "pygments_lexer": "ipython3", 27 | "version": "3.6.5" 28 | } 29 | }, 30 | "nbformat": 4, 31 | "nbformat_minor": 2 32 | } 33 | -------------------------------------------------------------------------------- /01 Tutorials/robot-marbles-part-3/robot-marbles-part-3.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "cadCAD is now open source! The tutorials have been moved to the [main repo](https://github.com/BlockScience/cadCAD)" 8 | ] 9 | } 10 | ], 11 | "metadata": { 12 | "kernelspec": { 13 | "display_name": "Python 3", 14 | "language": "python", 15 | "name": "python3" 16 | }, 17 | "language_info": { 18 | "codemirror_mode": { 19 | "name": "ipython", 20 | "version": 3 21 | }, 22 | "file_extension": ".py", 23 | "mimetype": "text/x-python", 24 | "name": "python", 25 | "nbconvert_exporter": "python", 26 | "pygments_lexer": "ipython3", 27 | "version": "3.6.5" 28 | } 29 | }, 30 | "nbformat": 4, 31 | "nbformat_minor": 2 32 | } 33 | -------------------------------------------------------------------------------- /01 Tutorials/robot-marbles-part-4/robot-marbles-part-4.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "cadCAD is now open source! The tutorials have been moved to the [main repo](https://github.com/BlockScience/cadCAD)" 8 | ] 9 | } 10 | ], 11 | "metadata": { 12 | "kernelspec": { 13 | "display_name": "Python 3", 14 | "language": "python", 15 | "name": "python3" 16 | }, 17 | "language_info": { 18 | "codemirror_mode": { 19 | "name": "ipython", 20 | "version": 3 21 | }, 22 | "file_extension": ".py", 23 | "mimetype": "text/x-python", 24 | "name": "python", 25 | "nbconvert_exporter": "python", 26 | "pygments_lexer": "ipython3", 27 | "version": "3.6.5" 28 | } 29 | }, 30 | "nbformat": 4, 31 | "nbformat_minor": 2 32 | } 33 | -------------------------------------------------------------------------------- /01 Tutorials/robot-marbles-part-5/robot-marbles-part-5.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "cadCAD is now open source! The tutorials have been moved to the [main repo](https://github.com/BlockScience/cadCAD)" 8 | ] 9 | } 10 | ], 11 | "metadata": { 12 | "kernelspec": { 13 | "display_name": "Python 3", 14 | "language": "python", 15 | "name": "python3" 16 | }, 17 | "language_info": { 18 | "codemirror_mode": { 19 | "name": "ipython", 20 | "version": 3 21 | }, 22 | "file_extension": ".py", 23 | "mimetype": "text/x-python", 24 | "name": "python", 25 | "nbconvert_exporter": "python", 26 | "pygments_lexer": "ipython3", 27 | "version": "3.6.5" 28 | } 29 | }, 30 | "nbformat": 4, 31 | "nbformat_minor": 2 32 | } 33 | -------------------------------------------------------------------------------- /01 Tutorials/videos/README.md: -------------------------------------------------------------------------------- 1 | cadCAD is now open source! The tutorials have been moved to the [main repo](https://github.com/BlockScience/cadCAD) -------------------------------------------------------------------------------- /01 Tutorials/videos/robot-marbles-part-1/README.md: -------------------------------------------------------------------------------- 1 | (https://youtu.be/uJEiYHRWA9g) 2 | -------------------------------------------------------------------------------- /01 Tutorials/videos/robot-marbles-part-1/config.py: -------------------------------------------------------------------------------- 1 | # import libraries 2 | from decimal import Decimal 3 | import numpy as np 4 | from datetime import timedelta 5 | from cadCAD.configuration import append_configs 6 | from cadCAD.configuration.utils import bound_norm_random, ep_time_step, config_sim 7 | 8 | seeds = { 9 | # 'z': np.random.RandomState(1), 10 | # 'a': np.random.RandomState(2) 11 | } 12 | 13 | sim_config = config_sim({ 14 | 'T': range(10), #number of discrete iterations in each experiement 15 | 'N': 1, #number of times the simulation will be run (Monte Carlo runs) 16 | #'M': g #parameter sweep dictionary 17 | }) 18 | 19 | 20 | # define the time deltas for the discrete increments in the model 21 | # ts_format = '%Y-%m-%d %H:%M:%S' 22 | # t_delta = timedelta(days=0, minutes=1, seconds=0) 23 | # def time_model(_g, step, sL, s, _input): 24 | # y = 'time' 25 | # x = ep_time_step(s, dt_str=s['time'], fromat_str=ts_format, _timedelta=t_delta) 26 | # return (y, x) 27 | 28 | # Behaviors 29 | 30 | # Mechanisms 31 | def update_A(_g, step, sL, s, _input): 32 | y = 'box_A' 33 | add_to_A = 0 34 | if (s['box_A'] > s['box_B']): 35 | add_to_A = -1 36 | elif (s['box_A'] < s['box_B']): 37 | add_to_A = 1 38 | x = s['box_A'] + add_to_A 39 | return (y, x) 40 | 41 | def update_B(_g, step, sL, s, _input): 42 | y = 'box_B' 43 | add_to_B = 0 44 | if (s['box_B'] > s['box_A']): 45 | add_to_B = -1 46 | elif (s['box_B'] < s['box_A']): 47 | add_to_B = 1 48 | x = s['box_B'] + add_to_B 49 | return (y, x) 50 | 51 | # Initial States 52 | genesis_states = { 53 | 'box_A': 10, # as per the description of the example, box_A starts out with 10 marbles in it 54 | 'box_B': 0 # as per the description of the example, box_B starts out empty 55 | } 56 | 57 | exogenous_states = { 58 | #'time': time_model 59 | } 60 | 61 | env_processes = { 62 | } 63 | 64 | #build mechanism dictionary to "wire up the circuit" 65 | mechanisms = [ 66 | { 67 | 'policies': { 68 | }, 69 | 'variables': { # The following state variables will be updated simultaneously 70 | 'box_A': update_A, 71 | 'box_B': update_B 72 | } 73 | } 74 | ] 75 | 76 | 77 | 78 | append_configs( 79 | sim_configs=sim_config, 80 | initial_state=genesis_states, 81 | seeds=seeds, 82 | raw_exogenous_states=exogenous_states, 83 | env_processes=env_processes, 84 | partial_state_update_blocks=mechanisms 85 | ) 86 | -------------------------------------------------------------------------------- /01 Tutorials/videos/robot-marbles-part-1/config2.py: -------------------------------------------------------------------------------- 1 | # import libraries 2 | from decimal import Decimal 3 | import numpy as np 4 | from datetime import timedelta 5 | from cadCAD.configuration import append_configs 6 | from cadCAD.configuration.utils import bound_norm_random, ep_time_step, config_sim 7 | 8 | seeds = { 9 | # 'z': np.random.RandomState(1), 10 | # 'a': np.random.RandomState(2) 11 | } 12 | 13 | sim_config = config_sim({ 14 | 'T': range(10), #number of discrete iterations in each experiement 15 | 'N': 1, #number of times the simulation will be run (Monte Carlo runs) 16 | #'M': g #parameter sweep dictionary 17 | }) 18 | 19 | 20 | # define the time deltas for the discrete increments in the model 21 | # ts_format = '%Y-%m-%d %H:%M:%S' 22 | # t_delta = timedelta(days=0, minutes=1, seconds=0) 23 | # def time_model(_g, step, sL, s, _input): 24 | # y = 'time' 25 | # x = ep_time_step(s, dt_str=s['time'], fromat_str=ts_format, _timedelta=t_delta) 26 | # return (y, x) 27 | 28 | # Behaviors 29 | 30 | # Mechanisms 31 | def update_A(_g, step, sL, s, _input): 32 | y = 'box_A' 33 | add_to_A = 0 34 | if (s['box_A'] > s['box_B']): 35 | add_to_A = -1 36 | elif (s['box_A'] < s['box_B']): 37 | add_to_A = 1 38 | x = s['box_A'] + add_to_A 39 | return (y, x) 40 | 41 | def update_B(_g, step, sL, s, _input): 42 | y = 'box_B' 43 | add_to_B = 0 44 | if (s['box_B'] > s['box_A']): 45 | add_to_B = -1 46 | elif (s['box_B'] < s['box_A']): 47 | add_to_B = 1 48 | x = s['box_B'] + add_to_B 49 | return (y, x) 50 | 51 | # Initial States 52 | genesis_states = { 53 | 'box_A': 11, # as per the description of the example, box_A starts out with 10 marbles in it 54 | 'box_B': 0 # as per the description of the example, box_B starts out empty 55 | } 56 | 57 | exogenous_states = { 58 | #'time': time_model 59 | } 60 | 61 | env_processes = { 62 | } 63 | 64 | #build mechanism dictionary to "wire up the circuit" 65 | mechanisms = [ 66 | { 67 | 'policies': { 68 | }, 69 | 'variables': { # The following state variables will be updated simultaneously 70 | 'box_A': update_A, 71 | 'box_B': update_B 72 | } 73 | } 74 | ] 75 | 76 | 77 | 78 | append_configs( 79 | sim_configs=sim_config, 80 | initial_state=genesis_states, 81 | seeds=seeds, 82 | raw_exogenous_states=exogenous_states, 83 | env_processes=env_processes, 84 | partial_state_update_blocks=mechanisms 85 | ) 86 | -------------------------------------------------------------------------------- /01 Tutorials/videos/robot-marbles-part-1/images/Mech.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlockScience/cadCAD-Tutorials/5ac9e99bfb66299316de4c9929fcc77fd16a23f9/01 Tutorials/videos/robot-marbles-part-1/images/Mech.jpeg -------------------------------------------------------------------------------- /01 Tutorials/videos/robot-marbles-part-1/images/Overview.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlockScience/cadCAD-Tutorials/5ac9e99bfb66299316de4c9929fcc77fd16a23f9/01 Tutorials/videos/robot-marbles-part-1/images/Overview.jpeg -------------------------------------------------------------------------------- /01 Tutorials/videos/robot-marbles-part-1/images/equations.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlockScience/cadCAD-Tutorials/5ac9e99bfb66299316de4c9929fcc77fd16a23f9/01 Tutorials/videos/robot-marbles-part-1/images/equations.png -------------------------------------------------------------------------------- /01 Tutorials/videos/robot-marbles-part-2/README.md: -------------------------------------------------------------------------------- 1 | (https://youtu.be/Y5MzhVRQyzY) 2 | -------------------------------------------------------------------------------- /01 Tutorials/videos/robot-marbles-part-2/cadCAD Template Robot and the Marbles - part 2.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# cadCAD Template: Robot and the Marbles - Part 2\n", 8 | "\n", 9 | "![](images/Overview.jpeg)\n", 10 | "![](images/Mech.jpeg)" 11 | ] 12 | }, 13 | { 14 | "cell_type": "code", 15 | "execution_count": 1, 16 | "metadata": {}, 17 | "outputs": [], 18 | "source": [ 19 | "# import libraries\n", 20 | "import pandas as pd\n", 21 | "import numpy as np\n", 22 | "import matplotlib \n", 23 | "from cadCAD.engine import ExecutionMode, ExecutionContext, Executor\n", 24 | "import configBlank\n", 25 | "from cadCAD import configs\n", 26 | "import matplotlib.pyplot as plt\n", 27 | "\n", 28 | "%matplotlib inline\n", 29 | "\n", 30 | "exec_mode = ExecutionMode()" 31 | ] 32 | }, 33 | { 34 | "cell_type": "code", 35 | "execution_count": 2, 36 | "metadata": {}, 37 | "outputs": [ 38 | { 39 | "name": "stdout", 40 | "output_type": "stream", 41 | "text": [ 42 | "single_proc: []\n", 43 | "[]\n" 44 | ] 45 | }, 46 | { 47 | "data": { 48 | "text/html": [ 49 | "
\n", 50 | "\n", 63 | "\n", 64 | " \n", 65 | " \n", 66 | " \n", 67 | " \n", 68 | " \n", 69 | " \n", 70 | " \n", 71 | " \n", 72 | " \n", 73 | " \n", 74 | " \n", 75 | " \n", 76 | " \n", 77 | " \n", 78 | " \n", 79 | " \n", 80 | " \n", 81 | " \n", 82 | " \n", 83 | " \n", 84 | " \n", 85 | " \n", 86 | " \n", 87 | " \n", 88 | " \n", 89 | " \n", 90 | " \n", 91 | " \n", 92 | " \n", 93 | " \n", 94 | " \n", 95 | " \n", 96 | " \n", 97 | " \n", 98 | " \n", 99 | " \n", 100 | " \n", 101 | " \n", 102 | " \n", 103 | " \n", 104 | " \n", 105 | " \n", 106 | " \n", 107 | " \n", 108 | " \n", 109 | " \n", 110 | " \n", 111 | " \n", 112 | " \n", 113 | " \n", 114 | " \n", 115 | " \n", 116 | " \n", 117 | " \n", 118 | " \n", 119 | " \n", 120 | " \n", 121 | " \n", 122 | " \n", 123 | " \n", 124 | " \n", 125 | " \n", 126 | " \n", 127 | " \n", 128 | " \n", 129 | " \n", 130 | " \n", 131 | " \n", 132 | " \n", 133 | " \n", 134 | " \n", 135 | " \n", 136 | " \n", 137 | " \n", 138 | " \n", 139 | " \n", 140 | " \n", 141 | " \n", 142 | " \n", 143 | " \n", 144 | " \n", 145 | " \n", 146 | " \n", 147 | " \n", 148 | " \n", 149 | "
box_Abox_B
runtimestepsubstep
100100
1191
2182
3173
4164
5155
6155
7155
8155
9155
10155
\n", 150 | "
" 151 | ], 152 | "text/plain": [ 153 | " box_A box_B\n", 154 | "run timestep substep \n", 155 | "1 0 0 10 0\n", 156 | " 1 1 9 1\n", 157 | " 2 1 8 2\n", 158 | " 3 1 7 3\n", 159 | " 4 1 6 4\n", 160 | " 5 1 5 5\n", 161 | " 6 1 5 5\n", 162 | " 7 1 5 5\n", 163 | " 8 1 5 5\n", 164 | " 9 1 5 5\n", 165 | " 10 1 5 5" 166 | ] 167 | }, 168 | "execution_count": 2, 169 | "metadata": {}, 170 | "output_type": "execute_result" 171 | } 172 | ], 173 | "source": [ 174 | "# Run Cad^2\n", 175 | "\n", 176 | "first_config = configs # only contains config1\n", 177 | "single_proc_ctx = ExecutionContext(context=exec_mode.single_proc)\n", 178 | "run = Executor(exec_context=single_proc_ctx, configs=first_config)\n", 179 | "\n", 180 | "raw_result, tensor_field = run.execute()\n", 181 | "df = pd.DataFrame(raw_result)\n", 182 | "df.set_index(['run', 'timestep', 'substep'])" 183 | ] 184 | }, 185 | { 186 | "cell_type": "code", 187 | "execution_count": 3, 188 | "metadata": {}, 189 | "outputs": [ 190 | { 191 | "data": { 192 | "image/png": "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\n", 193 | "text/plain": [ 194 | "
" 195 | ] 196 | }, 197 | "metadata": { 198 | "needs_background": "light" 199 | }, 200 | "output_type": "display_data" 201 | } 202 | ], 203 | "source": [ 204 | "df.plot('timestep', ['box_A', 'box_B'], grid=True, \n", 205 | " colormap = 'RdYlGn',\n", 206 | " xticks=list(df['timestep'].drop_duplicates()), \n", 207 | " yticks=list(range(1+(df['box_A']+df['box_B']).max())));" 208 | ] 209 | }, 210 | { 211 | "cell_type": "markdown", 212 | "metadata": {}, 213 | "source": [ 214 | "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." 215 | ] 216 | } 217 | ], 218 | "metadata": { 219 | "kernelspec": { 220 | "display_name": "Python 3", 221 | "language": "python", 222 | "name": "python3" 223 | }, 224 | "language_info": { 225 | "codemirror_mode": { 226 | "name": "ipython", 227 | "version": 3 228 | }, 229 | "file_extension": ".py", 230 | "mimetype": "text/x-python", 231 | "name": "python", 232 | "nbconvert_exporter": "python", 233 | "pygments_lexer": "ipython3", 234 | "version": "3.7.0" 235 | } 236 | }, 237 | "nbformat": 4, 238 | "nbformat_minor": 2 239 | } 240 | -------------------------------------------------------------------------------- /01 Tutorials/videos/robot-marbles-part-2/config.py: -------------------------------------------------------------------------------- 1 | # import libraries 2 | from decimal import Decimal 3 | import numpy as np 4 | from datetime import timedelta 5 | from cadCAD.configuration import append_configs 6 | from cadCAD.configuration.utils import bound_norm_random, ep_time_step, config_sim 7 | 8 | seeds = { 9 | # 'z': np.random.RandomState(1), 10 | # 'a': np.random.RandomState(2) 11 | } 12 | 13 | sim_config = config_sim({ 14 | 'T': range(10), #number of discrete iterations in each experiement 15 | 'N': 1, #number of times the simulation will be run (Monte Carlo runs) 16 | #'M': g #parameter sweep dictionary 17 | }) 18 | 19 | 20 | # define the time deltas for the discrete increments in the model 21 | # ts_format = '%Y-%m-%d %H:%M:%S' 22 | # t_delta = timedelta(days=0, minutes=1, seconds=0) 23 | # def time_model(_g, step, sL, s, _input): 24 | # y = 'time' 25 | # x = ep_time_step(s, dt_str=s['time'], fromat_str=ts_format, _timedelta=t_delta) 26 | # return (y, x) 27 | 28 | # Behaviors 29 | def robot_arm(_g, step, sL, s): 30 | add_to_A = 0 31 | if (s['box_A'] > s['box_B']): 32 | add_to_A = -1 33 | elif (s['box_A'] < s['box_B']): 34 | add_to_A = 1 35 | return({'add_to_A': add_to_A, 'add_to_B': -add_to_A}) 36 | 37 | 38 | 39 | # Mechanisms 40 | def increment_A(_g, step, sL, s, _input): 41 | y = 'box_A' 42 | x = s['box_A'] + _input['add_to_A'] 43 | return (y, x) 44 | 45 | def increment_B(_g, step, sL, s, _input): 46 | y = 'box_B' 47 | x = s['box_B'] + _input['add_to_B'] 48 | return (y, x) 49 | 50 | # Initial States 51 | genesis_states = { 52 | 'box_A': 10, # as per the description of the example, box_A starts out with 10 marbles in it 53 | 'box_B': 0 # as per the description of the example, box_B starts out empty 54 | } 55 | 56 | exogenous_states = { 57 | #'time': time_model 58 | } 59 | 60 | env_processes = { 61 | } 62 | 63 | #build mechanism dictionary to "wire up the circuit" 64 | mechanisms = [ 65 | { 66 | 'policies': { # The following policy functions will be evaluated and their returns will be passed to the state update functions 67 | 'robot_arm': robot_arm 68 | }, 69 | 'states': { # The following state variables will be updated simultaneously 70 | 'box_A': increment_A, 71 | 'box_B': increment_B 72 | } 73 | } 74 | ] 75 | 76 | 77 | 78 | append_configs( 79 | sim_configs=sim_config, 80 | initial_state=genesis_states, 81 | seeds=seeds, 82 | raw_exogenous_states=exogenous_states, 83 | env_processes=env_processes, 84 | partial_state_update_blocks=mechanisms 85 | ) 86 | -------------------------------------------------------------------------------- /01 Tutorials/videos/robot-marbles-part-2/config2.py: -------------------------------------------------------------------------------- 1 | # import libraries 2 | from decimal import Decimal 3 | import numpy as np 4 | from datetime import timedelta 5 | from cadCAD.configuration import append_configs 6 | from cadCAD.configuration.utils import bound_norm_random, ep_time_step, config_sim 7 | 8 | seeds = { 9 | # 'z': np.random.RandomState(1), 10 | # 'a': np.random.RandomState(2) 11 | } 12 | 13 | sim_config = config_sim({ 14 | 'T': range(10), #number of discrete iterations in each experiement 15 | 'N': 1, #number of times the simulation will be run (Monte Carlo runs) 16 | #'M': g #parameter sweep dictionary 17 | }) 18 | 19 | 20 | # define the time deltas for the discrete increments in the model 21 | # ts_format = '%Y-%m-%d %H:%M:%S' 22 | # t_delta = timedelta(days=0, minutes=1, seconds=0) 23 | # def time_model(_g, step, sL, s, _input): 24 | # y = 'time' 25 | # x = ep_time_step(s, dt_str=s['time'], fromat_str=ts_format, _timedelta=t_delta) 26 | # return (y, x) 27 | 28 | # Behaviors 29 | def robot_arm(_g, step, sL, s): 30 | add_to_A = 0 31 | if (s['box_A'] > s['box_B']): 32 | add_to_A = -1 33 | elif (s['box_A'] < s['box_B']): 34 | add_to_A = 1 35 | return({'add_to_A': add_to_A, 'add_to_B': -add_to_A}) 36 | 37 | 38 | 39 | # Mechanisms 40 | def increment_A(_g, step, sL, s, _input): 41 | y = 'box_A' 42 | x = s['box_A'] + _input['add_to_A'] 43 | return (y, x) 44 | 45 | def increment_B(_g, step, sL, s, _input): 46 | y = 'box_B' 47 | x = s['box_B'] + _input['add_to_B'] 48 | return (y, x) 49 | 50 | # Initial States 51 | genesis_states = { 52 | 'box_A': 10, # as per the description of the example, box_A starts out with 10 marbles in it 53 | 'box_B': 0 # as per the description of the example, box_B starts out empty 54 | } 55 | 56 | exogenous_states = { 57 | #'time': time_model 58 | } 59 | 60 | env_processes = { 61 | } 62 | 63 | #build mechanism dictionary to "wire up the circuit" 64 | mechanisms = [ 65 | { 66 | 'policies': { # The following policy functions will be evaluated and their returns will be passed to the state update functions 67 | 'robot_arm_1': robot_arm, 68 | 'robot_arm_2': robot_arm 69 | }, 70 | 71 | 'states': { # The following state variables will be updated simultaneously 72 | 'box_A': increment_A, 73 | 'box_B': increment_B 74 | } 75 | } 76 | ] 77 | 78 | 79 | 80 | append_configs( 81 | sim_configs=sim_config, 82 | initial_state=genesis_states, 83 | seeds=seeds, 84 | raw_exogenous_states=exogenous_states, 85 | env_processes=env_processes, 86 | partial_state_update_blocks=mechanisms 87 | ) 88 | -------------------------------------------------------------------------------- /01 Tutorials/videos/robot-marbles-part-2/configBlank.py: -------------------------------------------------------------------------------- 1 | # import libraries 2 | from decimal import Decimal 3 | import numpy as np 4 | from datetime import timedelta 5 | from cadCAD.configuration import append_configs 6 | from cadCAD.configuration.utils import bound_norm_random, ep_time_step, config_sim 7 | 8 | seeds = { 9 | } 10 | 11 | sim_config = config_sim({ 12 | 'T': range(10), 13 | 'N': 1 14 | }) 15 | 16 | # Behaviors 17 | def robot_arm(_g, step, sL, s): 18 | add_to_A = 0 19 | if (s['box_A'] > s['box_B']): 20 | add_to_A = -1 21 | elif (s['box_A'] < s['box_B']): 22 | add_to_A = 1 23 | return({'add_to_A': add_to_A, 'add_to_B': -add_to_A}) 24 | 25 | 26 | # Mechanisms 27 | def increment_A(_g, step, sL, s, _input): 28 | y = 'box_A' 29 | x = s['box_A'] + _input['add_to_A'] 30 | return (y, x) 31 | 32 | def increment_B(_g, step, sL, s, _input): 33 | y = 'box_B' 34 | x = s['box_B'] + _input['add_to_B'] 35 | return (y, x) 36 | 37 | # Initial States 38 | genesis_states = { 39 | 'box_A': 10, 40 | 'box_B': 0 41 | } 42 | 43 | exogenous_states = { 44 | } 45 | 46 | 47 | env_processes = { 48 | } 49 | 50 | 51 | mechanisms = [ 52 | { 53 | 'policies': { 54 | 'robot_arm': robot_arm 55 | }, 56 | 'states': { 57 | 'box_A': increment_A, 58 | 'box_B': increment_B 59 | } 60 | } 61 | ] 62 | 63 | 64 | append_configs( 65 | sim_configs=sim_config, 66 | initial_state=genesis_states, 67 | seeds=seeds, 68 | raw_exogenous_states=exogenous_states, 69 | env_processes=env_processes, 70 | partial_state_update_blocks=mechanisms 71 | ) -------------------------------------------------------------------------------- /01 Tutorials/videos/robot-marbles-part-2/images/Mech.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlockScience/cadCAD-Tutorials/5ac9e99bfb66299316de4c9929fcc77fd16a23f9/01 Tutorials/videos/robot-marbles-part-2/images/Mech.jpeg -------------------------------------------------------------------------------- /01 Tutorials/videos/robot-marbles-part-2/images/Mech2.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlockScience/cadCAD-Tutorials/5ac9e99bfb66299316de4c9929fcc77fd16a23f9/01 Tutorials/videos/robot-marbles-part-2/images/Mech2.jpeg -------------------------------------------------------------------------------- /01 Tutorials/videos/robot-marbles-part-2/images/Overview.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlockScience/cadCAD-Tutorials/5ac9e99bfb66299316de4c9929fcc77fd16a23f9/01 Tutorials/videos/robot-marbles-part-2/images/Overview.jpeg -------------------------------------------------------------------------------- /01 Tutorials/videos/robot-marbles-part-3/README.md: -------------------------------------------------------------------------------- 1 | (https://youtu.be/wF539-K0qXs) 2 | -------------------------------------------------------------------------------- /01 Tutorials/videos/robot-marbles-part-3/cadCAD Template Robot and the Marbles - part 3.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# cadCAD Template: Robot and the Marbles - Part 3\n", 8 | "\n", 9 | "![](images/Overview.jpeg)\n", 10 | "![](images/Mech1.jpeg)\n", 11 | "\n", 12 | "\n", 13 | "### Asynchronous Subsystems\n", 14 | "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", 15 | "\n", 16 | "Suppose that instead of acting simultaneously, the robots in our examples operated in the following manner:\n", 17 | "\n", 18 | "* Robot 1: acts once every 2 timesteps\n", 19 | "* Robot 2: acts once every 3 timesteps\n", 20 | "\n", 21 | "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." 22 | ] 23 | }, 24 | { 25 | "cell_type": "code", 26 | "execution_count": 1, 27 | "metadata": {}, 28 | "outputs": [], 29 | "source": [ 30 | "# import libraries\n", 31 | "import pandas as pd\n", 32 | "import numpy as np\n", 33 | "import matplotlib \n", 34 | "from cadCAD.engine import ExecutionMode, ExecutionContext, Executor\n", 35 | "import config\n", 36 | "from cadCAD import configs\n", 37 | "import matplotlib.pyplot as plt\n", 38 | "\n", 39 | "%matplotlib inline\n", 40 | "\n", 41 | "exec_mode = ExecutionMode()" 42 | ] 43 | }, 44 | { 45 | "cell_type": "code", 46 | "execution_count": 2, 47 | "metadata": {}, 48 | "outputs": [ 49 | { 50 | "name": "stdout", 51 | "output_type": "stream", 52 | "text": [ 53 | "single_proc: []\n", 54 | "[]\n" 55 | ] 56 | }, 57 | { 58 | "data": { 59 | "text/html": [ 60 | "
\n", 61 | "\n", 74 | "\n", 75 | " \n", 76 | " \n", 77 | " \n", 78 | " \n", 79 | " \n", 80 | " \n", 81 | " \n", 82 | " \n", 83 | " \n", 84 | " \n", 85 | " \n", 86 | " \n", 87 | " \n", 88 | " \n", 89 | " \n", 90 | " \n", 91 | " \n", 92 | " \n", 93 | " \n", 94 | " \n", 95 | " \n", 96 | " \n", 97 | " \n", 98 | " \n", 99 | " \n", 100 | " \n", 101 | " \n", 102 | " \n", 103 | " \n", 104 | " \n", 105 | " \n", 106 | " \n", 107 | " \n", 108 | " \n", 109 | " \n", 110 | " \n", 111 | " \n", 112 | " \n", 113 | " \n", 114 | " \n", 115 | " \n", 116 | " \n", 117 | " \n", 118 | " \n", 119 | " \n", 120 | " \n", 121 | " \n", 122 | " \n", 123 | " \n", 124 | " \n", 125 | " \n", 126 | " \n", 127 | " \n", 128 | " \n", 129 | " \n", 130 | " \n", 131 | " \n", 132 | " \n", 133 | " \n", 134 | " \n", 135 | " \n", 136 | " \n", 137 | " \n", 138 | " \n", 139 | " \n", 140 | " \n", 141 | " \n", 142 | " \n", 143 | " \n", 144 | " \n", 145 | " \n", 146 | " \n", 147 | " \n", 148 | " \n", 149 | " \n", 150 | " \n", 151 | " \n", 152 | " \n", 153 | " \n", 154 | " \n", 155 | " \n", 156 | " \n", 157 | " \n", 158 | " \n", 159 | " \n", 160 | "
box_Abox_B
runtimestepsubstep
100100
11100
2191
3182
4173
5173
6155
7155
8155
9155
10155
\n", 161 | "
" 162 | ], 163 | "text/plain": [ 164 | " box_A box_B\n", 165 | "run timestep substep \n", 166 | "1 0 0 10 0\n", 167 | " 1 1 10 0\n", 168 | " 2 1 9 1\n", 169 | " 3 1 8 2\n", 170 | " 4 1 7 3\n", 171 | " 5 1 7 3\n", 172 | " 6 1 5 5\n", 173 | " 7 1 5 5\n", 174 | " 8 1 5 5\n", 175 | " 9 1 5 5\n", 176 | " 10 1 5 5" 177 | ] 178 | }, 179 | "execution_count": 2, 180 | "metadata": {}, 181 | "output_type": "execute_result" 182 | } 183 | ], 184 | "source": [ 185 | "# Run Cad^2\n", 186 | "\n", 187 | "first_config = configs # only contains config1\n", 188 | "single_proc_ctx = ExecutionContext(context=exec_mode.single_proc)\n", 189 | "run = Executor(exec_context=single_proc_ctx, configs=first_config)\n", 190 | "\n", 191 | "raw_result, tensor_field = run.execute()\n", 192 | "df = pd.DataFrame(raw_result)\n", 193 | "df.set_index(['run', 'timestep', 'substep'])" 194 | ] 195 | }, 196 | { 197 | "cell_type": "code", 198 | "execution_count": 3, 199 | "metadata": {}, 200 | "outputs": [ 201 | { 202 | "data": { 203 | "image/png": "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\n", 204 | "text/plain": [ 205 | "
" 206 | ] 207 | }, 208 | "metadata": { 209 | "needs_background": "light" 210 | }, 211 | "output_type": "display_data" 212 | } 213 | ], 214 | "source": [ 215 | "df.plot('timestep', ['box_A', 'box_B'], grid=True, \n", 216 | " colormap = 'RdYlGn',\n", 217 | " xticks=list(df['timestep'].drop_duplicates()), \n", 218 | " yticks=list(range(1+(df['box_A']+df['box_B']).max())));" 219 | ] 220 | }, 221 | { 222 | "cell_type": "markdown", 223 | "metadata": {}, 224 | "source": [ 225 | "Let's take a step-by-step look at what the simulation tells us:\n", 226 | "\n", 227 | "* Timestep 1: the number of marbles in the boxes does not change, as none of the robots act\n", 228 | "* Timestep 2: Robot 1 acts, Robot 2 doesn't; resulting in one marble being moved from box A to box B\n", 229 | "* Timestep 3: Robot 2 acts, Robot 1 doesn't; resulting in one marble being moved from box A to box B\n", 230 | "* Timestep 4: Robot 1 acts, Robot 2 doesn't; resulting in one marble being moved from box A to box B\n", 231 | "* Timestep 5: the number of marbles in the boxes does not change, as none of the robots act\n", 232 | "* 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." 233 | ] 234 | } 235 | ], 236 | "metadata": { 237 | "kernelspec": { 238 | "display_name": "Python 3", 239 | "language": "python", 240 | "name": "python3" 241 | }, 242 | "language_info": { 243 | "codemirror_mode": { 244 | "name": "ipython", 245 | "version": 3 246 | }, 247 | "file_extension": ".py", 248 | "mimetype": "text/x-python", 249 | "name": "python", 250 | "nbconvert_exporter": "python", 251 | "pygments_lexer": "ipython3", 252 | "version": "3.7.0" 253 | } 254 | }, 255 | "nbformat": 4, 256 | "nbformat_minor": 2 257 | } 258 | -------------------------------------------------------------------------------- /01 Tutorials/videos/robot-marbles-part-3/config.py: -------------------------------------------------------------------------------- 1 | # import libraries 2 | from decimal import Decimal 3 | import numpy as np 4 | from datetime import timedelta 5 | from cadCAD.configuration import append_configs 6 | from cadCAD.configuration.utils import bound_norm_random, ep_time_step, config_sim 7 | 8 | seeds = { 9 | # 'z': np.random.RandomState(1), 10 | # 'a': np.random.RandomState(2) 11 | } 12 | 13 | sim_config = config_sim({ 14 | 'T': range(10), #number of discrete iterations in each experiement 15 | 'N': 1, #number of times the simulation will be run (Monte Carlo runs) 16 | #'M': g #parameter sweep dictionary 17 | }) 18 | 19 | 20 | # define the time deltas for the discrete increments in the model 21 | # ts_format = '%Y-%m-%d %H:%M:%S' 22 | # t_delta = timedelta(days=0, minutes=1, seconds=0) 23 | # def time_model(_g, step, sL, s, _input): 24 | # y = 'time' 25 | # x = ep_time_step(s, dt_str=s['time'], fromat_str=ts_format, _timedelta=t_delta) 26 | # return (y, x) 27 | 28 | # Behaviors 29 | def robot_arm(_g, step, sL, s): 30 | add_to_A = 0 31 | if (s['box_A'] > s['box_B']): 32 | add_to_A = -1 33 | elif (s['box_A'] < s['box_B']): 34 | add_to_A = 1 35 | return({'add_to_A': add_to_A, 'add_to_B': -add_to_A}) 36 | 37 | robots_periods = [2,3] # Robot 1 acts once every 2 timesteps; Robot 2 acts once every 3 timesteps 38 | 39 | def get_current_timestep(cur_substep, s): 40 | if cur_substep == 1: 41 | return s['timestep']+1 42 | return s['timestep'] 43 | 44 | def robot_arm_1(_g, step, sL, s): 45 | _robotId = 1 46 | if get_current_timestep(step, s)%robots_periods[_robotId-1]==0: # on timesteps that are multiple of 2, Robot 1 acts 47 | return robot_arm(_g, step, sL, s) 48 | else: 49 | return({'add_to_A': 0, 'add_to_B': 0}) # for all other timesteps, Robot 1 doesn't interfere with the system 50 | 51 | def robot_arm_2(_g, step, sL, s): 52 | _robotId = 2 53 | if get_current_timestep(step, s)%robots_periods[_robotId-1]==0: # on timesteps that are multiple of 3, Robot 2 acts 54 | return robot_arm(_g, step, sL, s) 55 | else: 56 | return({'add_to_A': 0, 'add_to_B': 0}) # for all other timesteps, Robot 2 doesn't interfere with the system 57 | 58 | 59 | 60 | # Mechanisms 61 | def increment_A(_g, step, sL, s, _input): 62 | y = 'box_A' 63 | x = s['box_A'] + _input['add_to_A'] 64 | return (y, x) 65 | 66 | def increment_B(_g, step, sL, s, _input): 67 | y = 'box_B' 68 | x = s['box_B'] + _input['add_to_B'] 69 | return (y, x) 70 | 71 | # Initial States 72 | genesis_states = { 73 | 'box_A': 10, # as per the description of the example, box_A starts out with 10 marbles in it 74 | 'box_B': 0 # as per the description of the example, box_B starts out empty 75 | } 76 | 77 | exogenous_states = { 78 | #'time': time_model 79 | } 80 | 81 | env_processes = { 82 | } 83 | 84 | #build mechanism dictionary to "wire up the circuit" 85 | mechanisms = [ 86 | { 87 | 'policies': { # The following policy functions will be evaluated and their returns will be passed to the state update functions 88 | 'robot_arm_1': robot_arm_1, 89 | 'robot_arm_2': robot_arm_2 90 | }, 91 | 92 | 'states': { # The following state variables will be updated simultaneously 93 | 'box_A': increment_A, 94 | 'box_B': increment_B 95 | } 96 | } 97 | ] 98 | 99 | 100 | 101 | append_configs( 102 | sim_configs=sim_config, 103 | initial_state=genesis_states, 104 | seeds=seeds, 105 | raw_exogenous_states=exogenous_states, 106 | env_processes=env_processes, 107 | partial_state_update_blocks=mechanisms 108 | ) 109 | -------------------------------------------------------------------------------- /01 Tutorials/videos/robot-marbles-part-3/images/Mech1.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlockScience/cadCAD-Tutorials/5ac9e99bfb66299316de4c9929fcc77fd16a23f9/01 Tutorials/videos/robot-marbles-part-3/images/Mech1.jpeg -------------------------------------------------------------------------------- /01 Tutorials/videos/robot-marbles-part-3/images/Overview.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlockScience/cadCAD-Tutorials/5ac9e99bfb66299316de4c9929fcc77fd16a23f9/01 Tutorials/videos/robot-marbles-part-3/images/Overview.jpeg -------------------------------------------------------------------------------- /01 Tutorials/videos/robot-marbles-part-4/README.md: -------------------------------------------------------------------------------- 1 | (https://youtu.be/MLNTqqX47Ew) 2 | -------------------------------------------------------------------------------- /01 Tutorials/videos/robot-marbles-part-4/config.py: -------------------------------------------------------------------------------- 1 | # import libraries 2 | from decimal import Decimal 3 | import numpy as np 4 | from datetime import timedelta 5 | from cadCAD.configuration import append_configs 6 | from cadCAD.configuration.utils import bound_norm_random, ep_time_step, config_sim 7 | 8 | seeds = { 9 | # 'z': np.random.RandomState(1), 10 | # 'a': np.random.RandomState(2) 11 | } 12 | 13 | sim_config = config_sim({ 14 | 'T': range(10), #number of discrete iterations in each experiement 15 | 'N': 1, #number of times the simulation will be run (Monte Carlo runs) 16 | #'M': g #parameter sweep dictionary 17 | }) 18 | 19 | 20 | # define the time deltas for the discrete increments in the model 21 | # ts_format = '%Y-%m-%d %H:%M:%S' 22 | # t_delta = timedelta(days=0, minutes=1, seconds=0) 23 | # def time_model(_g, step, sL, s, _input): 24 | # y = 'time' 25 | # x = ep_time_step(s, dt_str=s['time'], fromat_str=ts_format, _timedelta=t_delta) 26 | # return (y, x) 27 | 28 | # Behaviors 29 | def robot_arm(_g, step, sL, s): 30 | add_to_A = 0 31 | if (s['box_A'] > s['box_B']): 32 | add_to_A = -1 33 | elif (s['box_A'] < s['box_B']): 34 | add_to_A = 1 35 | return({'add_to_A': add_to_A, 'add_to_B': -add_to_A}) 36 | 37 | robots_probabilities = [0.5,1/3] # Robot 1 acts with a 50% probability; Robot 2, 33.33% 38 | 39 | def robot_arm_1(_g, step, sL, s): 40 | _robotId = 1 41 | if np.random.rand() s['box_B']): 32 | add_to_A = -1 33 | elif (s['box_A'] < s['box_B']): 34 | add_to_A = 1 35 | return({'add_to_A': add_to_A, 'add_to_B': -add_to_A}) 36 | 37 | robots_probabilities = [0.5,1/3] # Robot 1 acts with a 50% probability; Robot 2, 33.33% 38 | 39 | def robot_arm_1(_g, step, sL, s): 40 | _robotId = 1 41 | if np.random.rand() params['reserve_threshold']*current_state['fiat_reserve']: 16 | budget_released = target_release 17 | else: 18 | budget_released = (1.0-params['reserve_threshold'])*current_state['fiat_reserve'] 19 | else: 20 | budget_released = params['min_budget_release']*current_state['fiat_reserve'] 21 | 22 | return {'budget_released': budget_released} 23 | 24 | def minting_policy(params, step, history, current_state): 25 | ''' 26 | governance decision ~ determines the conditions or schedule of new tokens minted 27 | ''' 28 | mint = (params['final_supply']-current_state['token_supply'])*params['release_rate'] 29 | return {'mint': mint} 30 | 31 | 32 | def conversion_policy(params, step, history, current_state): 33 | ''' 34 | governance decision ~ system policy for token/fiat unit of value conversion 35 | ''' 36 | ncr = params['conversion_rate_gain']*current_state['smooth_avg_token_reserve']/current_state['smooth_avg_fiat_reserve'] 37 | return {'new_conversion_rate': ncr} 38 | 39 | # Mechanisms 40 | def release_funds(params, step, sL, s, _input): 41 | #tokens outbound 42 | y = 'fiat_reserve' 43 | x = s['fiat_reserve'] - _input['budget_released'] 44 | return (y, x) 45 | 46 | def update_budget(params, step, sL, s, _input): 47 | #tokens outbound 48 | y = 'operational_budget' 49 | x = s['operational_budget'] + _input['budget_released'] 50 | return (y, x) 51 | 52 | def mint1(params, step, sL, s, _input): 53 | ''' 54 | minting process mints into the reserve 55 | ''' 56 | y = 'token_supply' 57 | x = s['token_supply'] + _input['mint'] 58 | return (y, x) 59 | 60 | def mint2(params, step, sL, s, _input): 61 | y = 'token_reserve' 62 | x = s['token_reserve'] + _input['mint'] 63 | return (y, x) 64 | 65 | def update_conversion_rate(params, step, sL, s, _input): 66 | y = 'conversion_rate' 67 | x = _input['new_conversion_rate'] 68 | return (y, x) -------------------------------------------------------------------------------- /02 Reference Models/ThreeSided/model/parts/investors.py: -------------------------------------------------------------------------------- 1 | 2 | 3 | # Behaviors 4 | def investors(params, step, history, current_state): 5 | # Pay relevant parties 6 | if current_state['timestep'] == 1: 7 | return {'Invest': 1} 8 | elif current_state['timestep'] == 10: 9 | return {'Invest': 1} 10 | else: 11 | return {'Invest': 0} 12 | 13 | 14 | # Mechanisms 15 | def receive_fiat_from_investors(params, step, sL, s, _input): 16 | y = 'fiat_reserve' 17 | if _input['Invest'] == 1: 18 | x = s['fiat_reserve'] + s['seed_money'] 19 | else: 20 | x = s['fiat_reserve'] 21 | return (y, x) 22 | 23 | -------------------------------------------------------------------------------- /02 Reference Models/ThreeSided/model/parts/producers.py: -------------------------------------------------------------------------------- 1 | 2 | import numpy as np 3 | #governance decision ~ system policy for compensating producers 4 | #consider transaction volume, labor committed and token reserve and supply to determine payout 5 | 6 | #this function is a parameter of this policy which determines diminishing value of more labor 7 | base_value = 1000.0 8 | 9 | def marginal_utility_function(x): 10 | #this is how much the platform value a total amount of production (in fiat) 11 | return base_value+np.sqrt(x) 12 | 13 | 14 | # Behaviors 15 | def producer_choice(params, step, history, current_state): 16 | #ROI heuristic 17 | # add or remove resources based on deviation from threshold 18 | if current_state['producer_roi_estimate'] < 0: 19 | delta_labor = current_state['volume_of_production']*(params['attrition_rate']-1.0) 20 | else: 21 | ratio = current_state['producer_roi_estimate']/params['roi_threshold'] 22 | delta_labor = params['roi_gain']*current_state['volume_of_production']*(ratio-1.0) 23 | 24 | return {'delta_labor': delta_labor} 25 | 26 | def producer_compensation_policy(params, step, history, current_state): 27 | tokens_paid = current_state['conversion_rate']*marginal_utility_function(current_state['volume_of_production']) 28 | return {'tokens_paid': tokens_paid} 29 | 30 | # Mechanisms 31 | def commit_delta_production(params, step, sL, s, _input): 32 | y = 'volume_of_production' 33 | x = s['volume_of_production']+_input['delta_labor'] 34 | return (y, x) 35 | 36 | 37 | def compensate_production(params, step, sL, s, _input): 38 | y = 'token_reserve' 39 | x = s['token_reserve']-_input['tokens_paid'] 40 | return (y, x) 41 | 42 | def update_producer_roi_estimate(params, step, sL, s, _input): 43 | revenue = _input['tokens_paid']/s['conversion_rate'] 44 | cost = s['cost_of_production']*s['volume_of_production'] 45 | spot_ROI_estimate = (revenue-cost)/cost 46 | y = 'producer_roi_estimate' 47 | x = params['rho']*spot_ROI_estimate + s['producer_roi_estimate']*(1.0-params['rho']) 48 | return (y, x) -------------------------------------------------------------------------------- /02 Reference Models/ThreeSided/model/parts/providers.py: -------------------------------------------------------------------------------- 1 | 2 | # Behaviors 3 | def provider_choice(params, step, history, current_state): 4 | #fiat claimed by providers 5 | #note: balance of provided vol covered in tokens (computed later) 6 | txo_fiat = params['theta']*current_state['tx_volume']+ (1-params['theta'])*params['gamma']*current_state['volume_of_production']*current_state['cost_of_production'] 7 | return {'txo_fiat': txo_fiat} 8 | 9 | 10 | # Mechanisms 11 | def compensate_providers1(params, step, sL, s, _input): 12 | #fiat outbound 13 | y = 'fiat_reserve' 14 | x = s['fiat_reserve']-_input['txo_fiat']*(1.0-params['platform_fee']) 15 | return (y, x) 16 | 17 | def compensate_providers2(params, step, sL, s, _input): 18 | #tokens outbound 19 | y = 'token_reserve' 20 | fiat_eq = s['tx_volume']-_input['txo_fiat'] 21 | x = s['token_reserve']-s['conversion_rate']*fiat_eq*(1.0-params['platform_fee']-params['conversion_fee']) 22 | return (y, x) 23 | -------------------------------------------------------------------------------- /02 Reference Models/ThreeSided/model/parts/sys_params.py: -------------------------------------------------------------------------------- 1 | 2 | 3 | # params 4 | params = { 5 | 'eta': [.065], # for tx_volume_generator 6 | 'tampw': [100000], # transactions limit 7 | 'alpha': [.9], # for cost_of_production_generator 8 | 'beta': [1.0], # for cost_of_production_generator 9 | 'flat': [500], #log quadratic overhead model; parameters 10 | 'a': [1000.0], 11 | 'b': [100.0], 12 | 'c': [1.0], 13 | 'd': [1.0], 14 | 'theta': [0.6], #theta percent of service providers ALWAYS use fiat, 15 | 'gamma': [0.1], #parameter gamma is a tuning gain 16 | 'roi_threshold': [.2], 17 | 'attrition_rate': [.5], 18 | 'roi_gain': [0.025], 19 | 'conversion_fee': [.03], 20 | 'platform_fee': [0.075], 21 | 'rho': [.1], 22 | 'buffer_runway': [3.0], 23 | 'reserve_threshold': [.25], 24 | 'min_budget_release': [0], 25 | 'final_supply': [1000000.0], #1M #unit: tokens 26 | 'release_rate':[.01], #percent of remaining, 27 | 'conversion_rate_gain': [1] 28 | } 29 | 30 | 31 | 32 | # Initial States 33 | initial_values = { 34 | 'fiat_reserve': float(25000),#unit: fiat 35 | 'overhead_cost': float(500), #unit: fiat 36 | 'operational_budget': float(25000), #unit: fiat 37 | 'token_reserve': float(25000),#unit: tok 38 | 'token_supply': float(25000),#unit: tok 39 | 'tx_volume': float(1000), #unit: fiat 40 | 'conversion_rate': float(1), #unit: tok/fiat 41 | 'cost_of_production': float(10), #unit: fiat/labor 42 | 'volume_of_production': float(20), #unit: labor 43 | 'producer_roi_estimate': float(1.1), #unitless //signal for informing policies 44 | 'smooth_avg_fiat_reserve': float(25000), #unit: fiat //signal for informing policies 45 | 'smooth_avg_token_reserve': float(25000), #unit: token //signal for informing policies 46 | } -------------------------------------------------------------------------------- /02 Reference Models/ThreeSided/model/parts/system.py: -------------------------------------------------------------------------------- 1 | 2 | # Mechanisms 3 | def update_smooth_avg_fiat_reserve(params, step, sL, s, _input): 4 | y = 'smooth_avg_fiat_reserve' 5 | x = s['fiat_reserve']*params['rho']+s['smooth_avg_fiat_reserve']*(1-params['rho']) 6 | return (y, x) 7 | 8 | def update_smooth_avg_token_reserve(params, step, sL, s, _input): 9 | y = 'smooth_avg_token_reserve' 10 | x = s['token_reserve']*params['rho']+s['smooth_avg_token_reserve']*(1-params['rho']) 11 | return (y, x) 12 | 13 | -------------------------------------------------------------------------------- /02 Reference Models/ThreeSided/model/parts/utils.py: -------------------------------------------------------------------------------- 1 | # import libraries 2 | import pandas as pd 3 | import numpy as np 4 | import matplotlib.pyplot as plt 5 | 6 | 7 | ##### Utils 8 | def aggregate_runs(df,aggregate_dimension): 9 | ''' 10 | Function to aggregate the monte carlo runs along a single dimension. 11 | 12 | Parameters: 13 | df: dataframe name 14 | aggregate_dimension: the dimension you would like to aggregate on, the standard one is timestep. 15 | 16 | Example run: 17 | mean_df,median_df,std_df,min_df = aggregate_runs(df,'timestep') 18 | ''' 19 | aggregate_dimension = aggregate_dimension 20 | 21 | mean_df = df.groupby(aggregate_dimension).mean().reset_index() 22 | median_df = df.groupby(aggregate_dimension).median().reset_index() 23 | std_df = df.groupby(aggregate_dimension).std().reset_index() 24 | min_df = df.groupby(aggregate_dimension).min().reset_index() 25 | 26 | return mean_df,median_df,std_df,min_df -------------------------------------------------------------------------------- /02 Reference Models/ThreeSided/model/run.py: -------------------------------------------------------------------------------- 1 | import pandas as pd 2 | from .parts.utils import * 3 | from model import config 4 | from cadCAD.engine import ExecutionMode, ExecutionContext,Executor 5 | from cadCAD import configs 6 | 7 | def run(): 8 | ''' 9 | Definition: 10 | Run simulation 11 | ''' 12 | exec_mode = ExecutionMode() 13 | local_mode_ctx = ExecutionContext(context=exec_mode.local_mode) 14 | 15 | simulation = Executor(exec_context=local_mode_ctx, configs=configs) 16 | raw_system_events, tensor_field, sessions = simulation.execute() 17 | # Result System Events DataFrame 18 | df = pd.DataFrame(raw_system_events) 19 | return df 20 | 21 | 22 | 23 | def postprocessing(df, sim_ind=-1): 24 | ''' 25 | Function for postprocessing the simulation results 26 | ''' 27 | # subset to last substep of each simulation 28 | df= df[df.substep==df.substep.max()] 29 | 30 | mean_df,median_df,std_df,min_df = aggregate_runs(df,'timestep') 31 | 32 | return mean_df,median_df,std_df,min_df -------------------------------------------------------------------------------- /02 Reference Models/ThreeSided/model/state_variables.py: -------------------------------------------------------------------------------- 1 | from .parts.sys_params import * 2 | 3 | # Initial States 4 | state_variables = { 5 | 'fiat_reserve': initial_values['fiat_reserve'],#unit: fiat 6 | 'overhead_cost': initial_values['overhead_cost'], #unit: fiat 7 | 'operational_budget': initial_values['operational_budget'], #unit: fiat 8 | 'token_reserve': initial_values['token_reserve'],#unit: tok 9 | 'token_supply': initial_values['token_supply'],#unit: tok 10 | 'tx_volume': initial_values['tx_volume'], #unit: fiat 11 | 'conversion_rate': initial_values['conversion_rate'], #unit: tok/fiat 12 | 'cost_of_production': initial_values['cost_of_production'], #unit: fiat/labor 13 | 'volume_of_production': initial_values['volume_of_production'], #unit: labor 14 | 'producer_roi_estimate': initial_values['producer_roi_estimate'], #unitless //signal for informing policies 15 | 'smooth_avg_fiat_reserve': initial_values['smooth_avg_fiat_reserve'], #unit: fiat //signal for informing policies 16 | 'smooth_avg_token_reserve': initial_values['smooth_avg_token_reserve'], #unit: token //signal for informing policies 17 | } 18 | 19 | -------------------------------------------------------------------------------- /02 Reference Models/ThreeSided/threesidedmarket.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlockScience/cadCAD-Tutorials/5ac9e99bfb66299316de4c9929fcc77fd16a23f9/02 Reference Models/ThreeSided/threesidedmarket.jpeg -------------------------------------------------------------------------------- /02 Reference Models/ThreeSidedBasic/Basic Three-Sided Market Model.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlockScience/cadCAD-Tutorials/5ac9e99bfb66299316de4c9929fcc77fd16a23f9/02 Reference Models/ThreeSidedBasic/Basic Three-Sided Market Model.pdf -------------------------------------------------------------------------------- /02 Reference Models/ThreeSidedBasic/depreciated/Latex/Basic Three-Sided Market Model.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlockScience/cadCAD-Tutorials/5ac9e99bfb66299316de4c9929fcc77fd16a23f9/02 Reference Models/ThreeSidedBasic/depreciated/Latex/Basic Three-Sided Market Model.pdf -------------------------------------------------------------------------------- /02 Reference Models/ThreeSidedBasic/depreciated/Latex/images/3SidedMarketBasicDemo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlockScience/cadCAD-Tutorials/5ac9e99bfb66299316de4c9929fcc77fd16a23f9/02 Reference Models/ThreeSidedBasic/depreciated/Latex/images/3SidedMarketBasicDemo.png -------------------------------------------------------------------------------- /02 Reference Models/ThreeSidedBasic/depreciated/Latex/images/Results-eps-converted-to.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlockScience/cadCAD-Tutorials/5ac9e99bfb66299316de4c9929fcc77fd16a23f9/02 Reference Models/ThreeSidedBasic/depreciated/Latex/images/Results-eps-converted-to.pdf -------------------------------------------------------------------------------- /02 Reference Models/ThreeSidedBasic/depreciated/Latex/images/components-eps-converted-to.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlockScience/cadCAD-Tutorials/5ac9e99bfb66299316de4c9929fcc77fd16a23f9/02 Reference Models/ThreeSidedBasic/depreciated/Latex/images/components-eps-converted-to.pdf -------------------------------------------------------------------------------- /02 Reference Models/ThreeSidedBasic/depreciated/Latex/images/productCost.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlockScience/cadCAD-Tutorials/5ac9e99bfb66299316de4c9929fcc77fd16a23f9/02 Reference Models/ThreeSidedBasic/depreciated/Latex/images/productCost.png -------------------------------------------------------------------------------- /02 Reference Models/ThreeSidedBasic/depreciated/Latex/main.aux: -------------------------------------------------------------------------------- 1 | \relax 2 | \providecommand \oddpage@label [2]{} 3 | \@writefile{toc}{\contentsline {section}{\numberline {1}Introduction}{1}} 4 | \@writefile{lof}{\contentsline {figure}{\numberline {1}{\ignorespaces Basic Three-Sided Market Model}}{2}} 5 | \@writefile{toc}{\contentsline {section}{\numberline {2}Building a Model of a Three-Sided Market}{2}} 6 | \@writefile{toc}{\contentsline {section}{\numberline {3}Build Individual Components}{3}} 7 | \@writefile{toc}{\contentsline {subsection}{\numberline {3.1}Transaction Growth Rate}{3}} 8 | \@writefile{toc}{\contentsline {subsection}{\numberline {3.2}Product Cost}{3}} 9 | \@writefile{lof}{\contentsline {figure}{\numberline {2}{\ignorespaces Components}}{3}} 10 | \newlabel{fig:components}{{2}{3}} 11 | \@writefile{toc}{\contentsline {section}{\numberline {4}cadCAD Simulation}{4}} 12 | \@writefile{lot}{\contentsline {table}{\numberline {1}{\ignorespaces First five time steps of the Monte Carlo Run}}{4}} 13 | \newlabel{table:FirstFive}{{1}{4}} 14 | \@writefile{lot}{\contentsline {table}{\numberline {2}{\ignorespaces Last five time steps of the Monte Carlo Run}}{4}} 15 | \newlabel{table:LastFive}{{2}{4}} 16 | \@writefile{lof}{\contentsline {figure}{\numberline {3}{\ignorespaces Results}}{5}} 17 | \newlabel{fig:results}{{3}{5}} 18 | \@writefile{toc}{\contentsline {section}{\numberline {5}Conclusion}{5}} 19 | -------------------------------------------------------------------------------- /02 Reference Models/ThreeSidedBasic/depreciated/Latex/main.log: -------------------------------------------------------------------------------- 1 | This is pdfTeX, Version 3.14159265-2.6-1.40.19 (TeX Live 2019/dev/Debian) (preloaded format=pdflatex 2019.1.16) 10 APR 2019 14:57 2 | entering extended mode 3 | restricted \write18 enabled. 4 | %&-line parsing enabled. 5 | **main.tex 6 | (./main.tex 7 | LaTeX2e <2018-04-01> patch level 5 8 | (/usr/share/texlive/texmf-dist/tex/latex/extsizes/extarticle.cls 9 | Document Class: extarticle 1996/10/08 v1.0 Non Standard LaTeX document class 10 | (/usr/share/texlive/texmf-dist/tex/latex/base/size12.clo 11 | File: size12.clo 2014/09/29 v1.4h Standard LaTeX file (size option) 12 | ) 13 | (/usr/share/texlive/texmf-dist/tex/latex/base/exscale.sty 14 | Package: exscale 2014/09/29 v2.1h Standard LaTeX package exscale 15 | LaTeX Font Info: Redeclaring symbol font `largesymbols' on input line 57. 16 | LaTeX Font Info: Overwriting symbol font `largesymbols' in version `normal' 17 | (Font) OMX/cmex/m/n --> OMX/cmex/m/n on input line 57. 18 | LaTeX Font Info: Overwriting symbol font `largesymbols' in version `bold' 19 | (Font) OMX/cmex/m/n --> OMX/cmex/m/n on input line 57. 20 | \big@size=\dimen102 21 | ) 22 | \c@part=\count80 23 | \c@section=\count81 24 | \c@subsection=\count82 25 | \c@subsubsection=\count83 26 | \c@paragraph=\count84 27 | \c@subparagraph=\count85 28 | \c@figure=\count86 29 | \c@table=\count87 30 | \abovecaptionskip=\skip41 31 | \belowcaptionskip=\skip42 32 | \bibindent=\dimen103 33 | ) 34 | (/usr/share/texlive/texmf-dist/tex/latex/base/inputenc.sty 35 | Package: inputenc 2018/04/06 v1.3b Input encoding file 36 | \inpenc@prehook=\toks14 37 | \inpenc@posthook=\toks15 38 | ) 39 | (/usr/share/texlive/texmf-dist/tex/latex/graphics/graphicx.sty 40 | Package: graphicx 2017/06/01 v1.1a Enhanced LaTeX Graphics (DPC,SPQR) 41 | 42 | (/usr/share/texlive/texmf-dist/tex/latex/graphics/keyval.sty 43 | Package: keyval 2014/10/28 v1.15 key=value parser (DPC) 44 | \KV@toks@=\toks16 45 | ) 46 | (/usr/share/texlive/texmf-dist/tex/latex/graphics/graphics.sty 47 | Package: graphics 2017/06/25 v1.2c Standard LaTeX Graphics (DPC,SPQR) 48 | 49 | (/usr/share/texlive/texmf-dist/tex/latex/graphics/trig.sty 50 | Package: trig 2016/01/03 v1.10 sin cos tan (DPC) 51 | ) 52 | (/usr/share/texlive/texmf-dist/tex/latex/graphics-cfg/graphics.cfg 53 | File: graphics.cfg 2016/06/04 v1.11 sample graphics configuration 54 | ) 55 | Package graphics Info: Driver file: pdftex.def on input line 99. 56 | 57 | (/usr/share/texlive/texmf-dist/tex/latex/graphics-def/pdftex.def 58 | File: pdftex.def 2018/01/08 v1.0l Graphics/color driver for pdftex 59 | )) 60 | \Gin@req@height=\dimen104 61 | \Gin@req@width=\dimen105 62 | ) 63 | (/usr/share/texlive/texmf-dist/tex/latex/booktabs/booktabs.sty 64 | Package: booktabs 2016/04/27 v1.618033 publication quality tables 65 | \heavyrulewidth=\dimen106 66 | \lightrulewidth=\dimen107 67 | \cmidrulewidth=\dimen108 68 | \belowrulesep=\dimen109 69 | \belowbottomsep=\dimen110 70 | \aboverulesep=\dimen111 71 | \abovetopsep=\dimen112 72 | \cmidrulesep=\dimen113 73 | \cmidrulekern=\dimen114 74 | \defaultaddspace=\dimen115 75 | \@cmidla=\count88 76 | \@cmidlb=\count89 77 | \@aboverulesep=\dimen116 78 | \@belowrulesep=\dimen117 79 | \@thisruleclass=\count90 80 | \@lastruleclass=\count91 81 | \@thisrulewidth=\dimen118 82 | ) 83 | (/usr/share/texlive/texmf-dist/tex/latex/adjustbox/adjustbox.sty 84 | Package: adjustbox 2018/04/08 v1.1 Adjusting TeX boxes (trim, clip, ...) 85 | 86 | (/usr/share/texlive/texmf-dist/tex/latex/xkeyval/xkeyval.sty 87 | Package: xkeyval 2014/12/03 v2.7a package option processing (HA) 88 | 89 | (/usr/share/texlive/texmf-dist/tex/generic/xkeyval/xkeyval.tex 90 | (/usr/share/texlive/texmf-dist/tex/generic/xkeyval/xkvutils.tex 91 | \XKV@toks=\toks17 92 | \XKV@tempa@toks=\toks18 93 | ) 94 | \XKV@depth=\count92 95 | File: xkeyval.tex 2014/12/03 v2.7a key=value parser (HA) 96 | )) 97 | (/usr/share/texlive/texmf-dist/tex/latex/adjustbox/adjcalc.sty 98 | Package: adjcalc 2012/05/16 v1.1 Provides advanced setlength with multiple back 99 | -ends (calc, etex, pgfmath) 100 | ) 101 | (/usr/share/texlive/texmf-dist/tex/latex/adjustbox/trimclip.sty 102 | Package: trimclip 2018/04/08 v1.1 Trim and clip general TeX material 103 | 104 | (/usr/share/texlive/texmf-dist/tex/latex/collectbox/collectbox.sty 105 | Package: collectbox 2012/05/17 v0.4b Collect macro arguments as boxes 106 | \collectedbox=\box26 107 | ) 108 | \tc@llx=\dimen119 109 | \tc@lly=\dimen120 110 | \tc@urx=\dimen121 111 | \tc@ury=\dimen122 112 | Package trimclip Info: Using driver 'tc-pdftex.def'. 113 | 114 | (/usr/share/texlive/texmf-dist/tex/latex/adjustbox/tc-pdftex.def 115 | File: tc-pdftex.def 2018/04/08 v2.1 Clipping driver for pdftex 116 | )) 117 | \adjbox@Width=\dimen123 118 | \adjbox@Height=\dimen124 119 | \adjbox@Depth=\dimen125 120 | \adjbox@Totalheight=\dimen126 121 | \adjbox@pwidth=\dimen127 122 | \adjbox@pheight=\dimen128 123 | \adjbox@pdepth=\dimen129 124 | \adjbox@ptotalheight=\dimen130 125 | 126 | (/usr/share/texlive/texmf-dist/tex/latex/ifoddpage/ifoddpage.sty 127 | Package: ifoddpage 2016/04/23 v1.1 Conditionals for odd/even page detection 128 | \c@checkoddpage=\count93 129 | ) 130 | (/usr/share/texlive/texmf-dist/tex/latex/varwidth/varwidth.sty 131 | Package: varwidth 2009/03/30 ver 0.92; Variable-width minipages 132 | \@vwid@box=\box27 133 | \sift@deathcycles=\count94 134 | \@vwid@loff=\dimen131 135 | \@vwid@roff=\dimen132 136 | )) 137 | (/usr/share/texlive/texmf-dist/tex/latex/geometry/geometry.sty 138 | Package: geometry 2018/04/16 v5.8 Page Geometry 139 | 140 | (/usr/share/texlive/texmf-dist/tex/generic/oberdiek/ifpdf.sty 141 | Package: ifpdf 2017/03/15 v3.2 Provides the ifpdf switch 142 | ) 143 | (/usr/share/texlive/texmf-dist/tex/generic/oberdiek/ifvtex.sty 144 | Package: ifvtex 2016/05/16 v1.6 Detect VTeX and its facilities (HO) 145 | Package ifvtex Info: VTeX not detected. 146 | ) 147 | (/usr/share/texlive/texmf-dist/tex/generic/ifxetex/ifxetex.sty 148 | Package: ifxetex 2010/09/12 v0.6 Provides ifxetex conditional 149 | ) 150 | \Gm@cnth=\count95 151 | \Gm@cntv=\count96 152 | \c@Gm@tempcnt=\count97 153 | \Gm@bindingoffset=\dimen133 154 | \Gm@wd@mp=\dimen134 155 | \Gm@odd@mp=\dimen135 156 | \Gm@even@mp=\dimen136 157 | \Gm@layoutwidth=\dimen137 158 | \Gm@layoutheight=\dimen138 159 | \Gm@layouthoffset=\dimen139 160 | \Gm@layoutvoffset=\dimen140 161 | \Gm@dimlist=\toks19 162 | ) (./main.aux) 163 | \openout1 = `main.aux'. 164 | 165 | LaTeX Font Info: Checking defaults for OML/cmm/m/it on input line 13. 166 | LaTeX Font Info: ... okay on input line 13. 167 | LaTeX Font Info: Checking defaults for T1/cmr/m/n on input line 13. 168 | LaTeX Font Info: ... okay on input line 13. 169 | LaTeX Font Info: Checking defaults for OT1/cmr/m/n on input line 13. 170 | LaTeX Font Info: ... okay on input line 13. 171 | LaTeX Font Info: Checking defaults for OMS/cmsy/m/n on input line 13. 172 | LaTeX Font Info: ... okay on input line 13. 173 | LaTeX Font Info: Checking defaults for OMX/cmex/m/n on input line 13. 174 | LaTeX Font Info: ... okay on input line 13. 175 | LaTeX Font Info: Checking defaults for U/cmr/m/n on input line 13. 176 | LaTeX Font Info: ... okay on input line 13. 177 | 178 | (/usr/share/texlive/texmf-dist/tex/context/base/mkii/supp-pdf.mkii 179 | [Loading MPS to PDF converter (version 2006.09.02).] 180 | \scratchcounter=\count98 181 | \scratchdimen=\dimen141 182 | \scratchbox=\box28 183 | \nofMPsegments=\count99 184 | \nofMParguments=\count100 185 | \everyMPshowfont=\toks20 186 | \MPscratchCnt=\count101 187 | \MPscratchDim=\dimen142 188 | \MPnumerator=\count102 189 | \makeMPintoPDFobject=\count103 190 | \everyMPtoPDFconversion=\toks21 191 | ) (/usr/share/texlive/texmf-dist/tex/latex/oberdiek/epstopdf-base.sty 192 | Package: epstopdf-base 2016/05/15 v2.6 Base part for package epstopdf 193 | 194 | (/usr/share/texlive/texmf-dist/tex/generic/oberdiek/infwarerr.sty 195 | Package: infwarerr 2016/05/16 v1.4 Providing info/warning/error messages (HO) 196 | ) 197 | (/usr/share/texlive/texmf-dist/tex/latex/oberdiek/grfext.sty 198 | Package: grfext 2016/05/16 v1.2 Manage graphics extensions (HO) 199 | 200 | (/usr/share/texlive/texmf-dist/tex/generic/oberdiek/kvdefinekeys.sty 201 | Package: kvdefinekeys 2016/05/16 v1.4 Define keys (HO) 202 | 203 | (/usr/share/texlive/texmf-dist/tex/generic/oberdiek/ltxcmds.sty 204 | Package: ltxcmds 2016/05/16 v1.23 LaTeX kernel commands for general use (HO) 205 | ))) 206 | (/usr/share/texlive/texmf-dist/tex/latex/oberdiek/kvoptions.sty 207 | Package: kvoptions 2016/05/16 v3.12 Key value format for package options (HO) 208 | 209 | (/usr/share/texlive/texmf-dist/tex/generic/oberdiek/kvsetkeys.sty 210 | Package: kvsetkeys 2016/05/16 v1.17 Key value parser (HO) 211 | 212 | (/usr/share/texlive/texmf-dist/tex/generic/oberdiek/etexcmds.sty 213 | Package: etexcmds 2016/05/16 v1.6 Avoid name clashes with e-TeX commands (HO) 214 | 215 | (/usr/share/texlive/texmf-dist/tex/generic/oberdiek/ifluatex.sty 216 | Package: ifluatex 2016/05/16 v1.4 Provides the ifluatex switch (HO) 217 | Package ifluatex Info: LuaTeX not detected. 218 | )))) 219 | (/usr/share/texlive/texmf-dist/tex/generic/oberdiek/pdftexcmds.sty 220 | Package: pdftexcmds 2018/01/30 v0.27 Utility functions of pdfTeX for LuaTeX (HO 221 | ) 222 | Package pdftexcmds Info: LuaTeX not detected. 223 | Package pdftexcmds Info: \pdf@primitive is available. 224 | Package pdftexcmds Info: \pdf@ifprimitive is available. 225 | Package pdftexcmds Info: \pdfdraftmode found. 226 | ) 227 | Package epstopdf-base Info: Redefining graphics rule for `.eps' on input line 4 228 | 38. 229 | Package grfext Info: Graphics extension search list: 230 | (grfext) [.pdf,.png,.jpg,.mps,.jpeg,.jbig2,.jb2,.PDF,.PNG,.JPG,.JPE 231 | G,.JBIG2,.JB2,.eps] 232 | (grfext) \AppendGraphicsExtensions on input line 456. 233 | 234 | (/usr/share/texlive/texmf-dist/tex/latex/latexconfig/epstopdf-sys.cfg 235 | File: epstopdf-sys.cfg 2010/07/13 v1.3 Configuration of (r)epstopdf for TeX Liv 236 | e 237 | )) 238 | *geometry* driver: auto-detecting 239 | *geometry* detected driver: pdftex 240 | *geometry* verbose mode - [ preamble ] result: 241 | * driver: pdftex 242 | * paper: letterpaper 243 | * layout: 244 | * layoutoffset:(h,v)=(0.0pt,0.0pt) 245 | * modes: 246 | * h-part:(L,W,R)=(72.26999pt, 469.75502pt, 72.26999pt) 247 | * v-part:(T,H,B)=(72.26999pt, 650.43001pt, 72.26999pt) 248 | * \paperwidth=614.295pt 249 | * \paperheight=794.96999pt 250 | * \textwidth=469.75502pt 251 | * \textheight=650.43001pt 252 | * \oddsidemargin=0.0pt 253 | * \evensidemargin=0.0pt 254 | * \topmargin=-37.0pt 255 | * \headheight=12.0pt 256 | * \headsep=25.0pt 257 | * \topskip=12.0pt 258 | * \footskip=30.0pt 259 | * \marginparwidth=44.0pt 260 | * \marginparsep=10.0pt 261 | * \columnsep=10.0pt 262 | * \skip\footins=10.8pt plus 4.0pt minus 2.0pt 263 | * \hoffset=0.0pt 264 | * \voffset=0.0pt 265 | * \mag=1000 266 | * \@twocolumnfalse 267 | * \@twosidefalse 268 | * \@mparswitchfalse 269 | * \@reversemarginfalse 270 | * (1in=72.27pt=25.4mm, 1cm=28.453pt) 271 | 272 | LaTeX Font Info: External font `cmex7' loaded for size 273 | (Font) <7> on input line 15. 274 | 275 | File: images/3SidedMarketBasicDemo.png Graphic file (type png) 276 | 277 | Package pdftex.def Info: images/3SidedMarketBasicDemo.png used on input line 2 278 | 3. 279 | (pdftex.def) Requested size: 469.75502pt x 308.06392pt. 280 | 281 | LaTeX Warning: `h' float specifier changed to `ht'. 282 | 283 | [1 284 | 285 | {/var/lib/texmf/fonts/map/pdftex/updmap/pdftex.map}] 286 | Underfull \hbox (badness 10000) in paragraph at lines 28--29 287 | 288 | [] 289 | 290 | 291 | Underfull \hbox (badness 10000) in paragraph at lines 30--32 292 | 293 | [] 294 | 295 | [2 <./images/3SidedMarketBasicDemo.png>] 296 | Package epstopdf Info: Source file: 297 | (epstopdf) date: 2019-04-02 09:08:25 298 | (epstopdf) size: 33991 bytes 299 | (epstopdf) Output file: 300 | (epstopdf) date: 2019-04-02 09:16:22 301 | (epstopdf) size: 12872 bytes 302 | (epstopdf) Command: 304 | (epstopdf) \includegraphics on input line 47. 305 | Package epstopdf Info: Output file is already uptodate. 306 | 307 | 308 | pdfTeX warning: /usr/bin/pdflatex (file ./images/components-eps-converted-to.pd 309 | f): PDF inclusion: found PDF version <1.7>, but at most version <1.5> allowed 310 | 311 | File: images/components-eps-converted-to.pdf Graphic file (type pdf) 312 | 313 | Package pdftex.def Info: images/components-eps-converted-to.pdf used on input 314 | line 47. 315 | (pdftex.def) Requested size: 469.75502pt x 156.58498pt. 316 | [3 <./images/components-eps-converted-to.pdf>] 317 | Underfull \hbox (badness 10000) in paragraph at lines 55--56 318 | 319 | [] 320 | 321 | LaTeX Font Info: External font `cmex7' loaded for size 322 | (Font) <6> on input line 61. 323 | Package epstopdf Info: Source file: 324 | (epstopdf) date: 2019-04-02 10:32:02 325 | (epstopdf) size: 106192 bytes 326 | (epstopdf) Output file: 327 | (epstopdf) date: 2019-04-02 10:32:56 328 | (epstopdf) size: 25786 bytes 329 | (epstopdf) Command: 331 | (epstopdf) \includegraphics on input line 98. 332 | Package epstopdf Info: Output file is already uptodate. 333 | 334 | 335 | pdfTeX warning: /usr/bin/pdflatex (file ./images/Results-eps-converted-to.pdf): 336 | PDF inclusion: found PDF version <1.7>, but at most version <1.5> allowed 337 | 338 | File: images/Results-eps-converted-to.pdf Graphic file (type pdf) 339 | 340 | Package pdftex.def Info: images/Results-eps-converted-to.pdf used on input lin 341 | e 98. 342 | (pdftex.def) Requested size: 469.75502pt x 469.75496pt. 343 | [4] [5 <./images/Results-eps-converted-to.pdf>] [6] (./main.aux) ) 344 | Here is how much of TeX's memory you used: 345 | 3007 strings out of 492641 346 | 47227 string characters out of 6131787 347 | 125444 words of memory out of 5000000 348 | 6841 multiletter control sequences out of 15000+600000 349 | 9399 words of font info for 34 fonts, out of 8000000 for 9000 350 | 1141 hyphenation exceptions out of 8191 351 | 41i,9n,68p,1587b,338s stack positions out of 5000i,500n,10000p,200000b,80000s 352 | 356 | Output written on main.pdf (6 pages, 107705 bytes). 357 | PDF statistics: 358 | 120 PDF objects out of 1000 (max. 8388607) 359 | 35 compressed objects within 1 object stream 360 | 0 named destinations out of 1000 (max. 500000) 361 | 16 words of extra memory for PDF output out of 10000 (max. 10000000) 362 | 363 | -------------------------------------------------------------------------------- /02 Reference Models/ThreeSidedBasic/depreciated/Latex/main.synctex.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlockScience/cadCAD-Tutorials/5ac9e99bfb66299316de4c9929fcc77fd16a23f9/02 Reference Models/ThreeSidedBasic/depreciated/Latex/main.synctex.gz -------------------------------------------------------------------------------- /02 Reference Models/ThreeSidedBasic/depreciated/Latex/main.tex: -------------------------------------------------------------------------------- 1 | \documentclass[12pt]{extarticle} 2 | \usepackage[utf8]{inputenc} 3 | % \usepackage{cite} 4 | \usepackage{graphicx} 5 | \usepackage{booktabs} 6 | \usepackage{adjustbox} 7 | \usepackage[letterpaper, margin=1in]{geometry} 8 | 9 | \title{Basic Three-Sided Market Model} 10 | \author{BlockScience} 11 | \date{April 2019} 12 | 13 | \begin{document} 14 | 15 | \maketitle 16 | 17 | 18 | \section{Introduction} 19 | The goal of this exercise is to demonstrate the value of BlockScience's approach to business networks and use of dynamical system simulations, or "Digital Twins", to provide foresight and insights to inform key decisions. The example here is of a ‘Three-Sided Market’ model which is for platform businesses where the product being produced enables transactions between a service provider and service consumer. The reference example for this case is a ride sharing app such as Uber. In this case drivers would be providers and riders would be consumers. The corporation Uber is the producer, and in our three-sided-market that role will be spread to a decentralized community collectively providing all of the functions required for users (providers and consumers) to have an equivalent user experience. We will walk through a basic dynamical system ecosystem model taking in some external variables and seeing how the system responds to these signals and evolves in order to illustrate how dynamical systems simulation modeling can be a vital ingredient to our clients' strategic planning. 20 | 21 | \begin{figure}[h] 22 | \centering 23 | \includegraphics[width=1\textwidth]{images/3SidedMarketBasicDemo.png} 24 | \caption{Basic Three-Sided Market Model} 25 | \end{figure} 26 | \newpage 27 | \section{Building a Model of a Three-Sided Market} 28 | To construct our model, we will use our internally developed simulation tool called cadCAD, a complex adaptive dynamics Computer Aided Design tool. \\ 29 | 30 | \noindent 31 | cadCAD is a differential games based simulation software package for research, validation, and Computer Aided Design of economic systems created by BlockScience. 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. \\ 32 | 33 | \noindent 34 | What that essentially means is cadCAD allows us to use code to help solidify our conceptualized ideas and run them to see how the system responds. We can then iteratively refine our work until we have constructed a model that closely reflects reality at the start of the model, embed strategic assumptions, and test different strategies to optimize the steps to take to help our clients meet their business goals. 35 | 36 | \section{Build Individual Components} 37 | Before we begin modeling, we first work with our clients to determine their business requirements and strategic goals. We use Systems Engineering Methodologies, and leverage our experienced team of Executive Advisors to refine high level ideas into actionable pieces. In order to create a holistic model that takes into account all of the components and how they interact together in our dynamic system, we first start with constructing each individual component. We leverage our collective expertise and perform research to identify the proper structure of these components. We will build two components as an example below. 38 | 39 | \subsection{Transaction Growth Rate} 40 | We construct a stochastic (random) s-shaped growth curve to represent the transaction volume of the ecosystem. See figure \ref{fig:components} 41 | 42 | \subsection{Product Cost} 43 | We create a random process to represent the growth of the cost of production, due to inflation, etc over time. See figure \ref{fig:components} 44 | \\ 45 | \begin{figure}[h] 46 | \centering 47 | \includegraphics[width=1\textwidth]{images/components.eps} 48 | \caption{Components} 49 | \label{fig:components} 50 | \end{figure} 51 | \newpage 52 | 53 | 54 | \section{cadCAD Simulation} 55 | Once we finish defining the configuration file that contains the mathematical specifications and simulation commands, examples of which are shown in the previous section, we can then run simulations. For our example here, we can look at the results at the beginning and the end of our model to see we started on 2018-01-01 and allowed our model to evolve every 30 days until 2020-12-26. We run our model 100 times, and take the mean of all of the simulations. As many of our components include random and varying factors, each simulation will run a little different from each other simulation. See the first five results at table \ref{table:FirstFive} and the last five at table \ref{table:LastFive}. \\ 56 | 57 | 58 | \begin{table}[h] 59 | \centering 60 | \begin{adjustbox}{max width=\textwidth} 61 | \begin{tabular}{lllllllllll} 62 | \toprule 63 | timestep & COGS & R\&D & fiat\_reserve & overhead\_cost & product\_cost & revenue & seed\_money & tx\_volume \\ 64 | 0 & 0 & 0 & 0 & 100 & 0.3 & 0 & 0 & 100 \\ 65 | 1 & 6.34138 & 0 & 60068.01 & 100 & 0.24 & 108.01 & 100000 & 135.01 \\ 66 | 2 & 32.560 & 0 & 100139.18 & 100 & 0.20 & 171.18 & 100000 & 180.2203 \\ 67 | 3 & 38.09 & 0 & 100267.71 & 100 & 0.19 & 228.53 & 100000 & 240.61 \\ 68 | 4 & 48.75 & 0 & 100465.04 & 100 & 0.19 & 297.33 & 100000 & 311.50 69 | \end{tabular} 70 | \end{adjustbox} 71 | \caption{First five time steps of the Monte Carlo Run} 72 | \label{table:FirstFive} 73 | \end{table} 74 | 75 | \begin{table}[h] 76 | \centering 77 | \begin{adjustbox}{max width=\textwidth} 78 | \begin{tabular}{lllllllllll} 79 | \toprule 80 | timestep & COGS & R\&D & fiat\_reserve & overhead\_cost & product\_cost & revenue & seed\_money & tx\_volume \\ 81 | 32 & 15103.09 & 1000 & 1029399.17 & 10100 & 0.17 & 90679.09 & 200000 & 91242.08 \\ 82 | 33 & 15701.94 & 1000 & 1112510.76 & 10100 & 0.19 & 93211.59 & 200000 & 93703.97 \\ 83 | 34 & 17344.59 & 2000 & 1197496.01 & 10100 & 0.177 & 95085.26 & 200000 & 95430.58 \\ 84 | 35 & 16565.27 & 2000 & 1284050.85 & 10100 & 0.1599 & 96654.83 & 200000 & 96960.90 \\ 85 | 36 & 15484.41 & 2000 & 1371673.12 & 10100 & 0.16 & 97722.27 & 200000 & 97912.61 86 | \end{tabular} 87 | \end{adjustbox} 88 | \caption{Last five time steps of the Monte Carlo Run} 89 | \label{table:LastFive} 90 | \end{table} 91 | \noindent 92 | 93 | 94 | We plotted the results of the simulation below in figure \ref{fig:results}. We can see that the Fiat Reserve stayed modest and mostly flat as the company was starting up, with the investor seed money keeping the company afloat. But as transactions and revenue began to expand, we can see tracked performance metrics began to increase. As the company begins, we can see a low value of overhead costs, but it slowly ramps up overtime as the company matures, rents office space, hires more employees, etc. Cost of Goods Sold (COGS) starts off very low, but accelerates over time, as a result of the increased volume. Revenue is similar to COGS, but a smoother curve as the price of \$1 stays constant through the 36 month simulation. Transaction volume per month, as it is an exogenous (external to the system) process, it follows the same s-shaped curve we built as an individual component above. It is used to drive the rest of the model (the transaction volume can be modeled as well, but for this example we kept it simple.) We then look at the transaction Product Cost, which decreases after economies of scale are developed. Research and Development per month starts as zero and increases every 17 months by 1,000 per month. Finally, Gross Margin and EBITDA per month, show how we can layer on top of our modeling common business metrics. The sky is really the limit on what we can do with our simulations, as we can use existing design patterns we have internally developed, or build individual components from scratch to maximize accuracy for our clients. 95 | 96 | \begin{figure}[h] 97 | \centering 98 | \includegraphics[width=1\textwidth]{images/Results.eps} 99 | \caption{Results} 100 | \label{fig:results} 101 | \end{figure} 102 | 103 | \section{Conclusion} 104 | We have walked through a basic dynamical system ecosystem model taking in some external variables and seeing how the system responds to these signals and evolves. We observe that the policy and pricing incentives built into the model represent a successful business model. BlockScience goes in depth into each component, using cross functional teams of researchers to create novel solutions for our clients. What makes our modeling approach so powerful is that we can do A/B testing, or in other words, try slightly different policies and see how the system interacts and how the outputs we are concerned about respond. It is an extremely effective mechanism for making business decisions. Our methodologies, along with the cadCAD tool, enable us to help companies optimize their existing business models, mitigate risks, and help launch new companies or lines of business with the confidence of engineered and rigorously tested solutions. 105 | \end{document} 106 | 107 | 108 | -------------------------------------------------------------------------------- /02 Reference Models/ThreeSidedBasic/depreciated/cadCadFunctions.py: -------------------------------------------------------------------------------- 1 | ''' 2 | cadCAD helper functions. 3 | Individual functions developed by Michael Zargham, Matthew Barlin, and Andrew Clark. 4 | ''' 5 | 6 | # import libraries 7 | import pandas as pd 8 | import numpy as np 9 | import matplotlib.pyplot as plt 10 | 11 | def aggregate_runs(df,aggregate_dimension): 12 | ''' 13 | Function to aggregate the monte carlo runs along a single dimension. 14 | 15 | Parameters: 16 | df: dataframe name 17 | aggregate_dimension: the dimension you would like to aggregate on, the standard one is timestep. 18 | 19 | Example run: 20 | mean_df,median_df,std_df,min_df = aggregate_runs(df,'timestep') 21 | ''' 22 | aggregate_dimension = aggregate_dimension 23 | 24 | mean_df = df.groupby(aggregate_dimension).mean().reset_index() 25 | median_df = df.groupby(aggregate_dimension).median().reset_index() 26 | std_df = df.groupby(aggregate_dimension).std().reset_index() 27 | min_df = df.groupby(aggregate_dimension).min().reset_index() 28 | 29 | return mean_df,median_df,std_df,min_df 30 | 31 | def plot_averaged_runs(df,aggregate_dimension,x, y,run_count,lx=False,ly=False, suppMin=False): 32 | ''' 33 | Function to plot the mean, median, etc of the monte carlo runs along a single variable. 34 | 35 | Parameters: 36 | df: dataframe name 37 | aggregate_dimension: the dimension you would like to aggregate on, the standard one is timestep. 38 | x = x axis variable for plotting 39 | y = y axis variable for plotting 40 | run_count = the number of monte carlo simulations 41 | lx = True/False for if the x axis should be logged 42 | ly = True/False for if the x axis should be logged 43 | suppMin: True/False for if the miniumum value should be plotted 44 | 45 | Note: Run aggregate_runs before using this function 46 | 47 | Example run: 48 | plot_averaged_runs('timestep', 'revenue',100, suppMin=True) 49 | 50 | ''' 51 | mean_df,median_df,std_df,min_df = aggregate_runs(df,aggregate_dimension) 52 | 53 | plt.figure(figsize=(10,6)) 54 | if not(suppMin): 55 | plt.plot(mean_df[x].values, mean_df[y].values, 56 | mean_df[x].values,median_df[y].values, 57 | mean_df[x].values,mean_df[y].values+std_df[y].values, 58 | mean_df[x].values,min_df[y].values) 59 | plt.legend(['mean', 'median', 'mean+ 1*std', 'min'],bbox_to_anchor=(1.05, 1), loc=2, borderaxespad=0.) 60 | 61 | else: 62 | plt.plot(mean_df[x].values, mean_df[y].values, 63 | mean_df[x].values,median_df[y].values, 64 | mean_df[x].values,mean_df[y].values+std_df[y].values, 65 | mean_df[x].values,mean_df[y].values-std_df[y].values) 66 | plt.legend(['mean', 'median', 'mean+ 1*std', 'mean - 1*std'],bbox_to_anchor=(1.05, 1), loc=2, borderaxespad=0.) 67 | 68 | plt.xlabel(x) 69 | plt.ylabel(y) 70 | title_text = 'Performance of ' + y + ' over all of ' + str(run_count) + ' Monte Carlo runs' 71 | plt.title(title_text) 72 | if lx: 73 | plt.xscale('log') 74 | 75 | if ly: 76 | plt.yscale('log') 77 | 78 | 79 | def first_five_plot(df,aggregate_dimension,x,y,run_count): 80 | ''' 81 | A function that generates timeseries plot of at most the first five Monte Carlo runs. 82 | 83 | Parameters: 84 | df: dataframe name 85 | aggregate_dimension: the dimension you would like to aggregate on, the standard one is timestep. 86 | x = x axis variable for plotting 87 | y = y axis variable for plotting 88 | run_count = the number of monte carlo simulations 89 | 90 | Note: Run aggregate_runs before using this function 91 | Example run: 92 | first_five_plot(df,'revenue',100) 93 | ''' 94 | mean_df,median_df,std_df,min_df = aggregate_runs(df,aggregate_dimension) 95 | plt.figure(figsize=(10,6)) 96 | if run_count < 5: 97 | runs = run_count 98 | else: 99 | runs = 5 100 | for r in range(1,runs+1): 101 | legend_name = 'Run ' + str(r) 102 | plt.plot(df[df.run==r].timestep, df[df.run==r][y], label = legend_name ) 103 | plt.plot(mean_df[x], mean_df[y], label = 'Mean', color = 'black') 104 | plt.legend(bbox_to_anchor=(1.05, 1), loc=2, borderaxespad=0.) 105 | plt.xlabel(x) 106 | plt.ylabel(y) 107 | title_text = 'Performance of ' + y + ' over the First ' + str(runs) + ' Monte Carlo Runs' 108 | plt.title(title_text) 109 | -------------------------------------------------------------------------------- /02 Reference Models/ThreeSidedBasic/images/3SidedMarketBasicDemo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlockScience/cadCAD-Tutorials/5ac9e99bfb66299316de4c9929fcc77fd16a23f9/02 Reference Models/ThreeSidedBasic/images/3SidedMarketBasicDemo.png -------------------------------------------------------------------------------- /02 Reference Models/ThreeSidedBasic/images/productCost.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlockScience/cadCAD-Tutorials/5ac9e99bfb66299316de4c9929fcc77fd16a23f9/02 Reference Models/ThreeSidedBasic/images/productCost.png -------------------------------------------------------------------------------- /02 Reference Models/ThreeSidedBasic/model/config.py: -------------------------------------------------------------------------------- 1 | import math 2 | from decimal import Decimal 3 | from datetime import timedelta 4 | import numpy as np 5 | from typing import Dict, List 6 | 7 | from cadCAD.configuration import Experiment 8 | from cadCAD.configuration.utils import bound_norm_random, ep_time_step, config_sim, access_block 9 | from copy import deepcopy 10 | from cadCAD import configs 11 | from .state_variables import state_variables 12 | from .partial_state_update_block import partial_state_update_blocks 13 | from .parts.sys_params import * 14 | 15 | 16 | sim_config = config_sim({ 17 | 'T': range(36), #day 18 | 'N': 100, 19 | 'M': params, 20 | }) 21 | 22 | seeds = { 23 | 'a': np.random.RandomState(2), 24 | } 25 | 26 | exp = Experiment() 27 | 28 | exp.append_configs( 29 | sim_configs=sim_config, 30 | initial_state=state_variables, 31 | seeds=seeds, 32 | partial_state_update_blocks=partial_state_update_blocks 33 | ) 34 | 35 | 36 | def get_configs(): 37 | ''' 38 | Function to extract the configuration information for display in a notebook. 39 | ''' 40 | 41 | 42 | return sim_config,state_variables,partial_state_update_blocks 43 | -------------------------------------------------------------------------------- /02 Reference Models/ThreeSidedBasic/model/partial_state_update_block.py: -------------------------------------------------------------------------------- 1 | from .parts.exogenous import * 2 | from .parts.flows import * 3 | from .parts.investors import * 4 | from .parts.kpis import * 5 | 6 | 7 | # The Partial State Update Blocks 8 | partial_state_update_blocks = [ 9 | # exogenous.py: 10 | { 11 | 'policies': 12 | { 13 | }, 14 | 'variables': 15 | { 16 | 'tx_volume': tx_volume_generator, 17 | 'product_cost': product_cost_generator, 18 | 'seed_money': investors_generator, 19 | 'overhead_cost': update_overhead_costs, 20 | 'R&D': R_and_D 21 | } 22 | 23 | }, 24 | # flows.py: 25 | { 26 | 'policies': 27 | { 28 | 'action': inflow 29 | }, 30 | 'variables': 31 | { 32 | 'fiat_reserve': receive_fiat_from_consumers, 33 | 'revenue': receive_revenue_from_consumers 34 | } 35 | }, 36 | 37 | #investors.py: 38 | { 39 | 'policies': 40 | { 41 | 'action': investors 42 | }, 43 | 'variables': 44 | { 45 | 'seed_money': receive_fiat_from_investors 46 | } 47 | }, 48 | #fiat.py: 49 | { 50 | 'policies': 51 | { 52 | 'action': outflow 53 | }, 54 | 'variables': 55 | { 56 | 'fiat_reserve': pay_fiat_to_producers, 57 | 'fiat_reserve': pay_investment_expenses, 58 | 'fiat_reserve': pay_overhead_costs 59 | } 60 | }, 61 | #kpis.py: 62 | { 63 | 'policies': 64 | { 65 | 'action': kpis 66 | }, 67 | 'variables': 68 | { 69 | 'COGS': COGS 70 | } 71 | }, 72 | 73 | ] 74 | 75 | 76 | -------------------------------------------------------------------------------- /02 Reference Models/ThreeSidedBasic/model/parts/exogenous.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | 3 | 4 | # Exogenous Mechanisms 5 | def tx_volume_generator(params, step, sL, s, _input): 6 | y = 'tx_volume' 7 | x = s['tx_volume']*(1+2*params['eta']*np.random.rand()*(1-s['tx_volume']/params['tampw'])) 8 | return (y, x) 9 | 10 | def product_cost_generator(params, step, sL, s, _input): 11 | y = 'product_cost' 12 | x = params['alpha']*s['product_cost']+params['beta']*np.random.rand() - params['costDecrease'] 13 | return (y, x) 14 | 15 | def investors_generator(params, step, sL, s, _input): 16 | y = 'seed_money' 17 | if s['timestep'] == 1: 18 | x = s['seed_money'] + params['vcRoundFunding'] 19 | elif s['timestep'] == 10: 20 | x = s['seed_money'] + params['vcRoundFunding'] 21 | else: 22 | x = s['seed_money'] + 0 23 | return (y, x) 24 | 25 | def update_overhead_costs(params, step, sL, s, _input): 26 | # Create step function for updating overhead costs 27 | y = 'overhead_cost' 28 | if s['timestep']%15 == 0: 29 | x = s['overhead_cost'] + params['overHeadCosts'] 30 | else: 31 | x = s['overhead_cost'] + 0 32 | return (y, x) 33 | 34 | def R_and_D(params, step, sL, s, _input): 35 | y = 'R&D' 36 | if s['timestep']%17 == 0: 37 | x = s['R&D'] + 1000 38 | else: 39 | x = s['R&D'] + 0 40 | return (y, x) 41 | 42 | -------------------------------------------------------------------------------- /02 Reference Models/ThreeSidedBasic/model/parts/flows.py: -------------------------------------------------------------------------------- 1 | 2 | 3 | # Behaviors 4 | def inflow(params, step, history, current_state): 5 | # Receive money from relevant parties 6 | return {'Receive': 1} 7 | 8 | def outflow(params, step, history, current_state): 9 | # Pay relevant parties 10 | return {'Pay': 1} 11 | 12 | 13 | # Mechanisms 14 | def receive_fiat_from_consumers(params, step, sL, s, _input): 15 | y = 'fiat_reserve' 16 | if _input['Receive'] == 1: 17 | x = s['fiat_reserve'] + s['tx_volume'] * params['price'] 18 | else: 19 | x = s['fiat_reserve'] 20 | return (y, x) 21 | 22 | def receive_revenue_from_consumers(params, step, sL, s, _input): 23 | y = 'revenue' 24 | if _input['Receive'] == 1: 25 | x = s['tx_volume'] * params['price'] 26 | else: 27 | x = s['revenue'] 28 | return (y, x) 29 | 30 | def pay_fiat_to_producers(params, step, sL, s, _input): 31 | y = 'fiat_reserve' 32 | if _input['Pay'] == 1: 33 | x = s['fiat_reserve'] - (s['product_cost'] * s['tx_volume']) 34 | x = s['fiat_reserve'] 35 | return (y, x) 36 | 37 | def pay_investment_expenses(params, step, sL, s, _input): 38 | y = 'fiat_reserve' 39 | if _input['Pay'] == 1: 40 | x = s['fiat_reserve'] - s['R&D'] 41 | else: 42 | x = s['fiat_reserve'] 43 | return (y, x) 44 | 45 | def pay_overhead_costs(params, step, sL, s, _input): 46 | y = 'fiat_reserve' 47 | if _input['Pay'] == 1: 48 | x = s['fiat_reserve'] - s['overhead_cost'] 49 | else: 50 | x = s['fiat_reserve'] 51 | return (y, x) 52 | 53 | 54 | -------------------------------------------------------------------------------- /02 Reference Models/ThreeSidedBasic/model/parts/investors.py: -------------------------------------------------------------------------------- 1 | 2 | 3 | # Behaviors 4 | def investors(params, step, history, current_state): 5 | # Pay relevant parties 6 | if current_state['timestep'] == 1: 7 | return {'Invest': 1} 8 | elif current_state['timestep'] == 10: 9 | return {'Invest': 1} 10 | else: 11 | return {'Invest': 0} 12 | 13 | 14 | # Mechanisms 15 | def receive_fiat_from_investors(params, step, sL, s, _input): 16 | y = 'fiat_reserve' 17 | if _input['Invest'] == 1: 18 | x = s['fiat_reserve'] + s['seed_money'] 19 | else: 20 | x = s['fiat_reserve'] 21 | return (y, x) 22 | 23 | -------------------------------------------------------------------------------- /02 Reference Models/ThreeSidedBasic/model/parts/kpis.py: -------------------------------------------------------------------------------- 1 | # Behaviors 2 | def kpis(params, step, history, current_state): 3 | return {'Stat': 1} 4 | 5 | 6 | 7 | # Mechanisms 8 | def COGS(params, step, sL, s, _input): 9 | y = 'COGS' 10 | if _input['Stat'] == 1: 11 | x = (s['product_cost'] * s['tx_volume']) 12 | else: 13 | x = s['COGS'] 14 | return (y, x) 15 | 16 | -------------------------------------------------------------------------------- /02 Reference Models/ThreeSidedBasic/model/parts/sys_params.py: -------------------------------------------------------------------------------- 1 | 2 | 3 | # params 4 | params = { 5 | 'eta': [.33], # for tx_volume_generator 6 | 'tampw': [100000], # transactions limit 7 | 'alpha': [.5], # for data acquisition cost generator 8 | 'beta': [.2], # for data acquisition cost generator 9 | 'costDecrease': [.015], # decrease in cost 10 | 'price': [1], # sales price 11 | 'vcRoundFunding': [100000.0], 12 | 'overHeadCosts': [5000.0] 13 | } 14 | 15 | 16 | 17 | # Initial States 18 | initial_values = { 19 | 'tx_volume': float(100), #unit: fiat 20 | 'product_cost': float(.3), #unit: fiat cost 21 | 'revenue': float(0), # revenue per month 22 | 'fiat_reserve': float(0),#unit: fiat 23 | 'overhead_cost': float(100), #unit: fiat per month 24 | 'seed_money': float(0), 25 | 'R&D': float(0), #per month 26 | 'COGS': float(0), #per month 27 | } 28 | -------------------------------------------------------------------------------- /02 Reference Models/ThreeSidedBasic/model/parts/utils.py: -------------------------------------------------------------------------------- 1 | # import libraries 2 | import pandas as pd 3 | import numpy as np 4 | import matplotlib.pyplot as plt 5 | 6 | 7 | ##### Utils 8 | def aggregate_runs(df,aggregate_dimension): 9 | ''' 10 | Function to aggregate the monte carlo runs along a single dimension. 11 | 12 | Parameters: 13 | df: dataframe name 14 | aggregate_dimension: the dimension you would like to aggregate on, the standard one is timestep. 15 | 16 | Example run: 17 | mean_df,median_df,std_df,min_df = aggregate_runs(df,'timestep') 18 | ''' 19 | aggregate_dimension = aggregate_dimension 20 | 21 | mean_df = df.groupby(aggregate_dimension).mean().reset_index() 22 | median_df = df.groupby(aggregate_dimension).median().reset_index() 23 | std_df = df.groupby(aggregate_dimension).std().reset_index() 24 | min_df = df.groupby(aggregate_dimension).min().reset_index() 25 | 26 | return mean_df,median_df,std_df,min_df -------------------------------------------------------------------------------- /02 Reference Models/ThreeSidedBasic/model/run.py: -------------------------------------------------------------------------------- 1 | import pandas as pd 2 | from .parts.utils import * 3 | from model import config 4 | from cadCAD.engine import ExecutionMode, ExecutionContext,Executor 5 | from cadCAD import configs 6 | 7 | def run(): 8 | ''' 9 | Definition: 10 | Run simulation 11 | ''' 12 | exec_mode = ExecutionMode() 13 | local_mode_ctx = ExecutionContext(context=exec_mode.local_mode) 14 | 15 | simulation = Executor(exec_context=local_mode_ctx, configs=configs) 16 | raw_system_events, tensor_field, sessions = simulation.execute() 17 | # Result System Events DataFrame 18 | df = pd.DataFrame(raw_system_events) 19 | return df 20 | 21 | 22 | -------------------------------------------------------------------------------- /02 Reference Models/ThreeSidedBasic/model/state_variables.py: -------------------------------------------------------------------------------- 1 | from .parts.sys_params import * 2 | 3 | # Initial States 4 | state_variables = { 5 | 'tx_volume': initial_values['tx_volume'], #unit: fiat 6 | 'product_cost': initial_values['product_cost'], #unit: fiat cost 7 | 'revenue': initial_values['revenue'], # revenue per month 8 | 'fiat_reserve': initial_values['fiat_reserve'],#unit: fiat 9 | 'overhead_cost': initial_values['overhead_cost'], #unit: fiat per month 10 | 'seed_money': initial_values['seed_money'], 11 | 'R&D': initial_values['R&D'], #per month 12 | 'COGS': initial_values['COGS'] #per month 13 | } 14 | 15 | -------------------------------------------------------------------------------- /02 Reference Models/Verifiers-Dilemma/Dilemma.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlockScience/cadCAD-Tutorials/5ac9e99bfb66299316de4c9929fcc77fd16a23f9/02 Reference Models/Verifiers-Dilemma/Dilemma.jpeg -------------------------------------------------------------------------------- /02 Reference Models/Verifiers-Dilemma/feedback.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlockScience/cadCAD-Tutorials/5ac9e99bfb66299316de4c9929fcc77fd16a23f9/02 Reference Models/Verifiers-Dilemma/feedback.jpeg -------------------------------------------------------------------------------- /02 Reference Models/Viral-Marketing-SIR/SIR.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlockScience/cadCAD-Tutorials/5ac9e99bfb66299316de4c9929fcc77fd16a23f9/02 Reference Models/Viral-Marketing-SIR/SIR.jpeg -------------------------------------------------------------------------------- /02 Reference Models/Viral-Marketing-SIR/SIR0.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlockScience/cadCAD-Tutorials/5ac9e99bfb66299316de4c9929fcc77fd16a23f9/02 Reference Models/Viral-Marketing-SIR/SIR0.jpeg -------------------------------------------------------------------------------- /02 Reference Models/sourcecred/graph_generators.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | """ 4 | Created on Sun Mar 17 13:00:33 2019 5 | 6 | @author: Zargham 7 | """ 8 | import networkx as nx 9 | 10 | def lineGraphGen(N, bidir=False,nodeTypeName='vanilla',edgeTypeName='vanilla'): 11 | 12 | line = nx.path_graph(N, create_using=nx.MultiDiGraph) 13 | if not(bidir): 14 | G = line 15 | else: 16 | edges = line.edges 17 | G = nx.MultiDiGraph() 18 | for e in edges: 19 | G.add_edge(e[0],e[1]) 20 | G.add_edge(e[1],e[0]) 21 | 22 | nx.set_node_attributes(G,nodeTypeName, 'type') 23 | nx.set_edge_attributes(G,edgeTypeName, 'type') 24 | 25 | return G 26 | 27 | def starGraphGen(N, kind='sink',nodeTypeName='vanilla',edgeTypeName='vanilla'): 28 | 29 | star = nx.star_graph(N) 30 | G = nx.MultiDiGraph() 31 | 32 | for e in star.edges: 33 | if (kind == 'source') or (kind == 'bidir'): 34 | G.add_edge(e[0],e[1]) 35 | if (kind == 'sink') or (kind == 'bidir'): 36 | G.add_edge(e[1],e[0]) 37 | 38 | nx.set_node_attributes(G,nodeTypeName, 'type') 39 | nx.set_edge_attributes(G,edgeTypeName, 'type') 40 | 41 | return G 42 | 43 | def circleGraphGen(N, bidir=False,nodeTypeName='vanilla',edgeTypeName='vanilla' ): 44 | 45 | circle = nx.cycle_graph(N, create_using=nx.MultiDiGraph) 46 | if not(bidir): 47 | G = circle 48 | else: 49 | edges = circle.edges 50 | G = nx.MultiDiGraph() 51 | for e in edges: 52 | G.add_edge(e[0],e[1]) 53 | G.add_edge(e[1],e[0]) 54 | 55 | nx.set_node_attributes(G,nodeTypeName, 'type') 56 | nx.set_edge_attributes(G,edgeTypeName, 'type') 57 | 58 | return G 59 | 60 | def treeGraphGen(r,h, kind='sink',nodeTypeName='vanilla',edgeTypeName='vanilla'): 61 | 62 | tree = nx.balanced_tree(r,h, create_using=nx.MultiDiGraph) 63 | 64 | if kind=='source': 65 | G = tree 66 | elif kind =='sink': 67 | G = nx.MultiDiGraph() 68 | for e in tree.edges: 69 | G.add_edge(e[1],e[0]) 70 | elif kind == 'bidir': 71 | G = nx.MultiDiGraph() 72 | for e in tree.edges: 73 | G.add_edge(e[1],e[0]) 74 | G.add_edge(e[0],e[1]) 75 | 76 | nx.set_node_attributes(G,nodeTypeName, 'type') 77 | nx.set_edge_attributes(G,edgeTypeName, 'type') 78 | 79 | return G -------------------------------------------------------------------------------- /02 Reference Models/sourcecred/import_graph.py: -------------------------------------------------------------------------------- 1 | from __future__ import absolute_import 2 | from __future__ import division 3 | from __future__ import print_function 4 | 5 | import networkx as nx 6 | import collections 7 | 8 | AddressType = collections.namedtuple("AddressType", ("prefix", "type")) 9 | 10 | 11 | def _type_prefix_match(address_types, address): 12 | """For a given address, find the type matching the address. 13 | 14 | Takes an object containing an array of {prefix, type} pairs, and 15 | an address. Returns the first type whose corresponding prefix 16 | was a prefix of the given address. 17 | """ 18 | for address_type in address_types: 19 | prefix = address_type.prefix 20 | if address[: len(prefix)] == prefix: 21 | return address_type.type 22 | raise ValueError("No matching prefix for {}".format(address)) 23 | 24 | 25 | def node_type(address): 26 | """Return a string that identifies the "type" of a SourceCred node. 27 | 28 | For any anticipated SourceCred node (i.e., it was supplied by one of the two 29 | standard SourceCred plugins, i.e., sourcecred/git and sourcecred/github), 30 | this method returns a string which identifies the most specific declared 31 | node_type that matches the given node. 32 | 33 | The SourceCred type system is still pretty ad-hoc, 34 | (see: https://github.com/sourcecred/sourcecred/issues/710), so this system is 35 | likely to change in the future. 36 | """ 37 | NODE_PREFIX_TO_TYPE = [ 38 | AddressType(prefix=["sourcecred", "github", "REPO"], type="github/repo"), 39 | AddressType( 40 | prefix=["sourcecred", "github", "USERLIKE", "USER"], type="github/user" 41 | ), 42 | AddressType( 43 | prefix=["sourcecred", "github", "USERLIKE", "BOT"], type="github/bot" 44 | ), 45 | AddressType(prefix=["sourcecred", "github", "PULL"], type="github/pull"), 46 | AddressType(prefix=["sourcecred", "github", "ISSUE"], type="github/issue"), 47 | AddressType(prefix=["sourcecred", "github", "REVIEW"], type="github/review"), 48 | AddressType(prefix=["sourcecred", "github", "COMMENT"], type="github/comment"), 49 | AddressType(prefix=["sourcecred", "git", "COMMIT"], type="git/commit"), 50 | ] 51 | return _type_prefix_match(NODE_PREFIX_TO_TYPE, address) 52 | 53 | 54 | def edge_type(address): 55 | """Return a string that identifies the "type" of a SourceCred edge. 56 | 57 | For any anticipated SourceCred edge (i.e., it was supplied by one of the two 58 | standard SourceCred plugins, i.e., sourcecred/git and sourcecred/github), 59 | this method returns a string which identifies the most specific declared 60 | edge_type that matches the given node. 61 | 62 | The SourceCred type system is still pretty ad-hoc, 63 | (see: https://github.com/sourcecred/sourcecred/issues/710), so this system is 64 | likely to change in the future. 65 | """ 66 | EDGE_PREFIX_TO_TYPE = [ 67 | AddressType( 68 | prefix=["sourcecred", "github", "HAS_PARENT"], type="github/hasParent" 69 | ), 70 | AddressType( 71 | prefix=["sourcecred", "github", "REFERENCES"], type="github/references" 72 | ), 73 | AddressType( 74 | prefix=["sourcecred", "github", "MENTIONS_AUTHOR"], 75 | type="github/mentionsAuthor", 76 | ), 77 | AddressType(prefix=["sourcecred", "github", "AUTHORS"], type="github/authors"), 78 | AddressType(prefix=["sourcecred", "github", "PULL"], type="github/pull"), 79 | AddressType(prefix=["sourcecred", "github", "ISSUE"], type="github/issue"), 80 | AddressType(prefix=["sourcecred", "github", "REVIEW"], type="github/review"), 81 | AddressType(prefix=["sourcecred", "github", "COMMENT"], type="github/comment"), 82 | AddressType( 83 | prefix=["sourcecred", "github", "MERGED_AS"], type="github/mergedAs" 84 | ), 85 | AddressType( 86 | prefix=["sourcecred", "github", "REACTS", "HOORAY"], 87 | type="github/reactsHooray", 88 | ), 89 | AddressType( 90 | prefix=["sourcecred", "github", "REACTS", "THUMBS_UP"], 91 | type="github/reactsThumbsUp", 92 | ), 93 | AddressType( 94 | prefix=["sourcecred", "github", "REACTS", "HEART"], 95 | type="github/reactsHeart", 96 | ), 97 | AddressType( 98 | prefix=["sourcecred", "github", "REACTS", "ROCKET"], 99 | type="github/reactsRocket", 100 | ), 101 | AddressType(prefix=["sourcecred", "git", "HAS_PARENT"], type="git/hasParent"), 102 | ] 103 | return _type_prefix_match(EDGE_PREFIX_TO_TYPE, address) 104 | 105 | 106 | def json_to_graph(json): 107 | """Convert a serialized SourceCred graph to a MultiDiGraph. 108 | 109 | Takes in a Python dict representing a SourceCred graph json. 110 | Returns a networkx MultiDiGraph, with node and edge type identifiers 111 | added as an additional property. 112 | """ 113 | [compat, data] = json 114 | assert compat["type"] == "sourcecred/graph", compat 115 | assert compat["version"] == "0.4.0", compat 116 | 117 | def nodePropertyDict(address): 118 | return {"address": tuple(address), "type": node_type(address)} 119 | 120 | def edgePropertyDict(address): 121 | return {"address": tuple(address), "type": edge_type(address)} 122 | 123 | nodes = data["nodes"] 124 | edges = data["edges"] 125 | g = nx.MultiDiGraph() 126 | for (i, n) in enumerate(nodes): 127 | g.add_node(i, **nodePropertyDict(n)) 128 | for e in edges: 129 | g.add_edge(e["srcIndex"], e["dstIndex"], **edgePropertyDict(e["address"])) 130 | return g 131 | -------------------------------------------------------------------------------- /02 Reference Models/sourcecred/inspect_subgraph.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | """ 4 | Created on Wed Mar 13 07:58:28 2019 5 | 6 | @author: Zargham 7 | """ 8 | import networkx as nx 9 | import numpy as np 10 | import matplotlib.pyplot as plt 11 | 12 | 13 | def getNodeAttributeUniques(g, attr): 14 | print(type(attr)) 15 | return set(nx.get_node_attributes(g, attr).values()) 16 | 17 | 18 | def make_colors(g): 19 | 20 | node_types = set(nx.get_node_attributes(g, "type").values()) 21 | 22 | cmap = plt.cm.jet 23 | Nc = cmap.N 24 | Nt = len(node_types) 25 | dN = int(Nc / Nt) 26 | cmaplist = [cmap(i * dN) for i in range(Nt)] 27 | 28 | colors = {} 29 | bunches = {} 30 | 31 | counter = 0 32 | for nt in node_types: 33 | bunches[nt] = [x for x, y in g.nodes(data=True) if y["type"] == nt] 34 | colors[nt] = cmaplist[counter] 35 | counter = counter + 1 36 | 37 | return colors 38 | 39 | 40 | def inspectSubGraph(g, bunch, expand=True, verbose=False, label=True, pos="kk"): 41 | 42 | nbunch = bunch 43 | if expand: 44 | for s in bunch: 45 | nbunch = list(nx.all_neighbors(g, s)) + nbunch 46 | 47 | # print(nbunch) 48 | sg = nx.subgraph(g, set(nbunch)) 49 | colors = make_colors(sg) 50 | 51 | # sgs = nx.get_node_attributes(sg,'shape') 52 | # print(sgc) 53 | # nx.draw_kamada_kawai(sg, node_color =sgc, node_shape=sgs , alpha=.5) 54 | 55 | for x, y in sg.nodes(data=True): 56 | sg.nodes[x]["color"] = colors[y["type"]] 57 | if y["type"] == "vanilla": 58 | sg.nodes[x]["label"] = x 59 | 60 | elif (y["type"] == "github/repo") or (y["type"] == "github/user"): 61 | sg.nodes[x]["label"] = y["address"][4] 62 | 63 | else: 64 | sg.nodes[x]["label"] = y["type"].split("/")[-1] 65 | 66 | if verbose: 67 | print("nodes") 68 | for n in sg.nodes: 69 | print(n) 70 | print(sg.nodes[n]) 71 | 72 | print("") 73 | print("edges") 74 | for e in sg.edges: 75 | print(e) 76 | print(sg.edges[e]) 77 | 78 | labels = None 79 | if label: 80 | labels = nx.get_node_attributes(sg, "label") 81 | 82 | # print(sgc) 83 | sgc = np.array(list(nx.get_node_attributes(sg, "color").values())) 84 | 85 | if pos == "kk": 86 | nx.draw_kamada_kawai( 87 | sg, 88 | node_color=sgc, 89 | node_shape=".", 90 | alpha=0.5, 91 | labels=labels, 92 | font_size=8, 93 | figsize=(20, 10), 94 | ) 95 | elif pos == "spring": 96 | nx.draw_spring( 97 | sg, 98 | node_color=sgc, 99 | node_shape=".", 100 | alpha=0.5, 101 | labels=labels, 102 | font_size=8, 103 | figsize=(20, 10), 104 | ) 105 | elif pos == "spectral": 106 | nx.draw_spectral( 107 | sg, 108 | node_color=sgc, 109 | node_shape=".", 110 | alpha=0.5, 111 | labels=labels, 112 | font_size=8, 113 | figsize=(20, 10), 114 | ) 115 | else: 116 | nx.draw_circular( 117 | sg, 118 | node_color=sgc, 119 | node_shape=".", 120 | alpha=0.5, 121 | labels=labels, 122 | font_size=8, 123 | figsize=(20, 10), 124 | ) 125 | 126 | return sg.copy() 127 | -------------------------------------------------------------------------------- /02 Reference Models/sourcecred/page_ranker.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | """ 4 | Created on Thu Mar 14 20:43:21 2019 5 | 6 | @author: Zargham 7 | """ 8 | 9 | import networkx as nx 10 | import pandas as pd 11 | import numpy as np 12 | 13 | #defaults 14 | default_self_loop_wt= .001 15 | 16 | def update_score(g,alpha,seed, lazy=False, lazy_wt = .5): 17 | 18 | #lazy random walk assumes a topology independent 1/2 wt on self-loops 19 | lazy_wt = lazy_wt*float(lazy) 20 | 21 | prior_x = nx.get_node_attributes(g,'score') 22 | for n in g.nodes: 23 | self_wt = g.nodes[n]['self_wt']/g.nodes[n]['total_wt'] 24 | 25 | val = (1-alpha)*self_wt*prior_x[n] + alpha*seed[n] 26 | for nb in g.nodes[n]['out_nbr']: 27 | #outbound neighbor 28 | e_count = edge_count(g, n,nb) 29 | for e3 in range(e_count): 30 | wt = g.edges[(n,nb,e3)]['out_weight']/g.nodes[nb]['total_wt'] 31 | val = val + (1-alpha)*wt*prior_x[nb] 32 | 33 | for nb in g.nodes[n]['in_nbr']: 34 | #inbound neighbor 35 | e_count = edge_count(g, nb,n) 36 | for e3 in range(e_count): 37 | wt = g.edges[(nb,n,e3)]['in_weight']/g.nodes[nb]['total_wt'] 38 | val = val + (1-alpha)*wt*prior_x[nb] 39 | 40 | #print(val) 41 | 42 | g.nodes[n]['score']= lazy_wt*prior_x[n]+(1-lazy_wt)*val 43 | 44 | return g 45 | 46 | #helper function 47 | def edge_count(g,src,dst): 48 | i =0 49 | stop = False 50 | while not(stop): 51 | try: 52 | g.edges[(src,dst,i)] 53 | i=i+1 54 | except: 55 | stop = True 56 | return i 57 | 58 | #tuples are (to_weight, from_weight) 59 | default_edge_wt_by_type = { 60 | 'github/authors': (0.5,1), 61 | 'github/hasParent':(1,1/4), 62 | 'git/hasParent':(1,1/4), 63 | 'github/mentionsAuthor': (1,1/32), 64 | 'github/mergedAs':(.5,1), 65 | 'github/references':(1,1/16), 66 | 'github/reactsHeart':(2,1/32), 67 | 'github/reactsHooray':(4,1/32), 68 | 'github/reactsRocket':(1,0), #appears to be missing from current implementation 69 | 'github/reactsThumbsUp':(1,1/32) 70 | } 71 | 72 | default_node_wt_by_type = { 73 | 'github/issue':2.0, 74 | 'github/repo':4.0, 75 | 'github/comment': 1.0, 76 | 'git/commit':2.0, 77 | 'github/user':1.0, 78 | 'github/bot':1.0, 79 | 'github/review': 1.0, 80 | 'github/pull': 4.0 81 | } 82 | 83 | 84 | def wt_heuristic(g, 85 | node_wt_by_type=default_node_wt_by_type, 86 | edge_wt_by_type=default_edge_wt_by_type, 87 | self_loop_wt=default_self_loop_wt): 88 | 89 | for e in g.edges: 90 | e_wts = edge_wt_by_type[g.edges[e]['type']] 91 | src_wt = node_wt_by_type[g.nodes[e[0]]['type']] 92 | dst_wt = node_wt_by_type[g.nodes[e[1]]['type']] 93 | 94 | g.edges[e]['in_weight'] = e_wts[0]*dst_wt 95 | g.edges[e]['out_weight'] = e_wts[1]*src_wt 96 | 97 | ''' 98 | for n in g.nodes: 99 | wt = self_loop_wt 100 | for nb in nx.all_neighbors(g,n): 101 | #outbound neighbor 102 | if nb in g.neighbors(n): 103 | e_count = edge_count(g,n,nb) 104 | for e3 in range(e_count): 105 | wt = wt + g.edges[(n,nb,e3)]['out_weight'] 106 | #inbound neighbor 107 | else: 108 | e_count = edge_count(g,nb,n) 109 | for e3 in range(e_count): 110 | wt = wt + g.edges[(nb,n,e3)]['in_weight'] 111 | 112 | g.nodes[n]['denominator']=wt 113 | ''' 114 | 115 | #create neighborhoods 116 | for n in g.nodes: 117 | g.nodes[n]['all_nbr']= set(nx.all_neighbors(g,n)) 118 | g.nodes[n]['in_nbr'] = set() 119 | g.nodes[n]['out_nbr'] = set() 120 | for nb in g.nodes[n]['all_nbr']: 121 | #print((n,nb)) 122 | try : 123 | g.edges[(nb,n,0)] 124 | g.nodes[n]['in_nbr'].add(nb) 125 | except: 126 | pass 127 | try : 128 | g.edges[(n,nb,0)] 129 | g.nodes[n]['out_nbr'].add(nb) 130 | except: 131 | pass 132 | 133 | for n in g.nodes: 134 | self_wt = self_loop_wt#/g.nodes[n]['denominator'] 135 | g.nodes[n]['self_wt']=self_wt 136 | total_wt = self_wt 137 | for nb in g.nodes[n]['out_nbr']: 138 | #outbound neighbor 139 | e_count = edge_count(g, n,nb) 140 | for e3 in range(e_count): 141 | wt = g.edges[(n,nb,e3)]['in_weight']#/g.nodes[nb]['denominator'] 142 | #g.edges[(n,nb,e3)]['normalized_out_wt']=wt 143 | total_wt = total_wt+wt 144 | 145 | for nb in g.nodes[n]['in_nbr']: 146 | #inbound neighbor 147 | e_count = edge_count(g, nb,n) 148 | for e3 in range(e_count): 149 | wt = g.edges[(nb,n,e3)]['out_weight']#/g.nodes[nb]['denominator'] 150 | #g.edges[(nb,n,e3)]['normalized_in_wt']=wt 151 | total_wt = total_wt+wt 152 | 153 | 154 | g.nodes[n]['total_wt'] = total_wt 155 | 156 | return g 157 | 158 | def pageRanker(g, 159 | alpha, 160 | K, 161 | seed=None, 162 | initial_value = None, 163 | lazy=False, 164 | lazy_wt = .5, 165 | lazy_decay = True, 166 | self_loop_wt=default_self_loop_wt, 167 | node_wt_by_type =default_node_wt_by_type, 168 | edge_wt_by_type=default_edge_wt_by_type): 169 | 170 | #improve input verification for seed 171 | #must be dict keyed to nodes 172 | #with non-negative floating point values summing to 1 173 | if seed==None: 174 | N = len(g.nodes) 175 | seed = {n:1.0/N for n in g.nodes} 176 | 177 | #improve input verification for initial value 178 | #must be dict keyed to nodes 179 | #with non-negative floating point values summing to 1 180 | if initial_value==None: 181 | initial_value = seed 182 | 183 | for n in g.nodes: 184 | g.nodes[n]['score'] = initial_value[n] 185 | 186 | g = wt_heuristic(g, 187 | node_wt_by_type=node_wt_by_type, 188 | edge_wt_by_type=edge_wt_by_type, 189 | self_loop_wt=self_loop_wt) 190 | 191 | #print(g.nodes[0]) 192 | 193 | x_dict = {0:initial_value} 194 | for k in range(0,K): 195 | g = update_score(g, 196 | alpha, 197 | seed, 198 | lazy, 199 | lazy_wt*(1-int(lazy_decay)*k/(k+3))) 200 | x_dict[k+1] = nx.get_node_attributes(g,'score') 201 | 202 | 203 | #result in numpy array format 204 | pr= np.array([g.nodes[n]['score'] for n in range(len(g.nodes))]) 205 | 206 | #trajectory in pandas dataframe format 207 | df = pd.DataFrame(x_dict).T 208 | return pr,df, g -------------------------------------------------------------------------------- /03 Methodology/EmergentV.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlockScience/cadCAD-Tutorials/5ac9e99bfb66299316de4c9929fcc77fd16a23f9/03 Methodology/EmergentV.jpg -------------------------------------------------------------------------------- /03 Methodology/System Simulation Architecture - U-E-O.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlockScience/cadCAD-Tutorials/5ac9e99bfb66299316de4c9929fcc77fd16a23f9/03 Methodology/System Simulation Architecture - U-E-O.pdf -------------------------------------------------------------------------------- /03 Methodology/workflow.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlockScience/cadCAD-Tutorials/5ac9e99bfb66299316de4c9929fcc77fd16a23f9/03 Methodology/workflow.jpeg -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Opensource demos repository can be found [here](https://github.com/cadcad-org/demos) 2 | -------------------------------------------------------------------------------- /documentation/Historically_State_Access.md: -------------------------------------------------------------------------------- 1 | Historical State Access 2 | == 3 | #### Motivation 4 | 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. 5 | 6 | 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. 7 | 8 | #### Exclusion List 9 | Create a list of states to exclude from the reported PSU. 10 | ```python 11 | exclusion_list = [ 12 | 'nonexistent', 'last_x', '2nd_to_last_x', '3rd_to_last_x', '4th_to_last_x' 13 | ] 14 | ``` 15 | ##### Example Policy Updates 16 | ###### Last partial state update 17 | ```python 18 | def last_update(_params, substep, sH, s): 19 | return {"last_x": access_block( 20 | state_history=sH, 21 | target_field="last_x", # Add a field to the exclusion list 22 | psu_block_offset=-1, 23 | exculsion_list=exclusion_list 24 | ) 25 | } 26 | ``` 27 | * 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. 28 | ##### Define State Updates 29 | ###### 2nd to last partial state update 30 | ```python 31 | def second2last_update(_params, substep, sH, s): 32 | return {"2nd_to_last_x": access_block(sH, "2nd_to_last_x", -2, exclusion_list)} 33 | ``` 34 | 35 | 36 | ###### 3rd to last partial state update 37 | ```python 38 | def third_to_last_x(_params, substep, sH, s, _input): 39 | return '3rd_to_last_x', access_block(sH, "3rd_to_last_x", -3, exclusion_list) 40 | ``` 41 | ###### 4rd to last partial state update 42 | ```python 43 | def fourth_to_last_x(_params, substep, sH, s, _input): 44 | return '4th_to_last_x', access_block(sH, "4th_to_last_x", -4, exclusion_list) 45 | ``` 46 | ###### Non-exsistent partial state update 47 | * `psu_block_offset >= 0` doesn't exist 48 | ```python 49 | def nonexistent(_params, substep, sH, s, _input): 50 | return 'nonexistent', access_block(sH, "nonexistent", 0, exclusion_list) 51 | ``` 52 | 53 | #### Example Simulation 54 | link 55 | 56 | #### Example Output 57 | ###### State History 58 | ``` 59 | +----+-------+-----------+------------+-----+ 60 | | | run | substep | timestep | x | 61 | |----+-------+-----------+------------+-----| 62 | | 0 | 1 | 0 | 0 | 0 | 63 | | 1 | 1 | 1 | 1 | 1 | 64 | | 2 | 1 | 2 | 1 | 2 | 65 | | 3 | 1 | 3 | 1 | 3 | 66 | | 4 | 1 | 1 | 2 | 4 | 67 | | 5 | 1 | 2 | 2 | 5 | 68 | | 6 | 1 | 3 | 2 | 6 | 69 | | 7 | 1 | 1 | 3 | 7 | 70 | | 8 | 1 | 2 | 3 | 8 | 71 | | 9 | 1 | 3 | 3 | 9 | 72 | +----+-------+-----------+------------+-----+ 73 | ``` 74 | ###### Accessed State History: 75 | Example: `last_x` 76 | ``` 77 | +----+-----------------------------------------------------------------------------------------------------------------------------------------------------+ 78 | | | last_x | 79 | |----+-----------------------------------------------------------------------------------------------------------------------------------------------------| 80 | | 0 | [] | 81 | | 1 | [{'x': 0, 'run': 1, 'substep': 0, 'timestep': 0}] | 82 | | 2 | [{'x': 0, 'run': 1, 'substep': 0, 'timestep': 0}] | 83 | | 3 | [{'x': 0, 'run': 1, 'substep': 0, 'timestep': 0}] | 84 | | 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}] | 85 | | 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}] | 86 | | 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}] | 87 | | 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}] | 88 | | 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}] | 89 | | 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}] | 90 | +----+-----------------------------------------------------------------------------------------------------------------------------------------------------+ 91 | ``` -------------------------------------------------------------------------------- /documentation/Policy_Aggregation.md: -------------------------------------------------------------------------------- 1 | Policy Aggregation 2 | == 3 | 4 | For each Partial State Update, multiple policy dictionaries are aggregated into a single dictionary to be imputted into 5 | all state functions using an initial reduction function and optional subsequent map functions. 6 | 7 | #### Aggregate Function Composition: 8 | ```python 9 | # Reduce Function 10 | add = lambda a, b: a + b # Used to add policy values of the same key 11 | # Map Function 12 | mult_by_2 = lambda y: y * 2 # Used to multiply all policy values by 2 13 | policy_ops=[add, mult_by_2] 14 | ``` 15 | 16 | ##### Example Policy Updates per Partial State Update (PSU) 17 | ```python 18 | def p1_psu1(_params, step, sH, s): 19 | return {'policy1': 1} 20 | def p2_psu1(_params, step, sH, s): 21 | return {'policy2': 2} 22 | ``` 23 | * `add` not applicable due to lack of redundant policies 24 | * `mult_by_2` applied to all policies 25 | * Result: `{'policy1': 2, 'policy2': 4}` 26 | 27 | ```python 28 | def p1_psu2(_params, step, sH, s): 29 | return {'policy1': 2, 'policy2': 2} 30 | def p2_psu2(_params, step, sH, s): 31 | return {'policy1': 2, 'policy2': 2} 32 | ``` 33 | * `add` applicable due to redundant policies 34 | * `mult_by_2` applied to all policies 35 | * Result: `{'policy1': 8, 'policy2': 8}` 36 | 37 | ```python 38 | def p1_psu3(_params, step, sH, s): 39 | return {'policy1': 1, 'policy2': 2, 'policy3': 3} 40 | def p2_psu3(_params, step, sH, s): 41 | return {'policy1': 1, 'policy2': 2, 'policy3': 3} 42 | ``` 43 | * `add` applicable due to redundant policies 44 | * `mult_by_2` applied to all policies 45 | * Result: `{'policy1': 4, 'policy2': 8, 'policy3': 12}` 46 | 47 | #### Aggregate Policies using functions 48 | ```python 49 | from cadCAD.configuration import append_configs 50 | 51 | append_configs( 52 | sim_configs=???, 53 | initial_state=???, 54 | partial_state_update_blocks=???, 55 | policy_ops=[add, mult_by_2] # Default: [lambda a, b: a + b] 56 | ) 57 | ``` 58 | 59 | #### Example 60 | ##### * [System Model Configuration](examples/policy_aggregation.py) 61 | ##### * Simulation Results: 62 | ``` 63 | +----+---------------------------------------------+-------+------+-----------+------------+ 64 | | | policies | run | s1 | substep | timestep | 65 | |----+---------------------------------------------+-------+------+-----------+------------| 66 | | 0 | {} | 1 | 0 | 0 | 0 | 67 | | 1 | {'policy1': 2, 'policy2': 4} | 1 | 1 | 1 | 1 | 68 | | 2 | {'policy1': 8, 'policy2': 8} | 1 | 2 | 2 | 1 | 69 | | 3 | {'policy3': 12, 'policy1': 4, 'policy2': 8} | 1 | 3 | 3 | 1 | 70 | | 4 | {'policy1': 2, 'policy2': 4} | 1 | 4 | 1 | 2 | 71 | | 5 | {'policy1': 8, 'policy2': 8} | 1 | 5 | 2 | 2 | 72 | | 6 | {'policy3': 12, 'policy1': 4, 'policy2': 8} | 1 | 6 | 3 | 2 | 73 | | 7 | {'policy1': 2, 'policy2': 4} | 1 | 7 | 1 | 3 | 74 | | 8 | {'policy1': 8, 'policy2': 8} | 1 | 8 | 2 | 3 | 75 | | 9 | {'policy3': 12, 'policy1': 4, 'policy2': 8} | 1 | 9 | 3 | 3 | 76 | +----+---------------------------------------------+-------+------+-----------+------------+ 77 | ``` 78 | -------------------------------------------------------------------------------- /documentation/Simulation_Configuration.md: -------------------------------------------------------------------------------- 1 | Simulation Configuration 2 | == 3 | 4 | ## Introduction 5 | 6 | Given a **Simulation Configuration**, cadCAD produces datasets that represent the evolution of the state of a system 7 | over [discrete time](https://en.wikipedia.org/wiki/Discrete_time_and_continuous_time#Discrete_time). The state of the 8 | system is described by a set of [State Variables](#State-Variables). The dynamic of the system is described by 9 | [Policy Functions](#Policy-Functions) and [State Update Functions](#State-Update-Functions), which are evaluated by 10 | cadCAD according to the definitions set by the user in [Partial State Update Blocks](#Partial-State-Update-Blocks). 11 | 12 | A Simulation Configuration is comprised of a [System Model](#System-Model) and a set of 13 | [Simulation Properties](#Simulation-Properties) 14 | 15 | `append_configs`, stores a **Simulation Configuration** to be [Executed](/JS4Q9oayQASihxHBJzz4Ug) by cadCAD 16 | 17 | ```python 18 | from cadCAD.configuration import append_configs 19 | 20 | append_configs( 21 | initial_state = ..., # System Model 22 | partial_state_update_blocks = .., # System Model 23 | policy_ops = ..., # System Model 24 | sim_configs = ... # Simulation Properties 25 | ) 26 | ``` 27 | Parameters: 28 | * **initial_state** : _dict_ - [State Variables](#State-Variables) and their initial values 29 | * **partial_state_update_blocks** : List[dict[dict]] - List of [Partial State Update Blocks](#Partial-State-Update-Blocks) 30 | * **policy_ops** : List[functions] - See [Policy Aggregation](/63k2ncjITuqOPCUHzK7Viw) 31 | * **sim_configs** - See [System Model Parameter Sweep](/4oJ_GT6zRWW8AO3yMhFKrg) 32 | 33 | ## Simulation Properties 34 | 35 | Simulation properties are passed to `append_configs` in the `sim_configs` parameter. To construct this parameter, we 36 | use the `config_sim` function in `cadCAD.configuration.utils` 37 | 38 | ```python 39 | from cadCAD.configuration.utils import config_sim 40 | 41 | c = config_sim({ 42 | "N": ..., 43 | "T": range(...), 44 | "M": ... 45 | }) 46 | 47 | append_configs( 48 | ... 49 | sim_configs = c # Simulation Properties 50 | ) 51 | ``` 52 | 53 | ### T - Simulation Length 54 | Computer simulations run in discrete time: 55 | 56 | >Discrete time views values of variables as occurring at distinct, separate "points in time", or equivalently as being 57 | unchanged throughout each non-zero region of time ("time period")—that is, time is viewed as a discrete variable. (...) 58 | 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 59 | new fixed reading of 10:38, etc. 60 | ([source: Wikipedia](https://en.wikipedia.org/wiki/Discrete_time_and_continuous_time#Discrete_time)) 61 | 62 | As is common in many simulation tools, in cadCAD too we refer to each discrete unit of time as a **timestep**. cadCAD 63 | increments a "time counter", and at each step it updates the state variables according to the equations that describe 64 | the system. 65 | 66 | The main simulation property that the user must set when creating a Simulation Configuration is the number of timesteps 67 | in the simulation. In other words, for how long do they want to simulate the system that has been modeled. 68 | 69 | ### N - Number of Runs 70 | 71 | cadCAD facilitates running multiple simulations of the same system sequentially, reporting the results of all those 72 | runs in a single dataset. This is especially helpful for running 73 | [Monte Carlo Simulations](https://github.com/BlockScience/cadCAD-Tutorials/blob/master/01%20Tutorials/robot-marbles-part-4/robot-marbles-part-4.ipynb). 74 | 75 | ### M - Parameters of the System 76 | 77 | Parameters of the system, passed to the state update functions and the policy functions in the `params` parameter are 78 | defined here. See [System Model Parameter Sweep](/4oJ_GT6zRWW8AO3yMhFKrg) for more information. 79 | 80 | ## System Model 81 | The System Model describes the system that will be simulated in cadCAD. It is comprised of a set of 82 | [State Variables](###Sate-Variables) and the [State Update Functions](#State-Update-Functions) that determine the 83 | evolution of the state of the system over time. [Policy Functions](#Policy-Functions) (representations of user policies 84 | or internal system control policies) may also be part of a System Model. 85 | 86 | ### State Variables 87 | >A state variable is one of the set of variables that are used to describe the mathematical "state" of a dynamical 88 | system. Intuitively, the state of a system describes enough about the system to determine its future behaviour in the 89 | absence of any external forces affecting the system. ([source: Wikipedia](https://en.wikipedia.org/wiki/State_variable)) 90 | 91 | cadCAD can handle state variables of any Python data type, including custom classes. It is up to the user of cadCAD to 92 | determine the state variables needed to **sufficiently and accurately** describe the system they are interested in. 93 | 94 | State Variables are passed to `append_configs` along with its initial values, as a Python `dict` where the `dict_keys` 95 | are the names of the variables and the `dict_values` are their initial values. 96 | 97 | ```python 98 | from cadCAD.configuration import append_configs 99 | 100 | genesis_states = { 101 | 'state_variable_1': 0, 102 | 'state_variable_2': 0, 103 | 'state_variable_3': 1.5, 104 | 'timestamp': '2019-01-01 00:00:00' 105 | } 106 | 107 | append_configs( 108 | initial_state = genesis_states, 109 | ... 110 | ) 111 | ``` 112 | ### State Update Functions 113 | State Update Functions represent equations according to which the state variables change over time. Each state update 114 | function must return a tuple containing a string with the name of the state variable being updated and its new value. 115 | Each state update function can only modify a single state variable. The general structure of a state update function is: 116 | ```python 117 | def state_update_function_A(_params, substep, sH, s, _input): 118 | ... 119 | return 'state_variable_name', new_value 120 | ``` 121 | Parameters: 122 | * **_params** : _dict_ - [System parameters](/4oJ_GT6zRWW8AO3yMhFKrg) 123 | * **substep** : _int_ - Current [substep](#Substep) 124 | * **sH** : _list[list[dict_]] - Historical values of all state variables for the simulation. See 125 | [Historical State Access](/smiyQTnATtC9xPwvF8KbBQ) for details 126 | * **s** : _dict_ - Current state of the system, where the `dict_keys` are the names of the state variables and the 127 | `dict_values` are their current values. 128 | * **_input** : _dict_ - Aggregation of the signals of all policy functions in the current 129 | [Partial State Update Block](#Partial-State-Update-Block) 130 | 131 | Return: 132 | * _tuple_ containing a string with the name of the state variable being updated and its new value. 133 | 134 | State update functions should not modify any of the parameters passed to it, as those are mutable Python objects that 135 | cadCAD relies on in order to run the simulation according to the specifications. 136 | 137 | ### Policy Functions 138 | A Policy Function computes one or more signals to be passed to [State Update Functions](#State-Update-Functions) 139 | (via the _\_input_ parameter). Read 140 | [this article](https://github.com/BlockScience/cadCAD-Tutorials/blob/master/01%20Tutorials/robot-marbles-part-2/robot-marbles-part-2.ipynb) 141 | for details on why and when to use policy functions. 142 | 143 | 156 | 157 | The general structure of a policy function is: 158 | ```python 159 | def policy_function_1(_params, substep, sH, s): 160 | ... 161 | return {'signal_1': value_1, ..., 'signal_N': value_N} 162 | ``` 163 | Parameters: 164 | * **_params** : _dict_ - [System parameters](/4oJ_GT6zRWW8AO3yMhFKrg) 165 | * **substep** : _int_ - Current [substep](#Substep) 166 | * **sH** : _list[list[dict_]] - Historical values of all state variables for the simulation. See 167 | [Historical State Access](/smiyQTnATtC9xPwvF8KbBQ) for details 168 | * **s** : _dict_ - Current state of the system, where the `dict_keys` are the names of the state variables and the 169 | `dict_values` are their current values. 170 | 171 | Return: 172 | * _dict_ of signals to be passed to the state update functions in the same 173 | [Partial State Update Block](#Partial-State-Update-Blocks) 174 | 175 | Policy functions should not modify any of the parameters passed to it, as those are mutable Python objects that cadCAD 176 | relies on in order to run the simulation according to the specifications. 177 | 178 | At each [Partial State Update Block](#Partial-State-Update-Blocks) (PSUB), the `dicts` returned by all policy functions 179 | within that PSUB dictionaries are aggregated into a single `dict` using an initial reduction function 180 | (a key-wise operation, default: `dic1['keyA'] + dic2['keyA']`) and optional subsequent map functions. The resulting 181 | aggregated `dict` is then passed as the `_input` parameter to the state update functions in that PSUB. For more 182 | information on how to modify the aggregation method, see [Policy Aggregation](/63k2ncjITuqOPCUHzK7Viw). 183 | 184 | ### Partial State Update Blocks 185 | 186 | A **Partial State Update Block** (PSUB) is a set of State Update Functions and Policy Functions such that State Update 187 | Functions in the set are independent from each other and Policies in the set are independent from each other and from 188 | the State Update Functions in the set. In other words, if a state variable is updated in a PSUB, its new value cannot 189 | impact the State Update Functions and Policy Functions in that PSUB - only those in the next PSUB. 190 | 191 | ![](https://i.imgur.com/9rlX9TG.png) 192 | 193 | Partial State Update Blocks are passed to `append_configs` as a List of Python `dicts` where the `dict_keys` are named 194 | `"policies"` and `"variables"` and the values are also Python `dicts` where the keys are the names of the policy and 195 | state update functions and the values are the functions. 196 | 197 | ```python 198 | PSUBs = [ 199 | { 200 | "policies": { 201 | "b_1": policy_function_1, 202 | ... 203 | "b_J": policy_function_J 204 | }, 205 | "variables": { 206 | "s_1": state_update_function_1, 207 | ... 208 | "s_K": state_update_function_K 209 | } 210 | }, #PSUB_1, 211 | {...}, #PSUB_2, 212 | ... 213 | {...} #PSUB_M 214 | ] 215 | 216 | append_configs( 217 | ... 218 | partial_state_update_blocks = PSUBs, 219 | ... 220 | ) 221 | 222 | ``` 223 | 224 | #### Substep 225 | At each timestep, cadCAD iterates over the `partial_state_update_blocks` list. For each Partial State Update Block, 226 | cadCAD returns a record containing the state of the system at the end of that PSUB. We refer to that subdivision of a 227 | timestep as a `substep`. 228 | 229 | ## Result Dataset 230 | 231 | cadCAD returns a dataset containing the evolution of the state variables defined by the user over time, with three `int` 232 | indexes: 233 | * `run` - id of the [run](#N-Number-of-Runs) 234 | * `timestep` - discrete unit of time (the total number of timesteps is defined by the user in the 235 | [T Simulation Parameter](#T-Simulation-Length)) 236 | * `substep` - subdivision of timestep (the number of [substeps](#Substeps) is the same as the number of Partial State 237 | Update Blocks) 238 | 239 | Therefore, the total number of records in the resulting dataset is `N` x `T` x `len(partial_state_update_blocks)` 240 | 241 | #### [System Simulation Execution](https://github.com/BlockScience/cadCAD-Tutorials/blob/master/documentation/Simulation_Execution.md) 242 | -------------------------------------------------------------------------------- /documentation/Simulation_Execution.md: -------------------------------------------------------------------------------- 1 | Simulation Execution 2 | == 3 | System Simulations are executed with the execution engine executor (`cadCAD.engine.Executor`) given System Model 4 | Configurations. There are multiple simulation Execution Modes and Execution Contexts. 5 | 6 | ### Steps: 7 | 1. #### *Choose Execution Mode*: 8 | * ##### Simulation Execution Modes: 9 | `cadCAD` executes a process per System Model Configuration and a thread per System Simulation. 10 | ##### Class: `cadCAD.engine.ExecutionMode` 11 | ##### Attributes: 12 | * **Single Process:** A single process Execution Mode for a single System Model Configuration (Example: 13 | `cadCAD.engine.ExecutionMode().single_proc`). 14 | * **Multi-Process:** Multiple process Execution Mode for System Model Simulations which executes on a thread per 15 | given System Model Configuration (Example: `cadCAD.engine.ExecutionMode().multi_proc`). 16 | 2. #### *Create Execution Context using Execution Mode:* 17 | ```python 18 | from cadCAD.engine import ExecutionMode, ExecutionContext 19 | exec_mode = ExecutionMode() 20 | single_proc_ctx = ExecutionContext(context=exec_mode.single_proc) 21 | ``` 22 | 3. #### *Create Simulation Executor* 23 | ```python 24 | from cadCAD.engine import Executor 25 | from cadCAD import configs 26 | simulation = Executor(exec_context=single_proc_ctx, configs=configs) 27 | ``` 28 | 4. #### *Execute Simulation: Produce System Event Dataset* 29 | A Simulation execution produces a System Event Dataset and the Tensor Field applied to initial states used to create it. 30 | ```python 31 | import pandas as pd 32 | raw_system_events, tensor_field = simulation.execute() 33 | 34 | # Simulation Result Types: 35 | # raw_system_events: List[dict] 36 | # tensor_field: pd.DataFrame 37 | 38 | # Result System Events DataFrame 39 | simulation_result = pd.DataFrame(raw_system_events) 40 | ``` 41 | 42 | ##### Example Tensor Field 43 | ``` 44 | +----+-----+--------------------------------+--------------------------------+ 45 | | | m | b1 | s1 | 46 | |----+-----+--------------------------------+--------------------------------| 47 | | 0 | 1 | | | 48 | | 1 | 2 | | | 49 | | 2 | 3 | | | 50 | +----+-----+--------------------------------+--------------------------------+ 51 | ``` 52 | 53 | ##### Example Result: System Events DataFrame 54 | ``` 55 | +----+-------+------------+-----------+------+-----------+ 56 | | | run | timestep | substep | s1 | s2 | 57 | |----+-------+------------+-----------+------+-----------| 58 | | 0 | 1 | 0 | 0 | 0 | 0.0 | 59 | | 1 | 1 | 1 | 1 | 1 | 4 | 60 | | 2 | 1 | 1 | 2 | 2 | 6 | 61 | | 3 | 1 | 1 | 3 | 3 | [ 30 300] | 62 | | 4 | 2 | 0 | 0 | 0 | 0.0 | 63 | | 5 | 2 | 1 | 1 | 1 | 4 | 64 | | 6 | 2 | 1 | 2 | 2 | 6 | 65 | | 7 | 2 | 1 | 3 | 3 | [ 30 300] | 66 | +----+-------+------------+-----------+------+-----------+ 67 | ``` 68 | 69 | ### Execution Examples: 70 | ##### Single Simulation Execution (Single Process Execution) 71 | Example [System Model Configurations](link): 72 | * [System Model A](link): `/documentation/examples/sys_model_A.py` 73 | * [System Model B](link): `/documentation/examples/sys_model_B.py` 74 | Example Simulation Executions: 75 | * [System Model A](link): `/documentation/examples/sys_model_A_exec.py` 76 | * [System Model B](link): `/documentation/examples/sys_model_B_exec.py` 77 | ```python 78 | import pandas as pd 79 | from tabulate import tabulate 80 | from cadCAD.engine import ExecutionMode, ExecutionContext, Executor 81 | from documentation.examples import sys_model_A 82 | from cadCAD import configs 83 | 84 | exec_mode = ExecutionMode() 85 | 86 | # Single Process Execution using a Single System Model Configuration: 87 | # sys_model_A 88 | sys_model_A = [configs[0]] # sys_model_A 89 | single_proc_ctx = ExecutionContext(context=exec_mode.single_proc) 90 | sys_model_A_simulation = Executor(exec_context=single_proc_ctx, configs=sys_model_A) 91 | 92 | sys_model_A_raw_result, sys_model_A_tensor_field = sys_model_A_simulation.execute() 93 | sys_model_A_result = pd.DataFrame(sys_model_A_raw_result) 94 | print() 95 | print("Tensor Field: sys_model_A") 96 | print(tabulate(sys_model_A_tensor_field, headers='keys', tablefmt='psql')) 97 | print("Result: System Events DataFrame") 98 | print(tabulate(sys_model_A_result, headers='keys', tablefmt='psql')) 99 | print() 100 | ``` 101 | 102 | ##### Multiple Simulation Execution 103 | 104 | * ##### *Multi Process Execution* 105 | Documentation: [Simulation Execution](link) 106 | [Example Simulation Executions::](link) `/documentation/examples/sys_model_AB_exec.py` 107 | Example [System Model Configurations](link): 108 | * [System Model A](link): `/documentation/examples/sys_model_A.py` 109 | * [System Model B](link): `/documentation/examples/sys_model_B.py` 110 | ```python 111 | import pandas as pd 112 | from tabulate import tabulate 113 | from cadCAD.engine import ExecutionMode, ExecutionContext, Executor 114 | from documentation.examples import sys_model_A, sys_model_B 115 | from cadCAD import configs 116 | 117 | exec_mode = ExecutionMode() 118 | 119 | # # Multiple Processes Execution using Multiple System Model Configurations: 120 | # # sys_model_A & sys_model_B 121 | multi_proc_ctx = ExecutionContext(context=exec_mode.multi_proc) 122 | sys_model_AB_simulation = Executor(exec_context=multi_proc_ctx, configs=configs) 123 | 124 | i = 0 125 | config_names = ['sys_model_A', 'sys_model_B'] 126 | for sys_model_AB_raw_result, sys_model_AB_tensor_field in sys_model_AB_simulation.execute(): 127 | sys_model_AB_result = pd.DataFrame(sys_model_AB_raw_result) 128 | print() 129 | print(f"Tensor Field: {config_names[i]}") 130 | print(tabulate(sys_model_AB_tensor_field, headers='keys', tablefmt='psql')) 131 | print("Result: System Events DataFrame:") 132 | print(tabulate(sys_model_AB_result, headers='keys', tablefmt='psql')) 133 | print() 134 | i += 1 135 | ``` 136 | 137 | * ##### *Parameter Sweep* 138 | Documentation: [System Model Parameter Sweep](link) 139 | [Example:](link) `/documentation/examples/param_sweep.py` 140 | ```python 141 | import pandas as pd 142 | from tabulate import tabulate 143 | # The following imports NEED to be in the exact order 144 | from cadCAD.engine import ExecutionMode, ExecutionContext, Executor 145 | from documentation.examples import param_sweep 146 | from cadCAD import configs 147 | 148 | exec_mode = ExecutionMode() 149 | multi_proc_ctx = ExecutionContext(context=exec_mode.multi_proc) 150 | run = Executor(exec_context=multi_proc_ctx, configs=configs) 151 | 152 | for raw_result, tensor_field in run.execute(): 153 | result = pd.DataFrame(raw_result) 154 | print() 155 | print("Tensor Field:") 156 | print(tabulate(tensor_field, headers='keys', tablefmt='psql')) 157 | print("Output:") 158 | print(tabulate(result, headers='keys', tablefmt='psql')) 159 | print() 160 | ``` 161 | -------------------------------------------------------------------------------- /documentation/System_Model_Parameter_Sweep.md: -------------------------------------------------------------------------------- 1 | System Model Parameter Sweep 2 | == 3 | Parametrization of a System Model configuration that produces multiple configurations. 4 | 5 | ##### Set Parameters 6 | ```python 7 | params = { 8 | 'alpha': [1], 9 | 'beta': [2, 5], 10 | 'gamma': [3, 4], 11 | 'omega': [7] 12 | } 13 | ``` 14 | The parameters above produce 2 simulations. 15 | * Simulation 1: 16 | * `alpha = 1` 17 | * `beta = 2` 18 | * `gamma = 3` 19 | * `omega = 7` 20 | * Simulation 2: 21 | * `alpha = 1` 22 | * `beta = 5` 23 | * `gamma = 4` 24 | * `omega = 7` 25 | 26 | All parameters can also be set to include a single parameter each, which will result in a single simulation. 27 | 28 | ##### Example State Updates 29 | 30 | Previous State: 31 | `y = 0` 32 | 33 | ```python 34 | def state_update(_params, step, sH, s, _input): 35 | y = 'state' 36 | x = s['state'] + _params['alpha'] + _params['gamma'] 37 | return y, x 38 | ``` 39 | * Updated State: 40 | * Simulation 1: `y = 4 = 0 + 1 + 3` 41 | * Simulation 2: `y = 5 = 0 + 1 + 4` 42 | 43 | ##### Example Policy Updates 44 | ```python 45 | # Internal States per Mechanism 46 | def policies(_params, step, sH, s): 47 | return {'beta': _params['beta'], 'gamma': _params['gamma']} 48 | ``` 49 | * Simulation 1: `{'beta': 2, 'gamma': 3]}` 50 | * Simulation 2: `{'beta': 5, 'gamma': 4}` 51 | 52 | ##### Configure Simulation 53 | ```python 54 | from cadCAD.configuration.utils import config_sim 55 | 56 | g = { 57 | 'alpha': [1], 58 | 'beta': [2, 5], 59 | 'gamma': [3, 4], 60 | 'omega': [7] 61 | } 62 | 63 | sim_config = config_sim( 64 | { 65 | "N": 2, 66 | "T": range(5), 67 | "M": g, 68 | } 69 | ) 70 | ``` 71 | #### Example 72 | ##### * [System Model Configuration](https://github.com/BlockScience/cadCAD-Tutorials/blob/master/Documentation/examples/param_sweep.py) 73 | ##### * Simulation Results: 74 | -------------------------------------------------------------------------------- /documentation/examples/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlockScience/cadCAD-Tutorials/5ac9e99bfb66299316de4c9929fcc77fd16a23f9/documentation/examples/__init__.py -------------------------------------------------------------------------------- /documentation/examples/example_1.py: -------------------------------------------------------------------------------- 1 | from pprint import pprint 2 | 3 | import pandas as pd 4 | from tabulate import tabulate 5 | from cadCAD.engine import ExecutionMode, ExecutionContext, Executor 6 | from documentation.examples import sys_model_A, sys_model_B 7 | from cadCAD import configs 8 | 9 | exec_mode = ExecutionMode() 10 | 11 | # Single Process Execution using a Single System Model Configuration: 12 | # sys_model_A 13 | sys_model_A = [configs[0]] 14 | single_proc_ctx = ExecutionContext(context=exec_mode.single_proc) 15 | sys_model_A_simulation = Executor(exec_context=single_proc_ctx, configs=sys_model_A) 16 | 17 | sys_model_A_raw_result, sys_model_A_tensor_field = sys_model_A_simulation.execute() 18 | sys_model_A_result = pd.DataFrame(sys_model_A_raw_result) 19 | print() 20 | print("Tensor Field: sys_model_A") 21 | print(tabulate(sys_model_A_tensor_field, headers='keys', tablefmt='psql')) 22 | print("Result: System Events DataFrame") 23 | print(tabulate(sys_model_A_result, headers='keys', tablefmt='psql')) 24 | print() 25 | 26 | # # Multiple Processes Execution using Multiple System Model Configurations: 27 | # # sys_model_A & sys_model_B 28 | multi_proc_ctx = ExecutionContext(context=exec_mode.multi_proc) 29 | sys_model_AB_simulation = Executor(exec_context=multi_proc_ctx, configs=configs) 30 | 31 | 32 | 33 | i = 0 34 | config_names = ['sys_model_A', 'sys_model_B'] 35 | for sys_model_AB_raw_result, sys_model_AB_tensor_field in sys_model_AB_simulation.execute(): 36 | print() 37 | pprint(sys_model_AB_raw_result) 38 | # sys_model_AB_result = pd.DataFrame(sys_model_AB_raw_result) 39 | print() 40 | print(f"Tensor Field: {config_names[i]}") 41 | print(tabulate(sys_model_AB_tensor_field, headers='keys', tablefmt='psql')) 42 | # print("Result: System Events DataFrame:") 43 | # print(tabulate(sys_model_AB_result, headers='keys', tablefmt='psql')) 44 | # print() 45 | i += 1 -------------------------------------------------------------------------------- /documentation/examples/historical_state_access.py: -------------------------------------------------------------------------------- 1 | import pandas as pd 2 | from tabulate import tabulate 3 | from cadCAD.configuration import append_configs 4 | from cadCAD.configuration.utils import config_sim, access_block 5 | from cadCAD.engine import ExecutionMode, ExecutionContext, Executor 6 | from cadCAD import configs 7 | 8 | 9 | policies, variables = {}, {} 10 | exclusion_list = ['nonexsistant', 'last_x', '2nd_to_last_x', '3rd_to_last_x', '4th_to_last_x'] 11 | 12 | # Policies per Mechanism 13 | 14 | # state_history, target_field, psu_block_offset, exculsion_list 15 | def last_update(_g, substep, sH, s): 16 | return {"last_x": access_block( 17 | state_history=sH, 18 | target_field="last_x", 19 | psu_block_offset=-1, 20 | exculsion_list=exclusion_list 21 | ) 22 | } 23 | policies["last_x"] = last_update 24 | 25 | def second2last_update(_g, substep, sH, s): 26 | return {"2nd_to_last_x": access_block(sH, "2nd_to_last_x", -2, exclusion_list)} 27 | policies["2nd_to_last_x"] = second2last_update 28 | 29 | 30 | # Internal States per Mechanism 31 | 32 | # WARNING: DO NOT delete elements from sH 33 | def add(y, x): 34 | return lambda _g, substep, sH, s, _input: (y, s[y] + x) 35 | variables['x'] = add('x', 1) 36 | 37 | # last_partial_state_update_block 38 | def nonexsistant(_g, substep, sH, s, _input): 39 | return 'nonexsistant', access_block(sH, "nonexsistant", 0, exclusion_list) 40 | variables['nonexsistant'] = nonexsistant 41 | 42 | # last_partial_state_update_block 43 | def last_x(_g, substep, sH, s, _input): 44 | return 'last_x', _input["last_x"] 45 | variables['last_x'] = last_x 46 | 47 | # 2nd to last partial state update block 48 | def second_to_last_x(_g, substep, sH, s, _input): 49 | return '2nd_to_last_x', _input["2nd_to_last_x"] 50 | variables['2nd_to_last_x'] = second_to_last_x 51 | 52 | # 3rd to last partial state update block 53 | def third_to_last_x(_g, substep, sH, s, _input): 54 | return '3rd_to_last_x', access_block(sH, "3rd_to_last_x", -3, exclusion_list) 55 | variables['3rd_to_last_x'] = third_to_last_x 56 | 57 | # 4th to last partial state update block 58 | def fourth_to_last_x(_g, substep, sH, s, _input): 59 | return '4th_to_last_x', access_block(sH, "4th_to_last_x", -4, exclusion_list) 60 | variables['4th_to_last_x'] = fourth_to_last_x 61 | 62 | 63 | genesis_states = { 64 | 'x': 0, 65 | 'nonexsistant': [], 66 | 'last_x': [], 67 | '2nd_to_last_x': [], 68 | '3rd_to_last_x': [], 69 | '4th_to_last_x': [] 70 | } 71 | 72 | PSUB = { 73 | "policies": policies, 74 | "variables": variables 75 | } 76 | 77 | psubs = { 78 | "PSUB1": PSUB, 79 | "PSUB2": PSUB, 80 | "PSUB3": PSUB 81 | } 82 | 83 | sim_config = config_sim( 84 | { 85 | "N": 1, 86 | "T": range(3), 87 | } 88 | ) 89 | 90 | append_configs( 91 | sim_configs=sim_config, 92 | initial_state=genesis_states, 93 | partial_state_update_blocks=psubs 94 | ) 95 | 96 | exec_mode = ExecutionMode() 97 | single_proc_ctx = ExecutionContext(context=exec_mode.single_proc) 98 | run = Executor(exec_context=single_proc_ctx, configs=configs) 99 | 100 | raw_result, tensor_field = run.execute() 101 | result = pd.DataFrame(raw_result) 102 | cols = ['run','substep','timestep','x','nonexsistant','last_x','2nd_to_last_x','3rd_to_last_x','4th_to_last_x'] 103 | result = result[cols] 104 | 105 | print() 106 | print("Tensor Field:") 107 | print(tabulate(tensor_field, headers='keys', tablefmt='psql')) 108 | print("Output:") 109 | print(tabulate(result, headers='keys', tablefmt='psql')) 110 | print() -------------------------------------------------------------------------------- /documentation/examples/param_sweep.py: -------------------------------------------------------------------------------- 1 | import pprint 2 | from typing import Dict, List 3 | 4 | import pandas as pd 5 | from tabulate import tabulate 6 | 7 | from cadCAD.configuration import append_configs 8 | from cadCAD.configuration.utils import env_trigger, var_substep_trigger, config_sim, psub_list 9 | from cadCAD.engine import ExecutionMode, ExecutionContext, Executor 10 | from cadCAD import configs 11 | 12 | pp = pprint.PrettyPrinter(indent=4) 13 | 14 | 15 | def some_function(x): 16 | return x 17 | 18 | 19 | g: Dict[str, List[int]] = { 20 | 'alpha': [1], 21 | 'beta': [2, 5], 22 | 'gamma': [3, 4], 23 | 'omega': [some_function] 24 | } 25 | 26 | psu_steps = ['1', '2', '3'] 27 | system_substeps = len(psu_steps) 28 | var_timestep_trigger = var_substep_trigger([0, system_substeps]) 29 | env_timestep_trigger = env_trigger(system_substeps) 30 | env_process = {} 31 | 32 | 33 | # Policies 34 | def gamma(_params, step, sH, s): 35 | return {'gamma': _params['gamma']} 36 | 37 | 38 | def omega(_params, step, sH, s): 39 | return {'omega': _params['omega'](7)} 40 | 41 | 42 | # Internal States 43 | def alpha(_params, step, sH, s, _input): 44 | return 'alpha', _params['alpha'] 45 | 46 | def alpha_plus_gamma(_params, step, sH, s, _input): 47 | return 'alpha_plus_gamma', _params['alpha'] + _params['gamma'] 48 | 49 | 50 | def beta(_params, step, sH, s, _input): 51 | return 'beta', _params['beta'] 52 | 53 | 54 | def policies(_params, step, sH, s, _input): 55 | return 'policies', _input 56 | 57 | 58 | def sweeped(_params, step, sH, s, _input): 59 | return 'sweeped', {'beta': _params['beta'], 'gamma': _params['gamma']} 60 | 61 | 62 | 63 | 64 | 65 | genesis_states = { 66 | 'alpha_plus_gamma': 0, 67 | 'alpha': 0, 68 | 'beta': 0, 69 | 'policies': {}, 70 | 'sweeped': {} 71 | } 72 | 73 | env_process['sweeped'] = env_timestep_trigger(trigger_field='timestep', trigger_vals=[5], funct_list=[lambda _g, x: _g['beta']]) 74 | 75 | sim_config = config_sim( 76 | { 77 | "N": 2, 78 | "T": range(5), 79 | "M": g, 80 | } 81 | ) 82 | 83 | psu_block = {k: {"policies": {}, "variables": {}} for k in psu_steps} 84 | for m in psu_steps: 85 | psu_block[m]['policies']['gamma'] = gamma 86 | psu_block[m]['policies']['omega'] = omega 87 | psu_block[m]["variables"]['alpha'] = alpha_plus_gamma 88 | psu_block[m]["variables"]['alpha_plus_gamma'] = alpha 89 | psu_block[m]["variables"]['beta'] = beta 90 | psu_block[m]['variables']['policies'] = policies 91 | psu_block[m]["variables"]['sweeped'] = var_timestep_trigger(y='sweeped', f=sweeped) 92 | 93 | psubs = psub_list(psu_block, psu_steps) 94 | print() 95 | pp.pprint(psu_block) 96 | print() 97 | 98 | append_configs( 99 | sim_configs=sim_config, 100 | initial_state=genesis_states, 101 | env_processes=env_process, 102 | partial_state_update_blocks=psubs 103 | ) 104 | 105 | exec_mode = ExecutionMode() 106 | multi_proc_ctx = ExecutionContext(context=exec_mode.multi_proc) 107 | run = Executor(exec_context=multi_proc_ctx, configs=configs) 108 | 109 | for raw_result, tensor_field in run.execute(): 110 | result = pd.DataFrame(raw_result) 111 | print() 112 | print("Tensor Field:") 113 | print(tabulate(tensor_field, headers='keys', tablefmt='psql')) 114 | print("Output:") 115 | print(tabulate(result, headers='keys', tablefmt='psql')) 116 | print() -------------------------------------------------------------------------------- /documentation/examples/policy_aggregation.py: -------------------------------------------------------------------------------- 1 | import pandas as pd 2 | from tabulate import tabulate 3 | 4 | from cadCAD.configuration import append_configs 5 | from cadCAD.configuration.utils import config_sim 6 | from cadCAD.engine import ExecutionMode, ExecutionContext, Executor 7 | from cadCAD import configs 8 | 9 | # Policies per Mechanism 10 | def p1m1(_g, step, sH, s): 11 | return {'policy1': 1} 12 | def p2m1(_g, step, sH, s): 13 | return {'policy2': 2} 14 | 15 | def p1m2(_g, step, sH, s): 16 | return {'policy1': 2, 'policy2': 2} 17 | def p2m2(_g, step, sH, s): 18 | return {'policy1': 2, 'policy2': 2} 19 | 20 | def p1m3(_g, step, sH, s): 21 | return {'policy1': 1, 'policy2': 2, 'policy3': 3} 22 | def p2m3(_g, step, sH, s): 23 | return {'policy1': 1, 'policy2': 2, 'policy3': 3} 24 | 25 | 26 | # Internal States per Mechanism 27 | def add(y, x): 28 | return lambda _g, step, sH, s, _input: (y, s[y] + x) 29 | 30 | def policies(_g, step, sH, s, _input): 31 | y = 'policies' 32 | x = _input 33 | return (y, x) 34 | 35 | 36 | # Genesis States 37 | genesis_states = { 38 | 'policies': {}, 39 | 's1': 0 40 | } 41 | 42 | variables = { 43 | 's1': add('s1', 1), 44 | "policies": policies 45 | } 46 | 47 | psubs = { 48 | "m1": { 49 | "policies": { 50 | "p1": p1m1, 51 | "p2": p2m1 52 | }, 53 | "variables": variables 54 | }, 55 | "m2": { 56 | "policies": { 57 | "p1": p1m2, 58 | "p2": p2m2 59 | }, 60 | "variables": variables 61 | }, 62 | "m3": { 63 | "policies": { 64 | "p1": p1m3, 65 | "p2": p2m3 66 | }, 67 | "variables": variables 68 | } 69 | } 70 | 71 | 72 | sim_config = config_sim( 73 | { 74 | "N": 1, 75 | "T": range(3), 76 | } 77 | ) 78 | 79 | append_configs( 80 | sim_configs=sim_config, 81 | initial_state=genesis_states, 82 | partial_state_update_blocks=psubs, 83 | policy_ops=[lambda a, b: a + b, lambda y: y * 2] # Default: lambda a, b: a + b 84 | ) 85 | 86 | exec_mode = ExecutionMode() 87 | single_proc_ctx = ExecutionContext(context=exec_mode.single_proc) 88 | run = Executor(exec_context=single_proc_ctx, configs=configs) 89 | 90 | raw_result, tensor_field = run.execute() 91 | result = pd.DataFrame(raw_result) 92 | 93 | print() 94 | print("Tensor Field:") 95 | print(tabulate(tensor_field, headers='keys', tablefmt='psql')) 96 | print("Output:") 97 | print(tabulate(result, headers='keys', tablefmt='psql')) 98 | print() -------------------------------------------------------------------------------- /documentation/examples/sys_model_A.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | from datetime import timedelta 3 | 4 | 5 | from cadCAD.configuration import append_configs 6 | from cadCAD.configuration.utils import bound_norm_random, config_sim, time_step, env_trigger 7 | 8 | seeds = { 9 | 'z': np.random.RandomState(1), 10 | 'a': np.random.RandomState(2), 11 | 'b': np.random.RandomState(3), 12 | 'c': np.random.RandomState(4) 13 | } 14 | 15 | 16 | # Policies per Mechanism 17 | def p1m1(_g, step, sH, s): 18 | return {'param1': 1} 19 | def p2m1(_g, step, sH, s): 20 | return {'param1': 1, 'param2': 4} 21 | 22 | def p1m2(_g, step, sH, s): 23 | return {'param1': 'a', 'param2': 2} 24 | def p2m2(_g, step, sH, s): 25 | return {'param1': 'b', 'param2': 4} 26 | 27 | def p1m3(_g, step, sH, s): 28 | return {'param1': ['c'], 'param2': np.array([10, 100])} 29 | def p2m3(_g, step, sH, s): 30 | return {'param1': ['d'], 'param2': np.array([20, 200])} 31 | 32 | 33 | # Internal States per Mechanism 34 | def s1m1(_g, step, sH, s, _input): 35 | y = 's1' 36 | x = s['s1'] + 1 37 | return (y, x) 38 | def s2m1(_g, step, sH, s, _input): 39 | y = 's2' 40 | x = _input['param2'] 41 | return (y, x) 42 | 43 | def s1m2(_g, step, sH, s, _input): 44 | y = 's1' 45 | x = s['s1'] + 1 46 | return (y, x) 47 | def s2m2(_g, step, sH, s, _input): 48 | y = 's2' 49 | x = _input['param2'] 50 | return (y, x) 51 | 52 | def s1m3(_g, step, sH, s, _input): 53 | y = 's1' 54 | x = s['s1'] + 1 55 | return (y, x) 56 | def s2m3(_g, step, sH, s, _input): 57 | y = 's2' 58 | x = _input['param2'] 59 | return (y, x) 60 | 61 | def policies(_g, step, sH, s, _input): 62 | y = 'policies' 63 | x = _input 64 | return (y, x) 65 | 66 | 67 | # Exogenous States 68 | proc_one_coef_A = 0.7 69 | proc_one_coef_B = 1.3 70 | 71 | def es3(_g, step, sH, s, _input): 72 | y = 's3' 73 | x = s['s3'] * bound_norm_random(seeds['a'], proc_one_coef_A, proc_one_coef_B) 74 | return (y, x) 75 | 76 | def es4(_g, step, sH, s, _input): 77 | y = 's4' 78 | x = s['s4'] * bound_norm_random(seeds['b'], proc_one_coef_A, proc_one_coef_B) 79 | return (y, x) 80 | 81 | def update_timestamp(_g, step, sH, s, _input): 82 | y = 'timestamp' 83 | return y, time_step(dt_str=s[y], dt_format='%Y-%m-%d %H:%M:%S', _timedelta=timedelta(days=0, minutes=0, seconds=1)) 84 | 85 | 86 | # Genesis States 87 | genesis_states = { 88 | 's1': 0.0, 89 | 's2': 0.0, 90 | 's3': 1.0, 91 | 's4': 1.0, 92 | 'timestamp': '2018-10-01 15:16:24' 93 | } 94 | 95 | 96 | # Environment Process 97 | # ToDo: Depreciation Waring for env_proc_trigger convention 98 | trigger_timestamps = ['2018-10-01 15:16:25', '2018-10-01 15:16:27', '2018-10-01 15:16:29'] 99 | env_processes = { 100 | "s3": [lambda _g, x: 5], 101 | "s4": env_trigger(3)(trigger_field='timestamp', trigger_vals=trigger_timestamps, funct_list=[lambda _g, x: 10]) 102 | } 103 | 104 | 105 | psubs = [ 106 | { 107 | "policies": { 108 | "b1": p1m1, 109 | "b2": p2m1 110 | }, 111 | "variables": { 112 | "s1": s1m1, 113 | "s2": s2m1, 114 | "s3": es3, 115 | "s4": es4, 116 | "timestamp": update_timestamp 117 | } 118 | }, 119 | { 120 | "policies": { 121 | "b1": p1m2, 122 | "b2": p2m2 123 | }, 124 | "variables": { 125 | "s1": s1m2, 126 | "s2": s2m2, 127 | # "s3": es3p1, 128 | # "s4": es4p2, 129 | } 130 | }, 131 | { 132 | "policies": { 133 | "b1": p1m3, 134 | "b2": p2m3 135 | }, 136 | "variables": { 137 | "s1": s1m3, 138 | "s2": s2m3, 139 | # "s3": es3p1, 140 | # "s4": es4p2, 141 | } 142 | } 143 | ] 144 | 145 | 146 | sim_config = config_sim( 147 | { 148 | "N": 2, 149 | "T": range(1), 150 | } 151 | ) 152 | 153 | append_configs( 154 | sim_configs=sim_config, 155 | initial_state=genesis_states, 156 | env_processes=env_processes, 157 | partial_state_update_blocks=psubs, 158 | policy_ops=[lambda a, b: a + b] 159 | ) -------------------------------------------------------------------------------- /documentation/examples/sys_model_AB_exec.py: -------------------------------------------------------------------------------- 1 | import pandas as pd 2 | from tabulate import tabulate 3 | from cadCAD.engine import ExecutionMode, ExecutionContext, Executor 4 | from documentation.examples import sys_model_A, sys_model_B 5 | from cadCAD import configs 6 | 7 | exec_mode = ExecutionMode() 8 | 9 | # # Multiple Processes Execution using Multiple System Model Configurations: 10 | # # sys_model_A & sys_model_B 11 | multi_proc_ctx = ExecutionContext(context=exec_mode.multi_proc) 12 | sys_model_AB_simulation = Executor(exec_context=multi_proc_ctx, configs=configs) 13 | 14 | i = 0 15 | config_names = ['sys_model_A', 'sys_model_B'] 16 | for sys_model_AB_raw_result, sys_model_AB_tensor_field in sys_model_AB_simulation.execute(): 17 | sys_model_AB_result = pd.DataFrame(sys_model_AB_raw_result) 18 | print() 19 | print(f"Tensor Field: {config_names[i]}") 20 | print(tabulate(sys_model_AB_tensor_field, headers='keys', tablefmt='psql')) 21 | print("Result: System Events DataFrame:") 22 | print(tabulate(sys_model_AB_result, headers='keys', tablefmt='psql')) 23 | print() 24 | i += 1 -------------------------------------------------------------------------------- /documentation/examples/sys_model_A_exec.py: -------------------------------------------------------------------------------- 1 | import pandas as pd 2 | from tabulate import tabulate 3 | from cadCAD.engine import ExecutionMode, ExecutionContext, Executor 4 | from documentation.examples import sys_model_A 5 | from cadCAD import configs 6 | 7 | exec_mode = ExecutionMode() 8 | 9 | # Single Process Execution using a Single System Model Configuration: 10 | # sys_model_A 11 | sys_model_A = [configs[0]] # sys_model_A 12 | single_proc_ctx = ExecutionContext(context=exec_mode.single_proc) 13 | sys_model_A_simulation = Executor(exec_context=single_proc_ctx, configs=sys_model_A) 14 | 15 | sys_model_A_raw_result, sys_model_A_tensor_field = sys_model_A_simulation.execute() 16 | sys_model_A_result = pd.DataFrame(sys_model_A_raw_result) 17 | print() 18 | print("Tensor Field: sys_model_A") 19 | print(tabulate(sys_model_A_tensor_field, headers='keys', tablefmt='psql')) 20 | print("Result: System Events DataFrame") 21 | print(tabulate(sys_model_A_result, headers='keys', tablefmt='psql')) 22 | print() -------------------------------------------------------------------------------- /documentation/examples/sys_model_B.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | from datetime import timedelta 3 | 4 | from cadCAD.configuration import append_configs 5 | from cadCAD.configuration.utils import bound_norm_random, config_sim, env_trigger, time_step 6 | 7 | seeds = { 8 | 'z': np.random.RandomState(1), 9 | 'a': np.random.RandomState(2), 10 | 'b': np.random.RandomState(3), 11 | 'c': np.random.RandomState(3) 12 | } 13 | 14 | 15 | # Policies per Mechanism 16 | def p1m1(_g, step, sH, s): 17 | return {'param1': 1} 18 | def p2m1(_g, step, sH, s): 19 | return {'param2': 4} 20 | 21 | def p1m2(_g, step, sH, s): 22 | return {'param1': 'a', 'param2': 2} 23 | def p2m2(_g, step, sH, s): 24 | return {'param1': 'b', 'param2': 4} 25 | 26 | def p1m3(_g, step, sH, s): 27 | return {'param1': ['c'], 'param2': np.array([10, 100])} 28 | def p2m3(_g, step, sH, s): 29 | return {'param1': ['d'], 'param2': np.array([20, 200])} 30 | 31 | 32 | # Internal States per Mechanism 33 | def s1m1(_g, step, sH, s, _input): 34 | y = 's1' 35 | x = _input['param1'] 36 | return (y, x) 37 | def s2m1(_g, step, sH, s, _input): 38 | y = 's2' 39 | x = _input['param2'] 40 | return (y, x) 41 | 42 | def s1m2(_g, step, sH, s, _input): 43 | y = 's1' 44 | x = _input['param1'] 45 | return (y, x) 46 | def s2m2(_g, step, sH, s, _input): 47 | y = 's2' 48 | x = _input['param2'] 49 | return (y, x) 50 | 51 | def s1m3(_g, step, sH, s, _input): 52 | y = 's1' 53 | x = _input['param1'] 54 | return (y, x) 55 | def s2m3(_g, step, sH, s, _input): 56 | y = 's2' 57 | x = _input['param2'] 58 | return (y, x) 59 | 60 | 61 | # Exogenous States 62 | proc_one_coef_A = 0.7 63 | proc_one_coef_B = 1.3 64 | 65 | def es3(_g, step, sH, s, _input): 66 | y = 's3' 67 | x = s['s3'] * bound_norm_random(seeds['a'], proc_one_coef_A, proc_one_coef_B) 68 | return (y, x) 69 | 70 | def es4(_g, step, sH, s, _input): 71 | y = 's4' 72 | x = s['s4'] * bound_norm_random(seeds['b'], proc_one_coef_A, proc_one_coef_B) 73 | return (y, x) 74 | 75 | def update_timestamp(_g, step, sH, s, _input): 76 | y = 'timestamp' 77 | return y, time_step(dt_str=s[y], dt_format='%Y-%m-%d %H:%M:%S', _timedelta=timedelta(days=0, minutes=0, seconds=1)) 78 | 79 | 80 | # Genesis States 81 | genesis_states = { 82 | 's1': 0, 83 | 's2': 0, 84 | 's3': 1, 85 | 's4': 1, 86 | 'timestamp': '2018-10-01 15:16:24' 87 | } 88 | 89 | 90 | # Environment Process 91 | # ToDo: Depreciation Waring for env_proc_trigger convention 92 | trigger_timestamps = ['2018-10-01 15:16:25', '2018-10-01 15:16:27', '2018-10-01 15:16:29'] 93 | env_processes = { 94 | "s3": [lambda _g, x: 5], 95 | "s4": env_trigger(3)(trigger_field='timestamp', trigger_vals=trigger_timestamps, funct_list=[lambda _g, x: 10]) 96 | } 97 | 98 | psubs = [ 99 | { 100 | "policies": { 101 | "b1": p1m1, 102 | # "b2": p2m1 103 | }, 104 | "states": { 105 | "s1": s1m1, 106 | # "s2": s2m1 107 | "s3": es3, 108 | "s4": es4, 109 | "timestep": update_timestamp 110 | } 111 | }, 112 | { 113 | "policies": { 114 | "b1": p1m2, 115 | # "b2": p2m2 116 | }, 117 | "states": { 118 | "s1": s1m2, 119 | # "s2": s2m2 120 | } 121 | }, 122 | { 123 | "policies": { 124 | "b1": p1m3, 125 | "b2": p2m3 126 | }, 127 | "states": { 128 | "s1": s1m3, 129 | "s2": s2m3 130 | } 131 | } 132 | ] 133 | 134 | 135 | sim_config = config_sim( 136 | { 137 | "N": 2, 138 | "T": range(5), 139 | } 140 | ) 141 | 142 | append_configs( 143 | sim_configs=sim_config, 144 | initial_state=genesis_states, 145 | env_processes=env_processes, 146 | partial_state_update_blocks=psubs 147 | ) -------------------------------------------------------------------------------- /documentation/examples/sys_model_B_exec.py: -------------------------------------------------------------------------------- 1 | import pandas as pd 2 | from tabulate import tabulate 3 | # The following imports NEED to be in the exact order 4 | from cadCAD.engine import ExecutionMode, ExecutionContext, Executor 5 | from documentation.examples import sys_model_B 6 | from cadCAD import configs 7 | 8 | exec_mode = ExecutionMode() 9 | 10 | print("Simulation Execution: Single Configuration") 11 | print() 12 | first_config = configs # only contains sys_model_B 13 | single_proc_ctx = ExecutionContext(context=exec_mode.single_proc) 14 | run = Executor(exec_context=single_proc_ctx, configs=first_config) 15 | 16 | raw_result, tensor_field = run.execute() 17 | result = pd.DataFrame(raw_result) 18 | print() 19 | print("Tensor Field: sys_model_B") 20 | print(tabulate(tensor_field, headers='keys', tablefmt='psql')) 21 | print("Output:") 22 | print(tabulate(result, headers='keys', tablefmt='psql')) 23 | print() 24 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | pandas 2 | numpy 3 | scipy 4 | funcy 5 | cadCAD 6 | jupyter 7 | matplotlib 8 | seaborn 9 | networkx 10 | --------------------------------------------------------------------------------