diff --git a/DESCRIPTION b/DESCRIPTION
index 5f26d104..c90ea708 100644
--- a/DESCRIPTION
+++ b/DESCRIPTION
@@ -1,7 +1,7 @@
Package: simtrial
Type: Package
Title: Clinical Trial Simulation
-Version: 0.3.2.4
+Version: 0.3.2.7
Authors@R: c(
person("Keaven", "Anderson", email = "keaven_anderson@merck.com", role = c("aut")),
person("Yilong", "Zhang", email = "elong0527@gmail.com", role = c("aut")),
@@ -44,7 +44,6 @@ Imports:
future,
methods,
mvtnorm,
- rlang,
stats,
survival,
utils
diff --git a/LICENSE b/LICENSE
index 603d1e58..2e3e301d 100644
--- a/LICENSE
+++ b/LICENSE
@@ -632,7 +632,7 @@ state the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
simtrial: Clinical Trial Simulation
- Copyright (c) 2023 Merck & Co., Inc., Rahway, NJ, USA and its affiliates. All rights reserved.
+ Copyright (c) 2024 Merck & Co., Inc., Rahway, NJ, USA and its affiliates. All rights reserved.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -652,7 +652,7 @@ Also add information on how to contact you by electronic and paper mail.
If the program does terminal interaction, make it output a short
notice like this when it starts in an interactive mode:
- simtrial Copyright (c) 2023 Merck & Co., Inc., Rahway, NJ, USA and its affiliates. All rights reserved.
+ simtrial Copyright (c) 2024 Merck & Co., Inc., Rahway, NJ, USA and its affiliates. All rights reserved.
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
diff --git a/NAMESPACE b/NAMESPACE
index 20a05c2a..c42f556d 100644
--- a/NAMESPACE
+++ b/NAMESPACE
@@ -1,6 +1,7 @@
# Generated by roxygen2: do not edit by hand
export(counting_process)
+export(create_cutting)
export(cut_data_by_date)
export(cut_data_by_event)
export(early_zero)
diff --git a/R/counting_process.R b/R/counting_process.R
index 288a8376..02751327 100644
--- a/R/counting_process.R
+++ b/R/counting_process.R
@@ -1,4 +1,4 @@
-# Copyright (c) 2023 Merck & Co., Inc., Rahway, NJ, USA and its affiliates.
+# Copyright (c) 2024 Merck & Co., Inc., Rahway, NJ, USA and its affiliates.
# All rights reserved.
#
# This file is part of the simtrial program.
diff --git a/R/cut_data_by_date.R b/R/cut_data_by_date.R
index d8224c76..90bc9747 100644
--- a/R/cut_data_by_date.R
+++ b/R/cut_data_by_date.R
@@ -1,4 +1,4 @@
-# Copyright (c) 2023 Merck & Co., Inc., Rahway, NJ, USA and its affiliates.
+# Copyright (c) 2024 Merck & Co., Inc., Rahway, NJ, USA and its affiliates.
# All rights reserved.
#
# This file is part of the simtrial program.
diff --git a/R/cut_data_by_event.R b/R/cut_data_by_event.R
index c17c6d15..3667d8f7 100644
--- a/R/cut_data_by_event.R
+++ b/R/cut_data_by_event.R
@@ -1,4 +1,4 @@
-# Copyright (c) 2023 Merck & Co., Inc., Rahway, NJ, USA and its affiliates.
+# Copyright (c) 2024 Merck & Co., Inc., Rahway, NJ, USA and its affiliates.
# All rights reserved.
#
# This file is part of the simtrial program.
diff --git a/R/early_zero_weight.R b/R/early_zero_weight.R
index 42e769a9..3ee012c6 100644
--- a/R/early_zero_weight.R
+++ b/R/early_zero_weight.R
@@ -1,4 +1,4 @@
-# Copyright (c) 2023 Merck & Co., Inc., Rahway, NJ, USA and its affiliates.
+# Copyright (c) 2024 Merck & Co., Inc., Rahway, NJ, USA and its affiliates.
# All rights reserved.
#
# This file is part of the simtrial program.
diff --git a/R/ex1_delayed_effect.R b/R/ex1_delayed_effect.R
index f8dd7acb..debb3177 100644
--- a/R/ex1_delayed_effect.R
+++ b/R/ex1_delayed_effect.R
@@ -1,4 +1,4 @@
-# Copyright (c) 2023 Merck & Co., Inc., Rahway, NJ, USA and its affiliates.
+# Copyright (c) 2024 Merck & Co., Inc., Rahway, NJ, USA and its affiliates.
# All rights reserved.
#
# This file is part of the simtrial program.
diff --git a/R/ex2_delayed_effect.R b/R/ex2_delayed_effect.R
index 69bd3375..6546d0af 100644
--- a/R/ex2_delayed_effect.R
+++ b/R/ex2_delayed_effect.R
@@ -1,4 +1,4 @@
-# Copyright (c) 2023 Merck & Co., Inc., Rahway, NJ, USA and its affiliates.
+# Copyright (c) 2024 Merck & Co., Inc., Rahway, NJ, USA and its affiliates.
# All rights reserved.
#
# This file is part of the simtrial program.
diff --git a/R/ex3_cure_with_ph.R b/R/ex3_cure_with_ph.R
index 9071b160..20975c4c 100644
--- a/R/ex3_cure_with_ph.R
+++ b/R/ex3_cure_with_ph.R
@@ -1,4 +1,4 @@
-# Copyright (c) 2023 Merck & Co., Inc., Rahway, NJ, USA and its affiliates.
+# Copyright (c) 2024 Merck & Co., Inc., Rahway, NJ, USA and its affiliates.
# All rights reserved.
#
# This file is part of the simtrial program.
diff --git a/R/ex4_belly.R b/R/ex4_belly.R
index 835f10d6..60ce29a2 100644
--- a/R/ex4_belly.R
+++ b/R/ex4_belly.R
@@ -1,4 +1,4 @@
-# Copyright (c) 2023 Merck & Co., Inc., Rahway, NJ, USA and its affiliates.
+# Copyright (c) 2024 Merck & Co., Inc., Rahway, NJ, USA and its affiliates.
# All rights reserved.
#
# This file is part of the simtrial program.
diff --git a/R/ex5_widening.R b/R/ex5_widening.R
index 7e19ec38..c4b489f9 100644
--- a/R/ex5_widening.R
+++ b/R/ex5_widening.R
@@ -1,4 +1,4 @@
-# Copyright (c) 2023 Merck & Co., Inc., Rahway, NJ, USA and its affiliates.
+# Copyright (c) 2024 Merck & Co., Inc., Rahway, NJ, USA and its affiliates.
# All rights reserved.
#
# This file is part of the simtrial program.
diff --git a/R/ex6_crossing.R b/R/ex6_crossing.R
index 5ec12d78..1329db9c 100644
--- a/R/ex6_crossing.R
+++ b/R/ex6_crossing.R
@@ -1,4 +1,4 @@
-# Copyright (c) 2023 Merck & Co., Inc., Rahway, NJ, USA and its affiliates.
+# Copyright (c) 2024 Merck & Co., Inc., Rahway, NJ, USA and its affiliates.
# All rights reserved.
#
# This file is part of the simtrial program.
diff --git a/R/fh_weight.R b/R/fh_weight.R
index 00dc7373..04d998b9 100644
--- a/R/fh_weight.R
+++ b/R/fh_weight.R
@@ -1,4 +1,4 @@
-# Copyright (c) 2023 Merck & Co., Inc., Rahway, NJ, USA and its affiliates.
+# Copyright (c) 2024 Merck & Co., Inc., Rahway, NJ, USA and its affiliates.
# All rights reserved.
#
# This file is part of the simtrial program.
diff --git a/R/fit_pwexp.R b/R/fit_pwexp.R
index 13e0949c..cdd8d140 100644
--- a/R/fit_pwexp.R
+++ b/R/fit_pwexp.R
@@ -1,4 +1,4 @@
-# Copyright (c) 2023 Merck & Co., Inc., Rahway, NJ, USA and its affiliates.
+# Copyright (c) 2024 Merck & Co., Inc., Rahway, NJ, USA and its affiliates.
# All rights reserved.
#
# This file is part of the simtrial program.
diff --git a/R/get_analysis_date.R b/R/get_analysis_date.R
index a703786c..7cbc987a 100644
--- a/R/get_analysis_date.R
+++ b/R/get_analysis_date.R
@@ -1,4 +1,4 @@
-# Copyright (c) 2023 Merck & Co., Inc., Rahway, NJ, USA and its affiliates.
+# Copyright (c) 2024 Merck & Co., Inc., Rahway, NJ, USA and its affiliates.
# All rights reserved.
#
# This file is part of the simtrial program.
diff --git a/R/get_cut_date_by_event.R b/R/get_cut_date_by_event.R
index 1c6c311d..43e7e15d 100644
--- a/R/get_cut_date_by_event.R
+++ b/R/get_cut_date_by_event.R
@@ -1,4 +1,4 @@
-# Copyright (c) 2023 Merck & Co., Inc., Rahway, NJ, USA and its affiliates.
+# Copyright (c) 2024 Merck & Co., Inc., Rahway, NJ, USA and its affiliates.
# All rights reserved.
#
# This file is part of the simtrial program.
diff --git a/R/global.R b/R/global.R
index 79176e64..71c2500d 100644
--- a/R/global.R
+++ b/R/global.R
@@ -1,4 +1,4 @@
-# Copyright (c) 2023 Merck & Co., Inc., Rahway, NJ, USA and its affiliates.
+# Copyright (c) 2024 Merck & Co., Inc., Rahway, NJ, USA and its affiliates.
# All rights reserved.
#
# This file is part of the simtrial program.
diff --git a/R/input_checking.R b/R/input_checking.R
index af17165f..0aa90e69 100644
--- a/R/input_checking.R
+++ b/R/input_checking.R
@@ -1,4 +1,4 @@
-# Copyright (c) 2023 Merck & Co., Inc., Rahway, NJ, USA and its affiliates.
+# Copyright (c) 2024 Merck & Co., Inc., Rahway, NJ, USA and its affiliates.
# All rights reserved.
#
# This file is part of the simtrial program.
diff --git a/R/maxcombo.R b/R/maxcombo.R
index ccad2fff..b9a7f503 100644
--- a/R/maxcombo.R
+++ b/R/maxcombo.R
@@ -1,4 +1,4 @@
-# Copyright (c) 2023 Merck & Co., Inc., Rahway, NJ, USA and its affiliates.
+# Copyright (c) 2024 Merck & Co., Inc., Rahway, NJ, USA and its affiliates.
# All rights reserved.
#
# This file is part of the simtrial program.
@@ -18,38 +18,37 @@
#' Maxcombo test
#'
+#' WARNING: This experimental function is a work-in-progress. The function
+#' arguments will change as we add additional features.
+#'
#' @param data a tte dataset
-#' @param test1 maxcombo test1
-#' @param test2 maxcombo test2
-#' @param ... additional tests
+#' @param rho Numeric vector passed to \code{\link{fh_weight}}. Must be greater
+#' than or equal to zero. Must be the same length as \code{gamma}.
+#' @param gamma Numeric vector passed to \code{\link{fh_weight}}. Must be
+#' greater than or equal to zero. Must be the same length as \code{rho}.
#'
#' @return pvalues
#' @export
#'
+#' @seealso \code{\link{fh_weight}}
+#'
#' @examples
#' sim_pw_surv(n = 200) |>
#' cut_data_by_event(150) |>
-#' maxcombo(test1 = wlr(data, rho = 0, gamma = 0) |> quote(),
-#' test2 = wlr(data, rho = 0, gamma = 0.5) |> quote())
-maxcombo <- function(data, test1, test2, ...){
- all_args <- match.call(expand.dots = FALSE)
- args <- all_args[-1] # Exclude the first element (function name)
-
- n_test <- length(args) - 1
- rho_vector <- NULL
- gamma_vector <- NULL
-
- for (i in 1:n_test) {
- test_i <- get(paste0("test", i))
- rho_vector <- c(rho_vector, test_i$rho)
- gamma_vector <- c(gamma_vector, test_i$gamma)
- }
+#' maxcombo(rho = c(0, 0), gamma = c(0, 0.5))
+maxcombo <- function(data, rho, gamma){
+ stopifnot(
+ is.numeric(rho), is.numeric(gamma),
+ rho >= 0, gamma >= 0,
+ length(rho) == length(gamma)
+ )
ans <- data |>
counting_process(arm = "experimental") |>
fh_weight(
- rho_gamma = data.frame(rho = rho_vector, gamma = gamma_vector),
- return_corr = TRUE)
+ rho_gamma = data.frame(rho = rho, gamma = gamma),
+ return_corr = TRUE
+ )
ans <- data.frame(p_value = pvalue_maxcombo(ans))
diff --git a/R/mb_delayed_effect.R b/R/mb_delayed_effect.R
index 3a3cb042..56580361 100644
--- a/R/mb_delayed_effect.R
+++ b/R/mb_delayed_effect.R
@@ -1,4 +1,4 @@
-# Copyright (c) 2023 Merck & Co., Inc., Rahway, NJ, USA and its affiliates.
+# Copyright (c) 2024 Merck & Co., Inc., Rahway, NJ, USA and its affiliates.
# All rights reserved.
#
# This file is part of the simtrial program.
diff --git a/R/mb_weight.R b/R/mb_weight.R
index ac78791b..7872774d 100644
--- a/R/mb_weight.R
+++ b/R/mb_weight.R
@@ -1,4 +1,4 @@
-# Copyright (c) 2023 Merck & Co., Inc., Rahway, NJ, USA and its affiliates.
+# Copyright (c) 2024 Merck & Co., Inc., Rahway, NJ, USA and its affiliates.
# All rights reserved.
#
# This file is part of the simtrial program.
diff --git a/R/pvalue_maxcombo.R b/R/pvalue_maxcombo.R
index 71308428..273bd862 100644
--- a/R/pvalue_maxcombo.R
+++ b/R/pvalue_maxcombo.R
@@ -1,4 +1,4 @@
-# Copyright (c) 2023 Merck & Co., Inc., Rahway, NJ, USA and its affiliates.
+# Copyright (c) 2024 Merck & Co., Inc., Rahway, NJ, USA and its affiliates.
# All rights reserved.
#
# This file is part of the simtrial program.
diff --git a/R/randomize_by_fixed_block.R b/R/randomize_by_fixed_block.R
index 5d0b0b67..995930ea 100644
--- a/R/randomize_by_fixed_block.R
+++ b/R/randomize_by_fixed_block.R
@@ -1,4 +1,4 @@
-# Copyright (c) 2023 Merck & Co., Inc., Rahway, NJ, USA and its affiliates.
+# Copyright (c) 2024 Merck & Co., Inc., Rahway, NJ, USA and its affiliates.
# All rights reserved.
#
# This file is part of the simtrial program.
diff --git a/R/rpwexp.R b/R/rpwexp.R
index d05cc705..d2011b19 100644
--- a/R/rpwexp.R
+++ b/R/rpwexp.R
@@ -1,4 +1,4 @@
-# Copyright (c) 2023 Merck & Co., Inc., Rahway, NJ, USA and its affiliates.
+# Copyright (c) 2024 Merck & Co., Inc., Rahway, NJ, USA and its affiliates.
# All rights reserved.
#
# This file is part of the simtrial program.
diff --git a/R/rpwexp_enroll.R b/R/rpwexp_enroll.R
index f3d1f6f4..c5e615c7 100644
--- a/R/rpwexp_enroll.R
+++ b/R/rpwexp_enroll.R
@@ -1,4 +1,4 @@
-# Copyright (c) 2023 Merck & Co., Inc., Rahway, NJ, USA and its affiliates.
+# Copyright (c) 2024 Merck & Co., Inc., Rahway, NJ, USA and its affiliates.
# All rights reserved.
#
# This file is part of the simtrial program.
diff --git a/R/rpwexp_naive.R b/R/rpwexp_naive.R
index 64b83d3f..63a93140 100644
--- a/R/rpwexp_naive.R
+++ b/R/rpwexp_naive.R
@@ -1,4 +1,4 @@
-# Copyright (c) 2023 Merck & Co., Inc., Rahway, NJ, USA and its affiliates.
+# Copyright (c) 2024 Merck & Co., Inc., Rahway, NJ, USA and its affiliates.
# All rights reserved.
#
# This file is part of the simtrial program.
diff --git a/R/sim_fixed_n.R b/R/sim_fixed_n.R
index d2e92acd..6348247f 100644
--- a/R/sim_fixed_n.R
+++ b/R/sim_fixed_n.R
@@ -1,4 +1,4 @@
-# Copyright (c) 2023 Merck & Co., Inc., Rahway, NJ, USA and its affiliates.
+# Copyright (c) 2024 Merck & Co., Inc., Rahway, NJ, USA and its affiliates.
# All rights reserved.
#
# This file is part of the simtrial program.
diff --git a/R/sim_gs_n.R b/R/sim_gs_n.R
index b7463903..043ab23c 100644
--- a/R/sim_gs_n.R
+++ b/R/sim_gs_n.R
@@ -1,4 +1,4 @@
-# Copyright (c) 2023 Merck & Co., Inc., Rahway, NJ, USA and its affiliates.
+# Copyright (c) 2024 Merck & Co., Inc., Rahway, NJ, USA and its affiliates.
# All rights reserved.
#
# This file is part of the simtrial program.
@@ -16,13 +16,22 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
-#' Simulate group sequantial designs with fixed sample size
+#' Simulate group sequential designs with fixed sample size
+#'
+#' WARNING: This experimental function is a work-in-progress. The function
+#' arguments will change as we add additional features.
+#'
#' @inheritParams sim_fixed_n
-#' @param test a functional call of the test such as \code{wlr()} or \code{maxcombo()}
-#' @param cutting a functional call of the cutting for IA(s) and FA, see examples
+#' @param test a test function such as \code{\link{wlr}},
+#' \code{\link{maxcombo}}, or \code{\link{rmst}}. The simulated data set is
+#' passed as the first positional argument to the test function provided.
+#' @param cutting a list of cutting functions created by
+#' \code{\link{create_cutting}}, see examples
#' @param seed random seed
+#' @param ... Arguments passed to the test function provided by the argument
+#' \code{test}
#'
-#' @return a data frame summaring the simulation ID, analysis date, z statistics or p-values
+#' @return a data frame summarizing the simulation ID, analysis date, z statistics or p-values
#' @export
#'
#' @examples
@@ -58,12 +67,13 @@
#' # - At least 20 months have elapsed after enrolling 200/400 subjects, with a
#' # minimum of 20 months follow-up
#' # However, if events accumulation is slow, we will wait for a maximum of 24 months.
-#' ia1 <- get_analysis_date(data,
-#' planned_calendar_time = 20,
-#' target_event_overall = 100,
-#' max_extension_for_target_event = 24,
-#' min_n_overall = 200,
-#' min_followup = 20) |> quote()
+#' ia1 <- create_cutting(
+#' planned_calendar_time = 20,
+#' target_event_overall = 100,
+#' max_extension_for_target_event = 24,
+#' min_n_overall = 200,
+#' min_followup = 20
+#' )
#'
#' # IA2
#' # The 2nd interim analysis will occur at the later of the following 3 conditions:
@@ -71,19 +81,21 @@
#' # - At least 250 events have occurred
#' # - At least 10 months after IA1
#' # However, if events accumulation is slow, we will wait for a maximum of 34 months.
-#' ia2 <- get_analysis_date(data,
-#' planned_calendar_time = 32,
-#' target_event_overall = 200,
-#' max_extension_for_target_event = 34,
-#' min_time_after_previous_analysis = 10) |> quote()
+#' ia2 <- create_cutting(
+#' planned_calendar_time = 32,
+#' target_event_overall = 200,
+#' max_extension_for_target_event = 34,
+#' min_time_after_previous_analysis = 10
+#' )
#'
#' # FA
#' # The final analysis will occur at the later of the following 2 conditions:
#' # - At least 45 months have passed since the start of the study
#' # - At least 300 events have occurred
-#' fa <- get_analysis_date(data,
-#' planned_calendar_time = 45,
-#' target_event_overall = 350) |> quote()
+#' fa <- create_cutting(
+#' planned_calendar_time = 45,
+#' target_event_overall = 350
+#' )
#'
#' # Test 1: regular logrank test
#' sim_gs_n(
@@ -91,9 +103,10 @@
#' sample_size = 400,
#' enroll_rate = enroll_rate,
#' fail_rate = fail_rate,
-#' test = wlr(data, weight = fh(rho = 0, gamma = 0)) |> quote(),
+#' test = wlr,
#' cutting = list(ia1 = ia1, ia2 = ia2, fa = fa),
-#' seed = 2024)
+#' seed = 2024,
+#' weight = fh(rho = 0, gamma = 0))
#'
#' # Test 2: weighted logrank test by FH(0, 0.5)
#' sim_gs_n(
@@ -101,9 +114,10 @@
#' sample_size = 400,
#' enroll_rate = enroll_rate,
#' fail_rate = fail_rate,
-#' test = wlr(data, weight = fh(rho = 0, gamma = 0.5)) |> quote(),
+#' test = wlr,
#' cutting = list(ia1 = ia1, ia2 = ia2, fa = fa),
-#' seed = 2024)
+#' seed = 2024,
+#' weight = fh(rho = 0, gamma = 0.5))
#'
#'
#' # Test 3: weighted logrank test by MB(6)
@@ -112,9 +126,10 @@
#' sample_size = 400,
#' enroll_rate = enroll_rate,
#' fail_rate = fail_rate,
-#' test = wlr(data, weight = mb(delay = 3)) |> quote(),
+#' test = wlr,
#' cutting = list(ia1 = ia1, ia2 = ia2, fa = fa),
-#' seed = 2024)
+#' seed = 2024,
+#' weight = mb(delay = 3))
#'
#' # Test 4: weighted logrank test by early zero (6)
#' sim_gs_n(
@@ -122,9 +137,10 @@
#' sample_size = 400,
#' enroll_rate = enroll_rate,
#' fail_rate = fail_rate,
-#' test = wlr(data, weight = early_zero(6)) |> quote(),
+#' test = wlr,
#' cutting = list(ia1 = ia1, ia2 = ia2, fa = fa),
-#' seed = 2024)
+#' seed = 2024,
+#' weight = early_zero(6))
#'
#' # Test 5: RMST
#' sim_gs_n(
@@ -132,9 +148,10 @@
#' sample_size = 400,
#' enroll_rate = enroll_rate,
#' fail_rate = fail_rate,
-#' test = rmst(data, tau = 20) |> quote(),
+#' test = rmst,
#' cutting = list(ia1 = ia1, ia2 = ia2, fa = fa),
-#' seed = 2024)
+#' seed = 2024,
+#' tau = 20)
#'
#' # Test 6: maxcombo (FH(0,0) + FH(0, 0.5))
#' sim_gs_n(
@@ -142,11 +159,11 @@
#' sample_size = 400,
#' enroll_rate = enroll_rate,
#' fail_rate = fail_rate,
-#' test = maxcombo(data,
-#' test1 = wlr(data, rho = 0, gamma = 0) |> quote(),
-#' test2 = wlr(data, rho = 0, gamma = 0.5) |> quote()) |> quote(),
+#' test = maxcombo,
#' cutting = list(ia1 = ia1, ia2 = ia2, fa = fa),
-#' seed = 2024)
+#' seed = 2024,
+#' rho = c(0, 0),
+#' gamma = c(0, 0.5))
sim_gs_n <- function(
# number of simulations
n_sim = 1000,
@@ -168,18 +185,20 @@ sim_gs_n <- function(
block = rep(c("experimental", "control"), 2),
# default is to to logrank testing
# but alternative tests (such as rmst, maxcombo) can be specified
- test = wlr(weight = fh(rho = 0, gamma = 0)) |> quote(),
+ test = wlr,
# cutting for IA(s) and FA
cutting = NULL,
# random seed
- seed = 2024
+ seed = 2024,
+ # arguments passed to `test`
+ ...
){
# input checking
# TODO
# simulate for n_sim times
ans <- NULL
- for (sim_id in 1:n_sim) {
+ for (sim_id in seq_len(n_sim)) {
set.seed(seed + sim_id)
# generate data
simu_data <- sim_pw_surv(
@@ -195,20 +214,16 @@ sim_gs_n <- function(
cut_date <- rep(-100, n_analysis)
ans_1sim <- NULL
- for (i_analysis in 1:n_analysis) {
+ for (i_analysis in seq_len(n_analysis)) {
# get cut date
- if (i_analysis < n_analysis) {
- cut_date[i_analysis] <- cutting[[paste0("ia", i_analysis)]] |> eval(envir = rlang::env(data = simu_data))
- } else {
- cut_date[i_analysis] <- cutting[["fa"]] |> eval(envir = rlang::env(data = simu_data))
- }
+ cut_date[i_analysis] <- cutting[[i_analysis]](data = simu_data)
# cut the data
simu_data_cut <- simu_data |> cut_data_by_date(cut_date[i_analysis])
# test
- ans_1sim_new <- eval(test, envir = rlang::env(data = simu_data_cut))
+ ans_1sim_new <- test(simu_data_cut, ...)
ans_1sim_new$analysis <- i_analysis
ans_1sim_new$cut_date <- cut_date[i_analysis]
ans_1sim_new$sim_id <- sim_id
@@ -221,3 +236,36 @@ sim_gs_n <- function(
}
return(ans)
}
+
+#' Create a cutting function
+#'
+#' Create a cutting function for use with \code{\link{sim_gs_n}}
+#'
+#' @param ... Arguments passed to \code{\link{get_analysis_date}}
+#'
+#' @return A function that accepts a data frame of simulated trial data and
+#' returns a cut date
+#'
+#' @export
+#'
+#' @seealso \code{\link{get_analysis_date}}, \code{\link{sim_gs_n}}
+#'
+#' @examples
+#' # Simulate trial data
+#' trial_data <- sim_pw_surv()
+#'
+#' # Create a cutting function that applies the following 2 conditions:
+#' # - At least 45 months have passed since the start of the study
+#' # - At least 300 events have occurred
+#' cutting <- create_cutting(
+#' planned_calendar_time = 45,
+#' target_event_overall = 350
+#' )
+#'
+#' # Cut the trial data
+#' cutting(trial_data)
+create_cutting <- function(...) {
+ function(data) {
+ get_analysis_date(data, ...)
+ }
+}
diff --git a/R/sim_pw_surv.R b/R/sim_pw_surv.R
index 0c744b2a..f4189957 100644
--- a/R/sim_pw_surv.R
+++ b/R/sim_pw_surv.R
@@ -1,4 +1,4 @@
-# Copyright (c) 2023 Merck & Co., Inc., Rahway, NJ, USA and its affiliates.
+# Copyright (c) 2024 Merck & Co., Inc., Rahway, NJ, USA and its affiliates.
# All rights reserved.
#
# This file is part of the simtrial program.
diff --git a/R/simtrial-package.R b/R/simtrial-package.R
index ec9503a0..6c225d57 100644
--- a/R/simtrial-package.R
+++ b/R/simtrial-package.R
@@ -1,4 +1,4 @@
-# Copyright (c) 2023 Merck & Co., Inc., Rahway, NJ, USA and its affiliates.
+# Copyright (c) 2024 Merck & Co., Inc., Rahway, NJ, USA and its affiliates.
# All rights reserved.
#
# This file is part of the pkglite program.
diff --git a/R/to_sim_pw_surv.R b/R/to_sim_pw_surv.R
index c589c008..537c4f1d 100644
--- a/R/to_sim_pw_surv.R
+++ b/R/to_sim_pw_surv.R
@@ -1,4 +1,4 @@
-# Copyright (c) 2023 Merck & Co., Inc., Rahway, NJ, USA and its affiliates.
+# Copyright (c) 2024 Merck & Co., Inc., Rahway, NJ, USA and its affiliates.
# All rights reserved.
#
# This file is part of the simtrial program.
diff --git a/R/wlr.R b/R/wlr.R
index 3ef300e5..fdd65265 100644
--- a/R/wlr.R
+++ b/R/wlr.R
@@ -1,4 +1,4 @@
-# Copyright (c) 2023 Merck & Co., Inc., Rahway, NJ, USA and its affiliates.
+# Copyright (c) 2024 Merck & Co., Inc., Rahway, NJ, USA and its affiliates.
# All rights reserved.
#
# This file is part of the simtrial program.
@@ -19,9 +19,13 @@
#' Weighted logrank test
#'
#' @param data cutted dataset generated by sim_pw_surv
-#' @param weight weighting functions, such as \code{fh_weight}, \code{mb_weight}, and \code{early_zero_weight}.
+#' @param weight weighting functions, such as \code{\link{fh_weight}},
+#' \code{\link{mb_weight}}, and \code{\link{early_zero_weight}}.
#'
#' @return test results
+#'
+#' @importFrom data.table setDF setDT
+#'
#' @export
#' @examples
#' sim_pw_surv(n = 200) |>
@@ -38,29 +42,35 @@
#'
wlr <- function(data, weight){
- if ("fh" %in% class(weight)) {
+ if (inherits(weight, "fh")) {
ans <- data |>
counting_process(arm = "experimental") |>
fh_weight(rho_gamma = data.frame(rho = weight$rho, gamma = weight$gamma))
- } else if ("mb" %in% class(weight)) {
+ } else if (inherits(weight, "mb")) {
ans <- data |>
counting_process(arm = "experimental") |>
- mb_weight(delay = weight$delay, w_max = weight$w_max) |>
- dplyr::summarize(
- s = sum(o_minus_e * mb_weight),
- v = sum(var_o_minus_e * mb_weight^2),
- z = s / sqrt(v)) |>
- dplyr::select(z)
- } else if ("early_period" %in% class(weight)){
+ mb_weight(delay = weight$delay, w_max = weight$w_max)
+ setDT(ans)
+ ans <- ans[,
+ .(
+ s = sum(o_minus_e * mb_weight),
+ v = sum(var_o_minus_e * mb_weight^2)
+ )
+ ][, .(z = s / sqrt(v))]
+ setDF(ans)
+ } else if (inherits(weight, "early_period")) {
ans <- data |>
counting_process(arm = "experimental") |>
- early_zero_weight(early_period = weight$early_period) |>
- dplyr::summarize(
- s = sum(o_minus_e * weight),
- v = sum(var_o_minus_e * weight^2),
- z = s / sqrt(v)) |>
- dplyr::select(z)
+ early_zero_weight(early_period = weight$early_period)
+ setDT(ans)
+ ans <- ans[,
+ .(
+ s = sum(o_minus_e * weight),
+ v = sum(var_o_minus_e * weight^2)
+ )
+ ][, .(z = s / sqrt(v))]
+ setDF(ans)
}
return(ans)
}
diff --git a/R/wlr_weight.R b/R/wlr_weight.R
index ff03e7ba..f4106407 100644
--- a/R/wlr_weight.R
+++ b/R/wlr_weight.R
@@ -1,4 +1,4 @@
-# Copyright (c) 2023 Merck & Co., Inc., Rahway, NJ, USA and its affiliates.
+# Copyright (c) 2024 Merck & Co., Inc., Rahway, NJ, USA and its affiliates.
# All rights reserved.
#
# This file is part of the simtrial program.
@@ -18,17 +18,15 @@
#' Fleming-Harrington weighting function
#'
-#' @param rho Non-negative number. \code{rho = 0, gamma = 0} is equavalent to regular logrank test.
-#' @param gamma Non-negative number. \code{rho = 0, gamma = 0} is equavalent to regular logrank test.
+#' @param rho Non-negative number. \code{rho = 0, gamma = 0} is equivalent to regular logrank test.
+#' @param gamma Non-negative number. \code{rho = 0, gamma = 0} is equivalent to regular logrank test.
#'
#' @export
#' @return A list of parameters of the Fleming-Harrington weighting function
#' @examples
#' fh(rho = 0, gamma = 0.5)
fh <- function(rho = 0, gamma = 0){
- ans <- list(rho = rho, gamma = gamma)
- class(ans) <- c(class(ans), "fh", "wlr")
- return(ans)
+ structure(list(rho = rho, gamma = gamma), class = c("list", "fh", "wlr"))
}
#' Magirr and Burman weighting function
@@ -45,9 +43,7 @@ fh <- function(rho = 0, gamma = 0){
#' @examples
#' mb(delay = 6, w_max = 2)
mb <- function(delay = 4, w_max = Inf){
- ans <- list(delay = delay, w_max = w_max)
- class(ans) <- c(class(ans), "mb", "wlr")
- return(ans)
+ structure(list(delay = delay, w_max = w_max), class = c("list", "mb", "wlr"))
}
#' Zero early weighting function
@@ -64,7 +60,5 @@ mb <- function(delay = 4, w_max = Inf){
#' @examples
#' early_zero(6)
early_zero <- function(early_period){
- ans <- list(early_period = early_period)
- class(ans) <- c(class(ans), "early_period", "wlr")
- return(ans)
+ structure(list(early_period = early_period), class = c("list", "early_period", "wlr"))
}
diff --git a/_pkgdown.yml b/_pkgdown.yml
index ba44cdad..ac94271d 100644
--- a/_pkgdown.yml
+++ b/_pkgdown.yml
@@ -20,7 +20,7 @@ footer:
left: [developed_by, built_with, legal]
right: [blank]
components:
- legal: "
Copyright © 2023 Merck & Co., Inc., Rahway, NJ, USA and its affiliates. All rights reserved."
+ legal: "
Copyright © 2024 Merck & Co., Inc., Rahway, NJ, USA and its affiliates. All rights reserved."
blank: ""
reference:
@@ -43,6 +43,7 @@ reference:
- cut_data_by_event
- get_cut_date_by_event
- get_analysis_date
+ - create_cutting
- title: "Compute p-values/test statistics"
contents:
diff --git a/man/create_cutting.Rd b/man/create_cutting.Rd
new file mode 100644
index 00000000..9e7b70eb
--- /dev/null
+++ b/man/create_cutting.Rd
@@ -0,0 +1,36 @@
+% Generated by roxygen2: do not edit by hand
+% Please edit documentation in R/sim_gs_n.R
+\name{create_cutting}
+\alias{create_cutting}
+\title{Create a cutting function}
+\usage{
+create_cutting(...)
+}
+\arguments{
+\item{...}{Arguments passed to \code{\link{get_analysis_date}}}
+}
+\value{
+A function that accepts a data frame of simulated trial data and
+returns a cut date
+}
+\description{
+Create a cutting function for use with \code{\link{sim_gs_n}}
+}
+\examples{
+# Simulate trial data
+trial_data <- sim_pw_surv()
+
+# Create a cutting function that applies the following 2 conditions:
+# - At least 45 months have passed since the start of the study
+# - At least 300 events have occurred
+cutting <- create_cutting(
+ planned_calendar_time = 45,
+ target_event_overall = 350
+)
+
+# Cut the trial data
+cutting(trial_data)
+}
+\seealso{
+\code{\link{get_analysis_date}}, \code{\link{sim_gs_n}}
+}
diff --git a/man/fh.Rd b/man/fh.Rd
index 4760a085..9f191609 100644
--- a/man/fh.Rd
+++ b/man/fh.Rd
@@ -7,9 +7,9 @@
fh(rho = 0, gamma = 0)
}
\arguments{
-\item{rho}{Non-negative number. \code{rho = 0, gamma = 0} is equavalent to regular logrank test.}
+\item{rho}{Non-negative number. \code{rho = 0, gamma = 0} is equivalent to regular logrank test.}
-\item{gamma}{Non-negative number. \code{rho = 0, gamma = 0} is equavalent to regular logrank test.}
+\item{gamma}{Non-negative number. \code{rho = 0, gamma = 0} is equivalent to regular logrank test.}
}
\value{
A list of parameters of the Fleming-Harrington weighting function
diff --git a/man/maxcombo.Rd b/man/maxcombo.Rd
index 35e32c75..4159f060 100644
--- a/man/maxcombo.Rd
+++ b/man/maxcombo.Rd
@@ -4,26 +4,29 @@
\alias{maxcombo}
\title{Maxcombo test}
\usage{
-maxcombo(data, test1, test2, ...)
+maxcombo(data, rho, gamma)
}
\arguments{
\item{data}{a tte dataset}
-\item{test1}{maxcombo test1}
+\item{rho}{Numeric vector passed to \code{\link{fh_weight}}. Must be greater
+than or equal to zero. Must be the same length as \code{gamma}.}
-\item{test2}{maxcombo test2}
-
-\item{...}{additional tests}
+\item{gamma}{Numeric vector passed to \code{\link{fh_weight}}. Must be
+greater than or equal to zero. Must be the same length as \code{rho}.}
}
\value{
pvalues
}
\description{
-Maxcombo test
+WARNING: This experimental function is a work-in-progress. The function
+arguments will change as we add additional features.
}
\examples{
sim_pw_surv(n = 200) |>
cut_data_by_event(150) |>
- maxcombo(test1 = wlr(data, rho = 0, gamma = 0) |> quote(),
- test2 = wlr(data, rho = 0, gamma = 0.5) |> quote())
+ maxcombo(rho = c(0, 0), gamma = c(0, 0.5))
+}
+\seealso{
+\code{\link{fh_weight}}
}
diff --git a/man/sim_gs_n.Rd b/man/sim_gs_n.Rd
index 728a7079..4df396b6 100644
--- a/man/sim_gs_n.Rd
+++ b/man/sim_gs_n.Rd
@@ -2,7 +2,7 @@
% Please edit documentation in R/sim_gs_n.R
\name{sim_gs_n}
\alias{sim_gs_n}
-\title{Simulate group sequantial designs with fixed sample size}
+\title{Simulate group sequential designs with fixed sample size}
\usage{
sim_gs_n(
n_sim = 1000,
@@ -12,9 +12,10 @@ sim_gs_n(
fail_rate = data.frame(stratum = "All", duration = c(3, 100), fail_rate = log(2)/c(9,
18), hr = c(0.9, 0.6), dropout_rate = rep(0.001, 2)),
block = rep(c("experimental", "control"), 2),
- test = quote(wlr(weight = fh(rho = 0, gamma = 0))),
+ test = wlr,
cutting = NULL,
- seed = 2024
+ seed = 2024,
+ ...
)
}
\arguments{
@@ -35,17 +36,24 @@ for experimental vs. control, and dropout rates by stratum and time period.}
\item{block}{As in \code{\link[=sim_pw_surv]{sim_pw_surv()}}. Vector of treatments to be included
in each block.}
-\item{test}{a functional call of the test such as \code{wlr()} or \code{maxcombo()}}
+\item{test}{a test function such as \code{\link{wlr}},
+\code{\link{maxcombo}}, or \code{\link{rmst}}. The simulated data set is
+passed as the first positional argument to the test function provided.}
-\item{cutting}{a functional call of the cutting for IA(s) and FA, see examples}
+\item{cutting}{a list of cutting functions created by
+\code{\link{create_cutting}}, see examples}
\item{seed}{random seed}
+
+\item{...}{Arguments passed to the test function provided by the argument
+\code{test}}
}
\value{
-a data frame summaring the simulation ID, analysis date, z statistics or p-values
+a data frame summarizing the simulation ID, analysis date, z statistics or p-values
}
\description{
-Simulate group sequantial designs with fixed sample size
+WARNING: This experimental function is a work-in-progress. The function
+arguments will change as we add additional features.
}
\examples{
library(gsDesign2)
@@ -80,12 +88,13 @@ ratio <- 1 # randomization ratio (exp:col)
# - At least 20 months have elapsed after enrolling 200/400 subjects, with a
# minimum of 20 months follow-up
# However, if events accumulation is slow, we will wait for a maximum of 24 months.
-ia1 <- get_analysis_date(data,
- planned_calendar_time = 20,
- target_event_overall = 100,
- max_extension_for_target_event = 24,
- min_n_overall = 200,
- min_followup = 20) |> quote()
+ia1 <- create_cutting(
+ planned_calendar_time = 20,
+ target_event_overall = 100,
+ max_extension_for_target_event = 24,
+ min_n_overall = 200,
+ min_followup = 20
+)
# IA2
# The 2nd interim analysis will occur at the later of the following 3 conditions:
@@ -93,19 +102,21 @@ ia1 <- get_analysis_date(data,
# - At least 250 events have occurred
# - At least 10 months after IA1
# However, if events accumulation is slow, we will wait for a maximum of 34 months.
-ia2 <- get_analysis_date(data,
- planned_calendar_time = 32,
- target_event_overall = 200,
- max_extension_for_target_event = 34,
- min_time_after_previous_analysis = 10) |> quote()
+ia2 <- create_cutting(
+ planned_calendar_time = 32,
+ target_event_overall = 200,
+ max_extension_for_target_event = 34,
+ min_time_after_previous_analysis = 10
+)
# FA
# The final analysis will occur at the later of the following 2 conditions:
# - At least 45 months have passed since the start of the study
# - At least 300 events have occurred
-fa <- get_analysis_date(data,
- planned_calendar_time = 45,
- target_event_overall = 350) |> quote()
+fa <- create_cutting(
+ planned_calendar_time = 45,
+ target_event_overall = 350
+)
# Test 1: regular logrank test
sim_gs_n(
@@ -113,9 +124,10 @@ sim_gs_n(
sample_size = 400,
enroll_rate = enroll_rate,
fail_rate = fail_rate,
- test = wlr(data, weight = fh(rho = 0, gamma = 0)) |> quote(),
+ test = wlr,
cutting = list(ia1 = ia1, ia2 = ia2, fa = fa),
- seed = 2024)
+ seed = 2024,
+ weight = fh(rho = 0, gamma = 0))
# Test 2: weighted logrank test by FH(0, 0.5)
sim_gs_n(
@@ -123,9 +135,10 @@ sim_gs_n(
sample_size = 400,
enroll_rate = enroll_rate,
fail_rate = fail_rate,
- test = wlr(data, weight = fh(rho = 0, gamma = 0.5)) |> quote(),
+ test = wlr,
cutting = list(ia1 = ia1, ia2 = ia2, fa = fa),
- seed = 2024)
+ seed = 2024,
+ weight = fh(rho = 0, gamma = 0.5))
# Test 3: weighted logrank test by MB(6)
@@ -134,9 +147,10 @@ sim_gs_n(
sample_size = 400,
enroll_rate = enroll_rate,
fail_rate = fail_rate,
- test = wlr(data, weight = mb(delay = 3)) |> quote(),
+ test = wlr,
cutting = list(ia1 = ia1, ia2 = ia2, fa = fa),
- seed = 2024)
+ seed = 2024,
+ weight = mb(delay = 3))
# Test 4: weighted logrank test by early zero (6)
sim_gs_n(
@@ -144,9 +158,10 @@ sim_gs_n(
sample_size = 400,
enroll_rate = enroll_rate,
fail_rate = fail_rate,
- test = wlr(data, weight = early_zero(6)) |> quote(),
+ test = wlr,
cutting = list(ia1 = ia1, ia2 = ia2, fa = fa),
- seed = 2024)
+ seed = 2024,
+ weight = early_zero(6))
# Test 5: RMST
sim_gs_n(
@@ -154,9 +169,10 @@ sim_gs_n(
sample_size = 400,
enroll_rate = enroll_rate,
fail_rate = fail_rate,
- test = rmst(data, tau = 20) |> quote(),
+ test = rmst,
cutting = list(ia1 = ia1, ia2 = ia2, fa = fa),
- seed = 2024)
+ seed = 2024,
+ tau = 20)
# Test 6: maxcombo (FH(0,0) + FH(0, 0.5))
sim_gs_n(
@@ -164,9 +180,9 @@ sim_gs_n(
sample_size = 400,
enroll_rate = enroll_rate,
fail_rate = fail_rate,
- test = maxcombo(data,
- test1 = wlr(data, rho = 0, gamma = 0) |> quote(),
- test2 = wlr(data, rho = 0, gamma = 0.5) |> quote()) |> quote(),
+ test = maxcombo,
cutting = list(ia1 = ia1, ia2 = ia2, fa = fa),
- seed = 2024)
+ seed = 2024,
+ rho = c(0, 0),
+ gamma = c(0, 0.5))
}
diff --git a/man/wlr.Rd b/man/wlr.Rd
index a718f676..8a017f8a 100644
--- a/man/wlr.Rd
+++ b/man/wlr.Rd
@@ -9,7 +9,8 @@ wlr(data, weight)
\arguments{
\item{data}{cutted dataset generated by sim_pw_surv}
-\item{weight}{weighting functions, such as \code{fh_weight}, \code{mb_weight}, and \code{early_zero_weight}.}
+\item{weight}{weighting functions, such as \code{\link{fh_weight}},
+\code{\link{mb_weight}}, and \code{\link{early_zero_weight}}.}
}
\value{
test results
diff --git a/tests/testthat/helper-sim_gs_n.R b/tests/testthat/helper-sim_gs_n.R
new file mode 100644
index 00000000..fe6104da
--- /dev/null
+++ b/tests/testthat/helper-sim_gs_n.R
@@ -0,0 +1,72 @@
+# helper functions used by test-unvalidated-sim_gs_n.R
+
+test_enroll_rate <- function() {
+ # parameters for enrollment
+ enroll_rampup_duration <- 4 # duration for enrollment ramp up
+ enroll_duration <- 16 # total enrollment duration
+ enroll_rate <- gsDesign2::define_enroll_rate(
+ duration = c(enroll_rampup_duration,
+ enroll_duration - enroll_rampup_duration),
+ rate = c(10, 30)
+ )
+ return(enroll_rate)
+}
+
+test_fail_rate <- function() {
+ # parameters for treatment effect
+ delay_effect_duration <- 3 # delay treatment effect in months
+ median_col <- 9 # survival median of the control arm
+ median_exp <- c(9, 14) # survival median of the experimental arm
+ dropout_rate <- 0.001
+ fail_rate <- gsDesign2::define_fail_rate(
+ duration = c(delay_effect_duration, 100),
+ fail_rate = log(2) / median_col,
+ hr = median_col / median_exp,
+ dropout_rate = dropout_rate
+ )
+ return(fail_rate)
+}
+
+test_cutting <- function() {
+ # other related parameters
+ alpha <- 0.025 # type I error
+ beta <- 0.1 # type II error
+ ratio <- 1 # randomization ratio (exp:col)
+ # Define cuttings of 2 IAs and 1 FA
+ # IA1
+ # The 1st interim analysis will occur at the later of the following 3 conditions:
+ # - At least 20 months have passed since the start of the study
+ # - At least 100 events have occurred
+ # - At least 20 months have elapsed after enrolling 200/400 subjects, with a
+ # minimum of 20 months follow-up
+ # However, if events accumulation is slow, we will wait for a maximum of 24 months.
+ ia1 <- create_cutting(
+ planned_calendar_time = 20,
+ target_event_overall = 100,
+ max_extension_for_target_event = 24,
+ min_n_overall = 200,
+ min_followup = 20
+ )
+ # IA2
+ # The 2nd interim analysis will occur at the later of the following 3 conditions:
+ # - At least 32 months have passed since the start of the study
+ # - At least 250 events have occurred
+ # - At least 10 months after IA1
+ # However, if events accumulation is slow, we will wait for a maximum of 34 months.
+ ia2 <- create_cutting(
+ planned_calendar_time = 32,
+ target_event_overall = 200,
+ max_extension_for_target_event = 34,
+ min_time_after_previous_analysis = 10
+ )
+ # FA
+ # The final analysis will occur at the later of the following 2 conditions:
+ # - At least 45 months have passed since the start of the study
+ # - At least 300 events have occurred
+ fa <- create_cutting(
+ planned_calendar_time = 45,
+ target_event_overall = 350
+ )
+
+ return(list(ia1 = ia1, ia2 = ia2, fa = fa))
+}
diff --git a/tests/testthat/test-unvalidated-maxcombo.R b/tests/testthat/test-unvalidated-maxcombo.R
new file mode 100644
index 00000000..a69f64b8
--- /dev/null
+++ b/tests/testthat/test-unvalidated-maxcombo.R
@@ -0,0 +1,21 @@
+# 2024-02-23: Converted `example("maxcombo")` to tests from commit 914c604
+# https://github.com/Merck/simtrial/pull/201/commits/914c6049cf9afb526f2286fdacfabf883050e175
+
+test_that("maxcombo returns consistent results", {
+ set.seed(1)
+ observed <- sim_pw_surv(n = 200) |>
+ cut_data_by_event(150) |>
+ maxcombo(rho = c(0, 0), gamma = c(0, 0.5))
+ expected <- data.frame(p_value = 1.5739680815363144e-06)
+ expect_equal(observed, expected)
+})
+
+test_that("maxcombo fails early with bad input", {
+ input <- observed <- sim_pw_surv(n = 200) |>
+ cut_data_by_event(150)
+ expect_error(maxcombo(input, rho = c(-1, 0), gamma = c(0, 0.5)))
+ expect_error(maxcombo(input, rho = c(0, 0), gamma = c(-1, 0.5)))
+ expect_error(maxcombo(input, rho = letters[1:2], gamma = c(0, 0.5)))
+ expect_error(maxcombo(input, rho = c(0, 0), gamma = letters[1:2]))
+ expect_error(maxcombo(input, rho = c(0), gamma = c(0, 0.5)))
+})
diff --git a/tests/testthat/test-unvalidated-sim_gs_n.R b/tests/testthat/test-unvalidated-sim_gs_n.R
new file mode 100644
index 00000000..c8f11916
--- /dev/null
+++ b/tests/testthat/test-unvalidated-sim_gs_n.R
@@ -0,0 +1,168 @@
+# 2024-02-22: Converted `example("sim_gs_n")` to tests from commit 306de0d
+# https://github.com/Merck/simtrial/tree/306de0dbe380fdb1e906a59f34bf3871d3ee5312
+
+# See helper-sim_gs_n.R for helper functions
+
+test_that("Test 1: regular logrank test", {
+ observed <- sim_gs_n(
+ n_sim = 3,
+ sample_size = 400,
+ enroll_rate = test_enroll_rate(),
+ fail_rate = test_fail_rate(),
+ test = wlr,
+ cutting = test_cutting(),
+ seed = 2024,
+ weight = fh(rho = 0, gamma = 0)
+ )
+ expected <- data.frame(
+ rho = numeric(9),
+ gamma = numeric(9),
+ z = c(
+ -3.7486049782713247, -4.53034007934394, -4.316452743033609,
+ -3.4771440155825752, -3.8631501353780324, -3.2777779731288317,
+ -3.075862925191481, -3.619345457605645, -4.2225917786532925
+ ),
+ analysis = rep(1:3, 3),
+ cut_date = c(24, 32, 45, 24, 32, 46.219327415802894, 24, 32, 50.86585486314699),
+ sim_id = rep(1:3, each = 3L)
+ )
+ expect_equal(observed, expected)
+})
+
+test_that("Test 2: weighted logrank test by FH(0, 0.5)", {
+ observed <- sim_gs_n(
+ n_sim = 3,
+ sample_size = 400,
+ enroll_rate = test_enroll_rate(),
+ fail_rate = test_fail_rate(),
+ test = wlr,
+ cutting = test_cutting(),
+ seed = 2024,
+ weight = fh(rho = 0, gamma = 0.5)
+ )
+ expected <- data.frame(
+ rho = numeric(9),
+ gamma = rep(0.5, 9L),
+ z = c(
+ -4.149161171743935, -4.778107819550277, -4.2607297587160256,
+ -3.605092910242299, -3.945081123231263, -2.919179640988388,
+ -3.1432278107909206, -3.640458610667732, -4.243289152457
+ ),
+ analysis = rep(1:3, 3),
+ cut_date = c(24, 32, 45, 24, 32, 46.219327415802894, 24, 32, 50.86585486314699),
+ sim_id = rep(1:3, each = 3L)
+ )
+ expect_equal(observed, expected)
+})
+
+test_that("Test 3: weighted logrank test by MB(6)", {
+ observed <- sim_gs_n(
+ n_sim = 3,
+ sample_size = 400,
+ enroll_rate = test_enroll_rate(),
+ fail_rate = test_fail_rate(),
+ test = wlr,
+ cutting = test_cutting(),
+ seed = 2024,
+ weight = mb(delay = 3)
+ )
+ expected <- data.frame(
+ z = c(
+ -3.797133894694147, -4.581330588107247, -4.3496437937060906,
+ -3.5011312494121394, -3.886541892591609, -3.2792862684447983,
+ -3.114079263266195, -3.6587146250230145, -4.2632793831797855
+ ),
+ analysis = rep(1:3, 3),
+ cut_date = c(24, 32, 45, 24, 32, 46.219327415802894, 24, 32, 50.86585486314699),
+ sim_id = rep(1:3, each = 3L)
+ )
+ expect_equal(observed, expected)
+})
+
+test_that("Test 4: weighted logrank test by early zero (6)", {
+ observed <- sim_gs_n(
+ n_sim = 3,
+ sample_size = 400,
+ enroll_rate = test_enroll_rate(),
+ fail_rate = test_fail_rate(),
+ test = wlr,
+ cutting = test_cutting(),
+ seed = 2024,
+ weight = early_zero(6)
+ )
+ expected <- data.frame(
+ z = c(
+ -4.552617167258777, -5.188572984743822, -4.686073828268738,
+ -3.185533497487861, -3.5975030245947046, -2.786930008687834,
+ -2.3673440974318556, -3.0630537456426414, -3.7816194091003705
+ ),
+ analysis = rep(1:3, 3),
+ cut_date = c(24, 32, 45, 24, 32, 46.219327415802894, 24, 32, 50.86585486314699),
+ sim_id = rep(1:3, each = 3L)
+ )
+ expect_equal(observed, expected)
+})
+
+test_that("Test 5: RMST", {
+ observed <- sim_gs_n(
+ n_sim = 3,
+ sample_size = 400,
+ enroll_rate = test_enroll_rate(),
+ fail_rate = test_fail_rate(),
+ test = rmst,
+ cutting = test_cutting(),
+ seed = 2024,
+ tau = 20
+ )
+ expected <- data.frame(
+ rmst_arm1 = c(
+ 12.466259284156251, 12.444204897288326, 12.425100778728808,
+ 12.392111715564337, 12.496963791557544, 12.479119007501355, 12.62769367846186,
+ 12.737915554271744, 12.740241766667666
+ ),
+ rmst_arm0 = c(
+ 9.585107633112955, 9.591073977478539, 9.590592780789704, 9.824721964671674,
+ 10.097271436421035, 10.110783864663125, 10.340195893022198,
+ 10.289798076615766, 10.261299533752227
+ ),
+ rmst_diff = c(
+ 2.8811516510432966, 2.8531309198097876, 2.834507997939104, 2.567389750892662,
+ 2.3996923551365086, 2.36833514283823, 2.287497785439662, 2.4481174776559786,
+ 2.478942232915438
+ ),
+ z = c(
+ 3.7899815357169184, 3.991862864282945, 3.980100861311682, 3.474868814723485,
+ 3.2950209410683957, 3.2541151987300845, 2.9805344295194454,
+ 3.3009521580248022, 3.3504301652133
+ ),
+ analysis = rep(1:3, 3),
+ cut_date = c(24, 32, 45, 24, 32, 46.219327415802894, 24, 32, 50.86585486314699),
+ sim_id = rep(1:3, each = 3L)
+ )
+ expect_equal(observed, expected)
+})
+
+test_that("Test 6: maxcombo (FH(0,0) + FH(0, 0.5))", {
+ observed <- sim_gs_n(
+ n_sim = 3,
+ sample_size = 400,
+ enroll_rate = test_enroll_rate(),
+ fail_rate = test_fail_rate(),
+ test = maxcombo,
+ cutting = test_cutting(),
+ seed = 2024,
+ rho = c(0, 0),
+ gamma = c(0, 0.5)
+ )
+ expected <- data.frame(
+ p_value = c(
+ 2.6155386454673746e-05, 1.4330486162172917e-06, 1.247801863046849e-05,
+ 0.0002358380298724816, 6.130077643518028e-05, 0.0007667834024346343,
+ 0.001216230102102256, 0.00020471863687732128, 1.7249355113824194e-05
+ ),
+ analysis = rep(1:3, 3),
+ cut_date = c(24, 32, 45, 24, 32, 46.219327415802894, 24, 32, 50.86585486314699),
+ sim_id = rep(1:3, each = 3L)
+ )
+ expect_equal(observed, expected)
+})