Skip to contents

Run the BOIN design with backfilling (BF-BOIN) of Zhao et al. (2024) over many simulated trials. Dose escalation proceeds in fully staggered cohorts with the BOIN decision table; patients who arrive while the escalation waits for the DLT assessment of its current cohort are backfilled to a lower dose that is safe and has shown a response. Return the patient, DLT, backfill and response counts at every dose together with the duration of each trial.

Usage

bf_boin_simulate(
  target,
  p_true,
  p_resp,
  n_cohort,
  cohort_size,
  window,
  accrual_rate,
  n_cap = 12,
  backfill_dose = c("highest", "lowest"),
  conflict_dose = c("highest", "lowest"),
  no_slot = c("wait", "leave"),
  accrual = c("exponential", "uniform", "fixed"),
  dlt_time = c("weibull", "uniform"),
  late_fraction = 0.5,
  resp_window = window,
  resp_late_fraction = 0.5,
  resp_cor = 0,
  n_trials = 10000,
  start_dose = 1,
  n_earlystop = 18,
  p_saf = NULL,
  p_tox = NULL,
  cutoff_eli = 0.95,
  extrasafe = FALSE,
  offset = 0.05,
  stay_on_1_of_3 = FALSE,
  n_earlystop_rule = c("with_stay", "simple"),
  seed = 123
)

Arguments

target

Numeric scalar. Target DLT probability, for example 0.25.

p_true

Numeric vector. True DLT probability at each dose level, in increasing dose order. The probability of a DLT within the assessment window.

p_resp

Numeric vector of the same length as p_true. True probability of a response within the response window at each dose. A response at or below a dose is what makes the dose eligible for backfilling.

n_cohort

Integer scalar. Number of cohorts in the dose escalation.

cohort_size

Integer scalar or vector. Number of patients per cohort of the dose escalation. A scalar is used for every cohort. A vector shorter than n_cohort is padded with its last element and a longer one is truncated.

window

Numeric scalar. Length of the DLT assessment window.

accrual_rate

Numeric scalar. Average number of patients arriving per unit of time, in the same unit as window.

n_cap

Integer scalar. A dose is no longer backfilled once this many patients, from the dose escalation and from backfilling together, have been treated at it. The dose escalation can still treat patients at the dose. Defaults to 12.

backfill_dose

Character scalar. Which dose receives a backfill patient when several are open: "highest" (the default, as in both articles) or "lowest".

conflict_dose

Character scalar. When the data of several backfilled doses conflict with those of the current dose, which of them anchors the pooled estimate: "highest" (the default here, following Zhao et al., 2024) or "lowest" (the default of be_boin_simulate, following Chen et al., 2026). See the details.

no_slot

Character scalar. What happens to a patient who arrives when neither the dose escalation nor any backfill dose can take a patient: "wait" (the default), the patient waits and is treated as soon as one can, as in tite_boin_simulate; or "leave", the patient is turned away and the trial waits for the next arrival.

accrual

Character scalar. Distribution of the times between arrivals: "exponential" (the default) for a Poisson process, "uniform" for a uniform distribution on (0, 2 / accrual_rate), or "fixed" for arrivals exactly 1 / accrual_rate apart.

dlt_time

Character scalar. Distribution of the time to DLT within the window, and of the time to response within the response window: "weibull" (the default) or "uniform".

late_fraction

Numeric scalar strictly between 0 and 1. Share of the DLTs that occur in the second half of the assessment window under the Weibull distribution. Defaults to 0.5.

resp_window

Numeric scalar. Length of the window within which a response is observed. Defaults to window.

resp_late_fraction

Numeric scalar strictly between 0 and 1. Share of the responses that occur in the second half of the response window under the Weibull distribution. Defaults to 0.5.

resp_cor

Numeric scalar strictly between -1 and 1. Correlation of the Gaussian copula that links the DLT and the response of a patient; a positive value makes a response more likely in a patient with a DLT. Defaults to 0, independence.

n_trials

Integer scalar. Number of trials to simulate. Defaults to 10000.

start_dose

Integer scalar. Dose level for the first cohort. Defaults to 1.

n_earlystop

Integer scalar. The trial stops once this many patients, backfilled ones included, have been treated at the current dose and the design would stay there. Defaults to 18.

p_saf

Numeric scalar. Highest DLT probability deemed subtherapeutic. Defaults to 0.6 * target.

p_tox

Numeric scalar. Lowest DLT probability deemed overly toxic. Defaults to 1.4 * target.

cutoff_eli

Numeric scalar. Posterior probability cutoff for dose elimination. Defaults to 0.95.

extrasafe

Logical scalar. Apply the stricter safety stopping rule at the lowest dose. Defaults to FALSE.

offset

Numeric scalar between 0 and 0.5. Amount by which cutoff_eli is relaxed for the safety stopping rule. Defaults to 0.05.

stay_on_1_of_3

Logical scalar. When TRUE, one DLT out of three patients leads to staying rather than de-escalating, in every use of the decision table. Zhao et al. (2024) use this modification in their main simulation. Defaults to FALSE. See boin_boundary.

n_earlystop_rule

Character scalar, either "with_stay" or "simple". See boin_simulate.

seed

Integer scalar or NULL. Random seed. When NULL the current state of the random number generator is used. The state of the calling session is restored on exit. Defaults to 123.

Value

An object of class c("bf_boin_trials", "backfill_trials"), which is a list with components

n_pts

Integer matrix, n_trials by number of doses, of patients treated, backfilled ones included.

n_tox

Integer matrix of the same shape, of DLTs, counted once every patient has completed the assessment.

n_bf

Integer matrix of the same shape, of backfilled patients.

n_resp

Integer matrix of the same shape, of patients with a response within the response window.

eliminated

Logical matrix of the same shape, marking doses eliminated during the trial.

cohorts_used

Integer vector of dose escalation cohorts treated in each trial.

stop_reason

Character vector giving why each trial ended, with the values of boin_simulate.

duration

Numeric vector. Time from the first arrival until every enrolled patient has completed the DLT assessment.

n_suspensions

Integer vector. Number of dose escalation decisions at which the escalation had to wait.

time_suspended

Numeric vector. Total time the escalation waited.

n_turned_away

Integer vector. Patients turned away, which happens only with no_slot = "leave".

boundary

The boin_boundary object used.

settings

List of the design parameters.

Details

Dose escalation. Cohorts are fully staggered: the next cohort starts only when every patient of the current one has completed the DLT assessment. The decision then follows the BOIN decision table applied to the patients at the current dose who have completed the assessment, backfilled ones included; pending backfill patients are left out, as in Zhao et al. (2024). Dose elimination is checked at the same moments, with the same completed patients, at every dose.

Backfilling. A patient who arrives while the escalation waits is backfilled to the highest dose b (or the lowest, with backfill_dose = "lowest") that is below the current dose, has not been eliminated, has fewer than n_cap patients, and has a response observed at b or at a lower dose. A dose is closed for backfilling when its own DLT rate exceeds the de-escalation boundary and so does the rate pooled with the next higher dose; the doses above it close with it. The rules are evaluated whenever a patient arrives, so a closed dose reopens when new data no longer meet the closing condition.

Conflicts. When the data of a backfilled dose b below the current dose call for a more conservative decision than those of the current dose (Table 2 of Zhao et al., 2024), the decision is taken instead from the data pooled from dose b* to the current dose, where b* is the highest conflicting dose by default. A de-escalation then goes to the highest dose k at or above b* whose data pooled from b* stay at or below the de-escalation boundary, or to b* - 1 if there is none, and to the lowest dose if b* is the lowest.

End of the trial. The trial stops when the escalation has treated n_cohort cohorts, when n_earlystop is reached with a decision to stay, or when the lowest dose is eliminated. Backfilling stops with the escalation. Every enrolled patient is followed to the end of the assessment, and the data of all patients, backfilled ones included, are those from which the MTD is selected.

Arrivals and outcomes. Patients arrive one at a time. The DLT of a patient and its time follow p_true and dlt_time as in tite_boin_simulate; the response and its time follow p_resp, resp_window and resp_late_fraction in the same way, linked to the DLT by resp_cor. Neither article states how responses are timed or correlated with DLTs. The Weibull time to response with half of the responses in the second half of the window and the Gaussian copula follow Takeda et al. (2025), who set the correlation to 0.2; the default here is independence.

Random numbers. The DLT variates of the escalation patients are drawn from R's stream exactly as in boin_simulate; arrivals and the variates of backfill patients and of responses come from two generators of their own seeded with seed. As a result, when no dose is ever opened for backfilling, for example with every p_resp equal to 0, the trials are identical to those of boin_simulate with the same seed.

Agreement with the article. With stay_on_1_of_3 = TRUE, n_earlystop = 9, accrual = "uniform" and no_slot = "leave", the operating characteristics of Table 4 of Zhao et al. (2024) are reproduced within simulation error, durations included. The article states a Poisson process, but its durations, for BOIN as well as for BF-BOIN, agree with uniform times between arrivals and patients turned away while the escalation waits. The trial example of Figure 1 of the article is replayed patient by patient in the tests of the package.

References

Zhao, Y., Yuan, Y., Korn, E. L. and Freidlin, B. (2024). Backfilling Patients in Phase I Dose-Escalation Trials Using Bayesian Optimal Interval Design (BOIN). Clinical Cancer Research, 30(4), 673-679.

Chen, K., Zhao, Y., Takeda, K. and Yuan, Y. (2026). BE-BOIN: A Dose Optimization Design Accommodating Backfill and Late-Onset Toxicity. Therapeutic Innovation and Regulatory Science. doi:10.1007/s43441-026-00994-0

Takeda, K., Zhu, J. and Hirakawa, A. (2025). BF-BOIN-ET: A Backfill Bayesian Optimal Interval Design Using Efficacy and Toxicity Outcomes for Dose Optimization. Pharmaceutical Statistics, 24(2), e2470.

Examples

# Scenario 3 of Zhao et al. (2024)
trials <- bf_boin_simulate(
  target = 0.25,
  p_true = c(0.04, 0.12, 0.25, 0.43, 0.63),
  p_resp = c(0.10, 0.20, 0.30, 0.45, 0.58),
  n_cohort = 10,
  cohort_size = 3,
  window = 1,
  accrual_rate = 3,
  n_earlystop = 9,
  stay_on_1_of_3 = TRUE,
  n_trials = 200,
  seed = 123
)
trials
#> Simulated BF-BOIN (Zhao et al., 2024) trials
#>   trials          : 200
#>   doses           : 5
#>   target DLT rate : 0.25
#>   cohorts         : 10 of size 3
#>   escalation size : 30
#>   backfill cap    : 12 patients per dose
#>   window          : 1 (DLT), 1 (response)
#>   accrual         : 3 patients per unit of time (exponential)
#> 
#> Average per trial:
#>                        DL1   DL2  DL3  DL4  DL5
#> Patients treated      6.35 10.96 9.29 3.36 0.28
#>   of which backfilled 1.79  3.36 1.98 0.17 0.00
#> DLTs observed         0.28  1.36 2.34 1.47 0.20
#> Responses             0.62  2.20 2.84 1.56 0.20
#> 
#> Patients per trial    : mean 30.24, of which backfilled 7.3
#> Trials with backfill  : 83.5%
#> Trial duration        : mean 13.64, median 13.78
#> Escalation waiting    : 100% of trials, mean time 5.51 per trial
#> 
#> Stopping reason (%):
#> 
#> max_sample_size     n_earlystop 
#>            27.5            72.5 

colMeans(trials$n_bf)
#>   DL1   DL2   DL3   DL4   DL5 
#> 1.790 3.360 1.980 0.175 0.000