Skip to content

fix: fix init with draws or fit object and without .stan file#1171

Merged
jgabry merged 3 commits intomasterfrom
fix-1088-init-without-stan-file
Apr 6, 2026
Merged

fix: fix init with draws or fit object and without .stan file#1171
jgabry merged 3 commits intomasterfrom
fix-1088-init-without-stan-file

Conversation

@avehtari
Copy link
Copy Markdown
Member

@avehtari avehtari commented Apr 6, 2026

Closes #1088

Fix init from fit objects when model has no Stan file

When a CmdStanModel is created with only exe_file (no .stan file), using a fit object (e.g. from $pathfinder()) as init fails with the uninformative error "'init' contains empty lists.".

Root cause

Without a Stan file, model$variables() is unavailable, so model_variables is NULL throughout the init processing pipeline. Four functions (process_init.CmdStanMCMC, process_init_approx, process_init.CmdStanPathfinder, process_init.CmdStanMLE) had fallback code that constructed model_variables$parameters as a character vector of column names, but process_init.draws() expects it to be a named list with $dimensions metadata. This caused names(model_variables$parameters) to return NULL, producing empty init lists.

Fix

  • Added model_variables_from_draws() helper that infers parameter names and number of dimensions from posterior::variables(as_draws_df(...)): names without [ are scalars, names with [ are containers (base name extracted via sub("\\[.*", "", ...)), and the number of , determine the number of dimensions.
  • process_init.draws() calls this helper when model_variables is NULL, so it works without a Stan file.
  • Removed the broken column-index-based fallbacks from the four intermediate process_init.* methods — they now pass model_variables through as-is and let process_init.draws() handle the NULL case.
  • Cleaned up extra columns (lw, weight) that process_init_approx and the Pathfinder no-lp branch add to draws before passing downstream.
  • "Pathfinder inits do not drop dimensions" test was renamed to "Inits from fit/draws work for exe-only models with various parameter types" and modified to test more different containers, and to include test case for exe-file-only model to .

Notes

  • Using model$variables() when Stan file is available still has benefit of creating the init list only with the actual model variables.
  • Using model_variables_from_draws() has downside of including transformed paramaters and generated quantities, although that is unlikely to have big performance effect.
  • When the init is based on a fit object, it would be possible to to get the names of the parameters and dimensions (and drop transformed parameters and generated quantities) with fit$variable_skeleton(transformed_parameters = FALSE, generated_quantities = FALSE) but that causes compilation of model methods which adds overhead, and thus was not added here.
  • The design of the fix is by me. Coding and testing was assisted by Claude

Copyright and Licensing

Please list the copyright holder for the work you are submitting
(this will be you or your assignee, such as a university or company):

Aki Vehtari

By submitting this pull request, the copyright holder is agreeing to
license the submitted work under the following licenses:

@avehtari avehtari requested a review from jgabry April 6, 2026 10:10
@codecov-commenter
Copy link
Copy Markdown

codecov-commenter commented Apr 6, 2026

Codecov Report

❌ Patch coverage is 87.67123% with 9 lines in your changes missing coverage. Please review.
✅ Project coverage is 91.23%. Comparing base (c0e7c35) to head (a9d1d90).

Files with missing lines Patch % Lines
R/args.R 87.67% 9 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           master    #1171      +/-   ##
==========================================
+ Coverage   91.14%   91.23%   +0.08%     
==========================================
  Files          15       15              
  Lines        6065     6070       +5     
==========================================
+ Hits         5528     5538      +10     
+ Misses        537      532       -5     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Copy link
Copy Markdown
Member

@jgabry jgabry left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's an edge case that causes an error. I think it's inferring the wrong number of dimensions for higher dimensional objects that only contain 1 element:

stan_code <- write_stan_file(
  "
  data { real y; }
  parameters { matrix[1,1] mu; }
  model { y ~ normal(mu[1,1], 1); }
  "
)
mod <- cmdstan_model(stan_code, force_recompile = TRUE)
fit <- mod$sample(data = list(y = 0))
mod_exe <- cmdstan_model(exe_file = mod$exe_file())

# both of these error 
mod_exe$sample(data = list(y = 0), chains = 1, init = fit$draws())
mod_exe$sample(data = list(y = 0), chains = 1, init = fit)

I think this would also error for array[1,1] real, array[1,1,1] real, etc., although I haven't tested those. These probably aren't very common in Stan programs, but could exist.

@avehtari
Copy link
Copy Markdown
Member Author

avehtari commented Apr 6, 2026

Fixed and the description in the first comment has been updated

also fix some uses of `=` for assignment (unrelated to this PR)
Copy link
Copy Markdown
Member

@jgabry jgabry left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good now, thanks. We can merge if everything passes. (I also pushed one commit cleaning up a couple of trivial unrelated things in args.R that I noticed while I was looking at it. I probably should do that separately from this PR, but it was just changing some = to <- for assignment)

@VisruthSK
Copy link
Copy Markdown
Member

VisruthSK commented Apr 6, 2026

but it was just changing some = to <- for assignment)

In conjunction with #1153 maybe we could try running jarl or lintr and cleaning up some simple fixes like these?

@jgabry
Copy link
Copy Markdown
Member

jgabry commented Apr 6, 2026

but it was just changing some = to <- for assignment)

In conjunction with #1153 maybe we could try running jarl or lintr and cleaning up some simple fixes like these?

Yeah good idea. We could do this as part of #1153. There are probably a bunch of things like this throughout the package.

@avehtari
Copy link
Copy Markdown
Member Author

avehtari commented Apr 6, 2026

I also notices some bad indentation making it harder to see nesting in if-else-statements. I think it's better to make a separate PR for formatting

@jgabry
Copy link
Copy Markdown
Member

jgabry commented Apr 6, 2026

Actually @VisruthSK maybe we should do this before #1153 so that the diffs are separate?

@jgabry
Copy link
Copy Markdown
Member

jgabry commented Apr 6, 2026

Thanks Aki! merging now.

@jgabry jgabry merged commit 021545d into master Apr 6, 2026
14 checks passed
@jgabry jgabry deleted the fix-1088-init-without-stan-file branch April 6, 2026 22:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

initiailizing with a draws or fit object fails if the model is created without a .stan file

4 participants