This bug report was written with the assistance of Claude
Describe the bug
CmdStanModel caches private$variables_ on first $variables() call
(R/model.R:894) and private$stan_code_ at construction (R/model.R:263).
Neither is invalidated by $compile(), and stan_code_ is only ever refreshed
by $format(overwrite_file = TRUE) (R/model.R:1182).
So if the underlying .stan file changes and the model is recompiled through the
same object, $variables() and $code() keep describing the old program while
the executable is the new one. This is not just cosmetic: the fitting methods use
self$variables() for init/data checking, so they validate against the wrong
parameter set.
To Reproduce
library(cmdstanr)
d <- tempdir()
f <- file.path(d, "m.stan")
writeLines(c("parameters { real alpha; }", "model { alpha ~ std_normal(); }"), f)
mod <- cmdstan_model(f)
names(mod$variables()$parameters)
#> [1] "alpha"
# edit the model, then recompile through the same object
writeLines(c("parameters { real beta; }", "model { beta ~ std_normal(); }"), f)
mod$compile(force_recompile = TRUE)
names(mod$variables()$parameters)
#> [1] "alpha" # stale
mod$code()
#> [1] "parameters { real alpha; }" "model { alpha ~ std_normal(); }" # stale
fit <- mod$sample(chains = 1, iter_sampling = 100, iter_warmup = 100, refresh = 0)
posterior::variables(fit$draws())
#> [1] "lp__" "beta" # the exe really is the new model
# a freshly constructed object is correct
names(cmdstan_model(f, compile = FALSE)$variables()$parameters)
#> [1] "beta"
Concrete user-visible fallout — supplying a correct init for the new model
produces a spurious warning naming the old parameter:
mod$sample(chains = 1, iter_sampling = 100, iter_warmup = 100, refresh = 0,
init = list(list(beta = 0)))
#> Init values were only set for a subset of parameters.
#> Missing init values for the following parameters:
#> alpha
Expected behavior
$compile() should invalidate private$variables_ and re-read
private$stan_code_ so that $variables(), $code(), and the init/data checks
in the fitting methods reflect the program that was actually compiled.
Operating system
macOS 15.4
** CmdStanR version number**
0.9.0.9001 (dev), CmdStan 2.39.0
Additional context
Noticed while reviewing #1226. Unrelated to that PR's changes; the caching code
is untouched by it. One side effect of the variables_ cache is that the
"pre and post compilation" assertion in the $variables() works with #includes
test is vacuous — vars_post is just the cached vars_pre. Worth revisiting
that test alongside a fix.
This bug report was written with the assistance of Claude
Describe the bug
CmdStanModelcachesprivate$variables_on first$variables()call(
R/model.R:894) andprivate$stan_code_at construction (R/model.R:263).Neither is invalidated by
$compile(), andstan_code_is only ever refreshedby
$format(overwrite_file = TRUE)(R/model.R:1182).So if the underlying
.stanfile changes and the model is recompiled through thesame object,
$variables()and$code()keep describing the old program whilethe executable is the new one. This is not just cosmetic: the fitting methods use
self$variables()for init/data checking, so they validate against the wrongparameter set.
To Reproduce
Expected behavior
$compile() should invalidate private$variables_ and re-read
private$stan_code_ so that $variables(), $code(), and the init/data checks
in the fitting methods reflect the program that was actually compiled.
Operating system
macOS 15.4
** CmdStanR version number**
0.9.0.9001 (dev), CmdStan 2.39.0
Additional context
Noticed while reviewing #1226. Unrelated to that PR's changes; the caching code
is untouched by it. One side effect of the variables_ cache is that the
"pre and post compilation" assertion in the $variables() works with #includes
test is vacuous — vars_post is just the cached vars_pre. Worth revisiting
that test alongside a fix.