Nothing
testthat::local_edition(3)
perturb_censoring_hazard <- function(object, hazard_row, amount) {
out <- object
selected <- object$hazard.table[hazard_row, , drop = FALSE]
table_row <- which(
out$table$stratum == selected$stratum &
out$table$time == selected$time
)
stopifnot(length(table_row) == 1L)
out$table$hazard[table_row] <- out$table$hazard[table_row] + amount
stratum_rows <- which(out$table$stratum == selected$stratum)
right <- cumprod(1 - out$table$hazard[stratum_rows])
out$table$survival.right[stratum_rows] <- right
out$table$survival.left[stratum_rows] <- c(1, head(right, -1L))
if ("survival.right.raw" %in% names(out$table)) {
out$table$survival.right.raw[stratum_rows] <- right
out$table$survival.left.raw[stratum_rows] <- c(1, head(right, -1L))
truncation <- out$prob.truncation
out$table$survival.right.used[stratum_rows] <- if (is.null(truncation)) {
right
} else {
pmax(right, truncation)
}
out$table$survival.left.used[stratum_rows] <- if (is.null(truncation)) {
c(1, head(right, -1L))
} else {
pmax(c(1, head(right, -1L)), truncation)
}
}
out$hazard.table <- out$table[out$table$n.censor > 0, , drop = FALSE]
out$minimum.survival <- min(out$table$survival.right)
out
}
closed_form_example <- function() {
make_cell <- function(group, stratum, status) {
data.frame(
time = seq_along(status),
status = status,
group = factor(rep(group, length(status)), levels = c("A", "B")),
stratum = stratum
)
}
do.call(rbind, list(
make_cell("A", "X", c(2L, 0L, 1L, 0L, 1L, 2L, 0L, 1L)),
make_cell("A", "Y", c(0L, 2L, 1L, 0L, 2L, 1L, 0L, 1L)),
make_cell("B", "X", c(2L, 0L, 0L, 1L, 2L, 1L, 0L, 1L)),
make_cell("B", "Y", c(0L, 2L, 0L, 1L, 1L, 0L, 2L, 1L))
))
}
# Direct transcription of Scheike et al. (2023), Section 6.1 and p. 2487.
# It deliberately reconstructs Lambda1 from the working CIF and does not use
# build_closed_form_augmentation() or its stored H process.
paper_augmentation_reference <- function(
base, working, time, status, x, exposure,
strata.censor, strata.competing.risk, weights
) {
event_time <- base$event.time
working_cell <- cifmodeling:::ciftest_working_cell(
exposure,
strata.competing.risk
)
cell <- cifmodeling:::ciftest_augmentation_cell(
exposure,
strata.competing.risk,
strata.censor
)
cells <- unique(data.frame(
cell = cell,
working.cell = working_cell,
censor.stratum = as.character(strata.censor),
stringsAsFactors = FALSE
))
censor_label <- as.character(strata.censor)
p <- ncol(x)
h_process <- vector("list", nrow(cells))
names(h_process) <- cells$cell
for (k in seq_len(nrow(cells))) {
level <- cells$cell[k]
member <- which(cell == level & weights > 0)
tab <- working$table[
working$table$cell == cells$working.cell[k],
,
drop = FALSE
]
matched <- match(event_time, tab$time)
present <- !is.na(matched)
d_lambda1 <- numeric(length(event_time))
d_lambda1[present] <-
log1p(-tab$cif1.left[matched[present]]) -
log1p(-tab$cif1.right[matched[present]])
g_left <- cifmodeling:::predict_censoring_km(
base$censoring,
event_time,
rep.int(cells$censor.stratum[k], length(event_time)),
side = "left"
)
x_cell <- x[member[1L], ]
integrand <- sweep(base$xbar, 2L, x_cell,
function(mean, value) value - mean)
integrand <- integrand * (base$fh.weight * g_left * d_lambda1)
h_process[[level]] <- apply(
integrand,
2L,
function(column) rev(cumsum(rev(column)))
) |>
matrix(nrow = length(event_time), ncol = p)
}
iid <- matrix(0, nrow(x), p)
for (k in seq_len(nrow(base$censoring$hazard.table))) {
hazard <- base$censoring$hazard.table[k, ]
in_stratum <- censor_label == hazard$stratum
at_risk <- in_stratum & time >= hazard$time
censored <- in_stratum & time == hazard$time & status == 0L
martingale <- weights * (
as.numeric(censored) - hazard$hazard * as.numeric(at_risk)
)
hstar <- matrix(0, nrow(x), p)
relevant <- which(in_stratum)
working_left <- cifmodeling:::predict_working_aj(
working,
rep.int(hazard$time, length(relevant)),
exposure[relevant],
strata.competing.risk[relevant],
side = "left"
)
g_left <- cifmodeling:::predict_censoring_km(
base$censoring, hazard$time, hazard$stratum, side = "left"
)
h_index <- which(event_time >= hazard$time)[1L]
if (!is.na(h_index)) {
for (level in unique(cell[relevant])) {
target <- relevant[cell[relevant] == level]
local <- match(target, relevant)
ratio <- working_left[local, "cif2"] /
(working_left[local, "survival"] * g_left)
ratio[working_left[local, "cif2"] == 0] <- 0
hstar[target, ] <- outer(ratio, h_process[[level]][h_index, ])
}
}
hbar <- colSums(hstar[at_risk, , drop = FALSE] * weights[at_risk]) /
sum(weights[at_risk])
iid <- iid + sweep(hstar, 2L, hbar, "-") * martingale
}
colnames(iid) <- colnames(x)
list(score.iid.augment = iid, h.process = h_process)
}
testthat::test_that("censoring KM retains strata, fractional weights, and limits", {
time <- c(1, 2, 3, 1, 2, 4)
status <- c(2L, 0L, 1L, 0L, 2L, 1L)
stratum <- factor(c("A", "A", "A", "B", "B", "B"))
weight <- c(0.5, 1.5, 2, 1, 2, 1)
fit <- cifmodeling:::estimate_censoring_km(
time, status,
strata = stratum,
weights = weight
)
testthat::expect_s3_class(fit, "ciftest_censoring_km")
testthat::expect_equal(
cifmodeling:::predict_censoring_km(fit, c(2, 1), c("A", "B"), "left"),
c(1, 1),
tolerance = 1e-12
)
testthat::expect_equal(
cifmodeling:::predict_censoring_km(fit, c(2, 1), c("A", "B"), "right"),
c(4 / 7, 3 / 4),
tolerance = 1e-12
)
testthat::expect_equal(
cifmodeling:::predict_censoring_km(fit, c(3, 4), c("A", "B"), "left"),
c(4 / 7, 3 / 4),
tolerance = 1e-12
)
})
testthat::test_that("administrative horizon completion is not a censoring jump", {
time <- c(1, 2, 3, 4, 6, 6)
status <- c(1L, 2L, 0L, 1L, 0L, 0L)
censoring_event <- c(FALSE, FALSE, TRUE, FALSE, FALSE, FALSE)
fit <- cifmodeling:::estimate_censoring_km(
time,
status,
censoring.event = censoring_event
)
testthat::expect_equal(fit$hazard.table$time, 3)
testthat::expect_false(any(fit$hazard.table$time == 6))
testthat::expect_identical(fit$censoring.event, censoring_event)
})
testthat::test_that("AIPWCC includes event-free completion through tau", {
old <- options(cifmodeling.ciftest.engine = "R")
on.exit(options(old), add = TRUE)
df <- data.frame(
time = c(1, 2, 3, 4, 8, 9, 10, 12),
status = c(1L, 2L, 1L, 2L, 0L, 0L, 0L, 0L),
group = factor(c("A", "A", "B", "B", "A", "B", "A", "B"))
)
methods <- data.frame(
method_id = "seed_map",
augmentation = TRUE,
iteration = 0L,
fixed.point.solver = "seed-map",
strata.censor = NA_character_,
strata.competing.risk = NA_character_,
rho = 0,
gamma = 0,
stringsAsFactors = FALSE
)
fit <- cifmodeling:::ciftest_batch_internal(
Event(time, status) ~ group,
data = df,
methods = methods,
tau = 6
)[[1L]]
components <- fit$diagnostics$iteration.components
testthat::expect_true(any(abs(components$horizon.completion) > 0))
testthat::expect_equal(
components$event + components$censor.past +
components$censor.working.aj,
fit$score.iid,
tolerance = 1e-12
)
testthat::expect_false(any(
fit$diagnostics$censoring.km$hazard.table$time == 6
))
})
testthat::test_that("working AJ retains A-by-strata cells and predictable limits", {
single <- cifmodeling:::estimate_working_aj(
t = 1:4,
epsilon = c(1L, 2L, 0L, 1L),
exposure = rep("A", 4),
strata = rep("X", 4)
)
testthat::expect_equal(
single$table$survival.right,
c(3 / 4, 1 / 2, 1 / 2, 0),
tolerance = 1e-12
)
testthat::expect_equal(
single$table$d.cif2,
pmax(0, single$table$cif2.right - single$table$cif2.left),
tolerance = 0
)
testthat::expect_equal(single$table$cif1.right,
c(1 / 4, 1 / 4, 1 / 4, 3 / 4),
tolerance = 1e-12)
testthat::expect_equal(single$table$cif2.right,
c(0, 1 / 4, 1 / 4, 1 / 4),
tolerance = 1e-12)
testthat::expect_equal(
single$table$d.lambda1[c(1, 4)],
c(-log(3 / 4), log(3)),
tolerance = 1e-12
)
testthat::expect_equal(
single$table$d.lambda1,
diff(c(0, -log1p(-single$table$cif1.right))),
tolerance = 1e-12
)
testthat::expect_equal(
cifmodeling:::predict_working_aj(single, 2, "A", "X", "left"),
matrix(c(3 / 4, 1 / 4, 0), nrow = 1,
dimnames = list(NULL, c("survival", "cif1", "cif2"))),
tolerance = 1e-12
)
df <- closed_form_example()
stratified <- cifmodeling:::estimate_working_aj(
df$time, df$status, df$group, df$stratum
)
testthat::expect_identical(nrow(stratified$cells), 4L)
testthat::expect_setequal(stratified$cells$exposure, c("A", "B"))
testthat::expect_setequal(stratified$cells$stratum, c("X", "Y"))
testthat::expect_lt(
max(abs(with(stratified$table,
survival.right + cif1.right + cif2.right - 1))),
1e-12
)
})
testthat::test_that("Fine-Gray working hazard rejects a terminal unit CIF", {
testthat::expect_error(
cifmodeling:::estimate_working_aj(
t = 1:3,
epsilon = c(0L, 0L, 1L),
exposure = rep("A", 3)
),
"subdistribution-hazard positivity"
)
})
testthat::test_that("FH weights remain aligned for mixed-width decimal times", {
df <- data.frame(
time = c(0.25, 2.5, 12.75, 103.125, 0.5, 4.75, 15.5, 120.25),
status = c(2L, 0L, 1L, 1L, 0L, 2L, 1L, 1L),
group = factor(rep(c("A", "B"), each = 4))
)
x <- stats::model.matrix(~ group, df)[, -1L, drop = FALSE]
event_time <- sort(unique(df$time[df$status == 1L]))
supplied <- seq_along(event_time) / 10
fit <- cifmodeling:::build_fg_score_iid(
df$time, df$status, x,
fh.weight = supplied
)
automatic <- cifmodeling:::build_fg_score_iid(
df$time, df$status, x,
rho = 0.5,
gamma = 0.5
)
testthat::expect_equal(fit$event.time, event_time)
testthat::expect_equal(fit$fh.weight, supplied)
testthat::expect_length(automatic$fh.weight, length(event_time))
testthat::expect_true(all(is.finite(automatic$fh.weight)))
})
testthat::test_that("Fine-Gray score iid has an exact matrix decomposition", {
df <- data.frame(
time = 1:12,
status = c(2L, 0L, 1L, 1L, 2L, 0L, 1L, 2L, 1L, 0L, 1L, 2L),
group = factor(rep(c("A", "B"), 6))
)
x <- stats::model.matrix(~ group, df)[, -1L, drop = FALSE]
colnames(x) <- "groupB"
fit <- cifmodeling:::build_fg_score_iid(
df$time, df$status, x,
rho = 0.25,
gamma = 0.5
)
testthat::expect_identical(dim(fit$score.iid), c(nrow(df), 1L))
testthat::expect_equal(colSums(fit$score.iid.base), fit$score, tolerance = 1e-12)
testthat::expect_equal(fit$score, fit$event.score, tolerance = 1e-12)
testthat::expect_equal(
colSums(fit$score.iid.censor),
stats::setNames(0, colnames(fit$score.iid.censor)),
tolerance = 1e-12
)
testthat::expect_true(any(abs(fit$score.iid.censor) > 1e-8))
testthat::expect_lt(fit$diagnostics$score.decomposition.error, 1e-12)
testthat::expect_lt(fit$diagnostics$censor.centering.error, 1e-12)
})
testthat::test_that("censoring-score derivative matches finite differences", {
df <- data.frame(
time = 1:12,
status = c(2L, 0L, 1L, 1L, 2L, 0L, 1L, 2L, 1L, 0L, 1L, 2L),
group = factor(rep(c("A", "B"), 6))
)
x <- stats::model.matrix(~ group, df)[, -1L, drop = FALSE]
base <- cifmodeling:::build_fg_score_iid(df$time, df$status, x)
step <- 1e-6
for (k in seq_len(nrow(base$censoring$hazard.table))) {
plus <- cifmodeling:::build_fg_score_iid(
df$time, df$status, x,
censoring = perturb_censoring_hazard(base$censoring, k, step)
)
minus <- cifmodeling:::build_fg_score_iid(
df$time, df$status, x,
censoring = perturb_censoring_hazard(base$censoring, k, -step)
)
numerical <- (plus$event.score - minus$event.score) / (2 * step)
testthat::expect_equal(
unname(base$censor.derivative[k, ]),
unname(numerical),
tolerance = 2e-7,
info = paste("censoring hazard row", k)
)
}
})
testthat::test_that("censoring contribution is zero without competing events", {
df <- data.frame(
time = 1:10,
status = c(1L, 0L, 1L, 0L, 1L, 0L, 1L, 0L, 1L, 0L),
group = factor(rep(c("A", "B"), 5))
)
x <- stats::model.matrix(~ group, df)[, -1L, drop = FALSE]
fit <- cifmodeling:::build_fg_score_iid(df$time, df$status, x)
testthat::expect_equal(fit$score.iid.censor, fit$score.iid.censor * 0)
testthat::expect_equal(fit$censor.derivative, fit$censor.derivative * 0)
})
testthat::test_that("standard Gray exposes diagnostic iid without changing its variance", {
df <- data.frame(
time = c(1, 2, 2, 3, 4, 5, 5, 6, 7, 8, 8, 9),
status = c(1L, 0L, 2L, 1L, 2L, 0L, 1L, 1L, 0L, 2L, 1L, 0L),
group = factor(c("A", "A", "B", "B", "A", "B",
"A", "B", "A", "B", "A", "B"))
)
fit <- ciftest(
Event(time, status) ~ group,
df,
augmentation = FALSE,
rho = 1
)
testthat::expect_true(fit$diagnostics$score.iid.available)
testthat::expect_equal(colSums(fit$score.iid.base), fit$score, tolerance = 1e-12)
testthat::expect_equal(
colSums(fit$score.iid.censor),
stats::setNames(0, colnames(fit$score.iid.censor)),
tolerance = 1e-12
)
testthat::expect_equal(fit$score.iid.augment, fit$score.iid.augment * 0)
testthat::expect_identical(fit$variance.method, "gray")
testthat::expect_match(fit$diagnostics$score.iid.variance.role, "diagnostic only")
process <- fit$diagnostics$fh.weight.process
testthat::expect_s3_class(process, "data.frame")
testthat::expect_identical(
names(process), c("time", "weight", "stratum", "source")
)
testthat::expect_identical(
unique(process$source), "gray-pooled-subdistribution-left"
)
testthat::expect_true(all(process$time %in% df$time[df$status == 1L]))
})
testthat::test_that("truncated censoring-score derivative matches finite differences", {
df <- data.frame(
time = 1:12,
status = c(2L, 0L, 1L, 1L, 2L, 0L, 1L, 2L, 1L, 0L, 1L, 2L),
group = factor(rep(c("A", "B"), 6))
)
x <- stats::model.matrix(~ group, df)[, -1L, drop = FALSE]
censoring <- cifmodeling:::estimate_censoring_km(
df$time, df$status, prob.truncation = 0.8
)
base <- cifmodeling:::build_fg_score_iid(
df$time, df$status, x,
censoring = censoring, prob.truncation = 0.8
)
step <- 1e-6
for (k in seq_len(nrow(base$censoring$hazard.table))) {
plus <- cifmodeling:::build_fg_score_iid(
df$time, df$status, x,
censoring = perturb_censoring_hazard(base$censoring, k, step),
prob.truncation = 0.8
)
minus <- cifmodeling:::build_fg_score_iid(
df$time, df$status, x,
censoring = perturb_censoring_hazard(base$censoring, k, -step),
prob.truncation = 0.8
)
numerical <- (plus$event.score - minus$event.score) / (2 * step)
testthat::expect_equal(
unname(base$censor.derivative[k, ]),
unname(numerical),
tolerance = 2e-7,
info = paste("truncated censoring hazard row", k)
)
}
})
testthat::test_that("closed-form augmentation has a score-scale iid decomposition", {
df <- closed_form_example()
fit <- ciftest(
Event(time, status) ~ group,
data = df,
strata.censor = "stratum",
strata.competing.risk = "stratum",
augmentation = TRUE
)
testthat::expect_identical(fit$method,
"Closed-form augmented Fine-Gray score test")
testthat::expect_identical(fit$variance.method, "score-iid")
testthat::expect_identical(dim(fit$score.iid.augment), c(nrow(df), 1L))
testthat::expect_true(any(abs(fit$score.iid.augment) > 1e-8))
testthat::expect_equal(
fit$score,
colSums(fit$score.iid.base) + colSums(fit$score.iid.censor) +
colSums(fit$score.iid.augment),
tolerance = 1e-12
)
testthat::expect_equal(fit$score.iid,
fit$score.iid.base + fit$score.iid.censor +
fit$score.iid.augment,
tolerance = 1e-12)
testthat::expect_equal(fit$vcov.score, crossprod(fit$score.iid),
tolerance = 1e-12)
testthat::expect_lt(fit$diagnostics$augmentation.centering.error, 1e-12)
testthat::expect_s3_class(fit$diagnostics$working.aj,
"ciftest_working_aj")
process <- fit$diagnostics$fh.weight.process
expected <- cifmodeling:::ciftest_null_fh_weight(
df$time, df$status, 1L, 2L, rep.int(1, nrow(df)), 0, 0
)
testthat::expect_equal(process$time, sort(unique(df$time[df$status == 1L])))
testthat::expect_equal(process$weight, expected)
testthat::expect_identical(unique(process$source), "pooled-aj-left")
# Independent raw martingale sum. Risk-set centering leaves its column sum
# unchanged because every fitted censoring-martingale increment sums to zero.
working <- fit$diagnostics$working.aj
censoring <- fit$diagnostics$censoring.km
event_time <- sort(unique(df$time[df$status == 1L]))
cell <- cifmodeling:::ciftest_augmentation_cell(
df$group,
df$stratum,
df$stratum
)
raw <- 0
for (k in seq_len(nrow(censoring$hazard.table))) {
row <- censoring$hazard.table[k, ]
in_stratum <- df$stratum == row$stratum
at_risk <- in_stratum & df$time >= row$time
censored <- in_stratum & df$time == row$time & df$status == 0L
martingale <- as.numeric(censored) - row$hazard * as.numeric(at_risk)
prediction <- cifmodeling:::predict_working_aj(
working,
rep(row$time, nrow(df)),
df$group,
df$stratum,
"left"
)
event_index <- which(event_time >= row$time)[1L]
if (!is.na(event_index)) {
h <- vapply(cell, function(level) {
fit$diagnostics$h.process[[level]][event_index, 1L]
}, numeric(1))
g <- cifmodeling:::predict_censoring_km(
censoring, row$time, row$stratum, "left"
)
raw <- raw + sum(
martingale * h * prediction[, "cif2"] /
(prediction[, "survival"] * g),
na.rm = TRUE
)
}
}
testthat::expect_equal(unname(colSums(fit$score.iid.augment)), raw,
tolerance = 1e-12)
})
testthat::test_that("closed-form augmentation matches the paper equation", {
df <- closed_form_example()
x <- stats::model.matrix(~ group, df)[, -1L, drop = FALSE]
colnames(x) <- "groupB"
weights <- rep.int(1, nrow(df))
base <- cifmodeling:::build_fg_score_iid(
df$time, df$status, x,
strata = df$stratum,
weights = weights,
rho = 0.5,
gamma = 0.25
)
working <- cifmodeling:::estimate_working_aj(
df$time, df$status, df$group, df$stratum, weights
)
actual <- cifmodeling:::build_closed_form_augmentation(
base, working, df$time, df$status, x, df$group,
df$stratum, df$stratum, weights
)
reference <- paper_augmentation_reference(
base, working, df$time, df$status, x, df$group,
df$stratum, df$stratum, weights
)
testthat::expect_equal(
actual$score.iid.augment,
reference$score.iid.augment,
tolerance = 1e-12
)
testthat::expect_equal(
unname(actual$score),
unname(colSums(reference$score.iid.augment)),
tolerance = 1e-12
)
for (level in names(actual$h.process)) {
testthat::expect_equal(
unname(actual$h.process[[level]]),
unname(reference$h.process[[level]]),
tolerance = 1e-12,
info = level
)
}
})
testthat::test_that("censoring and competing-risk nuisance strata are independent", {
df <- closed_form_example()
df$censor.stratum <- factor(rep(c("C1", "C2"), each = 4L, times = 4L))
x <- stats::model.matrix(~ group, df)[, -1L, drop = FALSE]
colnames(x) <- "groupB"
weights <- rep.int(1, nrow(df))
base <- cifmodeling:::build_fg_score_iid(
df$time,
df$status,
x,
strata = df$censor.stratum,
weights = weights,
rho = 0.5,
gamma = 0.25
)
working <- cifmodeling:::estimate_working_aj(
df$time,
df$status,
df$group,
df$stratum,
weights
)
actual <- cifmodeling:::build_closed_form_augmentation(
base,
working,
df$time,
df$status,
x,
df$group,
df$censor.stratum,
df$stratum,
weights
)
reference <- paper_augmentation_reference(
base,
working,
df$time,
df$status,
x,
df$group,
df$censor.stratum,
df$stratum,
weights
)
testthat::expect_equal(
actual$score.iid.augment,
reference$score.iid.augment,
tolerance = 1e-12
)
testthat::expect_setequal(
actual$augmentation.cells$censor.stratum,
levels(df$censor.stratum)
)
testthat::expect_setequal(
actual$augmentation.cells$competing.risk.stratum,
unique(df$stratum)
)
fit <- ciftest(
Event(time, status) ~ group,
data = df,
strata.censor = "censor.stratum",
strata.competing.risk = "stratum",
rho = 0.5,
gamma = 0.25,
augmentation = TRUE
)
testthat::expect_identical(fit$strata.censor.info$name, "censor.stratum")
testthat::expect_identical(fit$strata.competing.risk.info$name, "stratum")
testthat::expect_equal(
fit$diagnostics$augmentation.cells,
actual$augmentation.cells
)
testthat::expect_equal(unname(fit$score.iid.augment),
unname(actual$score.iid.augment),
tolerance = 1e-12)
})
testthat::test_that("both nuisance strata participate in complete-case selection", {
df <- closed_form_example()
df$censor.stratum <- factor(rep(c("C1", "C2"), each = 4L, times = 4L))
df$competing.stratum <- factor(df$stratum)
df$censor.stratum[1L] <- NA
df$competing.stratum[10L] <- NA
fit <- ciftest(
Event(time, status) ~ group,
data = df,
strata.censor = "censor.stratum",
strata.competing.risk = "competing.stratum",
augmentation = TRUE
)
testthat::expect_identical(fit$n, nrow(df) - 2L)
testthat::expect_identical(
fit$diagnostics$analysis.row.index,
setdiff(seq_len(nrow(df)), c(1L, 10L))
)
testthat::expect_false(anyNA(fit$strata.censor.info$values))
testthat::expect_false(anyNA(fit$strata.competing.risk.info$values))
})
testthat::test_that("closed-form augmentation vanishes without competing events", {
df <- data.frame(
time = rep(1:6, 2),
status = rep(c(1L, 0L, 1L, 0L, 1L, 0L), 2),
group = factor(rep(c("A", "B"), each = 6))
)
x <- stats::model.matrix(~ group, df)[, -1L, drop = FALSE]
base <- cifmodeling:::build_fg_score_iid(df$time, df$status, x)
working <- cifmodeling:::estimate_working_aj(
df$time, df$status, df$group
)
augment <- cifmodeling:::build_closed_form_augmentation(
base, working, df$time, df$status, x, df$group
)
testthat::expect_equal(augment$score.iid.augment,
augment$score.iid.augment * 0)
testthat::expect_equal(unname(augment$score), 0)
})
testthat::test_that("augmented ciftest records its nontrivial pooled-AJ FH process", {
df <- closed_form_example()
fit <- ciftest(
Event(time, status) ~ group,
data = df,
augmentation = TRUE,
rho = 0.5,
gamma = 0.5
)
process <- fit$diagnostics$fh.weight.process
expected <- cifmodeling:::ciftest_null_fh_weight(
df$time, df$status, 1L, 2L, rep.int(1, nrow(df)), 0.5, 0.5
)
testthat::expect_equal(process$time, sort(unique(df$time[df$status == 1L])))
testthat::expect_equal(process$weight, expected, tolerance = 1e-14)
testthat::expect_identical(unique(process$stratum), "pooled")
testthat::expect_identical(unique(process$source), "pooled-aj-left")
})
testthat::test_that("integer iteration refines the closed-form seed", {
df <- closed_form_example()
augmented <- ciftest(
Event(time, status) ~ group,
data = df,
iteration = 0
)
iterated1 <- ciftest(
Event(time, status) ~ group,
data = df,
iteration = 1
)
iterated2 <- ciftest(
Event(time, status) ~ group,
data = df,
iteration = 2
)
testthat::expect_identical(
augmented$method,
"Closed-form augmented Fine-Gray score test"
)
testthat::expect_identical(
iterated1$method,
"Iterated time-weighted Fine-Gray score test"
)
testthat::expect_identical(iterated1$iteration, 1L)
testthat::expect_identical(iterated2$iterations, 2L)
testthat::expect_identical(dim(iterated2$score.iid), c(nrow(df), 1L))
testthat::expect_equal(
iterated2$vcov.score,
crossprod(iterated2$score.iid),
tolerance = 1e-12
)
testthat::expect_equal(
iterated2$score,
colSums(iterated2$score.iid),
tolerance = 1e-12
)
testthat::expect_lt(
iterated2$fixed.point.residual,
iterated1$fixed.point.residual
)
testthat::expect_equal(
iterated2$score.iid.iterated,
iterated2$score.iid,
tolerance = 1e-12
)
testthat::expect_equal(
iterated2$score.iid.augment,
augmented$score.iid.augment,
tolerance = 1e-12
)
testthat::expect_true(all(is.na(augmented$score.iid.iterated)))
printed <- paste(utils::capture.output(print(iterated2)), collapse = "\n")
testthat::expect_match(
printed, "Iteration: 2 of 2 requested refinements", fixed = TRUE
)
testthat::expect_match(printed, "Fixed-point residual", fixed = TRUE)
})
testthat::test_that("Appendix-E correction vanishes without censoring", {
n <- 40L
df <- data.frame(
time = c(seq_len(n), 100),
status = c(rep(c(1L, 2L, 2L, 1L), n / 4L), 0L),
group = factor(c(rep(c("A", "A", "B", "B"), n / 4L), "A")),
weight = c(rep.int(1, n), 0)
)
augmented <- ciftest(
Event(time, status) ~ group,
data = df,
weights = "weight",
iteration = 0
)
iterated <- ciftest(
Event(time, status) ~ group,
data = df,
weights = "weight",
iteration = 1
)
testthat::expect_equal(iterated$last.increment, 0, tolerance = 1e-12)
testthat::expect_equal(iterated$fixed.point.residual, 0,
tolerance = 1e-12)
testthat::expect_equal(iterated$score, augmented$score,
tolerance = 1e-12)
testthat::expect_equal(iterated$vcov.score, augmented$vcov.score,
tolerance = 1e-12)
})
testthat::test_that("Appendix-E positivity is limited to its active support", {
set.seed(1668883259L)
df <- cifsimulate(
n = 200,
effect = "constant",
shr = 0.3,
rho1 = 0.2,
rho2 = 3,
rate = c(1, 1),
beta1.L = -0.1,
beta2 = c(A = 0, L = 0.3),
tau = 6,
analysis.tau = 6,
effect.rho = 1,
effect.gamma = 1,
grid.width = 0.01,
prob.A = 0.5,
prob.L = 0.5,
censor.rate = 0.719323755452953,
censor.log.hazard = c(A = 0, L = 0)
)
testthat::expect_identical(
as.integer(table(factor(df$status, levels = 0:2))),
c(60L, 17L, 123L)
)
fit <- ciftest(Event(time, status) ~ A, data = df, iteration = 1)
support <- fit$diagnostics$iteration.support
testthat::expect_true(is.finite(fit$p.value))
testthat::expect_gt(support$ignored.tail.censoring.times, 0L)
testthat::expect_gt(support$skipped.zero.future.evaluations, 0L)
testthat::expect_gt(support$minimum.active.working.survival, 0)
working <- cifmodeling:::estimate_working_aj(
df$time, df$status, df$A
)
late_time <- max(df$time[df$status == 1L]) + 0.1
l_process <- cifmodeling:::ciftest_appendix_e_l_process(
working,
late_time,
exposure = "1",
active = TRUE
)
testthat::expect_equal(
l_process$value,
unname(l_process$prediction[, "cif2"] /
l_process$prediction[, "survival"]),
tolerance = 1e-12
)
})
testthat::test_that("weighted iteration uses the same FH direction", {
df <- closed_form_example()
early <- ciftest(
Event(time, status) ~ group,
data = df,
rho = 1,
gamma = 0,
iteration = 2
)
late <- ciftest(
Event(time, status) ~ group,
data = df,
rho = 0,
gamma = 1,
iteration = 2
)
testthat::expect_true(is.finite(early$p.value))
testthat::expect_true(is.finite(late$p.value))
testthat::expect_false(isTRUE(all.equal(early$score, late$score)))
testthat::expect_identical(nrow(early$diagnostics$iteration.history), 2L)
})
testthat::test_that("iterated score is invariant to analysis-row order", {
df <- closed_form_example()
original <- ciftest(
Event(time, status) ~ group,
data = df,
rho = 1,
iteration = 2
)
permutation <- c(32, 1, 24, 9, 17, 4, 28, 13, 20, 7, 31, 2,
25, 10, 18, 5, 29, 14, 21, 8, 30, 3, 26, 11,
19, 6, 27, 12, 16, 15, 23, 22)
permuted <- ciftest(
Event(time, status) ~ group,
data = df[permutation, , drop = FALSE],
rho = 1,
iteration = 2
)
testthat::expect_equal(permuted$score, original$score, tolerance = 1e-12)
testthat::expect_equal(permuted$vcov.score, original$vcov.score,
tolerance = 1e-12)
testthat::expect_equal(
permuted$score.iid[order(permutation), , drop = FALSE],
original$score.iid,
tolerance = 1e-12
)
})
testthat::test_that("Fine-Gray score is invariant to analysis-row order", {
df <- data.frame(
time = 1:12,
status = c(2L, 0L, 1L, 1L, 2L, 0L, 1L, 2L, 1L, 0L, 1L, 2L),
group = factor(rep(c("A", "B"), 6))
)
x <- stats::model.matrix(~ group, df)[, -1L, drop = FALSE]
original <- cifmodeling:::build_fg_score_iid(df$time, df$status, x)
order <- c(12, 1, 8, 3, 10, 5, 2, 11, 7, 4, 9, 6)
permuted <- cifmodeling:::build_fg_score_iid(
df$time[order], df$status[order], x[order, , drop = FALSE]
)
testthat::expect_equal(permuted$score, original$score, tolerance = 1e-12)
testthat::expect_equal(
permuted$score.iid[order(order), , drop = FALSE],
original$score.iid,
tolerance = 1e-12
)
})
testthat::test_that("batch engine reuses nuisance fits and matches scalar ciftest", {
old <- options(cifmodeling.ciftest.engine = "R")
on.exit(options(old), add = TRUE)
df <- closed_form_example()
methods <- data.frame(
method_id = c(
"gray__unweighted", "gray__early",
"pooled__unweighted", "pooled__early",
"L__unweighted", "L__early"
),
augmentation = c(FALSE, FALSE, TRUE, TRUE, TRUE, TRUE),
strata.censor = c(NA, NA, NA, NA, "stratum", "stratum"),
strata.competing.risk = c(NA, NA, NA, NA, "stratum", "stratum"),
rho = c(0, 1, 0, 1, 0, 1),
gamma = 0,
stringsAsFactors = FALSE
)
batch <- cifmodeling:::ciftest_batch_internal(
Event(time, status) ~ group,
data = df,
methods = methods
)
testthat::expect_s3_class(batch, "ciftest_batch")
testthat::expect_identical(names(batch), methods$method_id)
timing <- attr(batch, "timing")
batch_timing <- attr(batch, "batch.timing")
testthat::expect_identical(timing$method_id, methods$method_id)
testthat::expect_true(all(timing$elapsed_seconds >= 0))
testthat::expect_equal(batch_timing$cache_misses, 5L)
testthat::expect_equal(batch_timing$cache_hits, 5L)
for (i in seq_len(nrow(methods))) {
scalar <- ciftest(
Event(time, status) ~ group,
data = df,
augmentation = methods$augmentation[i],
strata.censor = if (is.na(methods$strata.censor[i])) {
NULL
} else methods$strata.censor[i],
strata.competing.risk = if (
is.na(methods$strata.competing.risk[i])
) {
NULL
} else methods$strata.competing.risk[i],
rho = methods$rho[i],
gamma = methods$gamma[i]
)
actual <- batch[[methods$method_id[i]]]
testthat::expect_s3_class(actual, "ciftest")
testthat::expect_equal(actual$score, scalar$score, tolerance = 1e-12)
testthat::expect_equal(actual$vcov.score, scalar$vcov.score,
tolerance = 1e-12)
testthat::expect_equal(actual$score.iid, scalar$score.iid,
tolerance = 1e-12)
testthat::expect_equal(actual$statistic, scalar$statistic,
tolerance = 1e-12)
testthat::expect_equal(actual$p.value, scalar$p.value,
tolerance = 1e-12)
}
})
testthat::test_that("batch engine carries finite iteration counts", {
old <- options(cifmodeling.ciftest.engine = "R")
on.exit(options(old), add = TRUE)
df <- closed_form_example()
methods <- data.frame(
method_id = c("augmented", "iterated_1", "iterated_2"),
augmentation = TRUE,
iteration = 0:2,
strata.censor = NA_character_,
strata.competing.risk = NA_character_,
rho = 0,
gamma = 0,
stringsAsFactors = FALSE
)
batch <- cifmodeling:::ciftest_batch_internal(
Event(time, status) ~ group,
data = df,
methods = methods
)
for (i in seq_len(nrow(methods))) {
scalar <- ciftest(
Event(time, status) ~ group,
data = df,
augmentation = TRUE,
iteration = methods$iteration[i]
)
actual <- batch[[methods$method_id[i]]]
testthat::expect_equal(actual$score.iid, scalar$score.iid,
tolerance = 1e-12)
testthat::expect_equal(actual$p.value, scalar$p.value,
tolerance = 1e-12)
testthat::expect_identical(actual$iterations,
as.integer(methods$iteration[i]))
}
})
testthat::test_that("batch Fine-Gray score-IID method uses its own variance", {
old <- options(cifmodeling.ciftest.engine = "R")
on.exit(options(old), add = TRUE)
df <- closed_form_example()
methods <- data.frame(
method_id = c("fine_gray", "closed_form", "iterated_1"),
augmentation = c(FALSE, TRUE, TRUE),
iteration = c(0L, 0L, 1L),
score.construction = c("fine-gray", "standard", "standard"),
strata.censor = NA_character_,
strata.competing.risk = NA_character_,
rho = 0,
gamma = 0,
stringsAsFactors = FALSE
)
batch <- cifmodeling:::ciftest_batch_internal(
Event(time, status) ~ group,
data = df,
methods = methods
)
fit <- batch$fine_gray
x <- stats::model.matrix(~ group, df)[, -1L, drop = FALSE]
colnames(x) <- "a_B"
reference <- cifmodeling:::build_fg_score_iid(
df$time, df$status, x
)
testthat::expect_s3_class(fit, "ciftest")
testthat::expect_identical(fit$method, "Fine-Gray score test")
testthat::expect_identical(fit$variance.method, "score-iid")
testthat::expect_false(fit$augmentation)
testthat::expect_equal(fit$score, reference$score, tolerance = 1e-12)
testthat::expect_equal(fit$score.iid, reference$score.iid,
tolerance = 1e-12)
testthat::expect_equal(fit$vcov.score, crossprod(reference$score.iid),
tolerance = 1e-12)
testthat::expect_false(isTRUE(all.equal(
fit$vcov.score, batch$closed_form$vcov.score
)))
})
testthat::test_that("direct fixed-point batch agrees with converged iteration", {
old <- options(cifmodeling.ciftest.engine = "R")
on.exit(options(old), add = TRUE)
df <- closed_form_example()
methods <- data.frame(
method_id = c("finite_10", "direct_0", "direct_early"),
augmentation = TRUE,
iteration = c(10L, 0L, 0L),
fixed.point.solver = c("finite", "direct", "direct"),
strata.censor = NA_character_,
strata.competing.risk = NA_character_,
rho = c(0, 0, 5),
gamma = 0,
stringsAsFactors = FALSE
)
batch <- cifmodeling:::ciftest_batch_internal(
Event(time, status) ~ group,
data = df,
methods = methods
)
finite <- batch$finite_10
direct <- batch$direct_0
early <- batch$direct_early
testthat::expect_s3_class(direct, "ciftest")
testthat::expect_identical(
direct$method,
"Direct fixed-point time-weighted Fine-Gray score test"
)
testthat::expect_identical(direct$iterations, NA_integer_)
testthat::expect_true(direct$converged)
testthat::expect_lt(direct$fixed.point.residual, 1e-10)
testthat::expect_equal(direct$score.iid, finite$score.iid,
tolerance = 1e-7)
testthat::expect_equal(direct$p.value, finite$p.value,
tolerance = 1e-8)
testthat::expect_true(is.finite(
direct$diagnostics$iteration.support$operator.spectral.radius
))
testthat::expect_true(
direct$diagnostics$iteration.support$operator.contractive
)
testthat::expect_true(is.finite(
direct$diagnostics$iteration.support$system.reciprocal.condition
))
testthat::expect_true(is.finite(early$p.value))
testthat::expect_identical(
early$diagnostics$iteration.support$state.dimension,
direct$diagnostics$iteration.support$state.dimension
)
})
testthat::test_that("batch exposes the Appendix-E seed-map diagnostic", {
old <- options(cifmodeling.ciftest.engine = "R")
on.exit(options(old), add = TRUE)
n <- 40L
df <- data.frame(
time = c(seq_len(n), 100),
status = c(rep(c(1L, 2L, 2L, 1L), n / 4L), 0L),
group = factor(c(rep(c("A", "A", "B", "B"), n / 4L), "A")),
weight = c(rep.int(1, n), 0)
)
methods <- data.frame(
method_id = c("closed", "seed_map"),
augmentation = TRUE,
iteration = 0L,
fixed.point.solver = c("finite", "seed-map"),
strata.censor = NA_character_,
strata.competing.risk = NA_character_,
rho = 0,
gamma = 0,
stringsAsFactors = FALSE
)
batch <- cifmodeling:::ciftest_batch_internal(
Event(time, status) ~ group,
data = df,
weights = "weight",
methods = methods
)
seed_map <- batch$seed_map
testthat::expect_s3_class(seed_map, "ciftest")
testthat::expect_identical(
seed_map$method,
"AIPWCC seed-map diagnostic score test"
)
testthat::expect_identical(seed_map$iterations, 0L)
testthat::expect_identical(
seed_map$diagnostics$iteration.support$solver,
"seed-map"
)
testthat::expect_equal(
seed_map$diagnostics$fixed.point$value,
seed_map$diagnostics$fixed.point$seed,
tolerance = 0
)
testthat::expect_equal(seed_map$score, batch$closed$score,
tolerance = 1e-12)
testthat::expect_equal(seed_map$vcov.score, batch$closed$vcov.score,
tolerance = 1e-12)
components <- seed_map$diagnostics$iteration.components
testthat::expect_named(
components,
c(
"event", "censor.past", "censor.working.aj", "censor.total",
"horizon.completion"
)
)
testthat::expect_equal(
components$event + components$censor.past +
components$censor.working.aj,
seed_map$score.iid,
tolerance = 1e-12
)
testthat::expect_equal(
components$censor.past + components$censor.working.aj,
components$censor.total,
tolerance = 0
)
})
testthat::test_that("finite and direct iterates are anchored at closed form", {
old <- options(cifmodeling.ciftest.engine = "R")
on.exit(options(old), add = TRUE)
df <- closed_form_example()
methods <- data.frame(
method_id = c("closed", "seed_map", "iterated_1", "direct"),
augmentation = TRUE,
iteration = c(0L, 0L, 1L, 0L),
fixed.point.solver = c("finite", "seed-map", "finite", "direct"),
strata.censor = NA_character_,
strata.competing.risk = NA_character_,
rho = 0,
gamma = 0,
stringsAsFactors = FALSE
)
batch <- cifmodeling:::ciftest_batch_internal(
Event(time, status) ~ group,
data = df,
methods = methods
)
testthat::expect_false(
batch$seed_map$diagnostics$iteration.anchor$applied
)
for (method in c("iterated_1", "direct")) {
fit <- batch[[method]]
anchor <- fit$diagnostics$iteration.anchor
testthat::expect_true(anchor$applied)
testthat::expect_identical(
anchor$construction,
"closed-form + AIPWCC(value) - AIPWCC(seed)"
)
testthat::expect_equal(
anchor$seed.aipwcc.score,
batch$seed_map$score,
tolerance = 1e-12
)
testthat::expect_equal(
anchor$score.adjustment,
batch$closed$score - batch$seed_map$score,
tolerance = 1e-12
)
testthat::expect_equal(
fit$score,
anchor$raw.aipwcc.score + anchor$score.adjustment,
tolerance = 1e-12
)
testthat::expect_equal(anchor$identity.error, 0, tolerance = 0)
}
})
testthat::test_that("AIPWCC anchoring preserves the zeroth step", {
closed <- matrix(c(1, 2, 3, 4), ncol = 2L)
seed <- matrix(c(4, 3, 2, 1), ncol = 2L)
value <- seed + matrix(c(0.1, -0.2, 0.3, -0.4), ncol = 2L)
anchored <- cifmodeling:::ciftest_anchor_aipwcc_iid(
closed, value, seed
)
zeroth <- cifmodeling:::ciftest_anchor_aipwcc_iid(
closed, seed, seed
)
testthat::expect_equal(zeroth$score.iid, closed, tolerance = 0)
testthat::expect_equal(
anchored$score.iid,
closed + value - seed,
tolerance = 1e-15
)
testthat::expect_equal(anchored$identity.error, 0, tolerance = 0)
testthat::expect_error(
cifmodeling:::ciftest_anchor_aipwcc_iid(
closed, value[-1L, , drop = FALSE], seed
),
"must conform"
)
})
testthat::test_that("direct convergence requires a contraction", {
testthat::expect_true(cifmodeling:::ciftest_direct_converged(
residual = 1e-12, tolerance = 1e-8, spectral.radius = 0.9
))
testthat::expect_false(cifmodeling:::ciftest_direct_converged(
residual = 1e-12, tolerance = 1e-8, spectral.radius = 1
))
testthat::expect_false(cifmodeling:::ciftest_direct_converged(
residual = 1e-12, tolerance = 1e-8, spectral.radius = 1.2
))
testthat::expect_false(cifmodeling:::ciftest_direct_converged(
residual = 1e-4, tolerance = 1e-8, spectral.radius = 0.5
))
})
testthat::test_that("Appendix-E operator is linear", {
df <- closed_form_example()
x <- stats::model.matrix(~ group, df)[, -1L, drop = FALSE]
base <- cifmodeling:::build_fg_score_iid(df$time, df$status, x)
working <- cifmodeling:::estimate_working_aj(
df$time, df$status, df$group
)
setup <- cifmodeling:::ciftest_iteration_setup(
base, working, df$time, df$status, x, df$group
)
operator <- cifmodeling:::ciftest_appendix_e_operator(
setup, base, working
)
state_dimension <- operator$state.dimension
v <- array(seq_len(state_dimension) / state_dimension,
dim = c(length(setup$working.cell), setup$event.count, 1L))
zero <- array(0, dim = dim(v))
mapped <- cifmodeling:::ciftest_appendix_e_map(
v, zero, base, working,
setup$working.cell, setup$exposure.by.cell, setup$subject.cell,
setup$risk.weight
)
testthat::expect_equal(
as.numeric(mapped),
as.numeric(operator$K %*% as.numeric(v)),
tolerance = 1e-12
)
})
testthat::test_that("batch engine applies common nuisance complete cases", {
df <- closed_form_example()
df$stratum[1L] <- NA
methods <- data.frame(
method_id = "L",
augmentation = TRUE,
strata.censor = "stratum",
strata.competing.risk = "stratum",
rho = 0,
gamma = 0,
stringsAsFactors = FALSE
)
fit <- cifmodeling:::ciftest_batch_internal(
Event(time, status) ~ group,
data = df,
methods = methods
)
testthat::expect_equal(nobs(fit$L), nrow(df) - 1L)
testthat::expect_false(fit$L$diagnostics$analysis.included[1L])
})
testthat::test_that("Rcpp score and augmentation kernels match R reference", {
namespace <- asNamespace("cifmodeling")
testthat::skip_if_not(exists(
"_cifmodeling_ciftest_fg_iid_kernel_cpp",
envir = namespace,
inherits = FALSE
))
testthat::skip_if_not(exists(
"_cifmodeling_ciftest_augmentation_iid_kernel_cpp",
envir = namespace,
inherits = FALSE
))
old <- options(cifmodeling.ciftest.engine = "R")
on.exit(options(old), add = TRUE)
df <- closed_form_example()
x <- stats::model.matrix(~ group, df)[, -1L, drop = FALSE]
colnames(x) <- "groupB"
base_r <- cifmodeling:::build_fg_score_iid(
df$time, df$status, x,
strata = df$stratum,
rho = 0.5,
gamma = 0.25
)
working <- cifmodeling:::estimate_working_aj(
df$time, df$status, df$group, df$stratum
)
augment_r <- cifmodeling:::build_closed_form_augmentation(
base_r, working, df$time, df$status, x, df$group,
df$stratum, df$stratum
)
options(cifmodeling.ciftest.engine = "Rcpp")
base_cpp <- cifmodeling:::build_fg_score_iid(
df$time, df$status, x,
strata = df$stratum,
rho = 0.5,
gamma = 0.25
)
augment_cpp <- cifmodeling:::build_closed_form_augmentation(
base_cpp, working, df$time, df$status, x, df$group,
df$stratum, df$stratum
)
fields <- c(
"score", "event.score", "score.iid", "score.iid.base",
"score.iid.censor", "xbar", "risk.total", "event.count",
"censor.derivative"
)
for (field in fields) {
testthat::expect_equal(
base_cpp[[field]], base_r[[field]], tolerance = 1e-10,
info = field
)
}
testthat::expect_equal(
augment_cpp$score.iid.augment,
augment_r$score.iid.augment,
tolerance = 1e-10
)
testthat::expect_equal(augment_cpp$score, augment_r$score,
tolerance = 1e-10)
testthat::expect_identical(base_cpp$diagnostics$engine, "Rcpp-prefix")
testthat::expect_identical(augment_cpp$diagnostics$engine, "Rcpp-prefix")
})
testthat::test_that("multiweight Rcpp batch matches scalar Rcpp fits", {
namespace <- asNamespace("cifmodeling")
symbols <- c(
"_cifmodeling_ciftest_fg_iid_multi_kernel_cpp",
"_cifmodeling_ciftest_augmentation_iid_multi_kernel_cpp"
)
for (symbol in symbols) {
testthat::skip_if_not(exists(
symbol, envir = namespace, inherits = FALSE
))
}
old <- options(cifmodeling.ciftest.engine = "Rcpp")
on.exit(options(old), add = TRUE)
df <- closed_form_example()
methods <- data.frame(
method_id = c("pooled_0", "pooled_1", "L_0", "L_1"),
augmentation = TRUE,
strata.censor = c(NA, NA, "stratum", "stratum"),
strata.competing.risk = c(NA, NA, "stratum", "stratum"),
rho = c(0, 1, 0, 1),
gamma = 0,
stringsAsFactors = FALSE
)
batch <- cifmodeling:::ciftest_batch_internal(
Event(time, status) ~ group, df, methods
)
for (i in seq_len(nrow(methods))) {
scalar <- ciftest(
Event(time, status) ~ group,
data = df,
augmentation = TRUE,
strata.censor = if (is.na(methods$strata.censor[i])) {
NULL
} else methods$strata.censor[i],
strata.competing.risk = if (
is.na(methods$strata.competing.risk[i])
) {
NULL
} else methods$strata.competing.risk[i],
rho = methods$rho[i],
gamma = methods$gamma[i]
)
actual <- batch[[methods$method_id[i]]]
testthat::expect_equal(actual$score.iid, scalar$score.iid,
tolerance = 1e-10)
testthat::expect_equal(actual$vcov.score, scalar$vcov.score,
tolerance = 1e-8)
testthat::expect_equal(actual$p.value, scalar$p.value,
tolerance = 1e-8)
testthat::expect_identical(
actual$diagnostics$score.engine, "Rcpp-prefix-multi"
)
testthat::expect_identical(
actual$diagnostics$augmentation.engine, "Rcpp-prefix-multi"
)
}
timing <- attr(batch, "batch.timing")
testthat::expect_true(timing$elapsed_multiweight_precompute_seconds >= 0)
testthat::expect_length(timing$multiweight_errors, 0L)
})
testthat::test_that("Fine-Gray prefix kernels match legacy with ties and weights", {
namespace <- asNamespace("cifmodeling")
symbols <- c(
"_cifmodeling_ciftest_fg_iid_prefix_kernel_cpp",
"_cifmodeling_ciftest_fg_iid_prefix_multi_kernel_cpp"
)
for (symbol in symbols) {
testthat::skip_if_not(exists(
symbol, envir = namespace, inherits = FALSE
))
}
old <- options(
cifmodeling.ciftest.engine = "Rcpp",
cifmodeling.ciftest.fg.engine = "check"
)
on.exit(options(old), add = TRUE)
time <- rep(seq_len(8L), each = 3L)
status <- rep(c(11L, 22L, 0L), 8L)
status[24L] <- 11L
strata <- rep(c("S1", "S2"), length.out = length(time))
weights <- rep(c(1, 0.5, 1.25, 0.75), length.out = length(time))
weights[c(5L, 18L)] <- 0
x <- cbind(
group = rep(c(0, 1), length.out = length(time)),
z = (seq_along(time) - mean(seq_along(time))) / length(time)
)
scalar <- cifmodeling:::build_fg_score_iid(
time, status, x,
code.event1 = 11L,
code.event2 = 22L,
code.censoring = 0L,
strata = strata,
weights = weights,
rho = 0.5,
gamma = 0.25
)
testthat::expect_identical(scalar$diagnostics$engine, "Rcpp-check")
testthat::expect_lt(
max(abs(colSums(scalar$score.iid.censor))), 1e-10
)
multi <- cifmodeling:::build_fg_score_iid_multi(
time, status, x,
rho = c(0, 0.5, 0),
gamma = c(0, 0.25, 1),
code.event1 = 11L,
code.event2 = 22L,
code.censoring = 0L,
strata = strata,
weights = weights
)
testthat::expect_length(multi, 3L)
testthat::expect_true(all(vapply(
multi,
function(value) identical(value$diagnostics$engine,
"Rcpp-check-multi"),
logical(1L)
)))
})
testthat::test_that("augmentation prefix kernels match legacy by nuisance cell", {
namespace <- asNamespace("cifmodeling")
symbols <- c(
"_cifmodeling_ciftest_augmentation_iid_prefix_kernel_cpp",
"_cifmodeling_ciftest_augmentation_iid_prefix_multi_kernel_cpp"
)
for (symbol in symbols) {
testthat::skip_if_not(exists(
symbol, envir = namespace, inherits = FALSE
))
}
old <- options(
cifmodeling.ciftest.engine = "Rcpp",
cifmodeling.ciftest.fg.engine = "prefix",
cifmodeling.ciftest.augmentation.engine = "check"
)
on.exit(options(old), add = TRUE)
df <- closed_form_example()
group_b <- as.numeric(df$group == levels(df$group)[2L])
x <- cbind(groupB = group_b, groupB2 = 2 * group_b)
weights <- rep(c(1, 0.5, 1.25, 0.75), length.out = nrow(df))
weights[2L] <- 0
base <- cifmodeling:::build_fg_score_iid(
df$time, df$status, x,
strata = df$stratum,
weights = weights,
rho = 0.5,
gamma = 0.25
)
working <- cifmodeling:::estimate_working_aj(
df$time, df$status, df$group, df$stratum,
weights = weights
)
scalar <- cifmodeling:::build_closed_form_augmentation(
base, working, df$time, df$status, x, df$group,
df$stratum, df$stratum, weights = weights
)
testthat::expect_identical(scalar$diagnostics$engine, "Rcpp-check")
bases <- cifmodeling:::build_fg_score_iid_multi(
df$time, df$status, x,
rho = c(0, 1), gamma = c(0, 0),
strata = df$stratum, weights = weights
)
multi <- cifmodeling:::build_closed_form_augmentation_multi(
bases, working, df$time, df$status, x, df$group,
df$stratum, df$stratum, weights = weights
)
testthat::expect_length(multi, 2L)
testthat::expect_true(all(vapply(
multi,
function(value) identical(value$diagnostics$engine,
"Rcpp-check-multi"),
logical(1L)
)))
})
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.