Package {simFastBOIN}


Type: Package
Title: Fast Simulation of Bayesian Optimal Interval Designs for Phase I Trials
Version: 2.0.0
Date: 2026-09-18
Description: Design and evaluate phase I dose-finding trials that use the Bayesian optimal interval (BOIN) design of Liu and Yuan (2015) <doi:10.1111/rssc.12089>. Functions are provided to tabulate the decision boundaries, to simulate trials, to estimate the dose-toxicity curve under a monotonicity constraint and to select the maximum tolerated dose. The simulation engine is written in C++ and draws one random variate per patient in enrollment order, which reproduces the reference implementation in the 'BOIN' package trial by trial for a given seed. The traditional 3+3 design is provided as a comparator, with operating characteristics obtained in closed form rather than by simulation.
License: MIT + file LICENSE
Encoding: UTF-8
Depends: R (≥ 3.5.0)
Imports: Rcpp (≥ 1.0.0), stats, utils
LinkingTo: Rcpp
Suggests: BOIN, ggplot2 (≥ 3.4.0), Iso, knitr, rmarkdown, spelling, testthat (≥ 3.0.0)
Language: en-US
URL: https://github.com/gosukehommaEX/simFastBOIN
BugReports: https://github.com/gosukehommaEX/simFastBOIN/issues
Config/testthat/edition: 3
VignetteBuilder: knitr
Config/roxygen2/version: 8.0.0
NeedsCompilation: yes
Packaged: 2026-09-18 11:34:37 UTC; i_lik
Author: Gosuke Homma ORCID iD [aut, cre]
Maintainer: Gosuke Homma <my.name.is.gosuke@gmail.com>
Repository: CRAN
Date/Publication: 2026-09-18 15:00:13 UTC

simFastBOIN: Fast Simulation of Bayesian Optimal Interval Designs

Description

Tools for designing and evaluating phase I dose-finding trials that use the Bayesian optimal interval (BOIN) design of Liu and Yuan (2015). The simulation engine is written in C++ and reproduces the reference implementation in the BOIN package exactly, including the order in which random variates are consumed, so that results obtained with the same seed agree to the last trial.

Design tools

boin_lambda

Escalation and de-escalation interval boundaries.

boin_p_tox

The toxic threshold giving a required de-escalation boundary.

boin_boundary

Integer decision boundaries as a function of sample size.

boin_decision_table

Decision table indexed by DLTs and patients, with print and plot methods.

boin_stopping_table

Safety stopping boundary as a two-row table.

Simulation tools

sim_boin

Operating characteristics for one scenario.

sim_boin_multi

Operating characteristics for several scenarios.

boin_simulate

Raw trial data from the simulation engine.

boin_isotonic

Isotonic estimates of the DLT probability.

boin_select_mtd

MTD selection from completed trials.

The 3+3 design

oc_3p3

Operating characteristics of the traditional 3+3 design, in closed form.

sim_3p3

The same design by simulation, as a check on the closed form.

Author(s)

Maintainer: Gosuke Homma my.name.is.gosuke@gmail.com (ORCID)

Authors:

References

Liu S. and Yuan, Y. (2015). Bayesian Optimal Interval Designs for Phase I Clinical Trials. Journal of the Royal Statistical Society: Series C, 64, 507-523.

Yan, F., Zhang, L., Zhou, Y., Pan, H., Liu, S. and Yuan, Y. (2020). BOIN: An R Package for Designing Single-Agent and Drug-Combination Dose-Finding Trials Using Bayesian Optimal Interval Designs. Journal of Statistical Software, 94(13), 1-32.

See Also

Useful links:


Coerce BOIN Decision Boundaries to a Data Frame

Description

Return the integer decision boundaries produced by boin_boundary as one row per sample size.

Usage

## S3 method for class 'boin_boundary'
as.data.frame(x, row.names = NULL, optional = FALSE, ...)

Arguments

x

An object of class boin_boundary.

row.names

Passed on for compatibility with the generic, normally unused.

optional

Passed on for compatibility with the generic, normally unused.

...

Further arguments, currently ignored.

Value

A data frame with columns n_pts, escalate_if_dlt_leq, deescalate_if_dlt_geq and eliminate_if_dlt_geq, plus stop_if_dlt_geq when the boundaries were built with extrasafe = TRUE.

Examples

bd <- boin_boundary(target = 0.30, max_n = 18)
as.data.frame(bd)[seq(3, 18, by = 3), ]


Integer Decision Boundaries for the BOIN Design

Description

Tabulate, for every attainable number of patients treated at a dose, the number of DLTs that triggers escalation, de-escalation, elimination and, when requested, the stricter safety stopping rule at the lowest dose.

Usage

boin_boundary(
  target,
  max_n,
  p_saf = NULL,
  p_tox = NULL,
  cutoff_eli = 0.95,
  extrasafe = FALSE,
  offset = 0.05,
  stay_on_1_of_3 = FALSE
)

Arguments

target

Numeric scalar. Target DLT probability, for example 0.30.

max_n

Integer scalar. Largest number of patients that can be treated at a single dose, which is the number of columns of the resulting table. For a trial with n_cohort cohorts of size cohort_size this is n_cohort * cohort_size.

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 above which a dose is eliminated for toxicity. Defaults to 0.95.

extrasafe

Logical scalar. When TRUE, also tabulate the safety stopping boundary applied 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 at the current dose rather than de-escalating. Defaults to FALSE. See the details.

Details

The escalation boundary is floor(lambda_e * n) and the de-escalation boundary is ceiling(lambda_d * n), with the convention that when lambda_d * n is a whole number de-escalation requires one more DLT. The elimination boundary is the smallest positive number of DLTs for which Pr(p > target | data) exceeds cutoff_eli under a uniform Beta(1, 1) prior, and is not evaluated before three patients have been treated. The de-escalation boundary is capped at the elimination boundary.

With the default thresholds these definitions reproduce BOIN::get.boundary() exactly.

Value

An object of class boin_boundary, which is a list with components

lambda_e

Escalation interval boundary.

lambda_d

De-escalation interval boundary.

n

Number of patients, 1 to max_n.

b_esc

Escalate when the number of DLTs is at most this value.

b_deesc

De-escalate when the number of DLTs reaches this value.

b_elim

Eliminate the dose when the number of DLTs reaches this value, NA when no elimination is possible at that sample size.

b_stop

Safety stopping boundary at the lowest dose, all NA unless extrasafe is TRUE.

stay_on_1_of_3

Whether the modification was requested.

stay_on_1_of_3_applied

Whether it changed the boundaries.

together with the design parameters used.

Staying on one DLT out of three

For some target rates the optimal BOIN decision after one DLT in three patients is to de-escalate, because the likelihood of overdosing then exceeds the likelihood of proper dosing. Long practice with the 3+3 design has nonetheless made staying at the dose the widely accepted choice, and stay_on_1_of_3 = TRUE aligns the design with that practice by raising the de-escalation boundary at three patients from one DLT to two. Nothing else in the table changes.

The modification is applied only where it is meaningful, that is when one DLT out of three currently triggers de-escalation. It never overrides an escalation, and it never overrides an elimination, which is a safety rule. Whether it took effect is reported in stay_on_1_of_3_applied. With the default thresholds it takes effect for target rates from about 0.098 to 0.279; below that range one DLT out of three already eliminates the dose, and above it the design already stays.

References

Liu S. and Yuan, Y. (2015). Bayesian Optimal Interval Designs for Phase I Clinical Trials. Journal of the Royal Statistical Society: Series C, 64, 507-523.

See Also

boin_lambda, boin_decision_table

Examples

bd <- boin_boundary(target = 0.30, max_n = 18)
bd

# At a target of 0.25 one DLT out of three de-escalates by default
boin_boundary(target = 0.25, max_n = 18)$b_deesc[3]

# and stays once the modification is switched on
modified <- boin_boundary(target = 0.25, max_n = 18, stay_on_1_of_3 = TRUE)
modified$b_deesc[3]
modified$stay_on_1_of_3_applied

# At a target of 0.30 the design already stays, so nothing changes
boin_boundary(target = 0.30, max_n = 18, stay_on_1_of_3 = TRUE)$stay_on_1_of_3_applied


Decision Table for the BOIN Design

Description

Build the lookup table that maps a pair of DLT and patient counts at the current dose to the dose assignment decision.

Usage

boin_decision_table(
  target,
  max_n,
  p_saf = NULL,
  p_tox = NULL,
  cutoff_eli = 0.95,
  stay_on_1_of_3 = FALSE
)

Arguments

target

Numeric scalar. Target DLT probability.

max_n

Integer scalar. Largest number of patients treated at a single dose.

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.

stay_on_1_of_3

Logical scalar. When TRUE, one DLT out of three patients leads to staying at the current dose rather than de-escalating. Defaults to FALSE. See boin_boundary for what the modification does.

Details

The table is derived from boin_boundary and therefore agrees with the decisions taken by the simulation engine. Elimination takes precedence over the other rules, then escalation, then de-escalation.

Value

An object of class boin_decision_table, which is a character matrix with max_n + 1 rows, labeled by the number of DLTs from 0 to max_n, and max_n columns, labeled by the number of patients from 1 to max_n. Entries are "E" to escalate, "S" to stay, "D" to de-escalate and "DE" to de-escalate and eliminate the dose together with all higher doses. Combinations with more DLTs than patients are NA. The object has print and plot methods; subsetting it returns a plain matrix.

See Also

boin_boundary, plot.boin_decision_table

Examples

decisions <- boin_decision_table(target = 0.30, max_n = 12)
decisions

# Only the sample sizes reached at the end of a cohort of three
print(decisions, cohort_size = 3)

# One DLT out of three de-escalates at a target of 0.25
boin_decision_table(target = 0.25, max_n = 9)["1", "3"]

# and stays once the modification is switched on
boin_decision_table(target = 0.25, max_n = 9, stay_on_1_of_3 = TRUE)["1", "3"]


Isotonic Estimates of the DLT Probability

Description

Estimate the DLT probability at each dose under the constraint that toxicity does not decrease with dose, using the pool adjacent violators algorithm.

Usage

boin_isotonic(n_pts, n_tox, admissible = NULL)

Arguments

n_pts

Integer matrix with one row per trial and one column per dose, or a vector for a single trial, giving the number of patients treated.

n_tox

Integer matrix or vector of the same shape as n_pts, giving the number of DLTs observed.

admissible

Logical matrix of the same shape as n_pts, or NULL. Doses that are FALSE are left out of the estimation and returned as NA. Defaults to all doses that have treated at least one patient.

Details

Pseudo-counts of 0.05 DLTs and 0.1 patients are added before the fit, and doses are pooled with inverse variance weights. Doses left out through admissible do not influence the estimates of the remaining doses, which matters when eliminated doses must be excluded before selecting the MTD.

Value

A numeric matrix with one row per trial and one column per dose. Doses that did not enter the estimation are NA.

References

Liu S. and Yuan, Y. (2015). Bayesian Optimal Interval Designs for Phase I Clinical Trials. Journal of the Royal Statistical Society: Series C, 64, 507-523.

See Also

boin_select_mtd

Examples

# A single trial
boin_isotonic(n_pts = c(3, 6, 9, 12), n_tox = c(0, 1, 3, 4))

# Several trials at once
n_pts <- matrix(c(3, 6, 9, 12,
                  3, 6, 9, 12,
                  3, 6, 9, 12), nrow = 3, byrow = TRUE)
n_tox <- matrix(c(0, 1, 3, 4,
                  0, 0, 2, 3,
                  1, 2, 4, 6), nrow = 3, byrow = TRUE)
boin_isotonic(n_pts, n_tox)


Escalation and De-escalation Interval Boundaries

Description

Compute the two boundaries that define the BOIN decision interval. A dose is escalated when the observed DLT rate falls at or below lambda_e and de-escalated when it reaches lambda_d.

Usage

boin_lambda(target, p_saf = NULL, p_tox = NULL)

Arguments

target

Numeric scalar. Target DLT probability, for example 0.30.

p_saf

Numeric scalar. Highest DLT probability deemed subtherapeutic, so that dose escalation should be undertaken. Defaults to 0.6 * target.

p_tox

Numeric scalar. Lowest DLT probability deemed overly toxic, so that dose de-escalation is required. Defaults to 1.4 * target.

Details

The boundaries minimize the probability of incorrect dose assignment under a three-point hypothesis on the DLT probability at the current dose. Values of p_saf and p_tox close to target should be avoided, because the sample sizes of phase I trials cannot distinguish the target rate from rates close to it.

Value

A list with components lambda_e and lambda_d.

References

Liu S. and Yuan, Y. (2015). Bayesian Optimal Interval Designs for Phase I Clinical Trials. Journal of the Royal Statistical Society: Series C, 64, 507-523.

Examples

boin_lambda(target = 0.30)

boin_lambda(target = 0.25, p_saf = 0.12, p_tox = 0.40)


Toxic Threshold Giving a Required De-escalation Boundary

Description

Find the value of p_tox for which the BOIN de-escalation boundary lambda_d equals a required value. This inverts boin_lambda, which maps p_tox to lambda_d.

Usage

boin_p_tox(target, lambda_d)

Arguments

target

Numeric scalar. Target DLT probability.

lambda_d

Numeric scalar. Required de-escalation boundary. Must lie strictly between target and 1.

Details

lambda_d increases strictly with p_tox, from target in the limit as p_tox approaches target to 1 in the limit as p_tox approaches 1, so the solution exists and is unique for any lambda_d strictly between those bounds. The root is found numerically.

A boundary close to the target needs a toxic threshold close to the target, and the rest of the package refuses a p_tox within ten percent of target, on the grounds that phase I sample sizes cannot tell the two rates apart. The value is still returned, since the inversion is well defined, but a warning names the smallest boundary that leaves a usable threshold. For a target of 0.30 that smallest boundary is about 0.315.

A design team that wants to tighten the de-escalation boundary usually states the boundary rather than the threshold behind it. This function turns that statement into the p_tox to pass to the other functions, so that the whole design follows from it.

Value

A numeric scalar, the value of p_tox that produces lambda_d.

See Also

boin_lambda, boin_boundary

Examples

# A target of 0.30 gives a de-escalation boundary of 0.359 by default
boin_lambda(target = 0.30)$lambda_d

# The toxic threshold that tightens it to 0.33
p_tox <- boin_p_tox(target = 0.30, lambda_d = 0.33)
p_tox

# which is what it claims to be
boin_lambda(target = 0.30, p_tox = p_tox)$lambda_d

# A boundary too close to the target leaves an unusable threshold, and says so
boin_p_tox(target = 0.30, lambda_d = 0.31)

# and shifts the de-escalation boundary down by one DLT at every cohort end
as.data.frame(boin_boundary(0.30, 18))[seq(3, 18, 3), ]
as.data.frame(boin_boundary(0.30, 18, p_tox = p_tox))[seq(3, 18, 3), ]


Select the MTD from Completed Trials

Description

Choose the maximum tolerated dose for each of a set of completed trials from the final patient and DLT counts.

Usage

boin_select_mtd(
  n_pts,
  n_tox,
  target,
  cutoff_eli = 0.95,
  extrasafe = FALSE,
  offset = 0.05,
  bound_mtd = FALSE,
  p_tox = NULL,
  mtd_max_estimate = NULL,
  min_mtd_sample = 1
)

Arguments

n_pts

Integer matrix with one row per trial and one column per dose, or a vector for a single trial, giving the number of patients treated.

n_tox

Integer matrix or vector of the same shape as n_pts, giving the number of DLTs observed.

target

Numeric scalar. Target DLT probability.

cutoff_eli

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

extrasafe

Logical scalar. Apply the stricter safety rule at the lowest dose, in which case no dose is selected when the lowest dose is judged too toxic. Defaults to FALSE.

offset

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

bound_mtd

Logical scalar. Require the isotonic estimate at the selected dose to be at or below the de-escalation boundary. Defaults to FALSE.

p_tox

Numeric scalar. Lowest DLT probability deemed overly toxic, used to derive the de-escalation boundary when bound_mtd is TRUE. Defaults to 1.4 * target.

mtd_max_estimate

Numeric scalar or NULL. Largest isotonic estimate a dose may have and still be selected. Supplying it bounds the selection whatever bound_mtd says, and replaces the de-escalation boundary that bound_mtd would otherwise use. Defaults to NULL.

min_mtd_sample

Integer scalar. Smallest number of patients a dose must have received to be eligible. Defaults to 1, which admits every dose that treated a patient.

Details

Dose elimination is re-derived from the final data of each trial rather than carried over from the dose-finding stage, which is what the reference implementation does and which matters when a trial ends at its maximum sample size. The isotonic fit is computed over the admissible doses only, so that eliminated doses do not influence the estimates of the doses that remain. The dose whose estimate is closest to target is selected, with ties broken by a small increasing perturbation across the admissible doses.

bound_mtd caps the estimate at the de-escalation boundary, which always lies above target. A cap at or below the target rate therefore cannot be expressed that way, and needs mtd_max_estimate. The two caps are independent of the decision table, so bounding the selection does not change how the trial was run.

Values of reason are "selected", "lowest_dose_eliminated", "no_admissible_dose" and "no_dose_below_bound".

Value

A data frame with one row per trial and columns

trial

Trial index.

mtd

Selected dose level, or NA when no dose is selected.

reason

Why the dose was or was not selected.

References

Liu S. and Yuan, Y. (2015). Bayesian Optimal Interval Designs for Phase I Clinical Trials. Journal of the Royal Statistical Society: Series C, 64, 507-523.

See Also

boin_isotonic, boin_simulate

Examples

n_pts <- matrix(c(3, 6, 9, 3,
                  3, 6, 9, 3), nrow = 2, byrow = TRUE)
n_tox <- matrix(c(0, 1, 3, 2,
                  0, 1, 2, 1), nrow = 2, byrow = TRUE)

boin_select_mtd(n_pts, n_tox, target = 0.30)

boin_select_mtd(n_pts, n_tox, target = 0.30, bound_mtd = TRUE)

# Require the isotonic estimate at the selected dose to be at most 0.30,
# which the de-escalation boundary cannot express
boin_select_mtd(n_pts, n_tox, target = 0.30, mtd_max_estimate = 0.30)


Simulate BOIN Trials

Description

Run the BOIN dose-finding algorithm over many simulated trials and return the patient and DLT counts at every dose. This is the simulation engine behind sim_boin, exposed for users who want the raw trial data.

Usage

boin_simulate(
  target,
  p_true,
  n_cohort,
  cohort_size,
  n_trials = 10000,
  start_dose = 1,
  n_earlystop = 18,
  p_saf = NULL,
  p_tox = NULL,
  cutoff_eli = 0.95,
  extrasafe = FALSE,
  offset = 0.05,
  titration = FALSE,
  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.30.

p_true

Numeric vector. True DLT probability at each dose level, in increasing dose order.

n_cohort

Integer scalar. Number of cohorts in a trial.

cohort_size

Integer scalar or vector. Number of patients per cohort. 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.

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. It is ignored when titration is TRUE, because the titration phase always begins at the lowest dose.

n_earlystop

Integer scalar. The trial stops once this many patients 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.

titration

Logical scalar. Start with single patient cohorts until the first DLT is seen. Ignored when the first cohort size is one. Defaults to FALSE.

stay_on_1_of_3

Logical scalar. When TRUE, one DLT out of three patients leads to staying at the current dose rather than de-escalating. Defaults to FALSE. See boin_boundary.

n_earlystop_rule

Character scalar, either "with_stay" or "simple". Under "with_stay" the trial stops at n_earlystop only when the design would remain at the current dose, which is the rule used by the reference implementation. Under "simple" it stops as soon as the threshold is reached.

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.

Details

One uniform variate is drawn per patient, in enrollment order. Two details matter for reproducibility: the titration phase draws one variate per dose level whether or not it is used, and a cohort cut short by the maximum sample size still draws a full cohort's worth. This is the random number consumption of BOIN::get.oc(), so with the same seed and matching arguments a run reproduces the reference implementation trial by trial.

Possible values of stop_reason are "lowest_dose_eliminated", "lowest_dose_too_toxic", "n_earlystop", "max_sample_size" and "max_cohorts".

Value

An object of class boin_trials, which is a list with components

n_pts

Integer matrix, n_trials by number of doses, of patients treated.

n_tox

Integer matrix of the same shape, of DLTs observed.

eliminated

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

cohorts_used

Integer vector of cohorts completed in each trial.

stop_reason

Character vector giving why each trial ended.

boundary

The boin_boundary object used.

settings

List of the design parameters.

References

Liu S. and Yuan, Y. (2015). Bayesian Optimal Interval Designs for Phase I Clinical Trials. Journal of the Royal Statistical Society: Series C, 64, 507-523.

See Also

sim_boin, boin_select_mtd

Examples

trials <- boin_simulate(
  target = 0.30,
  p_true = c(0.05, 0.15, 0.30, 0.45, 0.60),
  n_cohort = 10,
  cohort_size = 3,
  n_trials = 200,
  seed = 123
)
trials

head(trials$n_pts)
table(trials$stop_reason)


Safety Stopping Boundary as a Two-Row Table

Description

Present the safety stopping boundary at the lowest dose as a compact table with one column per sample size, which is the shape usually wanted in a protocol or a report.

Usage

boin_stopping_table(x, cohort_size = NULL)

Arguments

x

An object of class boin_boundary, built with extrasafe = TRUE.

cohort_size

Integer scalar or NULL. When supplied, only the sample sizes that are multiples of cohort_size are kept.

Details

The same numbers are available one row per sample size from as.data.frame() on the boundary object. This function transposes them and labels the rows, which suits a table pasted into a document or rendered with knitr::kable() or DT::datatable().

Value

A data frame with two rows, labeled by the quantity they hold, and one column per sample size. Sample sizes at which no number of DLTs triggers the rule are dropped.

See Also

boin_boundary

Examples

bd <- boin_boundary(target = 0.30, max_n = 18, extrasafe = TRUE)

boin_stopping_table(bd)

# Only the sample sizes reached at the end of a cohort of three
boin_stopping_table(bd, cohort_size = 3)


Exact Operating Characteristics of the 3+3 Design

Description

Compute the operating characteristics of the traditional 3+3 dose-finding design exactly. The probability of every path the design can take is evaluated in closed form, so the result carries no Monte Carlo error and no seed is involved. Use it as a comparator for the BOIN results returned by sim_boin.

Usage

oc_3p3(
  p_true,
  mtd_rule = c("previous", "expand"),
  start_dose = 1,
  overdose_cutoff = NULL
)

Arguments

p_true

Numeric vector. True DLT probability at each dose level, in increasing dose order.

mtd_rule

Character scalar, either "previous" or "expand". The two definitions of the MTD in common use. See Details. Defaults to "previous".

start_dose

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

overdose_cutoff

Numeric scalar or NULL. Doses whose true DLT probability exceeds this value count as overdoses in the overdose component of the result. Defaults to NULL, which uses one third.

Details

The escalation rule is the traditional one. Three patients are treated at the current dose. No DLT leads to the next dose up. One DLT out of three leads to three more patients at the same dose, and then to the next dose up if no further DLT is seen and to stopping otherwise. Two or more DLTs out of three stop the trial at once. A trial that escalates past the highest dose ends there.

The two MTD rules differ only in what happens once escalation has stopped. "previous" names the dose below the one declared too toxic, and the highest dose when escalation ran out of doses. "expand" instead takes the MTD to be the highest dose at which at most one of six patients had a DLT: starting from the highest dose still eligible, a dose that has only three patients is expanded to six and assessed, and the search moves down a level whenever the expanded dose fails. Neither rule is universally the standard, so the comparator being matched should be checked before a rule is chosen. The two agree on which doses are visited during escalation, and so on the probability that a patient is exposed to an overly toxic dose; they differ in the sample size and in the selection percentages.

The 3+3 design has no fixed maximum sample size, so the within-trial exposure percentage and the 60 percent and 80 percent thresholds reported for BOIN in sim_boin have no counterpart here.

Value

An object of class oc_3p3, which is a list with components

sel_percent

Percentage of trials selecting each dose as the MTD.

percent_no_mtd

Percentage of trials ending without an MTD.

n_pts_dose

Average number of patients treated at each dose.

n_tox_dose

Average number of DLTs observed at each dose.

total_n_pts

Average total number of patients per trial.

total_n_tox

Average total number of DLTs per trial.

overdose

List describing the design's relationship with doses above overdose_cutoff: pct_patients (the percentage of all patients treated at such a dose, that is the probability that a patient is dosed above the cutoff), avg_n_patients, pct_trials_any (the percentage of trials treating at least one patient there), pct_trials_mtd_above (the percentage of all trials whose selected MTD is above the cutoff) and pct_mtd_above_when_selected (the same among the trials that selected an MTD). The cutoff and the dose levels doses that exceed it are also returned.

together with p_true, n_doses, mtd_rule, start_dose, method and the call.

See Also

sim_3p3, sim_boin

Examples

oc_3p3(p_true = c(0.30, 0.48, 0.67))

# The other definition of the MTD
oc_3p3(p_true = c(0.30, 0.48, 0.67), mtd_rule = "expand")

# Exposure to doses above a stated DLT rate
oc_3p3(p_true = c(0.20, 0.40, 0.60), overdose_cutoff = 1 / 3)$overdose


Plot a BOIN Decision Table

Description

Draw the decision table produced by boin_decision_table as a grid of colored cells, one per pair of DLT and patient counts, with the decision letter in each cell.

Usage

## S3 method for class 'boin_decision_table'
plot(x, text_size = 1, colors = NULL, ...)

Arguments

x

An object of class boin_decision_table.

text_size

Numeric scalar. Multiplier applied to every text size in the figure. Use a larger value when the figure is exported at high resolution, for example into a report. Defaults to 1.

colors

Named character vector of four colors, with names "E", "S", "D" and "DE". Defaults to a palette whose adjacent categories remain distinguishable under the common forms of color vision deficiency.

...

Further arguments, currently ignored.

Details

Every cell carries its decision letter, so the figure does not rely on color alone to convey the decision and remains readable in grayscale.

Requires the ggplot2 package, which is only suggested by simFastBOIN rather than required.

Value

A ggplot2 object, which can be printed, saved with ggplot2::ggsave() or extended with further layers.

See Also

boin_decision_table, print.boin_decision_table

Examples


decisions <- boin_decision_table(target = 0.30, max_n = 12)

plot(decisions)

# Larger text for a high resolution export
plot(decisions, text_size = 2)

# A palette of your own
plot(decisions, colors = c(E = "#4DAF4A", S = "#377EB8",
                           D = "#FF7F00", DE = "#E41A1C"))


Print BOIN Decision Boundaries

Description

Display the interval boundaries and the integer decision boundaries produced by boin_boundary.

Usage

## S3 method for class 'boin_boundary'
print(x, cohort_size = NULL, ...)

Arguments

x

An object of class boin_boundary.

cohort_size

Integer scalar or NULL. When supplied, only the sample sizes that are multiples of cohort_size are shown, which is how the boundaries are consulted during a trial with equally sized cohorts.

...

Further arguments, currently ignored.

Value

The object x, invisibly.

Examples

bd <- boin_boundary(target = 0.30, max_n = 18, extrasafe = TRUE)
print(bd, cohort_size = 3)


Print a BOIN Decision Table

Description

Display the decision table produced by boin_decision_table, optionally restricted to the sample sizes reached at the end of a cohort.

Usage

## S3 method for class 'boin_decision_table'
print(x, cohort_size = NULL, ...)

Arguments

x

An object of class boin_decision_table.

cohort_size

Integer scalar or NULL. When supplied, only the sample sizes that are multiples of cohort_size are shown, which is how the table is consulted during a trial with equally sized cohorts.

...

Further arguments, currently ignored.

Value

The object x, invisibly.

See Also

boin_decision_table, plot.boin_decision_table

Examples

decisions <- boin_decision_table(target = 0.30, max_n = 18)

print(decisions, cohort_size = 3)


Print Operating Characteristics of a BOIN Design

Description

Display the summary table produced by sim_boin.

Usage

## S3 method for class 'boin_oc'
print(
  x,
  digits = 1,
  percent = FALSE,
  kable = FALSE,
  kable_format = "pipe",
  ...
)

Arguments

x

An object of class boin_oc.

digits

Integer scalar. Number of decimal places. Defaults to 1.

percent

Logical scalar. Express the average number of patients and DLTs at each dose as a percentage of the trial total instead of a count. Defaults to FALSE.

kable

Logical scalar. Return the table through knitr::kable() rather than printing it directly, which is convenient inside a report. Requires the knitr package. Defaults to FALSE.

kable_format

Character scalar passed to knitr::kable(), for example "pipe", "html" or "latex". Defaults to "pipe".

...

Further arguments, currently ignored.

Value

The object x, invisibly.

Examples

oc <- sim_boin(
  target = 0.30,
  p_true = c(0.05, 0.15, 0.30, 0.45, 0.60),
  n_cohort = 10,
  cohort_size = 3,
  n_trials = 200,
  seed = 123
)

print(oc)
print(oc, percent = TRUE)


Print Operating Characteristics Across Scenarios

Description

Display the combined summary table produced by sim_boin_multi.

Usage

## S3 method for class 'boin_oc_multi'
print(
  x,
  digits = 1,
  percent = FALSE,
  kable = FALSE,
  kable_format = "pipe",
  ...
)

Arguments

x

An object of class boin_oc_multi.

digits

Integer scalar. Number of decimal places. Defaults to 1.

percent

Logical scalar. Express the average number of patients and DLTs at each dose as a percentage of the trial total instead of a count. Defaults to FALSE.

kable

Logical scalar. Return the table through knitr::kable() rather than printing it directly. Requires the knitr package. Defaults to FALSE.

kable_format

Character scalar passed to knitr::kable(), for example "pipe", "html" or "latex". Defaults to "pipe".

...

Further arguments, currently ignored.

Value

The object x, invisibly.

Examples

oc <- sim_boin_multi(
  target = 0.30,
  scenarios = list(
    list(name = "MTD at dose 3", p_true = c(0.05, 0.15, 0.30, 0.45, 0.60)),
    list(name = "All toxic",     p_true = c(0.35, 0.45, 0.55, 0.65, 0.75))
  ),
  n_cohort = 10,
  cohort_size = 3,
  n_trials = 200,
  seed = 123
)

print(oc)
print(oc, percent = TRUE)


Print Simulated BOIN Trials

Description

Show a compact summary of the object returned by boin_simulate instead of printing the full trial matrices.

Usage

## S3 method for class 'boin_trials'
print(x, ...)

Arguments

x

An object of class boin_trials.

...

Further arguments, currently ignored.

Value

The object x, invisibly.

Examples

trials <- boin_simulate(
  target = 0.30,
  p_true = c(0.05, 0.15, 0.30, 0.45, 0.60),
  n_cohort = 10,
  cohort_size = 3,
  n_trials = 100,
  seed = 1
)
print(trials)


Print Operating Characteristics of the 3+3 Design

Description

Display the summary table produced by oc_3p3 or sim_3p3. The layout matches print.boin_oc, so a 3+3 table can be read beside a BOIN one.

Usage

## S3 method for class 'oc_3p3'
print(
  x,
  digits = 1,
  percent = FALSE,
  kable = FALSE,
  kable_format = "pipe",
  ...
)

Arguments

x

An object of class oc_3p3.

digits

Integer scalar. Number of decimal places. Defaults to 1.

percent

Logical scalar. Express the average number of patients and DLTs at each dose as a percentage of the trial total instead of a count. Defaults to FALSE.

kable

Logical scalar. Return the table through knitr::kable() rather than printing it directly, which is convenient inside a report. Requires the knitr package. Defaults to FALSE.

kable_format

Character scalar passed to knitr::kable(), for example "pipe", "html" or "latex". Defaults to "pipe".

...

Further arguments, currently ignored.

Value

The object x, invisibly.

See Also

oc_3p3, sim_3p3

Examples

oc <- oc_3p3(p_true = c(0.30, 0.48, 0.67))

print(oc)
print(oc, percent = TRUE)


Deprecated Functions in simFastBOIN

Description

These functions were renamed in version 2.0.0. They still work but issue a deprecation warning and will be removed in a future release. Their return values are those of the replacement functions, which differ from the return values of version 1.3.2, so calls should be updated rather than left in place.

Usage

get_boin_boundary(...)

get_boin_decision(...)

get_boin_stopping_boundaries(...)

get_pts_and_tox(...)

isotonic_regression(...)

select_mtd(...)

Arguments

...

Arguments passed to the replacement function. Note that the replacements use different argument names and a different argument order, so only calls that name every argument will carry over unchanged.

Value

The value of the corresponding replacement function.

Replacements

get_boin_boundary()

use boin_lambda for the interval boundaries, or boin_boundary for the integer decision boundaries.

get_boin_decision()

use boin_decision_table.

get_boin_stopping_boundaries()

use boin_boundary with extrasafe = TRUE and read the b_stop component.

get_pts_and_tox()

use boin_simulate.

isotonic_regression()

use boin_isotonic.

select_mtd()

use boin_select_mtd, which now takes the patient and DLT counts instead of precomputed isotonic estimates.


Simulate the 3+3 Design

Description

Simulate the traditional 3+3 dose-finding design and summarize the same quantities that oc_3p3 computes exactly. The two are meant to be used together: oc_3p3() gives the answer without Monte Carlo error, and this function confirms it from independent trials.

Usage

sim_3p3(
  p_true,
  n_trials = 10000,
  mtd_rule = c("previous", "expand"),
  start_dose = 1,
  overdose_cutoff = NULL,
  seed = 123
)

Arguments

p_true

Numeric vector. True DLT probability at each dose level, in increasing dose order.

n_trials

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

mtd_rule

Character scalar, either "previous" or "expand". See oc_3p3. Defaults to "previous".

start_dose

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

overdose_cutoff

Numeric scalar or NULL. Doses whose true DLT probability exceeds this value count as overdoses in the overdose component of the result. Defaults to NULL, which uses one third.

seed

Integer scalar or NULL. Random seed. The state of the calling session is restored on exit. Defaults to 123.

Details

The design is described under oc_3p3. Since the operating characteristics of the 3+3 design can be written in closed form, this function is a check on that closed form rather than the way to obtain the numbers. Simulation is the only option when a quantity is wanted that the closed form does not provide, such as the distribution of the sample size rather than its mean.

Value

An object of class oc_3p3, with the components described in oc_3p3. The method component is the number of trials rather than "exact".

See Also

oc_3p3, sim_boin

Examples

exact <- oc_3p3(p_true = c(0.30, 0.48, 0.67))
simulated <- sim_3p3(p_true = c(0.30, 0.48, 0.67), n_trials = 2000, seed = 1)

round(exact$sel_percent, 2)
round(simulated$sel_percent, 2)


Operating Characteristics of a BOIN Design

Description

Simulate a BOIN dose-finding trial many times under one dose-toxicity scenario and summarize how often each dose is selected as the MTD, how many patients are treated at each dose and how many DLTs are observed.

Usage

sim_boin(
  target,
  p_true,
  n_cohort,
  cohort_size,
  n_trials = 10000,
  start_dose = 1,
  n_earlystop = 18,
  p_saf = NULL,
  p_tox = NULL,
  cutoff_eli = 0.95,
  extrasafe = FALSE,
  offset = 0.05,
  titration = FALSE,
  stay_on_1_of_3 = FALSE,
  bound_mtd = FALSE,
  mtd_max_estimate = NULL,
  min_mtd_sample = 1,
  overdose_cutoff = NULL,
  n_earlystop_rule = c("with_stay", "simple"),
  keep_trials = FALSE,
  verbose = FALSE,
  seed = 123
)

Arguments

target

Numeric scalar. Target DLT probability, for example 0.30.

p_true

Numeric vector. True DLT probability at each dose level, in increasing dose order.

n_cohort

Integer scalar. Number of cohorts in a trial.

cohort_size

Integer scalar or vector. Number of patients per cohort. 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.

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. It is ignored when titration is TRUE, because the titration phase always begins at the lowest dose.

n_earlystop

Integer scalar. The trial stops once this many patients have been treated at the current dose and the design would stay there. Defaults to 18. Set it to a value above the maximum sample size to switch this rule off.

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.

titration

Logical scalar. Start with single patient cohorts until the first DLT is seen. Ignored when the first cohort size is one. Defaults to FALSE.

stay_on_1_of_3

Logical scalar. When TRUE, one DLT out of three patients leads to staying at the current dose rather than de-escalating. Defaults to FALSE. See boin_boundary.

bound_mtd

Logical scalar. Require the isotonic estimate at the selected dose to be at or below the de-escalation boundary. Defaults to FALSE.

mtd_max_estimate

Numeric scalar or NULL. Largest isotonic estimate a dose may have and still be selected as the MTD. Supplying it bounds the selection whatever bound_mtd says, and unlike bound_mtd it can be set at or below the target rate. It changes only the selection, never the dose-finding itself. Defaults to NULL.

min_mtd_sample

Integer scalar. Smallest number of patients a dose must have received to be eligible as the MTD. Defaults to 1.

overdose_cutoff

Numeric scalar or NULL. Doses whose true DLT probability exceeds this value count as overdoses in the overdose component of the result. Defaults to NULL, which uses target.

n_earlystop_rule

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

keep_trials

Logical scalar. Keep the full trial by trial data in the result. Defaults to FALSE.

verbose

Logical scalar. Report progress while the simulation runs. Defaults to FALSE.

seed

Integer scalar or NULL. Random seed. The state of the calling session is restored on exit. Defaults to 123.

Details

The engine draws one uniform variate per patient, in enrollment order, and applies the decision rules in the order used by BOIN::get.oc(). See boin_simulate for the two places where a variate is drawn but not used. With the same seed and matching arguments the two implementations agree trial by trial, not merely on average.

Note that n_earlystop defaults to 18 here, whereas the reference implementation defaults to 100, which in practice switches the rule off.

Value

An object of class boin_oc, which is a list with components

sel_percent

Percentage of trials selecting each dose as the MTD.

percent_no_mtd

Percentage of trials ending without an MTD.

n_pts_dose

Average number of patients treated at each dose.

n_tox_dose

Average number of DLTs observed at each dose.

total_n_pts

Average total number of patients per trial.

total_n_tox

Average total number of DLTs per trial.

overdose

List describing the design's relationship with doses above overdose_cutoff. Two questions are answered separately. How far were patients exposed during the trial: pct_patients (the percentage of all simulated patients treated at such a dose, that is the probability that a patient is dosed above the cutoff), pct_patients_by_trial (the same percentage computed within each trial and then averaged), avg_n_patients, pct_trials_any, pct_trials_over_60 and pct_trials_over_80. And how often did the design end up recommending such a dose: pct_trials_mtd_above (the percentage of all trials whose selected MTD is above the cutoff) and pct_mtd_above_when_selected (the same among the trials that selected an MTD at all). The cutoff and the dose levels doses that exceed it are also returned.

stop_reason_percent

Percentage of trials by reason for stopping.

trials

Trial level data when keep_trials is TRUE, otherwise NULL.

together with the design parameters and the call.

References

Liu S. and Yuan, Y. (2015). Bayesian Optimal Interval Designs for Phase I Clinical Trials. Journal of the Royal Statistical Society: Series C, 64, 507-523.

See Also

sim_boin_multi, boin_simulate

Examples

oc <- sim_boin(
  target = 0.30,
  p_true = c(0.05, 0.15, 0.30, 0.45, 0.60),
  n_cohort = 10,
  cohort_size = 3,
  n_trials = 500,
  seed = 123
)
oc


# A larger run with the safety options switched on
oc_safe <- sim_boin(
  target = 0.30,
  p_true = c(0.30, 0.40, 0.50, 0.60, 0.70),
  n_cohort = 20,
  cohort_size = 3,
  n_trials = 10000,
  extrasafe = TRUE,
  bound_mtd = TRUE,
  titration = TRUE,
  seed = 123
)
oc_safe

# How often are patients dosed above a true DLT rate of 0.33?
oc_cut <- sim_boin(
  target = 0.30,
  p_true = c(0.10, 0.20, 0.30, 0.42, 0.55),
  n_cohort = 20,
  cohort_size = 3,
  n_trials = 10000,
  overdose_cutoff = 0.33,
  seed = 123
)
oc_cut$overdose$pct_patients            # patients dosed above 0.33
oc_cut$overdose$pct_trials_mtd_above     # trials recommending a dose above 0.33



Operating Characteristics Across Several Scenarios

Description

Run sim_boin under a list of dose-toxicity scenarios that share the same design, and collect the results into one table.

Usage

sim_boin_multi(
  target,
  scenarios,
  n_cohort,
  cohort_size,
  n_trials = 10000,
  start_dose = 1,
  n_earlystop = 18,
  p_saf = NULL,
  p_tox = NULL,
  cutoff_eli = 0.95,
  extrasafe = FALSE,
  offset = 0.05,
  titration = FALSE,
  stay_on_1_of_3 = FALSE,
  bound_mtd = FALSE,
  mtd_max_estimate = NULL,
  min_mtd_sample = 1,
  overdose_cutoff = NULL,
  n_earlystop_rule = c("with_stay", "simple"),
  keep_trials = FALSE,
  verbose = FALSE,
  seed = 123
)

Arguments

target

Numeric scalar. Target DLT probability.

scenarios

A list of scenarios. Each element is a list with a name and a p_true vector, or a plain numeric vector of true DLT probabilities in which case the list names are used as scenario names. Every scenario must have the same number of doses.

n_cohort

Integer scalar. Number of cohorts in a trial.

cohort_size

Integer scalar or vector. Number of patients per cohort.

n_trials

Integer scalar. Number of trials per scenario. Defaults to 10000.

start_dose

Integer scalar. Dose level for the first cohort. Defaults to 1. It is ignored when titration is TRUE.

n_earlystop

Integer scalar. Early stopping sample size at the current dose. 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.

offset

Numeric scalar between 0 and 0.5. Relaxation of cutoff_eli for the safety stopping rule. Defaults to 0.05.

titration

Logical scalar. Start with single patient cohorts until the first DLT.

stay_on_1_of_3

Logical scalar. Make one DLT out of three patients a stay rather than a de-escalation. See boin_boundary.

bound_mtd

Logical scalar. Bound the isotonic estimate at the selected MTD by the de-escalation boundary.

mtd_max_estimate

Numeric scalar or NULL. Largest isotonic estimate a dose may have and still be selected as the MTD. See sim_boin.

min_mtd_sample

Integer scalar. Smallest number of patients for a dose to be eligible.

overdose_cutoff

Numeric scalar or NULL. Doses whose true DLT probability exceeds this value count as overdoses. Defaults to NULL, which uses target.

n_earlystop_rule

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

keep_trials

Logical scalar. Keep the trial by trial data of every scenario.

verbose

Logical scalar. Report progress while the simulations run.

seed

Integer scalar or NULL. Random seed, applied to every scenario, so that a scenario simulated here matches the same scenario simulated on its own with sim_boin.

Value

An object of class boin_oc_multi, which is a list with components

results

Named list of boin_oc objects, one per scenario.

summary_table

Data frame collecting all scenarios.

scenario_names

Character vector of scenario names.

n_doses

Number of dose levels.

call

The matched call.

See Also

sim_boin

Examples

scenarios <- list(
  list(name = "MTD at dose 3", p_true = c(0.05, 0.15, 0.30, 0.45, 0.60)),
  list(name = "All toxic",     p_true = c(0.35, 0.45, 0.55, 0.65, 0.75))
)

oc <- sim_boin_multi(
  target = 0.30,
  scenarios = scenarios,
  n_cohort = 10,
  cohort_size = 3,
  n_trials = 200,
  seed = 123
)
oc