fitLogrank() is faster. It now computes the
(stratified) log rank statistic directly from
survival::survdiff() as observed-minus-expected events over
its standard error, instead of fitting two Cox models per treatment arm
(one for the sign of the effect and one with ties = "exact"
for the score test). Its magnitude agrees with the previous exact-score
statistic up to floating point rounding, while its sign now consistently
follows the treatment log-rank score; with tied event times this can
correct the previous sign when the Efron Cox coefficient pointed in the
opposite direction. info and the tidy = FALSE
columns are unchanged. When the statistic is undefined because its
variance is zero (e.g., no event in the subset), a warning is issued and
a simulation placeholder z = 0 with the corresponding
p = 0.5 is returned instead of an error. On a three-arm
dose-selection design with log rank tests at two milestones this removes
roughly 40% of the per-replicate time, and roughly a third on an
enrichment design driven by conditional power.regimen_trajectory to the switches that have happened by
the lock time, and the n_switches count, are now computed
for all switching patients at once (one strsplit() plus
tabulate()), instead of a per-patient mapply()
followed by a per-patient regular expression. Both columns are unchanged
for names without the reserved characters below; on a 1000-patient
three-arm design with crossover this removes roughly 14% of the
per-replicate time.'@' and ';' are now reserved characters of
the regimen_trajectory encoding: arm() rejects
a name containing either, whether or not the trial uses a regimen (e.g.,
arm(name = 'dose@5mg') used to be accepted and now is an
error), and what() of a regimen or of
crossover() must not return a new_treatment
containing either. Previously such names silently corrupted the
trajectory and n_switches. Data locking also asserts that
every trajectory with a switch parses cleanly and keeps its initial
segment.tidy in controller$run()
(default FALSE). With tidy = TRUE, the per-arm
event count table (output column
n_events_<milestone>_<arms>) is not saved at
milestones; per-endpoint totals and milestone times are still saved, and
the table remains available in the attributes of locked data, so
event_plot() is unaffected. Saving that table is the most
expensive part of the standard outputs: skipping it removes roughly 15%
of the per-replicate time on a small two-arm design with trivial actions
(on top of 1.35.5) and about 3% on a three-arm dose-selection design
with log-rank tests at milestones. Unlike tidy in
get_output(), which removes columns after the fact, this
avoids the cost entirely.controller$run() collects the output of each replicate
in a list and row-binds once at the end, instead of calling
bind_rows() after every replicate (a fixed cost of roughly
1 ms per call). The same applies to the parallel path. Outputs are
unchanged, including the partial output kept when a replicate fails.
Removes roughly 10% of the per-replicate time on a small two-arm design
with trivial actions and 3-5% on heavier designs.enroll_patients()
now assembles the patient data of each arm directly from one generated
pool, skipping the per-stratum bookkeeping (table(),
merge(), split(), bind_rows())
that stratified randomization requires. Generator and dropout functions
are called in exactly the same order and with the same sizes as before,
so the random number stream and therefore all results are unchanged for
a given seed (a regression test pins the patient data of a fixed-seed
trial to reference values). On a small two-arm design with trivial
actions this removes roughly 19% of the per-replicate time; the relative
gain shrinks as the statistical work per milestone grows.arm(name, ...)). The criteria are now
applied as a logical row mask with the semantics of
dplyr::filter() (conditions combined with
&, rows with NA dropped,
.data/.env pronouns supported), instead of
calling dplyr::filter() in every round of the
rejection-sampling loop. The mask evaluation is shared with the
lock-time fast path of 1.35.2 (internal
filter_conditions_mask()). The human-readable criteria
string used in error messages is also built once, when the arm is
created, instead of on every generator call (deparsing quosures is not
free). Results are unchanged; on a 1000-patient three-arm design with
pfs <= os as inclusion criterion this removes roughly 9%
of the per-replicate time.eventNumber(endpoint = 'pfs', n = 40, patient_id <= 70)
or enrollment(n = 100, biomarker == 1), now take the C++
lock-time fast path. The subset conditions are reduced to a logical row
mask with the semantics of dplyr::filter() (conditions
combined with &, rows with NA dropped,
.data/.env pronouns supported) and the
existing C++ helpers are applied to the subset, instead of building
per-endpoint event tables with dplyr for every endpoint in
the trial. Results are unchanged; the pure-R path remains available
through options(trialsimulator.use_cpp = FALSE). On an
enrichment design whose milestones are all subgroup-filtered this
removes roughly 11% of the per-replicate time.n_switches column of locked data is now computed on the
subset of patients who switched treatment, instead of running a regular
expression over the regimen_trajectory of every enrolled
patient at every milestone. Results are unchanged; for a 1000-patient
three-arm design with crossover this removes roughly 9% of the
per-replicate time.trial$add_arms() deep-clones every
arm it registers, and trial$add_regimen() deep-clones the
regimen. Consequently, changes made to the caller’s arm or regimen
objects after registration no longer affect the trial, and adaptations
within the trial (e.g., trial$update_generator(),
trial$crossover()) no longer modify the caller’s objects,
so those objects can be safely reused, e.g., to build another trial.
Complete the configuration of an arm before registering it; after
registration, change it only through the trial’s adaptation methods. The
copy covers the arm, endpoint, and regimen objects themselves; a mutable
environment or R6 object captured by a user-supplied function
(generator, action,
what/when/how) is shared by
design of R closures and is not isolated.trial$add_arms() registration is now transactional: all
incoming arms are validated (including endpoint-set consistency and
re-use of the name of a previously removed arm) before any of them is
installed, so a failing batch no longer leaves the trial partially
modified. Re-adding an arm under the name of a removed arm is rejected
explicitly; previously it failed halfway with the trial left partially
modified.controller$run() now restores the listener’s milestones
to their as-designed state before the first replicate. Previously,
reusing a listener from an earlier controller in the same session left
its milestones in a triggered state, silently suppressing them in the
new run.controller$run() shared its endpoint objects with the live
arms, so a trial$update_generator() call in one replicate
silently altered the data-generating process of all later replicates,
and a failing replicate could not be reproduced from the seed reported
in its error message. The snapshot now deep-clones endpoints, and every
replicate starts from freshly cloned, as-designed arms.trial$update_generator() now accepts
endpoint_name in any order. Endpoint names registered
together in one endpoint() call are matched as a set, so,
e.g., c('pfs', 'biomarker') and
c('biomarker', 'pfs') are equivalent. Previously the names
had to be given in registration order, and a reordered vector was
rejected with a misleading error message. In addition, when
endpoint_name covers only part of a registration, or mixes
names from different registrations, the error message now spells out the
exact endpoint_name vector(s) to use.trial$eventNumberReestimationFromConditionalPower()
re-estimates the number of events at the final analysis for every
treatment-vs-placebo comparison of a time-to-event endpoint: the
smallest whole number of events, greater than the number observed at a
triggered interim milestone, at which the conditional power of
trial$conditionalPower() reaches a target. Conditional
power can be evaluated at the interim trend or at a user-specified
hazard ratio, and a practical cap can be imposed through
D_cap. When no solution exists in the requested range,
D and achieved_cp are NA and
target_reached is FALSE. The search is exact
even when conditional power is not monotone in the event number.trial$conditionalPower() and the new method.effect argument of
trial$conditionalPower() no longer has a default value; it
must be specified explicitly as 'trend',
'null', or a hazard ratio.trial$conditionalPower() computes
conditional power at a triggered interim milestone for every
treatment-vs-placebo comparison of a time-to-event endpoint, under a
group sequential design with one interim and one final analysis. It
pulls the milestone’s locked data automatically and calls
fitLogrank() internally to obtain the observed z statistic
and number of events of each comparison. Conditional power can be
evaluated at the interim trend (default), under the null, or at a
user-specified hazard ratio, which is converted internally using the
allocation ratio in effect at the milestone. Its alpha
argument is the one-sided nominal significance level corresponding to
the planned final critical boundary, not the total design alpha or alpha
spent at the final look. The calculation assumes the trial continues as
designed (constant allocation ratio of the compared arms, planned final
statistic and boundary); it is users’ responsibility to call it only
when legitimate, e.g., not after the allocation ratio of the compared
arms was adapted, as TrialSimulator does not verify this.
Results are validated against rpact and
gsDesign in unit tests.dry_run argument of controller$run()
is now defunct.controller$run() can no longer be called twice without
reset() in between. Previously, a second run()
silently continued the already-executed trial (all milestones already
triggered, snapshots partially overwritten) instead of starting a new
simulation. To define a milestone whose triggering condition or action
depends on interim results, register it upfront and revise it within an
action function through update_milestone().save_milestone_time() only after the trial clock had been
moved backwards and the locked snapshot stored; that check remains as an
internal assertion, and set_current_time() gains a backstop
against backward clock moves.listener$add_milestones() now raises an error when a
milestone with the same name is already registered. Previously it warned
and silently over-wrote the registered milestone. To modify a
not-yet-triggered milestone within an action function, use
update_milestone().Arms$get_number_endpoints(),
Endpoints$get_readout() and
Endpoints$get_type() are now private. The machinery methods
of Arms (get_name(),
get_endpoints_name(), has_endpoint() and
update_endpoint_generator()) and of Endpoints
(get_uid() and update_generator()), which stay
public only because trials and arms invoke them, now carry a bold
warning that users should not call them directly.Controllers, Arms and Endpoints
now come with brief usage notes in the class description; exploratory
methods (test_generator(), get_generator() and
get_name() of Endpoints;
generate_data() and get_endpoints() of
Arms) are documented as helpful for understanding the
classes but not needed in formal simulation.Controllers$get_trial(),
Controllers$get_listener(),
Controllers$mute(),
Milestones$execute_action(),
Milestones$get_type(),
Milestones$get_trigger_condition(),
Milestones$get_action(),
Regimens$get_number_time_selector() and
Regimens$get_number_data_modifier() are now private. They
were used only internally by their own classes.Milestones and all
public methods of Regimens are invoked on their objects by
other components of the package (listeners and trials) and stay public
only for that reason; they now carry a bold warning that users should
not call them directly, in the same style as the Trials and
Listeners classes.Listeners class:
get_milestones() is now private. The machinery methods
monitor(), mute() and reset(),
which stay public only because the controller invokes them, now carry a
bold warning that users should not call them directly, in the same style
as the Trials class.trial$set_duration(), trial$resize(),
trial$remove_arms(),
trial$update_sample_ratio() and
trial$update_generator() now raise an error when called
before any milestone has been triggered, i.e., outside an action
function.trial$update_milestone() (wrapper
update_milestone()): update the triggering condition and/or
the action of a not-yet-triggered milestone from within an action
function. The update takes effect right after the current action
function returns, and the as-designed milestone is restored between
simulation replicates.action of a milestone must be a function;
NULL is no longer accepted. Use doNothing if
no action is intended.Trials class: 38 methods
used only internally are now private (including
censor_trial_data(), roll_back(),
enroll_patients(), get_trial_data() and
independentIncrement()), leaving 34 public members whose
definitions and documentation are reorganized into sections: adaptation
methods, methods callable within action functions (data access and
manipulation, trial status queries, statistical testing), trial setup
(add_regimen(), which must not be called within action
functions), and internal machinery. Machinery methods that stay public
only because other components of the package invoke them now carry a
bold warning that users should not call them directly.make_snapshot() distinguishes private methods from data
fields via bindingIsLocked() (R6 locks the binding of every
member defined as a function) instead of a hardcoded name list, so
snapshot/reset stay correct as methods are added..data$ in tidyselect contexts
(rename()/select() in the correlated PFS/OS
generators, PiecewiseConstantExponentialRNG(), and endpoint
naming) with string literals, eliminating the tidyselect deprecation
warnings that flooded test output. .data$ remains in
data-masking contexts (filter(), mutate(),
aes()), where it is still the recommended idiom;
R CMD check stays clean.set_dropout() documentation no longer claims adaptive
use: dropout times are generated at enrollment, so updating the
generator within an action function would not apply to enrolled
patients..gitignore and
exclude .DS_Store from the build via
.Rbuildignore.event_plot() now
selects the endpoint column via all_of() (tidyselect
external-vector deprecation), and plot.three_state_model()
zooms with coord_cartesian() instead of
xlim(), so the dashed guide segments anchored at the axes
are clipped and rendered rather than dropped with a ggplot2
warning.Rplots.pdf appearing
after test runs: summarizeDataFrame() restored
par() settings via on.exit() after its
png() device was already closed, which implicitly opened
the default device. par() settings are local to the device
and need no restore.make_snapshot() silently dropped
NULL-valued private fields from the snapshot (assigning
NULL with [[<- deletes a list entry);
reset()’s explicit re-null list masked this for existing
fields. The snapshot now preserves NULL fields, so any
future field is restored across simulation replicates by
construction.dunnettTest() that referenced
an undefined variable.doseRanging vignette that
compared a string literal instead of the decision
column.doseRanging
and fixedDesign vignettes under the 1.25.2 enrollment
convention; the fixedDesign output now contains the 1,000
replicates its code states (previously 100).R CMD check GitHub Actions workflow
(macOS/Windows/Ubuntu; R release/devel/oldrel).\value sections to exported help topics, a grouped
reference index for the pkgdown site, and mention the newest adaptations
in the actionFunctions vignette introduction.graphicalMCP entry from
Suggests.trial$update_accrual_rate()
(wrapper update_accrual_rate()): update the accrual rate of
the recruitment curve at a milestone, e.g., to revise recruitment after
dose selection or enrichment, or to pause it for a period after an
interim decision. end_time of the new
accrual_rate is measured from the milestone; patients not
yet enrolled (and the enrollment reserves used by resize())
are re-planned and re-randomized under the new schedule, while enrolled
patients are left unchanged. Like other adaptations, it must be called
within an action function, after a milestone has been triggered.StaggeredRecruiter() now enrolls patient k
when the planned cumulative accrual reaches k (previously
k - 1): under a constant rate r the
n-th patient enrolls exactly at n / r, so a
milestone triggered by enrollment(n) occurs exactly at the
planned accrual time. The first patient enrolls at
1 / piecewise_rate instead of time 0, and all enrollment
times shift by one inter-arrival accordingly; simulation results under a
fixed seed differ slightly from 1.25.1. The precomputed output of the
adaptiveDesign vignette is regenerated under the new
convention.sample() without stratification. The warning is suppressed
when silent = TRUE.trial$stop_followup() (wrapper
stop_followup()): stop follow-up of a subset of enrolled
patients at a milestone, optionally after extra follow-up time
(additional_followup). Patients are selected by conditions
compatible with dplyr::filter; affected time-to-event
endpoints are censored and non-time-to-event readouts are set to
missing. This adaptation supports, e.g., treatment discontinuation and
enrichment design. Like other adaptations, it must be called within an
action function, after a milestone has been triggered.censor_trial_data() gains ... to further
restrict the patients to be censored by conditions compatible with
dplyr::filter, in addition to selected_arms
and enrolled_before. Internal callers are unchanged and
benchmark at parity with 1.24.0; simulation outputs are identical.controller$run() now displays a progress bar when
silent = TRUE and n_workers = 1 if the
simulation is expected to take more than 1 minute. Package
cli is added to Imports for this feature.trial() now defaults enroller to
StaggeredRecruiter and accepts no other enroller: any
non-StaggeredRecruiter value is rejected with an
informative error. The enroller argument is retained for
backward compatibility, so existing code that passes
enroller = StaggeredRecruiter explicitly is unaffected, and
code that omits it now gets the default.test-enroller.R covering the default, explicit
StaggeredRecruiter, rejection of other enrollers, and
post-construction set_enroller() enforcement.StaggeredRecruiter() now supports recruitment pauses: a
window with piecewise_rate = 0 enrolls no one while
calendar time still advances, so accrual resumes at the window’s
end_time. Pauses may occur in the first window or span
several consecutive windows (e.g., a safety hold, a site not yet
activated, or a seasonal gap).StaggeredRecruiter() enrollment times are now the
deterministic inverse of the cumulative accrual intensity: the
cumulative accrual capacity increases by window length ×
piecewise_rate across each window (no per-window
truncation), so an integer-capacity window holds exactly that many
patients. Single open-ended schedules and integer-capacity windows are
unchanged; schedules with fractional per-window capacity now yield
slightly different (more accurate) times.StaggeredRecruiter() input validation is stricter: the
last end_time must be Inf with a positive rate
(so the schedule can always supply the patients the engine requests,
including the inflated count used for adaptive resizing); a positive
rate too low to enroll even one patient (window length ×
piecewise_rate < 1) is now an error pointing to
piecewise_rate = 0; and n must be a positive
integer.test-StaggeredRecruiter.R covering pauses (leading,
middle, and consecutive), the per-window count property, equidistant
spacing, the low-rate and schedule-shape validation errors, and
n validation.GraphicalTesting$test() no longer errors with
alpha_spent should be monotonically increasing when a
hypothesis is first tested only at a later (or final) look. This happens
when a hypothesis holds zero or very small allocated alpha at early
looks and inherits alpha after another hypothesis is rejected: those
looks yield a degenerate (flat, near-zero) reconstructed cumulative
alpha-spent sequence. Such entries are now truncated and floored to a
strictly increasing sequence before being passed to the group sequential
boundary computation.computeCumulativeAlphaSpent
treats Inf boundaries as zero increments.endpoint() now accepts type = "baseline"
for a non-tte endpoint observed at randomization (e.g., a baseline
covariate, biomarker, or subgroup indicator). Its readout is
0 by definition and must be omitted from
readout. For forward compatibility, a non-tte endpoint
observed at randomization can still be defined the existing way with
readout = 0. Endpoints$new() continues to
recognize only "tte" and "non-tte"; the
conversion happens in endpoint().crossover().regimen()/crossover() examples
and help pages to use the natural
ifelse(condition, new_value, original) idiom in
how() and to return only the switching patients in
what(), rather than relying on NA to mark
unchanged cells or non-switchers. The engine still accepts
NA for backward compatibility.crossover() for milestone-triggered treatment
crossover. Called inside a milestone’s action function, it lets patients
still in the trial switch treatment at (or after) the milestone,
altering only their post-switch endpoint values. Regimens are unified
under one contract keyed off an earliest crossover time; the classic
enrollment regimen added via add_regimen() is the
T = 0 case.how() may now only modify post-switch
outcomes: returning a value that differs from the original for an
endpoint whose readout/event is at or before switch_time (a
pre-switch or already-observed outcome) raises an error. Guard such
how() functions accordingly,
e.g. os = ifelse(os > switch_time, new_os, os).Surv() and strata() from the
survival package so that user-supplied formulas in action
functions (e.g. Surv(os, os_event) ~ arm) work after
library(TrialSimulator) alone, without requiring
library(survival) or the survival:: prefix.
This fixes errors in parallel runs (n_workers > 1) where
each worker only attaches TrialSimulator (reported in
#14).'or' would error out when not all of its branches
could be reached, instead of resolving to the reachable branch.eventNumber() and enrollment() conditions.
Wall-time reduction ranges from a few percent to ~20% depending on how
condition-evaluation-heavy the design is, with no change to results. Set
options(trialsimulator.use_cpp = FALSE) to fall back to the
original R implementation.doseRanging.Rmd now loads pre-computed simulation output;
simulatePfsAndOsGumbel.Rmd uses a smaller validation
sample).CorrelatedPfsAndOs2() to simulate correlated PFS
and OS using a Gumbel copula while targeting marginal PFS/OS medians and
Kendall’s tau between observed, uncensored PFS and OS times.dplyr::filter() call in
Trials$get_event_tables() when no filter expression is
provided, reducing total simulation wall time by roughly 5-10% in trials
with frequent milestone condition checks.n_switches column to locked data returned by
get_locked_data(), counting the number of treatment
switches per patient within the data lock window.expandRegimen() to expand the
regimen_trajectory column in locked data into a long-format
data frame with one row per regimen segment per patient.trial() using argument
stratification_factors.... in regimen() to pass arguments
to what(), when() and how().regimen() to support both single or
multiple switching.regimen().enrollment() to define milestone. This bug does not affect
milestone triggering.tidy (default: TRUE) in
Controllers$run() to stop computing and saving event count
per arm per endpoint for 40% shorter run time.solvePiecewiseConstantExponentialDistribution() to compute
event rates in time windows given survival probabilities at
changepoints.qPiecewiseExponent(), the quantile function of
piecewise exponential distribution. This function is useful to simulate
time-to-event endpoint that is correlated to other endpoints using the
copula method. For example, the simdata package needs
marginal quantile functions.Controllers$run() through
new argument n_workers. The package mirai is
used. Although mirai advocates the use of L’Ecuyer-CMRG
streams to maintain independence between multiple streams, however,
TrialSimulator resets it to be Mersenne-Twister streams to
force identical behavior between n_workers = 1 and
n_workers > 1. This enables debuggability and
reproduciability under single-process mode by setting seed that causes
issues under multi-process mode.remove_arms(), add_arms(),
update_sample_ratio(), set_duration(),
resize() and update_generator().Trials$resize() that resizes an
ongoing trial.get_output() by setting new argument
tidy = TRUE.Trials$update_generator().enforce = TRUE is no longer needed when adding new arms
to an existing trial with at least one arm through
Trials$add_arms(). However, for backward compatibility,
legacy codes with enforce = TRUE still behaves as expected
and no need to update.milestone_name. Now action function only requires argument
trial and supports optional arguments.milestone() now support ... to pass
arguments to action functions.enrollment() now supports
min_treatment_duration to ensure minimum treatment duration
received by patients at a milestone. With its default value 0, milestone
is triggered when a specific number of patients are enrolled.invisible(NULL) is no longer recommended as return value of
action function.event_plot() for plot of
cumulative events number when endpoint name is "ep". This
is due to data masking in dplyr.update_sample_ratio. This test is probably broken by
randomness (it is okay).summarizeMilestoneTime and its plot method
to summarize triggering time of milestones.update_sample_ratio() now supports updating multiple
arms simultaneously. When ratio is not a whole number,
sample() is used to replace the permuted block algorithm to
randomize patients to arms. This enable response-adaptive design.update_sample_ratio().-Add vignette of fixed design. -Add vignette of wrapper functions of commom statistical tests.
enroll_patients. This is useful when a milestone is
triggered after all patients are recruited.... in eventNumber to count event
in subset of trial data. This is useful in enrichment design when
milestone is defined based on biomarker.get as alias of
get_custom_data in the Trials class.trial$dunnettTest(..., planned_info = "default") triggers
an error.Trials$dunnettTest to be compatible to one-sided
logrank test.fitLogrank now supports
formula. strata(...) can be in
formula. No covariate is accepted.fitLogistic.fitLogistic now supports
scale = "coefficient" to compute regression coefficient as
main effect of arm in the presence of covariates. It is
also equivalent to scale = "log odds ratio" in the absence
of covariates.fitLogistic.fitCoxph now supports formula
to compute log hazard ratio or hazard ratio as main effect of
arm. It will detect whether arm’s main effect is specified
in formula. It allows covariates and interaction between covariates and
arm. However, only the main effect of arm is tested and returned.fitCoxph.fitLogistic now supports computing log
odds ratio, odds ratio, risk ratio, and risk difference using
emmeans contrast, in the presence of covariates.fitLogistic and
fitLinear.fitLogistic now supports
formula with covariates, and uses emmeans
contrast to compute average treatment effect (ATE) on the
logit scale.fitLinear now supports
formula with covariates, and uses emmeans
contrast to compute average treatment effect (ATE) on the mean
scale.trigger_condition in the function
milestone is deprecated and is replaced with
when. Note that trigger_condition is still
supported in the R6 class Milestones.trial$get_custom_data throws an error
when n > 1 in controller$run(n) because
custom data is wiped out in trial$reset.arm through the
... argument.rmarkdown.rmarkdown.controller() as per
suggestion from CRAN team.message() so
that Shiny app can display it properly.solveMixtureExponentialDistribution to
compute median of exponential endpoint of subgroup or the overall
population.endpoints, arm,
trial, event, listener and
controller for Endpoint$new,
Arm$new, Trial$new, Event$new,
Listener$new and Controller$new.Trial$set_duration.enroll_a_patient. Use
enroll_patients only.n > 1 in
Controller$run when an arm can possibly be removed
adaptively during a trial.enrollment. This is useful to
count randomized patients of all arms even if some are removed
adaptively.GraphicalTesting
and graphicalMCP to repository TrialSimulatorDocuments.Controller$run now can specify number of simulation
replicates by newly added argument n. If n is
greater than 1, simulation results can be accessed in
Controller$get_output().StaggeredRecruiter to force the enrollment
time of the first patient is zero. This is an known issue but I was too
lazy to fix it. Earlier version may have overestimated time of
events.fitFarringtonManning of Farrington-Manning
test for rate difference.Trial$bind to row bind data frame in
action functions. It is useful to prepare inputs of group sequential or
graphical test.weibullDropout to compute parameters of
Weibull distribution when using it for dropout distribution.1e-5 while no alpha should have been propagated.enrollment, eventNumber and
calendarTime can be combined with & and
|. Nested combination is supported by using
parentheses.TriggerByEventNumbers and
TriggerByCalendarTime are therefore deprecated.fitLogistic to fit logistic regression
model.generator in
Endpoint.GraphicalTesting when a hypothesis is
tested multiple times at the same stage because more alpha is passed
from other rejected hypothesis.do_nothing() if users
have no intent to do anything at a triggered event. This function can be
passed to the argument action when creating a new event,
e.g.,
Event$new(name = 'interim', trigger_condition = TriggerByCalendarTime, action = do_nothing, calendar_time = 64).Controller$run() and insert error
message into output (see Trial$get_output()$error_message).
It helps to integrate TrialSimulator with
targets.Trial$get_seed().GraphicalTesting based on simplified interface
of GroupSequentialTest.