Skip to content

Add save_diagnostics to laplace_sample and expose the Hessian - #870

Open
atarutin wants to merge 1 commit into
stan-dev:developfrom
atarutin:laplace-save-diagnostics
Open

atarutin wants to merge 1 commit into
stan-dev:developfrom
atarutin:laplace-save-diagnostics

Conversation

@atarutin

@atarutin atarutin commented Oct 9, 2026

Copy link
Copy Markdown
Contributor

Submission Checklist

  • Run unit tests
  • Declare copyright holder and open-source license: see below

Summary

Closes #868.

CmdStan's laplace method can write a diagnostic file holding the Hessian of the log density at the mode, on the unconstrained scale. In CmdStan 2.40.0 the file is JSON with the keys lp_mode, gradient and Hessian. This PR implements the API agreed in the issue:

  • CmdStanModel.laplace_sample(..., save_diagnostics: bool = False). When True, diagnostic_file=<output_dir>/<model>-<time>_diagnostic.json is added to the output argument group. It reuses the existing CmdStanArgs.save_latent_dynamics → RunSet.diagnostic_files → compose_command(diagnostic_file=...) path that sample uses. RunSet now gives the diagnostic file a .json extension when the method is Laplace, and .csv otherwise, as before.
  • CmdStanLaplace.diagnostic_file: str | None holds the raw path, like CmdStanMCMC.diagnostic_files. It is included in save_output_files, accepted by CmdStanLaplace.from_files(diagnostic_file=...), and shown in repr.
  • CmdStanLaplace.hessian -> np.ndarray | None parses the Hessian key on first access. It is None when the diagnostic file was not saved.

Test: test_laplace_hessian fits test/data/linear_regression.stan with jacobian=False and sig_figs=18. It asserts that the Hessian has shape (3, 3), one row per unconstrained parameter (alpha, beta, log sigma), that it is symmetric and negative definite, and that it matches the analytic Hessian of the normal log likelihood evaluated at the mode CmdStan used (rtol=1e-6, atol=1e-6). In five runs with different seeds the largest absolute difference was about 1e-8. The test also checks that save_output_files moves the diagnostic file and that from_files reads it back. test_laplace_outputs now also asserts that diagnostic_file and hessian are None by default.

Points for review:

  • The argument is named save_diagnostics, as agreed in the issue. sample currently calls the equivalent argument save_latent_dynamics, a name that describes HMC output. Internally this PR passes save_latent_dynamics=save_diagnostics to CmdStanArgs. I can rename anything here if you prefer different names.
  • Only the Hessian is parsed. lp_mode and gradient stay in the file, which diagnostic_file points to.
  • from_output_files does not discover the diagnostic file on its own. The config JSON's output section is parsed with only file and sig_figs as fields. I left discovery out to keep this PR small.

What I ran. All runs were in a Linux container with Python 3.12.14 and CmdStan 2.40.0, on develop at edf9fe3:

  • isort --check-only, black --check, flake8, pylint --rcfile=.pylintrc, and mypy on cmdstanpy test: all clean.
  • pytest test/test_laplace.py test/test_laplace_output_files.py test/test_runset.py test/test_cmdstan_args.py: all pass. test_args_bad passes only as a non-root user; see below.
  • pytest test, excluding test_install_cmdstan.py, test_cxx_installation.py, test_model.py and test_compilation.py: 408 passed, 3 skipped, 4 failed. The 4 failures (test_args_bad, test_bernoulli_bad, test_save_csv, test_validate_dir) come from running as root, where read-only directories are writable. They fail the same way on unmodified develop as root, and pass as a non-root user.
  • Against develop without the change, test_laplace_hessian and the extended test_laplace_outputs fail.

AI disclosure, per the Stan AI Contribution Policy: this change was prepared with Claude Code (Anthropic).

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):

Aleksandr Tarutin

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

🤖 Generated with Claude Code

CmdStan's laplace method writes the Hessian of the log density at the
mode, on the unconstrained scale, to its diagnostic file as JSON.
laplace_sample(save_diagnostics=True) now passes diagnostic_file= in the
output argument group. CmdStanLaplace records the path as
diagnostic_file, moves it in save_output_files, accepts it in
from_files, and parses the matrix in the hessian property, which is None
when the file was not saved.

Closes stan-dev#868
@atarutin
atarutin force-pushed the laplace-save-diagnostics branch from 24f4873 to e32b237 Compare October 9, 2026 18:16

@atarutin atarutin left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Looks clean.

@atarutin
atarutin marked this pull request as ready for review October 9, 2026 19:06
@amas0

amas0 commented Oct 9, 2026

Copy link
Copy Markdown
Collaborator

I know we do the same thing in variational, but I'm not sure how I feel about overloading save_latent_dynamics to mean saving position/momentum for sample, but other diagnostics for variational/laplace?

@WardBrian

Copy link
Copy Markdown
Member

diagnostics is the name cmdstan actually uses for the arguments, so maybe it's better to just use that consistently in the shared code? I'm not really sure of the history of latent_dynamics

@amas0

amas0 commented Oct 9, 2026

Copy link
Copy Markdown
Collaborator

Oh yeah in that case, seems like the perfect time to get it all under diagnostics? We can deprecate/remove the latent_dynamics arg as part of the 2.0 release

@WardBrian

Copy link
Copy Markdown
Member

I think that's a good call (and the perfect example of something I'm glad came up before 2.0)

This branch has not been deployed

No deployments
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.

laplace_sample: expose CmdStan's diagnostic_file (the Hessian at the mode)

3 participants