├── .gitignore ├── BondingCurve ├── .ipynb_checkpoints │ └── cic_initialization-checkpoint.ipynb ├── CICecosubsystem.jpeg ├── CICecosystem.jpeg ├── CICinvariant.jpeg ├── GrassrootsEconomicsCICcontractconservation.jpeg └── cic_initialization.ipynb ├── Colab ├── .ipynb_checkpoints │ ├── CIC_Network_cadCAD_model-checkpoint.ipynb │ └── CIC_Network_cadCAD_model_params-checkpoint.ipynb ├── CIC_Network_cadCAD_model.ipynb ├── CIC_Network_cadCAD_model_params.ipynb └── images │ ├── agentDistribution.png │ ├── dualoperator.png │ ├── gap_statistic.png │ ├── graph.png │ ├── pca.png │ └── v4differentialspec.png ├── Documents └── 2020.05.25_RedCrossCICRoleTaxonomy.pdf ├── LICENSE ├── README.md ├── Simulation ├── .gitignore ├── .ipynb_checkpoints │ └── CIC_Network_cadCAD_model-checkpoint.ipynb ├── CIC_Network_cadCAD_model.ipynb ├── images │ ├── agentDistribution.png │ ├── dualoperator.png │ ├── experiments.png │ ├── gap_statistic.png │ ├── graph.png │ ├── graphNoFees.png │ ├── pca.png │ └── v4differentialspec.png └── model │ ├── .DS_Store │ ├── __pycache__ │ ├── economyconfig.cpython-36.pyc │ ├── economyconfig.cpython-37.pyc │ ├── economyconfig.cpython-38.pyc │ ├── genesis_states.cpython-36.pyc │ ├── genesis_states.cpython-37.pyc │ ├── genesis_states.cpython-38.pyc │ ├── partial_state_update_block.cpython-36.pyc │ ├── partial_state_update_block.cpython-37.pyc │ └── partial_state_update_block.cpython-38.pyc │ ├── economyconfig.py │ ├── genesis_states.py │ ├── partial_state_update_block.py │ └── parts │ ├── __pycache__ │ ├── designed.cpython-36.pyc │ ├── designed.cpython-37.pyc │ ├── exogenousProcesses.cpython-36.pyc │ ├── exogenousProcesses.cpython-37.pyc │ ├── exogenousProcesses.cpython-38.pyc │ ├── initialization.cpython-37.pyc │ ├── initialization.cpython-38.pyc │ ├── kpis.cpython-36.pyc │ ├── kpis.cpython-37.pyc │ ├── kpis.cpython-38.pyc │ ├── operatorentity.cpython-37.pyc │ ├── operatorentity.cpython-38.pyc │ ├── subpopulation_clusters.cpython-37.pyc │ ├── subpopulation_clusters.cpython-38.pyc │ ├── supportingFunctions.cpython-37.pyc │ ├── supportingFunctions.cpython-38.pyc │ ├── system.cpython-37.pyc │ └── system.cpython-38.pyc │ ├── exogenousProcesses.py │ ├── initialization.py │ ├── kpis.py │ ├── operatorentity.py │ ├── subpopulation_clusters.py │ ├── supportingFunctions.py │ └── system.py ├── Simulation_param ├── .ipynb_checkpoints │ └── CIC_Network_cadCAD_model_params_Template-checkpoint.ipynb ├── CIC_Network_cadCAD_model_params_Template.ipynb ├── images │ ├── agentDistribution.png │ ├── dualoperator.png │ ├── experiments.png │ ├── gap_statistic.png │ ├── graph.png │ ├── pca.png │ └── v4differentialspec.png └── model │ ├── economyconfig.py │ ├── genesis_states.py │ ├── partial_state_update_block.py │ └── parts │ ├── __pycache__ │ ├── designed.cpython-36.pyc │ ├── designed.cpython-37.pyc │ ├── exogenousProcesses.cpython-36.pyc │ ├── exogenousProcesses.cpython-37.pyc │ ├── initialization.cpython-37.pyc │ ├── kpis.cpython-36.pyc │ ├── kpis.cpython-37.pyc │ ├── operatorentity.cpython-37.pyc │ ├── subpopulation_clusters.cpython-37.pyc │ ├── supportingFunctions.cpython-37.pyc │ └── system.cpython-37.pyc │ ├── exogenousProcesses.py │ ├── initialization.py │ ├── kpis.py │ ├── operatorentity.py │ ├── subpopulation_clusters.py │ ├── supportingFunctions.py │ └── system.py └── SubpopulationGenerator ├── .ipynb_checkpoints └── Subpopulation_Construction-checkpoint.ipynb ├── Subpopulation_Construction.ipynb ├── clusters.csv ├── data ├── sarafu_xDAI_tx_all_pub_all_time_12May2020.csv └── sarafu_xDAI_users_all_pub_all_time_12May2020.csv ├── gap_statistic.png ├── geographic ├── .ipynb_checkpoints │ └── Subpopulation_Construction-checkpoint.ipynb ├── Subpopulation_Construction.ipynb └── data │ └── transactions_users_xDAI_26_July_2020.zip └── pca.png /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | Simulation_param/__pycache__ 3 | Simulation_param/model/__pycache__ 4 | Simulation_param/model/parts/__pycache__ 5 | *.csv 6 | -------------------------------------------------------------------------------- /BondingCurve/CICecosubsystem.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlockScience/Community_Inclusion_Currencies/a8de2d06723759c6d2381a06f0aa397d3aadc847/BondingCurve/CICecosubsystem.jpeg -------------------------------------------------------------------------------- /BondingCurve/CICecosystem.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlockScience/Community_Inclusion_Currencies/a8de2d06723759c6d2381a06f0aa397d3aadc847/BondingCurve/CICecosystem.jpeg -------------------------------------------------------------------------------- /BondingCurve/CICinvariant.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlockScience/Community_Inclusion_Currencies/a8de2d06723759c6d2381a06f0aa397d3aadc847/BondingCurve/CICinvariant.jpeg -------------------------------------------------------------------------------- /BondingCurve/GrassrootsEconomicsCICcontractconservation.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlockScience/Community_Inclusion_Currencies/a8de2d06723759c6d2381a06f0aa397d3aadc847/BondingCurve/GrassrootsEconomicsCICcontractconservation.jpeg -------------------------------------------------------------------------------- /Colab/images/agentDistribution.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlockScience/Community_Inclusion_Currencies/a8de2d06723759c6d2381a06f0aa397d3aadc847/Colab/images/agentDistribution.png -------------------------------------------------------------------------------- /Colab/images/dualoperator.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlockScience/Community_Inclusion_Currencies/a8de2d06723759c6d2381a06f0aa397d3aadc847/Colab/images/dualoperator.png -------------------------------------------------------------------------------- /Colab/images/gap_statistic.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlockScience/Community_Inclusion_Currencies/a8de2d06723759c6d2381a06f0aa397d3aadc847/Colab/images/gap_statistic.png -------------------------------------------------------------------------------- /Colab/images/graph.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlockScience/Community_Inclusion_Currencies/a8de2d06723759c6d2381a06f0aa397d3aadc847/Colab/images/graph.png -------------------------------------------------------------------------------- /Colab/images/pca.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlockScience/Community_Inclusion_Currencies/a8de2d06723759c6d2381a06f0aa397d3aadc847/Colab/images/pca.png -------------------------------------------------------------------------------- /Colab/images/v4differentialspec.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlockScience/Community_Inclusion_Currencies/a8de2d06723759c6d2381a06f0aa397d3aadc847/Colab/images/v4differentialspec.png -------------------------------------------------------------------------------- /Documents/2020.05.25_RedCrossCICRoleTaxonomy.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlockScience/Community_Inclusion_Currencies/a8de2d06723759c6d2381a06f0aa397d3aadc847/Documents/2020.05.25_RedCrossCICRoleTaxonomy.pdf -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU LESSER GENERAL PUBLIC LICENSE 2 | Version 3, 29 June 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | 9 | This version of the GNU Lesser General Public License incorporates 10 | the terms and conditions of version 3 of the GNU General Public 11 | License, supplemented by the additional permissions listed below. 12 | 13 | 0. Additional Definitions. 14 | 15 | As used herein, "this License" refers to version 3 of the GNU Lesser 16 | General Public License, and the "GNU GPL" refers to version 3 of the GNU 17 | General Public License. 18 | 19 | "The Library" refers to a covered work governed by this License, 20 | other than an Application or a Combined Work as defined below. 21 | 22 | An "Application" is any work that makes use of an interface provided 23 | by the Library, but which is not otherwise based on the Library. 24 | Defining a subclass of a class defined by the Library is deemed a mode 25 | of using an interface provided by the Library. 26 | 27 | A "Combined Work" is a work produced by combining or linking an 28 | Application with the Library. The particular version of the Library 29 | with which the Combined Work was made is also called the "Linked 30 | Version". 31 | 32 | The "Minimal Corresponding Source" for a Combined Work means the 33 | Corresponding Source for the Combined Work, excluding any source code 34 | for portions of the Combined Work that, considered in isolation, are 35 | based on the Application, and not on the Linked Version. 36 | 37 | The "Corresponding Application Code" for a Combined Work means the 38 | object code and/or source code for the Application, including any data 39 | and utility programs needed for reproducing the Combined Work from the 40 | Application, but excluding the System Libraries of the Combined Work. 41 | 42 | 1. Exception to Section 3 of the GNU GPL. 43 | 44 | You may convey a covered work under sections 3 and 4 of this License 45 | without being bound by section 3 of the GNU GPL. 46 | 47 | 2. Conveying Modified Versions. 48 | 49 | If you modify a copy of the Library, and, in your modifications, a 50 | facility refers to a function or data to be supplied by an Application 51 | that uses the facility (other than as an argument passed when the 52 | facility is invoked), then you may convey a copy of the modified 53 | version: 54 | 55 | a) under this License, provided that you make a good faith effort to 56 | ensure that, in the event an Application does not supply the 57 | function or data, the facility still operates, and performs 58 | whatever part of its purpose remains meaningful, or 59 | 60 | b) under the GNU GPL, with none of the additional permissions of 61 | this License applicable to that copy. 62 | 63 | 3. Object Code Incorporating Material from Library Header Files. 64 | 65 | The object code form of an Application may incorporate material from 66 | a header file that is part of the Library. You may convey such object 67 | code under terms of your choice, provided that, if the incorporated 68 | material is not limited to numerical parameters, data structure 69 | layouts and accessors, or small macros, inline functions and templates 70 | (ten or fewer lines in length), you do both of the following: 71 | 72 | a) Give prominent notice with each copy of the object code that the 73 | Library is used in it and that the Library and its use are 74 | covered by this License. 75 | 76 | b) Accompany the object code with a copy of the GNU GPL and this license 77 | document. 78 | 79 | 4. Combined Works. 80 | 81 | You may convey a Combined Work under terms of your choice that, 82 | taken together, effectively do not restrict modification of the 83 | portions of the Library contained in the Combined Work and reverse 84 | engineering for debugging such modifications, if you also do each of 85 | the following: 86 | 87 | a) Give prominent notice with each copy of the Combined Work that 88 | the Library is used in it and that the Library and its use are 89 | covered by this License. 90 | 91 | b) Accompany the Combined Work with a copy of the GNU GPL and this license 92 | document. 93 | 94 | c) For a Combined Work that displays copyright notices during 95 | execution, include the copyright notice for the Library among 96 | these notices, as well as a reference directing the user to the 97 | copies of the GNU GPL and this license document. 98 | 99 | d) Do one of the following: 100 | 101 | 0) Convey the Minimal Corresponding Source under the terms of this 102 | License, and the Corresponding Application Code in a form 103 | suitable for, and under terms that permit, the user to 104 | recombine or relink the Application with a modified version of 105 | the Linked Version to produce a modified Combined Work, in the 106 | manner specified by section 6 of the GNU GPL for conveying 107 | Corresponding Source. 108 | 109 | 1) Use a suitable shared library mechanism for linking with the 110 | Library. A suitable mechanism is one that (a) uses at run time 111 | a copy of the Library already present on the user's computer 112 | system, and (b) will operate properly with a modified version 113 | of the Library that is interface-compatible with the Linked 114 | Version. 115 | 116 | e) Provide Installation Information, but only if you would otherwise 117 | be required to provide such information under section 6 of the 118 | GNU GPL, and only to the extent that such information is 119 | necessary to install and execute a modified version of the 120 | Combined Work produced by recombining or relinking the 121 | Application with a modified version of the Linked Version. (If 122 | you use option 4d0, the Installation Information must accompany 123 | the Minimal Corresponding Source and Corresponding Application 124 | Code. If you use option 4d1, you must provide the Installation 125 | Information in the manner specified by section 6 of the GNU GPL 126 | for conveying Corresponding Source.) 127 | 128 | 5. Combined Libraries. 129 | 130 | You may place library facilities that are a work based on the 131 | Library side by side in a single library together with other library 132 | facilities that are not Applications and are not covered by this 133 | License, and convey such a combined library under terms of your 134 | choice, if you do both of the following: 135 | 136 | a) Accompany the combined library with a copy of the same work based 137 | on the Library, uncombined with any other library facilities, 138 | conveyed under the terms of this License. 139 | 140 | b) Give prominent notice with the combined library that part of it 141 | is a work based on the Library, and explaining where to find the 142 | accompanying uncombined form of the same work. 143 | 144 | 6. Revised Versions of the GNU Lesser General Public License. 145 | 146 | The Free Software Foundation may publish revised and/or new versions 147 | of the GNU Lesser General Public License from time to time. Such new 148 | versions will be similar in spirit to the present version, but may 149 | differ in detail to address new problems or concerns. 150 | 151 | Each version is given a distinguishing version number. If the 152 | Library as you received it specifies that a certain numbered version 153 | of the GNU Lesser General Public License "or any later version" 154 | applies to it, you have the option of following the terms and 155 | conditions either of that published version or of any later version 156 | published by the Free Software Foundation. If the Library as you 157 | received it does not specify a version number of the GNU Lesser 158 | General Public License, you may choose any version of the GNU Lesser 159 | General Public License ever published by the Free Software Foundation. 160 | 161 | If the Library as you received it specifies that a proxy can decide 162 | whether future versions of the GNU Lesser General Public License shall 163 | apply, that proxy's public statement of acceptance of any version is 164 | permanent authorization for you to choose that version for the 165 | Library. 166 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Community_Inclusion_Currencies 2 | Repository for Complex Systems model of the [Grassroots Economics](https://www.grassrootseconomics.org/) Community Inclusion Currencies ([CIC](http://cichub.org/)) project with the Red Cross. The Colab notebooks are able to be run and played with by anyone who uses the link. Modeling is built in [cadCAD](https://cadcad.org/). 3 | 4 | ## What is cadCAD? 5 | cadCAD (complex adaptive dynamics Computer-Aided Design) is a python based modeling framework for research, validation, and Computer Aided Design of complex systems. Given a model of a complex system, cadCAD can simulate the impact that a set of actions might have on it. This helps users make informed, rigorously tested decisions on how best to modify or interact with the system in order to achieve their goals. cadCAD supports different system modeling approaches and can be easily integrated with common empirical data science workflows. Monte Carlo methods, A/B testing and parameter sweeping features are natively supported and optimized for. 6 | 7 | See [cadCAD on Github](https://github.com/BlockScience/cadCAD/tree/master/tutorials) for some tutorials on how to use cadCAD. 8 | 9 | ## Reproducibility 10 | In order to reperform this code, we recommend the researcher use the following link to download https://www.anaconda.com/products/individual to download Python 3.7+. To install the specific version of cadCAD this repository was built with, run the following code: 11 | ```pip install cadCAD==0.4.22``` 12 | 13 | To download the specific version of this code, run the following command in your command line: 14 | 15 | ```git clone https://github.com/BlockScience/Community_Inclusion_Currencies.git``` 16 | 17 | Then run ```cd Community_Inclusion_Currencies``` to enter the repository. Finally, run ```jupyter notebook``` to open a notebook server to run the various notebooks in this repository. 18 | 19 | 20 | ## Simulations 21 | 22 | ### Theory work 23 | [Click here](https://nbviewer.jupyter.org/github/BlockScience/Community_Inclusion_Currencies/blob/master/BondingCurve/cic_initialization.ipynb) 24 | 25 | 26 | ### Subpopulation initialization 27 | [Click here](https://nbviewer.jupyter.org/github/BlockScience/Community_Inclusion_Currencies/blob/master/SubpopulationGenerator/Subpopulation_Construction.ipynb) 28 | 29 | ### Simulation work 30 | [Click here](https://nbviewer.jupyter.org/github/BlockScience/Community_Inclusion_Currencies/blob/master/Simulation/CIC_Network_cadCAD_model.ipynb) 31 | 32 | ### Parameter sweep 33 | [Click here](https://nbviewer.jupyter.org/github/BlockScience/Community_Inclusion_Currencies/blob/master/Simulation_param/CIC_Network_cadCAD_model_params_Template.ipynb) 34 | 35 | ### Colab - last refresh and synchronisation date: 5-26-2020. 36 | 37 | #### Note: Colabs use 10 instead of 50 clusters for speed. 38 | [Click here to get to an interactive notebook](https://colab.research.google.com/drive/1JkpX6UwJAezxUkVVj2SHFah-eNUzEif0) 39 | 40 | [Click here to for an interactive notebook with a parameter sweep](https://colab.research.google.com/drive/1_vtPeTrEEq95RlyHu9awSRMuXUgr0WAt) 41 | 42 | 43 | ## Role Taxonomy 44 | Block Science produced a role taxonomy of the CIC project. [Click here](https://gitlab.com/grassrootseconomics/cic-modeling/-/blob/master/Documents/2020.05.25_RedCrossCICRoleTaxonomy.pdf) to view it. 45 | ## Concepts addressed 46 | 47 | #### Bonding Curves 48 | * [From Curved Bonding to Configuration Spaces](https://epub.wu.ac.at/7385) 49 | 50 | #### Systems Thinking 51 | * https://community.cadcad.org/t/introduction-to-systems-thinking/18 52 | * https://community.cadcad.org/t/working-glossary-of-systems-concepts/17 53 | 54 | #### cadCAD 55 | * https://community.cadcad.org/t/introduction-to-cadcad/15 56 | * https://community.cadcad.org/t/putting-cadcad-in-context/19 57 | * https://github.com/BlockScience/cadCAD/tree/master/tutorials 58 | 59 | #### Token Engineering 60 | * https://blog.oceanprotocol.com/towards-a-practice-of-token-engineering-b02feeeff7ca 61 | * https://assets.pubpub.org/sy02t720/31581340240758.pdf 62 | 63 | #### Community Currencies 64 | * https://www.investopedia.com/terms/c/community_currencies.asp 65 | 66 | #### Subpopulation modeling 67 | 68 | #### Complex systems 69 | * https://www.frontiersin.org/articles/10.3389/fams.2015.00007/full 70 | * https://epub.wu.ac.at/7433/1/zargham_paruch_shorish.pdf 71 | 72 | #### Network theory 73 | 74 | #### Economics 75 | * https://ergodicityeconomics.com/lecture-notes/ 76 | 77 | #### Systems Engineering 78 | * http://systems.hitchins.net/systems-engineering/se-monographs/seessence.pdf 79 | 80 | 81 | -------------------------------------------------------------------------------- /Simulation/.gitignore: -------------------------------------------------------------------------------- 1 | .vscode/ 2 | notes.txt -------------------------------------------------------------------------------- /Simulation/images/agentDistribution.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlockScience/Community_Inclusion_Currencies/a8de2d06723759c6d2381a06f0aa397d3aadc847/Simulation/images/agentDistribution.png -------------------------------------------------------------------------------- /Simulation/images/dualoperator.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlockScience/Community_Inclusion_Currencies/a8de2d06723759c6d2381a06f0aa397d3aadc847/Simulation/images/dualoperator.png -------------------------------------------------------------------------------- /Simulation/images/experiments.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlockScience/Community_Inclusion_Currencies/a8de2d06723759c6d2381a06f0aa397d3aadc847/Simulation/images/experiments.png -------------------------------------------------------------------------------- /Simulation/images/gap_statistic.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlockScience/Community_Inclusion_Currencies/a8de2d06723759c6d2381a06f0aa397d3aadc847/Simulation/images/gap_statistic.png -------------------------------------------------------------------------------- /Simulation/images/graph.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlockScience/Community_Inclusion_Currencies/a8de2d06723759c6d2381a06f0aa397d3aadc847/Simulation/images/graph.png -------------------------------------------------------------------------------- /Simulation/images/graphNoFees.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlockScience/Community_Inclusion_Currencies/a8de2d06723759c6d2381a06f0aa397d3aadc847/Simulation/images/graphNoFees.png -------------------------------------------------------------------------------- /Simulation/images/pca.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlockScience/Community_Inclusion_Currencies/a8de2d06723759c6d2381a06f0aa397d3aadc847/Simulation/images/pca.png -------------------------------------------------------------------------------- /Simulation/images/v4differentialspec.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlockScience/Community_Inclusion_Currencies/a8de2d06723759c6d2381a06f0aa397d3aadc847/Simulation/images/v4differentialspec.png -------------------------------------------------------------------------------- /Simulation/model/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlockScience/Community_Inclusion_Currencies/a8de2d06723759c6d2381a06f0aa397d3aadc847/Simulation/model/.DS_Store -------------------------------------------------------------------------------- /Simulation/model/__pycache__/economyconfig.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlockScience/Community_Inclusion_Currencies/a8de2d06723759c6d2381a06f0aa397d3aadc847/Simulation/model/__pycache__/economyconfig.cpython-36.pyc -------------------------------------------------------------------------------- /Simulation/model/__pycache__/economyconfig.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlockScience/Community_Inclusion_Currencies/a8de2d06723759c6d2381a06f0aa397d3aadc847/Simulation/model/__pycache__/economyconfig.cpython-37.pyc -------------------------------------------------------------------------------- /Simulation/model/__pycache__/economyconfig.cpython-38.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlockScience/Community_Inclusion_Currencies/a8de2d06723759c6d2381a06f0aa397d3aadc847/Simulation/model/__pycache__/economyconfig.cpython-38.pyc -------------------------------------------------------------------------------- /Simulation/model/__pycache__/genesis_states.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlockScience/Community_Inclusion_Currencies/a8de2d06723759c6d2381a06f0aa397d3aadc847/Simulation/model/__pycache__/genesis_states.cpython-36.pyc -------------------------------------------------------------------------------- /Simulation/model/__pycache__/genesis_states.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlockScience/Community_Inclusion_Currencies/a8de2d06723759c6d2381a06f0aa397d3aadc847/Simulation/model/__pycache__/genesis_states.cpython-37.pyc -------------------------------------------------------------------------------- /Simulation/model/__pycache__/genesis_states.cpython-38.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlockScience/Community_Inclusion_Currencies/a8de2d06723759c6d2381a06f0aa397d3aadc847/Simulation/model/__pycache__/genesis_states.cpython-38.pyc -------------------------------------------------------------------------------- /Simulation/model/__pycache__/partial_state_update_block.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlockScience/Community_Inclusion_Currencies/a8de2d06723759c6d2381a06f0aa397d3aadc847/Simulation/model/__pycache__/partial_state_update_block.cpython-36.pyc -------------------------------------------------------------------------------- /Simulation/model/__pycache__/partial_state_update_block.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlockScience/Community_Inclusion_Currencies/a8de2d06723759c6d2381a06f0aa397d3aadc847/Simulation/model/__pycache__/partial_state_update_block.cpython-37.pyc -------------------------------------------------------------------------------- /Simulation/model/__pycache__/partial_state_update_block.cpython-38.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlockScience/Community_Inclusion_Currencies/a8de2d06723759c6d2381a06f0aa397d3aadc847/Simulation/model/__pycache__/partial_state_update_block.cpython-38.pyc -------------------------------------------------------------------------------- /Simulation/model/economyconfig.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 | 10 | from .genesis_states import genesis_states 11 | from .partial_state_update_block import partial_state_update_block 12 | 13 | 14 | sim_config = config_sim({ 15 | 'N': 5, 16 | 'T': range(100), # day 17 | }) 18 | 19 | 20 | env_processes = {} 21 | 22 | exp = Experiment() 23 | 24 | exp.append_configs( 25 | sim_configs=sim_config, 26 | initial_state=genesis_states, 27 | env_processes=env_processes, 28 | partial_state_update_blocks=partial_state_update_block 29 | ) 30 | 31 | -------------------------------------------------------------------------------- /Simulation/model/genesis_states.py: -------------------------------------------------------------------------------- 1 | from .parts.initialization import * 2 | import pandas as pd 3 | 4 | genesis_states = { 5 | # initial states of the economy 6 | 'network': create_network(), # networkx market 7 | 'KPIDemand': {}, 8 | 'KPISpend': {}, 9 | 'KPISpendOverDemand': {}, 10 | 'VelocityOfMoney': 0, 11 | 'startingBalance': {}, 12 | '30_day_spend': {}, 13 | 'withdraw': {}, 14 | 'outboundAgents': [], 15 | 'inboundAgents': [], 16 | 'operatorFiatBalance': initialOperatingFiatBalance, 17 | 'operatorCICBalance': initialOperatingCICBalance, 18 | 'fundsInProcess': {'timestep': [], 'decision': [], 'cic': [], 'shilling': []}, 19 | 'totalDistributedToAgents': 0, 20 | 'totalMinted': 0, 21 | 'totalBurned': 0, 22 | 'exitFeeRevenue': 0, 23 | 'drip': initial_drip_amount 24 | } 25 | -------------------------------------------------------------------------------- /Simulation/model/partial_state_update_block.py: -------------------------------------------------------------------------------- 1 | from .parts.exogenousProcesses import * 2 | from .parts.kpis import * 3 | from .parts.system import * 4 | from .parts.operatorentity import * 5 | 6 | partial_state_update_block = { 7 | # Exogenous 8 | 'Exogenous': { 9 | 'policies': { 10 | }, 11 | 'variables': { 12 | 'startingBalance': startingBalance, 13 | '30_day_spend': update_30_day_spend, 14 | 'network': clear_agent_activity, 15 | } 16 | }, 17 | 'drip': { 18 | 'policies': { 19 | 'action': calculate_drip, 20 | }, 21 | 'variables': { 22 | 'operatorFiatBalance': redCrossDrop, 23 | 'drip': update_drip 24 | } 25 | }, 26 | # Users 27 | 'Behaviors': { 28 | 'policies': { 29 | 'action': choose_agents 30 | }, 31 | 'variables': { 32 | 'network': update_agent_activity, 33 | 'outboundAgents': update_outboundAgents, 34 | 'inboundAgents': update_inboundAgents 35 | } 36 | }, 37 | 'Spend allocation': { 38 | 'policies': { 39 | 'action': spend_allocation 40 | }, 41 | 'variables': { 42 | 'network': update_node_spend 43 | } 44 | }, 45 | 'Withdraw behavior': { 46 | 'policies': { 47 | 'action': withdraw_calculation 48 | }, 49 | 'variables': { 50 | 'withdraw': update_withdraw, 51 | 'network': update_network_withraw, 52 | 'operatorFiatBalance': update_operatorFiatBalance_withdraw, 53 | 'operatorCICBalance': update_operatorCICBalance_withdraw 54 | } 55 | }, 56 | # Operator 57 | 'Fees': { 58 | 'policies': { 59 | 'action': fee_calculation 60 | }, 61 | 'variables': { 62 | 'exitFeeRevenue': update_exit_fee_revenue, 63 | 'operatorCICBalance': update_operator_balance_with_fee, 64 | 'withdraw': deduct_fee_from_withdrawal 65 | } 66 | 67 | }, 68 | 'Operator Disburse to Agents': { 69 | 'policies': { 70 | 'action': disbursement_to_agents 71 | }, 72 | 'variables': { 73 | 'network': update_agent_tokens, 74 | 'operatorCICBalance': update_operator_FromDisbursements, 75 | 'totalDistributedToAgents': update_totalDistributedToAgents 76 | } 77 | }, 78 | 'Operator Inventory Control': { 79 | 'policies': { 80 | 'action': inventory_controller 81 | }, 82 | 'variables': { 83 | 'operatorFiatBalance': update_operator_fiatBalance, 84 | 'operatorCICBalance': update_operator_cicBalance, 85 | 'totalMinted': update_totalMinted, 86 | 'totalBurned': update_totalBurned, 87 | 'fundsInProcess': update_fundsInProcess, 88 | 'network': update_network_mintBurn 89 | } 90 | }, 91 | 92 | # KPIs 93 | 'KPIs': { 94 | 'policies': { 95 | 'action': kpis 96 | }, 97 | 'variables': { 98 | 'KPIDemand': update_KPIDemand, 99 | 'KPISpend': update_KPISpend, 100 | 'KPISpendOverDemand': update_KPISpendOverDemand 101 | } 102 | }, 103 | 'Velocity': { 104 | 'policies': { 105 | 'action': velocity_of_money 106 | }, 107 | 'variables': { 108 | 109 | 'VelocityOfMoney': update_velocity_of_money 110 | } 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /Simulation/model/parts/__pycache__/designed.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlockScience/Community_Inclusion_Currencies/a8de2d06723759c6d2381a06f0aa397d3aadc847/Simulation/model/parts/__pycache__/designed.cpython-36.pyc -------------------------------------------------------------------------------- /Simulation/model/parts/__pycache__/designed.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlockScience/Community_Inclusion_Currencies/a8de2d06723759c6d2381a06f0aa397d3aadc847/Simulation/model/parts/__pycache__/designed.cpython-37.pyc -------------------------------------------------------------------------------- /Simulation/model/parts/__pycache__/exogenousProcesses.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlockScience/Community_Inclusion_Currencies/a8de2d06723759c6d2381a06f0aa397d3aadc847/Simulation/model/parts/__pycache__/exogenousProcesses.cpython-36.pyc -------------------------------------------------------------------------------- /Simulation/model/parts/__pycache__/exogenousProcesses.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlockScience/Community_Inclusion_Currencies/a8de2d06723759c6d2381a06f0aa397d3aadc847/Simulation/model/parts/__pycache__/exogenousProcesses.cpython-37.pyc -------------------------------------------------------------------------------- /Simulation/model/parts/__pycache__/exogenousProcesses.cpython-38.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlockScience/Community_Inclusion_Currencies/a8de2d06723759c6d2381a06f0aa397d3aadc847/Simulation/model/parts/__pycache__/exogenousProcesses.cpython-38.pyc -------------------------------------------------------------------------------- /Simulation/model/parts/__pycache__/initialization.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlockScience/Community_Inclusion_Currencies/a8de2d06723759c6d2381a06f0aa397d3aadc847/Simulation/model/parts/__pycache__/initialization.cpython-37.pyc -------------------------------------------------------------------------------- /Simulation/model/parts/__pycache__/initialization.cpython-38.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlockScience/Community_Inclusion_Currencies/a8de2d06723759c6d2381a06f0aa397d3aadc847/Simulation/model/parts/__pycache__/initialization.cpython-38.pyc -------------------------------------------------------------------------------- /Simulation/model/parts/__pycache__/kpis.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlockScience/Community_Inclusion_Currencies/a8de2d06723759c6d2381a06f0aa397d3aadc847/Simulation/model/parts/__pycache__/kpis.cpython-36.pyc -------------------------------------------------------------------------------- /Simulation/model/parts/__pycache__/kpis.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlockScience/Community_Inclusion_Currencies/a8de2d06723759c6d2381a06f0aa397d3aadc847/Simulation/model/parts/__pycache__/kpis.cpython-37.pyc -------------------------------------------------------------------------------- /Simulation/model/parts/__pycache__/kpis.cpython-38.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlockScience/Community_Inclusion_Currencies/a8de2d06723759c6d2381a06f0aa397d3aadc847/Simulation/model/parts/__pycache__/kpis.cpython-38.pyc -------------------------------------------------------------------------------- /Simulation/model/parts/__pycache__/operatorentity.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlockScience/Community_Inclusion_Currencies/a8de2d06723759c6d2381a06f0aa397d3aadc847/Simulation/model/parts/__pycache__/operatorentity.cpython-37.pyc -------------------------------------------------------------------------------- /Simulation/model/parts/__pycache__/operatorentity.cpython-38.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlockScience/Community_Inclusion_Currencies/a8de2d06723759c6d2381a06f0aa397d3aadc847/Simulation/model/parts/__pycache__/operatorentity.cpython-38.pyc -------------------------------------------------------------------------------- /Simulation/model/parts/__pycache__/subpopulation_clusters.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlockScience/Community_Inclusion_Currencies/a8de2d06723759c6d2381a06f0aa397d3aadc847/Simulation/model/parts/__pycache__/subpopulation_clusters.cpython-37.pyc -------------------------------------------------------------------------------- /Simulation/model/parts/__pycache__/subpopulation_clusters.cpython-38.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlockScience/Community_Inclusion_Currencies/a8de2d06723759c6d2381a06f0aa397d3aadc847/Simulation/model/parts/__pycache__/subpopulation_clusters.cpython-38.pyc -------------------------------------------------------------------------------- /Simulation/model/parts/__pycache__/supportingFunctions.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlockScience/Community_Inclusion_Currencies/a8de2d06723759c6d2381a06f0aa397d3aadc847/Simulation/model/parts/__pycache__/supportingFunctions.cpython-37.pyc -------------------------------------------------------------------------------- /Simulation/model/parts/__pycache__/supportingFunctions.cpython-38.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlockScience/Community_Inclusion_Currencies/a8de2d06723759c6d2381a06f0aa397d3aadc847/Simulation/model/parts/__pycache__/supportingFunctions.cpython-38.pyc -------------------------------------------------------------------------------- /Simulation/model/parts/__pycache__/system.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlockScience/Community_Inclusion_Currencies/a8de2d06723759c6d2381a06f0aa397d3aadc847/Simulation/model/parts/__pycache__/system.cpython-37.pyc -------------------------------------------------------------------------------- /Simulation/model/parts/__pycache__/system.cpython-38.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlockScience/Community_Inclusion_Currencies/a8de2d06723759c6d2381a06f0aa397d3aadc847/Simulation/model/parts/__pycache__/system.cpython-38.pyc -------------------------------------------------------------------------------- /Simulation/model/parts/exogenousProcesses.py: -------------------------------------------------------------------------------- 1 | 2 | import numpy as np 3 | import pandas as pd 4 | import math 5 | from .initialization import * 6 | from .supportingFunctions import * 7 | 8 | 9 | def calculate_drip(params, step, sL, s): 10 | ''' 11 | ''' 12 | timestep = s['timestep'] 13 | reduceMultiplier = math.floor(timestep / drip_reduce_frequency) 14 | reduceDripBy = reduceMultiplier*drip_reduce_size 15 | drip = max(initial_drip_amount - reduceDripBy, 0) 16 | 17 | return {'drip': drip} 18 | 19 | 20 | def update_drip(params, step, sL, s, _input): 21 | ''' 22 | ''' 23 | y = 'drip' 24 | x = _input['drip'] 25 | 26 | return (y, x) 27 | 28 | 29 | def startingBalance(params, step, sL, s, _input): 30 | ''' 31 | Calculate agent starting balance every 30 days 32 | ''' 33 | y = 'startingBalance' 34 | network = s['network'] 35 | 36 | startingBalance = {} 37 | 38 | timestep = s['timestep'] 39 | 40 | division = timestep % 31 == 0 # 31, and not 30 to note start of the month 41 | 42 | if timestep == 1: 43 | for i in clusters: 44 | startingBalance[i] = network.nodes[i]['tokens'] 45 | elif division == True: 46 | for i in clusters: 47 | startingBalance[i] = network.nodes[i]['tokens'] 48 | else: 49 | startingBalance = s['startingBalance'] 50 | x = startingBalance 51 | 52 | return (y, x) 53 | 54 | 55 | def update_30_day_spend(params, step, sL, s, _input): 56 | ''' 57 | Aggregate agent spend. Refresh every 30 days. 58 | ''' 59 | y = '30_day_spend' 60 | network = s['network'] 61 | 62 | timestep = s['timestep'] 63 | 64 | division = timestep % 31 == 0 # 31, and not 30 to note start of the month 65 | 66 | if division == True: 67 | outflowSpend, inflowSpend = iterateEdges(network, 'spend') 68 | spend = outflowSpend 69 | else: 70 | spendOld = s['30_day_spend'] 71 | outflowSpend, inflowSpend = iterateEdges(network, 'spend') 72 | spend = DictionaryMergeAddition(spendOld, outflowSpend) 73 | 74 | x = spend 75 | return (y, x) 76 | 77 | 78 | def redCrossDrop(params, step, sL, s, _input): 79 | ''' 80 | Every 30 days, the red cross drips to the grassroots operator node 81 | ''' 82 | y = 'operatorFiatBalance' 83 | fiatBalance = s['operatorFiatBalance'] 84 | 85 | timestep = s['timestep'] 86 | 87 | division = timestep % redCrossDripFrequency == 0 88 | 89 | if division == True: 90 | fiatBalance = fiatBalance + _input['drip'] 91 | else: 92 | pass 93 | 94 | x = fiatBalance 95 | return (y, x) 96 | 97 | 98 | def clear_agent_activity(params, step, sL, s, _input): 99 | ''' 100 | Clear agent activity from the previous timestep 101 | ''' 102 | y = 'network' 103 | network = s['network'] 104 | 105 | if s['timestep'] > 0: 106 | outboundAgents = s['outboundAgents'] 107 | inboundAgents = s['inboundAgents'] 108 | 109 | try: 110 | for i, j in zip(outboundAgents, inboundAgents): 111 | network[i][j]['demand'] = 0 112 | except: 113 | pass 114 | 115 | # Clear cic % demand edge weights 116 | try: 117 | for i, j in zip(outboundAgents, inboundAgents): 118 | network[i][j]['fractionOfDemandInCIC'] = 0 119 | except: 120 | pass 121 | 122 | # Clear utility edge types 123 | try: 124 | for i, j in zip(outboundAgents, inboundAgents): 125 | network[i][j]['utility'] = 0 126 | except: 127 | pass 128 | 129 | # Clear cic % spend edge weights 130 | try: 131 | for i, j in zip(outboundAgents, inboundAgents): 132 | network[i][j]['fractionOfActualSpendInCIC'] = 0 133 | except: 134 | pass 135 | # Clear spend edge types 136 | try: 137 | for i, j in zip(outboundAgents, inboundAgents): 138 | network[i][j]['spend'] = 0 139 | except: 140 | pass 141 | else: 142 | pass 143 | x = network 144 | return (y, x) 145 | -------------------------------------------------------------------------------- /Simulation/model/parts/initialization.py: -------------------------------------------------------------------------------- 1 | 2 | # import libraries 3 | import networkx as nx 4 | import matplotlib.pyplot as plt 5 | import numpy as np 6 | from .supportingFunctions import * 7 | from .subpopulation_clusters import * 8 | 9 | # Assumptions: 10 | # Amount received in shilling when withdraw occurs 11 | leverage = 1 12 | 13 | # process time 14 | process_lag = 15 # timesteps 15 | 16 | # intial red cross drip amount 17 | initial_drip_amount = 10000 18 | # when drip amount gets reduced 19 | drip_reduce_frequency = 90 # days 20 | # By how much drip gets reduced 21 | # Drip can never go to negative, e.g. drip = max(newDrip,0) 22 | drip_reduce_size = 5000 23 | 24 | 25 | # starting operatorFiatBalance 26 | initialOperatingFiatBalance = 100000 27 | # starting operatorCICBalance 28 | initialOperatingCICBalance = 100000 29 | 30 | redCrossDripFrequency = 30 # days 31 | 32 | # system actors 33 | system = ['external', 'cic'] 34 | 35 | # chamas 36 | chama = ['chama_1', 'chama_2', 'chama_3', 'chama_4'] 37 | 38 | # traders 39 | # only trading on the cic. Link to external and cic not to other agents 40 | traders = ['ta', 'tb', 'tc'] 41 | 42 | allAgents = clusters.copy() + system 43 | 44 | 45 | R0 = 40000 # xDAI 46 | kappa = 4 # leverage 47 | P0 = 1/100 # initial price 48 | S0 = kappa*R0/P0 49 | V0 = invariant(R0, S0, kappa) 50 | P = spot_price(R0, V0, kappa) 51 | 52 | # Price level 53 | priceLevel = 100 54 | 55 | fractionOfDemandInCIC = 0.5 56 | fractionOfActualSpendInCIC = 0.5 57 | 58 | 59 | def create_network(): 60 | # Create network graph 61 | network = nx.DiGraph() 62 | 63 | # Add nodes for n participants plus the external economy and the cic network 64 | for i in clusters: 65 | network.add_node(i, type='Agent', tokens=clustersMedianSourceBalance[int(i)], native_currency=int( 66 | np.random.uniform(low=clusters1stQSourceBalance[int(i)], high=clusters3rdQSourceBalance[int(i)], size=1)[0])) 67 | 68 | network.add_node('external', type='Cloud', native_currency=100000000, 69 | tokens=0, delta_native_currency=0, pos=(1, 50)) 70 | network.add_node('cic', type='Contract', tokens=S0, 71 | native_currency=R0, pos=(50, 1)) 72 | 73 | for i in chama: 74 | network.add_node(i, type='Chama') 75 | 76 | for i in traders: 77 | network.add_node(i, type='Trader', tokens=20, native_currency=20, 78 | price_belief=1, trust_level=1) 79 | 80 | # Create bi-directional edges between all participants 81 | for i in allAgents: 82 | for j in allAgents: 83 | if i != j: 84 | network.add_edge(i, j) 85 | 86 | # Create bi-directional edges between each trader and the external economy and the cic environment 87 | for i in traders: 88 | for j in system: 89 | if i != j: 90 | network.add_edge(i, j) 91 | 92 | # Create bi-directional edges between some agent and a chama node representing membershio 93 | for i in chama: 94 | for j in clusters: 95 | if np.random.choice(['Member', 'Non_Member'], 1, p=[.50, .50])[0] == 'Member': 96 | network.add_edge(i, j) 97 | 98 | # Type colors 99 | color_map = [] 100 | for i in network.nodes: 101 | if network.nodes[i]['type'] == 'Agent': 102 | color_map.append('Red') 103 | elif network.nodes[i]['type'] == 'Cloud': 104 | color_map.append('Blue') 105 | elif network.nodes[i]['type'] == 'Contract': 106 | color_map.append('Green') 107 | elif network.nodes[i]['type'] == 'Trader': 108 | color_map.append('Yellow') 109 | elif network.nodes[i]['type'] == 'Chama': 110 | color_map.append('Orange') 111 | 112 | # pos = nx.spring_layout(network, pos=nx.get_node_attributes( 113 | # network, 'pos'), fixed=nx.get_node_attributes(network, 'pos'), seed=10) 114 | # nx.draw(network, node_color=color_map, 115 | # pos=pos, with_labels=True, alpha=0.7) 116 | # plt.savefig('images/graph.png') 117 | # plt.figure(figsize=(20, 20)) 118 | # plt.show() 119 | return network 120 | -------------------------------------------------------------------------------- /Simulation/model/parts/kpis.py: -------------------------------------------------------------------------------- 1 | 2 | import numpy as np 3 | from .initialization import * 4 | from .supportingFunctions import * 5 | import networkx as nx 6 | 7 | 8 | # Behaviors 9 | def kpis(params, step, sL, s): 10 | '''''' 11 | # instantiate network state 12 | network = s['network'] 13 | 14 | KPIDemand = {} 15 | KPISpend = {} 16 | KPISpendOverDemand = {} 17 | for i in mixingAgents: 18 | demand = [] 19 | for j in network.adj[i]: 20 | try: 21 | demand.append(network.adj[i][j]['demand']) 22 | except: 23 | pass 24 | 25 | spend = [] 26 | for j in network.adj[i]: 27 | try: 28 | spend.append(network.adj[i][j]['spend']) 29 | except: 30 | pass 31 | 32 | sumDemand = sum(demand) 33 | sumSpend = sum(spend) 34 | try: 35 | spendOverDemand = sumSpend/sumDemand 36 | except: 37 | spendOverDemand = 0 38 | 39 | KPIDemand[i] = sumDemand 40 | KPISpend[i] = sumSpend 41 | KPISpendOverDemand[i] = spendOverDemand 42 | 43 | #print(nx.katz_centrality_numpy(G=network,weight='spend')) 44 | return {'KPIDemand':KPIDemand,'KPISpend':KPISpend,'KPISpendOverDemand':KPISpendOverDemand} 45 | 46 | def velocity_of_money(params, step, sL, s): 47 | '''''' 48 | # instantiate network state 49 | network = s['network'] 50 | 51 | KPISpend = s['KPISpend'] 52 | 53 | T = [] 54 | for i,j in KPISpend.items(): 55 | T.append(j) 56 | 57 | T = sum(T) 58 | 59 | M = [] 60 | for i in clusters: 61 | M.append(network.nodes[i]['tokens'] + network.nodes[i]['native_currency']) 62 | 63 | M = sum(M) 64 | 65 | V_t = (priceLevel *T)/M 66 | 67 | return {'V_t':V_t,'T':T,'M':M} 68 | 69 | 70 | # Mechanisms 71 | def update_KPIDemand(params, step, sL, s,_input): 72 | y = 'KPIDemand' 73 | x = _input['KPIDemand'] 74 | return (y,x) 75 | 76 | def update_KPISpend(params, step, sL, s,_input): 77 | y = 'KPISpend' 78 | x = _input['KPISpend'] 79 | return (y,x) 80 | 81 | def update_KPISpendOverDemand(params, step, sL, s,_input): 82 | y = 'KPISpendOverDemand' 83 | x = _input['KPISpendOverDemand'] 84 | return (y,x) 85 | 86 | 87 | def update_velocity_of_money(params, step, sL, s,_input): 88 | y = 'VelocityOfMoney' 89 | x = _input['V_t'] 90 | return (y,x) 91 | -------------------------------------------------------------------------------- /Simulation/model/parts/operatorentity.py: -------------------------------------------------------------------------------- 1 | 2 | import numpy as np 3 | import pandas as pd 4 | from cadCAD.configuration.utils import access_block 5 | from .initialization import * 6 | from .supportingFunctions import * 7 | from .subpopulation_clusters import * 8 | from collections import OrderedDict 9 | 10 | # Parameters 11 | FrequencyOfAllocation = 30 12 | idealFiat = 100000 13 | idealCIC = 100000 14 | varianceCIC = 30000 15 | varianceFiat = 30000 16 | unadjustedPerAgent = 100 17 | # fee rate percentages 18 | feeRateExit = 0.05 19 | 20 | # Behaviors 21 | def fee_calculation(params, step, sL, s): 22 | ''' 23 | Calculate fee from withdrawals 24 | ''' 25 | withdraw = s['withdraw'] 26 | fee = {} 27 | 28 | try: 29 | for key, value in withdraw.items(): 30 | fee[key] = value*feeRateExit 31 | except: 32 | return {'fee': fee} 33 | 34 | return {'fee': fee} 35 | 36 | 37 | def disbursement_to_agents(params, step, sL, s): 38 | ''' 39 | Distribute every FrequencyOfAllocation days to agents based off of centrality allocation metric 40 | ''' 41 | fiatBalance = s['operatorFiatBalance'] 42 | cicBalance = s['operatorCICBalance'] 43 | timestep = s['timestep'] 44 | 45 | division = timestep % FrequencyOfAllocation == 0 46 | 47 | if division == True: 48 | agentDistribution = {} # agent: amount distributed 49 | for i, j in agentAllocation.items(): 50 | agentDistribution[i] = unadjustedPerAgent * agentAllocation[i][1] 51 | distribute = 'Yes' 52 | 53 | else: 54 | agentDistribution = 0 55 | distribute = 'No' 56 | 57 | return {'distribute': distribute, 'amount': agentDistribution} 58 | 59 | 60 | def inventory_controller(params, step, sL, s): 61 | ''' 62 | Monetary policy hysteresis conservation allocation between fiat and cic reserves. 63 | 64 | ''' 65 | fiatBalance = s['operatorFiatBalance'] 66 | cicBalance = s['operatorCICBalance'] 67 | timestep = s['timestep'] 68 | fundsInProcess = s['fundsInProcess'] 69 | 70 | updatedCIC = cicBalance 71 | updatedFiat = fiatBalance 72 | 73 | # Toggle inventory controller 74 | # on 75 | #decision,amt = mint_burn_logic_control(idealCIC,updatedCIC,varianceCIC,updatedFiat,varianceFiat,idealFiat) 76 | # off 77 | decision = 'none' 78 | amt = 0 79 | 80 | if decision == 'burn': 81 | try: 82 | deltaR, realized_price = withdraw( 83 | amt, updatedFiat, updatedCIC, V0, kappa) 84 | # update state 85 | # fiatBalance = fiatBalance - deltaR 86 | # cicBalance = cicBalance - amt 87 | fiatChange = abs(deltaR) 88 | cicChange = amt 89 | 90 | except: 91 | print('Not enough to burn') 92 | 93 | fiatChange = 0 94 | cicChange = 0 95 | 96 | elif decision == 'mint': 97 | try: 98 | deltaS, realized_price = mint( 99 | amt, updatedFiat, updatedCIC, V0, kappa) 100 | # update state 101 | # fiatBalance = fiatBalance + amt 102 | # cicBalance = cicBalance + deltaS 103 | fiatChange = amt 104 | cicChange = abs(deltaS) 105 | 106 | except: 107 | print('Not enough to mint') 108 | fiatChange = 0 109 | cicChange = 0 110 | 111 | else: 112 | fiatChange = 0 113 | cicChange = 0 114 | decision = 'none' 115 | pass 116 | 117 | if decision == 'mint': 118 | fundsInProcess['timestep'].append(timestep + process_lag) 119 | fundsInProcess['decision'].append(decision) 120 | fundsInProcess['cic'].append(fiatChange) 121 | fundsInProcess['shilling'].append(cicChange) 122 | elif decision == 'burn': 123 | fundsInProcess['timestep'].append(timestep + process_lag) 124 | fundsInProcess['decision'].append(decision) 125 | fundsInProcess['cic'].append(fiatChange) 126 | fundsInProcess['shilling'].append(cicChange) 127 | else: 128 | pass 129 | 130 | return {'decision': decision, 'fiatChange': fiatChange, 'cicChange': cicChange, 'fundsInProcess': fundsInProcess} 131 | 132 | 133 | # Mechanisms 134 | def update_exit_fee_revenue(params, step, sL, s, _input): 135 | ''' 136 | ''' 137 | y = 'exitFeeRevenue' 138 | fee = _input['fee'] 139 | x = s['exitFeeRevenue'] 140 | x += sum(fee.values()) 141 | 142 | return (y, x) 143 | 144 | 145 | def update_operator_balance_with_fee(params, step, sL, s, _input): 146 | ''' 147 | ''' 148 | y = 'operatorCICBalance' 149 | x = s['operatorCICBalance'] 150 | fee = _input['fee'] 151 | x += sum(fee.values()) 152 | 153 | return (y, x) 154 | 155 | 156 | def deduct_fee_from_withdrawal(params, step, sL, s, _input): 157 | ''' 158 | Made the assumption that fee is deducted from the withdrawal amount. 159 | An alternative would be to deduct the fee from agents balance. 160 | ''' 161 | y = 'withdraw' 162 | x = s['withdraw'] 163 | fee = _input['fee'] 164 | 165 | if(isinstance(x, (list))): 166 | x = {key: x[key] - fee.get(key, 0) for key in x} 167 | 168 | return (y, x) 169 | 170 | 171 | def update_agent_tokens(params, step, sL, s, _input): 172 | ''' 173 | ''' 174 | y = 'network' 175 | network = s['network'] 176 | 177 | distribute = _input['distribute'] 178 | amount = _input['amount'] 179 | 180 | if distribute == 'Yes': 181 | for i in clusters: 182 | network.nodes[i]['tokens'] = network.nodes[i]['tokens'] + amount[i] 183 | else: 184 | pass 185 | 186 | return (y, network) 187 | 188 | 189 | def update_operator_FromDisbursements(params, step, sL, s, _input): 190 | ''' 191 | ''' 192 | y = 'operatorCICBalance' 193 | x = s['operatorCICBalance'] 194 | timestep = s['timestep'] 195 | 196 | distribute = _input['distribute'] 197 | amount = _input['amount'] 198 | 199 | if distribute == 'Yes': 200 | totalDistribution = [] 201 | for i, j in amount.items(): 202 | totalDistribution.append(j) 203 | 204 | totalDistribution = sum(totalDistribution) 205 | x = x - totalDistribution 206 | 207 | else: 208 | pass 209 | 210 | return (y, x) 211 | 212 | 213 | def update_totalDistributedToAgents(params, step, sL, s, _input): 214 | ''' 215 | ''' 216 | y = 'totalDistributedToAgents' 217 | x = s['totalDistributedToAgents'] 218 | timestep = s['timestep'] 219 | 220 | distribute = _input['distribute'] 221 | amount = _input['amount'] 222 | 223 | if distribute == 'Yes': 224 | totalDistribution = [] 225 | for i, j in amount.items(): 226 | totalDistribution.append(j) 227 | 228 | totalDistribution = sum(totalDistribution) 229 | x = x + totalDistribution 230 | else: 231 | pass 232 | 233 | return (y, x) 234 | 235 | 236 | def update_operator_fiatBalance(params, step, sL, s, _input): 237 | ''' 238 | ''' 239 | y = 'operatorFiatBalance' 240 | x = s['operatorFiatBalance'] 241 | fundsInProcess = s['fundsInProcess'] 242 | timestep = s['timestep'] 243 | if _input['fiatChange']: 244 | try: 245 | if fundsInProcess['timestep'][0] == timestep + 1: 246 | if fundsInProcess['decision'][0] == 'mint': 247 | x = x - abs(fundsInProcess['shilling'][0]) 248 | elif fundsInProcess['decision'][0] == 'burn': 249 | x = x + abs(fundsInProcess['shilling'][0]) 250 | else: 251 | pass 252 | except: 253 | pass 254 | else: 255 | pass 256 | 257 | return (y, x) 258 | 259 | 260 | def update_operator_cicBalance(params, step, sL, s, _input): 261 | ''' 262 | ''' 263 | y = 'operatorCICBalance' 264 | x = s['operatorCICBalance'] 265 | fundsInProcess = s['fundsInProcess'] 266 | timestep = s['timestep'] 267 | 268 | if _input['cicChange']: 269 | try: 270 | if fundsInProcess['timestep'][0] == timestep + 1: 271 | if fundsInProcess['decision'][0] == 'mint': 272 | x = x + abs(fundsInProcess['cic'][0]) 273 | elif fundsInProcess['decision'][0] == 'burn': 274 | x = x - abs(fundsInProcess['cic'][0]) 275 | else: 276 | pass 277 | except: 278 | pass 279 | else: 280 | pass 281 | 282 | return (y, x) 283 | 284 | 285 | def update_totalMinted(params, step, sL, s, _input): 286 | ''' 287 | ''' 288 | y = 'totalMinted' 289 | x = s['totalMinted'] 290 | timestep = s['timestep'] 291 | try: 292 | if _input['fundsInProcess']['decision'][0] == 'mint': 293 | x = x + abs(_input['fundsInProcess']['cic'][0]) 294 | elif _input['fundsInProcess']['decision'][0] == 'burn': 295 | pass 296 | except: 297 | pass 298 | 299 | return (y, x) 300 | 301 | 302 | def update_totalBurned(params, step, sL, s, _input): 303 | ''' 304 | ''' 305 | y = 'totalBurned' 306 | x = s['totalBurned'] 307 | timestep = s['timestep'] 308 | try: 309 | if _input['fundsInProcess']['decision'][0] == 'burn': 310 | x = x + abs(_input['fundsInProcess']['cic'][0]) 311 | elif _input['fundsInProcess']['decision'][0] == 'mint': 312 | pass 313 | except: 314 | pass 315 | 316 | return (y, x) 317 | 318 | 319 | def update_fundsInProcess(params, step, sL, s, _input): 320 | ''' 321 | ''' 322 | y = 'fundsInProcess' 323 | x = _input['fundsInProcess'] 324 | timestep = s['timestep'] 325 | 326 | if _input['fundsInProcess']: 327 | try: 328 | if x['timestep'][0] == timestep: 329 | del x['timestep'][0] 330 | del x['decision'][0] 331 | del x['cic'][0] 332 | del x['shilling'][0] 333 | else: 334 | pass 335 | except: 336 | pass 337 | else: 338 | pass 339 | 340 | return (y, x) 341 | 342 | 343 | def update_network_mintBurn(params, step, sL, s, _input): 344 | ''' 345 | Update network for minting and burning 346 | ''' 347 | y = 'network' 348 | network = s['network'] 349 | 350 | try: 351 | if _input['fundsInProcess']['decision'][0] == 'mint': 352 | amountCIC = abs(_input['fundsInProcess']['cic'][0]) 353 | amountFiat = abs(_input['fundsInProcess']['shilling'][0]) 354 | decision = 'mint' 355 | elif _input['fundsInProcess']['decision'][0] == 'burn': 356 | amountCIC = abs(_input['fundsInProcess']['cic'][0]) 357 | amountFiat = abs(_input['fundsInProcess']['shilling'][0]) 358 | decision = 'burn' 359 | else: 360 | amountCIC = 0 361 | amountFiat = 0 362 | decision = 'none' 363 | except: 364 | amountCIC = 0 365 | amountFiat = 0 366 | decision = 'none' 367 | 368 | if decision == 'mint': 369 | # update cic node 370 | network.nodes['cic']['native_currency'] = network.nodes['cic']['native_currency'] + amountFiat 371 | network.nodes['cic']['tokens'] = network.nodes['cic']['tokens'] + amountCIC 372 | elif decision == 'burn': 373 | # update cic node 374 | network.nodes['cic']['native_currency'] = network.nodes['cic']['native_currency'] - amountFiat 375 | network.nodes['cic']['tokens'] = network.nodes['cic']['tokens'] - amountCIC 376 | elif decision == 'none': 377 | pass 378 | 379 | x = network 380 | return (y, x) 381 | -------------------------------------------------------------------------------- /Simulation/model/parts/subpopulation_clusters.py: -------------------------------------------------------------------------------- 1 | # Create initilization file (copy from here) 2 | 3 | clusters = ['0', 4 | '1', 5 | '2', 6 | '3', 7 | '4', 8 | '5', 9 | '6', 10 | '7', 11 | '8', 12 | '9', 13 | '10', 14 | '11', 15 | '12', 16 | '13', 17 | '14', 18 | '15', 19 | '16', 20 | '17', 21 | '18', 22 | '19', 23 | '20', 24 | '21', 25 | '22', 26 | '23', 27 | '24', 28 | '25', 29 | '26', 30 | '27', 31 | '28', 32 | '29', 33 | '30', 34 | '31', 35 | '32', 36 | '33', 37 | '34', 38 | '35', 39 | '36', 40 | '37', 41 | '38', 42 | '39', 43 | '40', 44 | '41', 45 | '42', 46 | '43', 47 | '44', 48 | '45', 49 | '46', 50 | '47', 51 | '48', 52 | '49'] 53 | 54 | mixingAgents = ['0', 55 | '1', 56 | '2', 57 | '3', 58 | '4', 59 | '5', 60 | '6', 61 | '7', 62 | '8', 63 | '9', 64 | '10', 65 | '11', 66 | '12', 67 | '13', 68 | '14', 69 | '15', 70 | '16', 71 | '17', 72 | '18', 73 | '19', 74 | '20', 75 | '21', 76 | '22', 77 | '23', 78 | '24', 79 | '25', 80 | '26', 81 | '27', 82 | '28', 83 | '29', 84 | '30', 85 | '31', 86 | '32', 87 | '33', 88 | '34', 89 | '35', 90 | '36', 91 | '37', 92 | '38', 93 | '39', 94 | '40', 95 | '41', 96 | '42', 97 | '43', 98 | '44', 99 | '45', 100 | '46', 101 | '47', 102 | '48', 103 | '49', 104 | 'external'] 105 | 106 | 107 | clustersMedianSourceBalance = [150.0, 108 | 340.0, 109 | 250.0, 110 | 20.0, 111 | 330.0, 112 | 320.0, 113 | 240.0, 114 | 300.0, 115 | 300.0, 116 | 50.0, 117 | 900.0, 118 | 120.0, 119 | 400.0, 120 | 180.0, 121 | 300.0, 122 | 6000.0, 123 | 132.5, 124 | 130.0, 125 | 160.0, 126 | 5000.0, 127 | 150.0, 128 | 10000.0, 129 | 200.0, 130 | 10000.0, 131 | 200.0, 132 | 200.0, 133 | 35000.0, 134 | 20000.0, 135 | 100.0, 136 | 500.0, 137 | 425.0, 138 | 13320.0, 139 | 500.0, 140 | 500.0, 141 | 1000.0, 142 | 390.0, 143 | 150.0, 144 | 250.0, 145 | 45000.0, 146 | 36300.0, 147 | 960.0, 148 | 120.0, 149 | 200.0, 150 | 100.0, 151 | 220.0, 152 | 600.0, 153 | 62000.0, 154 | 500.0, 155 | 900.0, 156 | 486.0] 157 | 158 | clusters1stQSourceBalance = [56.0, 159 | 118.46, 160 | 105.0, 161 | 64767.51, 162 | 251652.0, 163 | 124.5, 164 | 4139.28, 165 | 146.1, 166 | 1002.5, 167 | 17145.78, 168 | 52676.2, 169 | 100.0, 170 | 121082.43, 171 | 112.0, 172 | 28849.43, 173 | 27619.22, 174 | 66.36, 175 | 251652.0, 176 | 148.0, 177 | 38653.54, 178 | 67.22, 179 | 121082.43, 180 | 6429.46, 181 | 555.04, 182 | 104.48, 183 | 96.43, 184 | 52676.2, 185 | 251652.0, 186 | 64.73, 187 | 36824.5, 188 | 15182.03, 189 | 485.94, 190 | 21660.89, 191 | 11210.0, 192 | 100579.18, 193 | 100.46, 194 | 2845.01, 195 | 3338.98, 196 | 1274.91, 197 | 6724.88, 198 | 38653.54, 199 | 114.5, 200 | 68.0, 201 | 100.0, 202 | 20.93, 203 | 14050.3, 204 | 63145.96, 205 | 9276.23, 206 | 63234.8, 207 | 64767.51] 208 | 209 | clusters3rdQSourceBalance = [403.96, 210 | 506.6, 211 | 592.96, 212 | 64767.51, 213 | 251652.0, 214 | 1501.41, 215 | 7214.9, 216 | 869.82, 217 | 1557.01, 218 | 18304.36, 219 | 55142.93, 220 | 419.96, 221 | 121082.43, 222 | 816.3, 223 | 38653.54, 224 | 37106.89, 225 | 770.65, 226 | 251652.0, 227 | 838.46, 228 | 38653.54, 229 | 315.0, 230 | 121082.43, 231 | 9074.79, 232 | 5726.66, 233 | 602.02, 234 | 437.96, 235 | 63234.8, 236 | 251652.0, 237 | 425.0, 238 | 40953.15, 239 | 17145.78, 240 | 6349.27, 241 | 25695.83, 242 | 13156.46, 243 | 100579.18, 244 | 819.33, 245 | 4158.5, 246 | 5597.38, 247 | 2823.81, 248 | 20030.91, 249 | 51710.52, 250 | 537.94, 251 | 542.92, 252 | 415.43, 253 | 895.66, 254 | 18304.36, 255 | 63145.96, 256 | 14050.3, 257 | 64767.51, 258 | 64767.51] 259 | 260 | clustersMu = [329.98, 261 | 588.11, 262 | 469.93, 263 | 492.32, 264 | 2443.89, 265 | 565.21, 266 | 1120.5, 267 | 408.1, 268 | 550.09, 269 | 503.42, 270 | 2478.89, 271 | 349.93, 272 | 9354.55, 273 | 453.69, 274 | 4298.1, 275 | 7508.1, 276 | 376.86, 277 | 8074.0, 278 | 333.75, 279 | 7691.43, 280 | 362.68, 281 | 15562.5, 282 | 672.28, 283 | 10809.6, 284 | 274.98, 285 | 405.46, 286 | 34555.56, 287 | 14338.57, 288 | 255.48, 289 | 1229.44, 290 | 1470.23, 291 | 14590.61, 292 | 1527.75, 293 | 770.73, 294 | 1039.05, 295 | 503.7, 296 | 362.11, 297 | 499.51, 298 | 45000.0, 299 | 37504.55, 300 | 1941.82, 301 | 262.96, 302 | 702.23, 303 | 168.57, 304 | 2000.58, 305 | 1383.32, 306 | 65333.33, 307 | 1454.43, 308 | 1483.11, 309 | 1853.03] 310 | 311 | clustersSigma = [583.23, 312 | 1501.26, 313 | 966.32, 314 | 1452.2, 315 | 6789.39, 316 | 847.29, 317 | 2228.12, 318 | 483.5, 319 | 852.2, 320 | 1170.38, 321 | 3256.26, 322 | 1174.55, 323 | 16235.99, 324 | 841.35, 325 | 7696.91, 326 | 6814.68, 327 | 785.21, 328 | 10886.9, 329 | 712.65, 330 | 8713.11, 331 | 708.54, 332 | 18542.24, 333 | 1164.0, 334 | 3682.08, 335 | 340.99, 336 | 624.76, 337 | 8171.77, 338 | 15060.34, 339 | 461.52, 340 | 1774.39, 341 | 4617.97, 342 | 4770.82, 343 | 2641.75, 344 | 1133.41, 345 | 767.87, 346 | 437.68, 347 | 652.72, 348 | 761.07, 349 | 7071.07, 350 | 5274.96, 351 | 2716.8, 352 | 572.43, 353 | 1553.21, 354 | 210.61, 355 | 4477.94, 356 | 1798.73, 357 | 31134.12, 358 | 2147.9, 359 | 1900.27, 360 | 2909.68] 361 | 362 | 363 | # nested dictionary 364 | UtilityTypesOrdered = {'0': {'Food/Water': 0.4119323241317899, 365 | 'Farming/Labour': 0.26090828138913624, 366 | 'Shop': 0.17916295636687443, 367 | 'Savings Group': 0.07266251113089937, 368 | 'Fuel/Energy': 0.034194122885129116, 369 | 'Transport': 0.02617987533392698, 370 | 'Health': 0.006767586821015138, 371 | 'Education': 0.004096170970614425, 372 | 'None': 0.004096170970614425}, 373 | '1': {'Food/Water': 1.0}, 374 | '2': {'Savings Group': 0.87890625, 375 | 'Health': 0.08984375, 376 | 'Food/Water': 0.03125}, 377 | '3': {'Savings Group': 0.4905964535196131, 378 | 'Farming/Labour': 0.3610961848468565, 379 | 'Food/Water': 0.14830736163353037}, 380 | '4': {'Farming/Labour': 0.2843866171003718, 381 | 'Shop': 0.25650557620817843, 382 | 'Fuel/Energy': 0.17843866171003717, 383 | 'Food/Water': 0.16171003717472118, 384 | 'None': 0.10966542750929369, 385 | 'Savings Group': 0.0055762081784386614, 386 | 'Transport': 0.0037174721189591076}, 387 | '5': {'Farming/Labour': 0.421875, 388 | 'Food/Water': 0.421875, 389 | 'Shop': 0.0625, 390 | 'Savings Group': 0.03125, 391 | 'Fuel/Energy': 0.03125, 392 | 'Transport': 0.03125}, 393 | '6': {'Savings Group': 0.6008097165991902, 394 | 'Food/Water': 0.35870445344129553, 395 | 'Shop': 0.04048582995951417}, 396 | '7': {'Farming/Labour': 0.4346590909090909, 397 | 'Food/Water': 0.2869318181818182, 398 | 'Shop': 0.1278409090909091, 399 | 'Fuel/Energy': 0.07670454545454546, 400 | 'Savings Group': 0.03977272727272727, 401 | 'Education': 0.017045454545454544, 402 | 'None': 0.011363636363636364, 403 | 'Transport': 0.002840909090909091, 404 | 'Health': 0.002840909090909091}, 405 | '8': {'Savings Group': 1.0}, 406 | '9': {'Savings Group': 0.7142857142857143, 407 | 'Food/Water': 0.18181818181818182, 408 | 'Farming/Labour': 0.07792207792207792, 409 | 'Education': 0.025974025974025976}, 410 | '10': {'Food/Water': 0.3499875508340941, 411 | 'Farming/Labour': 0.3162088140094614, 412 | 'Shop': 0.21047389824881732, 413 | 'Transport': 0.03950535314133953, 414 | 'None': 0.03386173126400531, 415 | 'Fuel/Energy': 0.022491493069964313, 416 | 'Education': 0.01709685451074778, 417 | 'Savings Group': 0.006473566271059839, 418 | 'Environment': 0.002157855423686613, 419 | 'Health': 0.0016598887874512407, 420 | 'Chama': 8.299443937256204e-05}, 421 | '11': {'Savings Group': 0.4873417721518987, 422 | 'Food/Water': 0.3377445339470656, 423 | 'Education': 0.09723820483314154, 424 | 'Farming/Labour': 0.06271576524741082, 425 | 'Shop': 0.014959723820483314}, 426 | '12': {'Food/Water': 0.34994337485843713, 427 | 'Shop': 0.2332955832389581, 428 | 'Farming/Labour': 0.19592298980747452, 429 | 'Fuel/Energy': 0.057757644394110984, 430 | 'Savings Group': 0.053227633069082674, 431 | 'Education': 0.05096262740656852, 432 | 'None': 0.026047565118912798, 433 | 'Transport': 0.020385050962627407, 434 | 'Health': 0.011325028312570781, 435 | 'Environment': 0.0011325028312570782}, 436 | '13': {'Savings Group': 0.3712871287128713, 437 | 'Food/Water': 0.247974797479748, 438 | 'Shop': 0.19801980198019803, 439 | 'Fuel/Energy': 0.08235823582358236, 440 | 'Health': 0.07605760576057606, 441 | 'Farming/Labour': 0.024302430243024302}, 442 | '14': {'Savings Group': 1.0}, 443 | '15': {'Savings Group': 1.0}, 444 | '16': {'Savings Group': 0.5, 'Food/Water': 0.5}, 445 | '17': {'Savings Group': 0.7335701598579041, 446 | 'Shop': 0.17584369449378331, 447 | 'Food/Water': 0.0905861456483126}, 448 | '18': {'Savings Group': 0.6984126984126984, 449 | 'Food/Water': 0.23809523809523808, 450 | 'Farming/Labour': 0.06349206349206349}, 451 | '19': {'Savings Group': 1.0}, 452 | '20': {'Savings Group': 1.0}, 453 | '21': {'Farming/Labour': 0.47619047619047616, 454 | 'Food/Water': 0.3333333333333333, 455 | 'Shop': 0.09523809523809523, 456 | 'Fuel/Energy': 0.047619047619047616, 457 | 'Transport': 0.047619047619047616}, 458 | '22': {'Food/Water': 0.33040588654165676, 459 | 'Farming/Labour': 0.3209114645145977, 460 | 'Shop': 0.164016140517446, 461 | 'None': 0.06147638262520769, 462 | 'Fuel/Energy': 0.05008307619273677, 463 | 'Transport': 0.028957987182530263, 464 | 'Savings Group': 0.023973415618324233, 465 | 'Education': 0.014478993591265131, 466 | 'Health': 0.0035604082601471635, 467 | 'Environment': 0.0011868027533823878, 468 | 'Staff': 0.00047472110135295516, 469 | 'Chama': 0.00023736055067647758, 470 | 'Game': 0.00023736055067647758}, 471 | '23': {'Savings Group': 0.8323424494649228, 472 | 'Farming/Labour': 0.16765755053507728}, 473 | '24': {'Farming/Labour': 0.38481675392670156, 474 | 'Food/Water': 0.3717277486910995, 475 | 'Shop': 0.1387434554973822, 476 | 'Fuel/Energy': 0.05235602094240838, 477 | 'Transport': 0.02356020942408377, 478 | 'Savings Group': 0.01832460732984293, 479 | 'Education': 0.007853403141361256, 480 | 'Staff': 0.002617801047120419}, 481 | '25': {'Savings Group': 0.7916666666666666, 482 | 'Food/Water': 0.20833333333333334}, 483 | '26': {'Savings Group': 0.7442348008385744, 'Food/Water': 0.2557651991614256}, 484 | '27': {'Food/Water': 0.3333333333333333, 485 | 'Farming/Labour': 0.25, 486 | 'Health': 0.25, 487 | 'Savings Group': 0.08333333333333333, 488 | 'Fuel/Energy': 0.08333333333333333}, 489 | '28': {'Food/Water': 1.0}, 490 | '29': {'Food/Water': 0.27335640138408307, 491 | 'Farming/Labour': 0.23529411764705882, 492 | 'Shop': 0.21972318339100347, 493 | 'Fuel/Energy': 0.21280276816608998, 494 | 'None': 0.03806228373702422, 495 | 'Education': 0.006920415224913495, 496 | 'Transport': 0.006920415224913495, 497 | 'Savings Group': 0.005190311418685121, 498 | 'Staff': 0.0017301038062283738}, 499 | '30': {'Food/Water': 0.36228287841191065, 500 | 'Shop': 0.2679900744416873, 501 | 'Farming/Labour': 0.21712158808933002, 502 | 'Savings Group': 0.08436724565756824, 503 | 'Education': 0.02481389578163772, 504 | 'Fuel/Energy': 0.018610421836228287, 505 | 'Transport': 0.017369727047146403, 506 | 'None': 0.0037220843672456576, 507 | 'Health': 0.0024813895781637717, 508 | 'Environment': 0.0012406947890818859}, 509 | '31': {'Savings Group': 0.8, 510 | 'Food/Water': 0.13333333333333333, 511 | 'Shop': 0.06666666666666667}, 512 | '32': {'Savings Group': 0.7444444444444445, 513 | 'Farming/Labour': 0.2, 514 | 'Food/Water': 0.05555555555555555}, 515 | '33': {'Food/Water': 0.33343474292668085, 516 | 'Farming/Labour': 0.28414968055978096, 517 | 'Savings Group': 0.18892607240644965, 518 | 'Shop': 0.1146942500760572, 519 | 'Fuel/Energy': 0.06936416184971098, 520 | 'None': 0.006693033160937024, 521 | 'Education': 0.0027380590203833284}, 522 | '34': {'Savings Group': 1.0}, 523 | '35': {'Food/Water': 0.3829787234042553, 524 | 'Farming/Labour': 0.2390488110137672, 525 | 'Shop': 0.1902377972465582, 526 | 'Savings Group': 0.07259073842302878, 527 | 'Transport': 0.060075093867334166, 528 | 'Health': 0.030037546933667083, 529 | 'Fuel/Energy': 0.016270337922403004, 530 | 'None': 0.0050062578222778474, 531 | 'Education': 0.0037546933667083854}, 532 | '36': {'Savings Group': 1.0}, 533 | '37': {'Farming/Labour': 0.5454545454545454, 534 | 'Food/Water': 0.36363636363636365, 535 | 'Savings Group': 0.045454545454545456, 536 | 'Shop': 0.045454545454545456}, 537 | '38': {'Savings Group': 1.0}, 538 | '39': {'Savings Group': 1.0}, 539 | '40': {'Farming/Labour': 0.3595236417447678, 540 | 'Food/Water': 0.3165386512578395, 541 | 'Shop': 0.18842928616728913, 542 | 'Fuel/Energy': 0.05108871820167712, 543 | 'None': 0.0360439715312522, 544 | 'Transport': 0.022443802409978154, 545 | 'Education': 0.01039391163413431, 546 | 'Savings Group': 0.00842083010358678, 547 | 'Health': 0.004545134240011275, 548 | 'Staff': 0.0011627087590726517, 549 | 'Environment': 0.0010570079627933197, 550 | 'System': 0.00035233598759777326}, 551 | '41': {'Food/Water': 0.33003300330033003, 552 | 'Farming/Labour': 0.2739273927392739, 553 | 'Shop': 0.1782178217821782, 554 | 'Savings Group': 0.13861386138613863, 555 | 'Health': 0.0429042904290429, 556 | 'Fuel/Energy': 0.0165016501650165, 557 | 'Transport': 0.0165016501650165, 558 | 'Education': 0.0033003300330033004}, 559 | '42': {'Savings Group': 0.8661740558292282, 'Health': 0.13382594417077176}, 560 | '43': {'Savings Group': 1.0}, 561 | '44': {'Food/Water': 0.4805194805194805, 562 | 'Shop': 0.14285714285714285, 563 | 'Savings Group': 0.14285714285714285, 564 | 'Farming/Labour': 0.13636363636363635, 565 | 'Health': 0.06493506493506493, 566 | 'Transport': 0.012987012987012988, 567 | 'Environment': 0.012987012987012988, 568 | 'Fuel/Energy': 0.006493506493506494}, 569 | '45': {'Food/Water': 0.35471100554235946, 570 | 'Farming/Labour': 0.2414885193982581, 571 | 'Shop': 0.23198733174980204, 572 | 'Education': 0.03800475059382423, 573 | 'None': 0.035629453681710214, 574 | 'Transport': 0.035629453681710214, 575 | 'Fuel/Energy': 0.028503562945368172, 576 | 'Savings Group': 0.02454473475851148, 577 | 'Health': 0.006334125098970704, 578 | 'Environment': 0.001583531274742676, 579 | 'Staff': 0.000791765637371338, 580 | 'System': 0.000791765637371338}, 581 | '46': {'Savings Group': 0.6981132075471698, 582 | 'Health': 0.18867924528301888, 583 | 'Food/Water': 0.09433962264150944, 584 | 'Shop': 0.018867924528301886}, 585 | '47': {'Savings Group': 0.5555555555555556, 586 | 'Farming/Labour': 0.2222222222222222, 587 | 'Food/Water': 0.2222222222222222}, 588 | '48': {'Food/Water': 0.38795180722891565, 589 | 'Savings Group': 0.38313253012048193, 590 | 'Health': 0.10120481927710843, 591 | 'Shop': 0.09879518072289156, 592 | 'Fuel/Energy': 0.016867469879518072, 593 | 'Farming/Labour': 0.012048192771084338}, 594 | '49': {'Food/Water': 0.3829787234042553, 595 | 'Savings Group': 0.3829787234042553, 596 | 'Education': 0.19148936170212766, 597 | 'Fuel/Energy': 0.0425531914893617}, 598 | 'external': {'Food/Water': 1, 599 | 'Fuel/Energy': 2, 600 | 'Health': 3, 601 | 'Education': 4, 602 | 'Savings Group': 5, 603 | 'Shop': 6}} 604 | 605 | # nested dictionary 606 | utilityTypesProbability = {'0': {'Food/Water': 0.4119323241317899, 607 | 'Farming/Labour': 0.26090828138913624, 608 | 'Shop': 0.17916295636687443, 609 | 'Savings Group': 0.07266251113089937, 610 | 'Fuel/Energy': 0.034194122885129116, 611 | 'Transport': 0.02617987533392698, 612 | 'Health': 0.006767586821015138, 613 | 'Education': 0.004096170970614425, 614 | 'None': 0.004096170970614425}, 615 | '1': {'Food/Water': 1.0}, 616 | '2': {'Savings Group': 0.87890625, 617 | 'Health': 0.08984375, 618 | 'Food/Water': 0.03125}, 619 | '3': {'Savings Group': 0.4905964535196131, 620 | 'Farming/Labour': 0.3610961848468565, 621 | 'Food/Water': 0.14830736163353037}, 622 | '4': {'Farming/Labour': 0.2843866171003718, 623 | 'Shop': 0.25650557620817843, 624 | 'Fuel/Energy': 0.17843866171003717, 625 | 'Food/Water': 0.16171003717472118, 626 | 'None': 0.10966542750929369, 627 | 'Savings Group': 0.0055762081784386614, 628 | 'Transport': 0.0037174721189591076}, 629 | '5': {'Farming/Labour': 0.421875, 630 | 'Food/Water': 0.421875, 631 | 'Shop': 0.0625, 632 | 'Savings Group': 0.03125, 633 | 'Fuel/Energy': 0.03125, 634 | 'Transport': 0.03125}, 635 | '6': {'Savings Group': 0.6008097165991902, 636 | 'Food/Water': 0.35870445344129553, 637 | 'Shop': 0.04048582995951417}, 638 | '7': {'Farming/Labour': 0.4346590909090909, 639 | 'Food/Water': 0.2869318181818182, 640 | 'Shop': 0.1278409090909091, 641 | 'Fuel/Energy': 0.07670454545454546, 642 | 'Savings Group': 0.03977272727272727, 643 | 'Education': 0.017045454545454544, 644 | 'None': 0.011363636363636364, 645 | 'Transport': 0.002840909090909091, 646 | 'Health': 0.002840909090909091}, 647 | '8': {'Savings Group': 1.0}, 648 | '9': {'Savings Group': 0.7142857142857143, 649 | 'Food/Water': 0.18181818181818182, 650 | 'Farming/Labour': 0.07792207792207792, 651 | 'Education': 0.025974025974025976}, 652 | '10': {'Food/Water': 0.3499875508340941, 653 | 'Farming/Labour': 0.3162088140094614, 654 | 'Shop': 0.21047389824881732, 655 | 'Transport': 0.03950535314133953, 656 | 'None': 0.03386173126400531, 657 | 'Fuel/Energy': 0.022491493069964313, 658 | 'Education': 0.01709685451074778, 659 | 'Savings Group': 0.006473566271059839, 660 | 'Environment': 0.002157855423686613, 661 | 'Health': 0.0016598887874512407, 662 | 'Chama': 8.299443937256204e-05}, 663 | '11': {'Savings Group': 0.4873417721518987, 664 | 'Food/Water': 0.3377445339470656, 665 | 'Education': 0.09723820483314154, 666 | 'Farming/Labour': 0.06271576524741082, 667 | 'Shop': 0.014959723820483314}, 668 | '12': {'Food/Water': 0.34994337485843713, 669 | 'Shop': 0.2332955832389581, 670 | 'Farming/Labour': 0.19592298980747452, 671 | 'Fuel/Energy': 0.057757644394110984, 672 | 'Savings Group': 0.053227633069082674, 673 | 'Education': 0.05096262740656852, 674 | 'None': 0.026047565118912798, 675 | 'Transport': 0.020385050962627407, 676 | 'Health': 0.011325028312570781, 677 | 'Environment': 0.0011325028312570782}, 678 | '13': {'Savings Group': 0.3712871287128713, 679 | 'Food/Water': 0.247974797479748, 680 | 'Shop': 0.19801980198019803, 681 | 'Fuel/Energy': 0.08235823582358236, 682 | 'Health': 0.07605760576057606, 683 | 'Farming/Labour': 0.024302430243024302}, 684 | '14': {'Savings Group': 1.0}, 685 | '15': {'Savings Group': 1.0}, 686 | '16': {'Savings Group': 0.5, 'Food/Water': 0.5}, 687 | '17': {'Savings Group': 0.7335701598579041, 688 | 'Shop': 0.17584369449378331, 689 | 'Food/Water': 0.0905861456483126}, 690 | '18': {'Savings Group': 0.6984126984126984, 691 | 'Food/Water': 0.23809523809523808, 692 | 'Farming/Labour': 0.06349206349206349}, 693 | '19': {'Savings Group': 1.0}, 694 | '20': {'Savings Group': 1.0}, 695 | '21': {'Farming/Labour': 0.47619047619047616, 696 | 'Food/Water': 0.3333333333333333, 697 | 'Shop': 0.09523809523809523, 698 | 'Fuel/Energy': 0.047619047619047616, 699 | 'Transport': 0.047619047619047616}, 700 | '22': {'Food/Water': 0.33040588654165676, 701 | 'Farming/Labour': 0.3209114645145977, 702 | 'Shop': 0.164016140517446, 703 | 'None': 0.06147638262520769, 704 | 'Fuel/Energy': 0.05008307619273677, 705 | 'Transport': 0.028957987182530263, 706 | 'Savings Group': 0.023973415618324233, 707 | 'Education': 0.014478993591265131, 708 | 'Health': 0.0035604082601471635, 709 | 'Environment': 0.0011868027533823878, 710 | 'Staff': 0.00047472110135295516, 711 | 'Chama': 0.00023736055067647758, 712 | 'Game': 0.00023736055067647758}, 713 | '23': {'Savings Group': 0.8323424494649228, 714 | 'Farming/Labour': 0.16765755053507728}, 715 | '24': {'Farming/Labour': 0.38481675392670156, 716 | 'Food/Water': 0.3717277486910995, 717 | 'Shop': 0.1387434554973822, 718 | 'Fuel/Energy': 0.05235602094240838, 719 | 'Transport': 0.02356020942408377, 720 | 'Savings Group': 0.01832460732984293, 721 | 'Education': 0.007853403141361256, 722 | 'Staff': 0.002617801047120419}, 723 | '25': {'Savings Group': 0.7916666666666666, 724 | 'Food/Water': 0.20833333333333334}, 725 | '26': {'Savings Group': 0.7442348008385744, 'Food/Water': 0.2557651991614256}, 726 | '27': {'Food/Water': 0.3333333333333333, 727 | 'Farming/Labour': 0.25, 728 | 'Health': 0.25, 729 | 'Savings Group': 0.08333333333333333, 730 | 'Fuel/Energy': 0.08333333333333333}, 731 | '28': {'Food/Water': 1.0}, 732 | '29': {'Food/Water': 0.27335640138408307, 733 | 'Farming/Labour': 0.23529411764705882, 734 | 'Shop': 0.21972318339100347, 735 | 'Fuel/Energy': 0.21280276816608998, 736 | 'None': 0.03806228373702422, 737 | 'Education': 0.006920415224913495, 738 | 'Transport': 0.006920415224913495, 739 | 'Savings Group': 0.005190311418685121, 740 | 'Staff': 0.0017301038062283738}, 741 | '30': {'Food/Water': 0.36228287841191065, 742 | 'Shop': 0.2679900744416873, 743 | 'Farming/Labour': 0.21712158808933002, 744 | 'Savings Group': 0.08436724565756824, 745 | 'Education': 0.02481389578163772, 746 | 'Fuel/Energy': 0.018610421836228287, 747 | 'Transport': 0.017369727047146403, 748 | 'None': 0.0037220843672456576, 749 | 'Health': 0.0024813895781637717, 750 | 'Environment': 0.0012406947890818859}, 751 | '31': {'Savings Group': 0.8, 752 | 'Food/Water': 0.13333333333333333, 753 | 'Shop': 0.06666666666666667}, 754 | '32': {'Savings Group': 0.7444444444444445, 755 | 'Farming/Labour': 0.2, 756 | 'Food/Water': 0.05555555555555555}, 757 | '33': {'Food/Water': 0.33343474292668085, 758 | 'Farming/Labour': 0.28414968055978096, 759 | 'Savings Group': 0.18892607240644965, 760 | 'Shop': 0.1146942500760572, 761 | 'Fuel/Energy': 0.06936416184971098, 762 | 'None': 0.006693033160937024, 763 | 'Education': 0.0027380590203833284}, 764 | '34': {'Savings Group': 1.0}, 765 | '35': {'Food/Water': 0.3829787234042553, 766 | 'Farming/Labour': 0.2390488110137672, 767 | 'Shop': 0.1902377972465582, 768 | 'Savings Group': 0.07259073842302878, 769 | 'Transport': 0.060075093867334166, 770 | 'Health': 0.030037546933667083, 771 | 'Fuel/Energy': 0.016270337922403004, 772 | 'None': 0.0050062578222778474, 773 | 'Education': 0.0037546933667083854}, 774 | '36': {'Savings Group': 1.0}, 775 | '37': {'Farming/Labour': 0.5454545454545454, 776 | 'Food/Water': 0.36363636363636365, 777 | 'Savings Group': 0.045454545454545456, 778 | 'Shop': 0.045454545454545456}, 779 | '38': {'Savings Group': 1.0}, 780 | '39': {'Savings Group': 1.0}, 781 | '40': {'Farming/Labour': 0.3595236417447678, 782 | 'Food/Water': 0.3165386512578395, 783 | 'Shop': 0.18842928616728913, 784 | 'Fuel/Energy': 0.05108871820167712, 785 | 'None': 0.0360439715312522, 786 | 'Transport': 0.022443802409978154, 787 | 'Education': 0.01039391163413431, 788 | 'Savings Group': 0.00842083010358678, 789 | 'Health': 0.004545134240011275, 790 | 'Staff': 0.0011627087590726517, 791 | 'Environment': 0.0010570079627933197, 792 | 'System': 0.00035233598759777326}, 793 | '41': {'Food/Water': 0.33003300330033003, 794 | 'Farming/Labour': 0.2739273927392739, 795 | 'Shop': 0.1782178217821782, 796 | 'Savings Group': 0.13861386138613863, 797 | 'Health': 0.0429042904290429, 798 | 'Fuel/Energy': 0.0165016501650165, 799 | 'Transport': 0.0165016501650165, 800 | 'Education': 0.0033003300330033004}, 801 | '42': {'Savings Group': 0.8661740558292282, 'Health': 0.13382594417077176}, 802 | '43': {'Savings Group': 1.0}, 803 | '44': {'Food/Water': 0.4805194805194805, 804 | 'Shop': 0.14285714285714285, 805 | 'Savings Group': 0.14285714285714285, 806 | 'Farming/Labour': 0.13636363636363635, 807 | 'Health': 0.06493506493506493, 808 | 'Transport': 0.012987012987012988, 809 | 'Environment': 0.012987012987012988, 810 | 'Fuel/Energy': 0.006493506493506494}, 811 | '45': {'Food/Water': 0.35471100554235946, 812 | 'Farming/Labour': 0.2414885193982581, 813 | 'Shop': 0.23198733174980204, 814 | 'Education': 0.03800475059382423, 815 | 'None': 0.035629453681710214, 816 | 'Transport': 0.035629453681710214, 817 | 'Fuel/Energy': 0.028503562945368172, 818 | 'Savings Group': 0.02454473475851148, 819 | 'Health': 0.006334125098970704, 820 | 'Environment': 0.001583531274742676, 821 | 'Staff': 0.000791765637371338, 822 | 'System': 0.000791765637371338}, 823 | '46': {'Savings Group': 0.6981132075471698, 824 | 'Health': 0.18867924528301888, 825 | 'Food/Water': 0.09433962264150944, 826 | 'Shop': 0.018867924528301886}, 827 | '47': {'Savings Group': 0.5555555555555556, 828 | 'Farming/Labour': 0.2222222222222222, 829 | 'Food/Water': 0.2222222222222222}, 830 | '48': {'Food/Water': 0.38795180722891565, 831 | 'Savings Group': 0.38313253012048193, 832 | 'Health': 0.10120481927710843, 833 | 'Shop': 0.09879518072289156, 834 | 'Fuel/Energy': 0.016867469879518072, 835 | 'Farming/Labour': 0.012048192771084338}, 836 | '49': {'Food/Water': 0.3829787234042553, 837 | 'Savings Group': 0.3829787234042553, 838 | 'Education': 0.19148936170212766, 839 | 'Fuel/Energy': 0.0425531914893617}, 840 | 'external': {'Food/Water': 0.6, 841 | 'Fuel/Energy': 0.1, 842 | 'Health': 0.03, 843 | 'Education': 0.015, 844 | 'Savings Group': 0.065, 845 | 'Shop': 0.19}} 846 | 847 | # agent:[centrality,allocationValue] 848 | agentAllocation = {'0': [1, 1], 849 | '1': [1, 1], 850 | '2': [1, 1], 851 | '3': [1, 1], 852 | '4': [1, 1], 853 | '5': [1, 1], 854 | '6': [1, 1], 855 | '7': [1, 1], 856 | '8': [1, 1], 857 | '9': [1, 1], 858 | '10': [1, 1], 859 | '11': [1, 1], 860 | '12': [1, 1], 861 | '13': [1, 1], 862 | '14': [1, 1], 863 | '15': [1, 1], 864 | '16': [1, 1], 865 | '17': [1, 1], 866 | '18': [1, 1], 867 | '19': [1, 1], 868 | '20': [1, 1], 869 | '21': [1, 1], 870 | '22': [1, 1], 871 | '23': [1, 1], 872 | '24': [1, 1], 873 | '25': [1, 1], 874 | '26': [1, 1], 875 | '27': [1, 1], 876 | '28': [1, 1], 877 | '29': [1, 1], 878 | '30': [1, 1], 879 | '31': [1, 1], 880 | '32': [1, 1], 881 | '33': [1, 1], 882 | '34': [1, 1], 883 | '35': [1, 1], 884 | '36': [1, 1], 885 | '37': [1, 1], 886 | '38': [1, 1], 887 | '39': [1, 1], 888 | '40': [1, 1], 889 | '41': [1, 1], 890 | '42': [1, 1], 891 | '43': [1, 1], 892 | '44': [1, 1], 893 | '45': [1, 1], 894 | '46': [1, 1], 895 | '47': [1, 1], 896 | '48': [1, 1], 897 | '49': [1, 1]} 898 | -------------------------------------------------------------------------------- /Simulation/model/parts/supportingFunctions.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | from scipy.stats import gamma 3 | import matplotlib.pyplot as plt 4 | 5 | default_kappa= 4 6 | default_exit_tax = .02 7 | 8 | #value function for a given state (R,S) 9 | def invariant(R,S,kappa=default_kappa): 10 | 11 | return (S**kappa)/R 12 | 13 | #given a value function (parameterized by kappa) 14 | #and an invariant coeficient V0 15 | #return Supply S as a function of reserve R 16 | def reserve(S, V0, kappa=default_kappa): 17 | return (S**kappa)/V0 18 | 19 | #given a value function (parameterized by kappa) 20 | #and an invariant coeficient V0 21 | #return Supply S as a function of reserve R 22 | def supply(R, V0, kappa=default_kappa): 23 | return (V0*R)**(1/kappa) 24 | 25 | #given a value function (parameterized by kappa) 26 | #and an invariant coeficient V0 27 | #return a spot price P as a function of reserve R 28 | def spot_price(R, V0, kappa=default_kappa): 29 | return kappa*R**((kappa-1)/kappa)/V0**(1/kappa) 30 | 31 | #for a given state (R,S) 32 | #given a value function (parameterized by kappa) 33 | #and an invariant coeficient V0 34 | #deposit deltaR to Mint deltaS 35 | #with realized price deltaR/deltaS 36 | def mint(deltaR, R,S, V0, kappa=default_kappa): 37 | deltaS = (V0*(R+deltaR))**(1/kappa)-S 38 | if deltaS ==0: 39 | realized_price = spot_price(R+deltaR, V0, kappa) 40 | else: 41 | realized_price = deltaR/deltaS 42 | deltaS = round(deltaS,2) 43 | return deltaS, realized_price 44 | 45 | #for a given state (R,S) 46 | #given a value function (parameterized by kappa) 47 | #and an invariant coeficient V0 48 | #burn deltaS to Withdraw deltaR 49 | #with realized price deltaR/deltaS 50 | def withdraw(deltaS, R,S, V0, kappa=default_kappa): 51 | deltaR = R-((S-deltaS)**kappa)/V0 52 | if deltaS ==0: 53 | realized_price = spot_price(R+deltaR, V0, kappa) 54 | else: 55 | realized_price = deltaR/deltaS 56 | deltaR = round(deltaR,2) 57 | return deltaR, realized_price 58 | 59 | 60 | 61 | def iterateEdges(network,edgeToIterate): 62 | ''' 63 | Description: 64 | Iterate through a network on a weighted edge and return 65 | two dictionaries: the inflow and outflow for the given agents 66 | in the format: 67 | 68 | {'Agent':amount} 69 | ''' 70 | outflows = {} 71 | inflows = {} 72 | for i,j in network.edges: 73 | try: 74 | amount = network[i][j][edgeToIterate] 75 | if i in outflows: 76 | outflows[i] = outflows[i] + amount 77 | else: 78 | outflows[i] = amount 79 | if j in inflows: 80 | inflows[j] = inflows[j] + amount 81 | else: 82 | inflows[j] = amount 83 | except: 84 | pass 85 | return outflows,inflows 86 | 87 | 88 | def inflowAndOutflowDictionaryMerge(inflow,outflow): 89 | ''' 90 | Description: 91 | Merge two dictionaries and return one dictionary with zero floor''' 92 | 93 | merged = {} 94 | 95 | inflowsKeys = [k for k,v in inflow.items() if k not in outflow] 96 | for i in inflowsKeys: 97 | merged[i] = inflow[i] 98 | outflowsKeys = [k for k,v in outflow.items() if k not in inflow] 99 | for i in outflowsKeys: 100 | merged[i] = outflow[i] 101 | overlapKeys = [k for k,v in inflow.items() if k in outflow] 102 | for i in overlapKeys: 103 | amt = outflow[i] - inflow[i] 104 | if amt < 0: 105 | merged[i] = 0 106 | else: 107 | merged[i] = amt 108 | pass 109 | 110 | return merged 111 | 112 | 113 | def spendCalculation(agentToPay,agentToReceive,rankOrderDemand,maxSpendCurrency,maxSpendTokens,cicPercentage): 114 | ''' 115 | Function to calculate if an agent can pay for demand given token and currency contraints 116 | ''' 117 | if (rankOrderDemand[agentToReceive] * (1-cicPercentage)) > maxSpendCurrency[agentToPay]: 118 | verdict_currency = 'No' 119 | else: 120 | verdict_currency = 'Enough' 121 | 122 | if (rankOrderDemand[agentToReceive] * cicPercentage) > maxSpendTokens[agentToPay]: 123 | verdict_cic = 'No' 124 | else: 125 | verdict_cic = 'Enough' 126 | 127 | if verdict_currency == 'Enough'and verdict_cic == 'Enough': 128 | spend = rankOrderDemand[agentToReceive] 129 | 130 | elif maxSpendCurrency[agentToPay] > 0 and maxSpendTokens[agentToPay] > 0: 131 | if maxSpendTokens[agentToPay] > maxSpendCurrency[agentToPay]: 132 | spend = maxSpendCurrency[agentToPay] 133 | elif maxSpendCurrency[agentToPay] > maxSpendTokens[agentToPay]: 134 | spend = maxSpendTokens[agentToPay] 135 | else: 136 | spend = 0 137 | 138 | return spend 139 | 140 | 141 | def spendCalculationExternal(agentToPay,agentToReceive,rankOrderDemand,maxSpendCurrency): 142 | ''' 143 | ''' 144 | if rankOrderDemand[agentToReceive] > maxSpendCurrency[agentToPay]: 145 | verdict_currency = 'No' 146 | else: 147 | verdict_currency = 'Enough' 148 | 149 | if verdict_currency == 'Enough': 150 | spend = rankOrderDemand[agentToReceive] 151 | 152 | elif maxSpendCurrency[agentToPay] > 0: 153 | spend = maxSpendCurrency[agentToPay] 154 | else: 155 | spend = 0 156 | 157 | return spend 158 | 159 | 160 | def DictionaryMergeAddition(inflow,outflow): 161 | ''' 162 | Description: 163 | Merge two dictionaries and return one dictionary''' 164 | 165 | merged = {} 166 | 167 | inflowsKeys = [k for k,v in inflow.items() if k not in outflow] 168 | for i in inflowsKeys: 169 | merged[i] = inflow[i] 170 | outflowsKeys = [k for k,v in outflow.items() if k not in inflow] 171 | for i in outflowsKeys: 172 | merged[i] = outflow[i] 173 | overlapKeys = [k for k,v in inflow.items() if k in outflow] 174 | for i in overlapKeys: 175 | merged[i] = outflow[i] + inflow[i] 176 | 177 | return merged 178 | 179 | def mint_burn_logic_control(idealCIC,actualCIC,varianceCIC,actualFiat,varianceFiat,idealFiat): 180 | ''' 181 | Inventory control function to test if the current balance is in an acceptable range. Tolerance range 182 | 183 | Test: mint_burn_logic_control(100000,subset['operatorCICBalance'][499],30000,subset['operatorFiatBalance'][499],30000,100000) 184 | ''' 185 | if idealFiat - varianceFiat <= actualFiat <= idealFiat + (2*varianceFiat): 186 | decision = 'none' 187 | amount = 0 188 | else: 189 | if (idealFiat - varianceFiat) > actualFiat: 190 | decision = 'burn' 191 | amount = (idealFiat + varianceFiat) - actualFiat 192 | else: 193 | pass 194 | if actualFiat > (idealFiat + varianceFiat): 195 | decision = 'mint' 196 | amount = actualFiat - (idealFiat + varianceFiat) 197 | else: 198 | pass 199 | 200 | if decision == 'mint': 201 | if actualCIC < (idealCIC - varianceCIC): 202 | if amount > actualCIC: 203 | decision = 'none' 204 | amount = 0 205 | else: 206 | pass 207 | if decision == 'none': 208 | if actualCIC < (idealCIC - varianceCIC): 209 | decision = 'mint' 210 | amount = (idealCIC-varianceCIC) 211 | else: 212 | pass 213 | 214 | amount = round(amount,2) 215 | return decision, amount 216 | 217 | #NetworkX functions 218 | def get_nodes_by_type(g, node_type_selection): 219 | return [node for node in g.nodes if g.nodes[node]['type']== node_type_selection] 220 | 221 | def get_edges_by_type(g, edge_type_selection): 222 | return [edge for edge in g.edges if g.edges[edge]['type']== edge_type_selection] 223 | 224 | def get_edges(g): 225 | return [edge for edge in g.edges if g.edges[edge]] 226 | 227 | def get_nodes(g): 228 | ''' 229 | df.network.apply(lambda g: np.array([g.nodes[j]['balls'] for j in get_nodes(g)])) 230 | ''' 231 | return [node for node in g.nodes if g.nodes[node]] 232 | 233 | def aggregate_runs(df,aggregate_dimension): 234 | ''' 235 | Function to aggregate the monte carlo runs along a single dimension. 236 | Parameters: 237 | df: dataframe name 238 | aggregate_dimension: the dimension you would like to aggregate on, the standard one is timestep. 239 | Example run: 240 | mean_df,median_df,std_df,min_df = aggregate_runs(df,'timestep') 241 | ''' 242 | df = df[df['substep'] == df.substep.max()] 243 | mean_df = df.groupby(aggregate_dimension).mean().reset_index() 244 | median_df = df.groupby(aggregate_dimension).median().reset_index() 245 | std_df = df.groupby(aggregate_dimension).std().reset_index() 246 | min_df = df.groupby(aggregate_dimension).min().reset_index() 247 | 248 | return mean_df,median_df,std_df,min_df 249 | 250 | 251 | def plot_median_with_quantiles(df,aggregate_dimension,x, y): 252 | ''' 253 | Function to plot the median and 1st and 3rd quartiles of the monte carlo runs along a single variable. 254 | Parameters: 255 | df: dataframe name 256 | aggregate_dimension: the dimension you would like to aggregate on, the standard one is timestep. 257 | x = x axis variable for plotting 258 | y = y axis variable for plotting 259 | 260 | Example run: 261 | plot_median_with_quantiles(df,'timestep','timestep','AggregatedAgentSpend') 262 | ''' 263 | 264 | df = df[df['substep'] == df.substep.max()] 265 | firstQuantile = df.groupby(aggregate_dimension).quantile(0.25).reset_index() 266 | thirdQuantile = df.groupby(aggregate_dimension).quantile(0.75).reset_index() 267 | median_df = df.groupby(aggregate_dimension).median().reset_index() 268 | 269 | fig, ax = plt.subplots(1,figsize=(10,6)) 270 | ax.plot(median_df[x].values, median_df[y].values, lw=2, label='Median', color='blue') 271 | ax.fill_between(firstQuantile[x].values, firstQuantile[y].values, thirdQuantile[y].values, facecolor='black', alpha=0.2) 272 | ax.set_title(y + ' Median') 273 | ax.legend(loc='upper left') 274 | ax.set_xlabel('Timestep') 275 | ax.set_ylabel('Amount') 276 | ax.grid() 277 | 278 | def plot_median_with_quantiles_annotation(df,aggregate_dimension,x, y): 279 | ''' 280 | Function to plot the median and 1st and 3rd quartiles of the monte carlo runs along a single variable. 281 | Parameters: 282 | df: dataframe name 283 | aggregate_dimension: the dimension you would like to aggregate on, the standard one is timestep. 284 | x = x axis variable for plotting 285 | y = y axis variable for plotting 286 | 287 | Example run: 288 | plot_median_with_quantiles(df,'timestep','timestep','AggregatedAgentSpend') 289 | ''' 290 | 291 | df = df[df['substep'] == df.substep.max()] 292 | firstQuantile = df.groupby(aggregate_dimension).quantile(0.25).reset_index() 293 | thirdQuantile = df.groupby(aggregate_dimension).quantile(0.75).reset_index() 294 | median_df = df.groupby(aggregate_dimension).median().reset_index() 295 | 296 | fig, ax = plt.subplots(1,figsize=(10,6)) 297 | ax.axvline(x=30,linewidth=2, color='r') 298 | ax.annotate('Agents can withdraw and Red Cross Drip occurs', xy=(30,2), xytext=(35, 1), 299 | arrowprops=dict(facecolor='black', shrink=0.05)) 300 | 301 | ax.axvline(x=60,linewidth=2, color='r') 302 | ax.axvline(x=90,linewidth=2, color='r') 303 | ax.plot(median_df[x].values, median_df[y].values, lw=2, label='Median', color='blue') 304 | ax.fill_between(firstQuantile[x].values, firstQuantile[y].values, thirdQuantile[y].values, facecolor='black', alpha=0.2) 305 | ax.set_title(y + ' Median') 306 | ax.legend(loc='upper left') 307 | ax.set_xlabel('Timestep') 308 | ax.set_ylabel('Amount') 309 | ax.grid() 310 | 311 | 312 | def first_five_plot(df,aggregate_dimension,x,y,run_count): 313 | ''' 314 | A function that generates timeseries plot of at most the first five Monte Carlo runs. 315 | Parameters: 316 | df: dataframe name 317 | aggregate_dimension: the dimension you would like to aggregate on, the standard one is timestep. 318 | x = x axis variable for plotting 319 | y = y axis variable for plotting 320 | run_count = the number of monte carlo simulations 321 | Note: Run aggregate_runs before using this function 322 | Example run: 323 | first_five_plot(df,'timestep','timestep','revenue',run_count=100) 324 | ''' 325 | mean_df,median_df,std_df,min_df = aggregate_runs(df,aggregate_dimension) 326 | plt.figure(figsize=(10,6)) 327 | if run_count < 5: 328 | runs = run_count 329 | else: 330 | runs = 5 331 | for r in range(1,runs+1): 332 | legend_name = 'Run ' + str(r) 333 | plt.plot(df[df.run==r].timestep, df[df.run==r][y], label = legend_name ) 334 | plt.plot(mean_df[x], mean_df[y], label = 'Mean', color = 'black') 335 | plt.legend(bbox_to_anchor=(1.05, 1), loc=2, borderaxespad=0.) 336 | plt.xlabel(x) 337 | plt.ylabel(y) 338 | title_text = 'Performance of ' + y + ' over the First ' + str(runs) + ' Monte Carlo Runs' 339 | plt.title(title_text) 340 | 341 | 342 | def plot_fan_chart(df,aggregate_dimension,x, y,lx=False,ly=False,density_hack=True): 343 | def q10(x): 344 | return x.quantile(0.1) 345 | 346 | def q20(x): 347 | return x.quantile(0.2) 348 | 349 | def q30(x): 350 | return x.quantile(0.3) 351 | 352 | def q40(x): 353 | return x.quantile(0.4) 354 | 355 | def q60(x): 356 | return x.quantile(0.6) 357 | 358 | def q70(x): 359 | return x.quantile(0.7) 360 | 361 | def q80(x): 362 | return x.quantile(0.8) 363 | 364 | def q90(x): 365 | return x.quantile(0.9) 366 | 367 | run_count = max(df.run) 368 | 369 | agg_metrics = [q10, q20, q30, q40, 'median', q60, q70, q80, q90] 370 | agg_df = df.groupby(aggregate_dimension).agg({y: agg_metrics}) 371 | agg_metrics = agg_df.columns.levels[1].values 372 | agg_df.columns = ['_'.join(col).strip() for col in agg_df.columns.values] 373 | plt.figure(figsize=(10,6)) 374 | 375 | df = agg_df.reset_index() 376 | lines = plt.plot(df[x], df[f'{y}_median']) 377 | color = lines[0].get_color() 378 | if density_hack: 379 | avg_iqr = [] 380 | for i in range(len(agg_metrics)-1): 381 | m = (agg_metrics[i], agg_metrics[i+1]) 382 | iqr = df[f'{y}_{m[1]}'] - df[f'{y}_{m[0]}'] 383 | avg_iqr.append(iqr.sum()) 384 | inv_avg_iqr = [1/i for i in avg_iqr] 385 | norm_avg_iqr = [i/max(inv_avg_iqr) for i in inv_avg_iqr] 386 | i = 0 387 | while i 0: 43 | stepDemands.append(round(i,2)) 44 | else: 45 | stepDemands.append(1) 46 | 47 | 48 | 49 | stepUtilities = [] 50 | 51 | for i in outboundAgents: 52 | stepUtilities.append(np.random.choice(list(UtilityTypesOrdered[str(i)].keys()),size=1,p=list(utilityTypesProbability[str(i)].values()))[0]) 53 | #stepUtilities.append(random.choice(list(UtilityTypesOrdered[str(i)].keys()),k=1,weights=list(utilityTypesProbability[str(i)].values()))[0]) 54 | 55 | return {'outboundAgents':outboundAgents,'inboundAgents':inboundAgents,'stepDemands':stepDemands,'stepUtilities':stepUtilities} 56 | 57 | 58 | def spend_allocation(params, step, sL, s): 59 | ''' 60 | Take mixing agents, demand, and utilities and allocate agent shillings and tokens based on utility and scarcity. 61 | ''' 62 | # instantiate network state 63 | network = s['network'] 64 | 65 | spendI = [] 66 | spendJ = [] 67 | spendAmount = [] 68 | 69 | # calculate max about of spend available to each agent 70 | maxSpendShilling = {} 71 | for i in mixingAgents: 72 | maxSpendShilling[i] = network.nodes[i]['native_currency'] 73 | 74 | maxSpendCIC = {} 75 | for i in mixingAgents: 76 | maxSpendCIC[i] = network.nodes[i]['tokens'] 77 | 78 | 79 | for i in mixingAgents: 80 | rankOrder = {} 81 | rankOrderDemand = {} 82 | for j in network.adj[i]: 83 | try: 84 | #print(network.adj[i][j]['utility']) 85 | #print(network.adj[i][j]) 86 | utility = network.adj[i][j]['utility'] 87 | rankOrder[j] = UtilityTypesOrdered[i][utility] 88 | rankOrderDemand[j] = network.adj[i][j]['demand'] 89 | rankOrder = dict(OrderedDict(sorted(rankOrder.items(), key=lambda v: v, reverse=False))) 90 | for k in rankOrder: 91 | # if i or j is external, we transact 100% in shilling 92 | if i == 'external': 93 | amt = spendCalculationExternal(i,j,rankOrderDemand,maxSpendShilling) 94 | spendI.append(i) 95 | spendJ.append(j) 96 | spendAmount.append(amt) 97 | maxSpendShilling[i] = maxSpendShilling[i] - amt 98 | elif j == 'external': 99 | amt = spendCalculationExternal(i,j,rankOrderDemand,maxSpendShilling) 100 | spendI.append(i) 101 | spendJ.append(j) 102 | spendAmount.append(amt) 103 | maxSpendShilling[i] = maxSpendShilling[i] - amt 104 | else: 105 | amt = spendCalculation(i,j,rankOrderDemand,maxSpendShilling,maxSpendCIC,fractionOfDemandInCIC) 106 | spendI.append(i) 107 | spendJ.append(j) 108 | spendAmount.append(amt) 109 | maxSpendShilling[i] = maxSpendShilling[i] - amt * (1- fractionOfDemandInCIC) 110 | maxSpendCIC[i] = maxSpendCIC[i] - (amt * fractionOfDemandInCIC) 111 | except: 112 | pass 113 | return {'spendI':spendI,'spendJ':spendJ,'spendAmount':spendAmount} 114 | 115 | 116 | def withdraw_calculation(params, step, sL, s): 117 | '''''' 118 | # instantiate network state 119 | network = s['network'] 120 | 121 | # Assumptions: 122 | # * user is only able to withdraw up to 50% of balance, assuming they have spent 50% of balance 123 | # * Agents will withdraw as much as they can. 124 | withdraw = {} 125 | 126 | fiftyThreshold = {} 127 | 128 | startingBalance = s['startingBalance'] 129 | 130 | spend = s['30_day_spend'] 131 | timestep = s['timestep'] 132 | 133 | maxWithdraw = maxAmountofWithdraw 134 | 135 | division = timestep % 30 == 0 136 | 137 | if division == True: 138 | for i,j in startingBalance.items(): 139 | fiftyThreshold[i] = j * 0.5 140 | if s['timestep'] > 7: 141 | for i,j in fiftyThreshold.items(): 142 | if spend[i] > 0 and fiftyThreshold[i] > 0: 143 | if spend[i] * fractionOfActualSpendInCIC >= fiftyThreshold[i]: 144 | spent = spend[i] 145 | amount = spent * redeemPercentage 146 | if network.nodes[i]['tokens'] > amount: 147 | if maxWithdraw - amount > 0: 148 | withdraw[i] = amount 149 | maxWithdraw = maxWithdraw - amount 150 | else: 151 | if maxWithdraw > 1: 152 | withdraw[i] = maxWithdraw 153 | maxWithdraw = 0 154 | else: 155 | pass 156 | elif network.nodes[i]['tokens'] < amount: 157 | if maxWithdraw - network.nodes[i]['tokens'] > 0: 158 | withdraw[i] = network.nodes[i]['tokens'] 159 | maxWithdraw = maxWithdraw - network.nodes[i]['tokens'] 160 | else: 161 | if maxWithdraw > 1: 162 | withdraw[i] = maxWithdraw 163 | maxWithdraw = 0 164 | else: 165 | pass 166 | else: 167 | pass 168 | else: 169 | pass 170 | else: 171 | pass 172 | else: 173 | pass 174 | 175 | return {'withdraw':withdraw} 176 | 177 | # Mechanisms 178 | def update_agent_activity(params,step,sL,s,_input): 179 | ''' 180 | Update the network for interacting agent, their demand, and utility. 181 | ''' 182 | y = 'network' 183 | network = s['network'] 184 | 185 | outboundAgents = _input['outboundAgents'] 186 | inboundAgents = _input['inboundAgents'] 187 | stepDemands = _input['stepDemands'] 188 | stepUtilities = _input['stepUtilities'] 189 | 190 | # create demand edge weights 191 | try: 192 | for i,j,l in zip(outboundAgents,inboundAgents,stepDemands): 193 | network[i][j]['demand'] = l 194 | except: 195 | pass 196 | 197 | # Create cic % edge weights 198 | try: 199 | for i,j in zip(outboundAgents,inboundAgents): 200 | # if one of the agents is external, we will transact in 100% shilling 201 | if i == 'external': 202 | network[i][j]['fractionOfDemandInCIC'] = 1 203 | elif j == 'external': 204 | network[i][j]['fractionOfDemandInCIC'] = 1 205 | else: 206 | network[i][j]['fractionOfDemandInCIC'] = fractionOfDemandInCIC 207 | except: 208 | pass 209 | 210 | # Create utility edge types 211 | try: 212 | for i,j,l in zip(outboundAgents,inboundAgents,stepUtilities): 213 | network[i][j]['utility'] = l 214 | except: 215 | pass 216 | 217 | x = network 218 | return (y,x) 219 | 220 | 221 | def update_outboundAgents(params,step,sL,s,_input): 222 | ''' 223 | Update outBoundAgents state variable 224 | ''' 225 | y = 'outboundAgents' 226 | 227 | x = _input['outboundAgents'] 228 | 229 | return (y,x) 230 | 231 | def update_inboundAgents(params,step,sL,s,_input): 232 | ''' 233 | Update inBoundAgents state variable 234 | ''' 235 | y = 'inboundAgents' 236 | 237 | x = _input['inboundAgents'] 238 | return (y,x) 239 | 240 | 241 | def update_node_spend(params, step, sL, s,_input): 242 | ''' 243 | Update network with actual spend of agents. 244 | ''' 245 | y = 'network' 246 | network = s['network'] 247 | 248 | spendI = _input['spendI'] 249 | spendJ = _input['spendJ'] 250 | spendAmount = _input['spendAmount'] 251 | 252 | for i,j,l in zip(spendI,spendJ,spendAmount): 253 | network[i][j]['spend'] = l 254 | if i == 'external': 255 | network[i][j]['fractionOfActualSpendInCIC'] = 1 256 | elif j == 'external': 257 | network[i][j]['fractionOfActualSpendInCIC'] = 1 258 | else: 259 | network[i][j]['fractionOfActualSpendInCIC'] = fractionOfActualSpendInCIC 260 | 261 | outflowSpend, inflowSpend = iterateEdges(network,'spend') 262 | 263 | for i, j in inflowSpend.items(): 264 | if i == 'external': 265 | network.nodes[i]['native_currency'] = network.nodes[i]['native_currency'] + inflowSpend[i] 266 | elif j == 'external': 267 | network.nodes[i]['native_currency'] = network.nodes[i]['native_currency'] + inflowSpend[i] 268 | else: 269 | network.nodes[i]['native_currency'] = network.nodes[i]['native_currency'] + inflowSpend[i] * (1- fractionOfDemandInCIC) 270 | network.nodes[i]['tokens'] = network.nodes[i]['tokens'] + (inflowSpend[i] * fractionOfDemandInCIC) 271 | 272 | for i, j in outflowSpend.items(): 273 | if i == 'external': 274 | network.nodes[i]['native_currency'] = network.nodes[i]['native_currency'] - outflowSpend[i] 275 | elif j == 'external': 276 | network.nodes[i]['native_currency'] = network.nodes[i]['native_currency'] - outflowSpend[i] 277 | else: 278 | network.nodes[i]['native_currency'] = network.nodes[i]['native_currency'] - outflowSpend[i]* (1- fractionOfDemandInCIC) 279 | network.nodes[i]['tokens'] = network.nodes[i]['tokens'] - (outflowSpend[i] * fractionOfDemandInCIC) 280 | 281 | # Store the net of the inflow and outflow per step 282 | network.nodes['external']['delta_native_currency'] = sum(inflowSpend.values()) - sum(outflowSpend.values()) 283 | 284 | x = network 285 | return (y,x) 286 | 287 | 288 | def update_withdraw(params, step, sL, s,_input): 289 | ''' 290 | Update flow state variable with the aggregated amount of shillings withdrawn 291 | ''' 292 | y = 'withdraw' 293 | x = s['withdraw'] 294 | if _input['withdraw']: 295 | x = _input['withdraw'] 296 | else: 297 | x = 0 298 | 299 | return (y,x) 300 | 301 | def update_network_withraw(params, step, sL, s,_input): 302 | ''' 303 | Update network for agents withdrawing 304 | ''' 305 | y = 'network' 306 | network = s['network'] 307 | withdraw = _input['withdraw'] 308 | 309 | if withdraw: 310 | for i,j in withdraw.items(): 311 | # update agent nodes 312 | network.nodes[i]['tokens'] = network.nodes[i]['tokens'] - j 313 | network.nodes[i]['native_currency'] = network.nodes[i]['native_currency'] + (j * leverage) 314 | 315 | withdrawnCICSum = [] 316 | for i,j in withdraw.items(): 317 | withdrawnCICSum.append(j) 318 | 319 | # update cic node 320 | network.nodes['cic']['native_currency'] = network.nodes[i]['native_currency'] - (sum(withdrawnCICSum) * leverage) 321 | network.nodes['cic']['tokens'] = network.nodes[i]['tokens'] + (sum(withdrawnCICSum) * leverage) 322 | 323 | else: 324 | pass 325 | x = network 326 | return (y,x) 327 | 328 | 329 | def update_operatorFiatBalance_withdraw(params, step, sL, s,_input): 330 | ''' 331 | Update flow state variable with the aggregated amount of shillings withdrawn 332 | ''' 333 | y = 'operatorFiatBalance' 334 | x = s['operatorFiatBalance'] 335 | if _input['withdraw']: 336 | withdraw = _input['withdraw'] 337 | withdrawnCICSum = [] 338 | for i,j in withdraw.items(): 339 | withdrawnCICSum.append(j) 340 | x = x - sum(withdrawnCICSum) 341 | else: 342 | pass 343 | 344 | return (y,x) 345 | 346 | 347 | 348 | def update_operatorCICBalance_withdraw(params, step, sL, s,_input): 349 | ''' 350 | Update flow state variable with the aggregated amount of shillings withdrawn 351 | ''' 352 | y = 'operatorCICBalance' 353 | x = s['operatorCICBalance'] 354 | if _input['withdraw']: 355 | withdraw = _input['withdraw'] 356 | withdrawnCICSum = [] 357 | for i,j in withdraw.items(): 358 | withdrawnCICSum.append(j) 359 | x = x + sum(withdrawnCICSum) 360 | else: 361 | pass 362 | 363 | return (y,x) -------------------------------------------------------------------------------- /Simulation_param/images/agentDistribution.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlockScience/Community_Inclusion_Currencies/a8de2d06723759c6d2381a06f0aa397d3aadc847/Simulation_param/images/agentDistribution.png -------------------------------------------------------------------------------- /Simulation_param/images/dualoperator.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlockScience/Community_Inclusion_Currencies/a8de2d06723759c6d2381a06f0aa397d3aadc847/Simulation_param/images/dualoperator.png -------------------------------------------------------------------------------- /Simulation_param/images/experiments.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlockScience/Community_Inclusion_Currencies/a8de2d06723759c6d2381a06f0aa397d3aadc847/Simulation_param/images/experiments.png -------------------------------------------------------------------------------- /Simulation_param/images/gap_statistic.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlockScience/Community_Inclusion_Currencies/a8de2d06723759c6d2381a06f0aa397d3aadc847/Simulation_param/images/gap_statistic.png -------------------------------------------------------------------------------- /Simulation_param/images/graph.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlockScience/Community_Inclusion_Currencies/a8de2d06723759c6d2381a06f0aa397d3aadc847/Simulation_param/images/graph.png -------------------------------------------------------------------------------- /Simulation_param/images/pca.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlockScience/Community_Inclusion_Currencies/a8de2d06723759c6d2381a06f0aa397d3aadc847/Simulation_param/images/pca.png -------------------------------------------------------------------------------- /Simulation_param/images/v4differentialspec.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlockScience/Community_Inclusion_Currencies/a8de2d06723759c6d2381a06f0aa397d3aadc847/Simulation_param/images/v4differentialspec.png -------------------------------------------------------------------------------- /Simulation_param/model/economyconfig.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 | 10 | from .genesis_states import genesis_states 11 | from .partial_state_update_block import partial_state_update_block 12 | 13 | params: Dict[str, List[int]] = { 14 | 'drip_frequency': [30,60,90] # in days 15 | } 16 | 17 | 18 | sim_config = config_sim({ 19 | 'N': 3, 20 | 'T': range(30), #day 21 | 'M': params, 22 | }) 23 | 24 | seeds = { 25 | 'p': np.random.RandomState(26042019), 26 | } 27 | env_processes = {} 28 | 29 | 30 | exp = Experiment() 31 | 32 | exp.append_configs( 33 | sim_configs=sim_config, 34 | initial_state=genesis_states, 35 | seeds = seeds, 36 | env_processes=env_processes, 37 | partial_state_update_blocks=partial_state_update_block 38 | ) 39 | 40 | -------------------------------------------------------------------------------- /Simulation_param/model/genesis_states.py: -------------------------------------------------------------------------------- 1 | from .parts.initialization import * 2 | import pandas as pd 3 | 4 | genesis_states = { 5 | # initial states of the economy 6 | 'network': create_network(),# networkx market 7 | 'KPIDemand': {}, 8 | 'KPISpend': {}, 9 | 'KPISpendOverDemand': {}, 10 | 'VelocityOfMoney':0, 11 | 'startingBalance': {}, 12 | '30_day_spend': {}, 13 | 'withdraw':{}, 14 | 'outboundAgents':[], 15 | 'inboundAgents':[], 16 | 'operatorFiatBalance': initialOperatingFiatBalance, 17 | 'operatorCICBalance': initialOperatingCICBalance, 18 | 'fundsInProcess': {'timestep':[],'decision':[],'cic':[],'shilling':[]}, 19 | 'totalDistributedToAgents':0, 20 | 'totalMinted':0, 21 | 'totalBurned':0 22 | } 23 | 24 | -------------------------------------------------------------------------------- /Simulation_param/model/partial_state_update_block.py: -------------------------------------------------------------------------------- 1 | from .parts.exogenousProcesses import * 2 | from .parts.kpis import * 3 | from .parts.system import * 4 | from .parts.operatorentity import * 5 | 6 | partial_state_update_block = { 7 | # Exogenous 8 | 'Exogenous': { 9 | 'policies': { 10 | }, 11 | 'variables': { 12 | 'startingBalance': startingBalance, 13 | 'operatorFiatBalance': redCrossDrop, 14 | '30_day_spend': update_30_day_spend, 15 | 'network':clear_agent_activity 16 | } 17 | }, 18 | # Users 19 | 'Behaviors': { 20 | 'policies': { 21 | 'action': choose_agents 22 | }, 23 | 'variables': { 24 | 'network': update_agent_activity, 25 | 'outboundAgents': update_outboundAgents, 26 | 'inboundAgents':update_inboundAgents 27 | } 28 | }, 29 | 'Spend allocation': { 30 | 'policies': { 31 | 'action': spend_allocation 32 | }, 33 | 'variables': { 34 | 'network': update_node_spend 35 | } 36 | }, 37 | 'Withdraw behavior': { 38 | 'policies': { 39 | 'action': withdraw_calculation 40 | }, 41 | 'variables': { 42 | 'withdraw': update_withdraw, 43 | 'network':update_network_withraw, 44 | 'operatorFiatBalance':update_operatorFiatBalance_withdraw, 45 | 'operatorCICBalance':update_operatorCICBalance_withdraw 46 | } 47 | }, 48 | # Operator 49 | 'Operator Disburse to Agents': { 50 | 'policies': { 51 | 'action': disbursement_to_agents 52 | }, 53 | 'variables': { 54 | 'network':update_agent_tokens, 55 | 'operatorCICBalance':update_operator_FromDisbursements, 56 | 'totalDistributedToAgents':update_totalDistributedToAgents 57 | } 58 | }, 59 | 'Operator Inventory Control': { 60 | 'policies': { 61 | 'action': inventory_controller 62 | }, 63 | 'variables': { 64 | 'operatorFiatBalance':update_operator_fiatBalance, 65 | 'operatorCICBalance':update_operator_cicBalance, 66 | 'totalMinted': update_totalMinted, 67 | 'totalBurned':update_totalBurned, 68 | 'fundsInProcess':update_fundsInProcess, 69 | 'network':update_network_mintBurn 70 | } 71 | }, 72 | 73 | # KPIs 74 | 'KPIs': { 75 | 'policies': { 76 | 'action':kpis 77 | }, 78 | 'variables':{ 79 | 'KPIDemand': update_KPIDemand, 80 | 'KPISpend': update_KPISpend, 81 | 'KPISpendOverDemand': update_KPISpendOverDemand 82 | } 83 | }, 84 | 'Velocity': { 85 | 'policies': { 86 | 'action':velocity_of_money 87 | }, 88 | 'variables':{ 89 | 90 | 'VelocityOfMoney': update_velocity_of_money 91 | } 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /Simulation_param/model/parts/__pycache__/designed.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlockScience/Community_Inclusion_Currencies/a8de2d06723759c6d2381a06f0aa397d3aadc847/Simulation_param/model/parts/__pycache__/designed.cpython-36.pyc -------------------------------------------------------------------------------- /Simulation_param/model/parts/__pycache__/designed.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlockScience/Community_Inclusion_Currencies/a8de2d06723759c6d2381a06f0aa397d3aadc847/Simulation_param/model/parts/__pycache__/designed.cpython-37.pyc -------------------------------------------------------------------------------- /Simulation_param/model/parts/__pycache__/exogenousProcesses.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlockScience/Community_Inclusion_Currencies/a8de2d06723759c6d2381a06f0aa397d3aadc847/Simulation_param/model/parts/__pycache__/exogenousProcesses.cpython-36.pyc -------------------------------------------------------------------------------- /Simulation_param/model/parts/__pycache__/exogenousProcesses.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlockScience/Community_Inclusion_Currencies/a8de2d06723759c6d2381a06f0aa397d3aadc847/Simulation_param/model/parts/__pycache__/exogenousProcesses.cpython-37.pyc -------------------------------------------------------------------------------- /Simulation_param/model/parts/__pycache__/initialization.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlockScience/Community_Inclusion_Currencies/a8de2d06723759c6d2381a06f0aa397d3aadc847/Simulation_param/model/parts/__pycache__/initialization.cpython-37.pyc -------------------------------------------------------------------------------- /Simulation_param/model/parts/__pycache__/kpis.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlockScience/Community_Inclusion_Currencies/a8de2d06723759c6d2381a06f0aa397d3aadc847/Simulation_param/model/parts/__pycache__/kpis.cpython-36.pyc -------------------------------------------------------------------------------- /Simulation_param/model/parts/__pycache__/kpis.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlockScience/Community_Inclusion_Currencies/a8de2d06723759c6d2381a06f0aa397d3aadc847/Simulation_param/model/parts/__pycache__/kpis.cpython-37.pyc -------------------------------------------------------------------------------- /Simulation_param/model/parts/__pycache__/operatorentity.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlockScience/Community_Inclusion_Currencies/a8de2d06723759c6d2381a06f0aa397d3aadc847/Simulation_param/model/parts/__pycache__/operatorentity.cpython-37.pyc -------------------------------------------------------------------------------- /Simulation_param/model/parts/__pycache__/subpopulation_clusters.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlockScience/Community_Inclusion_Currencies/a8de2d06723759c6d2381a06f0aa397d3aadc847/Simulation_param/model/parts/__pycache__/subpopulation_clusters.cpython-37.pyc -------------------------------------------------------------------------------- /Simulation_param/model/parts/__pycache__/supportingFunctions.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlockScience/Community_Inclusion_Currencies/a8de2d06723759c6d2381a06f0aa397d3aadc847/Simulation_param/model/parts/__pycache__/supportingFunctions.cpython-37.pyc -------------------------------------------------------------------------------- /Simulation_param/model/parts/__pycache__/system.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlockScience/Community_Inclusion_Currencies/a8de2d06723759c6d2381a06f0aa397d3aadc847/Simulation_param/model/parts/__pycache__/system.cpython-37.pyc -------------------------------------------------------------------------------- /Simulation_param/model/parts/exogenousProcesses.py: -------------------------------------------------------------------------------- 1 | 2 | import numpy as np 3 | import pandas as pd 4 | from .initialization import * 5 | from .supportingFunctions import * 6 | 7 | 8 | def startingBalance(params, step, sL, s, _input): 9 | ''' 10 | Calculate agent starting balance every 30 days 11 | ''' 12 | y = 'startingBalance' 13 | network = s['network'] 14 | 15 | startingBalance = {} 16 | 17 | timestep = s['timestep'] 18 | 19 | division = timestep % 31 == 0 20 | 21 | if timestep == 1: 22 | for i in clusters: 23 | startingBalance[i] = network.nodes[i]['tokens'] 24 | elif division == True: 25 | for i in clusters: 26 | startingBalance[i] = network.nodes[i]['tokens'] 27 | else: 28 | startingBalance = s['startingBalance'] 29 | x = startingBalance 30 | 31 | return (y, x) 32 | 33 | def update_30_day_spend(params, step, sL, s,_input): 34 | ''' 35 | Aggregate agent spend. Refresh every 30 days. 36 | ''' 37 | y = '30_day_spend' 38 | network = s['network'] 39 | 40 | timestep = s['timestep'] 41 | 42 | division = timestep % 31 == 0 43 | 44 | if division == True: 45 | outflowSpend, inflowSpend = iterateEdges(network,'spend') 46 | spend = outflowSpend 47 | else: 48 | spendOld = s['30_day_spend'] 49 | outflowSpend, inflowSpend = iterateEdges(network,'spend') 50 | spend = DictionaryMergeAddition(spendOld,outflowSpend) 51 | 52 | x = spend 53 | return (y, x) 54 | 55 | def redCrossDrop(params, step, sL, s, _input): 56 | ''' 57 | Every 30 days, the red cross drips to the grassroots operator node 58 | ''' 59 | y = 'operatorFiatBalance' 60 | fiatBalance = s['operatorFiatBalance'] 61 | 62 | timestep = s['timestep'] 63 | 64 | division = timestep % params['drip_frequency'] == 0 65 | 66 | if division == True: 67 | fiatBalance = fiatBalance + drip 68 | else: 69 | pass 70 | 71 | x = fiatBalance 72 | return (y, x) 73 | 74 | def clear_agent_activity(params,step,sL,s,_input): 75 | ''' 76 | Clear agent activity from the previous timestep 77 | ''' 78 | y = 'network' 79 | network = s['network'] 80 | 81 | if s['timestep'] > 0: 82 | outboundAgents = s['outboundAgents'] 83 | inboundAgents = s['inboundAgents'] 84 | 85 | try: 86 | for i,j in zip(outboundAgents,inboundAgents): 87 | network[i][j]['demand'] = 0 88 | except: 89 | pass 90 | 91 | # Clear cic % demand edge weights 92 | try: 93 | for i,j in zip(outboundAgents,inboundAgents): 94 | network[i][j]['fractionOfDemandInCIC'] = 0 95 | except: 96 | pass 97 | 98 | 99 | # Clear utility edge types 100 | try: 101 | for i,j in zip(outboundAgents,inboundAgents): 102 | network[i][j]['utility'] = 0 103 | except: 104 | pass 105 | 106 | # Clear cic % spend edge weights 107 | try: 108 | for i,j in zip(outboundAgents,inboundAgents): 109 | network[i][j]['fractionOfActualSpendInCIC'] = 0 110 | except: 111 | pass 112 | # Clear spend edge types 113 | try: 114 | for i,j in zip(outboundAgents,inboundAgents): 115 | network[i][j]['spend'] = 0 116 | except: 117 | pass 118 | else: 119 | pass 120 | x = network 121 | return (y,x) -------------------------------------------------------------------------------- /Simulation_param/model/parts/initialization.py: -------------------------------------------------------------------------------- 1 | 2 | # import libraries 3 | import networkx as nx 4 | import matplotlib.pyplot as plt 5 | import numpy as np 6 | from .supportingFunctions import * 7 | from .subpopulation_clusters import * 8 | 9 | # Assumptions: 10 | # Amount received in shilling when withdraw occurs 11 | leverage = 1 12 | 13 | # process time 14 | process_lag = 15 # timesteps 15 | 16 | # red cross drip amount 17 | drip = 10000 18 | 19 | # starting operatorFiatBalance 20 | initialOperatingFiatBalance = 100000 21 | # starting operatorCICBalance 22 | initialOperatingCICBalance = 100000 23 | 24 | redCrossDripFrequency = 90 # days 25 | 26 | # system actors 27 | system = ['external','cic'] 28 | 29 | # chamas 30 | chama = ['chama_1','chama_2','chama_3','chama_4'] 31 | 32 | # traders 33 | traders = ['ta','tb','tc'] #only trading on the cic. Link to external and cic not to other agents 34 | 35 | allAgents = clusters.copy() + system 36 | 37 | 38 | R0 = 40000 #xDAI 39 | kappa = 4 #leverage 40 | P0 = 1/100 #initial price 41 | S0 = kappa*R0/P0 42 | V0 = invariant(R0,S0,kappa) 43 | P = spot_price(R0, V0, kappa) 44 | 45 | # Price level 46 | priceLevel = 100 47 | 48 | fractionOfDemandInCIC = 0.5 49 | fractionOfActualSpendInCIC = 0.5 50 | 51 | def create_network(): 52 | # Create network graph 53 | network = nx.DiGraph() 54 | 55 | # Add nodes for n participants plus the external economy and the cic network 56 | for i in clusters: 57 | network.add_node(i,type='Agent',tokens=clustersMedianSourceBalance[int(i)], native_currency = int(np.random.uniform(low=clusters1stQSourceBalance[int(i)], high=clusters3rdQSourceBalance[int(i)], size=1)[0])) 58 | 59 | 60 | network.add_node('external',type='Cloud',native_currency = 100000000,tokens = 0,delta_native_currency = 0, pos=(1,50)) 61 | network.add_node('cic',type='Contract',tokens= S0, native_currency = R0,pos=(50,1)) 62 | 63 | for i in chama: 64 | network.add_node(i,type='Chama') 65 | 66 | for i in traders: 67 | network.add_node(i,type='Trader',tokens=20, native_currency = 20, 68 | price_belief = 1, trust_level = 1) 69 | 70 | # Create bi-directional edges between all participants 71 | for i in allAgents: 72 | for j in allAgents: 73 | if i!=j: 74 | network.add_edge(i,j) 75 | 76 | # Create bi-directional edges between each trader and the external economy and the cic environment 77 | for i in traders: 78 | for j in system: 79 | if i!=j: 80 | network.add_edge(i,j) 81 | 82 | # Create bi-directional edges between some agent and a chama node representing membershio 83 | for i in chama: 84 | for j in clusters: 85 | if np.random.choice(['Member','Non_Member'],1,p=[.50,.50])[0] == 'Member': 86 | network.add_edge(i,j) 87 | 88 | # Type colors 89 | color_map = [] 90 | for i in network.nodes: 91 | if network.nodes[i]['type'] == 'Agent': 92 | color_map.append('Red') 93 | elif network.nodes[i]['type'] == 'Cloud': 94 | color_map.append('Blue') 95 | elif network.nodes[i]['type'] == 'Contract': 96 | color_map.append('Green') 97 | elif network.nodes[i]['type'] == 'Trader': 98 | color_map.append('Yellow') 99 | elif network.nodes[i]['type'] == 'Chama': 100 | color_map.append('Orange') 101 | 102 | pos = nx.spring_layout(network,pos=nx.get_node_attributes(network,'pos'),fixed=nx.get_node_attributes(network,'pos'),seed=10) 103 | nx.draw(network,node_color = color_map,pos=pos,with_labels=True,alpha=0.7) 104 | plt.savefig('images/graph.png') 105 | plt.figure(figsize=(20,20)) 106 | plt.show() 107 | return network -------------------------------------------------------------------------------- /Simulation_param/model/parts/kpis.py: -------------------------------------------------------------------------------- 1 | 2 | import numpy as np 3 | from .initialization import * 4 | from .supportingFunctions import * 5 | import networkx as nx 6 | 7 | 8 | # Behaviors 9 | def kpis(params, step, sL, s): 10 | '''''' 11 | # instantiate network state 12 | network = s['network'] 13 | 14 | KPIDemand = {} 15 | KPISpend = {} 16 | KPISpendOverDemand = {} 17 | for i in mixingAgents: 18 | demand = [] 19 | for j in network.adj[i]: 20 | try: 21 | demand.append(network.adj[i][j]['demand']) 22 | except: 23 | pass 24 | 25 | spend = [] 26 | for j in network.adj[i]: 27 | try: 28 | spend.append(network.adj[i][j]['spend']) 29 | except: 30 | pass 31 | 32 | sumDemand = sum(demand) 33 | sumSpend = sum(spend) 34 | try: 35 | spendOverDemand = sumSpend/sumDemand 36 | except: 37 | spendOverDemand = 0 38 | 39 | KPIDemand[i] = sumDemand 40 | KPISpend[i] = sumSpend 41 | KPISpendOverDemand[i] = spendOverDemand 42 | 43 | #print(nx.katz_centrality_numpy(G=network,weight='spend')) 44 | return {'KPIDemand':KPIDemand,'KPISpend':KPISpend,'KPISpendOverDemand':KPISpendOverDemand} 45 | 46 | def velocity_of_money(params, step, sL, s): 47 | '''''' 48 | # instantiate network state 49 | network = s['network'] 50 | 51 | KPISpend = s['KPISpend'] 52 | 53 | T = [] 54 | for i,j in KPISpend.items(): 55 | T.append(j) 56 | 57 | T = sum(T) 58 | 59 | M = [] 60 | for i in clusters: 61 | M.append(network.nodes[i]['tokens'] + network.nodes[i]['native_currency']) 62 | 63 | M = sum(M) 64 | 65 | V_t = (priceLevel *T)/M 66 | 67 | return {'V_t':V_t,'T':T,'M':M} 68 | 69 | 70 | # Mechanisms 71 | def update_KPIDemand(params, step, sL, s,_input): 72 | y = 'KPIDemand' 73 | x = _input['KPIDemand'] 74 | return (y,x) 75 | 76 | def update_KPISpend(params, step, sL, s,_input): 77 | y = 'KPISpend' 78 | x = _input['KPISpend'] 79 | return (y,x) 80 | 81 | def update_KPISpendOverDemand(params, step, sL, s,_input): 82 | y = 'KPISpendOverDemand' 83 | x = _input['KPISpendOverDemand'] 84 | return (y,x) 85 | 86 | 87 | def update_velocity_of_money(params, step, sL, s,_input): 88 | y = 'VelocityOfMoney' 89 | x = _input['V_t'] 90 | return (y,x) 91 | -------------------------------------------------------------------------------- /Simulation_param/model/parts/operatorentity.py: -------------------------------------------------------------------------------- 1 | 2 | import numpy as np 3 | import pandas as pd 4 | from cadCAD.configuration.utils import access_block 5 | from .initialization import * 6 | from .supportingFunctions import * 7 | from .subpopulation_clusters import * 8 | from collections import OrderedDict 9 | 10 | # Parameters 11 | FrequencyOfAllocation = 30 12 | idealFiat = 100000 13 | idealCIC = 100000 14 | varianceCIC = 30000 15 | varianceFiat = 30000 16 | unadjustedPerAgent = 100 17 | 18 | 19 | # Behaviors 20 | def disbursement_to_agents(params, step, sL, s): 21 | ''' 22 | Distribute every FrequencyOfAllocation days to agents based off of centrality allocation metric 23 | ''' 24 | fiatBalance = s['operatorFiatBalance'] 25 | cicBalance = s['operatorCICBalance'] 26 | timestep = s['timestep'] 27 | 28 | division = timestep % FrequencyOfAllocation == 0 29 | 30 | if division == True: 31 | agentDistribution ={} # agent: amount distributed 32 | for i,j in agentAllocation.items(): 33 | agentDistribution[i] = unadjustedPerAgent * agentAllocation[i][1] 34 | distribute = 'Yes' 35 | 36 | else: 37 | agentDistribution = 0 38 | distribute = 'No' 39 | 40 | 41 | return {'distribute':distribute,'amount':agentDistribution} 42 | 43 | 44 | def inventory_controller(params, step, sL, s): 45 | ''' 46 | Monetary policy hysteresis conservation allocation between fiat and cic reserves. 47 | ''' 48 | fiatBalance = s['operatorFiatBalance'] 49 | cicBalance = s['operatorCICBalance'] 50 | timestep = s['timestep'] 51 | fundsInProcess = s['fundsInProcess'] 52 | 53 | 54 | updatedCIC = cicBalance 55 | updatedFiat = fiatBalance 56 | 57 | # Toggle inventory controller 58 | # on 59 | #decision,amt = mint_burn_logic_control(idealCIC,updatedCIC,varianceCIC,updatedFiat,varianceFiat,idealFiat) 60 | # off 61 | decision = 'none' 62 | amt = 0 63 | 64 | if decision == 'burn': 65 | try: 66 | deltaR, realized_price = withdraw(amt,updatedFiat,updatedCIC, V0, kappa) 67 | # update state 68 | # fiatBalance = fiatBalance - deltaR 69 | # cicBalance = cicBalance - amt 70 | fiatChange = abs(deltaR) 71 | cicChange = amt 72 | 73 | except: 74 | print('Not enough to burn') 75 | 76 | fiatChange = 0 77 | cicChange = 0 78 | 79 | elif decision == 'mint': 80 | try: 81 | deltaS, realized_price = mint(amt,updatedFiat,updatedCIC, V0, kappa) 82 | # update state 83 | # fiatBalance = fiatBalance + amt 84 | # cicBalance = cicBalance + deltaS 85 | fiatChange = amt 86 | cicChange = abs(deltaS) 87 | 88 | except: 89 | print('Not enough to mint') 90 | fiatChange = 0 91 | cicChange = 0 92 | 93 | else: 94 | fiatChange = 0 95 | cicChange = 0 96 | decision = 'none' 97 | pass 98 | 99 | if decision == 'mint': 100 | fundsInProcess['timestep'].append(timestep + process_lag) 101 | fundsInProcess['decision'].append(decision) 102 | fundsInProcess['cic'].append(fiatChange) 103 | fundsInProcess['shilling'].append(cicChange) 104 | elif decision == 'burn': 105 | fundsInProcess['timestep'].append(timestep +process_lag) 106 | fundsInProcess['decision'].append(decision) 107 | fundsInProcess['cic'].append(fiatChange) 108 | fundsInProcess['shilling'].append(cicChange) 109 | else: 110 | pass 111 | 112 | return {'decision':decision,'fiatChange':fiatChange,'cicChange':cicChange,'fundsInProcess':fundsInProcess} 113 | 114 | 115 | 116 | # Mechanisms 117 | def update_agent_tokens(params,step,sL,s,_input): 118 | ''' 119 | ''' 120 | y = 'network' 121 | network = s['network'] 122 | 123 | distribute = _input['distribute'] 124 | amount = _input['amount'] 125 | 126 | if distribute == 'Yes': 127 | for i in clusters: 128 | network.nodes[i]['tokens'] = network.nodes[i]['tokens'] + amount[i] 129 | else: 130 | pass 131 | 132 | return (y,network) 133 | 134 | def update_operator_FromDisbursements(params,step,sL,s,_input): 135 | ''' 136 | ''' 137 | y = 'operatorCICBalance' 138 | x = s['operatorCICBalance'] 139 | timestep = s['timestep'] 140 | 141 | distribute = _input['distribute'] 142 | amount = _input['amount'] 143 | 144 | if distribute == 'Yes': 145 | totalDistribution = [] 146 | for i,j in amount.items(): 147 | totalDistribution.append(j) 148 | 149 | totalDistribution = sum(totalDistribution) 150 | x = x - totalDistribution 151 | 152 | else: 153 | pass 154 | 155 | return (y,x) 156 | 157 | def update_totalDistributedToAgents(params,step,sL,s,_input): 158 | ''' 159 | ''' 160 | y = 'totalDistributedToAgents' 161 | x = s['totalDistributedToAgents'] 162 | timestep = s['timestep'] 163 | 164 | distribute = _input['distribute'] 165 | amount = _input['amount'] 166 | 167 | if distribute == 'Yes': 168 | totalDistribution = [] 169 | for i,j in amount.items(): 170 | totalDistribution.append(j) 171 | 172 | totalDistribution = sum(totalDistribution) 173 | x = x + totalDistribution 174 | else: 175 | pass 176 | 177 | return (y,x) 178 | 179 | def update_operator_fiatBalance(params,step,sL,s,_input): 180 | ''' 181 | ''' 182 | y = 'operatorFiatBalance' 183 | x = s['operatorFiatBalance'] 184 | fundsInProcess = s['fundsInProcess'] 185 | timestep = s['timestep'] 186 | if _input['fiatChange']: 187 | try: 188 | if fundsInProcess['timestep'][0] == timestep + 1: 189 | if fundsInProcess['decision'][0] == 'mint': 190 | x = x - abs(fundsInProcess['shilling'][0]) 191 | elif fundsInProcess['decision'][0] == 'burn': 192 | x = x + abs(fundsInProcess['shilling'][0]) 193 | else: 194 | pass 195 | except: 196 | pass 197 | else: 198 | pass 199 | 200 | 201 | return (y,x) 202 | 203 | def update_operator_cicBalance(params,step,sL,s,_input): 204 | ''' 205 | ''' 206 | y = 'operatorCICBalance' 207 | x = s['operatorCICBalance'] 208 | fundsInProcess = s['fundsInProcess'] 209 | timestep = s['timestep'] 210 | 211 | if _input['cicChange']: 212 | try: 213 | if fundsInProcess['timestep'][0] == timestep + 1: 214 | if fundsInProcess['decision'][0] == 'mint': 215 | x = x + abs(fundsInProcess['cic'][0]) 216 | elif fundsInProcess['decision'][0] == 'burn': 217 | x = x - abs(fundsInProcess['cic'][0]) 218 | else: 219 | pass 220 | except: 221 | pass 222 | else: 223 | pass 224 | 225 | return (y,x) 226 | 227 | def update_totalMinted(params,step,sL,s,_input): 228 | ''' 229 | ''' 230 | y = 'totalMinted' 231 | x = s['totalMinted'] 232 | timestep = s['timestep'] 233 | try: 234 | if _input['fundsInProcess']['decision'][0] == 'mint': 235 | x = x + abs(_input['fundsInProcess']['cic'][0]) 236 | elif _input['fundsInProcess']['decision'][0] == 'burn': 237 | pass 238 | except: 239 | pass 240 | 241 | 242 | return (y,x) 243 | 244 | def update_totalBurned(params,step,sL,s,_input): 245 | ''' 246 | ''' 247 | y = 'totalBurned' 248 | x = s['totalBurned'] 249 | timestep = s['timestep'] 250 | try: 251 | if _input['fundsInProcess']['decision'][0] == 'burn': 252 | x = x + abs(_input['fundsInProcess']['cic'][0]) 253 | elif _input['fundsInProcess']['decision'][0] == 'mint': 254 | pass 255 | except: 256 | pass 257 | 258 | return (y,x) 259 | 260 | 261 | def update_fundsInProcess(params,step,sL,s,_input): 262 | ''' 263 | ''' 264 | y = 'fundsInProcess' 265 | x = _input['fundsInProcess'] 266 | timestep = s['timestep'] 267 | 268 | if _input['fundsInProcess']: 269 | try: 270 | if x['timestep'][0] == timestep: 271 | del x['timestep'][0] 272 | del x['decision'][0] 273 | del x['cic'][0] 274 | del x['shilling'][0] 275 | else: 276 | pass 277 | except: 278 | pass 279 | else: 280 | pass 281 | 282 | return (y,x) 283 | 284 | def update_network_mintBurn(params, step, sL, s,_input): 285 | ''' 286 | Update network for minting and burning 287 | ''' 288 | y = 'network' 289 | network = s['network'] 290 | 291 | try: 292 | if _input['fundsInProcess']['decision'][0] == 'mint': 293 | amountCIC = abs(_input['fundsInProcess']['cic'][0]) 294 | amountFiat = abs(_input['fundsInProcess']['shilling'][0]) 295 | decision = 'mint' 296 | elif _input['fundsInProcess']['decision'][0] == 'burn': 297 | amountCIC = abs(_input['fundsInProcess']['cic'][0]) 298 | amountFiat = abs(_input['fundsInProcess']['shilling'][0]) 299 | decision = 'burn' 300 | else: 301 | amountCIC = 0 302 | amountFiat = 0 303 | decision = 'none' 304 | except: 305 | amountCIC = 0 306 | amountFiat = 0 307 | decision = 'none' 308 | 309 | 310 | if decision == 'mint': 311 | # update cic node 312 | network.nodes['cic']['native_currency'] = network.nodes[i]['native_currency'] + amountFiat 313 | network.nodes['cic']['tokens'] = network.nodes[i]['tokens'] + amountCIC 314 | elif decision == 'burn': 315 | # update cic node 316 | network.nodes['cic']['native_currency'] = network.nodes[i]['native_currency'] - amountFiat 317 | network.nodes['cic']['tokens'] = network.nodes[i]['tokens'] - amountCIC 318 | elif decision == 'none': 319 | pass 320 | 321 | x = network 322 | return (y,x) 323 | -------------------------------------------------------------------------------- /Simulation_param/model/parts/subpopulation_clusters.py: -------------------------------------------------------------------------------- 1 | 2 | clusters = ['0', 3 | '1', 4 | '2', 5 | '3', 6 | '4', 7 | '5', 8 | '6', 9 | '7', 10 | '8', 11 | '9', 12 | '10', 13 | '11', 14 | '12', 15 | '13', 16 | '14', 17 | '15', 18 | '16', 19 | '17', 20 | '18', 21 | '19', 22 | '20', 23 | '21', 24 | '22', 25 | '23', 26 | '24', 27 | '25', 28 | '26', 29 | '27', 30 | '28', 31 | '29', 32 | '30', 33 | '31', 34 | '32', 35 | '33', 36 | '34', 37 | '35', 38 | '36', 39 | '37', 40 | '38', 41 | '39', 42 | '40', 43 | '41', 44 | '42', 45 | '43', 46 | '44', 47 | '45', 48 | '46', 49 | '47', 50 | '48', 51 | '49'] 52 | 53 | mixingAgents = ['0', 54 | '1', 55 | '2', 56 | '3', 57 | '4', 58 | '5', 59 | '6', 60 | '7', 61 | '8', 62 | '9', 63 | '10', 64 | '11', 65 | '12', 66 | '13', 67 | '14', 68 | '15', 69 | '16', 70 | '17', 71 | '18', 72 | '19', 73 | '20', 74 | '21', 75 | '22', 76 | '23', 77 | '24', 78 | '25', 79 | '26', 80 | '27', 81 | '28', 82 | '29', 83 | '30', 84 | '31', 85 | '32', 86 | '33', 87 | '34', 88 | '35', 89 | '36', 90 | '37', 91 | '38', 92 | '39', 93 | '40', 94 | '41', 95 | '42', 96 | '43', 97 | '44', 98 | '45', 99 | '46', 100 | '47', 101 | '48', 102 | '49', 103 | 'external'] 104 | 105 | 106 | clustersMedianSourceBalance = [150.0, 107 | 340.0, 108 | 250.0, 109 | 20.0, 110 | 330.0, 111 | 320.0, 112 | 240.0, 113 | 300.0, 114 | 300.0, 115 | 50.0, 116 | 900.0, 117 | 120.0, 118 | 400.0, 119 | 180.0, 120 | 300.0, 121 | 6000.0, 122 | 132.5, 123 | 130.0, 124 | 160.0, 125 | 5000.0, 126 | 150.0, 127 | 10000.0, 128 | 200.0, 129 | 10000.0, 130 | 200.0, 131 | 200.0, 132 | 35000.0, 133 | 20000.0, 134 | 100.0, 135 | 500.0, 136 | 425.0, 137 | 13320.0, 138 | 500.0, 139 | 500.0, 140 | 1000.0, 141 | 390.0, 142 | 150.0, 143 | 250.0, 144 | 45000.0, 145 | 36300.0, 146 | 960.0, 147 | 120.0, 148 | 200.0, 149 | 100.0, 150 | 220.0, 151 | 600.0, 152 | 62000.0, 153 | 500.0, 154 | 900.0, 155 | 486.0] 156 | 157 | clusters1stQSourceBalance = [56.0, 158 | 118.46, 159 | 105.0, 160 | 64767.51, 161 | 251652.0, 162 | 124.5, 163 | 4139.28, 164 | 146.1, 165 | 1002.5, 166 | 17145.78, 167 | 52676.2, 168 | 100.0, 169 | 121082.43, 170 | 112.0, 171 | 28849.43, 172 | 27619.22, 173 | 66.36, 174 | 251652.0, 175 | 148.0, 176 | 38653.54, 177 | 67.22, 178 | 121082.43, 179 | 6429.46, 180 | 555.04, 181 | 104.48, 182 | 96.43, 183 | 52676.2, 184 | 251652.0, 185 | 64.73, 186 | 36824.5, 187 | 15182.03, 188 | 485.94, 189 | 21660.89, 190 | 11210.0, 191 | 100579.18, 192 | 100.46, 193 | 2845.01, 194 | 3338.98, 195 | 1274.91, 196 | 6724.88, 197 | 38653.54, 198 | 114.5, 199 | 68.0, 200 | 100.0, 201 | 20.93, 202 | 14050.3, 203 | 63145.96, 204 | 9276.23, 205 | 63234.8, 206 | 64767.51] 207 | 208 | clusters3rdQSourceBalance = [403.96, 209 | 506.6, 210 | 592.96, 211 | 64767.51, 212 | 251652.0, 213 | 1501.41, 214 | 7214.9, 215 | 869.82, 216 | 1557.01, 217 | 18304.36, 218 | 55142.93, 219 | 419.96, 220 | 121082.43, 221 | 816.3, 222 | 38653.54, 223 | 37106.89, 224 | 770.65, 225 | 251652.0, 226 | 838.46, 227 | 38653.54, 228 | 315.0, 229 | 121082.43, 230 | 9074.79, 231 | 5726.66, 232 | 602.02, 233 | 437.96, 234 | 63234.8, 235 | 251652.0, 236 | 425.0, 237 | 40953.15, 238 | 17145.78, 239 | 6349.27, 240 | 25695.83, 241 | 13156.46, 242 | 100579.18, 243 | 819.33, 244 | 4158.5, 245 | 5597.38, 246 | 2823.81, 247 | 20030.91, 248 | 51710.52, 249 | 537.94, 250 | 542.92, 251 | 415.43, 252 | 895.66, 253 | 18304.36, 254 | 63145.96, 255 | 14050.3, 256 | 64767.51, 257 | 64767.51] 258 | 259 | clustersMu = [329.98, 260 | 588.11, 261 | 469.93, 262 | 492.32, 263 | 2443.89, 264 | 565.21, 265 | 1120.5, 266 | 408.1, 267 | 550.09, 268 | 503.42, 269 | 2478.89, 270 | 349.93, 271 | 9354.55, 272 | 453.69, 273 | 4298.1, 274 | 7508.1, 275 | 376.86, 276 | 8074.0, 277 | 333.75, 278 | 7691.43, 279 | 362.68, 280 | 15562.5, 281 | 672.28, 282 | 10809.6, 283 | 274.98, 284 | 405.46, 285 | 34555.56, 286 | 14338.57, 287 | 255.48, 288 | 1229.44, 289 | 1470.23, 290 | 14590.61, 291 | 1527.75, 292 | 770.73, 293 | 1039.05, 294 | 503.7, 295 | 362.11, 296 | 499.51, 297 | 45000.0, 298 | 37504.55, 299 | 1941.82, 300 | 262.96, 301 | 702.23, 302 | 168.57, 303 | 2000.58, 304 | 1383.32, 305 | 65333.33, 306 | 1454.43, 307 | 1483.11, 308 | 1853.03] 309 | 310 | clustersSigma = [583.23, 311 | 1501.26, 312 | 966.32, 313 | 1452.2, 314 | 6789.39, 315 | 847.29, 316 | 2228.12, 317 | 483.5, 318 | 852.2, 319 | 1170.38, 320 | 3256.26, 321 | 1174.55, 322 | 16235.99, 323 | 841.35, 324 | 7696.91, 325 | 6814.68, 326 | 785.21, 327 | 10886.9, 328 | 712.65, 329 | 8713.11, 330 | 708.54, 331 | 18542.24, 332 | 1164.0, 333 | 3682.08, 334 | 340.99, 335 | 624.76, 336 | 8171.77, 337 | 15060.34, 338 | 461.52, 339 | 1774.39, 340 | 4617.97, 341 | 4770.82, 342 | 2641.75, 343 | 1133.41, 344 | 767.87, 345 | 437.68, 346 | 652.72, 347 | 761.07, 348 | 7071.07, 349 | 5274.96, 350 | 2716.8, 351 | 572.43, 352 | 1553.21, 353 | 210.61, 354 | 4477.94, 355 | 1798.73, 356 | 31134.12, 357 | 2147.9, 358 | 1900.27, 359 | 2909.68] 360 | 361 | 362 | # nested dictionary 363 | UtilityTypesOrdered = {'0': {'Food/Water': 0.4119323241317899, 364 | 'Farming/Labour': 0.26090828138913624, 365 | 'Shop': 0.17916295636687443, 366 | 'Savings Group': 0.07266251113089937, 367 | 'Fuel/Energy': 0.034194122885129116, 368 | 'Transport': 0.02617987533392698, 369 | 'Health': 0.006767586821015138, 370 | 'Education': 0.004096170970614425, 371 | 'None': 0.004096170970614425}, 372 | '1': {'Food/Water': 1.0}, 373 | '2': {'Savings Group': 0.87890625, 374 | 'Health': 0.08984375, 375 | 'Food/Water': 0.03125}, 376 | '3': {'Savings Group': 0.4905964535196131, 377 | 'Farming/Labour': 0.3610961848468565, 378 | 'Food/Water': 0.14830736163353037}, 379 | '4': {'Farming/Labour': 0.2843866171003718, 380 | 'Shop': 0.25650557620817843, 381 | 'Fuel/Energy': 0.17843866171003717, 382 | 'Food/Water': 0.16171003717472118, 383 | 'None': 0.10966542750929369, 384 | 'Savings Group': 0.0055762081784386614, 385 | 'Transport': 0.0037174721189591076}, 386 | '5': {'Farming/Labour': 0.421875, 387 | 'Food/Water': 0.421875, 388 | 'Shop': 0.0625, 389 | 'Savings Group': 0.03125, 390 | 'Fuel/Energy': 0.03125, 391 | 'Transport': 0.03125}, 392 | '6': {'Savings Group': 0.6008097165991902, 393 | 'Food/Water': 0.35870445344129553, 394 | 'Shop': 0.04048582995951417}, 395 | '7': {'Farming/Labour': 0.4346590909090909, 396 | 'Food/Water': 0.2869318181818182, 397 | 'Shop': 0.1278409090909091, 398 | 'Fuel/Energy': 0.07670454545454546, 399 | 'Savings Group': 0.03977272727272727, 400 | 'Education': 0.017045454545454544, 401 | 'None': 0.011363636363636364, 402 | 'Transport': 0.002840909090909091, 403 | 'Health': 0.002840909090909091}, 404 | '8': {'Savings Group': 1.0}, 405 | '9': {'Savings Group': 0.7142857142857143, 406 | 'Food/Water': 0.18181818181818182, 407 | 'Farming/Labour': 0.07792207792207792, 408 | 'Education': 0.025974025974025976}, 409 | '10': {'Food/Water': 0.3499875508340941, 410 | 'Farming/Labour': 0.3162088140094614, 411 | 'Shop': 0.21047389824881732, 412 | 'Transport': 0.03950535314133953, 413 | 'None': 0.03386173126400531, 414 | 'Fuel/Energy': 0.022491493069964313, 415 | 'Education': 0.01709685451074778, 416 | 'Savings Group': 0.006473566271059839, 417 | 'Environment': 0.002157855423686613, 418 | 'Health': 0.0016598887874512407, 419 | 'Chama': 8.299443937256204e-05}, 420 | '11': {'Savings Group': 0.4873417721518987, 421 | 'Food/Water': 0.3377445339470656, 422 | 'Education': 0.09723820483314154, 423 | 'Farming/Labour': 0.06271576524741082, 424 | 'Shop': 0.014959723820483314}, 425 | '12': {'Food/Water': 0.34994337485843713, 426 | 'Shop': 0.2332955832389581, 427 | 'Farming/Labour': 0.19592298980747452, 428 | 'Fuel/Energy': 0.057757644394110984, 429 | 'Savings Group': 0.053227633069082674, 430 | 'Education': 0.05096262740656852, 431 | 'None': 0.026047565118912798, 432 | 'Transport': 0.020385050962627407, 433 | 'Health': 0.011325028312570781, 434 | 'Environment': 0.0011325028312570782}, 435 | '13': {'Savings Group': 0.3712871287128713, 436 | 'Food/Water': 0.247974797479748, 437 | 'Shop': 0.19801980198019803, 438 | 'Fuel/Energy': 0.08235823582358236, 439 | 'Health': 0.07605760576057606, 440 | 'Farming/Labour': 0.024302430243024302}, 441 | '14': {'Savings Group': 1.0}, 442 | '15': {'Savings Group': 1.0}, 443 | '16': {'Savings Group': 0.5, 'Food/Water': 0.5}, 444 | '17': {'Savings Group': 0.7335701598579041, 445 | 'Shop': 0.17584369449378331, 446 | 'Food/Water': 0.0905861456483126}, 447 | '18': {'Savings Group': 0.6984126984126984, 448 | 'Food/Water': 0.23809523809523808, 449 | 'Farming/Labour': 0.06349206349206349}, 450 | '19': {'Savings Group': 1.0}, 451 | '20': {'Savings Group': 1.0}, 452 | '21': {'Farming/Labour': 0.47619047619047616, 453 | 'Food/Water': 0.3333333333333333, 454 | 'Shop': 0.09523809523809523, 455 | 'Fuel/Energy': 0.047619047619047616, 456 | 'Transport': 0.047619047619047616}, 457 | '22': {'Food/Water': 0.33040588654165676, 458 | 'Farming/Labour': 0.3209114645145977, 459 | 'Shop': 0.164016140517446, 460 | 'None': 0.06147638262520769, 461 | 'Fuel/Energy': 0.05008307619273677, 462 | 'Transport': 0.028957987182530263, 463 | 'Savings Group': 0.023973415618324233, 464 | 'Education': 0.014478993591265131, 465 | 'Health': 0.0035604082601471635, 466 | 'Environment': 0.0011868027533823878, 467 | 'Staff': 0.00047472110135295516, 468 | 'Chama': 0.00023736055067647758, 469 | 'Game': 0.00023736055067647758}, 470 | '23': {'Savings Group': 0.8323424494649228, 471 | 'Farming/Labour': 0.16765755053507728}, 472 | '24': {'Farming/Labour': 0.38481675392670156, 473 | 'Food/Water': 0.3717277486910995, 474 | 'Shop': 0.1387434554973822, 475 | 'Fuel/Energy': 0.05235602094240838, 476 | 'Transport': 0.02356020942408377, 477 | 'Savings Group': 0.01832460732984293, 478 | 'Education': 0.007853403141361256, 479 | 'Staff': 0.002617801047120419}, 480 | '25': {'Savings Group': 0.7916666666666666, 481 | 'Food/Water': 0.20833333333333334}, 482 | '26': {'Savings Group': 0.7442348008385744, 'Food/Water': 0.2557651991614256}, 483 | '27': {'Food/Water': 0.3333333333333333, 484 | 'Farming/Labour': 0.25, 485 | 'Health': 0.25, 486 | 'Savings Group': 0.08333333333333333, 487 | 'Fuel/Energy': 0.08333333333333333}, 488 | '28': {'Food/Water': 1.0}, 489 | '29': {'Food/Water': 0.27335640138408307, 490 | 'Farming/Labour': 0.23529411764705882, 491 | 'Shop': 0.21972318339100347, 492 | 'Fuel/Energy': 0.21280276816608998, 493 | 'None': 0.03806228373702422, 494 | 'Education': 0.006920415224913495, 495 | 'Transport': 0.006920415224913495, 496 | 'Savings Group': 0.005190311418685121, 497 | 'Staff': 0.0017301038062283738}, 498 | '30': {'Food/Water': 0.36228287841191065, 499 | 'Shop': 0.2679900744416873, 500 | 'Farming/Labour': 0.21712158808933002, 501 | 'Savings Group': 0.08436724565756824, 502 | 'Education': 0.02481389578163772, 503 | 'Fuel/Energy': 0.018610421836228287, 504 | 'Transport': 0.017369727047146403, 505 | 'None': 0.0037220843672456576, 506 | 'Health': 0.0024813895781637717, 507 | 'Environment': 0.0012406947890818859}, 508 | '31': {'Savings Group': 0.8, 509 | 'Food/Water': 0.13333333333333333, 510 | 'Shop': 0.06666666666666667}, 511 | '32': {'Savings Group': 0.7444444444444445, 512 | 'Farming/Labour': 0.2, 513 | 'Food/Water': 0.05555555555555555}, 514 | '33': {'Food/Water': 0.33343474292668085, 515 | 'Farming/Labour': 0.28414968055978096, 516 | 'Savings Group': 0.18892607240644965, 517 | 'Shop': 0.1146942500760572, 518 | 'Fuel/Energy': 0.06936416184971098, 519 | 'None': 0.006693033160937024, 520 | 'Education': 0.0027380590203833284}, 521 | '34': {'Savings Group': 1.0}, 522 | '35': {'Food/Water': 0.3829787234042553, 523 | 'Farming/Labour': 0.2390488110137672, 524 | 'Shop': 0.1902377972465582, 525 | 'Savings Group': 0.07259073842302878, 526 | 'Transport': 0.060075093867334166, 527 | 'Health': 0.030037546933667083, 528 | 'Fuel/Energy': 0.016270337922403004, 529 | 'None': 0.0050062578222778474, 530 | 'Education': 0.0037546933667083854}, 531 | '36': {'Savings Group': 1.0}, 532 | '37': {'Farming/Labour': 0.5454545454545454, 533 | 'Food/Water': 0.36363636363636365, 534 | 'Savings Group': 0.045454545454545456, 535 | 'Shop': 0.045454545454545456}, 536 | '38': {'Savings Group': 1.0}, 537 | '39': {'Savings Group': 1.0}, 538 | '40': {'Farming/Labour': 0.3595236417447678, 539 | 'Food/Water': 0.3165386512578395, 540 | 'Shop': 0.18842928616728913, 541 | 'Fuel/Energy': 0.05108871820167712, 542 | 'None': 0.0360439715312522, 543 | 'Transport': 0.022443802409978154, 544 | 'Education': 0.01039391163413431, 545 | 'Savings Group': 0.00842083010358678, 546 | 'Health': 0.004545134240011275, 547 | 'Staff': 0.0011627087590726517, 548 | 'Environment': 0.0010570079627933197, 549 | 'System': 0.00035233598759777326}, 550 | '41': {'Food/Water': 0.33003300330033003, 551 | 'Farming/Labour': 0.2739273927392739, 552 | 'Shop': 0.1782178217821782, 553 | 'Savings Group': 0.13861386138613863, 554 | 'Health': 0.0429042904290429, 555 | 'Fuel/Energy': 0.0165016501650165, 556 | 'Transport': 0.0165016501650165, 557 | 'Education': 0.0033003300330033004}, 558 | '42': {'Savings Group': 0.8661740558292282, 'Health': 0.13382594417077176}, 559 | '43': {'Savings Group': 1.0}, 560 | '44': {'Food/Water': 0.4805194805194805, 561 | 'Shop': 0.14285714285714285, 562 | 'Savings Group': 0.14285714285714285, 563 | 'Farming/Labour': 0.13636363636363635, 564 | 'Health': 0.06493506493506493, 565 | 'Transport': 0.012987012987012988, 566 | 'Environment': 0.012987012987012988, 567 | 'Fuel/Energy': 0.006493506493506494}, 568 | '45': {'Food/Water': 0.35471100554235946, 569 | 'Farming/Labour': 0.2414885193982581, 570 | 'Shop': 0.23198733174980204, 571 | 'Education': 0.03800475059382423, 572 | 'None': 0.035629453681710214, 573 | 'Transport': 0.035629453681710214, 574 | 'Fuel/Energy': 0.028503562945368172, 575 | 'Savings Group': 0.02454473475851148, 576 | 'Health': 0.006334125098970704, 577 | 'Environment': 0.001583531274742676, 578 | 'Staff': 0.000791765637371338, 579 | 'System': 0.000791765637371338}, 580 | '46': {'Savings Group': 0.6981132075471698, 581 | 'Health': 0.18867924528301888, 582 | 'Food/Water': 0.09433962264150944, 583 | 'Shop': 0.018867924528301886}, 584 | '47': {'Savings Group': 0.5555555555555556, 585 | 'Farming/Labour': 0.2222222222222222, 586 | 'Food/Water': 0.2222222222222222}, 587 | '48': {'Food/Water': 0.38795180722891565, 588 | 'Savings Group': 0.38313253012048193, 589 | 'Health': 0.10120481927710843, 590 | 'Shop': 0.09879518072289156, 591 | 'Fuel/Energy': 0.016867469879518072, 592 | 'Farming/Labour': 0.012048192771084338}, 593 | '49': {'Food/Water': 0.3829787234042553, 594 | 'Savings Group': 0.3829787234042553, 595 | 'Education': 0.19148936170212766, 596 | 'Fuel/Energy': 0.0425531914893617}, 597 | 'external': {'Food/Water': 1, 598 | 'Fuel/Energy': 2, 599 | 'Health': 3, 600 | 'Education': 4, 601 | 'Savings Group': 5, 602 | 'Shop': 6}} 603 | 604 | # nested dictionary 605 | utilityTypesProbability = {'0': {'Food/Water': 0.4119323241317899, 606 | 'Farming/Labour': 0.26090828138913624, 607 | 'Shop': 0.17916295636687443, 608 | 'Savings Group': 0.07266251113089937, 609 | 'Fuel/Energy': 0.034194122885129116, 610 | 'Transport': 0.02617987533392698, 611 | 'Health': 0.006767586821015138, 612 | 'Education': 0.004096170970614425, 613 | 'None': 0.004096170970614425}, 614 | '1': {'Food/Water': 1.0}, 615 | '2': {'Savings Group': 0.87890625, 616 | 'Health': 0.08984375, 617 | 'Food/Water': 0.03125}, 618 | '3': {'Savings Group': 0.4905964535196131, 619 | 'Farming/Labour': 0.3610961848468565, 620 | 'Food/Water': 0.14830736163353037}, 621 | '4': {'Farming/Labour': 0.2843866171003718, 622 | 'Shop': 0.25650557620817843, 623 | 'Fuel/Energy': 0.17843866171003717, 624 | 'Food/Water': 0.16171003717472118, 625 | 'None': 0.10966542750929369, 626 | 'Savings Group': 0.0055762081784386614, 627 | 'Transport': 0.0037174721189591076}, 628 | '5': {'Farming/Labour': 0.421875, 629 | 'Food/Water': 0.421875, 630 | 'Shop': 0.0625, 631 | 'Savings Group': 0.03125, 632 | 'Fuel/Energy': 0.03125, 633 | 'Transport': 0.03125}, 634 | '6': {'Savings Group': 0.6008097165991902, 635 | 'Food/Water': 0.35870445344129553, 636 | 'Shop': 0.04048582995951417}, 637 | '7': {'Farming/Labour': 0.4346590909090909, 638 | 'Food/Water': 0.2869318181818182, 639 | 'Shop': 0.1278409090909091, 640 | 'Fuel/Energy': 0.07670454545454546, 641 | 'Savings Group': 0.03977272727272727, 642 | 'Education': 0.017045454545454544, 643 | 'None': 0.011363636363636364, 644 | 'Transport': 0.002840909090909091, 645 | 'Health': 0.002840909090909091}, 646 | '8': {'Savings Group': 1.0}, 647 | '9': {'Savings Group': 0.7142857142857143, 648 | 'Food/Water': 0.18181818181818182, 649 | 'Farming/Labour': 0.07792207792207792, 650 | 'Education': 0.025974025974025976}, 651 | '10': {'Food/Water': 0.3499875508340941, 652 | 'Farming/Labour': 0.3162088140094614, 653 | 'Shop': 0.21047389824881732, 654 | 'Transport': 0.03950535314133953, 655 | 'None': 0.03386173126400531, 656 | 'Fuel/Energy': 0.022491493069964313, 657 | 'Education': 0.01709685451074778, 658 | 'Savings Group': 0.006473566271059839, 659 | 'Environment': 0.002157855423686613, 660 | 'Health': 0.0016598887874512407, 661 | 'Chama': 8.299443937256204e-05}, 662 | '11': {'Savings Group': 0.4873417721518987, 663 | 'Food/Water': 0.3377445339470656, 664 | 'Education': 0.09723820483314154, 665 | 'Farming/Labour': 0.06271576524741082, 666 | 'Shop': 0.014959723820483314}, 667 | '12': {'Food/Water': 0.34994337485843713, 668 | 'Shop': 0.2332955832389581, 669 | 'Farming/Labour': 0.19592298980747452, 670 | 'Fuel/Energy': 0.057757644394110984, 671 | 'Savings Group': 0.053227633069082674, 672 | 'Education': 0.05096262740656852, 673 | 'None': 0.026047565118912798, 674 | 'Transport': 0.020385050962627407, 675 | 'Health': 0.011325028312570781, 676 | 'Environment': 0.0011325028312570782}, 677 | '13': {'Savings Group': 0.3712871287128713, 678 | 'Food/Water': 0.247974797479748, 679 | 'Shop': 0.19801980198019803, 680 | 'Fuel/Energy': 0.08235823582358236, 681 | 'Health': 0.07605760576057606, 682 | 'Farming/Labour': 0.024302430243024302}, 683 | '14': {'Savings Group': 1.0}, 684 | '15': {'Savings Group': 1.0}, 685 | '16': {'Savings Group': 0.5, 'Food/Water': 0.5}, 686 | '17': {'Savings Group': 0.7335701598579041, 687 | 'Shop': 0.17584369449378331, 688 | 'Food/Water': 0.0905861456483126}, 689 | '18': {'Savings Group': 0.6984126984126984, 690 | 'Food/Water': 0.23809523809523808, 691 | 'Farming/Labour': 0.06349206349206349}, 692 | '19': {'Savings Group': 1.0}, 693 | '20': {'Savings Group': 1.0}, 694 | '21': {'Farming/Labour': 0.47619047619047616, 695 | 'Food/Water': 0.3333333333333333, 696 | 'Shop': 0.09523809523809523, 697 | 'Fuel/Energy': 0.047619047619047616, 698 | 'Transport': 0.047619047619047616}, 699 | '22': {'Food/Water': 0.33040588654165676, 700 | 'Farming/Labour': 0.3209114645145977, 701 | 'Shop': 0.164016140517446, 702 | 'None': 0.06147638262520769, 703 | 'Fuel/Energy': 0.05008307619273677, 704 | 'Transport': 0.028957987182530263, 705 | 'Savings Group': 0.023973415618324233, 706 | 'Education': 0.014478993591265131, 707 | 'Health': 0.0035604082601471635, 708 | 'Environment': 0.0011868027533823878, 709 | 'Staff': 0.00047472110135295516, 710 | 'Chama': 0.00023736055067647758, 711 | 'Game': 0.00023736055067647758}, 712 | '23': {'Savings Group': 0.8323424494649228, 713 | 'Farming/Labour': 0.16765755053507728}, 714 | '24': {'Farming/Labour': 0.38481675392670156, 715 | 'Food/Water': 0.3717277486910995, 716 | 'Shop': 0.1387434554973822, 717 | 'Fuel/Energy': 0.05235602094240838, 718 | 'Transport': 0.02356020942408377, 719 | 'Savings Group': 0.01832460732984293, 720 | 'Education': 0.007853403141361256, 721 | 'Staff': 0.002617801047120419}, 722 | '25': {'Savings Group': 0.7916666666666666, 723 | 'Food/Water': 0.20833333333333334}, 724 | '26': {'Savings Group': 0.7442348008385744, 'Food/Water': 0.2557651991614256}, 725 | '27': {'Food/Water': 0.3333333333333333, 726 | 'Farming/Labour': 0.25, 727 | 'Health': 0.25, 728 | 'Savings Group': 0.08333333333333333, 729 | 'Fuel/Energy': 0.08333333333333333}, 730 | '28': {'Food/Water': 1.0}, 731 | '29': {'Food/Water': 0.27335640138408307, 732 | 'Farming/Labour': 0.23529411764705882, 733 | 'Shop': 0.21972318339100347, 734 | 'Fuel/Energy': 0.21280276816608998, 735 | 'None': 0.03806228373702422, 736 | 'Education': 0.006920415224913495, 737 | 'Transport': 0.006920415224913495, 738 | 'Savings Group': 0.005190311418685121, 739 | 'Staff': 0.0017301038062283738}, 740 | '30': {'Food/Water': 0.36228287841191065, 741 | 'Shop': 0.2679900744416873, 742 | 'Farming/Labour': 0.21712158808933002, 743 | 'Savings Group': 0.08436724565756824, 744 | 'Education': 0.02481389578163772, 745 | 'Fuel/Energy': 0.018610421836228287, 746 | 'Transport': 0.017369727047146403, 747 | 'None': 0.0037220843672456576, 748 | 'Health': 0.0024813895781637717, 749 | 'Environment': 0.0012406947890818859}, 750 | '31': {'Savings Group': 0.8, 751 | 'Food/Water': 0.13333333333333333, 752 | 'Shop': 0.06666666666666667}, 753 | '32': {'Savings Group': 0.7444444444444445, 754 | 'Farming/Labour': 0.2, 755 | 'Food/Water': 0.05555555555555555}, 756 | '33': {'Food/Water': 0.33343474292668085, 757 | 'Farming/Labour': 0.28414968055978096, 758 | 'Savings Group': 0.18892607240644965, 759 | 'Shop': 0.1146942500760572, 760 | 'Fuel/Energy': 0.06936416184971098, 761 | 'None': 0.006693033160937024, 762 | 'Education': 0.0027380590203833284}, 763 | '34': {'Savings Group': 1.0}, 764 | '35': {'Food/Water': 0.3829787234042553, 765 | 'Farming/Labour': 0.2390488110137672, 766 | 'Shop': 0.1902377972465582, 767 | 'Savings Group': 0.07259073842302878, 768 | 'Transport': 0.060075093867334166, 769 | 'Health': 0.030037546933667083, 770 | 'Fuel/Energy': 0.016270337922403004, 771 | 'None': 0.0050062578222778474, 772 | 'Education': 0.0037546933667083854}, 773 | '36': {'Savings Group': 1.0}, 774 | '37': {'Farming/Labour': 0.5454545454545454, 775 | 'Food/Water': 0.36363636363636365, 776 | 'Savings Group': 0.045454545454545456, 777 | 'Shop': 0.045454545454545456}, 778 | '38': {'Savings Group': 1.0}, 779 | '39': {'Savings Group': 1.0}, 780 | '40': {'Farming/Labour': 0.3595236417447678, 781 | 'Food/Water': 0.3165386512578395, 782 | 'Shop': 0.18842928616728913, 783 | 'Fuel/Energy': 0.05108871820167712, 784 | 'None': 0.0360439715312522, 785 | 'Transport': 0.022443802409978154, 786 | 'Education': 0.01039391163413431, 787 | 'Savings Group': 0.00842083010358678, 788 | 'Health': 0.004545134240011275, 789 | 'Staff': 0.0011627087590726517, 790 | 'Environment': 0.0010570079627933197, 791 | 'System': 0.00035233598759777326}, 792 | '41': {'Food/Water': 0.33003300330033003, 793 | 'Farming/Labour': 0.2739273927392739, 794 | 'Shop': 0.1782178217821782, 795 | 'Savings Group': 0.13861386138613863, 796 | 'Health': 0.0429042904290429, 797 | 'Fuel/Energy': 0.0165016501650165, 798 | 'Transport': 0.0165016501650165, 799 | 'Education': 0.0033003300330033004}, 800 | '42': {'Savings Group': 0.8661740558292282, 'Health': 0.13382594417077176}, 801 | '43': {'Savings Group': 1.0}, 802 | '44': {'Food/Water': 0.4805194805194805, 803 | 'Shop': 0.14285714285714285, 804 | 'Savings Group': 0.14285714285714285, 805 | 'Farming/Labour': 0.13636363636363635, 806 | 'Health': 0.06493506493506493, 807 | 'Transport': 0.012987012987012988, 808 | 'Environment': 0.012987012987012988, 809 | 'Fuel/Energy': 0.006493506493506494}, 810 | '45': {'Food/Water': 0.35471100554235946, 811 | 'Farming/Labour': 0.2414885193982581, 812 | 'Shop': 0.23198733174980204, 813 | 'Education': 0.03800475059382423, 814 | 'None': 0.035629453681710214, 815 | 'Transport': 0.035629453681710214, 816 | 'Fuel/Energy': 0.028503562945368172, 817 | 'Savings Group': 0.02454473475851148, 818 | 'Health': 0.006334125098970704, 819 | 'Environment': 0.001583531274742676, 820 | 'Staff': 0.000791765637371338, 821 | 'System': 0.000791765637371338}, 822 | '46': {'Savings Group': 0.6981132075471698, 823 | 'Health': 0.18867924528301888, 824 | 'Food/Water': 0.09433962264150944, 825 | 'Shop': 0.018867924528301886}, 826 | '47': {'Savings Group': 0.5555555555555556, 827 | 'Farming/Labour': 0.2222222222222222, 828 | 'Food/Water': 0.2222222222222222}, 829 | '48': {'Food/Water': 0.38795180722891565, 830 | 'Savings Group': 0.38313253012048193, 831 | 'Health': 0.10120481927710843, 832 | 'Shop': 0.09879518072289156, 833 | 'Fuel/Energy': 0.016867469879518072, 834 | 'Farming/Labour': 0.012048192771084338}, 835 | '49': {'Food/Water': 0.3829787234042553, 836 | 'Savings Group': 0.3829787234042553, 837 | 'Education': 0.19148936170212766, 838 | 'Fuel/Energy': 0.0425531914893617}, 839 | 'external': {'Food/Water': 0.6, 840 | 'Fuel/Energy': 0.1, 841 | 'Health': 0.03, 842 | 'Education': 0.015, 843 | 'Savings Group': 0.065, 844 | 'Shop': 0.19}} 845 | 846 | # agent:[centrality,allocationValue] 847 | agentAllocation = {'0': [1, 1], 848 | '1': [1, 1], 849 | '2': [1, 1], 850 | '3': [1, 1], 851 | '4': [1, 1], 852 | '5': [1, 1], 853 | '6': [1, 1], 854 | '7': [1, 1], 855 | '8': [1, 1], 856 | '9': [1, 1], 857 | '10': [1, 1], 858 | '11': [1, 1], 859 | '12': [1, 1], 860 | '13': [1, 1], 861 | '14': [1, 1], 862 | '15': [1, 1], 863 | '16': [1, 1], 864 | '17': [1, 1], 865 | '18': [1, 1], 866 | '19': [1, 1], 867 | '20': [1, 1], 868 | '21': [1, 1], 869 | '22': [1, 1], 870 | '23': [1, 1], 871 | '24': [1, 1], 872 | '25': [1, 1], 873 | '26': [1, 1], 874 | '27': [1, 1], 875 | '28': [1, 1], 876 | '29': [1, 1], 877 | '30': [1, 1], 878 | '31': [1, 1], 879 | '32': [1, 1], 880 | '33': [1, 1], 881 | '34': [1, 1], 882 | '35': [1, 1], 883 | '36': [1, 1], 884 | '37': [1, 1], 885 | '38': [1, 1], 886 | '39': [1, 1], 887 | '40': [1, 1], 888 | '41': [1, 1], 889 | '42': [1, 1], 890 | '43': [1, 1], 891 | '44': [1, 1], 892 | '45': [1, 1], 893 | '46': [1, 1], 894 | '47': [1, 1], 895 | '48': [1, 1], 896 | '49': [1, 1]} 897 | -------------------------------------------------------------------------------- /Simulation_param/model/parts/supportingFunctions.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | from scipy.stats import gamma 3 | import matplotlib.pyplot as plt 4 | 5 | default_kappa= 4 6 | default_exit_tax = .02 7 | 8 | #value function for a given state (R,S) 9 | def invariant(R,S,kappa=default_kappa): 10 | 11 | return (S**kappa)/R 12 | 13 | #given a value function (parameterized by kappa) 14 | #and an invariant coeficient V0 15 | #return Supply S as a function of reserve R 16 | def reserve(S, V0, kappa=default_kappa): 17 | return (S**kappa)/V0 18 | 19 | #given a value function (parameterized by kappa) 20 | #and an invariant coeficient V0 21 | #return Supply S as a function of reserve R 22 | def supply(R, V0, kappa=default_kappa): 23 | return (V0*R)**(1/kappa) 24 | 25 | #given a value function (parameterized by kappa) 26 | #and an invariant coeficient V0 27 | #return a spot price P as a function of reserve R 28 | def spot_price(R, V0, kappa=default_kappa): 29 | return kappa*R**((kappa-1)/kappa)/V0**(1/kappa) 30 | 31 | #for a given state (R,S) 32 | #given a value function (parameterized by kappa) 33 | #and an invariant coeficient V0 34 | #deposit deltaR to Mint deltaS 35 | #with realized price deltaR/deltaS 36 | def mint(deltaR, R,S, V0, kappa=default_kappa): 37 | deltaS = (V0*(R+deltaR))**(1/kappa)-S 38 | if deltaS ==0: 39 | realized_price = spot_price(R+deltaR, V0, kappa) 40 | else: 41 | realized_price = deltaR/deltaS 42 | deltaS = round(deltaS,2) 43 | return deltaS, realized_price 44 | 45 | #for a given state (R,S) 46 | #given a value function (parameterized by kappa) 47 | #and an invariant coeficient V0 48 | #burn deltaS to Withdraw deltaR 49 | #with realized price deltaR/deltaS 50 | def withdraw(deltaS, R,S, V0, kappa=default_kappa): 51 | deltaR = R-((S-deltaS)**kappa)/V0 52 | if deltaS ==0: 53 | realized_price = spot_price(R+deltaR, V0, kappa) 54 | else: 55 | realized_price = deltaR/deltaS 56 | deltaR = round(deltaR,2) 57 | return deltaR, realized_price 58 | 59 | 60 | 61 | def iterateEdges(network,edgeToIterate): 62 | ''' 63 | Description: 64 | Iterate through a network on a weighted edge and return 65 | two dictionaries: the inflow and outflow for the given agents 66 | in the format: 67 | 68 | {'Agent':amount} 69 | ''' 70 | outflows = {} 71 | inflows = {} 72 | for i,j in network.edges: 73 | try: 74 | amount = network[i][j][edgeToIterate] 75 | if i in outflows: 76 | outflows[i] = outflows[i] + amount 77 | else: 78 | outflows[i] = amount 79 | if j in inflows: 80 | inflows[j] = inflows[j] + amount 81 | else: 82 | inflows[j] = amount 83 | except: 84 | pass 85 | return outflows,inflows 86 | 87 | 88 | def inflowAndOutflowDictionaryMerge(inflow,outflow): 89 | ''' 90 | Description: 91 | Merge two dictionaries and return one dictionary with zero floor''' 92 | 93 | merged = {} 94 | 95 | inflowsKeys = [k for k,v in inflow.items() if k not in outflow] 96 | for i in inflowsKeys: 97 | merged[i] = inflow[i] 98 | outflowsKeys = [k for k,v in outflow.items() if k not in inflow] 99 | for i in outflowsKeys: 100 | merged[i] = outflow[i] 101 | overlapKeys = [k for k,v in inflow.items() if k in outflow] 102 | for i in overlapKeys: 103 | amt = outflow[i] - inflow[i] 104 | if amt < 0: 105 | merged[i] = 0 106 | else: 107 | merged[i] = amt 108 | pass 109 | 110 | return merged 111 | 112 | 113 | def spendCalculation(agentToPay,agentToReceive,rankOrderDemand,maxSpendCurrency,maxSpendTokens,cicPercentage): 114 | ''' 115 | Function to calculate if an agent can pay for demand given token and currency contraints 116 | ''' 117 | if (rankOrderDemand[agentToReceive] * (1-cicPercentage)) > maxSpendCurrency[agentToPay]: 118 | verdict_currency = 'No' 119 | else: 120 | verdict_currency = 'Enough' 121 | 122 | if (rankOrderDemand[agentToReceive] * cicPercentage) > maxSpendTokens[agentToPay]: 123 | verdict_cic = 'No' 124 | else: 125 | verdict_cic = 'Enough' 126 | 127 | if verdict_currency == 'Enough'and verdict_cic == 'Enough': 128 | spend = rankOrderDemand[agentToReceive] 129 | 130 | elif maxSpendCurrency[agentToPay] > 0 and maxSpendTokens[agentToPay] > 0: 131 | if maxSpendTokens[agentToPay] > maxSpendCurrency[agentToPay]: 132 | spend = maxSpendCurrency[agentToPay] 133 | elif maxSpendCurrency[agentToPay] > maxSpendTokens[agentToPay]: 134 | spend = maxSpendTokens[agentToPay] 135 | else: 136 | spend = 0 137 | 138 | return spend 139 | 140 | 141 | def spendCalculationExternal(agentToPay,agentToReceive,rankOrderDemand,maxSpendCurrency): 142 | ''' 143 | ''' 144 | if rankOrderDemand[agentToReceive] > maxSpendCurrency[agentToPay]: 145 | verdict_currency = 'No' 146 | else: 147 | verdict_currency = 'Enough' 148 | 149 | if verdict_currency == 'Enough': 150 | spend = rankOrderDemand[agentToReceive] 151 | 152 | elif maxSpendCurrency[agentToPay] > 0: 153 | spend = maxSpendCurrency[agentToPay] 154 | else: 155 | spend = 0 156 | 157 | return spend 158 | 159 | 160 | def DictionaryMergeAddition(inflow,outflow): 161 | ''' 162 | Description: 163 | Merge two dictionaries and return one dictionary''' 164 | 165 | merged = {} 166 | 167 | inflowsKeys = [k for k,v in inflow.items() if k not in outflow] 168 | for i in inflowsKeys: 169 | merged[i] = inflow[i] 170 | outflowsKeys = [k for k,v in outflow.items() if k not in inflow] 171 | for i in outflowsKeys: 172 | merged[i] = outflow[i] 173 | overlapKeys = [k for k,v in inflow.items() if k in outflow] 174 | for i in overlapKeys: 175 | merged[i] = outflow[i] + inflow[i] 176 | 177 | return merged 178 | 179 | def mint_burn_logic_control(idealCIC,actualCIC,varianceCIC,actualFiat,varianceFiat,idealFiat): 180 | ''' 181 | Inventory control function to test if the current balance is in an acceptable range. Tolerance range 182 | 183 | Test: mint_burn_logic_control(100000,subset['operatorCICBalance'][499],30000,subset['operatorFiatBalance'][499],30000,100000) 184 | ''' 185 | if idealFiat - varianceFiat <= actualFiat <= idealFiat + (2*varianceFiat): 186 | decision = 'none' 187 | amount = 0 188 | else: 189 | if (idealFiat - varianceFiat) > actualFiat: 190 | decision = 'burn' 191 | amount = (idealFiat + varianceFiat) - actualFiat 192 | else: 193 | pass 194 | if actualFiat > (idealFiat + varianceFiat): 195 | decision = 'mint' 196 | amount = actualFiat - (idealFiat + varianceFiat) 197 | else: 198 | pass 199 | 200 | if decision == 'mint': 201 | if actualCIC < (idealCIC - varianceCIC): 202 | if amount > actualCIC: 203 | decision = 'none' 204 | amount = 0 205 | else: 206 | pass 207 | if decision == 'none': 208 | if actualCIC < (idealCIC - varianceCIC): 209 | decision = 'mint' 210 | amount = (idealCIC-varianceCIC) 211 | else: 212 | pass 213 | 214 | amount = round(amount,2) 215 | return decision, amount 216 | 217 | #NetworkX functions 218 | def get_nodes_by_type(g, node_type_selection): 219 | return [node for node in g.nodes if g.nodes[node]['type']== node_type_selection] 220 | 221 | def get_edges_by_type(g, edge_type_selection): 222 | return [edge for edge in g.edges if g.edges[edge]['type']== edge_type_selection] 223 | 224 | def get_edges(g): 225 | return [edge for edge in g.edges if g.edges[edge]] 226 | 227 | def get_nodes(g): 228 | ''' 229 | df.network.apply(lambda g: np.array([g.nodes[j]['balls'] for j in get_nodes(g)])) 230 | ''' 231 | return [node for node in g.nodes if g.nodes[node]] 232 | 233 | def aggregate_runs(df,aggregate_dimension): 234 | ''' 235 | Function to aggregate the monte carlo runs along a single dimension. 236 | Parameters: 237 | df: dataframe name 238 | aggregate_dimension: the dimension you would like to aggregate on, the standard one is timestep. 239 | Example run: 240 | mean_df,median_df,std_df,min_df = aggregate_runs(df,'timestep') 241 | ''' 242 | df = df[df['substep'] == df.substep.max()] 243 | mean_df = df.groupby(aggregate_dimension).mean().reset_index() 244 | median_df = df.groupby(aggregate_dimension).median().reset_index() 245 | std_df = df.groupby(aggregate_dimension).std().reset_index() 246 | min_df = df.groupby(aggregate_dimension).min().reset_index() 247 | 248 | return mean_df,median_df,std_df,min_df 249 | 250 | 251 | def plot_median_with_quantiles(df,aggregate_dimension,x, y): 252 | ''' 253 | Function to plot the median and 1st and 3rd quartiles of the monte carlo runs along a single variable. 254 | Parameters: 255 | df: dataframe name 256 | aggregate_dimension: the dimension you would like to aggregate on, the standard one is timestep. 257 | x = x axis variable for plotting 258 | y = y axis variable for plotting 259 | 260 | Example run: 261 | plot_median_with_quantiles(df,'timestep','timestep','AggregatedAgentSpend') 262 | ''' 263 | 264 | df = df[df['substep'] == df.substep.max()] 265 | firstQuantile = df.groupby(aggregate_dimension).quantile(0.25).reset_index() 266 | thirdQuantile = df.groupby(aggregate_dimension).quantile(0.75).reset_index() 267 | median_df = df.groupby(aggregate_dimension).median().reset_index() 268 | 269 | fig, ax = plt.subplots(1,figsize=(10,6)) 270 | ax.plot(median_df[x].values, median_df[y].values, lw=2, label='Median', color='blue') 271 | ax.fill_between(firstQuantile[x].values, firstQuantile[y].values, thirdQuantile[y].values, facecolor='black', alpha=0.2) 272 | ax.set_title(y + ' Median') 273 | ax.legend(loc='upper left') 274 | ax.set_xlabel('Timestep') 275 | ax.set_ylabel('Amount') 276 | ax.grid() 277 | 278 | def plot_median_with_quantiles_annotation(df,aggregate_dimension,x, y): 279 | ''' 280 | Function to plot the median and 1st and 3rd quartiles of the monte carlo runs along a single variable. 281 | Parameters: 282 | df: dataframe name 283 | aggregate_dimension: the dimension you would like to aggregate on, the standard one is timestep. 284 | x = x axis variable for plotting 285 | y = y axis variable for plotting 286 | 287 | Example run: 288 | plot_median_with_quantiles(df,'timestep','timestep','AggregatedAgentSpend') 289 | ''' 290 | 291 | df = df[df['substep'] == df.substep.max()] 292 | firstQuantile = df.groupby(aggregate_dimension).quantile(0.25).reset_index() 293 | thirdQuantile = df.groupby(aggregate_dimension).quantile(0.75).reset_index() 294 | median_df = df.groupby(aggregate_dimension).median().reset_index() 295 | 296 | fig, ax = plt.subplots(1,figsize=(10,6)) 297 | ax.axvline(x=30,linewidth=2, color='r') 298 | ax.annotate('Agents can withdraw and Red Cross Drip occurs', xy=(30,2), xytext=(35, 1), 299 | arrowprops=dict(facecolor='black', shrink=0.05)) 300 | 301 | ax.axvline(x=60,linewidth=2, color='r') 302 | ax.axvline(x=90,linewidth=2, color='r') 303 | ax.plot(median_df[x].values, median_df[y].values, lw=2, label='Median', color='blue') 304 | ax.fill_between(firstQuantile[x].values, firstQuantile[y].values, thirdQuantile[y].values, facecolor='black', alpha=0.2) 305 | ax.set_title(y + ' Median') 306 | ax.legend(loc='upper left') 307 | ax.set_xlabel('Timestep') 308 | ax.set_ylabel('Amount') 309 | ax.grid() 310 | 311 | 312 | def first_five_plot(df,aggregate_dimension,x,y,run_count): 313 | ''' 314 | A function that generates timeseries plot of at most the first five Monte Carlo runs. 315 | Parameters: 316 | df: dataframe name 317 | aggregate_dimension: the dimension you would like to aggregate on, the standard one is timestep. 318 | x = x axis variable for plotting 319 | y = y axis variable for plotting 320 | run_count = the number of monte carlo simulations 321 | Note: Run aggregate_runs before using this function 322 | Example run: 323 | first_five_plot(df,'timestep','timestep','revenue',run_count=100) 324 | ''' 325 | mean_df,median_df,std_df,min_df = aggregate_runs(df,aggregate_dimension) 326 | plt.figure(figsize=(10,6)) 327 | if run_count < 5: 328 | runs = run_count 329 | else: 330 | runs = 5 331 | for r in range(1,runs+1): 332 | legend_name = 'Run ' + str(r) 333 | plt.plot(df[df.run==r].timestep, df[df.run==r][y], label = legend_name ) 334 | plt.plot(mean_df[x], mean_df[y], label = 'Mean', color = 'black') 335 | plt.legend(bbox_to_anchor=(1.05, 1), loc=2, borderaxespad=0.) 336 | plt.xlabel(x) 337 | plt.ylabel(y) 338 | title_text = 'Performance of ' + y + ' over the First ' + str(runs) + ' Monte Carlo Runs' 339 | plt.title(title_text) 340 | 341 | 342 | def plot_fan_chart(df,aggregate_dimension,x, y,lx=False,ly=False,density_hack=True): 343 | def q10(x): 344 | return x.quantile(0.1) 345 | 346 | def q20(x): 347 | return x.quantile(0.2) 348 | 349 | def q30(x): 350 | return x.quantile(0.3) 351 | 352 | def q40(x): 353 | return x.quantile(0.4) 354 | 355 | def q60(x): 356 | return x.quantile(0.6) 357 | 358 | def q70(x): 359 | return x.quantile(0.7) 360 | 361 | def q80(x): 362 | return x.quantile(0.8) 363 | 364 | def q90(x): 365 | return x.quantile(0.9) 366 | 367 | run_count = max(df.run) 368 | 369 | agg_metrics = [q10, q20, q30, q40, 'median', q60, q70, q80, q90] 370 | agg_df = df.groupby(aggregate_dimension).agg({y: agg_metrics}) 371 | agg_metrics = agg_df.columns.levels[1].values 372 | agg_df.columns = ['_'.join(col).strip() for col in agg_df.columns.values] 373 | plt.figure(figsize=(10,6)) 374 | 375 | df = agg_df.reset_index() 376 | lines = plt.plot(df[x], df[f'{y}_median']) 377 | color = lines[0].get_color() 378 | if density_hack: 379 | avg_iqr = [] 380 | for i in range(len(agg_metrics)-1): 381 | m = (agg_metrics[i], agg_metrics[i+1]) 382 | iqr = df[f'{y}_{m[1]}'] - df[f'{y}_{m[0]}'] 383 | avg_iqr.append(iqr.sum()) 384 | inv_avg_iqr = [1/i for i in avg_iqr] 385 | norm_avg_iqr = [i/max(inv_avg_iqr) for i in inv_avg_iqr] 386 | i = 0 387 | while i 1 and M. 420 | 421 | Returns: 422 | Lists of parameter subset dataframes for mean, median, and std. The number of dataframes 423 | in each list is equal to the simulation N. 424 | 425 | Example run: 426 | means,medians,stds = param_sweep_aggregation(result,'timestep') 427 | ''' 428 | 429 | df = df[df['substep'] == df.substep.max()] 430 | subsets = [] 431 | for i in df.subset.unique(): 432 | subsets.append(df[df['subset']==i]) 433 | 434 | means = [] 435 | for i in range(0,len(subsets)): 436 | means.append(subsets[i].groupby(aggregation_dimension).mean().reset_index()) 437 | 438 | medians = [] 439 | for i in range(0,len(subsets)): 440 | medians.append(subsets[i].groupby(aggregation_dimension).median().reset_index()) 441 | 442 | stds = [] 443 | for i in range(0,len(subsets)): 444 | stds.append(subsets[i].groupby(aggregation_dimension).std().reset_index()) 445 | 446 | return means,medians,stds 447 | 448 | 449 | def param_plot(dfs,x,y,params,swept,saveFig=False,dims=(10,6)): 450 | ''' 451 | Description: 452 | Function to plot parameter sweep monte carlo results to illustrate the effect the swept 453 | parameter has on the simulation. 454 | 455 | Parameters: 456 | dfs: list of a pandas dataframes calculated in param_sweep_aggregation() 457 | x: string of the desired x in the simulation; e.x. 'timestep' 458 | y: string of the desired x in the simulation; e.x. 'Velocity' 459 | params: list of parameter sweep values to analyze, e.x. [30,60,90] 460 | swept: string of the parameter swept, e.e. 'money drip' 461 | saveFig: optional boolean if the plot should be saved or not 462 | dims: optional figure size values 463 | 464 | Assumptions: 465 | A cadCAD simulation was completed with an config N > 1 and M and param_sweep_aggregation() was run 466 | 467 | Returns: 468 | Plot 469 | 470 | Example run: 471 | param_plot(medians,'timestep','AggregatedAgentSpend',params,swept) 472 | 473 | ''' 474 | plt.figure(figsize=dims) 475 | for i in range(0,len(dfs)): 476 | dfs[i][y].plot() 477 | 478 | plt.legend(params) 479 | plt.xlabel(x) 480 | plt.ylabel(y) 481 | title_text = 'Effect of ' + swept + ' Parameter Sweep on ' + y 482 | plt.title(title_text) 483 | if saveFig: 484 | plt.savefig(title_text + '_.png') -------------------------------------------------------------------------------- /Simulation_param/model/parts/system.py: -------------------------------------------------------------------------------- 1 | 2 | import numpy as np 3 | import pandas as pd 4 | from cadCAD.configuration.utils import access_block 5 | from .initialization import * 6 | from .supportingFunctions import * 7 | from collections import OrderedDict 8 | from .subpopulation_clusters import * 9 | 10 | 11 | # Parameters 12 | agentsMinus = 5 13 | # percentage of balance a user can redeem 14 | redeemPercentage = 0.5 15 | # maximum withdraw amount per 30 days 16 | maxAmountofWithdraw = 30000 17 | 18 | # Behaviors 19 | def choose_agents(params, step, sL, s): 20 | ''' 21 | Choose agents to interact during the given timestep and create their demand from a uniform distribution. 22 | Based on probability, choose utility. 23 | ''' 24 | outboundAgents = np.random.choice(mixingAgents,size=len(mixingAgents)-agentsMinus).tolist() 25 | inboundAgents = np.random.choice(mixingAgents,size=len(mixingAgents)-agentsMinus).tolist() 26 | 27 | demands = [] 28 | for i in outboundAgents: 29 | if i == 'external': 30 | demands.append(np.random.normal(sum(clustersMu)/len(clustersMu), sum(clustersSigma)/len(clustersMu), 1)[0]) 31 | else: 32 | demands.append(np.random.normal(clustersMu[int(i)], clustersSigma[int(i)], 1)[0]) 33 | 34 | stepDemands = [] 35 | for i in demands: 36 | if i > 0: 37 | stepDemands.append(round(i,2)) 38 | else: 39 | stepDemands.append(1) 40 | 41 | 42 | 43 | stepUtilities = [] 44 | 45 | for i in outboundAgents: 46 | stepUtilities.append(np.random.choice(list(UtilityTypesOrdered[str(i)].keys()),size=1,p=list(utilityTypesProbability[str(i)].values()))[0]) 47 | 48 | 49 | return {'outboundAgents':outboundAgents,'inboundAgents':inboundAgents,'stepDemands':stepDemands,'stepUtilities':stepUtilities} 50 | 51 | 52 | def spend_allocation(params, step, sL, s): 53 | ''' 54 | Take mixing agents, demand, and utilities and allocate agent shillings and tokens based on utility and scarcity. 55 | ''' 56 | # instantiate network state 57 | network = s['network'] 58 | 59 | spendI = [] 60 | spendJ = [] 61 | spendAmount = [] 62 | 63 | # calculate max about of spend available to each agent 64 | maxSpendShilling = {} 65 | for i in mixingAgents: 66 | maxSpendShilling[i] = network.nodes[i]['native_currency'] 67 | 68 | maxSpendCIC = {} 69 | for i in mixingAgents: 70 | maxSpendCIC[i] = network.nodes[i]['tokens'] 71 | 72 | 73 | for i in mixingAgents: 74 | rankOrder = {} 75 | rankOrderDemand = {} 76 | for j in network.adj[i]: 77 | try: 78 | #print(network.adj[i][j]['utility']) 79 | #print(network.adj[i][j]) 80 | utility = network.adj[i][j]['utility'] 81 | rankOrder[j] = UtilityTypesOrdered[i][utility] 82 | rankOrderDemand[j] = network.adj[i][j]['demand'] 83 | rankOrder = dict(OrderedDict(sorted(rankOrder.items(), key=lambda v: v, reverse=False))) 84 | for k in rankOrder: 85 | # if i or j is external, we transact 100% in shilling 86 | if i == 'external': 87 | amt = spendCalculationExternal(i,j,rankOrderDemand,maxSpendShilling) 88 | spendI.append(i) 89 | spendJ.append(j) 90 | spendAmount.append(amt) 91 | maxSpendShilling[i] = maxSpendShilling[i] - amt 92 | elif j == 'external': 93 | amt = spendCalculationExternal(i,j,rankOrderDemand,maxSpendShilling) 94 | spendI.append(i) 95 | spendJ.append(j) 96 | spendAmount.append(amt) 97 | maxSpendShilling[i] = maxSpendShilling[i] - amt 98 | else: 99 | amt = spendCalculation(i,j,rankOrderDemand,maxSpendShilling,maxSpendCIC,fractionOfDemandInCIC) 100 | spendI.append(i) 101 | spendJ.append(j) 102 | spendAmount.append(amt) 103 | maxSpendShilling[i] = maxSpendShilling[i] - amt * (1- fractionOfDemandInCIC) 104 | maxSpendCIC[i] = maxSpendCIC[i] - (amt * fractionOfDemandInCIC) 105 | except: 106 | pass 107 | return {'spendI':spendI,'spendJ':spendJ,'spendAmount':spendAmount} 108 | 109 | 110 | def withdraw_calculation(params, step, sL, s): 111 | '''''' 112 | # instantiate network state 113 | network = s['network'] 114 | 115 | # Assumptions: 116 | # * user is only able to withdraw up to 50% of balance, assuming they have spent 50% of balance 117 | # * Agents will withdraw as much as they can. 118 | withdraw = {} 119 | 120 | fiftyThreshold = {} 121 | 122 | startingBalance = s['startingBalance'] 123 | 124 | spend = s['30_day_spend'] 125 | timestep = s['timestep'] 126 | 127 | maxWithdraw = maxAmountofWithdraw 128 | 129 | division = timestep % 30 == 0 130 | 131 | if division == True: 132 | for i,j in startingBalance.items(): 133 | fiftyThreshold[i] = j * 0.5 134 | if s['timestep'] > 7: 135 | for i,j in fiftyThreshold.items(): 136 | if spend[i] > 0 and fiftyThreshold[i] > 0: 137 | if spend[i] * fractionOfActualSpendInCIC >= fiftyThreshold[i]: 138 | spent = spend[i] 139 | amount = spent * redeemPercentage 140 | if network.nodes[i]['tokens'] > amount: 141 | if maxWithdraw - amount > 0: 142 | withdraw[i] = amount 143 | maxWithdraw = maxWithdraw - amount 144 | else: 145 | if maxWithdraw > 1: 146 | withdraw[i] = maxWithdraw 147 | maxWithdraw = 0 148 | else: 149 | pass 150 | elif network.nodes[i]['tokens'] < amount: 151 | if maxWithdraw - network.nodes[i]['tokens'] > 0: 152 | withdraw[i] = network.nodes[i]['tokens'] 153 | maxWithdraw = maxWithdraw - network.nodes[i]['tokens'] 154 | else: 155 | if maxWithdraw > 1: 156 | withdraw[i] = maxWithdraw 157 | maxWithdraw = 0 158 | else: 159 | pass 160 | else: 161 | pass 162 | else: 163 | pass 164 | else: 165 | pass 166 | else: 167 | pass 168 | 169 | return {'withdraw':withdraw} 170 | 171 | # Mechanisms 172 | def update_agent_activity(params,step,sL,s,_input): 173 | ''' 174 | Update the network for interacting agent, their demand, and utility. 175 | ''' 176 | y = 'network' 177 | network = s['network'] 178 | 179 | outboundAgents = _input['outboundAgents'] 180 | inboundAgents = _input['inboundAgents'] 181 | stepDemands = _input['stepDemands'] 182 | stepUtilities = _input['stepUtilities'] 183 | 184 | # create demand edge weights 185 | try: 186 | for i,j,l in zip(outboundAgents,inboundAgents,stepDemands): 187 | network[i][j]['demand'] = l 188 | except: 189 | pass 190 | 191 | # Create cic % edge weights 192 | try: 193 | for i,j in zip(outboundAgents,inboundAgents): 194 | # if one of the agents is external, we will transact in 100% shilling 195 | if i == 'external': 196 | network[i][j]['fractionOfDemandInCIC'] = 1 197 | elif j == 'external': 198 | network[i][j]['fractionOfDemandInCIC'] = 1 199 | else: 200 | network[i][j]['fractionOfDemandInCIC'] = fractionOfDemandInCIC 201 | except: 202 | pass 203 | 204 | # Create utility edge types 205 | try: 206 | for i,j,l in zip(outboundAgents,inboundAgents,stepUtilities): 207 | network[i][j]['utility'] = l 208 | except: 209 | pass 210 | 211 | x = network 212 | return (y,x) 213 | 214 | 215 | def update_outboundAgents(params,step,sL,s,_input): 216 | ''' 217 | Update outBoundAgents state variable 218 | ''' 219 | y = 'outboundAgents' 220 | 221 | x = _input['outboundAgents'] 222 | 223 | return (y,x) 224 | 225 | def update_inboundAgents(params,step,sL,s,_input): 226 | ''' 227 | Update inBoundAgents state variable 228 | ''' 229 | y = 'inboundAgents' 230 | 231 | x = _input['inboundAgents'] 232 | return (y,x) 233 | 234 | 235 | def update_node_spend(params, step, sL, s,_input): 236 | ''' 237 | Update network with actual spend of agents. 238 | ''' 239 | y = 'network' 240 | network = s['network'] 241 | 242 | spendI = _input['spendI'] 243 | spendJ = _input['spendJ'] 244 | spendAmount = _input['spendAmount'] 245 | 246 | for i,j,l in zip(spendI,spendJ,spendAmount): 247 | network[i][j]['spend'] = l 248 | if i == 'external': 249 | network[i][j]['fractionOfActualSpendInCIC'] = 1 250 | elif j == 'external': 251 | network[i][j]['fractionOfActualSpendInCIC'] = 1 252 | else: 253 | network[i][j]['fractionOfActualSpendInCIC'] = fractionOfActualSpendInCIC 254 | 255 | outflowSpend, inflowSpend = iterateEdges(network,'spend') 256 | 257 | for i, j in inflowSpend.items(): 258 | if i == 'external': 259 | network.nodes[i]['native_currency'] = network.nodes[i]['native_currency'] + inflowSpend[i] 260 | elif j == 'external': 261 | network.nodes[i]['native_currency'] = network.nodes[i]['native_currency'] + inflowSpend[i] 262 | else: 263 | network.nodes[i]['native_currency'] = network.nodes[i]['native_currency'] + inflowSpend[i] * (1- fractionOfDemandInCIC) 264 | network.nodes[i]['tokens'] = network.nodes[i]['tokens'] + (inflowSpend[i] * fractionOfDemandInCIC) 265 | 266 | for i, j in outflowSpend.items(): 267 | if i == 'external': 268 | network.nodes[i]['native_currency'] = network.nodes[i]['native_currency'] - outflowSpend[i] 269 | elif j == 'external': 270 | network.nodes[i]['native_currency'] = network.nodes[i]['native_currency'] - outflowSpend[i] 271 | else: 272 | network.nodes[i]['native_currency'] = network.nodes[i]['native_currency'] - outflowSpend[i]* (1- fractionOfDemandInCIC) 273 | network.nodes[i]['tokens'] = network.nodes[i]['tokens'] - (outflowSpend[i] * fractionOfDemandInCIC) 274 | 275 | # Store the net of the inflow and outflow per step 276 | network.nodes['external']['delta_native_currency'] = sum(inflowSpend.values()) - sum(outflowSpend.values()) 277 | 278 | x = network 279 | return (y,x) 280 | 281 | 282 | def update_withdraw(params, step, sL, s,_input): 283 | ''' 284 | Update flow state variable with the aggregated amount of shillings withdrawn 285 | ''' 286 | y = 'withdraw' 287 | x = s['withdraw'] 288 | if _input['withdraw']: 289 | x = _input['withdraw'] 290 | else: 291 | x = 0 292 | 293 | return (y,x) 294 | 295 | def update_network_withraw(params, step, sL, s,_input): 296 | ''' 297 | Update network for agents withdrawing 298 | ''' 299 | y = 'network' 300 | network = s['network'] 301 | withdraw = _input['withdraw'] 302 | 303 | if withdraw: 304 | for i,j in withdraw.items(): 305 | # update agent nodes 306 | network.nodes[i]['tokens'] = network.nodes[i]['tokens'] - j 307 | network.nodes[i]['native_currency'] = network.nodes[i]['native_currency'] + (j * leverage) 308 | 309 | withdrawnCICSum = [] 310 | for i,j in withdraw.items(): 311 | withdrawnCICSum.append(j) 312 | 313 | # update cic node 314 | network.nodes['cic']['native_currency'] = network.nodes[i]['native_currency'] - (sum(withdrawnCICSum) * leverage) 315 | network.nodes['cic']['tokens'] = network.nodes[i]['tokens'] + (sum(withdrawnCICSum) * leverage) 316 | 317 | else: 318 | pass 319 | x = network 320 | return (y,x) 321 | 322 | 323 | def update_operatorFiatBalance_withdraw(params, step, sL, s,_input): 324 | ''' 325 | Update flow state variable with the aggregated amount of shillings withdrawn 326 | ''' 327 | y = 'operatorFiatBalance' 328 | x = s['operatorFiatBalance'] 329 | if _input['withdraw']: 330 | withdraw = _input['withdraw'] 331 | withdrawnCICSum = [] 332 | for i,j in withdraw.items(): 333 | withdrawnCICSum.append(j) 334 | x = x - sum(withdrawnCICSum) 335 | else: 336 | pass 337 | 338 | return (y,x) 339 | 340 | 341 | 342 | def update_operatorCICBalance_withdraw(params, step, sL, s,_input): 343 | ''' 344 | Update flow state variable with the aggregated amount of shillings withdrawn 345 | ''' 346 | y = 'operatorCICBalance' 347 | x = s['operatorCICBalance'] 348 | if _input['withdraw']: 349 | withdraw = _input['withdraw'] 350 | withdrawnCICSum = [] 351 | for i,j in withdraw.items(): 352 | withdrawnCICSum.append(j) 353 | x = x + sum(withdrawnCICSum) 354 | else: 355 | pass 356 | 357 | return (y,x) -------------------------------------------------------------------------------- /SubpopulationGenerator/gap_statistic.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlockScience/Community_Inclusion_Currencies/a8de2d06723759c6d2381a06f0aa397d3aadc847/SubpopulationGenerator/gap_statistic.png -------------------------------------------------------------------------------- /SubpopulationGenerator/geographic/data/transactions_users_xDAI_26_July_2020.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlockScience/Community_Inclusion_Currencies/a8de2d06723759c6d2381a06f0aa397d3aadc847/SubpopulationGenerator/geographic/data/transactions_users_xDAI_26_July_2020.zip -------------------------------------------------------------------------------- /SubpopulationGenerator/pca.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlockScience/Community_Inclusion_Currencies/a8de2d06723759c6d2381a06f0aa397d3aadc847/SubpopulationGenerator/pca.png --------------------------------------------------------------------------------