R's weirdnesses are fun & useful richfitz Rich FitzJohn R is - - PowerPoint PPT Presentation

r s weirdnesses are fun useful
SMART_READER_LITE
LIVE PREVIEW

R's weirdnesses are fun & useful richfitz Rich FitzJohn R is - - PowerPoint PPT Presentation

R's weirdnesses are fun & useful richfitz Rich FitzJohn R is a really weird language There are people who think of it as a statistical package - a free version of stata perhaps. Like stata, R includes lots of useful things Statistics


slide-1
SLIDE 1

R's weirdnesses are fun & useful

Rich FitzJohn richfitz

  • R is a really weird language

There are people who think of it as a statistical package - a free version of stata perhaps. Like stata, R includes lots of useful things

slide-2
SLIDE 2

Statistics programs generally include distributions

R includes...

slide-3
SLIDE 3

Statistics programs generally include statistical tests

slide-4
SLIDE 4

Statistics programs generally include plotting

slide-5
SLIDE 5

Statistics programs don't often include blog generators

cran.r-project.org/package=blogdown

R also has some weird things available in packages

slide-6
SLIDE 6

Statistics programs don't often include webservers

cran.r-project.org/package=httpuv
slide-7
SLIDE 7

Statistics programs don't often include minecraft clients

github.com/ropenscilabs/miner
slide-8
SLIDE 8

Statistics programs don't often include metaprogramming

Metaprogramming is where a program reads, generates, analyses or transforms a program Unlike the other, newer, weirdnesses this one has been here from the beginning

slide-9
SLIDE 9

THEY DIDN’T STOP TO THINK IF THEY SHOULD YOUR SCIENTISTS WERE SO PREOCCUPIED WITH WHETHER OR NOT THEY COULD D A T A

At first metaprogramming seems like a really bizarre thing to do in any language And it's very unexpected in a statistical package metaprogramming makes much more sense when you know R's history

slide-10
SLIDE 10

Algol

1956

Fortran

1957

C

1971

S

1976 R has a strange history. It turns up as derivative of S - and S is ancient, coming out of Bell Labs in 1976.

slide-11
SLIDE 11

Algol

1956

Fortran

1957

C

1971

S

1976

Python

1991

C++

1985

Ruby

1995

Julia

2012 This is older than C++, Python, Ruby and much older than Julia

slide-12
SLIDE 12

Algol

1956

Fortran

1957

Scheme

1970

C

1971

S

1976

R

1993 R was developed as a new implementation of S in 1993 by Ross Ihaka and Robert Gentleman. They were heavily influenced by Scheme - a language popular in computing science for decades, and which has lots of interesting ideas despite being very small. The one that really turns up is that data and code are the same sort of thing (homiconicity) Generally R looks a lot like C or Fortran (procedural, do this, then that) but sometimes the weird scheme bits shine through

slide-13
SLIDE 13

R's weirdnesses are fun & useful

Rich FitzJohn richfitz

  • Today I want to talk about how metaprogramming is fun and useful

Using R since 1999, second language (after Python) but my workhorse I no longer do any data analysis I build infrastructure and this talk discusses some of it

slide-14
SLIDE 14

For the last 2.5 years I have worked as a research software engineer in the Department of Infectious Disease Epidemiology at Imperial College London Epidemiological modelling has a long history, but now we use lots of R!

slide-15
SLIDE 15

Encryption Docker Differential equations

Objectives for this talk

  • 1. R has some strange features that make it surprisingly powerful. These should be used with care
  • 2. Three packages that do interesting things
  • 3. Three fields that you may not have encountered with R

Don't try to learn everything - It's going to be very light touch and not very deep If one section seems uninteresting to you, just wait 10 minutes and the next one will be totally different Take home one new package, idea, or way of thinking about R

slide-16
SLIDE 16

Encryption

Why encrypt things from R?

slide-17
SLIDE 17

write.csv(mydata, "secret.csv")

Encrypt and save csv

We want to encrypt a csv file. But the encryption tools won't work with this function.

slide-18
SLIDE 18

tmp <- tempfile() write.csv(mydata, tmp)

Encrypt and save csv

So we first must write it out in plain text

slide-19
SLIDE 19

tmp <- tempfile() write.csv(mydata, tmp) bytes <- readBin(tmp, ...) enc <- sodium::data_encrypt(bytes, key)

Encrypt and save csv

Then read it back up and encrypt that data

slide-20
SLIDE 20

tmp <- tempfile() write.csv(mydata, tmp) bytes <- readBin(tmp, ...) enc <- sodium::data_encrypt(bytes, key) enc [1] a7 8e 31 99 3b 7b ac 58 4e 35 37 79 [13] 53 10 4c fe 5e 78 de 4e 4d 25 77 26

Encrypt and save csv

This involves working with raw vectors which you don't generally see unless you go out of your way

slide-21
SLIDE 21

tmp <- tempfile() write.csv(mydata, tmp) bytes <- readBin(tmp, ...) enc <- sodium::data_encrypt(bytes, key) writeBin(enc, "secret.csv") file.remove(tmp)

Encrypt and save csv

slide-22
SLIDE 22

enc <- readBin("secret.csv", ...) bytes <- sodium::data_decrypt(enc, key) tmp <- tempfile() writeBin(bytes, tmp) mydata <- read.csv(tmp) file.remove(tmp)

Decrypt and read csv

slide-23
SLIDE 23

A simpler interface

cyphr::encrypt(write.csv(mydata, "secret.csv"), key) mydata <- cyphr::decrypt(read.csv("secret.csv"), key)

slide-24
SLIDE 24

A simpler interface

cyphr::encrypt(write.csv(mydata, "secret.csv"), key) # Write mydata to temp file using write.csv
 # Encrypt temp file contents to "secret.csv" using key
 # Delete temp file

slide-25
SLIDE 25

A simpler interface

cyphr::encrypt(write.csv(mydata, "secret.csv"), key) # Decide on a temporary file tmp # Detect filename is second argument "secret.csv" # Rewrite expression as write.csv(mydata, tmp) # Evaluate new expression (in same environment as old) # Read in tmp as bytes # Encrypt the contents with cyphr::encrypt(bytes, key) # Save encrypted data as secret.csv # Delete the temporary file tmp

slide-26
SLIDE 26

Expressions are data

as.list(quote(saveRDS(mydata, "secret.rds"))) [[1]] saveRDS [[2]] mydata [[3]] [1] "secret.rds"

This works because in R, expressions are simply data! You can walk through the tree and work with parts of the expression at will This sort of processing is used in all sorts of places:

  • automatic plot axes
  • library
  • data.frames that build out of the names
slide-27
SLIDE 27

A simpler interface

cyphr::encrypt(write.csv(mydata, "secret.csv"), key) # Write mydata to temp file using write.csv
 # Encrypt temp file to "secret.csv" using key
 # Delete temp file mydata <- cyphr::decrypt(read.csv("secret.csv"), key) # Decrypt "secret.csv" into temp file using key # Read mydata from temp file using read.csv
 # Delete temp file

slide-28
SLIDE 28

A simpler interface

cyphr::encrypt(saveRDS(mydata, "secret.rds"), key) # Write mydata to temp file using saveRDS
 # Encrypt temp file to "secret.rds" using key
 # Delete temp file mydata <- cyphr::decrypt(readRDS("secret.rds"), key) # Decrypt "secret.rds" into temp file using key # Read mydata from temp file using readRDS
 # Delete temp file

We can change the target function to read and write different types of files and everything just works

slide-29
SLIDE 29

Encrypting an analysis

mydata <- read.csv("secret.csv") newdata <- my_analysis_function(mydata) saveRDS(newdata, "export.rds")

The idea is that it can then just be taken to an existing analysis and wrapped around the code that already exists Rather than having to replace every input/output line with 5 lines of repetitive and error-prone code, or using special encryption/decryption functions we can change an analysis very simply

slide-30
SLIDE 30

Encrypting an analysis

mydata <- cyphr::decrypt(read.csv("secret.csv"), key) newdata <- my_analysis_function(mydata) cyphr::encrypt(saveRDS(newdata, "export.rds"), key)

This does not work with plotting (yet) Alternative approaches would be to use encrypted volumes but these are less portable and awkward to share

slide-31
SLIDE 31

A little goes a long way - talk about how this breaks referential transparency and so needs to be used with care Talk about where this is used elsewhere in the R ecosystem - library, dplyr, subset, etc Talk about how programming with these functions can be hard and how a whole new package (rlang) exists to try and simplify programming with NSE. Not best used everywhere, but when used lightly can be very expressive

slide-32
SLIDE 32

D i f f e r e n t i a l e q u a t i

  • n

s

Something completely different!

slide-33
SLIDE 33

S I R

dI dt

<latexit sha1_base64="1mqyaLH0HvCuY+5X9BJn6PiBZ1E=">ACiXicdVFdaxNBFJ2sH62x2g8fRkMQoUSdtOmTXwqRFDBhyrGFpKlzM7eTYfMzmxn7krDkt/R1/pP/Bv+G+8mLZhSLwczrlzP85NCq08huGfRvDo8ZOna+vPms83Xrzc3Nre+eFt6SQMpdXWnSXCg1YGhqhQw1nhQOSJhtNkOqj105/gvLmO84KiHMxMSpTUiBR8ThzQlbp53mV4vx8qxW2o6jb6fY4gf3+wX6XQCeMDo/6PGqHi2ix2zg5325MxqmVZQ4GpRbej6KwLgSDpXUMG+OSw+FkFMxgRFBI3LwcbWYes7fEpPyzDp6BvmC/fdHJXLvZ3lCmbnAC39fq8mHtFGJWS+ulClKBCOXjbJSc7S8toCnyoFEPSMgpFM0K5cXgoxAMq50mZRvAC5skp1VRolbQr3WI1X6ASRHjAXytRrVd9sYqnxwJoUDC18J1PdWt/9oCYK/d4XuofZ+gApu8e+EOnufOf/x8MO+1+O/x60DpOfi9vtM5eszdsl0XsiB2zT+yEDZlkl+ya3bBfwUbQCXrB+2Vq0Li96yu2EsHgL2Cpyu8=</latexit><latexit sha1_base64="1mqyaLH0HvCuY+5X9BJn6PiBZ1E=">ACiXicdVFdaxNBFJ2sH62x2g8fRkMQoUSdtOmTXwqRFDBhyrGFpKlzM7eTYfMzmxn7krDkt/R1/pP/Bv+G+8mLZhSLwczrlzP85NCq08huGfRvDo8ZOna+vPms83Xrzc3Nre+eFt6SQMpdXWnSXCg1YGhqhQw1nhQOSJhtNkOqj105/gvLmO84KiHMxMSpTUiBR8ThzQlbp53mV4vx8qxW2o6jb6fY4gf3+wX6XQCeMDo/6PGqHi2ix2zg5325MxqmVZQ4GpRbej6KwLgSDpXUMG+OSw+FkFMxgRFBI3LwcbWYes7fEpPyzDp6BvmC/fdHJXLvZ3lCmbnAC39fq8mHtFGJWS+ulClKBCOXjbJSc7S8toCnyoFEPSMgpFM0K5cXgoxAMq50mZRvAC5skp1VRolbQr3WI1X6ASRHjAXytRrVd9sYqnxwJoUDC18J1PdWt/9oCYK/d4XuofZ+gApu8e+EOnufOf/x8MO+1+O/x60DpOfi9vtM5eszdsl0XsiB2zT+yEDZlkl+ya3bBfwUbQCXrB+2Vq0Li96yu2EsHgL2Cpyu8=</latexit><latexit sha1_base64="1mqyaLH0HvCuY+5X9BJn6PiBZ1E=">ACiXicdVFdaxNBFJ2sH62x2g8fRkMQoUSdtOmTXwqRFDBhyrGFpKlzM7eTYfMzmxn7krDkt/R1/pP/Bv+G+8mLZhSLwczrlzP85NCq08huGfRvDo8ZOna+vPms83Xrzc3Nre+eFt6SQMpdXWnSXCg1YGhqhQw1nhQOSJhtNkOqj105/gvLmO84KiHMxMSpTUiBR8ThzQlbp53mV4vx8qxW2o6jb6fY4gf3+wX6XQCeMDo/6PGqHi2ix2zg5325MxqmVZQ4GpRbej6KwLgSDpXUMG+OSw+FkFMxgRFBI3LwcbWYes7fEpPyzDp6BvmC/fdHJXLvZ3lCmbnAC39fq8mHtFGJWS+ulClKBCOXjbJSc7S8toCnyoFEPSMgpFM0K5cXgoxAMq50mZRvAC5skp1VRolbQr3WI1X6ASRHjAXytRrVd9sYqnxwJoUDC18J1PdWt/9oCYK/d4XuofZ+gApu8e+EOnufOf/x8MO+1+O/x60DpOfi9vtM5eszdsl0XsiB2zT+yEDZlkl+ya3bBfwUbQCXrB+2Vq0Li96yu2EsHgL2Cpyu8=</latexit>

dS dt

<latexit sha1_base64="Se031vE/7LFUGq2Wld4y9AVu1A8=">ACiXicdVHbatAEF2rt9RNm0sf+7LUFIRnLixu5TwIX2oQ/pxU3AFmG1GjmLV7vK7qjECH9HXtM/yW/kbzqyE6hDOrBwOGd2LmeSQiuPYXjTCB49fvL02drz5ov1l682Nre2f3lbOglDabV1J4nwoJWBISrUcFI4EHmi4TiZDmr9+Dc4r6z5ibMC4lxMjMqUFEhUPM6ckFX6Y16lOD/dbIXtKOp2uj1OYK+/v9cl0AmjDwd9HrXDRbTYbRydbjUm49TKMgeDUgvR1FYFwJh0pqmDfHpYdCyKmYwIigETn4uFpMPefviEl5Zh09g3zB/vujErn3szyhzFzgmb+v1eRD2qjErBdXyhQlgpHLRlmpOVpeW8BT5UCinhEQ0imalcszQUYgGdVcabMoXoBcWaW6KI2SNoV7rMYLdIJID5gLZeq1qu82sdR4YE0Kha+k6lure98UhOFfvcr3cPsfnYA0/cP/KHT3PnP/w+GnXa/HX7bx0m18sbrbE37C3bYRE7YIfsCztiQybZObtkV+xPsB50gl7wcZkaNG7v+pqtRD4C3XVyvk=</latexit><latexit sha1_base64="Se031vE/7LFUGq2Wld4y9AVu1A8=">ACiXicdVHbatAEF2rt9RNm0sf+7LUFIRnLixu5TwIX2oQ/pxU3AFmG1GjmLV7vK7qjECH9HXtM/yW/kbzqyE6hDOrBwOGd2LmeSQiuPYXjTCB49fvL02drz5ov1l682Nre2f3lbOglDabV1J4nwoJWBISrUcFI4EHmi4TiZDmr9+Dc4r6z5ibMC4lxMjMqUFEhUPM6ckFX6Y16lOD/dbIXtKOp2uj1OYK+/v9cl0AmjDwd9HrXDRbTYbRydbjUm49TKMgeDUgvR1FYFwJh0pqmDfHpYdCyKmYwIigETn4uFpMPefviEl5Zh09g3zB/vujErn3szyhzFzgmb+v1eRD2qjErBdXyhQlgpHLRlmpOVpeW8BT5UCinhEQ0imalcszQUYgGdVcabMoXoBcWaW6KI2SNoV7rMYLdIJID5gLZeq1qu82sdR4YE0Kha+k6lure98UhOFfvcr3cPsfnYA0/cP/KHT3PnP/w+GnXa/HX7bx0m18sbrbE37C3bYRE7YIfsCztiQybZObtkV+xPsB50gl7wcZkaNG7v+pqtRD4C3XVyvk=</latexit><latexit sha1_base64="Se031vE/7LFUGq2Wld4y9AVu1A8=">ACiXicdVHbatAEF2rt9RNm0sf+7LUFIRnLixu5TwIX2oQ/pxU3AFmG1GjmLV7vK7qjECH9HXtM/yW/kbzqyE6hDOrBwOGd2LmeSQiuPYXjTCB49fvL02drz5ov1l682Nre2f3lbOglDabV1J4nwoJWBISrUcFI4EHmi4TiZDmr9+Dc4r6z5ibMC4lxMjMqUFEhUPM6ckFX6Y16lOD/dbIXtKOp2uj1OYK+/v9cl0AmjDwd9HrXDRbTYbRydbjUm49TKMgeDUgvR1FYFwJh0pqmDfHpYdCyKmYwIigETn4uFpMPefviEl5Zh09g3zB/vujErn3szyhzFzgmb+v1eRD2qjErBdXyhQlgpHLRlmpOVpeW8BT5UCinhEQ0imalcszQUYgGdVcabMoXoBcWaW6KI2SNoV7rMYLdIJID5gLZeq1qu82sdR4YE0Kha+k6lure98UhOFfvcr3cPsfnYA0/cP/KHT3PnP/w+GnXa/HX7bx0m18sbrbE37C3bYRE7YIfsCztiQybZObtkV+xPsB50gl7wcZkaNG7v+pqtRD4C3XVyvk=</latexit>

dR dt

<latexit sha1_base64="TVQ3MVcKCYwdAJyR45Z7vcI6s=">ACiXicdVFdSxtBFJ1sbWtTW7V97MtgKFiQsBtNTfokpNA+9MFKU4VkdnZu3HI7Mw6c1cMS35HX+s/8W/03/RuotCIvTBwOfO/Tg3KbTyGIZ/GsGTtafPnq+/aL7cePV6c2v7zU9vSydhK27iwRHrQyMESFGs4KByJPNJwm0Gtn16B8qaHzgrIM7FxKhMSYFExePMCVmlJ/Mqxfn5VitsR1G30+1xAv9g/0ugU4YfTzs86gdLqLF7uL4fLsxGadWljkYlFp4P4rCAuNKOFRSw7w5Lj0UQk7FBEYEjcjBx9Vi6jl/T0zKM+voGeQL9t8flci9n+UJZeYCL/xDrSYf0YlZr24UqYoEYxcNspKzdHy2gKeKgcS9YyAkE7RrFxeCDICyajmSptF8QLkyirVdWmUtCk8YDVeoxNEesBcKFOvVZ3YxFLjgTUpGFr4Xqa6tb7WU0U+r1vdA+z98UBTD8odOc+8/z8Ydtr9dvj9oHWU3C5vtM7esR2yJ2yI7YV3bMhkyS/aL/WY3wUbQCXrBp2Vq0Li761u2EsHgL3O3yvg=</latexit><latexit sha1_base64="TVQ3MVcKCYwdAJyR45Z7vcI6s=">ACiXicdVFdSxtBFJ1sbWtTW7V97MtgKFiQsBtNTfokpNA+9MFKU4VkdnZu3HI7Mw6c1cMS35HX+s/8W/03/RuotCIvTBwOfO/Tg3KbTyGIZ/GsGTtafPnq+/aL7cePV6c2v7zU9vSydhK27iwRHrQyMESFGs4KByJPNJwm0Gtn16B8qaHzgrIM7FxKhMSYFExePMCVmlJ/Mqxfn5VitsR1G30+1xAv9g/0ugU4YfTzs86gdLqLF7uL4fLsxGadWljkYlFp4P4rCAuNKOFRSw7w5Lj0UQk7FBEYEjcjBx9Vi6jl/T0zKM+voGeQL9t8flci9n+UJZeYCL/xDrSYf0YlZr24UqYoEYxcNspKzdHy2gKeKgcS9YyAkE7RrFxeCDICyajmSptF8QLkyirVdWmUtCk8YDVeoxNEesBcKFOvVZ3YxFLjgTUpGFr4Xqa6tb7WU0U+r1vdA+z98UBTD8odOc+8/z8Ydtr9dvj9oHWU3C5vtM7esR2yJ2yI7YV3bMhkyS/aL/WY3wUbQCXrBp2Vq0Li761u2EsHgL3O3yvg=</latexit><latexit sha1_base64="TVQ3MVcKCYwdAJyR45Z7vcI6s=">ACiXicdVFdSxtBFJ1sbWtTW7V97MtgKFiQsBtNTfokpNA+9MFKU4VkdnZu3HI7Mw6c1cMS35HX+s/8W/03/RuotCIvTBwOfO/Tg3KbTyGIZ/GsGTtafPnq+/aL7cePV6c2v7zU9vSydhK27iwRHrQyMESFGs4KByJPNJwm0Gtn16B8qaHzgrIM7FxKhMSYFExePMCVmlJ/Mqxfn5VitsR1G30+1xAv9g/0ugU4YfTzs86gdLqLF7uL4fLsxGadWljkYlFp4P4rCAuNKOFRSw7w5Lj0UQk7FBEYEjcjBx9Vi6jl/T0zKM+voGeQL9t8flci9n+UJZeYCL/xDrSYf0YlZr24UqYoEYxcNspKzdHy2gKeKgcS9YyAkE7RrFxeCDICyajmSptF8QLkyirVdWmUtCk8YDVeoxNEesBcKFOvVZ3YxFLjgTUpGFr4Xqa6tb7WU0U+r1vdA+z98UBTD8odOc+8/z8Ydtr9dvj9oHWU3C5vtM7esR2yJ2yI7YV3bMhkyS/aL/WY3wUbQCXrBp2Vq0Li761u2EsHgL3O3yvg=</latexit>

Susceptible, infected, resistant Described in terms of rates of change of the variables with respect to time Common type of modelling, and usually intractable analytically

slide-34
SLIDE 34

Time Variable

But suppose we did know the position of the variable at some point in time

slide-35
SLIDE 35

Time Variable

And we can compute its slope with respect to time

slide-36
SLIDE 36

Time Variable

We can extrapolate down and correct as we go and work out the rest of the curve

slide-37
SLIDE 37

Time Variable

Repeating over and over again

slide-38
SLIDE 38

easy fast

  • r

In R there are generally two choices for doing differential equation modelling - easy (expressive) but slow or fast (but harder to write and maintain)

slide-39
SLIDE 39 lorenz <- function(t, y, parms) { sigma <- parms[1] R <- parms[2] b <- parms[3] y1 <- y[1] y2 <- y[2] y3 <- y[3] list(c(sigma * (y2 - y1), R * y1 - y2 - y1 * y3,
  • b * y3 + y1 * y2))
}

easy

In the easy form you just write the rhs as an R function - you can take time and whatever parameters you want, the current state of the variables and do anything you want. You can use any R function no matter how weird All you need to do is return the derivatives with respect to time in the same order as the variables

slide-40
SLIDE 40 lorenz <- function(t, y, parms) { sigma <- parms[1] R <- parms[2] b <- parms[3] y1 <- y[1] y2 <- y[2] y3 <- y[3] list(c(sigma * (y2 - y1), R * y1 - y2 - y1 * y3,
  • b * y3 + y1 * y2))
}

easy

deSolve::ode(t, y, lorenz)

Then just pass this in to deSolve where there are a lot of great solvers to use

slide-41
SLIDE 41 void initmod(void (* odeparms)(int *, double *)) { int N = 3;
  • deparms(&N, parms);
} void lorenz(int *n, double *t, double *y, double *dydt, double *yout, int *ip) { double sigma = parms[0]; double R = parms[1]; double b = parms[2]; double y1 = y[0]; double y2 = y[1]; double y3 = y[2]; dydt[0] = sigma * (y2 - y1); dydt[1] = R * y1 - y2 - y1 * y3; dydt[2] = -b * y3 + y1 * y2; }

fast

  • The fast version is a bit more work
  • Rather than write in R we write in C
  • We can't use names anywhere and need to remember where everything is in our vector
  • Uses C's semantics of not returning a vector but writing in place
slide-42
SLIDE 42 void initmod(void (* odeparms)(int *, double *)) { int N = 3;
  • deparms(&N, parms);
} void lorenz(int *n, double *t, double *y, double *dydt, double *yout, int *ip) { double sigma = parms[0]; double R = parms[1]; double b = parms[2]; double y1 = y[0]; double y2 = y[1]; double y3 = y[2]; dydt[0] = sigma * (y2 - y1); dydt[1] = R * y1 - y2 - y1 * y3; dydt[2] = -b * y3 + y1 * y2; }

fast

deSolve::ode(t, y, "lorenz", initfunc = "initmod", dllname = "lorenz")
  • We need to compile this, then load it into R
  • Once in R we can run it basically as before
slide-43
SLIDE 43 lorenz <- function(t, y, parms) { sigma <- parms[1] R <- parms[2] b <- parms[3] y1 <- y[1] y2 <- y[2] y3 <- y[3] list(c(sigma * (y2 - y1), R * y1 - y2 - y1 * y3,
  • b * y3 + y1 * y2))
} void initmod(void (* odeparms)(int *, double *)) { int N = 3;
  • deparms(&N, parms);
} void lorenz(int *n, double *t, double *y, double *dydt, double *yout, int *ip) { double sigma = parms[0]; double R = parms[1]; double b = parms[2]; double y1 = y[0]; double y2 = y[1]; double y3 = y[2]; dydt[0] = sigma * (y2 - y1); dydt[1] = R * y1 - y2 - y1 * y3; dydt[2] = -b * y3 + y1 * y2; }

These approaches really aren't that different

slide-44
SLIDE 44 void initmod(void (* odeparms)(int *, double *)) { int N = 3;
  • deparms(&N, parms);
} void lorenz(int *n, double *t, double *y, double *dydt, double *yout, int *ip) { double sigma = parms[0]; double R = parms[1]; double b = parms[2]; double y1 = y[0]; double y2 = y[1]; double y3 = y[2]; dydt[0] = sigma * (y2 - y1); dydt[1] = R * y1 - y2 - y1 * y3; dydt[2] = -b * y3 + y1 * y2; } lorenz <- function(t, y, parms) { sigma <- parms[1] R <- parms[2] b <- parms[3] y1 <- y[1] y2 <- y[2] y3 <- y[3] list(c(sigma * (y2 - y1), R * y1 - y2 - y1 * y3,
  • b * y3 + y1 * y2))
}

Unpack our parameters

slide-45
SLIDE 45 void initmod(void (* odeparms)(int *, double *)) { int N = 3;
  • deparms(&N, parms);
} void lorenz(int *n, double *t, double *y, double *dydt, double *yout, int *ip) { double sigma = parms[0]; double R = parms[1]; double b = parms[2]; double y1 = y[0]; double y2 = y[1]; double y3 = y[2]; dydt[0] = sigma * (y2 - y1); dydt[1] = R * y1 - y2 - y1 * y3; dydt[2] = -b * y3 + y1 * y2; } lorenz <- function(t, y, parms) { sigma <- parms[1] R <- parms[2] b <- parms[3] y1 <- y[1] y2 <- y[2] y3 <- y[3] list(c(sigma * (y2 - y1), R * y1 - y2 - y1 * y3,
  • b * y3 + y1 * y2))
}

Unpack our variables

slide-46
SLIDE 46 lorenz <- function(t, y, parms) { sigma <- parms[1] R <- parms[2] b <- parms[3] y1 <- y[1] y2 <- y[2] y3 <- y[3] list(c(sigma * (y2 - y1), R * y1 - y2 - y1 * y3,
  • b * y3 + y1 * y2))
} void initmod(void (* odeparms)(int *, double *)) { int N = 3;
  • deparms(&N, parms);
} void lorenz(int *n, double *t, double *y, double *dydt, double *yout, int *ip) { double sigma = parms[0]; double R = parms[1]; double b = parms[2]; double y1 = y[0]; double y2 = y[1]; double y3 = y[2]; dydt[0] = sigma * (y2 - y1); dydt[1] = R * y1 - y2 - y1 * y3; dydt[2] = -b * y3 + y1 * y2; }

Compute our derivatives

slide-47
SLIDE 47 lorenz <- function(t, y, parms) { sigma <- parms[1] R <- parms[2] b <- parms[3] y1 <- y[1] y2 <- y[2] y3 <- y[3] list(c(sigma * (y2 - y1), R * y1 - y2 - y1 * y3,
  • b * y3 + y1 * y2))
} void initmod(void (* odeparms)(int *, double *)) { int N = 3;
  • deparms(&N, parms);
} void lorenz(int *n, double *t, double *y, double *dydt, double *yout, int *ip) { double sigma = parms[0]; double R = parms[1]; double b = parms[2]; double y1 = y[0]; double y2 = y[1]; double y3 = y[2]; dydt[0] = sigma * (y2 - y1); dydt[1] = R * y1 - y2 - y1 * y3; dydt[2] = -b * y3 + y1 * y2; }

What is this? It's a spell that we write (it's actually a function that tales a function pointer as an argument, then calls that function on the address of stack allocated integer, along with the vector of parameters that deSolve will pass in)

slide-48
SLIDE 48 lorenz <- function(t, y, parms) { sigma <- parms[1] R <- parms[2] b <- parms[3] y1 <- y[1] y2 <- y[2] y3 <- y[3] list(c(sigma * (y2 - y1), R * y1 - y2 - y1 * y3,
  • b * y3 + y1 * y2))
} void initmod(void (* odeparms)(int *, double *)) { int N = 3;
  • deparms(&N, parms);
} void lorenz(int *n, double *t, double *y, double *dydt, double *yout, int *ip) { double sigma = parms[0]; double R = parms[1]; double b = parms[2]; double y1 = y[0]; double y2 = y[1]; double y3 = y[2]; dydt[0] = sigma * (y2 - y1); dydt[1] = R * y1 - y2 - y1 * y3; dydt[2] = -b * y3 + y1 * y2; }

(it's actually a function that tales a function pointer as an argument, then calls that function on the address of stack allocated integer, along with the vector of parameters that deSolve will pass in)

slide-49
SLIDE 49

easy fast

  • r

Obviously real world cases are going to be more complicated than this but it would be nice to be able to remove the tradeoff here

slide-50
SLIDE 50

fast and easy

slide-51
SLIDE 51

lorenz <- odin::odin({ ## Derivatives deriv(y1) <- sigma * (y2 - y1) deriv(y2) <- R * y1 - y2 - y1 * y3 deriv(y3) <- -b * y3 + y1 * y2 ## Initial conditions initial(y1) <- 10.0 initial(y2) <- 1.0 initial(y3) <- 1.0 ## parameters sigma <- user() R <- user() b <- user() })

  • din

Odin is a "domain specific language" Same idea as the encryption package but more extreme - now we take a set of R code and never run it - we just use it define a problem. We can pull it apart and do things to it - in this case generate C code, compile that, load it into R and wrap that up as an R object

slide-52
SLIDE 52

lorenz <- odin::odin({ ... sigma <- user() R <- user() b <- user() }) model <- lorenz(sigma = 10.0, R = 28.0, b = 8 / 3) t <- seq(0, 50, length.out = 10000) y <- model$run(t)

  • din

name the args in the call

slide-53
SLIDE 53
slide-54
SLIDE 54

deriv(y1) <- sigma * (y2 - y1) list(`<-`, deriv(y1), sigma * (y2 - y1)) dydt[0] = sigma * (y2 - y1);

Rewriting expressions

slide-55
SLIDE 55

deriv(y1[]) <- sigma * (y2[i] - y1[i]) list(`<-`, deriv(y1[]), sigma * (y2[i] - y1[i])) for (size_t i = 0; i < len_y1; ++i) { dydt[i] = sigma * (y2[i] - y1[i]); }

Rewriting expressions

this approach scales up through application of simple rules to support things like automatically working over arrays

slide-56
SLIDE 56

lorenz <- odin::odin({ ## Derivatives deriv(y1) <- sigma * (y2 - y1) deriv(y2) <- R * y1 - y2 - y1 * y3 deriv(y3) <- -b * y3 + y1 * y2 ## Initial conditions initial(y1) <- 10.0 initial(y2) <- 1.0 initial(y3) <- 1.0 ## parameters sigma <- user() R <- user() b <- user() }) Odin is a "domain specific language" Same idea as the encryption package but more extreme - now we take a set of R code and never run it - we just use it define a problem. We can pull it apart and do things to it - in this case generate C code, compile that, load it into R and wrap that up as an R object

slide-57
SLIDE 57

a b X X = a + b

<latexit sha1_base64="HCVyjhK92BlSIlJoJtC/U7I8jLQ=">AChXicdVHLahtBEBxtXoryspNjLoNFwCFm2ZUl2zqEGByIDzk4IYoVZGF6Z1vyoHksM73BYvFX+Or8S34jf5NZyYbIOA0DRVPd1d3VijpKUn+NKJ79x8fNR83Hry9NnzF2vrL797WzqBA2GVdcMPCpcECSFA4Lh6AzhcfZ7KDWj3+i89KabzQvcKxhauRECqBA/Rjy9xz4O56drWTOE17nd4eD2C7393uBdBJ0p3dPk/jZBFtdh1Hp+uN6UluRanRkFDg/ShNChpX4EgKhRetk9JjAWIGUxwFaECjH1eLiS/4m8DkfGJdeIb4gv3RwXa+7nOQqYGOvO3tZq8SxuVNkbV9IUJaERy0aTUnGyvLbPc+lQkJoHAMLJMCsXZ+BAUFhSa6XNoniBYsVKdV4aKWyOt1hF5+QgkB5JgzS1reqrzWxofGBNjiYvpFD3Vrf/CinkvzW53ALs/XJIc7e3vEnOZm/z/YNCJ+3Hypdvez34vb9Rkr9kG2Qp2X7JAdsQETLNLdsV+Rc0ojrRzjI1alzf9RVbiejDX4lFx10=</latexit><latexit sha1_base64="HCVyjhK92BlSIlJoJtC/U7I8jLQ=">AChXicdVHLahtBEBxtXoryspNjLoNFwCFm2ZUl2zqEGByIDzk4IYoVZGF6Z1vyoHksM73BYvFX+Or8S34jf5NZyYbIOA0DRVPd1d3VijpKUn+NKJ79x8fNR83Hry9NnzF2vrL797WzqBA2GVdcMPCpcECSFA4Lh6AzhcfZ7KDWj3+i89KabzQvcKxhauRECqBA/Rjy9xz4O56drWTOE17nd4eD2C7393uBdBJ0p3dPk/jZBFtdh1Hp+uN6UluRanRkFDg/ShNChpX4EgKhRetk9JjAWIGUxwFaECjH1eLiS/4m8DkfGJdeIb4gv3RwXa+7nOQqYGOvO3tZq8SxuVNkbV9IUJaERy0aTUnGyvLbPc+lQkJoHAMLJMCsXZ+BAUFhSa6XNoniBYsVKdV4aKWyOt1hF5+QgkB5JgzS1reqrzWxofGBNjiYvpFD3Vrf/CinkvzW53ALs/XJIc7e3vEnOZm/z/YNCJ+3Hypdvez34vb9Rkr9kG2Qp2X7JAdsQETLNLdsV+Rc0ojrRzjI1alzf9RVbiejDX4lFx10=</latexit><latexit sha1_base64="HCVyjhK92BlSIlJoJtC/U7I8jLQ=">AChXicdVHLahtBEBxtXoryspNjLoNFwCFm2ZUl2zqEGByIDzk4IYoVZGF6Z1vyoHksM73BYvFX+Or8S34jf5NZyYbIOA0DRVPd1d3VijpKUn+NKJ79x8fNR83Hry9NnzF2vrL797WzqBA2GVdcMPCpcECSFA4Lh6AzhcfZ7KDWj3+i89KabzQvcKxhauRECqBA/Rjy9xz4O56drWTOE17nd4eD2C7393uBdBJ0p3dPk/jZBFtdh1Hp+uN6UluRanRkFDg/ShNChpX4EgKhRetk9JjAWIGUxwFaECjH1eLiS/4m8DkfGJdeIb4gv3RwXa+7nOQqYGOvO3tZq8SxuVNkbV9IUJaERy0aTUnGyvLbPc+lQkJoHAMLJMCsXZ+BAUFhSa6XNoniBYsVKdV4aKWyOt1hF5+QgkB5JgzS1reqrzWxofGBNjiYvpFD3Vrf/CinkvzW53ALs/XJIc7e3vEnOZm/z/YNCJ+3Hypdvez34vb9Rkr9kG2Qp2X7JAdsQETLNLdsV+Rc0ojrRzjI1alzf9RVbiejDX4lFx10=</latexit>

transition missing here - return to the SIR model then display this

slide-58
SLIDE 58

a b X Y c Z W

slide-59
SLIDE 59

a b X Y c Z W

slide-60
SLIDE 60

a b X Y c Z W

slide-61
SLIDE 61

a b X Y c Z W

slide-62
SLIDE 62

S I R

dI dt

<latexit sha1_base64="1mqyaLH0HvCuY+5X9BJn6PiBZ1E=">ACiXicdVFdaxNBFJ2sH62x2g8fRkMQoUSdtOmTXwqRFDBhyrGFpKlzM7eTYfMzmxn7krDkt/R1/pP/Bv+G+8mLZhSLwczrlzP85NCq08huGfRvDo8ZOna+vPms83Xrzc3Nre+eFt6SQMpdXWnSXCg1YGhqhQw1nhQOSJhtNkOqj105/gvLmO84KiHMxMSpTUiBR8ThzQlbp53mV4vx8qxW2o6jb6fY4gf3+wX6XQCeMDo/6PGqHi2ix2zg5325MxqmVZQ4GpRbej6KwLgSDpXUMG+OSw+FkFMxgRFBI3LwcbWYes7fEpPyzDp6BvmC/fdHJXLvZ3lCmbnAC39fq8mHtFGJWS+ulClKBCOXjbJSc7S8toCnyoFEPSMgpFM0K5cXgoxAMq50mZRvAC5skp1VRolbQr3WI1X6ASRHjAXytRrVd9sYqnxwJoUDC18J1PdWt/9oCYK/d4XuofZ+gApu8e+EOnufOf/x8MO+1+O/x60DpOfi9vtM5eszdsl0XsiB2zT+yEDZlkl+ya3bBfwUbQCXrB+2Vq0Li96yu2EsHgL2Cpyu8=</latexit><latexit sha1_base64="1mqyaLH0HvCuY+5X9BJn6PiBZ1E=">ACiXicdVFdaxNBFJ2sH62x2g8fRkMQoUSdtOmTXwqRFDBhyrGFpKlzM7eTYfMzmxn7krDkt/R1/pP/Bv+G+8mLZhSLwczrlzP85NCq08huGfRvDo8ZOna+vPms83Xrzc3Nre+eFt6SQMpdXWnSXCg1YGhqhQw1nhQOSJhtNkOqj105/gvLmO84KiHMxMSpTUiBR8ThzQlbp53mV4vx8qxW2o6jb6fY4gf3+wX6XQCeMDo/6PGqHi2ix2zg5325MxqmVZQ4GpRbej6KwLgSDpXUMG+OSw+FkFMxgRFBI3LwcbWYes7fEpPyzDp6BvmC/fdHJXLvZ3lCmbnAC39fq8mHtFGJWS+ulClKBCOXjbJSc7S8toCnyoFEPSMgpFM0K5cXgoxAMq50mZRvAC5skp1VRolbQr3WI1X6ASRHjAXytRrVd9sYqnxwJoUDC18J1PdWt/9oCYK/d4XuofZ+gApu8e+EOnufOf/x8MO+1+O/x60DpOfi9vtM5eszdsl0XsiB2zT+yEDZlkl+ya3bBfwUbQCXrB+2Vq0Li96yu2EsHgL2Cpyu8=</latexit><latexit sha1_base64="1mqyaLH0HvCuY+5X9BJn6PiBZ1E=">ACiXicdVFdaxNBFJ2sH62x2g8fRkMQoUSdtOmTXwqRFDBhyrGFpKlzM7eTYfMzmxn7krDkt/R1/pP/Bv+G+8mLZhSLwczrlzP85NCq08huGfRvDo8ZOna+vPms83Xrzc3Nre+eFt6SQMpdXWnSXCg1YGhqhQw1nhQOSJhtNkOqj105/gvLmO84KiHMxMSpTUiBR8ThzQlbp53mV4vx8qxW2o6jb6fY4gf3+wX6XQCeMDo/6PGqHi2ix2zg5325MxqmVZQ4GpRbej6KwLgSDpXUMG+OSw+FkFMxgRFBI3LwcbWYes7fEpPyzDp6BvmC/fdHJXLvZ3lCmbnAC39fq8mHtFGJWS+ulClKBCOXjbJSc7S8toCnyoFEPSMgpFM0K5cXgoxAMq50mZRvAC5skp1VRolbQr3WI1X6ASRHjAXytRrVd9sYqnxwJoUDC18J1PdWt/9oCYK/d4XuofZ+gApu8e+EOnufOf/x8MO+1+O/x60DpOfi9vtM5eszdsl0XsiB2zT+yEDZlkl+ya3bBfwUbQCXrB+2Vq0Li96yu2EsHgL2Cpyu8=</latexit>

dS dt

<latexit sha1_base64="Se031vE/7LFUGq2Wld4y9AVu1A8=">ACiXicdVHbatAEF2rt9RNm0sf+7LUFIRnLixu5TwIX2oQ/pxU3AFmG1GjmLV7vK7qjECH9HXtM/yW/kbzqyE6hDOrBwOGd2LmeSQiuPYXjTCB49fvL02drz5ov1l682Nre2f3lbOglDabV1J4nwoJWBISrUcFI4EHmi4TiZDmr9+Dc4r6z5ibMC4lxMjMqUFEhUPM6ckFX6Y16lOD/dbIXtKOp2uj1OYK+/v9cl0AmjDwd9HrXDRbTYbRydbjUm49TKMgeDUgvR1FYFwJh0pqmDfHpYdCyKmYwIigETn4uFpMPefviEl5Zh09g3zB/vujErn3szyhzFzgmb+v1eRD2qjErBdXyhQlgpHLRlmpOVpeW8BT5UCinhEQ0imalcszQUYgGdVcabMoXoBcWaW6KI2SNoV7rMYLdIJID5gLZeq1qu82sdR4YE0Kha+k6lure98UhOFfvcr3cPsfnYA0/cP/KHT3PnP/w+GnXa/HX7bx0m18sbrbE37C3bYRE7YIfsCztiQybZObtkV+xPsB50gl7wcZkaNG7v+pqtRD4C3XVyvk=</latexit><latexit sha1_base64="Se031vE/7LFUGq2Wld4y9AVu1A8=">ACiXicdVHbatAEF2rt9RNm0sf+7LUFIRnLixu5TwIX2oQ/pxU3AFmG1GjmLV7vK7qjECH9HXtM/yW/kbzqyE6hDOrBwOGd2LmeSQiuPYXjTCB49fvL02drz5ov1l682Nre2f3lbOglDabV1J4nwoJWBISrUcFI4EHmi4TiZDmr9+Dc4r6z5ibMC4lxMjMqUFEhUPM6ckFX6Y16lOD/dbIXtKOp2uj1OYK+/v9cl0AmjDwd9HrXDRbTYbRydbjUm49TKMgeDUgvR1FYFwJh0pqmDfHpYdCyKmYwIigETn4uFpMPefviEl5Zh09g3zB/vujErn3szyhzFzgmb+v1eRD2qjErBdXyhQlgpHLRlmpOVpeW8BT5UCinhEQ0imalcszQUYgGdVcabMoXoBcWaW6KI2SNoV7rMYLdIJID5gLZeq1qu82sdR4YE0Kha+k6lure98UhOFfvcr3cPsfnYA0/cP/KHT3PnP/w+GnXa/HX7bx0m18sbrbE37C3bYRE7YIfsCztiQybZObtkV+xPsB50gl7wcZkaNG7v+pqtRD4C3XVyvk=</latexit><latexit sha1_base64="Se031vE/7LFUGq2Wld4y9AVu1A8=">ACiXicdVHbatAEF2rt9RNm0sf+7LUFIRnLixu5TwIX2oQ/pxU3AFmG1GjmLV7vK7qjECH9HXtM/yW/kbzqyE6hDOrBwOGd2LmeSQiuPYXjTCB49fvL02drz5ov1l682Nre2f3lbOglDabV1J4nwoJWBISrUcFI4EHmi4TiZDmr9+Dc4r6z5ibMC4lxMjMqUFEhUPM6ckFX6Y16lOD/dbIXtKOp2uj1OYK+/v9cl0AmjDwd9HrXDRbTYbRydbjUm49TKMgeDUgvR1FYFwJh0pqmDfHpYdCyKmYwIigETn4uFpMPefviEl5Zh09g3zB/vujErn3szyhzFzgmb+v1eRD2qjErBdXyhQlgpHLRlmpOVpeW8BT5UCinhEQ0imalcszQUYgGdVcabMoXoBcWaW6KI2SNoV7rMYLdIJID5gLZeq1qu82sdR4YE0Kha+k6lure98UhOFfvcr3cPsfnYA0/cP/KHT3PnP/w+GnXa/HX7bx0m18sbrbE37C3bYRE7YIfsCztiQybZObtkV+xPsB50gl7wcZkaNG7v+pqtRD4C3XVyvk=</latexit>

dR dt

<latexit sha1_base64="TVQ3MVcKCYwdAJyR45Z7vcI6s=">ACiXicdVFdSxtBFJ1sbWtTW7V97MtgKFiQsBtNTfokpNA+9MFKU4VkdnZu3HI7Mw6c1cMS35HX+s/8W/03/RuotCIvTBwOfO/Tg3KbTyGIZ/GsGTtafPnq+/aL7cePV6c2v7zU9vSydhK27iwRHrQyMESFGs4KByJPNJwm0Gtn16B8qaHzgrIM7FxKhMSYFExePMCVmlJ/Mqxfn5VitsR1G30+1xAv9g/0ugU4YfTzs86gdLqLF7uL4fLsxGadWljkYlFp4P4rCAuNKOFRSw7w5Lj0UQk7FBEYEjcjBx9Vi6jl/T0zKM+voGeQL9t8flci9n+UJZeYCL/xDrSYf0YlZr24UqYoEYxcNspKzdHy2gKeKgcS9YyAkE7RrFxeCDICyajmSptF8QLkyirVdWmUtCk8YDVeoxNEesBcKFOvVZ3YxFLjgTUpGFr4Xqa6tb7WU0U+r1vdA+z98UBTD8odOc+8/z8Ydtr9dvj9oHWU3C5vtM7esR2yJ2yI7YV3bMhkyS/aL/WY3wUbQCXrBp2Vq0Li761u2EsHgL3O3yvg=</latexit><latexit sha1_base64="TVQ3MVcKCYwdAJyR45Z7vcI6s=">ACiXicdVFdSxtBFJ1sbWtTW7V97MtgKFiQsBtNTfokpNA+9MFKU4VkdnZu3HI7Mw6c1cMS35HX+s/8W/03/RuotCIvTBwOfO/Tg3KbTyGIZ/GsGTtafPnq+/aL7cePV6c2v7zU9vSydhK27iwRHrQyMESFGs4KByJPNJwm0Gtn16B8qaHzgrIM7FxKhMSYFExePMCVmlJ/Mqxfn5VitsR1G30+1xAv9g/0ugU4YfTzs86gdLqLF7uL4fLsxGadWljkYlFp4P4rCAuNKOFRSw7w5Lj0UQk7FBEYEjcjBx9Vi6jl/T0zKM+voGeQL9t8flci9n+UJZeYCL/xDrSYf0YlZr24UqYoEYxcNspKzdHy2gKeKgcS9YyAkE7RrFxeCDICyajmSptF8QLkyirVdWmUtCk8YDVeoxNEesBcKFOvVZ3YxFLjgTUpGFr4Xqa6tb7WU0U+r1vdA+z98UBTD8odOc+8/z8Ydtr9dvj9oHWU3C5vtM7esR2yJ2yI7YV3bMhkyS/aL/WY3wUbQCXrBp2Vq0Li761u2EsHgL3O3yvg=</latexit><latexit sha1_base64="TVQ3MVcKCYwdAJyR45Z7vcI6s=">ACiXicdVFdSxtBFJ1sbWtTW7V97MtgKFiQsBtNTfokpNA+9MFKU4VkdnZu3HI7Mw6c1cMS35HX+s/8W/03/RuotCIvTBwOfO/Tg3KbTyGIZ/GsGTtafPnq+/aL7cePV6c2v7zU9vSydhK27iwRHrQyMESFGs4KByJPNJwm0Gtn16B8qaHzgrIM7FxKhMSYFExePMCVmlJ/Mqxfn5VitsR1G30+1xAv9g/0ugU4YfTzs86gdLqLF7uL4fLsxGadWljkYlFp4P4rCAuNKOFRSw7w5Lj0UQk7FBEYEjcjBx9Vi6jl/T0zKM+voGeQL9t8flci9n+UJZeYCL/xDrSYf0YlZr24UqYoEYxcNspKzdHy2gKeKgcS9YyAkE7RrFxeCDICyajmSptF8QLkyirVdWmUtCk8YDVeoxNEesBcKFOvVZ3YxFLjgTUpGFr4Xqa6tb7WU0U+r1vdA+z98UBTD8odOc+8/z8Ydtr9dvj9oHWU3C5vtM7esR2yJ2yI7YV3bMhkyS/aL/WY3wUbQCXrBp2Vq0Li761u2EsHgL3O3yvg=</latexit>

Susceptible, infected, resistant

slide-63
SLIDE 63

sir <- odin::odin({ deriv(S) <- -beta * S * I / N deriv(I) <- beta * S * I / N - gamma * I deriv(R) <- gamma * I initial(S) <- 1000 initial(I) <- 1 initial(R) <- 0 N <- S + I + R beta <- 0.2 gamma <- 0.1 })

don't forget to fix this slide - the right side needs to go away

slide-64
SLIDE 64

S I N R

dS dt

<latexit sha1_base64="Se031vE/7LFUGq2Wld4y9AVu1A8=">ACiXicdVHbatAEF2rt9RNm0sf+7LUFIRnLixu5TwIX2oQ/pxU3AFmG1GjmLV7vK7qjECH9HXtM/yW/kbzqyE6hDOrBwOGd2LmeSQiuPYXjTCB49fvL02drz5ov1l682Nre2f3lbOglDabV1J4nwoJWBISrUcFI4EHmi4TiZDmr9+Dc4r6z5ibMC4lxMjMqUFEhUPM6ckFX6Y16lOD/dbIXtKOp2uj1OYK+/v9cl0AmjDwd9HrXDRbTYbRydbjUm49TKMgeDUgvR1FYFwJh0pqmDfHpYdCyKmYwIigETn4uFpMPefviEl5Zh09g3zB/vujErn3szyhzFzgmb+v1eRD2qjErBdXyhQlgpHLRlmpOVpeW8BT5UCinhEQ0imalcszQUYgGdVcabMoXoBcWaW6KI2SNoV7rMYLdIJID5gLZeq1qu82sdR4YE0Kha+k6lure98UhOFfvcr3cPsfnYA0/cP/KHT3PnP/w+GnXa/HX7bx0m18sbrbE37C3bYRE7YIfsCztiQybZObtkV+xPsB50gl7wcZkaNG7v+pqtRD4C3XVyvk=</latexit><latexit sha1_base64="Se031vE/7LFUGq2Wld4y9AVu1A8=">ACiXicdVHbatAEF2rt9RNm0sf+7LUFIRnLixu5TwIX2oQ/pxU3AFmG1GjmLV7vK7qjECH9HXtM/yW/kbzqyE6hDOrBwOGd2LmeSQiuPYXjTCB49fvL02drz5ov1l682Nre2f3lbOglDabV1J4nwoJWBISrUcFI4EHmi4TiZDmr9+Dc4r6z5ibMC4lxMjMqUFEhUPM6ckFX6Y16lOD/dbIXtKOp2uj1OYK+/v9cl0AmjDwd9HrXDRbTYbRydbjUm49TKMgeDUgvR1FYFwJh0pqmDfHpYdCyKmYwIigETn4uFpMPefviEl5Zh09g3zB/vujErn3szyhzFzgmb+v1eRD2qjErBdXyhQlgpHLRlmpOVpeW8BT5UCinhEQ0imalcszQUYgGdVcabMoXoBcWaW6KI2SNoV7rMYLdIJID5gLZeq1qu82sdR4YE0Kha+k6lure98UhOFfvcr3cPsfnYA0/cP/KHT3PnP/w+GnXa/HX7bx0m18sbrbE37C3bYRE7YIfsCztiQybZObtkV+xPsB50gl7wcZkaNG7v+pqtRD4C3XVyvk=</latexit><latexit sha1_base64="Se031vE/7LFUGq2Wld4y9AVu1A8=">ACiXicdVHbatAEF2rt9RNm0sf+7LUFIRnLixu5TwIX2oQ/pxU3AFmG1GjmLV7vK7qjECH9HXtM/yW/kbzqyE6hDOrBwOGd2LmeSQiuPYXjTCB49fvL02drz5ov1l682Nre2f3lbOglDabV1J4nwoJWBISrUcFI4EHmi4TiZDmr9+Dc4r6z5ibMC4lxMjMqUFEhUPM6ckFX6Y16lOD/dbIXtKOp2uj1OYK+/v9cl0AmjDwd9HrXDRbTYbRydbjUm49TKMgeDUgvR1FYFwJh0pqmDfHpYdCyKmYwIigETn4uFpMPefviEl5Zh09g3zB/vujErn3szyhzFzgmb+v1eRD2qjErBdXyhQlgpHLRlmpOVpeW8BT5UCinhEQ0imalcszQUYgGdVcabMoXoBcWaW6KI2SNoV7rMYLdIJID5gLZeq1qu82sdR4YE0Kha+k6lure98UhOFfvcr3cPsfnYA0/cP/KHT3PnP/w+GnXa/HX7bx0m18sbrbE37C3bYRE7YIfsCztiQybZObtkV+xPsB50gl7wcZkaNG7v+pqtRD4C3XVyvk=</latexit>

beta

deriv(S) <- -beta * S * I / N
 N <- S + I + R

slide-65
SLIDE 65

Time Variable

Application in an epi context:

  • ODE systems with ~10k compartments
  • Periodic interventions
  • Delays where whole parts of the graph are replayed

Package is agnostic about how inference with these models would be done - there's lots of different reasons to solve an ODE system and it's out of scope here. Scope of the package

  • Simple delay differential equations (limited by R's DDE solvers)
  • Arrays for structured compartment models
  • Same interface for discrete time models, which may be stochastic
slide-66
SLIDE 66

Docker

slide-67
SLIDE 67

what is docker?

slide-68
SLIDE 68

Docker is a software technology providing operating- system-level virtualization also known as containers, promoted by the company Docker, Inc. Docker provides an additional layer of abstraction and automation of

  • perating-system-level virtualization on Windows and
  • Linux. Docker uses the resource isolation features of the

Linux kernel such as cgroups and kernel namespaces, and a union-capable file system such as OverlayFS and others to allow independent "containers" to run within a single Linux instance, avoiding the overhead of starting and maintaining virtual machines.

It's really hard to explain what docker is and not be really boring and/or incorrect

slide-69
SLIDE 69

why use docker?

More interesting is to ask why one would want to use docker

slide-70
SLIDE 70

Docker
 image

"works on my machine"

System dependencies R packages Scripts / data container break into 2?

slide-71
SLIDE 71

database

port

persistent storage

R app

break into 2 as well

slide-72
SLIDE 72

database

port

persistent storage

shiny
 app

port

proxy

port

slide-73
SLIDE 73

The metaphor is containers because that's like the shipping revolution - pre containers loading and unloading at the docs was labour intensive

slide-74
SLIDE 74

but after containers turn up it's much easier to ignore what is inside and just build tools around a standard size

slide-75
SLIDE 75 /containers/create: post: summary: "Create a container" consumes:
  • "application/json"
parameters:
  • name: "name"
in: "query" description: "Assign the specified name to the container." type: "string" responses: 201: description: "Container created successfully" schema: type: "object" description: "OK response to ContainerCreate operation" properties: Id: description: "The ID of the created container" type: "string"

swagger

OK so docker is awesome, let's use it from R!

slide-76
SLIDE 76 /containers/create: post: summary: "Create a container" consumes:
  • "application/json"
parameters:
  • name: "name"
in: "query" description: "Assign the specified name to the container." type: "string" responses: 201: description: "Container created successfully" schema: type: "object" description: "OK response to ContainerCreate operation" properties: Id: description: "The ID of the created container" type: "string"

where

slide-77
SLIDE 77 /containers/create: post: summary: "Create a container" consumes:
  • "application/json"
parameters:
  • name: "name"
in: "query" description: "Assign the specified name to the container." type: "string" responses: 201: description: "Container created successfully" schema: type: "object" description: "OK response to ContainerCreate operation" properties: Id: description: "The ID of the created container" type: "string"

parameters

slide-78
SLIDE 78 /containers/create: post: summary: "Create a container" consumes:
  • "application/json"
parameters:
  • name: "name"
in: "query" description: "Assign the specified name to the container." type: "string" responses: 201: description: "Container created successfully" schema: type: "object" description: "OK response to ContainerCreate operation" properties: Id: description: "The ID of the created container" type: "string"

returning

slide-79
SLIDE 79 /containers/create: post: summary: "Create a container" consumes:
  • "application/json"
parameters:
  • name: "name"
in: "query" description: "Assign the specified name to the container." type: "string" responses: 201: description: "Container created successfully" schema: type: "object" description: "OK response to ContainerCreate operation" properties: Id: description: "The ID of the created container" type: "string"

90 methods 10,000 lines 12 versions

slide-80
SLIDE 80 if tmpfs: if version_lt(version, '1.22'): raise host_config_version_error('tmpfs', '1.22') self["Tmpfs"] = convert_tmpfs_mounts(tmpfs) if userns_mode: if version_lt(version, '1.23'): raise host_config_version_error('userns_mode', '1.23') self['UsernsMode'] = userns_mode if pids_limit: if version_lt(version, '1.23'): raise host_config_version_error('pids_limit', '1.23') self["PidsLimit"] = pids_limit if isolation: if version_lt(version, '1.24'): raise host_config_version_error('isolation', '1.24') self['Isolation'] = isolation if auto_remove: if version_lt(version, '1.25'): raise host_config_version_error('auto_remove', '1.25') self['AutoRemove'] = auto_remove

if
 else hell

The python folks have a really wonderful docker client - from a user perspective it's a joy to use but the code behind it hits this version issue head on But we have this crazy dynamic language, so let's do it a different way.

slide-81
SLIDE 81

add <- function(a, b) { a + b }

write a function How to

slide-82
SLIDE 82

add <- function(a, b) { a + b } args <- alist(a =, b =) body <- quote(a + b) add <- as.function(c(args, body))

build a function How to

slide-83
SLIDE 83
slide-84
SLIDE 84

docker <- stevedore::docker_client()

stevedore

slide-85
SLIDE 85

(this gif will play on the README at https://github.com/richfitz/stevedore)

slide-86
SLIDE 86

docker <- stevedore::docker_client( api_version = "1.35")

Stevedore

slide-87
SLIDE 87
  • 1. Install database
  • 2. Configure & set up passwords
  • 3. Use database in package tests
  • 4. Make sure you clean up properly!

Testing packages

OK, so why:

* you can set up an empty container for testing your package just like travis (but locally) * but you can extend that all the way out to cover things like getting database included
slide-88
SLIDE 88 echo mysql-server mysql-server/root_password password $MYSQL_PASSWORD | \ debconf-set-selections echo mysql-server mysql-server/root_password_again password $MYSQL_PASSWORD | \ debconf-set-selections apt-get install -y mysql-server systemctl stop mysql mv /var/lib/mysql /mnt/data/mysql ln -s /mnt/data/mysql /var/lib/mysql echo "alias /var/lib/mysql/ -> /mnt/data/mysql," >> \ /etc/apparmor.d/tunables/alias sudo systemctl restart apparmor systemctl start mysql mysql -u root -p$MYSQL_PASSWORD -e 'show databases;'| grep teamcity > /dev/null if [ "$?" = "1" ]; then cat > /tmp/database-setup.sql <<EOF CREATE DATABASE $TEAMCITY_DB_NAME DEFAULT CHARACTER SET utf8 COLLATE utf8_bin; CREATE USER '$TEAMCITY_DB_USER'@'%' IDENTIFIED BY '$TEAMCITY_DB_PASS'; GRANT ALL ON $TEAMCITY_DB_NAME.* TO '$TEAMCITY_DB_USER'@'%'; EOF mysql -u root -p$MYSQL_PASSWORD < /tmp/database-setup.sql rm /tmp/database-setup.sql fi

This is the database part of our setup for our continuous integration server VM (mysql not postgres)

slide-89
SLIDE 89

Testing packages

env <- c("POSTGRES_PASS" = "s3cret!") db <- docker$containers$run("postgres", ports = "2222:5432", rm = TRUE, detach = TRUE, env = env)

slide-90
SLIDE 90

Testing packages

env <- c("POSTGRES_PASS" = "s3cret!") db <- docker$containers$run("postgres", ports = "2222:5432", rm = TRUE, detach = TRUE, env = env) con <- dbConnect(Postgres(), host = "localhost", port = 2222, user = "postgres", password = "s3cret!") dbWriteTable(con, "table", mydata)

slide-91
SLIDE 91

Testing packages

env <- c("POSTGRES_PASS" = "s3cret!") db <- docker$containers$run("postgres", ports = "2222:5432", rm = TRUE, detach = TRUE, env = env) con <- dbConnect(Postgres(), host = "localhost", port = 2222, user = "postgres", password = "s3cret!") dbWriteTable(con, "table", mydata) dbGetQuery(con, "SELECT * FROM table LIMIT 20")

slide-92
SLIDE 92

Testing packages

env <- c("POSTGRES_PASS" = "s3cret!") db <- docker$containers$run("postgres", ports = "2222:5432", rm = TRUE, detach = TRUE, env = env) con <- dbConnect(Postgres(), host = "localhost", port = 2222, user = "postgres", password = "s3cret!") dbWriteTable(con, "table", mydata) dbGetQuery(con, "SELECT * FROM table LIMIT 20") db$stop() But it's not limited to that - you could control a load balancing AWS cluster using docker swarm for your massively parallel ML pipeline perhaps

slide-93
SLIDE 93

Encryption Docker Differential equations

3 packages that do completely different things

slide-94
SLIDE 94

Encryption Docker Differential equations

cyphr

github.com/ropensci/cyphr

stevedore

github.com/richfitz/stevedore

  • din

github.com/mrc-ide/odin All 3 are available only through github at the moment, but will eventually make it to CRAN once they settle down The common thread is that all exploit R's dynamic language to generate interfaces that narrow the gap between what the user wants to do and what it would take to do it You don't have to use metaprogramming to do any of these things necessarily - but it's a useful and unusual trick Just remember it's a bit like marmite!

slide-95
SLIDE 95

R's weirdnesses are fun & useful

Rich FitzJohn richfitz

  • Hopefully that I've convinced you that R's weirdnesses are fun and useful and perhaps made you think about a package or an area that you'd not thought about before
  • 1. R has some strange features that make it surprisingly powerful. These should be used with care
  • 2. Three packages that do interesting things, using metaprogramming to build nice interfaces
  • 3. Three fields that you may not have encountered with R