Nothing
# The one way a covariance is installed on a fit (R/cov.R): the guard, the
# covList stash, the condition refresh, and the setCov() paths built on them.
.pdCov <- function(nm = c("tka", "tcl")) {
matrix(c(0.04, 0.01, 0.01, 0.09), 2, dimnames = list(nm, nm))
}
.fakeFitEnv <- function(cov = .pdCov(), covMethod = "r,s") {
.e <- new.env(parent = emptyenv())
.e$cov <- cov
.e$covMethod <- covMethod
.e$objDf <- data.frame(OBJF = 1, "Condition#(Cov)" = 99, "Condition#(Cor)" = 99, check.names = FALSE)
.e
}
test_that(".covGuard() names why a matrix is rejected", {
expect_identical(.covGuard(NULL)$reason, "could not be computed")
expect_identical(.covGuard(matrix(1, 2, 3))$reason, "could not be computed")
expect_identical(.covGuard(matrix(numeric(0), 0, 0))$reason, "could not be computed")
expect_identical(.covGuard(matrix(c(1, NA, NA, 1), 2))$reason, "is not finite")
expect_identical(.covGuard(matrix(c(1, Inf, Inf, 1), 2))$reason, "is not finite")
expect_identical(.covGuard(matrix(c(1, 0.5, 0, 1), 2))$reason, "is not symmetric")
expect_identical(.covGuard(matrix(c(1, 2, 2, 1), 2))$reason, "is not positive definite")
expect_identical(.covGuard(matrix(c(0, 0, 0, 1), 2))$reason, "is not positive definite")
expect_identical(.covGuard(matrix(0, 2, 2))$reason, "is not positive definite")
expect_false(.covGuard(matrix(c(1, 2, 2, 1), 2))$ok)
# a finite square matrix comes back symmetrized even when rejected
expect_equal(.covGuard(matrix(c(1, 2, 2, 1), 2))$cov, matrix(c(1, 2, 2, 1), 2))
expect_null(.covGuard(matrix(c(1, NA, NA, 1), 2))$cov)
})
test_that(".covGuard() accepts a positive-definite matrix and symmetrizes it", {
.m <- .pdCov()
.m[1, 2] <- .m[1, 2] + 1e-12 # rounding-level asymmetry is accepted
.g <- .covGuard(.m)
expect_true(.g$ok)
expect_identical(.g$reason, "")
expect_identical(.g$cov[1, 2], .g$cov[2, 1])
expect_equal(.g$cov[1, 2], 0.01 + 5e-13, tolerance = 1e-15)
expect_identical(dimnames(.g$cov), dimnames(.m))
expect_equal(.g$ev, eigen(.g$cov, symmetric = TRUE, only.values = TRUE)$values)
})
test_that(".covMethodFromSlot() inverts the foceiControl() covMethod slot", {
expect_identical(.covMethodFromSlot(1L), "r,s")
expect_identical(.covMethodFromSlot(2L), "r")
expect_identical(.covMethodFromSlot(3L), "s")
expect_identical(.covMethodFromSlot(2, "analytic"), "analytic")
expect_identical(.covMethodFromSlot(1L, "analytic"), "r,s")
expect_identical(.covMethodFromSlot(0L), "")
expect_identical(.covMethodFromSlot(NA_integer_), "")
expect_identical(.covMethodFromSlot("r"), "")
expect_identical(.covMethodFromSlot(NULL), "")
for (.n in names(.covMethodSlot)) {
expect_identical(.covMethodFromSlot(.covMethodSlot[[.n]]), .n)
}
})
test_that("a control given a foceiControl() covMethod slot keeps the covariance the slot names", {
for (.n in names(.covMethodSlot)) {
.slot <- foceiControl(covMethod = .n)$covMethod
expect_identical(nlmeControl(covMethod = .slot)$covMethod, .n)
expect_identical(vaeControl(covMethod = .slot)$covMethod, .n)
expect_identical(emviControl(covMethod = .slot)$covMethod, .n)
}
expect_identical(nlmeControl(covMethod = 0L)$covMethod, "")
expect_identical(vaeControl(covMethod = 0)$covMethod, "")
expect_error(nlmeControl(covMethod = 4L), "foceiControl() slot", fixed = TRUE)
})
test_that("foceiControl() keeps a covMethod slot and rejects anything that is neither a slot nor a name", {
for (.s in 0:3) {
expect_identical(foceiControl(covMethod = .s)$covMethod, .s)
}
expect_identical(foceiControl(covMethod = 3)$covMethod, 3L)
.slotMsg <- "an integer 'covMethod' is a foceiControl() slot: 0 (none), 1 (\"r,s\"), 2 (\"r\") or 3 (\"s\")"
expect_error(foceiControl(covMethod = 7), .slotMsg, fixed = TRUE)
expect_error(foceiControl(covMethod = -1L), .slotMsg, fixed = TRUE)
# the controls that hand their slot to foceiControl()
expect_error(foceControl(covMethod = 7), .slotMsg, fixed = TRUE)
expect_error(impmapControl(covMethod = 7), .slotMsg, fixed = TRUE)
.typeMsg <- "'covMethod' must be a covariance method name or a foceiControl() slot (0 to 3)"
expect_error(foceiControl(covMethod = NULL), .typeMsg, fixed = TRUE)
expect_error(foceiControl(covMethod = 1.5), .typeMsg, fixed = TRUE)
expect_error(foceiControl(covMethod = NA), .typeMsg, fixed = TRUE)
expect_error(foceiControl(covMethod = NA_integer_), .typeMsg, fixed = TRUE)
expect_error(foceiControl(covMethod = TRUE), .typeMsg, fixed = TRUE)
expect_error(foceiControl(covMethod = c(1L, 2L)), .typeMsg, fixed = TRUE)
expect_error(foceiControl(covMethod = list()), .typeMsg, fixed = TRUE)
})
test_that("a named \"\" covMethod still turns the covariance off", {
expect_identical(nlmeControl(covMethod = c(a = ""))$covMethod, "")
expect_identical(vaeControl(covMethod = c(a = ""))$covMethod, "")
expect_identical(emviControl(covMethod = c(a = ""))$covMethod, "")
expect_identical(foceiControl(covMethod = c(a = ""))$covMethod, 0L)
expect_identical(impmapControl(covMethod = c(a = ""))$covMethod, 0L)
})
test_that("a covariance refit sets each option under its own name only", {
.obj <- new.env(parent = emptyenv())
.obj$foceiControl <- foceiControl()
local_mocked_bindings(
getData = function(object) NULL,
nlmixr2CreateOutputFromUi = function(ui, data, control, ...) control
)
# hessEps, rmatNorm and gillStepCov are prefixes of the log-likelihood options
.ctl <- .setCovRefit(.obj, hessEpsLlik = 1e-3, rmatNormLlik = 0L, gillStepCovLlik = 3)
expect_identical(
.ctl[c("hessEpsLlik", "rmatNormLlik", "gillStepCovLlik")],
list(hessEpsLlik = 1e-3, rmatNormLlik = 0L, gillStepCovLlik = 3)
)
expect_identical(
.ctl[c("hessEps", "rmatNorm", "gillStepCov")],
.obj$foceiControl[c("hessEps", "rmatNorm", "gillStepCov")]
)
})
test_that(".covInnerIterations() gives a refit's covariance legs the fit's inner budget", {
expect_identical(.covInnerIterations(foceiControl(maxInnerIterations = 250L)), 250L)
# a fit with no budget of its own (saem, nlme, vae and vi evaluate their ETAs) gets
# foceiControl()'s default
.def <- 1000L
expect_identical(as.integer(formals(foceiControl)$maxInnerIterations), .def)
expect_identical(.covInnerIterations(foceiControl(maxInnerIterations = 0L)), .def)
expect_identical(.covInnerIterations(list()), .def)
expect_identical(.covInnerIterations(list(maxInnerIterations = NA_integer_)), .def)
expect_identical(.covInnerIterations(list(maxInnerIterations = -3L)), .def)
expect_identical(.covInnerIterations(list(maxInnerIterations = Inf)), .def)
expect_identical(.covInnerIterations(list(maxInnerIterations = c(5L, 6L))), .def)
})
test_that("a covariance refit reports the fit's ETAs but differentiates its marginal likelihood", {
.obj <- new.env(parent = emptyenv())
.obj$foceiControl <- foceiControl(maxInnerIterations = 250L, interaction = TRUE)
local_mocked_bindings(
getData = function(object) NULL,
nlmixr2CreateOutputFromUi = function(ui, data, control, ...) control
)
.ctl <- .setCovRefit(.obj, covMethod = "r")
# the refit evaluates the fit's ETAs; its covariance legs optimize them with the fit's
# budget, and with the fit's interaction
expect_identical(.ctl$maxInnerIterations, 0L)
expect_identical(.ctl$covMaxInnerIterations, 250L)
expect_identical(.ctl$interaction, 1L)
})
test_that("covMaxInnerIterations survives a foceiControl() round trip", {
# nlmixr2() rebuilds a control it is given (getValidNlmixrCtl()), and the post-fit
# recompute hands its control to nlmixr2()
.ctl <- foceiControl()
expect_null(.ctl$covMaxInnerIterations)
.ctl$covMaxInnerIterations <- 300L
expect_identical(getValidNlmixrCtl.focei(list(.ctl))$covMaxInnerIterations, 300L)
expect_identical(foceiControl(covMaxInnerIterations = 7)$covMaxInnerIterations, 7L)
expect_error(foceiControl(covMaxInnerIterations = 0L), "covMaxInnerIterations")
expect_error(foceiControl(covMaxInnerIterations = 1.5), "covMaxInnerIterations")
})
test_that("covInnerTol survives a foceiControl() round trip", {
# the covariance step's inner tolerance; NULL is the probe-tolerance rule
expect_null(foceiControl()$covInnerTol)
.ctl <- foceiControl()
.ctl$covInnerTol <- 1e-11
expect_identical(getValidNlmixrCtl.focei(list(.ctl))$covInnerTol, 1e-11)
expect_identical(foceiControl(covInnerTol = 1e-10)$covInnerTol, 1e-10)
.msg <- "'covInnerTol' must be a finite number > 0"
for (.bad in list(0, -1e-9, "a", Inf, c(1e-9, 1e-8))) {
expect_error(foceiControl(covInnerTol = .bad), .msg, fixed = TRUE)
}
expect_error(foceiControl(covInnerTol = c(1e-9, 1e-9)), "covInnerTol")
})
test_that(".covInstall() installs, stashes the replaced covariance and refreshes its diagnostics", {
.e <- .fakeFitEnv()
.new <- .pdCov() * 4
expect_true(.covInstall(.e, .new, "sa"))
expect_identical(.e$covMethod, "sa")
expect_equal(.e$cov, .new)
expect_identical(names(.e$covList), "r,s")
expect_equal(.e$covList[["r,s"]], .pdCov())
.ev <- eigen(.new, symmetric = TRUE, only.values = TRUE)$values
expect_equal(.e$objDf[["Condition#(Cov)"]], max(.ev) / min(.ev))
expect_equal(.e$conditionNumberCov, max(.ev) / min(.ev))
expect_equal(.e$eigenCov, .ev)
expect_equal(unname(diag(.e$fullCor)), unname(sqrt(diag(.new))))
# an unlabelled covariance is kept as "prev"; the installed name is never stashed
.e2 <- .fakeFitEnv(covMethod = "")
.covInstall(.e2, .new, "sa")
expect_identical(names(.e2$covList), "prev")
.covInstall(.e2, .new * 2, "sa")
expect_identical(names(.e2$covList), "prev")
})
test_that(".covInstall() leaves the fit as it was when the matrix is rejected", {
.e <- .fakeFitEnv()
.bad <- matrix(c(1, 2, 2, 1), 2, dimnames = dimnames(.pdCov()))
expect_warning(
.ok <- .covInstall(.e, .bad, "sa", extras = list(parFixedDf = "refit")),
"\"sa\" covariance is not positive definite; kept \"r,s\"",
fixed = TRUE
)
expect_false(.ok)
expect_identical(attr(.ok, "reason"), "is not positive definite")
expect_identical(.e$covMethod, "r,s")
expect_equal(.e$cov, .pdCov())
expect_false(exists("covList", envir = .e, inherits = FALSE))
expect_false(exists("parFixedDf", envir = .e, inherits = FALSE))
expect_identical(.e$objDf[["Condition#(Cov)"]], 99)
.e2 <- new.env(parent = emptyenv())
expect_warning(
.covInstall(.e2, NULL, "imp"),
"\"imp\" covariance could not be computed; none installed",
fixed = TRUE
)
expect_silent(.covInstall(.e2, NULL, "imp", warn = FALSE))
expect_warning(.covInstall(.e2, NULL, NULL), "the covariance could not be computed; none installed", fixed = TRUE)
})
test_that(".covInstall() says when what it installed is not what was asked for", {
.e <- .fakeFitEnv()
expect_warning(
.covInstall(.e, .pdCov(), "linFim", what = "sa"),
"\"linFim\" covariance installed instead of the requested \"sa\"",
fixed = TRUE
)
expect_identical(.e$covMethod, "linFim")
# a correction decoration or the full-shape suffix names the same covariance
expect_silent(.covInstall(.e, .pdCov(), "|r|,s (full)", what = "r,s"))
expect_silent(.covInstall(.e, .pdCov(), "analytic (full)", what = "analytic"))
})
test_that("the post-fit mu recompute keeps the fit's covariance when its result is unusable", {
.e <- .fakeFitEnv(covMethod = "nlme")
local_mocked_bindings(.foceiRecomputeMuCov = function(fit, est) {
list(
cov = matrix(c(1, 2, 2, 1), 2, dimnames = dimnames(.pdCov())),
covMethod = "r,s",
extras = list(parFixedDf = "refit"),
what = "r,s"
)
})
expect_warning(
.foceiInstallMuCov(.e, "nlme"),
"\"r,s\" covariance is not positive definite; kept \"nlme\"",
fixed = TRUE
)
expect_identical(.e$covMethod, "nlme")
expect_equal(.e$cov, .pdCov())
expect_false(exists("parFixedDf", envir = .e, inherits = FALSE))
# a recompute that failed outright says so too
local_mocked_bindings(.foceiRecomputeMuCov = function(fit, est) list(what = "analytic"))
expect_warning(
.foceiInstallMuCov(.e, "nlme"),
"\"analytic\" covariance could not be computed; kept \"nlme\"",
fixed = TRUE
)
expect_identical(.e$covMethod, "nlme")
expect_equal(.e$cov, .pdCov())
# no recompute requested: nothing to say
local_mocked_bindings(.foceiRecomputeMuCov = function(fit, est) NULL)
expect_silent(.foceiInstallMuCov(.e, "nlme"))
})
test_that("the post-fit mu recompute carries the refit's tables and stashes the fit's covariance", {
.e <- .fakeFitEnv(covMethod = "nlme")
local_mocked_bindings(.foceiRecomputeMuCov = function(fit, est) {
list(
cov = .pdCov() * 2,
covMethod = "r,s (full)",
extras = list(parFixedDf = "refit", covList = list(r = .pdCov())),
what = "r,s"
)
})
expect_true(.foceiInstallMuCov(.e, "nlme"))
expect_identical(.e$covMethod, "r,s (full)")
expect_equal(.e$cov, .pdCov() * 2)
expect_identical(.e$parFixedDf, "refit")
expect_identical(names(.e$covList), c("r", "nlme"))
expect_equal(.e$covList$nlme, .pdCov())
})
nmTest({
.oneCmt <- function() {
ini({
tka <- 0.45
tcl <- 1.0
tv <- 3.45
add.sd <- 0.7
eta.ka ~ 0.6
eta.cl ~ 0.3
eta.v ~ 0.1
})
model({
ka <- exp(tka + eta.ka)
cl <- exp(tcl + eta.cl)
v <- exp(tv + eta.v)
linCmt() ~ add(add.sd)
})
}
.fitOnce <- function() {
suppressWarnings(nlmixr2(
.oneCmt,
nlmixr2data::theo_sd,
est = "focei",
control = foceiControl(print = 0, covMethod = "r,s", calcTables = FALSE)
))
}
test_that("a cached covariance that is not positive definite is not reinstalled", {
.fit <- .fitOnce()
.cov0 <- .fit$cov
.m0 <- .fit$covMethod
.bad <- .cov0
.bad[1, 1] <- -.bad[1, 1]
.cl <- .fit$env$covList
.cl$imp <- .bad
assign("covList", .cl, envir = .fit$env)
expect_error(
suppressMessages(setCov(.fit, "imp")),
"covMethod=\"imp\" could not be computed for this fit (the result is not positive definite)",
fixed = TRUE
)
expect_identical(.fit$covMethod, .m0)
expect_equal(.fit$cov, .cov0)
})
test_that("setCov() checks the covariance a nested fit gives before installing it", {
.fit <- .fitOnce()
.cov0 <- .fit$cov
.m0 <- .fit$covMethod
local_mocked_bindings(.covRecomputeNative = function(fit, est, control, useEtaMat = TRUE) {
list(cov = get("cov", envir = fit$env) * 2, covMethod = "linFim", mixRotated = TRUE)
})
expect_error(
setCov(.fit, "sa"),
"covMethod=\"sa\" could not be computed for this fit (the result was \"linFim\")",
fixed = TRUE
)
expect_identical(.fit$covMethod, .m0)
expect_equal(.fit$cov, .cov0)
expect_null(.fit$env$covOptions$sa)
})
test_that("a finite-difference setCov() keeps the label its refit computed", {
.fit <- .fitOnce()
.theta <- .fit$env$covList[["r,s"]]
.pf <- .fit$parFixedDf
local_mocked_bindings(nlmixr2CreateOutputFromUi = function(...) {
list(cov = .theta, covMethod = "|r|,s", parFixedDf = .pf, parFixed = NULL)
})
suppressMessages(setCov(.fit, "r,s", control = rsControl(hessEps = 1e-4)))
expect_identical(.fit$covMethod, "|r|,s")
expect_equal(.fit$cov, .theta)
# the options are recorded under the installed name too, so the same request is not recomputed
expect_equal(.fit$env$covOptions[["|r|,s"]]$hessEps, 1e-4)
expect_error(setCov(.fit, "r,s", control = rsControl(hessEps = 1e-4)), "no need to switch")
})
test_that("a finite-difference setCov() whose refit falls back to another covariance installs nothing", {
.fit <- .fitOnce()
.cov0 <- .fit$cov
.m0 <- .fit$covMethod
.theta <- .fit$env$covList[["r,s"]]
.pf <- .fit$parFixedDf
local_mocked_bindings(nlmixr2CreateOutputFromUi = function(...) {
list(cov = .theta, covMethod = "r", parFixedDf = .pf, parFixed = NULL)
})
expect_error(
setCov(.fit, "r,s", control = rsControl(hessEps = 1e-4)),
"covMethod=\"r,s\" could not be computed for this fit (the result was \"r\")",
fixed = TRUE
)
expect_identical(.fit$covMethod, .m0)
expect_equal(.fit$cov, .cov0)
})
test_that("a refit with no covariance (a mu-referenced fit's covariance step) installs nothing", {
.fit <- .fitOnce()
.cov0 <- .fit$cov
.m0 <- .fit$covMethod
local_mocked_bindings(nlmixr2CreateOutputFromUi = function(...) {
list(cov = NULL, covMethod = "", parFixedDf = NULL, parFixed = NULL)
})
expect_error(
setCov(.fit, "s", control = rsControl(hessEps = 1e-4)),
"covMethod=\"s\" could not be computed for this fit; the covariance is left unchanged",
fixed = TRUE
)
expect_identical(.fit$covMethod, .m0)
expect_equal(.fit$cov, .cov0)
# getVarCov(force = TRUE) refits the same way, and warns instead
expect_warning(
.v <- nlme::getVarCov(.fit, force = TRUE),
sprintf("the covariance could not be computed; kept \"%s\"", .m0),
fixed = TRUE
)
expect_equal(.v, .cov0)
expect_identical(.fit$covMethod, .m0)
})
# The routes that compute a FOCEi covariance at a finished fit's estimates --
# setCov(), getVarCov(force = TRUE), the post-fit recompute and the vae/vi
# hand-off -- report the fit's ETAs but differentiate its marginal likelihood: they
# give the estimation-time covariance of a FOCEi fit with no outer iterations
# started from the fit's ETAs. The full nlmixr2() refits (the recompute, vae/vi)
# reproduce it exactly; setCov()'s lighter refit to within the inner problem's
# tolerance (theta SEs within 1e-5 relative, Omega SEs within 2e-3 of the full
# shape). Holding the ETAs fixed (or dropping the interaction) would make the
# theta SEs several times too small.
.zeroOuterRef <- function(fit, covMethod, covFull = FALSE, interaction = TRUE) {
suppressWarnings(nlmixr2(
fit$finalUi,
nlmixr2data::theo_sd,
est = "focei",
control = foceiControl(
print = 0,
calcTables = FALSE,
maxOuterIterations = 0L,
maxInnerIterations = 1000L,
etaMat = fit$etaMat,
covMethod = covMethod,
covFull = covFull,
interaction = interaction
)
))
}
.seOf <- function(fit) sqrt(diag(fit$cov))
.maxRel <- function(a, b) max(abs(a / b[names(a)] - 1))
.ceOneCmt <- function() {
ini({
tka <- 0.45
tcl <- 1.0
tv <- 3.45
add.sd <- 0.3
prop.sd <- 0.1
eta.ka ~ 0.6
eta.cl ~ 0.3
eta.v ~ 0.1
})
model({
ka <- exp(tka + eta.ka)
cl <- exp(tcl + eta.cl)
v <- exp(tv + eta.v)
linCmt() ~ add(add.sd) + prop(prop.sd)
})
}
test_that("a finite-difference setCov() is the covariance of the fit's marginal likelihood", {
# setCov() reproduces the covariance a fit with that covMethod computes while it is
# estimated: the estimates are the same (the covariance step does not change them),
# and both start every leg from the fit's ETAs optimized again at the covariance
# step's tolerances. It held the ETAs fixed with interaction = 0, and its SEs were 2
# to 25 times too small.
.none <- suppressWarnings(nlmixr2(
.oneCmt,
nlmixr2data::theo_sd,
est = "focei",
control = foceiControl(print = 0, covMethod = "", calcTables = FALSE)
))
for (.m in c("r", "s", "r,s", "r (full)", "r,s (full)")) {
.full <- .covIsFull(.m)
.native <- suppressWarnings(nlmixr2(
.oneCmt,
nlmixr2data::theo_sd,
est = "focei",
control = foceiControl(print = 0, covMethod = .covBaseName(.m), covFull = .full, calcTables = FALSE)
))
expect_identical(.native$objf, .none$objf)
expect_identical(.native$covMethod, .m)
.fit <- .none
suppressMessages(suppressWarnings(setCov(.fit, .m)))
expect_identical(.fit$covMethod, .m)
expect_setequal(names(.seOf(.fit)), names(.seOf(.native)))
# measured: at most 9e-6 (theta-only) and 3e-4 (full) apart
expect_lt(.maxRel(.seOf(.fit), .seOf(.native)), if (.full) 1e-3 else 1e-4, label = .m)
}
# getVarCov(force = TRUE) recomputes the fit's own covariance
.fit <- suppressWarnings(nlmixr2(
.oneCmt,
nlmixr2data::theo_sd,
est = "focei",
control = foceiControl(print = 0, covMethod = "r", covFull = FALSE, calcTables = FALSE)
))
.v <- suppressMessages(suppressWarnings(nlme::getVarCov(.fit, force = TRUE)))
expect_lt(.maxRel(sqrt(diag(.v)), .seOf(.fit)), 1e-6)
})
test_that("setCov() differentiates the likelihood the fit used: interaction is kept", {
# with a proportional error the interaction changes the objective, so setCov() of a
# FOCEI fit must differentiate the FOCEI one, not the FOCE one (interaction = 0)
.ctl <- function(...) foceiControl(print = 0, calcTables = FALSE, covFull = FALSE, ...)
.none <- suppressWarnings(nlmixr2(.ceOneCmt, nlmixr2data::theo_sd, est = "focei", control = .ctl(covMethod = "")))
.focei <- suppressWarnings(nlmixr2(.ceOneCmt, nlmixr2data::theo_sd, est = "focei", control = .ctl(covMethod = "r")))
.foce <- .zeroOuterRef(.none, "r", interaction = FALSE)
# the two likelihoods give add.sd SEs 34% apart here
expect_gt(.seOf(.foce)[["add.sd"]] / .seOf(.focei)[["add.sd"]], 1.2)
suppressMessages(suppressWarnings(setCov(.none, "r")))
expect_identical(.none$covMethod, "r")
# measured: 2e-11 apart
expect_lt(.maxRel(.seOf(.none), .seOf(.focei)), 1e-6)
})
test_that("the post-fit mu recompute differentiates the marginal likelihood", {
.ctl <- foceiControl(print = 0, calcTables = FALSE)
.mf <- suppressWarnings(nlmixr2(.oneCmt, nlmixr2data::theo_sd, est = "mfocei", control = .ctl))
expect_identical(.mf$covMethod, "r,s (full)")
# the recompute is a FOCEi refit of the full model at the fit's estimates that reports
# the fit's ETAs (maxInnerIterations = 0) and gives its covariance legs an inner budget
.refCtl <- foceiControl(
print = 0,
calcTables = FALSE,
maxOuterIterations = 0L,
maxInnerIterations = 0L,
covMaxInnerIterations = 1000L,
etaMat = .mf$etaMat
)
.ref <- suppressWarnings(nlmixr2(.mf$finalUi, nlmixr2data::theo_sd, est = "focei", control = .refCtl))
expect_identical(.ref$covMethod, "r,s (full)")
expect_setequal(names(.seOf(.mf)), names(.seOf(.ref)))
expect_lt(.maxRel(.seOf(.mf), .seOf(.ref)), 1e-6)
# a FOCEi fit with no outer iterations that optimizes the ETAs itself first starts the
# covariance legs from slightly different ETAs: the same covariance up to the
# finite-difference noise at the covariance step's tolerances (measured 0.2%)
expect_lt(.maxRel(.seOf(.mf), .seOf(.zeroOuterRef(.mf, "r,s", covFull = TRUE))), 0.01)
# an "analytic" request outside the analytic scope (linCmt) falls back to the
# finite-difference sandwich, which is marginal too, and says so
.an <- foceiControl(print = 0, calcTables = FALSE, covMethod = "analytic")
# the post-fit recompute's warning is reported once: raised, or kept in $runInfo
# with the run's other warnings when warnings are collected
.acc <- new.env(parent = emptyenv())
.acc$w <- character(0)
.mfa <- withCallingHandlers(
nlmixr2(.oneCmt, nlmixr2data::theo_sd, est = "mfocei", control = .an),
warning = function(w) {
.acc$w <- c(.acc$w, conditionMessage(w))
invokeRestart("muffleWarning")
}
)
.msg <- "\"r,s (full)\" covariance installed instead of the requested \"analytic\""
expect_identical(sum(grepl(.msg, c(.acc$w, .mfa$runInfo), fixed = TRUE)), 1L)
expect_identical(.mfa$covMethod, "r,s (full)")
expect_lt(.maxRel(.seOf(.mfa), .seOf(.ref)), 1e-6)
})
test_that("vae and emvi report the covariance of their likelihood's marginal at their estimates", {
skip_on_cran()
# Their output step evaluates the FOCE objective at their own ETAs; the covariance
# comes after it, with the interaction of their `likelihood` (FOCEI) and the ETAs
# optimized from theirs at every finite-difference leg. It held the encoder or
# variational means fixed, with interaction = 0.
.refOf <- function(fit) {
.ctl <- fit$foceiControl
.ctl$maxInnerIterations <- 1000L
.ctl$etaMat <- fit$etaMat
.ctl$calcTables <- FALSE
suppressMessages(suppressWarnings(nlmixr2(fit$finalUi, nlmixr2data::theo_sd, est = "focei", control = .ctl)))
}
.fits <- list(
vae = vaeControl(
itersBurnIn = 8L,
iters = 16L,
klWarmup = 4L,
gammaIter = 12L,
covariateSelection = FALSE,
print = 0L,
covMethod = "r",
seed = 1L
),
emvi = emviControl(iters = 60L, print = 0L, covMethod = "r", seed = 7L)
)
for (.est in names(.fits)) {
.fit <- suppressMessages(suppressWarnings(nlmixr2(
.oneCmt,
nlmixr2data::theo_sd,
est = .est,
control = .fits[[.est]]
)))
# the fit's FOCEi control carries its likelihood's interaction; the output step's
# control (in finalUi) evaluated FOCE
expect_identical(.fit$foceiControl$interaction, 1L, label = .est)
.ref <- .refOf(.fit)
expect_identical(.covFdType(.fit$covMethod), "r", label = .est)
expect_identical(.fit$covMethod, .ref$covMethod, label = .est)
expect_setequal(names(.seOf(.fit)), names(.seOf(.ref)))
expect_lt(.maxRel(.seOf(.fit), .seOf(.ref)), 1e-6, label = .est)
# the method's own parameter table is kept, its SEs taken from the installed matrix
.pf <- .fit$parFixedDf
.th <- c("tka", "tcl", "tv", "add.sd")
expect_setequal(rownames(.pf), .th)
expect_equal(unname(.pf[.th, "SE"]), unname(.seOf(.fit)[.th]), tolerance = 1e-12, label = .est)
}
})
})
test_that("a vae or vi FOCEi covariance that fails leaves the fit without one, with a warning", {
# the method's estimates are done by then, so neither a failed recompute nor a
# failed install may abort the fit
.e <- new.env(parent = emptyenv())
local_mocked_bindings(
.setCovEnv = function(fit) .e,
.foceiRecomputeCov = function(...) stop("no solve"),
.package = "nlmixr2est"
)
expect_warning(
.r <- .foceiInstallOwnEtaCov(.e, foceiControl()),
"FOCEi covariance not computed (no solve)",
fixed = TRUE
)
expect_false(.r)
local_mocked_bindings(
.foceiRecomputeCov = function(...) list(cov = diag(2), covMethod = "r", what = "r", extras = list()),
.covInstall = function(...) stop("no table"),
.package = "nlmixr2est"
)
expect_warning(
.r <- .foceiInstallOwnEtaCov(.e, foceiControl()),
"FOCEi covariance not installed (no table)",
fixed = TRUE
)
expect_false(.r)
expect_false(exists("cov", envir = .e, inherits = FALSE))
})
Any scripts or data that you put into this service are public.
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.