├── 1 ├── Spreading Processes on Networks 1.ipynb └── images │ ├── Adelaide.png │ ├── Brisbane.png │ ├── Melbourne.png │ ├── Perth.png │ ├── network_example.png │ └── sydney.png ├── 2 PageRank ├── PageRank worked exercises.ipynb └── PageRank.ipynb ├── 3 Random Graphs ├── CM_generation.png ├── CM_generation0.pdf ├── CM_generation0.png ├── CM_generationneg1.pdf ├── CM_generationneg1.png ├── Random Graphs - with_solns.ipynb ├── Random Graphs Lecture.ipynb ├── final_circle.pdf └── final_circle.png ├── 4 Kuramoto ├── Kuramoto code.ipynb ├── Kuramoto lecture with improved fit.ipynb ├── Kuramoto lecture.ipynb └── weirdoscilliations.png ├── 5 Disease Modeling ├── Intro │ ├── Epidemic Intro.ipynb │ └── SIS_SIR_basic.png ├── SIR analysis │ ├── CM_generation0.png │ ├── CM_generationneg1.png │ ├── Effective_Degree_SIR.png │ ├── SIR - Mathematical Analysis.ipynb │ ├── final_circle.png │ ├── heterogeneous_MF_revised.png │ ├── homogeneous_MF.png │ └── sexual_PL.png └── SIS analysis │ ├── 3nodeSIS.png │ ├── Effective_Degree.png │ └── SIS - Mathematical Analysis.ipynb ├── 6 Complex Contagions ├── Centola_fig1.png ├── Centola_fig2.png └── complex.ipynb ├── Assignments ├── Assignment 1.ipynb ├── Assignment 2.ipynb ├── Assignment 3.ipynb └── Projects.ipynb └── README.md /1/images/Adelaide.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joelmiller/DynamicProcessesOnNetworks/ad7ca239697164fdad9464a60f48f7df8e60e49a/1/images/Adelaide.png -------------------------------------------------------------------------------- /1/images/Brisbane.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joelmiller/DynamicProcessesOnNetworks/ad7ca239697164fdad9464a60f48f7df8e60e49a/1/images/Brisbane.png -------------------------------------------------------------------------------- /1/images/Melbourne.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joelmiller/DynamicProcessesOnNetworks/ad7ca239697164fdad9464a60f48f7df8e60e49a/1/images/Melbourne.png -------------------------------------------------------------------------------- /1/images/Perth.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joelmiller/DynamicProcessesOnNetworks/ad7ca239697164fdad9464a60f48f7df8e60e49a/1/images/Perth.png -------------------------------------------------------------------------------- /1/images/network_example.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joelmiller/DynamicProcessesOnNetworks/ad7ca239697164fdad9464a60f48f7df8e60e49a/1/images/network_example.png -------------------------------------------------------------------------------- /1/images/sydney.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joelmiller/DynamicProcessesOnNetworks/ad7ca239697164fdad9464a60f48f7df8e60e49a/1/images/sydney.png -------------------------------------------------------------------------------- /3 Random Graphs/CM_generation.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joelmiller/DynamicProcessesOnNetworks/ad7ca239697164fdad9464a60f48f7df8e60e49a/3 Random Graphs/CM_generation.png -------------------------------------------------------------------------------- /3 Random Graphs/CM_generation0.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joelmiller/DynamicProcessesOnNetworks/ad7ca239697164fdad9464a60f48f7df8e60e49a/3 Random Graphs/CM_generation0.pdf -------------------------------------------------------------------------------- /3 Random Graphs/CM_generation0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joelmiller/DynamicProcessesOnNetworks/ad7ca239697164fdad9464a60f48f7df8e60e49a/3 Random Graphs/CM_generation0.png -------------------------------------------------------------------------------- /3 Random Graphs/CM_generationneg1.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joelmiller/DynamicProcessesOnNetworks/ad7ca239697164fdad9464a60f48f7df8e60e49a/3 Random Graphs/CM_generationneg1.pdf -------------------------------------------------------------------------------- /3 Random Graphs/CM_generationneg1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joelmiller/DynamicProcessesOnNetworks/ad7ca239697164fdad9464a60f48f7df8e60e49a/3 Random Graphs/CM_generationneg1.png -------------------------------------------------------------------------------- /3 Random Graphs/Random Graphs Lecture.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": { 6 | "deletable": true, 7 | "editable": true 8 | }, 9 | "source": [ 10 | "Edits:\n", 11 | "- I've made a bunch of small edits improving the links to documentation and such.\n", 12 | "- I clarified that you don't need to be writing your own algorithm to generate these networks.\n", 13 | "- I added some images to help demonstrate the construction of Configuration Model Networks, and to help demonstrate the \"size biasing\" effect." 14 | ] 15 | }, 16 | { 17 | "cell_type": "markdown", 18 | "metadata": { 19 | "deletable": true, 20 | "editable": true 21 | }, 22 | "source": [ 23 | "# Random Graphs\n", 24 | "\n" 25 | ] 26 | }, 27 | { 28 | "cell_type": "markdown", 29 | "metadata": { 30 | "deletable": true, 31 | "editable": true 32 | }, 33 | "source": [ 34 | "So far we have looked at the PageRank algorithm. The premise of PageRank and similar algorithms is that the structure of the network contains valuable information which the random surfer concept gives us access to.\n", 35 | "\n", 36 | "We're going to shift gears soon and look at other processes that happen on networks. For these processes, we are going to hypothesize that what happens isn't strongly dependent on finer details of the global structure. We are going to look at how much of these various processes can be explained by what happens on random networks.\n", 37 | "\n", 38 | "The underlying philosophy is that there may be some real-world emergent behavior we want to explain, and that the emergent behavior is robust for a large class of networks. We are going to try to generate the simplest networks for which this emergent behavior exists.\n", 39 | "\n", 40 | "So we start with very simple networks.\n", 41 | "\n", 42 | "Networkx provides methods to produce each of these network classes, so **I am not asking you to** write code to produce these networks. I am however going to give slowly decreasing amounts of guidance on how to use the networkx commands to generate and analyze these graphs. The purpose of this is to get you practice finding commands and instructions on how to use them." 43 | ] 44 | }, 45 | { 46 | "cell_type": "markdown", 47 | "metadata": { 48 | "deletable": true, 49 | "editable": true 50 | }, 51 | "source": [ 52 | "## The Erdős–Rényi network model\n", 53 | "\n", 54 | "In 1959 **Edgar Gilbert** introduced a network model for which there are $N$ nodes, and each pair of nodes has an edge with probability $p$. This model is usually called the Erdős–Rényi network model. It is sometimes referred to as $G(N,p)$. \n", 55 | "\n", 56 | "That same year, Erdős and Rényi introduced a similar model for which there are $N$ nodes, and $m$ edges are added randomly to the network. This is sometimes called the Erdős–Rényi network model It is usually referred to as $G(N,m)$.\n", 57 | "\n", 58 | "We'll study $G(N,p)$, but we will also call it the Erdős–Rényi network model. Here is sample code that will generate these, but networkx has better algorithms built in that you should use." 59 | ] 60 | }, 61 | { 62 | "cell_type": "code", 63 | "execution_count": null, 64 | "metadata": { 65 | "collapsed": true, 66 | "deletable": true, 67 | "editable": true 68 | }, 69 | "outputs": [], 70 | "source": [ 71 | "import networkx as nx\n", 72 | "def my_ER_graph(N, p):\n", 73 | " nodelist = list(range(N))\n", 74 | " G = nx.Graph()\n", 75 | " G.add_nodes_from(nodelist)\n", 76 | " for node in nodelist:\n", 77 | " for potential_neighbor in range(node+1, N):\n", 78 | " if random.random()\n", 441 | "\n", 442 | "Note: we may get self-edges and repeated-edges (so networkx's implementation returns a MultiGraph()).\n", 443 | "\n", 444 | "\n", 445 | "#### Exercise\n", 446 | "\n", 447 | "Create a large (say $N=1000000$ node) Configuration Model network with degrees `[3]*(N//2) + [1]*(N//2)`. (also test what happens if you use `N/2` instead of `N//2` to see why I have two divide signs).\n", 448 | "\n", 449 | "Choose 50 nodes at random and check their degrees. You should get about half with degree 3 and half with degree 1.\n", 450 | "\n", 451 | "Now choose 50 nodes at random, and for each of those nodes, choose a random neighbor. Before checking, predict how many should have degree 3 and how many should have degree 1. Check the degrees of the neighbors.\n", 452 | "\n", 453 | "Use this to explain the title of the article: \"Why your friends have more friends than you do\": https://www.jstor.org/stable/2781907\n", 454 | "\n", 455 | "Then check the clustering and average shortest path lengths for these networks.\n", 456 | "\n", 457 | "Next, take varying values of $N$ and modify the proportion of nodes with degree 3. Plot the proportion of nodes that are in the largest component as a function of the proportion of nodes with degree $3$. Can you say why the transition is where it is?" 458 | ] 459 | }, 460 | { 461 | "cell_type": "code", 462 | "execution_count": null, 463 | "metadata": { 464 | "collapsed": true, 465 | "deletable": true, 466 | "editable": true 467 | }, 468 | "outputs": [], 469 | "source": [] 470 | }, 471 | { 472 | "cell_type": "markdown", 473 | "metadata": { 474 | "deletable": true, 475 | "editable": true 476 | }, 477 | "source": [ 478 | "We can demonstrate the principles of the exercise above in the following. Consider the three figures below. \n", 479 | "- We start by showing the nodes of the network. \n", 480 | "- Then we show the network with stubs, where half of the nodes have degree $1$ and half degree $3$.\n", 481 | "- Finally we show the fully connected network.\n", 482 | "\n", 483 | "Please do the following steps several times:\n", 484 | "- Look at the first figure and select one of the nodes. \n", 485 | "- Then look at that node in the figure with stubs. Since half of them have $3$ and half $1$, you should get $3$ half of the time.\n", 486 | "- Then go to the next figure where the stubs are joined, but still focus on that node. Without looking at the neighbors, choose one of the edges from your node and follow it to the neighbor. Check the degree of the neighbor. You should see that you reach degree $3$ nodes more often than degree $1$. (how much more often?)\n", 487 | "\n", 488 | "\n", 489 | "\n", 490 | "\n", 491 | "\n", 492 | "\n", 493 | "\n" 494 | ] 495 | }, 496 | { 497 | "cell_type": "code", 498 | "execution_count": null, 499 | "metadata": { 500 | "collapsed": true, 501 | "deletable": true, 502 | "editable": true 503 | }, 504 | "outputs": [], 505 | "source": [] 506 | } 507 | ], 508 | "metadata": { 509 | "kernelspec": { 510 | "display_name": "Python 3", 511 | "language": "python", 512 | "name": "python3" 513 | }, 514 | "language_info": { 515 | "codemirror_mode": { 516 | "name": "ipython", 517 | "version": 3 518 | }, 519 | "file_extension": ".py", 520 | "mimetype": "text/x-python", 521 | "name": "python", 522 | "nbconvert_exporter": "python", 523 | "pygments_lexer": "ipython3", 524 | "version": "3.5.2" 525 | } 526 | }, 527 | "nbformat": 4, 528 | "nbformat_minor": 2 529 | } 530 | -------------------------------------------------------------------------------- /3 Random Graphs/final_circle.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joelmiller/DynamicProcessesOnNetworks/ad7ca239697164fdad9464a60f48f7df8e60e49a/3 Random Graphs/final_circle.pdf -------------------------------------------------------------------------------- /3 Random Graphs/final_circle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joelmiller/DynamicProcessesOnNetworks/ad7ca239697164fdad9464a60f48f7df8e60e49a/3 Random Graphs/final_circle.png -------------------------------------------------------------------------------- /4 Kuramoto/weirdoscilliations.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joelmiller/DynamicProcessesOnNetworks/ad7ca239697164fdad9464a60f48f7df8e60e49a/4 Kuramoto/weirdoscilliations.png -------------------------------------------------------------------------------- /5 Disease Modeling/Intro/Epidemic Intro.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": { 6 | "deletable": true, 7 | "editable": true 8 | }, 9 | "source": [ 10 | "# Disease Modeling\n", 11 | "\n", 12 | "One of the most widely studied topics in network theory is the spread of infectious disease.\n", 13 | "\n", 14 | "## Standard Models\n", 15 | "\n", 16 | "There are two common models of disease:\n", 17 | "\n", 18 | "- SIR disease: \n", 19 | " - **S**usceptible individuals who have contact with infected individuals may become infected. \n", 20 | " - **I**nfected individuals may transmit to their neighbors/partners and later recover.\n", 21 | " - **R**ecovered individuals are immune to reinfection.\n", 22 | " \n", 23 | "- SIS disease:\n", 24 | " - **S**usceptible individuals who have contact with infected individuals may become infected. \n", 25 | " - **I**nfected individuals may transmit to their neighbors/partners and later recover. However they return to the susceptible class after recovery.\n", 26 | " \n", 27 | " \n", 28 | "![image](SIS_SIR_basic.png)\n", 29 | "\n", 30 | "\n", 31 | "An SIR disease spreading in a closed population (no births/deaths or immigration/emigration) is guaranteed to die out in a \"reasonable\" period of time. An SIS disease may persist for exponentially long periods of time.\n", 32 | "\n", 33 | "Many researchers have used mathematical modeling to provide guidance to policy decisions. \"Recently\" (i.e., the last 20 years) new insights have come from network-based models and through large-scale \"agent-based\" computer simulations.\n", 34 | "\n", 35 | "For this part of the course it may be worth looking at the book \"Mathematics of Epidemics on Networks\". The figure above is Fig 1.11 of the book.\n" 36 | ] 37 | }, 38 | { 39 | "cell_type": "markdown", 40 | "metadata": { 41 | "deletable": true, 42 | "editable": true 43 | }, 44 | "source": [ 45 | "## SIR Disease\n", 46 | "\n", 47 | "A good example of an SIR disease is Measles. Almost everyone who has had measles (or 2 vaccinations) gains lifelong immunity.\n", 48 | "\n", 49 | "There are two basic models of an SIR disease on a network.\n", 50 | "\n", 51 | "- **Discrete time** model: \n", 52 | " - **Duration**: In the discrete time version of the SIR model, each infected individual is infectious for a single time step. \n", 53 | " - **Transmission Process**: During that time step, the indivdiual transmits with probability $p$ to each neighbor.\n", 54 | " \n", 55 | "- **Continuous time** model:\n", 56 | " - **Duration**: In the continuous time version, each infected individual recovers with rate $\\gamma$. In other words, in a very short time interval of length $\\Delta t$, if there are $M$ infected individuals, we would expect a randomly chosen set of size about $M \\gamma \\Delta t$ of them to recover. Equivalently, the duration of infection is exponentially distributed with rate $\\gamma$.\n", 57 | " - **Transmission Process**: During the infectious period, individuals transmit (independently) to their neighbors with rate $\\tau$ (many people use $\\beta$ instead).\n", 58 | " - **Transmission Probability**: The probability of transmitting to a given neighbor before recovering is $\\tau/(\\tau + \\gamma)$." 59 | ] 60 | }, 61 | { 62 | "cell_type": "markdown", 63 | "metadata": { 64 | "deletable": true, 65 | "editable": true 66 | }, 67 | "source": [ 68 | "### Simulating SIR disease with EoN\n", 69 | "\n", 70 | "We're going to simulate SIR disease spread on networks using the Python package EoN. This should be installed on all of the room's computers, and hopefully it's on your personal machines. If you have any trouble installing, please let me know.\n", 71 | "\n", 72 | "The documentation for EoN is available at [https://epidemicsonnetworks.readthedocs.io/en/latest/](https://epidemicsonnetworks.readthedocs.io/en/latest/). A friend pointed out to me that this reads better as Epidemic Sonnet Works.\n", 73 | "\n", 74 | "Let's start with the basic discrete-time version, for which EoN has `basic_discrete_SIR`. Here is [the documentation](https://epidemicsonnetworks.readthedocs.io/en/latest/functions/EoN.basic_discrete_SIR.html#EoN.basic_discrete_SIR).\n", 75 | "\n" 76 | ] 77 | }, 78 | { 79 | "cell_type": "code", 80 | "execution_count": 12, 81 | "metadata": { 82 | "collapsed": false, 83 | "deletable": true, 84 | "editable": true 85 | }, 86 | "outputs": [ 87 | { 88 | "data": { 89 | "image/png": "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\n", 90 | "text/plain": [ 91 | "" 92 | ] 93 | }, 94 | "metadata": {}, 95 | "output_type": "display_data" 96 | } 97 | ], 98 | "source": [ 99 | "#You may need to run this more than once before something interesting\n", 100 | "#happens. By default a single individual is randomly infected. That\n", 101 | "#individual may recover before transmitting, in which case the output\n", 102 | "#is a bit boring.\n", 103 | "\n", 104 | "import EoN\n", 105 | "import networkx as nx\n", 106 | "import matplotlib.pyplot as plt\n", 107 | "\n", 108 | "N = 1000\n", 109 | "G = nx.fast_gnp_random_graph(N, 3/(N-1))\n", 110 | "\n", 111 | "p=0.75\n", 112 | "\n", 113 | "t, S, I, R = EoN.basic_discrete_SIR(G, p)\n", 114 | "\n", 115 | "plt.plot(t, S, label= 'S')\n", 116 | "plt.plot(t, I, label = 'I')\n", 117 | "plt.plot(t, R, label = 'R')\n", 118 | "plt.legend()\n", 119 | "plt.show()" 120 | ] 121 | }, 122 | { 123 | "cell_type": "markdown", 124 | "metadata": { 125 | "deletable": true, 126 | "editable": true 127 | }, 128 | "source": [ 129 | "What do we learn from this example?\n", 130 | "\n", 131 | "Depending on your luck, you may have learned that sometimes nothing interesting happens.\n", 132 | "\n", 133 | "You can also see that the number of infections initially grows while the number susceptible drops. At some point the number of infections starts to drop as well.\n", 134 | "\n", 135 | "**Questions to ponder**\n", 136 | "- What is it that triggers the drop in $I$?\n", 137 | "- Why is it that not all people get infected?\n", 138 | "- How often does an outbreak die out without getting large?\n" 139 | ] 140 | }, 141 | { 142 | "cell_type": "markdown", 143 | "metadata": { 144 | "deletable": true, 145 | "editable": true 146 | }, 147 | "source": [ 148 | "Now let's try the continuous time version. EoN provides several ways to implement this. We'll use `EoN.fast_SIR`, (though the `Gillespie` version turns out to be of comparable speed). Here is [the documentation](https://epidemicsonnetworks.readthedocs.io/en/latest/functions/EoN.fast_SIR.html#EoN.fast_SIR)." 149 | ] 150 | }, 151 | { 152 | "cell_type": "code", 153 | "execution_count": 4, 154 | "metadata": { 155 | "collapsed": false, 156 | "deletable": true, 157 | "editable": true 158 | }, 159 | "outputs": [ 160 | { 161 | "data": { 162 | "image/png": "iVBORw0KGgoAAAANSUhEUgAAAY0AAAD8CAYAAACLrvgBAAAABHNCSVQICAgIfAhkiAAAAAlwSFlz\nAAALEgAACxIB0t1+/AAAIABJREFUeJzt3Xl8VPW9//HXZyaTfQFCCEuABAMKVIQSUVyq1t22aq1V\ne6+VtlZvF629dnHrrdraX6WPtlbLlcqtVmmronQRW5ei1taFxYBBFERBBAJhCyQQss7M9/fHOYFJ\nTGTMwmTC+/l4zGPO+Z7v95xP5qF58z3n5Iw55xAREYlHINEFiIhI8lBoiIhI3BQaIiISN4WGiIjE\nTaEhIiJxU2iIiEjcFBoiIhI3hYaIiMRNoSEiInFLSXQBPW3w4MGuuLg40WWIiCSVZcuW7XTOFRys\nX78LjeLiYsrLyxNdhohIUjGzDfH00+kpERGJ20FDw8weMLPtZvZmTNsgM1toZu/67wNjtt1kZmvN\nbI2ZnR3TPtXMVvrb7jEz89vTzGye377EzIpjxszwj/Gumc3oqR9aRES6Jp6ZxoPAOe3abgSed86N\nBZ731zGzCcBlwER/zL1mFvTHzAauAsb6r9Z9Xgnsds6VAncBM/19DQJuBY4DpgG3xoaTiIgcege9\npuGc+3fsv/59FwCn+ssPAS8CN/jtjzrnmoD1ZrYWmGZm7wO5zrnFAGY2F7gQeNofc5u/r/nALH8W\ncjaw0Dm3yx+zEC9oHvnoP6aISO9qaWmhsrKSxsbGRJfyodLT0ykqKiIUCnVpfFcvhBc656r85a1A\nob88Algc06/Sb2vxl9u3t47ZBOCcC5tZLZAf297BmDbM7GrgaoBRo0Z17ScSEemGyspKcnJyKC4u\nxj/73uc456iurqayspKSkpIu7aPbF8Kd9y1OCf0mJ+fcHOdcmXOurKDgoHeMiYj0uMbGRvLz8/ts\nYACYGfn5+d2aDXU1NLaZ2TC/iGHAdr99MzAypl+R37bZX27f3maMmaUAeUD1h+xLRKRP6suB0aq7\nNXY1NBYArXczzQCeiGm/zL8jqgTvgvdS/1TWHjM73r9ecUW7Ma37uhh4wZ+9PAucZWYD/QvgZ/lt\nvcI5x/97ajVrt9f11iFERJJePLfcPgIsAo40s0ozuxK4EzjTzN4FzvDXcc69BTwGrAKeAb7pnIv4\nu/oG8FtgLbAO7yI4wP1Avn/R/Hr8O7H8C+A/Bl7zXz9qvSjeG96vrueRpRv51D0vMXfR++i700Uk\nGf3kJz9h4sSJTJo0icmTJ7NkyZIe3b/1t1+OZWVlrqt/Eb59byPfn/8GL67ZwUmlg/nZxZMYPiCj\nhysUkf5o9erVjB8/PqE1LFq0iOuvv54XX3yRtLQ0du7cSXNzM8OHD2/Tr6NazWyZc67sYMfQX4TH\nGJKTzu++dCx3XPgxXt+4m3Pvfol/vLU10WWJiMSlqqqKwYMHk5aWBsDgwYM/EBjd1e+ePdVdZsbl\nx4/mxNLBXPvIcq7+/TJmTB/NTeeNJz0UPPgOROSwd/uTb7Fqy54e3eeE4bnc+pmJH9rnrLPO4kc/\n+hHjxo3jjDPO4NJLL+WUU07p0To00+hEyeAs/vT1E7jypBIeWrSBz977qi6Si0iflp2dzbJly5gz\nZw4FBQVceumlPPjggz16DF3TiMMLb2/ju4+/QUNzhNsvmMjnpxYlxa11InLo9IVrGu3Nnz+fhx56\niCeffLJNu65p9LJPHlXI09edzOSRA/j+/Df49rwK9ja2JLosEZE21qxZw7vvvrt/vaKigtGjR/fo\nMXRNI06Fuen84avHce8/13LXc+9QsamGX39hCpOKBiS6NBERAOrq6rj22mupqakhJSWF0tJS5syZ\n06PHUGh8BMGAce3pYzn+iHyue+R1Pjf7VW445yiuPKlEp6tEJOGmTp3Kq6++2qvH0OmpLji2eBBP\nXXcynzxqCHf8fTVXzS2ntl6nq0Sk/1NodNGAzFR+c/lUfvjpCby4Zgef+vVLlL/fa3+wLiLSJyg0\nusHM+MpJJTz2temYwSX3LeIX/1hDSySa6NJERHqFQqMHfHzUQJ761slc9PEifv3CWj43+1XW7dDf\ndIhI/6PQ6CE56SF+/vljmP2fH2fjrno+dc9L/GHxBj34UET6FYVGDzv36GE8++1PcGzxIH7w1ze5\n4oGlVNU2JLosEZEeodDoBYW56cz9yjTuuPBjLNuwm/P04EMROQSys7N7/RgKjV7S+uDDBdecyIiB\nGVz9+2V857EVujVXRJKaQqOXlQ7J4c9fP5FrTivlrxWbOfOuf/Hcqm2JLktEpEv0F+GHQGpKgO+e\nfSRnTxzK9+av4Ktzy7loygh++JkJDMhMTXR5ItLTnr4Rtq7s2X0OPRrOvbNn99kFmmkcQkcX5bHg\nmpP41uljWbBiC2fe9W8WatYhIklEM41DLDUlwPVnjuOsCYV8b/4bXDW3nPOPGc4PPj2eITnpiS5P\nRHpCH5gR9BbNNBLkYyPyeOKbJ/LfZ4zjmTe3cvrP/8XvXllPWH9NLiJ9mEIjgVJTAlx3xlie/e9P\nMGX0QG5/chXnz3qFZRv0DCsR6ZsUGn1AyeAsHvryscz+z4+zu76Zz81exPceX0F1XVOiSxORJFJX\n1/uPL1Jo9BFmxrlHD+O560/hv04Zw19e38wnf/Ev/rB4A5GoHkUiIn2DQqOPyUpL4aZzx/PMt09m\nwrBcfvDXN/nsva+wYlNNoksTEVFo9FWlQ3J4+KrjuPuyyWytbeTCe1/h5r+spKa+OdGlichhTKHR\nh5kZF0wewfPfOYWvnFjCvNc2cdrPX2TeaxuJ6pSViCSAQiMJ5KSH+J9PT+Bv155E6ZBsbvjTSi7+\nzau8ubk20aWJyGFGoZFExg/L5bH/ms7PP38MG6rrOX/Wy3x//go27apPdGkicpjQX4QnGTPj4qlF\nnDm+kLuee4eHl27kiYotfGHaKL5x6hEMydVflYscroLBIEcffTSRSITS0lLmzp1LTk5Ojx5DM40k\nlZcZ4rbzJ/Kv753KZ44Zzu8Xb+Dkn/2Tnz61mu17GhNdnogkQEZGBhUVFaxcuZLc3Fzuu+++Hj+G\nQiPJDcvL4OefP4bnrz+Fcz42lN++vJ6TfvZPbv7LSt7ZtjfR5YlIgkyfPp1169b1+H67dXrKzG4C\nvghEgZXAl4FMYB5QDLwPXOKc2x3T/0ogAnzLOfes3z4VeBDIAJ4CrnPOOTNLA+YCU4Fq4FLn3Pvd\nqbm/Kh6cxd2XTeH6M8fxm3+9x/xllTy8ZCOnHVnA108tZVrJoESXKHLYmLl0Jm/vertH93nUoKO4\nYdoNcfWNRCIsXLiQ0047rUdrgG7MNMysGLgamOqc+xgQBC4DbgSed86NBZ731zGzCf72icA5wL1m\nFvR3Nxu4Chjrv87x268EdjvnSoG7gJldrfdwMTo/i59edDSLbzqd75w5jhWVtVxy3yIuuvcVFqzY\nQoseiCjSbzU0NDB58mSGDh3Kxo0b+drXvtbjx+jOTGMP0AJkmFkL3gxjC3ATcKrf5yHgReAG4ALg\nUedcE7DezNYC08zsfSDXObcYwMzmAhcCT/tjbvP3NR+YZWbmnNMfKRzEoKxUrj19LF89eQyPlW/i\nd6+s51uPvE5hbhqXHzeaS6eN1KPYRXpJvDOCntZ6TaO+vp6zzz6bBQsWcNFFF/XoMbo803DO7QJ+\nDmwEqoBa59w/gELnXJXfbStQ6C+PADbF7KLSbxvhL7dvbzPGORcGaoH8rtZ8OMpIDTLjhGJe+M6p\n/O5LxzKuMIdfLHyHE376Atc8vJwl71WjDBbpXzIzM7nnnnu45ZZbiEZ79uxCl2caZnYE8N9ACVAD\nPG5ml8f28a9L9PpvJDO7Gu9UGaNGjertwyWlQMA47aghnHbUEN7bUccfl2zk8fJN/O2NKo4szGHG\nCcVcMHk4WWm6C1ukP5gyZQqlpaXMmzePL3zhCz223+7cPVUGvOqc2+GcawH+DJwAbDOzYQD++3a/\n/2ZgZMz4Ir9ts7/cvr3NGDNLAfLwLoi34Zyb45wrc86VFRQUdONHOjyMKcjmfz49gSU3n8HPPjcJ\nM7j5LyuZesdCvvv4CpZv3K3Zh0gSav9o9CeffLJHAwO6FxprgOPNLNPMDDgdWA0sAGb4fWYAT/jL\nC4DLzCzNzErwLngv9U9l7TGz4/39XNFuTOu+LgZe0PWMnpORGuSSY0fy9HUnM/9r0/nslBE8tbKK\ni+59lXPvfonfvvQeVbUNiS5TRPqQLp+LcM5V+Bety/FuuX0dmANkA4+Z2ZXABuASv/9bZvYYsAoI\nA990zkX83X2DA7fcPu2/AO4Hfu9fNN+Fd/eV9DAzo6x4EGXFg7jlUxN4csUWHl26kTv+vpo7/r6a\nSUV5XDy1iM9MGs7ArNRElysiCWT97R/uZWVlrry8PNFl9AvrdtTx7Ftb+duKKlZV7SEUNI4ryefU\nIws4ZVwBpUOy8SaHIrJ69WqOOuqoPv//hHOOt99+m/Hjx7dpN7Nlzrmyg41XaMhBOedYVbWHBSu2\n8MLq7by73TtvOmJABp8Y5wXIiaX55KSHElypSOKsX7+enJwc8vPz+2xwOOeorq5m7969lJSUtNmm\n0JBes7mmgX+/s4MX12znlbXV1DWFCRhMHjmAE44YzAml+Rw9Ik8hIoeVlpYWKisraWzs289+S09P\np6ioiFCo7f+fCg05JFoiUZZv2M1L7+7klXU7eaOylkjUYQalBdkcM3IAx4wcwOSiARw5NIfUFD3u\nTKQvUmhIQtQ2tFCxqYYV/qtiUw3V+7yvqE1NCTBxeC7HFA1gsh8mxfmZfXYqL3I4UWhIn+CcY3NN\nAys21bKi0guRlZW1NLR4N87lZYSYVJTnhUjRACaNzNPjTUQSIN7Q0J//Sq8yM4oGZlI0MJNPTRoG\nQDgSZe2OOn8mUsuKTTXc++I6Iv73ng/PS+eYkQOYVDSAsUOyKR7sjU8PBT/sUCJyCCg05JBLCQY4\namguRw3N5dJjvbaG5ghvban1Tm1VekHy9Jtb24zLz0pl2IB0hudlMDo/k9H5WYzOz2TUoEyG5qWT\nlqJQEeltCg3pEzJSg/v/wLBVTX0z63fuY0N1PZt21bOltoGq2kbW79zHv97ZQVO47YPYBmSGGJ6X\nwfAB6QzNS2dobjoFOWneKzud/OxUBmamkpGqcBHpKoWG9FkDMlOZMiqVKaMGfmBbNOrYtrdxf6BU\n1TaybU8jW2oaqNzdQPmG3dTUt3S434xQkEFZqeRlhLz3zBC56SFyM1K89/QU8jJTyU1PIcdfz0kP\nkZkWJCMUJBTUHWBy+FJoSFIKBIxheRkMy8vg+DEdPy2/sSXCzromduz1XtX7mtm1r5nd+5rZVd9M\nbX0L1fua2VLbwJ6GMHsaW2gOH/wx0qGgkR4Kkh4KkpYS8F9B0kPee1roQFtaSsBfDx5oCwVITwmQ\nmhIkFDRSUwKEgq0vIzUYIOS3pQYDpKYYKYEAKUEjFAyQEjBCKd62YMAImhEI6A40OTQUGtJvpYeC\n+y/Cx6uxJcKexhZq61vY0xhmb2MLexvD7G0MU98cpqE5Qn1LhIbmCE3hCE0tUZrCUW85HKWpJcru\nfc1+W5SmlgiN/ntTOEo42nt3Kx4IEPYHSWyoBM1bN4OAGQH//cB6zHKgdZvXzzjQB2P/2LbjW8da\nm+3t1/1d+O/esaCDdmP/7dixd2UbbQOy7bZO2tvd1m2drHRp33GOid3QPuI721+n+2q/zV8pzE3n\n4qlF9CaFhkiM1hlEb932G45EaY5EaWyJ0hKJ0hz23lsizluORmkJe3287Y7mSJRwJEo44miJ+u/+\nfiIRR8Q5olHvPRKFqHNEot6rdfnAu7fd+e8H1h3R6IE251y77eBo2ycSjRKJOhzsH9N6DBdz3NZj\nRfxjOOeNad2ntx2g9TgH+kT9/e/XLnNjV2P/fKBte/sxrsNtH4jzNtviGxNvDb1l8sgBCg2R/iQl\nGCAlGCBTDwsWX5ug6SSQ2v89XSICqZVCQ0QkgWJPnXX+cIS+c81Kt4GIiEjcFBoiIhI3hYaIiMRN\noSEiInFTaIiISNwUGiIiEjeFhoiIxE2hISIicVNoiIhI3BQaIiISN4WGiIjETaEhIiJxU2iIiEjc\nFBoiIhI3hYaIiMRNoSEiInFTaIiISNy6FRpmNsDM5pvZ22a22symm9kgM1toZu/67wNj+t9kZmvN\nbI2ZnR3TPtXMVvrb7jH/q6zMLM3M5vntS8ysuDv1iohI93R3pnE38Ixz7ijgGGA1cCPwvHNuLPC8\nv46ZTQAuAyYC5wD3mlnQ389s4CpgrP86x2+/EtjtnCsF7gJmdrNeERHphi6HhpnlAZ8A7gdwzjU7\n52qAC4CH/G4PARf6yxcAjzrnmpxz64G1wDQzGwbkOucWO+/b0+e2G9O6r/nA6Wadf4uuiIj0ru7M\nNEqAHcDvzOx1M/utmWUBhc65Kr/PVqDQXx4BbIoZX+m3jfCX27e3GeOcCwO1QH43ahYRkW7oTmik\nAB8HZjvnpgD78E9FtfJnDq4bx4iLmV1tZuVmVr5jx47ePpyIyGGrO6FRCVQ655b46/PxQmSbf8oJ\n/327v30zMDJmfJHfttlfbt/eZoyZpQB5QHX7Qpxzc5xzZc65soKCgm78SCIi8mG6HBrOua3AJjM7\n0m86HVgFLABm+G0zgCf85QXAZf4dUSV4F7yX+qey9pjZ8f71iivajWnd18XAC/7sRUREEiClm+Ov\nBf5oZqnAe8CX8YLoMTO7EtgAXALgnHvLzB7DC5Yw8E3nXMTfzzeAB4EM4Gn/Bd5F9t+b2VpgF97d\nVyIikiDW3/7hXlZW5srLyxNdhohIUjGzZc65soP101+Ei4hI3BQaIiISN4WGiIjETaEhIiJxU2iI\niEjcFBoiIhI3hYaIiMRNoSEiInFTaIiISNwUGiIiEjeFhoiIxE2hISIicVNoiIhI3BQaIiISN4WG\niIjETaEhIiJxU2iIiEjcFBoiIhI3hYaIiMRNoSEiInFTaIiISNwUGiIiEjeFhoiIxE2hISIicVNo\niIhI3BQaIiISN4WGiIjETaEhIiJxU2iIiEjcFBoiIhI3hYaIiMRNoSEiInHrdmiYWdDMXjezv/nr\ng8xsoZm9678PjOl7k5mtNbM1ZnZ2TPtUM1vpb7vHzMxvTzOzeX77EjMr7m69IiLSdT0x07gOWB2z\nfiPwvHNuLPC8v46ZTQAuAyYC5wD3mlnQHzMbuAoY67/O8duvBHY750qBu4CZPVCviIh0UbdCw8yK\ngE8Bv41pvgB4yF9+CLgwpv1R51yTc249sBaYZmbDgFzn3GLnnAPmthvTuq/5wOmtsxARETn0ujvT\n+BXwfSAa01bonKvyl7cChf7yCGBTTL9Kv22Ev9y+vc0Y51wYqAXy2xdhZlebWbmZle/YsaNbP5CI\niHSuy6FhZp8GtjvnlnXWx585uK4eI17OuTnOuTLnXFlBQUFvH05E5LCV0o2xJwLnm9l5QDqQa2Z/\nALaZ2TDnXJV/6mm7338zMDJmfJHfttlfbt8eO6bSzFKAPKC6GzWLiEg3dHmm4Zy7yTlX5JwrxrvA\n/YJz7nJgATDD7zYDeMJfXgBc5t8RVYJ3wXupfyprj5kd71+vuKLdmNZ9Xewfo9dnLiIi0rHuzDQ6\ncyfwmJldCWwALgFwzr1lZo8Bq4Aw8E3nXMQf8w3gQSADeNp/AdwP/N7M1gK78MJJREQSxPrbP9zL\nyspceXl5ossQEUkqZrbMOVd2sH76i3AREYmbQkNEROKm0BARkbgpNEREJG4KDRERiZtCQ0RE4qbQ\nEBGRuCk0REQkbgoNERGJm0JDRETiptAQEZG4KTRERCRuCg0REYmbQkNEROKm0BARkbgpNEREJG4K\nDRERiVtvfN2riPQC5xxhF6Yl0kJTpInmSLP3inrvTZEmWqLetnA0TMRFiLro/leH69ED7bHvzrkO\n+3fU7nAdLztHlJjlDrbvXycK/peIOn+hdXtsG44PtLXpF/NNpO3b2oyL41id7etD+3VwrPbfjhrb\n1tF+Y/fV2bE6/BlwjB80nnvPuJfepNAQ6SbnHA3hBupa6qhrrmNvy17qmuv2r+9r2UdjpJHGcCNN\nkaY2v9z3/+Jv90u/OdL8wT7RZqIuesh/PsMIWICABQhaEDNr8x6wwP4+Zn5fYpZjtu/v42/fPw7b\nv+4fdP+xW9vMbH/b/tpi2swM7MB281bajIndV7zH+ig1ta53dqzYfX3YsTrbT6c/g68op4jeptAQ\n8YWjYaobqtnVuIvdjbupbqymtqmWmqYaappq9odA7Pve5r3sa9lHxEUOuv+gBUkLppEWTCMUDJEW\nTCM1kEpq8MArI5RBaiDV29baHtvH37Z/fLvtacE0QoEQoUCozS/6NssB75d6wAIEA8E2fWLfY8NB\npJVCQw4LLZEWtuzbwua9m6msq2RL3Ra21m9lR/0OdjXuoqaphl2Nuzr8l7xh5KblkhPKITs1m+xQ\nNsOyh5ETyiErlEVO6oH27FA22anZXpu/nhnKJDMlk1AwlICfXKRnKTSk32iJtlC5t5L1tetZV7OO\nTXs3sXHvRir3VrK9fnubc8YpgRQKMwspyChgVM4ojik4hsEZgxmSOYT89HwGpg9kYPpABqUPIic1\nh4DpnhERUGhIEqpvqWd97Xreq32PdTXrWF+7nvV71rNpzybCLry/3+CMwYzKGcVxw45jRPaI/a+i\nnCIKMgoIBoIJ/ClEkpNCQ/qsqIuyvnY9b+x4g3U161hXu473at5jy74t+/ukBFIYnTOaMXljOH3U\n6ZTklVCcW8wRA44gK5SVwOpF+ieFhvQZLdEWVlevZvm25Szbtozl25ezp3kPAKmBVMYMGMPkIZP5\n3IDPcUTeEZTklTAydyShgK4ViBwqCg1JmHA0zNu73mbp1qUsrVrK8u3LaQg3ADA6dzSnjzqdKUOm\nMHnIZEbljNLpJJE+QKEhh0wkGmFV9Spe3fIqr+94nde3vU59uB6AI/KO4MLSC5laOJWphVMZnDE4\nwdWKSEcUGtKr6prreHnzy/xjwz9YunUptU21GMaYvDF85ojPMLVwKmWFZRRkFiS6VBGJg0JDetyO\n+h38Y8M/eG7Dc1RsryDswuSn53PayNOYPmw604dPZ2D6wESXKSJdoNCQHlHdUM1zG57jmfefYdm2\nZTgcpQNKmTFxBicXnczkgsm6JiHSDyg0pMtqm2p5fuPzPLP+GZZuXUrERSjJK+Hrx3yds0vOZkze\nmESXKCI9rMuhYWYjgblAId7zFuc45+42s0HAPKAYeB+4xDm32x9zE3AlEAG+5Zx71m+fCjwIZABP\nAdc555yZpfnHmApUA5c6597vas3SfXXNdfxz0z95ev3TLKpaRDgaZmTOSL7ysa9wdvHZjBs4Ts8q\nEunHujPTCAPfcc4tN7McYJmZLQS+BDzvnLvTzG4EbgRuMLMJwGXARGA48JyZjXPORYDZwFXAErzQ\nOAd4Gi9gdjvnSs3sMmAmcGk3apYuenPnmzy8+mGeff9ZmqPNDMsaxuXjL+ecknOYMGiCgkLkMNHl\n0HDOVQFV/vJeM1sNjAAuAE71uz0EvAjc4Lc/6pxrAtab2Vpgmpm9D+Q65xYDmNlc4EK80LgAuM3f\n13xglpmZa/+AeukVTZEmnln/DI++/ShvVr9JZkomnx37WT495tNMKpik5zGJHIZ65JqGmRUDU/Bm\nCoV+oABsxTt9BV6gLI4ZVum3tfjL7dtbx2wCcM6FzawWyAd29kTd0rGt+7Yyb8085r8zn5qmGkry\nSrhp2k2cf8T5ZKdmJ7o8EUmgboeGmWUDfwK+7ZzbE3uawr8u0euzAjO7GrgaYNSoUb19uH5r5Y6V\n/O6t3/HCxhdwOE4tOpX/GP8fTBs6TaefRAToZmiYWQgvMP7onPuz37zNzIY556rMbBiw3W/fDIyM\nGV7kt232l9u3x46pNLMUIA/vgngbzrk5wByAsrIynbr6iJZvW86silm8tvU1skPZXDHxCi4Zd8kh\n+RYwEUku3bl7yoD7gdXOuV/GbFoAzADu9N+fiGl/2Mx+iXchfCyw1DkXMbM9ZnY83umtK4Bft9vX\nIuBi4AVdz+gZzjkWVS1idsVsKnZUkJ+ez/eP/T4Xjb1IT4cVkU51Z6ZxIvBFYKWZVfhtN+OFxWNm\ndiWwAbgEwDn3lpk9BqzCu/Pqm/6dUwDf4MAtt0/7L/BC6ff+RfNdeHdfSTe9tvU1Zr0+i+XblzM0\nayg3TruRi8ZeREZKRqJLE5E+zvrbP9zLyspceXl5osvok97d/S53LbuLlza/REFGAVdNuorPjf0c\nqcHURJcmIglmZsucc2UH66e/CD8MvFf7HrMrZvPs+8+SFcriO1O/w2VHXUZ6SnqiSxORJKPQ6Mc2\n7dnEb974DX9772+kBlL56tFf5YoJVzAgfUCiSxORJKXQ6IdqGmv4zRu/Yd6aeaRYCl8c/0W+cvRX\nGJQ+KNGliUiSU2j0I5FohL+u/St3L7+b2uZaLhp7Ed845hv6rgoR6TEKjX5iza413PrqrbxV/RZT\nhkzhB8f/gHEDxyW6LBHpZxQaSa62qZbZK2bz6NuPkpeWx09P/innlZyn50KJSK9QaCSpSDTC/Hfm\nM6tiFnua93Dx2Iu5dsq1usgtIr1KoZGEyreW87PXfsbqXas5duix3HDsDRw56MhElyUihwGFRhLZ\num8rM5fO5LmNz1GYWcjMk2dybsm5epigiBwyCo0kEHVRHl/zOHctv4uoi3LN5Gu4YuIVeuyHiBxy\nCo0+bsOeDdz66q0s27aM44cdz63Tb9XTZ0UkYRQafVQkGmHuqrn8b8X/khpM5Ucn/IgLSy/UqSgR\nSSiFRh/09q63+dGiH7Fy50o+OfKT/OD4H+gP9ESkT1Bo9CGN4UbmvDGHB958YP/fXHyq5FOaXYhI\nn6HQ6CPe2vkWN798M+/Vvsf5R5zP94/9PnlpeYkuS0SkDYVGgrVEWpizcg7/98b/MThjMPedcR8n\njDgh0WWJiHRIoZFA7+5+l1tevoXVu1Zz/hHnc8O0G8hNzU10WSIinVJoJEAkGuGhVQ8x6/VZ5KTm\n8KvTfsUNi4Y8AAAKIUlEQVTpo05PdFkiIgel0DjENu7ZyC0v30LFjgrOGHUG/zP9f/Q9FyKSNBQa\nh0jURZm3Zh53LbuLlEAKd558J+eVnKc7o0QkqSg0DoGquip++OoPWVy1mBNHnMjt02+nMKsw0WWJ\niHxkCo1e5JzjiXVPMHPpTCIuwg+n/5CLx16s2YWIJC2FRi/Z2bCT2xfdzoubXmRq4VR+fOKPGZkz\nMtFliYh0i0KjFzy9/mnuWHwHjeFGvlf2PS6fcLm+SU9E+gWFRg+qbarl9kW3s3DDQiYVTOLHJ/6Y\nMXljEl2WiEiPUWj0kJc3v8xtr95GdWM11338Or408UukBPTxikj/ot9q3bRt3zZmvjaThRsWUpxb\nzB/O+wMT8ycmuiwRkV6h0OiicDTMo6sfYVbFLMLRFq6J5vLlUCmpr9wH9dUQboSG3ZAxCNb/GwaV\nwKjpsH01bFrs7aToWKh8DYpPhpqNMPYsGHMqZA6CQMh7zx4CqdmgO65EpA8w51yia+hRZWVlrry8\nvOd26Bzs2QJrnoKnvguhTF7PK+COLOOdQJQT6xu4pXo3I8PhnjtmvHKGwd4qb7n4ZHBRGDzOC6iC\n8TBgJGQXQnoeBIKHvj4RSRpmtsw5V3awfppptFe3HTa8Ao9/6QObqgMBfpmXzoIcx1CC/IoCPjl6\nKnZkDuQOh9EnQWON1zljEKTlQDAEoQxv5hFMBcz7BR5uhEgYIk2wfRW8/XfIL/XGBYIQyoSd70DV\nCm8Wkl8KdVu9WUtqDhx5LrgIvPkn73g71sA+v/bOBEIwfApkFUBOIWQPhZyh3rFaAyYt16s5LUez\nGxH5AIVGq71b4f6zoGZD2/ZACpFzZ/L4nne4Z+u/aYg2ceWEGVw96WoyQ5nx7z+U0XY9Je3Acu5w\nKD2ja3Vf/EDb9aY6b/ax/t+w4VUvjI46zzvF9cY8b1tzHWxcBA27DrJz8wKkaJrXN6sAhh4NqVmQ\nmQ/RCAw7BrIGe6fR0gcoaET6uaQ4PWVm5wB3A0Hgt865Ozvr2+XTU+FmeORSGH0ilJwCw47BBUO8\nvPllfv36r1m9azXHDT2Om4+/uf/cRhtuhrpt3um3pj1eoNRuhvqd0FDjBdvbfwPswAwqJd2bJXUk\nkAKhLEjP9U6dpeV4+4g0Q+4IbzaTOdgLsKDfNy3H65+S7oVRapau4YgkQLynp/p8aJhZEHgHOBOo\nBF4DvuCcW9VR/566plGxvYJZFbNYUrWEYVnDuH7q9ZxdfLYeARKNQrgBmvbCns3e6bymOu/UWX01\nNNdDYy3s3QKNe6CqIv59W8C7LgPeKbj0XG92kz3EO22WnuuFSjAVWhq8bYEUrz0t15vNpaR7p9tS\nM72+KRlee2qWN2sSkQ71p2sa04C1zrn3AMzsUeACoMPQ6A7nHEu2LuH+lfezuGoxA9IGcOO0G7lk\n3CWE9AvHEwgcmBHkDI1/nHPQ4gdK8z6ItHjvzXu9tnCTt33dC5A1xJuhNNR412n2boWd73qzoeZ9\nnc90DqZ1NhPKglC6d4yUdP+VBsG0A20W8H7WQErMK9h23YIfbOtwPZ4+sfvspA/4MzCLeQ8ceAWC\n7baZZmzS45IhNEYAm2LWK4Hjevogm+s2c83z17C2Zi356flcP/V6Lj3y0o923UI6Z3YgbD5M2VcO\nvi/nIBo+8Gqo8WY+4Ubv1VLvB9I+b0bS0uCv13nbmur8GxGa/TFN3u3R4aYD6855NxrsP06k7TFb\nZ0RJoTVAAnwgVPBDZX+4xK53tNxun52N+UAJ1vGYjo7daT20a2u3/oF+XdVuHx3us4O2D/TrYp/u\nGPqxD17n7GHJEBoHZWZXA1cDjBo1qkv7KMwsZET2CGZMnMG5JeeSFkw7+CBJDPMv0LfO/tJyDn0N\n0agfKh8SLO3bPtC/s3HRjvuAH1bOCzWct976irbf5jrpH7Pd26n/FnOqOnZbh/3aj2nfL/aXoetk\nTCfH3t/Wbr398Tob1x0fOF3fwT47PKXveqhPNw0Y3fP7bCcZQmMzEPt42CK/bT/n3BxgDnjXNLpy\nkJRACrNOn9XVGuVwEwgAAV0nkcNOMjx69TVgrJmVmFkqcBmwIME1iYgclvr8TMM5Fzaza4Bn8W65\nfcA591aCyxIROSz1+dAAcM49BTyV6DpERA53yXB6SkRE+giFhoiIxE2hISIicVNoiIhI3BQaIiIS\ntz7/wMKPysx2ABsO2rFzg4GdPVTOoZbMtUNy15/MtUNy15/MtUPfqX+0c67gYJ36XWh0l5mVx/Ok\nx74omWuH5K4/mWuH5K4/mWuH5Ktfp6dERCRuCg0REYmbQuOD5iS6gG5I5tohuetP5tohuetP5toh\nyerXNQ0REYmbZhoiIhI3hYbPzM4xszVmttbMbkx0PR+Vmb1vZivNrMLMuv8l6b3MzB4ws+1m9mZM\n2yAzW2hm7/rvAxNZY2c6qf02M9vsf/4VZnZeImvsjJmNNLN/mtkqM3vLzK7z25Pls++s/j7/+ZtZ\nupktNbMVZrbazO7025Pis2+l01OAmQWBd4Az8b5O9jXgC865Hv8e8t5iZu8DZc65vnC/90GZ2SeA\nOmCuc+5jftvPgF3OuTv94B7onLshkXV2pJPabwPqnHM/T2RtB2Nmw4BhzrnlZpYDLAMuBL5Ecnz2\nndV/CX388zczA7Kcc3VmFgJeBr4LfIYk+OxbaabhmQasdc6955xrBh4FLkhwTf2ac+7fwK52zRcA\nD/nLD+H9MuhzOqk9KTjnqpxzy/3lvcBqYATJ89l3Vn+f5zx1/moI7/uBdpMkn30rhYZnBLApZr2S\nJPkPMYYDnjOzZf53piejQudclb+8FShMZDFdcK2ZveGfvurTpxgAzKwYmAIsIQk/+3b1QxJ8/mYW\nNLMKYDvwonPuTZLss1do9B8nOecmA+cC3/RPoSQt5503TaZzp7OBMcBkoAr4RWLL+XBmlg38Cfi2\nc25P7LZk+Ow7qD8pPn/nXMT//7QIONnMTmu3vc9/9goNz2ZgZMx6kd+WNJxzm/337cBf8E65JZtt\n/jnr1nPX2xNcT9ycc9v8XwhR4P/ow5+/fz79T8AfnXN/9puT5rPvqP5k+vwBnHM1wN+BMpLosweF\nRqvXgLFmVmJmqcBlwIIE1xQ3M8vyLwpiZlnAWcCbHz6qT1oAzPCXZwBPJLCWj6T1f3rfZ+mjn79/\nMfZ+YLVz7pcxm5Lis++s/mT4/M2swMwG+MsZeDfeVJAkn30r3T3l82/R+xXexakHnHM/SXBJcTOz\nMXizC/C+9/3hvl6/mT0CnIr3hM9twK3AX4HHgFF4Tyq+xDnX5y44d1L7qXinRhzwPvBfMeep+wwz\nOwl4CVgJRP3mm/GuCyTDZ99Z/V+gj3/+ZjYJ70J3wH/9wTk308zySYLPvpVCQ0RE4qbTUyIiEjeF\nhoiIxE2hISIicVNoiIhI3BQaIiISN4WGiIjETaEhIiJxU2iIiEjc/j9UCzKCA0MUcAAAAABJRU5E\nrkJggg==\n", 163 | "text/plain": [ 164 | "" 165 | ] 166 | }, 167 | "metadata": {}, 168 | "output_type": "display_data" 169 | } 170 | ], 171 | "source": [ 172 | "import EoN\n", 173 | "import networkx as nx\n", 174 | "import matplotlib.pyplot as plt\n", 175 | "\n", 176 | "N_over_2 = 50000\n", 177 | "N = 2* N_over_2\n", 178 | "\n", 179 | "deg_dist = [5,2]*(N_over_2)\n", 180 | "\n", 181 | "\n", 182 | "G = nx.configuration_model(deg_dist)\n", 183 | "\n", 184 | "t, S, I, R = EoN.fast_SIR(G, 0.5, 1, rho = 0.02)\n", 185 | "#transmission rate of 0.5\n", 186 | "#recovery rate of 1\n", 187 | "#randomly infect 2% of the population to start.\n", 188 | "\n", 189 | "plt.plot(t, S, label = 'S')\n", 190 | "plt.plot(t, I, label = 'I')\n", 191 | "plt.plot(t, R, label = 'R')\n", 192 | "plt.legend()\n", 193 | "plt.show()" 194 | ] 195 | }, 196 | { 197 | "cell_type": "markdown", 198 | "metadata": { 199 | "deletable": true, 200 | "editable": true 201 | }, 202 | "source": [ 203 | "### Epidemics versus non-Epidemic Outbreaks\n", 204 | "\n", 205 | "In the discrete simulation, you may have observed two very distinct behaviors. Either the disease spread and infected most of the population, or almost nothing happened.\n", 206 | "\n", 207 | "We divide the behavior into two classes:\n", 208 | "\n", 209 | "- **Epidemic outbreaks**: When an epidemic happens, the disease spreads until it is limited by the fact that the population size is finite.\n", 210 | "\n", 211 | "- **Non-Epidemic outbreaks** When a non-epidemic outbreak happens, the disease dies out because it happened to not transmit much early on. The fact that the population size is finite did not play a role in this.\n", 212 | "\n", 213 | "If I just say \"outbreak\", I'm referring to a non-epidemic outbreak.\n", 214 | "\n", 215 | "Let's see what this looks like. We'll use an Erdős–Rényi network since they can be generated quickly." 216 | ] 217 | }, 218 | { 219 | "cell_type": "code", 220 | "execution_count": 49, 221 | "metadata": { 222 | "collapsed": false, 223 | "deletable": true, 224 | "editable": true 225 | }, 226 | "outputs": [ 227 | { 228 | "name": "stdout", 229 | "output_type": "stream", 230 | "text": [ 231 | "0 of 10000\n", 232 | "1000 of 10000\n", 233 | "2000 of 10000\n", 234 | "3000 of 10000\n", 235 | "4000 of 10000\n", 236 | "5000 of 10000\n", 237 | "6000 of 10000\n", 238 | "7000 of 10000\n", 239 | "8000 of 10000\n", 240 | "9000 of 10000\n" 241 | ] 242 | }, 243 | { 244 | "data": { 245 | "image/png": "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\n7Y0QQG4AAAAASUVORK5CYII=\n", 246 | "text/plain": [ 247 | "" 248 | ] 249 | }, 250 | "metadata": {}, 251 | "output_type": "display_data" 252 | } 253 | ], 254 | "source": [ 255 | "import EoN\n", 256 | "import networkx as nx\n", 257 | "import matplotlib.pyplot as plt\n", 258 | "\n", 259 | "import matplotlib #these last 2 imports are\n", 260 | "from distutils.version import LooseVersion #used to check \n", 261 | " #matplotlib version\n", 262 | "\n", 263 | "plt.clf()\n", 264 | "\n", 265 | "N=1000\n", 266 | "G = nx.fast_gnp_random_graph(N, 3./N)\n", 267 | "p = 0.5\n", 268 | "iterations = 10000\n", 269 | "\n", 270 | "sizes = []\n", 271 | "for counter in range(iterations):\n", 272 | " if counter%1000 == 0:\n", 273 | " print(counter, \" of \", iterations)\n", 274 | " t, S, I, R = EoN.basic_discrete_SIR(G, p)\n", 275 | " sizes.append(R[-1]) #the '-1' grabs the last entry of R.\n", 276 | "\n", 277 | "\n", 278 | "fig = plt.figure(1)\n", 279 | "main = plt.axes()\n", 280 | "\n", 281 | "#In older versions of matplotlib the `density` argument doesn't exist\n", 282 | "#and `normed` should be used. In newer versions `normed` has been \n", 283 | "#deprecated. My laptop has the old version, and updating it is oddly \n", 284 | "#difficult. So the bit below runs different code depending on the \n", 285 | "#version.\n", 286 | "\n", 287 | "if LooseVersion(matplotlib.__version__) >= LooseVersion(\"2.1\"): \n", 288 | " main.hist(sizes, bins = range(N+1), density = True) \n", 289 | "else:\n", 290 | " main.hist(sizes, bins = range(N+1), normed = 1) \n", 291 | "main.axis(xmax=1000, ymax = 0.05)\n", 292 | "\n", 293 | "plt.xlabel('Final Epidemic Size')\n", 294 | "plt.ylabel('Frequency')\n", 295 | "\n", 296 | "inset = plt.axes([0.3,0.4,0.5,0.4])\n", 297 | "if LooseVersion(matplotlib.__version__) >= LooseVersion(\"2.1\"): \n", 298 | " inset.hist(sizes,bins = range(N+1), density=True)\n", 299 | "else:\n", 300 | " inset.hist(sizes, bins = range(N+1), normed=1)\n", 301 | " \n", 302 | "inset.axis(xmin = 300, xmax = 800, ymin=0, ymax = 0.008)\n", 303 | "\n", 304 | "plt.show()" 305 | ] 306 | } 307 | ], 308 | "metadata": { 309 | "kernelspec": { 310 | "display_name": "Python 3", 311 | "language": "python", 312 | "name": "python3" 313 | }, 314 | "language_info": { 315 | "codemirror_mode": { 316 | "name": "ipython", 317 | "version": 3 318 | }, 319 | "file_extension": ".py", 320 | "mimetype": "text/x-python", 321 | "name": "python", 322 | "nbconvert_exporter": "python", 323 | "pygments_lexer": "ipython3", 324 | "version": "3.5.2" 325 | } 326 | }, 327 | "nbformat": 4, 328 | "nbformat_minor": 2 329 | } 330 | -------------------------------------------------------------------------------- /5 Disease Modeling/Intro/SIS_SIR_basic.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joelmiller/DynamicProcessesOnNetworks/ad7ca239697164fdad9464a60f48f7df8e60e49a/5 Disease Modeling/Intro/SIS_SIR_basic.png -------------------------------------------------------------------------------- /5 Disease Modeling/SIR analysis/CM_generation0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joelmiller/DynamicProcessesOnNetworks/ad7ca239697164fdad9464a60f48f7df8e60e49a/5 Disease Modeling/SIR analysis/CM_generation0.png -------------------------------------------------------------------------------- /5 Disease Modeling/SIR analysis/CM_generationneg1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joelmiller/DynamicProcessesOnNetworks/ad7ca239697164fdad9464a60f48f7df8e60e49a/5 Disease Modeling/SIR analysis/CM_generationneg1.png -------------------------------------------------------------------------------- /5 Disease Modeling/SIR analysis/Effective_Degree_SIR.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joelmiller/DynamicProcessesOnNetworks/ad7ca239697164fdad9464a60f48f7df8e60e49a/5 Disease Modeling/SIR analysis/Effective_Degree_SIR.png -------------------------------------------------------------------------------- /5 Disease Modeling/SIR analysis/final_circle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joelmiller/DynamicProcessesOnNetworks/ad7ca239697164fdad9464a60f48f7df8e60e49a/5 Disease Modeling/SIR analysis/final_circle.png -------------------------------------------------------------------------------- /5 Disease Modeling/SIR analysis/heterogeneous_MF_revised.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joelmiller/DynamicProcessesOnNetworks/ad7ca239697164fdad9464a60f48f7df8e60e49a/5 Disease Modeling/SIR analysis/heterogeneous_MF_revised.png -------------------------------------------------------------------------------- /5 Disease Modeling/SIR analysis/homogeneous_MF.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joelmiller/DynamicProcessesOnNetworks/ad7ca239697164fdad9464a60f48f7df8e60e49a/5 Disease Modeling/SIR analysis/homogeneous_MF.png -------------------------------------------------------------------------------- /5 Disease Modeling/SIR analysis/sexual_PL.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joelmiller/DynamicProcessesOnNetworks/ad7ca239697164fdad9464a60f48f7df8e60e49a/5 Disease Modeling/SIR analysis/sexual_PL.png -------------------------------------------------------------------------------- /5 Disease Modeling/SIS analysis/3nodeSIS.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joelmiller/DynamicProcessesOnNetworks/ad7ca239697164fdad9464a60f48f7df8e60e49a/5 Disease Modeling/SIS analysis/3nodeSIS.png -------------------------------------------------------------------------------- /5 Disease Modeling/SIS analysis/Effective_Degree.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joelmiller/DynamicProcessesOnNetworks/ad7ca239697164fdad9464a60f48f7df8e60e49a/5 Disease Modeling/SIS analysis/Effective_Degree.png -------------------------------------------------------------------------------- /6 Complex Contagions/Centola_fig1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joelmiller/DynamicProcessesOnNetworks/ad7ca239697164fdad9464a60f48f7df8e60e49a/6 Complex Contagions/Centola_fig1.png -------------------------------------------------------------------------------- /6 Complex Contagions/Centola_fig2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joelmiller/DynamicProcessesOnNetworks/ad7ca239697164fdad9464a60f48f7df8e60e49a/6 Complex Contagions/Centola_fig2.png -------------------------------------------------------------------------------- /Assignments/Assignment 1.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": { 6 | "deletable": true, 7 | "editable": true 8 | }, 9 | "source": [ 10 | "### modifications since posted online:\n", 11 | "A grammatical problem with the new rules for the surfer in problem 1 has been fixed.\n", 12 | "\n", 13 | "Modified question 1c to make it answerable since I realized it must converge.\n", 14 | "\n", 15 | "Clarified that in Qestion 2 you can assume the matrix has a full eigenspace.\n", 16 | "\n", 17 | "Corrected 3c to say that $1/cd$ is the eigenvalue, not $cd$." 18 | ] 19 | }, 20 | { 21 | "cell_type": "markdown", 22 | "metadata": { 23 | "deletable": true, 24 | "editable": true 25 | }, 26 | "source": [] 27 | }, 28 | { 29 | "cell_type": "markdown", 30 | "metadata": { 31 | "deletable": true, 32 | "editable": true 33 | }, 34 | "source": [ 35 | "[Please ensure that the top of your assignment has the required comment on copying]." 36 | ] 37 | }, 38 | { 39 | "cell_type": "markdown", 40 | "metadata": { 41 | "collapsed": true, 42 | "deletable": true, 43 | "editable": true 44 | }, 45 | "source": [ 46 | "# Assigment 1" 47 | ] 48 | }, 49 | { 50 | "cell_type": "code", 51 | "execution_count": null, 52 | "metadata": { 53 | "collapsed": true, 54 | "deletable": true, 55 | "editable": true 56 | }, 57 | "outputs": [], 58 | "source": [] 59 | }, 60 | { 61 | "cell_type": "markdown", 62 | "metadata": { 63 | "deletable": true, 64 | "editable": true 65 | }, 66 | "source": [ 67 | "### Problem 1\n", 68 | "\n", 69 | "Consider a directed network $G$. So far we have written a function that calculates the vector $\\vec{x}(n)$ of probabilities that a surfer is at each given node in $G$ at step $n$. However, in doing this we made two assumptions I would like to change\n", 70 | "- We have assumed that when the surfer jumps (or \"teleports\") without following an edge, it does so to any node with equal probability.\n", 71 | "- We have assumed that all nodes in $G$ have at least one edge going out.\n", 72 | "\n", 73 | "\n", 74 | "Consider now a different pair of rules for the surfer:\n", 75 | "- when the surfer jumps/teleports, he/she goes to pages with a weighted probability provided by a dict input to the function.\n", 76 | "- if the surfer arrives at a node with no out edges, he/she jumps/teleports with probability 1, not $\\alpha$.\n", 77 | "\n", 78 | "Given these rules:\n", 79 | "##### Part a\n", 80 | "\n", 81 | "Please **write a function** that can be called by\n", 82 | "\n", 83 | " `Personalized_PageRank(G, alpha, teleport_weights, iterations)`\n", 84 | "\n", 85 | "where the inputs satisfiy\n", 86 | "- `G` is a graph\n", 87 | "- `alpha` is a number between 0 and 1 (as before)\n", 88 | "- `teleport_weights` is a dict where `teleport_weights[node]` is the probability of arriving at `node` given that the surfer is jumping.\n", 89 | "- `iterations` is the number of iterations to do.\n", 90 | "\n", 91 | "The function should return $\\vec{x}($ `iterations` $)$. \n", 92 | "\n", 93 | "There is more than one way such an algorithm could be implemented, one of which is based on matrix multiplication. **Do not use matrix multiplication**.\n", 94 | "\n", 95 | "Be sure to **comment your code** and be sure that you **deal with nodes with no out-edges**. \n", 96 | "\n" 97 | ] 98 | }, 99 | { 100 | "cell_type": "code", 101 | "execution_count": null, 102 | "metadata": { 103 | "collapsed": true, 104 | "deletable": true, 105 | "editable": true 106 | }, 107 | "outputs": [], 108 | "source": [] 109 | }, 110 | { 111 | "cell_type": "markdown", 112 | "metadata": { 113 | "deletable": true, 114 | "editable": true 115 | }, 116 | "source": [ 117 | "##### Part b\n", 118 | "\n", 119 | "Assume $\\alpha>0$, and state a condition on `teleport_weights` that would guarantee that the output of your algorithm converges regardless of `G` as `iterations` $\\to \\infty$.\n" 120 | ] 121 | }, 122 | { 123 | "cell_type": "markdown", 124 | "metadata": { 125 | "deletable": true, 126 | "editable": true 127 | }, 128 | "source": [] 129 | }, 130 | { 131 | "cell_type": "markdown", 132 | "metadata": { 133 | "deletable": true, 134 | "editable": true 135 | }, 136 | "source": [ 137 | "\n", 138 | "##### Part c\n", 139 | "\n", 140 | "[this replaces the previous **part c** and is **optional** - when I wrote the previous **part c** I had two different examples muddled in my memory]\n", 141 | "\n", 142 | "As in part (b), assume $\\alpha>0$ and state a condition on `teleport_weights` that would guarantee the algorithm assigns **positive weight** to all nodes as `iterations` $\\to \\infty$.\n", 143 | "\n", 144 | "Assume $\\alpha>0$ and find an example `G` and `teleport_weights` that give `0` weight to some nodes." 145 | ] 146 | }, 147 | { 148 | "cell_type": "code", 149 | "execution_count": null, 150 | "metadata": { 151 | "collapsed": true, 152 | "deletable": true, 153 | "editable": true 154 | }, 155 | "outputs": [], 156 | "source": [] 157 | }, 158 | { 159 | "cell_type": "markdown", 160 | "metadata": { 161 | "deletable": true, 162 | "editable": true 163 | }, 164 | "source": [ 165 | "### Problem 2\n", 166 | "\n", 167 | "Now consider the case where the surfer jumps to all pages with equal probability again, and for simplicity assume that all nodes in $G$ have at least one edge going out.\n", 168 | "\n", 169 | "In class we derived a matrix $P$ such that $\\vec{x}(n) = P \\vec{x}(n-1)$ for a specific matrix $P$.\n", 170 | "\n", 171 | "Let's assume that instead of jumping in equally spaced intervals, the surfer can move at any time, and does so with rate $1$. If the surfer moves, then with probability $\\alpha$ he/she jumps to a random page. Otherwise he/she follows a randomly chosen link.\n", 172 | "\n", 173 | "- **Find a matrix $Q$** such that $\\frac{d}{dt} \\vec{x} = Q \\vec{x}$.\n", 174 | "\n", 175 | "- Assume that as $t \\to \\infty$, we have $\\frac{d}{dt} \\vec{x} \\to \\vec{0}$, so the vector of probabilities approaches a constant. **How is $\\lim_{t\\to \\infty} \\vec{x}(t)$ related to $Q$**?\n", 176 | "\n", 177 | "- **Prove that** if $\\alpha>0$ then in fact $\\vec{x}(t)$ does go to a constant value.\n", 178 | "\n", 179 | "(you may assume that all eigenvalues of $Q$ have a full eigenspace)" 180 | ] 181 | }, 182 | { 183 | "cell_type": "code", 184 | "execution_count": null, 185 | "metadata": { 186 | "collapsed": true, 187 | "deletable": true, 188 | "editable": true 189 | }, 190 | "outputs": [], 191 | "source": [] 192 | }, 193 | { 194 | "cell_type": "markdown", 195 | "metadata": { 196 | "deletable": true, 197 | "editable": true 198 | }, 199 | "source": [ 200 | "### Problem 3\n", 201 | "\n", 202 | "Besides PageRank, there are other algorithms used for ranking websites. Consider HITS (Hypertext-Induced-Topic-Search) which is based on the idea that webpages play two roles: they provide information themselvesand they link to other pages that have useful information. We assign page $i$ two weights $a_i$ and $h_i$ representing its \"authority\" and \"hub\" weights. We assume that a page's hub weight is proportional to the sum of the authority weights of the pages that it links to, and its authority weight is proportional to the sum of the hub weights of the pages linking to it. The weights are normalized so that $\\sum_i h_i = 1$ and $\\sum_i a_i = 1$.\n" 203 | ] 204 | }, 205 | { 206 | "cell_type": "markdown", 207 | "metadata": { 208 | "deletable": true, 209 | "editable": true 210 | }, 211 | "source": [ 212 | "\n", 213 | "##### Part a\n", 214 | "Explain why \n", 215 | "$h_i = c \\sum_{j} A_{ij} a_j$ for all $i$, where $A_{ij}$ is 1 if there is a link from $i$ to $j$ and 0 otherwise (the direction is important) and c is a normalization constant equal to $1/\\sum_i \\sum_j A_{ij}a_j$.\n", 216 | "\n" 217 | ] 218 | }, 219 | { 220 | "cell_type": "markdown", 221 | "metadata": { 222 | "deletable": true, 223 | "editable": true 224 | }, 225 | "source": [] 226 | }, 227 | { 228 | "cell_type": "markdown", 229 | "metadata": { 230 | "deletable": true, 231 | "editable": true 232 | }, 233 | "source": [ 234 | "##### Part b\n", 235 | "Similarly explain why $a_i = d \\sum_j A_{ji}h_j$ where $d = 1/\\sum_i \\sum_j A_{ji} h_j$.\n", 236 | "\n" 237 | ] 238 | }, 239 | { 240 | "cell_type": "markdown", 241 | "metadata": { 242 | "deletable": true, 243 | "editable": true 244 | }, 245 | "source": [] 246 | }, 247 | { 248 | "cell_type": "markdown", 249 | "metadata": { 250 | "deletable": true, 251 | "editable": true 252 | }, 253 | "source": [ 254 | "##### Part c\n", 255 | "Use this to show that $\\vec{a} = cdA^T A \\vec{a}$, and thus $1/cd$ must be an eigenvalue and $\\vec{a}$ an eigenvector of $A^TA$.\n" 256 | ] 257 | }, 258 | { 259 | "cell_type": "markdown", 260 | "metadata": { 261 | "deletable": true, 262 | "editable": true 263 | }, 264 | "source": [] 265 | }, 266 | { 267 | "cell_type": "markdown", 268 | "metadata": { 269 | "deletable": true, 270 | "editable": true 271 | }, 272 | "source": [ 273 | "For the HITS algorithm, we start with an initial guess for $\\vec{a}$, denoted $\\vec{a}(0)$. Then we calculate $A\\vec{a}(0)$ and normalize the\n", 274 | "resulting vector to sum to 1 to give $\\vec{h}(0)$. Then we find $A^T\\vec{h}(0)$ and normalize it to sum to 1, giving $\\vec{a}(1)$. The\n", 275 | "limit of $\\vec{a}$ as this process is repeated is considered to give the authority weights of the page.\n", 276 | "\n", 277 | "##### Part d\n", 278 | "\n", 279 | "Write a function\n", 280 | "\n", 281 | "`HITS_auth(G, initial_weights, iterations)`\n", 282 | "\n", 283 | "for which \n", 284 | "- `G` is a directed graph\n", 285 | "- `initial_weights` is a dict such that `initial_weights[node]` gives the initial authority weight assigned to `node`.\n", 286 | "- `iterations` is the number of iterations to perform [so we find $\\vec{a}($ `iterations` $)$].\n", 287 | "\n", 288 | "It should return $\\vec{a}($ `iterations` $)$.\n", 289 | "\n", 290 | "This method **should not rely on matrix multiplication**. You will use it below. You should probably check a few calculations by hand.\n" 291 | ] 292 | }, 293 | { 294 | "cell_type": "code", 295 | "execution_count": null, 296 | "metadata": { 297 | "collapsed": true, 298 | "deletable": true, 299 | "editable": true 300 | }, 301 | "outputs": [], 302 | "source": [] 303 | }, 304 | { 305 | "cell_type": "markdown", 306 | "metadata": { 307 | "deletable": true, 308 | "editable": true 309 | }, 310 | "source": [ 311 | "\n", 312 | "Consider the following network:" 313 | ] 314 | }, 315 | { 316 | "cell_type": "code", 317 | "execution_count": 9, 318 | "metadata": { 319 | "collapsed": false, 320 | "deletable": true, 321 | "editable": true 322 | }, 323 | "outputs": [ 324 | { 325 | "data": { 326 | "image/png": "iVBORw0KGgoAAAANSUhEUgAAAdcAAAFCCAYAAACjL5cxAAAABHNCSVQICAgIfAhkiAAAAAlwSFlz\nAAALEgAACxIB0t1+/AAAIABJREFUeJzt3XmUVPXd5/FPNd3Q1TAiaZYQmIAQUCKgHoU4eAhrPDZx\norglY5xA6+QJolk0aHAhSsbAk6gY0UblORrOo5moeCaYoHHUKPjEk1EWWSIoUUNciIE4CjbdTW93\n/rj8ml6qumu5y+/e+36d00epulX+2h/V335X3a5OOY7jCAAAeKYk7AUAABA3DFcAADzGcAUAwGMM\nVwAAPMZwBQDAYwxXAAA8xnAFAMBjDFcAADzGcAUAwGMMVwAAPMZwBQDAYwxXAAA8xnAFAMBjDFcA\nADzGcAUAwGMMVwAAPMZwBQDAYwxXAAA8xnAFAMBjDFcAADzGcAUAwGMMVwAAPMZwBQDAYwxXAAA8\nxnAFAMBjpWEvAIAH9u+X1qyRduyQDh6U+veXJk6UqqulQYPCXh2QOCnHcZywFwGgQJs2ScuXS7//\nvfvnhoZj16XTkuNIVVXSDTdIkyaFs0YggRiuQFTdd5+0aJFUX+8O0WxSKXfQ3nGHdOWVwa0PSDCe\nFgaiyAzWurqej3Uc97hFi9w/M2AB31GuQNRs2iRNn95hsN4raY2knZL+29F/z6iiQtq4UTrjDH/X\nCCQcZwsDUbN8uftUcDufk3SzpMt7um19vXt7AL6iXIEo2b9fGjGi44lL7dws6X11U66SVF4uvfsu\nZxEDPqJcgShZs6b4+0ilvLkfAFkxXIEo2bEja7XmrL5e2rnTm/UAyIjhCkTJwYPe3M/HH3tzPwAy\nYrgCUdK/vzf3M2CAN/cDICOGKxAlEye6JyR10iypQVLL0Y+Go5dllE5LEyb4tUIA4mxhIFqynC18\nq6SlnQ695ejlXXC2MOA7yhWIgObmZu3du1ePb9igptmz3TN+27lVktPp49YM9+OkUvrglFP0XkOD\nWlpafF41kFyUK2CJw4cPa9OmTdq7d6/eeecd7dq1S2+99Zbef/99ffLJJ5KklpYWvfyLX2jKjTfm\n9taHnTSVlem/NDVpR1mZWltbVVlZqeHDh2vMmDEaN26cRo0apZEjR2ry5Mnq06eP158ikBgMV8AS\nd999t6699lql02nV1dWp80MzlUpp9uzZevbZZ/N7b2GjokLOHXdo/L33ateuXV2uLikpUUVFhWpr\na7V27VpddNFFxX5KQGIxXAFL1NfXa8yYMfrggw8yXp9Op7V7926NGDHCvaDA34qzZcsWTZ06VfWd\n3kLRPTSliRMnasuWLerVq5cXnxaQSLzmClginU7r8ccfVzqdznjd1VdffWywSnpi0CBNaWpS07nn\nuicpdb5dOq3W3r21LpXS1rvuavttOKeffrrOO+88lZWVdfnvlJeX6/HHH2ewAkWiXAGLNDY26qyz\nztLmzZs7XH788cfrvffeU79+/dTU1KTrr79eNTU1am5u1v79+zXQcdy3NNy5032DiAEDpAkT9Pqk\nSZowc6bKysp0yy23aPHixSopKdHf//53feELX1Bdp6eVzz33XK1bt47hChSJcgUssXXrVp1xxhka\nPHiwhg4d2nZ53759tWLFCvXr10/vvfeeJk2apAceeEBNTU3H6nPQIOm666R//3fpd79z/3nddWqt\nrFQ6nVZjY6N++tOfatasWfroo480dOhQLV68WBUVFZLcp4PHjRungwcPatq0adqzZ08Y/wuA2GC4\nAiFrbGzUkiVLdM455+j666/X+vXr9cQTT7Q9PTx8+HDNmzdPTz31lMaPH68///nPba+XlpT0/BAu\nLS2VJNXV1enll1/WSSedpD/96U+67rrr1K9fP0nu08Hr1q3Thg0b9PWvf11TpkzRXXfdxY/rAAVi\nuAIhMrW6fft2bd++XZdddplSqZSmTJmiK664QpJ0//3364c//KEuvvhiHTp0qKiB19TUpH/+85+a\nNWuWVqxYoXvuuUeStHTpUo0dO1YlJSX67ne/q1deeUXr1q2jYoFCOQACd+TIEefmm292Bg0a5Dz8\n8MNOa2trl2Pq6uqctWvXOqeffrpTXl7e+T0iHElOeXm5c+DAgaz/nR07djjHHXdc1ttWVVU5jz32\nmNPc3Nzlti0tLc7KlSudyspKZ8WKFRmPAZAZ5QoELFutdpZOp3XhhRfqq1/9qkpKSlSe4T2FC1VR\nUaHevXvrnHPO0SWXXJLxBCYqFigcwxUISOfXVp988skOJy5lkkqltHTpUr3//vu65pprVFZWltPr\nrNmUlJQonU5ryZIl2rdvn773ve/1eJvRo0frxRdf5LVYIA/8KA4QgK1bt2r+/PkaOXKkHnjggR6H\naia1tbU64YQTNHfuXP3qV79Sa2urWlpatG/fPg0cODDjbXbu3KnJkyerpKREpaWluuSSS7Rhwwbt\n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\n", 327 | "text/plain": [ 328 | "" 329 | ] 330 | }, 331 | "metadata": {}, 332 | "output_type": "display_data" 333 | } 334 | ], 335 | "source": [ 336 | "import networkx as nx\n", 337 | "import matplotlib.pyplot as plt\n", 338 | "\n", 339 | "G = nx.DiGraph()\n", 340 | "G.add_edges_from([(6,2), (6,3), (6,4), (6,5), (2,1), (3,1), (4,1), (5,1)])\n", 341 | "\n", 342 | "#you don't need to worry about how I'm defining `pos` here. It's just\n", 343 | "#so that you can see the network structure more clearly.\n", 344 | "pos = {1:(0,0), 2:(-3,-2), 3:(-1,-2), 4:(1,-2), 5:(3,-2), 6:(0,-4)}\n", 345 | "\n", 346 | "nx.draw(G, pos, with_labels = True, arrowsize=20)\n", 347 | "plt.show()" 348 | ] 349 | }, 350 | { 351 | "cell_type": "markdown", 352 | "metadata": { 353 | "deletable": true, 354 | "editable": true 355 | }, 356 | "source": [ 357 | "##### Part e\n", 358 | "\n", 359 | "By starting with the initial guess that all nodes have authority weight $1/6$, calculate the HITS authority weights after 50 iterations." 360 | ] 361 | }, 362 | { 363 | "cell_type": "code", 364 | "execution_count": null, 365 | "metadata": { 366 | "collapsed": true, 367 | "deletable": true, 368 | "editable": true 369 | }, 370 | "outputs": [], 371 | "source": [] 372 | }, 373 | { 374 | "cell_type": "markdown", 375 | "metadata": { 376 | "deletable": true, 377 | "editable": true 378 | }, 379 | "source": [ 380 | "##### Part f\n", 381 | "\n", 382 | "Now take a different initial guess with the authority weight of page 1 equal to $1/3$, the weights of pages\n", 383 | "2, 3, 4, and 5 all equal to $1/12$ and the weight of page 6 equal to $1/3$. Use 50 iterations to calculate the\n", 384 | "HITS authority weights. You should get a different answer." 385 | ] 386 | }, 387 | { 388 | "cell_type": "code", 389 | "execution_count": null, 390 | "metadata": { 391 | "collapsed": true, 392 | "deletable": true, 393 | "editable": true 394 | }, 395 | "outputs": [], 396 | "source": [] 397 | }, 398 | { 399 | "cell_type": "markdown", 400 | "metadata": { 401 | "deletable": true, 402 | "editable": true 403 | }, 404 | "source": [ 405 | "##### Part g\n", 406 | "\n", 407 | "Calculate the **`PageRank`** of `G` with $\\alpha = 0.1$ and 50 iterations. Then add a node $7$ to `G` with edges to 2, 3, 4, and 5 and recalculate the PageRank. Comment on how the ranking of the nodes changes for these two networks. \n", 408 | "\n", 409 | "\n", 410 | "(if you go back and recalculate anything above, make sure you reset `G`)" 411 | ] 412 | }, 413 | { 414 | "cell_type": "code", 415 | "execution_count": null, 416 | "metadata": { 417 | "collapsed": true, 418 | "deletable": true, 419 | "editable": true 420 | }, 421 | "outputs": [], 422 | "source": [] 423 | }, 424 | { 425 | "cell_type": "markdown", 426 | "metadata": { 427 | "deletable": true, 428 | "editable": true 429 | }, 430 | "source": [ 431 | "#### Part h\n", 432 | "\n", 433 | "Find the HITS authority weights assuming an initial guess of $1/7$ for all pages in this new network.\n", 434 | "\n", 435 | "Then find the HITS authority weights assuming an initial guess with the authority weight of page 1 equal to $1/3$, the weights of pages 2, 3, 4, and 5 all $1/12$ and the weights of pages 6 and 7 both $1/6$.\n", 436 | "\n", 437 | "Comment on how this is similar or different to what you saw for the authority weights of the original network." 438 | ] 439 | }, 440 | { 441 | "cell_type": "code", 442 | "execution_count": null, 443 | "metadata": { 444 | "collapsed": true, 445 | "deletable": true, 446 | "editable": true 447 | }, 448 | "outputs": [], 449 | "source": [] 450 | }, 451 | { 452 | "cell_type": "markdown", 453 | "metadata": { 454 | "deletable": true, 455 | "editable": true 456 | }, 457 | "source": [ 458 | "##### Part i\n", 459 | "\n", 460 | "Calculate the eigenvalues of $A^TA$ for the two versions of the network (you can do this numerically with numpy or matlab). \n", 461 | "\n", 462 | "Use the results to explain why it is possible for the final result to depend on the starting point for HITS on the first network, but not for\n", 463 | "the modified network. " 464 | ] 465 | }, 466 | { 467 | "cell_type": "code", 468 | "execution_count": null, 469 | "metadata": { 470 | "collapsed": true, 471 | "deletable": true, 472 | "editable": true 473 | }, 474 | "outputs": [], 475 | "source": [] 476 | } 477 | ], 478 | "metadata": { 479 | "kernelspec": { 480 | "display_name": "Python 3", 481 | "language": "python", 482 | "name": "python3" 483 | }, 484 | "language_info": { 485 | "codemirror_mode": { 486 | "name": "ipython", 487 | "version": 3 488 | }, 489 | "file_extension": ".py", 490 | "mimetype": "text/x-python", 491 | "name": "python", 492 | "nbconvert_exporter": "python", 493 | "pygments_lexer": "ipython3", 494 | "version": "3.5.2" 495 | } 496 | }, 497 | "nbformat": 4, 498 | "nbformat_minor": 2 499 | } 500 | -------------------------------------------------------------------------------- /Assignments/Assignment 2.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": { 6 | "deletable": true, 7 | "editable": true 8 | }, 9 | "source": [ 10 | "modifications since placed online:\n", 11 | "\n", 12 | "- In 3.a.vi, changed $c_i(t)$ to $\\alpha_i(t)$.\n", 13 | "\n", 14 | "- **This change is only a comment and does not affect any of the work you are asked to do**: added paragraph after last problem about the fact that the prediction is valid for all time, not just large time. \n", 15 | "\n", 16 | "\n", 17 | "# Assignment 2" 18 | ] 19 | }, 20 | { 21 | "cell_type": "markdown", 22 | "metadata": { 23 | "collapsed": true, 24 | "deletable": true, 25 | "editable": true 26 | }, 27 | "source": [] 28 | }, 29 | { 30 | "cell_type": "markdown", 31 | "metadata": { 32 | "deletable": true, 33 | "editable": true 34 | }, 35 | "source": [ 36 | "## Question 1:\n", 37 | "\n", 38 | "In this question we will explore some properties of Configuration Model and Erdős–Rényi networks.\n", 39 | "\n", 40 | "In this problem it will be useful to set up a loop that runs until a list gets to a certain length. Here is an example of how this can be done:" 41 | ] 42 | }, 43 | { 44 | "cell_type": "code", 45 | "execution_count": 1, 46 | "metadata": { 47 | "collapsed": true, 48 | "deletable": true, 49 | "editable": true 50 | }, 51 | "outputs": [], 52 | "source": [ 53 | "import random\n", 54 | "\n", 55 | "L = []\n", 56 | "while len(L)<1000: #this loop gives some hints of how one \n", 57 | " if random.random()<0.5: #might repeat until 1000 objects have been\n", 58 | " L.append(1) #found\n" 59 | ] 60 | }, 61 | { 62 | "cell_type": "markdown", 63 | "metadata": { 64 | "deletable": true, 65 | "editable": true 66 | }, 67 | "source": [ 68 | "### Part a)\n", 69 | "#### i)\n", 70 | "Use the built-in networkx command to create a Configuration Model network with $N=100$,$000$ nodes, with half having degree $5$, and the other half having degree $10$." 71 | ] 72 | }, 73 | { 74 | "cell_type": "code", 75 | "execution_count": null, 76 | "metadata": { 77 | "collapsed": true, 78 | "deletable": true, 79 | "editable": true 80 | }, 81 | "outputs": [], 82 | "source": [] 83 | }, 84 | { 85 | "cell_type": "markdown", 86 | "metadata": { 87 | "deletable": true, 88 | "editable": true 89 | }, 90 | "source": [ 91 | "#### ii)\n", 92 | "Choose 1000 nodes at random from the network and create a histogram of their degrees. Use the `plt.hist` command, and set `density = True`." 93 | ] 94 | }, 95 | { 96 | "cell_type": "code", 97 | "execution_count": null, 98 | "metadata": { 99 | "collapsed": true, 100 | "deletable": true, 101 | "editable": true 102 | }, 103 | "outputs": [], 104 | "source": [] 105 | }, 106 | { 107 | "cell_type": "markdown", 108 | "metadata": { 109 | "deletable": true, 110 | "editable": true 111 | }, 112 | "source": [ 113 | "#### iii)\n", 114 | "Choose nodes $v_i$ at random from the graph and then choose a neighbor $w_i$ (at random). Repeat until $1000$ nodes $w_i$ have been chosen. Then create a histogram of the degrees of the $w_i$. Use the `plt.hist` command, and set `density = True`.\n" 115 | ] 116 | }, 117 | { 118 | "cell_type": "code", 119 | "execution_count": null, 120 | "metadata": { 121 | "collapsed": true, 122 | "deletable": true, 123 | "editable": true 124 | }, 125 | "outputs": [], 126 | "source": [] 127 | }, 128 | { 129 | "cell_type": "markdown", 130 | "metadata": { 131 | "deletable": true, 132 | "editable": true 133 | }, 134 | "source": [ 135 | "#### iv)\n", 136 | "Explain the differences between the two histograms." 137 | ] 138 | }, 139 | { 140 | "cell_type": "markdown", 141 | "metadata": { 142 | "deletable": true, 143 | "editable": true 144 | }, 145 | "source": [] 146 | }, 147 | { 148 | "cell_type": "markdown", 149 | "metadata": { 150 | "deletable": true, 151 | "editable": true 152 | }, 153 | "source": [ 154 | "### Part b)\n", 155 | "\n", 156 | "Use one of the built-in networkx commands to create an Erdős–Rényi network with $N=100$,$000$ nodes and average degree $4$. " 157 | ] 158 | }, 159 | { 160 | "cell_type": "code", 161 | "execution_count": null, 162 | "metadata": { 163 | "collapsed": true, 164 | "deletable": true, 165 | "editable": true 166 | }, 167 | "outputs": [], 168 | "source": [] 169 | }, 170 | { 171 | "cell_type": "markdown", 172 | "metadata": { 173 | "deletable": true, 174 | "editable": true 175 | }, 176 | "source": [ 177 | "#### i)\n", 178 | "Choose 1000 nodes at random from the network and create a histogram of their degrees.\n" 179 | ] 180 | }, 181 | { 182 | "cell_type": "code", 183 | "execution_count": null, 184 | "metadata": { 185 | "collapsed": true, 186 | "deletable": true, 187 | "editable": true 188 | }, 189 | "outputs": [], 190 | "source": [] 191 | }, 192 | { 193 | "cell_type": "markdown", 194 | "metadata": { 195 | "deletable": true, 196 | "editable": true 197 | }, 198 | "source": [ 199 | "#### ii)\n", 200 | "Choose nodes $v_i$ at random from the graph and if it has non-zero degree, choose a neighbor $w_i$ (at random). Repeat until $1000$ of the $w_i$ have been chosen Then create a histogram of their degrees (with bin width 1)." 201 | ] 202 | }, 203 | { 204 | "cell_type": "code", 205 | "execution_count": null, 206 | "metadata": { 207 | "collapsed": true, 208 | "deletable": true, 209 | "editable": true 210 | }, 211 | "outputs": [], 212 | "source": [] 213 | }, 214 | { 215 | "cell_type": "markdown", 216 | "metadata": { 217 | "deletable": true, 218 | "editable": true 219 | }, 220 | "source": [ 221 | "#### iii)\n", 222 | "How are these two histograms similar?" 223 | ] 224 | }, 225 | { 226 | "cell_type": "markdown", 227 | "metadata": { 228 | "deletable": true, 229 | "editable": true 230 | }, 231 | "source": [] 232 | }, 233 | { 234 | "cell_type": "markdown", 235 | "metadata": { 236 | "deletable": true, 237 | "editable": true 238 | }, 239 | "source": [ 240 | "#### iv) \n", 241 | "When the average degree is small compared to the number of nodes, Erdős–Rényi networks have a Poisson degree distribution. So the probability of a degree $k$ given an average $r$ is $r^k e^{-r}/k!$ . Use this to show that the similarity you observed in the histograms is to be expected." 242 | ] 243 | }, 244 | { 245 | "cell_type": "markdown", 246 | "metadata": { 247 | "deletable": true, 248 | "editable": true 249 | }, 250 | "source": [] 251 | }, 252 | { 253 | "cell_type": "markdown", 254 | "metadata": { 255 | "deletable": true, 256 | "editable": true 257 | }, 258 | "source": [ 259 | "## Question 2:\n", 260 | "\n", 261 | "The following function will generate a Configuration Model network of $N$ nodes, with a fraction $p$ of the nodes having degree $3$ and the rest having degree $1$." 262 | ] 263 | }, 264 | { 265 | "cell_type": "code", 266 | "execution_count": null, 267 | "metadata": { 268 | "collapsed": true, 269 | "deletable": true, 270 | "editable": true 271 | }, 272 | "outputs": [], 273 | "source": [ 274 | "import networkx as nx\n", 275 | "import random\n", 276 | "\n", 277 | "def generate_degree_3_and_1_CM_network(N, p):\n", 278 | " r'''\n", 279 | " Inputs:\n", 280 | " N : integer, the number of nodes. Must be even\n", 281 | " p : probability between 0 and 1.\n", 282 | " \n", 283 | " Returns:\n", 284 | " G : Configuration Model Graph\n", 285 | " '''\n", 286 | " \n", 287 | " if N%2 !=0:\n", 288 | " raise ValueError(\"N must be even\")\n", 289 | " M = int(N*p)\n", 290 | " deg_dist = [3]*M + [1]*(N-M)\n", 291 | " random.shuffle(deg_dist) #this shuffles the degree distribution. It\n", 292 | " #is included here purely so that there is\n", 293 | " #no correlation between the node id and its\n", 294 | " #degree\n", 295 | " G = nx.configuration_model(deg_dist)\n", 296 | " return G\n", 297 | " \n", 298 | " " 299 | ] 300 | }, 301 | { 302 | "cell_type": "markdown", 303 | "metadata": { 304 | "deletable": true, 305 | "editable": true 306 | }, 307 | "source": [ 308 | "A \"Connected Component\" of a graph is a maximal connected subset of the nodes. The proportion of nodes in the largest connected component of a graph `G` is given by \n", 309 | "\n", 310 | "`max(len(CC) for CC in nx.connected_components(G))/G.order()`\n", 311 | "\n", 312 | "#### i) \n", 313 | "Set $N=1000$ and generate graphs `G` using the function above for each $p$ from $0$ to $1$ by steps of size $0.01$ [e.g., `for p in np.linspace(0,1,101):`]. Plot the proportion of `G`'s nodes which are in the largest connected component. Repeat for $N=5000$ and $N=10000$ on the same plot.\n" 314 | ] 315 | }, 316 | { 317 | "cell_type": "code", 318 | "execution_count": null, 319 | "metadata": { 320 | "collapsed": true, 321 | "deletable": true, 322 | "editable": true 323 | }, 324 | "outputs": [], 325 | "source": [] 326 | }, 327 | { 328 | "cell_type": "markdown", 329 | "metadata": { 330 | "deletable": true, 331 | "editable": true 332 | }, 333 | "source": [ 334 | "\n", 335 | "#### ii)\n", 336 | "There should be a threshold value of $p$ where behavior changes. In light of what you learned in the previous problem, explain why this threshold is where it is.\n" 337 | ] 338 | }, 339 | { 340 | "cell_type": "markdown", 341 | "metadata": { 342 | "deletable": true, 343 | "editable": true 344 | }, 345 | "source": [] 346 | }, 347 | { 348 | "cell_type": "markdown", 349 | "metadata": { 350 | "deletable": true, 351 | "editable": true 352 | }, 353 | "source": [ 354 | "## Question 3:" 355 | ] 356 | }, 357 | { 358 | "cell_type": "markdown", 359 | "metadata": { 360 | "deletable": true, 361 | "editable": true 362 | }, 363 | "source": [ 364 | "In lecture we looked at coupled oscillators with identical natural frequency on a connected graph. Under the assumption that their phases are initially close together, we showed that they should converge to exactly the same phase.\n", 365 | "\n", 366 | "In this question we will consider what happens when the coupled oscillators have similar but not identical natural frequencies, and under the assumption that the phases stay close together." 367 | ] 368 | }, 369 | { 370 | "cell_type": "markdown", 371 | "metadata": { 372 | "deletable": true, 373 | "editable": true 374 | }, 375 | "source": [ 376 | "### Part a)\n", 377 | "#### i)\n", 378 | "Starting from the model equation for $j = 0, 1, \\ldots, N-1$ nodes:\n", 379 | "\\begin{equation*}\n", 380 | "\\frac{d}{dt} \\phi_j(t) = \\omega_j + c \\sum_{k: \\{k,j\\}\\text{ is an edge}} \\sin(\\phi_k(t) - \\phi_j(t))\n", 381 | "\\end{equation*}\n", 382 | "Set $\\overline{\\omega} = \\sum \\omega_j /N$. Show that by setting $\\hat{\\phi}_j(t) = \\phi_j(t) - \\overline{\\omega} t$ and $\\hat{\\omega}_j = \\omega_j - \\overline{\\omega}$ we arrive at the model\n", 383 | "\\begin{equation*}\n", 384 | "\\frac{d}{dt} \\hat{\\phi}_j(t) = \\hat{\\omega}_j + c \\sum_{k: \\{k,j\\}\\text{ is an edge}} \\sin(\\hat{\\phi}_k(t) - \\hat{\\phi}_j(t))\n", 385 | "\\end{equation*}\n", 386 | "where now $\\hat{\\omega}_j$ has average $0$." 387 | ] 388 | }, 389 | { 390 | "cell_type": "markdown", 391 | "metadata": { 392 | "deletable": true, 393 | "editable": true 394 | }, 395 | "source": [] 396 | }, 397 | { 398 | "cell_type": "markdown", 399 | "metadata": { 400 | "deletable": true, 401 | "editable": true 402 | }, 403 | "source": [ 404 | "#### ii)\n", 405 | "Now drop the hats and explain why if the phases are all close together, we can assume the equations are can be written in vector form as approximately\n", 406 | "\\begin{equation*}\n", 407 | "\\frac{d}{dt} \\vec{\\phi}(t) = \\vec{\\omega} - c L \\vec{\\phi}(t)\n", 408 | "\\end{equation*}\n", 409 | "Where the matrix $L = D-A$ where $D$ is the diagonal matrix whose entry $D_{ii}$ is the degree of node $i$ and $A$ is the adjacency matrix. The matrix $L$ is known as the **Laplacian of `G`**. In the lectures we used $A-D$ in place of $-L$." 410 | ] 411 | }, 412 | { 413 | "cell_type": "markdown", 414 | "metadata": { 415 | "deletable": true, 416 | "editable": true 417 | }, 418 | "source": [] 419 | }, 420 | { 421 | "cell_type": "markdown", 422 | "metadata": { 423 | "deletable": true, 424 | "editable": true 425 | }, 426 | "source": [ 427 | "#### iii)\n", 428 | "\n", 429 | "Show that for a connected graph `G`, the Laplacian `L` is real and symmetric. This guarantees that each eigenector of `L` is real and has a full eigenspace (and that the eigenvectors are orthogonal).\n" 430 | ] 431 | }, 432 | { 433 | "cell_type": "markdown", 434 | "metadata": { 435 | "deletable": true, 436 | "editable": true 437 | }, 438 | "source": [] 439 | }, 440 | { 441 | "cell_type": "markdown", 442 | "metadata": { 443 | "deletable": true, 444 | "editable": true 445 | }, 446 | "source": [ 447 | "#### iv)\n", 448 | "Let $r_0, r_1, \\ldots, r_{N-1}$ be the eigenvalues of $L$ and $\\vec{w}_0, \\vec{w}_1, \\ldots, \\vec{w}_{N-1}$ be the corresponding eigenvectors.\n", 449 | "\n", 450 | "Explain why we know that we can write\n", 451 | "\\begin{equation*}\n", 452 | "\\vec{\\phi}(t) = \\sum \\alpha_i(t) \\vec{w}_i\n", 453 | "\\end{equation*}\n", 454 | "and \n", 455 | "\\begin{equation*}\n", 456 | "\\vec{\\omega} = \\sum \\beta_i \\vec{w}_i\n", 457 | "\\end{equation*}\n" 458 | ] 459 | }, 460 | { 461 | "cell_type": "code", 462 | "execution_count": null, 463 | "metadata": { 464 | "collapsed": true, 465 | "deletable": true, 466 | "editable": true 467 | }, 468 | "outputs": [], 469 | "source": [] 470 | }, 471 | { 472 | "cell_type": "markdown", 473 | "metadata": { 474 | "deletable": true, 475 | "editable": true 476 | }, 477 | "source": [ 478 | "#### v)\n", 479 | "Show that $L$ has an eigenvalue equal to zero, which we take to be $r_0$. Additionally (you do not need to prove this), the Perron-Frobenius theorem can be used with a few twists to show that the zero eigenvalue is simple and all others have positive real part.\n" 480 | ] 481 | }, 482 | { 483 | "cell_type": "markdown", 484 | "metadata": { 485 | "deletable": true, 486 | "editable": true 487 | }, 488 | "source": [ 489 | "#### vi)\n", 490 | "\n", 491 | "Rewrite the vector equation for $d \\vec{\\phi}(t) /dt$ above in terms of sums of eigenvectors of $L$, and find a differential equation for $\\alpha_i(t)$. Find the solution for $\\alpha_i(t)$ in the case that $r_0=0$ and in the case that $r_i \\neq 0$ (this second case may require integrating factors or other techniques). \n" 492 | ] 493 | }, 494 | { 495 | "cell_type": "markdown", 496 | "metadata": { 497 | "deletable": true, 498 | "editable": true 499 | }, 500 | "source": [] 501 | }, 502 | { 503 | "cell_type": "markdown", 504 | "metadata": { 505 | "deletable": true, 506 | "editable": true 507 | }, 508 | "source": [ 509 | "#### vii)\n", 510 | "Show that for $r_i \\neq 0$, the solution $\\alpha_i(t)$ approaches a constant as $t \\to \\infty$, and find the constant value in terms of $\\beta_i$.\n", 511 | "\n" 512 | ] 513 | }, 514 | { 515 | "cell_type": "markdown", 516 | "metadata": { 517 | "deletable": true, 518 | "editable": true 519 | }, 520 | "source": [ 521 | "#### viii)\n", 522 | "I do not ask you to show it, but you can assume that for the eigenvalue $r_0=0$, \n", 523 | "- the coefficient $\\beta_0$ is $0$ and \n", 524 | "- $\\alpha_0(t)$ is constant and equals the average of $\\phi_i(0)$.\n", 525 | "\n", 526 | "Using this and your previous answer, write down the long-term phase vector $\\lim_{t\\to\\infty} \\vec{\\phi}(t)$ as a function of the $\\beta_i$ for $i \\neq 0$ and the constant $\\alpha_0$." 527 | ] 528 | }, 529 | { 530 | "cell_type": "markdown", 531 | "metadata": { 532 | "deletable": true, 533 | "editable": true 534 | }, 535 | "source": [ 536 | "### Part b)\n", 537 | "\n", 538 | "Now we check our predictions. The functions below will take a graph `G` and some initial conditions and solve the Kuramoto model. These are (almost) identical to what was presented in the lecture, except that I have change the function `display_phases` to `plot_phases`, and you now need to include `plt.show()` to actually make the plots show." 539 | ] 540 | }, 541 | { 542 | "cell_type": "code", 543 | "execution_count": 2, 544 | "metadata": { 545 | "collapsed": true, 546 | "deletable": true, 547 | "editable": true 548 | }, 549 | "outputs": [], 550 | "source": [ 551 | "import networkx as nx\n", 552 | "import scipy.integrate as integrate\n", 553 | "import numpy as np\n", 554 | "import matplotlib.pyplot as plt\n", 555 | "import scipy\n", 556 | "import random\n", 557 | "\n", 558 | "#First some things that will be needed to find the derivatives.\n", 559 | "\n", 560 | "def phase_deriv(node, X, G, frequencies, c):\n", 561 | " #calculates the derivative of the phase of `node` given the current state\n", 562 | " \n", 563 | " if nx.is_directed(G): #behaves differently if graph is directed\n", 564 | " phase_differences = [(X[pred] - X[node]) for pred in G.predecessors(node)]\n", 565 | " else:\n", 566 | " phase_differences = [(X[neighbor] - X[node]) for neighbor in G.neighbors(node)]\n", 567 | " sin_phase_diff = np.sin(np.array(phase_differences))\n", 568 | " #sin_phase_diff = map(lambda x: scipy.sin(2*scipy.pi*x), phase_differences)\n", 569 | " Y = sin_phase_diff.sum()\n", 570 | " return frequencies[node] + c*Y\n", 571 | "\n", 572 | "\n", 573 | "def dphase_dt(X, t, G, frequencies, c): \n", 574 | " #uses phase_deriv to find the derivative of phases of all nodes.\n", 575 | " dXdt = np.array([phase_deriv(node, X, G, frequencies, c) for node in G.nodes()])\n", 576 | " return dXdt\n", 577 | "\n", 578 | "\n", 579 | "def solve_model(G, tstop, c = 1, initial_phase = None, natural_frequencies = None, ntimes = 1001):\n", 580 | " r'''\n", 581 | " The arguments of this function are:\n", 582 | " \n", 583 | " G - a networkx Graph or a DiGraph\n", 584 | " \n", 585 | " tstop - final time of simulation (assumes that it starts at 0)\n", 586 | " \n", 587 | " c - an optional argument for the coupling strength, it defaults to 1.\n", 588 | " \n", 589 | " initial_phase - an optional argument giving the initial_phase of all nodes. \n", 590 | " Input as a dict. It defaults to random values in (0, 2pi) for each node\n", 591 | " \n", 592 | " natural_frequencies - an optional argument giving the natural frequencies of all nodes.\n", 593 | " Input as a dict. It defaults to random values in -0.5, 0.5\n", 594 | " \n", 595 | " ntimes - an integer stating how many points between 0 and tstop should be returned.\n", 596 | " \n", 597 | " \n", 598 | " \n", 599 | " the function returns:\n", 600 | " times - an np array of times\n", 601 | " X - a 2d np array giving the oscillator phase of each node at each time in times.'''\n", 602 | " \n", 603 | " nodelist = list(G.nodes())\n", 604 | " if natural_frequencies is None:\n", 605 | " frequencies =[-0.5+np.random.random() for node in nodelist] \n", 606 | " else:\n", 607 | " frequencies = [natural_frequencies[node] for node in nodelist]\n", 608 | " if initial_phase is None:\n", 609 | " phase0 = np.array([np.random.random()*2*np.pi for node in nodelist])\n", 610 | " else:\n", 611 | " phase0 = np.array([initial_phase[node] for node in nodelist])\n", 612 | " times = np.linspace(0, tstop, ntimes)\n", 613 | " X = integrate.odeint(dphase_dt, phase0, times, args = (G, frequencies, c))\n", 614 | " \n", 615 | " return times, X\n", 616 | " \n", 617 | "def plot_phases(times, X, start_time = None, stop_time = None):\n", 618 | " r''' \n", 619 | " \n", 620 | " Code for displaying the phases of the oscillators. \n", 621 | " \n", 622 | " Arguments\n", 623 | " ---------\n", 624 | " \n", 625 | " times - the times returned by solve_model\n", 626 | " X - the phases returned by solve_model\n", 627 | " \n", 628 | " optional Arguments\n", 629 | " ------------------\n", 630 | " start_time - the time to start the plots at. default to initial time\n", 631 | " stop_time - the time to stop the plots at. default to final time'''\n", 632 | " \n", 633 | " if start_time is None:\n", 634 | " start_index =0\n", 635 | " elif start_time>times[-1]:\n", 636 | " raise ValueError(\"start_time is greater than times[-1]\")\n", 637 | " else:\n", 638 | " start_index = np.argmax(times>=start_time)\n", 639 | " if stop_time is None:\n", 640 | " stop_index = len(times)-1\n", 641 | " elif stop_time < times[0]:\n", 642 | " raise ValueError(\"stop_time is less than times[0]\")\n", 643 | " else:\n", 644 | " stop_index = np.argmax(times>= stop_time)\n", 645 | " if start_index>stop_index:\n", 646 | " raise ValueError(\"start_time > stop_time\")\n", 647 | " \n", 648 | " plt.clf()\n", 649 | " for node in G.nodes():\n", 650 | " x = times[start_index:stop_index]\n", 651 | " y = X[start_index:stop_index, node]%(2*np.pi)\n", 652 | " \n", 653 | " #when we mod out by 2pi, we introduce discontinuities (where it crosses the top a\n", 654 | " #re-enters on the bottom). These next commands prevent matplotlib from putting vertical\n", 655 | " #lines at those points.\n", 656 | " jumppos = np.where(np.abs(np.diff(y)) >= 1.5*np.pi)[0]+1\n", 657 | " x = np.insert(x, jumppos, np.nan)\n", 658 | " y = np.insert(y, jumppos, np.nan)\n", 659 | " plt.plot(x,y)\n", 660 | " plt.xlabel('times')\n", 661 | " plt.ylabel('phases')\n" 662 | ] 663 | }, 664 | { 665 | "cell_type": "markdown", 666 | "metadata": { 667 | "deletable": true, 668 | "editable": true 669 | }, 670 | "source": [ 671 | "#### i)\n", 672 | "- Define `G` to be an Erdős–Rényi network of 100 nodes and average degree 2.\n" 673 | ] 674 | }, 675 | { 676 | "cell_type": "code", 677 | "execution_count": null, 678 | "metadata": { 679 | "collapsed": true, 680 | "deletable": true, 681 | "editable": true 682 | }, 683 | "outputs": [], 684 | "source": [] 685 | }, 686 | { 687 | "cell_type": "markdown", 688 | "metadata": { 689 | "collapsed": true, 690 | "deletable": true, 691 | "editable": true 692 | }, 693 | "source": [ 694 | "- Restrict your attention to the largest connected component of `G` and rename `G` to this component. This is done with these commands:\n" 695 | ] 696 | }, 697 | { 698 | "cell_type": "code", 699 | "execution_count": null, 700 | "metadata": { 701 | "collapsed": true, 702 | "deletable": true, 703 | "editable": true 704 | }, 705 | "outputs": [], 706 | "source": [ 707 | "largest_component = max(nx.connected_components(G), key = len)\n", 708 | "G = nx.Graph(nx.induced_subgraph(G,largest_component))\n", 709 | "G = nx.convert_node_labels_to_integers(G)" 710 | ] 711 | }, 712 | { 713 | "cell_type": "markdown", 714 | "metadata": { 715 | "deletable": true, 716 | "editable": true 717 | }, 718 | "source": [ 719 | "- Set " 720 | ] 721 | }, 722 | { 723 | "cell_type": "code", 724 | "execution_count": null, 725 | "metadata": { 726 | "collapsed": true, 727 | "deletable": true, 728 | "editable": true 729 | }, 730 | "outputs": [], 731 | "source": [ 732 | "initial_phase = {node:np.pi+0.2*random.random() for node in G.nodes()}\n", 733 | "natural_frequencies = {node:random.random() for node in G.nodes()}" 734 | ] 735 | }, 736 | { 737 | "cell_type": "markdown", 738 | "metadata": { 739 | "deletable": true, 740 | "editable": true 741 | }, 742 | "source": [ 743 | "#### ii)\n", 744 | "\n", 745 | "Redefine `natural_frequencies` (which corresponds to $\\vec{\\omega}$) by performing the change of variables in step i of part a." 746 | ] 747 | }, 748 | { 749 | "cell_type": "code", 750 | "execution_count": null, 751 | "metadata": { 752 | "collapsed": true, 753 | "deletable": true, 754 | "editable": true 755 | }, 756 | "outputs": [], 757 | "source": [] 758 | }, 759 | { 760 | "cell_type": "markdown", 761 | "metadata": { 762 | "deletable": true, 763 | "editable": true 764 | }, 765 | "source": [ 766 | "#### iii)\n", 767 | "Set times and X to be the outputs from running the model with initial_phase and natural_frequencies for the graph G for 30 units of time with c=4." 768 | ] 769 | }, 770 | { 771 | "cell_type": "code", 772 | "execution_count": null, 773 | "metadata": { 774 | "collapsed": true, 775 | "deletable": true, 776 | "editable": true 777 | }, 778 | "outputs": [], 779 | "source": [] 780 | }, 781 | { 782 | "cell_type": "markdown", 783 | "metadata": { 784 | "deletable": true, 785 | "editable": true 786 | }, 787 | "source": [ 788 | "#### iv)\n", 789 | "The following code generates `L`:\n", 790 | "\n" 791 | ] 792 | }, 793 | { 794 | "cell_type": "code", 795 | "execution_count": null, 796 | "metadata": { 797 | "collapsed": false, 798 | "deletable": true, 799 | "editable": true 800 | }, 801 | "outputs": [], 802 | "source": [ 803 | "A = nx.to_numpy_matrix(G)\n", 804 | "\n", 805 | "d = []\n", 806 | "for node in range(G.order()):\n", 807 | "\n", 808 | " d.append(G.degree(node))\n", 809 | "\n", 810 | "D = np.diag(d)\n", 811 | "\n", 812 | "\n", 813 | "L = D-A" 814 | ] 815 | }, 816 | { 817 | "cell_type": "markdown", 818 | "metadata": { 819 | "deletable": true, 820 | "editable": true 821 | }, 822 | "source": [ 823 | "Use \n", 824 | "\n" 825 | ] 826 | }, 827 | { 828 | "cell_type": "code", 829 | "execution_count": null, 830 | "metadata": { 831 | "collapsed": true, 832 | "deletable": true, 833 | "editable": true 834 | }, 835 | "outputs": [], 836 | "source": [ 837 | "R, W = scipy.linalg.eig(L)" 838 | ] 839 | }, 840 | { 841 | "cell_type": "markdown", 842 | "metadata": { 843 | "deletable": true, 844 | "editable": true 845 | }, 846 | "source": [ 847 | "to find a vector of the eigenvalues R and a matrix of the corresponding eigenvectors W. Each column of W is the eigenvector for the corresponding entry of the eigenvalue in R.\n", 848 | "\n", 849 | "`W` and `R` are real, but numpy stores them as complex numbers (with machine precision level imaginary parts). Let's convert them to reals.\n", 850 | "\n" 851 | ] 852 | }, 853 | { 854 | "cell_type": "code", 855 | "execution_count": null, 856 | "metadata": { 857 | "collapsed": true, 858 | "deletable": true, 859 | "editable": true 860 | }, 861 | "outputs": [], 862 | "source": [ 863 | "W = np.real(W)\n", 864 | "R = np.real(R)" 865 | ] 866 | }, 867 | { 868 | "cell_type": "markdown", 869 | "metadata": { 870 | "deletable": true, 871 | "editable": true 872 | }, 873 | "source": [ 874 | "You can find the coefficients $\\beta_i$ by" 875 | ] 876 | }, 877 | { 878 | "cell_type": "code", 879 | "execution_count": null, 880 | "metadata": { 881 | "collapsed": true, 882 | "deletable": true, 883 | "editable": true 884 | }, 885 | "outputs": [], 886 | "source": [ 887 | "Omegas = np.array([natural_frequencies[node] for node in range(G.order())])\n", 888 | "Betas = np.linalg.solve(W, Omegas)\n" 889 | ] 890 | }, 891 | { 892 | "cell_type": "markdown", 893 | "metadata": { 894 | "deletable": true, 895 | "editable": true 896 | }, 897 | "source": [ 898 | "Use this information to calculate your expression in step viii of Part a, saving it in a vector named `prediction`." 899 | ] 900 | }, 901 | { 902 | "cell_type": "code", 903 | "execution_count": null, 904 | "metadata": { 905 | "collapsed": false, 906 | "deletable": true, 907 | "editable": true 908 | }, 909 | "outputs": [], 910 | "source": [ 911 | "\n" 912 | ] 913 | }, 914 | { 915 | "cell_type": "markdown", 916 | "metadata": { 917 | "deletable": true, 918 | "editable": true 919 | }, 920 | "source": [ 921 | "#### v)\n", 922 | "\n", 923 | "Now plot your phases (without displaying them) using `plot_phases`" 924 | ] 925 | }, 926 | { 927 | "cell_type": "code", 928 | "execution_count": null, 929 | "metadata": { 930 | "collapsed": true, 931 | "deletable": true, 932 | "editable": true 933 | }, 934 | "outputs": [], 935 | "source": [] 936 | }, 937 | { 938 | "cell_type": "markdown", 939 | "metadata": { 940 | "deletable": true, 941 | "editable": true 942 | }, 943 | "source": [ 944 | "and use" 945 | ] 946 | }, 947 | { 948 | "cell_type": "code", 949 | "execution_count": null, 950 | "metadata": { 951 | "collapsed": true, 952 | "deletable": true, 953 | "editable": true 954 | }, 955 | "outputs": [], 956 | "source": [ 957 | "plt.plot([40]*G.order(), prediction, '.')\n", 958 | "plt.show()" 959 | ] 960 | }, 961 | { 962 | "cell_type": "markdown", 963 | "metadata": { 964 | "deletable": true, 965 | "editable": true 966 | }, 967 | "source": [ 968 | "To plot your predictions as dots at time $40$.\n", 969 | "\n", 970 | "Are these a reasonable fit (perhaps shifted vertically a small amount)?" 971 | ] 972 | }, 973 | { 974 | "cell_type": "markdown", 975 | "metadata": { 976 | "deletable": true, 977 | "editable": true 978 | }, 979 | "source": [] 980 | }, 981 | { 982 | "cell_type": "markdown", 983 | "metadata": { 984 | "deletable": true, 985 | "editable": true 986 | }, 987 | "source": [ 988 | "In fact, our prediction doesn't just tell us what happens for large times. When we include the terms that decay as $t \\to \\infty$, we get a prediction about all time. I haven't included that in this problem simply because it requires a little more technical effort to plot, but if you're interested you can probably work out how to plot the full time predictions and compare them with the true solutions." 989 | ] 990 | } 991 | ], 992 | "metadata": { 993 | "kernelspec": { 994 | "display_name": "Python 3", 995 | "language": "python", 996 | "name": "python3" 997 | }, 998 | "language_info": { 999 | "codemirror_mode": { 1000 | "name": "ipython", 1001 | "version": 3 1002 | }, 1003 | "file_extension": ".py", 1004 | "mimetype": "text/x-python", 1005 | "name": "python", 1006 | "nbconvert_exporter": "python", 1007 | "pygments_lexer": "ipython3", 1008 | "version": "3.5.2" 1009 | } 1010 | }, 1011 | "nbformat": 4, 1012 | "nbformat_minor": 2 1013 | } 1014 | -------------------------------------------------------------------------------- /Assignments/Projects.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": { 6 | "deletable": true, 7 | "editable": true 8 | }, 9 | "source": [ 10 | "[changes since put online:\n", 11 | "- correct a bug in configuration model networks for project 1\n", 12 | "- corrected a typo in last bullet of project 2.\n", 13 | "- made clearer that writing code from scratch may be best option in project 2\n", 14 | "]\n", 15 | "\n", 16 | "# Projects:\n", 17 | "\n", 18 | "Please do one of the following 3 problems (note that Problem 1 gives the choice of two different scenarios. If you choose Problem 1, you do not need to do both)." 19 | ] 20 | }, 21 | { 22 | "cell_type": "markdown", 23 | "metadata": { 24 | "deletable": true, 25 | "editable": true 26 | }, 27 | "source": [ 28 | "## Problem 1 (Contact tracing with Asymptomatic Transmissions)\n", 29 | "\n", 30 | "Consider an infectious disease in which some individuals may transmit to their contacts even without showing symptoms. There are two scenarios we will consider that can cause this. You **have your choice of which scenario** to consider.\n", 31 | "\n", 32 | "\n", 33 | "- **scenario 1** After becoming infected, individuals have an incubation period (E) prior to becoming symptomatic (I). In that incubation period, they may be infectious. After becoming symptomatic, they remain infectious until they recover (R) or are identified (T). So without any intervention the transitions are S->E->I->R. Symptomatic (I) individuals enter the additional traced/identified \"T\" class either because of their symptoms, or because an infected neighbor was identified and they were then traced. The incubating individuals (E) can enter the traced/identified class (T) only by contact tracing from an identified neighbor.\n", 34 | "\n", 35 | "- **scenario 2** After becoming infected, some individuals have a completely asymptomatic infection, while others are symptomatic. Both may be infectious. The symptomatic individuals (I_s) behave like the 'I' individuals above, and the asymptomatic individuals (I_a) behave like the 'E' individuals above. The transitions here are S -> I_s -> R and S -> I_a -> R in absence of intervention. With interventions I_s nodes are identified because of symptoms or because of contact tracing. The I_a nodes are identified only through contact tracing.\n", 36 | "\n", 37 | "We would like to know how well contact tracing works in these populations. In both cases, individuals that have been identified are removed from the population (so they stop transmitting). For each identified node, there is a period over which its infected neighbors may be identified. During this period, the symptomatic and asymptomatic neighbors are found with some rate (per edge). \n", 38 | "\n", 39 | "You will need to simulate epidemics with these properties on various types of networks and write up a report to provide policy recommendations. The code below will do the simulations. This will not be as fast as some of the simulations we've used already, so don't be surprised if you need to use smaller networks.\n", 40 | "\n", 41 | "Please explore a range of networks, including Watts-Strogatz and Configuration Model networks. Also explore various parameters. Report on \n", 42 | "- the impact of tracing compared to just isolating symptomatic individuals \n", 43 | "- under which conditions it would be better to invest resources in more efficient tracing versus more efficient identification of symptomatic individuals. \n", 44 | "- What network structures are more or less amenable to these control measures\n", 45 | "- What assumptions are made that may limit the predictions you come up with.\n", 46 | "\n", 47 | "\n", 48 | " Note that we've discovered a bug if a node has an edge to itself, which can happen in Configuration Model networks. This can be corrected with the following command right after `G` is defined: `G.remove_edges_from(list(G.selfloop_edges()))` " 49 | ] 50 | }, 51 | { 52 | "cell_type": "code", 53 | "execution_count": 29, 54 | "metadata": { 55 | "collapsed": true, 56 | "deletable": true, 57 | "editable": true 58 | }, 59 | "outputs": [], 60 | "source": [ 61 | "import EoN\n", 62 | "import networkx as nx\n", 63 | "import random\n", 64 | "import matplotlib.pyplot as plt\n", 65 | "\n", 66 | "def SEIRT_with_contact_tracing(G, tau_E, tau_I, gamma_E, gamma_IT, gamma_IR, xi_T, zeta_T, rho):\n", 67 | " r'''\n", 68 | " Arguments:\n", 69 | " G - networkx graph\n", 70 | " tau_E - transmission rate of incubating/exposed individuals (E) to susceptible neighbors \n", 71 | " tau_I - transmission rate of symptomatic individuals (I) to susceptible neighbors\n", 72 | " gamma_E - rate that individuals go from E to I\n", 73 | " gamma_IT - rate that individuals in I become identified due to symptoms (they move into T)\n", 74 | " gamma_IR - rate that individuals in I recover \n", 75 | " xi_T - rate that an E or I neighbor of an identified individual with an identified neighbor is found due to contact tracing\n", 76 | " zeta_T rate at which the policy makers stop tracing contact of a given identified individual \n", 77 | " rho - initial proportion infected (they all start in E)\n", 78 | "\n", 79 | " \n", 80 | " returns numpy arrays:\n", 81 | " \n", 82 | " t, S, E, I, R, Te, Ti \n", 83 | " \n", 84 | " Here 'S' is the history of number susceptible, similarly for E, I, R. Then Te gives counts of how many were identified \n", 85 | " while in E and Ti gives counts of how many were identified while in I.\n", 86 | " \n", 87 | " The code is based on the simple contagion code in EoN.\n", 88 | " \n", 89 | " The full documentation is here: https://epidemicsonnetworks.readthedocs.io/en/latest/functions/EoN.Gillespie_simple_contagion.html\n", 90 | " '''\n", 91 | " \n", 92 | " #internally we have two traced classes: T1 and T2. In T1, their neighbors are being actively traced.\n", 93 | " #in T2, we have stopped tracing their partners. The transition is at rate zeta_T. These are further subdivided\n", 94 | " #based on what state the node was in when identified. This subdivision is just for book-keeping - it doesn't affect\n", 95 | " #the dynamics\n", 96 | " \n", 97 | " H = nx.DiGraph() #this graph captures all of the transitions that can happen without an edge.\n", 98 | " H.add_edge('E', 'I', rate = gamma_E)\n", 99 | " H.add_edge('I', 'T1i', rate = gamma_IT)\n", 100 | " H.add_edge('I', 'R', rate = gamma_IR)\n", 101 | " H.add_edge('T1e', 'T2e', rate = zeta_T)\n", 102 | " H.add_edge('T1i', 'T2i', rate = zeta_T)\n", 103 | "\n", 104 | " \n", 105 | " J = nx.DiGraph() #these are the transitions that happen because of an edge in the contact network.\n", 106 | " J.add_edge(('E', 'S'), ('E', 'E'), rate = tau_E) #an E individual with an S neighbor can make the neighbor E.\n", 107 | " J.add_edge(('I', 'S'), ('I', 'E'), rate = tau_I)\n", 108 | " J.add_edge(('T1e', 'E'), ('T1e', 'T1e'), rate = xi_T)\n", 109 | " J.add_edge(('T1e', 'I'), ('T1e', 'T1s'), rate = xi_T)\n", 110 | " J.add_edge(('T1i', 'E'), ('T1i', 'T1e'), rate = xi_T)\n", 111 | " J.add_edge(('T1i', 'I'), ('T1i', 'T1i'), rate = xi_T)\n", 112 | "\n", 113 | "\n", 114 | " return_statuses = ('S', 'E', 'I', 'R', 'T1e', 'T2e', 'T1i', 'T2i')\n", 115 | " \n", 116 | " IC = {node:'S' for node in G.nodes()} #cleaner to use a 'defaultdict', but sticking to this.\n", 117 | " for node in G.nodes():\n", 118 | " if random.random()" 151 | ] 152 | }, 153 | "metadata": { 154 | "needs_background": "light" 155 | }, 156 | "output_type": "display_data" 157 | } 158 | ], 159 | "source": [ 160 | "G = nx.erdos_renyi_graph(100, 0.2)\n", 161 | "#G = nx.newman_watts_strogatz_graph(100, 5, 0.2, seed=None) #k=degree of nodes\n", 162 | "\n", 163 | "G = nx.configuration_model(deg_dist) \n", 164 | "G.remove_edges_from(list(G.selfloop_edges()))\n", 165 | "tau_E = 0.01 # transmission rate of incubating/exposed individuals (E) to susceptible neighbors \n", 166 | "tau_I = 0.01 # transmission rate of symptomatic individuals (I) to susceptible neighbors\n", 167 | "gamma_E = 0.85 # rate that individuals go from E to I\n", 168 | "gamma_IT = 0.7 # rate that individuals in I become identified due to symptoms (they move into T)\n", 169 | "gamma_IR = 0.8 # rate that individuals in I recover \n", 170 | "xi_T = 0.3 # rate that an E or I neighbor of an identified individual with an identified neighbor is found due to contact tracing\n", 171 | "zeta_T = 0.6 #rate at which the policy makers stop tracing contact of a given identified individual \n", 172 | "rho = 0.1\n", 173 | "\n", 174 | "t, S, E, I, R, T1_e, T1_i = SEIRT_with_contact_tracing(G, tau_E, tau_I, gamma_E, gamma_IT, gamma_IR, xi_T, zeta_T, rho)\n", 175 | "\n", 176 | "plt.semilogy(t, S, label = 'Susceptible')\n", 177 | "plt.semilogy(t, E, label = 'Exposed')\n", 178 | "plt.semilogy(t, I, label = 'Infected')\n", 179 | "plt.semilogy(t, R, label = 'Recovered')\n", 180 | "plt.legend()\n", 181 | "\n", 182 | "print(I)\n", 183 | "print(E)" 184 | ] 185 | }, 186 | { 187 | "cell_type": "code", 188 | "execution_count": 2, 189 | "metadata": { 190 | "collapsed": true, 191 | "deletable": true, 192 | "editable": true 193 | }, 194 | "outputs": [], 195 | "source": [ 196 | "import EoN\n", 197 | "import networkx as nx\n", 198 | "import random\n", 199 | "import matplotlib.pyplot as plt\n", 200 | "\n", 201 | "def SEIRT_with_contact_tracing(G, tau_E, tau_I, gamma_E, gamma_IT, gamma_IR, xi_T, zeta_T, rho):\n", 202 | " r'''\n", 203 | " Arguments:\n", 204 | " G - networkx graph\n", 205 | " tau_E - transmission rate of incubating/exposed individuals (E) to susceptible neighbors \n", 206 | " tau_I - transmission rate of symptomatic individuals (I) to susceptible neighbors\n", 207 | " gamma_E - rate that individuals go from E to I\n", 208 | " gamma_IT - rate that individuals in I become identified due to symptoms (they move into T)\n", 209 | " gamma_IR - rate that individuals in I recover \n", 210 | " xi_T - rate that an E or I neighbor of an identified individual with an identified neighbor is found due to contact tracing\n", 211 | " zeta_T rate at which the policy makers stop tracing contact of a given identified individual \n", 212 | " rho - initial proportion infected (they all start in E)\n", 213 | "\n", 214 | " \n", 215 | " returns numpy arrays:\n", 216 | " \n", 217 | " t, S, E, I, R, Te, Ti \n", 218 | " \n", 219 | " Here 'S' is the history of number susceptible, similarly for E, I, R. Then Te gives counts of how many were identified \n", 220 | " while in E and Ti gives counts of how many were identified while in I.\n", 221 | " \n", 222 | " The code is based on the simple contagion code in EoN.\n", 223 | " \n", 224 | " The full documentation is here: https://epidemicsonnetworks.readthedocs.io/en/latest/functions/EoN.Gillespie_simple_contagion.html\n", 225 | " '''\n", 226 | " \n", 227 | " #internally we have two traced classes: T1 and T2. In T1, their neighbors are being actively traced.\n", 228 | " #in T2, we have stopped tracing their partners. The transition is at rate zeta_T. These are further subdivided\n", 229 | " #based on what state the node was in when identified. This subdivision is just for book-keeping - it doesn't affect\n", 230 | " #the dynamics\n", 231 | " \n", 232 | " H = nx.DiGraph() #this graph captures all of the transitions that can happen without an edge.\n", 233 | " H.add_edge('E', 'I', rate = gamma_E)\n", 234 | " H.add_edge('I', 'T1i', rate = gamma_IT)\n", 235 | " H.add_edge('I', 'R', rate = gamma_IR)\n", 236 | " H.add_edge('T1e', 'T2e', rate = zeta_T)\n", 237 | " H.add_edge('T1i', 'T2i', rate = zeta_T)\n", 238 | "\n", 239 | " \n", 240 | " J = nx.DiGraph() #these are the transitions that happen because of an edge in the contact network.\n", 241 | " J.add_edge(('E', 'S'), ('E', 'E'), rate = tau_E) #an E individual with an S neighbor can make the neighbor E.\n", 242 | " J.add_edge(('I', 'S'), ('I', 'E'), rate = tau_I)\n", 243 | " J.add_edge(('T1e', 'E'), ('T1e', 'T1e'), rate = xi_T)\n", 244 | " J.add_edge(('T1e', 'I'), ('T1e', 'T1s'), rate = xi_T)\n", 245 | " J.add_edge(('T1i', 'E'), ('T1i', 'T1e'), rate = xi_T)\n", 246 | " J.add_edge(('T1i', 'I'), ('T1i', 'T1i'), rate = xi_T)\n", 247 | "\n", 248 | "\n", 249 | " return_statuses = ('S', 'E', 'I', 'R', 'T1e', 'T2e', 'T1i', 'T2i')\n", 250 | " \n", 251 | " IC = {node:'S' for node in G.nodes()} #cleaner to use a 'defaultdict', but sticking to this.\n", 252 | " for node in G.nodes():\n", 253 | " if random.random()\n", 336 | "it may be easiest to do this from scratch rather than trying to adapt EoN). The code from the last assignment which dealt with introducing an intervention would be a good place to start.\n", 337 | "\n", 338 | "- Start with a small fraction $\\rho$ having each belief on the first issue.\n", 339 | "- Set some threshold $r$ such that once $r$ neighbors have one belief or the other the node adopts that belief at the next time step. If in a single time step, both beliefs cross the threshold, the node takes the most common belief among its neighbors, and if they are equal, it chooses one of them randomly.\n", 340 | "- Run this until no more transitions happen. There may be individuals who have no opinion at this point. Reduce $r$ by one and run the simulation further (from the final state). Keep going until $r=1$.\n", 341 | "- We will start from this system state and simulate multiple scenarios. Try to find a scenario where similar numbers hold each belief.\n", 342 | "- Now introduce the second issue randomly again. Set a threshold $r$. Denote the two beliefs 'a' and 'b'. A node will adopt 'a' (or 'b') if the number of those who agree with it on issue 1 who believe 'a' plus the number who disagree on issue ~~2~~ 1 who believe 'b' crosses $r$. As before, you'll need some form of tiebreaker.\n", 343 | "\n", 344 | "Do we see strong correlations at the end between the beliefs on issue 1 and issue 2? Try this with many network types (Configuration Model, Watts-Strogatz etc). What changes? What doesn't? What network types are easy/hard to get equal numbers holding the same beliefs on issue 1? Comment on what implications this might have for society." 345 | ] 346 | }, 347 | { 348 | "cell_type": "markdown", 349 | "metadata": { 350 | "collapsed": true, 351 | "deletable": true, 352 | "editable": true 353 | }, 354 | "source": [ 355 | "## Problem 3 (your suggestions)\n", 356 | "\n", 357 | "If you've got a problem that you would be interested in working on, I am open to suggestions. \n", 358 | "- You'll need to run it by me before working on it.\n", 359 | "- I reserve the right to modify the things you do.\n", 360 | "- I reserve the right to refuse if I feel it\n", 361 | " - is not challenging enough \n", 362 | " - has too high of a risk that something won't work\n", 363 | " - or that I'm simply not qualified to judge it." 364 | ] 365 | }, 366 | { 367 | "cell_type": "code", 368 | "execution_count": null, 369 | "metadata": { 370 | "collapsed": true, 371 | "deletable": true, 372 | "editable": true 373 | }, 374 | "outputs": [], 375 | "source": [] 376 | } 377 | ], 378 | "metadata": { 379 | "kernelspec": { 380 | "display_name": "Python 3", 381 | "language": "python", 382 | "name": "python3" 383 | }, 384 | "language_info": { 385 | "codemirror_mode": { 386 | "name": "ipython", 387 | "version": 3 388 | }, 389 | "file_extension": ".py", 390 | "mimetype": "text/x-python", 391 | "name": "python", 392 | "nbconvert_exporter": "python", 393 | "pygments_lexer": "ipython3", 394 | "version": "3.5.2" 395 | } 396 | }, 397 | "nbformat": 4, 398 | "nbformat_minor": 2 399 | } 400 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # DynamicProcessesOnNetworks 2 | 3 | These are the jupyter notebooks used for my AMSI summer school course on Dynamic Processes Spreading in Complex Networks. 4 | 5 | Most of these notes were written on the fly while I was lecturing 7 hours a week. So there are likely to be small issues either in presentation or in the description. But I think the code I wrote is in good shape. If you see any issues, please report them (see the issues link at the top of the github page). 6 | --------------------------------------------------------------------------------