{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# CIC Current System Network Graph"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Graph overview \n",
    "\n",
    "Modeling as a weighted directed graph with agents as nodes. A network is a set of items (nodes or vertices) connected by edges or links. \n",
    "We represent a network by a graph (N, g), which consists of a set of nodes N = {1, . . . , n}.\n",
    "\n",
    "#### Node types\n",
    "* Agent\n",
    "\n",
    "An agent is a user of the CIC system.\n",
    "* Chama\n",
    "\n",
    "A chama is a savings group consisting of multiple agents. Redemptions of CICs for fiat occur through chamas.\n",
    "* Trader\n",
    "\n",
    "A trader is an agent interacting with the bonding curve for investment/arbitrage opportunities.\n",
    "* Cloud\n",
    "\n",
    "The cloud is a representation of the open boundary to the world external to the model.\n",
    "* Contract\n",
    "\n",
    "The contract is the smart contract of the bonding curve.\n",
    "\n",
    "### Edges between agents\n",
    "The edge weight gij > 0 takes on non-binary values, representing the intensity of the interaction, so we refer to (N, g) as a weighted graph.\n",
    "E is the set of “directed” edges, i.e., (i, j) ∈ E\n",
    "\n",
    "#### Edge types\n",
    "* Demand\n",
    "* Fraction of demand in CIC\n",
    "* Utility - stack ranking. Food/Water is first, shopping, etc farther down\n",
    "* Spend\n",
    "* Fraction of actual in CIC\n",
    "\n",
    "![](images/dualoperator.png)\n",
    "\n",
    "\n",
    "![](images/v3differentialspec.png)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Assumptions\n",
    "(Defining data structures, not just initialization. Baking in degrees of freedom for future experimentation)\n",
    "\n",
    "* agents = a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p\n",
    "* Agent starting native currency is picked from a uniform distribution with a range of 20 to 500. Starting tokens is 400.\n",
    "* system = external,cic\n",
    "* chama = chama_1,chama_2,chama_3,chama_4\n",
    "\n",
    "Chamas are currently set to zero, it can be configured for more detailed analysis later on.\n",
    "* traders = ta,tb,tc\n",
    "\n",
    "Traders are currently set to zero, it can be configured for more detailed analysis later on.\n",
    "* Utility Types Ordered:\n",
    " * Food/Water\n",
    " * Fuel/Energy\n",
    " * Health\n",
    " * Education\n",
    " * Savings Group\n",
    " * Shop\n",
    "* Utility Types Probability \n",
    "  * 0.6\n",
    "  * 0.10\n",
    "  * 0.03\n",
    "  * 0.015\n",
    "  * 0.065\n",
    "  * 0.19\n",
    "* R0 = 500\n",
    "* S0 = 200000\n",
    "* P = 1\n",
    "* priceLevel = 100\n",
    "* fractionOfDemandInCIC = 0.5\n",
    "* fractionOfActualSpendInCIC = 0.5 # if an agent is interacting with the external environment, then the actual spend is 100% shilling.\n",
    "* kappa = 4\n",
    "\n",
    "\n",
    "## Initial State Values\n",
    "\n",
    "# Equations\n",
    "\n",
    "## Generators\n",
    "* Agent generation for each time step: Random choice of all agents minus 2 for both paying and receiving.  \n",
    "\n",
    "* Agent demand each time: Uniform distribution with a low value of 1 and a high of 500. \n",
    " \n",
    "### Red Cross Drip\n",
    "Every 30 days, the Red Cross drips 4000 shilling to the grassroots operator fiat balance.  \n",
    "\n",
    "### Spend Allocation \n",
    "\n",
    "#### Parameters:\n",
    "* Agent to pay: $i$\n",
    "* Agent to receive: $j$\n",
    "* Rank Order Demand: $\\frac{v_{i,j}}{d_{i,j}}$\n",
    "* Amount of currency agent $i$ has to spend, $\\gamma$\n",
    "* Amount of cic agent $i$ has to spend, $\\gamma_\\textrm{cic}$\n",
    "* Percentage of transaction in cic, $\\phi$\n",
    "* Spend, $\\zeta$\n",
    "\n",
    "\n",
    "if $\\frac{v_{i,j}}{d_{i,j}} * 1-\\phi > \\gamma_{i} \\textrm{and} \\frac{v_{i,j}}{d_{i,j}} * \\phi > \\gamma_\\textrm{cic} \\Rightarrow \\zeta = \\frac{v_{i,j}}{d_{i,j}}$ \n",
    "\n",
    "else $ \\Rightarrow \\zeta = \\gamma$\n",
    "\n",
    "Allocate utility type by stack ranking in. Allocate remaining fiat and cic until all demand is met or i runs out.\n",
    "\n",
    "\n",
    "### Withdraw calculation\n",
    "\n",
    "The user is able to withdraw up to 50% of the their CIC balance if they have spent 50% of their balance within the last 30 days at a conversion ratio of 1:1, meaning that for every one token withdraw, they receive 1 in native currency. We are assuming that agents want what to withdraw as much as they can.\n",
    "This is one of the most important control points for Grassroots economics. The more people withdraw CIC from the system, the more difficult it is on the system. The more people can withdraw, the better the adoption however. The inverse also holds true: the less individuals can withdraw, the lower the adoption.\n",
    "\n",
    "## Distribution to agents\n",
    "#### Parameters\n",
    "FrequencyOfAllocation = 45 # frequency of allocation of drip to agents\n",
    "* idealFiat = 5000\n",
    "* idealCIC = 200000\n",
    "* varianceCIC = 50000\n",
    "* varianceFiat = 1000\n",
    "* unadjustedPerAgent = 50\n",
    "\n",
    "```\n",
    "# agent:[centrality,allocationValue]\n",
    "agentAllocation = {'a':[1,1],'b':[1,1],'c':[1,1], \n",
    "                   'd':[1,1],'e':[1,1],'f':[1,1],\n",
    "                   'g':[1,1],'h':[1,1],'i':[1,1],\n",
    "                   'j':[1,1],'k':[1,1],'l':[1,1],\n",
    "                   'm':[1,1],'o':[1,1],'p':[1,1]}\n",
    "```\n",
    "\n",
    "Every 15 days, a total of unadjustedPerAgent * agents will be distributed among the agents. Allocation will occur based off of the the agent allocation dictionary allocation value. We can optimize the allocation overtime and make a state variable for adjustment overtime as a result of centrality. We are currently assuming that all agents have the same centrality and allocation.\n",
    "\n",
    "Internal velocity is better than external velocity of the system. Point of leverage to make more internal cycles. Canbe used for tuning system effiency.\n",
    "![](images/agentDistribution.png)\n",
    "\n",
    "### Inventory Controller\n",
    "Heuristic Monetary policy hysteresis conservation allocation between fiat and cic reserves. We've created an inventory control function to test if the current balance is in an acceptable tolarance. For the calculation, we use the following 2 variables, current CIC balance and current fiat balance, along with 2 parameters, desired cic and variance.\n",
    "\n",
    "Below is \n",
    "```\n",
    "if idealCIC - variance <= actual <= ideal + (2*variance):\n",
    "    decision = 'none'\n",
    "    amount = 0\n",
    "else:\n",
    "    \n",
    "    if (ideal + variance) > actual :\n",
    "        decision = 'mint'\n",
    "        amount = (ideal + variance) - actual\n",
    "    else:\n",
    "        pass\n",
    "    if actual > (ideal + variance):\n",
    "        decision = 'burn'\n",
    "        amount = actual - (ideal + variance) \n",
    "    else:\n",
    "        pass\n",
    "\n",
    "if decision == 'mint':\n",
    "    if fiat < (ideal - variance):\n",
    "        if amount > fiat:\n",
    "            decision = 'none'\n",
    "            amount = 0\n",
    "        else:\n",
    "            pass\n",
    "if decision == 'none':\n",
    "    if fiat < (ideal - variance):\n",
    "        decision = 'mint'\n",
    "        amount = (ideal-variance)\n",
    "    else:\n",
    "        pass\n",
    "    \n",
    "\n",
    "```\n",
    "\n",
    "If the controller wants to mint, the amount decided from the inventory controller, $\\Delta R$ is inserted into the following minting equation:\n",
    "\n",
    "- Conservation equation, V0: $V(R+ \\Delta R', S+\\Delta S) = \\frac{(S+\\Delta S)^\\kappa}{R+\\Delta R'} =\\frac{S^\\kappa}{R}$\n",
    "- Derived Mint equation: $\\Delta S = mint\\big(\\Delta R ; (R,S)\\big)= S\\big(\\sqrt[\\kappa]{(1+\\frac{\\Delta R}{R})}-1\\big)$\n",
    " \n",
    "\n",
    "\n",
    "If the controller wants to burn, the amount decided from the inventory controller, $\\Delta S$ is inserted into the following minting equation:\n",
    " - Derived Withdraw equation: $\\Delta R = withdraw\\big(\\Delta S ; (R,S)\\big)= R\\big(1-(1-\\frac{\\Delta S}{S})^\\kappa \\big)$\n",
    " \n",
    "\n",
    "There is a built in process lag of 7 days before the newly minted or burned CIC is added to the respective operator accounts.\n",
    "\n",
    "### Velocity of Money \n",
    "\n",
    "Indirect measurement of velocity of money per timestep:\n",
    "\n",
    "$V_t = \\frac{PT}{M}$\n",
    "\n",
    "Where\n",
    "\n",
    "* $V_t$ is the velocity of money for all agent transaction in the time period examined\n",
    "* $P$ is the price level\n",
    "* $T$ is the aggregated real value of all agent transactions in the time period examined\n",
    "* $M$ is the average money supply in the economy in the time period examined.\n",
    "\n",
    "\n",
    "\n",
    "## Simulation run\n",
    "* 5 monte carlo runs with 100 timesteps. Each timestep is equal to 1 day.\n",
    "* We are going to perform a parameter sweep in this notebook over the frequency of the Red Cross drips into the system. For our simulation, we will run our model with drips every 30,60, and 90 days, and compare/contrast the performance of our system against over these differences.\n",
    "\n",
    "## Proposed Experiments\n",
    "![](images/experiments.png)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Define cadCAD Model"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Requirement already satisfied: cadCAD in /home/aclarkdata/anaconda3/lib/python3.7/site-packages (0.3.1)\r\n",
      "Requirement already satisfied: pathos in /home/aclarkdata/anaconda3/lib/python3.7/site-packages (from cadCAD) (0.2.5)\r\n",
      "Requirement already satisfied: pandas in /home/aclarkdata/anaconda3/lib/python3.7/site-packages (from cadCAD) (1.0.3)\r\n",
      "Requirement already satisfied: fn in /home/aclarkdata/anaconda3/lib/python3.7/site-packages (from cadCAD) (0.4.3)\r\n",
      "Requirement already satisfied: funcy in /home/aclarkdata/anaconda3/lib/python3.7/site-packages (from cadCAD) (1.14)\r\n",
      "Requirement already satisfied: wheel in /home/aclarkdata/anaconda3/lib/python3.7/site-packages (from cadCAD) (0.33.6)\r\n",
      "Requirement already satisfied: tabulate in /home/aclarkdata/anaconda3/lib/python3.7/site-packages (from cadCAD) (0.8.2)\r\n",
      "Requirement already satisfied: pox>=0.2.7 in /home/aclarkdata/anaconda3/lib/python3.7/site-packages (from pathos->cadCAD) (0.2.7)\r\n",
      "Requirement already satisfied: dill>=0.3.1 in /home/aclarkdata/anaconda3/lib/python3.7/site-packages (from pathos->cadCAD) (0.3.1.1)\r\n",
      "Requirement already satisfied: ppft>=1.6.6.1 in /home/aclarkdata/anaconda3/lib/python3.7/site-packages (from pathos->cadCAD) (1.6.6.1)\r\n",
      "Requirement already satisfied: multiprocess>=0.70.9 in /home/aclarkdata/anaconda3/lib/python3.7/site-packages (from pathos->cadCAD) (0.70.9)\r\n",
      "Requirement already satisfied: pytz>=2017.2 in /home/aclarkdata/anaconda3/lib/python3.7/site-packages (from pandas->cadCAD) (2018.7)\r\n",
      "Requirement already satisfied: python-dateutil>=2.6.1 in /home/aclarkdata/.local/lib/python3.7/site-packages (from pandas->cadCAD) (2.8.0)\r\n",
      "Requirement already satisfied: numpy>=1.13.3 in /home/aclarkdata/anaconda3/lib/python3.7/site-packages (from pandas->cadCAD) (1.18.2)\r\n",
      "Requirement already satisfied: six>=1.7.3 in /home/aclarkdata/anaconda3/lib/python3.7/site-packages (from ppft>=1.6.6.1->pathos->cadCAD) (1.14.0)\r\n"
     ]
    }
   ],
   "source": [
    "!pip install cadCAD"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "/home/aclarkdata/anaconda3/lib/python3.7/site-packages/statsmodels/tools/_testing.py:19: FutureWarning: pandas.util.testing is deprecated. Use the functions in the public API at pandas.testing instead.\n",
      "  import pandas.util.testing as tm\n"
     ]
    }
   ],
   "source": [
    "# import libraries\n",
    "import math\n",
    "from decimal import Decimal\n",
    "from datetime import timedelta\n",
    "import numpy as np\n",
    "from typing import Dict, List\n",
    "\n",
    "from cadCAD.configuration import append_configs\n",
    "from cadCAD.configuration.utils import bound_norm_random, ep_time_step, config_sim, access_block\n",
    "\n",
    "\n",
    "# The following imports NEED to be in the exact order\n",
    "from cadCAD.engine import ExecutionMode, ExecutionContext, Executor\n",
    "from cadCAD import configs\n",
    "\n",
    "\n",
    "import pandas as pd\n",
    "import seaborn as sns\n",
    "from tabulate import tabulate\n",
    "import matplotlib.pyplot as plt\n",
    "from ipywidgets import interact, interactive, fixed, interact_manual\n",
    "import ipywidgets as widgets\n",
    "from IPython.display import clear_output\n",
    "import networkx as nx\n",
    "from collections import OrderedDict\n",
    "pd.options.display.float_format = '{:.2f}'.format\n",
    "\n",
    "%matplotlib inline"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "default_kappa= 4\n",
    "default_exit_tax = .02\n",
    "\n",
    "#value function for a given state (R,S)\n",
    "def invariant(R,S,kappa=default_kappa):\n",
    "    \n",
    "    return (S**kappa)/R\n",
    "\n",
    "#given a value function (parameterized by kappa)\n",
    "#and an invariant coeficient V0\n",
    "#return Supply S as a function of reserve R\n",
    "def reserve(S, V0, kappa=default_kappa):\n",
    "    return (S**kappa)/V0\n",
    "\n",
    "#given a value function (parameterized by kappa)\n",
    "#and an invariant coeficient V0\n",
    "#return Supply S as a function of reserve R\n",
    "def supply(R, V0, kappa=default_kappa):\n",
    "    return (V0*R)**(1/kappa)\n",
    "\n",
    "#given a value function (parameterized by kappa)\n",
    "#and an invariant coeficient V0\n",
    "#return a spot price P as a function of reserve R\n",
    "def spot_price(R, V0, kappa=default_kappa):\n",
    "    return kappa*R**((kappa-1)/kappa)/V0**(1/kappa)\n",
    "\n",
    "#for a given state (R,S)\n",
    "#given a value function (parameterized by kappa)\n",
    "#and an invariant coeficient V0\n",
    "#deposit deltaR to Mint deltaS\n",
    "#with realized price deltaR/deltaS\n",
    "def mint(deltaR, R,S, V0, kappa=default_kappa):\n",
    "    deltaS = (V0*(R+deltaR))**(1/kappa)-S\n",
    "    if deltaS ==0:\n",
    "        realized_price = spot_price(R+deltaR, V0, kappa)\n",
    "    else:\n",
    "        realized_price = deltaR/deltaS\n",
    "    deltaS = round(deltaS,2)\n",
    "    return deltaS, realized_price\n",
    "\n",
    "#for a given state (R,S)\n",
    "#given a value function (parameterized by kappa)\n",
    "#and an invariant coeficient V0\n",
    "#burn deltaS to Withdraw deltaR\n",
    "#with realized price deltaR/deltaS\n",
    "def withdraw(deltaS, R,S, V0, kappa=default_kappa):\n",
    "    deltaR = R-((S-deltaS)**kappa)/V0\n",
    "    if deltaS ==0:\n",
    "        realized_price = spot_price(R+deltaR, V0, kappa)\n",
    "    else:\n",
    "        realized_price = deltaR/deltaS\n",
    "    deltaR = round(deltaR,2)\n",
    "    return deltaR, realized_price\n",
    "\n",
    "\n",
    "\n",
    "def iterateEdges(network,edgeToIterate):\n",
    "    '''\n",
    "    Description:\n",
    "    Iterate through a network on a weighted edge and return\n",
    "    two dictionaries: the inflow and outflow for the given agents\n",
    "    in the format:\n",
    "    \n",
    "    {'Agent':amount}\n",
    "    '''\n",
    "    outflows = {}\n",
    "    inflows = {}\n",
    "    for i,j in network.edges:\n",
    "        try:\n",
    "            amount = network[i][j][edgeToIterate]\n",
    "            if i in outflows:\n",
    "                outflows[i] = outflows[i] + amount\n",
    "            else:\n",
    "                outflows[i] =  amount\n",
    "            if j in inflows:\n",
    "                inflows[j] = inflows[j] + amount\n",
    "            else:\n",
    "                inflows[j] = amount\n",
    "        except:\n",
    "            pass\n",
    "    return outflows,inflows\n",
    "\n",
    "\n",
    "def inflowAndOutflowDictionaryMerge(inflow,outflow):\n",
    "    '''\n",
    "    Description:\n",
    "    Merge two dictionaries and return one dictionary with zero floor'''\n",
    "    \n",
    "    merged = {}\n",
    "\n",
    "    inflowsKeys = [k for k,v in inflow.items() if k not in outflow]\n",
    "    for i in inflowsKeys:\n",
    "        merged[i] = inflow[i]\n",
    "    outflowsKeys = [k for k,v in outflow.items() if k not in inflow]\n",
    "    for i in outflowsKeys:\n",
    "        merged[i] = outflow[i]\n",
    "    overlapKeys = [k for k,v in inflow.items() if k in outflow]\n",
    "    for i in overlapKeys:\n",
    "        amt = outflow[i] - inflow[i] \n",
    "        if amt < 0:\n",
    "            merged[i] = 0\n",
    "        else:\n",
    "            merged[i] = amt\n",
    "            pass\n",
    "        \n",
    "    return merged\n",
    "\n",
    "        \n",
    "def spendCalculation(agentToPay,agentToReceive,rankOrderDemand,maxSpendCurrency,maxSpendTokens,cicPercentage):\n",
    "    '''\n",
    "    Function to calculate if an agent can pay for demand given token and currency contraints\n",
    "    '''\n",
    "    if (rankOrderDemand[agentToReceive] * (1-cicPercentage)) > maxSpendCurrency[agentToPay]:\n",
    "        verdict_currency = 'No'\n",
    "    else:\n",
    "        verdict_currency = 'Enough'\n",
    "        \n",
    "    if (rankOrderDemand[agentToReceive] * cicPercentage) > maxSpendTokens[agentToPay]:\n",
    "        verdict_cic = 'No'\n",
    "    else:\n",
    "        verdict_cic = 'Enough'\n",
    "    \n",
    "    if verdict_currency == 'Enough'and verdict_cic == 'Enough':\n",
    "        spend = rankOrderDemand[agentToReceive]\n",
    "    \n",
    "    elif maxSpendCurrency[agentToPay] > 0:\n",
    "        spend = maxSpendCurrency[agentToPay]\n",
    "    else:\n",
    "        spend = 0\n",
    "        \n",
    "    return spend\n",
    "\n",
    "\n",
    "def spendCalculationExternal(agentToPay,agentToReceive,rankOrderDemand,maxSpendCurrency):\n",
    "    '''\n",
    "    '''\n",
    "    if rankOrderDemand[agentToReceive] > maxSpendCurrency[agentToPay]:\n",
    "        verdict_currency = 'No'\n",
    "    else:\n",
    "        verdict_currency = 'Enough'\n",
    "    \n",
    "    if verdict_currency == 'Enough':\n",
    "        spend = rankOrderDemand[agentToReceive]\n",
    "        \n",
    "    elif maxSpendCurrency[agentToPay] > 0:\n",
    "        spend = maxSpendCurrency[agentToPay]\n",
    "    else:\n",
    "        spend = 0\n",
    "        \n",
    "    return spend\n",
    "\n",
    "\n",
    "def DictionaryMergeAddition(inflow,outflow):\n",
    "    '''\n",
    "    Description:\n",
    "    Merge two dictionaries and return one dictionary'''\n",
    "    \n",
    "    merged = {}\n",
    "\n",
    "    inflowsKeys = [k for k,v in inflow.items() if k not in outflow]\n",
    "    for i in inflowsKeys:\n",
    "        merged[i] = inflow[i]\n",
    "    outflowsKeys = [k for k,v in outflow.items() if k not in inflow]\n",
    "    for i in outflowsKeys:\n",
    "        merged[i] = outflow[i]\n",
    "    overlapKeys = [k for k,v in inflow.items() if k in outflow]\n",
    "    for i in overlapKeys:\n",
    "        merged[i] = outflow[i] + inflow[i] \n",
    "        \n",
    "    return merged\n",
    "\n",
    "def mint_burn_logic_control(ideal,actual,variance,fiat,fiat_variance,ideal_fiat):\n",
    "    '''\n",
    "    Inventory control function to test if the current balance is in an acceptable range. Tolerance range \n",
    "    '''\n",
    "    if ideal - variance <= actual <= ideal + (2*variance):\n",
    "        decision = 'none'\n",
    "        amount = 0\n",
    "    else:\n",
    "        if (ideal + variance) > actual:\n",
    "            decision = 'mint'\n",
    "            amount = (ideal + variance) - actual\n",
    "        else:\n",
    "            pass\n",
    "        if actual > (ideal + variance):\n",
    "            decision = 'burn'\n",
    "            amount = actual - (ideal + variance) \n",
    "        else:\n",
    "            pass\n",
    "\n",
    "    if decision == 'mint':\n",
    "        if fiat < (ideal_fiat - fiat_variance):\n",
    "            if amount > fiat:\n",
    "                decision = 'none'\n",
    "                amount = 0\n",
    "            else:\n",
    "                pass\n",
    "    if decision == 'none':\n",
    "        if fiat < (ideal_fiat - fiat_variance):\n",
    "            decision = 'mint'\n",
    "            amount = (ideal_fiat-fiat_variance)\n",
    "        else:\n",
    "            pass\n",
    "    \n",
    "    amount = round(amount,2)\n",
    "    return decision, amount\n",
    "    \n",
    "#NetworkX functions\n",
    "def get_nodes_by_type(g, node_type_selection):\n",
    "    return [node for node in g.nodes if g.nodes[node]['type']== node_type_selection]\n",
    "\n",
    "def get_edges_by_type(g, edge_type_selection):\n",
    "    return [edge for edge in g.edges if g.edges[edge]['type']== edge_type_selection]\n",
    "\n",
    "def get_edges(g):\n",
    "    return [edge for edge in g.edges if g.edges[edge]]\n",
    "\n",
    "def get_nodes(g):\n",
    "    '''\n",
    "    df.network.apply(lambda g: np.array([g.nodes[j]['balls'] for j in get_nodes(g)]))\n",
    "    '''\n",
    "    return [node for node in g.nodes if g.nodes[node]]\n",
    "\n",
    "def aggregate_runs(df,aggregate_dimension):\n",
    "    '''\n",
    "    Function to aggregate the monte carlo runs along a single dimension.\n",
    "    Parameters:\n",
    "    df: dataframe name\n",
    "    aggregate_dimension: the dimension you would like to aggregate on, the standard one is timestep.\n",
    "    Example run:\n",
    "    mean_df,median_df,std_df,min_df = aggregate_runs(df,'timestep')\n",
    "    '''\n",
    "    df = df[df['substep'] == df.substep.max()]\n",
    "    mean_df = df.groupby(aggregate_dimension).mean().reset_index()\n",
    "    median_df = df.groupby(aggregate_dimension).median().reset_index()\n",
    "    std_df = df.groupby(aggregate_dimension).std().reset_index()\n",
    "    min_df = df.groupby(aggregate_dimension).min().reset_index()\n",
    "\n",
    "    return mean_df,median_df,std_df,min_df\n",
    "\n",
    "\n",
    "\n",
    "def plot_averaged_runs(df,aggregate_dimension,x, y,run_count,lx=False,ly=False, suppMin=False):\n",
    "    '''\n",
    "    Function to plot the mean, median, etc of the monte carlo runs along a single variable.\n",
    "    Parameters:\n",
    "    df: dataframe name\n",
    "    aggregate_dimension: the dimension you would like to aggregate on, the standard one is timestep.\n",
    "    x = x axis variable for plotting\n",
    "    y = y axis variable for plotting\n",
    "    run_count = the number of monte carlo simulations\n",
    "    lx = True/False for if the x axis should be logged\n",
    "    ly = True/False for if the x axis should be logged\n",
    "    suppMin: True/False for if the miniumum value should be plotted\n",
    "    Note: Run aggregate_runs before using this function\n",
    "    Example run:\n",
    "    '''\n",
    "    mean_df,median_df,std_df,min_df = aggregate_runs(df,aggregate_dimension)\n",
    "\n",
    "    plt.figure(figsize=(10,6))\n",
    "    if not(suppMin):\n",
    "        plt.plot(mean_df[x].values, mean_df[y].values,\n",
    "             mean_df[x].values,median_df[y].values,\n",
    "             mean_df[x].values,mean_df[y].values+std_df[y].values,\n",
    "             mean_df[x].values,min_df[y].values)\n",
    "        plt.legend(['mean', 'median', 'mean+ 1*std', 'min'],bbox_to_anchor=(1.05, 1), loc=2, borderaxespad=0.)\n",
    "\n",
    "    else:\n",
    "        plt.plot(mean_df[x].values, mean_df[y].values,\n",
    "             mean_df[x].values,median_df[y].values,\n",
    "             mean_df[x].values,mean_df[y].values+std_df[y].values,\n",
    "             mean_df[x].values,mean_df[y].values-std_df[y].values)\n",
    "        plt.legend(['mean', 'median', 'mean+ 1*std', 'mean - 1*std'],bbox_to_anchor=(1.05, 1), loc=2, borderaxespad=0.)\n",
    "\n",
    "    plt.xlabel(x)\n",
    "    plt.ylabel(y)\n",
    "    title_text = 'Performance of ' + y + ' over all of ' + str(run_count) + ' Monte Carlo runs'\n",
    "    plt.title(title_text)\n",
    "    if lx:\n",
    "        plt.xscale('log')\n",
    "\n",
    "    if ly:\n",
    "        plt.yscale('log')\n",
    "\n",
    "def plot_median_with_quantiles(df,aggregate_dimension,x, y):\n",
    "    '''\n",
    "    Function to plot the median and 1st and 3rd quartiles of the monte carlo runs along a single variable.\n",
    "    Parameters:\n",
    "    df: dataframe name\n",
    "    aggregate_dimension: the dimension you would like to aggregate on, the standard one is timestep.\n",
    "    x = x axis variable for plotting\n",
    "    y = y axis variable for plotting\n",
    "\n",
    "    Example run:\n",
    "    plot_median_with_quantiles(df,'timestep','timestep','AggregatedAgentSpend')\n",
    "    '''\n",
    "    \n",
    "    df = df[df['substep'] == df.substep.max()]\n",
    "    firstQuantile = df.groupby(aggregate_dimension).quantile(0.25).reset_index()\n",
    "    thirdQuantile = df.groupby(aggregate_dimension).quantile(0.75).reset_index()\n",
    "    median_df = df.groupby(aggregate_dimension).median().reset_index()\n",
    "    \n",
    "    fig, ax = plt.subplots(1,figsize=(10,6))\n",
    "    ax.plot(median_df[x].values, median_df[y].values, lw=2, label='Median', color='blue')\n",
    "    ax.fill_between(firstQuantile[x].values, firstQuantile[y].values, thirdQuantile[y].values, facecolor='black', alpha=0.2)\n",
    "    ax.set_title(y + ' Median')\n",
    "    ax.legend(loc='upper left')\n",
    "    ax.set_xlabel('Timestep')\n",
    "    ax.set_ylabel('Amount')\n",
    "    ax.grid()\n",
    "    \n",
    "def plot_median_with_quantiles_annotation(df,aggregate_dimension,x, y):\n",
    "    '''\n",
    "    Function to plot the median and 1st and 3rd quartiles of the monte carlo runs along a single variable.\n",
    "    Parameters:\n",
    "    df: dataframe name\n",
    "    aggregate_dimension: the dimension you would like to aggregate on, the standard one is timestep.\n",
    "    x = x axis variable for plotting\n",
    "    y = y axis variable for plotting\n",
    "\n",
    "    Example run:\n",
    "    plot_median_with_quantiles(df,'timestep','timestep','AggregatedAgentSpend')\n",
    "    '''\n",
    "    \n",
    "    df = df[df['substep'] == df.substep.max()]\n",
    "    firstQuantile = df.groupby(aggregate_dimension).quantile(0.25).reset_index()\n",
    "    thirdQuantile = df.groupby(aggregate_dimension).quantile(0.75).reset_index()\n",
    "    median_df = df.groupby(aggregate_dimension).median().reset_index()\n",
    "    \n",
    "    fig, ax = plt.subplots(1,figsize=(10,6))\n",
    "    ax.axvline(x=30,linewidth=2, color='r')\n",
    "    ax.annotate('Agents can withdraw and Red Cross Drip occurs', xy=(30,2), xytext=(35, 1),\n",
    "            arrowprops=dict(facecolor='black', shrink=0.05))\n",
    "    \n",
    "    ax.axvline(x=60,linewidth=2, color='r')\n",
    "    ax.axvline(x=90,linewidth=2, color='r')\n",
    "    ax.plot(median_df[x].values, median_df[y].values, lw=2, label='Median', color='blue')\n",
    "    ax.fill_between(firstQuantile[x].values, firstQuantile[y].values, thirdQuantile[y].values, facecolor='black', alpha=0.2)\n",
    "    ax.set_title(y + ' Median')\n",
    "    ax.legend(loc='upper left')\n",
    "    ax.set_xlabel('Timestep')\n",
    "    ax.set_ylabel('Amount')\n",
    "    ax.grid()\n",
    "\n",
    "\n",
    "def first_five_plot(df,aggregate_dimension,x,y,run_count):\n",
    "    '''\n",
    "    A function that generates timeseries plot of at most the first five Monte Carlo runs.\n",
    "    Parameters:\n",
    "    df: dataframe name\n",
    "    aggregate_dimension: the dimension you would like to aggregate on, the standard one is timestep.\n",
    "    x = x axis variable for plotting\n",
    "    y = y axis variable for plotting\n",
    "    run_count = the number of monte carlo simulations\n",
    "    Note: Run aggregate_runs before using this function\n",
    "    Example run:\n",
    "    first_five_plot(df,'timestep','timestep','revenue',run_count=100)\n",
    "    '''\n",
    "    mean_df,median_df,std_df,min_df = aggregate_runs(df,aggregate_dimension)\n",
    "    plt.figure(figsize=(10,6))\n",
    "    if run_count < 5:\n",
    "        runs = run_count\n",
    "    else:\n",
    "        runs = 5\n",
    "    for r in range(1,runs+1):\n",
    "        legend_name = 'Run ' + str(r)\n",
    "        plt.plot(df[df.run==r].timestep, df[df.run==r][y], label = legend_name )\n",
    "    plt.plot(mean_df[x], mean_df[y], label = 'Mean', color = 'black')\n",
    "    plt.legend(bbox_to_anchor=(1.05, 1), loc=2, borderaxespad=0.)\n",
    "    plt.xlabel(x)\n",
    "    plt.ylabel(y)\n",
    "    title_text = 'Performance of ' + y + ' over the First ' + str(runs) + ' Monte Carlo Runs'\n",
    "    plt.title(title_text)\n",
    "    #plt.savefig(y +'_FirstFiveRuns.jpeg')\n",
    "    \n",
    "    \n",
    "def aggregate_runs_param_mc(df,aggregate_dimension):\n",
    "    '''\n",
    "    Function to aggregate the monte carlo runs along a single dimension.\n",
    "    Parameters:\n",
    "    df: dataframe name\n",
    "    aggregate_dimension: the dimension you would like to aggregate on, the standard one is timestep.\n",
    "    Example run:\n",
    "    mean_df,median_df,std_df,min_df = aggregate_runs(df,'timestep')\n",
    "    '''\n",
    "    df = df[df['substep'] == df.substep.max()]\n",
    "    mean_df = df.groupby(aggregate_dimension).mean().reset_index()\n",
    "    median_df = df.groupby(aggregate_dimension).median().reset_index()\n",
    "    #min_df = df.groupby(aggregate_dimension).min().reset_index()\n",
    "    #max_df = df.groupby(aggregate_dimension).max().reset_index()\n",
    "    return mean_df,median_df\n",
    "\n",
    "def param_dfs(results,params,swept):\n",
    "    mean_df,median_df = aggregate_runs_param_mc(results[0]['result'],'timestep')\n",
    "    mean_df[swept] = params[0]\n",
    "    median_df[swept] = params[0]\n",
    "    #max_df[swept] = params[0]\n",
    "    #min_df[swept] = params[0]\n",
    "    for i in range(1,len(params)):\n",
    "        mean_df_intermediate,median_df_intermediate = aggregate_runs_param_mc(results[i]['result'],'timestep')\n",
    "        mean_df_intermediate[swept] = params[i]\n",
    "        median_df_intermediate[swept] = params[i]\n",
    "        #max_df_intermediate[swept] = params[i]\n",
    "        #min_df_intermediate[swept] = params[i]\n",
    "        mean_df= pd.concat([mean_df, mean_df_intermediate])\n",
    "        median_df= pd.concat([median_df, median_df_intermediate])\n",
    "        #max_df= pd.concat([max_df, max_df_intermediate])\n",
    "        #min_df= pd.concat([min_df, min_df_intermediate])\n",
    "    return mean_df,median_df\n",
    "\n",
    "\n",
    "def param_plot(results,state_var_x, state_var_y, parameter, save_plot = False,**kwargs):\n",
    "    '''\n",
    "    Results (df) is the dataframe (concatenated list of results dictionaries)\n",
    "    length = intreger, number of parameter values\n",
    "    Enter state variable name as a string for x and y. Enter the swept parameter name as a string.\n",
    "    y_label kwarg for custom y-label and title reference\n",
    "    x_label kwarg for custom x-axis label\n",
    "    '''\n",
    "    sns.scatterplot(x=state_var_x, y = state_var_y, hue = parameter, style= parameter, palette  = 'coolwarm',alpha=1, data = results, legend=\"full\")\n",
    "    title_text = 'Effect of ' + parameter + ' Parameter Sweep on ' + state_var_y\n",
    "    for key, value in kwargs.items():\n",
    "        if key == 'y_label':\n",
    "            plt.ylabel(value)\n",
    "            title_text = 'Effect of ' + parameter + ' Parameter Sweep on ' + value\n",
    "        if key == 'x_label':\n",
    "            plt.xlabel(value)\n",
    "    plt.title(title_text)\n",
    "    if save_plot == True:\n",
    "        filename = state_var_y + state_var_x + parameter + 'plot.png'\n",
    "# #         plt.savefig('static/images/' + filename)\n",
    "#         plt.savefig(filename)\n",
    "        lgd = plt.legend(bbox_to_anchor=(1.05, 1), loc=2, borderaxespad=0.)\n",
    "        #title_text = 'Market Volatility versus Normalized Liquid Token Supply for All Runs'\n",
    "        plt.title(title_text)\n",
    "        plt.savefig('static/images/' + filename, bbox_extra_artists=(lgd,), bbox_inches='tight')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Initilization \n",
    "\n",
    "# Assumptions:\n",
    "# Amount received in shilling when withdraw occurs\n",
    "leverage = 1 \n",
    "\n",
    "# process time\n",
    "process_lag = 7 # timesteps\n",
    "\n",
    "# red cross drip amount\n",
    "drip = 4000\n",
    "\n",
    "# system initialization\n",
    "agents = ['a','b','c','d','e','f','g','h','i','j','k','l','m','o','p']\n",
    "\n",
    "# system actors\n",
    "system = ['external','cic']\n",
    "\n",
    "# chamas\n",
    "chama = ['chama_1','chama_2','chama_3','chama_4']\n",
    "\n",
    "# traders\n",
    "traders = ['ta','tb','tc'] #only trading on the cic. Link to external and cic not to other agents\n",
    "\n",
    "allAgents = agents + system\n",
    "\n",
    "mixingAgents = ['a','b','c','d','e','f','g','h','i','j','k','l','m','o','p','external']\n",
    "\n",
    "UtilityTypesOrdered ={'Food/Water':1,\n",
    "                    'Fuel/Energy':2,\n",
    "                    'Health':3,\n",
    "                    'Education':4,\n",
    "                    'Savings Group':5,\n",
    "                    'Shop':6}\n",
    "\n",
    "utilityTypesProbability = {'Food/Water':0.6,\n",
    "                    'Fuel/Energy':0.10,\n",
    "                    'Health':0.03,\n",
    "                    'Education':0.015,\n",
    "                    'Savings Group':0.065,\n",
    "                    'Shop':0.19}\n",
    "\n",
    "\n",
    "R0 =  500 #thousand xDAI\n",
    "kappa = 4 #leverage\n",
    "P0 = 1/100 #initial price\n",
    "S0 = kappa*R0/P0\n",
    "V0 = invariant(R0,S0,kappa)\n",
    "P = spot_price(R0, V0, kappa)\n",
    "\n",
    "# Price level\n",
    "priceLevel = 100\n",
    "\n",
    "fractionOfDemandInCIC = 0.5\n",
    "fractionOfActualSpendInCIC = 0.5\n",
    "\n",
    "def create_network():\n",
    "    # Create network graph\n",
    "    network = nx.DiGraph()\n",
    "\n",
    "    # Add nodes for n participants plus the external economy and the cic network\n",
    "    for i in agents:\n",
    "        network.add_node(i,type='Agent',tokens=400, native_currency = int(np.random.uniform(low=20, high=500, size=1)[0]))\n",
    "        \n",
    "        \n",
    "    network.add_node('external',type='Contract',native_currency = 100000000,tokens = 0,delta_native_currency = 0, pos=(1,50))\n",
    "    network.add_node('cic',type='Contract',tokens= S0, native_currency = R0,pos=(50,1))\n",
    "\n",
    "    for i in chama:\n",
    "        network.add_node(i,type='Chama')\n",
    "        \n",
    "    for i in traders:\n",
    "        network.add_node(i,type='Trader',tokens=20, native_currency = 20, \n",
    "                        price_belief = 1, trust_level = 1)\n",
    "        \n",
    "    # Create bi-directional edges between all participants\n",
    "    for i in allAgents:\n",
    "        for j in allAgents:\n",
    "            if i!=j:\n",
    "                network.add_edge(i,j)\n",
    "\n",
    "    # Create bi-directional edges between each trader and the external economy and the cic environment            \n",
    "    for i in traders:\n",
    "        for j in system:\n",
    "            if i!=j:\n",
    "                network.add_edge(i,j)\n",
    "                \n",
    "    # Create bi-directional edges between some agent and a chama node representing membershio      \n",
    "    for i in chama:\n",
    "        for j in agents:\n",
    "            if np.random.choice(['Member','Non_Member'],1,p=[.50,.50])[0] == 'Member':\n",
    "                network.add_edge(i,j)\n",
    "\n",
    "    # Type colors \n",
    "    colors = ['Red','Blue','Green','Orange']\n",
    "    color_map = []\n",
    "    for i in network.nodes:\n",
    "        if network.nodes[i]['type'] == 'Agent':\n",
    "            color_map.append('Red')\n",
    "        elif network.nodes[i]['type'] == 'Cloud':\n",
    "            color_map.append('Blue')\n",
    "        elif network.nodes[i]['type'] == 'Contract':\n",
    "            color_map.append('Green')\n",
    "        elif network.nodes[i]['type'] == 'Trader':\n",
    "            color_map.append('Yellow')\n",
    "        elif network.nodes[i]['type'] == 'Chama':\n",
    "            color_map.append('Orange')\n",
    "            \n",
    "    pos = nx.spring_layout(network,pos=nx.get_node_attributes(network,'pos'),fixed=nx.get_node_attributes(network,'pos'),seed=10)\n",
    "    nx.draw(network,node_color = color_map,pos=pos,with_labels=True,alpha=0.7)\n",
    "    plt.savefig('images/graph.png')\n",
    "    plt.show()\n",
    "    return network"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 100108 characters]\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "\n",
    "genesis_states = { \n",
    "    # initial states of the economy\n",
    "    'network': create_network(),# networkx market\n",
    "    'KPIDemand': {},\n",
    "    'KPISpend': {},\n",
    "    'KPISpendOverDemand': {},\n",
    "    'VelocityOfMoney':0,\n",
    "    'startingBalance': {},\n",
    "    '30_day_spend': {},\n",
    "    'withdraw':{},\n",
    "    'outboundAgents':[],\n",
    "    'inboundAgents':[],\n",
    "    'operatorFiatBalance': R0,\n",
    "    'operatorCICBalance': S0,\n",
    "    'fundsInProcess': {'timestep':[],'decision':[],'cic':[],'shilling':[]},\n",
    "    'totalDistributedToAgents':0,\n",
    "    'totalMinted':0,\n",
    "    'totalBurned':0\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Exogenous \n",
    "def startingBalance(params, step, sL, s, _input):\n",
    "    '''\n",
    "    Calculate agent starting balance every 30 days\n",
    "    '''\n",
    "    y = 'startingBalance'\n",
    "    network = s['network']\n",
    "\n",
    "    startingBalance = {}\n",
    "\n",
    "    timestep = s['timestep']\n",
    "\n",
    "    division =  timestep % 31  == 0\n",
    "\n",
    "    if timestep == 1:\n",
    "        for i in agents:\n",
    "            startingBalance[i] = network.nodes[i]['tokens']\n",
    "    elif division == True:\n",
    "        for i in agents:\n",
    "            startingBalance[i] = network.nodes[i]['tokens']\n",
    "    else:\n",
    "        startingBalance = s['startingBalance']\n",
    "    x = startingBalance\n",
    "\n",
    "    return (y, x)\n",
    "\n",
    "def update_30_day_spend(params, step, sL, s,_input):\n",
    "    '''\n",
    "    Aggregate agent spend. Refresh every 30 days.\n",
    "    '''\n",
    "    y = '30_day_spend'\n",
    "    network = s['network']\n",
    "\n",
    "    timestep = s['timestep']\n",
    "\n",
    "    division =  timestep % 31  == 0\n",
    "\n",
    "    if division == True:\n",
    "        outflowSpend, inflowSpend = iterateEdges(network,'spend')\n",
    "        spend =  outflowSpend \n",
    "    else:\n",
    "        spendOld = s['30_day_spend']\n",
    "        outflowSpend, inflowSpend = iterateEdges(network,'spend')\n",
    "        spend = DictionaryMergeAddition(spendOld,outflowSpend) \n",
    "\n",
    "    x = spend\n",
    "    return (y, x)\n",
    "\n",
    "def redCrossDrop(params, step, sL, s, _input):\n",
    "    '''\n",
    "    Every 30 days, the red cross drips to the grassroots operator node\n",
    "    '''\n",
    "    y = 'operatorFiatBalance'\n",
    "    fiatBalance = s['operatorFiatBalance']\n",
    "    \n",
    "    timestep = s['timestep']\n",
    "    \n",
    "    division =  timestep % params['drip_frequency']  == 0\n",
    "\n",
    "    if division == True:\n",
    "        fiatBalance = fiatBalance + drip\n",
    "    else:\n",
    "        pass\n",
    "\n",
    "    x = fiatBalance\n",
    "    return (y, x)\n",
    "\n",
    "\n",
    "def clear_agent_activity(params,step,sL,s,_input):\n",
    "    '''\n",
    "    Clear agent activity from the previous timestep\n",
    "    '''\n",
    "    y = 'network'\n",
    "    network = s['network']\n",
    "\n",
    "    if s['timestep'] > 0:\n",
    "        outboundAgents = s['outboundAgents']\n",
    "        inboundAgents = s['inboundAgents']\n",
    "        \n",
    "        try:\n",
    "            for i,j in zip(outboundAgents,inboundAgents):\n",
    "                network[i][j]['demand'] = 0\n",
    "        except:\n",
    "            pass\n",
    "\n",
    "        # Clear cic % demand edge weights\n",
    "        try:\n",
    "            for i,j in zip(outboundAgents,inboundAgents):\n",
    "                network[i][j]['fractionOfDemandInCIC'] = 0\n",
    "        except:\n",
    "            pass\n",
    "\n",
    "\n",
    "        # Clear utility edge types\n",
    "        try: \n",
    "            for i,j in zip(outboundAgents,inboundAgents):\n",
    "                network[i][j]['utility'] = 0\n",
    "        except:\n",
    "            pass\n",
    "        \n",
    "        # Clear cic % spend edge weights\n",
    "        try:\n",
    "            for i,j in zip(outboundAgents,inboundAgents):\n",
    "                network[i][j]['fractionOfActualSpendInCIC'] = 0\n",
    "        except:\n",
    "            pass\n",
    "        # Clear spend edge types\n",
    "        try: \n",
    "            for i,j in zip(outboundAgents,inboundAgents):\n",
    "                network[i][j]['spend'] = 0\n",
    "        except:\n",
    "            pass\n",
    "    else:\n",
    "        pass\n",
    "    x = network\n",
    "    return (y,x)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [],
   "source": [
    "# System\n",
    "\n",
    "# Parameters\n",
    "agentsMinus = 2\n",
    "# percentage of balance a user can redeem\n",
    "redeemPercentage = 0.5\n",
    "\n",
    "# Behaviors\n",
    "def choose_agents(params, step, sL, s):\n",
    "    '''\n",
    "    Choose agents to interact during the given timestep and create their demand from a uniform distribution. \n",
    "    Based on probability, choose utility. \n",
    "    '''\n",
    "    outboundAgents = np.random.choice(mixingAgents,size=len(mixingAgents)-agentsMinus).tolist()\n",
    "    inboundAgents = np.random.choice(mixingAgents,size=len(mixingAgents)-agentsMinus).tolist()\n",
    "    stepDemands = np.random.uniform(low=1, high=500, size=len(mixingAgents)-agentsMinus).astype(int)\n",
    "    \n",
    "\n",
    "    stepUtilities = np.random.choice(list(UtilityTypesOrdered.keys()),size=len(mixingAgents)-agentsMinus,p=list(utilityTypesProbability.values())).tolist()\n",
    "\n",
    "    return {'outboundAgents':outboundAgents,'inboundAgents':inboundAgents,'stepDemands':stepDemands,'stepUtilities':stepUtilities}\n",
    "\n",
    "\n",
    "def spend_allocation(params, step, sL, s):\n",
    "    '''\n",
    "    Take mixing agents, demand, and utilities and allocate agent shillings and tokens based on utility and scarcity. \n",
    "    '''\n",
    "    # instantiate network state\n",
    "    network = s['network']\n",
    "\n",
    "    spendI = []\n",
    "    spendJ = []\n",
    "    spendAmount = []\n",
    "\n",
    "    # calculate max about of spend available to each agent\n",
    "    maxSpendShilling = {}\n",
    "    for i in mixingAgents:\n",
    "        maxSpendShilling[i] = network.nodes[i]['native_currency']\n",
    "        \n",
    "    maxSpendCIC = {}\n",
    "    for i in mixingAgents:\n",
    "        maxSpendCIC[i] = network.nodes[i]['tokens']\n",
    "\n",
    "\n",
    "    for i in mixingAgents: \n",
    "        rankOrder = {}\n",
    "        rankOrderDemand = {}\n",
    "        for j in network.adj[i]:\n",
    "            try:\n",
    "                rankOrder[j] = UtilityTypesOrdered[network.adj[i][j]['utility']]\n",
    "                rankOrderDemand[j] = network.adj[i][j]['demand']\n",
    "                rankOrder = dict(OrderedDict(sorted(rankOrder.items(), key=lambda v: v, reverse=False)))\n",
    "                for k in rankOrder:\n",
    "                    # if i or j is external, we transact 100% in shilling\n",
    "                    if i == 'external':\n",
    "                        amt = spendCalculationExternal(i,j,rankOrderDemand,maxSpendShilling)\n",
    "                        spendI.append(i)\n",
    "                        spendJ.append(j)\n",
    "                        spendAmount.append(amt)\n",
    "                        maxSpendShilling[i] = maxSpendShilling[i] - amt \n",
    "                    elif j == 'external':\n",
    "                        amt = spendCalculationExternal(i,j,rankOrderDemand,maxSpendShilling)\n",
    "                        spendI.append(i)\n",
    "                        spendJ.append(j)\n",
    "                        spendAmount.append(amt)\n",
    "                        maxSpendShilling[i] = maxSpendShilling[i] - amt \n",
    "                    else:\n",
    "                        amt = spendCalculation(i,j,rankOrderDemand,maxSpendShilling,maxSpendCIC,fractionOfDemandInCIC)\n",
    "                        spendI.append(i)\n",
    "                        spendJ.append(j)\n",
    "                        spendAmount.append(amt)\n",
    "                        maxSpendShilling[i] = maxSpendShilling[i] - amt * (1- fractionOfDemandInCIC)\n",
    "                        maxSpendCIC[i] = maxSpendCIC[i] - (amt * fractionOfDemandInCIC)\n",
    "            except:\n",
    "                pass\n",
    "    return {'spendI':spendI,'spendJ':spendJ,'spendAmount':spendAmount}\n",
    "\n",
    "\n",
    "def withdraw_calculation(params, step, sL, s):\n",
    "    ''''''\n",
    "    # instantiate network state\n",
    "    network = s['network']\n",
    "\n",
    "    # Assumptions:\n",
    "    # * user is only able to withdraw up to 50% of balance, assuming they have spent 50% of balance\n",
    "    # * Agents will withdraw as much as they can.\n",
    "    withdraw = {}\n",
    "\n",
    "    fiftyThreshold = {}\n",
    "\n",
    "    startingBalance = s['startingBalance']\n",
    "\n",
    "    spend = s['30_day_spend']\n",
    "    timestep = s['timestep']\n",
    "\n",
    "    division =  timestep % 30  == 0\n",
    "\n",
    "    if division == True:\n",
    "        for i,j in startingBalance.items():\n",
    "            fiftyThreshold[i] = j * 0.5\n",
    "        if s['timestep'] > 7:\n",
    "            for i,j in fiftyThreshold.items():\n",
    "                if spend[i] > 0 and fiftyThreshold[i] > 0:\n",
    "                    if spend[i] * fractionOfActualSpendInCIC >= fiftyThreshold[i]:\n",
    "                        spent = spend[i]\n",
    "                        amount = spent * redeemPercentage\n",
    "                        if network.nodes[i]['tokens'] > amount:\n",
    "                            withdraw[i] = amount\n",
    "                        elif  network.nodes[i]['tokens'] < amount:\n",
    "                            withdraw[i] = network.nodes[i]['tokens']\n",
    "                    else:\n",
    "                        pass\n",
    "                else:\n",
    "                    pass\n",
    "        else:\n",
    "            pass\n",
    "    else:\n",
    "        pass\n",
    "\n",
    "\n",
    "    return {'withdraw':withdraw}\n",
    "\n",
    "# Mechanisms \n",
    "def update_agent_activity(params,step,sL,s,_input):\n",
    "    '''\n",
    "    Update the network for interacting agent, their demand, and utility.\n",
    "    '''\n",
    "    y = 'network'\n",
    "    network = s['network']\n",
    "\n",
    "    outboundAgents = _input['outboundAgents']\n",
    "    inboundAgents = _input['inboundAgents']\n",
    "    stepDemands = _input['stepDemands']\n",
    "    stepUtilities = _input['stepUtilities']\n",
    "    \n",
    "    # create demand edge weights\n",
    "    try:\n",
    "        for i,j,l in zip(outboundAgents,inboundAgents,stepDemands):\n",
    "            network[i][j]['demand'] = l\n",
    "    except:\n",
    "        pass\n",
    "\n",
    "    # Create cic % edge weights\n",
    "    try:\n",
    "        for i,j in zip(outboundAgents,inboundAgents):\n",
    "            # if one of the agents is external, we will transact in 100% shilling\n",
    "            if i == 'external':\n",
    "                network[i][j]['fractionOfDemandInCIC'] = 1\n",
    "            elif j == 'external':\n",
    "                network[i][j]['fractionOfDemandInCIC'] = 1\n",
    "            else:\n",
    "                network[i][j]['fractionOfDemandInCIC'] = fractionOfDemandInCIC\n",
    "    except:\n",
    "        pass\n",
    "\n",
    "    # Create utility edge types\n",
    "    try: \n",
    "        for i,j,l in zip(outboundAgents,inboundAgents,stepUtilities):\n",
    "            network[i][j]['utility'] = l\n",
    "    except:\n",
    "        pass\n",
    "\n",
    "    x = network\n",
    "    return (y,x)\n",
    "\n",
    "\n",
    "def update_outboundAgents(params,step,sL,s,_input):\n",
    "    '''\n",
    "    Update outBoundAgents state variable\n",
    "    '''\n",
    "    y = 'outboundAgents'\n",
    "\n",
    "    x = _input['outboundAgents']\n",
    "\n",
    "    return (y,x)\n",
    "\n",
    "def update_inboundAgents(params,step,sL,s,_input):\n",
    "    '''\n",
    "    Update inBoundAgents state variable\n",
    "    '''\n",
    "    y = 'inboundAgents'\n",
    "\n",
    "    x = _input['inboundAgents']\n",
    "    return (y,x)\n",
    "\n",
    "\n",
    "def update_node_spend(params, step, sL, s,_input):\n",
    "    '''\n",
    "    Update network with actual spend of agents.\n",
    "    '''\n",
    "    y = 'network'\n",
    "    network = s['network']\n",
    "    \n",
    "    spendI = _input['spendI']\n",
    "    spendJ = _input['spendJ']\n",
    "    spendAmount = _input['spendAmount']\n",
    "\n",
    "    for i,j,l in zip(spendI,spendJ,spendAmount):   \n",
    "        network[i][j]['spend'] = l\n",
    "        if i == 'external':\n",
    "            network[i][j]['fractionOfActualSpendInCIC'] = 1\n",
    "        elif j == 'external':\n",
    "            network[i][j]['fractionOfActualSpendInCIC'] = 1\n",
    "        else:\n",
    "            network[i][j]['fractionOfActualSpendInCIC'] = fractionOfActualSpendInCIC\n",
    "\n",
    "    outflowSpend, inflowSpend = iterateEdges(network,'spend')\n",
    "\n",
    "    for i, j in inflowSpend.items():\n",
    "        if i == 'external':\n",
    "            network.nodes[i]['native_currency'] = network.nodes[i]['native_currency'] +  inflowSpend[i]\n",
    "        elif j == 'external':\n",
    "            network.nodes[i]['native_currency'] = network.nodes[i]['native_currency'] +  inflowSpend[i]\n",
    "        else:\n",
    "            network.nodes[i]['native_currency'] = network.nodes[i]['native_currency'] +  inflowSpend[i] * (1- fractionOfDemandInCIC)\n",
    "            network.nodes[i]['tokens'] = network.nodes[i]['tokens'] + (inflowSpend[i] * fractionOfDemandInCIC)\n",
    "        \n",
    "    for i, j in outflowSpend.items():\n",
    "        if i == 'external':\n",
    "            network.nodes[i]['native_currency'] = network.nodes[i]['native_currency'] - outflowSpend[i]\n",
    "        elif j == 'external':\n",
    "            network.nodes[i]['native_currency'] = network.nodes[i]['native_currency'] - outflowSpend[i]\n",
    "        else:\n",
    "            network.nodes[i]['native_currency'] = network.nodes[i]['native_currency'] - outflowSpend[i]* (1- fractionOfDemandInCIC)\n",
    "            network.nodes[i]['tokens'] = network.nodes[i]['tokens'] - (outflowSpend[i] * fractionOfDemandInCIC)\n",
    "\n",
    "    # Store the net of the inflow and outflow per step\n",
    "    network.nodes['external']['delta_native_currency'] = sum(inflowSpend.values()) - sum(outflowSpend.values())\n",
    "\n",
    "    x = network\n",
    "    return (y,x)\n",
    "\n",
    "\n",
    "def update_withdraw(params, step, sL, s,_input):\n",
    "    '''\n",
    "    Update flow sstate variable with the aggregated amount of shillings withdrawn\n",
    "    '''\n",
    "    y = 'withdraw'\n",
    "    x = s['withdraw']\n",
    "    if _input['withdraw']:\n",
    "        x = _input['withdraw']\n",
    "    else:\n",
    "        x = 0\n",
    "\n",
    "    return (y,x)\n",
    "\n",
    "def update_network_withraw(params, step, sL, s,_input):\n",
    "    '''\n",
    "    Update network for agents withdrawing \n",
    "    '''\n",
    "    y = 'network'\n",
    "    network = s['network']\n",
    "    withdraw = _input['withdraw']\n",
    "\n",
    "    if withdraw:\n",
    "        for i,j in withdraw.items():\n",
    "            # update agent nodes\n",
    "            network.nodes[i]['tokens'] = network.nodes[i]['tokens'] - j\n",
    "            network.nodes[i]['native_currency'] = network.nodes[i]['native_currency'] + (j * leverage)\n",
    "\n",
    "        withdrawnCICSum = []\n",
    "        for i,j in withdraw.items():\n",
    "            withdrawnCICSum.append(j)\n",
    "        \n",
    "        # update cic node\n",
    "        network.nodes['cic']['native_currency'] = network.nodes[i]['native_currency'] - (sum(withdrawnCICSum) * leverage)\n",
    "        network.nodes['cic']['tokens'] = network.nodes[i]['tokens'] + (sum(withdrawnCICSum) * leverage)\n",
    "\n",
    "    else:\n",
    "        pass\n",
    "    x = network\n",
    "    return (y,x)\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Operating Entity\n",
    "\n",
    "# Parameters\n",
    "FrequencyOfAllocation = 45 # every two weeks\n",
    "idealFiat = 5000\n",
    "idealCIC = 200000\n",
    "varianceCIC = 50000\n",
    "varianceFiat = 1000\n",
    "unadjustedPerAgent = 50\n",
    "\n",
    "\n",
    "\n",
    "\n",
    "agentAllocation = {'a':[1,1],'b':[1,1],'c':[1,1], # agent:[centrality,allocationValue]\n",
    "                   'd':[1,1],'e':[1,1],'f':[1,1],\n",
    "                   'g':[1,1],'h':[1,1],'i':[1,1],\n",
    "                   'j':[1,1],'k':[1,1],'l':[1,1],\n",
    "                   'm':[1,1],'o':[1,1],'p':[1,1]}\n",
    "\n",
    "# Behaviors\n",
    "def disbursement_to_agents(params, step, sL, s):\n",
    "    '''\n",
    "    Distribute every FrequencyOfAllocation days to agents based off of centrality allocation metric\n",
    "    '''\n",
    "    fiatBalance = s['operatorFiatBalance']\n",
    "    cicBalance = s['operatorCICBalance']\n",
    "    timestep = s['timestep']\n",
    "\n",
    "    division =  timestep % FrequencyOfAllocation  == 0\n",
    "\n",
    "    if division == True:\n",
    "        agentDistribution ={} # agent: amount distributed\n",
    "        for i,j in agentAllocation.items():\n",
    "            agentDistribution[i] = unadjustedPerAgent * agentAllocation[i][1]\n",
    "        distribute = 'Yes'\n",
    "        \n",
    "    else:\n",
    "        agentDistribution = 0\n",
    "        distribute = 'No'\n",
    "\n",
    "\n",
    "    return {'distribute':distribute,'amount':agentDistribution}\n",
    "\n",
    "\n",
    "def inventory_controller(params, step, sL, s):\n",
    "    '''\n",
    "    Monetary policy hysteresis conservation allocation between fiat and cic reserves.\n",
    "    \n",
    "    '''\n",
    "    fiatBalance = s['operatorFiatBalance']\n",
    "    cicBalance = s['operatorCICBalance']\n",
    "    timestep = s['timestep']\n",
    "    fundsInProcess = s['fundsInProcess']\n",
    "\n",
    "\n",
    "    updatedCIC = cicBalance\n",
    "    updatedFiat = fiatBalance\n",
    "\n",
    "    #decision,amt = mint_burn_logic_control(idealCIC,updatedCIC,variance,updatedFiat)\n",
    "    decision,amt = mint_burn_logic_control(idealCIC,updatedCIC,varianceCIC,updatedFiat,varianceFiat,idealFiat)\n",
    "\n",
    "    if decision == 'burn':\n",
    "        try:\n",
    "            deltaR, realized_price = withdraw(amt,updatedFiat,updatedCIC, V0, kappa)\n",
    "            # update state\n",
    "            # fiatBalance = fiatBalance - deltaR\n",
    "            # cicBalance = cicBalance - amt\n",
    "            fiatChange = abs(deltaR)\n",
    "            cicChange = amt\n",
    "\n",
    "        except:\n",
    "            print('Not enough to burn')\n",
    "\n",
    "            fiatChange = 0\n",
    "            cicChange = 0\n",
    "        \n",
    "    elif decision == 'mint':\n",
    "        try:\n",
    "            deltaS, realized_price = mint(amt,updatedFiat,updatedCIC, V0, kappa)\n",
    "            # update state\n",
    "            # fiatBalance = fiatBalance + amt\n",
    "            # cicBalance = cicBalance + deltaS\n",
    "            fiatChange = amt\n",
    "            cicChange = abs(deltaS)\n",
    "\n",
    "        except:\n",
    "            print('Not enough to mint')\n",
    "            fiatChange = 0\n",
    "            cicChange = 0\n",
    "\n",
    "    else:\n",
    "        fiatChange = 0\n",
    "        cicChange = 0\n",
    "        decision = 'none'\n",
    "        pass\n",
    "\n",
    "    if decision == 'mint':\n",
    "        fundsInProcess['timestep'].append(timestep + process_lag)\n",
    "        fundsInProcess['decision'].append(decision)\n",
    "        fundsInProcess['cic'].append(fiatChange)\n",
    "        fundsInProcess['shilling'].append(cicChange)\n",
    "    elif decision == 'burn':\n",
    "        fundsInProcess['timestep'].append(timestep +process_lag)\n",
    "        fundsInProcess['decision'].append(decision)\n",
    "        fundsInProcess['cic'].append(fiatChange)\n",
    "        fundsInProcess['shilling'].append(cicChange)\n",
    "    else:\n",
    "        pass\n",
    "    \n",
    "    return {'decision':decision,'fiatChange':fiatChange,'cicChange':cicChange,'fundsInProcess':fundsInProcess}\n",
    "\n",
    "\n",
    "\n",
    "# Mechanisms \n",
    "def update_agent_tokens(params,step,sL,s,_input):\n",
    "    '''\n",
    "    '''\n",
    "    y = 'network'\n",
    "    network = s['network']\n",
    "\n",
    "    distribute = _input['distribute']\n",
    "    amount = _input['amount']\n",
    "\n",
    "    if distribute == 'Yes':\n",
    "        for i in agents:\n",
    "            network.nodes[i]['tokens'] = network.nodes[i]['tokens'] + amount[i]\n",
    "    else:\n",
    "        pass\n",
    "\n",
    "    return (y,network)\n",
    "\n",
    "def update_operator_FromDisbursements(params,step,sL,s,_input):\n",
    "    '''\n",
    "    '''\n",
    "    y = 'operatorCICBalance'\n",
    "    x = s['operatorCICBalance']\n",
    "    timestep = s['timestep']\n",
    "    \n",
    "    distribute = _input['distribute']\n",
    "    amount = _input['amount'] \n",
    "\n",
    "    if distribute == 'Yes':\n",
    "        totalDistribution = []\n",
    "        for i,j in amount.items():\n",
    "            totalDistribution.append(j)\n",
    "        \n",
    "        totalDistribution = sum(totalDistribution)\n",
    "        x = x - totalDistribution\n",
    "\n",
    "    else:\n",
    "        pass\n",
    "\n",
    "    return (y,x)\n",
    "\n",
    "def update_totalDistributedToAgents(params,step,sL,s,_input):\n",
    "    '''\n",
    "    '''\n",
    "    y = 'totalDistributedToAgents'\n",
    "    x = s['totalDistributedToAgents']\n",
    "    timestep = s['timestep']\n",
    "    \n",
    "    distribute = _input['distribute']\n",
    "    amount = _input['amount'] \n",
    "\n",
    "    if distribute == 'Yes':\n",
    "        totalDistribution = []\n",
    "        for i,j in amount.items():\n",
    "            totalDistribution.append(j)\n",
    "        \n",
    "        totalDistribution = sum(totalDistribution)\n",
    "        x = x + totalDistribution\n",
    "    else:\n",
    "        pass\n",
    "\n",
    "    return (y,x)\n",
    "\n",
    "def update_operator_fiatBalance(params,step,sL,s,_input):\n",
    "    '''\n",
    "    '''\n",
    "    y = 'operatorFiatBalance'\n",
    "    x = s['operatorFiatBalance']\n",
    "    fundsInProcess = s['fundsInProcess']\n",
    "    timestep = s['timestep']\n",
    "    if _input['fiatChange']:\n",
    "        try:\n",
    "            if fundsInProcess['timestep'][0] == timestep + 1:\n",
    "                if fundsInProcess['decision'][0] == 'mint':\n",
    "                    x = x - abs(fundsInProcess['shilling'][0])\n",
    "                elif fundsInProcess['decision'][0] == 'burn':\n",
    "                    x = x + abs(fundsInProcess['shilling'][0])\n",
    "            else:\n",
    "                pass\n",
    "        except:\n",
    "            pass\n",
    "    else:\n",
    "        pass\n",
    "\n",
    "\n",
    "    return (y,x)\n",
    "\n",
    "def update_operator_cicBalance(params,step,sL,s,_input):\n",
    "    '''\n",
    "    '''\n",
    "    y = 'operatorCICBalance'\n",
    "    x = s['operatorCICBalance']\n",
    "    fundsInProcess = s['fundsInProcess']\n",
    "    timestep = s['timestep']\n",
    "\n",
    "    if _input['cicChange']:\n",
    "        try:\n",
    "            if fundsInProcess['timestep'][0] == timestep + 1:\n",
    "                if fundsInProcess['decision'][0] == 'mint':\n",
    "                    x = x + abs(fundsInProcess['cic'][0])\n",
    "                elif fundsInProcess['decision'][0] == 'burn':\n",
    "                    x = x - abs(fundsInProcess['cic'][0])\n",
    "            else:\n",
    "                pass\n",
    "        except:\n",
    "            pass\n",
    "    else:\n",
    "        pass\n",
    "\n",
    "    return (y,x)\n",
    "\n",
    "def update_totalMinted(params,step,sL,s,_input):\n",
    "    '''\n",
    "    '''\n",
    "    y = 'totalMinted'\n",
    "    x = s['totalMinted']\n",
    "    timestep = s['timestep']\n",
    "    try:\n",
    "        if _input['fundsInProcess']['decision'][0] == 'mint':\n",
    "            x = x + abs(_input['fundsInProcess']['cic'][0])\n",
    "        elif _input['fundsInProcess']['decision'][0] == 'burn':\n",
    "            pass\n",
    "    except:\n",
    "        pass\n",
    "\n",
    "\n",
    "    return (y,x)\n",
    "\n",
    "def update_totalBurned(params,step,sL,s,_input):\n",
    "    '''\n",
    "    '''\n",
    "    y = 'totalBurned'\n",
    "    x = s['totalBurned']\n",
    "    timestep = s['timestep']\n",
    "    try:\n",
    "        if _input['fundsInProcess']['decision'][0] == 'burn':\n",
    "            x = x + abs(_input['fundsInProcess']['cic'][0])\n",
    "        elif _input['fundsInProcess']['decision'][0] == 'mint':\n",
    "            pass\n",
    "    except:\n",
    "        pass\n",
    "\n",
    "    return (y,x)\n",
    "\n",
    "def update_fundsInProcess(params,step,sL,s,_input):\n",
    "    '''\n",
    "    '''\n",
    "    y = 'fundsInProcess'\n",
    "    x = _input['fundsInProcess']\n",
    "    timestep = s['timestep']\n",
    "\n",
    "    if _input['fundsInProcess']:\n",
    "        try:\n",
    "            if x['timestep'][0] == timestep:\n",
    "                del x['timestep'][0]\n",
    "                del x['decision'][0]\n",
    "                del x['cic'][0]\n",
    "                del x['shilling'][0]\n",
    "            else:\n",
    "                pass\n",
    "        except:\n",
    "            pass\n",
    "    else:\n",
    "        pass\n",
    "\n",
    "    return (y,x)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [],
   "source": [
    "# KPI\n",
    "\n",
    "# Behaviors\n",
    "def kpis(params, step, sL, s):\n",
    "    ''''''\n",
    "    # instantiate network state\n",
    "    network = s['network']\n",
    "\n",
    "    KPIDemand = {}\n",
    "    KPISpend = {}\n",
    "    KPISpendOverDemand = {}\n",
    "    for i in mixingAgents:\n",
    "        demand = []\n",
    "        for j in network.adj[i]:\n",
    "            try:\n",
    "                demand.append(network.adj[i][j]['demand'])\n",
    "            except:\n",
    "                pass\n",
    "\n",
    "        spend = []\n",
    "        for j in network.adj[i]:\n",
    "            try:\n",
    "                spend.append(network.adj[i][j]['spend'])\n",
    "            except:\n",
    "                pass\n",
    "\n",
    "        sumDemand = sum(demand)\n",
    "        sumSpend = sum(spend)\n",
    "        try:\n",
    "            spendOverDemand = sumSpend/sumDemand\n",
    "        except:\n",
    "            spendOverDemand = 0\n",
    "\n",
    "        KPIDemand[i] = sumDemand\n",
    "        KPISpend[i] = sumSpend\n",
    "        KPISpendOverDemand[i] = spendOverDemand\n",
    "\n",
    "    #print(nx.katz_centrality_numpy(G=network,weight='spend'))\n",
    "    return {'KPIDemand':KPIDemand,'KPISpend':KPISpend,'KPISpendOverDemand':KPISpendOverDemand}\n",
    "\n",
    "def velocity_of_money(params, step, sL, s):\n",
    "    ''''''\n",
    "    # instantiate network state\n",
    "    network = s['network']\n",
    "\n",
    "    KPISpend = s['KPISpend']\n",
    "\n",
    "    # TODO: Moving average for state variable\n",
    "    T = []\n",
    "    for i,j in KPISpend.items():\n",
    "        T.append(j)\n",
    "        \n",
    "    T = sum(T)\n",
    "    \n",
    "    # TODO Moving average for state variable \n",
    "    M = []\n",
    "    for i in agents:\n",
    "        M.append(network.nodes[i]['tokens'] + network.nodes[i]['native_currency'])\n",
    "        \n",
    "    M = sum(M)\n",
    "    \n",
    "    V_t = (priceLevel *T)/M\n",
    "\n",
    "    return {'V_t':V_t,'T':T,'M':M}\n",
    "\n",
    "\n",
    "# Mechanisms\n",
    "def update_KPIDemand(params, step, sL, s,_input):\n",
    "    y = 'KPIDemand'\n",
    "    x = _input['KPIDemand']\n",
    "    return (y,x)\n",
    "\n",
    "def update_KPISpend(params, step, sL, s,_input):\n",
    "    y = 'KPISpend'\n",
    "    x = _input['KPISpend']\n",
    "    return (y,x)\n",
    "\n",
    "def update_KPISpendOverDemand(params, step, sL, s,_input):\n",
    "    y = 'KPISpendOverDemand'\n",
    "    x = _input['KPISpendOverDemand']\n",
    "    return (y,x)\n",
    "\n",
    "\n",
    "def update_velocity_of_money(params, step, sL, s,_input):\n",
    "    y = 'VelocityOfMoney'\n",
    "    x = _input['V_t']\n",
    "    return (y,x)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [],
   "source": [
    "# partial state update block\n",
    "partial_state_update_block = {\n",
    "    # Exogenous\n",
    "    'Exogenous': {\n",
    "        'policies': {\n",
    "        },\n",
    "        'variables': {\n",
    "            'startingBalance': startingBalance,\n",
    "            'operatorFiatBalance': redCrossDrop,\n",
    "            '30_day_spend': update_30_day_spend,\n",
    "            'network':clear_agent_activity\n",
    "        }\n",
    "    },\n",
    "    # Users\n",
    "    'Behaviors': {\n",
    "        'policies': {\n",
    "            'action': choose_agents\n",
    "        },\n",
    "        'variables': {\n",
    "        'network': update_agent_activity,\n",
    "        'outboundAgents': update_outboundAgents,\n",
    "        'inboundAgents':update_inboundAgents\n",
    "        }\n",
    "    },\n",
    "    'Spend allocation': {\n",
    "        'policies': {\n",
    "            'action': spend_allocation\n",
    "        },\n",
    "        'variables': {\n",
    "        'network': update_node_spend\n",
    "        }\n",
    "    },\n",
    "    'Withdraw behavior': {\n",
    "        'policies': {\n",
    "            'action': withdraw_calculation\n",
    "        },\n",
    "        'variables': {\n",
    "        'withdraw': update_withdraw,\n",
    "        'network':update_network_withraw\n",
    "        }\n",
    "    },\n",
    "    # Operator\n",
    "    'Operator Disburse to Agents': {\n",
    "        'policies': {\n",
    "            'action': disbursement_to_agents\n",
    "        },\n",
    "        'variables': {\n",
    "        'network':update_agent_tokens,\n",
    "        'operatorCICBalance':update_operator_FromDisbursements,\n",
    "        'totalDistributedToAgents':update_totalDistributedToAgents\n",
    "        }\n",
    "    },\n",
    "    'Operator Inventory Control': {\n",
    "        'policies': {\n",
    "            'action': inventory_controller\n",
    "        },\n",
    "        'variables': {\n",
    "        'operatorFiatBalance':update_operator_fiatBalance,\n",
    "        'operatorCICBalance':update_operator_cicBalance, \n",
    "        'totalMinted': update_totalMinted,\n",
    "        'totalBurned':update_totalBurned,\n",
    "        'fundsInProcess':update_fundsInProcess\n",
    "        }\n",
    "    },\n",
    "    # KPIs\n",
    "    'KPIs': {\n",
    "        'policies': {\n",
    "            'action':kpis\n",
    "        },\n",
    "        'variables':{\n",
    "            'KPIDemand': update_KPIDemand,\n",
    "            'KPISpend': update_KPISpend,\n",
    "            'KPISpendOverDemand': update_KPISpendOverDemand        \n",
    "        }\n",
    "    },\n",
    "    'Velocity': {\n",
    "        'policies': {\n",
    "            'action':velocity_of_money\n",
    "        },\n",
    "        'variables':{\n",
    "\n",
    "            'VelocityOfMoney': update_velocity_of_money\n",
    "        }\n",
    "    }\n",
    "}\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[{'N': 5, 'T': range(0, 100), 'M': {'drip_frequency': 30}}, {'N': 5, 'T': range(0, 100), 'M': {'drip_frequency': 60}}, {'N': 5, 'T': range(0, 100), 'M': {'drip_frequency': 90}}]\n",
      "[{'N': 5, 'T': range(0, 100), 'M': {'drip_frequency': 30}}, {'N': 5, 'T': range(0, 100), 'M': {'drip_frequency': 60}}, {'N': 5, 'T': range(0, 100), 'M': {'drip_frequency': 90}}]\n",
      "[{'N': 5, 'T': range(0, 100), 'M': {'drip_frequency': 30}}, {'N': 5, 'T': range(0, 100), 'M': {'drip_frequency': 60}}, {'N': 5, 'T': range(0, 100), 'M': {'drip_frequency': 90}}]\n"
     ]
    }
   ],
   "source": [
    "# config\n",
    "params: Dict[str, List[int]] = {\n",
    "    'drip_frequency': [30,60,90] # in days\n",
    "}\n",
    "\n",
    "\n",
    "sim_config = config_sim({\n",
    "    'N': 5,\n",
    "    'T': range(100), #day \n",
    "    'M': params,\n",
    "})\n",
    "\n",
    "seeds = {\n",
    "    'p': np.random.RandomState(26042019),\n",
    "}\n",
    "env_processes = {}\n",
    "\n",
    "\n",
    "append_configs(\n",
    "    sim_configs=sim_config,\n",
    "    initial_state=genesis_states,\n",
    "    seeds=seeds,\n",
    "    env_processes=env_processes,\n",
    "    partial_state_update_blocks=partial_state_update_block\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Run cadCAD model"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [],
   "source": [
    "exec_mode = ExecutionMode()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "                            __________   ____ \n",
      "          ________ __ _____/ ____/   |  / __ \\\n",
      "         / ___/ __` / __  / /   / /| | / / / /\n",
      "        / /__/ /_/ / /_/ / /___/ ___ |/ /_/ / \n",
      "        \\___/\\__,_/\\__,_/\\____/_/  |_/_____/  \n",
      "        by BlockScience\n",
      "        \n",
      "Execution Mode: multi_proc: [<cadCAD.configuration.Configuration object at 0x7f54b92c5ad0>, <cadCAD.configuration.Configuration object at 0x7f54b92c5f90>, <cadCAD.configuration.Configuration object at 0x7f54b92c5850>]\n",
      "Configurations: [<cadCAD.configuration.Configuration object at 0x7f54b92c5ad0>, <cadCAD.configuration.Configuration object at 0x7f54b92c5f90>, <cadCAD.configuration.Configuration object at 0x7f54b92c5850>]\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "/home/aclarkdata/anaconda3/lib/python3.7/site-packages/cadCAD/utils/__init__.py:113: FutureWarning: The use of a dictionary to describe Partial State Update Blocks will be deprecated. Use a list instead.\n",
      "  FutureWarning)\n"
     ]
    }
   ],
   "source": [
    "exec_mode = ExecutionMode()\n",
    "multi_proc_ctx = ExecutionContext(context=exec_mode.multi_proc)\n",
    "run = Executor(exec_context=multi_proc_ctx, configs=configs)\n",
    "\n",
    "i = 0\n",
    "results = {}\n",
    "for raw_result, tensor_field in run.execute():\n",
    "    result = pd.DataFrame(raw_result)\n",
    "    results[i] = {}\n",
    "    results[i]['result'] = result\n",
    "    i += 1"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>network</th>\n",
       "      <th>KPIDemand</th>\n",
       "      <th>KPISpend</th>\n",
       "      <th>KPISpendOverDemand</th>\n",
       "      <th>VelocityOfMoney</th>\n",
       "      <th>startingBalance</th>\n",
       "      <th>30_day_spend</th>\n",
       "      <th>withdraw</th>\n",
       "      <th>outboundAgents</th>\n",
       "      <th>inboundAgents</th>\n",
       "      <th>operatorFiatBalance</th>\n",
       "      <th>operatorCICBalance</th>\n",
       "      <th>fundsInProcess</th>\n",
       "      <th>totalDistributedToAgents</th>\n",
       "      <th>totalMinted</th>\n",
       "      <th>totalBurned</th>\n",
       "      <th>run</th>\n",
       "      <th>substep</th>\n",
       "      <th>timestep</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>4000</th>\n",
       "      <td>(a, b, c, d, e, f, g, h, i, j, k, l, m, o, p, ...</td>\n",
       "      <td>{'a': 246, 'b': 0, 'c': 466, 'd': 620, 'e': 45...</td>\n",
       "      <td>{'a': 246, 'b': 0, 'c': 5.187631236062657, 'd'...</td>\n",
       "      <td>{'a': 1.0, 'b': 0, 'c': 0.011132255871379093, ...</td>\n",
       "      <td>9.77</td>\n",
       "      <td>{'a': 136.4003802092373, 'b': 848.068007320516...</td>\n",
       "      <td>{'a': 422.1992395815254, 'b': 3202.55026803101...</td>\n",
       "      <td>0</td>\n",
       "      <td>[f, h, c, o, f, k, a, p, d, o, h, g, k, a]</td>\n",
       "      <td>[e, f, f, f, k, h, i, external, b, external, g...</td>\n",
       "      <td>16500</td>\n",
       "      <td>198500.00</td>\n",
       "      <td>{'timestep': [], 'decision': [], 'cic': [], 's...</td>\n",
       "      <td>1500</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>5</td>\n",
       "      <td>4</td>\n",
       "      <td>100</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>4001</th>\n",
       "      <td>(a, b, c, d, e, f, g, h, i, j, k, l, m, o, p, ...</td>\n",
       "      <td>{'a': 246, 'b': 0, 'c': 466, 'd': 620, 'e': 45...</td>\n",
       "      <td>{'a': 246, 'b': 0, 'c': 5.187631236062657, 'd'...</td>\n",
       "      <td>{'a': 1.0, 'b': 0, 'c': 0.011132255871379093, ...</td>\n",
       "      <td>9.77</td>\n",
       "      <td>{'a': 136.4003802092373, 'b': 848.068007320516...</td>\n",
       "      <td>{'a': 422.1992395815254, 'b': 3202.55026803101...</td>\n",
       "      <td>0</td>\n",
       "      <td>[f, h, c, o, f, k, a, p, d, o, h, g, k, a]</td>\n",
       "      <td>[e, f, f, f, k, h, i, external, b, external, g...</td>\n",
       "      <td>16500</td>\n",
       "      <td>198500.00</td>\n",
       "      <td>{'timestep': [], 'decision': [], 'cic': [], 's...</td>\n",
       "      <td>1500</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>5</td>\n",
       "      <td>5</td>\n",
       "      <td>100</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>4002</th>\n",
       "      <td>(a, b, c, d, e, f, g, h, i, j, k, l, m, o, p, ...</td>\n",
       "      <td>{'a': 246, 'b': 0, 'c': 466, 'd': 620, 'e': 45...</td>\n",
       "      <td>{'a': 246, 'b': 0, 'c': 5.187631236062657, 'd'...</td>\n",
       "      <td>{'a': 1.0, 'b': 0, 'c': 0.011132255871379093, ...</td>\n",
       "      <td>9.77</td>\n",
       "      <td>{'a': 136.4003802092373, 'b': 848.068007320516...</td>\n",
       "      <td>{'a': 422.1992395815254, 'b': 3202.55026803101...</td>\n",
       "      <td>0</td>\n",
       "      <td>[f, h, c, o, f, k, a, p, d, o, h, g, k, a]</td>\n",
       "      <td>[e, f, f, f, k, h, i, external, b, external, g...</td>\n",
       "      <td>16500</td>\n",
       "      <td>198500.00</td>\n",
       "      <td>{'timestep': [], 'decision': [], 'cic': [], 's...</td>\n",
       "      <td>1500</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>5</td>\n",
       "      <td>6</td>\n",
       "      <td>100</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>4003</th>\n",
       "      <td>(a, b, c, d, e, f, g, h, i, j, k, l, m, o, p, ...</td>\n",
       "      <td>{'a': 346, 'b': 0, 'c': 431, 'd': 245, 'e': 0,...</td>\n",
       "      <td>{'a': 346, 'b': 0, 'c': 2.5938156180313285, 'd...</td>\n",
       "      <td>{'a': 1.0, 'b': 0, 'c': 0.0060181336845274444,...</td>\n",
       "      <td>9.77</td>\n",
       "      <td>{'a': 136.4003802092373, 'b': 848.068007320516...</td>\n",
       "      <td>{'a': 422.1992395815254, 'b': 3202.55026803101...</td>\n",
       "      <td>0</td>\n",
       "      <td>[f, h, c, o, f, k, a, p, d, o, h, g, k, a]</td>\n",
       "      <td>[e, f, f, f, k, h, i, external, b, external, g...</td>\n",
       "      <td>16500</td>\n",
       "      <td>198500.00</td>\n",
       "      <td>{'timestep': [], 'decision': [], 'cic': [], 's...</td>\n",
       "      <td>1500</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>5</td>\n",
       "      <td>7</td>\n",
       "      <td>100</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>4004</th>\n",
       "      <td>(a, b, c, d, e, f, g, h, i, j, k, l, m, o, p, ...</td>\n",
       "      <td>{'a': 346, 'b': 0, 'c': 431, 'd': 245, 'e': 0,...</td>\n",
       "      <td>{'a': 346, 'b': 0, 'c': 2.5938156180313285, 'd...</td>\n",
       "      <td>{'a': 1.0, 'b': 0, 'c': 0.0060181336845274444,...</td>\n",
       "      <td>20.19</td>\n",
       "      <td>{'a': 136.4003802092373, 'b': 848.068007320516...</td>\n",
       "      <td>{'a': 422.1992395815254, 'b': 3202.55026803101...</td>\n",
       "      <td>0</td>\n",
       "      <td>[f, h, c, o, f, k, a, p, d, o, h, g, k, a]</td>\n",
       "      <td>[e, f, f, f, k, h, i, external, b, external, g...</td>\n",
       "      <td>16500</td>\n",
       "      <td>198500.00</td>\n",
       "      <td>{'timestep': [], 'decision': [], 'cic': [], 's...</td>\n",
       "      <td>1500</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>5</td>\n",
       "      <td>8</td>\n",
       "      <td>100</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "                                                network  \\\n",
       "4000  (a, b, c, d, e, f, g, h, i, j, k, l, m, o, p, ...   \n",
       "4001  (a, b, c, d, e, f, g, h, i, j, k, l, m, o, p, ...   \n",
       "4002  (a, b, c, d, e, f, g, h, i, j, k, l, m, o, p, ...   \n",
       "4003  (a, b, c, d, e, f, g, h, i, j, k, l, m, o, p, ...   \n",
       "4004  (a, b, c, d, e, f, g, h, i, j, k, l, m, o, p, ...   \n",
       "\n",
       "                                              KPIDemand  \\\n",
       "4000  {'a': 246, 'b': 0, 'c': 466, 'd': 620, 'e': 45...   \n",
       "4001  {'a': 246, 'b': 0, 'c': 466, 'd': 620, 'e': 45...   \n",
       "4002  {'a': 246, 'b': 0, 'c': 466, 'd': 620, 'e': 45...   \n",
       "4003  {'a': 346, 'b': 0, 'c': 431, 'd': 245, 'e': 0,...   \n",
       "4004  {'a': 346, 'b': 0, 'c': 431, 'd': 245, 'e': 0,...   \n",
       "\n",
       "                                               KPISpend  \\\n",
       "4000  {'a': 246, 'b': 0, 'c': 5.187631236062657, 'd'...   \n",
       "4001  {'a': 246, 'b': 0, 'c': 5.187631236062657, 'd'...   \n",
       "4002  {'a': 246, 'b': 0, 'c': 5.187631236062657, 'd'...   \n",
       "4003  {'a': 346, 'b': 0, 'c': 2.5938156180313285, 'd...   \n",
       "4004  {'a': 346, 'b': 0, 'c': 2.5938156180313285, 'd...   \n",
       "\n",
       "                                     KPISpendOverDemand  VelocityOfMoney  \\\n",
       "4000  {'a': 1.0, 'b': 0, 'c': 0.011132255871379093, ...             9.77   \n",
       "4001  {'a': 1.0, 'b': 0, 'c': 0.011132255871379093, ...             9.77   \n",
       "4002  {'a': 1.0, 'b': 0, 'c': 0.011132255871379093, ...             9.77   \n",
       "4003  {'a': 1.0, 'b': 0, 'c': 0.0060181336845274444,...             9.77   \n",
       "4004  {'a': 1.0, 'b': 0, 'c': 0.0060181336845274444,...            20.19   \n",
       "\n",
       "                                        startingBalance  \\\n",
       "4000  {'a': 136.4003802092373, 'b': 848.068007320516...   \n",
       "4001  {'a': 136.4003802092373, 'b': 848.068007320516...   \n",
       "4002  {'a': 136.4003802092373, 'b': 848.068007320516...   \n",
       "4003  {'a': 136.4003802092373, 'b': 848.068007320516...   \n",
       "4004  {'a': 136.4003802092373, 'b': 848.068007320516...   \n",
       "\n",
       "                                           30_day_spend withdraw  \\\n",
       "4000  {'a': 422.1992395815254, 'b': 3202.55026803101...        0   \n",
       "4001  {'a': 422.1992395815254, 'b': 3202.55026803101...        0   \n",
       "4002  {'a': 422.1992395815254, 'b': 3202.55026803101...        0   \n",
       "4003  {'a': 422.1992395815254, 'b': 3202.55026803101...        0   \n",
       "4004  {'a': 422.1992395815254, 'b': 3202.55026803101...        0   \n",
       "\n",
       "                                  outboundAgents  \\\n",
       "4000  [f, h, c, o, f, k, a, p, d, o, h, g, k, a]   \n",
       "4001  [f, h, c, o, f, k, a, p, d, o, h, g, k, a]   \n",
       "4002  [f, h, c, o, f, k, a, p, d, o, h, g, k, a]   \n",
       "4003  [f, h, c, o, f, k, a, p, d, o, h, g, k, a]   \n",
       "4004  [f, h, c, o, f, k, a, p, d, o, h, g, k, a]   \n",
       "\n",
       "                                          inboundAgents  operatorFiatBalance  \\\n",
       "4000  [e, f, f, f, k, h, i, external, b, external, g...                16500   \n",
       "4001  [e, f, f, f, k, h, i, external, b, external, g...                16500   \n",
       "4002  [e, f, f, f, k, h, i, external, b, external, g...                16500   \n",
       "4003  [e, f, f, f, k, h, i, external, b, external, g...                16500   \n",
       "4004  [e, f, f, f, k, h, i, external, b, external, g...                16500   \n",
       "\n",
       "      operatorCICBalance                                     fundsInProcess  \\\n",
       "4000           198500.00  {'timestep': [], 'decision': [], 'cic': [], 's...   \n",
       "4001           198500.00  {'timestep': [], 'decision': [], 'cic': [], 's...   \n",
       "4002           198500.00  {'timestep': [], 'decision': [], 'cic': [], 's...   \n",
       "4003           198500.00  {'timestep': [], 'decision': [], 'cic': [], 's...   \n",
       "4004           198500.00  {'timestep': [], 'decision': [], 'cic': [], 's...   \n",
       "\n",
       "      totalDistributedToAgents  totalMinted  totalBurned  run  substep  \\\n",
       "4000                      1500            0            0    5        4   \n",
       "4001                      1500            0            0    5        5   \n",
       "4002                      1500            0            0    5        6   \n",
       "4003                      1500            0            0    5        7   \n",
       "4004                      1500            0            0    5        8   \n",
       "\n",
       "      timestep  \n",
       "4000       100  \n",
       "4001       100  \n",
       "4002       100  \n",
       "4003       100  \n",
       "4004       100  "
      ]
     },
     "execution_count": 14,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "results[0]['result'].tail()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [],
   "source": [
    "for i in range(0,len(results)):\n",
    "    results[i]['result']['agents'] = results[i]['result'].network.apply(lambda g: np.array([get_nodes_by_type(g,'Agent')][0]))\n",
    "    results[i]['result']['agent_tokens'] = results[i]['result'].network.apply(lambda g: np.array([g.nodes[j]['tokens'] for j in get_nodes_by_type(g,'Agent')]))\n",
    "    results[i]['result']['agent_native_currency'] = results[i]['result'].network.apply(lambda g: np.array([g.nodes[j]['native_currency'] for j in get_nodes_by_type(g,'Agent')]))\n",
    "    # Create dataframe variables   \n",
    "    tokens = []\n",
    "    for j in results[i]['result'].index:\n",
    "         tokens.append(sum(results[i]['result']['agent_tokens'][j]))\n",
    "\n",
    "    results[i]['result']['AggregatedAgentCICHolding'] = tokens  \n",
    "\n",
    "    currency = []\n",
    "    for j in results[i]['result'].index:\n",
    "         currency.append(sum(results[i]['result']['agent_native_currency'][j]))\n",
    "\n",
    "    results[i]['result']['AggregatedAgentCurrencyHolding'] = currency  \n",
    "\n",
    "    AggregatedSpend = []\n",
    "    for j in results[i]['result'].index:\n",
    "         AggregatedSpend.append(sum(results[i]['result']['KPISpend'][j].values()))\n",
    "\n",
    "    results[i]['result']['AggregatedAgentSpend'] = AggregatedSpend   \n",
    "\n",
    "    AggregatedDemand = []\n",
    "    for j in results[i]['result'].index:\n",
    "         AggregatedDemand.append(sum(results[i]['result']['KPIDemand'][j].values()))\n",
    "\n",
    "    results[i]['result']['AggregatedAgentDemand'] = AggregatedDemand  \n",
    "\n",
    "\n",
    "    AggregatedKPISpendOverDemand = []\n",
    "    for j in results[i]['result'].index:\n",
    "         AggregatedKPISpendOverDemand.append(sum(results[i]['result']['KPISpendOverDemand'][j].values()))\n",
    "\n",
    "    results[i]['result']['AggregatedKPISpendOverDemand'] = AggregatedKPISpendOverDemand  \n",
    "\n",
    "\n",
    "    AggregatedGapOfDemandMinusSpend = []\n",
    "    for j in results[i]['result'].index:\n",
    "         AggregatedGapOfDemandMinusSpend.append(sum(results[i]['result']['KPIDemand'][j].values())- sum(results[i]['result']['KPISpend'][j].values()))\n",
    "\n",
    "    results[i]['result']['AggregatedGapOfDemandMinusSpend'] = AggregatedGapOfDemandMinusSpend  "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>timestep</th>\n",
       "      <th>VelocityOfMoney</th>\n",
       "      <th>operatorFiatBalance</th>\n",
       "      <th>operatorCICBalance</th>\n",
       "      <th>totalDistributedToAgents</th>\n",
       "      <th>totalMinted</th>\n",
       "      <th>totalBurned</th>\n",
       "      <th>run</th>\n",
       "      <th>substep</th>\n",
       "      <th>AggregatedAgentCICHolding</th>\n",
       "      <th>AggregatedAgentCurrencyHolding</th>\n",
       "      <th>AggregatedAgentSpend</th>\n",
       "      <th>AggregatedAgentDemand</th>\n",
       "      <th>AggregatedKPISpendOverDemand</th>\n",
       "      <th>AggregatedGapOfDemandMinusSpend</th>\n",
       "      <th>Red Cross Drip Frequency</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>1</td>\n",
       "      <td>14.04</td>\n",
       "      <td>4500</td>\n",
       "      <td>200000.00</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>3</td>\n",
       "      <td>8</td>\n",
       "      <td>6000.00</td>\n",
       "      <td>2912.00</td>\n",
       "      <td>1255.25</td>\n",
       "      <td>2534</td>\n",
       "      <td>4.96</td>\n",
       "      <td>1325.00</td>\n",
       "      <td>30</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>2</td>\n",
       "      <td>18.48</td>\n",
       "      <td>4500</td>\n",
       "      <td>200000.00</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>3</td>\n",
       "      <td>8</td>\n",
       "      <td>6040.00</td>\n",
       "      <td>2952.00</td>\n",
       "      <td>1693.62</td>\n",
       "      <td>3370</td>\n",
       "      <td>5.59</td>\n",
       "      <td>1292.75</td>\n",
       "      <td>30</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>3</td>\n",
       "      <td>16.27</td>\n",
       "      <td>4500</td>\n",
       "      <td>200000.00</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>3</td>\n",
       "      <td>8</td>\n",
       "      <td>6049.50</td>\n",
       "      <td>2961.50</td>\n",
       "      <td>1466.34</td>\n",
       "      <td>2441</td>\n",
       "      <td>5.46</td>\n",
       "      <td>381.50</td>\n",
       "      <td>30</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3</th>\n",
       "      <td>4</td>\n",
       "      <td>18.75</td>\n",
       "      <td>4500</td>\n",
       "      <td>200000.00</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>3</td>\n",
       "      <td>8</td>\n",
       "      <td>6124.94</td>\n",
       "      <td>3036.94</td>\n",
       "      <td>1672.00</td>\n",
       "      <td>2867</td>\n",
       "      <td>6.48</td>\n",
       "      <td>1195.00</td>\n",
       "      <td>30</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>4</th>\n",
       "      <td>5</td>\n",
       "      <td>15.17</td>\n",
       "      <td>4500</td>\n",
       "      <td>200000.00</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>3</td>\n",
       "      <td>8</td>\n",
       "      <td>6385.50</td>\n",
       "      <td>3297.50</td>\n",
       "      <td>1568.00</td>\n",
       "      <td>1914</td>\n",
       "      <td>5.49</td>\n",
       "      <td>734.89</td>\n",
       "      <td>30</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "   timestep  VelocityOfMoney  operatorFiatBalance  operatorCICBalance  \\\n",
       "0         1            14.04                 4500           200000.00   \n",
       "1         2            18.48                 4500           200000.00   \n",
       "2         3            16.27                 4500           200000.00   \n",
       "3         4            18.75                 4500           200000.00   \n",
       "4         5            15.17                 4500           200000.00   \n",
       "\n",
       "   totalDistributedToAgents  totalMinted  totalBurned  run  substep  \\\n",
       "0                         0            0            0    3        8   \n",
       "1                         0            0            0    3        8   \n",
       "2                         0            0            0    3        8   \n",
       "3                         0            0            0    3        8   \n",
       "4                         0            0            0    3        8   \n",
       "\n",
       "   AggregatedAgentCICHolding  AggregatedAgentCurrencyHolding  \\\n",
       "0                    6000.00                         2912.00   \n",
       "1                    6040.00                         2952.00   \n",
       "2                    6049.50                         2961.50   \n",
       "3                    6124.94                         3036.94   \n",
       "4                    6385.50                         3297.50   \n",
       "\n",
       "   AggregatedAgentSpend  AggregatedAgentDemand  AggregatedKPISpendOverDemand  \\\n",
       "0               1255.25                   2534                          4.96   \n",
       "1               1693.62                   3370                          5.59   \n",
       "2               1466.34                   2441                          5.46   \n",
       "3               1672.00                   2867                          6.48   \n",
       "4               1568.00                   1914                          5.49   \n",
       "\n",
       "   AggregatedGapOfDemandMinusSpend  Red Cross Drip Frequency  \n",
       "0                          1325.00                        30  \n",
       "1                          1292.75                        30  \n",
       "2                           381.50                        30  \n",
       "3                          1195.00                        30  \n",
       "4                           734.89                        30  "
      ]
     },
     "execution_count": 16,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "params = [30,60,90]\n",
    "swept = 'Red Cross Drip Frequency'\n",
    "mean_df,median_df = param_dfs(results,params,swept)\n",
    "median_df.head()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 51056 characters]\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "# plot of agent activity per timestep\n",
    "param_plot(median_df,'timestep', 'AggregatedAgentSpend',swept)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 46556 characters]\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "param_plot(median_df,'timestep', 'VelocityOfMoney',swept)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 22672 characters]\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "param_plot(median_df,'timestep', 'operatorCICBalance',swept)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 27828 characters]\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "param_plot(median_df,'timestep', 'operatorFiatBalance',swept)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 36896 characters]\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "param_plot(median_df,'timestep', 'AggregatedAgentCICHolding',swept)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 38712 characters]\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "param_plot(median_df,'timestep', 'AggregatedAgentCurrencyHolding',swept)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 52960 characters]\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "param_plot(median_df,'timestep', 'AggregatedAgentDemand',swept)"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.5"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
