{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "from cadCAD.engine import ExecutionMode, ExecutionContext, Executor\n",
    "from cadCAD.configuration import Configuration\n",
    "import networkx as nx\n",
    "import matplotlib.pyplot as plt\n",
    "import numpy as np\n",
    "import scipy.stats as sts\n",
    "import pandas as pd\n",
    "import seaborn as sns\n",
    "import matplotlib.colors as colors\n",
    "import matplotlib.cm as cmx\n",
    "\n",
    "%matplotlib inline\n",
    "\n",
    "#import conviction files\n",
    "from conviction_helpers import *\n",
    "from conviction_system_logic import *"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "This notebook uses the differential games framework developed by BlockScience. It is currently in private beta, and building towards a full open source release.\n",
    "\n",
    "**Description:**\n",
    "\n",
    "cadCAD is a Python library that assists in the processes of designing, testing and validating complex systems through simulation. At its core, cadCAD is a differential games engine that supports parameter sweeping and Monte Carlo analyses and can be easily integrated with other scientific computing Python modules and data science workflows.\n",
    "\n",
    "To learn more about cadCAD, follow our [tutorial series](../../tutorials)\n",
    "\n",
    "**Installing cadCAD:**\n",
    "\n",
    "cadCAD is in private beta. Tokens are issued to participants. Replace `<TOKEN>` in the installation URL below\n",
    "```bash\n",
    "pip3 install cadCAD --extra-index-url https://<TOKEN>@repo.fury.io/blockscience/\n",
    "```\n",
    "\n",
    "If you'd like to participate in the beta program, contact cadcad [at] block [dot] science.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "#THIS policy is one of the main paramters of this system!\n",
    "\n",
    "#maximum share of funds a proposal can take\n",
    "default_beta = .2 #later we should set this to be param so we can sweep it\n",
    "# tuning param for the trigger function\n",
    "default_rho = default_beta**2\n",
    "\n",
    "def trigger_threshold(requested, funds, supply, beta=default_beta , rho=default_rho):\n",
    "    \n",
    "    share = requested/funds\n",
    "    if share < beta:\n",
    "        return rho*supply/(beta-share)**2\n",
    "    else: \n",
    "        return np.inf"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "/Users/Zargham/Documents/GitHub/conviction/conviction_helpers.py:96: RuntimeWarning: divide by zero encountered in log10\n",
      "  demo_data_Z0[sof_ind,ts_ind] = np.log10(trigger)\n",
      "/Users/Zargham/Documents/GitHub/conviction/conviction_helpers.py:98: RuntimeWarning: invalid value encountered in double_scalars\n",
      "  demo_data_Z2[sof_ind,ts_ind] = trigger/tc #share of maximum possible conviction\n",
      "/Users/Zargham/Documents/GitHub/conviction/conviction_helpers.py:99: RuntimeWarning: invalid value encountered in double_scalars\n",
      "  demo_data_Z3[sof_ind,ts_ind] = np.log10(trigger/tc)\n"
     ]
    }
   ],
   "source": [
    "dict1 = trigger_sweep('token_supply',trigger_threshold)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Text(0.15940000000000001, 1008990000.0, 'fixed alpha = 0.5')"
      ]
     },
     "execution_count": 4,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "image/png": "[encoded data, 34028 characters]\n",
      "text/plain": [
       "<Figure size 720x360 with 2 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "trigger_plotter(dict1['share_of_funds'],\n",
    "                dict1['log10_trigger'], \n",
    "                'log10_trigger',\n",
    "                dict1['total_supply'],\n",
    "                'Token Supply')\n",
    "axis = plt.axis()\n",
    "plt.text(.2*axis[0]+.8*axis[1],axis[-1]*1.01, 'fixed alpha = 0.5')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [],
   "source": [
    "dict2 = trigger_sweep('alpha',trigger_threshold)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "dict_keys(['log10_trigger', 'trigger', 'share_of_max_conv', 'log10_share_of_max_conv', 'alpha', 'share_of_funds'])"
      ]
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "dict2.keys()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 31012 characters]\n",
      "text/plain": [
       "<Figure size 720x360 with 2 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "trigger_plotter(dict2['share_of_funds'],\n",
    "                dict2['log10_share_of_max_conv'], \n",
    "                'Log10 Share of Conviction Required to Pass',\n",
    "                dict2['alpha'],\n",
    "                'alpha')\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [],
   "source": [
    "n= 25 #initial participants\n",
    "m= 3 #initial proposals\n",
    "\n",
    "initial_sentiment = .5\n",
    "\n",
    "network, initial_funds, initial_supply, total_requested = initialize_network(n,m,total_funds_given_total_supply,trigger_threshold)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Note from Kris, consider: substitutibility of proposals st when a substitute passes, affinity for the others goes away; this will make the process more realistic because proposals will end up never passing.\n",
    "\n",
    "implementation notes:\n",
    "- create substitutability matrix (proposal x proposal)\n",
    "- update accounting when thing pass: change affinities and should affect sentiments\n",
    "- define a new 'type' of proposals for tracking 'dead' ones (no longer candidates = zero tokens in support)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [],
   "source": [
    "proposals = get_nodes_by_type(network, 'proposal')\n",
    "participants = get_nodes_by_type(network, 'participant')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{'type': 'proposal',\n",
       " 'conviction': 0,\n",
       " 'status': 'candidate',\n",
       " 'age': 0,\n",
       " 'funds_requested': 63248.8961832528,\n",
       " 'trigger': inf}"
      ]
     },
     "execution_count": 10,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "#sample proposal\n",
    "network.nodes[proposals[0]]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{'type': 'participant',\n",
       " 'holdings': 753.5821088000997,\n",
       " 'sentiment': 0.20260793282468248}"
      ]
     },
     "execution_count": 11,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "#sample participant\n",
    "network.nodes[participants[0]]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{'affinity': 0.13023927236764288, 'tokens': 0, 'conviction': 0}"
      ]
     },
     "execution_count": 12,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "#sample relationship participant to proposal\n",
    "network.edges[(participants[0],proposals[0])]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Explore the data created in initial conditions!"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Text(0.5, 1.0, 'Histogram of Participants Token Holdings')"
      ]
     },
     "execution_count": 13,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "image/png": "[encoded data, 8232 characters]\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "plt.hist([ network.nodes[i]['holdings'] for i in participants])\n",
    "plt.title('Histogram of Participants Token Holdings')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Text(0.5, 1.0, 'Histogram of Proposals Funds Requested')"
      ]
     },
     "execution_count": 14,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "image/png": "[encoded data, 10116 characters]\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "plt.hist([ network.nodes[i]['funds_requested'] for i in proposals])\n",
    "plt.title('Histogram of Proposals Funds Requested')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Text(0.5, 1.0, 'Histogram of Affinities between Participants and Proposals')"
      ]
     },
     "execution_count": 15,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "image/png": "[encoded data, 10416 characters]\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "plt.hist([ network.edges[e]['affinity'] for e in network.edges])\n",
    "plt.title('Histogram of Affinities between Participants and Proposals')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Text(0.5, 1.0, 'Histogram of Affinities between Participants and Proposals weighted by holdings')"
      ]
     },
     "execution_count": 16,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "image/png": "[encoded data, 12340 characters]\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "plt.hist([ network.edges[e]['affinity'] for e in network.edges], weights = [network.nodes[e[0]]['holdings']for e in network.edges],alpha = 1)\n",
    "plt.title('Histogram of Affinities between Participants and Proposals weighted by holdings')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {},
   "outputs": [],
   "source": [
    "affinities = np.empty((n,m))\n",
    "for i_ind in range(n):\n",
    "    for j_ind in range(m):\n",
    "        i = participants[i_ind]\n",
    "        j = proposals[j_ind]\n",
    "        affinities[i_ind][j_ind] = network.edges[(i,j)]['affinity']"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Text(0.5, 106.33200000000001, 'participant_id')"
      ]
     },
     "execution_count": 18,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "image/png": "[encoded data, 16596 characters]\n",
      "text/plain": [
       "<Figure size 1440x360 with 2 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "dims = (20, 5)\n",
    "fig, ax = plt.subplots(figsize=dims)\n",
    "\n",
    "sns.heatmap(affinities.T,\n",
    "            xticklabels=participants,\n",
    "            yticklabels=proposals,\n",
    "            square=True,\n",
    "            cbar=True,\n",
    "            ax=ax)\n",
    "\n",
    "plt.title('affinities between participants and proposals')\n",
    "plt.ylabel('proposal_id')\n",
    "plt.xlabel('participant_id')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[0.5]\n"
     ]
    }
   ],
   "source": [
    "#power of 1 token forever\n",
    "conviction_capactity = [2]\n",
    "alpha = [1-1/cc for cc in conviction_capactity]\n",
    "print(alpha)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {},
   "outputs": [],
   "source": [
    "params= {\n",
    "    'sensitivity': [.75],\n",
    "    'tmin': [7], #unit days; minimum periods passed before a proposal can pass\n",
    "    'sentiment_decay': [.001], #termed mu in the state update function\n",
    "    'alpha': alpha,\n",
    "    'base_completion_rate': [10],\n",
    "    'trigger_func': [trigger_threshold]\n",
    "    }"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 28,
   "metadata": {},
   "outputs": [],
   "source": [
    "# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # \n",
    "# Settings of general simulation parameters, unrelated to the system itself\n",
    "# `T` is a range with the number of discrete units of time the simulation will run for;\n",
    "# `N` is the number of times the simulation will be run (Monte Carlo runs)\n",
    "time_periods_per_run = 250\n",
    "monte_carlo_runs = 1\n",
    "\n",
    "simulation_parameters = {\n",
    "    'T': range(time_periods_per_run),\n",
    "    'N': monte_carlo_runs,\n",
    "    'M': params\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 29,
   "metadata": {},
   "outputs": [],
   "source": [
    "initial_conditions = {'network':network,\n",
    "                      'supply': initial_supply,\n",
    "                      'funds':initial_funds,\n",
    "                      'sentiment': initial_sentiment}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#functions for partial state update block 1\n",
    "\n",
    "def gen_new_participant(network, new_participant_holdings):\n",
    "    \n",
    "    i = len([node for node in network.nodes])\n",
    "    \n",
    "    network.add_node(i)\n",
    "    network.nodes[i]['type']=\"participant\"\n",
    "    \n",
    "    s_rv = np.random.rand() \n",
    "    network.nodes[i]['sentiment'] = s_rv\n",
    "    network.nodes[i]['holdings']=new_participant_holdings\n",
    "    \n",
    "    for j in get_nodes_by_type(network, 'proposal'):\n",
    "        network.add_edge(i, j)\n",
    "        \n",
    "        rv = np.random.rand()\n",
    "        a_rv = 1-4*(1-rv)*rv #polarized distribution\n",
    "        network.edges[(i, j)]['affinity'] = a_rv\n",
    "        network.edges[(i,j)]['tokens'] = a_rv*network.nodes[i]['holdings']\n",
    "        network.edges[(i, j)]['conviction'] = 0\n",
    "    \n",
    "    return network\n",
    "    \n",
    "\n",
    "def gen_new_proposal(network, funds, supply):\n",
    "    j = len([node for node in network.nodes])\n",
    "    network.add_node(j)\n",
    "    network.nodes[j]['type']=\"proposal\"\n",
    "    \n",
    "    network.nodes[j]['conviction']=0\n",
    "    network.nodes[j]['status']='candidate'\n",
    "    network.nodes[j]['age']=0\n",
    "    \n",
    "    rescale = 10000*funds/initial_funds\n",
    "    r_rv = gamma.rvs(3,loc=0.001, scale=rescale)\n",
    "    network.node[j]['funds_requested'] = r_rv\n",
    "    \n",
    "    network.nodes[j]['trigger']= trigger_threshold(r_rv, funds, supply)\n",
    "    \n",
    "    participants = get_nodes_by_type(network, 'participant')\n",
    "    proposing_participant = np.random.choice(participants)\n",
    "    \n",
    "    for i in participants:\n",
    "        network.add_edge(i, j)\n",
    "        if i==proposing_participant:\n",
    "            network.edges[(i, j)]['affinity']=1\n",
    "        else:\n",
    "            rv = np.random.rand()\n",
    "            a_rv = 1-4*(1-rv)*rv #polarized distribution\n",
    "            network.edges[(i, j)]['affinity'] = a_rv\n",
    "            \n",
    "        network.edges[(i, j)]['conviction'] = 0\n",
    "        network.edges[(i,j)]['tokens'] = 0\n",
    "    return network\n",
    "        \n",
    "        \n",
    "\n",
    "def driving_process(params, step, sL, s):\n",
    "    \n",
    "    #placeholder plumbing for random processes\n",
    "    arrival_rate = 10/s['sentiment']\n",
    "    rv1 = np.random.rand()\n",
    "    new_participant = bool(rv1<1/arrival_rate)\n",
    "    if new_participant:\n",
    "        h_rv = expon.rvs(loc=0.0, scale=1000)\n",
    "        new_participant_holdings = h_rv\n",
    "    else:\n",
    "        new_participant_holdings = 0\n",
    "    \n",
    "    network = s['network']\n",
    "    affinities = [network.edges[e]['affinity'] for e in network.edges ]\n",
    "    median_affinity = np.median(affinities)\n",
    "    \n",
    "    proposals = get_nodes_by_type(network, 'proposal')\n",
    "    fund_requests = [network.nodes[j]['funds_requested'] for j in proposals if network.nodes[j]['status']=='candidate' ]\n",
    "    \n",
    "    funds = s['funds']\n",
    "    total_funds_requested = np.sum(fund_requests)\n",
    "    \n",
    "    proposal_rate = 10/median_affinity * total_funds_requested/funds\n",
    "    rv2 = np.random.rand()\n",
    "    new_proposal = bool(rv2<1/proposal_rate)\n",
    "    \n",
    "    sentiment = s['sentiment']\n",
    "    funds = s['funds']\n",
    "    scale_factor = 1+4000*sentiment**2\n",
    "    \n",
    "    #this shouldn't happen but expon is throwing domain errors\n",
    "    if scale_factor > 1: \n",
    "        funds_arrival = expon.rvs(loc = 0, scale = scale_factor )\n",
    "    else:\n",
    "        funds_arrival = 0\n",
    "    \n",
    "    return({'new_participant':new_participant,\n",
    "            'new_participant_holdings':new_participant_holdings,\n",
    "            'new_proposal':new_proposal, \n",
    "            'funds_arrival':funds_arrival})\n",
    "\n",
    "def update_network(params, step, sL, s, _input):\n",
    "    \n",
    "    network = s['network']\n",
    "    funds = s['funds']\n",
    "    supply = s['supply']\n",
    "    #placeholder plumbing for new proposals and new participants\n",
    "    new_participant = _input['new_participant'] #T/F\n",
    "    new_proposal = _input['new_proposal'] #T/F\n",
    "    # IF THEN logic to create new nodes // left out for now since always FALSE\n",
    "    if new_participant:\n",
    "        new_participant_holdings = _input['new_participant_holdings']\n",
    "        network = gen_new_participant(network, new_participant_holdings)\n",
    "    \n",
    "    if new_proposal:\n",
    "        network= gen_new_proposal(network,funds,supply )\n",
    "    \n",
    "    #update age of the existing proposals\n",
    "    proposals = get_nodes_by_type(network, 'proposal')\n",
    "    \n",
    "    for j in proposals:\n",
    "        network.nodes[j]['age'] =  network.nodes[j]['age']+1\n",
    "        if network.nodes[j]['status'] == 'candidate':\n",
    "            requested = network.nodes[j]['funds_requested']\n",
    "            network.nodes[j]['trigger'] = trigger_threshold(requested, funds, supply)\n",
    "        else:\n",
    "            network.nodes[j]['trigger'] = np.nan\n",
    "            \n",
    "    key = 'network'\n",
    "    value = network\n",
    "    \n",
    "    return (key, value)\n",
    "\n",
    "def increment_funds(params, step, sL, s, _input):\n",
    "    \n",
    "    funds = s['funds']\n",
    "    funds_arrival = _input['funds_arrival']\n",
    "\n",
    "    #increment funds\n",
    "    funds = funds + funds_arrival\n",
    "    \n",
    "    key = 'funds'\n",
    "    value = funds\n",
    "    \n",
    "    return (key, value)\n",
    "\n",
    "def increment_supply(params, step, sL, s, _input):\n",
    "    \n",
    "    supply = s['supply']\n",
    "    supply_arrival = _input['new_participant_holdings']\n",
    "\n",
    "    #increment funds\n",
    "    supply = supply + supply_arrival\n",
    "    \n",
    "    key = 'supply'\n",
    "    value = supply\n",
    "    \n",
    "    return (key, value)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#partial state update block 2\n",
    "def check_progress(params, step, sL, s):\n",
    "    \n",
    "    network = s['network']\n",
    "    proposals = get_nodes_by_type(network, 'proposal')\n",
    "    \n",
    "    completed = []\n",
    "    for j in proposals:\n",
    "        if network.nodes[j]['status'] == 'active':\n",
    "            grant_size = network.nodes[j]['funds_requested']\n",
    "            likelihood = 1.0/(min_completion_rate+np.log(grant_size))\n",
    "            if np.random.rand() < likelihood:\n",
    "                completed.append(j)\n",
    "    \n",
    "    return({'completed':completed})\n",
    "\n",
    "def complete_proposal(params, step, sL, s, _input):\n",
    "    \n",
    "    network = s['network']\n",
    "    participants = get_nodes_by_type(network, 'participant')\n",
    "    \n",
    "    completed = _input['completed']\n",
    "    for j in completed:\n",
    "        network.nodes[j]['status']='completed'\n",
    "        for i in participants:\n",
    "            force = network.edges[(i,j)]['affinity']\n",
    "            sentiment = network.node[i]['sentiment']\n",
    "            network.node[i]['sentiment'] = get_sentimental(sentiment, force, decay=False)\n",
    "    \n",
    "    key = 'network'\n",
    "    value = network\n",
    "    \n",
    "    return (key, value)\n",
    "\n",
    "def update_sentiment_on_completion(params, step, sL, s, _input):\n",
    "    \n",
    "    network = s['network']\n",
    "    proposals = get_nodes_by_type(network, 'proposal')\n",
    "    completed = _input['completed']\n",
    "    \n",
    "    grants_outstanding = np.sum([network.nodes[j]['funds_requested'] for j in proposals if network.nodes[j]['status']=='active'])\n",
    "    \n",
    "    grants_completed = np.sum([network.nodes[j]['funds_requested'] for j in completed])\n",
    "    \n",
    "    sentiment = s['sentiment']\n",
    "    \n",
    "    force = grants_completed/grants_outstanding\n",
    "    if (force >=0) and (force <=1):\n",
    "        sentiment = get_sentimental(sentiment, force, True)\n",
    "    else:\n",
    "        sentiment = get_sentimental(sentiment, 0, True)\n",
    "    \n",
    "    \n",
    "    key = 'sentiment'\n",
    "    value = sentiment\n",
    "    \n",
    "    return (key, value)\n",
    "\n",
    "def get_sentimental(sentiment, force, decay=True):\n",
    "    sentiment = sentiment*(1-int(decay)*mu) + force\n",
    "    \n",
    "    if sentiment > 1:\n",
    "        sentiment = 1\n",
    "        \n",
    "    return sentiment"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#partial state update block 3\n",
    "def trigger_function(params, step, sL, s):\n",
    "    \n",
    "    network = s['network']\n",
    "    funds = s['funds']\n",
    "    supply = s['supply']\n",
    "    proposals = get_nodes_by_type(network, 'proposal')\n",
    "    \n",
    "    accepted = []\n",
    "    triggers = {}\n",
    "    for j in proposals:\n",
    "        if network.nodes[j]['status'] == 'candidate':\n",
    "            requested = network.nodes[j]['funds_requested']\n",
    "            age = network.nodes[j]['age']\n",
    "            threshold = trigger_threshold(requested, funds, supply)\n",
    "            if age > tmin:\n",
    "                conviction = network.nodes[j]['conviction']\n",
    "                if conviction >threshold:\n",
    "                    accepted.append(j)\n",
    "        else:\n",
    "            threshold = np.nan\n",
    "            \n",
    "        triggers[j] = threshold\n",
    "                \n",
    "        \n",
    "                    \n",
    "    return({'accepted':accepted, 'triggers':triggers})\n",
    "\n",
    "def decrement_funds(params, step, sL, s, _input):\n",
    "    \n",
    "    funds = s['funds']\n",
    "    network = s['network']\n",
    "    accepted = _input['accepted']\n",
    "\n",
    "    #decrement funds\n",
    "    for j in accepted:\n",
    "        funds = funds - network.nodes[j]['funds_requested']\n",
    "    \n",
    "    key = 'funds'\n",
    "    value = funds\n",
    "    \n",
    "    return (key, value)\n",
    "\n",
    "def update_proposals(params, step, sL, s, _input):\n",
    "    \n",
    "    network = s['network']\n",
    "    accepted = _input['accepted']\n",
    "    triggers = _input['triggers']\n",
    "    participants = get_nodes_by_type(network, 'participant')\n",
    "    proposals = get_nodes_by_type(network, 'proposals')\n",
    "    \n",
    "    for j in proposals:\n",
    "        network.nodes[j]['trigger'] = triggers[j]\n",
    "    \n",
    "    #bookkeeping conviction and participant sentiment\n",
    "    for j in accepted:\n",
    "        network.nodes[j]['status']='active'\n",
    "        network.nodes[j]['conviction']=np.nan\n",
    "        #change status to active\n",
    "        for i in participants:\n",
    "        \n",
    "            edge = (i,j)\n",
    "            #reset tokens assigned to other candidates\n",
    "            network.edges[(i,j)]['tokens']=0\n",
    "            network.edges[(i,j)]['conviction'] = np.nan\n",
    "            \n",
    "            #update participants sentiments (positive or negative) \n",
    "            affinities = [network.edges[(i,p)]['affinity'] for p in proposals if not(p in accepted)]\n",
    "            if len(affinities)>1:\n",
    "                max_affinity = np.max(affinities)\n",
    "                force = network.edges[(i,j)]['affinity']-sensitivity*max_affinity\n",
    "            else:\n",
    "                force = 0\n",
    "            \n",
    "            #based on what their affinities to the accepted proposals\n",
    "            network.nodes[i]['sentiment'] = get_sentimental(network.nodes[i]['sentiment'], force, False)\n",
    "            \n",
    "    \n",
    "    key = 'network'\n",
    "    value = network\n",
    "    \n",
    "    return (key, value)\n",
    "\n",
    "def update_sentiment_on_release(params, step, sL, s, _input):\n",
    "    \n",
    "    network = s['network']\n",
    "    proposals = get_nodes_by_type(network, 'proposal')\n",
    "    accepted = _input['accepted']\n",
    "    \n",
    "    proposals_outstanding = np.sum([network.nodes[j]['funds_requested'] for j in proposals if network.nodes[j]['status']=='candidate'])\n",
    "    \n",
    "    proposals_accepted = np.sum([network.nodes[j]['funds_requested'] for j in accepted])\n",
    "    \n",
    "    sentiment = s['sentiment']\n",
    "    force = proposals_accepted/proposals_outstanding\n",
    "    if (force >=0) and (force <=1):\n",
    "        sentiment = get_sentimental(sentiment, force, False)\n",
    "    else:\n",
    "        sentiment = get_sentimental(sentiment, 0, False)\n",
    "    \n",
    "    key = 'sentiment'\n",
    "    value = sentiment\n",
    "    \n",
    "    return (key, value)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "def participants_decisions(params, step, sL, s):\n",
    "    \n",
    "    network = s['network']\n",
    "    participants = get_nodes_by_type(network, 'participant')\n",
    "    proposals = get_nodes_by_type(network, 'proposal')\n",
    "    candidates = [j for j in proposals if network.nodes[j]['status']=='candidate']\n",
    "    \n",
    "    gain = .01\n",
    "    delta_holdings={}\n",
    "    proposals_supported ={}\n",
    "    for i in participants:\n",
    "        force = network.nodes[i]['sentiment']-sensitivity\n",
    "        delta_holdings[i] = network.nodes[i]['holdings']*gain*force\n",
    "        \n",
    "        support = []\n",
    "        for j in candidates:\n",
    "            affinity = network.edges[(i, j)]['affinity']\n",
    "            cutoff = sensitivity*np.max([network.edges[(i,p)]['affinity'] for p in candidates])\n",
    "            if cutoff <.5:\n",
    "                cutoff = .5\n",
    "            \n",
    "            if affinity > cutoff:\n",
    "                support.append(j)\n",
    "        \n",
    "        proposals_supported[i] = support\n",
    "    \n",
    "    return({'delta_holdings':delta_holdings, 'proposals_supported':proposals_supported})\n",
    "\n",
    "def update_tokens(params, step, sL, s, _input):\n",
    "    \n",
    "    network = s['network']\n",
    "    delta_holdings = _input['delta_holdings']\n",
    "    proposals = get_nodes_by_type(network, 'proposal')\n",
    "    proposals_supported = _input['proposals_supported']\n",
    "    participants = get_nodes_by_type(network, 'participant')\n",
    "    \n",
    "    for i in participants:\n",
    "        network.nodes[i]['holdings'] = network.nodes[i]['holdings']+delta_holdings[i]\n",
    "        supported = proposals_supported[i]\n",
    "        total_affinity = np.sum([ network.edges[(i, j)]['affinity'] for j in supported])\n",
    "        for j in proposals:\n",
    "            if j in supported:\n",
    "                normalized_affinity = network.edges[(i, j)]['affinity']/total_affinity\n",
    "                network.edges[(i, j)]['tokens'] = normalized_affinity*network.nodes[i]['holdings']\n",
    "            else:\n",
    "                network.edges[(i, j)]['tokens'] = 0\n",
    "            \n",
    "            prior_conviction = network.edges[(i, j)]['conviction']\n",
    "            current_tokens = network.edges[(i, j)]['tokens']\n",
    "            network.edges[(i, j)]['conviction'] =current_tokens+alpha*prior_conviction\n",
    "    \n",
    "    for j in proposals:\n",
    "        network.nodes[j]['conviction'] = np.sum([ network.edges[(i, j)]['conviction'] for i in participants])\n",
    "    \n",
    "    key = 'network'\n",
    "    value = network\n",
    "    \n",
    "    return (key, value)\n",
    "\n",
    "def update_supply(params, step, sL, s, _input):\n",
    "    \n",
    "    supply = s['supply']\n",
    "    delta_holdings = _input['delta_holdings']\n",
    "    delta_supply = np.sum([v for v in delta_holdings.values()])\n",
    "    \n",
    "    supply = supply + delta_supply\n",
    "    \n",
    "    key = 'supply'\n",
    "    value = supply\n",
    "    \n",
    "    return (key, value)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 30,
   "metadata": {},
   "outputs": [],
   "source": [
    "# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # \n",
    "# The Partial State Update Blocks\n",
    "partial_state_update_blocks = [\n",
    "    { \n",
    "        'policies': { \n",
    "            #new proposals or new participants\n",
    "            'random': driving_process\n",
    "        },\n",
    "        'variables': {\n",
    "            'network': update_network,\n",
    "            'funds':increment_funds,\n",
    "            'supply':increment_supply\n",
    "        }\n",
    "    },\n",
    "    {\n",
    "      'policies': {\n",
    "          'completion': check_progress #see if any of the funded proposals completes\n",
    "        },\n",
    "        'variables': { # The following state variables will be updated simultaneously\n",
    "            'sentiment': update_sentiment_on_completion, #note completing decays sentiment, completing bumps it\n",
    "            'network': complete_proposal #book-keeping\n",
    "        }\n",
    "    },\n",
    "        {\n",
    "      'policies': {\n",
    "          'release': trigger_function #check each proposal to see if it passes\n",
    "        },\n",
    "        'variables': { # The following state variables will be updated simultaneously\n",
    "            'funds': decrement_funds, #funds expended\n",
    "            'sentiment': update_sentiment_on_release, #releasing funds can bump sentiment\n",
    "            'network': update_proposals #reset convictions, and participants sentiments\n",
    "                                        #update based on affinities\n",
    "        }\n",
    "    },\n",
    "    { \n",
    "        'policies': { \n",
    "            'participants_act': participants_decisions, #high sentiment, high affinity =>buy\n",
    "                                                        #low sentiment, low affinities => burn\n",
    "                                                        #assign tokens to top affinities\n",
    "        },\n",
    "        'variables': {\n",
    "            'supply': update_supply,\n",
    "            'network': update_tokens #update everyones holdings \n",
    "                                    #and their conviction for each proposal\n",
    "        }\n",
    "    }\n",
    "]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 31,
   "metadata": {},
   "outputs": [],
   "source": [
    "# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # \n",
    "# The configurations above are then packaged into a `Configuration` object\n",
    "config = Configuration(initial_state=initial_conditions, #dict containing variable names and initial values\n",
    "                       partial_state_update_blocks=partial_state_update_blocks, #dict containing state update functions\n",
    "                       sim_config=simulation_parameters #dict containing simulation parameters\n",
    "                      )"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 32,
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "single_proc: [<cadCAD.configuration.Configuration object at 0x1a19a85c18>]\n",
      "[{'sensitivity': [0.75], 'tmin': [7], 'sentiment_decay': [0.001], 'alpha': [0.5], 'base_completion_rate': [10], 'trigger_func': [<function trigger_threshold at 0x1a1831c620>]}]\n",
      "<class 'list'>\n"
     ]
    },
    {
     "ename": "TypeError",
     "evalue": "list indices must be integers or slices, not str",
     "output_type": "error",
     "traceback": [
      "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[0;31mTypeError\u001b[0m                                 Traceback (most recent call last)",
      "\u001b[0;32m<ipython-input-32-57ee2d652975>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m\u001b[0m\n\u001b[1;32m      2\u001b[0m \u001b[0mexec_context\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mExecutionContext\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mexec_mode\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0msingle_proc\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m      3\u001b[0m \u001b[0mexecutor\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mExecutor\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mexec_context\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m[\u001b[0m\u001b[0mconfig\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;31m# Pass the configuration object inside an array\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 4\u001b[0;31m \u001b[0mraw_result\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mtensor\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mexecutor\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mmain\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;31m# The `main()` method returns a tuple; its first elements contains the raw results\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
      "\u001b[0;32m/anaconda3/lib/python3.6/site-packages/cadCAD/engine/__init__.py\u001b[0m in \u001b[0;36mexecute\u001b[0;34m(self)\u001b[0m\n\u001b[1;32m     96\u001b[0m             \u001b[0;31m# ToDO: Deprication Handler - \"sanitize\" in appropriate place\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m     97\u001b[0m             \u001b[0mtensor_field\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mcreate_tensor_field\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mpartial_state_updates\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mpop\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0meps\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mpop\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 98\u001b[0;31m             \u001b[0mresult\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mexec_method\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0msimulation_execs\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mvar_dict_list\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mstates_lists\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mconfigs_structs\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0menv_processes_list\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mTs\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mNs\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m     99\u001b[0m             \u001b[0mfinal_result\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mresult\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mtensor_field\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    100\u001b[0m         \u001b[0;32melif\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mexec_context\u001b[0m \u001b[0;34m==\u001b[0m \u001b[0mExecutionMode\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mmulti_proc\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0;32m/anaconda3/lib/python3.6/site-packages/cadCAD/engine/__init__.py\u001b[0m in \u001b[0;36msingle_proc_exec\u001b[0;34m(simulation_execs, var_dict_list, states_lists, configs_structs, env_processes_list, Ts, Ns)\u001b[0m\n\u001b[1;32m     31\u001b[0m     \u001b[0ml\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m[\u001b[0m\u001b[0msimulation_execs\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mstates_lists\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mconfigs_structs\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0menv_processes_list\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mTs\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mNs\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m     32\u001b[0m     \u001b[0msimulation_exec\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mstates_list\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mconfig\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0menv_processes\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mT\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mN\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mlist\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mmap\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;32mlambda\u001b[0m \u001b[0mx\u001b[0m\u001b[0;34m:\u001b[0m \u001b[0mx\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mpop\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0ml\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 33\u001b[0;31m     \u001b[0mresult\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0msimulation_exec\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mvar_dict_list\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mstates_list\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mconfig\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0menv_processes\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mT\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mN\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m     34\u001b[0m     \u001b[0;32mreturn\u001b[0m \u001b[0mflatten\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mresult\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m     35\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0;32m/anaconda3/lib/python3.6/site-packages/cadCAD/engine/simulation.py\u001b[0m in \u001b[0;36msimulation\u001b[0;34m(self, var_dict, states_list, configs, env_processes, time_seq, runs)\u001b[0m\n\u001b[1;32m    270\u001b[0m             TPool().map(\n\u001b[1;32m    271\u001b[0m                 \u001b[0;32mlambda\u001b[0m \u001b[0mrun\u001b[0m\u001b[0;34m:\u001b[0m \u001b[0mexecute_run\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mvar_dict\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mstates_list\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mconfigs\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0menv_processes\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mtime_seq\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mrun\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 272\u001b[0;31m                 \u001b[0mlist\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mrange\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mruns\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m    273\u001b[0m             )\n\u001b[1;32m    274\u001b[0m         )\n",
      "\u001b[0;32m/anaconda3/lib/python3.6/site-packages/pathos/threading.py\u001b[0m in \u001b[0;36mmap\u001b[0;34m(self, f, *args, **kwds)\u001b[0m\n\u001b[1;32m    132\u001b[0m         \u001b[0mAbstractWorkerPool\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_AbstractWorkerPool__map\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mf\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m*\u001b[0m\u001b[0margs\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m**\u001b[0m\u001b[0mkwds\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    133\u001b[0m         \u001b[0m_pool\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_serve\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 134\u001b[0;31m         \u001b[0;32mreturn\u001b[0m \u001b[0m_pool\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mmap\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mstar\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mf\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mzip\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m*\u001b[0m\u001b[0margs\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;31m# chunksize\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m    135\u001b[0m     \u001b[0mmap\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m__doc__\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mAbstractWorkerPool\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mmap\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m__doc__\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    136\u001b[0m     \u001b[0;32mdef\u001b[0m \u001b[0mimap\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mf\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m*\u001b[0m\u001b[0margs\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m**\u001b[0m\u001b[0mkwds\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0;32m/anaconda3/lib/python3.6/site-packages/multiprocess/pool.py\u001b[0m in \u001b[0;36mmap\u001b[0;34m(self, func, iterable, chunksize)\u001b[0m\n\u001b[1;32m    264\u001b[0m         \u001b[0;32min\u001b[0m \u001b[0ma\u001b[0m \u001b[0mlist\u001b[0m \u001b[0mthat\u001b[0m \u001b[0;32mis\u001b[0m \u001b[0mreturned\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    265\u001b[0m         '''\n\u001b[0;32m--> 266\u001b[0;31m         \u001b[0;32mreturn\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_map_async\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mfunc\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0miterable\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mmapstar\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mchunksize\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mget\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m    267\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    268\u001b[0m     \u001b[0;32mdef\u001b[0m \u001b[0mstarmap\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mfunc\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0miterable\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mchunksize\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;32mNone\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0;32m/anaconda3/lib/python3.6/site-packages/multiprocess/pool.py\u001b[0m in \u001b[0;36mget\u001b[0;34m(self, timeout)\u001b[0m\n\u001b[1;32m    642\u001b[0m             \u001b[0;32mreturn\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_value\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    643\u001b[0m         \u001b[0;32melse\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 644\u001b[0;31m             \u001b[0;32mraise\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_value\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m    645\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    646\u001b[0m     \u001b[0;32mdef\u001b[0m \u001b[0m_set\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mi\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mobj\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0;32m/anaconda3/lib/python3.6/site-packages/multiprocess/pool.py\u001b[0m in \u001b[0;36mworker\u001b[0;34m(inqueue, outqueue, initializer, initargs, maxtasks, wrap_exception)\u001b[0m\n\u001b[1;32m    117\u001b[0m         \u001b[0mjob\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mi\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mfunc\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0margs\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mkwds\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mtask\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    118\u001b[0m         \u001b[0;32mtry\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 119\u001b[0;31m             \u001b[0mresult\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m(\u001b[0m\u001b[0;32mTrue\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mfunc\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m*\u001b[0m\u001b[0margs\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m**\u001b[0m\u001b[0mkwds\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m    120\u001b[0m         \u001b[0;32mexcept\u001b[0m \u001b[0mException\u001b[0m \u001b[0;32mas\u001b[0m \u001b[0me\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    121\u001b[0m             \u001b[0;32mif\u001b[0m \u001b[0mwrap_exception\u001b[0m \u001b[0;32mand\u001b[0m \u001b[0mfunc\u001b[0m \u001b[0;32mis\u001b[0m \u001b[0;32mnot\u001b[0m \u001b[0m_helper_reraises_exception\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0;32m/anaconda3/lib/python3.6/site-packages/multiprocess/pool.py\u001b[0m in \u001b[0;36mmapstar\u001b[0;34m(args)\u001b[0m\n\u001b[1;32m     42\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m     43\u001b[0m \u001b[0;32mdef\u001b[0m \u001b[0mmapstar\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0margs\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 44\u001b[0;31m     \u001b[0;32mreturn\u001b[0m \u001b[0mlist\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mmap\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m*\u001b[0m\u001b[0margs\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m     45\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m     46\u001b[0m \u001b[0;32mdef\u001b[0m \u001b[0mstarmapstar\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0margs\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0;32m/anaconda3/lib/python3.6/site-packages/pathos/helpers/mp_helper.py\u001b[0m in \u001b[0;36m<lambda>\u001b[0;34m(args)\u001b[0m\n\u001b[1;32m     13\u001b[0m \u001b[0;32mdef\u001b[0m \u001b[0mstarargs\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mf\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m     14\u001b[0m     \u001b[0;34m\"\"\"decorator to convert a many-arg function to a single-arg function\"\"\"\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 15\u001b[0;31m     \u001b[0mfunc\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;32mlambda\u001b[0m \u001b[0margs\u001b[0m\u001b[0;34m:\u001b[0m \u001b[0mf\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m*\u001b[0m\u001b[0margs\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m     16\u001b[0m    \u001b[0;31m#func.__module__ = f.__module__\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m     17\u001b[0m    \u001b[0;31m#func.__name__ = f.__name__\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0;32m/anaconda3/lib/python3.6/site-packages/cadCAD/engine/simulation.py\u001b[0m in \u001b[0;36m<lambda>\u001b[0;34m(run)\u001b[0m\n\u001b[1;32m    269\u001b[0m         pipe_run: List[List[Dict[str, Any]]] = flatten(\n\u001b[1;32m    270\u001b[0m             TPool().map(\n\u001b[0;32m--> 271\u001b[0;31m                 \u001b[0;32mlambda\u001b[0m \u001b[0mrun\u001b[0m\u001b[0;34m:\u001b[0m \u001b[0mexecute_run\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mvar_dict\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mstates_list\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mconfigs\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0menv_processes\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mtime_seq\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mrun\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m    272\u001b[0m                 \u001b[0mlist\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mrange\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mruns\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    273\u001b[0m             )\n",
      "\u001b[0;32m/anaconda3/lib/python3.6/site-packages/cadCAD/engine/simulation.py\u001b[0m in \u001b[0;36mexecute_run\u001b[0;34m(var_dict, states_list, configs, env_processes, time_seq, run)\u001b[0m\n\u001b[1;32m    262\u001b[0m             \u001b[0mstates_list_copy\u001b[0m\u001b[0;34m:\u001b[0m \u001b[0mList\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0mDict\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0mstr\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mAny\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m]\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mlist\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mgenerate_init_sys_metrics\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mdeepcopy\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mstates_list\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    263\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 264\u001b[0;31m             \u001b[0mfirst_timestep_per_run\u001b[0m\u001b[0;34m:\u001b[0m \u001b[0mList\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0mDict\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0mstr\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mAny\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m]\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mrun_pipeline\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mvar_dict\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mstates_list_copy\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mconfigs\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0menv_processes\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mtime_seq\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mrun\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m    265\u001b[0m             \u001b[0;32mdel\u001b[0m \u001b[0mstates_list_copy\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    266\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0;32m/anaconda3/lib/python3.6/site-packages/cadCAD/engine/simulation.py\u001b[0m in \u001b[0;36mrun_pipeline\u001b[0;34m(self, var_dict, states_list, configs, env_processes, time_seq, run)\u001b[0m\n\u001b[1;32m    230\u001b[0m         \u001b[0;32mfor\u001b[0m \u001b[0mtime_step\u001b[0m \u001b[0;32min\u001b[0m \u001b[0mtime_seq\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    231\u001b[0m             pipe_run: List[Dict[str, Any]] = self.state_update_pipeline(\n\u001b[0;32m--> 232\u001b[0;31m                 \u001b[0mvar_dict\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0msimulation_list\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mconfigs\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0menv_processes\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mtime_step\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mrun\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m    233\u001b[0m             )\n\u001b[1;32m    234\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0;32m/anaconda3/lib/python3.6/site-packages/cadCAD/engine/simulation.py\u001b[0m in \u001b[0;36mstate_update_pipeline\u001b[0;34m(self, var_dict, simulation_list, configs, env_processes, time_step, run)\u001b[0m\n\u001b[1;32m    197\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    198\u001b[0m             states_list: List[Dict[str, Any]] = self.partial_state_update(\n\u001b[0;32m--> 199\u001b[0;31m                 \u001b[0mvar_dict\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0msub_step\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mstates_list\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0msimulation_list\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0ms_conf\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mp_conf\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0menv_processes\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mtime_step\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mrun\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m    200\u001b[0m             )\n\u001b[1;32m    201\u001b[0m             \u001b[0;31m# print(sub_step)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0;32m/anaconda3/lib/python3.6/site-packages/cadCAD/engine/simulation.py\u001b[0m in \u001b[0;36mpartial_state_update\u001b[0;34m(self, var_dict, sub_step, sL, sH, state_funcs, policy_funcs, env_processes, time_step, run)\u001b[0m\n\u001b[1;32m    136\u001b[0m             \u001b[0;32mreturn\u001b[0m \u001b[0mdestination\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    137\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 138\u001b[0;31m         \u001b[0mlast_in_copy\u001b[0m\u001b[0;34m:\u001b[0m \u001b[0mDict\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0mstr\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mAny\u001b[0m\u001b[0;34m]\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mtransfer_missing_fields\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mlast_in_obj\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mdict\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mgenerate_record\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mstate_funcs\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m    139\u001b[0m         \u001b[0;31m# ToDo: Remove\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    140\u001b[0m         \u001b[0mlast_in_copy\u001b[0m\u001b[0;34m:\u001b[0m \u001b[0mDict\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0mstr\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mAny\u001b[0m\u001b[0;34m]\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mapply_env_proc\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0menv_processes\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mlast_in_copy\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mlast_in_copy\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;34m'timestep'\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0;32m/anaconda3/lib/python3.6/site-packages/cadCAD/engine/simulation.py\u001b[0m in \u001b[0;36mgenerate_record\u001b[0;34m(state_funcs)\u001b[0m\n\u001b[1;32m    127\u001b[0m         \u001b[0;32mdef\u001b[0m \u001b[0mgenerate_record\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mstate_funcs\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    128\u001b[0m             \u001b[0;32mfor\u001b[0m \u001b[0mf\u001b[0m \u001b[0;32min\u001b[0m \u001b[0mstate_funcs\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 129\u001b[0;31m                 \u001b[0;32myield\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mstate_update_exception\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mf\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mvar_dict\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0msub_step\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0msH\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mlast_in_obj\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0m_input\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m    130\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    131\u001b[0m         \u001b[0;32mdef\u001b[0m \u001b[0mtransfer_missing_fields\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0msource\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mdestination\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0;32m~/Documents/GitHub/conviction/conviction_system_logic.py\u001b[0m in \u001b[0;36mupdate_network\u001b[0;34m(params, step, sL, s, _input)\u001b[0m\n\u001b[1;32m    119\u001b[0m     \u001b[0mfunds\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0ms\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;34m'funds'\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    120\u001b[0m     \u001b[0msupply\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0ms\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;34m'supply'\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 121\u001b[0;31m     \u001b[0mtrigger_func\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mparams\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;34m'trigger_func'\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m    122\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    123\u001b[0m     \u001b[0mnew_participant\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0m_input\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;34m'new_participant'\u001b[0m\u001b[0;34m]\u001b[0m \u001b[0;31m#T/F\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0;31mTypeError\u001b[0m: list indices must be integers or slices, not str"
     ]
    }
   ],
   "source": [
    "exec_mode = ExecutionMode()\n",
    "exec_context = ExecutionContext(exec_mode.single_proc)\n",
    "executor = Executor(exec_context, [config]) # Pass the configuration object inside an array\n",
    "raw_result, tensor = executor.main() # The `main()` method returns a tuple; its first elements contains the raw results"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "df = pd.DataFrame(raw_result)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "df.tail(5)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "df.supply.plot()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "df.sentiment.plot()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "df.plot(x='timestep', y='funds')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "def pad(vec, length,fill=True):\n",
    "    \n",
    "    if fill:\n",
    "        padded = np.zeros(length,)\n",
    "    else:\n",
    "        padded = np.empty(length,)\n",
    "        padded[:] = np.nan\n",
    "        \n",
    "    for i in range(len(vec)):\n",
    "        padded[i]= vec[i]\n",
    "        \n",
    "    return padded\n",
    "\n",
    "def make2D(key, data, fill=False):\n",
    "    maxL = data[key].apply(len).max()\n",
    "    newkey = 'padded_'+key\n",
    "    data[newkey] = data[key].apply(lambda x: pad(x,maxL,fill))\n",
    "    reshaped = np.array([a for a in data[newkey].values])\n",
    "    \n",
    "    return reshaped"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "df['conviction'] = df.network.apply(lambda g: np.array([g.nodes[j]['conviction'] for j in get_nodes_by_type(g, 'proposal') if g.nodes[j]['status']=='candidate']))\n",
    "df['candidate_count'] = df.network.apply(lambda g: len([j for j in get_nodes_by_type(g, 'proposal') if g.nodes[j]['status']=='candidate']))\n",
    "df['candidate_funds'] = df.network.apply(lambda g: np.sum([g.nodes[j]['funds_requested'] for j in get_nodes_by_type(g, 'proposal') if g.nodes[j]['status']=='candidate']))\n",
    "df['candidate_funds_requested'] = df.network.apply(lambda g: np.array([g.nodes[j]['funds_requested'] for j in get_nodes_by_type(g, 'proposal') if g.nodes[j]['status']=='candidate']))\n",
    "df['active_count'] = df.network.apply(lambda g: len([j for j in get_nodes_by_type(g, 'proposal') if g.nodes[j]['status']=='active']))\n",
    "df['active_funds'] = df.network.apply(lambda g: np.sum([g.nodes[j]['funds_requested'] for j in get_nodes_by_type(g, 'proposal') if g.nodes[j]['status']=='active']))\n",
    "df['completed_count'] = df.network.apply(lambda g: len([j for j in get_nodes_by_type(g, 'proposal') if g.nodes[j]['status']=='completed']))\n",
    "df['completed_funds'] = df.network.apply(lambda g: np.sum([g.nodes[j]['funds_requested'] for j in get_nodes_by_type(g, 'proposal') if g.nodes[j]['status']=='completed']))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "df['funds_requested'] = df.network.apply(lambda g: np.array([g.nodes[j]['funds_requested'] for j in get_nodes_by_type(g, 'proposal')]))\n",
    "df['share_of_funds_requested'] = df.candidate_funds_requested/df.funds\n",
    "\n",
    "df['share_of_funds_requested_all'] = df.funds_requested/df.funds"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "df['triggers'] = df.network.apply(lambda g: np.array([g.nodes[j]['trigger'] for j in get_nodes_by_type(g, 'proposal') if g.nodes[j]['status']=='candidate' ]))\n",
    "df['conviction_share_of_trigger'] = df.conviction/df.triggers\n",
    "df['age'] = df.network.apply(lambda g: np.array([g.nodes[j]['age'] for j in get_nodes_by_type(g, 'proposal') if g.nodes[j]['status']=='candidate' ]))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "df['age_all'] = df.network.apply(lambda g: np.array([g.nodes[j]['age'] for j in get_nodes_by_type(g, 'proposal') ]))\n",
    "df['conviction_all'] = df.network.apply(lambda g: np.array([g.nodes[j]['conviction'] for j in get_nodes_by_type(g, 'proposal') ]))\n",
    "df['triggers_all'] = df.network.apply(lambda g: np.array([g.nodes[j]['trigger'] for j in get_nodes_by_type(g, 'proposal')  ]))\n",
    "\n",
    "df['conviction_share_of_trigger_all'] = df.conviction_all/df.triggers_all"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "rdf= df[df.substep==4].copy()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "last_net= df.network.values[-1]\n",
    "last_props=get_nodes_by_type(last_net, 'proposal')\n",
    "M = len(last_props)\n",
    "last_parts=get_nodes_by_type(last_net, 'participant')\n",
    "N = len(last_parts)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "affinities = np.empty((N,M))\n",
    "for i_ind in range(N):\n",
    "    for j_ind in range(M):\n",
    "        i = last_parts[i_ind]\n",
    "        j = last_props[j_ind]\n",
    "        affinities[i_ind][j_ind] = last_net.edges[(i,j)]['affinity']"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "dims = (100, 25)\n",
    "fig, ax = plt.subplots(figsize=dims)\n",
    "\n",
    "sns.heatmap(affinities,\n",
    "            yticklabels=last_parts,\n",
    "            xticklabels=last_props,\n",
    "            square=True,\n",
    "            cbar=True,\n",
    "            ax=ax)\n",
    "\n",
    "plt.title('affinities between participants and proposals')\n",
    "plt.xlabel('proposal_id')\n",
    "plt.ylabel('participant_id')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#working on deduplicating colors\n",
    "#\n",
    "#last_props=get_nodes_by_type(last_net, 'proposal')\n",
    "#M = len(last_props)\n",
    "\n",
    "#cm = plt.get_cmap('gist_rainbow')\n",
    "#c= [cm(1.*j/M) for j in range(M)] "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "make2D('age_all', rdf)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "plt.plot(rdf.timestep,make2D('age_all', rdf))\n",
    "plt.title('check age')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "rdf.plot(x='timestep',y=['candidate_count','active_count','completed_count'])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "rdf.plot(x='timestep',y=['candidate_funds','active_funds','completed_funds'])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "plt.semilogy(rdf.timestep,make2D('conviction_all', rdf))\n",
    "plt.title('conviction by proposal')\n",
    "plt.xlabel('time $t$')\n",
    "plt.ylabel('conviction')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "plt.semilogy(make2D('age_all', rdf),make2D('conviction_all', rdf))\n",
    "plt.title('conviction by proposal')\n",
    "plt.xlabel('proposal age')\n",
    "plt.ylabel('conviction')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "plt.plot(rdf.timestep,make2D('share_of_funds_requested_all', rdf))\n",
    "plt.title('share_of_funds_requested by proposal')\n",
    "plt.xlabel('time $t$')\n",
    "plt.ylabel('share_of_funds_requested')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "plt.semilogy(make2D('age_all', rdf),make2D('share_of_funds_requested_all', rdf))\n",
    "plt.title('share_of_funds_requested by proposal')\n",
    "plt.xlabel('proposal age')\n",
    "plt.ylabel('share_of_funds_requested')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "plt.loglog(make2D('share_of_funds_requested_all', rdf), make2D('conviction_all', rdf), '.')\n",
    "plt.ylabel('conviction')\n",
    "plt.xlabel('share_of_funds_requested')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "plt.semilogy(make2D('age_all', rdf), make2D('triggers_all', rdf))\n",
    "plt.ylabel('triggers')\n",
    "plt.xlabel('proposal_age')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "plt.loglog(make2D('conviction_all', rdf), make2D('triggers_all', rdf))\n",
    "a = plt.axis()\n",
    "plt.loglog(a[:2],a[2:], 'k',alpha=.5 )\n",
    "plt.ylabel('triggers')\n",
    "plt.xlabel('conviction')\n",
    "plt.title('phase: Triggers & Conviction')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "plt.semilogy(rdf.timestep,make2D('conviction_share_of_trigger_all', rdf))\n",
    "plt.title('conviction_share_of_trigger')\n",
    "plt.xlabel('time $t$')\n",
    "plt.ylabel('conviction_share_of_trigger')\n",
    "plt.hlines(1,0,T, linestyle='--')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "plt.semilogy(make2D('age_all', rdf), make2D('conviction_share_of_trigger_all', rdf))\n",
    "plt.ylabel('triggers')\n",
    "plt.xlabel('proposal_age')\n",
    "plt.hlines(1,0,T, linestyle='--')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "pos = {}\n",
    "for ind in range(N):\n",
    "    i = last_parts[ind] \n",
    "    pos[i] = np.array([0, 2*ind-N])\n",
    "\n",
    "for ind in range(M):\n",
    "    j = last_props[ind] \n",
    "    pos[j] = np.array([1, 2*N/M *ind-N])\n",
    "\n",
    "#for i in last_parts:\n",
    "#for j in last_props:\n",
    "        "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "edges = [e for e in last_net.edges]\n",
    "max_tok = np.max([last_net.edges[e]['tokens'] for e in edges])\n",
    "\n",
    "E = len(edges)\n",
    "\n",
    "node_color = np.empty((M+N,4))\n",
    "node_size = np.empty(M+N)\n",
    "\n",
    "edge_color = np.empty((E,4))\n",
    "cm = plt.get_cmap('Reds')\n",
    "\n",
    "cNorm  = colors.Normalize(vmin=0, vmax=max_tok)\n",
    "scalarMap = cmx.ScalarMappable(norm=cNorm, cmap=cm)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "size_scale = 1/500\n",
    "node_label = {}\n",
    "\n",
    "for j in last_props:\n",
    "    node_size[j] = last_net.nodes[j]['funds_requested']*size_scale\n",
    "    if last_net.nodes[j]['status']==\"candidate\":\n",
    "        node_color[j] = colors.to_rgba('blue')\n",
    "        trigger = last_net.nodes[j]['trigger']\n",
    "        #print(trigger)\n",
    "        conviction = last_net.nodes[j]['conviction']\n",
    "        #print(conviction)\n",
    "        percent_of_trigger = str(int(100*conviction/trigger))+'%'\n",
    "        #age = last_net.nodes[j]['age']\n",
    "        node_label[j] = str(percent_of_trigger)\n",
    "    elif last_net.nodes[j]['status']==\"active\":\n",
    "        node_color[j] = colors.to_rgba('orange')\n",
    "        node_label[j] = ''\n",
    "    elif last_net.nodes[j]['status']==\"completed\":\n",
    "        node_color[j] = colors.to_rgba('green')\n",
    "        node_label[j] = ''\n",
    "\n",
    "for i in last_parts:    \n",
    "    node_size[i] = last_net.nodes[i]['holdings']*size_scale\n",
    "    node_color[i] = colors.to_rgba('red')\n",
    "    node_label[i] = ''\n",
    "\n",
    "included_edges = []\n",
    "for ind in range(E):\n",
    "    e = edges[ind]\n",
    "    tokens = last_net.edges[e]['tokens']\n",
    "    if tokens >0:\n",
    "        included_edges.append(e)\n",
    "    #print(tokens)\n",
    "    edge_color[ind] = scalarMap.to_rgba(tokens)\n",
    "\n",
    "iE = len(included_edges)\n",
    "included_edge_color = np.empty((iE,4))\n",
    "for ind in range(iE):\n",
    "    e = included_edges[ind]\n",
    "    tokens = last_net.edges[e]['tokens']\n",
    "    included_edge_color[ind] = scalarMap.to_rgba(tokens)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "nx.draw(last_net,\n",
    "        pos=pos, \n",
    "        node_size = node_size, \n",
    "        node_color = node_color, \n",
    "        edge_color = included_edge_color, \n",
    "        edgelist=included_edges,\n",
    "        labels = node_label)\n",
    "plt.title('Tokens Staked by Partipants to Proposals')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "nets = rdf.network.values"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "def snap_plot(nets, size_scale = 1/500, ani = False, dims = (20,20), savefigs=False ):\n",
    "    \n",
    "    last_net= df.network.values[-1]\n",
    "    last_props=get_nodes_by_type(last_net, 'proposal')\n",
    "    M = len(last_props)\n",
    "    last_parts=get_nodes_by_type(last_net, 'participant')\n",
    "    N = len(last_parts)\n",
    "    pos = {}\n",
    "    \n",
    "    for ind in range(N):\n",
    "        i = last_parts[ind] \n",
    "        pos[i] = np.array([0, 2*ind-N])\n",
    "\n",
    "    for ind in range(M):\n",
    "        j = last_props[ind] \n",
    "        pos[j] = np.array([1, 2*N/M *ind-N])\n",
    "    \n",
    "    if ani:\n",
    "        figs = []\n",
    "        fig, ax = plt.subplots(figsize=dims)\n",
    "    \n",
    "    if savefigs:\n",
    "        counter = 0\n",
    "        length = 10\n",
    "        import string\n",
    "        unique_id = ''.join([np.random.choice(list(string.ascii_letters + string.digits)) for _ in range(length)])\n",
    "    for net in nets:\n",
    "        edges = [e for e in net.edges]\n",
    "        max_tok = np.max([net.edges[e]['tokens'] for e in edges])\n",
    "\n",
    "        E = len(edges)\n",
    "        \n",
    "        net_props = get_nodes_by_type(net, 'proposal')\n",
    "        net_parts = get_nodes_by_type(net, 'participant')\n",
    "        net_node_label ={}\n",
    "        \n",
    "        num_nodes = len([node for node in net.nodes])\n",
    "        \n",
    "        node_color = np.empty((num_nodes,4))\n",
    "        node_size = np.empty(num_nodes)\n",
    "\n",
    "        edge_color = np.empty((E,4))\n",
    "        cm = plt.get_cmap('Reds')\n",
    "\n",
    "        cNorm  = colors.Normalize(vmin=0, vmax=max_tok)\n",
    "        scalarMap = cmx.ScalarMappable(norm=cNorm, cmap=cm)\n",
    "    \n",
    "    \n",
    "\n",
    "        for j in net_props:\n",
    "            node_size[j] = net.nodes[j]['funds_requested']*size_scale\n",
    "            if net.nodes[j]['status']==\"candidate\":\n",
    "                node_color[j] = colors.to_rgba('blue')\n",
    "                trigger = net.nodes[j]['trigger']      \n",
    "                conviction = net.nodes[j]['conviction']\n",
    "                percent_of_trigger = \"          \"+str(int(100*conviction/trigger))+'%'\n",
    "                net_node_label[j] = str(percent_of_trigger)\n",
    "            elif net.nodes[j]['status']==\"active\":\n",
    "                node_color[j] = colors.to_rgba('orange')\n",
    "                net_node_label[j] = ''\n",
    "            elif net.nodes[j]['status']==\"completed\":\n",
    "                node_color[j] = colors.to_rgba('green')\n",
    "                net_node_label[j] = ''\n",
    "\n",
    "        for i in net_parts:    \n",
    "            node_size[i] = net.nodes[i]['holdings']*size_scale\n",
    "            node_color[i] = colors.to_rgba('red')\n",
    "            net_node_label[i] = ''\n",
    "\n",
    "        included_edges = []\n",
    "        for ind in range(E):\n",
    "            e = edges[ind]\n",
    "            tokens = net.edges[e]['tokens']\n",
    "            if tokens >0:\n",
    "                included_edges.append(e)\n",
    "            edge_color[ind] = scalarMap.to_rgba(tokens)\n",
    "\n",
    "        iE = len(included_edges)\n",
    "        included_edge_color = np.empty((iE,4))\n",
    "        for ind in range(iE):\n",
    "            e = included_edges[ind]\n",
    "            tokens = net.edges[e]['tokens']\n",
    "            included_edge_color[ind] = scalarMap.to_rgba(tokens)\n",
    "        \n",
    "        nx.draw(net,\n",
    "                pos=pos, \n",
    "                node_size = node_size,\n",
    "                node_color = node_color, \n",
    "                edge_color = included_edge_color, \n",
    "                edgelist=included_edges,\n",
    "                labels = net_node_label)\n",
    "        plt.title('Tokens Staked by Partipants to Proposals')\n",
    "        if ani:\n",
    "            nx.draw(net,\n",
    "                    pos=pos, \n",
    "                    node_size = node_size,\n",
    "                    node_color = node_color, \n",
    "                    edge_color = included_edge_color, \n",
    "                    edgelist=included_edges,\n",
    "                    labels = net_node_label, ax=ax)\n",
    "            figs.append(fig)\n",
    "            \n",
    "        else:\n",
    "            nx.draw(net,\n",
    "                pos=pos, \n",
    "                node_size = node_size,\n",
    "                node_color = node_color, \n",
    "                edge_color = included_edge_color, \n",
    "                edgelist=included_edges,\n",
    "                labels = net_node_label)\n",
    "            plt.title('Tokens Staked by Partipants to Proposals')\n",
    "            if savefigs:\n",
    "                plt.savefig(unique_id+'_fig'+str(counter)+'.png')\n",
    "                counter = counter+1\n",
    "            plt.show()\n",
    "        \n",
    "    if ani:\n",
    "        False\n",
    "        #anim = animation.ArtistAnimation(fig, , interval=50, blit=True, repeat_delay=1000)\n",
    "        #plt.show()\n",
    "            "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "scrolled": false
   },
   "outputs": [],
   "source": [
    "snap_plot(nets, ani=False, savefigs=False)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#totally failing at animating by trying to save a sequence of figures.\n",
    "#snap_plot(nets, ani=True)\n",
    "\n",
    "#saving the images to files works so there is almost the option to compile a video from the images"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.5"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
