Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion NEWS.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# cmdstanr (development version)

* Chain IDs in generated filenames are now zero-padded to at least two digits,
for example `01` instead of `1`. (#1244)
* When using CmdStan through WSL, paths for output, diagnostic, profile, config,
and metric files now remain accessible to Windows R when an explicit output
directory is supplied. (#1110; related: #1113)
Expand Down Expand Up @@ -80,7 +82,7 @@ CmdStan 2.39 or newer, and `read_cmdstan_csv()` returns these times from
standalone generated quantities CSV files. (#1168)
* `laplace()` no longer overwrites the internally generated optimizer CSV when
`mode = NULL` and `output_basename` is supplied. The internally generated
optimizer CSV now uses the filename `<output_basename>-mode-1.csv`.
optimizer CSV now uses the filename `<output_basename>-mode-01.csv`.

* CmdStanModel objects created using `compile_model_methods = TRUE` that are
then saved and reloaded no longer error in model fitting methods. Model methods
Expand Down
3 changes: 2 additions & 1 deletion R/fit.R
Original file line number Diff line number Diff line change
Expand Up @@ -1000,7 +1000,8 @@ CmdStanFit$set("public", name = "cmdstan_diagnose", value = cmdstan_diagnose)
#' * `basename` is the user's provided `basename` argument or, if `NULL`, the
#' model name;
#' * `timestamp` is of the form `format(Sys.time(), "%Y%m%d%H%M")`;
#' * `id` is the MCMC chain id (or `1` for non MCMC);
#' * `id` is the MCMC chain id, zero-padded to at least two digits (or `01` for
#' non-MCMC);
#' * `random` contains six random hexadecimal characters.
#'
#' `$save_latent_dynamics_files()` uses the pattern
Expand Down
3 changes: 2 additions & 1 deletion R/utils.R
Original file line number Diff line number Diff line change
Expand Up @@ -266,7 +266,8 @@ generate_file_names <-
new_names <- paste0(new_names, "-", stamp)
}
if (!is.null(ids)) {
new_names <- paste0(new_names, "-", ids)
width <- max(2L, nchar(sprintf("%d", max(ids))))
new_names <- paste0(new_names, "-", sprintf("%0*d", width, ids))
}
if (random) {
rand_num_pid <- as.integer(stats::runif(1, min = 0, max = 1E7)) + Sys.getpid()
Expand Down
3 changes: 2 additions & 1 deletion man/fit-method-save_output_files.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions tests/testthat/test-fit-shared.R
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ test_that("saving csv output files works", {
should_match <- paste0("testing-output-",
base::format(Sys.time(), "%Y%m%d%H%M"),
"-",
seq_len(fit$num_procs()))
sprintf("%02d", seq_len(fit$num_procs())))
for (j in seq_along(paths)) {
expect_match(paths[j], should_match[j])
}
Expand Down Expand Up @@ -72,7 +72,7 @@ test_that("saving diagnostic csv output works", {
should_match <- paste0("testing-output-diagnostic-",
base::format(Sys.time(), "%Y%m%d%H%M"),
"-",
seq_len(fit$num_procs()))
sprintf("%02d", seq_len(fit$num_procs())))

for (j in seq_along(paths)) {
expect_match(paths[j], should_match[j])
Expand Down
6 changes: 3 additions & 3 deletions tests/testthat/test-model-laplace.R
Original file line number Diff line number Diff line change
Expand Up @@ -76,11 +76,11 @@ test_that("laplace() avoids output_basename conflict with internal optimize()",
)
)

expect_equal(basename(fit$output_files()), "custom-laplace-1.csv")
expect_equal(basename(fit$mode()$output_files()), "custom-laplace-mode-1.csv")
expect_equal(basename(fit$output_files()), "custom-laplace-01.csv")
expect_equal(basename(fit$mode()$output_files()), "custom-laplace-mode-01.csv")
expect_setequal(
list.files(output_dir, pattern = "\\.csv$"),
c("custom-laplace-1.csv", "custom-laplace-mode-1.csv")
c("custom-laplace-01.csv", "custom-laplace-mode-01.csv")
)
})

Expand Down
16 changes: 8 additions & 8 deletions tests/testthat/test-model-output_dir.R
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ test_that("WSL output paths stay host-native until command composition", {
output_basename = "model"
)
})
output_files <- file.path(host_dirs, "model-1.csv")
output_files <- file.path(host_dirs, "model-01.csv")
expect_equal(
vapply(args, function(x) x$output_dir, character(1)),
host_dirs
Expand All @@ -62,15 +62,15 @@ test_that("WSL output paths stay host-native until command composition", {
)
sub("file=", "", command_args[grepl("^file=", command_args)], fixed = TRUE)
}, character(1))
expect_equal(cmdstan_output_files, file.path(wsl_dirs, "model-1.csv"))
expect_equal(cmdstan_output_files, file.path(wsl_dirs, "model-01.csv"))

command_args <- args[[1]]$compose_all_args(
output_file = output_files[1],
profile_file = file.path(host_dirs[1], "model-profile-1.csv"),
latent_dynamics_file = file.path(host_dirs[1], "model-diagnostic-1.csv")
profile_file = file.path(host_dirs[1], "model-profile-01.csv"),
latent_dynamics_file = file.path(host_dirs[1], "model-diagnostic-01.csv")
)
expect_in("diagnostic_file=/mnt/c/output/model-diagnostic-1.csv", command_args)
expect_in("profile_file=/mnt/c/output/model-profile-1.csv", command_args)
expect_in("diagnostic_file=/mnt/c/output/model-diagnostic-01.csv", command_args)
expect_in("profile_file=/mnt/c/output/model-profile-01.csv", command_args)

# Omitting output_dir must still use the faster WSL-native temp directory.
default_args <- CmdStanArgs$new(
Expand All @@ -82,7 +82,7 @@ test_that("WSL output paths stay host-native until command composition", {
)
expect_equal(default_args$output_dir, "//wsl$/Ubuntu/tmp/cmdstanr")
expect_in(
"file=/tmp/cmdstanr/model-1.csv",
"file=/tmp/cmdstanr/model-01.csv",
default_args$compose_all_args(
output_file = default_args$new_files("output")
)
Expand Down Expand Up @@ -145,7 +145,7 @@ test_that("all fitting methods work with output_dir", {
fit <- testing_fit("bernoulli", method = method, seed = 123,
output_basename = "custom")
n_files <- length(fit$output_files())
files <- paste0("custom-", 1:n_files, ".csv")
files <- sprintf("custom-%02d.csv", seq_len(n_files))
expect_equal(basename(fit$output_files()), files)
}

Expand Down
4 changes: 2 additions & 2 deletions tests/testthat/test-model-pathfinder.R
Original file line number Diff line number Diff line change
Expand Up @@ -169,9 +169,9 @@ test_that("pathfinder() saves single path outputs", {
)
)

expect_equal(basename(fit$output_files()), "pathfinder-1.csv")
expect_equal(basename(fit$output_files()), "pathfinder-01.csv")
single_path_files <- file.path(output_dir, paste0(
"pathfinder-1_path_",
"pathfinder-01_path_",
rep(1:2, each = 2),
c(".csv", ".json")
))
Expand Down
24 changes: 24 additions & 0 deletions tests/testthat/test-utils.R
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,30 @@ test_that("get_standalone_hpp() suggests formatting deprecated syntax", {

# misc --------------------------------------------------------------------

test_that("generate_file_names() zero-pads IDs for lexicographic sorting", {
expect_equal(
generate_file_names(
basename = "output",
ids = 1:10,
timestamp = FALSE,
random = FALSE
),
paste0("output-", sprintf("%02d", 1:10), ".csv")
)

file_names <- generate_file_names(
basename = "output",
ids = 1:100,
timestamp = FALSE,
random = FALSE
)
expect_equal(
file_names[c(1, 9, 10, 100)],
paste0("output-", c("001", "009", "010", "100"), ".csv")
)
expect_equal(sort(file_names), file_names)
})

test_that("copy_temp_files retains sources if any copy fails", {
source_dir <- withr::local_tempdir()
destination_dir <- withr::local_tempdir()
Expand Down
Loading