Skip to contents

simFastBOIN 2.1.0

This version adds the time-to-event BOIN (TITE-BOIN) design, the BF-BOIN and BE-BOIN designs, which backfill patients to lower doses while the dose escalation waits, the BOIN design for trials of two drugs given together, and a decision table for the 3+3 design. No existing function or result changes.

TITE-BOIN decision table

  • tite_boin_decision_table() tabulates the decision rule of the TITE-BOIN design, which lets new patients be treated while the DLT assessment of earlier patients is still pending. Two methods are offered: the single mean imputation of Yuan et al. (2018), method = "imputation", with boundaries on the standardized total follow-up time (STFT), and the effective sample size of Lin and Yuan (2020), method = "ess", with boundaries on the effective sample size (ESS). The table has print() and plot() methods, and the printed layout follows the published tables.

  • The suspension rules of the two articles are available for both methods: max_pending_ratio (accrual is suspended when more than half of the patients are pending, the default of the imputation method) and min_completed (escalation requires two patients with a completed assessment, the default of the effective sample size method).

  • min_follow_up adds rule 2 of Chen et al. (2025): while patients are pending, escalation requires every pending patient at the current dose to have been followed for at least this fraction of the assessment window, and accrual is suspended until then. It is available in tite_boin_decision_table(), tite_boin_simulate(), sim_tite_boin() and sim_tite_boin_multi(), and defaults to 0, which changes nothing. With max_pending_ratio = 0.49 (their rule 1 with A = 51) and min_follow_up = 0.25, the imputation method reproduces every entry of Table 1 (target 0.3) of Chen et al. (2025) and of Table A1 (target 0.25) of the supplementary materials of Chen et al. (2026), 131 states in all. The printed table shows the condition, for example >= 0.22 & MF >= 0.25.

  • With the defaults, the imputation method reproduces every entry of Table 1 (target 0.2) of Yuan et al. (2018) and Table S1 (target 0.3) of its supplementary appendix, 640 states in all, and the printed table has the same rows. The published tables allow de-escalation when the observed DLT rate equals the target, which equation (5) of the appendix, read literally, does not; the implementation follows the tables. The dose decisions of the trial example in Figure 1 of that article are reproduced as well.

  • Elimination counts the pending patients as treated without DLT, as both articles define it. States without pending patients agree with boin_decision_table().

TITE-BOIN simulation engine

  • tite_boin_simulate() simulates TITE-BOIN trials in which patients arrive over time and DLTs can occur late in the assessment window. It returns the patient and DLT counts of boin_simulate() together with the duration of each trial, the number of suspensions of accrual and the time spent suspended. The engine is written in C++ (src/tite_core.h), like the BOIN engine.

  • The dose for a cohort is decided when its first patient arrives, with the rules of tite_boin_decision_table(); the engine and the table are checked against each other at every state. A suspension lasts until the next pending patient at the current dose completes the assessment or, with a positive min_follow_up, until the minimum follow-up is reached, whichever comes first. Because DLTs can be observed after a dose has been left, the elimination rule is checked at every dose, not only the current one.

  • Times between arrivals can be exponential, uniform or fixed, and the time to DLT Weibull, with the share of DLTs in the second half of the window set by late_fraction, or uniform.

  • prior_weights weights the follow-up of the pending patients by a piecewise uniform prior for the time to DLT over the three thirds of the window, as in Appendix D of Yuan et al. (2018) and Section S1 of Lin and Yuan (2020). The decision table is unchanged; only the follow-up compared with it is. Equal weights, the default, use the unweighted computation, so the default results do not change. The weighted trials agree exactly with the separate Python implementation, which uses the formula of Lin and Yuan’s reference code.

  • One uniform variate per patient, drawn from R’s stream in the order used by boin_simulate(), decides both whether a DLT occurs and when; arrivals come from a separate generator. Whenever no patient is pending at a decision the trials are therefore identical to those of boin_simulate() with the same seed, which the tests check for both methods and several designs.

  • The trials agree exactly with a separate implementation written in Python, run on a replica of R’s random number stream.

TITE-BOIN operating characteristics

  • sim_tite_boin() and sim_tite_boin_multi() summarize simulated TITE-BOIN trials in the same way as sim_boin() and sim_boin_multi(), with the same options for selecting the MTD (bound_mtd, mtd_max_estimate, min_mtd_sample) and the same overdose component. They add the average and standard deviation of the trial duration, the percentage of trials with accrual suspended, and the average number and total time of suspensions.

  • The results inherit from the BOIN classes (c("tite_boin_oc", "boin_oc") and c("tite_boin_oc_multi", "boin_oc_multi")), so code that reads the result of sim_boin() also reads them. They have their own print() methods, which also show the design and the timing; the table of sim_tite_boin_multi() has two rows more per scenario, for the duration and the suspensions.

  • Whenever no patient is pending at a decision, every summary agrees exactly with that of sim_boin() under the same seed, including the options of MTD selection and the safety rules; the tests check this for both methods.

Backfilling: BF-BOIN and BE-BOIN

  • bf_boin_simulate() simulates the BOIN design with backfilling (BF-BOIN) of Zhao et al. (2024). The dose escalation proceeds in fully staggered cohorts with the BOIN decision table, and a patient who arrives while it waits is backfilled to a lower dose that has not been eliminated, has fewer than n_cap patients and has a response observed at or below it. Doses are closed for backfilling, and conflicts between the backfilled doses and the current dose are resolved with pooled data, as in Table 2 of the article.

  • be_boin_simulate() simulates BE-BOIN of Chen et al. (2026), which combines backfilling with TITE-BOIN. The escalation decides while patients are pending, with rules 1 and 2 of the article (max_pending_ratio = 0.49 and min_follow_up = 0.25), and every estimate imputes the pending patients, over several doses with equation (2) of the article.

  • sim_bf_boin(), sim_be_boin(), sim_bf_boin_multi() and sim_be_boin_multi() summarize the simulated trials. The results inherit from the BOIN classes, count backfilled patients among the patients treated, and add the backfilled patients and the responses at each dose, the trial duration, the waits of the escalation and the patients turned away. The MTD is selected from the data of all patients, as in sim_boin(). They have their own print() methods, and the table of the _multi functions has seven rows per scenario.

  • Points that the articles leave open are arguments: no_slot decides whether a patient with nowhere to go waits or is turned away, conflict_dose whether the highest (Zhao et al., 2024) or the lowest (Chen et al., 2026) conflicting dose anchors the pooled estimate, and backfill_dose which open dose receives a backfill patient. The time to response is Weibull (resp_window, resp_late_fraction), and the DLT and the response are linked by a Gaussian copula (resp_cor, 0 by default), as in Takeda et al. (2025).

  • The engine is written in C++ (src/backfill_core.h). The DLT variates of the escalation are drawn from R’s stream as in boin_simulate(); arrivals, backfill patients and responses have generators of their own. When no dose is ever opened for backfilling the trials are identical to those of boin_simulate() (BF-BOIN) and of tite_boin_simulate() (BE-BOIN with no_slot = "wait") with the same seed, which the tests check.

  • 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), twelve scenarios of BF-BOIN and five of BOIN, are reproduced within simulation error, durations included; over 20 seeds of 10,000 trials the largest gaps were 2.1 points for the selection, 0.4 patients and 0.17 months. The article states a Poisson process of arrivals, but its durations agree with uniform times between arrivals and patients turned away while the escalation waits. inst/validation/compare-with-Zhao2024.R repeats the comparison.

  • The trial examples of Figure 1 of Zhao et al. (2024) and of Section S2 of the supplementary materials of Chen et al. (2026) are replayed patient by patient, and the simulated trials agree exactly with a separate implementation written in Python, over 2,700 trials of both designs.

BOIN design for drug combinations

  • comb_boin_simulate() simulates the BOIN drug-combination design of Lin and Yin (2017), which looks for a single MTD in a matrix of dose combinations of two drugs. After each cohort the decision of the single-agent design is taken at the current combination; an escalation goes one level up of either drug, and a de-escalation one level down, to the neighbor with the larger posterior probability that its DLT rate lies between the boundaries. The engine is written in C++ (src/comb_core.h) and follows BOIN::get.oc.comb() with mtd.contour = FALSE: the same rules, applied in the same order, with the random variates drawn in the same order, so that with the same seed the two produce the same trials.

  • comb_boin_select_mtd() selects the MTD combination from completed trials, with the bivariate isotonic regression of Iso::biviso(), the routine the reference implementation calls. Combinations that the regression pools are equal in exact arithmetic but can differ in their last digits, and these digits decide between combinations on the same anti-diagonal, so another algorithm would select differently in a few trials out of a thousand. The ‘Iso’ package, which version 1.4.0 moved to Suggests, is therefore imported again.

  • sim_comb_boin() and sim_comb_boin_multi() summarize the simulated trials: the selection percentage and the average numbers of patients and DLTs at every combination, the percentages of trials selecting a true MTD combination and of patients treated at one, and the exposure to combinations above overdose_cutoff. They have their own print() methods, and the table of sim_comb_boin_multi() has one row per scenario.

  • comb_boin_next() gives the combination for the next cohort of a trial in progress, from the numbers of patients and DLTs observed at every combination and the combination of the last cohort. It reports the boundaries that apply, the two candidates with their posterior probabilities and scores, both candidates when they tie, the combinations eliminated, and why the trial stops when it does. It has print() and plot() methods; the plot draws the dose matrix with the data, the current and next combinations and the eliminated ones. The decision is taken by the same C++ code as in the simulations (comb_decide() in src/comb_core.h), so a trial is run with the rules whose operating characteristics sim_comb_boin() reports. These differ from BOIN::next.comb() in three respects: BOIN::next.comb() stops as soon as n.earlystop patients have been treated at the current combination, blocks an escalation of one drug when a combination at the next level of that drug has an observed DLT rate at or above lambda_d, and breaks ties at random. The tests check that comb_boin_next() takes the decision of simulated trials after every cohort, and that it agrees with BOIN::next.comb() on random data wherever the rules coincide. The C++ code also takes the same decision as the Python implementation at each of the 40,664 states reached by 3,300 simulated trials in 11 settings.

  • The tests reproduce the example of Yan et al. (2020): every number printed by summary() in the article agrees to the printed precision. The one average exactly half-way between two printed values, 1.905 patients at A2B4, is printed 1.90 in the article and 1.91 by R 4.6.0; how such a value is rounded depends on the version of R. The tests also check exact agreement with BOIN::get.oc.comb() in nine settings whenever the BOIN package is installed. The simulated trials also agree exactly with a separate implementation written in Python and run on a replica of R’s random number stream, over 5,500 trials in 11 settings. inst/validation/compare-comb-with-BOIN.R extends the comparison with BOIN to 200 configurations, and inst/validation/compare-with-LinYin2017.R sets the results beside Tables 2 and 3 of Lin and Yin (2017), whose rules differ in some details.

  • The waterfall design of Zhang and Yuan (2016), which looks for the MTD contour, and a time-to-event version of the drug-combination design are not provided.

3+3 decision table

  • decision_table_3p3() tabulates the rule of the 3+3 design used by oc_3p3() and sim_3p3(): the decision at three and at six patients during dose escalation and, for mtd_rule = "expand", during the search for the MTD that follows. It has print() and plot() methods in the style of the BOIN decision table. The tests follow the table through every possible course of a trial and obtain the operating characteristics of oc_3p3().

Documentation

  • A second vignette, vignette("simFastBOIN-tite"), describes the TITE-BOIN design. The introductory vignette gains a pointer to it and a paragraph on decision_table_3p3(). The README describes the design, how it is checked, and its speed: 10,000 trials of five doses and 20 cohorts of three take 0.09 s with the imputation method and 0.11 s with the effective sample size, against 0.05 s for sim_boin() on the same machine.

  • The labels of plot.tite_boin_decision_table() are shorter, the codes over the boundaries (for example E/S over >=2.15), so that they fit in the cells.

  • A third vignette, vignette("simFastBOIN-backfill"), describes the BF-BOIN and BE-BOIN designs, and the README and the introductory vignette point to it.

  • The DESCRIPTION cites the two TITE-BOIN articles and the three articles on backfilling and its suspension rules.

  • A fourth vignette, vignette("simFastBOIN-combination"), describes the drug-combination design, and the README and the introductory vignette point to it. The DESCRIPTION cites Lin and Yin (2017). The vignette also shows the decision table for a protocol and how to run a trial with comb_boin_next().

  • A pkgdown configuration (_pkgdown.yml) groups the reference pages by design and lists the four vignettes as articles.

  • The plot() methods of boin_decision_table(), tite_boin_decision_table() and comb_boin_next() draw the legend key of every decision or status, including those that do not occur in the figure, which ggplot2 3.5.0 and later otherwise leave blank.

simFastBOIN 2.0.0

CRAN release: 2026-09-18

The first release since 1.3.2, and a breaking one. Versions 1.4.0 and 1.5.0 were development versions on GitHub and were never released; their entries are kept below because the changes they describe are all part of this release. Anyone upgrading from 1.3.2 should read the 1.4.0 entry, which lists the renamed functions and the corrected defects.

This section covers three design options requested for a quality control review. Every new option is off by default, so a simulation run with version 1.4.0 arguments produces exactly the same trials, selections and summary figures. Two names in the returned objects did change, and are listed under their respective headings below: overdose60 and overdose80 moved into the new overdose component, and one reason code was renamed.

Staying on one DLT out of three

  • stay_on_1_of_3 makes one DLT out of three patients a stay rather than a de-escalation, which is the modification offered by the BOIN web application. It is available on boin_boundary(), boin_decision_table(), boin_simulate(), sim_boin() and sim_boin_multi().

    The option raises the de-escalation boundary at three patients from one DLT to two, so exactly one cell of the decision table changes and nothing else moves. It is applied only where one DLT out of three currently de-escalates: it never overrides an escalation, and it never overrides an elimination, which is a safety rule. boin_boundary() reports whether it took effect in stay_on_1_of_3_applied.

    With the default thresholds it takes effect for target rates from about 0.098 to 0.279. Note that the web application describes the range as 0.25 to 0.279; the upper end agrees, but the lower end is 0.098, below which one DLT out of three already eliminates the dose.

Bounding the MTD by a stated DLT rate

  • mtd_max_estimate caps the isotonic estimate a dose may have and still be selected as the MTD, on boin_select_mtd(), sim_boin() and sim_boin_multi(). It changes only the selection, never the dose-finding, so the decision table is untouched.

    bound_mtd caps the estimate at the de-escalation boundary, which always lies above the target rate. A cap at or below the target therefore cannot be expressed with bound_mtd at all, and needs mtd_max_estimate.

  • The reason code "no_dose_below_lambda_d" returned by boin_select_mtd() is now "no_dose_below_bound", since the bound need not be the de-escalation boundary.

Exposure to overly toxic doses

  • sim_boin() and sim_boin_multi() gain overdose_cutoff, and report an overdose component describing how far patients were exposed to doses whose true DLT probability exceeds it:

    • 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 the design ends up recommending such a dose, which is a separate question from exposure during the trial:

    • pct_trials_mtd_above, the percentage of all trials whose selected MTD is above the cutoff;
    • pct_mtd_above_when_selected, the same among the trials that selected an MTD at all.

    The cutoff defaults to target, which reproduces the earlier behavior.

  • This replaces the overdose60 and overdose80 components of the result, which are now overdose$pct_trials_over_60 and overdose$pct_trials_over_80. They are reported as zero rather than NA when no dose exceeds the cutoff, and the doses component names the dose levels that do.

Choosing a de-escalation boundary directly

  • boin_p_tox() returns the value of p_tox for which the de-escalation boundary equals a stated value, inverting boin_lambda(). A design team that wants to tighten the boundary usually states the boundary rather than the threshold behind it, and this turns that statement into the argument the other functions take.

    A boundary close to the target needs a threshold close to the target, and the rest of the package refuses a p_tox within ten percent of target. The inverted value is still returned, but a warning names the smallest boundary that leaves a usable threshold: about 0.315 for a target of 0.30.

Printing

  • print() on the result of sim_boin_multi() gains percent and digits, which the method for a single scenario already had. Passing percent = TRUE to the cross-scenario method previously fell into ... and was ignored, so the counts were printed as though nothing had been asked for.

Documentation

  • start_dose, added in version 1.4.0, is now documented as being ignored when titration = TRUE, because the titration phase always begins at the lowest dose. This matches the reference implementation.

  • The spelling throughout the documentation is now the United States spelling declared by the Language field, and tests/spelling.R keeps it that way. The colours argument of plot.boin_decision_table() is renamed colors accordingly. The argument was introduced in version 1.4.0, which was never released, so no released code is affected.

The 3+3 design as a comparator

  • oc_3p3() returns the operating characteristics of the traditional 3+3 design. The probability of every path the design can take is evaluated in closed form, so the result carries no Monte Carlo error and takes no seed. sim_3p3() simulates the same design and is there to confirm the closed form. Both return an object of class oc_3p3 whose components carry the same names as those of sim_boin(), so the two designs can be tabulated side by side, and print() lays them out the same way.

  • mtd_rule selects between the two definitions of the MTD in common use. "previous" names the dose below the one declared too toxic. "expand" takes the MTD to be the highest dose at which at most one of six patients had a DLT, expanding a dose that has only three patients before assessing it. Neither 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 therefore on the probability that a patient is exposed to an overly toxic dose; they differ in the sample size and in the selection percentages.

  • overdose_cutoff works as it does for sim_boin() and defaults to one third here, which is the rate the regulatory question is asked about. 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 have no counterpart and are not returned.

Validation

  • inst/validation/compare-with-BOIN.R compares the package against BOIN over 200 configurations, five dose-toxicity scenarios by five designs by eight option combinations, and covers extrasafe, titration and boundMTD. All 200 agree to within floating point on the selection percentages, the patients and DLTs at each dose, the percentage of trials ending without an MTD and the totals. This is a defect test rather than a Monte Carlo comparison, because the two implementations draw the same variates in the same order for a given seed. The options that BOIN has no counterpart for are checked separately, to confirm that each leaves the simulated trials untouched when it is off.

simFastBOIN 1.4.0

This is a substantial revision. The simulation engine has been rewritten in C++, the user-facing functions have been renamed, and several defects that affected numerical results have been corrected. Results obtained with version 1.3.2 are not reproduced by this version, even with the same seed.

Exact agreement with the BOIN package

The engine now draws one uniform variate per patient, in enrollment order, and applies the decision rules in the same order as BOIN::get.oc(). With the same seed and matching arguments the two implementations agree trial by trial rather than only on average. The test suite checks this directly against BOIN::get.oc() and BOIN::get.boundary() when the BOIN package is installed.

Version 1.3.2 claimed in its README that random number generation was the same as that of the BOIN package when the seed was fixed. That claim was incorrect, because trials were generated across trials rather than one at a time, and it has been removed.

Corrected defects

  • max_total_pts was computed as n_cohort * cohort_size[1], so a trial with a vector cohort_size used the wrong maximum sample size. It is now the sum of the cohort sizes.

  • With titration = TRUE and a vector cohort_size, the titration phase tested if (cohort_size > 1) on a vector, which stops with an error on R 4.2 and later.

  • The early stopping rule at n_earlystop was evaluated after the dose had already been changed, and therefore against the wrong dose. It is now evaluated at the dose that was just treated, before the transition, as in the reference implementation. This changes operating characteristics, in particular when a de-escalation lands on a dose that has already accrued n_earlystop patients.

  • MTD selection now re-derives dose elimination from the final data of the trial instead of carrying the elimination status over from the dose-finding stage. The two differ when a trial ends at its maximum sample size, because the last cohort was then never checked against the elimination boundary.

  • The isotonic fit used for MTD selection is now computed over the admissible doses only. Previously every treated dose entered the fit, so an eliminated dose could change the estimates at the doses below it and hence the selected MTD.

  • The tie-breaking perturbation was applied twice, once inside isotonic_regression() and once inside select_mtd(), and was indexed by dose level rather than by position in the admissible set. It is now applied once, during MTD selection, and boin_isotonic() returns the unperturbed estimates.

  • get_pts_and_tox() called set.seed() without restoring the state of the random number generator. The new functions restore it on exit.

  • Random number generation was not consistent within a trial: the titration phase, the ordinary cohorts and the final partial cohort used three different schemes, the last of which drew a binomial variate. All patients now use a single scheme.

Renamed functions

The old names remain available and issue a deprecation warning, but they return the value of the replacement function, which is not the value returned by version 1.3.2. See ?"simFastBOIN-deprecated".

Version 1.3.2 Version 1.4.0
get_boin_boundary() boin_lambda(), and boin_boundary() for the integer boundaries
get_boin_decision() boin_decision_table()
get_boin_stopping_boundaries() boin_boundary(extrasafe = TRUE)
get_pts_and_tox() boin_simulate()
isotonic_regression() boin_isotonic()
select_mtd() boin_select_mtd()

sim_boin() and sim_boin_multi() keep their names.

Changed interfaces

  • The design arguments come first: sim_boin(target, p_true, n_cohort, cohort_size, ...), with n_trials now an optional argument. Calls that relied on positional matching must be updated.

  • boundMTD is now bound_mtd, and return_details is now keep_trials.

  • sim_boin() returns an object of class boin_oc directly, rather than a list with a summary element. Selection percentages, average patient counts and average DLT counts are separate components, and the percentage of trials selecting no MTD is no longer appended to the selection vector.

  • sim_boin() and sim_boin_multi() now return their result visibly, so calling them at the prompt prints the summary and assigning the result is silent. Previously the result was invisible unless verbose = TRUE.

  • sim_boin_multi() uses the same seed for every scenario. Version 1.3.2 used seed + i for the i-th scenario, so a scenario simulated in a multi-scenario run did not match the same scenario simulated on its own.

  • sim_boin_multi() accepts a plain named list of p_true vectors in addition to the list of list(name, p_true) used previously.

  • boin_select_mtd() takes the patient and DLT counts, not precomputed isotonic estimates, since the fit depends on which doses are admissible.

  • Progress messages are emitted with message() rather than cat(), so they can be suppressed with suppressMessages().

New

  • start_dose, matching the reference implementation, which did not exist in version 1.3.2.
  • boin_boundary() returns the escalation, de-escalation, elimination and safety stopping boundaries as integer DLT counts indexed by sample size, with a print method that can restrict the table to the end of each cohort.
  • boin_decision_table() returns a classed object with print and plot methods. The print method blanks the impossible combinations and can restrict the table to the sample sizes reached at the end of a cohort; the plot method draws the table as a grid of colored cells, each carrying its decision letter so that the figure does not rely on color alone. It needs ggplot2, which is suggested rather than required.
  • boin_stopping_table() lays the safety stopping boundary out as a two-row table, one column per sample size.
  • boin_simulate() returns the raw trial data with a stop_reason for every trial, and has a print method.
  • Operating characteristics now include the risk of overdosing 60 and 80 percent of patients, and the distribution of the reason for stopping.
  • Arguments are validated. Out-of-range probabilities, thresholds too close to the target, non-monotone p_true and inconsistent counts are reported instead of propagating silently.

Dependencies

  • Added Rcpp, and utils for one call to globalVariables().
  • Added ggplot2 to Suggests, used only by plot.boin_decision_table().
  • Removed Iso. The pool adjacent violators algorithm is implemented in C++; Iso is now only suggested, and used in a test that checks the two agree.
  • knitr and kableExtra moved out of Imports. knitr is suggested and used for the vignette and for the optional table output; kableExtra is no longer used.
  • utils was imported in NAMESPACE but absent from DESCRIPTION. Neither imports it now.

Performance

The C++ engine replaces the vectorised R implementation, and MTD selection no longer calls out to R once per trial. For five doses, 20 cohorts of three, n_earlystop = 18 and 10000 simulated trials, one measurement gave 9.98 seconds elapsed for BOIN::get.oc() against 0.07 seconds for sim_boin(). The ratio depends on the design and on the machine, and the README carries the code that reproduces the measurement.

simFastBOIN 1.3.2

CRAN release: 2025-12-17

New Features

Customizable Safety and Toxicity Thresholds

  • Added p_saf and p_tox parameters to core functions

    • sim_boin(), sim_boin_multi(), and get_pts_and_tox() now accept custom safety and toxicity thresholds
    • p_saf: Highest toxicity probability deemed acceptable for safety (default: 0.6 * target)
    • p_tox: Lowest toxicity probability deemed unacceptable for toxicity (default: 1.4 * target)
    • These parameters are passed to get_boin_boundary() for boundary calculation
    • Stored in summary objects for reference and reproducibility
  • Usage examples

    # Using default thresholds (0.6 * target and 1.4 * target)
    result_default <- sim_boin(
      n_trials = 10000,
      target = 0.30,
      p_true = c(0.10, 0.25, 0.40, 0.55, 0.70),
      n_cohort = 10,
      cohort_size = 3,
      seed = 123
    )
    
    # Using custom thresholds
    result_custom <- sim_boin(
      n_trials = 10000,
      target = 0.30,
      p_true = c(0.10, 0.25, 0.40, 0.55, 0.70),
      n_cohort = 10,
      cohort_size = 3,
      p_saf = 0.15,  # Custom safety threshold
      p_tox = 0.45,  # Custom toxicity threshold
      seed = 123
    )

Documentation Improvements

  • Enhanced parameter documentation
    • Added comprehensive roxygen2 documentation for p_saf and p_tox parameters
    • All @param entries now use consistent multi-line format for better readability
    • Updated examples to demonstrate custom threshold usage
  • Expanded test coverage
    • Added tests for p_saf and p_tox parameter handling in sim_boin()
    • Added tests for p_saf and p_tox parameter handling in sim_boin_multi()
    • Added tests for p_saf and p_tox parameter handling in get_pts_and_tox()
    • Verified that custom values are correctly stored in summary objects
    • Verified that default values are correctly calculated when not specified

Breaking Changes

None. All existing code continues to work as before. The new p_saf and p_tox parameters have sensible defaults (0.6 * target and 1.4 * target respectively) that match the standard BOIN methodology, ensuring full backward compatibility.

Internal Changes

  • Updated function signatures to include p_saf and p_tox parameters with NULL defaults
  • Modified internal logic to calculate default values when parameters are not specified
  • Updated summary objects to store p_saf and p_tox values for reproducibility

simFastBOIN 1.3.1

Bug Fixes

  • Fixed DESCRIPTION Date field
    • Corrected Date from 2024-12-06 to 2025-12-06
    • This was a typo in the year field that was caught during CRAN submission process

No functional changes. All code and features remain identical to version 1.3.0.


simFastBOIN 1.3.0

New Features

Progress Message Control

  • Added verbose parameter to sim_boin() and sim_boin_multi()

    • Control whether progress messages are printed to console
    • verbose = FALSE (default): Run silently without progress messages
    • verbose = TRUE: Display progress messages as in previous versions
    • Particularly useful for R Markdown documents and vignettes where clean output is desired
    • Results are identical regardless of verbose setting
  • Usage examples

    # Silent mode (default) - ideal for vignettes and reports
    result <- sim_boin(
      n_trials = 10000,
      target = 0.30,
      p_true = c(0.10, 0.25, 0.40, 0.55, 0.70),
      n_cohort = 10,
      cohort_size = 3,
      seed = 123
    )
    
    # With progress messages
    result <- sim_boin(
      n_trials = 10000,
      target = 0.30,
      p_true = c(0.10, 0.25, 0.40, 0.55, 0.70),
      n_cohort = 10,
      cohort_size = 3,
      verbose = TRUE,
      seed = 123
    )

Documentation Improvements

  • Standardized roxygen2 documentation format
    • All parameter descriptions now use consistent multi-line format
    • Improved readability and maintenance
    • Enhanced consistency across all functions
  • Updated vignettes
    • Clean output without progress messages
    • Better integration with R Markdown workflows
    • Improved presentation quality

Breaking Changes

None. All existing code continues to work as before. The new verbose parameter defaults to FALSE, which changes the default behavior to silent mode, but all functionality remains identical.

Migration Guide

For users who prefer the previous behavior with progress messages:

# Add verbose = TRUE to see progress messages
result <- sim_boin(
  n_trials = 10000,
  target = 0.30,
  p_true = p_true,
  n_cohort = 48,
  cohort_size = 3,
  verbose = TRUE,  # Add this line
  seed = 123
)

simFastBOIN 1.2.1

New Features: Multi-Scenario Simulation and HTML Output

New Multi-Scenario Simulation Function

  • Added sim_boin_multi() function

    • Run BOIN simulations across multiple dose-toxicity scenarios simultaneously
    • Automatically orchestrates simulations for each scenario using sim_boin()
    • Aggregates results into a unified comparison table
    • Ideal for protocol development evaluating multiple dose-toxicity relationships
    • Returns results organized by scenario for easy comparison
    • Progress messages track simulation status for each scenario
  • Usage example

    scenarios <- list(
      list(name = "Scenario 1: MTD at DL4",
           p_true = c(0.05, 0.10, 0.20, 0.30, 0.45)),
      list(name = "Scenario 2: MTD at DL3",
           p_true = c(0.10, 0.15, 0.30, 0.45, 0.60))
    )
    
    result <- sim_boin_multi(
      scenarios = scenarios,
      target = 0.30,
      n_trials = 10000,
      n_cohort = 48,
      cohort_size = 3,
      seed = 123
    )

Enhanced Print Methods: HTML Table Output

  • Added html format option to print.boin_summary() and print.boin_multi_summary()

    • kable_format = "html": Generate HTML tables with enhanced styling
    • Includes striped rows, hover effects, and responsive formatting via kableExtra
    • Automatically applies visual formatting including bold headers and borders
    • Useful for web-based reports and interactive documents
    • Full support for embedded HTML display in R Markdown documents
  • Updated kable_format parameter documentation

    • "pipe" (default): Markdown pipe table format
    • "simple": Minimal text table format
    • "latex": LaTeX table format
    • "html": HTML table format with enhanced styling (NEW)
  • Enhanced print output examples

    # HTML table for web display
    print(result$summary, kable = TRUE, kable_format = "html")
    
    # Multi-scenario results as HTML
    print(multi_result, kable = TRUE, kable_format = "html")

Documentation and Output Formatting Enhancements

Comprehensive roxygen2 Documentation

  • Added detailed roxygen2-formatted documentation to all functions
  • Enhanced function comments
    • Added section headers for major processing blocks
    • Detailed explanations of algorithm steps and decision logic
    • Clear descriptions of parameter usage and constraints
    • Clarified relationships between input parameters and outputs
  • Added percent parameter
    • percent = FALSE (default): Display Avg Pts and Avg DLTs as absolute numbers
    • percent = TRUE: Display as percentages of total

All changes are backward compatible. New parameters have sensible defaults.


simFastBOIN 1.2.0

Bug Fixes and Compatibility

BOIN Package Compatibility

  • Restored exact compatibility with BOIN package
    • Changed DLT generation from runif() back to rbinom()
    • rbinom() ensures identical random number sequence as BOIN with same seed
    • Verified: MTD selection results now match BOIN within <0.5% across all scenarios

Default Parameter Corrections

  • Updated default values to match BOIN standard
    • min_mtd_sample: Changed from 6 to 1
      • Doses with ≥1 patient can now be considered for MTD selection
      • Matches BOIN package default behavior
    • n_earlystop_rule: Changed default from “simple” to “with_stay”
      • Trial now stops when n ≥ n_earlystop AND next decision = “Stay”
      • Ensures algorithm convergence before stopping
      • Follows BOIN standard implementation

Performance Optimizations

Vectorized Implementation

  • Batch processing for improved performance
    • Uses vectorized operations for fast simulation
    • Pre-allocated vectors and vectorized computations
    • Early exit for trials with no valid doses

DLT Generation Optimization

  • Optimized random number generation in sim_boin()
    • Uses rbinom() for accurate DLT generation matching BOIN package
    • Vectorized operations for efficient computation
    • Performance optimization particularly notable for large-scale simulations

MTD Selection Enhancement

  • Optimized select_mtd() function
    • Returns NA immediately when no valid MTD candidates exist
    • Avoids unnecessary computations for trials without viable doses
    • Improves overall simulation efficiency

Internal Improvements

  • Enhanced code documentation with detailed optimization rationale
  • Improved memory efficiency through pre-allocation
  • Maintained backward compatibility with existing APIs

Documentation Updates

  • Updated roxygen2 documentation in sim_boin.R
  • Updated parameter descriptions
  • Updated README.md with corrected default values

Breaking Changes

None. The changes restore compatibility and fix defaults to match standard BOIN behavior. Users running with explicit parameters should see no change.

Migration Guide

For users upgrading from simFastBOIN 1.1.0:

If you were using defaults:

# Old code (simFastBOIN 1.0.0)
result <- sim_boin(n_trials = 10000, target = 0.30, p_true = p_true, ...)

# New code (simFastBOIN 1.2.0) - No change needed!
# Default behavior now matches BOIN package
result <- sim_boin(n_trials = 10000, target = 0.30, p_true = p_true, ...)

If you were using custom parameters:

# Explicitly setting these will ensure consistent behavior across versions
result <- sim_boin(
  n_trials = 10000,
  target = 0.30,
  p_true = p_true,
  min_mtd_sample = 1,        # Now the default
  n_earlystop_rule = "with_stay",  # Now the default
  ...
)

simFastBOIN 1.0.0

Initial Release

Core Features

  • High-Performance BOIN Simulation
    • Vectorized implementation for 2-5x speedup over traditional approaches
    • Batch processing of all trials simultaneously at each cohort
    • Efficient matrix operations for state management
  • Automatic Decision Table Generation
    • sim_boin() automatically generates BOIN boundaries and decision tables
    • No need for manual pre-computation
    • User-friendly API with minimal required parameters
  • Safety Features
    • Optional extrasafe parameter for safety stopping at lowest dose
    • Dose elimination rules based on posterior probability
    • Configurable safety thresholds
  • Professional Output
    • Publication-ready summary tables
    • Optional knitr::kable format for RMarkdown
    • Detailed trial-level results available

Main Functions

Performance

  • 10,000 trials with 9 doses and 48 cohorts: ~1-2 seconds
  • Memory efficient: <100MB for typical simulations
  • Scales with number of cohorts, not number of trials

Documentation

  • Comprehensive function documentation with examples
  • Detailed README with quick start guide
  • Performance benchmarks and comparisons