99# '
1010# ' This class is based on the Python class `OnlineStatistics` from Tom Monks
1111# ' (2021) sim-tools: fundamental tools to support the simulation process in
12- # ' python (https://github.com/TomMonks /sim-tools) (MIT Licence).
12+ # ' python (https://github.com/sim-tools /sim-tools) (MIT Licence).
1313# '
1414# ' @docType class
15- # ' @importFrom R6 R6Class
1615# '
1716# ' @return Object of `R6Class` with methods for running mean and variance
1817# ' calculation.
@@ -128,10 +127,9 @@ WelfordStats <- R6Class("WelfordStats", list( # nolint: object_name_linter
128127# '
129128# ' This class is based on the Python class `ReplicationTabulizer` from Tom
130129# ' Monks (2021) sim-tools: fundamental tools to support the simulation process
131- # ' in python (https://github.com/TomMonks /sim-tools) (MIT Licence).
130+ # ' in python (https://github.com/sim-tools /sim-tools) (MIT Licence).
132131# '
133132# ' @docType class
134- # ' @importFrom R6 R6Class
135133# '
136134# ' @return Object of `R6Class` with methods for storing and tabulising results.
137135# ' @export
@@ -205,10 +203,9 @@ ReplicationTabuliser <- R6Class("ReplicationTabuliser", list( # nolint: object_n
205203# '
206204# ' This class is based on the Python class `ReplicationsAlgorithm` from Tom
207205# ' Monks (2021) sim-tools: fundamental tools to support the simulation process
208- # ' in python (https://github.com/TomMonks /sim-tools) (MIT Licence).
206+ # ' in python (https://github.com/sim-tools /sim-tools) (MIT Licence).
209207# '
210208# ' @docType class
211- # ' @importFrom R6 R6Class
212209# '
213210# ' @return Object of `ReplicationsAlgorithm` with methods for determining the
214211# ' appropriate number of replications to use.
@@ -304,7 +301,7 @@ ReplicationsAlgorithm <- R6Class("ReplicationsAlgorithm", list( # nolint: object
304301 stop(" desired_precision must be greater than 0." , call. = FALSE )
305302 }
306303 if (self $ replication_budget < self $ initial_replications ) {
307- stop(" replication_budget must be less than initial_replications." ,
304+ stop(" replication_budget must be greater than initial_replications." ,
308305 call. = FALSE )
309306 }
310307 },
@@ -333,8 +330,13 @@ ReplicationsAlgorithm <- R6Class("ReplicationsAlgorithm", list( # nolint: object
333330 call. = FALSE )
334331 }
335332
336- # Check if list is empty or no values below threshold
337- if (length(lst ) == 0L || all(is.na(lst )) || ! any(unlist(lst ) < 0.5 )) {
333+ # Check if list is empty or all NA
334+ if (length(lst ) == 0L || all(is.na(lst ))) {
335+ return (NULL )
336+ }
337+
338+ # Check that there are no values below threshold
339+ if (! any(unlist(lst ) < self $ desired_precision , na.rm = TRUE )) {
338340 return (NULL )
339341 }
340342
@@ -504,6 +506,82 @@ ReplicationsAlgorithm <- R6Class("ReplicationsAlgorithm", list( # nolint: object
504506))
505507
506508
509+ # ' Automated replications selection using Welford‑based online statistics.
510+ # '
511+ # ' @description
512+ # ' A user‑friendly wrapper around the ReplicationsAlgorithm class that:
513+ # ' - Runs the replications sequence
514+ # ' - Returns minimum required replications for each metric
515+ # ' - Returns summary tables for each metric (replication‑by‑replication)
516+ # '
517+ # ' Based on Hoad, Robinson, & Davies (2010) "Automated selection of the number
518+ # ' of replications for a discrete-event simulation".
519+ # ' You just call this as a function, without exposing the R6 internals.
520+ # '
521+ # ' @param param List, model configuration (passed to your `runner` or `model`).
522+ # ' @param metrics Character vector of metric names (columns in `run_results`).
523+ # ' @param desired_precision Target deviation of CI half‑width as proportion
524+ # ' of the mean, e.g. `0.1` for 10%.
525+ # ' @param initial_replications Number of initial replications.
526+ # ' @param look_ahead Minimum extra replications to “look ahead”.
527+ # ' @param replication_budget Maximum allowed replications.
528+ # ' @param verbose Logical; whether to print startup messages.
529+ # '
530+ # ' @return A list with:
531+ # ' \itemize{
532+ # ' \item `nreps` named list of min replications per metric (or `NA` if not
533+ # ' met).
534+ # ' \item `summary_table` dataframe with per‑replication statistics for all
535+ # ' metrics.
536+ # ' \item `status` character vector: metrics for which desired precision was
537+ # ' not reached.
538+ # ' }
539+ # ' @export
540+ run_replications_algorithm <- function (
541+ param ,
542+ metrics = c(" mean_waiting_time_nurse" ,
543+ " mean_serve_time_nurse" ,
544+ " utilisation_nurse" ),
545+ desired_precision = 0.1 ,
546+ initial_replications = 3L ,
547+ look_ahead = 5L ,
548+ replication_budget = 1000L ,
549+ verbose = TRUE
550+ ) {
551+ # Construct the R6 algorithm object
552+ alg <- ReplicationsAlgorithm $ new(
553+ param = param ,
554+ metrics = metrics ,
555+ desired_precision = desired_precision ,
556+ initial_replications = initial_replications ,
557+ look_ahead = look_ahead ,
558+ replication_budget = replication_budget ,
559+ verbose = verbose
560+ )
561+
562+ # Run the algorithm
563+ alg $ select()
564+
565+ # Extract results in a plain‑list form
566+ nreps <- as.list(alg $ nreps ) # numeric/NA for each metric
567+
568+ # Identify which metrics didn’t converge
569+ unsolved <- names(nreps )[vapply(nreps , is.na , logical (1L ))]
570+ # nolint start: keyword_quote_linter
571+ status <- if (length(unsolved ) > 0L ) {
572+ c(" not_converged" = unsolved )
573+ } else {
574+ c(" converged" = NA_character_ )
575+ } # nolint end: keyword_quote_linter
576+
577+ list (
578+ nreps = nreps ,
579+ summary_table = alg $ summary_table ,
580+ status = status
581+ )
582+ }
583+
584+
507585# ' Use the confidence interval method to select the number of replications.
508586# '
509587# ' This could be altered to use WelfordStats and ReplicationTabuliser if
@@ -514,10 +592,6 @@ ReplicationsAlgorithm <- R6Class("ReplicationsAlgorithm", list( # nolint: object
514592# ' @param metric Name of performance metric to assess.
515593# ' @param verbose Boolean, whether to print messages about parameters.
516594# '
517- # ' @importFrom dplyr filter pull select slice_head
518- # ' @importFrom stats sd t.test
519- # ' @importFrom utils tail
520- # '
521595# ' @return Dataframe with results from each replication.
522596# ' @export
523597
@@ -609,10 +683,6 @@ confidence_interval_method <- function(replications, desired_precision,
609683# ' @param file_path Path and filename to save the plot to.
610684# ' @param min_rep The number of replications required to meet the desired
611685# ' precision.
612- # '
613- # ' @importFrom ggplot2 aes geom_line geom_ribbon geom_vline ggplot ggsave labs
614- # ' @importFrom ggplot2 theme_minimal
615- # ' @importFrom rlang .data
616686
617687plot_replication_ci <- function (
618688 conf_ints , yaxis_title , file_path = NULL , min_rep = NULL
0 commit comments