--- title: "Deterministic models" output: rmarkdown::html_vignette vignette: > %\VignetteIndexEntry{Deterministic models} %\VignetteEngine{knitr::rmarkdown} %\VignetteEncoding{UTF-8} --- ```{r, include = FALSE} knitr::opts_chunk$set( collapse = TRUE, comment = "#>", fig.width = 7, fig.height = 5) in_pkgdown <- identical(Sys.getenv("IN_PKGDOWN"), "true") ``` Stochastic models are slow! Ignoring issues of parallelism and fast random numbers (see `vignette("design")`), you still must run the model some number of times within a particle filter to estimate the likelihood. We're experimenting with alternative approaches to approximate the likelihood, including running the stochastic models "deterministically" with a single particle. In this case calls to `rbinom(n, p)` (for example) will be replaced with their mean (`n * p`). This is not exactly the same model as the stochastic model, nor is it directly even a limit case of it. However, we hope that it still lands in about the right area of high probability density and can be used for a pilot run before running a pmcmc properly. We demonstrate this, as in `vignette("sir_models")` with our simple SIR model. ```{r} sir <- dust::dust_example("sir") ``` The data set is included within the package: ```{r} incidence <- read.csv(system.file("sir_incidence.csv", package = "mcstate")) dt <- 0.25 data <- mcstate::particle_filter_data(incidence, time = "day", rate = 1 / dt) ``` A comparison function ```{r} compare <- function(state, observed, pars = NULL) { if (is.na(observed$cases)) { return(NULL) } exp_noise <- 1e6 incidence_modelled <- state[1, , drop = TRUE] incidence_observed <- observed$cases lambda <- incidence_modelled + rexp(n = length(incidence_modelled), rate = exp_noise) dpois(x = incidence_observed, lambda = lambda, log = TRUE) } ``` An index function for filtering the run state ```{r} index <- function(info) { list(run = 5L, state = 1:5) } ``` Parameter information for the pMCMC, including a roughly tuned kernel so that we get adequate mixing ```{r} proposal_kernel <- rbind(c(0.00057, 0.00034), c(0.00034, 0.00026)) pars <- mcstate::pmcmc_parameters$new( list(mcstate::pmcmc_parameter("beta", 0.2, min = 0, max = 1, prior = function(p) log(1e-10)), mcstate::pmcmc_parameter("gamma", 0.1, min = 0, max = 1, prior = function(p) log(1e-10))), proposal = proposal_kernel) ``` First, run a stochastic fit, as in `vignette("sir_models")`. Increasing the number of particles will reduce the variance in the estimate of the the likelihood: ```{r, include = in_pkgdown, eval = in_pkgdown} n_steps <- 300 n_particles <- 500 ``` ```{r, include = !in_pkgdown, eval = !in_pkgdown} n_steps <- 30 n_particles <- 50 ``` ```{r} control <- mcstate::pmcmc_control(n_steps) p1 <- mcstate::particle_filter$new(data, sir, n_particles, compare, index = index, n_threads = dust::dust_openmp_threads()) res1 <- mcstate::pmcmc(pars, p1, control = control) ``` then again, with the deterministic filter. The only change is to use the object `mcstate::particle_deterministic` and omit the `n_particles` element to the constructor (there will only ever be one particle!) and the `n_threads` element which has no effect here. ```{r} p2 <- mcstate::particle_deterministic$new(data, sir, compare, index = index) res2 <- mcstate::pmcmc(pars, p2, control = control) ``` Here, we plot the estimated points for the stochastic (blue) and deterministic (red) parameter samples, showing overlapping but different distributions: ```{r} plot(res1$pars, col = "#0000ff55", pch = 19) points(res2$pars, col = "#ff000055", pch = 19) legend("topleft", c("Stochastic", "Deterministic"), pch = 19, col = c("blue", "red"), bty = "n") ```