To be able to edit code and run cells, you need to run the notebook yourself. Where would you like to run the notebook?

In the cloud (experimental)

Binder is a free, open source service that runs scientific notebooks in the cloud! It will take a while, usually 2-7 minutes to get a session.

On your computer

(Recommended if you want to store your changes.)

  1. Copy the notebook URL:
  2. Run Pluto

    (Also see: How to install Julia and Pluto)

  3. Paste URL in the Open box

Frontmatter

If you are publishing this notebook on the web, you can set the parameters below to provide HTML metadata. This is useful for search engines and social media.

Author 1

homework 5, version 0

👀 Reading hidden code
246 μs

Submission by: Jazzy Doe (jazz@mit.edu)

👀 Reading hidden code
34.8 ms

Oopsie! You need to update Pluto to the latest version

Close Pluto, go to the REPL, and type:

julia> import Pkg
julia> Pkg.update("Pluto")
👀 Reading hidden code
# WARNING FOR OLD PLUTO VERSIONS, DONT DELETE ME

html"""
<script>
const warning = html`
<h2 style="color: #800">Oopsie! You need to update Pluto to the latest version</h2>
<p>Close Pluto, go to the REPL, and type:
<pre><code>julia> import Pkg
julia> Pkg.update("Pluto")
</code></pre>
`

const super_old = window.version_info == null || window.version_info.pluto == null
if(super_old) {
return warning
}
const version_str = window.version_info.pluto.substring(1)
const numbers = version_str.split(".").map(Number)
console.log(numbers)

if(numbers[0] > 0 || numbers[1] > 12 || numbers[2] > 1) {
} else {
return warning
}

</script>
130 μs

Homework 5: Epidemic modeling II

18.S191, fall 2020

This notebook contains built-in, live answer checks! In some exercises you will see a coloured box, which runs a test case on your code, and provides feedback based on the result. Simply edit the code, run it, and the check runs again.

For MIT students: there will also be some additional (secret) test cases that will be run as part of the grading process, and we will look at your notebook and write comments.

Feel free to ask questions!

👀 Reading hidden code
572 μs
# edit the code below to set your name and kerberos ID (i.e. email without @mit.edu)

student = (name = "Jazzy Doe", kerberos_id = "jazz")

# you might need to wait until all other cells in this notebook have completed running.
# scroll around the page to see what's up
👀 Reading hidden code
20.0 μs

Let's create a package environment:

👀 Reading hidden code
268 μs
begin
using Pkg
Pkg.activate(mktempdir())
end
👀 Reading hidden code
❔
  Activating new project at `/tmp/jl_kES2x7`
121 ms
begin
Pkg.add(["PlutoUI", "Plots"])

using Plots
gr()
using PlutoUI
end
👀 Reading hidden code
❔
    Updating registry at `~/.julia/registries/General.toml`
   Resolving package versions...
    Updating `/tmp/jl_kES2x7/Project.toml`
  [91a5bcdd] + Plots v1.40.10
  [7f904dfe] + PlutoUI v0.7.61
    Updating `/tmp/jl_kES2x7/Manifest.toml`
  [6e696c72] + AbstractPlutoDingetjes v1.3.2
  [66dad0bd] + AliasTables v1.1.3
  [d1d4a3ce] + BitFlags v0.1.9
  [d360d2e6] + ChainRulesCore v1.25.1
  [9e997f8a] + ChangesOfVariables v0.1.9
  [944b1d66] + CodecZlib v0.7.8
  [35d6a980] + ColorSchemes v3.29.0
  [3da002f7] + ColorTypes v0.11.5
  [c3611d14] + ColorVectorSpace v0.10.0
  [5ae59095] + Colors v0.13.0
  [34da2185] + Compat v4.16.0
  [f0e56b4a] + ConcurrentUtilities v2.5.0
  [187b0558] + ConstructionBase v1.5.8
  [d38c429a] + Contour v0.6.3
  [9a962f9c] + DataAPI v1.16.0
  [864edb3b] + DataStructures v0.18.20
  [ffbed154] + DocStringExtensions v0.9.3
  [460bff9d] + ExceptionUnwrapping v0.1.11
  [c87230d0] + FFMPEG v0.4.2
  [53c48c17] + FixedPointNumbers v0.8.5
  [1fa38f19] + Format v1.3.7
  [28b8d3ca] + GR v0.73.13
  [42e2da0e] + Grisu v1.0.2
  [cd3eb016] + HTTP v1.10.15
  [47d2ed2b] + Hyperscript v0.0.5
  [ac1192a8] + HypertextLiteral v0.9.5
  [b5f81e59] + IOCapture v0.2.5
  [3587e190] + InverseFunctions v0.1.17
  [92d709cd] + IrrationalConstants v0.2.4
  [1019f520] + JLFzf v0.1.9
  [692b3bcd] + JLLWrappers v1.7.0
  [682c06a0] + JSON v0.21.4
  [b964fa9f] + LaTeXStrings v1.4.0
  [23fbe1c1] + Latexify v0.16.6
  [2ab3a3ac] + LogExpFunctions v0.3.28
  [e6f89c97] + LoggingExtras v1.1.0
  [6c6e2e6c] + MIMEs v1.0.0
  [1914dd2f] + MacroTools v0.5.15
  [739be429] + MbedTLS v1.1.9
  [442fdcdd] + Measures v0.3.2
  [e1d29d7a] + Missings v1.2.0
  [77ba4419] + NaNMath v1.0.3
  [4d8831e6] + OpenSSL v1.4.3
  [bac558e1] + OrderedCollections v1.8.0
  [69de0a69] + Parsers v2.8.1
  [b98c9c47] + Pipe v1.3.0
  [ccf2f8ad] + PlotThemes v3.3.0
  [995b91a9] + PlotUtils v1.4.3
  [91a5bcdd] + Plots v1.40.10
  [7f904dfe] + PlutoUI v0.7.61
  [aea7be01] + PrecompileTools v1.2.1
  [21216c6a] + Preferences v1.4.3
  [43287f4e] + PtrArrays v1.3.0
  [3cdcf5f2] + RecipesBase v1.3.4
  [01d81517] + RecipesPipeline v0.6.12
  [189a3867] + Reexport v1.2.2
  [05181044] + RelocatableFolders v1.0.1
  [ae029012] + Requires v1.3.1
  [6c6a2e73] + Scratch v1.2.1
  [992d4aef] + Showoff v1.0.3
  [777ac1f9] + SimpleBufferStream v1.2.0
  [a2af1166] + SortingAlgorithms v1.2.1
  [860ef19b] + StableRNGs v1.0.2
  [82ae8749] + StatsAPI v1.7.0
  [2913bbd2] + StatsBase v0.34.4
  [62fd8b95] + TensorCore v0.1.1
  [3bb67fe8] + TranscodingStreams v0.11.3
  [410a4b4d] + Tricks v0.1.10
  [5c2747f8] + URIs v1.5.1
  [1cfade01] + UnicodeFun v0.4.1
  [1986cc42] + Unitful v1.22.0
  [45397f5d] + UnitfulLatexify v1.6.4
  [41fe7b60] + Unzip v0.2.0
  [6e34b625] + Bzip2_jll v1.0.9+0
  [83423d85] + Cairo_jll v1.18.2+1
  [ee1fde0b] + Dbus_jll v1.14.10+0
  [2702e6a9] + EpollShim_jll v0.0.20230411+1
  [2e619515] + Expat_jll v2.6.5+0
  [b22a6f82] + FFMPEG_jll v4.4.4+1
  [a3f928ae] + Fontconfig_jll v2.15.0+0
  [d7e528f0] + FreeType2_jll v2.13.3+1
  [559328eb] + FriBidi_jll v1.0.16+0
  [0656b61e] + GLFW_jll v3.4.0+2
  [d2c73de3] + GR_jll v0.73.13+0
  [78b55507] + Gettext_jll v0.21.0+0
  [7746bdde] + Glib_jll v2.82.4+0
  [3b182d85] + Graphite2_jll v1.3.14+1
  [2e76f6c2] + HarfBuzz_jll v8.5.0+0
  [aacddb02] + JpegTurbo_jll v3.1.1+0
  [c1c5ebd0] + LAME_jll v3.100.2+0
  [88015f11] + LERC_jll v4.0.1+0
  [1d63c593] + LLVMOpenMP_jll v18.1.7+0
  [dd4b983a] + LZO_jll v2.10.3+0
  [e9f186c6] + Libffi_jll v3.2.2+2
  [d4300ac3] + Libgcrypt_jll v1.11.0+0
  [7e76a0d4] + Libglvnd_jll v1.7.0+0
  [7add5ba3] + Libgpg_error_jll v1.51.1+0
  [94ce4f54] + Libiconv_jll v1.18.0+0
  [4b2f31a3] + Libmount_jll v2.40.3+0
  [89763e89] + Libtiff_jll v4.7.1+0
  [38a345b3] + Libuuid_jll v2.40.3+0
  [e7412a2a] + Ogg_jll v1.3.5+1
  [458c3c95] + OpenSSL_jll v3.0.16+0
  [91d4177d] + Opus_jll v1.3.3+0
  [36c8627f] + Pango_jll v1.56.1+0
  [30392449] + Pixman_jll v0.43.4+0
  [c0090381] + Qt6Base_jll v6.7.1+1
  [629bc702] + Qt6Declarative_jll v6.7.1+2
  [ce943373] + Qt6ShaderTools_jll v6.7.1+1
  [e99dba38] + Qt6Wayland_jll v6.7.1+1
  [a44049a8] + Vulkan_Loader_jll v1.3.243+0
  [a2964d1f] + Wayland_jll v1.21.0+2
  [2381bf8a] + Wayland_protocols_jll v1.36.0+0
  [02c8fc9c] + XML2_jll v2.13.6+1
  [aed1982a] + XSLT_jll v1.1.42+0
  [ffd25f8a] + XZ_jll v5.6.4+1
  [f67eecfb] + Xorg_libICE_jll v1.1.1+0
  [c834827a] + Xorg_libSM_jll v1.2.4+0
  [4f6342f7] + Xorg_libX11_jll v1.8.6+3
  [0c0b7dd1] + Xorg_libXau_jll v1.0.12+0
  [935fb764] + Xorg_libXcursor_jll v1.2.3+0
  [a3789734] + Xorg_libXdmcp_jll v1.1.5+0
  [1082639a] + Xorg_libXext_jll v1.3.6+3
  [d091e8ba] + Xorg_libXfixes_jll v6.0.0+0
  [a51aa0fd] + Xorg_libXi_jll v1.8.2+0
  [d1454406] + Xorg_libXinerama_jll v1.1.5+0
  [ec84b674] + Xorg_libXrandr_jll v1.5.4+0
  [ea2f1a96] + Xorg_libXrender_jll v0.9.11+1
  [14d82f49] + Xorg_libpthread_stubs_jll v0.1.2+0
  [c7cfdc94] + Xorg_libxcb_jll v1.17.0+3
  [cc61e674] + Xorg_libxkbfile_jll v1.1.2+1
  [e920d4aa] + Xorg_xcb_util_cursor_jll v0.1.4+0
  [12413925] + Xorg_xcb_util_image_jll v0.4.0+1
  [2def613f] + Xorg_xcb_util_jll v0.4.0+1
  [975044d2] + Xorg_xcb_util_keysyms_jll v0.4.0+1
  [0d47668e] + Xorg_xcb_util_renderutil_jll v0.3.9+1
  [c22f9ab0] + Xorg_xcb_util_wm_jll v0.4.1+1
  [35661453] + Xorg_xkbcomp_jll v1.4.6+1
  [33bec58e] + Xorg_xkeyboard_config_jll v2.39.0+0
  [c5fb5394] + Xorg_xtrans_jll v1.5.1+0
  [3161d3a3] + Zstd_jll v1.5.7+1
  [35ca27e7] + eudev_jll v3.2.9+0
  [214eeab7] + fzf_jll v0.56.3+0
  [1a1c6b14] + gperf_jll v3.1.1+1
  [a4ae2306] + libaom_jll v3.11.0+0
  [0ac62f75] + libass_jll v0.15.2+0
  [1183f4f0] + libdecor_jll v0.2.2+0
  [2db6ffa8] + libevdev_jll v1.11.0+0
  [f638f0a6] + libfdk_aac_jll v2.0.3+0
  [36db933b] + libinput_jll v1.18.0+0
  [b53b4c65] + libpng_jll v1.6.47+0
  [f27f6e37] + libvorbis_jll v1.3.7+2
  [009596ad] + mtdev_jll v1.1.6+0
  [1270edf5] + x264_jll v2021.5.5+0
  [dfaa095f] + x265_jll v3.5.0+0
  [d8fb68d0] + xkbcommon_jll v1.4.1+2
  [0dad84c5] + ArgTools
  [56f22d72] + Artifacts
  [2a0f44e3] + Base64
  [ade2ca70] + Dates
  [8bb1440f] + DelimitedFiles
  [f43a241f] + Downloads
  [7b1f6079] + FileWatching
  [b77e0a4c] + InteractiveUtils
  [b27032c2] + LibCURL
  [76f85450] + LibGit2
  [8f399da3] + Libdl
  [37e2e46d] + LinearAlgebra
  [56ddb016] + Logging
  [d6f4376e] + Markdown
  [a63ad114] + Mmap
  [ca575930] + NetworkOptions
  [44cfe95a] + Pkg
  [de0858da] + Printf
  [3fa0cd96] + REPL
  [9a3f8284] + Random
  [ea8e919c] + SHA
  [9e88b42a] + Serialization
  [6462fe0b] + Sockets
  [2f01184e] + SparseArrays
  [10745b16] + Statistics
  [fa267f1f] + TOML
  [a4e569a6] + Tar
  [8dfed614] + Test
  [cf7118a7] + UUIDs
  [4ec0a83e] + Unicode
  [e66e0078] + CompilerSupportLibraries_jll
  [deac9b47] + LibCURL_jll
  [29816b5a] + LibSSH2_jll
  [c8ffd9c3] + MbedTLS_jll
  [14a3606d] + MozillaCACerts_jll
  [4536629a] + OpenBLAS_jll
  [05823500] + OpenLibm_jll
  [efcefdf7] + PCRE2_jll
  [83775a58] + Zlib_jll
  [8e850b90] + libblastrampoline_jll
  [8e850ede] + nghttp2_jll
  [3f19e933] + p7zip_jll
8.1 s

TODO

👀 Reading hidden code
1.7 ms

In this problem set, we will look at a simple spatial agent-based epidemic model: agents can interact only with other agents that are nearby. (In the previous homework any agent could interact with any other, which is not realistic.)

A simple approach is to use discrete space: each agent lives in one cell of a square grid. For simplicity we will allow no more than one agent in each cell, but this requires some care to design the rules of the model to respect this.

We will adapt some functionality from the previous homework.

TODO

You should copy and paste your code from that homework into this notebook.

md"""
In this problem set, we will look at a simple **spatial** agent-based epidemic model: agents can interact only with other agents that are *nearby*. (In the previous homework any agent could interact with any other, which is not realistic.)

A simple approach is to use **discrete space**: each agent lives
in one cell of a square grid. For simplicity we will allow no more than
one agent in each cell, but this requires some care to
design the rules of the model to respect this.

We will adapt some functionality from the previous homework. $TODO You should copy and paste your code from that homework into this notebook.
"""
👀 Reading hidden code
8.8 ms

Exercise 1: Wandering at random in 2D

In this exercise we will implement a random walk on a 2D lattice (grid). At each time step, a walker jumps to a neighbouring position at random (i.e. chosen with uniform probability from the available adjacent positions).

👉 Define an abstract type AbstractWalker.

md"""
## **Exercise 1:** _Wandering at random in 2D_

In this exercise we will implement a **random walk** on a 2D lattice (grid). At each time step, a walker jumps to a neighbouring position at random (i.e. chosen with uniform probability from the available adjacent positions).

👉 Define an abstract type `AbstractWalker`.
"""
👀 Reading hidden code
449 μs
abstract type AbstractWalker end
👀 Reading hidden code
343 μs

👉 Define an abstract type Abstract2DWalker that is a subtype of AbstractWalker (using <:).

👀 Reading hidden code
254 μs
abstract type Abstract2DWalker <: AbstractWalker end
👀 Reading hidden code
330 μs

👉 Define an struct type Location that contains integers x and y.

👀 Reading hidden code
218 μs
struct Location
x::Int
y::Int
end
👀 Reading hidden code
1.4 ms

👉 Define a struct type Wanderer that is a subtype of AbstractWalker2D. It contains a field called position that is a Location object.

👀 Reading hidden code
260 μs
Wanderer
begin
struct Wanderer <: Abstract2DWalker
position::Location
end
Wanderer(x,y) = Wanderer(Location(x,y))
end
👀 Reading hidden code
1.6 ms

👉 (i) Check that Julia automatically provides a constructor function Walker2D(position) that accepts an object of type Location.

(ii) Construct a Wanderer located at the origin.

👀 Reading hidden code
277 μs
Wanderer(Location(0,0))
👀 Reading hidden code
14.9 μs

👉 Write a new method Wanderer(x, y) that takes two integers, x and y and creates a Wanderer at the corresponding position.

👀 Reading hidden code
224 μs
accumulate (generic function with 2 methods)
accumulate
👀 Reading hidden code
11.4 μs

👉 Write a function make_tuple that takes an object of type Location and returns the corresponding tuple (x, y).

👀 Reading hidden code
223 μs
make_tuple (generic function with 1 method)
make_tuple(w::Wanderer) = w.location.x, w.location.y
👀 Reading hidden code
506 μs

In the following questions, the functions should take an object of type AbstractWalker2D (or you can just leave them untyped).

  1. Write a "getter" function position that returns the position as a Location object.

👀 Reading hidden code
359 μs
position (generic function with 1 method)
position(w::Wanderer) = w.position
👀 Reading hidden code
391 μs
  1. Write a "setter" function set_position that walker and a location l and creates a new Walker whose location is l

👀 Reading hidden code
283 μs
setposition (generic function with 1 method)
setposition(w::Wanderer, l::Location) = Wanderer(l)
👀 Reading hidden code
430 μs

(i) Write a function jump that returns a possible new position for a walker after a 2D jump as a Location object.

Jumps are equally likely in the directions right, up, left and down. Diagonal jumps are not allowed.

A nice way to implement this is to write a tuple moves of possible moves, and call rand on that tuple to get a random move. Then add the move to the current location.

👀 Reading hidden code
445 μs

👀 Reading hidden code
68.9 μs

(ii) Check that your jump function works and that the jumps are not diagonal.

👀 Reading hidden code
209 μs
Base.:+(a::Location, b::Location) = Location(a.x+b.x, a.y+b.y)
👀 Reading hidden code
579 μs
  1. Write a function jump that moves a walker to a new position (it should return a new Walker – the walker at the next time step). What arguments does the function need?

👀 Reading hidden code
306 μs
moves = [Location(1,0), Location(0,1), Location(-1,0), Location(0,-1)]
👀 Reading hidden code
21.0 μs
move_walker (generic function with 1 method)
move_walker(origin::Wanderer, move) = Wanderer(position(origin) + move)
👀 Reading hidden code
475 μs
  1. Write a function trajectory that calculates a trajectory of a 2D walker of length N.

Functional programming pro-tip: Rather than using a for loop to do this, use accumulate with move_walker and n random moves (created using rand(moves, n)). Pass init=Wanderer(0,0) to start accumulate from the origin.

👀 Reading hidden code
383 μs
trajectory (generic function with 1 method)
trajectory(w::Wanderer, n::Int) = accumulate(move_walker, rand(moves, n), init=w)
👀 Reading hidden code
579 μs
trajectory(Wanderer(Location(4,4)), 10)
👀 Reading hidden code
119 ms
  1. Plot 10 trajectories of length 10,000 on a single figure, all starting at the origin.

    Use the Plots.jl package. plot can accept a Vector of Tuples, i.e. (x,y) pairs, as the coordinates to plot. Use ratio=1 so that distances in the x and y directions are the same.

So for example, you can compose the plot like this:

let p = plot(ratio=1)                   # Create a new plot with aspect ratio 1:1
	plot!(p, [(0,0), (0,1), (1,1), (0,1)])      # plot one trajectory
	plot!(p, [(0,0), (0,-1), (-1,-1), (0,-1)])  # plot the second one
	p
end
👀 Reading hidden code
424 μs
# Edit this to insert your plots! Use a for loop to draw 10 trajectories.
let p = plot(ratio=1)
for _ in 1:10
plot!(p, tuple.(cumsum(randn(100)), cumsum(randn(100))))
end
p
end
👀 Reading hidden code
3.6 s
Location(-1,0)
👀 Reading hidden code
14.1 μs
dirs = (left=(-1,0), right=(1,0))
👀 Reading hidden code
18.1 μs

Thoughts fonsi:

We might want to define these types ourselves if the rest of the ntoebook depends on them.

We don't use any other subtypes of AbstractWanderer, so let's not use AbstractWanderer2D?

+ instead of jump?

we don't need all these types, maybe later? If we just use Location and Movement then the code is more charming. We can also use tuples instead of Location

Movement is also a x, y struct. +(::Location, ::Movement)::Location

rand(moves)

reduce(1:T, init=Location(0,0)) do prev_location, _
	prev_location + rand(moves)
end

and accumulate

md"# Thoughts fonsi:

We might want to define these types ourselves if the rest of the ntoebook depends on them.

We don't use any other subtypes of `AbstractWanderer`, so let's not use `AbstractWanderer2D`?

`+` instead of `jump`?

we don't need all these types, maybe later? If we just use `Location` and `Movement` then the code is more charming. We can also use tuples instead of Location

`Movement` is also a x, y struct. `+(::Location, ::Movement)::Location`

`rand(moves)`

```julia
reduce(1:T, init=Location(0,0)) do prev_location, _
prev_location + rand(moves)
end
```
and `accumulate`

"
👀 Reading hidden code
539 μs

Exercise 2: Wandering agent

In this exercise we will combine our Agent type from the previous homework with the 2D random walker that we just created, by adding a position to the Agent type.

👀 Reading hidden code
344 μs

👉 Define a type Agent that is a subtype of AbstractWalker2D from Exercise 1, since it will behave like a random walker and lives in 2D.

`Agent` should contain a `Location`, as well as a `state` of type `InfectionStatus` (as in Homework 4).)

[For simplicity we will not use a `num_infected` field, but feel free to do so!]
md"""
👉 Define a type `Agent` that is a subtype of `AbstractWalker2D` from Exercise 1, since it will behave like a random walker and lives in 2D.

`Agent` should contain a `Location`, as well as a `state` of type `InfectionStatus` (as in Homework 4).)

[For simplicity we will not use a `num_infected` field, but feel free to do so!]
"""
👀 Reading hidden code
240 μs

👀 Reading hidden code
77.4 μs
  1. Agents live in a box of side length 2L, centered at the origin. We need to decide (i.e. model) what happens when they reach the walls of the box (boundaries), in other words what kind of boundary conditions to use.

    One relatively simple boundary condition is a reflecting boundary:

    Each wall of the box is a reflective mirror, modelled using "bounce-back": if the walker tries to jump beyond the wall, it bounces back to the same position that it started from (i.e. the wall is "springy"). That is, it proposes to take a step, but is blocked in that direction, so instead it remains where it is during that step.

    Use the method of the jump function from above (that proposes a new position) to define a new method for the jump function, which also accepts a size S and implements reflecting boundary conditions. It returns a Location object representing the new position (inside the grid).

👀 Reading hidden code
675 μs
move_walker_bounded (generic function with 1 method)
function move_walker_bounded(boundary)
function (walker, move)
end
end
👀 Reading hidden code
731 μs

👀 Reading hidden code
86.3 μs
  1. Check that this is working by drawing a trajectory of an Agent inside a square box of side length 20,

using your function trajectory from Exercise 1.

You should draw the boundaries of the box and also a trajectory that is sufficiently long to see what happens at the boundary, but not so long that it fills up the box.

👀 Reading hidden code
397 μs
trajectory (generic function with 2 methods)
trajectory(w::Wanderer, n::Int, boundary) = accumulate(move_walker_bounded(boundary), rand(moves, n), init=w)
👀 Reading hidden code
618 μs

Exercise 3: Spatial epidemic model – Initialization and visualization

We now have all of the technology in place to simulate an agent-based model in space!

We will impose that at most one agent can be on a given site at all times, modelling the fact that two people cannot be in the same place as one other.

👉 Write a function initialize that takes parameters L and N, where 2L is the side length of the square box where the agents live and N is the number of agents.

It builds, one by one, a collection of agents, by proposing a position for each one and checking if that position is occupied. If the position is occupied, it should generate another one until it finds a free spot.

Create additional functions that you find useful so that each function is short and self-contained,.

The agents are all susceptible, except one, chosen at random, which is infectious.

`initialize` returns a `Vector` of `Agent`s.
  1. Run your initialization function for L=10 and N=20 and store the result in a variable agents.

  2. Write a function visualize that takes in a collection of agents as argument. It should plot a point for each agent at its location, coloured according to its status.

    You can use the keyword argument c=cs inside your call to the plotting function to set the colours of points to a vector of integers called cs. Don't forget to use ratio=1.

  3. Visualize the initial condition you created.

md"""
## **Exercise 3:** _Spatial epidemic model -- Initialization and visualization_

We now have all of the technology in place to simulate an agent-based model in space!

We will impose that at most one agent can be on a given site at all times, modelling the fact that two people cannot be in the same place as one other.

👉 Write a function `initialize` that takes parameters $L$ and $N$, where $2L$ is the side length of the square box where the agents live and $N$ is the number of agents.

It builds, one by one, a collection of agents, by proposing a position for each one and checking if that position is occupied. If the position is occupied, it should generate another one until it finds a free spot.

Create additional functions that you find useful so that each function is short and self-contained,.

The agents are all susceptible, except one, chosen at random, which is infectious.
`initialize` returns a `Vector` of `Agent`s.

2. Run your initialization function for $L=10$ and $N=20$ and store the result in a variable `agents`.

3. Write a function `visualize` that takes in a collection of agents as argument. It should plot a point for each agent at its location, coloured according to its status.

You can use the keyword argument `c=cs` inside your call to the plotting function to set the colours of points to a vector of integers called `cs`. Don't forget to use `ratio=1`.

4. Visualize the initial condition you created.
"""
👀 Reading hidden code
821 μs

Exercise 4: Spatial epidemic model – Dynamics

  1. Write a function step! that does one step of the dynamics:

    • Choose an agent at random, say i.

    • Propose a new neighbouring position for that agent, as above.

    • If that new position is unoccupied, the agent moves there.

    • If the new position is occupied, no motion occurs, but there is contact and the infection may be transmitted from agent i to the neighbour that it contacts, with the corresponding probability.

    • Agent i recovers with the corresponding probability.

  2. Write a function dynamics! that takes the same parameters as step!, together with a number of sweeps.

    Run the dynamics for the given number of sweeps. (Re-use your sweep! function from the previous homework.)

    Save the state of the whole system, together with the total numbers of S, I and R individuals, after each sweep, for later use.

    You may need the function deepcopy to copy the state of the whole system.

  3. Given one simulation run, write an interactive visualization that shows both the state at time n (using visualize) and the history of S, I and R from time 0 up to time n.

    [You can make two separate plot objects p1=plot(...) and p2=plot(...) or similar, and use plot(p1, p2) to display them together.]

  4. Using L=20 and N=100, experiment with the infection and recovery probabilities until you find an epidemic outbreak. (Take the recovery probability quite small.)

  5. For the values that you found in the previous part,

run 50 simulations. Plot S, I and R as a function of time for each of them (with transparency!).

  1. Plot their means with error bars. This should look qualitatively similar to what you saw in the previous homework.

👀 Reading hidden code
1.6 ms

Exercise 5: Effect of socialization

In this exercise we'll modify the simple mixing model. Instead of a constant mixing probability, i.e. a constant probability that any pair of people interact on a given day, we will have a variable probability associated with each agent, modelling the fact that some people are more or less social than others.

👉 Create a new agent type SocialAgent with fields infection_status, num_infected, and social_score. The attribute social_score represents an agent's probability of interacting with any other agent in the population.

👉 Create a population of 500 agents, with social_scores chosen from 10 equally-spaced between 0.1 and 0.5.

👉 Write a new function that can be used in our simulation code to model interactions between these agents. When two agents interact, their social scores are added together and the result is the probability that they interact. Only if they interact is the infection then transmitted with the usual probability.

👉 Plot the SIR curves of the resulting simulation.

👉 Make a scatter plot showing each agent's mixing rate on one axis, and the num_infected from the simulation in the other axis. How does the mean Run this simulation several times and comment on the results.

Run a simulation for 100 steps, and then apply a "lockdown" where every agent's social score gets multiplied by 0.25, and then run a second simulation which runs on that same population from there. What do you notice? How does changing this factor form 0.25 to other numbers affect things?

md"""
## **Exercise 5:** _Effect of socialization_

In this exercise we'll modify the simple mixing model. Instead of a constant mixing probability, i.e. a constant probability that any pair of people interact on a given day, we will have a variable probability associated with each agent, modelling the fact that some people are more or less social than others.

👉 Create a new agent type `SocialAgent` with fields `infection_status`, `num_infected`, and `social_score`. The attribute `social_score` represents an agent's probability of interacting with any other agent in the population.

👉 Create a population of 500 agents, with `social_score`s chosen from 10 equally-spaced between 0.1 and 0.5.

👉 Write a new function that can be used in our simulation code to model interactions between these agents. When two agents interact, their social scores are added together and the result is the probability that they interact. Only if they interact is the infection then transmitted with the usual probability.

👉 Plot the SIR curves of the resulting simulation.

👉 Make a scatter plot showing each agent's mixing rate on one axis, and the `num_infected` from the simulation in the other axis. How does the mean Run this simulation several times and comment on the results.



Run a simulation for 100 steps, and then apply a "lockdown" where every agent's social score gets multiplied by 0.25, and then run a second simulation which runs on that same population from there. What do you notice? How does changing this factor form 0.25 to other numbers affect things?
"""
👀 Reading hidden code
713 μs

Exercise 6 (Extra credit): Effect of distancing

We can use a variant of the above model to investigate the effect of the mis-named "social distancing" (we want people to be socially close, but physically distant).

In this variant, we separate out the two effects "infection" and "movement": an infected agent chooses a neighbouring site, and if it finds a susceptible there then it infects it with probability pI. For simplicity we can ignore recovery.

Separately, an agent chooses a neighbouring site to move to, and moves there with probability pM if the site is vacant. (Otherwise it stays where it is.)

When pM=0, the agents cannot move, and hence are completely quarantined in their original locations. 👉 How does the disease spread in this case?

👉 Run the dynamics repeatedly, and plot the sites which become infected.

👉 How does this change as you increase the density ρ=N/(L2) of agents? Start with a small density.

This is basically the site percolation model.

When we increase pM, we allow some local motion via random walks. 👉 Investigate how this leaky quarantine affects the infection dynamics with different densities.

md"""
### Exercise 6 (Extra credit): Effect of distancing

We can use a variant of the above model to investigate the effect of the
mis-named "social distancing"
(we want people to be *socially* close, but *physically* distant).

In this variant, we separate out the two effects "infection" and
"movement": an infected agent chooses a
neighbouring site, and if it finds a susceptible there then it infects it
with probability $p_I$. For simplicity we can ignore recovery.

Separately, an agent chooses a neighbouring site to move to,
and moves there with probability $p_M$ if the site is vacant. (Otherwise it
stays where it is.)

When $p_M = 0$, the agents cannot move, and hence are
completely quarantined in their original locations.
👉 How does the disease spread in this case?

👉 Run the dynamics repeatedly, and plot the sites which become infected.

👉 How does this change as you increase the *density*
$\rho = N / (L^2)$ of agents? Start with a small density.

This is basically the [**site percolation**](https://en.wikipedia.org/wiki/Percolation_theory) model.

When we increase $p_M$, we allow some local motion via random walks.
👉 Investigate how this leaky quarantine affects the infection dynamics with
different densities.

"""
👀 Reading hidden code
797 μs

Before you submit

Remember to fill in your name and Kerberos ID at the top of this notebook.

👀 Reading hidden code
409 μs

Function library

Just some helper functions used in the notebook.

👀 Reading hidden code
233 μs
hint (generic function with 1 method)
👀 Reading hidden code
474 μs
almost (generic function with 1 method)
👀 Reading hidden code
469 μs
still_missing (generic function with 2 methods)
👀 Reading hidden code
906 μs
keep_working (generic function with 2 methods)
👀 Reading hidden code
880 μs
👀 Reading hidden code
39.8 ms
correct (generic function with 2 methods)
👀 Reading hidden code
793 μs
not_defined (generic function with 1 method)
👀 Reading hidden code
865 μs

Multiplayer

md"# Multiplayer"
👀 Reading hidden code
181 μs
👀 Reading hidden code
132 μs
You have to reload this cell
👀 Reading hidden code
125 μs
You need to reload this cell
👀 Reading hidden code
126 μs