From b09ed69dff0f8e24d6183532716fb8c090484b3a Mon Sep 17 00:00:00 2001 From: MLopez-Ibanez <2620021+MLopez-Ibanez@users.noreply.github.com> Date: Tue, 7 Jan 2025 15:11:04 +0000 Subject: [PATCH] * R/parameterAnalysis.R (getConfigurationById): use match instead of %in%. --- NEWS.md | 3 ++ R/parameterAnalysis.R | 65 +++++++++++++++-------------- man/getConfigurationById.Rd | 7 ++-- man/getConfigurationByIteration.Rd | 2 +- man/getFinalElites.Rd | 2 +- man/get_instanceID_seed_pairs.Rd | 4 +- tests/testthat/test-get-functions.R | 11 +++++ 7 files changed, 55 insertions(+), 39 deletions(-) create mode 100644 tests/testthat/test-get-functions.R diff --git a/NEWS.md b/NEWS.md index 5402bfa0..34812cc3 100644 --- a/NEWS.md +++ b/NEWS.md @@ -25,6 +25,9 @@ (`--capping-after-first-test`). If set to 1, elimination due to capping only happens after `firstTest` instances are seen (issue #78, suggested by Nguyen Dang). + * `getConfigurationById()` now returns configurations in the same order + (including repeated values) of the IDs passed as argument. + ## Fixes * Fix #76: Recovery (`--recover-file`) is working again with a completely new implementation. diff --git a/R/parameterAnalysis.R b/R/parameterAnalysis.R index b79545e3..346b15eb 100644 --- a/R/parameterAnalysis.R +++ b/R/parameterAnalysis.R @@ -1,18 +1,18 @@ #' Return the elite configurations of the final iteration. -#' +#' #' @inheritParams has_testing_data -#' @param n Number of elite configurations to return, if \code{n} is larger than the +#' @param n `integer(1)`\cr Number of elite configurations to return, if \code{n} is larger than the #' number of configurations, then only the existing ones are returned. The default (\code{n=0}) returns all of them. #' @param drop.metadata `logical(1)`\cr Remove metadata, such as the #' configuration ID and the ID of the parent, from the returned #' configurations. See [removeConfigurationsMetaData()]. -#' +#' #' @return A data frame containing the elite configurations required. #' #' @examples #' log_file <- system.file("exdata/irace-acotsp.Rdata", package="irace", mustWork=TRUE) #' print(removeConfigurationsMetaData(getFinalElites(log_file, n=1))) -#' +#' #' @author Manuel López-Ibáñez and Leslie Pérez Cáceres #' @concept analysis #' @export @@ -20,20 +20,20 @@ getFinalElites <- function(iraceResults, n = 0L, drop.metadata = FALSE) { if (missing(iraceResults)) stop("argument 'iraceResults' is missing") iraceResults <- read_logfile(iraceResults) - - last.elites <- iraceResults$allElites[[length(iraceResults$allElites)]] - + + last_elites <- iraceResults$allElites[[length(iraceResults$allElites)]] + if (n == 0L) - n <- length(last.elites) - - if (length(last.elites) < n) { - cat("Only", length(last.elites), "configurations available, reducing n,") - n <- length(last.elites) + n <- length(last_elites) + + if (length(last_elites) < n) { + cat("Only", length(last_elites), "configurations available, reducing n,") + n <- length(last_elites) } - last.elites <- last.elites[seq_len(n)] - + last_elites <- last_elites[seq_len(n)] + configurations <- subset(iraceResults$allConfigurations, - get(".ID.") %in% as.character(last.elites), + get(".ID.") %in% as.character(last_elites), drop = FALSE) if (drop.metadata) configurations <- removeConfigurationsMetaData(configurations) @@ -41,14 +41,15 @@ getFinalElites <- function(iraceResults, n = 0L, drop.metadata = FALSE) } #' Returns the configurations selected by ID. -#' -#' @param ids (`integer()`)\cr The id or a vector of ids of the candidates configurations to obtain. +#' +#' @param ids `integer()`\cr The id or a vector of ids of the candidates configurations to obtain. #' @inheritParams getFinalElites -#' -#' @return A data frame containing the elite configurations required. +#' +#' @return A data frame containing the elite configurations required, in the +#' order and with the repetitions given by `ids`. #' @examples #' log_file <- system.file("exdata/irace-acotsp.Rdata", package="irace", mustWork=TRUE) -#' getConfigurationById(log_file, ids = c(1,2), drop.metadata = TRUE) +#' getConfigurationById(log_file, ids = c(2,1), drop.metadata = TRUE) #' #' @author Manuel López-Ibáñez and Leslie Pérez Cáceres #' @concept analysis @@ -57,7 +58,7 @@ getConfigurationById <- function(iraceResults, ids, drop.metadata = FALSE) { if (missing(iraceResults)) stop("argument 'iraceResults' is missing") iraceResults <- read_logfile(iraceResults) - + if (length(ids) < 1L) stop("You must provide at least one configuration id.") get_configuration_by_id_helper(iraceResults$allConfigurations, ids, drop_metadata = drop.metadata) @@ -65,16 +66,16 @@ getConfigurationById <- function(iraceResults, ids, drop.metadata = FALSE) #' Returns the configurations by the iteration in which they were executed. #' -#' @param iterations (`integer()`)\cr The iteration number or a vector of iteration numbers from where +#' @param iterations `integer()`\cr The iteration number or a vector of iteration numbers from where #' the configurations should be obtained. Negative values start counting from the last iteration. #' @inheritParams getFinalElites -#' +#' #' @return A data frame containing the elite configurations required. #' #' @examples #' log_file <- system.file("exdata/irace-acotsp.Rdata", package="irace", mustWork=TRUE) #' getConfigurationByIteration(log_file, iterations = c(-2, -1), drop.metadata = TRUE) -#' +#' #' @author Manuel López-Ibáñez and Leslie Pérez Cáceres #' @concept analysis #' @export @@ -94,7 +95,7 @@ getConfigurationByIteration <- function(iraceResults, iterations, drop.metadata if (is.null(iraceResults$state$experiment_log) || nrow(iraceResults$state$experiment_log) == 0L) stop("'iraceResults' does not contain experiment_log, maybe the wrong file, an incomplete run or the wrong version of irace?") - + ids <- unique(subset(as.data.frame(iraceResults$state$experiment_log), iteration %in% iterations, select="configuration", drop=TRUE)) @@ -103,11 +104,11 @@ getConfigurationByIteration <- function(iraceResults, iterations, drop.metadata get_configuration_by_id_helper <- function(allConfigurations, ids, drop_metadata) -{ - configurations <- allConfigurations[allConfigurations[[".ID."]] %in% ids, , drop=FALSE] +{ + configurations <- allConfigurations[match(ids, allConfigurations[[".ID."]]), , drop=FALSE] if (nrow(configurations) == 0L) stop("No configuration found with ID:", ids, ".") - + if (drop_metadata) configurations <- removeConfigurationsMetaData(configurations) configurations @@ -117,9 +118,9 @@ get_configuration_by_id_helper <- function(allConfigurations, ids, drop_metadata #' (and optionally the actual instances). #' #' @inheritParams getFinalElites -#' @param index (`integer()`)\cr Indexes of the (instanceID,seed) pairs to be returned. The default returns everything. -#' @param instances (`logical(1)`)\cr Whether to add the actual instances as an additional column (only if the instances are of atomic type). -#' +#' @param index `integer()`\cr Indexes of the (instanceID,seed) pairs to be returned. The default returns everything. +#' @param instances `logical(1)`\cr Whether to add the actual instances as an additional column (only if the instances are of atomic type). +#' #' @return `data.table()`\cr With default arguments, a `data.table` containing two columns #' `"instanceID"` and `"seed"`. With `instances=TRUE` and if the instances #' are of atomic type (see [is.atomic()]) type, another column `instance` is @@ -148,7 +149,7 @@ get_instanceID_seed_pairs <- function(iraceResults, index, instances = FALSE) warning("instances=TRUE requested, but instances are not of atomic type") return(instances_log) } - + instanceID <- instances_log[["instanceID"]] cbind(instances_log, instance = instances[instanceID]) } diff --git a/man/getConfigurationById.Rd b/man/getConfigurationById.Rd index 318617e0..0845ee63 100644 --- a/man/getConfigurationById.Rd +++ b/man/getConfigurationById.Rd @@ -9,21 +9,22 @@ getConfigurationById(iraceResults, ids, drop.metadata = FALSE) \arguments{ \item{iraceResults}{\code{list()}|\code{character(1)}\cr Object created by \pkg{irace} and typically saved in the log file \code{irace.Rdata}. If a character string is given, then it is interpreted as the path to the log file from which the \code{iraceResults} object will be loaded.} -\item{ids}{(\code{integer()})\cr The id or a vector of ids of the candidates configurations to obtain.} +\item{ids}{\code{integer()}\cr The id or a vector of ids of the candidates configurations to obtain.} \item{drop.metadata}{\code{logical(1)}\cr Remove metadata, such as the configuration ID and the ID of the parent, from the returned configurations. See \code{\link[=removeConfigurationsMetaData]{removeConfigurationsMetaData()}}.} } \value{ -A data frame containing the elite configurations required. +A data frame containing the elite configurations required, in the +order and with the repetitions given by \code{ids}. } \description{ Returns the configurations selected by ID. } \examples{ log_file <- system.file("exdata/irace-acotsp.Rdata", package="irace", mustWork=TRUE) -getConfigurationById(log_file, ids = c(1,2), drop.metadata = TRUE) +getConfigurationById(log_file, ids = c(2,1), drop.metadata = TRUE) } \author{ diff --git a/man/getConfigurationByIteration.Rd b/man/getConfigurationByIteration.Rd index 6f7afe38..5259318c 100644 --- a/man/getConfigurationByIteration.Rd +++ b/man/getConfigurationByIteration.Rd @@ -9,7 +9,7 @@ getConfigurationByIteration(iraceResults, iterations, drop.metadata = FALSE) \arguments{ \item{iraceResults}{\code{list()}|\code{character(1)}\cr Object created by \pkg{irace} and typically saved in the log file \code{irace.Rdata}. If a character string is given, then it is interpreted as the path to the log file from which the \code{iraceResults} object will be loaded.} -\item{iterations}{(\code{integer()})\cr The iteration number or a vector of iteration numbers from where +\item{iterations}{\code{integer()}\cr The iteration number or a vector of iteration numbers from where the configurations should be obtained. Negative values start counting from the last iteration.} \item{drop.metadata}{\code{logical(1)}\cr Remove metadata, such as the diff --git a/man/getFinalElites.Rd b/man/getFinalElites.Rd index ad01f298..9a65bb95 100644 --- a/man/getFinalElites.Rd +++ b/man/getFinalElites.Rd @@ -9,7 +9,7 @@ getFinalElites(iraceResults, n = 0L, drop.metadata = FALSE) \arguments{ \item{iraceResults}{\code{list()}|\code{character(1)}\cr Object created by \pkg{irace} and typically saved in the log file \code{irace.Rdata}. If a character string is given, then it is interpreted as the path to the log file from which the \code{iraceResults} object will be loaded.} -\item{n}{Number of elite configurations to return, if \code{n} is larger than the +\item{n}{\code{integer(1)}\cr Number of elite configurations to return, if \code{n} is larger than the number of configurations, then only the existing ones are returned. The default (\code{n=0}) returns all of them.} \item{drop.metadata}{\code{logical(1)}\cr Remove metadata, such as the diff --git a/man/get_instanceID_seed_pairs.Rd b/man/get_instanceID_seed_pairs.Rd index 276ed05e..7fb7474c 100644 --- a/man/get_instanceID_seed_pairs.Rd +++ b/man/get_instanceID_seed_pairs.Rd @@ -10,9 +10,9 @@ get_instanceID_seed_pairs(iraceResults, index, instances = FALSE) \arguments{ \item{iraceResults}{\code{list()}|\code{character(1)}\cr Object created by \pkg{irace} and typically saved in the log file \code{irace.Rdata}. If a character string is given, then it is interpreted as the path to the log file from which the \code{iraceResults} object will be loaded.} -\item{index}{(\code{integer()})\cr Indexes of the (instanceID,seed) pairs to be returned. The default returns everything.} +\item{index}{\code{integer()}\cr Indexes of the (instanceID,seed) pairs to be returned. The default returns everything.} -\item{instances}{(\code{logical(1)})\cr Whether to add the actual instances as an additional column (only if the instances are of atomic type).} +\item{instances}{\code{logical(1)}\cr Whether to add the actual instances as an additional column (only if the instances are of atomic type).} } \value{ \code{data.table()}\cr With default arguments, a \code{data.table} containing two columns diff --git a/tests/testthat/test-get-functions.R b/tests/testthat/test-get-functions.R new file mode 100644 index 00000000..90c55a57 --- /dev/null +++ b/tests/testthat/test-get-functions.R @@ -0,0 +1,11 @@ +withr::with_output_sink("test-get-functions.Rout", { + + test_that("getConfigurationById()", { + log <- read_logfile(system.file(package="irace", "exdata", "irace-acotsp.Rdata", mustWork=TRUE)) + ids <- sample(log$allConfigurations[[".ID."]], size=3) + ids <- c(ids, rev(ids)) + sel_ids <- getConfigurationById(log, ids = ids)[[".ID."]] + expect_identical(sel_ids, ids) +}) + +})