tests/testthat/test-oc1S.R

## test the analytical OC function via brute force simulation
set.seed(12354)

## expect results to be 1% exact
eps <- 1e-2

## here we test against the reference Neuenschwander et al.,
## Statist. Med. 2011, 30, 1618 (*the* double criterion paper)

## Example for Figure 3
s <- 2
theta_ni <- 0.4

theta_a <- 0
alpha <- 0.05
beta <- 0.2

za <- qnorm(1 - alpha)
n1 <- 155
c1 <- theta_ni - za * s / sqrt(n1)

thetaA <- c(theta_a, theta_ni)

## standard NI design, tests only statistical significance to be
## smaller than theta_ni with 1-alpha certainty
decA <- decision1S(1 - alpha, theta_ni, lower.tail = TRUE)

prior <- mixnorm(c(1, 0, 100), sigma = s)

test_scenario <- function(oc_res, ref) {
  resA <- oc_res - ref
  expect_true(all(abs(resA) < eps))
}

test_that("Classical NI design critical value", {
  expect_true(abs(decision1S_boundary(prior, 155, decA) - c1) < eps)
})

## n set to give power 80% to detect 0 and type I error 5% for no
## better than theta_ni
test_that("Classical NI design at target    sample size for OCs", {
  test_scenario(oc1S(prior, 155, decA)(thetaA), c(1 - beta, alpha))
})
test_that("Classical NI design at increased sample size for OCs", {
  test_scenario(oc1S(prior, 233, decA)(thetaA), c(1 - 0.08, alpha))
})
test_that("Classical NI design at decreased sample size for OCs", {
  test_scenario(oc1S(prior, 77, decA)(thetaA), c(1 - 0.45, alpha))
})

## now double criterion with indecision point (mean estimate must be
## lower than this)
theta_c <- c1

## statistical significance
dec1 <- decision1S(1 - alpha, theta_ni, lower.tail = TRUE)
## require mean to be at least as good as theta_c
dec2 <- decision1S(0.5, theta_c, lower.tail = TRUE)
## combination
decComb <- decision1S(
  c(1 - alpha, 0.5),
  c(theta_ni, theta_c),
  lower.tail = TRUE
)

thetaD <- c(theta_c, theta_ni)

## since theta_c == c1, both decision criteria are the same for n =
## 155
test_that("Double criterion NI design at target    sample size for OCs, combined      ", {
  test_scenario(oc1S(prior, 155, decComb)(thetaD), c(0.50, alpha))
})
test_that("Double criterion NI design at target    sample size for OCs, stat criterion", {
  test_scenario(oc1S(prior, 155, dec1)(thetaD), c(0.50, alpha))
})
test_that("Double criterion NI design at target    sample size for OCs, mean criterion", {
  test_scenario(oc1S(prior, 155, dec2)(thetaD), c(0.50, alpha))
})

## at an increased sample size only the mean criterion is active
test_that("Double criterion NI design at increased sample size for OCs, combined      ", {
  test_scenario(oc1S(prior, 233, decComb)(thetaD), c(0.50, 0.02))
})
test_that("Double criterion NI design at increased sample size for OCs, mean criterion", {
  test_scenario(oc1S(prior, 233, dec2)(thetaD), c(0.50, 0.02))
})

## at a  decreased sample size only the stat criterion is active
test_that("Double criterion NI design at decreased sample size for OCs, combined      ", {
  test_scenario(oc1S(prior, 78, decComb)(thetaD), c(1 - 0.68, alpha))
})
test_that("Double criterion NI design at decreased sample size for OCs, stat criterion", {
  test_scenario(oc1S(prior, 78, dec1)(thetaD), c(1 - 0.68, alpha))
})

## test type 1 error and correctness of critical values wrt to
## lower.tail=TRUE/FALSE
dec1b <- decision1S(1 - alpha, theta_ni, lower.tail = FALSE)

## design object, decision function, posterior function must return
## posterior after updatding the prior with the given value
test_critical_discrete <- function(crit, decision, posterior) {
  lower.tail <- attr(decision, "lower.tail")
  if (lower.tail) {
    expect_equal(decision(posterior(crit - 1)), 1)
    expect_equal(decision(posterior(crit)), 1)
    expect_equal(decision(posterior(crit + 1)), 0)
  } else {
    expect_equal(decision(posterior(crit - 1)), 0)
    expect_equal(decision(posterior(crit)), 0)
    expect_equal(decision(posterior(crit + 1)), 1)
  }
}

## binary case
beta_prior <- mixbeta(c(1, 1, 1))
design_binary <- oc1S(beta_prior, 1000, dec1)
design_binaryB <- oc1S(beta_prior, 1000, dec1b)
crit1 <- decision1S_boundary(beta_prior, 1000, dec1)
crit1B <- decision1S_boundary(beta_prior, 1000, dec1b)
posterior_binary <- function(r) postmix(beta_prior, r = r, n = 1000)
test_that("Binary type I error rate", {
  test_scenario(design_binary(theta_ni), alpha)
})
test_that("Binary crticial value, lower.tail=TRUE", {
  test_critical_discrete(crit1, dec1, posterior_binary)
})
test_that("Binary crticial value, lower.tail=FALSE", {
  test_critical_discrete(crit1B, dec1b, posterior_binary)
})

test_that("Binary boundary case, lower.tail=TRUE", {
  expect_numeric(
    design_binary(1),
    lower = 0,
    upper = 1,
    finite = TRUE,
    any.missing = FALSE
  )
})
test_that("Binary boundary case, lower.tail=FALSE", {
  expect_numeric(
    design_binaryB(0),
    lower = 0,
    upper = 1,
    finite = TRUE,
    any.missing = FALSE
  )
})

## poisson case
gamma_prior <- mixgamma(c(1, 2, 2))
dec_count <- decision1S(1 - alpha, 1, lower.tail = TRUE)
dec_countB <- decision1S(1 - alpha, 1, lower.tail = FALSE)
design_poisson <- oc1S(gamma_prior, 1000, dec_count)
design_poissonB <- oc1S(gamma_prior, 1000, dec_countB)
pcrit1 <- decision1S_boundary(gamma_prior, 1000, dec_count)
pcrit1B <- decision1S_boundary(gamma_prior, 1000, dec_countB)
posterior_poisson <- function(m) postmix(gamma_prior, m = m / 1000, n = 1000)
test_that("Poisson type I error rate", {
  test_scenario(design_poisson(1), alpha)
})
test_that("Poisson critical value, lower.tail=TRUE", {
  test_critical_discrete(pcrit1, dec_count, posterior_poisson)
})
test_that("Poisson critical value, lower.tail=FALSE", {
  test_critical_discrete(pcrit1B, dec_countB, posterior_poisson)
})

Try the RBesT package in your browser

Any scripts or data that you put into this service are public.

RBesT documentation built on June 8, 2025, 10:05 a.m.