---
title: "Design-informed truncation time selection"
author: "Xinyue Zhao, Haitao Pan"
output: rmarkdown::html_vignette
vignette: >
  %\VignetteIndexEntry{Design-informed truncation time selection}
  %\VignetteEngine{knitr::rmarkdown}
  %\VignetteEncoding{UTF-8}
---

```{r setup, include = FALSE}
knitr::opts_chunk$set(collapse = TRUE, comment = "#>")
library(AHTauDesign)

## Precomputed full-setting results, generated by
## data-raw/precomputed.R (not run at build time).
prec_file <- "precomputed_results.rds"
if (!file.exists(prec_file)) {
  prec_file <- file.path("vignettes", prec_file)
}
pre <- readRDS(prec_file)
```

## Introduction

This vignette contains **two kinds of output**, and it is important to
distinguish them.

1. A **quick toy example**, executed when this vignette is built. It uses
   `n_sim = 10`, `n_boot = 10` and a coarse `tau_grid` so that the vignette
   builds in seconds. It illustrates the *workflow and function usage only*.
   Its numerical results are based on far too few simulated trials and
   bootstrap resamples to be stable, and **should not be interpreted as
   simulation or inferential results.**

2. **Precomputed full-setting results**, using `r pre$meta$n_sim` simulated
   trials and `r pre$meta$n_boot` bootstrap resamples per trial. The complete
   code producing each result is shown but not evaluated at build time; the
   stored output is displayed instead. All substantive statements in the text
   below refer to these results.

Every precomputed result is reproducible after a single `set.seed()` call with
seed 202608. Precomputed blocks are marked *Precomputed*; the toy
block is marked *Toy example*.

## Quick start: a runnable toy example

> **Toy example.** `n_sim = 10`, `n_boot = 10`, coarse `tau_grid`. These
> settings exist so the vignette builds quickly. The feasibility
> classifications and selected truncation time produced here are unstable and
> are *not* the results discussed in the rest of this vignette.

```{r toy-twostage}
set.seed(202608)
toy_result <- twostage_tau(
  N = 60, A = 24, F_followup = 6,
  tau_clin = 24,
  tau_grid = seq(6, 24, by = 6),
  effect_model = list(type = "ph", lambda0 = -log(0.5) / 24, HR = 0.5),
  delta = 12, epsilon = 0.05,
  n_sim = 10, n_boot = 10)

toy_result

```

For real design work, use the package defaults (`n_sim = 100`, `n_boot = 100`) or larger, with a finer `tau_grid`. Everything below uses those settings.          



## The planned design

We use a single running example: a two-arm trial with 60 participants, 24 months of accrual, and 6 additional months of follow-up, under a **proportional-hazards** effect with a hazard ratio of 0.5.     

```{r}
effect_model <- list(type = "ph", lambda0 = -log(0.5) / 24, HR = 0.5)
```

## Stage 1: assessing the clinically proposed truncation time

The clinical team has proposed a truncation time of 24 months.

```{r stage1-code, eval = FALSE}
set.seed(202608)
assess_tau(
  N = 60, A = 24, F_followup = 6,
  tau = 24,
  effect_model = effect_model,
  n_sim = 100, n_boot = 100)

```

```{r stage1-show, echo = FALSE}
pre$assess_base
```

*Precomputed (`r pre$meta$n_sim` simulations, `r pre$meta$n_boot` bootstrap resamples).* 

This output can be summarized as follows: 

$\quad$ For a trial with (N = 60), a 24-month accrual period, and only 6 months of additional follow-up, the statistic at 24 months could be successfully computed in all simulation runs. However, only approximately nine patients in total were expected to remain in the risk set at that time point, with about four to five patients in each treatment arm. This provides severely insufficient statistical support. Therefore, the clinically specified truncation time, ($\tau_{clin} = 24$) months, was deemed infeasible. Importantly, this failure was driven primarily by the limited follow-up design, rather than by an inadequate treatment effect or a failure of the computational procedure.                      

## How can ($\tau = 24$) months be made feasible?

There are three main ways to improve the feasibility of using $\tau = 24$ months.              

### Approach 1: increase the additional follow-up period

The most direct solution is to increase the additional follow-up period. For example, if $$F = 6 $$
is increased to approximately $$F = 24 ,$$
then even the last enrolled patient would have the opportunity to complete 24 months of follow-up.      

$\quad$ Under this design, nearly all patients could potentially contribute to the risk set at 24 months. The expected total risk-set size would therefore increase substantially, from approximately 9 patients to approximately 36 patients: 
$$30 \times 0.5 + 30 \times 0.707 \approx 36.2.$$    

$\quad$ Thus, extending the additional follow-up period is the most direct and efficient way to make ($\tau = 24$) months feasible.          

```{r approach1-code, eval = FALSE}
set.seed(202608)
assess_tau(N = 60, A = 24, F_followup = 24, tau = 24,
           effect_model = effect_model,
           n_sim = 100, n_boot = 100)

```

```{r approach1-show, echo = FALSE}
pre$assess_long_fu

```

*Precomputed (`r pre$meta$n_sim` simulations, `r pre$meta$n_boot` bootstrap resamples).* 

    
### Approach 2: select an earlier truncation time

Another solution is to use an earlier truncation time.

Under the current design: 

- At ($\tau = 12$) months, approximately 75\% of patients have the opportunity to reach the specified follow-up time.  
- At ($\tau = 18$) months, approximately 50\% of patients have the opportunity to reach the specified follow-up time. 

- At ($\tau = 24$) months, approximately 25\% of patients have the opportunity to reach the specified follow-up time. 

Therefore, optimize\_tau() would likely identify a feasible or optimal truncation time substantially earlier than 24 months, possibly some where within the range of 12 to 18 months.       

```{r approach2-code, eval = FALSE}
set.seed(202608)
assess_tau(N = 60, A = 24, F_followup = 6, tau = 12,
           effect_model = effect_model,
           n_sim = 100, n_boot = 100)

```

```{r approach2-show, echo = FALSE}
pre$assess_tau12

```

*Precomputed (`r pre$meta$n_sim` simulations, `r pre$meta$n_boot` bootstrap resamples).* 

This approach improves statistical support at the cost of evaluating treatment effects over a shorter time horizon.   

### Approach 3: increase the sample size

Increasing the sample size also increases the number of patients remaining in the risk set at 24 months.   

$\quad$ Under the current design, the expected proportion of patients remaining in the risk set at 24 months is only approximately $$0.15.$$      

$\quad$ Therefore, to obtain an expected risk-set of approximately 30 patients, the required total sample size would be roughly $$N \approx \frac{30}{0.15} \approx 200.$$

```{r approach3-code, eval = FALSE}
set.seed(202608)
assess_tau(N = 200, A = 24, F_followup = 6, tau = 24,
           effect_model = effect_model,
           n_sim = 100, n_boot = 100)

```

```{r approach3-show, echo = FALSE}
pre$assess_n200

```

*Precomputed (`r pre$meta$n_sim` simulations, `r pre$meta$n_boot` bootstrap resamples).* 

$\quad$ The rough calculation suggests that approximately ($N = 200$) patients would be needed to obtain an expected risk-set size near 30 at ($\tau = 24$) months. In the Monte Carlo assessment, ($N = 200$) produced an expected total risk-set size of 29.9 and was classified as Borderline. This near-threshold result illustrates that increasing sample size can improve support, but sample-size increase alone may be inefficient when the fundamental limitation is that few patients have sufficient follow-up to contribute information at the 24-month truncation time.        

### Customizing the hard-failure rules

The built-in rules can be inspected directly:

```{r}
default_fail_thresholds()

```

A user running an exploratory pilot may accept weaker support, and can
override any subset of them:

```{r relaxed-code, eval = FALSE}
set.seed(202608)
assess_tau(N = 60, A = 24, F_followup = 6, tau = 24,
           effect_model = effect_model,
           fail_thresholds = list(total_risk = 5, arm_risk = 2),
           n_sim = 100, n_boot = 100)

```

```{r relaxed-show, echo = FALSE}
pre$assess_relaxed

```

*Precomputed (`r pre$meta$n_sim` simulations, `r pre$meta$n_boot` bootstrap resamples).*

Unspecified elements keep their defaults. Relaxing a rule changes only the
classification, not the underlying statistical support.



## Function "optimize\_tau()": feasibility-constrained optimization   

```{r optimize-code, eval = FALSE}
set.seed(202608)
optimize_tau(
  N = 60, A = 24, F_followup = 6,
  tau_clin = 24,
  tau_grid = seq(6, 36, by = 3),
  effect_model = effect_model,
  delta = 12, epsilon = 0.05,
  n_sim = 100, n_boot = 100)

```

```{r optimize-show, echo = FALSE}
pre$optimization

```

*Precomputed (`r pre$meta$n_sim` simulations, `r pre$meta$n_boot` bootstrap resamples).*  

$\quad$ The clinically proposed truncation time of 24 months failed the prespecified feasibility criteria because of inadequate risk-set support. Among the candidate truncation times satisfying both the feasibility requirements and the prespecified 12-month clinical-distance constraint, 12 months was the only admissible candidate and was therefore selected as the final truncation time.               

## The complete two-stage workflow

```{r twostage-code, eval = FALSE}
set.seed(202608)
result <- twostage_tau(
  N = 60, A = 24, F_followup = 6,
  tau_clin = 24,
  tau_grid = seq(6, 36, by = 3),
  effect_model = effect_model,
  delta = 12, epsilon = 0.05,
  n_sim = 100, n_boot = 100)

summary(result)

```

```{r twostage-show, echo = FALSE}
result <- pre$twostage
summary(result)

```

*Precomputed (`r pre$meta$n_sim` simulations, `r pre$meta$n_boot` bootstrap resamples).* 

$\quad$ Under the planned design with 60 participants, 24 months of accrual, and 6 additional months of follow-up, the clinically proposed truncation time of 24 months failed the Stage 1 feasibility assessment because of inadequate risk-set support. The truncation times of 6, 9, and 12 months passed the feasibility criteria, but only 12 months fell within the prespecified clinical-distance tolerance of 12 months from the proposed clinical time. Thus, 12 months was the only admissible candidate and was selected as the
final truncation time. An independent evaluation confirmed that the selected 12-month time remained feasible, whereas the original 24-month clinical time remained infeasible.

```{r fig.width = 7, fig.height = 4.5}
plot(result)
```


### Why is one table called the independent evaluation table?      

$\quad$ $\tau^{\star}$ is chosen as the best of many candidates, so its performance in the **selection table** is subject to the winner's curse. The **independent evaluation** therefore re-simulates fresh trials and evaluates only the clinical time and the already-fixed $\tau^{\star}$, which gives unbiased estimates for the design that was selected.     



