From 2851495ff847838874be436a36f912956f4a82c0 Mon Sep 17 00:00:00 2001 From: LittleBeannie Date: Mon, 25 Aug 2025 14:52:12 -0400 Subject: [PATCH 1/6] Revise and unify the help file of `gs_power_npe` and `gs_design_npe` --- R/gs_design_npe.R | 96 ++------ R/gs_power_npe.R | 80 ++++--- man/gs_design_npe.Rd | 273 ---------------------- man/gs_power_design_npe.Rd | 448 +++++++++++++++++++++++++++++++++++++ man/gs_power_npe.Rd | 251 --------------------- 5 files changed, 514 insertions(+), 634 deletions(-) delete mode 100644 man/gs_design_npe.Rd create mode 100644 man/gs_power_design_npe.Rd delete mode 100644 man/gs_power_npe.Rd diff --git a/R/gs_design_npe.R b/R/gs_design_npe.R index a7920e2c..ed77a43b 100644 --- a/R/gs_design_npe.R +++ b/R/gs_design_npe.R @@ -16,82 +16,14 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . -#' Group sequential design computation with non-constant effect and information -#' -#' Derives group sequential design size, -#' bounds and boundary crossing probabilities based on proportionate -#' information and effect size at analyses. -#' It allows a non-constant treatment effect over time, -#' but also can be applied for the usual homogeneous effect size designs. -#' It requires treatment effect and proportionate statistical information -#' at each analysis as well as a method of deriving bounds, such as spending. -#' The routine enables two things not available in the gsDesign package: -#' 1) non-constant effect, 2) more flexibility in boundary selection. -#' For many applications, the non-proportional-hazards design function -#' `gs_design_nph()` will be used; it calls this function. -#' Initial bound types supported are 1) spending bounds, -#' 2) fixed bounds, and 3) Haybittle-Peto-like bounds. -#' The requirement is to have a boundary update method that -#' can each bound without knowledge of future bounds. -#' As an example, bounds based on conditional power that -#' require knowledge of all future bounds are not supported by this routine; -#' a more limited conditional power method will be demonstrated. -#' Boundary family designs Wang-Tsiatis designs including -#' the original (non-spending-function-based) O'Brien-Fleming and Pocock designs -#' are not supported by [gs_power_npe()]. -#' -#' @param theta Natural parameter for group sequential design -#' representing expected incremental drift at all analyses; -#' used for power calculation. -#' @param theta0 Natural parameter used for upper bound spending; -#' if `NULL`, this will be set to 0. -#' @param theta1 Natural parameter used for lower bound spending; -#' if `NULL`, this will be set to `theta` -#' which yields the usual beta-spending. -#' If set to 0, spending is 2-sided under null hypothesis. -#' @param info Proportionate statistical information at -#' all analyses for input `theta`. -#' @param info0 Proportionate statistical information -#' under null hypothesis, if different than alternative; -#' impacts null hypothesis bound calculation. -#' @param info1 Proportionate statistical information -#' under alternate hypothesis; -#' impacts null hypothesis bound calculation. -#' @param info_scale Information scale for calculation. Options are: -#' - `"h0_h1_info"` (default): variance under both null and alternative hypotheses is used. -#' - `"h0_info"`: variance under null hypothesis is used. -#' - `"h1_info"`: variance under alternative hypothesis is used. + + +#' @rdname gs_power_design_npe #' @param alpha One-sided Type I error. #' @param beta Type II error. -#' @param binding Indicator of whether futility bound is binding; -#' default of `FALSE` is recommended. -#' @param upper Function to compute upper bound. -#' @param lower Function to compare lower bound. -#' @param upar Parameters passed to the function provided in `upper`. -#' @param lpar Parameters passed to the function provided in `lower`. -#' @param test_upper Indicator of which analyses should include -#' an upper (efficacy) bound; single value of `TRUE` (default) indicates -#' all analyses; otherwise, a logical vector of the same length as `info` -#' should indicate which analyses will have an efficacy bound. -#' @param test_lower Indicator of which analyses should include an lower bound; -#' single value of `TRUE` (default) indicates all analyses; -#' single value `FALSE` indicates no lower bound; otherwise, -#' a logical vector of the same length as `info` should indicate which -#' analyses will have a lower bound. -#' @param r Integer value controlling grid for numerical integration -#' as in Jennison and Turnbull (2000); default is 18, range is 1 to 80. -#' Larger values provide larger number of grid points and greater accuracy. -#' Normally `r` will not be changed by the user. -#' @param tol Tolerance parameter for boundary convergence (on Z-scale). -#' -#' @return A tibble with columns analysis, bound, z, probability, theta, info, info0. -#' + #' @details -#' The inputs `info` and `info0` should be -#' vectors of the same length with increasing positive numbers. -#' The design returned will change these by some constant scale -#' factor to ensure the design has power `1 - beta`. -#' The bound specifications in `upper`, `lower`, `upar`, `lpar` +#' The bound specifications (`upper`, `lower`, `upar`, `lpar`) of \code{gs_design_npe()} #' will be used to ensure Type I error and other boundary properties are as specified. #' #' @section Specification: @@ -131,7 +63,7 @@ #' library(gsDesign) #' #' # Example 1 ---- -#' # Single analysis +#' # gs_design_npe with single analysis #' # Lachin book p 71 difference of proportions example #' pc <- .28 # Control response rate #' pe <- .40 # Experimental response rate @@ -147,7 +79,7 @@ #' #' #' # Example 2 ---- -#' # Fixed bound +#' # gs_design_npe with with fixed bound #' x <- gs_design_npe( #' alpha = 0.0125, #' theta = c(.1, .2, .3), @@ -163,15 +95,15 @@ #' # Same upper bound; this represents non-binding Type I error and will total 0.025 #' gs_power_npe( #' theta = rep(0, 3), -#' info = (x %>% filter(bound == "upper"))$info, +#' info = (x |> dplyr::filter(bound == "upper"))$info, #' upper = gs_b, -#' upar = (x %>% filter(bound == "upper"))$z, +#' upar = (x |> dplyr::filter(bound == "upper"))$z, #' lower = gs_b, #' lpar = rep(-Inf, 3) #' ) #' #' # Example 3 ---- -#' # Spending bound examples +#' # gs_design_npe with spending bound #' # Design with futility only at analysis 1; efficacy only at analyses 2, 3 #' # Spending bound for efficacy; fixed bound for futility #' # NOTE: test_upper and test_lower DO NOT WORK with gs_b; must explicitly make bounds infinite @@ -201,7 +133,7 @@ #' ) #' #' # Example 4 ---- -#' # Spending function bounds +#' # gs_design_npe with spending function bounds #' # 2-sided asymmetric bounds #' # Lower spending based on non-zero effect #' gs_design_npe( @@ -215,7 +147,7 @@ #' ) #' #' # Example 5 ---- -#' # Two-sided symmetric spend, O'Brien-Fleming spending +#' # gs_design_npe with two-sided symmetric spend, O'Brien-Fleming spending #' # Typically, 2-sided bounds are binding #' xx <- gs_design_npe( #' theta = c(.1, .2, .3), @@ -236,8 +168,8 @@ #' binding = TRUE, #' upper = gs_b, #' lower = gs_b, -#' upar = (xx %>% filter(bound == "upper"))$z, -#' lpar = -(xx %>% filter(bound == "upper"))$z +#' upar = (xx |> dplyr::filter(bound == "upper"))$z, +#' lpar = -(xx |> dplyr::filter(bound == "upper"))$z #' ) gs_design_npe <- function( theta = .1, theta0 = 0, theta1 = theta, # 3 theta diff --git a/R/gs_power_npe.R b/R/gs_power_npe.R index c4cf23ab..7964f56c 100644 --- a/R/gs_power_npe.R +++ b/R/gs_power_npe.R @@ -16,20 +16,26 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . -#' Group sequential bound computation with non-constant effect +#' @title Group sequential design computation with non-constant effect and information. #' -#' Derives group sequential bounds and boundary crossing probabilities for a design. -#' It allows a non-constant treatment effect over time, +#' @description The following 2 functions allows a non-constant treatment effect over time, #' but also can be applied for the usual homogeneous effect size designs. -#' It requires treatment effect and statistical information at each analysis +#' They requires treatment effect and statistical information at each analysis #' as well as a method of deriving bounds, such as spending. -#' The routine enables two things not available in the gsDesign package: -#' 1) non-constant effect, 2) more flexibility in boundary selection. -#' For many applications, the non-proportional-hazards design function -#' `gs_design_nph()` will be used; it calls this function. -#' Initial bound types supported are 1) spending bounds, -#' 2) fixed bounds, and 3) Haybittle-Peto-like bounds. -#' The requirement is to have a boundary update method that can +#' Initial bound types supported are 1) spending bounds, 2) fixed bounds, and 3) Haybittle-Peto-like bounds. +#' The above routine enables two things not available in the gsDesign package: 1) +#' non-constant effect, 2) more flexibility in boundary selection. +#' +#' \code{gs_power_npe()} derives group sequential bounds and boundary crossing probabilities +#' for a design, given treatment effect and information at each analysis, as well as the +#' method of deriving bounds, such as spending. +#' +#' \code{gs_design_npe()} derives group sequential design size, +#' bounds and boundary crossing probabilities based on proportionate +#' information and effect size at analyses, as well as the +#' method of deriving bounds, such as spending. +#' +#' The requirement is to have a boundary update method that can compute #' each bound without knowledge of future bounds. #' As an example, bounds based on conditional power that require #' knowledge of all future bounds are not supported by this routine; @@ -42,8 +48,11 @@ #' expected incremental drift at all analyses; used for power calculation. #' @param theta0 Natural parameter for null hypothesis, #' if needed for upper bound computation. +#' Default is 0. #' @param theta1 Natural parameter for alternate hypothesis, #' if needed for lower bound computation. +#' The default is the same as `theta`, which yields the usual beta-spending. +#' If set to 0, spending is 2-sided under the null hypothesis. #' @param info Statistical information at all analyses for input `theta`. #' @param info0 Statistical information under null hypothesis, #' if different than `info`; @@ -77,10 +86,20 @@ #' Normally, `r` will not be changed by the user. #' @param tol Tolerance parameter for boundary convergence (on Z-scale). #' -#' @return A tibble with columns as analysis index, bounds, z, -#' crossing probability, theta (standardized treatment effect), -#' theta1 (standardized treatment effect under alternative hypothesis), -#' information fraction, and statistical information. +#' @return A tibble with columns of +#' - `analysis`: analysis index. +#' - `bound`: either of value `"upper"` or `"lower"`, indicating the upper and lower bound. +#' - `z`: the Z-score bounds. +#' - `probability`: cumulative probability of crossing the bound at or before the analysis. +#' - `theta`: same as the input. +#' - `theta1`: same as the input. +#' - `info`: statistical information at each analysis. +#' + If it is returned by `gs_power_ahr`, the `info`, `info0`, `info1` is same as the input. +#' + If it is returned by `gs_power_ahr`, the `info`, `info0`, `info1` is change by some constant scale +#' factor to ensure the design has power `1 - beta`. +#' - `info0`: statistical information under the null at each analysis. +#' - `info1`: statistical information under the alternative at each analysis. +#' - `info_frac`: information fraction at each analysis, i.e., `info / max(info)`. #' #' @section Specification: #' \if{latex}{ @@ -117,17 +136,18 @@ #' } #' \if{html}{The contents of this section are shown in PDF user manual only.} #' +#' @name gs_power_design_npe +#' @rdname gs_power_design_npe #' @export #' #' @examples -#' library(gsDesign) -#' library(gsDesign2) -#' library(dplyr) #' -#' # Default (single analysis; Type I error controlled) -#' gs_power_npe(theta = 0) %>% filter(bound == "upper") +#' # Example 6 ---- +#' # Default of gs_power_npe (single analysis; Type I error controlled) +#' gs_power_npe(theta = 0) |> dplyr::filter(bound == "upper") #' -#' # Fixed bound +#' # Example 7 ---- +#' # gs_power_npe with fixed bound #' gs_power_npe( #' theta = c(.1, .2, .3), #' info = (1:3) * 40, @@ -143,10 +163,11 @@ #' info = (1:3) * 40, #' upar = gsDesign::gsDesign(k = 3, sfu = gsDesign::sfLDOF)$upper$bound, #' lpar = rep(-Inf, 3) -#' ) %>% -#' filter(bound == "upper") +#' ) |> +#' dplyr::filter(bound == "upper") #' -#' # Fixed bound with futility only at analysis 1; efficacy only at analyses 2, 3 +#' # Example 8 ---- +#' # gs_power_npe with fixed bound testing futility only at analysis 1; efficacy only at analyses 2, 3 #' gs_power_npe( #' theta = c(.1, .2, .3), #' info = (1:3) * 40, @@ -156,7 +177,8 @@ #' lpar = c(qnorm(.1), -Inf, -Inf) #' ) #' -#' # Spending function bounds +#' # Example 8 ---- +#' # gs_power_npe with spending function bounds #' # Lower spending based on non-zero effect #' gs_power_npe( #' theta = c(.1, .2, .3), @@ -177,7 +199,8 @@ #' lpar = list(sf = gsDesign::sfHSD, total_spend = 0.1, param = -1, timing = NULL) #' ) #' -#' # Two-sided symmetric spend, O'Brien-Fleming spending +#' # Example 9 ---- +#' # gs_power_npe with two-sided symmetric spend, O'Brien-Fleming spending #' # Typically, 2-sided bounds are binding #' x <- gs_power_npe( #' theta = rep(0, 3), @@ -195,10 +218,11 @@ #' theta = c(.1, .2, .3), #' info = (1:3) * 40, #' binding = TRUE, -#' upar = (x %>% filter(bound == "upper"))$z, -#' lpar = -(x %>% filter(bound == "upper"))$z +#' upar = (x |> dplyr::filter(bound == "upper"))$z, +#' lpar = -(x |> dplyr::filter(bound == "upper"))$z #' ) #' +#' # Example 10 ---- #' # Different values of `r` and `tol` lead to different numerical accuracy #' # Larger `r` and smaller `tol` give better accuracy, but leads to slow computation #' n_analysis <- 5 diff --git a/man/gs_design_npe.Rd b/man/gs_design_npe.Rd deleted file mode 100644 index e8bf17a2..00000000 --- a/man/gs_design_npe.Rd +++ /dev/null @@ -1,273 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/gs_design_npe.R -\name{gs_design_npe} -\alias{gs_design_npe} -\title{Group sequential design computation with non-constant effect and information} -\usage{ -gs_design_npe( - theta = 0.1, - theta0 = 0, - theta1 = theta, - info = 1, - info0 = NULL, - info1 = NULL, - info_scale = c("h0_h1_info", "h0_info", "h1_info"), - alpha = 0.025, - beta = 0.1, - upper = gs_b, - upar = qnorm(0.975), - lower = gs_b, - lpar = -Inf, - test_upper = TRUE, - test_lower = TRUE, - binding = FALSE, - r = 18, - tol = 1e-06 -) -} -\arguments{ -\item{theta}{Natural parameter for group sequential design -representing expected incremental drift at all analyses; -used for power calculation.} - -\item{theta0}{Natural parameter used for upper bound spending; -if \code{NULL}, this will be set to 0.} - -\item{theta1}{Natural parameter used for lower bound spending; -if \code{NULL}, this will be set to \code{theta} -which yields the usual beta-spending. -If set to 0, spending is 2-sided under null hypothesis.} - -\item{info}{Proportionate statistical information at -all analyses for input \code{theta}.} - -\item{info0}{Proportionate statistical information -under null hypothesis, if different than alternative; -impacts null hypothesis bound calculation.} - -\item{info1}{Proportionate statistical information -under alternate hypothesis; -impacts null hypothesis bound calculation.} - -\item{info_scale}{Information scale for calculation. Options are: -\itemize{ -\item \code{"h0_h1_info"} (default): variance under both null and alternative hypotheses is used. -\item \code{"h0_info"}: variance under null hypothesis is used. -\item \code{"h1_info"}: variance under alternative hypothesis is used. -}} - -\item{alpha}{One-sided Type I error.} - -\item{beta}{Type II error.} - -\item{upper}{Function to compute upper bound.} - -\item{upar}{Parameters passed to the function provided in \code{upper}.} - -\item{lower}{Function to compare lower bound.} - -\item{lpar}{Parameters passed to the function provided in \code{lower}.} - -\item{test_upper}{Indicator of which analyses should include -an upper (efficacy) bound; single value of \code{TRUE} (default) indicates -all analyses; otherwise, a logical vector of the same length as \code{info} -should indicate which analyses will have an efficacy bound.} - -\item{test_lower}{Indicator of which analyses should include an lower bound; -single value of \code{TRUE} (default) indicates all analyses; -single value \code{FALSE} indicates no lower bound; otherwise, -a logical vector of the same length as \code{info} should indicate which -analyses will have a lower bound.} - -\item{binding}{Indicator of whether futility bound is binding; -default of \code{FALSE} is recommended.} - -\item{r}{Integer value controlling grid for numerical integration -as in Jennison and Turnbull (2000); default is 18, range is 1 to 80. -Larger values provide larger number of grid points and greater accuracy. -Normally \code{r} will not be changed by the user.} - -\item{tol}{Tolerance parameter for boundary convergence (on Z-scale).} -} -\value{ -A tibble with columns analysis, bound, z, probability, theta, info, info0. -} -\description{ -Derives group sequential design size, -bounds and boundary crossing probabilities based on proportionate -information and effect size at analyses. -It allows a non-constant treatment effect over time, -but also can be applied for the usual homogeneous effect size designs. -It requires treatment effect and proportionate statistical information -at each analysis as well as a method of deriving bounds, such as spending. -The routine enables two things not available in the gsDesign package: -\enumerate{ -\item non-constant effect, 2) more flexibility in boundary selection. -For many applications, the non-proportional-hazards design function -\code{gs_design_nph()} will be used; it calls this function. -Initial bound types supported are 1) spending bounds, -\item fixed bounds, and 3) Haybittle-Peto-like bounds. -The requirement is to have a boundary update method that -can each bound without knowledge of future bounds. -As an example, bounds based on conditional power that -require knowledge of all future bounds are not supported by this routine; -a more limited conditional power method will be demonstrated. -Boundary family designs Wang-Tsiatis designs including -the original (non-spending-function-based) O'Brien-Fleming and Pocock designs -are not supported by \code{\link[=gs_power_npe]{gs_power_npe()}}. -} -} -\details{ -The inputs \code{info} and \code{info0} should be -vectors of the same length with increasing positive numbers. -The design returned will change these by some constant scale -factor to ensure the design has power \code{1 - beta}. -The bound specifications in \code{upper}, \code{lower}, \code{upar}, \code{lpar} -will be used to ensure Type I error and other boundary properties are as specified. -} -\section{Specification}{ - -\if{latex}{ - \itemize{ - \item Validate if input info is a numeric vector or NULL, if non-NULL validate if it - is strictly increasing and positive. - \item Validate if input info0 is a numeric vector or NULL, if non-NULL validate if it - is strictly increasing and positive. - \item Validate if input info1 is a numeric vector or NULL, if non-NULL validate if it - is strictly increasing and positive. - \item Validate if input theta is a real vector and has the same length as info. - \item Validate if input theta1 is a real vector and has the same length as info. - \item Validate if input test_upper and test_lower are logical and have the same length as info. - \item Validate if input test_upper value is TRUE. - \item Validate if input alpha and beta are positive and of length one. - \item Validate if input alpha and beta are from the unit interval and alpha is smaller than beta. - \item Initialize bounds, numerical integration grids, boundary crossing probabilities. - \item Compute fixed sample size for desired power and Type I error. - \item Find an interval for information inflation to give correct power using \code{gs_power_npe()}. - \item - \item If there is no interim analysis, return a tibble including Analysis time, upper bound, Z-value, - Probability of crossing bound, theta, info0 and info1. - \item If the design is a group sequential design, return a tibble of Analysis, - Bound, Z, Probability, theta, info, info0. - } -} -\if{html}{The contents of this section are shown in PDF user manual only.} -} - -\examples{ -library(dplyr) -library(gsDesign) - -# Example 1 ---- -# Single analysis -# Lachin book p 71 difference of proportions example -pc <- .28 # Control response rate -pe <- .40 # Experimental response rate -p0 <- (pc + pe) / 2 # Ave response rate under H0 - -# Information per increment of 1 in sample size -info0 <- 1 / (p0 * (1 - p0) * 4) -info <- 1 / (pc * (1 - pc) * 2 + pe * (1 - pe) * 2) - -# Result should round up to next even number = 652 -# Divide information needed under H1 by information per patient added -gs_design_npe(theta = pe - pc, info = info, info0 = info0) - - -# Example 2 ---- -# Fixed bound -x <- gs_design_npe( - alpha = 0.0125, - theta = c(.1, .2, .3), - info = (1:3) * 80, - info0 = (1:3) * 80, - upper = gs_b, - upar = gsDesign::gsDesign(k = 3, sfu = gsDesign::sfLDOF, alpha = 0.0125)$upper$bound, - lower = gs_b, - lpar = c(-1, 0, 0) -) -x - -# Same upper bound; this represents non-binding Type I error and will total 0.025 -gs_power_npe( - theta = rep(0, 3), - info = (x \%>\% filter(bound == "upper"))$info, - upper = gs_b, - upar = (x \%>\% filter(bound == "upper"))$z, - lower = gs_b, - lpar = rep(-Inf, 3) -) - -# Example 3 ---- -# Spending bound examples -# Design with futility only at analysis 1; efficacy only at analyses 2, 3 -# Spending bound for efficacy; fixed bound for futility -# NOTE: test_upper and test_lower DO NOT WORK with gs_b; must explicitly make bounds infinite -# test_upper and test_lower DO WORK with gs_spending_bound -gs_design_npe( - theta = c(.1, .2, .3), - info = (1:3) * 40, - info0 = (1:3) * 40, - upper = gs_spending_bound, - upar = list(sf = gsDesign::sfLDOF, total_spend = 0.025, param = NULL, timing = NULL), - lower = gs_b, - lpar = c(-1, -Inf, -Inf), - test_upper = c(FALSE, TRUE, TRUE) -) - -# one can try `info_scale = "h1_info"` or `info_scale = "h0_info"` here -gs_design_npe( - theta = c(.1, .2, .3), - info = (1:3) * 40, - info0 = (1:3) * 30, - info_scale = "h1_info", - upper = gs_spending_bound, - upar = list(sf = gsDesign::sfLDOF, total_spend = 0.025, param = NULL, timing = NULL), - lower = gs_b, - lpar = c(-1, -Inf, -Inf), - test_upper = c(FALSE, TRUE, TRUE) -) - -# Example 4 ---- -# Spending function bounds -# 2-sided asymmetric bounds -# Lower spending based on non-zero effect -gs_design_npe( - theta = c(.1, .2, .3), - info = (1:3) * 40, - info0 = (1:3) * 30, - upper = gs_spending_bound, - upar = list(sf = gsDesign::sfLDOF, total_spend = 0.025, param = NULL, timing = NULL), - lower = gs_spending_bound, - lpar = list(sf = gsDesign::sfHSD, total_spend = 0.1, param = -1, timing = NULL) -) - -# Example 5 ---- -# Two-sided symmetric spend, O'Brien-Fleming spending -# Typically, 2-sided bounds are binding -xx <- gs_design_npe( - theta = c(.1, .2, .3), - info = (1:3) * 40, - binding = TRUE, - upper = gs_spending_bound, - upar = list(sf = gsDesign::sfLDOF, total_spend = 0.025, param = NULL, timing = NULL), - lower = gs_spending_bound, - lpar = list(sf = gsDesign::sfLDOF, total_spend = 0.025, param = NULL, timing = NULL) -) -xx - -# Re-use these bounds under alternate hypothesis -# Always use binding = TRUE for power calculations -gs_power_npe( - theta = c(.1, .2, .3), - info = (1:3) * 40, - binding = TRUE, - upper = gs_b, - lower = gs_b, - upar = (xx \%>\% filter(bound == "upper"))$z, - lpar = -(xx \%>\% filter(bound == "upper"))$z -) -} -\author{ -Keaven Anderson \email{keaven_anderson@merck.com} -} diff --git a/man/gs_power_design_npe.Rd b/man/gs_power_design_npe.Rd new file mode 100644 index 00000000..8c0bb976 --- /dev/null +++ b/man/gs_power_design_npe.Rd @@ -0,0 +1,448 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/gs_design_npe.R, R/gs_power_npe.R +\name{gs_design_npe} +\alias{gs_design_npe} +\alias{gs_power_design_npe} +\alias{gs_power_npe} +\title{Group sequential design computation with non-constant effect and information.} +\usage{ +gs_design_npe( + theta = 0.1, + theta0 = 0, + theta1 = theta, + info = 1, + info0 = NULL, + info1 = NULL, + info_scale = c("h0_h1_info", "h0_info", "h1_info"), + alpha = 0.025, + beta = 0.1, + upper = gs_b, + upar = qnorm(0.975), + lower = gs_b, + lpar = -Inf, + test_upper = TRUE, + test_lower = TRUE, + binding = FALSE, + r = 18, + tol = 1e-06 +) + +gs_power_npe( + theta = 0.1, + theta0 = 0, + theta1 = theta, + info = 1, + info0 = NULL, + info1 = NULL, + info_scale = c("h0_h1_info", "h0_info", "h1_info"), + upper = gs_b, + upar = qnorm(0.975), + lower = gs_b, + lpar = -Inf, + test_upper = TRUE, + test_lower = TRUE, + binding = FALSE, + r = 18, + tol = 1e-06 +) +} +\arguments{ +\item{theta}{Natural parameter for group sequential design representing +expected incremental drift at all analyses; used for power calculation.} + +\item{theta0}{Natural parameter for null hypothesis, +if needed for upper bound computation. +Default is 0.} + +\item{theta1}{Natural parameter for alternate hypothesis, +if needed for lower bound computation. +The default is the same as \code{theta}, which yields the usual beta-spending. +If set to 0, spending is 2-sided under the null hypothesis.} + +\item{info}{Statistical information at all analyses for input \code{theta}.} + +\item{info0}{Statistical information under null hypothesis, +if different than \code{info}; +impacts null hypothesis bound calculation.} + +\item{info1}{Statistical information under hypothesis used for +futility bound calculation if different from +\code{info}; impacts futility hypothesis bound calculation.} + +\item{info_scale}{Information scale for calculation. Options are: +\itemize{ +\item \code{"h0_h1_info"} (default): variance under both null and alternative hypotheses is used. +\item \code{"h0_info"}: variance under null hypothesis is used. +\item \code{"h1_info"}: variance under alternative hypothesis is used. +}} + +\item{alpha}{One-sided Type I error.} + +\item{beta}{Type II error.} + +\item{upper}{Function to compute upper bound.} + +\item{upar}{Parameters passed to \code{upper}.} + +\item{lower}{Function to compare lower bound.} + +\item{lpar}{parameters passed to \code{lower}.} + +\item{test_upper}{Indicator of which analyses should include +an upper (efficacy) bound; +single value of \code{TRUE} (default) indicates all analyses; otherwise, +a logical vector of the same length as \code{info} should +indicate which analyses will have an efficacy bound.} + +\item{test_lower}{Indicator of which analyses should include a lower bound; +single value of \code{TRUE} (default) indicates all analyses; +single value of \code{FALSE} indicated no lower bound; otherwise, +a logical vector of the same length as \code{info} should +indicate which analyses will have a lower bound.} + +\item{binding}{Indicator of whether futility bound is binding; +default of \code{FALSE} is recommended.} + +\item{r}{Integer value controlling grid for numerical integration as in +Jennison and Turnbull (2000); default is 18, range is 1 to 80. +Larger values provide larger number of grid points and greater accuracy. +Normally, \code{r} will not be changed by the user.} + +\item{tol}{Tolerance parameter for boundary convergence (on Z-scale).} +} +\value{ +A tibble with columns of +\itemize{ +\item \code{analysis}: analysis index. +\item \code{bound}: either of value \code{"upper"} or \code{"lower"}, indicating the upper and lower bound. +\item \code{z}: the Z-score bounds. +\item \code{probability}: cumulative probability of crossing the bound at or before the analysis. +\item \code{theta}: same as the input. +\item \code{theta1}: same as the input. +\item \code{info}: statistical information at each analysis. +\itemize{ +\item If it is returned by \code{gs_power_ahr}, the \code{info}, \code{info0}, \code{info1} is same as the input. +\item If it is returned by \code{gs_power_ahr}, the \code{info}, \code{info0}, \code{info1} is change by some constant scale +factor to ensure the design has power \code{1 - beta}. +} +\item \code{info0}: statistical information under the null at each analysis. +\item \code{info1}: statistical information under the alternative at each analysis. +\item \code{info_frac}: information fraction at each analysis, i.e., \code{info / max(info)}. +} +} +\description{ +The following 2 functions allows a non-constant treatment effect over time, +but also can be applied for the usual homogeneous effect size designs. +They requires treatment effect and statistical information at each analysis +as well as a method of deriving bounds, such as spending. +Initial bound types supported are 1) spending bounds, 2) fixed bounds, and 3) Haybittle-Peto-like bounds. +The above routine enables two things not available in the gsDesign package: 1) +non-constant effect, 2) more flexibility in boundary selection. + +\code{gs_power_npe()} derives group sequential bounds and boundary crossing probabilities +for a design, given treatment effect and information at each analysis, as well as the +method of deriving bounds, such as spending. + +\code{gs_design_npe()} derives group sequential design size, +bounds and boundary crossing probabilities based on proportionate +information and effect size at analyses, as well as the +method of deriving bounds, such as spending. + +The requirement is to have a boundary update method that can compute +each bound without knowledge of future bounds. +As an example, bounds based on conditional power that require +knowledge of all future bounds are not supported by this routine; +a more limited conditional power method will be demonstrated. +Boundary family designs Wang-Tsiatis designs including the +original (non-spending-function-based) O'Brien-Fleming and Pocock designs +are not supported by \code{gs_power_npe()}. +} +\details{ +The bound specifications (\code{upper}, \code{lower}, \code{upar}, \code{lpar}) of \code{gs_design_npe()} +will be used to ensure Type I error and other boundary properties are as specified. +} +\section{Specification}{ + +\if{latex}{ + \itemize{ + \item Validate if input info is a numeric vector or NULL, if non-NULL validate if it + is strictly increasing and positive. + \item Validate if input info0 is a numeric vector or NULL, if non-NULL validate if it + is strictly increasing and positive. + \item Validate if input info1 is a numeric vector or NULL, if non-NULL validate if it + is strictly increasing and positive. + \item Validate if input theta is a real vector and has the same length as info. + \item Validate if input theta1 is a real vector and has the same length as info. + \item Validate if input test_upper and test_lower are logical and have the same length as info. + \item Validate if input test_upper value is TRUE. + \item Validate if input alpha and beta are positive and of length one. + \item Validate if input alpha and beta are from the unit interval and alpha is smaller than beta. + \item Initialize bounds, numerical integration grids, boundary crossing probabilities. + \item Compute fixed sample size for desired power and Type I error. + \item Find an interval for information inflation to give correct power using \code{gs_power_npe()}. + \item + \item If there is no interim analysis, return a tibble including Analysis time, upper bound, Z-value, + Probability of crossing bound, theta, info0 and info1. + \item If the design is a group sequential design, return a tibble of Analysis, + Bound, Z, Probability, theta, info, info0. + } +} +\if{html}{The contents of this section are shown in PDF user manual only.} + + +\if{latex}{ + \itemize{ + \item Extract the length of input info as the number of interim analysis. + \item Validate if input info0 is NULL, so set it equal to info. + \item Validate if the length of inputs info and info0 are the same. + \item Validate if input theta is a scalar, so replicate + the value for all k interim analysis. + \item Validate if input theta1 is NULL and if it is a scalar. + If it is NULL, set it equal to input theta. If it is a scalar, + replicate the value for all k interim analysis. + \item Validate if input test_upper is a scalar, + so replicate the value for all k interim analysis. + \item Validate if input test_lower is a scalar, + so replicate the value for all k interim analysis. + \item Define vector a to be -Inf with + length equal to the number of interim analysis. + \item Define vector b to be Inf with + length equal to the number of interim analysis. + \item Define hgm1_0 and hgm1 to be NULL. + \item Define upper_prob and lower_prob to be + vectors of NA with length of the number of interim analysis. + \item Update lower and upper bounds using \code{gs_b()}. + \item If there are no interim analysis, compute probabilities + of crossing upper and lower bounds + using \code{h1()}. + \item Compute cross upper and lower bound probabilities + using \code{hupdate()} and \code{h1()}. + \item Return a tibble of analysis number, bound, z-values, + probability of crossing bounds, + theta, theta1, info, and info0. + } +} +\if{html}{The contents of this section are shown in PDF user manual only.} +} + +\examples{ +library(dplyr) +library(gsDesign) + +# Example 1 ---- +# gs_design_npe with single analysis +# Lachin book p 71 difference of proportions example +pc <- .28 # Control response rate +pe <- .40 # Experimental response rate +p0 <- (pc + pe) / 2 # Ave response rate under H0 + +# Information per increment of 1 in sample size +info0 <- 1 / (p0 * (1 - p0) * 4) +info <- 1 / (pc * (1 - pc) * 2 + pe * (1 - pe) * 2) + +# Result should round up to next even number = 652 +# Divide information needed under H1 by information per patient added +gs_design_npe(theta = pe - pc, info = info, info0 = info0) + + +# Example 2 ---- +# gs_design_npe with with fixed bound +x <- gs_design_npe( + alpha = 0.0125, + theta = c(.1, .2, .3), + info = (1:3) * 80, + info0 = (1:3) * 80, + upper = gs_b, + upar = gsDesign::gsDesign(k = 3, sfu = gsDesign::sfLDOF, alpha = 0.0125)$upper$bound, + lower = gs_b, + lpar = c(-1, 0, 0) +) +x + +# Same upper bound; this represents non-binding Type I error and will total 0.025 +gs_power_npe( + theta = rep(0, 3), + info = (x |> dplyr::filter(bound == "upper"))$info, + upper = gs_b, + upar = (x |> dplyr::filter(bound == "upper"))$z, + lower = gs_b, + lpar = rep(-Inf, 3) +) + +# Example 3 ---- +# gs_design_npe with spending bound +# Design with futility only at analysis 1; efficacy only at analyses 2, 3 +# Spending bound for efficacy; fixed bound for futility +# NOTE: test_upper and test_lower DO NOT WORK with gs_b; must explicitly make bounds infinite +# test_upper and test_lower DO WORK with gs_spending_bound +gs_design_npe( + theta = c(.1, .2, .3), + info = (1:3) * 40, + info0 = (1:3) * 40, + upper = gs_spending_bound, + upar = list(sf = gsDesign::sfLDOF, total_spend = 0.025, param = NULL, timing = NULL), + lower = gs_b, + lpar = c(-1, -Inf, -Inf), + test_upper = c(FALSE, TRUE, TRUE) +) + +# one can try `info_scale = "h1_info"` or `info_scale = "h0_info"` here +gs_design_npe( + theta = c(.1, .2, .3), + info = (1:3) * 40, + info0 = (1:3) * 30, + info_scale = "h1_info", + upper = gs_spending_bound, + upar = list(sf = gsDesign::sfLDOF, total_spend = 0.025, param = NULL, timing = NULL), + lower = gs_b, + lpar = c(-1, -Inf, -Inf), + test_upper = c(FALSE, TRUE, TRUE) +) + +# Example 4 ---- +# gs_design_npe with spending function bounds +# 2-sided asymmetric bounds +# Lower spending based on non-zero effect +gs_design_npe( + theta = c(.1, .2, .3), + info = (1:3) * 40, + info0 = (1:3) * 30, + upper = gs_spending_bound, + upar = list(sf = gsDesign::sfLDOF, total_spend = 0.025, param = NULL, timing = NULL), + lower = gs_spending_bound, + lpar = list(sf = gsDesign::sfHSD, total_spend = 0.1, param = -1, timing = NULL) +) + +# Example 5 ---- +# gs_design_npe with two-sided symmetric spend, O'Brien-Fleming spending +# Typically, 2-sided bounds are binding +xx <- gs_design_npe( + theta = c(.1, .2, .3), + info = (1:3) * 40, + binding = TRUE, + upper = gs_spending_bound, + upar = list(sf = gsDesign::sfLDOF, total_spend = 0.025, param = NULL, timing = NULL), + lower = gs_spending_bound, + lpar = list(sf = gsDesign::sfLDOF, total_spend = 0.025, param = NULL, timing = NULL) +) +xx + +# Re-use these bounds under alternate hypothesis +# Always use binding = TRUE for power calculations +gs_power_npe( + theta = c(.1, .2, .3), + info = (1:3) * 40, + binding = TRUE, + upper = gs_b, + lower = gs_b, + upar = (xx |> dplyr::filter(bound == "upper"))$z, + lpar = -(xx |> dplyr::filter(bound == "upper"))$z +) + +# Example 6 ---- +# Default of gs_power_npe (single analysis; Type I error controlled) +gs_power_npe(theta = 0) |> dplyr::filter(bound == "upper") + +# Example 7 ---- +# gs_power_npe with fixed bound +gs_power_npe( + theta = c(.1, .2, .3), + info = (1:3) * 40, + upper = gs_b, + upar = gsDesign::gsDesign(k = 3, sfu = gsDesign::sfLDOF)$upper$bound, + lower = gs_b, + lpar = c(-1, 0, 0) +) + +# Same fixed efficacy bounds, no futility bound (i.e., non-binding bound), null hypothesis +gs_power_npe( + theta = rep(0, 3), + info = (1:3) * 40, + upar = gsDesign::gsDesign(k = 3, sfu = gsDesign::sfLDOF)$upper$bound, + lpar = rep(-Inf, 3) +) |> + dplyr::filter(bound == "upper") + +# Example 8 ---- +# gs_power_npe with fixed bound testing futility only at analysis 1; efficacy only at analyses 2, 3 +gs_power_npe( + theta = c(.1, .2, .3), + info = (1:3) * 40, + upper = gs_b, + upar = c(Inf, 3, 2), + lower = gs_b, + lpar = c(qnorm(.1), -Inf, -Inf) +) + +# Example 8 ---- +# gs_power_npe with spending function bounds +# Lower spending based on non-zero effect +gs_power_npe( + theta = c(.1, .2, .3), + info = (1:3) * 40, + upper = gs_spending_bound, + upar = list(sf = gsDesign::sfLDOF, total_spend = 0.025, param = NULL, timing = NULL), + lower = gs_spending_bound, + lpar = list(sf = gsDesign::sfHSD, total_spend = 0.1, param = -1, timing = NULL) +) + +# Same bounds, but power under different theta +gs_power_npe( + theta = c(.15, .25, .35), + info = (1:3) * 40, + upper = gs_spending_bound, + upar = list(sf = gsDesign::sfLDOF, total_spend = 0.025, param = NULL, timing = NULL), + lower = gs_spending_bound, + lpar = list(sf = gsDesign::sfHSD, total_spend = 0.1, param = -1, timing = NULL) +) + +# Example 9 ---- +# gs_power_npe with two-sided symmetric spend, O'Brien-Fleming spending +# Typically, 2-sided bounds are binding +x <- gs_power_npe( + theta = rep(0, 3), + info = (1:3) * 40, + binding = TRUE, + upper = gs_spending_bound, + upar = list(sf = gsDesign::sfLDOF, total_spend = 0.025, param = NULL, timing = NULL), + lower = gs_spending_bound, + lpar = list(sf = gsDesign::sfLDOF, total_spend = 0.025, param = NULL, timing = NULL) +) + +# Re-use these bounds under alternate hypothesis +# Always use binding = TRUE for power calculations +gs_power_npe( + theta = c(.1, .2, .3), + info = (1:3) * 40, + binding = TRUE, + upar = (x |> dplyr::filter(bound == "upper"))$z, + lpar = -(x |> dplyr::filter(bound == "upper"))$z +) + +# Example 10 ---- +# Different values of `r` and `tol` lead to different numerical accuracy +# Larger `r` and smaller `tol` give better accuracy, but leads to slow computation +n_analysis <- 5 +gs_power_npe( + theta = 0.1, + info = 1:n_analysis, + info0 = 1:n_analysis, + info1 = NULL, + info_scale = "h0_info", + upper = gs_spending_bound, + upar = list(sf = gsDesign::sfLDOF, total_spend = 0.025, param = NULL, timing = NULL), + lower = gs_b, + lpar = -rep(Inf, n_analysis), + test_upper = TRUE, + test_lower = FALSE, + binding = FALSE, + # Try different combinations of (r, tol) with + # r in 6, 18, 24, 30, 35, 40, 50, 60, 70, 80, 90, 100 + # tol in 1e-6, 1e-12 + r = 6, + tol = 1e-6 +) +} +\author{ +Keaven Anderson \email{keaven_anderson@merck.com} +} diff --git a/man/gs_power_npe.Rd b/man/gs_power_npe.Rd deleted file mode 100644 index 324be946..00000000 --- a/man/gs_power_npe.Rd +++ /dev/null @@ -1,251 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/gs_power_npe.R -\name{gs_power_npe} -\alias{gs_power_npe} -\title{Group sequential bound computation with non-constant effect} -\usage{ -gs_power_npe( - theta = 0.1, - theta0 = 0, - theta1 = theta, - info = 1, - info0 = NULL, - info1 = NULL, - info_scale = c("h0_h1_info", "h0_info", "h1_info"), - upper = gs_b, - upar = qnorm(0.975), - lower = gs_b, - lpar = -Inf, - test_upper = TRUE, - test_lower = TRUE, - binding = FALSE, - r = 18, - tol = 1e-06 -) -} -\arguments{ -\item{theta}{Natural parameter for group sequential design representing -expected incremental drift at all analyses; used for power calculation.} - -\item{theta0}{Natural parameter for null hypothesis, -if needed for upper bound computation.} - -\item{theta1}{Natural parameter for alternate hypothesis, -if needed for lower bound computation.} - -\item{info}{Statistical information at all analyses for input \code{theta}.} - -\item{info0}{Statistical information under null hypothesis, -if different than \code{info}; -impacts null hypothesis bound calculation.} - -\item{info1}{Statistical information under hypothesis used for -futility bound calculation if different from -\code{info}; impacts futility hypothesis bound calculation.} - -\item{info_scale}{Information scale for calculation. Options are: -\itemize{ -\item \code{"h0_h1_info"} (default): variance under both null and alternative hypotheses is used. -\item \code{"h0_info"}: variance under null hypothesis is used. -\item \code{"h1_info"}: variance under alternative hypothesis is used. -}} - -\item{upper}{Function to compute upper bound.} - -\item{upar}{Parameters passed to \code{upper}.} - -\item{lower}{Function to compare lower bound.} - -\item{lpar}{parameters passed to \code{lower}.} - -\item{test_upper}{Indicator of which analyses should include -an upper (efficacy) bound; -single value of \code{TRUE} (default) indicates all analyses; otherwise, -a logical vector of the same length as \code{info} should -indicate which analyses will have an efficacy bound.} - -\item{test_lower}{Indicator of which analyses should include a lower bound; -single value of \code{TRUE} (default) indicates all analyses; -single value of \code{FALSE} indicated no lower bound; otherwise, -a logical vector of the same length as \code{info} should -indicate which analyses will have a lower bound.} - -\item{binding}{Indicator of whether futility bound is binding; -default of \code{FALSE} is recommended.} - -\item{r}{Integer value controlling grid for numerical integration as in -Jennison and Turnbull (2000); default is 18, range is 1 to 80. -Larger values provide larger number of grid points and greater accuracy. -Normally, \code{r} will not be changed by the user.} - -\item{tol}{Tolerance parameter for boundary convergence (on Z-scale).} -} -\value{ -A tibble with columns as analysis index, bounds, z, -crossing probability, theta (standardized treatment effect), -theta1 (standardized treatment effect under alternative hypothesis), -information fraction, and statistical information. -} -\description{ -Derives group sequential bounds and boundary crossing probabilities for a design. -It allows a non-constant treatment effect over time, -but also can be applied for the usual homogeneous effect size designs. -It requires treatment effect and statistical information at each analysis -as well as a method of deriving bounds, such as spending. -The routine enables two things not available in the gsDesign package: -\enumerate{ -\item non-constant effect, 2) more flexibility in boundary selection. -For many applications, the non-proportional-hazards design function -\code{gs_design_nph()} will be used; it calls this function. -Initial bound types supported are 1) spending bounds, -\item fixed bounds, and 3) Haybittle-Peto-like bounds. -The requirement is to have a boundary update method that can -each bound without knowledge of future bounds. -As an example, bounds based on conditional power that require -knowledge of all future bounds are not supported by this routine; -a more limited conditional power method will be demonstrated. -Boundary family designs Wang-Tsiatis designs including the -original (non-spending-function-based) O'Brien-Fleming and Pocock designs -are not supported by \code{gs_power_npe()}. -} -} -\section{Specification}{ - -\if{latex}{ - \itemize{ - \item Extract the length of input info as the number of interim analysis. - \item Validate if input info0 is NULL, so set it equal to info. - \item Validate if the length of inputs info and info0 are the same. - \item Validate if input theta is a scalar, so replicate - the value for all k interim analysis. - \item Validate if input theta1 is NULL and if it is a scalar. - If it is NULL, set it equal to input theta. If it is a scalar, - replicate the value for all k interim analysis. - \item Validate if input test_upper is a scalar, - so replicate the value for all k interim analysis. - \item Validate if input test_lower is a scalar, - so replicate the value for all k interim analysis. - \item Define vector a to be -Inf with - length equal to the number of interim analysis. - \item Define vector b to be Inf with - length equal to the number of interim analysis. - \item Define hgm1_0 and hgm1 to be NULL. - \item Define upper_prob and lower_prob to be - vectors of NA with length of the number of interim analysis. - \item Update lower and upper bounds using \code{gs_b()}. - \item If there are no interim analysis, compute probabilities - of crossing upper and lower bounds - using \code{h1()}. - \item Compute cross upper and lower bound probabilities - using \code{hupdate()} and \code{h1()}. - \item Return a tibble of analysis number, bound, z-values, - probability of crossing bounds, - theta, theta1, info, and info0. - } -} -\if{html}{The contents of this section are shown in PDF user manual only.} -} - -\examples{ -library(gsDesign) -library(gsDesign2) -library(dplyr) - -# Default (single analysis; Type I error controlled) -gs_power_npe(theta = 0) \%>\% filter(bound == "upper") - -# Fixed bound -gs_power_npe( - theta = c(.1, .2, .3), - info = (1:3) * 40, - upper = gs_b, - upar = gsDesign::gsDesign(k = 3, sfu = gsDesign::sfLDOF)$upper$bound, - lower = gs_b, - lpar = c(-1, 0, 0) -) - -# Same fixed efficacy bounds, no futility bound (i.e., non-binding bound), null hypothesis -gs_power_npe( - theta = rep(0, 3), - info = (1:3) * 40, - upar = gsDesign::gsDesign(k = 3, sfu = gsDesign::sfLDOF)$upper$bound, - lpar = rep(-Inf, 3) -) \%>\% - filter(bound == "upper") - -# Fixed bound with futility only at analysis 1; efficacy only at analyses 2, 3 -gs_power_npe( - theta = c(.1, .2, .3), - info = (1:3) * 40, - upper = gs_b, - upar = c(Inf, 3, 2), - lower = gs_b, - lpar = c(qnorm(.1), -Inf, -Inf) -) - -# Spending function bounds -# Lower spending based on non-zero effect -gs_power_npe( - theta = c(.1, .2, .3), - info = (1:3) * 40, - upper = gs_spending_bound, - upar = list(sf = gsDesign::sfLDOF, total_spend = 0.025, param = NULL, timing = NULL), - lower = gs_spending_bound, - lpar = list(sf = gsDesign::sfHSD, total_spend = 0.1, param = -1, timing = NULL) -) - -# Same bounds, but power under different theta -gs_power_npe( - theta = c(.15, .25, .35), - info = (1:3) * 40, - upper = gs_spending_bound, - upar = list(sf = gsDesign::sfLDOF, total_spend = 0.025, param = NULL, timing = NULL), - lower = gs_spending_bound, - lpar = list(sf = gsDesign::sfHSD, total_spend = 0.1, param = -1, timing = NULL) -) - -# Two-sided symmetric spend, O'Brien-Fleming spending -# Typically, 2-sided bounds are binding -x <- gs_power_npe( - theta = rep(0, 3), - info = (1:3) * 40, - binding = TRUE, - upper = gs_spending_bound, - upar = list(sf = gsDesign::sfLDOF, total_spend = 0.025, param = NULL, timing = NULL), - lower = gs_spending_bound, - lpar = list(sf = gsDesign::sfLDOF, total_spend = 0.025, param = NULL, timing = NULL) -) - -# Re-use these bounds under alternate hypothesis -# Always use binding = TRUE for power calculations -gs_power_npe( - theta = c(.1, .2, .3), - info = (1:3) * 40, - binding = TRUE, - upar = (x \%>\% filter(bound == "upper"))$z, - lpar = -(x \%>\% filter(bound == "upper"))$z -) - -# Different values of `r` and `tol` lead to different numerical accuracy -# Larger `r` and smaller `tol` give better accuracy, but leads to slow computation -n_analysis <- 5 -gs_power_npe( - theta = 0.1, - info = 1:n_analysis, - info0 = 1:n_analysis, - info1 = NULL, - info_scale = "h0_info", - upper = gs_spending_bound, - upar = list(sf = gsDesign::sfLDOF, total_spend = 0.025, param = NULL, timing = NULL), - lower = gs_b, - lpar = -rep(Inf, n_analysis), - test_upper = TRUE, - test_lower = FALSE, - binding = FALSE, - # Try different combinations of (r, tol) with - # r in 6, 18, 24, 30, 35, 40, 50, 60, 70, 80, 90, 100 - # tol in 1e-6, 1e-12 - r = 6, - tol = 1e-6 -) -} From be5007ab30414f19b34fe32b94f39a3e16cb80e2 Mon Sep 17 00:00:00 2001 From: LittleBeannie Date: Mon, 25 Aug 2025 16:15:17 -0400 Subject: [PATCH 2/6] fix the testthat error of `as_rtf` due to path change --- tests/testthat/Rplots.pdf | Bin 0 -> 3611 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 tests/testthat/Rplots.pdf diff --git a/tests/testthat/Rplots.pdf b/tests/testthat/Rplots.pdf new file mode 100644 index 0000000000000000000000000000000000000000..65eb0df12d465c0958e7d4a11c8c9ce44ebb7a5c GIT binary patch literal 3611 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 Z`jJGKFp&ZOIGdK1t`0&;$=u!o@n6JGF6saP literal 0 HcmV?d00001 From 6bd1186112252efab1d40b7f74e38a6ff7b77de4 Mon Sep 17 00:00:00 2001 From: LittleBeannie Date: Mon, 25 Aug 2025 16:41:58 -0400 Subject: [PATCH 3/6] fix testthat error in `as_rtf` --- tests/testthat/Rplots.pdf | Bin 3611 -> 3611 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/tests/testthat/Rplots.pdf b/tests/testthat/Rplots.pdf index 65eb0df12d465c0958e7d4a11c8c9ce44ebb7a5c..fa83c639baaa97dd1128e442228d4cb5d3c194ba 100644 GIT binary patch delta 23 bcmbO&Gh1eYHH(R%fyqRB2{64e`T#EgPT~fY delta 23 bcmbO&Gh1eYHH)E%iSa~x2{64e`T#EgPZ|cB From 42676c700737f1bd833481460735a567981978e3 Mon Sep 17 00:00:00 2001 From: LittleBeannie Date: Mon, 25 Aug 2025 16:59:31 -0400 Subject: [PATCH 4/6] update the Rplots.pdf with the latest version of testthat --- tests/testthat/Rplots.pdf | Bin 3611 -> 3611 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/tests/testthat/Rplots.pdf b/tests/testthat/Rplots.pdf index fa83c639baaa97dd1128e442228d4cb5d3c194ba..077930d641c7c93a580fa51ca6247d61e5f1c9ef 100644 GIT binary patch delta 23 bcmbO&Gh1eYHH)c*iRDCl2{64e`T#EgP(B8? delta 23 bcmbO&Gh1eYHH(R%fyqRB2{64e`T#EgPT~fY From 7c12f4d996cd2da531bc923c1d84bff23c83f81a Mon Sep 17 00:00:00 2001 From: LittleBeannie Date: Tue, 26 Aug 2025 10:02:39 -0400 Subject: [PATCH 5/6] Install the latest r2rtf and update the testing results --- tests/testthat/Rplots.pdf | Bin 3611 -> 3611 bytes .../independent_as_rtf/fixed_design_ahr.rtf | 16 ++++++++-------- .../fixed_design_ahr_footnote.rtf | 16 ++++++++-------- .../fixed_design_ahr_title.rtf | 16 ++++++++-------- .../independent_as_rtf/gs_design_ahr.rtf | 16 ++++++++-------- .../independent_as_rtf/gs_design_rd.rtf | 16 ++++++++-------- .../independent_as_rtf/gs_design_wlr.rtf | 16 ++++++++-------- .../independent_as_rtf/gs_power_wlr.rtf | 16 ++++++++-------- .../gs_power_wlr_cols_display.rtf | 16 ++++++++-------- .../gs_power_wlr_efficacy_bound.rtf | 16 ++++++++-------- .../gs_power_wlr_footnote.rtf | 16 ++++++++-------- .../gs_power_wlr_futility_bound.rtf | 16 ++++++++-------- .../gs_power_wlr_spanner.rtf | 16 ++++++++-------- .../independent_as_rtf/gs_power_wlr_title.rtf | 16 ++++++++-------- 14 files changed, 104 insertions(+), 104 deletions(-) diff --git a/tests/testthat/Rplots.pdf b/tests/testthat/Rplots.pdf index 077930d641c7c93a580fa51ca6247d61e5f1c9ef..a7df32ca5610a23e9a653c33500bfbae45b8f888 100644 GIT binary patch delta 29 ecmbO&Gh1eY1-qG{fq{Xk;Y52;7;|Iv0bT%ea|gWu delta 29 ecmbO&Gh1eY1-q%CnW=?| Date: Tue, 26 Aug 2025 15:21:51 -0400 Subject: [PATCH 6/6] remove Rplots.pdf --- tests/testthat/Rplots.pdf | Bin 3611 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 tests/testthat/Rplots.pdf diff --git a/tests/testthat/Rplots.pdf b/tests/testthat/Rplots.pdf deleted file mode 100644 index a7df32ca5610a23e9a653c33500bfbae45b8f888..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3611 zcmZ`+c{r479~L3gVy8JNFIfw(8H}-&Wh_~;W+&5lF{d#z&AgK(W8boUp+s3DT0WnI zY*Dgj8Cyyzq7xAcMX0`+&N-cPo$vbI>w2&EdhX}JIQph+w3;{|wU9>t{OC5{Gpw!jXwNT0k(1zms zfA^e-Fp1se0GQM8)BqxZ4%jkaDg$P>+0iJz3<5;s>}sl^)i_i?W>GkhGUCV)1Vr}b zs6hWz1AtB;R0se~@Gzc4@drRVygx(-G}r|Wz+VlV_3!fkZ1}wnv?BV_0S~~7%|Kz0 zVRjj41Njp1#*|>dL!G_UQrG0XUVkIg{7LphGrP81_PdW)wD+zCL?C zXc`QgJHnis(%0v3u;-8{G)F3)@B;zq4(7&y7Mt;h+`klaAdX@W@R*5-F`f?j0vJw} z*PnO5S^aq=BN7bJ$ebY{4mwLDKpax=IQtqvYl!R*2LNa-9Si`P5jlnIFNs}?g9sE~ zh@*)Pv;SxyA~-iME6B-lOd^5Rq}^nfA(V7+;Btmis$!@HHORjvaZFlxPO`Cpo%YIq6XtZ-C zeObjL>~jtzsI!8O)kpTw`=_7}Z^jj;Q*}g|Q__8qk~2Hj>(R{$gc$f(ykQ6BO(iny zIEG6pV_fYm-O-n%O2|+`N2^YUa7|itpZqWcy7sa}dj#A2d)?JUJS-odi9jtnwYGAX{NQBqc)r_^X zS>CY`i%6XGdh2JG@SNRTcS@m}v5ka4qBxh={5HGBuL*rVAXn1eX2u@onF9@B-VSY3 zD*lIWkB@s=Z7Vpf49+fX6zqvGIT^-sXnwi$8$Ng?6Pp2}OuV(pexaqfwyypu>X%(_ z3li3)`M)s^NCO>sS?)_`?ZjYpSgB5#gyyy1Gmm36_^ZzW^(S?8ax3lC(u za$lGE#W4H;m(n3&K;WG3;ejRQ&JJ^)FMY{_IoWxetmtn{mpbcjT@rE;X#{f|x=zHt z|NWIMcWzC9%hZr(&T!u>kLbhg_Z|w@aS2ZHa2qKlZa?FLnv52^unh-Dibd8G?!6dY z?xT2vk5MSB8H1tjg`)_Qnpl3ds2-o~k>168uX8*KU*ALi+%b4e?O^gX#jM zE$(-ONxW4)w%8qMv63y_AJAB7wdmT1m#92pLW{Ast(PZ-T@gp4%7i0@gmteas|!m! zGBZvOmJ<+`xqU&Tgqvvi{KA0}>G~v#^s+7wF+NjMl%4g(osXr(=~u)jVH>m4*ZKzgXSrY%U1VOenwd-C)q(x9RkOmY*bQ;Mm?A<7Ds69s zwUmN*6?YY~YTt00P8_l$1z%d}`fuG)srjVc?X)|mNT_>=b3*4t&hhG{F=Gx+!PI-$ zlb-s=6A!nYm~^KqQeCK`b;$c7uY{IT1lw0W^n8TY&B6r3cN|SCkWms%5%^E6h4CT0 zYEj038P=-KD%eO)!IyRAHrTb6)4TYgYV?UQGaV-#laMM}@-pvl=3*-CiBl%8?UR%?mHd?m zPO-OaA;$o@60kTdHIO?xG`c+ec<9!UZt*9l ztN&Rj%DdHMvKjliWY39C8}q^{lbMo!LOh~1Grj+Y?<%Sk)?$2R$Txgyh-uIW?Fh9G zjSF1}U0W5{Q28qNb^k`wh9jRYp9~)_UpZgx?vL>*tzxZS@n7RBQd3e-rC|0lkOpXH zjXmo9+GMTf)5e%H+HQVBKD0hD!eg|J#>>Fav0a!dZ7bAm)IM}V-~L|Sw~c)Xssj?o zC5)5#lJ{AQ3}@!FlAtvAA=MbwovMv01#U>!c8|cSx!R3@KuR9@WdO4?{*-8dW56(B z<#u_F>eG82pPzd!drs8fo;k~6lKsh@wJ!)k!}-5TpL)>J{PbH)OmR$CQ6GM2@F8lj za`Yo#atDGC=$98{tQVqFepdJG>gZUD+xxI*UnC_WB;9G2i!XbKf=|`8M*VVduk3QB0$f zLSCaMMuO3O(WWg1GE@tnuFn@5S9Z_roC%7H9*7)RC|Y}z(wY^=lui>6+*u(Iu@^6D zFEscdvcac2I*YeLwn?@}b_th*J9aI!SiD&D+STHdoxzEh|DQ)QAHD&zH3{gxv|*w-7f)21QGYAU0yxy|eABJJ|I^5!Cg=TYZX&oAi|M2l?@b{40tZ5XPcw*!cB3h8iSn}P* zcFi%?NMsxCt~dJ1be3c0ih{Q8nngY>U!CGpKelYsqqxjmdEg!8-r_arQRs2!o)3I| z=JCdffm_#ahq}yHsJR<7cToDGYGP}Mrz4cA)l|T+dNn^U+jQr_E7vMNh0l8=izk`3 zYh&t2H(n$@S9*r6BQBQSvXQn5mY1|Dw>oS&L3vAVUcc1ma_J=Vc}6vKr?-g2a_)70 zJv#qlymr5miy8}*esSP#6P=%6-ko+?@ACWmc6b;2+T=S{cdgu!o?~8+T}{m#lVSPE zBGtv_T)E#u>GP+JA&nL9KRz3FE<54kzDBO_S?UXYu+h&~9G}F@X6kGnz?f-&j_BKH zs6SSGv-(|Y`0Ma@QHeavzO=qR)hnt{IrVl4W7+3XOV31b#PG`w(rrpv?d1d9333Ss zBCf74d}=jHIQOqRY1K^sb+17Fn&J}CInP%*Pc99~FQm;MIPyzyb#3SMvgva@OKZ}@ z2F`TP--5>k9-Y4?T5$YrLGF=DjJbF3-V76(tU{M^&l}Lo!TXdCq=B)OnJ`w~yS4X6 zLtcH_s@&Nxnda^5^}gW^^(Oscc;PhvrnD~Kem=bfse}el&ubBxuN^j(w0UXRrKuvn zQG&WK)U}oVdfxsi<&{O9OjCE`ms#hH@|jvXnKkZ4mt@wy$scM;+Pt#1FI@9$rPmx_ zaAeLv_k&MMj2>aUQt>GCeKq|4tjrgDdu%^$<=_kRP6ehSc+`76ciA(Zk<8 zH+$cV1w9DfLaU4GX?^ot-5RdAdh*7DXWxewp(Xg)>Q@(Jg`fB3`}Ps^N!9tl?~U0( zq8jx}l}m?@W{1yy*}M92u`I>5Ae?6{c4d=o!2fWIe^_ztpEeZnhZQ#^vwbCz%=Y3O z+xpkag-A9c(}{lq2oOi~^Mhy*nZP#e9)PA67)T^D=ztCeJj0;C5DD^w5hzVf(3irF z40JjX0R3tBvuuxxConixmq4Tu7=eByC>Q`?B8lx~!9YBLMj->>DH_BnWOw2T1c(eH zKwlzz6rD&1Ks7Q2_J#ZakoH3)fo=CmB>dm-00!9~Ph$j<@C+CLDgG2PbecU4|AU#% zaqeD!%Ob%v$Pb|oU=i%}^Tz{Vw6rv|06*X-hGyp{&I6EtVkitdl>7rjqu9yjpBPr> ze=rRlb~O1%ohJH!_%u)`>|b>-4NoLNG