library(TMB)
compile("SIR_try_to_break_tmb.cpp")
dyn.load(dynlib("SIR_try_to_break_tmb"))
# ------------------------------------------
# Trying to break TMB Automatic
# Differentiation (AD)
# ------------------------------------------
# We introduce two ways to represent
# transmission:
# 1. y = log(beta) = log(x - 1)
# 2. x = beta + 1 = exp(y) + 1
#
# Store y in a TMB parameter
# Store x in a 1x1 sparse data matrix
#
# On the C++ side, at every function
# evaluation start by storing exp(y) + 1
# in x. Then use x in expressions
# required to compute the likelihood.
#
# This approach should fail to give
# reasonable/correct gradients if
# the AD machinery is not implemented
# for this sparse matrix class.
#
# Failure would clearly indicate
# that we need to be careful about
# what classes we use in defining
# objective functions in TMB.
#
# Success might indicate that we
# don't need to be careful, but
# there is always the possibility
# that we didn't choose an offending
# class.
# ------------------------------------------
# simulated incidence time series using the following parameters:
# beta = 0.05
# gamma = 0.01
# nbdisp = 20
# and the following constants:
# N = 1e7 -- total population size
# I0 = exp(-3) ~ 0.04978707 -- initial number of infected individuals.
# -- now that I look at this, it doesn't
# -- look right, but I don't think this is an
# -- issue for the current goals
simulated_incidence =
c(21142, 33058, 17897, 31985, 26137, 25229, 29885, 37729, 39970,
34085, 39473, 30872, 35766, 33358, 50120, 53363, 41875, 50854,
31798, 47244, 46007, 39505, 61416, 62898, 57462, 59592, 43489,
66236, 72622, 65582, 72186, 73235, 97367, 73209, 85605, 76294,
110397, 111123, 124301, 67211, 117142, 80442, 76282, 119964,
114966, 92815, 110600, 103442, 129273, 115845, 115017, 144605,
93493, 115627, 89845, 124580, 134464, 128302, 117909, 142681,
196050, 136264, 139951, 128954, 165404, 215344, 178069, 107529,
244738, 170347, 174966, 234961, 197407, 132084, 148747, 125393,
147786, 123326, 207731, 110553, 152299, 188208, 182393, 144416,
151706, 92410, 147819, 81283, 68689, 96493, 92547, 142112, 121699,
114169, 94884, 54743, 52095, 52281, 67706, 54149)
plot(simulated_incidence)
obj = MakeADFun(
data = list(
obs_incidence = simulated_incidence,
N = 1e7,
## ----------------------------------------------------
## THIS IS A KEY BIT:
## ----------------------------------------------------
## - pass a sparse matrix in for beta+1, which is a scalar
## - this matrix will be modified on the C++ side,
## and used in the computation of the likelihood
## ----------------------------------------------------
beta_p_1 = as(Matrix::sparseMatrix(i = 1, j = 1, x = 0), "dgTMatrix")
),
# start away from the true parameters, so that the
# optimizer will take us back if it can
parameters = list(
log_beta = 0,
log_gamma = 0,
log_nbdisp = 0
),
DLL = "SIR_try_to_break_tmb"
)
# optimize
obj$hessian <- TRUE
opt <- do.call("optim", obj)
# we converge, opt$convergence = 0
opt$convergence
# we get close to the true values
opt$par
log(c(beta = 0.05, gamma = 0.01, nbdisp = 20)) # true parameters
# not quite sure how to interpret these, but the
# gradient looks smallish -- can't remember how
# to scale gradients to assess convergence.
# pretty high correlation between log_beta and
# log_gamma, but this shows up whether we use
# log_beta directly in the likelihood calculations
# or via beta_p_1.
obj$fn(opt$par)
obj$gr(opt$par)
cov2cor(solve(obj$he(opt$par)))
# plot the fitted model
sims = obj$simulate()
lines(exp(sims$log_incidence), col = 'red', lwd = 3)
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.