{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Aragon Conviction Voting Model - Version 3\n",
    "\n",
    "New to this version 3  model are the following elements:\n",
    "\n",
    "* Adding the realism that not all participant tokens are being allocated to proposals at each timestep.\n",
    "* Refactored parameters and system initialization to make more readable and consistent.\n",
    "* Changed file structure and file names to align with emerging cadCAD standards.\n",
    "* Making the distinction between effective and total supply.\n",
    "* Refining alpha calculations to more accurately reflect the 1Hive implementation. Discussion of alpha and its relation to alpha in the contract and how it relates to the timescales\n",
    "* Updated differential specification and write-up to respect new state variables\n",
    "* Moved all unit denominations to Honey, the 1Hive governance token.\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# An Introduction to Conviction Voting\n",
    "\n",
    "Conviction Voting is an approach to organizing a communities preferences into discrete decisions in the management of that communities resources. Strictly speaking conviction voting is less like voting and more like signal processing. Framing the approach and the initial algorithm design was done by Michael Zargham and published in a short research proposal [Social Sensor Fusion](https://github.com/BlockScience/conviction/blob/master/social-sensorfusion.pdf). This work is based on a dynamic resource allocation algorithm presented in Dr. Zargham's PhD Thesis.\n",
    "\n",
    "The work proceeded in collaboration with the Commons Stack, including expanding on the python implementation to makeup part of the Commons Simulator game. An implemention of Conviction Voting as a smart contract within the Aragon Framework was developed by 1Hive.org and is currently being used for community decision making for allocations of their community currency, Honey.\n",
    "\n",
    "\n",
    "## The Word Problem\n",
    "\n",
    "Suppose a group of people want to coordinate to make a collective decision. Social dynamics such as discussions, signaling, and even changing ones mind based on feedback from others input play an important role in these processes. While the actual decision making process involves a lot of informal processes, in order to be fair the ultimate decision making process still requires a set of formal rules that the community collecively agrees to, which serves to functionally channel a plurality of preferences into a discrete outcomes. In our case we are interested in a procedure which supports asynchronous interactions, an provides visibility into likely outcomes prior to their resolution to serve as a driver of good faith, debate and healthy forms of coalition building. Furthermore, participations should be able to show support for multiple initiatives, and to vary the level of support shown. Participants have a quantity of signaling power which may be fixed or variable, homogenous or heterogenous. For the purpose of this document, we'll focus on the case where the discrete decisions to be made are decisions to allocate funds from a shared funding pool towards projects of interest to the community.\n",
    "\n",
    "## Converting to a Math Problem\n",
    "\n",
    "Let's start taking these words and constructing a mathematical representation that supports a design that meets the description above. To start we need to define participants.\n",
    "\n",
    "### Participants\n",
    "Let $\\mathcal{A}$ be the set of participants. Consider a participant $a\\in \\mathcal{A}$. Any participant $a$ has some capacity to participate in the voting process through their token holdings $h[a]$. In a homogenous fixed token quantity system (like you might see in a democratic allocation of equal tokens per each participant), $h[a] = h$ for all $a\\in \\mathcal{A}$ where $h$ is a constant. The access control process managing how one becomes a participant determines the total supply of \"votes\" $S = \\sum_{a\\in \\mathcal{A}} = n\\cdot h$ where the number of participants is $n = |\\mathcal{A}|$. In a smart contract setting, the set $\\mathcal{A}$ is a set of addresses, and $h[a]$ is a quantity of tokens held by each address $a\\in \\mathcal{A}$. \n",
    "\n",
    "### Proposals & Shared Resources\n",
    "Next, we introduce the idea of proposals.  Consider a proposal $i\\in \\mathcal{C}$. Any proposal $i$ is associated with a request for resources $r[i]$. Those requested resources would be allocated from a constrained pool of communal resources currently totaling $R$. The pool of resources may become depleted because when a proposal $i$ passes the reserve is decremented by $R^+= R-r[i]$. Therefore it makes sense for us to consider what fraction of the shared resources are being request $\\mu_i = \\frac{r[i]}{R}$, which means that thre resource depletion from passing proposals can be bounded by requiring $\\mu_i < \\mu$ where $\\mu$ is a constant representing the maximum fraction of the shared resources which can be dispersed by any one proposal. In order for the system to be sustainable a source of new resources is required. In the case where $R$ is funding, new funding can come from revenues, donations, or in some DAO use cases minting tokens.\n",
    "\n",
    "### Participants Preferences for Proposals\n",
    "\n",
    "Most of the interesting information in this system is distributed amongst the participants and it manifests as preferences over the proposals. This can be visualized as a matrix $W\\in \\mathbb{R}^{n \\times m}$, with participants holding randomized affinities from -1 to +1 over all proposals.\n",
    "![](https://i.imgur.com/Rk2BYKd.png)\n",
    "\n",
    "These private hidden signals drive discussions and voting actions. Each participant individually decides how to allocate their votes across the available proposals. Participant $a$ supports proposal $i$ by setting $x[a,i]>0$ but they are limited by their total token holdings $\\sum_{k\\in \\mathcal{C}} x[a,k] \\le h[a]$.  Assuming each participant chooses a subset of the proposals to support, a support graph is formed.\n",
    "![](https://i.imgur.com/KRh8tKn.png)\n",
    "\n",
    "## Aggregating Information\n",
    "\n",
    "In order to break out of the synchronous ad hoc voting model, a dynamical systems model of this system is introduced, which is explored further below.\n",
    "\n",
    "### Participants Allocate Voting Power\n",
    "![](https://i.imgur.com/DZRDwk6.png)\n",
    "\n",
    "In the above diagram, we examine the participant view. Participant $a$ with holdings $h$ at time $t$ supports proposals $i$ and $j$ with $x$ conviction. The sum of all conviction asserted by participant $a$ is between 0 and the total holdings of participant $a$.\n",
    "\n",
    "### System Accounts Proposal Conviction\n",
    "![](https://i.imgur.com/euAei5R.png)\n",
    "\n",
    "In the above diagram, we examine the proposal view. Proposal $j$ with total conviction $y$ at time $t$ is supported by participants $a$, $b$ and $c$ with $x$ conviction. The total conviction $y$ at time $t+1$ is equal to the total conviction at time $t$ decremented by an exponential decay $\\\\alpha$ plus the sum of all conviction from $k$ agents in time step $t$.\n",
    "\n",
    "### Understanding Alpha\n",
    "Below are some graphs used to demonstrate, play with, and understand the shapes and choices for the $\\\\alpha$ parameter, which regulates the half life decay rate of the agent preference conviction growth and decay.\n",
    "\n",
    "* https://www.desmos.com/calculator/x9uc6w72lm\n",
    "* https://www.desmos.com/calculator/0lmtia9jql\n",
    "\n",
    "See the [Deriving_Alpha](Deriving_Alpha.ipynb) notebook for more details around alpha and how it is derived.\n",
    "\n",
    "\n",
    "## Converting Signals to Discrete Decisions\n",
    "\n",
    "Conviction can be considered like a fluctuating kinetic energy, with the Trigger function acting as a required activation energy for proposals to pass. This is the mechanism by which a continuous community preference turns into a discrete action event: passing a proposal. See [Trigger Function Explanation](Trigger_Function_Explanation.ipynb) for more details around the trigger function and how it works."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Resolving Passed Proposals\n",
    "\n",
    "![](images/stockflow_cv_trigger.png)\n",
    "\n",
    "This diagram shows the trigger function logic, which depends on token supply $S$, total resources available $R$ and total conviction $y$ at time $t$, as well as the proposal's requested resources $r$, the maximum share of funds a proposal can take ($\\beta$) and a tuning parameter for the trigger function ($\\rho$). Essentially, this function controls the maximum amount of funds that can be requested by a proposal ($\\beta$), using an equation resembling electron repulsion to ensure conviction increases massively beyond that point.\n",
    "\n",
    "## Social Systems Modeling\n",
    "\n",
    "In the conviction voting model, multiple graph structures are used to represent participants and proposals to represent a subjective, exploratory modeling of the social system interacting.\n",
    "\n",
    "### Sentiment\n",
    "\n",
    "Global Sentiment denotes the outside world appreciating the output of the community.\n",
    "Local Sentiment denotes the agents within the system feeling good about the community.\n",
    "Sentiment increases when proposals pass and work is completed in the community, and decreases when proposals fail and community progress stalls.\n",
    "\n",
    "### Relationships between Participants\n",
    "\n",
    "Edges from participant to participant denote influence (to represent subjective social influence) and are assigned randomly as mixing processes.\n",
    "\n",
    "### Relationships between Proposals\n",
    "\n",
    "Edges from proposal to proposal represent conflict, either positive or negative.\n",
    "Some proposals are synergistic (passing one makes the other more desirable).\n",
    "Some proposals are (partially) substitutable (passing one makes the other less desirable).\n",
    "\n",
    "\n",
    "### Notion of Honey supply\n",
    "#### Total supply = $S$\n",
    "#### Effective supply = $E$\n",
    "#### Funding Pool = $F$\n",
    "#### Other supply = $L$, effectively slack. Funds could be in cold storage, in liquidity pools or otherwise in any address not actively participating in conviction voting.\n",
    "$$S = F + E + L$$ \n",
    "\n",
    "System has the right to do direct mints:\n",
    "$$F^+ = F + minted tokens$$\n",
    "$$S^+ = S + minted tokens$$\n",
    "\n",
    "The system may also see the arrival of new funds which come from outside supply and are donated to the funding pool:\n",
    "$$L^+ = L - donated tokens$$\n",
    "$$F^+ = F + donated tokens$$\n",
    "\n",
    "When tokens are added to a liquidity pool or cold wallet and removed from staking on proposals:\n",
    "$$L^+ = L + tokens$$ \n",
    "$$E^+ = E - tokens$$ \n",
    "\n",
    "When tokens are removed from a liquidity pool or cold wallet and staked towards proposals:\n",
    "$$L^+ = L - tokens$$ \n",
    "$$E^+ = E + tokens$$\n",
    "\n",
    "Tokens in $L$ or $E$ are defined at the level of the account holding them.\n",
    "\n",
    "Total supply $S$ can be made a param and the state supply should be only $E$, effective supply."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## cadCAD Overview\n",
    "\n",
    "In the cadCAD simulation [methodology](https://community.cadcad.org/t/differential-specification-syntax-key/31), we operate on four layers: **Policies, Mechanisms, States**, and **Metrics**. Information flows do not have explicit feedback loop unless noted. **Policies** determine the inputs into the system dynamics, and can come from user input, observations from the exogenous environment, or algorithms. **Mechanisms** are functions that take the policy decisions and update the States to reflect the policy level changes. **States** are variables that represent the system quantities at the given point in time, and **Metrics** are computed from state variables to assess the health of the system. Metrics can often be thought of as KPIs, or Key Performance Indicators. \n",
    "\n",
    "At a more granular level, to setup a model, there are system conventions and configurations that must be [followed.](https://community.cadcad.org/t/introduction-to-simulation-configurations/34)\n",
    "\n",
    "The way to think of cadCAD modeling is analogous to machine learning pipelines which normally consist of multiple steps when training and running a deployed model. There is preprocessing, which includes segregating features between continuous and categorical, transforming or imputing data, and then instantiating, training, and running a machine learning model with specified hyperparameters. cadCAD modeling can be thought of in the same way as states, roughly translating into features, are fed into pipelines that have built-in logic to direct traffic between different mechanisms, such as scaling and imputation. Accuracy scores, ROC, etc. are analogous to the metrics that can be configured on a cadCAD model, specifying how well a given model is doing in meeting its objectives. The parameter sweeping capability of cadCAD can be thought of as a grid search, or way to find the optimal hyperparameters for a system by running through alternative scenarios. A/B style testing that cadCAD enables is used in the same way machine learning models are A/B tested, except out of the box, in providing a side by side comparison of muliple different models to compare and contrast performance. Utilizing the field of Systems Identification, dynamical systems models can be used to \"online learn\" by providing a feedback loop to generative system mechanisms. \n",
    "\n",
    "\n",
    "## Differential Specification \n",
    "![](images/Aragon_v3.png)\n",
    "\n",
    "## File structure\n",
    "* ```Aragon_Conviction_Voting_Model.ipynb```\n",
    "* model\n",
    "\n",
    "In the model folder there exist 4 files and folder, the [```config.py```](model/config.py), [```partial_state_update_block.py```](model/partial_state_update_block.py), [```run.py```](model/run.py), and [```state_variables.py```](model/state_variables.py). The [```config.py```](model/config.py) contains the simulation configurations, aggregating the partial states, and the state variables. The [```partial_state_update_block.py```](model/partial_state_update_block.py) contains the partial state update blocks and how they update the state variables. [```state_variables.py```](model/state_variables.py) defines the state variables and [```run.py```](model/run.py) actually runs the simulation.\n",
    "\n",
    "The mechanisms of the model live within the parts subfolder as:\n",
    "* [```system.py```](model/parts/system.py)\n",
    "* [```participants.py```](model/parts/participants.py)\n",
    "* [```proposals.py```](model/parts/proposals.py)\n",
    "\n",
    "The initial parameters and hyperparameters of the system are defined in [```sys_params.py```](model/sys_params.py) and helper functions, plots, trigger function, etc are in the [```utils.py```](model/utils.py).\n",
    "\n",
    "### Note:\n",
    "When running this notebook simulation, be sure to run from \"Kernal\" -> \"Restart & Run All\"\n",
    "\n",
    "## Schema of the states \n",
    "The model consists of a temporal in memory graph database called *network* containing nodes of type **Participant** and type **Proposal**. Participants will have *holdings* and *sentiment* and Proposals will have *funds_required, status*(candidate or active), *conviction* Tthe model as three kinds of edges:\n",
    "* (Participant, participant), we labeled this edge type \"influencer\" and it contains information about how the preferences and sentiment of one participant influence another \n",
    "* (Proposal, Proposal), we labeled this edge type \"conflict\" and it contains information about how synergistic or anti-synergistic two proposals are; basically people are likely to support multiple things that have synergy (meaning once one is passed there is more utility from the other) but they are not likely to pass things that have antisynergy (meaning once one is passed there is less utility from the other).\n",
    "* The edges between Participant and Proposal, which are described below.\n",
    "    \n",
    "\n",
    "Edges in the network go from nodes of type Participant to nodes of type Proposal with the edges having the key *type*, of which all will be set to *support*. Edges from participant $i$ to proposal $j$ will have the following additional characteristics:\n",
    "* Each pairing (i,j) will have *affinity*, which determines how much $i$ likes or dislikes proposal $j$.\n",
    "* Each participant $i$, assigns its $tokens$ over the edges (i,j) for all $j$ such that the summation of all $j$ such that ```Sum_j = network.edges[(i,j)]['tokens'] = network.nodes[i]['holdings']```. This value of tokens for participants on proposals must be less than or equal to the total number of tokens held by the participant.\n",
    "* Each pairing (i,j) will have *conviction* local to that edge whose update at each timestep is computed using the value of *tokens* at that edge.\n",
    "* Each proposal *j* will have a *conviction* which is equal to the sum of the conviction on its inbound edges: ```network.nodes[j]['conviction'] = Sum_i  network.edges[(i,j)]['conviction']```. \n",
    "\n",
    "\n",
    "The other state variables in the model are *funds*, *sentiment*, *effective_supply*, and *total_supply*.\n",
    "\n",
    "The system consists of 100 time steps without a parameter sweep or monte carlo.\n",
    "\n",
    " \n",
    "## Partial State Update Blocks \n",
    "\n",
    "Each partial state update block is kind of a like a phase in a phased based board game. Everyone decides what to do and it reconciles all decisions. One timestep is a full turn, with each block being a phase of a timestep or turn. We will walk through the individaul Partial State update blocks one by one below."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "```\n",
    "{\n",
    "# system.py: \n",
    "'policies': { \n",
    "    'random': driving_process\n",
    "},\n",
    "'variables': {\n",
    "    'network': update_network,\n",
    "    'effective_supply':increment_supply,\n",
    "}\n",
    "```\n",
    "\n",
    "To simulate the arrival of participants and proposal into the system, we have a driving process to represent the arrival of individual agents. We use a random uniform distribution generator, over [0, 1), to calculate the number of new participants. We then use an exponential distribution to calculate the particpant's tokens by using a loc of 0.0 and a scale of expected holdings, which is calculated by .1*supply/number of existing participants. We calculate the number of new proposals by     \n",
    "```\n",
    "proposal_rate = 1/median_affinity * (1+total_funds_requested/funds)\n",
    "rv2 = np.random.rand()\n",
    "new_proposal = bool(rv2<1/proposal_rate)\n",
    "```\n",
    "The network state variable is updated to include the new participants and proposals, while the *effective_supply state variable is updated for the additiona of new particpant's funds. \n",
    "```\n",
    " {\n",
    "    'policies': { \n",
    "        'random': minting_rule\n",
    "    },\n",
    "    'variables': {\n",
    "        'total_supply': mint_to_supply,\n",
    "        'funds':mint_to_funds,\n",
    "\n",
    "    }\n",
    "},\n",
    "```\n",
    "A behavior called *minting_rule* is included to record the general expansion of system supply every day. The *total_supply* and *funds* state variables are incrased with these minted values.\n",
    "[To see the partial state update's code, click here](model/parts/system.py)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "```\n",
    "{\n",
    "  # participants.py   \n",
    "  'policies': {\n",
    "      'completion': check_progress \n",
    "    },\n",
    "    'variables': { \n",
    "        'sentiment': update_sentiment_on_completion, #not completing projects decays sentiment, completing bumps it\n",
    "        'network': complete_proposal\n",
    "    }\n",
    "},\n",
    "```\n",
    "\n",
    "In the next phase of the turn, [to see the logic code, click here](model/parts/participants.py), the *check_progress* behavior checks for the completion of previously funded proposals. The code calculates the completion and failure rates as follows:\n",
    "\n",
    "```\n",
    "likelihood = 1.0/(base_completion_rate+np.log(grant_size))\n",
    "\n",
    "failure_rate = 1.0/(base_failure_rate+np.log(grant_size))\n",
    "if np.random.rand() < likelihood:\n",
    "    completed.append(j)\n",
    "elif np.random.rand() < failure_rate:\n",
    "    failed.append(j)\n",
    "```\n",
    "With the base_completion_rate being 100 and the base_failure_rate as 200. \n",
    "\n",
    "The mechanism then updates the respective *network* nodes and updates the sentiment variable on proposal completion. "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "```\n",
    "  # proposals.py\n",
    "  'policies': {\n",
    "      'release': trigger_function \n",
    "    },\n",
    "    'variables': { \n",
    "        'funds': decrement_funds, \n",
    "        'sentiment': update_sentiment_on_release, #releasing funds can bump sentiment\n",
    "        'network': update_proposals \n",
    "    }\n",
    "},\n",
    " ```\n",
    " \n",
    "The [trigger release function](model/parts/proposals.py) checks to see if each proposal passes or not. If a proposal passes, funds are decremented by the amount of the proposal, while the proposal's status is changed in the network object."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "```\n",
    "{ \n",
    "    # participants.py\n",
    "    'policies': { \n",
    "        'participants_act': participants_decisions\n",
    "    },\n",
    "    'variables': {\n",
    "        'network': update_tokens \n",
    "    }\n",
    "}\n",
    "```\n",
    "\n",
    "The Participants decide based on their affinity if which proposals they would like to support,[to see the logic code, click here](model/parts/participants.py). Proposals that participants have high affinity for receive more support and pledged tokens than proposals with lower affinity and sentiment. We then update everyone's holdings and their conviction for each proposal.\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Model next steps\n",
    "\n",
    "The the model described above is the third iteration model that covers the core mechanisms of the Aragon Conviction Voting model. Below are next additional dynamics we can attend to enrich the model, and provide workstreams for subsequent iterations of this lab notebook.\n",
    "\n",
    "* Add a uniswap instance\n",
    "    * A next step to model the 1Hive ecosystem would be to model the Uniswap interface. With this interface, agents would be able to add or remove liquidity, buy or redeem Honey for more voting power, and ultimately enter or leave the system. \n",
    "* Mixing of token holdings among participants\n",
    "    * Introducing heterogeneous token holdings would be another next step in creating a model more representative of the live system.\n",
    "* Proposals which are good or no good together\n",
    "    * Introducing conflict \n",
    "* Affects of outcomes on sentiment"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Simulation"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Configuration\n",
    "Let's factor out into its own notebook where we review the config object and its partial state update blocks. We will initialize the network x object and pull out the simulation configuration, state_variables, and partial state update blocks from the [config.py](model/config.py)."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Params (config.py) :  {'beta': 0.2, 'rho': 0.0025, 'alpha': 0.7937005259840998, 'gamma': 0.001, 'sensitivity': 0.75, 'tmin': 1, 'min_supp': 1, 'base_completion_rate': 45, 'base_failure_rate': 180, 'base_engagement_rate': 0.3, 'lowest_affinity_to_support': 0.3}\n"
     ]
    },
    {
     "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": [
    "from model import config\n",
    "from model.parts.sys_params import initial_values\n",
    "from model.parts.utils import *"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "from copy import deepcopy\n",
    "from cadCAD import configs\n",
    "\n",
    "# Initialize network x\n",
    "for c in configs:\n",
    "    c.initial_state = deepcopy(c.initial_state)\n",
    "    c.initial_state['network'] = initialize_network(initial_values['n'],initial_values['m'],\n",
    "                                            initial_values['initial_funds'],\n",
    "                                            initial_values['supply'],c.sim_config['M'])\n",
    "    \n",
    "# pull out configurations to illustrate\n",
    "sim_config,state_variables,partial_state_update_blocks = config.get_configs()\n",
    "state_variables['network'] = c.initial_state['network']"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[{'policies': {'random': <function model.parts.system.driving_process(params, step, sL, s)>},\n",
       "  'variables': {'network': <function model.parts.system.update_network(params, step, sL, s, _input)>,\n",
       "   'effective_supply': <function model.parts.system.increment_supply(params, step, sL, s, _input)>}},\n",
       " {'policies': {'random': <function model.parts.system.minting_rule(params, step, sL, s)>},\n",
       "  'variables': {'total_supply': <function model.parts.system.mint_to_supply(params, step, sL, s, _input)>,\n",
       "   'funds': <function model.parts.system.mint_to_funds(params, step, sL, s, _input)>}},\n",
       " {'policies': {'completion': <function model.parts.participants.check_progress(params, step, sL, s)>},\n",
       "  'variables': {'sentiment': <function model.parts.participants.update_sentiment_on_completion(params, step, sL, s, _input)>,\n",
       "   'network': <function model.parts.participants.complete_proposal(params, step, sL, s, _input)>}},\n",
       " {'policies': {'release': <function model.parts.proposals.trigger_function(params, step, sL, s)>},\n",
       "  'variables': {'funds': <function model.parts.proposals.decrement_funds(params, step, sL, s, _input)>,\n",
       "   'sentiment': <function model.parts.proposals.update_sentiment_on_release(params, step, sL, s, _input)>,\n",
       "   'network': <function model.parts.proposals.update_proposals(params, step, sL, s, _input)>}},\n",
       " {'policies': {'participants_act': <function model.parts.participants.participants_decisions(params, step, sL, s)>},\n",
       "  'variables': {'network': <function model.parts.participants.update_tokens(params, step, sL, s, _input)>}}]"
      ]
     },
     "execution_count": 3,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "partial_state_update_blocks"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Parameters\n",
    "\n",
    "Initial values are the starting values for the simulation."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{'initial_sentiment': 0.6,\n",
       " 'n': 30,\n",
       " 'm': 7,\n",
       " 'initial_funds': 4867.21,\n",
       " 'supply': 22392.22}"
      ]
     },
     "execution_count": 4,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "initial_values"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "$n$ is initial participants, whereas $m$ is initial proposals.\n",
    "\n",
    "Sim_config holds the global hyperparameters for the simulations"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{'beta': 0.2,\n",
       " 'rho': 0.0025,\n",
       " 'alpha': 0.7937005259840998,\n",
       " 'gamma': 0.001,\n",
       " 'sensitivity': 0.75,\n",
       " 'tmin': 1,\n",
       " 'min_supp': 1,\n",
       " 'base_completion_rate': 45,\n",
       " 'base_failure_rate': 180,\n",
       " 'base_engagement_rate': 0.3,\n",
       " 'lowest_affinity_to_support': 0.3}"
      ]
     },
     "execution_count": 5,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "sim_config[0]['M']"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Initial state variable values"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{'network': <networkx.classes.digraph.DiGraph at 0x7fe4fb288c50>,\n",
       " 'funds': 4867.21,\n",
       " 'sentiment': 0.6,\n",
       " 'effective_supply': 14020.008000000002,\n",
       " 'total_supply': 22392.22}"
      ]
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "state_variables"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Hyperparameter explanations:\n",
    "* $\\beta$ = .2  Upper bound on share of funds dispersed in the example Trigger Function\n",
    "* $\\rho$ = 0.002  Scale Parameter for the example Trigger Function\n",
    "* $\\alpha$ : 0.79370 timescale set in days with 3 day halflife\n",
    "* $\\gamma$: 0.001 The expansion of supply per per day\n",
    "* sensitivity of participant decisions to changes in affinity \n",
    "* tmin = 1 unit days; minimum periods passed before a proposal can pass\n",
    "* min_supp = 50 number of tokens that must be stake for a proposal to be a candidate\n",
    "* base_completion_rate': 45,  # expected number of days to complete a proposals.\n",
    "* base_failure_rate': [180], # expected number of days until a proposal will fail\n",
    "* base_engagement_rate' :[0.3], # Probability of being active on a certain day if 100% sentiment\n",
    "* lowest_affinity_to_support': [0.3],# lowest affinity to required to support a proposal\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### Exploring the State Data Structure\n",
    "\n",
    "A graph is a type of temporal data structure that evolves over time. A graph $\\mathcal{G}(\\mathcal{V},\\mathcal{E})$ consists of vertices or nodes, $\\mathcal{V} = \\{1...\\mathcal{V}\\}$ and is connected by edges  $\\mathcal{E} \\subseteq \\mathcal{V} \\times \\mathcal{V}$.\n",
    "\n",
    "See *Schema of the states* above for more details\n",
    "\n",
    "\n",
    "Let's explore!"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [],
   "source": [
    "# To explore our model prior to the simulation, we extract key components from our networkX object into lists.\n",
    "proposals = get_nodes_by_type(state_variables['network'], 'proposal')\n",
    "participants = get_nodes_by_type(state_variables['network'], 'participant')\n",
    "supporters = get_edges_by_type(state_variables['network'], 'support')\n",
    "influencers = get_edges_by_type(state_variables['network'], 'influence')\n",
    "competitors = get_edges_by_type(state_variables['network'], 'conflict')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{'type': 'participant',\n",
       " 'holdings': 758.4701233898538,\n",
       " 'sentiment': 0.36153123371230367}"
      ]
     },
     "execution_count": 8,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "#sample a participant\n",
    "state_variables['network'].nodes[participants[0]]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Text(0, 0.5, 'Count of Participants')"
      ]
     },
     "execution_count": 9,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "image/png": "[encoded data, 11188 characters]\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "# Let's look at the distribution of participant holdings at the start of the sim\n",
    "plt.hist([ state_variables['network'].nodes[i]['holdings'] for i in participants])\n",
    "plt.title('Histogram of Participants Token Holdings')\n",
    "plt.xlabel('Amount of Honey')\n",
    "plt.ylabel('Count of Participants')\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "/home/aclarkdata/anaconda3/lib/python3.7/site-packages/networkx/drawing/nx_pylab.py:563: MatplotlibDeprecationWarning: \n",
      "The iterable function was deprecated in Matplotlib 3.1 and will be removed in 3.3. Use np.iterable instead.\n",
      "  if not cb.iterable(width):\n",
      "/home/aclarkdata/anaconda3/lib/python3.7/site-packages/networkx/drawing/nx_pylab.py:660: MatplotlibDeprecationWarning: \n",
      "The iterable function was deprecated in Matplotlib 3.1 and will be removed in 3.3. Use np.iterable instead.\n",
      "  if cb.iterable(node_size):  # many node sizes\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "Text(0.5, 1.0, 'Participants Social Network')"
      ]
     },
     "execution_count": 10,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "image/png": "[encoded data, 93668 characters]\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "nx.draw_spring(state_variables['network'], nodelist = participants, edgelist=influencers)\n",
    "plt.title('Participants Social Network')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{'type': 'proposal',\n",
       " 'conviction': 0,\n",
       " 'status': 'candidate',\n",
       " 'age': 0,\n",
       " 'funds_requested': 1635.5704024958463,\n",
       " 'trigger': inf}"
      ]
     },
     "execution_count": 11,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "#lets look at proposals\n",
    "state_variables['network'].nodes[proposals[0]]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Proposals initially start without any conviction, and with the status of a candidate. If the proposal's amount of  conviction is greater than it's trigger, then the proposal moves to active and it's funds requested are granted. "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "All initial proposal start with 0 conviction and state 'candidate'we can simply examine the amounts of funds requested"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [],
   "source": [
    "funds_array = np.array([ state_variables['network'].nodes[i]['funds_requested'] for i in proposals])\n",
    "conviction_required = np.array([trigger_threshold(r, initial_values['initial_funds'], initial_values['supply'], sim_config[0]['M']['alpha'],sim_config[0]['M']) for r in funds_array])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Text(0, 0.5, 'Amount of Honey requested(as a Fraction of Funds available)')"
      ]
     },
     "execution_count": 13,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "image/png": "[encoded data, 14352 characters]\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "plt.bar( proposals, funds_array/initial_values['initial_funds'])\n",
    "plt.title('Bar chart of Proposals Funds Requested')\n",
    "plt.xlabel('Proposal identifier')\n",
    "plt.ylabel('Amount of Honey requested(as a Fraction of Funds available)')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Text(0, 0.5, 'Amount of Conviction')"
      ]
     },
     "execution_count": 14,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "image/png": "[encoded data, 11800 characters]\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "plt.bar( proposals, conviction_required)\n",
    "plt.title('Bar chart of Proposals Conviction Required')\n",
    "plt.xlabel('Proposal identifier')\n",
    "plt.ylabel('Amount of Conviction')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Conviction is a concept that arises in the edges between participants and proposals in the initial conditions there are no votes yet so we can look at that later however, the voting choices are driven by underlying affinities which we can see now."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Text(0.5, 55.73999999999998, 'Participant_id')"
      ]
     },
     "execution_count": 15,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "image/png": "[encoded data, 19124 characters]\n",
      "text/plain": [
       "<Figure size 1440x360 with 2 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "m = len(proposals)\n",
    "n = len(participants)\n",
    "\n",
    "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] = state_variables['network'].edges[(i,j)]['affinity']\n",
    "\n",
    "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",
    "            cmap = plt.cm.RdYlGn,\n",
    "            ax=ax)\n",
    "\n",
    "plt.title('Affinities between participants and proposals')\n",
    "plt.ylabel('Proposal_id')\n",
    "plt.xlabel('Participant_id')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Run simulation\n",
    "\n",
    "Now we will create the final system configuration, append the genesis states we created, and run our simulation."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [],
   "source": [
    "from cadCAD.configuration import Experiment\n",
    "\n",
    "# Create configuration\n",
    "exp = Experiment()\n",
    "\n",
    "exp.append_configs(\n",
    "    sim_configs=sim_config,\n",
    "    initial_state=state_variables,\n",
    "    seeds=1,\n",
    "    partial_state_update_blocks=partial_state_update_blocks\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "                  ___________    ____\n",
      "  ________ __ ___/ / ____/   |  / __ \\\n",
      " / ___/ __` / __  / /   / /| | / / / /\n",
      "/ /__/ /_/ / /_/ / /___/ ___ |/ /_/ /\n",
      "\\___/\\__,_/\\__,_/\\____/_/  |_/_____/\n",
      "by cadCAD\n",
      "\n",
      "Execution Mode: local_proc\n",
      "Configuration Count: 2\n",
      "Dimensions of the first simulation: (Timesteps, Params, Runs, Vars) = (100, 11, 1, 5)\n",
      "Execution Method: local_simulations\n",
      "SimIDs   : [0, 1]\n",
      "SubsetIDs: [0, 0]\n",
      "Ns       : [0, 0]\n",
      "ExpIDs   : [0, 0]\n",
      "Total execution time: 324.40s\n"
     ]
    }
   ],
   "source": [
    "import numpy as np\n",
    "import pandas as pd\n",
    "from model import run\n",
    "pd.options.display.float_format = '{:.2f}'.format\n",
    "\n",
    "%matplotlib inline\n",
    "\n",
    "rdf = run.run()\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "After the simulation has run successfully, we perform some postprocessing to extract node and edge values from the network object and add as columns to the pandas dataframe. For the rdf, we take only the values at the last substep of each timestep in the simulation."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {},
   "outputs": [],
   "source": [
    "df= run.postprocessing(rdf,0)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "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>funds</th>\n",
       "      <th>sentiment</th>\n",
       "      <th>effective_supply</th>\n",
       "      <th>total_supply</th>\n",
       "      <th>simulation</th>\n",
       "      <th>subset</th>\n",
       "      <th>run</th>\n",
       "      <th>substep</th>\n",
       "      <th>timestep</th>\n",
       "      <th>...</th>\n",
       "      <th>funds_requested</th>\n",
       "      <th>share_of_funds_requested</th>\n",
       "      <th>share_of_funds_requested_all</th>\n",
       "      <th>triggers</th>\n",
       "      <th>conviction_share_of_trigger</th>\n",
       "      <th>age</th>\n",
       "      <th>age_all</th>\n",
       "      <th>conviction_all</th>\n",
       "      <th>triggers_all</th>\n",
       "      <th>conviction_share_of_trigger_all</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>5</th>\n",
       "      <td>(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,...</td>\n",
       "      <td>4889.60</td>\n",
       "      <td>0.60</td>\n",
       "      <td>14020.01</td>\n",
       "      <td>22414.61</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>1</td>\n",
       "      <td>5</td>\n",
       "      <td>1</td>\n",
       "      <td>...</td>\n",
       "      <td>[1635.5704024958463, 2177.89207462645, 375.000...</td>\n",
       "      <td>[0.33449968502669863, 0.4454129347614804, 0.07...</td>\n",
       "      <td>[0.33449968502669863, 0.4454129347614804, 0.07...</td>\n",
       "      <td>[inf, inf, 11238.455532714786, 633287.50254494...</td>\n",
       "      <td>[0.0, 0.0, 0.003740978192469739, 0.00047483075...</td>\n",
       "      <td>[1, 1, 1, 1, 1, 1]</td>\n",
       "      <td>[1, 1, 1, 1, 1, 1, 1]</td>\n",
       "      <td>[266.503232036339, 52.749078945560456, 42.0428...</td>\n",
       "      <td>[inf, inf, 11238.455532714786, 633287.50254494...</td>\n",
       "      <td>[0.0, 0.0, 0.003740978192469739, 0.00047483075...</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>10</th>\n",
       "      <td>(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,...</td>\n",
       "      <td>4912.02</td>\n",
       "      <td>0.60</td>\n",
       "      <td>14020.01</td>\n",
       "      <td>22437.03</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>1</td>\n",
       "      <td>5</td>\n",
       "      <td>2</td>\n",
       "      <td>...</td>\n",
       "      <td>[1635.5704024958463, 2177.89207462645, 375.000...</td>\n",
       "      <td>[0.3329732894576922, 0.44338041766077285, 0.07...</td>\n",
       "      <td>[0.3329732894576922, 0.44338041766077285, 0.07...</td>\n",
       "      <td>[inf, inf, 11174.230590474432, 572947.78483859...</td>\n",
       "      <td>[0.0, 0.0, 0.015214500767545958, 0.00094140099...</td>\n",
       "      <td>[2, 2, 2, 2, 2, 2, 1, 1]</td>\n",
       "      <td>[2, 2, 2, 2, 2, 2, 2, 1, 1]</td>\n",
       "      <td>[541.366516506568, 94.6160506498286, 170.01033...</td>\n",
       "      <td>[inf, inf, 11174.230590474432, 572947.78483859...</td>\n",
       "      <td>[0.0, 0.0, 0.015214500767545958, 0.00094140099...</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>15</th>\n",
       "      <td>(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,...</td>\n",
       "      <td>4934.45</td>\n",
       "      <td>0.60</td>\n",
       "      <td>14020.01</td>\n",
       "      <td>22459.46</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>1</td>\n",
       "      <td>5</td>\n",
       "      <td>3</td>\n",
       "      <td>...</td>\n",
       "      <td>[1635.5704024958463, 2177.89207462645, 375.000...</td>\n",
       "      <td>[0.3314592555152592, 0.44136436104901916, 0.07...</td>\n",
       "      <td>[0.3314592555152592, 0.44136436104901916, 0.07...</td>\n",
       "      <td>[inf, inf, 11111.070175797702, 521232.83488613...</td>\n",
       "      <td>[0.0, 0.0, 0.02444213075591761, 0.001102536686...</td>\n",
       "      <td>[3, 3, 3, 3, 3, 3, 2, 2]</td>\n",
       "      <td>[3, 3, 3, 3, 3, 3, 3, 2, 2]</td>\n",
       "      <td>[622.9283976334391, 127.84588811286764, 271.57...</td>\n",
       "      <td>[inf, inf, 11111.070175797702, 521232.83488613...</td>\n",
       "      <td>[0.0, 0.0, 0.02444213075591761, 0.001102536686...</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>20</th>\n",
       "      <td>(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,...</td>\n",
       "      <td>4956.91</td>\n",
       "      <td>0.60</td>\n",
       "      <td>14069.75</td>\n",
       "      <td>22481.92</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>1</td>\n",
       "      <td>5</td>\n",
       "      <td>4</td>\n",
       "      <td>...</td>\n",
       "      <td>[1635.5704024958463, 2177.89207462645, 375.000...</td>\n",
       "      <td>[0.3299574343848422, 0.43936456676780056, 0.07...</td>\n",
       "      <td>[0.3299574343848422, 0.43936456676780056, 0.07...</td>\n",
       "      <td>[inf, inf, 11048.948812591681, 476557.06400915...</td>\n",
       "      <td>[0.0, 0.0, 0.03187567649261185, 0.001264695738...</td>\n",
       "      <td>[4, 4, 4, 4, 4, 4, 3, 3, 1]</td>\n",
       "      <td>[4, 4, 4, 4, 4, 4, 4, 3, 3, 1, 1]</td>\n",
       "      <td>[687.6641055840894, 154.22042758564788, 352.19...</td>\n",
       "      <td>[inf, inf, 11048.948812591681, 476557.06400915...</td>\n",
       "      <td>[0.0, 0.0, 0.03187567649261185, 0.001264695738...</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>25</th>\n",
       "      <td>(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,...</td>\n",
       "      <td>4979.40</td>\n",
       "      <td>0.60</td>\n",
       "      <td>14069.75</td>\n",
       "      <td>22504.41</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>1</td>\n",
       "      <td>5</td>\n",
       "      <td>5</td>\n",
       "      <td>...</td>\n",
       "      <td>[1635.5704024958463, 2177.89207462645, 375.000...</td>\n",
       "      <td>[0.3284676796309342, 0.4373808398265926, 0.075...</td>\n",
       "      <td>[0.3284676796309342, 0.4373808398265926, 0.075...</td>\n",
       "      <td>[inf, inf, 11026.824827540717, 439237.51613763...</td>\n",
       "      <td>[0.0, 0.0, 0.036126338828180254, 0.00142278434...</td>\n",
       "      <td>[5, 5, 5, 5, 5, 5, 4, 4, 2, 1, 1]</td>\n",
       "      <td>[5, 5, 5, 5, 5, 5, 5, 4, 4, 2, 2, 1, 1]</td>\n",
       "      <td>[739.0448710344735, 152.79894968865366, 398.35...</td>\n",
       "      <td>[inf, inf, 11026.824827540717, 439237.51613763...</td>\n",
       "      <td>[0.0, 0.0, 0.036126338828180254, 0.00142278434...</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "<p>5 rows × 33 columns</p>\n",
       "</div>"
      ],
      "text/plain": [
       "                                              network   funds  sentiment  \\\n",
       "5   (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,... 4889.60       0.60   \n",
       "10  (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,... 4912.02       0.60   \n",
       "15  (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,... 4934.45       0.60   \n",
       "20  (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,... 4956.91       0.60   \n",
       "25  (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,... 4979.40       0.60   \n",
       "\n",
       "    effective_supply  total_supply  simulation  subset  run  substep  \\\n",
       "5           14020.01      22414.61           0       0    1        5   \n",
       "10          14020.01      22437.03           0       0    1        5   \n",
       "15          14020.01      22459.46           0       0    1        5   \n",
       "20          14069.75      22481.92           0       0    1        5   \n",
       "25          14069.75      22504.41           0       0    1        5   \n",
       "\n",
       "    timestep  ...                                    funds_requested  \\\n",
       "5          1  ...  [1635.5704024958463, 2177.89207462645, 375.000...   \n",
       "10         2  ...  [1635.5704024958463, 2177.89207462645, 375.000...   \n",
       "15         3  ...  [1635.5704024958463, 2177.89207462645, 375.000...   \n",
       "20         4  ...  [1635.5704024958463, 2177.89207462645, 375.000...   \n",
       "25         5  ...  [1635.5704024958463, 2177.89207462645, 375.000...   \n",
       "\n",
       "                             share_of_funds_requested  \\\n",
       "5   [0.33449968502669863, 0.4454129347614804, 0.07...   \n",
       "10  [0.3329732894576922, 0.44338041766077285, 0.07...   \n",
       "15  [0.3314592555152592, 0.44136436104901916, 0.07...   \n",
       "20  [0.3299574343848422, 0.43936456676780056, 0.07...   \n",
       "25  [0.3284676796309342, 0.4373808398265926, 0.075...   \n",
       "\n",
       "                         share_of_funds_requested_all  \\\n",
       "5   [0.33449968502669863, 0.4454129347614804, 0.07...   \n",
       "10  [0.3329732894576922, 0.44338041766077285, 0.07...   \n",
       "15  [0.3314592555152592, 0.44136436104901916, 0.07...   \n",
       "20  [0.3299574343848422, 0.43936456676780056, 0.07...   \n",
       "25  [0.3284676796309342, 0.4373808398265926, 0.075...   \n",
       "\n",
       "                                             triggers  \\\n",
       "5   [inf, inf, 11238.455532714786, 633287.50254494...   \n",
       "10  [inf, inf, 11174.230590474432, 572947.78483859...   \n",
       "15  [inf, inf, 11111.070175797702, 521232.83488613...   \n",
       "20  [inf, inf, 11048.948812591681, 476557.06400915...   \n",
       "25  [inf, inf, 11026.824827540717, 439237.51613763...   \n",
       "\n",
       "                          conviction_share_of_trigger  \\\n",
       "5   [0.0, 0.0, 0.003740978192469739, 0.00047483075...   \n",
       "10  [0.0, 0.0, 0.015214500767545958, 0.00094140099...   \n",
       "15  [0.0, 0.0, 0.02444213075591761, 0.001102536686...   \n",
       "20  [0.0, 0.0, 0.03187567649261185, 0.001264695738...   \n",
       "25  [0.0, 0.0, 0.036126338828180254, 0.00142278434...   \n",
       "\n",
       "                                  age  \\\n",
       "5                  [1, 1, 1, 1, 1, 1]   \n",
       "10           [2, 2, 2, 2, 2, 2, 1, 1]   \n",
       "15           [3, 3, 3, 3, 3, 3, 2, 2]   \n",
       "20        [4, 4, 4, 4, 4, 4, 3, 3, 1]   \n",
       "25  [5, 5, 5, 5, 5, 5, 4, 4, 2, 1, 1]   \n",
       "\n",
       "                                    age_all  \\\n",
       "5                     [1, 1, 1, 1, 1, 1, 1]   \n",
       "10              [2, 2, 2, 2, 2, 2, 2, 1, 1]   \n",
       "15              [3, 3, 3, 3, 3, 3, 3, 2, 2]   \n",
       "20        [4, 4, 4, 4, 4, 4, 4, 3, 3, 1, 1]   \n",
       "25  [5, 5, 5, 5, 5, 5, 5, 4, 4, 2, 2, 1, 1]   \n",
       "\n",
       "                                       conviction_all  \\\n",
       "5   [266.503232036339, 52.749078945560456, 42.0428...   \n",
       "10  [541.366516506568, 94.6160506498286, 170.01033...   \n",
       "15  [622.9283976334391, 127.84588811286764, 271.57...   \n",
       "20  [687.6641055840894, 154.22042758564788, 352.19...   \n",
       "25  [739.0448710344735, 152.79894968865366, 398.35...   \n",
       "\n",
       "                                         triggers_all  \\\n",
       "5   [inf, inf, 11238.455532714786, 633287.50254494...   \n",
       "10  [inf, inf, 11174.230590474432, 572947.78483859...   \n",
       "15  [inf, inf, 11111.070175797702, 521232.83488613...   \n",
       "20  [inf, inf, 11048.948812591681, 476557.06400915...   \n",
       "25  [inf, inf, 11026.824827540717, 439237.51613763...   \n",
       "\n",
       "                      conviction_share_of_trigger_all  \n",
       "5   [0.0, 0.0, 0.003740978192469739, 0.00047483075...  \n",
       "10  [0.0, 0.0, 0.015214500767545958, 0.00094140099...  \n",
       "15  [0.0, 0.0, 0.02444213075591761, 0.001102536686...  \n",
       "20  [0.0, 0.0, 0.03187567649261185, 0.001264695738...  \n",
       "25  [0.0, 0.0, 0.036126338828180254, 0.00142278434...  \n",
       "\n",
       "[5 rows x 33 columns]"
      ]
     },
     "execution_count": 19,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "df.head(5)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<matplotlib.axes._subplots.AxesSubplot at 0x7fe4f05b7290>"
      ]
     },
     "execution_count": 20,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "image/png": "[encoded data, 17280 characters]\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "df.plot('timestep','sentiment')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The above plot demonstrates system sentiment changing over time as proposals pass or fail."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<matplotlib.axes._subplots.AxesSubplot at 0x7fe4c76d6b10>"
      ]
     },
     "execution_count": 21,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "image/png": "[encoded data, 20180 characters]\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "df.plot('timestep',['funds', 'candidate_funds'])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Funds represent the total available funds, whereas candidate funds represent total funds requested by candidate proposals."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 58496 characters]\n",
      "text/plain": [
       "<Figure size 612x792 with 2 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "affinities_plot(df)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The above matrix represents participant affinities towards proposals, ranging from -1 to +1."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<matplotlib.legend.Legend at 0x7fe4a30e0c50>"
      ]
     },
     "execution_count": 23,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "image/png": "[encoded data, 36508 characters]\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "df.plot(x='timestep',y=['candidate_count','active_count','completed_count', 'killed_count', 'failed_count'],\n",
    "         kind='area')\n",
    "plt.title('Proposal Status')\n",
    "plt.ylabel('count of proposals')\n",
    "plt.legend(ncol = 3,loc='upper center', bbox_to_anchor=(0.5, -0.15))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The above graph shows the number of various types of proposals at a range of timesteps. Ecosystems with more completed proposals will have higher overall agent sentiment than systems with more failed and killed proposals."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<matplotlib.legend.Legend at 0x7fe484aabd50>"
      ]
     },
     "execution_count": 24,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "image/png": "[encoded data, 36416 characters]\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "df.plot(x='timestep',y=['candidate_funds','active_funds','completed_funds', 'killed_funds', 'failed_funds'], kind='area')\n",
    "plt.title('Proposal Status weighted by funds requested')\n",
    "plt.ylabel('Funds worth of proposals')\n",
    "plt.legend(ncol = 3,loc='upper center', bbox_to_anchor=(0.5, -0.15))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The above graph shows the amount of funds requested by various types of proposals at a range of timesteps."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "metadata": {},
   "outputs": [],
   "source": [
    "nets = df.network.values"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "/home/aclarkdata/anaconda3/lib/python3.7/site-packages/networkx/drawing/nx_pylab.py:563: MatplotlibDeprecationWarning: \n",
      "The iterable function was deprecated in Matplotlib 3.1 and will be removed in 3.3. Use np.iterable instead.\n",
      "  if not cb.iterable(width):\n",
      "/home/aclarkdata/anaconda3/lib/python3.7/site-packages/networkx/drawing/nx_pylab.py:569: MatplotlibDeprecationWarning: \n",
      "The iterable function was deprecated in Matplotlib 3.1 and will be removed in 3.3. Use np.iterable instead.\n",
      "  and cb.iterable(edge_color) \\\n",
      "/home/aclarkdata/anaconda3/lib/python3.7/site-packages/networkx/drawing/nx_pylab.py:579: MatplotlibDeprecationWarning: \n",
      "The iterable function was deprecated in Matplotlib 3.1 and will be removed in 3.3. Use np.iterable instead.\n",
      "  for c in edge_color]):\n",
      "/home/aclarkdata/anaconda3/lib/python3.7/site-packages/networkx/drawing/nx_pylab.py:660: MatplotlibDeprecationWarning: \n",
      "The iterable function was deprecated in Matplotlib 3.1 and will be removed in 3.3. Use np.iterable instead.\n",
      "  if cb.iterable(node_size):  # many node sizes\n",
      "/home/aclarkdata/repos/Aragon_Conviction_Voting/models/v3/model/parts/utils.py:356: UserWarning: This figure includes Axes that are not compatible with tight_layout, so results might be incorrect.\n",
      "  plt.tight_layout()\n"
     ]
    },
    {
     "data": {
      "image/png": "[encoded data, 104312 characters]\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "K = 0\n",
    "N = 1\n",
    "\n",
    "snap_plot(nets[K:N], size_scale = 1/300,savefigs=True)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "On the left side are participants, with the right side of the graph being the proposals. With this graph, we can see the links between the participants and the proposals that they support. The percentage on the right hand are the the amount of the required amount to pass that has been fulfilled.\n",
    "\n",
    "You can move the K and N to different points within the 100 timesteps, 0 indexed, to see how the model evolves overtime. \n",
    "\n",
    "As you can see with the plot above at the start of the simulation, no proposals have been formally supported yet. Below we can see a many interactions between agents and proposals."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 112304 characters]\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "snap_plot(nets[80:81], size_scale = 1/300,savefigs=True)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 28,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<matplotlib.axes._subplots.AxesSubplot at 0x7fe4a3e6c950>"
      ]
     },
     "execution_count": 28,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "image/png": "[encoded data, 15080 characters]\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "df.plot('timestep',['effective_supply'])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 29,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<matplotlib.axes._subplots.AxesSubplot at 0x7fe53888d1d0>"
      ]
     },
     "execution_count": 29,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "image/png": "[encoded data, 11604 characters]\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "df.plot('timestep',['participant_count'])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "As expected *effective_supply* is increasing with the arrival of new participants."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Conclusion\n",
    "\n",
    "We have created a conviction voting model that closely adheres to the 1Hive implementation. This notebook describes the use case, how the model works, and provides descriptions of how it fits together."
   ]
  }
 ],
 "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
}
