read_csv_header() can match more than one line
Nobody has claimed this yet.
- Dominant language
- R
- Stars
- 1.1k
- Forks
- 266
- Avg merge
- 2h 56m
- Merged PRs (30d)
- 1
Description
Summary:
If the path to the output file in the Stan CSV matches one of the regexes in read_csv_header(), then the function throws an error.
Description:
read_csv_header() uses regexes to extract information like the number of warmup iterations from the Stan CSV. Because this is done in a while() loop, if multiple lines (prior to the header) match a regex, then the last match will be used. I happened to include the term within in the name one of my models (I was experimenting with within-chain parallelization), and noticed that read_stan_csv() was throwing an error. It turns out that the output file name was matching the thin regex, and because the result was a character, integer coercion resulted in an NA value that propagated to iter.count.
It seems that this could possibly be avoided by replacing the regex "#.*thin" with "#[[:blank:]]*thin". Another solution would be to avoid including "reserved words" in the model name.
Reproducible Steps:
The following reprex demonstrates the issue, and shows the solution proposed above.
csv_lines <- c(
"# model = redcard_within_model",
"# method = sample (Default)",
"# sample",
"# num_samples = 1000 (Default)",
"# num_warmup = 1000 (Default)",
"# save_warmup = 0 (Default)",
"# thin = 1 (Default)",
"# output",
"# file = redcard_within-202103251619-1-16b40e.csv",
"lp__,accept_stat__,stepsize__,treedepth__,n_leapfrog__,divergent__,energy__,beta.1,beta.2"
)
tmp <- tempfile(fileext = ".csv")
writeLines(csv_lines, tmp)
rstan:::read_csv_header(tmp)
#> Warning in rstan:::read_csv_header(tmp): NAs introduced by coercion to integer
#> range
#> [1] "lp__,accept_stat__,stepsize__,treedepth__,n_leapfrog__,divergent__,energy__,beta.1,beta.2"
#> attr(,"iter.count")
#> [1] NA
#> attr(,"lineno")
#> [1] 10
g <- function(f, comment.char = '#') {
con <- file(f, 'r')
niter <- 0
iter.count <- NA
save.warmup <- FALSE
sample.count <- NA_integer_
thin <- NULL
while (length(input <- readLines(con, n = 1)) > 0) {
niter <- niter + 1
if (!grepl(comment.char, input)) break;
if (grepl("# iter=",input))
iter.count <- as.integer(gsub("# iter=","",input))
if (grepl("#.*num_samples",input)){
sample.count <- as.integer(gsub("[^0-9]*([0-9]*).*","\\1",input))
}
if (grepl("#.*num_warmup",input)){
warmup.count <- as.integer(gsub("[^0-9]*([0-9]*).*","\\1",input))
} else {
warmup.count <- 0L
}
if (grepl("#[[:blank:]]*thin", input)){
thin <- as.integer(gsub("[^0-9]*([0-9]*).*","\\1",input))
}
if (grepl("#.*save_warmup",input)){
save.warmup <- !grepl("0",input)
}
if (grepl("#.*output_sample",input)){
iter.count <- as.numeric(gsub("[^0-9]*([0-9]*).*","\\1",input))
}
}
header <- input
if(is.na(iter.count)){
if(save.warmup)
iter.count <- warmup.count + sample.count
else
iter.count <- sample.count
}
if(!is.null(thin)){
iter.count <- iter.count %/% thin
}
attr(header, "iter.count") <- iter.count
attr(header, "lineno") <- niter
close(con)
header
}
g(tmp)
#> [1] "lp__,accept_stat__,stepsize__,treedepth__,n_leapfrog__,divergent__,energy__,beta.1,beta.2"
#> attr(,"iter.count")
#> [1] 1000
#> attr(,"lineno")
#> [1] 10
RStan Version:
2.21.2
R Version:
R version 4.0.3 (2020-10-10)
Operating System:
Ubuntu 18.04
Contributor guide
No contributing guide indexed for this repository
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start at the read_csv_header() entry point and reproduce the issue with the supplied csv_lines example, focusing on matching the thin metadata line. Done means a model or output filename containing "thin" no longer produces an NA iter.count, while the actual # thin header still yields the expected iteration count.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- r
- Domain
- data
- Issue type
- Bug
- Difficulty
- 2/5
- Estimated time
- 1-3 hours
- Activity status
- Stale
- Clarity
- Clearly specified
- Newbie friendliness
- 55/100