Skip to content

Commit 8bbb77e

Browse files
committed
update app
1 parent 7158d9a commit 8bbb77e

19 files changed

Lines changed: 712 additions & 52 deletions

DESCRIPTION

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ Description: Sample size calculation for adaptive trials.
1212
License: Apache License 2.0
1313
Encoding: UTF-8
1414
Roxygen: list(markdown = TRUE)
15-
RoxygenNote: 7.3.2
15+
RoxygenNote: 7.3.3
1616
Depends:
1717
R (>= 4.1.0)
1818
Imports:
@@ -36,6 +36,6 @@ Suggests:
3636
tinytest,
3737
kableExtra,
3838
tibble
39-
LinkingTo: Rcpp
39+
LinkingTo: Rcpp, RcppProgress
4040
SystemRequirements: JAGS (>= 4.0.0)
4141
Config/testthat/edition: 3

NAMESPACE

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@ export(plot_prior_weight)
3737
export(posterior)
3838
export(power)
3939
export(power_fisher)
40+
export(rct_beta_power)
41+
export(rct_power_beta_binom_cpp_vec)
4042
export(run_bcts_app)
4143
export(sim_rct_normal)
4244
export(singlearm_beta_power)

R/RcppExports.R

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,3 +155,61 @@ singlearm_beta_type1_exact <- function(n_t, M, threshold, prior = "flat", a_base
155155
.Call(`_bcts_singlearm_beta_type1_exact`, n_t, M, threshold, prior, a_base, b_base, p_null)
156156
}
157157

158+
#' Estimate Power for Bayesian RCT Using Beta-Binomial Conjugate Model (C++)
159+
#'
160+
#' Performs Monte Carlo simulation to estimate the statistical power of a
161+
#' Bayesian randomized controlled trial (RCT) using conjugate Beta-Binomial
162+
#' models for the control and treatment arms. The function supports flat priors
163+
#' and power priors on the control arm, and allows for fully customizable
164+
#' baseline Beta prior parameters for both arms.
165+
#'
166+
#' A trial is declared successful if the posterior probability
167+
#' \eqn{Pr(\theta_t - \theta_c > M \mid \text{data}) \ge \gamma}.
168+
#'
169+
#' @param B Integer. Number of simulated trials.
170+
#' @param p_c,p_t Numeric in \[0, 1\]. True response probabilities in the control and treatment arms.
171+
#' @param n_c,n_t Integers. Sample sizes in the control and treatment arms.
172+
#' @param M Numeric. Margin on the risk-difference scale:
173+
#' - Negative for non-inferiority,
174+
#' - Zero for equivalence,
175+
#' - Positive for superiority.
176+
#' @param threshold Numeric in (0, 1). Posterior probability threshold \eqn{\gamma}.
177+
#' @param prior Character. Type of prior to use:
178+
#' - `"flat"`: independent Beta priors for both arms,
179+
#' - `"power"`: power prior on the control arm, flat prior on treatment.
180+
#' @param prior_args List of prior hyperparameters. The following elements are supported:
181+
#' - `a0`: Discount factor for historical control data (only used if `prior = "power"`).
182+
#' - `y_0`, `n_0`: Number of responses and total patients in the historical control data.
183+
#' - `a_base_c`, `b_base_c`: Shape parameters of the Beta prior for the control arm.
184+
#' - `a_base_t`, `b_base_t`: Shape parameters of the Beta prior for the treatment arm.
185+
#' - Defaults for all `a_base_*` and `b_base_*` values are 1 (i.e., flat prior).
186+
#' @param n_draws Integer. Number of posterior draws per trial for estimating the probability.
187+
#' @param show_progress Logical. Show progress bar in the console.
188+
#'
189+
#' @return A logical vector of length `B`, indicating for each trial whether the decision
190+
#' criterion was met (i.e., trial declared successful).
191+
#'
192+
#' @details This function uses Rcpp and vectorized binomial simulation to increase speed.
193+
#' Posterior samples are drawn from Beta distributions parameterized using either flat priors
194+
#' or power priors (for control) combined with observed trial data.
195+
#'
196+
#' @examples
197+
#' prior_args <- list(
198+
#' a0 = 0.5, y_0 = 20, n_0 = 30,
199+
#' a_base_c = 1, b_base_c = 1,
200+
#' a_base_t = 2, b_base_t = 2
201+
#' )
202+
#' decisions <- rct_power_beta_binom_cpp_vec(
203+
#' B = 1000, p_c = 0.8, p_t = 0.8,
204+
#' n_c = 25, n_t = 25,
205+
#' M = -0.1, threshold = 0.9,
206+
#' prior = "power", prior_args = prior_args,
207+
#' n_draws = 2000, show_progress = FALSE
208+
#' )
209+
#' mean(decisions) # Estimated power
210+
#'
211+
#' @export
212+
rct_power_beta_binom_cpp_vec <- function(B, p_c, p_t, n_c, n_t, M, threshold, prior, prior_args, n_draws, show_progress = TRUE) {
213+
.Call(`_bcts_rct_power_beta_binom_cpp_vec`, B, p_c, p_t, n_c, n_t, M, threshold, prior, prior_args, n_draws, show_progress)
214+
}
215+

R/bayesNI-conj-calibrate.R

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -38,9 +38,6 @@
3838
#' )
3939
#' res$estimate
4040
#' res$ci
41-
#'
42-
#' @seealso [bcts_type1_betaBinom_conj()], [bcts_calibrate_betaBinom_conj()]
43-
#' @export
4441
bcts_power_betaBinom_conj <- function(B = 1000, p_c, p_t, n_c, n_t, M,
4542
threshold,
4643
prior = c("flat","power"),
@@ -130,10 +127,7 @@ bcts_power_betaBinom_conj <- function(B = 1000, p_c, p_t, n_c, n_t, M,
130127
#' prior = "flat",
131128
#' n_draws = 200
132129
#' )
133-
#'
134-
#' @seealso [bcts_calibrate_betaBinom_conj()], [bcts_power_betaBinom_conj()]
135130
#' @family conjugate-BetaBinom
136-
#' @export
137131
bcts_type1_betaBinom_conj <- function(B = 2000, p_c, M, n_c, n_t,
138132
threshold, prior = c("flat","power"),
139133
prior_args = list(),
Lines changed: 18 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -21,30 +21,32 @@
2121
#' @param seed RNG seed for reproducibility.
2222
#' @param show_progress Logical. Show text progress bars during simulation.
2323
#' @param verbose Logical. Print iteration messages during calibration.
24+
#' @param method Character. Method for estimation. Either `"simulate"` or `"cpp"`.
2425
#'
2526
#' @return An object of class `"bayesNI"` with components:
2627
#' - `calibration`: list from [bcts_calibrate_betaBinom_conj()]
2728
#' - `power`: estimated Bayesian power at calibrated `gamma`
2829
#' - `settings`: list of all input parameters (echoed)
2930
#'
3031
#' @seealso [bcts_calibrate_betaBinom_conj()],
31-
#' [bcts_power_betaBinom_conj()],
32+
#' [rct_beta_power()],
3233
#' [bcts_type1_betaBinom_conj()]
3334
#' @family conjugate-NI
3435
#'
3536
#' @examples
3637
#' \donttest{
37-
#' res <- bcts_run_betaBinom_conj(
38+
#' res <- rct_beta_calibrate(
3839
#' alpha = 0.10, p_c = .85, p_t = .85,
3940
#' n_c = 29, n_t = 29, NI_margin = -0.20,
40-
#' prior = "flat", B_cal = 1000, B_power = 500
41+
#' prior = "flat", B_cal = 1000, B_power = 500,
42+
#' method = "cpp
4143
#' )
4244
#' res$calibration$gamma
4345
#' res$power
4446
#' }
4547
#'
4648
#' @export
47-
bcts_run_betaBinom_conj <- function(alpha = 0.10,
49+
rct_beta_calibrate <- function(alpha = 0.10,
4850
p_c = 0.85, p_t = 0.85,
4951
n_c = 29, n_t = 29,
5052
NI_margin = -0.20,
@@ -54,9 +56,12 @@ bcts_run_betaBinom_conj <- function(alpha = 0.10,
5456
n_draws = 2000,
5557
tol = 0.002,
5658
seed = 123,
57-
show_progress = FALSE, verbose = TRUE) {
59+
show_progress = FALSE, verbose = TRUE,
60+
method = c("cpp", "simulate")) {
5861
prior <- match.arg(prior)
5962

63+
method <- match.arg(method)
64+
6065
# 1) Calibrate gamma using conjugate machinery
6166
cal <- bcts_calibrate_betaBinom_conj(alpha = alpha, p_c = p_c, M = NI_margin,
6267
n_c = n_c, n_t = n_t,
@@ -66,12 +71,14 @@ bcts_run_betaBinom_conj <- function(alpha = 0.10,
6671
show_progress = show_progress, verbose = verbose)
6772

6873
# 2) Simulate Bayesian "power" at calibrated gamma
69-
power <- bcts_power_betaBinom_conj(B = B_power, p_c = p_c, p_t = p_t,
70-
n_c = n_c, n_t = n_t, M = NI_margin,
71-
threshold = cal$gamma,
72-
prior = prior, prior_args = prior_args,
73-
n_draws = n_draws,
74-
seed = seed, show_progress = show_progress)
74+
power <- rct_beta_power(B = B_power, p_c = p_c, p_t = p_t,
75+
n_c = n_c, n_t = n_t, M = NI_margin,
76+
threshold = cal$gamma,
77+
prior = prior, prior_args = prior_args,
78+
n_draws = n_draws,
79+
show_progress = show_progress,
80+
method = method, seed = seed)
81+
7582

7683
out <- list(
7784
calibration = cal,

R/rct_beta_power.R

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
#' Estimate Bayesian Power for a 2-arm Binomial RCT (Beta-Binomial Conjugate)
2+
#'
3+
#' @description Computes the power of a Bayesian randomized controlled trial
4+
#' using conjugate Beta-Binomial models. Can use exact simulation in R or fast
5+
#' simulation in C++.
6+
#'
7+
#' @param B Integer. Number of trial simulations (ignored if \code{method = "exact"}).
8+
#' @param p_c,p_t Numeric in \[0,1\]. True response probabilities in control and treatment arms.
9+
#' @param n_c,n_t Integers. Sample sizes in control and treatment arms.
10+
#' @param M Numeric. Margin on the risk-difference scale. Default is 0 (superiority/equivalence).
11+
#' @param threshold Posterior probability cutoff (e.g. 0.9).
12+
#' @param prior Character. Prior type: \code{"flat"} or \code{"power"}.
13+
#' @param prior_args List with prior hyperparameters. Optional elements:
14+
#' - \code{a0}, \code{y_0}, \code{n_0} for power prior
15+
#' - \code{a_base_c}, \code{b_base_c} for control arm prior
16+
#' - \code{a_base_t}, \code{b_base_t} for treatment arm prior
17+
#' @param n_draws Integer. Number of posterior samples per trial.
18+
#' @param show_progress Logical. Show text progress bar?
19+
#' @param method Character. Either \code{"simulate"} (pure R) or \code{"cpp"} (fast C++).
20+
#' @param seed Optional integer. If provided, sets the RNG seed for reproducibility.
21+
#'
22+
#' @return A list with:
23+
#' \item{estimate}{Estimated power (probability of success)}
24+
#' \item{mc_se}{Monte Carlo standard error}
25+
#' \item{successes}{Number of trials with successful outcome}
26+
#' \item{B}{Number of simulations}
27+
#'
28+
#' @examples
29+
#' # Using C++ backend
30+
#' rct_beta_power(
31+
#' B = 1000, p_c = 0.85, p_t = 0.85,
32+
#' n_c = 30, n_t = 30, M = -0.1,
33+
#' threshold = 0.9, prior = "flat",
34+
#' method = "cpp", show_progress = FALSE
35+
#' )
36+
#'
37+
#' @export
38+
rct_beta_power <- function(B = 10000,
39+
p_c, p_t, n_c, n_t,
40+
M = 0,
41+
threshold,
42+
prior = c("flat", "power"),
43+
prior_args = list(),
44+
n_draws = 2000,
45+
show_progress = TRUE,
46+
method = c("cpp", "simulate"),
47+
seed = NULL) {
48+
prior <- match.arg(prior)
49+
method <- match.arg(method)
50+
51+
if (!is.null(seed)) set.seed(seed)
52+
53+
if (method == "simulate") {
54+
res <- bcts_power_betaBinom_conj(
55+
B = B,
56+
p_c = p_c,
57+
p_t = p_t,
58+
n_c = n_c,
59+
n_t = n_t,
60+
M = M,
61+
threshold = threshold,
62+
prior = prior,
63+
prior_args = prior_args,
64+
n_draws = n_draws,
65+
show_progress = show_progress,
66+
seed = seed
67+
)
68+
return(res)
69+
}
70+
71+
if (method == "cpp") {
72+
# Ensure required C++ function is available
73+
dec_vec <- rct_power_beta_binom_cpp_vec(
74+
B = B,
75+
p_c = p_c,
76+
p_t = p_t,
77+
n_c = n_c,
78+
n_t = n_t,
79+
M = M,
80+
threshold = threshold,
81+
prior = prior,
82+
prior_args = prior_args,
83+
n_draws = n_draws,
84+
show_progress = show_progress
85+
)
86+
k <- sum(dec_vec)
87+
p <- mean(dec_vec)
88+
mc_se <- sqrt(p * (1 - p) / B)
89+
90+
ci <- binom::binom.confint(x=k, n=B, conf.level = 0.95, methods = "wilson")
91+
92+
return(list(
93+
estimate = p,
94+
ci_lower = ci["lower"],
95+
ci_upper = ci["upper"],
96+
mc_se = mc_se,
97+
successes = k,
98+
B = B
99+
))
100+
}
101+
102+
stop("Unsupported method. Choose either 'simulate' or 'cpp'.")
103+
}

inst/app/R/sim-core.R

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,10 +29,11 @@ run_all_oc <- function(pt, nt, pc, nc, M, mode, gamma, alpha, calibrate_on,
2929
n_draws = ndraws, show_progress = FALSE
3030
)
3131

32-
pw <- bcts_power_betaBinom_conj(
32+
pw <- rct_beta_power(
3333
B = B, p_c = pc, p_t = pt, n_c = nc, n_t = nt, M = M,
3434
threshold = gamma_used, prior = prior, prior_args = prior_args,
35-
n_draws = ndraws, seed = seed, show_progress = FALSE
35+
n_draws = ndraws, seed = seed, show_progress = FALSE,
36+
method = "cpp"
3637
)
3738

3839
list(

inst/app/app.R

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
# ---- Load packages that the APP needs ----
55
library(shiny)
6+
library(shinyjs)
67
library(ggplot2)
78
library(bcts)
89

@@ -322,6 +323,7 @@ server <- function(input, output, session) {
322323
"sens",
323324
sim = sim, # your eventReactive from primary analysis
324325
pt = reactive(input$pt / 100),
326+
pc = reactive(input$pc / 100),
325327
nt = reactive(input$nt),
326328
nc = reactive(input$nc),
327329
M = reactive(input$M / 100),

0 commit comments

Comments
 (0)