library(gsDesign)The upper end of the Jennison-Turnbull grid in src/gridpts.c is:
grid_limit <- function(r) 3 + 4 * log(r)
grid_tbl <- data.frame(
r = c(18, 50, 70, 71, 80),
z_max = grid_limit(c(18, 50, 70, 71, 80)),
exceeds_20 = grid_limit(c(18, 50, 70, 71, 80)) > 20
)
signif(grid_tbl, 8)
#> r z_max exceeds_20
#> 1 18 14.56149 0
#> 2 50 18.64809 0
#> 3 70 19.99398 0
#> 4 71 20.05072 1
#> 5 80 20.52811 1Direct checks discussed:
rdbl <- 80
3 + 4 * log(rdbl)
#> [1] 20.52811
rdbl <- 70
3 + 4 * log(rdbl)
#> [1] 19.99398Use a design with trimmed efficacy spending so the first look is effectively "no testing" (upper bound at 20).
skip_summary <- function(r) {
x <- gsDesign(
k = 4,
n.fix = 100,
sfu = sfTrimmed,
sfupar = list(sf = sfHSD, param = 1, trange = c(0.3, 0.9)),
r = r
)
data.frame(
r = r,
b1 = x$upper$bound[1],
b2 = x$upper$bound[2],
p1_h0 = x$upper$prob[1, 1],
p2_h0 = x$upper$prob[2, 1],
alpha_h0 = sum(x$upper$prob[, 1])
)
}
res <- do.call(rbind, lapply(c(18, 50, 70, 71, 80), skip_summary))
signif(res, 16)
#> r b1 b2 p1_h0 p2_h0 alpha_h0
#> 1 18 20 2.155497 2.753624e-89 0.01554894 0.02421384
#> 2 50 20 2.155497 2.753624e-89 0.01554893 0.02421383
#> 3 70 20 2.155497 2.753624e-89 0.01554893 0.02421383
#> 4 71 20 2.155497 2.753624e-89 0.01554893 0.02421383
#> 5 80 20 2.155497 2.753624e-89 0.01554893 0.02421383Compare full upper-bound/probability vectors to r=70:
skip_vector <- function(r) {
x <- gsDesign(
k = 4,
n.fix = 100,
sfu = sfTrimmed,
sfupar = list(sf = sfHSD, param = 1, trange = c(0.3, 0.9)),
r = r
)
c(x$upper$bound, x$upper$prob[, 1])
}
v70 <- skip_vector(70)
cmp_r <- c(18, 50, 71, 80)
diff_tbl <- data.frame(
r = cmp_r,
max_abs_diff_vs_r70 = vapply(cmp_r, function(r) max(abs(skip_vector(r) - v70)), numeric(1))
)
format(diff_tbl, digits = 17)
#> r max_abs_diff_vs_r70
#> 1 18 2.5101146006178965e-07
#> 2 50 3.2197817745327484e-09
#> 3 71 5.5082605143752517e-11
#> 4 80 4.6306114498406714e-10- The grid-range argument is correct: for
r<=70,3 + 4*log(r) <= 20, so increasing the boundary cap above 20 should have essentially no impact in that range. - For
70 < r <= 80, the grid extends slightly above 20 (up to about 20.53 atr=80), so tiny tail differences are possible. - In the skipped-look check above,
r=70vsr=80differs only at a microscopic scale (max absolute difference around1e-10in this example). EXTREMEZis not only a boundary cap. Insrc/gsbound.c, it is also used as the Newton iteration limit (j++ < EXTREMEZ), so changing it directly toINFINITYis unsafe.- A robust change should separate concerns:
BOUND_CAP_Zfor boundary capping semantics.MAX_NR_ITERfor convergence safety.- R-side handling for "no bound" output semantics (current code has
several hardcoded
+/-20assumptions in plotting and helper paths).